diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..24383e4 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "linux"] + shallow = true + path = linux + url = https://github.com/lkl/linux.git diff --git a/binding.gyp b/binding.gyp index 332f2dc..0bb36ac 100644 --- a/binding.gyp +++ b/binding.gyp @@ -13,23 +13,23 @@ { 'action_name': "lkl_make", 'inputs': [ - "src/linux/**" + "linux/**" ], 'outputs': [ - "src/linux/tools/lkl/liblkl.a" + "linux/tools/lkl/liblkl.a" ], - 'action': [ 'make', '-j4', '-C', 'src/linux/tools/lkl', 'static' ], + 'action': [ 'make', '-j4', '-C', 'linux/tools/lkl', 'static' ], 'message': 'Compiling LKL kernel..' } ], "cflags_cc": [ '-fpermissive', '-Wno-pointer-arith' ], "defines": [ "CONFIG_AUTO_LKL_POSIX_HOST" ], "libraries": [ - "../src/linux/tools/lkl/liblkl.a" + "../linux/tools/lkl/liblkl.a" ], "include_dirs": [ "/{s:->#\(.*\):/* \1 */:; \ - s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \ - s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \ - s:->::; p;}" -endef - -# Use filechk to avoid rebuilds when a header changes, but the resulting file -# does not -define filechk_offsets - (set -e; \ - echo "#ifndef $2"; \ - echo "#define $2"; \ - echo "/*"; \ - echo " * DO NOT MODIFY."; \ - echo " *"; \ - echo " * This file was generated by Kbuild"; \ - echo " */"; \ - echo ""; \ - sed -ne $(sed-y); \ - echo ""; \ - echo "#endif" ) -endef - -##### -# 1) Generate bounds.h - -bounds-file := include/generated/bounds.h - -always := $(bounds-file) -targets := kernel/bounds.s - -# We use internal kbuild rules to avoid the "is up to date" message from make -kernel/bounds.s: kernel/bounds.c FORCE - $(Q)mkdir -p $(dir $@) - $(call if_changed_dep,cc_s_c) - -$(obj)/$(bounds-file): kernel/bounds.s FORCE - $(call filechk,offsets,__LINUX_BOUNDS_H__) - -##### -# 2) Generate timeconst.h - -timeconst-file := include/generated/timeconst.h - -targets += $(timeconst-file) - -quiet_cmd_gentimeconst = GEN $@ -define cmd_gentimeconst - (echo $(CONFIG_HZ) | bc -q $< ) > $@ -endef -define filechk_gentimeconst - (echo $(CONFIG_HZ) | bc -q $< ) -endef - -$(obj)/$(timeconst-file): kernel/time/timeconst.bc FORCE - $(call filechk,gentimeconst) - -##### -# 3) Generate asm-offsets.h -# - -offsets-file := include/generated/asm-offsets.h - -always += $(offsets-file) -targets += arch/$(SRCARCH)/kernel/asm-offsets.s - -# We use internal kbuild rules to avoid the "is up to date" message from make -arch/$(SRCARCH)/kernel/asm-offsets.s: arch/$(SRCARCH)/kernel/asm-offsets.c \ - $(obj)/$(timeconst-file) $(obj)/$(bounds-file) FORCE - $(Q)mkdir -p $(dir $@) - $(call if_changed_dep,cc_s_c) - -$(obj)/$(offsets-file): arch/$(SRCARCH)/kernel/asm-offsets.s FORCE - $(call filechk,offsets,__ASM_OFFSETS_H__) - -##### -# 4) Check for missing system calls -# - -always += missing-syscalls -targets += missing-syscalls - -quiet_cmd_syscalls = CALL $< - cmd_syscalls = $(CONFIG_SHELL) $< $(CC) $(c_flags) $(missing_syscalls_flags) - -missing-syscalls: scripts/checksyscalls.sh $(offsets-file) FORCE - $(call cmd,syscalls) - -##### -# 5) Generate constants for Python GDB integration -# - -extra-$(CONFIG_GDB_SCRIPTS) += build_constants_py - -build_constants_py: $(obj)/$(timeconst-file) $(obj)/$(bounds-file) - @$(MAKE) $(build)=scripts/gdb/linux $@ - -# Keep these three files during make clean -no-clean-files := $(bounds-file) $(offsets-file) $(timeconst-file) diff --git a/src/linux/Kconfig b/src/linux/Kconfig deleted file mode 100644 index c13f48d..0000000 --- a/src/linux/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see Documentation/kbuild/kconfig-language.txt. -# -mainmenu "Linux/$ARCH $KERNELVERSION Kernel Configuration" - -config SRCARCH - string - option env="SRCARCH" - -source "arch/$SRCARCH/Kconfig" diff --git a/src/linux/Makefile b/src/linux/Makefile deleted file mode 100644 index 35a1e95..0000000 --- a/src/linux/Makefile +++ /dev/null @@ -1,1704 +0,0 @@ -VERSION = 4 -PATCHLEVEL = 9 -SUBLEVEL = 0 -EXTRAVERSION = -NAME = Roaring Lionus - -# *DOCUMENTATION* -# To see a list of typical targets execute "make help" -# More info can be located in ./README -# Comments in this file are targeted only to the developer, do not -# expect to learn how to build the kernel reading this file. - -# o Do not use make's built-in rules and variables -# (this increases performance and avoids hard-to-debug behaviour); -# o Look for make include files relative to root of kernel src -MAKEFLAGS += -rR --include-dir=$(CURDIR) - -# Avoid funny character set dependencies -unexport LC_ALL -LC_COLLATE=C -LC_NUMERIC=C -export LC_COLLATE LC_NUMERIC - -# Avoid interference with shell env settings -unexport GREP_OPTIONS - -# We are using a recursive build, so we need to do a little thinking -# to get the ordering right. -# -# Most importantly: sub-Makefiles should only ever modify files in -# their own directory. If in some directory we have a dependency on -# a file in another dir (which doesn't happen often, but it's often -# unavoidable when linking the built-in.o targets which finally -# turn into vmlinux), we will call a sub make in that other dir, and -# after that we are sure that everything which is in that other dir -# is now up to date. -# -# The only cases where we need to modify files which have global -# effects are thus separated out and done before the recursive -# descending is started. They are now explicitly listed as the -# prepare rule. - -# Beautify output -# --------------------------------------------------------------------------- -# -# Normally, we echo the whole command before executing it. By making -# that echo $($(quiet)$(cmd)), we now have the possibility to set -# $(quiet) to choose other forms of output instead, e.g. -# -# quiet_cmd_cc_o_c = Compiling $(RELDIR)/$@ -# cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< -# -# If $(quiet) is empty, the whole command will be printed. -# If it is set to "quiet_", only the short version will be printed. -# If it is set to "silent_", nothing will be printed at all, since -# the variable $(silent_cmd_cc_o_c) doesn't exist. -# -# A simple variant is to prefix commands with $(Q) - that's useful -# for commands that shall be hidden in non-verbose mode. -# -# $(Q)ln $@ :< -# -# If KBUILD_VERBOSE equals 0 then the above command will be hidden. -# If KBUILD_VERBOSE equals 1 then the above command is displayed. -# -# To put more focus on warnings, be less verbose as default -# Use 'make V=1' to see the full commands - -ifeq ("$(origin V)", "command line") - KBUILD_VERBOSE = $(V) -endif -ifndef KBUILD_VERBOSE - KBUILD_VERBOSE = 0 -endif - -ifeq ($(KBUILD_VERBOSE),1) - quiet = - Q = -else - quiet=quiet_ - Q = @ -endif - -# If the user is running make -s (silent mode), suppress echoing of -# commands - -ifneq ($(filter 4.%,$(MAKE_VERSION)),) # make-4 -ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),) - quiet=silent_ -endif -else # make-3.8x -ifneq ($(filter s% -s%,$(MAKEFLAGS)),) - quiet=silent_ -endif -endif - -export quiet Q KBUILD_VERBOSE - -# kbuild supports saving output files in a separate directory. -# To locate output files in a separate directory two syntaxes are supported. -# In both cases the working directory must be the root of the kernel src. -# 1) O= -# Use "make O=dir/to/store/output/files/" -# -# 2) Set KBUILD_OUTPUT -# Set the environment variable KBUILD_OUTPUT to point to the directory -# where the output files shall be placed. -# export KBUILD_OUTPUT=dir/to/store/output/files/ -# make -# -# The O= assignment takes precedence over the KBUILD_OUTPUT environment -# variable. - -# KBUILD_SRC is set on invocation of make in OBJ directory -# KBUILD_SRC is not intended to be used by the regular user (for now) -ifeq ($(KBUILD_SRC),) - -# OK, Make called in directory where kernel src resides -# Do we want to locate output files in a separate directory? -ifeq ("$(origin O)", "command line") - KBUILD_OUTPUT := $(O) -endif - -# That's our default target when none is given on the command line -PHONY := _all -_all: - -# Cancel implicit rules on top Makefile -$(CURDIR)/Makefile Makefile: ; - -ifneq ($(words $(subst :, ,$(CURDIR))), 1) - $(error main directory cannot contain spaces nor colons) -endif - -ifneq ($(KBUILD_OUTPUT),) -# Invoke a second make in the output directory, passing relevant variables -# check that the output directory actually exists -saved-output := $(KBUILD_OUTPUT) -KBUILD_OUTPUT := $(shell mkdir -p $(KBUILD_OUTPUT) && cd $(KBUILD_OUTPUT) \ - && /bin/pwd) -$(if $(KBUILD_OUTPUT),, \ - $(error failed to create output directory "$(saved-output)")) - -PHONY += $(MAKECMDGOALS) sub-make - -$(filter-out _all sub-make $(CURDIR)/Makefile, $(MAKECMDGOALS)) _all: sub-make - @: - -sub-make: - $(Q)$(MAKE) -C $(KBUILD_OUTPUT) KBUILD_SRC=$(CURDIR) \ - -f $(CURDIR)/Makefile $(filter-out _all sub-make,$(MAKECMDGOALS)) - -# Leave processing to above invocation of make -skip-makefile := 1 -endif # ifneq ($(KBUILD_OUTPUT),) -endif # ifeq ($(KBUILD_SRC),) - -# We process the rest of the Makefile if this is the final invocation of make -ifeq ($(skip-makefile),) - -# Do not print "Entering directory ...", -# but we want to display it when entering to the output directory -# so that IDEs/editors are able to understand relative filenames. -MAKEFLAGS += --no-print-directory - -# Call a source code checker (by default, "sparse") as part of the -# C compilation. -# -# Use 'make C=1' to enable checking of only re-compiled files. -# Use 'make C=2' to enable checking of *all* source files, regardless -# of whether they are re-compiled or not. -# -# See the file "Documentation/sparse.txt" for more details, including -# where to get the "sparse" utility. - -ifeq ("$(origin C)", "command line") - KBUILD_CHECKSRC = $(C) -endif -ifndef KBUILD_CHECKSRC - KBUILD_CHECKSRC = 0 -endif - -# Use make M=dir to specify directory of external module to build -# Old syntax make ... SUBDIRS=$PWD is still supported -# Setting the environment variable KBUILD_EXTMOD take precedence -ifdef SUBDIRS - KBUILD_EXTMOD ?= $(SUBDIRS) -endif - -ifeq ("$(origin M)", "command line") - KBUILD_EXTMOD := $(M) -endif - -# If building an external module we do not care about the all: rule -# but instead _all depend on modules -PHONY += all -ifeq ($(KBUILD_EXTMOD),) -_all: all -else -_all: modules -endif - -ifeq ($(KBUILD_SRC),) - # building in the source tree - srctree := . -else - ifeq ($(KBUILD_SRC)/,$(dir $(CURDIR))) - # building in a subdirectory of the source tree - srctree := .. - else - srctree := $(KBUILD_SRC) - endif -endif -objtree := . -src := $(srctree) -obj := $(objtree) - -VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD)) - -export srctree objtree VPATH - -# SUBARCH tells the usermode build what the underlying arch is. That is set -# first, and if a usermode build is happening, the "ARCH=um" on the command -# line overrides the setting of ARCH below. If a native build is happening, -# then ARCH is assigned, getting whatever value it gets normally, and -# SUBARCH is subsequently ignored. - -SUBARCH := $(shell uname -m | sed -e s/i.86/x86/ -e s/x86_64/x86/ \ - -e s/sun4u/sparc64/ \ - -e s/arm.*/arm/ -e s/sa110/arm/ \ - -e s/s390x/s390/ -e s/parisc64/parisc/ \ - -e s/ppc.*/powerpc/ -e s/mips.*/mips/ \ - -e s/sh[234].*/sh/ -e s/aarch64.*/arm64/ ) - -# Cross compiling and selecting different set of gcc/bin-utils -# --------------------------------------------------------------------------- -# -# When performing cross compilation for other architectures ARCH shall be set -# to the target architecture. (See arch/* for the possibilities). -# ARCH can be set during invocation of make: -# make ARCH=ia64 -# Another way is to have ARCH set in the environment. -# The default ARCH is the host where make is executed. - -# CROSS_COMPILE specify the prefix used for all executables used -# during compilation. Only gcc and related bin-utils executables -# are prefixed with $(CROSS_COMPILE). -# CROSS_COMPILE can be set on the command line -# make CROSS_COMPILE=ia64-linux- -# Alternatively CROSS_COMPILE can be set in the environment. -# A third alternative is to store a setting in .config so that plain -# "make" in the configured kernel build directory always uses that. -# Default value for CROSS_COMPILE is not to prefix executables -# Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile -ARCH ?= $(SUBARCH) -CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%) - -# Architecture as present in compile.h -UTS_MACHINE := $(ARCH) -SRCARCH := $(ARCH) - -# Additional ARCH settings for x86 -ifeq ($(ARCH),i386) - SRCARCH := x86 -endif -ifeq ($(ARCH),x86_64) - SRCARCH := x86 -endif - -# Additional ARCH settings for sparc -ifeq ($(ARCH),sparc32) - SRCARCH := sparc -endif -ifeq ($(ARCH),sparc64) - SRCARCH := sparc -endif - -# Additional ARCH settings for sh -ifeq ($(ARCH),sh64) - SRCARCH := sh -endif - -# Additional ARCH settings for tile -ifeq ($(ARCH),tilepro) - SRCARCH := tile -endif -ifeq ($(ARCH),tilegx) - SRCARCH := tile -endif - -# Where to locate arch specific headers -hdr-arch := $(SRCARCH) - -KCONFIG_CONFIG ?= .config -export KCONFIG_CONFIG - -# SHELL used by kbuild -CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ - else if [ -x /bin/bash ]; then echo /bin/bash; \ - else echo sh; fi ; fi) - -HOSTCC = gcc -HOSTCXX = g++ -HOSTCFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -O2 -fomit-frame-pointer -std=gnu89 -HOSTCXXFLAGS = -O2 - -ifeq ($(shell $(HOSTCC) -v 2>&1 | grep -c "clang version"), 1) -HOSTCFLAGS += -Wno-unused-value -Wno-unused-parameter \ - -Wno-missing-field-initializers -fno-delete-null-pointer-checks -endif - -# Decide whether to build built-in, modular, or both. -# Normally, just do built-in. - -KBUILD_MODULES := -KBUILD_BUILTIN := 1 - -# If we have only "make modules", don't compile built-in objects. -# When we're building modules with modversions, we need to consider -# the built-in objects during the descend as well, in order to -# make sure the checksums are up to date before we record them. - -ifeq ($(MAKECMDGOALS),modules) - KBUILD_BUILTIN := $(if $(CONFIG_MODVERSIONS),1) -endif - -# If we have "make modules", compile modules -# in addition to whatever we do anyway. -# Just "make" or "make all" shall build modules as well - -ifneq ($(filter all _all modules,$(MAKECMDGOALS)),) - KBUILD_MODULES := 1 -endif - -ifeq ($(MAKECMDGOALS),) - KBUILD_MODULES := 1 -endif - -export KBUILD_MODULES KBUILD_BUILTIN -export KBUILD_CHECKSRC KBUILD_SRC KBUILD_EXTMOD - -# We need some generic definitions (do not try to remake the file). -scripts/Kbuild.include: ; -include scripts/Kbuild.include - -# Make variables (CC, etc...) -AS = $(CROSS_COMPILE)as -LD = $(CROSS_COMPILE)ld -CC = $(CROSS_COMPILE)gcc -CPP = $(CC) -E -AR = $(CROSS_COMPILE)ar -NM = $(CROSS_COMPILE)nm -STRIP = $(CROSS_COMPILE)strip -OBJCOPY = $(CROSS_COMPILE)objcopy -OBJDUMP = $(CROSS_COMPILE)objdump -AWK = awk -GENKSYMS = scripts/genksyms/genksyms -INSTALLKERNEL := installkernel -DEPMOD = /sbin/depmod -PERL = perl -PYTHON = python -CHECK = sparse - -CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ \ - -Wbitwise -Wno-return-void $(CF) -NOSTDINC_FLAGS = -CFLAGS_MODULE = -AFLAGS_MODULE = -LDFLAGS_MODULE = -CFLAGS_KERNEL = -AFLAGS_KERNEL = -LDFLAGS_vmlinux = -CFLAGS_GCOV = -fprofile-arcs -ftest-coverage -fno-tree-loop-im -Wno-maybe-uninitialized -CFLAGS_KCOV := $(call cc-option,-fsanitize-coverage=trace-pc,) - - -# Use USERINCLUDE when you must reference the UAPI directories only. -USERINCLUDE := \ - -I$(srctree)/arch/$(hdr-arch)/include/uapi \ - -I$(objtree)/arch/$(hdr-arch)/include/generated/uapi \ - -I$(srctree)/include/uapi \ - -I$(objtree)/include/generated/uapi \ - -include $(srctree)/include/linux/kconfig.h - -# Use LINUXINCLUDE when you must reference the include/ directory. -# Needed to be compatible with the O= option -LINUXINCLUDE := \ - -I$(srctree)/arch/$(hdr-arch)/include \ - -I$(objtree)/arch/$(hdr-arch)/include/generated/uapi \ - -I$(objtree)/arch/$(hdr-arch)/include/generated \ - $(if $(KBUILD_SRC), -I$(srctree)/include) \ - -I$(objtree)/include - -LINUXINCLUDE += $(filter-out $(LINUXINCLUDE),$(USERINCLUDE)) - -KBUILD_CPPFLAGS := -D__KERNEL__ - -KBUILD_CFLAGS := -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs \ - -fno-strict-aliasing -fno-common \ - -Werror-implicit-function-declaration \ - -Wno-format-security \ - -std=gnu89 $(call cc-option,-fno-PIE) - - -KBUILD_AFLAGS_KERNEL := -KBUILD_CFLAGS_KERNEL := -KBUILD_AFLAGS := -D__ASSEMBLY__ $(call cc-option,-fno-PIE) -KBUILD_AFLAGS_MODULE := -DMODULE -KBUILD_CFLAGS_MODULE := -DMODULE -KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds - -# Read KERNELRELEASE from include/config/kernel.release (if it exists) -KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null) -KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION) - -export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION -export ARCH SRCARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC -export CPP AR NM STRIP OBJCOPY OBJDUMP -export MAKE AWK GENKSYMS INSTALLKERNEL PERL PYTHON UTS_MACHINE -export HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS - -export KBUILD_CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS -export KBUILD_CFLAGS CFLAGS_KERNEL CFLAGS_MODULE CFLAGS_GCOV CFLAGS_KCOV CFLAGS_KASAN CFLAGS_UBSAN -export KBUILD_AFLAGS AFLAGS_KERNEL AFLAGS_MODULE -export KBUILD_AFLAGS_MODULE KBUILD_CFLAGS_MODULE KBUILD_LDFLAGS_MODULE -export KBUILD_AFLAGS_KERNEL KBUILD_CFLAGS_KERNEL -export KBUILD_ARFLAGS - -# When compiling out-of-tree modules, put MODVERDIR in the module -# tree rather than in the kernel tree. The kernel tree might -# even be read-only. -export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_versions - -# Files to ignore in find ... statements - -export RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o \ - -name CVS -o -name .pc -o -name .hg -o -name .git \) \ - -prune -o -export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn \ - --exclude CVS --exclude .pc --exclude .hg --exclude .git - -# =========================================================================== -# Rules shared between *config targets and build targets - -# Basic helpers built in scripts/ -PHONY += scripts_basic -scripts_basic: - $(Q)$(MAKE) $(build)=scripts/basic - $(Q)rm -f .tmp_quiet_recordmcount - -# To avoid any implicit rule to kick in, define an empty command. -scripts/basic/%: scripts_basic ; - -PHONY += outputmakefile -# outputmakefile generates a Makefile in the output directory, if using a -# separate output directory. This allows convenient use of make in the -# output directory. -outputmakefile: -ifneq ($(KBUILD_SRC),) - $(Q)ln -fsn $(srctree) source - $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \ - $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL) -endif - -# Support for using generic headers in asm-generic -PHONY += asm-generic -asm-generic: - $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.asm-generic \ - src=asm obj=arch/$(SRCARCH)/include/generated/asm - $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.asm-generic \ - src=uapi/asm obj=arch/$(SRCARCH)/include/generated/uapi/asm - -# To make sure we do not include .config for any of the *config targets -# catch them early, and hand them over to scripts/kconfig/Makefile -# It is allowed to specify more targets when calling make, including -# mixing *config targets and build targets. -# For example 'make oldconfig all'. -# Detect when mixed targets is specified, and make a second invocation -# of make so .config is not included in this case either (for *config). - -version_h := include/generated/uapi/linux/version.h -old_version_h := include/linux/version.h - -no-dot-config-targets := clean mrproper distclean \ - cscope gtags TAGS tags help% %docs check% coccicheck \ - $(version_h) headers_% archheaders archscripts \ - kernelversion %src-pkg - -config-targets := 0 -mixed-targets := 0 -dot-config := 1 - -ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),) - ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),) - dot-config := 0 - endif -endif - -ifeq ($(KBUILD_EXTMOD),) - ifneq ($(filter config %config,$(MAKECMDGOALS)),) - config-targets := 1 - ifneq ($(words $(MAKECMDGOALS)),1) - mixed-targets := 1 - endif - endif -endif -# install and module_install need also be processed one by one -ifneq ($(filter install,$(MAKECMDGOALS)),) - ifneq ($(filter modules_install,$(MAKECMDGOALS)),) - mixed-targets := 1 - endif -endif - -ifeq ($(mixed-targets),1) -# =========================================================================== -# We're called with mixed targets (*config and build targets). -# Handle them one by one. - -PHONY += $(MAKECMDGOALS) __build_one_by_one - -$(filter-out __build_one_by_one, $(MAKECMDGOALS)): __build_one_by_one - @: - -__build_one_by_one: - $(Q)set -e; \ - for i in $(MAKECMDGOALS); do \ - $(MAKE) -f $(srctree)/Makefile $$i; \ - done - -else -ifeq ($(config-targets),1) -# =========================================================================== -# *config targets only - make sure prerequisites are updated, and descend -# in scripts/kconfig to make the *config target - -# Read arch specific Makefile to set KBUILD_DEFCONFIG as needed. -# KBUILD_DEFCONFIG may point out an alternative default configuration -# used for 'make defconfig' -include arch/$(SRCARCH)/Makefile -export KBUILD_DEFCONFIG KBUILD_KCONFIG - -config: scripts_basic outputmakefile FORCE - $(Q)$(MAKE) $(build)=scripts/kconfig $@ - -%config: scripts_basic outputmakefile FORCE - $(Q)$(MAKE) $(build)=scripts/kconfig $@ - -else -# =========================================================================== -# Build targets only - this includes vmlinux, arch specific targets, clean -# targets and others. In general all targets except *config targets. - -ifeq ($(KBUILD_EXTMOD),) -# Additional helpers built in scripts/ -# Carefully list dependencies so we do not try to build scripts twice -# in parallel -PHONY += scripts -scripts: scripts_basic include/config/auto.conf include/config/tristate.conf \ - asm-generic gcc-plugins - $(Q)$(MAKE) $(build)=$(@) - -# Objects we will link into vmlinux / subdirs we need to visit -init-y := init/ -drivers-y := drivers/ sound/ firmware/ -net-y := net/ -libs-y := lib/ -core-y := usr/ -virt-y := virt/ -endif # KBUILD_EXTMOD - -ifeq ($(dot-config),1) -# Read in config --include arch/$(SRCARCH)/auto.conf --include include/config/auto.conf - -ifeq ($(KBUILD_EXTMOD),) -# Read in dependencies to all Kconfig* files, make sure to run -# oldconfig if changes are detected. --include include/config/auto.conf.cmd - -# To avoid any implicit rule to kick in, define an empty command -$(KCONFIG_CONFIG) include/config/auto.conf.cmd: ; - -# If .config is newer than include/config/auto.conf, someone tinkered -# with it and forgot to run make oldconfig. -# if auto.conf.cmd is missing then we are probably in a cleaned tree so -# we execute the config step to be sure to catch updated Kconfig files -include/config/%.conf: $(KCONFIG_CONFIG) include/config/auto.conf.cmd - $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig -else -# external modules needs include/generated/autoconf.h and include/config/auto.conf -# but do not care if they are up-to-date. Use auto.conf to trigger the test -PHONY += include/config/auto.conf - -include/config/auto.conf: - $(Q)test -e include/generated/autoconf.h -a -e $@ || ( \ - echo >&2; \ - echo >&2 " ERROR: Kernel configuration is invalid."; \ - echo >&2 " include/generated/autoconf.h or $@ are missing.";\ - echo >&2 " Run 'make oldconfig && make prepare' on kernel src to fix it."; \ - echo >&2 ; \ - /bin/false) - -endif # KBUILD_EXTMOD - -else -# Dummy target needed, because used as prerequisite -include/config/auto.conf: ; -endif # $(dot-config) - -# For the kernel to actually contain only the needed exported symbols, -# we have to build modules as well to determine what those symbols are. -# (this can be evaluated only once include/config/auto.conf has been included) -ifdef CONFIG_TRIM_UNUSED_KSYMS - KBUILD_MODULES := 1 -endif - -# The all: target is the default when no target is given on the -# command line. -# This allow a user to issue only 'make' to build a kernel including modules -# Defaults to vmlinux, but the arch makefile usually adds further targets -all: vmlinux - -# The arch Makefile can set ARCH_{CPP,A,C}FLAGS to override the default -# values of the respective KBUILD_* variables -ARCH_CPPFLAGS := -ARCH_AFLAGS := -ARCH_CFLAGS := -include arch/$(SRCARCH)/Makefile - -KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,) -KBUILD_CFLAGS += $(call cc-disable-warning,frame-address,) - -ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION -KBUILD_CFLAGS += $(call cc-option,-ffunction-sections,) -KBUILD_CFLAGS += $(call cc-option,-fdata-sections,) -endif - -ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE -KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,) -else -ifdef CONFIG_PROFILE_ALL_BRANCHES -KBUILD_CFLAGS += -O2 $(call cc-disable-warning,maybe-uninitialized,) -else -KBUILD_CFLAGS += -O2 -endif -endif - -KBUILD_CFLAGS += $(call cc-ifversion, -lt, 0409, \ - $(call cc-disable-warning,maybe-uninitialized,)) - -# Tell gcc to never replace conditional load with a non-conditional one -KBUILD_CFLAGS += $(call cc-option,--param=allow-store-data-races=0) - -include scripts/Makefile.gcc-plugins - -ifdef CONFIG_READABLE_ASM -# Disable optimizations that make assembler listings hard to read. -# reorder blocks reorders the control in the function -# ipa clone creates specialized cloned functions -# partial inlining inlines only parts of functions -KBUILD_CFLAGS += $(call cc-option,-fno-reorder-blocks,) \ - $(call cc-option,-fno-ipa-cp-clone,) \ - $(call cc-option,-fno-partial-inlining) -endif - -ifneq ($(CONFIG_FRAME_WARN),0) -KBUILD_CFLAGS += $(call cc-option,-Wframe-larger-than=${CONFIG_FRAME_WARN}) -endif - -# This selects the stack protector compiler flag. Testing it is delayed -# until after .config has been reprocessed, in the prepare-compiler-check -# target. -ifdef CONFIG_CC_STACKPROTECTOR_REGULAR - stackp-flag := -fstack-protector - stackp-name := REGULAR -else -ifdef CONFIG_CC_STACKPROTECTOR_STRONG - stackp-flag := -fstack-protector-strong - stackp-name := STRONG -else - # Force off for distro compilers that enable stack protector by default. - stackp-flag := $(call cc-option, -fno-stack-protector) -endif -endif -# Find arch-specific stack protector compiler sanity-checking script. -ifdef CONFIG_CC_STACKPROTECTOR - stackp-path := $(srctree)/scripts/gcc-$(SRCARCH)_$(BITS)-has-stack-protector.sh - stackp-check := $(wildcard $(stackp-path)) -endif -KBUILD_CFLAGS += $(stackp-flag) - -ifeq ($(cc-name),clang) -KBUILD_CPPFLAGS += $(call cc-option,-Qunused-arguments,) -KBUILD_CPPFLAGS += $(call cc-option,-Wno-unknown-warning-option,) -KBUILD_CFLAGS += $(call cc-disable-warning, unused-variable) -KBUILD_CFLAGS += $(call cc-disable-warning, format-invalid-specifier) -KBUILD_CFLAGS += $(call cc-disable-warning, gnu) -# Quiet clang warning: comparison of unsigned expression < 0 is always false -KBUILD_CFLAGS += $(call cc-disable-warning, tautological-compare) -# CLANG uses a _MergedGlobals as optimization, but this breaks modpost, as the -# source of a reference will be _MergedGlobals and not on of the whitelisted names. -# See modpost pattern 2 -KBUILD_CFLAGS += $(call cc-option, -mno-global-merge,) -KBUILD_CFLAGS += $(call cc-option, -fcatch-undefined-behavior) -else - -# These warnings generated too much noise in a regular build. -# Use make W=1 to enable them (see scripts/Makefile.build) -KBUILD_CFLAGS += $(call cc-disable-warning, unused-but-set-variable) -KBUILD_CFLAGS += $(call cc-disable-warning, unused-const-variable) -endif - -ifdef CONFIG_FRAME_POINTER -KBUILD_CFLAGS += -fno-omit-frame-pointer -fno-optimize-sibling-calls -else -# Some targets (ARM with Thumb2, for example), can't be built with frame -# pointers. For those, we don't have FUNCTION_TRACER automatically -# select FRAME_POINTER. However, FUNCTION_TRACER adds -pg, and this is -# incompatible with -fomit-frame-pointer with current GCC, so we don't use -# -fomit-frame-pointer with FUNCTION_TRACER. -ifndef CONFIG_FUNCTION_TRACER -KBUILD_CFLAGS += -fomit-frame-pointer -endif -endif - -KBUILD_CFLAGS += $(call cc-option, -fno-var-tracking-assignments) - -ifdef CONFIG_DEBUG_INFO -ifdef CONFIG_DEBUG_INFO_SPLIT -KBUILD_CFLAGS += $(call cc-option, -gsplit-dwarf, -g) -else -KBUILD_CFLAGS += -g -endif -KBUILD_AFLAGS += -Wa,-gdwarf-2 -endif -ifdef CONFIG_DEBUG_INFO_DWARF4 -KBUILD_CFLAGS += $(call cc-option, -gdwarf-4,) -endif - -ifdef CONFIG_DEBUG_INFO_REDUCED -KBUILD_CFLAGS += $(call cc-option, -femit-struct-debug-baseonly) \ - $(call cc-option,-fno-var-tracking) -endif - -ifdef CONFIG_FUNCTION_TRACER -ifndef CC_FLAGS_FTRACE -CC_FLAGS_FTRACE := -pg -endif -export CC_FLAGS_FTRACE -ifdef CONFIG_HAVE_FENTRY -CC_USING_FENTRY := $(call cc-option, -mfentry -DCC_USING_FENTRY) -endif -KBUILD_CFLAGS += $(CC_FLAGS_FTRACE) $(CC_USING_FENTRY) -KBUILD_AFLAGS += $(CC_USING_FENTRY) -ifdef CONFIG_DYNAMIC_FTRACE - ifdef CONFIG_HAVE_C_RECORDMCOUNT - BUILD_C_RECORDMCOUNT := y - export BUILD_C_RECORDMCOUNT - endif -endif -endif - -# We trigger additional mismatches with less inlining -ifdef CONFIG_DEBUG_SECTION_MISMATCH -KBUILD_CFLAGS += $(call cc-option, -fno-inline-functions-called-once) -endif - -# arch Makefile may override CC so keep this after arch Makefile is included -NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include) -CHECKFLAGS += $(NOSTDINC_FLAGS) - -# warn about C99 declaration after statement -KBUILD_CFLAGS += $(call cc-option,-Wdeclaration-after-statement,) - -# disable pointer signed / unsigned warnings in gcc 4.0 -KBUILD_CFLAGS += $(call cc-disable-warning, pointer-sign) - -# disable invalid "can't wrap" optimizations for signed / pointers -KBUILD_CFLAGS += $(call cc-option,-fno-strict-overflow) - -# conserve stack if available -KBUILD_CFLAGS += $(call cc-option,-fconserve-stack) - -# disallow errors like 'EXPORT_GPL(foo);' with missing header -KBUILD_CFLAGS += $(call cc-option,-Werror=implicit-int) - -# require functions to have arguments in prototypes, not empty 'int foo()' -KBUILD_CFLAGS += $(call cc-option,-Werror=strict-prototypes) - -# Prohibit date/time macros, which would make the build non-deterministic -KBUILD_CFLAGS += $(call cc-option,-Werror=date-time) - -# enforce correct pointer usage -KBUILD_CFLAGS += $(call cc-option,-Werror=incompatible-pointer-types) - -# use the deterministic mode of AR if available -KBUILD_ARFLAGS := $(call ar-option,D) - -# check for 'asm goto' -ifeq ($(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-goto.sh $(CC)), y) - KBUILD_CFLAGS += -DCC_HAVE_ASM_GOTO - KBUILD_AFLAGS += -DCC_HAVE_ASM_GOTO -endif - -include scripts/Makefile.kasan -include scripts/Makefile.extrawarn -include scripts/Makefile.ubsan - -# Add any arch overrides and user supplied CPPFLAGS, AFLAGS and CFLAGS as the -# last assignments -KBUILD_CPPFLAGS += $(ARCH_CPPFLAGS) $(KCPPFLAGS) -KBUILD_AFLAGS += $(ARCH_AFLAGS) $(KAFLAGS) -KBUILD_CFLAGS += $(ARCH_CFLAGS) $(KCFLAGS) - -# Use --build-id when available. -LDFLAGS_BUILD_ID = $(patsubst -Wl$(comma)%,%,\ - $(call cc-ldoption, -Wl$(comma)--build-id,)) -KBUILD_LDFLAGS_MODULE += $(LDFLAGS_BUILD_ID) -LDFLAGS_vmlinux += $(LDFLAGS_BUILD_ID) - -ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION -LDFLAGS_vmlinux += $(call ld-option, --gc-sections,) -endif - -ifeq ($(CONFIG_STRIP_ASM_SYMS),y) -LDFLAGS_vmlinux += $(call ld-option, -X,) -endif - -# Default kernel image to build when no specific target is given. -# KBUILD_IMAGE may be overruled on the command line or -# set in the environment -# Also any assignments in arch/$(ARCH)/Makefile take precedence over -# this default value -export KBUILD_IMAGE ?= vmlinux - -# -# INSTALL_PATH specifies where to place the updated kernel and system map -# images. Default is /boot, but you can set it to other values -export INSTALL_PATH ?= /boot - -# -# INSTALL_DTBS_PATH specifies a prefix for relocations required by build roots. -# Like INSTALL_MOD_PATH, it isn't defined in the Makefile, but can be passed as -# an argument if needed. Otherwise it defaults to the kernel install path -# -export INSTALL_DTBS_PATH ?= $(INSTALL_PATH)/dtbs/$(KERNELRELEASE) - -# -# INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory -# relocations required by build roots. This is not defined in the -# makefile but the argument can be passed to make if needed. -# - -MODLIB = $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE) -export MODLIB - -# -# INSTALL_MOD_STRIP, if defined, will cause modules to be -# stripped after they are installed. If INSTALL_MOD_STRIP is '1', then -# the default option --strip-debug will be used. Otherwise, -# INSTALL_MOD_STRIP value will be used as the options to the strip command. - -ifdef INSTALL_MOD_STRIP -ifeq ($(INSTALL_MOD_STRIP),1) -mod_strip_cmd = $(STRIP) --strip-debug -else -mod_strip_cmd = $(STRIP) $(INSTALL_MOD_STRIP) -endif # INSTALL_MOD_STRIP=1 -else -mod_strip_cmd = true -endif # INSTALL_MOD_STRIP -export mod_strip_cmd - -# CONFIG_MODULE_COMPRESS, if defined, will cause module to be compressed -# after they are installed in agreement with CONFIG_MODULE_COMPRESS_GZIP -# or CONFIG_MODULE_COMPRESS_XZ. - -mod_compress_cmd = true -ifdef CONFIG_MODULE_COMPRESS - ifdef CONFIG_MODULE_COMPRESS_GZIP - mod_compress_cmd = gzip -n -f - endif # CONFIG_MODULE_COMPRESS_GZIP - ifdef CONFIG_MODULE_COMPRESS_XZ - mod_compress_cmd = xz -f - endif # CONFIG_MODULE_COMPRESS_XZ -endif # CONFIG_MODULE_COMPRESS -export mod_compress_cmd - -# Select initial ramdisk compression format, default is gzip(1). -# This shall be used by the dracut(8) tool while creating an initramfs image. -# -INITRD_COMPRESS-y := gzip -INITRD_COMPRESS-$(CONFIG_RD_BZIP2) := bzip2 -INITRD_COMPRESS-$(CONFIG_RD_LZMA) := lzma -INITRD_COMPRESS-$(CONFIG_RD_XZ) := xz -INITRD_COMPRESS-$(CONFIG_RD_LZO) := lzo -INITRD_COMPRESS-$(CONFIG_RD_LZ4) := lz4 -# do not export INITRD_COMPRESS, since we didn't actually -# choose a sane default compression above. -# export INITRD_COMPRESS := $(INITRD_COMPRESS-y) - -ifdef CONFIG_MODULE_SIG_ALL -$(eval $(call config_filename,MODULE_SIG_KEY)) - -mod_sign_cmd = scripts/sign-file $(CONFIG_MODULE_SIG_HASH) $(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY) certs/signing_key.x509 -else -mod_sign_cmd = true -endif -export mod_sign_cmd - - -ifeq ($(KBUILD_EXTMOD),) -core-y += kernel/ certs/ mm/ fs/ ipc/ security/ crypto/ block/ - -vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ - $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ - $(net-y) $(net-m) $(libs-y) $(libs-m) $(virt-y))) - -vmlinux-alldirs := $(sort $(vmlinux-dirs) $(patsubst %/,%,$(filter %/, \ - $(init-) $(core-) $(drivers-) $(net-) $(libs-) $(virt-)))) - -init-y := $(patsubst %/, %/built-in.o, $(init-y)) -core-y := $(patsubst %/, %/built-in.o, $(core-y)) -drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y)) -net-y := $(patsubst %/, %/built-in.o, $(net-y)) -libs-y1 := $(patsubst %/, %/lib.a, $(libs-y)) -libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y)) -libs-y := $(libs-y1) $(libs-y2) -virt-y := $(patsubst %/, %/built-in.o, $(virt-y)) - -# Externally visible symbols (used by link-vmlinux.sh) -export KBUILD_VMLINUX_INIT := $(head-y) $(init-y) -export KBUILD_VMLINUX_MAIN := $(core-y) $(libs-y) $(drivers-y) $(net-y) $(virt-y) -export KBUILD_LDS := arch/$(SRCARCH)/kernel/vmlinux.lds -export LDFLAGS_vmlinux -# used by scripts/pacmage/Makefile -export KBUILD_ALLDIRS := $(sort $(filter-out arch/%,$(vmlinux-alldirs)) arch Documentation include samples scripts tools) - -vmlinux-deps := $(KBUILD_LDS) $(KBUILD_VMLINUX_INIT) $(KBUILD_VMLINUX_MAIN) - -# Include targets which we want to execute sequentially if the rest of the -# kernel build went well. If CONFIG_TRIM_UNUSED_KSYMS is set, this might be -# evaluated more than once. -PHONY += vmlinux_prereq -vmlinux_prereq: $(vmlinux-deps) FORCE -ifdef CONFIG_HEADERS_CHECK - $(Q)$(MAKE) -f $(srctree)/Makefile headers_check -endif -ifdef CONFIG_GDB_SCRIPTS - $(Q)ln -fsn `cd $(srctree) && /bin/pwd`/scripts/gdb/vmlinux-gdb.py -endif -ifdef CONFIG_TRIM_UNUSED_KSYMS - $(Q)$(CONFIG_SHELL) $(srctree)/scripts/adjust_autoksyms.sh \ - "$(MAKE) -f $(srctree)/Makefile vmlinux" -endif - -# standalone target for easier testing -include/generated/autoksyms.h: FORCE - $(Q)$(CONFIG_SHELL) $(srctree)/scripts/adjust_autoksyms.sh true - -ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink) - -# Final link of vmlinux with optional arch pass after final link - cmd_link-vmlinux = \ - $(CONFIG_SHELL) $< $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) ; \ - $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) - -vmlinux: scripts/link-vmlinux.sh vmlinux_prereq $(vmlinux-deps) FORCE - +$(call if_changed,link-vmlinux) - -# Build samples along the rest of the kernel -ifdef CONFIG_SAMPLES -vmlinux-dirs += samples -endif - -# The actual objects are generated when descending, -# make sure no implicit rule kicks in -$(sort $(vmlinux-deps)): $(vmlinux-dirs) ; - -# Handle descending into subdirectories listed in $(vmlinux-dirs) -# Preset locale variables to speed up the build process. Limit locale -# tweaks to this spot to avoid wrong language settings when running -# make menuconfig etc. -# Error messages still appears in the original language - -PHONY += $(vmlinux-dirs) -$(vmlinux-dirs): prepare scripts - $(Q)$(MAKE) $(build)=$@ - -define filechk_kernel.release - echo "$(KERNELVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))" -endef - -# Store (new) KERNELRELEASE string in include/config/kernel.release -include/config/kernel.release: include/config/auto.conf FORCE - $(call filechk,kernel.release) - - -# Things we need to do before we recursively start building the kernel -# or the modules are listed in "prepare". -# A multi level approach is used. prepareN is processed before prepareN-1. -# archprepare is used in arch Makefiles and when processed asm symlink, -# version.h and scripts_basic is processed / created. - -# Listed in dependency order -PHONY += prepare archprepare prepare0 prepare1 prepare2 prepare3 - -# prepare3 is used to check if we are building in a separate output directory, -# and if so do: -# 1) Check that make has not been executed in the kernel src $(srctree) -prepare3: include/config/kernel.release -ifneq ($(KBUILD_SRC),) - @$(kecho) ' Using $(srctree) as source for kernel' - $(Q)if [ -f $(srctree)/.config -o -d $(srctree)/include/config ]; then \ - echo >&2 " $(srctree) is not clean, please run 'make mrproper'"; \ - echo >&2 " in the '$(srctree)' directory.";\ - /bin/false; \ - fi; -endif - -# prepare2 creates a makefile if using a separate output directory. -# From this point forward, .config has been reprocessed, so any rules -# that need to depend on updated CONFIG_* values can be checked here. -prepare2: prepare3 prepare-compiler-check outputmakefile asm-generic - -prepare1: prepare2 $(version_h) include/generated/utsrelease.h \ - include/config/auto.conf - $(cmd_crmodverdir) - -archprepare: archheaders archscripts prepare1 scripts_basic - -prepare0: archprepare gcc-plugins - $(Q)$(MAKE) $(build)=. - -# All the preparing.. -prepare: prepare0 prepare-objtool - -ifdef CONFIG_STACK_VALIDATION - has_libelf := $(call try-run,\ - echo "int main() {}" | $(HOSTCC) -xc -o /dev/null -lelf -,1,0) - ifeq ($(has_libelf),1) - objtool_target := tools/objtool FORCE - else - $(warning "Cannot use CONFIG_STACK_VALIDATION, please install libelf-dev, libelf-devel or elfutils-libelf-devel") - SKIP_STACK_VALIDATION := 1 - export SKIP_STACK_VALIDATION - endif -endif - -PHONY += prepare-objtool -prepare-objtool: $(objtool_target) - -# Check for CONFIG flags that require compiler support. Abort the build -# after .config has been processed, but before the kernel build starts. -# -# For security-sensitive CONFIG options, we don't want to fallback and/or -# silently change which compiler flags will be used, since that leads to -# producing kernels with different security feature characteristics -# depending on the compiler used. (For example, "But I selected -# CC_STACKPROTECTOR_STRONG! Why did it build with _REGULAR?!") -PHONY += prepare-compiler-check -prepare-compiler-check: FORCE -# Make sure compiler supports requested stack protector flag. -ifdef stackp-name - ifeq ($(call cc-option, $(stackp-flag)),) - @echo Cannot use CONFIG_CC_STACKPROTECTOR_$(stackp-name): \ - $(stackp-flag) not supported by compiler >&2 && exit 1 - endif -endif -# Make sure compiler does not have buggy stack-protector support. -ifdef stackp-check - ifneq ($(shell $(CONFIG_SHELL) $(stackp-check) $(CC) $(KBUILD_CPPFLAGS) $(biarch)),y) - @echo Cannot use CONFIG_CC_STACKPROTECTOR_$(stackp-name): \ - $(stackp-flag) available but compiler is broken >&2 && exit 1 - endif -endif - @: - -# Generate some files -# --------------------------------------------------------------------------- - -# KERNELRELEASE can change from a few different places, meaning version.h -# needs to be updated, so this check is forced on all builds - -uts_len := 64 -define filechk_utsrelease.h - if [ `echo -n "$(KERNELRELEASE)" | wc -c ` -gt $(uts_len) ]; then \ - echo '"$(KERNELRELEASE)" exceeds $(uts_len) characters' >&2; \ - exit 1; \ - fi; \ - (echo \#define UTS_RELEASE \"$(KERNELRELEASE)\";) -endef - -define filechk_version.h - (echo \#define LINUX_VERSION_CODE $(shell \ - expr $(VERSION) \* 65536 + 0$(PATCHLEVEL) \* 256 + 0$(SUBLEVEL)); \ - echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))';) -endef - -$(version_h): $(srctree)/Makefile FORCE - $(call filechk,version.h) - $(Q)rm -f $(old_version_h) - -include/generated/utsrelease.h: include/config/kernel.release FORCE - $(call filechk,utsrelease.h) - -PHONY += headerdep -headerdep: - $(Q)find $(srctree)/include/ -name '*.h' | xargs --max-args 1 \ - $(srctree)/scripts/headerdep.pl -I$(srctree)/include - -# --------------------------------------------------------------------------- -# Firmware install -INSTALL_FW_PATH=$(INSTALL_MOD_PATH)/lib/firmware -export INSTALL_FW_PATH - -PHONY += firmware_install -firmware_install: - @mkdir -p $(objtree)/firmware - $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_install - -# --------------------------------------------------------------------------- -# Kernel headers - -#Default location for installed headers -export INSTALL_HDR_PATH = $(objtree)/usr - -# If we do an all arch process set dst to asm-$(hdr-arch) -hdr-dst = $(if $(KBUILD_HEADERS), dst=include/asm-$(hdr-arch), dst=include/asm) - -PHONY += archheaders -archheaders: - -PHONY += archscripts -archscripts: - -PHONY += __headers -__headers: $(version_h) scripts_basic asm-generic archheaders archscripts - $(Q)$(MAKE) $(build)=scripts build_unifdef - -PHONY += headers_install_all -headers_install_all: - $(Q)$(CONFIG_SHELL) $(srctree)/scripts/headers.sh install - -PHONY += headers_install -headers_install: __headers - $(if $(wildcard $(srctree)/arch/$(hdr-arch)/include/uapi/asm/Kbuild),, \ - $(error Headers not exportable for the $(SRCARCH) architecture)) - $(Q)$(MAKE) $(hdr-inst)=include/uapi - $(Q)$(MAKE) $(hdr-inst)=arch/$(hdr-arch)/include/uapi/asm $(hdr-dst) - -PHONY += headers_check_all -headers_check_all: headers_install_all - $(Q)$(CONFIG_SHELL) $(srctree)/scripts/headers.sh check - -PHONY += headers_check -headers_check: headers_install - $(Q)$(MAKE) $(hdr-inst)=include/uapi HDRCHECK=1 - $(Q)$(MAKE) $(hdr-inst)=arch/$(hdr-arch)/include/uapi/asm $(hdr-dst) HDRCHECK=1 - -# --------------------------------------------------------------------------- -# Kernel selftest - -PHONY += kselftest -kselftest: - $(Q)$(MAKE) -C tools/testing/selftests run_tests - -kselftest-clean: - $(Q)$(MAKE) -C tools/testing/selftests clean - -PHONY += kselftest-merge -kselftest-merge: - $(if $(wildcard $(objtree)/.config),, $(error No .config exists, config your kernel first!)) - $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh \ - -m $(objtree)/.config \ - $(srctree)/tools/testing/selftests/*/config - +$(Q)$(MAKE) -f $(srctree)/Makefile olddefconfig - -# --------------------------------------------------------------------------- -# Modules - -ifdef CONFIG_MODULES - -# By default, build modules as well - -all: modules - -# Build modules -# -# A module can be listed more than once in obj-m resulting in -# duplicate lines in modules.order files. Those are removed -# using awk while concatenating to the final file. - -PHONY += modules -modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) modules.builtin - $(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order - @$(kecho) ' Building modules, stage 2.'; - $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost - $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modbuild - -modules.builtin: $(vmlinux-dirs:%=%/modules.builtin) - $(Q)$(AWK) '!x[$$0]++' $^ > $(objtree)/modules.builtin - -%/modules.builtin: include/config/auto.conf - $(Q)$(MAKE) $(modbuiltin)=$* - - -# Target to prepare building external modules -PHONY += modules_prepare -modules_prepare: prepare scripts - -# Target to install modules -PHONY += modules_install -modules_install: _modinst_ _modinst_post - -PHONY += _modinst_ -_modinst_: - @rm -rf $(MODLIB)/kernel - @rm -f $(MODLIB)/source - @mkdir -p $(MODLIB)/kernel - @ln -s `cd $(srctree) && /bin/pwd` $(MODLIB)/source - @if [ ! $(objtree) -ef $(MODLIB)/build ]; then \ - rm -f $(MODLIB)/build ; \ - ln -s $(CURDIR) $(MODLIB)/build ; \ - fi - @cp -f $(objtree)/modules.order $(MODLIB)/ - @cp -f $(objtree)/modules.builtin $(MODLIB)/ - $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modinst - -# This depmod is only for convenience to give the initial -# boot a modules.dep even before / is mounted read-write. However the -# boot script depmod is the master version. -PHONY += _modinst_post -_modinst_post: _modinst_ - $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.fwinst obj=firmware __fw_modinst - $(call cmd,depmod) - -ifeq ($(CONFIG_MODULE_SIG), y) -PHONY += modules_sign -modules_sign: - $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modsign -endif - -else # CONFIG_MODULES - -# Modules not configured -# --------------------------------------------------------------------------- - -PHONY += modules modules_install -modules modules_install: - @echo >&2 - @echo >&2 "The present kernel configuration has modules disabled." - @echo >&2 "Type 'make config' and enable loadable module support." - @echo >&2 "Then build a kernel with module support enabled." - @echo >&2 - @exit 1 - -endif # CONFIG_MODULES - -### -# Cleaning is done on three levels. -# make clean Delete most generated files -# Leave enough to build external modules -# make mrproper Delete the current configuration, and all generated files -# make distclean Remove editor backup files, patch leftover files and the like - -# Directories & files removed with 'make clean' -CLEAN_DIRS += $(MODVERDIR) - -# Directories & files removed with 'make mrproper' -MRPROPER_DIRS += include/config usr/include include/generated \ - arch/*/include/generated .tmp_objdiff -MRPROPER_FILES += .config .config.old .version .old_version \ - Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \ - signing_key.pem signing_key.priv signing_key.x509 \ - x509.genkey extra_certificates signing_key.x509.keyid \ - signing_key.x509.signer vmlinux-gdb.py - -# clean - Delete most, but leave enough to build external modules -# -clean: rm-dirs := $(CLEAN_DIRS) -clean: rm-files := $(CLEAN_FILES) -clean-dirs := $(addprefix _clean_, . $(vmlinux-alldirs) Documentation samples) - -PHONY += $(clean-dirs) clean archclean vmlinuxclean -$(clean-dirs): - $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@) - -vmlinuxclean: - $(Q)$(CONFIG_SHELL) $(srctree)/scripts/link-vmlinux.sh clean - $(Q)$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) clean) - -clean: archclean vmlinuxclean - -# mrproper - Delete all generated files, including .config -# -mrproper: rm-dirs := $(wildcard $(MRPROPER_DIRS)) -mrproper: rm-files := $(wildcard $(MRPROPER_FILES)) -mrproper-dirs := $(addprefix _mrproper_,Documentation/DocBook scripts) - -PHONY += $(mrproper-dirs) mrproper archmrproper -$(mrproper-dirs): - $(Q)$(MAKE) $(clean)=$(patsubst _mrproper_%,%,$@) - -mrproper: clean archmrproper $(mrproper-dirs) - $(call cmd,rmdirs) - $(call cmd,rmfiles) - -# distclean -# -PHONY += distclean - -distclean: mrproper - @find $(srctree) $(RCS_FIND_IGNORE) \ - \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ - -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ - -o -name '.*.rej' -o -name '*%' -o -name 'core' \) \ - -type f -print | xargs rm -f - - -# Packaging of the kernel to various formats -# --------------------------------------------------------------------------- -# rpm target kept for backward compatibility -package-dir := scripts/package - -%src-pkg: FORCE - $(Q)$(MAKE) $(build)=$(package-dir) $@ -%pkg: include/config/kernel.release FORCE - $(Q)$(MAKE) $(build)=$(package-dir) $@ -rpm: include/config/kernel.release FORCE - $(Q)$(MAKE) $(build)=$(package-dir) $@ - - -# Brief documentation of the typical targets used -# --------------------------------------------------------------------------- - -boards := $(wildcard $(srctree)/arch/$(SRCARCH)/configs/*_defconfig) -boards := $(sort $(notdir $(boards))) -board-dirs := $(dir $(wildcard $(srctree)/arch/$(SRCARCH)/configs/*/*_defconfig)) -board-dirs := $(sort $(notdir $(board-dirs:/=))) - -PHONY += help -help: - @echo 'Cleaning targets:' - @echo ' clean - Remove most generated files but keep the config and' - @echo ' enough build support to build external modules' - @echo ' mrproper - Remove all generated files + config + various backup files' - @echo ' distclean - mrproper + remove editor backup and patch files' - @echo '' - @echo 'Configuration targets:' - @$(MAKE) -f $(srctree)/scripts/kconfig/Makefile help - @echo '' - @echo 'Other generic targets:' - @echo ' all - Build all targets marked with [*]' - @echo '* vmlinux - Build the bare kernel' - @echo '* modules - Build all modules' - @echo ' modules_install - Install all modules to INSTALL_MOD_PATH (default: /)' - @echo ' firmware_install- Install all firmware to INSTALL_FW_PATH' - @echo ' (default: $$(INSTALL_MOD_PATH)/lib/firmware)' - @echo ' dir/ - Build all files in dir and below' - @echo ' dir/file.[ois] - Build specified target only' - @echo ' dir/file.lst - Build specified mixed source/assembly target only' - @echo ' (requires a recent binutils and recent build (System.map))' - @echo ' dir/file.ko - Build module including final link' - @echo ' modules_prepare - Set up for building external modules' - @echo ' tags/TAGS - Generate tags file for editors' - @echo ' cscope - Generate cscope index' - @echo ' gtags - Generate GNU GLOBAL index' - @echo ' kernelrelease - Output the release version string (use with make -s)' - @echo ' kernelversion - Output the version stored in Makefile (use with make -s)' - @echo ' image_name - Output the image name (use with make -s)' - @echo ' headers_install - Install sanitised kernel headers to INSTALL_HDR_PATH'; \ - echo ' (default: $(INSTALL_HDR_PATH))'; \ - echo '' - @echo 'Static analysers' - @echo ' checkstack - Generate a list of stack hogs' - @echo ' namespacecheck - Name space analysis on compiled kernel' - @echo ' versioncheck - Sanity check on version.h usage' - @echo ' includecheck - Check for duplicate included header files' - @echo ' export_report - List the usages of all exported symbols' - @echo ' headers_check - Sanity check on exported headers' - @echo ' headerdep - Detect inclusion cycles in headers' - @$(MAKE) -f $(srctree)/scripts/Makefile.help checker-help - @echo '' - @echo 'Kernel selftest' - @echo ' kselftest - Build and run kernel selftest (run as root)' - @echo ' Build, install, and boot kernel before' - @echo ' running kselftest on it' - @echo ' kselftest-clean - Remove all generated kselftest files' - @echo ' kselftest-merge - Merge all the config dependencies of kselftest to existed' - @echo ' .config.' - @echo '' - @echo 'Kernel packaging:' - @$(MAKE) $(build)=$(package-dir) help - @echo '' - @echo 'Documentation targets:' - @$(MAKE) -f $(srctree)/Documentation/Makefile.sphinx dochelp - @echo '' - @$(MAKE) -f $(srctree)/Documentation/DocBook/Makefile dochelp - @echo '' - @echo 'Architecture specific targets ($(SRCARCH)):' - @$(if $(archhelp),$(archhelp),\ - echo ' No architecture specific help defined for $(SRCARCH)') - @echo '' - @$(if $(boards), \ - $(foreach b, $(boards), \ - printf " %-24s - Build for %s\\n" $(b) $(subst _defconfig,,$(b));) \ - echo '') - @$(if $(board-dirs), \ - $(foreach b, $(board-dirs), \ - printf " %-16s - Show %s-specific targets\\n" help-$(b) $(b);) \ - printf " %-16s - Show all of the above\\n" help-boards; \ - echo '') - - @echo ' make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build' - @echo ' make V=2 [targets] 2 => give reason for rebuild of target' - @echo ' make O=dir [targets] Locate all output files in "dir", including .config' - @echo ' make C=1 [targets] Check all c source with $$CHECK (sparse by default)' - @echo ' make C=2 [targets] Force check of all c source with $$CHECK' - @echo ' make RECORDMCOUNT_WARN=1 [targets] Warn about ignored mcount sections' - @echo ' make W=n [targets] Enable extra gcc checks, n=1,2,3 where' - @echo ' 1: warnings which may be relevant and do not occur too often' - @echo ' 2: warnings which occur quite often but may still be relevant' - @echo ' 3: more obscure warnings, can most likely be ignored' - @echo ' Multiple levels can be combined with W=12 or W=123' - @echo '' - @echo 'Execute "make" or "make all" to build all targets marked with [*] ' - @echo 'For further info see the ./README file' - - -help-board-dirs := $(addprefix help-,$(board-dirs)) - -help-boards: $(help-board-dirs) - -boards-per-dir = $(sort $(notdir $(wildcard $(srctree)/arch/$(SRCARCH)/configs/$*/*_defconfig))) - -$(help-board-dirs): help-%: - @echo 'Architecture specific targets ($(SRCARCH) $*):' - @$(if $(boards-per-dir), \ - $(foreach b, $(boards-per-dir), \ - printf " %-24s - Build for %s\\n" $*/$(b) $(subst _defconfig,,$(b));) \ - echo '') - - -# Documentation targets -# --------------------------------------------------------------------------- -DOC_TARGETS := xmldocs sgmldocs psdocs latexdocs pdfdocs htmldocs mandocs installmandocs epubdocs cleandocs -PHONY += $(DOC_TARGETS) -$(DOC_TARGETS): scripts_basic FORCE - $(Q)$(MAKE) $(build)=scripts build_docproc build_check-lc_ctype - $(Q)$(MAKE) $(build)=Documentation -f $(srctree)/Documentation/Makefile.sphinx $@ - $(Q)$(MAKE) $(build)=Documentation/DocBook $@ - -else # KBUILD_EXTMOD - -### -# External module support. -# When building external modules the kernel used as basis is considered -# read-only, and no consistency checks are made and the make -# system is not used on the basis kernel. If updates are required -# in the basis kernel ordinary make commands (without M=...) must -# be used. -# -# The following are the only valid targets when building external -# modules. -# make M=dir clean Delete all automatically generated files -# make M=dir modules Make all modules in specified dir -# make M=dir Same as 'make M=dir modules' -# make M=dir modules_install -# Install the modules built in the module directory -# Assumes install directory is already created - -# We are always building modules -KBUILD_MODULES := 1 -PHONY += crmodverdir -crmodverdir: - $(cmd_crmodverdir) - -PHONY += $(objtree)/Module.symvers -$(objtree)/Module.symvers: - @test -e $(objtree)/Module.symvers || ( \ - echo; \ - echo " WARNING: Symbol version dump $(objtree)/Module.symvers"; \ - echo " is missing; modules will have no dependencies and modversions."; \ - echo ) - -module-dirs := $(addprefix _module_,$(KBUILD_EXTMOD)) -PHONY += $(module-dirs) modules -$(module-dirs): crmodverdir $(objtree)/Module.symvers - $(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@) - -modules: $(module-dirs) - @$(kecho) ' Building modules, stage 2.'; - $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost - -PHONY += modules_install -modules_install: _emodinst_ _emodinst_post - -install-dir := $(if $(INSTALL_MOD_DIR),$(INSTALL_MOD_DIR),extra) -PHONY += _emodinst_ -_emodinst_: - $(Q)mkdir -p $(MODLIB)/$(install-dir) - $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modinst - -PHONY += _emodinst_post -_emodinst_post: _emodinst_ - $(call cmd,depmod) - -clean-dirs := $(addprefix _clean_,$(KBUILD_EXTMOD)) - -PHONY += $(clean-dirs) clean -$(clean-dirs): - $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@) - -clean: rm-dirs := $(MODVERDIR) -clean: rm-files := $(KBUILD_EXTMOD)/Module.symvers - -PHONY += help -help: - @echo ' Building external modules.' - @echo ' Syntax: make -C path/to/kernel/src M=$$PWD target' - @echo '' - @echo ' modules - default target, build the module(s)' - @echo ' modules_install - install the module' - @echo ' clean - remove generated files in module directory only' - @echo '' - -# Dummies... -PHONY += prepare scripts -prepare: ; -scripts: ; -endif # KBUILD_EXTMOD - -clean: $(clean-dirs) - $(call cmd,rmdirs) - $(call cmd,rmfiles) - @find $(if $(KBUILD_EXTMOD), $(KBUILD_EXTMOD), .) $(RCS_FIND_IGNORE) \ - \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \ - -o -name '*.ko.*' \ - -o -name '*.dwo' \ - -o -name '*.su' \ - -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \ - -o -name '*.symtypes' -o -name 'modules.order' \ - -o -name modules.builtin -o -name '.tmp_*.o.*' \ - -o -name '*.c.[012]*.*' \ - -o -name '*.gcno' \) -type f -print | xargs rm -f - -# Generate tags for editors -# --------------------------------------------------------------------------- -quiet_cmd_tags = GEN $@ - cmd_tags = $(CONFIG_SHELL) $(srctree)/scripts/tags.sh $@ - -tags TAGS cscope gtags: FORCE - $(call cmd,tags) - -# Scripts to check various things for consistency -# --------------------------------------------------------------------------- - -PHONY += includecheck versioncheck coccicheck namespacecheck export_report - -includecheck: - find $(srctree)/* $(RCS_FIND_IGNORE) \ - -name '*.[hcS]' -type f -print | sort \ - | xargs $(PERL) -w $(srctree)/scripts/checkincludes.pl - -versioncheck: - find $(srctree)/* $(RCS_FIND_IGNORE) \ - -name '*.[hcS]' -type f -print | sort \ - | xargs $(PERL) -w $(srctree)/scripts/checkversion.pl - -coccicheck: - $(Q)$(CONFIG_SHELL) $(srctree)/scripts/$@ - -namespacecheck: - $(PERL) $(srctree)/scripts/namespace.pl - -export_report: - $(PERL) $(srctree)/scripts/export_report.pl - -endif #ifeq ($(config-targets),1) -endif #ifeq ($(mixed-targets),1) - -PHONY += checkstack kernelrelease kernelversion image_name - -# UML needs a little special treatment here. It wants to use the host -# toolchain, so needs $(SUBARCH) passed to checkstack.pl. Everyone -# else wants $(ARCH), including people doing cross-builds, which means -# that $(SUBARCH) doesn't work here. -ifeq ($(ARCH), um) -CHECKSTACK_ARCH := $(SUBARCH) -else -CHECKSTACK_ARCH := $(ARCH) -endif -checkstack: - $(OBJDUMP) -d vmlinux $$(find . -name '*.ko') | \ - $(PERL) $(src)/scripts/checkstack.pl $(CHECKSTACK_ARCH) - -kernelrelease: - @echo "$(KERNELVERSION)$$($(CONFIG_SHELL) $(srctree)/scripts/setlocalversion $(srctree))" - -kernelversion: - @echo $(KERNELVERSION) - -image_name: - @echo $(KBUILD_IMAGE) - -# Clear a bunch of variables before executing the submake -tools/: FORCE - $(Q)mkdir -p $(objtree)/tools - $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(shell cd $(objtree) && /bin/pwd) subdir=tools -C $(src)/tools/ - -tools/%: FORCE - $(Q)mkdir -p $(objtree)/tools - $(Q)$(MAKE) LDFLAGS= MAKEFLAGS="$(filter --j% -j,$(MAKEFLAGS))" O=$(shell cd $(objtree) && /bin/pwd) subdir=tools -C $(src)/tools/ $* - -# Single targets -# --------------------------------------------------------------------------- -# Single targets are compatible with: -# - build with mixed source and output -# - build with separate output dir 'make O=...' -# - external modules -# -# target-dir => where to store outputfile -# build-dir => directory in kernel source tree to use - -ifeq ($(KBUILD_EXTMOD),) - build-dir = $(patsubst %/,%,$(dir $@)) - target-dir = $(dir $@) -else - zap-slash=$(filter-out .,$(patsubst %/,%,$(dir $@))) - build-dir = $(KBUILD_EXTMOD)$(if $(zap-slash),/$(zap-slash)) - target-dir = $(if $(KBUILD_EXTMOD),$(dir $<),$(dir $@)) -endif - -%.s: %.c prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) -%.i: %.c prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) -%.o: %.c prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) -%.lst: %.c prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) -%.s: %.S prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) -%.o: %.S prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) -%.symtypes: %.c prepare scripts FORCE - $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) - -# Modules -/: prepare scripts FORCE - $(cmd_crmodverdir) - $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ - $(build)=$(build-dir) -# Make sure the latest headers are built for Documentation -Documentation/ samples/: headers_install -%/: prepare scripts FORCE - $(cmd_crmodverdir) - $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ - $(build)=$(build-dir) -%.ko: prepare scripts FORCE - $(cmd_crmodverdir) - $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ - $(build)=$(build-dir) $(@:.ko=.o) - $(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost - -# FIXME Should go into a make.lib or something -# =========================================================================== - -quiet_cmd_rmdirs = $(if $(wildcard $(rm-dirs)),CLEAN $(wildcard $(rm-dirs))) - cmd_rmdirs = rm -rf $(rm-dirs) - -quiet_cmd_rmfiles = $(if $(wildcard $(rm-files)),CLEAN $(wildcard $(rm-files))) - cmd_rmfiles = rm -f $(rm-files) - -# Run depmod only if we have System.map and depmod is executable -quiet_cmd_depmod = DEPMOD $(KERNELRELEASE) - cmd_depmod = $(CONFIG_SHELL) $(srctree)/scripts/depmod.sh $(DEPMOD) \ - $(KERNELRELEASE) "$(patsubst y,_,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX))" - -# Create temporary dir for module support files -# clean it up only when building all modules -cmd_crmodverdir = $(Q)mkdir -p $(MODVERDIR) \ - $(if $(KBUILD_MODULES),; rm -f $(MODVERDIR)/*) - -# read all saved command lines - -targets := $(wildcard $(sort $(targets))) -cmd_files := $(wildcard .*.cmd $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd)) - -ifneq ($(cmd_files),) - $(cmd_files): ; # Do not try to update included dependency files - include $(cmd_files) -endif - -endif # skip-makefile - -PHONY += FORCE -FORCE: - -# Declare the contents of the .PHONY variable as phony. We keep that -# information in a variable so we can use it in if_changed and friends. -.PHONY: $(PHONY) diff --git a/src/linux/README.md b/src/linux/README.md deleted file mode 120000 index 35c47a9..0000000 --- a/src/linux/README.md +++ /dev/null @@ -1 +0,0 @@ -Documentation/lkl.txt \ No newline at end of file diff --git a/src/linux/arch/.gitignore b/src/linux/arch/.gitignore deleted file mode 100644 index 7414689..0000000 --- a/src/linux/arch/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -i386 -x86_64 diff --git a/src/linux/arch/Kconfig b/src/linux/arch/Kconfig deleted file mode 100644 index 659bdd0..0000000 --- a/src/linux/arch/Kconfig +++ /dev/null @@ -1,772 +0,0 @@ -# -# General architecture dependent options -# - -config KEXEC_CORE - bool - -config OPROFILE - tristate "OProfile system profiling" - depends on PROFILING - depends on HAVE_OPROFILE - select RING_BUFFER - select RING_BUFFER_ALLOW_SWAP - help - OProfile is a profiling system capable of profiling the - whole system, include the kernel, kernel modules, libraries, - and applications. - - If unsure, say N. - -config OPROFILE_EVENT_MULTIPLEX - bool "OProfile multiplexing support (EXPERIMENTAL)" - default n - depends on OPROFILE && X86 - help - The number of hardware counters is limited. The multiplexing - feature enables OProfile to gather more events than counters - are provided by the hardware. This is realized by switching - between events at an user specified time interval. - - If unsure, say N. - -config HAVE_OPROFILE - bool - -config OPROFILE_NMI_TIMER - def_bool y - depends on PERF_EVENTS && HAVE_PERF_EVENTS_NMI && !PPC64 - -config KPROBES - bool "Kprobes" - depends on MODULES - depends on HAVE_KPROBES - select KALLSYMS - help - Kprobes allows you to trap at almost any kernel address and - execute a callback function. register_kprobe() establishes - a probepoint and specifies the callback. Kprobes is useful - for kernel debugging, non-intrusive instrumentation and testing. - If in doubt, say "N". - -config JUMP_LABEL - bool "Optimize very unlikely/likely branches" - depends on HAVE_ARCH_JUMP_LABEL - help - This option enables a transparent branch optimization that - makes certain almost-always-true or almost-always-false branch - conditions even cheaper to execute within the kernel. - - Certain performance-sensitive kernel code, such as trace points, - scheduler functionality, networking code and KVM have such - branches and include support for this optimization technique. - - If it is detected that the compiler has support for "asm goto", - the kernel will compile such branches with just a nop - instruction. When the condition flag is toggled to true, the - nop will be converted to a jump instruction to execute the - conditional block of instructions. - - This technique lowers overhead and stress on the branch prediction - of the processor and generally makes the kernel faster. The update - of the condition is slower, but those are always very rare. - - ( On 32-bit x86, the necessary options added to the compiler - flags may increase the size of the kernel slightly. ) - -config STATIC_KEYS_SELFTEST - bool "Static key selftest" - depends on JUMP_LABEL - help - Boot time self-test of the branch patching code. - -config OPTPROBES - def_bool y - depends on KPROBES && HAVE_OPTPROBES - depends on !PREEMPT - -config KPROBES_ON_FTRACE - def_bool y - depends on KPROBES && HAVE_KPROBES_ON_FTRACE - depends on DYNAMIC_FTRACE_WITH_REGS - help - If function tracer is enabled and the arch supports full - passing of pt_regs to function tracing, then kprobes can - optimize on top of function tracing. - -config UPROBES - def_bool n - help - Uprobes is the user-space counterpart to kprobes: they - enable instrumentation applications (such as 'perf probe') - to establish unintrusive probes in user-space binaries and - libraries, by executing handler functions when the probes - are hit by user-space applications. - - ( These probes come in the form of single-byte breakpoints, - managed by the kernel and kept transparent to the probed - application. ) - -config HAVE_64BIT_ALIGNED_ACCESS - def_bool 64BIT && !HAVE_EFFICIENT_UNALIGNED_ACCESS - help - Some architectures require 64 bit accesses to be 64 bit - aligned, which also requires structs containing 64 bit values - to be 64 bit aligned too. This includes some 32 bit - architectures which can do 64 bit accesses, as well as 64 bit - architectures without unaligned access. - - This symbol should be selected by an architecture if 64 bit - accesses are required to be 64 bit aligned in this way even - though it is not a 64 bit architecture. - - See Documentation/unaligned-memory-access.txt for more - information on the topic of unaligned memory accesses. - -config HAVE_EFFICIENT_UNALIGNED_ACCESS - bool - help - Some architectures are unable to perform unaligned accesses - without the use of get_unaligned/put_unaligned. Others are - unable to perform such accesses efficiently (e.g. trap on - unaligned access and require fixing it up in the exception - handler.) - - This symbol should be selected by an architecture if it can - perform unaligned accesses efficiently to allow different - code paths to be selected for these cases. Some network - drivers, for example, could opt to not fix up alignment - problems with received packets if doing so would not help - much. - - See Documentation/unaligned-memory-access.txt for more - information on the topic of unaligned memory accesses. - -config ARCH_USE_BUILTIN_BSWAP - bool - help - Modern versions of GCC (since 4.4) have builtin functions - for handling byte-swapping. Using these, instead of the old - inline assembler that the architecture code provides in the - __arch_bswapXX() macros, allows the compiler to see what's - happening and offers more opportunity for optimisation. In - particular, the compiler will be able to combine the byteswap - with a nearby load or store and use load-and-swap or - store-and-swap instructions if the architecture has them. It - should almost *never* result in code which is worse than the - hand-coded assembler in . But just in case it - does, the use of the builtins is optional. - - Any architecture with load-and-swap or store-and-swap - instructions should set this. And it shouldn't hurt to set it - on architectures that don't have such instructions. - -config KRETPROBES - def_bool y - depends on KPROBES && HAVE_KRETPROBES - -config USER_RETURN_NOTIFIER - bool - depends on HAVE_USER_RETURN_NOTIFIER - help - Provide a kernel-internal notification when a cpu is about to - switch to user mode. - -config HAVE_IOREMAP_PROT - bool - -config HAVE_KPROBES - bool - -config HAVE_KRETPROBES - bool - -config HAVE_OPTPROBES - bool - -config HAVE_KPROBES_ON_FTRACE - bool - -config HAVE_NMI - bool - -config HAVE_NMI_WATCHDOG - depends on HAVE_NMI - bool -# -# An arch should select this if it provides all these things: -# -# task_pt_regs() in asm/processor.h or asm/ptrace.h -# arch_has_single_step() if there is hardware single-step support -# arch_has_block_step() if there is hardware block-step support -# asm/syscall.h supplying asm-generic/syscall.h interface -# linux/regset.h user_regset interfaces -# CORE_DUMP_USE_REGSET #define'd in linux/elf.h -# TIF_SYSCALL_TRACE calls tracehook_report_syscall_{entry,exit} -# TIF_NOTIFY_RESUME calls tracehook_notify_resume() -# signal delivery calls tracehook_signal_handler() -# -config HAVE_ARCH_TRACEHOOK - bool - -config HAVE_DMA_CONTIGUOUS - bool - -config GENERIC_SMP_IDLE_THREAD - bool - -config GENERIC_IDLE_POLL_SETUP - bool - -# Select if arch init_task initializer is different to init/init_task.c -config ARCH_INIT_TASK - bool - -# Select if arch has its private alloc_task_struct() function -config ARCH_TASK_STRUCT_ALLOCATOR - bool - -# Select if arch has its private alloc_thread_stack() function -config ARCH_THREAD_STACK_ALLOCATOR - bool - -# Select if arch wants to size task_struct dynamically via arch_task_struct_size: -config ARCH_WANTS_DYNAMIC_TASK_STRUCT - bool - -config HAVE_REGS_AND_STACK_ACCESS_API - bool - help - This symbol should be selected by an architecure if it supports - the API needed to access registers and stack entries from pt_regs, - declared in asm/ptrace.h - For example the kprobes-based event tracer needs this API. - -config HAVE_CLK - bool - help - The calls support software clock gating and - thus are a key power management tool on many systems. - -config HAVE_DMA_API_DEBUG - bool - -config HAVE_HW_BREAKPOINT - bool - depends on PERF_EVENTS - -config HAVE_MIXED_BREAKPOINTS_REGS - bool - depends on HAVE_HW_BREAKPOINT - help - Depending on the arch implementation of hardware breakpoints, - some of them have separate registers for data and instruction - breakpoints addresses, others have mixed registers to store - them but define the access type in a control register. - Select this option if your arch implements breakpoints under the - latter fashion. - -config HAVE_USER_RETURN_NOTIFIER - bool - -config HAVE_PERF_EVENTS_NMI - bool - help - System hardware can generate an NMI using the perf event - subsystem. Also has support for calculating CPU cycle events - to determine how many clock cycles in a given period. - -config HAVE_PERF_REGS - bool - help - Support selective register dumps for perf events. This includes - bit-mapping of each registers and a unique architecture id. - -config HAVE_PERF_USER_STACK_DUMP - bool - help - Support user stack dumps for perf event samples. This needs - access to the user stack pointer which is not unified across - architectures. - -config HAVE_ARCH_JUMP_LABEL - bool - -config HAVE_RCU_TABLE_FREE - bool - -config ARCH_HAVE_NMI_SAFE_CMPXCHG - bool - -config HAVE_ALIGNED_STRUCT_PAGE - bool - help - This makes sure that struct pages are double word aligned and that - e.g. the SLUB allocator can perform double word atomic operations - on a struct page for better performance. However selecting this - might increase the size of a struct page by a word. - -config HAVE_CMPXCHG_LOCAL - bool - -config HAVE_CMPXCHG_DOUBLE - bool - -config ARCH_WANT_IPC_PARSE_VERSION - bool - -config ARCH_WANT_COMPAT_IPC_PARSE_VERSION - bool - -config ARCH_WANT_OLD_COMPAT_IPC - select ARCH_WANT_COMPAT_IPC_PARSE_VERSION - bool - -config HAVE_ARCH_SECCOMP_FILTER - bool - help - An arch should select this symbol if it provides all of these things: - - syscall_get_arch() - - syscall_get_arguments() - - syscall_rollback() - - syscall_set_return_value() - - SIGSYS siginfo_t support - - secure_computing is called from a ptrace_event()-safe context - - secure_computing return value is checked and a return value of -1 - results in the system call being skipped immediately. - - seccomp syscall wired up - -config SECCOMP_FILTER - def_bool y - depends on HAVE_ARCH_SECCOMP_FILTER && SECCOMP && NET - help - Enable tasks to build secure computing environments defined - in terms of Berkeley Packet Filter programs which implement - task-defined system call filtering polices. - - See Documentation/prctl/seccomp_filter.txt for details. - -config HAVE_GCC_PLUGINS - bool - help - An arch should select this symbol if it supports building with - GCC plugins. - -menuconfig GCC_PLUGINS - bool "GCC plugins" - depends on HAVE_GCC_PLUGINS - depends on !COMPILE_TEST - help - GCC plugins are loadable modules that provide extra features to the - compiler. They are useful for runtime instrumentation and static analysis. - - See Documentation/gcc-plugins.txt for details. - -config GCC_PLUGIN_CYC_COMPLEXITY - bool "Compute the cyclomatic complexity of a function" - depends on GCC_PLUGINS - help - The complexity M of a function's control flow graph is defined as: - M = E - N + 2P - where - - E = the number of edges - N = the number of nodes - P = the number of connected components (exit nodes). - -config GCC_PLUGIN_SANCOV - bool - depends on GCC_PLUGINS - help - This plugin inserts a __sanitizer_cov_trace_pc() call at the start of - basic blocks. It supports all gcc versions with plugin support (from - gcc-4.5 on). It is based on the commit "Add fuzzing coverage support" - by Dmitry Vyukov . - -config GCC_PLUGIN_LATENT_ENTROPY - bool "Generate some entropy during boot and runtime" - depends on GCC_PLUGINS - help - By saying Y here the kernel will instrument some kernel code to - extract some entropy from both original and artificially created - program state. This will help especially embedded systems where - there is little 'natural' source of entropy normally. The cost - is some slowdown of the boot process (about 0.5%) and fork and - irq processing. - - Note that entropy extracted this way is not cryptographically - secure! - - This plugin was ported from grsecurity/PaX. More information at: - * https://grsecurity.net/ - * https://pax.grsecurity.net/ - -config HAVE_CC_STACKPROTECTOR - bool - help - An arch should select this symbol if: - - its compiler supports the -fstack-protector option - - it has implemented a stack canary (e.g. __stack_chk_guard) - -config CC_STACKPROTECTOR - def_bool n - help - Set when a stack-protector mode is enabled, so that the build - can enable kernel-side support for the GCC feature. - -choice - prompt "Stack Protector buffer overflow detection" - depends on HAVE_CC_STACKPROTECTOR - default CC_STACKPROTECTOR_NONE - help - This option turns on the "stack-protector" GCC feature. This - feature puts, at the beginning of functions, a canary value on - the stack just before the return address, and validates - the value just before actually returning. Stack based buffer - overflows (that need to overwrite this return address) now also - overwrite the canary, which gets detected and the attack is then - neutralized via a kernel panic. - -config CC_STACKPROTECTOR_NONE - bool "None" - help - Disable "stack-protector" GCC feature. - -config CC_STACKPROTECTOR_REGULAR - bool "Regular" - select CC_STACKPROTECTOR - help - Functions will have the stack-protector canary logic added if they - have an 8-byte or larger character array on the stack. - - This feature requires gcc version 4.2 or above, or a distribution - gcc with the feature backported ("-fstack-protector"). - - On an x86 "defconfig" build, this feature adds canary checks to - about 3% of all kernel functions, which increases kernel code size - by about 0.3%. - -config CC_STACKPROTECTOR_STRONG - bool "Strong" - select CC_STACKPROTECTOR - help - Functions will have the stack-protector canary logic added in any - of the following conditions: - - - local variable's address used as part of the right hand side of an - assignment or function argument - - local variable is an array (or union containing an array), - regardless of array type or length - - uses register local variables - - This feature requires gcc version 4.9 or above, or a distribution - gcc with the feature backported ("-fstack-protector-strong"). - - On an x86 "defconfig" build, this feature adds canary checks to - about 20% of all kernel functions, which increases the kernel code - size by about 2%. - -endchoice - -config THIN_ARCHIVES - bool - help - Select this if the architecture wants to use thin archives - instead of ld -r to create the built-in.o files. - -config LD_DEAD_CODE_DATA_ELIMINATION - bool - help - Select this if the architecture wants to do dead code and - data elimination with the linker by compiling with - -ffunction-sections -fdata-sections and linking with - --gc-sections. - - This requires that the arch annotates or otherwise protects - its external entry points from being discarded. Linker scripts - must also merge .text.*, .data.*, and .bss.* correctly into - output sections. Care must be taken not to pull in unrelated - sections (e.g., '.text.init'). Typically '.' in section names - is used to distinguish them from label names / C identifiers. - -config HAVE_ARCH_WITHIN_STACK_FRAMES - bool - help - An architecture should select this if it can walk the kernel stack - frames to determine if an object is part of either the arguments - or local variables (i.e. that it excludes saved return addresses, - and similar) by implementing an inline arch_within_stack_frames(), - which is used by CONFIG_HARDENED_USERCOPY. - -config HAVE_CONTEXT_TRACKING - bool - help - Provide kernel/user boundaries probes necessary for subsystems - that need it, such as userspace RCU extended quiescent state. - Syscalls need to be wrapped inside user_exit()-user_enter() through - the slow path using TIF_NOHZ flag. Exceptions handlers must be - wrapped as well. Irqs are already protected inside - rcu_irq_enter/rcu_irq_exit() but preemption or signal handling on - irq exit still need to be protected. - -config HAVE_VIRT_CPU_ACCOUNTING - bool - -config HAVE_VIRT_CPU_ACCOUNTING_GEN - bool - default y if 64BIT - help - With VIRT_CPU_ACCOUNTING_GEN, cputime_t becomes 64-bit. - Before enabling this option, arch code must be audited - to ensure there are no races in concurrent read/write of - cputime_t. For example, reading/writing 64-bit cputime_t on - some 32-bit arches may require multiple accesses, so proper - locking is needed to protect against concurrent accesses. - - -config HAVE_IRQ_TIME_ACCOUNTING - bool - help - Archs need to ensure they use a high enough resolution clock to - support irq time accounting and then call enable_sched_clock_irqtime(). - -config HAVE_ARCH_TRANSPARENT_HUGEPAGE - bool - -config HAVE_ARCH_HUGE_VMAP - bool - -config HAVE_ARCH_SOFT_DIRTY - bool - -config HAVE_MOD_ARCH_SPECIFIC - bool - help - The arch uses struct mod_arch_specific to store data. Many arches - just need a simple module loader without arch specific data - those - should not enable this. - -config MODULES_USE_ELF_RELA - bool - help - Modules only use ELF RELA relocations. Modules with ELF REL - relocations will give an error. - -config MODULES_USE_ELF_REL - bool - help - Modules only use ELF REL relocations. Modules with ELF RELA - relocations will give an error. - -config HAVE_UNDERSCORE_SYMBOL_PREFIX - bool - help - Some architectures generate an _ in front of C symbols; things like - module loading and assembly files need to know about this. - -config HAVE_IRQ_EXIT_ON_IRQ_STACK - bool - help - Architecture doesn't only execute the irq handler on the irq stack - but also irq_exit(). This way we can process softirqs on this irq - stack instead of switching to a new one when we call __do_softirq() - in the end of an hardirq. - This spares a stack switch and improves cache usage on softirq - processing. - -config PGTABLE_LEVELS - int - default 2 - -config ARCH_HAS_ELF_RANDOMIZE - bool - help - An architecture supports choosing randomized locations for - stack, mmap, brk, and ET_DYN. Defined functions: - - arch_mmap_rnd() - - arch_randomize_brk() - -config HAVE_ARCH_MMAP_RND_BITS - bool - help - An arch should select this symbol if it supports setting a variable - number of bits for use in establishing the base address for mmap - allocations, has MMU enabled and provides values for both: - - ARCH_MMAP_RND_BITS_MIN - - ARCH_MMAP_RND_BITS_MAX - -config HAVE_EXIT_THREAD - bool - help - An architecture implements exit_thread. - -config ARCH_MMAP_RND_BITS_MIN - int - -config ARCH_MMAP_RND_BITS_MAX - int - -config ARCH_MMAP_RND_BITS_DEFAULT - int - -config ARCH_MMAP_RND_BITS - int "Number of bits to use for ASLR of mmap base address" if EXPERT - range ARCH_MMAP_RND_BITS_MIN ARCH_MMAP_RND_BITS_MAX - default ARCH_MMAP_RND_BITS_DEFAULT if ARCH_MMAP_RND_BITS_DEFAULT - default ARCH_MMAP_RND_BITS_MIN - depends on HAVE_ARCH_MMAP_RND_BITS - help - This value can be used to select the number of bits to use to - determine the random offset to the base address of vma regions - resulting from mmap allocations. This value will be bounded - by the architecture's minimum and maximum supported values. - - This value can be changed after boot using the - /proc/sys/vm/mmap_rnd_bits tunable - -config HAVE_ARCH_MMAP_RND_COMPAT_BITS - bool - help - An arch should select this symbol if it supports running applications - in compatibility mode, supports setting a variable number of bits for - use in establishing the base address for mmap allocations, has MMU - enabled and provides values for both: - - ARCH_MMAP_RND_COMPAT_BITS_MIN - - ARCH_MMAP_RND_COMPAT_BITS_MAX - -config ARCH_MMAP_RND_COMPAT_BITS_MIN - int - -config ARCH_MMAP_RND_COMPAT_BITS_MAX - int - -config ARCH_MMAP_RND_COMPAT_BITS_DEFAULT - int - -config ARCH_MMAP_RND_COMPAT_BITS - int "Number of bits to use for ASLR of mmap base address for compatible applications" if EXPERT - range ARCH_MMAP_RND_COMPAT_BITS_MIN ARCH_MMAP_RND_COMPAT_BITS_MAX - default ARCH_MMAP_RND_COMPAT_BITS_DEFAULT if ARCH_MMAP_RND_COMPAT_BITS_DEFAULT - default ARCH_MMAP_RND_COMPAT_BITS_MIN - depends on HAVE_ARCH_MMAP_RND_COMPAT_BITS - help - This value can be used to select the number of bits to use to - determine the random offset to the base address of vma regions - resulting from mmap allocations for compatible applications This - value will be bounded by the architecture's minimum and maximum - supported values. - - This value can be changed after boot using the - /proc/sys/vm/mmap_rnd_compat_bits tunable - -config HAVE_COPY_THREAD_TLS - bool - help - Architecture provides copy_thread_tls to accept tls argument via - normal C parameter passing, rather than extracting the syscall - argument from pt_regs. - -config HAVE_STACK_VALIDATION - bool - help - Architecture supports the 'objtool check' host tool command, which - performs compile-time stack metadata validation. - -config HAVE_ARCH_HASH - bool - default n - help - If this is set, the architecture provides an - file which provides platform-specific implementations of some - functions in or fs/namei.c. - -config ISA_BUS_API - def_bool ISA - -# -# ABI hall of shame -# -config CLONE_BACKWARDS - bool - help - Architecture has tls passed as the 4th argument of clone(2), - not the 5th one. - -config CLONE_BACKWARDS2 - bool - help - Architecture has the first two arguments of clone(2) swapped. - -config CLONE_BACKWARDS3 - bool - help - Architecture has tls passed as the 3rd argument of clone(2), - not the 5th one. - -config ODD_RT_SIGACTION - bool - help - Architecture has unusual rt_sigaction(2) arguments - -config OLD_SIGSUSPEND - bool - help - Architecture has old sigsuspend(2) syscall, of one-argument variety - -config OLD_SIGSUSPEND3 - bool - help - Even weirder antique ABI - three-argument sigsuspend(2) - -config OLD_SIGACTION - bool - help - Architecture has old sigaction(2) syscall. Nope, not the same - as OLD_SIGSUSPEND | OLD_SIGSUSPEND3 - alpha has sigsuspend(2), - but fairly different variant of sigaction(2), thanks to OSF/1 - compatibility... - -config COMPAT_OLD_SIGACTION - bool - -config ARCH_NO_COHERENT_DMA_MMAP - bool - -config CPU_NO_EFFICIENT_FFS - def_bool n - -config HAVE_ARCH_VMAP_STACK - def_bool n - help - An arch should select this symbol if it can support kernel stacks - in vmalloc space. This means: - - - vmalloc space must be large enough to hold many kernel stacks. - This may rule out many 32-bit architectures. - - - Stacks in vmalloc space need to work reliably. For example, if - vmap page tables are created on demand, either this mechanism - needs to work while the stack points to a virtual address with - unpopulated page tables or arch code (switch_to() and switch_mm(), - most likely) needs to ensure that the stack's page table entries - are populated before running on a possibly unpopulated stack. - - - If the stack overflows into a guard page, something reasonable - should happen. The definition of "reasonable" is flexible, but - instantly rebooting without logging anything would be unfriendly. - -config VMAP_STACK - default y - bool "Use a virtually-mapped stack" - depends on HAVE_ARCH_VMAP_STACK && !KASAN - ---help--- - Enable this if you want the use virtually-mapped kernel stacks - with guard pages. This causes kernel stack overflows to be - caught immediately rather than causing difficult-to-diagnose - corruption. - - This is presently incompatible with KASAN because KASAN expects - the stack to map directly to the KASAN shadow map using a formula - that is incorrect if the stack is in vmalloc space. - -source "kernel/gcov/Kconfig" diff --git a/src/linux/arch/alpha/kernel/.gitignore b/src/linux/arch/alpha/kernel/.gitignore deleted file mode 100644 index c5f676c..0000000 --- a/src/linux/arch/alpha/kernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.lds diff --git a/src/linux/arch/arc/boot/.gitignore b/src/linux/arch/arc/boot/.gitignore deleted file mode 100644 index 5246969..0000000 --- a/src/linux/arch/arc/boot/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.dtb* -uImage diff --git a/src/linux/arch/arc/kernel/.gitignore b/src/linux/arch/arc/kernel/.gitignore deleted file mode 100644 index c5f676c..0000000 --- a/src/linux/arch/arc/kernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.lds diff --git a/src/linux/arch/arm/boot/.gitignore b/src/linux/arch/arm/boot/.gitignore deleted file mode 100644 index 3c79f85..0000000 --- a/src/linux/arch/arm/boot/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -Image -zImage -xipImage -bootpImage -uImage -*.dtb diff --git a/src/linux/arch/arm/boot/compressed/.gitignore b/src/linux/arch/arm/boot/compressed/.gitignore deleted file mode 100644 index 86b2f5d..0000000 --- a/src/linux/arch/arm/boot/compressed/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -ashldi3.S -bswapsdi2.S -font.c -lib1funcs.S -hyp-stub.S -piggy_data -vmlinux -vmlinux.lds - -# borrowed libfdt files -fdt.c -fdt.h -fdt_ro.c -fdt_rw.c -fdt_wip.c -libfdt.h -libfdt_internal.h diff --git a/src/linux/arch/arm/boot/dts/include/dt-bindings b/src/linux/arch/arm/boot/dts/include/dt-bindings deleted file mode 120000 index 08c00e4..0000000 --- a/src/linux/arch/arm/boot/dts/include/dt-bindings +++ /dev/null @@ -1 +0,0 @@ -../../../../../include/dt-bindings \ No newline at end of file diff --git a/src/linux/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v1.2.dts b/src/linux/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v1.2.dts deleted file mode 120000 index c2f22fc..0000000 --- a/src/linux/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v1.2.dts +++ /dev/null @@ -1 +0,0 @@ -sun8i-a23-q8-tablet.dts \ No newline at end of file diff --git a/src/linux/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts b/src/linux/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts deleted file mode 120000 index c2f22fc..0000000 --- a/src/linux/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts +++ /dev/null @@ -1 +0,0 @@ -sun8i-a23-q8-tablet.dts \ No newline at end of file diff --git a/src/linux/arch/arm/boot/dts/sun8i-a33-et-q8-v1.6.dts b/src/linux/arch/arm/boot/dts/sun8i-a33-et-q8-v1.6.dts deleted file mode 120000 index 4519fd7..0000000 --- a/src/linux/arch/arm/boot/dts/sun8i-a33-et-q8-v1.6.dts +++ /dev/null @@ -1 +0,0 @@ -sun8i-a33-q8-tablet.dts \ No newline at end of file diff --git a/src/linux/arch/arm/boot/dts/sun8i-a33-ippo-q8h-v1.2.dts b/src/linux/arch/arm/boot/dts/sun8i-a33-ippo-q8h-v1.2.dts deleted file mode 120000 index 4519fd7..0000000 --- a/src/linux/arch/arm/boot/dts/sun8i-a33-ippo-q8h-v1.2.dts +++ /dev/null @@ -1 +0,0 @@ -sun8i-a33-q8-tablet.dts \ No newline at end of file diff --git a/src/linux/arch/arm/crypto/.gitignore b/src/linux/arch/arm/crypto/.gitignore deleted file mode 100644 index 31e1f53..0000000 --- a/src/linux/arch/arm/crypto/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -aesbs-core.S -sha256-core.S -sha512-core.S diff --git a/src/linux/arch/arm/kernel/.gitignore b/src/linux/arch/arm/kernel/.gitignore deleted file mode 100644 index c5f676c..0000000 --- a/src/linux/arch/arm/kernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.lds diff --git a/src/linux/arch/arm/vdso/.gitignore b/src/linux/arch/arm/vdso/.gitignore deleted file mode 100644 index 6b47f6e..0000000 --- a/src/linux/arch/arm/vdso/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -vdso.lds -vdso.so.raw -vdsomunge diff --git a/src/linux/arch/arm64/boot/.gitignore b/src/linux/arch/arm64/boot/.gitignore deleted file mode 100644 index 8dab0bb..0000000 --- a/src/linux/arch/arm64/boot/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -Image -Image.gz diff --git a/src/linux/arch/arm64/boot/dts/.gitignore b/src/linux/arch/arm64/boot/dts/.gitignore deleted file mode 100644 index b60ed20..0000000 --- a/src/linux/arch/arm64/boot/dts/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.dtb diff --git a/src/linux/arch/arm64/boot/dts/arm/vexpress-v2m-rs1.dtsi b/src/linux/arch/arm64/boot/dts/arm/vexpress-v2m-rs1.dtsi deleted file mode 120000 index 68fd0f8..0000000 --- a/src/linux/arch/arm64/boot/dts/arm/vexpress-v2m-rs1.dtsi +++ /dev/null @@ -1 +0,0 @@ -../../../../arm/boot/dts/vexpress-v2m-rs1.dtsi \ No newline at end of file diff --git a/src/linux/arch/arm64/boot/dts/broadcom/bcm2835-rpi.dtsi b/src/linux/arch/arm64/boot/dts/broadcom/bcm2835-rpi.dtsi deleted file mode 120000 index 3937b77..0000000 --- a/src/linux/arch/arm64/boot/dts/broadcom/bcm2835-rpi.dtsi +++ /dev/null @@ -1 +0,0 @@ -../../../../arm/boot/dts/bcm2835-rpi.dtsi \ No newline at end of file diff --git a/src/linux/arch/arm64/boot/dts/broadcom/bcm283x-rpi-smsc9514.dtsi b/src/linux/arch/arm64/boot/dts/broadcom/bcm283x-rpi-smsc9514.dtsi deleted file mode 120000 index dca7c05..0000000 --- a/src/linux/arch/arm64/boot/dts/broadcom/bcm283x-rpi-smsc9514.dtsi +++ /dev/null @@ -1 +0,0 @@ -../../../../arm/boot/dts/bcm283x-rpi-smsc9514.dtsi \ No newline at end of file diff --git a/src/linux/arch/arm64/boot/dts/broadcom/bcm283x.dtsi b/src/linux/arch/arm64/boot/dts/broadcom/bcm283x.dtsi deleted file mode 120000 index 5f54e4c..0000000 --- a/src/linux/arch/arm64/boot/dts/broadcom/bcm283x.dtsi +++ /dev/null @@ -1 +0,0 @@ -../../../../arm/boot/dts/bcm283x.dtsi \ No newline at end of file diff --git a/src/linux/arch/arm64/boot/dts/include/dt-bindings b/src/linux/arch/arm64/boot/dts/include/dt-bindings deleted file mode 120000 index 08c00e4..0000000 --- a/src/linux/arch/arm64/boot/dts/include/dt-bindings +++ /dev/null @@ -1 +0,0 @@ -../../../../../include/dt-bindings \ No newline at end of file diff --git a/src/linux/arch/arm64/boot/dts/socionext/uniphier-pinctrl.dtsi b/src/linux/arch/arm64/boot/dts/socionext/uniphier-pinctrl.dtsi deleted file mode 120000 index f42fb6f..0000000 --- a/src/linux/arch/arm64/boot/dts/socionext/uniphier-pinctrl.dtsi +++ /dev/null @@ -1 +0,0 @@ -../../../../arm/boot/dts/uniphier-pinctrl.dtsi \ No newline at end of file diff --git a/src/linux/arch/arm64/boot/dts/socionext/uniphier-ref-daughter.dtsi b/src/linux/arch/arm64/boot/dts/socionext/uniphier-ref-daughter.dtsi deleted file mode 120000 index 4685a8d..0000000 --- a/src/linux/arch/arm64/boot/dts/socionext/uniphier-ref-daughter.dtsi +++ /dev/null @@ -1 +0,0 @@ -../../../../arm/boot/dts/uniphier-ref-daughter.dtsi \ No newline at end of file diff --git a/src/linux/arch/arm64/boot/dts/socionext/uniphier-support-card.dtsi b/src/linux/arch/arm64/boot/dts/socionext/uniphier-support-card.dtsi deleted file mode 120000 index 1246db9..0000000 --- a/src/linux/arch/arm64/boot/dts/socionext/uniphier-support-card.dtsi +++ /dev/null @@ -1 +0,0 @@ -../../../../arm/boot/dts/uniphier-support-card.dtsi \ No newline at end of file diff --git a/src/linux/arch/arm64/kernel/.gitignore b/src/linux/arch/arm64/kernel/.gitignore deleted file mode 100644 index c5f676c..0000000 --- a/src/linux/arch/arm64/kernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.lds diff --git a/src/linux/arch/arm64/kernel/vdso/.gitignore b/src/linux/arch/arm64/kernel/vdso/.gitignore deleted file mode 100644 index b8cc94e..0000000 --- a/src/linux/arch/arm64/kernel/vdso/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -vdso.lds -vdso-offsets.h diff --git a/src/linux/arch/avr32/boot/images/.gitignore b/src/linux/arch/avr32/boot/images/.gitignore deleted file mode 100644 index 64ea9d0..0000000 --- a/src/linux/arch/avr32/boot/images/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -uImage -uImage.srec -vmlinux.cso -sfdwarf.log diff --git a/src/linux/arch/avr32/kernel/.gitignore b/src/linux/arch/avr32/kernel/.gitignore deleted file mode 100644 index c5f676c..0000000 --- a/src/linux/arch/avr32/kernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.lds diff --git a/src/linux/arch/blackfin/boot/.gitignore b/src/linux/arch/blackfin/boot/.gitignore deleted file mode 100644 index 1287a54..0000000 --- a/src/linux/arch/blackfin/boot/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -vmImage* -vmlinux* -uImage* diff --git a/src/linux/arch/blackfin/kernel/.gitignore b/src/linux/arch/blackfin/kernel/.gitignore deleted file mode 100644 index c5f676c..0000000 --- a/src/linux/arch/blackfin/kernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.lds diff --git a/src/linux/arch/cris/boot/.gitignore b/src/linux/arch/cris/boot/.gitignore deleted file mode 100644 index 171a085..0000000 --- a/src/linux/arch/cris/boot/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -Image -zImage diff --git a/src/linux/arch/cris/boot/dts/include/dt-bindings b/src/linux/arch/cris/boot/dts/include/dt-bindings deleted file mode 120000 index 08c00e4..0000000 --- a/src/linux/arch/cris/boot/dts/include/dt-bindings +++ /dev/null @@ -1 +0,0 @@ -../../../../../include/dt-bindings \ No newline at end of file diff --git a/src/linux/arch/ia64/kernel/.gitignore b/src/linux/arch/ia64/kernel/.gitignore deleted file mode 100644 index 21cb0da..0000000 --- a/src/linux/arch/ia64/kernel/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -gate.lds -vmlinux.lds diff --git a/src/linux/arch/lkl/.gitignore b/src/linux/arch/lkl/.gitignore deleted file mode 100644 index c619b7d..0000000 --- a/src/linux/arch/lkl/.gitignore +++ /dev/null @@ -1 +0,0 @@ -kernel/vmlinux.lds diff --git a/src/linux/arch/lkl/Kconfig b/src/linux/arch/lkl/Kconfig deleted file mode 100644 index 568364a..0000000 --- a/src/linux/arch/lkl/Kconfig +++ /dev/null @@ -1,80 +0,0 @@ -config LKL - def_bool y - depends on !SMP && !MMU && !COREDUMP && !SECCOMP && !UPROBES && !COMPAT && !USER_RETURN_NOTIFIER - select ARCH_THREAD_STACK_ALLOCATOR - select RWSEM_GENERIC_SPINLOCK - select GENERIC_ATOMIC64 - select SEMAPHORE_SLEEPERS - select GENERIC_TIME - select GENERIC_FIND_NEXT_BIT - select GENERIC_HWEIGHT - select GENERIC_HARDIRQS - select FLATMEM - select FLAT_NODE_MEM_MAP - select GENERIC_CLOCKEVENTS - select GENERIC_CPU_DEVICES - select NO_HZ_IDLE - select NO_PREEMPT - select ARCH_WANT_FRAME_POINTERS - select HAS_DMA - select PHYS_ADDR_T_64BIT if 64BIT - select 64BIT if OUTPUT_FORMAT = "elf64-x86-64" - select HAVE_UNDERSCORE_SYMBOL_PREFIX if OUTPUT_FORMAT = "pe-i386" - select 64BIT if OUTPUT_FORMAT = "elf64-x86-64-freebsd" - select IP_PNP - select IP_PNP_DHCP - -config OUTPUTFORMAT - string - option env="OUTPUT_FORMAT" - -config OUTPUT_FORMAT - string "Output format" - default OUTPUTFORMAT - -config ARCH_DMA_ADDR_T_64BIT - def_bool 64BIT - -config 64BIT - def_bool n - -config BIG_ENDIAN - def_bool n - -config GENERIC_CSUM - def_bool y - -config GENERIC_HWEIGHT - def_bool y - -config NO_IOPORT_MAP - def_bool y - -config RWSEM_GENERIC_SPINLOCK - bool - default y - -source init/Kconfig - -source net/Kconfig - -source drivers/Kconfig - -source fs/Kconfig - -source mm/Kconfig - -source kernel/Kconfig.preempt - -source kernel/Kconfig.locks - -source kernel/Kconfig.hz - -source security/Kconfig - -source crypto/Kconfig - -source lib/Kconfig - -source lib/Kconfig.debug - diff --git a/src/linux/arch/lkl/Makefile b/src/linux/arch/lkl/Makefile deleted file mode 100644 index 84efa75..0000000 --- a/src/linux/arch/lkl/Makefile +++ /dev/null @@ -1,56 +0,0 @@ -include arch/lkl/auto.conf - -KBUILD_CFLAGS += -fno-builtin - -ifneq (,$(filter $(OUTPUT_FORMAT),elf64-x86-64 elf64-x86-64-freebsd elf32-littlearm )) -KBUILD_CFLAGS += -fPIC -else ifeq ($(OUTPUT_FORMAT),pe-i386) -prefix=_ -# workaround for #include_next errors -LINUXINCLUDE := -isystem arch/lkl/include/system $(LINUXINCLUDE) -# workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52991 -KBUILD_CFLAGS += -mno-ms-bitfields -else -$(error Unrecognized platform: $(OUTPUT_FORMAT)) -endif - -ifneq (,$(filter $(OUTPUT_FORMAT),elf64-x86-64-freebsd)) -NPROC=$(shell sysctl -n hw.ncpu) -else -NPROC=$(shell nproc) -endif - -LDFLAGS_vmlinux += -r -LKL_ENTRY_POINTS := lkl_start_kernel lkl_sys_halt lkl_syscall lkl_trigger_irq \ - lkl_get_free_irq lkl_put_irq lkl_create_syscall_thread \ - lkl_stop_syscall_thread lkl_is_running - -core-y += arch/lkl/kernel/ -core-y += arch/lkl/mm/ - -all: lkl.o - -lkl.o: vmlinux - $(OBJCOPY) -R .eh_frame -R .syscall_defs $(foreach sym,$(LKL_ENTRY_POINTS),-G$(prefix)$(sym)) vmlinux lkl.o - -arch/lkl/include/generated/uapi/asm/syscall_defs.h: vmlinux - $(OBJCOPY) -j .syscall_defs -O binary --set-section-flags .syscall_defs=alloc $< $@ - sed -i 's/\x0//g' $@ - -install: lkl.o __headers arch/lkl/include/generated/uapi/asm/syscall_defs.h - @echo " INSTALL $(INSTALL_PATH)/lib/lkl.o" - @mkdir -p $(INSTALL_PATH)/lib/ - @cp lkl.o $(INSTALL_PATH)/lib/ - @$(srctree)/arch/lkl/scripts/headers_install.py \ - $(subst -j,-j$(NPROC),$(findstring -j,$(MAKEFLAGS))) \ - $(INSTALL_PATH)/include - -archclean: - $(Q)$(MAKE) $(clean)=$(boot) - -define archhelp - echo ' install - Install library and headers to INSTALL_PATH/{lib,include}' -endef - - - diff --git a/src/linux/arch/lkl/auto.conf b/src/linux/arch/lkl/auto.conf deleted file mode 100644 index 4bfd65a..0000000 --- a/src/linux/arch/lkl/auto.conf +++ /dev/null @@ -1 +0,0 @@ -export OUTPUT_FORMAT=$(shell $(LD) -r -print-output-format) diff --git a/src/linux/arch/lkl/defconfig b/src/linux/arch/lkl/defconfig deleted file mode 100644 index f91380b..0000000 --- a/src/linux/arch/lkl/defconfig +++ /dev/null @@ -1,95 +0,0 @@ -# CONFIG_LOCALVERSION_AUTO is not set -CONFIG_NO_HZ_IDLE=y -# CONFIG_SYSFS_SYSCALL is not set -CONFIG_KALLSYMS_USE_DATA_SECTION=y -CONFIG_KALLSYMS_ALL=y -# CONFIG_BASE_FULL is not set -# CONFIG_FUTEX is not set -# CONFIG_SIGNALFD is not set -# CONFIG_TIMERFD is not set -# CONFIG_AIO is not set -# CONFIG_ADVISE_SYSCALLS is not set -CONFIG_EMBEDDED=y -# CONFIG_VM_EVENT_COUNTERS is not set -# CONFIG_COMPAT_BRK is not set -# CONFIG_BLK_DEV_BSG is not set -CONFIG_NET=y -CONFIG_INET=y -# CONFIG_WIRELESS is not set -# CONFIG_UEVENT_HELPER is not set -# CONFIG_FW_LOADER is not set -CONFIG_VIRTIO_BLK=y -CONFIG_NETDEVICES=y -CONFIG_VIRTIO_NET=y -# CONFIG_ETHERNET is not set -# CONFIG_WLAN is not set -# CONFIG_VT is not set -CONFIG_VIRTIO_MMIO=y -CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES=y -CONFIG_EXT4_FS=y -CONFIG_EXT4_FS_POSIX_ACL=y -CONFIG_EXT4_FS_SECURITY=y -CONFIG_XFS_FS=y -CONFIG_XFS_POSIX_ACL=y -CONFIG_BTRFS_FS=y -CONFIG_BTRFS_FS_POSIX_ACL=y -# CONFIG_FILE_LOCKING is not set -# CONFIG_DNOTIFY is not set -# CONFIG_INOTIFY_USER is not set -CONFIG_VFAT_FS=y -CONFIG_NLS_CODEPAGE_437=y -CONFIG_NLS_CODEPAGE_737=y -CONFIG_NLS_CODEPAGE_775=y -CONFIG_NLS_CODEPAGE_850=y -CONFIG_NLS_CODEPAGE_852=y -CONFIG_NLS_CODEPAGE_855=y -CONFIG_NLS_CODEPAGE_857=y -CONFIG_NLS_CODEPAGE_860=y -CONFIG_NLS_CODEPAGE_861=y -CONFIG_NLS_CODEPAGE_862=y -CONFIG_NLS_CODEPAGE_863=y -CONFIG_NLS_CODEPAGE_864=y -CONFIG_NLS_CODEPAGE_865=y -CONFIG_NLS_CODEPAGE_866=y -CONFIG_NLS_CODEPAGE_869=y -CONFIG_NLS_CODEPAGE_936=y -CONFIG_NLS_CODEPAGE_950=y -CONFIG_NLS_CODEPAGE_932=y -CONFIG_NLS_CODEPAGE_949=y -CONFIG_NLS_CODEPAGE_874=y -CONFIG_NLS_ISO8859_8=y -CONFIG_NLS_CODEPAGE_1250=y -CONFIG_NLS_CODEPAGE_1251=y -CONFIG_NLS_ASCII=y -CONFIG_NLS_ISO8859_1=y -CONFIG_NLS_ISO8859_2=y -CONFIG_NLS_ISO8859_3=y -CONFIG_NLS_ISO8859_4=y -CONFIG_NLS_ISO8859_5=y -CONFIG_NLS_ISO8859_6=y -CONFIG_NLS_ISO8859_7=y -CONFIG_NLS_ISO8859_9=y -CONFIG_NLS_ISO8859_13=y -CONFIG_NLS_ISO8859_14=y -CONFIG_NLS_ISO8859_15=y -CONFIG_NLS_KOI8_R=y -CONFIG_NLS_KOI8_U=y -CONFIG_NLS_MAC_ROMAN=y -CONFIG_NLS_MAC_CELTIC=y -CONFIG_NLS_MAC_CENTEURO=y -CONFIG_NLS_MAC_CROATIAN=y -CONFIG_NLS_MAC_CYRILLIC=y -CONFIG_NLS_MAC_GAELIC=y -CONFIG_NLS_MAC_GREEK=y -CONFIG_NLS_MAC_ICELAND=y -CONFIG_NLS_MAC_INUIT=y -CONFIG_NLS_MAC_ROMANIAN=y -CONFIG_NLS_MAC_TURKISH=y -CONFIG_NLS_UTF8=y -CONFIG_HZ_100=y -CONFIG_CRYPTO_ANSI_CPRNG=y -CONFIG_PRINTK_TIME=y -CONFIG_DEBUG_INFO=y -CONFIG_DEBUG_INFO_REDUCED=y -# CONFIG_ENABLE_WARN_DEPRECATED is not set -# CONFIG_ENABLE_MUST_CHECK is not set diff --git a/src/linux/arch/lkl/include/asm/Kbuild b/src/linux/arch/lkl/include/asm/Kbuild deleted file mode 100644 index edf6aa2..0000000 --- a/src/linux/arch/lkl/include/asm/Kbuild +++ /dev/null @@ -1,76 +0,0 @@ -generic-y += atomic.h -generic-y += barrier.h -generic-y += bitops.h -generic-y += bug.h -generic-y += bugs.h -generic-y += cache.h -generic-y += cacheflush.h -generic-y += checksum.h -generic-y += cmpxchg-local.h -generic-y += cmpxchg.h -generic-y += cputime.h -generic-y += current.h -generic-y += delay.h -generic-y += device.h -generic-y += div64.h -generic-y += dma.h -generic-y += emergency-restart.h -generic-y += errno.h -generic-y += exec.h -generic-y += ftrace.h -generic-y += futex.h -generic-y += hardirq.h -generic-y += hw_irq.h -generic-y += ioctl.h -generic-y += ipcbuf.h -generic-y += irq_regs.h -generic-y += irqflags.h -generic-y += irq_work.h -generic-y += kdebug.h -generic-y += kmap_types.h -generic-y += linkage.h -generic-y += local.h -generic-y += local64.h -generic-y += mcs_spinlock.h -generic-y += mmu.h -generic-y += mmu_context.h -generic-y += module.h -generic-y += msgbuf.h -generic-y += page.h -generic-y += param.h -generic-y += parport.h -generic-y += pci.h -generic-y += percpu.h -generic-y += pgalloc.h -generic-y += poll.h -generic-y += preempt.h -generic-y += resource.h -generic-y += rwsem.h -generic-y += scatterlist.h -generic-y += seccomp.h -generic-y += sections.h -generic-y += segment.h -generic-y += sembuf.h -generic-y += serial.h -generic-y += shmbuf.h -generic-y += signal.h -generic-y += simd.h -generic-y += sizes.h -generic-y += socket.h -generic-y += sockios.h -generic-y += stat.h -generic-y += statfs.h -generic-y += string.h -generic-y += swab.h -generic-y += switch_to.h -generic-y += termbits.h -generic-y += termios.h -generic-y += time.h -generic-y += timex.h -generic-y += tlb.h -generic-y += tlbflush.h -generic-y += topology.h -generic-y += trace_clock.h -generic-y += uaccess.h -generic-y += unaligned.h -generic-y += word-at-a-time.h diff --git a/src/linux/arch/lkl/include/asm/bitsperlong.h b/src/linux/arch/lkl/include/asm/bitsperlong.h deleted file mode 100644 index 282b081..0000000 --- a/src/linux/arch/lkl/include/asm/bitsperlong.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __LKL_BITSPERLONG_H -#define __LKL_BITSPERLONG_H - -#include - -#define BITS_PER_LONG __BITS_PER_LONG - -#define BITS_PER_LONG_LONG 64 - -#endif - diff --git a/src/linux/arch/lkl/include/asm/byteorder.h b/src/linux/arch/lkl/include/asm/byteorder.h deleted file mode 100644 index 78c9685..0000000 --- a/src/linux/arch/lkl/include/asm/byteorder.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _ASM_LKL_BYTEORDER_H -#define _ASM_LKL_BYTEORDER_H - -#include - -#endif /* _ASM_LKL_BYTEORDER_H */ diff --git a/src/linux/arch/lkl/include/asm/cpu.h b/src/linux/arch/lkl/include/asm/cpu.h deleted file mode 100644 index 67436cd..0000000 --- a/src/linux/arch/lkl/include/asm/cpu.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _ASM_LKL_CPU_H -#define _ASM_LKL_CPU_H - -int lkl_cpu_get(void); -void lkl_cpu_put(void); -int lkl_cpu_try_run_irq(int irq); -int lkl_cpu_init(void); -void lkl_cpu_shutdown(void); -void lkl_cpu_wait_shutdown(void); -void lkl_cpu_wakeup_idle(void); -void lkl_cpu_change_owner(lkl_thread_t owner); -void lkl_cpu_set_irqs_pending(void); -void lkl_idle_tail_schedule(void); -int lkl_cpu_idle_pending(void); -extern void cpu_idle_loop(void); - -#endif /* _ASM_LKL_CPU_H */ diff --git a/src/linux/arch/lkl/include/asm/dma-mapping.h b/src/linux/arch/lkl/include/asm/dma-mapping.h deleted file mode 100644 index 2d768c6..0000000 --- a/src/linux/arch/lkl/include/asm/dma-mapping.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _ASM_LKL_DMA_MAPPING_H -#define _ASM_LKL_DMA_MAPPING_H - -static inline struct dma_map_ops *get_dma_ops(struct device *dev) -{ - return &dma_noop_ops; -} - -static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size, - enum dma_data_direction direction) -{ -} - -static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) -{ - if (!dev->dma_mask) - return false; - return addr + size - 1 <= *dev->dma_mask; -} - -#endif diff --git a/src/linux/arch/lkl/include/asm/elf.h b/src/linux/arch/lkl/include/asm/elf.h deleted file mode 100644 index cada3ab..0000000 --- a/src/linux/arch/lkl/include/asm/elf.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _ASM_LKL_ELF_H -#define _ASM_LKL_ELF_H - -#define elf_check_arch(x) 0 - -#ifdef CONFIG_64BIT -#define ELF_CLASS ELFCLASS64 -#else -#define ELF_CLASS ELFCLASS32 -#endif - -#endif - diff --git a/src/linux/arch/lkl/include/asm/host_ops.h b/src/linux/arch/lkl/include/asm/host_ops.h deleted file mode 100644 index 90d07a9..0000000 --- a/src/linux/arch/lkl/include/asm/host_ops.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _ASM_LKL_HOST_OPS_H -#define _ASM_LKL_HOST_OPS_H - -#include "irq.h" -#include - -extern struct lkl_host_operations *lkl_ops; - -#define lkl_puts(text) lkl_ops->print(text, strlen(text)) - -#endif diff --git a/src/linux/arch/lkl/include/asm/io.h b/src/linux/arch/lkl/include/asm/io.h deleted file mode 100644 index fd6f4af..0000000 --- a/src/linux/arch/lkl/include/asm/io.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef _ASM_LKL_IO_H -#define _ASM_LKL_IO_H - -#include -#include - -#define __raw_readb __raw_readb -static inline u8 __raw_readb(const volatile void __iomem *addr) -{ - int ret; - u8 value; - - ret = lkl_ops->iomem_access(addr, &value, sizeof(value), 0); - WARN(ret, "error reading iomem %p", addr); - - return value; -} - -#define __raw_readw __raw_readw -static inline u16 __raw_readw(const volatile void __iomem *addr) -{ - int ret; - u16 value; - - ret = lkl_ops->iomem_access(addr, &value, sizeof(value), 0); - WARN(ret, "error reading iomem %p", addr); - - return value; -} - -#define __raw_readl __raw_readl -static inline u32 __raw_readl(const volatile void __iomem *addr) -{ - int ret; - u32 value; - - ret = lkl_ops->iomem_access(addr, &value, sizeof(value), 0); - WARN(ret, "error reading iomem %p", addr); - - return value; -} - -#ifdef CONFIG_64BIT -#define __raw_readq __raw_readq -static inline u64 __raw_readq(const volatile void __iomem *addr) -{ - int ret; - u64 value; - - ret = lkl_ops->iomem_access(addr, &value, sizeof(value), 0); - WARN(ret, "error reading iomem %p", addr); - - return value; -} -#endif /* CONFIG_64BIT */ - -#define __raw_writeb __raw_writeb -static inline void __raw_writeb(u8 value, volatile void __iomem *addr) -{ - int ret; - - ret = lkl_ops->iomem_access(addr, &value, sizeof(value), 1); - WARN(ret, "error writing iomem %p", addr); -} - -#define __raw_writew __raw_writew -static inline void __raw_writew(u16 value, volatile void __iomem *addr) -{ - int ret; - - ret = lkl_ops->iomem_access(addr, &value, sizeof(value), 1); - WARN(ret, "error writing iomem %p", addr); -} - -#define __raw_writel __raw_writel -static inline void __raw_writel(u32 value, volatile void __iomem *addr) -{ - int ret; - - ret = lkl_ops->iomem_access(addr, &value, sizeof(value), 1); - WARN(ret, "error writing iomem %p", addr); -} - -#ifdef CONFIG_64BIT -#define __raw_writeq __raw_writeq -static inline void __raw_writeq(u64 value, volatile void __iomem *addr) -{ - int ret; - - ret = lkl_ops->iomem_access(addr, &value, sizeof(value), 1); - WARN(ret, "error writing iomem %p", addr); -} -#endif /* CONFIG_64BIT */ - -#define ioremap ioremap -static inline void __iomem *ioremap(phys_addr_t offset, size_t size) -{ - return (void __iomem *)lkl_ops->ioremap(offset, size); -} - -#include - -#endif /* _ASM_LKL_IO_H */ - diff --git a/src/linux/arch/lkl/include/asm/irq.h b/src/linux/arch/lkl/include/asm/irq.h deleted file mode 100644 index 975894e..0000000 --- a/src/linux/arch/lkl/include/asm/irq.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _ASM_LKL_IRQ_H -#define _ASM_LKL_IRQ_H - -#define IRQ_STATUS_BITS (sizeof(long) * 8) -#define NR_IRQS ((int)(IRQ_STATUS_BITS * IRQ_STATUS_BITS)) - -void run_irqs(void); -void set_irq_pending(int irq); - -#include - -#endif diff --git a/src/linux/arch/lkl/include/asm/mutex.h b/src/linux/arch/lkl/include/asm/mutex.h deleted file mode 100644 index 77c2c53..0000000 --- a/src/linux/arch/lkl/include/asm/mutex.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _ASM_LKL_MUTEX_H -#define _ASM_LKL_MUTEX_H - -#include - -#endif - diff --git a/src/linux/arch/lkl/include/asm/page.h b/src/linux/arch/lkl/include/asm/page.h deleted file mode 100644 index df5db97..0000000 --- a/src/linux/arch/lkl/include/asm/page.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _ASM_LKL_PAGE_H -#define _ASM_LKL_PAGE_H - -#define CONFIG_KERNEL_RAM_BASE_ADDRESS memory_start - -#ifndef __ASSEMBLY__ -void free_mem(void); -void bootmem_init(unsigned long mem_size); -#endif - -#include - -#endif /* _ASM_LKL_PAGE_H */ diff --git a/src/linux/arch/lkl/include/asm/pgtable.h b/src/linux/arch/lkl/include/asm/pgtable.h deleted file mode 100644 index 9bb4593..0000000 --- a/src/linux/arch/lkl/include/asm/pgtable.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef _LKL_PGTABLE_H -#define _LKL_PGTABLE_H - -#include - -/* - * (C) Copyright 2000-2002, Greg Ungerer - */ - -#include -#include -#include - -#define pgd_present(pgd) (1) -#define pgd_none(pgd) (0) -#define pgd_bad(pgd) (0) -#define pgd_clear(pgdp) -#define kern_addr_valid(addr) (1) -#define pmd_offset(a, b) ((void *)0) - -#define PAGE_NONE __pgprot(0) -#define PAGE_SHARED __pgprot(0) -#define PAGE_COPY __pgprot(0) -#define PAGE_READONLY __pgprot(0) -#define PAGE_KERNEL __pgprot(0) - -void paging_init(void); -#define swapper_pg_dir ((pgd_t *)0) - -#define __swp_type(x) (0) -#define __swp_offset(x) (0) -#define __swp_entry(typ, off) ((swp_entry_t) { ((typ) | ((off) << 7)) }) -#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) -#define __swp_entry_to_pte(x) ((pte_t) { (x).val }) - -/* - * ZERO_PAGE is a global shared page that is always zero: used - * for zero-mapped memory areas etc.. - */ -extern void *empty_zero_page; -#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) - -/* - * No page table caches to initialise. - */ -#define pgtable_cache_init() do { } while (0) - -/* - * All 32bit addresses are effectively valid for vmalloc... - * Sort of meaningless for non-VM targets. - */ -#define VMALLOC_START 0 -#define VMALLOC_END 0xffffffff -#define KMAP_START 0 -#define KMAP_END 0xffffffff - -#include - -#define check_pgt_cache() do { } while (0) - -#endif diff --git a/src/linux/arch/lkl/include/asm/processor.h b/src/linux/arch/lkl/include/asm/processor.h deleted file mode 100644 index 76b38f1..0000000 --- a/src/linux/arch/lkl/include/asm/processor.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef _ASM_LKL_PROCESSOR_H -#define _ASM_LKL_PROCESSOR_H - -struct task_struct; - -static inline void cpu_relax(void) -{ - unsigned long flags; - - /* since this is usually called in a tight loop waiting for some - * external condition (e.g. jiffies) lets run interrupts now to allow - * the external condition to propagate */ - local_irq_save(flags); - local_irq_restore(flags); -} - -#define current_text_addr() ({ __label__ _l; _l: &&_l; }) - -static inline unsigned long thread_saved_pc(struct task_struct *tsk) -{ - return 0; -} - -static inline void release_thread(struct task_struct *dead_task) -{ -} - -static inline void prepare_to_copy(struct task_struct *tsk) -{ -} - -static inline unsigned long get_wchan(struct task_struct *p) -{ - return 0; -} - -static inline void flush_thread(void) -{ -} - -static inline void trap_init(void) -{ -} - -struct thread_struct { }; - -#define INIT_THREAD { } - -#define task_pt_regs(tsk) (struct pt_regs *)(NULL) - -/* We don't have strict user/kernel spaces */ -#define TASK_SIZE ((unsigned long)-1) -#define TASK_UNMAPPED_BASE 0 - -#define KSTK_EIP(tsk) (0) -#define KSTK_ESP(tsk) (0) - -#endif diff --git a/src/linux/arch/lkl/include/asm/ptrace.h b/src/linux/arch/lkl/include/asm/ptrace.h deleted file mode 100644 index 9d9b70c..0000000 --- a/src/linux/arch/lkl/include/asm/ptrace.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _ASM_LKL_PTRACE_H -#define _ASM_LKL_PTRACE_H - -#include - -struct task_struct; - -#define user_mode(regs) 0 -#define kernel_mode(regs) 1 -#define profile_pc(regs) 0 -#define instruction_pointer(regs) 0 -#define user_stack_pointer(regs) 0 - -static inline long arch_ptrace(struct task_struct *child, - long request, unsigned long addr, - unsigned long data) -{ - return -EINVAL; -} - -static inline void ptrace_disable(struct task_struct *child) -{ -} - -#endif diff --git a/src/linux/arch/lkl/include/asm/sched.h b/src/linux/arch/lkl/include/asm/sched.h deleted file mode 100644 index 7154d7f..0000000 --- a/src/linux/arch/lkl/include/asm/sched.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _ASM_LKL_SCHED_H -#define _ASM_LKL_SCHED_H - -#include - -static inline void thread_sched_jb(void) -{ - set_ti_thread_flag(current_thread_info(), TIF_SCHED_JB); - - if (test_ti_thread_flag(current_thread_info(), TIF_HOST_THREAD)) { - set_current_state(TASK_UNINTERRUPTIBLE); - lkl_ops->jmp_buf_set(¤t_thread_info()->sched_jb, - schedule); - } else { - lkl_ops->jmp_buf_set(¤t_thread_info()->sched_jb, - lkl_idle_tail_schedule); - } -} - -void switch_to_host_task(struct task_struct *); - -#endif /* _ASM_LKL_SCHED_H */ diff --git a/src/linux/arch/lkl/include/asm/setup.h b/src/linux/arch/lkl/include/asm/setup.h deleted file mode 100644 index 831a2fe..0000000 --- a/src/linux/arch/lkl/include/asm/setup.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _ASM_LKL_SETUP_H -#define _ASM_LKL_SETUP_H - -#define COMMAND_LINE_SIZE 4096 - -#endif diff --git a/src/linux/arch/lkl/include/asm/syscalls.h b/src/linux/arch/lkl/include/asm/syscalls.h deleted file mode 100644 index 43956b4..0000000 --- a/src/linux/arch/lkl/include/asm/syscalls.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _ASM_LKL_SYSCALLS_H -#define _ASM_LKL_SYSCALLS_H - -int syscalls_init(void); -void syscalls_cleanup(void); -long lkl_syscall(long no, long *params); - -#define sys_mmap sys_mmap_pgoff -#define sys_mmap2 sys_mmap_pgoff -#define sys_clone sys_ni_syscall -#define sys_vfork sys_ni_syscall -#define sys_rt_sigreturn sys_ni_syscall - -#include - -#endif /* _ASM_LKL_SYSCALLS_H */ diff --git a/src/linux/arch/lkl/include/asm/syscalls_32.h b/src/linux/arch/lkl/include/asm/syscalls_32.h deleted file mode 100644 index 9351fe2..0000000 --- a/src/linux/arch/lkl/include/asm/syscalls_32.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _ASM_SYSCALLS_32_H -#define _ASM_SYSCALLS_32_H - -#include -#include -#include -#include - -#if __BITS_PER_LONG == 32 - -/* kernel/syscalls_32.c */ -asmlinkage long sys32_truncate64(const char __user *, unsigned long, unsigned long); -asmlinkage long sys32_ftruncate64(unsigned int, unsigned long, unsigned long); - -#ifdef CONFIG_MMU -struct mmap_arg_struct32; -asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *); -#endif - -asmlinkage long sys32_wait4(pid_t, unsigned int __user *, int, struct rusage __user *); - -asmlinkage long sys32_pread64(unsigned int, char __user *, u32, u32, u32); -asmlinkage long sys32_pwrite64(unsigned int, const char __user *, u32, u32, u32); - -long sys32_fadvise64_64(int, __u32, __u32, __u32, __u32, int); - -asmlinkage ssize_t sys32_readahead(int, unsigned, unsigned, size_t); -asmlinkage long sys32_sync_file_range(int, unsigned, unsigned, - unsigned, unsigned, unsigned int); -asmlinkage long sys32_sync_file_range2(int, unsigned int, - unsigned, unsigned, - unsigned, unsigned); -asmlinkage long sys32_fadvise64(int, unsigned, unsigned, size_t, int); -asmlinkage long sys32_fallocate(int, int, unsigned, - unsigned, unsigned, unsigned); - -#endif /* __BITS_PER_LONG */ - -#endif /* _ASM_SYSCALLS_32_H */ diff --git a/src/linux/arch/lkl/include/asm/thread_info.h b/src/linux/arch/lkl/include/asm/thread_info.h deleted file mode 100644 index de00569..0000000 --- a/src/linux/arch/lkl/include/asm/thread_info.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef _ASM_LKL_THREAD_INFO_H -#define _ASM_LKL_THREAD_INFO_H - -#define THREAD_SIZE (4096) - -#ifndef __ASSEMBLY__ -#include -#include -#include - -typedef struct { - unsigned long seg; -} mm_segment_t; - -struct thread_info { - struct task_struct *task; - unsigned long flags; - int preempt_count; - mm_segment_t addr_limit; - struct lkl_sem *sched_sem; - struct lkl_jmp_buf sched_jb; - bool dead; - lkl_thread_t tid; - struct task_struct *prev_sched; - unsigned long stackend; -}; - -#define INIT_THREAD_INFO(tsk) \ -{ \ - .task = &tsk, \ - .preempt_count = INIT_PREEMPT_COUNT, \ - .flags = 0, \ - .addr_limit = KERNEL_DS, \ -} - -#define init_thread_info (init_thread_union.thread_info) -#define init_stack (init_thread_union.stack) - -/* how to get the thread information struct from C */ -extern struct thread_info *_current_thread_info; -static inline struct thread_info *current_thread_info(void) -{ - return _current_thread_info; -} - -/* thread information allocation */ -unsigned long *alloc_thread_stack_node(struct task_struct *, int node); -void free_thread_stack(struct task_struct *tsk); - -void threads_init(void); -void threads_cleanup(void); - -#define TIF_SYSCALL_TRACE 0 -#define TIF_NOTIFY_RESUME 1 -#define TIF_SIGPENDING 2 -#define TIF_NEED_RESCHED 3 -#define TIF_RESTORE_SIGMASK 4 -#define TIF_MEMDIE 5 -#define TIF_NOHZ 6 -#define TIF_SCHED_JB 7 -#define TIF_HOST_THREAD 8 -#define TIF_IDLE 9 - -#define __HAVE_THREAD_FUNCTIONS - -#define task_thread_info(task) ((struct thread_info *)(task)->stack) -#define task_stack_page(task) ((task)->stack) -void setup_thread_stack(struct task_struct *p, struct task_struct *org); -#define end_of_stack(p) (&task_thread_info(p)->stackend) - -#endif /* __ASSEMBLY__ */ - -#endif diff --git a/src/linux/arch/lkl/include/asm/unistd.h b/src/linux/arch/lkl/include/asm/unistd.h deleted file mode 100644 index c3451df..0000000 --- a/src/linux/arch/lkl/include/asm/unistd.h +++ /dev/null @@ -1,28 +0,0 @@ -#include - -__SYSCALL(__NR_virtio_mmio_device_add, sys_virtio_mmio_device_add) - -#define __SC_ASCII(t, a) #t "," #a - -#define __ASCII_MAP0(m,...) -#define __ASCII_MAP1(m,t,a) m(t,a) -#define __ASCII_MAP2(m,t,a,...) m(t,a) "," __ASCII_MAP1(m,__VA_ARGS__) -#define __ASCII_MAP3(m,t,a,...) m(t,a) "," __ASCII_MAP2(m,__VA_ARGS__) -#define __ASCII_MAP4(m,t,a,...) m(t,a) "," __ASCII_MAP3(m,__VA_ARGS__) -#define __ASCII_MAP5(m,t,a,...) m(t,a) "," __ASCII_MAP4(m,__VA_ARGS__) -#define __ASCII_MAP6(m,t,a,...) m(t,a) "," __ASCII_MAP5(m,__VA_ARGS__) -#define __ASCII_MAP(n,...) __ASCII_MAP##n(__VA_ARGS__) - -#ifdef __MINGW32__ -#define SECTION_ATTRS "n0" -#else -#define SECTION_ATTRS "a" -#endif - -#define __SYSCALL_DEFINE_ARCH(x, name, ...) \ - asm(".section .syscall_defs,\"" SECTION_ATTRS "\"\n" \ - ".ascii \"#ifdef __NR" #name "\\n\"\n" \ - ".ascii \"SYSCALL_DEFINE" #x "(" #name "," \ - __ASCII_MAP(x, __SC_ASCII, __VA_ARGS__) ")\\n\"\n" \ - ".ascii \"#endif\\n\"\n" \ - ".section .text\n"); diff --git a/src/linux/arch/lkl/include/asm/unistd_32.h b/src/linux/arch/lkl/include/asm/unistd_32.h deleted file mode 100644 index 03b8019..0000000 --- a/src/linux/arch/lkl/include/asm/unistd_32.h +++ /dev/null @@ -1,30 +0,0 @@ -#include - -#ifndef __SYSCALL -#define __SYSCALL(x, y) -#endif - -#if __BITS_PER_LONG == 32 -__SYSCALL(__NR3264_truncate, sys32_truncate64) -__SYSCALL(__NR3264_ftruncate, sys32_ftruncate64) - -#ifdef CONFIG_MMU -__SYSCALL(__NR3264_mmap, sys32_mmap) -#endif - -__SYSCALL(__NR_wait4, sys32_wait4) - -__SYSCALL(__NR_pread64, sys32_pread64) -__SYSCALL(__NR_pwrite64, sys32_pwrite64) - -__SYSCALL(__NR_readahead, sys32_readahead) -#ifdef __ARCH_WANT_SYNC_FILE_RANGE2 -__SYSCALL(__NR_sync_file_range2, sys32_sync_file_range2) -#else -__SYSCALL(__NR_sync_file_range, sys32_sync_file_range) -#endif -/* mm/fadvise.c */ -__SYSCALL(__NR3264_fadvise64, sys32_fadvise64_64) -__SYSCALL(__NR_fallocate, sys32_fallocate) - -#endif diff --git a/src/linux/arch/lkl/include/asm/vmlinux.lds.h b/src/linux/arch/lkl/include/asm/vmlinux.lds.h deleted file mode 100644 index 7925b02..0000000 --- a/src/linux/arch/lkl/include/asm/vmlinux.lds.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _LKL_VMLINUX_LDS_H -#define _LKL_VMLINUX_LDS_H - -#ifdef __MINGW32__ -#define RODATA_SECTION .rdata -#define RO_AFTER_INIT_DATA -#endif - -#include - -#endif diff --git a/src/linux/arch/lkl/include/asm/xor.h b/src/linux/arch/lkl/include/asm/xor.h deleted file mode 100644 index ad2be82..0000000 --- a/src/linux/arch/lkl/include/asm/xor.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _ASM_LKL_XOR_H -#define _ASM_LKL_XOR_H - -#include - -#define XOR_SELECT_TEMPLATE(x) (&xor_block_8regs) - -#endif /* _ASM_LKL_XOR_H */ diff --git a/src/linux/arch/lkl/include/system/stdarg.h b/src/linux/arch/lkl/include/system/stdarg.h deleted file mode 100644 index db463c5..0000000 --- a/src/linux/arch/lkl/include/system/stdarg.h +++ /dev/null @@ -1 +0,0 @@ -/* empty file to avoid #include_next error */ diff --git a/src/linux/arch/lkl/include/uapi/asm/Kbuild b/src/linux/arch/lkl/include/uapi/asm/Kbuild deleted file mode 100644 index 83f0fb9..0000000 --- a/src/linux/arch/lkl/include/uapi/asm/Kbuild +++ /dev/null @@ -1,35 +0,0 @@ -# UAPI Header export list -include include/uapi/asm-generic/Kbuild.asm - -generic-y += auxvec.h -generic-y += elf.h -generic-y += errno.h -generic-y += fcntl.h -generic-y += ioctl.h -generic-y += ioctls.h -generic-y += ipcbuf.h -generic-y += kvm_para.h -generic-y += mman.h -generic-y += msgbuf.h -generic-y += param.h -generic-y += poll.h -generic-y += posix_types.h -generic-y += ptrace.h -generic-y += resource.h -generic-y += sembuf.h -generic-y += setup.h -generic-y += shmbuf.h -generic-y += shmparam.h -generic-y += signal.h -generic-y += socket.h -generic-y += sockios.h -generic-y += stat.h -generic-y += statfs.h -generic-y += swab.h -generic-y += termbits.h -generic-y += termios.h -generic-y += timex.h -generic-y += types.h - -# no header-y since we need special user headers handling -# see arch/lkl/script/headers.py diff --git a/src/linux/arch/lkl/include/uapi/asm/bitsperlong.h b/src/linux/arch/lkl/include/uapi/asm/bitsperlong.h deleted file mode 100644 index 66ab347..0000000 --- a/src/linux/arch/lkl/include/uapi/asm/bitsperlong.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _ASM_UAPI_LKL_BITSPERLONG_H -#define _ASM_UAPI_LKL_BITSPERLONG_H - -#ifdef CONFIG_64BIT -#define __BITS_PER_LONG 64 -#else -#define __BITS_PER_LONG 32 -#endif - -#define __ARCH_WANT_STAT64 - -#endif /* _ASM_UAPI_LKL_BITSPERLONG_H */ diff --git a/src/linux/arch/lkl/include/uapi/asm/byteorder.h b/src/linux/arch/lkl/include/uapi/asm/byteorder.h deleted file mode 100644 index 136f934..0000000 --- a/src/linux/arch/lkl/include/uapi/asm/byteorder.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _ASM_UAPI_LKL_BYTEORDER_H -#define _ASM_UAPI_LKL_BYTEORDER_H - -#if defined(CONFIG_BIG_ENDIAN) -#include -#else -#include -#endif - -#endif /* _ASM_UAPI_LKL_BYTEORDER_H */ diff --git a/src/linux/arch/lkl/include/uapi/asm/host_ops.h b/src/linux/arch/lkl/include/uapi/asm/host_ops.h deleted file mode 100644 index d5de01b..0000000 --- a/src/linux/arch/lkl/include/uapi/asm/host_ops.h +++ /dev/null @@ -1,154 +0,0 @@ -#ifndef _ASM_UAPI_LKL_HOST_OPS_H -#define _ASM_UAPI_LKL_HOST_OPS_H - -/* Defined in {posix,nt}-host.c */ -struct lkl_mutex; -struct lkl_sem; -struct lkl_tls_key; -typedef unsigned long lkl_thread_t; -struct lkl_jmp_buf { - unsigned long buf[32]; -}; - -/** - * lkl_host_operations - host operations used by the Linux kernel - * - * These operations must be provided by a host library or by the application - * itself. - * - * @virtio_devices - string containg the list of virtio devices in virtio mmio - * command line format. This string is appended to the kernel command line and - * is provided here for convenience to be implemented by the host library. - * - * @print - optional operation that receives console messages - * - * @panic - called during a kernel panic - * - * @sem_alloc - allocate a host semaphore an initialize it to count - * @sem_free - free a host semaphore - * @sem_up - perform an up operation on the semaphore - * @sem_down - perform a down operation on the semaphore - * - * @mutex_alloc - allocate and initialize a host mutex; the recursive parameter - * determines if the mutex is recursive or not - * @mutex_free - free a host mutex - * @mutex_lock - acquire the mutex - * @mutex_unlock - release the mutex - * - * @thread_create - create a new thread and run f(arg) in its context; returns a - * thread handle or 0 if the thread could not be created - * @thread_detach - on POSIX systems, free up resources held by - * pthreads. Noop on Win32. - * @thread_exit - terminates the current thread - * @thread_join - wait for the given thread to terminate. Returns 0 - * for success, -1 otherwise - * - * @tls_alloc - allocate a thread local storage key; returns 0 if successful; if - * destructor is not NULL it will be called when a thread terminates with its - * argument set to the current thread local storage value - * @tls_free - frees a thread local storage key; returns 0 if succesful - * @tls_set - associate data to the thread local storage key; returns 0 if - * successful - * @tls_get - return data associated with the thread local storage key or NULL - * on error - * - * @mem_alloc - allocate memory - * @mem_free - free memory - * - * @timer_create - allocate a host timer that runs fn(arg) when the timer - * fires. - * @timer_free - disarms and free the timer - * @timer_set_oneshot - arm the timer to fire once, after delta ns. - * @timer_set_periodic - arm the timer to fire periodically, with a period of - * delta ns. - * - * @ioremap - searches for an I/O memory region identified by addr and size and - * returns a pointer to the start of the address range that can be used by - * iomem_access - * @iomem_acess - reads or writes to and I/O memory region; addr must be in the - * range returned by ioremap - * - * @gettid - returns the host thread id of the caller, which need not - * be the same as the handle returned by thread_create - * - * @jmp_buf_set - runs the give function and setups a jump back point by saving - * the context in the jump buffer; jmp_buf_longjmp can be called from the give - * function or any callee in that function to return back to the jump back - * point - * - * NOTE: we can't return from jmp_buf_set before calling jmp_buf_longjmp or - * otherwise the saved context (stack) is not going to be valid, so we must pass - * the function that will eventually call longjmp here - * - * @jmp_buf_longjmp - perform a jump back to the saved jump buffer - */ -struct lkl_host_operations { - const char *virtio_devices; - - void (*print)(const char *str, int len); - void (*panic)(void); - - struct lkl_sem* (*sem_alloc)(int count); - void (*sem_free)(struct lkl_sem *sem); - void (*sem_up)(struct lkl_sem *sem); - void (*sem_down)(struct lkl_sem *sem); - - struct lkl_mutex *(*mutex_alloc)(int recursive); - void (*mutex_free)(struct lkl_mutex *mutex); - void (*mutex_lock)(struct lkl_mutex *mutex); - void (*mutex_unlock)(struct lkl_mutex *mutex); - - lkl_thread_t (*thread_create)(void (*f)(void *), void *arg); - void (*thread_detach)(void); - void (*thread_exit)(void); - int (*thread_join)(lkl_thread_t tid); - lkl_thread_t (*thread_self)(void); - int (*thread_equal)(lkl_thread_t a, lkl_thread_t b); - - struct lkl_tls_key *(*tls_alloc)(void (*destructor)(void *)); - void (*tls_free)(struct lkl_tls_key *key); - int (*tls_set)(struct lkl_tls_key *key, void *data); - void *(*tls_get)(struct lkl_tls_key *key); - - void* (*mem_alloc)(unsigned long); - void (*mem_free)(void *); - - unsigned long long (*time)(void); - - void* (*timer_alloc)(void (*fn)(void *), void *arg); - int (*timer_set_oneshot)(void *timer, unsigned long delta); - void (*timer_free)(void *timer); - - void* (*ioremap)(long addr, int size); - int (*iomem_access)(const volatile void *addr, void *val, int size, - int write); - - long (*gettid)(void); - - void (*jmp_buf_set)(struct lkl_jmp_buf *jmpb, void (*f)(void)); - void (*jmp_buf_longjmp)(struct lkl_jmp_buf *jmpb, int val); -}; - -/** - * lkl_start_kernel - registers the host operations and starts the kernel - * - * The function returns only after the kernel is shutdown with lkl_sys_halt. - * - * @lkl_ops - pointer to host operations - * @mem_size - how much memory to allocate to the Linux kernel - * @cmd_line - format for command line string that is going to be used to - * generate the Linux kernel command line - */ -int lkl_start_kernel(struct lkl_host_operations *lkl_ops, - unsigned long mem_size, - const char *cmd_line, ...); - -/** - * lkl_is_running - returns 1 if the kernel is currently running - */ -int lkl_is_running(void); - -int lkl_printf(const char *, ...); -void lkl_bug(const char *, ...); - -#endif diff --git a/src/linux/arch/lkl/include/uapi/asm/irq.h b/src/linux/arch/lkl/include/uapi/asm/irq.h deleted file mode 100644 index 89f78fe..0000000 --- a/src/linux/arch/lkl/include/uapi/asm/irq.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _ASM_UAPI_LKL_IRQ_H -#define _ASM_UAPI_LKL_IRQ_H - -/** - * lkl_trigger_irq - generate an interrupt - * - * This function is used by the device host side to signal its Linux counterpart - * that some event happened. - * - * @irq - the irq number to signal - */ -int lkl_trigger_irq(int irq); - -/** - * lkl_get_free_irq - find and reserve a free IRQ number - * - * This function is called by the host device code to find an unused IRQ number - * and reserved it for its own use. - * - * @user - a string to identify the user - * @returns - and irq number that can be used by request_irq or an negative - * value in case of an error - */ -int lkl_get_free_irq(const char *user); - -/** - * lkl_put_irq - release an IRQ number previously obtained with lkl_get_free_irq - * - * @irq - irq number to release - * @user - string identifying the user; should be the same as the one passed to - * lkl_get_free_irq when the irq number was obtained - */ -void lkl_put_irq(int irq, const char *name); - -#endif diff --git a/src/linux/arch/lkl/include/uapi/asm/sigcontext.h b/src/linux/arch/lkl/include/uapi/asm/sigcontext.h deleted file mode 100644 index 77aba40..0000000 --- a/src/linux/arch/lkl/include/uapi/asm/sigcontext.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _ASM_UAPI_LKL_SIGCONTEXT_H -#define _ASM_UAPI_LKL_SIGCONTEXT_H - -#include - -struct pt_regs { - void *irq_data; -}; - -struct sigcontext { - struct pt_regs regs; - unsigned long oldmask; -}; - -#endif diff --git a/src/linux/arch/lkl/include/uapi/asm/siginfo.h b/src/linux/arch/lkl/include/uapi/asm/siginfo.h deleted file mode 100644 index fbed347..0000000 --- a/src/linux/arch/lkl/include/uapi/asm/siginfo.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _ASM_LKL_SIGINFO_H -#define _ASM_LKL_SIGINFO_H - -#ifdef CONFIG_64BIT -#define __ARCH_SI_PREAMBLE_SIZE (4 * sizeof(int)) -#endif - -#include - -#endif /* _ASM_LKL_SIGINFO_H */ diff --git a/src/linux/arch/lkl/include/uapi/asm/syscalls.h b/src/linux/arch/lkl/include/uapi/asm/syscalls.h deleted file mode 100644 index 0fc87b8..0000000 --- a/src/linux/arch/lkl/include/uapi/asm/syscalls.h +++ /dev/null @@ -1,308 +0,0 @@ -#ifndef _ASM_UAPI_LKL_SYSCALLS_H -#define _ASM_UAPI_LKL_SYSCALLS_H - -#include -#include - -typedef __kernel_uid32_t qid_t; -typedef __kernel_fd_set fd_set; -typedef __kernel_mode_t mode_t; -typedef unsigned short umode_t; -typedef __u32 nlink_t; -typedef __kernel_off_t off_t; -typedef __kernel_pid_t pid_t; -typedef __kernel_key_t key_t; -typedef __kernel_suseconds_t suseconds_t; -typedef __kernel_timer_t timer_t; -typedef __kernel_clockid_t clockid_t; -typedef __kernel_mqd_t mqd_t; -typedef __kernel_uid32_t uid_t; -typedef __kernel_gid32_t gid_t; -typedef __kernel_uid16_t uid16_t; -typedef __kernel_gid16_t gid16_t; -typedef unsigned long uintptr_t; -#ifdef CONFIG_UID16 -typedef __kernel_old_uid_t old_uid_t; -typedef __kernel_old_gid_t old_gid_t; -#endif -typedef __kernel_loff_t loff_t; -typedef __kernel_size_t size_t; -typedef __kernel_ssize_t ssize_t; -typedef __kernel_time_t time_t; -typedef __kernel_clock_t clock_t; -typedef __u32 u32; -typedef __s32 s32; -typedef __u64 u64; -typedef __s64 s64; - -#define __user - -#include -/* Temporary undefine system calls that don't have data types defined in UAPI - * headers */ -#undef __NR_kexec_load -#undef __NR_getcpu -#undef __NR_sched_getattr -#undef __NR_sched_setattr -#undef __NR_sched_setparam -#undef __NR_sched_getparam -#undef __NR_sched_setscheduler -#undef __NR_name_to_handle_at -#undef __NR_open_by_handle_at - -#undef __NR_umount -#define __NR_umount __NR_umount2 - -#ifdef CONFIG_64BIT -#define __NR_newstat __NR3264_stat -#define __NR_newlstat __NR3264_lstat -#define __NR_newfstat __NR3264_fstat -#define __NR_newfstatat __NR3264_fstatat -#endif - -#define __NR_mmap_pgoff __NR3264_mmap - -#include -#include -#include -#include -#define __KERNEL__ /* to pull in S_ definitions */ -#include -#undef __KERNEL__ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Define data structures used in system calls that are not defined in UAPI - * headers */ -struct sockaddr { - unsigned short int sa_family; - char sa_data[14]; -}; - -#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1 -#define __UAPI_DEF_IF_IFNAMSIZ 1 -#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1 -#define __UAPI_DEF_IF_IFREQ 1 -#define __UAPI_DEF_IF_IFMAP 1 -#include -#define __UAPI_DEF_IN_IPPROTO 1 -#define __UAPI_DEF_IN_ADDR 1 -#define __UAPI_DEF_IN6_ADDR 1 -#define __UAPI_DEF_IP_MREQ 1 -#define __UAPI_DEF_IN_PKTINFO 1 -#define __UAPI_DEF_SOCKADDR_IN 1 -#define __UAPI_DEF_IN_CLASS 1 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -struct user_msghdr { - void __user *msg_name; /* ptr to socket address structure */ - int msg_namelen; /* size of socket address structure */ - struct iovec __user *msg_iov; /* scatter/gather array */ - __kernel_size_t msg_iovlen; /* # elements in msg_iov */ - void __user *msg_control; /* ancillary data */ - __kernel_size_t msg_controllen; /* ancillary data buffer length */ - unsigned int msg_flags; /* flags on received message */ -}; - -typedef __u32 key_serial_t; - -struct mmsghdr { - struct user_msghdr msg_hdr; - unsigned int msg_len; -}; - -struct linux_dirent64 { - u64 d_ino; - s64 d_off; - unsigned short d_reclen; - unsigned char d_type; - char d_name[0]; -}; - -struct linux_dirent { - unsigned long d_ino; - unsigned long d_off; - unsigned short d_reclen; - char d_name[1]; -}; - -struct ustat { - __kernel_daddr_t f_tfree; - __kernel_ino_t f_tinode; - char f_fname[6]; - char f_fpack[6]; -}; - -#define AF_UNSPEC 0 -#define AF_UNIX 1 -#define AF_LOCAL 1 -#define AF_INET 2 -#define AF_AX25 3 -#define AF_IPX 4 -#define AF_APPLETALK 5 -#define AF_NETROM 6 -#define AF_BRIDGE 7 -#define AF_ATMPVC 8 -#define AF_X25 9 -#define AF_INET6 10 -#define AF_ROSE 11 -#define AF_DECnet 12 -#define AF_NETBEUI 13 -#define AF_SECURITY 14 -#define AF_KEY 15 -#define AF_NETLINK 16 -#define AF_ROUTE AF_NETLINK -#define AF_PACKET 17 -#define AF_ASH 18 -#define AF_ECONET 19 -#define AF_ATMSVC 20 -#define AF_RDS 21 -#define AF_SNA 22 -#define AF_IRDA 23 -#define AF_PPPOX 24 -#define AF_WANPIPE 25 -#define AF_LLC 26 -#define AF_IB 27 -#define AF_MPLS 28 -#define AF_CAN 29 -#define AF_TIPC 30 -#define AF_BLUETOOTH 31 -#define AF_IUCV 32 -#define AF_RXRPC 33 -#define AF_ISDN 34 -#define AF_PHONET 35 -#define AF_IEEE802154 36 -#define AF_CAIF 37 -#define AF_ALG 38 -#define AF_NFC 39 -#define AF_VSOCK 40 - -#define SOCK_STREAM 1 -#define SOCK_DGRAM 2 -#define SOCK_RAW 3 -#define SOCK_RDM 4 -#define SOCK_SEQPACKET 5 -#define SOCK_DCCP 6 -#define SOCK_PACKET 10 - -#define MSG_TRUNC 0x20 - -/* avoid colision with system headers defines */ -#define sa_handler sa_handler -#define st_atime st_atime -#define st_mtime st_mtime -#define st_ctime st_ctime -#define s_addr s_addr - -long lkl_syscall(long no, long *params); -long lkl_sys_halt(void); - -#define __MAP0(m,...) -#define __MAP1(m,t,a) m(t,a) -#define __MAP2(m,t,a,...) m(t,a), __MAP1(m,__VA_ARGS__) -#define __MAP3(m,t,a,...) m(t,a), __MAP2(m,__VA_ARGS__) -#define __MAP4(m,t,a,...) m(t,a), __MAP3(m,__VA_ARGS__) -#define __MAP5(m,t,a,...) m(t,a), __MAP4(m,__VA_ARGS__) -#define __MAP6(m,t,a,...) m(t,a), __MAP5(m,__VA_ARGS__) -#define __MAP(n,...) __MAP##n(__VA_ARGS__) - -#define __SC_LONG(t, a) (long)a -#define __SC_TABLE(t, a) {sizeof(t), (long long)(a)} -#define __SC_DECL(t, a) t a - -#define LKL_SYSCALL0(name) \ - static inline long lkl_sys##name(void) \ - { \ - long params[6]; \ - return lkl_syscall(__lkl__NR##name, params); \ - } - -#if __BITS_PER_LONG == 32 -#define LKL_SYSCALLx(x, name, ...) \ - static inline \ - long lkl_sys##name(__MAP(x, __SC_DECL, __VA_ARGS__)) \ - { \ - struct { \ - unsigned int size; \ - long long value; \ - } lkl_params[x] = { __MAP(x, __SC_TABLE, __VA_ARGS__) }; \ - long params[6], i, k; \ - for (i = k = 0;i < x && k < 6;i++, k++) { \ - if (lkl_params[i].size > sizeof(long) && \ - k + 1 < 6) { \ - params[k] = \ - (long)(lkl_params[i].value & (-1UL)); \ - k++; \ - params[k] = \ - (long)(lkl_params[i].value >> __BITS_PER_LONG); \ - } else { \ - params[k] = (long)(lkl_params[i].value); \ - } \ - } \ - return lkl_syscall(__lkl__NR##name, params); \ - } -#else -#define LKL_SYSCALLx(x, name, ...) \ - static inline \ - long lkl_sys##name(__MAP(x, __SC_DECL, __VA_ARGS__)) \ - { \ - long params[6] = { __MAP(x, __SC_LONG, __VA_ARGS__) }; \ - return lkl_syscall(__lkl__NR##name, params); \ - } -#endif - -#define SYSCALL_DEFINE0(name, ...) LKL_SYSCALL0(name) -#define SYSCALL_DEFINE1(name, ...) LKL_SYSCALLx(1, name, __VA_ARGS__) -#define SYSCALL_DEFINE2(name, ...) LKL_SYSCALLx(2, name, __VA_ARGS__) -#define SYSCALL_DEFINE3(name, ...) LKL_SYSCALLx(3, name, __VA_ARGS__) -#define SYSCALL_DEFINE4(name, ...) LKL_SYSCALLx(4, name, __VA_ARGS__) -#define SYSCALL_DEFINE5(name, ...) LKL_SYSCALLx(5, name, __VA_ARGS__) -#define SYSCALL_DEFINE6(name, ...) LKL_SYSCALLx(6, name, __VA_ARGS__) - -#if __BITS_PER_LONG == 32 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpointer-to-int-cast" -#endif - -#include - -#if __BITS_PER_LONG == 32 -#pragma GCC diagnostic pop -#endif - -#endif diff --git a/src/linux/arch/lkl/include/uapi/asm/unistd.h b/src/linux/arch/lkl/include/uapi/asm/unistd.h deleted file mode 100644 index 878c175..0000000 --- a/src/linux/arch/lkl/include/uapi/asm/unistd.h +++ /dev/null @@ -1,12 +0,0 @@ -#define __ARCH_WANT_SYSCALL_NO_AT -#define __ARCH_WANT_SYSCALL_DEPRECATED -#define __ARCH_WANT_SYSCALL_NO_FLAGS -#define __ARCH_WANT_RENAMEAT - -#if __BITS_PER_LONG == 64 -#define __ARCH_WANT_SYS_NEWFSTATAT -#endif - -#include - -#define __NR_virtio_mmio_device_add (__NR_arch_specific_syscall + 0) diff --git a/src/linux/arch/lkl/kernel/Makefile b/src/linux/arch/lkl/kernel/Makefile deleted file mode 100644 index ef489f2..0000000 --- a/src/linux/arch/lkl/kernel/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -extra-y := vmlinux.lds - -obj-y = setup.o threads.o irq.o time.o syscalls.o misc.o console.o \ - syscalls_32.o cpu.o diff --git a/src/linux/arch/lkl/kernel/asm-offsets.c b/src/linux/arch/lkl/kernel/asm-offsets.c deleted file mode 100644 index 9e26311..0000000 --- a/src/linux/arch/lkl/kernel/asm-offsets.c +++ /dev/null @@ -1 +0,0 @@ -/* Dummy asm-offsets.c file. Required by kbuild and ready to be used - hint! */ diff --git a/src/linux/arch/lkl/kernel/console.c b/src/linux/arch/lkl/kernel/console.c deleted file mode 100644 index bd3a686..0000000 --- a/src/linux/arch/lkl/kernel/console.c +++ /dev/null @@ -1,41 +0,0 @@ -#include -#include -#include -#include - -static void console_write(struct console *con, const char *str, unsigned len) -{ - if (lkl_ops->print) - lkl_ops->print(str, len); -} - -#ifdef CONFIG_LKL_EARLY_CONSOLE -static struct console lkl_boot_console = { - .name = "lkl_boot_console", - .write = console_write, - .flags = CON_PRINTBUFFER | CON_BOOT, - .index = -1, -}; - -int __init lkl_boot_console_init(void) -{ - register_console(&lkl_boot_console); - return 0; -} -early_initcall(lkl_boot_console_init); -#endif - -static struct console lkl_console = { - .name = "lkl_console", - .write = console_write, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -int __init lkl_console_init(void) -{ - register_console(&lkl_console); - return 0; -} -core_initcall(lkl_console_init); - diff --git a/src/linux/arch/lkl/kernel/cpu.c b/src/linux/arch/lkl/kernel/cpu.c deleted file mode 100644 index 2c31526..0000000 --- a/src/linux/arch/lkl/kernel/cpu.c +++ /dev/null @@ -1,305 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * This structure is used to get access to the "LKL CPU" that allows us to run - * Linux code. Because we have to deal with various synchronization requirements - * between idle thread, system calls, interrupts, "reentrancy", CPU shutdown, - * imbalance wake up (i.e. acquire the CPU from one thread and release it from - * another), we can't use a simple synchronization mechanism such as (recursive) - * mutex or semaphore. Instead, we use a mutex and a bunch of status data plus a - * semaphore. - */ -struct lkl_cpu { - /* lock that protects the CPU status data */ - struct lkl_mutex *lock; - /* - * Since we must free the cpu lock during shutdown we need a - * synchronization algorithm between lkl_cpu_shutdown() and the CPU - * access functions since lkl_cpu_get() gets called from thread - * destructor callback functions which may be scheduled after - * lkl_cpu_shutdown() has freed the cpu lock. - * - * An atomic counter is used to keep track of the number of running - * CPU access functions and allow the shutdown function to wait for - * them. - * - * The shutdown functions adds MAX_THREADS to this counter which allows - * the CPU access functions to check if the shutdown process has - * started. - * - * This algorithm assumes that we never have more the MAX_THREADS - * requesting CPU access. - */ - #define MAX_THREADS 1000000 - unsigned int shutdown_gate; - bool irqs_pending; - /* no of threads waiting the CPU */ - unsigned int sleepers; - /* no of times the current thread got the CPU */ - unsigned int count; - /* current thread that owns the CPU */ - lkl_thread_t owner; - /* semaphore for threads waiting the CPU */ - struct lkl_sem *sem; - /* semaphore for the idle thread */ - struct lkl_sem *idle_sem; - /* if the idle thread is pending */ - bool idle_pending; - /* jmp_buf used for idle thread to restart */ - struct lkl_jmp_buf idle_jb; - /* semaphore used for shutdown */ - struct lkl_sem *shutdown_sem; -} cpu; - -static int __cpu_try_get_lock(int n) -{ - lkl_thread_t self; - - if (__sync_fetch_and_add(&cpu.shutdown_gate, n) >= MAX_THREADS) - return -2; - - lkl_ops->mutex_lock(cpu.lock); - - if (cpu.shutdown_gate >= MAX_THREADS) - return -1; - - self = lkl_ops->thread_self(); - - if (cpu.owner && !lkl_ops->thread_equal(cpu.owner, self)) - return 0; - - cpu.owner = self; - cpu.count++; - - return 1; -} - -static void __cpu_try_get_unlock(int lock_ret, int n) -{ - if (lock_ret >= -1) - lkl_ops->mutex_unlock(cpu.lock); - __sync_fetch_and_sub(&cpu.shutdown_gate, n); -} - -void lkl_cpu_change_owner(lkl_thread_t owner) -{ - lkl_ops->mutex_lock(cpu.lock); - if (cpu.count > 1) - lkl_bug("bad count while changing owner\n"); - cpu.owner = owner; - lkl_ops->mutex_unlock(cpu.lock); -} - -int lkl_cpu_get(void) -{ - int ret; - - ret = __cpu_try_get_lock(1); - - while (ret == 0) { - cpu.sleepers++; - __cpu_try_get_unlock(ret, 0); - lkl_ops->sem_down(cpu.sem); - ret = __cpu_try_get_lock(0); - } - - __cpu_try_get_unlock(ret, 1); - - return ret; -} - -void lkl_cpu_put(void) -{ - lkl_ops->mutex_lock(cpu.lock); - - if (!cpu.count || !cpu.owner || - !lkl_ops->thread_equal(cpu.owner, lkl_ops->thread_self())) - lkl_bug("%s: unbalanced put\n", __func__); - - while (cpu.irqs_pending && !irqs_disabled()) { - cpu.irqs_pending = false; - lkl_ops->mutex_unlock(cpu.lock); - run_irqs(); - lkl_ops->mutex_lock(cpu.lock); - } - - if (need_resched() && cpu.count == 1) { - if (in_interrupt()) - lkl_bug("%s: in interrupt\n", __func__); - lkl_ops->mutex_unlock(cpu.lock); - thread_sched_jb(); - return; - } - - if (--cpu.count > 0) { - lkl_ops->mutex_unlock(cpu.lock); - return; - } - - if (cpu.sleepers) { - cpu.sleepers--; - lkl_ops->sem_up(cpu.sem); - } - - cpu.owner = 0; - - lkl_ops->mutex_unlock(cpu.lock); -} - -int lkl_cpu_try_run_irq(int irq) -{ - int ret; - - ret = __cpu_try_get_lock(1); - if (!ret) { - set_irq_pending(irq); - cpu.irqs_pending = true; - } - __cpu_try_get_unlock(ret, 1); - - return ret; -} - -void lkl_cpu_shutdown(void) -{ - __sync_fetch_and_add(&cpu.shutdown_gate, MAX_THREADS); -} - -void lkl_cpu_wait_shutdown(void) -{ - lkl_ops->sem_down(cpu.shutdown_sem); - lkl_ops->sem_free(cpu.shutdown_sem); -} - -static void lkl_cpu_cleanup(bool shutdown) -{ - while (__sync_fetch_and_add(&cpu.shutdown_gate, 0) > MAX_THREADS) - ; - - if (shutdown) - lkl_ops->sem_up(cpu.shutdown_sem); - else if (cpu.shutdown_sem) - lkl_ops->sem_free(cpu.shutdown_sem); - if (cpu.idle_sem) - lkl_ops->sem_free(cpu.idle_sem); - if (cpu.sem) - lkl_ops->sem_free(cpu.sem); - if (cpu.lock) - lkl_ops->mutex_free(cpu.lock); -} - -void arch_cpu_idle(void) -{ - if (cpu.shutdown_gate >= MAX_THREADS) { - - lkl_ops->mutex_lock(cpu.lock); - while (cpu.sleepers--) - lkl_ops->sem_up(cpu.sem); - lkl_ops->mutex_unlock(cpu.lock); - - lkl_cpu_cleanup(true); - - lkl_ops->thread_exit(); - } - /* enable irqs now to allow direct irqs to run */ - local_irq_enable(); - - if (need_resched()) - return; - - cpu.idle_pending = true; - lkl_cpu_put(); - - lkl_ops->sem_down(cpu.idle_sem); - - cpu.idle_pending = false; - /* to match that of schedule_preempt_disabled() */ - preempt_disable(); - lkl_ops->jmp_buf_longjmp(&cpu.idle_jb, 1); -} - -void arch_cpu_idle_prepare(void) -{ - set_ti_thread_flag(current_thread_info(), TIF_IDLE); - /* - * We hijack the idle loop here so that we can let the idle thread - * jump back to the beginning. - */ - while (1) - lkl_ops->jmp_buf_set(&cpu.idle_jb, cpu_idle_loop); -} - -void lkl_cpu_wakeup_idle(void) -{ - lkl_ops->sem_up(cpu.idle_sem); -} - -int lkl_cpu_init(void) -{ - cpu.lock = lkl_ops->mutex_alloc(0); - cpu.sem = lkl_ops->sem_alloc(0); - cpu.idle_sem = lkl_ops->sem_alloc(0); - cpu.shutdown_sem = lkl_ops->sem_alloc(0); - - if (!cpu.lock || !cpu.sem || !cpu.idle_sem || !cpu.shutdown_sem) { - lkl_cpu_cleanup(false); - return -ENOMEM; - } - - return 0; -} - -/* - * Simulate the exit path of idle loop so that we can schedule when LKL is - * in idle. - * It's just a duplication of those in idle.c so a better way is to refactor - * idle.c to expose such function. - */ -void lkl_idle_tail_schedule(void) -{ - - if (!cpu.idle_pending || - !test_bit(TIF_IDLE, ¤t_thread_info()->flags)) - lkl_bug("%s: not in idle\n", __func__); - - start_critical_timings(); - __current_set_polling(); - - if (WARN_ON_ONCE(irqs_disabled())) - local_irq_enable(); - - rcu_idle_exit(); - arch_cpu_idle_exit(); - preempt_set_need_resched(); - tick_nohz_idle_exit(); - __current_clr_polling(); - - /* - * memory barrier copied from idle.c - */ - smp_mb__after_atomic(); - - /* - * Didn't find a way to include kernel/sched/sched.h for - * sched_ttwu_pending(). - * Anyway, it's no op when not CONFIG_SMP. - */ - - schedule_preempt_disabled(); -} - -int lkl_cpu_idle_pending(void) -{ - return cpu.idle_pending; -} diff --git a/src/linux/arch/lkl/kernel/irq.c b/src/linux/arch/lkl/kernel/irq.c deleted file mode 100644 index b5dbbaa..0000000 --- a/src/linux/arch/lkl/kernel/irq.c +++ /dev/null @@ -1,186 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * To avoid much overhead we use an indirect approach: the irqs are marked using - * a bitmap (array of longs) and a summary of the modified bits is kept in a - * separate "index" long - one bit for each sizeof(long). Thus we can support - * 4096 irqs on 64bit platforms and 1024 irqs on 32bit platforms. - * - * Whenever an irq is trigger both the array and the index is updated. To find - * which irqs were triggered we first search the index and then the - * corresponding part of the arrary. - */ -static unsigned long irq_status[NR_IRQS/IRQ_STATUS_BITS]; -static unsigned long irq_index_status; - -static inline unsigned long test_and_clear_irq_index_status(void) -{ - if (!irq_index_status) - return 0; - return __sync_fetch_and_and(&irq_index_status, 0); -} - -static inline unsigned long test_and_clear_irq_status(int index) -{ - if (!&irq_status[index]) - return 0; - return __sync_fetch_and_and(&irq_status[index], 0); -} - -void set_irq_pending(int irq) -{ - int index = irq / IRQ_STATUS_BITS; - int bit = irq % IRQ_STATUS_BITS; - - __sync_fetch_and_or(&irq_status[index], BIT(bit)); - __sync_fetch_and_or(&irq_index_status, BIT(index)); -} - -static struct irq_info { - const char *user; -} irqs[NR_IRQS]; - -static bool irqs_enabled; - -static void run_irq(int irq) -{ - unsigned long flags; - - /* interrupt handlers need to run with interrupts disabled */ - local_irq_save(flags); - irq_enter(); - generic_handle_irq(irq); - irq_exit(); - local_irq_restore(flags); -} - -/** - * This function can be called from arbitrary host threads, so do not - * issue any Linux calls (e.g. prink) if lkl_cpu_get() was not issued - * before. - */ -int lkl_trigger_irq(int irq) -{ - int ret; - - if (!irq || irq > NR_IRQS) - return -EINVAL; - - ret = lkl_cpu_try_run_irq(irq); - if (ret <= 0) - return ret; - - /* - * Since this can be called from Linux context (e.g. lkl_trigger_irq -> - * IRQ -> softirq -> lkl_trigger_irq) make sure we are actually allowed - * to run irqs at this point - */ - if (!irqs_enabled) { - set_irq_pending(irq); - lkl_cpu_put(); - return 0; - } - - run_irq(irq); - - lkl_cpu_put(); - - return 0; -} - -static inline void for_each_bit(unsigned long word, void (*f)(int, int), int j) -{ - int i = 0; - - while (word) { - if (word & 1) - f(i, j); - word >>= 1; - i++; - } -} - -static inline void deliver_irq(int bit, int index) -{ - run_irq(index * IRQ_STATUS_BITS + bit); -} - -static inline void check_irq_status(int i, int unused) -{ - for_each_bit(test_and_clear_irq_status(i), deliver_irq, i); -} - -void run_irqs(void) -{ - for_each_bit(test_and_clear_irq_index_status(), check_irq_status, 0); -} - -int show_interrupts(struct seq_file *p, void *v) -{ - return 0; -} - -int lkl_get_free_irq(const char *user) -{ - int i; - int ret = -EBUSY; - - /* 0 is not a valid IRQ */ - for (i = 1; i < NR_IRQS; i++) { - if (!irqs[i].user) { - irqs[i].user = user; - ret = i; - break; - } - } - - return ret; -} - -void lkl_put_irq(int i, const char *user) -{ - if (!irqs[i].user || strcmp(irqs[i].user, user) != 0) { - WARN("%s tried to release %s's irq %d", user, irqs[i].user, i); - return; - } - - irqs[i].user = NULL; -} - -unsigned long arch_local_save_flags(void) -{ - return irqs_enabled; -} - -void arch_local_irq_restore(unsigned long flags) -{ - if (flags == ARCH_IRQ_ENABLED && irqs_enabled == ARCH_IRQ_DISABLED && - !in_interrupt()) - run_irqs(); - irqs_enabled = flags; -} - -void init_IRQ(void) -{ - int i; - - for (i = 0; i < NR_IRQS; i++) - irq_set_chip_and_handler(i, &dummy_irq_chip, handle_simple_irq); - - pr_info("lkl: irqs initialized\n"); -} - -void cpu_yield_to_irqs(void) -{ - cpu_relax(); -} diff --git a/src/linux/arch/lkl/kernel/misc.c b/src/linux/arch/lkl/kernel/misc.c deleted file mode 100644 index 44d4736..0000000 --- a/src/linux/arch/lkl/kernel/misc.c +++ /dev/null @@ -1,57 +0,0 @@ -#include -#include -#include -#include -#include -#include - -void dump_stack(void) -{ - unsigned long dummy; - unsigned long *stack = &dummy; - unsigned long addr; - - pr_info("Call Trace:\n"); - while (((long)stack & (THREAD_SIZE - 1)) != 0) { - addr = *stack; - if (__kernel_text_address(addr)) { - pr_info("%p: [<%08lx>]", stack, addr); - print_symbol(KERN_CONT " %s", addr); - pr_cont("\n"); - } - stack++; - } - pr_info("\n"); -} - -void show_regs(struct pt_regs *regs) -{ -} - -#ifdef CONFIG_PROC_FS -static void *cpuinfo_start(struct seq_file *m, loff_t *pos) -{ - return NULL; -} - -static void *cpuinfo_next(struct seq_file *m, void *v, loff_t *pos) -{ - return NULL; -} - -static void cpuinfo_stop(struct seq_file *m, void *v) -{ -} - -static int show_cpuinfo(struct seq_file *m, void *v) -{ - return 0; -} - -const struct seq_operations cpuinfo_op = { - .start = cpuinfo_start, - .next = cpuinfo_next, - .stop = cpuinfo_stop, - .show = show_cpuinfo, -}; -#endif diff --git a/src/linux/arch/lkl/kernel/setup.c b/src/linux/arch/lkl/kernel/setup.c deleted file mode 100644 index d6da246..0000000 --- a/src/linux/arch/lkl/kernel/setup.c +++ /dev/null @@ -1,184 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct lkl_host_operations *lkl_ops; -static char cmd_line[COMMAND_LINE_SIZE]; -static void *init_sem; -static int is_running; -void (*pm_power_off)(void) = NULL; -static unsigned long mem_size; - -long lkl_panic_blink(int state) -{ - lkl_ops->panic(); - return 0; -} - -void __init setup_arch(char **cl) -{ - *cl = cmd_line; - panic_blink = lkl_panic_blink; - bootmem_init(mem_size); -} - -static void __init lkl_run_kernel(void *arg) -{ - threads_init(); - lkl_cpu_get(); - start_kernel(); -} - -int __init lkl_start_kernel(struct lkl_host_operations *ops, - unsigned long _mem_size, - const char *fmt, ...) -{ - va_list ap; - int ret; - - lkl_ops = ops; - mem_size = _mem_size; - - va_start(ap, fmt); - ret = vsnprintf(boot_command_line, COMMAND_LINE_SIZE, fmt, ap); - va_end(ap); - - if (ops->virtio_devices) - strncpy(boot_command_line + ret, ops->virtio_devices, - COMMAND_LINE_SIZE - ret); - - memcpy(cmd_line, boot_command_line, COMMAND_LINE_SIZE); - - init_sem = lkl_ops->sem_alloc(0); - if (!init_sem) - return -ENOMEM; - - ret = lkl_cpu_init(); - if (ret) - goto out_free_init_sem; - - ret = lkl_ops->thread_create(lkl_run_kernel, NULL); - if (!ret) { - ret = -ENOMEM; - goto out_free_init_sem; - } - - lkl_ops->sem_down(init_sem); - lkl_ops->sem_free(init_sem); - current_thread_info()->tid = lkl_ops->thread_self(); - lkl_cpu_change_owner(current_thread_info()->tid); - - lkl_cpu_put(); - is_running = 1; - - return 0; - -out_free_init_sem: - lkl_ops->sem_free(init_sem); - - return ret; -} - -int lkl_is_running(void) -{ - return is_running; -} - -void machine_halt(void) -{ - lkl_cpu_shutdown(); -} - -void machine_power_off(void) -{ - machine_halt(); -} - -void machine_restart(char *unused) -{ - machine_halt(); -} - -long lkl_sys_halt(void) -{ - long err; - long params[6] = {LINUX_REBOOT_MAGIC1, - LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART, }; - - err = lkl_syscall(__NR_reboot, params); - if (err < 0) - return err; - - is_running = false; - - lkl_cpu_wait_shutdown(); - - syscalls_cleanup(); - threads_cleanup(); - /* Shutdown the clockevents source. */ - tick_suspend_local(); - free_mem(); - - return 0; -} - - -static int lkl_run_init(struct linux_binprm *bprm); - -static struct linux_binfmt lkl_run_init_binfmt = { - .module = THIS_MODULE, - .load_binary = lkl_run_init, -}; - -static int lkl_run_init(struct linux_binprm *bprm) -{ - int ret; - - if (strcmp("/init", bprm->filename) != 0) - return -EINVAL; - - ret = flush_old_exec(bprm); - if (ret) - return ret; - set_personality(PER_LINUX); - setup_new_exec(bprm); - install_exec_creds(bprm); - - set_binfmt(&lkl_run_init_binfmt); - - init_pid_ns.child_reaper = 0; - - syscalls_init(); - - lkl_ops->sem_up(init_sem); - lkl_ops->thread_exit(); - - return 0; -} - - -/* skip mounting the "real" rootfs. ramfs is good enough. */ -static int __init fs_setup(void) -{ - int fd; - - fd = sys_open("/init", O_CREAT, 0700); - WARN_ON(fd < 0); - sys_close(fd); - - register_binfmt(&lkl_run_init_binfmt); - - return 0; -} -late_initcall(fs_setup); diff --git a/src/linux/arch/lkl/kernel/syscalls.c b/src/linux/arch/lkl/kernel/syscalls.c deleted file mode 100644 index fb8e8d5..0000000 --- a/src/linux/arch/lkl/kernel/syscalls.c +++ /dev/null @@ -1,199 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static asmlinkage long sys_virtio_mmio_device_add(long base, long size, - unsigned int irq); - -typedef long (*syscall_handler_t)(long arg1, ...); - -#undef __SYSCALL -#define __SYSCALL(nr, sym) [nr] = (syscall_handler_t)sym, - -syscall_handler_t syscall_table[__NR_syscalls] = { - [0 ... __NR_syscalls - 1] = (syscall_handler_t)sys_ni_syscall, -#include - -#if __BITS_PER_LONG == 32 -#include -#endif -}; - -static long run_syscall(long no, long *params) -{ - long ret; - - if (no < 0 || no >= __NR_syscalls) - return -ENOSYS; - - ret = syscall_table[no](params[0], params[1], params[2], params[3], - params[4], params[5]); - - task_work_run(); - - return ret; -} - - -#define CLONE_FLAGS (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_THREAD | \ - CLONE_SIGHAND | SIGCHLD) - -static int host_task_id; -static struct task_struct *host0; - -static int new_host_task(struct task_struct **task) -{ - pid_t pid; - - switch_to_host_task(host0); - - pid = kernel_thread(NULL, NULL, CLONE_FLAGS); - if (pid < 0) - return pid; - - rcu_read_lock(); - *task = find_task_by_pid_ns(pid, &init_pid_ns); - rcu_read_unlock(); - - host_task_id++; - - snprintf((*task)->comm, sizeof((*task)->comm), "host%d", host_task_id); - - return 0; -} -static void exit_task(void) -{ - do_exit(0); -} - -static void del_host_task(void *arg) -{ - struct task_struct *task = (struct task_struct *)arg; - struct thread_info *ti = task_thread_info(task); - - if (lkl_cpu_get() < 0) - return; - - switch_to_host_task(task); - host_task_id--; - set_ti_thread_flag(ti, TIF_SCHED_JB); - lkl_ops->jmp_buf_set(&ti->sched_jb, exit_task); -} - -static struct lkl_tls_key *task_key; - -long lkl_syscall(long no, long *params) -{ - struct task_struct *task = host0; - long ret; - - ret = lkl_cpu_get(); - if (ret < 0) - return ret; - - if (lkl_ops->tls_get) { - task = lkl_ops->tls_get(task_key); - if (!task) { - ret = new_host_task(&task); - if (ret) - goto out; - lkl_ops->tls_set(task_key, task); - } - } - - switch_to_host_task(task); - - ret = run_syscall(no, params); - - if (no == __NR_reboot) { - thread_sched_jb(); - return ret; - } - -out: - lkl_cpu_put(); - - return ret; -} - -int syscalls_init(void) -{ - snprintf(current->comm, sizeof(current->comm), "host0"); - set_thread_flag(TIF_HOST_THREAD); - host0 = current; - - if (lkl_ops->tls_alloc) { - task_key = lkl_ops->tls_alloc(del_host_task); - if (!task_key) - return -1; - } - - return 0; -} - -void syscalls_cleanup(void) -{ - if (lkl_ops->tls_free) - lkl_ops->tls_free(task_key); -} - -SYSCALL_DEFINE3(virtio_mmio_device_add, long, base, long, size, unsigned int, - irq) -{ - struct platform_device *pdev; - int ret; - - struct resource res[] = { - [0] = { - .start = base, - .end = base + size - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = irq, - .end = irq, - .flags = IORESOURCE_IRQ, - }, - }; - - pdev = platform_device_alloc("virtio-mmio", PLATFORM_DEVID_AUTO); - if (!pdev) { - dev_err(&pdev->dev, "%s: Unable to device alloc for virtio-mmio\n", __func__); - return -ENOMEM; - } - - ret = platform_device_add_resources(pdev, res, ARRAY_SIZE(res)); - if (ret) { - dev_err(&pdev->dev, "%s: Unable to add resources for %s%d\n", __func__, pdev->name, pdev->id); - goto exit_device_put; - } - - ret = platform_device_add(pdev); - if (ret < 0) { - dev_err(&pdev->dev, "%s: Unable to add %s%d\n", __func__, pdev->name, pdev->id); - goto exit_release_pdev; - } - - return pdev->id; - -exit_release_pdev: - platform_device_del(pdev); -exit_device_put: - platform_device_put(pdev); - - return ret; -} diff --git a/src/linux/arch/lkl/kernel/syscalls_32.c b/src/linux/arch/lkl/kernel/syscalls_32.c deleted file mode 100644 index 96bf5e4..0000000 --- a/src/linux/arch/lkl/kernel/syscalls_32.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * sys_ia32.c: Conversion between 32bit and 64bit native syscalls. Based on - * sys_sparc32 - * - * Copyright (C) 2000 VA Linux Co - * Copyright (C) 2000 Don Dugger - * Copyright (C) 1999 Arun Sharma - * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) - * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 2000 Hewlett-Packard Co. - * Copyright (C) 2000 David Mosberger-Tang - * Copyright (C) 2000,2001,2002 Andi Kleen, SuSE Labs (x86-64 port) - * - * These routines maintain argument size conversion between 32bit and 64bit - * environment. In 2.5 most of this should be moved to a generic directory. - * - * This file assumes that there is a hole at the end of user address space. - * - * Some of the functions are LE specific currently. These are - * hopefully all marked. This should be fixed. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define AA(__x) ((unsigned long)(__x)) - -#if __BITS_PER_LONG == 32 - -asmlinkage long sys32_truncate64(const char __user *filename, - unsigned long offset_low, - unsigned long offset_high) -{ - return sys_truncate64(filename, ((loff_t) offset_high << 32) | offset_low); -} - -asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long offset_low, - unsigned long offset_high) -{ - return sys_ftruncate64(fd, ((loff_t) offset_high << 32) | offset_low); -} - -#ifdef CONFIG_MMU -/* - * Linux/i386 didn't use to be able to handle more than - * 4 system call parameters, so these system calls used a memory - * block for parameter passing.. - */ - -struct mmap_arg_struct32 { - unsigned int addr; - unsigned int len; - unsigned int prot; - unsigned int flags; - unsigned int fd; - unsigned int offset; -}; - -asmlinkage long sys32_mmap(struct mmap_arg_struct32 __user *arg) -{ - struct mmap_arg_struct32 a; - - if (copy_from_user(&a, arg, sizeof(a))) - return -EFAULT; - - if (a.offset & ~PAGE_MASK) - return -EINVAL; - - return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, - a.offset>>PAGE_SHIFT); -} -#endif - -asmlinkage long sys32_wait4(pid_t pid, unsigned int __user *stat_addr, - int options, struct rusage __user *ru) -{ - return sys_wait4(pid, stat_addr, options, ru); -} - -asmlinkage long sys32_pread64(unsigned int fd, char __user *ubuf, u32 count, - u32 poslo, u32 poshi) -{ - return sys_pread64(fd, ubuf, count, - ((loff_t)AA(poshi) << 32) | AA(poslo)); -} - -asmlinkage long sys32_pwrite64(unsigned int fd, const char __user *ubuf, - u32 count, u32 poslo, u32 poshi) -{ - return sys_pwrite64(fd, ubuf, count, - ((loff_t)AA(poshi) << 32) | AA(poslo)); -} - - -/* - * Some system calls that need sign extended arguments. This could be - * done by a generic wrapper. - */ -long sys32_fadvise64_64(int fd, __u32 offset_low, __u32 offset_high, - __u32 len_low, __u32 len_high, int advice) -{ - return sys_fadvise64_64(fd, - (((u64)offset_high)<<32) | offset_low, - (((u64)len_high)<<32) | len_low, - advice); -} - -asmlinkage ssize_t sys32_readahead(int fd, unsigned off_lo, unsigned off_hi, - size_t count) -{ - return sys_readahead(fd, ((u64)off_hi << 32) | off_lo, count); -} - -asmlinkage long sys32_sync_file_range(int fd, unsigned off_low, unsigned off_hi, - unsigned n_low, unsigned n_hi, unsigned int flags) -{ - return sys_sync_file_range(fd, - ((u64)off_hi << 32) | off_low, - ((u64)n_hi << 32) | n_low, flags); -} - -asmlinkage long sys32_sync_file_range2(int fd, unsigned int flags, - unsigned off_low, unsigned off_hi, - unsigned n_low, unsigned n_hi) -{ - return sys_sync_file_range(fd, - ((u64)off_hi << 32) | off_low, - ((u64)n_hi << 32) | n_low, flags); -} - -asmlinkage long sys32_fallocate(int fd, int mode, unsigned offset_lo, - unsigned offset_hi, unsigned len_lo, - unsigned len_hi) -{ - return sys_fallocate(fd, mode, ((u64)offset_hi << 32) | offset_lo, - ((u64)len_hi << 32) | len_lo); -} - -#endif diff --git a/src/linux/arch/lkl/kernel/threads.c b/src/linux/arch/lkl/kernel/threads.c deleted file mode 100644 index caede2f..0000000 --- a/src/linux/arch/lkl/kernel/threads.c +++ /dev/null @@ -1,232 +0,0 @@ -#include -#include -#include -#include -#include -#include - -static int init_ti(struct thread_info *ti) -{ - ti->sched_sem = lkl_ops->sem_alloc(0); - if (!ti->sched_sem) - return -ENOMEM; - - ti->dead = false; - ti->prev_sched = NULL; - ti->tid = 0; - - return 0; -} - -unsigned long *alloc_thread_stack_node(struct task_struct *task, int node) -{ - struct thread_info *ti; - - ti = kmalloc(sizeof(*ti), GFP_KERNEL); - if (!ti) - return NULL; - - if (init_ti(ti)) { - kfree(ti); - return NULL; - } - ti->task = task; - - - return (unsigned long *)ti; -} - -/* - * The only new tasks created are kernel threads that have a predefined starting - * point thus no stack copy is required. - */ -void setup_thread_stack(struct task_struct *p, struct task_struct *org) -{ - struct thread_info *ti = task_thread_info(p); - struct thread_info *org_ti = task_thread_info(org); - - ti->flags = org_ti->flags; - ti->preempt_count = org_ti->preempt_count; - ti->addr_limit = org_ti->addr_limit; -} - -static void kill_thread(struct thread_info *ti) -{ - if (!test_ti_thread_flag(ti, TIF_HOST_THREAD)) { - ti->dead = true; - lkl_ops->sem_up(ti->sched_sem); - lkl_ops->thread_join(ti->tid); - } - lkl_ops->sem_free(ti->sched_sem); - -} - -void free_thread_stack(struct task_struct *tsk) -{ - struct thread_info *ti = task_thread_info(tsk); - - kill_thread(ti); - kfree(ti); -} - -struct thread_info *_current_thread_info = &init_thread_union.thread_info; - -/* - * schedule() expects the return of this function to be the task that we - * switched away from. Returning prev is not going to work because we are - * actually going to return the previous taks that was scheduled before the - * task we are going to wake up, and not the current task, e.g.: - * - * swapper -> init: saved prev on swapper stack is swapper - * init -> ksoftirqd0: saved prev on init stack is init - * ksoftirqd0 -> swapper: returned prev is swapper - */ -static struct task_struct *abs_prev = &init_task; - -struct task_struct *__switch_to(struct task_struct *prev, - struct task_struct *next) -{ - struct thread_info *_prev = task_thread_info(prev); - struct thread_info *_next = task_thread_info(next); - unsigned long _prev_flags = _prev->flags; - bool wakeup_idle = test_bit(TIF_IDLE, &_next->flags) && - lkl_cpu_idle_pending(); - struct lkl_jmp_buf _prev_jb; - - _current_thread_info = task_thread_info(next); - _next->prev_sched = prev; - abs_prev = prev; - - BUG_ON(!_next->tid); - - if (test_bit(TIF_SCHED_JB, &_prev_flags)) { - /* Atomic. Must be done before wakeup next */ - clear_ti_thread_flag(_prev, TIF_SCHED_JB); - _prev_jb = _prev->sched_jb; - } - if (wakeup_idle) - schedule_tail(abs_prev); - lkl_cpu_change_owner(_next->tid); - - /* No kernel code is allowed after wakeup next */ - if (wakeup_idle) - lkl_cpu_wakeup_idle(); - else - lkl_ops->sem_up(_next->sched_sem); - - if (test_bit(TIF_SCHED_JB, &_prev_flags)) { - lkl_ops->jmp_buf_longjmp(&_prev_jb, 1); - } else { - lkl_ops->sem_down(_prev->sched_sem); - } - - if (_prev->dead) - lkl_ops->thread_exit(); - - return abs_prev; -} - -void switch_to_host_task(struct task_struct *task) -{ - if (current == task) - return; - - if (WARN_ON(!test_tsk_thread_flag(task, TIF_HOST_THREAD))) - return; - - task_thread_info(task)->tid = lkl_ops->thread_self(); - - wake_up_process(task); - thread_sched_jb(); - lkl_ops->sem_down(task_thread_info(task)->sched_sem); - schedule_tail(abs_prev); -} - -struct thread_bootstrap_arg { - struct thread_info *ti; - int (*f)(void *); - void *arg; -}; - -static void thread_bootstrap(void *_tba) -{ - struct thread_bootstrap_arg *tba = (struct thread_bootstrap_arg *)_tba; - struct thread_info *ti = tba->ti; - int (*f)(void *) = tba->f; - void *arg = tba->arg; - - lkl_ops->sem_down(ti->sched_sem); - kfree(tba); - if (ti->prev_sched) - schedule_tail(ti->prev_sched); - - f(arg); - do_exit(0); -} - -int copy_thread(unsigned long clone_flags, unsigned long esp, - unsigned long unused, struct task_struct *p) -{ - struct thread_info *ti = task_thread_info(p); - struct thread_bootstrap_arg *tba; - - if (!esp) { - set_ti_thread_flag(ti, TIF_HOST_THREAD); - return 0; - } - - tba = kmalloc(sizeof(*tba), GFP_KERNEL); - if (!tba) - return -ENOMEM; - - tba->f = (int (*)(void *))esp; - tba->arg = (void *)unused; - tba->ti = ti; - - ti->tid = lkl_ops->thread_create(thread_bootstrap, tba); - if (!ti->tid) { - kfree(tba); - return -ENOMEM; - } - - return 0; -} - -void show_stack(struct task_struct *task, unsigned long *esp) -{ -} - -/** - * This is called before the kernel initializes, so no kernel calls (including - * printk) can't be made yet. - */ -void threads_init(void) -{ - int ret; - struct thread_info *ti = &init_thread_union.thread_info; - - ret = init_ti(ti); - if (ret < 0) - lkl_printf("lkl: failed to allocate init schedule semaphore\n"); - - ti->tid = lkl_ops->thread_self(); -} - -void threads_cleanup(void) -{ - struct task_struct *p, *t; - - for_each_process_thread(p, t) { - struct thread_info *ti = task_thread_info(t); - - if (t->pid != 1 && !test_ti_thread_flag(ti, TIF_HOST_THREAD)) - WARN(!(t->flags & PF_KTHREAD), - "non kernel thread task %s\n", t->comm); - WARN(t->state == TASK_RUNNING, - "thread %s still running while halting\n", t->comm); - - kill_thread(ti); - } - - lkl_ops->sem_free(init_thread_union.thread_info.sched_sem); -} diff --git a/src/linux/arch/lkl/kernel/time.c b/src/linux/arch/lkl/kernel/time.c deleted file mode 100644 index b15f80b..0000000 --- a/src/linux/arch/lkl/kernel/time.c +++ /dev/null @@ -1,143 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -static unsigned long long boot_time; - -void __ndelay(unsigned long nsecs) -{ - unsigned long long start = lkl_ops->time(); - - while (lkl_ops->time() < start + nsecs) - ; -} - -void __udelay(unsigned long usecs) -{ - __ndelay(usecs * NSEC_PER_USEC); -} - -void __const_udelay(unsigned long xloops) -{ - __udelay(xloops / 5); -} - -void calibrate_delay(void) -{ -} - -void read_persistent_clock(struct timespec *ts) -{ - *ts = ns_to_timespec(lkl_ops->time()); -} - -/* - * Scheduler clock - returns current time in nanosec units. - * - */ -unsigned long long sched_clock(void) -{ - if (!boot_time) - return 0; - - return lkl_ops->time() - boot_time; -} - -static cycle_t clock_read(struct clocksource *cs) -{ - return lkl_ops->time(); -} - -static struct clocksource clocksource = { - .name = "lkl", - .rating = 499, - .read = clock_read, - .flags = CLOCK_SOURCE_IS_CONTINUOUS, - .mask = CLOCKSOURCE_MASK(64), -}; - -static void *timer; - -static int timer_irq; - -static void timer_fn(void *arg) -{ - lkl_trigger_irq(timer_irq); -} - -static int clockevent_set_state_shutdown(struct clock_event_device *evt) -{ - if (timer) { - lkl_ops->timer_free(timer); - timer = NULL; - } - - return 0; -} - -static int clockevent_set_state_oneshot(struct clock_event_device *evt) -{ - timer = lkl_ops->timer_alloc(timer_fn, NULL); - if (!timer) - return -ENOMEM; - - return 0; -} - -static irqreturn_t timer_irq_handler(int irq, void *dev_id) -{ - struct clock_event_device *dev = (struct clock_event_device *)dev_id; - - dev->event_handler(dev); - - return IRQ_HANDLED; -} - -static int clockevent_next_event(unsigned long ns, - struct clock_event_device *evt) -{ - return lkl_ops->timer_set_oneshot(timer, ns); -} - -static struct clock_event_device clockevent = { - .name = "lkl", - .features = CLOCK_EVT_FEAT_ONESHOT, - .set_state_oneshot = clockevent_set_state_oneshot, - .set_next_event = clockevent_next_event, - .set_state_shutdown = clockevent_set_state_shutdown, -}; - -static struct irqaction irq0 = { - .handler = timer_irq_handler, - .flags = IRQF_NOBALANCING | IRQF_TIMER, - .dev_id = &clockevent, - .name = "timer" -}; - -void __init time_init(void) -{ - int ret; - - if (!lkl_ops->timer_alloc || !lkl_ops->timer_free || - !lkl_ops->timer_set_oneshot || !lkl_ops->time) { - pr_err("lkl: no time or timer support provided by host\n"); - return; - } - - timer_irq = lkl_get_free_irq("timer"); - setup_irq(timer_irq, &irq0); - - ret = clocksource_register_khz(&clocksource, 1000000); - if (ret) - pr_err("lkl: unable to register clocksource\n"); - - clockevents_config_and_register(&clockevent, NSEC_PER_SEC, 1, ULONG_MAX); - - boot_time = lkl_ops->time(); - pr_info("lkl: time and timers initialized (irq%d)\n", timer_irq); -} diff --git a/src/linux/arch/lkl/kernel/vmlinux.lds.S b/src/linux/arch/lkl/kernel/vmlinux.lds.S deleted file mode 100644 index 3095f53..0000000 --- a/src/linux/arch/lkl/kernel/vmlinux.lds.S +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include -#include -#include - -OUTPUT_FORMAT(CONFIG_OUTPUT_FORMAT) - -VMLINUX_SYMBOL(jiffies) = VMLINUX_SYMBOL(jiffies_64); - -SECTIONS -{ - VMLINUX_SYMBOL(__init_begin) = .; - HEAD_TEXT_SECTION - INIT_TEXT_SECTION(PAGE_SIZE) - INIT_DATA_SECTION(16) - PERCPU_SECTION(L1_CACHE_BYTES) - VMLINUX_SYMBOL(__init_end) = .; - - VMLINUX_SYMBOL(_stext) = .; - VMLINUX_SYMBOL(_text) = . ; - VMLINUX_SYMBOL(text) = . ; - .text : - { - TEXT_TEXT - SCHED_TEXT - LOCK_TEXT - CPUIDLE_TEXT - } - VMLINUX_SYMBOL(_etext) = .; - - VMLINUX_SYMBOL(_sdata) = .; - RO_DATA_SECTION(PAGE_SIZE) - RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE) - VMLINUX_SYMBOL(_edata) = .; - - EXCEPTION_TABLE(16) - NOTES - - BSS_SECTION(0, 0, 0) - VMLINUX_SYMBOL(_end) = .; - - STABS_DEBUG - DWARF_DEBUG - - DISCARDS -} diff --git a/src/linux/arch/lkl/mm/Makefile b/src/linux/arch/lkl/mm/Makefile deleted file mode 100644 index 2af6e30..0000000 --- a/src/linux/arch/lkl/mm/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-y = bootmem.o diff --git a/src/linux/arch/lkl/mm/bootmem.c b/src/linux/arch/lkl/mm/bootmem.c deleted file mode 100644 index 6a7966d..0000000 --- a/src/linux/arch/lkl/mm/bootmem.c +++ /dev/null @@ -1,73 +0,0 @@ -#include -#include -#include - -unsigned long memory_start, memory_end; -static unsigned long _memory_start, mem_size; - -void *empty_zero_page; - -void __init bootmem_init(unsigned long mem_size) -{ - unsigned long bootmap_size; - - _memory_start = (unsigned long)lkl_ops->mem_alloc(mem_size); - memory_start = _memory_start; - BUG_ON(!memory_start); - memory_end = memory_start + mem_size; - - if (PAGE_ALIGN(memory_start) != memory_start) { - mem_size -= PAGE_ALIGN(memory_start) - memory_start; - memory_start = PAGE_ALIGN(memory_start); - mem_size = (mem_size / PAGE_SIZE) * PAGE_SIZE; - } - pr_info("bootmem address range: 0x%lx - 0x%lx\n", memory_start, - memory_start+mem_size); - /* - * Give all the memory to the bootmap allocator, tell it to put the - * boot mem_map at the start of memory. - */ - max_low_pfn = virt_to_pfn(memory_end); - min_low_pfn = virt_to_pfn(memory_start); - bootmap_size = init_bootmem_node(NODE_DATA(0), min_low_pfn, min_low_pfn, - max_low_pfn); - - /* - * Free the usable memory, we have to make sure we do not free - * the bootmem bitmap so we then reserve it after freeing it :-) - */ - free_bootmem(memory_start, mem_size); - reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT); - - empty_zero_page = alloc_bootmem_pages(PAGE_SIZE); - memset((void *)empty_zero_page, 0, PAGE_SIZE); - - { - unsigned long zones_size[MAX_NR_ZONES] = {0, }; - - zones_size[ZONE_NORMAL] = (mem_size) >> PAGE_SHIFT; - free_area_init(zones_size); - } -} - -void __init mem_init(void) -{ - max_mapnr = (((unsigned long)high_memory) - PAGE_OFFSET) >> PAGE_SHIFT; - /* this will put all memory onto the freelists */ - totalram_pages = free_all_bootmem(); - pr_info("Memory available: %luk/%luk RAM\n", - (nr_free_pages() << PAGE_SHIFT) >> 10, mem_size >> 10); -} - -/* - * In our case __init memory is not part of the page allocator so there is - * nothing to free. - */ -void free_initmem(void) -{ -} - -void free_mem(void) -{ - lkl_ops->mem_free((void *)_memory_start); -} diff --git a/src/linux/arch/lkl/scripts/headers_install.py b/src/linux/arch/lkl/scripts/headers_install.py deleted file mode 100755 index c9b10e1..0000000 --- a/src/linux/arch/lkl/scripts/headers_install.py +++ /dev/null @@ -1,183 +0,0 @@ -#!/usr/bin/env python -import re, os, sys, argparse, multiprocessing, fnmatch - -srctree = os.environ["srctree"] -objtree = os.environ["objtree"] -header_paths = [ "include/uapi/", "arch/lkl/include/uapi/", - "arch/lkl/include/generated/uapi/", "include/generated/" ] - -headers = set() -includes = set() - -def relpath2abspath(relpath): - if "generated" in relpath: - return objtree + "/" + relpath - else: - return srctree + "/" + relpath - -def find_headers(path): - headers.add(path) - f = open(relpath2abspath(path)) - for l in f.readlines(): - m = re.search("#include <(.*)>", l) - try: - i = m.group(1) - for p in header_paths: - if os.access(relpath2abspath(p + i), os.R_OK): - if p + i not in headers: - includes.add(i) - headers.add(p + i) - find_headers(p + i) - except: - pass - f.close() - -def has_lkl_prefix(w): - return w.startswith("lkl") or w.startswith("_lkl") or w.startswith("__lkl") \ - or w.startswith("LKL") or w.startswith("_LKL") or w.startswith("__LKL") - -def find_symbols(regexp, store): - for h in headers: - f = open(h) - for l in f.readlines(): - m = regexp.search(l) - if not m: - continue - for e in reversed(m.groups()): - if e: - if not has_lkl_prefix(e): - store.add(e) - break - f.close() - -def find_ml_symbols(regexp, store): - for h in headers: - for i in regexp.finditer(open(h).read()): - for j in reversed(i.groups()): - if j: - if not has_lkl_prefix(j): - store.add(j) - break - -def find_enums(block_regexp, symbol_regexp, store): - for h in headers: - # remove comments - content = re.sub(re.compile("(\/\*(\*(?!\/)|[^*])*\*\/)", re.S|re.M), " ", open(h).read()) - # remove preprocesor lines - clean_content = "" - for l in content.split("\n"): - if re.match("\s*#", l): - continue - clean_content += l + "\n" - for i in block_regexp.finditer(clean_content): - for j in reversed(i.groups()): - if j: - for k in symbol_regexp.finditer(j): - for l in k.groups(): - if l: - if not has_lkl_prefix(l): - store.add(l) - break - -def lkl_prefix(w): - r = "" - - if w.startswith("__"): - r = "__" - elif w.startswith("_"): - r = "_" - - if w.isupper(): - r += "LKL" - else: - r += "lkl" - - if not w.startswith("_"): - r += "_" - - r += w - - return r - -def replace(h): - content = open(h).read() - for i in includes: - search_str = "(#[ \t]*include[ \t]*[<\"][ \t]*)" + i + "([ \t]*[>\"])" - replace_str = "\\1" + "lkl/" + i + "\\2" - content = re.sub(search_str, replace_str, content) - tmp = "" - for w in re.split("(\W+)", content): - if w in defines: - w = lkl_prefix(w) - tmp += w - content = tmp - for s in structs: - search_str = "(\W?struct\s+)" + s + "(\W)" - replace_str = "\\1" + lkl_prefix(s) + "\\2" - content = re.sub(search_str, replace_str, content, flags = re.MULTILINE) - for s in unions: - search_str = "(\W?union\s+)" + s + "(\W)" - replace_str = "\\1" + lkl_prefix(s) + "\\2" - content = re.sub(search_str, replace_str, content, flags = re.MULTILINE) - open(h, 'w').write(content) - -parser = argparse.ArgumentParser(description='install lkl headers') -parser.add_argument('path', help='path to install to', ) -parser.add_argument('-j', '--jobs', help='number of parallel jobs', default=1, type=int) -args = parser.parse_args() - -find_headers("arch/lkl/include/uapi/asm/syscalls.h") -headers.add("arch/lkl/include/uapi/asm/host_ops.h") - -new_headers = set() - -for h in headers: - dir = os.path.dirname(h) - copyfromdir = os.path.dirname(relpath2abspath(h)) - out_dir = args.path + "/" + re.sub("(arch/lkl/include/uapi/|arch/lkl/include/generated/uapi/|include/uapi/|include/generated/uapi/|include/generated)(.*)", "lkl/\\2", dir) - try: - os.makedirs(out_dir) - except: - pass - print(" INSTALL\t%s" % (out_dir + "/" + os.path.basename(h))) - os.system(srctree+"/scripts/headers_install.sh %s %s %s" % (out_dir, copyfromdir, - os.path.basename(h))) - new_headers.add(out_dir + "/" + os.path.basename(h)) - -headers = new_headers - -defines = set() -structs = set() -unions = set() - -p = re.compile("#[ \t]*define[ \t]*(\w+)") -find_symbols(p, defines) -p = re.compile("typedef.*(\(\*(\w+)\)\(.*\)\s*|\W+(\w+)\s*|\s+(\w+)\(.*\)\s*);") -find_symbols(p, defines) -p = re.compile("typedef\s+(struct|union)\s+\w*\s*{[^\\{\}]*}\W*(\w+)\s*;", re.M|re.S) -find_ml_symbols(p, defines) -defines.add("siginfo_t") -defines.add("sigevent_t") -p = re.compile("struct\s+(\w+)\s*\{") -find_symbols(p, structs) -structs.add("iovec") -p = re.compile("union\s+(\w+)\s*\{") -find_symbols(p, unions) -p = re.compile("static\s+__inline__(\s+\w+)+\s+(\w+)\([^)]*\)\s") -find_symbols(p, defines) -p = re.compile("enum\s+(\w*)\s*{([^}]*)}", re.M|re.S) -q = re.compile("(\w+)\s*(,|=[^,]*|$)", re.M|re.S) -find_enums(p, q, defines) - -def process_header(h): - print(" REPLACE\t%s" % (out_dir + "/" + os.path.basename(h))) - replace(h) - -p = multiprocessing.Pool(args.jobs) -try: - p.map_async(process_header, headers).wait(999999) - p.close() -except: - p.terminate() -finally: - p.join() diff --git a/src/linux/arch/m32r/kernel/.gitignore b/src/linux/arch/m32r/kernel/.gitignore deleted file mode 100644 index c5f676c..0000000 --- a/src/linux/arch/m32r/kernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.lds diff --git a/src/linux/arch/m68k/kernel/.gitignore b/src/linux/arch/m68k/kernel/.gitignore deleted file mode 100644 index c5f676c..0000000 --- a/src/linux/arch/m68k/kernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.lds diff --git a/src/linux/arch/metag/boot/.gitignore b/src/linux/arch/metag/boot/.gitignore deleted file mode 100644 index 2d6c0c1..0000000 --- a/src/linux/arch/metag/boot/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -vmlinux* -uImage* -ramdisk.* -*.dtb* diff --git a/src/linux/arch/metag/boot/dts/include/dt-bindings b/src/linux/arch/metag/boot/dts/include/dt-bindings deleted file mode 120000 index 08c00e4..0000000 --- a/src/linux/arch/metag/boot/dts/include/dt-bindings +++ /dev/null @@ -1 +0,0 @@ -../../../../../include/dt-bindings \ No newline at end of file diff --git a/src/linux/arch/metag/kernel/.gitignore b/src/linux/arch/metag/kernel/.gitignore deleted file mode 100644 index c5f676c..0000000 --- a/src/linux/arch/metag/kernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.lds diff --git a/src/linux/arch/microblaze/boot/.gitignore b/src/linux/arch/microblaze/boot/.gitignore deleted file mode 100644 index bf04591..0000000 --- a/src/linux/arch/microblaze/boot/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.dtb -linux.bin* -simpleImage.* diff --git a/src/linux/arch/microblaze/kernel/.gitignore b/src/linux/arch/microblaze/kernel/.gitignore deleted file mode 100644 index c5f676c..0000000 --- a/src/linux/arch/microblaze/kernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.lds diff --git a/src/linux/arch/mips/boot/.gitignore b/src/linux/arch/mips/boot/.gitignore deleted file mode 100644 index d3962cd..0000000 --- a/src/linux/arch/mips/boot/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -mkboot -elf2ecoff -vmlinux.* -zImage -zImage.tmp -calc_vmlinuz_load_addr -uImage -*.dtb diff --git a/src/linux/arch/mips/boot/dts/include/dt-bindings b/src/linux/arch/mips/boot/dts/include/dt-bindings deleted file mode 120000 index 08c00e4..0000000 --- a/src/linux/arch/mips/boot/dts/include/dt-bindings +++ /dev/null @@ -1 +0,0 @@ -../../../../../include/dt-bindings \ No newline at end of file diff --git a/src/linux/arch/mips/boot/tools/.gitignore b/src/linux/arch/mips/boot/tools/.gitignore deleted file mode 100644 index be0ed06..0000000 --- a/src/linux/arch/mips/boot/tools/.gitignore +++ /dev/null @@ -1 +0,0 @@ -relocs diff --git a/src/linux/arch/mips/kernel/.gitignore b/src/linux/arch/mips/kernel/.gitignore deleted file mode 100644 index c5f676c..0000000 --- a/src/linux/arch/mips/kernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.lds diff --git a/src/linux/arch/mips/vdso/.gitignore b/src/linux/arch/mips/vdso/.gitignore deleted file mode 100644 index 5286a7d..0000000 --- a/src/linux/arch/mips/vdso/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -*.so* -vdso-*image.c -genvdso -vdso*.lds diff --git a/src/linux/arch/mn10300/boot/.gitignore b/src/linux/arch/mn10300/boot/.gitignore deleted file mode 100644 index b6718de..0000000 --- a/src/linux/arch/mn10300/boot/.gitignore +++ /dev/null @@ -1 +0,0 @@ -zImage diff --git a/src/linux/arch/parisc/kernel/.gitignore b/src/linux/arch/parisc/kernel/.gitignore deleted file mode 100644 index c5f676c..0000000 --- a/src/linux/arch/parisc/kernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.lds diff --git a/src/linux/arch/powerpc/boot/.gitignore b/src/linux/arch/powerpc/boot/.gitignore deleted file mode 100644 index d61c035..0000000 --- a/src/linux/arch/powerpc/boot/.gitignore +++ /dev/null @@ -1,44 +0,0 @@ -addnote -empty.c -hack-coff -inffast.c -inffast.h -inffixed.h -inflate.c -inflate.h -inftrees.c -inftrees.h -infutil.c -infutil.h -kernel-vmlinux.strip.c -kernel-vmlinux.strip.gz -mktree -uImage -cuImage.* -dtbImage.* -*.dtb -treeImage.* -zImage -zImage.initrd -zImage.bin.* -zImage.chrp -zImage.coff -zImage.epapr -zImage.holly -zImage.*lds -zImage.miboot -zImage.pmac -zImage.pseries -zconf.h -zlib.h -zutil.h -fdt.c -fdt.h -fdt_ro.c -fdt_rw.c -fdt_strerror.c -fdt_sw.c -fdt_wip.c -libfdt.h -libfdt_internal.h - diff --git a/src/linux/arch/powerpc/boot/dts/include/dt-bindings b/src/linux/arch/powerpc/boot/dts/include/dt-bindings deleted file mode 120000 index 08c00e4..0000000 --- a/src/linux/arch/powerpc/boot/dts/include/dt-bindings +++ /dev/null @@ -1 +0,0 @@ -../../../../../include/dt-bindings \ No newline at end of file diff --git a/src/linux/arch/powerpc/kernel/.gitignore b/src/linux/arch/powerpc/kernel/.gitignore deleted file mode 100644 index c5f676c..0000000 --- a/src/linux/arch/powerpc/kernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.lds diff --git a/src/linux/arch/powerpc/kernel/vdso32/.gitignore b/src/linux/arch/powerpc/kernel/vdso32/.gitignore deleted file mode 100644 index fea5809..0000000 --- a/src/linux/arch/powerpc/kernel/vdso32/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -vdso32.lds -vdso32.so.dbg diff --git a/src/linux/arch/powerpc/kernel/vdso64/.gitignore b/src/linux/arch/powerpc/kernel/vdso64/.gitignore deleted file mode 100644 index 77a0b42..0000000 --- a/src/linux/arch/powerpc/kernel/vdso64/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -vdso64.lds -vdso64.so.dbg diff --git a/src/linux/arch/powerpc/platforms/cell/spufs/.gitignore b/src/linux/arch/powerpc/platforms/cell/spufs/.gitignore deleted file mode 100644 index a09ee8d..0000000 --- a/src/linux/arch/powerpc/platforms/cell/spufs/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -spu_save_dump.h -spu_restore_dump.h diff --git a/src/linux/arch/s390/boot/.gitignore b/src/linux/arch/s390/boot/.gitignore deleted file mode 100644 index 017d591..0000000 --- a/src/linux/arch/s390/boot/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -image -bzImage diff --git a/src/linux/arch/s390/boot/compressed/.gitignore b/src/linux/arch/s390/boot/compressed/.gitignore deleted file mode 100644 index ae06b9b..0000000 --- a/src/linux/arch/s390/boot/compressed/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -sizes.h -vmlinux -vmlinux.lds diff --git a/src/linux/arch/s390/kernel/.gitignore b/src/linux/arch/s390/kernel/.gitignore deleted file mode 100644 index c5f676c..0000000 --- a/src/linux/arch/s390/kernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.lds diff --git a/src/linux/arch/s390/kernel/vdso32/.gitignore b/src/linux/arch/s390/kernel/vdso32/.gitignore deleted file mode 100644 index e45fba9..0000000 --- a/src/linux/arch/s390/kernel/vdso32/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vdso32.lds diff --git a/src/linux/arch/s390/kernel/vdso64/.gitignore b/src/linux/arch/s390/kernel/vdso64/.gitignore deleted file mode 100644 index 3fd18cf..0000000 --- a/src/linux/arch/s390/kernel/vdso64/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vdso64.lds diff --git a/src/linux/arch/s390/tools/.gitignore b/src/linux/arch/s390/tools/.gitignore deleted file mode 100644 index 72a4b2c..0000000 --- a/src/linux/arch/s390/tools/.gitignore +++ /dev/null @@ -1 +0,0 @@ -gen_facilities diff --git a/src/linux/arch/sh/boot/.gitignore b/src/linux/arch/sh/boot/.gitignore deleted file mode 100644 index 541087d..0000000 --- a/src/linux/arch/sh/boot/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -zImage -vmlinux* -uImage* diff --git a/src/linux/arch/sh/boot/compressed/.gitignore b/src/linux/arch/sh/boot/compressed/.gitignore deleted file mode 100644 index 2374a83..0000000 --- a/src/linux/arch/sh/boot/compressed/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.bin.* diff --git a/src/linux/arch/sh/kernel/.gitignore b/src/linux/arch/sh/kernel/.gitignore deleted file mode 100644 index c5f676c..0000000 --- a/src/linux/arch/sh/kernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.lds diff --git a/src/linux/arch/sh/kernel/vsyscall/.gitignore b/src/linux/arch/sh/kernel/vsyscall/.gitignore deleted file mode 100644 index 40836ad..0000000 --- a/src/linux/arch/sh/kernel/vsyscall/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vsyscall.lds diff --git a/src/linux/arch/sparc/boot/.gitignore b/src/linux/arch/sparc/boot/.gitignore deleted file mode 100644 index fc6f398..0000000 --- a/src/linux/arch/sparc/boot/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -btfix.S -btfixupprep -image -zImage -tftpboot.img -vmlinux.aout -piggyback - diff --git a/src/linux/arch/sparc/kernel/.gitignore b/src/linux/arch/sparc/kernel/.gitignore deleted file mode 100644 index c5f676c..0000000 --- a/src/linux/arch/sparc/kernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.lds diff --git a/src/linux/arch/um/.gitignore b/src/linux/arch/um/.gitignore deleted file mode 100644 index a73d3a1..0000000 --- a/src/linux/arch/um/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -kernel/config.c -kernel/config.tmp -kernel/vmlinux.lds diff --git a/src/linux/arch/unicore32/.gitignore b/src/linux/arch/unicore32/.gitignore deleted file mode 100644 index 947e99c..0000000 --- a/src/linux/arch/unicore32/.gitignore +++ /dev/null @@ -1,21 +0,0 @@ -# -# Generated include files -# -include/generated -# -# Generated ld script file -# -kernel/vmlinux.lds -# -# Generated images in boot -# -boot/Image -boot/zImage -boot/uImage -# -# Generated files in boot/compressed -# -boot/compressed/piggy.S -boot/compressed/piggy.gzip -boot/compressed/vmlinux -boot/compressed/vmlinux.lds diff --git a/src/linux/arch/x86/.gitignore b/src/linux/arch/x86/.gitignore deleted file mode 100644 index aff152c..0000000 --- a/src/linux/arch/x86/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -boot/compressed/vmlinux -tools/test_get_len -tools/insn_sanity -purgatory/kexec-purgatory.c -purgatory/purgatory.ro - diff --git a/src/linux/arch/x86/boot/.gitignore b/src/linux/arch/x86/boot/.gitignore deleted file mode 100644 index e3cf9f6..0000000 --- a/src/linux/arch/x86/boot/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -bootsect -bzImage -cpustr.h -mkcpustr -voffset.h -zoffset.h -setup -setup.bin -setup.elf diff --git a/src/linux/arch/x86/boot/compressed/.gitignore b/src/linux/arch/x86/boot/compressed/.gitignore deleted file mode 100644 index 4a46fab..0000000 --- a/src/linux/arch/x86/boot/compressed/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -relocs -vmlinux.bin.all -vmlinux.relocs -vmlinux.lds -mkpiggy -piggy.S diff --git a/src/linux/arch/x86/boot/tools/.gitignore b/src/linux/arch/x86/boot/tools/.gitignore deleted file mode 100644 index 378eac2..0000000 --- a/src/linux/arch/x86/boot/tools/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build diff --git a/src/linux/arch/x86/entry/syscalls/syscall_32.tbl b/src/linux/arch/x86/entry/syscalls/syscall_32.tbl deleted file mode 100644 index 2b36185..0000000 --- a/src/linux/arch/x86/entry/syscalls/syscall_32.tbl +++ /dev/null @@ -1,391 +0,0 @@ -# -# 32-bit system call numbers and entry vectors -# -# The format is: -# -# -# The abi is always "i386" for this file. -# -0 i386 restart_syscall sys_restart_syscall -1 i386 exit sys_exit -2 i386 fork sys_fork sys_fork -3 i386 read sys_read -4 i386 write sys_write -5 i386 open sys_open compat_sys_open -6 i386 close sys_close -7 i386 waitpid sys_waitpid sys32_waitpid -8 i386 creat sys_creat -9 i386 link sys_link -10 i386 unlink sys_unlink -11 i386 execve sys_execve compat_sys_execve -12 i386 chdir sys_chdir -13 i386 time sys_time compat_sys_time -14 i386 mknod sys_mknod -15 i386 chmod sys_chmod -16 i386 lchown sys_lchown16 -17 i386 break -18 i386 oldstat sys_stat -19 i386 lseek sys_lseek compat_sys_lseek -20 i386 getpid sys_getpid -21 i386 mount sys_mount compat_sys_mount -22 i386 umount sys_oldumount -23 i386 setuid sys_setuid16 -24 i386 getuid sys_getuid16 -25 i386 stime sys_stime compat_sys_stime -26 i386 ptrace sys_ptrace compat_sys_ptrace -27 i386 alarm sys_alarm -28 i386 oldfstat sys_fstat -29 i386 pause sys_pause -30 i386 utime sys_utime compat_sys_utime -31 i386 stty -32 i386 gtty -33 i386 access sys_access -34 i386 nice sys_nice -35 i386 ftime -36 i386 sync sys_sync -37 i386 kill sys_kill -38 i386 rename sys_rename -39 i386 mkdir sys_mkdir -40 i386 rmdir sys_rmdir -41 i386 dup sys_dup -42 i386 pipe sys_pipe -43 i386 times sys_times compat_sys_times -44 i386 prof -45 i386 brk sys_brk -46 i386 setgid sys_setgid16 -47 i386 getgid sys_getgid16 -48 i386 signal sys_signal -49 i386 geteuid sys_geteuid16 -50 i386 getegid sys_getegid16 -51 i386 acct sys_acct -52 i386 umount2 sys_umount -53 i386 lock -54 i386 ioctl sys_ioctl compat_sys_ioctl -55 i386 fcntl sys_fcntl compat_sys_fcntl64 -56 i386 mpx -57 i386 setpgid sys_setpgid -58 i386 ulimit -59 i386 oldolduname sys_olduname -60 i386 umask sys_umask -61 i386 chroot sys_chroot -62 i386 ustat sys_ustat compat_sys_ustat -63 i386 dup2 sys_dup2 -64 i386 getppid sys_getppid -65 i386 getpgrp sys_getpgrp -66 i386 setsid sys_setsid -67 i386 sigaction sys_sigaction compat_sys_sigaction -68 i386 sgetmask sys_sgetmask -69 i386 ssetmask sys_ssetmask -70 i386 setreuid sys_setreuid16 -71 i386 setregid sys_setregid16 -72 i386 sigsuspend sys_sigsuspend sys_sigsuspend -73 i386 sigpending sys_sigpending compat_sys_sigpending -74 i386 sethostname sys_sethostname -75 i386 setrlimit sys_setrlimit compat_sys_setrlimit -76 i386 getrlimit sys_old_getrlimit compat_sys_old_getrlimit -77 i386 getrusage sys_getrusage compat_sys_getrusage -78 i386 gettimeofday sys_gettimeofday compat_sys_gettimeofday -79 i386 settimeofday sys_settimeofday compat_sys_settimeofday -80 i386 getgroups sys_getgroups16 -81 i386 setgroups sys_setgroups16 -82 i386 select sys_old_select compat_sys_old_select -83 i386 symlink sys_symlink -84 i386 oldlstat sys_lstat -85 i386 readlink sys_readlink -86 i386 uselib sys_uselib -87 i386 swapon sys_swapon -88 i386 reboot sys_reboot -89 i386 readdir sys_old_readdir compat_sys_old_readdir -90 i386 mmap sys_old_mmap sys32_mmap -91 i386 munmap sys_munmap -92 i386 truncate sys_truncate compat_sys_truncate -93 i386 ftruncate sys_ftruncate compat_sys_ftruncate -94 i386 fchmod sys_fchmod -95 i386 fchown sys_fchown16 -96 i386 getpriority sys_getpriority -97 i386 setpriority sys_setpriority -98 i386 profil -99 i386 statfs sys_statfs compat_sys_statfs -100 i386 fstatfs sys_fstatfs compat_sys_fstatfs -101 i386 ioperm sys_ioperm -102 i386 socketcall sys_socketcall compat_sys_socketcall -103 i386 syslog sys_syslog -104 i386 setitimer sys_setitimer compat_sys_setitimer -105 i386 getitimer sys_getitimer compat_sys_getitimer -106 i386 stat sys_newstat compat_sys_newstat -107 i386 lstat sys_newlstat compat_sys_newlstat -108 i386 fstat sys_newfstat compat_sys_newfstat -109 i386 olduname sys_uname -110 i386 iopl sys_iopl -111 i386 vhangup sys_vhangup -112 i386 idle -113 i386 vm86old sys_vm86old sys_ni_syscall -114 i386 wait4 sys_wait4 compat_sys_wait4 -115 i386 swapoff sys_swapoff -116 i386 sysinfo sys_sysinfo compat_sys_sysinfo -117 i386 ipc sys_ipc compat_sys_ipc -118 i386 fsync sys_fsync -119 i386 sigreturn sys_sigreturn sys32_sigreturn -120 i386 clone sys_clone stub32_clone -121 i386 setdomainname sys_setdomainname -122 i386 uname sys_newuname -123 i386 modify_ldt sys_modify_ldt -124 i386 adjtimex sys_adjtimex compat_sys_adjtimex -125 i386 mprotect sys_mprotect -126 i386 sigprocmask sys_sigprocmask compat_sys_sigprocmask -127 i386 create_module -128 i386 init_module sys_init_module -129 i386 delete_module sys_delete_module -130 i386 get_kernel_syms -131 i386 quotactl sys_quotactl sys32_quotactl -132 i386 getpgid sys_getpgid -133 i386 fchdir sys_fchdir -134 i386 bdflush sys_bdflush -135 i386 sysfs sys_sysfs -136 i386 personality sys_personality -137 i386 afs_syscall -138 i386 setfsuid sys_setfsuid16 -139 i386 setfsgid sys_setfsgid16 -140 i386 _llseek sys_llseek -141 i386 getdents sys_getdents compat_sys_getdents -142 i386 _newselect sys_select compat_sys_select -143 i386 flock sys_flock -144 i386 msync sys_msync -145 i386 readv sys_readv compat_sys_readv -146 i386 writev sys_writev compat_sys_writev -147 i386 getsid sys_getsid -148 i386 fdatasync sys_fdatasync -149 i386 _sysctl sys_sysctl compat_sys_sysctl -150 i386 mlock sys_mlock -151 i386 munlock sys_munlock -152 i386 mlockall sys_mlockall -153 i386 munlockall sys_munlockall -154 i386 sched_setparam sys_sched_setparam -155 i386 sched_getparam sys_sched_getparam -156 i386 sched_setscheduler sys_sched_setscheduler -157 i386 sched_getscheduler sys_sched_getscheduler -158 i386 sched_yield sys_sched_yield -159 i386 sched_get_priority_max sys_sched_get_priority_max -160 i386 sched_get_priority_min sys_sched_get_priority_min -161 i386 sched_rr_get_interval sys_sched_rr_get_interval compat_sys_sched_rr_get_interval -162 i386 nanosleep sys_nanosleep compat_sys_nanosleep -163 i386 mremap sys_mremap -164 i386 setresuid sys_setresuid16 -165 i386 getresuid sys_getresuid16 -166 i386 vm86 sys_vm86 sys_ni_syscall -167 i386 query_module -168 i386 poll sys_poll -169 i386 nfsservctl -170 i386 setresgid sys_setresgid16 -171 i386 getresgid sys_getresgid16 -172 i386 prctl sys_prctl -173 i386 rt_sigreturn sys_rt_sigreturn sys32_rt_sigreturn -174 i386 rt_sigaction sys_rt_sigaction compat_sys_rt_sigaction -175 i386 rt_sigprocmask sys_rt_sigprocmask -176 i386 rt_sigpending sys_rt_sigpending compat_sys_rt_sigpending -177 i386 rt_sigtimedwait sys_rt_sigtimedwait compat_sys_rt_sigtimedwait -178 i386 rt_sigqueueinfo sys_rt_sigqueueinfo compat_sys_rt_sigqueueinfo -179 i386 rt_sigsuspend sys_rt_sigsuspend -180 i386 pread64 sys_pread64 sys32_pread -181 i386 pwrite64 sys_pwrite64 sys32_pwrite -182 i386 chown sys_chown16 -183 i386 getcwd sys_getcwd -184 i386 capget sys_capget -185 i386 capset sys_capset -186 i386 sigaltstack sys_sigaltstack compat_sys_sigaltstack -187 i386 sendfile sys_sendfile compat_sys_sendfile -188 i386 getpmsg -189 i386 putpmsg -190 i386 vfork sys_vfork sys_vfork -191 i386 ugetrlimit sys_getrlimit compat_sys_getrlimit -192 i386 mmap2 sys_mmap_pgoff -193 i386 truncate64 sys_truncate64 sys32_truncate64 -194 i386 ftruncate64 sys_ftruncate64 sys32_ftruncate64 -195 i386 stat64 sys_stat64 sys32_stat64 -196 i386 lstat64 sys_lstat64 sys32_lstat64 -197 i386 fstat64 sys_fstat64 sys32_fstat64 -198 i386 lchown32 sys_lchown -199 i386 getuid32 sys_getuid -200 i386 getgid32 sys_getgid -201 i386 geteuid32 sys_geteuid -202 i386 getegid32 sys_getegid -203 i386 setreuid32 sys_setreuid -204 i386 setregid32 sys_setregid -205 i386 getgroups32 sys_getgroups -206 i386 setgroups32 sys_setgroups -207 i386 fchown32 sys_fchown -208 i386 setresuid32 sys_setresuid -209 i386 getresuid32 sys_getresuid -210 i386 setresgid32 sys_setresgid -211 i386 getresgid32 sys_getresgid -212 i386 chown32 sys_chown -213 i386 setuid32 sys_setuid -214 i386 setgid32 sys_setgid -215 i386 setfsuid32 sys_setfsuid -216 i386 setfsgid32 sys_setfsgid -217 i386 pivot_root sys_pivot_root -218 i386 mincore sys_mincore -219 i386 madvise sys_madvise -220 i386 getdents64 sys_getdents64 compat_sys_getdents64 -221 i386 fcntl64 sys_fcntl64 compat_sys_fcntl64 -# 222 is unused -# 223 is unused -224 i386 gettid sys_gettid -225 i386 readahead sys_readahead sys32_readahead -226 i386 setxattr sys_setxattr -227 i386 lsetxattr sys_lsetxattr -228 i386 fsetxattr sys_fsetxattr -229 i386 getxattr sys_getxattr -230 i386 lgetxattr sys_lgetxattr -231 i386 fgetxattr sys_fgetxattr -232 i386 listxattr sys_listxattr -233 i386 llistxattr sys_llistxattr -234 i386 flistxattr sys_flistxattr -235 i386 removexattr sys_removexattr -236 i386 lremovexattr sys_lremovexattr -237 i386 fremovexattr sys_fremovexattr -238 i386 tkill sys_tkill -239 i386 sendfile64 sys_sendfile64 -240 i386 futex sys_futex compat_sys_futex -241 i386 sched_setaffinity sys_sched_setaffinity compat_sys_sched_setaffinity -242 i386 sched_getaffinity sys_sched_getaffinity compat_sys_sched_getaffinity -243 i386 set_thread_area sys_set_thread_area -244 i386 get_thread_area sys_get_thread_area -245 i386 io_setup sys_io_setup compat_sys_io_setup -246 i386 io_destroy sys_io_destroy -247 i386 io_getevents sys_io_getevents compat_sys_io_getevents -248 i386 io_submit sys_io_submit compat_sys_io_submit -249 i386 io_cancel sys_io_cancel -250 i386 fadvise64 sys_fadvise64 sys32_fadvise64 -# 251 is available for reuse (was briefly sys_set_zone_reclaim) -252 i386 exit_group sys_exit_group -253 i386 lookup_dcookie sys_lookup_dcookie compat_sys_lookup_dcookie -254 i386 epoll_create sys_epoll_create -255 i386 epoll_ctl sys_epoll_ctl -256 i386 epoll_wait sys_epoll_wait -257 i386 remap_file_pages sys_remap_file_pages -258 i386 set_tid_address sys_set_tid_address -259 i386 timer_create sys_timer_create compat_sys_timer_create -260 i386 timer_settime sys_timer_settime compat_sys_timer_settime -261 i386 timer_gettime sys_timer_gettime compat_sys_timer_gettime -262 i386 timer_getoverrun sys_timer_getoverrun -263 i386 timer_delete sys_timer_delete -264 i386 clock_settime sys_clock_settime compat_sys_clock_settime -265 i386 clock_gettime sys_clock_gettime compat_sys_clock_gettime -266 i386 clock_getres sys_clock_getres compat_sys_clock_getres -267 i386 clock_nanosleep sys_clock_nanosleep compat_sys_clock_nanosleep -268 i386 statfs64 sys_statfs64 compat_sys_statfs64 -269 i386 fstatfs64 sys_fstatfs64 compat_sys_fstatfs64 -270 i386 tgkill sys_tgkill -271 i386 utimes sys_utimes compat_sys_utimes -272 i386 fadvise64_64 sys_fadvise64_64 sys32_fadvise64_64 -273 i386 vserver -274 i386 mbind sys_mbind -275 i386 get_mempolicy sys_get_mempolicy compat_sys_get_mempolicy -276 i386 set_mempolicy sys_set_mempolicy -277 i386 mq_open sys_mq_open compat_sys_mq_open -278 i386 mq_unlink sys_mq_unlink -279 i386 mq_timedsend sys_mq_timedsend compat_sys_mq_timedsend -280 i386 mq_timedreceive sys_mq_timedreceive compat_sys_mq_timedreceive -281 i386 mq_notify sys_mq_notify compat_sys_mq_notify -282 i386 mq_getsetattr sys_mq_getsetattr compat_sys_mq_getsetattr -283 i386 kexec_load sys_kexec_load compat_sys_kexec_load -284 i386 waitid sys_waitid compat_sys_waitid -# 285 sys_setaltroot -286 i386 add_key sys_add_key -287 i386 request_key sys_request_key -288 i386 keyctl sys_keyctl compat_sys_keyctl -289 i386 ioprio_set sys_ioprio_set -290 i386 ioprio_get sys_ioprio_get -291 i386 inotify_init sys_inotify_init -292 i386 inotify_add_watch sys_inotify_add_watch -293 i386 inotify_rm_watch sys_inotify_rm_watch -294 i386 migrate_pages sys_migrate_pages -295 i386 openat sys_openat compat_sys_openat -296 i386 mkdirat sys_mkdirat -297 i386 mknodat sys_mknodat -298 i386 fchownat sys_fchownat -299 i386 futimesat sys_futimesat compat_sys_futimesat -300 i386 fstatat64 sys_fstatat64 sys32_fstatat -301 i386 unlinkat sys_unlinkat -302 i386 renameat sys_renameat -303 i386 linkat sys_linkat -304 i386 symlinkat sys_symlinkat -305 i386 readlinkat sys_readlinkat -306 i386 fchmodat sys_fchmodat -307 i386 faccessat sys_faccessat -308 i386 pselect6 sys_pselect6 compat_sys_pselect6 -309 i386 ppoll sys_ppoll compat_sys_ppoll -310 i386 unshare sys_unshare -311 i386 set_robust_list sys_set_robust_list compat_sys_set_robust_list -312 i386 get_robust_list sys_get_robust_list compat_sys_get_robust_list -313 i386 splice sys_splice -314 i386 sync_file_range sys_sync_file_range sys32_sync_file_range -315 i386 tee sys_tee -316 i386 vmsplice sys_vmsplice compat_sys_vmsplice -317 i386 move_pages sys_move_pages compat_sys_move_pages -318 i386 getcpu sys_getcpu -319 i386 epoll_pwait sys_epoll_pwait -320 i386 utimensat sys_utimensat compat_sys_utimensat -321 i386 signalfd sys_signalfd compat_sys_signalfd -322 i386 timerfd_create sys_timerfd_create -323 i386 eventfd sys_eventfd -324 i386 fallocate sys_fallocate sys32_fallocate -325 i386 timerfd_settime sys_timerfd_settime compat_sys_timerfd_settime -326 i386 timerfd_gettime sys_timerfd_gettime compat_sys_timerfd_gettime -327 i386 signalfd4 sys_signalfd4 compat_sys_signalfd4 -328 i386 eventfd2 sys_eventfd2 -329 i386 epoll_create1 sys_epoll_create1 -330 i386 dup3 sys_dup3 -331 i386 pipe2 sys_pipe2 -332 i386 inotify_init1 sys_inotify_init1 -333 i386 preadv sys_preadv compat_sys_preadv -334 i386 pwritev sys_pwritev compat_sys_pwritev -335 i386 rt_tgsigqueueinfo sys_rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo -336 i386 perf_event_open sys_perf_event_open -337 i386 recvmmsg sys_recvmmsg compat_sys_recvmmsg -338 i386 fanotify_init sys_fanotify_init -339 i386 fanotify_mark sys_fanotify_mark compat_sys_fanotify_mark -340 i386 prlimit64 sys_prlimit64 -341 i386 name_to_handle_at sys_name_to_handle_at -342 i386 open_by_handle_at sys_open_by_handle_at compat_sys_open_by_handle_at -343 i386 clock_adjtime sys_clock_adjtime compat_sys_clock_adjtime -344 i386 syncfs sys_syncfs -345 i386 sendmmsg sys_sendmmsg compat_sys_sendmmsg -346 i386 setns sys_setns -347 i386 process_vm_readv sys_process_vm_readv compat_sys_process_vm_readv -348 i386 process_vm_writev sys_process_vm_writev compat_sys_process_vm_writev -349 i386 kcmp sys_kcmp -350 i386 finit_module sys_finit_module -351 i386 sched_setattr sys_sched_setattr -352 i386 sched_getattr sys_sched_getattr -353 i386 renameat2 sys_renameat2 -354 i386 seccomp sys_seccomp -355 i386 getrandom sys_getrandom -356 i386 memfd_create sys_memfd_create -357 i386 bpf sys_bpf -358 i386 execveat sys_execveat compat_sys_execveat -359 i386 socket sys_socket -360 i386 socketpair sys_socketpair -361 i386 bind sys_bind -362 i386 connect sys_connect -363 i386 listen sys_listen -364 i386 accept4 sys_accept4 -365 i386 getsockopt sys_getsockopt compat_sys_getsockopt -366 i386 setsockopt sys_setsockopt compat_sys_setsockopt -367 i386 getsockname sys_getsockname -368 i386 getpeername sys_getpeername -369 i386 sendto sys_sendto -370 i386 sendmsg sys_sendmsg compat_sys_sendmsg -371 i386 recvfrom sys_recvfrom compat_sys_recvfrom -372 i386 recvmsg sys_recvmsg compat_sys_recvmsg -373 i386 shutdown sys_shutdown -374 i386 userfaultfd sys_userfaultfd -375 i386 membarrier sys_membarrier -376 i386 mlock2 sys_mlock2 -377 i386 copy_file_range sys_copy_file_range -378 i386 preadv2 sys_preadv2 compat_sys_preadv2 -379 i386 pwritev2 sys_pwritev2 compat_sys_pwritev2 -380 i386 pkey_mprotect sys_pkey_mprotect -381 i386 pkey_alloc sys_pkey_alloc -382 i386 pkey_free sys_pkey_free diff --git a/src/linux/arch/x86/entry/vdso/.gitignore b/src/linux/arch/x86/entry/vdso/.gitignore deleted file mode 100644 index aae8ffd..0000000 --- a/src/linux/arch/x86/entry/vdso/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -vdso.lds -vdsox32.lds -vdso32-syscall-syms.lds -vdso32-sysenter-syms.lds -vdso32-int80-syms.lds -vdso-image-*.c -vdso2c diff --git a/src/linux/arch/x86/entry/vdso/vdso32/.gitignore b/src/linux/arch/x86/entry/vdso/vdso32/.gitignore deleted file mode 100644 index e45fba9..0000000 --- a/src/linux/arch/x86/entry/vdso/vdso32/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vdso32.lds diff --git a/src/linux/arch/x86/kernel/.gitignore b/src/linux/arch/x86/kernel/.gitignore deleted file mode 100644 index 08f4fd7..0000000 --- a/src/linux/arch/x86/kernel/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -vsyscall.lds -vsyscall_32.lds -vmlinux.lds diff --git a/src/linux/arch/x86/kernel/cpu/.gitignore b/src/linux/arch/x86/kernel/cpu/.gitignore deleted file mode 100644 index 667df55..0000000 --- a/src/linux/arch/x86/kernel/cpu/.gitignore +++ /dev/null @@ -1 +0,0 @@ -capflags.c diff --git a/src/linux/arch/x86/lib/.gitignore b/src/linux/arch/x86/lib/.gitignore deleted file mode 100644 index 8df89f0..0000000 --- a/src/linux/arch/x86/lib/.gitignore +++ /dev/null @@ -1 +0,0 @@ -inat-tables.c diff --git a/src/linux/arch/x86/ras/Kconfig b/src/linux/arch/x86/ras/Kconfig deleted file mode 100644 index d957d5f..0000000 --- a/src/linux/arch/x86/ras/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config MCE_AMD_INJ - tristate "Simple MCE injection interface for AMD processors" - depends on RAS && EDAC_DECODE_MCE && DEBUG_FS && AMD_NB - default n - help - This is a simple debugfs interface to inject MCEs and test different - aspects of the MCE handling code. - - WARNING: Do not even assume this interface is staying stable! diff --git a/src/linux/arch/x86/realmode/rm/.gitignore b/src/linux/arch/x86/realmode/rm/.gitignore deleted file mode 100644 index b6ed3a2..0000000 --- a/src/linux/arch/x86/realmode/rm/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -pasyms.h -realmode.lds -realmode.relocs diff --git a/src/linux/arch/x86/tools/.gitignore b/src/linux/arch/x86/tools/.gitignore deleted file mode 100644 index be0ed06..0000000 --- a/src/linux/arch/x86/tools/.gitignore +++ /dev/null @@ -1 +0,0 @@ -relocs diff --git a/src/linux/arch/x86/um/vdso/.gitignore b/src/linux/arch/x86/um/vdso/.gitignore deleted file mode 100644 index 9cac6d0..0000000 --- a/src/linux/arch/x86/um/vdso/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -vdso-syms.lds -vdso.lds diff --git a/src/linux/arch/xtensa/boot/.gitignore b/src/linux/arch/xtensa/boot/.gitignore deleted file mode 100644 index be76559..0000000 --- a/src/linux/arch/xtensa/boot/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -uImage -zImage.redboot -*.dtb diff --git a/src/linux/arch/xtensa/boot/boot-elf/.gitignore b/src/linux/arch/xtensa/boot/boot-elf/.gitignore deleted file mode 100644 index 5ff8fbb..0000000 --- a/src/linux/arch/xtensa/boot/boot-elf/.gitignore +++ /dev/null @@ -1 +0,0 @@ -boot.lds diff --git a/src/linux/arch/xtensa/boot/lib/.gitignore b/src/linux/arch/xtensa/boot/lib/.gitignore deleted file mode 100644 index 1629a61..0000000 --- a/src/linux/arch/xtensa/boot/lib/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -inffast.c -inflate.c -inftrees.c diff --git a/src/linux/arch/xtensa/kernel/.gitignore b/src/linux/arch/xtensa/kernel/.gitignore deleted file mode 100644 index c5f676c..0000000 --- a/src/linux/arch/xtensa/kernel/.gitignore +++ /dev/null @@ -1 +0,0 @@ -vmlinux.lds diff --git a/src/linux/block/Kconfig b/src/linux/block/Kconfig deleted file mode 100644 index 1d4d624..0000000 --- a/src/linux/block/Kconfig +++ /dev/null @@ -1,133 +0,0 @@ -# -# Block layer core configuration -# -menuconfig BLOCK - bool "Enable the block layer" if EXPERT - default y - select SBITMAP - help - Provide block layer support for the kernel. - - Disable this option to remove the block layer support from the - kernel. This may be useful for embedded devices. - - If this option is disabled: - - - block device files will become unusable - - some filesystems (such as ext3) will become unavailable. - - Also, SCSI character devices and USB storage will be disabled since - they make use of various block layer definitions and facilities. - - Say Y here unless you know you really don't want to mount disks and - suchlike. - -if BLOCK - -config LBDAF - bool "Support for large (2TB+) block devices and files" - depends on !64BIT - default y - help - Enable block devices or files of size 2TB and larger. - - This option is required to support the full capacity of large - (2TB+) block devices, including RAID, disk, Network Block Device, - Logical Volume Manager (LVM) and loopback. - - This option also enables support for single files larger than - 2TB. - - The ext4 filesystem requires that this feature be enabled in - order to support filesystems that have the huge_file feature - enabled. Otherwise, it will refuse to mount in the read-write - mode any filesystems that use the huge_file feature, which is - enabled by default by mke2fs.ext4. - - The GFS2 filesystem also requires this feature. - - If unsure, say Y. - -config BLK_DEV_BSG - bool "Block layer SG support v4" - default y - help - Saying Y here will enable generic SG (SCSI generic) v4 support - for any block device. - - Unlike SG v3 (aka block/scsi_ioctl.c drivers/scsi/sg.c), SG v4 - can handle complicated SCSI commands: tagged variable length cdbs - with bidirectional data transfers and generic request/response - protocols (e.g. Task Management Functions and SMP in Serial - Attached SCSI). - - This option is required by recent UDEV versions to properly - access device serial numbers, etc. - - If unsure, say Y. - -config BLK_DEV_BSGLIB - bool "Block layer SG support v4 helper lib" - default n - select BLK_DEV_BSG - help - Subsystems will normally enable this if needed. Users will not - normally need to manually enable this. - - If unsure, say N. - -config BLK_DEV_INTEGRITY - bool "Block layer data integrity support" - select CRC_T10DIF if BLK_DEV_INTEGRITY - ---help--- - Some storage devices allow extra information to be - stored/retrieved to help protect the data. The block layer - data integrity option provides hooks which can be used by - filesystems to ensure better data integrity. - - Say yes here if you have a storage device that provides the - T10/SCSI Data Integrity Field or the T13/ATA External Path - Protection. If in doubt, say N. - -config BLK_DEV_THROTTLING - bool "Block layer bio throttling support" - depends on BLK_CGROUP=y - default n - ---help--- - Block layer bio throttling support. It can be used to limit - the IO rate to a device. IO rate policies are per cgroup and - one needs to mount and use blkio cgroup controller for creating - cgroups and specifying per device IO rate policies. - - See Documentation/cgroups/blkio-controller.txt for more information. - -config BLK_CMDLINE_PARSER - bool "Block device command line partition parser" - default n - ---help--- - Enabling this option allows you to specify the partition layout from - the kernel boot args. This is typically of use for embedded devices - which don't otherwise have any standardized method for listing the - partitions on a block device. - - See Documentation/block/cmdline-partition.txt for more information. - -menu "Partition Types" - -source "block/partitions/Kconfig" - -endmenu - -endif # BLOCK - -config BLOCK_COMPAT - bool - depends on BLOCK && COMPAT - default y - -config BLK_MQ_PCI - bool - depends on BLOCK && PCI - default y - -source block/Kconfig.iosched diff --git a/src/linux/block/Kconfig.iosched b/src/linux/block/Kconfig.iosched deleted file mode 100644 index 421bef9..0000000 --- a/src/linux/block/Kconfig.iosched +++ /dev/null @@ -1,68 +0,0 @@ -if BLOCK - -menu "IO Schedulers" - -config IOSCHED_NOOP - bool - default y - ---help--- - The no-op I/O scheduler is a minimal scheduler that does basic merging - and sorting. Its main uses include non-disk based block devices like - memory devices, and specialised software or hardware environments - that do their own scheduling and require only minimal assistance from - the kernel. - -config IOSCHED_DEADLINE - tristate "Deadline I/O scheduler" - default y - ---help--- - The deadline I/O scheduler is simple and compact. It will provide - CSCAN service with FIFO expiration of requests, switching to - a new point in the service tree and doing a batch of IO from there - in case of expiry. - -config IOSCHED_CFQ - tristate "CFQ I/O scheduler" - default y - ---help--- - The CFQ I/O scheduler tries to distribute bandwidth equally - among all processes in the system. It should provide a fair - and low latency working environment, suitable for both desktop - and server systems. - - This is the default I/O scheduler. - -config CFQ_GROUP_IOSCHED - bool "CFQ Group Scheduling support" - depends on IOSCHED_CFQ && BLK_CGROUP - default n - ---help--- - Enable group IO scheduling in CFQ. - -choice - prompt "Default I/O scheduler" - default DEFAULT_CFQ - help - Select the I/O scheduler which will be used by default for all - block devices. - - config DEFAULT_DEADLINE - bool "Deadline" if IOSCHED_DEADLINE=y - - config DEFAULT_CFQ - bool "CFQ" if IOSCHED_CFQ=y - - config DEFAULT_NOOP - bool "No-op" - -endchoice - -config DEFAULT_IOSCHED - string - default "deadline" if DEFAULT_DEADLINE - default "cfq" if DEFAULT_CFQ - default "noop" if DEFAULT_NOOP - -endmenu - -endif diff --git a/src/linux/block/Makefile b/src/linux/block/Makefile deleted file mode 100644 index 36acdd7..0000000 --- a/src/linux/block/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# -# Makefile for the kernel block layer -# - -obj-$(CONFIG_BLOCK) := bio.o elevator.o blk-core.o blk-tag.o blk-sysfs.o \ - blk-flush.o blk-settings.o blk-ioc.o blk-map.o \ - blk-exec.o blk-merge.o blk-softirq.o blk-timeout.o \ - blk-lib.o blk-mq.o blk-mq-tag.o \ - blk-mq-sysfs.o blk-mq-cpumap.o ioctl.o \ - genhd.o scsi_ioctl.o partition-generic.o ioprio.o \ - badblocks.o partitions/ - -obj-$(CONFIG_BOUNCE) += bounce.o -obj-$(CONFIG_BLK_DEV_BSG) += bsg.o -obj-$(CONFIG_BLK_DEV_BSGLIB) += bsg-lib.o -obj-$(CONFIG_BLK_CGROUP) += blk-cgroup.o -obj-$(CONFIG_BLK_DEV_THROTTLING) += blk-throttle.o -obj-$(CONFIG_IOSCHED_NOOP) += noop-iosched.o -obj-$(CONFIG_IOSCHED_DEADLINE) += deadline-iosched.o -obj-$(CONFIG_IOSCHED_CFQ) += cfq-iosched.o - -obj-$(CONFIG_BLOCK_COMPAT) += compat_ioctl.o -obj-$(CONFIG_BLK_CMDLINE_PARSER) += cmdline-parser.o -obj-$(CONFIG_BLK_DEV_INTEGRITY) += bio-integrity.o blk-integrity.o t10-pi.o -obj-$(CONFIG_BLK_MQ_PCI) += blk-mq-pci.o diff --git a/src/linux/block/badblocks.c b/src/linux/block/badblocks.c deleted file mode 100644 index 6ebcef2..0000000 --- a/src/linux/block/badblocks.c +++ /dev/null @@ -1,610 +0,0 @@ -/* - * Bad block management - * - * - Heavily based on MD badblocks code from Neil Brown - * - * Copyright (c) 2015, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * badblocks_check() - check a given range for bad sectors - * @bb: the badblocks structure that holds all badblock information - * @s: sector (start) at which to check for badblocks - * @sectors: number of sectors to check for badblocks - * @first_bad: pointer to store location of the first badblock - * @bad_sectors: pointer to store number of badblocks after @first_bad - * - * We can record which blocks on each device are 'bad' and so just - * fail those blocks, or that stripe, rather than the whole device. - * Entries in the bad-block table are 64bits wide. This comprises: - * Length of bad-range, in sectors: 0-511 for lengths 1-512 - * Start of bad-range, sector offset, 54 bits (allows 8 exbibytes) - * A 'shift' can be set so that larger blocks are tracked and - * consequently larger devices can be covered. - * 'Acknowledged' flag - 1 bit. - the most significant bit. - * - * Locking of the bad-block table uses a seqlock so badblocks_check - * might need to retry if it is very unlucky. - * We will sometimes want to check for bad blocks in a bi_end_io function, - * so we use the write_seqlock_irq variant. - * - * When looking for a bad block we specify a range and want to - * know if any block in the range is bad. So we binary-search - * to the last range that starts at-or-before the given endpoint, - * (or "before the sector after the target range") - * then see if it ends after the given start. - * - * Return: - * 0: there are no known bad blocks in the range - * 1: there are known bad block which are all acknowledged - * -1: there are bad blocks which have not yet been acknowledged in metadata. - * plus the start/length of the first bad section we overlap. - */ -int badblocks_check(struct badblocks *bb, sector_t s, int sectors, - sector_t *first_bad, int *bad_sectors) -{ - int hi; - int lo; - u64 *p = bb->page; - int rv; - sector_t target = s + sectors; - unsigned seq; - - if (bb->shift > 0) { - /* round the start down, and the end up */ - s >>= bb->shift; - target += (1<shift) - 1; - target >>= bb->shift; - sectors = target - s; - } - /* 'target' is now the first block after the bad range */ - -retry: - seq = read_seqbegin(&bb->lock); - lo = 0; - rv = 0; - hi = bb->count; - - /* Binary search between lo and hi for 'target' - * i.e. for the last range that starts before 'target' - */ - /* INVARIANT: ranges before 'lo' and at-or-after 'hi' - * are known not to be the last range before target. - * VARIANT: hi-lo is the number of possible - * ranges, and decreases until it reaches 1 - */ - while (hi - lo > 1) { - int mid = (lo + hi) / 2; - sector_t a = BB_OFFSET(p[mid]); - - if (a < target) - /* This could still be the one, earlier ranges - * could not. - */ - lo = mid; - else - /* This and later ranges are definitely out. */ - hi = mid; - } - /* 'lo' might be the last that started before target, but 'hi' isn't */ - if (hi > lo) { - /* need to check all range that end after 's' to see if - * any are unacknowledged. - */ - while (lo >= 0 && - BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) { - if (BB_OFFSET(p[lo]) < target) { - /* starts before the end, and finishes after - * the start, so they must overlap - */ - if (rv != -1 && BB_ACK(p[lo])) - rv = 1; - else - rv = -1; - *first_bad = BB_OFFSET(p[lo]); - *bad_sectors = BB_LEN(p[lo]); - } - lo--; - } - } - - if (read_seqretry(&bb->lock, seq)) - goto retry; - - return rv; -} -EXPORT_SYMBOL_GPL(badblocks_check); - -static void badblocks_update_acked(struct badblocks *bb) -{ - u64 *p = bb->page; - int i; - bool unacked = false; - - if (!bb->unacked_exist) - return; - - for (i = 0; i < bb->count ; i++) { - if (!BB_ACK(p[i])) { - unacked = true; - break; - } - } - - if (!unacked) - bb->unacked_exist = 0; -} - -/** - * badblocks_set() - Add a range of bad blocks to the table. - * @bb: the badblocks structure that holds all badblock information - * @s: first sector to mark as bad - * @sectors: number of sectors to mark as bad - * @acknowledged: weather to mark the bad sectors as acknowledged - * - * This might extend the table, or might contract it if two adjacent ranges - * can be merged. We binary-search to find the 'insertion' point, then - * decide how best to handle it. - * - * Return: - * 0: success - * 1: failed to set badblocks (out of space) - */ -int badblocks_set(struct badblocks *bb, sector_t s, int sectors, - int acknowledged) -{ - u64 *p; - int lo, hi; - int rv = 0; - unsigned long flags; - - if (bb->shift < 0) - /* badblocks are disabled */ - return 0; - - if (bb->shift) { - /* round the start down, and the end up */ - sector_t next = s + sectors; - - s >>= bb->shift; - next += (1<shift) - 1; - next >>= bb->shift; - sectors = next - s; - } - - write_seqlock_irqsave(&bb->lock, flags); - - p = bb->page; - lo = 0; - hi = bb->count; - /* Find the last range that starts at-or-before 's' */ - while (hi - lo > 1) { - int mid = (lo + hi) / 2; - sector_t a = BB_OFFSET(p[mid]); - - if (a <= s) - lo = mid; - else - hi = mid; - } - if (hi > lo && BB_OFFSET(p[lo]) > s) - hi = lo; - - if (hi > lo) { - /* we found a range that might merge with the start - * of our new range - */ - sector_t a = BB_OFFSET(p[lo]); - sector_t e = a + BB_LEN(p[lo]); - int ack = BB_ACK(p[lo]); - - if (e >= s) { - /* Yes, we can merge with a previous range */ - if (s == a && s + sectors >= e) - /* new range covers old */ - ack = acknowledged; - else - ack = ack && acknowledged; - - if (e < s + sectors) - e = s + sectors; - if (e - a <= BB_MAX_LEN) { - p[lo] = BB_MAKE(a, e-a, ack); - s = e; - } else { - /* does not all fit in one range, - * make p[lo] maximal - */ - if (BB_LEN(p[lo]) != BB_MAX_LEN) - p[lo] = BB_MAKE(a, BB_MAX_LEN, ack); - s = a + BB_MAX_LEN; - } - sectors = e - s; - } - } - if (sectors && hi < bb->count) { - /* 'hi' points to the first range that starts after 's'. - * Maybe we can merge with the start of that range - */ - sector_t a = BB_OFFSET(p[hi]); - sector_t e = a + BB_LEN(p[hi]); - int ack = BB_ACK(p[hi]); - - if (a <= s + sectors) { - /* merging is possible */ - if (e <= s + sectors) { - /* full overlap */ - e = s + sectors; - ack = acknowledged; - } else - ack = ack && acknowledged; - - a = s; - if (e - a <= BB_MAX_LEN) { - p[hi] = BB_MAKE(a, e-a, ack); - s = e; - } else { - p[hi] = BB_MAKE(a, BB_MAX_LEN, ack); - s = a + BB_MAX_LEN; - } - sectors = e - s; - lo = hi; - hi++; - } - } - if (sectors == 0 && hi < bb->count) { - /* we might be able to combine lo and hi */ - /* Note: 's' is at the end of 'lo' */ - sector_t a = BB_OFFSET(p[hi]); - int lolen = BB_LEN(p[lo]); - int hilen = BB_LEN(p[hi]); - int newlen = lolen + hilen - (s - a); - - if (s >= a && newlen < BB_MAX_LEN) { - /* yes, we can combine them */ - int ack = BB_ACK(p[lo]) && BB_ACK(p[hi]); - - p[lo] = BB_MAKE(BB_OFFSET(p[lo]), newlen, ack); - memmove(p + hi, p + hi + 1, - (bb->count - hi - 1) * 8); - bb->count--; - } - } - while (sectors) { - /* didn't merge (it all). - * Need to add a range just before 'hi' - */ - if (bb->count >= MAX_BADBLOCKS) { - /* No room for more */ - rv = 1; - break; - } else { - int this_sectors = sectors; - - memmove(p + hi + 1, p + hi, - (bb->count - hi) * 8); - bb->count++; - - if (this_sectors > BB_MAX_LEN) - this_sectors = BB_MAX_LEN; - p[hi] = BB_MAKE(s, this_sectors, acknowledged); - sectors -= this_sectors; - s += this_sectors; - } - } - - bb->changed = 1; - if (!acknowledged) - bb->unacked_exist = 1; - else - badblocks_update_acked(bb); - write_sequnlock_irqrestore(&bb->lock, flags); - - return rv; -} -EXPORT_SYMBOL_GPL(badblocks_set); - -/** - * badblocks_clear() - Remove a range of bad blocks to the table. - * @bb: the badblocks structure that holds all badblock information - * @s: first sector to mark as bad - * @sectors: number of sectors to mark as bad - * - * This may involve extending the table if we spilt a region, - * but it must not fail. So if the table becomes full, we just - * drop the remove request. - * - * Return: - * 0: success - * 1: failed to clear badblocks - */ -int badblocks_clear(struct badblocks *bb, sector_t s, int sectors) -{ - u64 *p; - int lo, hi; - sector_t target = s + sectors; - int rv = 0; - - if (bb->shift > 0) { - /* When clearing we round the start up and the end down. - * This should not matter as the shift should align with - * the block size and no rounding should ever be needed. - * However it is better the think a block is bad when it - * isn't than to think a block is not bad when it is. - */ - s += (1<shift) - 1; - s >>= bb->shift; - target >>= bb->shift; - sectors = target - s; - } - - write_seqlock_irq(&bb->lock); - - p = bb->page; - lo = 0; - hi = bb->count; - /* Find the last range that starts before 'target' */ - while (hi - lo > 1) { - int mid = (lo + hi) / 2; - sector_t a = BB_OFFSET(p[mid]); - - if (a < target) - lo = mid; - else - hi = mid; - } - if (hi > lo) { - /* p[lo] is the last range that could overlap the - * current range. Earlier ranges could also overlap, - * but only this one can overlap the end of the range. - */ - if ((BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > target) && - (BB_OFFSET(p[lo]) < target)) { - /* Partial overlap, leave the tail of this range */ - int ack = BB_ACK(p[lo]); - sector_t a = BB_OFFSET(p[lo]); - sector_t end = a + BB_LEN(p[lo]); - - if (a < s) { - /* we need to split this range */ - if (bb->count >= MAX_BADBLOCKS) { - rv = -ENOSPC; - goto out; - } - memmove(p+lo+1, p+lo, (bb->count - lo) * 8); - bb->count++; - p[lo] = BB_MAKE(a, s-a, ack); - lo++; - } - p[lo] = BB_MAKE(target, end - target, ack); - /* there is no longer an overlap */ - hi = lo; - lo--; - } - while (lo >= 0 && - (BB_OFFSET(p[lo]) + BB_LEN(p[lo]) > s) && - (BB_OFFSET(p[lo]) < target)) { - /* This range does overlap */ - if (BB_OFFSET(p[lo]) < s) { - /* Keep the early parts of this range. */ - int ack = BB_ACK(p[lo]); - sector_t start = BB_OFFSET(p[lo]); - - p[lo] = BB_MAKE(start, s - start, ack); - /* now low doesn't overlap, so.. */ - break; - } - lo--; - } - /* 'lo' is strictly before, 'hi' is strictly after, - * anything between needs to be discarded - */ - if (hi - lo > 1) { - memmove(p+lo+1, p+hi, (bb->count - hi) * 8); - bb->count -= (hi - lo - 1); - } - } - - badblocks_update_acked(bb); - bb->changed = 1; -out: - write_sequnlock_irq(&bb->lock); - return rv; -} -EXPORT_SYMBOL_GPL(badblocks_clear); - -/** - * ack_all_badblocks() - Acknowledge all bad blocks in a list. - * @bb: the badblocks structure that holds all badblock information - * - * This only succeeds if ->changed is clear. It is used by - * in-kernel metadata updates - */ -void ack_all_badblocks(struct badblocks *bb) -{ - if (bb->page == NULL || bb->changed) - /* no point even trying */ - return; - write_seqlock_irq(&bb->lock); - - if (bb->changed == 0 && bb->unacked_exist) { - u64 *p = bb->page; - int i; - - for (i = 0; i < bb->count ; i++) { - if (!BB_ACK(p[i])) { - sector_t start = BB_OFFSET(p[i]); - int len = BB_LEN(p[i]); - - p[i] = BB_MAKE(start, len, 1); - } - } - bb->unacked_exist = 0; - } - write_sequnlock_irq(&bb->lock); -} -EXPORT_SYMBOL_GPL(ack_all_badblocks); - -/** - * badblocks_show() - sysfs access to bad-blocks list - * @bb: the badblocks structure that holds all badblock information - * @page: buffer received from sysfs - * @unack: weather to show unacknowledged badblocks - * - * Return: - * Length of returned data - */ -ssize_t badblocks_show(struct badblocks *bb, char *page, int unack) -{ - size_t len; - int i; - u64 *p = bb->page; - unsigned seq; - - if (bb->shift < 0) - return 0; - -retry: - seq = read_seqbegin(&bb->lock); - - len = 0; - i = 0; - - while (len < PAGE_SIZE && i < bb->count) { - sector_t s = BB_OFFSET(p[i]); - unsigned int length = BB_LEN(p[i]); - int ack = BB_ACK(p[i]); - - i++; - - if (unack && ack) - continue; - - len += snprintf(page+len, PAGE_SIZE-len, "%llu %u\n", - (unsigned long long)s << bb->shift, - length << bb->shift); - } - if (unack && len == 0) - bb->unacked_exist = 0; - - if (read_seqretry(&bb->lock, seq)) - goto retry; - - return len; -} -EXPORT_SYMBOL_GPL(badblocks_show); - -/** - * badblocks_store() - sysfs access to bad-blocks list - * @bb: the badblocks structure that holds all badblock information - * @page: buffer received from sysfs - * @len: length of data received from sysfs - * @unack: weather to show unacknowledged badblocks - * - * Return: - * Length of the buffer processed or -ve error. - */ -ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len, - int unack) -{ - unsigned long long sector; - int length; - char newline; - - switch (sscanf(page, "%llu %d%c", §or, &length, &newline)) { - case 3: - if (newline != '\n') - return -EINVAL; - case 2: - if (length <= 0) - return -EINVAL; - break; - default: - return -EINVAL; - } - - if (badblocks_set(bb, sector, length, !unack)) - return -ENOSPC; - else - return len; -} -EXPORT_SYMBOL_GPL(badblocks_store); - -static int __badblocks_init(struct device *dev, struct badblocks *bb, - int enable) -{ - bb->dev = dev; - bb->count = 0; - if (enable) - bb->shift = 0; - else - bb->shift = -1; - if (dev) - bb->page = devm_kzalloc(dev, PAGE_SIZE, GFP_KERNEL); - else - bb->page = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (!bb->page) { - bb->shift = -1; - return -ENOMEM; - } - seqlock_init(&bb->lock); - - return 0; -} - -/** - * badblocks_init() - initialize the badblocks structure - * @bb: the badblocks structure that holds all badblock information - * @enable: weather to enable badblocks accounting - * - * Return: - * 0: success - * -ve errno: on error - */ -int badblocks_init(struct badblocks *bb, int enable) -{ - return __badblocks_init(NULL, bb, enable); -} -EXPORT_SYMBOL_GPL(badblocks_init); - -int devm_init_badblocks(struct device *dev, struct badblocks *bb) -{ - if (!bb) - return -EINVAL; - return __badblocks_init(dev, bb, 1); -} -EXPORT_SYMBOL_GPL(devm_init_badblocks); - -/** - * badblocks_exit() - free the badblocks structure - * @bb: the badblocks structure that holds all badblock information - */ -void badblocks_exit(struct badblocks *bb) -{ - if (!bb) - return; - if (bb->dev) - devm_kfree(bb->dev, bb->page); - else - kfree(bb->page); - bb->page = NULL; -} -EXPORT_SYMBOL_GPL(badblocks_exit); diff --git a/src/linux/block/bio.c b/src/linux/block/bio.c deleted file mode 100644 index db85c57..0000000 --- a/src/linux/block/bio.c +++ /dev/null @@ -1,2065 +0,0 @@ -/* - * Copyright (C) 2001 Jens Axboe - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public Licens - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * Test patch to inline a certain number of bi_io_vec's inside the bio - * itself, to shrink a bio data allocation from two mempool calls to one - */ -#define BIO_INLINE_VECS 4 - -/* - * if you change this list, also change bvec_alloc or things will - * break badly! cannot be bigger than what you can fit into an - * unsigned short - */ -#define BV(x) { .nr_vecs = x, .name = "biovec-"__stringify(x) } -static struct biovec_slab bvec_slabs[BVEC_POOL_NR] __read_mostly = { - BV(1), BV(4), BV(16), BV(64), BV(128), BV(BIO_MAX_PAGES), -}; -#undef BV - -/* - * fs_bio_set is the bio_set containing bio and iovec memory pools used by - * IO code that does not need private memory pools. - */ -struct bio_set *fs_bio_set; -EXPORT_SYMBOL(fs_bio_set); - -/* - * Our slab pool management - */ -struct bio_slab { - struct kmem_cache *slab; - unsigned int slab_ref; - unsigned int slab_size; - char name[8]; -}; -static DEFINE_MUTEX(bio_slab_lock); -static struct bio_slab *bio_slabs; -static unsigned int bio_slab_nr, bio_slab_max; - -static struct kmem_cache *bio_find_or_create_slab(unsigned int extra_size) -{ - unsigned int sz = sizeof(struct bio) + extra_size; - struct kmem_cache *slab = NULL; - struct bio_slab *bslab, *new_bio_slabs; - unsigned int new_bio_slab_max; - unsigned int i, entry = -1; - - mutex_lock(&bio_slab_lock); - - i = 0; - while (i < bio_slab_nr) { - bslab = &bio_slabs[i]; - - if (!bslab->slab && entry == -1) - entry = i; - else if (bslab->slab_size == sz) { - slab = bslab->slab; - bslab->slab_ref++; - break; - } - i++; - } - - if (slab) - goto out_unlock; - - if (bio_slab_nr == bio_slab_max && entry == -1) { - new_bio_slab_max = bio_slab_max << 1; - new_bio_slabs = krealloc(bio_slabs, - new_bio_slab_max * sizeof(struct bio_slab), - GFP_KERNEL); - if (!new_bio_slabs) - goto out_unlock; - bio_slab_max = new_bio_slab_max; - bio_slabs = new_bio_slabs; - } - if (entry == -1) - entry = bio_slab_nr++; - - bslab = &bio_slabs[entry]; - - snprintf(bslab->name, sizeof(bslab->name), "bio-%d", entry); - slab = kmem_cache_create(bslab->name, sz, ARCH_KMALLOC_MINALIGN, - SLAB_HWCACHE_ALIGN, NULL); - if (!slab) - goto out_unlock; - - bslab->slab = slab; - bslab->slab_ref = 1; - bslab->slab_size = sz; -out_unlock: - mutex_unlock(&bio_slab_lock); - return slab; -} - -static void bio_put_slab(struct bio_set *bs) -{ - struct bio_slab *bslab = NULL; - unsigned int i; - - mutex_lock(&bio_slab_lock); - - for (i = 0; i < bio_slab_nr; i++) { - if (bs->bio_slab == bio_slabs[i].slab) { - bslab = &bio_slabs[i]; - break; - } - } - - if (WARN(!bslab, KERN_ERR "bio: unable to find slab!\n")) - goto out; - - WARN_ON(!bslab->slab_ref); - - if (--bslab->slab_ref) - goto out; - - kmem_cache_destroy(bslab->slab); - bslab->slab = NULL; - -out: - mutex_unlock(&bio_slab_lock); -} - -unsigned int bvec_nr_vecs(unsigned short idx) -{ - return bvec_slabs[idx].nr_vecs; -} - -void bvec_free(mempool_t *pool, struct bio_vec *bv, unsigned int idx) -{ - if (!idx) - return; - idx--; - - BIO_BUG_ON(idx >= BVEC_POOL_NR); - - if (idx == BVEC_POOL_MAX) { - mempool_free(bv, pool); - } else { - struct biovec_slab *bvs = bvec_slabs + idx; - - kmem_cache_free(bvs->slab, bv); - } -} - -struct bio_vec *bvec_alloc(gfp_t gfp_mask, int nr, unsigned long *idx, - mempool_t *pool) -{ - struct bio_vec *bvl; - - /* - * see comment near bvec_array define! - */ - switch (nr) { - case 1: - *idx = 0; - break; - case 2 ... 4: - *idx = 1; - break; - case 5 ... 16: - *idx = 2; - break; - case 17 ... 64: - *idx = 3; - break; - case 65 ... 128: - *idx = 4; - break; - case 129 ... BIO_MAX_PAGES: - *idx = 5; - break; - default: - return NULL; - } - - /* - * idx now points to the pool we want to allocate from. only the - * 1-vec entry pool is mempool backed. - */ - if (*idx == BVEC_POOL_MAX) { -fallback: - bvl = mempool_alloc(pool, gfp_mask); - } else { - struct biovec_slab *bvs = bvec_slabs + *idx; - gfp_t __gfp_mask = gfp_mask & ~(__GFP_DIRECT_RECLAIM | __GFP_IO); - - /* - * Make this allocation restricted and don't dump info on - * allocation failures, since we'll fallback to the mempool - * in case of failure. - */ - __gfp_mask |= __GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN; - - /* - * Try a slab allocation. If this fails and __GFP_DIRECT_RECLAIM - * is set, retry with the 1-entry mempool - */ - bvl = kmem_cache_alloc(bvs->slab, __gfp_mask); - if (unlikely(!bvl && (gfp_mask & __GFP_DIRECT_RECLAIM))) { - *idx = BVEC_POOL_MAX; - goto fallback; - } - } - - (*idx)++; - return bvl; -} - -static void __bio_free(struct bio *bio) -{ - bio_disassociate_task(bio); - - if (bio_integrity(bio)) - bio_integrity_free(bio); -} - -static void bio_free(struct bio *bio) -{ - struct bio_set *bs = bio->bi_pool; - void *p; - - __bio_free(bio); - - if (bs) { - bvec_free(bs->bvec_pool, bio->bi_io_vec, BVEC_POOL_IDX(bio)); - - /* - * If we have front padding, adjust the bio pointer before freeing - */ - p = bio; - p -= bs->front_pad; - - mempool_free(p, bs->bio_pool); - } else { - /* Bio was allocated by bio_kmalloc() */ - kfree(bio); - } -} - -void bio_init(struct bio *bio) -{ - memset(bio, 0, sizeof(*bio)); - atomic_set(&bio->__bi_remaining, 1); - atomic_set(&bio->__bi_cnt, 1); -} -EXPORT_SYMBOL(bio_init); - -/** - * bio_reset - reinitialize a bio - * @bio: bio to reset - * - * Description: - * After calling bio_reset(), @bio will be in the same state as a freshly - * allocated bio returned bio bio_alloc_bioset() - the only fields that are - * preserved are the ones that are initialized by bio_alloc_bioset(). See - * comment in struct bio. - */ -void bio_reset(struct bio *bio) -{ - unsigned long flags = bio->bi_flags & (~0UL << BIO_RESET_BITS); - - __bio_free(bio); - - memset(bio, 0, BIO_RESET_BYTES); - bio->bi_flags = flags; - atomic_set(&bio->__bi_remaining, 1); -} -EXPORT_SYMBOL(bio_reset); - -static struct bio *__bio_chain_endio(struct bio *bio) -{ - struct bio *parent = bio->bi_private; - - if (!parent->bi_error) - parent->bi_error = bio->bi_error; - bio_put(bio); - return parent; -} - -static void bio_chain_endio(struct bio *bio) -{ - bio_endio(__bio_chain_endio(bio)); -} - -/** - * bio_chain - chain bio completions - * @bio: the target bio - * @parent: the @bio's parent bio - * - * The caller won't have a bi_end_io called when @bio completes - instead, - * @parent's bi_end_io won't be called until both @parent and @bio have - * completed; the chained bio will also be freed when it completes. - * - * The caller must not set bi_private or bi_end_io in @bio. - */ -void bio_chain(struct bio *bio, struct bio *parent) -{ - BUG_ON(bio->bi_private || bio->bi_end_io); - - bio->bi_private = parent; - bio->bi_end_io = bio_chain_endio; - bio_inc_remaining(parent); -} -EXPORT_SYMBOL(bio_chain); - -static void bio_alloc_rescue(struct work_struct *work) -{ - struct bio_set *bs = container_of(work, struct bio_set, rescue_work); - struct bio *bio; - - while (1) { - spin_lock(&bs->rescue_lock); - bio = bio_list_pop(&bs->rescue_list); - spin_unlock(&bs->rescue_lock); - - if (!bio) - break; - - generic_make_request(bio); - } -} - -static void punt_bios_to_rescuer(struct bio_set *bs) -{ - struct bio_list punt, nopunt; - struct bio *bio; - - /* - * In order to guarantee forward progress we must punt only bios that - * were allocated from this bio_set; otherwise, if there was a bio on - * there for a stacking driver higher up in the stack, processing it - * could require allocating bios from this bio_set, and doing that from - * our own rescuer would be bad. - * - * Since bio lists are singly linked, pop them all instead of trying to - * remove from the middle of the list: - */ - - bio_list_init(&punt); - bio_list_init(&nopunt); - - while ((bio = bio_list_pop(current->bio_list))) - bio_list_add(bio->bi_pool == bs ? &punt : &nopunt, bio); - - *current->bio_list = nopunt; - - spin_lock(&bs->rescue_lock); - bio_list_merge(&bs->rescue_list, &punt); - spin_unlock(&bs->rescue_lock); - - queue_work(bs->rescue_workqueue, &bs->rescue_work); -} - -/** - * bio_alloc_bioset - allocate a bio for I/O - * @gfp_mask: the GFP_ mask given to the slab allocator - * @nr_iovecs: number of iovecs to pre-allocate - * @bs: the bio_set to allocate from. - * - * Description: - * If @bs is NULL, uses kmalloc() to allocate the bio; else the allocation is - * backed by the @bs's mempool. - * - * When @bs is not NULL, if %__GFP_DIRECT_RECLAIM is set then bio_alloc will - * always be able to allocate a bio. This is due to the mempool guarantees. - * To make this work, callers must never allocate more than 1 bio at a time - * from this pool. Callers that need to allocate more than 1 bio must always - * submit the previously allocated bio for IO before attempting to allocate - * a new one. Failure to do so can cause deadlocks under memory pressure. - * - * Note that when running under generic_make_request() (i.e. any block - * driver), bios are not submitted until after you return - see the code in - * generic_make_request() that converts recursion into iteration, to prevent - * stack overflows. - * - * This would normally mean allocating multiple bios under - * generic_make_request() would be susceptible to deadlocks, but we have - * deadlock avoidance code that resubmits any blocked bios from a rescuer - * thread. - * - * However, we do not guarantee forward progress for allocations from other - * mempools. Doing multiple allocations from the same mempool under - * generic_make_request() should be avoided - instead, use bio_set's front_pad - * for per bio allocations. - * - * RETURNS: - * Pointer to new bio on success, NULL on failure. - */ -struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs) -{ - gfp_t saved_gfp = gfp_mask; - unsigned front_pad; - unsigned inline_vecs; - struct bio_vec *bvl = NULL; - struct bio *bio; - void *p; - - if (!bs) { - if (nr_iovecs > UIO_MAXIOV) - return NULL; - - p = kmalloc(sizeof(struct bio) + - nr_iovecs * sizeof(struct bio_vec), - gfp_mask); - front_pad = 0; - inline_vecs = nr_iovecs; - } else { - /* should not use nobvec bioset for nr_iovecs > 0 */ - if (WARN_ON_ONCE(!bs->bvec_pool && nr_iovecs > 0)) - return NULL; - /* - * generic_make_request() converts recursion to iteration; this - * means if we're running beneath it, any bios we allocate and - * submit will not be submitted (and thus freed) until after we - * return. - * - * This exposes us to a potential deadlock if we allocate - * multiple bios from the same bio_set() while running - * underneath generic_make_request(). If we were to allocate - * multiple bios (say a stacking block driver that was splitting - * bios), we would deadlock if we exhausted the mempool's - * reserve. - * - * We solve this, and guarantee forward progress, with a rescuer - * workqueue per bio_set. If we go to allocate and there are - * bios on current->bio_list, we first try the allocation - * without __GFP_DIRECT_RECLAIM; if that fails, we punt those - * bios we would be blocking to the rescuer workqueue before - * we retry with the original gfp_flags. - */ - - if (current->bio_list && !bio_list_empty(current->bio_list)) - gfp_mask &= ~__GFP_DIRECT_RECLAIM; - - p = mempool_alloc(bs->bio_pool, gfp_mask); - if (!p && gfp_mask != saved_gfp) { - punt_bios_to_rescuer(bs); - gfp_mask = saved_gfp; - p = mempool_alloc(bs->bio_pool, gfp_mask); - } - - front_pad = bs->front_pad; - inline_vecs = BIO_INLINE_VECS; - } - - if (unlikely(!p)) - return NULL; - - bio = p + front_pad; - bio_init(bio); - - if (nr_iovecs > inline_vecs) { - unsigned long idx = 0; - - bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx, bs->bvec_pool); - if (!bvl && gfp_mask != saved_gfp) { - punt_bios_to_rescuer(bs); - gfp_mask = saved_gfp; - bvl = bvec_alloc(gfp_mask, nr_iovecs, &idx, bs->bvec_pool); - } - - if (unlikely(!bvl)) - goto err_free; - - bio->bi_flags |= idx << BVEC_POOL_OFFSET; - } else if (nr_iovecs) { - bvl = bio->bi_inline_vecs; - } - - bio->bi_pool = bs; - bio->bi_max_vecs = nr_iovecs; - bio->bi_io_vec = bvl; - return bio; - -err_free: - mempool_free(p, bs->bio_pool); - return NULL; -} -EXPORT_SYMBOL(bio_alloc_bioset); - -void zero_fill_bio(struct bio *bio) -{ - unsigned long flags; - struct bio_vec bv; - struct bvec_iter iter; - - bio_for_each_segment(bv, bio, iter) { - char *data = bvec_kmap_irq(&bv, &flags); - memset(data, 0, bv.bv_len); - flush_dcache_page(bv.bv_page); - bvec_kunmap_irq(data, &flags); - } -} -EXPORT_SYMBOL(zero_fill_bio); - -/** - * bio_put - release a reference to a bio - * @bio: bio to release reference to - * - * Description: - * Put a reference to a &struct bio, either one you have gotten with - * bio_alloc, bio_get or bio_clone. The last put of a bio will free it. - **/ -void bio_put(struct bio *bio) -{ - if (!bio_flagged(bio, BIO_REFFED)) - bio_free(bio); - else { - BIO_BUG_ON(!atomic_read(&bio->__bi_cnt)); - - /* - * last put frees it - */ - if (atomic_dec_and_test(&bio->__bi_cnt)) - bio_free(bio); - } -} -EXPORT_SYMBOL(bio_put); - -inline int bio_phys_segments(struct request_queue *q, struct bio *bio) -{ - if (unlikely(!bio_flagged(bio, BIO_SEG_VALID))) - blk_recount_segments(q, bio); - - return bio->bi_phys_segments; -} -EXPORT_SYMBOL(bio_phys_segments); - -/** - * __bio_clone_fast - clone a bio that shares the original bio's biovec - * @bio: destination bio - * @bio_src: bio to clone - * - * Clone a &bio. Caller will own the returned bio, but not - * the actual data it points to. Reference count of returned - * bio will be one. - * - * Caller must ensure that @bio_src is not freed before @bio. - */ -void __bio_clone_fast(struct bio *bio, struct bio *bio_src) -{ - BUG_ON(bio->bi_pool && BVEC_POOL_IDX(bio)); - - /* - * most users will be overriding ->bi_bdev with a new target, - * so we don't set nor calculate new physical/hw segment counts here - */ - bio->bi_bdev = bio_src->bi_bdev; - bio_set_flag(bio, BIO_CLONED); - bio->bi_opf = bio_src->bi_opf; - bio->bi_iter = bio_src->bi_iter; - bio->bi_io_vec = bio_src->bi_io_vec; - - bio_clone_blkcg_association(bio, bio_src); -} -EXPORT_SYMBOL(__bio_clone_fast); - -/** - * bio_clone_fast - clone a bio that shares the original bio's biovec - * @bio: bio to clone - * @gfp_mask: allocation priority - * @bs: bio_set to allocate from - * - * Like __bio_clone_fast, only also allocates the returned bio - */ -struct bio *bio_clone_fast(struct bio *bio, gfp_t gfp_mask, struct bio_set *bs) -{ - struct bio *b; - - b = bio_alloc_bioset(gfp_mask, 0, bs); - if (!b) - return NULL; - - __bio_clone_fast(b, bio); - - if (bio_integrity(bio)) { - int ret; - - ret = bio_integrity_clone(b, bio, gfp_mask); - - if (ret < 0) { - bio_put(b); - return NULL; - } - } - - return b; -} -EXPORT_SYMBOL(bio_clone_fast); - -/** - * bio_clone_bioset - clone a bio - * @bio_src: bio to clone - * @gfp_mask: allocation priority - * @bs: bio_set to allocate from - * - * Clone bio. Caller will own the returned bio, but not the actual data it - * points to. Reference count of returned bio will be one. - */ -struct bio *bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask, - struct bio_set *bs) -{ - struct bvec_iter iter; - struct bio_vec bv; - struct bio *bio; - - /* - * Pre immutable biovecs, __bio_clone() used to just do a memcpy from - * bio_src->bi_io_vec to bio->bi_io_vec. - * - * We can't do that anymore, because: - * - * - The point of cloning the biovec is to produce a bio with a biovec - * the caller can modify: bi_idx and bi_bvec_done should be 0. - * - * - The original bio could've had more than BIO_MAX_PAGES biovecs; if - * we tried to clone the whole thing bio_alloc_bioset() would fail. - * But the clone should succeed as long as the number of biovecs we - * actually need to allocate is fewer than BIO_MAX_PAGES. - * - * - Lastly, bi_vcnt should not be looked at or relied upon by code - * that does not own the bio - reason being drivers don't use it for - * iterating over the biovec anymore, so expecting it to be kept up - * to date (i.e. for clones that share the parent biovec) is just - * asking for trouble and would force extra work on - * __bio_clone_fast() anyways. - */ - - bio = bio_alloc_bioset(gfp_mask, bio_segments(bio_src), bs); - if (!bio) - return NULL; - bio->bi_bdev = bio_src->bi_bdev; - bio->bi_opf = bio_src->bi_opf; - bio->bi_iter.bi_sector = bio_src->bi_iter.bi_sector; - bio->bi_iter.bi_size = bio_src->bi_iter.bi_size; - - switch (bio_op(bio)) { - case REQ_OP_DISCARD: - case REQ_OP_SECURE_ERASE: - break; - case REQ_OP_WRITE_SAME: - bio->bi_io_vec[bio->bi_vcnt++] = bio_src->bi_io_vec[0]; - break; - default: - bio_for_each_segment(bv, bio_src, iter) - bio->bi_io_vec[bio->bi_vcnt++] = bv; - break; - } - - if (bio_integrity(bio_src)) { - int ret; - - ret = bio_integrity_clone(bio, bio_src, gfp_mask); - if (ret < 0) { - bio_put(bio); - return NULL; - } - } - - bio_clone_blkcg_association(bio, bio_src); - - return bio; -} -EXPORT_SYMBOL(bio_clone_bioset); - -/** - * bio_add_pc_page - attempt to add page to bio - * @q: the target queue - * @bio: destination bio - * @page: page to add - * @len: vec entry length - * @offset: vec entry offset - * - * Attempt to add a page to the bio_vec maplist. This can fail for a - * number of reasons, such as the bio being full or target block device - * limitations. The target block device must allow bio's up to PAGE_SIZE, - * so it is always possible to add a single page to an empty bio. - * - * This should only be used by REQ_PC bios. - */ -int bio_add_pc_page(struct request_queue *q, struct bio *bio, struct page - *page, unsigned int len, unsigned int offset) -{ - int retried_segments = 0; - struct bio_vec *bvec; - - /* - * cloned bio must not modify vec list - */ - if (unlikely(bio_flagged(bio, BIO_CLONED))) - return 0; - - if (((bio->bi_iter.bi_size + len) >> 9) > queue_max_hw_sectors(q)) - return 0; - - /* - * For filesystems with a blocksize smaller than the pagesize - * we will often be called with the same page as last time and - * a consecutive offset. Optimize this special case. - */ - if (bio->bi_vcnt > 0) { - struct bio_vec *prev = &bio->bi_io_vec[bio->bi_vcnt - 1]; - - if (page == prev->bv_page && - offset == prev->bv_offset + prev->bv_len) { - prev->bv_len += len; - bio->bi_iter.bi_size += len; - goto done; - } - - /* - * If the queue doesn't support SG gaps and adding this - * offset would create a gap, disallow it. - */ - if (bvec_gap_to_prev(q, prev, offset)) - return 0; - } - - if (bio->bi_vcnt >= bio->bi_max_vecs) - return 0; - - /* - * setup the new entry, we might clear it again later if we - * cannot add the page - */ - bvec = &bio->bi_io_vec[bio->bi_vcnt]; - bvec->bv_page = page; - bvec->bv_len = len; - bvec->bv_offset = offset; - bio->bi_vcnt++; - bio->bi_phys_segments++; - bio->bi_iter.bi_size += len; - - /* - * Perform a recount if the number of segments is greater - * than queue_max_segments(q). - */ - - while (bio->bi_phys_segments > queue_max_segments(q)) { - - if (retried_segments) - goto failed; - - retried_segments = 1; - blk_recount_segments(q, bio); - } - - /* If we may be able to merge these biovecs, force a recount */ - if (bio->bi_vcnt > 1 && (BIOVEC_PHYS_MERGEABLE(bvec-1, bvec))) - bio_clear_flag(bio, BIO_SEG_VALID); - - done: - return len; - - failed: - bvec->bv_page = NULL; - bvec->bv_len = 0; - bvec->bv_offset = 0; - bio->bi_vcnt--; - bio->bi_iter.bi_size -= len; - blk_recount_segments(q, bio); - return 0; -} -EXPORT_SYMBOL(bio_add_pc_page); - -/** - * bio_add_page - attempt to add page to bio - * @bio: destination bio - * @page: page to add - * @len: vec entry length - * @offset: vec entry offset - * - * Attempt to add a page to the bio_vec maplist. This will only fail - * if either bio->bi_vcnt == bio->bi_max_vecs or it's a cloned bio. - */ -int bio_add_page(struct bio *bio, struct page *page, - unsigned int len, unsigned int offset) -{ - struct bio_vec *bv; - - /* - * cloned bio must not modify vec list - */ - if (WARN_ON_ONCE(bio_flagged(bio, BIO_CLONED))) - return 0; - - /* - * For filesystems with a blocksize smaller than the pagesize - * we will often be called with the same page as last time and - * a consecutive offset. Optimize this special case. - */ - if (bio->bi_vcnt > 0) { - bv = &bio->bi_io_vec[bio->bi_vcnt - 1]; - - if (page == bv->bv_page && - offset == bv->bv_offset + bv->bv_len) { - bv->bv_len += len; - goto done; - } - } - - if (bio->bi_vcnt >= bio->bi_max_vecs) - return 0; - - bv = &bio->bi_io_vec[bio->bi_vcnt]; - bv->bv_page = page; - bv->bv_len = len; - bv->bv_offset = offset; - - bio->bi_vcnt++; -done: - bio->bi_iter.bi_size += len; - return len; -} -EXPORT_SYMBOL(bio_add_page); - -struct submit_bio_ret { - struct completion event; - int error; -}; - -static void submit_bio_wait_endio(struct bio *bio) -{ - struct submit_bio_ret *ret = bio->bi_private; - - ret->error = bio->bi_error; - complete(&ret->event); -} - -/** - * submit_bio_wait - submit a bio, and wait until it completes - * @bio: The &struct bio which describes the I/O - * - * Simple wrapper around submit_bio(). Returns 0 on success, or the error from - * bio_endio() on failure. - */ -int submit_bio_wait(struct bio *bio) -{ - struct submit_bio_ret ret; - - init_completion(&ret.event); - bio->bi_private = &ret; - bio->bi_end_io = submit_bio_wait_endio; - bio->bi_opf |= REQ_SYNC; - submit_bio(bio); - wait_for_completion_io(&ret.event); - - return ret.error; -} -EXPORT_SYMBOL(submit_bio_wait); - -/** - * bio_advance - increment/complete a bio by some number of bytes - * @bio: bio to advance - * @bytes: number of bytes to complete - * - * This updates bi_sector, bi_size and bi_idx; if the number of bytes to - * complete doesn't align with a bvec boundary, then bv_len and bv_offset will - * be updated on the last bvec as well. - * - * @bio will then represent the remaining, uncompleted portion of the io. - */ -void bio_advance(struct bio *bio, unsigned bytes) -{ - if (bio_integrity(bio)) - bio_integrity_advance(bio, bytes); - - bio_advance_iter(bio, &bio->bi_iter, bytes); -} -EXPORT_SYMBOL(bio_advance); - -/** - * bio_alloc_pages - allocates a single page for each bvec in a bio - * @bio: bio to allocate pages for - * @gfp_mask: flags for allocation - * - * Allocates pages up to @bio->bi_vcnt. - * - * Returns 0 on success, -ENOMEM on failure. On failure, any allocated pages are - * freed. - */ -int bio_alloc_pages(struct bio *bio, gfp_t gfp_mask) -{ - int i; - struct bio_vec *bv; - - bio_for_each_segment_all(bv, bio, i) { - bv->bv_page = alloc_page(gfp_mask); - if (!bv->bv_page) { - while (--bv >= bio->bi_io_vec) - __free_page(bv->bv_page); - return -ENOMEM; - } - } - - return 0; -} -EXPORT_SYMBOL(bio_alloc_pages); - -/** - * bio_copy_data - copy contents of data buffers from one chain of bios to - * another - * @src: source bio list - * @dst: destination bio list - * - * If @src and @dst are single bios, bi_next must be NULL - otherwise, treats - * @src and @dst as linked lists of bios. - * - * Stops when it reaches the end of either @src or @dst - that is, copies - * min(src->bi_size, dst->bi_size) bytes (or the equivalent for lists of bios). - */ -void bio_copy_data(struct bio *dst, struct bio *src) -{ - struct bvec_iter src_iter, dst_iter; - struct bio_vec src_bv, dst_bv; - void *src_p, *dst_p; - unsigned bytes; - - src_iter = src->bi_iter; - dst_iter = dst->bi_iter; - - while (1) { - if (!src_iter.bi_size) { - src = src->bi_next; - if (!src) - break; - - src_iter = src->bi_iter; - } - - if (!dst_iter.bi_size) { - dst = dst->bi_next; - if (!dst) - break; - - dst_iter = dst->bi_iter; - } - - src_bv = bio_iter_iovec(src, src_iter); - dst_bv = bio_iter_iovec(dst, dst_iter); - - bytes = min(src_bv.bv_len, dst_bv.bv_len); - - src_p = kmap_atomic(src_bv.bv_page); - dst_p = kmap_atomic(dst_bv.bv_page); - - memcpy(dst_p + dst_bv.bv_offset, - src_p + src_bv.bv_offset, - bytes); - - kunmap_atomic(dst_p); - kunmap_atomic(src_p); - - bio_advance_iter(src, &src_iter, bytes); - bio_advance_iter(dst, &dst_iter, bytes); - } -} -EXPORT_SYMBOL(bio_copy_data); - -struct bio_map_data { - int is_our_pages; - struct iov_iter iter; - struct iovec iov[]; -}; - -static struct bio_map_data *bio_alloc_map_data(unsigned int iov_count, - gfp_t gfp_mask) -{ - if (iov_count > UIO_MAXIOV) - return NULL; - - return kmalloc(sizeof(struct bio_map_data) + - sizeof(struct iovec) * iov_count, gfp_mask); -} - -/** - * bio_copy_from_iter - copy all pages from iov_iter to bio - * @bio: The &struct bio which describes the I/O as destination - * @iter: iov_iter as source - * - * Copy all pages from iov_iter to bio. - * Returns 0 on success, or error on failure. - */ -static int bio_copy_from_iter(struct bio *bio, struct iov_iter iter) -{ - int i; - struct bio_vec *bvec; - - bio_for_each_segment_all(bvec, bio, i) { - ssize_t ret; - - ret = copy_page_from_iter(bvec->bv_page, - bvec->bv_offset, - bvec->bv_len, - &iter); - - if (!iov_iter_count(&iter)) - break; - - if (ret < bvec->bv_len) - return -EFAULT; - } - - return 0; -} - -/** - * bio_copy_to_iter - copy all pages from bio to iov_iter - * @bio: The &struct bio which describes the I/O as source - * @iter: iov_iter as destination - * - * Copy all pages from bio to iov_iter. - * Returns 0 on success, or error on failure. - */ -static int bio_copy_to_iter(struct bio *bio, struct iov_iter iter) -{ - int i; - struct bio_vec *bvec; - - bio_for_each_segment_all(bvec, bio, i) { - ssize_t ret; - - ret = copy_page_to_iter(bvec->bv_page, - bvec->bv_offset, - bvec->bv_len, - &iter); - - if (!iov_iter_count(&iter)) - break; - - if (ret < bvec->bv_len) - return -EFAULT; - } - - return 0; -} - -void bio_free_pages(struct bio *bio) -{ - struct bio_vec *bvec; - int i; - - bio_for_each_segment_all(bvec, bio, i) - __free_page(bvec->bv_page); -} -EXPORT_SYMBOL(bio_free_pages); - -/** - * bio_uncopy_user - finish previously mapped bio - * @bio: bio being terminated - * - * Free pages allocated from bio_copy_user_iov() and write back data - * to user space in case of a read. - */ -int bio_uncopy_user(struct bio *bio) -{ - struct bio_map_data *bmd = bio->bi_private; - int ret = 0; - - if (!bio_flagged(bio, BIO_NULL_MAPPED)) { - /* - * if we're in a workqueue, the request is orphaned, so - * don't copy into a random user address space, just free - * and return -EINTR so user space doesn't expect any data. - */ - if (!current->mm) - ret = -EINTR; - else if (bio_data_dir(bio) == READ) - ret = bio_copy_to_iter(bio, bmd->iter); - if (bmd->is_our_pages) - bio_free_pages(bio); - } - kfree(bmd); - bio_put(bio); - return ret; -} - -/** - * bio_copy_user_iov - copy user data to bio - * @q: destination block queue - * @map_data: pointer to the rq_map_data holding pages (if necessary) - * @iter: iovec iterator - * @gfp_mask: memory allocation flags - * - * Prepares and returns a bio for indirect user io, bouncing data - * to/from kernel pages as necessary. Must be paired with - * call bio_uncopy_user() on io completion. - */ -struct bio *bio_copy_user_iov(struct request_queue *q, - struct rq_map_data *map_data, - const struct iov_iter *iter, - gfp_t gfp_mask) -{ - struct bio_map_data *bmd; - struct page *page; - struct bio *bio; - int i, ret; - int nr_pages = 0; - unsigned int len = iter->count; - unsigned int offset = map_data ? offset_in_page(map_data->offset) : 0; - - for (i = 0; i < iter->nr_segs; i++) { - unsigned long uaddr; - unsigned long end; - unsigned long start; - - uaddr = (unsigned long) iter->iov[i].iov_base; - end = (uaddr + iter->iov[i].iov_len + PAGE_SIZE - 1) - >> PAGE_SHIFT; - start = uaddr >> PAGE_SHIFT; - - /* - * Overflow, abort - */ - if (end < start) - return ERR_PTR(-EINVAL); - - nr_pages += end - start; - } - - if (offset) - nr_pages++; - - bmd = bio_alloc_map_data(iter->nr_segs, gfp_mask); - if (!bmd) - return ERR_PTR(-ENOMEM); - - /* - * We need to do a deep copy of the iov_iter including the iovecs. - * The caller provided iov might point to an on-stack or otherwise - * shortlived one. - */ - bmd->is_our_pages = map_data ? 0 : 1; - memcpy(bmd->iov, iter->iov, sizeof(struct iovec) * iter->nr_segs); - iov_iter_init(&bmd->iter, iter->type, bmd->iov, - iter->nr_segs, iter->count); - - ret = -ENOMEM; - bio = bio_kmalloc(gfp_mask, nr_pages); - if (!bio) - goto out_bmd; - - if (iter->type & WRITE) - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); - - ret = 0; - - if (map_data) { - nr_pages = 1 << map_data->page_order; - i = map_data->offset / PAGE_SIZE; - } - while (len) { - unsigned int bytes = PAGE_SIZE; - - bytes -= offset; - - if (bytes > len) - bytes = len; - - if (map_data) { - if (i == map_data->nr_entries * nr_pages) { - ret = -ENOMEM; - break; - } - - page = map_data->pages[i / nr_pages]; - page += (i % nr_pages); - - i++; - } else { - page = alloc_page(q->bounce_gfp | gfp_mask); - if (!page) { - ret = -ENOMEM; - break; - } - } - - if (bio_add_pc_page(q, bio, page, bytes, offset) < bytes) - break; - - len -= bytes; - offset = 0; - } - - if (ret) - goto cleanup; - - /* - * success - */ - if (((iter->type & WRITE) && (!map_data || !map_data->null_mapped)) || - (map_data && map_data->from_user)) { - ret = bio_copy_from_iter(bio, *iter); - if (ret) - goto cleanup; - } - - bio->bi_private = bmd; - return bio; -cleanup: - if (!map_data) - bio_free_pages(bio); - bio_put(bio); -out_bmd: - kfree(bmd); - return ERR_PTR(ret); -} - -/** - * bio_map_user_iov - map user iovec into bio - * @q: the struct request_queue for the bio - * @iter: iovec iterator - * @gfp_mask: memory allocation flags - * - * Map the user space address into a bio suitable for io to a block - * device. Returns an error pointer in case of error. - */ -struct bio *bio_map_user_iov(struct request_queue *q, - const struct iov_iter *iter, - gfp_t gfp_mask) -{ - int j; - int nr_pages = 0; - struct page **pages; - struct bio *bio; - int cur_page = 0; - int ret, offset; - struct iov_iter i; - struct iovec iov; - - iov_for_each(iov, i, *iter) { - unsigned long uaddr = (unsigned long) iov.iov_base; - unsigned long len = iov.iov_len; - unsigned long end = (uaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT; - unsigned long start = uaddr >> PAGE_SHIFT; - - /* - * Overflow, abort - */ - if (end < start) - return ERR_PTR(-EINVAL); - - nr_pages += end - start; - /* - * buffer must be aligned to at least logical block size for now - */ - if (uaddr & queue_dma_alignment(q)) - return ERR_PTR(-EINVAL); - } - - if (!nr_pages) - return ERR_PTR(-EINVAL); - - bio = bio_kmalloc(gfp_mask, nr_pages); - if (!bio) - return ERR_PTR(-ENOMEM); - - ret = -ENOMEM; - pages = kcalloc(nr_pages, sizeof(struct page *), gfp_mask); - if (!pages) - goto out; - - iov_for_each(iov, i, *iter) { - unsigned long uaddr = (unsigned long) iov.iov_base; - unsigned long len = iov.iov_len; - unsigned long end = (uaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT; - unsigned long start = uaddr >> PAGE_SHIFT; - const int local_nr_pages = end - start; - const int page_limit = cur_page + local_nr_pages; - - ret = get_user_pages_fast(uaddr, local_nr_pages, - (iter->type & WRITE) != WRITE, - &pages[cur_page]); - if (ret < local_nr_pages) { - ret = -EFAULT; - goto out_unmap; - } - - offset = offset_in_page(uaddr); - for (j = cur_page; j < page_limit; j++) { - unsigned int bytes = PAGE_SIZE - offset; - - if (len <= 0) - break; - - if (bytes > len) - bytes = len; - - /* - * sorry... - */ - if (bio_add_pc_page(q, bio, pages[j], bytes, offset) < - bytes) - break; - - len -= bytes; - offset = 0; - } - - cur_page = j; - /* - * release the pages we didn't map into the bio, if any - */ - while (j < page_limit) - put_page(pages[j++]); - } - - kfree(pages); - - /* - * set data direction, and check if mapped pages need bouncing - */ - if (iter->type & WRITE) - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); - - bio_set_flag(bio, BIO_USER_MAPPED); - - /* - * subtle -- if __bio_map_user() ended up bouncing a bio, - * it would normally disappear when its bi_end_io is run. - * however, we need it for the unmap, so grab an extra - * reference to it - */ - bio_get(bio); - return bio; - - out_unmap: - for (j = 0; j < nr_pages; j++) { - if (!pages[j]) - break; - put_page(pages[j]); - } - out: - kfree(pages); - bio_put(bio); - return ERR_PTR(ret); -} - -static void __bio_unmap_user(struct bio *bio) -{ - struct bio_vec *bvec; - int i; - - /* - * make sure we dirty pages we wrote to - */ - bio_for_each_segment_all(bvec, bio, i) { - if (bio_data_dir(bio) == READ) - set_page_dirty_lock(bvec->bv_page); - - put_page(bvec->bv_page); - } - - bio_put(bio); -} - -/** - * bio_unmap_user - unmap a bio - * @bio: the bio being unmapped - * - * Unmap a bio previously mapped by bio_map_user(). Must be called with - * a process context. - * - * bio_unmap_user() may sleep. - */ -void bio_unmap_user(struct bio *bio) -{ - __bio_unmap_user(bio); - bio_put(bio); -} - -static void bio_map_kern_endio(struct bio *bio) -{ - bio_put(bio); -} - -/** - * bio_map_kern - map kernel address into bio - * @q: the struct request_queue for the bio - * @data: pointer to buffer to map - * @len: length in bytes - * @gfp_mask: allocation flags for bio allocation - * - * Map the kernel address into a bio suitable for io to a block - * device. Returns an error pointer in case of error. - */ -struct bio *bio_map_kern(struct request_queue *q, void *data, unsigned int len, - gfp_t gfp_mask) -{ - unsigned long kaddr = (unsigned long)data; - unsigned long end = (kaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT; - unsigned long start = kaddr >> PAGE_SHIFT; - const int nr_pages = end - start; - int offset, i; - struct bio *bio; - - bio = bio_kmalloc(gfp_mask, nr_pages); - if (!bio) - return ERR_PTR(-ENOMEM); - - offset = offset_in_page(kaddr); - for (i = 0; i < nr_pages; i++) { - unsigned int bytes = PAGE_SIZE - offset; - - if (len <= 0) - break; - - if (bytes > len) - bytes = len; - - if (bio_add_pc_page(q, bio, virt_to_page(data), bytes, - offset) < bytes) { - /* we don't support partial mappings */ - bio_put(bio); - return ERR_PTR(-EINVAL); - } - - data += bytes; - len -= bytes; - offset = 0; - } - - bio->bi_end_io = bio_map_kern_endio; - return bio; -} -EXPORT_SYMBOL(bio_map_kern); - -static void bio_copy_kern_endio(struct bio *bio) -{ - bio_free_pages(bio); - bio_put(bio); -} - -static void bio_copy_kern_endio_read(struct bio *bio) -{ - char *p = bio->bi_private; - struct bio_vec *bvec; - int i; - - bio_for_each_segment_all(bvec, bio, i) { - memcpy(p, page_address(bvec->bv_page), bvec->bv_len); - p += bvec->bv_len; - } - - bio_copy_kern_endio(bio); -} - -/** - * bio_copy_kern - copy kernel address into bio - * @q: the struct request_queue for the bio - * @data: pointer to buffer to copy - * @len: length in bytes - * @gfp_mask: allocation flags for bio and page allocation - * @reading: data direction is READ - * - * copy the kernel address into a bio suitable for io to a block - * device. Returns an error pointer in case of error. - */ -struct bio *bio_copy_kern(struct request_queue *q, void *data, unsigned int len, - gfp_t gfp_mask, int reading) -{ - unsigned long kaddr = (unsigned long)data; - unsigned long end = (kaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT; - unsigned long start = kaddr >> PAGE_SHIFT; - struct bio *bio; - void *p = data; - int nr_pages = 0; - - /* - * Overflow, abort - */ - if (end < start) - return ERR_PTR(-EINVAL); - - nr_pages = end - start; - bio = bio_kmalloc(gfp_mask, nr_pages); - if (!bio) - return ERR_PTR(-ENOMEM); - - while (len) { - struct page *page; - unsigned int bytes = PAGE_SIZE; - - if (bytes > len) - bytes = len; - - page = alloc_page(q->bounce_gfp | gfp_mask); - if (!page) - goto cleanup; - - if (!reading) - memcpy(page_address(page), p, bytes); - - if (bio_add_pc_page(q, bio, page, bytes, 0) < bytes) - break; - - len -= bytes; - p += bytes; - } - - if (reading) { - bio->bi_end_io = bio_copy_kern_endio_read; - bio->bi_private = data; - } else { - bio->bi_end_io = bio_copy_kern_endio; - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); - } - - return bio; - -cleanup: - bio_free_pages(bio); - bio_put(bio); - return ERR_PTR(-ENOMEM); -} - -/* - * bio_set_pages_dirty() and bio_check_pages_dirty() are support functions - * for performing direct-IO in BIOs. - * - * The problem is that we cannot run set_page_dirty() from interrupt context - * because the required locks are not interrupt-safe. So what we can do is to - * mark the pages dirty _before_ performing IO. And in interrupt context, - * check that the pages are still dirty. If so, fine. If not, redirty them - * in process context. - * - * We special-case compound pages here: normally this means reads into hugetlb - * pages. The logic in here doesn't really work right for compound pages - * because the VM does not uniformly chase down the head page in all cases. - * But dirtiness of compound pages is pretty meaningless anyway: the VM doesn't - * handle them at all. So we skip compound pages here at an early stage. - * - * Note that this code is very hard to test under normal circumstances because - * direct-io pins the pages with get_user_pages(). This makes - * is_page_cache_freeable return false, and the VM will not clean the pages. - * But other code (eg, flusher threads) could clean the pages if they are mapped - * pagecache. - * - * Simply disabling the call to bio_set_pages_dirty() is a good way to test the - * deferred bio dirtying paths. - */ - -/* - * bio_set_pages_dirty() will mark all the bio's pages as dirty. - */ -void bio_set_pages_dirty(struct bio *bio) -{ - struct bio_vec *bvec; - int i; - - bio_for_each_segment_all(bvec, bio, i) { - struct page *page = bvec->bv_page; - - if (page && !PageCompound(page)) - set_page_dirty_lock(page); - } -} - -static void bio_release_pages(struct bio *bio) -{ - struct bio_vec *bvec; - int i; - - bio_for_each_segment_all(bvec, bio, i) { - struct page *page = bvec->bv_page; - - if (page) - put_page(page); - } -} - -/* - * bio_check_pages_dirty() will check that all the BIO's pages are still dirty. - * If they are, then fine. If, however, some pages are clean then they must - * have been written out during the direct-IO read. So we take another ref on - * the BIO and the offending pages and re-dirty the pages in process context. - * - * It is expected that bio_check_pages_dirty() will wholly own the BIO from - * here on. It will run one put_page() against each page and will run one - * bio_put() against the BIO. - */ - -static void bio_dirty_fn(struct work_struct *work); - -static DECLARE_WORK(bio_dirty_work, bio_dirty_fn); -static DEFINE_SPINLOCK(bio_dirty_lock); -static struct bio *bio_dirty_list; - -/* - * This runs in process context - */ -static void bio_dirty_fn(struct work_struct *work) -{ - unsigned long flags; - struct bio *bio; - - spin_lock_irqsave(&bio_dirty_lock, flags); - bio = bio_dirty_list; - bio_dirty_list = NULL; - spin_unlock_irqrestore(&bio_dirty_lock, flags); - - while (bio) { - struct bio *next = bio->bi_private; - - bio_set_pages_dirty(bio); - bio_release_pages(bio); - bio_put(bio); - bio = next; - } -} - -void bio_check_pages_dirty(struct bio *bio) -{ - struct bio_vec *bvec; - int nr_clean_pages = 0; - int i; - - bio_for_each_segment_all(bvec, bio, i) { - struct page *page = bvec->bv_page; - - if (PageDirty(page) || PageCompound(page)) { - put_page(page); - bvec->bv_page = NULL; - } else { - nr_clean_pages++; - } - } - - if (nr_clean_pages) { - unsigned long flags; - - spin_lock_irqsave(&bio_dirty_lock, flags); - bio->bi_private = bio_dirty_list; - bio_dirty_list = bio; - spin_unlock_irqrestore(&bio_dirty_lock, flags); - schedule_work(&bio_dirty_work); - } else { - bio_put(bio); - } -} - -void generic_start_io_acct(int rw, unsigned long sectors, - struct hd_struct *part) -{ - int cpu = part_stat_lock(); - - part_round_stats(cpu, part); - part_stat_inc(cpu, part, ios[rw]); - part_stat_add(cpu, part, sectors[rw], sectors); - part_inc_in_flight(part, rw); - - part_stat_unlock(); -} -EXPORT_SYMBOL(generic_start_io_acct); - -void generic_end_io_acct(int rw, struct hd_struct *part, - unsigned long start_time) -{ - unsigned long duration = jiffies - start_time; - int cpu = part_stat_lock(); - - part_stat_add(cpu, part, ticks[rw], duration); - part_round_stats(cpu, part); - part_dec_in_flight(part, rw); - - part_stat_unlock(); -} -EXPORT_SYMBOL(generic_end_io_acct); - -#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE -void bio_flush_dcache_pages(struct bio *bi) -{ - struct bio_vec bvec; - struct bvec_iter iter; - - bio_for_each_segment(bvec, bi, iter) - flush_dcache_page(bvec.bv_page); -} -EXPORT_SYMBOL(bio_flush_dcache_pages); -#endif - -static inline bool bio_remaining_done(struct bio *bio) -{ - /* - * If we're not chaining, then ->__bi_remaining is always 1 and - * we always end io on the first invocation. - */ - if (!bio_flagged(bio, BIO_CHAIN)) - return true; - - BUG_ON(atomic_read(&bio->__bi_remaining) <= 0); - - if (atomic_dec_and_test(&bio->__bi_remaining)) { - bio_clear_flag(bio, BIO_CHAIN); - return true; - } - - return false; -} - -/** - * bio_endio - end I/O on a bio - * @bio: bio - * - * Description: - * bio_endio() will end I/O on the whole bio. bio_endio() is the preferred - * way to end I/O on a bio. No one should call bi_end_io() directly on a - * bio unless they own it and thus know that it has an end_io function. - **/ -void bio_endio(struct bio *bio) -{ -again: - if (!bio_remaining_done(bio)) - return; - - /* - * Need to have a real endio function for chained bios, otherwise - * various corner cases will break (like stacking block devices that - * save/restore bi_end_io) - however, we want to avoid unbounded - * recursion and blowing the stack. Tail call optimization would - * handle this, but compiling with frame pointers also disables - * gcc's sibling call optimization. - */ - if (bio->bi_end_io == bio_chain_endio) { - bio = __bio_chain_endio(bio); - goto again; - } - - if (bio->bi_end_io) - bio->bi_end_io(bio); -} -EXPORT_SYMBOL(bio_endio); - -/** - * bio_split - split a bio - * @bio: bio to split - * @sectors: number of sectors to split from the front of @bio - * @gfp: gfp mask - * @bs: bio set to allocate from - * - * Allocates and returns a new bio which represents @sectors from the start of - * @bio, and updates @bio to represent the remaining sectors. - * - * Unless this is a discard request the newly allocated bio will point - * to @bio's bi_io_vec; it is the caller's responsibility to ensure that - * @bio is not freed before the split. - */ -struct bio *bio_split(struct bio *bio, int sectors, - gfp_t gfp, struct bio_set *bs) -{ - struct bio *split = NULL; - - BUG_ON(sectors <= 0); - BUG_ON(sectors >= bio_sectors(bio)); - - /* - * Discards need a mutable bio_vec to accommodate the payload - * required by the DSM TRIM and UNMAP commands. - */ - if (bio_op(bio) == REQ_OP_DISCARD || bio_op(bio) == REQ_OP_SECURE_ERASE) - split = bio_clone_bioset(bio, gfp, bs); - else - split = bio_clone_fast(bio, gfp, bs); - - if (!split) - return NULL; - - split->bi_iter.bi_size = sectors << 9; - - if (bio_integrity(split)) - bio_integrity_trim(split, 0, sectors); - - bio_advance(bio, split->bi_iter.bi_size); - - return split; -} -EXPORT_SYMBOL(bio_split); - -/** - * bio_trim - trim a bio - * @bio: bio to trim - * @offset: number of sectors to trim from the front of @bio - * @size: size we want to trim @bio to, in sectors - */ -void bio_trim(struct bio *bio, int offset, int size) -{ - /* 'bio' is a cloned bio which we need to trim to match - * the given offset and size. - */ - - size <<= 9; - if (offset == 0 && size == bio->bi_iter.bi_size) - return; - - bio_clear_flag(bio, BIO_SEG_VALID); - - bio_advance(bio, offset << 9); - - bio->bi_iter.bi_size = size; -} -EXPORT_SYMBOL_GPL(bio_trim); - -/* - * create memory pools for biovec's in a bio_set. - * use the global biovec slabs created for general use. - */ -mempool_t *biovec_create_pool(int pool_entries) -{ - struct biovec_slab *bp = bvec_slabs + BVEC_POOL_MAX; - - return mempool_create_slab_pool(pool_entries, bp->slab); -} - -void bioset_free(struct bio_set *bs) -{ - if (bs->rescue_workqueue) - destroy_workqueue(bs->rescue_workqueue); - - if (bs->bio_pool) - mempool_destroy(bs->bio_pool); - - if (bs->bvec_pool) - mempool_destroy(bs->bvec_pool); - - bioset_integrity_free(bs); - bio_put_slab(bs); - - kfree(bs); -} -EXPORT_SYMBOL(bioset_free); - -static struct bio_set *__bioset_create(unsigned int pool_size, - unsigned int front_pad, - bool create_bvec_pool) -{ - unsigned int back_pad = BIO_INLINE_VECS * sizeof(struct bio_vec); - struct bio_set *bs; - - bs = kzalloc(sizeof(*bs), GFP_KERNEL); - if (!bs) - return NULL; - - bs->front_pad = front_pad; - - spin_lock_init(&bs->rescue_lock); - bio_list_init(&bs->rescue_list); - INIT_WORK(&bs->rescue_work, bio_alloc_rescue); - - bs->bio_slab = bio_find_or_create_slab(front_pad + back_pad); - if (!bs->bio_slab) { - kfree(bs); - return NULL; - } - - bs->bio_pool = mempool_create_slab_pool(pool_size, bs->bio_slab); - if (!bs->bio_pool) - goto bad; - - if (create_bvec_pool) { - bs->bvec_pool = biovec_create_pool(pool_size); - if (!bs->bvec_pool) - goto bad; - } - - bs->rescue_workqueue = alloc_workqueue("bioset", WQ_MEM_RECLAIM, 0); - if (!bs->rescue_workqueue) - goto bad; - - return bs; -bad: - bioset_free(bs); - return NULL; -} - -/** - * bioset_create - Create a bio_set - * @pool_size: Number of bio and bio_vecs to cache in the mempool - * @front_pad: Number of bytes to allocate in front of the returned bio - * - * Description: - * Set up a bio_set to be used with @bio_alloc_bioset. Allows the caller - * to ask for a number of bytes to be allocated in front of the bio. - * Front pad allocation is useful for embedding the bio inside - * another structure, to avoid allocating extra data to go with the bio. - * Note that the bio must be embedded at the END of that structure always, - * or things will break badly. - */ -struct bio_set *bioset_create(unsigned int pool_size, unsigned int front_pad) -{ - return __bioset_create(pool_size, front_pad, true); -} -EXPORT_SYMBOL(bioset_create); - -/** - * bioset_create_nobvec - Create a bio_set without bio_vec mempool - * @pool_size: Number of bio to cache in the mempool - * @front_pad: Number of bytes to allocate in front of the returned bio - * - * Description: - * Same functionality as bioset_create() except that mempool is not - * created for bio_vecs. Saving some memory for bio_clone_fast() users. - */ -struct bio_set *bioset_create_nobvec(unsigned int pool_size, unsigned int front_pad) -{ - return __bioset_create(pool_size, front_pad, false); -} -EXPORT_SYMBOL(bioset_create_nobvec); - -#ifdef CONFIG_BLK_CGROUP - -/** - * bio_associate_blkcg - associate a bio with the specified blkcg - * @bio: target bio - * @blkcg_css: css of the blkcg to associate - * - * Associate @bio with the blkcg specified by @blkcg_css. Block layer will - * treat @bio as if it were issued by a task which belongs to the blkcg. - * - * This function takes an extra reference of @blkcg_css which will be put - * when @bio is released. The caller must own @bio and is responsible for - * synchronizing calls to this function. - */ -int bio_associate_blkcg(struct bio *bio, struct cgroup_subsys_state *blkcg_css) -{ - if (unlikely(bio->bi_css)) - return -EBUSY; - css_get(blkcg_css); - bio->bi_css = blkcg_css; - return 0; -} -EXPORT_SYMBOL_GPL(bio_associate_blkcg); - -/** - * bio_associate_current - associate a bio with %current - * @bio: target bio - * - * Associate @bio with %current if it hasn't been associated yet. Block - * layer will treat @bio as if it were issued by %current no matter which - * task actually issues it. - * - * This function takes an extra reference of @task's io_context and blkcg - * which will be put when @bio is released. The caller must own @bio, - * ensure %current->io_context exists, and is responsible for synchronizing - * calls to this function. - */ -int bio_associate_current(struct bio *bio) -{ - struct io_context *ioc; - - if (bio->bi_css) - return -EBUSY; - - ioc = current->io_context; - if (!ioc) - return -ENOENT; - - get_io_context_active(ioc); - bio->bi_ioc = ioc; - bio->bi_css = task_get_css(current, io_cgrp_id); - return 0; -} -EXPORT_SYMBOL_GPL(bio_associate_current); - -/** - * bio_disassociate_task - undo bio_associate_current() - * @bio: target bio - */ -void bio_disassociate_task(struct bio *bio) -{ - if (bio->bi_ioc) { - put_io_context(bio->bi_ioc); - bio->bi_ioc = NULL; - } - if (bio->bi_css) { - css_put(bio->bi_css); - bio->bi_css = NULL; - } -} - -/** - * bio_clone_blkcg_association - clone blkcg association from src to dst bio - * @dst: destination bio - * @src: source bio - */ -void bio_clone_blkcg_association(struct bio *dst, struct bio *src) -{ - if (src->bi_css) - WARN_ON(bio_associate_blkcg(dst, src->bi_css)); -} - -#endif /* CONFIG_BLK_CGROUP */ - -static void __init biovec_init_slabs(void) -{ - int i; - - for (i = 0; i < BVEC_POOL_NR; i++) { - int size; - struct biovec_slab *bvs = bvec_slabs + i; - - if (bvs->nr_vecs <= BIO_INLINE_VECS) { - bvs->slab = NULL; - continue; - } - - size = bvs->nr_vecs * sizeof(struct bio_vec); - bvs->slab = kmem_cache_create(bvs->name, size, 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); - } -} - -static int __init init_bio(void) -{ - bio_slab_max = 2; - bio_slab_nr = 0; - bio_slabs = kzalloc(bio_slab_max * sizeof(struct bio_slab), GFP_KERNEL); - if (!bio_slabs) - panic("bio: can't allocate bios\n"); - - bio_integrity_init(); - biovec_init_slabs(); - - fs_bio_set = bioset_create(BIO_POOL_SIZE, 0); - if (!fs_bio_set) - panic("bio: can't allocate bios\n"); - - if (bioset_integrity_create(fs_bio_set, BIO_POOL_SIZE)) - panic("bio: can't create integrity pool\n"); - - return 0; -} -subsys_initcall(init_bio); diff --git a/src/linux/block/blk-core.c b/src/linux/block/blk-core.c deleted file mode 100644 index 14d7c07..0000000 --- a/src/linux/block/blk-core.c +++ /dev/null @@ -1,3549 +0,0 @@ -/* - * Copyright (C) 1991, 1992 Linus Torvalds - * Copyright (C) 1994, Karl Keyte: Added support for disk statistics - * Elevator latency, (C) 2000 Andrea Arcangeli SuSE - * Queue request tables / lock, selectable elevator, Jens Axboe - * kernel-doc documentation started by NeilBrown - * - July2000 - * bio rewrite, highmem i/o, etc, Jens Axboe - may 2001 - */ - -/* - * This handles all read/write requests to block devices - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CREATE_TRACE_POINTS -#include - -#include "blk.h" -#include "blk-mq.h" - -EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_remap); -EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_remap); -EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_complete); -EXPORT_TRACEPOINT_SYMBOL_GPL(block_split); -EXPORT_TRACEPOINT_SYMBOL_GPL(block_unplug); - -DEFINE_IDA(blk_queue_ida); - -/* - * For the allocated request tables - */ -struct kmem_cache *request_cachep; - -/* - * For queue allocation - */ -struct kmem_cache *blk_requestq_cachep; - -/* - * Controlling structure to kblockd - */ -static struct workqueue_struct *kblockd_workqueue; - -static void blk_clear_congested(struct request_list *rl, int sync) -{ -#ifdef CONFIG_CGROUP_WRITEBACK - clear_wb_congested(rl->blkg->wb_congested, sync); -#else - /* - * If !CGROUP_WRITEBACK, all blkg's map to bdi->wb and we shouldn't - * flip its congestion state for events on other blkcgs. - */ - if (rl == &rl->q->root_rl) - clear_wb_congested(rl->q->backing_dev_info.wb.congested, sync); -#endif -} - -static void blk_set_congested(struct request_list *rl, int sync) -{ -#ifdef CONFIG_CGROUP_WRITEBACK - set_wb_congested(rl->blkg->wb_congested, sync); -#else - /* see blk_clear_congested() */ - if (rl == &rl->q->root_rl) - set_wb_congested(rl->q->backing_dev_info.wb.congested, sync); -#endif -} - -void blk_queue_congestion_threshold(struct request_queue *q) -{ - int nr; - - nr = q->nr_requests - (q->nr_requests / 8) + 1; - if (nr > q->nr_requests) - nr = q->nr_requests; - q->nr_congestion_on = nr; - - nr = q->nr_requests - (q->nr_requests / 8) - (q->nr_requests / 16) - 1; - if (nr < 1) - nr = 1; - q->nr_congestion_off = nr; -} - -/** - * blk_get_backing_dev_info - get the address of a queue's backing_dev_info - * @bdev: device - * - * Locates the passed device's request queue and returns the address of its - * backing_dev_info. This function can only be called if @bdev is opened - * and the return value is never NULL. - */ -struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev) -{ - struct request_queue *q = bdev_get_queue(bdev); - - return &q->backing_dev_info; -} -EXPORT_SYMBOL(blk_get_backing_dev_info); - -void blk_rq_init(struct request_queue *q, struct request *rq) -{ - memset(rq, 0, sizeof(*rq)); - - INIT_LIST_HEAD(&rq->queuelist); - INIT_LIST_HEAD(&rq->timeout_list); - rq->cpu = -1; - rq->q = q; - rq->__sector = (sector_t) -1; - INIT_HLIST_NODE(&rq->hash); - RB_CLEAR_NODE(&rq->rb_node); - rq->cmd = rq->__cmd; - rq->cmd_len = BLK_MAX_CDB; - rq->tag = -1; - rq->start_time = jiffies; - set_start_time_ns(rq); - rq->part = NULL; -} -EXPORT_SYMBOL(blk_rq_init); - -static void req_bio_endio(struct request *rq, struct bio *bio, - unsigned int nbytes, int error) -{ - if (error) - bio->bi_error = error; - - if (unlikely(rq->cmd_flags & REQ_QUIET)) - bio_set_flag(bio, BIO_QUIET); - - bio_advance(bio, nbytes); - - /* don't actually finish bio if it's part of flush sequence */ - if (bio->bi_iter.bi_size == 0 && !(rq->cmd_flags & REQ_FLUSH_SEQ)) - bio_endio(bio); -} - -void blk_dump_rq_flags(struct request *rq, char *msg) -{ - int bit; - - printk(KERN_INFO "%s: dev %s: type=%x, flags=%llx\n", msg, - rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->cmd_type, - (unsigned long long) rq->cmd_flags); - - printk(KERN_INFO " sector %llu, nr/cnr %u/%u\n", - (unsigned long long)blk_rq_pos(rq), - blk_rq_sectors(rq), blk_rq_cur_sectors(rq)); - printk(KERN_INFO " bio %p, biotail %p, len %u\n", - rq->bio, rq->biotail, blk_rq_bytes(rq)); - - if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { - printk(KERN_INFO " cdb: "); - for (bit = 0; bit < BLK_MAX_CDB; bit++) - printk("%02x ", rq->cmd[bit]); - printk("\n"); - } -} -EXPORT_SYMBOL(blk_dump_rq_flags); - -static void blk_delay_work(struct work_struct *work) -{ - struct request_queue *q; - - q = container_of(work, struct request_queue, delay_work.work); - spin_lock_irq(q->queue_lock); - __blk_run_queue(q); - spin_unlock_irq(q->queue_lock); -} - -/** - * blk_delay_queue - restart queueing after defined interval - * @q: The &struct request_queue in question - * @msecs: Delay in msecs - * - * Description: - * Sometimes queueing needs to be postponed for a little while, to allow - * resources to come back. This function will make sure that queueing is - * restarted around the specified time. Queue lock must be held. - */ -void blk_delay_queue(struct request_queue *q, unsigned long msecs) -{ - if (likely(!blk_queue_dead(q))) - queue_delayed_work(kblockd_workqueue, &q->delay_work, - msecs_to_jiffies(msecs)); -} -EXPORT_SYMBOL(blk_delay_queue); - -/** - * blk_start_queue_async - asynchronously restart a previously stopped queue - * @q: The &struct request_queue in question - * - * Description: - * blk_start_queue_async() will clear the stop flag on the queue, and - * ensure that the request_fn for the queue is run from an async - * context. - **/ -void blk_start_queue_async(struct request_queue *q) -{ - queue_flag_clear(QUEUE_FLAG_STOPPED, q); - blk_run_queue_async(q); -} -EXPORT_SYMBOL(blk_start_queue_async); - -/** - * blk_start_queue - restart a previously stopped queue - * @q: The &struct request_queue in question - * - * Description: - * blk_start_queue() will clear the stop flag on the queue, and call - * the request_fn for the queue if it was in a stopped state when - * entered. Also see blk_stop_queue(). Queue lock must be held. - **/ -void blk_start_queue(struct request_queue *q) -{ - WARN_ON(!irqs_disabled()); - - queue_flag_clear(QUEUE_FLAG_STOPPED, q); - __blk_run_queue(q); -} -EXPORT_SYMBOL(blk_start_queue); - -/** - * blk_stop_queue - stop a queue - * @q: The &struct request_queue in question - * - * Description: - * The Linux block layer assumes that a block driver will consume all - * entries on the request queue when the request_fn strategy is called. - * Often this will not happen, because of hardware limitations (queue - * depth settings). If a device driver gets a 'queue full' response, - * or if it simply chooses not to queue more I/O at one point, it can - * call this function to prevent the request_fn from being called until - * the driver has signalled it's ready to go again. This happens by calling - * blk_start_queue() to restart queue operations. Queue lock must be held. - **/ -void blk_stop_queue(struct request_queue *q) -{ - cancel_delayed_work(&q->delay_work); - queue_flag_set(QUEUE_FLAG_STOPPED, q); -} -EXPORT_SYMBOL(blk_stop_queue); - -/** - * blk_sync_queue - cancel any pending callbacks on a queue - * @q: the queue - * - * Description: - * The block layer may perform asynchronous callback activity - * on a queue, such as calling the unplug function after a timeout. - * A block device may call blk_sync_queue to ensure that any - * such activity is cancelled, thus allowing it to release resources - * that the callbacks might use. The caller must already have made sure - * that its ->make_request_fn will not re-add plugging prior to calling - * this function. - * - * This function does not cancel any asynchronous activity arising - * out of elevator or throttling code. That would require elevator_exit() - * and blkcg_exit_queue() to be called with queue lock initialized. - * - */ -void blk_sync_queue(struct request_queue *q) -{ - del_timer_sync(&q->timeout); - - if (q->mq_ops) { - struct blk_mq_hw_ctx *hctx; - int i; - - queue_for_each_hw_ctx(q, hctx, i) { - cancel_work_sync(&hctx->run_work); - cancel_delayed_work_sync(&hctx->delay_work); - } - } else { - cancel_delayed_work_sync(&q->delay_work); - } -} -EXPORT_SYMBOL(blk_sync_queue); - -/** - * __blk_run_queue_uncond - run a queue whether or not it has been stopped - * @q: The queue to run - * - * Description: - * Invoke request handling on a queue if there are any pending requests. - * May be used to restart request handling after a request has completed. - * This variant runs the queue whether or not the queue has been - * stopped. Must be called with the queue lock held and interrupts - * disabled. See also @blk_run_queue. - */ -inline void __blk_run_queue_uncond(struct request_queue *q) -{ - if (unlikely(blk_queue_dead(q))) - return; - - /* - * Some request_fn implementations, e.g. scsi_request_fn(), unlock - * the queue lock internally. As a result multiple threads may be - * running such a request function concurrently. Keep track of the - * number of active request_fn invocations such that blk_drain_queue() - * can wait until all these request_fn calls have finished. - */ - q->request_fn_active++; - q->request_fn(q); - q->request_fn_active--; -} -EXPORT_SYMBOL_GPL(__blk_run_queue_uncond); - -/** - * __blk_run_queue - run a single device queue - * @q: The queue to run - * - * Description: - * See @blk_run_queue. This variant must be called with the queue lock - * held and interrupts disabled. - */ -void __blk_run_queue(struct request_queue *q) -{ - if (unlikely(blk_queue_stopped(q))) - return; - - __blk_run_queue_uncond(q); -} -EXPORT_SYMBOL(__blk_run_queue); - -/** - * blk_run_queue_async - run a single device queue in workqueue context - * @q: The queue to run - * - * Description: - * Tells kblockd to perform the equivalent of @blk_run_queue on behalf - * of us. The caller must hold the queue lock. - */ -void blk_run_queue_async(struct request_queue *q) -{ - if (likely(!blk_queue_stopped(q) && !blk_queue_dead(q))) - mod_delayed_work(kblockd_workqueue, &q->delay_work, 0); -} -EXPORT_SYMBOL(blk_run_queue_async); - -/** - * blk_run_queue - run a single device queue - * @q: The queue to run - * - * Description: - * Invoke request handling on this queue, if it has pending work to do. - * May be used to restart queueing when a request has completed. - */ -void blk_run_queue(struct request_queue *q) -{ - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - __blk_run_queue(q); - spin_unlock_irqrestore(q->queue_lock, flags); -} -EXPORT_SYMBOL(blk_run_queue); - -void blk_put_queue(struct request_queue *q) -{ - kobject_put(&q->kobj); -} -EXPORT_SYMBOL(blk_put_queue); - -/** - * __blk_drain_queue - drain requests from request_queue - * @q: queue to drain - * @drain_all: whether to drain all requests or only the ones w/ ELVPRIV - * - * Drain requests from @q. If @drain_all is set, all requests are drained. - * If not, only ELVPRIV requests are drained. The caller is responsible - * for ensuring that no new requests which need to be drained are queued. - */ -static void __blk_drain_queue(struct request_queue *q, bool drain_all) - __releases(q->queue_lock) - __acquires(q->queue_lock) -{ - int i; - - lockdep_assert_held(q->queue_lock); - - while (true) { - bool drain = false; - - /* - * The caller might be trying to drain @q before its - * elevator is initialized. - */ - if (q->elevator) - elv_drain_elevator(q); - - blkcg_drain_queue(q); - - /* - * This function might be called on a queue which failed - * driver init after queue creation or is not yet fully - * active yet. Some drivers (e.g. fd and loop) get unhappy - * in such cases. Kick queue iff dispatch queue has - * something on it and @q has request_fn set. - */ - if (!list_empty(&q->queue_head) && q->request_fn) - __blk_run_queue(q); - - drain |= q->nr_rqs_elvpriv; - drain |= q->request_fn_active; - - /* - * Unfortunately, requests are queued at and tracked from - * multiple places and there's no single counter which can - * be drained. Check all the queues and counters. - */ - if (drain_all) { - struct blk_flush_queue *fq = blk_get_flush_queue(q, NULL); - drain |= !list_empty(&q->queue_head); - for (i = 0; i < 2; i++) { - drain |= q->nr_rqs[i]; - drain |= q->in_flight[i]; - if (fq) - drain |= !list_empty(&fq->flush_queue[i]); - } - } - - if (!drain) - break; - - spin_unlock_irq(q->queue_lock); - - msleep(10); - - spin_lock_irq(q->queue_lock); - } - - /* - * With queue marked dead, any woken up waiter will fail the - * allocation path, so the wakeup chaining is lost and we're - * left with hung waiters. We need to wake up those waiters. - */ - if (q->request_fn) { - struct request_list *rl; - - blk_queue_for_each_rl(rl, q) - for (i = 0; i < ARRAY_SIZE(rl->wait); i++) - wake_up_all(&rl->wait[i]); - } -} - -/** - * blk_queue_bypass_start - enter queue bypass mode - * @q: queue of interest - * - * In bypass mode, only the dispatch FIFO queue of @q is used. This - * function makes @q enter bypass mode and drains all requests which were - * throttled or issued before. On return, it's guaranteed that no request - * is being throttled or has ELVPRIV set and blk_queue_bypass() %true - * inside queue or RCU read lock. - */ -void blk_queue_bypass_start(struct request_queue *q) -{ - spin_lock_irq(q->queue_lock); - q->bypass_depth++; - queue_flag_set(QUEUE_FLAG_BYPASS, q); - spin_unlock_irq(q->queue_lock); - - /* - * Queues start drained. Skip actual draining till init is - * complete. This avoids lenghty delays during queue init which - * can happen many times during boot. - */ - if (blk_queue_init_done(q)) { - spin_lock_irq(q->queue_lock); - __blk_drain_queue(q, false); - spin_unlock_irq(q->queue_lock); - - /* ensure blk_queue_bypass() is %true inside RCU read lock */ - synchronize_rcu(); - } -} -EXPORT_SYMBOL_GPL(blk_queue_bypass_start); - -/** - * blk_queue_bypass_end - leave queue bypass mode - * @q: queue of interest - * - * Leave bypass mode and restore the normal queueing behavior. - */ -void blk_queue_bypass_end(struct request_queue *q) -{ - spin_lock_irq(q->queue_lock); - if (!--q->bypass_depth) - queue_flag_clear(QUEUE_FLAG_BYPASS, q); - WARN_ON_ONCE(q->bypass_depth < 0); - spin_unlock_irq(q->queue_lock); -} -EXPORT_SYMBOL_GPL(blk_queue_bypass_end); - -void blk_set_queue_dying(struct request_queue *q) -{ - spin_lock_irq(q->queue_lock); - queue_flag_set(QUEUE_FLAG_DYING, q); - spin_unlock_irq(q->queue_lock); - - if (q->mq_ops) - blk_mq_wake_waiters(q); - else { - struct request_list *rl; - - blk_queue_for_each_rl(rl, q) { - if (rl->rq_pool) { - wake_up(&rl->wait[BLK_RW_SYNC]); - wake_up(&rl->wait[BLK_RW_ASYNC]); - } - } - } -} -EXPORT_SYMBOL_GPL(blk_set_queue_dying); - -/** - * blk_cleanup_queue - shutdown a request queue - * @q: request queue to shutdown - * - * Mark @q DYING, drain all pending requests, mark @q DEAD, destroy and - * put it. All future requests will be failed immediately with -ENODEV. - */ -void blk_cleanup_queue(struct request_queue *q) -{ - spinlock_t *lock = q->queue_lock; - - /* mark @q DYING, no new request or merges will be allowed afterwards */ - mutex_lock(&q->sysfs_lock); - blk_set_queue_dying(q); - spin_lock_irq(lock); - - /* - * A dying queue is permanently in bypass mode till released. Note - * that, unlike blk_queue_bypass_start(), we aren't performing - * synchronize_rcu() after entering bypass mode to avoid the delay - * as some drivers create and destroy a lot of queues while - * probing. This is still safe because blk_release_queue() will be - * called only after the queue refcnt drops to zero and nothing, - * RCU or not, would be traversing the queue by then. - */ - q->bypass_depth++; - queue_flag_set(QUEUE_FLAG_BYPASS, q); - - queue_flag_set(QUEUE_FLAG_NOMERGES, q); - queue_flag_set(QUEUE_FLAG_NOXMERGES, q); - queue_flag_set(QUEUE_FLAG_DYING, q); - spin_unlock_irq(lock); - mutex_unlock(&q->sysfs_lock); - - /* - * Drain all requests queued before DYING marking. Set DEAD flag to - * prevent that q->request_fn() gets invoked after draining finished. - */ - blk_freeze_queue(q); - spin_lock_irq(lock); - if (!q->mq_ops) - __blk_drain_queue(q, true); - queue_flag_set(QUEUE_FLAG_DEAD, q); - spin_unlock_irq(lock); - - /* for synchronous bio-based driver finish in-flight integrity i/o */ - blk_flush_integrity(); - - /* @q won't process any more request, flush async actions */ - del_timer_sync(&q->backing_dev_info.laptop_mode_wb_timer); - blk_sync_queue(q); - - if (q->mq_ops) - blk_mq_free_queue(q); - percpu_ref_exit(&q->q_usage_counter); - - spin_lock_irq(lock); - if (q->queue_lock != &q->__queue_lock) - q->queue_lock = &q->__queue_lock; - spin_unlock_irq(lock); - - bdi_unregister(&q->backing_dev_info); - - /* @q is and will stay empty, shutdown and put */ - blk_put_queue(q); -} -EXPORT_SYMBOL(blk_cleanup_queue); - -/* Allocate memory local to the request queue */ -static void *alloc_request_struct(gfp_t gfp_mask, void *data) -{ - int nid = (int)(long)data; - return kmem_cache_alloc_node(request_cachep, gfp_mask, nid); -} - -static void free_request_struct(void *element, void *unused) -{ - kmem_cache_free(request_cachep, element); -} - -int blk_init_rl(struct request_list *rl, struct request_queue *q, - gfp_t gfp_mask) -{ - if (unlikely(rl->rq_pool)) - return 0; - - rl->q = q; - rl->count[BLK_RW_SYNC] = rl->count[BLK_RW_ASYNC] = 0; - rl->starved[BLK_RW_SYNC] = rl->starved[BLK_RW_ASYNC] = 0; - init_waitqueue_head(&rl->wait[BLK_RW_SYNC]); - init_waitqueue_head(&rl->wait[BLK_RW_ASYNC]); - - rl->rq_pool = mempool_create_node(BLKDEV_MIN_RQ, alloc_request_struct, - free_request_struct, - (void *)(long)q->node, gfp_mask, - q->node); - if (!rl->rq_pool) - return -ENOMEM; - - return 0; -} - -void blk_exit_rl(struct request_list *rl) -{ - if (rl->rq_pool) - mempool_destroy(rl->rq_pool); -} - -struct request_queue *blk_alloc_queue(gfp_t gfp_mask) -{ - return blk_alloc_queue_node(gfp_mask, NUMA_NO_NODE); -} -EXPORT_SYMBOL(blk_alloc_queue); - -int blk_queue_enter(struct request_queue *q, bool nowait) -{ - while (true) { - int ret; - - if (percpu_ref_tryget_live(&q->q_usage_counter)) - return 0; - - if (nowait) - return -EBUSY; - - ret = wait_event_interruptible(q->mq_freeze_wq, - !atomic_read(&q->mq_freeze_depth) || - blk_queue_dying(q)); - if (blk_queue_dying(q)) - return -ENODEV; - if (ret) - return ret; - } -} - -void blk_queue_exit(struct request_queue *q) -{ - percpu_ref_put(&q->q_usage_counter); -} - -static void blk_queue_usage_counter_release(struct percpu_ref *ref) -{ - struct request_queue *q = - container_of(ref, struct request_queue, q_usage_counter); - - wake_up_all(&q->mq_freeze_wq); -} - -static void blk_rq_timed_out_timer(unsigned long data) -{ - struct request_queue *q = (struct request_queue *)data; - - kblockd_schedule_work(&q->timeout_work); -} - -struct request_queue *blk_alloc_queue_node(gfp_t gfp_mask, int node_id) -{ - struct request_queue *q; - int err; - - q = kmem_cache_alloc_node(blk_requestq_cachep, - gfp_mask | __GFP_ZERO, node_id); - if (!q) - return NULL; - - q->id = ida_simple_get(&blk_queue_ida, 0, 0, gfp_mask); - if (q->id < 0) - goto fail_q; - - q->bio_split = bioset_create(BIO_POOL_SIZE, 0); - if (!q->bio_split) - goto fail_id; - - q->backing_dev_info.ra_pages = - (VM_MAX_READAHEAD * 1024) / PAGE_SIZE; - q->backing_dev_info.capabilities = BDI_CAP_CGROUP_WRITEBACK; - q->backing_dev_info.name = "block"; - q->node = node_id; - - err = bdi_init(&q->backing_dev_info); - if (err) - goto fail_split; - - setup_timer(&q->backing_dev_info.laptop_mode_wb_timer, - laptop_mode_timer_fn, (unsigned long) q); - setup_timer(&q->timeout, blk_rq_timed_out_timer, (unsigned long) q); - INIT_LIST_HEAD(&q->queue_head); - INIT_LIST_HEAD(&q->timeout_list); - INIT_LIST_HEAD(&q->icq_list); -#ifdef CONFIG_BLK_CGROUP - INIT_LIST_HEAD(&q->blkg_list); -#endif - INIT_DELAYED_WORK(&q->delay_work, blk_delay_work); - - kobject_init(&q->kobj, &blk_queue_ktype); - - mutex_init(&q->sysfs_lock); - spin_lock_init(&q->__queue_lock); - - /* - * By default initialize queue_lock to internal lock and driver can - * override it later if need be. - */ - q->queue_lock = &q->__queue_lock; - - /* - * A queue starts its life with bypass turned on to avoid - * unnecessary bypass on/off overhead and nasty surprises during - * init. The initial bypass will be finished when the queue is - * registered by blk_register_queue(). - */ - q->bypass_depth = 1; - __set_bit(QUEUE_FLAG_BYPASS, &q->queue_flags); - - init_waitqueue_head(&q->mq_freeze_wq); - - /* - * Init percpu_ref in atomic mode so that it's faster to shutdown. - * See blk_register_queue() for details. - */ - if (percpu_ref_init(&q->q_usage_counter, - blk_queue_usage_counter_release, - PERCPU_REF_INIT_ATOMIC, GFP_KERNEL)) - goto fail_bdi; - - if (blkcg_init_queue(q)) - goto fail_ref; - - return q; - -fail_ref: - percpu_ref_exit(&q->q_usage_counter); -fail_bdi: - bdi_destroy(&q->backing_dev_info); -fail_split: - bioset_free(q->bio_split); -fail_id: - ida_simple_remove(&blk_queue_ida, q->id); -fail_q: - kmem_cache_free(blk_requestq_cachep, q); - return NULL; -} -EXPORT_SYMBOL(blk_alloc_queue_node); - -/** - * blk_init_queue - prepare a request queue for use with a block device - * @rfn: The function to be called to process requests that have been - * placed on the queue. - * @lock: Request queue spin lock - * - * Description: - * If a block device wishes to use the standard request handling procedures, - * which sorts requests and coalesces adjacent requests, then it must - * call blk_init_queue(). The function @rfn will be called when there - * are requests on the queue that need to be processed. If the device - * supports plugging, then @rfn may not be called immediately when requests - * are available on the queue, but may be called at some time later instead. - * Plugged queues are generally unplugged when a buffer belonging to one - * of the requests on the queue is needed, or due to memory pressure. - * - * @rfn is not required, or even expected, to remove all requests off the - * queue, but only as many as it can handle at a time. If it does leave - * requests on the queue, it is responsible for arranging that the requests - * get dealt with eventually. - * - * The queue spin lock must be held while manipulating the requests on the - * request queue; this lock will be taken also from interrupt context, so irq - * disabling is needed for it. - * - * Function returns a pointer to the initialized request queue, or %NULL if - * it didn't succeed. - * - * Note: - * blk_init_queue() must be paired with a blk_cleanup_queue() call - * when the block device is deactivated (such as at module unload). - **/ - -struct request_queue *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock) -{ - return blk_init_queue_node(rfn, lock, NUMA_NO_NODE); -} -EXPORT_SYMBOL(blk_init_queue); - -struct request_queue * -blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id) -{ - struct request_queue *uninit_q, *q; - - uninit_q = blk_alloc_queue_node(GFP_KERNEL, node_id); - if (!uninit_q) - return NULL; - - q = blk_init_allocated_queue(uninit_q, rfn, lock); - if (!q) - blk_cleanup_queue(uninit_q); - - return q; -} -EXPORT_SYMBOL(blk_init_queue_node); - -static blk_qc_t blk_queue_bio(struct request_queue *q, struct bio *bio); - -struct request_queue * -blk_init_allocated_queue(struct request_queue *q, request_fn_proc *rfn, - spinlock_t *lock) -{ - if (!q) - return NULL; - - q->fq = blk_alloc_flush_queue(q, NUMA_NO_NODE, 0); - if (!q->fq) - return NULL; - - if (blk_init_rl(&q->root_rl, q, GFP_KERNEL)) - goto fail; - - INIT_WORK(&q->timeout_work, blk_timeout_work); - q->request_fn = rfn; - q->prep_rq_fn = NULL; - q->unprep_rq_fn = NULL; - q->queue_flags |= QUEUE_FLAG_DEFAULT; - - /* Override internal queue lock with supplied lock pointer */ - if (lock) - q->queue_lock = lock; - - /* - * This also sets hw/phys segments, boundary and size - */ - blk_queue_make_request(q, blk_queue_bio); - - q->sg_reserved_size = INT_MAX; - - /* Protect q->elevator from elevator_change */ - mutex_lock(&q->sysfs_lock); - - /* init elevator */ - if (elevator_init(q, NULL)) { - mutex_unlock(&q->sysfs_lock); - goto fail; - } - - mutex_unlock(&q->sysfs_lock); - - return q; - -fail: - blk_free_flush_queue(q->fq); - return NULL; -} -EXPORT_SYMBOL(blk_init_allocated_queue); - -bool blk_get_queue(struct request_queue *q) -{ - if (likely(!blk_queue_dying(q))) { - __blk_get_queue(q); - return true; - } - - return false; -} -EXPORT_SYMBOL(blk_get_queue); - -static inline void blk_free_request(struct request_list *rl, struct request *rq) -{ - if (rq->cmd_flags & REQ_ELVPRIV) { - elv_put_request(rl->q, rq); - if (rq->elv.icq) - put_io_context(rq->elv.icq->ioc); - } - - mempool_free(rq, rl->rq_pool); -} - -/* - * ioc_batching returns true if the ioc is a valid batching request and - * should be given priority access to a request. - */ -static inline int ioc_batching(struct request_queue *q, struct io_context *ioc) -{ - if (!ioc) - return 0; - - /* - * Make sure the process is able to allocate at least 1 request - * even if the batch times out, otherwise we could theoretically - * lose wakeups. - */ - return ioc->nr_batch_requests == q->nr_batching || - (ioc->nr_batch_requests > 0 - && time_before(jiffies, ioc->last_waited + BLK_BATCH_TIME)); -} - -/* - * ioc_set_batching sets ioc to be a new "batcher" if it is not one. This - * will cause the process to be a "batcher" on all queues in the system. This - * is the behaviour we want though - once it gets a wakeup it should be given - * a nice run. - */ -static void ioc_set_batching(struct request_queue *q, struct io_context *ioc) -{ - if (!ioc || ioc_batching(q, ioc)) - return; - - ioc->nr_batch_requests = q->nr_batching; - ioc->last_waited = jiffies; -} - -static void __freed_request(struct request_list *rl, int sync) -{ - struct request_queue *q = rl->q; - - if (rl->count[sync] < queue_congestion_off_threshold(q)) - blk_clear_congested(rl, sync); - - if (rl->count[sync] + 1 <= q->nr_requests) { - if (waitqueue_active(&rl->wait[sync])) - wake_up(&rl->wait[sync]); - - blk_clear_rl_full(rl, sync); - } -} - -/* - * A request has just been released. Account for it, update the full and - * congestion status, wake up any waiters. Called under q->queue_lock. - */ -static void freed_request(struct request_list *rl, int op, unsigned int flags) -{ - struct request_queue *q = rl->q; - int sync = rw_is_sync(op, flags); - - q->nr_rqs[sync]--; - rl->count[sync]--; - if (flags & REQ_ELVPRIV) - q->nr_rqs_elvpriv--; - - __freed_request(rl, sync); - - if (unlikely(rl->starved[sync ^ 1])) - __freed_request(rl, sync ^ 1); -} - -int blk_update_nr_requests(struct request_queue *q, unsigned int nr) -{ - struct request_list *rl; - int on_thresh, off_thresh; - - spin_lock_irq(q->queue_lock); - q->nr_requests = nr; - blk_queue_congestion_threshold(q); - on_thresh = queue_congestion_on_threshold(q); - off_thresh = queue_congestion_off_threshold(q); - - blk_queue_for_each_rl(rl, q) { - if (rl->count[BLK_RW_SYNC] >= on_thresh) - blk_set_congested(rl, BLK_RW_SYNC); - else if (rl->count[BLK_RW_SYNC] < off_thresh) - blk_clear_congested(rl, BLK_RW_SYNC); - - if (rl->count[BLK_RW_ASYNC] >= on_thresh) - blk_set_congested(rl, BLK_RW_ASYNC); - else if (rl->count[BLK_RW_ASYNC] < off_thresh) - blk_clear_congested(rl, BLK_RW_ASYNC); - - if (rl->count[BLK_RW_SYNC] >= q->nr_requests) { - blk_set_rl_full(rl, BLK_RW_SYNC); - } else { - blk_clear_rl_full(rl, BLK_RW_SYNC); - wake_up(&rl->wait[BLK_RW_SYNC]); - } - - if (rl->count[BLK_RW_ASYNC] >= q->nr_requests) { - blk_set_rl_full(rl, BLK_RW_ASYNC); - } else { - blk_clear_rl_full(rl, BLK_RW_ASYNC); - wake_up(&rl->wait[BLK_RW_ASYNC]); - } - } - - spin_unlock_irq(q->queue_lock); - return 0; -} - -/* - * Determine if elevator data should be initialized when allocating the - * request associated with @bio. - */ -static bool blk_rq_should_init_elevator(struct bio *bio) -{ - if (!bio) - return true; - - /* - * Flush requests do not use the elevator so skip initialization. - * This allows a request to share the flush and elevator data. - */ - if (bio->bi_opf & (REQ_PREFLUSH | REQ_FUA)) - return false; - - return true; -} - -/** - * rq_ioc - determine io_context for request allocation - * @bio: request being allocated is for this bio (can be %NULL) - * - * Determine io_context to use for request allocation for @bio. May return - * %NULL if %current->io_context doesn't exist. - */ -static struct io_context *rq_ioc(struct bio *bio) -{ -#ifdef CONFIG_BLK_CGROUP - if (bio && bio->bi_ioc) - return bio->bi_ioc; -#endif - return current->io_context; -} - -/** - * __get_request - get a free request - * @rl: request list to allocate from - * @op: REQ_OP_READ/REQ_OP_WRITE - * @op_flags: rq_flag_bits - * @bio: bio to allocate request for (can be %NULL) - * @gfp_mask: allocation mask - * - * Get a free request from @q. This function may fail under memory - * pressure or if @q is dead. - * - * Must be called with @q->queue_lock held and, - * Returns ERR_PTR on failure, with @q->queue_lock held. - * Returns request pointer on success, with @q->queue_lock *not held*. - */ -static struct request *__get_request(struct request_list *rl, int op, - int op_flags, struct bio *bio, - gfp_t gfp_mask) -{ - struct request_queue *q = rl->q; - struct request *rq; - struct elevator_type *et = q->elevator->type; - struct io_context *ioc = rq_ioc(bio); - struct io_cq *icq = NULL; - const bool is_sync = rw_is_sync(op, op_flags) != 0; - int may_queue; - - if (unlikely(blk_queue_dying(q))) - return ERR_PTR(-ENODEV); - - may_queue = elv_may_queue(q, op, op_flags); - if (may_queue == ELV_MQUEUE_NO) - goto rq_starved; - - if (rl->count[is_sync]+1 >= queue_congestion_on_threshold(q)) { - if (rl->count[is_sync]+1 >= q->nr_requests) { - /* - * The queue will fill after this allocation, so set - * it as full, and mark this process as "batching". - * This process will be allowed to complete a batch of - * requests, others will be blocked. - */ - if (!blk_rl_full(rl, is_sync)) { - ioc_set_batching(q, ioc); - blk_set_rl_full(rl, is_sync); - } else { - if (may_queue != ELV_MQUEUE_MUST - && !ioc_batching(q, ioc)) { - /* - * The queue is full and the allocating - * process is not a "batcher", and not - * exempted by the IO scheduler - */ - return ERR_PTR(-ENOMEM); - } - } - } - blk_set_congested(rl, is_sync); - } - - /* - * Only allow batching queuers to allocate up to 50% over the defined - * limit of requests, otherwise we could have thousands of requests - * allocated with any setting of ->nr_requests - */ - if (rl->count[is_sync] >= (3 * q->nr_requests / 2)) - return ERR_PTR(-ENOMEM); - - q->nr_rqs[is_sync]++; - rl->count[is_sync]++; - rl->starved[is_sync] = 0; - - /* - * Decide whether the new request will be managed by elevator. If - * so, mark @op_flags and increment elvpriv. Non-zero elvpriv will - * prevent the current elevator from being destroyed until the new - * request is freed. This guarantees icq's won't be destroyed and - * makes creating new ones safe. - * - * Also, lookup icq while holding queue_lock. If it doesn't exist, - * it will be created after releasing queue_lock. - */ - if (blk_rq_should_init_elevator(bio) && !blk_queue_bypass(q)) { - op_flags |= REQ_ELVPRIV; - q->nr_rqs_elvpriv++; - if (et->icq_cache && ioc) - icq = ioc_lookup_icq(ioc, q); - } - - if (blk_queue_io_stat(q)) - op_flags |= REQ_IO_STAT; - spin_unlock_irq(q->queue_lock); - - /* allocate and init request */ - rq = mempool_alloc(rl->rq_pool, gfp_mask); - if (!rq) - goto fail_alloc; - - blk_rq_init(q, rq); - blk_rq_set_rl(rq, rl); - req_set_op_attrs(rq, op, op_flags | REQ_ALLOCED); - - /* init elvpriv */ - if (op_flags & REQ_ELVPRIV) { - if (unlikely(et->icq_cache && !icq)) { - if (ioc) - icq = ioc_create_icq(ioc, q, gfp_mask); - if (!icq) - goto fail_elvpriv; - } - - rq->elv.icq = icq; - if (unlikely(elv_set_request(q, rq, bio, gfp_mask))) - goto fail_elvpriv; - - /* @rq->elv.icq holds io_context until @rq is freed */ - if (icq) - get_io_context(icq->ioc); - } -out: - /* - * ioc may be NULL here, and ioc_batching will be false. That's - * OK, if the queue is under the request limit then requests need - * not count toward the nr_batch_requests limit. There will always - * be some limit enforced by BLK_BATCH_TIME. - */ - if (ioc_batching(q, ioc)) - ioc->nr_batch_requests--; - - trace_block_getrq(q, bio, op); - return rq; - -fail_elvpriv: - /* - * elvpriv init failed. ioc, icq and elvpriv aren't mempool backed - * and may fail indefinitely under memory pressure and thus - * shouldn't stall IO. Treat this request as !elvpriv. This will - * disturb iosched and blkcg but weird is bettern than dead. - */ - printk_ratelimited(KERN_WARNING "%s: dev %s: request aux data allocation failed, iosched may be disturbed\n", - __func__, dev_name(q->backing_dev_info.dev)); - - rq->cmd_flags &= ~REQ_ELVPRIV; - rq->elv.icq = NULL; - - spin_lock_irq(q->queue_lock); - q->nr_rqs_elvpriv--; - spin_unlock_irq(q->queue_lock); - goto out; - -fail_alloc: - /* - * Allocation failed presumably due to memory. Undo anything we - * might have messed up. - * - * Allocating task should really be put onto the front of the wait - * queue, but this is pretty rare. - */ - spin_lock_irq(q->queue_lock); - freed_request(rl, op, op_flags); - - /* - * in the very unlikely event that allocation failed and no - * requests for this direction was pending, mark us starved so that - * freeing of a request in the other direction will notice - * us. another possible fix would be to split the rq mempool into - * READ and WRITE - */ -rq_starved: - if (unlikely(rl->count[is_sync] == 0)) - rl->starved[is_sync] = 1; - return ERR_PTR(-ENOMEM); -} - -/** - * get_request - get a free request - * @q: request_queue to allocate request from - * @op: REQ_OP_READ/REQ_OP_WRITE - * @op_flags: rq_flag_bits - * @bio: bio to allocate request for (can be %NULL) - * @gfp_mask: allocation mask - * - * Get a free request from @q. If %__GFP_DIRECT_RECLAIM is set in @gfp_mask, - * this function keeps retrying under memory pressure and fails iff @q is dead. - * - * Must be called with @q->queue_lock held and, - * Returns ERR_PTR on failure, with @q->queue_lock held. - * Returns request pointer on success, with @q->queue_lock *not held*. - */ -static struct request *get_request(struct request_queue *q, int op, - int op_flags, struct bio *bio, - gfp_t gfp_mask) -{ - const bool is_sync = rw_is_sync(op, op_flags) != 0; - DEFINE_WAIT(wait); - struct request_list *rl; - struct request *rq; - - rl = blk_get_rl(q, bio); /* transferred to @rq on success */ -retry: - rq = __get_request(rl, op, op_flags, bio, gfp_mask); - if (!IS_ERR(rq)) - return rq; - - if (!gfpflags_allow_blocking(gfp_mask) || unlikely(blk_queue_dying(q))) { - blk_put_rl(rl); - return rq; - } - - /* wait on @rl and retry */ - prepare_to_wait_exclusive(&rl->wait[is_sync], &wait, - TASK_UNINTERRUPTIBLE); - - trace_block_sleeprq(q, bio, op); - - spin_unlock_irq(q->queue_lock); - io_schedule(); - - /* - * After sleeping, we become a "batching" process and will be able - * to allocate at least one request, and up to a big batch of them - * for a small period time. See ioc_batching, ioc_set_batching - */ - ioc_set_batching(q, current->io_context); - - spin_lock_irq(q->queue_lock); - finish_wait(&rl->wait[is_sync], &wait); - - goto retry; -} - -static struct request *blk_old_get_request(struct request_queue *q, int rw, - gfp_t gfp_mask) -{ - struct request *rq; - - BUG_ON(rw != READ && rw != WRITE); - - /* create ioc upfront */ - create_io_context(gfp_mask, q->node); - - spin_lock_irq(q->queue_lock); - rq = get_request(q, rw, 0, NULL, gfp_mask); - if (IS_ERR(rq)) { - spin_unlock_irq(q->queue_lock); - return rq; - } - - /* q->queue_lock is unlocked at this point */ - rq->__data_len = 0; - rq->__sector = (sector_t) -1; - rq->bio = rq->biotail = NULL; - return rq; -} - -struct request *blk_get_request(struct request_queue *q, int rw, gfp_t gfp_mask) -{ - if (q->mq_ops) - return blk_mq_alloc_request(q, rw, - (gfp_mask & __GFP_DIRECT_RECLAIM) ? - 0 : BLK_MQ_REQ_NOWAIT); - else - return blk_old_get_request(q, rw, gfp_mask); -} -EXPORT_SYMBOL(blk_get_request); - -/** - * blk_rq_set_block_pc - initialize a request to type BLOCK_PC - * @rq: request to be initialized - * - */ -void blk_rq_set_block_pc(struct request *rq) -{ - rq->cmd_type = REQ_TYPE_BLOCK_PC; - memset(rq->__cmd, 0, sizeof(rq->__cmd)); -} -EXPORT_SYMBOL(blk_rq_set_block_pc); - -/** - * blk_requeue_request - put a request back on queue - * @q: request queue where request should be inserted - * @rq: request to be inserted - * - * Description: - * Drivers often keep queueing requests until the hardware cannot accept - * more, when that condition happens we need to put the request back - * on the queue. Must be called with queue lock held. - */ -void blk_requeue_request(struct request_queue *q, struct request *rq) -{ - blk_delete_timer(rq); - blk_clear_rq_complete(rq); - trace_block_rq_requeue(q, rq); - - if (rq->cmd_flags & REQ_QUEUED) - blk_queue_end_tag(q, rq); - - BUG_ON(blk_queued_rq(rq)); - - elv_requeue_request(q, rq); -} -EXPORT_SYMBOL(blk_requeue_request); - -static void add_acct_request(struct request_queue *q, struct request *rq, - int where) -{ - blk_account_io_start(rq, true); - __elv_add_request(q, rq, where); -} - -static void part_round_stats_single(int cpu, struct hd_struct *part, - unsigned long now) -{ - int inflight; - - if (now == part->stamp) - return; - - inflight = part_in_flight(part); - if (inflight) { - __part_stat_add(cpu, part, time_in_queue, - inflight * (now - part->stamp)); - __part_stat_add(cpu, part, io_ticks, (now - part->stamp)); - } - part->stamp = now; -} - -/** - * part_round_stats() - Round off the performance stats on a struct disk_stats. - * @cpu: cpu number for stats access - * @part: target partition - * - * The average IO queue length and utilisation statistics are maintained - * by observing the current state of the queue length and the amount of - * time it has been in this state for. - * - * Normally, that accounting is done on IO completion, but that can result - * in more than a second's worth of IO being accounted for within any one - * second, leading to >100% utilisation. To deal with that, we call this - * function to do a round-off before returning the results when reading - * /proc/diskstats. This accounts immediately for all queue usage up to - * the current jiffies and restarts the counters again. - */ -void part_round_stats(int cpu, struct hd_struct *part) -{ - unsigned long now = jiffies; - - if (part->partno) - part_round_stats_single(cpu, &part_to_disk(part)->part0, now); - part_round_stats_single(cpu, part, now); -} -EXPORT_SYMBOL_GPL(part_round_stats); - -#ifdef CONFIG_PM -static void blk_pm_put_request(struct request *rq) -{ - if (rq->q->dev && !(rq->cmd_flags & REQ_PM) && !--rq->q->nr_pending) - pm_runtime_mark_last_busy(rq->q->dev); -} -#else -static inline void blk_pm_put_request(struct request *rq) {} -#endif - -/* - * queue lock must be held - */ -void __blk_put_request(struct request_queue *q, struct request *req) -{ - if (unlikely(!q)) - return; - - if (q->mq_ops) { - blk_mq_free_request(req); - return; - } - - blk_pm_put_request(req); - - elv_completed_request(q, req); - - /* this is a bio leak */ - WARN_ON(req->bio != NULL); - - /* - * Request may not have originated from ll_rw_blk. if not, - * it didn't come out of our reserved rq pools - */ - if (req->cmd_flags & REQ_ALLOCED) { - unsigned int flags = req->cmd_flags; - int op = req_op(req); - struct request_list *rl = blk_rq_rl(req); - - BUG_ON(!list_empty(&req->queuelist)); - BUG_ON(ELV_ON_HASH(req)); - - blk_free_request(rl, req); - freed_request(rl, op, flags); - blk_put_rl(rl); - } -} -EXPORT_SYMBOL_GPL(__blk_put_request); - -void blk_put_request(struct request *req) -{ - struct request_queue *q = req->q; - - if (q->mq_ops) - blk_mq_free_request(req); - else { - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - __blk_put_request(q, req); - spin_unlock_irqrestore(q->queue_lock, flags); - } -} -EXPORT_SYMBOL(blk_put_request); - -/** - * blk_add_request_payload - add a payload to a request - * @rq: request to update - * @page: page backing the payload - * @offset: offset in page - * @len: length of the payload. - * - * This allows to later add a payload to an already submitted request by - * a block driver. The driver needs to take care of freeing the payload - * itself. - * - * Note that this is a quite horrible hack and nothing but handling of - * discard requests should ever use it. - */ -void blk_add_request_payload(struct request *rq, struct page *page, - int offset, unsigned int len) -{ - struct bio *bio = rq->bio; - - bio->bi_io_vec->bv_page = page; - bio->bi_io_vec->bv_offset = offset; - bio->bi_io_vec->bv_len = len; - - bio->bi_iter.bi_size = len; - bio->bi_vcnt = 1; - bio->bi_phys_segments = 1; - - rq->__data_len = rq->resid_len = len; - rq->nr_phys_segments = 1; -} -EXPORT_SYMBOL_GPL(blk_add_request_payload); - -bool bio_attempt_back_merge(struct request_queue *q, struct request *req, - struct bio *bio) -{ - const int ff = bio->bi_opf & REQ_FAILFAST_MASK; - - if (!ll_back_merge_fn(q, req, bio)) - return false; - - trace_block_bio_backmerge(q, req, bio); - - if ((req->cmd_flags & REQ_FAILFAST_MASK) != ff) - blk_rq_set_mixed_merge(req); - - req->biotail->bi_next = bio; - req->biotail = bio; - req->__data_len += bio->bi_iter.bi_size; - req->ioprio = ioprio_best(req->ioprio, bio_prio(bio)); - - blk_account_io_start(req, false); - return true; -} - -bool bio_attempt_front_merge(struct request_queue *q, struct request *req, - struct bio *bio) -{ - const int ff = bio->bi_opf & REQ_FAILFAST_MASK; - - if (!ll_front_merge_fn(q, req, bio)) - return false; - - trace_block_bio_frontmerge(q, req, bio); - - if ((req->cmd_flags & REQ_FAILFAST_MASK) != ff) - blk_rq_set_mixed_merge(req); - - bio->bi_next = req->bio; - req->bio = bio; - - req->__sector = bio->bi_iter.bi_sector; - req->__data_len += bio->bi_iter.bi_size; - req->ioprio = ioprio_best(req->ioprio, bio_prio(bio)); - - blk_account_io_start(req, false); - return true; -} - -/** - * blk_attempt_plug_merge - try to merge with %current's plugged list - * @q: request_queue new bio is being queued at - * @bio: new bio being queued - * @request_count: out parameter for number of traversed plugged requests - * @same_queue_rq: pointer to &struct request that gets filled in when - * another request associated with @q is found on the plug list - * (optional, may be %NULL) - * - * Determine whether @bio being queued on @q can be merged with a request - * on %current's plugged list. Returns %true if merge was successful, - * otherwise %false. - * - * Plugging coalesces IOs from the same issuer for the same purpose without - * going through @q->queue_lock. As such it's more of an issuing mechanism - * than scheduling, and the request, while may have elvpriv data, is not - * added on the elevator at this point. In addition, we don't have - * reliable access to the elevator outside queue lock. Only check basic - * merging parameters without querying the elevator. - * - * Caller must ensure !blk_queue_nomerges(q) beforehand. - */ -bool blk_attempt_plug_merge(struct request_queue *q, struct bio *bio, - unsigned int *request_count, - struct request **same_queue_rq) -{ - struct blk_plug *plug; - struct request *rq; - bool ret = false; - struct list_head *plug_list; - - plug = current->plug; - if (!plug) - goto out; - *request_count = 0; - - if (q->mq_ops) - plug_list = &plug->mq_list; - else - plug_list = &plug->list; - - list_for_each_entry_reverse(rq, plug_list, queuelist) { - int el_ret; - - if (rq->q == q) { - (*request_count)++; - /* - * Only blk-mq multiple hardware queues case checks the - * rq in the same queue, there should be only one such - * rq in a queue - **/ - if (same_queue_rq) - *same_queue_rq = rq; - } - - if (rq->q != q || !blk_rq_merge_ok(rq, bio)) - continue; - - el_ret = blk_try_merge(rq, bio); - if (el_ret == ELEVATOR_BACK_MERGE) { - ret = bio_attempt_back_merge(q, rq, bio); - if (ret) - break; - } else if (el_ret == ELEVATOR_FRONT_MERGE) { - ret = bio_attempt_front_merge(q, rq, bio); - if (ret) - break; - } - } -out: - return ret; -} - -unsigned int blk_plug_queued_count(struct request_queue *q) -{ - struct blk_plug *plug; - struct request *rq; - struct list_head *plug_list; - unsigned int ret = 0; - - plug = current->plug; - if (!plug) - goto out; - - if (q->mq_ops) - plug_list = &plug->mq_list; - else - plug_list = &plug->list; - - list_for_each_entry(rq, plug_list, queuelist) { - if (rq->q == q) - ret++; - } -out: - return ret; -} - -void init_request_from_bio(struct request *req, struct bio *bio) -{ - req->cmd_type = REQ_TYPE_FS; - - req->cmd_flags |= bio->bi_opf & REQ_COMMON_MASK; - if (bio->bi_opf & REQ_RAHEAD) - req->cmd_flags |= REQ_FAILFAST_MASK; - - req->errors = 0; - req->__sector = bio->bi_iter.bi_sector; - req->ioprio = bio_prio(bio); - blk_rq_bio_prep(req->q, req, bio); -} - -static blk_qc_t blk_queue_bio(struct request_queue *q, struct bio *bio) -{ - const bool sync = !!(bio->bi_opf & REQ_SYNC); - struct blk_plug *plug; - int el_ret, rw_flags = 0, where = ELEVATOR_INSERT_SORT; - struct request *req; - unsigned int request_count = 0; - - /* - * low level driver can indicate that it wants pages above a - * certain limit bounced to low memory (ie for highmem, or even - * ISA dma in theory) - */ - blk_queue_bounce(q, &bio); - - blk_queue_split(q, &bio, q->bio_split); - - if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) { - bio->bi_error = -EIO; - bio_endio(bio); - return BLK_QC_T_NONE; - } - - if (bio->bi_opf & (REQ_PREFLUSH | REQ_FUA)) { - spin_lock_irq(q->queue_lock); - where = ELEVATOR_INSERT_FLUSH; - goto get_rq; - } - - /* - * Check if we can merge with the plugged list before grabbing - * any locks. - */ - if (!blk_queue_nomerges(q)) { - if (blk_attempt_plug_merge(q, bio, &request_count, NULL)) - return BLK_QC_T_NONE; - } else - request_count = blk_plug_queued_count(q); - - spin_lock_irq(q->queue_lock); - - el_ret = elv_merge(q, &req, bio); - if (el_ret == ELEVATOR_BACK_MERGE) { - if (bio_attempt_back_merge(q, req, bio)) { - elv_bio_merged(q, req, bio); - if (!attempt_back_merge(q, req)) - elv_merged_request(q, req, el_ret); - goto out_unlock; - } - } else if (el_ret == ELEVATOR_FRONT_MERGE) { - if (bio_attempt_front_merge(q, req, bio)) { - elv_bio_merged(q, req, bio); - if (!attempt_front_merge(q, req)) - elv_merged_request(q, req, el_ret); - goto out_unlock; - } - } - -get_rq: - /* - * This sync check and mask will be re-done in init_request_from_bio(), - * but we need to set it earlier to expose the sync flag to the - * rq allocator and io schedulers. - */ - if (sync) - rw_flags |= REQ_SYNC; - - /* - * Add in META/PRIO flags, if set, before we get to the IO scheduler - */ - rw_flags |= (bio->bi_opf & (REQ_META | REQ_PRIO)); - - /* - * Grab a free request. This is might sleep but can not fail. - * Returns with the queue unlocked. - */ - req = get_request(q, bio_data_dir(bio), rw_flags, bio, GFP_NOIO); - if (IS_ERR(req)) { - bio->bi_error = PTR_ERR(req); - bio_endio(bio); - goto out_unlock; - } - - /* - * After dropping the lock and possibly sleeping here, our request - * may now be mergeable after it had proven unmergeable (above). - * We don't worry about that case for efficiency. It won't happen - * often, and the elevators are able to handle it. - */ - init_request_from_bio(req, bio); - - if (test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags)) - req->cpu = raw_smp_processor_id(); - - plug = current->plug; - if (plug) { - /* - * If this is the first request added after a plug, fire - * of a plug trace. - */ - if (!request_count) - trace_block_plug(q); - else { - if (request_count >= BLK_MAX_REQUEST_COUNT) { - blk_flush_plug_list(plug, false); - trace_block_plug(q); - } - } - list_add_tail(&req->queuelist, &plug->list); - blk_account_io_start(req, true); - } else { - spin_lock_irq(q->queue_lock); - add_acct_request(q, req, where); - __blk_run_queue(q); -out_unlock: - spin_unlock_irq(q->queue_lock); - } - - return BLK_QC_T_NONE; -} - -/* - * If bio->bi_dev is a partition, remap the location - */ -static inline void blk_partition_remap(struct bio *bio) -{ - struct block_device *bdev = bio->bi_bdev; - - if (bio_sectors(bio) && bdev != bdev->bd_contains) { - struct hd_struct *p = bdev->bd_part; - - bio->bi_iter.bi_sector += p->start_sect; - bio->bi_bdev = bdev->bd_contains; - - trace_block_bio_remap(bdev_get_queue(bio->bi_bdev), bio, - bdev->bd_dev, - bio->bi_iter.bi_sector - p->start_sect); - } -} - -static void handle_bad_sector(struct bio *bio) -{ - char b[BDEVNAME_SIZE]; - - printk(KERN_INFO "attempt to access beyond end of device\n"); - printk(KERN_INFO "%s: rw=%d, want=%Lu, limit=%Lu\n", - bdevname(bio->bi_bdev, b), - bio->bi_opf, - (unsigned long long)bio_end_sector(bio), - (long long)(i_size_read(bio->bi_bdev->bd_inode) >> 9)); -} - -#ifdef CONFIG_FAIL_MAKE_REQUEST - -static DECLARE_FAULT_ATTR(fail_make_request); - -static int __init setup_fail_make_request(char *str) -{ - return setup_fault_attr(&fail_make_request, str); -} -__setup("fail_make_request=", setup_fail_make_request); - -static bool should_fail_request(struct hd_struct *part, unsigned int bytes) -{ - return part->make_it_fail && should_fail(&fail_make_request, bytes); -} - -static int __init fail_make_request_debugfs(void) -{ - struct dentry *dir = fault_create_debugfs_attr("fail_make_request", - NULL, &fail_make_request); - - return PTR_ERR_OR_ZERO(dir); -} - -late_initcall(fail_make_request_debugfs); - -#else /* CONFIG_FAIL_MAKE_REQUEST */ - -static inline bool should_fail_request(struct hd_struct *part, - unsigned int bytes) -{ - return false; -} - -#endif /* CONFIG_FAIL_MAKE_REQUEST */ - -/* - * Check whether this bio extends beyond the end of the device. - */ -static inline int bio_check_eod(struct bio *bio, unsigned int nr_sectors) -{ - sector_t maxsector; - - if (!nr_sectors) - return 0; - - /* Test device or partition size, when known. */ - maxsector = i_size_read(bio->bi_bdev->bd_inode) >> 9; - if (maxsector) { - sector_t sector = bio->bi_iter.bi_sector; - - if (maxsector < nr_sectors || maxsector - nr_sectors < sector) { - /* - * This may well happen - the kernel calls bread() - * without checking the size of the device, e.g., when - * mounting a device. - */ - handle_bad_sector(bio); - return 1; - } - } - - return 0; -} - -static noinline_for_stack bool -generic_make_request_checks(struct bio *bio) -{ - struct request_queue *q; - int nr_sectors = bio_sectors(bio); - int err = -EIO; - char b[BDEVNAME_SIZE]; - struct hd_struct *part; - - might_sleep(); - - if (bio_check_eod(bio, nr_sectors)) - goto end_io; - - q = bdev_get_queue(bio->bi_bdev); - if (unlikely(!q)) { - printk(KERN_ERR - "generic_make_request: Trying to access " - "nonexistent block-device %s (%Lu)\n", - bdevname(bio->bi_bdev, b), - (long long) bio->bi_iter.bi_sector); - goto end_io; - } - - part = bio->bi_bdev->bd_part; - if (should_fail_request(part, bio->bi_iter.bi_size) || - should_fail_request(&part_to_disk(part)->part0, - bio->bi_iter.bi_size)) - goto end_io; - - /* - * If this device has partitions, remap block n - * of partition p to block n+start(p) of the disk. - */ - blk_partition_remap(bio); - - if (bio_check_eod(bio, nr_sectors)) - goto end_io; - - /* - * Filter flush bio's early so that make_request based - * drivers without flush support don't have to worry - * about them. - */ - if ((bio->bi_opf & (REQ_PREFLUSH | REQ_FUA)) && - !test_bit(QUEUE_FLAG_WC, &q->queue_flags)) { - bio->bi_opf &= ~(REQ_PREFLUSH | REQ_FUA); - if (!nr_sectors) { - err = 0; - goto end_io; - } - } - - switch (bio_op(bio)) { - case REQ_OP_DISCARD: - if (!blk_queue_discard(q)) - goto not_supported; - break; - case REQ_OP_SECURE_ERASE: - if (!blk_queue_secure_erase(q)) - goto not_supported; - break; - case REQ_OP_WRITE_SAME: - if (!bdev_write_same(bio->bi_bdev)) - goto not_supported; - break; - default: - break; - } - - /* - * Various block parts want %current->io_context and lazy ioc - * allocation ends up trading a lot of pain for a small amount of - * memory. Just allocate it upfront. This may fail and block - * layer knows how to live with it. - */ - create_io_context(GFP_ATOMIC, q->node); - - if (!blkcg_bio_issue_check(q, bio)) - return false; - - trace_block_bio_queue(q, bio); - return true; - -not_supported: - err = -EOPNOTSUPP; -end_io: - bio->bi_error = err; - bio_endio(bio); - return false; -} - -/** - * generic_make_request - hand a buffer to its device driver for I/O - * @bio: The bio describing the location in memory and on the device. - * - * generic_make_request() is used to make I/O requests of block - * devices. It is passed a &struct bio, which describes the I/O that needs - * to be done. - * - * generic_make_request() does not return any status. The - * success/failure status of the request, along with notification of - * completion, is delivered asynchronously through the bio->bi_end_io - * function described (one day) else where. - * - * The caller of generic_make_request must make sure that bi_io_vec - * are set to describe the memory buffer, and that bi_dev and bi_sector are - * set to describe the device address, and the - * bi_end_io and optionally bi_private are set to describe how - * completion notification should be signaled. - * - * generic_make_request and the drivers it calls may use bi_next if this - * bio happens to be merged with someone else, and may resubmit the bio to - * a lower device by calling into generic_make_request recursively, which - * means the bio should NOT be touched after the call to ->make_request_fn. - */ -blk_qc_t generic_make_request(struct bio *bio) -{ - struct bio_list bio_list_on_stack; - blk_qc_t ret = BLK_QC_T_NONE; - - if (!generic_make_request_checks(bio)) - goto out; - - /* - * We only want one ->make_request_fn to be active at a time, else - * stack usage with stacked devices could be a problem. So use - * current->bio_list to keep a list of requests submited by a - * make_request_fn function. current->bio_list is also used as a - * flag to say if generic_make_request is currently active in this - * task or not. If it is NULL, then no make_request is active. If - * it is non-NULL, then a make_request is active, and new requests - * should be added at the tail - */ - if (current->bio_list) { - bio_list_add(current->bio_list, bio); - goto out; - } - - /* following loop may be a bit non-obvious, and so deserves some - * explanation. - * Before entering the loop, bio->bi_next is NULL (as all callers - * ensure that) so we have a list with a single bio. - * We pretend that we have just taken it off a longer list, so - * we assign bio_list to a pointer to the bio_list_on_stack, - * thus initialising the bio_list of new bios to be - * added. ->make_request() may indeed add some more bios - * through a recursive call to generic_make_request. If it - * did, we find a non-NULL value in bio_list and re-enter the loop - * from the top. In this case we really did just take the bio - * of the top of the list (no pretending) and so remove it from - * bio_list, and call into ->make_request() again. - */ - BUG_ON(bio->bi_next); - bio_list_init(&bio_list_on_stack); - current->bio_list = &bio_list_on_stack; - do { - struct request_queue *q = bdev_get_queue(bio->bi_bdev); - - if (likely(blk_queue_enter(q, false) == 0)) { - ret = q->make_request_fn(q, bio); - - blk_queue_exit(q); - - bio = bio_list_pop(current->bio_list); - } else { - struct bio *bio_next = bio_list_pop(current->bio_list); - - bio_io_error(bio); - bio = bio_next; - } - } while (bio); - current->bio_list = NULL; /* deactivate */ - -out: - return ret; -} -EXPORT_SYMBOL(generic_make_request); - -/** - * submit_bio - submit a bio to the block device layer for I/O - * @bio: The &struct bio which describes the I/O - * - * submit_bio() is very similar in purpose to generic_make_request(), and - * uses that function to do most of the work. Both are fairly rough - * interfaces; @bio must be presetup and ready for I/O. - * - */ -blk_qc_t submit_bio(struct bio *bio) -{ - /* - * If it's a regular read/write or a barrier with data attached, - * go through the normal accounting stuff before submission. - */ - if (bio_has_data(bio)) { - unsigned int count; - - if (unlikely(bio_op(bio) == REQ_OP_WRITE_SAME)) - count = bdev_logical_block_size(bio->bi_bdev) >> 9; - else - count = bio_sectors(bio); - - if (op_is_write(bio_op(bio))) { - count_vm_events(PGPGOUT, count); - } else { - task_io_account_read(bio->bi_iter.bi_size); - count_vm_events(PGPGIN, count); - } - - if (unlikely(block_dump)) { - char b[BDEVNAME_SIZE]; - printk(KERN_DEBUG "%s(%d): %s block %Lu on %s (%u sectors)\n", - current->comm, task_pid_nr(current), - op_is_write(bio_op(bio)) ? "WRITE" : "READ", - (unsigned long long)bio->bi_iter.bi_sector, - bdevname(bio->bi_bdev, b), - count); - } - } - - return generic_make_request(bio); -} -EXPORT_SYMBOL(submit_bio); - -/** - * blk_cloned_rq_check_limits - Helper function to check a cloned request - * for new the queue limits - * @q: the queue - * @rq: the request being checked - * - * Description: - * @rq may have been made based on weaker limitations of upper-level queues - * in request stacking drivers, and it may violate the limitation of @q. - * Since the block layer and the underlying device driver trust @rq - * after it is inserted to @q, it should be checked against @q before - * the insertion using this generic function. - * - * Request stacking drivers like request-based dm may change the queue - * limits when retrying requests on other queues. Those requests need - * to be checked against the new queue limits again during dispatch. - */ -static int blk_cloned_rq_check_limits(struct request_queue *q, - struct request *rq) -{ - if (blk_rq_sectors(rq) > blk_queue_get_max_sectors(q, req_op(rq))) { - printk(KERN_ERR "%s: over max size limit.\n", __func__); - return -EIO; - } - - /* - * queue's settings related to segment counting like q->bounce_pfn - * may differ from that of other stacking queues. - * Recalculate it to check the request correctly on this queue's - * limitation. - */ - blk_recalc_rq_segments(rq); - if (rq->nr_phys_segments > queue_max_segments(q)) { - printk(KERN_ERR "%s: over max segments limit.\n", __func__); - return -EIO; - } - - return 0; -} - -/** - * blk_insert_cloned_request - Helper for stacking drivers to submit a request - * @q: the queue to submit the request - * @rq: the request being queued - */ -int blk_insert_cloned_request(struct request_queue *q, struct request *rq) -{ - unsigned long flags; - int where = ELEVATOR_INSERT_BACK; - - if (blk_cloned_rq_check_limits(q, rq)) - return -EIO; - - if (rq->rq_disk && - should_fail_request(&rq->rq_disk->part0, blk_rq_bytes(rq))) - return -EIO; - - if (q->mq_ops) { - if (blk_queue_io_stat(q)) - blk_account_io_start(rq, true); - blk_mq_insert_request(rq, false, true, false); - return 0; - } - - spin_lock_irqsave(q->queue_lock, flags); - if (unlikely(blk_queue_dying(q))) { - spin_unlock_irqrestore(q->queue_lock, flags); - return -ENODEV; - } - - /* - * Submitting request must be dequeued before calling this function - * because it will be linked to another request_queue - */ - BUG_ON(blk_queued_rq(rq)); - - if (rq->cmd_flags & (REQ_PREFLUSH | REQ_FUA)) - where = ELEVATOR_INSERT_FLUSH; - - add_acct_request(q, rq, where); - if (where == ELEVATOR_INSERT_FLUSH) - __blk_run_queue(q); - spin_unlock_irqrestore(q->queue_lock, flags); - - return 0; -} -EXPORT_SYMBOL_GPL(blk_insert_cloned_request); - -/** - * blk_rq_err_bytes - determine number of bytes till the next failure boundary - * @rq: request to examine - * - * Description: - * A request could be merge of IOs which require different failure - * handling. This function determines the number of bytes which - * can be failed from the beginning of the request without - * crossing into area which need to be retried further. - * - * Return: - * The number of bytes to fail. - * - * Context: - * queue_lock must be held. - */ -unsigned int blk_rq_err_bytes(const struct request *rq) -{ - unsigned int ff = rq->cmd_flags & REQ_FAILFAST_MASK; - unsigned int bytes = 0; - struct bio *bio; - - if (!(rq->cmd_flags & REQ_MIXED_MERGE)) - return blk_rq_bytes(rq); - - /* - * Currently the only 'mixing' which can happen is between - * different fastfail types. We can safely fail portions - * which have all the failfast bits that the first one has - - * the ones which are at least as eager to fail as the first - * one. - */ - for (bio = rq->bio; bio; bio = bio->bi_next) { - if ((bio->bi_opf & ff) != ff) - break; - bytes += bio->bi_iter.bi_size; - } - - /* this could lead to infinite loop */ - BUG_ON(blk_rq_bytes(rq) && !bytes); - return bytes; -} -EXPORT_SYMBOL_GPL(blk_rq_err_bytes); - -void blk_account_io_completion(struct request *req, unsigned int bytes) -{ - if (blk_do_io_stat(req)) { - const int rw = rq_data_dir(req); - struct hd_struct *part; - int cpu; - - cpu = part_stat_lock(); - part = req->part; - part_stat_add(cpu, part, sectors[rw], bytes >> 9); - part_stat_unlock(); - } -} - -void blk_account_io_done(struct request *req) -{ - /* - * Account IO completion. flush_rq isn't accounted as a - * normal IO on queueing nor completion. Accounting the - * containing request is enough. - */ - if (blk_do_io_stat(req) && !(req->cmd_flags & REQ_FLUSH_SEQ)) { - unsigned long duration = jiffies - req->start_time; - const int rw = rq_data_dir(req); - struct hd_struct *part; - int cpu; - - cpu = part_stat_lock(); - part = req->part; - - part_stat_inc(cpu, part, ios[rw]); - part_stat_add(cpu, part, ticks[rw], duration); - part_round_stats(cpu, part); - part_dec_in_flight(part, rw); - - hd_struct_put(part); - part_stat_unlock(); - } -} - -#ifdef CONFIG_PM -/* - * Don't process normal requests when queue is suspended - * or in the process of suspending/resuming - */ -static struct request *blk_pm_peek_request(struct request_queue *q, - struct request *rq) -{ - if (q->dev && (q->rpm_status == RPM_SUSPENDED || - (q->rpm_status != RPM_ACTIVE && !(rq->cmd_flags & REQ_PM)))) - return NULL; - else - return rq; -} -#else -static inline struct request *blk_pm_peek_request(struct request_queue *q, - struct request *rq) -{ - return rq; -} -#endif - -void blk_account_io_start(struct request *rq, bool new_io) -{ - struct hd_struct *part; - int rw = rq_data_dir(rq); - int cpu; - - if (!blk_do_io_stat(rq)) - return; - - cpu = part_stat_lock(); - - if (!new_io) { - part = rq->part; - part_stat_inc(cpu, part, merges[rw]); - } else { - part = disk_map_sector_rcu(rq->rq_disk, blk_rq_pos(rq)); - if (!hd_struct_try_get(part)) { - /* - * The partition is already being removed, - * the request will be accounted on the disk only - * - * We take a reference on disk->part0 although that - * partition will never be deleted, so we can treat - * it as any other partition. - */ - part = &rq->rq_disk->part0; - hd_struct_get(part); - } - part_round_stats(cpu, part); - part_inc_in_flight(part, rw); - rq->part = part; - } - - part_stat_unlock(); -} - -/** - * blk_peek_request - peek at the top of a request queue - * @q: request queue to peek at - * - * Description: - * Return the request at the top of @q. The returned request - * should be started using blk_start_request() before LLD starts - * processing it. - * - * Return: - * Pointer to the request at the top of @q if available. Null - * otherwise. - * - * Context: - * queue_lock must be held. - */ -struct request *blk_peek_request(struct request_queue *q) -{ - struct request *rq; - int ret; - - while ((rq = __elv_next_request(q)) != NULL) { - - rq = blk_pm_peek_request(q, rq); - if (!rq) - break; - - if (!(rq->cmd_flags & REQ_STARTED)) { - /* - * This is the first time the device driver - * sees this request (possibly after - * requeueing). Notify IO scheduler. - */ - if (rq->cmd_flags & REQ_SORTED) - elv_activate_rq(q, rq); - - /* - * just mark as started even if we don't start - * it, a request that has been delayed should - * not be passed by new incoming requests - */ - rq->cmd_flags |= REQ_STARTED; - trace_block_rq_issue(q, rq); - } - - if (!q->boundary_rq || q->boundary_rq == rq) { - q->end_sector = rq_end_sector(rq); - q->boundary_rq = NULL; - } - - if (rq->cmd_flags & REQ_DONTPREP) - break; - - if (q->dma_drain_size && blk_rq_bytes(rq)) { - /* - * make sure space for the drain appears we - * know we can do this because max_hw_segments - * has been adjusted to be one fewer than the - * device can handle - */ - rq->nr_phys_segments++; - } - - if (!q->prep_rq_fn) - break; - - ret = q->prep_rq_fn(q, rq); - if (ret == BLKPREP_OK) { - break; - } else if (ret == BLKPREP_DEFER) { - /* - * the request may have been (partially) prepped. - * we need to keep this request in the front to - * avoid resource deadlock. REQ_STARTED will - * prevent other fs requests from passing this one. - */ - if (q->dma_drain_size && blk_rq_bytes(rq) && - !(rq->cmd_flags & REQ_DONTPREP)) { - /* - * remove the space for the drain we added - * so that we don't add it again - */ - --rq->nr_phys_segments; - } - - rq = NULL; - break; - } else if (ret == BLKPREP_KILL || ret == BLKPREP_INVALID) { - int err = (ret == BLKPREP_INVALID) ? -EREMOTEIO : -EIO; - - rq->cmd_flags |= REQ_QUIET; - /* - * Mark this request as started so we don't trigger - * any debug logic in the end I/O path. - */ - blk_start_request(rq); - __blk_end_request_all(rq, err); - } else { - printk(KERN_ERR "%s: bad return=%d\n", __func__, ret); - break; - } - } - - return rq; -} -EXPORT_SYMBOL(blk_peek_request); - -void blk_dequeue_request(struct request *rq) -{ - struct request_queue *q = rq->q; - - BUG_ON(list_empty(&rq->queuelist)); - BUG_ON(ELV_ON_HASH(rq)); - - list_del_init(&rq->queuelist); - - /* - * the time frame between a request being removed from the lists - * and to it is freed is accounted as io that is in progress at - * the driver side. - */ - if (blk_account_rq(rq)) { - q->in_flight[rq_is_sync(rq)]++; - set_io_start_time_ns(rq); - } -} - -/** - * blk_start_request - start request processing on the driver - * @req: request to dequeue - * - * Description: - * Dequeue @req and start timeout timer on it. This hands off the - * request to the driver. - * - * Block internal functions which don't want to start timer should - * call blk_dequeue_request(). - * - * Context: - * queue_lock must be held. - */ -void blk_start_request(struct request *req) -{ - blk_dequeue_request(req); - - /* - * We are now handing the request to the hardware, initialize - * resid_len to full count and add the timeout handler. - */ - req->resid_len = blk_rq_bytes(req); - if (unlikely(blk_bidi_rq(req))) - req->next_rq->resid_len = blk_rq_bytes(req->next_rq); - - BUG_ON(test_bit(REQ_ATOM_COMPLETE, &req->atomic_flags)); - blk_add_timer(req); -} -EXPORT_SYMBOL(blk_start_request); - -/** - * blk_fetch_request - fetch a request from a request queue - * @q: request queue to fetch a request from - * - * Description: - * Return the request at the top of @q. The request is started on - * return and LLD can start processing it immediately. - * - * Return: - * Pointer to the request at the top of @q if available. Null - * otherwise. - * - * Context: - * queue_lock must be held. - */ -struct request *blk_fetch_request(struct request_queue *q) -{ - struct request *rq; - - rq = blk_peek_request(q); - if (rq) - blk_start_request(rq); - return rq; -} -EXPORT_SYMBOL(blk_fetch_request); - -/** - * blk_update_request - Special helper function for request stacking drivers - * @req: the request being processed - * @error: %0 for success, < %0 for error - * @nr_bytes: number of bytes to complete @req - * - * Description: - * Ends I/O on a number of bytes attached to @req, but doesn't complete - * the request structure even if @req doesn't have leftover. - * If @req has leftover, sets it up for the next range of segments. - * - * This special helper function is only for request stacking drivers - * (e.g. request-based dm) so that they can handle partial completion. - * Actual device drivers should use blk_end_request instead. - * - * Passing the result of blk_rq_bytes() as @nr_bytes guarantees - * %false return from this function. - * - * Return: - * %false - this request doesn't have any more data - * %true - this request has more data - **/ -bool blk_update_request(struct request *req, int error, unsigned int nr_bytes) -{ - int total_bytes; - - trace_block_rq_complete(req->q, req, nr_bytes); - - if (!req->bio) - return false; - - /* - * For fs requests, rq is just carrier of independent bio's - * and each partial completion should be handled separately. - * Reset per-request error on each partial completion. - * - * TODO: tj: This is too subtle. It would be better to let - * low level drivers do what they see fit. - */ - if (req->cmd_type == REQ_TYPE_FS) - req->errors = 0; - - if (error && req->cmd_type == REQ_TYPE_FS && - !(req->cmd_flags & REQ_QUIET)) { - char *error_type; - - switch (error) { - case -ENOLINK: - error_type = "recoverable transport"; - break; - case -EREMOTEIO: - error_type = "critical target"; - break; - case -EBADE: - error_type = "critical nexus"; - break; - case -ETIMEDOUT: - error_type = "timeout"; - break; - case -ENOSPC: - error_type = "critical space allocation"; - break; - case -ENODATA: - error_type = "critical medium"; - break; - case -EIO: - default: - error_type = "I/O"; - break; - } - printk_ratelimited(KERN_ERR "%s: %s error, dev %s, sector %llu\n", - __func__, error_type, req->rq_disk ? - req->rq_disk->disk_name : "?", - (unsigned long long)blk_rq_pos(req)); - - } - - blk_account_io_completion(req, nr_bytes); - - total_bytes = 0; - while (req->bio) { - struct bio *bio = req->bio; - unsigned bio_bytes = min(bio->bi_iter.bi_size, nr_bytes); - - if (bio_bytes == bio->bi_iter.bi_size) - req->bio = bio->bi_next; - - req_bio_endio(req, bio, bio_bytes, error); - - total_bytes += bio_bytes; - nr_bytes -= bio_bytes; - - if (!nr_bytes) - break; - } - - /* - * completely done - */ - if (!req->bio) { - /* - * Reset counters so that the request stacking driver - * can find how many bytes remain in the request - * later. - */ - req->__data_len = 0; - return false; - } - - req->__data_len -= total_bytes; - - /* update sector only for requests with clear definition of sector */ - if (req->cmd_type == REQ_TYPE_FS) - req->__sector += total_bytes >> 9; - - /* mixed attributes always follow the first bio */ - if (req->cmd_flags & REQ_MIXED_MERGE) { - req->cmd_flags &= ~REQ_FAILFAST_MASK; - req->cmd_flags |= req->bio->bi_opf & REQ_FAILFAST_MASK; - } - - /* - * If total number of sectors is less than the first segment - * size, something has gone terribly wrong. - */ - if (blk_rq_bytes(req) < blk_rq_cur_bytes(req)) { - blk_dump_rq_flags(req, "request botched"); - req->__data_len = blk_rq_cur_bytes(req); - } - - /* recalculate the number of segments */ - blk_recalc_rq_segments(req); - - return true; -} -EXPORT_SYMBOL_GPL(blk_update_request); - -static bool blk_update_bidi_request(struct request *rq, int error, - unsigned int nr_bytes, - unsigned int bidi_bytes) -{ - if (blk_update_request(rq, error, nr_bytes)) - return true; - - /* Bidi request must be completed as a whole */ - if (unlikely(blk_bidi_rq(rq)) && - blk_update_request(rq->next_rq, error, bidi_bytes)) - return true; - - if (blk_queue_add_random(rq->q)) - add_disk_randomness(rq->rq_disk); - - return false; -} - -/** - * blk_unprep_request - unprepare a request - * @req: the request - * - * This function makes a request ready for complete resubmission (or - * completion). It happens only after all error handling is complete, - * so represents the appropriate moment to deallocate any resources - * that were allocated to the request in the prep_rq_fn. The queue - * lock is held when calling this. - */ -void blk_unprep_request(struct request *req) -{ - struct request_queue *q = req->q; - - req->cmd_flags &= ~REQ_DONTPREP; - if (q->unprep_rq_fn) - q->unprep_rq_fn(q, req); -} -EXPORT_SYMBOL_GPL(blk_unprep_request); - -/* - * queue lock must be held - */ -void blk_finish_request(struct request *req, int error) -{ - if (req->cmd_flags & REQ_QUEUED) - blk_queue_end_tag(req->q, req); - - BUG_ON(blk_queued_rq(req)); - - if (unlikely(laptop_mode) && req->cmd_type == REQ_TYPE_FS) - laptop_io_completion(&req->q->backing_dev_info); - - blk_delete_timer(req); - - if (req->cmd_flags & REQ_DONTPREP) - blk_unprep_request(req); - - blk_account_io_done(req); - - if (req->end_io) - req->end_io(req, error); - else { - if (blk_bidi_rq(req)) - __blk_put_request(req->next_rq->q, req->next_rq); - - __blk_put_request(req->q, req); - } -} -EXPORT_SYMBOL(blk_finish_request); - -/** - * blk_end_bidi_request - Complete a bidi request - * @rq: the request to complete - * @error: %0 for success, < %0 for error - * @nr_bytes: number of bytes to complete @rq - * @bidi_bytes: number of bytes to complete @rq->next_rq - * - * Description: - * Ends I/O on a number of bytes attached to @rq and @rq->next_rq. - * Drivers that supports bidi can safely call this member for any - * type of request, bidi or uni. In the later case @bidi_bytes is - * just ignored. - * - * Return: - * %false - we are done with this request - * %true - still buffers pending for this request - **/ -static bool blk_end_bidi_request(struct request *rq, int error, - unsigned int nr_bytes, unsigned int bidi_bytes) -{ - struct request_queue *q = rq->q; - unsigned long flags; - - if (blk_update_bidi_request(rq, error, nr_bytes, bidi_bytes)) - return true; - - spin_lock_irqsave(q->queue_lock, flags); - blk_finish_request(rq, error); - spin_unlock_irqrestore(q->queue_lock, flags); - - return false; -} - -/** - * __blk_end_bidi_request - Complete a bidi request with queue lock held - * @rq: the request to complete - * @error: %0 for success, < %0 for error - * @nr_bytes: number of bytes to complete @rq - * @bidi_bytes: number of bytes to complete @rq->next_rq - * - * Description: - * Identical to blk_end_bidi_request() except that queue lock is - * assumed to be locked on entry and remains so on return. - * - * Return: - * %false - we are done with this request - * %true - still buffers pending for this request - **/ -bool __blk_end_bidi_request(struct request *rq, int error, - unsigned int nr_bytes, unsigned int bidi_bytes) -{ - if (blk_update_bidi_request(rq, error, nr_bytes, bidi_bytes)) - return true; - - blk_finish_request(rq, error); - - return false; -} - -/** - * blk_end_request - Helper function for drivers to complete the request. - * @rq: the request being processed - * @error: %0 for success, < %0 for error - * @nr_bytes: number of bytes to complete - * - * Description: - * Ends I/O on a number of bytes attached to @rq. - * If @rq has leftover, sets it up for the next range of segments. - * - * Return: - * %false - we are done with this request - * %true - still buffers pending for this request - **/ -bool blk_end_request(struct request *rq, int error, unsigned int nr_bytes) -{ - return blk_end_bidi_request(rq, error, nr_bytes, 0); -} -EXPORT_SYMBOL(blk_end_request); - -/** - * blk_end_request_all - Helper function for drives to finish the request. - * @rq: the request to finish - * @error: %0 for success, < %0 for error - * - * Description: - * Completely finish @rq. - */ -void blk_end_request_all(struct request *rq, int error) -{ - bool pending; - unsigned int bidi_bytes = 0; - - if (unlikely(blk_bidi_rq(rq))) - bidi_bytes = blk_rq_bytes(rq->next_rq); - - pending = blk_end_bidi_request(rq, error, blk_rq_bytes(rq), bidi_bytes); - BUG_ON(pending); -} -EXPORT_SYMBOL(blk_end_request_all); - -/** - * blk_end_request_cur - Helper function to finish the current request chunk. - * @rq: the request to finish the current chunk for - * @error: %0 for success, < %0 for error - * - * Description: - * Complete the current consecutively mapped chunk from @rq. - * - * Return: - * %false - we are done with this request - * %true - still buffers pending for this request - */ -bool blk_end_request_cur(struct request *rq, int error) -{ - return blk_end_request(rq, error, blk_rq_cur_bytes(rq)); -} -EXPORT_SYMBOL(blk_end_request_cur); - -/** - * blk_end_request_err - Finish a request till the next failure boundary. - * @rq: the request to finish till the next failure boundary for - * @error: must be negative errno - * - * Description: - * Complete @rq till the next failure boundary. - * - * Return: - * %false - we are done with this request - * %true - still buffers pending for this request - */ -bool blk_end_request_err(struct request *rq, int error) -{ - WARN_ON(error >= 0); - return blk_end_request(rq, error, blk_rq_err_bytes(rq)); -} -EXPORT_SYMBOL_GPL(blk_end_request_err); - -/** - * __blk_end_request - Helper function for drivers to complete the request. - * @rq: the request being processed - * @error: %0 for success, < %0 for error - * @nr_bytes: number of bytes to complete - * - * Description: - * Must be called with queue lock held unlike blk_end_request(). - * - * Return: - * %false - we are done with this request - * %true - still buffers pending for this request - **/ -bool __blk_end_request(struct request *rq, int error, unsigned int nr_bytes) -{ - return __blk_end_bidi_request(rq, error, nr_bytes, 0); -} -EXPORT_SYMBOL(__blk_end_request); - -/** - * __blk_end_request_all - Helper function for drives to finish the request. - * @rq: the request to finish - * @error: %0 for success, < %0 for error - * - * Description: - * Completely finish @rq. Must be called with queue lock held. - */ -void __blk_end_request_all(struct request *rq, int error) -{ - bool pending; - unsigned int bidi_bytes = 0; - - if (unlikely(blk_bidi_rq(rq))) - bidi_bytes = blk_rq_bytes(rq->next_rq); - - pending = __blk_end_bidi_request(rq, error, blk_rq_bytes(rq), bidi_bytes); - BUG_ON(pending); -} -EXPORT_SYMBOL(__blk_end_request_all); - -/** - * __blk_end_request_cur - Helper function to finish the current request chunk. - * @rq: the request to finish the current chunk for - * @error: %0 for success, < %0 for error - * - * Description: - * Complete the current consecutively mapped chunk from @rq. Must - * be called with queue lock held. - * - * Return: - * %false - we are done with this request - * %true - still buffers pending for this request - */ -bool __blk_end_request_cur(struct request *rq, int error) -{ - return __blk_end_request(rq, error, blk_rq_cur_bytes(rq)); -} -EXPORT_SYMBOL(__blk_end_request_cur); - -/** - * __blk_end_request_err - Finish a request till the next failure boundary. - * @rq: the request to finish till the next failure boundary for - * @error: must be negative errno - * - * Description: - * Complete @rq till the next failure boundary. Must be called - * with queue lock held. - * - * Return: - * %false - we are done with this request - * %true - still buffers pending for this request - */ -bool __blk_end_request_err(struct request *rq, int error) -{ - WARN_ON(error >= 0); - return __blk_end_request(rq, error, blk_rq_err_bytes(rq)); -} -EXPORT_SYMBOL_GPL(__blk_end_request_err); - -void blk_rq_bio_prep(struct request_queue *q, struct request *rq, - struct bio *bio) -{ - req_set_op(rq, bio_op(bio)); - - if (bio_has_data(bio)) - rq->nr_phys_segments = bio_phys_segments(q, bio); - - rq->__data_len = bio->bi_iter.bi_size; - rq->bio = rq->biotail = bio; - - if (bio->bi_bdev) - rq->rq_disk = bio->bi_bdev->bd_disk; -} - -#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE -/** - * rq_flush_dcache_pages - Helper function to flush all pages in a request - * @rq: the request to be flushed - * - * Description: - * Flush all pages in @rq. - */ -void rq_flush_dcache_pages(struct request *rq) -{ - struct req_iterator iter; - struct bio_vec bvec; - - rq_for_each_segment(bvec, rq, iter) - flush_dcache_page(bvec.bv_page); -} -EXPORT_SYMBOL_GPL(rq_flush_dcache_pages); -#endif - -/** - * blk_lld_busy - Check if underlying low-level drivers of a device are busy - * @q : the queue of the device being checked - * - * Description: - * Check if underlying low-level drivers of a device are busy. - * If the drivers want to export their busy state, they must set own - * exporting function using blk_queue_lld_busy() first. - * - * Basically, this function is used only by request stacking drivers - * to stop dispatching requests to underlying devices when underlying - * devices are busy. This behavior helps more I/O merging on the queue - * of the request stacking driver and prevents I/O throughput regression - * on burst I/O load. - * - * Return: - * 0 - Not busy (The request stacking driver should dispatch request) - * 1 - Busy (The request stacking driver should stop dispatching request) - */ -int blk_lld_busy(struct request_queue *q) -{ - if (q->lld_busy_fn) - return q->lld_busy_fn(q); - - return 0; -} -EXPORT_SYMBOL_GPL(blk_lld_busy); - -/** - * blk_rq_unprep_clone - Helper function to free all bios in a cloned request - * @rq: the clone request to be cleaned up - * - * Description: - * Free all bios in @rq for a cloned request. - */ -void blk_rq_unprep_clone(struct request *rq) -{ - struct bio *bio; - - while ((bio = rq->bio) != NULL) { - rq->bio = bio->bi_next; - - bio_put(bio); - } -} -EXPORT_SYMBOL_GPL(blk_rq_unprep_clone); - -/* - * Copy attributes of the original request to the clone request. - * The actual data parts (e.g. ->cmd, ->sense) are not copied. - */ -static void __blk_rq_prep_clone(struct request *dst, struct request *src) -{ - dst->cpu = src->cpu; - req_set_op_attrs(dst, req_op(src), - (src->cmd_flags & REQ_CLONE_MASK) | REQ_NOMERGE); - dst->cmd_type = src->cmd_type; - dst->__sector = blk_rq_pos(src); - dst->__data_len = blk_rq_bytes(src); - dst->nr_phys_segments = src->nr_phys_segments; - dst->ioprio = src->ioprio; - dst->extra_len = src->extra_len; -} - -/** - * blk_rq_prep_clone - Helper function to setup clone request - * @rq: the request to be setup - * @rq_src: original request to be cloned - * @bs: bio_set that bios for clone are allocated from - * @gfp_mask: memory allocation mask for bio - * @bio_ctr: setup function to be called for each clone bio. - * Returns %0 for success, non %0 for failure. - * @data: private data to be passed to @bio_ctr - * - * Description: - * Clones bios in @rq_src to @rq, and copies attributes of @rq_src to @rq. - * The actual data parts of @rq_src (e.g. ->cmd, ->sense) - * are not copied, and copying such parts is the caller's responsibility. - * Also, pages which the original bios are pointing to are not copied - * and the cloned bios just point same pages. - * So cloned bios must be completed before original bios, which means - * the caller must complete @rq before @rq_src. - */ -int blk_rq_prep_clone(struct request *rq, struct request *rq_src, - struct bio_set *bs, gfp_t gfp_mask, - int (*bio_ctr)(struct bio *, struct bio *, void *), - void *data) -{ - struct bio *bio, *bio_src; - - if (!bs) - bs = fs_bio_set; - - __rq_for_each_bio(bio_src, rq_src) { - bio = bio_clone_fast(bio_src, gfp_mask, bs); - if (!bio) - goto free_and_out; - - if (bio_ctr && bio_ctr(bio, bio_src, data)) - goto free_and_out; - - if (rq->bio) { - rq->biotail->bi_next = bio; - rq->biotail = bio; - } else - rq->bio = rq->biotail = bio; - } - - __blk_rq_prep_clone(rq, rq_src); - - return 0; - -free_and_out: - if (bio) - bio_put(bio); - blk_rq_unprep_clone(rq); - - return -ENOMEM; -} -EXPORT_SYMBOL_GPL(blk_rq_prep_clone); - -int kblockd_schedule_work(struct work_struct *work) -{ - return queue_work(kblockd_workqueue, work); -} -EXPORT_SYMBOL(kblockd_schedule_work); - -int kblockd_schedule_work_on(int cpu, struct work_struct *work) -{ - return queue_work_on(cpu, kblockd_workqueue, work); -} -EXPORT_SYMBOL(kblockd_schedule_work_on); - -int kblockd_schedule_delayed_work(struct delayed_work *dwork, - unsigned long delay) -{ - return queue_delayed_work(kblockd_workqueue, dwork, delay); -} -EXPORT_SYMBOL(kblockd_schedule_delayed_work); - -int kblockd_schedule_delayed_work_on(int cpu, struct delayed_work *dwork, - unsigned long delay) -{ - return queue_delayed_work_on(cpu, kblockd_workqueue, dwork, delay); -} -EXPORT_SYMBOL(kblockd_schedule_delayed_work_on); - -/** - * blk_start_plug - initialize blk_plug and track it inside the task_struct - * @plug: The &struct blk_plug that needs to be initialized - * - * Description: - * Tracking blk_plug inside the task_struct will help with auto-flushing the - * pending I/O should the task end up blocking between blk_start_plug() and - * blk_finish_plug(). This is important from a performance perspective, but - * also ensures that we don't deadlock. For instance, if the task is blocking - * for a memory allocation, memory reclaim could end up wanting to free a - * page belonging to that request that is currently residing in our private - * plug. By flushing the pending I/O when the process goes to sleep, we avoid - * this kind of deadlock. - */ -void blk_start_plug(struct blk_plug *plug) -{ - struct task_struct *tsk = current; - - /* - * If this is a nested plug, don't actually assign it. - */ - if (tsk->plug) - return; - - INIT_LIST_HEAD(&plug->list); - INIT_LIST_HEAD(&plug->mq_list); - INIT_LIST_HEAD(&plug->cb_list); - /* - * Store ordering should not be needed here, since a potential - * preempt will imply a full memory barrier - */ - tsk->plug = plug; -} -EXPORT_SYMBOL(blk_start_plug); - -static int plug_rq_cmp(void *priv, struct list_head *a, struct list_head *b) -{ - struct request *rqa = container_of(a, struct request, queuelist); - struct request *rqb = container_of(b, struct request, queuelist); - - return !(rqa->q < rqb->q || - (rqa->q == rqb->q && blk_rq_pos(rqa) < blk_rq_pos(rqb))); -} - -/* - * If 'from_schedule' is true, then postpone the dispatch of requests - * until a safe kblockd context. We due this to avoid accidental big - * additional stack usage in driver dispatch, in places where the originally - * plugger did not intend it. - */ -static void queue_unplugged(struct request_queue *q, unsigned int depth, - bool from_schedule) - __releases(q->queue_lock) -{ - trace_block_unplug(q, depth, !from_schedule); - - if (from_schedule) - blk_run_queue_async(q); - else - __blk_run_queue(q); - spin_unlock(q->queue_lock); -} - -static void flush_plug_callbacks(struct blk_plug *plug, bool from_schedule) -{ - LIST_HEAD(callbacks); - - while (!list_empty(&plug->cb_list)) { - list_splice_init(&plug->cb_list, &callbacks); - - while (!list_empty(&callbacks)) { - struct blk_plug_cb *cb = list_first_entry(&callbacks, - struct blk_plug_cb, - list); - list_del(&cb->list); - cb->callback(cb, from_schedule); - } - } -} - -struct blk_plug_cb *blk_check_plugged(blk_plug_cb_fn unplug, void *data, - int size) -{ - struct blk_plug *plug = current->plug; - struct blk_plug_cb *cb; - - if (!plug) - return NULL; - - list_for_each_entry(cb, &plug->cb_list, list) - if (cb->callback == unplug && cb->data == data) - return cb; - - /* Not currently on the callback list */ - BUG_ON(size < sizeof(*cb)); - cb = kzalloc(size, GFP_ATOMIC); - if (cb) { - cb->data = data; - cb->callback = unplug; - list_add(&cb->list, &plug->cb_list); - } - return cb; -} -EXPORT_SYMBOL(blk_check_plugged); - -void blk_flush_plug_list(struct blk_plug *plug, bool from_schedule) -{ - struct request_queue *q; - unsigned long flags; - struct request *rq; - LIST_HEAD(list); - unsigned int depth; - - flush_plug_callbacks(plug, from_schedule); - - if (!list_empty(&plug->mq_list)) - blk_mq_flush_plug_list(plug, from_schedule); - - if (list_empty(&plug->list)) - return; - - list_splice_init(&plug->list, &list); - - list_sort(NULL, &list, plug_rq_cmp); - - q = NULL; - depth = 0; - - /* - * Save and disable interrupts here, to avoid doing it for every - * queue lock we have to take. - */ - local_irq_save(flags); - while (!list_empty(&list)) { - rq = list_entry_rq(list.next); - list_del_init(&rq->queuelist); - BUG_ON(!rq->q); - if (rq->q != q) { - /* - * This drops the queue lock - */ - if (q) - queue_unplugged(q, depth, from_schedule); - q = rq->q; - depth = 0; - spin_lock(q->queue_lock); - } - - /* - * Short-circuit if @q is dead - */ - if (unlikely(blk_queue_dying(q))) { - __blk_end_request_all(rq, -ENODEV); - continue; - } - - /* - * rq is already accounted, so use raw insert - */ - if (rq->cmd_flags & (REQ_PREFLUSH | REQ_FUA)) - __elv_add_request(q, rq, ELEVATOR_INSERT_FLUSH); - else - __elv_add_request(q, rq, ELEVATOR_INSERT_SORT_MERGE); - - depth++; - } - - /* - * This drops the queue lock - */ - if (q) - queue_unplugged(q, depth, from_schedule); - - local_irq_restore(flags); -} - -void blk_finish_plug(struct blk_plug *plug) -{ - if (plug != current->plug) - return; - blk_flush_plug_list(plug, false); - - current->plug = NULL; -} -EXPORT_SYMBOL(blk_finish_plug); - -bool blk_poll(struct request_queue *q, blk_qc_t cookie) -{ - struct blk_plug *plug; - long state; - unsigned int queue_num; - struct blk_mq_hw_ctx *hctx; - - if (!q->mq_ops || !q->mq_ops->poll || !blk_qc_t_valid(cookie) || - !test_bit(QUEUE_FLAG_POLL, &q->queue_flags)) - return false; - - queue_num = blk_qc_t_to_queue_num(cookie); - hctx = q->queue_hw_ctx[queue_num]; - hctx->poll_considered++; - - plug = current->plug; - if (plug) - blk_flush_plug_list(plug, false); - - state = current->state; - while (!need_resched()) { - int ret; - - hctx->poll_invoked++; - - ret = q->mq_ops->poll(hctx, blk_qc_t_to_tag(cookie)); - if (ret > 0) { - hctx->poll_success++; - set_current_state(TASK_RUNNING); - return true; - } - - if (signal_pending_state(state, current)) - set_current_state(TASK_RUNNING); - - if (current->state == TASK_RUNNING) - return true; - if (ret < 0) - break; - cpu_relax(); - } - - return false; -} -EXPORT_SYMBOL_GPL(blk_poll); - -#ifdef CONFIG_PM -/** - * blk_pm_runtime_init - Block layer runtime PM initialization routine - * @q: the queue of the device - * @dev: the device the queue belongs to - * - * Description: - * Initialize runtime-PM-related fields for @q and start auto suspend for - * @dev. Drivers that want to take advantage of request-based runtime PM - * should call this function after @dev has been initialized, and its - * request queue @q has been allocated, and runtime PM for it can not happen - * yet(either due to disabled/forbidden or its usage_count > 0). In most - * cases, driver should call this function before any I/O has taken place. - * - * This function takes care of setting up using auto suspend for the device, - * the autosuspend delay is set to -1 to make runtime suspend impossible - * until an updated value is either set by user or by driver. Drivers do - * not need to touch other autosuspend settings. - * - * The block layer runtime PM is request based, so only works for drivers - * that use request as their IO unit instead of those directly use bio's. - */ -void blk_pm_runtime_init(struct request_queue *q, struct device *dev) -{ - q->dev = dev; - q->rpm_status = RPM_ACTIVE; - pm_runtime_set_autosuspend_delay(q->dev, -1); - pm_runtime_use_autosuspend(q->dev); -} -EXPORT_SYMBOL(blk_pm_runtime_init); - -/** - * blk_pre_runtime_suspend - Pre runtime suspend check - * @q: the queue of the device - * - * Description: - * This function will check if runtime suspend is allowed for the device - * by examining if there are any requests pending in the queue. If there - * are requests pending, the device can not be runtime suspended; otherwise, - * the queue's status will be updated to SUSPENDING and the driver can - * proceed to suspend the device. - * - * For the not allowed case, we mark last busy for the device so that - * runtime PM core will try to autosuspend it some time later. - * - * This function should be called near the start of the device's - * runtime_suspend callback. - * - * Return: - * 0 - OK to runtime suspend the device - * -EBUSY - Device should not be runtime suspended - */ -int blk_pre_runtime_suspend(struct request_queue *q) -{ - int ret = 0; - - if (!q->dev) - return ret; - - spin_lock_irq(q->queue_lock); - if (q->nr_pending) { - ret = -EBUSY; - pm_runtime_mark_last_busy(q->dev); - } else { - q->rpm_status = RPM_SUSPENDING; - } - spin_unlock_irq(q->queue_lock); - return ret; -} -EXPORT_SYMBOL(blk_pre_runtime_suspend); - -/** - * blk_post_runtime_suspend - Post runtime suspend processing - * @q: the queue of the device - * @err: return value of the device's runtime_suspend function - * - * Description: - * Update the queue's runtime status according to the return value of the - * device's runtime suspend function and mark last busy for the device so - * that PM core will try to auto suspend the device at a later time. - * - * This function should be called near the end of the device's - * runtime_suspend callback. - */ -void blk_post_runtime_suspend(struct request_queue *q, int err) -{ - if (!q->dev) - return; - - spin_lock_irq(q->queue_lock); - if (!err) { - q->rpm_status = RPM_SUSPENDED; - } else { - q->rpm_status = RPM_ACTIVE; - pm_runtime_mark_last_busy(q->dev); - } - spin_unlock_irq(q->queue_lock); -} -EXPORT_SYMBOL(blk_post_runtime_suspend); - -/** - * blk_pre_runtime_resume - Pre runtime resume processing - * @q: the queue of the device - * - * Description: - * Update the queue's runtime status to RESUMING in preparation for the - * runtime resume of the device. - * - * This function should be called near the start of the device's - * runtime_resume callback. - */ -void blk_pre_runtime_resume(struct request_queue *q) -{ - if (!q->dev) - return; - - spin_lock_irq(q->queue_lock); - q->rpm_status = RPM_RESUMING; - spin_unlock_irq(q->queue_lock); -} -EXPORT_SYMBOL(blk_pre_runtime_resume); - -/** - * blk_post_runtime_resume - Post runtime resume processing - * @q: the queue of the device - * @err: return value of the device's runtime_resume function - * - * Description: - * Update the queue's runtime status according to the return value of the - * device's runtime_resume function. If it is successfully resumed, process - * the requests that are queued into the device's queue when it is resuming - * and then mark last busy and initiate autosuspend for it. - * - * This function should be called near the end of the device's - * runtime_resume callback. - */ -void blk_post_runtime_resume(struct request_queue *q, int err) -{ - if (!q->dev) - return; - - spin_lock_irq(q->queue_lock); - if (!err) { - q->rpm_status = RPM_ACTIVE; - __blk_run_queue(q); - pm_runtime_mark_last_busy(q->dev); - pm_request_autosuspend(q->dev); - } else { - q->rpm_status = RPM_SUSPENDED; - } - spin_unlock_irq(q->queue_lock); -} -EXPORT_SYMBOL(blk_post_runtime_resume); - -/** - * blk_set_runtime_active - Force runtime status of the queue to be active - * @q: the queue of the device - * - * If the device is left runtime suspended during system suspend the resume - * hook typically resumes the device and corrects runtime status - * accordingly. However, that does not affect the queue runtime PM status - * which is still "suspended". This prevents processing requests from the - * queue. - * - * This function can be used in driver's resume hook to correct queue - * runtime PM status and re-enable peeking requests from the queue. It - * should be called before first request is added to the queue. - */ -void blk_set_runtime_active(struct request_queue *q) -{ - spin_lock_irq(q->queue_lock); - q->rpm_status = RPM_ACTIVE; - pm_runtime_mark_last_busy(q->dev); - pm_request_autosuspend(q->dev); - spin_unlock_irq(q->queue_lock); -} -EXPORT_SYMBOL(blk_set_runtime_active); -#endif - -int __init blk_dev_init(void) -{ - BUILD_BUG_ON(__REQ_NR_BITS > 8 * - FIELD_SIZEOF(struct request, cmd_flags)); - - /* used for unplugging and affects IO latency/throughput - HIGHPRI */ - kblockd_workqueue = alloc_workqueue("kblockd", - WQ_MEM_RECLAIM | WQ_HIGHPRI, 0); - if (!kblockd_workqueue) - panic("Failed to create kblockd\n"); - - request_cachep = kmem_cache_create("blkdev_requests", - sizeof(struct request), 0, SLAB_PANIC, NULL); - - blk_requestq_cachep = kmem_cache_create("request_queue", - sizeof(struct request_queue), 0, SLAB_PANIC, NULL); - - return 0; -} diff --git a/src/linux/block/blk-exec.c b/src/linux/block/blk-exec.c deleted file mode 100644 index 7ea0432..0000000 --- a/src/linux/block/blk-exec.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Functions related to setting various queue properties from drivers - */ -#include -#include -#include -#include -#include -#include - -#include "blk.h" - -/* - * for max sense size - */ -#include - -/** - * blk_end_sync_rq - executes a completion event on a request - * @rq: request to complete - * @error: end I/O status of the request - */ -static void blk_end_sync_rq(struct request *rq, int error) -{ - struct completion *waiting = rq->end_io_data; - - rq->end_io_data = NULL; - - /* - * complete last, if this is a stack request the process (and thus - * the rq pointer) could be invalid right after this complete() - */ - complete(waiting); -} - -/** - * blk_execute_rq_nowait - insert a request into queue for execution - * @q: queue to insert the request in - * @bd_disk: matching gendisk - * @rq: request to insert - * @at_head: insert request at head or tail of queue - * @done: I/O completion handler - * - * Description: - * Insert a fully prepared request at the back of the I/O scheduler queue - * for execution. Don't wait for completion. - * - * Note: - * This function will invoke @done directly if the queue is dead. - */ -void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk, - struct request *rq, int at_head, - rq_end_io_fn *done) -{ - int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK; - - WARN_ON(irqs_disabled()); - WARN_ON(rq->cmd_type == REQ_TYPE_FS); - - rq->rq_disk = bd_disk; - rq->end_io = done; - - /* - * don't check dying flag for MQ because the request won't - * be reused after dying flag is set - */ - if (q->mq_ops) { - blk_mq_insert_request(rq, at_head, true, false); - return; - } - - spin_lock_irq(q->queue_lock); - - if (unlikely(blk_queue_dying(q))) { - rq->cmd_flags |= REQ_QUIET; - rq->errors = -ENXIO; - __blk_end_request_all(rq, rq->errors); - spin_unlock_irq(q->queue_lock); - return; - } - - __elv_add_request(q, rq, where); - __blk_run_queue(q); - spin_unlock_irq(q->queue_lock); -} -EXPORT_SYMBOL_GPL(blk_execute_rq_nowait); - -/** - * blk_execute_rq - insert a request into queue for execution - * @q: queue to insert the request in - * @bd_disk: matching gendisk - * @rq: request to insert - * @at_head: insert request at head or tail of queue - * - * Description: - * Insert a fully prepared request at the back of the I/O scheduler queue - * for execution and wait for completion. - */ -int blk_execute_rq(struct request_queue *q, struct gendisk *bd_disk, - struct request *rq, int at_head) -{ - DECLARE_COMPLETION_ONSTACK(wait); - char sense[SCSI_SENSE_BUFFERSIZE]; - int err = 0; - unsigned long hang_check; - - if (!rq->sense) { - memset(sense, 0, sizeof(sense)); - rq->sense = sense; - rq->sense_len = 0; - } - - rq->end_io_data = &wait; - blk_execute_rq_nowait(q, bd_disk, rq, at_head, blk_end_sync_rq); - - /* Prevent hang_check timer from firing at us during very long I/O */ - hang_check = sysctl_hung_task_timeout_secs; - if (hang_check) - while (!wait_for_completion_io_timeout(&wait, hang_check * (HZ/2))); - else - wait_for_completion_io(&wait); - - if (rq->errors) - err = -EIO; - - if (rq->sense == sense) { - rq->sense = NULL; - rq->sense_len = 0; - } - - return err; -} -EXPORT_SYMBOL(blk_execute_rq); diff --git a/src/linux/block/blk-flush.c b/src/linux/block/blk-flush.c deleted file mode 100644 index 3c882cb..0000000 --- a/src/linux/block/blk-flush.c +++ /dev/null @@ -1,572 +0,0 @@ -/* - * Functions to sequence FLUSH and FUA writes. - * - * Copyright (C) 2011 Max Planck Institute for Gravitational Physics - * Copyright (C) 2011 Tejun Heo - * - * This file is released under the GPLv2. - * - * REQ_{FLUSH|FUA} requests are decomposed to sequences consisted of three - * optional steps - PREFLUSH, DATA and POSTFLUSH - according to the request - * properties and hardware capability. - * - * If a request doesn't have data, only REQ_PREFLUSH makes sense, which - * indicates a simple flush request. If there is data, REQ_PREFLUSH indicates - * that the device cache should be flushed before the data is executed, and - * REQ_FUA means that the data must be on non-volatile media on request - * completion. - * - * If the device doesn't have writeback cache, FLUSH and FUA don't make any - * difference. The requests are either completed immediately if there's no - * data or executed as normal requests otherwise. - * - * If the device has writeback cache and supports FUA, REQ_PREFLUSH is - * translated to PREFLUSH but REQ_FUA is passed down directly with DATA. - * - * If the device has writeback cache and doesn't support FUA, REQ_PREFLUSH - * is translated to PREFLUSH and REQ_FUA to POSTFLUSH. - * - * The actual execution of flush is double buffered. Whenever a request - * needs to execute PRE or POSTFLUSH, it queues at - * fq->flush_queue[fq->flush_pending_idx]. Once certain criteria are met, a - * REQ_OP_FLUSH is issued and the pending_idx is toggled. When the flush - * completes, all the requests which were pending are proceeded to the next - * step. This allows arbitrary merging of different types of FLUSH/FUA - * requests. - * - * Currently, the following conditions are used to determine when to issue - * flush. - * - * C1. At any given time, only one flush shall be in progress. This makes - * double buffering sufficient. - * - * C2. Flush is deferred if any request is executing DATA of its sequence. - * This avoids issuing separate POSTFLUSHes for requests which shared - * PREFLUSH. - * - * C3. The second condition is ignored if there is a request which has - * waited longer than FLUSH_PENDING_TIMEOUT. This is to avoid - * starvation in the unlikely case where there are continuous stream of - * FUA (without FLUSH) requests. - * - * For devices which support FUA, it isn't clear whether C2 (and thus C3) - * is beneficial. - * - * Note that a sequenced FLUSH/FUA request with DATA is completed twice. - * Once while executing DATA and again after the whole sequence is - * complete. The first completion updates the contained bio but doesn't - * finish it so that the bio submitter is notified only after the whole - * sequence is complete. This is implemented by testing REQ_FLUSH_SEQ in - * req_bio_endio(). - * - * The above peculiarity requires that each FLUSH/FUA request has only one - * bio attached to it, which is guaranteed as they aren't allowed to be - * merged in the usual way. - */ - -#include -#include -#include -#include -#include -#include - -#include "blk.h" -#include "blk-mq.h" -#include "blk-mq-tag.h" - -/* FLUSH/FUA sequences */ -enum { - REQ_FSEQ_PREFLUSH = (1 << 0), /* pre-flushing in progress */ - REQ_FSEQ_DATA = (1 << 1), /* data write in progress */ - REQ_FSEQ_POSTFLUSH = (1 << 2), /* post-flushing in progress */ - REQ_FSEQ_DONE = (1 << 3), - - REQ_FSEQ_ACTIONS = REQ_FSEQ_PREFLUSH | REQ_FSEQ_DATA | - REQ_FSEQ_POSTFLUSH, - - /* - * If flush has been pending longer than the following timeout, - * it's issued even if flush_data requests are still in flight. - */ - FLUSH_PENDING_TIMEOUT = 5 * HZ, -}; - -static bool blk_kick_flush(struct request_queue *q, - struct blk_flush_queue *fq); - -static unsigned int blk_flush_policy(unsigned long fflags, struct request *rq) -{ - unsigned int policy = 0; - - if (blk_rq_sectors(rq)) - policy |= REQ_FSEQ_DATA; - - if (fflags & (1UL << QUEUE_FLAG_WC)) { - if (rq->cmd_flags & REQ_PREFLUSH) - policy |= REQ_FSEQ_PREFLUSH; - if (!(fflags & (1UL << QUEUE_FLAG_FUA)) && - (rq->cmd_flags & REQ_FUA)) - policy |= REQ_FSEQ_POSTFLUSH; - } - return policy; -} - -static unsigned int blk_flush_cur_seq(struct request *rq) -{ - return 1 << ffz(rq->flush.seq); -} - -static void blk_flush_restore_request(struct request *rq) -{ - /* - * After flush data completion, @rq->bio is %NULL but we need to - * complete the bio again. @rq->biotail is guaranteed to equal the - * original @rq->bio. Restore it. - */ - rq->bio = rq->biotail; - - /* make @rq a normal request */ - rq->cmd_flags &= ~REQ_FLUSH_SEQ; - rq->end_io = rq->flush.saved_end_io; -} - -static bool blk_flush_queue_rq(struct request *rq, bool add_front) -{ - if (rq->q->mq_ops) { - struct request_queue *q = rq->q; - - blk_mq_add_to_requeue_list(rq, add_front); - blk_mq_kick_requeue_list(q); - return false; - } else { - if (add_front) - list_add(&rq->queuelist, &rq->q->queue_head); - else - list_add_tail(&rq->queuelist, &rq->q->queue_head); - return true; - } -} - -/** - * blk_flush_complete_seq - complete flush sequence - * @rq: FLUSH/FUA request being sequenced - * @fq: flush queue - * @seq: sequences to complete (mask of %REQ_FSEQ_*, can be zero) - * @error: whether an error occurred - * - * @rq just completed @seq part of its flush sequence, record the - * completion and trigger the next step. - * - * CONTEXT: - * spin_lock_irq(q->queue_lock or fq->mq_flush_lock) - * - * RETURNS: - * %true if requests were added to the dispatch queue, %false otherwise. - */ -static bool blk_flush_complete_seq(struct request *rq, - struct blk_flush_queue *fq, - unsigned int seq, int error) -{ - struct request_queue *q = rq->q; - struct list_head *pending = &fq->flush_queue[fq->flush_pending_idx]; - bool queued = false, kicked; - - BUG_ON(rq->flush.seq & seq); - rq->flush.seq |= seq; - - if (likely(!error)) - seq = blk_flush_cur_seq(rq); - else - seq = REQ_FSEQ_DONE; - - switch (seq) { - case REQ_FSEQ_PREFLUSH: - case REQ_FSEQ_POSTFLUSH: - /* queue for flush */ - if (list_empty(pending)) - fq->flush_pending_since = jiffies; - list_move_tail(&rq->flush.list, pending); - break; - - case REQ_FSEQ_DATA: - list_move_tail(&rq->flush.list, &fq->flush_data_in_flight); - queued = blk_flush_queue_rq(rq, true); - break; - - case REQ_FSEQ_DONE: - /* - * @rq was previously adjusted by blk_flush_issue() for - * flush sequencing and may already have gone through the - * flush data request completion path. Restore @rq for - * normal completion and end it. - */ - BUG_ON(!list_empty(&rq->queuelist)); - list_del_init(&rq->flush.list); - blk_flush_restore_request(rq); - if (q->mq_ops) - blk_mq_end_request(rq, error); - else - __blk_end_request_all(rq, error); - break; - - default: - BUG(); - } - - kicked = blk_kick_flush(q, fq); - return kicked | queued; -} - -static void flush_end_io(struct request *flush_rq, int error) -{ - struct request_queue *q = flush_rq->q; - struct list_head *running; - bool queued = false; - struct request *rq, *n; - unsigned long flags = 0; - struct blk_flush_queue *fq = blk_get_flush_queue(q, flush_rq->mq_ctx); - - if (q->mq_ops) { - struct blk_mq_hw_ctx *hctx; - - /* release the tag's ownership to the req cloned from */ - spin_lock_irqsave(&fq->mq_flush_lock, flags); - hctx = blk_mq_map_queue(q, flush_rq->mq_ctx->cpu); - blk_mq_tag_set_rq(hctx, flush_rq->tag, fq->orig_rq); - flush_rq->tag = -1; - } - - running = &fq->flush_queue[fq->flush_running_idx]; - BUG_ON(fq->flush_pending_idx == fq->flush_running_idx); - - /* account completion of the flush request */ - fq->flush_running_idx ^= 1; - - if (!q->mq_ops) - elv_completed_request(q, flush_rq); - - /* and push the waiting requests to the next stage */ - list_for_each_entry_safe(rq, n, running, flush.list) { - unsigned int seq = blk_flush_cur_seq(rq); - - BUG_ON(seq != REQ_FSEQ_PREFLUSH && seq != REQ_FSEQ_POSTFLUSH); - queued |= blk_flush_complete_seq(rq, fq, seq, error); - } - - /* - * Kick the queue to avoid stall for two cases: - * 1. Moving a request silently to empty queue_head may stall the - * queue. - * 2. When flush request is running in non-queueable queue, the - * queue is hold. Restart the queue after flush request is finished - * to avoid stall. - * This function is called from request completion path and calling - * directly into request_fn may confuse the driver. Always use - * kblockd. - */ - if (queued || fq->flush_queue_delayed) { - WARN_ON(q->mq_ops); - blk_run_queue_async(q); - } - fq->flush_queue_delayed = 0; - if (q->mq_ops) - spin_unlock_irqrestore(&fq->mq_flush_lock, flags); -} - -/** - * blk_kick_flush - consider issuing flush request - * @q: request_queue being kicked - * @fq: flush queue - * - * Flush related states of @q have changed, consider issuing flush request. - * Please read the comment at the top of this file for more info. - * - * CONTEXT: - * spin_lock_irq(q->queue_lock or fq->mq_flush_lock) - * - * RETURNS: - * %true if flush was issued, %false otherwise. - */ -static bool blk_kick_flush(struct request_queue *q, struct blk_flush_queue *fq) -{ - struct list_head *pending = &fq->flush_queue[fq->flush_pending_idx]; - struct request *first_rq = - list_first_entry(pending, struct request, flush.list); - struct request *flush_rq = fq->flush_rq; - - /* C1 described at the top of this file */ - if (fq->flush_pending_idx != fq->flush_running_idx || list_empty(pending)) - return false; - - /* C2 and C3 */ - if (!list_empty(&fq->flush_data_in_flight) && - time_before(jiffies, - fq->flush_pending_since + FLUSH_PENDING_TIMEOUT)) - return false; - - /* - * Issue flush and toggle pending_idx. This makes pending_idx - * different from running_idx, which means flush is in flight. - */ - fq->flush_pending_idx ^= 1; - - blk_rq_init(q, flush_rq); - - /* - * Borrow tag from the first request since they can't - * be in flight at the same time. And acquire the tag's - * ownership for flush req. - */ - if (q->mq_ops) { - struct blk_mq_hw_ctx *hctx; - - flush_rq->mq_ctx = first_rq->mq_ctx; - flush_rq->tag = first_rq->tag; - fq->orig_rq = first_rq; - - hctx = blk_mq_map_queue(q, first_rq->mq_ctx->cpu); - blk_mq_tag_set_rq(hctx, first_rq->tag, flush_rq); - } - - flush_rq->cmd_type = REQ_TYPE_FS; - req_set_op_attrs(flush_rq, REQ_OP_FLUSH, WRITE_FLUSH | REQ_FLUSH_SEQ); - flush_rq->rq_disk = first_rq->rq_disk; - flush_rq->end_io = flush_end_io; - - return blk_flush_queue_rq(flush_rq, false); -} - -static void flush_data_end_io(struct request *rq, int error) -{ - struct request_queue *q = rq->q; - struct blk_flush_queue *fq = blk_get_flush_queue(q, NULL); - - /* - * Updating q->in_flight[] here for making this tag usable - * early. Because in blk_queue_start_tag(), - * q->in_flight[BLK_RW_ASYNC] is used to limit async I/O and - * reserve tags for sync I/O. - * - * More importantly this way can avoid the following I/O - * deadlock: - * - * - suppose there are 40 fua requests comming to flush queue - * and queue depth is 31 - * - 30 rqs are scheduled then blk_queue_start_tag() can't alloc - * tag for async I/O any more - * - all the 30 rqs are completed before FLUSH_PENDING_TIMEOUT - * and flush_data_end_io() is called - * - the other rqs still can't go ahead if not updating - * q->in_flight[BLK_RW_ASYNC] here, meantime these rqs - * are held in flush data queue and make no progress of - * handling post flush rq - * - only after the post flush rq is handled, all these rqs - * can be completed - */ - - elv_completed_request(q, rq); - - /* for avoiding double accounting */ - rq->cmd_flags &= ~REQ_STARTED; - - /* - * After populating an empty queue, kick it to avoid stall. Read - * the comment in flush_end_io(). - */ - if (blk_flush_complete_seq(rq, fq, REQ_FSEQ_DATA, error)) - blk_run_queue_async(q); -} - -static void mq_flush_data_end_io(struct request *rq, int error) -{ - struct request_queue *q = rq->q; - struct blk_mq_hw_ctx *hctx; - struct blk_mq_ctx *ctx = rq->mq_ctx; - unsigned long flags; - struct blk_flush_queue *fq = blk_get_flush_queue(q, ctx); - - hctx = blk_mq_map_queue(q, ctx->cpu); - - /* - * After populating an empty queue, kick it to avoid stall. Read - * the comment in flush_end_io(). - */ - spin_lock_irqsave(&fq->mq_flush_lock, flags); - if (blk_flush_complete_seq(rq, fq, REQ_FSEQ_DATA, error)) - blk_mq_run_hw_queue(hctx, true); - spin_unlock_irqrestore(&fq->mq_flush_lock, flags); -} - -/** - * blk_insert_flush - insert a new FLUSH/FUA request - * @rq: request to insert - * - * To be called from __elv_add_request() for %ELEVATOR_INSERT_FLUSH insertions. - * or __blk_mq_run_hw_queue() to dispatch request. - * @rq is being submitted. Analyze what needs to be done and put it on the - * right queue. - * - * CONTEXT: - * spin_lock_irq(q->queue_lock) in !mq case - */ -void blk_insert_flush(struct request *rq) -{ - struct request_queue *q = rq->q; - unsigned long fflags = q->queue_flags; /* may change, cache */ - unsigned int policy = blk_flush_policy(fflags, rq); - struct blk_flush_queue *fq = blk_get_flush_queue(q, rq->mq_ctx); - - /* - * @policy now records what operations need to be done. Adjust - * REQ_PREFLUSH and FUA for the driver. - */ - rq->cmd_flags &= ~REQ_PREFLUSH; - if (!(fflags & (1UL << QUEUE_FLAG_FUA))) - rq->cmd_flags &= ~REQ_FUA; - - /* - * An empty flush handed down from a stacking driver may - * translate into nothing if the underlying device does not - * advertise a write-back cache. In this case, simply - * complete the request. - */ - if (!policy) { - if (q->mq_ops) - blk_mq_end_request(rq, 0); - else - __blk_end_bidi_request(rq, 0, 0, 0); - return; - } - - BUG_ON(rq->bio != rq->biotail); /*assumes zero or single bio rq */ - - /* - * If there's data but flush is not necessary, the request can be - * processed directly without going through flush machinery. Queue - * for normal execution. - */ - if ((policy & REQ_FSEQ_DATA) && - !(policy & (REQ_FSEQ_PREFLUSH | REQ_FSEQ_POSTFLUSH))) { - if (q->mq_ops) { - blk_mq_insert_request(rq, false, false, true); - } else - list_add_tail(&rq->queuelist, &q->queue_head); - return; - } - - /* - * @rq should go through flush machinery. Mark it part of flush - * sequence and submit for further processing. - */ - memset(&rq->flush, 0, sizeof(rq->flush)); - INIT_LIST_HEAD(&rq->flush.list); - rq->cmd_flags |= REQ_FLUSH_SEQ; - rq->flush.saved_end_io = rq->end_io; /* Usually NULL */ - if (q->mq_ops) { - rq->end_io = mq_flush_data_end_io; - - spin_lock_irq(&fq->mq_flush_lock); - blk_flush_complete_seq(rq, fq, REQ_FSEQ_ACTIONS & ~policy, 0); - spin_unlock_irq(&fq->mq_flush_lock); - return; - } - rq->end_io = flush_data_end_io; - - blk_flush_complete_seq(rq, fq, REQ_FSEQ_ACTIONS & ~policy, 0); -} - -/** - * blkdev_issue_flush - queue a flush - * @bdev: blockdev to issue flush for - * @gfp_mask: memory allocation flags (for bio_alloc) - * @error_sector: error sector - * - * Description: - * Issue a flush for the block device in question. Caller can supply - * room for storing the error offset in case of a flush error, if they - * wish to. If WAIT flag is not passed then caller may check only what - * request was pushed in some internal queue for later handling. - */ -int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask, - sector_t *error_sector) -{ - struct request_queue *q; - struct bio *bio; - int ret = 0; - - if (bdev->bd_disk == NULL) - return -ENXIO; - - q = bdev_get_queue(bdev); - if (!q) - return -ENXIO; - - /* - * some block devices may not have their queue correctly set up here - * (e.g. loop device without a backing file) and so issuing a flush - * here will panic. Ensure there is a request function before issuing - * the flush. - */ - if (!q->make_request_fn) - return -ENXIO; - - bio = bio_alloc(gfp_mask, 0); - bio->bi_bdev = bdev; - bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_FLUSH); - - ret = submit_bio_wait(bio); - - /* - * The driver must store the error location in ->bi_sector, if - * it supports it. For non-stacked drivers, this should be - * copied from blk_rq_pos(rq). - */ - if (error_sector) - *error_sector = bio->bi_iter.bi_sector; - - bio_put(bio); - return ret; -} -EXPORT_SYMBOL(blkdev_issue_flush); - -struct blk_flush_queue *blk_alloc_flush_queue(struct request_queue *q, - int node, int cmd_size) -{ - struct blk_flush_queue *fq; - int rq_sz = sizeof(struct request); - - fq = kzalloc_node(sizeof(*fq), GFP_KERNEL, node); - if (!fq) - goto fail; - - if (q->mq_ops) { - spin_lock_init(&fq->mq_flush_lock); - rq_sz = round_up(rq_sz + cmd_size, cache_line_size()); - } - - fq->flush_rq = kzalloc_node(rq_sz, GFP_KERNEL, node); - if (!fq->flush_rq) - goto fail_rq; - - INIT_LIST_HEAD(&fq->flush_queue[0]); - INIT_LIST_HEAD(&fq->flush_queue[1]); - INIT_LIST_HEAD(&fq->flush_data_in_flight); - - return fq; - - fail_rq: - kfree(fq); - fail: - return NULL; -} - -void blk_free_flush_queue(struct blk_flush_queue *fq) -{ - /* bio based request queue hasn't flush queue */ - if (!fq) - return; - - kfree(fq->flush_rq); - kfree(fq); -} diff --git a/src/linux/block/blk-ioc.c b/src/linux/block/blk-ioc.c deleted file mode 100644 index 381cb50..0000000 --- a/src/linux/block/blk-ioc.c +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Functions related to io context handling - */ -#include -#include -#include -#include -#include -#include - -#include "blk.h" - -/* - * For io context allocations - */ -static struct kmem_cache *iocontext_cachep; - -/** - * get_io_context - increment reference count to io_context - * @ioc: io_context to get - * - * Increment reference count to @ioc. - */ -void get_io_context(struct io_context *ioc) -{ - BUG_ON(atomic_long_read(&ioc->refcount) <= 0); - atomic_long_inc(&ioc->refcount); -} -EXPORT_SYMBOL(get_io_context); - -static void icq_free_icq_rcu(struct rcu_head *head) -{ - struct io_cq *icq = container_of(head, struct io_cq, __rcu_head); - - kmem_cache_free(icq->__rcu_icq_cache, icq); -} - -/* Exit an icq. Called with both ioc and q locked. */ -static void ioc_exit_icq(struct io_cq *icq) -{ - struct elevator_type *et = icq->q->elevator->type; - - if (icq->flags & ICQ_EXITED) - return; - - if (et->ops.elevator_exit_icq_fn) - et->ops.elevator_exit_icq_fn(icq); - - icq->flags |= ICQ_EXITED; -} - -/* Release an icq. Called with both ioc and q locked. */ -static void ioc_destroy_icq(struct io_cq *icq) -{ - struct io_context *ioc = icq->ioc; - struct request_queue *q = icq->q; - struct elevator_type *et = q->elevator->type; - - lockdep_assert_held(&ioc->lock); - lockdep_assert_held(q->queue_lock); - - radix_tree_delete(&ioc->icq_tree, icq->q->id); - hlist_del_init(&icq->ioc_node); - list_del_init(&icq->q_node); - - /* - * Both setting lookup hint to and clearing it from @icq are done - * under queue_lock. If it's not pointing to @icq now, it never - * will. Hint assignment itself can race safely. - */ - if (rcu_access_pointer(ioc->icq_hint) == icq) - rcu_assign_pointer(ioc->icq_hint, NULL); - - ioc_exit_icq(icq); - - /* - * @icq->q might have gone away by the time RCU callback runs - * making it impossible to determine icq_cache. Record it in @icq. - */ - icq->__rcu_icq_cache = et->icq_cache; - call_rcu(&icq->__rcu_head, icq_free_icq_rcu); -} - -/* - * Slow path for ioc release in put_io_context(). Performs double-lock - * dancing to unlink all icq's and then frees ioc. - */ -static void ioc_release_fn(struct work_struct *work) -{ - struct io_context *ioc = container_of(work, struct io_context, - release_work); - unsigned long flags; - - /* - * Exiting icq may call into put_io_context() through elevator - * which will trigger lockdep warning. The ioc's are guaranteed to - * be different, use a different locking subclass here. Use - * irqsave variant as there's no spin_lock_irq_nested(). - */ - spin_lock_irqsave_nested(&ioc->lock, flags, 1); - - while (!hlist_empty(&ioc->icq_list)) { - struct io_cq *icq = hlist_entry(ioc->icq_list.first, - struct io_cq, ioc_node); - struct request_queue *q = icq->q; - - if (spin_trylock(q->queue_lock)) { - ioc_destroy_icq(icq); - spin_unlock(q->queue_lock); - } else { - spin_unlock_irqrestore(&ioc->lock, flags); - cpu_relax(); - spin_lock_irqsave_nested(&ioc->lock, flags, 1); - } - } - - spin_unlock_irqrestore(&ioc->lock, flags); - - kmem_cache_free(iocontext_cachep, ioc); -} - -/** - * put_io_context - put a reference of io_context - * @ioc: io_context to put - * - * Decrement reference count of @ioc and release it if the count reaches - * zero. - */ -void put_io_context(struct io_context *ioc) -{ - unsigned long flags; - bool free_ioc = false; - - if (ioc == NULL) - return; - - BUG_ON(atomic_long_read(&ioc->refcount) <= 0); - - /* - * Releasing ioc requires reverse order double locking and we may - * already be holding a queue_lock. Do it asynchronously from wq. - */ - if (atomic_long_dec_and_test(&ioc->refcount)) { - spin_lock_irqsave(&ioc->lock, flags); - if (!hlist_empty(&ioc->icq_list)) - queue_work(system_power_efficient_wq, - &ioc->release_work); - else - free_ioc = true; - spin_unlock_irqrestore(&ioc->lock, flags); - } - - if (free_ioc) - kmem_cache_free(iocontext_cachep, ioc); -} -EXPORT_SYMBOL(put_io_context); - -/** - * put_io_context_active - put active reference on ioc - * @ioc: ioc of interest - * - * Undo get_io_context_active(). If active reference reaches zero after - * put, @ioc can never issue further IOs and ioscheds are notified. - */ -void put_io_context_active(struct io_context *ioc) -{ - unsigned long flags; - struct io_cq *icq; - - if (!atomic_dec_and_test(&ioc->active_ref)) { - put_io_context(ioc); - return; - } - - /* - * Need ioc lock to walk icq_list and q lock to exit icq. Perform - * reverse double locking. Read comment in ioc_release_fn() for - * explanation on the nested locking annotation. - */ -retry: - spin_lock_irqsave_nested(&ioc->lock, flags, 1); - hlist_for_each_entry(icq, &ioc->icq_list, ioc_node) { - if (icq->flags & ICQ_EXITED) - continue; - if (spin_trylock(icq->q->queue_lock)) { - ioc_exit_icq(icq); - spin_unlock(icq->q->queue_lock); - } else { - spin_unlock_irqrestore(&ioc->lock, flags); - cpu_relax(); - goto retry; - } - } - spin_unlock_irqrestore(&ioc->lock, flags); - - put_io_context(ioc); -} - -/* Called by the exiting task */ -void exit_io_context(struct task_struct *task) -{ - struct io_context *ioc; - - task_lock(task); - ioc = task->io_context; - task->io_context = NULL; - task_unlock(task); - - atomic_dec(&ioc->nr_tasks); - put_io_context_active(ioc); -} - -/** - * ioc_clear_queue - break any ioc association with the specified queue - * @q: request_queue being cleared - * - * Walk @q->icq_list and exit all io_cq's. Must be called with @q locked. - */ -void ioc_clear_queue(struct request_queue *q) -{ - lockdep_assert_held(q->queue_lock); - - while (!list_empty(&q->icq_list)) { - struct io_cq *icq = list_entry(q->icq_list.next, - struct io_cq, q_node); - struct io_context *ioc = icq->ioc; - - spin_lock(&ioc->lock); - ioc_destroy_icq(icq); - spin_unlock(&ioc->lock); - } -} - -int create_task_io_context(struct task_struct *task, gfp_t gfp_flags, int node) -{ - struct io_context *ioc; - int ret; - - ioc = kmem_cache_alloc_node(iocontext_cachep, gfp_flags | __GFP_ZERO, - node); - if (unlikely(!ioc)) - return -ENOMEM; - - /* initialize */ - atomic_long_set(&ioc->refcount, 1); - atomic_set(&ioc->nr_tasks, 1); - atomic_set(&ioc->active_ref, 1); - spin_lock_init(&ioc->lock); - INIT_RADIX_TREE(&ioc->icq_tree, GFP_ATOMIC | __GFP_HIGH); - INIT_HLIST_HEAD(&ioc->icq_list); - INIT_WORK(&ioc->release_work, ioc_release_fn); - - /* - * Try to install. ioc shouldn't be installed if someone else - * already did or @task, which isn't %current, is exiting. Note - * that we need to allow ioc creation on exiting %current as exit - * path may issue IOs from e.g. exit_files(). The exit path is - * responsible for not issuing IO after exit_io_context(). - */ - task_lock(task); - if (!task->io_context && - (task == current || !(task->flags & PF_EXITING))) - task->io_context = ioc; - else - kmem_cache_free(iocontext_cachep, ioc); - - ret = task->io_context ? 0 : -EBUSY; - - task_unlock(task); - - return ret; -} - -/** - * get_task_io_context - get io_context of a task - * @task: task of interest - * @gfp_flags: allocation flags, used if allocation is necessary - * @node: allocation node, used if allocation is necessary - * - * Return io_context of @task. If it doesn't exist, it is created with - * @gfp_flags and @node. The returned io_context has its reference count - * incremented. - * - * This function always goes through task_lock() and it's better to use - * %current->io_context + get_io_context() for %current. - */ -struct io_context *get_task_io_context(struct task_struct *task, - gfp_t gfp_flags, int node) -{ - struct io_context *ioc; - - might_sleep_if(gfpflags_allow_blocking(gfp_flags)); - - do { - task_lock(task); - ioc = task->io_context; - if (likely(ioc)) { - get_io_context(ioc); - task_unlock(task); - return ioc; - } - task_unlock(task); - } while (!create_task_io_context(task, gfp_flags, node)); - - return NULL; -} -EXPORT_SYMBOL(get_task_io_context); - -/** - * ioc_lookup_icq - lookup io_cq from ioc - * @ioc: the associated io_context - * @q: the associated request_queue - * - * Look up io_cq associated with @ioc - @q pair from @ioc. Must be called - * with @q->queue_lock held. - */ -struct io_cq *ioc_lookup_icq(struct io_context *ioc, struct request_queue *q) -{ - struct io_cq *icq; - - lockdep_assert_held(q->queue_lock); - - /* - * icq's are indexed from @ioc using radix tree and hint pointer, - * both of which are protected with RCU. All removals are done - * holding both q and ioc locks, and we're holding q lock - if we - * find a icq which points to us, it's guaranteed to be valid. - */ - rcu_read_lock(); - icq = rcu_dereference(ioc->icq_hint); - if (icq && icq->q == q) - goto out; - - icq = radix_tree_lookup(&ioc->icq_tree, q->id); - if (icq && icq->q == q) - rcu_assign_pointer(ioc->icq_hint, icq); /* allowed to race */ - else - icq = NULL; -out: - rcu_read_unlock(); - return icq; -} -EXPORT_SYMBOL(ioc_lookup_icq); - -/** - * ioc_create_icq - create and link io_cq - * @ioc: io_context of interest - * @q: request_queue of interest - * @gfp_mask: allocation mask - * - * Make sure io_cq linking @ioc and @q exists. If icq doesn't exist, they - * will be created using @gfp_mask. - * - * The caller is responsible for ensuring @ioc won't go away and @q is - * alive and will stay alive until this function returns. - */ -struct io_cq *ioc_create_icq(struct io_context *ioc, struct request_queue *q, - gfp_t gfp_mask) -{ - struct elevator_type *et = q->elevator->type; - struct io_cq *icq; - - /* allocate stuff */ - icq = kmem_cache_alloc_node(et->icq_cache, gfp_mask | __GFP_ZERO, - q->node); - if (!icq) - return NULL; - - if (radix_tree_maybe_preload(gfp_mask) < 0) { - kmem_cache_free(et->icq_cache, icq); - return NULL; - } - - icq->ioc = ioc; - icq->q = q; - INIT_LIST_HEAD(&icq->q_node); - INIT_HLIST_NODE(&icq->ioc_node); - - /* lock both q and ioc and try to link @icq */ - spin_lock_irq(q->queue_lock); - spin_lock(&ioc->lock); - - if (likely(!radix_tree_insert(&ioc->icq_tree, q->id, icq))) { - hlist_add_head(&icq->ioc_node, &ioc->icq_list); - list_add(&icq->q_node, &q->icq_list); - if (et->ops.elevator_init_icq_fn) - et->ops.elevator_init_icq_fn(icq); - } else { - kmem_cache_free(et->icq_cache, icq); - icq = ioc_lookup_icq(ioc, q); - if (!icq) - printk(KERN_ERR "cfq: icq link failed!\n"); - } - - spin_unlock(&ioc->lock); - spin_unlock_irq(q->queue_lock); - radix_tree_preload_end(); - return icq; -} - -static int __init blk_ioc_init(void) -{ - iocontext_cachep = kmem_cache_create("blkdev_ioc", - sizeof(struct io_context), 0, SLAB_PANIC, NULL); - return 0; -} -subsys_initcall(blk_ioc_init); diff --git a/src/linux/block/blk-lib.c b/src/linux/block/blk-lib.c deleted file mode 100644 index 46fe924..0000000 --- a/src/linux/block/blk-lib.c +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Functions related to generic helpers functions - */ -#include -#include -#include -#include -#include - -#include "blk.h" - -static struct bio *next_bio(struct bio *bio, unsigned int nr_pages, - gfp_t gfp) -{ - struct bio *new = bio_alloc(gfp, nr_pages); - - if (bio) { - bio_chain(bio, new); - submit_bio(bio); - } - - return new; -} - -int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, - sector_t nr_sects, gfp_t gfp_mask, int flags, - struct bio **biop) -{ - struct request_queue *q = bdev_get_queue(bdev); - struct bio *bio = *biop; - unsigned int granularity; - enum req_op op; - int alignment; - sector_t bs_mask; - - if (!q) - return -ENXIO; - - if (flags & BLKDEV_DISCARD_SECURE) { - if (flags & BLKDEV_DISCARD_ZERO) - return -EOPNOTSUPP; - if (!blk_queue_secure_erase(q)) - return -EOPNOTSUPP; - op = REQ_OP_SECURE_ERASE; - } else { - if (!blk_queue_discard(q)) - return -EOPNOTSUPP; - if ((flags & BLKDEV_DISCARD_ZERO) && - !q->limits.discard_zeroes_data) - return -EOPNOTSUPP; - op = REQ_OP_DISCARD; - } - - bs_mask = (bdev_logical_block_size(bdev) >> 9) - 1; - if ((sector | nr_sects) & bs_mask) - return -EINVAL; - - /* Zero-sector (unknown) and one-sector granularities are the same. */ - granularity = max(q->limits.discard_granularity >> 9, 1U); - alignment = (bdev_discard_alignment(bdev) >> 9) % granularity; - - while (nr_sects) { - unsigned int req_sects; - sector_t end_sect, tmp; - - /* Make sure bi_size doesn't overflow */ - req_sects = min_t(sector_t, nr_sects, UINT_MAX >> 9); - - /** - * If splitting a request, and the next starting sector would be - * misaligned, stop the discard at the previous aligned sector. - */ - end_sect = sector + req_sects; - tmp = end_sect; - if (req_sects < nr_sects && - sector_div(tmp, granularity) != alignment) { - end_sect = end_sect - alignment; - sector_div(end_sect, granularity); - end_sect = end_sect * granularity + alignment; - req_sects = end_sect - sector; - } - - bio = next_bio(bio, 1, gfp_mask); - bio->bi_iter.bi_sector = sector; - bio->bi_bdev = bdev; - bio_set_op_attrs(bio, op, 0); - - bio->bi_iter.bi_size = req_sects << 9; - nr_sects -= req_sects; - sector = end_sect; - - /* - * We can loop for a long time in here, if someone does - * full device discards (like mkfs). Be nice and allow - * us to schedule out to avoid softlocking if preempt - * is disabled. - */ - cond_resched(); - } - - *biop = bio; - return 0; -} -EXPORT_SYMBOL(__blkdev_issue_discard); - -/** - * blkdev_issue_discard - queue a discard - * @bdev: blockdev to issue discard for - * @sector: start sector - * @nr_sects: number of sectors to discard - * @gfp_mask: memory allocation flags (for bio_alloc) - * @flags: BLKDEV_IFL_* flags to control behaviour - * - * Description: - * Issue a discard request for the sectors in question. - */ -int blkdev_issue_discard(struct block_device *bdev, sector_t sector, - sector_t nr_sects, gfp_t gfp_mask, unsigned long flags) -{ - struct bio *bio = NULL; - struct blk_plug plug; - int ret; - - blk_start_plug(&plug); - ret = __blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask, flags, - &bio); - if (!ret && bio) { - ret = submit_bio_wait(bio); - if (ret == -EOPNOTSUPP && !(flags & BLKDEV_DISCARD_ZERO)) - ret = 0; - bio_put(bio); - } - blk_finish_plug(&plug); - - return ret; -} -EXPORT_SYMBOL(blkdev_issue_discard); - -/** - * blkdev_issue_write_same - queue a write same operation - * @bdev: target blockdev - * @sector: start sector - * @nr_sects: number of sectors to write - * @gfp_mask: memory allocation flags (for bio_alloc) - * @page: page containing data to write - * - * Description: - * Issue a write same request for the sectors in question. - */ -int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, - sector_t nr_sects, gfp_t gfp_mask, - struct page *page) -{ - struct request_queue *q = bdev_get_queue(bdev); - unsigned int max_write_same_sectors; - struct bio *bio = NULL; - int ret = 0; - sector_t bs_mask; - - if (!q) - return -ENXIO; - - bs_mask = (bdev_logical_block_size(bdev) >> 9) - 1; - if ((sector | nr_sects) & bs_mask) - return -EINVAL; - - /* Ensure that max_write_same_sectors doesn't overflow bi_size */ - max_write_same_sectors = UINT_MAX >> 9; - - while (nr_sects) { - bio = next_bio(bio, 1, gfp_mask); - bio->bi_iter.bi_sector = sector; - bio->bi_bdev = bdev; - bio->bi_vcnt = 1; - bio->bi_io_vec->bv_page = page; - bio->bi_io_vec->bv_offset = 0; - bio->bi_io_vec->bv_len = bdev_logical_block_size(bdev); - bio_set_op_attrs(bio, REQ_OP_WRITE_SAME, 0); - - if (nr_sects > max_write_same_sectors) { - bio->bi_iter.bi_size = max_write_same_sectors << 9; - nr_sects -= max_write_same_sectors; - sector += max_write_same_sectors; - } else { - bio->bi_iter.bi_size = nr_sects << 9; - nr_sects = 0; - } - } - - if (bio) { - ret = submit_bio_wait(bio); - bio_put(bio); - } - return ret; -} -EXPORT_SYMBOL(blkdev_issue_write_same); - -/** - * blkdev_issue_zeroout - generate number of zero filed write bios - * @bdev: blockdev to issue - * @sector: start sector - * @nr_sects: number of sectors to write - * @gfp_mask: memory allocation flags (for bio_alloc) - * - * Description: - * Generate and issue number of bios with zerofiled pages. - */ - -static int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, - sector_t nr_sects, gfp_t gfp_mask) -{ - int ret; - struct bio *bio = NULL; - unsigned int sz; - sector_t bs_mask; - - bs_mask = (bdev_logical_block_size(bdev) >> 9) - 1; - if ((sector | nr_sects) & bs_mask) - return -EINVAL; - - while (nr_sects != 0) { - bio = next_bio(bio, min(nr_sects, (sector_t)BIO_MAX_PAGES), - gfp_mask); - bio->bi_iter.bi_sector = sector; - bio->bi_bdev = bdev; - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); - - while (nr_sects != 0) { - sz = min((sector_t) PAGE_SIZE >> 9 , nr_sects); - ret = bio_add_page(bio, ZERO_PAGE(0), sz << 9, 0); - nr_sects -= ret >> 9; - sector += ret >> 9; - if (ret < (sz << 9)) - break; - } - } - - if (bio) { - ret = submit_bio_wait(bio); - bio_put(bio); - return ret; - } - return 0; -} - -/** - * blkdev_issue_zeroout - zero-fill a block range - * @bdev: blockdev to write - * @sector: start sector - * @nr_sects: number of sectors to write - * @gfp_mask: memory allocation flags (for bio_alloc) - * @discard: whether to discard the block range - * - * Description: - * Zero-fill a block range. If the discard flag is set and the block - * device guarantees that subsequent READ operations to the block range - * in question will return zeroes, the blocks will be discarded. Should - * the discard request fail, if the discard flag is not set, or if - * discard_zeroes_data is not supported, this function will resort to - * zeroing the blocks manually, thus provisioning (allocating, - * anchoring) them. If the block device supports the WRITE SAME command - * blkdev_issue_zeroout() will use it to optimize the process of - * clearing the block range. Otherwise the zeroing will be performed - * using regular WRITE calls. - */ - -int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, - sector_t nr_sects, gfp_t gfp_mask, bool discard) -{ - if (discard) { - if (!blkdev_issue_discard(bdev, sector, nr_sects, gfp_mask, - BLKDEV_DISCARD_ZERO)) - return 0; - } - - if (bdev_write_same(bdev) && - blkdev_issue_write_same(bdev, sector, nr_sects, gfp_mask, - ZERO_PAGE(0)) == 0) - return 0; - - return __blkdev_issue_zeroout(bdev, sector, nr_sects, gfp_mask); -} -EXPORT_SYMBOL(blkdev_issue_zeroout); diff --git a/src/linux/block/blk-map.c b/src/linux/block/blk-map.c deleted file mode 100644 index 27fd8d9..0000000 --- a/src/linux/block/blk-map.c +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Functions related to mapping data to requests - */ -#include -#include -#include -#include -#include - -#include "blk.h" - -/* - * Append a bio to a passthrough request. Only works can be merged into - * the request based on the driver constraints. - */ -int blk_rq_append_bio(struct request *rq, struct bio *bio) -{ - if (!rq->bio) { - blk_rq_bio_prep(rq->q, rq, bio); - } else { - if (!ll_back_merge_fn(rq->q, rq, bio)) - return -EINVAL; - - rq->biotail->bi_next = bio; - rq->biotail = bio; - rq->__data_len += bio->bi_iter.bi_size; - } - - return 0; -} -EXPORT_SYMBOL(blk_rq_append_bio); - -static int __blk_rq_unmap_user(struct bio *bio) -{ - int ret = 0; - - if (bio) { - if (bio_flagged(bio, BIO_USER_MAPPED)) - bio_unmap_user(bio); - else - ret = bio_uncopy_user(bio); - } - - return ret; -} - -static int __blk_rq_map_user_iov(struct request *rq, - struct rq_map_data *map_data, struct iov_iter *iter, - gfp_t gfp_mask, bool copy) -{ - struct request_queue *q = rq->q; - struct bio *bio, *orig_bio; - int ret; - - if (copy) - bio = bio_copy_user_iov(q, map_data, iter, gfp_mask); - else - bio = bio_map_user_iov(q, iter, gfp_mask); - - if (IS_ERR(bio)) - return PTR_ERR(bio); - - if (map_data && map_data->null_mapped) - bio_set_flag(bio, BIO_NULL_MAPPED); - - iov_iter_advance(iter, bio->bi_iter.bi_size); - if (map_data) - map_data->offset += bio->bi_iter.bi_size; - - orig_bio = bio; - blk_queue_bounce(q, &bio); - - /* - * We link the bounce buffer in and could have to traverse it - * later so we have to get a ref to prevent it from being freed - */ - bio_get(bio); - - ret = blk_rq_append_bio(rq, bio); - if (ret) { - bio_endio(bio); - __blk_rq_unmap_user(orig_bio); - bio_put(bio); - return ret; - } - - return 0; -} - -/** - * blk_rq_map_user_iov - map user data to a request, for REQ_TYPE_BLOCK_PC usage - * @q: request queue where request should be inserted - * @rq: request to map data to - * @map_data: pointer to the rq_map_data holding pages (if necessary) - * @iter: iovec iterator - * @gfp_mask: memory allocation flags - * - * Description: - * Data will be mapped directly for zero copy I/O, if possible. Otherwise - * a kernel bounce buffer is used. - * - * A matching blk_rq_unmap_user() must be issued at the end of I/O, while - * still in process context. - * - * Note: The mapped bio may need to be bounced through blk_queue_bounce() - * before being submitted to the device, as pages mapped may be out of - * reach. It's the callers responsibility to make sure this happens. The - * original bio must be passed back in to blk_rq_unmap_user() for proper - * unmapping. - */ -int blk_rq_map_user_iov(struct request_queue *q, struct request *rq, - struct rq_map_data *map_data, - const struct iov_iter *iter, gfp_t gfp_mask) -{ - bool copy = false; - unsigned long align = q->dma_pad_mask | queue_dma_alignment(q); - struct bio *bio = NULL; - struct iov_iter i; - int ret; - - if (!iter_is_iovec(iter)) - goto fail; - - if (map_data) - copy = true; - else if (iov_iter_alignment(iter) & align) - copy = true; - else if (queue_virt_boundary(q)) - copy = queue_virt_boundary(q) & iov_iter_gap_alignment(iter); - - i = *iter; - do { - ret =__blk_rq_map_user_iov(rq, map_data, &i, gfp_mask, copy); - if (ret) - goto unmap_rq; - if (!bio) - bio = rq->bio; - } while (iov_iter_count(&i)); - - if (!bio_flagged(bio, BIO_USER_MAPPED)) - rq->cmd_flags |= REQ_COPY_USER; - return 0; - -unmap_rq: - __blk_rq_unmap_user(bio); -fail: - rq->bio = NULL; - return -EINVAL; -} -EXPORT_SYMBOL(blk_rq_map_user_iov); - -int blk_rq_map_user(struct request_queue *q, struct request *rq, - struct rq_map_data *map_data, void __user *ubuf, - unsigned long len, gfp_t gfp_mask) -{ - struct iovec iov; - struct iov_iter i; - int ret = import_single_range(rq_data_dir(rq), ubuf, len, &iov, &i); - - if (unlikely(ret < 0)) - return ret; - - return blk_rq_map_user_iov(q, rq, map_data, &i, gfp_mask); -} -EXPORT_SYMBOL(blk_rq_map_user); - -/** - * blk_rq_unmap_user - unmap a request with user data - * @bio: start of bio list - * - * Description: - * Unmap a rq previously mapped by blk_rq_map_user(). The caller must - * supply the original rq->bio from the blk_rq_map_user() return, since - * the I/O completion may have changed rq->bio. - */ -int blk_rq_unmap_user(struct bio *bio) -{ - struct bio *mapped_bio; - int ret = 0, ret2; - - while (bio) { - mapped_bio = bio; - if (unlikely(bio_flagged(bio, BIO_BOUNCED))) - mapped_bio = bio->bi_private; - - ret2 = __blk_rq_unmap_user(mapped_bio); - if (ret2 && !ret) - ret = ret2; - - mapped_bio = bio; - bio = bio->bi_next; - bio_put(mapped_bio); - } - - return ret; -} -EXPORT_SYMBOL(blk_rq_unmap_user); - -/** - * blk_rq_map_kern - map kernel data to a request, for REQ_TYPE_BLOCK_PC usage - * @q: request queue where request should be inserted - * @rq: request to fill - * @kbuf: the kernel buffer - * @len: length of user data - * @gfp_mask: memory allocation flags - * - * Description: - * Data will be mapped directly if possible. Otherwise a bounce - * buffer is used. Can be called multiple times to append multiple - * buffers. - */ -int blk_rq_map_kern(struct request_queue *q, struct request *rq, void *kbuf, - unsigned int len, gfp_t gfp_mask) -{ - int reading = rq_data_dir(rq) == READ; - unsigned long addr = (unsigned long) kbuf; - int do_copy = 0; - struct bio *bio; - int ret; - - if (len > (queue_max_hw_sectors(q) << 9)) - return -EINVAL; - if (!len || !kbuf) - return -EINVAL; - - do_copy = !blk_rq_aligned(q, addr, len) || object_is_on_stack(kbuf); - if (do_copy) - bio = bio_copy_kern(q, kbuf, len, gfp_mask, reading); - else - bio = bio_map_kern(q, kbuf, len, gfp_mask); - - if (IS_ERR(bio)) - return PTR_ERR(bio); - - if (!reading) - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); - - if (do_copy) - rq->cmd_flags |= REQ_COPY_USER; - - ret = blk_rq_append_bio(rq, bio); - if (unlikely(ret)) { - /* request is too big */ - bio_put(bio); - return ret; - } - - blk_queue_bounce(q, &rq->bio); - return 0; -} -EXPORT_SYMBOL(blk_rq_map_kern); diff --git a/src/linux/block/blk-merge.c b/src/linux/block/blk-merge.c deleted file mode 100644 index 2642e5f..0000000 --- a/src/linux/block/blk-merge.c +++ /dev/null @@ -1,817 +0,0 @@ -/* - * Functions related to segment and merge handling - */ -#include -#include -#include -#include -#include - -#include - -#include "blk.h" - -static struct bio *blk_bio_discard_split(struct request_queue *q, - struct bio *bio, - struct bio_set *bs, - unsigned *nsegs) -{ - unsigned int max_discard_sectors, granularity; - int alignment; - sector_t tmp; - unsigned split_sectors; - - *nsegs = 1; - - /* Zero-sector (unknown) and one-sector granularities are the same. */ - granularity = max(q->limits.discard_granularity >> 9, 1U); - - max_discard_sectors = min(q->limits.max_discard_sectors, UINT_MAX >> 9); - max_discard_sectors -= max_discard_sectors % granularity; - - if (unlikely(!max_discard_sectors)) { - /* XXX: warn */ - return NULL; - } - - if (bio_sectors(bio) <= max_discard_sectors) - return NULL; - - split_sectors = max_discard_sectors; - - /* - * If the next starting sector would be misaligned, stop the discard at - * the previous aligned sector. - */ - alignment = (q->limits.discard_alignment >> 9) % granularity; - - tmp = bio->bi_iter.bi_sector + split_sectors - alignment; - tmp = sector_div(tmp, granularity); - - if (split_sectors > tmp) - split_sectors -= tmp; - - return bio_split(bio, split_sectors, GFP_NOIO, bs); -} - -static struct bio *blk_bio_write_same_split(struct request_queue *q, - struct bio *bio, - struct bio_set *bs, - unsigned *nsegs) -{ - *nsegs = 1; - - if (!q->limits.max_write_same_sectors) - return NULL; - - if (bio_sectors(bio) <= q->limits.max_write_same_sectors) - return NULL; - - return bio_split(bio, q->limits.max_write_same_sectors, GFP_NOIO, bs); -} - -static inline unsigned get_max_io_size(struct request_queue *q, - struct bio *bio) -{ - unsigned sectors = blk_max_size_offset(q, bio->bi_iter.bi_sector); - unsigned mask = queue_logical_block_size(q) - 1; - - /* aligned to logical block size */ - sectors &= ~(mask >> 9); - - return sectors; -} - -static struct bio *blk_bio_segment_split(struct request_queue *q, - struct bio *bio, - struct bio_set *bs, - unsigned *segs) -{ - struct bio_vec bv, bvprv, *bvprvp = NULL; - struct bvec_iter iter; - unsigned seg_size = 0, nsegs = 0, sectors = 0; - unsigned front_seg_size = bio->bi_seg_front_size; - bool do_split = true; - struct bio *new = NULL; - const unsigned max_sectors = get_max_io_size(q, bio); - unsigned bvecs = 0; - - bio_for_each_segment(bv, bio, iter) { - /* - * With arbitrary bio size, the incoming bio may be very - * big. We have to split the bio into small bios so that - * each holds at most BIO_MAX_PAGES bvecs because - * bio_clone() can fail to allocate big bvecs. - * - * It should have been better to apply the limit per - * request queue in which bio_clone() is involved, - * instead of globally. The biggest blocker is the - * bio_clone() in bio bounce. - * - * If bio is splitted by this reason, we should have - * allowed to continue bios merging, but don't do - * that now for making the change simple. - * - * TODO: deal with bio bounce's bio_clone() gracefully - * and convert the global limit into per-queue limit. - */ - if (bvecs++ >= BIO_MAX_PAGES) - goto split; - - /* - * If the queue doesn't support SG gaps and adding this - * offset would create a gap, disallow it. - */ - if (bvprvp && bvec_gap_to_prev(q, bvprvp, bv.bv_offset)) - goto split; - - if (sectors + (bv.bv_len >> 9) > max_sectors) { - /* - * Consider this a new segment if we're splitting in - * the middle of this vector. - */ - if (nsegs < queue_max_segments(q) && - sectors < max_sectors) { - nsegs++; - sectors = max_sectors; - } - if (sectors) - goto split; - /* Make this single bvec as the 1st segment */ - } - - if (bvprvp && blk_queue_cluster(q)) { - if (seg_size + bv.bv_len > queue_max_segment_size(q)) - goto new_segment; - if (!BIOVEC_PHYS_MERGEABLE(bvprvp, &bv)) - goto new_segment; - if (!BIOVEC_SEG_BOUNDARY(q, bvprvp, &bv)) - goto new_segment; - - seg_size += bv.bv_len; - bvprv = bv; - bvprvp = &bvprv; - sectors += bv.bv_len >> 9; - - if (nsegs == 1 && seg_size > front_seg_size) - front_seg_size = seg_size; - continue; - } -new_segment: - if (nsegs == queue_max_segments(q)) - goto split; - - nsegs++; - bvprv = bv; - bvprvp = &bvprv; - seg_size = bv.bv_len; - sectors += bv.bv_len >> 9; - - if (nsegs == 1 && seg_size > front_seg_size) - front_seg_size = seg_size; - } - - do_split = false; -split: - *segs = nsegs; - - if (do_split) { - new = bio_split(bio, sectors, GFP_NOIO, bs); - if (new) - bio = new; - } - - bio->bi_seg_front_size = front_seg_size; - if (seg_size > bio->bi_seg_back_size) - bio->bi_seg_back_size = seg_size; - - return do_split ? new : NULL; -} - -void blk_queue_split(struct request_queue *q, struct bio **bio, - struct bio_set *bs) -{ - struct bio *split, *res; - unsigned nsegs; - - switch (bio_op(*bio)) { - case REQ_OP_DISCARD: - case REQ_OP_SECURE_ERASE: - split = blk_bio_discard_split(q, *bio, bs, &nsegs); - break; - case REQ_OP_WRITE_SAME: - split = blk_bio_write_same_split(q, *bio, bs, &nsegs); - break; - default: - split = blk_bio_segment_split(q, *bio, q->bio_split, &nsegs); - break; - } - - /* physical segments can be figured out during splitting */ - res = split ? split : *bio; - res->bi_phys_segments = nsegs; - bio_set_flag(res, BIO_SEG_VALID); - - if (split) { - /* there isn't chance to merge the splitted bio */ - split->bi_opf |= REQ_NOMERGE; - - bio_chain(split, *bio); - trace_block_split(q, split, (*bio)->bi_iter.bi_sector); - generic_make_request(*bio); - *bio = split; - } -} -EXPORT_SYMBOL(blk_queue_split); - -static unsigned int __blk_recalc_rq_segments(struct request_queue *q, - struct bio *bio, - bool no_sg_merge) -{ - struct bio_vec bv, bvprv = { NULL }; - int cluster, prev = 0; - unsigned int seg_size, nr_phys_segs; - struct bio *fbio, *bbio; - struct bvec_iter iter; - - if (!bio) - return 0; - - /* - * This should probably be returning 0, but blk_add_request_payload() - * (Christoph!!!!) - */ - if (bio_op(bio) == REQ_OP_DISCARD || bio_op(bio) == REQ_OP_SECURE_ERASE) - return 1; - - if (bio_op(bio) == REQ_OP_WRITE_SAME) - return 1; - - fbio = bio; - cluster = blk_queue_cluster(q); - seg_size = 0; - nr_phys_segs = 0; - for_each_bio(bio) { - bio_for_each_segment(bv, bio, iter) { - /* - * If SG merging is disabled, each bio vector is - * a segment - */ - if (no_sg_merge) - goto new_segment; - - if (prev && cluster) { - if (seg_size + bv.bv_len - > queue_max_segment_size(q)) - goto new_segment; - if (!BIOVEC_PHYS_MERGEABLE(&bvprv, &bv)) - goto new_segment; - if (!BIOVEC_SEG_BOUNDARY(q, &bvprv, &bv)) - goto new_segment; - - seg_size += bv.bv_len; - bvprv = bv; - continue; - } -new_segment: - if (nr_phys_segs == 1 && seg_size > - fbio->bi_seg_front_size) - fbio->bi_seg_front_size = seg_size; - - nr_phys_segs++; - bvprv = bv; - prev = 1; - seg_size = bv.bv_len; - } - bbio = bio; - } - - if (nr_phys_segs == 1 && seg_size > fbio->bi_seg_front_size) - fbio->bi_seg_front_size = seg_size; - if (seg_size > bbio->bi_seg_back_size) - bbio->bi_seg_back_size = seg_size; - - return nr_phys_segs; -} - -void blk_recalc_rq_segments(struct request *rq) -{ - bool no_sg_merge = !!test_bit(QUEUE_FLAG_NO_SG_MERGE, - &rq->q->queue_flags); - - rq->nr_phys_segments = __blk_recalc_rq_segments(rq->q, rq->bio, - no_sg_merge); -} - -void blk_recount_segments(struct request_queue *q, struct bio *bio) -{ - unsigned short seg_cnt; - - /* estimate segment number by bi_vcnt for non-cloned bio */ - if (bio_flagged(bio, BIO_CLONED)) - seg_cnt = bio_segments(bio); - else - seg_cnt = bio->bi_vcnt; - - if (test_bit(QUEUE_FLAG_NO_SG_MERGE, &q->queue_flags) && - (seg_cnt < queue_max_segments(q))) - bio->bi_phys_segments = seg_cnt; - else { - struct bio *nxt = bio->bi_next; - - bio->bi_next = NULL; - bio->bi_phys_segments = __blk_recalc_rq_segments(q, bio, false); - bio->bi_next = nxt; - } - - bio_set_flag(bio, BIO_SEG_VALID); -} -EXPORT_SYMBOL(blk_recount_segments); - -static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio, - struct bio *nxt) -{ - struct bio_vec end_bv = { NULL }, nxt_bv; - - if (!blk_queue_cluster(q)) - return 0; - - if (bio->bi_seg_back_size + nxt->bi_seg_front_size > - queue_max_segment_size(q)) - return 0; - - if (!bio_has_data(bio)) - return 1; - - bio_get_last_bvec(bio, &end_bv); - bio_get_first_bvec(nxt, &nxt_bv); - - if (!BIOVEC_PHYS_MERGEABLE(&end_bv, &nxt_bv)) - return 0; - - /* - * bio and nxt are contiguous in memory; check if the queue allows - * these two to be merged into one - */ - if (BIOVEC_SEG_BOUNDARY(q, &end_bv, &nxt_bv)) - return 1; - - return 0; -} - -static inline void -__blk_segment_map_sg(struct request_queue *q, struct bio_vec *bvec, - struct scatterlist *sglist, struct bio_vec *bvprv, - struct scatterlist **sg, int *nsegs, int *cluster) -{ - - int nbytes = bvec->bv_len; - - if (*sg && *cluster) { - if ((*sg)->length + nbytes > queue_max_segment_size(q)) - goto new_segment; - - if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec)) - goto new_segment; - if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bvec)) - goto new_segment; - - (*sg)->length += nbytes; - } else { -new_segment: - if (!*sg) - *sg = sglist; - else { - /* - * If the driver previously mapped a shorter - * list, we could see a termination bit - * prematurely unless it fully inits the sg - * table on each mapping. We KNOW that there - * must be more entries here or the driver - * would be buggy, so force clear the - * termination bit to avoid doing a full - * sg_init_table() in drivers for each command. - */ - sg_unmark_end(*sg); - *sg = sg_next(*sg); - } - - sg_set_page(*sg, bvec->bv_page, nbytes, bvec->bv_offset); - (*nsegs)++; - } - *bvprv = *bvec; -} - -static int __blk_bios_map_sg(struct request_queue *q, struct bio *bio, - struct scatterlist *sglist, - struct scatterlist **sg) -{ - struct bio_vec bvec, bvprv = { NULL }; - struct bvec_iter iter; - int nsegs, cluster; - - nsegs = 0; - cluster = blk_queue_cluster(q); - - switch (bio_op(bio)) { - case REQ_OP_DISCARD: - case REQ_OP_SECURE_ERASE: - /* - * This is a hack - drivers should be neither modifying the - * biovec, nor relying on bi_vcnt - but because of - * blk_add_request_payload(), a discard bio may or may not have - * a payload we need to set up here (thank you Christoph) and - * bi_vcnt is really the only way of telling if we need to. - */ - if (!bio->bi_vcnt) - return 0; - /* Fall through */ - case REQ_OP_WRITE_SAME: - *sg = sglist; - bvec = bio_iovec(bio); - sg_set_page(*sg, bvec.bv_page, bvec.bv_len, bvec.bv_offset); - return 1; - default: - break; - } - - for_each_bio(bio) - bio_for_each_segment(bvec, bio, iter) - __blk_segment_map_sg(q, &bvec, sglist, &bvprv, sg, - &nsegs, &cluster); - - return nsegs; -} - -/* - * map a request to scatterlist, return number of sg entries setup. Caller - * must make sure sg can hold rq->nr_phys_segments entries - */ -int blk_rq_map_sg(struct request_queue *q, struct request *rq, - struct scatterlist *sglist) -{ - struct scatterlist *sg = NULL; - int nsegs = 0; - - if (rq->bio) - nsegs = __blk_bios_map_sg(q, rq->bio, sglist, &sg); - - if (unlikely(rq->cmd_flags & REQ_COPY_USER) && - (blk_rq_bytes(rq) & q->dma_pad_mask)) { - unsigned int pad_len = - (q->dma_pad_mask & ~blk_rq_bytes(rq)) + 1; - - sg->length += pad_len; - rq->extra_len += pad_len; - } - - if (q->dma_drain_size && q->dma_drain_needed(rq)) { - if (op_is_write(req_op(rq))) - memset(q->dma_drain_buffer, 0, q->dma_drain_size); - - sg_unmark_end(sg); - sg = sg_next(sg); - sg_set_page(sg, virt_to_page(q->dma_drain_buffer), - q->dma_drain_size, - ((unsigned long)q->dma_drain_buffer) & - (PAGE_SIZE - 1)); - nsegs++; - rq->extra_len += q->dma_drain_size; - } - - if (sg) - sg_mark_end(sg); - - /* - * Something must have been wrong if the figured number of - * segment is bigger than number of req's physical segments - */ - WARN_ON(nsegs > rq->nr_phys_segments); - - return nsegs; -} -EXPORT_SYMBOL(blk_rq_map_sg); - -static inline int ll_new_hw_segment(struct request_queue *q, - struct request *req, - struct bio *bio) -{ - int nr_phys_segs = bio_phys_segments(q, bio); - - if (req->nr_phys_segments + nr_phys_segs > queue_max_segments(q)) - goto no_merge; - - if (blk_integrity_merge_bio(q, req, bio) == false) - goto no_merge; - - /* - * This will form the start of a new hw segment. Bump both - * counters. - */ - req->nr_phys_segments += nr_phys_segs; - return 1; - -no_merge: - req->cmd_flags |= REQ_NOMERGE; - if (req == q->last_merge) - q->last_merge = NULL; - return 0; -} - -int ll_back_merge_fn(struct request_queue *q, struct request *req, - struct bio *bio) -{ - if (req_gap_back_merge(req, bio)) - return 0; - if (blk_integrity_rq(req) && - integrity_req_gap_back_merge(req, bio)) - return 0; - if (blk_rq_sectors(req) + bio_sectors(bio) > - blk_rq_get_max_sectors(req, blk_rq_pos(req))) { - req->cmd_flags |= REQ_NOMERGE; - if (req == q->last_merge) - q->last_merge = NULL; - return 0; - } - if (!bio_flagged(req->biotail, BIO_SEG_VALID)) - blk_recount_segments(q, req->biotail); - if (!bio_flagged(bio, BIO_SEG_VALID)) - blk_recount_segments(q, bio); - - return ll_new_hw_segment(q, req, bio); -} - -int ll_front_merge_fn(struct request_queue *q, struct request *req, - struct bio *bio) -{ - - if (req_gap_front_merge(req, bio)) - return 0; - if (blk_integrity_rq(req) && - integrity_req_gap_front_merge(req, bio)) - return 0; - if (blk_rq_sectors(req) + bio_sectors(bio) > - blk_rq_get_max_sectors(req, bio->bi_iter.bi_sector)) { - req->cmd_flags |= REQ_NOMERGE; - if (req == q->last_merge) - q->last_merge = NULL; - return 0; - } - if (!bio_flagged(bio, BIO_SEG_VALID)) - blk_recount_segments(q, bio); - if (!bio_flagged(req->bio, BIO_SEG_VALID)) - blk_recount_segments(q, req->bio); - - return ll_new_hw_segment(q, req, bio); -} - -/* - * blk-mq uses req->special to carry normal driver per-request payload, it - * does not indicate a prepared command that we cannot merge with. - */ -static bool req_no_special_merge(struct request *req) -{ - struct request_queue *q = req->q; - - return !q->mq_ops && req->special; -} - -static int ll_merge_requests_fn(struct request_queue *q, struct request *req, - struct request *next) -{ - int total_phys_segments; - unsigned int seg_size = - req->biotail->bi_seg_back_size + next->bio->bi_seg_front_size; - - /* - * First check if the either of the requests are re-queued - * requests. Can't merge them if they are. - */ - if (req_no_special_merge(req) || req_no_special_merge(next)) - return 0; - - if (req_gap_back_merge(req, next->bio)) - return 0; - - /* - * Will it become too large? - */ - if ((blk_rq_sectors(req) + blk_rq_sectors(next)) > - blk_rq_get_max_sectors(req, blk_rq_pos(req))) - return 0; - - total_phys_segments = req->nr_phys_segments + next->nr_phys_segments; - if (blk_phys_contig_segment(q, req->biotail, next->bio)) { - if (req->nr_phys_segments == 1) - req->bio->bi_seg_front_size = seg_size; - if (next->nr_phys_segments == 1) - next->biotail->bi_seg_back_size = seg_size; - total_phys_segments--; - } - - if (total_phys_segments > queue_max_segments(q)) - return 0; - - if (blk_integrity_merge_rq(q, req, next) == false) - return 0; - - /* Merge is OK... */ - req->nr_phys_segments = total_phys_segments; - return 1; -} - -/** - * blk_rq_set_mixed_merge - mark a request as mixed merge - * @rq: request to mark as mixed merge - * - * Description: - * @rq is about to be mixed merged. Make sure the attributes - * which can be mixed are set in each bio and mark @rq as mixed - * merged. - */ -void blk_rq_set_mixed_merge(struct request *rq) -{ - unsigned int ff = rq->cmd_flags & REQ_FAILFAST_MASK; - struct bio *bio; - - if (rq->cmd_flags & REQ_MIXED_MERGE) - return; - - /* - * @rq will no longer represent mixable attributes for all the - * contained bios. It will just track those of the first one. - * Distributes the attributs to each bio. - */ - for (bio = rq->bio; bio; bio = bio->bi_next) { - WARN_ON_ONCE((bio->bi_opf & REQ_FAILFAST_MASK) && - (bio->bi_opf & REQ_FAILFAST_MASK) != ff); - bio->bi_opf |= ff; - } - rq->cmd_flags |= REQ_MIXED_MERGE; -} - -static void blk_account_io_merge(struct request *req) -{ - if (blk_do_io_stat(req)) { - struct hd_struct *part; - int cpu; - - cpu = part_stat_lock(); - part = req->part; - - part_round_stats(cpu, part); - part_dec_in_flight(part, rq_data_dir(req)); - - hd_struct_put(part); - part_stat_unlock(); - } -} - -/* - * Has to be called with the request spinlock acquired - */ -static int attempt_merge(struct request_queue *q, struct request *req, - struct request *next) -{ - if (!rq_mergeable(req) || !rq_mergeable(next)) - return 0; - - if (req_op(req) != req_op(next)) - return 0; - - /* - * not contiguous - */ - if (blk_rq_pos(req) + blk_rq_sectors(req) != blk_rq_pos(next)) - return 0; - - if (rq_data_dir(req) != rq_data_dir(next) - || req->rq_disk != next->rq_disk - || req_no_special_merge(next)) - return 0; - - if (req_op(req) == REQ_OP_WRITE_SAME && - !blk_write_same_mergeable(req->bio, next->bio)) - return 0; - - /* - * If we are allowed to merge, then append bio list - * from next to rq and release next. merge_requests_fn - * will have updated segment counts, update sector - * counts here. - */ - if (!ll_merge_requests_fn(q, req, next)) - return 0; - - /* - * If failfast settings disagree or any of the two is already - * a mixed merge, mark both as mixed before proceeding. This - * makes sure that all involved bios have mixable attributes - * set properly. - */ - if ((req->cmd_flags | next->cmd_flags) & REQ_MIXED_MERGE || - (req->cmd_flags & REQ_FAILFAST_MASK) != - (next->cmd_flags & REQ_FAILFAST_MASK)) { - blk_rq_set_mixed_merge(req); - blk_rq_set_mixed_merge(next); - } - - /* - * At this point we have either done a back merge - * or front merge. We need the smaller start_time of - * the merged requests to be the current request - * for accounting purposes. - */ - if (time_after(req->start_time, next->start_time)) - req->start_time = next->start_time; - - req->biotail->bi_next = next->bio; - req->biotail = next->biotail; - - req->__data_len += blk_rq_bytes(next); - - elv_merge_requests(q, req, next); - - /* - * 'next' is going away, so update stats accordingly - */ - blk_account_io_merge(next); - - req->ioprio = ioprio_best(req->ioprio, next->ioprio); - if (blk_rq_cpu_valid(next)) - req->cpu = next->cpu; - - /* owner-ship of bio passed from next to req */ - next->bio = NULL; - __blk_put_request(q, next); - return 1; -} - -int attempt_back_merge(struct request_queue *q, struct request *rq) -{ - struct request *next = elv_latter_request(q, rq); - - if (next) - return attempt_merge(q, rq, next); - - return 0; -} - -int attempt_front_merge(struct request_queue *q, struct request *rq) -{ - struct request *prev = elv_former_request(q, rq); - - if (prev) - return attempt_merge(q, prev, rq); - - return 0; -} - -int blk_attempt_req_merge(struct request_queue *q, struct request *rq, - struct request *next) -{ - struct elevator_queue *e = q->elevator; - - if (e->type->ops.elevator_allow_rq_merge_fn) - if (!e->type->ops.elevator_allow_rq_merge_fn(q, rq, next)) - return 0; - - return attempt_merge(q, rq, next); -} - -bool blk_rq_merge_ok(struct request *rq, struct bio *bio) -{ - if (!rq_mergeable(rq) || !bio_mergeable(bio)) - return false; - - if (req_op(rq) != bio_op(bio)) - return false; - - /* different data direction or already started, don't merge */ - if (bio_data_dir(bio) != rq_data_dir(rq)) - return false; - - /* must be same device and not a special request */ - if (rq->rq_disk != bio->bi_bdev->bd_disk || req_no_special_merge(rq)) - return false; - - /* only merge integrity protected bio into ditto rq */ - if (blk_integrity_merge_bio(rq->q, rq, bio) == false) - return false; - - /* must be using the same buffer */ - if (req_op(rq) == REQ_OP_WRITE_SAME && - !blk_write_same_mergeable(rq->bio, bio)) - return false; - - return true; -} - -int blk_try_merge(struct request *rq, struct bio *bio) -{ - if (blk_rq_pos(rq) + blk_rq_sectors(rq) == bio->bi_iter.bi_sector) - return ELEVATOR_BACK_MERGE; - else if (blk_rq_pos(rq) - bio_sectors(bio) == bio->bi_iter.bi_sector) - return ELEVATOR_FRONT_MERGE; - return ELEVATOR_NO_MERGE; -} diff --git a/src/linux/block/blk-mq-cpumap.c b/src/linux/block/blk-mq-cpumap.c deleted file mode 100644 index 19b1d9c..0000000 --- a/src/linux/block/blk-mq-cpumap.c +++ /dev/null @@ -1,105 +0,0 @@ -/* - * CPU <-> hardware queue mapping helpers - * - * Copyright (C) 2013-2014 Jens Axboe - */ -#include -#include -#include -#include -#include -#include - -#include -#include "blk.h" -#include "blk-mq.h" - -static int cpu_to_queue_index(unsigned int nr_cpus, unsigned int nr_queues, - const int cpu) -{ - return cpu * nr_queues / nr_cpus; -} - -static int get_first_sibling(unsigned int cpu) -{ - unsigned int ret; - - ret = cpumask_first(topology_sibling_cpumask(cpu)); - if (ret < nr_cpu_ids) - return ret; - - return cpu; -} - -int blk_mq_map_queues(struct blk_mq_tag_set *set) -{ - unsigned int *map = set->mq_map; - unsigned int nr_queues = set->nr_hw_queues; - const struct cpumask *online_mask = cpu_online_mask; - unsigned int i, nr_cpus, nr_uniq_cpus, queue, first_sibling; - cpumask_var_t cpus; - - if (!alloc_cpumask_var(&cpus, GFP_ATOMIC)) - return -ENOMEM; - - cpumask_clear(cpus); - nr_cpus = nr_uniq_cpus = 0; - for_each_cpu(i, online_mask) { - nr_cpus++; - first_sibling = get_first_sibling(i); - if (!cpumask_test_cpu(first_sibling, cpus)) - nr_uniq_cpus++; - cpumask_set_cpu(i, cpus); - } - - queue = 0; - for_each_possible_cpu(i) { - if (!cpumask_test_cpu(i, online_mask)) { - map[i] = 0; - continue; - } - - /* - * Easy case - we have equal or more hardware queues. Or - * there are no thread siblings to take into account. Do - * 1:1 if enough, or sequential mapping if less. - */ - if (nr_queues >= nr_cpus || nr_cpus == nr_uniq_cpus) { - map[i] = cpu_to_queue_index(nr_cpus, nr_queues, queue); - queue++; - continue; - } - - /* - * Less then nr_cpus queues, and we have some number of - * threads per cores. Map sibling threads to the same - * queue. - */ - first_sibling = get_first_sibling(i); - if (first_sibling == i) { - map[i] = cpu_to_queue_index(nr_uniq_cpus, nr_queues, - queue); - queue++; - } else - map[i] = map[first_sibling]; - } - - free_cpumask_var(cpus); - return 0; -} - -/* - * We have no quick way of doing reverse lookups. This is only used at - * queue init time, so runtime isn't important. - */ -int blk_mq_hw_queue_to_node(unsigned int *mq_map, unsigned int index) -{ - int i; - - for_each_possible_cpu(i) { - if (index == mq_map[i]) - return local_memory_node(cpu_to_node(i)); - } - - return NUMA_NO_NODE; -} diff --git a/src/linux/block/blk-mq-sysfs.c b/src/linux/block/blk-mq-sysfs.c deleted file mode 100644 index 01fb455..0000000 --- a/src/linux/block/blk-mq-sysfs.c +++ /dev/null @@ -1,504 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "blk-mq.h" -#include "blk-mq-tag.h" - -static void blk_mq_sysfs_release(struct kobject *kobj) -{ -} - -struct blk_mq_ctx_sysfs_entry { - struct attribute attr; - ssize_t (*show)(struct blk_mq_ctx *, char *); - ssize_t (*store)(struct blk_mq_ctx *, const char *, size_t); -}; - -struct blk_mq_hw_ctx_sysfs_entry { - struct attribute attr; - ssize_t (*show)(struct blk_mq_hw_ctx *, char *); - ssize_t (*store)(struct blk_mq_hw_ctx *, const char *, size_t); -}; - -static ssize_t blk_mq_sysfs_show(struct kobject *kobj, struct attribute *attr, - char *page) -{ - struct blk_mq_ctx_sysfs_entry *entry; - struct blk_mq_ctx *ctx; - struct request_queue *q; - ssize_t res; - - entry = container_of(attr, struct blk_mq_ctx_sysfs_entry, attr); - ctx = container_of(kobj, struct blk_mq_ctx, kobj); - q = ctx->queue; - - if (!entry->show) - return -EIO; - - res = -ENOENT; - mutex_lock(&q->sysfs_lock); - if (!blk_queue_dying(q)) - res = entry->show(ctx, page); - mutex_unlock(&q->sysfs_lock); - return res; -} - -static ssize_t blk_mq_sysfs_store(struct kobject *kobj, struct attribute *attr, - const char *page, size_t length) -{ - struct blk_mq_ctx_sysfs_entry *entry; - struct blk_mq_ctx *ctx; - struct request_queue *q; - ssize_t res; - - entry = container_of(attr, struct blk_mq_ctx_sysfs_entry, attr); - ctx = container_of(kobj, struct blk_mq_ctx, kobj); - q = ctx->queue; - - if (!entry->store) - return -EIO; - - res = -ENOENT; - mutex_lock(&q->sysfs_lock); - if (!blk_queue_dying(q)) - res = entry->store(ctx, page, length); - mutex_unlock(&q->sysfs_lock); - return res; -} - -static ssize_t blk_mq_hw_sysfs_show(struct kobject *kobj, - struct attribute *attr, char *page) -{ - struct blk_mq_hw_ctx_sysfs_entry *entry; - struct blk_mq_hw_ctx *hctx; - struct request_queue *q; - ssize_t res; - - entry = container_of(attr, struct blk_mq_hw_ctx_sysfs_entry, attr); - hctx = container_of(kobj, struct blk_mq_hw_ctx, kobj); - q = hctx->queue; - - if (!entry->show) - return -EIO; - - res = -ENOENT; - mutex_lock(&q->sysfs_lock); - if (!blk_queue_dying(q)) - res = entry->show(hctx, page); - mutex_unlock(&q->sysfs_lock); - return res; -} - -static ssize_t blk_mq_hw_sysfs_store(struct kobject *kobj, - struct attribute *attr, const char *page, - size_t length) -{ - struct blk_mq_hw_ctx_sysfs_entry *entry; - struct blk_mq_hw_ctx *hctx; - struct request_queue *q; - ssize_t res; - - entry = container_of(attr, struct blk_mq_hw_ctx_sysfs_entry, attr); - hctx = container_of(kobj, struct blk_mq_hw_ctx, kobj); - q = hctx->queue; - - if (!entry->store) - return -EIO; - - res = -ENOENT; - mutex_lock(&q->sysfs_lock); - if (!blk_queue_dying(q)) - res = entry->store(hctx, page, length); - mutex_unlock(&q->sysfs_lock); - return res; -} - -static ssize_t blk_mq_sysfs_dispatched_show(struct blk_mq_ctx *ctx, char *page) -{ - return sprintf(page, "%lu %lu\n", ctx->rq_dispatched[1], - ctx->rq_dispatched[0]); -} - -static ssize_t blk_mq_sysfs_merged_show(struct blk_mq_ctx *ctx, char *page) -{ - return sprintf(page, "%lu\n", ctx->rq_merged); -} - -static ssize_t blk_mq_sysfs_completed_show(struct blk_mq_ctx *ctx, char *page) -{ - return sprintf(page, "%lu %lu\n", ctx->rq_completed[1], - ctx->rq_completed[0]); -} - -static ssize_t sysfs_list_show(char *page, struct list_head *list, char *msg) -{ - struct request *rq; - int len = snprintf(page, PAGE_SIZE - 1, "%s:\n", msg); - - list_for_each_entry(rq, list, queuelist) { - const int rq_len = 2 * sizeof(rq) + 2; - - /* if the output will be truncated */ - if (PAGE_SIZE - 1 < len + rq_len) { - /* backspacing if it can't hold '\t...\n' */ - if (PAGE_SIZE - 1 < len + 5) - len -= rq_len; - len += snprintf(page + len, PAGE_SIZE - 1 - len, - "\t...\n"); - break; - } - len += snprintf(page + len, PAGE_SIZE - 1 - len, - "\t%p\n", rq); - } - - return len; -} - -static ssize_t blk_mq_sysfs_rq_list_show(struct blk_mq_ctx *ctx, char *page) -{ - ssize_t ret; - - spin_lock(&ctx->lock); - ret = sysfs_list_show(page, &ctx->rq_list, "CTX pending"); - spin_unlock(&ctx->lock); - - return ret; -} - -static ssize_t blk_mq_hw_sysfs_poll_show(struct blk_mq_hw_ctx *hctx, char *page) -{ - return sprintf(page, "considered=%lu, invoked=%lu, success=%lu\n", - hctx->poll_considered, hctx->poll_invoked, - hctx->poll_success); -} - -static ssize_t blk_mq_hw_sysfs_poll_store(struct blk_mq_hw_ctx *hctx, - const char *page, size_t size) -{ - hctx->poll_considered = hctx->poll_invoked = hctx->poll_success = 0; - - return size; -} - -static ssize_t blk_mq_hw_sysfs_queued_show(struct blk_mq_hw_ctx *hctx, - char *page) -{ - return sprintf(page, "%lu\n", hctx->queued); -} - -static ssize_t blk_mq_hw_sysfs_run_show(struct blk_mq_hw_ctx *hctx, char *page) -{ - return sprintf(page, "%lu\n", hctx->run); -} - -static ssize_t blk_mq_hw_sysfs_dispatched_show(struct blk_mq_hw_ctx *hctx, - char *page) -{ - char *start_page = page; - int i; - - page += sprintf(page, "%8u\t%lu\n", 0U, hctx->dispatched[0]); - - for (i = 1; i < BLK_MQ_MAX_DISPATCH_ORDER - 1; i++) { - unsigned int d = 1U << (i - 1); - - page += sprintf(page, "%8u\t%lu\n", d, hctx->dispatched[i]); - } - - page += sprintf(page, "%8u+\t%lu\n", 1U << (i - 1), - hctx->dispatched[i]); - return page - start_page; -} - -static ssize_t blk_mq_hw_sysfs_rq_list_show(struct blk_mq_hw_ctx *hctx, - char *page) -{ - ssize_t ret; - - spin_lock(&hctx->lock); - ret = sysfs_list_show(page, &hctx->dispatch, "HCTX pending"); - spin_unlock(&hctx->lock); - - return ret; -} - -static ssize_t blk_mq_hw_sysfs_tags_show(struct blk_mq_hw_ctx *hctx, char *page) -{ - return blk_mq_tag_sysfs_show(hctx->tags, page); -} - -static ssize_t blk_mq_hw_sysfs_active_show(struct blk_mq_hw_ctx *hctx, char *page) -{ - return sprintf(page, "%u\n", atomic_read(&hctx->nr_active)); -} - -static ssize_t blk_mq_hw_sysfs_cpus_show(struct blk_mq_hw_ctx *hctx, char *page) -{ - unsigned int i, first = 1; - ssize_t ret = 0; - - for_each_cpu(i, hctx->cpumask) { - if (first) - ret += sprintf(ret + page, "%u", i); - else - ret += sprintf(ret + page, ", %u", i); - - first = 0; - } - - ret += sprintf(ret + page, "\n"); - return ret; -} - -static struct blk_mq_ctx_sysfs_entry blk_mq_sysfs_dispatched = { - .attr = {.name = "dispatched", .mode = S_IRUGO }, - .show = blk_mq_sysfs_dispatched_show, -}; -static struct blk_mq_ctx_sysfs_entry blk_mq_sysfs_merged = { - .attr = {.name = "merged", .mode = S_IRUGO }, - .show = blk_mq_sysfs_merged_show, -}; -static struct blk_mq_ctx_sysfs_entry blk_mq_sysfs_completed = { - .attr = {.name = "completed", .mode = S_IRUGO }, - .show = blk_mq_sysfs_completed_show, -}; -static struct blk_mq_ctx_sysfs_entry blk_mq_sysfs_rq_list = { - .attr = {.name = "rq_list", .mode = S_IRUGO }, - .show = blk_mq_sysfs_rq_list_show, -}; - -static struct attribute *default_ctx_attrs[] = { - &blk_mq_sysfs_dispatched.attr, - &blk_mq_sysfs_merged.attr, - &blk_mq_sysfs_completed.attr, - &blk_mq_sysfs_rq_list.attr, - NULL, -}; - -static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_queued = { - .attr = {.name = "queued", .mode = S_IRUGO }, - .show = blk_mq_hw_sysfs_queued_show, -}; -static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_run = { - .attr = {.name = "run", .mode = S_IRUGO }, - .show = blk_mq_hw_sysfs_run_show, -}; -static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_dispatched = { - .attr = {.name = "dispatched", .mode = S_IRUGO }, - .show = blk_mq_hw_sysfs_dispatched_show, -}; -static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_active = { - .attr = {.name = "active", .mode = S_IRUGO }, - .show = blk_mq_hw_sysfs_active_show, -}; -static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_pending = { - .attr = {.name = "pending", .mode = S_IRUGO }, - .show = blk_mq_hw_sysfs_rq_list_show, -}; -static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_tags = { - .attr = {.name = "tags", .mode = S_IRUGO }, - .show = blk_mq_hw_sysfs_tags_show, -}; -static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_cpus = { - .attr = {.name = "cpu_list", .mode = S_IRUGO }, - .show = blk_mq_hw_sysfs_cpus_show, -}; -static struct blk_mq_hw_ctx_sysfs_entry blk_mq_hw_sysfs_poll = { - .attr = {.name = "io_poll", .mode = S_IWUSR | S_IRUGO }, - .show = blk_mq_hw_sysfs_poll_show, - .store = blk_mq_hw_sysfs_poll_store, -}; - -static struct attribute *default_hw_ctx_attrs[] = { - &blk_mq_hw_sysfs_queued.attr, - &blk_mq_hw_sysfs_run.attr, - &blk_mq_hw_sysfs_dispatched.attr, - &blk_mq_hw_sysfs_pending.attr, - &blk_mq_hw_sysfs_tags.attr, - &blk_mq_hw_sysfs_cpus.attr, - &blk_mq_hw_sysfs_active.attr, - &blk_mq_hw_sysfs_poll.attr, - NULL, -}; - -static const struct sysfs_ops blk_mq_sysfs_ops = { - .show = blk_mq_sysfs_show, - .store = blk_mq_sysfs_store, -}; - -static const struct sysfs_ops blk_mq_hw_sysfs_ops = { - .show = blk_mq_hw_sysfs_show, - .store = blk_mq_hw_sysfs_store, -}; - -static struct kobj_type blk_mq_ktype = { - .sysfs_ops = &blk_mq_sysfs_ops, - .release = blk_mq_sysfs_release, -}; - -static struct kobj_type blk_mq_ctx_ktype = { - .sysfs_ops = &blk_mq_sysfs_ops, - .default_attrs = default_ctx_attrs, - .release = blk_mq_sysfs_release, -}; - -static struct kobj_type blk_mq_hw_ktype = { - .sysfs_ops = &blk_mq_hw_sysfs_ops, - .default_attrs = default_hw_ctx_attrs, - .release = blk_mq_sysfs_release, -}; - -static void blk_mq_unregister_hctx(struct blk_mq_hw_ctx *hctx) -{ - struct blk_mq_ctx *ctx; - int i; - - if (!hctx->nr_ctx) - return; - - hctx_for_each_ctx(hctx, ctx, i) - kobject_del(&ctx->kobj); - - kobject_del(&hctx->kobj); -} - -static int blk_mq_register_hctx(struct blk_mq_hw_ctx *hctx) -{ - struct request_queue *q = hctx->queue; - struct blk_mq_ctx *ctx; - int i, ret; - - if (!hctx->nr_ctx) - return 0; - - ret = kobject_add(&hctx->kobj, &q->mq_kobj, "%u", hctx->queue_num); - if (ret) - return ret; - - hctx_for_each_ctx(hctx, ctx, i) { - ret = kobject_add(&ctx->kobj, &hctx->kobj, "cpu%u", ctx->cpu); - if (ret) - break; - } - - return ret; -} - -static void __blk_mq_unregister_dev(struct device *dev, struct request_queue *q) -{ - struct blk_mq_hw_ctx *hctx; - struct blk_mq_ctx *ctx; - int i, j; - - queue_for_each_hw_ctx(q, hctx, i) { - blk_mq_unregister_hctx(hctx); - - hctx_for_each_ctx(hctx, ctx, j) - kobject_put(&ctx->kobj); - - kobject_put(&hctx->kobj); - } - - kobject_uevent(&q->mq_kobj, KOBJ_REMOVE); - kobject_del(&q->mq_kobj); - kobject_put(&q->mq_kobj); - - kobject_put(&dev->kobj); - - q->mq_sysfs_init_done = false; -} - -void blk_mq_unregister_dev(struct device *dev, struct request_queue *q) -{ - blk_mq_disable_hotplug(); - __blk_mq_unregister_dev(dev, q); - blk_mq_enable_hotplug(); -} - -void blk_mq_hctx_kobj_init(struct blk_mq_hw_ctx *hctx) -{ - kobject_init(&hctx->kobj, &blk_mq_hw_ktype); -} - -static void blk_mq_sysfs_init(struct request_queue *q) -{ - struct blk_mq_ctx *ctx; - int cpu; - - kobject_init(&q->mq_kobj, &blk_mq_ktype); - - for_each_possible_cpu(cpu) { - ctx = per_cpu_ptr(q->queue_ctx, cpu); - kobject_init(&ctx->kobj, &blk_mq_ctx_ktype); - } -} - -int blk_mq_register_dev(struct device *dev, struct request_queue *q) -{ - struct blk_mq_hw_ctx *hctx; - int ret, i; - - blk_mq_disable_hotplug(); - - blk_mq_sysfs_init(q); - - ret = kobject_add(&q->mq_kobj, kobject_get(&dev->kobj), "%s", "mq"); - if (ret < 0) - goto out; - - kobject_uevent(&q->mq_kobj, KOBJ_ADD); - - queue_for_each_hw_ctx(q, hctx, i) { - ret = blk_mq_register_hctx(hctx); - if (ret) - break; - } - - if (ret) - __blk_mq_unregister_dev(dev, q); - else - q->mq_sysfs_init_done = true; -out: - blk_mq_enable_hotplug(); - - return ret; -} -EXPORT_SYMBOL_GPL(blk_mq_register_dev); - -void blk_mq_sysfs_unregister(struct request_queue *q) -{ - struct blk_mq_hw_ctx *hctx; - int i; - - if (!q->mq_sysfs_init_done) - return; - - queue_for_each_hw_ctx(q, hctx, i) - blk_mq_unregister_hctx(hctx); -} - -int blk_mq_sysfs_register(struct request_queue *q) -{ - struct blk_mq_hw_ctx *hctx; - int i, ret = 0; - - if (!q->mq_sysfs_init_done) - return ret; - - queue_for_each_hw_ctx(q, hctx, i) { - ret = blk_mq_register_hctx(hctx); - if (ret) - break; - } - - return ret; -} diff --git a/src/linux/block/blk-mq-tag.c b/src/linux/block/blk-mq-tag.c deleted file mode 100644 index dcf5ce3..0000000 --- a/src/linux/block/blk-mq-tag.c +++ /dev/null @@ -1,478 +0,0 @@ -/* - * Tag allocation using scalable bitmaps. Uses active queue tracking to support - * fairer distribution of tags between multiple submitters when a shared tag map - * is used. - * - * Copyright (C) 2013-2014 Jens Axboe - */ -#include -#include - -#include -#include "blk.h" -#include "blk-mq.h" -#include "blk-mq-tag.h" - -bool blk_mq_has_free_tags(struct blk_mq_tags *tags) -{ - if (!tags) - return true; - - return sbitmap_any_bit_clear(&tags->bitmap_tags.sb); -} - -/* - * If a previously inactive queue goes active, bump the active user count. - */ -bool __blk_mq_tag_busy(struct blk_mq_hw_ctx *hctx) -{ - if (!test_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state) && - !test_and_set_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state)) - atomic_inc(&hctx->tags->active_queues); - - return true; -} - -/* - * Wakeup all potentially sleeping on tags - */ -void blk_mq_tag_wakeup_all(struct blk_mq_tags *tags, bool include_reserve) -{ - sbitmap_queue_wake_all(&tags->bitmap_tags); - if (include_reserve) - sbitmap_queue_wake_all(&tags->breserved_tags); -} - -/* - * If a previously busy queue goes inactive, potential waiters could now - * be allowed to queue. Wake them up and check. - */ -void __blk_mq_tag_idle(struct blk_mq_hw_ctx *hctx) -{ - struct blk_mq_tags *tags = hctx->tags; - - if (!test_and_clear_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state)) - return; - - atomic_dec(&tags->active_queues); - - blk_mq_tag_wakeup_all(tags, false); -} - -/* - * For shared tag users, we track the number of currently active users - * and attempt to provide a fair share of the tag depth for each of them. - */ -static inline bool hctx_may_queue(struct blk_mq_hw_ctx *hctx, - struct sbitmap_queue *bt) -{ - unsigned int depth, users; - - if (!hctx || !(hctx->flags & BLK_MQ_F_TAG_SHARED)) - return true; - if (!test_bit(BLK_MQ_S_TAG_ACTIVE, &hctx->state)) - return true; - - /* - * Don't try dividing an ant - */ - if (bt->sb.depth == 1) - return true; - - users = atomic_read(&hctx->tags->active_queues); - if (!users) - return true; - - /* - * Allow at least some tags - */ - depth = max((bt->sb.depth + users - 1) / users, 4U); - return atomic_read(&hctx->nr_active) < depth; -} - -static int __bt_get(struct blk_mq_hw_ctx *hctx, struct sbitmap_queue *bt) -{ - if (!hctx_may_queue(hctx, bt)) - return -1; - return __sbitmap_queue_get(bt); -} - -static int bt_get(struct blk_mq_alloc_data *data, struct sbitmap_queue *bt, - struct blk_mq_hw_ctx *hctx, struct blk_mq_tags *tags) -{ - struct sbq_wait_state *ws; - DEFINE_WAIT(wait); - int tag; - - tag = __bt_get(hctx, bt); - if (tag != -1) - return tag; - - if (data->flags & BLK_MQ_REQ_NOWAIT) - return -1; - - ws = bt_wait_ptr(bt, hctx); - do { - prepare_to_wait(&ws->wait, &wait, TASK_UNINTERRUPTIBLE); - - tag = __bt_get(hctx, bt); - if (tag != -1) - break; - - /* - * We're out of tags on this hardware queue, kick any - * pending IO submits before going to sleep waiting for - * some to complete. Note that hctx can be NULL here for - * reserved tag allocation. - */ - if (hctx) - blk_mq_run_hw_queue(hctx, false); - - /* - * Retry tag allocation after running the hardware queue, - * as running the queue may also have found completions. - */ - tag = __bt_get(hctx, bt); - if (tag != -1) - break; - - blk_mq_put_ctx(data->ctx); - - io_schedule(); - - data->ctx = blk_mq_get_ctx(data->q); - data->hctx = blk_mq_map_queue(data->q, data->ctx->cpu); - if (data->flags & BLK_MQ_REQ_RESERVED) { - bt = &data->hctx->tags->breserved_tags; - } else { - hctx = data->hctx; - bt = &hctx->tags->bitmap_tags; - } - finish_wait(&ws->wait, &wait); - ws = bt_wait_ptr(bt, hctx); - } while (1); - - finish_wait(&ws->wait, &wait); - return tag; -} - -static unsigned int __blk_mq_get_tag(struct blk_mq_alloc_data *data) -{ - int tag; - - tag = bt_get(data, &data->hctx->tags->bitmap_tags, data->hctx, - data->hctx->tags); - if (tag >= 0) - return tag + data->hctx->tags->nr_reserved_tags; - - return BLK_MQ_TAG_FAIL; -} - -static unsigned int __blk_mq_get_reserved_tag(struct blk_mq_alloc_data *data) -{ - int tag; - - if (unlikely(!data->hctx->tags->nr_reserved_tags)) { - WARN_ON_ONCE(1); - return BLK_MQ_TAG_FAIL; - } - - tag = bt_get(data, &data->hctx->tags->breserved_tags, NULL, - data->hctx->tags); - if (tag < 0) - return BLK_MQ_TAG_FAIL; - - return tag; -} - -unsigned int blk_mq_get_tag(struct blk_mq_alloc_data *data) -{ - if (data->flags & BLK_MQ_REQ_RESERVED) - return __blk_mq_get_reserved_tag(data); - return __blk_mq_get_tag(data); -} - -void blk_mq_put_tag(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx, - unsigned int tag) -{ - struct blk_mq_tags *tags = hctx->tags; - - if (tag >= tags->nr_reserved_tags) { - const int real_tag = tag - tags->nr_reserved_tags; - - BUG_ON(real_tag >= tags->nr_tags); - sbitmap_queue_clear(&tags->bitmap_tags, real_tag, ctx->cpu); - } else { - BUG_ON(tag >= tags->nr_reserved_tags); - sbitmap_queue_clear(&tags->breserved_tags, tag, ctx->cpu); - } -} - -struct bt_iter_data { - struct blk_mq_hw_ctx *hctx; - busy_iter_fn *fn; - void *data; - bool reserved; -}; - -static bool bt_iter(struct sbitmap *bitmap, unsigned int bitnr, void *data) -{ - struct bt_iter_data *iter_data = data; - struct blk_mq_hw_ctx *hctx = iter_data->hctx; - struct blk_mq_tags *tags = hctx->tags; - bool reserved = iter_data->reserved; - struct request *rq; - - if (!reserved) - bitnr += tags->nr_reserved_tags; - rq = tags->rqs[bitnr]; - - if (rq->q == hctx->queue) - iter_data->fn(hctx, rq, iter_data->data, reserved); - return true; -} - -static void bt_for_each(struct blk_mq_hw_ctx *hctx, struct sbitmap_queue *bt, - busy_iter_fn *fn, void *data, bool reserved) -{ - struct bt_iter_data iter_data = { - .hctx = hctx, - .fn = fn, - .data = data, - .reserved = reserved, - }; - - sbitmap_for_each_set(&bt->sb, bt_iter, &iter_data); -} - -struct bt_tags_iter_data { - struct blk_mq_tags *tags; - busy_tag_iter_fn *fn; - void *data; - bool reserved; -}; - -static bool bt_tags_iter(struct sbitmap *bitmap, unsigned int bitnr, void *data) -{ - struct bt_tags_iter_data *iter_data = data; - struct blk_mq_tags *tags = iter_data->tags; - bool reserved = iter_data->reserved; - struct request *rq; - - if (!reserved) - bitnr += tags->nr_reserved_tags; - rq = tags->rqs[bitnr]; - - iter_data->fn(rq, iter_data->data, reserved); - return true; -} - -static void bt_tags_for_each(struct blk_mq_tags *tags, struct sbitmap_queue *bt, - busy_tag_iter_fn *fn, void *data, bool reserved) -{ - struct bt_tags_iter_data iter_data = { - .tags = tags, - .fn = fn, - .data = data, - .reserved = reserved, - }; - - if (tags->rqs) - sbitmap_for_each_set(&bt->sb, bt_tags_iter, &iter_data); -} - -static void blk_mq_all_tag_busy_iter(struct blk_mq_tags *tags, - busy_tag_iter_fn *fn, void *priv) -{ - if (tags->nr_reserved_tags) - bt_tags_for_each(tags, &tags->breserved_tags, fn, priv, true); - bt_tags_for_each(tags, &tags->bitmap_tags, fn, priv, false); -} - -void blk_mq_tagset_busy_iter(struct blk_mq_tag_set *tagset, - busy_tag_iter_fn *fn, void *priv) -{ - int i; - - for (i = 0; i < tagset->nr_hw_queues; i++) { - if (tagset->tags && tagset->tags[i]) - blk_mq_all_tag_busy_iter(tagset->tags[i], fn, priv); - } -} -EXPORT_SYMBOL(blk_mq_tagset_busy_iter); - -int blk_mq_reinit_tagset(struct blk_mq_tag_set *set) -{ - int i, j, ret = 0; - - if (!set->ops->reinit_request) - goto out; - - for (i = 0; i < set->nr_hw_queues; i++) { - struct blk_mq_tags *tags = set->tags[i]; - - for (j = 0; j < tags->nr_tags; j++) { - if (!tags->rqs[j]) - continue; - - ret = set->ops->reinit_request(set->driver_data, - tags->rqs[j]); - if (ret) - goto out; - } - } - -out: - return ret; -} -EXPORT_SYMBOL_GPL(blk_mq_reinit_tagset); - -void blk_mq_queue_tag_busy_iter(struct request_queue *q, busy_iter_fn *fn, - void *priv) -{ - struct blk_mq_hw_ctx *hctx; - int i; - - - queue_for_each_hw_ctx(q, hctx, i) { - struct blk_mq_tags *tags = hctx->tags; - - /* - * If not software queues are currently mapped to this - * hardware queue, there's nothing to check - */ - if (!blk_mq_hw_queue_mapped(hctx)) - continue; - - if (tags->nr_reserved_tags) - bt_for_each(hctx, &tags->breserved_tags, fn, priv, true); - bt_for_each(hctx, &tags->bitmap_tags, fn, priv, false); - } - -} - -static unsigned int bt_unused_tags(const struct sbitmap_queue *bt) -{ - return bt->sb.depth - sbitmap_weight(&bt->sb); -} - -static int bt_alloc(struct sbitmap_queue *bt, unsigned int depth, - bool round_robin, int node) -{ - return sbitmap_queue_init_node(bt, depth, -1, round_robin, GFP_KERNEL, - node); -} - -static struct blk_mq_tags *blk_mq_init_bitmap_tags(struct blk_mq_tags *tags, - int node, int alloc_policy) -{ - unsigned int depth = tags->nr_tags - tags->nr_reserved_tags; - bool round_robin = alloc_policy == BLK_TAG_ALLOC_RR; - - if (bt_alloc(&tags->bitmap_tags, depth, round_robin, node)) - goto free_tags; - if (bt_alloc(&tags->breserved_tags, tags->nr_reserved_tags, round_robin, - node)) - goto free_bitmap_tags; - - return tags; -free_bitmap_tags: - sbitmap_queue_free(&tags->bitmap_tags); -free_tags: - kfree(tags); - return NULL; -} - -struct blk_mq_tags *blk_mq_init_tags(unsigned int total_tags, - unsigned int reserved_tags, - int node, int alloc_policy) -{ - struct blk_mq_tags *tags; - - if (total_tags > BLK_MQ_TAG_MAX) { - pr_err("blk-mq: tag depth too large\n"); - return NULL; - } - - tags = kzalloc_node(sizeof(*tags), GFP_KERNEL, node); - if (!tags) - return NULL; - - tags->nr_tags = total_tags; - tags->nr_reserved_tags = reserved_tags; - - return blk_mq_init_bitmap_tags(tags, node, alloc_policy); -} - -void blk_mq_free_tags(struct blk_mq_tags *tags) -{ - sbitmap_queue_free(&tags->bitmap_tags); - sbitmap_queue_free(&tags->breserved_tags); - kfree(tags); -} - -int blk_mq_tag_update_depth(struct blk_mq_tags *tags, unsigned int tdepth) -{ - tdepth -= tags->nr_reserved_tags; - if (tdepth > tags->nr_tags) - return -EINVAL; - - /* - * Don't need (or can't) update reserved tags here, they remain - * static and should never need resizing. - */ - sbitmap_queue_resize(&tags->bitmap_tags, tdepth); - - blk_mq_tag_wakeup_all(tags, false); - return 0; -} - -/** - * blk_mq_unique_tag() - return a tag that is unique queue-wide - * @rq: request for which to compute a unique tag - * - * The tag field in struct request is unique per hardware queue but not over - * all hardware queues. Hence this function that returns a tag with the - * hardware context index in the upper bits and the per hardware queue tag in - * the lower bits. - * - * Note: When called for a request that is queued on a non-multiqueue request - * queue, the hardware context index is set to zero. - */ -u32 blk_mq_unique_tag(struct request *rq) -{ - struct request_queue *q = rq->q; - struct blk_mq_hw_ctx *hctx; - int hwq = 0; - - if (q->mq_ops) { - hctx = blk_mq_map_queue(q, rq->mq_ctx->cpu); - hwq = hctx->queue_num; - } - - return (hwq << BLK_MQ_UNIQUE_TAG_BITS) | - (rq->tag & BLK_MQ_UNIQUE_TAG_MASK); -} -EXPORT_SYMBOL(blk_mq_unique_tag); - -ssize_t blk_mq_tag_sysfs_show(struct blk_mq_tags *tags, char *page) -{ - char *orig_page = page; - unsigned int free, res; - - if (!tags) - return 0; - - page += sprintf(page, "nr_tags=%u, reserved_tags=%u, " - "bits_per_word=%u\n", - tags->nr_tags, tags->nr_reserved_tags, - 1U << tags->bitmap_tags.sb.shift); - - free = bt_unused_tags(&tags->bitmap_tags); - res = bt_unused_tags(&tags->breserved_tags); - - page += sprintf(page, "nr_free=%u, nr_reserved=%u\n", free, res); - page += sprintf(page, "active_queues=%u\n", atomic_read(&tags->active_queues)); - - return page - orig_page; -} diff --git a/src/linux/block/blk-mq-tag.h b/src/linux/block/blk-mq-tag.h deleted file mode 100644 index d166273..0000000 --- a/src/linux/block/blk-mq-tag.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef INT_BLK_MQ_TAG_H -#define INT_BLK_MQ_TAG_H - -#include "blk-mq.h" - -/* - * Tag address space map. - */ -struct blk_mq_tags { - unsigned int nr_tags; - unsigned int nr_reserved_tags; - - atomic_t active_queues; - - struct sbitmap_queue bitmap_tags; - struct sbitmap_queue breserved_tags; - - struct request **rqs; - struct list_head page_list; -}; - - -extern struct blk_mq_tags *blk_mq_init_tags(unsigned int nr_tags, unsigned int reserved_tags, int node, int alloc_policy); -extern void blk_mq_free_tags(struct blk_mq_tags *tags); - -extern unsigned int blk_mq_get_tag(struct blk_mq_alloc_data *data); -extern void blk_mq_put_tag(struct blk_mq_hw_ctx *hctx, struct blk_mq_ctx *ctx, - unsigned int tag); -extern bool blk_mq_has_free_tags(struct blk_mq_tags *tags); -extern ssize_t blk_mq_tag_sysfs_show(struct blk_mq_tags *tags, char *page); -extern int blk_mq_tag_update_depth(struct blk_mq_tags *tags, unsigned int depth); -extern void blk_mq_tag_wakeup_all(struct blk_mq_tags *tags, bool); -void blk_mq_queue_tag_busy_iter(struct request_queue *q, busy_iter_fn *fn, - void *priv); - -static inline struct sbq_wait_state *bt_wait_ptr(struct sbitmap_queue *bt, - struct blk_mq_hw_ctx *hctx) -{ - if (!hctx) - return &bt->ws[0]; - return sbq_wait_ptr(bt, &hctx->wait_index); -} - -enum { - BLK_MQ_TAG_CACHE_MIN = 1, - BLK_MQ_TAG_CACHE_MAX = 64, -}; - -enum { - BLK_MQ_TAG_FAIL = -1U, - BLK_MQ_TAG_MIN = BLK_MQ_TAG_CACHE_MIN, - BLK_MQ_TAG_MAX = BLK_MQ_TAG_FAIL - 1, -}; - -extern bool __blk_mq_tag_busy(struct blk_mq_hw_ctx *); -extern void __blk_mq_tag_idle(struct blk_mq_hw_ctx *); - -static inline bool blk_mq_tag_busy(struct blk_mq_hw_ctx *hctx) -{ - if (!(hctx->flags & BLK_MQ_F_TAG_SHARED)) - return false; - - return __blk_mq_tag_busy(hctx); -} - -static inline void blk_mq_tag_idle(struct blk_mq_hw_ctx *hctx) -{ - if (!(hctx->flags & BLK_MQ_F_TAG_SHARED)) - return; - - __blk_mq_tag_idle(hctx); -} - -/* - * This helper should only be used for flush request to share tag - * with the request cloned from, and both the two requests can't be - * in flight at the same time. The caller has to make sure the tag - * can't be freed. - */ -static inline void blk_mq_tag_set_rq(struct blk_mq_hw_ctx *hctx, - unsigned int tag, struct request *rq) -{ - hctx->tags->rqs[tag] = rq; -} - -#endif diff --git a/src/linux/block/blk-mq.c b/src/linux/block/blk-mq.c deleted file mode 100644 index f3d27a6..0000000 --- a/src/linux/block/blk-mq.c +++ /dev/null @@ -1,2376 +0,0 @@ -/* - * Block multiqueue core code - * - * Copyright (C) 2013-2014 Jens Axboe - * Copyright (C) 2013-2014 Christoph Hellwig - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include "blk.h" -#include "blk-mq.h" -#include "blk-mq-tag.h" - -static DEFINE_MUTEX(all_q_mutex); -static LIST_HEAD(all_q_list); - -/* - * Check if any of the ctx's have pending work in this hardware queue - */ -static bool blk_mq_hctx_has_pending(struct blk_mq_hw_ctx *hctx) -{ - return sbitmap_any_bit_set(&hctx->ctx_map); -} - -/* - * Mark this ctx as having pending work in this hardware queue - */ -static void blk_mq_hctx_mark_pending(struct blk_mq_hw_ctx *hctx, - struct blk_mq_ctx *ctx) -{ - if (!sbitmap_test_bit(&hctx->ctx_map, ctx->index_hw)) - sbitmap_set_bit(&hctx->ctx_map, ctx->index_hw); -} - -static void blk_mq_hctx_clear_pending(struct blk_mq_hw_ctx *hctx, - struct blk_mq_ctx *ctx) -{ - sbitmap_clear_bit(&hctx->ctx_map, ctx->index_hw); -} - -void blk_mq_freeze_queue_start(struct request_queue *q) -{ - int freeze_depth; - - freeze_depth = atomic_inc_return(&q->mq_freeze_depth); - if (freeze_depth == 1) { - percpu_ref_kill(&q->q_usage_counter); - blk_mq_run_hw_queues(q, false); - } -} -EXPORT_SYMBOL_GPL(blk_mq_freeze_queue_start); - -static void blk_mq_freeze_queue_wait(struct request_queue *q) -{ - wait_event(q->mq_freeze_wq, percpu_ref_is_zero(&q->q_usage_counter)); -} - -/* - * Guarantee no request is in use, so we can change any data structure of - * the queue afterward. - */ -void blk_freeze_queue(struct request_queue *q) -{ - /* - * In the !blk_mq case we are only calling this to kill the - * q_usage_counter, otherwise this increases the freeze depth - * and waits for it to return to zero. For this reason there is - * no blk_unfreeze_queue(), and blk_freeze_queue() is not - * exported to drivers as the only user for unfreeze is blk_mq. - */ - blk_mq_freeze_queue_start(q); - blk_mq_freeze_queue_wait(q); -} - -void blk_mq_freeze_queue(struct request_queue *q) -{ - /* - * ...just an alias to keep freeze and unfreeze actions balanced - * in the blk_mq_* namespace - */ - blk_freeze_queue(q); -} -EXPORT_SYMBOL_GPL(blk_mq_freeze_queue); - -void blk_mq_unfreeze_queue(struct request_queue *q) -{ - int freeze_depth; - - freeze_depth = atomic_dec_return(&q->mq_freeze_depth); - WARN_ON_ONCE(freeze_depth < 0); - if (!freeze_depth) { - percpu_ref_reinit(&q->q_usage_counter); - wake_up_all(&q->mq_freeze_wq); - } -} -EXPORT_SYMBOL_GPL(blk_mq_unfreeze_queue); - -void blk_mq_wake_waiters(struct request_queue *q) -{ - struct blk_mq_hw_ctx *hctx; - unsigned int i; - - queue_for_each_hw_ctx(q, hctx, i) - if (blk_mq_hw_queue_mapped(hctx)) - blk_mq_tag_wakeup_all(hctx->tags, true); - - /* - * If we are called because the queue has now been marked as - * dying, we need to ensure that processes currently waiting on - * the queue are notified as well. - */ - wake_up_all(&q->mq_freeze_wq); -} - -bool blk_mq_can_queue(struct blk_mq_hw_ctx *hctx) -{ - return blk_mq_has_free_tags(hctx->tags); -} -EXPORT_SYMBOL(blk_mq_can_queue); - -static void blk_mq_rq_ctx_init(struct request_queue *q, struct blk_mq_ctx *ctx, - struct request *rq, int op, - unsigned int op_flags) -{ - if (blk_queue_io_stat(q)) - op_flags |= REQ_IO_STAT; - - INIT_LIST_HEAD(&rq->queuelist); - /* csd/requeue_work/fifo_time is initialized before use */ - rq->q = q; - rq->mq_ctx = ctx; - req_set_op_attrs(rq, op, op_flags); - /* do not touch atomic flags, it needs atomic ops against the timer */ - rq->cpu = -1; - INIT_HLIST_NODE(&rq->hash); - RB_CLEAR_NODE(&rq->rb_node); - rq->rq_disk = NULL; - rq->part = NULL; - rq->start_time = jiffies; -#ifdef CONFIG_BLK_CGROUP - rq->rl = NULL; - set_start_time_ns(rq); - rq->io_start_time_ns = 0; -#endif - rq->nr_phys_segments = 0; -#if defined(CONFIG_BLK_DEV_INTEGRITY) - rq->nr_integrity_segments = 0; -#endif - rq->special = NULL; - /* tag was already set */ - rq->errors = 0; - - rq->cmd = rq->__cmd; - - rq->extra_len = 0; - rq->sense_len = 0; - rq->resid_len = 0; - rq->sense = NULL; - - INIT_LIST_HEAD(&rq->timeout_list); - rq->timeout = 0; - - rq->end_io = NULL; - rq->end_io_data = NULL; - rq->next_rq = NULL; - - ctx->rq_dispatched[rw_is_sync(op, op_flags)]++; -} - -static struct request * -__blk_mq_alloc_request(struct blk_mq_alloc_data *data, int op, int op_flags) -{ - struct request *rq; - unsigned int tag; - - tag = blk_mq_get_tag(data); - if (tag != BLK_MQ_TAG_FAIL) { - rq = data->hctx->tags->rqs[tag]; - - if (blk_mq_tag_busy(data->hctx)) { - rq->cmd_flags = REQ_MQ_INFLIGHT; - atomic_inc(&data->hctx->nr_active); - } - - rq->tag = tag; - blk_mq_rq_ctx_init(data->q, data->ctx, rq, op, op_flags); - return rq; - } - - return NULL; -} - -struct request *blk_mq_alloc_request(struct request_queue *q, int rw, - unsigned int flags) -{ - struct blk_mq_ctx *ctx; - struct blk_mq_hw_ctx *hctx; - struct request *rq; - struct blk_mq_alloc_data alloc_data; - int ret; - - ret = blk_queue_enter(q, flags & BLK_MQ_REQ_NOWAIT); - if (ret) - return ERR_PTR(ret); - - ctx = blk_mq_get_ctx(q); - hctx = blk_mq_map_queue(q, ctx->cpu); - blk_mq_set_alloc_data(&alloc_data, q, flags, ctx, hctx); - rq = __blk_mq_alloc_request(&alloc_data, rw, 0); - blk_mq_put_ctx(ctx); - - if (!rq) { - blk_queue_exit(q); - return ERR_PTR(-EWOULDBLOCK); - } - - rq->__data_len = 0; - rq->__sector = (sector_t) -1; - rq->bio = rq->biotail = NULL; - return rq; -} -EXPORT_SYMBOL(blk_mq_alloc_request); - -struct request *blk_mq_alloc_request_hctx(struct request_queue *q, int rw, - unsigned int flags, unsigned int hctx_idx) -{ - struct blk_mq_hw_ctx *hctx; - struct blk_mq_ctx *ctx; - struct request *rq; - struct blk_mq_alloc_data alloc_data; - int ret; - - /* - * If the tag allocator sleeps we could get an allocation for a - * different hardware context. No need to complicate the low level - * allocator for this for the rare use case of a command tied to - * a specific queue. - */ - if (WARN_ON_ONCE(!(flags & BLK_MQ_REQ_NOWAIT))) - return ERR_PTR(-EINVAL); - - if (hctx_idx >= q->nr_hw_queues) - return ERR_PTR(-EIO); - - ret = blk_queue_enter(q, true); - if (ret) - return ERR_PTR(ret); - - /* - * Check if the hardware context is actually mapped to anything. - * If not tell the caller that it should skip this queue. - */ - hctx = q->queue_hw_ctx[hctx_idx]; - if (!blk_mq_hw_queue_mapped(hctx)) { - ret = -EXDEV; - goto out_queue_exit; - } - ctx = __blk_mq_get_ctx(q, cpumask_first(hctx->cpumask)); - - blk_mq_set_alloc_data(&alloc_data, q, flags, ctx, hctx); - rq = __blk_mq_alloc_request(&alloc_data, rw, 0); - if (!rq) { - ret = -EWOULDBLOCK; - goto out_queue_exit; - } - - return rq; - -out_queue_exit: - blk_queue_exit(q); - return ERR_PTR(ret); -} -EXPORT_SYMBOL_GPL(blk_mq_alloc_request_hctx); - -static void __blk_mq_free_request(struct blk_mq_hw_ctx *hctx, - struct blk_mq_ctx *ctx, struct request *rq) -{ - const int tag = rq->tag; - struct request_queue *q = rq->q; - - if (rq->cmd_flags & REQ_MQ_INFLIGHT) - atomic_dec(&hctx->nr_active); - rq->cmd_flags = 0; - - clear_bit(REQ_ATOM_STARTED, &rq->atomic_flags); - blk_mq_put_tag(hctx, ctx, tag); - blk_queue_exit(q); -} - -void blk_mq_free_hctx_request(struct blk_mq_hw_ctx *hctx, struct request *rq) -{ - struct blk_mq_ctx *ctx = rq->mq_ctx; - - ctx->rq_completed[rq_is_sync(rq)]++; - __blk_mq_free_request(hctx, ctx, rq); - -} -EXPORT_SYMBOL_GPL(blk_mq_free_hctx_request); - -void blk_mq_free_request(struct request *rq) -{ - blk_mq_free_hctx_request(blk_mq_map_queue(rq->q, rq->mq_ctx->cpu), rq); -} -EXPORT_SYMBOL_GPL(blk_mq_free_request); - -inline void __blk_mq_end_request(struct request *rq, int error) -{ - blk_account_io_done(rq); - - if (rq->end_io) { - rq->end_io(rq, error); - } else { - if (unlikely(blk_bidi_rq(rq))) - blk_mq_free_request(rq->next_rq); - blk_mq_free_request(rq); - } -} -EXPORT_SYMBOL(__blk_mq_end_request); - -void blk_mq_end_request(struct request *rq, int error) -{ - if (blk_update_request(rq, error, blk_rq_bytes(rq))) - BUG(); - __blk_mq_end_request(rq, error); -} -EXPORT_SYMBOL(blk_mq_end_request); - -static void __blk_mq_complete_request_remote(void *data) -{ - struct request *rq = data; - - rq->q->softirq_done_fn(rq); -} - -static void blk_mq_ipi_complete_request(struct request *rq) -{ - struct blk_mq_ctx *ctx = rq->mq_ctx; - bool shared = false; - int cpu; - - if (!test_bit(QUEUE_FLAG_SAME_COMP, &rq->q->queue_flags)) { - rq->q->softirq_done_fn(rq); - return; - } - - cpu = get_cpu(); - if (!test_bit(QUEUE_FLAG_SAME_FORCE, &rq->q->queue_flags)) - shared = cpus_share_cache(cpu, ctx->cpu); - - if (cpu != ctx->cpu && !shared && cpu_online(ctx->cpu)) { - rq->csd.func = __blk_mq_complete_request_remote; - rq->csd.info = rq; - rq->csd.flags = 0; - smp_call_function_single_async(ctx->cpu, &rq->csd); - } else { - rq->q->softirq_done_fn(rq); - } - put_cpu(); -} - -static void __blk_mq_complete_request(struct request *rq) -{ - struct request_queue *q = rq->q; - - if (!q->softirq_done_fn) - blk_mq_end_request(rq, rq->errors); - else - blk_mq_ipi_complete_request(rq); -} - -/** - * blk_mq_complete_request - end I/O on a request - * @rq: the request being processed - * - * Description: - * Ends all I/O on a request. It does not handle partial completions. - * The actual completion happens out-of-order, through a IPI handler. - **/ -void blk_mq_complete_request(struct request *rq, int error) -{ - struct request_queue *q = rq->q; - - if (unlikely(blk_should_fake_timeout(q))) - return; - if (!blk_mark_rq_complete(rq)) { - rq->errors = error; - __blk_mq_complete_request(rq); - } -} -EXPORT_SYMBOL(blk_mq_complete_request); - -int blk_mq_request_started(struct request *rq) -{ - return test_bit(REQ_ATOM_STARTED, &rq->atomic_flags); -} -EXPORT_SYMBOL_GPL(blk_mq_request_started); - -void blk_mq_start_request(struct request *rq) -{ - struct request_queue *q = rq->q; - - trace_block_rq_issue(q, rq); - - rq->resid_len = blk_rq_bytes(rq); - if (unlikely(blk_bidi_rq(rq))) - rq->next_rq->resid_len = blk_rq_bytes(rq->next_rq); - - blk_add_timer(rq); - - /* - * Ensure that ->deadline is visible before set the started - * flag and clear the completed flag. - */ - smp_mb__before_atomic(); - - /* - * Mark us as started and clear complete. Complete might have been - * set if requeue raced with timeout, which then marked it as - * complete. So be sure to clear complete again when we start - * the request, otherwise we'll ignore the completion event. - */ - if (!test_bit(REQ_ATOM_STARTED, &rq->atomic_flags)) - set_bit(REQ_ATOM_STARTED, &rq->atomic_flags); - if (test_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags)) - clear_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags); - - if (q->dma_drain_size && blk_rq_bytes(rq)) { - /* - * Make sure space for the drain appears. We know we can do - * this because max_hw_segments has been adjusted to be one - * fewer than the device can handle. - */ - rq->nr_phys_segments++; - } -} -EXPORT_SYMBOL(blk_mq_start_request); - -static void __blk_mq_requeue_request(struct request *rq) -{ - struct request_queue *q = rq->q; - - trace_block_rq_requeue(q, rq); - - if (test_and_clear_bit(REQ_ATOM_STARTED, &rq->atomic_flags)) { - if (q->dma_drain_size && blk_rq_bytes(rq)) - rq->nr_phys_segments--; - } -} - -void blk_mq_requeue_request(struct request *rq) -{ - __blk_mq_requeue_request(rq); - - BUG_ON(blk_queued_rq(rq)); - blk_mq_add_to_requeue_list(rq, true); -} -EXPORT_SYMBOL(blk_mq_requeue_request); - -static void blk_mq_requeue_work(struct work_struct *work) -{ - struct request_queue *q = - container_of(work, struct request_queue, requeue_work.work); - LIST_HEAD(rq_list); - struct request *rq, *next; - unsigned long flags; - - spin_lock_irqsave(&q->requeue_lock, flags); - list_splice_init(&q->requeue_list, &rq_list); - spin_unlock_irqrestore(&q->requeue_lock, flags); - - list_for_each_entry_safe(rq, next, &rq_list, queuelist) { - if (!(rq->cmd_flags & REQ_SOFTBARRIER)) - continue; - - rq->cmd_flags &= ~REQ_SOFTBARRIER; - list_del_init(&rq->queuelist); - blk_mq_insert_request(rq, true, false, false); - } - - while (!list_empty(&rq_list)) { - rq = list_entry(rq_list.next, struct request, queuelist); - list_del_init(&rq->queuelist); - blk_mq_insert_request(rq, false, false, false); - } - - /* - * Use the start variant of queue running here, so that running - * the requeue work will kick stopped queues. - */ - blk_mq_start_hw_queues(q); -} - -void blk_mq_add_to_requeue_list(struct request *rq, bool at_head) -{ - struct request_queue *q = rq->q; - unsigned long flags; - - /* - * We abuse this flag that is otherwise used by the I/O scheduler to - * request head insertation from the workqueue. - */ - BUG_ON(rq->cmd_flags & REQ_SOFTBARRIER); - - spin_lock_irqsave(&q->requeue_lock, flags); - if (at_head) { - rq->cmd_flags |= REQ_SOFTBARRIER; - list_add(&rq->queuelist, &q->requeue_list); - } else { - list_add_tail(&rq->queuelist, &q->requeue_list); - } - spin_unlock_irqrestore(&q->requeue_lock, flags); -} -EXPORT_SYMBOL(blk_mq_add_to_requeue_list); - -void blk_mq_cancel_requeue_work(struct request_queue *q) -{ - cancel_delayed_work_sync(&q->requeue_work); -} -EXPORT_SYMBOL_GPL(blk_mq_cancel_requeue_work); - -void blk_mq_kick_requeue_list(struct request_queue *q) -{ - kblockd_schedule_delayed_work(&q->requeue_work, 0); -} -EXPORT_SYMBOL(blk_mq_kick_requeue_list); - -void blk_mq_delay_kick_requeue_list(struct request_queue *q, - unsigned long msecs) -{ - kblockd_schedule_delayed_work(&q->requeue_work, - msecs_to_jiffies(msecs)); -} -EXPORT_SYMBOL(blk_mq_delay_kick_requeue_list); - -void blk_mq_abort_requeue_list(struct request_queue *q) -{ - unsigned long flags; - LIST_HEAD(rq_list); - - spin_lock_irqsave(&q->requeue_lock, flags); - list_splice_init(&q->requeue_list, &rq_list); - spin_unlock_irqrestore(&q->requeue_lock, flags); - - while (!list_empty(&rq_list)) { - struct request *rq; - - rq = list_first_entry(&rq_list, struct request, queuelist); - list_del_init(&rq->queuelist); - rq->errors = -EIO; - blk_mq_end_request(rq, rq->errors); - } -} -EXPORT_SYMBOL(blk_mq_abort_requeue_list); - -struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag) -{ - if (tag < tags->nr_tags) { - prefetch(tags->rqs[tag]); - return tags->rqs[tag]; - } - - return NULL; -} -EXPORT_SYMBOL(blk_mq_tag_to_rq); - -struct blk_mq_timeout_data { - unsigned long next; - unsigned int next_set; -}; - -void blk_mq_rq_timed_out(struct request *req, bool reserved) -{ - struct blk_mq_ops *ops = req->q->mq_ops; - enum blk_eh_timer_return ret = BLK_EH_RESET_TIMER; - - /* - * We know that complete is set at this point. If STARTED isn't set - * anymore, then the request isn't active and the "timeout" should - * just be ignored. This can happen due to the bitflag ordering. - * Timeout first checks if STARTED is set, and if it is, assumes - * the request is active. But if we race with completion, then - * we both flags will get cleared. So check here again, and ignore - * a timeout event with a request that isn't active. - */ - if (!test_bit(REQ_ATOM_STARTED, &req->atomic_flags)) - return; - - if (ops->timeout) - ret = ops->timeout(req, reserved); - - switch (ret) { - case BLK_EH_HANDLED: - __blk_mq_complete_request(req); - break; - case BLK_EH_RESET_TIMER: - blk_add_timer(req); - blk_clear_rq_complete(req); - break; - case BLK_EH_NOT_HANDLED: - break; - default: - printk(KERN_ERR "block: bad eh return: %d\n", ret); - break; - } -} - -static void blk_mq_check_expired(struct blk_mq_hw_ctx *hctx, - struct request *rq, void *priv, bool reserved) -{ - struct blk_mq_timeout_data *data = priv; - - if (!test_bit(REQ_ATOM_STARTED, &rq->atomic_flags)) { - /* - * If a request wasn't started before the queue was - * marked dying, kill it here or it'll go unnoticed. - */ - if (unlikely(blk_queue_dying(rq->q))) { - rq->errors = -EIO; - blk_mq_end_request(rq, rq->errors); - } - return; - } - - if (time_after_eq(jiffies, rq->deadline)) { - if (!blk_mark_rq_complete(rq)) - blk_mq_rq_timed_out(rq, reserved); - } else if (!data->next_set || time_after(data->next, rq->deadline)) { - data->next = rq->deadline; - data->next_set = 1; - } -} - -static void blk_mq_timeout_work(struct work_struct *work) -{ - struct request_queue *q = - container_of(work, struct request_queue, timeout_work); - struct blk_mq_timeout_data data = { - .next = 0, - .next_set = 0, - }; - int i; - - /* A deadlock might occur if a request is stuck requiring a - * timeout at the same time a queue freeze is waiting - * completion, since the timeout code would not be able to - * acquire the queue reference here. - * - * That's why we don't use blk_queue_enter here; instead, we use - * percpu_ref_tryget directly, because we need to be able to - * obtain a reference even in the short window between the queue - * starting to freeze, by dropping the first reference in - * blk_mq_freeze_queue_start, and the moment the last request is - * consumed, marked by the instant q_usage_counter reaches - * zero. - */ - if (!percpu_ref_tryget(&q->q_usage_counter)) - return; - - blk_mq_queue_tag_busy_iter(q, blk_mq_check_expired, &data); - - if (data.next_set) { - data.next = blk_rq_timeout(round_jiffies_up(data.next)); - mod_timer(&q->timeout, data.next); - } else { - struct blk_mq_hw_ctx *hctx; - - queue_for_each_hw_ctx(q, hctx, i) { - /* the hctx may be unmapped, so check it here */ - if (blk_mq_hw_queue_mapped(hctx)) - blk_mq_tag_idle(hctx); - } - } - blk_queue_exit(q); -} - -/* - * Reverse check our software queue for entries that we could potentially - * merge with. Currently includes a hand-wavy stop count of 8, to not spend - * too much time checking for merges. - */ -static bool blk_mq_attempt_merge(struct request_queue *q, - struct blk_mq_ctx *ctx, struct bio *bio) -{ - struct request *rq; - int checked = 8; - - list_for_each_entry_reverse(rq, &ctx->rq_list, queuelist) { - int el_ret; - - if (!checked--) - break; - - if (!blk_rq_merge_ok(rq, bio)) - continue; - - el_ret = blk_try_merge(rq, bio); - if (el_ret == ELEVATOR_BACK_MERGE) { - if (bio_attempt_back_merge(q, rq, bio)) { - ctx->rq_merged++; - return true; - } - break; - } else if (el_ret == ELEVATOR_FRONT_MERGE) { - if (bio_attempt_front_merge(q, rq, bio)) { - ctx->rq_merged++; - return true; - } - break; - } - } - - return false; -} - -struct flush_busy_ctx_data { - struct blk_mq_hw_ctx *hctx; - struct list_head *list; -}; - -static bool flush_busy_ctx(struct sbitmap *sb, unsigned int bitnr, void *data) -{ - struct flush_busy_ctx_data *flush_data = data; - struct blk_mq_hw_ctx *hctx = flush_data->hctx; - struct blk_mq_ctx *ctx = hctx->ctxs[bitnr]; - - sbitmap_clear_bit(sb, bitnr); - spin_lock(&ctx->lock); - list_splice_tail_init(&ctx->rq_list, flush_data->list); - spin_unlock(&ctx->lock); - return true; -} - -/* - * Process software queues that have been marked busy, splicing them - * to the for-dispatch - */ -static void flush_busy_ctxs(struct blk_mq_hw_ctx *hctx, struct list_head *list) -{ - struct flush_busy_ctx_data data = { - .hctx = hctx, - .list = list, - }; - - sbitmap_for_each_set(&hctx->ctx_map, flush_busy_ctx, &data); -} - -static inline unsigned int queued_to_index(unsigned int queued) -{ - if (!queued) - return 0; - - return min(BLK_MQ_MAX_DISPATCH_ORDER - 1, ilog2(queued) + 1); -} - -/* - * Run this hardware queue, pulling any software queues mapped to it in. - * Note that this function currently has various problems around ordering - * of IO. In particular, we'd like FIFO behaviour on handling existing - * items on the hctx->dispatch list. Ignore that for now. - */ -static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx) -{ - struct request_queue *q = hctx->queue; - struct request *rq; - LIST_HEAD(rq_list); - LIST_HEAD(driver_list); - struct list_head *dptr; - int queued; - - if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->state))) - return; - - WARN_ON(!cpumask_test_cpu(raw_smp_processor_id(), hctx->cpumask) && - cpu_online(hctx->next_cpu)); - - hctx->run++; - - /* - * Touch any software queue that has pending entries. - */ - flush_busy_ctxs(hctx, &rq_list); - - /* - * If we have previous entries on our dispatch list, grab them - * and stuff them at the front for more fair dispatch. - */ - if (!list_empty_careful(&hctx->dispatch)) { - spin_lock(&hctx->lock); - if (!list_empty(&hctx->dispatch)) - list_splice_init(&hctx->dispatch, &rq_list); - spin_unlock(&hctx->lock); - } - - /* - * Start off with dptr being NULL, so we start the first request - * immediately, even if we have more pending. - */ - dptr = NULL; - - /* - * Now process all the entries, sending them to the driver. - */ - queued = 0; - while (!list_empty(&rq_list)) { - struct blk_mq_queue_data bd; - int ret; - - rq = list_first_entry(&rq_list, struct request, queuelist); - list_del_init(&rq->queuelist); - - bd.rq = rq; - bd.list = dptr; - bd.last = list_empty(&rq_list); - - ret = q->mq_ops->queue_rq(hctx, &bd); - switch (ret) { - case BLK_MQ_RQ_QUEUE_OK: - queued++; - break; - case BLK_MQ_RQ_QUEUE_BUSY: - list_add(&rq->queuelist, &rq_list); - __blk_mq_requeue_request(rq); - break; - default: - pr_err("blk-mq: bad return on queue: %d\n", ret); - case BLK_MQ_RQ_QUEUE_ERROR: - rq->errors = -EIO; - blk_mq_end_request(rq, rq->errors); - break; - } - - if (ret == BLK_MQ_RQ_QUEUE_BUSY) - break; - - /* - * We've done the first request. If we have more than 1 - * left in the list, set dptr to defer issue. - */ - if (!dptr && rq_list.next != rq_list.prev) - dptr = &driver_list; - } - - hctx->dispatched[queued_to_index(queued)]++; - - /* - * Any items that need requeuing? Stuff them into hctx->dispatch, - * that is where we will continue on next queue run. - */ - if (!list_empty(&rq_list)) { - spin_lock(&hctx->lock); - list_splice(&rq_list, &hctx->dispatch); - spin_unlock(&hctx->lock); - /* - * the queue is expected stopped with BLK_MQ_RQ_QUEUE_BUSY, but - * it's possible the queue is stopped and restarted again - * before this. Queue restart will dispatch requests. And since - * requests in rq_list aren't added into hctx->dispatch yet, - * the requests in rq_list might get lost. - * - * blk_mq_run_hw_queue() already checks the STOPPED bit - **/ - blk_mq_run_hw_queue(hctx, true); - } -} - -/* - * It'd be great if the workqueue API had a way to pass - * in a mask and had some smarts for more clever placement. - * For now we just round-robin here, switching for every - * BLK_MQ_CPU_WORK_BATCH queued items. - */ -static int blk_mq_hctx_next_cpu(struct blk_mq_hw_ctx *hctx) -{ - if (hctx->queue->nr_hw_queues == 1) - return WORK_CPU_UNBOUND; - - if (--hctx->next_cpu_batch <= 0) { - int cpu = hctx->next_cpu, next_cpu; - - next_cpu = cpumask_next(hctx->next_cpu, hctx->cpumask); - if (next_cpu >= nr_cpu_ids) - next_cpu = cpumask_first(hctx->cpumask); - - hctx->next_cpu = next_cpu; - hctx->next_cpu_batch = BLK_MQ_CPU_WORK_BATCH; - - return cpu; - } - - return hctx->next_cpu; -} - -void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async) -{ - if (unlikely(test_bit(BLK_MQ_S_STOPPED, &hctx->state) || - !blk_mq_hw_queue_mapped(hctx))) - return; - - if (!async && !(hctx->flags & BLK_MQ_F_BLOCKING)) { - int cpu = get_cpu(); - if (cpumask_test_cpu(cpu, hctx->cpumask)) { - __blk_mq_run_hw_queue(hctx); - put_cpu(); - return; - } - - put_cpu(); - } - - kblockd_schedule_work_on(blk_mq_hctx_next_cpu(hctx), &hctx->run_work); -} - -void blk_mq_run_hw_queues(struct request_queue *q, bool async) -{ - struct blk_mq_hw_ctx *hctx; - int i; - - queue_for_each_hw_ctx(q, hctx, i) { - if ((!blk_mq_hctx_has_pending(hctx) && - list_empty_careful(&hctx->dispatch)) || - test_bit(BLK_MQ_S_STOPPED, &hctx->state)) - continue; - - blk_mq_run_hw_queue(hctx, async); - } -} -EXPORT_SYMBOL(blk_mq_run_hw_queues); - -void blk_mq_stop_hw_queue(struct blk_mq_hw_ctx *hctx) -{ - cancel_work(&hctx->run_work); - cancel_delayed_work(&hctx->delay_work); - set_bit(BLK_MQ_S_STOPPED, &hctx->state); -} -EXPORT_SYMBOL(blk_mq_stop_hw_queue); - -void blk_mq_stop_hw_queues(struct request_queue *q) -{ - struct blk_mq_hw_ctx *hctx; - int i; - - queue_for_each_hw_ctx(q, hctx, i) - blk_mq_stop_hw_queue(hctx); -} -EXPORT_SYMBOL(blk_mq_stop_hw_queues); - -void blk_mq_start_hw_queue(struct blk_mq_hw_ctx *hctx) -{ - clear_bit(BLK_MQ_S_STOPPED, &hctx->state); - - blk_mq_run_hw_queue(hctx, false); -} -EXPORT_SYMBOL(blk_mq_start_hw_queue); - -void blk_mq_start_hw_queues(struct request_queue *q) -{ - struct blk_mq_hw_ctx *hctx; - int i; - - queue_for_each_hw_ctx(q, hctx, i) - blk_mq_start_hw_queue(hctx); -} -EXPORT_SYMBOL(blk_mq_start_hw_queues); - -void blk_mq_start_stopped_hw_queues(struct request_queue *q, bool async) -{ - struct blk_mq_hw_ctx *hctx; - int i; - - queue_for_each_hw_ctx(q, hctx, i) { - if (!test_bit(BLK_MQ_S_STOPPED, &hctx->state)) - continue; - - clear_bit(BLK_MQ_S_STOPPED, &hctx->state); - blk_mq_run_hw_queue(hctx, async); - } -} -EXPORT_SYMBOL(blk_mq_start_stopped_hw_queues); - -static void blk_mq_run_work_fn(struct work_struct *work) -{ - struct blk_mq_hw_ctx *hctx; - - hctx = container_of(work, struct blk_mq_hw_ctx, run_work); - - __blk_mq_run_hw_queue(hctx); -} - -static void blk_mq_delay_work_fn(struct work_struct *work) -{ - struct blk_mq_hw_ctx *hctx; - - hctx = container_of(work, struct blk_mq_hw_ctx, delay_work.work); - - if (test_and_clear_bit(BLK_MQ_S_STOPPED, &hctx->state)) - __blk_mq_run_hw_queue(hctx); -} - -void blk_mq_delay_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs) -{ - if (unlikely(!blk_mq_hw_queue_mapped(hctx))) - return; - - kblockd_schedule_delayed_work_on(blk_mq_hctx_next_cpu(hctx), - &hctx->delay_work, msecs_to_jiffies(msecs)); -} -EXPORT_SYMBOL(blk_mq_delay_queue); - -static inline void __blk_mq_insert_req_list(struct blk_mq_hw_ctx *hctx, - struct request *rq, - bool at_head) -{ - struct blk_mq_ctx *ctx = rq->mq_ctx; - - trace_block_rq_insert(hctx->queue, rq); - - if (at_head) - list_add(&rq->queuelist, &ctx->rq_list); - else - list_add_tail(&rq->queuelist, &ctx->rq_list); -} - -static void __blk_mq_insert_request(struct blk_mq_hw_ctx *hctx, - struct request *rq, bool at_head) -{ - struct blk_mq_ctx *ctx = rq->mq_ctx; - - __blk_mq_insert_req_list(hctx, rq, at_head); - blk_mq_hctx_mark_pending(hctx, ctx); -} - -void blk_mq_insert_request(struct request *rq, bool at_head, bool run_queue, - bool async) -{ - struct blk_mq_ctx *ctx = rq->mq_ctx; - struct request_queue *q = rq->q; - struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, ctx->cpu); - - spin_lock(&ctx->lock); - __blk_mq_insert_request(hctx, rq, at_head); - spin_unlock(&ctx->lock); - - if (run_queue) - blk_mq_run_hw_queue(hctx, async); -} - -static void blk_mq_insert_requests(struct request_queue *q, - struct blk_mq_ctx *ctx, - struct list_head *list, - int depth, - bool from_schedule) - -{ - struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, ctx->cpu); - - trace_block_unplug(q, depth, !from_schedule); - - /* - * preemption doesn't flush plug list, so it's possible ctx->cpu is - * offline now - */ - spin_lock(&ctx->lock); - while (!list_empty(list)) { - struct request *rq; - - rq = list_first_entry(list, struct request, queuelist); - BUG_ON(rq->mq_ctx != ctx); - list_del_init(&rq->queuelist); - __blk_mq_insert_req_list(hctx, rq, false); - } - blk_mq_hctx_mark_pending(hctx, ctx); - spin_unlock(&ctx->lock); - - blk_mq_run_hw_queue(hctx, from_schedule); -} - -static int plug_ctx_cmp(void *priv, struct list_head *a, struct list_head *b) -{ - struct request *rqa = container_of(a, struct request, queuelist); - struct request *rqb = container_of(b, struct request, queuelist); - - return !(rqa->mq_ctx < rqb->mq_ctx || - (rqa->mq_ctx == rqb->mq_ctx && - blk_rq_pos(rqa) < blk_rq_pos(rqb))); -} - -void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule) -{ - struct blk_mq_ctx *this_ctx; - struct request_queue *this_q; - struct request *rq; - LIST_HEAD(list); - LIST_HEAD(ctx_list); - unsigned int depth; - - list_splice_init(&plug->mq_list, &list); - - list_sort(NULL, &list, plug_ctx_cmp); - - this_q = NULL; - this_ctx = NULL; - depth = 0; - - while (!list_empty(&list)) { - rq = list_entry_rq(list.next); - list_del_init(&rq->queuelist); - BUG_ON(!rq->q); - if (rq->mq_ctx != this_ctx) { - if (this_ctx) { - blk_mq_insert_requests(this_q, this_ctx, - &ctx_list, depth, - from_schedule); - } - - this_ctx = rq->mq_ctx; - this_q = rq->q; - depth = 0; - } - - depth++; - list_add_tail(&rq->queuelist, &ctx_list); - } - - /* - * If 'this_ctx' is set, we know we have entries to complete - * on 'ctx_list'. Do those. - */ - if (this_ctx) { - blk_mq_insert_requests(this_q, this_ctx, &ctx_list, depth, - from_schedule); - } -} - -static void blk_mq_bio_to_request(struct request *rq, struct bio *bio) -{ - init_request_from_bio(rq, bio); - - blk_account_io_start(rq, 1); -} - -static inline bool hctx_allow_merges(struct blk_mq_hw_ctx *hctx) -{ - return (hctx->flags & BLK_MQ_F_SHOULD_MERGE) && - !blk_queue_nomerges(hctx->queue); -} - -static inline bool blk_mq_merge_queue_io(struct blk_mq_hw_ctx *hctx, - struct blk_mq_ctx *ctx, - struct request *rq, struct bio *bio) -{ - if (!hctx_allow_merges(hctx) || !bio_mergeable(bio)) { - blk_mq_bio_to_request(rq, bio); - spin_lock(&ctx->lock); -insert_rq: - __blk_mq_insert_request(hctx, rq, false); - spin_unlock(&ctx->lock); - return false; - } else { - struct request_queue *q = hctx->queue; - - spin_lock(&ctx->lock); - if (!blk_mq_attempt_merge(q, ctx, bio)) { - blk_mq_bio_to_request(rq, bio); - goto insert_rq; - } - - spin_unlock(&ctx->lock); - __blk_mq_free_request(hctx, ctx, rq); - return true; - } -} - -struct blk_map_ctx { - struct blk_mq_hw_ctx *hctx; - struct blk_mq_ctx *ctx; -}; - -static struct request *blk_mq_map_request(struct request_queue *q, - struct bio *bio, - struct blk_map_ctx *data) -{ - struct blk_mq_hw_ctx *hctx; - struct blk_mq_ctx *ctx; - struct request *rq; - int op = bio_data_dir(bio); - int op_flags = 0; - struct blk_mq_alloc_data alloc_data; - - blk_queue_enter_live(q); - ctx = blk_mq_get_ctx(q); - hctx = blk_mq_map_queue(q, ctx->cpu); - - if (rw_is_sync(bio_op(bio), bio->bi_opf)) - op_flags |= REQ_SYNC; - - trace_block_getrq(q, bio, op); - blk_mq_set_alloc_data(&alloc_data, q, 0, ctx, hctx); - rq = __blk_mq_alloc_request(&alloc_data, op, op_flags); - - data->hctx = alloc_data.hctx; - data->ctx = alloc_data.ctx; - data->hctx->queued++; - return rq; -} - -static int blk_mq_direct_issue_request(struct request *rq, blk_qc_t *cookie) -{ - int ret; - struct request_queue *q = rq->q; - struct blk_mq_hw_ctx *hctx = blk_mq_map_queue(q, rq->mq_ctx->cpu); - struct blk_mq_queue_data bd = { - .rq = rq, - .list = NULL, - .last = 1 - }; - blk_qc_t new_cookie = blk_tag_to_qc_t(rq->tag, hctx->queue_num); - - /* - * For OK queue, we are done. For error, kill it. Any other - * error (busy), just add it to our list as we previously - * would have done - */ - ret = q->mq_ops->queue_rq(hctx, &bd); - if (ret == BLK_MQ_RQ_QUEUE_OK) { - *cookie = new_cookie; - return 0; - } - - __blk_mq_requeue_request(rq); - - if (ret == BLK_MQ_RQ_QUEUE_ERROR) { - *cookie = BLK_QC_T_NONE; - rq->errors = -EIO; - blk_mq_end_request(rq, rq->errors); - return 0; - } - - return -1; -} - -/* - * Multiple hardware queue variant. This will not use per-process plugs, - * but will attempt to bypass the hctx queueing if we can go straight to - * hardware for SYNC IO. - */ -static blk_qc_t blk_mq_make_request(struct request_queue *q, struct bio *bio) -{ - const int is_sync = rw_is_sync(bio_op(bio), bio->bi_opf); - const int is_flush_fua = bio->bi_opf & (REQ_PREFLUSH | REQ_FUA); - struct blk_map_ctx data; - struct request *rq; - unsigned int request_count = 0; - struct blk_plug *plug; - struct request *same_queue_rq = NULL; - blk_qc_t cookie; - - blk_queue_bounce(q, &bio); - - if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) { - bio_io_error(bio); - return BLK_QC_T_NONE; - } - - blk_queue_split(q, &bio, q->bio_split); - - if (!is_flush_fua && !blk_queue_nomerges(q) && - blk_attempt_plug_merge(q, bio, &request_count, &same_queue_rq)) - return BLK_QC_T_NONE; - - rq = blk_mq_map_request(q, bio, &data); - if (unlikely(!rq)) - return BLK_QC_T_NONE; - - cookie = blk_tag_to_qc_t(rq->tag, data.hctx->queue_num); - - if (unlikely(is_flush_fua)) { - blk_mq_bio_to_request(rq, bio); - blk_insert_flush(rq); - goto run_queue; - } - - plug = current->plug; - /* - * If the driver supports defer issued based on 'last', then - * queue it up like normal since we can potentially save some - * CPU this way. - */ - if (((plug && !blk_queue_nomerges(q)) || is_sync) && - !(data.hctx->flags & BLK_MQ_F_DEFER_ISSUE)) { - struct request *old_rq = NULL; - - blk_mq_bio_to_request(rq, bio); - - /* - * We do limited pluging. If the bio can be merged, do that. - * Otherwise the existing request in the plug list will be - * issued. So the plug list will have one request at most - */ - if (plug) { - /* - * The plug list might get flushed before this. If that - * happens, same_queue_rq is invalid and plug list is - * empty - */ - if (same_queue_rq && !list_empty(&plug->mq_list)) { - old_rq = same_queue_rq; - list_del_init(&old_rq->queuelist); - } - list_add_tail(&rq->queuelist, &plug->mq_list); - } else /* is_sync */ - old_rq = rq; - blk_mq_put_ctx(data.ctx); - if (!old_rq) - goto done; - if (!blk_mq_direct_issue_request(old_rq, &cookie)) - goto done; - blk_mq_insert_request(old_rq, false, true, true); - goto done; - } - - if (!blk_mq_merge_queue_io(data.hctx, data.ctx, rq, bio)) { - /* - * For a SYNC request, send it to the hardware immediately. For - * an ASYNC request, just ensure that we run it later on. The - * latter allows for merging opportunities and more efficient - * dispatching. - */ -run_queue: - blk_mq_run_hw_queue(data.hctx, !is_sync || is_flush_fua); - } - blk_mq_put_ctx(data.ctx); -done: - return cookie; -} - -/* - * Single hardware queue variant. This will attempt to use any per-process - * plug for merging and IO deferral. - */ -static blk_qc_t blk_sq_make_request(struct request_queue *q, struct bio *bio) -{ - const int is_sync = rw_is_sync(bio_op(bio), bio->bi_opf); - const int is_flush_fua = bio->bi_opf & (REQ_PREFLUSH | REQ_FUA); - struct blk_plug *plug; - unsigned int request_count = 0; - struct blk_map_ctx data; - struct request *rq; - blk_qc_t cookie; - - blk_queue_bounce(q, &bio); - - if (bio_integrity_enabled(bio) && bio_integrity_prep(bio)) { - bio_io_error(bio); - return BLK_QC_T_NONE; - } - - blk_queue_split(q, &bio, q->bio_split); - - if (!is_flush_fua && !blk_queue_nomerges(q)) { - if (blk_attempt_plug_merge(q, bio, &request_count, NULL)) - return BLK_QC_T_NONE; - } else - request_count = blk_plug_queued_count(q); - - rq = blk_mq_map_request(q, bio, &data); - if (unlikely(!rq)) - return BLK_QC_T_NONE; - - cookie = blk_tag_to_qc_t(rq->tag, data.hctx->queue_num); - - if (unlikely(is_flush_fua)) { - blk_mq_bio_to_request(rq, bio); - blk_insert_flush(rq); - goto run_queue; - } - - /* - * A task plug currently exists. Since this is completely lockless, - * utilize that to temporarily store requests until the task is - * either done or scheduled away. - */ - plug = current->plug; - if (plug) { - blk_mq_bio_to_request(rq, bio); - if (!request_count) - trace_block_plug(q); - - blk_mq_put_ctx(data.ctx); - - if (request_count >= BLK_MAX_REQUEST_COUNT) { - blk_flush_plug_list(plug, false); - trace_block_plug(q); - } - - list_add_tail(&rq->queuelist, &plug->mq_list); - return cookie; - } - - if (!blk_mq_merge_queue_io(data.hctx, data.ctx, rq, bio)) { - /* - * For a SYNC request, send it to the hardware immediately. For - * an ASYNC request, just ensure that we run it later on. The - * latter allows for merging opportunities and more efficient - * dispatching. - */ -run_queue: - blk_mq_run_hw_queue(data.hctx, !is_sync || is_flush_fua); - } - - blk_mq_put_ctx(data.ctx); - return cookie; -} - -static void blk_mq_free_rq_map(struct blk_mq_tag_set *set, - struct blk_mq_tags *tags, unsigned int hctx_idx) -{ - struct page *page; - - if (tags->rqs && set->ops->exit_request) { - int i; - - for (i = 0; i < tags->nr_tags; i++) { - if (!tags->rqs[i]) - continue; - set->ops->exit_request(set->driver_data, tags->rqs[i], - hctx_idx, i); - tags->rqs[i] = NULL; - } - } - - while (!list_empty(&tags->page_list)) { - page = list_first_entry(&tags->page_list, struct page, lru); - list_del_init(&page->lru); - /* - * Remove kmemleak object previously allocated in - * blk_mq_init_rq_map(). - */ - kmemleak_free(page_address(page)); - __free_pages(page, page->private); - } - - kfree(tags->rqs); - - blk_mq_free_tags(tags); -} - -static size_t order_to_size(unsigned int order) -{ - return (size_t)PAGE_SIZE << order; -} - -static struct blk_mq_tags *blk_mq_init_rq_map(struct blk_mq_tag_set *set, - unsigned int hctx_idx) -{ - struct blk_mq_tags *tags; - unsigned int i, j, entries_per_page, max_order = 4; - size_t rq_size, left; - - tags = blk_mq_init_tags(set->queue_depth, set->reserved_tags, - set->numa_node, - BLK_MQ_FLAG_TO_ALLOC_POLICY(set->flags)); - if (!tags) - return NULL; - - INIT_LIST_HEAD(&tags->page_list); - - tags->rqs = kzalloc_node(set->queue_depth * sizeof(struct request *), - GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY, - set->numa_node); - if (!tags->rqs) { - blk_mq_free_tags(tags); - return NULL; - } - - /* - * rq_size is the size of the request plus driver payload, rounded - * to the cacheline size - */ - rq_size = round_up(sizeof(struct request) + set->cmd_size, - cache_line_size()); - left = rq_size * set->queue_depth; - - for (i = 0; i < set->queue_depth; ) { - int this_order = max_order; - struct page *page; - int to_do; - void *p; - - while (this_order && left < order_to_size(this_order - 1)) - this_order--; - - do { - page = alloc_pages_node(set->numa_node, - GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY | __GFP_ZERO, - this_order); - if (page) - break; - if (!this_order--) - break; - if (order_to_size(this_order) < rq_size) - break; - } while (1); - - if (!page) - goto fail; - - page->private = this_order; - list_add_tail(&page->lru, &tags->page_list); - - p = page_address(page); - /* - * Allow kmemleak to scan these pages as they contain pointers - * to additional allocations like via ops->init_request(). - */ - kmemleak_alloc(p, order_to_size(this_order), 1, GFP_KERNEL); - entries_per_page = order_to_size(this_order) / rq_size; - to_do = min(entries_per_page, set->queue_depth - i); - left -= to_do * rq_size; - for (j = 0; j < to_do; j++) { - tags->rqs[i] = p; - if (set->ops->init_request) { - if (set->ops->init_request(set->driver_data, - tags->rqs[i], hctx_idx, i, - set->numa_node)) { - tags->rqs[i] = NULL; - goto fail; - } - } - - p += rq_size; - i++; - } - } - return tags; - -fail: - blk_mq_free_rq_map(set, tags, hctx_idx); - return NULL; -} - -/* - * 'cpu' is going away. splice any existing rq_list entries from this - * software queue to the hw queue dispatch list, and ensure that it - * gets run. - */ -static int blk_mq_hctx_notify_dead(unsigned int cpu, struct hlist_node *node) -{ - struct blk_mq_hw_ctx *hctx; - struct blk_mq_ctx *ctx; - LIST_HEAD(tmp); - - hctx = hlist_entry_safe(node, struct blk_mq_hw_ctx, cpuhp_dead); - ctx = __blk_mq_get_ctx(hctx->queue, cpu); - - spin_lock(&ctx->lock); - if (!list_empty(&ctx->rq_list)) { - list_splice_init(&ctx->rq_list, &tmp); - blk_mq_hctx_clear_pending(hctx, ctx); - } - spin_unlock(&ctx->lock); - - if (list_empty(&tmp)) - return 0; - - spin_lock(&hctx->lock); - list_splice_tail_init(&tmp, &hctx->dispatch); - spin_unlock(&hctx->lock); - - blk_mq_run_hw_queue(hctx, true); - return 0; -} - -static void blk_mq_remove_cpuhp(struct blk_mq_hw_ctx *hctx) -{ - cpuhp_state_remove_instance_nocalls(CPUHP_BLK_MQ_DEAD, - &hctx->cpuhp_dead); -} - -/* hctx->ctxs will be freed in queue's release handler */ -static void blk_mq_exit_hctx(struct request_queue *q, - struct blk_mq_tag_set *set, - struct blk_mq_hw_ctx *hctx, unsigned int hctx_idx) -{ - unsigned flush_start_tag = set->queue_depth; - - blk_mq_tag_idle(hctx); - - if (set->ops->exit_request) - set->ops->exit_request(set->driver_data, - hctx->fq->flush_rq, hctx_idx, - flush_start_tag + hctx_idx); - - if (set->ops->exit_hctx) - set->ops->exit_hctx(hctx, hctx_idx); - - blk_mq_remove_cpuhp(hctx); - blk_free_flush_queue(hctx->fq); - sbitmap_free(&hctx->ctx_map); -} - -static void blk_mq_exit_hw_queues(struct request_queue *q, - struct blk_mq_tag_set *set, int nr_queue) -{ - struct blk_mq_hw_ctx *hctx; - unsigned int i; - - queue_for_each_hw_ctx(q, hctx, i) { - if (i == nr_queue) - break; - blk_mq_exit_hctx(q, set, hctx, i); - } -} - -static void blk_mq_free_hw_queues(struct request_queue *q, - struct blk_mq_tag_set *set) -{ - struct blk_mq_hw_ctx *hctx; - unsigned int i; - - queue_for_each_hw_ctx(q, hctx, i) - free_cpumask_var(hctx->cpumask); -} - -static int blk_mq_init_hctx(struct request_queue *q, - struct blk_mq_tag_set *set, - struct blk_mq_hw_ctx *hctx, unsigned hctx_idx) -{ - int node; - unsigned flush_start_tag = set->queue_depth; - - node = hctx->numa_node; - if (node == NUMA_NO_NODE) - node = hctx->numa_node = set->numa_node; - - INIT_WORK(&hctx->run_work, blk_mq_run_work_fn); - INIT_DELAYED_WORK(&hctx->delay_work, blk_mq_delay_work_fn); - spin_lock_init(&hctx->lock); - INIT_LIST_HEAD(&hctx->dispatch); - hctx->queue = q; - hctx->queue_num = hctx_idx; - hctx->flags = set->flags & ~BLK_MQ_F_TAG_SHARED; - - cpuhp_state_add_instance_nocalls(CPUHP_BLK_MQ_DEAD, &hctx->cpuhp_dead); - - hctx->tags = set->tags[hctx_idx]; - - /* - * Allocate space for all possible cpus to avoid allocation at - * runtime - */ - hctx->ctxs = kmalloc_node(nr_cpu_ids * sizeof(void *), - GFP_KERNEL, node); - if (!hctx->ctxs) - goto unregister_cpu_notifier; - - if (sbitmap_init_node(&hctx->ctx_map, nr_cpu_ids, ilog2(8), GFP_KERNEL, - node)) - goto free_ctxs; - - hctx->nr_ctx = 0; - - if (set->ops->init_hctx && - set->ops->init_hctx(hctx, set->driver_data, hctx_idx)) - goto free_bitmap; - - hctx->fq = blk_alloc_flush_queue(q, hctx->numa_node, set->cmd_size); - if (!hctx->fq) - goto exit_hctx; - - if (set->ops->init_request && - set->ops->init_request(set->driver_data, - hctx->fq->flush_rq, hctx_idx, - flush_start_tag + hctx_idx, node)) - goto free_fq; - - return 0; - - free_fq: - kfree(hctx->fq); - exit_hctx: - if (set->ops->exit_hctx) - set->ops->exit_hctx(hctx, hctx_idx); - free_bitmap: - sbitmap_free(&hctx->ctx_map); - free_ctxs: - kfree(hctx->ctxs); - unregister_cpu_notifier: - blk_mq_remove_cpuhp(hctx); - return -1; -} - -static void blk_mq_init_cpu_queues(struct request_queue *q, - unsigned int nr_hw_queues) -{ - unsigned int i; - - for_each_possible_cpu(i) { - struct blk_mq_ctx *__ctx = per_cpu_ptr(q->queue_ctx, i); - struct blk_mq_hw_ctx *hctx; - - memset(__ctx, 0, sizeof(*__ctx)); - __ctx->cpu = i; - spin_lock_init(&__ctx->lock); - INIT_LIST_HEAD(&__ctx->rq_list); - __ctx->queue = q; - - /* If the cpu isn't online, the cpu is mapped to first hctx */ - if (!cpu_online(i)) - continue; - - hctx = blk_mq_map_queue(q, i); - - /* - * Set local node, IFF we have more than one hw queue. If - * not, we remain on the home node of the device - */ - if (nr_hw_queues > 1 && hctx->numa_node == NUMA_NO_NODE) - hctx->numa_node = local_memory_node(cpu_to_node(i)); - } -} - -static void blk_mq_map_swqueue(struct request_queue *q, - const struct cpumask *online_mask) -{ - unsigned int i; - struct blk_mq_hw_ctx *hctx; - struct blk_mq_ctx *ctx; - struct blk_mq_tag_set *set = q->tag_set; - - /* - * Avoid others reading imcomplete hctx->cpumask through sysfs - */ - mutex_lock(&q->sysfs_lock); - - queue_for_each_hw_ctx(q, hctx, i) { - cpumask_clear(hctx->cpumask); - hctx->nr_ctx = 0; - } - - /* - * Map software to hardware queues - */ - for_each_possible_cpu(i) { - /* If the cpu isn't online, the cpu is mapped to first hctx */ - if (!cpumask_test_cpu(i, online_mask)) - continue; - - ctx = per_cpu_ptr(q->queue_ctx, i); - hctx = blk_mq_map_queue(q, i); - - cpumask_set_cpu(i, hctx->cpumask); - ctx->index_hw = hctx->nr_ctx; - hctx->ctxs[hctx->nr_ctx++] = ctx; - } - - mutex_unlock(&q->sysfs_lock); - - queue_for_each_hw_ctx(q, hctx, i) { - /* - * If no software queues are mapped to this hardware queue, - * disable it and free the request entries. - */ - if (!hctx->nr_ctx) { - if (set->tags[i]) { - blk_mq_free_rq_map(set, set->tags[i], i); - set->tags[i] = NULL; - } - hctx->tags = NULL; - continue; - } - - /* unmapped hw queue can be remapped after CPU topo changed */ - if (!set->tags[i]) - set->tags[i] = blk_mq_init_rq_map(set, i); - hctx->tags = set->tags[i]; - WARN_ON(!hctx->tags); - - /* - * Set the map size to the number of mapped software queues. - * This is more accurate and more efficient than looping - * over all possibly mapped software queues. - */ - sbitmap_resize(&hctx->ctx_map, hctx->nr_ctx); - - /* - * Initialize batch roundrobin counts - */ - hctx->next_cpu = cpumask_first(hctx->cpumask); - hctx->next_cpu_batch = BLK_MQ_CPU_WORK_BATCH; - } -} - -static void queue_set_hctx_shared(struct request_queue *q, bool shared) -{ - struct blk_mq_hw_ctx *hctx; - int i; - - queue_for_each_hw_ctx(q, hctx, i) { - if (shared) - hctx->flags |= BLK_MQ_F_TAG_SHARED; - else - hctx->flags &= ~BLK_MQ_F_TAG_SHARED; - } -} - -static void blk_mq_update_tag_set_depth(struct blk_mq_tag_set *set, bool shared) -{ - struct request_queue *q; - - list_for_each_entry(q, &set->tag_list, tag_set_list) { - blk_mq_freeze_queue(q); - queue_set_hctx_shared(q, shared); - blk_mq_unfreeze_queue(q); - } -} - -static void blk_mq_del_queue_tag_set(struct request_queue *q) -{ - struct blk_mq_tag_set *set = q->tag_set; - - mutex_lock(&set->tag_list_lock); - list_del_init(&q->tag_set_list); - if (list_is_singular(&set->tag_list)) { - /* just transitioned to unshared */ - set->flags &= ~BLK_MQ_F_TAG_SHARED; - /* update existing queue */ - blk_mq_update_tag_set_depth(set, false); - } - mutex_unlock(&set->tag_list_lock); -} - -static void blk_mq_add_queue_tag_set(struct blk_mq_tag_set *set, - struct request_queue *q) -{ - q->tag_set = set; - - mutex_lock(&set->tag_list_lock); - - /* Check to see if we're transitioning to shared (from 1 to 2 queues). */ - if (!list_empty(&set->tag_list) && !(set->flags & BLK_MQ_F_TAG_SHARED)) { - set->flags |= BLK_MQ_F_TAG_SHARED; - /* update existing queue */ - blk_mq_update_tag_set_depth(set, true); - } - if (set->flags & BLK_MQ_F_TAG_SHARED) - queue_set_hctx_shared(q, true); - list_add_tail(&q->tag_set_list, &set->tag_list); - - mutex_unlock(&set->tag_list_lock); -} - -/* - * It is the actual release handler for mq, but we do it from - * request queue's release handler for avoiding use-after-free - * and headache because q->mq_kobj shouldn't have been introduced, - * but we can't group ctx/kctx kobj without it. - */ -void blk_mq_release(struct request_queue *q) -{ - struct blk_mq_hw_ctx *hctx; - unsigned int i; - - /* hctx kobj stays in hctx */ - queue_for_each_hw_ctx(q, hctx, i) { - if (!hctx) - continue; - kfree(hctx->ctxs); - kfree(hctx); - } - - q->mq_map = NULL; - - kfree(q->queue_hw_ctx); - - /* ctx kobj stays in queue_ctx */ - free_percpu(q->queue_ctx); -} - -struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *set) -{ - struct request_queue *uninit_q, *q; - - uninit_q = blk_alloc_queue_node(GFP_KERNEL, set->numa_node); - if (!uninit_q) - return ERR_PTR(-ENOMEM); - - q = blk_mq_init_allocated_queue(set, uninit_q); - if (IS_ERR(q)) - blk_cleanup_queue(uninit_q); - - return q; -} -EXPORT_SYMBOL(blk_mq_init_queue); - -static void blk_mq_realloc_hw_ctxs(struct blk_mq_tag_set *set, - struct request_queue *q) -{ - int i, j; - struct blk_mq_hw_ctx **hctxs = q->queue_hw_ctx; - - blk_mq_sysfs_unregister(q); - for (i = 0; i < set->nr_hw_queues; i++) { - int node; - - if (hctxs[i]) - continue; - - node = blk_mq_hw_queue_to_node(q->mq_map, i); - hctxs[i] = kzalloc_node(sizeof(struct blk_mq_hw_ctx), - GFP_KERNEL, node); - if (!hctxs[i]) - break; - - if (!zalloc_cpumask_var_node(&hctxs[i]->cpumask, GFP_KERNEL, - node)) { - kfree(hctxs[i]); - hctxs[i] = NULL; - break; - } - - atomic_set(&hctxs[i]->nr_active, 0); - hctxs[i]->numa_node = node; - hctxs[i]->queue_num = i; - - if (blk_mq_init_hctx(q, set, hctxs[i], i)) { - free_cpumask_var(hctxs[i]->cpumask); - kfree(hctxs[i]); - hctxs[i] = NULL; - break; - } - blk_mq_hctx_kobj_init(hctxs[i]); - } - for (j = i; j < q->nr_hw_queues; j++) { - struct blk_mq_hw_ctx *hctx = hctxs[j]; - - if (hctx) { - if (hctx->tags) { - blk_mq_free_rq_map(set, hctx->tags, j); - set->tags[j] = NULL; - } - blk_mq_exit_hctx(q, set, hctx, j); - free_cpumask_var(hctx->cpumask); - kobject_put(&hctx->kobj); - kfree(hctx->ctxs); - kfree(hctx); - hctxs[j] = NULL; - - } - } - q->nr_hw_queues = i; - blk_mq_sysfs_register(q); -} - -struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set, - struct request_queue *q) -{ - /* mark the queue as mq asap */ - q->mq_ops = set->ops; - - q->queue_ctx = alloc_percpu(struct blk_mq_ctx); - if (!q->queue_ctx) - goto err_exit; - - q->queue_hw_ctx = kzalloc_node(nr_cpu_ids * sizeof(*(q->queue_hw_ctx)), - GFP_KERNEL, set->numa_node); - if (!q->queue_hw_ctx) - goto err_percpu; - - q->mq_map = set->mq_map; - - blk_mq_realloc_hw_ctxs(set, q); - if (!q->nr_hw_queues) - goto err_hctxs; - - INIT_WORK(&q->timeout_work, blk_mq_timeout_work); - blk_queue_rq_timeout(q, set->timeout ? set->timeout : 30 * HZ); - - q->nr_queues = nr_cpu_ids; - - q->queue_flags |= QUEUE_FLAG_MQ_DEFAULT; - - if (!(set->flags & BLK_MQ_F_SG_MERGE)) - q->queue_flags |= 1 << QUEUE_FLAG_NO_SG_MERGE; - - q->sg_reserved_size = INT_MAX; - - INIT_DELAYED_WORK(&q->requeue_work, blk_mq_requeue_work); - INIT_LIST_HEAD(&q->requeue_list); - spin_lock_init(&q->requeue_lock); - - if (q->nr_hw_queues > 1) - blk_queue_make_request(q, blk_mq_make_request); - else - blk_queue_make_request(q, blk_sq_make_request); - - /* - * Do this after blk_queue_make_request() overrides it... - */ - q->nr_requests = set->queue_depth; - - if (set->ops->complete) - blk_queue_softirq_done(q, set->ops->complete); - - blk_mq_init_cpu_queues(q, set->nr_hw_queues); - - get_online_cpus(); - mutex_lock(&all_q_mutex); - - list_add_tail(&q->all_q_node, &all_q_list); - blk_mq_add_queue_tag_set(set, q); - blk_mq_map_swqueue(q, cpu_online_mask); - - mutex_unlock(&all_q_mutex); - put_online_cpus(); - - return q; - -err_hctxs: - kfree(q->queue_hw_ctx); -err_percpu: - free_percpu(q->queue_ctx); -err_exit: - q->mq_ops = NULL; - return ERR_PTR(-ENOMEM); -} -EXPORT_SYMBOL(blk_mq_init_allocated_queue); - -void blk_mq_free_queue(struct request_queue *q) -{ - struct blk_mq_tag_set *set = q->tag_set; - - mutex_lock(&all_q_mutex); - list_del_init(&q->all_q_node); - mutex_unlock(&all_q_mutex); - - blk_mq_del_queue_tag_set(q); - - blk_mq_exit_hw_queues(q, set, set->nr_hw_queues); - blk_mq_free_hw_queues(q, set); -} - -/* Basically redo blk_mq_init_queue with queue frozen */ -static void blk_mq_queue_reinit(struct request_queue *q, - const struct cpumask *online_mask) -{ - WARN_ON_ONCE(!atomic_read(&q->mq_freeze_depth)); - - blk_mq_sysfs_unregister(q); - - /* - * redo blk_mq_init_cpu_queues and blk_mq_init_hw_queues. FIXME: maybe - * we should change hctx numa_node according to new topology (this - * involves free and re-allocate memory, worthy doing?) - */ - - blk_mq_map_swqueue(q, online_mask); - - blk_mq_sysfs_register(q); -} - -/* - * New online cpumask which is going to be set in this hotplug event. - * Declare this cpumasks as global as cpu-hotplug operation is invoked - * one-by-one and dynamically allocating this could result in a failure. - */ -static struct cpumask cpuhp_online_new; - -static void blk_mq_queue_reinit_work(void) -{ - struct request_queue *q; - - mutex_lock(&all_q_mutex); - /* - * We need to freeze and reinit all existing queues. Freezing - * involves synchronous wait for an RCU grace period and doing it - * one by one may take a long time. Start freezing all queues in - * one swoop and then wait for the completions so that freezing can - * take place in parallel. - */ - list_for_each_entry(q, &all_q_list, all_q_node) - blk_mq_freeze_queue_start(q); - list_for_each_entry(q, &all_q_list, all_q_node) { - blk_mq_freeze_queue_wait(q); - - /* - * timeout handler can't touch hw queue during the - * reinitialization - */ - del_timer_sync(&q->timeout); - } - - list_for_each_entry(q, &all_q_list, all_q_node) - blk_mq_queue_reinit(q, &cpuhp_online_new); - - list_for_each_entry(q, &all_q_list, all_q_node) - blk_mq_unfreeze_queue(q); - - mutex_unlock(&all_q_mutex); -} - -static int blk_mq_queue_reinit_dead(unsigned int cpu) -{ - cpumask_copy(&cpuhp_online_new, cpu_online_mask); - blk_mq_queue_reinit_work(); - return 0; -} - -/* - * Before hotadded cpu starts handling requests, new mappings must be - * established. Otherwise, these requests in hw queue might never be - * dispatched. - * - * For example, there is a single hw queue (hctx) and two CPU queues (ctx0 - * for CPU0, and ctx1 for CPU1). - * - * Now CPU1 is just onlined and a request is inserted into ctx1->rq_list - * and set bit0 in pending bitmap as ctx1->index_hw is still zero. - * - * And then while running hw queue, flush_busy_ctxs() finds bit0 is set in - * pending bitmap and tries to retrieve requests in hctx->ctxs[0]->rq_list. - * But htx->ctxs[0] is a pointer to ctx0, so the request in ctx1->rq_list - * is ignored. - */ -static int blk_mq_queue_reinit_prepare(unsigned int cpu) -{ - cpumask_copy(&cpuhp_online_new, cpu_online_mask); - cpumask_set_cpu(cpu, &cpuhp_online_new); - blk_mq_queue_reinit_work(); - return 0; -} - -static int __blk_mq_alloc_rq_maps(struct blk_mq_tag_set *set) -{ - int i; - - for (i = 0; i < set->nr_hw_queues; i++) { - set->tags[i] = blk_mq_init_rq_map(set, i); - if (!set->tags[i]) - goto out_unwind; - } - - return 0; - -out_unwind: - while (--i >= 0) - blk_mq_free_rq_map(set, set->tags[i], i); - - return -ENOMEM; -} - -/* - * Allocate the request maps associated with this tag_set. Note that this - * may reduce the depth asked for, if memory is tight. set->queue_depth - * will be updated to reflect the allocated depth. - */ -static int blk_mq_alloc_rq_maps(struct blk_mq_tag_set *set) -{ - unsigned int depth; - int err; - - depth = set->queue_depth; - do { - err = __blk_mq_alloc_rq_maps(set); - if (!err) - break; - - set->queue_depth >>= 1; - if (set->queue_depth < set->reserved_tags + BLK_MQ_TAG_MIN) { - err = -ENOMEM; - break; - } - } while (set->queue_depth); - - if (!set->queue_depth || err) { - pr_err("blk-mq: failed to allocate request map\n"); - return -ENOMEM; - } - - if (depth != set->queue_depth) - pr_info("blk-mq: reduced tag depth (%u -> %u)\n", - depth, set->queue_depth); - - return 0; -} - -/* - * Alloc a tag set to be associated with one or more request queues. - * May fail with EINVAL for various error conditions. May adjust the - * requested depth down, if if it too large. In that case, the set - * value will be stored in set->queue_depth. - */ -int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set) -{ - int ret; - - BUILD_BUG_ON(BLK_MQ_MAX_DEPTH > 1 << BLK_MQ_UNIQUE_TAG_BITS); - - if (!set->nr_hw_queues) - return -EINVAL; - if (!set->queue_depth) - return -EINVAL; - if (set->queue_depth < set->reserved_tags + BLK_MQ_TAG_MIN) - return -EINVAL; - - if (!set->ops->queue_rq) - return -EINVAL; - - if (set->queue_depth > BLK_MQ_MAX_DEPTH) { - pr_info("blk-mq: reduced tag depth to %u\n", - BLK_MQ_MAX_DEPTH); - set->queue_depth = BLK_MQ_MAX_DEPTH; - } - - /* - * If a crashdump is active, then we are potentially in a very - * memory constrained environment. Limit us to 1 queue and - * 64 tags to prevent using too much memory. - */ - if (is_kdump_kernel()) { - set->nr_hw_queues = 1; - set->queue_depth = min(64U, set->queue_depth); - } - /* - * There is no use for more h/w queues than cpus. - */ - if (set->nr_hw_queues > nr_cpu_ids) - set->nr_hw_queues = nr_cpu_ids; - - set->tags = kzalloc_node(nr_cpu_ids * sizeof(struct blk_mq_tags *), - GFP_KERNEL, set->numa_node); - if (!set->tags) - return -ENOMEM; - - ret = -ENOMEM; - set->mq_map = kzalloc_node(sizeof(*set->mq_map) * nr_cpu_ids, - GFP_KERNEL, set->numa_node); - if (!set->mq_map) - goto out_free_tags; - - if (set->ops->map_queues) - ret = set->ops->map_queues(set); - else - ret = blk_mq_map_queues(set); - if (ret) - goto out_free_mq_map; - - ret = blk_mq_alloc_rq_maps(set); - if (ret) - goto out_free_mq_map; - - mutex_init(&set->tag_list_lock); - INIT_LIST_HEAD(&set->tag_list); - - return 0; - -out_free_mq_map: - kfree(set->mq_map); - set->mq_map = NULL; -out_free_tags: - kfree(set->tags); - set->tags = NULL; - return ret; -} -EXPORT_SYMBOL(blk_mq_alloc_tag_set); - -void blk_mq_free_tag_set(struct blk_mq_tag_set *set) -{ - int i; - - for (i = 0; i < nr_cpu_ids; i++) { - if (set->tags[i]) - blk_mq_free_rq_map(set, set->tags[i], i); - } - - kfree(set->mq_map); - set->mq_map = NULL; - - kfree(set->tags); - set->tags = NULL; -} -EXPORT_SYMBOL(blk_mq_free_tag_set); - -int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr) -{ - struct blk_mq_tag_set *set = q->tag_set; - struct blk_mq_hw_ctx *hctx; - int i, ret; - - if (!set || nr > set->queue_depth) - return -EINVAL; - - ret = 0; - queue_for_each_hw_ctx(q, hctx, i) { - if (!hctx->tags) - continue; - ret = blk_mq_tag_update_depth(hctx->tags, nr); - if (ret) - break; - } - - if (!ret) - q->nr_requests = nr; - - return ret; -} - -void blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, int nr_hw_queues) -{ - struct request_queue *q; - - if (nr_hw_queues > nr_cpu_ids) - nr_hw_queues = nr_cpu_ids; - if (nr_hw_queues < 1 || nr_hw_queues == set->nr_hw_queues) - return; - - list_for_each_entry(q, &set->tag_list, tag_set_list) - blk_mq_freeze_queue(q); - - set->nr_hw_queues = nr_hw_queues; - list_for_each_entry(q, &set->tag_list, tag_set_list) { - blk_mq_realloc_hw_ctxs(set, q); - - if (q->nr_hw_queues > 1) - blk_queue_make_request(q, blk_mq_make_request); - else - blk_queue_make_request(q, blk_sq_make_request); - - blk_mq_queue_reinit(q, cpu_online_mask); - } - - list_for_each_entry(q, &set->tag_list, tag_set_list) - blk_mq_unfreeze_queue(q); -} -EXPORT_SYMBOL_GPL(blk_mq_update_nr_hw_queues); - -void blk_mq_disable_hotplug(void) -{ - mutex_lock(&all_q_mutex); -} - -void blk_mq_enable_hotplug(void) -{ - mutex_unlock(&all_q_mutex); -} - -static int __init blk_mq_init(void) -{ - cpuhp_setup_state_multi(CPUHP_BLK_MQ_DEAD, "block/mq:dead", NULL, - blk_mq_hctx_notify_dead); - - cpuhp_setup_state_nocalls(CPUHP_BLK_MQ_PREPARE, "block/mq:prepare", - blk_mq_queue_reinit_prepare, - blk_mq_queue_reinit_dead); - return 0; -} -subsys_initcall(blk_mq_init); diff --git a/src/linux/block/blk-mq.h b/src/linux/block/blk-mq.h deleted file mode 100644 index e5d2524..0000000 --- a/src/linux/block/blk-mq.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef INT_BLK_MQ_H -#define INT_BLK_MQ_H - -struct blk_mq_tag_set; - -struct blk_mq_ctx { - struct { - spinlock_t lock; - struct list_head rq_list; - } ____cacheline_aligned_in_smp; - - unsigned int cpu; - unsigned int index_hw; - - /* incremented at dispatch time */ - unsigned long rq_dispatched[2]; - unsigned long rq_merged; - - /* incremented at completion time */ - unsigned long ____cacheline_aligned_in_smp rq_completed[2]; - - struct request_queue *queue; - struct kobject kobj; -} ____cacheline_aligned_in_smp; - -void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async); -void blk_mq_freeze_queue(struct request_queue *q); -void blk_mq_free_queue(struct request_queue *q); -int blk_mq_update_nr_requests(struct request_queue *q, unsigned int nr); -void blk_mq_wake_waiters(struct request_queue *q); - -/* - * CPU hotplug helpers - */ -void blk_mq_enable_hotplug(void); -void blk_mq_disable_hotplug(void); - -/* - * CPU -> queue mappings - */ -int blk_mq_map_queues(struct blk_mq_tag_set *set); -extern int blk_mq_hw_queue_to_node(unsigned int *map, unsigned int); - -static inline struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *q, - int cpu) -{ - return q->queue_hw_ctx[q->mq_map[cpu]]; -} - -/* - * sysfs helpers - */ -extern int blk_mq_sysfs_register(struct request_queue *q); -extern void blk_mq_sysfs_unregister(struct request_queue *q); -extern void blk_mq_hctx_kobj_init(struct blk_mq_hw_ctx *hctx); - -extern void blk_mq_rq_timed_out(struct request *req, bool reserved); - -void blk_mq_release(struct request_queue *q); - -static inline struct blk_mq_ctx *__blk_mq_get_ctx(struct request_queue *q, - unsigned int cpu) -{ - return per_cpu_ptr(q->queue_ctx, cpu); -} - -/* - * This assumes per-cpu software queueing queues. They could be per-node - * as well, for instance. For now this is hardcoded as-is. Note that we don't - * care about preemption, since we know the ctx's are persistent. This does - * mean that we can't rely on ctx always matching the currently running CPU. - */ -static inline struct blk_mq_ctx *blk_mq_get_ctx(struct request_queue *q) -{ - return __blk_mq_get_ctx(q, get_cpu()); -} - -static inline void blk_mq_put_ctx(struct blk_mq_ctx *ctx) -{ - put_cpu(); -} - -struct blk_mq_alloc_data { - /* input parameter */ - struct request_queue *q; - unsigned int flags; - - /* input & output parameter */ - struct blk_mq_ctx *ctx; - struct blk_mq_hw_ctx *hctx; -}; - -static inline void blk_mq_set_alloc_data(struct blk_mq_alloc_data *data, - struct request_queue *q, unsigned int flags, - struct blk_mq_ctx *ctx, struct blk_mq_hw_ctx *hctx) -{ - data->q = q; - data->flags = flags; - data->ctx = ctx; - data->hctx = hctx; -} - -static inline bool blk_mq_hw_queue_mapped(struct blk_mq_hw_ctx *hctx) -{ - return hctx->nr_ctx && hctx->tags; -} - -#endif diff --git a/src/linux/block/blk-settings.c b/src/linux/block/blk-settings.c deleted file mode 100644 index f679ae1..0000000 --- a/src/linux/block/blk-settings.c +++ /dev/null @@ -1,863 +0,0 @@ -/* - * Functions related to setting various queue properties from drivers - */ -#include -#include -#include -#include -#include -#include /* for max_pfn/max_low_pfn */ -#include -#include -#include -#include - -#include "blk.h" - -unsigned long blk_max_low_pfn; -EXPORT_SYMBOL(blk_max_low_pfn); - -unsigned long blk_max_pfn; - -/** - * blk_queue_prep_rq - set a prepare_request function for queue - * @q: queue - * @pfn: prepare_request function - * - * It's possible for a queue to register a prepare_request callback which - * is invoked before the request is handed to the request_fn. The goal of - * the function is to prepare a request for I/O, it can be used to build a - * cdb from the request data for instance. - * - */ -void blk_queue_prep_rq(struct request_queue *q, prep_rq_fn *pfn) -{ - q->prep_rq_fn = pfn; -} -EXPORT_SYMBOL(blk_queue_prep_rq); - -/** - * blk_queue_unprep_rq - set an unprepare_request function for queue - * @q: queue - * @ufn: unprepare_request function - * - * It's possible for a queue to register an unprepare_request callback - * which is invoked before the request is finally completed. The goal - * of the function is to deallocate any data that was allocated in the - * prepare_request callback. - * - */ -void blk_queue_unprep_rq(struct request_queue *q, unprep_rq_fn *ufn) -{ - q->unprep_rq_fn = ufn; -} -EXPORT_SYMBOL(blk_queue_unprep_rq); - -void blk_queue_softirq_done(struct request_queue *q, softirq_done_fn *fn) -{ - q->softirq_done_fn = fn; -} -EXPORT_SYMBOL(blk_queue_softirq_done); - -void blk_queue_rq_timeout(struct request_queue *q, unsigned int timeout) -{ - q->rq_timeout = timeout; -} -EXPORT_SYMBOL_GPL(blk_queue_rq_timeout); - -void blk_queue_rq_timed_out(struct request_queue *q, rq_timed_out_fn *fn) -{ - q->rq_timed_out_fn = fn; -} -EXPORT_SYMBOL_GPL(blk_queue_rq_timed_out); - -void blk_queue_lld_busy(struct request_queue *q, lld_busy_fn *fn) -{ - q->lld_busy_fn = fn; -} -EXPORT_SYMBOL_GPL(blk_queue_lld_busy); - -/** - * blk_set_default_limits - reset limits to default values - * @lim: the queue_limits structure to reset - * - * Description: - * Returns a queue_limit struct to its default state. - */ -void blk_set_default_limits(struct queue_limits *lim) -{ - lim->max_segments = BLK_MAX_SEGMENTS; - lim->max_integrity_segments = 0; - lim->seg_boundary_mask = BLK_SEG_BOUNDARY_MASK; - lim->virt_boundary_mask = 0; - lim->max_segment_size = BLK_MAX_SEGMENT_SIZE; - lim->max_sectors = lim->max_hw_sectors = BLK_SAFE_MAX_SECTORS; - lim->max_dev_sectors = 0; - lim->chunk_sectors = 0; - lim->max_write_same_sectors = 0; - lim->max_discard_sectors = 0; - lim->max_hw_discard_sectors = 0; - lim->discard_granularity = 0; - lim->discard_alignment = 0; - lim->discard_misaligned = 0; - lim->discard_zeroes_data = 0; - lim->logical_block_size = lim->physical_block_size = lim->io_min = 512; - lim->bounce_pfn = (unsigned long)(BLK_BOUNCE_ANY >> PAGE_SHIFT); - lim->alignment_offset = 0; - lim->io_opt = 0; - lim->misaligned = 0; - lim->cluster = 1; -} -EXPORT_SYMBOL(blk_set_default_limits); - -/** - * blk_set_stacking_limits - set default limits for stacking devices - * @lim: the queue_limits structure to reset - * - * Description: - * Returns a queue_limit struct to its default state. Should be used - * by stacking drivers like DM that have no internal limits. - */ -void blk_set_stacking_limits(struct queue_limits *lim) -{ - blk_set_default_limits(lim); - - /* Inherit limits from component devices */ - lim->discard_zeroes_data = 1; - lim->max_segments = USHRT_MAX; - lim->max_hw_sectors = UINT_MAX; - lim->max_segment_size = UINT_MAX; - lim->max_sectors = UINT_MAX; - lim->max_dev_sectors = UINT_MAX; - lim->max_write_same_sectors = UINT_MAX; -} -EXPORT_SYMBOL(blk_set_stacking_limits); - -/** - * blk_queue_make_request - define an alternate make_request function for a device - * @q: the request queue for the device to be affected - * @mfn: the alternate make_request function - * - * Description: - * The normal way for &struct bios to be passed to a device - * driver is for them to be collected into requests on a request - * queue, and then to allow the device driver to select requests - * off that queue when it is ready. This works well for many block - * devices. However some block devices (typically virtual devices - * such as md or lvm) do not benefit from the processing on the - * request queue, and are served best by having the requests passed - * directly to them. This can be achieved by providing a function - * to blk_queue_make_request(). - * - * Caveat: - * The driver that does this *must* be able to deal appropriately - * with buffers in "highmemory". This can be accomplished by either calling - * __bio_kmap_atomic() to get a temporary kernel mapping, or by calling - * blk_queue_bounce() to create a buffer in normal memory. - **/ -void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn) -{ - /* - * set defaults - */ - q->nr_requests = BLKDEV_MAX_RQ; - - q->make_request_fn = mfn; - blk_queue_dma_alignment(q, 511); - blk_queue_congestion_threshold(q); - q->nr_batching = BLK_BATCH_REQ; - - blk_set_default_limits(&q->limits); - - /* - * by default assume old behaviour and bounce for any highmem page - */ - blk_queue_bounce_limit(q, BLK_BOUNCE_HIGH); -} -EXPORT_SYMBOL(blk_queue_make_request); - -/** - * blk_queue_bounce_limit - set bounce buffer limit for queue - * @q: the request queue for the device - * @max_addr: the maximum address the device can handle - * - * Description: - * Different hardware can have different requirements as to what pages - * it can do I/O directly to. A low level driver can call - * blk_queue_bounce_limit to have lower memory pages allocated as bounce - * buffers for doing I/O to pages residing above @max_addr. - **/ -void blk_queue_bounce_limit(struct request_queue *q, u64 max_addr) -{ - unsigned long b_pfn = max_addr >> PAGE_SHIFT; - int dma = 0; - - q->bounce_gfp = GFP_NOIO; -#if BITS_PER_LONG == 64 - /* - * Assume anything <= 4GB can be handled by IOMMU. Actually - * some IOMMUs can handle everything, but I don't know of a - * way to test this here. - */ - if (b_pfn < (min_t(u64, 0xffffffffUL, BLK_BOUNCE_HIGH) >> PAGE_SHIFT)) - dma = 1; - q->limits.bounce_pfn = max(max_low_pfn, b_pfn); -#else - if (b_pfn < blk_max_low_pfn) - dma = 1; - q->limits.bounce_pfn = b_pfn; -#endif - if (dma) { - init_emergency_isa_pool(); - q->bounce_gfp = GFP_NOIO | GFP_DMA; - q->limits.bounce_pfn = b_pfn; - } -} -EXPORT_SYMBOL(blk_queue_bounce_limit); - -/** - * blk_queue_max_hw_sectors - set max sectors for a request for this queue - * @q: the request queue for the device - * @max_hw_sectors: max hardware sectors in the usual 512b unit - * - * Description: - * Enables a low level driver to set a hard upper limit, - * max_hw_sectors, on the size of requests. max_hw_sectors is set by - * the device driver based upon the capabilities of the I/O - * controller. - * - * max_dev_sectors is a hard limit imposed by the storage device for - * READ/WRITE requests. It is set by the disk driver. - * - * max_sectors is a soft limit imposed by the block layer for - * filesystem type requests. This value can be overridden on a - * per-device basis in /sys/block//queue/max_sectors_kb. - * The soft limit can not exceed max_hw_sectors. - **/ -void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_sectors) -{ - struct queue_limits *limits = &q->limits; - unsigned int max_sectors; - - if ((max_hw_sectors << 9) < PAGE_SIZE) { - max_hw_sectors = 1 << (PAGE_SHIFT - 9); - printk(KERN_INFO "%s: set to minimum %d\n", - __func__, max_hw_sectors); - } - - limits->max_hw_sectors = max_hw_sectors; - max_sectors = min_not_zero(max_hw_sectors, limits->max_dev_sectors); - max_sectors = min_t(unsigned int, max_sectors, BLK_DEF_MAX_SECTORS); - limits->max_sectors = max_sectors; -} -EXPORT_SYMBOL(blk_queue_max_hw_sectors); - -/** - * blk_queue_chunk_sectors - set size of the chunk for this queue - * @q: the request queue for the device - * @chunk_sectors: chunk sectors in the usual 512b unit - * - * Description: - * If a driver doesn't want IOs to cross a given chunk size, it can set - * this limit and prevent merging across chunks. Note that the chunk size - * must currently be a power-of-2 in sectors. Also note that the block - * layer must accept a page worth of data at any offset. So if the - * crossing of chunks is a hard limitation in the driver, it must still be - * prepared to split single page bios. - **/ -void blk_queue_chunk_sectors(struct request_queue *q, unsigned int chunk_sectors) -{ - BUG_ON(!is_power_of_2(chunk_sectors)); - q->limits.chunk_sectors = chunk_sectors; -} -EXPORT_SYMBOL(blk_queue_chunk_sectors); - -/** - * blk_queue_max_discard_sectors - set max sectors for a single discard - * @q: the request queue for the device - * @max_discard_sectors: maximum number of sectors to discard - **/ -void blk_queue_max_discard_sectors(struct request_queue *q, - unsigned int max_discard_sectors) -{ - q->limits.max_hw_discard_sectors = max_discard_sectors; - q->limits.max_discard_sectors = max_discard_sectors; -} -EXPORT_SYMBOL(blk_queue_max_discard_sectors); - -/** - * blk_queue_max_write_same_sectors - set max sectors for a single write same - * @q: the request queue for the device - * @max_write_same_sectors: maximum number of sectors to write per command - **/ -void blk_queue_max_write_same_sectors(struct request_queue *q, - unsigned int max_write_same_sectors) -{ - q->limits.max_write_same_sectors = max_write_same_sectors; -} -EXPORT_SYMBOL(blk_queue_max_write_same_sectors); - -/** - * blk_queue_max_segments - set max hw segments for a request for this queue - * @q: the request queue for the device - * @max_segments: max number of segments - * - * Description: - * Enables a low level driver to set an upper limit on the number of - * hw data segments in a request. - **/ -void blk_queue_max_segments(struct request_queue *q, unsigned short max_segments) -{ - if (!max_segments) { - max_segments = 1; - printk(KERN_INFO "%s: set to minimum %d\n", - __func__, max_segments); - } - - q->limits.max_segments = max_segments; -} -EXPORT_SYMBOL(blk_queue_max_segments); - -/** - * blk_queue_max_segment_size - set max segment size for blk_rq_map_sg - * @q: the request queue for the device - * @max_size: max size of segment in bytes - * - * Description: - * Enables a low level driver to set an upper limit on the size of a - * coalesced segment - **/ -void blk_queue_max_segment_size(struct request_queue *q, unsigned int max_size) -{ - if (max_size < PAGE_SIZE) { - max_size = PAGE_SIZE; - printk(KERN_INFO "%s: set to minimum %d\n", - __func__, max_size); - } - - q->limits.max_segment_size = max_size; -} -EXPORT_SYMBOL(blk_queue_max_segment_size); - -/** - * blk_queue_logical_block_size - set logical block size for the queue - * @q: the request queue for the device - * @size: the logical block size, in bytes - * - * Description: - * This should be set to the lowest possible block size that the - * storage device can address. The default of 512 covers most - * hardware. - **/ -void blk_queue_logical_block_size(struct request_queue *q, unsigned short size) -{ - q->limits.logical_block_size = size; - - if (q->limits.physical_block_size < size) - q->limits.physical_block_size = size; - - if (q->limits.io_min < q->limits.physical_block_size) - q->limits.io_min = q->limits.physical_block_size; -} -EXPORT_SYMBOL(blk_queue_logical_block_size); - -/** - * blk_queue_physical_block_size - set physical block size for the queue - * @q: the request queue for the device - * @size: the physical block size, in bytes - * - * Description: - * This should be set to the lowest possible sector size that the - * hardware can operate on without reverting to read-modify-write - * operations. - */ -void blk_queue_physical_block_size(struct request_queue *q, unsigned int size) -{ - q->limits.physical_block_size = size; - - if (q->limits.physical_block_size < q->limits.logical_block_size) - q->limits.physical_block_size = q->limits.logical_block_size; - - if (q->limits.io_min < q->limits.physical_block_size) - q->limits.io_min = q->limits.physical_block_size; -} -EXPORT_SYMBOL(blk_queue_physical_block_size); - -/** - * blk_queue_alignment_offset - set physical block alignment offset - * @q: the request queue for the device - * @offset: alignment offset in bytes - * - * Description: - * Some devices are naturally misaligned to compensate for things like - * the legacy DOS partition table 63-sector offset. Low-level drivers - * should call this function for devices whose first sector is not - * naturally aligned. - */ -void blk_queue_alignment_offset(struct request_queue *q, unsigned int offset) -{ - q->limits.alignment_offset = - offset & (q->limits.physical_block_size - 1); - q->limits.misaligned = 0; -} -EXPORT_SYMBOL(blk_queue_alignment_offset); - -/** - * blk_limits_io_min - set minimum request size for a device - * @limits: the queue limits - * @min: smallest I/O size in bytes - * - * Description: - * Some devices have an internal block size bigger than the reported - * hardware sector size. This function can be used to signal the - * smallest I/O the device can perform without incurring a performance - * penalty. - */ -void blk_limits_io_min(struct queue_limits *limits, unsigned int min) -{ - limits->io_min = min; - - if (limits->io_min < limits->logical_block_size) - limits->io_min = limits->logical_block_size; - - if (limits->io_min < limits->physical_block_size) - limits->io_min = limits->physical_block_size; -} -EXPORT_SYMBOL(blk_limits_io_min); - -/** - * blk_queue_io_min - set minimum request size for the queue - * @q: the request queue for the device - * @min: smallest I/O size in bytes - * - * Description: - * Storage devices may report a granularity or preferred minimum I/O - * size which is the smallest request the device can perform without - * incurring a performance penalty. For disk drives this is often the - * physical block size. For RAID arrays it is often the stripe chunk - * size. A properly aligned multiple of minimum_io_size is the - * preferred request size for workloads where a high number of I/O - * operations is desired. - */ -void blk_queue_io_min(struct request_queue *q, unsigned int min) -{ - blk_limits_io_min(&q->limits, min); -} -EXPORT_SYMBOL(blk_queue_io_min); - -/** - * blk_limits_io_opt - set optimal request size for a device - * @limits: the queue limits - * @opt: smallest I/O size in bytes - * - * Description: - * Storage devices may report an optimal I/O size, which is the - * device's preferred unit for sustained I/O. This is rarely reported - * for disk drives. For RAID arrays it is usually the stripe width or - * the internal track size. A properly aligned multiple of - * optimal_io_size is the preferred request size for workloads where - * sustained throughput is desired. - */ -void blk_limits_io_opt(struct queue_limits *limits, unsigned int opt) -{ - limits->io_opt = opt; -} -EXPORT_SYMBOL(blk_limits_io_opt); - -/** - * blk_queue_io_opt - set optimal request size for the queue - * @q: the request queue for the device - * @opt: optimal request size in bytes - * - * Description: - * Storage devices may report an optimal I/O size, which is the - * device's preferred unit for sustained I/O. This is rarely reported - * for disk drives. For RAID arrays it is usually the stripe width or - * the internal track size. A properly aligned multiple of - * optimal_io_size is the preferred request size for workloads where - * sustained throughput is desired. - */ -void blk_queue_io_opt(struct request_queue *q, unsigned int opt) -{ - blk_limits_io_opt(&q->limits, opt); -} -EXPORT_SYMBOL(blk_queue_io_opt); - -/** - * blk_queue_stack_limits - inherit underlying queue limits for stacked drivers - * @t: the stacking driver (top) - * @b: the underlying device (bottom) - **/ -void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b) -{ - blk_stack_limits(&t->limits, &b->limits, 0); -} -EXPORT_SYMBOL(blk_queue_stack_limits); - -/** - * blk_stack_limits - adjust queue_limits for stacked devices - * @t: the stacking driver limits (top device) - * @b: the underlying queue limits (bottom, component device) - * @start: first data sector within component device - * - * Description: - * This function is used by stacking drivers like MD and DM to ensure - * that all component devices have compatible block sizes and - * alignments. The stacking driver must provide a queue_limits - * struct (top) and then iteratively call the stacking function for - * all component (bottom) devices. The stacking function will - * attempt to combine the values and ensure proper alignment. - * - * Returns 0 if the top and bottom queue_limits are compatible. The - * top device's block sizes and alignment offsets may be adjusted to - * ensure alignment with the bottom device. If no compatible sizes - * and alignments exist, -1 is returned and the resulting top - * queue_limits will have the misaligned flag set to indicate that - * the alignment_offset is undefined. - */ -int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, - sector_t start) -{ - unsigned int top, bottom, alignment, ret = 0; - - t->max_sectors = min_not_zero(t->max_sectors, b->max_sectors); - t->max_hw_sectors = min_not_zero(t->max_hw_sectors, b->max_hw_sectors); - t->max_dev_sectors = min_not_zero(t->max_dev_sectors, b->max_dev_sectors); - t->max_write_same_sectors = min(t->max_write_same_sectors, - b->max_write_same_sectors); - t->bounce_pfn = min_not_zero(t->bounce_pfn, b->bounce_pfn); - - t->seg_boundary_mask = min_not_zero(t->seg_boundary_mask, - b->seg_boundary_mask); - t->virt_boundary_mask = min_not_zero(t->virt_boundary_mask, - b->virt_boundary_mask); - - t->max_segments = min_not_zero(t->max_segments, b->max_segments); - t->max_integrity_segments = min_not_zero(t->max_integrity_segments, - b->max_integrity_segments); - - t->max_segment_size = min_not_zero(t->max_segment_size, - b->max_segment_size); - - t->misaligned |= b->misaligned; - - alignment = queue_limit_alignment_offset(b, start); - - /* Bottom device has different alignment. Check that it is - * compatible with the current top alignment. - */ - if (t->alignment_offset != alignment) { - - top = max(t->physical_block_size, t->io_min) - + t->alignment_offset; - bottom = max(b->physical_block_size, b->io_min) + alignment; - - /* Verify that top and bottom intervals line up */ - if (max(top, bottom) % min(top, bottom)) { - t->misaligned = 1; - ret = -1; - } - } - - t->logical_block_size = max(t->logical_block_size, - b->logical_block_size); - - t->physical_block_size = max(t->physical_block_size, - b->physical_block_size); - - t->io_min = max(t->io_min, b->io_min); - t->io_opt = lcm_not_zero(t->io_opt, b->io_opt); - - t->cluster &= b->cluster; - t->discard_zeroes_data &= b->discard_zeroes_data; - - /* Physical block size a multiple of the logical block size? */ - if (t->physical_block_size & (t->logical_block_size - 1)) { - t->physical_block_size = t->logical_block_size; - t->misaligned = 1; - ret = -1; - } - - /* Minimum I/O a multiple of the physical block size? */ - if (t->io_min & (t->physical_block_size - 1)) { - t->io_min = t->physical_block_size; - t->misaligned = 1; - ret = -1; - } - - /* Optimal I/O a multiple of the physical block size? */ - if (t->io_opt & (t->physical_block_size - 1)) { - t->io_opt = 0; - t->misaligned = 1; - ret = -1; - } - - t->raid_partial_stripes_expensive = - max(t->raid_partial_stripes_expensive, - b->raid_partial_stripes_expensive); - - /* Find lowest common alignment_offset */ - t->alignment_offset = lcm_not_zero(t->alignment_offset, alignment) - % max(t->physical_block_size, t->io_min); - - /* Verify that new alignment_offset is on a logical block boundary */ - if (t->alignment_offset & (t->logical_block_size - 1)) { - t->misaligned = 1; - ret = -1; - } - - /* Discard alignment and granularity */ - if (b->discard_granularity) { - alignment = queue_limit_discard_alignment(b, start); - - if (t->discard_granularity != 0 && - t->discard_alignment != alignment) { - top = t->discard_granularity + t->discard_alignment; - bottom = b->discard_granularity + alignment; - - /* Verify that top and bottom intervals line up */ - if ((max(top, bottom) % min(top, bottom)) != 0) - t->discard_misaligned = 1; - } - - t->max_discard_sectors = min_not_zero(t->max_discard_sectors, - b->max_discard_sectors); - t->max_hw_discard_sectors = min_not_zero(t->max_hw_discard_sectors, - b->max_hw_discard_sectors); - t->discard_granularity = max(t->discard_granularity, - b->discard_granularity); - t->discard_alignment = lcm_not_zero(t->discard_alignment, alignment) % - t->discard_granularity; - } - - return ret; -} -EXPORT_SYMBOL(blk_stack_limits); - -/** - * bdev_stack_limits - adjust queue limits for stacked drivers - * @t: the stacking driver limits (top device) - * @bdev: the component block_device (bottom) - * @start: first data sector within component device - * - * Description: - * Merges queue limits for a top device and a block_device. Returns - * 0 if alignment didn't change. Returns -1 if adding the bottom - * device caused misalignment. - */ -int bdev_stack_limits(struct queue_limits *t, struct block_device *bdev, - sector_t start) -{ - struct request_queue *bq = bdev_get_queue(bdev); - - start += get_start_sect(bdev); - - return blk_stack_limits(t, &bq->limits, start); -} -EXPORT_SYMBOL(bdev_stack_limits); - -/** - * disk_stack_limits - adjust queue limits for stacked drivers - * @disk: MD/DM gendisk (top) - * @bdev: the underlying block device (bottom) - * @offset: offset to beginning of data within component device - * - * Description: - * Merges the limits for a top level gendisk and a bottom level - * block_device. - */ -void disk_stack_limits(struct gendisk *disk, struct block_device *bdev, - sector_t offset) -{ - struct request_queue *t = disk->queue; - - if (bdev_stack_limits(&t->limits, bdev, offset >> 9) < 0) { - char top[BDEVNAME_SIZE], bottom[BDEVNAME_SIZE]; - - disk_name(disk, 0, top); - bdevname(bdev, bottom); - - printk(KERN_NOTICE "%s: Warning: Device %s is misaligned\n", - top, bottom); - } -} -EXPORT_SYMBOL(disk_stack_limits); - -/** - * blk_queue_dma_pad - set pad mask - * @q: the request queue for the device - * @mask: pad mask - * - * Set dma pad mask. - * - * Appending pad buffer to a request modifies the last entry of a - * scatter list such that it includes the pad buffer. - **/ -void blk_queue_dma_pad(struct request_queue *q, unsigned int mask) -{ - q->dma_pad_mask = mask; -} -EXPORT_SYMBOL(blk_queue_dma_pad); - -/** - * blk_queue_update_dma_pad - update pad mask - * @q: the request queue for the device - * @mask: pad mask - * - * Update dma pad mask. - * - * Appending pad buffer to a request modifies the last entry of a - * scatter list such that it includes the pad buffer. - **/ -void blk_queue_update_dma_pad(struct request_queue *q, unsigned int mask) -{ - if (mask > q->dma_pad_mask) - q->dma_pad_mask = mask; -} -EXPORT_SYMBOL(blk_queue_update_dma_pad); - -/** - * blk_queue_dma_drain - Set up a drain buffer for excess dma. - * @q: the request queue for the device - * @dma_drain_needed: fn which returns non-zero if drain is necessary - * @buf: physically contiguous buffer - * @size: size of the buffer in bytes - * - * Some devices have excess DMA problems and can't simply discard (or - * zero fill) the unwanted piece of the transfer. They have to have a - * real area of memory to transfer it into. The use case for this is - * ATAPI devices in DMA mode. If the packet command causes a transfer - * bigger than the transfer size some HBAs will lock up if there - * aren't DMA elements to contain the excess transfer. What this API - * does is adjust the queue so that the buf is always appended - * silently to the scatterlist. - * - * Note: This routine adjusts max_hw_segments to make room for appending - * the drain buffer. If you call blk_queue_max_segments() after calling - * this routine, you must set the limit to one fewer than your device - * can support otherwise there won't be room for the drain buffer. - */ -int blk_queue_dma_drain(struct request_queue *q, - dma_drain_needed_fn *dma_drain_needed, - void *buf, unsigned int size) -{ - if (queue_max_segments(q) < 2) - return -EINVAL; - /* make room for appending the drain */ - blk_queue_max_segments(q, queue_max_segments(q) - 1); - q->dma_drain_needed = dma_drain_needed; - q->dma_drain_buffer = buf; - q->dma_drain_size = size; - - return 0; -} -EXPORT_SYMBOL_GPL(blk_queue_dma_drain); - -/** - * blk_queue_segment_boundary - set boundary rules for segment merging - * @q: the request queue for the device - * @mask: the memory boundary mask - **/ -void blk_queue_segment_boundary(struct request_queue *q, unsigned long mask) -{ - if (mask < PAGE_SIZE - 1) { - mask = PAGE_SIZE - 1; - printk(KERN_INFO "%s: set to minimum %lx\n", - __func__, mask); - } - - q->limits.seg_boundary_mask = mask; -} -EXPORT_SYMBOL(blk_queue_segment_boundary); - -/** - * blk_queue_virt_boundary - set boundary rules for bio merging - * @q: the request queue for the device - * @mask: the memory boundary mask - **/ -void blk_queue_virt_boundary(struct request_queue *q, unsigned long mask) -{ - q->limits.virt_boundary_mask = mask; -} -EXPORT_SYMBOL(blk_queue_virt_boundary); - -/** - * blk_queue_dma_alignment - set dma length and memory alignment - * @q: the request queue for the device - * @mask: alignment mask - * - * description: - * set required memory and length alignment for direct dma transactions. - * this is used when building direct io requests for the queue. - * - **/ -void blk_queue_dma_alignment(struct request_queue *q, int mask) -{ - q->dma_alignment = mask; -} -EXPORT_SYMBOL(blk_queue_dma_alignment); - -/** - * blk_queue_update_dma_alignment - update dma length and memory alignment - * @q: the request queue for the device - * @mask: alignment mask - * - * description: - * update required memory and length alignment for direct dma transactions. - * If the requested alignment is larger than the current alignment, then - * the current queue alignment is updated to the new value, otherwise it - * is left alone. The design of this is to allow multiple objects - * (driver, device, transport etc) to set their respective - * alignments without having them interfere. - * - **/ -void blk_queue_update_dma_alignment(struct request_queue *q, int mask) -{ - BUG_ON(mask > PAGE_SIZE); - - if (mask > q->dma_alignment) - q->dma_alignment = mask; -} -EXPORT_SYMBOL(blk_queue_update_dma_alignment); - -void blk_queue_flush_queueable(struct request_queue *q, bool queueable) -{ - spin_lock_irq(q->queue_lock); - if (queueable) - clear_bit(QUEUE_FLAG_FLUSH_NQ, &q->queue_flags); - else - set_bit(QUEUE_FLAG_FLUSH_NQ, &q->queue_flags); - spin_unlock_irq(q->queue_lock); -} -EXPORT_SYMBOL_GPL(blk_queue_flush_queueable); - -/** - * blk_queue_write_cache - configure queue's write cache - * @q: the request queue for the device - * @wc: write back cache on or off - * @fua: device supports FUA writes, if true - * - * Tell the block layer about the write cache of @q. - */ -void blk_queue_write_cache(struct request_queue *q, bool wc, bool fua) -{ - spin_lock_irq(q->queue_lock); - if (wc) - queue_flag_set(QUEUE_FLAG_WC, q); - else - queue_flag_clear(QUEUE_FLAG_WC, q); - if (fua) - queue_flag_set(QUEUE_FLAG_FUA, q); - else - queue_flag_clear(QUEUE_FLAG_FUA, q); - spin_unlock_irq(q->queue_lock); -} -EXPORT_SYMBOL_GPL(blk_queue_write_cache); - -static int __init blk_settings_init(void) -{ - blk_max_low_pfn = max_low_pfn - 1; - blk_max_pfn = max_pfn - 1; - return 0; -} -subsys_initcall(blk_settings_init); diff --git a/src/linux/block/blk-softirq.c b/src/linux/block/blk-softirq.c deleted file mode 100644 index 06cf980..0000000 --- a/src/linux/block/blk-softirq.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Functions related to softirq rq completions - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include "blk.h" - -static DEFINE_PER_CPU(struct list_head, blk_cpu_done); - -/* - * Softirq action handler - move entries to local list and loop over them - * while passing them to the queue registered handler. - */ -static __latent_entropy void blk_done_softirq(struct softirq_action *h) -{ - struct list_head *cpu_list, local_list; - - local_irq_disable(); - cpu_list = this_cpu_ptr(&blk_cpu_done); - list_replace_init(cpu_list, &local_list); - local_irq_enable(); - - while (!list_empty(&local_list)) { - struct request *rq; - - rq = list_entry(local_list.next, struct request, ipi_list); - list_del_init(&rq->ipi_list); - rq->q->softirq_done_fn(rq); - } -} - -#ifdef CONFIG_SMP -static void trigger_softirq(void *data) -{ - struct request *rq = data; - unsigned long flags; - struct list_head *list; - - local_irq_save(flags); - list = this_cpu_ptr(&blk_cpu_done); - list_add_tail(&rq->ipi_list, list); - - if (list->next == &rq->ipi_list) - raise_softirq_irqoff(BLOCK_SOFTIRQ); - - local_irq_restore(flags); -} - -/* - * Setup and invoke a run of 'trigger_softirq' on the given cpu. - */ -static int raise_blk_irq(int cpu, struct request *rq) -{ - if (cpu_online(cpu)) { - struct call_single_data *data = &rq->csd; - - data->func = trigger_softirq; - data->info = rq; - data->flags = 0; - - smp_call_function_single_async(cpu, data); - return 0; - } - - return 1; -} -#else /* CONFIG_SMP */ -static int raise_blk_irq(int cpu, struct request *rq) -{ - return 1; -} -#endif - -static int blk_softirq_cpu_dead(unsigned int cpu) -{ - /* - * If a CPU goes away, splice its entries to the current CPU - * and trigger a run of the softirq - */ - local_irq_disable(); - list_splice_init(&per_cpu(blk_cpu_done, cpu), - this_cpu_ptr(&blk_cpu_done)); - raise_softirq_irqoff(BLOCK_SOFTIRQ); - local_irq_enable(); - - return 0; -} - -void __blk_complete_request(struct request *req) -{ - int ccpu, cpu; - struct request_queue *q = req->q; - unsigned long flags; - bool shared = false; - - BUG_ON(!q->softirq_done_fn); - - local_irq_save(flags); - cpu = smp_processor_id(); - - /* - * Select completion CPU - */ - if (req->cpu != -1) { - ccpu = req->cpu; - if (!test_bit(QUEUE_FLAG_SAME_FORCE, &q->queue_flags)) - shared = cpus_share_cache(cpu, ccpu); - } else - ccpu = cpu; - - /* - * If current CPU and requested CPU share a cache, run the softirq on - * the current CPU. One might concern this is just like - * QUEUE_FLAG_SAME_FORCE, but actually not. blk_complete_request() is - * running in interrupt handler, and currently I/O controller doesn't - * support multiple interrupts, so current CPU is unique actually. This - * avoids IPI sending from current CPU to the first CPU of a group. - */ - if (ccpu == cpu || shared) { - struct list_head *list; -do_local: - list = this_cpu_ptr(&blk_cpu_done); - list_add_tail(&req->ipi_list, list); - - /* - * if the list only contains our just added request, - * signal a raise of the softirq. If there are already - * entries there, someone already raised the irq but it - * hasn't run yet. - */ - if (list->next == &req->ipi_list) - raise_softirq_irqoff(BLOCK_SOFTIRQ); - } else if (raise_blk_irq(ccpu, req)) - goto do_local; - - local_irq_restore(flags); -} - -/** - * blk_complete_request - end I/O on a request - * @req: the request being processed - * - * Description: - * Ends all I/O on a request. It does not handle partial completions, - * unless the driver actually implements this in its completion callback - * through requeueing. The actual completion happens out-of-order, - * through a softirq handler. The user must have registered a completion - * callback through blk_queue_softirq_done(). - **/ -void blk_complete_request(struct request *req) -{ - if (unlikely(blk_should_fake_timeout(req->q))) - return; - if (!blk_mark_rq_complete(req)) - __blk_complete_request(req); -} -EXPORT_SYMBOL(blk_complete_request); - -static __init int blk_softirq_init(void) -{ - int i; - - for_each_possible_cpu(i) - INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i)); - - open_softirq(BLOCK_SOFTIRQ, blk_done_softirq); - cpuhp_setup_state_nocalls(CPUHP_BLOCK_SOFTIRQ_DEAD, - "block/softirq:dead", NULL, - blk_softirq_cpu_dead); - return 0; -} -subsys_initcall(blk_softirq_init); diff --git a/src/linux/block/blk-sysfs.c b/src/linux/block/blk-sysfs.c deleted file mode 100644 index 9cc8d7c..0000000 --- a/src/linux/block/blk-sysfs.c +++ /dev/null @@ -1,741 +0,0 @@ -/* - * Functions related to sysfs handling - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "blk.h" -#include "blk-mq.h" - -struct queue_sysfs_entry { - struct attribute attr; - ssize_t (*show)(struct request_queue *, char *); - ssize_t (*store)(struct request_queue *, const char *, size_t); -}; - -static ssize_t -queue_var_show(unsigned long var, char *page) -{ - return sprintf(page, "%lu\n", var); -} - -static ssize_t -queue_var_store(unsigned long *var, const char *page, size_t count) -{ - int err; - unsigned long v; - - err = kstrtoul(page, 10, &v); - if (err || v > UINT_MAX) - return -EINVAL; - - *var = v; - - return count; -} - -static ssize_t queue_requests_show(struct request_queue *q, char *page) -{ - return queue_var_show(q->nr_requests, (page)); -} - -static ssize_t -queue_requests_store(struct request_queue *q, const char *page, size_t count) -{ - unsigned long nr; - int ret, err; - - if (!q->request_fn && !q->mq_ops) - return -EINVAL; - - ret = queue_var_store(&nr, page, count); - if (ret < 0) - return ret; - - if (nr < BLKDEV_MIN_RQ) - nr = BLKDEV_MIN_RQ; - - if (q->request_fn) - err = blk_update_nr_requests(q, nr); - else - err = blk_mq_update_nr_requests(q, nr); - - if (err) - return err; - - return ret; -} - -static ssize_t queue_ra_show(struct request_queue *q, char *page) -{ - unsigned long ra_kb = q->backing_dev_info.ra_pages << - (PAGE_SHIFT - 10); - - return queue_var_show(ra_kb, (page)); -} - -static ssize_t -queue_ra_store(struct request_queue *q, const char *page, size_t count) -{ - unsigned long ra_kb; - ssize_t ret = queue_var_store(&ra_kb, page, count); - - if (ret < 0) - return ret; - - q->backing_dev_info.ra_pages = ra_kb >> (PAGE_SHIFT - 10); - - return ret; -} - -static ssize_t queue_max_sectors_show(struct request_queue *q, char *page) -{ - int max_sectors_kb = queue_max_sectors(q) >> 1; - - return queue_var_show(max_sectors_kb, (page)); -} - -static ssize_t queue_max_segments_show(struct request_queue *q, char *page) -{ - return queue_var_show(queue_max_segments(q), (page)); -} - -static ssize_t queue_max_integrity_segments_show(struct request_queue *q, char *page) -{ - return queue_var_show(q->limits.max_integrity_segments, (page)); -} - -static ssize_t queue_max_segment_size_show(struct request_queue *q, char *page) -{ - if (blk_queue_cluster(q)) - return queue_var_show(queue_max_segment_size(q), (page)); - - return queue_var_show(PAGE_SIZE, (page)); -} - -static ssize_t queue_logical_block_size_show(struct request_queue *q, char *page) -{ - return queue_var_show(queue_logical_block_size(q), page); -} - -static ssize_t queue_physical_block_size_show(struct request_queue *q, char *page) -{ - return queue_var_show(queue_physical_block_size(q), page); -} - -static ssize_t queue_io_min_show(struct request_queue *q, char *page) -{ - return queue_var_show(queue_io_min(q), page); -} - -static ssize_t queue_io_opt_show(struct request_queue *q, char *page) -{ - return queue_var_show(queue_io_opt(q), page); -} - -static ssize_t queue_discard_granularity_show(struct request_queue *q, char *page) -{ - return queue_var_show(q->limits.discard_granularity, page); -} - -static ssize_t queue_discard_max_hw_show(struct request_queue *q, char *page) -{ - - return sprintf(page, "%llu\n", - (unsigned long long)q->limits.max_hw_discard_sectors << 9); -} - -static ssize_t queue_discard_max_show(struct request_queue *q, char *page) -{ - return sprintf(page, "%llu\n", - (unsigned long long)q->limits.max_discard_sectors << 9); -} - -static ssize_t queue_discard_max_store(struct request_queue *q, - const char *page, size_t count) -{ - unsigned long max_discard; - ssize_t ret = queue_var_store(&max_discard, page, count); - - if (ret < 0) - return ret; - - if (max_discard & (q->limits.discard_granularity - 1)) - return -EINVAL; - - max_discard >>= 9; - if (max_discard > UINT_MAX) - return -EINVAL; - - if (max_discard > q->limits.max_hw_discard_sectors) - max_discard = q->limits.max_hw_discard_sectors; - - q->limits.max_discard_sectors = max_discard; - return ret; -} - -static ssize_t queue_discard_zeroes_data_show(struct request_queue *q, char *page) -{ - return queue_var_show(queue_discard_zeroes_data(q), page); -} - -static ssize_t queue_write_same_max_show(struct request_queue *q, char *page) -{ - return sprintf(page, "%llu\n", - (unsigned long long)q->limits.max_write_same_sectors << 9); -} - - -static ssize_t -queue_max_sectors_store(struct request_queue *q, const char *page, size_t count) -{ - unsigned long max_sectors_kb, - max_hw_sectors_kb = queue_max_hw_sectors(q) >> 1, - page_kb = 1 << (PAGE_SHIFT - 10); - ssize_t ret = queue_var_store(&max_sectors_kb, page, count); - - if (ret < 0) - return ret; - - max_hw_sectors_kb = min_not_zero(max_hw_sectors_kb, (unsigned long) - q->limits.max_dev_sectors >> 1); - - if (max_sectors_kb > max_hw_sectors_kb || max_sectors_kb < page_kb) - return -EINVAL; - - spin_lock_irq(q->queue_lock); - q->limits.max_sectors = max_sectors_kb << 1; - spin_unlock_irq(q->queue_lock); - - return ret; -} - -static ssize_t queue_max_hw_sectors_show(struct request_queue *q, char *page) -{ - int max_hw_sectors_kb = queue_max_hw_sectors(q) >> 1; - - return queue_var_show(max_hw_sectors_kb, (page)); -} - -#define QUEUE_SYSFS_BIT_FNS(name, flag, neg) \ -static ssize_t \ -queue_show_##name(struct request_queue *q, char *page) \ -{ \ - int bit; \ - bit = test_bit(QUEUE_FLAG_##flag, &q->queue_flags); \ - return queue_var_show(neg ? !bit : bit, page); \ -} \ -static ssize_t \ -queue_store_##name(struct request_queue *q, const char *page, size_t count) \ -{ \ - unsigned long val; \ - ssize_t ret; \ - ret = queue_var_store(&val, page, count); \ - if (ret < 0) \ - return ret; \ - if (neg) \ - val = !val; \ - \ - spin_lock_irq(q->queue_lock); \ - if (val) \ - queue_flag_set(QUEUE_FLAG_##flag, q); \ - else \ - queue_flag_clear(QUEUE_FLAG_##flag, q); \ - spin_unlock_irq(q->queue_lock); \ - return ret; \ -} - -QUEUE_SYSFS_BIT_FNS(nonrot, NONROT, 1); -QUEUE_SYSFS_BIT_FNS(random, ADD_RANDOM, 0); -QUEUE_SYSFS_BIT_FNS(iostats, IO_STAT, 0); -#undef QUEUE_SYSFS_BIT_FNS - -static ssize_t queue_nomerges_show(struct request_queue *q, char *page) -{ - return queue_var_show((blk_queue_nomerges(q) << 1) | - blk_queue_noxmerges(q), page); -} - -static ssize_t queue_nomerges_store(struct request_queue *q, const char *page, - size_t count) -{ - unsigned long nm; - ssize_t ret = queue_var_store(&nm, page, count); - - if (ret < 0) - return ret; - - spin_lock_irq(q->queue_lock); - queue_flag_clear(QUEUE_FLAG_NOMERGES, q); - queue_flag_clear(QUEUE_FLAG_NOXMERGES, q); - if (nm == 2) - queue_flag_set(QUEUE_FLAG_NOMERGES, q); - else if (nm) - queue_flag_set(QUEUE_FLAG_NOXMERGES, q); - spin_unlock_irq(q->queue_lock); - - return ret; -} - -static ssize_t queue_rq_affinity_show(struct request_queue *q, char *page) -{ - bool set = test_bit(QUEUE_FLAG_SAME_COMP, &q->queue_flags); - bool force = test_bit(QUEUE_FLAG_SAME_FORCE, &q->queue_flags); - - return queue_var_show(set << force, page); -} - -static ssize_t -queue_rq_affinity_store(struct request_queue *q, const char *page, size_t count) -{ - ssize_t ret = -EINVAL; -#ifdef CONFIG_SMP - unsigned long val; - - ret = queue_var_store(&val, page, count); - if (ret < 0) - return ret; - - spin_lock_irq(q->queue_lock); - if (val == 2) { - queue_flag_set(QUEUE_FLAG_SAME_COMP, q); - queue_flag_set(QUEUE_FLAG_SAME_FORCE, q); - } else if (val == 1) { - queue_flag_set(QUEUE_FLAG_SAME_COMP, q); - queue_flag_clear(QUEUE_FLAG_SAME_FORCE, q); - } else if (val == 0) { - queue_flag_clear(QUEUE_FLAG_SAME_COMP, q); - queue_flag_clear(QUEUE_FLAG_SAME_FORCE, q); - } - spin_unlock_irq(q->queue_lock); -#endif - return ret; -} - -static ssize_t queue_poll_show(struct request_queue *q, char *page) -{ - return queue_var_show(test_bit(QUEUE_FLAG_POLL, &q->queue_flags), page); -} - -static ssize_t queue_poll_store(struct request_queue *q, const char *page, - size_t count) -{ - unsigned long poll_on; - ssize_t ret; - - if (!q->mq_ops || !q->mq_ops->poll) - return -EINVAL; - - ret = queue_var_store(&poll_on, page, count); - if (ret < 0) - return ret; - - spin_lock_irq(q->queue_lock); - if (poll_on) - queue_flag_set(QUEUE_FLAG_POLL, q); - else - queue_flag_clear(QUEUE_FLAG_POLL, q); - spin_unlock_irq(q->queue_lock); - - return ret; -} - -static ssize_t queue_wc_show(struct request_queue *q, char *page) -{ - if (test_bit(QUEUE_FLAG_WC, &q->queue_flags)) - return sprintf(page, "write back\n"); - - return sprintf(page, "write through\n"); -} - -static ssize_t queue_wc_store(struct request_queue *q, const char *page, - size_t count) -{ - int set = -1; - - if (!strncmp(page, "write back", 10)) - set = 1; - else if (!strncmp(page, "write through", 13) || - !strncmp(page, "none", 4)) - set = 0; - - if (set == -1) - return -EINVAL; - - spin_lock_irq(q->queue_lock); - if (set) - queue_flag_set(QUEUE_FLAG_WC, q); - else - queue_flag_clear(QUEUE_FLAG_WC, q); - spin_unlock_irq(q->queue_lock); - - return count; -} - -static ssize_t queue_dax_show(struct request_queue *q, char *page) -{ - return queue_var_show(blk_queue_dax(q), page); -} - -static struct queue_sysfs_entry queue_requests_entry = { - .attr = {.name = "nr_requests", .mode = S_IRUGO | S_IWUSR }, - .show = queue_requests_show, - .store = queue_requests_store, -}; - -static struct queue_sysfs_entry queue_ra_entry = { - .attr = {.name = "read_ahead_kb", .mode = S_IRUGO | S_IWUSR }, - .show = queue_ra_show, - .store = queue_ra_store, -}; - -static struct queue_sysfs_entry queue_max_sectors_entry = { - .attr = {.name = "max_sectors_kb", .mode = S_IRUGO | S_IWUSR }, - .show = queue_max_sectors_show, - .store = queue_max_sectors_store, -}; - -static struct queue_sysfs_entry queue_max_hw_sectors_entry = { - .attr = {.name = "max_hw_sectors_kb", .mode = S_IRUGO }, - .show = queue_max_hw_sectors_show, -}; - -static struct queue_sysfs_entry queue_max_segments_entry = { - .attr = {.name = "max_segments", .mode = S_IRUGO }, - .show = queue_max_segments_show, -}; - -static struct queue_sysfs_entry queue_max_integrity_segments_entry = { - .attr = {.name = "max_integrity_segments", .mode = S_IRUGO }, - .show = queue_max_integrity_segments_show, -}; - -static struct queue_sysfs_entry queue_max_segment_size_entry = { - .attr = {.name = "max_segment_size", .mode = S_IRUGO }, - .show = queue_max_segment_size_show, -}; - -static struct queue_sysfs_entry queue_iosched_entry = { - .attr = {.name = "scheduler", .mode = S_IRUGO | S_IWUSR }, - .show = elv_iosched_show, - .store = elv_iosched_store, -}; - -static struct queue_sysfs_entry queue_hw_sector_size_entry = { - .attr = {.name = "hw_sector_size", .mode = S_IRUGO }, - .show = queue_logical_block_size_show, -}; - -static struct queue_sysfs_entry queue_logical_block_size_entry = { - .attr = {.name = "logical_block_size", .mode = S_IRUGO }, - .show = queue_logical_block_size_show, -}; - -static struct queue_sysfs_entry queue_physical_block_size_entry = { - .attr = {.name = "physical_block_size", .mode = S_IRUGO }, - .show = queue_physical_block_size_show, -}; - -static struct queue_sysfs_entry queue_io_min_entry = { - .attr = {.name = "minimum_io_size", .mode = S_IRUGO }, - .show = queue_io_min_show, -}; - -static struct queue_sysfs_entry queue_io_opt_entry = { - .attr = {.name = "optimal_io_size", .mode = S_IRUGO }, - .show = queue_io_opt_show, -}; - -static struct queue_sysfs_entry queue_discard_granularity_entry = { - .attr = {.name = "discard_granularity", .mode = S_IRUGO }, - .show = queue_discard_granularity_show, -}; - -static struct queue_sysfs_entry queue_discard_max_hw_entry = { - .attr = {.name = "discard_max_hw_bytes", .mode = S_IRUGO }, - .show = queue_discard_max_hw_show, -}; - -static struct queue_sysfs_entry queue_discard_max_entry = { - .attr = {.name = "discard_max_bytes", .mode = S_IRUGO | S_IWUSR }, - .show = queue_discard_max_show, - .store = queue_discard_max_store, -}; - -static struct queue_sysfs_entry queue_discard_zeroes_data_entry = { - .attr = {.name = "discard_zeroes_data", .mode = S_IRUGO }, - .show = queue_discard_zeroes_data_show, -}; - -static struct queue_sysfs_entry queue_write_same_max_entry = { - .attr = {.name = "write_same_max_bytes", .mode = S_IRUGO }, - .show = queue_write_same_max_show, -}; - -static struct queue_sysfs_entry queue_nonrot_entry = { - .attr = {.name = "rotational", .mode = S_IRUGO | S_IWUSR }, - .show = queue_show_nonrot, - .store = queue_store_nonrot, -}; - -static struct queue_sysfs_entry queue_nomerges_entry = { - .attr = {.name = "nomerges", .mode = S_IRUGO | S_IWUSR }, - .show = queue_nomerges_show, - .store = queue_nomerges_store, -}; - -static struct queue_sysfs_entry queue_rq_affinity_entry = { - .attr = {.name = "rq_affinity", .mode = S_IRUGO | S_IWUSR }, - .show = queue_rq_affinity_show, - .store = queue_rq_affinity_store, -}; - -static struct queue_sysfs_entry queue_iostats_entry = { - .attr = {.name = "iostats", .mode = S_IRUGO | S_IWUSR }, - .show = queue_show_iostats, - .store = queue_store_iostats, -}; - -static struct queue_sysfs_entry queue_random_entry = { - .attr = {.name = "add_random", .mode = S_IRUGO | S_IWUSR }, - .show = queue_show_random, - .store = queue_store_random, -}; - -static struct queue_sysfs_entry queue_poll_entry = { - .attr = {.name = "io_poll", .mode = S_IRUGO | S_IWUSR }, - .show = queue_poll_show, - .store = queue_poll_store, -}; - -static struct queue_sysfs_entry queue_wc_entry = { - .attr = {.name = "write_cache", .mode = S_IRUGO | S_IWUSR }, - .show = queue_wc_show, - .store = queue_wc_store, -}; - -static struct queue_sysfs_entry queue_dax_entry = { - .attr = {.name = "dax", .mode = S_IRUGO }, - .show = queue_dax_show, -}; - -static struct attribute *default_attrs[] = { - &queue_requests_entry.attr, - &queue_ra_entry.attr, - &queue_max_hw_sectors_entry.attr, - &queue_max_sectors_entry.attr, - &queue_max_segments_entry.attr, - &queue_max_integrity_segments_entry.attr, - &queue_max_segment_size_entry.attr, - &queue_iosched_entry.attr, - &queue_hw_sector_size_entry.attr, - &queue_logical_block_size_entry.attr, - &queue_physical_block_size_entry.attr, - &queue_io_min_entry.attr, - &queue_io_opt_entry.attr, - &queue_discard_granularity_entry.attr, - &queue_discard_max_entry.attr, - &queue_discard_max_hw_entry.attr, - &queue_discard_zeroes_data_entry.attr, - &queue_write_same_max_entry.attr, - &queue_nonrot_entry.attr, - &queue_nomerges_entry.attr, - &queue_rq_affinity_entry.attr, - &queue_iostats_entry.attr, - &queue_random_entry.attr, - &queue_poll_entry.attr, - &queue_wc_entry.attr, - &queue_dax_entry.attr, - NULL, -}; - -#define to_queue(atr) container_of((atr), struct queue_sysfs_entry, attr) - -static ssize_t -queue_attr_show(struct kobject *kobj, struct attribute *attr, char *page) -{ - struct queue_sysfs_entry *entry = to_queue(attr); - struct request_queue *q = - container_of(kobj, struct request_queue, kobj); - ssize_t res; - - if (!entry->show) - return -EIO; - mutex_lock(&q->sysfs_lock); - if (blk_queue_dying(q)) { - mutex_unlock(&q->sysfs_lock); - return -ENOENT; - } - res = entry->show(q, page); - mutex_unlock(&q->sysfs_lock); - return res; -} - -static ssize_t -queue_attr_store(struct kobject *kobj, struct attribute *attr, - const char *page, size_t length) -{ - struct queue_sysfs_entry *entry = to_queue(attr); - struct request_queue *q; - ssize_t res; - - if (!entry->store) - return -EIO; - - q = container_of(kobj, struct request_queue, kobj); - mutex_lock(&q->sysfs_lock); - if (blk_queue_dying(q)) { - mutex_unlock(&q->sysfs_lock); - return -ENOENT; - } - res = entry->store(q, page, length); - mutex_unlock(&q->sysfs_lock); - return res; -} - -static void blk_free_queue_rcu(struct rcu_head *rcu_head) -{ - struct request_queue *q = container_of(rcu_head, struct request_queue, - rcu_head); - kmem_cache_free(blk_requestq_cachep, q); -} - -/** - * blk_release_queue: - release a &struct request_queue when it is no longer needed - * @kobj: the kobj belonging to the request queue to be released - * - * Description: - * blk_release_queue is the pair to blk_init_queue() or - * blk_queue_make_request(). It should be called when a request queue is - * being released; typically when a block device is being de-registered. - * Currently, its primary task it to free all the &struct request - * structures that were allocated to the queue and the queue itself. - * - * Note: - * The low level driver must have finished any outstanding requests first - * via blk_cleanup_queue(). - **/ -static void blk_release_queue(struct kobject *kobj) -{ - struct request_queue *q = - container_of(kobj, struct request_queue, kobj); - - bdi_exit(&q->backing_dev_info); - blkcg_exit_queue(q); - - if (q->elevator) { - spin_lock_irq(q->queue_lock); - ioc_clear_queue(q); - spin_unlock_irq(q->queue_lock); - elevator_exit(q->elevator); - } - - blk_exit_rl(&q->root_rl); - - if (q->queue_tags) - __blk_queue_free_tags(q); - - if (!q->mq_ops) - blk_free_flush_queue(q->fq); - else - blk_mq_release(q); - - blk_trace_shutdown(q); - - if (q->bio_split) - bioset_free(q->bio_split); - - ida_simple_remove(&blk_queue_ida, q->id); - call_rcu(&q->rcu_head, blk_free_queue_rcu); -} - -static const struct sysfs_ops queue_sysfs_ops = { - .show = queue_attr_show, - .store = queue_attr_store, -}; - -struct kobj_type blk_queue_ktype = { - .sysfs_ops = &queue_sysfs_ops, - .default_attrs = default_attrs, - .release = blk_release_queue, -}; - -int blk_register_queue(struct gendisk *disk) -{ - int ret; - struct device *dev = disk_to_dev(disk); - struct request_queue *q = disk->queue; - - if (WARN_ON(!q)) - return -ENXIO; - - /* - * SCSI probing may synchronously create and destroy a lot of - * request_queues for non-existent devices. Shutting down a fully - * functional queue takes measureable wallclock time as RCU grace - * periods are involved. To avoid excessive latency in these - * cases, a request_queue starts out in a degraded mode which is - * faster to shut down and is made fully functional here as - * request_queues for non-existent devices never get registered. - */ - if (!blk_queue_init_done(q)) { - queue_flag_set_unlocked(QUEUE_FLAG_INIT_DONE, q); - percpu_ref_switch_to_percpu(&q->q_usage_counter); - blk_queue_bypass_end(q); - } - - ret = blk_trace_init_sysfs(dev); - if (ret) - return ret; - - ret = kobject_add(&q->kobj, kobject_get(&dev->kobj), "%s", "queue"); - if (ret < 0) { - blk_trace_remove_sysfs(dev); - return ret; - } - - kobject_uevent(&q->kobj, KOBJ_ADD); - - if (q->mq_ops) - blk_mq_register_dev(dev, q); - - if (!q->request_fn) - return 0; - - ret = elv_register_queue(q); - if (ret) { - kobject_uevent(&q->kobj, KOBJ_REMOVE); - kobject_del(&q->kobj); - blk_trace_remove_sysfs(dev); - kobject_put(&dev->kobj); - return ret; - } - - return 0; -} - -void blk_unregister_queue(struct gendisk *disk) -{ - struct request_queue *q = disk->queue; - - if (WARN_ON(!q)) - return; - - if (q->mq_ops) - blk_mq_unregister_dev(disk_to_dev(disk), q); - - if (q->request_fn) - elv_unregister_queue(q); - - kobject_uevent(&q->kobj, KOBJ_REMOVE); - kobject_del(&q->kobj); - blk_trace_remove_sysfs(disk_to_dev(disk)); - kobject_put(&disk_to_dev(disk)->kobj); -} diff --git a/src/linux/block/blk-tag.c b/src/linux/block/blk-tag.c deleted file mode 100644 index f0344e6..0000000 --- a/src/linux/block/blk-tag.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * Functions related to tagged command queuing - */ -#include -#include -#include -#include -#include - -#include "blk.h" - -/** - * blk_queue_find_tag - find a request by its tag and queue - * @q: The request queue for the device - * @tag: The tag of the request - * - * Notes: - * Should be used when a device returns a tag and you want to match - * it with a request. - * - * no locks need be held. - **/ -struct request *blk_queue_find_tag(struct request_queue *q, int tag) -{ - return blk_map_queue_find_tag(q->queue_tags, tag); -} -EXPORT_SYMBOL(blk_queue_find_tag); - -/** - * blk_free_tags - release a given set of tag maintenance info - * @bqt: the tag map to free - * - * Drop the reference count on @bqt and frees it when the last reference - * is dropped. - */ -void blk_free_tags(struct blk_queue_tag *bqt) -{ - if (atomic_dec_and_test(&bqt->refcnt)) { - BUG_ON(find_first_bit(bqt->tag_map, bqt->max_depth) < - bqt->max_depth); - - kfree(bqt->tag_index); - bqt->tag_index = NULL; - - kfree(bqt->tag_map); - bqt->tag_map = NULL; - - kfree(bqt); - } -} -EXPORT_SYMBOL(blk_free_tags); - -/** - * __blk_queue_free_tags - release tag maintenance info - * @q: the request queue for the device - * - * Notes: - * blk_cleanup_queue() will take care of calling this function, if tagging - * has been used. So there's no need to call this directly. - **/ -void __blk_queue_free_tags(struct request_queue *q) -{ - struct blk_queue_tag *bqt = q->queue_tags; - - if (!bqt) - return; - - blk_free_tags(bqt); - - q->queue_tags = NULL; - queue_flag_clear_unlocked(QUEUE_FLAG_QUEUED, q); -} - -/** - * blk_queue_free_tags - release tag maintenance info - * @q: the request queue for the device - * - * Notes: - * This is used to disable tagged queuing to a device, yet leave - * queue in function. - **/ -void blk_queue_free_tags(struct request_queue *q) -{ - queue_flag_clear_unlocked(QUEUE_FLAG_QUEUED, q); -} -EXPORT_SYMBOL(blk_queue_free_tags); - -static int -init_tag_map(struct request_queue *q, struct blk_queue_tag *tags, int depth) -{ - struct request **tag_index; - unsigned long *tag_map; - int nr_ulongs; - - if (q && depth > q->nr_requests * 2) { - depth = q->nr_requests * 2; - printk(KERN_ERR "%s: adjusted depth to %d\n", - __func__, depth); - } - - tag_index = kzalloc(depth * sizeof(struct request *), GFP_ATOMIC); - if (!tag_index) - goto fail; - - nr_ulongs = ALIGN(depth, BITS_PER_LONG) / BITS_PER_LONG; - tag_map = kzalloc(nr_ulongs * sizeof(unsigned long), GFP_ATOMIC); - if (!tag_map) - goto fail; - - tags->real_max_depth = depth; - tags->max_depth = depth; - tags->tag_index = tag_index; - tags->tag_map = tag_map; - - return 0; -fail: - kfree(tag_index); - return -ENOMEM; -} - -static struct blk_queue_tag *__blk_queue_init_tags(struct request_queue *q, - int depth, int alloc_policy) -{ - struct blk_queue_tag *tags; - - tags = kmalloc(sizeof(struct blk_queue_tag), GFP_ATOMIC); - if (!tags) - goto fail; - - if (init_tag_map(q, tags, depth)) - goto fail; - - atomic_set(&tags->refcnt, 1); - tags->alloc_policy = alloc_policy; - tags->next_tag = 0; - return tags; -fail: - kfree(tags); - return NULL; -} - -/** - * blk_init_tags - initialize the tag info for an external tag map - * @depth: the maximum queue depth supported - * @alloc_policy: tag allocation policy - **/ -struct blk_queue_tag *blk_init_tags(int depth, int alloc_policy) -{ - return __blk_queue_init_tags(NULL, depth, alloc_policy); -} -EXPORT_SYMBOL(blk_init_tags); - -/** - * blk_queue_init_tags - initialize the queue tag info - * @q: the request queue for the device - * @depth: the maximum queue depth supported - * @tags: the tag to use - * @alloc_policy: tag allocation policy - * - * Queue lock must be held here if the function is called to resize an - * existing map. - **/ -int blk_queue_init_tags(struct request_queue *q, int depth, - struct blk_queue_tag *tags, int alloc_policy) -{ - int rc; - - BUG_ON(tags && q->queue_tags && tags != q->queue_tags); - - if (!tags && !q->queue_tags) { - tags = __blk_queue_init_tags(q, depth, alloc_policy); - - if (!tags) - return -ENOMEM; - - } else if (q->queue_tags) { - rc = blk_queue_resize_tags(q, depth); - if (rc) - return rc; - queue_flag_set(QUEUE_FLAG_QUEUED, q); - return 0; - } else - atomic_inc(&tags->refcnt); - - /* - * assign it, all done - */ - q->queue_tags = tags; - queue_flag_set_unlocked(QUEUE_FLAG_QUEUED, q); - INIT_LIST_HEAD(&q->tag_busy_list); - return 0; -} -EXPORT_SYMBOL(blk_queue_init_tags); - -/** - * blk_queue_resize_tags - change the queueing depth - * @q: the request queue for the device - * @new_depth: the new max command queueing depth - * - * Notes: - * Must be called with the queue lock held. - **/ -int blk_queue_resize_tags(struct request_queue *q, int new_depth) -{ - struct blk_queue_tag *bqt = q->queue_tags; - struct request **tag_index; - unsigned long *tag_map; - int max_depth, nr_ulongs; - - if (!bqt) - return -ENXIO; - - /* - * if we already have large enough real_max_depth. just - * adjust max_depth. *NOTE* as requests with tag value - * between new_depth and real_max_depth can be in-flight, tag - * map can not be shrunk blindly here. - */ - if (new_depth <= bqt->real_max_depth) { - bqt->max_depth = new_depth; - return 0; - } - - /* - * Currently cannot replace a shared tag map with a new - * one, so error out if this is the case - */ - if (atomic_read(&bqt->refcnt) != 1) - return -EBUSY; - - /* - * save the old state info, so we can copy it back - */ - tag_index = bqt->tag_index; - tag_map = bqt->tag_map; - max_depth = bqt->real_max_depth; - - if (init_tag_map(q, bqt, new_depth)) - return -ENOMEM; - - memcpy(bqt->tag_index, tag_index, max_depth * sizeof(struct request *)); - nr_ulongs = ALIGN(max_depth, BITS_PER_LONG) / BITS_PER_LONG; - memcpy(bqt->tag_map, tag_map, nr_ulongs * sizeof(unsigned long)); - - kfree(tag_index); - kfree(tag_map); - return 0; -} -EXPORT_SYMBOL(blk_queue_resize_tags); - -/** - * blk_queue_end_tag - end tag operations for a request - * @q: the request queue for the device - * @rq: the request that has completed - * - * Description: - * Typically called when end_that_request_first() returns %0, meaning - * all transfers have been done for a request. It's important to call - * this function before end_that_request_last(), as that will put the - * request back on the free list thus corrupting the internal tag list. - * - * Notes: - * queue lock must be held. - **/ -void blk_queue_end_tag(struct request_queue *q, struct request *rq) -{ - struct blk_queue_tag *bqt = q->queue_tags; - unsigned tag = rq->tag; /* negative tags invalid */ - - BUG_ON(tag >= bqt->real_max_depth); - - list_del_init(&rq->queuelist); - rq->cmd_flags &= ~REQ_QUEUED; - rq->tag = -1; - - if (unlikely(bqt->tag_index[tag] == NULL)) - printk(KERN_ERR "%s: tag %d is missing\n", - __func__, tag); - - bqt->tag_index[tag] = NULL; - - if (unlikely(!test_bit(tag, bqt->tag_map))) { - printk(KERN_ERR "%s: attempt to clear non-busy tag (%d)\n", - __func__, tag); - return; - } - /* - * The tag_map bit acts as a lock for tag_index[bit], so we need - * unlock memory barrier semantics. - */ - clear_bit_unlock(tag, bqt->tag_map); -} -EXPORT_SYMBOL(blk_queue_end_tag); - -/** - * blk_queue_start_tag - find a free tag and assign it - * @q: the request queue for the device - * @rq: the block request that needs tagging - * - * Description: - * This can either be used as a stand-alone helper, or possibly be - * assigned as the queue &prep_rq_fn (in which case &struct request - * automagically gets a tag assigned). Note that this function - * assumes that any type of request can be queued! if this is not - * true for your device, you must check the request type before - * calling this function. The request will also be removed from - * the request queue, so it's the drivers responsibility to readd - * it if it should need to be restarted for some reason. - * - * Notes: - * queue lock must be held. - **/ -int blk_queue_start_tag(struct request_queue *q, struct request *rq) -{ - struct blk_queue_tag *bqt = q->queue_tags; - unsigned max_depth; - int tag; - - if (unlikely((rq->cmd_flags & REQ_QUEUED))) { - printk(KERN_ERR - "%s: request %p for device [%s] already tagged %d", - __func__, rq, - rq->rq_disk ? rq->rq_disk->disk_name : "?", rq->tag); - BUG(); - } - - /* - * Protect against shared tag maps, as we may not have exclusive - * access to the tag map. - * - * We reserve a few tags just for sync IO, since we don't want - * to starve sync IO on behalf of flooding async IO. - */ - max_depth = bqt->max_depth; - if (!rq_is_sync(rq) && max_depth > 1) { - switch (max_depth) { - case 2: - max_depth = 1; - break; - case 3: - max_depth = 2; - break; - default: - max_depth -= 2; - } - if (q->in_flight[BLK_RW_ASYNC] > max_depth) - return 1; - } - - do { - if (bqt->alloc_policy == BLK_TAG_ALLOC_FIFO) { - tag = find_first_zero_bit(bqt->tag_map, max_depth); - if (tag >= max_depth) - return 1; - } else { - int start = bqt->next_tag; - int size = min_t(int, bqt->max_depth, max_depth + start); - tag = find_next_zero_bit(bqt->tag_map, size, start); - if (tag >= size && start + size > bqt->max_depth) { - size = start + size - bqt->max_depth; - tag = find_first_zero_bit(bqt->tag_map, size); - } - if (tag >= size) - return 1; - } - - } while (test_and_set_bit_lock(tag, bqt->tag_map)); - /* - * We need lock ordering semantics given by test_and_set_bit_lock. - * See blk_queue_end_tag for details. - */ - - bqt->next_tag = (tag + 1) % bqt->max_depth; - rq->cmd_flags |= REQ_QUEUED; - rq->tag = tag; - bqt->tag_index[tag] = rq; - blk_start_request(rq); - list_add(&rq->queuelist, &q->tag_busy_list); - return 0; -} -EXPORT_SYMBOL(blk_queue_start_tag); - -/** - * blk_queue_invalidate_tags - invalidate all pending tags - * @q: the request queue for the device - * - * Description: - * Hardware conditions may dictate a need to stop all pending requests. - * In this case, we will safely clear the block side of the tag queue and - * readd all requests to the request queue in the right order. - * - * Notes: - * queue lock must be held. - **/ -void blk_queue_invalidate_tags(struct request_queue *q) -{ - struct list_head *tmp, *n; - - list_for_each_safe(tmp, n, &q->tag_busy_list) - blk_requeue_request(q, list_entry_rq(tmp)); -} -EXPORT_SYMBOL(blk_queue_invalidate_tags); diff --git a/src/linux/block/blk-timeout.c b/src/linux/block/blk-timeout.c deleted file mode 100644 index a30441a..0000000 --- a/src/linux/block/blk-timeout.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Functions related to generic timeout handling of requests. - */ -#include -#include -#include -#include - -#include "blk.h" -#include "blk-mq.h" - -#ifdef CONFIG_FAIL_IO_TIMEOUT - -static DECLARE_FAULT_ATTR(fail_io_timeout); - -static int __init setup_fail_io_timeout(char *str) -{ - return setup_fault_attr(&fail_io_timeout, str); -} -__setup("fail_io_timeout=", setup_fail_io_timeout); - -int blk_should_fake_timeout(struct request_queue *q) -{ - if (!test_bit(QUEUE_FLAG_FAIL_IO, &q->queue_flags)) - return 0; - - return should_fail(&fail_io_timeout, 1); -} - -static int __init fail_io_timeout_debugfs(void) -{ - struct dentry *dir = fault_create_debugfs_attr("fail_io_timeout", - NULL, &fail_io_timeout); - - return PTR_ERR_OR_ZERO(dir); -} - -late_initcall(fail_io_timeout_debugfs); - -ssize_t part_timeout_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct gendisk *disk = dev_to_disk(dev); - int set = test_bit(QUEUE_FLAG_FAIL_IO, &disk->queue->queue_flags); - - return sprintf(buf, "%d\n", set != 0); -} - -ssize_t part_timeout_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct gendisk *disk = dev_to_disk(dev); - int val; - - if (count) { - struct request_queue *q = disk->queue; - char *p = (char *) buf; - - val = simple_strtoul(p, &p, 10); - spin_lock_irq(q->queue_lock); - if (val) - queue_flag_set(QUEUE_FLAG_FAIL_IO, q); - else - queue_flag_clear(QUEUE_FLAG_FAIL_IO, q); - spin_unlock_irq(q->queue_lock); - } - - return count; -} - -#endif /* CONFIG_FAIL_IO_TIMEOUT */ - -/* - * blk_delete_timer - Delete/cancel timer for a given function. - * @req: request that we are canceling timer for - * - */ -void blk_delete_timer(struct request *req) -{ - list_del_init(&req->timeout_list); -} - -static void blk_rq_timed_out(struct request *req) -{ - struct request_queue *q = req->q; - enum blk_eh_timer_return ret = BLK_EH_RESET_TIMER; - - if (q->rq_timed_out_fn) - ret = q->rq_timed_out_fn(req); - switch (ret) { - case BLK_EH_HANDLED: - /* Can we use req->errors here? */ - __blk_complete_request(req); - break; - case BLK_EH_RESET_TIMER: - blk_add_timer(req); - blk_clear_rq_complete(req); - break; - case BLK_EH_NOT_HANDLED: - /* - * LLD handles this for now but in the future - * we can send a request msg to abort the command - * and we can move more of the generic scsi eh code to - * the blk layer. - */ - break; - default: - printk(KERN_ERR "block: bad eh return: %d\n", ret); - break; - } -} - -static void blk_rq_check_expired(struct request *rq, unsigned long *next_timeout, - unsigned int *next_set) -{ - if (time_after_eq(jiffies, rq->deadline)) { - list_del_init(&rq->timeout_list); - - /* - * Check if we raced with end io completion - */ - if (!blk_mark_rq_complete(rq)) - blk_rq_timed_out(rq); - } else if (!*next_set || time_after(*next_timeout, rq->deadline)) { - *next_timeout = rq->deadline; - *next_set = 1; - } -} - -void blk_timeout_work(struct work_struct *work) -{ - struct request_queue *q = - container_of(work, struct request_queue, timeout_work); - unsigned long flags, next = 0; - struct request *rq, *tmp; - int next_set = 0; - - if (blk_queue_enter(q, true)) - return; - spin_lock_irqsave(q->queue_lock, flags); - - list_for_each_entry_safe(rq, tmp, &q->timeout_list, timeout_list) - blk_rq_check_expired(rq, &next, &next_set); - - if (next_set) - mod_timer(&q->timeout, round_jiffies_up(next)); - - spin_unlock_irqrestore(q->queue_lock, flags); - blk_queue_exit(q); -} - -/** - * blk_abort_request -- Request request recovery for the specified command - * @req: pointer to the request of interest - * - * This function requests that the block layer start recovery for the - * request by deleting the timer and calling the q's timeout function. - * LLDDs who implement their own error recovery MAY ignore the timeout - * event if they generated blk_abort_req. Must hold queue lock. - */ -void blk_abort_request(struct request *req) -{ - if (blk_mark_rq_complete(req)) - return; - - if (req->q->mq_ops) { - blk_mq_rq_timed_out(req, false); - } else { - blk_delete_timer(req); - blk_rq_timed_out(req); - } -} -EXPORT_SYMBOL_GPL(blk_abort_request); - -unsigned long blk_rq_timeout(unsigned long timeout) -{ - unsigned long maxt; - - maxt = round_jiffies_up(jiffies + BLK_MAX_TIMEOUT); - if (time_after(timeout, maxt)) - timeout = maxt; - - return timeout; -} - -/** - * blk_add_timer - Start timeout timer for a single request - * @req: request that is about to start running. - * - * Notes: - * Each request has its own timer, and as it is added to the queue, we - * set up the timer. When the request completes, we cancel the timer. - * Queue lock must be held for the non-mq case, mq case doesn't care. - */ -void blk_add_timer(struct request *req) -{ - struct request_queue *q = req->q; - unsigned long expiry; - - /* blk-mq has its own handler, so we don't need ->rq_timed_out_fn */ - if (!q->mq_ops && !q->rq_timed_out_fn) - return; - - BUG_ON(!list_empty(&req->timeout_list)); - - /* - * Some LLDs, like scsi, peek at the timeout to prevent a - * command from being retried forever. - */ - if (!req->timeout) - req->timeout = q->rq_timeout; - - req->deadline = jiffies + req->timeout; - - /* - * Only the non-mq case needs to add the request to a protected list. - * For the mq case we simply scan the tag map. - */ - if (!q->mq_ops) - list_add_tail(&req->timeout_list, &req->q->timeout_list); - - /* - * If the timer isn't already pending or this timeout is earlier - * than an existing one, modify the timer. Round up to next nearest - * second. - */ - expiry = blk_rq_timeout(round_jiffies_up(req->deadline)); - - if (!timer_pending(&q->timeout) || - time_before(expiry, q->timeout.expires)) { - unsigned long diff = q->timeout.expires - expiry; - - /* - * Due to added timer slack to group timers, the timer - * will often be a little in front of what we asked for. - * So apply some tolerance here too, otherwise we keep - * modifying the timer because expires for value X - * will be X + something. - */ - if (!timer_pending(&q->timeout) || (diff >= HZ / 2)) - mod_timer(&q->timeout, expiry); - } - -} diff --git a/src/linux/block/blk.h b/src/linux/block/blk.h deleted file mode 100644 index 74444c4..0000000 --- a/src/linux/block/blk.h +++ /dev/null @@ -1,298 +0,0 @@ -#ifndef BLK_INTERNAL_H -#define BLK_INTERNAL_H - -#include -#include -#include "blk-mq.h" - -/* Amount of time in which a process may batch requests */ -#define BLK_BATCH_TIME (HZ/50UL) - -/* Number of requests a "batching" process may submit */ -#define BLK_BATCH_REQ 32 - -/* Max future timer expiry for timeouts */ -#define BLK_MAX_TIMEOUT (5 * HZ) - -struct blk_flush_queue { - unsigned int flush_queue_delayed:1; - unsigned int flush_pending_idx:1; - unsigned int flush_running_idx:1; - unsigned long flush_pending_since; - struct list_head flush_queue[2]; - struct list_head flush_data_in_flight; - struct request *flush_rq; - - /* - * flush_rq shares tag with this rq, both can't be active - * at the same time - */ - struct request *orig_rq; - spinlock_t mq_flush_lock; -}; - -extern struct kmem_cache *blk_requestq_cachep; -extern struct kmem_cache *request_cachep; -extern struct kobj_type blk_queue_ktype; -extern struct ida blk_queue_ida; - -static inline struct blk_flush_queue *blk_get_flush_queue( - struct request_queue *q, struct blk_mq_ctx *ctx) -{ - if (q->mq_ops) - return blk_mq_map_queue(q, ctx->cpu)->fq; - return q->fq; -} - -static inline void __blk_get_queue(struct request_queue *q) -{ - kobject_get(&q->kobj); -} - -struct blk_flush_queue *blk_alloc_flush_queue(struct request_queue *q, - int node, int cmd_size); -void blk_free_flush_queue(struct blk_flush_queue *q); - -int blk_init_rl(struct request_list *rl, struct request_queue *q, - gfp_t gfp_mask); -void blk_exit_rl(struct request_list *rl); -void init_request_from_bio(struct request *req, struct bio *bio); -void blk_rq_bio_prep(struct request_queue *q, struct request *rq, - struct bio *bio); -void blk_queue_bypass_start(struct request_queue *q); -void blk_queue_bypass_end(struct request_queue *q); -void blk_dequeue_request(struct request *rq); -void __blk_queue_free_tags(struct request_queue *q); -bool __blk_end_bidi_request(struct request *rq, int error, - unsigned int nr_bytes, unsigned int bidi_bytes); -void blk_freeze_queue(struct request_queue *q); - -static inline void blk_queue_enter_live(struct request_queue *q) -{ - /* - * Given that running in generic_make_request() context - * guarantees that a live reference against q_usage_counter has - * been established, further references under that same context - * need not check that the queue has been frozen (marked dead). - */ - percpu_ref_get(&q->q_usage_counter); -} - -#ifdef CONFIG_BLK_DEV_INTEGRITY -void blk_flush_integrity(void); -#else -static inline void blk_flush_integrity(void) -{ -} -#endif - -void blk_timeout_work(struct work_struct *work); -unsigned long blk_rq_timeout(unsigned long timeout); -void blk_add_timer(struct request *req); -void blk_delete_timer(struct request *); - - -bool bio_attempt_front_merge(struct request_queue *q, struct request *req, - struct bio *bio); -bool bio_attempt_back_merge(struct request_queue *q, struct request *req, - struct bio *bio); -bool blk_attempt_plug_merge(struct request_queue *q, struct bio *bio, - unsigned int *request_count, - struct request **same_queue_rq); -unsigned int blk_plug_queued_count(struct request_queue *q); - -void blk_account_io_start(struct request *req, bool new_io); -void blk_account_io_completion(struct request *req, unsigned int bytes); -void blk_account_io_done(struct request *req); - -/* - * Internal atomic flags for request handling - */ -enum rq_atomic_flags { - REQ_ATOM_COMPLETE = 0, - REQ_ATOM_STARTED, -}; - -/* - * EH timer and IO completion will both attempt to 'grab' the request, make - * sure that only one of them succeeds - */ -static inline int blk_mark_rq_complete(struct request *rq) -{ - return test_and_set_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags); -} - -static inline void blk_clear_rq_complete(struct request *rq) -{ - clear_bit(REQ_ATOM_COMPLETE, &rq->atomic_flags); -} - -/* - * Internal elevator interface - */ -#define ELV_ON_HASH(rq) ((rq)->cmd_flags & REQ_HASHED) - -void blk_insert_flush(struct request *rq); - -static inline struct request *__elv_next_request(struct request_queue *q) -{ - struct request *rq; - struct blk_flush_queue *fq = blk_get_flush_queue(q, NULL); - - while (1) { - if (!list_empty(&q->queue_head)) { - rq = list_entry_rq(q->queue_head.next); - return rq; - } - - /* - * Flush request is running and flush request isn't queueable - * in the drive, we can hold the queue till flush request is - * finished. Even we don't do this, driver can't dispatch next - * requests and will requeue them. And this can improve - * throughput too. For example, we have request flush1, write1, - * flush 2. flush1 is dispatched, then queue is hold, write1 - * isn't inserted to queue. After flush1 is finished, flush2 - * will be dispatched. Since disk cache is already clean, - * flush2 will be finished very soon, so looks like flush2 is - * folded to flush1. - * Since the queue is hold, a flag is set to indicate the queue - * should be restarted later. Please see flush_end_io() for - * details. - */ - if (fq->flush_pending_idx != fq->flush_running_idx && - !queue_flush_queueable(q)) { - fq->flush_queue_delayed = 1; - return NULL; - } - if (unlikely(blk_queue_bypass(q)) || - !q->elevator->type->ops.elevator_dispatch_fn(q, 0)) - return NULL; - } -} - -static inline void elv_activate_rq(struct request_queue *q, struct request *rq) -{ - struct elevator_queue *e = q->elevator; - - if (e->type->ops.elevator_activate_req_fn) - e->type->ops.elevator_activate_req_fn(q, rq); -} - -static inline void elv_deactivate_rq(struct request_queue *q, struct request *rq) -{ - struct elevator_queue *e = q->elevator; - - if (e->type->ops.elevator_deactivate_req_fn) - e->type->ops.elevator_deactivate_req_fn(q, rq); -} - -#ifdef CONFIG_FAIL_IO_TIMEOUT -int blk_should_fake_timeout(struct request_queue *); -ssize_t part_timeout_show(struct device *, struct device_attribute *, char *); -ssize_t part_timeout_store(struct device *, struct device_attribute *, - const char *, size_t); -#else -static inline int blk_should_fake_timeout(struct request_queue *q) -{ - return 0; -} -#endif - -int ll_back_merge_fn(struct request_queue *q, struct request *req, - struct bio *bio); -int ll_front_merge_fn(struct request_queue *q, struct request *req, - struct bio *bio); -int attempt_back_merge(struct request_queue *q, struct request *rq); -int attempt_front_merge(struct request_queue *q, struct request *rq); -int blk_attempt_req_merge(struct request_queue *q, struct request *rq, - struct request *next); -void blk_recalc_rq_segments(struct request *rq); -void blk_rq_set_mixed_merge(struct request *rq); -bool blk_rq_merge_ok(struct request *rq, struct bio *bio); -int blk_try_merge(struct request *rq, struct bio *bio); - -void blk_queue_congestion_threshold(struct request_queue *q); - -int blk_dev_init(void); - - -/* - * Return the threshold (number of used requests) at which the queue is - * considered to be congested. It include a little hysteresis to keep the - * context switch rate down. - */ -static inline int queue_congestion_on_threshold(struct request_queue *q) -{ - return q->nr_congestion_on; -} - -/* - * The threshold at which a queue is considered to be uncongested - */ -static inline int queue_congestion_off_threshold(struct request_queue *q) -{ - return q->nr_congestion_off; -} - -extern int blk_update_nr_requests(struct request_queue *, unsigned int); - -/* - * Contribute to IO statistics IFF: - * - * a) it's attached to a gendisk, and - * b) the queue had IO stats enabled when this request was started, and - * c) it's a file system request - */ -static inline int blk_do_io_stat(struct request *rq) -{ - return rq->rq_disk && - (rq->cmd_flags & REQ_IO_STAT) && - (rq->cmd_type == REQ_TYPE_FS); -} - -/* - * Internal io_context interface - */ -void get_io_context(struct io_context *ioc); -struct io_cq *ioc_lookup_icq(struct io_context *ioc, struct request_queue *q); -struct io_cq *ioc_create_icq(struct io_context *ioc, struct request_queue *q, - gfp_t gfp_mask); -void ioc_clear_queue(struct request_queue *q); - -int create_task_io_context(struct task_struct *task, gfp_t gfp_mask, int node); - -/** - * create_io_context - try to create task->io_context - * @gfp_mask: allocation mask - * @node: allocation node - * - * If %current->io_context is %NULL, allocate a new io_context and install - * it. Returns the current %current->io_context which may be %NULL if - * allocation failed. - * - * Note that this function can't be called with IRQ disabled because - * task_lock which protects %current->io_context is IRQ-unsafe. - */ -static inline struct io_context *create_io_context(gfp_t gfp_mask, int node) -{ - WARN_ON_ONCE(irqs_disabled()); - if (unlikely(!current->io_context)) - create_task_io_context(current, gfp_mask, node); - return current->io_context; -} - -/* - * Internal throttling interface - */ -#ifdef CONFIG_BLK_DEV_THROTTLING -extern void blk_throtl_drain(struct request_queue *q); -extern int blk_throtl_init(struct request_queue *q); -extern void blk_throtl_exit(struct request_queue *q); -#else /* CONFIG_BLK_DEV_THROTTLING */ -static inline void blk_throtl_drain(struct request_queue *q) { } -static inline int blk_throtl_init(struct request_queue *q) { return 0; } -static inline void blk_throtl_exit(struct request_queue *q) { } -#endif /* CONFIG_BLK_DEV_THROTTLING */ - -#endif /* BLK_INTERNAL_H */ diff --git a/src/linux/block/cfq-iosched.c b/src/linux/block/cfq-iosched.c deleted file mode 100644 index 5e24d88..0000000 --- a/src/linux/block/cfq-iosched.c +++ /dev/null @@ -1,4927 +0,0 @@ -/* - * CFQ, or complete fairness queueing, disk scheduler. - * - * Based on ideas from a previously unfinished io - * scheduler (round robin per-process disk scheduling) and Andrea Arcangeli. - * - * Copyright (C) 2003 Jens Axboe - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "blk.h" - -/* - * tunables - */ -/* max queue in one round of service */ -static const int cfq_quantum = 8; -static const u64 cfq_fifo_expire[2] = { NSEC_PER_SEC / 4, NSEC_PER_SEC / 8 }; -/* maximum backwards seek, in KiB */ -static const int cfq_back_max = 16 * 1024; -/* penalty of a backwards seek */ -static const int cfq_back_penalty = 2; -static const u64 cfq_slice_sync = NSEC_PER_SEC / 10; -static u64 cfq_slice_async = NSEC_PER_SEC / 25; -static const int cfq_slice_async_rq = 2; -static u64 cfq_slice_idle = NSEC_PER_SEC / 125; -static u64 cfq_group_idle = NSEC_PER_SEC / 125; -static const u64 cfq_target_latency = (u64)NSEC_PER_SEC * 3/10; /* 300 ms */ -static const int cfq_hist_divisor = 4; - -/* - * offset from end of service tree - */ -#define CFQ_IDLE_DELAY (NSEC_PER_SEC / 5) - -/* - * below this threshold, we consider thinktime immediate - */ -#define CFQ_MIN_TT (2 * NSEC_PER_SEC / HZ) - -#define CFQ_SLICE_SCALE (5) -#define CFQ_HW_QUEUE_MIN (5) -#define CFQ_SERVICE_SHIFT 12 - -#define CFQQ_SEEK_THR (sector_t)(8 * 100) -#define CFQQ_CLOSE_THR (sector_t)(8 * 1024) -#define CFQQ_SECT_THR_NONROT (sector_t)(2 * 32) -#define CFQQ_SEEKY(cfqq) (hweight32(cfqq->seek_history) > 32/8) - -#define RQ_CIC(rq) icq_to_cic((rq)->elv.icq) -#define RQ_CFQQ(rq) (struct cfq_queue *) ((rq)->elv.priv[0]) -#define RQ_CFQG(rq) (struct cfq_group *) ((rq)->elv.priv[1]) - -static struct kmem_cache *cfq_pool; - -#define CFQ_PRIO_LISTS IOPRIO_BE_NR -#define cfq_class_idle(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE) -#define cfq_class_rt(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_RT) - -#define sample_valid(samples) ((samples) > 80) -#define rb_entry_cfqg(node) rb_entry((node), struct cfq_group, rb_node) - -/* blkio-related constants */ -#define CFQ_WEIGHT_LEGACY_MIN 10 -#define CFQ_WEIGHT_LEGACY_DFL 500 -#define CFQ_WEIGHT_LEGACY_MAX 1000 - -struct cfq_ttime { - u64 last_end_request; - - u64 ttime_total; - u64 ttime_mean; - unsigned long ttime_samples; -}; - -/* - * Most of our rbtree usage is for sorting with min extraction, so - * if we cache the leftmost node we don't have to walk down the tree - * to find it. Idea borrowed from Ingo Molnars CFS scheduler. We should - * move this into the elevator for the rq sorting as well. - */ -struct cfq_rb_root { - struct rb_root rb; - struct rb_node *left; - unsigned count; - u64 min_vdisktime; - struct cfq_ttime ttime; -}; -#define CFQ_RB_ROOT (struct cfq_rb_root) { .rb = RB_ROOT, \ - .ttime = {.last_end_request = ktime_get_ns(),},} - -/* - * Per process-grouping structure - */ -struct cfq_queue { - /* reference count */ - int ref; - /* various state flags, see below */ - unsigned int flags; - /* parent cfq_data */ - struct cfq_data *cfqd; - /* service_tree member */ - struct rb_node rb_node; - /* service_tree key */ - u64 rb_key; - /* prio tree member */ - struct rb_node p_node; - /* prio tree root we belong to, if any */ - struct rb_root *p_root; - /* sorted list of pending requests */ - struct rb_root sort_list; - /* if fifo isn't expired, next request to serve */ - struct request *next_rq; - /* requests queued in sort_list */ - int queued[2]; - /* currently allocated requests */ - int allocated[2]; - /* fifo list of requests in sort_list */ - struct list_head fifo; - - /* time when queue got scheduled in to dispatch first request. */ - u64 dispatch_start; - u64 allocated_slice; - u64 slice_dispatch; - /* time when first request from queue completed and slice started. */ - u64 slice_start; - u64 slice_end; - s64 slice_resid; - - /* pending priority requests */ - int prio_pending; - /* number of requests that are on the dispatch list or inside driver */ - int dispatched; - - /* io prio of this group */ - unsigned short ioprio, org_ioprio; - unsigned short ioprio_class, org_ioprio_class; - - pid_t pid; - - u32 seek_history; - sector_t last_request_pos; - - struct cfq_rb_root *service_tree; - struct cfq_queue *new_cfqq; - struct cfq_group *cfqg; - /* Number of sectors dispatched from queue in single dispatch round */ - unsigned long nr_sectors; -}; - -/* - * First index in the service_trees. - * IDLE is handled separately, so it has negative index - */ -enum wl_class_t { - BE_WORKLOAD = 0, - RT_WORKLOAD = 1, - IDLE_WORKLOAD = 2, - CFQ_PRIO_NR, -}; - -/* - * Second index in the service_trees. - */ -enum wl_type_t { - ASYNC_WORKLOAD = 0, - SYNC_NOIDLE_WORKLOAD = 1, - SYNC_WORKLOAD = 2 -}; - -struct cfqg_stats { -#ifdef CONFIG_CFQ_GROUP_IOSCHED - /* number of ios merged */ - struct blkg_rwstat merged; - /* total time spent on device in ns, may not be accurate w/ queueing */ - struct blkg_rwstat service_time; - /* total time spent waiting in scheduler queue in ns */ - struct blkg_rwstat wait_time; - /* number of IOs queued up */ - struct blkg_rwstat queued; - /* total disk time and nr sectors dispatched by this group */ - struct blkg_stat time; -#ifdef CONFIG_DEBUG_BLK_CGROUP - /* time not charged to this cgroup */ - struct blkg_stat unaccounted_time; - /* sum of number of ios queued across all samples */ - struct blkg_stat avg_queue_size_sum; - /* count of samples taken for average */ - struct blkg_stat avg_queue_size_samples; - /* how many times this group has been removed from service tree */ - struct blkg_stat dequeue; - /* total time spent waiting for it to be assigned a timeslice. */ - struct blkg_stat group_wait_time; - /* time spent idling for this blkcg_gq */ - struct blkg_stat idle_time; - /* total time with empty current active q with other requests queued */ - struct blkg_stat empty_time; - /* fields after this shouldn't be cleared on stat reset */ - uint64_t start_group_wait_time; - uint64_t start_idle_time; - uint64_t start_empty_time; - uint16_t flags; -#endif /* CONFIG_DEBUG_BLK_CGROUP */ -#endif /* CONFIG_CFQ_GROUP_IOSCHED */ -}; - -/* Per-cgroup data */ -struct cfq_group_data { - /* must be the first member */ - struct blkcg_policy_data cpd; - - unsigned int weight; - unsigned int leaf_weight; -}; - -/* This is per cgroup per device grouping structure */ -struct cfq_group { - /* must be the first member */ - struct blkg_policy_data pd; - - /* group service_tree member */ - struct rb_node rb_node; - - /* group service_tree key */ - u64 vdisktime; - - /* - * The number of active cfqgs and sum of their weights under this - * cfqg. This covers this cfqg's leaf_weight and all children's - * weights, but does not cover weights of further descendants. - * - * If a cfqg is on the service tree, it's active. An active cfqg - * also activates its parent and contributes to the children_weight - * of the parent. - */ - int nr_active; - unsigned int children_weight; - - /* - * vfraction is the fraction of vdisktime that the tasks in this - * cfqg are entitled to. This is determined by compounding the - * ratios walking up from this cfqg to the root. - * - * It is in fixed point w/ CFQ_SERVICE_SHIFT and the sum of all - * vfractions on a service tree is approximately 1. The sum may - * deviate a bit due to rounding errors and fluctuations caused by - * cfqgs entering and leaving the service tree. - */ - unsigned int vfraction; - - /* - * There are two weights - (internal) weight is the weight of this - * cfqg against the sibling cfqgs. leaf_weight is the wight of - * this cfqg against the child cfqgs. For the root cfqg, both - * weights are kept in sync for backward compatibility. - */ - unsigned int weight; - unsigned int new_weight; - unsigned int dev_weight; - - unsigned int leaf_weight; - unsigned int new_leaf_weight; - unsigned int dev_leaf_weight; - - /* number of cfqq currently on this group */ - int nr_cfqq; - - /* - * Per group busy queues average. Useful for workload slice calc. We - * create the array for each prio class but at run time it is used - * only for RT and BE class and slot for IDLE class remains unused. - * This is primarily done to avoid confusion and a gcc warning. - */ - unsigned int busy_queues_avg[CFQ_PRIO_NR]; - /* - * rr lists of queues with requests. We maintain service trees for - * RT and BE classes. These trees are subdivided in subclasses - * of SYNC, SYNC_NOIDLE and ASYNC based on workload type. For IDLE - * class there is no subclassification and all the cfq queues go on - * a single tree service_tree_idle. - * Counts are embedded in the cfq_rb_root - */ - struct cfq_rb_root service_trees[2][3]; - struct cfq_rb_root service_tree_idle; - - u64 saved_wl_slice; - enum wl_type_t saved_wl_type; - enum wl_class_t saved_wl_class; - - /* number of requests that are on the dispatch list or inside driver */ - int dispatched; - struct cfq_ttime ttime; - struct cfqg_stats stats; /* stats for this cfqg */ - - /* async queue for each priority case */ - struct cfq_queue *async_cfqq[2][IOPRIO_BE_NR]; - struct cfq_queue *async_idle_cfqq; - -}; - -struct cfq_io_cq { - struct io_cq icq; /* must be the first member */ - struct cfq_queue *cfqq[2]; - struct cfq_ttime ttime; - int ioprio; /* the current ioprio */ -#ifdef CONFIG_CFQ_GROUP_IOSCHED - uint64_t blkcg_serial_nr; /* the current blkcg serial */ -#endif -}; - -/* - * Per block device queue structure - */ -struct cfq_data { - struct request_queue *queue; - /* Root service tree for cfq_groups */ - struct cfq_rb_root grp_service_tree; - struct cfq_group *root_group; - - /* - * The priority currently being served - */ - enum wl_class_t serving_wl_class; - enum wl_type_t serving_wl_type; - u64 workload_expires; - struct cfq_group *serving_group; - - /* - * Each priority tree is sorted by next_request position. These - * trees are used when determining if two or more queues are - * interleaving requests (see cfq_close_cooperator). - */ - struct rb_root prio_trees[CFQ_PRIO_LISTS]; - - unsigned int busy_queues; - unsigned int busy_sync_queues; - - int rq_in_driver; - int rq_in_flight[2]; - - /* - * queue-depth detection - */ - int rq_queued; - int hw_tag; - /* - * hw_tag can be - * -1 => indeterminate, (cfq will behave as if NCQ is present, to allow better detection) - * 1 => NCQ is present (hw_tag_est_depth is the estimated max depth) - * 0 => no NCQ - */ - int hw_tag_est_depth; - unsigned int hw_tag_samples; - - /* - * idle window management - */ - struct hrtimer idle_slice_timer; - struct work_struct unplug_work; - - struct cfq_queue *active_queue; - struct cfq_io_cq *active_cic; - - sector_t last_position; - - /* - * tunables, see top of file - */ - unsigned int cfq_quantum; - unsigned int cfq_back_penalty; - unsigned int cfq_back_max; - unsigned int cfq_slice_async_rq; - unsigned int cfq_latency; - u64 cfq_fifo_expire[2]; - u64 cfq_slice[2]; - u64 cfq_slice_idle; - u64 cfq_group_idle; - u64 cfq_target_latency; - - /* - * Fallback dummy cfqq for extreme OOM conditions - */ - struct cfq_queue oom_cfqq; - - u64 last_delayed_sync; -}; - -static struct cfq_group *cfq_get_next_cfqg(struct cfq_data *cfqd); -static void cfq_put_queue(struct cfq_queue *cfqq); - -static struct cfq_rb_root *st_for(struct cfq_group *cfqg, - enum wl_class_t class, - enum wl_type_t type) -{ - if (!cfqg) - return NULL; - - if (class == IDLE_WORKLOAD) - return &cfqg->service_tree_idle; - - return &cfqg->service_trees[class][type]; -} - -enum cfqq_state_flags { - CFQ_CFQQ_FLAG_on_rr = 0, /* on round-robin busy list */ - CFQ_CFQQ_FLAG_wait_request, /* waiting for a request */ - CFQ_CFQQ_FLAG_must_dispatch, /* must be allowed a dispatch */ - CFQ_CFQQ_FLAG_must_alloc_slice, /* per-slice must_alloc flag */ - CFQ_CFQQ_FLAG_fifo_expire, /* FIFO checked in this slice */ - CFQ_CFQQ_FLAG_idle_window, /* slice idling enabled */ - CFQ_CFQQ_FLAG_prio_changed, /* task priority has changed */ - CFQ_CFQQ_FLAG_slice_new, /* no requests dispatched in slice */ - CFQ_CFQQ_FLAG_sync, /* synchronous queue */ - CFQ_CFQQ_FLAG_coop, /* cfqq is shared */ - CFQ_CFQQ_FLAG_split_coop, /* shared cfqq will be splitted */ - CFQ_CFQQ_FLAG_deep, /* sync cfqq experienced large depth */ - CFQ_CFQQ_FLAG_wait_busy, /* Waiting for next request */ -}; - -#define CFQ_CFQQ_FNS(name) \ -static inline void cfq_mark_cfqq_##name(struct cfq_queue *cfqq) \ -{ \ - (cfqq)->flags |= (1 << CFQ_CFQQ_FLAG_##name); \ -} \ -static inline void cfq_clear_cfqq_##name(struct cfq_queue *cfqq) \ -{ \ - (cfqq)->flags &= ~(1 << CFQ_CFQQ_FLAG_##name); \ -} \ -static inline int cfq_cfqq_##name(const struct cfq_queue *cfqq) \ -{ \ - return ((cfqq)->flags & (1 << CFQ_CFQQ_FLAG_##name)) != 0; \ -} - -CFQ_CFQQ_FNS(on_rr); -CFQ_CFQQ_FNS(wait_request); -CFQ_CFQQ_FNS(must_dispatch); -CFQ_CFQQ_FNS(must_alloc_slice); -CFQ_CFQQ_FNS(fifo_expire); -CFQ_CFQQ_FNS(idle_window); -CFQ_CFQQ_FNS(prio_changed); -CFQ_CFQQ_FNS(slice_new); -CFQ_CFQQ_FNS(sync); -CFQ_CFQQ_FNS(coop); -CFQ_CFQQ_FNS(split_coop); -CFQ_CFQQ_FNS(deep); -CFQ_CFQQ_FNS(wait_busy); -#undef CFQ_CFQQ_FNS - -#if defined(CONFIG_CFQ_GROUP_IOSCHED) && defined(CONFIG_DEBUG_BLK_CGROUP) - -/* cfqg stats flags */ -enum cfqg_stats_flags { - CFQG_stats_waiting = 0, - CFQG_stats_idling, - CFQG_stats_empty, -}; - -#define CFQG_FLAG_FNS(name) \ -static inline void cfqg_stats_mark_##name(struct cfqg_stats *stats) \ -{ \ - stats->flags |= (1 << CFQG_stats_##name); \ -} \ -static inline void cfqg_stats_clear_##name(struct cfqg_stats *stats) \ -{ \ - stats->flags &= ~(1 << CFQG_stats_##name); \ -} \ -static inline int cfqg_stats_##name(struct cfqg_stats *stats) \ -{ \ - return (stats->flags & (1 << CFQG_stats_##name)) != 0; \ -} \ - -CFQG_FLAG_FNS(waiting) -CFQG_FLAG_FNS(idling) -CFQG_FLAG_FNS(empty) -#undef CFQG_FLAG_FNS - -/* This should be called with the queue_lock held. */ -static void cfqg_stats_update_group_wait_time(struct cfqg_stats *stats) -{ - unsigned long long now; - - if (!cfqg_stats_waiting(stats)) - return; - - now = sched_clock(); - if (time_after64(now, stats->start_group_wait_time)) - blkg_stat_add(&stats->group_wait_time, - now - stats->start_group_wait_time); - cfqg_stats_clear_waiting(stats); -} - -/* This should be called with the queue_lock held. */ -static void cfqg_stats_set_start_group_wait_time(struct cfq_group *cfqg, - struct cfq_group *curr_cfqg) -{ - struct cfqg_stats *stats = &cfqg->stats; - - if (cfqg_stats_waiting(stats)) - return; - if (cfqg == curr_cfqg) - return; - stats->start_group_wait_time = sched_clock(); - cfqg_stats_mark_waiting(stats); -} - -/* This should be called with the queue_lock held. */ -static void cfqg_stats_end_empty_time(struct cfqg_stats *stats) -{ - unsigned long long now; - - if (!cfqg_stats_empty(stats)) - return; - - now = sched_clock(); - if (time_after64(now, stats->start_empty_time)) - blkg_stat_add(&stats->empty_time, - now - stats->start_empty_time); - cfqg_stats_clear_empty(stats); -} - -static void cfqg_stats_update_dequeue(struct cfq_group *cfqg) -{ - blkg_stat_add(&cfqg->stats.dequeue, 1); -} - -static void cfqg_stats_set_start_empty_time(struct cfq_group *cfqg) -{ - struct cfqg_stats *stats = &cfqg->stats; - - if (blkg_rwstat_total(&stats->queued)) - return; - - /* - * group is already marked empty. This can happen if cfqq got new - * request in parent group and moved to this group while being added - * to service tree. Just ignore the event and move on. - */ - if (cfqg_stats_empty(stats)) - return; - - stats->start_empty_time = sched_clock(); - cfqg_stats_mark_empty(stats); -} - -static void cfqg_stats_update_idle_time(struct cfq_group *cfqg) -{ - struct cfqg_stats *stats = &cfqg->stats; - - if (cfqg_stats_idling(stats)) { - unsigned long long now = sched_clock(); - - if (time_after64(now, stats->start_idle_time)) - blkg_stat_add(&stats->idle_time, - now - stats->start_idle_time); - cfqg_stats_clear_idling(stats); - } -} - -static void cfqg_stats_set_start_idle_time(struct cfq_group *cfqg) -{ - struct cfqg_stats *stats = &cfqg->stats; - - BUG_ON(cfqg_stats_idling(stats)); - - stats->start_idle_time = sched_clock(); - cfqg_stats_mark_idling(stats); -} - -static void cfqg_stats_update_avg_queue_size(struct cfq_group *cfqg) -{ - struct cfqg_stats *stats = &cfqg->stats; - - blkg_stat_add(&stats->avg_queue_size_sum, - blkg_rwstat_total(&stats->queued)); - blkg_stat_add(&stats->avg_queue_size_samples, 1); - cfqg_stats_update_group_wait_time(stats); -} - -#else /* CONFIG_CFQ_GROUP_IOSCHED && CONFIG_DEBUG_BLK_CGROUP */ - -static inline void cfqg_stats_set_start_group_wait_time(struct cfq_group *cfqg, struct cfq_group *curr_cfqg) { } -static inline void cfqg_stats_end_empty_time(struct cfqg_stats *stats) { } -static inline void cfqg_stats_update_dequeue(struct cfq_group *cfqg) { } -static inline void cfqg_stats_set_start_empty_time(struct cfq_group *cfqg) { } -static inline void cfqg_stats_update_idle_time(struct cfq_group *cfqg) { } -static inline void cfqg_stats_set_start_idle_time(struct cfq_group *cfqg) { } -static inline void cfqg_stats_update_avg_queue_size(struct cfq_group *cfqg) { } - -#endif /* CONFIG_CFQ_GROUP_IOSCHED && CONFIG_DEBUG_BLK_CGROUP */ - -#ifdef CONFIG_CFQ_GROUP_IOSCHED - -static inline struct cfq_group *pd_to_cfqg(struct blkg_policy_data *pd) -{ - return pd ? container_of(pd, struct cfq_group, pd) : NULL; -} - -static struct cfq_group_data -*cpd_to_cfqgd(struct blkcg_policy_data *cpd) -{ - return cpd ? container_of(cpd, struct cfq_group_data, cpd) : NULL; -} - -static inline struct blkcg_gq *cfqg_to_blkg(struct cfq_group *cfqg) -{ - return pd_to_blkg(&cfqg->pd); -} - -static struct blkcg_policy blkcg_policy_cfq; - -static inline struct cfq_group *blkg_to_cfqg(struct blkcg_gq *blkg) -{ - return pd_to_cfqg(blkg_to_pd(blkg, &blkcg_policy_cfq)); -} - -static struct cfq_group_data *blkcg_to_cfqgd(struct blkcg *blkcg) -{ - return cpd_to_cfqgd(blkcg_to_cpd(blkcg, &blkcg_policy_cfq)); -} - -static inline struct cfq_group *cfqg_parent(struct cfq_group *cfqg) -{ - struct blkcg_gq *pblkg = cfqg_to_blkg(cfqg)->parent; - - return pblkg ? blkg_to_cfqg(pblkg) : NULL; -} - -static inline bool cfqg_is_descendant(struct cfq_group *cfqg, - struct cfq_group *ancestor) -{ - return cgroup_is_descendant(cfqg_to_blkg(cfqg)->blkcg->css.cgroup, - cfqg_to_blkg(ancestor)->blkcg->css.cgroup); -} - -static inline void cfqg_get(struct cfq_group *cfqg) -{ - return blkg_get(cfqg_to_blkg(cfqg)); -} - -static inline void cfqg_put(struct cfq_group *cfqg) -{ - return blkg_put(cfqg_to_blkg(cfqg)); -} - -#define cfq_log_cfqq(cfqd, cfqq, fmt, args...) do { \ - char __pbuf[128]; \ - \ - blkg_path(cfqg_to_blkg((cfqq)->cfqg), __pbuf, sizeof(__pbuf)); \ - blk_add_trace_msg((cfqd)->queue, "cfq%d%c%c %s " fmt, (cfqq)->pid, \ - cfq_cfqq_sync((cfqq)) ? 'S' : 'A', \ - cfqq_type((cfqq)) == SYNC_NOIDLE_WORKLOAD ? 'N' : ' ',\ - __pbuf, ##args); \ -} while (0) - -#define cfq_log_cfqg(cfqd, cfqg, fmt, args...) do { \ - char __pbuf[128]; \ - \ - blkg_path(cfqg_to_blkg(cfqg), __pbuf, sizeof(__pbuf)); \ - blk_add_trace_msg((cfqd)->queue, "%s " fmt, __pbuf, ##args); \ -} while (0) - -static inline void cfqg_stats_update_io_add(struct cfq_group *cfqg, - struct cfq_group *curr_cfqg, int op, - int op_flags) -{ - blkg_rwstat_add(&cfqg->stats.queued, op, op_flags, 1); - cfqg_stats_end_empty_time(&cfqg->stats); - cfqg_stats_set_start_group_wait_time(cfqg, curr_cfqg); -} - -static inline void cfqg_stats_update_timeslice_used(struct cfq_group *cfqg, - uint64_t time, unsigned long unaccounted_time) -{ - blkg_stat_add(&cfqg->stats.time, time); -#ifdef CONFIG_DEBUG_BLK_CGROUP - blkg_stat_add(&cfqg->stats.unaccounted_time, unaccounted_time); -#endif -} - -static inline void cfqg_stats_update_io_remove(struct cfq_group *cfqg, int op, - int op_flags) -{ - blkg_rwstat_add(&cfqg->stats.queued, op, op_flags, -1); -} - -static inline void cfqg_stats_update_io_merged(struct cfq_group *cfqg, int op, - int op_flags) -{ - blkg_rwstat_add(&cfqg->stats.merged, op, op_flags, 1); -} - -static inline void cfqg_stats_update_completion(struct cfq_group *cfqg, - uint64_t start_time, uint64_t io_start_time, int op, - int op_flags) -{ - struct cfqg_stats *stats = &cfqg->stats; - unsigned long long now = sched_clock(); - - if (time_after64(now, io_start_time)) - blkg_rwstat_add(&stats->service_time, op, op_flags, - now - io_start_time); - if (time_after64(io_start_time, start_time)) - blkg_rwstat_add(&stats->wait_time, op, op_flags, - io_start_time - start_time); -} - -/* @stats = 0 */ -static void cfqg_stats_reset(struct cfqg_stats *stats) -{ - /* queued stats shouldn't be cleared */ - blkg_rwstat_reset(&stats->merged); - blkg_rwstat_reset(&stats->service_time); - blkg_rwstat_reset(&stats->wait_time); - blkg_stat_reset(&stats->time); -#ifdef CONFIG_DEBUG_BLK_CGROUP - blkg_stat_reset(&stats->unaccounted_time); - blkg_stat_reset(&stats->avg_queue_size_sum); - blkg_stat_reset(&stats->avg_queue_size_samples); - blkg_stat_reset(&stats->dequeue); - blkg_stat_reset(&stats->group_wait_time); - blkg_stat_reset(&stats->idle_time); - blkg_stat_reset(&stats->empty_time); -#endif -} - -/* @to += @from */ -static void cfqg_stats_add_aux(struct cfqg_stats *to, struct cfqg_stats *from) -{ - /* queued stats shouldn't be cleared */ - blkg_rwstat_add_aux(&to->merged, &from->merged); - blkg_rwstat_add_aux(&to->service_time, &from->service_time); - blkg_rwstat_add_aux(&to->wait_time, &from->wait_time); - blkg_stat_add_aux(&from->time, &from->time); -#ifdef CONFIG_DEBUG_BLK_CGROUP - blkg_stat_add_aux(&to->unaccounted_time, &from->unaccounted_time); - blkg_stat_add_aux(&to->avg_queue_size_sum, &from->avg_queue_size_sum); - blkg_stat_add_aux(&to->avg_queue_size_samples, &from->avg_queue_size_samples); - blkg_stat_add_aux(&to->dequeue, &from->dequeue); - blkg_stat_add_aux(&to->group_wait_time, &from->group_wait_time); - blkg_stat_add_aux(&to->idle_time, &from->idle_time); - blkg_stat_add_aux(&to->empty_time, &from->empty_time); -#endif -} - -/* - * Transfer @cfqg's stats to its parent's aux counts so that the ancestors' - * recursive stats can still account for the amount used by this cfqg after - * it's gone. - */ -static void cfqg_stats_xfer_dead(struct cfq_group *cfqg) -{ - struct cfq_group *parent = cfqg_parent(cfqg); - - lockdep_assert_held(cfqg_to_blkg(cfqg)->q->queue_lock); - - if (unlikely(!parent)) - return; - - cfqg_stats_add_aux(&parent->stats, &cfqg->stats); - cfqg_stats_reset(&cfqg->stats); -} - -#else /* CONFIG_CFQ_GROUP_IOSCHED */ - -static inline struct cfq_group *cfqg_parent(struct cfq_group *cfqg) { return NULL; } -static inline bool cfqg_is_descendant(struct cfq_group *cfqg, - struct cfq_group *ancestor) -{ - return true; -} -static inline void cfqg_get(struct cfq_group *cfqg) { } -static inline void cfqg_put(struct cfq_group *cfqg) { } - -#define cfq_log_cfqq(cfqd, cfqq, fmt, args...) \ - blk_add_trace_msg((cfqd)->queue, "cfq%d%c%c " fmt, (cfqq)->pid, \ - cfq_cfqq_sync((cfqq)) ? 'S' : 'A', \ - cfqq_type((cfqq)) == SYNC_NOIDLE_WORKLOAD ? 'N' : ' ',\ - ##args) -#define cfq_log_cfqg(cfqd, cfqg, fmt, args...) do {} while (0) - -static inline void cfqg_stats_update_io_add(struct cfq_group *cfqg, - struct cfq_group *curr_cfqg, int op, int op_flags) { } -static inline void cfqg_stats_update_timeslice_used(struct cfq_group *cfqg, - uint64_t time, unsigned long unaccounted_time) { } -static inline void cfqg_stats_update_io_remove(struct cfq_group *cfqg, int op, - int op_flags) { } -static inline void cfqg_stats_update_io_merged(struct cfq_group *cfqg, int op, - int op_flags) { } -static inline void cfqg_stats_update_completion(struct cfq_group *cfqg, - uint64_t start_time, uint64_t io_start_time, int op, - int op_flags) { } - -#endif /* CONFIG_CFQ_GROUP_IOSCHED */ - -#define cfq_log(cfqd, fmt, args...) \ - blk_add_trace_msg((cfqd)->queue, "cfq " fmt, ##args) - -/* Traverses through cfq group service trees */ -#define for_each_cfqg_st(cfqg, i, j, st) \ - for (i = 0; i <= IDLE_WORKLOAD; i++) \ - for (j = 0, st = i < IDLE_WORKLOAD ? &cfqg->service_trees[i][j]\ - : &cfqg->service_tree_idle; \ - (i < IDLE_WORKLOAD && j <= SYNC_WORKLOAD) || \ - (i == IDLE_WORKLOAD && j == 0); \ - j++, st = i < IDLE_WORKLOAD ? \ - &cfqg->service_trees[i][j]: NULL) \ - -static inline bool cfq_io_thinktime_big(struct cfq_data *cfqd, - struct cfq_ttime *ttime, bool group_idle) -{ - u64 slice; - if (!sample_valid(ttime->ttime_samples)) - return false; - if (group_idle) - slice = cfqd->cfq_group_idle; - else - slice = cfqd->cfq_slice_idle; - return ttime->ttime_mean > slice; -} - -static inline bool iops_mode(struct cfq_data *cfqd) -{ - /* - * If we are not idling on queues and it is a NCQ drive, parallel - * execution of requests is on and measuring time is not possible - * in most of the cases until and unless we drive shallower queue - * depths and that becomes a performance bottleneck. In such cases - * switch to start providing fairness in terms of number of IOs. - */ - if (!cfqd->cfq_slice_idle && cfqd->hw_tag) - return true; - else - return false; -} - -static inline enum wl_class_t cfqq_class(struct cfq_queue *cfqq) -{ - if (cfq_class_idle(cfqq)) - return IDLE_WORKLOAD; - if (cfq_class_rt(cfqq)) - return RT_WORKLOAD; - return BE_WORKLOAD; -} - - -static enum wl_type_t cfqq_type(struct cfq_queue *cfqq) -{ - if (!cfq_cfqq_sync(cfqq)) - return ASYNC_WORKLOAD; - if (!cfq_cfqq_idle_window(cfqq)) - return SYNC_NOIDLE_WORKLOAD; - return SYNC_WORKLOAD; -} - -static inline int cfq_group_busy_queues_wl(enum wl_class_t wl_class, - struct cfq_data *cfqd, - struct cfq_group *cfqg) -{ - if (wl_class == IDLE_WORKLOAD) - return cfqg->service_tree_idle.count; - - return cfqg->service_trees[wl_class][ASYNC_WORKLOAD].count + - cfqg->service_trees[wl_class][SYNC_NOIDLE_WORKLOAD].count + - cfqg->service_trees[wl_class][SYNC_WORKLOAD].count; -} - -static inline int cfqg_busy_async_queues(struct cfq_data *cfqd, - struct cfq_group *cfqg) -{ - return cfqg->service_trees[RT_WORKLOAD][ASYNC_WORKLOAD].count + - cfqg->service_trees[BE_WORKLOAD][ASYNC_WORKLOAD].count; -} - -static void cfq_dispatch_insert(struct request_queue *, struct request *); -static struct cfq_queue *cfq_get_queue(struct cfq_data *cfqd, bool is_sync, - struct cfq_io_cq *cic, struct bio *bio); - -static inline struct cfq_io_cq *icq_to_cic(struct io_cq *icq) -{ - /* cic->icq is the first member, %NULL will convert to %NULL */ - return container_of(icq, struct cfq_io_cq, icq); -} - -static inline struct cfq_io_cq *cfq_cic_lookup(struct cfq_data *cfqd, - struct io_context *ioc) -{ - if (ioc) - return icq_to_cic(ioc_lookup_icq(ioc, cfqd->queue)); - return NULL; -} - -static inline struct cfq_queue *cic_to_cfqq(struct cfq_io_cq *cic, bool is_sync) -{ - return cic->cfqq[is_sync]; -} - -static inline void cic_set_cfqq(struct cfq_io_cq *cic, struct cfq_queue *cfqq, - bool is_sync) -{ - cic->cfqq[is_sync] = cfqq; -} - -static inline struct cfq_data *cic_to_cfqd(struct cfq_io_cq *cic) -{ - return cic->icq.q->elevator->elevator_data; -} - -/* - * We regard a request as SYNC, if it's either a read or has the SYNC bit - * set (in which case it could also be direct WRITE). - */ -static inline bool cfq_bio_sync(struct bio *bio) -{ - return bio_data_dir(bio) == READ || (bio->bi_opf & REQ_SYNC); -} - -/* - * scheduler run of queue, if there are requests pending and no one in the - * driver that will restart queueing - */ -static inline void cfq_schedule_dispatch(struct cfq_data *cfqd) -{ - if (cfqd->busy_queues) { - cfq_log(cfqd, "schedule dispatch"); - kblockd_schedule_work(&cfqd->unplug_work); - } -} - -/* - * Scale schedule slice based on io priority. Use the sync time slice only - * if a queue is marked sync and has sync io queued. A sync queue with async - * io only, should not get full sync slice length. - */ -static inline u64 cfq_prio_slice(struct cfq_data *cfqd, bool sync, - unsigned short prio) -{ - u64 base_slice = cfqd->cfq_slice[sync]; - u64 slice = div_u64(base_slice, CFQ_SLICE_SCALE); - - WARN_ON(prio >= IOPRIO_BE_NR); - - return base_slice + (slice * (4 - prio)); -} - -static inline u64 -cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - return cfq_prio_slice(cfqd, cfq_cfqq_sync(cfqq), cfqq->ioprio); -} - -/** - * cfqg_scale_charge - scale disk time charge according to cfqg weight - * @charge: disk time being charged - * @vfraction: vfraction of the cfqg, fixed point w/ CFQ_SERVICE_SHIFT - * - * Scale @charge according to @vfraction, which is in range (0, 1]. The - * scaling is inversely proportional. - * - * scaled = charge / vfraction - * - * The result is also in fixed point w/ CFQ_SERVICE_SHIFT. - */ -static inline u64 cfqg_scale_charge(u64 charge, - unsigned int vfraction) -{ - u64 c = charge << CFQ_SERVICE_SHIFT; /* make it fixed point */ - - /* charge / vfraction */ - c <<= CFQ_SERVICE_SHIFT; - return div_u64(c, vfraction); -} - -static inline u64 max_vdisktime(u64 min_vdisktime, u64 vdisktime) -{ - s64 delta = (s64)(vdisktime - min_vdisktime); - if (delta > 0) - min_vdisktime = vdisktime; - - return min_vdisktime; -} - -static inline u64 min_vdisktime(u64 min_vdisktime, u64 vdisktime) -{ - s64 delta = (s64)(vdisktime - min_vdisktime); - if (delta < 0) - min_vdisktime = vdisktime; - - return min_vdisktime; -} - -static void update_min_vdisktime(struct cfq_rb_root *st) -{ - struct cfq_group *cfqg; - - if (st->left) { - cfqg = rb_entry_cfqg(st->left); - st->min_vdisktime = max_vdisktime(st->min_vdisktime, - cfqg->vdisktime); - } -} - -/* - * get averaged number of queues of RT/BE priority. - * average is updated, with a formula that gives more weight to higher numbers, - * to quickly follows sudden increases and decrease slowly - */ - -static inline unsigned cfq_group_get_avg_queues(struct cfq_data *cfqd, - struct cfq_group *cfqg, bool rt) -{ - unsigned min_q, max_q; - unsigned mult = cfq_hist_divisor - 1; - unsigned round = cfq_hist_divisor / 2; - unsigned busy = cfq_group_busy_queues_wl(rt, cfqd, cfqg); - - min_q = min(cfqg->busy_queues_avg[rt], busy); - max_q = max(cfqg->busy_queues_avg[rt], busy); - cfqg->busy_queues_avg[rt] = (mult * max_q + min_q + round) / - cfq_hist_divisor; - return cfqg->busy_queues_avg[rt]; -} - -static inline u64 -cfq_group_slice(struct cfq_data *cfqd, struct cfq_group *cfqg) -{ - return cfqd->cfq_target_latency * cfqg->vfraction >> CFQ_SERVICE_SHIFT; -} - -static inline u64 -cfq_scaled_cfqq_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - u64 slice = cfq_prio_to_slice(cfqd, cfqq); - if (cfqd->cfq_latency) { - /* - * interested queues (we consider only the ones with the same - * priority class in the cfq group) - */ - unsigned iq = cfq_group_get_avg_queues(cfqd, cfqq->cfqg, - cfq_class_rt(cfqq)); - u64 sync_slice = cfqd->cfq_slice[1]; - u64 expect_latency = sync_slice * iq; - u64 group_slice = cfq_group_slice(cfqd, cfqq->cfqg); - - if (expect_latency > group_slice) { - u64 base_low_slice = 2 * cfqd->cfq_slice_idle; - u64 low_slice; - - /* scale low_slice according to IO priority - * and sync vs async */ - low_slice = div64_u64(base_low_slice*slice, sync_slice); - low_slice = min(slice, low_slice); - /* the adapted slice value is scaled to fit all iqs - * into the target latency */ - slice = div64_u64(slice*group_slice, expect_latency); - slice = max(slice, low_slice); - } - } - return slice; -} - -static inline void -cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - u64 slice = cfq_scaled_cfqq_slice(cfqd, cfqq); - u64 now = ktime_get_ns(); - - cfqq->slice_start = now; - cfqq->slice_end = now + slice; - cfqq->allocated_slice = slice; - cfq_log_cfqq(cfqd, cfqq, "set_slice=%llu", cfqq->slice_end - now); -} - -/* - * We need to wrap this check in cfq_cfqq_slice_new(), since ->slice_end - * isn't valid until the first request from the dispatch is activated - * and the slice time set. - */ -static inline bool cfq_slice_used(struct cfq_queue *cfqq) -{ - if (cfq_cfqq_slice_new(cfqq)) - return false; - if (ktime_get_ns() < cfqq->slice_end) - return false; - - return true; -} - -/* - * Lifted from AS - choose which of rq1 and rq2 that is best served now. - * We choose the request that is closest to the head right now. Distance - * behind the head is penalized and only allowed to a certain extent. - */ -static struct request * -cfq_choose_req(struct cfq_data *cfqd, struct request *rq1, struct request *rq2, sector_t last) -{ - sector_t s1, s2, d1 = 0, d2 = 0; - unsigned long back_max; -#define CFQ_RQ1_WRAP 0x01 /* request 1 wraps */ -#define CFQ_RQ2_WRAP 0x02 /* request 2 wraps */ - unsigned wrap = 0; /* bit mask: requests behind the disk head? */ - - if (rq1 == NULL || rq1 == rq2) - return rq2; - if (rq2 == NULL) - return rq1; - - if (rq_is_sync(rq1) != rq_is_sync(rq2)) - return rq_is_sync(rq1) ? rq1 : rq2; - - if ((rq1->cmd_flags ^ rq2->cmd_flags) & REQ_PRIO) - return rq1->cmd_flags & REQ_PRIO ? rq1 : rq2; - - s1 = blk_rq_pos(rq1); - s2 = blk_rq_pos(rq2); - - /* - * by definition, 1KiB is 2 sectors - */ - back_max = cfqd->cfq_back_max * 2; - - /* - * Strict one way elevator _except_ in the case where we allow - * short backward seeks which are biased as twice the cost of a - * similar forward seek. - */ - if (s1 >= last) - d1 = s1 - last; - else if (s1 + back_max >= last) - d1 = (last - s1) * cfqd->cfq_back_penalty; - else - wrap |= CFQ_RQ1_WRAP; - - if (s2 >= last) - d2 = s2 - last; - else if (s2 + back_max >= last) - d2 = (last - s2) * cfqd->cfq_back_penalty; - else - wrap |= CFQ_RQ2_WRAP; - - /* Found required data */ - - /* - * By doing switch() on the bit mask "wrap" we avoid having to - * check two variables for all permutations: --> faster! - */ - switch (wrap) { - case 0: /* common case for CFQ: rq1 and rq2 not wrapped */ - if (d1 < d2) - return rq1; - else if (d2 < d1) - return rq2; - else { - if (s1 >= s2) - return rq1; - else - return rq2; - } - - case CFQ_RQ2_WRAP: - return rq1; - case CFQ_RQ1_WRAP: - return rq2; - case (CFQ_RQ1_WRAP|CFQ_RQ2_WRAP): /* both rqs wrapped */ - default: - /* - * Since both rqs are wrapped, - * start with the one that's further behind head - * (--> only *one* back seek required), - * since back seek takes more time than forward. - */ - if (s1 <= s2) - return rq1; - else - return rq2; - } -} - -/* - * The below is leftmost cache rbtree addon - */ -static struct cfq_queue *cfq_rb_first(struct cfq_rb_root *root) -{ - /* Service tree is empty */ - if (!root->count) - return NULL; - - if (!root->left) - root->left = rb_first(&root->rb); - - if (root->left) - return rb_entry(root->left, struct cfq_queue, rb_node); - - return NULL; -} - -static struct cfq_group *cfq_rb_first_group(struct cfq_rb_root *root) -{ - if (!root->left) - root->left = rb_first(&root->rb); - - if (root->left) - return rb_entry_cfqg(root->left); - - return NULL; -} - -static void rb_erase_init(struct rb_node *n, struct rb_root *root) -{ - rb_erase(n, root); - RB_CLEAR_NODE(n); -} - -static void cfq_rb_erase(struct rb_node *n, struct cfq_rb_root *root) -{ - if (root->left == n) - root->left = NULL; - rb_erase_init(n, &root->rb); - --root->count; -} - -/* - * would be nice to take fifo expire time into account as well - */ -static struct request * -cfq_find_next_rq(struct cfq_data *cfqd, struct cfq_queue *cfqq, - struct request *last) -{ - struct rb_node *rbnext = rb_next(&last->rb_node); - struct rb_node *rbprev = rb_prev(&last->rb_node); - struct request *next = NULL, *prev = NULL; - - BUG_ON(RB_EMPTY_NODE(&last->rb_node)); - - if (rbprev) - prev = rb_entry_rq(rbprev); - - if (rbnext) - next = rb_entry_rq(rbnext); - else { - rbnext = rb_first(&cfqq->sort_list); - if (rbnext && rbnext != &last->rb_node) - next = rb_entry_rq(rbnext); - } - - return cfq_choose_req(cfqd, next, prev, blk_rq_pos(last)); -} - -static u64 cfq_slice_offset(struct cfq_data *cfqd, - struct cfq_queue *cfqq) -{ - /* - * just an approximation, should be ok. - */ - return (cfqq->cfqg->nr_cfqq - 1) * (cfq_prio_slice(cfqd, 1, 0) - - cfq_prio_slice(cfqd, cfq_cfqq_sync(cfqq), cfqq->ioprio)); -} - -static inline s64 -cfqg_key(struct cfq_rb_root *st, struct cfq_group *cfqg) -{ - return cfqg->vdisktime - st->min_vdisktime; -} - -static void -__cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg) -{ - struct rb_node **node = &st->rb.rb_node; - struct rb_node *parent = NULL; - struct cfq_group *__cfqg; - s64 key = cfqg_key(st, cfqg); - int left = 1; - - while (*node != NULL) { - parent = *node; - __cfqg = rb_entry_cfqg(parent); - - if (key < cfqg_key(st, __cfqg)) - node = &parent->rb_left; - else { - node = &parent->rb_right; - left = 0; - } - } - - if (left) - st->left = &cfqg->rb_node; - - rb_link_node(&cfqg->rb_node, parent, node); - rb_insert_color(&cfqg->rb_node, &st->rb); -} - -/* - * This has to be called only on activation of cfqg - */ -static void -cfq_update_group_weight(struct cfq_group *cfqg) -{ - if (cfqg->new_weight) { - cfqg->weight = cfqg->new_weight; - cfqg->new_weight = 0; - } -} - -static void -cfq_update_group_leaf_weight(struct cfq_group *cfqg) -{ - BUG_ON(!RB_EMPTY_NODE(&cfqg->rb_node)); - - if (cfqg->new_leaf_weight) { - cfqg->leaf_weight = cfqg->new_leaf_weight; - cfqg->new_leaf_weight = 0; - } -} - -static void -cfq_group_service_tree_add(struct cfq_rb_root *st, struct cfq_group *cfqg) -{ - unsigned int vfr = 1 << CFQ_SERVICE_SHIFT; /* start with 1 */ - struct cfq_group *pos = cfqg; - struct cfq_group *parent; - bool propagate; - - /* add to the service tree */ - BUG_ON(!RB_EMPTY_NODE(&cfqg->rb_node)); - - /* - * Update leaf_weight. We cannot update weight at this point - * because cfqg might already have been activated and is - * contributing its current weight to the parent's child_weight. - */ - cfq_update_group_leaf_weight(cfqg); - __cfq_group_service_tree_add(st, cfqg); - - /* - * Activate @cfqg and calculate the portion of vfraction @cfqg is - * entitled to. vfraction is calculated by walking the tree - * towards the root calculating the fraction it has at each level. - * The compounded ratio is how much vfraction @cfqg owns. - * - * Start with the proportion tasks in this cfqg has against active - * children cfqgs - its leaf_weight against children_weight. - */ - propagate = !pos->nr_active++; - pos->children_weight += pos->leaf_weight; - vfr = vfr * pos->leaf_weight / pos->children_weight; - - /* - * Compound ->weight walking up the tree. Both activation and - * vfraction calculation are done in the same loop. Propagation - * stops once an already activated node is met. vfraction - * calculation should always continue to the root. - */ - while ((parent = cfqg_parent(pos))) { - if (propagate) { - cfq_update_group_weight(pos); - propagate = !parent->nr_active++; - parent->children_weight += pos->weight; - } - vfr = vfr * pos->weight / parent->children_weight; - pos = parent; - } - - cfqg->vfraction = max_t(unsigned, vfr, 1); -} - -static void -cfq_group_notify_queue_add(struct cfq_data *cfqd, struct cfq_group *cfqg) -{ - struct cfq_rb_root *st = &cfqd->grp_service_tree; - struct cfq_group *__cfqg; - struct rb_node *n; - - cfqg->nr_cfqq++; - if (!RB_EMPTY_NODE(&cfqg->rb_node)) - return; - - /* - * Currently put the group at the end. Later implement something - * so that groups get lesser vtime based on their weights, so that - * if group does not loose all if it was not continuously backlogged. - */ - n = rb_last(&st->rb); - if (n) { - __cfqg = rb_entry_cfqg(n); - cfqg->vdisktime = __cfqg->vdisktime + CFQ_IDLE_DELAY; - } else - cfqg->vdisktime = st->min_vdisktime; - cfq_group_service_tree_add(st, cfqg); -} - -static void -cfq_group_service_tree_del(struct cfq_rb_root *st, struct cfq_group *cfqg) -{ - struct cfq_group *pos = cfqg; - bool propagate; - - /* - * Undo activation from cfq_group_service_tree_add(). Deactivate - * @cfqg and propagate deactivation upwards. - */ - propagate = !--pos->nr_active; - pos->children_weight -= pos->leaf_weight; - - while (propagate) { - struct cfq_group *parent = cfqg_parent(pos); - - /* @pos has 0 nr_active at this point */ - WARN_ON_ONCE(pos->children_weight); - pos->vfraction = 0; - - if (!parent) - break; - - propagate = !--parent->nr_active; - parent->children_weight -= pos->weight; - pos = parent; - } - - /* remove from the service tree */ - if (!RB_EMPTY_NODE(&cfqg->rb_node)) - cfq_rb_erase(&cfqg->rb_node, st); -} - -static void -cfq_group_notify_queue_del(struct cfq_data *cfqd, struct cfq_group *cfqg) -{ - struct cfq_rb_root *st = &cfqd->grp_service_tree; - - BUG_ON(cfqg->nr_cfqq < 1); - cfqg->nr_cfqq--; - - /* If there are other cfq queues under this group, don't delete it */ - if (cfqg->nr_cfqq) - return; - - cfq_log_cfqg(cfqd, cfqg, "del_from_rr group"); - cfq_group_service_tree_del(st, cfqg); - cfqg->saved_wl_slice = 0; - cfqg_stats_update_dequeue(cfqg); -} - -static inline u64 cfq_cfqq_slice_usage(struct cfq_queue *cfqq, - u64 *unaccounted_time) -{ - u64 slice_used; - u64 now = ktime_get_ns(); - - /* - * Queue got expired before even a single request completed or - * got expired immediately after first request completion. - */ - if (!cfqq->slice_start || cfqq->slice_start == now) { - /* - * Also charge the seek time incurred to the group, otherwise - * if there are mutiple queues in the group, each can dispatch - * a single request on seeky media and cause lots of seek time - * and group will never know it. - */ - slice_used = max_t(u64, (now - cfqq->dispatch_start), - jiffies_to_nsecs(1)); - } else { - slice_used = now - cfqq->slice_start; - if (slice_used > cfqq->allocated_slice) { - *unaccounted_time = slice_used - cfqq->allocated_slice; - slice_used = cfqq->allocated_slice; - } - if (cfqq->slice_start > cfqq->dispatch_start) - *unaccounted_time += cfqq->slice_start - - cfqq->dispatch_start; - } - - return slice_used; -} - -static void cfq_group_served(struct cfq_data *cfqd, struct cfq_group *cfqg, - struct cfq_queue *cfqq) -{ - struct cfq_rb_root *st = &cfqd->grp_service_tree; - u64 used_sl, charge, unaccounted_sl = 0; - int nr_sync = cfqg->nr_cfqq - cfqg_busy_async_queues(cfqd, cfqg) - - cfqg->service_tree_idle.count; - unsigned int vfr; - u64 now = ktime_get_ns(); - - BUG_ON(nr_sync < 0); - used_sl = charge = cfq_cfqq_slice_usage(cfqq, &unaccounted_sl); - - if (iops_mode(cfqd)) - charge = cfqq->slice_dispatch; - else if (!cfq_cfqq_sync(cfqq) && !nr_sync) - charge = cfqq->allocated_slice; - - /* - * Can't update vdisktime while on service tree and cfqg->vfraction - * is valid only while on it. Cache vfr, leave the service tree, - * update vdisktime and go back on. The re-addition to the tree - * will also update the weights as necessary. - */ - vfr = cfqg->vfraction; - cfq_group_service_tree_del(st, cfqg); - cfqg->vdisktime += cfqg_scale_charge(charge, vfr); - cfq_group_service_tree_add(st, cfqg); - - /* This group is being expired. Save the context */ - if (cfqd->workload_expires > now) { - cfqg->saved_wl_slice = cfqd->workload_expires - now; - cfqg->saved_wl_type = cfqd->serving_wl_type; - cfqg->saved_wl_class = cfqd->serving_wl_class; - } else - cfqg->saved_wl_slice = 0; - - cfq_log_cfqg(cfqd, cfqg, "served: vt=%llu min_vt=%llu", cfqg->vdisktime, - st->min_vdisktime); - cfq_log_cfqq(cfqq->cfqd, cfqq, - "sl_used=%llu disp=%llu charge=%llu iops=%u sect=%lu", - used_sl, cfqq->slice_dispatch, charge, - iops_mode(cfqd), cfqq->nr_sectors); - cfqg_stats_update_timeslice_used(cfqg, used_sl, unaccounted_sl); - cfqg_stats_set_start_empty_time(cfqg); -} - -/** - * cfq_init_cfqg_base - initialize base part of a cfq_group - * @cfqg: cfq_group to initialize - * - * Initialize the base part which is used whether %CONFIG_CFQ_GROUP_IOSCHED - * is enabled or not. - */ -static void cfq_init_cfqg_base(struct cfq_group *cfqg) -{ - struct cfq_rb_root *st; - int i, j; - - for_each_cfqg_st(cfqg, i, j, st) - *st = CFQ_RB_ROOT; - RB_CLEAR_NODE(&cfqg->rb_node); - - cfqg->ttime.last_end_request = ktime_get_ns(); -} - -#ifdef CONFIG_CFQ_GROUP_IOSCHED -static int __cfq_set_weight(struct cgroup_subsys_state *css, u64 val, - bool on_dfl, bool reset_dev, bool is_leaf_weight); - -static void cfqg_stats_exit(struct cfqg_stats *stats) -{ - blkg_rwstat_exit(&stats->merged); - blkg_rwstat_exit(&stats->service_time); - blkg_rwstat_exit(&stats->wait_time); - blkg_rwstat_exit(&stats->queued); - blkg_stat_exit(&stats->time); -#ifdef CONFIG_DEBUG_BLK_CGROUP - blkg_stat_exit(&stats->unaccounted_time); - blkg_stat_exit(&stats->avg_queue_size_sum); - blkg_stat_exit(&stats->avg_queue_size_samples); - blkg_stat_exit(&stats->dequeue); - blkg_stat_exit(&stats->group_wait_time); - blkg_stat_exit(&stats->idle_time); - blkg_stat_exit(&stats->empty_time); -#endif -} - -static int cfqg_stats_init(struct cfqg_stats *stats, gfp_t gfp) -{ - if (blkg_rwstat_init(&stats->merged, gfp) || - blkg_rwstat_init(&stats->service_time, gfp) || - blkg_rwstat_init(&stats->wait_time, gfp) || - blkg_rwstat_init(&stats->queued, gfp) || - blkg_stat_init(&stats->time, gfp)) - goto err; - -#ifdef CONFIG_DEBUG_BLK_CGROUP - if (blkg_stat_init(&stats->unaccounted_time, gfp) || - blkg_stat_init(&stats->avg_queue_size_sum, gfp) || - blkg_stat_init(&stats->avg_queue_size_samples, gfp) || - blkg_stat_init(&stats->dequeue, gfp) || - blkg_stat_init(&stats->group_wait_time, gfp) || - blkg_stat_init(&stats->idle_time, gfp) || - blkg_stat_init(&stats->empty_time, gfp)) - goto err; -#endif - return 0; -err: - cfqg_stats_exit(stats); - return -ENOMEM; -} - -static struct blkcg_policy_data *cfq_cpd_alloc(gfp_t gfp) -{ - struct cfq_group_data *cgd; - - cgd = kzalloc(sizeof(*cgd), GFP_KERNEL); - if (!cgd) - return NULL; - return &cgd->cpd; -} - -static void cfq_cpd_init(struct blkcg_policy_data *cpd) -{ - struct cfq_group_data *cgd = cpd_to_cfqgd(cpd); - unsigned int weight = cgroup_subsys_on_dfl(io_cgrp_subsys) ? - CGROUP_WEIGHT_DFL : CFQ_WEIGHT_LEGACY_DFL; - - if (cpd_to_blkcg(cpd) == &blkcg_root) - weight *= 2; - - cgd->weight = weight; - cgd->leaf_weight = weight; -} - -static void cfq_cpd_free(struct blkcg_policy_data *cpd) -{ - kfree(cpd_to_cfqgd(cpd)); -} - -static void cfq_cpd_bind(struct blkcg_policy_data *cpd) -{ - struct blkcg *blkcg = cpd_to_blkcg(cpd); - bool on_dfl = cgroup_subsys_on_dfl(io_cgrp_subsys); - unsigned int weight = on_dfl ? CGROUP_WEIGHT_DFL : CFQ_WEIGHT_LEGACY_DFL; - - if (blkcg == &blkcg_root) - weight *= 2; - - WARN_ON_ONCE(__cfq_set_weight(&blkcg->css, weight, on_dfl, true, false)); - WARN_ON_ONCE(__cfq_set_weight(&blkcg->css, weight, on_dfl, true, true)); -} - -static struct blkg_policy_data *cfq_pd_alloc(gfp_t gfp, int node) -{ - struct cfq_group *cfqg; - - cfqg = kzalloc_node(sizeof(*cfqg), gfp, node); - if (!cfqg) - return NULL; - - cfq_init_cfqg_base(cfqg); - if (cfqg_stats_init(&cfqg->stats, gfp)) { - kfree(cfqg); - return NULL; - } - - return &cfqg->pd; -} - -static void cfq_pd_init(struct blkg_policy_data *pd) -{ - struct cfq_group *cfqg = pd_to_cfqg(pd); - struct cfq_group_data *cgd = blkcg_to_cfqgd(pd->blkg->blkcg); - - cfqg->weight = cgd->weight; - cfqg->leaf_weight = cgd->leaf_weight; -} - -static void cfq_pd_offline(struct blkg_policy_data *pd) -{ - struct cfq_group *cfqg = pd_to_cfqg(pd); - int i; - - for (i = 0; i < IOPRIO_BE_NR; i++) { - if (cfqg->async_cfqq[0][i]) - cfq_put_queue(cfqg->async_cfqq[0][i]); - if (cfqg->async_cfqq[1][i]) - cfq_put_queue(cfqg->async_cfqq[1][i]); - } - - if (cfqg->async_idle_cfqq) - cfq_put_queue(cfqg->async_idle_cfqq); - - /* - * @blkg is going offline and will be ignored by - * blkg_[rw]stat_recursive_sum(). Transfer stats to the parent so - * that they don't get lost. If IOs complete after this point, the - * stats for them will be lost. Oh well... - */ - cfqg_stats_xfer_dead(cfqg); -} - -static void cfq_pd_free(struct blkg_policy_data *pd) -{ - struct cfq_group *cfqg = pd_to_cfqg(pd); - - cfqg_stats_exit(&cfqg->stats); - return kfree(cfqg); -} - -static void cfq_pd_reset_stats(struct blkg_policy_data *pd) -{ - struct cfq_group *cfqg = pd_to_cfqg(pd); - - cfqg_stats_reset(&cfqg->stats); -} - -static struct cfq_group *cfq_lookup_cfqg(struct cfq_data *cfqd, - struct blkcg *blkcg) -{ - struct blkcg_gq *blkg; - - blkg = blkg_lookup(blkcg, cfqd->queue); - if (likely(blkg)) - return blkg_to_cfqg(blkg); - return NULL; -} - -static void cfq_link_cfqq_cfqg(struct cfq_queue *cfqq, struct cfq_group *cfqg) -{ - cfqq->cfqg = cfqg; - /* cfqq reference on cfqg */ - cfqg_get(cfqg); -} - -static u64 cfqg_prfill_weight_device(struct seq_file *sf, - struct blkg_policy_data *pd, int off) -{ - struct cfq_group *cfqg = pd_to_cfqg(pd); - - if (!cfqg->dev_weight) - return 0; - return __blkg_prfill_u64(sf, pd, cfqg->dev_weight); -} - -static int cfqg_print_weight_device(struct seq_file *sf, void *v) -{ - blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), - cfqg_prfill_weight_device, &blkcg_policy_cfq, - 0, false); - return 0; -} - -static u64 cfqg_prfill_leaf_weight_device(struct seq_file *sf, - struct blkg_policy_data *pd, int off) -{ - struct cfq_group *cfqg = pd_to_cfqg(pd); - - if (!cfqg->dev_leaf_weight) - return 0; - return __blkg_prfill_u64(sf, pd, cfqg->dev_leaf_weight); -} - -static int cfqg_print_leaf_weight_device(struct seq_file *sf, void *v) -{ - blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), - cfqg_prfill_leaf_weight_device, &blkcg_policy_cfq, - 0, false); - return 0; -} - -static int cfq_print_weight(struct seq_file *sf, void *v) -{ - struct blkcg *blkcg = css_to_blkcg(seq_css(sf)); - struct cfq_group_data *cgd = blkcg_to_cfqgd(blkcg); - unsigned int val = 0; - - if (cgd) - val = cgd->weight; - - seq_printf(sf, "%u\n", val); - return 0; -} - -static int cfq_print_leaf_weight(struct seq_file *sf, void *v) -{ - struct blkcg *blkcg = css_to_blkcg(seq_css(sf)); - struct cfq_group_data *cgd = blkcg_to_cfqgd(blkcg); - unsigned int val = 0; - - if (cgd) - val = cgd->leaf_weight; - - seq_printf(sf, "%u\n", val); - return 0; -} - -static ssize_t __cfqg_set_weight_device(struct kernfs_open_file *of, - char *buf, size_t nbytes, loff_t off, - bool on_dfl, bool is_leaf_weight) -{ - unsigned int min = on_dfl ? CGROUP_WEIGHT_MIN : CFQ_WEIGHT_LEGACY_MIN; - unsigned int max = on_dfl ? CGROUP_WEIGHT_MAX : CFQ_WEIGHT_LEGACY_MAX; - struct blkcg *blkcg = css_to_blkcg(of_css(of)); - struct blkg_conf_ctx ctx; - struct cfq_group *cfqg; - struct cfq_group_data *cfqgd; - int ret; - u64 v; - - ret = blkg_conf_prep(blkcg, &blkcg_policy_cfq, buf, &ctx); - if (ret) - return ret; - - if (sscanf(ctx.body, "%llu", &v) == 1) { - /* require "default" on dfl */ - ret = -ERANGE; - if (!v && on_dfl) - goto out_finish; - } else if (!strcmp(strim(ctx.body), "default")) { - v = 0; - } else { - ret = -EINVAL; - goto out_finish; - } - - cfqg = blkg_to_cfqg(ctx.blkg); - cfqgd = blkcg_to_cfqgd(blkcg); - - ret = -ERANGE; - if (!v || (v >= min && v <= max)) { - if (!is_leaf_weight) { - cfqg->dev_weight = v; - cfqg->new_weight = v ?: cfqgd->weight; - } else { - cfqg->dev_leaf_weight = v; - cfqg->new_leaf_weight = v ?: cfqgd->leaf_weight; - } - ret = 0; - } -out_finish: - blkg_conf_finish(&ctx); - return ret ?: nbytes; -} - -static ssize_t cfqg_set_weight_device(struct kernfs_open_file *of, - char *buf, size_t nbytes, loff_t off) -{ - return __cfqg_set_weight_device(of, buf, nbytes, off, false, false); -} - -static ssize_t cfqg_set_leaf_weight_device(struct kernfs_open_file *of, - char *buf, size_t nbytes, loff_t off) -{ - return __cfqg_set_weight_device(of, buf, nbytes, off, false, true); -} - -static int __cfq_set_weight(struct cgroup_subsys_state *css, u64 val, - bool on_dfl, bool reset_dev, bool is_leaf_weight) -{ - unsigned int min = on_dfl ? CGROUP_WEIGHT_MIN : CFQ_WEIGHT_LEGACY_MIN; - unsigned int max = on_dfl ? CGROUP_WEIGHT_MAX : CFQ_WEIGHT_LEGACY_MAX; - struct blkcg *blkcg = css_to_blkcg(css); - struct blkcg_gq *blkg; - struct cfq_group_data *cfqgd; - int ret = 0; - - if (val < min || val > max) - return -ERANGE; - - spin_lock_irq(&blkcg->lock); - cfqgd = blkcg_to_cfqgd(blkcg); - if (!cfqgd) { - ret = -EINVAL; - goto out; - } - - if (!is_leaf_weight) - cfqgd->weight = val; - else - cfqgd->leaf_weight = val; - - hlist_for_each_entry(blkg, &blkcg->blkg_list, blkcg_node) { - struct cfq_group *cfqg = blkg_to_cfqg(blkg); - - if (!cfqg) - continue; - - if (!is_leaf_weight) { - if (reset_dev) - cfqg->dev_weight = 0; - if (!cfqg->dev_weight) - cfqg->new_weight = cfqgd->weight; - } else { - if (reset_dev) - cfqg->dev_leaf_weight = 0; - if (!cfqg->dev_leaf_weight) - cfqg->new_leaf_weight = cfqgd->leaf_weight; - } - } - -out: - spin_unlock_irq(&blkcg->lock); - return ret; -} - -static int cfq_set_weight(struct cgroup_subsys_state *css, struct cftype *cft, - u64 val) -{ - return __cfq_set_weight(css, val, false, false, false); -} - -static int cfq_set_leaf_weight(struct cgroup_subsys_state *css, - struct cftype *cft, u64 val) -{ - return __cfq_set_weight(css, val, false, false, true); -} - -static int cfqg_print_stat(struct seq_file *sf, void *v) -{ - blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), blkg_prfill_stat, - &blkcg_policy_cfq, seq_cft(sf)->private, false); - return 0; -} - -static int cfqg_print_rwstat(struct seq_file *sf, void *v) -{ - blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), blkg_prfill_rwstat, - &blkcg_policy_cfq, seq_cft(sf)->private, true); - return 0; -} - -static u64 cfqg_prfill_stat_recursive(struct seq_file *sf, - struct blkg_policy_data *pd, int off) -{ - u64 sum = blkg_stat_recursive_sum(pd_to_blkg(pd), - &blkcg_policy_cfq, off); - return __blkg_prfill_u64(sf, pd, sum); -} - -static u64 cfqg_prfill_rwstat_recursive(struct seq_file *sf, - struct blkg_policy_data *pd, int off) -{ - struct blkg_rwstat sum = blkg_rwstat_recursive_sum(pd_to_blkg(pd), - &blkcg_policy_cfq, off); - return __blkg_prfill_rwstat(sf, pd, &sum); -} - -static int cfqg_print_stat_recursive(struct seq_file *sf, void *v) -{ - blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), - cfqg_prfill_stat_recursive, &blkcg_policy_cfq, - seq_cft(sf)->private, false); - return 0; -} - -static int cfqg_print_rwstat_recursive(struct seq_file *sf, void *v) -{ - blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), - cfqg_prfill_rwstat_recursive, &blkcg_policy_cfq, - seq_cft(sf)->private, true); - return 0; -} - -static u64 cfqg_prfill_sectors(struct seq_file *sf, struct blkg_policy_data *pd, - int off) -{ - u64 sum = blkg_rwstat_total(&pd->blkg->stat_bytes); - - return __blkg_prfill_u64(sf, pd, sum >> 9); -} - -static int cfqg_print_stat_sectors(struct seq_file *sf, void *v) -{ - blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), - cfqg_prfill_sectors, &blkcg_policy_cfq, 0, false); - return 0; -} - -static u64 cfqg_prfill_sectors_recursive(struct seq_file *sf, - struct blkg_policy_data *pd, int off) -{ - struct blkg_rwstat tmp = blkg_rwstat_recursive_sum(pd->blkg, NULL, - offsetof(struct blkcg_gq, stat_bytes)); - u64 sum = atomic64_read(&tmp.aux_cnt[BLKG_RWSTAT_READ]) + - atomic64_read(&tmp.aux_cnt[BLKG_RWSTAT_WRITE]); - - return __blkg_prfill_u64(sf, pd, sum >> 9); -} - -static int cfqg_print_stat_sectors_recursive(struct seq_file *sf, void *v) -{ - blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), - cfqg_prfill_sectors_recursive, &blkcg_policy_cfq, 0, - false); - return 0; -} - -#ifdef CONFIG_DEBUG_BLK_CGROUP -static u64 cfqg_prfill_avg_queue_size(struct seq_file *sf, - struct blkg_policy_data *pd, int off) -{ - struct cfq_group *cfqg = pd_to_cfqg(pd); - u64 samples = blkg_stat_read(&cfqg->stats.avg_queue_size_samples); - u64 v = 0; - - if (samples) { - v = blkg_stat_read(&cfqg->stats.avg_queue_size_sum); - v = div64_u64(v, samples); - } - __blkg_prfill_u64(sf, pd, v); - return 0; -} - -/* print avg_queue_size */ -static int cfqg_print_avg_queue_size(struct seq_file *sf, void *v) -{ - blkcg_print_blkgs(sf, css_to_blkcg(seq_css(sf)), - cfqg_prfill_avg_queue_size, &blkcg_policy_cfq, - 0, false); - return 0; -} -#endif /* CONFIG_DEBUG_BLK_CGROUP */ - -static struct cftype cfq_blkcg_legacy_files[] = { - /* on root, weight is mapped to leaf_weight */ - { - .name = "weight_device", - .flags = CFTYPE_ONLY_ON_ROOT, - .seq_show = cfqg_print_leaf_weight_device, - .write = cfqg_set_leaf_weight_device, - }, - { - .name = "weight", - .flags = CFTYPE_ONLY_ON_ROOT, - .seq_show = cfq_print_leaf_weight, - .write_u64 = cfq_set_leaf_weight, - }, - - /* no such mapping necessary for !roots */ - { - .name = "weight_device", - .flags = CFTYPE_NOT_ON_ROOT, - .seq_show = cfqg_print_weight_device, - .write = cfqg_set_weight_device, - }, - { - .name = "weight", - .flags = CFTYPE_NOT_ON_ROOT, - .seq_show = cfq_print_weight, - .write_u64 = cfq_set_weight, - }, - - { - .name = "leaf_weight_device", - .seq_show = cfqg_print_leaf_weight_device, - .write = cfqg_set_leaf_weight_device, - }, - { - .name = "leaf_weight", - .seq_show = cfq_print_leaf_weight, - .write_u64 = cfq_set_leaf_weight, - }, - - /* statistics, covers only the tasks in the cfqg */ - { - .name = "time", - .private = offsetof(struct cfq_group, stats.time), - .seq_show = cfqg_print_stat, - }, - { - .name = "sectors", - .seq_show = cfqg_print_stat_sectors, - }, - { - .name = "io_service_bytes", - .private = (unsigned long)&blkcg_policy_cfq, - .seq_show = blkg_print_stat_bytes, - }, - { - .name = "io_serviced", - .private = (unsigned long)&blkcg_policy_cfq, - .seq_show = blkg_print_stat_ios, - }, - { - .name = "io_service_time", - .private = offsetof(struct cfq_group, stats.service_time), - .seq_show = cfqg_print_rwstat, - }, - { - .name = "io_wait_time", - .private = offsetof(struct cfq_group, stats.wait_time), - .seq_show = cfqg_print_rwstat, - }, - { - .name = "io_merged", - .private = offsetof(struct cfq_group, stats.merged), - .seq_show = cfqg_print_rwstat, - }, - { - .name = "io_queued", - .private = offsetof(struct cfq_group, stats.queued), - .seq_show = cfqg_print_rwstat, - }, - - /* the same statictics which cover the cfqg and its descendants */ - { - .name = "time_recursive", - .private = offsetof(struct cfq_group, stats.time), - .seq_show = cfqg_print_stat_recursive, - }, - { - .name = "sectors_recursive", - .seq_show = cfqg_print_stat_sectors_recursive, - }, - { - .name = "io_service_bytes_recursive", - .private = (unsigned long)&blkcg_policy_cfq, - .seq_show = blkg_print_stat_bytes_recursive, - }, - { - .name = "io_serviced_recursive", - .private = (unsigned long)&blkcg_policy_cfq, - .seq_show = blkg_print_stat_ios_recursive, - }, - { - .name = "io_service_time_recursive", - .private = offsetof(struct cfq_group, stats.service_time), - .seq_show = cfqg_print_rwstat_recursive, - }, - { - .name = "io_wait_time_recursive", - .private = offsetof(struct cfq_group, stats.wait_time), - .seq_show = cfqg_print_rwstat_recursive, - }, - { - .name = "io_merged_recursive", - .private = offsetof(struct cfq_group, stats.merged), - .seq_show = cfqg_print_rwstat_recursive, - }, - { - .name = "io_queued_recursive", - .private = offsetof(struct cfq_group, stats.queued), - .seq_show = cfqg_print_rwstat_recursive, - }, -#ifdef CONFIG_DEBUG_BLK_CGROUP - { - .name = "avg_queue_size", - .seq_show = cfqg_print_avg_queue_size, - }, - { - .name = "group_wait_time", - .private = offsetof(struct cfq_group, stats.group_wait_time), - .seq_show = cfqg_print_stat, - }, - { - .name = "idle_time", - .private = offsetof(struct cfq_group, stats.idle_time), - .seq_show = cfqg_print_stat, - }, - { - .name = "empty_time", - .private = offsetof(struct cfq_group, stats.empty_time), - .seq_show = cfqg_print_stat, - }, - { - .name = "dequeue", - .private = offsetof(struct cfq_group, stats.dequeue), - .seq_show = cfqg_print_stat, - }, - { - .name = "unaccounted_time", - .private = offsetof(struct cfq_group, stats.unaccounted_time), - .seq_show = cfqg_print_stat, - }, -#endif /* CONFIG_DEBUG_BLK_CGROUP */ - { } /* terminate */ -}; - -static int cfq_print_weight_on_dfl(struct seq_file *sf, void *v) -{ - struct blkcg *blkcg = css_to_blkcg(seq_css(sf)); - struct cfq_group_data *cgd = blkcg_to_cfqgd(blkcg); - - seq_printf(sf, "default %u\n", cgd->weight); - blkcg_print_blkgs(sf, blkcg, cfqg_prfill_weight_device, - &blkcg_policy_cfq, 0, false); - return 0; -} - -static ssize_t cfq_set_weight_on_dfl(struct kernfs_open_file *of, - char *buf, size_t nbytes, loff_t off) -{ - char *endp; - int ret; - u64 v; - - buf = strim(buf); - - /* "WEIGHT" or "default WEIGHT" sets the default weight */ - v = simple_strtoull(buf, &endp, 0); - if (*endp == '\0' || sscanf(buf, "default %llu", &v) == 1) { - ret = __cfq_set_weight(of_css(of), v, true, false, false); - return ret ?: nbytes; - } - - /* "MAJ:MIN WEIGHT" */ - return __cfqg_set_weight_device(of, buf, nbytes, off, true, false); -} - -static struct cftype cfq_blkcg_files[] = { - { - .name = "weight", - .flags = CFTYPE_NOT_ON_ROOT, - .seq_show = cfq_print_weight_on_dfl, - .write = cfq_set_weight_on_dfl, - }, - { } /* terminate */ -}; - -#else /* GROUP_IOSCHED */ -static struct cfq_group *cfq_lookup_cfqg(struct cfq_data *cfqd, - struct blkcg *blkcg) -{ - return cfqd->root_group; -} - -static inline void -cfq_link_cfqq_cfqg(struct cfq_queue *cfqq, struct cfq_group *cfqg) { - cfqq->cfqg = cfqg; -} - -#endif /* GROUP_IOSCHED */ - -/* - * The cfqd->service_trees holds all pending cfq_queue's that have - * requests waiting to be processed. It is sorted in the order that - * we will service the queues. - */ -static void cfq_service_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq, - bool add_front) -{ - struct rb_node **p, *parent; - struct cfq_queue *__cfqq; - u64 rb_key; - struct cfq_rb_root *st; - int left; - int new_cfqq = 1; - u64 now = ktime_get_ns(); - - st = st_for(cfqq->cfqg, cfqq_class(cfqq), cfqq_type(cfqq)); - if (cfq_class_idle(cfqq)) { - rb_key = CFQ_IDLE_DELAY; - parent = rb_last(&st->rb); - if (parent && parent != &cfqq->rb_node) { - __cfqq = rb_entry(parent, struct cfq_queue, rb_node); - rb_key += __cfqq->rb_key; - } else - rb_key += now; - } else if (!add_front) { - /* - * Get our rb key offset. Subtract any residual slice - * value carried from last service. A negative resid - * count indicates slice overrun, and this should position - * the next service time further away in the tree. - */ - rb_key = cfq_slice_offset(cfqd, cfqq) + now; - rb_key -= cfqq->slice_resid; - cfqq->slice_resid = 0; - } else { - rb_key = -NSEC_PER_SEC; - __cfqq = cfq_rb_first(st); - rb_key += __cfqq ? __cfqq->rb_key : now; - } - - if (!RB_EMPTY_NODE(&cfqq->rb_node)) { - new_cfqq = 0; - /* - * same position, nothing more to do - */ - if (rb_key == cfqq->rb_key && cfqq->service_tree == st) - return; - - cfq_rb_erase(&cfqq->rb_node, cfqq->service_tree); - cfqq->service_tree = NULL; - } - - left = 1; - parent = NULL; - cfqq->service_tree = st; - p = &st->rb.rb_node; - while (*p) { - parent = *p; - __cfqq = rb_entry(parent, struct cfq_queue, rb_node); - - /* - * sort by key, that represents service time. - */ - if (rb_key < __cfqq->rb_key) - p = &parent->rb_left; - else { - p = &parent->rb_right; - left = 0; - } - } - - if (left) - st->left = &cfqq->rb_node; - - cfqq->rb_key = rb_key; - rb_link_node(&cfqq->rb_node, parent, p); - rb_insert_color(&cfqq->rb_node, &st->rb); - st->count++; - if (add_front || !new_cfqq) - return; - cfq_group_notify_queue_add(cfqd, cfqq->cfqg); -} - -static struct cfq_queue * -cfq_prio_tree_lookup(struct cfq_data *cfqd, struct rb_root *root, - sector_t sector, struct rb_node **ret_parent, - struct rb_node ***rb_link) -{ - struct rb_node **p, *parent; - struct cfq_queue *cfqq = NULL; - - parent = NULL; - p = &root->rb_node; - while (*p) { - struct rb_node **n; - - parent = *p; - cfqq = rb_entry(parent, struct cfq_queue, p_node); - - /* - * Sort strictly based on sector. Smallest to the left, - * largest to the right. - */ - if (sector > blk_rq_pos(cfqq->next_rq)) - n = &(*p)->rb_right; - else if (sector < blk_rq_pos(cfqq->next_rq)) - n = &(*p)->rb_left; - else - break; - p = n; - cfqq = NULL; - } - - *ret_parent = parent; - if (rb_link) - *rb_link = p; - return cfqq; -} - -static void cfq_prio_tree_add(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - struct rb_node **p, *parent; - struct cfq_queue *__cfqq; - - if (cfqq->p_root) { - rb_erase(&cfqq->p_node, cfqq->p_root); - cfqq->p_root = NULL; - } - - if (cfq_class_idle(cfqq)) - return; - if (!cfqq->next_rq) - return; - - cfqq->p_root = &cfqd->prio_trees[cfqq->org_ioprio]; - __cfqq = cfq_prio_tree_lookup(cfqd, cfqq->p_root, - blk_rq_pos(cfqq->next_rq), &parent, &p); - if (!__cfqq) { - rb_link_node(&cfqq->p_node, parent, p); - rb_insert_color(&cfqq->p_node, cfqq->p_root); - } else - cfqq->p_root = NULL; -} - -/* - * Update cfqq's position in the service tree. - */ -static void cfq_resort_rr_list(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - /* - * Resorting requires the cfqq to be on the RR list already. - */ - if (cfq_cfqq_on_rr(cfqq)) { - cfq_service_tree_add(cfqd, cfqq, 0); - cfq_prio_tree_add(cfqd, cfqq); - } -} - -/* - * add to busy list of queues for service, trying to be fair in ordering - * the pending list according to last request service - */ -static void cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - cfq_log_cfqq(cfqd, cfqq, "add_to_rr"); - BUG_ON(cfq_cfqq_on_rr(cfqq)); - cfq_mark_cfqq_on_rr(cfqq); - cfqd->busy_queues++; - if (cfq_cfqq_sync(cfqq)) - cfqd->busy_sync_queues++; - - cfq_resort_rr_list(cfqd, cfqq); -} - -/* - * Called when the cfqq no longer has requests pending, remove it from - * the service tree. - */ -static void cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - cfq_log_cfqq(cfqd, cfqq, "del_from_rr"); - BUG_ON(!cfq_cfqq_on_rr(cfqq)); - cfq_clear_cfqq_on_rr(cfqq); - - if (!RB_EMPTY_NODE(&cfqq->rb_node)) { - cfq_rb_erase(&cfqq->rb_node, cfqq->service_tree); - cfqq->service_tree = NULL; - } - if (cfqq->p_root) { - rb_erase(&cfqq->p_node, cfqq->p_root); - cfqq->p_root = NULL; - } - - cfq_group_notify_queue_del(cfqd, cfqq->cfqg); - BUG_ON(!cfqd->busy_queues); - cfqd->busy_queues--; - if (cfq_cfqq_sync(cfqq)) - cfqd->busy_sync_queues--; -} - -/* - * rb tree support functions - */ -static void cfq_del_rq_rb(struct request *rq) -{ - struct cfq_queue *cfqq = RQ_CFQQ(rq); - const int sync = rq_is_sync(rq); - - BUG_ON(!cfqq->queued[sync]); - cfqq->queued[sync]--; - - elv_rb_del(&cfqq->sort_list, rq); - - if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY_ROOT(&cfqq->sort_list)) { - /* - * Queue will be deleted from service tree when we actually - * expire it later. Right now just remove it from prio tree - * as it is empty. - */ - if (cfqq->p_root) { - rb_erase(&cfqq->p_node, cfqq->p_root); - cfqq->p_root = NULL; - } - } -} - -static void cfq_add_rq_rb(struct request *rq) -{ - struct cfq_queue *cfqq = RQ_CFQQ(rq); - struct cfq_data *cfqd = cfqq->cfqd; - struct request *prev; - - cfqq->queued[rq_is_sync(rq)]++; - - elv_rb_add(&cfqq->sort_list, rq); - - if (!cfq_cfqq_on_rr(cfqq)) - cfq_add_cfqq_rr(cfqd, cfqq); - - /* - * check if this request is a better next-serve candidate - */ - prev = cfqq->next_rq; - cfqq->next_rq = cfq_choose_req(cfqd, cfqq->next_rq, rq, cfqd->last_position); - - /* - * adjust priority tree position, if ->next_rq changes - */ - if (prev != cfqq->next_rq) - cfq_prio_tree_add(cfqd, cfqq); - - BUG_ON(!cfqq->next_rq); -} - -static void cfq_reposition_rq_rb(struct cfq_queue *cfqq, struct request *rq) -{ - elv_rb_del(&cfqq->sort_list, rq); - cfqq->queued[rq_is_sync(rq)]--; - cfqg_stats_update_io_remove(RQ_CFQG(rq), req_op(rq), rq->cmd_flags); - cfq_add_rq_rb(rq); - cfqg_stats_update_io_add(RQ_CFQG(rq), cfqq->cfqd->serving_group, - req_op(rq), rq->cmd_flags); -} - -static struct request * -cfq_find_rq_fmerge(struct cfq_data *cfqd, struct bio *bio) -{ - struct task_struct *tsk = current; - struct cfq_io_cq *cic; - struct cfq_queue *cfqq; - - cic = cfq_cic_lookup(cfqd, tsk->io_context); - if (!cic) - return NULL; - - cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio)); - if (cfqq) - return elv_rb_find(&cfqq->sort_list, bio_end_sector(bio)); - - return NULL; -} - -static void cfq_activate_request(struct request_queue *q, struct request *rq) -{ - struct cfq_data *cfqd = q->elevator->elevator_data; - - cfqd->rq_in_driver++; - cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "activate rq, drv=%d", - cfqd->rq_in_driver); - - cfqd->last_position = blk_rq_pos(rq) + blk_rq_sectors(rq); -} - -static void cfq_deactivate_request(struct request_queue *q, struct request *rq) -{ - struct cfq_data *cfqd = q->elevator->elevator_data; - - WARN_ON(!cfqd->rq_in_driver); - cfqd->rq_in_driver--; - cfq_log_cfqq(cfqd, RQ_CFQQ(rq), "deactivate rq, drv=%d", - cfqd->rq_in_driver); -} - -static void cfq_remove_request(struct request *rq) -{ - struct cfq_queue *cfqq = RQ_CFQQ(rq); - - if (cfqq->next_rq == rq) - cfqq->next_rq = cfq_find_next_rq(cfqq->cfqd, cfqq, rq); - - list_del_init(&rq->queuelist); - cfq_del_rq_rb(rq); - - cfqq->cfqd->rq_queued--; - cfqg_stats_update_io_remove(RQ_CFQG(rq), req_op(rq), rq->cmd_flags); - if (rq->cmd_flags & REQ_PRIO) { - WARN_ON(!cfqq->prio_pending); - cfqq->prio_pending--; - } -} - -static int cfq_merge(struct request_queue *q, struct request **req, - struct bio *bio) -{ - struct cfq_data *cfqd = q->elevator->elevator_data; - struct request *__rq; - - __rq = cfq_find_rq_fmerge(cfqd, bio); - if (__rq && elv_bio_merge_ok(__rq, bio)) { - *req = __rq; - return ELEVATOR_FRONT_MERGE; - } - - return ELEVATOR_NO_MERGE; -} - -static void cfq_merged_request(struct request_queue *q, struct request *req, - int type) -{ - if (type == ELEVATOR_FRONT_MERGE) { - struct cfq_queue *cfqq = RQ_CFQQ(req); - - cfq_reposition_rq_rb(cfqq, req); - } -} - -static void cfq_bio_merged(struct request_queue *q, struct request *req, - struct bio *bio) -{ - cfqg_stats_update_io_merged(RQ_CFQG(req), bio_op(bio), bio->bi_opf); -} - -static void -cfq_merged_requests(struct request_queue *q, struct request *rq, - struct request *next) -{ - struct cfq_queue *cfqq = RQ_CFQQ(rq); - struct cfq_data *cfqd = q->elevator->elevator_data; - - /* - * reposition in fifo if next is older than rq - */ - if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist) && - next->fifo_time < rq->fifo_time && - cfqq == RQ_CFQQ(next)) { - list_move(&rq->queuelist, &next->queuelist); - rq->fifo_time = next->fifo_time; - } - - if (cfqq->next_rq == next) - cfqq->next_rq = rq; - cfq_remove_request(next); - cfqg_stats_update_io_merged(RQ_CFQG(rq), req_op(next), next->cmd_flags); - - cfqq = RQ_CFQQ(next); - /* - * all requests of this queue are merged to other queues, delete it - * from the service tree. If it's the active_queue, - * cfq_dispatch_requests() will choose to expire it or do idle - */ - if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY_ROOT(&cfqq->sort_list) && - cfqq != cfqd->active_queue) - cfq_del_cfqq_rr(cfqd, cfqq); -} - -static int cfq_allow_bio_merge(struct request_queue *q, struct request *rq, - struct bio *bio) -{ - struct cfq_data *cfqd = q->elevator->elevator_data; - struct cfq_io_cq *cic; - struct cfq_queue *cfqq; - - /* - * Disallow merge of a sync bio into an async request. - */ - if (cfq_bio_sync(bio) && !rq_is_sync(rq)) - return false; - - /* - * Lookup the cfqq that this bio will be queued with and allow - * merge only if rq is queued there. - */ - cic = cfq_cic_lookup(cfqd, current->io_context); - if (!cic) - return false; - - cfqq = cic_to_cfqq(cic, cfq_bio_sync(bio)); - return cfqq == RQ_CFQQ(rq); -} - -static int cfq_allow_rq_merge(struct request_queue *q, struct request *rq, - struct request *next) -{ - return RQ_CFQQ(rq) == RQ_CFQQ(next); -} - -static inline void cfq_del_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - hrtimer_try_to_cancel(&cfqd->idle_slice_timer); - cfqg_stats_update_idle_time(cfqq->cfqg); -} - -static void __cfq_set_active_queue(struct cfq_data *cfqd, - struct cfq_queue *cfqq) -{ - if (cfqq) { - cfq_log_cfqq(cfqd, cfqq, "set_active wl_class:%d wl_type:%d", - cfqd->serving_wl_class, cfqd->serving_wl_type); - cfqg_stats_update_avg_queue_size(cfqq->cfqg); - cfqq->slice_start = 0; - cfqq->dispatch_start = ktime_get_ns(); - cfqq->allocated_slice = 0; - cfqq->slice_end = 0; - cfqq->slice_dispatch = 0; - cfqq->nr_sectors = 0; - - cfq_clear_cfqq_wait_request(cfqq); - cfq_clear_cfqq_must_dispatch(cfqq); - cfq_clear_cfqq_must_alloc_slice(cfqq); - cfq_clear_cfqq_fifo_expire(cfqq); - cfq_mark_cfqq_slice_new(cfqq); - - cfq_del_timer(cfqd, cfqq); - } - - cfqd->active_queue = cfqq; -} - -/* - * current cfqq expired its slice (or was too idle), select new one - */ -static void -__cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq, - bool timed_out) -{ - cfq_log_cfqq(cfqd, cfqq, "slice expired t=%d", timed_out); - - if (cfq_cfqq_wait_request(cfqq)) - cfq_del_timer(cfqd, cfqq); - - cfq_clear_cfqq_wait_request(cfqq); - cfq_clear_cfqq_wait_busy(cfqq); - - /* - * If this cfqq is shared between multiple processes, check to - * make sure that those processes are still issuing I/Os within - * the mean seek distance. If not, it may be time to break the - * queues apart again. - */ - if (cfq_cfqq_coop(cfqq) && CFQQ_SEEKY(cfqq)) - cfq_mark_cfqq_split_coop(cfqq); - - /* - * store what was left of this slice, if the queue idled/timed out - */ - if (timed_out) { - if (cfq_cfqq_slice_new(cfqq)) - cfqq->slice_resid = cfq_scaled_cfqq_slice(cfqd, cfqq); - else - cfqq->slice_resid = cfqq->slice_end - ktime_get_ns(); - cfq_log_cfqq(cfqd, cfqq, "resid=%lld", cfqq->slice_resid); - } - - cfq_group_served(cfqd, cfqq->cfqg, cfqq); - - if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY_ROOT(&cfqq->sort_list)) - cfq_del_cfqq_rr(cfqd, cfqq); - - cfq_resort_rr_list(cfqd, cfqq); - - if (cfqq == cfqd->active_queue) - cfqd->active_queue = NULL; - - if (cfqd->active_cic) { - put_io_context(cfqd->active_cic->icq.ioc); - cfqd->active_cic = NULL; - } -} - -static inline void cfq_slice_expired(struct cfq_data *cfqd, bool timed_out) -{ - struct cfq_queue *cfqq = cfqd->active_queue; - - if (cfqq) - __cfq_slice_expired(cfqd, cfqq, timed_out); -} - -/* - * Get next queue for service. Unless we have a queue preemption, - * we'll simply select the first cfqq in the service tree. - */ -static struct cfq_queue *cfq_get_next_queue(struct cfq_data *cfqd) -{ - struct cfq_rb_root *st = st_for(cfqd->serving_group, - cfqd->serving_wl_class, cfqd->serving_wl_type); - - if (!cfqd->rq_queued) - return NULL; - - /* There is nothing to dispatch */ - if (!st) - return NULL; - if (RB_EMPTY_ROOT(&st->rb)) - return NULL; - return cfq_rb_first(st); -} - -static struct cfq_queue *cfq_get_next_queue_forced(struct cfq_data *cfqd) -{ - struct cfq_group *cfqg; - struct cfq_queue *cfqq; - int i, j; - struct cfq_rb_root *st; - - if (!cfqd->rq_queued) - return NULL; - - cfqg = cfq_get_next_cfqg(cfqd); - if (!cfqg) - return NULL; - - for_each_cfqg_st(cfqg, i, j, st) - if ((cfqq = cfq_rb_first(st)) != NULL) - return cfqq; - return NULL; -} - -/* - * Get and set a new active queue for service. - */ -static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd, - struct cfq_queue *cfqq) -{ - if (!cfqq) - cfqq = cfq_get_next_queue(cfqd); - - __cfq_set_active_queue(cfqd, cfqq); - return cfqq; -} - -static inline sector_t cfq_dist_from_last(struct cfq_data *cfqd, - struct request *rq) -{ - if (blk_rq_pos(rq) >= cfqd->last_position) - return blk_rq_pos(rq) - cfqd->last_position; - else - return cfqd->last_position - blk_rq_pos(rq); -} - -static inline int cfq_rq_close(struct cfq_data *cfqd, struct cfq_queue *cfqq, - struct request *rq) -{ - return cfq_dist_from_last(cfqd, rq) <= CFQQ_CLOSE_THR; -} - -static struct cfq_queue *cfqq_close(struct cfq_data *cfqd, - struct cfq_queue *cur_cfqq) -{ - struct rb_root *root = &cfqd->prio_trees[cur_cfqq->org_ioprio]; - struct rb_node *parent, *node; - struct cfq_queue *__cfqq; - sector_t sector = cfqd->last_position; - - if (RB_EMPTY_ROOT(root)) - return NULL; - - /* - * First, if we find a request starting at the end of the last - * request, choose it. - */ - __cfqq = cfq_prio_tree_lookup(cfqd, root, sector, &parent, NULL); - if (__cfqq) - return __cfqq; - - /* - * If the exact sector wasn't found, the parent of the NULL leaf - * will contain the closest sector. - */ - __cfqq = rb_entry(parent, struct cfq_queue, p_node); - if (cfq_rq_close(cfqd, cur_cfqq, __cfqq->next_rq)) - return __cfqq; - - if (blk_rq_pos(__cfqq->next_rq) < sector) - node = rb_next(&__cfqq->p_node); - else - node = rb_prev(&__cfqq->p_node); - if (!node) - return NULL; - - __cfqq = rb_entry(node, struct cfq_queue, p_node); - if (cfq_rq_close(cfqd, cur_cfqq, __cfqq->next_rq)) - return __cfqq; - - return NULL; -} - -/* - * cfqd - obvious - * cur_cfqq - passed in so that we don't decide that the current queue is - * closely cooperating with itself. - * - * So, basically we're assuming that that cur_cfqq has dispatched at least - * one request, and that cfqd->last_position reflects a position on the disk - * associated with the I/O issued by cur_cfqq. I'm not sure this is a valid - * assumption. - */ -static struct cfq_queue *cfq_close_cooperator(struct cfq_data *cfqd, - struct cfq_queue *cur_cfqq) -{ - struct cfq_queue *cfqq; - - if (cfq_class_idle(cur_cfqq)) - return NULL; - if (!cfq_cfqq_sync(cur_cfqq)) - return NULL; - if (CFQQ_SEEKY(cur_cfqq)) - return NULL; - - /* - * Don't search priority tree if it's the only queue in the group. - */ - if (cur_cfqq->cfqg->nr_cfqq == 1) - return NULL; - - /* - * We should notice if some of the queues are cooperating, eg - * working closely on the same area of the disk. In that case, - * we can group them together and don't waste time idling. - */ - cfqq = cfqq_close(cfqd, cur_cfqq); - if (!cfqq) - return NULL; - - /* If new queue belongs to different cfq_group, don't choose it */ - if (cur_cfqq->cfqg != cfqq->cfqg) - return NULL; - - /* - * It only makes sense to merge sync queues. - */ - if (!cfq_cfqq_sync(cfqq)) - return NULL; - if (CFQQ_SEEKY(cfqq)) - return NULL; - - /* - * Do not merge queues of different priority classes - */ - if (cfq_class_rt(cfqq) != cfq_class_rt(cur_cfqq)) - return NULL; - - return cfqq; -} - -/* - * Determine whether we should enforce idle window for this queue. - */ - -static bool cfq_should_idle(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - enum wl_class_t wl_class = cfqq_class(cfqq); - struct cfq_rb_root *st = cfqq->service_tree; - - BUG_ON(!st); - BUG_ON(!st->count); - - if (!cfqd->cfq_slice_idle) - return false; - - /* We never do for idle class queues. */ - if (wl_class == IDLE_WORKLOAD) - return false; - - /* We do for queues that were marked with idle window flag. */ - if (cfq_cfqq_idle_window(cfqq) && - !(blk_queue_nonrot(cfqd->queue) && cfqd->hw_tag)) - return true; - - /* - * Otherwise, we do only if they are the last ones - * in their service tree. - */ - if (st->count == 1 && cfq_cfqq_sync(cfqq) && - !cfq_io_thinktime_big(cfqd, &st->ttime, false)) - return true; - cfq_log_cfqq(cfqd, cfqq, "Not idling. st->count:%d", st->count); - return false; -} - -static void cfq_arm_slice_timer(struct cfq_data *cfqd) -{ - struct cfq_queue *cfqq = cfqd->active_queue; - struct cfq_rb_root *st = cfqq->service_tree; - struct cfq_io_cq *cic; - u64 sl, group_idle = 0; - u64 now = ktime_get_ns(); - - /* - * SSD device without seek penalty, disable idling. But only do so - * for devices that support queuing, otherwise we still have a problem - * with sync vs async workloads. - */ - if (blk_queue_nonrot(cfqd->queue) && cfqd->hw_tag) - return; - - WARN_ON(!RB_EMPTY_ROOT(&cfqq->sort_list)); - WARN_ON(cfq_cfqq_slice_new(cfqq)); - - /* - * idle is disabled, either manually or by past process history - */ - if (!cfq_should_idle(cfqd, cfqq)) { - /* no queue idling. Check for group idling */ - if (cfqd->cfq_group_idle) - group_idle = cfqd->cfq_group_idle; - else - return; - } - - /* - * still active requests from this queue, don't idle - */ - if (cfqq->dispatched) - return; - - /* - * task has exited, don't wait - */ - cic = cfqd->active_cic; - if (!cic || !atomic_read(&cic->icq.ioc->active_ref)) - return; - - /* - * If our average think time is larger than the remaining time - * slice, then don't idle. This avoids overrunning the allotted - * time slice. - */ - if (sample_valid(cic->ttime.ttime_samples) && - (cfqq->slice_end - now < cic->ttime.ttime_mean)) { - cfq_log_cfqq(cfqd, cfqq, "Not idling. think_time:%llu", - cic->ttime.ttime_mean); - return; - } - - /* - * There are other queues in the group or this is the only group and - * it has too big thinktime, don't do group idle. - */ - if (group_idle && - (cfqq->cfqg->nr_cfqq > 1 || - cfq_io_thinktime_big(cfqd, &st->ttime, true))) - return; - - cfq_mark_cfqq_wait_request(cfqq); - - if (group_idle) - sl = cfqd->cfq_group_idle; - else - sl = cfqd->cfq_slice_idle; - - hrtimer_start(&cfqd->idle_slice_timer, ns_to_ktime(sl), - HRTIMER_MODE_REL); - cfqg_stats_set_start_idle_time(cfqq->cfqg); - cfq_log_cfqq(cfqd, cfqq, "arm_idle: %llu group_idle: %d", sl, - group_idle ? 1 : 0); -} - -/* - * Move request from internal lists to the request queue dispatch list. - */ -static void cfq_dispatch_insert(struct request_queue *q, struct request *rq) -{ - struct cfq_data *cfqd = q->elevator->elevator_data; - struct cfq_queue *cfqq = RQ_CFQQ(rq); - - cfq_log_cfqq(cfqd, cfqq, "dispatch_insert"); - - cfqq->next_rq = cfq_find_next_rq(cfqd, cfqq, rq); - cfq_remove_request(rq); - cfqq->dispatched++; - (RQ_CFQG(rq))->dispatched++; - elv_dispatch_sort(q, rq); - - cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]++; - cfqq->nr_sectors += blk_rq_sectors(rq); -} - -/* - * return expired entry, or NULL to just start from scratch in rbtree - */ -static struct request *cfq_check_fifo(struct cfq_queue *cfqq) -{ - struct request *rq = NULL; - - if (cfq_cfqq_fifo_expire(cfqq)) - return NULL; - - cfq_mark_cfqq_fifo_expire(cfqq); - - if (list_empty(&cfqq->fifo)) - return NULL; - - rq = rq_entry_fifo(cfqq->fifo.next); - if (ktime_get_ns() < rq->fifo_time) - rq = NULL; - - return rq; -} - -static inline int -cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - const int base_rq = cfqd->cfq_slice_async_rq; - - WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR); - - return 2 * base_rq * (IOPRIO_BE_NR - cfqq->ioprio); -} - -/* - * Must be called with the queue_lock held. - */ -static int cfqq_process_refs(struct cfq_queue *cfqq) -{ - int process_refs, io_refs; - - io_refs = cfqq->allocated[READ] + cfqq->allocated[WRITE]; - process_refs = cfqq->ref - io_refs; - BUG_ON(process_refs < 0); - return process_refs; -} - -static void cfq_setup_merge(struct cfq_queue *cfqq, struct cfq_queue *new_cfqq) -{ - int process_refs, new_process_refs; - struct cfq_queue *__cfqq; - - /* - * If there are no process references on the new_cfqq, then it is - * unsafe to follow the ->new_cfqq chain as other cfqq's in the - * chain may have dropped their last reference (not just their - * last process reference). - */ - if (!cfqq_process_refs(new_cfqq)) - return; - - /* Avoid a circular list and skip interim queue merges */ - while ((__cfqq = new_cfqq->new_cfqq)) { - if (__cfqq == cfqq) - return; - new_cfqq = __cfqq; - } - - process_refs = cfqq_process_refs(cfqq); - new_process_refs = cfqq_process_refs(new_cfqq); - /* - * If the process for the cfqq has gone away, there is no - * sense in merging the queues. - */ - if (process_refs == 0 || new_process_refs == 0) - return; - - /* - * Merge in the direction of the lesser amount of work. - */ - if (new_process_refs >= process_refs) { - cfqq->new_cfqq = new_cfqq; - new_cfqq->ref += process_refs; - } else { - new_cfqq->new_cfqq = cfqq; - cfqq->ref += new_process_refs; - } -} - -static enum wl_type_t cfq_choose_wl_type(struct cfq_data *cfqd, - struct cfq_group *cfqg, enum wl_class_t wl_class) -{ - struct cfq_queue *queue; - int i; - bool key_valid = false; - u64 lowest_key = 0; - enum wl_type_t cur_best = SYNC_NOIDLE_WORKLOAD; - - for (i = 0; i <= SYNC_WORKLOAD; ++i) { - /* select the one with lowest rb_key */ - queue = cfq_rb_first(st_for(cfqg, wl_class, i)); - if (queue && - (!key_valid || queue->rb_key < lowest_key)) { - lowest_key = queue->rb_key; - cur_best = i; - key_valid = true; - } - } - - return cur_best; -} - -static void -choose_wl_class_and_type(struct cfq_data *cfqd, struct cfq_group *cfqg) -{ - u64 slice; - unsigned count; - struct cfq_rb_root *st; - u64 group_slice; - enum wl_class_t original_class = cfqd->serving_wl_class; - u64 now = ktime_get_ns(); - - /* Choose next priority. RT > BE > IDLE */ - if (cfq_group_busy_queues_wl(RT_WORKLOAD, cfqd, cfqg)) - cfqd->serving_wl_class = RT_WORKLOAD; - else if (cfq_group_busy_queues_wl(BE_WORKLOAD, cfqd, cfqg)) - cfqd->serving_wl_class = BE_WORKLOAD; - else { - cfqd->serving_wl_class = IDLE_WORKLOAD; - cfqd->workload_expires = now + jiffies_to_nsecs(1); - return; - } - - if (original_class != cfqd->serving_wl_class) - goto new_workload; - - /* - * For RT and BE, we have to choose also the type - * (SYNC, SYNC_NOIDLE, ASYNC), and to compute a workload - * expiration time - */ - st = st_for(cfqg, cfqd->serving_wl_class, cfqd->serving_wl_type); - count = st->count; - - /* - * check workload expiration, and that we still have other queues ready - */ - if (count && !(now > cfqd->workload_expires)) - return; - -new_workload: - /* otherwise select new workload type */ - cfqd->serving_wl_type = cfq_choose_wl_type(cfqd, cfqg, - cfqd->serving_wl_class); - st = st_for(cfqg, cfqd->serving_wl_class, cfqd->serving_wl_type); - count = st->count; - - /* - * the workload slice is computed as a fraction of target latency - * proportional to the number of queues in that workload, over - * all the queues in the same priority class - */ - group_slice = cfq_group_slice(cfqd, cfqg); - - slice = div_u64(group_slice * count, - max_t(unsigned, cfqg->busy_queues_avg[cfqd->serving_wl_class], - cfq_group_busy_queues_wl(cfqd->serving_wl_class, cfqd, - cfqg))); - - if (cfqd->serving_wl_type == ASYNC_WORKLOAD) { - u64 tmp; - - /* - * Async queues are currently system wide. Just taking - * proportion of queues with-in same group will lead to higher - * async ratio system wide as generally root group is going - * to have higher weight. A more accurate thing would be to - * calculate system wide asnc/sync ratio. - */ - tmp = cfqd->cfq_target_latency * - cfqg_busy_async_queues(cfqd, cfqg); - tmp = div_u64(tmp, cfqd->busy_queues); - slice = min_t(u64, slice, tmp); - - /* async workload slice is scaled down according to - * the sync/async slice ratio. */ - slice = div64_u64(slice*cfqd->cfq_slice[0], cfqd->cfq_slice[1]); - } else - /* sync workload slice is at least 2 * cfq_slice_idle */ - slice = max(slice, 2 * cfqd->cfq_slice_idle); - - slice = max_t(u64, slice, CFQ_MIN_TT); - cfq_log(cfqd, "workload slice:%llu", slice); - cfqd->workload_expires = now + slice; -} - -static struct cfq_group *cfq_get_next_cfqg(struct cfq_data *cfqd) -{ - struct cfq_rb_root *st = &cfqd->grp_service_tree; - struct cfq_group *cfqg; - - if (RB_EMPTY_ROOT(&st->rb)) - return NULL; - cfqg = cfq_rb_first_group(st); - update_min_vdisktime(st); - return cfqg; -} - -static void cfq_choose_cfqg(struct cfq_data *cfqd) -{ - struct cfq_group *cfqg = cfq_get_next_cfqg(cfqd); - u64 now = ktime_get_ns(); - - cfqd->serving_group = cfqg; - - /* Restore the workload type data */ - if (cfqg->saved_wl_slice) { - cfqd->workload_expires = now + cfqg->saved_wl_slice; - cfqd->serving_wl_type = cfqg->saved_wl_type; - cfqd->serving_wl_class = cfqg->saved_wl_class; - } else - cfqd->workload_expires = now - 1; - - choose_wl_class_and_type(cfqd, cfqg); -} - -/* - * Select a queue for service. If we have a current active queue, - * check whether to continue servicing it, or retrieve and set a new one. - */ -static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd) -{ - struct cfq_queue *cfqq, *new_cfqq = NULL; - u64 now = ktime_get_ns(); - - cfqq = cfqd->active_queue; - if (!cfqq) - goto new_queue; - - if (!cfqd->rq_queued) - return NULL; - - /* - * We were waiting for group to get backlogged. Expire the queue - */ - if (cfq_cfqq_wait_busy(cfqq) && !RB_EMPTY_ROOT(&cfqq->sort_list)) - goto expire; - - /* - * The active queue has run out of time, expire it and select new. - */ - if (cfq_slice_used(cfqq) && !cfq_cfqq_must_dispatch(cfqq)) { - /* - * If slice had not expired at the completion of last request - * we might not have turned on wait_busy flag. Don't expire - * the queue yet. Allow the group to get backlogged. - * - * The very fact that we have used the slice, that means we - * have been idling all along on this queue and it should be - * ok to wait for this request to complete. - */ - if (cfqq->cfqg->nr_cfqq == 1 && RB_EMPTY_ROOT(&cfqq->sort_list) - && cfqq->dispatched && cfq_should_idle(cfqd, cfqq)) { - cfqq = NULL; - goto keep_queue; - } else - goto check_group_idle; - } - - /* - * The active queue has requests and isn't expired, allow it to - * dispatch. - */ - if (!RB_EMPTY_ROOT(&cfqq->sort_list)) - goto keep_queue; - - /* - * If another queue has a request waiting within our mean seek - * distance, let it run. The expire code will check for close - * cooperators and put the close queue at the front of the service - * tree. If possible, merge the expiring queue with the new cfqq. - */ - new_cfqq = cfq_close_cooperator(cfqd, cfqq); - if (new_cfqq) { - if (!cfqq->new_cfqq) - cfq_setup_merge(cfqq, new_cfqq); - goto expire; - } - - /* - * No requests pending. If the active queue still has requests in - * flight or is idling for a new request, allow either of these - * conditions to happen (or time out) before selecting a new queue. - */ - if (hrtimer_active(&cfqd->idle_slice_timer)) { - cfqq = NULL; - goto keep_queue; - } - - /* - * This is a deep seek queue, but the device is much faster than - * the queue can deliver, don't idle - **/ - if (CFQQ_SEEKY(cfqq) && cfq_cfqq_idle_window(cfqq) && - (cfq_cfqq_slice_new(cfqq) || - (cfqq->slice_end - now > now - cfqq->slice_start))) { - cfq_clear_cfqq_deep(cfqq); - cfq_clear_cfqq_idle_window(cfqq); - } - - if (cfqq->dispatched && cfq_should_idle(cfqd, cfqq)) { - cfqq = NULL; - goto keep_queue; - } - - /* - * If group idle is enabled and there are requests dispatched from - * this group, wait for requests to complete. - */ -check_group_idle: - if (cfqd->cfq_group_idle && cfqq->cfqg->nr_cfqq == 1 && - cfqq->cfqg->dispatched && - !cfq_io_thinktime_big(cfqd, &cfqq->cfqg->ttime, true)) { - cfqq = NULL; - goto keep_queue; - } - -expire: - cfq_slice_expired(cfqd, 0); -new_queue: - /* - * Current queue expired. Check if we have to switch to a new - * service tree - */ - if (!new_cfqq) - cfq_choose_cfqg(cfqd); - - cfqq = cfq_set_active_queue(cfqd, new_cfqq); -keep_queue: - return cfqq; -} - -static int __cfq_forced_dispatch_cfqq(struct cfq_queue *cfqq) -{ - int dispatched = 0; - - while (cfqq->next_rq) { - cfq_dispatch_insert(cfqq->cfqd->queue, cfqq->next_rq); - dispatched++; - } - - BUG_ON(!list_empty(&cfqq->fifo)); - - /* By default cfqq is not expired if it is empty. Do it explicitly */ - __cfq_slice_expired(cfqq->cfqd, cfqq, 0); - return dispatched; -} - -/* - * Drain our current requests. Used for barriers and when switching - * io schedulers on-the-fly. - */ -static int cfq_forced_dispatch(struct cfq_data *cfqd) -{ - struct cfq_queue *cfqq; - int dispatched = 0; - - /* Expire the timeslice of the current active queue first */ - cfq_slice_expired(cfqd, 0); - while ((cfqq = cfq_get_next_queue_forced(cfqd)) != NULL) { - __cfq_set_active_queue(cfqd, cfqq); - dispatched += __cfq_forced_dispatch_cfqq(cfqq); - } - - BUG_ON(cfqd->busy_queues); - - cfq_log(cfqd, "forced_dispatch=%d", dispatched); - return dispatched; -} - -static inline bool cfq_slice_used_soon(struct cfq_data *cfqd, - struct cfq_queue *cfqq) -{ - u64 now = ktime_get_ns(); - - /* the queue hasn't finished any request, can't estimate */ - if (cfq_cfqq_slice_new(cfqq)) - return true; - if (now + cfqd->cfq_slice_idle * cfqq->dispatched > cfqq->slice_end) - return true; - - return false; -} - -static bool cfq_may_dispatch(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - unsigned int max_dispatch; - - if (cfq_cfqq_must_dispatch(cfqq)) - return true; - - /* - * Drain async requests before we start sync IO - */ - if (cfq_should_idle(cfqd, cfqq) && cfqd->rq_in_flight[BLK_RW_ASYNC]) - return false; - - /* - * If this is an async queue and we have sync IO in flight, let it wait - */ - if (cfqd->rq_in_flight[BLK_RW_SYNC] && !cfq_cfqq_sync(cfqq)) - return false; - - max_dispatch = max_t(unsigned int, cfqd->cfq_quantum / 2, 1); - if (cfq_class_idle(cfqq)) - max_dispatch = 1; - - /* - * Does this cfqq already have too much IO in flight? - */ - if (cfqq->dispatched >= max_dispatch) { - bool promote_sync = false; - /* - * idle queue must always only have a single IO in flight - */ - if (cfq_class_idle(cfqq)) - return false; - - /* - * If there is only one sync queue - * we can ignore async queue here and give the sync - * queue no dispatch limit. The reason is a sync queue can - * preempt async queue, limiting the sync queue doesn't make - * sense. This is useful for aiostress test. - */ - if (cfq_cfqq_sync(cfqq) && cfqd->busy_sync_queues == 1) - promote_sync = true; - - /* - * We have other queues, don't allow more IO from this one - */ - if (cfqd->busy_queues > 1 && cfq_slice_used_soon(cfqd, cfqq) && - !promote_sync) - return false; - - /* - * Sole queue user, no limit - */ - if (cfqd->busy_queues == 1 || promote_sync) - max_dispatch = -1; - else - /* - * Normally we start throttling cfqq when cfq_quantum/2 - * requests have been dispatched. But we can drive - * deeper queue depths at the beginning of slice - * subjected to upper limit of cfq_quantum. - * */ - max_dispatch = cfqd->cfq_quantum; - } - - /* - * Async queues must wait a bit before being allowed dispatch. - * We also ramp up the dispatch depth gradually for async IO, - * based on the last sync IO we serviced - */ - if (!cfq_cfqq_sync(cfqq) && cfqd->cfq_latency) { - u64 last_sync = ktime_get_ns() - cfqd->last_delayed_sync; - unsigned int depth; - - depth = div64_u64(last_sync, cfqd->cfq_slice[1]); - if (!depth && !cfqq->dispatched) - depth = 1; - if (depth < max_dispatch) - max_dispatch = depth; - } - - /* - * If we're below the current max, allow a dispatch - */ - return cfqq->dispatched < max_dispatch; -} - -/* - * Dispatch a request from cfqq, moving them to the request queue - * dispatch list. - */ -static bool cfq_dispatch_request(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - struct request *rq; - - BUG_ON(RB_EMPTY_ROOT(&cfqq->sort_list)); - - rq = cfq_check_fifo(cfqq); - if (rq) - cfq_mark_cfqq_must_dispatch(cfqq); - - if (!cfq_may_dispatch(cfqd, cfqq)) - return false; - - /* - * follow expired path, else get first next available - */ - if (!rq) - rq = cfqq->next_rq; - else - cfq_log_cfqq(cfqq->cfqd, cfqq, "fifo=%p", rq); - - /* - * insert request into driver dispatch list - */ - cfq_dispatch_insert(cfqd->queue, rq); - - if (!cfqd->active_cic) { - struct cfq_io_cq *cic = RQ_CIC(rq); - - atomic_long_inc(&cic->icq.ioc->refcount); - cfqd->active_cic = cic; - } - - return true; -} - -/* - * Find the cfqq that we need to service and move a request from that to the - * dispatch list - */ -static int cfq_dispatch_requests(struct request_queue *q, int force) -{ - struct cfq_data *cfqd = q->elevator->elevator_data; - struct cfq_queue *cfqq; - - if (!cfqd->busy_queues) - return 0; - - if (unlikely(force)) - return cfq_forced_dispatch(cfqd); - - cfqq = cfq_select_queue(cfqd); - if (!cfqq) - return 0; - - /* - * Dispatch a request from this cfqq, if it is allowed - */ - if (!cfq_dispatch_request(cfqd, cfqq)) - return 0; - - cfqq->slice_dispatch++; - cfq_clear_cfqq_must_dispatch(cfqq); - - /* - * expire an async queue immediately if it has used up its slice. idle - * queue always expire after 1 dispatch round. - */ - if (cfqd->busy_queues > 1 && ((!cfq_cfqq_sync(cfqq) && - cfqq->slice_dispatch >= cfq_prio_to_maxrq(cfqd, cfqq)) || - cfq_class_idle(cfqq))) { - cfqq->slice_end = ktime_get_ns() + 1; - cfq_slice_expired(cfqd, 0); - } - - cfq_log_cfqq(cfqd, cfqq, "dispatched a request"); - return 1; -} - -/* - * task holds one reference to the queue, dropped when task exits. each rq - * in-flight on this queue also holds a reference, dropped when rq is freed. - * - * Each cfq queue took a reference on the parent group. Drop it now. - * queue lock must be held here. - */ -static void cfq_put_queue(struct cfq_queue *cfqq) -{ - struct cfq_data *cfqd = cfqq->cfqd; - struct cfq_group *cfqg; - - BUG_ON(cfqq->ref <= 0); - - cfqq->ref--; - if (cfqq->ref) - return; - - cfq_log_cfqq(cfqd, cfqq, "put_queue"); - BUG_ON(rb_first(&cfqq->sort_list)); - BUG_ON(cfqq->allocated[READ] + cfqq->allocated[WRITE]); - cfqg = cfqq->cfqg; - - if (unlikely(cfqd->active_queue == cfqq)) { - __cfq_slice_expired(cfqd, cfqq, 0); - cfq_schedule_dispatch(cfqd); - } - - BUG_ON(cfq_cfqq_on_rr(cfqq)); - kmem_cache_free(cfq_pool, cfqq); - cfqg_put(cfqg); -} - -static void cfq_put_cooperator(struct cfq_queue *cfqq) -{ - struct cfq_queue *__cfqq, *next; - - /* - * If this queue was scheduled to merge with another queue, be - * sure to drop the reference taken on that queue (and others in - * the merge chain). See cfq_setup_merge and cfq_merge_cfqqs. - */ - __cfqq = cfqq->new_cfqq; - while (__cfqq) { - if (__cfqq == cfqq) { - WARN(1, "cfqq->new_cfqq loop detected\n"); - break; - } - next = __cfqq->new_cfqq; - cfq_put_queue(__cfqq); - __cfqq = next; - } -} - -static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - if (unlikely(cfqq == cfqd->active_queue)) { - __cfq_slice_expired(cfqd, cfqq, 0); - cfq_schedule_dispatch(cfqd); - } - - cfq_put_cooperator(cfqq); - - cfq_put_queue(cfqq); -} - -static void cfq_init_icq(struct io_cq *icq) -{ - struct cfq_io_cq *cic = icq_to_cic(icq); - - cic->ttime.last_end_request = ktime_get_ns(); -} - -static void cfq_exit_icq(struct io_cq *icq) -{ - struct cfq_io_cq *cic = icq_to_cic(icq); - struct cfq_data *cfqd = cic_to_cfqd(cic); - - if (cic_to_cfqq(cic, false)) { - cfq_exit_cfqq(cfqd, cic_to_cfqq(cic, false)); - cic_set_cfqq(cic, NULL, false); - } - - if (cic_to_cfqq(cic, true)) { - cfq_exit_cfqq(cfqd, cic_to_cfqq(cic, true)); - cic_set_cfqq(cic, NULL, true); - } -} - -static void cfq_init_prio_data(struct cfq_queue *cfqq, struct cfq_io_cq *cic) -{ - struct task_struct *tsk = current; - int ioprio_class; - - if (!cfq_cfqq_prio_changed(cfqq)) - return; - - ioprio_class = IOPRIO_PRIO_CLASS(cic->ioprio); - switch (ioprio_class) { - default: - printk(KERN_ERR "cfq: bad prio %x\n", ioprio_class); - case IOPRIO_CLASS_NONE: - /* - * no prio set, inherit CPU scheduling settings - */ - cfqq->ioprio = task_nice_ioprio(tsk); - cfqq->ioprio_class = task_nice_ioclass(tsk); - break; - case IOPRIO_CLASS_RT: - cfqq->ioprio = IOPRIO_PRIO_DATA(cic->ioprio); - cfqq->ioprio_class = IOPRIO_CLASS_RT; - break; - case IOPRIO_CLASS_BE: - cfqq->ioprio = IOPRIO_PRIO_DATA(cic->ioprio); - cfqq->ioprio_class = IOPRIO_CLASS_BE; - break; - case IOPRIO_CLASS_IDLE: - cfqq->ioprio_class = IOPRIO_CLASS_IDLE; - cfqq->ioprio = 7; - cfq_clear_cfqq_idle_window(cfqq); - break; - } - - /* - * keep track of original prio settings in case we have to temporarily - * elevate the priority of this queue - */ - cfqq->org_ioprio = cfqq->ioprio; - cfqq->org_ioprio_class = cfqq->ioprio_class; - cfq_clear_cfqq_prio_changed(cfqq); -} - -static void check_ioprio_changed(struct cfq_io_cq *cic, struct bio *bio) -{ - int ioprio = cic->icq.ioc->ioprio; - struct cfq_data *cfqd = cic_to_cfqd(cic); - struct cfq_queue *cfqq; - - /* - * Check whether ioprio has changed. The condition may trigger - * spuriously on a newly created cic but there's no harm. - */ - if (unlikely(!cfqd) || likely(cic->ioprio == ioprio)) - return; - - cfqq = cic_to_cfqq(cic, false); - if (cfqq) { - cfq_put_queue(cfqq); - cfqq = cfq_get_queue(cfqd, BLK_RW_ASYNC, cic, bio); - cic_set_cfqq(cic, cfqq, false); - } - - cfqq = cic_to_cfqq(cic, true); - if (cfqq) - cfq_mark_cfqq_prio_changed(cfqq); - - cic->ioprio = ioprio; -} - -static void cfq_init_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq, - pid_t pid, bool is_sync) -{ - RB_CLEAR_NODE(&cfqq->rb_node); - RB_CLEAR_NODE(&cfqq->p_node); - INIT_LIST_HEAD(&cfqq->fifo); - - cfqq->ref = 0; - cfqq->cfqd = cfqd; - - cfq_mark_cfqq_prio_changed(cfqq); - - if (is_sync) { - if (!cfq_class_idle(cfqq)) - cfq_mark_cfqq_idle_window(cfqq); - cfq_mark_cfqq_sync(cfqq); - } - cfqq->pid = pid; -} - -#ifdef CONFIG_CFQ_GROUP_IOSCHED -static void check_blkcg_changed(struct cfq_io_cq *cic, struct bio *bio) -{ - struct cfq_data *cfqd = cic_to_cfqd(cic); - struct cfq_queue *cfqq; - uint64_t serial_nr; - - rcu_read_lock(); - serial_nr = bio_blkcg(bio)->css.serial_nr; - rcu_read_unlock(); - - /* - * Check whether blkcg has changed. The condition may trigger - * spuriously on a newly created cic but there's no harm. - */ - if (unlikely(!cfqd) || likely(cic->blkcg_serial_nr == serial_nr)) - return; - - /* - * Drop reference to queues. New queues will be assigned in new - * group upon arrival of fresh requests. - */ - cfqq = cic_to_cfqq(cic, false); - if (cfqq) { - cfq_log_cfqq(cfqd, cfqq, "changed cgroup"); - cic_set_cfqq(cic, NULL, false); - cfq_put_queue(cfqq); - } - - cfqq = cic_to_cfqq(cic, true); - if (cfqq) { - cfq_log_cfqq(cfqd, cfqq, "changed cgroup"); - cic_set_cfqq(cic, NULL, true); - cfq_put_queue(cfqq); - } - - cic->blkcg_serial_nr = serial_nr; -} -#else -static inline void check_blkcg_changed(struct cfq_io_cq *cic, struct bio *bio) { } -#endif /* CONFIG_CFQ_GROUP_IOSCHED */ - -static struct cfq_queue ** -cfq_async_queue_prio(struct cfq_group *cfqg, int ioprio_class, int ioprio) -{ - switch (ioprio_class) { - case IOPRIO_CLASS_RT: - return &cfqg->async_cfqq[0][ioprio]; - case IOPRIO_CLASS_NONE: - ioprio = IOPRIO_NORM; - /* fall through */ - case IOPRIO_CLASS_BE: - return &cfqg->async_cfqq[1][ioprio]; - case IOPRIO_CLASS_IDLE: - return &cfqg->async_idle_cfqq; - default: - BUG(); - } -} - -static struct cfq_queue * -cfq_get_queue(struct cfq_data *cfqd, bool is_sync, struct cfq_io_cq *cic, - struct bio *bio) -{ - int ioprio_class = IOPRIO_PRIO_CLASS(cic->ioprio); - int ioprio = IOPRIO_PRIO_DATA(cic->ioprio); - struct cfq_queue **async_cfqq = NULL; - struct cfq_queue *cfqq; - struct cfq_group *cfqg; - - rcu_read_lock(); - cfqg = cfq_lookup_cfqg(cfqd, bio_blkcg(bio)); - if (!cfqg) { - cfqq = &cfqd->oom_cfqq; - goto out; - } - - if (!is_sync) { - if (!ioprio_valid(cic->ioprio)) { - struct task_struct *tsk = current; - ioprio = task_nice_ioprio(tsk); - ioprio_class = task_nice_ioclass(tsk); - } - async_cfqq = cfq_async_queue_prio(cfqg, ioprio_class, ioprio); - cfqq = *async_cfqq; - if (cfqq) - goto out; - } - - cfqq = kmem_cache_alloc_node(cfq_pool, GFP_NOWAIT | __GFP_ZERO, - cfqd->queue->node); - if (!cfqq) { - cfqq = &cfqd->oom_cfqq; - goto out; - } - - cfq_init_cfqq(cfqd, cfqq, current->pid, is_sync); - cfq_init_prio_data(cfqq, cic); - cfq_link_cfqq_cfqg(cfqq, cfqg); - cfq_log_cfqq(cfqd, cfqq, "alloced"); - - if (async_cfqq) { - /* a new async queue is created, pin and remember */ - cfqq->ref++; - *async_cfqq = cfqq; - } -out: - cfqq->ref++; - rcu_read_unlock(); - return cfqq; -} - -static void -__cfq_update_io_thinktime(struct cfq_ttime *ttime, u64 slice_idle) -{ - u64 elapsed = ktime_get_ns() - ttime->last_end_request; - elapsed = min(elapsed, 2UL * slice_idle); - - ttime->ttime_samples = (7*ttime->ttime_samples + 256) / 8; - ttime->ttime_total = div_u64(7*ttime->ttime_total + 256*elapsed, 8); - ttime->ttime_mean = div64_ul(ttime->ttime_total + 128, - ttime->ttime_samples); -} - -static void -cfq_update_io_thinktime(struct cfq_data *cfqd, struct cfq_queue *cfqq, - struct cfq_io_cq *cic) -{ - if (cfq_cfqq_sync(cfqq)) { - __cfq_update_io_thinktime(&cic->ttime, cfqd->cfq_slice_idle); - __cfq_update_io_thinktime(&cfqq->service_tree->ttime, - cfqd->cfq_slice_idle); - } -#ifdef CONFIG_CFQ_GROUP_IOSCHED - __cfq_update_io_thinktime(&cfqq->cfqg->ttime, cfqd->cfq_group_idle); -#endif -} - -static void -cfq_update_io_seektime(struct cfq_data *cfqd, struct cfq_queue *cfqq, - struct request *rq) -{ - sector_t sdist = 0; - sector_t n_sec = blk_rq_sectors(rq); - if (cfqq->last_request_pos) { - if (cfqq->last_request_pos < blk_rq_pos(rq)) - sdist = blk_rq_pos(rq) - cfqq->last_request_pos; - else - sdist = cfqq->last_request_pos - blk_rq_pos(rq); - } - - cfqq->seek_history <<= 1; - if (blk_queue_nonrot(cfqd->queue)) - cfqq->seek_history |= (n_sec < CFQQ_SECT_THR_NONROT); - else - cfqq->seek_history |= (sdist > CFQQ_SEEK_THR); -} - -/* - * Disable idle window if the process thinks too long or seeks so much that - * it doesn't matter - */ -static void -cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq, - struct cfq_io_cq *cic) -{ - int old_idle, enable_idle; - - /* - * Don't idle for async or idle io prio class - */ - if (!cfq_cfqq_sync(cfqq) || cfq_class_idle(cfqq)) - return; - - enable_idle = old_idle = cfq_cfqq_idle_window(cfqq); - - if (cfqq->queued[0] + cfqq->queued[1] >= 4) - cfq_mark_cfqq_deep(cfqq); - - if (cfqq->next_rq && (cfqq->next_rq->cmd_flags & REQ_NOIDLE)) - enable_idle = 0; - else if (!atomic_read(&cic->icq.ioc->active_ref) || - !cfqd->cfq_slice_idle || - (!cfq_cfqq_deep(cfqq) && CFQQ_SEEKY(cfqq))) - enable_idle = 0; - else if (sample_valid(cic->ttime.ttime_samples)) { - if (cic->ttime.ttime_mean > cfqd->cfq_slice_idle) - enable_idle = 0; - else - enable_idle = 1; - } - - if (old_idle != enable_idle) { - cfq_log_cfqq(cfqd, cfqq, "idle=%d", enable_idle); - if (enable_idle) - cfq_mark_cfqq_idle_window(cfqq); - else - cfq_clear_cfqq_idle_window(cfqq); - } -} - -/* - * Check if new_cfqq should preempt the currently active queue. Return 0 for - * no or if we aren't sure, a 1 will cause a preempt. - */ -static bool -cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq, - struct request *rq) -{ - struct cfq_queue *cfqq; - - cfqq = cfqd->active_queue; - if (!cfqq) - return false; - - if (cfq_class_idle(new_cfqq)) - return false; - - if (cfq_class_idle(cfqq)) - return true; - - /* - * Don't allow a non-RT request to preempt an ongoing RT cfqq timeslice. - */ - if (cfq_class_rt(cfqq) && !cfq_class_rt(new_cfqq)) - return false; - - /* - * if the new request is sync, but the currently running queue is - * not, let the sync request have priority. - */ - if (rq_is_sync(rq) && !cfq_cfqq_sync(cfqq) && !cfq_cfqq_must_dispatch(cfqq)) - return true; - - /* - * Treat ancestors of current cgroup the same way as current cgroup. - * For anybody else we disallow preemption to guarantee service - * fairness among cgroups. - */ - if (!cfqg_is_descendant(cfqq->cfqg, new_cfqq->cfqg)) - return false; - - if (cfq_slice_used(cfqq)) - return true; - - /* - * Allow an RT request to pre-empt an ongoing non-RT cfqq timeslice. - */ - if (cfq_class_rt(new_cfqq) && !cfq_class_rt(cfqq)) - return true; - - WARN_ON_ONCE(cfqq->ioprio_class != new_cfqq->ioprio_class); - /* Allow preemption only if we are idling on sync-noidle tree */ - if (cfqd->serving_wl_type == SYNC_NOIDLE_WORKLOAD && - cfqq_type(new_cfqq) == SYNC_NOIDLE_WORKLOAD && - RB_EMPTY_ROOT(&cfqq->sort_list)) - return true; - - /* - * So both queues are sync. Let the new request get disk time if - * it's a metadata request and the current queue is doing regular IO. - */ - if ((rq->cmd_flags & REQ_PRIO) && !cfqq->prio_pending) - return true; - - /* An idle queue should not be idle now for some reason */ - if (RB_EMPTY_ROOT(&cfqq->sort_list) && !cfq_should_idle(cfqd, cfqq)) - return true; - - if (!cfqd->active_cic || !cfq_cfqq_wait_request(cfqq)) - return false; - - /* - * if this request is as-good as one we would expect from the - * current cfqq, let it preempt - */ - if (cfq_rq_close(cfqd, cfqq, rq)) - return true; - - return false; -} - -/* - * cfqq preempts the active queue. if we allowed preempt with no slice left, - * let it have half of its nominal slice. - */ -static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - enum wl_type_t old_type = cfqq_type(cfqd->active_queue); - - cfq_log_cfqq(cfqd, cfqq, "preempt"); - cfq_slice_expired(cfqd, 1); - - /* - * workload type is changed, don't save slice, otherwise preempt - * doesn't happen - */ - if (old_type != cfqq_type(cfqq)) - cfqq->cfqg->saved_wl_slice = 0; - - /* - * Put the new queue at the front of the of the current list, - * so we know that it will be selected next. - */ - BUG_ON(!cfq_cfqq_on_rr(cfqq)); - - cfq_service_tree_add(cfqd, cfqq, 1); - - cfqq->slice_end = 0; - cfq_mark_cfqq_slice_new(cfqq); -} - -/* - * Called when a new fs request (rq) is added (to cfqq). Check if there's - * something we should do about it - */ -static void -cfq_rq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq, - struct request *rq) -{ - struct cfq_io_cq *cic = RQ_CIC(rq); - - cfqd->rq_queued++; - if (rq->cmd_flags & REQ_PRIO) - cfqq->prio_pending++; - - cfq_update_io_thinktime(cfqd, cfqq, cic); - cfq_update_io_seektime(cfqd, cfqq, rq); - cfq_update_idle_window(cfqd, cfqq, cic); - - cfqq->last_request_pos = blk_rq_pos(rq) + blk_rq_sectors(rq); - - if (cfqq == cfqd->active_queue) { - /* - * Remember that we saw a request from this process, but - * don't start queuing just yet. Otherwise we risk seeing lots - * of tiny requests, because we disrupt the normal plugging - * and merging. If the request is already larger than a single - * page, let it rip immediately. For that case we assume that - * merging is already done. Ditto for a busy system that - * has other work pending, don't risk delaying until the - * idle timer unplug to continue working. - */ - if (cfq_cfqq_wait_request(cfqq)) { - if (blk_rq_bytes(rq) > PAGE_SIZE || - cfqd->busy_queues > 1) { - cfq_del_timer(cfqd, cfqq); - cfq_clear_cfqq_wait_request(cfqq); - __blk_run_queue(cfqd->queue); - } else { - cfqg_stats_update_idle_time(cfqq->cfqg); - cfq_mark_cfqq_must_dispatch(cfqq); - } - } - } else if (cfq_should_preempt(cfqd, cfqq, rq)) { - /* - * not the active queue - expire current slice if it is - * idle and has expired it's mean thinktime or this new queue - * has some old slice time left and is of higher priority or - * this new queue is RT and the current one is BE - */ - cfq_preempt_queue(cfqd, cfqq); - __blk_run_queue(cfqd->queue); - } -} - -static void cfq_insert_request(struct request_queue *q, struct request *rq) -{ - struct cfq_data *cfqd = q->elevator->elevator_data; - struct cfq_queue *cfqq = RQ_CFQQ(rq); - - cfq_log_cfqq(cfqd, cfqq, "insert_request"); - cfq_init_prio_data(cfqq, RQ_CIC(rq)); - - rq->fifo_time = ktime_get_ns() + cfqd->cfq_fifo_expire[rq_is_sync(rq)]; - list_add_tail(&rq->queuelist, &cfqq->fifo); - cfq_add_rq_rb(rq); - cfqg_stats_update_io_add(RQ_CFQG(rq), cfqd->serving_group, req_op(rq), - rq->cmd_flags); - cfq_rq_enqueued(cfqd, cfqq, rq); -} - -/* - * Update hw_tag based on peak queue depth over 50 samples under - * sufficient load. - */ -static void cfq_update_hw_tag(struct cfq_data *cfqd) -{ - struct cfq_queue *cfqq = cfqd->active_queue; - - if (cfqd->rq_in_driver > cfqd->hw_tag_est_depth) - cfqd->hw_tag_est_depth = cfqd->rq_in_driver; - - if (cfqd->hw_tag == 1) - return; - - if (cfqd->rq_queued <= CFQ_HW_QUEUE_MIN && - cfqd->rq_in_driver <= CFQ_HW_QUEUE_MIN) - return; - - /* - * If active queue hasn't enough requests and can idle, cfq might not - * dispatch sufficient requests to hardware. Don't zero hw_tag in this - * case - */ - if (cfqq && cfq_cfqq_idle_window(cfqq) && - cfqq->dispatched + cfqq->queued[0] + cfqq->queued[1] < - CFQ_HW_QUEUE_MIN && cfqd->rq_in_driver < CFQ_HW_QUEUE_MIN) - return; - - if (cfqd->hw_tag_samples++ < 50) - return; - - if (cfqd->hw_tag_est_depth >= CFQ_HW_QUEUE_MIN) - cfqd->hw_tag = 1; - else - cfqd->hw_tag = 0; -} - -static bool cfq_should_wait_busy(struct cfq_data *cfqd, struct cfq_queue *cfqq) -{ - struct cfq_io_cq *cic = cfqd->active_cic; - u64 now = ktime_get_ns(); - - /* If the queue already has requests, don't wait */ - if (!RB_EMPTY_ROOT(&cfqq->sort_list)) - return false; - - /* If there are other queues in the group, don't wait */ - if (cfqq->cfqg->nr_cfqq > 1) - return false; - - /* the only queue in the group, but think time is big */ - if (cfq_io_thinktime_big(cfqd, &cfqq->cfqg->ttime, true)) - return false; - - if (cfq_slice_used(cfqq)) - return true; - - /* if slice left is less than think time, wait busy */ - if (cic && sample_valid(cic->ttime.ttime_samples) - && (cfqq->slice_end - now < cic->ttime.ttime_mean)) - return true; - - /* - * If think times is less than a jiffy than ttime_mean=0 and above - * will not be true. It might happen that slice has not expired yet - * but will expire soon (4-5 ns) during select_queue(). To cover the - * case where think time is less than a jiffy, mark the queue wait - * busy if only 1 jiffy is left in the slice. - */ - if (cfqq->slice_end - now <= jiffies_to_nsecs(1)) - return true; - - return false; -} - -static void cfq_completed_request(struct request_queue *q, struct request *rq) -{ - struct cfq_queue *cfqq = RQ_CFQQ(rq); - struct cfq_data *cfqd = cfqq->cfqd; - const int sync = rq_is_sync(rq); - u64 now = ktime_get_ns(); - - cfq_log_cfqq(cfqd, cfqq, "complete rqnoidle %d", - !!(rq->cmd_flags & REQ_NOIDLE)); - - cfq_update_hw_tag(cfqd); - - WARN_ON(!cfqd->rq_in_driver); - WARN_ON(!cfqq->dispatched); - cfqd->rq_in_driver--; - cfqq->dispatched--; - (RQ_CFQG(rq))->dispatched--; - cfqg_stats_update_completion(cfqq->cfqg, rq_start_time_ns(rq), - rq_io_start_time_ns(rq), req_op(rq), - rq->cmd_flags); - - cfqd->rq_in_flight[cfq_cfqq_sync(cfqq)]--; - - if (sync) { - struct cfq_rb_root *st; - - RQ_CIC(rq)->ttime.last_end_request = now; - - if (cfq_cfqq_on_rr(cfqq)) - st = cfqq->service_tree; - else - st = st_for(cfqq->cfqg, cfqq_class(cfqq), - cfqq_type(cfqq)); - - st->ttime.last_end_request = now; - /* - * We have to do this check in jiffies since start_time is in - * jiffies and it is not trivial to convert to ns. If - * cfq_fifo_expire[1] ever comes close to 1 jiffie, this test - * will become problematic but so far we are fine (the default - * is 128 ms). - */ - if (!time_after(rq->start_time + - nsecs_to_jiffies(cfqd->cfq_fifo_expire[1]), - jiffies)) - cfqd->last_delayed_sync = now; - } - -#ifdef CONFIG_CFQ_GROUP_IOSCHED - cfqq->cfqg->ttime.last_end_request = now; -#endif - - /* - * If this is the active queue, check if it needs to be expired, - * or if we want to idle in case it has no pending requests. - */ - if (cfqd->active_queue == cfqq) { - const bool cfqq_empty = RB_EMPTY_ROOT(&cfqq->sort_list); - - if (cfq_cfqq_slice_new(cfqq)) { - cfq_set_prio_slice(cfqd, cfqq); - cfq_clear_cfqq_slice_new(cfqq); - } - - /* - * Should we wait for next request to come in before we expire - * the queue. - */ - if (cfq_should_wait_busy(cfqd, cfqq)) { - u64 extend_sl = cfqd->cfq_slice_idle; - if (!cfqd->cfq_slice_idle) - extend_sl = cfqd->cfq_group_idle; - cfqq->slice_end = now + extend_sl; - cfq_mark_cfqq_wait_busy(cfqq); - cfq_log_cfqq(cfqd, cfqq, "will busy wait"); - } - - /* - * Idling is not enabled on: - * - expired queues - * - idle-priority queues - * - async queues - * - queues with still some requests queued - * - when there is a close cooperator - */ - if (cfq_slice_used(cfqq) || cfq_class_idle(cfqq)) - cfq_slice_expired(cfqd, 1); - else if (sync && cfqq_empty && - !cfq_close_cooperator(cfqd, cfqq)) { - cfq_arm_slice_timer(cfqd); - } - } - - if (!cfqd->rq_in_driver) - cfq_schedule_dispatch(cfqd); -} - -static void cfqq_boost_on_prio(struct cfq_queue *cfqq, int op_flags) -{ - /* - * If REQ_PRIO is set, boost class and prio level, if it's below - * BE/NORM. If prio is not set, restore the potentially boosted - * class/prio level. - */ - if (!(op_flags & REQ_PRIO)) { - cfqq->ioprio_class = cfqq->org_ioprio_class; - cfqq->ioprio = cfqq->org_ioprio; - } else { - if (cfq_class_idle(cfqq)) - cfqq->ioprio_class = IOPRIO_CLASS_BE; - if (cfqq->ioprio > IOPRIO_NORM) - cfqq->ioprio = IOPRIO_NORM; - } -} - -static inline int __cfq_may_queue(struct cfq_queue *cfqq) -{ - if (cfq_cfqq_wait_request(cfqq) && !cfq_cfqq_must_alloc_slice(cfqq)) { - cfq_mark_cfqq_must_alloc_slice(cfqq); - return ELV_MQUEUE_MUST; - } - - return ELV_MQUEUE_MAY; -} - -static int cfq_may_queue(struct request_queue *q, int op, int op_flags) -{ - struct cfq_data *cfqd = q->elevator->elevator_data; - struct task_struct *tsk = current; - struct cfq_io_cq *cic; - struct cfq_queue *cfqq; - - /* - * don't force setup of a queue from here, as a call to may_queue - * does not necessarily imply that a request actually will be queued. - * so just lookup a possibly existing queue, or return 'may queue' - * if that fails - */ - cic = cfq_cic_lookup(cfqd, tsk->io_context); - if (!cic) - return ELV_MQUEUE_MAY; - - cfqq = cic_to_cfqq(cic, rw_is_sync(op, op_flags)); - if (cfqq) { - cfq_init_prio_data(cfqq, cic); - cfqq_boost_on_prio(cfqq, op_flags); - - return __cfq_may_queue(cfqq); - } - - return ELV_MQUEUE_MAY; -} - -/* - * queue lock held here - */ -static void cfq_put_request(struct request *rq) -{ - struct cfq_queue *cfqq = RQ_CFQQ(rq); - - if (cfqq) { - const int rw = rq_data_dir(rq); - - BUG_ON(!cfqq->allocated[rw]); - cfqq->allocated[rw]--; - - /* Put down rq reference on cfqg */ - cfqg_put(RQ_CFQG(rq)); - rq->elv.priv[0] = NULL; - rq->elv.priv[1] = NULL; - - cfq_put_queue(cfqq); - } -} - -static struct cfq_queue * -cfq_merge_cfqqs(struct cfq_data *cfqd, struct cfq_io_cq *cic, - struct cfq_queue *cfqq) -{ - cfq_log_cfqq(cfqd, cfqq, "merging with queue %p", cfqq->new_cfqq); - cic_set_cfqq(cic, cfqq->new_cfqq, 1); - cfq_mark_cfqq_coop(cfqq->new_cfqq); - cfq_put_queue(cfqq); - return cic_to_cfqq(cic, 1); -} - -/* - * Returns NULL if a new cfqq should be allocated, or the old cfqq if this - * was the last process referring to said cfqq. - */ -static struct cfq_queue * -split_cfqq(struct cfq_io_cq *cic, struct cfq_queue *cfqq) -{ - if (cfqq_process_refs(cfqq) == 1) { - cfqq->pid = current->pid; - cfq_clear_cfqq_coop(cfqq); - cfq_clear_cfqq_split_coop(cfqq); - return cfqq; - } - - cic_set_cfqq(cic, NULL, 1); - - cfq_put_cooperator(cfqq); - - cfq_put_queue(cfqq); - return NULL; -} -/* - * Allocate cfq data structures associated with this request. - */ -static int -cfq_set_request(struct request_queue *q, struct request *rq, struct bio *bio, - gfp_t gfp_mask) -{ - struct cfq_data *cfqd = q->elevator->elevator_data; - struct cfq_io_cq *cic = icq_to_cic(rq->elv.icq); - const int rw = rq_data_dir(rq); - const bool is_sync = rq_is_sync(rq); - struct cfq_queue *cfqq; - - spin_lock_irq(q->queue_lock); - - check_ioprio_changed(cic, bio); - check_blkcg_changed(cic, bio); -new_queue: - cfqq = cic_to_cfqq(cic, is_sync); - if (!cfqq || cfqq == &cfqd->oom_cfqq) { - if (cfqq) - cfq_put_queue(cfqq); - cfqq = cfq_get_queue(cfqd, is_sync, cic, bio); - cic_set_cfqq(cic, cfqq, is_sync); - } else { - /* - * If the queue was seeky for too long, break it apart. - */ - if (cfq_cfqq_coop(cfqq) && cfq_cfqq_split_coop(cfqq)) { - cfq_log_cfqq(cfqd, cfqq, "breaking apart cfqq"); - cfqq = split_cfqq(cic, cfqq); - if (!cfqq) - goto new_queue; - } - - /* - * Check to see if this queue is scheduled to merge with - * another, closely cooperating queue. The merging of - * queues happens here as it must be done in process context. - * The reference on new_cfqq was taken in merge_cfqqs. - */ - if (cfqq->new_cfqq) - cfqq = cfq_merge_cfqqs(cfqd, cic, cfqq); - } - - cfqq->allocated[rw]++; - - cfqq->ref++; - cfqg_get(cfqq->cfqg); - rq->elv.priv[0] = cfqq; - rq->elv.priv[1] = cfqq->cfqg; - spin_unlock_irq(q->queue_lock); - return 0; -} - -static void cfq_kick_queue(struct work_struct *work) -{ - struct cfq_data *cfqd = - container_of(work, struct cfq_data, unplug_work); - struct request_queue *q = cfqd->queue; - - spin_lock_irq(q->queue_lock); - __blk_run_queue(cfqd->queue); - spin_unlock_irq(q->queue_lock); -} - -/* - * Timer running if the active_queue is currently idling inside its time slice - */ -static enum hrtimer_restart cfq_idle_slice_timer(struct hrtimer *timer) -{ - struct cfq_data *cfqd = container_of(timer, struct cfq_data, - idle_slice_timer); - struct cfq_queue *cfqq; - unsigned long flags; - int timed_out = 1; - - cfq_log(cfqd, "idle timer fired"); - - spin_lock_irqsave(cfqd->queue->queue_lock, flags); - - cfqq = cfqd->active_queue; - if (cfqq) { - timed_out = 0; - - /* - * We saw a request before the queue expired, let it through - */ - if (cfq_cfqq_must_dispatch(cfqq)) - goto out_kick; - - /* - * expired - */ - if (cfq_slice_used(cfqq)) - goto expire; - - /* - * only expire and reinvoke request handler, if there are - * other queues with pending requests - */ - if (!cfqd->busy_queues) - goto out_cont; - - /* - * not expired and it has a request pending, let it dispatch - */ - if (!RB_EMPTY_ROOT(&cfqq->sort_list)) - goto out_kick; - - /* - * Queue depth flag is reset only when the idle didn't succeed - */ - cfq_clear_cfqq_deep(cfqq); - } -expire: - cfq_slice_expired(cfqd, timed_out); -out_kick: - cfq_schedule_dispatch(cfqd); -out_cont: - spin_unlock_irqrestore(cfqd->queue->queue_lock, flags); - return HRTIMER_NORESTART; -} - -static void cfq_shutdown_timer_wq(struct cfq_data *cfqd) -{ - hrtimer_cancel(&cfqd->idle_slice_timer); - cancel_work_sync(&cfqd->unplug_work); -} - -static void cfq_exit_queue(struct elevator_queue *e) -{ - struct cfq_data *cfqd = e->elevator_data; - struct request_queue *q = cfqd->queue; - - cfq_shutdown_timer_wq(cfqd); - - spin_lock_irq(q->queue_lock); - - if (cfqd->active_queue) - __cfq_slice_expired(cfqd, cfqd->active_queue, 0); - - spin_unlock_irq(q->queue_lock); - - cfq_shutdown_timer_wq(cfqd); - -#ifdef CONFIG_CFQ_GROUP_IOSCHED - blkcg_deactivate_policy(q, &blkcg_policy_cfq); -#else - kfree(cfqd->root_group); -#endif - kfree(cfqd); -} - -static int cfq_init_queue(struct request_queue *q, struct elevator_type *e) -{ - struct cfq_data *cfqd; - struct blkcg_gq *blkg __maybe_unused; - int i, ret; - struct elevator_queue *eq; - - eq = elevator_alloc(q, e); - if (!eq) - return -ENOMEM; - - cfqd = kzalloc_node(sizeof(*cfqd), GFP_KERNEL, q->node); - if (!cfqd) { - kobject_put(&eq->kobj); - return -ENOMEM; - } - eq->elevator_data = cfqd; - - cfqd->queue = q; - spin_lock_irq(q->queue_lock); - q->elevator = eq; - spin_unlock_irq(q->queue_lock); - - /* Init root service tree */ - cfqd->grp_service_tree = CFQ_RB_ROOT; - - /* Init root group and prefer root group over other groups by default */ -#ifdef CONFIG_CFQ_GROUP_IOSCHED - ret = blkcg_activate_policy(q, &blkcg_policy_cfq); - if (ret) - goto out_free; - - cfqd->root_group = blkg_to_cfqg(q->root_blkg); -#else - ret = -ENOMEM; - cfqd->root_group = kzalloc_node(sizeof(*cfqd->root_group), - GFP_KERNEL, cfqd->queue->node); - if (!cfqd->root_group) - goto out_free; - - cfq_init_cfqg_base(cfqd->root_group); - cfqd->root_group->weight = 2 * CFQ_WEIGHT_LEGACY_DFL; - cfqd->root_group->leaf_weight = 2 * CFQ_WEIGHT_LEGACY_DFL; -#endif - - /* - * Not strictly needed (since RB_ROOT just clears the node and we - * zeroed cfqd on alloc), but better be safe in case someone decides - * to add magic to the rb code - */ - for (i = 0; i < CFQ_PRIO_LISTS; i++) - cfqd->prio_trees[i] = RB_ROOT; - - /* - * Our fallback cfqq if cfq_get_queue() runs into OOM issues. - * Grab a permanent reference to it, so that the normal code flow - * will not attempt to free it. oom_cfqq is linked to root_group - * but shouldn't hold a reference as it'll never be unlinked. Lose - * the reference from linking right away. - */ - cfq_init_cfqq(cfqd, &cfqd->oom_cfqq, 1, 0); - cfqd->oom_cfqq.ref++; - - spin_lock_irq(q->queue_lock); - cfq_link_cfqq_cfqg(&cfqd->oom_cfqq, cfqd->root_group); - cfqg_put(cfqd->root_group); - spin_unlock_irq(q->queue_lock); - - hrtimer_init(&cfqd->idle_slice_timer, CLOCK_MONOTONIC, - HRTIMER_MODE_REL); - cfqd->idle_slice_timer.function = cfq_idle_slice_timer; - - INIT_WORK(&cfqd->unplug_work, cfq_kick_queue); - - cfqd->cfq_quantum = cfq_quantum; - cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0]; - cfqd->cfq_fifo_expire[1] = cfq_fifo_expire[1]; - cfqd->cfq_back_max = cfq_back_max; - cfqd->cfq_back_penalty = cfq_back_penalty; - cfqd->cfq_slice[0] = cfq_slice_async; - cfqd->cfq_slice[1] = cfq_slice_sync; - cfqd->cfq_target_latency = cfq_target_latency; - cfqd->cfq_slice_async_rq = cfq_slice_async_rq; - cfqd->cfq_slice_idle = cfq_slice_idle; - cfqd->cfq_group_idle = cfq_group_idle; - cfqd->cfq_latency = 1; - cfqd->hw_tag = -1; - /* - * we optimistically start assuming sync ops weren't delayed in last - * second, in order to have larger depth for async operations. - */ - cfqd->last_delayed_sync = ktime_get_ns() - NSEC_PER_SEC; - return 0; - -out_free: - kfree(cfqd); - kobject_put(&eq->kobj); - return ret; -} - -static void cfq_registered_queue(struct request_queue *q) -{ - struct elevator_queue *e = q->elevator; - struct cfq_data *cfqd = e->elevator_data; - - /* - * Default to IOPS mode with no idling for SSDs - */ - if (blk_queue_nonrot(q)) - cfqd->cfq_slice_idle = 0; -} - -/* - * sysfs parts below --> - */ -static ssize_t -cfq_var_show(unsigned int var, char *page) -{ - return sprintf(page, "%u\n", var); -} - -static ssize_t -cfq_var_store(unsigned int *var, const char *page, size_t count) -{ - char *p = (char *) page; - - *var = simple_strtoul(p, &p, 10); - return count; -} - -#define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \ -static ssize_t __FUNC(struct elevator_queue *e, char *page) \ -{ \ - struct cfq_data *cfqd = e->elevator_data; \ - u64 __data = __VAR; \ - if (__CONV) \ - __data = div_u64(__data, NSEC_PER_MSEC); \ - return cfq_var_show(__data, (page)); \ -} -SHOW_FUNCTION(cfq_quantum_show, cfqd->cfq_quantum, 0); -SHOW_FUNCTION(cfq_fifo_expire_sync_show, cfqd->cfq_fifo_expire[1], 1); -SHOW_FUNCTION(cfq_fifo_expire_async_show, cfqd->cfq_fifo_expire[0], 1); -SHOW_FUNCTION(cfq_back_seek_max_show, cfqd->cfq_back_max, 0); -SHOW_FUNCTION(cfq_back_seek_penalty_show, cfqd->cfq_back_penalty, 0); -SHOW_FUNCTION(cfq_slice_idle_show, cfqd->cfq_slice_idle, 1); -SHOW_FUNCTION(cfq_group_idle_show, cfqd->cfq_group_idle, 1); -SHOW_FUNCTION(cfq_slice_sync_show, cfqd->cfq_slice[1], 1); -SHOW_FUNCTION(cfq_slice_async_show, cfqd->cfq_slice[0], 1); -SHOW_FUNCTION(cfq_slice_async_rq_show, cfqd->cfq_slice_async_rq, 0); -SHOW_FUNCTION(cfq_low_latency_show, cfqd->cfq_latency, 0); -SHOW_FUNCTION(cfq_target_latency_show, cfqd->cfq_target_latency, 1); -#undef SHOW_FUNCTION - -#define USEC_SHOW_FUNCTION(__FUNC, __VAR) \ -static ssize_t __FUNC(struct elevator_queue *e, char *page) \ -{ \ - struct cfq_data *cfqd = e->elevator_data; \ - u64 __data = __VAR; \ - __data = div_u64(__data, NSEC_PER_USEC); \ - return cfq_var_show(__data, (page)); \ -} -USEC_SHOW_FUNCTION(cfq_slice_idle_us_show, cfqd->cfq_slice_idle); -USEC_SHOW_FUNCTION(cfq_group_idle_us_show, cfqd->cfq_group_idle); -USEC_SHOW_FUNCTION(cfq_slice_sync_us_show, cfqd->cfq_slice[1]); -USEC_SHOW_FUNCTION(cfq_slice_async_us_show, cfqd->cfq_slice[0]); -USEC_SHOW_FUNCTION(cfq_target_latency_us_show, cfqd->cfq_target_latency); -#undef USEC_SHOW_FUNCTION - -#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \ -static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) \ -{ \ - struct cfq_data *cfqd = e->elevator_data; \ - unsigned int __data; \ - int ret = cfq_var_store(&__data, (page), count); \ - if (__data < (MIN)) \ - __data = (MIN); \ - else if (__data > (MAX)) \ - __data = (MAX); \ - if (__CONV) \ - *(__PTR) = (u64)__data * NSEC_PER_MSEC; \ - else \ - *(__PTR) = __data; \ - return ret; \ -} -STORE_FUNCTION(cfq_quantum_store, &cfqd->cfq_quantum, 1, UINT_MAX, 0); -STORE_FUNCTION(cfq_fifo_expire_sync_store, &cfqd->cfq_fifo_expire[1], 1, - UINT_MAX, 1); -STORE_FUNCTION(cfq_fifo_expire_async_store, &cfqd->cfq_fifo_expire[0], 1, - UINT_MAX, 1); -STORE_FUNCTION(cfq_back_seek_max_store, &cfqd->cfq_back_max, 0, UINT_MAX, 0); -STORE_FUNCTION(cfq_back_seek_penalty_store, &cfqd->cfq_back_penalty, 1, - UINT_MAX, 0); -STORE_FUNCTION(cfq_slice_idle_store, &cfqd->cfq_slice_idle, 0, UINT_MAX, 1); -STORE_FUNCTION(cfq_group_idle_store, &cfqd->cfq_group_idle, 0, UINT_MAX, 1); -STORE_FUNCTION(cfq_slice_sync_store, &cfqd->cfq_slice[1], 1, UINT_MAX, 1); -STORE_FUNCTION(cfq_slice_async_store, &cfqd->cfq_slice[0], 1, UINT_MAX, 1); -STORE_FUNCTION(cfq_slice_async_rq_store, &cfqd->cfq_slice_async_rq, 1, - UINT_MAX, 0); -STORE_FUNCTION(cfq_low_latency_store, &cfqd->cfq_latency, 0, 1, 0); -STORE_FUNCTION(cfq_target_latency_store, &cfqd->cfq_target_latency, 1, UINT_MAX, 1); -#undef STORE_FUNCTION - -#define USEC_STORE_FUNCTION(__FUNC, __PTR, MIN, MAX) \ -static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) \ -{ \ - struct cfq_data *cfqd = e->elevator_data; \ - unsigned int __data; \ - int ret = cfq_var_store(&__data, (page), count); \ - if (__data < (MIN)) \ - __data = (MIN); \ - else if (__data > (MAX)) \ - __data = (MAX); \ - *(__PTR) = (u64)__data * NSEC_PER_USEC; \ - return ret; \ -} -USEC_STORE_FUNCTION(cfq_slice_idle_us_store, &cfqd->cfq_slice_idle, 0, UINT_MAX); -USEC_STORE_FUNCTION(cfq_group_idle_us_store, &cfqd->cfq_group_idle, 0, UINT_MAX); -USEC_STORE_FUNCTION(cfq_slice_sync_us_store, &cfqd->cfq_slice[1], 1, UINT_MAX); -USEC_STORE_FUNCTION(cfq_slice_async_us_store, &cfqd->cfq_slice[0], 1, UINT_MAX); -USEC_STORE_FUNCTION(cfq_target_latency_us_store, &cfqd->cfq_target_latency, 1, UINT_MAX); -#undef USEC_STORE_FUNCTION - -#define CFQ_ATTR(name) \ - __ATTR(name, S_IRUGO|S_IWUSR, cfq_##name##_show, cfq_##name##_store) - -static struct elv_fs_entry cfq_attrs[] = { - CFQ_ATTR(quantum), - CFQ_ATTR(fifo_expire_sync), - CFQ_ATTR(fifo_expire_async), - CFQ_ATTR(back_seek_max), - CFQ_ATTR(back_seek_penalty), - CFQ_ATTR(slice_sync), - CFQ_ATTR(slice_sync_us), - CFQ_ATTR(slice_async), - CFQ_ATTR(slice_async_us), - CFQ_ATTR(slice_async_rq), - CFQ_ATTR(slice_idle), - CFQ_ATTR(slice_idle_us), - CFQ_ATTR(group_idle), - CFQ_ATTR(group_idle_us), - CFQ_ATTR(low_latency), - CFQ_ATTR(target_latency), - CFQ_ATTR(target_latency_us), - __ATTR_NULL -}; - -static struct elevator_type iosched_cfq = { - .ops = { - .elevator_merge_fn = cfq_merge, - .elevator_merged_fn = cfq_merged_request, - .elevator_merge_req_fn = cfq_merged_requests, - .elevator_allow_bio_merge_fn = cfq_allow_bio_merge, - .elevator_allow_rq_merge_fn = cfq_allow_rq_merge, - .elevator_bio_merged_fn = cfq_bio_merged, - .elevator_dispatch_fn = cfq_dispatch_requests, - .elevator_add_req_fn = cfq_insert_request, - .elevator_activate_req_fn = cfq_activate_request, - .elevator_deactivate_req_fn = cfq_deactivate_request, - .elevator_completed_req_fn = cfq_completed_request, - .elevator_former_req_fn = elv_rb_former_request, - .elevator_latter_req_fn = elv_rb_latter_request, - .elevator_init_icq_fn = cfq_init_icq, - .elevator_exit_icq_fn = cfq_exit_icq, - .elevator_set_req_fn = cfq_set_request, - .elevator_put_req_fn = cfq_put_request, - .elevator_may_queue_fn = cfq_may_queue, - .elevator_init_fn = cfq_init_queue, - .elevator_exit_fn = cfq_exit_queue, - .elevator_registered_fn = cfq_registered_queue, - }, - .icq_size = sizeof(struct cfq_io_cq), - .icq_align = __alignof__(struct cfq_io_cq), - .elevator_attrs = cfq_attrs, - .elevator_name = "cfq", - .elevator_owner = THIS_MODULE, -}; - -#ifdef CONFIG_CFQ_GROUP_IOSCHED -static struct blkcg_policy blkcg_policy_cfq = { - .dfl_cftypes = cfq_blkcg_files, - .legacy_cftypes = cfq_blkcg_legacy_files, - - .cpd_alloc_fn = cfq_cpd_alloc, - .cpd_init_fn = cfq_cpd_init, - .cpd_free_fn = cfq_cpd_free, - .cpd_bind_fn = cfq_cpd_bind, - - .pd_alloc_fn = cfq_pd_alloc, - .pd_init_fn = cfq_pd_init, - .pd_offline_fn = cfq_pd_offline, - .pd_free_fn = cfq_pd_free, - .pd_reset_stats_fn = cfq_pd_reset_stats, -}; -#endif - -static int __init cfq_init(void) -{ - int ret; - -#ifdef CONFIG_CFQ_GROUP_IOSCHED - ret = blkcg_policy_register(&blkcg_policy_cfq); - if (ret) - return ret; -#else - cfq_group_idle = 0; -#endif - - ret = -ENOMEM; - cfq_pool = KMEM_CACHE(cfq_queue, 0); - if (!cfq_pool) - goto err_pol_unreg; - - ret = elv_register(&iosched_cfq); - if (ret) - goto err_free_pool; - - return 0; - -err_free_pool: - kmem_cache_destroy(cfq_pool); -err_pol_unreg: -#ifdef CONFIG_CFQ_GROUP_IOSCHED - blkcg_policy_unregister(&blkcg_policy_cfq); -#endif - return ret; -} - -static void __exit cfq_exit(void) -{ -#ifdef CONFIG_CFQ_GROUP_IOSCHED - blkcg_policy_unregister(&blkcg_policy_cfq); -#endif - elv_unregister(&iosched_cfq); - kmem_cache_destroy(cfq_pool); -} - -module_init(cfq_init); -module_exit(cfq_exit); - -MODULE_AUTHOR("Jens Axboe"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Completely Fair Queueing IO scheduler"); diff --git a/src/linux/block/deadline-iosched.c b/src/linux/block/deadline-iosched.c deleted file mode 100644 index 55e0bb6..0000000 --- a/src/linux/block/deadline-iosched.c +++ /dev/null @@ -1,474 +0,0 @@ -/* - * Deadline i/o scheduler. - * - * Copyright (C) 2002 Jens Axboe - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * See Documentation/block/deadline-iosched.txt - */ -static const int read_expire = HZ / 2; /* max time before a read is submitted. */ -static const int write_expire = 5 * HZ; /* ditto for writes, these limits are SOFT! */ -static const int writes_starved = 2; /* max times reads can starve a write */ -static const int fifo_batch = 16; /* # of sequential requests treated as one - by the above parameters. For throughput. */ - -struct deadline_data { - /* - * run time data - */ - - /* - * requests (deadline_rq s) are present on both sort_list and fifo_list - */ - struct rb_root sort_list[2]; - struct list_head fifo_list[2]; - - /* - * next in sort order. read, write or both are NULL - */ - struct request *next_rq[2]; - unsigned int batching; /* number of sequential requests made */ - unsigned int starved; /* times reads have starved writes */ - - /* - * settings that change how the i/o scheduler behaves - */ - int fifo_expire[2]; - int fifo_batch; - int writes_starved; - int front_merges; -}; - -static void deadline_move_request(struct deadline_data *, struct request *); - -static inline struct rb_root * -deadline_rb_root(struct deadline_data *dd, struct request *rq) -{ - return &dd->sort_list[rq_data_dir(rq)]; -} - -/* - * get the request after `rq' in sector-sorted order - */ -static inline struct request * -deadline_latter_request(struct request *rq) -{ - struct rb_node *node = rb_next(&rq->rb_node); - - if (node) - return rb_entry_rq(node); - - return NULL; -} - -static void -deadline_add_rq_rb(struct deadline_data *dd, struct request *rq) -{ - struct rb_root *root = deadline_rb_root(dd, rq); - - elv_rb_add(root, rq); -} - -static inline void -deadline_del_rq_rb(struct deadline_data *dd, struct request *rq) -{ - const int data_dir = rq_data_dir(rq); - - if (dd->next_rq[data_dir] == rq) - dd->next_rq[data_dir] = deadline_latter_request(rq); - - elv_rb_del(deadline_rb_root(dd, rq), rq); -} - -/* - * add rq to rbtree and fifo - */ -static void -deadline_add_request(struct request_queue *q, struct request *rq) -{ - struct deadline_data *dd = q->elevator->elevator_data; - const int data_dir = rq_data_dir(rq); - - deadline_add_rq_rb(dd, rq); - - /* - * set expire time and add to fifo list - */ - rq->fifo_time = jiffies + dd->fifo_expire[data_dir]; - list_add_tail(&rq->queuelist, &dd->fifo_list[data_dir]); -} - -/* - * remove rq from rbtree and fifo. - */ -static void deadline_remove_request(struct request_queue *q, struct request *rq) -{ - struct deadline_data *dd = q->elevator->elevator_data; - - rq_fifo_clear(rq); - deadline_del_rq_rb(dd, rq); -} - -static int -deadline_merge(struct request_queue *q, struct request **req, struct bio *bio) -{ - struct deadline_data *dd = q->elevator->elevator_data; - struct request *__rq; - int ret; - - /* - * check for front merge - */ - if (dd->front_merges) { - sector_t sector = bio_end_sector(bio); - - __rq = elv_rb_find(&dd->sort_list[bio_data_dir(bio)], sector); - if (__rq) { - BUG_ON(sector != blk_rq_pos(__rq)); - - if (elv_bio_merge_ok(__rq, bio)) { - ret = ELEVATOR_FRONT_MERGE; - goto out; - } - } - } - - return ELEVATOR_NO_MERGE; -out: - *req = __rq; - return ret; -} - -static void deadline_merged_request(struct request_queue *q, - struct request *req, int type) -{ - struct deadline_data *dd = q->elevator->elevator_data; - - /* - * if the merge was a front merge, we need to reposition request - */ - if (type == ELEVATOR_FRONT_MERGE) { - elv_rb_del(deadline_rb_root(dd, req), req); - deadline_add_rq_rb(dd, req); - } -} - -static void -deadline_merged_requests(struct request_queue *q, struct request *req, - struct request *next) -{ - /* - * if next expires before rq, assign its expire time to rq - * and move into next position (next will be deleted) in fifo - */ - if (!list_empty(&req->queuelist) && !list_empty(&next->queuelist)) { - if (time_before((unsigned long)next->fifo_time, - (unsigned long)req->fifo_time)) { - list_move(&req->queuelist, &next->queuelist); - req->fifo_time = next->fifo_time; - } - } - - /* - * kill knowledge of next, this one is a goner - */ - deadline_remove_request(q, next); -} - -/* - * move request from sort list to dispatch queue. - */ -static inline void -deadline_move_to_dispatch(struct deadline_data *dd, struct request *rq) -{ - struct request_queue *q = rq->q; - - deadline_remove_request(q, rq); - elv_dispatch_add_tail(q, rq); -} - -/* - * move an entry to dispatch queue - */ -static void -deadline_move_request(struct deadline_data *dd, struct request *rq) -{ - const int data_dir = rq_data_dir(rq); - - dd->next_rq[READ] = NULL; - dd->next_rq[WRITE] = NULL; - dd->next_rq[data_dir] = deadline_latter_request(rq); - - /* - * take it off the sort and fifo list, move - * to dispatch queue - */ - deadline_move_to_dispatch(dd, rq); -} - -/* - * deadline_check_fifo returns 0 if there are no expired requests on the fifo, - * 1 otherwise. Requires !list_empty(&dd->fifo_list[data_dir]) - */ -static inline int deadline_check_fifo(struct deadline_data *dd, int ddir) -{ - struct request *rq = rq_entry_fifo(dd->fifo_list[ddir].next); - - /* - * rq is expired! - */ - if (time_after_eq(jiffies, (unsigned long)rq->fifo_time)) - return 1; - - return 0; -} - -/* - * deadline_dispatch_requests selects the best request according to - * read/write expire, fifo_batch, etc - */ -static int deadline_dispatch_requests(struct request_queue *q, int force) -{ - struct deadline_data *dd = q->elevator->elevator_data; - const int reads = !list_empty(&dd->fifo_list[READ]); - const int writes = !list_empty(&dd->fifo_list[WRITE]); - struct request *rq; - int data_dir; - - /* - * batches are currently reads XOR writes - */ - if (dd->next_rq[WRITE]) - rq = dd->next_rq[WRITE]; - else - rq = dd->next_rq[READ]; - - if (rq && dd->batching < dd->fifo_batch) - /* we have a next request are still entitled to batch */ - goto dispatch_request; - - /* - * at this point we are not running a batch. select the appropriate - * data direction (read / write) - */ - - if (reads) { - BUG_ON(RB_EMPTY_ROOT(&dd->sort_list[READ])); - - if (writes && (dd->starved++ >= dd->writes_starved)) - goto dispatch_writes; - - data_dir = READ; - - goto dispatch_find_request; - } - - /* - * there are either no reads or writes have been starved - */ - - if (writes) { -dispatch_writes: - BUG_ON(RB_EMPTY_ROOT(&dd->sort_list[WRITE])); - - dd->starved = 0; - - data_dir = WRITE; - - goto dispatch_find_request; - } - - return 0; - -dispatch_find_request: - /* - * we are not running a batch, find best request for selected data_dir - */ - if (deadline_check_fifo(dd, data_dir) || !dd->next_rq[data_dir]) { - /* - * A deadline has expired, the last request was in the other - * direction, or we have run out of higher-sectored requests. - * Start again from the request with the earliest expiry time. - */ - rq = rq_entry_fifo(dd->fifo_list[data_dir].next); - } else { - /* - * The last req was the same dir and we have a next request in - * sort order. No expired requests so continue on from here. - */ - rq = dd->next_rq[data_dir]; - } - - dd->batching = 0; - -dispatch_request: - /* - * rq is the selected appropriate request. - */ - dd->batching++; - deadline_move_request(dd, rq); - - return 1; -} - -static void deadline_exit_queue(struct elevator_queue *e) -{ - struct deadline_data *dd = e->elevator_data; - - BUG_ON(!list_empty(&dd->fifo_list[READ])); - BUG_ON(!list_empty(&dd->fifo_list[WRITE])); - - kfree(dd); -} - -/* - * initialize elevator private data (deadline_data). - */ -static int deadline_init_queue(struct request_queue *q, struct elevator_type *e) -{ - struct deadline_data *dd; - struct elevator_queue *eq; - - eq = elevator_alloc(q, e); - if (!eq) - return -ENOMEM; - - dd = kzalloc_node(sizeof(*dd), GFP_KERNEL, q->node); - if (!dd) { - kobject_put(&eq->kobj); - return -ENOMEM; - } - eq->elevator_data = dd; - - INIT_LIST_HEAD(&dd->fifo_list[READ]); - INIT_LIST_HEAD(&dd->fifo_list[WRITE]); - dd->sort_list[READ] = RB_ROOT; - dd->sort_list[WRITE] = RB_ROOT; - dd->fifo_expire[READ] = read_expire; - dd->fifo_expire[WRITE] = write_expire; - dd->writes_starved = writes_starved; - dd->front_merges = 1; - dd->fifo_batch = fifo_batch; - - spin_lock_irq(q->queue_lock); - q->elevator = eq; - spin_unlock_irq(q->queue_lock); - return 0; -} - -/* - * sysfs parts below - */ - -static ssize_t -deadline_var_show(int var, char *page) -{ - return sprintf(page, "%d\n", var); -} - -static ssize_t -deadline_var_store(int *var, const char *page, size_t count) -{ - char *p = (char *) page; - - *var = simple_strtol(p, &p, 10); - return count; -} - -#define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \ -static ssize_t __FUNC(struct elevator_queue *e, char *page) \ -{ \ - struct deadline_data *dd = e->elevator_data; \ - int __data = __VAR; \ - if (__CONV) \ - __data = jiffies_to_msecs(__data); \ - return deadline_var_show(__data, (page)); \ -} -SHOW_FUNCTION(deadline_read_expire_show, dd->fifo_expire[READ], 1); -SHOW_FUNCTION(deadline_write_expire_show, dd->fifo_expire[WRITE], 1); -SHOW_FUNCTION(deadline_writes_starved_show, dd->writes_starved, 0); -SHOW_FUNCTION(deadline_front_merges_show, dd->front_merges, 0); -SHOW_FUNCTION(deadline_fifo_batch_show, dd->fifo_batch, 0); -#undef SHOW_FUNCTION - -#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \ -static ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) \ -{ \ - struct deadline_data *dd = e->elevator_data; \ - int __data; \ - int ret = deadline_var_store(&__data, (page), count); \ - if (__data < (MIN)) \ - __data = (MIN); \ - else if (__data > (MAX)) \ - __data = (MAX); \ - if (__CONV) \ - *(__PTR) = msecs_to_jiffies(__data); \ - else \ - *(__PTR) = __data; \ - return ret; \ -} -STORE_FUNCTION(deadline_read_expire_store, &dd->fifo_expire[READ], 0, INT_MAX, 1); -STORE_FUNCTION(deadline_write_expire_store, &dd->fifo_expire[WRITE], 0, INT_MAX, 1); -STORE_FUNCTION(deadline_writes_starved_store, &dd->writes_starved, INT_MIN, INT_MAX, 0); -STORE_FUNCTION(deadline_front_merges_store, &dd->front_merges, 0, 1, 0); -STORE_FUNCTION(deadline_fifo_batch_store, &dd->fifo_batch, 0, INT_MAX, 0); -#undef STORE_FUNCTION - -#define DD_ATTR(name) \ - __ATTR(name, S_IRUGO|S_IWUSR, deadline_##name##_show, \ - deadline_##name##_store) - -static struct elv_fs_entry deadline_attrs[] = { - DD_ATTR(read_expire), - DD_ATTR(write_expire), - DD_ATTR(writes_starved), - DD_ATTR(front_merges), - DD_ATTR(fifo_batch), - __ATTR_NULL -}; - -static struct elevator_type iosched_deadline = { - .ops = { - .elevator_merge_fn = deadline_merge, - .elevator_merged_fn = deadline_merged_request, - .elevator_merge_req_fn = deadline_merged_requests, - .elevator_dispatch_fn = deadline_dispatch_requests, - .elevator_add_req_fn = deadline_add_request, - .elevator_former_req_fn = elv_rb_former_request, - .elevator_latter_req_fn = elv_rb_latter_request, - .elevator_init_fn = deadline_init_queue, - .elevator_exit_fn = deadline_exit_queue, - }, - - .elevator_attrs = deadline_attrs, - .elevator_name = "deadline", - .elevator_owner = THIS_MODULE, -}; - -static int __init deadline_init(void) -{ - return elv_register(&iosched_deadline); -} - -static void __exit deadline_exit(void) -{ - elv_unregister(&iosched_deadline); -} - -module_init(deadline_init); -module_exit(deadline_exit); - -MODULE_AUTHOR("Jens Axboe"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("deadline IO scheduler"); diff --git a/src/linux/block/elevator.c b/src/linux/block/elevator.c deleted file mode 100644 index f7d973a..0000000 --- a/src/linux/block/elevator.c +++ /dev/null @@ -1,1048 +0,0 @@ -/* - * Block device elevator/IO-scheduler. - * - * Copyright (C) 2000 Andrea Arcangeli SuSE - * - * 30042000 Jens Axboe : - * - * Split the elevator a bit so that it is possible to choose a different - * one or even write a new "plug in". There are three pieces: - * - elevator_fn, inserts a new request in the queue list - * - elevator_merge_fn, decides whether a new buffer can be merged with - * an existing request - * - elevator_dequeue_fn, called when a request is taken off the active list - * - * 20082000 Dave Jones : - * Removed tests for max-bomb-segments, which was breaking elvtune - * when run without -bN - * - * Jens: - * - Rework again to work with bio instead of buffer_heads - * - loose bi_dev comparisons, partition handling is right now - * - completely modularize elevator setup and teardown - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "blk.h" - -static DEFINE_SPINLOCK(elv_list_lock); -static LIST_HEAD(elv_list); - -/* - * Merge hash stuff. - */ -#define rq_hash_key(rq) (blk_rq_pos(rq) + blk_rq_sectors(rq)) - -/* - * Query io scheduler to see if the current process issuing bio may be - * merged with rq. - */ -static int elv_iosched_allow_bio_merge(struct request *rq, struct bio *bio) -{ - struct request_queue *q = rq->q; - struct elevator_queue *e = q->elevator; - - if (e->type->ops.elevator_allow_bio_merge_fn) - return e->type->ops.elevator_allow_bio_merge_fn(q, rq, bio); - - return 1; -} - -/* - * can we safely merge with this request? - */ -bool elv_bio_merge_ok(struct request *rq, struct bio *bio) -{ - if (!blk_rq_merge_ok(rq, bio)) - return false; - - if (!elv_iosched_allow_bio_merge(rq, bio)) - return false; - - return true; -} -EXPORT_SYMBOL(elv_bio_merge_ok); - -static struct elevator_type *elevator_find(const char *name) -{ - struct elevator_type *e; - - list_for_each_entry(e, &elv_list, list) { - if (!strcmp(e->elevator_name, name)) - return e; - } - - return NULL; -} - -static void elevator_put(struct elevator_type *e) -{ - module_put(e->elevator_owner); -} - -static struct elevator_type *elevator_get(const char *name, bool try_loading) -{ - struct elevator_type *e; - - spin_lock(&elv_list_lock); - - e = elevator_find(name); - if (!e && try_loading) { - spin_unlock(&elv_list_lock); - request_module("%s-iosched", name); - spin_lock(&elv_list_lock); - e = elevator_find(name); - } - - if (e && !try_module_get(e->elevator_owner)) - e = NULL; - - spin_unlock(&elv_list_lock); - - return e; -} - -static char chosen_elevator[ELV_NAME_MAX]; - -static int __init elevator_setup(char *str) -{ - /* - * Be backwards-compatible with previous kernels, so users - * won't get the wrong elevator. - */ - strncpy(chosen_elevator, str, sizeof(chosen_elevator) - 1); - return 1; -} - -__setup("elevator=", elevator_setup); - -/* called during boot to load the elevator chosen by the elevator param */ -void __init load_default_elevator_module(void) -{ - struct elevator_type *e; - - if (!chosen_elevator[0]) - return; - - spin_lock(&elv_list_lock); - e = elevator_find(chosen_elevator); - spin_unlock(&elv_list_lock); - - if (!e) - request_module("%s-iosched", chosen_elevator); -} - -static struct kobj_type elv_ktype; - -struct elevator_queue *elevator_alloc(struct request_queue *q, - struct elevator_type *e) -{ - struct elevator_queue *eq; - - eq = kzalloc_node(sizeof(*eq), GFP_KERNEL, q->node); - if (unlikely(!eq)) - return NULL; - - eq->type = e; - kobject_init(&eq->kobj, &elv_ktype); - mutex_init(&eq->sysfs_lock); - hash_init(eq->hash); - - return eq; -} -EXPORT_SYMBOL(elevator_alloc); - -static void elevator_release(struct kobject *kobj) -{ - struct elevator_queue *e; - - e = container_of(kobj, struct elevator_queue, kobj); - elevator_put(e->type); - kfree(e); -} - -int elevator_init(struct request_queue *q, char *name) -{ - struct elevator_type *e = NULL; - int err; - - /* - * q->sysfs_lock must be held to provide mutual exclusion between - * elevator_switch() and here. - */ - lockdep_assert_held(&q->sysfs_lock); - - if (unlikely(q->elevator)) - return 0; - - INIT_LIST_HEAD(&q->queue_head); - q->last_merge = NULL; - q->end_sector = 0; - q->boundary_rq = NULL; - - if (name) { - e = elevator_get(name, true); - if (!e) - return -EINVAL; - } - - /* - * Use the default elevator specified by config boot param or - * config option. Don't try to load modules as we could be running - * off async and request_module() isn't allowed from async. - */ - if (!e && *chosen_elevator) { - e = elevator_get(chosen_elevator, false); - if (!e) - printk(KERN_ERR "I/O scheduler %s not found\n", - chosen_elevator); - } - - if (!e) { - e = elevator_get(CONFIG_DEFAULT_IOSCHED, false); - if (!e) { - printk(KERN_ERR - "Default I/O scheduler not found. " \ - "Using noop.\n"); - e = elevator_get("noop", false); - } - } - - err = e->ops.elevator_init_fn(q, e); - if (err) - elevator_put(e); - return err; -} -EXPORT_SYMBOL(elevator_init); - -void elevator_exit(struct elevator_queue *e) -{ - mutex_lock(&e->sysfs_lock); - if (e->type->ops.elevator_exit_fn) - e->type->ops.elevator_exit_fn(e); - mutex_unlock(&e->sysfs_lock); - - kobject_put(&e->kobj); -} -EXPORT_SYMBOL(elevator_exit); - -static inline void __elv_rqhash_del(struct request *rq) -{ - hash_del(&rq->hash); - rq->cmd_flags &= ~REQ_HASHED; -} - -static void elv_rqhash_del(struct request_queue *q, struct request *rq) -{ - if (ELV_ON_HASH(rq)) - __elv_rqhash_del(rq); -} - -static void elv_rqhash_add(struct request_queue *q, struct request *rq) -{ - struct elevator_queue *e = q->elevator; - - BUG_ON(ELV_ON_HASH(rq)); - hash_add(e->hash, &rq->hash, rq_hash_key(rq)); - rq->cmd_flags |= REQ_HASHED; -} - -static void elv_rqhash_reposition(struct request_queue *q, struct request *rq) -{ - __elv_rqhash_del(rq); - elv_rqhash_add(q, rq); -} - -static struct request *elv_rqhash_find(struct request_queue *q, sector_t offset) -{ - struct elevator_queue *e = q->elevator; - struct hlist_node *next; - struct request *rq; - - hash_for_each_possible_safe(e->hash, rq, next, hash, offset) { - BUG_ON(!ELV_ON_HASH(rq)); - - if (unlikely(!rq_mergeable(rq))) { - __elv_rqhash_del(rq); - continue; - } - - if (rq_hash_key(rq) == offset) - return rq; - } - - return NULL; -} - -/* - * RB-tree support functions for inserting/lookup/removal of requests - * in a sorted RB tree. - */ -void elv_rb_add(struct rb_root *root, struct request *rq) -{ - struct rb_node **p = &root->rb_node; - struct rb_node *parent = NULL; - struct request *__rq; - - while (*p) { - parent = *p; - __rq = rb_entry(parent, struct request, rb_node); - - if (blk_rq_pos(rq) < blk_rq_pos(__rq)) - p = &(*p)->rb_left; - else if (blk_rq_pos(rq) >= blk_rq_pos(__rq)) - p = &(*p)->rb_right; - } - - rb_link_node(&rq->rb_node, parent, p); - rb_insert_color(&rq->rb_node, root); -} -EXPORT_SYMBOL(elv_rb_add); - -void elv_rb_del(struct rb_root *root, struct request *rq) -{ - BUG_ON(RB_EMPTY_NODE(&rq->rb_node)); - rb_erase(&rq->rb_node, root); - RB_CLEAR_NODE(&rq->rb_node); -} -EXPORT_SYMBOL(elv_rb_del); - -struct request *elv_rb_find(struct rb_root *root, sector_t sector) -{ - struct rb_node *n = root->rb_node; - struct request *rq; - - while (n) { - rq = rb_entry(n, struct request, rb_node); - - if (sector < blk_rq_pos(rq)) - n = n->rb_left; - else if (sector > blk_rq_pos(rq)) - n = n->rb_right; - else - return rq; - } - - return NULL; -} -EXPORT_SYMBOL(elv_rb_find); - -/* - * Insert rq into dispatch queue of q. Queue lock must be held on - * entry. rq is sort instead into the dispatch queue. To be used by - * specific elevators. - */ -void elv_dispatch_sort(struct request_queue *q, struct request *rq) -{ - sector_t boundary; - struct list_head *entry; - int stop_flags; - - if (q->last_merge == rq) - q->last_merge = NULL; - - elv_rqhash_del(q, rq); - - q->nr_sorted--; - - boundary = q->end_sector; - stop_flags = REQ_SOFTBARRIER | REQ_STARTED; - list_for_each_prev(entry, &q->queue_head) { - struct request *pos = list_entry_rq(entry); - - if (req_op(rq) != req_op(pos)) - break; - if (rq_data_dir(rq) != rq_data_dir(pos)) - break; - if (pos->cmd_flags & stop_flags) - break; - if (blk_rq_pos(rq) >= boundary) { - if (blk_rq_pos(pos) < boundary) - continue; - } else { - if (blk_rq_pos(pos) >= boundary) - break; - } - if (blk_rq_pos(rq) >= blk_rq_pos(pos)) - break; - } - - list_add(&rq->queuelist, entry); -} -EXPORT_SYMBOL(elv_dispatch_sort); - -/* - * Insert rq into dispatch queue of q. Queue lock must be held on - * entry. rq is added to the back of the dispatch queue. To be used by - * specific elevators. - */ -void elv_dispatch_add_tail(struct request_queue *q, struct request *rq) -{ - if (q->last_merge == rq) - q->last_merge = NULL; - - elv_rqhash_del(q, rq); - - q->nr_sorted--; - - q->end_sector = rq_end_sector(rq); - q->boundary_rq = rq; - list_add_tail(&rq->queuelist, &q->queue_head); -} -EXPORT_SYMBOL(elv_dispatch_add_tail); - -int elv_merge(struct request_queue *q, struct request **req, struct bio *bio) -{ - struct elevator_queue *e = q->elevator; - struct request *__rq; - int ret; - - /* - * Levels of merges: - * nomerges: No merges at all attempted - * noxmerges: Only simple one-hit cache try - * merges: All merge tries attempted - */ - if (blk_queue_nomerges(q) || !bio_mergeable(bio)) - return ELEVATOR_NO_MERGE; - - /* - * First try one-hit cache. - */ - if (q->last_merge && elv_bio_merge_ok(q->last_merge, bio)) { - ret = blk_try_merge(q->last_merge, bio); - if (ret != ELEVATOR_NO_MERGE) { - *req = q->last_merge; - return ret; - } - } - - if (blk_queue_noxmerges(q)) - return ELEVATOR_NO_MERGE; - - /* - * See if our hash lookup can find a potential backmerge. - */ - __rq = elv_rqhash_find(q, bio->bi_iter.bi_sector); - if (__rq && elv_bio_merge_ok(__rq, bio)) { - *req = __rq; - return ELEVATOR_BACK_MERGE; - } - - if (e->type->ops.elevator_merge_fn) - return e->type->ops.elevator_merge_fn(q, req, bio); - - return ELEVATOR_NO_MERGE; -} - -/* - * Attempt to do an insertion back merge. Only check for the case where - * we can append 'rq' to an existing request, so we can throw 'rq' away - * afterwards. - * - * Returns true if we merged, false otherwise - */ -static bool elv_attempt_insert_merge(struct request_queue *q, - struct request *rq) -{ - struct request *__rq; - bool ret; - - if (blk_queue_nomerges(q)) - return false; - - /* - * First try one-hit cache. - */ - if (q->last_merge && blk_attempt_req_merge(q, q->last_merge, rq)) - return true; - - if (blk_queue_noxmerges(q)) - return false; - - ret = false; - /* - * See if our hash lookup can find a potential backmerge. - */ - while (1) { - __rq = elv_rqhash_find(q, blk_rq_pos(rq)); - if (!__rq || !blk_attempt_req_merge(q, __rq, rq)) - break; - - /* The merged request could be merged with others, try again */ - ret = true; - rq = __rq; - } - - return ret; -} - -void elv_merged_request(struct request_queue *q, struct request *rq, int type) -{ - struct elevator_queue *e = q->elevator; - - if (e->type->ops.elevator_merged_fn) - e->type->ops.elevator_merged_fn(q, rq, type); - - if (type == ELEVATOR_BACK_MERGE) - elv_rqhash_reposition(q, rq); - - q->last_merge = rq; -} - -void elv_merge_requests(struct request_queue *q, struct request *rq, - struct request *next) -{ - struct elevator_queue *e = q->elevator; - const int next_sorted = next->cmd_flags & REQ_SORTED; - - if (next_sorted && e->type->ops.elevator_merge_req_fn) - e->type->ops.elevator_merge_req_fn(q, rq, next); - - elv_rqhash_reposition(q, rq); - - if (next_sorted) { - elv_rqhash_del(q, next); - q->nr_sorted--; - } - - q->last_merge = rq; -} - -void elv_bio_merged(struct request_queue *q, struct request *rq, - struct bio *bio) -{ - struct elevator_queue *e = q->elevator; - - if (e->type->ops.elevator_bio_merged_fn) - e->type->ops.elevator_bio_merged_fn(q, rq, bio); -} - -#ifdef CONFIG_PM -static void blk_pm_requeue_request(struct request *rq) -{ - if (rq->q->dev && !(rq->cmd_flags & REQ_PM)) - rq->q->nr_pending--; -} - -static void blk_pm_add_request(struct request_queue *q, struct request *rq) -{ - if (q->dev && !(rq->cmd_flags & REQ_PM) && q->nr_pending++ == 0 && - (q->rpm_status == RPM_SUSPENDED || q->rpm_status == RPM_SUSPENDING)) - pm_request_resume(q->dev); -} -#else -static inline void blk_pm_requeue_request(struct request *rq) {} -static inline void blk_pm_add_request(struct request_queue *q, - struct request *rq) -{ -} -#endif - -void elv_requeue_request(struct request_queue *q, struct request *rq) -{ - /* - * it already went through dequeue, we need to decrement the - * in_flight count again - */ - if (blk_account_rq(rq)) { - q->in_flight[rq_is_sync(rq)]--; - if (rq->cmd_flags & REQ_SORTED) - elv_deactivate_rq(q, rq); - } - - rq->cmd_flags &= ~REQ_STARTED; - - blk_pm_requeue_request(rq); - - __elv_add_request(q, rq, ELEVATOR_INSERT_REQUEUE); -} - -void elv_drain_elevator(struct request_queue *q) -{ - static int printed; - - lockdep_assert_held(q->queue_lock); - - while (q->elevator->type->ops.elevator_dispatch_fn(q, 1)) - ; - if (q->nr_sorted && printed++ < 10) { - printk(KERN_ERR "%s: forced dispatching is broken " - "(nr_sorted=%u), please report this\n", - q->elevator->type->elevator_name, q->nr_sorted); - } -} - -void __elv_add_request(struct request_queue *q, struct request *rq, int where) -{ - trace_block_rq_insert(q, rq); - - blk_pm_add_request(q, rq); - - rq->q = q; - - if (rq->cmd_flags & REQ_SOFTBARRIER) { - /* barriers are scheduling boundary, update end_sector */ - if (rq->cmd_type == REQ_TYPE_FS) { - q->end_sector = rq_end_sector(rq); - q->boundary_rq = rq; - } - } else if (!(rq->cmd_flags & REQ_ELVPRIV) && - (where == ELEVATOR_INSERT_SORT || - where == ELEVATOR_INSERT_SORT_MERGE)) - where = ELEVATOR_INSERT_BACK; - - switch (where) { - case ELEVATOR_INSERT_REQUEUE: - case ELEVATOR_INSERT_FRONT: - rq->cmd_flags |= REQ_SOFTBARRIER; - list_add(&rq->queuelist, &q->queue_head); - break; - - case ELEVATOR_INSERT_BACK: - rq->cmd_flags |= REQ_SOFTBARRIER; - elv_drain_elevator(q); - list_add_tail(&rq->queuelist, &q->queue_head); - /* - * We kick the queue here for the following reasons. - * - The elevator might have returned NULL previously - * to delay requests and returned them now. As the - * queue wasn't empty before this request, ll_rw_blk - * won't run the queue on return, resulting in hang. - * - Usually, back inserted requests won't be merged - * with anything. There's no point in delaying queue - * processing. - */ - __blk_run_queue(q); - break; - - case ELEVATOR_INSERT_SORT_MERGE: - /* - * If we succeed in merging this request with one in the - * queue already, we are done - rq has now been freed, - * so no need to do anything further. - */ - if (elv_attempt_insert_merge(q, rq)) - break; - case ELEVATOR_INSERT_SORT: - BUG_ON(rq->cmd_type != REQ_TYPE_FS); - rq->cmd_flags |= REQ_SORTED; - q->nr_sorted++; - if (rq_mergeable(rq)) { - elv_rqhash_add(q, rq); - if (!q->last_merge) - q->last_merge = rq; - } - - /* - * Some ioscheds (cfq) run q->request_fn directly, so - * rq cannot be accessed after calling - * elevator_add_req_fn. - */ - q->elevator->type->ops.elevator_add_req_fn(q, rq); - break; - - case ELEVATOR_INSERT_FLUSH: - rq->cmd_flags |= REQ_SOFTBARRIER; - blk_insert_flush(rq); - break; - default: - printk(KERN_ERR "%s: bad insertion point %d\n", - __func__, where); - BUG(); - } -} -EXPORT_SYMBOL(__elv_add_request); - -void elv_add_request(struct request_queue *q, struct request *rq, int where) -{ - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - __elv_add_request(q, rq, where); - spin_unlock_irqrestore(q->queue_lock, flags); -} -EXPORT_SYMBOL(elv_add_request); - -struct request *elv_latter_request(struct request_queue *q, struct request *rq) -{ - struct elevator_queue *e = q->elevator; - - if (e->type->ops.elevator_latter_req_fn) - return e->type->ops.elevator_latter_req_fn(q, rq); - return NULL; -} - -struct request *elv_former_request(struct request_queue *q, struct request *rq) -{ - struct elevator_queue *e = q->elevator; - - if (e->type->ops.elevator_former_req_fn) - return e->type->ops.elevator_former_req_fn(q, rq); - return NULL; -} - -int elv_set_request(struct request_queue *q, struct request *rq, - struct bio *bio, gfp_t gfp_mask) -{ - struct elevator_queue *e = q->elevator; - - if (e->type->ops.elevator_set_req_fn) - return e->type->ops.elevator_set_req_fn(q, rq, bio, gfp_mask); - return 0; -} - -void elv_put_request(struct request_queue *q, struct request *rq) -{ - struct elevator_queue *e = q->elevator; - - if (e->type->ops.elevator_put_req_fn) - e->type->ops.elevator_put_req_fn(rq); -} - -int elv_may_queue(struct request_queue *q, int op, int op_flags) -{ - struct elevator_queue *e = q->elevator; - - if (e->type->ops.elevator_may_queue_fn) - return e->type->ops.elevator_may_queue_fn(q, op, op_flags); - - return ELV_MQUEUE_MAY; -} - -void elv_completed_request(struct request_queue *q, struct request *rq) -{ - struct elevator_queue *e = q->elevator; - - /* - * request is released from the driver, io must be done - */ - if (blk_account_rq(rq)) { - q->in_flight[rq_is_sync(rq)]--; - if ((rq->cmd_flags & REQ_SORTED) && - e->type->ops.elevator_completed_req_fn) - e->type->ops.elevator_completed_req_fn(q, rq); - } -} - -#define to_elv(atr) container_of((atr), struct elv_fs_entry, attr) - -static ssize_t -elv_attr_show(struct kobject *kobj, struct attribute *attr, char *page) -{ - struct elv_fs_entry *entry = to_elv(attr); - struct elevator_queue *e; - ssize_t error; - - if (!entry->show) - return -EIO; - - e = container_of(kobj, struct elevator_queue, kobj); - mutex_lock(&e->sysfs_lock); - error = e->type ? entry->show(e, page) : -ENOENT; - mutex_unlock(&e->sysfs_lock); - return error; -} - -static ssize_t -elv_attr_store(struct kobject *kobj, struct attribute *attr, - const char *page, size_t length) -{ - struct elv_fs_entry *entry = to_elv(attr); - struct elevator_queue *e; - ssize_t error; - - if (!entry->store) - return -EIO; - - e = container_of(kobj, struct elevator_queue, kobj); - mutex_lock(&e->sysfs_lock); - error = e->type ? entry->store(e, page, length) : -ENOENT; - mutex_unlock(&e->sysfs_lock); - return error; -} - -static const struct sysfs_ops elv_sysfs_ops = { - .show = elv_attr_show, - .store = elv_attr_store, -}; - -static struct kobj_type elv_ktype = { - .sysfs_ops = &elv_sysfs_ops, - .release = elevator_release, -}; - -int elv_register_queue(struct request_queue *q) -{ - struct elevator_queue *e = q->elevator; - int error; - - error = kobject_add(&e->kobj, &q->kobj, "%s", "iosched"); - if (!error) { - struct elv_fs_entry *attr = e->type->elevator_attrs; - if (attr) { - while (attr->attr.name) { - if (sysfs_create_file(&e->kobj, &attr->attr)) - break; - attr++; - } - } - kobject_uevent(&e->kobj, KOBJ_ADD); - e->registered = 1; - if (e->type->ops.elevator_registered_fn) - e->type->ops.elevator_registered_fn(q); - } - return error; -} -EXPORT_SYMBOL(elv_register_queue); - -void elv_unregister_queue(struct request_queue *q) -{ - if (q) { - struct elevator_queue *e = q->elevator; - - kobject_uevent(&e->kobj, KOBJ_REMOVE); - kobject_del(&e->kobj); - e->registered = 0; - } -} -EXPORT_SYMBOL(elv_unregister_queue); - -int elv_register(struct elevator_type *e) -{ - char *def = ""; - - /* create icq_cache if requested */ - if (e->icq_size) { - if (WARN_ON(e->icq_size < sizeof(struct io_cq)) || - WARN_ON(e->icq_align < __alignof__(struct io_cq))) - return -EINVAL; - - snprintf(e->icq_cache_name, sizeof(e->icq_cache_name), - "%s_io_cq", e->elevator_name); - e->icq_cache = kmem_cache_create(e->icq_cache_name, e->icq_size, - e->icq_align, 0, NULL); - if (!e->icq_cache) - return -ENOMEM; - } - - /* register, don't allow duplicate names */ - spin_lock(&elv_list_lock); - if (elevator_find(e->elevator_name)) { - spin_unlock(&elv_list_lock); - if (e->icq_cache) - kmem_cache_destroy(e->icq_cache); - return -EBUSY; - } - list_add_tail(&e->list, &elv_list); - spin_unlock(&elv_list_lock); - - /* print pretty message */ - if (!strcmp(e->elevator_name, chosen_elevator) || - (!*chosen_elevator && - !strcmp(e->elevator_name, CONFIG_DEFAULT_IOSCHED))) - def = " (default)"; - - printk(KERN_INFO "io scheduler %s registered%s\n", e->elevator_name, - def); - return 0; -} -EXPORT_SYMBOL_GPL(elv_register); - -void elv_unregister(struct elevator_type *e) -{ - /* unregister */ - spin_lock(&elv_list_lock); - list_del_init(&e->list); - spin_unlock(&elv_list_lock); - - /* - * Destroy icq_cache if it exists. icq's are RCU managed. Make - * sure all RCU operations are complete before proceeding. - */ - if (e->icq_cache) { - rcu_barrier(); - kmem_cache_destroy(e->icq_cache); - e->icq_cache = NULL; - } -} -EXPORT_SYMBOL_GPL(elv_unregister); - -/* - * switch to new_e io scheduler. be careful not to introduce deadlocks - - * we don't free the old io scheduler, before we have allocated what we - * need for the new one. this way we have a chance of going back to the old - * one, if the new one fails init for some reason. - */ -static int elevator_switch(struct request_queue *q, struct elevator_type *new_e) -{ - struct elevator_queue *old = q->elevator; - bool registered = old->registered; - int err; - - /* - * Turn on BYPASS and drain all requests w/ elevator private data. - * Block layer doesn't call into a quiesced elevator - all requests - * are directly put on the dispatch list without elevator data - * using INSERT_BACK. All requests have SOFTBARRIER set and no - * merge happens either. - */ - blk_queue_bypass_start(q); - - /* unregister and clear all auxiliary data of the old elevator */ - if (registered) - elv_unregister_queue(q); - - spin_lock_irq(q->queue_lock); - ioc_clear_queue(q); - spin_unlock_irq(q->queue_lock); - - /* allocate, init and register new elevator */ - err = new_e->ops.elevator_init_fn(q, new_e); - if (err) - goto fail_init; - - if (registered) { - err = elv_register_queue(q); - if (err) - goto fail_register; - } - - /* done, kill the old one and finish */ - elevator_exit(old); - blk_queue_bypass_end(q); - - blk_add_trace_msg(q, "elv switch: %s", new_e->elevator_name); - - return 0; - -fail_register: - elevator_exit(q->elevator); -fail_init: - /* switch failed, restore and re-register old elevator */ - q->elevator = old; - elv_register_queue(q); - blk_queue_bypass_end(q); - - return err; -} - -/* - * Switch this queue to the given IO scheduler. - */ -static int __elevator_change(struct request_queue *q, const char *name) -{ - char elevator_name[ELV_NAME_MAX]; - struct elevator_type *e; - - if (!q->elevator) - return -ENXIO; - - strlcpy(elevator_name, name, sizeof(elevator_name)); - e = elevator_get(strstrip(elevator_name), true); - if (!e) { - printk(KERN_ERR "elevator: type %s not found\n", elevator_name); - return -EINVAL; - } - - if (!strcmp(elevator_name, q->elevator->type->elevator_name)) { - elevator_put(e); - return 0; - } - - return elevator_switch(q, e); -} - -int elevator_change(struct request_queue *q, const char *name) -{ - int ret; - - /* Protect q->elevator from elevator_init() */ - mutex_lock(&q->sysfs_lock); - ret = __elevator_change(q, name); - mutex_unlock(&q->sysfs_lock); - - return ret; -} -EXPORT_SYMBOL(elevator_change); - -ssize_t elv_iosched_store(struct request_queue *q, const char *name, - size_t count) -{ - int ret; - - if (!q->elevator) - return count; - - ret = __elevator_change(q, name); - if (!ret) - return count; - - printk(KERN_ERR "elevator: switch to %s failed\n", name); - return ret; -} - -ssize_t elv_iosched_show(struct request_queue *q, char *name) -{ - struct elevator_queue *e = q->elevator; - struct elevator_type *elv; - struct elevator_type *__e; - int len = 0; - - if (!q->elevator || !blk_queue_stackable(q)) - return sprintf(name, "none\n"); - - elv = e->type; - - spin_lock(&elv_list_lock); - list_for_each_entry(__e, &elv_list, list) { - if (!strcmp(elv->elevator_name, __e->elevator_name)) - len += sprintf(name+len, "[%s] ", elv->elevator_name); - else - len += sprintf(name+len, "%s ", __e->elevator_name); - } - spin_unlock(&elv_list_lock); - - len += sprintf(len+name, "\n"); - return len; -} - -struct request *elv_rb_former_request(struct request_queue *q, - struct request *rq) -{ - struct rb_node *rbprev = rb_prev(&rq->rb_node); - - if (rbprev) - return rb_entry_rq(rbprev); - - return NULL; -} -EXPORT_SYMBOL(elv_rb_former_request); - -struct request *elv_rb_latter_request(struct request_queue *q, - struct request *rq) -{ - struct rb_node *rbnext = rb_next(&rq->rb_node); - - if (rbnext) - return rb_entry_rq(rbnext); - - return NULL; -} -EXPORT_SYMBOL(elv_rb_latter_request); diff --git a/src/linux/block/genhd.c b/src/linux/block/genhd.c deleted file mode 100644 index fcd6d4f..0000000 --- a/src/linux/block/genhd.c +++ /dev/null @@ -1,1875 +0,0 @@ -/* - * gendisk handling - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "blk.h" - -static DEFINE_MUTEX(block_class_lock); -struct kobject *block_depr; - -/* for extended dynamic devt allocation, currently only one major is used */ -#define NR_EXT_DEVT (1 << MINORBITS) - -/* For extended devt allocation. ext_devt_lock prevents look up - * results from going away underneath its user. - */ -static DEFINE_SPINLOCK(ext_devt_lock); -static DEFINE_IDR(ext_devt_idr); - -static struct device_type disk_type; - -static void disk_check_events(struct disk_events *ev, - unsigned int *clearing_ptr); -static void disk_alloc_events(struct gendisk *disk); -static void disk_add_events(struct gendisk *disk); -static void disk_del_events(struct gendisk *disk); -static void disk_release_events(struct gendisk *disk); - -/** - * disk_get_part - get partition - * @disk: disk to look partition from - * @partno: partition number - * - * Look for partition @partno from @disk. If found, increment - * reference count and return it. - * - * CONTEXT: - * Don't care. - * - * RETURNS: - * Pointer to the found partition on success, NULL if not found. - */ -struct hd_struct *disk_get_part(struct gendisk *disk, int partno) -{ - struct hd_struct *part = NULL; - struct disk_part_tbl *ptbl; - - if (unlikely(partno < 0)) - return NULL; - - rcu_read_lock(); - - ptbl = rcu_dereference(disk->part_tbl); - if (likely(partno < ptbl->len)) { - part = rcu_dereference(ptbl->part[partno]); - if (part) - get_device(part_to_dev(part)); - } - - rcu_read_unlock(); - - return part; -} -EXPORT_SYMBOL_GPL(disk_get_part); - -/** - * disk_part_iter_init - initialize partition iterator - * @piter: iterator to initialize - * @disk: disk to iterate over - * @flags: DISK_PITER_* flags - * - * Initialize @piter so that it iterates over partitions of @disk. - * - * CONTEXT: - * Don't care. - */ -void disk_part_iter_init(struct disk_part_iter *piter, struct gendisk *disk, - unsigned int flags) -{ - struct disk_part_tbl *ptbl; - - rcu_read_lock(); - ptbl = rcu_dereference(disk->part_tbl); - - piter->disk = disk; - piter->part = NULL; - - if (flags & DISK_PITER_REVERSE) - piter->idx = ptbl->len - 1; - else if (flags & (DISK_PITER_INCL_PART0 | DISK_PITER_INCL_EMPTY_PART0)) - piter->idx = 0; - else - piter->idx = 1; - - piter->flags = flags; - - rcu_read_unlock(); -} -EXPORT_SYMBOL_GPL(disk_part_iter_init); - -/** - * disk_part_iter_next - proceed iterator to the next partition and return it - * @piter: iterator of interest - * - * Proceed @piter to the next partition and return it. - * - * CONTEXT: - * Don't care. - */ -struct hd_struct *disk_part_iter_next(struct disk_part_iter *piter) -{ - struct disk_part_tbl *ptbl; - int inc, end; - - /* put the last partition */ - disk_put_part(piter->part); - piter->part = NULL; - - /* get part_tbl */ - rcu_read_lock(); - ptbl = rcu_dereference(piter->disk->part_tbl); - - /* determine iteration parameters */ - if (piter->flags & DISK_PITER_REVERSE) { - inc = -1; - if (piter->flags & (DISK_PITER_INCL_PART0 | - DISK_PITER_INCL_EMPTY_PART0)) - end = -1; - else - end = 0; - } else { - inc = 1; - end = ptbl->len; - } - - /* iterate to the next partition */ - for (; piter->idx != end; piter->idx += inc) { - struct hd_struct *part; - - part = rcu_dereference(ptbl->part[piter->idx]); - if (!part) - continue; - if (!part_nr_sects_read(part) && - !(piter->flags & DISK_PITER_INCL_EMPTY) && - !(piter->flags & DISK_PITER_INCL_EMPTY_PART0 && - piter->idx == 0)) - continue; - - get_device(part_to_dev(part)); - piter->part = part; - piter->idx += inc; - break; - } - - rcu_read_unlock(); - - return piter->part; -} -EXPORT_SYMBOL_GPL(disk_part_iter_next); - -/** - * disk_part_iter_exit - finish up partition iteration - * @piter: iter of interest - * - * Called when iteration is over. Cleans up @piter. - * - * CONTEXT: - * Don't care. - */ -void disk_part_iter_exit(struct disk_part_iter *piter) -{ - disk_put_part(piter->part); - piter->part = NULL; -} -EXPORT_SYMBOL_GPL(disk_part_iter_exit); - -static inline int sector_in_part(struct hd_struct *part, sector_t sector) -{ - return part->start_sect <= sector && - sector < part->start_sect + part_nr_sects_read(part); -} - -/** - * disk_map_sector_rcu - map sector to partition - * @disk: gendisk of interest - * @sector: sector to map - * - * Find out which partition @sector maps to on @disk. This is - * primarily used for stats accounting. - * - * CONTEXT: - * RCU read locked. The returned partition pointer is valid only - * while preemption is disabled. - * - * RETURNS: - * Found partition on success, part0 is returned if no partition matches - */ -struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, sector_t sector) -{ - struct disk_part_tbl *ptbl; - struct hd_struct *part; - int i; - - ptbl = rcu_dereference(disk->part_tbl); - - part = rcu_dereference(ptbl->last_lookup); - if (part && sector_in_part(part, sector)) - return part; - - for (i = 1; i < ptbl->len; i++) { - part = rcu_dereference(ptbl->part[i]); - - if (part && sector_in_part(part, sector)) { - rcu_assign_pointer(ptbl->last_lookup, part); - return part; - } - } - return &disk->part0; -} -EXPORT_SYMBOL_GPL(disk_map_sector_rcu); - -/* - * Can be deleted altogether. Later. - * - */ -static struct blk_major_name { - struct blk_major_name *next; - int major; - char name[16]; -} *major_names[BLKDEV_MAJOR_HASH_SIZE]; - -/* index in the above - for now: assume no multimajor ranges */ -static inline int major_to_index(unsigned major) -{ - return major % BLKDEV_MAJOR_HASH_SIZE; -} - -#ifdef CONFIG_PROC_FS -void blkdev_show(struct seq_file *seqf, off_t offset) -{ - struct blk_major_name *dp; - - if (offset < BLKDEV_MAJOR_HASH_SIZE) { - mutex_lock(&block_class_lock); - for (dp = major_names[offset]; dp; dp = dp->next) - seq_printf(seqf, "%3d %s\n", dp->major, dp->name); - mutex_unlock(&block_class_lock); - } -} -#endif /* CONFIG_PROC_FS */ - -/** - * register_blkdev - register a new block device - * - * @major: the requested major device number [1..255]. If @major=0, try to - * allocate any unused major number. - * @name: the name of the new block device as a zero terminated string - * - * The @name must be unique within the system. - * - * The return value depends on the @major input parameter. - * - if a major device number was requested in range [1..255] then the - * function returns zero on success, or a negative error code - * - if any unused major number was requested with @major=0 parameter - * then the return value is the allocated major number in range - * [1..255] or a negative error code otherwise - */ -int register_blkdev(unsigned int major, const char *name) -{ - struct blk_major_name **n, *p; - int index, ret = 0; - - mutex_lock(&block_class_lock); - - /* temporary */ - if (major == 0) { - for (index = ARRAY_SIZE(major_names)-1; index > 0; index--) { - if (major_names[index] == NULL) - break; - } - - if (index == 0) { - printk("register_blkdev: failed to get major for %s\n", - name); - ret = -EBUSY; - goto out; - } - major = index; - ret = major; - } - - p = kmalloc(sizeof(struct blk_major_name), GFP_KERNEL); - if (p == NULL) { - ret = -ENOMEM; - goto out; - } - - p->major = major; - strlcpy(p->name, name, sizeof(p->name)); - p->next = NULL; - index = major_to_index(major); - - for (n = &major_names[index]; *n; n = &(*n)->next) { - if ((*n)->major == major) - break; - } - if (!*n) - *n = p; - else - ret = -EBUSY; - - if (ret < 0) { - printk("register_blkdev: cannot get major %d for %s\n", - major, name); - kfree(p); - } -out: - mutex_unlock(&block_class_lock); - return ret; -} - -EXPORT_SYMBOL(register_blkdev); - -void unregister_blkdev(unsigned int major, const char *name) -{ - struct blk_major_name **n; - struct blk_major_name *p = NULL; - int index = major_to_index(major); - - mutex_lock(&block_class_lock); - for (n = &major_names[index]; *n; n = &(*n)->next) - if ((*n)->major == major) - break; - if (!*n || strcmp((*n)->name, name)) { - WARN_ON(1); - } else { - p = *n; - *n = p->next; - } - mutex_unlock(&block_class_lock); - kfree(p); -} - -EXPORT_SYMBOL(unregister_blkdev); - -static struct kobj_map *bdev_map; - -/** - * blk_mangle_minor - scatter minor numbers apart - * @minor: minor number to mangle - * - * Scatter consecutively allocated @minor number apart if MANGLE_DEVT - * is enabled. Mangling twice gives the original value. - * - * RETURNS: - * Mangled value. - * - * CONTEXT: - * Don't care. - */ -static int blk_mangle_minor(int minor) -{ -#ifdef CONFIG_DEBUG_BLOCK_EXT_DEVT - int i; - - for (i = 0; i < MINORBITS / 2; i++) { - int low = minor & (1 << i); - int high = minor & (1 << (MINORBITS - 1 - i)); - int distance = MINORBITS - 1 - 2 * i; - - minor ^= low | high; /* clear both bits */ - low <<= distance; /* swap the positions */ - high >>= distance; - minor |= low | high; /* and set */ - } -#endif - return minor; -} - -/** - * blk_alloc_devt - allocate a dev_t for a partition - * @part: partition to allocate dev_t for - * @devt: out parameter for resulting dev_t - * - * Allocate a dev_t for block device. - * - * RETURNS: - * 0 on success, allocated dev_t is returned in *@devt. -errno on - * failure. - * - * CONTEXT: - * Might sleep. - */ -int blk_alloc_devt(struct hd_struct *part, dev_t *devt) -{ - struct gendisk *disk = part_to_disk(part); - int idx; - - /* in consecutive minor range? */ - if (part->partno < disk->minors) { - *devt = MKDEV(disk->major, disk->first_minor + part->partno); - return 0; - } - - /* allocate ext devt */ - idr_preload(GFP_KERNEL); - - spin_lock_bh(&ext_devt_lock); - idx = idr_alloc(&ext_devt_idr, part, 0, NR_EXT_DEVT, GFP_NOWAIT); - spin_unlock_bh(&ext_devt_lock); - - idr_preload_end(); - if (idx < 0) - return idx == -ENOSPC ? -EBUSY : idx; - - *devt = MKDEV(BLOCK_EXT_MAJOR, blk_mangle_minor(idx)); - return 0; -} - -/** - * blk_free_devt - free a dev_t - * @devt: dev_t to free - * - * Free @devt which was allocated using blk_alloc_devt(). - * - * CONTEXT: - * Might sleep. - */ -void blk_free_devt(dev_t devt) -{ - if (devt == MKDEV(0, 0)) - return; - - if (MAJOR(devt) == BLOCK_EXT_MAJOR) { - spin_lock_bh(&ext_devt_lock); - idr_remove(&ext_devt_idr, blk_mangle_minor(MINOR(devt))); - spin_unlock_bh(&ext_devt_lock); - } -} - -static char *bdevt_str(dev_t devt, char *buf) -{ - if (MAJOR(devt) <= 0xff && MINOR(devt) <= 0xff) { - char tbuf[BDEVT_SIZE]; - snprintf(tbuf, BDEVT_SIZE, "%02x%02x", MAJOR(devt), MINOR(devt)); - snprintf(buf, BDEVT_SIZE, "%-9s", tbuf); - } else - snprintf(buf, BDEVT_SIZE, "%03x:%05x", MAJOR(devt), MINOR(devt)); - - return buf; -} - -/* - * Register device numbers dev..(dev+range-1) - * range must be nonzero - * The hash chain is sorted on range, so that subranges can override. - */ -void blk_register_region(dev_t devt, unsigned long range, struct module *module, - struct kobject *(*probe)(dev_t, int *, void *), - int (*lock)(dev_t, void *), void *data) -{ - kobj_map(bdev_map, devt, range, module, probe, lock, data); -} - -EXPORT_SYMBOL(blk_register_region); - -void blk_unregister_region(dev_t devt, unsigned long range) -{ - kobj_unmap(bdev_map, devt, range); -} - -EXPORT_SYMBOL(blk_unregister_region); - -static struct kobject *exact_match(dev_t devt, int *partno, void *data) -{ - struct gendisk *p = data; - - return &disk_to_dev(p)->kobj; -} - -static int exact_lock(dev_t devt, void *data) -{ - struct gendisk *p = data; - - if (!get_disk(p)) - return -1; - return 0; -} - -static void register_disk(struct device *parent, struct gendisk *disk) -{ - struct device *ddev = disk_to_dev(disk); - struct block_device *bdev; - struct disk_part_iter piter; - struct hd_struct *part; - int err; - - ddev->parent = parent; - - dev_set_name(ddev, "%s", disk->disk_name); - - /* delay uevents, until we scanned partition table */ - dev_set_uevent_suppress(ddev, 1); - - if (device_add(ddev)) - return; - if (!sysfs_deprecated) { - err = sysfs_create_link(block_depr, &ddev->kobj, - kobject_name(&ddev->kobj)); - if (err) { - device_del(ddev); - return; - } - } - - /* - * avoid probable deadlock caused by allocating memory with - * GFP_KERNEL in runtime_resume callback of its all ancestor - * devices - */ - pm_runtime_set_memalloc_noio(ddev, true); - - disk->part0.holder_dir = kobject_create_and_add("holders", &ddev->kobj); - disk->slave_dir = kobject_create_and_add("slaves", &ddev->kobj); - - /* No minors to use for partitions */ - if (!disk_part_scan_enabled(disk)) - goto exit; - - /* No such device (e.g., media were just removed) */ - if (!get_capacity(disk)) - goto exit; - - bdev = bdget_disk(disk, 0); - if (!bdev) - goto exit; - - bdev->bd_invalidated = 1; - err = blkdev_get(bdev, FMODE_READ, NULL); - if (err < 0) - goto exit; - blkdev_put(bdev, FMODE_READ); - -exit: - /* announce disk after possible partitions are created */ - dev_set_uevent_suppress(ddev, 0); - kobject_uevent(&ddev->kobj, KOBJ_ADD); - - /* announce possible partitions */ - disk_part_iter_init(&piter, disk, 0); - while ((part = disk_part_iter_next(&piter))) - kobject_uevent(&part_to_dev(part)->kobj, KOBJ_ADD); - disk_part_iter_exit(&piter); -} - -/** - * device_add_disk - add partitioning information to kernel list - * @parent: parent device for the disk - * @disk: per-device partitioning information - * - * This function registers the partitioning information in @disk - * with the kernel. - * - * FIXME: error handling - */ -void device_add_disk(struct device *parent, struct gendisk *disk) -{ - struct backing_dev_info *bdi; - dev_t devt; - int retval; - - /* minors == 0 indicates to use ext devt from part0 and should - * be accompanied with EXT_DEVT flag. Make sure all - * parameters make sense. - */ - WARN_ON(disk->minors && !(disk->major || disk->first_minor)); - WARN_ON(!disk->minors && !(disk->flags & GENHD_FL_EXT_DEVT)); - - disk->flags |= GENHD_FL_UP; - - retval = blk_alloc_devt(&disk->part0, &devt); - if (retval) { - WARN_ON(1); - return; - } - disk_to_dev(disk)->devt = devt; - - /* ->major and ->first_minor aren't supposed to be - * dereferenced from here on, but set them just in case. - */ - disk->major = MAJOR(devt); - disk->first_minor = MINOR(devt); - - disk_alloc_events(disk); - - /* Register BDI before referencing it from bdev */ - bdi = &disk->queue->backing_dev_info; - bdi_register_owner(bdi, disk_to_dev(disk)); - - blk_register_region(disk_devt(disk), disk->minors, NULL, - exact_match, exact_lock, disk); - register_disk(parent, disk); - blk_register_queue(disk); - - /* - * Take an extra ref on queue which will be put on disk_release() - * so that it sticks around as long as @disk is there. - */ - WARN_ON_ONCE(!blk_get_queue(disk->queue)); - - retval = sysfs_create_link(&disk_to_dev(disk)->kobj, &bdi->dev->kobj, - "bdi"); - WARN_ON(retval); - - disk_add_events(disk); - blk_integrity_add(disk); -} -EXPORT_SYMBOL(device_add_disk); - -void del_gendisk(struct gendisk *disk) -{ - struct disk_part_iter piter; - struct hd_struct *part; - - blk_integrity_del(disk); - disk_del_events(disk); - - /* invalidate stuff */ - disk_part_iter_init(&piter, disk, - DISK_PITER_INCL_EMPTY | DISK_PITER_REVERSE); - while ((part = disk_part_iter_next(&piter))) { - invalidate_partition(disk, part->partno); - delete_partition(disk, part->partno); - } - disk_part_iter_exit(&piter); - - invalidate_partition(disk, 0); - set_capacity(disk, 0); - disk->flags &= ~GENHD_FL_UP; - - sysfs_remove_link(&disk_to_dev(disk)->kobj, "bdi"); - blk_unregister_queue(disk); - blk_unregister_region(disk_devt(disk), disk->minors); - - part_stat_set_all(&disk->part0, 0); - disk->part0.stamp = 0; - - kobject_put(disk->part0.holder_dir); - kobject_put(disk->slave_dir); - if (!sysfs_deprecated) - sysfs_remove_link(block_depr, dev_name(disk_to_dev(disk))); - pm_runtime_set_memalloc_noio(disk_to_dev(disk), false); - device_del(disk_to_dev(disk)); -} -EXPORT_SYMBOL(del_gendisk); - -/* sysfs access to bad-blocks list. */ -static ssize_t disk_badblocks_show(struct device *dev, - struct device_attribute *attr, - char *page) -{ - struct gendisk *disk = dev_to_disk(dev); - - if (!disk->bb) - return sprintf(page, "\n"); - - return badblocks_show(disk->bb, page, 0); -} - -static ssize_t disk_badblocks_store(struct device *dev, - struct device_attribute *attr, - const char *page, size_t len) -{ - struct gendisk *disk = dev_to_disk(dev); - - if (!disk->bb) - return -ENXIO; - - return badblocks_store(disk->bb, page, len, 0); -} - -/** - * get_gendisk - get partitioning information for a given device - * @devt: device to get partitioning information for - * @partno: returned partition index - * - * This function gets the structure containing partitioning - * information for the given device @devt. - */ -struct gendisk *get_gendisk(dev_t devt, int *partno) -{ - struct gendisk *disk = NULL; - - if (MAJOR(devt) != BLOCK_EXT_MAJOR) { - struct kobject *kobj; - - kobj = kobj_lookup(bdev_map, devt, partno); - if (kobj) - disk = dev_to_disk(kobj_to_dev(kobj)); - } else { - struct hd_struct *part; - - spin_lock_bh(&ext_devt_lock); - part = idr_find(&ext_devt_idr, blk_mangle_minor(MINOR(devt))); - if (part && get_disk(part_to_disk(part))) { - *partno = part->partno; - disk = part_to_disk(part); - } - spin_unlock_bh(&ext_devt_lock); - } - - return disk; -} -EXPORT_SYMBOL(get_gendisk); - -/** - * bdget_disk - do bdget() by gendisk and partition number - * @disk: gendisk of interest - * @partno: partition number - * - * Find partition @partno from @disk, do bdget() on it. - * - * CONTEXT: - * Don't care. - * - * RETURNS: - * Resulting block_device on success, NULL on failure. - */ -struct block_device *bdget_disk(struct gendisk *disk, int partno) -{ - struct hd_struct *part; - struct block_device *bdev = NULL; - - part = disk_get_part(disk, partno); - if (part) - bdev = bdget(part_devt(part)); - disk_put_part(part); - - return bdev; -} -EXPORT_SYMBOL(bdget_disk); - -/* - * print a full list of all partitions - intended for places where the root - * filesystem can't be mounted and thus to give the victim some idea of what - * went wrong - */ -void __init printk_all_partitions(void) -{ - struct class_dev_iter iter; - struct device *dev; - - class_dev_iter_init(&iter, &block_class, NULL, &disk_type); - while ((dev = class_dev_iter_next(&iter))) { - struct gendisk *disk = dev_to_disk(dev); - struct disk_part_iter piter; - struct hd_struct *part; - char name_buf[BDEVNAME_SIZE]; - char devt_buf[BDEVT_SIZE]; - - /* - * Don't show empty devices or things that have been - * suppressed - */ - if (get_capacity(disk) == 0 || - (disk->flags & GENHD_FL_SUPPRESS_PARTITION_INFO)) - continue; - - /* - * Note, unlike /proc/partitions, I am showing the - * numbers in hex - the same format as the root= - * option takes. - */ - disk_part_iter_init(&piter, disk, DISK_PITER_INCL_PART0); - while ((part = disk_part_iter_next(&piter))) { - bool is_part0 = part == &disk->part0; - - printk("%s%s %10llu %s %s", is_part0 ? "" : " ", - bdevt_str(part_devt(part), devt_buf), - (unsigned long long)part_nr_sects_read(part) >> 1 - , disk_name(disk, part->partno, name_buf), - part->info ? part->info->uuid : ""); - if (is_part0) { - if (dev->parent && dev->parent->driver) - printk(" driver: %s\n", - dev->parent->driver->name); - else - printk(" (driver?)\n"); - } else - printk("\n"); - } - disk_part_iter_exit(&piter); - } - class_dev_iter_exit(&iter); -} - -#ifdef CONFIG_PROC_FS -/* iterator */ -static void *disk_seqf_start(struct seq_file *seqf, loff_t *pos) -{ - loff_t skip = *pos; - struct class_dev_iter *iter; - struct device *dev; - - iter = kmalloc(sizeof(*iter), GFP_KERNEL); - if (!iter) - return ERR_PTR(-ENOMEM); - - seqf->private = iter; - class_dev_iter_init(iter, &block_class, NULL, &disk_type); - do { - dev = class_dev_iter_next(iter); - if (!dev) - return NULL; - } while (skip--); - - return dev_to_disk(dev); -} - -static void *disk_seqf_next(struct seq_file *seqf, void *v, loff_t *pos) -{ - struct device *dev; - - (*pos)++; - dev = class_dev_iter_next(seqf->private); - if (dev) - return dev_to_disk(dev); - - return NULL; -} - -static void disk_seqf_stop(struct seq_file *seqf, void *v) -{ - struct class_dev_iter *iter = seqf->private; - - /* stop is called even after start failed :-( */ - if (iter) { - class_dev_iter_exit(iter); - kfree(iter); - seqf->private = NULL; - } -} - -static void *show_partition_start(struct seq_file *seqf, loff_t *pos) -{ - void *p; - - p = disk_seqf_start(seqf, pos); - if (!IS_ERR_OR_NULL(p) && !*pos) - seq_puts(seqf, "major minor #blocks name\n\n"); - return p; -} - -static int show_partition(struct seq_file *seqf, void *v) -{ - struct gendisk *sgp = v; - struct disk_part_iter piter; - struct hd_struct *part; - char buf[BDEVNAME_SIZE]; - - /* Don't show non-partitionable removeable devices or empty devices */ - if (!get_capacity(sgp) || (!disk_max_parts(sgp) && - (sgp->flags & GENHD_FL_REMOVABLE))) - return 0; - if (sgp->flags & GENHD_FL_SUPPRESS_PARTITION_INFO) - return 0; - - /* show the full disk and all non-0 size partitions of it */ - disk_part_iter_init(&piter, sgp, DISK_PITER_INCL_PART0); - while ((part = disk_part_iter_next(&piter))) - seq_printf(seqf, "%4d %7d %10llu %s\n", - MAJOR(part_devt(part)), MINOR(part_devt(part)), - (unsigned long long)part_nr_sects_read(part) >> 1, - disk_name(sgp, part->partno, buf)); - disk_part_iter_exit(&piter); - - return 0; -} - -static const struct seq_operations partitions_op = { - .start = show_partition_start, - .next = disk_seqf_next, - .stop = disk_seqf_stop, - .show = show_partition -}; - -static int partitions_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &partitions_op); -} - -static const struct file_operations proc_partitions_operations = { - .open = partitions_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; -#endif - - -static struct kobject *base_probe(dev_t devt, int *partno, void *data) -{ - if (request_module("block-major-%d-%d", MAJOR(devt), MINOR(devt)) > 0) - /* Make old-style 2.4 aliases work */ - request_module("block-major-%d", MAJOR(devt)); - return NULL; -} - -static int __init genhd_device_init(void) -{ - int error; - - block_class.dev_kobj = sysfs_dev_block_kobj; - error = class_register(&block_class); - if (unlikely(error)) - return error; - bdev_map = kobj_map_init(base_probe, &block_class_lock); - blk_dev_init(); - - register_blkdev(BLOCK_EXT_MAJOR, "blkext"); - - /* create top-level block dir */ - if (!sysfs_deprecated) - block_depr = kobject_create_and_add("block", NULL); - return 0; -} - -subsys_initcall(genhd_device_init); - -static ssize_t disk_range_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gendisk *disk = dev_to_disk(dev); - - return sprintf(buf, "%d\n", disk->minors); -} - -static ssize_t disk_ext_range_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gendisk *disk = dev_to_disk(dev); - - return sprintf(buf, "%d\n", disk_max_parts(disk)); -} - -static ssize_t disk_removable_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gendisk *disk = dev_to_disk(dev); - - return sprintf(buf, "%d\n", - (disk->flags & GENHD_FL_REMOVABLE ? 1 : 0)); -} - -static ssize_t disk_ro_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gendisk *disk = dev_to_disk(dev); - - return sprintf(buf, "%d\n", get_disk_ro(disk) ? 1 : 0); -} - -static ssize_t disk_capability_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gendisk *disk = dev_to_disk(dev); - - return sprintf(buf, "%x\n", disk->flags); -} - -static ssize_t disk_alignment_offset_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct gendisk *disk = dev_to_disk(dev); - - return sprintf(buf, "%d\n", queue_alignment_offset(disk->queue)); -} - -static ssize_t disk_discard_alignment_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct gendisk *disk = dev_to_disk(dev); - - return sprintf(buf, "%d\n", queue_discard_alignment(disk->queue)); -} - -static DEVICE_ATTR(range, S_IRUGO, disk_range_show, NULL); -static DEVICE_ATTR(ext_range, S_IRUGO, disk_ext_range_show, NULL); -static DEVICE_ATTR(removable, S_IRUGO, disk_removable_show, NULL); -static DEVICE_ATTR(ro, S_IRUGO, disk_ro_show, NULL); -static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); -static DEVICE_ATTR(alignment_offset, S_IRUGO, disk_alignment_offset_show, NULL); -static DEVICE_ATTR(discard_alignment, S_IRUGO, disk_discard_alignment_show, - NULL); -static DEVICE_ATTR(capability, S_IRUGO, disk_capability_show, NULL); -static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); -static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL); -static DEVICE_ATTR(badblocks, S_IRUGO | S_IWUSR, disk_badblocks_show, - disk_badblocks_store); -#ifdef CONFIG_FAIL_MAKE_REQUEST -static struct device_attribute dev_attr_fail = - __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store); -#endif -#ifdef CONFIG_FAIL_IO_TIMEOUT -static struct device_attribute dev_attr_fail_timeout = - __ATTR(io-timeout-fail, S_IRUGO|S_IWUSR, part_timeout_show, - part_timeout_store); -#endif - -static struct attribute *disk_attrs[] = { - &dev_attr_range.attr, - &dev_attr_ext_range.attr, - &dev_attr_removable.attr, - &dev_attr_ro.attr, - &dev_attr_size.attr, - &dev_attr_alignment_offset.attr, - &dev_attr_discard_alignment.attr, - &dev_attr_capability.attr, - &dev_attr_stat.attr, - &dev_attr_inflight.attr, - &dev_attr_badblocks.attr, -#ifdef CONFIG_FAIL_MAKE_REQUEST - &dev_attr_fail.attr, -#endif -#ifdef CONFIG_FAIL_IO_TIMEOUT - &dev_attr_fail_timeout.attr, -#endif - NULL -}; - -static struct attribute_group disk_attr_group = { - .attrs = disk_attrs, -}; - -static const struct attribute_group *disk_attr_groups[] = { - &disk_attr_group, - NULL -}; - -/** - * disk_replace_part_tbl - replace disk->part_tbl in RCU-safe way - * @disk: disk to replace part_tbl for - * @new_ptbl: new part_tbl to install - * - * Replace disk->part_tbl with @new_ptbl in RCU-safe way. The - * original ptbl is freed using RCU callback. - * - * LOCKING: - * Matching bd_mutx locked. - */ -static void disk_replace_part_tbl(struct gendisk *disk, - struct disk_part_tbl *new_ptbl) -{ - struct disk_part_tbl *old_ptbl = disk->part_tbl; - - rcu_assign_pointer(disk->part_tbl, new_ptbl); - - if (old_ptbl) { - rcu_assign_pointer(old_ptbl->last_lookup, NULL); - kfree_rcu(old_ptbl, rcu_head); - } -} - -/** - * disk_expand_part_tbl - expand disk->part_tbl - * @disk: disk to expand part_tbl for - * @partno: expand such that this partno can fit in - * - * Expand disk->part_tbl such that @partno can fit in. disk->part_tbl - * uses RCU to allow unlocked dereferencing for stats and other stuff. - * - * LOCKING: - * Matching bd_mutex locked, might sleep. - * - * RETURNS: - * 0 on success, -errno on failure. - */ -int disk_expand_part_tbl(struct gendisk *disk, int partno) -{ - struct disk_part_tbl *old_ptbl = disk->part_tbl; - struct disk_part_tbl *new_ptbl; - int len = old_ptbl ? old_ptbl->len : 0; - int i, target; - size_t size; - - /* - * check for int overflow, since we can get here from blkpg_ioctl() - * with a user passed 'partno'. - */ - target = partno + 1; - if (target < 0) - return -EINVAL; - - /* disk_max_parts() is zero during initialization, ignore if so */ - if (disk_max_parts(disk) && target > disk_max_parts(disk)) - return -EINVAL; - - if (target <= len) - return 0; - - size = sizeof(*new_ptbl) + target * sizeof(new_ptbl->part[0]); - new_ptbl = kzalloc_node(size, GFP_KERNEL, disk->node_id); - if (!new_ptbl) - return -ENOMEM; - - new_ptbl->len = target; - - for (i = 0; i < len; i++) - rcu_assign_pointer(new_ptbl->part[i], old_ptbl->part[i]); - - disk_replace_part_tbl(disk, new_ptbl); - return 0; -} - -static void disk_release(struct device *dev) -{ - struct gendisk *disk = dev_to_disk(dev); - - blk_free_devt(dev->devt); - disk_release_events(disk); - kfree(disk->random); - disk_replace_part_tbl(disk, NULL); - hd_free_part(&disk->part0); - if (disk->queue) - blk_put_queue(disk->queue); - kfree(disk); -} -struct class block_class = { - .name = "block", -}; - -static char *block_devnode(struct device *dev, umode_t *mode, - kuid_t *uid, kgid_t *gid) -{ - struct gendisk *disk = dev_to_disk(dev); - - if (disk->devnode) - return disk->devnode(disk, mode); - return NULL; -} - -static struct device_type disk_type = { - .name = "disk", - .groups = disk_attr_groups, - .release = disk_release, - .devnode = block_devnode, -}; - -#ifdef CONFIG_PROC_FS -/* - * aggregate disk stat collector. Uses the same stats that the sysfs - * entries do, above, but makes them available through one seq_file. - * - * The output looks suspiciously like /proc/partitions with a bunch of - * extra fields. - */ -static int diskstats_show(struct seq_file *seqf, void *v) -{ - struct gendisk *gp = v; - struct disk_part_iter piter; - struct hd_struct *hd; - char buf[BDEVNAME_SIZE]; - int cpu; - - /* - if (&disk_to_dev(gp)->kobj.entry == block_class.devices.next) - seq_puts(seqf, "major minor name" - " rio rmerge rsect ruse wio wmerge " - "wsect wuse running use aveq" - "\n\n"); - */ - - disk_part_iter_init(&piter, gp, DISK_PITER_INCL_EMPTY_PART0); - while ((hd = disk_part_iter_next(&piter))) { - cpu = part_stat_lock(); - part_round_stats(cpu, hd); - part_stat_unlock(); - seq_printf(seqf, "%4d %7d %s %lu %lu %lu " - "%u %lu %lu %lu %u %u %u %u\n", - MAJOR(part_devt(hd)), MINOR(part_devt(hd)), - disk_name(gp, hd->partno, buf), - part_stat_read(hd, ios[READ]), - part_stat_read(hd, merges[READ]), - part_stat_read(hd, sectors[READ]), - jiffies_to_msecs(part_stat_read(hd, ticks[READ])), - part_stat_read(hd, ios[WRITE]), - part_stat_read(hd, merges[WRITE]), - part_stat_read(hd, sectors[WRITE]), - jiffies_to_msecs(part_stat_read(hd, ticks[WRITE])), - part_in_flight(hd), - jiffies_to_msecs(part_stat_read(hd, io_ticks)), - jiffies_to_msecs(part_stat_read(hd, time_in_queue)) - ); - } - disk_part_iter_exit(&piter); - - return 0; -} - -static const struct seq_operations diskstats_op = { - .start = disk_seqf_start, - .next = disk_seqf_next, - .stop = disk_seqf_stop, - .show = diskstats_show -}; - -static int diskstats_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &diskstats_op); -} - -static const struct file_operations proc_diskstats_operations = { - .open = diskstats_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int __init proc_genhd_init(void) -{ - proc_create("diskstats", 0, NULL, &proc_diskstats_operations); - proc_create("partitions", 0, NULL, &proc_partitions_operations); - return 0; -} -module_init(proc_genhd_init); -#endif /* CONFIG_PROC_FS */ - -dev_t blk_lookup_devt(const char *name, int partno) -{ - dev_t devt = MKDEV(0, 0); - struct class_dev_iter iter; - struct device *dev; - - class_dev_iter_init(&iter, &block_class, NULL, &disk_type); - while ((dev = class_dev_iter_next(&iter))) { - struct gendisk *disk = dev_to_disk(dev); - struct hd_struct *part; - - if (strcmp(dev_name(dev), name)) - continue; - - if (partno < disk->minors) { - /* We need to return the right devno, even - * if the partition doesn't exist yet. - */ - devt = MKDEV(MAJOR(dev->devt), - MINOR(dev->devt) + partno); - break; - } - part = disk_get_part(disk, partno); - if (part) { - devt = part_devt(part); - disk_put_part(part); - break; - } - disk_put_part(part); - } - class_dev_iter_exit(&iter); - return devt; -} -EXPORT_SYMBOL(blk_lookup_devt); - -struct gendisk *alloc_disk(int minors) -{ - return alloc_disk_node(minors, NUMA_NO_NODE); -} -EXPORT_SYMBOL(alloc_disk); - -struct gendisk *alloc_disk_node(int minors, int node_id) -{ - struct gendisk *disk; - - disk = kzalloc_node(sizeof(struct gendisk), GFP_KERNEL, node_id); - if (disk) { - if (!init_part_stats(&disk->part0)) { - kfree(disk); - return NULL; - } - disk->node_id = node_id; - if (disk_expand_part_tbl(disk, 0)) { - free_part_stats(&disk->part0); - kfree(disk); - return NULL; - } - disk->part_tbl->part[0] = &disk->part0; - - /* - * set_capacity() and get_capacity() currently don't use - * seqcounter to read/update the part0->nr_sects. Still init - * the counter as we can read the sectors in IO submission - * patch using seqence counters. - * - * TODO: Ideally set_capacity() and get_capacity() should be - * converted to make use of bd_mutex and sequence counters. - */ - seqcount_init(&disk->part0.nr_sects_seq); - if (hd_ref_init(&disk->part0)) { - hd_free_part(&disk->part0); - kfree(disk); - return NULL; - } - - disk->minors = minors; - rand_initialize_disk(disk); - disk_to_dev(disk)->class = &block_class; - disk_to_dev(disk)->type = &disk_type; - device_initialize(disk_to_dev(disk)); - } - return disk; -} -EXPORT_SYMBOL(alloc_disk_node); - -struct kobject *get_disk(struct gendisk *disk) -{ - struct module *owner; - struct kobject *kobj; - - if (!disk->fops) - return NULL; - owner = disk->fops->owner; - if (owner && !try_module_get(owner)) - return NULL; - kobj = kobject_get(&disk_to_dev(disk)->kobj); - if (kobj == NULL) { - module_put(owner); - return NULL; - } - return kobj; - -} - -EXPORT_SYMBOL(get_disk); - -void put_disk(struct gendisk *disk) -{ - if (disk) - kobject_put(&disk_to_dev(disk)->kobj); -} - -EXPORT_SYMBOL(put_disk); - -static void set_disk_ro_uevent(struct gendisk *gd, int ro) -{ - char event[] = "DISK_RO=1"; - char *envp[] = { event, NULL }; - - if (!ro) - event[8] = '0'; - kobject_uevent_env(&disk_to_dev(gd)->kobj, KOBJ_CHANGE, envp); -} - -void set_device_ro(struct block_device *bdev, int flag) -{ - bdev->bd_part->policy = flag; -} - -EXPORT_SYMBOL(set_device_ro); - -void set_disk_ro(struct gendisk *disk, int flag) -{ - struct disk_part_iter piter; - struct hd_struct *part; - - if (disk->part0.policy != flag) { - set_disk_ro_uevent(disk, flag); - disk->part0.policy = flag; - } - - disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY); - while ((part = disk_part_iter_next(&piter))) - part->policy = flag; - disk_part_iter_exit(&piter); -} - -EXPORT_SYMBOL(set_disk_ro); - -int bdev_read_only(struct block_device *bdev) -{ - if (!bdev) - return 0; - return bdev->bd_part->policy; -} - -EXPORT_SYMBOL(bdev_read_only); - -int invalidate_partition(struct gendisk *disk, int partno) -{ - int res = 0; - struct block_device *bdev = bdget_disk(disk, partno); - if (bdev) { - fsync_bdev(bdev); - res = __invalidate_device(bdev, true); - bdput(bdev); - } - return res; -} - -EXPORT_SYMBOL(invalidate_partition); - -/* - * Disk events - monitor disk events like media change and eject request. - */ -struct disk_events { - struct list_head node; /* all disk_event's */ - struct gendisk *disk; /* the associated disk */ - spinlock_t lock; - - struct mutex block_mutex; /* protects blocking */ - int block; /* event blocking depth */ - unsigned int pending; /* events already sent out */ - unsigned int clearing; /* events being cleared */ - - long poll_msecs; /* interval, -1 for default */ - struct delayed_work dwork; -}; - -static const char *disk_events_strs[] = { - [ilog2(DISK_EVENT_MEDIA_CHANGE)] = "media_change", - [ilog2(DISK_EVENT_EJECT_REQUEST)] = "eject_request", -}; - -static char *disk_uevents[] = { - [ilog2(DISK_EVENT_MEDIA_CHANGE)] = "DISK_MEDIA_CHANGE=1", - [ilog2(DISK_EVENT_EJECT_REQUEST)] = "DISK_EJECT_REQUEST=1", -}; - -/* list of all disk_events */ -static DEFINE_MUTEX(disk_events_mutex); -static LIST_HEAD(disk_events); - -/* disable in-kernel polling by default */ -static unsigned long disk_events_dfl_poll_msecs; - -static unsigned long disk_events_poll_jiffies(struct gendisk *disk) -{ - struct disk_events *ev = disk->ev; - long intv_msecs = 0; - - /* - * If device-specific poll interval is set, always use it. If - * the default is being used, poll iff there are events which - * can't be monitored asynchronously. - */ - if (ev->poll_msecs >= 0) - intv_msecs = ev->poll_msecs; - else if (disk->events & ~disk->async_events) - intv_msecs = disk_events_dfl_poll_msecs; - - return msecs_to_jiffies(intv_msecs); -} - -/** - * disk_block_events - block and flush disk event checking - * @disk: disk to block events for - * - * On return from this function, it is guaranteed that event checking - * isn't in progress and won't happen until unblocked by - * disk_unblock_events(). Events blocking is counted and the actual - * unblocking happens after the matching number of unblocks are done. - * - * Note that this intentionally does not block event checking from - * disk_clear_events(). - * - * CONTEXT: - * Might sleep. - */ -void disk_block_events(struct gendisk *disk) -{ - struct disk_events *ev = disk->ev; - unsigned long flags; - bool cancel; - - if (!ev) - return; - - /* - * Outer mutex ensures that the first blocker completes canceling - * the event work before further blockers are allowed to finish. - */ - mutex_lock(&ev->block_mutex); - - spin_lock_irqsave(&ev->lock, flags); - cancel = !ev->block++; - spin_unlock_irqrestore(&ev->lock, flags); - - if (cancel) - cancel_delayed_work_sync(&disk->ev->dwork); - - mutex_unlock(&ev->block_mutex); -} - -static void __disk_unblock_events(struct gendisk *disk, bool check_now) -{ - struct disk_events *ev = disk->ev; - unsigned long intv; - unsigned long flags; - - spin_lock_irqsave(&ev->lock, flags); - - if (WARN_ON_ONCE(ev->block <= 0)) - goto out_unlock; - - if (--ev->block) - goto out_unlock; - - intv = disk_events_poll_jiffies(disk); - if (check_now) - queue_delayed_work(system_freezable_power_efficient_wq, - &ev->dwork, 0); - else if (intv) - queue_delayed_work(system_freezable_power_efficient_wq, - &ev->dwork, intv); -out_unlock: - spin_unlock_irqrestore(&ev->lock, flags); -} - -/** - * disk_unblock_events - unblock disk event checking - * @disk: disk to unblock events for - * - * Undo disk_block_events(). When the block count reaches zero, it - * starts events polling if configured. - * - * CONTEXT: - * Don't care. Safe to call from irq context. - */ -void disk_unblock_events(struct gendisk *disk) -{ - if (disk->ev) - __disk_unblock_events(disk, false); -} - -/** - * disk_flush_events - schedule immediate event checking and flushing - * @disk: disk to check and flush events for - * @mask: events to flush - * - * Schedule immediate event checking on @disk if not blocked. Events in - * @mask are scheduled to be cleared from the driver. Note that this - * doesn't clear the events from @disk->ev. - * - * CONTEXT: - * If @mask is non-zero must be called with bdev->bd_mutex held. - */ -void disk_flush_events(struct gendisk *disk, unsigned int mask) -{ - struct disk_events *ev = disk->ev; - - if (!ev) - return; - - spin_lock_irq(&ev->lock); - ev->clearing |= mask; - if (!ev->block) - mod_delayed_work(system_freezable_power_efficient_wq, - &ev->dwork, 0); - spin_unlock_irq(&ev->lock); -} - -/** - * disk_clear_events - synchronously check, clear and return pending events - * @disk: disk to fetch and clear events from - * @mask: mask of events to be fetched and cleared - * - * Disk events are synchronously checked and pending events in @mask - * are cleared and returned. This ignores the block count. - * - * CONTEXT: - * Might sleep. - */ -unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask) -{ - const struct block_device_operations *bdops = disk->fops; - struct disk_events *ev = disk->ev; - unsigned int pending; - unsigned int clearing = mask; - - if (!ev) { - /* for drivers still using the old ->media_changed method */ - if ((mask & DISK_EVENT_MEDIA_CHANGE) && - bdops->media_changed && bdops->media_changed(disk)) - return DISK_EVENT_MEDIA_CHANGE; - return 0; - } - - disk_block_events(disk); - - /* - * store the union of mask and ev->clearing on the stack so that the - * race with disk_flush_events does not cause ambiguity (ev->clearing - * can still be modified even if events are blocked). - */ - spin_lock_irq(&ev->lock); - clearing |= ev->clearing; - ev->clearing = 0; - spin_unlock_irq(&ev->lock); - - disk_check_events(ev, &clearing); - /* - * if ev->clearing is not 0, the disk_flush_events got called in the - * middle of this function, so we want to run the workfn without delay. - */ - __disk_unblock_events(disk, ev->clearing ? true : false); - - /* then, fetch and clear pending events */ - spin_lock_irq(&ev->lock); - pending = ev->pending & mask; - ev->pending &= ~mask; - spin_unlock_irq(&ev->lock); - WARN_ON_ONCE(clearing & mask); - - return pending; -} - -/* - * Separate this part out so that a different pointer for clearing_ptr can be - * passed in for disk_clear_events. - */ -static void disk_events_workfn(struct work_struct *work) -{ - struct delayed_work *dwork = to_delayed_work(work); - struct disk_events *ev = container_of(dwork, struct disk_events, dwork); - - disk_check_events(ev, &ev->clearing); -} - -static void disk_check_events(struct disk_events *ev, - unsigned int *clearing_ptr) -{ - struct gendisk *disk = ev->disk; - char *envp[ARRAY_SIZE(disk_uevents) + 1] = { }; - unsigned int clearing = *clearing_ptr; - unsigned int events; - unsigned long intv; - int nr_events = 0, i; - - /* check events */ - events = disk->fops->check_events(disk, clearing); - - /* accumulate pending events and schedule next poll if necessary */ - spin_lock_irq(&ev->lock); - - events &= ~ev->pending; - ev->pending |= events; - *clearing_ptr &= ~clearing; - - intv = disk_events_poll_jiffies(disk); - if (!ev->block && intv) - queue_delayed_work(system_freezable_power_efficient_wq, - &ev->dwork, intv); - - spin_unlock_irq(&ev->lock); - - /* - * Tell userland about new events. Only the events listed in - * @disk->events are reported. Unlisted events are processed the - * same internally but never get reported to userland. - */ - for (i = 0; i < ARRAY_SIZE(disk_uevents); i++) - if (events & disk->events & (1 << i)) - envp[nr_events++] = disk_uevents[i]; - - if (nr_events) - kobject_uevent_env(&disk_to_dev(disk)->kobj, KOBJ_CHANGE, envp); -} - -/* - * A disk events enabled device has the following sysfs nodes under - * its /sys/block/X/ directory. - * - * events : list of all supported events - * events_async : list of events which can be detected w/o polling - * events_poll_msecs : polling interval, 0: disable, -1: system default - */ -static ssize_t __disk_events_show(unsigned int events, char *buf) -{ - const char *delim = ""; - ssize_t pos = 0; - int i; - - for (i = 0; i < ARRAY_SIZE(disk_events_strs); i++) - if (events & (1 << i)) { - pos += sprintf(buf + pos, "%s%s", - delim, disk_events_strs[i]); - delim = " "; - } - if (pos) - pos += sprintf(buf + pos, "\n"); - return pos; -} - -static ssize_t disk_events_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gendisk *disk = dev_to_disk(dev); - - return __disk_events_show(disk->events, buf); -} - -static ssize_t disk_events_async_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gendisk *disk = dev_to_disk(dev); - - return __disk_events_show(disk->async_events, buf); -} - -static ssize_t disk_events_poll_msecs_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct gendisk *disk = dev_to_disk(dev); - - return sprintf(buf, "%ld\n", disk->ev->poll_msecs); -} - -static ssize_t disk_events_poll_msecs_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct gendisk *disk = dev_to_disk(dev); - long intv; - - if (!count || !sscanf(buf, "%ld", &intv)) - return -EINVAL; - - if (intv < 0 && intv != -1) - return -EINVAL; - - disk_block_events(disk); - disk->ev->poll_msecs = intv; - __disk_unblock_events(disk, true); - - return count; -} - -static const DEVICE_ATTR(events, S_IRUGO, disk_events_show, NULL); -static const DEVICE_ATTR(events_async, S_IRUGO, disk_events_async_show, NULL); -static const DEVICE_ATTR(events_poll_msecs, S_IRUGO|S_IWUSR, - disk_events_poll_msecs_show, - disk_events_poll_msecs_store); - -static const struct attribute *disk_events_attrs[] = { - &dev_attr_events.attr, - &dev_attr_events_async.attr, - &dev_attr_events_poll_msecs.attr, - NULL, -}; - -/* - * The default polling interval can be specified by the kernel - * parameter block.events_dfl_poll_msecs which defaults to 0 - * (disable). This can also be modified runtime by writing to - * /sys/module/block/events_dfl_poll_msecs. - */ -static int disk_events_set_dfl_poll_msecs(const char *val, - const struct kernel_param *kp) -{ - struct disk_events *ev; - int ret; - - ret = param_set_ulong(val, kp); - if (ret < 0) - return ret; - - mutex_lock(&disk_events_mutex); - - list_for_each_entry(ev, &disk_events, node) - disk_flush_events(ev->disk, 0); - - mutex_unlock(&disk_events_mutex); - - return 0; -} - -static const struct kernel_param_ops disk_events_dfl_poll_msecs_param_ops = { - .set = disk_events_set_dfl_poll_msecs, - .get = param_get_ulong, -}; - -#undef MODULE_PARAM_PREFIX -#define MODULE_PARAM_PREFIX "block." - -module_param_cb(events_dfl_poll_msecs, &disk_events_dfl_poll_msecs_param_ops, - &disk_events_dfl_poll_msecs, 0644); - -/* - * disk_{alloc|add|del|release}_events - initialize and destroy disk_events. - */ -static void disk_alloc_events(struct gendisk *disk) -{ - struct disk_events *ev; - - if (!disk->fops->check_events) - return; - - ev = kzalloc(sizeof(*ev), GFP_KERNEL); - if (!ev) { - pr_warn("%s: failed to initialize events\n", disk->disk_name); - return; - } - - INIT_LIST_HEAD(&ev->node); - ev->disk = disk; - spin_lock_init(&ev->lock); - mutex_init(&ev->block_mutex); - ev->block = 1; - ev->poll_msecs = -1; - INIT_DELAYED_WORK(&ev->dwork, disk_events_workfn); - - disk->ev = ev; -} - -static void disk_add_events(struct gendisk *disk) -{ - if (!disk->ev) - return; - - /* FIXME: error handling */ - if (sysfs_create_files(&disk_to_dev(disk)->kobj, disk_events_attrs) < 0) - pr_warn("%s: failed to create sysfs files for events\n", - disk->disk_name); - - mutex_lock(&disk_events_mutex); - list_add_tail(&disk->ev->node, &disk_events); - mutex_unlock(&disk_events_mutex); - - /* - * Block count is initialized to 1 and the following initial - * unblock kicks it into action. - */ - __disk_unblock_events(disk, true); -} - -static void disk_del_events(struct gendisk *disk) -{ - if (!disk->ev) - return; - - disk_block_events(disk); - - mutex_lock(&disk_events_mutex); - list_del_init(&disk->ev->node); - mutex_unlock(&disk_events_mutex); - - sysfs_remove_files(&disk_to_dev(disk)->kobj, disk_events_attrs); -} - -static void disk_release_events(struct gendisk *disk) -{ - /* the block count should be 1 from disk_del_events() */ - WARN_ON_ONCE(disk->ev && disk->ev->block != 1); - kfree(disk->ev); -} diff --git a/src/linux/block/ioctl.c b/src/linux/block/ioctl.c deleted file mode 100644 index 755119c..0000000 --- a/src/linux/block/ioctl.c +++ /dev/null @@ -1,593 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg __user *arg) -{ - struct block_device *bdevp; - struct gendisk *disk; - struct hd_struct *part, *lpart; - struct blkpg_ioctl_arg a; - struct blkpg_partition p; - struct disk_part_iter piter; - long long start, length; - int partno; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg))) - return -EFAULT; - if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition))) - return -EFAULT; - disk = bdev->bd_disk; - if (bdev != bdev->bd_contains) - return -EINVAL; - partno = p.pno; - if (partno <= 0) - return -EINVAL; - switch (a.op) { - case BLKPG_ADD_PARTITION: - start = p.start >> 9; - length = p.length >> 9; - /* check for fit in a hd_struct */ - if (sizeof(sector_t) == sizeof(long) && - sizeof(long long) > sizeof(long)) { - long pstart = start, plength = length; - if (pstart != start || plength != length - || pstart < 0 || plength < 0 || partno > 65535) - return -EINVAL; - } - - mutex_lock(&bdev->bd_mutex); - - /* overlap? */ - disk_part_iter_init(&piter, disk, - DISK_PITER_INCL_EMPTY); - while ((part = disk_part_iter_next(&piter))) { - if (!(start + length <= part->start_sect || - start >= part->start_sect + part->nr_sects)) { - disk_part_iter_exit(&piter); - mutex_unlock(&bdev->bd_mutex); - return -EBUSY; - } - } - disk_part_iter_exit(&piter); - - /* all seems OK */ - part = add_partition(disk, partno, start, length, - ADDPART_FLAG_NONE, NULL); - mutex_unlock(&bdev->bd_mutex); - return PTR_ERR_OR_ZERO(part); - case BLKPG_DEL_PARTITION: - part = disk_get_part(disk, partno); - if (!part) - return -ENXIO; - - bdevp = bdget(part_devt(part)); - disk_put_part(part); - if (!bdevp) - return -ENOMEM; - - mutex_lock(&bdevp->bd_mutex); - if (bdevp->bd_openers) { - mutex_unlock(&bdevp->bd_mutex); - bdput(bdevp); - return -EBUSY; - } - /* all seems OK */ - fsync_bdev(bdevp); - invalidate_bdev(bdevp); - - mutex_lock_nested(&bdev->bd_mutex, 1); - delete_partition(disk, partno); - mutex_unlock(&bdev->bd_mutex); - mutex_unlock(&bdevp->bd_mutex); - bdput(bdevp); - - return 0; - case BLKPG_RESIZE_PARTITION: - start = p.start >> 9; - /* new length of partition in bytes */ - length = p.length >> 9; - /* check for fit in a hd_struct */ - if (sizeof(sector_t) == sizeof(long) && - sizeof(long long) > sizeof(long)) { - long pstart = start, plength = length; - if (pstart != start || plength != length - || pstart < 0 || plength < 0) - return -EINVAL; - } - part = disk_get_part(disk, partno); - if (!part) - return -ENXIO; - bdevp = bdget(part_devt(part)); - if (!bdevp) { - disk_put_part(part); - return -ENOMEM; - } - mutex_lock(&bdevp->bd_mutex); - mutex_lock_nested(&bdev->bd_mutex, 1); - if (start != part->start_sect) { - mutex_unlock(&bdevp->bd_mutex); - mutex_unlock(&bdev->bd_mutex); - bdput(bdevp); - disk_put_part(part); - return -EINVAL; - } - /* overlap? */ - disk_part_iter_init(&piter, disk, - DISK_PITER_INCL_EMPTY); - while ((lpart = disk_part_iter_next(&piter))) { - if (lpart->partno != partno && - !(start + length <= lpart->start_sect || - start >= lpart->start_sect + lpart->nr_sects) - ) { - disk_part_iter_exit(&piter); - mutex_unlock(&bdevp->bd_mutex); - mutex_unlock(&bdev->bd_mutex); - bdput(bdevp); - disk_put_part(part); - return -EBUSY; - } - } - disk_part_iter_exit(&piter); - part_nr_sects_write(part, (sector_t)length); - i_size_write(bdevp->bd_inode, p.length); - mutex_unlock(&bdevp->bd_mutex); - mutex_unlock(&bdev->bd_mutex); - bdput(bdevp); - disk_put_part(part); - return 0; - default: - return -EINVAL; - } -} - -/* - * This is an exported API for the block driver, and will not - * acquire bd_mutex. This API should be used in case that - * caller has held bd_mutex already. - */ -int __blkdev_reread_part(struct block_device *bdev) -{ - struct gendisk *disk = bdev->bd_disk; - - if (!disk_part_scan_enabled(disk) || bdev != bdev->bd_contains) - return -EINVAL; - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - lockdep_assert_held(&bdev->bd_mutex); - - return rescan_partitions(disk, bdev); -} -EXPORT_SYMBOL(__blkdev_reread_part); - -/* - * This is an exported API for the block driver, and will - * try to acquire bd_mutex. If bd_mutex has been held already - * in current context, please call __blkdev_reread_part(). - * - * Make sure the held locks in current context aren't required - * in open()/close() handler and I/O path for avoiding ABBA deadlock: - * - bd_mutex is held before calling block driver's open/close - * handler - * - reading partition table may submit I/O to the block device - */ -int blkdev_reread_part(struct block_device *bdev) -{ - int res; - - mutex_lock(&bdev->bd_mutex); - res = __blkdev_reread_part(bdev); - mutex_unlock(&bdev->bd_mutex); - - return res; -} -EXPORT_SYMBOL(blkdev_reread_part); - -static int blk_ioctl_discard(struct block_device *bdev, fmode_t mode, - unsigned long arg, unsigned long flags) -{ - uint64_t range[2]; - uint64_t start, len; - - if (!(mode & FMODE_WRITE)) - return -EBADF; - - if (copy_from_user(range, (void __user *)arg, sizeof(range))) - return -EFAULT; - - start = range[0]; - len = range[1]; - - if (start & 511) - return -EINVAL; - if (len & 511) - return -EINVAL; - start >>= 9; - len >>= 9; - - if (start + len > (i_size_read(bdev->bd_inode) >> 9)) - return -EINVAL; - return blkdev_issue_discard(bdev, start, len, GFP_KERNEL, flags); -} - -static int blk_ioctl_zeroout(struct block_device *bdev, fmode_t mode, - unsigned long arg) -{ - uint64_t range[2]; - struct address_space *mapping; - uint64_t start, end, len; - - if (!(mode & FMODE_WRITE)) - return -EBADF; - - if (copy_from_user(range, (void __user *)arg, sizeof(range))) - return -EFAULT; - - start = range[0]; - len = range[1]; - end = start + len - 1; - - if (start & 511) - return -EINVAL; - if (len & 511) - return -EINVAL; - if (end >= (uint64_t)i_size_read(bdev->bd_inode)) - return -EINVAL; - if (end < start) - return -EINVAL; - - /* Invalidate the page cache, including dirty pages */ - mapping = bdev->bd_inode->i_mapping; - truncate_inode_pages_range(mapping, start, end); - - return blkdev_issue_zeroout(bdev, start >> 9, len >> 9, GFP_KERNEL, - false); -} - -static int put_ushort(unsigned long arg, unsigned short val) -{ - return put_user(val, (unsigned short __user *)arg); -} - -static int put_int(unsigned long arg, int val) -{ - return put_user(val, (int __user *)arg); -} - -static int put_uint(unsigned long arg, unsigned int val) -{ - return put_user(val, (unsigned int __user *)arg); -} - -static int put_long(unsigned long arg, long val) -{ - return put_user(val, (long __user *)arg); -} - -static int put_ulong(unsigned long arg, unsigned long val) -{ - return put_user(val, (unsigned long __user *)arg); -} - -static int put_u64(unsigned long arg, u64 val) -{ - return put_user(val, (u64 __user *)arg); -} - -int __blkdev_driver_ioctl(struct block_device *bdev, fmode_t mode, - unsigned cmd, unsigned long arg) -{ - struct gendisk *disk = bdev->bd_disk; - - if (disk->fops->ioctl) - return disk->fops->ioctl(bdev, mode, cmd, arg); - - return -ENOTTY; -} -/* - * For the record: _GPL here is only because somebody decided to slap it - * on the previous export. Sheer idiocy, since it wasn't copyrightable - * at all and could be open-coded without any exports by anybody who cares. - */ -EXPORT_SYMBOL_GPL(__blkdev_driver_ioctl); - -static int blkdev_pr_register(struct block_device *bdev, - struct pr_registration __user *arg) -{ - const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; - struct pr_registration reg; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!ops || !ops->pr_register) - return -EOPNOTSUPP; - if (copy_from_user(®, arg, sizeof(reg))) - return -EFAULT; - - if (reg.flags & ~PR_FL_IGNORE_KEY) - return -EOPNOTSUPP; - return ops->pr_register(bdev, reg.old_key, reg.new_key, reg.flags); -} - -static int blkdev_pr_reserve(struct block_device *bdev, - struct pr_reservation __user *arg) -{ - const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; - struct pr_reservation rsv; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!ops || !ops->pr_reserve) - return -EOPNOTSUPP; - if (copy_from_user(&rsv, arg, sizeof(rsv))) - return -EFAULT; - - if (rsv.flags & ~PR_FL_IGNORE_KEY) - return -EOPNOTSUPP; - return ops->pr_reserve(bdev, rsv.key, rsv.type, rsv.flags); -} - -static int blkdev_pr_release(struct block_device *bdev, - struct pr_reservation __user *arg) -{ - const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; - struct pr_reservation rsv; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!ops || !ops->pr_release) - return -EOPNOTSUPP; - if (copy_from_user(&rsv, arg, sizeof(rsv))) - return -EFAULT; - - if (rsv.flags) - return -EOPNOTSUPP; - return ops->pr_release(bdev, rsv.key, rsv.type); -} - -static int blkdev_pr_preempt(struct block_device *bdev, - struct pr_preempt __user *arg, bool abort) -{ - const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; - struct pr_preempt p; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!ops || !ops->pr_preempt) - return -EOPNOTSUPP; - if (copy_from_user(&p, arg, sizeof(p))) - return -EFAULT; - - if (p.flags) - return -EOPNOTSUPP; - return ops->pr_preempt(bdev, p.old_key, p.new_key, p.type, abort); -} - -static int blkdev_pr_clear(struct block_device *bdev, - struct pr_clear __user *arg) -{ - const struct pr_ops *ops = bdev->bd_disk->fops->pr_ops; - struct pr_clear c; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!ops || !ops->pr_clear) - return -EOPNOTSUPP; - if (copy_from_user(&c, arg, sizeof(c))) - return -EFAULT; - - if (c.flags) - return -EOPNOTSUPP; - return ops->pr_clear(bdev, c.key); -} - -/* - * Is it an unrecognized ioctl? The correct returns are either - * ENOTTY (final) or ENOIOCTLCMD ("I don't know this one, try a - * fallback"). ENOIOCTLCMD gets turned into ENOTTY by the ioctl - * code before returning. - * - * Confused drivers sometimes return EINVAL, which is wrong. It - * means "I understood the ioctl command, but the parameters to - * it were wrong". - * - * We should aim to just fix the broken drivers, the EINVAL case - * should go away. - */ -static inline int is_unrecognized_ioctl(int ret) -{ - return ret == -EINVAL || - ret == -ENOTTY || - ret == -ENOIOCTLCMD; -} - -static int blkdev_flushbuf(struct block_device *bdev, fmode_t mode, - unsigned cmd, unsigned long arg) -{ - int ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - - ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg); - if (!is_unrecognized_ioctl(ret)) - return ret; - - fsync_bdev(bdev); - invalidate_bdev(bdev); - return 0; -} - -static int blkdev_roset(struct block_device *bdev, fmode_t mode, - unsigned cmd, unsigned long arg) -{ - int ret, n; - - ret = __blkdev_driver_ioctl(bdev, mode, cmd, arg); - if (!is_unrecognized_ioctl(ret)) - return ret; - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (get_user(n, (int __user *)arg)) - return -EFAULT; - set_device_ro(bdev, n); - return 0; -} - -static int blkdev_getgeo(struct block_device *bdev, - struct hd_geometry __user *argp) -{ - struct gendisk *disk = bdev->bd_disk; - struct hd_geometry geo; - int ret; - - if (!argp) - return -EINVAL; - if (!disk->fops->getgeo) - return -ENOTTY; - - /* - * We need to set the startsect first, the driver may - * want to override it. - */ - memset(&geo, 0, sizeof(geo)); - geo.start = get_start_sect(bdev); - ret = disk->fops->getgeo(bdev, &geo); - if (ret) - return ret; - if (copy_to_user(argp, &geo, sizeof(geo))) - return -EFAULT; - return 0; -} - -/* set the logical block size */ -static int blkdev_bszset(struct block_device *bdev, fmode_t mode, - int __user *argp) -{ - int ret, n; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (!argp) - return -EINVAL; - if (get_user(n, argp)) - return -EFAULT; - - if (!(mode & FMODE_EXCL)) { - bdgrab(bdev); - if (blkdev_get(bdev, mode | FMODE_EXCL, &bdev) < 0) - return -EBUSY; - } - - ret = set_blocksize(bdev, n); - if (!(mode & FMODE_EXCL)) - blkdev_put(bdev, mode | FMODE_EXCL); - return ret; -} - -/* - * always keep this in sync with compat_blkdev_ioctl() - */ -int blkdev_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd, - unsigned long arg) -{ - struct backing_dev_info *bdi; - void __user *argp = (void __user *)arg; - loff_t size; - unsigned int max_sectors; - - switch (cmd) { - case BLKFLSBUF: - return blkdev_flushbuf(bdev, mode, cmd, arg); - case BLKROSET: - return blkdev_roset(bdev, mode, cmd, arg); - case BLKDISCARD: - return blk_ioctl_discard(bdev, mode, arg, 0); - case BLKSECDISCARD: - return blk_ioctl_discard(bdev, mode, arg, - BLKDEV_DISCARD_SECURE); - case BLKZEROOUT: - return blk_ioctl_zeroout(bdev, mode, arg); - case HDIO_GETGEO: - return blkdev_getgeo(bdev, argp); - case BLKRAGET: - case BLKFRAGET: - if (!arg) - return -EINVAL; - bdi = blk_get_backing_dev_info(bdev); - return put_long(arg, (bdi->ra_pages * PAGE_SIZE) / 512); - case BLKROGET: - return put_int(arg, bdev_read_only(bdev) != 0); - case BLKBSZGET: /* get block device soft block size (cf. BLKSSZGET) */ - return put_int(arg, block_size(bdev)); - case BLKSSZGET: /* get block device logical block size */ - return put_int(arg, bdev_logical_block_size(bdev)); - case BLKPBSZGET: /* get block device physical block size */ - return put_uint(arg, bdev_physical_block_size(bdev)); - case BLKIOMIN: - return put_uint(arg, bdev_io_min(bdev)); - case BLKIOOPT: - return put_uint(arg, bdev_io_opt(bdev)); - case BLKALIGNOFF: - return put_int(arg, bdev_alignment_offset(bdev)); - case BLKDISCARDZEROES: - return put_uint(arg, bdev_discard_zeroes_data(bdev)); - case BLKSECTGET: - max_sectors = min_t(unsigned int, USHRT_MAX, - queue_max_sectors(bdev_get_queue(bdev))); - return put_ushort(arg, max_sectors); - case BLKROTATIONAL: - return put_ushort(arg, !blk_queue_nonrot(bdev_get_queue(bdev))); - case BLKRASET: - case BLKFRASET: - if(!capable(CAP_SYS_ADMIN)) - return -EACCES; - bdi = blk_get_backing_dev_info(bdev); - bdi->ra_pages = (arg * 512) / PAGE_SIZE; - return 0; - case BLKBSZSET: - return blkdev_bszset(bdev, mode, argp); - case BLKPG: - return blkpg_ioctl(bdev, argp); - case BLKRRPART: - return blkdev_reread_part(bdev); - case BLKGETSIZE: - size = i_size_read(bdev->bd_inode); - if ((size >> 9) > ~0UL) - return -EFBIG; - return put_ulong(arg, size >> 9); - case BLKGETSIZE64: - return put_u64(arg, i_size_read(bdev->bd_inode)); - case BLKTRACESTART: - case BLKTRACESTOP: - case BLKTRACESETUP: - case BLKTRACETEARDOWN: - return blk_trace_ioctl(bdev, cmd, argp); - case IOC_PR_REGISTER: - return blkdev_pr_register(bdev, argp); - case IOC_PR_RESERVE: - return blkdev_pr_reserve(bdev, argp); - case IOC_PR_RELEASE: - return blkdev_pr_release(bdev, argp); - case IOC_PR_PREEMPT: - return blkdev_pr_preempt(bdev, argp, false); - case IOC_PR_PREEMPT_ABORT: - return blkdev_pr_preempt(bdev, argp, true); - case IOC_PR_CLEAR: - return blkdev_pr_clear(bdev, argp); - default: - return __blkdev_driver_ioctl(bdev, mode, cmd, arg); - } -} -EXPORT_SYMBOL_GPL(blkdev_ioctl); diff --git a/src/linux/block/ioprio.c b/src/linux/block/ioprio.c deleted file mode 100644 index 01b8116..0000000 --- a/src/linux/block/ioprio.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * fs/ioprio.c - * - * Copyright (C) 2004 Jens Axboe - * - * Helper functions for setting/querying io priorities of processes. The - * system calls closely mimmick getpriority/setpriority, see the man page for - * those. The prio argument is a composite of prio class and prio data, where - * the data argument has meaning within that class. The standard scheduling - * classes have 8 distinct prio levels, with 0 being the highest prio and 7 - * being the lowest. - * - * IOW, setting BE scheduling class with prio 2 is done ala: - * - * unsigned int prio = (IOPRIO_CLASS_BE << IOPRIO_CLASS_SHIFT) | 2; - * - * ioprio_set(PRIO_PROCESS, pid, prio); - * - * See also Documentation/block/ioprio.txt - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int set_task_ioprio(struct task_struct *task, int ioprio) -{ - int err; - struct io_context *ioc; - const struct cred *cred = current_cred(), *tcred; - - rcu_read_lock(); - tcred = __task_cred(task); - if (!uid_eq(tcred->uid, cred->euid) && - !uid_eq(tcred->uid, cred->uid) && !capable(CAP_SYS_NICE)) { - rcu_read_unlock(); - return -EPERM; - } - rcu_read_unlock(); - - err = security_task_setioprio(task, ioprio); - if (err) - return err; - - ioc = get_task_io_context(task, GFP_ATOMIC, NUMA_NO_NODE); - if (ioc) { - ioc->ioprio = ioprio; - put_io_context(ioc); - } - - return err; -} -EXPORT_SYMBOL_GPL(set_task_ioprio); - -SYSCALL_DEFINE3(ioprio_set, int, which, int, who, int, ioprio) -{ - int class = IOPRIO_PRIO_CLASS(ioprio); - int data = IOPRIO_PRIO_DATA(ioprio); - struct task_struct *p, *g; - struct user_struct *user; - struct pid *pgrp; - kuid_t uid; - int ret; - - switch (class) { - case IOPRIO_CLASS_RT: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - /* fall through, rt has prio field too */ - case IOPRIO_CLASS_BE: - if (data >= IOPRIO_BE_NR || data < 0) - return -EINVAL; - - break; - case IOPRIO_CLASS_IDLE: - break; - case IOPRIO_CLASS_NONE: - if (data) - return -EINVAL; - break; - default: - return -EINVAL; - } - - ret = -ESRCH; - rcu_read_lock(); - switch (which) { - case IOPRIO_WHO_PROCESS: - if (!who) - p = current; - else - p = find_task_by_vpid(who); - if (p) - ret = set_task_ioprio(p, ioprio); - break; - case IOPRIO_WHO_PGRP: - if (!who) - pgrp = task_pgrp(current); - else - pgrp = find_vpid(who); - do_each_pid_thread(pgrp, PIDTYPE_PGID, p) { - ret = set_task_ioprio(p, ioprio); - if (ret) - break; - } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); - break; - case IOPRIO_WHO_USER: - uid = make_kuid(current_user_ns(), who); - if (!uid_valid(uid)) - break; - if (!who) - user = current_user(); - else - user = find_user(uid); - - if (!user) - break; - - do_each_thread(g, p) { - if (!uid_eq(task_uid(p), uid) || - !task_pid_vnr(p)) - continue; - ret = set_task_ioprio(p, ioprio); - if (ret) - goto free_uid; - } while_each_thread(g, p); -free_uid: - if (who) - free_uid(user); - break; - default: - ret = -EINVAL; - } - - rcu_read_unlock(); - return ret; -} - -static int get_task_ioprio(struct task_struct *p) -{ - int ret; - - ret = security_task_getioprio(p); - if (ret) - goto out; - ret = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_NONE, IOPRIO_NORM); - task_lock(p); - if (p->io_context) - ret = p->io_context->ioprio; - task_unlock(p); -out: - return ret; -} - -int ioprio_best(unsigned short aprio, unsigned short bprio) -{ - unsigned short aclass; - unsigned short bclass; - - if (!ioprio_valid(aprio)) - aprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, IOPRIO_NORM); - if (!ioprio_valid(bprio)) - bprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, IOPRIO_NORM); - - aclass = IOPRIO_PRIO_CLASS(aprio); - bclass = IOPRIO_PRIO_CLASS(bprio); - if (aclass == bclass) - return min(aprio, bprio); - if (aclass > bclass) - return bprio; - else - return aprio; -} - -SYSCALL_DEFINE2(ioprio_get, int, which, int, who) -{ - struct task_struct *g, *p; - struct user_struct *user; - struct pid *pgrp; - kuid_t uid; - int ret = -ESRCH; - int tmpio; - - rcu_read_lock(); - switch (which) { - case IOPRIO_WHO_PROCESS: - if (!who) - p = current; - else - p = find_task_by_vpid(who); - if (p) - ret = get_task_ioprio(p); - break; - case IOPRIO_WHO_PGRP: - if (!who) - pgrp = task_pgrp(current); - else - pgrp = find_vpid(who); - do_each_pid_thread(pgrp, PIDTYPE_PGID, p) { - tmpio = get_task_ioprio(p); - if (tmpio < 0) - continue; - if (ret == -ESRCH) - ret = tmpio; - else - ret = ioprio_best(ret, tmpio); - } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); - break; - case IOPRIO_WHO_USER: - uid = make_kuid(current_user_ns(), who); - if (!who) - user = current_user(); - else - user = find_user(uid); - - if (!user) - break; - - do_each_thread(g, p) { - if (!uid_eq(task_uid(p), user->uid) || - !task_pid_vnr(p)) - continue; - tmpio = get_task_ioprio(p); - if (tmpio < 0) - continue; - if (ret == -ESRCH) - ret = tmpio; - else - ret = ioprio_best(ret, tmpio); - } while_each_thread(g, p); - - if (who) - free_uid(user); - break; - default: - ret = -EINVAL; - } - - rcu_read_unlock(); - return ret; -} diff --git a/src/linux/block/noop-iosched.c b/src/linux/block/noop-iosched.c deleted file mode 100644 index a163c48..0000000 --- a/src/linux/block/noop-iosched.c +++ /dev/null @@ -1,124 +0,0 @@ -/* - * elevator noop - */ -#include -#include -#include -#include -#include -#include - -struct noop_data { - struct list_head queue; -}; - -static void noop_merged_requests(struct request_queue *q, struct request *rq, - struct request *next) -{ - list_del_init(&next->queuelist); -} - -static int noop_dispatch(struct request_queue *q, int force) -{ - struct noop_data *nd = q->elevator->elevator_data; - struct request *rq; - - rq = list_first_entry_or_null(&nd->queue, struct request, queuelist); - if (rq) { - list_del_init(&rq->queuelist); - elv_dispatch_sort(q, rq); - return 1; - } - return 0; -} - -static void noop_add_request(struct request_queue *q, struct request *rq) -{ - struct noop_data *nd = q->elevator->elevator_data; - - list_add_tail(&rq->queuelist, &nd->queue); -} - -static struct request * -noop_former_request(struct request_queue *q, struct request *rq) -{ - struct noop_data *nd = q->elevator->elevator_data; - - if (rq->queuelist.prev == &nd->queue) - return NULL; - return list_prev_entry(rq, queuelist); -} - -static struct request * -noop_latter_request(struct request_queue *q, struct request *rq) -{ - struct noop_data *nd = q->elevator->elevator_data; - - if (rq->queuelist.next == &nd->queue) - return NULL; - return list_next_entry(rq, queuelist); -} - -static int noop_init_queue(struct request_queue *q, struct elevator_type *e) -{ - struct noop_data *nd; - struct elevator_queue *eq; - - eq = elevator_alloc(q, e); - if (!eq) - return -ENOMEM; - - nd = kmalloc_node(sizeof(*nd), GFP_KERNEL, q->node); - if (!nd) { - kobject_put(&eq->kobj); - return -ENOMEM; - } - eq->elevator_data = nd; - - INIT_LIST_HEAD(&nd->queue); - - spin_lock_irq(q->queue_lock); - q->elevator = eq; - spin_unlock_irq(q->queue_lock); - return 0; -} - -static void noop_exit_queue(struct elevator_queue *e) -{ - struct noop_data *nd = e->elevator_data; - - BUG_ON(!list_empty(&nd->queue)); - kfree(nd); -} - -static struct elevator_type elevator_noop = { - .ops = { - .elevator_merge_req_fn = noop_merged_requests, - .elevator_dispatch_fn = noop_dispatch, - .elevator_add_req_fn = noop_add_request, - .elevator_former_req_fn = noop_former_request, - .elevator_latter_req_fn = noop_latter_request, - .elevator_init_fn = noop_init_queue, - .elevator_exit_fn = noop_exit_queue, - }, - .elevator_name = "noop", - .elevator_owner = THIS_MODULE, -}; - -static int __init noop_init(void) -{ - return elv_register(&elevator_noop); -} - -static void __exit noop_exit(void) -{ - elv_unregister(&elevator_noop); -} - -module_init(noop_init); -module_exit(noop_exit); - - -MODULE_AUTHOR("Jens Axboe"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("No-op IO scheduler"); diff --git a/src/linux/block/partition-generic.c b/src/linux/block/partition-generic.c deleted file mode 100644 index 71d9ed9..0000000 --- a/src/linux/block/partition-generic.c +++ /dev/null @@ -1,599 +0,0 @@ -/* - * Code extracted from drivers/block/genhd.c - * Copyright (C) 1991-1998 Linus Torvalds - * Re-organised Feb 1998 Russell King - * - * We now have independent partition support from the - * block drivers, which allows all the partition code to - * be grouped in one location, and it to be mostly self - * contained. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "partitions/check.h" - -#ifdef CONFIG_BLK_DEV_MD -extern void md_autodetect_dev(dev_t dev); -#endif - -/* - * disk_name() is used by partition check code and the genhd driver. - * It formats the devicename of the indicated disk into - * the supplied buffer (of size at least 32), and returns - * a pointer to that same buffer (for convenience). - */ - -char *disk_name(struct gendisk *hd, int partno, char *buf) -{ - if (!partno) - snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name); - else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1])) - snprintf(buf, BDEVNAME_SIZE, "%sp%d", hd->disk_name, partno); - else - snprintf(buf, BDEVNAME_SIZE, "%s%d", hd->disk_name, partno); - - return buf; -} - -const char *bdevname(struct block_device *bdev, char *buf) -{ - return disk_name(bdev->bd_disk, bdev->bd_part->partno, buf); -} - -EXPORT_SYMBOL(bdevname); - -/* - * There's very little reason to use this, you should really - * have a struct block_device just about everywhere and use - * bdevname() instead. - */ -const char *__bdevname(dev_t dev, char *buffer) -{ - scnprintf(buffer, BDEVNAME_SIZE, "unknown-block(%u,%u)", - MAJOR(dev), MINOR(dev)); - return buffer; -} - -EXPORT_SYMBOL(__bdevname); - -static ssize_t part_partition_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hd_struct *p = dev_to_part(dev); - - return sprintf(buf, "%d\n", p->partno); -} - -static ssize_t part_start_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hd_struct *p = dev_to_part(dev); - - return sprintf(buf, "%llu\n",(unsigned long long)p->start_sect); -} - -ssize_t part_size_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hd_struct *p = dev_to_part(dev); - return sprintf(buf, "%llu\n",(unsigned long long)part_nr_sects_read(p)); -} - -static ssize_t part_ro_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hd_struct *p = dev_to_part(dev); - return sprintf(buf, "%d\n", p->policy ? 1 : 0); -} - -static ssize_t part_alignment_offset_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hd_struct *p = dev_to_part(dev); - return sprintf(buf, "%llu\n", (unsigned long long)p->alignment_offset); -} - -static ssize_t part_discard_alignment_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hd_struct *p = dev_to_part(dev); - return sprintf(buf, "%u\n", p->discard_alignment); -} - -ssize_t part_stat_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hd_struct *p = dev_to_part(dev); - int cpu; - - cpu = part_stat_lock(); - part_round_stats(cpu, p); - part_stat_unlock(); - return sprintf(buf, - "%8lu %8lu %8llu %8u " - "%8lu %8lu %8llu %8u " - "%8u %8u %8u" - "\n", - part_stat_read(p, ios[READ]), - part_stat_read(p, merges[READ]), - (unsigned long long)part_stat_read(p, sectors[READ]), - jiffies_to_msecs(part_stat_read(p, ticks[READ])), - part_stat_read(p, ios[WRITE]), - part_stat_read(p, merges[WRITE]), - (unsigned long long)part_stat_read(p, sectors[WRITE]), - jiffies_to_msecs(part_stat_read(p, ticks[WRITE])), - part_in_flight(p), - jiffies_to_msecs(part_stat_read(p, io_ticks)), - jiffies_to_msecs(part_stat_read(p, time_in_queue))); -} - -ssize_t part_inflight_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hd_struct *p = dev_to_part(dev); - - return sprintf(buf, "%8u %8u\n", atomic_read(&p->in_flight[0]), - atomic_read(&p->in_flight[1])); -} - -#ifdef CONFIG_FAIL_MAKE_REQUEST -ssize_t part_fail_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct hd_struct *p = dev_to_part(dev); - - return sprintf(buf, "%d\n", p->make_it_fail); -} - -ssize_t part_fail_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct hd_struct *p = dev_to_part(dev); - int i; - - if (count > 0 && sscanf(buf, "%d", &i) > 0) - p->make_it_fail = (i == 0) ? 0 : 1; - - return count; -} -#endif - -static DEVICE_ATTR(partition, S_IRUGO, part_partition_show, NULL); -static DEVICE_ATTR(start, S_IRUGO, part_start_show, NULL); -static DEVICE_ATTR(size, S_IRUGO, part_size_show, NULL); -static DEVICE_ATTR(ro, S_IRUGO, part_ro_show, NULL); -static DEVICE_ATTR(alignment_offset, S_IRUGO, part_alignment_offset_show, NULL); -static DEVICE_ATTR(discard_alignment, S_IRUGO, part_discard_alignment_show, - NULL); -static DEVICE_ATTR(stat, S_IRUGO, part_stat_show, NULL); -static DEVICE_ATTR(inflight, S_IRUGO, part_inflight_show, NULL); -#ifdef CONFIG_FAIL_MAKE_REQUEST -static struct device_attribute dev_attr_fail = - __ATTR(make-it-fail, S_IRUGO|S_IWUSR, part_fail_show, part_fail_store); -#endif - -static struct attribute *part_attrs[] = { - &dev_attr_partition.attr, - &dev_attr_start.attr, - &dev_attr_size.attr, - &dev_attr_ro.attr, - &dev_attr_alignment_offset.attr, - &dev_attr_discard_alignment.attr, - &dev_attr_stat.attr, - &dev_attr_inflight.attr, -#ifdef CONFIG_FAIL_MAKE_REQUEST - &dev_attr_fail.attr, -#endif - NULL -}; - -static struct attribute_group part_attr_group = { - .attrs = part_attrs, -}; - -static const struct attribute_group *part_attr_groups[] = { - &part_attr_group, -#ifdef CONFIG_BLK_DEV_IO_TRACE - &blk_trace_attr_group, -#endif - NULL -}; - -static void part_release(struct device *dev) -{ - struct hd_struct *p = dev_to_part(dev); - blk_free_devt(dev->devt); - hd_free_part(p); - kfree(p); -} - -static int part_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct hd_struct *part = dev_to_part(dev); - - add_uevent_var(env, "PARTN=%u", part->partno); - if (part->info && part->info->volname[0]) - add_uevent_var(env, "PARTNAME=%s", part->info->volname); - return 0; -} - -struct device_type part_type = { - .name = "partition", - .groups = part_attr_groups, - .release = part_release, - .uevent = part_uevent, -}; - -static void delete_partition_rcu_cb(struct rcu_head *head) -{ - struct hd_struct *part = container_of(head, struct hd_struct, rcu_head); - - part->start_sect = 0; - part->nr_sects = 0; - part_stat_set_all(part, 0); - put_device(part_to_dev(part)); -} - -void __delete_partition(struct percpu_ref *ref) -{ - struct hd_struct *part = container_of(ref, struct hd_struct, ref); - call_rcu(&part->rcu_head, delete_partition_rcu_cb); -} - -void delete_partition(struct gendisk *disk, int partno) -{ - struct disk_part_tbl *ptbl = disk->part_tbl; - struct hd_struct *part; - - if (partno >= ptbl->len) - return; - - part = ptbl->part[partno]; - if (!part) - return; - - rcu_assign_pointer(ptbl->part[partno], NULL); - rcu_assign_pointer(ptbl->last_lookup, NULL); - kobject_put(part->holder_dir); - device_del(part_to_dev(part)); - - hd_struct_kill(part); -} - -static ssize_t whole_disk_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return 0; -} -static DEVICE_ATTR(whole_disk, S_IRUSR | S_IRGRP | S_IROTH, - whole_disk_show, NULL); - -struct hd_struct *add_partition(struct gendisk *disk, int partno, - sector_t start, sector_t len, int flags, - struct partition_meta_info *info) -{ - struct hd_struct *p; - dev_t devt = MKDEV(0, 0); - struct device *ddev = disk_to_dev(disk); - struct device *pdev; - struct disk_part_tbl *ptbl; - const char *dname; - int err; - - err = disk_expand_part_tbl(disk, partno); - if (err) - return ERR_PTR(err); - ptbl = disk->part_tbl; - - if (ptbl->part[partno]) - return ERR_PTR(-EBUSY); - - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) - return ERR_PTR(-EBUSY); - - if (!init_part_stats(p)) { - err = -ENOMEM; - goto out_free; - } - - seqcount_init(&p->nr_sects_seq); - pdev = part_to_dev(p); - - p->start_sect = start; - p->alignment_offset = - queue_limit_alignment_offset(&disk->queue->limits, start); - p->discard_alignment = - queue_limit_discard_alignment(&disk->queue->limits, start); - p->nr_sects = len; - p->partno = partno; - p->policy = get_disk_ro(disk); - - if (info) { - struct partition_meta_info *pinfo = alloc_part_info(disk); - if (!pinfo) - goto out_free_stats; - memcpy(pinfo, info, sizeof(*info)); - p->info = pinfo; - } - - dname = dev_name(ddev); - if (isdigit(dname[strlen(dname) - 1])) - dev_set_name(pdev, "%sp%d", dname, partno); - else - dev_set_name(pdev, "%s%d", dname, partno); - - device_initialize(pdev); - pdev->class = &block_class; - pdev->type = &part_type; - pdev->parent = ddev; - - err = blk_alloc_devt(p, &devt); - if (err) - goto out_free_info; - pdev->devt = devt; - - /* delay uevent until 'holders' subdir is created */ - dev_set_uevent_suppress(pdev, 1); - err = device_add(pdev); - if (err) - goto out_put; - - err = -ENOMEM; - p->holder_dir = kobject_create_and_add("holders", &pdev->kobj); - if (!p->holder_dir) - goto out_del; - - dev_set_uevent_suppress(pdev, 0); - if (flags & ADDPART_FLAG_WHOLEDISK) { - err = device_create_file(pdev, &dev_attr_whole_disk); - if (err) - goto out_del; - } - - err = hd_ref_init(p); - if (err) { - if (flags & ADDPART_FLAG_WHOLEDISK) - goto out_remove_file; - goto out_del; - } - - /* everything is up and running, commence */ - rcu_assign_pointer(ptbl->part[partno], p); - - /* suppress uevent if the disk suppresses it */ - if (!dev_get_uevent_suppress(ddev)) - kobject_uevent(&pdev->kobj, KOBJ_ADD); - return p; - -out_free_info: - free_part_info(p); -out_free_stats: - free_part_stats(p); -out_free: - kfree(p); - return ERR_PTR(err); -out_remove_file: - device_remove_file(pdev, &dev_attr_whole_disk); -out_del: - kobject_put(p->holder_dir); - device_del(pdev); -out_put: - put_device(pdev); - blk_free_devt(devt); - return ERR_PTR(err); -} - -static bool disk_unlock_native_capacity(struct gendisk *disk) -{ - const struct block_device_operations *bdops = disk->fops; - - if (bdops->unlock_native_capacity && - !(disk->flags & GENHD_FL_NATIVE_CAPACITY)) { - printk(KERN_CONT "enabling native capacity\n"); - bdops->unlock_native_capacity(disk); - disk->flags |= GENHD_FL_NATIVE_CAPACITY; - return true; - } else { - printk(KERN_CONT "truncated\n"); - return false; - } -} - -static int drop_partitions(struct gendisk *disk, struct block_device *bdev) -{ - struct disk_part_iter piter; - struct hd_struct *part; - int res; - - if (bdev->bd_part_count || bdev->bd_super) - return -EBUSY; - res = invalidate_partition(disk, 0); - if (res) - return res; - - disk_part_iter_init(&piter, disk, DISK_PITER_INCL_EMPTY); - while ((part = disk_part_iter_next(&piter))) - delete_partition(disk, part->partno); - disk_part_iter_exit(&piter); - - return 0; -} - -int rescan_partitions(struct gendisk *disk, struct block_device *bdev) -{ - struct parsed_partitions *state = NULL; - struct hd_struct *part; - int p, highest, res; -rescan: - if (state && !IS_ERR(state)) { - free_partitions(state); - state = NULL; - } - - res = drop_partitions(disk, bdev); - if (res) - return res; - - if (disk->fops->revalidate_disk) - disk->fops->revalidate_disk(disk); - blk_integrity_revalidate(disk); - check_disk_size_change(disk, bdev); - bdev->bd_invalidated = 0; - if (!get_capacity(disk) || !(state = check_partition(disk, bdev))) - return 0; - if (IS_ERR(state)) { - /* - * I/O error reading the partition table. If any - * partition code tried to read beyond EOD, retry - * after unlocking native capacity. - */ - if (PTR_ERR(state) == -ENOSPC) { - printk(KERN_WARNING "%s: partition table beyond EOD, ", - disk->disk_name); - if (disk_unlock_native_capacity(disk)) - goto rescan; - } - return -EIO; - } - /* - * If any partition code tried to read beyond EOD, try - * unlocking native capacity even if partition table is - * successfully read as we could be missing some partitions. - */ - if (state->access_beyond_eod) { - printk(KERN_WARNING - "%s: partition table partially beyond EOD, ", - disk->disk_name); - if (disk_unlock_native_capacity(disk)) - goto rescan; - } - - /* tell userspace that the media / partition table may have changed */ - kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE); - - /* Detect the highest partition number and preallocate - * disk->part_tbl. This is an optimization and not strictly - * necessary. - */ - for (p = 1, highest = 0; p < state->limit; p++) - if (state->parts[p].size) - highest = p; - - disk_expand_part_tbl(disk, highest); - - /* add partitions */ - for (p = 1; p < state->limit; p++) { - sector_t size, from; - - size = state->parts[p].size; - if (!size) - continue; - - from = state->parts[p].from; - if (from >= get_capacity(disk)) { - printk(KERN_WARNING - "%s: p%d start %llu is beyond EOD, ", - disk->disk_name, p, (unsigned long long) from); - if (disk_unlock_native_capacity(disk)) - goto rescan; - continue; - } - - if (from + size > get_capacity(disk)) { - printk(KERN_WARNING - "%s: p%d size %llu extends beyond EOD, ", - disk->disk_name, p, (unsigned long long) size); - - if (disk_unlock_native_capacity(disk)) { - /* free state and restart */ - goto rescan; - } else { - /* - * we can not ignore partitions of broken tables - * created by for example camera firmware, but - * we limit them to the end of the disk to avoid - * creating invalid block devices - */ - size = get_capacity(disk) - from; - } - } - - part = add_partition(disk, p, from, size, - state->parts[p].flags, - &state->parts[p].info); - if (IS_ERR(part)) { - printk(KERN_ERR " %s: p%d could not be added: %ld\n", - disk->disk_name, p, -PTR_ERR(part)); - continue; - } -#ifdef CONFIG_BLK_DEV_MD - if (state->parts[p].flags & ADDPART_FLAG_RAID) - md_autodetect_dev(part_to_dev(part)->devt); -#endif - } - free_partitions(state); - return 0; -} - -int invalidate_partitions(struct gendisk *disk, struct block_device *bdev) -{ - int res; - - if (!bdev->bd_invalidated) - return 0; - - res = drop_partitions(disk, bdev); - if (res) - return res; - - set_capacity(disk, 0); - check_disk_size_change(disk, bdev); - bdev->bd_invalidated = 0; - /* tell userspace that the media / partition table may have changed */ - kobject_uevent(&disk_to_dev(disk)->kobj, KOBJ_CHANGE); - - return 0; -} - -static struct page *read_pagecache_sector(struct block_device *bdev, sector_t n) -{ - struct address_space *mapping = bdev->bd_inode->i_mapping; - - return read_mapping_page(mapping, (pgoff_t)(n >> (PAGE_SHIFT-9)), - NULL); -} - -unsigned char *read_dev_sector(struct block_device *bdev, sector_t n, Sector *p) -{ - struct page *page; - - /* don't populate page cache for dax capable devices */ - if (IS_DAX(bdev->bd_inode)) - page = read_dax_sector(bdev, n); - else - page = read_pagecache_sector(bdev, n); - - if (!IS_ERR(page)) { - if (PageError(page)) - goto fail; - p->v = page; - return (unsigned char *)page_address(page) + ((n & ((1 << (PAGE_SHIFT - 9)) - 1)) << 9); -fail: - put_page(page); - } - p->v = NULL; - return NULL; -} - -EXPORT_SYMBOL(read_dev_sector); diff --git a/src/linux/block/partitions/Kconfig b/src/linux/block/partitions/Kconfig deleted file mode 100644 index 9b29a99..0000000 --- a/src/linux/block/partitions/Kconfig +++ /dev/null @@ -1,269 +0,0 @@ -# -# Partition configuration -# -config PARTITION_ADVANCED - bool "Advanced partition selection" - help - Say Y here if you would like to use hard disks under Linux which - were partitioned under an operating system running on a different - architecture than your Linux system. - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about foreign partitioning schemes. - - If unsure, say N. - -config ACORN_PARTITION - bool "Acorn partition support" if PARTITION_ADVANCED - default y if ARCH_ACORN - help - Support hard disks partitioned under Acorn operating systems. - -config ACORN_PARTITION_CUMANA - bool "Cumana partition support" if PARTITION_ADVANCED - default y if ARCH_ACORN - depends on ACORN_PARTITION - help - Say Y here if you would like to use hard disks under Linux which - were partitioned using the Cumana interface on Acorn machines. - -config ACORN_PARTITION_EESOX - bool "EESOX partition support" if PARTITION_ADVANCED - default y if ARCH_ACORN - depends on ACORN_PARTITION - -config ACORN_PARTITION_ICS - bool "ICS partition support" if PARTITION_ADVANCED - default y if ARCH_ACORN - depends on ACORN_PARTITION - help - Say Y here if you would like to use hard disks under Linux which - were partitioned using the ICS interface on Acorn machines. - -config ACORN_PARTITION_ADFS - bool "Native filecore partition support" if PARTITION_ADVANCED - default y if ARCH_ACORN - depends on ACORN_PARTITION - help - The Acorn Disc Filing System is the standard file system of the - RiscOS operating system which runs on Acorn's ARM-based Risc PC - systems and the Acorn Archimedes range of machines. If you say - `Y' here, Linux will support disk partitions created under ADFS. - -config ACORN_PARTITION_POWERTEC - bool "PowerTec partition support" if PARTITION_ADVANCED - default y if ARCH_ACORN - depends on ACORN_PARTITION - help - Support reading partition tables created on Acorn machines using - the PowerTec SCSI drive. - -config ACORN_PARTITION_RISCIX - bool "RISCiX partition support" if PARTITION_ADVANCED - default y if ARCH_ACORN - depends on ACORN_PARTITION - help - Once upon a time, there was a native Unix port for the Acorn series - of machines called RISCiX. If you say 'Y' here, Linux will be able - to read disks partitioned under RISCiX. - -config AIX_PARTITION - bool "AIX basic partition table support" if PARTITION_ADVANCED - help - Say Y here if you would like to be able to read the hard disk - partition table format used by IBM or Motorola PowerPC machines - running AIX. AIX actually uses a Logical Volume Manager, where - "logical volumes" can be spread across one or multiple disks, - but this driver works only for the simple case of partitions which - are contiguous. - Otherwise, say N. - -config OSF_PARTITION - bool "Alpha OSF partition support" if PARTITION_ADVANCED - default y if ALPHA - help - Say Y here if you would like to use hard disks under Linux which - were partitioned on an Alpha machine. - -config AMIGA_PARTITION - bool "Amiga partition table support" if PARTITION_ADVANCED - default y if (AMIGA || AFFS_FS=y) - help - Say Y here if you would like to use hard disks under Linux which - were partitioned under AmigaOS. - -config ATARI_PARTITION - bool "Atari partition table support" if PARTITION_ADVANCED - default y if ATARI - help - Say Y here if you would like to use hard disks under Linux which - were partitioned under the Atari OS. - -config IBM_PARTITION - bool "IBM disk label and partition support" - depends on PARTITION_ADVANCED && S390 - help - Say Y here if you would like to be able to read the hard disk - partition table format used by IBM DASD disks operating under CMS. - Otherwise, say N. - -config MAC_PARTITION - bool "Macintosh partition map support" if PARTITION_ADVANCED - default y if (MAC || PPC_PMAC) - help - Say Y here if you would like to use hard disks under Linux which - were partitioned on a Macintosh. - -config MSDOS_PARTITION - bool "PC BIOS (MSDOS partition tables) support" if PARTITION_ADVANCED - default y - help - Say Y here. - -config BSD_DISKLABEL - bool "BSD disklabel (FreeBSD partition tables) support" - depends on PARTITION_ADVANCED && MSDOS_PARTITION - help - FreeBSD uses its own hard disk partition scheme on your PC. It - requires only one entry in the primary partition table of your disk - and manages it similarly to DOS extended partitions, putting in its - first sector a new partition table in BSD disklabel format. Saying Y - here allows you to read these disklabels and further mount FreeBSD - partitions from within Linux if you have also said Y to "UFS - file system support", above. If you don't know what all this is - about, say N. - -config MINIX_SUBPARTITION - bool "Minix subpartition support" - depends on PARTITION_ADVANCED && MSDOS_PARTITION - help - Minix 2.0.0/2.0.2 subpartition table support for Linux. - Say Y here if you want to mount and use Minix 2.0.0/2.0.2 - subpartitions. - -config SOLARIS_X86_PARTITION - bool "Solaris (x86) partition table support" - depends on PARTITION_ADVANCED && MSDOS_PARTITION - help - Like most systems, Solaris x86 uses its own hard disk partition - table format, incompatible with all others. Saying Y here allows you - to read these partition tables and further mount Solaris x86 - partitions from within Linux if you have also said Y to "UFS - file system support", above. - -config UNIXWARE_DISKLABEL - bool "Unixware slices support" - depends on PARTITION_ADVANCED && MSDOS_PARTITION - ---help--- - Like some systems, UnixWare uses its own slice table inside a - partition (VTOC - Virtual Table of Contents). Its format is - incompatible with all other OSes. Saying Y here allows you to read - VTOC and further mount UnixWare partitions read-only from within - Linux if you have also said Y to "UFS file system support" or - "System V and Coherent file system support", above. - - This is mainly used to carry data from a UnixWare box to your - Linux box via a removable medium like magneto-optical, ZIP or - removable IDE drives. Note, however, that a good portable way to - transport files and directories between unixes (and even other - operating systems) is given by the tar program ("man tar" or - preferably "info tar"). - - If you don't know what all this is about, say N. - -config LDM_PARTITION - bool "Windows Logical Disk Manager (Dynamic Disk) support" - depends on PARTITION_ADVANCED - ---help--- - Say Y here if you would like to use hard disks under Linux which - were partitioned using Windows 2000's/XP's or Vista's Logical Disk - Manager. They are also known as "Dynamic Disks". - - Note this driver only supports Dynamic Disks with a protective MBR - label, i.e. DOS partition table. It does not support GPT labelled - Dynamic Disks yet as can be created with Vista. - - Windows 2000 introduced the concept of Dynamic Disks to get around - the limitations of the PC's partitioning scheme. The Logical Disk - Manager allows the user to repartition a disk and create spanned, - mirrored, striped or RAID volumes, all without the need for - rebooting. - - Normal partitions are now called Basic Disks under Windows 2000, XP, - and Vista. - - For a fuller description read . - - If unsure, say N. - -config LDM_DEBUG - bool "Windows LDM extra logging" - depends on LDM_PARTITION - help - Say Y here if you would like LDM to log verbosely. This could be - helpful if the driver doesn't work as expected and you'd like to - report a bug. - - If unsure, say N. - -config SGI_PARTITION - bool "SGI partition support" if PARTITION_ADVANCED - default y if DEFAULT_SGI_PARTITION - help - Say Y here if you would like to be able to read the hard disk - partition table format used by SGI machines. - -config ULTRIX_PARTITION - bool "Ultrix partition table support" if PARTITION_ADVANCED - default y if MACH_DECSTATION - help - Say Y here if you would like to be able to read the hard disk - partition table format used by DEC (now Compaq) Ultrix machines. - Otherwise, say N. - -config SUN_PARTITION - bool "Sun partition tables support" if PARTITION_ADVANCED - default y if (SPARC || SUN3 || SUN3X) - ---help--- - Like most systems, SunOS uses its own hard disk partition table - format, incompatible with all others. Saying Y here allows you to - read these partition tables and further mount SunOS partitions from - within Linux if you have also said Y to "UFS file system support", - above. This is mainly used to carry data from a SPARC under SunOS to - your Linux box via a removable medium like magneto-optical or ZIP - drives; note however that a good portable way to transport files and - directories between unixes (and even other operating systems) is - given by the tar program ("man tar" or preferably "info tar"). If - you don't know what all this is about, say N. - -config KARMA_PARTITION - bool "Karma Partition support" - depends on PARTITION_ADVANCED - help - Say Y here if you would like to mount the Rio Karma MP3 player, as it - uses a proprietary partition table. - -config EFI_PARTITION - bool "EFI GUID Partition support" if PARTITION_ADVANCED - default y - select CRC32 - help - Say Y here if you would like to use hard disks under Linux which - were partitioned using EFI GPT. - -config SYSV68_PARTITION - bool "SYSV68 partition table support" if PARTITION_ADVANCED - default y if VME - help - Say Y here if you would like to be able to read the hard disk - partition table format used by Motorola Delta machines (using - sysv68). - Otherwise, say N. - -config CMDLINE_PARTITION - bool "Command line partition support" if PARTITION_ADVANCED - select BLK_CMDLINE_PARSER - help - Say Y here if you want to read the partition table from bootargs. - The format for the command line is just like mtdparts. diff --git a/src/linux/block/partitions/Makefile b/src/linux/block/partitions/Makefile deleted file mode 100644 index 37a9527..0000000 --- a/src/linux/block/partitions/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# -# Makefile for the linux kernel. -# - -obj-$(CONFIG_BLOCK) := check.o - -obj-$(CONFIG_ACORN_PARTITION) += acorn.o -obj-$(CONFIG_AMIGA_PARTITION) += amiga.o -obj-$(CONFIG_ATARI_PARTITION) += atari.o -obj-$(CONFIG_AIX_PARTITION) += aix.o -obj-$(CONFIG_CMDLINE_PARTITION) += cmdline.o -obj-$(CONFIG_MAC_PARTITION) += mac.o -obj-$(CONFIG_LDM_PARTITION) += ldm.o -obj-$(CONFIG_MSDOS_PARTITION) += msdos.o -obj-$(CONFIG_OSF_PARTITION) += osf.o -obj-$(CONFIG_SGI_PARTITION) += sgi.o -obj-$(CONFIG_SUN_PARTITION) += sun.o -obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o -obj-$(CONFIG_IBM_PARTITION) += ibm.o -obj-$(CONFIG_EFI_PARTITION) += efi.o -obj-$(CONFIG_KARMA_PARTITION) += karma.o -obj-$(CONFIG_SYSV68_PARTITION) += sysv68.o diff --git a/src/linux/block/partitions/acorn.h b/src/linux/block/partitions/acorn.h deleted file mode 100644 index ede8285..0000000 --- a/src/linux/block/partitions/acorn.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * linux/fs/partitions/acorn.h - * - * Copyright (C) 1996-2001 Russell King. - * - * I _hate_ this partitioning mess - why can't we have one defined - * format, and everyone stick to it? - */ - -int adfspart_check_CUMANA(struct parsed_partitions *state); -int adfspart_check_ADFS(struct parsed_partitions *state); -int adfspart_check_ICS(struct parsed_partitions *state); -int adfspart_check_POWERTEC(struct parsed_partitions *state); -int adfspart_check_EESOX(struct parsed_partitions *state); diff --git a/src/linux/block/partitions/aix.h b/src/linux/block/partitions/aix.h deleted file mode 100644 index e0c66a9..0000000 --- a/src/linux/block/partitions/aix.h +++ /dev/null @@ -1 +0,0 @@ -extern int aix_partition(struct parsed_partitions *state); diff --git a/src/linux/block/partitions/amiga.h b/src/linux/block/partitions/amiga.h deleted file mode 100644 index d094585..0000000 --- a/src/linux/block/partitions/amiga.h +++ /dev/null @@ -1,6 +0,0 @@ -/* - * fs/partitions/amiga.h - */ - -int amiga_partition(struct parsed_partitions *state); - diff --git a/src/linux/block/partitions/atari.h b/src/linux/block/partitions/atari.h deleted file mode 100644 index f2ec43b..0000000 --- a/src/linux/block/partitions/atari.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * fs/partitions/atari.h - * Moved by Russell King from: - * - * linux/include/linux/atari_rootsec.h - * definitions for Atari Rootsector layout - * by Andreas Schwab (schwab@ls5.informatik.uni-dortmund.de) - * - * modified for ICD/Supra partitioning scheme restricted to at most 12 - * partitions - * by Guenther Kelleter (guenther@pool.informatik.rwth-aachen.de) - */ - -#include - -struct partition_info -{ - u8 flg; /* bit 0: active; bit 7: bootable */ - char id[3]; /* "GEM", "BGM", "XGM", or other */ - __be32 st; /* start of partition */ - __be32 siz; /* length of partition */ -}; - -struct rootsector -{ - char unused[0x156]; /* room for boot code */ - struct partition_info icdpart[8]; /* info for ICD-partitions 5..12 */ - char unused2[0xc]; - u32 hd_siz; /* size of disk in blocks */ - struct partition_info part[4]; - u32 bsl_st; /* start of bad sector list */ - u32 bsl_cnt; /* length of bad sector list */ - u16 checksum; /* checksum for bootable disks */ -} __packed; - -int atari_partition(struct parsed_partitions *state); diff --git a/src/linux/block/partitions/check.c b/src/linux/block/partitions/check.c deleted file mode 100644 index 16118d1..0000000 --- a/src/linux/block/partitions/check.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * fs/partitions/check.c - * - * Code extracted from drivers/block/genhd.c - * Copyright (C) 1991-1998 Linus Torvalds - * Re-organised Feb 1998 Russell King - * - * We now have independent partition support from the - * block drivers, which allows all the partition code to - * be grouped in one location, and it to be mostly self - * contained. - * - * Added needed MAJORS for new pairs, {hdi,hdj}, {hdk,hdl} - */ - -#include -#include -#include -#include - -#include "check.h" - -#include "acorn.h" -#include "amiga.h" -#include "atari.h" -#include "ldm.h" -#include "mac.h" -#include "msdos.h" -#include "osf.h" -#include "sgi.h" -#include "sun.h" -#include "ibm.h" -#include "ultrix.h" -#include "efi.h" -#include "karma.h" -#include "sysv68.h" -#include "cmdline.h" - -int warn_no_part = 1; /*This is ugly: should make genhd removable media aware*/ - -static int (*check_part[])(struct parsed_partitions *) = { - /* - * Probe partition formats with tables at disk address 0 - * that also have an ADFS boot block at 0xdc0. - */ -#ifdef CONFIG_ACORN_PARTITION_ICS - adfspart_check_ICS, -#endif -#ifdef CONFIG_ACORN_PARTITION_POWERTEC - adfspart_check_POWERTEC, -#endif -#ifdef CONFIG_ACORN_PARTITION_EESOX - adfspart_check_EESOX, -#endif - - /* - * Now move on to formats that only have partition info at - * disk address 0xdc0. Since these may also have stale - * PC/BIOS partition tables, they need to come before - * the msdos entry. - */ -#ifdef CONFIG_ACORN_PARTITION_CUMANA - adfspart_check_CUMANA, -#endif -#ifdef CONFIG_ACORN_PARTITION_ADFS - adfspart_check_ADFS, -#endif - -#ifdef CONFIG_CMDLINE_PARTITION - cmdline_partition, -#endif -#ifdef CONFIG_EFI_PARTITION - efi_partition, /* this must come before msdos */ -#endif -#ifdef CONFIG_SGI_PARTITION - sgi_partition, -#endif -#ifdef CONFIG_LDM_PARTITION - ldm_partition, /* this must come before msdos */ -#endif -#ifdef CONFIG_MSDOS_PARTITION - msdos_partition, -#endif -#ifdef CONFIG_OSF_PARTITION - osf_partition, -#endif -#ifdef CONFIG_SUN_PARTITION - sun_partition, -#endif -#ifdef CONFIG_AMIGA_PARTITION - amiga_partition, -#endif -#ifdef CONFIG_ATARI_PARTITION - atari_partition, -#endif -#ifdef CONFIG_MAC_PARTITION - mac_partition, -#endif -#ifdef CONFIG_ULTRIX_PARTITION - ultrix_partition, -#endif -#ifdef CONFIG_IBM_PARTITION - ibm_partition, -#endif -#ifdef CONFIG_KARMA_PARTITION - karma_partition, -#endif -#ifdef CONFIG_SYSV68_PARTITION - sysv68_partition, -#endif - NULL -}; - -static struct parsed_partitions *allocate_partitions(struct gendisk *hd) -{ - struct parsed_partitions *state; - int nr; - - state = kzalloc(sizeof(*state), GFP_KERNEL); - if (!state) - return NULL; - - nr = disk_max_parts(hd); - state->parts = vzalloc(nr * sizeof(state->parts[0])); - if (!state->parts) { - kfree(state); - return NULL; - } - - state->limit = nr; - - return state; -} - -void free_partitions(struct parsed_partitions *state) -{ - vfree(state->parts); - kfree(state); -} - -struct parsed_partitions * -check_partition(struct gendisk *hd, struct block_device *bdev) -{ - struct parsed_partitions *state; - int i, res, err; - - state = allocate_partitions(hd); - if (!state) - return NULL; - state->pp_buf = (char *)__get_free_page(GFP_KERNEL); - if (!state->pp_buf) { - free_partitions(state); - return NULL; - } - state->pp_buf[0] = '\0'; - - state->bdev = bdev; - disk_name(hd, 0, state->name); - snprintf(state->pp_buf, PAGE_SIZE, " %s:", state->name); - if (isdigit(state->name[strlen(state->name)-1])) - sprintf(state->name, "p"); - - i = res = err = 0; - while (!res && check_part[i]) { - memset(state->parts, 0, state->limit * sizeof(state->parts[0])); - res = check_part[i++](state); - if (res < 0) { - /* We have hit an I/O error which we don't report now. - * But record it, and let the others do their job. - */ - err = res; - res = 0; - } - - } - if (res > 0) { - printk(KERN_INFO "%s", state->pp_buf); - - free_page((unsigned long)state->pp_buf); - return state; - } - if (state->access_beyond_eod) - err = -ENOSPC; - if (err) - /* The partition is unrecognized. So report I/O errors if there were any */ - res = err; - if (res) { - if (warn_no_part) - strlcat(state->pp_buf, - " unable to read partition table\n", PAGE_SIZE); - printk(KERN_INFO "%s", state->pp_buf); - } - - free_page((unsigned long)state->pp_buf); - free_partitions(state); - return ERR_PTR(res); -} diff --git a/src/linux/block/partitions/check.h b/src/linux/block/partitions/check.h deleted file mode 100644 index eade17e..0000000 --- a/src/linux/block/partitions/check.h +++ /dev/null @@ -1,54 +0,0 @@ -#include -#include -#include - -/* - * add_gd_partition adds a partitions details to the devices partition - * description. - */ -struct parsed_partitions { - struct block_device *bdev; - char name[BDEVNAME_SIZE]; - struct { - sector_t from; - sector_t size; - int flags; - bool has_info; - struct partition_meta_info info; - } *parts; - int next; - int limit; - bool access_beyond_eod; - char *pp_buf; -}; - -void free_partitions(struct parsed_partitions *state); - -struct parsed_partitions * -check_partition(struct gendisk *, struct block_device *); - -static inline void *read_part_sector(struct parsed_partitions *state, - sector_t n, Sector *p) -{ - if (n >= get_capacity(state->bdev->bd_disk)) { - state->access_beyond_eod = true; - return NULL; - } - return read_dev_sector(state->bdev, n, p); -} - -static inline void -put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size) -{ - if (n < p->limit) { - char tmp[1 + BDEVNAME_SIZE + 10 + 1]; - - p->parts[n].from = from; - p->parts[n].size = size; - snprintf(tmp, sizeof(tmp), " %s%d", p->name, n); - strlcat(p->pp_buf, tmp, PAGE_SIZE); - } -} - -extern int warn_no_part; - diff --git a/src/linux/block/partitions/cmdline.h b/src/linux/block/partitions/cmdline.h deleted file mode 100644 index 26e0f8d..0000000 --- a/src/linux/block/partitions/cmdline.h +++ /dev/null @@ -1,2 +0,0 @@ - -int cmdline_partition(struct parsed_partitions *state); diff --git a/src/linux/block/partitions/efi.c b/src/linux/block/partitions/efi.c deleted file mode 100644 index bcd86e5..0000000 --- a/src/linux/block/partitions/efi.c +++ /dev/null @@ -1,737 +0,0 @@ -/************************************************************ - * EFI GUID Partition Table handling - * - * http://www.uefi.org/specs/ - * http://www.intel.com/technology/efi/ - * - * efi.[ch] by Matt Domsch - * Copyright 2000,2001,2002,2004 Dell Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * - * TODO: - * - * Changelog: - * Mon August 5th, 2013 Davidlohr Bueso - * - detect hybrid MBRs, tighter pMBR checking & cleanups. - * - * Mon Nov 09 2004 Matt Domsch - * - test for valid PMBR and valid PGPT before ever reading - * AGPT, allow override with 'gpt' kernel command line option. - * - check for first/last_usable_lba outside of size of disk - * - * Tue Mar 26 2002 Matt Domsch - * - Ported to 2.5.7-pre1 and 2.5.7-dj2 - * - Applied patch to avoid fault in alternate header handling - * - cleaned up find_valid_gpt - * - On-disk structure and copy in memory is *always* LE now - - * swab fields as needed - * - remove print_gpt_header() - * - only use first max_p partition entries, to keep the kernel minor number - * and partition numbers tied. - * - * Mon Feb 04 2002 Matt Domsch - * - Removed __PRIPTR_PREFIX - not being used - * - * Mon Jan 14 2002 Matt Domsch - * - Ported to 2.5.2-pre11 + library crc32 patch Linus applied - * - * Thu Dec 6 2001 Matt Domsch - * - Added compare_gpts(). - * - moved le_efi_guid_to_cpus() back into this file. GPT is the only - * thing that keeps EFI GUIDs on disk. - * - Changed gpt structure names and members to be simpler and more Linux-like. - * - * Wed Oct 17 2001 Matt Domsch - * - Removed CONFIG_DEVFS_VOLUMES_UUID code entirely per Martin Wilck - * - * Wed Oct 10 2001 Matt Domsch - * - Changed function comments to DocBook style per Andreas Dilger suggestion. - * - * Mon Oct 08 2001 Matt Domsch - * - Change read_lba() to use the page cache per Al Viro's work. - * - print u64s properly on all architectures - * - fixed debug_printk(), now Dprintk() - * - * Mon Oct 01 2001 Matt Domsch - * - Style cleanups - * - made most functions static - * - Endianness addition - * - remove test for second alternate header, as it's not per spec, - * and is unnecessary. There's now a method to read/write the last - * sector of an odd-sized disk from user space. No tools have ever - * been released which used this code, so it's effectively dead. - * - Per Asit Mallick of Intel, added a test for a valid PMBR. - * - Added kernel command line option 'gpt' to override valid PMBR test. - * - * Wed Jun 6 2001 Martin Wilck - * - added devfs volume UUID support (/dev/volumes/uuids) for - * mounting file systems by the partition GUID. - * - * Tue Dec 5 2000 Matt Domsch - * - Moved crc32() to linux/lib, added efi_crc32(). - * - * Thu Nov 30 2000 Matt Domsch - * - Replaced Intel's CRC32 function with an equivalent - * non-license-restricted version. - * - * Wed Oct 25 2000 Matt Domsch - * - Fixed the last_lba() call to return the proper last block - * - * Thu Oct 12 2000 Matt Domsch - * - Thanks to Andries Brouwer for his debugging assistance. - * - Code works, detects all the partitions. - * - ************************************************************/ -#include -#include -#include -#include -#include -#include "check.h" -#include "efi.h" - -/* This allows a kernel command line option 'gpt' to override - * the test for invalid PMBR. Not __initdata because reloading - * the partition tables happens after init too. - */ -static int force_gpt; -static int __init -force_gpt_fn(char *str) -{ - force_gpt = 1; - return 1; -} -__setup("gpt", force_gpt_fn); - - -/** - * efi_crc32() - EFI version of crc32 function - * @buf: buffer to calculate crc32 of - * @len: length of buf - * - * Description: Returns EFI-style CRC32 value for @buf - * - * This function uses the little endian Ethernet polynomial - * but seeds the function with ~0, and xor's with ~0 at the end. - * Note, the EFI Specification, v1.02, has a reference to - * Dr. Dobbs Journal, May 1994 (actually it's in May 1992). - */ -static inline u32 -efi_crc32(const void *buf, unsigned long len) -{ - return (crc32(~0L, buf, len) ^ ~0L); -} - -/** - * last_lba(): return number of last logical block of device - * @bdev: block device - * - * Description: Returns last LBA value on success, 0 on error. - * This is stored (by sd and ide-geometry) in - * the part[0] entry for this disk, and is the number of - * physical sectors available on the disk. - */ -static u64 last_lba(struct block_device *bdev) -{ - if (!bdev || !bdev->bd_inode) - return 0; - return div_u64(bdev->bd_inode->i_size, - bdev_logical_block_size(bdev)) - 1ULL; -} - -static inline int pmbr_part_valid(gpt_mbr_record *part) -{ - if (part->os_type != EFI_PMBR_OSTYPE_EFI_GPT) - goto invalid; - - /* set to 0x00000001 (i.e., the LBA of the GPT Partition Header) */ - if (le32_to_cpu(part->starting_lba) != GPT_PRIMARY_PARTITION_TABLE_LBA) - goto invalid; - - return GPT_MBR_PROTECTIVE; -invalid: - return 0; -} - -/** - * is_pmbr_valid(): test Protective MBR for validity - * @mbr: pointer to a legacy mbr structure - * @total_sectors: amount of sectors in the device - * - * Description: Checks for a valid protective or hybrid - * master boot record (MBR). The validity of a pMBR depends - * on all of the following properties: - * 1) MSDOS signature is in the last two bytes of the MBR - * 2) One partition of type 0xEE is found - * - * In addition, a hybrid MBR will have up to three additional - * primary partitions, which point to the same space that's - * marked out by up to three GPT partitions. - * - * Returns 0 upon invalid MBR, or GPT_MBR_PROTECTIVE or - * GPT_MBR_HYBRID depending on the device layout. - */ -static int is_pmbr_valid(legacy_mbr *mbr, sector_t total_sectors) -{ - uint32_t sz = 0; - int i, part = 0, ret = 0; /* invalid by default */ - - if (!mbr || le16_to_cpu(mbr->signature) != MSDOS_MBR_SIGNATURE) - goto done; - - for (i = 0; i < 4; i++) { - ret = pmbr_part_valid(&mbr->partition_record[i]); - if (ret == GPT_MBR_PROTECTIVE) { - part = i; - /* - * Ok, we at least know that there's a protective MBR, - * now check if there are other partition types for - * hybrid MBR. - */ - goto check_hybrid; - } - } - - if (ret != GPT_MBR_PROTECTIVE) - goto done; -check_hybrid: - for (i = 0; i < 4; i++) - if ((mbr->partition_record[i].os_type != - EFI_PMBR_OSTYPE_EFI_GPT) && - (mbr->partition_record[i].os_type != 0x00)) - ret = GPT_MBR_HYBRID; - - /* - * Protective MBRs take up the lesser of the whole disk - * or 2 TiB (32bit LBA), ignoring the rest of the disk. - * Some partitioning programs, nonetheless, choose to set - * the size to the maximum 32-bit limitation, disregarding - * the disk size. - * - * Hybrid MBRs do not necessarily comply with this. - * - * Consider a bad value here to be a warning to support dd'ing - * an image from a smaller disk to a larger disk. - */ - if (ret == GPT_MBR_PROTECTIVE) { - sz = le32_to_cpu(mbr->partition_record[part].size_in_lba); - if (sz != (uint32_t) total_sectors - 1 && sz != 0xFFFFFFFF) - pr_debug("GPT: mbr size in lba (%u) different than whole disk (%u).\n", - sz, min_t(uint32_t, - total_sectors - 1, 0xFFFFFFFF)); - } -done: - return ret; -} - -/** - * read_lba(): Read bytes from disk, starting at given LBA - * @state: disk parsed partitions - * @lba: the Logical Block Address of the partition table - * @buffer: destination buffer - * @count: bytes to read - * - * Description: Reads @count bytes from @state->bdev into @buffer. - * Returns number of bytes read on success, 0 on error. - */ -static size_t read_lba(struct parsed_partitions *state, - u64 lba, u8 *buffer, size_t count) -{ - size_t totalreadcount = 0; - struct block_device *bdev = state->bdev; - sector_t n = lba * (bdev_logical_block_size(bdev) / 512); - - if (!buffer || lba > last_lba(bdev)) - return 0; - - while (count) { - int copied = 512; - Sector sect; - unsigned char *data = read_part_sector(state, n++, §); - if (!data) - break; - if (copied > count) - copied = count; - memcpy(buffer, data, copied); - put_dev_sector(sect); - buffer += copied; - totalreadcount +=copied; - count -= copied; - } - return totalreadcount; -} - -/** - * alloc_read_gpt_entries(): reads partition entries from disk - * @state: disk parsed partitions - * @gpt: GPT header - * - * Description: Returns ptes on success, NULL on error. - * Allocates space for PTEs based on information found in @gpt. - * Notes: remember to free pte when you're done! - */ -static gpt_entry *alloc_read_gpt_entries(struct parsed_partitions *state, - gpt_header *gpt) -{ - size_t count; - gpt_entry *pte; - - if (!gpt) - return NULL; - - count = le32_to_cpu(gpt->num_partition_entries) * - le32_to_cpu(gpt->sizeof_partition_entry); - if (!count) - return NULL; - pte = kmalloc(count, GFP_KERNEL); - if (!pte) - return NULL; - - if (read_lba(state, le64_to_cpu(gpt->partition_entry_lba), - (u8 *) pte, count) < count) { - kfree(pte); - pte=NULL; - return NULL; - } - return pte; -} - -/** - * alloc_read_gpt_header(): Allocates GPT header, reads into it from disk - * @state: disk parsed partitions - * @lba: the Logical Block Address of the partition table - * - * Description: returns GPT header on success, NULL on error. Allocates - * and fills a GPT header starting at @ from @state->bdev. - * Note: remember to free gpt when finished with it. - */ -static gpt_header *alloc_read_gpt_header(struct parsed_partitions *state, - u64 lba) -{ - gpt_header *gpt; - unsigned ssz = bdev_logical_block_size(state->bdev); - - gpt = kmalloc(ssz, GFP_KERNEL); - if (!gpt) - return NULL; - - if (read_lba(state, lba, (u8 *) gpt, ssz) < ssz) { - kfree(gpt); - gpt=NULL; - return NULL; - } - - return gpt; -} - -/** - * is_gpt_valid() - tests one GPT header and PTEs for validity - * @state: disk parsed partitions - * @lba: logical block address of the GPT header to test - * @gpt: GPT header ptr, filled on return. - * @ptes: PTEs ptr, filled on return. - * - * Description: returns 1 if valid, 0 on error. - * If valid, returns pointers to newly allocated GPT header and PTEs. - */ -static int is_gpt_valid(struct parsed_partitions *state, u64 lba, - gpt_header **gpt, gpt_entry **ptes) -{ - u32 crc, origcrc; - u64 lastlba; - - if (!ptes) - return 0; - if (!(*gpt = alloc_read_gpt_header(state, lba))) - return 0; - - /* Check the GUID Partition Table signature */ - if (le64_to_cpu((*gpt)->signature) != GPT_HEADER_SIGNATURE) { - pr_debug("GUID Partition Table Header signature is wrong:" - "%lld != %lld\n", - (unsigned long long)le64_to_cpu((*gpt)->signature), - (unsigned long long)GPT_HEADER_SIGNATURE); - goto fail; - } - - /* Check the GUID Partition Table header size is too big */ - if (le32_to_cpu((*gpt)->header_size) > - bdev_logical_block_size(state->bdev)) { - pr_debug("GUID Partition Table Header size is too large: %u > %u\n", - le32_to_cpu((*gpt)->header_size), - bdev_logical_block_size(state->bdev)); - goto fail; - } - - /* Check the GUID Partition Table header size is too small */ - if (le32_to_cpu((*gpt)->header_size) < sizeof(gpt_header)) { - pr_debug("GUID Partition Table Header size is too small: %u < %zu\n", - le32_to_cpu((*gpt)->header_size), - sizeof(gpt_header)); - goto fail; - } - - /* Check the GUID Partition Table CRC */ - origcrc = le32_to_cpu((*gpt)->header_crc32); - (*gpt)->header_crc32 = 0; - crc = efi_crc32((const unsigned char *) (*gpt), le32_to_cpu((*gpt)->header_size)); - - if (crc != origcrc) { - pr_debug("GUID Partition Table Header CRC is wrong: %x != %x\n", - crc, origcrc); - goto fail; - } - (*gpt)->header_crc32 = cpu_to_le32(origcrc); - - /* Check that the my_lba entry points to the LBA that contains - * the GUID Partition Table */ - if (le64_to_cpu((*gpt)->my_lba) != lba) { - pr_debug("GPT my_lba incorrect: %lld != %lld\n", - (unsigned long long)le64_to_cpu((*gpt)->my_lba), - (unsigned long long)lba); - goto fail; - } - - /* Check the first_usable_lba and last_usable_lba are - * within the disk. - */ - lastlba = last_lba(state->bdev); - if (le64_to_cpu((*gpt)->first_usable_lba) > lastlba) { - pr_debug("GPT: first_usable_lba incorrect: %lld > %lld\n", - (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba), - (unsigned long long)lastlba); - goto fail; - } - if (le64_to_cpu((*gpt)->last_usable_lba) > lastlba) { - pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n", - (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba), - (unsigned long long)lastlba); - goto fail; - } - if (le64_to_cpu((*gpt)->last_usable_lba) < le64_to_cpu((*gpt)->first_usable_lba)) { - pr_debug("GPT: last_usable_lba incorrect: %lld > %lld\n", - (unsigned long long)le64_to_cpu((*gpt)->last_usable_lba), - (unsigned long long)le64_to_cpu((*gpt)->first_usable_lba)); - goto fail; - } - /* Check that sizeof_partition_entry has the correct value */ - if (le32_to_cpu((*gpt)->sizeof_partition_entry) != sizeof(gpt_entry)) { - pr_debug("GUID Partition Entry Size check failed.\n"); - goto fail; - } - - if (!(*ptes = alloc_read_gpt_entries(state, *gpt))) - goto fail; - - /* Check the GUID Partition Entry Array CRC */ - crc = efi_crc32((const unsigned char *) (*ptes), - le32_to_cpu((*gpt)->num_partition_entries) * - le32_to_cpu((*gpt)->sizeof_partition_entry)); - - if (crc != le32_to_cpu((*gpt)->partition_entry_array_crc32)) { - pr_debug("GUID Partition Entry Array CRC check failed.\n"); - goto fail_ptes; - } - - /* We're done, all's well */ - return 1; - - fail_ptes: - kfree(*ptes); - *ptes = NULL; - fail: - kfree(*gpt); - *gpt = NULL; - return 0; -} - -/** - * is_pte_valid() - tests one PTE for validity - * @pte:pte to check - * @lastlba: last lba of the disk - * - * Description: returns 1 if valid, 0 on error. - */ -static inline int -is_pte_valid(const gpt_entry *pte, const u64 lastlba) -{ - if ((!efi_guidcmp(pte->partition_type_guid, NULL_GUID)) || - le64_to_cpu(pte->starting_lba) > lastlba || - le64_to_cpu(pte->ending_lba) > lastlba) - return 0; - return 1; -} - -/** - * compare_gpts() - Search disk for valid GPT headers and PTEs - * @pgpt: primary GPT header - * @agpt: alternate GPT header - * @lastlba: last LBA number - * - * Description: Returns nothing. Sanity checks pgpt and agpt fields - * and prints warnings on discrepancies. - * - */ -static void -compare_gpts(gpt_header *pgpt, gpt_header *agpt, u64 lastlba) -{ - int error_found = 0; - if (!pgpt || !agpt) - return; - if (le64_to_cpu(pgpt->my_lba) != le64_to_cpu(agpt->alternate_lba)) { - pr_warn("GPT:Primary header LBA != Alt. header alternate_lba\n"); - pr_warn("GPT:%lld != %lld\n", - (unsigned long long)le64_to_cpu(pgpt->my_lba), - (unsigned long long)le64_to_cpu(agpt->alternate_lba)); - error_found++; - } - if (le64_to_cpu(pgpt->alternate_lba) != le64_to_cpu(agpt->my_lba)) { - pr_warn("GPT:Primary header alternate_lba != Alt. header my_lba\n"); - pr_warn("GPT:%lld != %lld\n", - (unsigned long long)le64_to_cpu(pgpt->alternate_lba), - (unsigned long long)le64_to_cpu(agpt->my_lba)); - error_found++; - } - if (le64_to_cpu(pgpt->first_usable_lba) != - le64_to_cpu(agpt->first_usable_lba)) { - pr_warn("GPT:first_usable_lbas don't match.\n"); - pr_warn("GPT:%lld != %lld\n", - (unsigned long long)le64_to_cpu(pgpt->first_usable_lba), - (unsigned long long)le64_to_cpu(agpt->first_usable_lba)); - error_found++; - } - if (le64_to_cpu(pgpt->last_usable_lba) != - le64_to_cpu(agpt->last_usable_lba)) { - pr_warn("GPT:last_usable_lbas don't match.\n"); - pr_warn("GPT:%lld != %lld\n", - (unsigned long long)le64_to_cpu(pgpt->last_usable_lba), - (unsigned long long)le64_to_cpu(agpt->last_usable_lba)); - error_found++; - } - if (efi_guidcmp(pgpt->disk_guid, agpt->disk_guid)) { - pr_warn("GPT:disk_guids don't match.\n"); - error_found++; - } - if (le32_to_cpu(pgpt->num_partition_entries) != - le32_to_cpu(agpt->num_partition_entries)) { - pr_warn("GPT:num_partition_entries don't match: " - "0x%x != 0x%x\n", - le32_to_cpu(pgpt->num_partition_entries), - le32_to_cpu(agpt->num_partition_entries)); - error_found++; - } - if (le32_to_cpu(pgpt->sizeof_partition_entry) != - le32_to_cpu(agpt->sizeof_partition_entry)) { - pr_warn("GPT:sizeof_partition_entry values don't match: " - "0x%x != 0x%x\n", - le32_to_cpu(pgpt->sizeof_partition_entry), - le32_to_cpu(agpt->sizeof_partition_entry)); - error_found++; - } - if (le32_to_cpu(pgpt->partition_entry_array_crc32) != - le32_to_cpu(agpt->partition_entry_array_crc32)) { - pr_warn("GPT:partition_entry_array_crc32 values don't match: " - "0x%x != 0x%x\n", - le32_to_cpu(pgpt->partition_entry_array_crc32), - le32_to_cpu(agpt->partition_entry_array_crc32)); - error_found++; - } - if (le64_to_cpu(pgpt->alternate_lba) != lastlba) { - pr_warn("GPT:Primary header thinks Alt. header is not at the end of the disk.\n"); - pr_warn("GPT:%lld != %lld\n", - (unsigned long long)le64_to_cpu(pgpt->alternate_lba), - (unsigned long long)lastlba); - error_found++; - } - - if (le64_to_cpu(agpt->my_lba) != lastlba) { - pr_warn("GPT:Alternate GPT header not at the end of the disk.\n"); - pr_warn("GPT:%lld != %lld\n", - (unsigned long long)le64_to_cpu(agpt->my_lba), - (unsigned long long)lastlba); - error_found++; - } - - if (error_found) - pr_warn("GPT: Use GNU Parted to correct GPT errors.\n"); - return; -} - -/** - * find_valid_gpt() - Search disk for valid GPT headers and PTEs - * @state: disk parsed partitions - * @gpt: GPT header ptr, filled on return. - * @ptes: PTEs ptr, filled on return. - * - * Description: Returns 1 if valid, 0 on error. - * If valid, returns pointers to newly allocated GPT header and PTEs. - * Validity depends on PMBR being valid (or being overridden by the - * 'gpt' kernel command line option) and finding either the Primary - * GPT header and PTEs valid, or the Alternate GPT header and PTEs - * valid. If the Primary GPT header is not valid, the Alternate GPT header - * is not checked unless the 'gpt' kernel command line option is passed. - * This protects against devices which misreport their size, and forces - * the user to decide to use the Alternate GPT. - */ -static int find_valid_gpt(struct parsed_partitions *state, gpt_header **gpt, - gpt_entry **ptes) -{ - int good_pgpt = 0, good_agpt = 0, good_pmbr = 0; - gpt_header *pgpt = NULL, *agpt = NULL; - gpt_entry *pptes = NULL, *aptes = NULL; - legacy_mbr *legacymbr; - sector_t total_sectors = i_size_read(state->bdev->bd_inode) >> 9; - u64 lastlba; - - if (!ptes) - return 0; - - lastlba = last_lba(state->bdev); - if (!force_gpt) { - /* This will be added to the EFI Spec. per Intel after v1.02. */ - legacymbr = kzalloc(sizeof(*legacymbr), GFP_KERNEL); - if (!legacymbr) - goto fail; - - read_lba(state, 0, (u8 *)legacymbr, sizeof(*legacymbr)); - good_pmbr = is_pmbr_valid(legacymbr, total_sectors); - kfree(legacymbr); - - if (!good_pmbr) - goto fail; - - pr_debug("Device has a %s MBR\n", - good_pmbr == GPT_MBR_PROTECTIVE ? - "protective" : "hybrid"); - } - - good_pgpt = is_gpt_valid(state, GPT_PRIMARY_PARTITION_TABLE_LBA, - &pgpt, &pptes); - if (good_pgpt) - good_agpt = is_gpt_valid(state, - le64_to_cpu(pgpt->alternate_lba), - &agpt, &aptes); - if (!good_agpt && force_gpt) - good_agpt = is_gpt_valid(state, lastlba, &agpt, &aptes); - - /* The obviously unsuccessful case */ - if (!good_pgpt && !good_agpt) - goto fail; - - compare_gpts(pgpt, agpt, lastlba); - - /* The good cases */ - if (good_pgpt) { - *gpt = pgpt; - *ptes = pptes; - kfree(agpt); - kfree(aptes); - if (!good_agpt) - pr_warn("Alternate GPT is invalid, using primary GPT.\n"); - return 1; - } - else if (good_agpt) { - *gpt = agpt; - *ptes = aptes; - kfree(pgpt); - kfree(pptes); - pr_warn("Primary GPT is invalid, using alternate GPT.\n"); - return 1; - } - - fail: - kfree(pgpt); - kfree(agpt); - kfree(pptes); - kfree(aptes); - *gpt = NULL; - *ptes = NULL; - return 0; -} - -/** - * efi_partition(struct parsed_partitions *state) - * @state: disk parsed partitions - * - * Description: called from check.c, if the disk contains GPT - * partitions, sets up partition entries in the kernel. - * - * If the first block on the disk is a legacy MBR, - * it will get handled by msdos_partition(). - * If it's a Protective MBR, we'll handle it here. - * - * We do not create a Linux partition for GPT, but - * only for the actual data partitions. - * Returns: - * -1 if unable to read the partition table - * 0 if this isn't our partition table - * 1 if successful - * - */ -int efi_partition(struct parsed_partitions *state) -{ - gpt_header *gpt = NULL; - gpt_entry *ptes = NULL; - u32 i; - unsigned ssz = bdev_logical_block_size(state->bdev) / 512; - - if (!find_valid_gpt(state, &gpt, &ptes) || !gpt || !ptes) { - kfree(gpt); - kfree(ptes); - return 0; - } - - pr_debug("GUID Partition Table is valid! Yea!\n"); - - for (i = 0; i < le32_to_cpu(gpt->num_partition_entries) && i < state->limit-1; i++) { - struct partition_meta_info *info; - unsigned label_count = 0; - unsigned label_max; - u64 start = le64_to_cpu(ptes[i].starting_lba); - u64 size = le64_to_cpu(ptes[i].ending_lba) - - le64_to_cpu(ptes[i].starting_lba) + 1ULL; - - if (!is_pte_valid(&ptes[i], last_lba(state->bdev))) - continue; - - put_partition(state, i+1, start * ssz, size * ssz); - - /* If this is a RAID volume, tell md */ - if (!efi_guidcmp(ptes[i].partition_type_guid, PARTITION_LINUX_RAID_GUID)) - state->parts[i + 1].flags = ADDPART_FLAG_RAID; - - info = &state->parts[i + 1].info; - efi_guid_to_str(&ptes[i].unique_partition_guid, info->uuid); - - /* Naively convert UTF16-LE to 7 bits. */ - label_max = min(ARRAY_SIZE(info->volname) - 1, - ARRAY_SIZE(ptes[i].partition_name)); - info->volname[label_max] = 0; - while (label_count < label_max) { - u8 c = ptes[i].partition_name[label_count] & 0xff; - if (c && !isprint(c)) - c = '!'; - info->volname[label_count] = c; - label_count++; - } - state->parts[i + 1].has_info = true; - } - kfree(ptes); - kfree(gpt); - strlcat(state->pp_buf, "\n", PAGE_SIZE); - return 1; -} diff --git a/src/linux/block/partitions/efi.h b/src/linux/block/partitions/efi.h deleted file mode 100644 index abd0b19..0000000 --- a/src/linux/block/partitions/efi.h +++ /dev/null @@ -1,133 +0,0 @@ -/************************************************************ - * EFI GUID Partition Table - * Per Intel EFI Specification v1.02 - * http://developer.intel.com/technology/efi/efi.htm - * - * By Matt Domsch Fri Sep 22 22:15:56 CDT 2000 - * Copyright 2000,2001 Dell Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - ************************************************************/ - -#ifndef FS_PART_EFI_H_INCLUDED -#define FS_PART_EFI_H_INCLUDED - -#include -#include -#include -#include -#include -#include -#include -#include - -#define MSDOS_MBR_SIGNATURE 0xaa55 -#define EFI_PMBR_OSTYPE_EFI 0xEF -#define EFI_PMBR_OSTYPE_EFI_GPT 0xEE - -#define GPT_MBR_PROTECTIVE 1 -#define GPT_MBR_HYBRID 2 - -#define GPT_HEADER_SIGNATURE 0x5452415020494645ULL -#define GPT_HEADER_REVISION_V1 0x00010000 -#define GPT_PRIMARY_PARTITION_TABLE_LBA 1 - -#define PARTITION_SYSTEM_GUID \ - EFI_GUID( 0xC12A7328, 0xF81F, 0x11d2, \ - 0xBA, 0x4B, 0x00, 0xA0, 0xC9, 0x3E, 0xC9, 0x3B) -#define LEGACY_MBR_PARTITION_GUID \ - EFI_GUID( 0x024DEE41, 0x33E7, 0x11d3, \ - 0x9D, 0x69, 0x00, 0x08, 0xC7, 0x81, 0xF3, 0x9F) -#define PARTITION_MSFT_RESERVED_GUID \ - EFI_GUID( 0xE3C9E316, 0x0B5C, 0x4DB8, \ - 0x81, 0x7D, 0xF9, 0x2D, 0xF0, 0x02, 0x15, 0xAE) -#define PARTITION_BASIC_DATA_GUID \ - EFI_GUID( 0xEBD0A0A2, 0xB9E5, 0x4433, \ - 0x87, 0xC0, 0x68, 0xB6, 0xB7, 0x26, 0x99, 0xC7) -#define PARTITION_LINUX_RAID_GUID \ - EFI_GUID( 0xa19d880f, 0x05fc, 0x4d3b, \ - 0xa0, 0x06, 0x74, 0x3f, 0x0f, 0x84, 0x91, 0x1e) -#define PARTITION_LINUX_SWAP_GUID \ - EFI_GUID( 0x0657fd6d, 0xa4ab, 0x43c4, \ - 0x84, 0xe5, 0x09, 0x33, 0xc8, 0x4b, 0x4f, 0x4f) -#define PARTITION_LINUX_LVM_GUID \ - EFI_GUID( 0xe6d6d379, 0xf507, 0x44c2, \ - 0xa2, 0x3c, 0x23, 0x8f, 0x2a, 0x3d, 0xf9, 0x28) - -typedef struct _gpt_header { - __le64 signature; - __le32 revision; - __le32 header_size; - __le32 header_crc32; - __le32 reserved1; - __le64 my_lba; - __le64 alternate_lba; - __le64 first_usable_lba; - __le64 last_usable_lba; - efi_guid_t disk_guid; - __le64 partition_entry_lba; - __le32 num_partition_entries; - __le32 sizeof_partition_entry; - __le32 partition_entry_array_crc32; - - /* The rest of the logical block is reserved by UEFI and must be zero. - * EFI standard handles this by: - * - * uint8_t reserved2[ BlockSize - 92 ]; - */ -} __packed gpt_header; - -typedef struct _gpt_entry_attributes { - u64 required_to_function:1; - u64 reserved:47; - u64 type_guid_specific:16; -} __packed gpt_entry_attributes; - -typedef struct _gpt_entry { - efi_guid_t partition_type_guid; - efi_guid_t unique_partition_guid; - __le64 starting_lba; - __le64 ending_lba; - gpt_entry_attributes attributes; - efi_char16_t partition_name[72 / sizeof (efi_char16_t)]; -} __packed gpt_entry; - -typedef struct _gpt_mbr_record { - u8 boot_indicator; /* unused by EFI, set to 0x80 for bootable */ - u8 start_head; /* unused by EFI, pt start in CHS */ - u8 start_sector; /* unused by EFI, pt start in CHS */ - u8 start_track; - u8 os_type; /* EFI and legacy non-EFI OS types */ - u8 end_head; /* unused by EFI, pt end in CHS */ - u8 end_sector; /* unused by EFI, pt end in CHS */ - u8 end_track; /* unused by EFI, pt end in CHS */ - __le32 starting_lba; /* used by EFI - start addr of the on disk pt */ - __le32 size_in_lba; /* used by EFI - size of pt in LBA */ -} __packed gpt_mbr_record; - - -typedef struct _legacy_mbr { - u8 boot_code[440]; - __le32 unique_mbr_signature; - __le16 unknown; - gpt_mbr_record partition_record[4]; - __le16 signature; -} __packed legacy_mbr; - -/* Functions */ -extern int efi_partition(struct parsed_partitions *state); - -#endif diff --git a/src/linux/block/partitions/ibm.h b/src/linux/block/partitions/ibm.h deleted file mode 100644 index 08fb080..0000000 --- a/src/linux/block/partitions/ibm.h +++ /dev/null @@ -1 +0,0 @@ -int ibm_partition(struct parsed_partitions *); diff --git a/src/linux/block/partitions/karma.h b/src/linux/block/partitions/karma.h deleted file mode 100644 index c764b2e..0000000 --- a/src/linux/block/partitions/karma.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * fs/partitions/karma.h - */ - -#define KARMA_LABEL_MAGIC 0xAB56 - -int karma_partition(struct parsed_partitions *state); - diff --git a/src/linux/block/partitions/ldm.h b/src/linux/block/partitions/ldm.h deleted file mode 100644 index 374242c..0000000 --- a/src/linux/block/partitions/ldm.h +++ /dev/null @@ -1,215 +0,0 @@ -/** - * ldm - Part of the Linux-NTFS project. - * - * Copyright (C) 2001,2002 Richard Russon - * Copyright (c) 2001-2007 Anton Altaparmakov - * Copyright (C) 2001,2002 Jakob Kemi - * - * Documentation is available at http://www.linux-ntfs.org/doku.php?id=downloads - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program (in the main directory of the Linux-NTFS source - * in the file COPYING); if not, write to the Free Software Foundation, - * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _FS_PT_LDM_H_ -#define _FS_PT_LDM_H_ - -#include -#include -#include -#include -#include -#include - -struct parsed_partitions; - -/* Magic numbers in CPU format. */ -#define MAGIC_VMDB 0x564D4442 /* VMDB */ -#define MAGIC_VBLK 0x56424C4B /* VBLK */ -#define MAGIC_PRIVHEAD 0x5052495648454144ULL /* PRIVHEAD */ -#define MAGIC_TOCBLOCK 0x544F43424C4F434BULL /* TOCBLOCK */ - -/* The defined vblk types. */ -#define VBLK_VOL5 0x51 /* Volume, version 5 */ -#define VBLK_CMP3 0x32 /* Component, version 3 */ -#define VBLK_PRT3 0x33 /* Partition, version 3 */ -#define VBLK_DSK3 0x34 /* Disk, version 3 */ -#define VBLK_DSK4 0x44 /* Disk, version 4 */ -#define VBLK_DGR3 0x35 /* Disk Group, version 3 */ -#define VBLK_DGR4 0x45 /* Disk Group, version 4 */ - -/* vblk flags indicating extra information will be present */ -#define VBLK_FLAG_COMP_STRIPE 0x10 -#define VBLK_FLAG_PART_INDEX 0x08 -#define VBLK_FLAG_DGR3_IDS 0x08 -#define VBLK_FLAG_DGR4_IDS 0x08 -#define VBLK_FLAG_VOLU_ID1 0x08 -#define VBLK_FLAG_VOLU_ID2 0x20 -#define VBLK_FLAG_VOLU_SIZE 0x80 -#define VBLK_FLAG_VOLU_DRIVE 0x02 - -/* size of a vblk's static parts */ -#define VBLK_SIZE_HEAD 16 -#define VBLK_SIZE_CMP3 22 /* Name and version */ -#define VBLK_SIZE_DGR3 12 -#define VBLK_SIZE_DGR4 44 -#define VBLK_SIZE_DSK3 12 -#define VBLK_SIZE_DSK4 45 -#define VBLK_SIZE_PRT3 28 -#define VBLK_SIZE_VOL5 58 - -/* component types */ -#define COMP_STRIPE 0x01 /* Stripe-set */ -#define COMP_BASIC 0x02 /* Basic disk */ -#define COMP_RAID 0x03 /* Raid-set */ - -/* Other constants. */ -#define LDM_DB_SIZE 2048 /* Size in sectors (= 1MiB). */ - -#define OFF_PRIV1 6 /* Offset of the first privhead - relative to the start of the - device in sectors */ - -/* Offsets to structures within the LDM Database in sectors. */ -#define OFF_PRIV2 1856 /* Backup private headers. */ -#define OFF_PRIV3 2047 - -#define OFF_TOCB1 1 /* Tables of contents. */ -#define OFF_TOCB2 2 -#define OFF_TOCB3 2045 -#define OFF_TOCB4 2046 - -#define OFF_VMDB 17 /* List of partitions. */ - -#define LDM_PARTITION 0x42 /* Formerly SFS (Landis). */ - -#define TOC_BITMAP1 "config" /* Names of the two defined */ -#define TOC_BITMAP2 "log" /* bitmaps in the TOCBLOCK. */ - -/* Borrowed from msdos.c */ -#define SYS_IND(p) (get_unaligned(&(p)->sys_ind)) - -struct frag { /* VBLK Fragment handling */ - struct list_head list; - u32 group; - u8 num; /* Total number of records */ - u8 rec; /* This is record number n */ - u8 map; /* Which portions are in use */ - u8 data[0]; -}; - -/* In memory LDM database structures. */ - -#define GUID_SIZE 16 - -struct privhead { /* Offsets and sizes are in sectors. */ - u16 ver_major; - u16 ver_minor; - u64 logical_disk_start; - u64 logical_disk_size; - u64 config_start; - u64 config_size; - u8 disk_id[GUID_SIZE]; -}; - -struct tocblock { /* We have exactly two bitmaps. */ - u8 bitmap1_name[16]; - u64 bitmap1_start; - u64 bitmap1_size; - u8 bitmap2_name[16]; - u64 bitmap2_start; - u64 bitmap2_size; -}; - -struct vmdb { /* VMDB: The database header */ - u16 ver_major; - u16 ver_minor; - u32 vblk_size; - u32 vblk_offset; - u32 last_vblk_seq; -}; - -struct vblk_comp { /* VBLK Component */ - u8 state[16]; - u64 parent_id; - u8 type; - u8 children; - u16 chunksize; -}; - -struct vblk_dgrp { /* VBLK Disk Group */ - u8 disk_id[64]; -}; - -struct vblk_disk { /* VBLK Disk */ - u8 disk_id[GUID_SIZE]; - u8 alt_name[128]; -}; - -struct vblk_part { /* VBLK Partition */ - u64 start; - u64 size; /* start, size and vol_off in sectors */ - u64 volume_offset; - u64 parent_id; - u64 disk_id; - u8 partnum; -}; - -struct vblk_volu { /* VBLK Volume */ - u8 volume_type[16]; - u8 volume_state[16]; - u8 guid[16]; - u8 drive_hint[4]; - u64 size; - u8 partition_type; -}; - -struct vblk_head { /* VBLK standard header */ - u32 group; - u16 rec; - u16 nrec; -}; - -struct vblk { /* Generalised VBLK */ - u8 name[64]; - u64 obj_id; - u32 sequence; - u8 flags; - u8 type; - union { - struct vblk_comp comp; - struct vblk_dgrp dgrp; - struct vblk_disk disk; - struct vblk_part part; - struct vblk_volu volu; - } vblk; - struct list_head list; -}; - -struct ldmdb { /* Cache of the database */ - struct privhead ph; - struct tocblock toc; - struct vmdb vm; - struct list_head v_dgrp; - struct list_head v_disk; - struct list_head v_volu; - struct list_head v_comp; - struct list_head v_part; -}; - -int ldm_partition(struct parsed_partitions *state); - -#endif /* _FS_PT_LDM_H_ */ - diff --git a/src/linux/block/partitions/mac.h b/src/linux/block/partitions/mac.h deleted file mode 100644 index 3c7d984..0000000 --- a/src/linux/block/partitions/mac.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * fs/partitions/mac.h - */ - -#define MAC_PARTITION_MAGIC 0x504d - -/* type field value for A/UX or other Unix partitions */ -#define APPLE_AUX_TYPE "Apple_UNIX_SVR2" - -struct mac_partition { - __be16 signature; /* expected to be MAC_PARTITION_MAGIC */ - __be16 res1; - __be32 map_count; /* # blocks in partition map */ - __be32 start_block; /* absolute starting block # of partition */ - __be32 block_count; /* number of blocks in partition */ - char name[32]; /* partition name */ - char type[32]; /* string type description */ - __be32 data_start; /* rel block # of first data block */ - __be32 data_count; /* number of data blocks */ - __be32 status; /* partition status bits */ - __be32 boot_start; - __be32 boot_size; - __be32 boot_load; - __be32 boot_load2; - __be32 boot_entry; - __be32 boot_entry2; - __be32 boot_cksum; - char processor[16]; /* identifies ISA of boot */ - /* there is more stuff after this that we don't need */ -}; - -#define MAC_STATUS_BOOTABLE 8 /* partition is bootable */ - -#define MAC_DRIVER_MAGIC 0x4552 - -/* Driver descriptor structure, in block 0 */ -struct mac_driver_desc { - __be16 signature; /* expected to be MAC_DRIVER_MAGIC */ - __be16 block_size; - __be32 block_count; - /* ... more stuff */ -}; - -int mac_partition(struct parsed_partitions *state); diff --git a/src/linux/block/partitions/msdos.c b/src/linux/block/partitions/msdos.c deleted file mode 100644 index 93e7c1b..0000000 --- a/src/linux/block/partitions/msdos.c +++ /dev/null @@ -1,582 +0,0 @@ -/* - * fs/partitions/msdos.c - * - * Code extracted from drivers/block/genhd.c - * Copyright (C) 1991-1998 Linus Torvalds - * - * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug - * in the early extended-partition checks and added DM partitions - * - * Support for DiskManager v6.0x added by Mark Lord, - * with information provided by OnTrack. This now works for linux fdisk - * and LILO, as well as loadlin and bootln. Note that disks other than - * /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1). - * - * More flexible handling of extended partitions - aeb, 950831 - * - * Check partition table on IDE disks for common CHS translations - * - * Re-organised Feb 1998 Russell King - */ -#include - -#include "check.h" -#include "msdos.h" -#include "efi.h" -#include "aix.h" - -/* - * Many architectures don't like unaligned accesses, while - * the nr_sects and start_sect partition table entries are - * at a 2 (mod 4) address. - */ -#include - -#define SYS_IND(p) get_unaligned(&p->sys_ind) - -static inline sector_t nr_sects(struct partition *p) -{ - return (sector_t)get_unaligned_le32(&p->nr_sects); -} - -static inline sector_t start_sect(struct partition *p) -{ - return (sector_t)get_unaligned_le32(&p->start_sect); -} - -static inline int is_extended_partition(struct partition *p) -{ - return (SYS_IND(p) == DOS_EXTENDED_PARTITION || - SYS_IND(p) == WIN98_EXTENDED_PARTITION || - SYS_IND(p) == LINUX_EXTENDED_PARTITION); -} - -#define MSDOS_LABEL_MAGIC1 0x55 -#define MSDOS_LABEL_MAGIC2 0xAA - -static inline int -msdos_magic_present(unsigned char *p) -{ - return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2); -} - -/* Value is EBCDIC 'IBMA' */ -#define AIX_LABEL_MAGIC1 0xC9 -#define AIX_LABEL_MAGIC2 0xC2 -#define AIX_LABEL_MAGIC3 0xD4 -#define AIX_LABEL_MAGIC4 0xC1 -static int aix_magic_present(struct parsed_partitions *state, unsigned char *p) -{ - struct partition *pt = (struct partition *) (p + 0x1be); - Sector sect; - unsigned char *d; - int slot, ret = 0; - - if (!(p[0] == AIX_LABEL_MAGIC1 && - p[1] == AIX_LABEL_MAGIC2 && - p[2] == AIX_LABEL_MAGIC3 && - p[3] == AIX_LABEL_MAGIC4)) - return 0; - /* Assume the partition table is valid if Linux partitions exists */ - for (slot = 1; slot <= 4; slot++, pt++) { - if (pt->sys_ind == LINUX_SWAP_PARTITION || - pt->sys_ind == LINUX_RAID_PARTITION || - pt->sys_ind == LINUX_DATA_PARTITION || - pt->sys_ind == LINUX_LVM_PARTITION || - is_extended_partition(pt)) - return 0; - } - d = read_part_sector(state, 7, §); - if (d) { - if (d[0] == '_' && d[1] == 'L' && d[2] == 'V' && d[3] == 'M') - ret = 1; - put_dev_sector(sect); - } - return ret; -} - -static void set_info(struct parsed_partitions *state, int slot, - u32 disksig) -{ - struct partition_meta_info *info = &state->parts[slot].info; - - snprintf(info->uuid, sizeof(info->uuid), "%08x-%02x", disksig, - slot); - info->volname[0] = 0; - state->parts[slot].has_info = true; -} - -/* - * Create devices for each logical partition in an extended partition. - * The logical partitions form a linked list, with each entry being - * a partition table with two entries. The first entry - * is the real data partition (with a start relative to the partition - * table start). The second is a pointer to the next logical partition - * (with a start relative to the entire extended partition). - * We do not create a Linux partition for the partition tables, but - * only for the actual data partitions. - */ - -static void parse_extended(struct parsed_partitions *state, - sector_t first_sector, sector_t first_size, - u32 disksig) -{ - struct partition *p; - Sector sect; - unsigned char *data; - sector_t this_sector, this_size; - sector_t sector_size = bdev_logical_block_size(state->bdev) / 512; - int loopct = 0; /* number of links followed - without finding a data partition */ - int i; - - this_sector = first_sector; - this_size = first_size; - - while (1) { - if (++loopct > 100) - return; - if (state->next == state->limit) - return; - data = read_part_sector(state, this_sector, §); - if (!data) - return; - - if (!msdos_magic_present(data + 510)) - goto done; - - p = (struct partition *) (data + 0x1be); - - /* - * Usually, the first entry is the real data partition, - * the 2nd entry is the next extended partition, or empty, - * and the 3rd and 4th entries are unused. - * However, DRDOS sometimes has the extended partition as - * the first entry (when the data partition is empty), - * and OS/2 seems to use all four entries. - */ - - /* - * First process the data partition(s) - */ - for (i = 0; i < 4; i++, p++) { - sector_t offs, size, next; - - if (!nr_sects(p) || is_extended_partition(p)) - continue; - - /* Check the 3rd and 4th entries - - these sometimes contain random garbage */ - offs = start_sect(p)*sector_size; - size = nr_sects(p)*sector_size; - next = this_sector + offs; - if (i >= 2) { - if (offs + size > this_size) - continue; - if (next < first_sector) - continue; - if (next + size > first_sector + first_size) - continue; - } - - put_partition(state, state->next, next, size); - set_info(state, state->next, disksig); - if (SYS_IND(p) == LINUX_RAID_PARTITION) - state->parts[state->next].flags = ADDPART_FLAG_RAID; - loopct = 0; - if (++state->next == state->limit) - goto done; - } - /* - * Next, process the (first) extended partition, if present. - * (So far, there seems to be no reason to make - * parse_extended() recursive and allow a tree - * of extended partitions.) - * It should be a link to the next logical partition. - */ - p -= 4; - for (i = 0; i < 4; i++, p++) - if (nr_sects(p) && is_extended_partition(p)) - break; - if (i == 4) - goto done; /* nothing left to do */ - - this_sector = first_sector + start_sect(p) * sector_size; - this_size = nr_sects(p) * sector_size; - put_dev_sector(sect); - } -done: - put_dev_sector(sect); -} - -/* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also - indicates linux swap. Be careful before believing this is Solaris. */ - -static void parse_solaris_x86(struct parsed_partitions *state, - sector_t offset, sector_t size, int origin) -{ -#ifdef CONFIG_SOLARIS_X86_PARTITION - Sector sect; - struct solaris_x86_vtoc *v; - int i; - short max_nparts; - - v = read_part_sector(state, offset + 1, §); - if (!v) - return; - if (le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) { - put_dev_sector(sect); - return; - } - { - char tmp[1 + BDEVNAME_SIZE + 10 + 11 + 1]; - - snprintf(tmp, sizeof(tmp), " %s%d: name, origin); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - } - if (le32_to_cpu(v->v_version) != 1) { - char tmp[64]; - - snprintf(tmp, sizeof(tmp), " cannot handle version %d vtoc>\n", - le32_to_cpu(v->v_version)); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - put_dev_sector(sect); - return; - } - /* Ensure we can handle previous case of VTOC with 8 entries gracefully */ - max_nparts = le16_to_cpu(v->v_nparts) > 8 ? SOLARIS_X86_NUMSLICE : 8; - for (i = 0; i < max_nparts && state->next < state->limit; i++) { - struct solaris_x86_slice *s = &v->v_slice[i]; - char tmp[3 + 10 + 1 + 1]; - - if (s->s_size == 0) - continue; - snprintf(tmp, sizeof(tmp), " [s%d]", i); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - /* solaris partitions are relative to current MS-DOS - * one; must add the offset of the current partition */ - put_partition(state, state->next++, - le32_to_cpu(s->s_start)+offset, - le32_to_cpu(s->s_size)); - } - put_dev_sector(sect); - strlcat(state->pp_buf, " >\n", PAGE_SIZE); -#endif -} - -#if defined(CONFIG_BSD_DISKLABEL) -/* - * Create devices for BSD partitions listed in a disklabel, under a - * dos-like partition. See parse_extended() for more information. - */ -static void parse_bsd(struct parsed_partitions *state, - sector_t offset, sector_t size, int origin, char *flavour, - int max_partitions) -{ - Sector sect; - struct bsd_disklabel *l; - struct bsd_partition *p; - char tmp[64]; - - l = read_part_sector(state, offset + 1, §); - if (!l) - return; - if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) { - put_dev_sector(sect); - return; - } - - snprintf(tmp, sizeof(tmp), " %s%d: <%s:", state->name, origin, flavour); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - - if (le16_to_cpu(l->d_npartitions) < max_partitions) - max_partitions = le16_to_cpu(l->d_npartitions); - for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) { - sector_t bsd_start, bsd_size; - - if (state->next == state->limit) - break; - if (p->p_fstype == BSD_FS_UNUSED) - continue; - bsd_start = le32_to_cpu(p->p_offset); - bsd_size = le32_to_cpu(p->p_size); - if (offset == bsd_start && size == bsd_size) - /* full parent partition, we have it already */ - continue; - if (offset > bsd_start || offset+size < bsd_start+bsd_size) { - strlcat(state->pp_buf, "bad subpartition - ignored\n", PAGE_SIZE); - continue; - } - put_partition(state, state->next++, bsd_start, bsd_size); - } - put_dev_sector(sect); - if (le16_to_cpu(l->d_npartitions) > max_partitions) { - snprintf(tmp, sizeof(tmp), " (ignored %d more)", - le16_to_cpu(l->d_npartitions) - max_partitions); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - } - strlcat(state->pp_buf, " >\n", PAGE_SIZE); -} -#endif - -static void parse_freebsd(struct parsed_partitions *state, - sector_t offset, sector_t size, int origin) -{ -#ifdef CONFIG_BSD_DISKLABEL - parse_bsd(state, offset, size, origin, "bsd", BSD_MAXPARTITIONS); -#endif -} - -static void parse_netbsd(struct parsed_partitions *state, - sector_t offset, sector_t size, int origin) -{ -#ifdef CONFIG_BSD_DISKLABEL - parse_bsd(state, offset, size, origin, "netbsd", BSD_MAXPARTITIONS); -#endif -} - -static void parse_openbsd(struct parsed_partitions *state, - sector_t offset, sector_t size, int origin) -{ -#ifdef CONFIG_BSD_DISKLABEL - parse_bsd(state, offset, size, origin, "openbsd", - OPENBSD_MAXPARTITIONS); -#endif -} - -/* - * Create devices for Unixware partitions listed in a disklabel, under a - * dos-like partition. See parse_extended() for more information. - */ -static void parse_unixware(struct parsed_partitions *state, - sector_t offset, sector_t size, int origin) -{ -#ifdef CONFIG_UNIXWARE_DISKLABEL - Sector sect; - struct unixware_disklabel *l; - struct unixware_slice *p; - - l = read_part_sector(state, offset + 29, §); - if (!l) - return; - if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC || - le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) { - put_dev_sector(sect); - return; - } - { - char tmp[1 + BDEVNAME_SIZE + 10 + 12 + 1]; - - snprintf(tmp, sizeof(tmp), " %s%d: name, origin); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - } - p = &l->vtoc.v_slice[1]; - /* I omit the 0th slice as it is the same as whole disk. */ - while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) { - if (state->next == state->limit) - break; - - if (p->s_label != UNIXWARE_FS_UNUSED) - put_partition(state, state->next++, - le32_to_cpu(p->start_sect), - le32_to_cpu(p->nr_sects)); - p++; - } - put_dev_sector(sect); - strlcat(state->pp_buf, " >\n", PAGE_SIZE); -#endif -} - -/* - * Minix 2.0.0/2.0.2 subpartition support. - * Anand Krishnamurthy - * Rajeev V. Pillai - */ -static void parse_minix(struct parsed_partitions *state, - sector_t offset, sector_t size, int origin) -{ -#ifdef CONFIG_MINIX_SUBPARTITION - Sector sect; - unsigned char *data; - struct partition *p; - int i; - - data = read_part_sector(state, offset, §); - if (!data) - return; - - p = (struct partition *)(data + 0x1be); - - /* The first sector of a Minix partition can have either - * a secondary MBR describing its subpartitions, or - * the normal boot sector. */ - if (msdos_magic_present(data + 510) && - SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */ - char tmp[1 + BDEVNAME_SIZE + 10 + 9 + 1]; - - snprintf(tmp, sizeof(tmp), " %s%d: name, origin); - strlcat(state->pp_buf, tmp, PAGE_SIZE); - for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) { - if (state->next == state->limit) - break; - /* add each partition in use */ - if (SYS_IND(p) == MINIX_PARTITION) - put_partition(state, state->next++, - start_sect(p), nr_sects(p)); - } - strlcat(state->pp_buf, " >\n", PAGE_SIZE); - } - put_dev_sector(sect); -#endif /* CONFIG_MINIX_SUBPARTITION */ -} - -static struct { - unsigned char id; - void (*parse)(struct parsed_partitions *, sector_t, sector_t, int); -} subtypes[] = { - {FREEBSD_PARTITION, parse_freebsd}, - {NETBSD_PARTITION, parse_netbsd}, - {OPENBSD_PARTITION, parse_openbsd}, - {MINIX_PARTITION, parse_minix}, - {UNIXWARE_PARTITION, parse_unixware}, - {SOLARIS_X86_PARTITION, parse_solaris_x86}, - {NEW_SOLARIS_X86_PARTITION, parse_solaris_x86}, - {0, NULL}, -}; - -int msdos_partition(struct parsed_partitions *state) -{ - sector_t sector_size = bdev_logical_block_size(state->bdev) / 512; - Sector sect; - unsigned char *data; - struct partition *p; - struct fat_boot_sector *fb; - int slot; - u32 disksig; - - data = read_part_sector(state, 0, §); - if (!data) - return -1; - - /* - * Note order! (some AIX disks, e.g. unbootable kind, - * have no MSDOS 55aa) - */ - if (aix_magic_present(state, data)) { - put_dev_sector(sect); -#ifdef CONFIG_AIX_PARTITION - return aix_partition(state); -#else - strlcat(state->pp_buf, " [AIX]", PAGE_SIZE); - return 0; -#endif - } - - if (!msdos_magic_present(data + 510)) { - put_dev_sector(sect); - return 0; - } - - /* - * Now that the 55aa signature is present, this is probably - * either the boot sector of a FAT filesystem or a DOS-type - * partition table. Reject this in case the boot indicator - * is not 0 or 0x80. - */ - p = (struct partition *) (data + 0x1be); - for (slot = 1; slot <= 4; slot++, p++) { - if (p->boot_ind != 0 && p->boot_ind != 0x80) { - /* - * Even without a valid boot inidicator value - * its still possible this is valid FAT filesystem - * without a partition table. - */ - fb = (struct fat_boot_sector *) data; - if (slot == 1 && fb->reserved && fb->fats - && fat_valid_media(fb->media)) { - strlcat(state->pp_buf, "\n", PAGE_SIZE); - put_dev_sector(sect); - return 1; - } else { - put_dev_sector(sect); - return 0; - } - } - } - -#ifdef CONFIG_EFI_PARTITION - p = (struct partition *) (data + 0x1be); - for (slot = 1 ; slot <= 4 ; slot++, p++) { - /* If this is an EFI GPT disk, msdos should ignore it. */ - if (SYS_IND(p) == EFI_PMBR_OSTYPE_EFI_GPT) { - put_dev_sector(sect); - return 0; - } - } -#endif - p = (struct partition *) (data + 0x1be); - - disksig = le32_to_cpup((__le32 *)(data + 0x1b8)); - - /* - * Look for partitions in two passes: - * First find the primary and DOS-type extended partitions. - * On the second pass look inside *BSD, Unixware and Solaris partitions. - */ - - state->next = 5; - for (slot = 1 ; slot <= 4 ; slot++, p++) { - sector_t start = start_sect(p)*sector_size; - sector_t size = nr_sects(p)*sector_size; - - if (!size) - continue; - if (is_extended_partition(p)) { - /* - * prevent someone doing mkfs or mkswap on an - * extended partition, but leave room for LILO - * FIXME: this uses one logical sector for > 512b - * sector, although it may not be enough/proper. - */ - sector_t n = 2; - - n = min(size, max(sector_size, n)); - put_partition(state, slot, start, n); - - strlcat(state->pp_buf, " <", PAGE_SIZE); - parse_extended(state, start, size, disksig); - strlcat(state->pp_buf, " >", PAGE_SIZE); - continue; - } - put_partition(state, slot, start, size); - set_info(state, slot, disksig); - if (SYS_IND(p) == LINUX_RAID_PARTITION) - state->parts[slot].flags = ADDPART_FLAG_RAID; - if (SYS_IND(p) == DM6_PARTITION) - strlcat(state->pp_buf, "[DM]", PAGE_SIZE); - if (SYS_IND(p) == EZD_PARTITION) - strlcat(state->pp_buf, "[EZD]", PAGE_SIZE); - } - - strlcat(state->pp_buf, "\n", PAGE_SIZE); - - /* second pass - output for each on a separate line */ - p = (struct partition *) (0x1be + data); - for (slot = 1 ; slot <= 4 ; slot++, p++) { - unsigned char id = SYS_IND(p); - int n; - - if (!nr_sects(p)) - continue; - - for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++) - ; - - if (!subtypes[n].parse) - continue; - subtypes[n].parse(state, start_sect(p) * sector_size, - nr_sects(p) * sector_size, slot); - } - put_dev_sector(sect); - return 1; -} diff --git a/src/linux/block/partitions/msdos.h b/src/linux/block/partitions/msdos.h deleted file mode 100644 index 38c781c..0000000 --- a/src/linux/block/partitions/msdos.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * fs/partitions/msdos.h - */ - -#define MSDOS_LABEL_MAGIC 0xAA55 - -int msdos_partition(struct parsed_partitions *state); - diff --git a/src/linux/block/partitions/osf.h b/src/linux/block/partitions/osf.h deleted file mode 100644 index 20ed231..0000000 --- a/src/linux/block/partitions/osf.h +++ /dev/null @@ -1,7 +0,0 @@ -/* - * fs/partitions/osf.h - */ - -#define DISKLABELMAGIC (0x82564557UL) - -int osf_partition(struct parsed_partitions *state); diff --git a/src/linux/block/partitions/sgi.h b/src/linux/block/partitions/sgi.h deleted file mode 100644 index b9553eb..0000000 --- a/src/linux/block/partitions/sgi.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * fs/partitions/sgi.h - */ - -extern int sgi_partition(struct parsed_partitions *state); - -#define SGI_LABEL_MAGIC 0x0be5a941 - diff --git a/src/linux/block/partitions/sun.h b/src/linux/block/partitions/sun.h deleted file mode 100644 index 2424baa..0000000 --- a/src/linux/block/partitions/sun.h +++ /dev/null @@ -1,8 +0,0 @@ -/* - * fs/partitions/sun.h - */ - -#define SUN_LABEL_MAGIC 0xDABE -#define SUN_VTOC_SANITY 0x600DDEEE - -int sun_partition(struct parsed_partitions *state); diff --git a/src/linux/block/partitions/sysv68.h b/src/linux/block/partitions/sysv68.h deleted file mode 100644 index bf2f5ff..0000000 --- a/src/linux/block/partitions/sysv68.h +++ /dev/null @@ -1 +0,0 @@ -extern int sysv68_partition(struct parsed_partitions *state); diff --git a/src/linux/block/partitions/ultrix.h b/src/linux/block/partitions/ultrix.h deleted file mode 100644 index a3cc00b..0000000 --- a/src/linux/block/partitions/ultrix.h +++ /dev/null @@ -1,5 +0,0 @@ -/* - * fs/partitions/ultrix.h - */ - -int ultrix_partition(struct parsed_partitions *state); diff --git a/src/linux/block/scsi_ioctl.c b/src/linux/block/scsi_ioctl.c deleted file mode 100644 index 0774799..0000000 --- a/src/linux/block/scsi_ioctl.c +++ /dev/null @@ -1,748 +0,0 @@ -/* - * Copyright (C) 2001 Jens Axboe - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public Licens - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -struct blk_cmd_filter { - unsigned long read_ok[BLK_SCSI_CMD_PER_LONG]; - unsigned long write_ok[BLK_SCSI_CMD_PER_LONG]; -}; - -static struct blk_cmd_filter blk_default_cmd_filter; - -/* Command group 3 is reserved and should never be used. */ -const unsigned char scsi_command_size_tbl[8] = -{ - 6, 10, 10, 12, - 16, 12, 10, 10 -}; -EXPORT_SYMBOL(scsi_command_size_tbl); - -#include - -static int sg_get_version(int __user *p) -{ - static const int sg_version_num = 30527; - return put_user(sg_version_num, p); -} - -static int scsi_get_idlun(struct request_queue *q, int __user *p) -{ - return put_user(0, p); -} - -static int scsi_get_bus(struct request_queue *q, int __user *p) -{ - return put_user(0, p); -} - -static int sg_get_timeout(struct request_queue *q) -{ - return jiffies_to_clock_t(q->sg_timeout); -} - -static int sg_set_timeout(struct request_queue *q, int __user *p) -{ - int timeout, err = get_user(timeout, p); - - if (!err) - q->sg_timeout = clock_t_to_jiffies(timeout); - - return err; -} - -static int max_sectors_bytes(struct request_queue *q) -{ - unsigned int max_sectors = queue_max_sectors(q); - - max_sectors = min_t(unsigned int, max_sectors, INT_MAX >> 9); - - return max_sectors << 9; -} - -static int sg_get_reserved_size(struct request_queue *q, int __user *p) -{ - int val = min_t(int, q->sg_reserved_size, max_sectors_bytes(q)); - - return put_user(val, p); -} - -static int sg_set_reserved_size(struct request_queue *q, int __user *p) -{ - int size, err = get_user(size, p); - - if (err) - return err; - - if (size < 0) - return -EINVAL; - - q->sg_reserved_size = min(size, max_sectors_bytes(q)); - return 0; -} - -/* - * will always return that we are ATAPI even for a real SCSI drive, I'm not - * so sure this is worth doing anything about (why would you care??) - */ -static int sg_emulated_host(struct request_queue *q, int __user *p) -{ - return put_user(1, p); -} - -static void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter) -{ - /* Basic read-only commands */ - __set_bit(TEST_UNIT_READY, filter->read_ok); - __set_bit(REQUEST_SENSE, filter->read_ok); - __set_bit(READ_6, filter->read_ok); - __set_bit(READ_10, filter->read_ok); - __set_bit(READ_12, filter->read_ok); - __set_bit(READ_16, filter->read_ok); - __set_bit(READ_BUFFER, filter->read_ok); - __set_bit(READ_DEFECT_DATA, filter->read_ok); - __set_bit(READ_CAPACITY, filter->read_ok); - __set_bit(READ_LONG, filter->read_ok); - __set_bit(INQUIRY, filter->read_ok); - __set_bit(MODE_SENSE, filter->read_ok); - __set_bit(MODE_SENSE_10, filter->read_ok); - __set_bit(LOG_SENSE, filter->read_ok); - __set_bit(START_STOP, filter->read_ok); - __set_bit(GPCMD_VERIFY_10, filter->read_ok); - __set_bit(VERIFY_16, filter->read_ok); - __set_bit(REPORT_LUNS, filter->read_ok); - __set_bit(SERVICE_ACTION_IN_16, filter->read_ok); - __set_bit(RECEIVE_DIAGNOSTIC, filter->read_ok); - __set_bit(MAINTENANCE_IN, filter->read_ok); - __set_bit(GPCMD_READ_BUFFER_CAPACITY, filter->read_ok); - - /* Audio CD commands */ - __set_bit(GPCMD_PLAY_CD, filter->read_ok); - __set_bit(GPCMD_PLAY_AUDIO_10, filter->read_ok); - __set_bit(GPCMD_PLAY_AUDIO_MSF, filter->read_ok); - __set_bit(GPCMD_PLAY_AUDIO_TI, filter->read_ok); - __set_bit(GPCMD_PAUSE_RESUME, filter->read_ok); - - /* CD/DVD data reading */ - __set_bit(GPCMD_READ_CD, filter->read_ok); - __set_bit(GPCMD_READ_CD_MSF, filter->read_ok); - __set_bit(GPCMD_READ_DISC_INFO, filter->read_ok); - __set_bit(GPCMD_READ_CDVD_CAPACITY, filter->read_ok); - __set_bit(GPCMD_READ_DVD_STRUCTURE, filter->read_ok); - __set_bit(GPCMD_READ_HEADER, filter->read_ok); - __set_bit(GPCMD_READ_TRACK_RZONE_INFO, filter->read_ok); - __set_bit(GPCMD_READ_SUBCHANNEL, filter->read_ok); - __set_bit(GPCMD_READ_TOC_PMA_ATIP, filter->read_ok); - __set_bit(GPCMD_REPORT_KEY, filter->read_ok); - __set_bit(GPCMD_SCAN, filter->read_ok); - __set_bit(GPCMD_GET_CONFIGURATION, filter->read_ok); - __set_bit(GPCMD_READ_FORMAT_CAPACITIES, filter->read_ok); - __set_bit(GPCMD_GET_EVENT_STATUS_NOTIFICATION, filter->read_ok); - __set_bit(GPCMD_GET_PERFORMANCE, filter->read_ok); - __set_bit(GPCMD_SEEK, filter->read_ok); - __set_bit(GPCMD_STOP_PLAY_SCAN, filter->read_ok); - - /* Basic writing commands */ - __set_bit(WRITE_6, filter->write_ok); - __set_bit(WRITE_10, filter->write_ok); - __set_bit(WRITE_VERIFY, filter->write_ok); - __set_bit(WRITE_12, filter->write_ok); - __set_bit(WRITE_VERIFY_12, filter->write_ok); - __set_bit(WRITE_16, filter->write_ok); - __set_bit(WRITE_LONG, filter->write_ok); - __set_bit(WRITE_LONG_2, filter->write_ok); - __set_bit(ERASE, filter->write_ok); - __set_bit(GPCMD_MODE_SELECT_10, filter->write_ok); - __set_bit(MODE_SELECT, filter->write_ok); - __set_bit(LOG_SELECT, filter->write_ok); - __set_bit(GPCMD_BLANK, filter->write_ok); - __set_bit(GPCMD_CLOSE_TRACK, filter->write_ok); - __set_bit(GPCMD_FLUSH_CACHE, filter->write_ok); - __set_bit(GPCMD_FORMAT_UNIT, filter->write_ok); - __set_bit(GPCMD_REPAIR_RZONE_TRACK, filter->write_ok); - __set_bit(GPCMD_RESERVE_RZONE_TRACK, filter->write_ok); - __set_bit(GPCMD_SEND_DVD_STRUCTURE, filter->write_ok); - __set_bit(GPCMD_SEND_EVENT, filter->write_ok); - __set_bit(GPCMD_SEND_KEY, filter->write_ok); - __set_bit(GPCMD_SEND_OPC, filter->write_ok); - __set_bit(GPCMD_SEND_CUE_SHEET, filter->write_ok); - __set_bit(GPCMD_SET_SPEED, filter->write_ok); - __set_bit(GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL, filter->write_ok); - __set_bit(GPCMD_LOAD_UNLOAD, filter->write_ok); - __set_bit(GPCMD_SET_STREAMING, filter->write_ok); - __set_bit(GPCMD_SET_READ_AHEAD, filter->write_ok); -} - -int blk_verify_command(unsigned char *cmd, fmode_t has_write_perm) -{ - struct blk_cmd_filter *filter = &blk_default_cmd_filter; - - /* root can do any command. */ - if (capable(CAP_SYS_RAWIO)) - return 0; - - /* Anybody who can open the device can do a read-safe command */ - if (test_bit(cmd[0], filter->read_ok)) - return 0; - - /* Write-safe commands require a writable open */ - if (test_bit(cmd[0], filter->write_ok) && has_write_perm) - return 0; - - return -EPERM; -} -EXPORT_SYMBOL(blk_verify_command); - -static int blk_fill_sghdr_rq(struct request_queue *q, struct request *rq, - struct sg_io_hdr *hdr, fmode_t mode) -{ - if (copy_from_user(rq->cmd, hdr->cmdp, hdr->cmd_len)) - return -EFAULT; - if (blk_verify_command(rq->cmd, mode & FMODE_WRITE)) - return -EPERM; - - /* - * fill in request structure - */ - rq->cmd_len = hdr->cmd_len; - - rq->timeout = msecs_to_jiffies(hdr->timeout); - if (!rq->timeout) - rq->timeout = q->sg_timeout; - if (!rq->timeout) - rq->timeout = BLK_DEFAULT_SG_TIMEOUT; - if (rq->timeout < BLK_MIN_SG_TIMEOUT) - rq->timeout = BLK_MIN_SG_TIMEOUT; - - return 0; -} - -static int blk_complete_sghdr_rq(struct request *rq, struct sg_io_hdr *hdr, - struct bio *bio) -{ - int r, ret = 0; - - /* - * fill in all the output members - */ - hdr->status = rq->errors & 0xff; - hdr->masked_status = status_byte(rq->errors); - hdr->msg_status = msg_byte(rq->errors); - hdr->host_status = host_byte(rq->errors); - hdr->driver_status = driver_byte(rq->errors); - hdr->info = 0; - if (hdr->masked_status || hdr->host_status || hdr->driver_status) - hdr->info |= SG_INFO_CHECK; - hdr->resid = rq->resid_len; - hdr->sb_len_wr = 0; - - if (rq->sense_len && hdr->sbp) { - int len = min((unsigned int) hdr->mx_sb_len, rq->sense_len); - - if (!copy_to_user(hdr->sbp, rq->sense, len)) - hdr->sb_len_wr = len; - else - ret = -EFAULT; - } - - r = blk_rq_unmap_user(bio); - if (!ret) - ret = r; - - return ret; -} - -static int sg_io(struct request_queue *q, struct gendisk *bd_disk, - struct sg_io_hdr *hdr, fmode_t mode) -{ - unsigned long start_time; - ssize_t ret = 0; - int writing = 0; - int at_head = 0; - struct request *rq; - char sense[SCSI_SENSE_BUFFERSIZE]; - struct bio *bio; - - if (hdr->interface_id != 'S') - return -EINVAL; - - if (hdr->dxfer_len > (queue_max_hw_sectors(q) << 9)) - return -EIO; - - if (hdr->dxfer_len) - switch (hdr->dxfer_direction) { - default: - return -EINVAL; - case SG_DXFER_TO_DEV: - writing = 1; - break; - case SG_DXFER_TO_FROM_DEV: - case SG_DXFER_FROM_DEV: - break; - } - if (hdr->flags & SG_FLAG_Q_AT_HEAD) - at_head = 1; - - ret = -ENOMEM; - rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL); - if (IS_ERR(rq)) - return PTR_ERR(rq); - blk_rq_set_block_pc(rq); - - if (hdr->cmd_len > BLK_MAX_CDB) { - rq->cmd = kzalloc(hdr->cmd_len, GFP_KERNEL); - if (!rq->cmd) - goto out_put_request; - } - - ret = blk_fill_sghdr_rq(q, rq, hdr, mode); - if (ret < 0) - goto out_free_cdb; - - ret = 0; - if (hdr->iovec_count) { - struct iov_iter i; - struct iovec *iov = NULL; - - ret = import_iovec(rq_data_dir(rq), - hdr->dxferp, hdr->iovec_count, - 0, &iov, &i); - if (ret < 0) - goto out_free_cdb; - - /* SG_IO howto says that the shorter of the two wins */ - iov_iter_truncate(&i, hdr->dxfer_len); - - ret = blk_rq_map_user_iov(q, rq, NULL, &i, GFP_KERNEL); - kfree(iov); - } else if (hdr->dxfer_len) - ret = blk_rq_map_user(q, rq, NULL, hdr->dxferp, hdr->dxfer_len, - GFP_KERNEL); - - if (ret) - goto out_free_cdb; - - bio = rq->bio; - memset(sense, 0, sizeof(sense)); - rq->sense = sense; - rq->sense_len = 0; - rq->retries = 0; - - start_time = jiffies; - - /* ignore return value. All information is passed back to caller - * (if he doesn't check that is his problem). - * N.B. a non-zero SCSI status is _not_ necessarily an error. - */ - blk_execute_rq(q, bd_disk, rq, at_head); - - hdr->duration = jiffies_to_msecs(jiffies - start_time); - - ret = blk_complete_sghdr_rq(rq, hdr, bio); - -out_free_cdb: - if (rq->cmd != rq->__cmd) - kfree(rq->cmd); -out_put_request: - blk_put_request(rq); - return ret; -} - -/** - * sg_scsi_ioctl -- handle deprecated SCSI_IOCTL_SEND_COMMAND ioctl - * @file: file this ioctl operates on (optional) - * @q: request queue to send scsi commands down - * @disk: gendisk to operate on (option) - * @sic: userspace structure describing the command to perform - * - * Send down the scsi command described by @sic to the device below - * the request queue @q. If @file is non-NULL it's used to perform - * fine-grained permission checks that allow users to send down - * non-destructive SCSI commands. If the caller has a struct gendisk - * available it should be passed in as @disk to allow the low level - * driver to use the information contained in it. A non-NULL @disk - * is only allowed if the caller knows that the low level driver doesn't - * need it (e.g. in the scsi subsystem). - * - * Notes: - * - This interface is deprecated - users should use the SG_IO - * interface instead, as this is a more flexible approach to - * performing SCSI commands on a device. - * - The SCSI command length is determined by examining the 1st byte - * of the given command. There is no way to override this. - * - Data transfers are limited to PAGE_SIZE - * - The length (x + y) must be at least OMAX_SB_LEN bytes long to - * accommodate the sense buffer when an error occurs. - * The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that - * old code will not be surprised. - * - If a Unix error occurs (e.g. ENOMEM) then the user will receive - * a negative return and the Unix error code in 'errno'. - * If the SCSI command succeeds then 0 is returned. - * Positive numbers returned are the compacted SCSI error codes (4 - * bytes in one int) where the lowest byte is the SCSI status. - */ -#define OMAX_SB_LEN 16 /* For backward compatibility */ -int sg_scsi_ioctl(struct request_queue *q, struct gendisk *disk, fmode_t mode, - struct scsi_ioctl_command __user *sic) -{ - struct request *rq; - int err; - unsigned int in_len, out_len, bytes, opcode, cmdlen; - char *buffer = NULL, sense[SCSI_SENSE_BUFFERSIZE]; - - if (!sic) - return -EINVAL; - - /* - * get in an out lengths, verify they don't exceed a page worth of data - */ - if (get_user(in_len, &sic->inlen)) - return -EFAULT; - if (get_user(out_len, &sic->outlen)) - return -EFAULT; - if (in_len > PAGE_SIZE || out_len > PAGE_SIZE) - return -EINVAL; - if (get_user(opcode, sic->data)) - return -EFAULT; - - bytes = max(in_len, out_len); - if (bytes) { - buffer = kzalloc(bytes, q->bounce_gfp | GFP_USER| __GFP_NOWARN); - if (!buffer) - return -ENOMEM; - - } - - rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_RECLAIM); - if (IS_ERR(rq)) { - err = PTR_ERR(rq); - goto error_free_buffer; - } - blk_rq_set_block_pc(rq); - - cmdlen = COMMAND_SIZE(opcode); - - /* - * get command and data to send to device, if any - */ - err = -EFAULT; - rq->cmd_len = cmdlen; - if (copy_from_user(rq->cmd, sic->data, cmdlen)) - goto error; - - if (in_len && copy_from_user(buffer, sic->data + cmdlen, in_len)) - goto error; - - err = blk_verify_command(rq->cmd, mode & FMODE_WRITE); - if (err) - goto error; - - /* default. possible overriden later */ - rq->retries = 5; - - switch (opcode) { - case SEND_DIAGNOSTIC: - case FORMAT_UNIT: - rq->timeout = FORMAT_UNIT_TIMEOUT; - rq->retries = 1; - break; - case START_STOP: - rq->timeout = START_STOP_TIMEOUT; - break; - case MOVE_MEDIUM: - rq->timeout = MOVE_MEDIUM_TIMEOUT; - break; - case READ_ELEMENT_STATUS: - rq->timeout = READ_ELEMENT_STATUS_TIMEOUT; - break; - case READ_DEFECT_DATA: - rq->timeout = READ_DEFECT_DATA_TIMEOUT; - rq->retries = 1; - break; - default: - rq->timeout = BLK_DEFAULT_SG_TIMEOUT; - break; - } - - if (bytes && blk_rq_map_kern(q, rq, buffer, bytes, __GFP_RECLAIM)) { - err = DRIVER_ERROR << 24; - goto error; - } - - memset(sense, 0, sizeof(sense)); - rq->sense = sense; - rq->sense_len = 0; - - blk_execute_rq(q, disk, rq, 0); - - err = rq->errors & 0xff; /* only 8 bit SCSI status */ - if (err) { - if (rq->sense_len && rq->sense) { - bytes = (OMAX_SB_LEN > rq->sense_len) ? - rq->sense_len : OMAX_SB_LEN; - if (copy_to_user(sic->data, rq->sense, bytes)) - err = -EFAULT; - } - } else { - if (copy_to_user(sic->data, buffer, out_len)) - err = -EFAULT; - } - -error: - blk_put_request(rq); - -error_free_buffer: - kfree(buffer); - - return err; -} -EXPORT_SYMBOL_GPL(sg_scsi_ioctl); - -/* Send basic block requests */ -static int __blk_send_generic(struct request_queue *q, struct gendisk *bd_disk, - int cmd, int data) -{ - struct request *rq; - int err; - - rq = blk_get_request(q, WRITE, __GFP_RECLAIM); - if (IS_ERR(rq)) - return PTR_ERR(rq); - blk_rq_set_block_pc(rq); - rq->timeout = BLK_DEFAULT_SG_TIMEOUT; - rq->cmd[0] = cmd; - rq->cmd[4] = data; - rq->cmd_len = 6; - err = blk_execute_rq(q, bd_disk, rq, 0); - blk_put_request(rq); - - return err; -} - -static inline int blk_send_start_stop(struct request_queue *q, - struct gendisk *bd_disk, int data) -{ - return __blk_send_generic(q, bd_disk, GPCMD_START_STOP_UNIT, data); -} - -int scsi_cmd_ioctl(struct request_queue *q, struct gendisk *bd_disk, fmode_t mode, - unsigned int cmd, void __user *arg) -{ - int err; - - if (!q) - return -ENXIO; - - switch (cmd) { - /* - * new sgv3 interface - */ - case SG_GET_VERSION_NUM: - err = sg_get_version(arg); - break; - case SCSI_IOCTL_GET_IDLUN: - err = scsi_get_idlun(q, arg); - break; - case SCSI_IOCTL_GET_BUS_NUMBER: - err = scsi_get_bus(q, arg); - break; - case SG_SET_TIMEOUT: - err = sg_set_timeout(q, arg); - break; - case SG_GET_TIMEOUT: - err = sg_get_timeout(q); - break; - case SG_GET_RESERVED_SIZE: - err = sg_get_reserved_size(q, arg); - break; - case SG_SET_RESERVED_SIZE: - err = sg_set_reserved_size(q, arg); - break; - case SG_EMULATED_HOST: - err = sg_emulated_host(q, arg); - break; - case SG_IO: { - struct sg_io_hdr hdr; - - err = -EFAULT; - if (copy_from_user(&hdr, arg, sizeof(hdr))) - break; - err = sg_io(q, bd_disk, &hdr, mode); - if (err == -EFAULT) - break; - - if (copy_to_user(arg, &hdr, sizeof(hdr))) - err = -EFAULT; - break; - } - case CDROM_SEND_PACKET: { - struct cdrom_generic_command cgc; - struct sg_io_hdr hdr; - - err = -EFAULT; - if (copy_from_user(&cgc, arg, sizeof(cgc))) - break; - cgc.timeout = clock_t_to_jiffies(cgc.timeout); - memset(&hdr, 0, sizeof(hdr)); - hdr.interface_id = 'S'; - hdr.cmd_len = sizeof(cgc.cmd); - hdr.dxfer_len = cgc.buflen; - err = 0; - switch (cgc.data_direction) { - case CGC_DATA_UNKNOWN: - hdr.dxfer_direction = SG_DXFER_UNKNOWN; - break; - case CGC_DATA_WRITE: - hdr.dxfer_direction = SG_DXFER_TO_DEV; - break; - case CGC_DATA_READ: - hdr.dxfer_direction = SG_DXFER_FROM_DEV; - break; - case CGC_DATA_NONE: - hdr.dxfer_direction = SG_DXFER_NONE; - break; - default: - err = -EINVAL; - } - if (err) - break; - - hdr.dxferp = cgc.buffer; - hdr.sbp = cgc.sense; - if (hdr.sbp) - hdr.mx_sb_len = sizeof(struct request_sense); - hdr.timeout = jiffies_to_msecs(cgc.timeout); - hdr.cmdp = ((struct cdrom_generic_command __user*) arg)->cmd; - hdr.cmd_len = sizeof(cgc.cmd); - - err = sg_io(q, bd_disk, &hdr, mode); - if (err == -EFAULT) - break; - - if (hdr.status) - err = -EIO; - - cgc.stat = err; - cgc.buflen = hdr.resid; - if (copy_to_user(arg, &cgc, sizeof(cgc))) - err = -EFAULT; - - break; - } - - /* - * old junk scsi send command ioctl - */ - case SCSI_IOCTL_SEND_COMMAND: - printk(KERN_WARNING "program %s is using a deprecated SCSI ioctl, please convert it to SG_IO\n", current->comm); - err = -EINVAL; - if (!arg) - break; - - err = sg_scsi_ioctl(q, bd_disk, mode, arg); - break; - case CDROMCLOSETRAY: - err = blk_send_start_stop(q, bd_disk, 0x03); - break; - case CDROMEJECT: - err = blk_send_start_stop(q, bd_disk, 0x02); - break; - default: - err = -ENOTTY; - } - - return err; -} -EXPORT_SYMBOL(scsi_cmd_ioctl); - -int scsi_verify_blk_ioctl(struct block_device *bd, unsigned int cmd) -{ - if (bd && bd == bd->bd_contains) - return 0; - - /* Actually none of these is particularly useful on a partition, - * but they are safe. - */ - switch (cmd) { - case SCSI_IOCTL_GET_IDLUN: - case SCSI_IOCTL_GET_BUS_NUMBER: - case SCSI_IOCTL_GET_PCI: - case SCSI_IOCTL_PROBE_HOST: - case SG_GET_VERSION_NUM: - case SG_SET_TIMEOUT: - case SG_GET_TIMEOUT: - case SG_GET_RESERVED_SIZE: - case SG_SET_RESERVED_SIZE: - case SG_EMULATED_HOST: - return 0; - case CDROM_GET_CAPABILITY: - /* Keep this until we remove the printk below. udev sends it - * and we do not want to spam dmesg about it. CD-ROMs do - * not have partitions, so we get here only for disks. - */ - return -ENOIOCTLCMD; - default: - break; - } - - if (capable(CAP_SYS_RAWIO)) - return 0; - - /* In particular, rule out all resets and host-specific ioctls. */ - printk_ratelimited(KERN_WARNING - "%s: sending ioctl %x to a partition!\n", current->comm, cmd); - - return -ENOIOCTLCMD; -} -EXPORT_SYMBOL(scsi_verify_blk_ioctl); - -int scsi_cmd_blk_ioctl(struct block_device *bd, fmode_t mode, - unsigned int cmd, void __user *arg) -{ - int ret; - - ret = scsi_verify_blk_ioctl(bd, cmd); - if (ret < 0) - return ret; - - return scsi_cmd_ioctl(bd->bd_disk->queue, bd->bd_disk, mode, cmd, arg); -} -EXPORT_SYMBOL(scsi_cmd_blk_ioctl); - -static int __init blk_scsi_ioctl_init(void) -{ - blk_set_cmd_filter_defaults(&blk_default_cmd_filter); - return 0; -} -fs_initcall(blk_scsi_ioctl_init); diff --git a/src/linux/certs/.gitignore b/src/linux/certs/.gitignore deleted file mode 100644 index f51aea4..0000000 --- a/src/linux/certs/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# -# Generated files -# -x509_certificate_list diff --git a/src/linux/certs/Kconfig b/src/linux/certs/Kconfig deleted file mode 100644 index fc5955f..0000000 --- a/src/linux/certs/Kconfig +++ /dev/null @@ -1,67 +0,0 @@ -menu "Certificates for signature checking" - -config MODULE_SIG_KEY - string "File name or PKCS#11 URI of module signing key" - default "certs/signing_key.pem" - depends on MODULE_SIG - help - Provide the file name of a private key/certificate in PEM format, - or a PKCS#11 URI according to RFC7512. The file should contain, or - the URI should identify, both the certificate and its corresponding - private key. - - If this option is unchanged from its default "certs/signing_key.pem", - then the kernel will automatically generate the private key and - certificate as described in Documentation/module-signing.txt - -config SYSTEM_TRUSTED_KEYRING - bool "Provide system-wide ring of trusted keys" - depends on KEYS - depends on ASYMMETRIC_KEY_TYPE - help - Provide a system keyring to which trusted keys can be added. Keys in - the keyring are considered to be trusted. Keys may be added at will - by the kernel from compiled-in data and from hardware key stores, but - userspace may only add extra keys if those keys can be verified by - keys already in the keyring. - - Keys in this keyring are used by module signature checking. - -config SYSTEM_TRUSTED_KEYS - string "Additional X.509 keys for default system keyring" - depends on SYSTEM_TRUSTED_KEYRING - help - If set, this option should be the filename of a PEM-formatted file - containing trusted X.509 certificates to be included in the default - system keyring. Any certificate used for module signing is implicitly - also trusted. - - NOTE: If you previously provided keys for the system keyring in the - form of DER-encoded *.x509 files in the top-level build directory, - those are no longer used. You will need to set this option instead. - -config SYSTEM_EXTRA_CERTIFICATE - bool "Reserve area for inserting a certificate without recompiling" - depends on SYSTEM_TRUSTED_KEYRING - help - If set, space for an extra certificate will be reserved in the kernel - image. This allows introducing a trusted certificate to the default - system keyring without recompiling the kernel. - -config SYSTEM_EXTRA_CERTIFICATE_SIZE - int "Number of bytes to reserve for the extra certificate" - depends on SYSTEM_EXTRA_CERTIFICATE - default 4096 - help - This is the number of bytes reserved in the kernel image for a - certificate to be inserted. - -config SECONDARY_TRUSTED_KEYRING - bool "Provide a keyring to which extra trustable keys may be added" - depends on SYSTEM_TRUSTED_KEYRING - help - If set, provide a keyring to which extra keys may be added, provided - those keys are not blacklisted and are vouched for by a key built - into the kernel or already in the secondary trusted keyring. - -endmenu diff --git a/src/linux/certs/Makefile b/src/linux/certs/Makefile deleted file mode 100644 index 2773c4a..0000000 --- a/src/linux/certs/Makefile +++ /dev/null @@ -1,99 +0,0 @@ -# -# Makefile for the linux kernel signature checking certificates. -# - -obj-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += system_keyring.o system_certificates.o - -ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y) - -$(eval $(call config_filename,SYSTEM_TRUSTED_KEYS)) - -# GCC doesn't include .incbin files in -MD generated dependencies (PR#66871) -$(obj)/system_certificates.o: $(obj)/x509_certificate_list - -# Cope with signing_key.x509 existing in $(srctree) not $(objtree) -AFLAGS_system_certificates.o := -I$(srctree) - -quiet_cmd_extract_certs = EXTRACT_CERTS $(patsubst "%",%,$(2)) - cmd_extract_certs = scripts/extract-cert $(2) $@ || ( rm $@; exit 1) - -targets += x509_certificate_list -$(obj)/x509_certificate_list: scripts/extract-cert $(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(SYSTEM_TRUSTED_KEYS_FILENAME) FORCE - $(call if_changed,extract_certs,$(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(CONFIG_SYSTEM_TRUSTED_KEYS)) -endif - -clean-files := x509_certificate_list .x509.list - -ifeq ($(CONFIG_MODULE_SIG),y) -############################################################################### -# -# If module signing is requested, say by allyesconfig, but a key has not been -# supplied, then one will need to be generated to make sure the build does not -# fail and that the kernel may be used afterwards. -# -############################################################################### -ifndef CONFIG_MODULE_SIG_HASH -$(error Could not determine digest type to use from kernel config) -endif - -redirect_openssl = 2>&1 -quiet_redirect_openssl = 2>&1 -silent_redirect_openssl = 2>/dev/null - -# We do it this way rather than having a boolean option for enabling an -# external private key, because 'make randconfig' might enable such a -# boolean option and we unfortunately can't make it depend on !RANDCONFIG. -ifeq ($(CONFIG_MODULE_SIG_KEY),"certs/signing_key.pem") -$(obj)/signing_key.pem: $(obj)/x509.genkey - @$(kecho) "###" - @$(kecho) "### Now generating an X.509 key pair to be used for signing modules." - @$(kecho) "###" - @$(kecho) "### If this takes a long time, you might wish to run rngd in the" - @$(kecho) "### background to keep the supply of entropy topped up. It" - @$(kecho) "### needs to be run as root, and uses a hardware random" - @$(kecho) "### number generator if one is available." - @$(kecho) "###" - $(Q)openssl req -new -nodes -utf8 -$(CONFIG_MODULE_SIG_HASH) -days 36500 \ - -batch -x509 -config $(obj)/x509.genkey \ - -outform PEM -out $(obj)/signing_key.pem \ - -keyout $(obj)/signing_key.pem \ - $($(quiet)redirect_openssl) - @$(kecho) "###" - @$(kecho) "### Key pair generated." - @$(kecho) "###" - -$(obj)/x509.genkey: - @$(kecho) Generating X.509 key generation config - @echo >$@ "[ req ]" - @echo >>$@ "default_bits = 4096" - @echo >>$@ "distinguished_name = req_distinguished_name" - @echo >>$@ "prompt = no" - @echo >>$@ "string_mask = utf8only" - @echo >>$@ "x509_extensions = myexts" - @echo >>$@ - @echo >>$@ "[ req_distinguished_name ]" - @echo >>$@ "#O = Unspecified company" - @echo >>$@ "CN = Build time autogenerated kernel key" - @echo >>$@ "#emailAddress = unspecified.user@unspecified.company" - @echo >>$@ - @echo >>$@ "[ myexts ]" - @echo >>$@ "basicConstraints=critical,CA:FALSE" - @echo >>$@ "keyUsage=digitalSignature" - @echo >>$@ "subjectKeyIdentifier=hash" - @echo >>$@ "authorityKeyIdentifier=keyid" -endif - -$(eval $(call config_filename,MODULE_SIG_KEY)) - -# If CONFIG_MODULE_SIG_KEY isn't a PKCS#11 URI, depend on it -ifeq ($(patsubst pkcs11:%,%,$(firstword $(MODULE_SIG_KEY_FILENAME))),$(firstword $(MODULE_SIG_KEY_FILENAME))) -X509_DEP := $(MODULE_SIG_KEY_SRCPREFIX)$(MODULE_SIG_KEY_FILENAME) -endif - -# GCC PR#66871 again. -$(obj)/system_certificates.o: $(obj)/signing_key.x509 - -targets += signing_key.x509 -$(obj)/signing_key.x509: scripts/extract-cert $(X509_DEP) FORCE - $(call if_changed,extract_certs,$(MODULE_SIG_KEY_SRCPREFIX)$(CONFIG_MODULE_SIG_KEY)) -endif diff --git a/src/linux/crypto/.gitignore b/src/linux/crypto/.gitignore deleted file mode 100644 index ee32837..0000000 --- a/src/linux/crypto/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*-asn1.[ch] diff --git a/src/linux/crypto/Kconfig b/src/linux/crypto/Kconfig deleted file mode 100644 index 84d7148..0000000 --- a/src/linux/crypto/Kconfig +++ /dev/null @@ -1,1714 +0,0 @@ -# -# Generic algorithms support -# -config XOR_BLOCKS - tristate - -# -# async_tx api: hardware offloaded memory transfer/transform support -# -source "crypto/async_tx/Kconfig" - -# -# Cryptographic API Configuration -# -menuconfig CRYPTO - tristate "Cryptographic API" - help - This option provides the core Cryptographic API. - -if CRYPTO - -comment "Crypto core or helper" - -config CRYPTO_FIPS - bool "FIPS 200 compliance" - depends on (CRYPTO_ANSI_CPRNG || CRYPTO_DRBG) && !CRYPTO_MANAGER_DISABLE_TESTS - depends on MODULE_SIG - help - This options enables the fips boot option which is - required if you want to system to operate in a FIPS 200 - certification. You should say no unless you know what - this is. - -config CRYPTO_ALGAPI - tristate - select CRYPTO_ALGAPI2 - help - This option provides the API for cryptographic algorithms. - -config CRYPTO_ALGAPI2 - tristate - -config CRYPTO_AEAD - tristate - select CRYPTO_AEAD2 - select CRYPTO_ALGAPI - -config CRYPTO_AEAD2 - tristate - select CRYPTO_ALGAPI2 - select CRYPTO_NULL2 - select CRYPTO_RNG2 - -config CRYPTO_BLKCIPHER - tristate - select CRYPTO_BLKCIPHER2 - select CRYPTO_ALGAPI - -config CRYPTO_BLKCIPHER2 - tristate - select CRYPTO_ALGAPI2 - select CRYPTO_RNG2 - select CRYPTO_WORKQUEUE - -config CRYPTO_HASH - tristate - select CRYPTO_HASH2 - select CRYPTO_ALGAPI - -config CRYPTO_HASH2 - tristate - select CRYPTO_ALGAPI2 - -config CRYPTO_RNG - tristate - select CRYPTO_RNG2 - select CRYPTO_ALGAPI - -config CRYPTO_RNG2 - tristate - select CRYPTO_ALGAPI2 - -config CRYPTO_RNG_DEFAULT - tristate - select CRYPTO_DRBG_MENU - -config CRYPTO_AKCIPHER2 - tristate - select CRYPTO_ALGAPI2 - -config CRYPTO_AKCIPHER - tristate - select CRYPTO_AKCIPHER2 - select CRYPTO_ALGAPI - -config CRYPTO_KPP2 - tristate - select CRYPTO_ALGAPI2 - -config CRYPTO_KPP - tristate - select CRYPTO_ALGAPI - select CRYPTO_KPP2 - -config CRYPTO_RSA - tristate "RSA algorithm" - select CRYPTO_AKCIPHER - select CRYPTO_MANAGER - select MPILIB - select ASN1 - help - Generic implementation of the RSA public key algorithm. - -config CRYPTO_DH - tristate "Diffie-Hellman algorithm" - select CRYPTO_KPP - select MPILIB - help - Generic implementation of the Diffie-Hellman algorithm. - -config CRYPTO_ECDH - tristate "ECDH algorithm" - select CRYTPO_KPP - help - Generic implementation of the ECDH algorithm - -config CRYPTO_MANAGER - tristate "Cryptographic algorithm manager" - select CRYPTO_MANAGER2 - help - Create default cryptographic template instantiations such as - cbc(aes). - -config CRYPTO_MANAGER2 - def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y) - select CRYPTO_AEAD2 - select CRYPTO_HASH2 - select CRYPTO_BLKCIPHER2 - select CRYPTO_AKCIPHER2 - select CRYPTO_KPP2 - -config CRYPTO_USER - tristate "Userspace cryptographic algorithm configuration" - depends on NET - select CRYPTO_MANAGER - help - Userspace configuration for cryptographic instantiations such as - cbc(aes). - -config CRYPTO_MANAGER_DISABLE_TESTS - bool "Disable run-time self tests" - default y - depends on CRYPTO_MANAGER2 - help - Disable run-time self tests that normally take place at - algorithm registration. - -config CRYPTO_GF128MUL - tristate "GF(2^128) multiplication functions" - help - Efficient table driven implementation of multiplications in the - field GF(2^128). This is needed by some cypher modes. This - option will be selected automatically if you select such a - cipher mode. Only select this option by hand if you expect to load - an external module that requires these functions. - -config CRYPTO_NULL - tristate "Null algorithms" - select CRYPTO_NULL2 - help - These are 'Null' algorithms, used by IPsec, which do nothing. - -config CRYPTO_NULL2 - tristate - select CRYPTO_ALGAPI2 - select CRYPTO_BLKCIPHER2 - select CRYPTO_HASH2 - -config CRYPTO_PCRYPT - tristate "Parallel crypto engine" - depends on SMP - select PADATA - select CRYPTO_MANAGER - select CRYPTO_AEAD - help - This converts an arbitrary crypto algorithm into a parallel - algorithm that executes in kernel threads. - -config CRYPTO_WORKQUEUE - tristate - -config CRYPTO_CRYPTD - tristate "Software async crypto daemon" - select CRYPTO_BLKCIPHER - select CRYPTO_HASH - select CRYPTO_MANAGER - select CRYPTO_WORKQUEUE - help - This is a generic software asynchronous crypto daemon that - converts an arbitrary synchronous software crypto algorithm - into an asynchronous algorithm that executes in a kernel thread. - -config CRYPTO_MCRYPTD - tristate "Software async multi-buffer crypto daemon" - select CRYPTO_BLKCIPHER - select CRYPTO_HASH - select CRYPTO_MANAGER - select CRYPTO_WORKQUEUE - help - This is a generic software asynchronous crypto daemon that - provides the kernel thread to assist multi-buffer crypto - algorithms for submitting jobs and flushing jobs in multi-buffer - crypto algorithms. Multi-buffer crypto algorithms are executed - in the context of this kernel thread and drivers can post - their crypto request asynchronously to be processed by this daemon. - -config CRYPTO_AUTHENC - tristate "Authenc support" - select CRYPTO_AEAD - select CRYPTO_BLKCIPHER - select CRYPTO_MANAGER - select CRYPTO_HASH - select CRYPTO_NULL - help - Authenc: Combined mode wrapper for IPsec. - This is required for IPSec. - -config CRYPTO_TEST - tristate "Testing module" - depends on m - select CRYPTO_MANAGER - help - Quick & dirty crypto test module. - -config CRYPTO_ABLK_HELPER - tristate - select CRYPTO_CRYPTD - -config CRYPTO_GLUE_HELPER_X86 - tristate - depends on X86 - select CRYPTO_ALGAPI - -config CRYPTO_ENGINE - tristate - -comment "Authenticated Encryption with Associated Data" - -config CRYPTO_CCM - tristate "CCM support" - select CRYPTO_CTR - select CRYPTO_AEAD - help - Support for Counter with CBC MAC. Required for IPsec. - -config CRYPTO_GCM - tristate "GCM/GMAC support" - select CRYPTO_CTR - select CRYPTO_AEAD - select CRYPTO_GHASH - select CRYPTO_NULL - help - Support for Galois/Counter Mode (GCM) and Galois Message - Authentication Code (GMAC). Required for IPSec. - -config CRYPTO_CHACHA20POLY1305 - tristate "ChaCha20-Poly1305 AEAD support" - select CRYPTO_CHACHA20 - select CRYPTO_POLY1305 - select CRYPTO_AEAD - help - ChaCha20-Poly1305 AEAD support, RFC7539. - - Support for the AEAD wrapper using the ChaCha20 stream cipher combined - with the Poly1305 authenticator. It is defined in RFC7539 for use in - IETF protocols. - -config CRYPTO_SEQIV - tristate "Sequence Number IV Generator" - select CRYPTO_AEAD - select CRYPTO_BLKCIPHER - select CRYPTO_NULL - select CRYPTO_RNG_DEFAULT - help - This IV generator generates an IV based on a sequence number by - xoring it with a salt. This algorithm is mainly useful for CTR - -config CRYPTO_ECHAINIV - tristate "Encrypted Chain IV Generator" - select CRYPTO_AEAD - select CRYPTO_NULL - select CRYPTO_RNG_DEFAULT - default m - help - This IV generator generates an IV based on the encryption of - a sequence number xored with a salt. This is the default - algorithm for CBC. - -comment "Block modes" - -config CRYPTO_CBC - tristate "CBC support" - select CRYPTO_BLKCIPHER - select CRYPTO_MANAGER - help - CBC: Cipher Block Chaining mode - This block cipher algorithm is required for IPSec. - -config CRYPTO_CTR - tristate "CTR support" - select CRYPTO_BLKCIPHER - select CRYPTO_SEQIV - select CRYPTO_MANAGER - help - CTR: Counter mode - This block cipher algorithm is required for IPSec. - -config CRYPTO_CTS - tristate "CTS support" - select CRYPTO_BLKCIPHER - help - CTS: Cipher Text Stealing - This is the Cipher Text Stealing mode as described by - Section 8 of rfc2040 and referenced by rfc3962. - (rfc3962 includes errata information in its Appendix A) - This mode is required for Kerberos gss mechanism support - for AES encryption. - -config CRYPTO_ECB - tristate "ECB support" - select CRYPTO_BLKCIPHER - select CRYPTO_MANAGER - help - ECB: Electronic CodeBook mode - This is the simplest block cipher algorithm. It simply encrypts - the input block by block. - -config CRYPTO_LRW - tristate "LRW support" - select CRYPTO_BLKCIPHER - select CRYPTO_MANAGER - select CRYPTO_GF128MUL - help - LRW: Liskov Rivest Wagner, a tweakable, non malleable, non movable - narrow block cipher mode for dm-crypt. Use it with cipher - specification string aes-lrw-benbi, the key must be 256, 320 or 384. - The first 128, 192 or 256 bits in the key are used for AES and the - rest is used to tie each cipher block to its logical position. - -config CRYPTO_PCBC - tristate "PCBC support" - select CRYPTO_BLKCIPHER - select CRYPTO_MANAGER - help - PCBC: Propagating Cipher Block Chaining mode - This block cipher algorithm is required for RxRPC. - -config CRYPTO_XTS - tristate "XTS support" - select CRYPTO_BLKCIPHER - select CRYPTO_MANAGER - select CRYPTO_GF128MUL - help - XTS: IEEE1619/D16 narrow block cipher use with aes-xts-plain, - key size 256, 384 or 512 bits. This implementation currently - can't handle a sectorsize which is not a multiple of 16 bytes. - -config CRYPTO_KEYWRAP - tristate "Key wrapping support" - select CRYPTO_BLKCIPHER - help - Support for key wrapping (NIST SP800-38F / RFC3394) without - padding. - -comment "Hash modes" - -config CRYPTO_CMAC - tristate "CMAC support" - select CRYPTO_HASH - select CRYPTO_MANAGER - help - Cipher-based Message Authentication Code (CMAC) specified by - The National Institute of Standards and Technology (NIST). - - https://tools.ietf.org/html/rfc4493 - http://csrc.nist.gov/publications/nistpubs/800-38B/SP_800-38B.pdf - -config CRYPTO_HMAC - tristate "HMAC support" - select CRYPTO_HASH - select CRYPTO_MANAGER - help - HMAC: Keyed-Hashing for Message Authentication (RFC2104). - This is required for IPSec. - -config CRYPTO_XCBC - tristate "XCBC support" - select CRYPTO_HASH - select CRYPTO_MANAGER - help - XCBC: Keyed-Hashing with encryption algorithm - http://www.ietf.org/rfc/rfc3566.txt - http://csrc.nist.gov/encryption/modes/proposedmodes/ - xcbc-mac/xcbc-mac-spec.pdf - -config CRYPTO_VMAC - tristate "VMAC support" - select CRYPTO_HASH - select CRYPTO_MANAGER - help - VMAC is a message authentication algorithm designed for - very high speed on 64-bit architectures. - - See also: - - -comment "Digest" - -config CRYPTO_CRC32C - tristate "CRC32c CRC algorithm" - select CRYPTO_HASH - select CRC32 - help - Castagnoli, et al Cyclic Redundancy-Check Algorithm. Used - by iSCSI for header and data digests and by others. - See Castagnoli93. Module will be crc32c. - -config CRYPTO_CRC32C_INTEL - tristate "CRC32c INTEL hardware acceleration" - depends on X86 - select CRYPTO_HASH - help - In Intel processor with SSE4.2 supported, the processor will - support CRC32C implementation using hardware accelerated CRC32 - instruction. This option will create 'crc32c-intel' module, - which will enable any routine to use the CRC32 instruction to - gain performance compared with software implementation. - Module will be crc32c-intel. - -config CRYPT_CRC32C_VPMSUM - tristate "CRC32c CRC algorithm (powerpc64)" - depends on PPC64 && ALTIVEC - select CRYPTO_HASH - select CRC32 - help - CRC32c algorithm implemented using vector polynomial multiply-sum - (vpmsum) instructions, introduced in POWER8. Enable on POWER8 - and newer processors for improved performance. - - -config CRYPTO_CRC32C_SPARC64 - tristate "CRC32c CRC algorithm (SPARC64)" - depends on SPARC64 - select CRYPTO_HASH - select CRC32 - help - CRC32c CRC algorithm implemented using sparc64 crypto instructions, - when available. - -config CRYPTO_CRC32 - tristate "CRC32 CRC algorithm" - select CRYPTO_HASH - select CRC32 - help - CRC-32-IEEE 802.3 cyclic redundancy-check algorithm. - Shash crypto api wrappers to crc32_le function. - -config CRYPTO_CRC32_PCLMUL - tristate "CRC32 PCLMULQDQ hardware acceleration" - depends on X86 - select CRYPTO_HASH - select CRC32 - help - From Intel Westmere and AMD Bulldozer processor with SSE4.2 - and PCLMULQDQ supported, the processor will support - CRC32 PCLMULQDQ implementation using hardware accelerated PCLMULQDQ - instruction. This option will create 'crc32-plcmul' module, - which will enable any routine to use the CRC-32-IEEE 802.3 checksum - and gain better performance as compared with the table implementation. - -config CRYPTO_CRCT10DIF - tristate "CRCT10DIF algorithm" - select CRYPTO_HASH - help - CRC T10 Data Integrity Field computation is being cast as - a crypto transform. This allows for faster crc t10 diff - transforms to be used if they are available. - -config CRYPTO_CRCT10DIF_PCLMUL - tristate "CRCT10DIF PCLMULQDQ hardware acceleration" - depends on X86 && 64BIT && CRC_T10DIF - select CRYPTO_HASH - help - For x86_64 processors with SSE4.2 and PCLMULQDQ supported, - CRC T10 DIF PCLMULQDQ computation can be hardware - accelerated PCLMULQDQ instruction. This option will create - 'crct10dif-plcmul' module, which is faster when computing the - crct10dif checksum as compared with the generic table implementation. - -config CRYPTO_GHASH - tristate "GHASH digest algorithm" - select CRYPTO_GF128MUL - select CRYPTO_HASH - help - GHASH is message digest algorithm for GCM (Galois/Counter Mode). - -config CRYPTO_POLY1305 - tristate "Poly1305 authenticator algorithm" - select CRYPTO_HASH - help - Poly1305 authenticator algorithm, RFC7539. - - Poly1305 is an authenticator algorithm designed by Daniel J. Bernstein. - It is used for the ChaCha20-Poly1305 AEAD, specified in RFC7539 for use - in IETF protocols. This is the portable C implementation of Poly1305. - -config CRYPTO_POLY1305_X86_64 - tristate "Poly1305 authenticator algorithm (x86_64/SSE2/AVX2)" - depends on X86 && 64BIT - select CRYPTO_POLY1305 - help - Poly1305 authenticator algorithm, RFC7539. - - Poly1305 is an authenticator algorithm designed by Daniel J. Bernstein. - It is used for the ChaCha20-Poly1305 AEAD, specified in RFC7539 for use - in IETF protocols. This is the x86_64 assembler implementation using SIMD - instructions. - -config CRYPTO_MD4 - tristate "MD4 digest algorithm" - select CRYPTO_HASH - help - MD4 message digest algorithm (RFC1320). - -config CRYPTO_MD5 - tristate "MD5 digest algorithm" - select CRYPTO_HASH - help - MD5 message digest algorithm (RFC1321). - -config CRYPTO_MD5_OCTEON - tristate "MD5 digest algorithm (OCTEON)" - depends on CPU_CAVIUM_OCTEON - select CRYPTO_MD5 - select CRYPTO_HASH - help - MD5 message digest algorithm (RFC1321) implemented - using OCTEON crypto instructions, when available. - -config CRYPTO_MD5_PPC - tristate "MD5 digest algorithm (PPC)" - depends on PPC - select CRYPTO_HASH - help - MD5 message digest algorithm (RFC1321) implemented - in PPC assembler. - -config CRYPTO_MD5_SPARC64 - tristate "MD5 digest algorithm (SPARC64)" - depends on SPARC64 - select CRYPTO_MD5 - select CRYPTO_HASH - help - MD5 message digest algorithm (RFC1321) implemented - using sparc64 crypto instructions, when available. - -config CRYPTO_MICHAEL_MIC - tristate "Michael MIC keyed digest algorithm" - select CRYPTO_HASH - help - Michael MIC is used for message integrity protection in TKIP - (IEEE 802.11i). This algorithm is required for TKIP, but it - should not be used for other purposes because of the weakness - of the algorithm. - -config CRYPTO_RMD128 - tristate "RIPEMD-128 digest algorithm" - select CRYPTO_HASH - help - RIPEMD-128 (ISO/IEC 10118-3:2004). - - RIPEMD-128 is a 128-bit cryptographic hash function. It should only - be used as a secure replacement for RIPEMD. For other use cases, - RIPEMD-160 should be used. - - Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel. - See - -config CRYPTO_RMD160 - tristate "RIPEMD-160 digest algorithm" - select CRYPTO_HASH - help - RIPEMD-160 (ISO/IEC 10118-3:2004). - - RIPEMD-160 is a 160-bit cryptographic hash function. It is intended - to be used as a secure replacement for the 128-bit hash functions - MD4, MD5 and it's predecessor RIPEMD - (not to be confused with RIPEMD-128). - - It's speed is comparable to SHA1 and there are no known attacks - against RIPEMD-160. - - Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel. - See - -config CRYPTO_RMD256 - tristate "RIPEMD-256 digest algorithm" - select CRYPTO_HASH - help - RIPEMD-256 is an optional extension of RIPEMD-128 with a - 256 bit hash. It is intended for applications that require - longer hash-results, without needing a larger security level - (than RIPEMD-128). - - Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel. - See - -config CRYPTO_RMD320 - tristate "RIPEMD-320 digest algorithm" - select CRYPTO_HASH - help - RIPEMD-320 is an optional extension of RIPEMD-160 with a - 320 bit hash. It is intended for applications that require - longer hash-results, without needing a larger security level - (than RIPEMD-160). - - Developed by Hans Dobbertin, Antoon Bosselaers and Bart Preneel. - See - -config CRYPTO_SHA1 - tristate "SHA1 digest algorithm" - select CRYPTO_HASH - help - SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). - -config CRYPTO_SHA1_SSSE3 - tristate "SHA1 digest algorithm (SSSE3/AVX/AVX2/SHA-NI)" - depends on X86 && 64BIT - select CRYPTO_SHA1 - select CRYPTO_HASH - help - SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented - using Supplemental SSE3 (SSSE3) instructions or Advanced Vector - Extensions (AVX/AVX2) or SHA-NI(SHA Extensions New Instructions), - when available. - -config CRYPTO_SHA256_SSSE3 - tristate "SHA256 digest algorithm (SSSE3/AVX/AVX2/SHA-NI)" - depends on X86 && 64BIT - select CRYPTO_SHA256 - select CRYPTO_HASH - help - SHA-256 secure hash standard (DFIPS 180-2) implemented - using Supplemental SSE3 (SSSE3) instructions, or Advanced Vector - Extensions version 1 (AVX1), or Advanced Vector Extensions - version 2 (AVX2) instructions, or SHA-NI (SHA Extensions New - Instructions) when available. - -config CRYPTO_SHA512_SSSE3 - tristate "SHA512 digest algorithm (SSSE3/AVX/AVX2)" - depends on X86 && 64BIT - select CRYPTO_SHA512 - select CRYPTO_HASH - help - SHA-512 secure hash standard (DFIPS 180-2) implemented - using Supplemental SSE3 (SSSE3) instructions, or Advanced Vector - Extensions version 1 (AVX1), or Advanced Vector Extensions - version 2 (AVX2) instructions, when available. - -config CRYPTO_SHA1_OCTEON - tristate "SHA1 digest algorithm (OCTEON)" - depends on CPU_CAVIUM_OCTEON - select CRYPTO_SHA1 - select CRYPTO_HASH - help - SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented - using OCTEON crypto instructions, when available. - -config CRYPTO_SHA1_SPARC64 - tristate "SHA1 digest algorithm (SPARC64)" - depends on SPARC64 - select CRYPTO_SHA1 - select CRYPTO_HASH - help - SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented - using sparc64 crypto instructions, when available. - -config CRYPTO_SHA1_PPC - tristate "SHA1 digest algorithm (powerpc)" - depends on PPC - help - This is the powerpc hardware accelerated implementation of the - SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). - -config CRYPTO_SHA1_PPC_SPE - tristate "SHA1 digest algorithm (PPC SPE)" - depends on PPC && SPE - help - SHA-1 secure hash standard (DFIPS 180-4) implemented - using powerpc SPE SIMD instruction set. - -config CRYPTO_SHA1_MB - tristate "SHA1 digest algorithm (x86_64 Multi-Buffer, Experimental)" - depends on X86 && 64BIT - select CRYPTO_SHA1 - select CRYPTO_HASH - select CRYPTO_MCRYPTD - help - SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented - using multi-buffer technique. This algorithm computes on - multiple data lanes concurrently with SIMD instructions for - better throughput. It should not be enabled by default but - used when there is significant amount of work to keep the keep - the data lanes filled to get performance benefit. If the data - lanes remain unfilled, a flush operation will be initiated to - process the crypto jobs, adding a slight latency. - -config CRYPTO_SHA256_MB - tristate "SHA256 digest algorithm (x86_64 Multi-Buffer, Experimental)" - depends on X86 && 64BIT - select CRYPTO_SHA256 - select CRYPTO_HASH - select CRYPTO_MCRYPTD - help - SHA-256 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented - using multi-buffer technique. This algorithm computes on - multiple data lanes concurrently with SIMD instructions for - better throughput. It should not be enabled by default but - used when there is significant amount of work to keep the keep - the data lanes filled to get performance benefit. If the data - lanes remain unfilled, a flush operation will be initiated to - process the crypto jobs, adding a slight latency. - -config CRYPTO_SHA512_MB - tristate "SHA512 digest algorithm (x86_64 Multi-Buffer, Experimental)" - depends on X86 && 64BIT - select CRYPTO_SHA512 - select CRYPTO_HASH - select CRYPTO_MCRYPTD - help - SHA-512 secure hash standard (FIPS 180-1/DFIPS 180-2) implemented - using multi-buffer technique. This algorithm computes on - multiple data lanes concurrently with SIMD instructions for - better throughput. It should not be enabled by default but - used when there is significant amount of work to keep the keep - the data lanes filled to get performance benefit. If the data - lanes remain unfilled, a flush operation will be initiated to - process the crypto jobs, adding a slight latency. - -config CRYPTO_SHA256 - tristate "SHA224 and SHA256 digest algorithm" - select CRYPTO_HASH - help - SHA256 secure hash standard (DFIPS 180-2). - - This version of SHA implements a 256 bit hash with 128 bits of - security against collision attacks. - - This code also includes SHA-224, a 224 bit hash with 112 bits - of security against collision attacks. - -config CRYPTO_SHA256_PPC_SPE - tristate "SHA224 and SHA256 digest algorithm (PPC SPE)" - depends on PPC && SPE - select CRYPTO_SHA256 - select CRYPTO_HASH - help - SHA224 and SHA256 secure hash standard (DFIPS 180-2) - implemented using powerpc SPE SIMD instruction set. - -config CRYPTO_SHA256_OCTEON - tristate "SHA224 and SHA256 digest algorithm (OCTEON)" - depends on CPU_CAVIUM_OCTEON - select CRYPTO_SHA256 - select CRYPTO_HASH - help - SHA-256 secure hash standard (DFIPS 180-2) implemented - using OCTEON crypto instructions, when available. - -config CRYPTO_SHA256_SPARC64 - tristate "SHA224 and SHA256 digest algorithm (SPARC64)" - depends on SPARC64 - select CRYPTO_SHA256 - select CRYPTO_HASH - help - SHA-256 secure hash standard (DFIPS 180-2) implemented - using sparc64 crypto instructions, when available. - -config CRYPTO_SHA512 - tristate "SHA384 and SHA512 digest algorithms" - select CRYPTO_HASH - help - SHA512 secure hash standard (DFIPS 180-2). - - This version of SHA implements a 512 bit hash with 256 bits of - security against collision attacks. - - This code also includes SHA-384, a 384 bit hash with 192 bits - of security against collision attacks. - -config CRYPTO_SHA512_OCTEON - tristate "SHA384 and SHA512 digest algorithms (OCTEON)" - depends on CPU_CAVIUM_OCTEON - select CRYPTO_SHA512 - select CRYPTO_HASH - help - SHA-512 secure hash standard (DFIPS 180-2) implemented - using OCTEON crypto instructions, when available. - -config CRYPTO_SHA512_SPARC64 - tristate "SHA384 and SHA512 digest algorithm (SPARC64)" - depends on SPARC64 - select CRYPTO_SHA512 - select CRYPTO_HASH - help - SHA-512 secure hash standard (DFIPS 180-2) implemented - using sparc64 crypto instructions, when available. - -config CRYPTO_SHA3 - tristate "SHA3 digest algorithm" - select CRYPTO_HASH - help - SHA-3 secure hash standard (DFIPS 202). It's based on - cryptographic sponge function family called Keccak. - - References: - http://keccak.noekeon.org/ - -config CRYPTO_TGR192 - tristate "Tiger digest algorithms" - select CRYPTO_HASH - help - Tiger hash algorithm 192, 160 and 128-bit hashes - - Tiger is a hash function optimized for 64-bit processors while - still having decent performance on 32-bit processors. - Tiger was developed by Ross Anderson and Eli Biham. - - See also: - . - -config CRYPTO_WP512 - tristate "Whirlpool digest algorithms" - select CRYPTO_HASH - help - Whirlpool hash algorithm 512, 384 and 256-bit hashes - - Whirlpool-512 is part of the NESSIE cryptographic primitives. - Whirlpool will be part of the ISO/IEC 10118-3:2003(E) standard - - See also: - - -config CRYPTO_GHASH_CLMUL_NI_INTEL - tristate "GHASH digest algorithm (CLMUL-NI accelerated)" - depends on X86 && 64BIT - select CRYPTO_CRYPTD - help - GHASH is message digest algorithm for GCM (Galois/Counter Mode). - The implementation is accelerated by CLMUL-NI of Intel. - -comment "Ciphers" - -config CRYPTO_AES - tristate "AES cipher algorithms" - select CRYPTO_ALGAPI - help - AES cipher algorithms (FIPS-197). AES uses the Rijndael - algorithm. - - Rijndael appears to be consistently a very good performer in - both hardware and software across a wide range of computing - environments regardless of its use in feedback or non-feedback - modes. Its key setup time is excellent, and its key agility is - good. Rijndael's very low memory requirements make it very well - suited for restricted-space environments, in which it also - demonstrates excellent performance. Rijndael's operations are - among the easiest to defend against power and timing attacks. - - The AES specifies three key sizes: 128, 192 and 256 bits - - See for more information. - -config CRYPTO_AES_586 - tristate "AES cipher algorithms (i586)" - depends on (X86 || UML_X86) && !64BIT - select CRYPTO_ALGAPI - select CRYPTO_AES - help - AES cipher algorithms (FIPS-197). AES uses the Rijndael - algorithm. - - Rijndael appears to be consistently a very good performer in - both hardware and software across a wide range of computing - environments regardless of its use in feedback or non-feedback - modes. Its key setup time is excellent, and its key agility is - good. Rijndael's very low memory requirements make it very well - suited for restricted-space environments, in which it also - demonstrates excellent performance. Rijndael's operations are - among the easiest to defend against power and timing attacks. - - The AES specifies three key sizes: 128, 192 and 256 bits - - See for more information. - -config CRYPTO_AES_X86_64 - tristate "AES cipher algorithms (x86_64)" - depends on (X86 || UML_X86) && 64BIT - select CRYPTO_ALGAPI - select CRYPTO_AES - help - AES cipher algorithms (FIPS-197). AES uses the Rijndael - algorithm. - - Rijndael appears to be consistently a very good performer in - both hardware and software across a wide range of computing - environments regardless of its use in feedback or non-feedback - modes. Its key setup time is excellent, and its key agility is - good. Rijndael's very low memory requirements make it very well - suited for restricted-space environments, in which it also - demonstrates excellent performance. Rijndael's operations are - among the easiest to defend against power and timing attacks. - - The AES specifies three key sizes: 128, 192 and 256 bits - - See for more information. - -config CRYPTO_AES_NI_INTEL - tristate "AES cipher algorithms (AES-NI)" - depends on X86 - select CRYPTO_AES_X86_64 if 64BIT - select CRYPTO_AES_586 if !64BIT - select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER - select CRYPTO_ALGAPI - select CRYPTO_GLUE_HELPER_X86 if 64BIT - select CRYPTO_LRW - select CRYPTO_XTS - help - Use Intel AES-NI instructions for AES algorithm. - - AES cipher algorithms (FIPS-197). AES uses the Rijndael - algorithm. - - Rijndael appears to be consistently a very good performer in - both hardware and software across a wide range of computing - environments regardless of its use in feedback or non-feedback - modes. Its key setup time is excellent, and its key agility is - good. Rijndael's very low memory requirements make it very well - suited for restricted-space environments, in which it also - demonstrates excellent performance. Rijndael's operations are - among the easiest to defend against power and timing attacks. - - The AES specifies three key sizes: 128, 192 and 256 bits - - See for more information. - - In addition to AES cipher algorithm support, the acceleration - for some popular block cipher mode is supported too, including - ECB, CBC, LRW, PCBC, XTS. The 64 bit version has additional - acceleration for CTR. - -config CRYPTO_AES_SPARC64 - tristate "AES cipher algorithms (SPARC64)" - depends on SPARC64 - select CRYPTO_CRYPTD - select CRYPTO_ALGAPI - help - Use SPARC64 crypto opcodes for AES algorithm. - - AES cipher algorithms (FIPS-197). AES uses the Rijndael - algorithm. - - Rijndael appears to be consistently a very good performer in - both hardware and software across a wide range of computing - environments regardless of its use in feedback or non-feedback - modes. Its key setup time is excellent, and its key agility is - good. Rijndael's very low memory requirements make it very well - suited for restricted-space environments, in which it also - demonstrates excellent performance. Rijndael's operations are - among the easiest to defend against power and timing attacks. - - The AES specifies three key sizes: 128, 192 and 256 bits - - See for more information. - - In addition to AES cipher algorithm support, the acceleration - for some popular block cipher mode is supported too, including - ECB and CBC. - -config CRYPTO_AES_PPC_SPE - tristate "AES cipher algorithms (PPC SPE)" - depends on PPC && SPE - help - AES cipher algorithms (FIPS-197). Additionally the acceleration - for popular block cipher modes ECB, CBC, CTR and XTS is supported. - This module should only be used for low power (router) devices - without hardware AES acceleration (e.g. caam crypto). It reduces the - size of the AES tables from 16KB to 8KB + 256 bytes and mitigates - timining attacks. Nevertheless it might be not as secure as other - architecture specific assembler implementations that work on 1KB - tables or 256 bytes S-boxes. - -config CRYPTO_ANUBIS - tristate "Anubis cipher algorithm" - select CRYPTO_ALGAPI - help - Anubis cipher algorithm. - - Anubis is a variable key length cipher which can use keys from - 128 bits to 320 bits in length. It was evaluated as a entrant - in the NESSIE competition. - - See also: - - - -config CRYPTO_ARC4 - tristate "ARC4 cipher algorithm" - select CRYPTO_BLKCIPHER - help - ARC4 cipher algorithm. - - ARC4 is a stream cipher using keys ranging from 8 bits to 2048 - bits in length. This algorithm is required for driver-based - WEP, but it should not be for other purposes because of the - weakness of the algorithm. - -config CRYPTO_BLOWFISH - tristate "Blowfish cipher algorithm" - select CRYPTO_ALGAPI - select CRYPTO_BLOWFISH_COMMON - help - Blowfish cipher algorithm, by Bruce Schneier. - - This is a variable key length cipher which can use keys from 32 - bits to 448 bits in length. It's fast, simple and specifically - designed for use on "large microprocessors". - - See also: - - -config CRYPTO_BLOWFISH_COMMON - tristate - help - Common parts of the Blowfish cipher algorithm shared by the - generic c and the assembler implementations. - - See also: - - -config CRYPTO_BLOWFISH_X86_64 - tristate "Blowfish cipher algorithm (x86_64)" - depends on X86 && 64BIT - select CRYPTO_ALGAPI - select CRYPTO_BLOWFISH_COMMON - help - Blowfish cipher algorithm (x86_64), by Bruce Schneier. - - This is a variable key length cipher which can use keys from 32 - bits to 448 bits in length. It's fast, simple and specifically - designed for use on "large microprocessors". - - See also: - - -config CRYPTO_CAMELLIA - tristate "Camellia cipher algorithms" - depends on CRYPTO - select CRYPTO_ALGAPI - help - Camellia cipher algorithms module. - - Camellia is a symmetric key block cipher developed jointly - at NTT and Mitsubishi Electric Corporation. - - The Camellia specifies three key sizes: 128, 192 and 256 bits. - - See also: - - -config CRYPTO_CAMELLIA_X86_64 - tristate "Camellia cipher algorithm (x86_64)" - depends on X86 && 64BIT - depends on CRYPTO - select CRYPTO_ALGAPI - select CRYPTO_GLUE_HELPER_X86 - select CRYPTO_LRW - select CRYPTO_XTS - help - Camellia cipher algorithm module (x86_64). - - Camellia is a symmetric key block cipher developed jointly - at NTT and Mitsubishi Electric Corporation. - - The Camellia specifies three key sizes: 128, 192 and 256 bits. - - See also: - - -config CRYPTO_CAMELLIA_AESNI_AVX_X86_64 - tristate "Camellia cipher algorithm (x86_64/AES-NI/AVX)" - depends on X86 && 64BIT - depends on CRYPTO - select CRYPTO_ALGAPI - select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER - select CRYPTO_GLUE_HELPER_X86 - select CRYPTO_CAMELLIA_X86_64 - select CRYPTO_LRW - select CRYPTO_XTS - help - Camellia cipher algorithm module (x86_64/AES-NI/AVX). - - Camellia is a symmetric key block cipher developed jointly - at NTT and Mitsubishi Electric Corporation. - - The Camellia specifies three key sizes: 128, 192 and 256 bits. - - See also: - - -config CRYPTO_CAMELLIA_AESNI_AVX2_X86_64 - tristate "Camellia cipher algorithm (x86_64/AES-NI/AVX2)" - depends on X86 && 64BIT - depends on CRYPTO - select CRYPTO_ALGAPI - select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER - select CRYPTO_GLUE_HELPER_X86 - select CRYPTO_CAMELLIA_X86_64 - select CRYPTO_CAMELLIA_AESNI_AVX_X86_64 - select CRYPTO_LRW - select CRYPTO_XTS - help - Camellia cipher algorithm module (x86_64/AES-NI/AVX2). - - Camellia is a symmetric key block cipher developed jointly - at NTT and Mitsubishi Electric Corporation. - - The Camellia specifies three key sizes: 128, 192 and 256 bits. - - See also: - - -config CRYPTO_CAMELLIA_SPARC64 - tristate "Camellia cipher algorithm (SPARC64)" - depends on SPARC64 - depends on CRYPTO - select CRYPTO_ALGAPI - help - Camellia cipher algorithm module (SPARC64). - - Camellia is a symmetric key block cipher developed jointly - at NTT and Mitsubishi Electric Corporation. - - The Camellia specifies three key sizes: 128, 192 and 256 bits. - - See also: - - -config CRYPTO_CAST_COMMON - tristate - help - Common parts of the CAST cipher algorithms shared by the - generic c and the assembler implementations. - -config CRYPTO_CAST5 - tristate "CAST5 (CAST-128) cipher algorithm" - select CRYPTO_ALGAPI - select CRYPTO_CAST_COMMON - help - The CAST5 encryption algorithm (synonymous with CAST-128) is - described in RFC2144. - -config CRYPTO_CAST5_AVX_X86_64 - tristate "CAST5 (CAST-128) cipher algorithm (x86_64/AVX)" - depends on X86 && 64BIT - select CRYPTO_ALGAPI - select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER - select CRYPTO_CAST_COMMON - select CRYPTO_CAST5 - help - The CAST5 encryption algorithm (synonymous with CAST-128) is - described in RFC2144. - - This module provides the Cast5 cipher algorithm that processes - sixteen blocks parallel using the AVX instruction set. - -config CRYPTO_CAST6 - tristate "CAST6 (CAST-256) cipher algorithm" - select CRYPTO_ALGAPI - select CRYPTO_CAST_COMMON - help - The CAST6 encryption algorithm (synonymous with CAST-256) is - described in RFC2612. - -config CRYPTO_CAST6_AVX_X86_64 - tristate "CAST6 (CAST-256) cipher algorithm (x86_64/AVX)" - depends on X86 && 64BIT - select CRYPTO_ALGAPI - select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER - select CRYPTO_GLUE_HELPER_X86 - select CRYPTO_CAST_COMMON - select CRYPTO_CAST6 - select CRYPTO_LRW - select CRYPTO_XTS - help - The CAST6 encryption algorithm (synonymous with CAST-256) is - described in RFC2612. - - This module provides the Cast6 cipher algorithm that processes - eight blocks parallel using the AVX instruction set. - -config CRYPTO_DES - tristate "DES and Triple DES EDE cipher algorithms" - select CRYPTO_ALGAPI - help - DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). - -config CRYPTO_DES_SPARC64 - tristate "DES and Triple DES EDE cipher algorithms (SPARC64)" - depends on SPARC64 - select CRYPTO_ALGAPI - select CRYPTO_DES - help - DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3), - optimized using SPARC64 crypto opcodes. - -config CRYPTO_DES3_EDE_X86_64 - tristate "Triple DES EDE cipher algorithm (x86-64)" - depends on X86 && 64BIT - select CRYPTO_ALGAPI - select CRYPTO_DES - help - Triple DES EDE (FIPS 46-3) algorithm. - - This module provides implementation of the Triple DES EDE cipher - algorithm that is optimized for x86-64 processors. Two versions of - algorithm are provided; regular processing one input block and - one that processes three blocks parallel. - -config CRYPTO_FCRYPT - tristate "FCrypt cipher algorithm" - select CRYPTO_ALGAPI - select CRYPTO_BLKCIPHER - help - FCrypt algorithm used by RxRPC. - -config CRYPTO_KHAZAD - tristate "Khazad cipher algorithm" - select CRYPTO_ALGAPI - help - Khazad cipher algorithm. - - Khazad was a finalist in the initial NESSIE competition. It is - an algorithm optimized for 64-bit processors with good performance - on 32-bit processors. Khazad uses an 128 bit key size. - - See also: - - -config CRYPTO_SALSA20 - tristate "Salsa20 stream cipher algorithm" - select CRYPTO_BLKCIPHER - help - Salsa20 stream cipher algorithm. - - Salsa20 is a stream cipher submitted to eSTREAM, the ECRYPT - Stream Cipher Project. See - - The Salsa20 stream cipher algorithm is designed by Daniel J. - Bernstein . See - -config CRYPTO_SALSA20_586 - tristate "Salsa20 stream cipher algorithm (i586)" - depends on (X86 || UML_X86) && !64BIT - select CRYPTO_BLKCIPHER - help - Salsa20 stream cipher algorithm. - - Salsa20 is a stream cipher submitted to eSTREAM, the ECRYPT - Stream Cipher Project. See - - The Salsa20 stream cipher algorithm is designed by Daniel J. - Bernstein . See - -config CRYPTO_SALSA20_X86_64 - tristate "Salsa20 stream cipher algorithm (x86_64)" - depends on (X86 || UML_X86) && 64BIT - select CRYPTO_BLKCIPHER - help - Salsa20 stream cipher algorithm. - - Salsa20 is a stream cipher submitted to eSTREAM, the ECRYPT - Stream Cipher Project. See - - The Salsa20 stream cipher algorithm is designed by Daniel J. - Bernstein . See - -config CRYPTO_CHACHA20 - tristate "ChaCha20 cipher algorithm" - select CRYPTO_BLKCIPHER - help - ChaCha20 cipher algorithm, RFC7539. - - ChaCha20 is a 256-bit high-speed stream cipher designed by Daniel J. - Bernstein and further specified in RFC7539 for use in IETF protocols. - This is the portable C implementation of ChaCha20. - - See also: - - -config CRYPTO_CHACHA20_X86_64 - tristate "ChaCha20 cipher algorithm (x86_64/SSSE3/AVX2)" - depends on X86 && 64BIT - select CRYPTO_BLKCIPHER - select CRYPTO_CHACHA20 - help - ChaCha20 cipher algorithm, RFC7539. - - ChaCha20 is a 256-bit high-speed stream cipher designed by Daniel J. - Bernstein and further specified in RFC7539 for use in IETF protocols. - This is the x86_64 assembler implementation using SIMD instructions. - - See also: - - -config CRYPTO_SEED - tristate "SEED cipher algorithm" - select CRYPTO_ALGAPI - help - SEED cipher algorithm (RFC4269). - - SEED is a 128-bit symmetric key block cipher that has been - developed by KISA (Korea Information Security Agency) as a - national standard encryption algorithm of the Republic of Korea. - It is a 16 round block cipher with the key size of 128 bit. - - See also: - - -config CRYPTO_SERPENT - tristate "Serpent cipher algorithm" - select CRYPTO_ALGAPI - help - Serpent cipher algorithm, by Anderson, Biham & Knudsen. - - Keys are allowed to be from 0 to 256 bits in length, in steps - of 8 bits. Also includes the 'Tnepres' algorithm, a reversed - variant of Serpent for compatibility with old kerneli.org code. - - See also: - - -config CRYPTO_SERPENT_SSE2_X86_64 - tristate "Serpent cipher algorithm (x86_64/SSE2)" - depends on X86 && 64BIT - select CRYPTO_ALGAPI - select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER - select CRYPTO_GLUE_HELPER_X86 - select CRYPTO_SERPENT - select CRYPTO_LRW - select CRYPTO_XTS - help - Serpent cipher algorithm, by Anderson, Biham & Knudsen. - - Keys are allowed to be from 0 to 256 bits in length, in steps - of 8 bits. - - This module provides Serpent cipher algorithm that processes eight - blocks parallel using SSE2 instruction set. - - See also: - - -config CRYPTO_SERPENT_SSE2_586 - tristate "Serpent cipher algorithm (i586/SSE2)" - depends on X86 && !64BIT - select CRYPTO_ALGAPI - select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER - select CRYPTO_GLUE_HELPER_X86 - select CRYPTO_SERPENT - select CRYPTO_LRW - select CRYPTO_XTS - help - Serpent cipher algorithm, by Anderson, Biham & Knudsen. - - Keys are allowed to be from 0 to 256 bits in length, in steps - of 8 bits. - - This module provides Serpent cipher algorithm that processes four - blocks parallel using SSE2 instruction set. - - See also: - - -config CRYPTO_SERPENT_AVX_X86_64 - tristate "Serpent cipher algorithm (x86_64/AVX)" - depends on X86 && 64BIT - select CRYPTO_ALGAPI - select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER - select CRYPTO_GLUE_HELPER_X86 - select CRYPTO_SERPENT - select CRYPTO_LRW - select CRYPTO_XTS - help - Serpent cipher algorithm, by Anderson, Biham & Knudsen. - - Keys are allowed to be from 0 to 256 bits in length, in steps - of 8 bits. - - This module provides the Serpent cipher algorithm that processes - eight blocks parallel using the AVX instruction set. - - See also: - - -config CRYPTO_SERPENT_AVX2_X86_64 - tristate "Serpent cipher algorithm (x86_64/AVX2)" - depends on X86 && 64BIT - select CRYPTO_ALGAPI - select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER - select CRYPTO_GLUE_HELPER_X86 - select CRYPTO_SERPENT - select CRYPTO_SERPENT_AVX_X86_64 - select CRYPTO_LRW - select CRYPTO_XTS - help - Serpent cipher algorithm, by Anderson, Biham & Knudsen. - - Keys are allowed to be from 0 to 256 bits in length, in steps - of 8 bits. - - This module provides Serpent cipher algorithm that processes 16 - blocks parallel using AVX2 instruction set. - - See also: - - -config CRYPTO_TEA - tristate "TEA, XTEA and XETA cipher algorithms" - select CRYPTO_ALGAPI - help - TEA cipher algorithm. - - Tiny Encryption Algorithm is a simple cipher that uses - many rounds for security. It is very fast and uses - little memory. - - Xtendend Tiny Encryption Algorithm is a modification to - the TEA algorithm to address a potential key weakness - in the TEA algorithm. - - Xtendend Encryption Tiny Algorithm is a mis-implementation - of the XTEA algorithm for compatibility purposes. - -config CRYPTO_TWOFISH - tristate "Twofish cipher algorithm" - select CRYPTO_ALGAPI - select CRYPTO_TWOFISH_COMMON - help - Twofish cipher algorithm. - - Twofish was submitted as an AES (Advanced Encryption Standard) - candidate cipher by researchers at CounterPane Systems. It is a - 16 round block cipher supporting key sizes of 128, 192, and 256 - bits. - - See also: - - -config CRYPTO_TWOFISH_COMMON - tristate - help - Common parts of the Twofish cipher algorithm shared by the - generic c and the assembler implementations. - -config CRYPTO_TWOFISH_586 - tristate "Twofish cipher algorithms (i586)" - depends on (X86 || UML_X86) && !64BIT - select CRYPTO_ALGAPI - select CRYPTO_TWOFISH_COMMON - help - Twofish cipher algorithm. - - Twofish was submitted as an AES (Advanced Encryption Standard) - candidate cipher by researchers at CounterPane Systems. It is a - 16 round block cipher supporting key sizes of 128, 192, and 256 - bits. - - See also: - - -config CRYPTO_TWOFISH_X86_64 - tristate "Twofish cipher algorithm (x86_64)" - depends on (X86 || UML_X86) && 64BIT - select CRYPTO_ALGAPI - select CRYPTO_TWOFISH_COMMON - help - Twofish cipher algorithm (x86_64). - - Twofish was submitted as an AES (Advanced Encryption Standard) - candidate cipher by researchers at CounterPane Systems. It is a - 16 round block cipher supporting key sizes of 128, 192, and 256 - bits. - - See also: - - -config CRYPTO_TWOFISH_X86_64_3WAY - tristate "Twofish cipher algorithm (x86_64, 3-way parallel)" - depends on X86 && 64BIT - select CRYPTO_ALGAPI - select CRYPTO_TWOFISH_COMMON - select CRYPTO_TWOFISH_X86_64 - select CRYPTO_GLUE_HELPER_X86 - select CRYPTO_LRW - select CRYPTO_XTS - help - Twofish cipher algorithm (x86_64, 3-way parallel). - - Twofish was submitted as an AES (Advanced Encryption Standard) - candidate cipher by researchers at CounterPane Systems. It is a - 16 round block cipher supporting key sizes of 128, 192, and 256 - bits. - - This module provides Twofish cipher algorithm that processes three - blocks parallel, utilizing resources of out-of-order CPUs better. - - See also: - - -config CRYPTO_TWOFISH_AVX_X86_64 - tristate "Twofish cipher algorithm (x86_64/AVX)" - depends on X86 && 64BIT - select CRYPTO_ALGAPI - select CRYPTO_CRYPTD - select CRYPTO_ABLK_HELPER - select CRYPTO_GLUE_HELPER_X86 - select CRYPTO_TWOFISH_COMMON - select CRYPTO_TWOFISH_X86_64 - select CRYPTO_TWOFISH_X86_64_3WAY - select CRYPTO_LRW - select CRYPTO_XTS - help - Twofish cipher algorithm (x86_64/AVX). - - Twofish was submitted as an AES (Advanced Encryption Standard) - candidate cipher by researchers at CounterPane Systems. It is a - 16 round block cipher supporting key sizes of 128, 192, and 256 - bits. - - This module provides the Twofish cipher algorithm that processes - eight blocks parallel using the AVX Instruction Set. - - See also: - - -comment "Compression" - -config CRYPTO_DEFLATE - tristate "Deflate compression algorithm" - select CRYPTO_ALGAPI - select ZLIB_INFLATE - select ZLIB_DEFLATE - help - This is the Deflate algorithm (RFC1951), specified for use in - IPSec with the IPCOMP protocol (RFC3173, RFC2394). - - You will most probably want this if using IPSec. - -config CRYPTO_LZO - tristate "LZO compression algorithm" - select CRYPTO_ALGAPI - select LZO_COMPRESS - select LZO_DECOMPRESS - help - This is the LZO algorithm. - -config CRYPTO_842 - tristate "842 compression algorithm" - select CRYPTO_ALGAPI - select 842_COMPRESS - select 842_DECOMPRESS - help - This is the 842 algorithm. - -config CRYPTO_LZ4 - tristate "LZ4 compression algorithm" - select CRYPTO_ALGAPI - select LZ4_COMPRESS - select LZ4_DECOMPRESS - help - This is the LZ4 algorithm. - -config CRYPTO_LZ4HC - tristate "LZ4HC compression algorithm" - select CRYPTO_ALGAPI - select LZ4HC_COMPRESS - select LZ4_DECOMPRESS - help - This is the LZ4 high compression mode algorithm. - -comment "Random Number Generation" - -config CRYPTO_ANSI_CPRNG - tristate "Pseudo Random Number Generation for Cryptographic modules" - select CRYPTO_AES - select CRYPTO_RNG - help - This option enables the generic pseudo random number generator - for cryptographic modules. Uses the Algorithm specified in - ANSI X9.31 A.2.4. Note that this option must be enabled if - CRYPTO_FIPS is selected - -menuconfig CRYPTO_DRBG_MENU - tristate "NIST SP800-90A DRBG" - help - NIST SP800-90A compliant DRBG. In the following submenu, one or - more of the DRBG types must be selected. - -if CRYPTO_DRBG_MENU - -config CRYPTO_DRBG_HMAC - bool - default y - select CRYPTO_HMAC - select CRYPTO_SHA256 - -config CRYPTO_DRBG_HASH - bool "Enable Hash DRBG" - select CRYPTO_SHA256 - help - Enable the Hash DRBG variant as defined in NIST SP800-90A. - -config CRYPTO_DRBG_CTR - bool "Enable CTR DRBG" - select CRYPTO_AES - depends on CRYPTO_CTR - help - Enable the CTR DRBG variant as defined in NIST SP800-90A. - -config CRYPTO_DRBG - tristate - default CRYPTO_DRBG_MENU - select CRYPTO_RNG - select CRYPTO_JITTERENTROPY - -endif # if CRYPTO_DRBG_MENU - -config CRYPTO_JITTERENTROPY - tristate "Jitterentropy Non-Deterministic Random Number Generator" - select CRYPTO_RNG - help - The Jitterentropy RNG is a noise that is intended - to provide seed to another RNG. The RNG does not - perform any cryptographic whitening of the generated - random numbers. This Jitterentropy RNG registers with - the kernel crypto API and can be used by any caller. - -config CRYPTO_USER_API - tristate - -config CRYPTO_USER_API_HASH - tristate "User-space interface for hash algorithms" - depends on NET - select CRYPTO_HASH - select CRYPTO_USER_API - help - This option enables the user-spaces interface for hash - algorithms. - -config CRYPTO_USER_API_SKCIPHER - tristate "User-space interface for symmetric key cipher algorithms" - depends on NET - select CRYPTO_BLKCIPHER - select CRYPTO_USER_API - help - This option enables the user-spaces interface for symmetric - key cipher algorithms. - -config CRYPTO_USER_API_RNG - tristate "User-space interface for random number generator algorithms" - depends on NET - select CRYPTO_RNG - select CRYPTO_USER_API - help - This option enables the user-spaces interface for random - number generator algorithms. - -config CRYPTO_USER_API_AEAD - tristate "User-space interface for AEAD cipher algorithms" - depends on NET - select CRYPTO_AEAD - select CRYPTO_USER_API - help - This option enables the user-spaces interface for AEAD - cipher algorithms. - -config CRYPTO_HASH_INFO - bool - -source "drivers/crypto/Kconfig" -source crypto/asymmetric_keys/Kconfig -source certs/Kconfig - -endif # if CRYPTO diff --git a/src/linux/crypto/Makefile b/src/linux/crypto/Makefile deleted file mode 100644 index bd6a029..0000000 --- a/src/linux/crypto/Makefile +++ /dev/null @@ -1,141 +0,0 @@ -# -# Cryptographic API -# - -obj-$(CONFIG_CRYPTO) += crypto.o -crypto-y := api.o cipher.o compress.o memneq.o - -obj-$(CONFIG_CRYPTO_WORKQUEUE) += crypto_wq.o - -obj-$(CONFIG_CRYPTO_ENGINE) += crypto_engine.o -obj-$(CONFIG_CRYPTO_FIPS) += fips.o - -crypto_algapi-$(CONFIG_PROC_FS) += proc.o -crypto_algapi-y := algapi.o scatterwalk.o $(crypto_algapi-y) -obj-$(CONFIG_CRYPTO_ALGAPI2) += crypto_algapi.o - -obj-$(CONFIG_CRYPTO_AEAD2) += aead.o - -crypto_blkcipher-y := ablkcipher.o -crypto_blkcipher-y += blkcipher.o -crypto_blkcipher-y += skcipher.o -obj-$(CONFIG_CRYPTO_BLKCIPHER2) += crypto_blkcipher.o -obj-$(CONFIG_CRYPTO_SEQIV) += seqiv.o -obj-$(CONFIG_CRYPTO_ECHAINIV) += echainiv.o - -crypto_hash-y += ahash.o -crypto_hash-y += shash.o -obj-$(CONFIG_CRYPTO_HASH2) += crypto_hash.o - -obj-$(CONFIG_CRYPTO_AKCIPHER2) += akcipher.o -obj-$(CONFIG_CRYPTO_KPP2) += kpp.o - -dh_generic-y := dh.o -dh_generic-y += dh_helper.o -obj-$(CONFIG_CRYPTO_DH) += dh_generic.o -ecdh_generic-y := ecc.o -ecdh_generic-y += ecdh.o -ecdh_generic-y += ecdh_helper.o -obj-$(CONFIG_CRYPTO_ECDH) += ecdh_generic.o - -$(obj)/rsapubkey-asn1.o: $(obj)/rsapubkey-asn1.c $(obj)/rsapubkey-asn1.h -$(obj)/rsaprivkey-asn1.o: $(obj)/rsaprivkey-asn1.c $(obj)/rsaprivkey-asn1.h -$(obj)/rsa_helper.o: $(obj)/rsapubkey-asn1.h $(obj)/rsaprivkey-asn1.h -clean-files += rsapubkey-asn1.c rsapubkey-asn1.h -clean-files += rsaprivkey-asn1.c rsaprivkey-asn1.h - -rsa_generic-y := rsapubkey-asn1.o -rsa_generic-y += rsaprivkey-asn1.o -rsa_generic-y += rsa.o -rsa_generic-y += rsa_helper.o -rsa_generic-y += rsa-pkcs1pad.o -obj-$(CONFIG_CRYPTO_RSA) += rsa_generic.o - -cryptomgr-y := algboss.o testmgr.o - -obj-$(CONFIG_CRYPTO_MANAGER2) += cryptomgr.o -obj-$(CONFIG_CRYPTO_USER) += crypto_user.o -obj-$(CONFIG_CRYPTO_CMAC) += cmac.o -obj-$(CONFIG_CRYPTO_HMAC) += hmac.o -obj-$(CONFIG_CRYPTO_VMAC) += vmac.o -obj-$(CONFIG_CRYPTO_XCBC) += xcbc.o -obj-$(CONFIG_CRYPTO_NULL2) += crypto_null.o -obj-$(CONFIG_CRYPTO_MD4) += md4.o -obj-$(CONFIG_CRYPTO_MD5) += md5.o -obj-$(CONFIG_CRYPTO_RMD128) += rmd128.o -obj-$(CONFIG_CRYPTO_RMD160) += rmd160.o -obj-$(CONFIG_CRYPTO_RMD256) += rmd256.o -obj-$(CONFIG_CRYPTO_RMD320) += rmd320.o -obj-$(CONFIG_CRYPTO_SHA1) += sha1_generic.o -obj-$(CONFIG_CRYPTO_SHA256) += sha256_generic.o -obj-$(CONFIG_CRYPTO_SHA512) += sha512_generic.o -obj-$(CONFIG_CRYPTO_SHA3) += sha3_generic.o -obj-$(CONFIG_CRYPTO_WP512) += wp512.o -obj-$(CONFIG_CRYPTO_TGR192) += tgr192.o -obj-$(CONFIG_CRYPTO_GF128MUL) += gf128mul.o -obj-$(CONFIG_CRYPTO_ECB) += ecb.o -obj-$(CONFIG_CRYPTO_CBC) += cbc.o -obj-$(CONFIG_CRYPTO_PCBC) += pcbc.o -obj-$(CONFIG_CRYPTO_CTS) += cts.o -obj-$(CONFIG_CRYPTO_LRW) += lrw.o -obj-$(CONFIG_CRYPTO_XTS) += xts.o -obj-$(CONFIG_CRYPTO_CTR) += ctr.o -obj-$(CONFIG_CRYPTO_KEYWRAP) += keywrap.o -obj-$(CONFIG_CRYPTO_GCM) += gcm.o -obj-$(CONFIG_CRYPTO_CCM) += ccm.o -obj-$(CONFIG_CRYPTO_CHACHA20POLY1305) += chacha20poly1305.o -obj-$(CONFIG_CRYPTO_PCRYPT) += pcrypt.o -obj-$(CONFIG_CRYPTO_CRYPTD) += cryptd.o -obj-$(CONFIG_CRYPTO_MCRYPTD) += mcryptd.o -obj-$(CONFIG_CRYPTO_DES) += des_generic.o -obj-$(CONFIG_CRYPTO_FCRYPT) += fcrypt.o -obj-$(CONFIG_CRYPTO_BLOWFISH) += blowfish_generic.o -obj-$(CONFIG_CRYPTO_BLOWFISH_COMMON) += blowfish_common.o -obj-$(CONFIG_CRYPTO_TWOFISH) += twofish_generic.o -obj-$(CONFIG_CRYPTO_TWOFISH_COMMON) += twofish_common.o -obj-$(CONFIG_CRYPTO_SERPENT) += serpent_generic.o -obj-$(CONFIG_CRYPTO_AES) += aes_generic.o -obj-$(CONFIG_CRYPTO_CAMELLIA) += camellia_generic.o -obj-$(CONFIG_CRYPTO_CAST_COMMON) += cast_common.o -obj-$(CONFIG_CRYPTO_CAST5) += cast5_generic.o -obj-$(CONFIG_CRYPTO_CAST6) += cast6_generic.o -obj-$(CONFIG_CRYPTO_ARC4) += arc4.o -obj-$(CONFIG_CRYPTO_TEA) += tea.o -obj-$(CONFIG_CRYPTO_KHAZAD) += khazad.o -obj-$(CONFIG_CRYPTO_ANUBIS) += anubis.o -obj-$(CONFIG_CRYPTO_SEED) += seed.o -obj-$(CONFIG_CRYPTO_SALSA20) += salsa20_generic.o -obj-$(CONFIG_CRYPTO_CHACHA20) += chacha20_generic.o -obj-$(CONFIG_CRYPTO_POLY1305) += poly1305_generic.o -obj-$(CONFIG_CRYPTO_DEFLATE) += deflate.o -obj-$(CONFIG_CRYPTO_MICHAEL_MIC) += michael_mic.o -obj-$(CONFIG_CRYPTO_CRC32C) += crc32c_generic.o -obj-$(CONFIG_CRYPTO_CRC32) += crc32_generic.o -obj-$(CONFIG_CRYPTO_CRCT10DIF) += crct10dif_common.o crct10dif_generic.o -obj-$(CONFIG_CRYPTO_AUTHENC) += authenc.o authencesn.o -obj-$(CONFIG_CRYPTO_LZO) += lzo.o -obj-$(CONFIG_CRYPTO_LZ4) += lz4.o -obj-$(CONFIG_CRYPTO_LZ4HC) += lz4hc.o -obj-$(CONFIG_CRYPTO_842) += 842.o -obj-$(CONFIG_CRYPTO_RNG2) += rng.o -obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_cprng.o -obj-$(CONFIG_CRYPTO_DRBG) += drbg.o -obj-$(CONFIG_CRYPTO_JITTERENTROPY) += jitterentropy_rng.o -CFLAGS_jitterentropy.o = -O0 -jitterentropy_rng-y := jitterentropy.o jitterentropy-kcapi.o -obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o -obj-$(CONFIG_CRYPTO_GHASH) += ghash-generic.o -obj-$(CONFIG_CRYPTO_USER_API) += af_alg.o -obj-$(CONFIG_CRYPTO_USER_API_HASH) += algif_hash.o -obj-$(CONFIG_CRYPTO_USER_API_SKCIPHER) += algif_skcipher.o -obj-$(CONFIG_CRYPTO_USER_API_RNG) += algif_rng.o -obj-$(CONFIG_CRYPTO_USER_API_AEAD) += algif_aead.o - -# -# generic algorithms and the async_tx api -# -obj-$(CONFIG_XOR_BLOCKS) += xor.o -obj-$(CONFIG_ASYNC_CORE) += async_tx/ -obj-$(CONFIG_ASYMMETRIC_KEY_TYPE) += asymmetric_keys/ -obj-$(CONFIG_CRYPTO_HASH_INFO) += hash_info.o -obj-$(CONFIG_CRYPTO_ABLK_HELPER) += ablk_helper.o diff --git a/src/linux/crypto/ablkcipher.c b/src/linux/crypto/ablkcipher.c deleted file mode 100644 index d676fc5..0000000 --- a/src/linux/crypto/ablkcipher.c +++ /dev/null @@ -1,494 +0,0 @@ -/* - * Asynchronous block chaining cipher operations. - * - * This is the asynchronous version of blkcipher.c indicating completion - * via a callback. - * - * Copyright (c) 2006 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "internal.h" - -struct ablkcipher_buffer { - struct list_head entry; - struct scatter_walk dst; - unsigned int len; - void *data; -}; - -enum { - ABLKCIPHER_WALK_SLOW = 1 << 0, -}; - -static inline void ablkcipher_buffer_write(struct ablkcipher_buffer *p) -{ - scatterwalk_copychunks(p->data, &p->dst, p->len, 1); -} - -void __ablkcipher_walk_complete(struct ablkcipher_walk *walk) -{ - struct ablkcipher_buffer *p, *tmp; - - list_for_each_entry_safe(p, tmp, &walk->buffers, entry) { - ablkcipher_buffer_write(p); - list_del(&p->entry); - kfree(p); - } -} -EXPORT_SYMBOL_GPL(__ablkcipher_walk_complete); - -static inline void ablkcipher_queue_write(struct ablkcipher_walk *walk, - struct ablkcipher_buffer *p) -{ - p->dst = walk->out; - list_add_tail(&p->entry, &walk->buffers); -} - -/* Get a spot of the specified length that does not straddle a page. - * The caller needs to ensure that there is enough space for this operation. - */ -static inline u8 *ablkcipher_get_spot(u8 *start, unsigned int len) -{ - u8 *end_page = (u8 *)(((unsigned long)(start + len - 1)) & PAGE_MASK); - - return max(start, end_page); -} - -static inline unsigned int ablkcipher_done_slow(struct ablkcipher_walk *walk, - unsigned int bsize) -{ - unsigned int n = bsize; - - for (;;) { - unsigned int len_this_page = scatterwalk_pagelen(&walk->out); - - if (len_this_page > n) - len_this_page = n; - scatterwalk_advance(&walk->out, n); - if (n == len_this_page) - break; - n -= len_this_page; - scatterwalk_start(&walk->out, sg_next(walk->out.sg)); - } - - return bsize; -} - -static inline unsigned int ablkcipher_done_fast(struct ablkcipher_walk *walk, - unsigned int n) -{ - scatterwalk_advance(&walk->in, n); - scatterwalk_advance(&walk->out, n); - - return n; -} - -static int ablkcipher_walk_next(struct ablkcipher_request *req, - struct ablkcipher_walk *walk); - -int ablkcipher_walk_done(struct ablkcipher_request *req, - struct ablkcipher_walk *walk, int err) -{ - struct crypto_tfm *tfm = req->base.tfm; - unsigned int nbytes = 0; - - if (likely(err >= 0)) { - unsigned int n = walk->nbytes - err; - - if (likely(!(walk->flags & ABLKCIPHER_WALK_SLOW))) - n = ablkcipher_done_fast(walk, n); - else if (WARN_ON(err)) { - err = -EINVAL; - goto err; - } else - n = ablkcipher_done_slow(walk, n); - - nbytes = walk->total - n; - err = 0; - } - - scatterwalk_done(&walk->in, 0, nbytes); - scatterwalk_done(&walk->out, 1, nbytes); - -err: - walk->total = nbytes; - walk->nbytes = nbytes; - - if (nbytes) { - crypto_yield(req->base.flags); - return ablkcipher_walk_next(req, walk); - } - - if (walk->iv != req->info) - memcpy(req->info, walk->iv, tfm->crt_ablkcipher.ivsize); - kfree(walk->iv_buffer); - - return err; -} -EXPORT_SYMBOL_GPL(ablkcipher_walk_done); - -static inline int ablkcipher_next_slow(struct ablkcipher_request *req, - struct ablkcipher_walk *walk, - unsigned int bsize, - unsigned int alignmask, - void **src_p, void **dst_p) -{ - unsigned aligned_bsize = ALIGN(bsize, alignmask + 1); - struct ablkcipher_buffer *p; - void *src, *dst, *base; - unsigned int n; - - n = ALIGN(sizeof(struct ablkcipher_buffer), alignmask + 1); - n += (aligned_bsize * 3 - (alignmask + 1) + - (alignmask & ~(crypto_tfm_ctx_alignment() - 1))); - - p = kmalloc(n, GFP_ATOMIC); - if (!p) - return ablkcipher_walk_done(req, walk, -ENOMEM); - - base = p + 1; - - dst = (u8 *)ALIGN((unsigned long)base, alignmask + 1); - src = dst = ablkcipher_get_spot(dst, bsize); - - p->len = bsize; - p->data = dst; - - scatterwalk_copychunks(src, &walk->in, bsize, 0); - - ablkcipher_queue_write(walk, p); - - walk->nbytes = bsize; - walk->flags |= ABLKCIPHER_WALK_SLOW; - - *src_p = src; - *dst_p = dst; - - return 0; -} - -static inline int ablkcipher_copy_iv(struct ablkcipher_walk *walk, - struct crypto_tfm *tfm, - unsigned int alignmask) -{ - unsigned bs = walk->blocksize; - unsigned int ivsize = tfm->crt_ablkcipher.ivsize; - unsigned aligned_bs = ALIGN(bs, alignmask + 1); - unsigned int size = aligned_bs * 2 + ivsize + max(aligned_bs, ivsize) - - (alignmask + 1); - u8 *iv; - - size += alignmask & ~(crypto_tfm_ctx_alignment() - 1); - walk->iv_buffer = kmalloc(size, GFP_ATOMIC); - if (!walk->iv_buffer) - return -ENOMEM; - - iv = (u8 *)ALIGN((unsigned long)walk->iv_buffer, alignmask + 1); - iv = ablkcipher_get_spot(iv, bs) + aligned_bs; - iv = ablkcipher_get_spot(iv, bs) + aligned_bs; - iv = ablkcipher_get_spot(iv, ivsize); - - walk->iv = memcpy(iv, walk->iv, ivsize); - return 0; -} - -static inline int ablkcipher_next_fast(struct ablkcipher_request *req, - struct ablkcipher_walk *walk) -{ - walk->src.page = scatterwalk_page(&walk->in); - walk->src.offset = offset_in_page(walk->in.offset); - walk->dst.page = scatterwalk_page(&walk->out); - walk->dst.offset = offset_in_page(walk->out.offset); - - return 0; -} - -static int ablkcipher_walk_next(struct ablkcipher_request *req, - struct ablkcipher_walk *walk) -{ - struct crypto_tfm *tfm = req->base.tfm; - unsigned int alignmask, bsize, n; - void *src, *dst; - int err; - - alignmask = crypto_tfm_alg_alignmask(tfm); - n = walk->total; - if (unlikely(n < crypto_tfm_alg_blocksize(tfm))) { - req->base.flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN; - return ablkcipher_walk_done(req, walk, -EINVAL); - } - - walk->flags &= ~ABLKCIPHER_WALK_SLOW; - src = dst = NULL; - - bsize = min(walk->blocksize, n); - n = scatterwalk_clamp(&walk->in, n); - n = scatterwalk_clamp(&walk->out, n); - - if (n < bsize || - !scatterwalk_aligned(&walk->in, alignmask) || - !scatterwalk_aligned(&walk->out, alignmask)) { - err = ablkcipher_next_slow(req, walk, bsize, alignmask, - &src, &dst); - goto set_phys_lowmem; - } - - walk->nbytes = n; - - return ablkcipher_next_fast(req, walk); - -set_phys_lowmem: - if (err >= 0) { - walk->src.page = virt_to_page(src); - walk->dst.page = virt_to_page(dst); - walk->src.offset = ((unsigned long)src & (PAGE_SIZE - 1)); - walk->dst.offset = ((unsigned long)dst & (PAGE_SIZE - 1)); - } - - return err; -} - -static int ablkcipher_walk_first(struct ablkcipher_request *req, - struct ablkcipher_walk *walk) -{ - struct crypto_tfm *tfm = req->base.tfm; - unsigned int alignmask; - - alignmask = crypto_tfm_alg_alignmask(tfm); - if (WARN_ON_ONCE(in_irq())) - return -EDEADLK; - - walk->iv = req->info; - walk->nbytes = walk->total; - if (unlikely(!walk->total)) - return 0; - - walk->iv_buffer = NULL; - if (unlikely(((unsigned long)walk->iv & alignmask))) { - int err = ablkcipher_copy_iv(walk, tfm, alignmask); - - if (err) - return err; - } - - scatterwalk_start(&walk->in, walk->in.sg); - scatterwalk_start(&walk->out, walk->out.sg); - - return ablkcipher_walk_next(req, walk); -} - -int ablkcipher_walk_phys(struct ablkcipher_request *req, - struct ablkcipher_walk *walk) -{ - walk->blocksize = crypto_tfm_alg_blocksize(req->base.tfm); - return ablkcipher_walk_first(req, walk); -} -EXPORT_SYMBOL_GPL(ablkcipher_walk_phys); - -static int setkey_unaligned(struct crypto_ablkcipher *tfm, const u8 *key, - unsigned int keylen) -{ - struct ablkcipher_alg *cipher = crypto_ablkcipher_alg(tfm); - unsigned long alignmask = crypto_ablkcipher_alignmask(tfm); - int ret; - u8 *buffer, *alignbuffer; - unsigned long absize; - - absize = keylen + alignmask; - buffer = kmalloc(absize, GFP_ATOMIC); - if (!buffer) - return -ENOMEM; - - alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); - memcpy(alignbuffer, key, keylen); - ret = cipher->setkey(tfm, alignbuffer, keylen); - memset(alignbuffer, 0, keylen); - kfree(buffer); - return ret; -} - -static int setkey(struct crypto_ablkcipher *tfm, const u8 *key, - unsigned int keylen) -{ - struct ablkcipher_alg *cipher = crypto_ablkcipher_alg(tfm); - unsigned long alignmask = crypto_ablkcipher_alignmask(tfm); - - if (keylen < cipher->min_keysize || keylen > cipher->max_keysize) { - crypto_ablkcipher_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - - if ((unsigned long)key & alignmask) - return setkey_unaligned(tfm, key, keylen); - - return cipher->setkey(tfm, key, keylen); -} - -static unsigned int crypto_ablkcipher_ctxsize(struct crypto_alg *alg, u32 type, - u32 mask) -{ - return alg->cra_ctxsize; -} - -static int crypto_init_ablkcipher_ops(struct crypto_tfm *tfm, u32 type, - u32 mask) -{ - struct ablkcipher_alg *alg = &tfm->__crt_alg->cra_ablkcipher; - struct ablkcipher_tfm *crt = &tfm->crt_ablkcipher; - - if (alg->ivsize > PAGE_SIZE / 8) - return -EINVAL; - - crt->setkey = setkey; - crt->encrypt = alg->encrypt; - crt->decrypt = alg->decrypt; - crt->base = __crypto_ablkcipher_cast(tfm); - crt->ivsize = alg->ivsize; - - return 0; -} - -#ifdef CONFIG_NET -static int crypto_ablkcipher_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - struct crypto_report_blkcipher rblkcipher; - - strncpy(rblkcipher.type, "ablkcipher", sizeof(rblkcipher.type)); - strncpy(rblkcipher.geniv, alg->cra_ablkcipher.geniv ?: "", - sizeof(rblkcipher.geniv)); - - rblkcipher.blocksize = alg->cra_blocksize; - rblkcipher.min_keysize = alg->cra_ablkcipher.min_keysize; - rblkcipher.max_keysize = alg->cra_ablkcipher.max_keysize; - rblkcipher.ivsize = alg->cra_ablkcipher.ivsize; - - if (nla_put(skb, CRYPTOCFGA_REPORT_BLKCIPHER, - sizeof(struct crypto_report_blkcipher), &rblkcipher)) - goto nla_put_failure; - return 0; - -nla_put_failure: - return -EMSGSIZE; -} -#else -static int crypto_ablkcipher_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif - -static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg) - __attribute__ ((unused)); -static void crypto_ablkcipher_show(struct seq_file *m, struct crypto_alg *alg) -{ - struct ablkcipher_alg *ablkcipher = &alg->cra_ablkcipher; - - seq_printf(m, "type : ablkcipher\n"); - seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? - "yes" : "no"); - seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); - seq_printf(m, "min keysize : %u\n", ablkcipher->min_keysize); - seq_printf(m, "max keysize : %u\n", ablkcipher->max_keysize); - seq_printf(m, "ivsize : %u\n", ablkcipher->ivsize); - seq_printf(m, "geniv : %s\n", ablkcipher->geniv ?: ""); -} - -const struct crypto_type crypto_ablkcipher_type = { - .ctxsize = crypto_ablkcipher_ctxsize, - .init = crypto_init_ablkcipher_ops, -#ifdef CONFIG_PROC_FS - .show = crypto_ablkcipher_show, -#endif - .report = crypto_ablkcipher_report, -}; -EXPORT_SYMBOL_GPL(crypto_ablkcipher_type); - -static int crypto_init_givcipher_ops(struct crypto_tfm *tfm, u32 type, - u32 mask) -{ - struct ablkcipher_alg *alg = &tfm->__crt_alg->cra_ablkcipher; - struct ablkcipher_tfm *crt = &tfm->crt_ablkcipher; - - if (alg->ivsize > PAGE_SIZE / 8) - return -EINVAL; - - crt->setkey = tfm->__crt_alg->cra_flags & CRYPTO_ALG_GENIV ? - alg->setkey : setkey; - crt->encrypt = alg->encrypt; - crt->decrypt = alg->decrypt; - crt->base = __crypto_ablkcipher_cast(tfm); - crt->ivsize = alg->ivsize; - - return 0; -} - -#ifdef CONFIG_NET -static int crypto_givcipher_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - struct crypto_report_blkcipher rblkcipher; - - strncpy(rblkcipher.type, "givcipher", sizeof(rblkcipher.type)); - strncpy(rblkcipher.geniv, alg->cra_ablkcipher.geniv ?: "", - sizeof(rblkcipher.geniv)); - - rblkcipher.blocksize = alg->cra_blocksize; - rblkcipher.min_keysize = alg->cra_ablkcipher.min_keysize; - rblkcipher.max_keysize = alg->cra_ablkcipher.max_keysize; - rblkcipher.ivsize = alg->cra_ablkcipher.ivsize; - - if (nla_put(skb, CRYPTOCFGA_REPORT_BLKCIPHER, - sizeof(struct crypto_report_blkcipher), &rblkcipher)) - goto nla_put_failure; - return 0; - -nla_put_failure: - return -EMSGSIZE; -} -#else -static int crypto_givcipher_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif - -static void crypto_givcipher_show(struct seq_file *m, struct crypto_alg *alg) - __attribute__ ((unused)); -static void crypto_givcipher_show(struct seq_file *m, struct crypto_alg *alg) -{ - struct ablkcipher_alg *ablkcipher = &alg->cra_ablkcipher; - - seq_printf(m, "type : givcipher\n"); - seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? - "yes" : "no"); - seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); - seq_printf(m, "min keysize : %u\n", ablkcipher->min_keysize); - seq_printf(m, "max keysize : %u\n", ablkcipher->max_keysize); - seq_printf(m, "ivsize : %u\n", ablkcipher->ivsize); - seq_printf(m, "geniv : %s\n", ablkcipher->geniv ?: ""); -} - -const struct crypto_type crypto_givcipher_type = { - .ctxsize = crypto_ablkcipher_ctxsize, - .init = crypto_init_givcipher_ops, -#ifdef CONFIG_PROC_FS - .show = crypto_givcipher_show, -#endif - .report = crypto_givcipher_report, -}; -EXPORT_SYMBOL_GPL(crypto_givcipher_type); diff --git a/src/linux/crypto/aead.c b/src/linux/crypto/aead.c deleted file mode 100644 index 3f5c5ff..0000000 --- a/src/linux/crypto/aead.c +++ /dev/null @@ -1,425 +0,0 @@ -/* - * AEAD: Authenticated Encryption with Associated Data - * - * This file provides API support for AEAD algorithms. - * - * Copyright (c) 2007-2015 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -static int setkey_unaligned(struct crypto_aead *tfm, const u8 *key, - unsigned int keylen) -{ - unsigned long alignmask = crypto_aead_alignmask(tfm); - int ret; - u8 *buffer, *alignbuffer; - unsigned long absize; - - absize = keylen + alignmask; - buffer = kmalloc(absize, GFP_ATOMIC); - if (!buffer) - return -ENOMEM; - - alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); - memcpy(alignbuffer, key, keylen); - ret = crypto_aead_alg(tfm)->setkey(tfm, alignbuffer, keylen); - memset(alignbuffer, 0, keylen); - kfree(buffer); - return ret; -} - -int crypto_aead_setkey(struct crypto_aead *tfm, - const u8 *key, unsigned int keylen) -{ - unsigned long alignmask = crypto_aead_alignmask(tfm); - - if ((unsigned long)key & alignmask) - return setkey_unaligned(tfm, key, keylen); - - return crypto_aead_alg(tfm)->setkey(tfm, key, keylen); -} -EXPORT_SYMBOL_GPL(crypto_aead_setkey); - -int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize) -{ - int err; - - if (authsize > crypto_aead_maxauthsize(tfm)) - return -EINVAL; - - if (crypto_aead_alg(tfm)->setauthsize) { - err = crypto_aead_alg(tfm)->setauthsize(tfm, authsize); - if (err) - return err; - } - - tfm->authsize = authsize; - return 0; -} -EXPORT_SYMBOL_GPL(crypto_aead_setauthsize); - -static void crypto_aead_exit_tfm(struct crypto_tfm *tfm) -{ - struct crypto_aead *aead = __crypto_aead_cast(tfm); - struct aead_alg *alg = crypto_aead_alg(aead); - - alg->exit(aead); -} - -static int crypto_aead_init_tfm(struct crypto_tfm *tfm) -{ - struct crypto_aead *aead = __crypto_aead_cast(tfm); - struct aead_alg *alg = crypto_aead_alg(aead); - - aead->authsize = alg->maxauthsize; - - if (alg->exit) - aead->base.exit = crypto_aead_exit_tfm; - - if (alg->init) - return alg->init(aead); - - return 0; -} - -#ifdef CONFIG_NET -static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - struct crypto_report_aead raead; - struct aead_alg *aead = container_of(alg, struct aead_alg, base); - - strncpy(raead.type, "aead", sizeof(raead.type)); - strncpy(raead.geniv, "", sizeof(raead.geniv)); - - raead.blocksize = alg->cra_blocksize; - raead.maxauthsize = aead->maxauthsize; - raead.ivsize = aead->ivsize; - - if (nla_put(skb, CRYPTOCFGA_REPORT_AEAD, - sizeof(struct crypto_report_aead), &raead)) - goto nla_put_failure; - return 0; - -nla_put_failure: - return -EMSGSIZE; -} -#else -static int crypto_aead_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif - -static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) - __attribute__ ((unused)); -static void crypto_aead_show(struct seq_file *m, struct crypto_alg *alg) -{ - struct aead_alg *aead = container_of(alg, struct aead_alg, base); - - seq_printf(m, "type : aead\n"); - seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? - "yes" : "no"); - seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); - seq_printf(m, "ivsize : %u\n", aead->ivsize); - seq_printf(m, "maxauthsize : %u\n", aead->maxauthsize); - seq_printf(m, "geniv : \n"); -} - -static void crypto_aead_free_instance(struct crypto_instance *inst) -{ - struct aead_instance *aead = aead_instance(inst); - - if (!aead->free) { - inst->tmpl->free(inst); - return; - } - - aead->free(aead); -} - -static const struct crypto_type crypto_aead_type = { - .extsize = crypto_alg_extsize, - .init_tfm = crypto_aead_init_tfm, - .free = crypto_aead_free_instance, -#ifdef CONFIG_PROC_FS - .show = crypto_aead_show, -#endif - .report = crypto_aead_report, - .maskclear = ~CRYPTO_ALG_TYPE_MASK, - .maskset = CRYPTO_ALG_TYPE_MASK, - .type = CRYPTO_ALG_TYPE_AEAD, - .tfmsize = offsetof(struct crypto_aead, base), -}; - -static int aead_geniv_setkey(struct crypto_aead *tfm, - const u8 *key, unsigned int keylen) -{ - struct aead_geniv_ctx *ctx = crypto_aead_ctx(tfm); - - return crypto_aead_setkey(ctx->child, key, keylen); -} - -static int aead_geniv_setauthsize(struct crypto_aead *tfm, - unsigned int authsize) -{ - struct aead_geniv_ctx *ctx = crypto_aead_ctx(tfm); - - return crypto_aead_setauthsize(ctx->child, authsize); -} - -struct aead_instance *aead_geniv_alloc(struct crypto_template *tmpl, - struct rtattr **tb, u32 type, u32 mask) -{ - const char *name; - struct crypto_aead_spawn *spawn; - struct crypto_attr_type *algt; - struct aead_instance *inst; - struct aead_alg *alg; - unsigned int ivsize; - unsigned int maxauthsize; - int err; - - algt = crypto_get_attr_type(tb); - if (IS_ERR(algt)) - return ERR_CAST(algt); - - if ((algt->type ^ CRYPTO_ALG_TYPE_AEAD) & algt->mask) - return ERR_PTR(-EINVAL); - - name = crypto_attr_alg_name(tb[1]); - if (IS_ERR(name)) - return ERR_CAST(name); - - inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL); - if (!inst) - return ERR_PTR(-ENOMEM); - - spawn = aead_instance_ctx(inst); - - /* Ignore async algorithms if necessary. */ - mask |= crypto_requires_sync(algt->type, algt->mask); - - crypto_set_aead_spawn(spawn, aead_crypto_instance(inst)); - err = crypto_grab_aead(spawn, name, type, mask); - if (err) - goto err_free_inst; - - alg = crypto_spawn_aead_alg(spawn); - - ivsize = crypto_aead_alg_ivsize(alg); - maxauthsize = crypto_aead_alg_maxauthsize(alg); - - err = -EINVAL; - if (ivsize < sizeof(u64)) - goto err_drop_alg; - - err = -ENAMETOOLONG; - if (snprintf(inst->alg.base.cra_name, CRYPTO_MAX_ALG_NAME, - "%s(%s)", tmpl->name, alg->base.cra_name) >= - CRYPTO_MAX_ALG_NAME) - goto err_drop_alg; - if (snprintf(inst->alg.base.cra_driver_name, CRYPTO_MAX_ALG_NAME, - "%s(%s)", tmpl->name, alg->base.cra_driver_name) >= - CRYPTO_MAX_ALG_NAME) - goto err_drop_alg; - - inst->alg.base.cra_flags = alg->base.cra_flags & CRYPTO_ALG_ASYNC; - inst->alg.base.cra_priority = alg->base.cra_priority; - inst->alg.base.cra_blocksize = alg->base.cra_blocksize; - inst->alg.base.cra_alignmask = alg->base.cra_alignmask; - inst->alg.base.cra_ctxsize = sizeof(struct aead_geniv_ctx); - - inst->alg.setkey = aead_geniv_setkey; - inst->alg.setauthsize = aead_geniv_setauthsize; - - inst->alg.ivsize = ivsize; - inst->alg.maxauthsize = maxauthsize; - -out: - return inst; - -err_drop_alg: - crypto_drop_aead(spawn); -err_free_inst: - kfree(inst); - inst = ERR_PTR(err); - goto out; -} -EXPORT_SYMBOL_GPL(aead_geniv_alloc); - -void aead_geniv_free(struct aead_instance *inst) -{ - crypto_drop_aead(aead_instance_ctx(inst)); - kfree(inst); -} -EXPORT_SYMBOL_GPL(aead_geniv_free); - -int aead_init_geniv(struct crypto_aead *aead) -{ - struct aead_geniv_ctx *ctx = crypto_aead_ctx(aead); - struct aead_instance *inst = aead_alg_instance(aead); - struct crypto_aead *child; - int err; - - spin_lock_init(&ctx->lock); - - err = crypto_get_default_rng(); - if (err) - goto out; - - err = crypto_rng_get_bytes(crypto_default_rng, ctx->salt, - crypto_aead_ivsize(aead)); - crypto_put_default_rng(); - if (err) - goto out; - - ctx->sknull = crypto_get_default_null_skcipher2(); - err = PTR_ERR(ctx->sknull); - if (IS_ERR(ctx->sknull)) - goto out; - - child = crypto_spawn_aead(aead_instance_ctx(inst)); - err = PTR_ERR(child); - if (IS_ERR(child)) - goto drop_null; - - ctx->child = child; - crypto_aead_set_reqsize(aead, crypto_aead_reqsize(child) + - sizeof(struct aead_request)); - - err = 0; - -out: - return err; - -drop_null: - crypto_put_default_null_skcipher2(); - goto out; -} -EXPORT_SYMBOL_GPL(aead_init_geniv); - -void aead_exit_geniv(struct crypto_aead *tfm) -{ - struct aead_geniv_ctx *ctx = crypto_aead_ctx(tfm); - - crypto_free_aead(ctx->child); - crypto_put_default_null_skcipher2(); -} -EXPORT_SYMBOL_GPL(aead_exit_geniv); - -int crypto_grab_aead(struct crypto_aead_spawn *spawn, const char *name, - u32 type, u32 mask) -{ - spawn->base.frontend = &crypto_aead_type; - return crypto_grab_spawn(&spawn->base, name, type, mask); -} -EXPORT_SYMBOL_GPL(crypto_grab_aead); - -struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask) -{ - return crypto_alloc_tfm(alg_name, &crypto_aead_type, type, mask); -} -EXPORT_SYMBOL_GPL(crypto_alloc_aead); - -static int aead_prepare_alg(struct aead_alg *alg) -{ - struct crypto_alg *base = &alg->base; - - if (max3(alg->maxauthsize, alg->ivsize, alg->chunksize) > - PAGE_SIZE / 8) - return -EINVAL; - - if (!alg->chunksize) - alg->chunksize = base->cra_blocksize; - - base->cra_type = &crypto_aead_type; - base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; - base->cra_flags |= CRYPTO_ALG_TYPE_AEAD; - - return 0; -} - -int crypto_register_aead(struct aead_alg *alg) -{ - struct crypto_alg *base = &alg->base; - int err; - - err = aead_prepare_alg(alg); - if (err) - return err; - - return crypto_register_alg(base); -} -EXPORT_SYMBOL_GPL(crypto_register_aead); - -void crypto_unregister_aead(struct aead_alg *alg) -{ - crypto_unregister_alg(&alg->base); -} -EXPORT_SYMBOL_GPL(crypto_unregister_aead); - -int crypto_register_aeads(struct aead_alg *algs, int count) -{ - int i, ret; - - for (i = 0; i < count; i++) { - ret = crypto_register_aead(&algs[i]); - if (ret) - goto err; - } - - return 0; - -err: - for (--i; i >= 0; --i) - crypto_unregister_aead(&algs[i]); - - return ret; -} -EXPORT_SYMBOL_GPL(crypto_register_aeads); - -void crypto_unregister_aeads(struct aead_alg *algs, int count) -{ - int i; - - for (i = count - 1; i >= 0; --i) - crypto_unregister_aead(&algs[i]); -} -EXPORT_SYMBOL_GPL(crypto_unregister_aeads); - -int aead_register_instance(struct crypto_template *tmpl, - struct aead_instance *inst) -{ - int err; - - err = aead_prepare_alg(&inst->alg); - if (err) - return err; - - return crypto_register_instance(tmpl, aead_crypto_instance(inst)); -} -EXPORT_SYMBOL_GPL(aead_register_instance); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Authenticated Encryption with Associated Data (AEAD)"); diff --git a/src/linux/crypto/aes_generic.c b/src/linux/crypto/aes_generic.c deleted file mode 100644 index 3dd1011..0000000 --- a/src/linux/crypto/aes_generic.c +++ /dev/null @@ -1,1478 +0,0 @@ -/* - * Cryptographic API. - * - * AES Cipher Algorithm. - * - * Based on Brian Gladman's code. - * - * Linux developers: - * Alexander Kjeldaas - * Herbert Valerio Riedel - * Kyle McMartin - * Adam J. Richter (conversion to 2.5 API). - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * --------------------------------------------------------------------------- - * Copyright (c) 2002, Dr Brian Gladman , Worcester, UK. - * All rights reserved. - * - * LICENSE TERMS - * - * The free distribution and use of this software in both source and binary - * form is allowed (with or without changes) provided that: - * - * 1. distributions of this source code include the above copyright - * notice, this list of conditions and the following disclaimer; - * - * 2. distributions in binary form include the above copyright - * notice, this list of conditions and the following disclaimer - * in the documentation and/or other associated materials; - * - * 3. the copyright holder's name is not used to endorse products - * built using this software without specific written permission. - * - * ALTERNATIVELY, provided that this notice is retained in full, this product - * may be distributed under the terms of the GNU General Public License (GPL), - * in which case the provisions of the GPL apply INSTEAD OF those given above. - * - * DISCLAIMER - * - * This software is provided 'as is' with no explicit or implied warranties - * in respect of its properties, including, but not limited to, correctness - * and/or fitness for purpose. - * --------------------------------------------------------------------------- - */ - -#include -#include -#include -#include -#include -#include -#include - -static inline u8 byte(const u32 x, const unsigned n) -{ - return x >> (n << 3); -} - -static const u32 rco_tab[10] = { 1, 2, 4, 8, 16, 32, 64, 128, 27, 54 }; - -__visible const u32 crypto_ft_tab[4][256] = { - { - 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, - 0x0df2f2ff, 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, - 0x50303060, 0x03010102, 0xa96767ce, 0x7d2b2b56, - 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, 0x9a7676ec, - 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, - 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, - 0xecadad41, 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, - 0xbf9c9c23, 0xf7a4a453, 0x967272e4, 0x5bc0c09b, - 0xc2b7b775, 0x1cfdfde1, 0xae93933d, 0x6a26264c, - 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, - 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, - 0x937171e2, 0x73d8d8ab, 0x53313162, 0x3f15152a, - 0x0c040408, 0x52c7c795, 0x65232346, 0x5ec3c39d, - 0x28181830, 0xa1969637, 0x0f05050a, 0xb59a9a2f, - 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, - 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, - 0x1b090912, 0x9e83831d, 0x742c2c58, 0x2e1a1a34, - 0x2d1b1b36, 0xb26e6edc, 0xee5a5ab4, 0xfba0a05b, - 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, 0xceb3b37d, - 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, - 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, - 0x60202040, 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, - 0xbe6a6ad4, 0x46cbcb8d, 0xd9bebe67, 0x4b393972, - 0xde4a4a94, 0xd44c4c98, 0xe85858b0, 0x4acfcf85, - 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, - 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, - 0xcf45458a, 0x10f9f9e9, 0x06020204, 0x817f7ffe, - 0xf05050a0, 0x443c3c78, 0xba9f9f25, 0xe3a8a84b, - 0xf35151a2, 0xfea3a35d, 0xc0404080, 0x8a8f8f05, - 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, - 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, - 0x30101020, 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, - 0x4ccdcd81, 0x140c0c18, 0x35131326, 0x2fececc3, - 0xe15f5fbe, 0xa2979735, 0xcc444488, 0x3917172e, - 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, - 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, - 0xa06060c0, 0x98818119, 0xd14f4f9e, 0x7fdcdca3, - 0x66222244, 0x7e2a2a54, 0xab90903b, 0x8388880b, - 0xca46468c, 0x29eeeec7, 0xd3b8b86b, 0x3c141428, - 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, - 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, - 0xdb494992, 0x0a06060c, 0x6c242448, 0xe45c5cb8, - 0x5dc2c29f, 0x6ed3d3bd, 0xefacac43, 0xa66262c4, - 0xa8919139, 0xa4959531, 0x37e4e4d3, 0x8b7979f2, - 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, - 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, - 0xb46c6cd8, 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, - 0xaf6565ca, 0x8e7a7af4, 0xe9aeae47, 0x18080810, - 0xd5baba6f, 0x887878f0, 0x6f25254a, 0x722e2e5c, - 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, - 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, - 0xdd4b4b96, 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, - 0x907070e0, 0x423e3e7c, 0xc4b5b571, 0xaa6666cc, - 0xd8484890, 0x05030306, 0x01f6f6f7, 0x120e0e1c, - 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, - 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, - 0x38e1e1d9, 0x13f8f8eb, 0xb398982b, 0x33111122, - 0xbb6969d2, 0x70d9d9a9, 0x898e8e07, 0xa7949433, - 0xb69b9b2d, 0x221e1e3c, 0x92878715, 0x20e9e9c9, - 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, - 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, - 0xdabfbf65, 0x31e6e6d7, 0xc6424284, 0xb86868d0, - 0xc3414182, 0xb0999929, 0x772d2d5a, 0x110f0f1e, - 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, 0x3a16162c, - }, { - 0x6363c6a5, 0x7c7cf884, 0x7777ee99, 0x7b7bf68d, - 0xf2f2ff0d, 0x6b6bd6bd, 0x6f6fdeb1, 0xc5c59154, - 0x30306050, 0x01010203, 0x6767cea9, 0x2b2b567d, - 0xfefee719, 0xd7d7b562, 0xabab4de6, 0x7676ec9a, - 0xcaca8f45, 0x82821f9d, 0xc9c98940, 0x7d7dfa87, - 0xfafaef15, 0x5959b2eb, 0x47478ec9, 0xf0f0fb0b, - 0xadad41ec, 0xd4d4b367, 0xa2a25ffd, 0xafaf45ea, - 0x9c9c23bf, 0xa4a453f7, 0x7272e496, 0xc0c09b5b, - 0xb7b775c2, 0xfdfde11c, 0x93933dae, 0x26264c6a, - 0x36366c5a, 0x3f3f7e41, 0xf7f7f502, 0xcccc834f, - 0x3434685c, 0xa5a551f4, 0xe5e5d134, 0xf1f1f908, - 0x7171e293, 0xd8d8ab73, 0x31316253, 0x15152a3f, - 0x0404080c, 0xc7c79552, 0x23234665, 0xc3c39d5e, - 0x18183028, 0x969637a1, 0x05050a0f, 0x9a9a2fb5, - 0x07070e09, 0x12122436, 0x80801b9b, 0xe2e2df3d, - 0xebebcd26, 0x27274e69, 0xb2b27fcd, 0x7575ea9f, - 0x0909121b, 0x83831d9e, 0x2c2c5874, 0x1a1a342e, - 0x1b1b362d, 0x6e6edcb2, 0x5a5ab4ee, 0xa0a05bfb, - 0x5252a4f6, 0x3b3b764d, 0xd6d6b761, 0xb3b37dce, - 0x2929527b, 0xe3e3dd3e, 0x2f2f5e71, 0x84841397, - 0x5353a6f5, 0xd1d1b968, 0x00000000, 0xededc12c, - 0x20204060, 0xfcfce31f, 0xb1b179c8, 0x5b5bb6ed, - 0x6a6ad4be, 0xcbcb8d46, 0xbebe67d9, 0x3939724b, - 0x4a4a94de, 0x4c4c98d4, 0x5858b0e8, 0xcfcf854a, - 0xd0d0bb6b, 0xefefc52a, 0xaaaa4fe5, 0xfbfbed16, - 0x434386c5, 0x4d4d9ad7, 0x33336655, 0x85851194, - 0x45458acf, 0xf9f9e910, 0x02020406, 0x7f7ffe81, - 0x5050a0f0, 0x3c3c7844, 0x9f9f25ba, 0xa8a84be3, - 0x5151a2f3, 0xa3a35dfe, 0x404080c0, 0x8f8f058a, - 0x92923fad, 0x9d9d21bc, 0x38387048, 0xf5f5f104, - 0xbcbc63df, 0xb6b677c1, 0xdadaaf75, 0x21214263, - 0x10102030, 0xffffe51a, 0xf3f3fd0e, 0xd2d2bf6d, - 0xcdcd814c, 0x0c0c1814, 0x13132635, 0xececc32f, - 0x5f5fbee1, 0x979735a2, 0x444488cc, 0x17172e39, - 0xc4c49357, 0xa7a755f2, 0x7e7efc82, 0x3d3d7a47, - 0x6464c8ac, 0x5d5dbae7, 0x1919322b, 0x7373e695, - 0x6060c0a0, 0x81811998, 0x4f4f9ed1, 0xdcdca37f, - 0x22224466, 0x2a2a547e, 0x90903bab, 0x88880b83, - 0x46468cca, 0xeeeec729, 0xb8b86bd3, 0x1414283c, - 0xdedea779, 0x5e5ebce2, 0x0b0b161d, 0xdbdbad76, - 0xe0e0db3b, 0x32326456, 0x3a3a744e, 0x0a0a141e, - 0x494992db, 0x06060c0a, 0x2424486c, 0x5c5cb8e4, - 0xc2c29f5d, 0xd3d3bd6e, 0xacac43ef, 0x6262c4a6, - 0x919139a8, 0x959531a4, 0xe4e4d337, 0x7979f28b, - 0xe7e7d532, 0xc8c88b43, 0x37376e59, 0x6d6ddab7, - 0x8d8d018c, 0xd5d5b164, 0x4e4e9cd2, 0xa9a949e0, - 0x6c6cd8b4, 0x5656acfa, 0xf4f4f307, 0xeaeacf25, - 0x6565caaf, 0x7a7af48e, 0xaeae47e9, 0x08081018, - 0xbaba6fd5, 0x7878f088, 0x25254a6f, 0x2e2e5c72, - 0x1c1c3824, 0xa6a657f1, 0xb4b473c7, 0xc6c69751, - 0xe8e8cb23, 0xdddda17c, 0x7474e89c, 0x1f1f3e21, - 0x4b4b96dd, 0xbdbd61dc, 0x8b8b0d86, 0x8a8a0f85, - 0x7070e090, 0x3e3e7c42, 0xb5b571c4, 0x6666ccaa, - 0x484890d8, 0x03030605, 0xf6f6f701, 0x0e0e1c12, - 0x6161c2a3, 0x35356a5f, 0x5757aef9, 0xb9b969d0, - 0x86861791, 0xc1c19958, 0x1d1d3a27, 0x9e9e27b9, - 0xe1e1d938, 0xf8f8eb13, 0x98982bb3, 0x11112233, - 0x6969d2bb, 0xd9d9a970, 0x8e8e0789, 0x949433a7, - 0x9b9b2db6, 0x1e1e3c22, 0x87871592, 0xe9e9c920, - 0xcece8749, 0x5555aaff, 0x28285078, 0xdfdfa57a, - 0x8c8c038f, 0xa1a159f8, 0x89890980, 0x0d0d1a17, - 0xbfbf65da, 0xe6e6d731, 0x424284c6, 0x6868d0b8, - 0x414182c3, 0x999929b0, 0x2d2d5a77, 0x0f0f1e11, - 0xb0b07bcb, 0x5454a8fc, 0xbbbb6dd6, 0x16162c3a, - }, { - 0x63c6a563, 0x7cf8847c, 0x77ee9977, 0x7bf68d7b, - 0xf2ff0df2, 0x6bd6bd6b, 0x6fdeb16f, 0xc59154c5, - 0x30605030, 0x01020301, 0x67cea967, 0x2b567d2b, - 0xfee719fe, 0xd7b562d7, 0xab4de6ab, 0x76ec9a76, - 0xca8f45ca, 0x821f9d82, 0xc98940c9, 0x7dfa877d, - 0xfaef15fa, 0x59b2eb59, 0x478ec947, 0xf0fb0bf0, - 0xad41ecad, 0xd4b367d4, 0xa25ffda2, 0xaf45eaaf, - 0x9c23bf9c, 0xa453f7a4, 0x72e49672, 0xc09b5bc0, - 0xb775c2b7, 0xfde11cfd, 0x933dae93, 0x264c6a26, - 0x366c5a36, 0x3f7e413f, 0xf7f502f7, 0xcc834fcc, - 0x34685c34, 0xa551f4a5, 0xe5d134e5, 0xf1f908f1, - 0x71e29371, 0xd8ab73d8, 0x31625331, 0x152a3f15, - 0x04080c04, 0xc79552c7, 0x23466523, 0xc39d5ec3, - 0x18302818, 0x9637a196, 0x050a0f05, 0x9a2fb59a, - 0x070e0907, 0x12243612, 0x801b9b80, 0xe2df3de2, - 0xebcd26eb, 0x274e6927, 0xb27fcdb2, 0x75ea9f75, - 0x09121b09, 0x831d9e83, 0x2c58742c, 0x1a342e1a, - 0x1b362d1b, 0x6edcb26e, 0x5ab4ee5a, 0xa05bfba0, - 0x52a4f652, 0x3b764d3b, 0xd6b761d6, 0xb37dceb3, - 0x29527b29, 0xe3dd3ee3, 0x2f5e712f, 0x84139784, - 0x53a6f553, 0xd1b968d1, 0x00000000, 0xedc12ced, - 0x20406020, 0xfce31ffc, 0xb179c8b1, 0x5bb6ed5b, - 0x6ad4be6a, 0xcb8d46cb, 0xbe67d9be, 0x39724b39, - 0x4a94de4a, 0x4c98d44c, 0x58b0e858, 0xcf854acf, - 0xd0bb6bd0, 0xefc52aef, 0xaa4fe5aa, 0xfbed16fb, - 0x4386c543, 0x4d9ad74d, 0x33665533, 0x85119485, - 0x458acf45, 0xf9e910f9, 0x02040602, 0x7ffe817f, - 0x50a0f050, 0x3c78443c, 0x9f25ba9f, 0xa84be3a8, - 0x51a2f351, 0xa35dfea3, 0x4080c040, 0x8f058a8f, - 0x923fad92, 0x9d21bc9d, 0x38704838, 0xf5f104f5, - 0xbc63dfbc, 0xb677c1b6, 0xdaaf75da, 0x21426321, - 0x10203010, 0xffe51aff, 0xf3fd0ef3, 0xd2bf6dd2, - 0xcd814ccd, 0x0c18140c, 0x13263513, 0xecc32fec, - 0x5fbee15f, 0x9735a297, 0x4488cc44, 0x172e3917, - 0xc49357c4, 0xa755f2a7, 0x7efc827e, 0x3d7a473d, - 0x64c8ac64, 0x5dbae75d, 0x19322b19, 0x73e69573, - 0x60c0a060, 0x81199881, 0x4f9ed14f, 0xdca37fdc, - 0x22446622, 0x2a547e2a, 0x903bab90, 0x880b8388, - 0x468cca46, 0xeec729ee, 0xb86bd3b8, 0x14283c14, - 0xdea779de, 0x5ebce25e, 0x0b161d0b, 0xdbad76db, - 0xe0db3be0, 0x32645632, 0x3a744e3a, 0x0a141e0a, - 0x4992db49, 0x060c0a06, 0x24486c24, 0x5cb8e45c, - 0xc29f5dc2, 0xd3bd6ed3, 0xac43efac, 0x62c4a662, - 0x9139a891, 0x9531a495, 0xe4d337e4, 0x79f28b79, - 0xe7d532e7, 0xc88b43c8, 0x376e5937, 0x6ddab76d, - 0x8d018c8d, 0xd5b164d5, 0x4e9cd24e, 0xa949e0a9, - 0x6cd8b46c, 0x56acfa56, 0xf4f307f4, 0xeacf25ea, - 0x65caaf65, 0x7af48e7a, 0xae47e9ae, 0x08101808, - 0xba6fd5ba, 0x78f08878, 0x254a6f25, 0x2e5c722e, - 0x1c38241c, 0xa657f1a6, 0xb473c7b4, 0xc69751c6, - 0xe8cb23e8, 0xdda17cdd, 0x74e89c74, 0x1f3e211f, - 0x4b96dd4b, 0xbd61dcbd, 0x8b0d868b, 0x8a0f858a, - 0x70e09070, 0x3e7c423e, 0xb571c4b5, 0x66ccaa66, - 0x4890d848, 0x03060503, 0xf6f701f6, 0x0e1c120e, - 0x61c2a361, 0x356a5f35, 0x57aef957, 0xb969d0b9, - 0x86179186, 0xc19958c1, 0x1d3a271d, 0x9e27b99e, - 0xe1d938e1, 0xf8eb13f8, 0x982bb398, 0x11223311, - 0x69d2bb69, 0xd9a970d9, 0x8e07898e, 0x9433a794, - 0x9b2db69b, 0x1e3c221e, 0x87159287, 0xe9c920e9, - 0xce8749ce, 0x55aaff55, 0x28507828, 0xdfa57adf, - 0x8c038f8c, 0xa159f8a1, 0x89098089, 0x0d1a170d, - 0xbf65dabf, 0xe6d731e6, 0x4284c642, 0x68d0b868, - 0x4182c341, 0x9929b099, 0x2d5a772d, 0x0f1e110f, - 0xb07bcbb0, 0x54a8fc54, 0xbb6dd6bb, 0x162c3a16, - }, { - 0xc6a56363, 0xf8847c7c, 0xee997777, 0xf68d7b7b, - 0xff0df2f2, 0xd6bd6b6b, 0xdeb16f6f, 0x9154c5c5, - 0x60503030, 0x02030101, 0xcea96767, 0x567d2b2b, - 0xe719fefe, 0xb562d7d7, 0x4de6abab, 0xec9a7676, - 0x8f45caca, 0x1f9d8282, 0x8940c9c9, 0xfa877d7d, - 0xef15fafa, 0xb2eb5959, 0x8ec94747, 0xfb0bf0f0, - 0x41ecadad, 0xb367d4d4, 0x5ffda2a2, 0x45eaafaf, - 0x23bf9c9c, 0x53f7a4a4, 0xe4967272, 0x9b5bc0c0, - 0x75c2b7b7, 0xe11cfdfd, 0x3dae9393, 0x4c6a2626, - 0x6c5a3636, 0x7e413f3f, 0xf502f7f7, 0x834fcccc, - 0x685c3434, 0x51f4a5a5, 0xd134e5e5, 0xf908f1f1, - 0xe2937171, 0xab73d8d8, 0x62533131, 0x2a3f1515, - 0x080c0404, 0x9552c7c7, 0x46652323, 0x9d5ec3c3, - 0x30281818, 0x37a19696, 0x0a0f0505, 0x2fb59a9a, - 0x0e090707, 0x24361212, 0x1b9b8080, 0xdf3de2e2, - 0xcd26ebeb, 0x4e692727, 0x7fcdb2b2, 0xea9f7575, - 0x121b0909, 0x1d9e8383, 0x58742c2c, 0x342e1a1a, - 0x362d1b1b, 0xdcb26e6e, 0xb4ee5a5a, 0x5bfba0a0, - 0xa4f65252, 0x764d3b3b, 0xb761d6d6, 0x7dceb3b3, - 0x527b2929, 0xdd3ee3e3, 0x5e712f2f, 0x13978484, - 0xa6f55353, 0xb968d1d1, 0x00000000, 0xc12ceded, - 0x40602020, 0xe31ffcfc, 0x79c8b1b1, 0xb6ed5b5b, - 0xd4be6a6a, 0x8d46cbcb, 0x67d9bebe, 0x724b3939, - 0x94de4a4a, 0x98d44c4c, 0xb0e85858, 0x854acfcf, - 0xbb6bd0d0, 0xc52aefef, 0x4fe5aaaa, 0xed16fbfb, - 0x86c54343, 0x9ad74d4d, 0x66553333, 0x11948585, - 0x8acf4545, 0xe910f9f9, 0x04060202, 0xfe817f7f, - 0xa0f05050, 0x78443c3c, 0x25ba9f9f, 0x4be3a8a8, - 0xa2f35151, 0x5dfea3a3, 0x80c04040, 0x058a8f8f, - 0x3fad9292, 0x21bc9d9d, 0x70483838, 0xf104f5f5, - 0x63dfbcbc, 0x77c1b6b6, 0xaf75dada, 0x42632121, - 0x20301010, 0xe51affff, 0xfd0ef3f3, 0xbf6dd2d2, - 0x814ccdcd, 0x18140c0c, 0x26351313, 0xc32fecec, - 0xbee15f5f, 0x35a29797, 0x88cc4444, 0x2e391717, - 0x9357c4c4, 0x55f2a7a7, 0xfc827e7e, 0x7a473d3d, - 0xc8ac6464, 0xbae75d5d, 0x322b1919, 0xe6957373, - 0xc0a06060, 0x19988181, 0x9ed14f4f, 0xa37fdcdc, - 0x44662222, 0x547e2a2a, 0x3bab9090, 0x0b838888, - 0x8cca4646, 0xc729eeee, 0x6bd3b8b8, 0x283c1414, - 0xa779dede, 0xbce25e5e, 0x161d0b0b, 0xad76dbdb, - 0xdb3be0e0, 0x64563232, 0x744e3a3a, 0x141e0a0a, - 0x92db4949, 0x0c0a0606, 0x486c2424, 0xb8e45c5c, - 0x9f5dc2c2, 0xbd6ed3d3, 0x43efacac, 0xc4a66262, - 0x39a89191, 0x31a49595, 0xd337e4e4, 0xf28b7979, - 0xd532e7e7, 0x8b43c8c8, 0x6e593737, 0xdab76d6d, - 0x018c8d8d, 0xb164d5d5, 0x9cd24e4e, 0x49e0a9a9, - 0xd8b46c6c, 0xacfa5656, 0xf307f4f4, 0xcf25eaea, - 0xcaaf6565, 0xf48e7a7a, 0x47e9aeae, 0x10180808, - 0x6fd5baba, 0xf0887878, 0x4a6f2525, 0x5c722e2e, - 0x38241c1c, 0x57f1a6a6, 0x73c7b4b4, 0x9751c6c6, - 0xcb23e8e8, 0xa17cdddd, 0xe89c7474, 0x3e211f1f, - 0x96dd4b4b, 0x61dcbdbd, 0x0d868b8b, 0x0f858a8a, - 0xe0907070, 0x7c423e3e, 0x71c4b5b5, 0xccaa6666, - 0x90d84848, 0x06050303, 0xf701f6f6, 0x1c120e0e, - 0xc2a36161, 0x6a5f3535, 0xaef95757, 0x69d0b9b9, - 0x17918686, 0x9958c1c1, 0x3a271d1d, 0x27b99e9e, - 0xd938e1e1, 0xeb13f8f8, 0x2bb39898, 0x22331111, - 0xd2bb6969, 0xa970d9d9, 0x07898e8e, 0x33a79494, - 0x2db69b9b, 0x3c221e1e, 0x15928787, 0xc920e9e9, - 0x8749cece, 0xaaff5555, 0x50782828, 0xa57adfdf, - 0x038f8c8c, 0x59f8a1a1, 0x09808989, 0x1a170d0d, - 0x65dabfbf, 0xd731e6e6, 0x84c64242, 0xd0b86868, - 0x82c34141, 0x29b09999, 0x5a772d2d, 0x1e110f0f, - 0x7bcbb0b0, 0xa8fc5454, 0x6dd6bbbb, 0x2c3a1616, - } -}; - -__visible const u32 crypto_fl_tab[4][256] = { - { - 0x00000063, 0x0000007c, 0x00000077, 0x0000007b, - 0x000000f2, 0x0000006b, 0x0000006f, 0x000000c5, - 0x00000030, 0x00000001, 0x00000067, 0x0000002b, - 0x000000fe, 0x000000d7, 0x000000ab, 0x00000076, - 0x000000ca, 0x00000082, 0x000000c9, 0x0000007d, - 0x000000fa, 0x00000059, 0x00000047, 0x000000f0, - 0x000000ad, 0x000000d4, 0x000000a2, 0x000000af, - 0x0000009c, 0x000000a4, 0x00000072, 0x000000c0, - 0x000000b7, 0x000000fd, 0x00000093, 0x00000026, - 0x00000036, 0x0000003f, 0x000000f7, 0x000000cc, - 0x00000034, 0x000000a5, 0x000000e5, 0x000000f1, - 0x00000071, 0x000000d8, 0x00000031, 0x00000015, - 0x00000004, 0x000000c7, 0x00000023, 0x000000c3, - 0x00000018, 0x00000096, 0x00000005, 0x0000009a, - 0x00000007, 0x00000012, 0x00000080, 0x000000e2, - 0x000000eb, 0x00000027, 0x000000b2, 0x00000075, - 0x00000009, 0x00000083, 0x0000002c, 0x0000001a, - 0x0000001b, 0x0000006e, 0x0000005a, 0x000000a0, - 0x00000052, 0x0000003b, 0x000000d6, 0x000000b3, - 0x00000029, 0x000000e3, 0x0000002f, 0x00000084, - 0x00000053, 0x000000d1, 0x00000000, 0x000000ed, - 0x00000020, 0x000000fc, 0x000000b1, 0x0000005b, - 0x0000006a, 0x000000cb, 0x000000be, 0x00000039, - 0x0000004a, 0x0000004c, 0x00000058, 0x000000cf, - 0x000000d0, 0x000000ef, 0x000000aa, 0x000000fb, - 0x00000043, 0x0000004d, 0x00000033, 0x00000085, - 0x00000045, 0x000000f9, 0x00000002, 0x0000007f, - 0x00000050, 0x0000003c, 0x0000009f, 0x000000a8, - 0x00000051, 0x000000a3, 0x00000040, 0x0000008f, - 0x00000092, 0x0000009d, 0x00000038, 0x000000f5, - 0x000000bc, 0x000000b6, 0x000000da, 0x00000021, - 0x00000010, 0x000000ff, 0x000000f3, 0x000000d2, - 0x000000cd, 0x0000000c, 0x00000013, 0x000000ec, - 0x0000005f, 0x00000097, 0x00000044, 0x00000017, - 0x000000c4, 0x000000a7, 0x0000007e, 0x0000003d, - 0x00000064, 0x0000005d, 0x00000019, 0x00000073, - 0x00000060, 0x00000081, 0x0000004f, 0x000000dc, - 0x00000022, 0x0000002a, 0x00000090, 0x00000088, - 0x00000046, 0x000000ee, 0x000000b8, 0x00000014, - 0x000000de, 0x0000005e, 0x0000000b, 0x000000db, - 0x000000e0, 0x00000032, 0x0000003a, 0x0000000a, - 0x00000049, 0x00000006, 0x00000024, 0x0000005c, - 0x000000c2, 0x000000d3, 0x000000ac, 0x00000062, - 0x00000091, 0x00000095, 0x000000e4, 0x00000079, - 0x000000e7, 0x000000c8, 0x00000037, 0x0000006d, - 0x0000008d, 0x000000d5, 0x0000004e, 0x000000a9, - 0x0000006c, 0x00000056, 0x000000f4, 0x000000ea, - 0x00000065, 0x0000007a, 0x000000ae, 0x00000008, - 0x000000ba, 0x00000078, 0x00000025, 0x0000002e, - 0x0000001c, 0x000000a6, 0x000000b4, 0x000000c6, - 0x000000e8, 0x000000dd, 0x00000074, 0x0000001f, - 0x0000004b, 0x000000bd, 0x0000008b, 0x0000008a, - 0x00000070, 0x0000003e, 0x000000b5, 0x00000066, - 0x00000048, 0x00000003, 0x000000f6, 0x0000000e, - 0x00000061, 0x00000035, 0x00000057, 0x000000b9, - 0x00000086, 0x000000c1, 0x0000001d, 0x0000009e, - 0x000000e1, 0x000000f8, 0x00000098, 0x00000011, - 0x00000069, 0x000000d9, 0x0000008e, 0x00000094, - 0x0000009b, 0x0000001e, 0x00000087, 0x000000e9, - 0x000000ce, 0x00000055, 0x00000028, 0x000000df, - 0x0000008c, 0x000000a1, 0x00000089, 0x0000000d, - 0x000000bf, 0x000000e6, 0x00000042, 0x00000068, - 0x00000041, 0x00000099, 0x0000002d, 0x0000000f, - 0x000000b0, 0x00000054, 0x000000bb, 0x00000016, - }, { - 0x00006300, 0x00007c00, 0x00007700, 0x00007b00, - 0x0000f200, 0x00006b00, 0x00006f00, 0x0000c500, - 0x00003000, 0x00000100, 0x00006700, 0x00002b00, - 0x0000fe00, 0x0000d700, 0x0000ab00, 0x00007600, - 0x0000ca00, 0x00008200, 0x0000c900, 0x00007d00, - 0x0000fa00, 0x00005900, 0x00004700, 0x0000f000, - 0x0000ad00, 0x0000d400, 0x0000a200, 0x0000af00, - 0x00009c00, 0x0000a400, 0x00007200, 0x0000c000, - 0x0000b700, 0x0000fd00, 0x00009300, 0x00002600, - 0x00003600, 0x00003f00, 0x0000f700, 0x0000cc00, - 0x00003400, 0x0000a500, 0x0000e500, 0x0000f100, - 0x00007100, 0x0000d800, 0x00003100, 0x00001500, - 0x00000400, 0x0000c700, 0x00002300, 0x0000c300, - 0x00001800, 0x00009600, 0x00000500, 0x00009a00, - 0x00000700, 0x00001200, 0x00008000, 0x0000e200, - 0x0000eb00, 0x00002700, 0x0000b200, 0x00007500, - 0x00000900, 0x00008300, 0x00002c00, 0x00001a00, - 0x00001b00, 0x00006e00, 0x00005a00, 0x0000a000, - 0x00005200, 0x00003b00, 0x0000d600, 0x0000b300, - 0x00002900, 0x0000e300, 0x00002f00, 0x00008400, - 0x00005300, 0x0000d100, 0x00000000, 0x0000ed00, - 0x00002000, 0x0000fc00, 0x0000b100, 0x00005b00, - 0x00006a00, 0x0000cb00, 0x0000be00, 0x00003900, - 0x00004a00, 0x00004c00, 0x00005800, 0x0000cf00, - 0x0000d000, 0x0000ef00, 0x0000aa00, 0x0000fb00, - 0x00004300, 0x00004d00, 0x00003300, 0x00008500, - 0x00004500, 0x0000f900, 0x00000200, 0x00007f00, - 0x00005000, 0x00003c00, 0x00009f00, 0x0000a800, - 0x00005100, 0x0000a300, 0x00004000, 0x00008f00, - 0x00009200, 0x00009d00, 0x00003800, 0x0000f500, - 0x0000bc00, 0x0000b600, 0x0000da00, 0x00002100, - 0x00001000, 0x0000ff00, 0x0000f300, 0x0000d200, - 0x0000cd00, 0x00000c00, 0x00001300, 0x0000ec00, - 0x00005f00, 0x00009700, 0x00004400, 0x00001700, - 0x0000c400, 0x0000a700, 0x00007e00, 0x00003d00, - 0x00006400, 0x00005d00, 0x00001900, 0x00007300, - 0x00006000, 0x00008100, 0x00004f00, 0x0000dc00, - 0x00002200, 0x00002a00, 0x00009000, 0x00008800, - 0x00004600, 0x0000ee00, 0x0000b800, 0x00001400, - 0x0000de00, 0x00005e00, 0x00000b00, 0x0000db00, - 0x0000e000, 0x00003200, 0x00003a00, 0x00000a00, - 0x00004900, 0x00000600, 0x00002400, 0x00005c00, - 0x0000c200, 0x0000d300, 0x0000ac00, 0x00006200, - 0x00009100, 0x00009500, 0x0000e400, 0x00007900, - 0x0000e700, 0x0000c800, 0x00003700, 0x00006d00, - 0x00008d00, 0x0000d500, 0x00004e00, 0x0000a900, - 0x00006c00, 0x00005600, 0x0000f400, 0x0000ea00, - 0x00006500, 0x00007a00, 0x0000ae00, 0x00000800, - 0x0000ba00, 0x00007800, 0x00002500, 0x00002e00, - 0x00001c00, 0x0000a600, 0x0000b400, 0x0000c600, - 0x0000e800, 0x0000dd00, 0x00007400, 0x00001f00, - 0x00004b00, 0x0000bd00, 0x00008b00, 0x00008a00, - 0x00007000, 0x00003e00, 0x0000b500, 0x00006600, - 0x00004800, 0x00000300, 0x0000f600, 0x00000e00, - 0x00006100, 0x00003500, 0x00005700, 0x0000b900, - 0x00008600, 0x0000c100, 0x00001d00, 0x00009e00, - 0x0000e100, 0x0000f800, 0x00009800, 0x00001100, - 0x00006900, 0x0000d900, 0x00008e00, 0x00009400, - 0x00009b00, 0x00001e00, 0x00008700, 0x0000e900, - 0x0000ce00, 0x00005500, 0x00002800, 0x0000df00, - 0x00008c00, 0x0000a100, 0x00008900, 0x00000d00, - 0x0000bf00, 0x0000e600, 0x00004200, 0x00006800, - 0x00004100, 0x00009900, 0x00002d00, 0x00000f00, - 0x0000b000, 0x00005400, 0x0000bb00, 0x00001600, - }, { - 0x00630000, 0x007c0000, 0x00770000, 0x007b0000, - 0x00f20000, 0x006b0000, 0x006f0000, 0x00c50000, - 0x00300000, 0x00010000, 0x00670000, 0x002b0000, - 0x00fe0000, 0x00d70000, 0x00ab0000, 0x00760000, - 0x00ca0000, 0x00820000, 0x00c90000, 0x007d0000, - 0x00fa0000, 0x00590000, 0x00470000, 0x00f00000, - 0x00ad0000, 0x00d40000, 0x00a20000, 0x00af0000, - 0x009c0000, 0x00a40000, 0x00720000, 0x00c00000, - 0x00b70000, 0x00fd0000, 0x00930000, 0x00260000, - 0x00360000, 0x003f0000, 0x00f70000, 0x00cc0000, - 0x00340000, 0x00a50000, 0x00e50000, 0x00f10000, - 0x00710000, 0x00d80000, 0x00310000, 0x00150000, - 0x00040000, 0x00c70000, 0x00230000, 0x00c30000, - 0x00180000, 0x00960000, 0x00050000, 0x009a0000, - 0x00070000, 0x00120000, 0x00800000, 0x00e20000, - 0x00eb0000, 0x00270000, 0x00b20000, 0x00750000, - 0x00090000, 0x00830000, 0x002c0000, 0x001a0000, - 0x001b0000, 0x006e0000, 0x005a0000, 0x00a00000, - 0x00520000, 0x003b0000, 0x00d60000, 0x00b30000, - 0x00290000, 0x00e30000, 0x002f0000, 0x00840000, - 0x00530000, 0x00d10000, 0x00000000, 0x00ed0000, - 0x00200000, 0x00fc0000, 0x00b10000, 0x005b0000, - 0x006a0000, 0x00cb0000, 0x00be0000, 0x00390000, - 0x004a0000, 0x004c0000, 0x00580000, 0x00cf0000, - 0x00d00000, 0x00ef0000, 0x00aa0000, 0x00fb0000, - 0x00430000, 0x004d0000, 0x00330000, 0x00850000, - 0x00450000, 0x00f90000, 0x00020000, 0x007f0000, - 0x00500000, 0x003c0000, 0x009f0000, 0x00a80000, - 0x00510000, 0x00a30000, 0x00400000, 0x008f0000, - 0x00920000, 0x009d0000, 0x00380000, 0x00f50000, - 0x00bc0000, 0x00b60000, 0x00da0000, 0x00210000, - 0x00100000, 0x00ff0000, 0x00f30000, 0x00d20000, - 0x00cd0000, 0x000c0000, 0x00130000, 0x00ec0000, - 0x005f0000, 0x00970000, 0x00440000, 0x00170000, - 0x00c40000, 0x00a70000, 0x007e0000, 0x003d0000, - 0x00640000, 0x005d0000, 0x00190000, 0x00730000, - 0x00600000, 0x00810000, 0x004f0000, 0x00dc0000, - 0x00220000, 0x002a0000, 0x00900000, 0x00880000, - 0x00460000, 0x00ee0000, 0x00b80000, 0x00140000, - 0x00de0000, 0x005e0000, 0x000b0000, 0x00db0000, - 0x00e00000, 0x00320000, 0x003a0000, 0x000a0000, - 0x00490000, 0x00060000, 0x00240000, 0x005c0000, - 0x00c20000, 0x00d30000, 0x00ac0000, 0x00620000, - 0x00910000, 0x00950000, 0x00e40000, 0x00790000, - 0x00e70000, 0x00c80000, 0x00370000, 0x006d0000, - 0x008d0000, 0x00d50000, 0x004e0000, 0x00a90000, - 0x006c0000, 0x00560000, 0x00f40000, 0x00ea0000, - 0x00650000, 0x007a0000, 0x00ae0000, 0x00080000, - 0x00ba0000, 0x00780000, 0x00250000, 0x002e0000, - 0x001c0000, 0x00a60000, 0x00b40000, 0x00c60000, - 0x00e80000, 0x00dd0000, 0x00740000, 0x001f0000, - 0x004b0000, 0x00bd0000, 0x008b0000, 0x008a0000, - 0x00700000, 0x003e0000, 0x00b50000, 0x00660000, - 0x00480000, 0x00030000, 0x00f60000, 0x000e0000, - 0x00610000, 0x00350000, 0x00570000, 0x00b90000, - 0x00860000, 0x00c10000, 0x001d0000, 0x009e0000, - 0x00e10000, 0x00f80000, 0x00980000, 0x00110000, - 0x00690000, 0x00d90000, 0x008e0000, 0x00940000, - 0x009b0000, 0x001e0000, 0x00870000, 0x00e90000, - 0x00ce0000, 0x00550000, 0x00280000, 0x00df0000, - 0x008c0000, 0x00a10000, 0x00890000, 0x000d0000, - 0x00bf0000, 0x00e60000, 0x00420000, 0x00680000, - 0x00410000, 0x00990000, 0x002d0000, 0x000f0000, - 0x00b00000, 0x00540000, 0x00bb0000, 0x00160000, - }, { - 0x63000000, 0x7c000000, 0x77000000, 0x7b000000, - 0xf2000000, 0x6b000000, 0x6f000000, 0xc5000000, - 0x30000000, 0x01000000, 0x67000000, 0x2b000000, - 0xfe000000, 0xd7000000, 0xab000000, 0x76000000, - 0xca000000, 0x82000000, 0xc9000000, 0x7d000000, - 0xfa000000, 0x59000000, 0x47000000, 0xf0000000, - 0xad000000, 0xd4000000, 0xa2000000, 0xaf000000, - 0x9c000000, 0xa4000000, 0x72000000, 0xc0000000, - 0xb7000000, 0xfd000000, 0x93000000, 0x26000000, - 0x36000000, 0x3f000000, 0xf7000000, 0xcc000000, - 0x34000000, 0xa5000000, 0xe5000000, 0xf1000000, - 0x71000000, 0xd8000000, 0x31000000, 0x15000000, - 0x04000000, 0xc7000000, 0x23000000, 0xc3000000, - 0x18000000, 0x96000000, 0x05000000, 0x9a000000, - 0x07000000, 0x12000000, 0x80000000, 0xe2000000, - 0xeb000000, 0x27000000, 0xb2000000, 0x75000000, - 0x09000000, 0x83000000, 0x2c000000, 0x1a000000, - 0x1b000000, 0x6e000000, 0x5a000000, 0xa0000000, - 0x52000000, 0x3b000000, 0xd6000000, 0xb3000000, - 0x29000000, 0xe3000000, 0x2f000000, 0x84000000, - 0x53000000, 0xd1000000, 0x00000000, 0xed000000, - 0x20000000, 0xfc000000, 0xb1000000, 0x5b000000, - 0x6a000000, 0xcb000000, 0xbe000000, 0x39000000, - 0x4a000000, 0x4c000000, 0x58000000, 0xcf000000, - 0xd0000000, 0xef000000, 0xaa000000, 0xfb000000, - 0x43000000, 0x4d000000, 0x33000000, 0x85000000, - 0x45000000, 0xf9000000, 0x02000000, 0x7f000000, - 0x50000000, 0x3c000000, 0x9f000000, 0xa8000000, - 0x51000000, 0xa3000000, 0x40000000, 0x8f000000, - 0x92000000, 0x9d000000, 0x38000000, 0xf5000000, - 0xbc000000, 0xb6000000, 0xda000000, 0x21000000, - 0x10000000, 0xff000000, 0xf3000000, 0xd2000000, - 0xcd000000, 0x0c000000, 0x13000000, 0xec000000, - 0x5f000000, 0x97000000, 0x44000000, 0x17000000, - 0xc4000000, 0xa7000000, 0x7e000000, 0x3d000000, - 0x64000000, 0x5d000000, 0x19000000, 0x73000000, - 0x60000000, 0x81000000, 0x4f000000, 0xdc000000, - 0x22000000, 0x2a000000, 0x90000000, 0x88000000, - 0x46000000, 0xee000000, 0xb8000000, 0x14000000, - 0xde000000, 0x5e000000, 0x0b000000, 0xdb000000, - 0xe0000000, 0x32000000, 0x3a000000, 0x0a000000, - 0x49000000, 0x06000000, 0x24000000, 0x5c000000, - 0xc2000000, 0xd3000000, 0xac000000, 0x62000000, - 0x91000000, 0x95000000, 0xe4000000, 0x79000000, - 0xe7000000, 0xc8000000, 0x37000000, 0x6d000000, - 0x8d000000, 0xd5000000, 0x4e000000, 0xa9000000, - 0x6c000000, 0x56000000, 0xf4000000, 0xea000000, - 0x65000000, 0x7a000000, 0xae000000, 0x08000000, - 0xba000000, 0x78000000, 0x25000000, 0x2e000000, - 0x1c000000, 0xa6000000, 0xb4000000, 0xc6000000, - 0xe8000000, 0xdd000000, 0x74000000, 0x1f000000, - 0x4b000000, 0xbd000000, 0x8b000000, 0x8a000000, - 0x70000000, 0x3e000000, 0xb5000000, 0x66000000, - 0x48000000, 0x03000000, 0xf6000000, 0x0e000000, - 0x61000000, 0x35000000, 0x57000000, 0xb9000000, - 0x86000000, 0xc1000000, 0x1d000000, 0x9e000000, - 0xe1000000, 0xf8000000, 0x98000000, 0x11000000, - 0x69000000, 0xd9000000, 0x8e000000, 0x94000000, - 0x9b000000, 0x1e000000, 0x87000000, 0xe9000000, - 0xce000000, 0x55000000, 0x28000000, 0xdf000000, - 0x8c000000, 0xa1000000, 0x89000000, 0x0d000000, - 0xbf000000, 0xe6000000, 0x42000000, 0x68000000, - 0x41000000, 0x99000000, 0x2d000000, 0x0f000000, - 0xb0000000, 0x54000000, 0xbb000000, 0x16000000, - } -}; - -__visible const u32 crypto_it_tab[4][256] = { - { - 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, - 0xcb6bab3b, 0xf1459d1f, 0xab58faac, 0x9303e34b, - 0x55fa3020, 0xf66d76ad, 0x9176cc88, 0x254c02f5, - 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, 0x8fa362b5, - 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, - 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, - 0xe75f8f03, 0x959c9215, 0xeb7a6dbf, 0xda595295, - 0x2d83bed4, 0xd3217458, 0x2969e049, 0x44c8c98e, - 0x6a89c275, 0x78798ef4, 0x6b3e5899, 0xdd71b927, - 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, - 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, - 0xe07764b1, 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, - 0x58684870, 0x19fd458f, 0x876cde94, 0xb7f87b52, - 0x23d373ab, 0xe2024b72, 0x578f1fe3, 0x2aab5566, - 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3, - 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, - 0x2b1ccf8a, 0x92b479a7, 0xf0f207f3, 0xa1e2694e, - 0xcdf4da65, 0xd5be0506, 0x1f6234d1, 0x8afea6c4, - 0x9d532e34, 0xa055f3a2, 0x32e18a05, 0x75ebf6a4, - 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd, - 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, - 0xb58d5491, 0x055dc471, 0x6fd40604, 0xff155060, - 0x24fb9819, 0x97e9bdd6, 0xcc434089, 0x779ed967, - 0xbd42e8b0, 0x888b8907, 0x385b19e7, 0xdbeec879, - 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, - 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, - 0xfbff0efd, 0x5638850f, 0x1ed5ae3d, 0x27392d36, - 0x64d90f0a, 0x21a65c68, 0xd1545b9b, 0x3a2e3624, - 0xb1670a0c, 0x0fe75793, 0xd296eeb4, 0x9e919b1b, - 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, - 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, - 0x0b0d090e, 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, - 0x8519f157, 0x4c0775af, 0xbbdd99ee, 0xfd607fa3, - 0x9f2601f7, 0xbcf5725c, 0xc53b6644, 0x347efb5b, - 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, - 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, - 0x7d244a85, 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, - 0x4b2f9e1d, 0xf330b2dc, 0xec52860d, 0xd0e3c177, - 0x6c16b32b, 0x99b970a9, 0xfa489411, 0x2264e947, - 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, - 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, - 0xcf81f5a6, 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, - 0xe49d3a2c, 0x0d927850, 0x9bcc5f6a, 0x62467e54, - 0xc2138df6, 0xe8b8d890, 0x5ef7392e, 0xf5afc382, - 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, - 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, - 0x097826cd, 0xf418596e, 0x01b79aec, 0xa89a4f83, - 0x656e95e6, 0x7ee6ffaa, 0x08cfbc21, 0xe6e815ef, - 0xd99be7ba, 0xce366f4a, 0xd4099fea, 0xd67cb029, - 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, - 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, - 0x4a9804f1, 0xf7daec41, 0x0e50cd7f, 0x2ff69117, - 0x8dd64d76, 0x4db0ef43, 0x544daacc, 0xdf0496e4, - 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, 0x7f516546, - 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, - 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, - 0x8c61d79a, 0x7a0ca137, 0x8e14f859, 0x893c13eb, - 0xee27a9ce, 0x35c961b7, 0xede51ce1, 0x3cb1477a, - 0x59dfd29c, 0x3f73f255, 0x79ce1418, 0xbf37c773, - 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, - 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, - 0x72c31d16, 0x0c25e2bc, 0x8b493c28, 0x41950dff, - 0x7101a839, 0xdeb30c08, 0x9ce4b4d8, 0x90c15664, - 0x6184cb7b, 0x70b632d5, 0x745c6c48, 0x4257b8d0, - }, { - 0xa7f45150, 0x65417e53, 0xa4171ac3, 0x5e273a96, - 0x6bab3bcb, 0x459d1ff1, 0x58faacab, 0x03e34b93, - 0xfa302055, 0x6d76adf6, 0x76cc8891, 0x4c02f525, - 0xd7e54ffc, 0xcb2ac5d7, 0x44352680, 0xa362b58f, - 0x5ab1de49, 0x1bba2567, 0x0eea4598, 0xc0fe5de1, - 0x752fc302, 0xf04c8112, 0x97468da3, 0xf9d36bc6, - 0x5f8f03e7, 0x9c921595, 0x7a6dbfeb, 0x595295da, - 0x83bed42d, 0x217458d3, 0x69e04929, 0xc8c98e44, - 0x89c2756a, 0x798ef478, 0x3e58996b, 0x71b927dd, - 0x4fe1beb6, 0xad88f017, 0xac20c966, 0x3ace7db4, - 0x4adf6318, 0x311ae582, 0x33519760, 0x7f536245, - 0x7764b1e0, 0xae6bbb84, 0xa081fe1c, 0x2b08f994, - 0x68487058, 0xfd458f19, 0x6cde9487, 0xf87b52b7, - 0xd373ab23, 0x024b72e2, 0x8f1fe357, 0xab55662a, - 0x28ebb207, 0xc2b52f03, 0x7bc5869a, 0x0837d3a5, - 0x872830f2, 0xa5bf23b2, 0x6a0302ba, 0x8216ed5c, - 0x1ccf8a2b, 0xb479a792, 0xf207f3f0, 0xe2694ea1, - 0xf4da65cd, 0xbe0506d5, 0x6234d11f, 0xfea6c48a, - 0x532e349d, 0x55f3a2a0, 0xe18a0532, 0xebf6a475, - 0xec830b39, 0xef6040aa, 0x9f715e06, 0x106ebd51, - 0x8a213ef9, 0x06dd963d, 0x053eddae, 0xbde64d46, - 0x8d5491b5, 0x5dc47105, 0xd406046f, 0x155060ff, - 0xfb981924, 0xe9bdd697, 0x434089cc, 0x9ed96777, - 0x42e8b0bd, 0x8b890788, 0x5b19e738, 0xeec879db, - 0x0a7ca147, 0x0f427ce9, 0x1e84f8c9, 0x00000000, - 0x86800983, 0xed2b3248, 0x70111eac, 0x725a6c4e, - 0xff0efdfb, 0x38850f56, 0xd5ae3d1e, 0x392d3627, - 0xd90f0a64, 0xa65c6821, 0x545b9bd1, 0x2e36243a, - 0x670a0cb1, 0xe757930f, 0x96eeb4d2, 0x919b1b9e, - 0xc5c0804f, 0x20dc61a2, 0x4b775a69, 0x1a121c16, - 0xba93e20a, 0x2aa0c0e5, 0xe0223c43, 0x171b121d, - 0x0d090e0b, 0xc78bf2ad, 0xa8b62db9, 0xa91e14c8, - 0x19f15785, 0x0775af4c, 0xdd99eebb, 0x607fa3fd, - 0x2601f79f, 0xf5725cbc, 0x3b6644c5, 0x7efb5b34, - 0x29438b76, 0xc623cbdc, 0xfcedb668, 0xf1e4b863, - 0xdc31d7ca, 0x85634210, 0x22971340, 0x11c68420, - 0x244a857d, 0x3dbbd2f8, 0x32f9ae11, 0xa129c76d, - 0x2f9e1d4b, 0x30b2dcf3, 0x52860dec, 0xe3c177d0, - 0x16b32b6c, 0xb970a999, 0x489411fa, 0x64e94722, - 0x8cfca8c4, 0x3ff0a01a, 0x2c7d56d8, 0x903322ef, - 0x4e4987c7, 0xd138d9c1, 0xa2ca8cfe, 0x0bd49836, - 0x81f5a6cf, 0xde7aa528, 0x8eb7da26, 0xbfad3fa4, - 0x9d3a2ce4, 0x9278500d, 0xcc5f6a9b, 0x467e5462, - 0x138df6c2, 0xb8d890e8, 0xf7392e5e, 0xafc382f5, - 0x805d9fbe, 0x93d0697c, 0x2dd56fa9, 0x1225cfb3, - 0x99acc83b, 0x7d1810a7, 0x639ce86e, 0xbb3bdb7b, - 0x7826cd09, 0x18596ef4, 0xb79aec01, 0x9a4f83a8, - 0x6e95e665, 0xe6ffaa7e, 0xcfbc2108, 0xe815efe6, - 0x9be7bad9, 0x366f4ace, 0x099fead4, 0x7cb029d6, - 0xb2a431af, 0x233f2a31, 0x94a5c630, 0x66a235c0, - 0xbc4e7437, 0xca82fca6, 0xd090e0b0, 0xd8a73315, - 0x9804f14a, 0xdaec41f7, 0x50cd7f0e, 0xf691172f, - 0xd64d768d, 0xb0ef434d, 0x4daacc54, 0x0496e4df, - 0xb5d19ee3, 0x886a4c1b, 0x1f2cc1b8, 0x5165467f, - 0xea5e9d04, 0x358c015d, 0x7487fa73, 0x410bfb2e, - 0x1d67b35a, 0xd2db9252, 0x5610e933, 0x47d66d13, - 0x61d79a8c, 0x0ca1377a, 0x14f8598e, 0x3c13eb89, - 0x27a9ceee, 0xc961b735, 0xe51ce1ed, 0xb1477a3c, - 0xdfd29c59, 0x73f2553f, 0xce141879, 0x37c773bf, - 0xcdf753ea, 0xaafd5f5b, 0x6f3ddf14, 0xdb447886, - 0xf3afca81, 0xc468b93e, 0x3424382c, 0x40a3c25f, - 0xc31d1672, 0x25e2bc0c, 0x493c288b, 0x950dff41, - 0x01a83971, 0xb30c08de, 0xe4b4d89c, 0xc1566490, - 0x84cb7b61, 0xb632d570, 0x5c6c4874, 0x57b8d042, - }, { - 0xf45150a7, 0x417e5365, 0x171ac3a4, 0x273a965e, - 0xab3bcb6b, 0x9d1ff145, 0xfaacab58, 0xe34b9303, - 0x302055fa, 0x76adf66d, 0xcc889176, 0x02f5254c, - 0xe54ffcd7, 0x2ac5d7cb, 0x35268044, 0x62b58fa3, - 0xb1de495a, 0xba25671b, 0xea45980e, 0xfe5de1c0, - 0x2fc30275, 0x4c8112f0, 0x468da397, 0xd36bc6f9, - 0x8f03e75f, 0x9215959c, 0x6dbfeb7a, 0x5295da59, - 0xbed42d83, 0x7458d321, 0xe0492969, 0xc98e44c8, - 0xc2756a89, 0x8ef47879, 0x58996b3e, 0xb927dd71, - 0xe1beb64f, 0x88f017ad, 0x20c966ac, 0xce7db43a, - 0xdf63184a, 0x1ae58231, 0x51976033, 0x5362457f, - 0x64b1e077, 0x6bbb84ae, 0x81fe1ca0, 0x08f9942b, - 0x48705868, 0x458f19fd, 0xde94876c, 0x7b52b7f8, - 0x73ab23d3, 0x4b72e202, 0x1fe3578f, 0x55662aab, - 0xebb20728, 0xb52f03c2, 0xc5869a7b, 0x37d3a508, - 0x2830f287, 0xbf23b2a5, 0x0302ba6a, 0x16ed5c82, - 0xcf8a2b1c, 0x79a792b4, 0x07f3f0f2, 0x694ea1e2, - 0xda65cdf4, 0x0506d5be, 0x34d11f62, 0xa6c48afe, - 0x2e349d53, 0xf3a2a055, 0x8a0532e1, 0xf6a475eb, - 0x830b39ec, 0x6040aaef, 0x715e069f, 0x6ebd5110, - 0x213ef98a, 0xdd963d06, 0x3eddae05, 0xe64d46bd, - 0x5491b58d, 0xc471055d, 0x06046fd4, 0x5060ff15, - 0x981924fb, 0xbdd697e9, 0x4089cc43, 0xd967779e, - 0xe8b0bd42, 0x8907888b, 0x19e7385b, 0xc879dbee, - 0x7ca1470a, 0x427ce90f, 0x84f8c91e, 0x00000000, - 0x80098386, 0x2b3248ed, 0x111eac70, 0x5a6c4e72, - 0x0efdfbff, 0x850f5638, 0xae3d1ed5, 0x2d362739, - 0x0f0a64d9, 0x5c6821a6, 0x5b9bd154, 0x36243a2e, - 0x0a0cb167, 0x57930fe7, 0xeeb4d296, 0x9b1b9e91, - 0xc0804fc5, 0xdc61a220, 0x775a694b, 0x121c161a, - 0x93e20aba, 0xa0c0e52a, 0x223c43e0, 0x1b121d17, - 0x090e0b0d, 0x8bf2adc7, 0xb62db9a8, 0x1e14c8a9, - 0xf1578519, 0x75af4c07, 0x99eebbdd, 0x7fa3fd60, - 0x01f79f26, 0x725cbcf5, 0x6644c53b, 0xfb5b347e, - 0x438b7629, 0x23cbdcc6, 0xedb668fc, 0xe4b863f1, - 0x31d7cadc, 0x63421085, 0x97134022, 0xc6842011, - 0x4a857d24, 0xbbd2f83d, 0xf9ae1132, 0x29c76da1, - 0x9e1d4b2f, 0xb2dcf330, 0x860dec52, 0xc177d0e3, - 0xb32b6c16, 0x70a999b9, 0x9411fa48, 0xe9472264, - 0xfca8c48c, 0xf0a01a3f, 0x7d56d82c, 0x3322ef90, - 0x4987c74e, 0x38d9c1d1, 0xca8cfea2, 0xd498360b, - 0xf5a6cf81, 0x7aa528de, 0xb7da268e, 0xad3fa4bf, - 0x3a2ce49d, 0x78500d92, 0x5f6a9bcc, 0x7e546246, - 0x8df6c213, 0xd890e8b8, 0x392e5ef7, 0xc382f5af, - 0x5d9fbe80, 0xd0697c93, 0xd56fa92d, 0x25cfb312, - 0xacc83b99, 0x1810a77d, 0x9ce86e63, 0x3bdb7bbb, - 0x26cd0978, 0x596ef418, 0x9aec01b7, 0x4f83a89a, - 0x95e6656e, 0xffaa7ee6, 0xbc2108cf, 0x15efe6e8, - 0xe7bad99b, 0x6f4ace36, 0x9fead409, 0xb029d67c, - 0xa431afb2, 0x3f2a3123, 0xa5c63094, 0xa235c066, - 0x4e7437bc, 0x82fca6ca, 0x90e0b0d0, 0xa73315d8, - 0x04f14a98, 0xec41f7da, 0xcd7f0e50, 0x91172ff6, - 0x4d768dd6, 0xef434db0, 0xaacc544d, 0x96e4df04, - 0xd19ee3b5, 0x6a4c1b88, 0x2cc1b81f, 0x65467f51, - 0x5e9d04ea, 0x8c015d35, 0x87fa7374, 0x0bfb2e41, - 0x67b35a1d, 0xdb9252d2, 0x10e93356, 0xd66d1347, - 0xd79a8c61, 0xa1377a0c, 0xf8598e14, 0x13eb893c, - 0xa9ceee27, 0x61b735c9, 0x1ce1ede5, 0x477a3cb1, - 0xd29c59df, 0xf2553f73, 0x141879ce, 0xc773bf37, - 0xf753eacd, 0xfd5f5baa, 0x3ddf146f, 0x447886db, - 0xafca81f3, 0x68b93ec4, 0x24382c34, 0xa3c25f40, - 0x1d1672c3, 0xe2bc0c25, 0x3c288b49, 0x0dff4195, - 0xa8397101, 0x0c08deb3, 0xb4d89ce4, 0x566490c1, - 0xcb7b6184, 0x32d570b6, 0x6c48745c, 0xb8d04257, - }, { - 0x5150a7f4, 0x7e536541, 0x1ac3a417, 0x3a965e27, - 0x3bcb6bab, 0x1ff1459d, 0xacab58fa, 0x4b9303e3, - 0x2055fa30, 0xadf66d76, 0x889176cc, 0xf5254c02, - 0x4ffcd7e5, 0xc5d7cb2a, 0x26804435, 0xb58fa362, - 0xde495ab1, 0x25671bba, 0x45980eea, 0x5de1c0fe, - 0xc302752f, 0x8112f04c, 0x8da39746, 0x6bc6f9d3, - 0x03e75f8f, 0x15959c92, 0xbfeb7a6d, 0x95da5952, - 0xd42d83be, 0x58d32174, 0x492969e0, 0x8e44c8c9, - 0x756a89c2, 0xf478798e, 0x996b3e58, 0x27dd71b9, - 0xbeb64fe1, 0xf017ad88, 0xc966ac20, 0x7db43ace, - 0x63184adf, 0xe582311a, 0x97603351, 0x62457f53, - 0xb1e07764, 0xbb84ae6b, 0xfe1ca081, 0xf9942b08, - 0x70586848, 0x8f19fd45, 0x94876cde, 0x52b7f87b, - 0xab23d373, 0x72e2024b, 0xe3578f1f, 0x662aab55, - 0xb20728eb, 0x2f03c2b5, 0x869a7bc5, 0xd3a50837, - 0x30f28728, 0x23b2a5bf, 0x02ba6a03, 0xed5c8216, - 0x8a2b1ccf, 0xa792b479, 0xf3f0f207, 0x4ea1e269, - 0x65cdf4da, 0x06d5be05, 0xd11f6234, 0xc48afea6, - 0x349d532e, 0xa2a055f3, 0x0532e18a, 0xa475ebf6, - 0x0b39ec83, 0x40aaef60, 0x5e069f71, 0xbd51106e, - 0x3ef98a21, 0x963d06dd, 0xddae053e, 0x4d46bde6, - 0x91b58d54, 0x71055dc4, 0x046fd406, 0x60ff1550, - 0x1924fb98, 0xd697e9bd, 0x89cc4340, 0x67779ed9, - 0xb0bd42e8, 0x07888b89, 0xe7385b19, 0x79dbeec8, - 0xa1470a7c, 0x7ce90f42, 0xf8c91e84, 0x00000000, - 0x09838680, 0x3248ed2b, 0x1eac7011, 0x6c4e725a, - 0xfdfbff0e, 0x0f563885, 0x3d1ed5ae, 0x3627392d, - 0x0a64d90f, 0x6821a65c, 0x9bd1545b, 0x243a2e36, - 0x0cb1670a, 0x930fe757, 0xb4d296ee, 0x1b9e919b, - 0x804fc5c0, 0x61a220dc, 0x5a694b77, 0x1c161a12, - 0xe20aba93, 0xc0e52aa0, 0x3c43e022, 0x121d171b, - 0x0e0b0d09, 0xf2adc78b, 0x2db9a8b6, 0x14c8a91e, - 0x578519f1, 0xaf4c0775, 0xeebbdd99, 0xa3fd607f, - 0xf79f2601, 0x5cbcf572, 0x44c53b66, 0x5b347efb, - 0x8b762943, 0xcbdcc623, 0xb668fced, 0xb863f1e4, - 0xd7cadc31, 0x42108563, 0x13402297, 0x842011c6, - 0x857d244a, 0xd2f83dbb, 0xae1132f9, 0xc76da129, - 0x1d4b2f9e, 0xdcf330b2, 0x0dec5286, 0x77d0e3c1, - 0x2b6c16b3, 0xa999b970, 0x11fa4894, 0x472264e9, - 0xa8c48cfc, 0xa01a3ff0, 0x56d82c7d, 0x22ef9033, - 0x87c74e49, 0xd9c1d138, 0x8cfea2ca, 0x98360bd4, - 0xa6cf81f5, 0xa528de7a, 0xda268eb7, 0x3fa4bfad, - 0x2ce49d3a, 0x500d9278, 0x6a9bcc5f, 0x5462467e, - 0xf6c2138d, 0x90e8b8d8, 0x2e5ef739, 0x82f5afc3, - 0x9fbe805d, 0x697c93d0, 0x6fa92dd5, 0xcfb31225, - 0xc83b99ac, 0x10a77d18, 0xe86e639c, 0xdb7bbb3b, - 0xcd097826, 0x6ef41859, 0xec01b79a, 0x83a89a4f, - 0xe6656e95, 0xaa7ee6ff, 0x2108cfbc, 0xefe6e815, - 0xbad99be7, 0x4ace366f, 0xead4099f, 0x29d67cb0, - 0x31afb2a4, 0x2a31233f, 0xc63094a5, 0x35c066a2, - 0x7437bc4e, 0xfca6ca82, 0xe0b0d090, 0x3315d8a7, - 0xf14a9804, 0x41f7daec, 0x7f0e50cd, 0x172ff691, - 0x768dd64d, 0x434db0ef, 0xcc544daa, 0xe4df0496, - 0x9ee3b5d1, 0x4c1b886a, 0xc1b81f2c, 0x467f5165, - 0x9d04ea5e, 0x015d358c, 0xfa737487, 0xfb2e410b, - 0xb35a1d67, 0x9252d2db, 0xe9335610, 0x6d1347d6, - 0x9a8c61d7, 0x377a0ca1, 0x598e14f8, 0xeb893c13, - 0xceee27a9, 0xb735c961, 0xe1ede51c, 0x7a3cb147, - 0x9c59dfd2, 0x553f73f2, 0x1879ce14, 0x73bf37c7, - 0x53eacdf7, 0x5f5baafd, 0xdf146f3d, 0x7886db44, - 0xca81f3af, 0xb93ec468, 0x382c3424, 0xc25f40a3, - 0x1672c31d, 0xbc0c25e2, 0x288b493c, 0xff41950d, - 0x397101a8, 0x08deb30c, 0xd89ce4b4, 0x6490c156, - 0x7b6184cb, 0xd570b632, 0x48745c6c, 0xd04257b8, - } -}; - -__visible const u32 crypto_il_tab[4][256] = { - { - 0x00000052, 0x00000009, 0x0000006a, 0x000000d5, - 0x00000030, 0x00000036, 0x000000a5, 0x00000038, - 0x000000bf, 0x00000040, 0x000000a3, 0x0000009e, - 0x00000081, 0x000000f3, 0x000000d7, 0x000000fb, - 0x0000007c, 0x000000e3, 0x00000039, 0x00000082, - 0x0000009b, 0x0000002f, 0x000000ff, 0x00000087, - 0x00000034, 0x0000008e, 0x00000043, 0x00000044, - 0x000000c4, 0x000000de, 0x000000e9, 0x000000cb, - 0x00000054, 0x0000007b, 0x00000094, 0x00000032, - 0x000000a6, 0x000000c2, 0x00000023, 0x0000003d, - 0x000000ee, 0x0000004c, 0x00000095, 0x0000000b, - 0x00000042, 0x000000fa, 0x000000c3, 0x0000004e, - 0x00000008, 0x0000002e, 0x000000a1, 0x00000066, - 0x00000028, 0x000000d9, 0x00000024, 0x000000b2, - 0x00000076, 0x0000005b, 0x000000a2, 0x00000049, - 0x0000006d, 0x0000008b, 0x000000d1, 0x00000025, - 0x00000072, 0x000000f8, 0x000000f6, 0x00000064, - 0x00000086, 0x00000068, 0x00000098, 0x00000016, - 0x000000d4, 0x000000a4, 0x0000005c, 0x000000cc, - 0x0000005d, 0x00000065, 0x000000b6, 0x00000092, - 0x0000006c, 0x00000070, 0x00000048, 0x00000050, - 0x000000fd, 0x000000ed, 0x000000b9, 0x000000da, - 0x0000005e, 0x00000015, 0x00000046, 0x00000057, - 0x000000a7, 0x0000008d, 0x0000009d, 0x00000084, - 0x00000090, 0x000000d8, 0x000000ab, 0x00000000, - 0x0000008c, 0x000000bc, 0x000000d3, 0x0000000a, - 0x000000f7, 0x000000e4, 0x00000058, 0x00000005, - 0x000000b8, 0x000000b3, 0x00000045, 0x00000006, - 0x000000d0, 0x0000002c, 0x0000001e, 0x0000008f, - 0x000000ca, 0x0000003f, 0x0000000f, 0x00000002, - 0x000000c1, 0x000000af, 0x000000bd, 0x00000003, - 0x00000001, 0x00000013, 0x0000008a, 0x0000006b, - 0x0000003a, 0x00000091, 0x00000011, 0x00000041, - 0x0000004f, 0x00000067, 0x000000dc, 0x000000ea, - 0x00000097, 0x000000f2, 0x000000cf, 0x000000ce, - 0x000000f0, 0x000000b4, 0x000000e6, 0x00000073, - 0x00000096, 0x000000ac, 0x00000074, 0x00000022, - 0x000000e7, 0x000000ad, 0x00000035, 0x00000085, - 0x000000e2, 0x000000f9, 0x00000037, 0x000000e8, - 0x0000001c, 0x00000075, 0x000000df, 0x0000006e, - 0x00000047, 0x000000f1, 0x0000001a, 0x00000071, - 0x0000001d, 0x00000029, 0x000000c5, 0x00000089, - 0x0000006f, 0x000000b7, 0x00000062, 0x0000000e, - 0x000000aa, 0x00000018, 0x000000be, 0x0000001b, - 0x000000fc, 0x00000056, 0x0000003e, 0x0000004b, - 0x000000c6, 0x000000d2, 0x00000079, 0x00000020, - 0x0000009a, 0x000000db, 0x000000c0, 0x000000fe, - 0x00000078, 0x000000cd, 0x0000005a, 0x000000f4, - 0x0000001f, 0x000000dd, 0x000000a8, 0x00000033, - 0x00000088, 0x00000007, 0x000000c7, 0x00000031, - 0x000000b1, 0x00000012, 0x00000010, 0x00000059, - 0x00000027, 0x00000080, 0x000000ec, 0x0000005f, - 0x00000060, 0x00000051, 0x0000007f, 0x000000a9, - 0x00000019, 0x000000b5, 0x0000004a, 0x0000000d, - 0x0000002d, 0x000000e5, 0x0000007a, 0x0000009f, - 0x00000093, 0x000000c9, 0x0000009c, 0x000000ef, - 0x000000a0, 0x000000e0, 0x0000003b, 0x0000004d, - 0x000000ae, 0x0000002a, 0x000000f5, 0x000000b0, - 0x000000c8, 0x000000eb, 0x000000bb, 0x0000003c, - 0x00000083, 0x00000053, 0x00000099, 0x00000061, - 0x00000017, 0x0000002b, 0x00000004, 0x0000007e, - 0x000000ba, 0x00000077, 0x000000d6, 0x00000026, - 0x000000e1, 0x00000069, 0x00000014, 0x00000063, - 0x00000055, 0x00000021, 0x0000000c, 0x0000007d, - }, { - 0x00005200, 0x00000900, 0x00006a00, 0x0000d500, - 0x00003000, 0x00003600, 0x0000a500, 0x00003800, - 0x0000bf00, 0x00004000, 0x0000a300, 0x00009e00, - 0x00008100, 0x0000f300, 0x0000d700, 0x0000fb00, - 0x00007c00, 0x0000e300, 0x00003900, 0x00008200, - 0x00009b00, 0x00002f00, 0x0000ff00, 0x00008700, - 0x00003400, 0x00008e00, 0x00004300, 0x00004400, - 0x0000c400, 0x0000de00, 0x0000e900, 0x0000cb00, - 0x00005400, 0x00007b00, 0x00009400, 0x00003200, - 0x0000a600, 0x0000c200, 0x00002300, 0x00003d00, - 0x0000ee00, 0x00004c00, 0x00009500, 0x00000b00, - 0x00004200, 0x0000fa00, 0x0000c300, 0x00004e00, - 0x00000800, 0x00002e00, 0x0000a100, 0x00006600, - 0x00002800, 0x0000d900, 0x00002400, 0x0000b200, - 0x00007600, 0x00005b00, 0x0000a200, 0x00004900, - 0x00006d00, 0x00008b00, 0x0000d100, 0x00002500, - 0x00007200, 0x0000f800, 0x0000f600, 0x00006400, - 0x00008600, 0x00006800, 0x00009800, 0x00001600, - 0x0000d400, 0x0000a400, 0x00005c00, 0x0000cc00, - 0x00005d00, 0x00006500, 0x0000b600, 0x00009200, - 0x00006c00, 0x00007000, 0x00004800, 0x00005000, - 0x0000fd00, 0x0000ed00, 0x0000b900, 0x0000da00, - 0x00005e00, 0x00001500, 0x00004600, 0x00005700, - 0x0000a700, 0x00008d00, 0x00009d00, 0x00008400, - 0x00009000, 0x0000d800, 0x0000ab00, 0x00000000, - 0x00008c00, 0x0000bc00, 0x0000d300, 0x00000a00, - 0x0000f700, 0x0000e400, 0x00005800, 0x00000500, - 0x0000b800, 0x0000b300, 0x00004500, 0x00000600, - 0x0000d000, 0x00002c00, 0x00001e00, 0x00008f00, - 0x0000ca00, 0x00003f00, 0x00000f00, 0x00000200, - 0x0000c100, 0x0000af00, 0x0000bd00, 0x00000300, - 0x00000100, 0x00001300, 0x00008a00, 0x00006b00, - 0x00003a00, 0x00009100, 0x00001100, 0x00004100, - 0x00004f00, 0x00006700, 0x0000dc00, 0x0000ea00, - 0x00009700, 0x0000f200, 0x0000cf00, 0x0000ce00, - 0x0000f000, 0x0000b400, 0x0000e600, 0x00007300, - 0x00009600, 0x0000ac00, 0x00007400, 0x00002200, - 0x0000e700, 0x0000ad00, 0x00003500, 0x00008500, - 0x0000e200, 0x0000f900, 0x00003700, 0x0000e800, - 0x00001c00, 0x00007500, 0x0000df00, 0x00006e00, - 0x00004700, 0x0000f100, 0x00001a00, 0x00007100, - 0x00001d00, 0x00002900, 0x0000c500, 0x00008900, - 0x00006f00, 0x0000b700, 0x00006200, 0x00000e00, - 0x0000aa00, 0x00001800, 0x0000be00, 0x00001b00, - 0x0000fc00, 0x00005600, 0x00003e00, 0x00004b00, - 0x0000c600, 0x0000d200, 0x00007900, 0x00002000, - 0x00009a00, 0x0000db00, 0x0000c000, 0x0000fe00, - 0x00007800, 0x0000cd00, 0x00005a00, 0x0000f400, - 0x00001f00, 0x0000dd00, 0x0000a800, 0x00003300, - 0x00008800, 0x00000700, 0x0000c700, 0x00003100, - 0x0000b100, 0x00001200, 0x00001000, 0x00005900, - 0x00002700, 0x00008000, 0x0000ec00, 0x00005f00, - 0x00006000, 0x00005100, 0x00007f00, 0x0000a900, - 0x00001900, 0x0000b500, 0x00004a00, 0x00000d00, - 0x00002d00, 0x0000e500, 0x00007a00, 0x00009f00, - 0x00009300, 0x0000c900, 0x00009c00, 0x0000ef00, - 0x0000a000, 0x0000e000, 0x00003b00, 0x00004d00, - 0x0000ae00, 0x00002a00, 0x0000f500, 0x0000b000, - 0x0000c800, 0x0000eb00, 0x0000bb00, 0x00003c00, - 0x00008300, 0x00005300, 0x00009900, 0x00006100, - 0x00001700, 0x00002b00, 0x00000400, 0x00007e00, - 0x0000ba00, 0x00007700, 0x0000d600, 0x00002600, - 0x0000e100, 0x00006900, 0x00001400, 0x00006300, - 0x00005500, 0x00002100, 0x00000c00, 0x00007d00, - }, { - 0x00520000, 0x00090000, 0x006a0000, 0x00d50000, - 0x00300000, 0x00360000, 0x00a50000, 0x00380000, - 0x00bf0000, 0x00400000, 0x00a30000, 0x009e0000, - 0x00810000, 0x00f30000, 0x00d70000, 0x00fb0000, - 0x007c0000, 0x00e30000, 0x00390000, 0x00820000, - 0x009b0000, 0x002f0000, 0x00ff0000, 0x00870000, - 0x00340000, 0x008e0000, 0x00430000, 0x00440000, - 0x00c40000, 0x00de0000, 0x00e90000, 0x00cb0000, - 0x00540000, 0x007b0000, 0x00940000, 0x00320000, - 0x00a60000, 0x00c20000, 0x00230000, 0x003d0000, - 0x00ee0000, 0x004c0000, 0x00950000, 0x000b0000, - 0x00420000, 0x00fa0000, 0x00c30000, 0x004e0000, - 0x00080000, 0x002e0000, 0x00a10000, 0x00660000, - 0x00280000, 0x00d90000, 0x00240000, 0x00b20000, - 0x00760000, 0x005b0000, 0x00a20000, 0x00490000, - 0x006d0000, 0x008b0000, 0x00d10000, 0x00250000, - 0x00720000, 0x00f80000, 0x00f60000, 0x00640000, - 0x00860000, 0x00680000, 0x00980000, 0x00160000, - 0x00d40000, 0x00a40000, 0x005c0000, 0x00cc0000, - 0x005d0000, 0x00650000, 0x00b60000, 0x00920000, - 0x006c0000, 0x00700000, 0x00480000, 0x00500000, - 0x00fd0000, 0x00ed0000, 0x00b90000, 0x00da0000, - 0x005e0000, 0x00150000, 0x00460000, 0x00570000, - 0x00a70000, 0x008d0000, 0x009d0000, 0x00840000, - 0x00900000, 0x00d80000, 0x00ab0000, 0x00000000, - 0x008c0000, 0x00bc0000, 0x00d30000, 0x000a0000, - 0x00f70000, 0x00e40000, 0x00580000, 0x00050000, - 0x00b80000, 0x00b30000, 0x00450000, 0x00060000, - 0x00d00000, 0x002c0000, 0x001e0000, 0x008f0000, - 0x00ca0000, 0x003f0000, 0x000f0000, 0x00020000, - 0x00c10000, 0x00af0000, 0x00bd0000, 0x00030000, - 0x00010000, 0x00130000, 0x008a0000, 0x006b0000, - 0x003a0000, 0x00910000, 0x00110000, 0x00410000, - 0x004f0000, 0x00670000, 0x00dc0000, 0x00ea0000, - 0x00970000, 0x00f20000, 0x00cf0000, 0x00ce0000, - 0x00f00000, 0x00b40000, 0x00e60000, 0x00730000, - 0x00960000, 0x00ac0000, 0x00740000, 0x00220000, - 0x00e70000, 0x00ad0000, 0x00350000, 0x00850000, - 0x00e20000, 0x00f90000, 0x00370000, 0x00e80000, - 0x001c0000, 0x00750000, 0x00df0000, 0x006e0000, - 0x00470000, 0x00f10000, 0x001a0000, 0x00710000, - 0x001d0000, 0x00290000, 0x00c50000, 0x00890000, - 0x006f0000, 0x00b70000, 0x00620000, 0x000e0000, - 0x00aa0000, 0x00180000, 0x00be0000, 0x001b0000, - 0x00fc0000, 0x00560000, 0x003e0000, 0x004b0000, - 0x00c60000, 0x00d20000, 0x00790000, 0x00200000, - 0x009a0000, 0x00db0000, 0x00c00000, 0x00fe0000, - 0x00780000, 0x00cd0000, 0x005a0000, 0x00f40000, - 0x001f0000, 0x00dd0000, 0x00a80000, 0x00330000, - 0x00880000, 0x00070000, 0x00c70000, 0x00310000, - 0x00b10000, 0x00120000, 0x00100000, 0x00590000, - 0x00270000, 0x00800000, 0x00ec0000, 0x005f0000, - 0x00600000, 0x00510000, 0x007f0000, 0x00a90000, - 0x00190000, 0x00b50000, 0x004a0000, 0x000d0000, - 0x002d0000, 0x00e50000, 0x007a0000, 0x009f0000, - 0x00930000, 0x00c90000, 0x009c0000, 0x00ef0000, - 0x00a00000, 0x00e00000, 0x003b0000, 0x004d0000, - 0x00ae0000, 0x002a0000, 0x00f50000, 0x00b00000, - 0x00c80000, 0x00eb0000, 0x00bb0000, 0x003c0000, - 0x00830000, 0x00530000, 0x00990000, 0x00610000, - 0x00170000, 0x002b0000, 0x00040000, 0x007e0000, - 0x00ba0000, 0x00770000, 0x00d60000, 0x00260000, - 0x00e10000, 0x00690000, 0x00140000, 0x00630000, - 0x00550000, 0x00210000, 0x000c0000, 0x007d0000, - }, { - 0x52000000, 0x09000000, 0x6a000000, 0xd5000000, - 0x30000000, 0x36000000, 0xa5000000, 0x38000000, - 0xbf000000, 0x40000000, 0xa3000000, 0x9e000000, - 0x81000000, 0xf3000000, 0xd7000000, 0xfb000000, - 0x7c000000, 0xe3000000, 0x39000000, 0x82000000, - 0x9b000000, 0x2f000000, 0xff000000, 0x87000000, - 0x34000000, 0x8e000000, 0x43000000, 0x44000000, - 0xc4000000, 0xde000000, 0xe9000000, 0xcb000000, - 0x54000000, 0x7b000000, 0x94000000, 0x32000000, - 0xa6000000, 0xc2000000, 0x23000000, 0x3d000000, - 0xee000000, 0x4c000000, 0x95000000, 0x0b000000, - 0x42000000, 0xfa000000, 0xc3000000, 0x4e000000, - 0x08000000, 0x2e000000, 0xa1000000, 0x66000000, - 0x28000000, 0xd9000000, 0x24000000, 0xb2000000, - 0x76000000, 0x5b000000, 0xa2000000, 0x49000000, - 0x6d000000, 0x8b000000, 0xd1000000, 0x25000000, - 0x72000000, 0xf8000000, 0xf6000000, 0x64000000, - 0x86000000, 0x68000000, 0x98000000, 0x16000000, - 0xd4000000, 0xa4000000, 0x5c000000, 0xcc000000, - 0x5d000000, 0x65000000, 0xb6000000, 0x92000000, - 0x6c000000, 0x70000000, 0x48000000, 0x50000000, - 0xfd000000, 0xed000000, 0xb9000000, 0xda000000, - 0x5e000000, 0x15000000, 0x46000000, 0x57000000, - 0xa7000000, 0x8d000000, 0x9d000000, 0x84000000, - 0x90000000, 0xd8000000, 0xab000000, 0x00000000, - 0x8c000000, 0xbc000000, 0xd3000000, 0x0a000000, - 0xf7000000, 0xe4000000, 0x58000000, 0x05000000, - 0xb8000000, 0xb3000000, 0x45000000, 0x06000000, - 0xd0000000, 0x2c000000, 0x1e000000, 0x8f000000, - 0xca000000, 0x3f000000, 0x0f000000, 0x02000000, - 0xc1000000, 0xaf000000, 0xbd000000, 0x03000000, - 0x01000000, 0x13000000, 0x8a000000, 0x6b000000, - 0x3a000000, 0x91000000, 0x11000000, 0x41000000, - 0x4f000000, 0x67000000, 0xdc000000, 0xea000000, - 0x97000000, 0xf2000000, 0xcf000000, 0xce000000, - 0xf0000000, 0xb4000000, 0xe6000000, 0x73000000, - 0x96000000, 0xac000000, 0x74000000, 0x22000000, - 0xe7000000, 0xad000000, 0x35000000, 0x85000000, - 0xe2000000, 0xf9000000, 0x37000000, 0xe8000000, - 0x1c000000, 0x75000000, 0xdf000000, 0x6e000000, - 0x47000000, 0xf1000000, 0x1a000000, 0x71000000, - 0x1d000000, 0x29000000, 0xc5000000, 0x89000000, - 0x6f000000, 0xb7000000, 0x62000000, 0x0e000000, - 0xaa000000, 0x18000000, 0xbe000000, 0x1b000000, - 0xfc000000, 0x56000000, 0x3e000000, 0x4b000000, - 0xc6000000, 0xd2000000, 0x79000000, 0x20000000, - 0x9a000000, 0xdb000000, 0xc0000000, 0xfe000000, - 0x78000000, 0xcd000000, 0x5a000000, 0xf4000000, - 0x1f000000, 0xdd000000, 0xa8000000, 0x33000000, - 0x88000000, 0x07000000, 0xc7000000, 0x31000000, - 0xb1000000, 0x12000000, 0x10000000, 0x59000000, - 0x27000000, 0x80000000, 0xec000000, 0x5f000000, - 0x60000000, 0x51000000, 0x7f000000, 0xa9000000, - 0x19000000, 0xb5000000, 0x4a000000, 0x0d000000, - 0x2d000000, 0xe5000000, 0x7a000000, 0x9f000000, - 0x93000000, 0xc9000000, 0x9c000000, 0xef000000, - 0xa0000000, 0xe0000000, 0x3b000000, 0x4d000000, - 0xae000000, 0x2a000000, 0xf5000000, 0xb0000000, - 0xc8000000, 0xeb000000, 0xbb000000, 0x3c000000, - 0x83000000, 0x53000000, 0x99000000, 0x61000000, - 0x17000000, 0x2b000000, 0x04000000, 0x7e000000, - 0xba000000, 0x77000000, 0xd6000000, 0x26000000, - 0xe1000000, 0x69000000, 0x14000000, 0x63000000, - 0x55000000, 0x21000000, 0x0c000000, 0x7d000000, - } -}; - -EXPORT_SYMBOL_GPL(crypto_ft_tab); -EXPORT_SYMBOL_GPL(crypto_fl_tab); -EXPORT_SYMBOL_GPL(crypto_it_tab); -EXPORT_SYMBOL_GPL(crypto_il_tab); - -/* initialise the key schedule from the user supplied key */ - -#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b) - -#define imix_col(y, x) do { \ - u = star_x(x); \ - v = star_x(u); \ - w = star_x(v); \ - t = w ^ (x); \ - (y) = u ^ v ^ w; \ - (y) ^= ror32(u ^ t, 8) ^ \ - ror32(v ^ t, 16) ^ \ - ror32(t, 24); \ -} while (0) - -#define ls_box(x) \ - crypto_fl_tab[0][byte(x, 0)] ^ \ - crypto_fl_tab[1][byte(x, 1)] ^ \ - crypto_fl_tab[2][byte(x, 2)] ^ \ - crypto_fl_tab[3][byte(x, 3)] - -#define loop4(i) do { \ - t = ror32(t, 8); \ - t = ls_box(t) ^ rco_tab[i]; \ - t ^= ctx->key_enc[4 * i]; \ - ctx->key_enc[4 * i + 4] = t; \ - t ^= ctx->key_enc[4 * i + 1]; \ - ctx->key_enc[4 * i + 5] = t; \ - t ^= ctx->key_enc[4 * i + 2]; \ - ctx->key_enc[4 * i + 6] = t; \ - t ^= ctx->key_enc[4 * i + 3]; \ - ctx->key_enc[4 * i + 7] = t; \ -} while (0) - -#define loop6(i) do { \ - t = ror32(t, 8); \ - t = ls_box(t) ^ rco_tab[i]; \ - t ^= ctx->key_enc[6 * i]; \ - ctx->key_enc[6 * i + 6] = t; \ - t ^= ctx->key_enc[6 * i + 1]; \ - ctx->key_enc[6 * i + 7] = t; \ - t ^= ctx->key_enc[6 * i + 2]; \ - ctx->key_enc[6 * i + 8] = t; \ - t ^= ctx->key_enc[6 * i + 3]; \ - ctx->key_enc[6 * i + 9] = t; \ - t ^= ctx->key_enc[6 * i + 4]; \ - ctx->key_enc[6 * i + 10] = t; \ - t ^= ctx->key_enc[6 * i + 5]; \ - ctx->key_enc[6 * i + 11] = t; \ -} while (0) - -#define loop8tophalf(i) do { \ - t = ror32(t, 8); \ - t = ls_box(t) ^ rco_tab[i]; \ - t ^= ctx->key_enc[8 * i]; \ - ctx->key_enc[8 * i + 8] = t; \ - t ^= ctx->key_enc[8 * i + 1]; \ - ctx->key_enc[8 * i + 9] = t; \ - t ^= ctx->key_enc[8 * i + 2]; \ - ctx->key_enc[8 * i + 10] = t; \ - t ^= ctx->key_enc[8 * i + 3]; \ - ctx->key_enc[8 * i + 11] = t; \ -} while (0) - -#define loop8(i) do { \ - loop8tophalf(i); \ - t = ctx->key_enc[8 * i + 4] ^ ls_box(t); \ - ctx->key_enc[8 * i + 12] = t; \ - t ^= ctx->key_enc[8 * i + 5]; \ - ctx->key_enc[8 * i + 13] = t; \ - t ^= ctx->key_enc[8 * i + 6]; \ - ctx->key_enc[8 * i + 14] = t; \ - t ^= ctx->key_enc[8 * i + 7]; \ - ctx->key_enc[8 * i + 15] = t; \ -} while (0) - -/** - * crypto_aes_expand_key - Expands the AES key as described in FIPS-197 - * @ctx: The location where the computed key will be stored. - * @in_key: The supplied key. - * @key_len: The length of the supplied key. - * - * Returns 0 on success. The function fails only if an invalid key size (or - * pointer) is supplied. - * The expanded key size is 240 bytes (max of 14 rounds with a unique 16 bytes - * key schedule plus a 16 bytes key which is used before the first round). - * The decryption key is prepared for the "Equivalent Inverse Cipher" as - * described in FIPS-197. The first slot (16 bytes) of each key (enc or dec) is - * for the initial combination, the second slot for the first round and so on. - */ -int crypto_aes_expand_key(struct crypto_aes_ctx *ctx, const u8 *in_key, - unsigned int key_len) -{ - const __le32 *key = (const __le32 *)in_key; - u32 i, t, u, v, w, j; - - if (key_len != AES_KEYSIZE_128 && key_len != AES_KEYSIZE_192 && - key_len != AES_KEYSIZE_256) - return -EINVAL; - - ctx->key_length = key_len; - - ctx->key_dec[key_len + 24] = ctx->key_enc[0] = le32_to_cpu(key[0]); - ctx->key_dec[key_len + 25] = ctx->key_enc[1] = le32_to_cpu(key[1]); - ctx->key_dec[key_len + 26] = ctx->key_enc[2] = le32_to_cpu(key[2]); - ctx->key_dec[key_len + 27] = ctx->key_enc[3] = le32_to_cpu(key[3]); - - switch (key_len) { - case AES_KEYSIZE_128: - t = ctx->key_enc[3]; - for (i = 0; i < 10; ++i) - loop4(i); - break; - - case AES_KEYSIZE_192: - ctx->key_enc[4] = le32_to_cpu(key[4]); - t = ctx->key_enc[5] = le32_to_cpu(key[5]); - for (i = 0; i < 8; ++i) - loop6(i); - break; - - case AES_KEYSIZE_256: - ctx->key_enc[4] = le32_to_cpu(key[4]); - ctx->key_enc[5] = le32_to_cpu(key[5]); - ctx->key_enc[6] = le32_to_cpu(key[6]); - t = ctx->key_enc[7] = le32_to_cpu(key[7]); - for (i = 0; i < 6; ++i) - loop8(i); - loop8tophalf(i); - break; - } - - ctx->key_dec[0] = ctx->key_enc[key_len + 24]; - ctx->key_dec[1] = ctx->key_enc[key_len + 25]; - ctx->key_dec[2] = ctx->key_enc[key_len + 26]; - ctx->key_dec[3] = ctx->key_enc[key_len + 27]; - - for (i = 4; i < key_len + 24; ++i) { - j = key_len + 24 - (i & ~3) + (i & 3); - imix_col(ctx->key_dec[j], ctx->key_enc[i]); - } - return 0; -} -EXPORT_SYMBOL_GPL(crypto_aes_expand_key); - -/** - * crypto_aes_set_key - Set the AES key. - * @tfm: The %crypto_tfm that is used in the context. - * @in_key: The input key. - * @key_len: The size of the key. - * - * Returns 0 on success, on failure the %CRYPTO_TFM_RES_BAD_KEY_LEN flag in tfm - * is set. The function uses crypto_aes_expand_key() to expand the key. - * &crypto_aes_ctx _must_ be the private data embedded in @tfm which is - * retrieved with crypto_tfm_ctx(). - */ -int crypto_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, - unsigned int key_len) -{ - struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); - u32 *flags = &tfm->crt_flags; - int ret; - - ret = crypto_aes_expand_key(ctx, in_key, key_len); - if (!ret) - return 0; - - *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; - return -EINVAL; -} -EXPORT_SYMBOL_GPL(crypto_aes_set_key); - -/* encrypt a block of text */ - -#define f_rn(bo, bi, n, k) do { \ - bo[n] = crypto_ft_tab[0][byte(bi[n], 0)] ^ \ - crypto_ft_tab[1][byte(bi[(n + 1) & 3], 1)] ^ \ - crypto_ft_tab[2][byte(bi[(n + 2) & 3], 2)] ^ \ - crypto_ft_tab[3][byte(bi[(n + 3) & 3], 3)] ^ *(k + n); \ -} while (0) - -#define f_nround(bo, bi, k) do {\ - f_rn(bo, bi, 0, k); \ - f_rn(bo, bi, 1, k); \ - f_rn(bo, bi, 2, k); \ - f_rn(bo, bi, 3, k); \ - k += 4; \ -} while (0) - -#define f_rl(bo, bi, n, k) do { \ - bo[n] = crypto_fl_tab[0][byte(bi[n], 0)] ^ \ - crypto_fl_tab[1][byte(bi[(n + 1) & 3], 1)] ^ \ - crypto_fl_tab[2][byte(bi[(n + 2) & 3], 2)] ^ \ - crypto_fl_tab[3][byte(bi[(n + 3) & 3], 3)] ^ *(k + n); \ -} while (0) - -#define f_lround(bo, bi, k) do {\ - f_rl(bo, bi, 0, k); \ - f_rl(bo, bi, 1, k); \ - f_rl(bo, bi, 2, k); \ - f_rl(bo, bi, 3, k); \ -} while (0) - -static void aes_encrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) -{ - const struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); - const __le32 *src = (const __le32 *)in; - __le32 *dst = (__le32 *)out; - u32 b0[4], b1[4]; - const u32 *kp = ctx->key_enc + 4; - const int key_len = ctx->key_length; - - b0[0] = le32_to_cpu(src[0]) ^ ctx->key_enc[0]; - b0[1] = le32_to_cpu(src[1]) ^ ctx->key_enc[1]; - b0[2] = le32_to_cpu(src[2]) ^ ctx->key_enc[2]; - b0[3] = le32_to_cpu(src[3]) ^ ctx->key_enc[3]; - - if (key_len > 24) { - f_nround(b1, b0, kp); - f_nround(b0, b1, kp); - } - - if (key_len > 16) { - f_nround(b1, b0, kp); - f_nround(b0, b1, kp); - } - - f_nround(b1, b0, kp); - f_nround(b0, b1, kp); - f_nround(b1, b0, kp); - f_nround(b0, b1, kp); - f_nround(b1, b0, kp); - f_nround(b0, b1, kp); - f_nround(b1, b0, kp); - f_nround(b0, b1, kp); - f_nround(b1, b0, kp); - f_lround(b0, b1, kp); - - dst[0] = cpu_to_le32(b0[0]); - dst[1] = cpu_to_le32(b0[1]); - dst[2] = cpu_to_le32(b0[2]); - dst[3] = cpu_to_le32(b0[3]); -} - -/* decrypt a block of text */ - -#define i_rn(bo, bi, n, k) do { \ - bo[n] = crypto_it_tab[0][byte(bi[n], 0)] ^ \ - crypto_it_tab[1][byte(bi[(n + 3) & 3], 1)] ^ \ - crypto_it_tab[2][byte(bi[(n + 2) & 3], 2)] ^ \ - crypto_it_tab[3][byte(bi[(n + 1) & 3], 3)] ^ *(k + n); \ -} while (0) - -#define i_nround(bo, bi, k) do {\ - i_rn(bo, bi, 0, k); \ - i_rn(bo, bi, 1, k); \ - i_rn(bo, bi, 2, k); \ - i_rn(bo, bi, 3, k); \ - k += 4; \ -} while (0) - -#define i_rl(bo, bi, n, k) do { \ - bo[n] = crypto_il_tab[0][byte(bi[n], 0)] ^ \ - crypto_il_tab[1][byte(bi[(n + 3) & 3], 1)] ^ \ - crypto_il_tab[2][byte(bi[(n + 2) & 3], 2)] ^ \ - crypto_il_tab[3][byte(bi[(n + 1) & 3], 3)] ^ *(k + n); \ -} while (0) - -#define i_lround(bo, bi, k) do {\ - i_rl(bo, bi, 0, k); \ - i_rl(bo, bi, 1, k); \ - i_rl(bo, bi, 2, k); \ - i_rl(bo, bi, 3, k); \ -} while (0) - -static void aes_decrypt(struct crypto_tfm *tfm, u8 *out, const u8 *in) -{ - const struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm); - const __le32 *src = (const __le32 *)in; - __le32 *dst = (__le32 *)out; - u32 b0[4], b1[4]; - const int key_len = ctx->key_length; - const u32 *kp = ctx->key_dec + 4; - - b0[0] = le32_to_cpu(src[0]) ^ ctx->key_dec[0]; - b0[1] = le32_to_cpu(src[1]) ^ ctx->key_dec[1]; - b0[2] = le32_to_cpu(src[2]) ^ ctx->key_dec[2]; - b0[3] = le32_to_cpu(src[3]) ^ ctx->key_dec[3]; - - if (key_len > 24) { - i_nround(b1, b0, kp); - i_nround(b0, b1, kp); - } - - if (key_len > 16) { - i_nround(b1, b0, kp); - i_nround(b0, b1, kp); - } - - i_nround(b1, b0, kp); - i_nround(b0, b1, kp); - i_nround(b1, b0, kp); - i_nround(b0, b1, kp); - i_nround(b1, b0, kp); - i_nround(b0, b1, kp); - i_nround(b1, b0, kp); - i_nround(b0, b1, kp); - i_nround(b1, b0, kp); - i_lround(b0, b1, kp); - - dst[0] = cpu_to_le32(b0[0]); - dst[1] = cpu_to_le32(b0[1]); - dst[2] = cpu_to_le32(b0[2]); - dst[3] = cpu_to_le32(b0[3]); -} - -static struct crypto_alg aes_alg = { - .cra_name = "aes", - .cra_driver_name = "aes-generic", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, - .cra_blocksize = AES_BLOCK_SIZE, - .cra_ctxsize = sizeof(struct crypto_aes_ctx), - .cra_alignmask = 3, - .cra_module = THIS_MODULE, - .cra_u = { - .cipher = { - .cia_min_keysize = AES_MIN_KEY_SIZE, - .cia_max_keysize = AES_MAX_KEY_SIZE, - .cia_setkey = crypto_aes_set_key, - .cia_encrypt = aes_encrypt, - .cia_decrypt = aes_decrypt - } - } -}; - -static int __init aes_init(void) -{ - return crypto_register_alg(&aes_alg); -} - -static void __exit aes_fini(void) -{ - crypto_unregister_alg(&aes_alg); -} - -module_init(aes_init); -module_exit(aes_fini); - -MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm"); -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_ALIAS_CRYPTO("aes"); -MODULE_ALIAS_CRYPTO("aes-generic"); diff --git a/src/linux/crypto/ahash.c b/src/linux/crypto/ahash.c deleted file mode 100644 index 2ce8bcb..0000000 --- a/src/linux/crypto/ahash.c +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Asynchronous Cryptographic Hash operations. - * - * This is the asynchronous version of hash.c with notification of - * completion via a callback. - * - * Copyright (c) 2008 Loc Ho - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -struct ahash_request_priv { - crypto_completion_t complete; - void *data; - u8 *result; - void *ubuf[] CRYPTO_MINALIGN_ATTR; -}; - -static inline struct ahash_alg *crypto_ahash_alg(struct crypto_ahash *hash) -{ - return container_of(crypto_hash_alg_common(hash), struct ahash_alg, - halg); -} - -static int hash_walk_next(struct crypto_hash_walk *walk) -{ - unsigned int alignmask = walk->alignmask; - unsigned int offset = walk->offset; - unsigned int nbytes = min(walk->entrylen, - ((unsigned int)(PAGE_SIZE)) - offset); - - if (walk->flags & CRYPTO_ALG_ASYNC) - walk->data = kmap(walk->pg); - else - walk->data = kmap_atomic(walk->pg); - walk->data += offset; - - if (offset & alignmask) { - unsigned int unaligned = alignmask + 1 - (offset & alignmask); - - if (nbytes > unaligned) - nbytes = unaligned; - } - - walk->entrylen -= nbytes; - return nbytes; -} - -static int hash_walk_new_entry(struct crypto_hash_walk *walk) -{ - struct scatterlist *sg; - - sg = walk->sg; - walk->offset = sg->offset; - walk->pg = sg_page(walk->sg) + (walk->offset >> PAGE_SHIFT); - walk->offset = offset_in_page(walk->offset); - walk->entrylen = sg->length; - - if (walk->entrylen > walk->total) - walk->entrylen = walk->total; - walk->total -= walk->entrylen; - - return hash_walk_next(walk); -} - -int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err) -{ - unsigned int alignmask = walk->alignmask; - unsigned int nbytes = walk->entrylen; - - walk->data -= walk->offset; - - if (nbytes && walk->offset & alignmask && !err) { - walk->offset = ALIGN(walk->offset, alignmask + 1); - walk->data += walk->offset; - - nbytes = min(nbytes, - ((unsigned int)(PAGE_SIZE)) - walk->offset); - walk->entrylen -= nbytes; - - return nbytes; - } - - if (walk->flags & CRYPTO_ALG_ASYNC) - kunmap(walk->pg); - else { - kunmap_atomic(walk->data); - /* - * The may sleep test only makes sense for sync users. - * Async users don't need to sleep here anyway. - */ - crypto_yield(walk->flags); - } - - if (err) - return err; - - if (nbytes) { - walk->offset = 0; - walk->pg++; - return hash_walk_next(walk); - } - - if (!walk->total) - return 0; - - walk->sg = sg_next(walk->sg); - - return hash_walk_new_entry(walk); -} -EXPORT_SYMBOL_GPL(crypto_hash_walk_done); - -int crypto_hash_walk_first(struct ahash_request *req, - struct crypto_hash_walk *walk) -{ - walk->total = req->nbytes; - - if (!walk->total) { - walk->entrylen = 0; - return 0; - } - - walk->alignmask = crypto_ahash_alignmask(crypto_ahash_reqtfm(req)); - walk->sg = req->src; - walk->flags = req->base.flags & CRYPTO_TFM_REQ_MASK; - - return hash_walk_new_entry(walk); -} -EXPORT_SYMBOL_GPL(crypto_hash_walk_first); - -int crypto_ahash_walk_first(struct ahash_request *req, - struct crypto_hash_walk *walk) -{ - walk->total = req->nbytes; - - if (!walk->total) { - walk->entrylen = 0; - return 0; - } - - walk->alignmask = crypto_ahash_alignmask(crypto_ahash_reqtfm(req)); - walk->sg = req->src; - walk->flags = req->base.flags & CRYPTO_TFM_REQ_MASK; - walk->flags |= CRYPTO_ALG_ASYNC; - - BUILD_BUG_ON(CRYPTO_TFM_REQ_MASK & CRYPTO_ALG_ASYNC); - - return hash_walk_new_entry(walk); -} -EXPORT_SYMBOL_GPL(crypto_ahash_walk_first); - -static int ahash_setkey_unaligned(struct crypto_ahash *tfm, const u8 *key, - unsigned int keylen) -{ - unsigned long alignmask = crypto_ahash_alignmask(tfm); - int ret; - u8 *buffer, *alignbuffer; - unsigned long absize; - - absize = keylen + alignmask; - buffer = kmalloc(absize, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); - memcpy(alignbuffer, key, keylen); - ret = tfm->setkey(tfm, alignbuffer, keylen); - kzfree(buffer); - return ret; -} - -int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, - unsigned int keylen) -{ - unsigned long alignmask = crypto_ahash_alignmask(tfm); - - if ((unsigned long)key & alignmask) - return ahash_setkey_unaligned(tfm, key, keylen); - - return tfm->setkey(tfm, key, keylen); -} -EXPORT_SYMBOL_GPL(crypto_ahash_setkey); - -static int ahash_nosetkey(struct crypto_ahash *tfm, const u8 *key, - unsigned int keylen) -{ - return -ENOSYS; -} - -static inline unsigned int ahash_align_buffer_size(unsigned len, - unsigned long mask) -{ - return len + (mask & ~(crypto_tfm_ctx_alignment() - 1)); -} - -static int ahash_save_req(struct ahash_request *req, crypto_completion_t cplt) -{ - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - unsigned long alignmask = crypto_ahash_alignmask(tfm); - unsigned int ds = crypto_ahash_digestsize(tfm); - struct ahash_request_priv *priv; - - priv = kmalloc(sizeof(*priv) + ahash_align_buffer_size(ds, alignmask), - (req->base.flags & CRYPTO_TFM_REQ_MAY_SLEEP) ? - GFP_KERNEL : GFP_ATOMIC); - if (!priv) - return -ENOMEM; - - /* - * WARNING: Voodoo programming below! - * - * The code below is obscure and hard to understand, thus explanation - * is necessary. See include/crypto/hash.h and include/linux/crypto.h - * to understand the layout of structures used here! - * - * The code here will replace portions of the ORIGINAL request with - * pointers to new code and buffers so the hashing operation can store - * the result in aligned buffer. We will call the modified request - * an ADJUSTED request. - * - * The newly mangled request will look as such: - * - * req { - * .result = ADJUSTED[new aligned buffer] - * .base.complete = ADJUSTED[pointer to completion function] - * .base.data = ADJUSTED[*req (pointer to self)] - * .priv = ADJUSTED[new priv] { - * .result = ORIGINAL(result) - * .complete = ORIGINAL(base.complete) - * .data = ORIGINAL(base.data) - * } - */ - - priv->result = req->result; - priv->complete = req->base.complete; - priv->data = req->base.data; - /* - * WARNING: We do not backup req->priv here! The req->priv - * is for internal use of the Crypto API and the - * user must _NOT_ _EVER_ depend on it's content! - */ - - req->result = PTR_ALIGN((u8 *)priv->ubuf, alignmask + 1); - req->base.complete = cplt; - req->base.data = req; - req->priv = priv; - - return 0; -} - -static void ahash_restore_req(struct ahash_request *req) -{ - struct ahash_request_priv *priv = req->priv; - - /* Restore the original crypto request. */ - req->result = priv->result; - req->base.complete = priv->complete; - req->base.data = priv->data; - req->priv = NULL; - - /* Free the req->priv.priv from the ADJUSTED request. */ - kzfree(priv); -} - -static void ahash_op_unaligned_finish(struct ahash_request *req, int err) -{ - struct ahash_request_priv *priv = req->priv; - - if (err == -EINPROGRESS) - return; - - if (!err) - memcpy(priv->result, req->result, - crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); - - ahash_restore_req(req); -} - -static void ahash_op_unaligned_done(struct crypto_async_request *req, int err) -{ - struct ahash_request *areq = req->data; - - /* - * Restore the original request, see ahash_op_unaligned() for what - * goes where. - * - * The "struct ahash_request *req" here is in fact the "req.base" - * from the ADJUSTED request from ahash_op_unaligned(), thus as it - * is a pointer to self, it is also the ADJUSTED "req" . - */ - - /* First copy req->result into req->priv.result */ - ahash_op_unaligned_finish(areq, err); - - /* Complete the ORIGINAL request. */ - areq->base.complete(&areq->base, err); -} - -static int ahash_op_unaligned(struct ahash_request *req, - int (*op)(struct ahash_request *)) -{ - int err; - - err = ahash_save_req(req, ahash_op_unaligned_done); - if (err) - return err; - - err = op(req); - ahash_op_unaligned_finish(req, err); - - return err; -} - -static int crypto_ahash_op(struct ahash_request *req, - int (*op)(struct ahash_request *)) -{ - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - unsigned long alignmask = crypto_ahash_alignmask(tfm); - - if ((unsigned long)req->result & alignmask) - return ahash_op_unaligned(req, op); - - return op(req); -} - -int crypto_ahash_final(struct ahash_request *req) -{ - return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->final); -} -EXPORT_SYMBOL_GPL(crypto_ahash_final); - -int crypto_ahash_finup(struct ahash_request *req) -{ - return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->finup); -} -EXPORT_SYMBOL_GPL(crypto_ahash_finup); - -int crypto_ahash_digest(struct ahash_request *req) -{ - return crypto_ahash_op(req, crypto_ahash_reqtfm(req)->digest); -} -EXPORT_SYMBOL_GPL(crypto_ahash_digest); - -static void ahash_def_finup_finish2(struct ahash_request *req, int err) -{ - struct ahash_request_priv *priv = req->priv; - - if (err == -EINPROGRESS) - return; - - if (!err) - memcpy(priv->result, req->result, - crypto_ahash_digestsize(crypto_ahash_reqtfm(req))); - - ahash_restore_req(req); -} - -static void ahash_def_finup_done2(struct crypto_async_request *req, int err) -{ - struct ahash_request *areq = req->data; - - ahash_def_finup_finish2(areq, err); - - areq->base.complete(&areq->base, err); -} - -static int ahash_def_finup_finish1(struct ahash_request *req, int err) -{ - if (err) - goto out; - - req->base.complete = ahash_def_finup_done2; - req->base.flags &= ~CRYPTO_TFM_REQ_MAY_SLEEP; - err = crypto_ahash_reqtfm(req)->final(req); - -out: - ahash_def_finup_finish2(req, err); - return err; -} - -static void ahash_def_finup_done1(struct crypto_async_request *req, int err) -{ - struct ahash_request *areq = req->data; - - err = ahash_def_finup_finish1(areq, err); - - areq->base.complete(&areq->base, err); -} - -static int ahash_def_finup(struct ahash_request *req) -{ - struct crypto_ahash *tfm = crypto_ahash_reqtfm(req); - int err; - - err = ahash_save_req(req, ahash_def_finup_done1); - if (err) - return err; - - err = tfm->update(req); - return ahash_def_finup_finish1(req, err); -} - -static int ahash_no_export(struct ahash_request *req, void *out) -{ - return -ENOSYS; -} - -static int ahash_no_import(struct ahash_request *req, const void *in) -{ - return -ENOSYS; -} - -static int crypto_ahash_init_tfm(struct crypto_tfm *tfm) -{ - struct crypto_ahash *hash = __crypto_ahash_cast(tfm); - struct ahash_alg *alg = crypto_ahash_alg(hash); - - hash->setkey = ahash_nosetkey; - hash->has_setkey = false; - hash->export = ahash_no_export; - hash->import = ahash_no_import; - - if (tfm->__crt_alg->cra_type != &crypto_ahash_type) - return crypto_init_shash_ops_async(tfm); - - hash->init = alg->init; - hash->update = alg->update; - hash->final = alg->final; - hash->finup = alg->finup ?: ahash_def_finup; - hash->digest = alg->digest; - - if (alg->setkey) { - hash->setkey = alg->setkey; - hash->has_setkey = true; - } - if (alg->export) - hash->export = alg->export; - if (alg->import) - hash->import = alg->import; - - return 0; -} - -static unsigned int crypto_ahash_extsize(struct crypto_alg *alg) -{ - if (alg->cra_type != &crypto_ahash_type) - return sizeof(struct crypto_shash *); - - return crypto_alg_extsize(alg); -} - -#ifdef CONFIG_NET -static int crypto_ahash_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - struct crypto_report_hash rhash; - - strncpy(rhash.type, "ahash", sizeof(rhash.type)); - - rhash.blocksize = alg->cra_blocksize; - rhash.digestsize = __crypto_hash_alg_common(alg)->digestsize; - - if (nla_put(skb, CRYPTOCFGA_REPORT_HASH, - sizeof(struct crypto_report_hash), &rhash)) - goto nla_put_failure; - return 0; - -nla_put_failure: - return -EMSGSIZE; -} -#else -static int crypto_ahash_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif - -static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) - __attribute__ ((unused)); -static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg) -{ - seq_printf(m, "type : ahash\n"); - seq_printf(m, "async : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ? - "yes" : "no"); - seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); - seq_printf(m, "digestsize : %u\n", - __crypto_hash_alg_common(alg)->digestsize); -} - -const struct crypto_type crypto_ahash_type = { - .extsize = crypto_ahash_extsize, - .init_tfm = crypto_ahash_init_tfm, -#ifdef CONFIG_PROC_FS - .show = crypto_ahash_show, -#endif - .report = crypto_ahash_report, - .maskclear = ~CRYPTO_ALG_TYPE_MASK, - .maskset = CRYPTO_ALG_TYPE_AHASH_MASK, - .type = CRYPTO_ALG_TYPE_AHASH, - .tfmsize = offsetof(struct crypto_ahash, base), -}; -EXPORT_SYMBOL_GPL(crypto_ahash_type); - -struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type, - u32 mask) -{ - return crypto_alloc_tfm(alg_name, &crypto_ahash_type, type, mask); -} -EXPORT_SYMBOL_GPL(crypto_alloc_ahash); - -int crypto_has_ahash(const char *alg_name, u32 type, u32 mask) -{ - return crypto_type_has_alg(alg_name, &crypto_ahash_type, type, mask); -} -EXPORT_SYMBOL_GPL(crypto_has_ahash); - -static int ahash_prepare_alg(struct ahash_alg *alg) -{ - struct crypto_alg *base = &alg->halg.base; - - if (alg->halg.digestsize > PAGE_SIZE / 8 || - alg->halg.statesize > PAGE_SIZE / 8 || - alg->halg.statesize == 0) - return -EINVAL; - - base->cra_type = &crypto_ahash_type; - base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; - base->cra_flags |= CRYPTO_ALG_TYPE_AHASH; - - return 0; -} - -int crypto_register_ahash(struct ahash_alg *alg) -{ - struct crypto_alg *base = &alg->halg.base; - int err; - - err = ahash_prepare_alg(alg); - if (err) - return err; - - return crypto_register_alg(base); -} -EXPORT_SYMBOL_GPL(crypto_register_ahash); - -int crypto_unregister_ahash(struct ahash_alg *alg) -{ - return crypto_unregister_alg(&alg->halg.base); -} -EXPORT_SYMBOL_GPL(crypto_unregister_ahash); - -int ahash_register_instance(struct crypto_template *tmpl, - struct ahash_instance *inst) -{ - int err; - - err = ahash_prepare_alg(&inst->alg); - if (err) - return err; - - return crypto_register_instance(tmpl, ahash_crypto_instance(inst)); -} -EXPORT_SYMBOL_GPL(ahash_register_instance); - -void ahash_free_instance(struct crypto_instance *inst) -{ - crypto_drop_spawn(crypto_instance_ctx(inst)); - kfree(ahash_instance(inst)); -} -EXPORT_SYMBOL_GPL(ahash_free_instance); - -int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn, - struct hash_alg_common *alg, - struct crypto_instance *inst) -{ - return crypto_init_spawn2(&spawn->base, &alg->base, inst, - &crypto_ahash_type); -} -EXPORT_SYMBOL_GPL(crypto_init_ahash_spawn); - -struct hash_alg_common *ahash_attr_alg(struct rtattr *rta, u32 type, u32 mask) -{ - struct crypto_alg *alg; - - alg = crypto_attr_alg2(rta, &crypto_ahash_type, type, mask); - return IS_ERR(alg) ? ERR_CAST(alg) : __crypto_hash_alg_common(alg); -} -EXPORT_SYMBOL_GPL(ahash_attr_alg); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Asynchronous cryptographic hash type"); diff --git a/src/linux/crypto/akcipher.c b/src/linux/crypto/akcipher.c deleted file mode 100644 index def301e..0000000 --- a/src/linux/crypto/akcipher.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Public Key Encryption - * - * Copyright (c) 2015, Intel Corporation - * Authors: Tadeusz Struk - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -#ifdef CONFIG_NET -static int crypto_akcipher_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - struct crypto_report_akcipher rakcipher; - - strncpy(rakcipher.type, "akcipher", sizeof(rakcipher.type)); - - if (nla_put(skb, CRYPTOCFGA_REPORT_AKCIPHER, - sizeof(struct crypto_report_akcipher), &rakcipher)) - goto nla_put_failure; - return 0; - -nla_put_failure: - return -EMSGSIZE; -} -#else -static int crypto_akcipher_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif - -static void crypto_akcipher_show(struct seq_file *m, struct crypto_alg *alg) - __attribute__ ((unused)); - -static void crypto_akcipher_show(struct seq_file *m, struct crypto_alg *alg) -{ - seq_puts(m, "type : akcipher\n"); -} - -static void crypto_akcipher_exit_tfm(struct crypto_tfm *tfm) -{ - struct crypto_akcipher *akcipher = __crypto_akcipher_tfm(tfm); - struct akcipher_alg *alg = crypto_akcipher_alg(akcipher); - - alg->exit(akcipher); -} - -static int crypto_akcipher_init_tfm(struct crypto_tfm *tfm) -{ - struct crypto_akcipher *akcipher = __crypto_akcipher_tfm(tfm); - struct akcipher_alg *alg = crypto_akcipher_alg(akcipher); - - if (alg->exit) - akcipher->base.exit = crypto_akcipher_exit_tfm; - - if (alg->init) - return alg->init(akcipher); - - return 0; -} - -static void crypto_akcipher_free_instance(struct crypto_instance *inst) -{ - struct akcipher_instance *akcipher = akcipher_instance(inst); - - akcipher->free(akcipher); -} - -static const struct crypto_type crypto_akcipher_type = { - .extsize = crypto_alg_extsize, - .init_tfm = crypto_akcipher_init_tfm, - .free = crypto_akcipher_free_instance, -#ifdef CONFIG_PROC_FS - .show = crypto_akcipher_show, -#endif - .report = crypto_akcipher_report, - .maskclear = ~CRYPTO_ALG_TYPE_MASK, - .maskset = CRYPTO_ALG_TYPE_MASK, - .type = CRYPTO_ALG_TYPE_AKCIPHER, - .tfmsize = offsetof(struct crypto_akcipher, base), -}; - -int crypto_grab_akcipher(struct crypto_akcipher_spawn *spawn, const char *name, - u32 type, u32 mask) -{ - spawn->base.frontend = &crypto_akcipher_type; - return crypto_grab_spawn(&spawn->base, name, type, mask); -} -EXPORT_SYMBOL_GPL(crypto_grab_akcipher); - -struct crypto_akcipher *crypto_alloc_akcipher(const char *alg_name, u32 type, - u32 mask) -{ - return crypto_alloc_tfm(alg_name, &crypto_akcipher_type, type, mask); -} -EXPORT_SYMBOL_GPL(crypto_alloc_akcipher); - -static void akcipher_prepare_alg(struct akcipher_alg *alg) -{ - struct crypto_alg *base = &alg->base; - - base->cra_type = &crypto_akcipher_type; - base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; - base->cra_flags |= CRYPTO_ALG_TYPE_AKCIPHER; -} - -int crypto_register_akcipher(struct akcipher_alg *alg) -{ - struct crypto_alg *base = &alg->base; - - akcipher_prepare_alg(alg); - return crypto_register_alg(base); -} -EXPORT_SYMBOL_GPL(crypto_register_akcipher); - -void crypto_unregister_akcipher(struct akcipher_alg *alg) -{ - crypto_unregister_alg(&alg->base); -} -EXPORT_SYMBOL_GPL(crypto_unregister_akcipher); - -int akcipher_register_instance(struct crypto_template *tmpl, - struct akcipher_instance *inst) -{ - akcipher_prepare_alg(&inst->alg); - return crypto_register_instance(tmpl, akcipher_crypto_instance(inst)); -} -EXPORT_SYMBOL_GPL(akcipher_register_instance); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Generic public key cipher type"); diff --git a/src/linux/crypto/algapi.c b/src/linux/crypto/algapi.c deleted file mode 100644 index df939b5..0000000 --- a/src/linux/crypto/algapi.c +++ /dev/null @@ -1,1030 +0,0 @@ -/* - * Cryptographic API for algorithms (i.e., low-level API). - * - * Copyright (c) 2006 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -static LIST_HEAD(crypto_template_list); - -static inline int crypto_set_driver_name(struct crypto_alg *alg) -{ - static const char suffix[] = "-generic"; - char *driver_name = alg->cra_driver_name; - int len; - - if (*driver_name) - return 0; - - len = strlcpy(driver_name, alg->cra_name, CRYPTO_MAX_ALG_NAME); - if (len + sizeof(suffix) > CRYPTO_MAX_ALG_NAME) - return -ENAMETOOLONG; - - memcpy(driver_name + len, suffix, sizeof(suffix)); - return 0; -} - -static inline void crypto_check_module_sig(struct module *mod) -{ - if (fips_enabled && mod && !module_sig_ok(mod)) - panic("Module %s signature verification failed in FIPS mode\n", - module_name(mod)); -} - -static int crypto_check_alg(struct crypto_alg *alg) -{ - crypto_check_module_sig(alg->cra_module); - - if (alg->cra_alignmask & (alg->cra_alignmask + 1)) - return -EINVAL; - - if (alg->cra_blocksize > PAGE_SIZE / 8) - return -EINVAL; - - if (alg->cra_priority < 0) - return -EINVAL; - - atomic_set(&alg->cra_refcnt, 1); - - return crypto_set_driver_name(alg); -} - -static void crypto_free_instance(struct crypto_instance *inst) -{ - if (!inst->alg.cra_type->free) { - inst->tmpl->free(inst); - return; - } - - inst->alg.cra_type->free(inst); -} - -static void crypto_destroy_instance(struct crypto_alg *alg) -{ - struct crypto_instance *inst = (void *)alg; - struct crypto_template *tmpl = inst->tmpl; - - crypto_free_instance(inst); - crypto_tmpl_put(tmpl); -} - -static struct list_head *crypto_more_spawns(struct crypto_alg *alg, - struct list_head *stack, - struct list_head *top, - struct list_head *secondary_spawns) -{ - struct crypto_spawn *spawn, *n; - - spawn = list_first_entry_or_null(stack, struct crypto_spawn, list); - if (!spawn) - return NULL; - - n = list_next_entry(spawn, list); - - if (spawn->alg && &n->list != stack && !n->alg) - n->alg = (n->list.next == stack) ? alg : - &list_next_entry(n, list)->inst->alg; - - list_move(&spawn->list, secondary_spawns); - - return &n->list == stack ? top : &n->inst->alg.cra_users; -} - -static void crypto_remove_instance(struct crypto_instance *inst, - struct list_head *list) -{ - struct crypto_template *tmpl = inst->tmpl; - - if (crypto_is_dead(&inst->alg)) - return; - - inst->alg.cra_flags |= CRYPTO_ALG_DEAD; - if (hlist_unhashed(&inst->list)) - return; - - if (!tmpl || !crypto_tmpl_get(tmpl)) - return; - - crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg); - list_move(&inst->alg.cra_list, list); - hlist_del(&inst->list); - inst->alg.cra_destroy = crypto_destroy_instance; - - BUG_ON(!list_empty(&inst->alg.cra_users)); -} - -void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list, - struct crypto_alg *nalg) -{ - u32 new_type = (nalg ?: alg)->cra_flags; - struct crypto_spawn *spawn, *n; - LIST_HEAD(secondary_spawns); - struct list_head *spawns; - LIST_HEAD(stack); - LIST_HEAD(top); - - spawns = &alg->cra_users; - list_for_each_entry_safe(spawn, n, spawns, list) { - if ((spawn->alg->cra_flags ^ new_type) & spawn->mask) - continue; - - list_move(&spawn->list, &top); - } - - spawns = ⊤ - do { - while (!list_empty(spawns)) { - struct crypto_instance *inst; - - spawn = list_first_entry(spawns, struct crypto_spawn, - list); - inst = spawn->inst; - - BUG_ON(&inst->alg == alg); - - list_move(&spawn->list, &stack); - - if (&inst->alg == nalg) - break; - - spawn->alg = NULL; - spawns = &inst->alg.cra_users; - } - } while ((spawns = crypto_more_spawns(alg, &stack, &top, - &secondary_spawns))); - - list_for_each_entry_safe(spawn, n, &secondary_spawns, list) { - if (spawn->alg) - list_move(&spawn->list, &spawn->alg->cra_users); - else - crypto_remove_instance(spawn->inst, list); - } -} -EXPORT_SYMBOL_GPL(crypto_remove_spawns); - -static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg) -{ - struct crypto_alg *q; - struct crypto_larval *larval; - int ret = -EAGAIN; - - if (crypto_is_dead(alg)) - goto err; - - INIT_LIST_HEAD(&alg->cra_users); - - /* No cheating! */ - alg->cra_flags &= ~CRYPTO_ALG_TESTED; - - ret = -EEXIST; - - list_for_each_entry(q, &crypto_alg_list, cra_list) { - if (q == alg) - goto err; - - if (crypto_is_moribund(q)) - continue; - - if (crypto_is_larval(q)) { - if (!strcmp(alg->cra_driver_name, q->cra_driver_name)) - goto err; - continue; - } - - if (!strcmp(q->cra_driver_name, alg->cra_name) || - !strcmp(q->cra_name, alg->cra_driver_name)) - goto err; - } - - larval = crypto_larval_alloc(alg->cra_name, - alg->cra_flags | CRYPTO_ALG_TESTED, 0); - if (IS_ERR(larval)) - goto out; - - ret = -ENOENT; - larval->adult = crypto_mod_get(alg); - if (!larval->adult) - goto free_larval; - - atomic_set(&larval->alg.cra_refcnt, 1); - memcpy(larval->alg.cra_driver_name, alg->cra_driver_name, - CRYPTO_MAX_ALG_NAME); - larval->alg.cra_priority = alg->cra_priority; - - list_add(&alg->cra_list, &crypto_alg_list); - list_add(&larval->alg.cra_list, &crypto_alg_list); - -out: - return larval; - -free_larval: - kfree(larval); -err: - larval = ERR_PTR(ret); - goto out; -} - -void crypto_alg_tested(const char *name, int err) -{ - struct crypto_larval *test; - struct crypto_alg *alg; - struct crypto_alg *q; - LIST_HEAD(list); - - down_write(&crypto_alg_sem); - list_for_each_entry(q, &crypto_alg_list, cra_list) { - if (crypto_is_moribund(q) || !crypto_is_larval(q)) - continue; - - test = (struct crypto_larval *)q; - - if (!strcmp(q->cra_driver_name, name)) - goto found; - } - - printk(KERN_ERR "alg: Unexpected test result for %s: %d\n", name, err); - goto unlock; - -found: - q->cra_flags |= CRYPTO_ALG_DEAD; - alg = test->adult; - if (err || list_empty(&alg->cra_list)) - goto complete; - - alg->cra_flags |= CRYPTO_ALG_TESTED; - - list_for_each_entry(q, &crypto_alg_list, cra_list) { - if (q == alg) - continue; - - if (crypto_is_moribund(q)) - continue; - - if (crypto_is_larval(q)) { - struct crypto_larval *larval = (void *)q; - - /* - * Check to see if either our generic name or - * specific name can satisfy the name requested - * by the larval entry q. - */ - if (strcmp(alg->cra_name, q->cra_name) && - strcmp(alg->cra_driver_name, q->cra_name)) - continue; - - if (larval->adult) - continue; - if ((q->cra_flags ^ alg->cra_flags) & larval->mask) - continue; - if (!crypto_mod_get(alg)) - continue; - - larval->adult = alg; - continue; - } - - if (strcmp(alg->cra_name, q->cra_name)) - continue; - - if (strcmp(alg->cra_driver_name, q->cra_driver_name) && - q->cra_priority > alg->cra_priority) - continue; - - crypto_remove_spawns(q, &list, alg); - } - -complete: - complete_all(&test->completion); - -unlock: - up_write(&crypto_alg_sem); - - crypto_remove_final(&list); -} -EXPORT_SYMBOL_GPL(crypto_alg_tested); - -void crypto_remove_final(struct list_head *list) -{ - struct crypto_alg *alg; - struct crypto_alg *n; - - list_for_each_entry_safe(alg, n, list, cra_list) { - list_del_init(&alg->cra_list); - crypto_alg_put(alg); - } -} -EXPORT_SYMBOL_GPL(crypto_remove_final); - -static void crypto_wait_for_test(struct crypto_larval *larval) -{ - int err; - - err = crypto_probing_notify(CRYPTO_MSG_ALG_REGISTER, larval->adult); - if (err != NOTIFY_STOP) { - if (WARN_ON(err != NOTIFY_DONE)) - goto out; - crypto_alg_tested(larval->alg.cra_driver_name, 0); - } - - err = wait_for_completion_killable(&larval->completion); - WARN_ON(err); - -out: - crypto_larval_kill(&larval->alg); -} - -int crypto_register_alg(struct crypto_alg *alg) -{ - struct crypto_larval *larval; - int err; - - err = crypto_check_alg(alg); - if (err) - return err; - - down_write(&crypto_alg_sem); - larval = __crypto_register_alg(alg); - up_write(&crypto_alg_sem); - - if (IS_ERR(larval)) - return PTR_ERR(larval); - - crypto_wait_for_test(larval); - return 0; -} -EXPORT_SYMBOL_GPL(crypto_register_alg); - -static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list) -{ - if (unlikely(list_empty(&alg->cra_list))) - return -ENOENT; - - alg->cra_flags |= CRYPTO_ALG_DEAD; - - crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg); - list_del_init(&alg->cra_list); - crypto_remove_spawns(alg, list, NULL); - - return 0; -} - -int crypto_unregister_alg(struct crypto_alg *alg) -{ - int ret; - LIST_HEAD(list); - - down_write(&crypto_alg_sem); - ret = crypto_remove_alg(alg, &list); - up_write(&crypto_alg_sem); - - if (ret) - return ret; - - BUG_ON(atomic_read(&alg->cra_refcnt) != 1); - if (alg->cra_destroy) - alg->cra_destroy(alg); - - crypto_remove_final(&list); - return 0; -} -EXPORT_SYMBOL_GPL(crypto_unregister_alg); - -int crypto_register_algs(struct crypto_alg *algs, int count) -{ - int i, ret; - - for (i = 0; i < count; i++) { - ret = crypto_register_alg(&algs[i]); - if (ret) - goto err; - } - - return 0; - -err: - for (--i; i >= 0; --i) - crypto_unregister_alg(&algs[i]); - - return ret; -} -EXPORT_SYMBOL_GPL(crypto_register_algs); - -int crypto_unregister_algs(struct crypto_alg *algs, int count) -{ - int i, ret; - - for (i = 0; i < count; i++) { - ret = crypto_unregister_alg(&algs[i]); - if (ret) - pr_err("Failed to unregister %s %s: %d\n", - algs[i].cra_driver_name, algs[i].cra_name, ret); - } - - return 0; -} -EXPORT_SYMBOL_GPL(crypto_unregister_algs); - -int crypto_register_template(struct crypto_template *tmpl) -{ - struct crypto_template *q; - int err = -EEXIST; - - down_write(&crypto_alg_sem); - - crypto_check_module_sig(tmpl->module); - - list_for_each_entry(q, &crypto_template_list, list) { - if (q == tmpl) - goto out; - } - - list_add(&tmpl->list, &crypto_template_list); - crypto_notify(CRYPTO_MSG_TMPL_REGISTER, tmpl); - err = 0; -out: - up_write(&crypto_alg_sem); - return err; -} -EXPORT_SYMBOL_GPL(crypto_register_template); - -void crypto_unregister_template(struct crypto_template *tmpl) -{ - struct crypto_instance *inst; - struct hlist_node *n; - struct hlist_head *list; - LIST_HEAD(users); - - down_write(&crypto_alg_sem); - - BUG_ON(list_empty(&tmpl->list)); - list_del_init(&tmpl->list); - - list = &tmpl->instances; - hlist_for_each_entry(inst, list, list) { - int err = crypto_remove_alg(&inst->alg, &users); - - BUG_ON(err); - } - - crypto_notify(CRYPTO_MSG_TMPL_UNREGISTER, tmpl); - - up_write(&crypto_alg_sem); - - hlist_for_each_entry_safe(inst, n, list, list) { - BUG_ON(atomic_read(&inst->alg.cra_refcnt) != 1); - crypto_free_instance(inst); - } - crypto_remove_final(&users); -} -EXPORT_SYMBOL_GPL(crypto_unregister_template); - -static struct crypto_template *__crypto_lookup_template(const char *name) -{ - struct crypto_template *q, *tmpl = NULL; - - down_read(&crypto_alg_sem); - list_for_each_entry(q, &crypto_template_list, list) { - if (strcmp(q->name, name)) - continue; - if (unlikely(!crypto_tmpl_get(q))) - continue; - - tmpl = q; - break; - } - up_read(&crypto_alg_sem); - - return tmpl; -} - -struct crypto_template *crypto_lookup_template(const char *name) -{ - return try_then_request_module(__crypto_lookup_template(name), - "crypto-%s", name); -} -EXPORT_SYMBOL_GPL(crypto_lookup_template); - -int crypto_register_instance(struct crypto_template *tmpl, - struct crypto_instance *inst) -{ - struct crypto_larval *larval; - int err; - - err = crypto_check_alg(&inst->alg); - if (err) - return err; - - inst->alg.cra_module = tmpl->module; - inst->alg.cra_flags |= CRYPTO_ALG_INSTANCE; - - if (unlikely(!crypto_mod_get(&inst->alg))) - return -EAGAIN; - - down_write(&crypto_alg_sem); - - larval = __crypto_register_alg(&inst->alg); - if (IS_ERR(larval)) - goto unlock; - - hlist_add_head(&inst->list, &tmpl->instances); - inst->tmpl = tmpl; - -unlock: - up_write(&crypto_alg_sem); - - err = PTR_ERR(larval); - if (IS_ERR(larval)) - goto err; - - crypto_wait_for_test(larval); - - /* Remove instance if test failed */ - if (!(inst->alg.cra_flags & CRYPTO_ALG_TESTED)) - crypto_unregister_instance(inst); - err = 0; - -err: - crypto_mod_put(&inst->alg); - return err; -} -EXPORT_SYMBOL_GPL(crypto_register_instance); - -int crypto_unregister_instance(struct crypto_instance *inst) -{ - LIST_HEAD(list); - - down_write(&crypto_alg_sem); - - crypto_remove_spawns(&inst->alg, &list, NULL); - crypto_remove_instance(inst, &list); - - up_write(&crypto_alg_sem); - - crypto_remove_final(&list); - - return 0; -} -EXPORT_SYMBOL_GPL(crypto_unregister_instance); - -int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg, - struct crypto_instance *inst, u32 mask) -{ - int err = -EAGAIN; - - spawn->inst = inst; - spawn->mask = mask; - - down_write(&crypto_alg_sem); - if (!crypto_is_moribund(alg)) { - list_add(&spawn->list, &alg->cra_users); - spawn->alg = alg; - err = 0; - } - up_write(&crypto_alg_sem); - - return err; -} -EXPORT_SYMBOL_GPL(crypto_init_spawn); - -int crypto_init_spawn2(struct crypto_spawn *spawn, struct crypto_alg *alg, - struct crypto_instance *inst, - const struct crypto_type *frontend) -{ - int err = -EINVAL; - - if ((alg->cra_flags ^ frontend->type) & frontend->maskset) - goto out; - - spawn->frontend = frontend; - err = crypto_init_spawn(spawn, alg, inst, frontend->maskset); - -out: - return err; -} -EXPORT_SYMBOL_GPL(crypto_init_spawn2); - -int crypto_grab_spawn(struct crypto_spawn *spawn, const char *name, - u32 type, u32 mask) -{ - struct crypto_alg *alg; - int err; - - alg = crypto_find_alg(name, spawn->frontend, type, mask); - if (IS_ERR(alg)) - return PTR_ERR(alg); - - err = crypto_init_spawn(spawn, alg, spawn->inst, mask); - crypto_mod_put(alg); - return err; -} -EXPORT_SYMBOL_GPL(crypto_grab_spawn); - -void crypto_drop_spawn(struct crypto_spawn *spawn) -{ - if (!spawn->alg) - return; - - down_write(&crypto_alg_sem); - list_del(&spawn->list); - up_write(&crypto_alg_sem); -} -EXPORT_SYMBOL_GPL(crypto_drop_spawn); - -static struct crypto_alg *crypto_spawn_alg(struct crypto_spawn *spawn) -{ - struct crypto_alg *alg; - struct crypto_alg *alg2; - - down_read(&crypto_alg_sem); - alg = spawn->alg; - alg2 = alg; - if (alg2) - alg2 = crypto_mod_get(alg2); - up_read(&crypto_alg_sem); - - if (!alg2) { - if (alg) - crypto_shoot_alg(alg); - return ERR_PTR(-EAGAIN); - } - - return alg; -} - -struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type, - u32 mask) -{ - struct crypto_alg *alg; - struct crypto_tfm *tfm; - - alg = crypto_spawn_alg(spawn); - if (IS_ERR(alg)) - return ERR_CAST(alg); - - tfm = ERR_PTR(-EINVAL); - if (unlikely((alg->cra_flags ^ type) & mask)) - goto out_put_alg; - - tfm = __crypto_alloc_tfm(alg, type, mask); - if (IS_ERR(tfm)) - goto out_put_alg; - - return tfm; - -out_put_alg: - crypto_mod_put(alg); - return tfm; -} -EXPORT_SYMBOL_GPL(crypto_spawn_tfm); - -void *crypto_spawn_tfm2(struct crypto_spawn *spawn) -{ - struct crypto_alg *alg; - struct crypto_tfm *tfm; - - alg = crypto_spawn_alg(spawn); - if (IS_ERR(alg)) - return ERR_CAST(alg); - - tfm = crypto_create_tfm(alg, spawn->frontend); - if (IS_ERR(tfm)) - goto out_put_alg; - - return tfm; - -out_put_alg: - crypto_mod_put(alg); - return tfm; -} -EXPORT_SYMBOL_GPL(crypto_spawn_tfm2); - -int crypto_register_notifier(struct notifier_block *nb) -{ - return blocking_notifier_chain_register(&crypto_chain, nb); -} -EXPORT_SYMBOL_GPL(crypto_register_notifier); - -int crypto_unregister_notifier(struct notifier_block *nb) -{ - return blocking_notifier_chain_unregister(&crypto_chain, nb); -} -EXPORT_SYMBOL_GPL(crypto_unregister_notifier); - -struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb) -{ - struct rtattr *rta = tb[0]; - struct crypto_attr_type *algt; - - if (!rta) - return ERR_PTR(-ENOENT); - if (RTA_PAYLOAD(rta) < sizeof(*algt)) - return ERR_PTR(-EINVAL); - if (rta->rta_type != CRYPTOA_TYPE) - return ERR_PTR(-EINVAL); - - algt = RTA_DATA(rta); - - return algt; -} -EXPORT_SYMBOL_GPL(crypto_get_attr_type); - -int crypto_check_attr_type(struct rtattr **tb, u32 type) -{ - struct crypto_attr_type *algt; - - algt = crypto_get_attr_type(tb); - if (IS_ERR(algt)) - return PTR_ERR(algt); - - if ((algt->type ^ type) & algt->mask) - return -EINVAL; - - return 0; -} -EXPORT_SYMBOL_GPL(crypto_check_attr_type); - -const char *crypto_attr_alg_name(struct rtattr *rta) -{ - struct crypto_attr_alg *alga; - - if (!rta) - return ERR_PTR(-ENOENT); - if (RTA_PAYLOAD(rta) < sizeof(*alga)) - return ERR_PTR(-EINVAL); - if (rta->rta_type != CRYPTOA_ALG) - return ERR_PTR(-EINVAL); - - alga = RTA_DATA(rta); - alga->name[CRYPTO_MAX_ALG_NAME - 1] = 0; - - return alga->name; -} -EXPORT_SYMBOL_GPL(crypto_attr_alg_name); - -struct crypto_alg *crypto_attr_alg2(struct rtattr *rta, - const struct crypto_type *frontend, - u32 type, u32 mask) -{ - const char *name; - - name = crypto_attr_alg_name(rta); - if (IS_ERR(name)) - return ERR_CAST(name); - - return crypto_find_alg(name, frontend, type, mask); -} -EXPORT_SYMBOL_GPL(crypto_attr_alg2); - -int crypto_attr_u32(struct rtattr *rta, u32 *num) -{ - struct crypto_attr_u32 *nu32; - - if (!rta) - return -ENOENT; - if (RTA_PAYLOAD(rta) < sizeof(*nu32)) - return -EINVAL; - if (rta->rta_type != CRYPTOA_U32) - return -EINVAL; - - nu32 = RTA_DATA(rta); - *num = nu32->num; - - return 0; -} -EXPORT_SYMBOL_GPL(crypto_attr_u32); - -int crypto_inst_setname(struct crypto_instance *inst, const char *name, - struct crypto_alg *alg) -{ - if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s(%s)", name, - alg->cra_name) >= CRYPTO_MAX_ALG_NAME) - return -ENAMETOOLONG; - - if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s(%s)", - name, alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME) - return -ENAMETOOLONG; - - return 0; -} -EXPORT_SYMBOL_GPL(crypto_inst_setname); - -void *crypto_alloc_instance2(const char *name, struct crypto_alg *alg, - unsigned int head) -{ - struct crypto_instance *inst; - char *p; - int err; - - p = kzalloc(head + sizeof(*inst) + sizeof(struct crypto_spawn), - GFP_KERNEL); - if (!p) - return ERR_PTR(-ENOMEM); - - inst = (void *)(p + head); - - err = crypto_inst_setname(inst, name, alg); - if (err) - goto err_free_inst; - - return p; - -err_free_inst: - kfree(p); - return ERR_PTR(err); -} -EXPORT_SYMBOL_GPL(crypto_alloc_instance2); - -struct crypto_instance *crypto_alloc_instance(const char *name, - struct crypto_alg *alg) -{ - struct crypto_instance *inst; - struct crypto_spawn *spawn; - int err; - - inst = crypto_alloc_instance2(name, alg, 0); - if (IS_ERR(inst)) - goto out; - - spawn = crypto_instance_ctx(inst); - err = crypto_init_spawn(spawn, alg, inst, - CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC); - - if (err) - goto err_free_inst; - - return inst; - -err_free_inst: - kfree(inst); - inst = ERR_PTR(err); - -out: - return inst; -} -EXPORT_SYMBOL_GPL(crypto_alloc_instance); - -void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen) -{ - INIT_LIST_HEAD(&queue->list); - queue->backlog = &queue->list; - queue->qlen = 0; - queue->max_qlen = max_qlen; -} -EXPORT_SYMBOL_GPL(crypto_init_queue); - -int crypto_enqueue_request(struct crypto_queue *queue, - struct crypto_async_request *request) -{ - int err = -EINPROGRESS; - - if (unlikely(queue->qlen >= queue->max_qlen)) { - err = -EBUSY; - if (!(request->flags & CRYPTO_TFM_REQ_MAY_BACKLOG)) - goto out; - if (queue->backlog == &queue->list) - queue->backlog = &request->list; - } - - queue->qlen++; - list_add_tail(&request->list, &queue->list); - -out: - return err; -} -EXPORT_SYMBOL_GPL(crypto_enqueue_request); - -struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue) -{ - struct list_head *request; - - if (unlikely(!queue->qlen)) - return NULL; - - queue->qlen--; - - if (queue->backlog != &queue->list) - queue->backlog = queue->backlog->next; - - request = queue->list.next; - list_del(request); - - return list_entry(request, struct crypto_async_request, list); -} -EXPORT_SYMBOL_GPL(crypto_dequeue_request); - -int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm) -{ - struct crypto_async_request *req; - - list_for_each_entry(req, &queue->list, list) { - if (req->tfm == tfm) - return 1; - } - - return 0; -} -EXPORT_SYMBOL_GPL(crypto_tfm_in_queue); - -static inline void crypto_inc_byte(u8 *a, unsigned int size) -{ - u8 *b = (a + size); - u8 c; - - for (; size; size--) { - c = *--b + 1; - *b = c; - if (c) - break; - } -} - -void crypto_inc(u8 *a, unsigned int size) -{ - __be32 *b = (__be32 *)(a + size); - u32 c; - - for (; size >= 4; size -= 4) { - c = be32_to_cpu(*--b) + 1; - *b = cpu_to_be32(c); - if (c) - return; - } - - crypto_inc_byte(a, size); -} -EXPORT_SYMBOL_GPL(crypto_inc); - -static inline void crypto_xor_byte(u8 *a, const u8 *b, unsigned int size) -{ - for (; size; size--) - *a++ ^= *b++; -} - -void crypto_xor(u8 *dst, const u8 *src, unsigned int size) -{ - u32 *a = (u32 *)dst; - u32 *b = (u32 *)src; - - for (; size >= 4; size -= 4) - *a++ ^= *b++; - - crypto_xor_byte((u8 *)a, (u8 *)b, size); -} -EXPORT_SYMBOL_GPL(crypto_xor); - -unsigned int crypto_alg_extsize(struct crypto_alg *alg) -{ - return alg->cra_ctxsize + - (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1)); -} -EXPORT_SYMBOL_GPL(crypto_alg_extsize); - -int crypto_type_has_alg(const char *name, const struct crypto_type *frontend, - u32 type, u32 mask) -{ - int ret = 0; - struct crypto_alg *alg = crypto_find_alg(name, frontend, type, mask); - - if (!IS_ERR(alg)) { - crypto_mod_put(alg); - ret = 1; - } - - return ret; -} -EXPORT_SYMBOL_GPL(crypto_type_has_alg); - -static int __init crypto_algapi_init(void) -{ - crypto_init_proc(); - return 0; -} - -static void __exit crypto_algapi_exit(void) -{ - crypto_exit_proc(); -} - -module_init(crypto_algapi_init); -module_exit(crypto_algapi_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Cryptographic algorithms API"); diff --git a/src/linux/crypto/algboss.c b/src/linux/crypto/algboss.c deleted file mode 100644 index 6e39d9c..0000000 --- a/src/linux/crypto/algboss.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Create default crypto algorithm instances. - * - * Copyright (c) 2006 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -struct cryptomgr_param { - struct rtattr *tb[CRYPTO_MAX_ATTRS + 2]; - - struct { - struct rtattr attr; - struct crypto_attr_type data; - } type; - - union { - struct rtattr attr; - struct { - struct rtattr attr; - struct crypto_attr_alg data; - } alg; - struct { - struct rtattr attr; - struct crypto_attr_u32 data; - } nu32; - } attrs[CRYPTO_MAX_ATTRS]; - - char template[CRYPTO_MAX_ALG_NAME]; - - struct crypto_larval *larval; - - u32 otype; - u32 omask; -}; - -struct crypto_test_param { - char driver[CRYPTO_MAX_ALG_NAME]; - char alg[CRYPTO_MAX_ALG_NAME]; - u32 type; -}; - -static int cryptomgr_probe(void *data) -{ - struct cryptomgr_param *param = data; - struct crypto_template *tmpl; - struct crypto_instance *inst; - int err; - - tmpl = crypto_lookup_template(param->template); - if (!tmpl) - goto out; - - do { - if (tmpl->create) { - err = tmpl->create(tmpl, param->tb); - continue; - } - - inst = tmpl->alloc(param->tb); - if (IS_ERR(inst)) - err = PTR_ERR(inst); - else if ((err = crypto_register_instance(tmpl, inst))) - tmpl->free(inst); - } while (err == -EAGAIN && !signal_pending(current)); - - crypto_tmpl_put(tmpl); - -out: - complete_all(¶m->larval->completion); - crypto_alg_put(¶m->larval->alg); - kfree(param); - module_put_and_exit(0); -} - -static int cryptomgr_schedule_probe(struct crypto_larval *larval) -{ - struct task_struct *thread; - struct cryptomgr_param *param; - const char *name = larval->alg.cra_name; - const char *p; - unsigned int len; - int i; - - if (!try_module_get(THIS_MODULE)) - goto err; - - param = kzalloc(sizeof(*param), GFP_KERNEL); - if (!param) - goto err_put_module; - - for (p = name; isalnum(*p) || *p == '-' || *p == '_'; p++) - ; - - len = p - name; - if (!len || *p != '(') - goto err_free_param; - - memcpy(param->template, name, len); - - i = 0; - for (;;) { - int notnum = 0; - - name = ++p; - len = 0; - - for (; isalnum(*p) || *p == '-' || *p == '_'; p++) - notnum |= !isdigit(*p); - - if (*p == '(') { - int recursion = 0; - - for (;;) { - if (!*++p) - goto err_free_param; - if (*p == '(') - recursion++; - else if (*p == ')' && !recursion--) - break; - } - - notnum = 1; - p++; - } - - len = p - name; - if (!len) - goto err_free_param; - - if (notnum) { - param->attrs[i].alg.attr.rta_len = - sizeof(param->attrs[i].alg); - param->attrs[i].alg.attr.rta_type = CRYPTOA_ALG; - memcpy(param->attrs[i].alg.data.name, name, len); - } else { - param->attrs[i].nu32.attr.rta_len = - sizeof(param->attrs[i].nu32); - param->attrs[i].nu32.attr.rta_type = CRYPTOA_U32; - param->attrs[i].nu32.data.num = - simple_strtol(name, NULL, 0); - } - - param->tb[i + 1] = ¶m->attrs[i].attr; - i++; - - if (i >= CRYPTO_MAX_ATTRS) - goto err_free_param; - - if (*p == ')') - break; - - if (*p != ',') - goto err_free_param; - } - - if (!i) - goto err_free_param; - - param->tb[i + 1] = NULL; - - param->type.attr.rta_len = sizeof(param->type); - param->type.attr.rta_type = CRYPTOA_TYPE; - param->type.data.type = larval->alg.cra_flags & ~CRYPTO_ALG_TESTED; - param->type.data.mask = larval->mask & ~CRYPTO_ALG_TESTED; - param->tb[0] = ¶m->type.attr; - - param->otype = larval->alg.cra_flags; - param->omask = larval->mask; - - crypto_alg_get(&larval->alg); - param->larval = larval; - - thread = kthread_run(cryptomgr_probe, param, "cryptomgr_probe"); - if (IS_ERR(thread)) - goto err_put_larval; - - wait_for_completion_interruptible(&larval->completion); - - return NOTIFY_STOP; - -err_put_larval: - crypto_alg_put(&larval->alg); -err_free_param: - kfree(param); -err_put_module: - module_put(THIS_MODULE); -err: - return NOTIFY_OK; -} - -static int cryptomgr_test(void *data) -{ - struct crypto_test_param *param = data; - u32 type = param->type; - int err = 0; - -#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS - goto skiptest; -#endif - - if (type & CRYPTO_ALG_TESTED) - goto skiptest; - - err = alg_test(param->driver, param->alg, type, CRYPTO_ALG_TESTED); - -skiptest: - crypto_alg_tested(param->driver, err); - - kfree(param); - module_put_and_exit(0); -} - -static int cryptomgr_schedule_test(struct crypto_alg *alg) -{ - struct task_struct *thread; - struct crypto_test_param *param; - u32 type; - - if (!try_module_get(THIS_MODULE)) - goto err; - - param = kzalloc(sizeof(*param), GFP_KERNEL); - if (!param) - goto err_put_module; - - memcpy(param->driver, alg->cra_driver_name, sizeof(param->driver)); - memcpy(param->alg, alg->cra_name, sizeof(param->alg)); - type = alg->cra_flags; - - /* This piece of crap needs to disappear into per-type test hooks. */ - if (!((type ^ CRYPTO_ALG_TYPE_BLKCIPHER) & - CRYPTO_ALG_TYPE_BLKCIPHER_MASK) && !(type & CRYPTO_ALG_GENIV) && - ((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) == - CRYPTO_ALG_TYPE_BLKCIPHER ? alg->cra_blkcipher.ivsize : - alg->cra_ablkcipher.ivsize)) - type |= CRYPTO_ALG_TESTED; - - param->type = type; - - thread = kthread_run(cryptomgr_test, param, "cryptomgr_test"); - if (IS_ERR(thread)) - goto err_free_param; - - return NOTIFY_STOP; - -err_free_param: - kfree(param); -err_put_module: - module_put(THIS_MODULE); -err: - return NOTIFY_OK; -} - -static int cryptomgr_notify(struct notifier_block *this, unsigned long msg, - void *data) -{ - switch (msg) { - case CRYPTO_MSG_ALG_REQUEST: - return cryptomgr_schedule_probe(data); - case CRYPTO_MSG_ALG_REGISTER: - return cryptomgr_schedule_test(data); - } - - return NOTIFY_DONE; -} - -static struct notifier_block cryptomgr_notifier = { - .notifier_call = cryptomgr_notify, -}; - -static int __init cryptomgr_init(void) -{ - return crypto_register_notifier(&cryptomgr_notifier); -} - -static void __exit cryptomgr_exit(void) -{ - int err = crypto_unregister_notifier(&cryptomgr_notifier); - BUG_ON(err); -} - -subsys_initcall(cryptomgr_init); -module_exit(cryptomgr_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Crypto Algorithm Manager"); diff --git a/src/linux/crypto/ansi_cprng.c b/src/linux/crypto/ansi_cprng.c deleted file mode 100644 index eff337c..0000000 --- a/src/linux/crypto/ansi_cprng.c +++ /dev/null @@ -1,478 +0,0 @@ -/* - * PRNG: Pseudo Random Number Generator - * Based on NIST Recommended PRNG From ANSI X9.31 Appendix A.2.4 using - * AES 128 cipher - * - * (C) Neil Horman - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * any later version. - * - * - */ - -#include -#include -#include -#include -#include -#include - -#define DEFAULT_PRNG_KEY "0123456789abcdef" -#define DEFAULT_PRNG_KSZ 16 -#define DEFAULT_BLK_SZ 16 -#define DEFAULT_V_SEED "zaybxcwdveuftgsh" - -/* - * Flags for the prng_context flags field - */ - -#define PRNG_FIXED_SIZE 0x1 -#define PRNG_NEED_RESET 0x2 - -/* - * Note: DT is our counter value - * I is our intermediate value - * V is our seed vector - * See http://csrc.nist.gov/groups/STM/cavp/documents/rng/931rngext.pdf - * for implementation details - */ - - -struct prng_context { - spinlock_t prng_lock; - unsigned char rand_data[DEFAULT_BLK_SZ]; - unsigned char last_rand_data[DEFAULT_BLK_SZ]; - unsigned char DT[DEFAULT_BLK_SZ]; - unsigned char I[DEFAULT_BLK_SZ]; - unsigned char V[DEFAULT_BLK_SZ]; - u32 rand_data_valid; - struct crypto_cipher *tfm; - u32 flags; -}; - -static int dbg; - -static void hexdump(char *note, unsigned char *buf, unsigned int len) -{ - if (dbg) { - printk(KERN_CRIT "%s", note); - print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET, - 16, 1, - buf, len, false); - } -} - -#define dbgprint(format, args...) do {\ -if (dbg)\ - printk(format, ##args);\ -} while (0) - -static void xor_vectors(unsigned char *in1, unsigned char *in2, - unsigned char *out, unsigned int size) -{ - int i; - - for (i = 0; i < size; i++) - out[i] = in1[i] ^ in2[i]; - -} -/* - * Returns DEFAULT_BLK_SZ bytes of random data per call - * returns 0 if generation succeeded, <0 if something went wrong - */ -static int _get_more_prng_bytes(struct prng_context *ctx, int cont_test) -{ - int i; - unsigned char tmp[DEFAULT_BLK_SZ]; - unsigned char *output = NULL; - - - dbgprint(KERN_CRIT "Calling _get_more_prng_bytes for context %p\n", - ctx); - - hexdump("Input DT: ", ctx->DT, DEFAULT_BLK_SZ); - hexdump("Input I: ", ctx->I, DEFAULT_BLK_SZ); - hexdump("Input V: ", ctx->V, DEFAULT_BLK_SZ); - - /* - * This algorithm is a 3 stage state machine - */ - for (i = 0; i < 3; i++) { - - switch (i) { - case 0: - /* - * Start by encrypting the counter value - * This gives us an intermediate value I - */ - memcpy(tmp, ctx->DT, DEFAULT_BLK_SZ); - output = ctx->I; - hexdump("tmp stage 0: ", tmp, DEFAULT_BLK_SZ); - break; - case 1: - - /* - * Next xor I with our secret vector V - * encrypt that result to obtain our - * pseudo random data which we output - */ - xor_vectors(ctx->I, ctx->V, tmp, DEFAULT_BLK_SZ); - hexdump("tmp stage 1: ", tmp, DEFAULT_BLK_SZ); - output = ctx->rand_data; - break; - case 2: - /* - * First check that we didn't produce the same - * random data that we did last time around through this - */ - if (!memcmp(ctx->rand_data, ctx->last_rand_data, - DEFAULT_BLK_SZ)) { - if (cont_test) { - panic("cprng %p Failed repetition check!\n", - ctx); - } - - printk(KERN_ERR - "ctx %p Failed repetition check!\n", - ctx); - - ctx->flags |= PRNG_NEED_RESET; - return -EINVAL; - } - memcpy(ctx->last_rand_data, ctx->rand_data, - DEFAULT_BLK_SZ); - - /* - * Lastly xor the random data with I - * and encrypt that to obtain a new secret vector V - */ - xor_vectors(ctx->rand_data, ctx->I, tmp, - DEFAULT_BLK_SZ); - output = ctx->V; - hexdump("tmp stage 2: ", tmp, DEFAULT_BLK_SZ); - break; - } - - - /* do the encryption */ - crypto_cipher_encrypt_one(ctx->tfm, output, tmp); - - } - - /* - * Now update our DT value - */ - for (i = DEFAULT_BLK_SZ - 1; i >= 0; i--) { - ctx->DT[i] += 1; - if (ctx->DT[i] != 0) - break; - } - - dbgprint("Returning new block for context %p\n", ctx); - ctx->rand_data_valid = 0; - - hexdump("Output DT: ", ctx->DT, DEFAULT_BLK_SZ); - hexdump("Output I: ", ctx->I, DEFAULT_BLK_SZ); - hexdump("Output V: ", ctx->V, DEFAULT_BLK_SZ); - hexdump("New Random Data: ", ctx->rand_data, DEFAULT_BLK_SZ); - - return 0; -} - -/* Our exported functions */ -static int get_prng_bytes(char *buf, size_t nbytes, struct prng_context *ctx, - int do_cont_test) -{ - unsigned char *ptr = buf; - unsigned int byte_count = (unsigned int)nbytes; - int err; - - - spin_lock_bh(&ctx->prng_lock); - - err = -EINVAL; - if (ctx->flags & PRNG_NEED_RESET) - goto done; - - /* - * If the FIXED_SIZE flag is on, only return whole blocks of - * pseudo random data - */ - err = -EINVAL; - if (ctx->flags & PRNG_FIXED_SIZE) { - if (nbytes < DEFAULT_BLK_SZ) - goto done; - byte_count = DEFAULT_BLK_SZ; - } - - /* - * Return 0 in case of success as mandated by the kernel - * crypto API interface definition. - */ - err = 0; - - dbgprint(KERN_CRIT "getting %d random bytes for context %p\n", - byte_count, ctx); - - -remainder: - if (ctx->rand_data_valid == DEFAULT_BLK_SZ) { - if (_get_more_prng_bytes(ctx, do_cont_test) < 0) { - memset(buf, 0, nbytes); - err = -EINVAL; - goto done; - } - } - - /* - * Copy any data less than an entire block - */ - if (byte_count < DEFAULT_BLK_SZ) { -empty_rbuf: - while (ctx->rand_data_valid < DEFAULT_BLK_SZ) { - *ptr = ctx->rand_data[ctx->rand_data_valid]; - ptr++; - byte_count--; - ctx->rand_data_valid++; - if (byte_count == 0) - goto done; - } - } - - /* - * Now copy whole blocks - */ - for (; byte_count >= DEFAULT_BLK_SZ; byte_count -= DEFAULT_BLK_SZ) { - if (ctx->rand_data_valid == DEFAULT_BLK_SZ) { - if (_get_more_prng_bytes(ctx, do_cont_test) < 0) { - memset(buf, 0, nbytes); - err = -EINVAL; - goto done; - } - } - if (ctx->rand_data_valid > 0) - goto empty_rbuf; - memcpy(ptr, ctx->rand_data, DEFAULT_BLK_SZ); - ctx->rand_data_valid += DEFAULT_BLK_SZ; - ptr += DEFAULT_BLK_SZ; - } - - /* - * Now go back and get any remaining partial block - */ - if (byte_count) - goto remainder; - -done: - spin_unlock_bh(&ctx->prng_lock); - dbgprint(KERN_CRIT "returning %d from get_prng_bytes in context %p\n", - err, ctx); - return err; -} - -static void free_prng_context(struct prng_context *ctx) -{ - crypto_free_cipher(ctx->tfm); -} - -static int reset_prng_context(struct prng_context *ctx, - const unsigned char *key, size_t klen, - const unsigned char *V, const unsigned char *DT) -{ - int ret; - const unsigned char *prng_key; - - spin_lock_bh(&ctx->prng_lock); - ctx->flags |= PRNG_NEED_RESET; - - prng_key = (key != NULL) ? key : (unsigned char *)DEFAULT_PRNG_KEY; - - if (!key) - klen = DEFAULT_PRNG_KSZ; - - if (V) - memcpy(ctx->V, V, DEFAULT_BLK_SZ); - else - memcpy(ctx->V, DEFAULT_V_SEED, DEFAULT_BLK_SZ); - - if (DT) - memcpy(ctx->DT, DT, DEFAULT_BLK_SZ); - else - memset(ctx->DT, 0, DEFAULT_BLK_SZ); - - memset(ctx->rand_data, 0, DEFAULT_BLK_SZ); - memset(ctx->last_rand_data, 0, DEFAULT_BLK_SZ); - - ctx->rand_data_valid = DEFAULT_BLK_SZ; - - ret = crypto_cipher_setkey(ctx->tfm, prng_key, klen); - if (ret) { - dbgprint(KERN_CRIT "PRNG: setkey() failed flags=%x\n", - crypto_cipher_get_flags(ctx->tfm)); - goto out; - } - - ret = 0; - ctx->flags &= ~PRNG_NEED_RESET; -out: - spin_unlock_bh(&ctx->prng_lock); - return ret; -} - -static int cprng_init(struct crypto_tfm *tfm) -{ - struct prng_context *ctx = crypto_tfm_ctx(tfm); - - spin_lock_init(&ctx->prng_lock); - ctx->tfm = crypto_alloc_cipher("aes", 0, 0); - if (IS_ERR(ctx->tfm)) { - dbgprint(KERN_CRIT "Failed to alloc tfm for context %p\n", - ctx); - return PTR_ERR(ctx->tfm); - } - - if (reset_prng_context(ctx, NULL, DEFAULT_PRNG_KSZ, NULL, NULL) < 0) - return -EINVAL; - - /* - * after allocation, we should always force the user to reset - * so they don't inadvertently use the insecure default values - * without specifying them intentially - */ - ctx->flags |= PRNG_NEED_RESET; - return 0; -} - -static void cprng_exit(struct crypto_tfm *tfm) -{ - free_prng_context(crypto_tfm_ctx(tfm)); -} - -static int cprng_get_random(struct crypto_rng *tfm, - const u8 *src, unsigned int slen, - u8 *rdata, unsigned int dlen) -{ - struct prng_context *prng = crypto_rng_ctx(tfm); - - return get_prng_bytes(rdata, dlen, prng, 0); -} - -/* - * This is the cprng_registered reset method the seed value is - * interpreted as the tuple { V KEY DT} - * V and KEY are required during reset, and DT is optional, detected - * as being present by testing the length of the seed - */ -static int cprng_reset(struct crypto_rng *tfm, - const u8 *seed, unsigned int slen) -{ - struct prng_context *prng = crypto_rng_ctx(tfm); - const u8 *key = seed + DEFAULT_BLK_SZ; - const u8 *dt = NULL; - - if (slen < DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ) - return -EINVAL; - - if (slen >= (2 * DEFAULT_BLK_SZ + DEFAULT_PRNG_KSZ)) - dt = key + DEFAULT_PRNG_KSZ; - - reset_prng_context(prng, key, DEFAULT_PRNG_KSZ, seed, dt); - - if (prng->flags & PRNG_NEED_RESET) - return -EINVAL; - return 0; -} - -#ifdef CONFIG_CRYPTO_FIPS -static int fips_cprng_get_random(struct crypto_rng *tfm, - const u8 *src, unsigned int slen, - u8 *rdata, unsigned int dlen) -{ - struct prng_context *prng = crypto_rng_ctx(tfm); - - return get_prng_bytes(rdata, dlen, prng, 1); -} - -static int fips_cprng_reset(struct crypto_rng *tfm, - const u8 *seed, unsigned int slen) -{ - u8 rdata[DEFAULT_BLK_SZ]; - const u8 *key = seed + DEFAULT_BLK_SZ; - int rc; - - struct prng_context *prng = crypto_rng_ctx(tfm); - - if (slen < DEFAULT_PRNG_KSZ + DEFAULT_BLK_SZ) - return -EINVAL; - - /* fips strictly requires seed != key */ - if (!memcmp(seed, key, DEFAULT_PRNG_KSZ)) - return -EINVAL; - - rc = cprng_reset(tfm, seed, slen); - - if (!rc) - goto out; - - /* this primes our continuity test */ - rc = get_prng_bytes(rdata, DEFAULT_BLK_SZ, prng, 0); - prng->rand_data_valid = DEFAULT_BLK_SZ; - -out: - return rc; -} -#endif - -static struct rng_alg rng_algs[] = { { - .generate = cprng_get_random, - .seed = cprng_reset, - .seedsize = DEFAULT_PRNG_KSZ + 2 * DEFAULT_BLK_SZ, - .base = { - .cra_name = "stdrng", - .cra_driver_name = "ansi_cprng", - .cra_priority = 100, - .cra_ctxsize = sizeof(struct prng_context), - .cra_module = THIS_MODULE, - .cra_init = cprng_init, - .cra_exit = cprng_exit, - } -#ifdef CONFIG_CRYPTO_FIPS -}, { - .generate = fips_cprng_get_random, - .seed = fips_cprng_reset, - .seedsize = DEFAULT_PRNG_KSZ + 2 * DEFAULT_BLK_SZ, - .base = { - .cra_name = "fips(ansi_cprng)", - .cra_driver_name = "fips_ansi_cprng", - .cra_priority = 300, - .cra_ctxsize = sizeof(struct prng_context), - .cra_module = THIS_MODULE, - .cra_init = cprng_init, - .cra_exit = cprng_exit, - } -#endif -} }; - -/* Module initalization */ -static int __init prng_mod_init(void) -{ - return crypto_register_rngs(rng_algs, ARRAY_SIZE(rng_algs)); -} - -static void __exit prng_mod_fini(void) -{ - crypto_unregister_rngs(rng_algs, ARRAY_SIZE(rng_algs)); -} - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Software Pseudo Random Number Generator"); -MODULE_AUTHOR("Neil Horman "); -module_param(dbg, int, 0); -MODULE_PARM_DESC(dbg, "Boolean to enable debugging (0/1 == off/on)"); -module_init(prng_mod_init); -module_exit(prng_mod_fini); -MODULE_ALIAS_CRYPTO("stdrng"); -MODULE_ALIAS_CRYPTO("ansi_cprng"); diff --git a/src/linux/crypto/api.c b/src/linux/crypto/api.c deleted file mode 100644 index bbc147c..0000000 --- a/src/linux/crypto/api.c +++ /dev/null @@ -1,615 +0,0 @@ -/* - * Scatterlist Cryptographic API. - * - * Copyright (c) 2002 James Morris - * Copyright (c) 2002 David S. Miller (davem@redhat.com) - * Copyright (c) 2005 Herbert Xu - * - * Portions derived from Cryptoapi, by Alexander Kjeldaas - * and Nettle, by Niels Möller. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -LIST_HEAD(crypto_alg_list); -EXPORT_SYMBOL_GPL(crypto_alg_list); -DECLARE_RWSEM(crypto_alg_sem); -EXPORT_SYMBOL_GPL(crypto_alg_sem); - -BLOCKING_NOTIFIER_HEAD(crypto_chain); -EXPORT_SYMBOL_GPL(crypto_chain); - -static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg); - -struct crypto_alg *crypto_mod_get(struct crypto_alg *alg) -{ - return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL; -} -EXPORT_SYMBOL_GPL(crypto_mod_get); - -void crypto_mod_put(struct crypto_alg *alg) -{ - struct module *module = alg->cra_module; - - crypto_alg_put(alg); - module_put(module); -} -EXPORT_SYMBOL_GPL(crypto_mod_put); - -static inline int crypto_is_test_larval(struct crypto_larval *larval) -{ - return larval->alg.cra_driver_name[0]; -} - -static struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, - u32 mask) -{ - struct crypto_alg *q, *alg = NULL; - int best = -2; - - list_for_each_entry(q, &crypto_alg_list, cra_list) { - int exact, fuzzy; - - if (crypto_is_moribund(q)) - continue; - - if ((q->cra_flags ^ type) & mask) - continue; - - if (crypto_is_larval(q) && - !crypto_is_test_larval((struct crypto_larval *)q) && - ((struct crypto_larval *)q)->mask != mask) - continue; - - exact = !strcmp(q->cra_driver_name, name); - fuzzy = !strcmp(q->cra_name, name); - if (!exact && !(fuzzy && q->cra_priority > best)) - continue; - - if (unlikely(!crypto_mod_get(q))) - continue; - - best = q->cra_priority; - if (alg) - crypto_mod_put(alg); - alg = q; - - if (exact) - break; - } - - return alg; -} - -static void crypto_larval_destroy(struct crypto_alg *alg) -{ - struct crypto_larval *larval = (void *)alg; - - BUG_ON(!crypto_is_larval(alg)); - if (larval->adult) - crypto_mod_put(larval->adult); - kfree(larval); -} - -struct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask) -{ - struct crypto_larval *larval; - - larval = kzalloc(sizeof(*larval), GFP_KERNEL); - if (!larval) - return ERR_PTR(-ENOMEM); - - larval->mask = mask; - larval->alg.cra_flags = CRYPTO_ALG_LARVAL | type; - larval->alg.cra_priority = -1; - larval->alg.cra_destroy = crypto_larval_destroy; - - strlcpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME); - init_completion(&larval->completion); - - return larval; -} -EXPORT_SYMBOL_GPL(crypto_larval_alloc); - -static struct crypto_alg *crypto_larval_add(const char *name, u32 type, - u32 mask) -{ - struct crypto_alg *alg; - struct crypto_larval *larval; - - larval = crypto_larval_alloc(name, type, mask); - if (IS_ERR(larval)) - return ERR_CAST(larval); - - atomic_set(&larval->alg.cra_refcnt, 2); - - down_write(&crypto_alg_sem); - alg = __crypto_alg_lookup(name, type, mask); - if (!alg) { - alg = &larval->alg; - list_add(&alg->cra_list, &crypto_alg_list); - } - up_write(&crypto_alg_sem); - - if (alg != &larval->alg) { - kfree(larval); - if (crypto_is_larval(alg)) - alg = crypto_larval_wait(alg); - } - - return alg; -} - -void crypto_larval_kill(struct crypto_alg *alg) -{ - struct crypto_larval *larval = (void *)alg; - - down_write(&crypto_alg_sem); - list_del(&alg->cra_list); - up_write(&crypto_alg_sem); - complete_all(&larval->completion); - crypto_alg_put(alg); -} -EXPORT_SYMBOL_GPL(crypto_larval_kill); - -static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg) -{ - struct crypto_larval *larval = (void *)alg; - long timeout; - - timeout = wait_for_completion_killable_timeout( - &larval->completion, 60 * HZ); - - alg = larval->adult; - if (timeout < 0) - alg = ERR_PTR(-EINTR); - else if (!timeout) - alg = ERR_PTR(-ETIMEDOUT); - else if (!alg) - alg = ERR_PTR(-ENOENT); - else if (crypto_is_test_larval(larval) && - !(alg->cra_flags & CRYPTO_ALG_TESTED)) - alg = ERR_PTR(-EAGAIN); - else if (!crypto_mod_get(alg)) - alg = ERR_PTR(-EAGAIN); - crypto_mod_put(&larval->alg); - - return alg; -} - -struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, u32 mask) -{ - struct crypto_alg *alg; - - down_read(&crypto_alg_sem); - alg = __crypto_alg_lookup(name, type, mask); - up_read(&crypto_alg_sem); - - return alg; -} -EXPORT_SYMBOL_GPL(crypto_alg_lookup); - -struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask) -{ - struct crypto_alg *alg; - - if (!name) - return ERR_PTR(-ENOENT); - - mask &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD); - type &= mask; - - alg = crypto_alg_lookup(name, type, mask); - if (!alg) { - request_module("crypto-%s", name); - - if (!((type ^ CRYPTO_ALG_NEED_FALLBACK) & mask & - CRYPTO_ALG_NEED_FALLBACK)) - request_module("crypto-%s-all", name); - - alg = crypto_alg_lookup(name, type, mask); - } - - if (alg) - return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg; - - return crypto_larval_add(name, type, mask); -} -EXPORT_SYMBOL_GPL(crypto_larval_lookup); - -int crypto_probing_notify(unsigned long val, void *v) -{ - int ok; - - ok = blocking_notifier_call_chain(&crypto_chain, val, v); - if (ok == NOTIFY_DONE) { - request_module("cryptomgr"); - ok = blocking_notifier_call_chain(&crypto_chain, val, v); - } - - return ok; -} -EXPORT_SYMBOL_GPL(crypto_probing_notify); - -struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) -{ - struct crypto_alg *alg; - struct crypto_alg *larval; - int ok; - - if (!((type | mask) & CRYPTO_ALG_TESTED)) { - type |= CRYPTO_ALG_TESTED; - mask |= CRYPTO_ALG_TESTED; - } - - /* - * If the internal flag is set for a cipher, require a caller to - * to invoke the cipher with the internal flag to use that cipher. - * Also, if a caller wants to allocate a cipher that may or may - * not be an internal cipher, use type | CRYPTO_ALG_INTERNAL and - * !(mask & CRYPTO_ALG_INTERNAL). - */ - if (!((type | mask) & CRYPTO_ALG_INTERNAL)) - mask |= CRYPTO_ALG_INTERNAL; - - larval = crypto_larval_lookup(name, type, mask); - if (IS_ERR(larval) || !crypto_is_larval(larval)) - return larval; - - ok = crypto_probing_notify(CRYPTO_MSG_ALG_REQUEST, larval); - - if (ok == NOTIFY_STOP) - alg = crypto_larval_wait(larval); - else { - crypto_mod_put(larval); - alg = ERR_PTR(-ENOENT); - } - crypto_larval_kill(larval); - return alg; -} -EXPORT_SYMBOL_GPL(crypto_alg_mod_lookup); - -static int crypto_init_ops(struct crypto_tfm *tfm, u32 type, u32 mask) -{ - const struct crypto_type *type_obj = tfm->__crt_alg->cra_type; - - if (type_obj) - return type_obj->init(tfm, type, mask); - - switch (crypto_tfm_alg_type(tfm)) { - case CRYPTO_ALG_TYPE_CIPHER: - return crypto_init_cipher_ops(tfm); - - case CRYPTO_ALG_TYPE_COMPRESS: - return crypto_init_compress_ops(tfm); - - default: - break; - } - - BUG(); - return -EINVAL; -} - -static void crypto_exit_ops(struct crypto_tfm *tfm) -{ - const struct crypto_type *type = tfm->__crt_alg->cra_type; - - if (type) { - if (tfm->exit) - tfm->exit(tfm); - return; - } - - switch (crypto_tfm_alg_type(tfm)) { - case CRYPTO_ALG_TYPE_CIPHER: - crypto_exit_cipher_ops(tfm); - break; - - case CRYPTO_ALG_TYPE_COMPRESS: - crypto_exit_compress_ops(tfm); - break; - - default: - BUG(); - } -} - -static unsigned int crypto_ctxsize(struct crypto_alg *alg, u32 type, u32 mask) -{ - const struct crypto_type *type_obj = alg->cra_type; - unsigned int len; - - len = alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1); - if (type_obj) - return len + type_obj->ctxsize(alg, type, mask); - - switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { - default: - BUG(); - - case CRYPTO_ALG_TYPE_CIPHER: - len += crypto_cipher_ctxsize(alg); - break; - - case CRYPTO_ALG_TYPE_COMPRESS: - len += crypto_compress_ctxsize(alg); - break; - } - - return len; -} - -void crypto_shoot_alg(struct crypto_alg *alg) -{ - down_write(&crypto_alg_sem); - alg->cra_flags |= CRYPTO_ALG_DYING; - up_write(&crypto_alg_sem); -} -EXPORT_SYMBOL_GPL(crypto_shoot_alg); - -struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type, - u32 mask) -{ - struct crypto_tfm *tfm = NULL; - unsigned int tfm_size; - int err = -ENOMEM; - - tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, type, mask); - tfm = kzalloc(tfm_size, GFP_KERNEL); - if (tfm == NULL) - goto out_err; - - tfm->__crt_alg = alg; - - err = crypto_init_ops(tfm, type, mask); - if (err) - goto out_free_tfm; - - if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm))) - goto cra_init_failed; - - goto out; - -cra_init_failed: - crypto_exit_ops(tfm); -out_free_tfm: - if (err == -EAGAIN) - crypto_shoot_alg(alg); - kfree(tfm); -out_err: - tfm = ERR_PTR(err); -out: - return tfm; -} -EXPORT_SYMBOL_GPL(__crypto_alloc_tfm); - -/* - * crypto_alloc_base - Locate algorithm and allocate transform - * @alg_name: Name of algorithm - * @type: Type of algorithm - * @mask: Mask for type comparison - * - * This function should not be used by new algorithm types. - * Please use crypto_alloc_tfm instead. - * - * crypto_alloc_base() will first attempt to locate an already loaded - * algorithm. If that fails and the kernel supports dynamically loadable - * modules, it will then attempt to load a module of the same name or - * alias. If that fails it will send a query to any loaded crypto manager - * to construct an algorithm on the fly. A refcount is grabbed on the - * algorithm which is then associated with the new transform. - * - * The returned transform is of a non-determinate type. Most people - * should use one of the more specific allocation functions such as - * crypto_alloc_blkcipher. - * - * In case of error the return value is an error pointer. - */ -struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask) -{ - struct crypto_tfm *tfm; - int err; - - for (;;) { - struct crypto_alg *alg; - - alg = crypto_alg_mod_lookup(alg_name, type, mask); - if (IS_ERR(alg)) { - err = PTR_ERR(alg); - goto err; - } - - tfm = __crypto_alloc_tfm(alg, type, mask); - if (!IS_ERR(tfm)) - return tfm; - - crypto_mod_put(alg); - err = PTR_ERR(tfm); - -err: - if (err != -EAGAIN) - break; - if (fatal_signal_pending(current)) { - err = -EINTR; - break; - } - } - - return ERR_PTR(err); -} -EXPORT_SYMBOL_GPL(crypto_alloc_base); - -void *crypto_create_tfm(struct crypto_alg *alg, - const struct crypto_type *frontend) -{ - char *mem; - struct crypto_tfm *tfm = NULL; - unsigned int tfmsize; - unsigned int total; - int err = -ENOMEM; - - tfmsize = frontend->tfmsize; - total = tfmsize + sizeof(*tfm) + frontend->extsize(alg); - - mem = kzalloc(total, GFP_KERNEL); - if (mem == NULL) - goto out_err; - - tfm = (struct crypto_tfm *)(mem + tfmsize); - tfm->__crt_alg = alg; - - err = frontend->init_tfm(tfm); - if (err) - goto out_free_tfm; - - if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm))) - goto cra_init_failed; - - goto out; - -cra_init_failed: - crypto_exit_ops(tfm); -out_free_tfm: - if (err == -EAGAIN) - crypto_shoot_alg(alg); - kfree(mem); -out_err: - mem = ERR_PTR(err); -out: - return mem; -} -EXPORT_SYMBOL_GPL(crypto_create_tfm); - -struct crypto_alg *crypto_find_alg(const char *alg_name, - const struct crypto_type *frontend, - u32 type, u32 mask) -{ - struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask) = - crypto_alg_mod_lookup; - - if (frontend) { - type &= frontend->maskclear; - mask &= frontend->maskclear; - type |= frontend->type; - mask |= frontend->maskset; - - if (frontend->lookup) - lookup = frontend->lookup; - } - - return lookup(alg_name, type, mask); -} -EXPORT_SYMBOL_GPL(crypto_find_alg); - -/* - * crypto_alloc_tfm - Locate algorithm and allocate transform - * @alg_name: Name of algorithm - * @frontend: Frontend algorithm type - * @type: Type of algorithm - * @mask: Mask for type comparison - * - * crypto_alloc_tfm() will first attempt to locate an already loaded - * algorithm. If that fails and the kernel supports dynamically loadable - * modules, it will then attempt to load a module of the same name or - * alias. If that fails it will send a query to any loaded crypto manager - * to construct an algorithm on the fly. A refcount is grabbed on the - * algorithm which is then associated with the new transform. - * - * The returned transform is of a non-determinate type. Most people - * should use one of the more specific allocation functions such as - * crypto_alloc_blkcipher. - * - * In case of error the return value is an error pointer. - */ -void *crypto_alloc_tfm(const char *alg_name, - const struct crypto_type *frontend, u32 type, u32 mask) -{ - void *tfm; - int err; - - for (;;) { - struct crypto_alg *alg; - - alg = crypto_find_alg(alg_name, frontend, type, mask); - if (IS_ERR(alg)) { - err = PTR_ERR(alg); - goto err; - } - - tfm = crypto_create_tfm(alg, frontend); - if (!IS_ERR(tfm)) - return tfm; - - crypto_mod_put(alg); - err = PTR_ERR(tfm); - -err: - if (err != -EAGAIN) - break; - if (fatal_signal_pending(current)) { - err = -EINTR; - break; - } - } - - return ERR_PTR(err); -} -EXPORT_SYMBOL_GPL(crypto_alloc_tfm); - -/* - * crypto_destroy_tfm - Free crypto transform - * @mem: Start of tfm slab - * @tfm: Transform to free - * - * This function frees up the transform and any associated resources, - * then drops the refcount on the associated algorithm. - */ -void crypto_destroy_tfm(void *mem, struct crypto_tfm *tfm) -{ - struct crypto_alg *alg; - - if (unlikely(!mem)) - return; - - alg = tfm->__crt_alg; - - if (!tfm->exit && alg->cra_exit) - alg->cra_exit(tfm); - crypto_exit_ops(tfm); - crypto_mod_put(alg); - kzfree(mem); -} -EXPORT_SYMBOL_GPL(crypto_destroy_tfm); - -int crypto_has_alg(const char *name, u32 type, u32 mask) -{ - int ret = 0; - struct crypto_alg *alg = crypto_alg_mod_lookup(name, type, mask); - - if (!IS_ERR(alg)) { - crypto_mod_put(alg); - ret = 1; - } - - return ret; -} -EXPORT_SYMBOL_GPL(crypto_has_alg); - -MODULE_DESCRIPTION("Cryptographic core API"); -MODULE_LICENSE("GPL"); diff --git a/src/linux/crypto/asymmetric_keys/.gitignore b/src/linux/crypto/asymmetric_keys/.gitignore deleted file mode 100644 index ee32837..0000000 --- a/src/linux/crypto/asymmetric_keys/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*-asn1.[ch] diff --git a/src/linux/crypto/asymmetric_keys/Kconfig b/src/linux/crypto/asymmetric_keys/Kconfig deleted file mode 100644 index 331f6ba..0000000 --- a/src/linux/crypto/asymmetric_keys/Kconfig +++ /dev/null @@ -1,64 +0,0 @@ -menuconfig ASYMMETRIC_KEY_TYPE - bool "Asymmetric (public-key cryptographic) key type" - depends on KEYS - help - This option provides support for a key type that holds the data for - the asymmetric keys used for public key cryptographic operations such - as encryption, decryption, signature generation and signature - verification. - -if ASYMMETRIC_KEY_TYPE - -config ASYMMETRIC_PUBLIC_KEY_SUBTYPE - tristate "Asymmetric public-key crypto algorithm subtype" - select MPILIB - select CRYPTO_HASH_INFO - select CRYPTO_AKCIPHER - help - This option provides support for asymmetric public key type handling. - If signature generation and/or verification are to be used, - appropriate hash algorithms (such as SHA-1) must be available. - ENOPKG will be reported if the requisite algorithm is unavailable. - -config X509_CERTIFICATE_PARSER - tristate "X.509 certificate parser" - depends on ASYMMETRIC_PUBLIC_KEY_SUBTYPE - select ASN1 - select OID_REGISTRY - help - This option provides support for parsing X.509 format blobs for key - data and provides the ability to instantiate a crypto key from a - public key packet found inside the certificate. - -config PKCS7_MESSAGE_PARSER - tristate "PKCS#7 message parser" - depends on X509_CERTIFICATE_PARSER - select ASN1 - select OID_REGISTRY - help - This option provides support for parsing PKCS#7 format messages for - signature data and provides the ability to verify the signature. - -config PKCS7_TEST_KEY - tristate "PKCS#7 testing key type" - depends on SYSTEM_DATA_VERIFICATION - help - This option provides a type of key that can be loaded up from a - PKCS#7 message - provided the message is signed by a trusted key. If - it is, the PKCS#7 wrapper is discarded and reading the key returns - just the payload. If it isn't, adding the key will fail with an - error. - - This is intended for testing the PKCS#7 parser. - -config SIGNED_PE_FILE_VERIFICATION - bool "Support for PE file signature verification" - depends on PKCS7_MESSAGE_PARSER=y - depends on SYSTEM_DATA_VERIFICATION - select ASN1 - select OID_REGISTRY - help - This option provides support for verifying the signature(s) on a - signed PE binary. - -endif # ASYMMETRIC_KEY_TYPE diff --git a/src/linux/crypto/async_tx/Kconfig b/src/linux/crypto/async_tx/Kconfig deleted file mode 100644 index f38a58a..0000000 --- a/src/linux/crypto/async_tx/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -config ASYNC_CORE - tristate - -config ASYNC_MEMCPY - tristate - select ASYNC_CORE - -config ASYNC_XOR - tristate - select ASYNC_CORE - select XOR_BLOCKS - -config ASYNC_PQ - tristate - select ASYNC_CORE - -config ASYNC_RAID6_RECOV - tristate - select ASYNC_CORE - select ASYNC_PQ - select ASYNC_XOR - -config ASYNC_TX_DISABLE_PQ_VAL_DMA - bool - -config ASYNC_TX_DISABLE_XOR_VAL_DMA - bool diff --git a/src/linux/crypto/blkcipher.c b/src/linux/crypto/blkcipher.c deleted file mode 100644 index a832426..0000000 --- a/src/linux/crypto/blkcipher.c +++ /dev/null @@ -1,560 +0,0 @@ -/* - * Block chaining cipher operations. - * - * Generic encrypt/decrypt wrapper for ciphers, handles operations across - * multiple page boundaries by using temporary blocks. In user context, - * the kernel is given a chance to schedule us once per page. - * - * Copyright (c) 2006 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -enum { - BLKCIPHER_WALK_PHYS = 1 << 0, - BLKCIPHER_WALK_SLOW = 1 << 1, - BLKCIPHER_WALK_COPY = 1 << 2, - BLKCIPHER_WALK_DIFF = 1 << 3, -}; - -static int blkcipher_walk_next(struct blkcipher_desc *desc, - struct blkcipher_walk *walk); -static int blkcipher_walk_first(struct blkcipher_desc *desc, - struct blkcipher_walk *walk); - -static inline void blkcipher_map_src(struct blkcipher_walk *walk) -{ - walk->src.virt.addr = scatterwalk_map(&walk->in); -} - -static inline void blkcipher_map_dst(struct blkcipher_walk *walk) -{ - walk->dst.virt.addr = scatterwalk_map(&walk->out); -} - -static inline void blkcipher_unmap_src(struct blkcipher_walk *walk) -{ - scatterwalk_unmap(walk->src.virt.addr); -} - -static inline void blkcipher_unmap_dst(struct blkcipher_walk *walk) -{ - scatterwalk_unmap(walk->dst.virt.addr); -} - -/* Get a spot of the specified length that does not straddle a page. - * The caller needs to ensure that there is enough space for this operation. - */ -static inline u8 *blkcipher_get_spot(u8 *start, unsigned int len) -{ - u8 *end_page = (u8 *)(((unsigned long)(start + len - 1)) & PAGE_MASK); - return max(start, end_page); -} - -static inline unsigned int blkcipher_done_slow(struct blkcipher_walk *walk, - unsigned int bsize) -{ - u8 *addr; - - addr = (u8 *)ALIGN((unsigned long)walk->buffer, walk->alignmask + 1); - addr = blkcipher_get_spot(addr, bsize); - scatterwalk_copychunks(addr, &walk->out, bsize, 1); - return bsize; -} - -static inline unsigned int blkcipher_done_fast(struct blkcipher_walk *walk, - unsigned int n) -{ - if (walk->flags & BLKCIPHER_WALK_COPY) { - blkcipher_map_dst(walk); - memcpy(walk->dst.virt.addr, walk->page, n); - blkcipher_unmap_dst(walk); - } else if (!(walk->flags & BLKCIPHER_WALK_PHYS)) { - if (walk->flags & BLKCIPHER_WALK_DIFF) - blkcipher_unmap_dst(walk); - blkcipher_unmap_src(walk); - } - - scatterwalk_advance(&walk->in, n); - scatterwalk_advance(&walk->out, n); - - return n; -} - -int blkcipher_walk_done(struct blkcipher_desc *desc, - struct blkcipher_walk *walk, int err) -{ - unsigned int nbytes = 0; - - if (likely(err >= 0)) { - unsigned int n = walk->nbytes - err; - - if (likely(!(walk->flags & BLKCIPHER_WALK_SLOW))) - n = blkcipher_done_fast(walk, n); - else if (WARN_ON(err)) { - err = -EINVAL; - goto err; - } else - n = blkcipher_done_slow(walk, n); - - nbytes = walk->total - n; - err = 0; - } - - scatterwalk_done(&walk->in, 0, nbytes); - scatterwalk_done(&walk->out, 1, nbytes); - -err: - walk->total = nbytes; - walk->nbytes = nbytes; - - if (nbytes) { - crypto_yield(desc->flags); - return blkcipher_walk_next(desc, walk); - } - - if (walk->iv != desc->info) - memcpy(desc->info, walk->iv, walk->ivsize); - if (walk->buffer != walk->page) - kfree(walk->buffer); - if (walk->page) - free_page((unsigned long)walk->page); - - return err; -} -EXPORT_SYMBOL_GPL(blkcipher_walk_done); - -static inline int blkcipher_next_slow(struct blkcipher_desc *desc, - struct blkcipher_walk *walk, - unsigned int bsize, - unsigned int alignmask) -{ - unsigned int n; - unsigned aligned_bsize = ALIGN(bsize, alignmask + 1); - - if (walk->buffer) - goto ok; - - walk->buffer = walk->page; - if (walk->buffer) - goto ok; - - n = aligned_bsize * 3 - (alignmask + 1) + - (alignmask & ~(crypto_tfm_ctx_alignment() - 1)); - walk->buffer = kmalloc(n, GFP_ATOMIC); - if (!walk->buffer) - return blkcipher_walk_done(desc, walk, -ENOMEM); - -ok: - walk->dst.virt.addr = (u8 *)ALIGN((unsigned long)walk->buffer, - alignmask + 1); - walk->dst.virt.addr = blkcipher_get_spot(walk->dst.virt.addr, bsize); - walk->src.virt.addr = blkcipher_get_spot(walk->dst.virt.addr + - aligned_bsize, bsize); - - scatterwalk_copychunks(walk->src.virt.addr, &walk->in, bsize, 0); - - walk->nbytes = bsize; - walk->flags |= BLKCIPHER_WALK_SLOW; - - return 0; -} - -static inline int blkcipher_next_copy(struct blkcipher_walk *walk) -{ - u8 *tmp = walk->page; - - blkcipher_map_src(walk); - memcpy(tmp, walk->src.virt.addr, walk->nbytes); - blkcipher_unmap_src(walk); - - walk->src.virt.addr = tmp; - walk->dst.virt.addr = tmp; - - return 0; -} - -static inline int blkcipher_next_fast(struct blkcipher_desc *desc, - struct blkcipher_walk *walk) -{ - unsigned long diff; - - walk->src.phys.page = scatterwalk_page(&walk->in); - walk->src.phys.offset = offset_in_page(walk->in.offset); - walk->dst.phys.page = scatterwalk_page(&walk->out); - walk->dst.phys.offset = offset_in_page(walk->out.offset); - - if (walk->flags & BLKCIPHER_WALK_PHYS) - return 0; - - diff = walk->src.phys.offset - walk->dst.phys.offset; - diff |= walk->src.virt.page - walk->dst.virt.page; - - blkcipher_map_src(walk); - walk->dst.virt.addr = walk->src.virt.addr; - - if (diff) { - walk->flags |= BLKCIPHER_WALK_DIFF; - blkcipher_map_dst(walk); - } - - return 0; -} - -static int blkcipher_walk_next(struct blkcipher_desc *desc, - struct blkcipher_walk *walk) -{ - unsigned int bsize; - unsigned int n; - int err; - - n = walk->total; - if (unlikely(n < walk->cipher_blocksize)) { - desc->flags |= CRYPTO_TFM_RES_BAD_BLOCK_LEN; - return blkcipher_walk_done(desc, walk, -EINVAL); - } - - bsize = min(walk->walk_blocksize, n); - - walk->flags &= ~(BLKCIPHER_WALK_SLOW | BLKCIPHER_WALK_COPY | - BLKCIPHER_WALK_DIFF); - if (!scatterwalk_aligned(&walk->in, walk->alignmask) || - !scatterwalk_aligned(&walk->out, walk->alignmask)) { - walk->flags |= BLKCIPHER_WALK_COPY; - if (!walk->page) { - walk->page = (void *)__get_free_page(GFP_ATOMIC); - if (!walk->page) - n = 0; - } - } - - n = scatterwalk_clamp(&walk->in, n); - n = scatterwalk_clamp(&walk->out, n); - - if (unlikely(n < bsize)) { - err = blkcipher_next_slow(desc, walk, bsize, walk->alignmask); - goto set_phys_lowmem; - } - - walk->nbytes = n; - if (walk->flags & BLKCIPHER_WALK_COPY) { - err = blkcipher_next_copy(walk); - goto set_phys_lowmem; - } - - return blkcipher_next_fast(desc, walk); - -set_phys_lowmem: - if (walk->flags & BLKCIPHER_WALK_PHYS) { - walk->src.phys.page = virt_to_page(walk->src.virt.addr); - walk->dst.phys.page = virt_to_page(walk->dst.virt.addr); - walk->src.phys.offset &= PAGE_SIZE - 1; - walk->dst.phys.offset &= PAGE_SIZE - 1; - } - return err; -} - -static inline int blkcipher_copy_iv(struct blkcipher_walk *walk) -{ - unsigned bs = walk->walk_blocksize; - unsigned aligned_bs = ALIGN(bs, walk->alignmask + 1); - unsigned int size = aligned_bs * 2 + - walk->ivsize + max(aligned_bs, walk->ivsize) - - (walk->alignmask + 1); - u8 *iv; - - size += walk->alignmask & ~(crypto_tfm_ctx_alignment() - 1); - walk->buffer = kmalloc(size, GFP_ATOMIC); - if (!walk->buffer) - return -ENOMEM; - - iv = (u8 *)ALIGN((unsigned long)walk->buffer, walk->alignmask + 1); - iv = blkcipher_get_spot(iv, bs) + aligned_bs; - iv = blkcipher_get_spot(iv, bs) + aligned_bs; - iv = blkcipher_get_spot(iv, walk->ivsize); - - walk->iv = memcpy(iv, walk->iv, walk->ivsize); - return 0; -} - -int blkcipher_walk_virt(struct blkcipher_desc *desc, - struct blkcipher_walk *walk) -{ - walk->flags &= ~BLKCIPHER_WALK_PHYS; - walk->walk_blocksize = crypto_blkcipher_blocksize(desc->tfm); - walk->cipher_blocksize = walk->walk_blocksize; - walk->ivsize = crypto_blkcipher_ivsize(desc->tfm); - walk->alignmask = crypto_blkcipher_alignmask(desc->tfm); - return blkcipher_walk_first(desc, walk); -} -EXPORT_SYMBOL_GPL(blkcipher_walk_virt); - -int blkcipher_walk_phys(struct blkcipher_desc *desc, - struct blkcipher_walk *walk) -{ - walk->flags |= BLKCIPHER_WALK_PHYS; - walk->walk_blocksize = crypto_blkcipher_blocksize(desc->tfm); - walk->cipher_blocksize = walk->walk_blocksize; - walk->ivsize = crypto_blkcipher_ivsize(desc->tfm); - walk->alignmask = crypto_blkcipher_alignmask(desc->tfm); - return blkcipher_walk_first(desc, walk); -} -EXPORT_SYMBOL_GPL(blkcipher_walk_phys); - -static int blkcipher_walk_first(struct blkcipher_desc *desc, - struct blkcipher_walk *walk) -{ - if (WARN_ON_ONCE(in_irq())) - return -EDEADLK; - - walk->iv = desc->info; - walk->nbytes = walk->total; - if (unlikely(!walk->total)) - return 0; - - walk->buffer = NULL; - if (unlikely(((unsigned long)walk->iv & walk->alignmask))) { - int err = blkcipher_copy_iv(walk); - if (err) - return err; - } - - scatterwalk_start(&walk->in, walk->in.sg); - scatterwalk_start(&walk->out, walk->out.sg); - walk->page = NULL; - - return blkcipher_walk_next(desc, walk); -} - -int blkcipher_walk_virt_block(struct blkcipher_desc *desc, - struct blkcipher_walk *walk, - unsigned int blocksize) -{ - walk->flags &= ~BLKCIPHER_WALK_PHYS; - walk->walk_blocksize = blocksize; - walk->cipher_blocksize = crypto_blkcipher_blocksize(desc->tfm); - walk->ivsize = crypto_blkcipher_ivsize(desc->tfm); - walk->alignmask = crypto_blkcipher_alignmask(desc->tfm); - return blkcipher_walk_first(desc, walk); -} -EXPORT_SYMBOL_GPL(blkcipher_walk_virt_block); - -int blkcipher_aead_walk_virt_block(struct blkcipher_desc *desc, - struct blkcipher_walk *walk, - struct crypto_aead *tfm, - unsigned int blocksize) -{ - walk->flags &= ~BLKCIPHER_WALK_PHYS; - walk->walk_blocksize = blocksize; - walk->cipher_blocksize = crypto_aead_blocksize(tfm); - walk->ivsize = crypto_aead_ivsize(tfm); - walk->alignmask = crypto_aead_alignmask(tfm); - return blkcipher_walk_first(desc, walk); -} -EXPORT_SYMBOL_GPL(blkcipher_aead_walk_virt_block); - -static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen) -{ - struct blkcipher_alg *cipher = &tfm->__crt_alg->cra_blkcipher; - unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); - int ret; - u8 *buffer, *alignbuffer; - unsigned long absize; - - absize = keylen + alignmask; - buffer = kmalloc(absize, GFP_ATOMIC); - if (!buffer) - return -ENOMEM; - - alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); - memcpy(alignbuffer, key, keylen); - ret = cipher->setkey(tfm, alignbuffer, keylen); - memset(alignbuffer, 0, keylen); - kfree(buffer); - return ret; -} - -static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) -{ - struct blkcipher_alg *cipher = &tfm->__crt_alg->cra_blkcipher; - unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); - - if (keylen < cipher->min_keysize || keylen > cipher->max_keysize) { - tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; - return -EINVAL; - } - - if ((unsigned long)key & alignmask) - return setkey_unaligned(tfm, key, keylen); - - return cipher->setkey(tfm, key, keylen); -} - -static int async_setkey(struct crypto_ablkcipher *tfm, const u8 *key, - unsigned int keylen) -{ - return setkey(crypto_ablkcipher_tfm(tfm), key, keylen); -} - -static int async_encrypt(struct ablkcipher_request *req) -{ - struct crypto_tfm *tfm = req->base.tfm; - struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; - struct blkcipher_desc desc = { - .tfm = __crypto_blkcipher_cast(tfm), - .info = req->info, - .flags = req->base.flags, - }; - - - return alg->encrypt(&desc, req->dst, req->src, req->nbytes); -} - -static int async_decrypt(struct ablkcipher_request *req) -{ - struct crypto_tfm *tfm = req->base.tfm; - struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; - struct blkcipher_desc desc = { - .tfm = __crypto_blkcipher_cast(tfm), - .info = req->info, - .flags = req->base.flags, - }; - - return alg->decrypt(&desc, req->dst, req->src, req->nbytes); -} - -static unsigned int crypto_blkcipher_ctxsize(struct crypto_alg *alg, u32 type, - u32 mask) -{ - struct blkcipher_alg *cipher = &alg->cra_blkcipher; - unsigned int len = alg->cra_ctxsize; - - if ((mask & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_MASK && - cipher->ivsize) { - len = ALIGN(len, (unsigned long)alg->cra_alignmask + 1); - len += cipher->ivsize; - } - - return len; -} - -static int crypto_init_blkcipher_ops_async(struct crypto_tfm *tfm) -{ - struct ablkcipher_tfm *crt = &tfm->crt_ablkcipher; - struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; - - crt->setkey = async_setkey; - crt->encrypt = async_encrypt; - crt->decrypt = async_decrypt; - crt->base = __crypto_ablkcipher_cast(tfm); - crt->ivsize = alg->ivsize; - - return 0; -} - -static int crypto_init_blkcipher_ops_sync(struct crypto_tfm *tfm) -{ - struct blkcipher_tfm *crt = &tfm->crt_blkcipher; - struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; - unsigned long align = crypto_tfm_alg_alignmask(tfm) + 1; - unsigned long addr; - - crt->setkey = setkey; - crt->encrypt = alg->encrypt; - crt->decrypt = alg->decrypt; - - addr = (unsigned long)crypto_tfm_ctx(tfm); - addr = ALIGN(addr, align); - addr += ALIGN(tfm->__crt_alg->cra_ctxsize, align); - crt->iv = (void *)addr; - - return 0; -} - -static int crypto_init_blkcipher_ops(struct crypto_tfm *tfm, u32 type, u32 mask) -{ - struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; - - if (alg->ivsize > PAGE_SIZE / 8) - return -EINVAL; - - if ((mask & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_MASK) - return crypto_init_blkcipher_ops_sync(tfm); - else - return crypto_init_blkcipher_ops_async(tfm); -} - -#ifdef CONFIG_NET -static int crypto_blkcipher_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - struct crypto_report_blkcipher rblkcipher; - - strncpy(rblkcipher.type, "blkcipher", sizeof(rblkcipher.type)); - strncpy(rblkcipher.geniv, alg->cra_blkcipher.geniv ?: "", - sizeof(rblkcipher.geniv)); - - rblkcipher.blocksize = alg->cra_blocksize; - rblkcipher.min_keysize = alg->cra_blkcipher.min_keysize; - rblkcipher.max_keysize = alg->cra_blkcipher.max_keysize; - rblkcipher.ivsize = alg->cra_blkcipher.ivsize; - - if (nla_put(skb, CRYPTOCFGA_REPORT_BLKCIPHER, - sizeof(struct crypto_report_blkcipher), &rblkcipher)) - goto nla_put_failure; - return 0; - -nla_put_failure: - return -EMSGSIZE; -} -#else -static int crypto_blkcipher_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif - -static void crypto_blkcipher_show(struct seq_file *m, struct crypto_alg *alg) - __attribute__ ((unused)); -static void crypto_blkcipher_show(struct seq_file *m, struct crypto_alg *alg) -{ - seq_printf(m, "type : blkcipher\n"); - seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); - seq_printf(m, "min keysize : %u\n", alg->cra_blkcipher.min_keysize); - seq_printf(m, "max keysize : %u\n", alg->cra_blkcipher.max_keysize); - seq_printf(m, "ivsize : %u\n", alg->cra_blkcipher.ivsize); - seq_printf(m, "geniv : %s\n", alg->cra_blkcipher.geniv ?: - ""); -} - -const struct crypto_type crypto_blkcipher_type = { - .ctxsize = crypto_blkcipher_ctxsize, - .init = crypto_init_blkcipher_ops, -#ifdef CONFIG_PROC_FS - .show = crypto_blkcipher_show, -#endif - .report = crypto_blkcipher_report, -}; -EXPORT_SYMBOL_GPL(crypto_blkcipher_type); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Generic block chaining cipher type"); diff --git a/src/linux/crypto/cipher.c b/src/linux/crypto/cipher.c deleted file mode 100644 index 39541e0..0000000 --- a/src/linux/crypto/cipher.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Cryptographic API. - * - * Cipher operations. - * - * Copyright (c) 2002 James Morris - * Copyright (c) 2005 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include "internal.h" - -static int setkey_unaligned(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen) -{ - struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher; - unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); - int ret; - u8 *buffer, *alignbuffer; - unsigned long absize; - - absize = keylen + alignmask; - buffer = kmalloc(absize, GFP_ATOMIC); - if (!buffer) - return -ENOMEM; - - alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); - memcpy(alignbuffer, key, keylen); - ret = cia->cia_setkey(tfm, alignbuffer, keylen); - memset(alignbuffer, 0, keylen); - kfree(buffer); - return ret; - -} - -static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen) -{ - struct cipher_alg *cia = &tfm->__crt_alg->cra_cipher; - unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); - - tfm->crt_flags &= ~CRYPTO_TFM_RES_MASK; - if (keylen < cia->cia_min_keysize || keylen > cia->cia_max_keysize) { - tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN; - return -EINVAL; - } - - if ((unsigned long)key & alignmask) - return setkey_unaligned(tfm, key, keylen); - - return cia->cia_setkey(tfm, key, keylen); -} - -static void cipher_crypt_unaligned(void (*fn)(struct crypto_tfm *, u8 *, - const u8 *), - struct crypto_tfm *tfm, - u8 *dst, const u8 *src) -{ - unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); - unsigned int size = crypto_tfm_alg_blocksize(tfm); - u8 buffer[size + alignmask]; - u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); - - memcpy(tmp, src, size); - fn(tfm, tmp, tmp); - memcpy(dst, tmp, size); -} - -static void cipher_encrypt_unaligned(struct crypto_tfm *tfm, - u8 *dst, const u8 *src) -{ - unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); - struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher; - - if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) { - cipher_crypt_unaligned(cipher->cia_encrypt, tfm, dst, src); - return; - } - - cipher->cia_encrypt(tfm, dst, src); -} - -static void cipher_decrypt_unaligned(struct crypto_tfm *tfm, - u8 *dst, const u8 *src) -{ - unsigned long alignmask = crypto_tfm_alg_alignmask(tfm); - struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher; - - if (unlikely(((unsigned long)dst | (unsigned long)src) & alignmask)) { - cipher_crypt_unaligned(cipher->cia_decrypt, tfm, dst, src); - return; - } - - cipher->cia_decrypt(tfm, dst, src); -} - -int crypto_init_cipher_ops(struct crypto_tfm *tfm) -{ - struct cipher_tfm *ops = &tfm->crt_cipher; - struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher; - - ops->cit_setkey = setkey; - ops->cit_encrypt_one = crypto_tfm_alg_alignmask(tfm) ? - cipher_encrypt_unaligned : cipher->cia_encrypt; - ops->cit_decrypt_one = crypto_tfm_alg_alignmask(tfm) ? - cipher_decrypt_unaligned : cipher->cia_decrypt; - - return 0; -} - -void crypto_exit_cipher_ops(struct crypto_tfm *tfm) -{ -} diff --git a/src/linux/crypto/compress.c b/src/linux/crypto/compress.c deleted file mode 100644 index c33f076..0000000 --- a/src/linux/crypto/compress.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Cryptographic API. - * - * Compression operations. - * - * Copyright (c) 2002 James Morris - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ -#include -#include -#include -#include -#include "internal.h" - -static int crypto_compress(struct crypto_tfm *tfm, - const u8 *src, unsigned int slen, - u8 *dst, unsigned int *dlen) -{ - return tfm->__crt_alg->cra_compress.coa_compress(tfm, src, slen, dst, - dlen); -} - -static int crypto_decompress(struct crypto_tfm *tfm, - const u8 *src, unsigned int slen, - u8 *dst, unsigned int *dlen) -{ - return tfm->__crt_alg->cra_compress.coa_decompress(tfm, src, slen, dst, - dlen); -} - -int crypto_init_compress_ops(struct crypto_tfm *tfm) -{ - struct compress_tfm *ops = &tfm->crt_compress; - - ops->cot_compress = crypto_compress; - ops->cot_decompress = crypto_decompress; - - return 0; -} - -void crypto_exit_compress_ops(struct crypto_tfm *tfm) -{ -} diff --git a/src/linux/crypto/crc32c_generic.c b/src/linux/crypto/crc32c_generic.c deleted file mode 100644 index 4c0a0e2..0000000 --- a/src/linux/crypto/crc32c_generic.c +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Cryptographic API. - * - * CRC32C chksum - * - *@Article{castagnoli-crc, - * author = { Guy Castagnoli and Stefan Braeuer and Martin Herrman}, - * title = {{Optimization of Cyclic Redundancy-Check Codes with 24 - * and 32 Parity Bits}}, - * journal = IEEE Transactions on Communication, - * year = {1993}, - * volume = {41}, - * number = {6}, - * pages = {}, - * month = {June}, - *} - * Used by the iSCSI driver, possibly others, and derived from the - * the iscsi-crc.c module of the linux-iscsi driver at - * http://linux-iscsi.sourceforge.net. - * - * Following the example of lib/crc32, this function is intended to be - * flexible and useful for all users. Modules that currently have their - * own crc32c, but hopefully may be able to use this one are: - * net/sctp (please add all your doco to here if you change to - * use this one!) - * - * - * Copyright (c) 2004 Cisco Systems, Inc. - * Copyright (c) 2008 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include - -#define CHKSUM_BLOCK_SIZE 1 -#define CHKSUM_DIGEST_SIZE 4 - -struct chksum_ctx { - u32 key; -}; - -struct chksum_desc_ctx { - u32 crc; -}; - -/* - * Steps through buffer one byte at at time, calculates reflected - * crc using table. - */ - -static int chksum_init(struct shash_desc *desc) -{ - struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm); - struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); - - ctx->crc = mctx->key; - - return 0; -} - -/* - * Setting the seed allows arbitrary accumulators and flexible XOR policy - * If your algorithm starts with ~0, then XOR with ~0 before you set - * the seed. - */ -static int chksum_setkey(struct crypto_shash *tfm, const u8 *key, - unsigned int keylen) -{ - struct chksum_ctx *mctx = crypto_shash_ctx(tfm); - - if (keylen != sizeof(mctx->key)) { - crypto_shash_set_flags(tfm, CRYPTO_TFM_RES_BAD_KEY_LEN); - return -EINVAL; - } - mctx->key = le32_to_cpu(*(__le32 *)key); - return 0; -} - -static int chksum_update(struct shash_desc *desc, const u8 *data, - unsigned int length) -{ - struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); - - ctx->crc = __crc32c_le(ctx->crc, data, length); - return 0; -} - -static int chksum_final(struct shash_desc *desc, u8 *out) -{ - struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); - - *(__le32 *)out = ~cpu_to_le32p(&ctx->crc); - return 0; -} - -static int __chksum_finup(u32 *crcp, const u8 *data, unsigned int len, u8 *out) -{ - *(__le32 *)out = ~cpu_to_le32(__crc32c_le(*crcp, data, len)); - return 0; -} - -static int chksum_finup(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *out) -{ - struct chksum_desc_ctx *ctx = shash_desc_ctx(desc); - - return __chksum_finup(&ctx->crc, data, len, out); -} - -static int chksum_digest(struct shash_desc *desc, const u8 *data, - unsigned int length, u8 *out) -{ - struct chksum_ctx *mctx = crypto_shash_ctx(desc->tfm); - - return __chksum_finup(&mctx->key, data, length, out); -} - -static int crc32c_cra_init(struct crypto_tfm *tfm) -{ - struct chksum_ctx *mctx = crypto_tfm_ctx(tfm); - - mctx->key = ~0; - return 0; -} - -static struct shash_alg alg = { - .digestsize = CHKSUM_DIGEST_SIZE, - .setkey = chksum_setkey, - .init = chksum_init, - .update = chksum_update, - .final = chksum_final, - .finup = chksum_finup, - .digest = chksum_digest, - .descsize = sizeof(struct chksum_desc_ctx), - .base = { - .cra_name = "crc32c", - .cra_driver_name = "crc32c-generic", - .cra_priority = 100, - .cra_blocksize = CHKSUM_BLOCK_SIZE, - .cra_alignmask = 3, - .cra_ctxsize = sizeof(struct chksum_ctx), - .cra_module = THIS_MODULE, - .cra_init = crc32c_cra_init, - } -}; - -static int __init crc32c_mod_init(void) -{ - return crypto_register_shash(&alg); -} - -static void __exit crc32c_mod_fini(void) -{ - crypto_unregister_shash(&alg); -} - -module_init(crc32c_mod_init); -module_exit(crc32c_mod_fini); - -MODULE_AUTHOR("Clay Haapala "); -MODULE_DESCRIPTION("CRC32c (Castagnoli) calculations wrapper for lib/crc32c"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_CRYPTO("crc32c"); -MODULE_ALIAS_CRYPTO("crc32c-generic"); diff --git a/src/linux/crypto/crypto_null.c b/src/linux/crypto/crypto_null.c deleted file mode 100644 index 20ff2c7..0000000 --- a/src/linux/crypto/crypto_null.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Cryptographic API. - * - * Null algorithms, aka Much Ado About Nothing. - * - * These are needed for IPsec, and may be useful in general for - * testing & debugging. - * - * The null cipher is compliant with RFC2410. - * - * Copyright (c) 2002 James Morris - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -static DEFINE_MUTEX(crypto_default_null_skcipher_lock); -static struct crypto_skcipher *crypto_default_null_skcipher; -static int crypto_default_null_skcipher_refcnt; - -static int null_compress(struct crypto_tfm *tfm, const u8 *src, - unsigned int slen, u8 *dst, unsigned int *dlen) -{ - if (slen > *dlen) - return -EINVAL; - memcpy(dst, src, slen); - *dlen = slen; - return 0; -} - -static int null_init(struct shash_desc *desc) -{ - return 0; -} - -static int null_update(struct shash_desc *desc, const u8 *data, - unsigned int len) -{ - return 0; -} - -static int null_final(struct shash_desc *desc, u8 *out) -{ - return 0; -} - -static int null_digest(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *out) -{ - return 0; -} - -static int null_hash_setkey(struct crypto_shash *tfm, const u8 *key, - unsigned int keylen) -{ return 0; } - -static int null_setkey(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen) -{ return 0; } - -static void null_crypt(struct crypto_tfm *tfm, u8 *dst, const u8 *src) -{ - memcpy(dst, src, NULL_BLOCK_SIZE); -} - -static int skcipher_null_crypt(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes) -{ - struct blkcipher_walk walk; - int err; - - blkcipher_walk_init(&walk, dst, src, nbytes); - err = blkcipher_walk_virt(desc, &walk); - - while (walk.nbytes) { - if (walk.src.virt.addr != walk.dst.virt.addr) - memcpy(walk.dst.virt.addr, walk.src.virt.addr, - walk.nbytes); - err = blkcipher_walk_done(desc, &walk, 0); - } - - return err; -} - -static struct shash_alg digest_null = { - .digestsize = NULL_DIGEST_SIZE, - .setkey = null_hash_setkey, - .init = null_init, - .update = null_update, - .finup = null_digest, - .digest = null_digest, - .final = null_final, - .base = { - .cra_name = "digest_null", - .cra_flags = CRYPTO_ALG_TYPE_SHASH, - .cra_blocksize = NULL_BLOCK_SIZE, - .cra_module = THIS_MODULE, - } -}; - -static struct crypto_alg null_algs[3] = { { - .cra_name = "cipher_null", - .cra_flags = CRYPTO_ALG_TYPE_CIPHER, - .cra_blocksize = NULL_BLOCK_SIZE, - .cra_ctxsize = 0, - .cra_module = THIS_MODULE, - .cra_u = { .cipher = { - .cia_min_keysize = NULL_KEY_SIZE, - .cia_max_keysize = NULL_KEY_SIZE, - .cia_setkey = null_setkey, - .cia_encrypt = null_crypt, - .cia_decrypt = null_crypt } } -}, { - .cra_name = "ecb(cipher_null)", - .cra_driver_name = "ecb-cipher_null", - .cra_priority = 100, - .cra_flags = CRYPTO_ALG_TYPE_BLKCIPHER, - .cra_blocksize = NULL_BLOCK_SIZE, - .cra_type = &crypto_blkcipher_type, - .cra_ctxsize = 0, - .cra_module = THIS_MODULE, - .cra_u = { .blkcipher = { - .min_keysize = NULL_KEY_SIZE, - .max_keysize = NULL_KEY_SIZE, - .ivsize = NULL_IV_SIZE, - .setkey = null_setkey, - .encrypt = skcipher_null_crypt, - .decrypt = skcipher_null_crypt } } -}, { - .cra_name = "compress_null", - .cra_flags = CRYPTO_ALG_TYPE_COMPRESS, - .cra_blocksize = NULL_BLOCK_SIZE, - .cra_ctxsize = 0, - .cra_module = THIS_MODULE, - .cra_u = { .compress = { - .coa_compress = null_compress, - .coa_decompress = null_compress } } -} }; - -MODULE_ALIAS_CRYPTO("compress_null"); -MODULE_ALIAS_CRYPTO("digest_null"); -MODULE_ALIAS_CRYPTO("cipher_null"); - -struct crypto_skcipher *crypto_get_default_null_skcipher(void) -{ - struct crypto_skcipher *tfm; - - mutex_lock(&crypto_default_null_skcipher_lock); - tfm = crypto_default_null_skcipher; - - if (!tfm) { - tfm = crypto_alloc_skcipher("ecb(cipher_null)", - 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(tfm)) - goto unlock; - - crypto_default_null_skcipher = tfm; - } - - crypto_default_null_skcipher_refcnt++; - -unlock: - mutex_unlock(&crypto_default_null_skcipher_lock); - - return tfm; -} -EXPORT_SYMBOL_GPL(crypto_get_default_null_skcipher); - -void crypto_put_default_null_skcipher(void) -{ - mutex_lock(&crypto_default_null_skcipher_lock); - if (!--crypto_default_null_skcipher_refcnt) { - crypto_free_skcipher(crypto_default_null_skcipher); - crypto_default_null_skcipher = NULL; - } - mutex_unlock(&crypto_default_null_skcipher_lock); -} -EXPORT_SYMBOL_GPL(crypto_put_default_null_skcipher); - -static int __init crypto_null_mod_init(void) -{ - int ret = 0; - - ret = crypto_register_algs(null_algs, ARRAY_SIZE(null_algs)); - if (ret < 0) - goto out; - - ret = crypto_register_shash(&digest_null); - if (ret < 0) - goto out_unregister_algs; - - return 0; - -out_unregister_algs: - crypto_unregister_algs(null_algs, ARRAY_SIZE(null_algs)); -out: - return ret; -} - -static void __exit crypto_null_mod_fini(void) -{ - crypto_unregister_shash(&digest_null); - crypto_unregister_algs(null_algs, ARRAY_SIZE(null_algs)); -} - -module_init(crypto_null_mod_init); -module_exit(crypto_null_mod_fini); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Null Cryptographic Algorithms"); diff --git a/src/linux/crypto/crypto_wq.c b/src/linux/crypto/crypto_wq.c deleted file mode 100644 index 2f1b8d1..0000000 --- a/src/linux/crypto/crypto_wq.c +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Workqueue for crypto subsystem - * - * Copyright (c) 2009 Intel Corp. - * Author: Huang Ying - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include - -struct workqueue_struct *kcrypto_wq; -EXPORT_SYMBOL_GPL(kcrypto_wq); - -static int __init crypto_wq_init(void) -{ - kcrypto_wq = alloc_workqueue("crypto", - WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, 1); - if (unlikely(!kcrypto_wq)) - return -ENOMEM; - return 0; -} - -static void __exit crypto_wq_exit(void) -{ - destroy_workqueue(kcrypto_wq); -} - -subsys_initcall(crypto_wq_init); -module_exit(crypto_wq_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Workqueue for crypto subsystem"); diff --git a/src/linux/crypto/drbg.c b/src/linux/crypto/drbg.c deleted file mode 100644 index 053035b..0000000 --- a/src/linux/crypto/drbg.c +++ /dev/null @@ -1,2079 +0,0 @@ -/* - * DRBG: Deterministic Random Bits Generator - * Based on NIST Recommended DRBG from NIST SP800-90A with the following - * properties: - * * CTR DRBG with DF with AES-128, AES-192, AES-256 cores - * * Hash DRBG with DF with SHA-1, SHA-256, SHA-384, SHA-512 cores - * * HMAC DRBG with DF with SHA-1, SHA-256, SHA-384, SHA-512 cores - * * with and without prediction resistance - * - * Copyright Stephan Mueller , 2014 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU General Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * DRBG Usage - * ========== - * The SP 800-90A DRBG allows the user to specify a personalization string - * for initialization as well as an additional information string for each - * random number request. The following code fragments show how a caller - * uses the kernel crypto API to use the full functionality of the DRBG. - * - * Usage without any additional data - * --------------------------------- - * struct crypto_rng *drng; - * int err; - * char data[DATALEN]; - * - * drng = crypto_alloc_rng(drng_name, 0, 0); - * err = crypto_rng_get_bytes(drng, &data, DATALEN); - * crypto_free_rng(drng); - * - * - * Usage with personalization string during initialization - * ------------------------------------------------------- - * struct crypto_rng *drng; - * int err; - * char data[DATALEN]; - * struct drbg_string pers; - * char personalization[11] = "some-string"; - * - * drbg_string_fill(&pers, personalization, strlen(personalization)); - * drng = crypto_alloc_rng(drng_name, 0, 0); - * // The reset completely re-initializes the DRBG with the provided - * // personalization string - * err = crypto_rng_reset(drng, &personalization, strlen(personalization)); - * err = crypto_rng_get_bytes(drng, &data, DATALEN); - * crypto_free_rng(drng); - * - * - * Usage with additional information string during random number request - * --------------------------------------------------------------------- - * struct crypto_rng *drng; - * int err; - * char data[DATALEN]; - * char addtl_string[11] = "some-string"; - * string drbg_string addtl; - * - * drbg_string_fill(&addtl, addtl_string, strlen(addtl_string)); - * drng = crypto_alloc_rng(drng_name, 0, 0); - * // The following call is a wrapper to crypto_rng_get_bytes() and returns - * // the same error codes. - * err = crypto_drbg_get_bytes_addtl(drng, &data, DATALEN, &addtl); - * crypto_free_rng(drng); - * - * - * Usage with personalization and additional information strings - * ------------------------------------------------------------- - * Just mix both scenarios above. - */ - -#include -#include - -/*************************************************************** - * Backend cipher definitions available to DRBG - ***************************************************************/ - -/* - * The order of the DRBG definitions here matter: every DRBG is registered - * as stdrng. Each DRBG receives an increasing cra_priority values the later - * they are defined in this array (see drbg_fill_array). - * - * HMAC DRBGs are favored over Hash DRBGs over CTR DRBGs, and - * the SHA256 / AES 256 over other ciphers. Thus, the favored - * DRBGs are the latest entries in this array. - */ -static const struct drbg_core drbg_cores[] = { -#ifdef CONFIG_CRYPTO_DRBG_CTR - { - .flags = DRBG_CTR | DRBG_STRENGTH128, - .statelen = 32, /* 256 bits as defined in 10.2.1 */ - .blocklen_bytes = 16, - .cra_name = "ctr_aes128", - .backend_cra_name = "aes", - }, { - .flags = DRBG_CTR | DRBG_STRENGTH192, - .statelen = 40, /* 320 bits as defined in 10.2.1 */ - .blocklen_bytes = 16, - .cra_name = "ctr_aes192", - .backend_cra_name = "aes", - }, { - .flags = DRBG_CTR | DRBG_STRENGTH256, - .statelen = 48, /* 384 bits as defined in 10.2.1 */ - .blocklen_bytes = 16, - .cra_name = "ctr_aes256", - .backend_cra_name = "aes", - }, -#endif /* CONFIG_CRYPTO_DRBG_CTR */ -#ifdef CONFIG_CRYPTO_DRBG_HASH - { - .flags = DRBG_HASH | DRBG_STRENGTH128, - .statelen = 55, /* 440 bits */ - .blocklen_bytes = 20, - .cra_name = "sha1", - .backend_cra_name = "sha1", - }, { - .flags = DRBG_HASH | DRBG_STRENGTH256, - .statelen = 111, /* 888 bits */ - .blocklen_bytes = 48, - .cra_name = "sha384", - .backend_cra_name = "sha384", - }, { - .flags = DRBG_HASH | DRBG_STRENGTH256, - .statelen = 111, /* 888 bits */ - .blocklen_bytes = 64, - .cra_name = "sha512", - .backend_cra_name = "sha512", - }, { - .flags = DRBG_HASH | DRBG_STRENGTH256, - .statelen = 55, /* 440 bits */ - .blocklen_bytes = 32, - .cra_name = "sha256", - .backend_cra_name = "sha256", - }, -#endif /* CONFIG_CRYPTO_DRBG_HASH */ -#ifdef CONFIG_CRYPTO_DRBG_HMAC - { - .flags = DRBG_HMAC | DRBG_STRENGTH128, - .statelen = 20, /* block length of cipher */ - .blocklen_bytes = 20, - .cra_name = "hmac_sha1", - .backend_cra_name = "hmac(sha1)", - }, { - .flags = DRBG_HMAC | DRBG_STRENGTH256, - .statelen = 48, /* block length of cipher */ - .blocklen_bytes = 48, - .cra_name = "hmac_sha384", - .backend_cra_name = "hmac(sha384)", - }, { - .flags = DRBG_HMAC | DRBG_STRENGTH256, - .statelen = 64, /* block length of cipher */ - .blocklen_bytes = 64, - .cra_name = "hmac_sha512", - .backend_cra_name = "hmac(sha512)", - }, { - .flags = DRBG_HMAC | DRBG_STRENGTH256, - .statelen = 32, /* block length of cipher */ - .blocklen_bytes = 32, - .cra_name = "hmac_sha256", - .backend_cra_name = "hmac(sha256)", - }, -#endif /* CONFIG_CRYPTO_DRBG_HMAC */ -}; - -static int drbg_uninstantiate(struct drbg_state *drbg); - -/****************************************************************** - * Generic helper functions - ******************************************************************/ - -/* - * Return strength of DRBG according to SP800-90A section 8.4 - * - * @flags DRBG flags reference - * - * Return: normalized strength in *bytes* value or 32 as default - * to counter programming errors - */ -static inline unsigned short drbg_sec_strength(drbg_flag_t flags) -{ - switch (flags & DRBG_STRENGTH_MASK) { - case DRBG_STRENGTH128: - return 16; - case DRBG_STRENGTH192: - return 24; - case DRBG_STRENGTH256: - return 32; - default: - return 32; - } -} - -/* - * Convert an integer into a byte representation of this integer. - * The byte representation is big-endian - * - * @val value to be converted - * @buf buffer holding the converted integer -- caller must ensure that - * buffer size is at least 32 bit - */ -#if (defined(CONFIG_CRYPTO_DRBG_HASH) || defined(CONFIG_CRYPTO_DRBG_CTR)) -static inline void drbg_cpu_to_be32(__u32 val, unsigned char *buf) -{ - struct s { - __be32 conv; - }; - struct s *conversion = (struct s *) buf; - - conversion->conv = cpu_to_be32(val); -} -#endif /* defined(CONFIG_CRYPTO_DRBG_HASH) || defined(CONFIG_CRYPTO_DRBG_CTR) */ - -/****************************************************************** - * CTR DRBG callback functions - ******************************************************************/ - -#ifdef CONFIG_CRYPTO_DRBG_CTR -#define CRYPTO_DRBG_CTR_STRING "CTR " -MODULE_ALIAS_CRYPTO("drbg_pr_ctr_aes256"); -MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes256"); -MODULE_ALIAS_CRYPTO("drbg_pr_ctr_aes192"); -MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes192"); -MODULE_ALIAS_CRYPTO("drbg_pr_ctr_aes128"); -MODULE_ALIAS_CRYPTO("drbg_nopr_ctr_aes128"); - -static void drbg_kcapi_symsetkey(struct drbg_state *drbg, - const unsigned char *key); -static int drbg_kcapi_sym(struct drbg_state *drbg, unsigned char *outval, - const struct drbg_string *in); -static int drbg_init_sym_kernel(struct drbg_state *drbg); -static int drbg_fini_sym_kernel(struct drbg_state *drbg); -static int drbg_kcapi_sym_ctr(struct drbg_state *drbg, - u8 *inbuf, u32 inbuflen, - u8 *outbuf, u32 outlen); -#define DRBG_CTR_NULL_LEN 128 -#define DRBG_OUTSCRATCHLEN DRBG_CTR_NULL_LEN - -/* BCC function for CTR DRBG as defined in 10.4.3 */ -static int drbg_ctr_bcc(struct drbg_state *drbg, - unsigned char *out, const unsigned char *key, - struct list_head *in) -{ - int ret = 0; - struct drbg_string *curr = NULL; - struct drbg_string data; - short cnt = 0; - - drbg_string_fill(&data, out, drbg_blocklen(drbg)); - - /* 10.4.3 step 2 / 4 */ - drbg_kcapi_symsetkey(drbg, key); - list_for_each_entry(curr, in, list) { - const unsigned char *pos = curr->buf; - size_t len = curr->len; - /* 10.4.3 step 4.1 */ - while (len) { - /* 10.4.3 step 4.2 */ - if (drbg_blocklen(drbg) == cnt) { - cnt = 0; - ret = drbg_kcapi_sym(drbg, out, &data); - if (ret) - return ret; - } - out[cnt] ^= *pos; - pos++; - cnt++; - len--; - } - } - /* 10.4.3 step 4.2 for last block */ - if (cnt) - ret = drbg_kcapi_sym(drbg, out, &data); - - return ret; -} - -/* - * scratchpad usage: drbg_ctr_update is interlinked with drbg_ctr_df - * (and drbg_ctr_bcc, but this function does not need any temporary buffers), - * the scratchpad is used as follows: - * drbg_ctr_update: - * temp - * start: drbg->scratchpad - * length: drbg_statelen(drbg) + drbg_blocklen(drbg) - * note: the cipher writing into this variable works - * blocklen-wise. Now, when the statelen is not a multiple - * of blocklen, the generateion loop below "spills over" - * by at most blocklen. Thus, we need to give sufficient - * memory. - * df_data - * start: drbg->scratchpad + - * drbg_statelen(drbg) + drbg_blocklen(drbg) - * length: drbg_statelen(drbg) - * - * drbg_ctr_df: - * pad - * start: df_data + drbg_statelen(drbg) - * length: drbg_blocklen(drbg) - * iv - * start: pad + drbg_blocklen(drbg) - * length: drbg_blocklen(drbg) - * temp - * start: iv + drbg_blocklen(drbg) - * length: drbg_satelen(drbg) + drbg_blocklen(drbg) - * note: temp is the buffer that the BCC function operates - * on. BCC operates blockwise. drbg_statelen(drbg) - * is sufficient when the DRBG state length is a multiple - * of the block size. For AES192 (and maybe other ciphers) - * this is not correct and the length for temp is - * insufficient (yes, that also means for such ciphers, - * the final output of all BCC rounds are truncated). - * Therefore, add drbg_blocklen(drbg) to cover all - * possibilities. - */ - -/* Derivation Function for CTR DRBG as defined in 10.4.2 */ -static int drbg_ctr_df(struct drbg_state *drbg, - unsigned char *df_data, size_t bytes_to_return, - struct list_head *seedlist) -{ - int ret = -EFAULT; - unsigned char L_N[8]; - /* S3 is input */ - struct drbg_string S1, S2, S4, cipherin; - LIST_HEAD(bcc_list); - unsigned char *pad = df_data + drbg_statelen(drbg); - unsigned char *iv = pad + drbg_blocklen(drbg); - unsigned char *temp = iv + drbg_blocklen(drbg); - size_t padlen = 0; - unsigned int templen = 0; - /* 10.4.2 step 7 */ - unsigned int i = 0; - /* 10.4.2 step 8 */ - const unsigned char *K = (unsigned char *) - "\x00\x01\x02\x03\x04\x05\x06\x07" - "\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17" - "\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"; - unsigned char *X; - size_t generated_len = 0; - size_t inputlen = 0; - struct drbg_string *seed = NULL; - - memset(pad, 0, drbg_blocklen(drbg)); - memset(iv, 0, drbg_blocklen(drbg)); - - /* 10.4.2 step 1 is implicit as we work byte-wise */ - - /* 10.4.2 step 2 */ - if ((512/8) < bytes_to_return) - return -EINVAL; - - /* 10.4.2 step 2 -- calculate the entire length of all input data */ - list_for_each_entry(seed, seedlist, list) - inputlen += seed->len; - drbg_cpu_to_be32(inputlen, &L_N[0]); - - /* 10.4.2 step 3 */ - drbg_cpu_to_be32(bytes_to_return, &L_N[4]); - - /* 10.4.2 step 5: length is L_N, input_string, one byte, padding */ - padlen = (inputlen + sizeof(L_N) + 1) % (drbg_blocklen(drbg)); - /* wrap the padlen appropriately */ - if (padlen) - padlen = drbg_blocklen(drbg) - padlen; - /* - * pad / padlen contains the 0x80 byte and the following zero bytes. - * As the calculated padlen value only covers the number of zero - * bytes, this value has to be incremented by one for the 0x80 byte. - */ - padlen++; - pad[0] = 0x80; - - /* 10.4.2 step 4 -- first fill the linked list and then order it */ - drbg_string_fill(&S1, iv, drbg_blocklen(drbg)); - list_add_tail(&S1.list, &bcc_list); - drbg_string_fill(&S2, L_N, sizeof(L_N)); - list_add_tail(&S2.list, &bcc_list); - list_splice_tail(seedlist, &bcc_list); - drbg_string_fill(&S4, pad, padlen); - list_add_tail(&S4.list, &bcc_list); - - /* 10.4.2 step 9 */ - while (templen < (drbg_keylen(drbg) + (drbg_blocklen(drbg)))) { - /* - * 10.4.2 step 9.1 - the padding is implicit as the buffer - * holds zeros after allocation -- even the increment of i - * is irrelevant as the increment remains within length of i - */ - drbg_cpu_to_be32(i, iv); - /* 10.4.2 step 9.2 -- BCC and concatenation with temp */ - ret = drbg_ctr_bcc(drbg, temp + templen, K, &bcc_list); - if (ret) - goto out; - /* 10.4.2 step 9.3 */ - i++; - templen += drbg_blocklen(drbg); - } - - /* 10.4.2 step 11 */ - X = temp + (drbg_keylen(drbg)); - drbg_string_fill(&cipherin, X, drbg_blocklen(drbg)); - - /* 10.4.2 step 12: overwriting of outval is implemented in next step */ - - /* 10.4.2 step 13 */ - drbg_kcapi_symsetkey(drbg, temp); - while (generated_len < bytes_to_return) { - short blocklen = 0; - /* - * 10.4.2 step 13.1: the truncation of the key length is - * implicit as the key is only drbg_blocklen in size based on - * the implementation of the cipher function callback - */ - ret = drbg_kcapi_sym(drbg, X, &cipherin); - if (ret) - goto out; - blocklen = (drbg_blocklen(drbg) < - (bytes_to_return - generated_len)) ? - drbg_blocklen(drbg) : - (bytes_to_return - generated_len); - /* 10.4.2 step 13.2 and 14 */ - memcpy(df_data + generated_len, X, blocklen); - generated_len += blocklen; - } - - ret = 0; - -out: - memset(iv, 0, drbg_blocklen(drbg)); - memset(temp, 0, drbg_statelen(drbg) + drbg_blocklen(drbg)); - memset(pad, 0, drbg_blocklen(drbg)); - return ret; -} - -/* - * update function of CTR DRBG as defined in 10.2.1.2 - * - * The reseed variable has an enhanced meaning compared to the update - * functions of the other DRBGs as follows: - * 0 => initial seed from initialization - * 1 => reseed via drbg_seed - * 2 => first invocation from drbg_ctr_update when addtl is present. In - * this case, the df_data scratchpad is not deleted so that it is - * available for another calls to prevent calling the DF function - * again. - * 3 => second invocation from drbg_ctr_update. When the update function - * was called with addtl, the df_data memory already contains the - * DFed addtl information and we do not need to call DF again. - */ -static int drbg_ctr_update(struct drbg_state *drbg, struct list_head *seed, - int reseed) -{ - int ret = -EFAULT; - /* 10.2.1.2 step 1 */ - unsigned char *temp = drbg->scratchpad; - unsigned char *df_data = drbg->scratchpad + drbg_statelen(drbg) + - drbg_blocklen(drbg); - - if (3 > reseed) - memset(df_data, 0, drbg_statelen(drbg)); - - if (!reseed) { - /* - * The DRBG uses the CTR mode of the underlying AES cipher. The - * CTR mode increments the counter value after the AES operation - * but SP800-90A requires that the counter is incremented before - * the AES operation. Hence, we increment it at the time we set - * it by one. - */ - crypto_inc(drbg->V, drbg_blocklen(drbg)); - - ret = crypto_skcipher_setkey(drbg->ctr_handle, drbg->C, - drbg_keylen(drbg)); - if (ret) - goto out; - } - - /* 10.2.1.3.2 step 2 and 10.2.1.4.2 step 2 */ - if (seed) { - ret = drbg_ctr_df(drbg, df_data, drbg_statelen(drbg), seed); - if (ret) - goto out; - } - - ret = drbg_kcapi_sym_ctr(drbg, df_data, drbg_statelen(drbg), - temp, drbg_statelen(drbg)); - if (ret) - return ret; - - /* 10.2.1.2 step 5 */ - ret = crypto_skcipher_setkey(drbg->ctr_handle, temp, - drbg_keylen(drbg)); - if (ret) - goto out; - /* 10.2.1.2 step 6 */ - memcpy(drbg->V, temp + drbg_keylen(drbg), drbg_blocklen(drbg)); - /* See above: increment counter by one to compensate timing of CTR op */ - crypto_inc(drbg->V, drbg_blocklen(drbg)); - ret = 0; - -out: - memset(temp, 0, drbg_statelen(drbg) + drbg_blocklen(drbg)); - if (2 != reseed) - memset(df_data, 0, drbg_statelen(drbg)); - return ret; -} - -/* - * scratchpad use: drbg_ctr_update is called independently from - * drbg_ctr_extract_bytes. Therefore, the scratchpad is reused - */ -/* Generate function of CTR DRBG as defined in 10.2.1.5.2 */ -static int drbg_ctr_generate(struct drbg_state *drbg, - unsigned char *buf, unsigned int buflen, - struct list_head *addtl) -{ - int ret; - int len = min_t(int, buflen, INT_MAX); - - /* 10.2.1.5.2 step 2 */ - if (addtl && !list_empty(addtl)) { - ret = drbg_ctr_update(drbg, addtl, 2); - if (ret) - return 0; - } - - /* 10.2.1.5.2 step 4.1 */ - ret = drbg_kcapi_sym_ctr(drbg, drbg->ctr_null_value, DRBG_CTR_NULL_LEN, - buf, len); - if (ret) - return ret; - - /* 10.2.1.5.2 step 6 */ - ret = drbg_ctr_update(drbg, NULL, 3); - if (ret) - len = ret; - - return len; -} - -static const struct drbg_state_ops drbg_ctr_ops = { - .update = drbg_ctr_update, - .generate = drbg_ctr_generate, - .crypto_init = drbg_init_sym_kernel, - .crypto_fini = drbg_fini_sym_kernel, -}; -#endif /* CONFIG_CRYPTO_DRBG_CTR */ - -/****************************************************************** - * HMAC DRBG callback functions - ******************************************************************/ - -#if defined(CONFIG_CRYPTO_DRBG_HASH) || defined(CONFIG_CRYPTO_DRBG_HMAC) -static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval, - const struct list_head *in); -static void drbg_kcapi_hmacsetkey(struct drbg_state *drbg, - const unsigned char *key); -static int drbg_init_hash_kernel(struct drbg_state *drbg); -static int drbg_fini_hash_kernel(struct drbg_state *drbg); -#endif /* (CONFIG_CRYPTO_DRBG_HASH || CONFIG_CRYPTO_DRBG_HMAC) */ - -#ifdef CONFIG_CRYPTO_DRBG_HMAC -#define CRYPTO_DRBG_HMAC_STRING "HMAC " -MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha512"); -MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha512"); -MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha384"); -MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha384"); -MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha256"); -MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha256"); -MODULE_ALIAS_CRYPTO("drbg_pr_hmac_sha1"); -MODULE_ALIAS_CRYPTO("drbg_nopr_hmac_sha1"); - -/* update function of HMAC DRBG as defined in 10.1.2.2 */ -static int drbg_hmac_update(struct drbg_state *drbg, struct list_head *seed, - int reseed) -{ - int ret = -EFAULT; - int i = 0; - struct drbg_string seed1, seed2, vdata; - LIST_HEAD(seedlist); - LIST_HEAD(vdatalist); - - if (!reseed) { - /* 10.1.2.3 step 2 -- memset(0) of C is implicit with kzalloc */ - memset(drbg->V, 1, drbg_statelen(drbg)); - drbg_kcapi_hmacsetkey(drbg, drbg->C); - } - - drbg_string_fill(&seed1, drbg->V, drbg_statelen(drbg)); - list_add_tail(&seed1.list, &seedlist); - /* buffer of seed2 will be filled in for loop below with one byte */ - drbg_string_fill(&seed2, NULL, 1); - list_add_tail(&seed2.list, &seedlist); - /* input data of seed is allowed to be NULL at this point */ - if (seed) - list_splice_tail(seed, &seedlist); - - drbg_string_fill(&vdata, drbg->V, drbg_statelen(drbg)); - list_add_tail(&vdata.list, &vdatalist); - for (i = 2; 0 < i; i--) { - /* first round uses 0x0, second 0x1 */ - unsigned char prefix = DRBG_PREFIX0; - if (1 == i) - prefix = DRBG_PREFIX1; - /* 10.1.2.2 step 1 and 4 -- concatenation and HMAC for key */ - seed2.buf = &prefix; - ret = drbg_kcapi_hash(drbg, drbg->C, &seedlist); - if (ret) - return ret; - drbg_kcapi_hmacsetkey(drbg, drbg->C); - - /* 10.1.2.2 step 2 and 5 -- HMAC for V */ - ret = drbg_kcapi_hash(drbg, drbg->V, &vdatalist); - if (ret) - return ret; - - /* 10.1.2.2 step 3 */ - if (!seed) - return ret; - } - - return 0; -} - -/* generate function of HMAC DRBG as defined in 10.1.2.5 */ -static int drbg_hmac_generate(struct drbg_state *drbg, - unsigned char *buf, - unsigned int buflen, - struct list_head *addtl) -{ - int len = 0; - int ret = 0; - struct drbg_string data; - LIST_HEAD(datalist); - - /* 10.1.2.5 step 2 */ - if (addtl && !list_empty(addtl)) { - ret = drbg_hmac_update(drbg, addtl, 1); - if (ret) - return ret; - } - - drbg_string_fill(&data, drbg->V, drbg_statelen(drbg)); - list_add_tail(&data.list, &datalist); - while (len < buflen) { - unsigned int outlen = 0; - /* 10.1.2.5 step 4.1 */ - ret = drbg_kcapi_hash(drbg, drbg->V, &datalist); - if (ret) - return ret; - outlen = (drbg_blocklen(drbg) < (buflen - len)) ? - drbg_blocklen(drbg) : (buflen - len); - - /* 10.1.2.5 step 4.2 */ - memcpy(buf + len, drbg->V, outlen); - len += outlen; - } - - /* 10.1.2.5 step 6 */ - if (addtl && !list_empty(addtl)) - ret = drbg_hmac_update(drbg, addtl, 1); - else - ret = drbg_hmac_update(drbg, NULL, 1); - if (ret) - return ret; - - return len; -} - -static const struct drbg_state_ops drbg_hmac_ops = { - .update = drbg_hmac_update, - .generate = drbg_hmac_generate, - .crypto_init = drbg_init_hash_kernel, - .crypto_fini = drbg_fini_hash_kernel, -}; -#endif /* CONFIG_CRYPTO_DRBG_HMAC */ - -/****************************************************************** - * Hash DRBG callback functions - ******************************************************************/ - -#ifdef CONFIG_CRYPTO_DRBG_HASH -#define CRYPTO_DRBG_HASH_STRING "HASH " -MODULE_ALIAS_CRYPTO("drbg_pr_sha512"); -MODULE_ALIAS_CRYPTO("drbg_nopr_sha512"); -MODULE_ALIAS_CRYPTO("drbg_pr_sha384"); -MODULE_ALIAS_CRYPTO("drbg_nopr_sha384"); -MODULE_ALIAS_CRYPTO("drbg_pr_sha256"); -MODULE_ALIAS_CRYPTO("drbg_nopr_sha256"); -MODULE_ALIAS_CRYPTO("drbg_pr_sha1"); -MODULE_ALIAS_CRYPTO("drbg_nopr_sha1"); - -/* - * Increment buffer - * - * @dst buffer to increment - * @add value to add - */ -static inline void drbg_add_buf(unsigned char *dst, size_t dstlen, - const unsigned char *add, size_t addlen) -{ - /* implied: dstlen > addlen */ - unsigned char *dstptr; - const unsigned char *addptr; - unsigned int remainder = 0; - size_t len = addlen; - - dstptr = dst + (dstlen-1); - addptr = add + (addlen-1); - while (len) { - remainder += *dstptr + *addptr; - *dstptr = remainder & 0xff; - remainder >>= 8; - len--; dstptr--; addptr--; - } - len = dstlen - addlen; - while (len && remainder > 0) { - remainder = *dstptr + 1; - *dstptr = remainder & 0xff; - remainder >>= 8; - len--; dstptr--; - } -} - -/* - * scratchpad usage: as drbg_hash_update and drbg_hash_df are used - * interlinked, the scratchpad is used as follows: - * drbg_hash_update - * start: drbg->scratchpad - * length: drbg_statelen(drbg) - * drbg_hash_df: - * start: drbg->scratchpad + drbg_statelen(drbg) - * length: drbg_blocklen(drbg) - * - * drbg_hash_process_addtl uses the scratchpad, but fully completes - * before either of the functions mentioned before are invoked. Therefore, - * drbg_hash_process_addtl does not need to be specifically considered. - */ - -/* Derivation Function for Hash DRBG as defined in 10.4.1 */ -static int drbg_hash_df(struct drbg_state *drbg, - unsigned char *outval, size_t outlen, - struct list_head *entropylist) -{ - int ret = 0; - size_t len = 0; - unsigned char input[5]; - unsigned char *tmp = drbg->scratchpad + drbg_statelen(drbg); - struct drbg_string data; - - /* 10.4.1 step 3 */ - input[0] = 1; - drbg_cpu_to_be32((outlen * 8), &input[1]); - - /* 10.4.1 step 4.1 -- concatenation of data for input into hash */ - drbg_string_fill(&data, input, 5); - list_add(&data.list, entropylist); - - /* 10.4.1 step 4 */ - while (len < outlen) { - short blocklen = 0; - /* 10.4.1 step 4.1 */ - ret = drbg_kcapi_hash(drbg, tmp, entropylist); - if (ret) - goto out; - /* 10.4.1 step 4.2 */ - input[0]++; - blocklen = (drbg_blocklen(drbg) < (outlen - len)) ? - drbg_blocklen(drbg) : (outlen - len); - memcpy(outval + len, tmp, blocklen); - len += blocklen; - } - -out: - memset(tmp, 0, drbg_blocklen(drbg)); - return ret; -} - -/* update function for Hash DRBG as defined in 10.1.1.2 / 10.1.1.3 */ -static int drbg_hash_update(struct drbg_state *drbg, struct list_head *seed, - int reseed) -{ - int ret = 0; - struct drbg_string data1, data2; - LIST_HEAD(datalist); - LIST_HEAD(datalist2); - unsigned char *V = drbg->scratchpad; - unsigned char prefix = DRBG_PREFIX1; - - if (!seed) - return -EINVAL; - - if (reseed) { - /* 10.1.1.3 step 1 */ - memcpy(V, drbg->V, drbg_statelen(drbg)); - drbg_string_fill(&data1, &prefix, 1); - list_add_tail(&data1.list, &datalist); - drbg_string_fill(&data2, V, drbg_statelen(drbg)); - list_add_tail(&data2.list, &datalist); - } - list_splice_tail(seed, &datalist); - - /* 10.1.1.2 / 10.1.1.3 step 2 and 3 */ - ret = drbg_hash_df(drbg, drbg->V, drbg_statelen(drbg), &datalist); - if (ret) - goto out; - - /* 10.1.1.2 / 10.1.1.3 step 4 */ - prefix = DRBG_PREFIX0; - drbg_string_fill(&data1, &prefix, 1); - list_add_tail(&data1.list, &datalist2); - drbg_string_fill(&data2, drbg->V, drbg_statelen(drbg)); - list_add_tail(&data2.list, &datalist2); - /* 10.1.1.2 / 10.1.1.3 step 4 */ - ret = drbg_hash_df(drbg, drbg->C, drbg_statelen(drbg), &datalist2); - -out: - memset(drbg->scratchpad, 0, drbg_statelen(drbg)); - return ret; -} - -/* processing of additional information string for Hash DRBG */ -static int drbg_hash_process_addtl(struct drbg_state *drbg, - struct list_head *addtl) -{ - int ret = 0; - struct drbg_string data1, data2; - LIST_HEAD(datalist); - unsigned char prefix = DRBG_PREFIX2; - - /* 10.1.1.4 step 2 */ - if (!addtl || list_empty(addtl)) - return 0; - - /* 10.1.1.4 step 2a */ - drbg_string_fill(&data1, &prefix, 1); - drbg_string_fill(&data2, drbg->V, drbg_statelen(drbg)); - list_add_tail(&data1.list, &datalist); - list_add_tail(&data2.list, &datalist); - list_splice_tail(addtl, &datalist); - ret = drbg_kcapi_hash(drbg, drbg->scratchpad, &datalist); - if (ret) - goto out; - - /* 10.1.1.4 step 2b */ - drbg_add_buf(drbg->V, drbg_statelen(drbg), - drbg->scratchpad, drbg_blocklen(drbg)); - -out: - memset(drbg->scratchpad, 0, drbg_blocklen(drbg)); - return ret; -} - -/* Hashgen defined in 10.1.1.4 */ -static int drbg_hash_hashgen(struct drbg_state *drbg, - unsigned char *buf, - unsigned int buflen) -{ - int len = 0; - int ret = 0; - unsigned char *src = drbg->scratchpad; - unsigned char *dst = drbg->scratchpad + drbg_statelen(drbg); - struct drbg_string data; - LIST_HEAD(datalist); - - /* 10.1.1.4 step hashgen 2 */ - memcpy(src, drbg->V, drbg_statelen(drbg)); - - drbg_string_fill(&data, src, drbg_statelen(drbg)); - list_add_tail(&data.list, &datalist); - while (len < buflen) { - unsigned int outlen = 0; - /* 10.1.1.4 step hashgen 4.1 */ - ret = drbg_kcapi_hash(drbg, dst, &datalist); - if (ret) { - len = ret; - goto out; - } - outlen = (drbg_blocklen(drbg) < (buflen - len)) ? - drbg_blocklen(drbg) : (buflen - len); - /* 10.1.1.4 step hashgen 4.2 */ - memcpy(buf + len, dst, outlen); - len += outlen; - /* 10.1.1.4 hashgen step 4.3 */ - if (len < buflen) - crypto_inc(src, drbg_statelen(drbg)); - } - -out: - memset(drbg->scratchpad, 0, - (drbg_statelen(drbg) + drbg_blocklen(drbg))); - return len; -} - -/* generate function for Hash DRBG as defined in 10.1.1.4 */ -static int drbg_hash_generate(struct drbg_state *drbg, - unsigned char *buf, unsigned int buflen, - struct list_head *addtl) -{ - int len = 0; - int ret = 0; - union { - unsigned char req[8]; - __be64 req_int; - } u; - unsigned char prefix = DRBG_PREFIX3; - struct drbg_string data1, data2; - LIST_HEAD(datalist); - - /* 10.1.1.4 step 2 */ - ret = drbg_hash_process_addtl(drbg, addtl); - if (ret) - return ret; - /* 10.1.1.4 step 3 */ - len = drbg_hash_hashgen(drbg, buf, buflen); - - /* this is the value H as documented in 10.1.1.4 */ - /* 10.1.1.4 step 4 */ - drbg_string_fill(&data1, &prefix, 1); - list_add_tail(&data1.list, &datalist); - drbg_string_fill(&data2, drbg->V, drbg_statelen(drbg)); - list_add_tail(&data2.list, &datalist); - ret = drbg_kcapi_hash(drbg, drbg->scratchpad, &datalist); - if (ret) { - len = ret; - goto out; - } - - /* 10.1.1.4 step 5 */ - drbg_add_buf(drbg->V, drbg_statelen(drbg), - drbg->scratchpad, drbg_blocklen(drbg)); - drbg_add_buf(drbg->V, drbg_statelen(drbg), - drbg->C, drbg_statelen(drbg)); - u.req_int = cpu_to_be64(drbg->reseed_ctr); - drbg_add_buf(drbg->V, drbg_statelen(drbg), u.req, 8); - -out: - memset(drbg->scratchpad, 0, drbg_blocklen(drbg)); - return len; -} - -/* - * scratchpad usage: as update and generate are used isolated, both - * can use the scratchpad - */ -static const struct drbg_state_ops drbg_hash_ops = { - .update = drbg_hash_update, - .generate = drbg_hash_generate, - .crypto_init = drbg_init_hash_kernel, - .crypto_fini = drbg_fini_hash_kernel, -}; -#endif /* CONFIG_CRYPTO_DRBG_HASH */ - -/****************************************************************** - * Functions common for DRBG implementations - ******************************************************************/ - -static inline int __drbg_seed(struct drbg_state *drbg, struct list_head *seed, - int reseed) -{ - int ret = drbg->d_ops->update(drbg, seed, reseed); - - if (ret) - return ret; - - drbg->seeded = true; - /* 10.1.1.2 / 10.1.1.3 step 5 */ - drbg->reseed_ctr = 1; - - return ret; -} - -static void drbg_async_seed(struct work_struct *work) -{ - struct drbg_string data; - LIST_HEAD(seedlist); - struct drbg_state *drbg = container_of(work, struct drbg_state, - seed_work); - unsigned int entropylen = drbg_sec_strength(drbg->core->flags); - unsigned char entropy[32]; - - BUG_ON(!entropylen); - BUG_ON(entropylen > sizeof(entropy)); - get_random_bytes(entropy, entropylen); - - drbg_string_fill(&data, entropy, entropylen); - list_add_tail(&data.list, &seedlist); - - mutex_lock(&drbg->drbg_mutex); - - /* If nonblocking pool is initialized, deactivate Jitter RNG */ - crypto_free_rng(drbg->jent); - drbg->jent = NULL; - - /* Set seeded to false so that if __drbg_seed fails the - * next generate call will trigger a reseed. - */ - drbg->seeded = false; - - __drbg_seed(drbg, &seedlist, true); - - if (drbg->seeded) - drbg->reseed_threshold = drbg_max_requests(drbg); - - mutex_unlock(&drbg->drbg_mutex); - - memzero_explicit(entropy, entropylen); -} - -/* - * Seeding or reseeding of the DRBG - * - * @drbg: DRBG state struct - * @pers: personalization / additional information buffer - * @reseed: 0 for initial seed process, 1 for reseeding - * - * return: - * 0 on success - * error value otherwise - */ -static int drbg_seed(struct drbg_state *drbg, struct drbg_string *pers, - bool reseed) -{ - int ret; - unsigned char entropy[((32 + 16) * 2)]; - unsigned int entropylen = drbg_sec_strength(drbg->core->flags); - struct drbg_string data1; - LIST_HEAD(seedlist); - - /* 9.1 / 9.2 / 9.3.1 step 3 */ - if (pers && pers->len > (drbg_max_addtl(drbg))) { - pr_devel("DRBG: personalization string too long %zu\n", - pers->len); - return -EINVAL; - } - - if (list_empty(&drbg->test_data.list)) { - drbg_string_fill(&data1, drbg->test_data.buf, - drbg->test_data.len); - pr_devel("DRBG: using test entropy\n"); - } else { - /* - * Gather entropy equal to the security strength of the DRBG. - * With a derivation function, a nonce is required in addition - * to the entropy. A nonce must be at least 1/2 of the security - * strength of the DRBG in size. Thus, entropy + nonce is 3/2 - * of the strength. The consideration of a nonce is only - * applicable during initial seeding. - */ - BUG_ON(!entropylen); - if (!reseed) - entropylen = ((entropylen + 1) / 2) * 3; - BUG_ON((entropylen * 2) > sizeof(entropy)); - - /* Get seed from in-kernel /dev/urandom */ - get_random_bytes(entropy, entropylen); - - if (!drbg->jent) { - drbg_string_fill(&data1, entropy, entropylen); - pr_devel("DRBG: (re)seeding with %u bytes of entropy\n", - entropylen); - } else { - /* Get seed from Jitter RNG */ - ret = crypto_rng_get_bytes(drbg->jent, - entropy + entropylen, - entropylen); - if (ret) { - pr_devel("DRBG: jent failed with %d\n", ret); - return ret; - } - - drbg_string_fill(&data1, entropy, entropylen * 2); - pr_devel("DRBG: (re)seeding with %u bytes of entropy\n", - entropylen * 2); - } - } - list_add_tail(&data1.list, &seedlist); - - /* - * concatenation of entropy with personalization str / addtl input) - * the variable pers is directly handed in by the caller, so check its - * contents whether it is appropriate - */ - if (pers && pers->buf && 0 < pers->len) { - list_add_tail(&pers->list, &seedlist); - pr_devel("DRBG: using personalization string\n"); - } - - if (!reseed) { - memset(drbg->V, 0, drbg_statelen(drbg)); - memset(drbg->C, 0, drbg_statelen(drbg)); - } - - ret = __drbg_seed(drbg, &seedlist, reseed); - - memzero_explicit(entropy, entropylen * 2); - - return ret; -} - -/* Free all substructures in a DRBG state without the DRBG state structure */ -static inline void drbg_dealloc_state(struct drbg_state *drbg) -{ - if (!drbg) - return; - kzfree(drbg->V); - drbg->Vbuf = NULL; - kzfree(drbg->C); - drbg->Cbuf = NULL; - kzfree(drbg->scratchpadbuf); - drbg->scratchpadbuf = NULL; - drbg->reseed_ctr = 0; - drbg->d_ops = NULL; - drbg->core = NULL; -} - -/* - * Allocate all sub-structures for a DRBG state. - * The DRBG state structure must already be allocated. - */ -static inline int drbg_alloc_state(struct drbg_state *drbg) -{ - int ret = -ENOMEM; - unsigned int sb_size = 0; - - switch (drbg->core->flags & DRBG_TYPE_MASK) { -#ifdef CONFIG_CRYPTO_DRBG_HMAC - case DRBG_HMAC: - drbg->d_ops = &drbg_hmac_ops; - break; -#endif /* CONFIG_CRYPTO_DRBG_HMAC */ -#ifdef CONFIG_CRYPTO_DRBG_HASH - case DRBG_HASH: - drbg->d_ops = &drbg_hash_ops; - break; -#endif /* CONFIG_CRYPTO_DRBG_HASH */ -#ifdef CONFIG_CRYPTO_DRBG_CTR - case DRBG_CTR: - drbg->d_ops = &drbg_ctr_ops; - break; -#endif /* CONFIG_CRYPTO_DRBG_CTR */ - default: - ret = -EOPNOTSUPP; - goto err; - } - - ret = drbg->d_ops->crypto_init(drbg); - if (ret < 0) - goto err; - - drbg->Vbuf = kmalloc(drbg_statelen(drbg) + ret, GFP_KERNEL); - if (!drbg->Vbuf) { - ret = -ENOMEM; - goto fini; - } - drbg->V = PTR_ALIGN(drbg->Vbuf, ret + 1); - drbg->Cbuf = kmalloc(drbg_statelen(drbg) + ret, GFP_KERNEL); - if (!drbg->Cbuf) { - ret = -ENOMEM; - goto fini; - } - drbg->C = PTR_ALIGN(drbg->Cbuf, ret + 1); - /* scratchpad is only generated for CTR and Hash */ - if (drbg->core->flags & DRBG_HMAC) - sb_size = 0; - else if (drbg->core->flags & DRBG_CTR) - sb_size = drbg_statelen(drbg) + drbg_blocklen(drbg) + /* temp */ - drbg_statelen(drbg) + /* df_data */ - drbg_blocklen(drbg) + /* pad */ - drbg_blocklen(drbg) + /* iv */ - drbg_statelen(drbg) + drbg_blocklen(drbg); /* temp */ - else - sb_size = drbg_statelen(drbg) + drbg_blocklen(drbg); - - if (0 < sb_size) { - drbg->scratchpadbuf = kzalloc(sb_size + ret, GFP_KERNEL); - if (!drbg->scratchpadbuf) { - ret = -ENOMEM; - goto fini; - } - drbg->scratchpad = PTR_ALIGN(drbg->scratchpadbuf, ret + 1); - } - - return 0; - -fini: - drbg->d_ops->crypto_fini(drbg); -err: - drbg_dealloc_state(drbg); - return ret; -} - -/************************************************************************* - * DRBG interface functions - *************************************************************************/ - -/* - * DRBG generate function as required by SP800-90A - this function - * generates random numbers - * - * @drbg DRBG state handle - * @buf Buffer where to store the random numbers -- the buffer must already - * be pre-allocated by caller - * @buflen Length of output buffer - this value defines the number of random - * bytes pulled from DRBG - * @addtl Additional input that is mixed into state, may be NULL -- note - * the entropy is pulled by the DRBG internally unconditionally - * as defined in SP800-90A. The additional input is mixed into - * the state in addition to the pulled entropy. - * - * return: 0 when all bytes are generated; < 0 in case of an error - */ -static int drbg_generate(struct drbg_state *drbg, - unsigned char *buf, unsigned int buflen, - struct drbg_string *addtl) -{ - int len = 0; - LIST_HEAD(addtllist); - - if (!drbg->core) { - pr_devel("DRBG: not yet seeded\n"); - return -EINVAL; - } - if (0 == buflen || !buf) { - pr_devel("DRBG: no output buffer provided\n"); - return -EINVAL; - } - if (addtl && NULL == addtl->buf && 0 < addtl->len) { - pr_devel("DRBG: wrong format of additional information\n"); - return -EINVAL; - } - - /* 9.3.1 step 2 */ - len = -EINVAL; - if (buflen > (drbg_max_request_bytes(drbg))) { - pr_devel("DRBG: requested random numbers too large %u\n", - buflen); - goto err; - } - - /* 9.3.1 step 3 is implicit with the chosen DRBG */ - - /* 9.3.1 step 4 */ - if (addtl && addtl->len > (drbg_max_addtl(drbg))) { - pr_devel("DRBG: additional information string too long %zu\n", - addtl->len); - goto err; - } - /* 9.3.1 step 5 is implicit with the chosen DRBG */ - - /* - * 9.3.1 step 6 and 9 supplemented by 9.3.2 step c is implemented - * here. The spec is a bit convoluted here, we make it simpler. - */ - if (drbg->reseed_threshold < drbg->reseed_ctr) - drbg->seeded = false; - - if (drbg->pr || !drbg->seeded) { - pr_devel("DRBG: reseeding before generation (prediction " - "resistance: %s, state %s)\n", - drbg->pr ? "true" : "false", - drbg->seeded ? "seeded" : "unseeded"); - /* 9.3.1 steps 7.1 through 7.3 */ - len = drbg_seed(drbg, addtl, true); - if (len) - goto err; - /* 9.3.1 step 7.4 */ - addtl = NULL; - } - - if (addtl && 0 < addtl->len) - list_add_tail(&addtl->list, &addtllist); - /* 9.3.1 step 8 and 10 */ - len = drbg->d_ops->generate(drbg, buf, buflen, &addtllist); - - /* 10.1.1.4 step 6, 10.1.2.5 step 7, 10.2.1.5.2 step 7 */ - drbg->reseed_ctr++; - if (0 >= len) - goto err; - - /* - * Section 11.3.3 requires to re-perform self tests after some - * generated random numbers. The chosen value after which self - * test is performed is arbitrary, but it should be reasonable. - * However, we do not perform the self tests because of the following - * reasons: it is mathematically impossible that the initial self tests - * were successfully and the following are not. If the initial would - * pass and the following would not, the kernel integrity is violated. - * In this case, the entire kernel operation is questionable and it - * is unlikely that the integrity violation only affects the - * correct operation of the DRBG. - * - * Albeit the following code is commented out, it is provided in - * case somebody has a need to implement the test of 11.3.3. - */ -#if 0 - if (drbg->reseed_ctr && !(drbg->reseed_ctr % 4096)) { - int err = 0; - pr_devel("DRBG: start to perform self test\n"); - if (drbg->core->flags & DRBG_HMAC) - err = alg_test("drbg_pr_hmac_sha256", - "drbg_pr_hmac_sha256", 0, 0); - else if (drbg->core->flags & DRBG_CTR) - err = alg_test("drbg_pr_ctr_aes128", - "drbg_pr_ctr_aes128", 0, 0); - else - err = alg_test("drbg_pr_sha256", - "drbg_pr_sha256", 0, 0); - if (err) { - pr_err("DRBG: periodical self test failed\n"); - /* - * uninstantiate implies that from now on, only errors - * are returned when reusing this DRBG cipher handle - */ - drbg_uninstantiate(drbg); - return 0; - } else { - pr_devel("DRBG: self test successful\n"); - } - } -#endif - - /* - * All operations were successful, return 0 as mandated by - * the kernel crypto API interface. - */ - len = 0; -err: - return len; -} - -/* - * Wrapper around drbg_generate which can pull arbitrary long strings - * from the DRBG without hitting the maximum request limitation. - * - * Parameters: see drbg_generate - * Return codes: see drbg_generate -- if one drbg_generate request fails, - * the entire drbg_generate_long request fails - */ -static int drbg_generate_long(struct drbg_state *drbg, - unsigned char *buf, unsigned int buflen, - struct drbg_string *addtl) -{ - unsigned int len = 0; - unsigned int slice = 0; - do { - int err = 0; - unsigned int chunk = 0; - slice = ((buflen - len) / drbg_max_request_bytes(drbg)); - chunk = slice ? drbg_max_request_bytes(drbg) : (buflen - len); - mutex_lock(&drbg->drbg_mutex); - err = drbg_generate(drbg, buf + len, chunk, addtl); - mutex_unlock(&drbg->drbg_mutex); - if (0 > err) - return err; - len += chunk; - } while (slice > 0 && (len < buflen)); - return 0; -} - -static void drbg_schedule_async_seed(struct random_ready_callback *rdy) -{ - struct drbg_state *drbg = container_of(rdy, struct drbg_state, - random_ready); - - schedule_work(&drbg->seed_work); -} - -static int drbg_prepare_hrng(struct drbg_state *drbg) -{ - int err; - - /* We do not need an HRNG in test mode. */ - if (list_empty(&drbg->test_data.list)) - return 0; - - INIT_WORK(&drbg->seed_work, drbg_async_seed); - - drbg->random_ready.owner = THIS_MODULE; - drbg->random_ready.func = drbg_schedule_async_seed; - - err = add_random_ready_callback(&drbg->random_ready); - - switch (err) { - case 0: - break; - - case -EALREADY: - err = 0; - /* fall through */ - - default: - drbg->random_ready.func = NULL; - return err; - } - - drbg->jent = crypto_alloc_rng("jitterentropy_rng", 0, 0); - - /* - * Require frequent reseeds until the seed source is fully - * initialized. - */ - drbg->reseed_threshold = 50; - - return err; -} - -/* - * DRBG instantiation function as required by SP800-90A - this function - * sets up the DRBG handle, performs the initial seeding and all sanity - * checks required by SP800-90A - * - * @drbg memory of state -- if NULL, new memory is allocated - * @pers Personalization string that is mixed into state, may be NULL -- note - * the entropy is pulled by the DRBG internally unconditionally - * as defined in SP800-90A. The additional input is mixed into - * the state in addition to the pulled entropy. - * @coreref reference to core - * @pr prediction resistance enabled - * - * return - * 0 on success - * error value otherwise - */ -static int drbg_instantiate(struct drbg_state *drbg, struct drbg_string *pers, - int coreref, bool pr) -{ - int ret; - bool reseed = true; - - pr_devel("DRBG: Initializing DRBG core %d with prediction resistance " - "%s\n", coreref, pr ? "enabled" : "disabled"); - mutex_lock(&drbg->drbg_mutex); - - /* 9.1 step 1 is implicit with the selected DRBG type */ - - /* - * 9.1 step 2 is implicit as caller can select prediction resistance - * and the flag is copied into drbg->flags -- - * all DRBG types support prediction resistance - */ - - /* 9.1 step 4 is implicit in drbg_sec_strength */ - - if (!drbg->core) { - drbg->core = &drbg_cores[coreref]; - drbg->pr = pr; - drbg->seeded = false; - drbg->reseed_threshold = drbg_max_requests(drbg); - - ret = drbg_alloc_state(drbg); - if (ret) - goto unlock; - - ret = drbg_prepare_hrng(drbg); - if (ret) - goto free_everything; - - if (IS_ERR(drbg->jent)) { - ret = PTR_ERR(drbg->jent); - drbg->jent = NULL; - if (fips_enabled || ret != -ENOENT) - goto free_everything; - pr_info("DRBG: Continuing without Jitter RNG\n"); - } - - reseed = false; - } - - ret = drbg_seed(drbg, pers, reseed); - - if (ret && !reseed) - goto free_everything; - - mutex_unlock(&drbg->drbg_mutex); - return ret; - -unlock: - mutex_unlock(&drbg->drbg_mutex); - return ret; - -free_everything: - mutex_unlock(&drbg->drbg_mutex); - drbg_uninstantiate(drbg); - return ret; -} - -/* - * DRBG uninstantiate function as required by SP800-90A - this function - * frees all buffers and the DRBG handle - * - * @drbg DRBG state handle - * - * return - * 0 on success - */ -static int drbg_uninstantiate(struct drbg_state *drbg) -{ - if (drbg->random_ready.func) { - del_random_ready_callback(&drbg->random_ready); - cancel_work_sync(&drbg->seed_work); - crypto_free_rng(drbg->jent); - drbg->jent = NULL; - } - - if (drbg->d_ops) - drbg->d_ops->crypto_fini(drbg); - drbg_dealloc_state(drbg); - /* no scrubbing of test_data -- this shall survive an uninstantiate */ - return 0; -} - -/* - * Helper function for setting the test data in the DRBG - * - * @drbg DRBG state handle - * @data test data - * @len test data length - */ -static void drbg_kcapi_set_entropy(struct crypto_rng *tfm, - const u8 *data, unsigned int len) -{ - struct drbg_state *drbg = crypto_rng_ctx(tfm); - - mutex_lock(&drbg->drbg_mutex); - drbg_string_fill(&drbg->test_data, data, len); - mutex_unlock(&drbg->drbg_mutex); -} - -/*************************************************************** - * Kernel crypto API cipher invocations requested by DRBG - ***************************************************************/ - -#if defined(CONFIG_CRYPTO_DRBG_HASH) || defined(CONFIG_CRYPTO_DRBG_HMAC) -struct sdesc { - struct shash_desc shash; - char ctx[]; -}; - -static int drbg_init_hash_kernel(struct drbg_state *drbg) -{ - struct sdesc *sdesc; - struct crypto_shash *tfm; - - tfm = crypto_alloc_shash(drbg->core->backend_cra_name, 0, 0); - if (IS_ERR(tfm)) { - pr_info("DRBG: could not allocate digest TFM handle: %s\n", - drbg->core->backend_cra_name); - return PTR_ERR(tfm); - } - BUG_ON(drbg_blocklen(drbg) != crypto_shash_digestsize(tfm)); - sdesc = kzalloc(sizeof(struct shash_desc) + crypto_shash_descsize(tfm), - GFP_KERNEL); - if (!sdesc) { - crypto_free_shash(tfm); - return -ENOMEM; - } - - sdesc->shash.tfm = tfm; - sdesc->shash.flags = 0; - drbg->priv_data = sdesc; - - return crypto_shash_alignmask(tfm); -} - -static int drbg_fini_hash_kernel(struct drbg_state *drbg) -{ - struct sdesc *sdesc = (struct sdesc *)drbg->priv_data; - if (sdesc) { - crypto_free_shash(sdesc->shash.tfm); - kzfree(sdesc); - } - drbg->priv_data = NULL; - return 0; -} - -static void drbg_kcapi_hmacsetkey(struct drbg_state *drbg, - const unsigned char *key) -{ - struct sdesc *sdesc = (struct sdesc *)drbg->priv_data; - - crypto_shash_setkey(sdesc->shash.tfm, key, drbg_statelen(drbg)); -} - -static int drbg_kcapi_hash(struct drbg_state *drbg, unsigned char *outval, - const struct list_head *in) -{ - struct sdesc *sdesc = (struct sdesc *)drbg->priv_data; - struct drbg_string *input = NULL; - - crypto_shash_init(&sdesc->shash); - list_for_each_entry(input, in, list) - crypto_shash_update(&sdesc->shash, input->buf, input->len); - return crypto_shash_final(&sdesc->shash, outval); -} -#endif /* (CONFIG_CRYPTO_DRBG_HASH || CONFIG_CRYPTO_DRBG_HMAC) */ - -#ifdef CONFIG_CRYPTO_DRBG_CTR -static int drbg_fini_sym_kernel(struct drbg_state *drbg) -{ - struct crypto_cipher *tfm = - (struct crypto_cipher *)drbg->priv_data; - if (tfm) - crypto_free_cipher(tfm); - drbg->priv_data = NULL; - - if (drbg->ctr_handle) - crypto_free_skcipher(drbg->ctr_handle); - drbg->ctr_handle = NULL; - - if (drbg->ctr_req) - skcipher_request_free(drbg->ctr_req); - drbg->ctr_req = NULL; - - kfree(drbg->ctr_null_value_buf); - drbg->ctr_null_value = NULL; - - kfree(drbg->outscratchpadbuf); - drbg->outscratchpadbuf = NULL; - - return 0; -} - -static void drbg_skcipher_cb(struct crypto_async_request *req, int error) -{ - struct drbg_state *drbg = req->data; - - if (error == -EINPROGRESS) - return; - drbg->ctr_async_err = error; - complete(&drbg->ctr_completion); -} - -static int drbg_init_sym_kernel(struct drbg_state *drbg) -{ - struct crypto_cipher *tfm; - struct crypto_skcipher *sk_tfm; - struct skcipher_request *req; - unsigned int alignmask; - char ctr_name[CRYPTO_MAX_ALG_NAME]; - - tfm = crypto_alloc_cipher(drbg->core->backend_cra_name, 0, 0); - if (IS_ERR(tfm)) { - pr_info("DRBG: could not allocate cipher TFM handle: %s\n", - drbg->core->backend_cra_name); - return PTR_ERR(tfm); - } - BUG_ON(drbg_blocklen(drbg) != crypto_cipher_blocksize(tfm)); - drbg->priv_data = tfm; - - if (snprintf(ctr_name, CRYPTO_MAX_ALG_NAME, "ctr(%s)", - drbg->core->backend_cra_name) >= CRYPTO_MAX_ALG_NAME) { - drbg_fini_sym_kernel(drbg); - return -EINVAL; - } - sk_tfm = crypto_alloc_skcipher(ctr_name, 0, 0); - if (IS_ERR(sk_tfm)) { - pr_info("DRBG: could not allocate CTR cipher TFM handle: %s\n", - ctr_name); - drbg_fini_sym_kernel(drbg); - return PTR_ERR(sk_tfm); - } - drbg->ctr_handle = sk_tfm; - - req = skcipher_request_alloc(sk_tfm, GFP_KERNEL); - if (!req) { - pr_info("DRBG: could not allocate request queue\n"); - drbg_fini_sym_kernel(drbg); - return -ENOMEM; - } - drbg->ctr_req = req; - skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, - drbg_skcipher_cb, drbg); - - alignmask = crypto_skcipher_alignmask(sk_tfm); - drbg->ctr_null_value_buf = kzalloc(DRBG_CTR_NULL_LEN + alignmask, - GFP_KERNEL); - if (!drbg->ctr_null_value_buf) { - drbg_fini_sym_kernel(drbg); - return -ENOMEM; - } - drbg->ctr_null_value = (u8 *)PTR_ALIGN(drbg->ctr_null_value_buf, - alignmask + 1); - - drbg->outscratchpadbuf = kmalloc(DRBG_OUTSCRATCHLEN + alignmask, - GFP_KERNEL); - if (!drbg->outscratchpadbuf) { - drbg_fini_sym_kernel(drbg); - return -ENOMEM; - } - drbg->outscratchpad = (u8 *)PTR_ALIGN(drbg->outscratchpadbuf, - alignmask + 1); - - return alignmask; -} - -static void drbg_kcapi_symsetkey(struct drbg_state *drbg, - const unsigned char *key) -{ - struct crypto_cipher *tfm = - (struct crypto_cipher *)drbg->priv_data; - - crypto_cipher_setkey(tfm, key, (drbg_keylen(drbg))); -} - -static int drbg_kcapi_sym(struct drbg_state *drbg, unsigned char *outval, - const struct drbg_string *in) -{ - struct crypto_cipher *tfm = - (struct crypto_cipher *)drbg->priv_data; - - /* there is only component in *in */ - BUG_ON(in->len < drbg_blocklen(drbg)); - crypto_cipher_encrypt_one(tfm, outval, in->buf); - return 0; -} - -static int drbg_kcapi_sym_ctr(struct drbg_state *drbg, - u8 *inbuf, u32 inlen, - u8 *outbuf, u32 outlen) -{ - struct scatterlist sg_in; - int ret; - - sg_init_one(&sg_in, inbuf, inlen); - - while (outlen) { - u32 cryptlen = min3(inlen, outlen, (u32)DRBG_OUTSCRATCHLEN); - struct scatterlist sg_out; - - /* Output buffer may not be valid for SGL, use scratchpad */ - sg_init_one(&sg_out, drbg->outscratchpad, cryptlen); - skcipher_request_set_crypt(drbg->ctr_req, &sg_in, &sg_out, - cryptlen, drbg->V); - ret = crypto_skcipher_encrypt(drbg->ctr_req); - switch (ret) { - case 0: - break; - case -EINPROGRESS: - case -EBUSY: - ret = wait_for_completion_interruptible( - &drbg->ctr_completion); - if (!ret && !drbg->ctr_async_err) { - reinit_completion(&drbg->ctr_completion); - break; - } - default: - goto out; - } - init_completion(&drbg->ctr_completion); - - memcpy(outbuf, drbg->outscratchpad, cryptlen); - - outlen -= cryptlen; - } - ret = 0; - -out: - memzero_explicit(drbg->outscratchpad, DRBG_OUTSCRATCHLEN); - return ret; -} -#endif /* CONFIG_CRYPTO_DRBG_CTR */ - -/*************************************************************** - * Kernel crypto API interface to register DRBG - ***************************************************************/ - -/* - * Look up the DRBG flags by given kernel crypto API cra_name - * The code uses the drbg_cores definition to do this - * - * @cra_name kernel crypto API cra_name - * @coreref reference to integer which is filled with the pointer to - * the applicable core - * @pr reference for setting prediction resistance - * - * return: flags - */ -static inline void drbg_convert_tfm_core(const char *cra_driver_name, - int *coreref, bool *pr) -{ - int i = 0; - size_t start = 0; - int len = 0; - - *pr = true; - /* disassemble the names */ - if (!memcmp(cra_driver_name, "drbg_nopr_", 10)) { - start = 10; - *pr = false; - } else if (!memcmp(cra_driver_name, "drbg_pr_", 8)) { - start = 8; - } else { - return; - } - - /* remove the first part */ - len = strlen(cra_driver_name) - start; - for (i = 0; ARRAY_SIZE(drbg_cores) > i; i++) { - if (!memcmp(cra_driver_name + start, drbg_cores[i].cra_name, - len)) { - *coreref = i; - return; - } - } -} - -static int drbg_kcapi_init(struct crypto_tfm *tfm) -{ - struct drbg_state *drbg = crypto_tfm_ctx(tfm); - - mutex_init(&drbg->drbg_mutex); - - return 0; -} - -static void drbg_kcapi_cleanup(struct crypto_tfm *tfm) -{ - drbg_uninstantiate(crypto_tfm_ctx(tfm)); -} - -/* - * Generate random numbers invoked by the kernel crypto API: - * The API of the kernel crypto API is extended as follows: - * - * src is additional input supplied to the RNG. - * slen is the length of src. - * dst is the output buffer where random data is to be stored. - * dlen is the length of dst. - */ -static int drbg_kcapi_random(struct crypto_rng *tfm, - const u8 *src, unsigned int slen, - u8 *dst, unsigned int dlen) -{ - struct drbg_state *drbg = crypto_rng_ctx(tfm); - struct drbg_string *addtl = NULL; - struct drbg_string string; - - if (slen) { - /* linked list variable is now local to allow modification */ - drbg_string_fill(&string, src, slen); - addtl = &string; - } - - return drbg_generate_long(drbg, dst, dlen, addtl); -} - -/* - * Seed the DRBG invoked by the kernel crypto API - */ -static int drbg_kcapi_seed(struct crypto_rng *tfm, - const u8 *seed, unsigned int slen) -{ - struct drbg_state *drbg = crypto_rng_ctx(tfm); - struct crypto_tfm *tfm_base = crypto_rng_tfm(tfm); - bool pr = false; - struct drbg_string string; - struct drbg_string *seed_string = NULL; - int coreref = 0; - - drbg_convert_tfm_core(crypto_tfm_alg_driver_name(tfm_base), &coreref, - &pr); - if (0 < slen) { - drbg_string_fill(&string, seed, slen); - seed_string = &string; - } - - return drbg_instantiate(drbg, seed_string, coreref, pr); -} - -/*************************************************************** - * Kernel module: code to load the module - ***************************************************************/ - -/* - * Tests as defined in 11.3.2 in addition to the cipher tests: testing - * of the error handling. - * - * Note: testing of failing seed source as defined in 11.3.2 is not applicable - * as seed source of get_random_bytes does not fail. - * - * Note 2: There is no sensible way of testing the reseed counter - * enforcement, so skip it. - */ -static inline int __init drbg_healthcheck_sanity(void) -{ - int len = 0; -#define OUTBUFLEN 16 - unsigned char buf[OUTBUFLEN]; - struct drbg_state *drbg = NULL; - int ret = -EFAULT; - int rc = -EFAULT; - bool pr = false; - int coreref = 0; - struct drbg_string addtl; - size_t max_addtllen, max_request_bytes; - - /* only perform test in FIPS mode */ - if (!fips_enabled) - return 0; - -#ifdef CONFIG_CRYPTO_DRBG_CTR - drbg_convert_tfm_core("drbg_nopr_ctr_aes128", &coreref, &pr); -#elif defined CONFIG_CRYPTO_DRBG_HASH - drbg_convert_tfm_core("drbg_nopr_sha256", &coreref, &pr); -#else - drbg_convert_tfm_core("drbg_nopr_hmac_sha256", &coreref, &pr); -#endif - - drbg = kzalloc(sizeof(struct drbg_state), GFP_KERNEL); - if (!drbg) - return -ENOMEM; - - mutex_init(&drbg->drbg_mutex); - drbg->core = &drbg_cores[coreref]; - drbg->reseed_threshold = drbg_max_requests(drbg); - - /* - * if the following tests fail, it is likely that there is a buffer - * overflow as buf is much smaller than the requested or provided - * string lengths -- in case the error handling does not succeed - * we may get an OOPS. And we want to get an OOPS as this is a - * grave bug. - */ - - max_addtllen = drbg_max_addtl(drbg); - max_request_bytes = drbg_max_request_bytes(drbg); - drbg_string_fill(&addtl, buf, max_addtllen + 1); - /* overflow addtllen with additonal info string */ - len = drbg_generate(drbg, buf, OUTBUFLEN, &addtl); - BUG_ON(0 < len); - /* overflow max_bits */ - len = drbg_generate(drbg, buf, (max_request_bytes + 1), NULL); - BUG_ON(0 < len); - - /* overflow max addtllen with personalization string */ - ret = drbg_seed(drbg, &addtl, false); - BUG_ON(0 == ret); - /* all tests passed */ - rc = 0; - - pr_devel("DRBG: Sanity tests for failure code paths successfully " - "completed\n"); - - kfree(drbg); - return rc; -} - -static struct rng_alg drbg_algs[22]; - -/* - * Fill the array drbg_algs used to register the different DRBGs - * with the kernel crypto API. To fill the array, the information - * from drbg_cores[] is used. - */ -static inline void __init drbg_fill_array(struct rng_alg *alg, - const struct drbg_core *core, int pr) -{ - int pos = 0; - static int priority = 200; - - memcpy(alg->base.cra_name, "stdrng", 6); - if (pr) { - memcpy(alg->base.cra_driver_name, "drbg_pr_", 8); - pos = 8; - } else { - memcpy(alg->base.cra_driver_name, "drbg_nopr_", 10); - pos = 10; - } - memcpy(alg->base.cra_driver_name + pos, core->cra_name, - strlen(core->cra_name)); - - alg->base.cra_priority = priority; - priority++; - /* - * If FIPS mode enabled, the selected DRBG shall have the - * highest cra_priority over other stdrng instances to ensure - * it is selected. - */ - if (fips_enabled) - alg->base.cra_priority += 200; - - alg->base.cra_ctxsize = sizeof(struct drbg_state); - alg->base.cra_module = THIS_MODULE; - alg->base.cra_init = drbg_kcapi_init; - alg->base.cra_exit = drbg_kcapi_cleanup; - alg->generate = drbg_kcapi_random; - alg->seed = drbg_kcapi_seed; - alg->set_ent = drbg_kcapi_set_entropy; - alg->seedsize = 0; -} - -static int __init drbg_init(void) -{ - unsigned int i = 0; /* pointer to drbg_algs */ - unsigned int j = 0; /* pointer to drbg_cores */ - int ret; - - ret = drbg_healthcheck_sanity(); - if (ret) - return ret; - - if (ARRAY_SIZE(drbg_cores) * 2 > ARRAY_SIZE(drbg_algs)) { - pr_info("DRBG: Cannot register all DRBG types" - "(slots needed: %zu, slots available: %zu)\n", - ARRAY_SIZE(drbg_cores) * 2, ARRAY_SIZE(drbg_algs)); - return -EFAULT; - } - - /* - * each DRBG definition can be used with PR and without PR, thus - * we instantiate each DRBG in drbg_cores[] twice. - * - * As the order of placing them into the drbg_algs array matters - * (the later DRBGs receive a higher cra_priority) we register the - * prediction resistance DRBGs first as the should not be too - * interesting. - */ - for (j = 0; ARRAY_SIZE(drbg_cores) > j; j++, i++) - drbg_fill_array(&drbg_algs[i], &drbg_cores[j], 1); - for (j = 0; ARRAY_SIZE(drbg_cores) > j; j++, i++) - drbg_fill_array(&drbg_algs[i], &drbg_cores[j], 0); - return crypto_register_rngs(drbg_algs, (ARRAY_SIZE(drbg_cores) * 2)); -} - -static void __exit drbg_exit(void) -{ - crypto_unregister_rngs(drbg_algs, (ARRAY_SIZE(drbg_cores) * 2)); -} - -module_init(drbg_init); -module_exit(drbg_exit); -#ifndef CRYPTO_DRBG_HASH_STRING -#define CRYPTO_DRBG_HASH_STRING "" -#endif -#ifndef CRYPTO_DRBG_HMAC_STRING -#define CRYPTO_DRBG_HMAC_STRING "" -#endif -#ifndef CRYPTO_DRBG_CTR_STRING -#define CRYPTO_DRBG_CTR_STRING "" -#endif -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Stephan Mueller "); -MODULE_DESCRIPTION("NIST SP800-90A Deterministic Random Bit Generator (DRBG) " - "using following cores: " - CRYPTO_DRBG_HASH_STRING - CRYPTO_DRBG_HMAC_STRING - CRYPTO_DRBG_CTR_STRING); -MODULE_ALIAS_CRYPTO("stdrng"); diff --git a/src/linux/crypto/echainiv.c b/src/linux/crypto/echainiv.c deleted file mode 100644 index e3d889b..0000000 --- a/src/linux/crypto/echainiv.c +++ /dev/null @@ -1,187 +0,0 @@ -/* - * echainiv: Encrypted Chain IV Generator - * - * This generator generates an IV based on a sequence number by multiplying - * it with a salt and then encrypting it with the same key as used to encrypt - * the plain text. This algorithm requires that the block size be equal - * to the IV size. It is mainly useful for CBC. - * - * This generator can only be used by algorithms where authentication - * is performed after encryption (i.e., authenc). - * - * Copyright (c) 2015 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int echainiv_encrypt(struct aead_request *req) -{ - struct crypto_aead *geniv = crypto_aead_reqtfm(req); - struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv); - struct aead_request *subreq = aead_request_ctx(req); - __be64 nseqno; - u64 seqno; - u8 *info; - unsigned int ivsize = crypto_aead_ivsize(geniv); - int err; - - if (req->cryptlen < ivsize) - return -EINVAL; - - aead_request_set_tfm(subreq, ctx->child); - - info = req->iv; - - if (req->src != req->dst) { - SKCIPHER_REQUEST_ON_STACK(nreq, ctx->sknull); - - skcipher_request_set_tfm(nreq, ctx->sknull); - skcipher_request_set_callback(nreq, req->base.flags, - NULL, NULL); - skcipher_request_set_crypt(nreq, req->src, req->dst, - req->assoclen + req->cryptlen, - NULL); - - err = crypto_skcipher_encrypt(nreq); - if (err) - return err; - } - - aead_request_set_callback(subreq, req->base.flags, - req->base.complete, req->base.data); - aead_request_set_crypt(subreq, req->dst, req->dst, - req->cryptlen, info); - aead_request_set_ad(subreq, req->assoclen); - - memcpy(&nseqno, info + ivsize - 8, 8); - seqno = be64_to_cpu(nseqno); - memset(info, 0, ivsize); - - scatterwalk_map_and_copy(info, req->dst, req->assoclen, ivsize, 1); - - do { - u64 a; - - memcpy(&a, ctx->salt + ivsize - 8, 8); - - a |= 1; - a *= seqno; - - memcpy(info + ivsize - 8, &a, 8); - } while ((ivsize -= 8)); - - return crypto_aead_encrypt(subreq); -} - -static int echainiv_decrypt(struct aead_request *req) -{ - struct crypto_aead *geniv = crypto_aead_reqtfm(req); - struct aead_geniv_ctx *ctx = crypto_aead_ctx(geniv); - struct aead_request *subreq = aead_request_ctx(req); - crypto_completion_t compl; - void *data; - unsigned int ivsize = crypto_aead_ivsize(geniv); - - if (req->cryptlen < ivsize) - return -EINVAL; - - aead_request_set_tfm(subreq, ctx->child); - - compl = req->base.complete; - data = req->base.data; - - aead_request_set_callback(subreq, req->base.flags, compl, data); - aead_request_set_crypt(subreq, req->src, req->dst, - req->cryptlen - ivsize, req->iv); - aead_request_set_ad(subreq, req->assoclen + ivsize); - - scatterwalk_map_and_copy(req->iv, req->src, req->assoclen, ivsize, 0); - - return crypto_aead_decrypt(subreq); -} - -static int echainiv_aead_create(struct crypto_template *tmpl, - struct rtattr **tb) -{ - struct aead_instance *inst; - struct crypto_aead_spawn *spawn; - struct aead_alg *alg; - int err; - - inst = aead_geniv_alloc(tmpl, tb, 0, 0); - - if (IS_ERR(inst)) - return PTR_ERR(inst); - - spawn = aead_instance_ctx(inst); - alg = crypto_spawn_aead_alg(spawn); - - err = -EINVAL; - if (inst->alg.ivsize & (sizeof(u64) - 1) || !inst->alg.ivsize) - goto free_inst; - - inst->alg.encrypt = echainiv_encrypt; - inst->alg.decrypt = echainiv_decrypt; - - inst->alg.init = aead_init_geniv; - inst->alg.exit = aead_exit_geniv; - - inst->alg.base.cra_ctxsize = sizeof(struct aead_geniv_ctx); - inst->alg.base.cra_ctxsize += inst->alg.ivsize; - - inst->free = aead_geniv_free; - - err = aead_register_instance(tmpl, inst); - if (err) - goto free_inst; - -out: - return err; - -free_inst: - aead_geniv_free(inst); - goto out; -} - -static void echainiv_free(struct crypto_instance *inst) -{ - aead_geniv_free(aead_instance(inst)); -} - -static struct crypto_template echainiv_tmpl = { - .name = "echainiv", - .create = echainiv_aead_create, - .free = echainiv_free, - .module = THIS_MODULE, -}; - -static int __init echainiv_module_init(void) -{ - return crypto_register_template(&echainiv_tmpl); -} - -static void __exit echainiv_module_exit(void) -{ - crypto_unregister_template(&echainiv_tmpl); -} - -module_init(echainiv_module_init); -module_exit(echainiv_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Encrypted Chain IV Generator"); -MODULE_ALIAS_CRYPTO("echainiv"); diff --git a/src/linux/crypto/hmac.c b/src/linux/crypto/hmac.c deleted file mode 100644 index 72e38c0..0000000 --- a/src/linux/crypto/hmac.c +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Cryptographic API. - * - * HMAC: Keyed-Hashing for Message Authentication (RFC2104). - * - * Copyright (c) 2002 James Morris - * Copyright (c) 2006 Herbert Xu - * - * The HMAC implementation is derived from USAGI. - * Copyright (c) 2002 Kazunori Miyazawa / USAGI - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -struct hmac_ctx { - struct crypto_shash *hash; -}; - -static inline void *align_ptr(void *p, unsigned int align) -{ - return (void *)ALIGN((unsigned long)p, align); -} - -static inline struct hmac_ctx *hmac_ctx(struct crypto_shash *tfm) -{ - return align_ptr(crypto_shash_ctx_aligned(tfm) + - crypto_shash_statesize(tfm) * 2, - crypto_tfm_ctx_alignment()); -} - -static int hmac_setkey(struct crypto_shash *parent, - const u8 *inkey, unsigned int keylen) -{ - int bs = crypto_shash_blocksize(parent); - int ds = crypto_shash_digestsize(parent); - int ss = crypto_shash_statesize(parent); - char *ipad = crypto_shash_ctx_aligned(parent); - char *opad = ipad + ss; - struct hmac_ctx *ctx = align_ptr(opad + ss, - crypto_tfm_ctx_alignment()); - struct crypto_shash *hash = ctx->hash; - SHASH_DESC_ON_STACK(shash, hash); - unsigned int i; - - shash->tfm = hash; - shash->flags = crypto_shash_get_flags(parent) - & CRYPTO_TFM_REQ_MAY_SLEEP; - - if (keylen > bs) { - int err; - - err = crypto_shash_digest(shash, inkey, keylen, ipad); - if (err) - return err; - - keylen = ds; - } else - memcpy(ipad, inkey, keylen); - - memset(ipad + keylen, 0, bs - keylen); - memcpy(opad, ipad, bs); - - for (i = 0; i < bs; i++) { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - - return crypto_shash_init(shash) ?: - crypto_shash_update(shash, ipad, bs) ?: - crypto_shash_export(shash, ipad) ?: - crypto_shash_init(shash) ?: - crypto_shash_update(shash, opad, bs) ?: - crypto_shash_export(shash, opad); -} - -static int hmac_export(struct shash_desc *pdesc, void *out) -{ - struct shash_desc *desc = shash_desc_ctx(pdesc); - - desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; - - return crypto_shash_export(desc, out); -} - -static int hmac_import(struct shash_desc *pdesc, const void *in) -{ - struct shash_desc *desc = shash_desc_ctx(pdesc); - struct hmac_ctx *ctx = hmac_ctx(pdesc->tfm); - - desc->tfm = ctx->hash; - desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; - - return crypto_shash_import(desc, in); -} - -static int hmac_init(struct shash_desc *pdesc) -{ - return hmac_import(pdesc, crypto_shash_ctx_aligned(pdesc->tfm)); -} - -static int hmac_update(struct shash_desc *pdesc, - const u8 *data, unsigned int nbytes) -{ - struct shash_desc *desc = shash_desc_ctx(pdesc); - - desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; - - return crypto_shash_update(desc, data, nbytes); -} - -static int hmac_final(struct shash_desc *pdesc, u8 *out) -{ - struct crypto_shash *parent = pdesc->tfm; - int ds = crypto_shash_digestsize(parent); - int ss = crypto_shash_statesize(parent); - char *opad = crypto_shash_ctx_aligned(parent) + ss; - struct shash_desc *desc = shash_desc_ctx(pdesc); - - desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; - - return crypto_shash_final(desc, out) ?: - crypto_shash_import(desc, opad) ?: - crypto_shash_finup(desc, out, ds, out); -} - -static int hmac_finup(struct shash_desc *pdesc, const u8 *data, - unsigned int nbytes, u8 *out) -{ - - struct crypto_shash *parent = pdesc->tfm; - int ds = crypto_shash_digestsize(parent); - int ss = crypto_shash_statesize(parent); - char *opad = crypto_shash_ctx_aligned(parent) + ss; - struct shash_desc *desc = shash_desc_ctx(pdesc); - - desc->flags = pdesc->flags & CRYPTO_TFM_REQ_MAY_SLEEP; - - return crypto_shash_finup(desc, data, nbytes, out) ?: - crypto_shash_import(desc, opad) ?: - crypto_shash_finup(desc, out, ds, out); -} - -static int hmac_init_tfm(struct crypto_tfm *tfm) -{ - struct crypto_shash *parent = __crypto_shash_cast(tfm); - struct crypto_shash *hash; - struct crypto_instance *inst = (void *)tfm->__crt_alg; - struct crypto_shash_spawn *spawn = crypto_instance_ctx(inst); - struct hmac_ctx *ctx = hmac_ctx(parent); - - hash = crypto_spawn_shash(spawn); - if (IS_ERR(hash)) - return PTR_ERR(hash); - - parent->descsize = sizeof(struct shash_desc) + - crypto_shash_descsize(hash); - - ctx->hash = hash; - return 0; -} - -static void hmac_exit_tfm(struct crypto_tfm *tfm) -{ - struct hmac_ctx *ctx = hmac_ctx(__crypto_shash_cast(tfm)); - crypto_free_shash(ctx->hash); -} - -static int hmac_create(struct crypto_template *tmpl, struct rtattr **tb) -{ - struct shash_instance *inst; - struct crypto_alg *alg; - struct shash_alg *salg; - int err; - int ds; - int ss; - - err = crypto_check_attr_type(tb, CRYPTO_ALG_TYPE_SHASH); - if (err) - return err; - - salg = shash_attr_alg(tb[1], 0, 0); - if (IS_ERR(salg)) - return PTR_ERR(salg); - - err = -EINVAL; - ds = salg->digestsize; - ss = salg->statesize; - alg = &salg->base; - if (ds > alg->cra_blocksize || - ss < alg->cra_blocksize) - goto out_put_alg; - - inst = shash_alloc_instance("hmac", alg); - err = PTR_ERR(inst); - if (IS_ERR(inst)) - goto out_put_alg; - - err = crypto_init_shash_spawn(shash_instance_ctx(inst), salg, - shash_crypto_instance(inst)); - if (err) - goto out_free_inst; - - inst->alg.base.cra_priority = alg->cra_priority; - inst->alg.base.cra_blocksize = alg->cra_blocksize; - inst->alg.base.cra_alignmask = alg->cra_alignmask; - - ss = ALIGN(ss, alg->cra_alignmask + 1); - inst->alg.digestsize = ds; - inst->alg.statesize = ss; - - inst->alg.base.cra_ctxsize = sizeof(struct hmac_ctx) + - ALIGN(ss * 2, crypto_tfm_ctx_alignment()); - - inst->alg.base.cra_init = hmac_init_tfm; - inst->alg.base.cra_exit = hmac_exit_tfm; - - inst->alg.init = hmac_init; - inst->alg.update = hmac_update; - inst->alg.final = hmac_final; - inst->alg.finup = hmac_finup; - inst->alg.export = hmac_export; - inst->alg.import = hmac_import; - inst->alg.setkey = hmac_setkey; - - err = shash_register_instance(tmpl, inst); - if (err) { -out_free_inst: - shash_free_instance(shash_crypto_instance(inst)); - } - -out_put_alg: - crypto_mod_put(alg); - return err; -} - -static struct crypto_template hmac_tmpl = { - .name = "hmac", - .create = hmac_create, - .free = shash_free_instance, - .module = THIS_MODULE, -}; - -static int __init hmac_module_init(void) -{ - return crypto_register_template(&hmac_tmpl); -} - -static void __exit hmac_module_exit(void) -{ - crypto_unregister_template(&hmac_tmpl); -} - -module_init(hmac_module_init); -module_exit(hmac_module_exit); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("HMAC hash algorithm"); -MODULE_ALIAS_CRYPTO("hmac"); diff --git a/src/linux/crypto/internal.h b/src/linux/crypto/internal.h deleted file mode 100644 index 7eefcdb..0000000 --- a/src/linux/crypto/internal.h +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Cryptographic API. - * - * Copyright (c) 2002 James Morris - * Copyright (c) 2005 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ -#ifndef _CRYPTO_INTERNAL_H -#define _CRYPTO_INTERNAL_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Crypto notification events. */ -enum { - CRYPTO_MSG_ALG_REQUEST, - CRYPTO_MSG_ALG_REGISTER, - CRYPTO_MSG_ALG_UNREGISTER, - CRYPTO_MSG_TMPL_REGISTER, - CRYPTO_MSG_TMPL_UNREGISTER, -}; - -struct crypto_instance; -struct crypto_template; - -struct crypto_larval { - struct crypto_alg alg; - struct crypto_alg *adult; - struct completion completion; - u32 mask; -}; - -extern struct list_head crypto_alg_list; -extern struct rw_semaphore crypto_alg_sem; -extern struct blocking_notifier_head crypto_chain; - -#ifdef CONFIG_PROC_FS -void __init crypto_init_proc(void); -void __exit crypto_exit_proc(void); -#else -static inline void crypto_init_proc(void) -{ } -static inline void crypto_exit_proc(void) -{ } -#endif - -static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg) -{ - return alg->cra_ctxsize; -} - -static inline unsigned int crypto_compress_ctxsize(struct crypto_alg *alg) -{ - return alg->cra_ctxsize; -} - -struct crypto_alg *crypto_mod_get(struct crypto_alg *alg); -struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, u32 mask); -struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask); - -int crypto_init_cipher_ops(struct crypto_tfm *tfm); -int crypto_init_compress_ops(struct crypto_tfm *tfm); - -void crypto_exit_cipher_ops(struct crypto_tfm *tfm); -void crypto_exit_compress_ops(struct crypto_tfm *tfm); - -struct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask); -void crypto_larval_kill(struct crypto_alg *alg); -struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask); -void crypto_alg_tested(const char *name, int err); - -void crypto_remove_spawns(struct crypto_alg *alg, struct list_head *list, - struct crypto_alg *nalg); -void crypto_remove_final(struct list_head *list); -void crypto_shoot_alg(struct crypto_alg *alg); -struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type, - u32 mask); -void *crypto_create_tfm(struct crypto_alg *alg, - const struct crypto_type *frontend); -struct crypto_alg *crypto_find_alg(const char *alg_name, - const struct crypto_type *frontend, - u32 type, u32 mask); -void *crypto_alloc_tfm(const char *alg_name, - const struct crypto_type *frontend, u32 type, u32 mask); - -int crypto_register_notifier(struct notifier_block *nb); -int crypto_unregister_notifier(struct notifier_block *nb); -int crypto_probing_notify(unsigned long val, void *v); - -unsigned int crypto_alg_extsize(struct crypto_alg *alg); - -int crypto_type_has_alg(const char *name, const struct crypto_type *frontend, - u32 type, u32 mask); - -static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg) -{ - atomic_inc(&alg->cra_refcnt); - return alg; -} - -static inline void crypto_alg_put(struct crypto_alg *alg) -{ - if (atomic_dec_and_test(&alg->cra_refcnt) && alg->cra_destroy) - alg->cra_destroy(alg); -} - -static inline int crypto_tmpl_get(struct crypto_template *tmpl) -{ - return try_module_get(tmpl->module); -} - -static inline void crypto_tmpl_put(struct crypto_template *tmpl) -{ - module_put(tmpl->module); -} - -static inline int crypto_is_larval(struct crypto_alg *alg) -{ - return alg->cra_flags & CRYPTO_ALG_LARVAL; -} - -static inline int crypto_is_dead(struct crypto_alg *alg) -{ - return alg->cra_flags & CRYPTO_ALG_DEAD; -} - -static inline int crypto_is_moribund(struct crypto_alg *alg) -{ - return alg->cra_flags & (CRYPTO_ALG_DEAD | CRYPTO_ALG_DYING); -} - -static inline void crypto_notify(unsigned long val, void *v) -{ - blocking_notifier_call_chain(&crypto_chain, val, v); -} - -#endif /* _CRYPTO_INTERNAL_H */ - diff --git a/src/linux/crypto/jitterentropy-kcapi.c b/src/linux/crypto/jitterentropy-kcapi.c deleted file mode 100644 index c493849..0000000 --- a/src/linux/crypto/jitterentropy-kcapi.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Non-physical true random number generator based on timing jitter -- - * Linux Kernel Crypto API specific code - * - * Copyright Stephan Mueller , 2015 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU General Public License, in which case the provisions of the GPL2 are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - */ - -#include -#include -#include -#include -#include -#include -#include - -struct rand_data; -int jent_read_entropy(struct rand_data *ec, unsigned char *data, - unsigned int len); -int jent_entropy_init(void); -struct rand_data *jent_entropy_collector_alloc(unsigned int osr, - unsigned int flags); -void jent_entropy_collector_free(struct rand_data *entropy_collector); - -/*************************************************************************** - * Helper function - ***************************************************************************/ - -__u64 jent_rol64(__u64 word, unsigned int shift) -{ - return rol64(word, shift); -} - -void *jent_zalloc(unsigned int len) -{ - return kzalloc(len, GFP_KERNEL); -} - -void jent_zfree(void *ptr) -{ - kzfree(ptr); -} - -int jent_fips_enabled(void) -{ - return fips_enabled; -} - -void jent_panic(char *s) -{ - panic("%s", s); -} - -void jent_memcpy(void *dest, const void *src, unsigned int n) -{ - memcpy(dest, src, n); -} - -/* - * Obtain a high-resolution time stamp value. The time stamp is used to measure - * the execution time of a given code path and its variations. Hence, the time - * stamp must have a sufficiently high resolution. - * - * Note, if the function returns zero because a given architecture does not - * implement a high-resolution time stamp, the RNG code's runtime test - * will detect it and will not produce output. - */ -void jent_get_nstime(__u64 *out) -{ - __u64 tmp = 0; - - tmp = random_get_entropy(); - - /* - * If random_get_entropy does not return a value, i.e. it is not - * implemented for a given architecture, use a clock source. - * hoping that there are timers we can work with. - */ - if (tmp == 0) - tmp = ktime_get_ns(); - - *out = tmp; -} - -/*************************************************************************** - * Kernel crypto API interface - ***************************************************************************/ - -struct jitterentropy { - spinlock_t jent_lock; - struct rand_data *entropy_collector; -}; - -static int jent_kcapi_init(struct crypto_tfm *tfm) -{ - struct jitterentropy *rng = crypto_tfm_ctx(tfm); - int ret = 0; - - rng->entropy_collector = jent_entropy_collector_alloc(1, 0); - if (!rng->entropy_collector) - ret = -ENOMEM; - - spin_lock_init(&rng->jent_lock); - return ret; -} - -static void jent_kcapi_cleanup(struct crypto_tfm *tfm) -{ - struct jitterentropy *rng = crypto_tfm_ctx(tfm); - - spin_lock(&rng->jent_lock); - if (rng->entropy_collector) - jent_entropy_collector_free(rng->entropy_collector); - rng->entropy_collector = NULL; - spin_unlock(&rng->jent_lock); -} - -static int jent_kcapi_random(struct crypto_rng *tfm, - const u8 *src, unsigned int slen, - u8 *rdata, unsigned int dlen) -{ - struct jitterentropy *rng = crypto_rng_ctx(tfm); - int ret = 0; - - spin_lock(&rng->jent_lock); - ret = jent_read_entropy(rng->entropy_collector, rdata, dlen); - spin_unlock(&rng->jent_lock); - - return ret; -} - -static int jent_kcapi_reset(struct crypto_rng *tfm, - const u8 *seed, unsigned int slen) -{ - return 0; -} - -static struct rng_alg jent_alg = { - .generate = jent_kcapi_random, - .seed = jent_kcapi_reset, - .seedsize = 0, - .base = { - .cra_name = "jitterentropy_rng", - .cra_driver_name = "jitterentropy_rng", - .cra_priority = 100, - .cra_ctxsize = sizeof(struct jitterentropy), - .cra_module = THIS_MODULE, - .cra_init = jent_kcapi_init, - .cra_exit = jent_kcapi_cleanup, - - } -}; - -static int __init jent_mod_init(void) -{ - int ret = 0; - - ret = jent_entropy_init(); - if (ret) { - pr_info("jitterentropy: Initialization failed with host not compliant with requirements: %d\n", ret); - return -EFAULT; - } - return crypto_register_rng(&jent_alg); -} - -static void __exit jent_mod_exit(void) -{ - crypto_unregister_rng(&jent_alg); -} - -module_init(jent_mod_init); -module_exit(jent_mod_exit); - -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_AUTHOR("Stephan Mueller "); -MODULE_DESCRIPTION("Non-physical True Random Number Generator based on CPU Jitter"); -MODULE_ALIAS_CRYPTO("jitterentropy_rng"); diff --git a/src/linux/crypto/jitterentropy.c b/src/linux/crypto/jitterentropy.c deleted file mode 100644 index acf44b2..0000000 --- a/src/linux/crypto/jitterentropy.c +++ /dev/null @@ -1,787 +0,0 @@ -/* - * Non-physical true random number generator based on timing jitter -- - * Jitter RNG standalone code. - * - * Copyright Stephan Mueller , 2015 - * - * Design - * ====== - * - * See http://www.chronox.de/jent.html - * - * License - * ======= - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU General Public License, in which case the provisions of the GPL2 are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - */ - -/* - * This Jitterentropy RNG is based on the jitterentropy library - * version 1.1.0 provided at http://www.chronox.de/jent.html - */ - -#ifdef __OPTIMIZE__ - #error "The CPU Jitter random number generator must not be compiled with optimizations. See documentation. Use the compiler switch -O0 for compiling jitterentropy.c." -#endif - -typedef unsigned long long __u64; -typedef long long __s64; -typedef unsigned int __u32; -#define NULL ((void *) 0) - -/* The entropy pool */ -struct rand_data { - /* all data values that are vital to maintain the security - * of the RNG are marked as SENSITIVE. A user must not - * access that information while the RNG executes its loops to - * calculate the next random value. */ - __u64 data; /* SENSITIVE Actual random number */ - __u64 old_data; /* SENSITIVE Previous random number */ - __u64 prev_time; /* SENSITIVE Previous time stamp */ -#define DATA_SIZE_BITS ((sizeof(__u64)) * 8) - __u64 last_delta; /* SENSITIVE stuck test */ - __s64 last_delta2; /* SENSITIVE stuck test */ - unsigned int stuck:1; /* Time measurement stuck */ - unsigned int osr; /* Oversample rate */ - unsigned int stir:1; /* Post-processing stirring */ - unsigned int disable_unbias:1; /* Deactivate Von-Neuman unbias */ -#define JENT_MEMORY_BLOCKS 64 -#define JENT_MEMORY_BLOCKSIZE 32 -#define JENT_MEMORY_ACCESSLOOPS 128 -#define JENT_MEMORY_SIZE (JENT_MEMORY_BLOCKS*JENT_MEMORY_BLOCKSIZE) - unsigned char *mem; /* Memory access location with size of - * memblocks * memblocksize */ - unsigned int memlocation; /* Pointer to byte in *mem */ - unsigned int memblocks; /* Number of memory blocks in *mem */ - unsigned int memblocksize; /* Size of one memory block in bytes */ - unsigned int memaccessloops; /* Number of memory accesses per random - * bit generation */ -}; - -/* Flags that can be used to initialize the RNG */ -#define JENT_DISABLE_STIR (1<<0) /* Disable stirring the entropy pool */ -#define JENT_DISABLE_UNBIAS (1<<1) /* Disable the Von-Neuman Unbiaser */ -#define JENT_DISABLE_MEMORY_ACCESS (1<<2) /* Disable memory access for more - * entropy, saves MEMORY_SIZE RAM for - * entropy collector */ - -/* -- error codes for init function -- */ -#define JENT_ENOTIME 1 /* Timer service not available */ -#define JENT_ECOARSETIME 2 /* Timer too coarse for RNG */ -#define JENT_ENOMONOTONIC 3 /* Timer is not monotonic increasing */ -#define JENT_EMINVARIATION 4 /* Timer variations too small for RNG */ -#define JENT_EVARVAR 5 /* Timer does not produce variations of - * variations (2nd derivation of time is - * zero). */ -#define JENT_EMINVARVAR 6 /* Timer variations of variations is tooi - * small. */ - -/*************************************************************************** - * Helper functions - ***************************************************************************/ - -void jent_get_nstime(__u64 *out); -__u64 jent_rol64(__u64 word, unsigned int shift); -void *jent_zalloc(unsigned int len); -void jent_zfree(void *ptr); -int jent_fips_enabled(void); -void jent_panic(char *s); -void jent_memcpy(void *dest, const void *src, unsigned int n); - -/** - * Update of the loop count used for the next round of - * an entropy collection. - * - * Input: - * @ec entropy collector struct -- may be NULL - * @bits is the number of low bits of the timer to consider - * @min is the number of bits we shift the timer value to the right at - * the end to make sure we have a guaranteed minimum value - * - * @return Newly calculated loop counter - */ -static __u64 jent_loop_shuffle(struct rand_data *ec, - unsigned int bits, unsigned int min) -{ - __u64 time = 0; - __u64 shuffle = 0; - unsigned int i = 0; - unsigned int mask = (1<data; - /* - * we fold the time value as much as possible to ensure that as many - * bits of the time stamp are included as possible - */ - for (i = 0; (DATA_SIZE_BITS / bits) > i; i++) { - shuffle ^= time & mask; - time = time >> bits; - } - - /* - * We add a lower boundary value to ensure we have a minimum - * RNG loop count. - */ - return (shuffle + (1<= i; i++) { - __u64 tmp = time << (DATA_SIZE_BITS - i); - - tmp = tmp >> (DATA_SIZE_BITS - 1); - new ^= tmp; - } - } - *folded = new; - return fold_loop_cnt; -} - -/** - * Memory Access noise source -- this is a noise source based on variations in - * memory access times - * - * This function performs memory accesses which will add to the timing - * variations due to an unknown amount of CPU wait states that need to be - * added when accessing memory. The memory size should be larger than the L1 - * caches as outlined in the documentation and the associated testing. - * - * The L1 cache has a very high bandwidth, albeit its access rate is usually - * slower than accessing CPU registers. Therefore, L1 accesses only add minimal - * variations as the CPU has hardly to wait. Starting with L2, significant - * variations are added because L2 typically does not belong to the CPU any more - * and therefore a wider range of CPU wait states is necessary for accesses. - * L3 and real memory accesses have even a wider range of wait states. However, - * to reliably access either L3 or memory, the ec->mem memory must be quite - * large which is usually not desirable. - * - * Input: - * @ec Reference to the entropy collector with the memory access data -- if - * the reference to the memory block to be accessed is NULL, this noise - * source is disabled - * @loop_cnt if a value not equal to 0 is set, use the given value as number of - * loops to perform the folding - * - * @return Number of memory access operations - */ -static unsigned int jent_memaccess(struct rand_data *ec, __u64 loop_cnt) -{ - unsigned char *tmpval = NULL; - unsigned int wrap = 0; - __u64 i = 0; -#define MAX_ACC_LOOP_BIT 7 -#define MIN_ACC_LOOP_BIT 0 - __u64 acc_loop_cnt = - jent_loop_shuffle(ec, MAX_ACC_LOOP_BIT, MIN_ACC_LOOP_BIT); - - if (NULL == ec || NULL == ec->mem) - return 0; - wrap = ec->memblocksize * ec->memblocks; - - /* - * testing purposes -- allow test app to set the counter, not - * needed during runtime - */ - if (loop_cnt) - acc_loop_cnt = loop_cnt; - - for (i = 0; i < (ec->memaccessloops + acc_loop_cnt); i++) { - tmpval = ec->mem + ec->memlocation; - /* - * memory access: just add 1 to one byte, - * wrap at 255 -- memory access implies read - * from and write to memory location - */ - *tmpval = (*tmpval + 1) & 0xff; - /* - * Addition of memblocksize - 1 to pointer - * with wrap around logic to ensure that every - * memory location is hit evenly - */ - ec->memlocation = ec->memlocation + ec->memblocksize - 1; - ec->memlocation = ec->memlocation % wrap; - } - return i; -} - -/*************************************************************************** - * Start of entropy processing logic - ***************************************************************************/ - -/** - * Stuck test by checking the: - * 1st derivation of the jitter measurement (time delta) - * 2nd derivation of the jitter measurement (delta of time deltas) - * 3rd derivation of the jitter measurement (delta of delta of time deltas) - * - * All values must always be non-zero. - * - * Input: - * @ec Reference to entropy collector - * @current_delta Jitter time delta - * - * @return - * 0 jitter measurement not stuck (good bit) - * 1 jitter measurement stuck (reject bit) - */ -static void jent_stuck(struct rand_data *ec, __u64 current_delta) -{ - __s64 delta2 = ec->last_delta - current_delta; - __s64 delta3 = delta2 - ec->last_delta2; - - ec->last_delta = current_delta; - ec->last_delta2 = delta2; - - if (!current_delta || !delta2 || !delta3) - ec->stuck = 1; -} - -/** - * This is the heart of the entropy generation: calculate time deltas and - * use the CPU jitter in the time deltas. The jitter is folded into one - * bit. You can call this function the "random bit generator" as it - * produces one random bit per invocation. - * - * WARNING: ensure that ->prev_time is primed before using the output - * of this function! This can be done by calling this function - * and not using its result. - * - * Input: - * @entropy_collector Reference to entropy collector - * - * @return One random bit - */ -static __u64 jent_measure_jitter(struct rand_data *ec) -{ - __u64 time = 0; - __u64 data = 0; - __u64 current_delta = 0; - - /* Invoke one noise source before time measurement to add variations */ - jent_memaccess(ec, 0); - - /* - * Get time stamp and calculate time delta to previous - * invocation to measure the timing variations - */ - jent_get_nstime(&time); - current_delta = time - ec->prev_time; - ec->prev_time = time; - - /* Now call the next noise sources which also folds the data */ - jent_fold_time(ec, current_delta, &data, 0); - - /* - * Check whether we have a stuck measurement. The enforcement - * is performed after the stuck value has been mixed into the - * entropy pool. - */ - jent_stuck(ec, current_delta); - - return data; -} - -/** - * Von Neuman unbias as explained in RFC 4086 section 4.2. As shown in the - * documentation of that RNG, the bits from jent_measure_jitter are considered - * independent which implies that the Von Neuman unbias operation is applicable. - * A proof of the Von-Neumann unbias operation to remove skews is given in the - * document "A proposal for: Functionality classes for random number - * generators", version 2.0 by Werner Schindler, section 5.4.1. - * - * Input: - * @entropy_collector Reference to entropy collector - * - * @return One random bit - */ -static __u64 jent_unbiased_bit(struct rand_data *entropy_collector) -{ - do { - __u64 a = jent_measure_jitter(entropy_collector); - __u64 b = jent_measure_jitter(entropy_collector); - - if (a == b) - continue; - if (1 == a) - return 1; - else - return 0; - } while (1); -} - -/** - * Shuffle the pool a bit by mixing some value with a bijective function (XOR) - * into the pool. - * - * The function generates a mixer value that depends on the bits set and the - * location of the set bits in the random number generated by the entropy - * source. Therefore, based on the generated random number, this mixer value - * can have 2**64 different values. That mixer value is initialized with the - * first two SHA-1 constants. After obtaining the mixer value, it is XORed into - * the random number. - * - * The mixer value is not assumed to contain any entropy. But due to the XOR - * operation, it can also not destroy any entropy present in the entropy pool. - * - * Input: - * @entropy_collector Reference to entropy collector - */ -static void jent_stir_pool(struct rand_data *entropy_collector) -{ - /* - * to shut up GCC on 32 bit, we have to initialize the 64 variable - * with two 32 bit variables - */ - union c { - __u64 u64; - __u32 u32[2]; - }; - /* - * This constant is derived from the first two 32 bit initialization - * vectors of SHA-1 as defined in FIPS 180-4 section 5.3.1 - */ - union c constant; - /* - * The start value of the mixer variable is derived from the third - * and fourth 32 bit initialization vector of SHA-1 as defined in - * FIPS 180-4 section 5.3.1 - */ - union c mixer; - unsigned int i = 0; - - /* - * Store the SHA-1 constants in reverse order to make up the 64 bit - * value -- this applies to a little endian system, on a big endian - * system, it reverses as expected. But this really does not matter - * as we do not rely on the specific numbers. We just pick the SHA-1 - * constants as they have a good mix of bit set and unset. - */ - constant.u32[1] = 0x67452301; - constant.u32[0] = 0xefcdab89; - mixer.u32[1] = 0x98badcfe; - mixer.u32[0] = 0x10325476; - - for (i = 0; i < DATA_SIZE_BITS; i++) { - /* - * get the i-th bit of the input random number and only XOR - * the constant into the mixer value when that bit is set - */ - if ((entropy_collector->data >> i) & 1) - mixer.u64 ^= constant.u64; - mixer.u64 = jent_rol64(mixer.u64, 1); - } - entropy_collector->data ^= mixer.u64; -} - -/** - * Generator of one 64 bit random number - * Function fills rand_data->data - * - * Input: - * @ec Reference to entropy collector - */ -static void jent_gen_entropy(struct rand_data *ec) -{ - unsigned int k = 0; - - /* priming of the ->prev_time value */ - jent_measure_jitter(ec); - - while (1) { - __u64 data = 0; - - if (ec->disable_unbias == 1) - data = jent_measure_jitter(ec); - else - data = jent_unbiased_bit(ec); - - /* enforcement of the jent_stuck test */ - if (ec->stuck) { - /* - * We only mix in the bit considered not appropriate - * without the LSFR. The reason is that if we apply - * the LSFR and we do not rotate, the 2nd bit with LSFR - * will cancel out the first LSFR application on the - * bad bit. - * - * And we do not rotate as we apply the next bit to the - * current bit location again. - */ - ec->data ^= data; - ec->stuck = 0; - continue; - } - - /* - * Fibonacci LSFR with polynom of - * x^64 + x^61 + x^56 + x^31 + x^28 + x^23 + 1 which is - * primitive according to - * http://poincare.matf.bg.ac.rs/~ezivkovm/publications/primpol1.pdf - * (the shift values are the polynom values minus one - * due to counting bits from 0 to 63). As the current - * position is always the LSB, the polynom only needs - * to shift data in from the left without wrap. - */ - ec->data ^= data; - ec->data ^= ((ec->data >> 63) & 1); - ec->data ^= ((ec->data >> 60) & 1); - ec->data ^= ((ec->data >> 55) & 1); - ec->data ^= ((ec->data >> 30) & 1); - ec->data ^= ((ec->data >> 27) & 1); - ec->data ^= ((ec->data >> 22) & 1); - ec->data = jent_rol64(ec->data, 1); - - /* - * We multiply the loop value with ->osr to obtain the - * oversampling rate requested by the caller - */ - if (++k >= (DATA_SIZE_BITS * ec->osr)) - break; - } - if (ec->stir) - jent_stir_pool(ec); -} - -/** - * The continuous test required by FIPS 140-2 -- the function automatically - * primes the test if needed. - * - * Return: - * 0 if FIPS test passed - * < 0 if FIPS test failed - */ -static void jent_fips_test(struct rand_data *ec) -{ - if (!jent_fips_enabled()) - return; - - /* prime the FIPS test */ - if (!ec->old_data) { - ec->old_data = ec->data; - jent_gen_entropy(ec); - } - - if (ec->data == ec->old_data) - jent_panic("jitterentropy: Duplicate output detected\n"); - - ec->old_data = ec->data; -} - -/** - * Entry function: Obtain entropy for the caller. - * - * This function invokes the entropy gathering logic as often to generate - * as many bytes as requested by the caller. The entropy gathering logic - * creates 64 bit per invocation. - * - * This function truncates the last 64 bit entropy value output to the exact - * size specified by the caller. - * - * Input: - * @ec Reference to entropy collector - * @data pointer to buffer for storing random data -- buffer must already - * exist - * @len size of the buffer, specifying also the requested number of random - * in bytes - * - * @return 0 when request is fulfilled or an error - * - * The following error codes can occur: - * -1 entropy_collector is NULL - */ -int jent_read_entropy(struct rand_data *ec, unsigned char *data, - unsigned int len) -{ - unsigned char *p = data; - - if (!ec) - return -1; - - while (0 < len) { - unsigned int tocopy; - - jent_gen_entropy(ec); - jent_fips_test(ec); - if ((DATA_SIZE_BITS / 8) < len) - tocopy = (DATA_SIZE_BITS / 8); - else - tocopy = len; - jent_memcpy(p, &ec->data, tocopy); - - len -= tocopy; - p += tocopy; - } - - return 0; -} - -/*************************************************************************** - * Initialization logic - ***************************************************************************/ - -struct rand_data *jent_entropy_collector_alloc(unsigned int osr, - unsigned int flags) -{ - struct rand_data *entropy_collector; - - entropy_collector = jent_zalloc(sizeof(struct rand_data)); - if (!entropy_collector) - return NULL; - - if (!(flags & JENT_DISABLE_MEMORY_ACCESS)) { - /* Allocate memory for adding variations based on memory - * access - */ - entropy_collector->mem = jent_zalloc(JENT_MEMORY_SIZE); - if (!entropy_collector->mem) { - jent_zfree(entropy_collector); - return NULL; - } - entropy_collector->memblocksize = JENT_MEMORY_BLOCKSIZE; - entropy_collector->memblocks = JENT_MEMORY_BLOCKS; - entropy_collector->memaccessloops = JENT_MEMORY_ACCESSLOOPS; - } - - /* verify and set the oversampling rate */ - if (0 == osr) - osr = 1; /* minimum sampling rate is 1 */ - entropy_collector->osr = osr; - - entropy_collector->stir = 1; - if (flags & JENT_DISABLE_STIR) - entropy_collector->stir = 0; - if (flags & JENT_DISABLE_UNBIAS) - entropy_collector->disable_unbias = 1; - - /* fill the data pad with non-zero values */ - jent_gen_entropy(entropy_collector); - - return entropy_collector; -} - -void jent_entropy_collector_free(struct rand_data *entropy_collector) -{ - jent_zfree(entropy_collector->mem); - entropy_collector->mem = NULL; - jent_zfree(entropy_collector); - entropy_collector = NULL; -} - -int jent_entropy_init(void) -{ - int i; - __u64 delta_sum = 0; - __u64 old_delta = 0; - int time_backwards = 0; - int count_var = 0; - int count_mod = 0; - - /* We could perform statistical tests here, but the problem is - * that we only have a few loop counts to do testing. These - * loop counts may show some slight skew and we produce - * false positives. - * - * Moreover, only old systems show potentially problematic - * jitter entropy that could potentially be caught here. But - * the RNG is intended for hardware that is available or widely - * used, but not old systems that are long out of favor. Thus, - * no statistical tests. - */ - - /* - * We could add a check for system capabilities such as clock_getres or - * check for CONFIG_X86_TSC, but it does not make much sense as the - * following sanity checks verify that we have a high-resolution - * timer. - */ - /* - * TESTLOOPCOUNT needs some loops to identify edge systems. 100 is - * definitely too little. - */ -#define TESTLOOPCOUNT 300 -#define CLEARCACHE 100 - for (i = 0; (TESTLOOPCOUNT + CLEARCACHE) > i; i++) { - __u64 time = 0; - __u64 time2 = 0; - __u64 folded = 0; - __u64 delta = 0; - unsigned int lowdelta = 0; - - jent_get_nstime(&time); - jent_fold_time(NULL, time, &folded, 1< i) - continue; - - /* test whether we have an increasing timer */ - if (!(time2 > time)) - time_backwards++; - - /* - * Avoid modulo of 64 bit integer to allow code to compile - * on 32 bit architectures. - */ - lowdelta = time2 - time; - if (!(lowdelta % 100)) - count_mod++; - - /* - * ensure that we have a varying delta timer which is necessary - * for the calculation of entropy -- perform this check - * only after the first loop is executed as we need to prime - * the old_data value - */ - if (i) { - if (delta != old_delta) - count_var++; - if (delta > old_delta) - delta_sum += (delta - old_delta); - else - delta_sum += (old_delta - delta); - } - old_delta = delta; - } - - /* - * we allow up to three times the time running backwards. - * CLOCK_REALTIME is affected by adjtime and NTP operations. Thus, - * if such an operation just happens to interfere with our test, it - * should not fail. The value of 3 should cover the NTP case being - * performed during our test run. - */ - if (3 < time_backwards) - return JENT_ENOMONOTONIC; - /* Error if the time variances are always identical */ - if (!delta_sum) - return JENT_EVARVAR; - - /* - * Variations of deltas of time must on average be larger - * than 1 to ensure the entropy estimation - * implied with 1 is preserved - */ - if (delta_sum <= 1) - return JENT_EMINVARVAR; - - /* - * Ensure that we have variations in the time stamp below 10 for at - * least 10% of all checks -- on some platforms, the counter - * increments in multiples of 100, but not always - */ - if ((TESTLOOPCOUNT/10 * 9) < count_mod) - return JENT_ECOARSETIME; - - return 0; -} diff --git a/src/linux/crypto/kpp.c b/src/linux/crypto/kpp.c deleted file mode 100644 index d36ce05..0000000 --- a/src/linux/crypto/kpp.c +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Key-agreement Protocol Primitives (KPP) - * - * Copyright (c) 2016, Intel Corporation - * Authors: Salvatore Benedetto - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -#ifdef CONFIG_NET -static int crypto_kpp_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - struct crypto_report_kpp rkpp; - - strncpy(rkpp.type, "kpp", sizeof(rkpp.type)); - - if (nla_put(skb, CRYPTOCFGA_REPORT_KPP, - sizeof(struct crypto_report_kpp), &rkpp)) - goto nla_put_failure; - return 0; - -nla_put_failure: - return -EMSGSIZE; -} -#else -static int crypto_kpp_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif - -static void crypto_kpp_show(struct seq_file *m, struct crypto_alg *alg) - __attribute__ ((unused)); - -static void crypto_kpp_show(struct seq_file *m, struct crypto_alg *alg) -{ - seq_puts(m, "type : kpp\n"); -} - -static void crypto_kpp_exit_tfm(struct crypto_tfm *tfm) -{ - struct crypto_kpp *kpp = __crypto_kpp_tfm(tfm); - struct kpp_alg *alg = crypto_kpp_alg(kpp); - - alg->exit(kpp); -} - -static int crypto_kpp_init_tfm(struct crypto_tfm *tfm) -{ - struct crypto_kpp *kpp = __crypto_kpp_tfm(tfm); - struct kpp_alg *alg = crypto_kpp_alg(kpp); - - if (alg->exit) - kpp->base.exit = crypto_kpp_exit_tfm; - - if (alg->init) - return alg->init(kpp); - - return 0; -} - -static const struct crypto_type crypto_kpp_type = { - .extsize = crypto_alg_extsize, - .init_tfm = crypto_kpp_init_tfm, -#ifdef CONFIG_PROC_FS - .show = crypto_kpp_show, -#endif - .report = crypto_kpp_report, - .maskclear = ~CRYPTO_ALG_TYPE_MASK, - .maskset = CRYPTO_ALG_TYPE_MASK, - .type = CRYPTO_ALG_TYPE_KPP, - .tfmsize = offsetof(struct crypto_kpp, base), -}; - -struct crypto_kpp *crypto_alloc_kpp(const char *alg_name, u32 type, u32 mask) -{ - return crypto_alloc_tfm(alg_name, &crypto_kpp_type, type, mask); -} -EXPORT_SYMBOL_GPL(crypto_alloc_kpp); - -static void kpp_prepare_alg(struct kpp_alg *alg) -{ - struct crypto_alg *base = &alg->base; - - base->cra_type = &crypto_kpp_type; - base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; - base->cra_flags |= CRYPTO_ALG_TYPE_KPP; -} - -int crypto_register_kpp(struct kpp_alg *alg) -{ - struct crypto_alg *base = &alg->base; - - kpp_prepare_alg(alg); - return crypto_register_alg(base); -} -EXPORT_SYMBOL_GPL(crypto_register_kpp); - -void crypto_unregister_kpp(struct kpp_alg *alg) -{ - crypto_unregister_alg(&alg->base); -} -EXPORT_SYMBOL_GPL(crypto_unregister_kpp); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Key-agreement Protocol Primitives"); diff --git a/src/linux/crypto/memneq.c b/src/linux/crypto/memneq.c deleted file mode 100644 index afed1bd..0000000 --- a/src/linux/crypto/memneq.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Constant-time equality testing of memory regions. - * - * Authors: - * - * James Yonan - * Daniel Borkmann - * - * This file is provided under a dual BSD/GPLv2 license. When using or - * redistributing this file, you may do so under either license. - * - * GPL LICENSE SUMMARY - * - * Copyright(c) 2013 OpenVPN Technologies, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * The full GNU General Public License is included in this distribution - * in the file called LICENSE.GPL. - * - * BSD LICENSE - * - * Copyright(c) 2013 OpenVPN Technologies, Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of OpenVPN Technologies nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include - -#ifndef __HAVE_ARCH_CRYPTO_MEMNEQ - -/* Generic path for arbitrary size */ -static inline unsigned long -__crypto_memneq_generic(const void *a, const void *b, size_t size) -{ - unsigned long neq = 0; - -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) - while (size >= sizeof(unsigned long)) { - neq |= *(unsigned long *)a ^ *(unsigned long *)b; - OPTIMIZER_HIDE_VAR(neq); - a += sizeof(unsigned long); - b += sizeof(unsigned long); - size -= sizeof(unsigned long); - } -#endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */ - while (size > 0) { - neq |= *(unsigned char *)a ^ *(unsigned char *)b; - OPTIMIZER_HIDE_VAR(neq); - a += 1; - b += 1; - size -= 1; - } - return neq; -} - -/* Loop-free fast-path for frequently used 16-byte size */ -static inline unsigned long __crypto_memneq_16(const void *a, const void *b) -{ - unsigned long neq = 0; - -#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS - if (sizeof(unsigned long) == 8) { - neq |= *(unsigned long *)(a) ^ *(unsigned long *)(b); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned long *)(a+8) ^ *(unsigned long *)(b+8); - OPTIMIZER_HIDE_VAR(neq); - } else if (sizeof(unsigned int) == 4) { - neq |= *(unsigned int *)(a) ^ *(unsigned int *)(b); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned int *)(a+4) ^ *(unsigned int *)(b+4); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned int *)(a+8) ^ *(unsigned int *)(b+8); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned int *)(a+12) ^ *(unsigned int *)(b+12); - OPTIMIZER_HIDE_VAR(neq); - } else -#endif /* CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS */ - { - neq |= *(unsigned char *)(a) ^ *(unsigned char *)(b); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned char *)(a+1) ^ *(unsigned char *)(b+1); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned char *)(a+2) ^ *(unsigned char *)(b+2); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned char *)(a+3) ^ *(unsigned char *)(b+3); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned char *)(a+4) ^ *(unsigned char *)(b+4); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned char *)(a+5) ^ *(unsigned char *)(b+5); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned char *)(a+6) ^ *(unsigned char *)(b+6); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned char *)(a+7) ^ *(unsigned char *)(b+7); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned char *)(a+8) ^ *(unsigned char *)(b+8); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned char *)(a+9) ^ *(unsigned char *)(b+9); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned char *)(a+10) ^ *(unsigned char *)(b+10); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned char *)(a+11) ^ *(unsigned char *)(b+11); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned char *)(a+12) ^ *(unsigned char *)(b+12); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned char *)(a+13) ^ *(unsigned char *)(b+13); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned char *)(a+14) ^ *(unsigned char *)(b+14); - OPTIMIZER_HIDE_VAR(neq); - neq |= *(unsigned char *)(a+15) ^ *(unsigned char *)(b+15); - OPTIMIZER_HIDE_VAR(neq); - } - - return neq; -} - -/* Compare two areas of memory without leaking timing information, - * and with special optimizations for common sizes. Users should - * not call this function directly, but should instead use - * crypto_memneq defined in crypto/algapi.h. - */ -noinline unsigned long __crypto_memneq(const void *a, const void *b, - size_t size) -{ - switch (size) { - case 16: - return __crypto_memneq_16(a, b); - default: - return __crypto_memneq_generic(a, b, size); - } -} -EXPORT_SYMBOL(__crypto_memneq); - -#endif /* __HAVE_ARCH_CRYPTO_MEMNEQ */ diff --git a/src/linux/crypto/proc.c b/src/linux/crypto/proc.c deleted file mode 100644 index 2cc10c9..0000000 --- a/src/linux/crypto/proc.c +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Scatterlist Cryptographic API. - * - * Procfs information. - * - * Copyright (c) 2002 James Morris - * Copyright (c) 2005 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include /* for module_name() */ -#include -#include -#include -#include "internal.h" - -static void *c_start(struct seq_file *m, loff_t *pos) -{ - down_read(&crypto_alg_sem); - return seq_list_start(&crypto_alg_list, *pos); -} - -static void *c_next(struct seq_file *m, void *p, loff_t *pos) -{ - return seq_list_next(p, &crypto_alg_list, pos); -} - -static void c_stop(struct seq_file *m, void *p) -{ - up_read(&crypto_alg_sem); -} - -static int c_show(struct seq_file *m, void *p) -{ - struct crypto_alg *alg = list_entry(p, struct crypto_alg, cra_list); - - seq_printf(m, "name : %s\n", alg->cra_name); - seq_printf(m, "driver : %s\n", alg->cra_driver_name); - seq_printf(m, "module : %s\n", module_name(alg->cra_module)); - seq_printf(m, "priority : %d\n", alg->cra_priority); - seq_printf(m, "refcnt : %d\n", atomic_read(&alg->cra_refcnt)); - seq_printf(m, "selftest : %s\n", - (alg->cra_flags & CRYPTO_ALG_TESTED) ? - "passed" : "unknown"); - seq_printf(m, "internal : %s\n", - (alg->cra_flags & CRYPTO_ALG_INTERNAL) ? - "yes" : "no"); - - if (alg->cra_flags & CRYPTO_ALG_LARVAL) { - seq_printf(m, "type : larval\n"); - seq_printf(m, "flags : 0x%x\n", alg->cra_flags); - goto out; - } - - if (alg->cra_type && alg->cra_type->show) { - alg->cra_type->show(m, alg); - goto out; - } - - switch (alg->cra_flags & (CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_LARVAL)) { - case CRYPTO_ALG_TYPE_CIPHER: - seq_printf(m, "type : cipher\n"); - seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); - seq_printf(m, "min keysize : %u\n", - alg->cra_cipher.cia_min_keysize); - seq_printf(m, "max keysize : %u\n", - alg->cra_cipher.cia_max_keysize); - break; - case CRYPTO_ALG_TYPE_COMPRESS: - seq_printf(m, "type : compression\n"); - break; - default: - seq_printf(m, "type : unknown\n"); - break; - } - -out: - seq_putc(m, '\n'); - return 0; -} - -static const struct seq_operations crypto_seq_ops = { - .start = c_start, - .next = c_next, - .stop = c_stop, - .show = c_show -}; - -static int crypto_info_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &crypto_seq_ops); -} - -static const struct file_operations proc_crypto_ops = { - .open = crypto_info_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release -}; - -void __init crypto_init_proc(void) -{ - proc_create("crypto", 0, NULL, &proc_crypto_ops); -} - -void __exit crypto_exit_proc(void) -{ - remove_proc_entry("crypto", NULL); -} diff --git a/src/linux/crypto/rng.c b/src/linux/crypto/rng.c deleted file mode 100644 index b81cffb..0000000 --- a/src/linux/crypto/rng.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Cryptographic API. - * - * RNG operations. - * - * Copyright (c) 2008 Neil Horman - * Copyright (c) 2015 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -static DEFINE_MUTEX(crypto_default_rng_lock); -struct crypto_rng *crypto_default_rng; -EXPORT_SYMBOL_GPL(crypto_default_rng); -static int crypto_default_rng_refcnt; - -static inline struct crypto_rng *__crypto_rng_cast(struct crypto_tfm *tfm) -{ - return container_of(tfm, struct crypto_rng, base); -} - -int crypto_rng_reset(struct crypto_rng *tfm, const u8 *seed, unsigned int slen) -{ - u8 *buf = NULL; - int err; - - if (!seed && slen) { - buf = kmalloc(slen, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - get_random_bytes(buf, slen); - seed = buf; - } - - err = crypto_rng_alg(tfm)->seed(tfm, seed, slen); - - kzfree(buf); - return err; -} -EXPORT_SYMBOL_GPL(crypto_rng_reset); - -static int crypto_rng_init_tfm(struct crypto_tfm *tfm) -{ - return 0; -} - -static unsigned int seedsize(struct crypto_alg *alg) -{ - struct rng_alg *ralg = container_of(alg, struct rng_alg, base); - - return ralg->seedsize; -} - -#ifdef CONFIG_NET -static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - struct crypto_report_rng rrng; - - strncpy(rrng.type, "rng", sizeof(rrng.type)); - - rrng.seedsize = seedsize(alg); - - if (nla_put(skb, CRYPTOCFGA_REPORT_RNG, - sizeof(struct crypto_report_rng), &rrng)) - goto nla_put_failure; - return 0; - -nla_put_failure: - return -EMSGSIZE; -} -#else -static int crypto_rng_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif - -static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg) - __attribute__ ((unused)); -static void crypto_rng_show(struct seq_file *m, struct crypto_alg *alg) -{ - seq_printf(m, "type : rng\n"); - seq_printf(m, "seedsize : %u\n", seedsize(alg)); -} - -static const struct crypto_type crypto_rng_type = { - .extsize = crypto_alg_extsize, - .init_tfm = crypto_rng_init_tfm, -#ifdef CONFIG_PROC_FS - .show = crypto_rng_show, -#endif - .report = crypto_rng_report, - .maskclear = ~CRYPTO_ALG_TYPE_MASK, - .maskset = CRYPTO_ALG_TYPE_MASK, - .type = CRYPTO_ALG_TYPE_RNG, - .tfmsize = offsetof(struct crypto_rng, base), -}; - -struct crypto_rng *crypto_alloc_rng(const char *alg_name, u32 type, u32 mask) -{ - return crypto_alloc_tfm(alg_name, &crypto_rng_type, type, mask); -} -EXPORT_SYMBOL_GPL(crypto_alloc_rng); - -int crypto_get_default_rng(void) -{ - struct crypto_rng *rng; - int err; - - mutex_lock(&crypto_default_rng_lock); - if (!crypto_default_rng) { - rng = crypto_alloc_rng("stdrng", 0, 0); - err = PTR_ERR(rng); - if (IS_ERR(rng)) - goto unlock; - - err = crypto_rng_reset(rng, NULL, crypto_rng_seedsize(rng)); - if (err) { - crypto_free_rng(rng); - goto unlock; - } - - crypto_default_rng = rng; - } - - crypto_default_rng_refcnt++; - err = 0; - -unlock: - mutex_unlock(&crypto_default_rng_lock); - - return err; -} -EXPORT_SYMBOL_GPL(crypto_get_default_rng); - -void crypto_put_default_rng(void) -{ - mutex_lock(&crypto_default_rng_lock); - crypto_default_rng_refcnt--; - mutex_unlock(&crypto_default_rng_lock); -} -EXPORT_SYMBOL_GPL(crypto_put_default_rng); - -#if defined(CONFIG_CRYPTO_RNG) || defined(CONFIG_CRYPTO_RNG_MODULE) -int crypto_del_default_rng(void) -{ - int err = -EBUSY; - - mutex_lock(&crypto_default_rng_lock); - if (crypto_default_rng_refcnt) - goto out; - - crypto_free_rng(crypto_default_rng); - crypto_default_rng = NULL; - - err = 0; - -out: - mutex_unlock(&crypto_default_rng_lock); - - return err; -} -EXPORT_SYMBOL_GPL(crypto_del_default_rng); -#endif - -int crypto_register_rng(struct rng_alg *alg) -{ - struct crypto_alg *base = &alg->base; - - if (alg->seedsize > PAGE_SIZE / 8) - return -EINVAL; - - base->cra_type = &crypto_rng_type; - base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; - base->cra_flags |= CRYPTO_ALG_TYPE_RNG; - - return crypto_register_alg(base); -} -EXPORT_SYMBOL_GPL(crypto_register_rng); - -void crypto_unregister_rng(struct rng_alg *alg) -{ - crypto_unregister_alg(&alg->base); -} -EXPORT_SYMBOL_GPL(crypto_unregister_rng); - -int crypto_register_rngs(struct rng_alg *algs, int count) -{ - int i, ret; - - for (i = 0; i < count; i++) { - ret = crypto_register_rng(algs + i); - if (ret) - goto err; - } - - return 0; - -err: - for (--i; i >= 0; --i) - crypto_unregister_rng(algs + i); - - return ret; -} -EXPORT_SYMBOL_GPL(crypto_register_rngs); - -void crypto_unregister_rngs(struct rng_alg *algs, int count) -{ - int i; - - for (i = count - 1; i >= 0; --i) - crypto_unregister_rng(algs + i); -} -EXPORT_SYMBOL_GPL(crypto_unregister_rngs); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Random Number Generator"); diff --git a/src/linux/crypto/scatterwalk.c b/src/linux/crypto/scatterwalk.c deleted file mode 100644 index c16c94f..0000000 --- a/src/linux/crypto/scatterwalk.c +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Cryptographic API. - * - * Cipher operations. - * - * Copyright (c) 2002 James Morris - * 2002 Adam J. Richter - * 2004 Jean-Luc Cooke - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include - -static inline void memcpy_dir(void *buf, void *sgdata, size_t nbytes, int out) -{ - void *src = out ? buf : sgdata; - void *dst = out ? sgdata : buf; - - memcpy(dst, src, nbytes); -} - -void scatterwalk_copychunks(void *buf, struct scatter_walk *walk, - size_t nbytes, int out) -{ - for (;;) { - unsigned int len_this_page = scatterwalk_pagelen(walk); - u8 *vaddr; - - if (len_this_page > nbytes) - len_this_page = nbytes; - - if (out != 2) { - vaddr = scatterwalk_map(walk); - memcpy_dir(buf, vaddr, len_this_page, out); - scatterwalk_unmap(vaddr); - } - - scatterwalk_advance(walk, len_this_page); - - if (nbytes == len_this_page) - break; - - buf += len_this_page; - nbytes -= len_this_page; - - scatterwalk_pagedone(walk, out & 1, 1); - } -} -EXPORT_SYMBOL_GPL(scatterwalk_copychunks); - -void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg, - unsigned int start, unsigned int nbytes, int out) -{ - struct scatter_walk walk; - struct scatterlist tmp[2]; - - if (!nbytes) - return; - - sg = scatterwalk_ffwd(tmp, sg, start); - - scatterwalk_start(&walk, sg); - scatterwalk_copychunks(buf, &walk, nbytes, out); - scatterwalk_done(&walk, out, 0); -} -EXPORT_SYMBOL_GPL(scatterwalk_map_and_copy); - -struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2], - struct scatterlist *src, - unsigned int len) -{ - for (;;) { - if (!len) - return src; - - if (src->length > len) - break; - - len -= src->length; - src = sg_next(src); - } - - sg_init_table(dst, 2); - sg_set_page(dst, sg_page(src), src->length - len, src->offset + len); - scatterwalk_crypto_chain(dst, sg_next(src), 0, 2); - - return dst; -} -EXPORT_SYMBOL_GPL(scatterwalk_ffwd); diff --git a/src/linux/crypto/sha256_generic.c b/src/linux/crypto/sha256_generic.c deleted file mode 100644 index 8f9c47e..0000000 --- a/src/linux/crypto/sha256_generic.c +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Cryptographic API. - * - * SHA-256, as specified in - * http://csrc.nist.gov/groups/STM/cavp/documents/shs/sha256-384-512.pdf - * - * SHA-256 code by Jean-Luc Cooke . - * - * Copyright (c) Jean-Luc Cooke - * Copyright (c) Andrew McDonald - * Copyright (c) 2002 James Morris - * SHA224 Support Copyright 2007 Intel Corporation - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -const u8 sha224_zero_message_hash[SHA224_DIGEST_SIZE] = { - 0xd1, 0x4a, 0x02, 0x8c, 0x2a, 0x3a, 0x2b, 0xc9, 0x47, - 0x61, 0x02, 0xbb, 0x28, 0x82, 0x34, 0xc4, 0x15, 0xa2, - 0xb0, 0x1f, 0x82, 0x8e, 0xa6, 0x2a, 0xc5, 0xb3, 0xe4, - 0x2f -}; -EXPORT_SYMBOL_GPL(sha224_zero_message_hash); - -const u8 sha256_zero_message_hash[SHA256_DIGEST_SIZE] = { - 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, - 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24, - 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, - 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 -}; -EXPORT_SYMBOL_GPL(sha256_zero_message_hash); - -static inline u32 Ch(u32 x, u32 y, u32 z) -{ - return z ^ (x & (y ^ z)); -} - -static inline u32 Maj(u32 x, u32 y, u32 z) -{ - return (x & y) | (z & (x | y)); -} - -#define e0(x) (ror32(x, 2) ^ ror32(x,13) ^ ror32(x,22)) -#define e1(x) (ror32(x, 6) ^ ror32(x,11) ^ ror32(x,25)) -#define s0(x) (ror32(x, 7) ^ ror32(x,18) ^ (x >> 3)) -#define s1(x) (ror32(x,17) ^ ror32(x,19) ^ (x >> 10)) - -static inline void LOAD_OP(int I, u32 *W, const u8 *input) -{ - W[I] = get_unaligned_be32((__u32 *)input + I); -} - -static inline void BLEND_OP(int I, u32 *W) -{ - W[I] = s1(W[I-2]) + W[I-7] + s0(W[I-15]) + W[I-16]; -} - -static void sha256_transform(u32 *state, const u8 *input) -{ - u32 a, b, c, d, e, f, g, h, t1, t2; - u32 W[64]; - int i; - - /* load the input */ - for (i = 0; i < 16; i++) - LOAD_OP(i, W, input); - - /* now blend */ - for (i = 16; i < 64; i++) - BLEND_OP(i, W); - - /* load the state into our registers */ - a=state[0]; b=state[1]; c=state[2]; d=state[3]; - e=state[4]; f=state[5]; g=state[6]; h=state[7]; - - /* now iterate */ - t1 = h + e1(e) + Ch(e,f,g) + 0x428a2f98 + W[ 0]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0x71374491 + W[ 1]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0xb5c0fbcf + W[ 2]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0xe9b5dba5 + W[ 3]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0x3956c25b + W[ 4]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0x59f111f1 + W[ 5]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0x923f82a4 + W[ 6]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0xab1c5ed5 + W[ 7]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0xd807aa98 + W[ 8]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0x12835b01 + W[ 9]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0x243185be + W[10]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0x550c7dc3 + W[11]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0x72be5d74 + W[12]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0x80deb1fe + W[13]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0x9bdc06a7 + W[14]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0xc19bf174 + W[15]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0xe49b69c1 + W[16]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0xefbe4786 + W[17]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0x0fc19dc6 + W[18]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0x240ca1cc + W[19]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0x2de92c6f + W[20]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0x4a7484aa + W[21]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0x5cb0a9dc + W[22]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0x76f988da + W[23]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0x983e5152 + W[24]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0xa831c66d + W[25]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0xb00327c8 + W[26]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0xbf597fc7 + W[27]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0xc6e00bf3 + W[28]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0xd5a79147 + W[29]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0x06ca6351 + W[30]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0x14292967 + W[31]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0x27b70a85 + W[32]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0x2e1b2138 + W[33]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0x4d2c6dfc + W[34]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0x53380d13 + W[35]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0x650a7354 + W[36]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0x766a0abb + W[37]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0x81c2c92e + W[38]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0x92722c85 + W[39]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0xa2bfe8a1 + W[40]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0xa81a664b + W[41]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0xc24b8b70 + W[42]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0xc76c51a3 + W[43]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0xd192e819 + W[44]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0xd6990624 + W[45]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0xf40e3585 + W[46]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0x106aa070 + W[47]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0x19a4c116 + W[48]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0x1e376c08 + W[49]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0x2748774c + W[50]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0x34b0bcb5 + W[51]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0x391c0cb3 + W[52]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0x4ed8aa4a + W[53]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0x5b9cca4f + W[54]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0x682e6ff3 + W[55]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - t1 = h + e1(e) + Ch(e,f,g) + 0x748f82ee + W[56]; - t2 = e0(a) + Maj(a,b,c); d+=t1; h=t1+t2; - t1 = g + e1(d) + Ch(d,e,f) + 0x78a5636f + W[57]; - t2 = e0(h) + Maj(h,a,b); c+=t1; g=t1+t2; - t1 = f + e1(c) + Ch(c,d,e) + 0x84c87814 + W[58]; - t2 = e0(g) + Maj(g,h,a); b+=t1; f=t1+t2; - t1 = e + e1(b) + Ch(b,c,d) + 0x8cc70208 + W[59]; - t2 = e0(f) + Maj(f,g,h); a+=t1; e=t1+t2; - t1 = d + e1(a) + Ch(a,b,c) + 0x90befffa + W[60]; - t2 = e0(e) + Maj(e,f,g); h+=t1; d=t1+t2; - t1 = c + e1(h) + Ch(h,a,b) + 0xa4506ceb + W[61]; - t2 = e0(d) + Maj(d,e,f); g+=t1; c=t1+t2; - t1 = b + e1(g) + Ch(g,h,a) + 0xbef9a3f7 + W[62]; - t2 = e0(c) + Maj(c,d,e); f+=t1; b=t1+t2; - t1 = a + e1(f) + Ch(f,g,h) + 0xc67178f2 + W[63]; - t2 = e0(b) + Maj(b,c,d); e+=t1; a=t1+t2; - - state[0] += a; state[1] += b; state[2] += c; state[3] += d; - state[4] += e; state[5] += f; state[6] += g; state[7] += h; - - /* clear any sensitive info... */ - a = b = c = d = e = f = g = h = t1 = t2 = 0; - memzero_explicit(W, 64 * sizeof(u32)); -} - -static void sha256_generic_block_fn(struct sha256_state *sst, u8 const *src, - int blocks) -{ - while (blocks--) { - sha256_transform(sst->state, src); - src += SHA256_BLOCK_SIZE; - } -} - -int crypto_sha256_update(struct shash_desc *desc, const u8 *data, - unsigned int len) -{ - return sha256_base_do_update(desc, data, len, sha256_generic_block_fn); -} -EXPORT_SYMBOL(crypto_sha256_update); - -static int sha256_final(struct shash_desc *desc, u8 *out) -{ - sha256_base_do_finalize(desc, sha256_generic_block_fn); - return sha256_base_finish(desc, out); -} - -int crypto_sha256_finup(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *hash) -{ - sha256_base_do_update(desc, data, len, sha256_generic_block_fn); - return sha256_final(desc, hash); -} -EXPORT_SYMBOL(crypto_sha256_finup); - -static struct shash_alg sha256_algs[2] = { { - .digestsize = SHA256_DIGEST_SIZE, - .init = sha256_base_init, - .update = crypto_sha256_update, - .final = sha256_final, - .finup = crypto_sha256_finup, - .descsize = sizeof(struct sha256_state), - .base = { - .cra_name = "sha256", - .cra_driver_name= "sha256-generic", - .cra_flags = CRYPTO_ALG_TYPE_SHASH, - .cra_blocksize = SHA256_BLOCK_SIZE, - .cra_module = THIS_MODULE, - } -}, { - .digestsize = SHA224_DIGEST_SIZE, - .init = sha224_base_init, - .update = crypto_sha256_update, - .final = sha256_final, - .finup = crypto_sha256_finup, - .descsize = sizeof(struct sha256_state), - .base = { - .cra_name = "sha224", - .cra_driver_name= "sha224-generic", - .cra_flags = CRYPTO_ALG_TYPE_SHASH, - .cra_blocksize = SHA224_BLOCK_SIZE, - .cra_module = THIS_MODULE, - } -} }; - -static int __init sha256_generic_mod_init(void) -{ - return crypto_register_shashes(sha256_algs, ARRAY_SIZE(sha256_algs)); -} - -static void __exit sha256_generic_mod_fini(void) -{ - crypto_unregister_shashes(sha256_algs, ARRAY_SIZE(sha256_algs)); -} - -module_init(sha256_generic_mod_init); -module_exit(sha256_generic_mod_fini); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("SHA-224 and SHA-256 Secure Hash Algorithm"); - -MODULE_ALIAS_CRYPTO("sha224"); -MODULE_ALIAS_CRYPTO("sha224-generic"); -MODULE_ALIAS_CRYPTO("sha256"); -MODULE_ALIAS_CRYPTO("sha256-generic"); diff --git a/src/linux/crypto/shash.c b/src/linux/crypto/shash.c deleted file mode 100644 index a051541..0000000 --- a/src/linux/crypto/shash.c +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Synchronous Cryptographic Hash operations. - * - * Copyright (c) 2008 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -static const struct crypto_type crypto_shash_type; - -static int shash_no_setkey(struct crypto_shash *tfm, const u8 *key, - unsigned int keylen) -{ - return -ENOSYS; -} - -static int shash_setkey_unaligned(struct crypto_shash *tfm, const u8 *key, - unsigned int keylen) -{ - struct shash_alg *shash = crypto_shash_alg(tfm); - unsigned long alignmask = crypto_shash_alignmask(tfm); - unsigned long absize; - u8 *buffer, *alignbuffer; - int err; - - absize = keylen + (alignmask & ~(crypto_tfm_ctx_alignment() - 1)); - buffer = kmalloc(absize, GFP_KERNEL); - if (!buffer) - return -ENOMEM; - - alignbuffer = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1); - memcpy(alignbuffer, key, keylen); - err = shash->setkey(tfm, alignbuffer, keylen); - kzfree(buffer); - return err; -} - -int crypto_shash_setkey(struct crypto_shash *tfm, const u8 *key, - unsigned int keylen) -{ - struct shash_alg *shash = crypto_shash_alg(tfm); - unsigned long alignmask = crypto_shash_alignmask(tfm); - - if ((unsigned long)key & alignmask) - return shash_setkey_unaligned(tfm, key, keylen); - - return shash->setkey(tfm, key, keylen); -} -EXPORT_SYMBOL_GPL(crypto_shash_setkey); - -static inline unsigned int shash_align_buffer_size(unsigned len, - unsigned long mask) -{ - typedef u8 __attribute__ ((aligned)) u8_aligned; - return len + (mask & ~(__alignof__(u8_aligned) - 1)); -} - -static int shash_update_unaligned(struct shash_desc *desc, const u8 *data, - unsigned int len) -{ - struct crypto_shash *tfm = desc->tfm; - struct shash_alg *shash = crypto_shash_alg(tfm); - unsigned long alignmask = crypto_shash_alignmask(tfm); - unsigned int unaligned_len = alignmask + 1 - - ((unsigned long)data & alignmask); - u8 ubuf[shash_align_buffer_size(unaligned_len, alignmask)] - __attribute__ ((aligned)); - u8 *buf = PTR_ALIGN(&ubuf[0], alignmask + 1); - int err; - - if (unaligned_len > len) - unaligned_len = len; - - memcpy(buf, data, unaligned_len); - err = shash->update(desc, buf, unaligned_len); - memset(buf, 0, unaligned_len); - - return err ?: - shash->update(desc, data + unaligned_len, len - unaligned_len); -} - -int crypto_shash_update(struct shash_desc *desc, const u8 *data, - unsigned int len) -{ - struct crypto_shash *tfm = desc->tfm; - struct shash_alg *shash = crypto_shash_alg(tfm); - unsigned long alignmask = crypto_shash_alignmask(tfm); - - if ((unsigned long)data & alignmask) - return shash_update_unaligned(desc, data, len); - - return shash->update(desc, data, len); -} -EXPORT_SYMBOL_GPL(crypto_shash_update); - -static int shash_final_unaligned(struct shash_desc *desc, u8 *out) -{ - struct crypto_shash *tfm = desc->tfm; - unsigned long alignmask = crypto_shash_alignmask(tfm); - struct shash_alg *shash = crypto_shash_alg(tfm); - unsigned int ds = crypto_shash_digestsize(tfm); - u8 ubuf[shash_align_buffer_size(ds, alignmask)] - __attribute__ ((aligned)); - u8 *buf = PTR_ALIGN(&ubuf[0], alignmask + 1); - int err; - - err = shash->final(desc, buf); - if (err) - goto out; - - memcpy(out, buf, ds); - -out: - memset(buf, 0, ds); - return err; -} - -int crypto_shash_final(struct shash_desc *desc, u8 *out) -{ - struct crypto_shash *tfm = desc->tfm; - struct shash_alg *shash = crypto_shash_alg(tfm); - unsigned long alignmask = crypto_shash_alignmask(tfm); - - if ((unsigned long)out & alignmask) - return shash_final_unaligned(desc, out); - - return shash->final(desc, out); -} -EXPORT_SYMBOL_GPL(crypto_shash_final); - -static int shash_finup_unaligned(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *out) -{ - return crypto_shash_update(desc, data, len) ?: - crypto_shash_final(desc, out); -} - -int crypto_shash_finup(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *out) -{ - struct crypto_shash *tfm = desc->tfm; - struct shash_alg *shash = crypto_shash_alg(tfm); - unsigned long alignmask = crypto_shash_alignmask(tfm); - - if (((unsigned long)data | (unsigned long)out) & alignmask) - return shash_finup_unaligned(desc, data, len, out); - - return shash->finup(desc, data, len, out); -} -EXPORT_SYMBOL_GPL(crypto_shash_finup); - -static int shash_digest_unaligned(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *out) -{ - return crypto_shash_init(desc) ?: - crypto_shash_finup(desc, data, len, out); -} - -int crypto_shash_digest(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *out) -{ - struct crypto_shash *tfm = desc->tfm; - struct shash_alg *shash = crypto_shash_alg(tfm); - unsigned long alignmask = crypto_shash_alignmask(tfm); - - if (((unsigned long)data | (unsigned long)out) & alignmask) - return shash_digest_unaligned(desc, data, len, out); - - return shash->digest(desc, data, len, out); -} -EXPORT_SYMBOL_GPL(crypto_shash_digest); - -static int shash_default_export(struct shash_desc *desc, void *out) -{ - memcpy(out, shash_desc_ctx(desc), crypto_shash_descsize(desc->tfm)); - return 0; -} - -static int shash_default_import(struct shash_desc *desc, const void *in) -{ - memcpy(shash_desc_ctx(desc), in, crypto_shash_descsize(desc->tfm)); - return 0; -} - -static int shash_async_setkey(struct crypto_ahash *tfm, const u8 *key, - unsigned int keylen) -{ - struct crypto_shash **ctx = crypto_ahash_ctx(tfm); - - return crypto_shash_setkey(*ctx, key, keylen); -} - -static int shash_async_init(struct ahash_request *req) -{ - struct crypto_shash **ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); - struct shash_desc *desc = ahash_request_ctx(req); - - desc->tfm = *ctx; - desc->flags = req->base.flags; - - return crypto_shash_init(desc); -} - -int shash_ahash_update(struct ahash_request *req, struct shash_desc *desc) -{ - struct crypto_hash_walk walk; - int nbytes; - - for (nbytes = crypto_hash_walk_first(req, &walk); nbytes > 0; - nbytes = crypto_hash_walk_done(&walk, nbytes)) - nbytes = crypto_shash_update(desc, walk.data, nbytes); - - return nbytes; -} -EXPORT_SYMBOL_GPL(shash_ahash_update); - -static int shash_async_update(struct ahash_request *req) -{ - return shash_ahash_update(req, ahash_request_ctx(req)); -} - -static int shash_async_final(struct ahash_request *req) -{ - return crypto_shash_final(ahash_request_ctx(req), req->result); -} - -int shash_ahash_finup(struct ahash_request *req, struct shash_desc *desc) -{ - struct crypto_hash_walk walk; - int nbytes; - - nbytes = crypto_hash_walk_first(req, &walk); - if (!nbytes) - return crypto_shash_final(desc, req->result); - - do { - nbytes = crypto_hash_walk_last(&walk) ? - crypto_shash_finup(desc, walk.data, nbytes, - req->result) : - crypto_shash_update(desc, walk.data, nbytes); - nbytes = crypto_hash_walk_done(&walk, nbytes); - } while (nbytes > 0); - - return nbytes; -} -EXPORT_SYMBOL_GPL(shash_ahash_finup); - -static int shash_async_finup(struct ahash_request *req) -{ - struct crypto_shash **ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); - struct shash_desc *desc = ahash_request_ctx(req); - - desc->tfm = *ctx; - desc->flags = req->base.flags; - - return shash_ahash_finup(req, desc); -} - -int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc) -{ - struct scatterlist *sg = req->src; - unsigned int offset = sg->offset; - unsigned int nbytes = req->nbytes; - int err; - - if (nbytes < min(sg->length, ((unsigned int)(PAGE_SIZE)) - offset)) { - void *data; - - data = kmap_atomic(sg_page(sg)); - err = crypto_shash_digest(desc, data + offset, nbytes, - req->result); - kunmap_atomic(data); - crypto_yield(desc->flags); - } else - err = crypto_shash_init(desc) ?: - shash_ahash_finup(req, desc); - - return err; -} -EXPORT_SYMBOL_GPL(shash_ahash_digest); - -static int shash_async_digest(struct ahash_request *req) -{ - struct crypto_shash **ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); - struct shash_desc *desc = ahash_request_ctx(req); - - desc->tfm = *ctx; - desc->flags = req->base.flags; - - return shash_ahash_digest(req, desc); -} - -static int shash_async_export(struct ahash_request *req, void *out) -{ - return crypto_shash_export(ahash_request_ctx(req), out); -} - -static int shash_async_import(struct ahash_request *req, const void *in) -{ - struct crypto_shash **ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); - struct shash_desc *desc = ahash_request_ctx(req); - - desc->tfm = *ctx; - desc->flags = req->base.flags; - - return crypto_shash_import(desc, in); -} - -static void crypto_exit_shash_ops_async(struct crypto_tfm *tfm) -{ - struct crypto_shash **ctx = crypto_tfm_ctx(tfm); - - crypto_free_shash(*ctx); -} - -int crypto_init_shash_ops_async(struct crypto_tfm *tfm) -{ - struct crypto_alg *calg = tfm->__crt_alg; - struct shash_alg *alg = __crypto_shash_alg(calg); - struct crypto_ahash *crt = __crypto_ahash_cast(tfm); - struct crypto_shash **ctx = crypto_tfm_ctx(tfm); - struct crypto_shash *shash; - - if (!crypto_mod_get(calg)) - return -EAGAIN; - - shash = crypto_create_tfm(calg, &crypto_shash_type); - if (IS_ERR(shash)) { - crypto_mod_put(calg); - return PTR_ERR(shash); - } - - *ctx = shash; - tfm->exit = crypto_exit_shash_ops_async; - - crt->init = shash_async_init; - crt->update = shash_async_update; - crt->final = shash_async_final; - crt->finup = shash_async_finup; - crt->digest = shash_async_digest; - crt->setkey = shash_async_setkey; - - crt->has_setkey = alg->setkey != shash_no_setkey; - - if (alg->export) - crt->export = shash_async_export; - if (alg->import) - crt->import = shash_async_import; - - crt->reqsize = sizeof(struct shash_desc) + crypto_shash_descsize(shash); - - return 0; -} - -static int crypto_shash_init_tfm(struct crypto_tfm *tfm) -{ - struct crypto_shash *hash = __crypto_shash_cast(tfm); - - hash->descsize = crypto_shash_alg(hash)->descsize; - return 0; -} - -#ifdef CONFIG_NET -static int crypto_shash_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - struct crypto_report_hash rhash; - struct shash_alg *salg = __crypto_shash_alg(alg); - - strncpy(rhash.type, "shash", sizeof(rhash.type)); - - rhash.blocksize = alg->cra_blocksize; - rhash.digestsize = salg->digestsize; - - if (nla_put(skb, CRYPTOCFGA_REPORT_HASH, - sizeof(struct crypto_report_hash), &rhash)) - goto nla_put_failure; - return 0; - -nla_put_failure: - return -EMSGSIZE; -} -#else -static int crypto_shash_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif - -static void crypto_shash_show(struct seq_file *m, struct crypto_alg *alg) - __attribute__ ((unused)); -static void crypto_shash_show(struct seq_file *m, struct crypto_alg *alg) -{ - struct shash_alg *salg = __crypto_shash_alg(alg); - - seq_printf(m, "type : shash\n"); - seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); - seq_printf(m, "digestsize : %u\n", salg->digestsize); -} - -static const struct crypto_type crypto_shash_type = { - .extsize = crypto_alg_extsize, - .init_tfm = crypto_shash_init_tfm, -#ifdef CONFIG_PROC_FS - .show = crypto_shash_show, -#endif - .report = crypto_shash_report, - .maskclear = ~CRYPTO_ALG_TYPE_MASK, - .maskset = CRYPTO_ALG_TYPE_MASK, - .type = CRYPTO_ALG_TYPE_SHASH, - .tfmsize = offsetof(struct crypto_shash, base), -}; - -struct crypto_shash *crypto_alloc_shash(const char *alg_name, u32 type, - u32 mask) -{ - return crypto_alloc_tfm(alg_name, &crypto_shash_type, type, mask); -} -EXPORT_SYMBOL_GPL(crypto_alloc_shash); - -static int shash_prepare_alg(struct shash_alg *alg) -{ - struct crypto_alg *base = &alg->base; - - if (alg->digestsize > PAGE_SIZE / 8 || - alg->descsize > PAGE_SIZE / 8 || - alg->statesize > PAGE_SIZE / 8) - return -EINVAL; - - base->cra_type = &crypto_shash_type; - base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; - base->cra_flags |= CRYPTO_ALG_TYPE_SHASH; - - if (!alg->finup) - alg->finup = shash_finup_unaligned; - if (!alg->digest) - alg->digest = shash_digest_unaligned; - if (!alg->export) { - alg->export = shash_default_export; - alg->import = shash_default_import; - alg->statesize = alg->descsize; - } - if (!alg->setkey) - alg->setkey = shash_no_setkey; - - return 0; -} - -int crypto_register_shash(struct shash_alg *alg) -{ - struct crypto_alg *base = &alg->base; - int err; - - err = shash_prepare_alg(alg); - if (err) - return err; - - return crypto_register_alg(base); -} -EXPORT_SYMBOL_GPL(crypto_register_shash); - -int crypto_unregister_shash(struct shash_alg *alg) -{ - return crypto_unregister_alg(&alg->base); -} -EXPORT_SYMBOL_GPL(crypto_unregister_shash); - -int crypto_register_shashes(struct shash_alg *algs, int count) -{ - int i, ret; - - for (i = 0; i < count; i++) { - ret = crypto_register_shash(&algs[i]); - if (ret) - goto err; - } - - return 0; - -err: - for (--i; i >= 0; --i) - crypto_unregister_shash(&algs[i]); - - return ret; -} -EXPORT_SYMBOL_GPL(crypto_register_shashes); - -int crypto_unregister_shashes(struct shash_alg *algs, int count) -{ - int i, ret; - - for (i = count - 1; i >= 0; --i) { - ret = crypto_unregister_shash(&algs[i]); - if (ret) - pr_err("Failed to unregister %s %s: %d\n", - algs[i].base.cra_driver_name, - algs[i].base.cra_name, ret); - } - - return 0; -} -EXPORT_SYMBOL_GPL(crypto_unregister_shashes); - -int shash_register_instance(struct crypto_template *tmpl, - struct shash_instance *inst) -{ - int err; - - err = shash_prepare_alg(&inst->alg); - if (err) - return err; - - return crypto_register_instance(tmpl, shash_crypto_instance(inst)); -} -EXPORT_SYMBOL_GPL(shash_register_instance); - -void shash_free_instance(struct crypto_instance *inst) -{ - crypto_drop_spawn(crypto_instance_ctx(inst)); - kfree(shash_instance(inst)); -} -EXPORT_SYMBOL_GPL(shash_free_instance); - -int crypto_init_shash_spawn(struct crypto_shash_spawn *spawn, - struct shash_alg *alg, - struct crypto_instance *inst) -{ - return crypto_init_spawn2(&spawn->base, &alg->base, inst, - &crypto_shash_type); -} -EXPORT_SYMBOL_GPL(crypto_init_shash_spawn); - -struct shash_alg *shash_attr_alg(struct rtattr *rta, u32 type, u32 mask) -{ - struct crypto_alg *alg; - - alg = crypto_attr_alg2(rta, &crypto_shash_type, type, mask); - return IS_ERR(alg) ? ERR_CAST(alg) : - container_of(alg, struct shash_alg, base); -} -EXPORT_SYMBOL_GPL(shash_attr_alg); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Synchronous cryptographic hash type"); diff --git a/src/linux/crypto/skcipher.c b/src/linux/crypto/skcipher.c deleted file mode 100644 index f7d0018..0000000 --- a/src/linux/crypto/skcipher.c +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Symmetric key cipher operations. - * - * Generic encrypt/decrypt wrapper for ciphers, handles operations across - * multiple page boundaries by using temporary blocks. In user context, - * the kernel is given a chance to schedule us once per page. - * - * Copyright (c) 2015 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -static unsigned int crypto_skcipher_extsize(struct crypto_alg *alg) -{ - if (alg->cra_type == &crypto_blkcipher_type) - return sizeof(struct crypto_blkcipher *); - - if (alg->cra_type == &crypto_ablkcipher_type || - alg->cra_type == &crypto_givcipher_type) - return sizeof(struct crypto_ablkcipher *); - - return crypto_alg_extsize(alg); -} - -static int skcipher_setkey_blkcipher(struct crypto_skcipher *tfm, - const u8 *key, unsigned int keylen) -{ - struct crypto_blkcipher **ctx = crypto_skcipher_ctx(tfm); - struct crypto_blkcipher *blkcipher = *ctx; - int err; - - crypto_blkcipher_clear_flags(blkcipher, ~0); - crypto_blkcipher_set_flags(blkcipher, crypto_skcipher_get_flags(tfm) & - CRYPTO_TFM_REQ_MASK); - err = crypto_blkcipher_setkey(blkcipher, key, keylen); - crypto_skcipher_set_flags(tfm, crypto_blkcipher_get_flags(blkcipher) & - CRYPTO_TFM_RES_MASK); - - return err; -} - -static int skcipher_crypt_blkcipher(struct skcipher_request *req, - int (*crypt)(struct blkcipher_desc *, - struct scatterlist *, - struct scatterlist *, - unsigned int)) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct crypto_blkcipher **ctx = crypto_skcipher_ctx(tfm); - struct blkcipher_desc desc = { - .tfm = *ctx, - .info = req->iv, - .flags = req->base.flags, - }; - - - return crypt(&desc, req->dst, req->src, req->cryptlen); -} - -static int skcipher_encrypt_blkcipher(struct skcipher_request *req) -{ - struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); - struct crypto_tfm *tfm = crypto_skcipher_tfm(skcipher); - struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; - - return skcipher_crypt_blkcipher(req, alg->encrypt); -} - -static int skcipher_decrypt_blkcipher(struct skcipher_request *req) -{ - struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); - struct crypto_tfm *tfm = crypto_skcipher_tfm(skcipher); - struct blkcipher_alg *alg = &tfm->__crt_alg->cra_blkcipher; - - return skcipher_crypt_blkcipher(req, alg->decrypt); -} - -static void crypto_exit_skcipher_ops_blkcipher(struct crypto_tfm *tfm) -{ - struct crypto_blkcipher **ctx = crypto_tfm_ctx(tfm); - - crypto_free_blkcipher(*ctx); -} - -static int crypto_init_skcipher_ops_blkcipher(struct crypto_tfm *tfm) -{ - struct crypto_alg *calg = tfm->__crt_alg; - struct crypto_skcipher *skcipher = __crypto_skcipher_cast(tfm); - struct crypto_blkcipher **ctx = crypto_tfm_ctx(tfm); - struct crypto_blkcipher *blkcipher; - struct crypto_tfm *btfm; - - if (!crypto_mod_get(calg)) - return -EAGAIN; - - btfm = __crypto_alloc_tfm(calg, CRYPTO_ALG_TYPE_BLKCIPHER, - CRYPTO_ALG_TYPE_MASK); - if (IS_ERR(btfm)) { - crypto_mod_put(calg); - return PTR_ERR(btfm); - } - - blkcipher = __crypto_blkcipher_cast(btfm); - *ctx = blkcipher; - tfm->exit = crypto_exit_skcipher_ops_blkcipher; - - skcipher->setkey = skcipher_setkey_blkcipher; - skcipher->encrypt = skcipher_encrypt_blkcipher; - skcipher->decrypt = skcipher_decrypt_blkcipher; - - skcipher->ivsize = crypto_blkcipher_ivsize(blkcipher); - skcipher->keysize = calg->cra_blkcipher.max_keysize; - - return 0; -} - -static int skcipher_setkey_ablkcipher(struct crypto_skcipher *tfm, - const u8 *key, unsigned int keylen) -{ - struct crypto_ablkcipher **ctx = crypto_skcipher_ctx(tfm); - struct crypto_ablkcipher *ablkcipher = *ctx; - int err; - - crypto_ablkcipher_clear_flags(ablkcipher, ~0); - crypto_ablkcipher_set_flags(ablkcipher, - crypto_skcipher_get_flags(tfm) & - CRYPTO_TFM_REQ_MASK); - err = crypto_ablkcipher_setkey(ablkcipher, key, keylen); - crypto_skcipher_set_flags(tfm, - crypto_ablkcipher_get_flags(ablkcipher) & - CRYPTO_TFM_RES_MASK); - - return err; -} - -static int skcipher_crypt_ablkcipher(struct skcipher_request *req, - int (*crypt)(struct ablkcipher_request *)) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - struct crypto_ablkcipher **ctx = crypto_skcipher_ctx(tfm); - struct ablkcipher_request *subreq = skcipher_request_ctx(req); - - ablkcipher_request_set_tfm(subreq, *ctx); - ablkcipher_request_set_callback(subreq, skcipher_request_flags(req), - req->base.complete, req->base.data); - ablkcipher_request_set_crypt(subreq, req->src, req->dst, req->cryptlen, - req->iv); - - return crypt(subreq); -} - -static int skcipher_encrypt_ablkcipher(struct skcipher_request *req) -{ - struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); - struct crypto_tfm *tfm = crypto_skcipher_tfm(skcipher); - struct ablkcipher_alg *alg = &tfm->__crt_alg->cra_ablkcipher; - - return skcipher_crypt_ablkcipher(req, alg->encrypt); -} - -static int skcipher_decrypt_ablkcipher(struct skcipher_request *req) -{ - struct crypto_skcipher *skcipher = crypto_skcipher_reqtfm(req); - struct crypto_tfm *tfm = crypto_skcipher_tfm(skcipher); - struct ablkcipher_alg *alg = &tfm->__crt_alg->cra_ablkcipher; - - return skcipher_crypt_ablkcipher(req, alg->decrypt); -} - -static void crypto_exit_skcipher_ops_ablkcipher(struct crypto_tfm *tfm) -{ - struct crypto_ablkcipher **ctx = crypto_tfm_ctx(tfm); - - crypto_free_ablkcipher(*ctx); -} - -static int crypto_init_skcipher_ops_ablkcipher(struct crypto_tfm *tfm) -{ - struct crypto_alg *calg = tfm->__crt_alg; - struct crypto_skcipher *skcipher = __crypto_skcipher_cast(tfm); - struct crypto_ablkcipher **ctx = crypto_tfm_ctx(tfm); - struct crypto_ablkcipher *ablkcipher; - struct crypto_tfm *abtfm; - - if (!crypto_mod_get(calg)) - return -EAGAIN; - - abtfm = __crypto_alloc_tfm(calg, 0, 0); - if (IS_ERR(abtfm)) { - crypto_mod_put(calg); - return PTR_ERR(abtfm); - } - - ablkcipher = __crypto_ablkcipher_cast(abtfm); - *ctx = ablkcipher; - tfm->exit = crypto_exit_skcipher_ops_ablkcipher; - - skcipher->setkey = skcipher_setkey_ablkcipher; - skcipher->encrypt = skcipher_encrypt_ablkcipher; - skcipher->decrypt = skcipher_decrypt_ablkcipher; - - skcipher->ivsize = crypto_ablkcipher_ivsize(ablkcipher); - skcipher->reqsize = crypto_ablkcipher_reqsize(ablkcipher) + - sizeof(struct ablkcipher_request); - skcipher->keysize = calg->cra_ablkcipher.max_keysize; - - return 0; -} - -static void crypto_skcipher_exit_tfm(struct crypto_tfm *tfm) -{ - struct crypto_skcipher *skcipher = __crypto_skcipher_cast(tfm); - struct skcipher_alg *alg = crypto_skcipher_alg(skcipher); - - alg->exit(skcipher); -} - -static int crypto_skcipher_init_tfm(struct crypto_tfm *tfm) -{ - struct crypto_skcipher *skcipher = __crypto_skcipher_cast(tfm); - struct skcipher_alg *alg = crypto_skcipher_alg(skcipher); - - if (tfm->__crt_alg->cra_type == &crypto_blkcipher_type) - return crypto_init_skcipher_ops_blkcipher(tfm); - - if (tfm->__crt_alg->cra_type == &crypto_ablkcipher_type || - tfm->__crt_alg->cra_type == &crypto_givcipher_type) - return crypto_init_skcipher_ops_ablkcipher(tfm); - - skcipher->setkey = alg->setkey; - skcipher->encrypt = alg->encrypt; - skcipher->decrypt = alg->decrypt; - skcipher->ivsize = alg->ivsize; - skcipher->keysize = alg->max_keysize; - - if (alg->exit) - skcipher->base.exit = crypto_skcipher_exit_tfm; - - if (alg->init) - return alg->init(skcipher); - - return 0; -} - -static void crypto_skcipher_free_instance(struct crypto_instance *inst) -{ - struct skcipher_instance *skcipher = - container_of(inst, struct skcipher_instance, s.base); - - skcipher->free(skcipher); -} - -static void crypto_skcipher_show(struct seq_file *m, struct crypto_alg *alg) - __attribute__ ((unused)); -static void crypto_skcipher_show(struct seq_file *m, struct crypto_alg *alg) -{ - struct skcipher_alg *skcipher = container_of(alg, struct skcipher_alg, - base); - - seq_printf(m, "type : skcipher\n"); - seq_printf(m, "async : %s\n", - alg->cra_flags & CRYPTO_ALG_ASYNC ? "yes" : "no"); - seq_printf(m, "blocksize : %u\n", alg->cra_blocksize); - seq_printf(m, "min keysize : %u\n", skcipher->min_keysize); - seq_printf(m, "max keysize : %u\n", skcipher->max_keysize); - seq_printf(m, "ivsize : %u\n", skcipher->ivsize); - seq_printf(m, "chunksize : %u\n", skcipher->chunksize); -} - -#ifdef CONFIG_NET -static int crypto_skcipher_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - struct crypto_report_blkcipher rblkcipher; - struct skcipher_alg *skcipher = container_of(alg, struct skcipher_alg, - base); - - strncpy(rblkcipher.type, "skcipher", sizeof(rblkcipher.type)); - strncpy(rblkcipher.geniv, "", sizeof(rblkcipher.geniv)); - - rblkcipher.blocksize = alg->cra_blocksize; - rblkcipher.min_keysize = skcipher->min_keysize; - rblkcipher.max_keysize = skcipher->max_keysize; - rblkcipher.ivsize = skcipher->ivsize; - - if (nla_put(skb, CRYPTOCFGA_REPORT_BLKCIPHER, - sizeof(struct crypto_report_blkcipher), &rblkcipher)) - goto nla_put_failure; - return 0; - -nla_put_failure: - return -EMSGSIZE; -} -#else -static int crypto_skcipher_report(struct sk_buff *skb, struct crypto_alg *alg) -{ - return -ENOSYS; -} -#endif - -static const struct crypto_type crypto_skcipher_type2 = { - .extsize = crypto_skcipher_extsize, - .init_tfm = crypto_skcipher_init_tfm, - .free = crypto_skcipher_free_instance, -#ifdef CONFIG_PROC_FS - .show = crypto_skcipher_show, -#endif - .report = crypto_skcipher_report, - .maskclear = ~CRYPTO_ALG_TYPE_MASK, - .maskset = CRYPTO_ALG_TYPE_BLKCIPHER_MASK, - .type = CRYPTO_ALG_TYPE_SKCIPHER, - .tfmsize = offsetof(struct crypto_skcipher, base), -}; - -int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, - const char *name, u32 type, u32 mask) -{ - spawn->base.frontend = &crypto_skcipher_type2; - return crypto_grab_spawn(&spawn->base, name, type, mask); -} -EXPORT_SYMBOL_GPL(crypto_grab_skcipher); - -struct crypto_skcipher *crypto_alloc_skcipher(const char *alg_name, - u32 type, u32 mask) -{ - return crypto_alloc_tfm(alg_name, &crypto_skcipher_type2, type, mask); -} -EXPORT_SYMBOL_GPL(crypto_alloc_skcipher); - -int crypto_has_skcipher2(const char *alg_name, u32 type, u32 mask) -{ - return crypto_type_has_alg(alg_name, &crypto_skcipher_type2, - type, mask); -} -EXPORT_SYMBOL_GPL(crypto_has_skcipher2); - -static int skcipher_prepare_alg(struct skcipher_alg *alg) -{ - struct crypto_alg *base = &alg->base; - - if (alg->ivsize > PAGE_SIZE / 8 || alg->chunksize > PAGE_SIZE / 8) - return -EINVAL; - - if (!alg->chunksize) - alg->chunksize = base->cra_blocksize; - - base->cra_type = &crypto_skcipher_type2; - base->cra_flags &= ~CRYPTO_ALG_TYPE_MASK; - base->cra_flags |= CRYPTO_ALG_TYPE_SKCIPHER; - - return 0; -} - -int crypto_register_skcipher(struct skcipher_alg *alg) -{ - struct crypto_alg *base = &alg->base; - int err; - - err = skcipher_prepare_alg(alg); - if (err) - return err; - - return crypto_register_alg(base); -} -EXPORT_SYMBOL_GPL(crypto_register_skcipher); - -void crypto_unregister_skcipher(struct skcipher_alg *alg) -{ - crypto_unregister_alg(&alg->base); -} -EXPORT_SYMBOL_GPL(crypto_unregister_skcipher); - -int crypto_register_skciphers(struct skcipher_alg *algs, int count) -{ - int i, ret; - - for (i = 0; i < count; i++) { - ret = crypto_register_skcipher(&algs[i]); - if (ret) - goto err; - } - - return 0; - -err: - for (--i; i >= 0; --i) - crypto_unregister_skcipher(&algs[i]); - - return ret; -} -EXPORT_SYMBOL_GPL(crypto_register_skciphers); - -void crypto_unregister_skciphers(struct skcipher_alg *algs, int count) -{ - int i; - - for (i = count - 1; i >= 0; --i) - crypto_unregister_skcipher(&algs[i]); -} -EXPORT_SYMBOL_GPL(crypto_unregister_skciphers); - -int skcipher_register_instance(struct crypto_template *tmpl, - struct skcipher_instance *inst) -{ - int err; - - err = skcipher_prepare_alg(&inst->alg); - if (err) - return err; - - return crypto_register_instance(tmpl, skcipher_crypto_instance(inst)); -} -EXPORT_SYMBOL_GPL(skcipher_register_instance); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Symmetric key cipher type"); diff --git a/src/linux/crypto/testmgr.c b/src/linux/crypto/testmgr.c deleted file mode 100644 index 62dffa0..0000000 --- a/src/linux/crypto/testmgr.c +++ /dev/null @@ -1,4198 +0,0 @@ -/* - * Algorithm testing framework and tests. - * - * Copyright (c) 2002 James Morris - * Copyright (c) 2002 Jean-Francois Dive - * Copyright (c) 2007 Nokia Siemens Networks - * Copyright (c) 2008 Herbert Xu - * - * Updated RFC4106 AES-GCM testing. - * Authors: Aidan O'Mahony (aidan.o.mahony@intel.com) - * Adrian Hoban - * Gabriele Paoloni - * Tadeusz Struk (tadeusz.struk@intel.com) - * Copyright (c) 2010, Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -static bool notests; -module_param(notests, bool, 0644); -MODULE_PARM_DESC(notests, "disable crypto self-tests"); - -#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS - -/* a perfect nop */ -int alg_test(const char *driver, const char *alg, u32 type, u32 mask) -{ - return 0; -} - -#else - -#include "testmgr.h" - -/* - * Need slab memory for testing (size in number of pages). - */ -#define XBUFSIZE 8 - -/* - * Indexes into the xbuf to simulate cross-page access. - */ -#define IDX1 32 -#define IDX2 32400 -#define IDX3 1 -#define IDX4 8193 -#define IDX5 22222 -#define IDX6 17101 -#define IDX7 27333 -#define IDX8 3000 - -/* -* Used by test_cipher() -*/ -#define ENCRYPT 1 -#define DECRYPT 0 - -struct tcrypt_result { - struct completion completion; - int err; -}; - -struct aead_test_suite { - struct { - struct aead_testvec *vecs; - unsigned int count; - } enc, dec; -}; - -struct cipher_test_suite { - struct { - struct cipher_testvec *vecs; - unsigned int count; - } enc, dec; -}; - -struct comp_test_suite { - struct { - struct comp_testvec *vecs; - unsigned int count; - } comp, decomp; -}; - -struct hash_test_suite { - struct hash_testvec *vecs; - unsigned int count; -}; - -struct cprng_test_suite { - struct cprng_testvec *vecs; - unsigned int count; -}; - -struct drbg_test_suite { - struct drbg_testvec *vecs; - unsigned int count; -}; - -struct akcipher_test_suite { - struct akcipher_testvec *vecs; - unsigned int count; -}; - -struct kpp_test_suite { - struct kpp_testvec *vecs; - unsigned int count; -}; - -struct alg_test_desc { - const char *alg; - int (*test)(const struct alg_test_desc *desc, const char *driver, - u32 type, u32 mask); - int fips_allowed; /* set if alg is allowed in fips mode */ - - union { - struct aead_test_suite aead; - struct cipher_test_suite cipher; - struct comp_test_suite comp; - struct hash_test_suite hash; - struct cprng_test_suite cprng; - struct drbg_test_suite drbg; - struct akcipher_test_suite akcipher; - struct kpp_test_suite kpp; - } suite; -}; - -static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 }; - -static void hexdump(unsigned char *buf, unsigned int len) -{ - print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET, - 16, 1, - buf, len, false); -} - -static void tcrypt_complete(struct crypto_async_request *req, int err) -{ - struct tcrypt_result *res = req->data; - - if (err == -EINPROGRESS) - return; - - res->err = err; - complete(&res->completion); -} - -static int testmgr_alloc_buf(char *buf[XBUFSIZE]) -{ - int i; - - for (i = 0; i < XBUFSIZE; i++) { - buf[i] = (void *)__get_free_page(GFP_KERNEL); - if (!buf[i]) - goto err_free_buf; - } - - return 0; - -err_free_buf: - while (i-- > 0) - free_page((unsigned long)buf[i]); - - return -ENOMEM; -} - -static void testmgr_free_buf(char *buf[XBUFSIZE]) -{ - int i; - - for (i = 0; i < XBUFSIZE; i++) - free_page((unsigned long)buf[i]); -} - -static int wait_async_op(struct tcrypt_result *tr, int ret) -{ - if (ret == -EINPROGRESS || ret == -EBUSY) { - wait_for_completion(&tr->completion); - reinit_completion(&tr->completion); - ret = tr->err; - } - return ret; -} - -static int ahash_partial_update(struct ahash_request **preq, - struct crypto_ahash *tfm, struct hash_testvec *template, - void *hash_buff, int k, int temp, struct scatterlist *sg, - const char *algo, char *result, struct tcrypt_result *tresult) -{ - char *state; - struct ahash_request *req; - int statesize, ret = -EINVAL; - const char guard[] = { 0x00, 0xba, 0xad, 0x00 }; - - req = *preq; - statesize = crypto_ahash_statesize( - crypto_ahash_reqtfm(req)); - state = kmalloc(statesize + sizeof(guard), GFP_KERNEL); - if (!state) { - pr_err("alt: hash: Failed to alloc state for %s\n", algo); - goto out_nostate; - } - memcpy(state + statesize, guard, sizeof(guard)); - ret = crypto_ahash_export(req, state); - WARN_ON(memcmp(state + statesize, guard, sizeof(guard))); - if (ret) { - pr_err("alt: hash: Failed to export() for %s\n", algo); - goto out; - } - ahash_request_free(req); - req = ahash_request_alloc(tfm, GFP_KERNEL); - if (!req) { - pr_err("alg: hash: Failed to alloc request for %s\n", algo); - goto out_noreq; - } - ahash_request_set_callback(req, - CRYPTO_TFM_REQ_MAY_BACKLOG, - tcrypt_complete, tresult); - - memcpy(hash_buff, template->plaintext + temp, - template->tap[k]); - sg_init_one(&sg[0], hash_buff, template->tap[k]); - ahash_request_set_crypt(req, sg, result, template->tap[k]); - ret = crypto_ahash_import(req, state); - if (ret) { - pr_err("alg: hash: Failed to import() for %s\n", algo); - goto out; - } - ret = wait_async_op(tresult, crypto_ahash_update(req)); - if (ret) - goto out; - *preq = req; - ret = 0; - goto out_noreq; -out: - ahash_request_free(req); -out_noreq: - kfree(state); -out_nostate: - return ret; -} - -static int __test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, - unsigned int tcount, bool use_digest, - const int align_offset) -{ - const char *algo = crypto_tfm_alg_driver_name(crypto_ahash_tfm(tfm)); - unsigned int i, j, k, temp; - struct scatterlist sg[8]; - char *result; - char *key; - struct ahash_request *req; - struct tcrypt_result tresult; - void *hash_buff; - char *xbuf[XBUFSIZE]; - int ret = -ENOMEM; - - result = kmalloc(MAX_DIGEST_SIZE, GFP_KERNEL); - if (!result) - return ret; - key = kmalloc(MAX_KEYLEN, GFP_KERNEL); - if (!key) - goto out_nobuf; - if (testmgr_alloc_buf(xbuf)) - goto out_nobuf; - - init_completion(&tresult.completion); - - req = ahash_request_alloc(tfm, GFP_KERNEL); - if (!req) { - printk(KERN_ERR "alg: hash: Failed to allocate request for " - "%s\n", algo); - goto out_noreq; - } - ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, - tcrypt_complete, &tresult); - - j = 0; - for (i = 0; i < tcount; i++) { - if (template[i].np) - continue; - - ret = -EINVAL; - if (WARN_ON(align_offset + template[i].psize > PAGE_SIZE)) - goto out; - - j++; - memset(result, 0, MAX_DIGEST_SIZE); - - hash_buff = xbuf[0]; - hash_buff += align_offset; - - memcpy(hash_buff, template[i].plaintext, template[i].psize); - sg_init_one(&sg[0], hash_buff, template[i].psize); - - if (template[i].ksize) { - crypto_ahash_clear_flags(tfm, ~0); - if (template[i].ksize > MAX_KEYLEN) { - pr_err("alg: hash: setkey failed on test %d for %s: key size %d > %d\n", - j, algo, template[i].ksize, MAX_KEYLEN); - ret = -EINVAL; - goto out; - } - memcpy(key, template[i].key, template[i].ksize); - ret = crypto_ahash_setkey(tfm, key, template[i].ksize); - if (ret) { - printk(KERN_ERR "alg: hash: setkey failed on " - "test %d for %s: ret=%d\n", j, algo, - -ret); - goto out; - } - } - - ahash_request_set_crypt(req, sg, result, template[i].psize); - if (use_digest) { - ret = wait_async_op(&tresult, crypto_ahash_digest(req)); - if (ret) { - pr_err("alg: hash: digest failed on test %d " - "for %s: ret=%d\n", j, algo, -ret); - goto out; - } - } else { - ret = wait_async_op(&tresult, crypto_ahash_init(req)); - if (ret) { - pr_err("alt: hash: init failed on test %d " - "for %s: ret=%d\n", j, algo, -ret); - goto out; - } - ret = wait_async_op(&tresult, crypto_ahash_update(req)); - if (ret) { - pr_err("alt: hash: update failed on test %d " - "for %s: ret=%d\n", j, algo, -ret); - goto out; - } - ret = wait_async_op(&tresult, crypto_ahash_final(req)); - if (ret) { - pr_err("alt: hash: final failed on test %d " - "for %s: ret=%d\n", j, algo, -ret); - goto out; - } - } - - if (memcmp(result, template[i].digest, - crypto_ahash_digestsize(tfm))) { - printk(KERN_ERR "alg: hash: Test %d failed for %s\n", - j, algo); - hexdump(result, crypto_ahash_digestsize(tfm)); - ret = -EINVAL; - goto out; - } - } - - j = 0; - for (i = 0; i < tcount; i++) { - /* alignment tests are only done with continuous buffers */ - if (align_offset != 0) - break; - - if (!template[i].np) - continue; - - j++; - memset(result, 0, MAX_DIGEST_SIZE); - - temp = 0; - sg_init_table(sg, template[i].np); - ret = -EINVAL; - for (k = 0; k < template[i].np; k++) { - if (WARN_ON(offset_in_page(IDX[k]) + - template[i].tap[k] > PAGE_SIZE)) - goto out; - sg_set_buf(&sg[k], - memcpy(xbuf[IDX[k] >> PAGE_SHIFT] + - offset_in_page(IDX[k]), - template[i].plaintext + temp, - template[i].tap[k]), - template[i].tap[k]); - temp += template[i].tap[k]; - } - - if (template[i].ksize) { - if (template[i].ksize > MAX_KEYLEN) { - pr_err("alg: hash: setkey failed on test %d for %s: key size %d > %d\n", - j, algo, template[i].ksize, MAX_KEYLEN); - ret = -EINVAL; - goto out; - } - crypto_ahash_clear_flags(tfm, ~0); - memcpy(key, template[i].key, template[i].ksize); - ret = crypto_ahash_setkey(tfm, key, template[i].ksize); - - if (ret) { - printk(KERN_ERR "alg: hash: setkey " - "failed on chunking test %d " - "for %s: ret=%d\n", j, algo, -ret); - goto out; - } - } - - ahash_request_set_crypt(req, sg, result, template[i].psize); - ret = crypto_ahash_digest(req); - switch (ret) { - case 0: - break; - case -EINPROGRESS: - case -EBUSY: - wait_for_completion(&tresult.completion); - reinit_completion(&tresult.completion); - ret = tresult.err; - if (!ret) - break; - /* fall through */ - default: - printk(KERN_ERR "alg: hash: digest failed " - "on chunking test %d for %s: " - "ret=%d\n", j, algo, -ret); - goto out; - } - - if (memcmp(result, template[i].digest, - crypto_ahash_digestsize(tfm))) { - printk(KERN_ERR "alg: hash: Chunking test %d " - "failed for %s\n", j, algo); - hexdump(result, crypto_ahash_digestsize(tfm)); - ret = -EINVAL; - goto out; - } - } - - /* partial update exercise */ - j = 0; - for (i = 0; i < tcount; i++) { - /* alignment tests are only done with continuous buffers */ - if (align_offset != 0) - break; - - if (template[i].np < 2) - continue; - - j++; - memset(result, 0, MAX_DIGEST_SIZE); - - ret = -EINVAL; - hash_buff = xbuf[0]; - memcpy(hash_buff, template[i].plaintext, - template[i].tap[0]); - sg_init_one(&sg[0], hash_buff, template[i].tap[0]); - - if (template[i].ksize) { - crypto_ahash_clear_flags(tfm, ~0); - if (template[i].ksize > MAX_KEYLEN) { - pr_err("alg: hash: setkey failed on test %d for %s: key size %d > %d\n", - j, algo, template[i].ksize, MAX_KEYLEN); - ret = -EINVAL; - goto out; - } - memcpy(key, template[i].key, template[i].ksize); - ret = crypto_ahash_setkey(tfm, key, template[i].ksize); - if (ret) { - pr_err("alg: hash: setkey failed on test %d for %s: ret=%d\n", - j, algo, -ret); - goto out; - } - } - - ahash_request_set_crypt(req, sg, result, template[i].tap[0]); - ret = wait_async_op(&tresult, crypto_ahash_init(req)); - if (ret) { - pr_err("alt: hash: init failed on test %d for %s: ret=%d\n", - j, algo, -ret); - goto out; - } - ret = wait_async_op(&tresult, crypto_ahash_update(req)); - if (ret) { - pr_err("alt: hash: update failed on test %d for %s: ret=%d\n", - j, algo, -ret); - goto out; - } - - temp = template[i].tap[0]; - for (k = 1; k < template[i].np; k++) { - ret = ahash_partial_update(&req, tfm, &template[i], - hash_buff, k, temp, &sg[0], algo, result, - &tresult); - if (ret) { - pr_err("hash: partial update failed on test %d for %s: ret=%d\n", - j, algo, -ret); - goto out_noreq; - } - temp += template[i].tap[k]; - } - ret = wait_async_op(&tresult, crypto_ahash_final(req)); - if (ret) { - pr_err("alt: hash: final failed on test %d for %s: ret=%d\n", - j, algo, -ret); - goto out; - } - if (memcmp(result, template[i].digest, - crypto_ahash_digestsize(tfm))) { - pr_err("alg: hash: Partial Test %d failed for %s\n", - j, algo); - hexdump(result, crypto_ahash_digestsize(tfm)); - ret = -EINVAL; - goto out; - } - } - - ret = 0; - -out: - ahash_request_free(req); -out_noreq: - testmgr_free_buf(xbuf); -out_nobuf: - kfree(key); - kfree(result); - return ret; -} - -static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template, - unsigned int tcount, bool use_digest) -{ - unsigned int alignmask; - int ret; - - ret = __test_hash(tfm, template, tcount, use_digest, 0); - if (ret) - return ret; - - /* test unaligned buffers, check with one byte offset */ - ret = __test_hash(tfm, template, tcount, use_digest, 1); - if (ret) - return ret; - - alignmask = crypto_tfm_alg_alignmask(&tfm->base); - if (alignmask) { - /* Check if alignment mask for tfm is correctly set. */ - ret = __test_hash(tfm, template, tcount, use_digest, - alignmask + 1); - if (ret) - return ret; - } - - return 0; -} - -static int __test_aead(struct crypto_aead *tfm, int enc, - struct aead_testvec *template, unsigned int tcount, - const bool diff_dst, const int align_offset) -{ - const char *algo = crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm)); - unsigned int i, j, k, n, temp; - int ret = -ENOMEM; - char *q; - char *key; - struct aead_request *req; - struct scatterlist *sg; - struct scatterlist *sgout; - const char *e, *d; - struct tcrypt_result result; - unsigned int authsize, iv_len; - void *input; - void *output; - void *assoc; - char *iv; - char *xbuf[XBUFSIZE]; - char *xoutbuf[XBUFSIZE]; - char *axbuf[XBUFSIZE]; - - iv = kzalloc(MAX_IVLEN, GFP_KERNEL); - if (!iv) - return ret; - key = kmalloc(MAX_KEYLEN, GFP_KERNEL); - if (!key) - goto out_noxbuf; - if (testmgr_alloc_buf(xbuf)) - goto out_noxbuf; - if (testmgr_alloc_buf(axbuf)) - goto out_noaxbuf; - if (diff_dst && testmgr_alloc_buf(xoutbuf)) - goto out_nooutbuf; - - /* avoid "the frame size is larger than 1024 bytes" compiler warning */ - sg = kmalloc(sizeof(*sg) * 8 * (diff_dst ? 4 : 2), GFP_KERNEL); - if (!sg) - goto out_nosg; - sgout = &sg[16]; - - if (diff_dst) - d = "-ddst"; - else - d = ""; - - if (enc == ENCRYPT) - e = "encryption"; - else - e = "decryption"; - - init_completion(&result.completion); - - req = aead_request_alloc(tfm, GFP_KERNEL); - if (!req) { - pr_err("alg: aead%s: Failed to allocate request for %s\n", - d, algo); - goto out; - } - - aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, - tcrypt_complete, &result); - - iv_len = crypto_aead_ivsize(tfm); - - for (i = 0, j = 0; i < tcount; i++) { - if (template[i].np) - continue; - - j++; - - /* some templates have no input data but they will - * touch input - */ - input = xbuf[0]; - input += align_offset; - assoc = axbuf[0]; - - ret = -EINVAL; - if (WARN_ON(align_offset + template[i].ilen > - PAGE_SIZE || template[i].alen > PAGE_SIZE)) - goto out; - - memcpy(input, template[i].input, template[i].ilen); - memcpy(assoc, template[i].assoc, template[i].alen); - if (template[i].iv) - memcpy(iv, template[i].iv, iv_len); - else - memset(iv, 0, iv_len); - - crypto_aead_clear_flags(tfm, ~0); - if (template[i].wk) - crypto_aead_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY); - - if (template[i].klen > MAX_KEYLEN) { - pr_err("alg: aead%s: setkey failed on test %d for %s: key size %d > %d\n", - d, j, algo, template[i].klen, - MAX_KEYLEN); - ret = -EINVAL; - goto out; - } - memcpy(key, template[i].key, template[i].klen); - - ret = crypto_aead_setkey(tfm, key, template[i].klen); - if (template[i].fail == !ret) { - pr_err("alg: aead%s: setkey failed on test %d for %s: flags=%x\n", - d, j, algo, crypto_aead_get_flags(tfm)); - goto out; - } else if (ret) - continue; - - authsize = abs(template[i].rlen - template[i].ilen); - ret = crypto_aead_setauthsize(tfm, authsize); - if (ret) { - pr_err("alg: aead%s: Failed to set authsize to %u on test %d for %s\n", - d, authsize, j, algo); - goto out; - } - - k = !!template[i].alen; - sg_init_table(sg, k + 1); - sg_set_buf(&sg[0], assoc, template[i].alen); - sg_set_buf(&sg[k], input, - template[i].ilen + (enc ? authsize : 0)); - output = input; - - if (diff_dst) { - sg_init_table(sgout, k + 1); - sg_set_buf(&sgout[0], assoc, template[i].alen); - - output = xoutbuf[0]; - output += align_offset; - sg_set_buf(&sgout[k], output, - template[i].rlen + (enc ? 0 : authsize)); - } - - aead_request_set_crypt(req, sg, (diff_dst) ? sgout : sg, - template[i].ilen, iv); - - aead_request_set_ad(req, template[i].alen); - - ret = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req); - - switch (ret) { - case 0: - if (template[i].novrfy) { - /* verification was supposed to fail */ - pr_err("alg: aead%s: %s failed on test %d for %s: ret was 0, expected -EBADMSG\n", - d, e, j, algo); - /* so really, we got a bad message */ - ret = -EBADMSG; - goto out; - } - break; - case -EINPROGRESS: - case -EBUSY: - wait_for_completion(&result.completion); - reinit_completion(&result.completion); - ret = result.err; - if (!ret) - break; - case -EBADMSG: - if (template[i].novrfy) - /* verification failure was expected */ - continue; - /* fall through */ - default: - pr_err("alg: aead%s: %s failed on test %d for %s: ret=%d\n", - d, e, j, algo, -ret); - goto out; - } - - q = output; - if (memcmp(q, template[i].result, template[i].rlen)) { - pr_err("alg: aead%s: Test %d failed on %s for %s\n", - d, j, e, algo); - hexdump(q, template[i].rlen); - ret = -EINVAL; - goto out; - } - } - - for (i = 0, j = 0; i < tcount; i++) { - /* alignment tests are only done with continuous buffers */ - if (align_offset != 0) - break; - - if (!template[i].np) - continue; - - j++; - - if (template[i].iv) - memcpy(iv, template[i].iv, iv_len); - else - memset(iv, 0, MAX_IVLEN); - - crypto_aead_clear_flags(tfm, ~0); - if (template[i].wk) - crypto_aead_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY); - if (template[i].klen > MAX_KEYLEN) { - pr_err("alg: aead%s: setkey failed on test %d for %s: key size %d > %d\n", - d, j, algo, template[i].klen, MAX_KEYLEN); - ret = -EINVAL; - goto out; - } - memcpy(key, template[i].key, template[i].klen); - - ret = crypto_aead_setkey(tfm, key, template[i].klen); - if (template[i].fail == !ret) { - pr_err("alg: aead%s: setkey failed on chunk test %d for %s: flags=%x\n", - d, j, algo, crypto_aead_get_flags(tfm)); - goto out; - } else if (ret) - continue; - - authsize = abs(template[i].rlen - template[i].ilen); - - ret = -EINVAL; - sg_init_table(sg, template[i].anp + template[i].np); - if (diff_dst) - sg_init_table(sgout, template[i].anp + template[i].np); - - ret = -EINVAL; - for (k = 0, temp = 0; k < template[i].anp; k++) { - if (WARN_ON(offset_in_page(IDX[k]) + - template[i].atap[k] > PAGE_SIZE)) - goto out; - sg_set_buf(&sg[k], - memcpy(axbuf[IDX[k] >> PAGE_SHIFT] + - offset_in_page(IDX[k]), - template[i].assoc + temp, - template[i].atap[k]), - template[i].atap[k]); - if (diff_dst) - sg_set_buf(&sgout[k], - axbuf[IDX[k] >> PAGE_SHIFT] + - offset_in_page(IDX[k]), - template[i].atap[k]); - temp += template[i].atap[k]; - } - - for (k = 0, temp = 0; k < template[i].np; k++) { - if (WARN_ON(offset_in_page(IDX[k]) + - template[i].tap[k] > PAGE_SIZE)) - goto out; - - q = xbuf[IDX[k] >> PAGE_SHIFT] + offset_in_page(IDX[k]); - memcpy(q, template[i].input + temp, template[i].tap[k]); - sg_set_buf(&sg[template[i].anp + k], - q, template[i].tap[k]); - - if (diff_dst) { - q = xoutbuf[IDX[k] >> PAGE_SHIFT] + - offset_in_page(IDX[k]); - - memset(q, 0, template[i].tap[k]); - - sg_set_buf(&sgout[template[i].anp + k], - q, template[i].tap[k]); - } - - n = template[i].tap[k]; - if (k == template[i].np - 1 && enc) - n += authsize; - if (offset_in_page(q) + n < PAGE_SIZE) - q[n] = 0; - - temp += template[i].tap[k]; - } - - ret = crypto_aead_setauthsize(tfm, authsize); - if (ret) { - pr_err("alg: aead%s: Failed to set authsize to %u on chunk test %d for %s\n", - d, authsize, j, algo); - goto out; - } - - if (enc) { - if (WARN_ON(sg[template[i].anp + k - 1].offset + - sg[template[i].anp + k - 1].length + - authsize > PAGE_SIZE)) { - ret = -EINVAL; - goto out; - } - - if (diff_dst) - sgout[template[i].anp + k - 1].length += - authsize; - sg[template[i].anp + k - 1].length += authsize; - } - - aead_request_set_crypt(req, sg, (diff_dst) ? sgout : sg, - template[i].ilen, - iv); - - aead_request_set_ad(req, template[i].alen); - - ret = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req); - - switch (ret) { - case 0: - if (template[i].novrfy) { - /* verification was supposed to fail */ - pr_err("alg: aead%s: %s failed on chunk test %d for %s: ret was 0, expected -EBADMSG\n", - d, e, j, algo); - /* so really, we got a bad message */ - ret = -EBADMSG; - goto out; - } - break; - case -EINPROGRESS: - case -EBUSY: - wait_for_completion(&result.completion); - reinit_completion(&result.completion); - ret = result.err; - if (!ret) - break; - case -EBADMSG: - if (template[i].novrfy) - /* verification failure was expected */ - continue; - /* fall through */ - default: - pr_err("alg: aead%s: %s failed on chunk test %d for %s: ret=%d\n", - d, e, j, algo, -ret); - goto out; - } - - ret = -EINVAL; - for (k = 0, temp = 0; k < template[i].np; k++) { - if (diff_dst) - q = xoutbuf[IDX[k] >> PAGE_SHIFT] + - offset_in_page(IDX[k]); - else - q = xbuf[IDX[k] >> PAGE_SHIFT] + - offset_in_page(IDX[k]); - - n = template[i].tap[k]; - if (k == template[i].np - 1) - n += enc ? authsize : -authsize; - - if (memcmp(q, template[i].result + temp, n)) { - pr_err("alg: aead%s: Chunk test %d failed on %s at page %u for %s\n", - d, j, e, k, algo); - hexdump(q, n); - goto out; - } - - q += n; - if (k == template[i].np - 1 && !enc) { - if (!diff_dst && - memcmp(q, template[i].input + - temp + n, authsize)) - n = authsize; - else - n = 0; - } else { - for (n = 0; offset_in_page(q + n) && q[n]; n++) - ; - } - if (n) { - pr_err("alg: aead%s: Result buffer corruption in chunk test %d on %s at page %u for %s: %u bytes:\n", - d, j, e, k, algo, n); - hexdump(q, n); - goto out; - } - - temp += template[i].tap[k]; - } - } - - ret = 0; - -out: - aead_request_free(req); - kfree(sg); -out_nosg: - if (diff_dst) - testmgr_free_buf(xoutbuf); -out_nooutbuf: - testmgr_free_buf(axbuf); -out_noaxbuf: - testmgr_free_buf(xbuf); -out_noxbuf: - kfree(key); - kfree(iv); - return ret; -} - -static int test_aead(struct crypto_aead *tfm, int enc, - struct aead_testvec *template, unsigned int tcount) -{ - unsigned int alignmask; - int ret; - - /* test 'dst == src' case */ - ret = __test_aead(tfm, enc, template, tcount, false, 0); - if (ret) - return ret; - - /* test 'dst != src' case */ - ret = __test_aead(tfm, enc, template, tcount, true, 0); - if (ret) - return ret; - - /* test unaligned buffers, check with one byte offset */ - ret = __test_aead(tfm, enc, template, tcount, true, 1); - if (ret) - return ret; - - alignmask = crypto_tfm_alg_alignmask(&tfm->base); - if (alignmask) { - /* Check if alignment mask for tfm is correctly set. */ - ret = __test_aead(tfm, enc, template, tcount, true, - alignmask + 1); - if (ret) - return ret; - } - - return 0; -} - -static int test_cipher(struct crypto_cipher *tfm, int enc, - struct cipher_testvec *template, unsigned int tcount) -{ - const char *algo = crypto_tfm_alg_driver_name(crypto_cipher_tfm(tfm)); - unsigned int i, j, k; - char *q; - const char *e; - void *data; - char *xbuf[XBUFSIZE]; - int ret = -ENOMEM; - - if (testmgr_alloc_buf(xbuf)) - goto out_nobuf; - - if (enc == ENCRYPT) - e = "encryption"; - else - e = "decryption"; - - j = 0; - for (i = 0; i < tcount; i++) { - if (template[i].np) - continue; - - if (fips_enabled && template[i].fips_skip) - continue; - - j++; - - ret = -EINVAL; - if (WARN_ON(template[i].ilen > PAGE_SIZE)) - goto out; - - data = xbuf[0]; - memcpy(data, template[i].input, template[i].ilen); - - crypto_cipher_clear_flags(tfm, ~0); - if (template[i].wk) - crypto_cipher_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY); - - ret = crypto_cipher_setkey(tfm, template[i].key, - template[i].klen); - if (template[i].fail == !ret) { - printk(KERN_ERR "alg: cipher: setkey failed " - "on test %d for %s: flags=%x\n", j, - algo, crypto_cipher_get_flags(tfm)); - goto out; - } else if (ret) - continue; - - for (k = 0; k < template[i].ilen; - k += crypto_cipher_blocksize(tfm)) { - if (enc) - crypto_cipher_encrypt_one(tfm, data + k, - data + k); - else - crypto_cipher_decrypt_one(tfm, data + k, - data + k); - } - - q = data; - if (memcmp(q, template[i].result, template[i].rlen)) { - printk(KERN_ERR "alg: cipher: Test %d failed " - "on %s for %s\n", j, e, algo); - hexdump(q, template[i].rlen); - ret = -EINVAL; - goto out; - } - } - - ret = 0; - -out: - testmgr_free_buf(xbuf); -out_nobuf: - return ret; -} - -static int __test_skcipher(struct crypto_skcipher *tfm, int enc, - struct cipher_testvec *template, unsigned int tcount, - const bool diff_dst, const int align_offset) -{ - const char *algo = - crypto_tfm_alg_driver_name(crypto_skcipher_tfm(tfm)); - unsigned int i, j, k, n, temp; - char *q; - struct skcipher_request *req; - struct scatterlist sg[8]; - struct scatterlist sgout[8]; - const char *e, *d; - struct tcrypt_result result; - void *data; - char iv[MAX_IVLEN]; - char *xbuf[XBUFSIZE]; - char *xoutbuf[XBUFSIZE]; - int ret = -ENOMEM; - unsigned int ivsize = crypto_skcipher_ivsize(tfm); - - if (testmgr_alloc_buf(xbuf)) - goto out_nobuf; - - if (diff_dst && testmgr_alloc_buf(xoutbuf)) - goto out_nooutbuf; - - if (diff_dst) - d = "-ddst"; - else - d = ""; - - if (enc == ENCRYPT) - e = "encryption"; - else - e = "decryption"; - - init_completion(&result.completion); - - req = skcipher_request_alloc(tfm, GFP_KERNEL); - if (!req) { - pr_err("alg: skcipher%s: Failed to allocate request for %s\n", - d, algo); - goto out; - } - - skcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, - tcrypt_complete, &result); - - j = 0; - for (i = 0; i < tcount; i++) { - if (template[i].np && !template[i].also_non_np) - continue; - - if (fips_enabled && template[i].fips_skip) - continue; - - if (template[i].iv) - memcpy(iv, template[i].iv, ivsize); - else - memset(iv, 0, MAX_IVLEN); - - j++; - ret = -EINVAL; - if (WARN_ON(align_offset + template[i].ilen > PAGE_SIZE)) - goto out; - - data = xbuf[0]; - data += align_offset; - memcpy(data, template[i].input, template[i].ilen); - - crypto_skcipher_clear_flags(tfm, ~0); - if (template[i].wk) - crypto_skcipher_set_flags(tfm, - CRYPTO_TFM_REQ_WEAK_KEY); - - ret = crypto_skcipher_setkey(tfm, template[i].key, - template[i].klen); - if (template[i].fail == !ret) { - pr_err("alg: skcipher%s: setkey failed on test %d for %s: flags=%x\n", - d, j, algo, crypto_skcipher_get_flags(tfm)); - goto out; - } else if (ret) - continue; - - sg_init_one(&sg[0], data, template[i].ilen); - if (diff_dst) { - data = xoutbuf[0]; - data += align_offset; - sg_init_one(&sgout[0], data, template[i].ilen); - } - - skcipher_request_set_crypt(req, sg, (diff_dst) ? sgout : sg, - template[i].ilen, iv); - ret = enc ? crypto_skcipher_encrypt(req) : - crypto_skcipher_decrypt(req); - - switch (ret) { - case 0: - break; - case -EINPROGRESS: - case -EBUSY: - wait_for_completion(&result.completion); - reinit_completion(&result.completion); - ret = result.err; - if (!ret) - break; - /* fall through */ - default: - pr_err("alg: skcipher%s: %s failed on test %d for %s: ret=%d\n", - d, e, j, algo, -ret); - goto out; - } - - q = data; - if (memcmp(q, template[i].result, template[i].rlen)) { - pr_err("alg: skcipher%s: Test %d failed (invalid result) on %s for %s\n", - d, j, e, algo); - hexdump(q, template[i].rlen); - ret = -EINVAL; - goto out; - } - - if (template[i].iv_out && - memcmp(iv, template[i].iv_out, - crypto_skcipher_ivsize(tfm))) { - pr_err("alg: skcipher%s: Test %d failed (invalid output IV) on %s for %s\n", - d, j, e, algo); - hexdump(iv, crypto_skcipher_ivsize(tfm)); - ret = -EINVAL; - goto out; - } - } - - j = 0; - for (i = 0; i < tcount; i++) { - /* alignment tests are only done with continuous buffers */ - if (align_offset != 0) - break; - - if (!template[i].np) - continue; - - if (fips_enabled && template[i].fips_skip) - continue; - - if (template[i].iv) - memcpy(iv, template[i].iv, ivsize); - else - memset(iv, 0, MAX_IVLEN); - - j++; - crypto_skcipher_clear_flags(tfm, ~0); - if (template[i].wk) - crypto_skcipher_set_flags(tfm, - CRYPTO_TFM_REQ_WEAK_KEY); - - ret = crypto_skcipher_setkey(tfm, template[i].key, - template[i].klen); - if (template[i].fail == !ret) { - pr_err("alg: skcipher%s: setkey failed on chunk test %d for %s: flags=%x\n", - d, j, algo, crypto_skcipher_get_flags(tfm)); - goto out; - } else if (ret) - continue; - - temp = 0; - ret = -EINVAL; - sg_init_table(sg, template[i].np); - if (diff_dst) - sg_init_table(sgout, template[i].np); - for (k = 0; k < template[i].np; k++) { - if (WARN_ON(offset_in_page(IDX[k]) + - template[i].tap[k] > PAGE_SIZE)) - goto out; - - q = xbuf[IDX[k] >> PAGE_SHIFT] + offset_in_page(IDX[k]); - - memcpy(q, template[i].input + temp, template[i].tap[k]); - - if (offset_in_page(q) + template[i].tap[k] < PAGE_SIZE) - q[template[i].tap[k]] = 0; - - sg_set_buf(&sg[k], q, template[i].tap[k]); - if (diff_dst) { - q = xoutbuf[IDX[k] >> PAGE_SHIFT] + - offset_in_page(IDX[k]); - - sg_set_buf(&sgout[k], q, template[i].tap[k]); - - memset(q, 0, template[i].tap[k]); - if (offset_in_page(q) + - template[i].tap[k] < PAGE_SIZE) - q[template[i].tap[k]] = 0; - } - - temp += template[i].tap[k]; - } - - skcipher_request_set_crypt(req, sg, (diff_dst) ? sgout : sg, - template[i].ilen, iv); - - ret = enc ? crypto_skcipher_encrypt(req) : - crypto_skcipher_decrypt(req); - - switch (ret) { - case 0: - break; - case -EINPROGRESS: - case -EBUSY: - wait_for_completion(&result.completion); - reinit_completion(&result.completion); - ret = result.err; - if (!ret) - break; - /* fall through */ - default: - pr_err("alg: skcipher%s: %s failed on chunk test %d for %s: ret=%d\n", - d, e, j, algo, -ret); - goto out; - } - - temp = 0; - ret = -EINVAL; - for (k = 0; k < template[i].np; k++) { - if (diff_dst) - q = xoutbuf[IDX[k] >> PAGE_SHIFT] + - offset_in_page(IDX[k]); - else - q = xbuf[IDX[k] >> PAGE_SHIFT] + - offset_in_page(IDX[k]); - - if (memcmp(q, template[i].result + temp, - template[i].tap[k])) { - pr_err("alg: skcipher%s: Chunk test %d failed on %s at page %u for %s\n", - d, j, e, k, algo); - hexdump(q, template[i].tap[k]); - goto out; - } - - q += template[i].tap[k]; - for (n = 0; offset_in_page(q + n) && q[n]; n++) - ; - if (n) { - pr_err("alg: skcipher%s: Result buffer corruption in chunk test %d on %s at page %u for %s: %u bytes:\n", - d, j, e, k, algo, n); - hexdump(q, n); - goto out; - } - temp += template[i].tap[k]; - } - } - - ret = 0; - -out: - skcipher_request_free(req); - if (diff_dst) - testmgr_free_buf(xoutbuf); -out_nooutbuf: - testmgr_free_buf(xbuf); -out_nobuf: - return ret; -} - -static int test_skcipher(struct crypto_skcipher *tfm, int enc, - struct cipher_testvec *template, unsigned int tcount) -{ - unsigned int alignmask; - int ret; - - /* test 'dst == src' case */ - ret = __test_skcipher(tfm, enc, template, tcount, false, 0); - if (ret) - return ret; - - /* test 'dst != src' case */ - ret = __test_skcipher(tfm, enc, template, tcount, true, 0); - if (ret) - return ret; - - /* test unaligned buffers, check with one byte offset */ - ret = __test_skcipher(tfm, enc, template, tcount, true, 1); - if (ret) - return ret; - - alignmask = crypto_tfm_alg_alignmask(&tfm->base); - if (alignmask) { - /* Check if alignment mask for tfm is correctly set. */ - ret = __test_skcipher(tfm, enc, template, tcount, true, - alignmask + 1); - if (ret) - return ret; - } - - return 0; -} - -static int test_comp(struct crypto_comp *tfm, struct comp_testvec *ctemplate, - struct comp_testvec *dtemplate, int ctcount, int dtcount) -{ - const char *algo = crypto_tfm_alg_driver_name(crypto_comp_tfm(tfm)); - unsigned int i; - char result[COMP_BUF_SIZE]; - int ret; - - for (i = 0; i < ctcount; i++) { - int ilen; - unsigned int dlen = COMP_BUF_SIZE; - - memset(result, 0, sizeof (result)); - - ilen = ctemplate[i].inlen; - ret = crypto_comp_compress(tfm, ctemplate[i].input, - ilen, result, &dlen); - if (ret) { - printk(KERN_ERR "alg: comp: compression failed " - "on test %d for %s: ret=%d\n", i + 1, algo, - -ret); - goto out; - } - - if (dlen != ctemplate[i].outlen) { - printk(KERN_ERR "alg: comp: Compression test %d " - "failed for %s: output len = %d\n", i + 1, algo, - dlen); - ret = -EINVAL; - goto out; - } - - if (memcmp(result, ctemplate[i].output, dlen)) { - printk(KERN_ERR "alg: comp: Compression test %d " - "failed for %s\n", i + 1, algo); - hexdump(result, dlen); - ret = -EINVAL; - goto out; - } - } - - for (i = 0; i < dtcount; i++) { - int ilen; - unsigned int dlen = COMP_BUF_SIZE; - - memset(result, 0, sizeof (result)); - - ilen = dtemplate[i].inlen; - ret = crypto_comp_decompress(tfm, dtemplate[i].input, - ilen, result, &dlen); - if (ret) { - printk(KERN_ERR "alg: comp: decompression failed " - "on test %d for %s: ret=%d\n", i + 1, algo, - -ret); - goto out; - } - - if (dlen != dtemplate[i].outlen) { - printk(KERN_ERR "alg: comp: Decompression test %d " - "failed for %s: output len = %d\n", i + 1, algo, - dlen); - ret = -EINVAL; - goto out; - } - - if (memcmp(result, dtemplate[i].output, dlen)) { - printk(KERN_ERR "alg: comp: Decompression test %d " - "failed for %s\n", i + 1, algo); - hexdump(result, dlen); - ret = -EINVAL; - goto out; - } - } - - ret = 0; - -out: - return ret; -} - -static int test_cprng(struct crypto_rng *tfm, struct cprng_testvec *template, - unsigned int tcount) -{ - const char *algo = crypto_tfm_alg_driver_name(crypto_rng_tfm(tfm)); - int err = 0, i, j, seedsize; - u8 *seed; - char result[32]; - - seedsize = crypto_rng_seedsize(tfm); - - seed = kmalloc(seedsize, GFP_KERNEL); - if (!seed) { - printk(KERN_ERR "alg: cprng: Failed to allocate seed space " - "for %s\n", algo); - return -ENOMEM; - } - - for (i = 0; i < tcount; i++) { - memset(result, 0, 32); - - memcpy(seed, template[i].v, template[i].vlen); - memcpy(seed + template[i].vlen, template[i].key, - template[i].klen); - memcpy(seed + template[i].vlen + template[i].klen, - template[i].dt, template[i].dtlen); - - err = crypto_rng_reset(tfm, seed, seedsize); - if (err) { - printk(KERN_ERR "alg: cprng: Failed to reset rng " - "for %s\n", algo); - goto out; - } - - for (j = 0; j < template[i].loops; j++) { - err = crypto_rng_get_bytes(tfm, result, - template[i].rlen); - if (err < 0) { - printk(KERN_ERR "alg: cprng: Failed to obtain " - "the correct amount of random data for " - "%s (requested %d)\n", algo, - template[i].rlen); - goto out; - } - } - - err = memcmp(result, template[i].result, - template[i].rlen); - if (err) { - printk(KERN_ERR "alg: cprng: Test %d failed for %s\n", - i, algo); - hexdump(result, template[i].rlen); - err = -EINVAL; - goto out; - } - } - -out: - kfree(seed); - return err; -} - -static int alg_test_aead(const struct alg_test_desc *desc, const char *driver, - u32 type, u32 mask) -{ - struct crypto_aead *tfm; - int err = 0; - - tfm = crypto_alloc_aead(driver, type | CRYPTO_ALG_INTERNAL, mask); - if (IS_ERR(tfm)) { - printk(KERN_ERR "alg: aead: Failed to load transform for %s: " - "%ld\n", driver, PTR_ERR(tfm)); - return PTR_ERR(tfm); - } - - if (desc->suite.aead.enc.vecs) { - err = test_aead(tfm, ENCRYPT, desc->suite.aead.enc.vecs, - desc->suite.aead.enc.count); - if (err) - goto out; - } - - if (!err && desc->suite.aead.dec.vecs) - err = test_aead(tfm, DECRYPT, desc->suite.aead.dec.vecs, - desc->suite.aead.dec.count); - -out: - crypto_free_aead(tfm); - return err; -} - -static int alg_test_cipher(const struct alg_test_desc *desc, - const char *driver, u32 type, u32 mask) -{ - struct crypto_cipher *tfm; - int err = 0; - - tfm = crypto_alloc_cipher(driver, type | CRYPTO_ALG_INTERNAL, mask); - if (IS_ERR(tfm)) { - printk(KERN_ERR "alg: cipher: Failed to load transform for " - "%s: %ld\n", driver, PTR_ERR(tfm)); - return PTR_ERR(tfm); - } - - if (desc->suite.cipher.enc.vecs) { - err = test_cipher(tfm, ENCRYPT, desc->suite.cipher.enc.vecs, - desc->suite.cipher.enc.count); - if (err) - goto out; - } - - if (desc->suite.cipher.dec.vecs) - err = test_cipher(tfm, DECRYPT, desc->suite.cipher.dec.vecs, - desc->suite.cipher.dec.count); - -out: - crypto_free_cipher(tfm); - return err; -} - -static int alg_test_skcipher(const struct alg_test_desc *desc, - const char *driver, u32 type, u32 mask) -{ - struct crypto_skcipher *tfm; - int err = 0; - - tfm = crypto_alloc_skcipher(driver, type | CRYPTO_ALG_INTERNAL, mask); - if (IS_ERR(tfm)) { - printk(KERN_ERR "alg: skcipher: Failed to load transform for " - "%s: %ld\n", driver, PTR_ERR(tfm)); - return PTR_ERR(tfm); - } - - if (desc->suite.cipher.enc.vecs) { - err = test_skcipher(tfm, ENCRYPT, desc->suite.cipher.enc.vecs, - desc->suite.cipher.enc.count); - if (err) - goto out; - } - - if (desc->suite.cipher.dec.vecs) - err = test_skcipher(tfm, DECRYPT, desc->suite.cipher.dec.vecs, - desc->suite.cipher.dec.count); - -out: - crypto_free_skcipher(tfm); - return err; -} - -static int alg_test_comp(const struct alg_test_desc *desc, const char *driver, - u32 type, u32 mask) -{ - struct crypto_comp *tfm; - int err; - - tfm = crypto_alloc_comp(driver, type, mask); - if (IS_ERR(tfm)) { - printk(KERN_ERR "alg: comp: Failed to load transform for %s: " - "%ld\n", driver, PTR_ERR(tfm)); - return PTR_ERR(tfm); - } - - err = test_comp(tfm, desc->suite.comp.comp.vecs, - desc->suite.comp.decomp.vecs, - desc->suite.comp.comp.count, - desc->suite.comp.decomp.count); - - crypto_free_comp(tfm); - return err; -} - -static int alg_test_hash(const struct alg_test_desc *desc, const char *driver, - u32 type, u32 mask) -{ - struct crypto_ahash *tfm; - int err; - - tfm = crypto_alloc_ahash(driver, type | CRYPTO_ALG_INTERNAL, mask); - if (IS_ERR(tfm)) { - printk(KERN_ERR "alg: hash: Failed to load transform for %s: " - "%ld\n", driver, PTR_ERR(tfm)); - return PTR_ERR(tfm); - } - - err = test_hash(tfm, desc->suite.hash.vecs, - desc->suite.hash.count, true); - if (!err) - err = test_hash(tfm, desc->suite.hash.vecs, - desc->suite.hash.count, false); - - crypto_free_ahash(tfm); - return err; -} - -static int alg_test_crc32c(const struct alg_test_desc *desc, - const char *driver, u32 type, u32 mask) -{ - struct crypto_shash *tfm; - u32 val; - int err; - - err = alg_test_hash(desc, driver, type, mask); - if (err) - goto out; - - tfm = crypto_alloc_shash(driver, type | CRYPTO_ALG_INTERNAL, mask); - if (IS_ERR(tfm)) { - printk(KERN_ERR "alg: crc32c: Failed to load transform for %s: " - "%ld\n", driver, PTR_ERR(tfm)); - err = PTR_ERR(tfm); - goto out; - } - - do { - SHASH_DESC_ON_STACK(shash, tfm); - u32 *ctx = (u32 *)shash_desc_ctx(shash); - - shash->tfm = tfm; - shash->flags = 0; - - *ctx = le32_to_cpu(420553207); - err = crypto_shash_final(shash, (u8 *)&val); - if (err) { - printk(KERN_ERR "alg: crc32c: Operation failed for " - "%s: %d\n", driver, err); - break; - } - - if (val != ~420553207) { - printk(KERN_ERR "alg: crc32c: Test failed for %s: " - "%d\n", driver, val); - err = -EINVAL; - } - } while (0); - - crypto_free_shash(tfm); - -out: - return err; -} - -static int alg_test_cprng(const struct alg_test_desc *desc, const char *driver, - u32 type, u32 mask) -{ - struct crypto_rng *rng; - int err; - - rng = crypto_alloc_rng(driver, type | CRYPTO_ALG_INTERNAL, mask); - if (IS_ERR(rng)) { - printk(KERN_ERR "alg: cprng: Failed to load transform for %s: " - "%ld\n", driver, PTR_ERR(rng)); - return PTR_ERR(rng); - } - - err = test_cprng(rng, desc->suite.cprng.vecs, desc->suite.cprng.count); - - crypto_free_rng(rng); - - return err; -} - - -static int drbg_cavs_test(struct drbg_testvec *test, int pr, - const char *driver, u32 type, u32 mask) -{ - int ret = -EAGAIN; - struct crypto_rng *drng; - struct drbg_test_data test_data; - struct drbg_string addtl, pers, testentropy; - unsigned char *buf = kzalloc(test->expectedlen, GFP_KERNEL); - - if (!buf) - return -ENOMEM; - - drng = crypto_alloc_rng(driver, type | CRYPTO_ALG_INTERNAL, mask); - if (IS_ERR(drng)) { - printk(KERN_ERR "alg: drbg: could not allocate DRNG handle for " - "%s\n", driver); - kzfree(buf); - return -ENOMEM; - } - - test_data.testentropy = &testentropy; - drbg_string_fill(&testentropy, test->entropy, test->entropylen); - drbg_string_fill(&pers, test->pers, test->perslen); - ret = crypto_drbg_reset_test(drng, &pers, &test_data); - if (ret) { - printk(KERN_ERR "alg: drbg: Failed to reset rng\n"); - goto outbuf; - } - - drbg_string_fill(&addtl, test->addtla, test->addtllen); - if (pr) { - drbg_string_fill(&testentropy, test->entpra, test->entprlen); - ret = crypto_drbg_get_bytes_addtl_test(drng, - buf, test->expectedlen, &addtl, &test_data); - } else { - ret = crypto_drbg_get_bytes_addtl(drng, - buf, test->expectedlen, &addtl); - } - if (ret < 0) { - printk(KERN_ERR "alg: drbg: could not obtain random data for " - "driver %s\n", driver); - goto outbuf; - } - - drbg_string_fill(&addtl, test->addtlb, test->addtllen); - if (pr) { - drbg_string_fill(&testentropy, test->entprb, test->entprlen); - ret = crypto_drbg_get_bytes_addtl_test(drng, - buf, test->expectedlen, &addtl, &test_data); - } else { - ret = crypto_drbg_get_bytes_addtl(drng, - buf, test->expectedlen, &addtl); - } - if (ret < 0) { - printk(KERN_ERR "alg: drbg: could not obtain random data for " - "driver %s\n", driver); - goto outbuf; - } - - ret = memcmp(test->expected, buf, test->expectedlen); - -outbuf: - crypto_free_rng(drng); - kzfree(buf); - return ret; -} - - -static int alg_test_drbg(const struct alg_test_desc *desc, const char *driver, - u32 type, u32 mask) -{ - int err = 0; - int pr = 0; - int i = 0; - struct drbg_testvec *template = desc->suite.drbg.vecs; - unsigned int tcount = desc->suite.drbg.count; - - if (0 == memcmp(driver, "drbg_pr_", 8)) - pr = 1; - - for (i = 0; i < tcount; i++) { - err = drbg_cavs_test(&template[i], pr, driver, type, mask); - if (err) { - printk(KERN_ERR "alg: drbg: Test %d failed for %s\n", - i, driver); - err = -EINVAL; - break; - } - } - return err; - -} - -static int do_test_kpp(struct crypto_kpp *tfm, struct kpp_testvec *vec, - const char *alg) -{ - struct kpp_request *req; - void *input_buf = NULL; - void *output_buf = NULL; - struct tcrypt_result result; - unsigned int out_len_max; - int err = -ENOMEM; - struct scatterlist src, dst; - - req = kpp_request_alloc(tfm, GFP_KERNEL); - if (!req) - return err; - - init_completion(&result.completion); - - err = crypto_kpp_set_secret(tfm, vec->secret, vec->secret_size); - if (err < 0) - goto free_req; - - out_len_max = crypto_kpp_maxsize(tfm); - output_buf = kzalloc(out_len_max, GFP_KERNEL); - if (!output_buf) { - err = -ENOMEM; - goto free_req; - } - - /* Use appropriate parameter as base */ - kpp_request_set_input(req, NULL, 0); - sg_init_one(&dst, output_buf, out_len_max); - kpp_request_set_output(req, &dst, out_len_max); - kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, - tcrypt_complete, &result); - - /* Compute public key */ - err = wait_async_op(&result, crypto_kpp_generate_public_key(req)); - if (err) { - pr_err("alg: %s: generate public key test failed. err %d\n", - alg, err); - goto free_output; - } - /* Verify calculated public key */ - if (memcmp(vec->expected_a_public, sg_virt(req->dst), - vec->expected_a_public_size)) { - pr_err("alg: %s: generate public key test failed. Invalid output\n", - alg); - err = -EINVAL; - goto free_output; - } - - /* Calculate shared secret key by using counter part (b) public key. */ - input_buf = kzalloc(vec->b_public_size, GFP_KERNEL); - if (!input_buf) { - err = -ENOMEM; - goto free_output; - } - - memcpy(input_buf, vec->b_public, vec->b_public_size); - sg_init_one(&src, input_buf, vec->b_public_size); - sg_init_one(&dst, output_buf, out_len_max); - kpp_request_set_input(req, &src, vec->b_public_size); - kpp_request_set_output(req, &dst, out_len_max); - kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, - tcrypt_complete, &result); - err = wait_async_op(&result, crypto_kpp_compute_shared_secret(req)); - if (err) { - pr_err("alg: %s: compute shard secret test failed. err %d\n", - alg, err); - goto free_all; - } - /* - * verify shared secret from which the user will derive - * secret key by executing whatever hash it has chosen - */ - if (memcmp(vec->expected_ss, sg_virt(req->dst), - vec->expected_ss_size)) { - pr_err("alg: %s: compute shared secret test failed. Invalid output\n", - alg); - err = -EINVAL; - } - -free_all: - kfree(input_buf); -free_output: - kfree(output_buf); -free_req: - kpp_request_free(req); - return err; -} - -static int test_kpp(struct crypto_kpp *tfm, const char *alg, - struct kpp_testvec *vecs, unsigned int tcount) -{ - int ret, i; - - for (i = 0; i < tcount; i++) { - ret = do_test_kpp(tfm, vecs++, alg); - if (ret) { - pr_err("alg: %s: test failed on vector %d, err=%d\n", - alg, i + 1, ret); - return ret; - } - } - return 0; -} - -static int alg_test_kpp(const struct alg_test_desc *desc, const char *driver, - u32 type, u32 mask) -{ - struct crypto_kpp *tfm; - int err = 0; - - tfm = crypto_alloc_kpp(driver, type | CRYPTO_ALG_INTERNAL, mask); - if (IS_ERR(tfm)) { - pr_err("alg: kpp: Failed to load tfm for %s: %ld\n", - driver, PTR_ERR(tfm)); - return PTR_ERR(tfm); - } - if (desc->suite.kpp.vecs) - err = test_kpp(tfm, desc->alg, desc->suite.kpp.vecs, - desc->suite.kpp.count); - - crypto_free_kpp(tfm); - return err; -} - -static int test_akcipher_one(struct crypto_akcipher *tfm, - struct akcipher_testvec *vecs) -{ - char *xbuf[XBUFSIZE]; - struct akcipher_request *req; - void *outbuf_enc = NULL; - void *outbuf_dec = NULL; - struct tcrypt_result result; - unsigned int out_len_max, out_len = 0; - int err = -ENOMEM; - struct scatterlist src, dst, src_tab[2]; - - if (testmgr_alloc_buf(xbuf)) - return err; - - req = akcipher_request_alloc(tfm, GFP_KERNEL); - if (!req) - goto free_xbuf; - - init_completion(&result.completion); - - if (vecs->public_key_vec) - err = crypto_akcipher_set_pub_key(tfm, vecs->key, - vecs->key_len); - else - err = crypto_akcipher_set_priv_key(tfm, vecs->key, - vecs->key_len); - if (err) - goto free_req; - - err = -ENOMEM; - out_len_max = crypto_akcipher_maxsize(tfm); - outbuf_enc = kzalloc(out_len_max, GFP_KERNEL); - if (!outbuf_enc) - goto free_req; - - if (WARN_ON(vecs->m_size > PAGE_SIZE)) - goto free_all; - - memcpy(xbuf[0], vecs->m, vecs->m_size); - - sg_init_table(src_tab, 2); - sg_set_buf(&src_tab[0], xbuf[0], 8); - sg_set_buf(&src_tab[1], xbuf[0] + 8, vecs->m_size - 8); - sg_init_one(&dst, outbuf_enc, out_len_max); - akcipher_request_set_crypt(req, src_tab, &dst, vecs->m_size, - out_len_max); - akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, - tcrypt_complete, &result); - - /* Run RSA encrypt - c = m^e mod n;*/ - err = wait_async_op(&result, crypto_akcipher_encrypt(req)); - if (err) { - pr_err("alg: akcipher: encrypt test failed. err %d\n", err); - goto free_all; - } - if (req->dst_len != vecs->c_size) { - pr_err("alg: akcipher: encrypt test failed. Invalid output len\n"); - err = -EINVAL; - goto free_all; - } - /* verify that encrypted message is equal to expected */ - if (memcmp(vecs->c, outbuf_enc, vecs->c_size)) { - pr_err("alg: akcipher: encrypt test failed. Invalid output\n"); - hexdump(outbuf_enc, vecs->c_size); - err = -EINVAL; - goto free_all; - } - /* Don't invoke decrypt for vectors with public key */ - if (vecs->public_key_vec) { - err = 0; - goto free_all; - } - outbuf_dec = kzalloc(out_len_max, GFP_KERNEL); - if (!outbuf_dec) { - err = -ENOMEM; - goto free_all; - } - - if (WARN_ON(vecs->c_size > PAGE_SIZE)) - goto free_all; - - memcpy(xbuf[0], vecs->c, vecs->c_size); - - sg_init_one(&src, xbuf[0], vecs->c_size); - sg_init_one(&dst, outbuf_dec, out_len_max); - init_completion(&result.completion); - akcipher_request_set_crypt(req, &src, &dst, vecs->c_size, out_len_max); - - /* Run RSA decrypt - m = c^d mod n;*/ - err = wait_async_op(&result, crypto_akcipher_decrypt(req)); - if (err) { - pr_err("alg: akcipher: decrypt test failed. err %d\n", err); - goto free_all; - } - out_len = req->dst_len; - if (out_len < vecs->m_size) { - pr_err("alg: akcipher: decrypt test failed. " - "Invalid output len %u\n", out_len); - err = -EINVAL; - goto free_all; - } - /* verify that decrypted message is equal to the original msg */ - if (memchr_inv(outbuf_dec, 0, out_len - vecs->m_size) || - memcmp(vecs->m, outbuf_dec + out_len - vecs->m_size, - vecs->m_size)) { - pr_err("alg: akcipher: decrypt test failed. Invalid output\n"); - hexdump(outbuf_dec, out_len); - err = -EINVAL; - } -free_all: - kfree(outbuf_dec); - kfree(outbuf_enc); -free_req: - akcipher_request_free(req); -free_xbuf: - testmgr_free_buf(xbuf); - return err; -} - -static int test_akcipher(struct crypto_akcipher *tfm, const char *alg, - struct akcipher_testvec *vecs, unsigned int tcount) -{ - const char *algo = - crypto_tfm_alg_driver_name(crypto_akcipher_tfm(tfm)); - int ret, i; - - for (i = 0; i < tcount; i++) { - ret = test_akcipher_one(tfm, vecs++); - if (!ret) - continue; - - pr_err("alg: akcipher: test %d failed for %s, err=%d\n", - i + 1, algo, ret); - return ret; - } - return 0; -} - -static int alg_test_akcipher(const struct alg_test_desc *desc, - const char *driver, u32 type, u32 mask) -{ - struct crypto_akcipher *tfm; - int err = 0; - - tfm = crypto_alloc_akcipher(driver, type | CRYPTO_ALG_INTERNAL, mask); - if (IS_ERR(tfm)) { - pr_err("alg: akcipher: Failed to load tfm for %s: %ld\n", - driver, PTR_ERR(tfm)); - return PTR_ERR(tfm); - } - if (desc->suite.akcipher.vecs) - err = test_akcipher(tfm, desc->alg, desc->suite.akcipher.vecs, - desc->suite.akcipher.count); - - crypto_free_akcipher(tfm); - return err; -} - -static int alg_test_null(const struct alg_test_desc *desc, - const char *driver, u32 type, u32 mask) -{ - return 0; -} - -/* Please keep this list sorted by algorithm name. */ -static const struct alg_test_desc alg_test_descs[] = { - { - .alg = "__cbc-cast5-avx", - .test = alg_test_null, - }, { - .alg = "__cbc-cast6-avx", - .test = alg_test_null, - }, { - .alg = "__cbc-serpent-avx", - .test = alg_test_null, - }, { - .alg = "__cbc-serpent-avx2", - .test = alg_test_null, - }, { - .alg = "__cbc-serpent-sse2", - .test = alg_test_null, - }, { - .alg = "__cbc-twofish-avx", - .test = alg_test_null, - }, { - .alg = "__driver-cbc-aes-aesni", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "__driver-cbc-camellia-aesni", - .test = alg_test_null, - }, { - .alg = "__driver-cbc-camellia-aesni-avx2", - .test = alg_test_null, - }, { - .alg = "__driver-cbc-cast5-avx", - .test = alg_test_null, - }, { - .alg = "__driver-cbc-cast6-avx", - .test = alg_test_null, - }, { - .alg = "__driver-cbc-serpent-avx", - .test = alg_test_null, - }, { - .alg = "__driver-cbc-serpent-avx2", - .test = alg_test_null, - }, { - .alg = "__driver-cbc-serpent-sse2", - .test = alg_test_null, - }, { - .alg = "__driver-cbc-twofish-avx", - .test = alg_test_null, - }, { - .alg = "__driver-ecb-aes-aesni", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "__driver-ecb-camellia-aesni", - .test = alg_test_null, - }, { - .alg = "__driver-ecb-camellia-aesni-avx2", - .test = alg_test_null, - }, { - .alg = "__driver-ecb-cast5-avx", - .test = alg_test_null, - }, { - .alg = "__driver-ecb-cast6-avx", - .test = alg_test_null, - }, { - .alg = "__driver-ecb-serpent-avx", - .test = alg_test_null, - }, { - .alg = "__driver-ecb-serpent-avx2", - .test = alg_test_null, - }, { - .alg = "__driver-ecb-serpent-sse2", - .test = alg_test_null, - }, { - .alg = "__driver-ecb-twofish-avx", - .test = alg_test_null, - }, { - .alg = "__driver-gcm-aes-aesni", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "__ghash-pclmulqdqni", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "ansi_cprng", - .test = alg_test_cprng, - .suite = { - .cprng = { - .vecs = ansi_cprng_aes_tv_template, - .count = ANSI_CPRNG_AES_TEST_VECTORS - } - } - }, { - .alg = "authenc(hmac(md5),ecb(cipher_null))", - .test = alg_test_aead, - .suite = { - .aead = { - .enc = { - .vecs = hmac_md5_ecb_cipher_null_enc_tv_template, - .count = HMAC_MD5_ECB_CIPHER_NULL_ENC_TEST_VECTORS - }, - .dec = { - .vecs = hmac_md5_ecb_cipher_null_dec_tv_template, - .count = HMAC_MD5_ECB_CIPHER_NULL_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "authenc(hmac(sha1),cbc(aes))", - .test = alg_test_aead, - .suite = { - .aead = { - .enc = { - .vecs = - hmac_sha1_aes_cbc_enc_tv_temp, - .count = - HMAC_SHA1_AES_CBC_ENC_TEST_VEC - } - } - } - }, { - .alg = "authenc(hmac(sha1),cbc(des))", - .test = alg_test_aead, - .suite = { - .aead = { - .enc = { - .vecs = - hmac_sha1_des_cbc_enc_tv_temp, - .count = - HMAC_SHA1_DES_CBC_ENC_TEST_VEC - } - } - } - }, { - .alg = "authenc(hmac(sha1),cbc(des3_ede))", - .test = alg_test_aead, - .fips_allowed = 1, - .suite = { - .aead = { - .enc = { - .vecs = - hmac_sha1_des3_ede_cbc_enc_tv_temp, - .count = - HMAC_SHA1_DES3_EDE_CBC_ENC_TEST_VEC - } - } - } - }, { - .alg = "authenc(hmac(sha1),ctr(aes))", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "authenc(hmac(sha1),ecb(cipher_null))", - .test = alg_test_aead, - .suite = { - .aead = { - .enc = { - .vecs = - hmac_sha1_ecb_cipher_null_enc_tv_temp, - .count = - HMAC_SHA1_ECB_CIPHER_NULL_ENC_TEST_VEC - }, - .dec = { - .vecs = - hmac_sha1_ecb_cipher_null_dec_tv_temp, - .count = - HMAC_SHA1_ECB_CIPHER_NULL_DEC_TEST_VEC - } - } - } - }, { - .alg = "authenc(hmac(sha1),rfc3686(ctr(aes)))", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "authenc(hmac(sha224),cbc(des))", - .test = alg_test_aead, - .suite = { - .aead = { - .enc = { - .vecs = - hmac_sha224_des_cbc_enc_tv_temp, - .count = - HMAC_SHA224_DES_CBC_ENC_TEST_VEC - } - } - } - }, { - .alg = "authenc(hmac(sha224),cbc(des3_ede))", - .test = alg_test_aead, - .fips_allowed = 1, - .suite = { - .aead = { - .enc = { - .vecs = - hmac_sha224_des3_ede_cbc_enc_tv_temp, - .count = - HMAC_SHA224_DES3_EDE_CBC_ENC_TEST_VEC - } - } - } - }, { - .alg = "authenc(hmac(sha256),cbc(aes))", - .test = alg_test_aead, - .fips_allowed = 1, - .suite = { - .aead = { - .enc = { - .vecs = - hmac_sha256_aes_cbc_enc_tv_temp, - .count = - HMAC_SHA256_AES_CBC_ENC_TEST_VEC - } - } - } - }, { - .alg = "authenc(hmac(sha256),cbc(des))", - .test = alg_test_aead, - .suite = { - .aead = { - .enc = { - .vecs = - hmac_sha256_des_cbc_enc_tv_temp, - .count = - HMAC_SHA256_DES_CBC_ENC_TEST_VEC - } - } - } - }, { - .alg = "authenc(hmac(sha256),cbc(des3_ede))", - .test = alg_test_aead, - .fips_allowed = 1, - .suite = { - .aead = { - .enc = { - .vecs = - hmac_sha256_des3_ede_cbc_enc_tv_temp, - .count = - HMAC_SHA256_DES3_EDE_CBC_ENC_TEST_VEC - } - } - } - }, { - .alg = "authenc(hmac(sha256),ctr(aes))", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "authenc(hmac(sha256),rfc3686(ctr(aes)))", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "authenc(hmac(sha384),cbc(des))", - .test = alg_test_aead, - .suite = { - .aead = { - .enc = { - .vecs = - hmac_sha384_des_cbc_enc_tv_temp, - .count = - HMAC_SHA384_DES_CBC_ENC_TEST_VEC - } - } - } - }, { - .alg = "authenc(hmac(sha384),cbc(des3_ede))", - .test = alg_test_aead, - .fips_allowed = 1, - .suite = { - .aead = { - .enc = { - .vecs = - hmac_sha384_des3_ede_cbc_enc_tv_temp, - .count = - HMAC_SHA384_DES3_EDE_CBC_ENC_TEST_VEC - } - } - } - }, { - .alg = "authenc(hmac(sha384),ctr(aes))", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "authenc(hmac(sha384),rfc3686(ctr(aes)))", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "authenc(hmac(sha512),cbc(aes))", - .fips_allowed = 1, - .test = alg_test_aead, - .suite = { - .aead = { - .enc = { - .vecs = - hmac_sha512_aes_cbc_enc_tv_temp, - .count = - HMAC_SHA512_AES_CBC_ENC_TEST_VEC - } - } - } - }, { - .alg = "authenc(hmac(sha512),cbc(des))", - .test = alg_test_aead, - .suite = { - .aead = { - .enc = { - .vecs = - hmac_sha512_des_cbc_enc_tv_temp, - .count = - HMAC_SHA512_DES_CBC_ENC_TEST_VEC - } - } - } - }, { - .alg = "authenc(hmac(sha512),cbc(des3_ede))", - .test = alg_test_aead, - .fips_allowed = 1, - .suite = { - .aead = { - .enc = { - .vecs = - hmac_sha512_des3_ede_cbc_enc_tv_temp, - .count = - HMAC_SHA512_DES3_EDE_CBC_ENC_TEST_VEC - } - } - } - }, { - .alg = "authenc(hmac(sha512),ctr(aes))", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "authenc(hmac(sha512),rfc3686(ctr(aes)))", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "cbc(aes)", - .test = alg_test_skcipher, - .fips_allowed = 1, - .suite = { - .cipher = { - .enc = { - .vecs = aes_cbc_enc_tv_template, - .count = AES_CBC_ENC_TEST_VECTORS - }, - .dec = { - .vecs = aes_cbc_dec_tv_template, - .count = AES_CBC_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "cbc(anubis)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = anubis_cbc_enc_tv_template, - .count = ANUBIS_CBC_ENC_TEST_VECTORS - }, - .dec = { - .vecs = anubis_cbc_dec_tv_template, - .count = ANUBIS_CBC_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "cbc(blowfish)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = bf_cbc_enc_tv_template, - .count = BF_CBC_ENC_TEST_VECTORS - }, - .dec = { - .vecs = bf_cbc_dec_tv_template, - .count = BF_CBC_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "cbc(camellia)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = camellia_cbc_enc_tv_template, - .count = CAMELLIA_CBC_ENC_TEST_VECTORS - }, - .dec = { - .vecs = camellia_cbc_dec_tv_template, - .count = CAMELLIA_CBC_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "cbc(cast5)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = cast5_cbc_enc_tv_template, - .count = CAST5_CBC_ENC_TEST_VECTORS - }, - .dec = { - .vecs = cast5_cbc_dec_tv_template, - .count = CAST5_CBC_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "cbc(cast6)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = cast6_cbc_enc_tv_template, - .count = CAST6_CBC_ENC_TEST_VECTORS - }, - .dec = { - .vecs = cast6_cbc_dec_tv_template, - .count = CAST6_CBC_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "cbc(des)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = des_cbc_enc_tv_template, - .count = DES_CBC_ENC_TEST_VECTORS - }, - .dec = { - .vecs = des_cbc_dec_tv_template, - .count = DES_CBC_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "cbc(des3_ede)", - .test = alg_test_skcipher, - .fips_allowed = 1, - .suite = { - .cipher = { - .enc = { - .vecs = des3_ede_cbc_enc_tv_template, - .count = DES3_EDE_CBC_ENC_TEST_VECTORS - }, - .dec = { - .vecs = des3_ede_cbc_dec_tv_template, - .count = DES3_EDE_CBC_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "cbc(serpent)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = serpent_cbc_enc_tv_template, - .count = SERPENT_CBC_ENC_TEST_VECTORS - }, - .dec = { - .vecs = serpent_cbc_dec_tv_template, - .count = SERPENT_CBC_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "cbc(twofish)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = tf_cbc_enc_tv_template, - .count = TF_CBC_ENC_TEST_VECTORS - }, - .dec = { - .vecs = tf_cbc_dec_tv_template, - .count = TF_CBC_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ccm(aes)", - .test = alg_test_aead, - .fips_allowed = 1, - .suite = { - .aead = { - .enc = { - .vecs = aes_ccm_enc_tv_template, - .count = AES_CCM_ENC_TEST_VECTORS - }, - .dec = { - .vecs = aes_ccm_dec_tv_template, - .count = AES_CCM_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "chacha20", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = chacha20_enc_tv_template, - .count = CHACHA20_ENC_TEST_VECTORS - }, - .dec = { - .vecs = chacha20_enc_tv_template, - .count = CHACHA20_ENC_TEST_VECTORS - }, - } - } - }, { - .alg = "cmac(aes)", - .fips_allowed = 1, - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = aes_cmac128_tv_template, - .count = CMAC_AES_TEST_VECTORS - } - } - }, { - .alg = "cmac(des3_ede)", - .fips_allowed = 1, - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = des3_ede_cmac64_tv_template, - .count = CMAC_DES3_EDE_TEST_VECTORS - } - } - }, { - .alg = "compress_null", - .test = alg_test_null, - }, { - .alg = "crc32", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = crc32_tv_template, - .count = CRC32_TEST_VECTORS - } - } - }, { - .alg = "crc32c", - .test = alg_test_crc32c, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = crc32c_tv_template, - .count = CRC32C_TEST_VECTORS - } - } - }, { - .alg = "crct10dif", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = crct10dif_tv_template, - .count = CRCT10DIF_TEST_VECTORS - } - } - }, { - .alg = "cryptd(__driver-cbc-aes-aesni)", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "cryptd(__driver-cbc-camellia-aesni)", - .test = alg_test_null, - }, { - .alg = "cryptd(__driver-cbc-camellia-aesni-avx2)", - .test = alg_test_null, - }, { - .alg = "cryptd(__driver-cbc-serpent-avx2)", - .test = alg_test_null, - }, { - .alg = "cryptd(__driver-ecb-aes-aesni)", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "cryptd(__driver-ecb-camellia-aesni)", - .test = alg_test_null, - }, { - .alg = "cryptd(__driver-ecb-camellia-aesni-avx2)", - .test = alg_test_null, - }, { - .alg = "cryptd(__driver-ecb-cast5-avx)", - .test = alg_test_null, - }, { - .alg = "cryptd(__driver-ecb-cast6-avx)", - .test = alg_test_null, - }, { - .alg = "cryptd(__driver-ecb-serpent-avx)", - .test = alg_test_null, - }, { - .alg = "cryptd(__driver-ecb-serpent-avx2)", - .test = alg_test_null, - }, { - .alg = "cryptd(__driver-ecb-serpent-sse2)", - .test = alg_test_null, - }, { - .alg = "cryptd(__driver-ecb-twofish-avx)", - .test = alg_test_null, - }, { - .alg = "cryptd(__driver-gcm-aes-aesni)", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "cryptd(__ghash-pclmulqdqni)", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "ctr(aes)", - .test = alg_test_skcipher, - .fips_allowed = 1, - .suite = { - .cipher = { - .enc = { - .vecs = aes_ctr_enc_tv_template, - .count = AES_CTR_ENC_TEST_VECTORS - }, - .dec = { - .vecs = aes_ctr_dec_tv_template, - .count = AES_CTR_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ctr(blowfish)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = bf_ctr_enc_tv_template, - .count = BF_CTR_ENC_TEST_VECTORS - }, - .dec = { - .vecs = bf_ctr_dec_tv_template, - .count = BF_CTR_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ctr(camellia)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = camellia_ctr_enc_tv_template, - .count = CAMELLIA_CTR_ENC_TEST_VECTORS - }, - .dec = { - .vecs = camellia_ctr_dec_tv_template, - .count = CAMELLIA_CTR_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ctr(cast5)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = cast5_ctr_enc_tv_template, - .count = CAST5_CTR_ENC_TEST_VECTORS - }, - .dec = { - .vecs = cast5_ctr_dec_tv_template, - .count = CAST5_CTR_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ctr(cast6)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = cast6_ctr_enc_tv_template, - .count = CAST6_CTR_ENC_TEST_VECTORS - }, - .dec = { - .vecs = cast6_ctr_dec_tv_template, - .count = CAST6_CTR_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ctr(des)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = des_ctr_enc_tv_template, - .count = DES_CTR_ENC_TEST_VECTORS - }, - .dec = { - .vecs = des_ctr_dec_tv_template, - .count = DES_CTR_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ctr(des3_ede)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = des3_ede_ctr_enc_tv_template, - .count = DES3_EDE_CTR_ENC_TEST_VECTORS - }, - .dec = { - .vecs = des3_ede_ctr_dec_tv_template, - .count = DES3_EDE_CTR_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ctr(serpent)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = serpent_ctr_enc_tv_template, - .count = SERPENT_CTR_ENC_TEST_VECTORS - }, - .dec = { - .vecs = serpent_ctr_dec_tv_template, - .count = SERPENT_CTR_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ctr(twofish)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = tf_ctr_enc_tv_template, - .count = TF_CTR_ENC_TEST_VECTORS - }, - .dec = { - .vecs = tf_ctr_dec_tv_template, - .count = TF_CTR_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "cts(cbc(aes))", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = cts_mode_enc_tv_template, - .count = CTS_MODE_ENC_TEST_VECTORS - }, - .dec = { - .vecs = cts_mode_dec_tv_template, - .count = CTS_MODE_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "deflate", - .test = alg_test_comp, - .fips_allowed = 1, - .suite = { - .comp = { - .comp = { - .vecs = deflate_comp_tv_template, - .count = DEFLATE_COMP_TEST_VECTORS - }, - .decomp = { - .vecs = deflate_decomp_tv_template, - .count = DEFLATE_DECOMP_TEST_VECTORS - } - } - } - }, { - .alg = "dh", - .test = alg_test_kpp, - .fips_allowed = 1, - .suite = { - .kpp = { - .vecs = dh_tv_template, - .count = DH_TEST_VECTORS - } - } - }, { - .alg = "digest_null", - .test = alg_test_null, - }, { - .alg = "drbg_nopr_ctr_aes128", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = { - .vecs = drbg_nopr_ctr_aes128_tv_template, - .count = ARRAY_SIZE(drbg_nopr_ctr_aes128_tv_template) - } - } - }, { - .alg = "drbg_nopr_ctr_aes192", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = { - .vecs = drbg_nopr_ctr_aes192_tv_template, - .count = ARRAY_SIZE(drbg_nopr_ctr_aes192_tv_template) - } - } - }, { - .alg = "drbg_nopr_ctr_aes256", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = { - .vecs = drbg_nopr_ctr_aes256_tv_template, - .count = ARRAY_SIZE(drbg_nopr_ctr_aes256_tv_template) - } - } - }, { - /* - * There is no need to specifically test the DRBG with every - * backend cipher -- covered by drbg_nopr_hmac_sha256 test - */ - .alg = "drbg_nopr_hmac_sha1", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_nopr_hmac_sha256", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = { - .vecs = drbg_nopr_hmac_sha256_tv_template, - .count = - ARRAY_SIZE(drbg_nopr_hmac_sha256_tv_template) - } - } - }, { - /* covered by drbg_nopr_hmac_sha256 test */ - .alg = "drbg_nopr_hmac_sha384", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_nopr_hmac_sha512", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "drbg_nopr_sha1", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_nopr_sha256", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = { - .vecs = drbg_nopr_sha256_tv_template, - .count = ARRAY_SIZE(drbg_nopr_sha256_tv_template) - } - } - }, { - /* covered by drbg_nopr_sha256 test */ - .alg = "drbg_nopr_sha384", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_nopr_sha512", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_pr_ctr_aes128", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = { - .vecs = drbg_pr_ctr_aes128_tv_template, - .count = ARRAY_SIZE(drbg_pr_ctr_aes128_tv_template) - } - } - }, { - /* covered by drbg_pr_ctr_aes128 test */ - .alg = "drbg_pr_ctr_aes192", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_pr_ctr_aes256", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_pr_hmac_sha1", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_pr_hmac_sha256", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = { - .vecs = drbg_pr_hmac_sha256_tv_template, - .count = ARRAY_SIZE(drbg_pr_hmac_sha256_tv_template) - } - } - }, { - /* covered by drbg_pr_hmac_sha256 test */ - .alg = "drbg_pr_hmac_sha384", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_pr_hmac_sha512", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "drbg_pr_sha1", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_pr_sha256", - .test = alg_test_drbg, - .fips_allowed = 1, - .suite = { - .drbg = { - .vecs = drbg_pr_sha256_tv_template, - .count = ARRAY_SIZE(drbg_pr_sha256_tv_template) - } - } - }, { - /* covered by drbg_pr_sha256 test */ - .alg = "drbg_pr_sha384", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "drbg_pr_sha512", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "ecb(__aes-aesni)", - .test = alg_test_null, - .fips_allowed = 1, - }, { - .alg = "ecb(aes)", - .test = alg_test_skcipher, - .fips_allowed = 1, - .suite = { - .cipher = { - .enc = { - .vecs = aes_enc_tv_template, - .count = AES_ENC_TEST_VECTORS - }, - .dec = { - .vecs = aes_dec_tv_template, - .count = AES_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ecb(anubis)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = anubis_enc_tv_template, - .count = ANUBIS_ENC_TEST_VECTORS - }, - .dec = { - .vecs = anubis_dec_tv_template, - .count = ANUBIS_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ecb(arc4)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = arc4_enc_tv_template, - .count = ARC4_ENC_TEST_VECTORS - }, - .dec = { - .vecs = arc4_dec_tv_template, - .count = ARC4_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ecb(blowfish)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = bf_enc_tv_template, - .count = BF_ENC_TEST_VECTORS - }, - .dec = { - .vecs = bf_dec_tv_template, - .count = BF_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ecb(camellia)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = camellia_enc_tv_template, - .count = CAMELLIA_ENC_TEST_VECTORS - }, - .dec = { - .vecs = camellia_dec_tv_template, - .count = CAMELLIA_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ecb(cast5)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = cast5_enc_tv_template, - .count = CAST5_ENC_TEST_VECTORS - }, - .dec = { - .vecs = cast5_dec_tv_template, - .count = CAST5_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ecb(cast6)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = cast6_enc_tv_template, - .count = CAST6_ENC_TEST_VECTORS - }, - .dec = { - .vecs = cast6_dec_tv_template, - .count = CAST6_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ecb(cipher_null)", - .test = alg_test_null, - }, { - .alg = "ecb(des)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = des_enc_tv_template, - .count = DES_ENC_TEST_VECTORS - }, - .dec = { - .vecs = des_dec_tv_template, - .count = DES_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ecb(des3_ede)", - .test = alg_test_skcipher, - .fips_allowed = 1, - .suite = { - .cipher = { - .enc = { - .vecs = des3_ede_enc_tv_template, - .count = DES3_EDE_ENC_TEST_VECTORS - }, - .dec = { - .vecs = des3_ede_dec_tv_template, - .count = DES3_EDE_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ecb(fcrypt)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = fcrypt_pcbc_enc_tv_template, - .count = 1 - }, - .dec = { - .vecs = fcrypt_pcbc_dec_tv_template, - .count = 1 - } - } - } - }, { - .alg = "ecb(khazad)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = khazad_enc_tv_template, - .count = KHAZAD_ENC_TEST_VECTORS - }, - .dec = { - .vecs = khazad_dec_tv_template, - .count = KHAZAD_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ecb(seed)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = seed_enc_tv_template, - .count = SEED_ENC_TEST_VECTORS - }, - .dec = { - .vecs = seed_dec_tv_template, - .count = SEED_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ecb(serpent)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = serpent_enc_tv_template, - .count = SERPENT_ENC_TEST_VECTORS - }, - .dec = { - .vecs = serpent_dec_tv_template, - .count = SERPENT_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ecb(tea)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = tea_enc_tv_template, - .count = TEA_ENC_TEST_VECTORS - }, - .dec = { - .vecs = tea_dec_tv_template, - .count = TEA_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ecb(tnepres)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = tnepres_enc_tv_template, - .count = TNEPRES_ENC_TEST_VECTORS - }, - .dec = { - .vecs = tnepres_dec_tv_template, - .count = TNEPRES_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ecb(twofish)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = tf_enc_tv_template, - .count = TF_ENC_TEST_VECTORS - }, - .dec = { - .vecs = tf_dec_tv_template, - .count = TF_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ecb(xeta)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = xeta_enc_tv_template, - .count = XETA_ENC_TEST_VECTORS - }, - .dec = { - .vecs = xeta_dec_tv_template, - .count = XETA_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ecb(xtea)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = xtea_enc_tv_template, - .count = XTEA_ENC_TEST_VECTORS - }, - .dec = { - .vecs = xtea_dec_tv_template, - .count = XTEA_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ecdh", - .test = alg_test_kpp, - .fips_allowed = 1, - .suite = { - .kpp = { - .vecs = ecdh_tv_template, - .count = ECDH_TEST_VECTORS - } - } - }, { - .alg = "gcm(aes)", - .test = alg_test_aead, - .fips_allowed = 1, - .suite = { - .aead = { - .enc = { - .vecs = aes_gcm_enc_tv_template, - .count = AES_GCM_ENC_TEST_VECTORS - }, - .dec = { - .vecs = aes_gcm_dec_tv_template, - .count = AES_GCM_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "ghash", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = ghash_tv_template, - .count = GHASH_TEST_VECTORS - } - } - }, { - .alg = "hmac(crc32)", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = bfin_crc_tv_template, - .count = BFIN_CRC_TEST_VECTORS - } - } - }, { - .alg = "hmac(md5)", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = hmac_md5_tv_template, - .count = HMAC_MD5_TEST_VECTORS - } - } - }, { - .alg = "hmac(rmd128)", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = hmac_rmd128_tv_template, - .count = HMAC_RMD128_TEST_VECTORS - } - } - }, { - .alg = "hmac(rmd160)", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = hmac_rmd160_tv_template, - .count = HMAC_RMD160_TEST_VECTORS - } - } - }, { - .alg = "hmac(sha1)", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = hmac_sha1_tv_template, - .count = HMAC_SHA1_TEST_VECTORS - } - } - }, { - .alg = "hmac(sha224)", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = hmac_sha224_tv_template, - .count = HMAC_SHA224_TEST_VECTORS - } - } - }, { - .alg = "hmac(sha256)", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = hmac_sha256_tv_template, - .count = HMAC_SHA256_TEST_VECTORS - } - } - }, { - .alg = "hmac(sha3-224)", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = hmac_sha3_224_tv_template, - .count = HMAC_SHA3_224_TEST_VECTORS - } - } - }, { - .alg = "hmac(sha3-256)", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = hmac_sha3_256_tv_template, - .count = HMAC_SHA3_256_TEST_VECTORS - } - } - }, { - .alg = "hmac(sha3-384)", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = hmac_sha3_384_tv_template, - .count = HMAC_SHA3_384_TEST_VECTORS - } - } - }, { - .alg = "hmac(sha3-512)", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = hmac_sha3_512_tv_template, - .count = HMAC_SHA3_512_TEST_VECTORS - } - } - }, { - .alg = "hmac(sha384)", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = hmac_sha384_tv_template, - .count = HMAC_SHA384_TEST_VECTORS - } - } - }, { - .alg = "hmac(sha512)", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = hmac_sha512_tv_template, - .count = HMAC_SHA512_TEST_VECTORS - } - } - }, { - .alg = "jitterentropy_rng", - .fips_allowed = 1, - .test = alg_test_null, - }, { - .alg = "kw(aes)", - .test = alg_test_skcipher, - .fips_allowed = 1, - .suite = { - .cipher = { - .enc = { - .vecs = aes_kw_enc_tv_template, - .count = ARRAY_SIZE(aes_kw_enc_tv_template) - }, - .dec = { - .vecs = aes_kw_dec_tv_template, - .count = ARRAY_SIZE(aes_kw_dec_tv_template) - } - } - } - }, { - .alg = "lrw(aes)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = aes_lrw_enc_tv_template, - .count = AES_LRW_ENC_TEST_VECTORS - }, - .dec = { - .vecs = aes_lrw_dec_tv_template, - .count = AES_LRW_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "lrw(camellia)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = camellia_lrw_enc_tv_template, - .count = CAMELLIA_LRW_ENC_TEST_VECTORS - }, - .dec = { - .vecs = camellia_lrw_dec_tv_template, - .count = CAMELLIA_LRW_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "lrw(cast6)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = cast6_lrw_enc_tv_template, - .count = CAST6_LRW_ENC_TEST_VECTORS - }, - .dec = { - .vecs = cast6_lrw_dec_tv_template, - .count = CAST6_LRW_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "lrw(serpent)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = serpent_lrw_enc_tv_template, - .count = SERPENT_LRW_ENC_TEST_VECTORS - }, - .dec = { - .vecs = serpent_lrw_dec_tv_template, - .count = SERPENT_LRW_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "lrw(twofish)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = tf_lrw_enc_tv_template, - .count = TF_LRW_ENC_TEST_VECTORS - }, - .dec = { - .vecs = tf_lrw_dec_tv_template, - .count = TF_LRW_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "lz4", - .test = alg_test_comp, - .fips_allowed = 1, - .suite = { - .comp = { - .comp = { - .vecs = lz4_comp_tv_template, - .count = LZ4_COMP_TEST_VECTORS - }, - .decomp = { - .vecs = lz4_decomp_tv_template, - .count = LZ4_DECOMP_TEST_VECTORS - } - } - } - }, { - .alg = "lz4hc", - .test = alg_test_comp, - .fips_allowed = 1, - .suite = { - .comp = { - .comp = { - .vecs = lz4hc_comp_tv_template, - .count = LZ4HC_COMP_TEST_VECTORS - }, - .decomp = { - .vecs = lz4hc_decomp_tv_template, - .count = LZ4HC_DECOMP_TEST_VECTORS - } - } - } - }, { - .alg = "lzo", - .test = alg_test_comp, - .fips_allowed = 1, - .suite = { - .comp = { - .comp = { - .vecs = lzo_comp_tv_template, - .count = LZO_COMP_TEST_VECTORS - }, - .decomp = { - .vecs = lzo_decomp_tv_template, - .count = LZO_DECOMP_TEST_VECTORS - } - } - } - }, { - .alg = "md4", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = md4_tv_template, - .count = MD4_TEST_VECTORS - } - } - }, { - .alg = "md5", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = md5_tv_template, - .count = MD5_TEST_VECTORS - } - } - }, { - .alg = "michael_mic", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = michael_mic_tv_template, - .count = MICHAEL_MIC_TEST_VECTORS - } - } - }, { - .alg = "ofb(aes)", - .test = alg_test_skcipher, - .fips_allowed = 1, - .suite = { - .cipher = { - .enc = { - .vecs = aes_ofb_enc_tv_template, - .count = AES_OFB_ENC_TEST_VECTORS - }, - .dec = { - .vecs = aes_ofb_dec_tv_template, - .count = AES_OFB_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "pcbc(fcrypt)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = fcrypt_pcbc_enc_tv_template, - .count = FCRYPT_ENC_TEST_VECTORS - }, - .dec = { - .vecs = fcrypt_pcbc_dec_tv_template, - .count = FCRYPT_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "poly1305", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = poly1305_tv_template, - .count = POLY1305_TEST_VECTORS - } - } - }, { - .alg = "rfc3686(ctr(aes))", - .test = alg_test_skcipher, - .fips_allowed = 1, - .suite = { - .cipher = { - .enc = { - .vecs = aes_ctr_rfc3686_enc_tv_template, - .count = AES_CTR_3686_ENC_TEST_VECTORS - }, - .dec = { - .vecs = aes_ctr_rfc3686_dec_tv_template, - .count = AES_CTR_3686_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "rfc4106(gcm(aes))", - .test = alg_test_aead, - .fips_allowed = 1, - .suite = { - .aead = { - .enc = { - .vecs = aes_gcm_rfc4106_enc_tv_template, - .count = AES_GCM_4106_ENC_TEST_VECTORS - }, - .dec = { - .vecs = aes_gcm_rfc4106_dec_tv_template, - .count = AES_GCM_4106_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "rfc4309(ccm(aes))", - .test = alg_test_aead, - .fips_allowed = 1, - .suite = { - .aead = { - .enc = { - .vecs = aes_ccm_rfc4309_enc_tv_template, - .count = AES_CCM_4309_ENC_TEST_VECTORS - }, - .dec = { - .vecs = aes_ccm_rfc4309_dec_tv_template, - .count = AES_CCM_4309_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "rfc4543(gcm(aes))", - .test = alg_test_aead, - .suite = { - .aead = { - .enc = { - .vecs = aes_gcm_rfc4543_enc_tv_template, - .count = AES_GCM_4543_ENC_TEST_VECTORS - }, - .dec = { - .vecs = aes_gcm_rfc4543_dec_tv_template, - .count = AES_GCM_4543_DEC_TEST_VECTORS - }, - } - } - }, { - .alg = "rfc7539(chacha20,poly1305)", - .test = alg_test_aead, - .suite = { - .aead = { - .enc = { - .vecs = rfc7539_enc_tv_template, - .count = RFC7539_ENC_TEST_VECTORS - }, - .dec = { - .vecs = rfc7539_dec_tv_template, - .count = RFC7539_DEC_TEST_VECTORS - }, - } - } - }, { - .alg = "rfc7539esp(chacha20,poly1305)", - .test = alg_test_aead, - .suite = { - .aead = { - .enc = { - .vecs = rfc7539esp_enc_tv_template, - .count = RFC7539ESP_ENC_TEST_VECTORS - }, - .dec = { - .vecs = rfc7539esp_dec_tv_template, - .count = RFC7539ESP_DEC_TEST_VECTORS - }, - } - } - }, { - .alg = "rmd128", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = rmd128_tv_template, - .count = RMD128_TEST_VECTORS - } - } - }, { - .alg = "rmd160", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = rmd160_tv_template, - .count = RMD160_TEST_VECTORS - } - } - }, { - .alg = "rmd256", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = rmd256_tv_template, - .count = RMD256_TEST_VECTORS - } - } - }, { - .alg = "rmd320", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = rmd320_tv_template, - .count = RMD320_TEST_VECTORS - } - } - }, { - .alg = "rsa", - .test = alg_test_akcipher, - .fips_allowed = 1, - .suite = { - .akcipher = { - .vecs = rsa_tv_template, - .count = RSA_TEST_VECTORS - } - } - }, { - .alg = "salsa20", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = salsa20_stream_enc_tv_template, - .count = SALSA20_STREAM_ENC_TEST_VECTORS - } - } - } - }, { - .alg = "sha1", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = sha1_tv_template, - .count = SHA1_TEST_VECTORS - } - } - }, { - .alg = "sha224", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = sha224_tv_template, - .count = SHA224_TEST_VECTORS - } - } - }, { - .alg = "sha256", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = sha256_tv_template, - .count = SHA256_TEST_VECTORS - } - } - }, { - .alg = "sha3-224", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = sha3_224_tv_template, - .count = SHA3_224_TEST_VECTORS - } - } - }, { - .alg = "sha3-256", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = sha3_256_tv_template, - .count = SHA3_256_TEST_VECTORS - } - } - }, { - .alg = "sha3-384", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = sha3_384_tv_template, - .count = SHA3_384_TEST_VECTORS - } - } - }, { - .alg = "sha3-512", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = sha3_512_tv_template, - .count = SHA3_512_TEST_VECTORS - } - } - }, { - .alg = "sha384", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = sha384_tv_template, - .count = SHA384_TEST_VECTORS - } - } - }, { - .alg = "sha512", - .test = alg_test_hash, - .fips_allowed = 1, - .suite = { - .hash = { - .vecs = sha512_tv_template, - .count = SHA512_TEST_VECTORS - } - } - }, { - .alg = "tgr128", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = tgr128_tv_template, - .count = TGR128_TEST_VECTORS - } - } - }, { - .alg = "tgr160", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = tgr160_tv_template, - .count = TGR160_TEST_VECTORS - } - } - }, { - .alg = "tgr192", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = tgr192_tv_template, - .count = TGR192_TEST_VECTORS - } - } - }, { - .alg = "vmac(aes)", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = aes_vmac128_tv_template, - .count = VMAC_AES_TEST_VECTORS - } - } - }, { - .alg = "wp256", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = wp256_tv_template, - .count = WP256_TEST_VECTORS - } - } - }, { - .alg = "wp384", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = wp384_tv_template, - .count = WP384_TEST_VECTORS - } - } - }, { - .alg = "wp512", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = wp512_tv_template, - .count = WP512_TEST_VECTORS - } - } - }, { - .alg = "xcbc(aes)", - .test = alg_test_hash, - .suite = { - .hash = { - .vecs = aes_xcbc128_tv_template, - .count = XCBC_AES_TEST_VECTORS - } - } - }, { - .alg = "xts(aes)", - .test = alg_test_skcipher, - .fips_allowed = 1, - .suite = { - .cipher = { - .enc = { - .vecs = aes_xts_enc_tv_template, - .count = AES_XTS_ENC_TEST_VECTORS - }, - .dec = { - .vecs = aes_xts_dec_tv_template, - .count = AES_XTS_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "xts(camellia)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = camellia_xts_enc_tv_template, - .count = CAMELLIA_XTS_ENC_TEST_VECTORS - }, - .dec = { - .vecs = camellia_xts_dec_tv_template, - .count = CAMELLIA_XTS_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "xts(cast6)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = cast6_xts_enc_tv_template, - .count = CAST6_XTS_ENC_TEST_VECTORS - }, - .dec = { - .vecs = cast6_xts_dec_tv_template, - .count = CAST6_XTS_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "xts(serpent)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = serpent_xts_enc_tv_template, - .count = SERPENT_XTS_ENC_TEST_VECTORS - }, - .dec = { - .vecs = serpent_xts_dec_tv_template, - .count = SERPENT_XTS_DEC_TEST_VECTORS - } - } - } - }, { - .alg = "xts(twofish)", - .test = alg_test_skcipher, - .suite = { - .cipher = { - .enc = { - .vecs = tf_xts_enc_tv_template, - .count = TF_XTS_ENC_TEST_VECTORS - }, - .dec = { - .vecs = tf_xts_dec_tv_template, - .count = TF_XTS_DEC_TEST_VECTORS - } - } - } - } -}; - -static bool alg_test_descs_checked; - -static void alg_test_descs_check_order(void) -{ - int i; - - /* only check once */ - if (alg_test_descs_checked) - return; - - alg_test_descs_checked = true; - - for (i = 1; i < ARRAY_SIZE(alg_test_descs); i++) { - int diff = strcmp(alg_test_descs[i - 1].alg, - alg_test_descs[i].alg); - - if (WARN_ON(diff > 0)) { - pr_warn("testmgr: alg_test_descs entries in wrong order: '%s' before '%s'\n", - alg_test_descs[i - 1].alg, - alg_test_descs[i].alg); - } - - if (WARN_ON(diff == 0)) { - pr_warn("testmgr: duplicate alg_test_descs entry: '%s'\n", - alg_test_descs[i].alg); - } - } -} - -static int alg_find_test(const char *alg) -{ - int start = 0; - int end = ARRAY_SIZE(alg_test_descs); - - while (start < end) { - int i = (start + end) / 2; - int diff = strcmp(alg_test_descs[i].alg, alg); - - if (diff > 0) { - end = i; - continue; - } - - if (diff < 0) { - start = i + 1; - continue; - } - - return i; - } - - return -1; -} - -int alg_test(const char *driver, const char *alg, u32 type, u32 mask) -{ - int i; - int j; - int rc; - - if (!fips_enabled && notests) { - printk_once(KERN_INFO "alg: self-tests disabled\n"); - return 0; - } - - alg_test_descs_check_order(); - - if ((type & CRYPTO_ALG_TYPE_MASK) == CRYPTO_ALG_TYPE_CIPHER) { - char nalg[CRYPTO_MAX_ALG_NAME]; - - if (snprintf(nalg, sizeof(nalg), "ecb(%s)", alg) >= - sizeof(nalg)) - return -ENAMETOOLONG; - - i = alg_find_test(nalg); - if (i < 0) - goto notest; - - if (fips_enabled && !alg_test_descs[i].fips_allowed) - goto non_fips_alg; - - rc = alg_test_cipher(alg_test_descs + i, driver, type, mask); - goto test_done; - } - - i = alg_find_test(alg); - j = alg_find_test(driver); - if (i < 0 && j < 0) - goto notest; - - if (fips_enabled && ((i >= 0 && !alg_test_descs[i].fips_allowed) || - (j >= 0 && !alg_test_descs[j].fips_allowed))) - goto non_fips_alg; - - rc = 0; - if (i >= 0) - rc |= alg_test_descs[i].test(alg_test_descs + i, driver, - type, mask); - if (j >= 0 && j != i) - rc |= alg_test_descs[j].test(alg_test_descs + j, driver, - type, mask); - -test_done: - if (fips_enabled && rc) - panic("%s: %s alg self test failed in fips mode!\n", driver, alg); - - if (fips_enabled && !rc) - pr_info("alg: self-tests for %s (%s) passed\n", driver, alg); - - return rc; - -notest: - printk(KERN_INFO "alg: No test for %s (%s)\n", alg, driver); - return 0; -non_fips_alg: - return -EINVAL; -} - -#endif /* CONFIG_CRYPTO_MANAGER_DISABLE_TESTS */ - -EXPORT_SYMBOL_GPL(alg_test); diff --git a/src/linux/crypto/xor.c b/src/linux/crypto/xor.c deleted file mode 100644 index 20475c8..0000000 --- a/src/linux/crypto/xor.c +++ /dev/null @@ -1,170 +0,0 @@ -/* - * xor.c : Multiple Devices driver for Linux - * - * Copyright (C) 1996, 1997, 1998, 1999, 2000, - * Ingo Molnar, Matti Aarnio, Jakub Jelinek, Richard Henderson. - * - * Dispatch optimized RAID-5 checksumming functions. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * You should have received a copy of the GNU General Public License - * (for example /usr/src/linux/COPYING); if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#define BH_TRACE 0 -#include -#include -#include -#include -#include -#include -#include - -#ifndef XOR_SELECT_TEMPLATE -#define XOR_SELECT_TEMPLATE(x) (x) -#endif - -/* The xor routines to use. */ -static struct xor_block_template *active_template; - -void -xor_blocks(unsigned int src_count, unsigned int bytes, void *dest, void **srcs) -{ - unsigned long *p1, *p2, *p3, *p4; - - p1 = (unsigned long *) srcs[0]; - if (src_count == 1) { - active_template->do_2(bytes, dest, p1); - return; - } - - p2 = (unsigned long *) srcs[1]; - if (src_count == 2) { - active_template->do_3(bytes, dest, p1, p2); - return; - } - - p3 = (unsigned long *) srcs[2]; - if (src_count == 3) { - active_template->do_4(bytes, dest, p1, p2, p3); - return; - } - - p4 = (unsigned long *) srcs[3]; - active_template->do_5(bytes, dest, p1, p2, p3, p4); -} -EXPORT_SYMBOL(xor_blocks); - -/* Set of all registered templates. */ -static struct xor_block_template *__initdata template_list; - -#define BENCH_SIZE (PAGE_SIZE) - -static void __init -do_xor_speed(struct xor_block_template *tmpl, void *b1, void *b2) -{ - int speed; - unsigned long now, j; - int i, count, max; - - tmpl->next = template_list; - template_list = tmpl; - - preempt_disable(); - - /* - * Count the number of XORs done during a whole jiffy, and use - * this to calculate the speed of checksumming. We use a 2-page - * allocation to have guaranteed color L1-cache layout. - */ - max = 0; - for (i = 0; i < 5; i++) { - j = jiffies; - count = 0; - while ((now = jiffies) == j) - cpu_relax(); - while (time_before(jiffies, now + 1)) { - mb(); /* prevent loop optimzation */ - tmpl->do_2(BENCH_SIZE, b1, b2); - mb(); - count++; - mb(); - cpu_yield_to_irqs(); - } - if (count > max) - max = count; - } - - preempt_enable(); - - speed = max * (HZ * BENCH_SIZE / 1024); - tmpl->speed = speed; - - printk(KERN_INFO " %-10s: %5d.%03d MB/sec\n", tmpl->name, - speed / 1000, speed % 1000); -} - -static int __init -calibrate_xor_blocks(void) -{ - void *b1, *b2; - struct xor_block_template *f, *fastest; - - fastest = XOR_SELECT_TEMPLATE(NULL); - - if (fastest) { - printk(KERN_INFO "xor: automatically using best " - "checksumming function %-10s\n", - fastest->name); - goto out; - } - - /* - * Note: Since the memory is not actually used for _anything_ but to - * test the XOR speed, we don't really want kmemcheck to warn about - * reading uninitialized bytes here. - */ - b1 = (void *) __get_free_pages(GFP_KERNEL | __GFP_NOTRACK, 2); - if (!b1) { - printk(KERN_WARNING "xor: Yikes! No memory available.\n"); - return -ENOMEM; - } - b2 = b1 + 2*PAGE_SIZE + BENCH_SIZE; - - /* - * If this arch/cpu has a short-circuited selection, don't loop through - * all the possible functions, just test the best one - */ - -#define xor_speed(templ) do_xor_speed((templ), b1, b2) - - printk(KERN_INFO "xor: measuring software checksum speed\n"); - XOR_TRY_TEMPLATES; - fastest = template_list; - for (f = fastest; f; f = f->next) - if (f->speed > fastest->speed) - fastest = f; - - printk(KERN_INFO "xor: using function: %s (%d.%03d MB/sec)\n", - fastest->name, fastest->speed / 1000, fastest->speed % 1000); - -#undef xor_speed - - free_pages((unsigned long)b1, 2); -out: - active_template = fastest; - return 0; -} - -static __exit void xor_exit(void) { } - -MODULE_LICENSE("GPL"); - -/* when built-in xor.o must initialize before drivers/md/md.o */ -core_initcall(calibrate_xor_blocks); -module_exit(xor_exit); diff --git a/src/linux/drivers/Kconfig b/src/linux/drivers/Kconfig deleted file mode 100644 index e1e2066..0000000 --- a/src/linux/drivers/Kconfig +++ /dev/null @@ -1,205 +0,0 @@ -menu "Device Drivers" - -source "drivers/amba/Kconfig" - -source "drivers/base/Kconfig" - -source "drivers/bus/Kconfig" - -source "drivers/connector/Kconfig" - -source "drivers/mtd/Kconfig" - -source "drivers/of/Kconfig" - -source "drivers/parport/Kconfig" - -source "drivers/pnp/Kconfig" - -source "drivers/block/Kconfig" - -source "drivers/nvme/Kconfig" - -# misc before ide - BLK_DEV_SGIIOC4 depends on SGI_IOC4 - -source "drivers/misc/Kconfig" - -source "drivers/ide/Kconfig" - -source "drivers/scsi/Kconfig" - -source "drivers/ata/Kconfig" - -source "drivers/md/Kconfig" - -source "drivers/target/Kconfig" - -source "drivers/message/fusion/Kconfig" - -source "drivers/firewire/Kconfig" - -source "drivers/macintosh/Kconfig" - -source "drivers/net/Kconfig" - -source "drivers/isdn/Kconfig" - -source "drivers/lightnvm/Kconfig" - -# input before char - char/joystick depends on it. As does USB. - -source "drivers/input/Kconfig" - -source "drivers/char/Kconfig" - -source "drivers/i2c/Kconfig" - -source "drivers/spi/Kconfig" - -source "drivers/spmi/Kconfig" - -source "drivers/hsi/Kconfig" - -source "drivers/pps/Kconfig" - -source "drivers/ptp/Kconfig" - -source "drivers/pinctrl/Kconfig" - -source "drivers/gpio/Kconfig" - -source "drivers/w1/Kconfig" - -source "drivers/power/Kconfig" - -source "drivers/hwmon/Kconfig" - -source "drivers/thermal/Kconfig" - -source "drivers/watchdog/Kconfig" - -source "drivers/ssb/Kconfig" - -source "drivers/bcma/Kconfig" - -source "drivers/mfd/Kconfig" - -source "drivers/regulator/Kconfig" - -source "drivers/media/Kconfig" - -source "drivers/video/Kconfig" - -source "sound/Kconfig" - -source "drivers/hid/Kconfig" - -source "drivers/usb/Kconfig" - -source "drivers/uwb/Kconfig" - -source "drivers/mmc/Kconfig" - -source "drivers/memstick/Kconfig" - -source "drivers/leds/Kconfig" - -source "drivers/accessibility/Kconfig" - -source "drivers/infiniband/Kconfig" - -source "drivers/edac/Kconfig" - -source "drivers/rtc/Kconfig" - -source "drivers/dma/Kconfig" - -source "drivers/dma-buf/Kconfig" - -source "drivers/dca/Kconfig" - -source "drivers/auxdisplay/Kconfig" - -source "drivers/uio/Kconfig" - -source "drivers/vfio/Kconfig" - -source "drivers/vlynq/Kconfig" - -source "drivers/virt/Kconfig" - -source "drivers/virtio/Kconfig" - -source "drivers/hv/Kconfig" - -source "drivers/xen/Kconfig" - -source "drivers/staging/Kconfig" - -source "drivers/platform/Kconfig" - -source "drivers/clk/Kconfig" - -source "drivers/hwspinlock/Kconfig" - -source "drivers/clocksource/Kconfig" - -source "drivers/mailbox/Kconfig" - -source "drivers/iommu/Kconfig" - -source "drivers/remoteproc/Kconfig" - -source "drivers/rpmsg/Kconfig" - -source "drivers/soc/Kconfig" - -source "drivers/devfreq/Kconfig" - -source "drivers/extcon/Kconfig" - -source "drivers/memory/Kconfig" - -source "drivers/iio/Kconfig" - -source "drivers/ntb/Kconfig" - -source "drivers/vme/Kconfig" - -source "drivers/pwm/Kconfig" - -source "drivers/irqchip/Kconfig" - -source "drivers/ipack/Kconfig" - -source "drivers/reset/Kconfig" - -source "drivers/fmc/Kconfig" - -source "drivers/phy/Kconfig" - -source "drivers/powercap/Kconfig" - -source "drivers/mcb/Kconfig" - -source "drivers/perf/Kconfig" - -source "drivers/ras/Kconfig" - -source "drivers/thunderbolt/Kconfig" - -source "drivers/android/Kconfig" - -source "drivers/nvdimm/Kconfig" - -source "drivers/dax/Kconfig" - -source "drivers/nvmem/Kconfig" - -source "drivers/hwtracing/stm/Kconfig" - -source "drivers/hwtracing/intel_th/Kconfig" - -source "drivers/fpga/Kconfig" - -endmenu diff --git a/src/linux/drivers/Makefile b/src/linux/drivers/Makefile deleted file mode 100644 index 194d20b..0000000 --- a/src/linux/drivers/Makefile +++ /dev/null @@ -1,175 +0,0 @@ -# -# Makefile for the Linux kernel device drivers. -# -# 15 Sep 2000, Christoph Hellwig -# Rewritten to use lists instead of if-statements. -# - -obj-y += irqchip/ -obj-y += bus/ - -obj-$(CONFIG_GENERIC_PHY) += phy/ - -# GPIO must come after pinctrl as gpios may need to mux pins etc -obj-$(CONFIG_PINCTRL) += pinctrl/ -obj-$(CONFIG_GPIOLIB) += gpio/ -obj-y += pwm/ -obj-$(CONFIG_PCI) += pci/ -obj-$(CONFIG_PARISC) += parisc/ -obj-$(CONFIG_RAPIDIO) += rapidio/ -obj-y += video/ -obj-y += idle/ - -# IPMI must come before ACPI in order to provide IPMI opregion support -obj-y += char/ipmi/ - -obj-$(CONFIG_ACPI) += acpi/ -obj-$(CONFIG_SFI) += sfi/ -# PnP must come after ACPI since it will eventually need to check if acpi -# was used and do nothing if so -obj-$(CONFIG_PNP) += pnp/ -obj-y += amba/ - -obj-y += clk/ -# Many drivers will want to use DMA so this has to be made available -# really early. -obj-$(CONFIG_DMADEVICES) += dma/ - -# SOC specific infrastructure drivers. -obj-y += soc/ - -obj-$(CONFIG_VIRTIO) += virtio/ -obj-$(CONFIG_XEN) += xen/ - -# regulators early, since some subsystems rely on them to initialize -obj-$(CONFIG_REGULATOR) += regulator/ - -# reset controllers early, since gpu drivers might rely on them to initialize -obj-$(CONFIG_RESET_CONTROLLER) += reset/ - -# tty/ comes before char/ so that the VT console is the boot-time -# default. -obj-y += tty/ -obj-y += char/ - -# iommu/ comes before gpu as gpu are using iommu controllers -obj-$(CONFIG_IOMMU_SUPPORT) += iommu/ - -# gpu/ comes after char for AGP vs DRM startup and after iommu -obj-y += gpu/ - -obj-$(CONFIG_CONNECTOR) += connector/ - -# i810fb and intelfb depend on char/agp/ -obj-$(CONFIG_FB_I810) += video/fbdev/i810/ -obj-$(CONFIG_FB_INTEL) += video/fbdev/intelfb/ - -obj-$(CONFIG_PARPORT) += parport/ -obj-$(CONFIG_NVM) += lightnvm/ -obj-y += base/ block/ misc/ mfd/ nfc/ -obj-$(CONFIG_LIBNVDIMM) += nvdimm/ -obj-$(CONFIG_DEV_DAX) += dax/ -obj-$(CONFIG_DMA_SHARED_BUFFER) += dma-buf/ -obj-$(CONFIG_NUBUS) += nubus/ -obj-y += macintosh/ -obj-$(CONFIG_IDE) += ide/ -obj-$(CONFIG_SCSI) += scsi/ -obj-y += nvme/ -obj-$(CONFIG_ATA) += ata/ -obj-$(CONFIG_TARGET_CORE) += target/ -obj-$(CONFIG_MTD) += mtd/ -obj-$(CONFIG_SPI) += spi/ -obj-$(CONFIG_SPMI) += spmi/ -obj-$(CONFIG_HSI) += hsi/ -obj-y += net/ -obj-$(CONFIG_ATM) += atm/ -obj-$(CONFIG_FUSION) += message/ -obj-y += firewire/ -obj-$(CONFIG_UIO) += uio/ -obj-$(CONFIG_VFIO) += vfio/ -obj-y += cdrom/ -obj-y += auxdisplay/ -obj-$(CONFIG_PCCARD) += pcmcia/ -obj-$(CONFIG_DIO) += dio/ -obj-$(CONFIG_SBUS) += sbus/ -obj-$(CONFIG_ZORRO) += zorro/ -obj-$(CONFIG_ATA_OVER_ETH) += block/aoe/ -obj-$(CONFIG_PARIDE) += block/paride/ -obj-$(CONFIG_TC) += tc/ -obj-$(CONFIG_UWB) += uwb/ -obj-$(CONFIG_USB_PHY) += usb/ -obj-$(CONFIG_USB) += usb/ -obj-$(CONFIG_PCI) += usb/ -obj-$(CONFIG_USB_GADGET) += usb/ -obj-$(CONFIG_SERIO) += input/serio/ -obj-$(CONFIG_GAMEPORT) += input/gameport/ -obj-$(CONFIG_INPUT) += input/ -obj-$(CONFIG_RTC_LIB) += rtc/ -obj-y += i2c/ media/ -obj-$(CONFIG_PPS) += pps/ -obj-$(CONFIG_PTP_1588_CLOCK) += ptp/ -obj-$(CONFIG_W1) += w1/ -obj-y += power/ -obj-$(CONFIG_HWMON) += hwmon/ -obj-$(CONFIG_THERMAL) += thermal/ -obj-$(CONFIG_WATCHDOG) += watchdog/ -obj-$(CONFIG_MD) += md/ -obj-$(CONFIG_BT) += bluetooth/ -obj-$(CONFIG_ACCESSIBILITY) += accessibility/ -obj-$(CONFIG_ISDN) += isdn/ -obj-$(CONFIG_EDAC) += edac/ -obj-$(CONFIG_EISA) += eisa/ -obj-y += lguest/ -obj-$(CONFIG_CPU_FREQ) += cpufreq/ -obj-$(CONFIG_CPU_IDLE) += cpuidle/ -obj-y += mmc/ -obj-$(CONFIG_MEMSTICK) += memstick/ -obj-$(CONFIG_NEW_LEDS) += leds/ -obj-$(CONFIG_INFINIBAND) += infiniband/ -obj-$(CONFIG_SGI_SN) += sn/ -obj-y += firmware/ -obj-$(CONFIG_CRYPTO) += crypto/ -obj-$(CONFIG_SUPERH) += sh/ -ifndef CONFIG_ARCH_USES_GETTIMEOFFSET -obj-y += clocksource/ -endif -obj-$(CONFIG_DCA) += dca/ -obj-$(CONFIG_HID) += hid/ -obj-$(CONFIG_PPC_PS3) += ps3/ -obj-$(CONFIG_OF) += of/ -obj-$(CONFIG_SSB) += ssb/ -obj-$(CONFIG_BCMA) += bcma/ -obj-$(CONFIG_VHOST_RING) += vhost/ -obj-$(CONFIG_VHOST) += vhost/ -obj-$(CONFIG_VLYNQ) += vlynq/ -obj-$(CONFIG_STAGING) += staging/ -obj-y += platform/ - -obj-$(CONFIG_MAILBOX) += mailbox/ -obj-$(CONFIG_HWSPINLOCK) += hwspinlock/ -obj-$(CONFIG_REMOTEPROC) += remoteproc/ -obj-$(CONFIG_RPMSG) += rpmsg/ - -# Virtualization drivers -obj-$(CONFIG_VIRT_DRIVERS) += virt/ -obj-$(CONFIG_HYPERV) += hv/ - -obj-$(CONFIG_PM_DEVFREQ) += devfreq/ -obj-$(CONFIG_EXTCON) += extcon/ -obj-$(CONFIG_MEMORY) += memory/ -obj-$(CONFIG_IIO) += iio/ -obj-$(CONFIG_VME_BUS) += vme/ -obj-$(CONFIG_IPACK_BUS) += ipack/ -obj-$(CONFIG_NTB) += ntb/ -obj-$(CONFIG_FMC) += fmc/ -obj-$(CONFIG_POWERCAP) += powercap/ -obj-$(CONFIG_MCB) += mcb/ -obj-$(CONFIG_PERF_EVENTS) += perf/ -obj-$(CONFIG_RAS) += ras/ -obj-$(CONFIG_THUNDERBOLT) += thunderbolt/ -obj-$(CONFIG_CORESIGHT) += hwtracing/coresight/ -obj-y += hwtracing/intel_th/ -obj-$(CONFIG_STM) += hwtracing/stm/ -obj-$(CONFIG_ANDROID) += android/ -obj-$(CONFIG_NVMEM) += nvmem/ -obj-$(CONFIG_FPGA) += fpga/ diff --git a/src/linux/drivers/accessibility/Kconfig b/src/linux/drivers/accessibility/Kconfig deleted file mode 100644 index ef3b65b..0000000 --- a/src/linux/drivers/accessibility/Kconfig +++ /dev/null @@ -1,33 +0,0 @@ -menuconfig ACCESSIBILITY - bool "Accessibility support" - ---help--- - Accessibility handles all special kinds of hardware devices or - software adapters which help people with disabilities (e.g. - blindness) to use computers. - - That includes braille devices, speech synthesis, keyboard - remapping, etc. - - Say Y here to get to see options for accessibility. - This option alone does not add any kernel code. - - If you say N, all options in this submenu will be skipped and disabled. - - If unsure, say N. - -if ACCESSIBILITY -config A11Y_BRAILLE_CONSOLE - bool "Console on braille device" - depends on VT - depends on SERIAL_CORE_CONSOLE - ---help--- - Enables console output on a braille device connected to a 8250 - serial port. For now only the VisioBraille device is supported. - - To actually enable it, you need to pass option - console=brl,ttyS0 - to the kernel. Options are the same as for serial console. - - If unsure, say N. - -endif # ACCESSIBILITY diff --git a/src/linux/drivers/amba/Kconfig b/src/linux/drivers/amba/Kconfig deleted file mode 100644 index 294ba6f..0000000 --- a/src/linux/drivers/amba/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config ARM_AMBA - bool - -if ARM_AMBA - -config TEGRA_AHB - bool - default y if ARCH_TEGRA - help - Adds AHB configuration functionality for NVIDIA Tegra SoCs, - which controls AHB bus master arbitration and some performance - parameters (priority, prefetch size). - -endif diff --git a/src/linux/drivers/amba/Makefile b/src/linux/drivers/amba/Makefile deleted file mode 100644 index 66e81c2..0000000 --- a/src/linux/drivers/amba/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-$(CONFIG_ARM_AMBA) += bus.o -obj-$(CONFIG_TEGRA_AHB) += tegra-ahb.o diff --git a/src/linux/drivers/android/Kconfig b/src/linux/drivers/android/Kconfig deleted file mode 100644 index bdfc6c6..0000000 --- a/src/linux/drivers/android/Kconfig +++ /dev/null @@ -1,37 +0,0 @@ -menu "Android" - -config ANDROID - bool "Android Drivers" - ---help--- - Enable support for various drivers needed on the Android platform - -if ANDROID - -config ANDROID_BINDER_IPC - bool "Android Binder IPC Driver" - depends on MMU - default n - ---help--- - Binder is used in Android for both communication between processes, - and remote method invocation. - - This means one Android process can call a method/routine in another - Android process, using Binder to identify, invoke and pass arguments - between said processes. - -config ANDROID_BINDER_IPC_32BIT - bool - depends on !64BIT && ANDROID_BINDER_IPC - default y - ---help--- - The Binder API has been changed to support both 32 and 64bit - applications in a mixed environment. - - Enable this to support an old 32-bit Android user-space (v4.4 and - earlier). - - Note that enabling this will break newer Android user-space. - -endif # if ANDROID - -endmenu diff --git a/src/linux/drivers/ata/Kconfig b/src/linux/drivers/ata/Kconfig deleted file mode 100644 index 2c8be74..0000000 --- a/src/linux/drivers/ata/Kconfig +++ /dev/null @@ -1,1052 +0,0 @@ -# -# SATA/PATA driver configuration -# - -config HAVE_PATA_PLATFORM - bool - help - This is an internal configuration node for any machine that - uses pata-platform driver to enable the relevant driver in the - configuration structure without having to submit endless patches - to update the PATA_PLATFORM entry. - -menuconfig ATA - tristate "Serial ATA and Parallel ATA drivers (libata)" - depends on HAS_IOMEM - depends on BLOCK - depends on !(M32R || M68K || S390) || BROKEN - select SCSI - select GLOB - ---help--- - If you want to use an ATA hard disk, ATA tape drive, ATA CD-ROM or - any other ATA device under Linux, say Y and make sure that you know - the name of your ATA host adapter (the card inside your computer - that "speaks" the ATA protocol, also called ATA controller), - because you will be asked for it. - - NOTE: ATA enables basic SCSI support; *however*, - 'SCSI disk support', 'SCSI tape support', or - 'SCSI CDROM support' may also be needed, - depending on your hardware configuration. - -if ATA - -config ATA_NONSTANDARD - bool - default n - -config ATA_VERBOSE_ERROR - bool "Verbose ATA error reporting" - default y - help - This option adds parsing of ATA command descriptions and error bits - in libata kernel output, making it easier to interpret. - This option will enlarge the kernel by approx. 6KB. Disable it only - if kernel size is more important than ease of debugging. - - If unsure, say Y. - -config ATA_ACPI - bool "ATA ACPI Support" - depends on ACPI - default y - help - This option adds support for ATA-related ACPI objects. - These ACPI objects add the ability to retrieve taskfiles - from the ACPI BIOS and write them to the disk controller. - These objects may be related to performance, security, - power management, or other areas. - You can disable this at kernel boot time by using the - option libata.noacpi=1 - -config SATA_ZPODD - bool "SATA Zero Power Optical Disc Drive (ZPODD) support" - depends on ATA_ACPI && PM - default n - help - This option adds support for SATA Zero Power Optical Disc - Drive (ZPODD). It requires both the ODD and the platform - support, and if enabled, will automatically power on/off the - ODD when certain condition is satisfied. This does not impact - end user's experience of the ODD, only power is saved when - the ODD is not in use (i.e. no disc inside). - - If unsure, say N. - -config SATA_PMP - bool "SATA Port Multiplier support" - default y - help - This option adds support for SATA Port Multipliers - (the SATA version of an ethernet hub, or SAS expander). - -comment "Controllers with non-SFF native interface" - -config SATA_AHCI - tristate "AHCI SATA support" - depends on PCI - help - This option enables support for AHCI Serial ATA. - - If unsure, say N. - -config SATA_AHCI_PLATFORM - tristate "Platform AHCI SATA support" - help - This option enables support for Platform AHCI Serial ATA - controllers. - - If unsure, say N. - -config AHCI_BRCM - tristate "Broadcom AHCI SATA support" - depends on ARCH_BRCMSTB || BMIPS_GENERIC || ARCH_BCM_NSP - help - This option enables support for the AHCI SATA3 controller found on - Broadcom SoC's. - - If unsure, say N. - -config AHCI_DA850 - tristate "DaVinci DA850 AHCI SATA support" - depends on ARCH_DAVINCI_DA850 - help - This option enables support for the DaVinci DA850 SoC's - onboard AHCI SATA. - - If unsure, say N. - -config AHCI_ST - tristate "ST AHCI SATA support" - depends on ARCH_STI - help - This option enables support for ST AHCI SATA controller. - - If unsure, say N. - -config AHCI_IMX - tristate "Freescale i.MX AHCI SATA support" - depends on MFD_SYSCON && (ARCH_MXC || COMPILE_TEST) - help - This option enables support for the Freescale i.MX SoC's - onboard AHCI SATA. - - If unsure, say N. - -config AHCI_CEVA - tristate "CEVA AHCI SATA support" - depends on OF - help - This option enables support for the CEVA AHCI SATA. - It can be found on the Xilinx Zynq UltraScale+ MPSoC. - - If unsure, say N. - -config AHCI_MVEBU - tristate "Marvell EBU AHCI SATA support" - depends on ARCH_MVEBU - help - This option enables support for the Marvebu EBU SoC's - onboard AHCI SATA. - - If unsure, say N. - -config AHCI_OCTEON - tristate "Cavium Octeon Soc Serial ATA" - depends on SATA_AHCI_PLATFORM && CAVIUM_OCTEON_SOC - default y - help - This option enables support for Cavium Octeon SoC Serial ATA. - - If unsure, say N. - -config AHCI_SUNXI - tristate "Allwinner sunxi AHCI SATA support" - depends on ARCH_SUNXI - help - This option enables support for the Allwinner sunxi SoC's - onboard AHCI SATA. - - If unsure, say N. - -config AHCI_TEGRA - tristate "NVIDIA Tegra124 AHCI SATA support" - depends on ARCH_TEGRA - help - This option enables support for the NVIDIA Tegra124 SoC's - onboard AHCI SATA. - - If unsure, say N. - -config AHCI_XGENE - tristate "APM X-Gene 6.0Gbps AHCI SATA host controller support" - depends on PHY_XGENE - help - This option enables support for APM X-Gene SoC SATA host controller. - -config AHCI_QORIQ - tristate "Freescale QorIQ AHCI SATA support" - depends on OF - help - This option enables support for the Freescale QorIQ AHCI SoC's - onboard AHCI SATA. - - If unsure, say N. - -config SATA_FSL - tristate "Freescale 3.0Gbps SATA support" - depends on FSL_SOC - help - This option enables support for Freescale 3.0Gbps SATA controller. - It can be found on MPC837x and MPC8315. - - If unsure, say N. - -config SATA_AHCI_SEATTLE - tristate "AMD Seattle 6.0Gbps AHCI SATA host controller support" - depends on ARCH_SEATTLE - help - This option enables support for AMD Seattle SATA host controller. - - If unsure, say N - -config SATA_INIC162X - tristate "Initio 162x SATA support (Very Experimental)" - depends on PCI - help - This option enables support for Initio 162x Serial ATA. - -config SATA_ACARD_AHCI - tristate "ACard AHCI variant (ATP 8620)" - depends on PCI - help - This option enables support for Acard. - - If unsure, say N. - -config SATA_SIL24 - tristate "Silicon Image 3124/3132 SATA support" - depends on PCI - help - This option enables support for Silicon Image 3124/3132 Serial ATA. - - If unsure, say N. - -config ATA_SFF - bool "ATA SFF support (for legacy IDE and PATA)" - default y - help - This option adds support for ATA controllers with SFF - compliant or similar programming interface. - - SFF is the legacy IDE interface that has been around since - the dawn of time. Almost all PATA controllers have an - SFF interface. Many SATA controllers have an SFF interface - when configured into a legacy compatibility mode. - - For users with exclusively modern controllers like AHCI, - Silicon Image 3124, or Marvell 6440, you may choose to - disable this unneeded SFF support. - - If unsure, say Y. - -if ATA_SFF - -comment "SFF controllers with custom DMA interface" - -config PDC_ADMA - tristate "Pacific Digital ADMA support" - depends on PCI - help - This option enables support for Pacific Digital ADMA controllers - - If unsure, say N. - -config PATA_OCTEON_CF - tristate "OCTEON Boot Bus Compact Flash support" - depends on CAVIUM_OCTEON_SOC - help - This option enables a polled compact flash driver for use with - compact flash cards attached to the OCTEON boot bus. - - If unsure, say N. - -config SATA_QSTOR - tristate "Pacific Digital SATA QStor support" - depends on PCI - help - This option enables support for Pacific Digital Serial ATA QStor. - - If unsure, say N. - -config SATA_SX4 - tristate "Promise SATA SX4 support (Experimental)" - depends on PCI - help - This option enables support for Promise Serial ATA SX4. - - If unsure, say N. - -config ATA_BMDMA - bool "ATA BMDMA support" - default y - help - This option adds support for SFF ATA controllers with BMDMA - capability. BMDMA stands for bus-master DMA and is the - de facto DMA interface for SFF controllers. - - If unsure, say Y. - -if ATA_BMDMA - -comment "SATA SFF controllers with BMDMA" - -config ATA_PIIX - tristate "Intel ESB, ICH, PIIX3, PIIX4 PATA/SATA support" - depends on PCI - help - This option enables support for ICH5/6/7/8 Serial ATA - and support for PATA on the Intel ESB/ICH/PIIX3/PIIX4 series - host controllers. - - If unsure, say N. - -config SATA_DWC - tristate "DesignWare Cores SATA support" - depends on DMADEVICES - select GENERIC_PHY - help - This option enables support for the on-chip SATA controller of the - AppliedMicro processor 460EX. - - If unsure, say N. - -config SATA_DWC_OLD_DMA - bool "Support old device trees" - depends on SATA_DWC - select DW_DMAC_CORE - default y if 460EX - help - This option enables support for old device trees without the - "dmas" property. - -config SATA_DWC_DEBUG - bool "Debugging driver version" - depends on SATA_DWC - help - This option enables debugging output in the driver. - -config SATA_DWC_VDEBUG - bool "Verbose debug output" - depends on SATA_DWC_DEBUG - help - This option enables the taskfile dumping and NCQ debugging. - -config SATA_HIGHBANK - tristate "Calxeda Highbank SATA support" - depends on ARCH_HIGHBANK || COMPILE_TEST - help - This option enables support for the Calxeda Highbank SoC's - onboard SATA. - - If unsure, say N. - -config SATA_MV - tristate "Marvell SATA support" - depends on PCI || ARCH_DOVE || ARCH_MV78XX0 || \ - ARCH_MVEBU || ARCH_ORION5X || COMPILE_TEST - select GENERIC_PHY - help - This option enables support for the Marvell Serial ATA family. - Currently supports 88SX[56]0[48][01] PCI(-X) chips, - as well as the newer [67]042 PCI-X/PCIe and SOC devices. - - If unsure, say N. - -config SATA_NV - tristate "NVIDIA SATA support" - depends on PCI - help - This option enables support for NVIDIA Serial ATA. - - If unsure, say N. - -config SATA_PROMISE - tristate "Promise SATA TX2/TX4 support" - depends on PCI - help - This option enables support for Promise Serial ATA TX2/TX4. - - If unsure, say N. - -config SATA_RCAR - tristate "Renesas R-Car SATA support" - depends on ARCH_RENESAS || COMPILE_TEST - help - This option enables support for Renesas R-Car Serial ATA. - - If unsure, say N. - -config SATA_SIL - tristate "Silicon Image SATA support" - depends on PCI - help - This option enables support for Silicon Image Serial ATA. - - If unsure, say N. - -config SATA_SIS - tristate "SiS 964/965/966/180 SATA support" - depends on PCI - select PATA_SIS - help - This option enables support for SiS Serial ATA on - SiS 964/965/966/180 and Parallel ATA on SiS 180. - The PATA support for SiS 180 requires additionally to - enable the PATA_SIS driver in the config. - If unsure, say N. - -config SATA_SVW - tristate "ServerWorks Frodo / Apple K2 SATA support" - depends on PCI - help - This option enables support for Broadcom/Serverworks/Apple K2 - SATA support. - - If unsure, say N. - -config SATA_ULI - tristate "ULi Electronics SATA support" - depends on PCI - help - This option enables support for ULi Electronics SATA. - - If unsure, say N. - -config SATA_VIA - tristate "VIA SATA support" - depends on PCI - help - This option enables support for VIA Serial ATA. - - If unsure, say N. - -config SATA_VITESSE - tristate "VITESSE VSC-7174 / INTEL 31244 SATA support" - depends on PCI - help - This option enables support for Vitesse VSC7174 and Intel 31244 Serial ATA. - - If unsure, say N. - -comment "PATA SFF controllers with BMDMA" - -config PATA_ALI - tristate "ALi PATA support" - depends on PCI - help - This option enables support for the ALi ATA interfaces - found on the many ALi chipsets. - - If unsure, say N. - -config PATA_AMD - tristate "AMD/NVidia PATA support" - depends on PCI - help - This option enables support for the AMD and NVidia PATA - interfaces found on the chipsets for Athlon/Athlon64. - - If unsure, say N. - -config PATA_ARASAN_CF - tristate "ARASAN CompactFlash PATA Controller Support" - depends on ARCH_SPEAR13XX || COMPILE_TEST - depends on DMADEVICES - select DMA_ENGINE - help - Say Y here to support the ARASAN CompactFlash PATA controller - -config PATA_ARTOP - tristate "ARTOP 6210/6260 PATA support" - depends on PCI - help - This option enables support for ARTOP PATA controllers. - - If unsure, say N. - -config PATA_ATIIXP - tristate "ATI PATA support" - depends on PCI - help - This option enables support for the ATI ATA interfaces - found on the many ATI chipsets. - - If unsure, say N. - -config PATA_ATP867X - tristate "ARTOP/Acard ATP867X PATA support" - depends on PCI - help - This option enables support for ARTOP/Acard ATP867X PATA - controllers. - - If unsure, say N. - -config PATA_BF54X - tristate "Blackfin 54x ATAPI support" - depends on BF542 || BF548 || BF549 - help - This option enables support for the built-in ATAPI controller on - Blackfin 54x family chips. - - If unsure, say N. - -config PATA_CMD64X - tristate "CMD64x PATA support" - depends on PCI - help - This option enables support for the CMD64x series chips - except for the CMD640. - - If unsure, say N. - -config PATA_CS5520 - tristate "CS5510/5520 PATA support" - depends on PCI && (X86_32 || COMPILE_TEST) - help - This option enables support for the Cyrix 5510/5520 - companion chip used with the MediaGX/Geode processor family. - - If unsure, say N. - -config PATA_CS5530 - tristate "CS5530 PATA support" - depends on PCI && (X86_32 || COMPILE_TEST) - help - This option enables support for the Cyrix/NatSemi/AMD CS5530 - companion chip used with the MediaGX/Geode processor family. - - If unsure, say N. - -config PATA_CS5535 - tristate "CS5535 PATA support (Experimental)" - depends on PCI && X86_32 - help - This option enables support for the NatSemi/AMD CS5535 - companion chip used with the Geode processor family. - - If unsure, say N. - -config PATA_CS5536 - tristate "CS5536 PATA support" - depends on PCI && (X86_32 || MIPS || COMPILE_TEST) - help - This option enables support for the AMD CS5536 - companion chip used with the Geode LX processor family. - - If unsure, say N. - -config PATA_CYPRESS - tristate "Cypress CY82C693 PATA support (Very Experimental)" - depends on PCI - help - This option enables support for the Cypress/Contaq CY82C693 - chipset found in some Alpha systems - - If unsure, say N. - -config PATA_EFAR - tristate "EFAR SLC90E66 support" - depends on PCI - help - This option enables support for the EFAR SLC90E66 - IDE controller found on some older machines. - - If unsure, say N. - -config PATA_EP93XX - tristate "Cirrus Logic EP93xx PATA support" - depends on ARCH_EP93XX - help - This option enables support for the PATA controller in - the Cirrus Logic EP9312 and EP9315 ARM CPU. - - If unsure, say N. - -config PATA_HPT366 - tristate "HPT 366/368 PATA support" - depends on PCI - help - This option enables support for the HPT 366 and 368 - PATA controllers via the new ATA layer. - - If unsure, say N. - -config PATA_HPT37X - tristate "HPT 370/370A/371/372/374/302 PATA support" - depends on PCI - help - This option enables support for the majority of the later HPT - PATA controllers via the new ATA layer. - - If unsure, say N. - -config PATA_HPT3X2N - tristate "HPT 371N/372N/302N PATA support" - depends on PCI - help - This option enables support for the N variant HPT PATA - controllers via the new ATA layer. - - If unsure, say N. - -config PATA_HPT3X3 - tristate "HPT 343/363 PATA support" - depends on PCI - help - This option enables support for the HPT 343/363 - PATA controllers via the new ATA layer - - If unsure, say N. - -config PATA_HPT3X3_DMA - bool "HPT 343/363 DMA support" - depends on PATA_HPT3X3 - help - This option enables DMA support for the HPT343/363 - controllers. Enable with care as there are still some - problems with DMA on this chipset. - -config PATA_ICSIDE - tristate "Acorn ICS PATA support" - depends on ARM && ARCH_ACORN - help - On Acorn systems, say Y here if you wish to use the ICS PATA - interface card. This is not required for ICS partition support. - If you are unsure, say N to this. - -config PATA_IMX - tristate "PATA support for Freescale iMX" - depends on ARCH_MXC - help - This option enables support for the PATA host available on Freescale - iMX SoCs. - - If unsure, say N. - -config PATA_IT8213 - tristate "IT8213 PATA support (Experimental)" - depends on PCI - help - This option enables support for the ITE 821 PATA - controllers via the new ATA layer. - - If unsure, say N. - -config PATA_IT821X - tristate "IT8211/2 PATA support" - depends on PCI - help - This option enables support for the ITE 8211 and 8212 - PATA controllers via the new ATA layer, including RAID - mode. - - If unsure, say N. - -config PATA_JMICRON - tristate "JMicron PATA support" - depends on PCI - help - Enable support for the JMicron IDE controller, via the new - ATA layer. - - If unsure, say N. - -config PATA_MACIO - tristate "Apple PowerMac/PowerBook internal 'MacIO' IDE" - depends on PPC_PMAC - help - Most IDE capable PowerMacs have IDE busses driven by a variant - of this controller which is part of the Apple chipset used on - most PowerMac models. Some models have multiple busses using - different chipsets, though generally, MacIO is one of them. - -config PATA_MARVELL - tristate "Marvell PATA support via legacy mode" - depends on PCI - help - This option enables limited support for the Marvell 88SE61xx ATA - controllers. If you wish to use only the SATA ports then select - the AHCI driver alone. If you wish to the use the PATA port or - both SATA and PATA include this driver. - - If unsure, say N. - -config PATA_MPC52xx - tristate "Freescale MPC52xx SoC internal IDE" - depends on PPC_MPC52xx && PPC_BESTCOMM - select PPC_BESTCOMM_ATA - help - This option enables support for integrated IDE controller - of the Freescale MPC52xx SoC. - - If unsure, say N. - -config PATA_NETCELL - tristate "NETCELL Revolution RAID support" - depends on PCI - help - This option enables support for the Netcell Revolution RAID - PATA controller. - - If unsure, say N. - -config PATA_NINJA32 - tristate "Ninja32/Delkin Cardbus ATA support" - depends on PCI - help - This option enables support for the Ninja32, Delkin and - possibly other brands of Cardbus ATA adapter - - If unsure, say N. - -config PATA_NS87415 - tristate "Nat Semi NS87415 PATA support" - depends on PCI - help - This option enables support for the National Semiconductor - NS87415 PCI-IDE controller. - - If unsure, say N. - -config PATA_OLDPIIX - tristate "Intel PATA old PIIX support" - depends on PCI - help - This option enables support for early PIIX PATA support. - - If unsure, say N. - -config PATA_OPTIDMA - tristate "OPTI FireStar PATA support (Very Experimental)" - depends on PCI - help - This option enables DMA/PIO support for the later OPTi - controllers found on some old motherboards and in some - laptops. - - If unsure, say N. - -config PATA_PDC2027X - tristate "Promise PATA 2027x support" - depends on PCI - help - This option enables support for Promise PATA pdc20268 to pdc20277 host adapters. - - If unsure, say N. - -config PATA_PDC_OLD - tristate "Older Promise PATA controller support" - depends on PCI - help - This option enables support for the Promise 20246, 20262, 20263, - 20265 and 20267 adapters. - - If unsure, say N. - -config PATA_RADISYS - tristate "RADISYS 82600 PATA support (Experimental)" - depends on PCI - help - This option enables support for the RADISYS 82600 - PATA controllers via the new ATA layer - - If unsure, say N. - -config PATA_RDC - tristate "RDC PATA support" - depends on PCI - help - This option enables basic support for the later RDC PATA controllers - controllers via the new ATA layer. For the RDC 1010, you need to - enable the IT821X driver instead. - - If unsure, say N. - -config PATA_SC1200 - tristate "SC1200 PATA support" - depends on PCI && (X86_32 || COMPILE_TEST) - help - This option enables support for the NatSemi/AMD SC1200 SoC - companion chip used with the Geode processor family. - - If unsure, say N. - -config PATA_SCH - tristate "Intel SCH PATA support" - depends on PCI - help - This option enables support for Intel SCH PATA on the Intel - SCH (US15W, US15L, UL11L) series host controllers. - - If unsure, say N. - -config PATA_SERVERWORKS - tristate "SERVERWORKS OSB4/CSB5/CSB6/HT1000 PATA support" - depends on PCI - help - This option enables support for the Serverworks OSB4/CSB5/CSB6 and - HT1000 PATA controllers, via the new ATA layer. - - If unsure, say N. - -config PATA_SIL680 - tristate "CMD / Silicon Image 680 PATA support" - depends on PCI - help - This option enables support for CMD / Silicon Image 680 PATA. - - If unsure, say N. - -config PATA_SIS - tristate "SiS PATA support" - depends on PCI - help - This option enables support for SiS PATA controllers - - If unsure, say N. - -config PATA_TOSHIBA - tristate "Toshiba Piccolo support (Experimental)" - depends on PCI - help - Support for the Toshiba Piccolo controllers. Currently only the - primary channel is supported by this driver. - - If unsure, say N. - -config PATA_TRIFLEX - tristate "Compaq Triflex PATA support" - depends on PCI - help - Enable support for the Compaq 'Triflex' IDE controller as found - on many Compaq Pentium-Pro systems, via the new ATA layer. - - If unsure, say N. - -config PATA_VIA - tristate "VIA PATA support" - depends on PCI - help - This option enables support for the VIA PATA interfaces - found on the many VIA chipsets. - - If unsure, say N. - -config PATA_PXA - tristate "PXA DMA-capable PATA support" - depends on ARCH_PXA - help - This option enables support for harddrive attached to PXA CPU's bus. - - NOTE: This driver utilizes PXA DMA controller, in case your hardware - is not capable of doing MWDMA, use pata_platform instead. - - If unsure, say N. - -config PATA_WINBOND - tristate "Winbond SL82C105 PATA support" - depends on PCI - help - This option enables support for SL82C105 PATA devices found in the - Netwinder and some other systems - - If unsure, say N. - -endif # ATA_BMDMA - -comment "PIO-only SFF controllers" - -config PATA_AT32 - tristate "Atmel AVR32 PATA support (Experimental)" - depends on AVR32 && PLATFORM_AT32AP - help - This option enables support for the IDE devices on the - Atmel AT32AP platform. - - If unsure, say N. - -config PATA_AT91 - tristate "PATA support for AT91SAM9260" - depends on ARM && SOC_AT91SAM9 - help - This option enables support for IDE devices on the Atmel AT91SAM9260 SoC. - - If unsure, say N. - -config PATA_CMD640_PCI - tristate "CMD640 PCI PATA support (Experimental)" - depends on PCI - help - This option enables support for the CMD640 PCI IDE - interface chip. Only the primary channel is currently - supported. - - If unsure, say N. - -config PATA_ISAPNP - tristate "ISA Plug and Play PATA support" - depends on ISAPNP - help - This option enables support for ISA plug & play ATA - controllers such as those found on old soundcards. - - If unsure, say N. - -config PATA_IXP4XX_CF - tristate "IXP4XX Compact Flash support" - depends on ARCH_IXP4XX - help - This option enables support for a Compact Flash connected on - the ixp4xx expansion bus. This driver had been written for - Loft/Avila boards in mind but can work with others. - - If unsure, say N. - -config PATA_MPIIX - tristate "Intel PATA MPIIX support" - depends on PCI - help - This option enables support for MPIIX PATA support. - - If unsure, say N. - -config PATA_NS87410 - tristate "Nat Semi NS87410 PATA support" - depends on PCI - help - This option enables support for the National Semiconductor - NS87410 PCI-IDE controller. - - If unsure, say N. - -config PATA_OPTI - tristate "OPTI621/6215 PATA support (Very Experimental)" - depends on PCI - help - This option enables full PIO support for the early Opti ATA - controllers found on some old motherboards. - - If unsure, say N. - -config PATA_PALMLD - tristate "Palm LifeDrive PATA support" - depends on MACH_PALMLD - help - This option enables support for Palm LifeDrive's internal ATA - port via the new ATA layer. - - If unsure, say N. - -config PATA_PCMCIA - tristate "PCMCIA PATA support" - depends on PCMCIA - help - This option enables support for PCMCIA ATA interfaces, including - compact flash card adapters via the new ATA layer. - - If unsure, say N. - -config PATA_PLATFORM - tristate "Generic platform device PATA support" - depends on EXPERT || PPC || HAVE_PATA_PLATFORM - help - This option enables support for generic directly connected ATA - devices commonly found on embedded systems. - - If unsure, say N. - -config PATA_OF_PLATFORM - tristate "OpenFirmware platform device PATA support" - depends on PATA_PLATFORM && OF - help - This option enables support for generic directly connected ATA - devices commonly found on embedded systems with OpenFirmware - bindings. - - If unsure, say N. - -config PATA_QDI - tristate "QDI VLB PATA support" - depends on ISA - select PATA_LEGACY - help - Support for QDI 6500 and 6580 PATA controllers on VESA local bus. - -config PATA_RB532 - tristate "RouterBoard 532 PATA CompactFlash support" - depends on MIKROTIK_RB532 - help - This option enables support for the RouterBoard 532 - PATA CompactFlash controller. - - If unsure, say N. - -config PATA_RZ1000 - tristate "PC Tech RZ1000 PATA support" - depends on PCI - help - This option enables basic support for the PC Tech RZ1000/1 - PATA controllers via the new ATA layer - - If unsure, say N. - -config PATA_SAMSUNG_CF - tristate "Samsung SoC PATA support" - depends on SAMSUNG_DEV_IDE - help - This option enables basic support for Samsung's S3C/S5P board - PATA controllers via the new ATA layer - - If unsure, say N. - -config PATA_WINBOND_VLB - tristate "Winbond W83759A VLB PATA support (Experimental)" - depends on ISA - select PATA_LEGACY - help - Support for the Winbond W83759A controller on Vesa Local Bus - systems. - -comment "Generic fallback / legacy drivers" - -config PATA_ACPI - tristate "ACPI firmware driver for PATA" - depends on ATA_ACPI && ATA_BMDMA - help - This option enables an ACPI method driver which drives - motherboard PATA controller interfaces through the ACPI - firmware in the BIOS. This driver can sometimes handle - otherwise unsupported hardware. - -config ATA_GENERIC - tristate "Generic ATA support" - depends on PCI && ATA_BMDMA - help - This option enables support for generic BIOS configured - ATA controllers via the new ATA layer - - If unsure, say N. - -config PATA_LEGACY - tristate "Legacy ISA PATA support (Experimental)" - depends on (ISA || PCI) - help - This option enables support for ISA/VLB/PCI bus legacy PATA - ports and allows them to be accessed via the new ATA layer. - - If unsure, say N. - -endif # ATA_SFF -endif # ATA diff --git a/src/linux/drivers/atm/.gitignore b/src/linux/drivers/atm/.gitignore deleted file mode 100644 index fc0ae5e..0000000 --- a/src/linux/drivers/atm/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# Ignore generated files -fore200e_mkfirm -fore200e_pca_fw.c -pca200e.bin -pca200e_ecd.bin2 diff --git a/src/linux/drivers/atm/Kconfig b/src/linux/drivers/atm/Kconfig deleted file mode 100644 index 31c6010..0000000 --- a/src/linux/drivers/atm/Kconfig +++ /dev/null @@ -1,401 +0,0 @@ -# -# ATM device configuration -# - -menuconfig ATM_DRIVERS - bool "ATM drivers" - depends on NETDEVICES && ATM - default y - ---help--- - Say Y here to get to see options for Asynchronous Transfer Mode - device drivers. This option alone does not add any kernel code. - - If you say N, all options in this submenu will be skipped and disabled. - -if ATM_DRIVERS && NETDEVICES && ATM - -config ATM_DUMMY - tristate "Dummy ATM driver" - help - Dummy ATM driver. Useful for proxy signalling, testing, - and development. If unsure, say N. - -config ATM_TCP - tristate "ATM over TCP" - depends on INET - help - ATM over TCP driver. Useful mainly for development and for - experiments. If unsure, say N. - -config ATM_LANAI - tristate "Efficient Networks Speedstream 3010" - depends on PCI && ATM - help - Supports ATM cards based on the Efficient Networks "Lanai" - chipset such as the Speedstream 3010 and the ENI-25p. The - Speedstream 3060 is currently not supported since we don't - have the code to drive the on-board Alcatel DSL chipset (yet). - -config ATM_ENI - tristate "Efficient Networks ENI155P" - depends on PCI - ---help--- - Driver for the Efficient Networks ENI155p series and SMC ATM - Power155 155 Mbps ATM adapters. Both, the versions with 512KB and - 2MB on-board RAM (Efficient calls them "C" and "S", respectively), - and the FPGA and the ASIC Tonga versions of the board are supported. - The driver works with MMF (-MF or ...F) and UTP-5 (-U5 or ...D) - adapters. - - To compile this driver as a module, choose M here: the module will - be called eni. - -config ATM_ENI_DEBUG - bool "Enable extended debugging" - depends on ATM_ENI - help - Extended debugging records various events and displays that list - when an inconsistency is detected. This mechanism is faster than - generally using printks, but still has some impact on performance. - Note that extended debugging may create certain race conditions - itself. Enable this ONLY if you suspect problems with the driver. - -config ATM_ENI_TUNE_BURST - bool "Fine-tune burst settings" - depends on ATM_ENI - ---help--- - In order to obtain good throughput, the ENI NIC can transfer - multiple words of data per PCI bus access cycle. Such a multi-word - transfer is called a burst. - - The default settings for the burst sizes are suitable for most PCI - chipsets. However, in some cases, large bursts may overrun buffers - in the PCI chipset and cause data corruption. In such cases, large - bursts must be disabled and only (slower) small bursts can be used. - The burst sizes can be set independently in the send (TX) and - receive (RX) direction. - - Note that enabling many different burst sizes in the same direction - may increase the cost of setting up a transfer such that the - resulting throughput is lower than when using only the largest - available burst size. - - Also, sometimes larger bursts lead to lower throughput, e.g. on an - Intel 440FX board, a drop from 135 Mbps to 103 Mbps was observed - when going from 8W to 16W bursts. - -config ATM_ENI_BURST_TX_16W - bool "Enable 16W TX bursts (discouraged)" - depends on ATM_ENI_TUNE_BURST - help - Burst sixteen words at once in the send direction. This may work - with recent PCI chipsets, but is known to fail with older chipsets. - -config ATM_ENI_BURST_TX_8W - bool "Enable 8W TX bursts (recommended)" - depends on ATM_ENI_TUNE_BURST - help - Burst eight words at once in the send direction. This is the default - setting. - -config ATM_ENI_BURST_TX_4W - bool "Enable 4W TX bursts (optional)" - depends on ATM_ENI_TUNE_BURST - help - Burst four words at once in the send direction. You may want to try - this if you have disabled 8W bursts. Enabling 4W if 8W is also set - may or may not improve throughput. - -config ATM_ENI_BURST_TX_2W - bool "Enable 2W TX bursts (optional)" - depends on ATM_ENI_TUNE_BURST - help - Burst two words at once in the send direction. You may want to try - this if you have disabled 4W and 8W bursts. Enabling 2W if 4W or 8W - are also set may or may not improve throughput. - -config ATM_ENI_BURST_RX_16W - bool "Enable 16W RX bursts (discouraged)" - depends on ATM_ENI_TUNE_BURST - help - Burst sixteen words at once in the receive direction. This may work - with recent PCI chipsets, but is known to fail with older chipsets. - -config ATM_ENI_BURST_RX_8W - bool "Enable 8W RX bursts (discouraged)" - depends on ATM_ENI_TUNE_BURST - help - Burst eight words at once in the receive direction. This may work - with recent PCI chipsets, but is known to fail with older chipsets, - such as the Intel Neptune series. - -config ATM_ENI_BURST_RX_4W - bool "Enable 4W RX bursts (recommended)" - depends on ATM_ENI_TUNE_BURST - help - Burst four words at once in the receive direction. This is the - default setting. Enabling 4W if 8W is also set may or may not - improve throughput. - -config ATM_ENI_BURST_RX_2W - bool "Enable 2W RX bursts (optional)" - depends on ATM_ENI_TUNE_BURST - help - Burst two words at once in the receive direction. You may want to - try this if you have disabled 4W and 8W bursts. Enabling 2W if 4W or - 8W are also set may or may not improve throughput. - -config ATM_FIRESTREAM - tristate "Fujitsu FireStream (FS50/FS155) " - depends on PCI && VIRT_TO_BUS - help - Driver for the Fujitsu FireStream 155 (MB86697) and - FireStream 50 (MB86695) ATM PCI chips. - - To compile this driver as a module, choose M here: the module will - be called firestream. - -config ATM_ZATM - tristate "ZeitNet ZN1221/ZN1225" - depends on PCI && VIRT_TO_BUS - help - Driver for the ZeitNet ZN1221 (MMF) and ZN1225 (UTP-5) 155 Mbps ATM - adapters. - - To compile this driver as a module, choose M here: the module will - be called zatm. - -config ATM_ZATM_DEBUG - bool "Enable extended debugging" - depends on ATM_ZATM - help - Extended debugging records various events and displays that list - when an inconsistency is detected. This mechanism is faster than - generally using printks, but still has some impact on performance. - Note that extended debugging may create certain race conditions - itself. Enable this ONLY if you suspect problems with the driver. - -config ATM_NICSTAR - tristate "IDT 77201 (NICStAR) (ForeRunnerLE)" - depends on PCI - help - The NICStAR chipset family is used in a large number of ATM NICs for - 25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE - series. Say Y if you have one of those. - - To compile this driver as a module, choose M here: the module will - be called nicstar. - -config ATM_NICSTAR_USE_SUNI - bool "Use suni PHY driver (155Mbps)" - depends on ATM_NICSTAR - help - Support for the S-UNI and compatible PHYsical layer chips. These are - found in most 155Mbps NICStAR based ATM cards, namely in the - ForeRunner LE155 cards. This driver provides detection of cable~ - removal and reinsertion and provides some statistics. This driver - doesn't have removal capability when compiled as a module, so if you - need that capability don't include S-UNI support (it's not needed to - make the card work). - -config ATM_NICSTAR_USE_IDT77105 - bool "Use IDT77015 PHY driver (25Mbps)" - depends on ATM_NICSTAR - help - Support for the PHYsical layer chip in ForeRunner LE25 cards. In - addition to cable removal/reinsertion detection, this driver allows - you to control the loopback mode of the chip via a dedicated IOCTL. - This driver is required for proper handling of temporary carrier - loss, so if you have a 25Mbps NICStAR based ATM card you must say Y. - -config ATM_IDT77252 - tristate "IDT 77252 (NICStAR II)" - depends on PCI - help - Driver for the IDT 77252 ATM PCI chips. - - To compile this driver as a module, choose M here: the module will - be called idt77252. - -config ATM_IDT77252_DEBUG - bool "Enable debugging messages" - depends on ATM_IDT77252 - help - Somewhat useful debugging messages are available. The choice of - messages is controlled by a bitmap. This may be specified as a - module argument. See the file for - the meanings of the bits in the mask. - - When active, these messages can have a significant impact on the - speed of the driver, and the size of your syslog files! When - inactive, they will have only a modest impact on performance. - -config ATM_IDT77252_RCV_ALL - bool "Receive ALL cells in raw queue" - depends on ATM_IDT77252 - help - Enable receiving of all cells on the ATM link, that do not match - an open connection in the raw cell queue of the driver. Useful - for debugging or special applications only, so the safe answer is N. - -config ATM_IDT77252_USE_SUNI - bool - depends on ATM_IDT77252 - default y - -config ATM_AMBASSADOR - tristate "Madge Ambassador (Collage PCI 155 Server)" - depends on PCI && VIRT_TO_BUS - select BITREVERSE - help - This is a driver for ATMizer based ATM card produced by Madge - Networks Ltd. Say Y (or M to compile as a module named ambassador) - here if you have one of these cards. - -config ATM_AMBASSADOR_DEBUG - bool "Enable debugging messages" - depends on ATM_AMBASSADOR - ---help--- - Somewhat useful debugging messages are available. The choice of - messages is controlled by a bitmap. This may be specified as a - module argument (kernel command line argument as well?), changed - dynamically using an ioctl (not yet) or changed by sending the - string "Dxxxx" to VCI 1023 (where x is a hex digit). See the file - for the meanings of the bits in the - mask. - - When active, these messages can have a significant impact on the - speed of the driver, and the size of your syslog files! When - inactive, they will have only a modest impact on performance. - -config ATM_HORIZON - tristate "Madge Horizon [Ultra] (Collage PCI 25 and Collage PCI 155 Client)" - depends on PCI && VIRT_TO_BUS - help - This is a driver for the Horizon chipset ATM adapter cards once - produced by Madge Networks Ltd. Say Y (or M to compile as a module - named horizon) here if you have one of these cards. - -config ATM_HORIZON_DEBUG - bool "Enable debugging messages" - depends on ATM_HORIZON - ---help--- - Somewhat useful debugging messages are available. The choice of - messages is controlled by a bitmap. This may be specified as a - module argument (kernel command line argument as well?), changed - dynamically using an ioctl (not yet) or changed by sending the - string "Dxxxx" to VCI 1023 (where x is a hex digit). See the file - for the meanings of the bits in the - mask. - - When active, these messages can have a significant impact on the - speed of the driver, and the size of your syslog files! When - inactive, they will have only a modest impact on performance. - -config ATM_IA - tristate "Interphase ATM PCI x575/x525/x531" - depends on PCI - ---help--- - This is a driver for the Interphase (i)ChipSAR adapter cards - which include a variety of variants in term of the size of the - control memory (128K-1KVC, 512K-4KVC), the size of the packet - memory (128K, 512K, 1M), and the PHY type (Single/Multi mode OC3, - UTP155, UTP25, DS3 and E3). Go to: - - for more info about the cards. Say Y (or M to compile as a module - named iphase) here if you have one of these cards. - - See the file for further - details. - -config ATM_IA_DEBUG - bool "Enable debugging messages" - depends on ATM_IA - ---help--- - Somewhat useful debugging messages are available. The choice of - messages is controlled by a bitmap. This may be specified as a - module argument (kernel command line argument as well?), changed - dynamically using an ioctl (Get the debug utility, iadbg, from - ). - - See the file for the meanings of the - bits in the mask. - - When active, these messages can have a significant impact on the - speed of the driver, and the size of your syslog files! When - inactive, they will have only a modest impact on performance. - -config ATM_FORE200E - tristate "FORE Systems 200E-series" - depends on (PCI || SBUS) - select FW_LOADER - ---help--- - This is a driver for the FORE Systems 200E-series ATM adapter - cards. It simultaneously supports PCA-200E and SBA-200E models - on PCI and SBUS hosts. Say Y (or M to compile as a module - named fore_200e) here if you have one of these ATM adapters. - - See the file for - further details. - -config ATM_FORE200E_USE_TASKLET - bool "Defer interrupt work to a tasklet" - depends on ATM_FORE200E - default n - help - This defers work to be done by the interrupt handler to a - tasklet instead of handling everything at interrupt time. This - may improve the responsive of the host. - -config ATM_FORE200E_TX_RETRY - int "Maximum number of tx retries" - depends on ATM_FORE200E - default "16" - ---help--- - Specifies the number of times the driver attempts to transmit - a message before giving up, if the transmit queue of the ATM card - is transiently saturated. - - Saturation of the transmit queue may occur only under extreme - conditions, e.g. when a fast host continuously submits very small - frames (<64 bytes) or raw AAL0 cells (48 bytes) to the ATM adapter. - - Note that under common conditions, it is unlikely that you encounter - a saturation of the transmit queue, so the retry mechanism never - comes into play. - -config ATM_FORE200E_DEBUG - int "Debugging level (0-3)" - depends on ATM_FORE200E - default "0" - help - Specifies the level of debugging messages issued by the driver. - The verbosity of the driver increases with the value of this - parameter. - - When active, these messages can have a significant impact on - the performances of the driver, and the size of your syslog files! - Keep the debugging level to 0 during normal operations. - -config ATM_HE - tristate "ForeRunner HE Series" - depends on PCI - help - This is a driver for the Marconi ForeRunner HE-series ATM adapter - cards. It simultaneously supports the 155 and 622 versions. - -config ATM_HE_USE_SUNI - bool "Use S/UNI PHY driver" - depends on ATM_HE - help - Support for the S/UNI-Ultra and S/UNI-622 found in the ForeRunner - HE cards. This driver provides carrier detection some statistics. - -config ATM_SOLOS - tristate "Solos ADSL2+ PCI Multiport card driver" - depends on PCI - select FW_LOADER - help - Support for the Solos multiport ADSL2+ card. - -endif # ATM diff --git a/src/linux/drivers/auxdisplay/Kconfig b/src/linux/drivers/auxdisplay/Kconfig deleted file mode 100644 index 10e1b9e..0000000 --- a/src/linux/drivers/auxdisplay/Kconfig +++ /dev/null @@ -1,131 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see Documentation/kbuild/kconfig-language.txt. -# -# Auxiliary display drivers configuration. -# - -menuconfig AUXDISPLAY - bool "Auxiliary Display support" - ---help--- - Say Y here to get to see options for auxiliary display drivers. - This option alone does not add any kernel code. - - If you say N, all options in this submenu will be skipped and disabled. - -if AUXDISPLAY - -config KS0108 - tristate "KS0108 LCD Controller" - depends on PARPORT_PC - default n - ---help--- - If you have a LCD controlled by one or more KS0108 - controllers, say Y. You will need also another more specific - driver for your LCD. - - Depends on Parallel Port support. If you say Y at - parport, you will be able to compile this as a module (M) - and built-in as well (Y). - - To compile this as a module, choose M here: - the module will be called ks0108. - - If unsure, say N. - -config KS0108_PORT - hex "Parallel port where the LCD is connected" - depends on KS0108 - default 0x378 - ---help--- - The address of the parallel port where the LCD is connected. - - The first standard parallel port address is 0x378. - The second standard parallel port address is 0x278. - The third standard parallel port address is 0x3BC. - - You can specify a different address if you need. - - If you don't know what I'm talking about, load the parport module, - and execute "dmesg" or "cat /proc/ioports". You can see there how - many parallel ports are present and which address each one has. - - Usually you only need to use 0x378. - - If you compile this as a module, you can still override this - using the module parameters. - -config KS0108_DELAY - int "Delay between each control writing (microseconds)" - depends on KS0108 - default "2" - ---help--- - Amount of time the ks0108 should wait between each control write - to the parallel port. - - If your LCD seems to miss random writings, increment this. - - If you don't know what I'm talking about, ignore it. - - If you compile this as a module, you can still override this - value using the module parameters. - -config CFAG12864B - tristate "CFAG12864B LCD" - depends on X86 - depends on FB - depends on KS0108 - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - default n - ---help--- - If you have a Crystalfontz 128x64 2-color LCD, cfag12864b Series, - say Y. You also need the ks0108 LCD Controller driver. - - For help about how to wire your LCD to the parallel port, - check Documentation/auxdisplay/cfag12864b - - Depends on the x86 arch and the framebuffer support. - - The LCD framebuffer driver can be attached to a console. - It will work fine. However, you can't attach it to the fbdev driver - of the xorg server. - - To compile this as a module, choose M here: - the modules will be called cfag12864b and cfag12864bfb. - - If unsure, say N. - -config CFAG12864B_RATE - int "Refresh rate (hertz)" - depends on CFAG12864B - default "20" - ---help--- - Refresh rate of the LCD. - - As the LCD is not memory mapped, the driver has to make the work by - software. This means you should be careful setting this value higher. - If your CPUs are really slow or you feel the system is slowed down, - decrease the value. - - Be careful modifying this value to a very high value: - You can freeze the computer, or the LCD maybe can't draw as fast as you - are requesting. - - If you don't know what I'm talking about, ignore it. - - If you compile this as a module, you can still override this - value using the module parameters. - -config IMG_ASCII_LCD - tristate "Imagination Technologies ASCII LCD Display" - default y if MIPS_MALTA || MIPS_SEAD3 - select SYSCON - help - Enable this to support the simple ASCII LCD displays found on - development boards such as the MIPS Boston, MIPS Malta & MIPS SEAD3 - from Imagination Technologies. - -endif # AUXDISPLAY diff --git a/src/linux/drivers/auxdisplay/Makefile b/src/linux/drivers/auxdisplay/Makefile deleted file mode 100644 index 3127175..0000000 --- a/src/linux/drivers/auxdisplay/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for the kernel auxiliary displays device drivers. -# - -obj-$(CONFIG_KS0108) += ks0108.o -obj-$(CONFIG_CFAG12864B) += cfag12864b.o cfag12864bfb.o -obj-$(CONFIG_IMG_ASCII_LCD) += img-ascii-lcd.o diff --git a/src/linux/drivers/base/Kconfig b/src/linux/drivers/base/Kconfig deleted file mode 100644 index d02e7c0..0000000 --- a/src/linux/drivers/base/Kconfig +++ /dev/null @@ -1,339 +0,0 @@ -menu "Generic Driver Options" - -config UEVENT_HELPER - bool "Support for uevent helper" - default y - help - The uevent helper program is forked by the kernel for - every uevent. - Before the switch to the netlink-based uevent source, this was - used to hook hotplug scripts into kernel device events. It - usually pointed to a shell script at /sbin/hotplug. - This should not be used today, because usual systems create - many events at bootup or device discovery in a very short time - frame. One forked process per event can create so many processes - that it creates a high system load, or on smaller systems - it is known to create out-of-memory situations during bootup. - -config UEVENT_HELPER_PATH - string "path to uevent helper" - depends on UEVENT_HELPER - default "" - help - To disable user space helper program execution at by default - specify an empty string here. This setting can still be altered - via /proc/sys/kernel/hotplug or via /sys/kernel/uevent_helper - later at runtime. - -config DEVTMPFS - bool "Maintain a devtmpfs filesystem to mount at /dev" - help - This creates a tmpfs/ramfs filesystem instance early at bootup. - In this filesystem, the kernel driver core maintains device - nodes with their default names and permissions for all - registered devices with an assigned major/minor number. - Userspace can modify the filesystem content as needed, add - symlinks, and apply needed permissions. - It provides a fully functional /dev directory, where usually - udev runs on top, managing permissions and adding meaningful - symlinks. - In very limited environments, it may provide a sufficient - functional /dev without any further help. It also allows simple - rescue systems, and reliably handles dynamic major/minor numbers. - - Notice: if CONFIG_TMPFS isn't enabled, the simpler ramfs - file system will be used instead. - -config DEVTMPFS_MOUNT - bool "Automount devtmpfs at /dev, after the kernel mounted the rootfs" - depends on DEVTMPFS - help - This will instruct the kernel to automatically mount the - devtmpfs filesystem at /dev, directly after the kernel has - mounted the root filesystem. The behavior can be overridden - with the commandline parameter: devtmpfs.mount=0|1. - This option does not affect initramfs based booting, here - the devtmpfs filesystem always needs to be mounted manually - after the rootfs is mounted. - With this option enabled, it allows to bring up a system in - rescue mode with init=/bin/sh, even when the /dev directory - on the rootfs is completely empty. - -config STANDALONE - bool "Select only drivers that don't need compile-time external firmware" - default y - help - Select this option if you don't have magic firmware for drivers that - need it. - - If unsure, say Y. - -config PREVENT_FIRMWARE_BUILD - bool "Prevent firmware from being built" - default y - help - Say yes to avoid building firmware. Firmware is usually shipped - with the driver and only when updating the firmware should a - rebuild be made. - If unsure, say Y here. - -config FW_LOADER - tristate "Userspace firmware loading support" if EXPERT - default y - ---help--- - This option is provided for the case where none of the in-tree modules - require userspace firmware loading support, but a module built - out-of-tree does. - -config FIRMWARE_IN_KERNEL - bool "Include in-kernel firmware blobs in kernel binary" - depends on FW_LOADER - default y - help - The kernel source tree includes a number of firmware 'blobs' - that are used by various drivers. The recommended way to - use these is to run "make firmware_install", which, after - converting ihex files to binary, copies all of the needed - binary files in firmware/ to /lib/firmware/ on your system so - that they can be loaded by userspace helpers on request. - - Enabling this option will build each required firmware blob - into the kernel directly, where request_firmware() will find - them without having to call out to userspace. This may be - useful if your root file system requires a device that uses - such firmware and do not wish to use an initrd. - - This single option controls the inclusion of firmware for - every driver that uses request_firmware() and ships its - firmware in the kernel source tree, which avoids a - proliferation of 'Include firmware for xxx device' options. - - Say 'N' and let firmware be loaded from userspace. - -config EXTRA_FIRMWARE - string "External firmware blobs to build into the kernel binary" - depends on FW_LOADER - help - This option allows firmware to be built into the kernel for the case - where the user either cannot or doesn't want to provide it from - userspace at runtime (for example, when the firmware in question is - required for accessing the boot device, and the user doesn't want to - use an initrd). - - This option is a string and takes the (space-separated) names of the - firmware files -- the same names that appear in MODULE_FIRMWARE() - and request_firmware() in the source. These files should exist under - the directory specified by the EXTRA_FIRMWARE_DIR option, which is - by default the firmware subdirectory of the kernel source tree. - - For example, you might set CONFIG_EXTRA_FIRMWARE="usb8388.bin", copy - the usb8388.bin file into the firmware directory, and build the kernel. - Then any request_firmware("usb8388.bin") will be satisfied internally - without needing to call out to userspace. - - WARNING: If you include additional firmware files into your binary - kernel image that are not available under the terms of the GPL, - then it may be a violation of the GPL to distribute the resulting - image since it combines both GPL and non-GPL work. You should - consult a lawyer of your own before distributing such an image. - -config EXTRA_FIRMWARE_DIR - string "Firmware blobs root directory" - depends on EXTRA_FIRMWARE != "" - default "firmware" - help - This option controls the directory in which the kernel build system - looks for the firmware files listed in the EXTRA_FIRMWARE option. - The default is firmware/ in the kernel source tree, but by changing - this option you can point it elsewhere, such as /lib/firmware/ or - some other directory containing the firmware files. - -config FW_LOADER_USER_HELPER - bool - -config FW_LOADER_USER_HELPER_FALLBACK - bool "Fallback user-helper invocation for firmware loading" - depends on FW_LOADER - select FW_LOADER_USER_HELPER - help - This option enables / disables the invocation of user-helper - (e.g. udev) for loading firmware files as a fallback after the - direct file loading in kernel fails. The user-mode helper is - no longer required unless you have a special firmware file that - resides in a non-standard path. Moreover, the udev support has - been deprecated upstream. - - If you are unsure about this, say N here. - -config WANT_DEV_COREDUMP - bool - help - Drivers should "select" this option if they desire to use the - device coredump mechanism. - -config ALLOW_DEV_COREDUMP - bool "Allow device coredump" if EXPERT - default y - help - This option controls if the device coredump mechanism is available or - not; if disabled, the mechanism will be omitted even if drivers that - can use it are enabled. - Say 'N' for more sensitive systems or systems that don't want - to ever access the information to not have the code, nor keep any - data. - - If unsure, say Y. - -config DEV_COREDUMP - bool - default y if WANT_DEV_COREDUMP - depends on ALLOW_DEV_COREDUMP - -config DEBUG_DRIVER - bool "Driver Core verbose debug messages" - depends on DEBUG_KERNEL - help - Say Y here if you want the Driver core to produce a bunch of - debug messages to the system log. Select this if you are having a - problem with the driver core and want to see more of what is - going on. - - If you are unsure about this, say N here. - -config DEBUG_DEVRES - bool "Managed device resources verbose debug messages" - depends on DEBUG_KERNEL - help - This option enables kernel parameter devres.log. If set to - non-zero, devres debug messages are printed. Select this if - you are having a problem with devres or want to debug - resource management for a managed device. devres.log can be - switched on and off from sysfs node. - - If you are unsure about this, Say N here. - -config DEBUG_TEST_DRIVER_REMOVE - bool "Test driver remove calls during probe (UNSTABLE)" - depends on DEBUG_KERNEL - help - Say Y here if you want the Driver core to test driver remove functions - by calling probe, remove, probe. This tests the remove path without - having to unbind the driver or unload the driver module. - - This option is expected to find errors and may render your system - unusable. You should say N here unless you are explicitly looking to - test this functionality. - -config SYS_HYPERVISOR - bool - default n - -config GENERIC_CPU_DEVICES - bool - default n - -config GENERIC_CPU_AUTOPROBE - bool - -config SOC_BUS - bool - -source "drivers/base/regmap/Kconfig" - -config DMA_SHARED_BUFFER - bool - default n - select ANON_INODES - help - This option enables the framework for buffer-sharing between - multiple drivers. A buffer is associated with a file using driver - APIs extension; the file's descriptor can then be passed on to other - driver. - -config FENCE_TRACE - bool "Enable verbose FENCE_TRACE messages" - depends on DMA_SHARED_BUFFER - help - Enable the FENCE_TRACE printks. This will add extra - spam to the console log, but will make it easier to diagnose - lockup related problems for dma-buffers shared across multiple - devices. - -config DMA_CMA - bool "DMA Contiguous Memory Allocator" - depends on HAVE_DMA_CONTIGUOUS && CMA - help - This enables the Contiguous Memory Allocator which allows drivers - to allocate big physically-contiguous blocks of memory for use with - hardware components that do not support I/O map nor scatter-gather. - - You can disable CMA by specifying "cma=0" on the kernel's command - line. - - For more information see . - If unsure, say "n". - -if DMA_CMA -comment "Default contiguous memory area size:" - -config CMA_SIZE_MBYTES - int "Size in Mega Bytes" - depends on !CMA_SIZE_SEL_PERCENTAGE - default 0 if X86 - default 16 - help - Defines the size (in MiB) of the default memory area for Contiguous - Memory Allocator. If the size of 0 is selected, CMA is disabled by - default, but it can be enabled by passing cma=size[MG] to the kernel. - - -config CMA_SIZE_PERCENTAGE - int "Percentage of total memory" - depends on !CMA_SIZE_SEL_MBYTES - default 0 if X86 - default 10 - help - Defines the size of the default memory area for Contiguous Memory - Allocator as a percentage of the total memory in the system. - If 0 percent is selected, CMA is disabled by default, but it can be - enabled by passing cma=size[MG] to the kernel. - -choice - prompt "Selected region size" - default CMA_SIZE_SEL_MBYTES - -config CMA_SIZE_SEL_MBYTES - bool "Use mega bytes value only" - -config CMA_SIZE_SEL_PERCENTAGE - bool "Use percentage value only" - -config CMA_SIZE_SEL_MIN - bool "Use lower value (minimum)" - -config CMA_SIZE_SEL_MAX - bool "Use higher value (maximum)" - -endchoice - -config CMA_ALIGNMENT - int "Maximum PAGE_SIZE order of alignment for contiguous buffers" - range 4 12 - default 8 - help - DMA mapping framework by default aligns all buffers to the smallest - PAGE_SIZE order which is greater than or equal to the requested buffer - size. This works well for buffers up to a few hundreds kilobytes, but - for larger buffers it just a memory waste. With this parameter you can - specify the maximum PAGE_SIZE order for contiguous buffers. Larger - buffers will be aligned only to this specified order. The order is - expressed as a power of two multiplied by the PAGE_SIZE. - - For example, if your system defaults to 4KiB pages, the order value - of 8 means that the buffers will be aligned up to 1MiB only. - - If unsure, leave the default value "8". - -endif - -endmenu diff --git a/src/linux/drivers/base/Makefile b/src/linux/drivers/base/Makefile deleted file mode 100644 index 2609ba2..0000000 --- a/src/linux/drivers/base/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -# Makefile for the Linux device tree - -obj-y := component.o core.o bus.o dd.o syscore.o \ - driver.o class.o platform.o \ - cpu.o firmware.o init.o map.o devres.o \ - attribute_container.o transport_class.o \ - topology.o container.o property.o cacheinfo.o -obj-$(CONFIG_DEVTMPFS) += devtmpfs.o -obj-$(CONFIG_DMA_CMA) += dma-contiguous.o -obj-y += power/ -obj-$(CONFIG_HAS_DMA) += dma-mapping.o -obj-$(CONFIG_HAVE_GENERIC_DMA_COHERENT) += dma-coherent.o -obj-$(CONFIG_ISA_BUS_API) += isa.o -obj-$(CONFIG_FW_LOADER) += firmware_class.o -obj-$(CONFIG_NUMA) += node.o -obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o -ifeq ($(CONFIG_SYSFS),y) -obj-$(CONFIG_MODULES) += module.o -endif -obj-$(CONFIG_SYS_HYPERVISOR) += hypervisor.o -obj-$(CONFIG_REGMAP) += regmap/ -obj-$(CONFIG_SOC_BUS) += soc.o -obj-$(CONFIG_PINCTRL) += pinctrl.o -obj-$(CONFIG_DEV_COREDUMP) += devcoredump.o -obj-$(CONFIG_GENERIC_MSI_IRQ_DOMAIN) += platform-msi.o - -ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG - diff --git a/src/linux/drivers/base/attribute_container.c b/src/linux/drivers/base/attribute_container.c deleted file mode 100644 index 95e3ef8..0000000 --- a/src/linux/drivers/base/attribute_container.c +++ /dev/null @@ -1,442 +0,0 @@ -/* - * attribute_container.c - implementation of a simple container for classes - * - * Copyright (c) 2005 - James Bottomley - * - * This file is licensed under GPLv2 - * - * The basic idea here is to enable a device to be attached to an - * aritrary numer of classes without having to allocate storage for them. - * Instead, the contained classes select the devices they need to attach - * to via a matching function. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "base.h" - -/* This is a private structure used to tie the classdev and the - * container .. it should never be visible outside this file */ -struct internal_container { - struct klist_node node; - struct attribute_container *cont; - struct device classdev; -}; - -static void internal_container_klist_get(struct klist_node *n) -{ - struct internal_container *ic = - container_of(n, struct internal_container, node); - get_device(&ic->classdev); -} - -static void internal_container_klist_put(struct klist_node *n) -{ - struct internal_container *ic = - container_of(n, struct internal_container, node); - put_device(&ic->classdev); -} - - -/** - * attribute_container_classdev_to_container - given a classdev, return the container - * - * @classdev: the class device created by attribute_container_add_device. - * - * Returns the container associated with this classdev. - */ -struct attribute_container * -attribute_container_classdev_to_container(struct device *classdev) -{ - struct internal_container *ic = - container_of(classdev, struct internal_container, classdev); - return ic->cont; -} -EXPORT_SYMBOL_GPL(attribute_container_classdev_to_container); - -static LIST_HEAD(attribute_container_list); - -static DEFINE_MUTEX(attribute_container_mutex); - -/** - * attribute_container_register - register an attribute container - * - * @cont: The container to register. This must be allocated by the - * callee and should also be zeroed by it. - */ -int -attribute_container_register(struct attribute_container *cont) -{ - INIT_LIST_HEAD(&cont->node); - klist_init(&cont->containers, internal_container_klist_get, - internal_container_klist_put); - - mutex_lock(&attribute_container_mutex); - list_add_tail(&cont->node, &attribute_container_list); - mutex_unlock(&attribute_container_mutex); - - return 0; -} -EXPORT_SYMBOL_GPL(attribute_container_register); - -/** - * attribute_container_unregister - remove a container registration - * - * @cont: previously registered container to remove - */ -int -attribute_container_unregister(struct attribute_container *cont) -{ - int retval = -EBUSY; - - mutex_lock(&attribute_container_mutex); - spin_lock(&cont->containers.k_lock); - if (!list_empty(&cont->containers.k_list)) - goto out; - retval = 0; - list_del(&cont->node); - out: - spin_unlock(&cont->containers.k_lock); - mutex_unlock(&attribute_container_mutex); - return retval; - -} -EXPORT_SYMBOL_GPL(attribute_container_unregister); - -/* private function used as class release */ -static void attribute_container_release(struct device *classdev) -{ - struct internal_container *ic - = container_of(classdev, struct internal_container, classdev); - struct device *dev = classdev->parent; - - kfree(ic); - put_device(dev); -} - -/** - * attribute_container_add_device - see if any container is interested in dev - * - * @dev: device to add attributes to - * @fn: function to trigger addition of class device. - * - * This function allocates storage for the class device(s) to be - * attached to dev (one for each matching attribute_container). If no - * fn is provided, the code will simply register the class device via - * device_add. If a function is provided, it is expected to add - * the class device at the appropriate time. One of the things that - * might be necessary is to allocate and initialise the classdev and - * then add it a later time. To do this, call this routine for - * allocation and initialisation and then use - * attribute_container_device_trigger() to call device_add() on - * it. Note: after this, the class device contains a reference to dev - * which is not relinquished until the release of the classdev. - */ -void -attribute_container_add_device(struct device *dev, - int (*fn)(struct attribute_container *, - struct device *, - struct device *)) -{ - struct attribute_container *cont; - - mutex_lock(&attribute_container_mutex); - list_for_each_entry(cont, &attribute_container_list, node) { - struct internal_container *ic; - - if (attribute_container_no_classdevs(cont)) - continue; - - if (!cont->match(cont, dev)) - continue; - - ic = kzalloc(sizeof(*ic), GFP_KERNEL); - if (!ic) { - dev_err(dev, "failed to allocate class container\n"); - continue; - } - - ic->cont = cont; - device_initialize(&ic->classdev); - ic->classdev.parent = get_device(dev); - ic->classdev.class = cont->class; - cont->class->dev_release = attribute_container_release; - dev_set_name(&ic->classdev, "%s", dev_name(dev)); - if (fn) - fn(cont, dev, &ic->classdev); - else - attribute_container_add_class_device(&ic->classdev); - klist_add_tail(&ic->node, &cont->containers); - } - mutex_unlock(&attribute_container_mutex); -} - -/* FIXME: can't break out of this unless klist_iter_exit is also - * called before doing the break - */ -#define klist_for_each_entry(pos, head, member, iter) \ - for (klist_iter_init(head, iter); (pos = ({ \ - struct klist_node *n = klist_next(iter); \ - n ? container_of(n, typeof(*pos), member) : \ - ({ klist_iter_exit(iter) ; NULL; }); \ - })) != NULL;) - - -/** - * attribute_container_remove_device - make device eligible for removal. - * - * @dev: The generic device - * @fn: A function to call to remove the device - * - * This routine triggers device removal. If fn is NULL, then it is - * simply done via device_unregister (note that if something - * still has a reference to the classdev, then the memory occupied - * will not be freed until the classdev is released). If you want a - * two phase release: remove from visibility and then delete the - * device, then you should use this routine with a fn that calls - * device_del() and then use attribute_container_device_trigger() - * to do the final put on the classdev. - */ -void -attribute_container_remove_device(struct device *dev, - void (*fn)(struct attribute_container *, - struct device *, - struct device *)) -{ - struct attribute_container *cont; - - mutex_lock(&attribute_container_mutex); - list_for_each_entry(cont, &attribute_container_list, node) { - struct internal_container *ic; - struct klist_iter iter; - - if (attribute_container_no_classdevs(cont)) - continue; - - if (!cont->match(cont, dev)) - continue; - - klist_for_each_entry(ic, &cont->containers, node, &iter) { - if (dev != ic->classdev.parent) - continue; - klist_del(&ic->node); - if (fn) - fn(cont, dev, &ic->classdev); - else { - attribute_container_remove_attrs(&ic->classdev); - device_unregister(&ic->classdev); - } - } - } - mutex_unlock(&attribute_container_mutex); -} - -/** - * attribute_container_device_trigger - execute a trigger for each matching classdev - * - * @dev: The generic device to run the trigger for - * @fn the function to execute for each classdev. - * - * This function is for executing a trigger when you need to know both - * the container and the classdev. If you only care about the - * container, then use attribute_container_trigger() instead. - */ -void -attribute_container_device_trigger(struct device *dev, - int (*fn)(struct attribute_container *, - struct device *, - struct device *)) -{ - struct attribute_container *cont; - - mutex_lock(&attribute_container_mutex); - list_for_each_entry(cont, &attribute_container_list, node) { - struct internal_container *ic; - struct klist_iter iter; - - if (!cont->match(cont, dev)) - continue; - - if (attribute_container_no_classdevs(cont)) { - fn(cont, dev, NULL); - continue; - } - - klist_for_each_entry(ic, &cont->containers, node, &iter) { - if (dev == ic->classdev.parent) - fn(cont, dev, &ic->classdev); - } - } - mutex_unlock(&attribute_container_mutex); -} - -/** - * attribute_container_trigger - trigger a function for each matching container - * - * @dev: The generic device to activate the trigger for - * @fn: the function to trigger - * - * This routine triggers a function that only needs to know the - * matching containers (not the classdev) associated with a device. - * It is more lightweight than attribute_container_device_trigger, so - * should be used in preference unless the triggering function - * actually needs to know the classdev. - */ -void -attribute_container_trigger(struct device *dev, - int (*fn)(struct attribute_container *, - struct device *)) -{ - struct attribute_container *cont; - - mutex_lock(&attribute_container_mutex); - list_for_each_entry(cont, &attribute_container_list, node) { - if (cont->match(cont, dev)) - fn(cont, dev); - } - mutex_unlock(&attribute_container_mutex); -} - -/** - * attribute_container_add_attrs - add attributes - * - * @classdev: The class device - * - * This simply creates all the class device sysfs files from the - * attributes listed in the container - */ -int -attribute_container_add_attrs(struct device *classdev) -{ - struct attribute_container *cont = - attribute_container_classdev_to_container(classdev); - struct device_attribute **attrs = cont->attrs; - int i, error; - - BUG_ON(attrs && cont->grp); - - if (!attrs && !cont->grp) - return 0; - - if (cont->grp) - return sysfs_create_group(&classdev->kobj, cont->grp); - - for (i = 0; attrs[i]; i++) { - sysfs_attr_init(&attrs[i]->attr); - error = device_create_file(classdev, attrs[i]); - if (error) - return error; - } - - return 0; -} - -/** - * attribute_container_add_class_device - same function as device_add - * - * @classdev: the class device to add - * - * This performs essentially the same function as device_add except for - * attribute containers, namely add the classdev to the system and then - * create the attribute files - */ -int -attribute_container_add_class_device(struct device *classdev) -{ - int error = device_add(classdev); - - if (error) - return error; - return attribute_container_add_attrs(classdev); -} - -/** - * attribute_container_add_class_device_adapter - simple adapter for triggers - * - * This function is identical to attribute_container_add_class_device except - * that it is designed to be called from the triggers - */ -int -attribute_container_add_class_device_adapter(struct attribute_container *cont, - struct device *dev, - struct device *classdev) -{ - return attribute_container_add_class_device(classdev); -} - -/** - * attribute_container_remove_attrs - remove any attribute files - * - * @classdev: The class device to remove the files from - * - */ -void -attribute_container_remove_attrs(struct device *classdev) -{ - struct attribute_container *cont = - attribute_container_classdev_to_container(classdev); - struct device_attribute **attrs = cont->attrs; - int i; - - if (!attrs && !cont->grp) - return; - - if (cont->grp) { - sysfs_remove_group(&classdev->kobj, cont->grp); - return ; - } - - for (i = 0; attrs[i]; i++) - device_remove_file(classdev, attrs[i]); -} - -/** - * attribute_container_class_device_del - equivalent of class_device_del - * - * @classdev: the class device - * - * This function simply removes all the attribute files and then calls - * device_del. - */ -void -attribute_container_class_device_del(struct device *classdev) -{ - attribute_container_remove_attrs(classdev); - device_del(classdev); -} - -/** - * attribute_container_find_class_device - find the corresponding class_device - * - * @cont: the container - * @dev: the generic device - * - * Looks up the device in the container's list of class devices and returns - * the corresponding class_device. - */ -struct device * -attribute_container_find_class_device(struct attribute_container *cont, - struct device *dev) -{ - struct device *cdev = NULL; - struct internal_container *ic; - struct klist_iter iter; - - klist_for_each_entry(ic, &cont->containers, node, &iter) { - if (ic->classdev.parent == dev) { - cdev = &ic->classdev; - /* FIXME: must exit iterator then break */ - klist_iter_exit(&iter); - break; - } - } - - return cdev; -} -EXPORT_SYMBOL_GPL(attribute_container_find_class_device); diff --git a/src/linux/drivers/base/base.h b/src/linux/drivers/base/base.h deleted file mode 100644 index e05db38..0000000 --- a/src/linux/drivers/base/base.h +++ /dev/null @@ -1,154 +0,0 @@ -#include - -/** - * struct subsys_private - structure to hold the private to the driver core portions of the bus_type/class structure. - * - * @subsys - the struct kset that defines this subsystem - * @devices_kset - the subsystem's 'devices' directory - * @interfaces - list of subsystem interfaces associated - * @mutex - protect the devices, and interfaces lists. - * - * @drivers_kset - the list of drivers associated - * @klist_devices - the klist to iterate over the @devices_kset - * @klist_drivers - the klist to iterate over the @drivers_kset - * @bus_notifier - the bus notifier list for anything that cares about things - * on this bus. - * @bus - pointer back to the struct bus_type that this structure is associated - * with. - * - * @glue_dirs - "glue" directory to put in-between the parent device to - * avoid namespace conflicts - * @class - pointer back to the struct class that this structure is associated - * with. - * - * This structure is the one that is the actual kobject allowing struct - * bus_type/class to be statically allocated safely. Nothing outside of the - * driver core should ever touch these fields. - */ -struct subsys_private { - struct kset subsys; - struct kset *devices_kset; - struct list_head interfaces; - struct mutex mutex; - - struct kset *drivers_kset; - struct klist klist_devices; - struct klist klist_drivers; - struct blocking_notifier_head bus_notifier; - unsigned int drivers_autoprobe:1; - struct bus_type *bus; - - struct kset glue_dirs; - struct class *class; -}; -#define to_subsys_private(obj) container_of(obj, struct subsys_private, subsys.kobj) - -struct driver_private { - struct kobject kobj; - struct klist klist_devices; - struct klist_node knode_bus; - struct module_kobject *mkobj; - struct device_driver *driver; -}; -#define to_driver(obj) container_of(obj, struct driver_private, kobj) - -/** - * struct device_private - structure to hold the private to the driver core portions of the device structure. - * - * @klist_children - klist containing all children of this device - * @knode_parent - node in sibling list - * @knode_driver - node in driver list - * @knode_bus - node in bus list - * @deferred_probe - entry in deferred_probe_list which is used to retry the - * binding of drivers which were unable to get all the resources needed by - * the device; typically because it depends on another driver getting - * probed first. - * @device - pointer back to the struct device that this structure is - * associated with. - * - * Nothing outside of the driver core should ever touch these fields. - */ -struct device_private { - struct klist klist_children; - struct klist_node knode_parent; - struct klist_node knode_driver; - struct klist_node knode_bus; - struct list_head deferred_probe; - struct device *device; -}; -#define to_device_private_parent(obj) \ - container_of(obj, struct device_private, knode_parent) -#define to_device_private_driver(obj) \ - container_of(obj, struct device_private, knode_driver) -#define to_device_private_bus(obj) \ - container_of(obj, struct device_private, knode_bus) - -extern int device_private_init(struct device *dev); - -/* initialisation functions */ -extern int devices_init(void); -extern int buses_init(void); -extern int classes_init(void); -extern int firmware_init(void); -#ifdef CONFIG_SYS_HYPERVISOR -extern int hypervisor_init(void); -#else -static inline int hypervisor_init(void) { return 0; } -#endif -extern int platform_bus_init(void); -extern void cpu_dev_init(void); -extern void container_dev_init(void); - -struct kobject *virtual_device_parent(struct device *dev); - -extern int bus_add_device(struct device *dev); -extern void bus_probe_device(struct device *dev); -extern void bus_remove_device(struct device *dev); - -extern int bus_add_driver(struct device_driver *drv); -extern void bus_remove_driver(struct device_driver *drv); - -extern void driver_detach(struct device_driver *drv); -extern int driver_probe_device(struct device_driver *drv, struct device *dev); -extern void driver_deferred_probe_del(struct device *dev); -static inline int driver_match_device(struct device_driver *drv, - struct device *dev) -{ - return drv->bus->match ? drv->bus->match(dev, drv) : 1; -} -extern bool driver_allows_async_probing(struct device_driver *drv); - -extern int driver_add_groups(struct device_driver *drv, - const struct attribute_group **groups); -extern void driver_remove_groups(struct device_driver *drv, - const struct attribute_group **groups); - -extern int device_add_groups(struct device *dev, - const struct attribute_group **groups); -extern void device_remove_groups(struct device *dev, - const struct attribute_group **groups); - -extern char *make_class_name(const char *name, struct kobject *kobj); - -extern int devres_release_all(struct device *dev); -extern void device_block_probing(void); -extern void device_unblock_probing(void); - -/* /sys/devices directory */ -extern struct kset *devices_kset; -extern void devices_kset_move_last(struct device *dev); - -#if defined(CONFIG_MODULES) && defined(CONFIG_SYSFS) -extern void module_add_driver(struct module *mod, struct device_driver *drv); -extern void module_remove_driver(struct device_driver *drv); -#else -static inline void module_add_driver(struct module *mod, - struct device_driver *drv) { } -static inline void module_remove_driver(struct device_driver *drv) { } -#endif - -#ifdef CONFIG_DEVTMPFS -extern int devtmpfs_init(void); -#else -static inline int devtmpfs_init(void) { return 0; } -#endif diff --git a/src/linux/drivers/base/bus.c b/src/linux/drivers/base/bus.c deleted file mode 100644 index 6470eb8..0000000 --- a/src/linux/drivers/base/bus.c +++ /dev/null @@ -1,1284 +0,0 @@ -/* - * bus.c - bus driver management - * - * Copyright (c) 2002-3 Patrick Mochel - * Copyright (c) 2002-3 Open Source Development Labs - * Copyright (c) 2007 Greg Kroah-Hartman - * Copyright (c) 2007 Novell Inc. - * - * This file is released under the GPLv2 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "base.h" -#include "power/power.h" - -/* /sys/devices/system */ -static struct kset *system_kset; - -#define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr) - -/* - * sysfs bindings for drivers - */ - -#define to_drv_attr(_attr) container_of(_attr, struct driver_attribute, attr) - - -static int __must_check bus_rescan_devices_helper(struct device *dev, - void *data); - -static struct bus_type *bus_get(struct bus_type *bus) -{ - if (bus) { - kset_get(&bus->p->subsys); - return bus; - } - return NULL; -} - -static void bus_put(struct bus_type *bus) -{ - if (bus) - kset_put(&bus->p->subsys); -} - -static ssize_t drv_attr_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct driver_attribute *drv_attr = to_drv_attr(attr); - struct driver_private *drv_priv = to_driver(kobj); - ssize_t ret = -EIO; - - if (drv_attr->show) - ret = drv_attr->show(drv_priv->driver, buf); - return ret; -} - -static ssize_t drv_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t count) -{ - struct driver_attribute *drv_attr = to_drv_attr(attr); - struct driver_private *drv_priv = to_driver(kobj); - ssize_t ret = -EIO; - - if (drv_attr->store) - ret = drv_attr->store(drv_priv->driver, buf, count); - return ret; -} - -static const struct sysfs_ops driver_sysfs_ops = { - .show = drv_attr_show, - .store = drv_attr_store, -}; - -static void driver_release(struct kobject *kobj) -{ - struct driver_private *drv_priv = to_driver(kobj); - - pr_debug("driver: '%s': %s\n", kobject_name(kobj), __func__); - kfree(drv_priv); -} - -static struct kobj_type driver_ktype = { - .sysfs_ops = &driver_sysfs_ops, - .release = driver_release, -}; - -/* - * sysfs bindings for buses - */ -static ssize_t bus_attr_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct bus_attribute *bus_attr = to_bus_attr(attr); - struct subsys_private *subsys_priv = to_subsys_private(kobj); - ssize_t ret = 0; - - if (bus_attr->show) - ret = bus_attr->show(subsys_priv->bus, buf); - return ret; -} - -static ssize_t bus_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t count) -{ - struct bus_attribute *bus_attr = to_bus_attr(attr); - struct subsys_private *subsys_priv = to_subsys_private(kobj); - ssize_t ret = 0; - - if (bus_attr->store) - ret = bus_attr->store(subsys_priv->bus, buf, count); - return ret; -} - -static const struct sysfs_ops bus_sysfs_ops = { - .show = bus_attr_show, - .store = bus_attr_store, -}; - -int bus_create_file(struct bus_type *bus, struct bus_attribute *attr) -{ - int error; - if (bus_get(bus)) { - error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr); - bus_put(bus); - } else - error = -EINVAL; - return error; -} -EXPORT_SYMBOL_GPL(bus_create_file); - -void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr) -{ - if (bus_get(bus)) { - sysfs_remove_file(&bus->p->subsys.kobj, &attr->attr); - bus_put(bus); - } -} -EXPORT_SYMBOL_GPL(bus_remove_file); - -static void bus_release(struct kobject *kobj) -{ - struct subsys_private *priv = to_subsys_private(kobj); - struct bus_type *bus = priv->bus; - - kfree(priv); - bus->p = NULL; -} - -static struct kobj_type bus_ktype = { - .sysfs_ops = &bus_sysfs_ops, - .release = bus_release, -}; - -static int bus_uevent_filter(struct kset *kset, struct kobject *kobj) -{ - struct kobj_type *ktype = get_ktype(kobj); - - if (ktype == &bus_ktype) - return 1; - return 0; -} - -static const struct kset_uevent_ops bus_uevent_ops = { - .filter = bus_uevent_filter, -}; - -static struct kset *bus_kset; - -/* Manually detach a device from its associated driver. */ -static ssize_t unbind_store(struct device_driver *drv, const char *buf, - size_t count) -{ - struct bus_type *bus = bus_get(drv->bus); - struct device *dev; - int err = -ENODEV; - - dev = bus_find_device_by_name(bus, NULL, buf); - if (dev && dev->driver == drv) { - if (dev->parent) /* Needed for USB */ - device_lock(dev->parent); - device_release_driver(dev); - if (dev->parent) - device_unlock(dev->parent); - err = count; - } - put_device(dev); - bus_put(bus); - return err; -} -static DRIVER_ATTR_WO(unbind); - -/* - * Manually attach a device to a driver. - * Note: the driver must want to bind to the device, - * it is not possible to override the driver's id table. - */ -static ssize_t bind_store(struct device_driver *drv, const char *buf, - size_t count) -{ - struct bus_type *bus = bus_get(drv->bus); - struct device *dev; - int err = -ENODEV; - - dev = bus_find_device_by_name(bus, NULL, buf); - if (dev && dev->driver == NULL && driver_match_device(drv, dev)) { - if (dev->parent) /* Needed for USB */ - device_lock(dev->parent); - device_lock(dev); - err = driver_probe_device(drv, dev); - device_unlock(dev); - if (dev->parent) - device_unlock(dev->parent); - - if (err > 0) { - /* success */ - err = count; - } else if (err == 0) { - /* driver didn't accept device */ - err = -ENODEV; - } - } - put_device(dev); - bus_put(bus); - return err; -} -static DRIVER_ATTR_WO(bind); - -static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf) -{ - return sprintf(buf, "%d\n", bus->p->drivers_autoprobe); -} - -static ssize_t store_drivers_autoprobe(struct bus_type *bus, - const char *buf, size_t count) -{ - if (buf[0] == '0') - bus->p->drivers_autoprobe = 0; - else - bus->p->drivers_autoprobe = 1; - return count; -} - -static ssize_t store_drivers_probe(struct bus_type *bus, - const char *buf, size_t count) -{ - struct device *dev; - int err = -EINVAL; - - dev = bus_find_device_by_name(bus, NULL, buf); - if (!dev) - return -ENODEV; - if (bus_rescan_devices_helper(dev, NULL) == 0) - err = count; - put_device(dev); - return err; -} - -static struct device *next_device(struct klist_iter *i) -{ - struct klist_node *n = klist_next(i); - struct device *dev = NULL; - struct device_private *dev_prv; - - if (n) { - dev_prv = to_device_private_bus(n); - dev = dev_prv->device; - } - return dev; -} - -/** - * bus_for_each_dev - device iterator. - * @bus: bus type. - * @start: device to start iterating from. - * @data: data for the callback. - * @fn: function to be called for each device. - * - * Iterate over @bus's list of devices, and call @fn for each, - * passing it @data. If @start is not NULL, we use that device to - * begin iterating from. - * - * We check the return of @fn each time. If it returns anything - * other than 0, we break out and return that value. - * - * NOTE: The device that returns a non-zero value is not retained - * in any way, nor is its refcount incremented. If the caller needs - * to retain this data, it should do so, and increment the reference - * count in the supplied callback. - */ -int bus_for_each_dev(struct bus_type *bus, struct device *start, - void *data, int (*fn)(struct device *, void *)) -{ - struct klist_iter i; - struct device *dev; - int error = 0; - - if (!bus || !bus->p) - return -EINVAL; - - klist_iter_init_node(&bus->p->klist_devices, &i, - (start ? &start->p->knode_bus : NULL)); - while ((dev = next_device(&i)) && !error) - error = fn(dev, data); - klist_iter_exit(&i); - return error; -} -EXPORT_SYMBOL_GPL(bus_for_each_dev); - -/** - * bus_find_device - device iterator for locating a particular device. - * @bus: bus type - * @start: Device to begin with - * @data: Data to pass to match function - * @match: Callback function to check device - * - * This is similar to the bus_for_each_dev() function above, but it - * returns a reference to a device that is 'found' for later use, as - * determined by the @match callback. - * - * The callback should return 0 if the device doesn't match and non-zero - * if it does. If the callback returns non-zero, this function will - * return to the caller and not iterate over any more devices. - */ -struct device *bus_find_device(struct bus_type *bus, - struct device *start, void *data, - int (*match)(struct device *dev, void *data)) -{ - struct klist_iter i; - struct device *dev; - - if (!bus || !bus->p) - return NULL; - - klist_iter_init_node(&bus->p->klist_devices, &i, - (start ? &start->p->knode_bus : NULL)); - while ((dev = next_device(&i))) - if (match(dev, data) && get_device(dev)) - break; - klist_iter_exit(&i); - return dev; -} -EXPORT_SYMBOL_GPL(bus_find_device); - -static int match_name(struct device *dev, void *data) -{ - const char *name = data; - - return sysfs_streq(name, dev_name(dev)); -} - -/** - * bus_find_device_by_name - device iterator for locating a particular device of a specific name - * @bus: bus type - * @start: Device to begin with - * @name: name of the device to match - * - * This is similar to the bus_find_device() function above, but it handles - * searching by a name automatically, no need to write another strcmp matching - * function. - */ -struct device *bus_find_device_by_name(struct bus_type *bus, - struct device *start, const char *name) -{ - return bus_find_device(bus, start, (void *)name, match_name); -} -EXPORT_SYMBOL_GPL(bus_find_device_by_name); - -/** - * subsys_find_device_by_id - find a device with a specific enumeration number - * @subsys: subsystem - * @id: index 'id' in struct device - * @hint: device to check first - * - * Check the hint's next object and if it is a match return it directly, - * otherwise, fall back to a full list search. Either way a reference for - * the returned object is taken. - */ -struct device *subsys_find_device_by_id(struct bus_type *subsys, unsigned int id, - struct device *hint) -{ - struct klist_iter i; - struct device *dev; - - if (!subsys) - return NULL; - - if (hint) { - klist_iter_init_node(&subsys->p->klist_devices, &i, &hint->p->knode_bus); - dev = next_device(&i); - if (dev && dev->id == id && get_device(dev)) { - klist_iter_exit(&i); - return dev; - } - klist_iter_exit(&i); - } - - klist_iter_init_node(&subsys->p->klist_devices, &i, NULL); - while ((dev = next_device(&i))) { - if (dev->id == id && get_device(dev)) { - klist_iter_exit(&i); - return dev; - } - } - klist_iter_exit(&i); - return NULL; -} -EXPORT_SYMBOL_GPL(subsys_find_device_by_id); - -static struct device_driver *next_driver(struct klist_iter *i) -{ - struct klist_node *n = klist_next(i); - struct driver_private *drv_priv; - - if (n) { - drv_priv = container_of(n, struct driver_private, knode_bus); - return drv_priv->driver; - } - return NULL; -} - -/** - * bus_for_each_drv - driver iterator - * @bus: bus we're dealing with. - * @start: driver to start iterating on. - * @data: data to pass to the callback. - * @fn: function to call for each driver. - * - * This is nearly identical to the device iterator above. - * We iterate over each driver that belongs to @bus, and call - * @fn for each. If @fn returns anything but 0, we break out - * and return it. If @start is not NULL, we use it as the head - * of the list. - * - * NOTE: we don't return the driver that returns a non-zero - * value, nor do we leave the reference count incremented for that - * driver. If the caller needs to know that info, it must set it - * in the callback. It must also be sure to increment the refcount - * so it doesn't disappear before returning to the caller. - */ -int bus_for_each_drv(struct bus_type *bus, struct device_driver *start, - void *data, int (*fn)(struct device_driver *, void *)) -{ - struct klist_iter i; - struct device_driver *drv; - int error = 0; - - if (!bus) - return -EINVAL; - - klist_iter_init_node(&bus->p->klist_drivers, &i, - start ? &start->p->knode_bus : NULL); - while ((drv = next_driver(&i)) && !error) - error = fn(drv, data); - klist_iter_exit(&i); - return error; -} -EXPORT_SYMBOL_GPL(bus_for_each_drv); - -static int device_add_attrs(struct bus_type *bus, struct device *dev) -{ - int error = 0; - int i; - - if (!bus->dev_attrs) - return 0; - - for (i = 0; bus->dev_attrs[i].attr.name; i++) { - error = device_create_file(dev, &bus->dev_attrs[i]); - if (error) { - while (--i >= 0) - device_remove_file(dev, &bus->dev_attrs[i]); - break; - } - } - return error; -} - -static void device_remove_attrs(struct bus_type *bus, struct device *dev) -{ - int i; - - if (bus->dev_attrs) { - for (i = 0; bus->dev_attrs[i].attr.name; i++) - device_remove_file(dev, &bus->dev_attrs[i]); - } -} - -/** - * bus_add_device - add device to bus - * @dev: device being added - * - * - Add device's bus attributes. - * - Create links to device's bus. - * - Add the device to its bus's list of devices. - */ -int bus_add_device(struct device *dev) -{ - struct bus_type *bus = bus_get(dev->bus); - int error = 0; - - if (bus) { - pr_debug("bus: '%s': add device %s\n", bus->name, dev_name(dev)); - error = device_add_attrs(bus, dev); - if (error) - goto out_put; - error = device_add_groups(dev, bus->dev_groups); - if (error) - goto out_id; - error = sysfs_create_link(&bus->p->devices_kset->kobj, - &dev->kobj, dev_name(dev)); - if (error) - goto out_groups; - error = sysfs_create_link(&dev->kobj, - &dev->bus->p->subsys.kobj, "subsystem"); - if (error) - goto out_subsys; - klist_add_tail(&dev->p->knode_bus, &bus->p->klist_devices); - } - return 0; - -out_subsys: - sysfs_remove_link(&bus->p->devices_kset->kobj, dev_name(dev)); -out_groups: - device_remove_groups(dev, bus->dev_groups); -out_id: - device_remove_attrs(bus, dev); -out_put: - bus_put(dev->bus); - return error; -} - -/** - * bus_probe_device - probe drivers for a new device - * @dev: device to probe - * - * - Automatically probe for a driver if the bus allows it. - */ -void bus_probe_device(struct device *dev) -{ - struct bus_type *bus = dev->bus; - struct subsys_interface *sif; - - if (!bus) - return; - - if (bus->p->drivers_autoprobe) - device_initial_probe(dev); - - mutex_lock(&bus->p->mutex); - list_for_each_entry(sif, &bus->p->interfaces, node) - if (sif->add_dev) - sif->add_dev(dev, sif); - mutex_unlock(&bus->p->mutex); -} - -/** - * bus_remove_device - remove device from bus - * @dev: device to be removed - * - * - Remove device from all interfaces. - * - Remove symlink from bus' directory. - * - Delete device from bus's list. - * - Detach from its driver. - * - Drop reference taken in bus_add_device(). - */ -void bus_remove_device(struct device *dev) -{ - struct bus_type *bus = dev->bus; - struct subsys_interface *sif; - - if (!bus) - return; - - mutex_lock(&bus->p->mutex); - list_for_each_entry(sif, &bus->p->interfaces, node) - if (sif->remove_dev) - sif->remove_dev(dev, sif); - mutex_unlock(&bus->p->mutex); - - sysfs_remove_link(&dev->kobj, "subsystem"); - sysfs_remove_link(&dev->bus->p->devices_kset->kobj, - dev_name(dev)); - device_remove_attrs(dev->bus, dev); - device_remove_groups(dev, dev->bus->dev_groups); - if (klist_node_attached(&dev->p->knode_bus)) - klist_del(&dev->p->knode_bus); - - pr_debug("bus: '%s': remove device %s\n", - dev->bus->name, dev_name(dev)); - device_release_driver(dev); - bus_put(dev->bus); -} - -static int __must_check add_bind_files(struct device_driver *drv) -{ - int ret; - - ret = driver_create_file(drv, &driver_attr_unbind); - if (ret == 0) { - ret = driver_create_file(drv, &driver_attr_bind); - if (ret) - driver_remove_file(drv, &driver_attr_unbind); - } - return ret; -} - -static void remove_bind_files(struct device_driver *drv) -{ - driver_remove_file(drv, &driver_attr_bind); - driver_remove_file(drv, &driver_attr_unbind); -} - -static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe); -static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO, - show_drivers_autoprobe, store_drivers_autoprobe); - -static int add_probe_files(struct bus_type *bus) -{ - int retval; - - retval = bus_create_file(bus, &bus_attr_drivers_probe); - if (retval) - goto out; - - retval = bus_create_file(bus, &bus_attr_drivers_autoprobe); - if (retval) - bus_remove_file(bus, &bus_attr_drivers_probe); -out: - return retval; -} - -static void remove_probe_files(struct bus_type *bus) -{ - bus_remove_file(bus, &bus_attr_drivers_autoprobe); - bus_remove_file(bus, &bus_attr_drivers_probe); -} - -static ssize_t uevent_store(struct device_driver *drv, const char *buf, - size_t count) -{ - enum kobject_action action; - - if (kobject_action_type(buf, count, &action) == 0) - kobject_uevent(&drv->p->kobj, action); - return count; -} -static DRIVER_ATTR_WO(uevent); - -static void driver_attach_async(void *_drv, async_cookie_t cookie) -{ - struct device_driver *drv = _drv; - int ret; - - ret = driver_attach(drv); - - pr_debug("bus: '%s': driver %s async attach completed: %d\n", - drv->bus->name, drv->name, ret); -} - -/** - * bus_add_driver - Add a driver to the bus. - * @drv: driver. - */ -int bus_add_driver(struct device_driver *drv) -{ - struct bus_type *bus; - struct driver_private *priv; - int error = 0; - - bus = bus_get(drv->bus); - if (!bus) - return -EINVAL; - - pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name); - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) { - error = -ENOMEM; - goto out_put_bus; - } - klist_init(&priv->klist_devices, NULL, NULL); - priv->driver = drv; - drv->p = priv; - priv->kobj.kset = bus->p->drivers_kset; - error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL, - "%s", drv->name); - if (error) - goto out_unregister; - - klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers); - if (drv->bus->p->drivers_autoprobe) { - if (driver_allows_async_probing(drv)) { - pr_debug("bus: '%s': probing driver %s asynchronously\n", - drv->bus->name, drv->name); - async_schedule(driver_attach_async, drv); - } else { - error = driver_attach(drv); - if (error) - goto out_unregister; - } - } - module_add_driver(drv->owner, drv); - - error = driver_create_file(drv, &driver_attr_uevent); - if (error) { - printk(KERN_ERR "%s: uevent attr (%s) failed\n", - __func__, drv->name); - } - error = driver_add_groups(drv, bus->drv_groups); - if (error) { - /* How the hell do we get out of this pickle? Give up */ - printk(KERN_ERR "%s: driver_create_groups(%s) failed\n", - __func__, drv->name); - } - - if (!drv->suppress_bind_attrs) { - error = add_bind_files(drv); - if (error) { - /* Ditto */ - printk(KERN_ERR "%s: add_bind_files(%s) failed\n", - __func__, drv->name); - } - } - - return 0; - -out_unregister: - kobject_put(&priv->kobj); - kfree(drv->p); - drv->p = NULL; -out_put_bus: - bus_put(bus); - return error; -} - -/** - * bus_remove_driver - delete driver from bus's knowledge. - * @drv: driver. - * - * Detach the driver from the devices it controls, and remove - * it from its bus's list of drivers. Finally, we drop the reference - * to the bus we took in bus_add_driver(). - */ -void bus_remove_driver(struct device_driver *drv) -{ - if (!drv->bus) - return; - - if (!drv->suppress_bind_attrs) - remove_bind_files(drv); - driver_remove_groups(drv, drv->bus->drv_groups); - driver_remove_file(drv, &driver_attr_uevent); - klist_remove(&drv->p->knode_bus); - pr_debug("bus: '%s': remove driver %s\n", drv->bus->name, drv->name); - driver_detach(drv); - module_remove_driver(drv); - kobject_put(&drv->p->kobj); - bus_put(drv->bus); -} - -/* Helper for bus_rescan_devices's iter */ -static int __must_check bus_rescan_devices_helper(struct device *dev, - void *data) -{ - int ret = 0; - - if (!dev->driver) { - if (dev->parent) /* Needed for USB */ - device_lock(dev->parent); - ret = device_attach(dev); - if (dev->parent) - device_unlock(dev->parent); - } - return ret < 0 ? ret : 0; -} - -/** - * bus_rescan_devices - rescan devices on the bus for possible drivers - * @bus: the bus to scan. - * - * This function will look for devices on the bus with no driver - * attached and rescan it against existing drivers to see if it matches - * any by calling device_attach() for the unbound devices. - */ -int bus_rescan_devices(struct bus_type *bus) -{ - return bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper); -} -EXPORT_SYMBOL_GPL(bus_rescan_devices); - -/** - * device_reprobe - remove driver for a device and probe for a new driver - * @dev: the device to reprobe - * - * This function detaches the attached driver (if any) for the given - * device and restarts the driver probing process. It is intended - * to use if probing criteria changed during a devices lifetime and - * driver attachment should change accordingly. - */ -int device_reprobe(struct device *dev) -{ - if (dev->driver) { - if (dev->parent) /* Needed for USB */ - device_lock(dev->parent); - device_release_driver(dev); - if (dev->parent) - device_unlock(dev->parent); - } - return bus_rescan_devices_helper(dev, NULL); -} -EXPORT_SYMBOL_GPL(device_reprobe); - -/** - * find_bus - locate bus by name. - * @name: name of bus. - * - * Call kset_find_obj() to iterate over list of buses to - * find a bus by name. Return bus if found. - * - * Note that kset_find_obj increments bus' reference count. - */ -#if 0 -struct bus_type *find_bus(char *name) -{ - struct kobject *k = kset_find_obj(bus_kset, name); - return k ? to_bus(k) : NULL; -} -#endif /* 0 */ - -static int bus_add_groups(struct bus_type *bus, - const struct attribute_group **groups) -{ - return sysfs_create_groups(&bus->p->subsys.kobj, groups); -} - -static void bus_remove_groups(struct bus_type *bus, - const struct attribute_group **groups) -{ - sysfs_remove_groups(&bus->p->subsys.kobj, groups); -} - -static void klist_devices_get(struct klist_node *n) -{ - struct device_private *dev_prv = to_device_private_bus(n); - struct device *dev = dev_prv->device; - - get_device(dev); -} - -static void klist_devices_put(struct klist_node *n) -{ - struct device_private *dev_prv = to_device_private_bus(n); - struct device *dev = dev_prv->device; - - put_device(dev); -} - -static ssize_t bus_uevent_store(struct bus_type *bus, - const char *buf, size_t count) -{ - enum kobject_action action; - - if (kobject_action_type(buf, count, &action) == 0) - kobject_uevent(&bus->p->subsys.kobj, action); - return count; -} -static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store); - -/** - * bus_register - register a driver-core subsystem - * @bus: bus to register - * - * Once we have that, we register the bus with the kobject - * infrastructure, then register the children subsystems it has: - * the devices and drivers that belong to the subsystem. - */ -int bus_register(struct bus_type *bus) -{ - int retval; - struct subsys_private *priv; - struct lock_class_key *key = &bus->lock_key; - - priv = kzalloc(sizeof(struct subsys_private), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->bus = bus; - bus->p = priv; - - BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier); - - retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name); - if (retval) - goto out; - - priv->subsys.kobj.kset = bus_kset; - priv->subsys.kobj.ktype = &bus_ktype; - priv->drivers_autoprobe = 1; - - retval = kset_register(&priv->subsys); - if (retval) - goto out; - - retval = bus_create_file(bus, &bus_attr_uevent); - if (retval) - goto bus_uevent_fail; - - priv->devices_kset = kset_create_and_add("devices", NULL, - &priv->subsys.kobj); - if (!priv->devices_kset) { - retval = -ENOMEM; - goto bus_devices_fail; - } - - priv->drivers_kset = kset_create_and_add("drivers", NULL, - &priv->subsys.kobj); - if (!priv->drivers_kset) { - retval = -ENOMEM; - goto bus_drivers_fail; - } - - INIT_LIST_HEAD(&priv->interfaces); - __mutex_init(&priv->mutex, "subsys mutex", key); - klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put); - klist_init(&priv->klist_drivers, NULL, NULL); - - retval = add_probe_files(bus); - if (retval) - goto bus_probe_files_fail; - - retval = bus_add_groups(bus, bus->bus_groups); - if (retval) - goto bus_groups_fail; - - pr_debug("bus: '%s': registered\n", bus->name); - return 0; - -bus_groups_fail: - remove_probe_files(bus); -bus_probe_files_fail: - kset_unregister(bus->p->drivers_kset); -bus_drivers_fail: - kset_unregister(bus->p->devices_kset); -bus_devices_fail: - bus_remove_file(bus, &bus_attr_uevent); -bus_uevent_fail: - kset_unregister(&bus->p->subsys); -out: - kfree(bus->p); - bus->p = NULL; - return retval; -} -EXPORT_SYMBOL_GPL(bus_register); - -/** - * bus_unregister - remove a bus from the system - * @bus: bus. - * - * Unregister the child subsystems and the bus itself. - * Finally, we call bus_put() to release the refcount - */ -void bus_unregister(struct bus_type *bus) -{ - pr_debug("bus: '%s': unregistering\n", bus->name); - if (bus->dev_root) - device_unregister(bus->dev_root); - bus_remove_groups(bus, bus->bus_groups); - remove_probe_files(bus); - kset_unregister(bus->p->drivers_kset); - kset_unregister(bus->p->devices_kset); - bus_remove_file(bus, &bus_attr_uevent); - kset_unregister(&bus->p->subsys); -} -EXPORT_SYMBOL_GPL(bus_unregister); - -int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb) -{ - return blocking_notifier_chain_register(&bus->p->bus_notifier, nb); -} -EXPORT_SYMBOL_GPL(bus_register_notifier); - -int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb) -{ - return blocking_notifier_chain_unregister(&bus->p->bus_notifier, nb); -} -EXPORT_SYMBOL_GPL(bus_unregister_notifier); - -struct kset *bus_get_kset(struct bus_type *bus) -{ - return &bus->p->subsys; -} -EXPORT_SYMBOL_GPL(bus_get_kset); - -struct klist *bus_get_device_klist(struct bus_type *bus) -{ - return &bus->p->klist_devices; -} -EXPORT_SYMBOL_GPL(bus_get_device_klist); - -/* - * Yes, this forcibly breaks the klist abstraction temporarily. It - * just wants to sort the klist, not change reference counts and - * take/drop locks rapidly in the process. It does all this while - * holding the lock for the list, so objects can't otherwise be - * added/removed while we're swizzling. - */ -static void device_insertion_sort_klist(struct device *a, struct list_head *list, - int (*compare)(const struct device *a, - const struct device *b)) -{ - struct klist_node *n; - struct device_private *dev_prv; - struct device *b; - - list_for_each_entry(n, list, n_node) { - dev_prv = to_device_private_bus(n); - b = dev_prv->device; - if (compare(a, b) <= 0) { - list_move_tail(&a->p->knode_bus.n_node, - &b->p->knode_bus.n_node); - return; - } - } - list_move_tail(&a->p->knode_bus.n_node, list); -} - -void bus_sort_breadthfirst(struct bus_type *bus, - int (*compare)(const struct device *a, - const struct device *b)) -{ - LIST_HEAD(sorted_devices); - struct klist_node *n, *tmp; - struct device_private *dev_prv; - struct device *dev; - struct klist *device_klist; - - device_klist = bus_get_device_klist(bus); - - spin_lock(&device_klist->k_lock); - list_for_each_entry_safe(n, tmp, &device_klist->k_list, n_node) { - dev_prv = to_device_private_bus(n); - dev = dev_prv->device; - device_insertion_sort_klist(dev, &sorted_devices, compare); - } - list_splice(&sorted_devices, &device_klist->k_list); - spin_unlock(&device_klist->k_lock); -} -EXPORT_SYMBOL_GPL(bus_sort_breadthfirst); - -/** - * subsys_dev_iter_init - initialize subsys device iterator - * @iter: subsys iterator to initialize - * @subsys: the subsys we wanna iterate over - * @start: the device to start iterating from, if any - * @type: device_type of the devices to iterate over, NULL for all - * - * Initialize subsys iterator @iter such that it iterates over devices - * of @subsys. If @start is set, the list iteration will start there, - * otherwise if it is NULL, the iteration starts at the beginning of - * the list. - */ -void subsys_dev_iter_init(struct subsys_dev_iter *iter, struct bus_type *subsys, - struct device *start, const struct device_type *type) -{ - struct klist_node *start_knode = NULL; - - if (start) - start_knode = &start->p->knode_bus; - klist_iter_init_node(&subsys->p->klist_devices, &iter->ki, start_knode); - iter->type = type; -} -EXPORT_SYMBOL_GPL(subsys_dev_iter_init); - -/** - * subsys_dev_iter_next - iterate to the next device - * @iter: subsys iterator to proceed - * - * Proceed @iter to the next device and return it. Returns NULL if - * iteration is complete. - * - * The returned device is referenced and won't be released till - * iterator is proceed to the next device or exited. The caller is - * free to do whatever it wants to do with the device including - * calling back into subsys code. - */ -struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter) -{ - struct klist_node *knode; - struct device *dev; - - for (;;) { - knode = klist_next(&iter->ki); - if (!knode) - return NULL; - dev = to_device_private_bus(knode)->device; - if (!iter->type || iter->type == dev->type) - return dev; - } -} -EXPORT_SYMBOL_GPL(subsys_dev_iter_next); - -/** - * subsys_dev_iter_exit - finish iteration - * @iter: subsys iterator to finish - * - * Finish an iteration. Always call this function after iteration is - * complete whether the iteration ran till the end or not. - */ -void subsys_dev_iter_exit(struct subsys_dev_iter *iter) -{ - klist_iter_exit(&iter->ki); -} -EXPORT_SYMBOL_GPL(subsys_dev_iter_exit); - -int subsys_interface_register(struct subsys_interface *sif) -{ - struct bus_type *subsys; - struct subsys_dev_iter iter; - struct device *dev; - - if (!sif || !sif->subsys) - return -ENODEV; - - subsys = bus_get(sif->subsys); - if (!subsys) - return -EINVAL; - - mutex_lock(&subsys->p->mutex); - list_add_tail(&sif->node, &subsys->p->interfaces); - if (sif->add_dev) { - subsys_dev_iter_init(&iter, subsys, NULL, NULL); - while ((dev = subsys_dev_iter_next(&iter))) - sif->add_dev(dev, sif); - subsys_dev_iter_exit(&iter); - } - mutex_unlock(&subsys->p->mutex); - - return 0; -} -EXPORT_SYMBOL_GPL(subsys_interface_register); - -void subsys_interface_unregister(struct subsys_interface *sif) -{ - struct bus_type *subsys; - struct subsys_dev_iter iter; - struct device *dev; - - if (!sif || !sif->subsys) - return; - - subsys = sif->subsys; - - mutex_lock(&subsys->p->mutex); - list_del_init(&sif->node); - if (sif->remove_dev) { - subsys_dev_iter_init(&iter, subsys, NULL, NULL); - while ((dev = subsys_dev_iter_next(&iter))) - sif->remove_dev(dev, sif); - subsys_dev_iter_exit(&iter); - } - mutex_unlock(&subsys->p->mutex); - - bus_put(subsys); -} -EXPORT_SYMBOL_GPL(subsys_interface_unregister); - -static void system_root_device_release(struct device *dev) -{ - kfree(dev); -} - -static int subsys_register(struct bus_type *subsys, - const struct attribute_group **groups, - struct kobject *parent_of_root) -{ - struct device *dev; - int err; - - err = bus_register(subsys); - if (err < 0) - return err; - - dev = kzalloc(sizeof(struct device), GFP_KERNEL); - if (!dev) { - err = -ENOMEM; - goto err_dev; - } - - err = dev_set_name(dev, "%s", subsys->name); - if (err < 0) - goto err_name; - - dev->kobj.parent = parent_of_root; - dev->groups = groups; - dev->release = system_root_device_release; - - err = device_register(dev); - if (err < 0) - goto err_dev_reg; - - subsys->dev_root = dev; - return 0; - -err_dev_reg: - put_device(dev); - dev = NULL; -err_name: - kfree(dev); -err_dev: - bus_unregister(subsys); - return err; -} - -/** - * subsys_system_register - register a subsystem at /sys/devices/system/ - * @subsys: system subsystem - * @groups: default attributes for the root device - * - * All 'system' subsystems have a /sys/devices/system/ root device - * with the name of the subsystem. The root device can carry subsystem- - * wide attributes. All registered devices are below this single root - * device and are named after the subsystem with a simple enumeration - * number appended. The registered devices are not explicitly named; - * only 'id' in the device needs to be set. - * - * Do not use this interface for anything new, it exists for compatibility - * with bad ideas only. New subsystems should use plain subsystems; and - * add the subsystem-wide attributes should be added to the subsystem - * directory itself and not some create fake root-device placed in - * /sys/devices/system/. - */ -int subsys_system_register(struct bus_type *subsys, - const struct attribute_group **groups) -{ - return subsys_register(subsys, groups, &system_kset->kobj); -} -EXPORT_SYMBOL_GPL(subsys_system_register); - -/** - * subsys_virtual_register - register a subsystem at /sys/devices/virtual/ - * @subsys: virtual subsystem - * @groups: default attributes for the root device - * - * All 'virtual' subsystems have a /sys/devices/system/ root device - * with the name of the subystem. The root device can carry subsystem-wide - * attributes. All registered devices are below this single root device. - * There's no restriction on device naming. This is for kernel software - * constructs which need sysfs interface. - */ -int subsys_virtual_register(struct bus_type *subsys, - const struct attribute_group **groups) -{ - struct kobject *virtual_dir; - - virtual_dir = virtual_device_parent(NULL); - if (!virtual_dir) - return -ENOMEM; - - return subsys_register(subsys, groups, virtual_dir); -} -EXPORT_SYMBOL_GPL(subsys_virtual_register); - -int __init buses_init(void) -{ - bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL); - if (!bus_kset) - return -ENOMEM; - - system_kset = kset_create_and_add("system", NULL, &devices_kset->kobj); - if (!system_kset) - return -ENOMEM; - - return 0; -} diff --git a/src/linux/drivers/base/cacheinfo.c b/src/linux/drivers/base/cacheinfo.c deleted file mode 100644 index e9fd32e..0000000 --- a/src/linux/drivers/base/cacheinfo.c +++ /dev/null @@ -1,554 +0,0 @@ -/* - * cacheinfo support - processor cache information via sysfs - * - * Based on arch/x86/kernel/cpu/intel_cacheinfo.c - * Author: Sudeep Holla - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* pointer to per cpu cacheinfo */ -static DEFINE_PER_CPU(struct cpu_cacheinfo, ci_cpu_cacheinfo); -#define ci_cacheinfo(cpu) (&per_cpu(ci_cpu_cacheinfo, cpu)) -#define cache_leaves(cpu) (ci_cacheinfo(cpu)->num_leaves) -#define per_cpu_cacheinfo(cpu) (ci_cacheinfo(cpu)->info_list) - -struct cpu_cacheinfo *get_cpu_cacheinfo(unsigned int cpu) -{ - return ci_cacheinfo(cpu); -} - -#ifdef CONFIG_OF -static int cache_setup_of_node(unsigned int cpu) -{ - struct device_node *np; - struct cacheinfo *this_leaf; - struct device *cpu_dev = get_cpu_device(cpu); - struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); - unsigned int index = 0; - - /* skip if of_node is already populated */ - if (this_cpu_ci->info_list->of_node) - return 0; - - if (!cpu_dev) { - pr_err("No cpu device for CPU %d\n", cpu); - return -ENODEV; - } - np = cpu_dev->of_node; - if (!np) { - pr_err("Failed to find cpu%d device node\n", cpu); - return -ENOENT; - } - - while (index < cache_leaves(cpu)) { - this_leaf = this_cpu_ci->info_list + index; - if (this_leaf->level != 1) - np = of_find_next_cache_node(np); - else - np = of_node_get(np);/* cpu node itself */ - if (!np) - break; - this_leaf->of_node = np; - index++; - } - - if (index != cache_leaves(cpu)) /* not all OF nodes populated */ - return -ENOENT; - - return 0; -} - -static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf, - struct cacheinfo *sib_leaf) -{ - return sib_leaf->of_node == this_leaf->of_node; -} -#else -static inline int cache_setup_of_node(unsigned int cpu) { return 0; } -static inline bool cache_leaves_are_shared(struct cacheinfo *this_leaf, - struct cacheinfo *sib_leaf) -{ - /* - * For non-DT systems, assume unique level 1 cache, system-wide - * shared caches for all other levels. This will be used only if - * arch specific code has not populated shared_cpu_map - */ - return !(this_leaf->level == 1); -} -#endif - -static int cache_shared_cpu_map_setup(unsigned int cpu) -{ - struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); - struct cacheinfo *this_leaf, *sib_leaf; - unsigned int index; - int ret; - - ret = cache_setup_of_node(cpu); - if (ret) - return ret; - - for (index = 0; index < cache_leaves(cpu); index++) { - unsigned int i; - - this_leaf = this_cpu_ci->info_list + index; - /* skip if shared_cpu_map is already populated */ - if (!cpumask_empty(&this_leaf->shared_cpu_map)) - continue; - - cpumask_set_cpu(cpu, &this_leaf->shared_cpu_map); - for_each_online_cpu(i) { - struct cpu_cacheinfo *sib_cpu_ci = get_cpu_cacheinfo(i); - - if (i == cpu || !sib_cpu_ci->info_list) - continue;/* skip if itself or no cacheinfo */ - sib_leaf = sib_cpu_ci->info_list + index; - if (cache_leaves_are_shared(this_leaf, sib_leaf)) { - cpumask_set_cpu(cpu, &sib_leaf->shared_cpu_map); - cpumask_set_cpu(i, &this_leaf->shared_cpu_map); - } - } - } - - return 0; -} - -static void cache_shared_cpu_map_remove(unsigned int cpu) -{ - struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); - struct cacheinfo *this_leaf, *sib_leaf; - unsigned int sibling, index; - - for (index = 0; index < cache_leaves(cpu); index++) { - this_leaf = this_cpu_ci->info_list + index; - for_each_cpu(sibling, &this_leaf->shared_cpu_map) { - struct cpu_cacheinfo *sib_cpu_ci; - - if (sibling == cpu) /* skip itself */ - continue; - - sib_cpu_ci = get_cpu_cacheinfo(sibling); - if (!sib_cpu_ci->info_list) - continue; - - sib_leaf = sib_cpu_ci->info_list + index; - cpumask_clear_cpu(cpu, &sib_leaf->shared_cpu_map); - cpumask_clear_cpu(sibling, &this_leaf->shared_cpu_map); - } - of_node_put(this_leaf->of_node); - } -} - -static void free_cache_attributes(unsigned int cpu) -{ - if (!per_cpu_cacheinfo(cpu)) - return; - - cache_shared_cpu_map_remove(cpu); - - kfree(per_cpu_cacheinfo(cpu)); - per_cpu_cacheinfo(cpu) = NULL; -} - -int __weak init_cache_level(unsigned int cpu) -{ - return -ENOENT; -} - -int __weak populate_cache_leaves(unsigned int cpu) -{ - return -ENOENT; -} - -static int detect_cache_attributes(unsigned int cpu) -{ - int ret; - - if (init_cache_level(cpu) || !cache_leaves(cpu)) - return -ENOENT; - - per_cpu_cacheinfo(cpu) = kcalloc(cache_leaves(cpu), - sizeof(struct cacheinfo), GFP_KERNEL); - if (per_cpu_cacheinfo(cpu) == NULL) - return -ENOMEM; - - ret = populate_cache_leaves(cpu); - if (ret) - goto free_ci; - /* - * For systems using DT for cache hierarchy, of_node and shared_cpu_map - * will be set up here only if they are not populated already - */ - ret = cache_shared_cpu_map_setup(cpu); - if (ret) { - pr_warn("Unable to detect cache hierarchy from DT for CPU %d\n", - cpu); - goto free_ci; - } - return 0; - -free_ci: - free_cache_attributes(cpu); - return ret; -} - -/* pointer to cpuX/cache device */ -static DEFINE_PER_CPU(struct device *, ci_cache_dev); -#define per_cpu_cache_dev(cpu) (per_cpu(ci_cache_dev, cpu)) - -static cpumask_t cache_dev_map; - -/* pointer to array of devices for cpuX/cache/indexY */ -static DEFINE_PER_CPU(struct device **, ci_index_dev); -#define per_cpu_index_dev(cpu) (per_cpu(ci_index_dev, cpu)) -#define per_cache_index_dev(cpu, idx) ((per_cpu_index_dev(cpu))[idx]) - -#define show_one(file_name, object) \ -static ssize_t file_name##_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - struct cacheinfo *this_leaf = dev_get_drvdata(dev); \ - return sprintf(buf, "%u\n", this_leaf->object); \ -} - -show_one(level, level); -show_one(coherency_line_size, coherency_line_size); -show_one(number_of_sets, number_of_sets); -show_one(physical_line_partition, physical_line_partition); -show_one(ways_of_associativity, ways_of_associativity); - -static ssize_t size_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct cacheinfo *this_leaf = dev_get_drvdata(dev); - - return sprintf(buf, "%uK\n", this_leaf->size >> 10); -} - -static ssize_t shared_cpumap_show_func(struct device *dev, bool list, char *buf) -{ - struct cacheinfo *this_leaf = dev_get_drvdata(dev); - const struct cpumask *mask = &this_leaf->shared_cpu_map; - - return cpumap_print_to_pagebuf(list, buf, mask); -} - -static ssize_t shared_cpu_map_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return shared_cpumap_show_func(dev, false, buf); -} - -static ssize_t shared_cpu_list_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return shared_cpumap_show_func(dev, true, buf); -} - -static ssize_t type_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct cacheinfo *this_leaf = dev_get_drvdata(dev); - - switch (this_leaf->type) { - case CACHE_TYPE_DATA: - return sprintf(buf, "Data\n"); - case CACHE_TYPE_INST: - return sprintf(buf, "Instruction\n"); - case CACHE_TYPE_UNIFIED: - return sprintf(buf, "Unified\n"); - default: - return -EINVAL; - } -} - -static ssize_t allocation_policy_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct cacheinfo *this_leaf = dev_get_drvdata(dev); - unsigned int ci_attr = this_leaf->attributes; - int n = 0; - - if ((ci_attr & CACHE_READ_ALLOCATE) && (ci_attr & CACHE_WRITE_ALLOCATE)) - n = sprintf(buf, "ReadWriteAllocate\n"); - else if (ci_attr & CACHE_READ_ALLOCATE) - n = sprintf(buf, "ReadAllocate\n"); - else if (ci_attr & CACHE_WRITE_ALLOCATE) - n = sprintf(buf, "WriteAllocate\n"); - return n; -} - -static ssize_t write_policy_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct cacheinfo *this_leaf = dev_get_drvdata(dev); - unsigned int ci_attr = this_leaf->attributes; - int n = 0; - - if (ci_attr & CACHE_WRITE_THROUGH) - n = sprintf(buf, "WriteThrough\n"); - else if (ci_attr & CACHE_WRITE_BACK) - n = sprintf(buf, "WriteBack\n"); - return n; -} - -static DEVICE_ATTR_RO(level); -static DEVICE_ATTR_RO(type); -static DEVICE_ATTR_RO(coherency_line_size); -static DEVICE_ATTR_RO(ways_of_associativity); -static DEVICE_ATTR_RO(number_of_sets); -static DEVICE_ATTR_RO(size); -static DEVICE_ATTR_RO(allocation_policy); -static DEVICE_ATTR_RO(write_policy); -static DEVICE_ATTR_RO(shared_cpu_map); -static DEVICE_ATTR_RO(shared_cpu_list); -static DEVICE_ATTR_RO(physical_line_partition); - -static struct attribute *cache_default_attrs[] = { - &dev_attr_type.attr, - &dev_attr_level.attr, - &dev_attr_shared_cpu_map.attr, - &dev_attr_shared_cpu_list.attr, - &dev_attr_coherency_line_size.attr, - &dev_attr_ways_of_associativity.attr, - &dev_attr_number_of_sets.attr, - &dev_attr_size.attr, - &dev_attr_allocation_policy.attr, - &dev_attr_write_policy.attr, - &dev_attr_physical_line_partition.attr, - NULL -}; - -static umode_t -cache_default_attrs_is_visible(struct kobject *kobj, - struct attribute *attr, int unused) -{ - struct device *dev = kobj_to_dev(kobj); - struct cacheinfo *this_leaf = dev_get_drvdata(dev); - const struct cpumask *mask = &this_leaf->shared_cpu_map; - umode_t mode = attr->mode; - - if ((attr == &dev_attr_type.attr) && this_leaf->type) - return mode; - if ((attr == &dev_attr_level.attr) && this_leaf->level) - return mode; - if ((attr == &dev_attr_shared_cpu_map.attr) && !cpumask_empty(mask)) - return mode; - if ((attr == &dev_attr_shared_cpu_list.attr) && !cpumask_empty(mask)) - return mode; - if ((attr == &dev_attr_coherency_line_size.attr) && - this_leaf->coherency_line_size) - return mode; - if ((attr == &dev_attr_ways_of_associativity.attr) && - this_leaf->size) /* allow 0 = full associativity */ - return mode; - if ((attr == &dev_attr_number_of_sets.attr) && - this_leaf->number_of_sets) - return mode; - if ((attr == &dev_attr_size.attr) && this_leaf->size) - return mode; - if ((attr == &dev_attr_write_policy.attr) && - (this_leaf->attributes & CACHE_WRITE_POLICY_MASK)) - return mode; - if ((attr == &dev_attr_allocation_policy.attr) && - (this_leaf->attributes & CACHE_ALLOCATE_POLICY_MASK)) - return mode; - if ((attr == &dev_attr_physical_line_partition.attr) && - this_leaf->physical_line_partition) - return mode; - - return 0; -} - -static const struct attribute_group cache_default_group = { - .attrs = cache_default_attrs, - .is_visible = cache_default_attrs_is_visible, -}; - -static const struct attribute_group *cache_default_groups[] = { - &cache_default_group, - NULL, -}; - -static const struct attribute_group *cache_private_groups[] = { - &cache_default_group, - NULL, /* Place holder for private group */ - NULL, -}; - -const struct attribute_group * -__weak cache_get_priv_group(struct cacheinfo *this_leaf) -{ - return NULL; -} - -static const struct attribute_group ** -cache_get_attribute_groups(struct cacheinfo *this_leaf) -{ - const struct attribute_group *priv_group = - cache_get_priv_group(this_leaf); - - if (!priv_group) - return cache_default_groups; - - if (!cache_private_groups[1]) - cache_private_groups[1] = priv_group; - - return cache_private_groups; -} - -/* Add/Remove cache interface for CPU device */ -static void cpu_cache_sysfs_exit(unsigned int cpu) -{ - int i; - struct device *ci_dev; - - if (per_cpu_index_dev(cpu)) { - for (i = 0; i < cache_leaves(cpu); i++) { - ci_dev = per_cache_index_dev(cpu, i); - if (!ci_dev) - continue; - device_unregister(ci_dev); - } - kfree(per_cpu_index_dev(cpu)); - per_cpu_index_dev(cpu) = NULL; - } - device_unregister(per_cpu_cache_dev(cpu)); - per_cpu_cache_dev(cpu) = NULL; -} - -static int cpu_cache_sysfs_init(unsigned int cpu) -{ - struct device *dev = get_cpu_device(cpu); - - if (per_cpu_cacheinfo(cpu) == NULL) - return -ENOENT; - - per_cpu_cache_dev(cpu) = cpu_device_create(dev, NULL, NULL, "cache"); - if (IS_ERR(per_cpu_cache_dev(cpu))) - return PTR_ERR(per_cpu_cache_dev(cpu)); - - /* Allocate all required memory */ - per_cpu_index_dev(cpu) = kcalloc(cache_leaves(cpu), - sizeof(struct device *), GFP_KERNEL); - if (unlikely(per_cpu_index_dev(cpu) == NULL)) - goto err_out; - - return 0; - -err_out: - cpu_cache_sysfs_exit(cpu); - return -ENOMEM; -} - -static int cache_add_dev(unsigned int cpu) -{ - unsigned int i; - int rc; - struct device *ci_dev, *parent; - struct cacheinfo *this_leaf; - struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu); - const struct attribute_group **cache_groups; - - rc = cpu_cache_sysfs_init(cpu); - if (unlikely(rc < 0)) - return rc; - - parent = per_cpu_cache_dev(cpu); - for (i = 0; i < cache_leaves(cpu); i++) { - this_leaf = this_cpu_ci->info_list + i; - if (this_leaf->disable_sysfs) - continue; - cache_groups = cache_get_attribute_groups(this_leaf); - ci_dev = cpu_device_create(parent, this_leaf, cache_groups, - "index%1u", i); - if (IS_ERR(ci_dev)) { - rc = PTR_ERR(ci_dev); - goto err; - } - per_cache_index_dev(cpu, i) = ci_dev; - } - cpumask_set_cpu(cpu, &cache_dev_map); - - return 0; -err: - cpu_cache_sysfs_exit(cpu); - return rc; -} - -static void cache_remove_dev(unsigned int cpu) -{ - if (!cpumask_test_cpu(cpu, &cache_dev_map)) - return; - cpumask_clear_cpu(cpu, &cache_dev_map); - - cpu_cache_sysfs_exit(cpu); -} - -static int cacheinfo_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) -{ - unsigned int cpu = (unsigned long)hcpu; - int rc = 0; - - switch (action & ~CPU_TASKS_FROZEN) { - case CPU_ONLINE: - rc = detect_cache_attributes(cpu); - if (!rc) - rc = cache_add_dev(cpu); - break; - case CPU_DEAD: - cache_remove_dev(cpu); - free_cache_attributes(cpu); - break; - } - return notifier_from_errno(rc); -} - -static int __init cacheinfo_sysfs_init(void) -{ - int cpu, rc = 0; - - cpu_notifier_register_begin(); - - for_each_online_cpu(cpu) { - rc = detect_cache_attributes(cpu); - if (rc) - goto out; - rc = cache_add_dev(cpu); - if (rc) { - free_cache_attributes(cpu); - pr_err("error populating cacheinfo..cpu%d\n", cpu); - goto out; - } - } - __hotcpu_notifier(cacheinfo_cpu_callback, 0); - -out: - cpu_notifier_register_done(); - return rc; -} - -device_initcall(cacheinfo_sysfs_init); diff --git a/src/linux/drivers/base/class.c b/src/linux/drivers/base/class.c deleted file mode 100644 index 71059e3..0000000 --- a/src/linux/drivers/base/class.c +++ /dev/null @@ -1,600 +0,0 @@ -/* - * class.c - basic device class management - * - * Copyright (c) 2002-3 Patrick Mochel - * Copyright (c) 2002-3 Open Source Development Labs - * Copyright (c) 2003-2004 Greg Kroah-Hartman - * Copyright (c) 2003-2004 IBM Corp. - * - * This file is released under the GPLv2 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "base.h" - -#define to_class_attr(_attr) container_of(_attr, struct class_attribute, attr) - -static ssize_t class_attr_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct class_attribute *class_attr = to_class_attr(attr); - struct subsys_private *cp = to_subsys_private(kobj); - ssize_t ret = -EIO; - - if (class_attr->show) - ret = class_attr->show(cp->class, class_attr, buf); - return ret; -} - -static ssize_t class_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t count) -{ - struct class_attribute *class_attr = to_class_attr(attr); - struct subsys_private *cp = to_subsys_private(kobj); - ssize_t ret = -EIO; - - if (class_attr->store) - ret = class_attr->store(cp->class, class_attr, buf, count); - return ret; -} - -static void class_release(struct kobject *kobj) -{ - struct subsys_private *cp = to_subsys_private(kobj); - struct class *class = cp->class; - - pr_debug("class '%s': release.\n", class->name); - - if (class->class_release) - class->class_release(class); - else - pr_debug("class '%s' does not have a release() function, " - "be careful\n", class->name); - - kfree(cp); -} - -static const struct kobj_ns_type_operations *class_child_ns_type(struct kobject *kobj) -{ - struct subsys_private *cp = to_subsys_private(kobj); - struct class *class = cp->class; - - return class->ns_type; -} - -static const struct sysfs_ops class_sysfs_ops = { - .show = class_attr_show, - .store = class_attr_store, -}; - -static struct kobj_type class_ktype = { - .sysfs_ops = &class_sysfs_ops, - .release = class_release, - .child_ns_type = class_child_ns_type, -}; - -/* Hotplug events for classes go to the class subsys */ -static struct kset *class_kset; - - -int class_create_file_ns(struct class *cls, const struct class_attribute *attr, - const void *ns) -{ - int error; - - if (cls) - error = sysfs_create_file_ns(&cls->p->subsys.kobj, - &attr->attr, ns); - else - error = -EINVAL; - return error; -} - -void class_remove_file_ns(struct class *cls, const struct class_attribute *attr, - const void *ns) -{ - if (cls) - sysfs_remove_file_ns(&cls->p->subsys.kobj, &attr->attr, ns); -} - -static struct class *class_get(struct class *cls) -{ - if (cls) - kset_get(&cls->p->subsys); - return cls; -} - -static void class_put(struct class *cls) -{ - if (cls) - kset_put(&cls->p->subsys); -} - -static int add_class_attrs(struct class *cls) -{ - int i; - int error = 0; - - if (cls->class_attrs) { - for (i = 0; cls->class_attrs[i].attr.name; i++) { - error = class_create_file(cls, &cls->class_attrs[i]); - if (error) - goto error; - } - } -done: - return error; -error: - while (--i >= 0) - class_remove_file(cls, &cls->class_attrs[i]); - goto done; -} - -static void remove_class_attrs(struct class *cls) -{ - int i; - - if (cls->class_attrs) { - for (i = 0; cls->class_attrs[i].attr.name; i++) - class_remove_file(cls, &cls->class_attrs[i]); - } -} - -static void klist_class_dev_get(struct klist_node *n) -{ - struct device *dev = container_of(n, struct device, knode_class); - - get_device(dev); -} - -static void klist_class_dev_put(struct klist_node *n) -{ - struct device *dev = container_of(n, struct device, knode_class); - - put_device(dev); -} - -int __class_register(struct class *cls, struct lock_class_key *key) -{ - struct subsys_private *cp; - int error; - - pr_debug("device class '%s': registering\n", cls->name); - - cp = kzalloc(sizeof(*cp), GFP_KERNEL); - if (!cp) - return -ENOMEM; - klist_init(&cp->klist_devices, klist_class_dev_get, klist_class_dev_put); - INIT_LIST_HEAD(&cp->interfaces); - kset_init(&cp->glue_dirs); - __mutex_init(&cp->mutex, "subsys mutex", key); - error = kobject_set_name(&cp->subsys.kobj, "%s", cls->name); - if (error) { - kfree(cp); - return error; - } - - /* set the default /sys/dev directory for devices of this class */ - if (!cls->dev_kobj) - cls->dev_kobj = sysfs_dev_char_kobj; - -#if defined(CONFIG_BLOCK) - /* let the block class directory show up in the root of sysfs */ - if (!sysfs_deprecated || cls != &block_class) - cp->subsys.kobj.kset = class_kset; -#else - cp->subsys.kobj.kset = class_kset; -#endif - cp->subsys.kobj.ktype = &class_ktype; - cp->class = cls; - cls->p = cp; - - error = kset_register(&cp->subsys); - if (error) { - kfree(cp); - return error; - } - error = add_class_attrs(class_get(cls)); - class_put(cls); - return error; -} -EXPORT_SYMBOL_GPL(__class_register); - -void class_unregister(struct class *cls) -{ - pr_debug("device class '%s': unregistering\n", cls->name); - remove_class_attrs(cls); - kset_unregister(&cls->p->subsys); -} - -static void class_create_release(struct class *cls) -{ - pr_debug("%s called for %s\n", __func__, cls->name); - kfree(cls); -} - -/** - * class_create - create a struct class structure - * @owner: pointer to the module that is to "own" this struct class - * @name: pointer to a string for the name of this class. - * @key: the lock_class_key for this class; used by mutex lock debugging - * - * This is used to create a struct class pointer that can then be used - * in calls to device_create(). - * - * Returns &struct class pointer on success, or ERR_PTR() on error. - * - * Note, the pointer created here is to be destroyed when finished by - * making a call to class_destroy(). - */ -struct class *__class_create(struct module *owner, const char *name, - struct lock_class_key *key) -{ - struct class *cls; - int retval; - - cls = kzalloc(sizeof(*cls), GFP_KERNEL); - if (!cls) { - retval = -ENOMEM; - goto error; - } - - cls->name = name; - cls->owner = owner; - cls->class_release = class_create_release; - - retval = __class_register(cls, key); - if (retval) - goto error; - - return cls; - -error: - kfree(cls); - return ERR_PTR(retval); -} -EXPORT_SYMBOL_GPL(__class_create); - -/** - * class_destroy - destroys a struct class structure - * @cls: pointer to the struct class that is to be destroyed - * - * Note, the pointer to be destroyed must have been created with a call - * to class_create(). - */ -void class_destroy(struct class *cls) -{ - if ((cls == NULL) || (IS_ERR(cls))) - return; - - class_unregister(cls); -} - -/** - * class_dev_iter_init - initialize class device iterator - * @iter: class iterator to initialize - * @class: the class we wanna iterate over - * @start: the device to start iterating from, if any - * @type: device_type of the devices to iterate over, NULL for all - * - * Initialize class iterator @iter such that it iterates over devices - * of @class. If @start is set, the list iteration will start there, - * otherwise if it is NULL, the iteration starts at the beginning of - * the list. - */ -void class_dev_iter_init(struct class_dev_iter *iter, struct class *class, - struct device *start, const struct device_type *type) -{ - struct klist_node *start_knode = NULL; - - if (start) - start_knode = &start->knode_class; - klist_iter_init_node(&class->p->klist_devices, &iter->ki, start_knode); - iter->type = type; -} -EXPORT_SYMBOL_GPL(class_dev_iter_init); - -/** - * class_dev_iter_next - iterate to the next device - * @iter: class iterator to proceed - * - * Proceed @iter to the next device and return it. Returns NULL if - * iteration is complete. - * - * The returned device is referenced and won't be released till - * iterator is proceed to the next device or exited. The caller is - * free to do whatever it wants to do with the device including - * calling back into class code. - */ -struct device *class_dev_iter_next(struct class_dev_iter *iter) -{ - struct klist_node *knode; - struct device *dev; - - while (1) { - knode = klist_next(&iter->ki); - if (!knode) - return NULL; - dev = container_of(knode, struct device, knode_class); - if (!iter->type || iter->type == dev->type) - return dev; - } -} -EXPORT_SYMBOL_GPL(class_dev_iter_next); - -/** - * class_dev_iter_exit - finish iteration - * @iter: class iterator to finish - * - * Finish an iteration. Always call this function after iteration is - * complete whether the iteration ran till the end or not. - */ -void class_dev_iter_exit(struct class_dev_iter *iter) -{ - klist_iter_exit(&iter->ki); -} -EXPORT_SYMBOL_GPL(class_dev_iter_exit); - -/** - * class_for_each_device - device iterator - * @class: the class we're iterating - * @start: the device to start with in the list, if any. - * @data: data for the callback - * @fn: function to be called for each device - * - * Iterate over @class's list of devices, and call @fn for each, - * passing it @data. If @start is set, the list iteration will start - * there, otherwise if it is NULL, the iteration starts at the - * beginning of the list. - * - * We check the return of @fn each time. If it returns anything - * other than 0, we break out and return that value. - * - * @fn is allowed to do anything including calling back into class - * code. There's no locking restriction. - */ -int class_for_each_device(struct class *class, struct device *start, - void *data, int (*fn)(struct device *, void *)) -{ - struct class_dev_iter iter; - struct device *dev; - int error = 0; - - if (!class) - return -EINVAL; - if (!class->p) { - WARN(1, "%s called for class '%s' before it was initialized", - __func__, class->name); - return -EINVAL; - } - - class_dev_iter_init(&iter, class, start, NULL); - while ((dev = class_dev_iter_next(&iter))) { - error = fn(dev, data); - if (error) - break; - } - class_dev_iter_exit(&iter); - - return error; -} -EXPORT_SYMBOL_GPL(class_for_each_device); - -/** - * class_find_device - device iterator for locating a particular device - * @class: the class we're iterating - * @start: Device to begin with - * @data: data for the match function - * @match: function to check device - * - * This is similar to the class_for_each_dev() function above, but it - * returns a reference to a device that is 'found' for later use, as - * determined by the @match callback. - * - * The callback should return 0 if the device doesn't match and non-zero - * if it does. If the callback returns non-zero, this function will - * return to the caller and not iterate over any more devices. - * - * Note, you will need to drop the reference with put_device() after use. - * - * @match is allowed to do anything including calling back into class - * code. There's no locking restriction. - */ -struct device *class_find_device(struct class *class, struct device *start, - const void *data, - int (*match)(struct device *, const void *)) -{ - struct class_dev_iter iter; - struct device *dev; - - if (!class) - return NULL; - if (!class->p) { - WARN(1, "%s called for class '%s' before it was initialized", - __func__, class->name); - return NULL; - } - - class_dev_iter_init(&iter, class, start, NULL); - while ((dev = class_dev_iter_next(&iter))) { - if (match(dev, data)) { - get_device(dev); - break; - } - } - class_dev_iter_exit(&iter); - - return dev; -} -EXPORT_SYMBOL_GPL(class_find_device); - -int class_interface_register(struct class_interface *class_intf) -{ - struct class *parent; - struct class_dev_iter iter; - struct device *dev; - - if (!class_intf || !class_intf->class) - return -ENODEV; - - parent = class_get(class_intf->class); - if (!parent) - return -EINVAL; - - mutex_lock(&parent->p->mutex); - list_add_tail(&class_intf->node, &parent->p->interfaces); - if (class_intf->add_dev) { - class_dev_iter_init(&iter, parent, NULL, NULL); - while ((dev = class_dev_iter_next(&iter))) - class_intf->add_dev(dev, class_intf); - class_dev_iter_exit(&iter); - } - mutex_unlock(&parent->p->mutex); - - return 0; -} - -void class_interface_unregister(struct class_interface *class_intf) -{ - struct class *parent = class_intf->class; - struct class_dev_iter iter; - struct device *dev; - - if (!parent) - return; - - mutex_lock(&parent->p->mutex); - list_del_init(&class_intf->node); - if (class_intf->remove_dev) { - class_dev_iter_init(&iter, parent, NULL, NULL); - while ((dev = class_dev_iter_next(&iter))) - class_intf->remove_dev(dev, class_intf); - class_dev_iter_exit(&iter); - } - mutex_unlock(&parent->p->mutex); - - class_put(parent); -} - -ssize_t show_class_attr_string(struct class *class, - struct class_attribute *attr, char *buf) -{ - struct class_attribute_string *cs; - - cs = container_of(attr, struct class_attribute_string, attr); - return snprintf(buf, PAGE_SIZE, "%s\n", cs->str); -} - -EXPORT_SYMBOL_GPL(show_class_attr_string); - -struct class_compat { - struct kobject *kobj; -}; - -/** - * class_compat_register - register a compatibility class - * @name: the name of the class - * - * Compatibility class are meant as a temporary user-space compatibility - * workaround when converting a family of class devices to a bus devices. - */ -struct class_compat *class_compat_register(const char *name) -{ - struct class_compat *cls; - - cls = kmalloc(sizeof(struct class_compat), GFP_KERNEL); - if (!cls) - return NULL; - cls->kobj = kobject_create_and_add(name, &class_kset->kobj); - if (!cls->kobj) { - kfree(cls); - return NULL; - } - return cls; -} -EXPORT_SYMBOL_GPL(class_compat_register); - -/** - * class_compat_unregister - unregister a compatibility class - * @cls: the class to unregister - */ -void class_compat_unregister(struct class_compat *cls) -{ - kobject_put(cls->kobj); - kfree(cls); -} -EXPORT_SYMBOL_GPL(class_compat_unregister); - -/** - * class_compat_create_link - create a compatibility class device link to - * a bus device - * @cls: the compatibility class - * @dev: the target bus device - * @device_link: an optional device to which a "device" link should be created - */ -int class_compat_create_link(struct class_compat *cls, struct device *dev, - struct device *device_link) -{ - int error; - - error = sysfs_create_link(cls->kobj, &dev->kobj, dev_name(dev)); - if (error) - return error; - - /* - * Optionally add a "device" link (typically to the parent), as a - * class device would have one and we want to provide as much - * backwards compatibility as possible. - */ - if (device_link) { - error = sysfs_create_link(&dev->kobj, &device_link->kobj, - "device"); - if (error) - sysfs_remove_link(cls->kobj, dev_name(dev)); - } - - return error; -} -EXPORT_SYMBOL_GPL(class_compat_create_link); - -/** - * class_compat_remove_link - remove a compatibility class device link to - * a bus device - * @cls: the compatibility class - * @dev: the target bus device - * @device_link: an optional device to which a "device" link was previously - * created - */ -void class_compat_remove_link(struct class_compat *cls, struct device *dev, - struct device *device_link) -{ - if (device_link) - sysfs_remove_link(&dev->kobj, "device"); - sysfs_remove_link(cls->kobj, dev_name(dev)); -} -EXPORT_SYMBOL_GPL(class_compat_remove_link); - -int __init classes_init(void) -{ - class_kset = kset_create_and_add("class", NULL, NULL); - if (!class_kset) - return -ENOMEM; - return 0; -} - -EXPORT_SYMBOL_GPL(class_create_file_ns); -EXPORT_SYMBOL_GPL(class_remove_file_ns); -EXPORT_SYMBOL_GPL(class_unregister); -EXPORT_SYMBOL_GPL(class_destroy); - -EXPORT_SYMBOL_GPL(class_interface_register); -EXPORT_SYMBOL_GPL(class_interface_unregister); diff --git a/src/linux/drivers/base/component.c b/src/linux/drivers/base/component.c deleted file mode 100644 index 89b032f..0000000 --- a/src/linux/drivers/base/component.c +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Componentized device handling. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This is work in progress. We gather up the component devices into a list, - * and bind them when instructed. At the moment, we're specific to the DRM - * subsystem, and only handles one master device, but this doesn't have to be - * the case. - */ -#include -#include -#include -#include -#include -#include -#include - -struct component; - -struct component_match_array { - void *data; - int (*compare)(struct device *, void *); - void (*release)(struct device *, void *); - struct component *component; - bool duplicate; -}; - -struct component_match { - size_t alloc; - size_t num; - struct component_match_array *compare; -}; - -struct master { - struct list_head node; - bool bound; - - const struct component_master_ops *ops; - struct device *dev; - struct component_match *match; -}; - -struct component { - struct list_head node; - struct master *master; - bool bound; - - const struct component_ops *ops; - struct device *dev; -}; - -static DEFINE_MUTEX(component_mutex); -static LIST_HEAD(component_list); -static LIST_HEAD(masters); - -static struct master *__master_find(struct device *dev, - const struct component_master_ops *ops) -{ - struct master *m; - - list_for_each_entry(m, &masters, node) - if (m->dev == dev && (!ops || m->ops == ops)) - return m; - - return NULL; -} - -static struct component *find_component(struct master *master, - int (*compare)(struct device *, void *), void *compare_data) -{ - struct component *c; - - list_for_each_entry(c, &component_list, node) { - if (c->master && c->master != master) - continue; - - if (compare(c->dev, compare_data)) - return c; - } - - return NULL; -} - -static int find_components(struct master *master) -{ - struct component_match *match = master->match; - size_t i; - int ret = 0; - - /* - * Scan the array of match functions and attach - * any components which are found to this master. - */ - for (i = 0; i < match->num; i++) { - struct component_match_array *mc = &match->compare[i]; - struct component *c; - - dev_dbg(master->dev, "Looking for component %zu\n", i); - - if (match->compare[i].component) - continue; - - c = find_component(master, mc->compare, mc->data); - if (!c) { - ret = -ENXIO; - break; - } - - dev_dbg(master->dev, "found component %s, duplicate %u\n", dev_name(c->dev), !!c->master); - - /* Attach this component to the master */ - match->compare[i].duplicate = !!c->master; - match->compare[i].component = c; - c->master = master; - } - return ret; -} - -/* Detach component from associated master */ -static void remove_component(struct master *master, struct component *c) -{ - size_t i; - - /* Detach the component from this master. */ - for (i = 0; i < master->match->num; i++) - if (master->match->compare[i].component == c) - master->match->compare[i].component = NULL; -} - -/* - * Try to bring up a master. If component is NULL, we're interested in - * this master, otherwise it's a component which must be present to try - * and bring up the master. - * - * Returns 1 for successful bringup, 0 if not ready, or -ve errno. - */ -static int try_to_bring_up_master(struct master *master, - struct component *component) -{ - int ret; - - dev_dbg(master->dev, "trying to bring up master\n"); - - if (find_components(master)) { - dev_dbg(master->dev, "master has incomplete components\n"); - return 0; - } - - if (component && component->master != master) { - dev_dbg(master->dev, "master is not for this component (%s)\n", - dev_name(component->dev)); - return 0; - } - - if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) - return -ENOMEM; - - /* Found all components */ - ret = master->ops->bind(master->dev); - if (ret < 0) { - devres_release_group(master->dev, NULL); - dev_info(master->dev, "master bind failed: %d\n", ret); - return ret; - } - - master->bound = true; - return 1; -} - -static int try_to_bring_up_masters(struct component *component) -{ - struct master *m; - int ret = 0; - - list_for_each_entry(m, &masters, node) { - if (!m->bound) { - ret = try_to_bring_up_master(m, component); - if (ret != 0) - break; - } - } - - return ret; -} - -static void take_down_master(struct master *master) -{ - if (master->bound) { - master->ops->unbind(master->dev); - devres_release_group(master->dev, NULL); - master->bound = false; - } -} - -static void component_match_release(struct device *master, - struct component_match *match) -{ - unsigned int i; - - for (i = 0; i < match->num; i++) { - struct component_match_array *mc = &match->compare[i]; - - if (mc->release) - mc->release(master, mc->data); - } - - kfree(match->compare); -} - -static void devm_component_match_release(struct device *dev, void *res) -{ - component_match_release(dev, res); -} - -static int component_match_realloc(struct device *dev, - struct component_match *match, size_t num) -{ - struct component_match_array *new; - - if (match->alloc == num) - return 0; - - new = kmalloc_array(num, sizeof(*new), GFP_KERNEL); - if (!new) - return -ENOMEM; - - if (match->compare) { - memcpy(new, match->compare, sizeof(*new) * - min(match->num, num)); - kfree(match->compare); - } - match->compare = new; - match->alloc = num; - - return 0; -} - -/* - * Add a component to be matched, with a release function. - * - * The match array is first created or extended if necessary. - */ -void component_match_add_release(struct device *master, - struct component_match **matchptr, - void (*release)(struct device *, void *), - int (*compare)(struct device *, void *), void *compare_data) -{ - struct component_match *match = *matchptr; - - if (IS_ERR(match)) - return; - - if (!match) { - match = devres_alloc(devm_component_match_release, - sizeof(*match), GFP_KERNEL); - if (!match) { - *matchptr = ERR_PTR(-ENOMEM); - return; - } - - devres_add(master, match); - - *matchptr = match; - } - - if (match->num == match->alloc) { - size_t new_size = match->alloc + 16; - int ret; - - ret = component_match_realloc(master, match, new_size); - if (ret) { - *matchptr = ERR_PTR(ret); - return; - } - } - - match->compare[match->num].compare = compare; - match->compare[match->num].release = release; - match->compare[match->num].data = compare_data; - match->compare[match->num].component = NULL; - match->num++; -} -EXPORT_SYMBOL(component_match_add_release); - -static void free_master(struct master *master) -{ - struct component_match *match = master->match; - int i; - - list_del(&master->node); - - if (match) { - for (i = 0; i < match->num; i++) { - struct component *c = match->compare[i].component; - if (c) - c->master = NULL; - } - } - - kfree(master); -} - -int component_master_add_with_match(struct device *dev, - const struct component_master_ops *ops, - struct component_match *match) -{ - struct master *master; - int ret; - - /* Reallocate the match array for its true size */ - ret = component_match_realloc(dev, match, match->num); - if (ret) - return ret; - - master = kzalloc(sizeof(*master), GFP_KERNEL); - if (!master) - return -ENOMEM; - - master->dev = dev; - master->ops = ops; - master->match = match; - - /* Add to the list of available masters. */ - mutex_lock(&component_mutex); - list_add(&master->node, &masters); - - ret = try_to_bring_up_master(master, NULL); - - if (ret < 0) - free_master(master); - - mutex_unlock(&component_mutex); - - return ret < 0 ? ret : 0; -} -EXPORT_SYMBOL_GPL(component_master_add_with_match); - -void component_master_del(struct device *dev, - const struct component_master_ops *ops) -{ - struct master *master; - - mutex_lock(&component_mutex); - master = __master_find(dev, ops); - if (master) { - take_down_master(master); - free_master(master); - } - mutex_unlock(&component_mutex); -} -EXPORT_SYMBOL_GPL(component_master_del); - -static void component_unbind(struct component *component, - struct master *master, void *data) -{ - WARN_ON(!component->bound); - - component->ops->unbind(component->dev, master->dev, data); - component->bound = false; - - /* Release all resources claimed in the binding of this component */ - devres_release_group(component->dev, component); -} - -void component_unbind_all(struct device *master_dev, void *data) -{ - struct master *master; - struct component *c; - size_t i; - - WARN_ON(!mutex_is_locked(&component_mutex)); - - master = __master_find(master_dev, NULL); - if (!master) - return; - - /* Unbind components in reverse order */ - for (i = master->match->num; i--; ) - if (!master->match->compare[i].duplicate) { - c = master->match->compare[i].component; - component_unbind(c, master, data); - } -} -EXPORT_SYMBOL_GPL(component_unbind_all); - -static int component_bind(struct component *component, struct master *master, - void *data) -{ - int ret; - - /* - * Each component initialises inside its own devres group. - * This allows us to roll-back a failed component without - * affecting anything else. - */ - if (!devres_open_group(master->dev, NULL, GFP_KERNEL)) - return -ENOMEM; - - /* - * Also open a group for the device itself: this allows us - * to release the resources claimed against the sub-device - * at the appropriate moment. - */ - if (!devres_open_group(component->dev, component, GFP_KERNEL)) { - devres_release_group(master->dev, NULL); - return -ENOMEM; - } - - dev_dbg(master->dev, "binding %s (ops %ps)\n", - dev_name(component->dev), component->ops); - - ret = component->ops->bind(component->dev, master->dev, data); - if (!ret) { - component->bound = true; - - /* - * Close the component device's group so that resources - * allocated in the binding are encapsulated for removal - * at unbind. Remove the group on the DRM device as we - * can clean those resources up independently. - */ - devres_close_group(component->dev, NULL); - devres_remove_group(master->dev, NULL); - - dev_info(master->dev, "bound %s (ops %ps)\n", - dev_name(component->dev), component->ops); - } else { - devres_release_group(component->dev, NULL); - devres_release_group(master->dev, NULL); - - dev_err(master->dev, "failed to bind %s (ops %ps): %d\n", - dev_name(component->dev), component->ops, ret); - } - - return ret; -} - -int component_bind_all(struct device *master_dev, void *data) -{ - struct master *master; - struct component *c; - size_t i; - int ret = 0; - - WARN_ON(!mutex_is_locked(&component_mutex)); - - master = __master_find(master_dev, NULL); - if (!master) - return -EINVAL; - - /* Bind components in match order */ - for (i = 0; i < master->match->num; i++) - if (!master->match->compare[i].duplicate) { - c = master->match->compare[i].component; - ret = component_bind(c, master, data); - if (ret) - break; - } - - if (ret != 0) { - for (; i--; ) - if (!master->match->compare[i].duplicate) { - c = master->match->compare[i].component; - component_unbind(c, master, data); - } - } - - return ret; -} -EXPORT_SYMBOL_GPL(component_bind_all); - -int component_add(struct device *dev, const struct component_ops *ops) -{ - struct component *component; - int ret; - - component = kzalloc(sizeof(*component), GFP_KERNEL); - if (!component) - return -ENOMEM; - - component->ops = ops; - component->dev = dev; - - dev_dbg(dev, "adding component (ops %ps)\n", ops); - - mutex_lock(&component_mutex); - list_add_tail(&component->node, &component_list); - - ret = try_to_bring_up_masters(component); - if (ret < 0) { - if (component->master) - remove_component(component->master, component); - list_del(&component->node); - - kfree(component); - } - mutex_unlock(&component_mutex); - - return ret < 0 ? ret : 0; -} -EXPORT_SYMBOL_GPL(component_add); - -void component_del(struct device *dev, const struct component_ops *ops) -{ - struct component *c, *component = NULL; - - mutex_lock(&component_mutex); - list_for_each_entry(c, &component_list, node) - if (c->dev == dev && c->ops == ops) { - list_del(&c->node); - component = c; - break; - } - - if (component && component->master) { - take_down_master(component->master); - remove_component(component->master, component); - } - - mutex_unlock(&component_mutex); - - WARN_ON(!component); - kfree(component); -} -EXPORT_SYMBOL_GPL(component_del); - -MODULE_LICENSE("GPL v2"); diff --git a/src/linux/drivers/base/container.c b/src/linux/drivers/base/container.c deleted file mode 100644 index ecbfbe2..0000000 --- a/src/linux/drivers/base/container.c +++ /dev/null @@ -1,44 +0,0 @@ -/* - * System bus type for containers. - * - * Copyright (C) 2013, Intel Corporation - * Author: Rafael J. Wysocki - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include - -#include "base.h" - -#define CONTAINER_BUS_NAME "container" - -static int trivial_online(struct device *dev) -{ - return 0; -} - -static int container_offline(struct device *dev) -{ - struct container_dev *cdev = to_container_dev(dev); - - return cdev->offline ? cdev->offline(cdev) : 0; -} - -struct bus_type container_subsys = { - .name = CONTAINER_BUS_NAME, - .dev_name = CONTAINER_BUS_NAME, - .online = trivial_online, - .offline = container_offline, -}; - -void __init container_dev_init(void) -{ - int ret; - - ret = subsys_system_register(&container_subsys, NULL); - if (ret) - pr_err("%s() failed: %d\n", __func__, ret); -} diff --git a/src/linux/drivers/base/core.c b/src/linux/drivers/base/core.c deleted file mode 100644 index ce057a5..0000000 --- a/src/linux/drivers/base/core.c +++ /dev/null @@ -1,2314 +0,0 @@ -/* - * drivers/base/core.c - core driver model code (device registration, etc) - * - * Copyright (c) 2002-3 Patrick Mochel - * Copyright (c) 2002-3 Open Source Development Labs - * Copyright (c) 2006 Greg Kroah-Hartman - * Copyright (c) 2006 Novell, Inc. - * - * This file is released under the GPLv2 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "base.h" -#include "power/power.h" - -#ifdef CONFIG_SYSFS_DEPRECATED -#ifdef CONFIG_SYSFS_DEPRECATED_V2 -long sysfs_deprecated = 1; -#else -long sysfs_deprecated = 0; -#endif -static int __init sysfs_deprecated_setup(char *arg) -{ - return kstrtol(arg, 10, &sysfs_deprecated); -} -early_param("sysfs.deprecated", sysfs_deprecated_setup); -#endif - -int (*platform_notify)(struct device *dev) = NULL; -int (*platform_notify_remove)(struct device *dev) = NULL; -static struct kobject *dev_kobj; -struct kobject *sysfs_dev_char_kobj; -struct kobject *sysfs_dev_block_kobj; - -static DEFINE_MUTEX(device_hotplug_lock); - -void lock_device_hotplug(void) -{ - mutex_lock(&device_hotplug_lock); -} - -void unlock_device_hotplug(void) -{ - mutex_unlock(&device_hotplug_lock); -} - -int lock_device_hotplug_sysfs(void) -{ - if (mutex_trylock(&device_hotplug_lock)) - return 0; - - /* Avoid busy looping (5 ms of sleep should do). */ - msleep(5); - return restart_syscall(); -} - -#ifdef CONFIG_BLOCK -static inline int device_is_not_partition(struct device *dev) -{ - return !(dev->type == &part_type); -} -#else -static inline int device_is_not_partition(struct device *dev) -{ - return 1; -} -#endif - -/** - * dev_driver_string - Return a device's driver name, if at all possible - * @dev: struct device to get the name of - * - * Will return the device's driver's name if it is bound to a device. If - * the device is not bound to a driver, it will return the name of the bus - * it is attached to. If it is not attached to a bus either, an empty - * string will be returned. - */ -const char *dev_driver_string(const struct device *dev) -{ - struct device_driver *drv; - - /* dev->driver can change to NULL underneath us because of unbinding, - * so be careful about accessing it. dev->bus and dev->class should - * never change once they are set, so they don't need special care. - */ - drv = ACCESS_ONCE(dev->driver); - return drv ? drv->name : - (dev->bus ? dev->bus->name : - (dev->class ? dev->class->name : "")); -} -EXPORT_SYMBOL(dev_driver_string); - -#define to_dev_attr(_attr) container_of(_attr, struct device_attribute, attr) - -static ssize_t dev_attr_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct device_attribute *dev_attr = to_dev_attr(attr); - struct device *dev = kobj_to_dev(kobj); - ssize_t ret = -EIO; - - if (dev_attr->show) - ret = dev_attr->show(dev, dev_attr, buf); - if (ret >= (ssize_t)PAGE_SIZE) { - print_symbol("dev_attr_show: %s returned bad count\n", - (unsigned long)dev_attr->show); - } - return ret; -} - -static ssize_t dev_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t count) -{ - struct device_attribute *dev_attr = to_dev_attr(attr); - struct device *dev = kobj_to_dev(kobj); - ssize_t ret = -EIO; - - if (dev_attr->store) - ret = dev_attr->store(dev, dev_attr, buf, count); - return ret; -} - -static const struct sysfs_ops dev_sysfs_ops = { - .show = dev_attr_show, - .store = dev_attr_store, -}; - -#define to_ext_attr(x) container_of(x, struct dev_ext_attribute, attr) - -ssize_t device_store_ulong(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct dev_ext_attribute *ea = to_ext_attr(attr); - char *end; - unsigned long new = simple_strtoul(buf, &end, 0); - if (end == buf) - return -EINVAL; - *(unsigned long *)(ea->var) = new; - /* Always return full write size even if we didn't consume all */ - return size; -} -EXPORT_SYMBOL_GPL(device_store_ulong); - -ssize_t device_show_ulong(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct dev_ext_attribute *ea = to_ext_attr(attr); - return snprintf(buf, PAGE_SIZE, "%lx\n", *(unsigned long *)(ea->var)); -} -EXPORT_SYMBOL_GPL(device_show_ulong); - -ssize_t device_store_int(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t size) -{ - struct dev_ext_attribute *ea = to_ext_attr(attr); - char *end; - long new = simple_strtol(buf, &end, 0); - if (end == buf || new > INT_MAX || new < INT_MIN) - return -EINVAL; - *(int *)(ea->var) = new; - /* Always return full write size even if we didn't consume all */ - return size; -} -EXPORT_SYMBOL_GPL(device_store_int); - -ssize_t device_show_int(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct dev_ext_attribute *ea = to_ext_attr(attr); - - return snprintf(buf, PAGE_SIZE, "%d\n", *(int *)(ea->var)); -} -EXPORT_SYMBOL_GPL(device_show_int); - -ssize_t device_store_bool(struct device *dev, struct device_attribute *attr, - const char *buf, size_t size) -{ - struct dev_ext_attribute *ea = to_ext_attr(attr); - - if (strtobool(buf, ea->var) < 0) - return -EINVAL; - - return size; -} -EXPORT_SYMBOL_GPL(device_store_bool); - -ssize_t device_show_bool(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct dev_ext_attribute *ea = to_ext_attr(attr); - - return snprintf(buf, PAGE_SIZE, "%d\n", *(bool *)(ea->var)); -} -EXPORT_SYMBOL_GPL(device_show_bool); - -/** - * device_release - free device structure. - * @kobj: device's kobject. - * - * This is called once the reference count for the object - * reaches 0. We forward the call to the device's release - * method, which should handle actually freeing the structure. - */ -static void device_release(struct kobject *kobj) -{ - struct device *dev = kobj_to_dev(kobj); - struct device_private *p = dev->p; - - /* - * Some platform devices are driven without driver attached - * and managed resources may have been acquired. Make sure - * all resources are released. - * - * Drivers still can add resources into device after device - * is deleted but alive, so release devres here to avoid - * possible memory leak. - */ - devres_release_all(dev); - - if (dev->release) - dev->release(dev); - else if (dev->type && dev->type->release) - dev->type->release(dev); - else if (dev->class && dev->class->dev_release) - dev->class->dev_release(dev); - else - WARN(1, KERN_ERR "Device '%s' does not have a release() " - "function, it is broken and must be fixed.\n", - dev_name(dev)); - kfree(p); -} - -static const void *device_namespace(struct kobject *kobj) -{ - struct device *dev = kobj_to_dev(kobj); - const void *ns = NULL; - - if (dev->class && dev->class->ns_type) - ns = dev->class->namespace(dev); - - return ns; -} - -static struct kobj_type device_ktype = { - .release = device_release, - .sysfs_ops = &dev_sysfs_ops, - .namespace = device_namespace, -}; - - -static int dev_uevent_filter(struct kset *kset, struct kobject *kobj) -{ - struct kobj_type *ktype = get_ktype(kobj); - - if (ktype == &device_ktype) { - struct device *dev = kobj_to_dev(kobj); - if (dev->bus) - return 1; - if (dev->class) - return 1; - } - return 0; -} - -static const char *dev_uevent_name(struct kset *kset, struct kobject *kobj) -{ - struct device *dev = kobj_to_dev(kobj); - - if (dev->bus) - return dev->bus->name; - if (dev->class) - return dev->class->name; - return NULL; -} - -static int dev_uevent(struct kset *kset, struct kobject *kobj, - struct kobj_uevent_env *env) -{ - struct device *dev = kobj_to_dev(kobj); - int retval = 0; - - /* add device node properties if present */ - if (MAJOR(dev->devt)) { - const char *tmp; - const char *name; - umode_t mode = 0; - kuid_t uid = GLOBAL_ROOT_UID; - kgid_t gid = GLOBAL_ROOT_GID; - - add_uevent_var(env, "MAJOR=%u", MAJOR(dev->devt)); - add_uevent_var(env, "MINOR=%u", MINOR(dev->devt)); - name = device_get_devnode(dev, &mode, &uid, &gid, &tmp); - if (name) { - add_uevent_var(env, "DEVNAME=%s", name); - if (mode) - add_uevent_var(env, "DEVMODE=%#o", mode & 0777); - if (!uid_eq(uid, GLOBAL_ROOT_UID)) - add_uevent_var(env, "DEVUID=%u", from_kuid(&init_user_ns, uid)); - if (!gid_eq(gid, GLOBAL_ROOT_GID)) - add_uevent_var(env, "DEVGID=%u", from_kgid(&init_user_ns, gid)); - kfree(tmp); - } - } - - if (dev->type && dev->type->name) - add_uevent_var(env, "DEVTYPE=%s", dev->type->name); - - if (dev->driver) - add_uevent_var(env, "DRIVER=%s", dev->driver->name); - - /* Add common DT information about the device */ - of_device_uevent(dev, env); - - /* have the bus specific function add its stuff */ - if (dev->bus && dev->bus->uevent) { - retval = dev->bus->uevent(dev, env); - if (retval) - pr_debug("device: '%s': %s: bus uevent() returned %d\n", - dev_name(dev), __func__, retval); - } - - /* have the class specific function add its stuff */ - if (dev->class && dev->class->dev_uevent) { - retval = dev->class->dev_uevent(dev, env); - if (retval) - pr_debug("device: '%s': %s: class uevent() " - "returned %d\n", dev_name(dev), - __func__, retval); - } - - /* have the device type specific function add its stuff */ - if (dev->type && dev->type->uevent) { - retval = dev->type->uevent(dev, env); - if (retval) - pr_debug("device: '%s': %s: dev_type uevent() " - "returned %d\n", dev_name(dev), - __func__, retval); - } - - return retval; -} - -static const struct kset_uevent_ops device_uevent_ops = { - .filter = dev_uevent_filter, - .name = dev_uevent_name, - .uevent = dev_uevent, -}; - -static ssize_t uevent_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct kobject *top_kobj; - struct kset *kset; - struct kobj_uevent_env *env = NULL; - int i; - size_t count = 0; - int retval; - - /* search the kset, the device belongs to */ - top_kobj = &dev->kobj; - while (!top_kobj->kset && top_kobj->parent) - top_kobj = top_kobj->parent; - if (!top_kobj->kset) - goto out; - - kset = top_kobj->kset; - if (!kset->uevent_ops || !kset->uevent_ops->uevent) - goto out; - - /* respect filter */ - if (kset->uevent_ops && kset->uevent_ops->filter) - if (!kset->uevent_ops->filter(kset, &dev->kobj)) - goto out; - - env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); - if (!env) - return -ENOMEM; - - /* let the kset specific function add its keys */ - retval = kset->uevent_ops->uevent(kset, &dev->kobj, env); - if (retval) - goto out; - - /* copy keys to file */ - for (i = 0; i < env->envp_idx; i++) - count += sprintf(&buf[count], "%s\n", env->envp[i]); -out: - kfree(env); - return count; -} - -static ssize_t uevent_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - enum kobject_action action; - - if (kobject_action_type(buf, count, &action) == 0) - kobject_uevent(&dev->kobj, action); - else - dev_err(dev, "uevent: unknown action-string\n"); - return count; -} -static DEVICE_ATTR_RW(uevent); - -static ssize_t online_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - bool val; - - device_lock(dev); - val = !dev->offline; - device_unlock(dev); - return sprintf(buf, "%u\n", val); -} - -static ssize_t online_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - bool val; - int ret; - - ret = strtobool(buf, &val); - if (ret < 0) - return ret; - - ret = lock_device_hotplug_sysfs(); - if (ret) - return ret; - - ret = val ? device_online(dev) : device_offline(dev); - unlock_device_hotplug(); - return ret < 0 ? ret : count; -} -static DEVICE_ATTR_RW(online); - -int device_add_groups(struct device *dev, const struct attribute_group **groups) -{ - return sysfs_create_groups(&dev->kobj, groups); -} - -void device_remove_groups(struct device *dev, - const struct attribute_group **groups) -{ - sysfs_remove_groups(&dev->kobj, groups); -} - -static int device_add_attrs(struct device *dev) -{ - struct class *class = dev->class; - const struct device_type *type = dev->type; - int error; - - if (class) { - error = device_add_groups(dev, class->dev_groups); - if (error) - return error; - } - - if (type) { - error = device_add_groups(dev, type->groups); - if (error) - goto err_remove_class_groups; - } - - error = device_add_groups(dev, dev->groups); - if (error) - goto err_remove_type_groups; - - if (device_supports_offline(dev) && !dev->offline_disabled) { - error = device_create_file(dev, &dev_attr_online); - if (error) - goto err_remove_dev_groups; - } - - return 0; - - err_remove_dev_groups: - device_remove_groups(dev, dev->groups); - err_remove_type_groups: - if (type) - device_remove_groups(dev, type->groups); - err_remove_class_groups: - if (class) - device_remove_groups(dev, class->dev_groups); - - return error; -} - -static void device_remove_attrs(struct device *dev) -{ - struct class *class = dev->class; - const struct device_type *type = dev->type; - - device_remove_file(dev, &dev_attr_online); - device_remove_groups(dev, dev->groups); - - if (type) - device_remove_groups(dev, type->groups); - - if (class) - device_remove_groups(dev, class->dev_groups); -} - -static ssize_t dev_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - return print_dev_t(buf, dev->devt); -} -static DEVICE_ATTR_RO(dev); - -/* /sys/devices/ */ -struct kset *devices_kset; - -/** - * devices_kset_move_before - Move device in the devices_kset's list. - * @deva: Device to move. - * @devb: Device @deva should come before. - */ -static void devices_kset_move_before(struct device *deva, struct device *devb) -{ - if (!devices_kset) - return; - pr_debug("devices_kset: Moving %s before %s\n", - dev_name(deva), dev_name(devb)); - spin_lock(&devices_kset->list_lock); - list_move_tail(&deva->kobj.entry, &devb->kobj.entry); - spin_unlock(&devices_kset->list_lock); -} - -/** - * devices_kset_move_after - Move device in the devices_kset's list. - * @deva: Device to move - * @devb: Device @deva should come after. - */ -static void devices_kset_move_after(struct device *deva, struct device *devb) -{ - if (!devices_kset) - return; - pr_debug("devices_kset: Moving %s after %s\n", - dev_name(deva), dev_name(devb)); - spin_lock(&devices_kset->list_lock); - list_move(&deva->kobj.entry, &devb->kobj.entry); - spin_unlock(&devices_kset->list_lock); -} - -/** - * devices_kset_move_last - move the device to the end of devices_kset's list. - * @dev: device to move - */ -void devices_kset_move_last(struct device *dev) -{ - if (!devices_kset) - return; - pr_debug("devices_kset: Moving %s to end of list\n", dev_name(dev)); - spin_lock(&devices_kset->list_lock); - list_move_tail(&dev->kobj.entry, &devices_kset->list); - spin_unlock(&devices_kset->list_lock); -} - -/** - * device_create_file - create sysfs attribute file for device. - * @dev: device. - * @attr: device attribute descriptor. - */ -int device_create_file(struct device *dev, - const struct device_attribute *attr) -{ - int error = 0; - - if (dev) { - WARN(((attr->attr.mode & S_IWUGO) && !attr->store), - "Attribute %s: write permission without 'store'\n", - attr->attr.name); - WARN(((attr->attr.mode & S_IRUGO) && !attr->show), - "Attribute %s: read permission without 'show'\n", - attr->attr.name); - error = sysfs_create_file(&dev->kobj, &attr->attr); - } - - return error; -} -EXPORT_SYMBOL_GPL(device_create_file); - -/** - * device_remove_file - remove sysfs attribute file. - * @dev: device. - * @attr: device attribute descriptor. - */ -void device_remove_file(struct device *dev, - const struct device_attribute *attr) -{ - if (dev) - sysfs_remove_file(&dev->kobj, &attr->attr); -} -EXPORT_SYMBOL_GPL(device_remove_file); - -/** - * device_remove_file_self - remove sysfs attribute file from its own method. - * @dev: device. - * @attr: device attribute descriptor. - * - * See kernfs_remove_self() for details. - */ -bool device_remove_file_self(struct device *dev, - const struct device_attribute *attr) -{ - if (dev) - return sysfs_remove_file_self(&dev->kobj, &attr->attr); - else - return false; -} -EXPORT_SYMBOL_GPL(device_remove_file_self); - -/** - * device_create_bin_file - create sysfs binary attribute file for device. - * @dev: device. - * @attr: device binary attribute descriptor. - */ -int device_create_bin_file(struct device *dev, - const struct bin_attribute *attr) -{ - int error = -EINVAL; - if (dev) - error = sysfs_create_bin_file(&dev->kobj, attr); - return error; -} -EXPORT_SYMBOL_GPL(device_create_bin_file); - -/** - * device_remove_bin_file - remove sysfs binary attribute file - * @dev: device. - * @attr: device binary attribute descriptor. - */ -void device_remove_bin_file(struct device *dev, - const struct bin_attribute *attr) -{ - if (dev) - sysfs_remove_bin_file(&dev->kobj, attr); -} -EXPORT_SYMBOL_GPL(device_remove_bin_file); - -static void klist_children_get(struct klist_node *n) -{ - struct device_private *p = to_device_private_parent(n); - struct device *dev = p->device; - - get_device(dev); -} - -static void klist_children_put(struct klist_node *n) -{ - struct device_private *p = to_device_private_parent(n); - struct device *dev = p->device; - - put_device(dev); -} - -/** - * device_initialize - init device structure. - * @dev: device. - * - * This prepares the device for use by other layers by initializing - * its fields. - * It is the first half of device_register(), if called by - * that function, though it can also be called separately, so one - * may use @dev's fields. In particular, get_device()/put_device() - * may be used for reference counting of @dev after calling this - * function. - * - * All fields in @dev must be initialized by the caller to 0, except - * for those explicitly set to some other value. The simplest - * approach is to use kzalloc() to allocate the structure containing - * @dev. - * - * NOTE: Use put_device() to give up your reference instead of freeing - * @dev directly once you have called this function. - */ -void device_initialize(struct device *dev) -{ - dev->kobj.kset = devices_kset; - kobject_init(&dev->kobj, &device_ktype); - INIT_LIST_HEAD(&dev->dma_pools); - mutex_init(&dev->mutex); - lockdep_set_novalidate_class(&dev->mutex); - spin_lock_init(&dev->devres_lock); - INIT_LIST_HEAD(&dev->devres_head); - device_pm_init(dev); - set_dev_node(dev, -1); -#ifdef CONFIG_GENERIC_MSI_IRQ - INIT_LIST_HEAD(&dev->msi_list); -#endif -} -EXPORT_SYMBOL_GPL(device_initialize); - -struct kobject *virtual_device_parent(struct device *dev) -{ - static struct kobject *virtual_dir = NULL; - - if (!virtual_dir) - virtual_dir = kobject_create_and_add("virtual", - &devices_kset->kobj); - - return virtual_dir; -} - -struct class_dir { - struct kobject kobj; - struct class *class; -}; - -#define to_class_dir(obj) container_of(obj, struct class_dir, kobj) - -static void class_dir_release(struct kobject *kobj) -{ - struct class_dir *dir = to_class_dir(kobj); - kfree(dir); -} - -static const -struct kobj_ns_type_operations *class_dir_child_ns_type(struct kobject *kobj) -{ - struct class_dir *dir = to_class_dir(kobj); - return dir->class->ns_type; -} - -static struct kobj_type class_dir_ktype = { - .release = class_dir_release, - .sysfs_ops = &kobj_sysfs_ops, - .child_ns_type = class_dir_child_ns_type -}; - -static struct kobject * -class_dir_create_and_add(struct class *class, struct kobject *parent_kobj) -{ - struct class_dir *dir; - int retval; - - dir = kzalloc(sizeof(*dir), GFP_KERNEL); - if (!dir) - return NULL; - - dir->class = class; - kobject_init(&dir->kobj, &class_dir_ktype); - - dir->kobj.kset = &class->p->glue_dirs; - - retval = kobject_add(&dir->kobj, parent_kobj, "%s", class->name); - if (retval < 0) { - kobject_put(&dir->kobj); - return NULL; - } - return &dir->kobj; -} - -static DEFINE_MUTEX(gdp_mutex); - -static struct kobject *get_device_parent(struct device *dev, - struct device *parent) -{ - if (dev->class) { - struct kobject *kobj = NULL; - struct kobject *parent_kobj; - struct kobject *k; - -#ifdef CONFIG_BLOCK - /* block disks show up in /sys/block */ - if (sysfs_deprecated && dev->class == &block_class) { - if (parent && parent->class == &block_class) - return &parent->kobj; - return &block_class.p->subsys.kobj; - } -#endif - - /* - * If we have no parent, we live in "virtual". - * Class-devices with a non class-device as parent, live - * in a "glue" directory to prevent namespace collisions. - */ - if (parent == NULL) - parent_kobj = virtual_device_parent(dev); - else if (parent->class && !dev->class->ns_type) - return &parent->kobj; - else - parent_kobj = &parent->kobj; - - mutex_lock(&gdp_mutex); - - /* find our class-directory at the parent and reference it */ - spin_lock(&dev->class->p->glue_dirs.list_lock); - list_for_each_entry(k, &dev->class->p->glue_dirs.list, entry) - if (k->parent == parent_kobj) { - kobj = kobject_get(k); - break; - } - spin_unlock(&dev->class->p->glue_dirs.list_lock); - if (kobj) { - mutex_unlock(&gdp_mutex); - return kobj; - } - - /* or create a new class-directory at the parent device */ - k = class_dir_create_and_add(dev->class, parent_kobj); - /* do not emit an uevent for this simple "glue" directory */ - mutex_unlock(&gdp_mutex); - return k; - } - - /* subsystems can specify a default root directory for their devices */ - if (!parent && dev->bus && dev->bus->dev_root) - return &dev->bus->dev_root->kobj; - - if (parent) - return &parent->kobj; - return NULL; -} - -static inline bool live_in_glue_dir(struct kobject *kobj, - struct device *dev) -{ - if (!kobj || !dev->class || - kobj->kset != &dev->class->p->glue_dirs) - return false; - return true; -} - -static inline struct kobject *get_glue_dir(struct device *dev) -{ - return dev->kobj.parent; -} - -/* - * make sure cleaning up dir as the last step, we need to make - * sure .release handler of kobject is run with holding the - * global lock - */ -static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) -{ - /* see if we live in a "glue" directory */ - if (!live_in_glue_dir(glue_dir, dev)) - return; - - mutex_lock(&gdp_mutex); - kobject_put(glue_dir); - mutex_unlock(&gdp_mutex); -} - -static int device_add_class_symlinks(struct device *dev) -{ - struct device_node *of_node = dev_of_node(dev); - int error; - - if (of_node) { - error = sysfs_create_link(&dev->kobj, &of_node->kobj,"of_node"); - if (error) - dev_warn(dev, "Error %d creating of_node link\n",error); - /* An error here doesn't warrant bringing down the device */ - } - - if (!dev->class) - return 0; - - error = sysfs_create_link(&dev->kobj, - &dev->class->p->subsys.kobj, - "subsystem"); - if (error) - goto out_devnode; - - if (dev->parent && device_is_not_partition(dev)) { - error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, - "device"); - if (error) - goto out_subsys; - } - -#ifdef CONFIG_BLOCK - /* /sys/block has directories and does not need symlinks */ - if (sysfs_deprecated && dev->class == &block_class) - return 0; -#endif - - /* link in the class directory pointing to the device */ - error = sysfs_create_link(&dev->class->p->subsys.kobj, - &dev->kobj, dev_name(dev)); - if (error) - goto out_device; - - return 0; - -out_device: - sysfs_remove_link(&dev->kobj, "device"); - -out_subsys: - sysfs_remove_link(&dev->kobj, "subsystem"); -out_devnode: - sysfs_remove_link(&dev->kobj, "of_node"); - return error; -} - -static void device_remove_class_symlinks(struct device *dev) -{ - if (dev_of_node(dev)) - sysfs_remove_link(&dev->kobj, "of_node"); - - if (!dev->class) - return; - - if (dev->parent && device_is_not_partition(dev)) - sysfs_remove_link(&dev->kobj, "device"); - sysfs_remove_link(&dev->kobj, "subsystem"); -#ifdef CONFIG_BLOCK - if (sysfs_deprecated && dev->class == &block_class) - return; -#endif - sysfs_delete_link(&dev->class->p->subsys.kobj, &dev->kobj, dev_name(dev)); -} - -/** - * dev_set_name - set a device name - * @dev: device - * @fmt: format string for the device's name - */ -int dev_set_name(struct device *dev, const char *fmt, ...) -{ - va_list vargs; - int err; - - va_start(vargs, fmt); - err = kobject_set_name_vargs(&dev->kobj, fmt, vargs); - va_end(vargs); - return err; -} -EXPORT_SYMBOL_GPL(dev_set_name); - -/** - * device_to_dev_kobj - select a /sys/dev/ directory for the device - * @dev: device - * - * By default we select char/ for new entries. Setting class->dev_obj - * to NULL prevents an entry from being created. class->dev_kobj must - * be set (or cleared) before any devices are registered to the class - * otherwise device_create_sys_dev_entry() and - * device_remove_sys_dev_entry() will disagree about the presence of - * the link. - */ -static struct kobject *device_to_dev_kobj(struct device *dev) -{ - struct kobject *kobj; - - if (dev->class) - kobj = dev->class->dev_kobj; - else - kobj = sysfs_dev_char_kobj; - - return kobj; -} - -static int device_create_sys_dev_entry(struct device *dev) -{ - struct kobject *kobj = device_to_dev_kobj(dev); - int error = 0; - char devt_str[15]; - - if (kobj) { - format_dev_t(devt_str, dev->devt); - error = sysfs_create_link(kobj, &dev->kobj, devt_str); - } - - return error; -} - -static void device_remove_sys_dev_entry(struct device *dev) -{ - struct kobject *kobj = device_to_dev_kobj(dev); - char devt_str[15]; - - if (kobj) { - format_dev_t(devt_str, dev->devt); - sysfs_remove_link(kobj, devt_str); - } -} - -int device_private_init(struct device *dev) -{ - dev->p = kzalloc(sizeof(*dev->p), GFP_KERNEL); - if (!dev->p) - return -ENOMEM; - dev->p->device = dev; - klist_init(&dev->p->klist_children, klist_children_get, - klist_children_put); - INIT_LIST_HEAD(&dev->p->deferred_probe); - return 0; -} - -/** - * device_add - add device to device hierarchy. - * @dev: device. - * - * This is part 2 of device_register(), though may be called - * separately _iff_ device_initialize() has been called separately. - * - * This adds @dev to the kobject hierarchy via kobject_add(), adds it - * to the global and sibling lists for the device, then - * adds it to the other relevant subsystems of the driver model. - * - * Do not call this routine or device_register() more than once for - * any device structure. The driver model core is not designed to work - * with devices that get unregistered and then spring back to life. - * (Among other things, it's very hard to guarantee that all references - * to the previous incarnation of @dev have been dropped.) Allocate - * and register a fresh new struct device instead. - * - * NOTE: _Never_ directly free @dev after calling this function, even - * if it returned an error! Always use put_device() to give up your - * reference instead. - */ -int device_add(struct device *dev) -{ - struct device *parent = NULL; - struct kobject *kobj; - struct class_interface *class_intf; - int error = -EINVAL; - struct kobject *glue_dir = NULL; - - dev = get_device(dev); - if (!dev) - goto done; - - if (!dev->p) { - error = device_private_init(dev); - if (error) - goto done; - } - - /* - * for statically allocated devices, which should all be converted - * some day, we need to initialize the name. We prevent reading back - * the name, and force the use of dev_name() - */ - if (dev->init_name) { - dev_set_name(dev, "%s", dev->init_name); - dev->init_name = NULL; - } - - /* subsystems can specify simple device enumeration */ - if (!dev_name(dev) && dev->bus && dev->bus->dev_name) - dev_set_name(dev, "%s%u", dev->bus->dev_name, dev->id); - - if (!dev_name(dev)) { - error = -EINVAL; - goto name_error; - } - - pr_debug("device: '%s': %s\n", dev_name(dev), __func__); - - parent = get_device(dev->parent); - kobj = get_device_parent(dev, parent); - if (kobj) - dev->kobj.parent = kobj; - - /* use parent numa_node */ - if (parent && (dev_to_node(dev) == NUMA_NO_NODE)) - set_dev_node(dev, dev_to_node(parent)); - - /* first, register with generic layer. */ - /* we require the name to be set before, and pass NULL */ - error = kobject_add(&dev->kobj, dev->kobj.parent, NULL); - if (error) { - glue_dir = get_glue_dir(dev); - goto Error; - } - - /* notify platform of device entry */ - if (platform_notify) - platform_notify(dev); - - error = device_create_file(dev, &dev_attr_uevent); - if (error) - goto attrError; - - error = device_add_class_symlinks(dev); - if (error) - goto SymlinkError; - error = device_add_attrs(dev); - if (error) - goto AttrsError; - error = bus_add_device(dev); - if (error) - goto BusError; - error = dpm_sysfs_add(dev); - if (error) - goto DPMError; - device_pm_add(dev); - - if (MAJOR(dev->devt)) { - error = device_create_file(dev, &dev_attr_dev); - if (error) - goto DevAttrError; - - error = device_create_sys_dev_entry(dev); - if (error) - goto SysEntryError; - - devtmpfs_create_node(dev); - } - - /* Notify clients of device addition. This call must come - * after dpm_sysfs_add() and before kobject_uevent(). - */ - if (dev->bus) - blocking_notifier_call_chain(&dev->bus->p->bus_notifier, - BUS_NOTIFY_ADD_DEVICE, dev); - - kobject_uevent(&dev->kobj, KOBJ_ADD); - bus_probe_device(dev); - if (parent) - klist_add_tail(&dev->p->knode_parent, - &parent->p->klist_children); - - if (dev->class) { - mutex_lock(&dev->class->p->mutex); - /* tie the class to the device */ - klist_add_tail(&dev->knode_class, - &dev->class->p->klist_devices); - - /* notify any interfaces that the device is here */ - list_for_each_entry(class_intf, - &dev->class->p->interfaces, node) - if (class_intf->add_dev) - class_intf->add_dev(dev, class_intf); - mutex_unlock(&dev->class->p->mutex); - } -done: - put_device(dev); - return error; - SysEntryError: - if (MAJOR(dev->devt)) - device_remove_file(dev, &dev_attr_dev); - DevAttrError: - device_pm_remove(dev); - dpm_sysfs_remove(dev); - DPMError: - bus_remove_device(dev); - BusError: - device_remove_attrs(dev); - AttrsError: - device_remove_class_symlinks(dev); - SymlinkError: - device_remove_file(dev, &dev_attr_uevent); - attrError: - kobject_uevent(&dev->kobj, KOBJ_REMOVE); - glue_dir = get_glue_dir(dev); - kobject_del(&dev->kobj); - Error: - cleanup_glue_dir(dev, glue_dir); - put_device(parent); -name_error: - kfree(dev->p); - dev->p = NULL; - goto done; -} -EXPORT_SYMBOL_GPL(device_add); - -/** - * device_register - register a device with the system. - * @dev: pointer to the device structure - * - * This happens in two clean steps - initialize the device - * and add it to the system. The two steps can be called - * separately, but this is the easiest and most common. - * I.e. you should only call the two helpers separately if - * have a clearly defined need to use and refcount the device - * before it is added to the hierarchy. - * - * For more information, see the kerneldoc for device_initialize() - * and device_add(). - * - * NOTE: _Never_ directly free @dev after calling this function, even - * if it returned an error! Always use put_device() to give up the - * reference initialized in this function instead. - */ -int device_register(struct device *dev) -{ - device_initialize(dev); - return device_add(dev); -} -EXPORT_SYMBOL_GPL(device_register); - -/** - * get_device - increment reference count for device. - * @dev: device. - * - * This simply forwards the call to kobject_get(), though - * we do take care to provide for the case that we get a NULL - * pointer passed in. - */ -struct device *get_device(struct device *dev) -{ - return dev ? kobj_to_dev(kobject_get(&dev->kobj)) : NULL; -} -EXPORT_SYMBOL_GPL(get_device); - -/** - * put_device - decrement reference count. - * @dev: device in question. - */ -void put_device(struct device *dev) -{ - /* might_sleep(); */ - if (dev) - kobject_put(&dev->kobj); -} -EXPORT_SYMBOL_GPL(put_device); - -/** - * device_del - delete device from system. - * @dev: device. - * - * This is the first part of the device unregistration - * sequence. This removes the device from the lists we control - * from here, has it removed from the other driver model - * subsystems it was added to in device_add(), and removes it - * from the kobject hierarchy. - * - * NOTE: this should be called manually _iff_ device_add() was - * also called manually. - */ -void device_del(struct device *dev) -{ - struct device *parent = dev->parent; - struct kobject *glue_dir = NULL; - struct class_interface *class_intf; - - /* Notify clients of device removal. This call must come - * before dpm_sysfs_remove(). - */ - if (dev->bus) - blocking_notifier_call_chain(&dev->bus->p->bus_notifier, - BUS_NOTIFY_DEL_DEVICE, dev); - dpm_sysfs_remove(dev); - if (parent) - klist_del(&dev->p->knode_parent); - if (MAJOR(dev->devt)) { - devtmpfs_delete_node(dev); - device_remove_sys_dev_entry(dev); - device_remove_file(dev, &dev_attr_dev); - } - if (dev->class) { - device_remove_class_symlinks(dev); - - mutex_lock(&dev->class->p->mutex); - /* notify any interfaces that the device is now gone */ - list_for_each_entry(class_intf, - &dev->class->p->interfaces, node) - if (class_intf->remove_dev) - class_intf->remove_dev(dev, class_intf); - /* remove the device from the class list */ - klist_del(&dev->knode_class); - mutex_unlock(&dev->class->p->mutex); - } - device_remove_file(dev, &dev_attr_uevent); - device_remove_attrs(dev); - bus_remove_device(dev); - device_pm_remove(dev); - driver_deferred_probe_del(dev); - device_remove_properties(dev); - - /* Notify the platform of the removal, in case they - * need to do anything... - */ - if (platform_notify_remove) - platform_notify_remove(dev); - if (dev->bus) - blocking_notifier_call_chain(&dev->bus->p->bus_notifier, - BUS_NOTIFY_REMOVED_DEVICE, dev); - kobject_uevent(&dev->kobj, KOBJ_REMOVE); - glue_dir = get_glue_dir(dev); - kobject_del(&dev->kobj); - cleanup_glue_dir(dev, glue_dir); - put_device(parent); -} -EXPORT_SYMBOL_GPL(device_del); - -/** - * device_unregister - unregister device from system. - * @dev: device going away. - * - * We do this in two parts, like we do device_register(). First, - * we remove it from all the subsystems with device_del(), then - * we decrement the reference count via put_device(). If that - * is the final reference count, the device will be cleaned up - * via device_release() above. Otherwise, the structure will - * stick around until the final reference to the device is dropped. - */ -void device_unregister(struct device *dev) -{ - pr_debug("device: '%s': %s\n", dev_name(dev), __func__); - device_del(dev); - put_device(dev); -} -EXPORT_SYMBOL_GPL(device_unregister); - -static struct device *prev_device(struct klist_iter *i) -{ - struct klist_node *n = klist_prev(i); - struct device *dev = NULL; - struct device_private *p; - - if (n) { - p = to_device_private_parent(n); - dev = p->device; - } - return dev; -} - -static struct device *next_device(struct klist_iter *i) -{ - struct klist_node *n = klist_next(i); - struct device *dev = NULL; - struct device_private *p; - - if (n) { - p = to_device_private_parent(n); - dev = p->device; - } - return dev; -} - -/** - * device_get_devnode - path of device node file - * @dev: device - * @mode: returned file access mode - * @uid: returned file owner - * @gid: returned file group - * @tmp: possibly allocated string - * - * Return the relative path of a possible device node. - * Non-default names may need to allocate a memory to compose - * a name. This memory is returned in tmp and needs to be - * freed by the caller. - */ -const char *device_get_devnode(struct device *dev, - umode_t *mode, kuid_t *uid, kgid_t *gid, - const char **tmp) -{ - char *s; - - *tmp = NULL; - - /* the device type may provide a specific name */ - if (dev->type && dev->type->devnode) - *tmp = dev->type->devnode(dev, mode, uid, gid); - if (*tmp) - return *tmp; - - /* the class may provide a specific name */ - if (dev->class && dev->class->devnode) - *tmp = dev->class->devnode(dev, mode); - if (*tmp) - return *tmp; - - /* return name without allocation, tmp == NULL */ - if (strchr(dev_name(dev), '!') == NULL) - return dev_name(dev); - - /* replace '!' in the name with '/' */ - s = kstrdup(dev_name(dev), GFP_KERNEL); - if (!s) - return NULL; - strreplace(s, '!', '/'); - return *tmp = s; -} - -/** - * device_for_each_child - device child iterator. - * @parent: parent struct device. - * @fn: function to be called for each device. - * @data: data for the callback. - * - * Iterate over @parent's child devices, and call @fn for each, - * passing it @data. - * - * We check the return of @fn each time. If it returns anything - * other than 0, we break out and return that value. - */ -int device_for_each_child(struct device *parent, void *data, - int (*fn)(struct device *dev, void *data)) -{ - struct klist_iter i; - struct device *child; - int error = 0; - - if (!parent->p) - return 0; - - klist_iter_init(&parent->p->klist_children, &i); - while ((child = next_device(&i)) && !error) - error = fn(child, data); - klist_iter_exit(&i); - return error; -} -EXPORT_SYMBOL_GPL(device_for_each_child); - -/** - * device_for_each_child_reverse - device child iterator in reversed order. - * @parent: parent struct device. - * @fn: function to be called for each device. - * @data: data for the callback. - * - * Iterate over @parent's child devices, and call @fn for each, - * passing it @data. - * - * We check the return of @fn each time. If it returns anything - * other than 0, we break out and return that value. - */ -int device_for_each_child_reverse(struct device *parent, void *data, - int (*fn)(struct device *dev, void *data)) -{ - struct klist_iter i; - struct device *child; - int error = 0; - - if (!parent->p) - return 0; - - klist_iter_init(&parent->p->klist_children, &i); - while ((child = prev_device(&i)) && !error) - error = fn(child, data); - klist_iter_exit(&i); - return error; -} -EXPORT_SYMBOL_GPL(device_for_each_child_reverse); - -/** - * device_find_child - device iterator for locating a particular device. - * @parent: parent struct device - * @match: Callback function to check device - * @data: Data to pass to match function - * - * This is similar to the device_for_each_child() function above, but it - * returns a reference to a device that is 'found' for later use, as - * determined by the @match callback. - * - * The callback should return 0 if the device doesn't match and non-zero - * if it does. If the callback returns non-zero and a reference to the - * current device can be obtained, this function will return to the caller - * and not iterate over any more devices. - * - * NOTE: you will need to drop the reference with put_device() after use. - */ -struct device *device_find_child(struct device *parent, void *data, - int (*match)(struct device *dev, void *data)) -{ - struct klist_iter i; - struct device *child; - - if (!parent) - return NULL; - - klist_iter_init(&parent->p->klist_children, &i); - while ((child = next_device(&i))) - if (match(child, data) && get_device(child)) - break; - klist_iter_exit(&i); - return child; -} -EXPORT_SYMBOL_GPL(device_find_child); - -int __init devices_init(void) -{ - devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL); - if (!devices_kset) - return -ENOMEM; - dev_kobj = kobject_create_and_add("dev", NULL); - if (!dev_kobj) - goto dev_kobj_err; - sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj); - if (!sysfs_dev_block_kobj) - goto block_kobj_err; - sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj); - if (!sysfs_dev_char_kobj) - goto char_kobj_err; - - return 0; - - char_kobj_err: - kobject_put(sysfs_dev_block_kobj); - block_kobj_err: - kobject_put(dev_kobj); - dev_kobj_err: - kset_unregister(devices_kset); - return -ENOMEM; -} - -static int device_check_offline(struct device *dev, void *not_used) -{ - int ret; - - ret = device_for_each_child(dev, NULL, device_check_offline); - if (ret) - return ret; - - return device_supports_offline(dev) && !dev->offline ? -EBUSY : 0; -} - -/** - * device_offline - Prepare the device for hot-removal. - * @dev: Device to be put offline. - * - * Execute the device bus type's .offline() callback, if present, to prepare - * the device for a subsequent hot-removal. If that succeeds, the device must - * not be used until either it is removed or its bus type's .online() callback - * is executed. - * - * Call under device_hotplug_lock. - */ -int device_offline(struct device *dev) -{ - int ret; - - if (dev->offline_disabled) - return -EPERM; - - ret = device_for_each_child(dev, NULL, device_check_offline); - if (ret) - return ret; - - device_lock(dev); - if (device_supports_offline(dev)) { - if (dev->offline) { - ret = 1; - } else { - ret = dev->bus->offline(dev); - if (!ret) { - kobject_uevent(&dev->kobj, KOBJ_OFFLINE); - dev->offline = true; - } - } - } - device_unlock(dev); - - return ret; -} - -/** - * device_online - Put the device back online after successful device_offline(). - * @dev: Device to be put back online. - * - * If device_offline() has been successfully executed for @dev, but the device - * has not been removed subsequently, execute its bus type's .online() callback - * to indicate that the device can be used again. - * - * Call under device_hotplug_lock. - */ -int device_online(struct device *dev) -{ - int ret = 0; - - device_lock(dev); - if (device_supports_offline(dev)) { - if (dev->offline) { - ret = dev->bus->online(dev); - if (!ret) { - kobject_uevent(&dev->kobj, KOBJ_ONLINE); - dev->offline = false; - } - } else { - ret = 1; - } - } - device_unlock(dev); - - return ret; -} - -struct root_device { - struct device dev; - struct module *owner; -}; - -static inline struct root_device *to_root_device(struct device *d) -{ - return container_of(d, struct root_device, dev); -} - -static void root_device_release(struct device *dev) -{ - kfree(to_root_device(dev)); -} - -/** - * __root_device_register - allocate and register a root device - * @name: root device name - * @owner: owner module of the root device, usually THIS_MODULE - * - * This function allocates a root device and registers it - * using device_register(). In order to free the returned - * device, use root_device_unregister(). - * - * Root devices are dummy devices which allow other devices - * to be grouped under /sys/devices. Use this function to - * allocate a root device and then use it as the parent of - * any device which should appear under /sys/devices/{name} - * - * The /sys/devices/{name} directory will also contain a - * 'module' symlink which points to the @owner directory - * in sysfs. - * - * Returns &struct device pointer on success, or ERR_PTR() on error. - * - * Note: You probably want to use root_device_register(). - */ -struct device *__root_device_register(const char *name, struct module *owner) -{ - struct root_device *root; - int err = -ENOMEM; - - root = kzalloc(sizeof(struct root_device), GFP_KERNEL); - if (!root) - return ERR_PTR(err); - - err = dev_set_name(&root->dev, "%s", name); - if (err) { - kfree(root); - return ERR_PTR(err); - } - - root->dev.release = root_device_release; - - err = device_register(&root->dev); - if (err) { - put_device(&root->dev); - return ERR_PTR(err); - } - -#ifdef CONFIG_MODULES /* gotta find a "cleaner" way to do this */ - if (owner) { - struct module_kobject *mk = &owner->mkobj; - - err = sysfs_create_link(&root->dev.kobj, &mk->kobj, "module"); - if (err) { - device_unregister(&root->dev); - return ERR_PTR(err); - } - root->owner = owner; - } -#endif - - return &root->dev; -} -EXPORT_SYMBOL_GPL(__root_device_register); - -/** - * root_device_unregister - unregister and free a root device - * @dev: device going away - * - * This function unregisters and cleans up a device that was created by - * root_device_register(). - */ -void root_device_unregister(struct device *dev) -{ - struct root_device *root = to_root_device(dev); - - if (root->owner) - sysfs_remove_link(&root->dev.kobj, "module"); - - device_unregister(dev); -} -EXPORT_SYMBOL_GPL(root_device_unregister); - - -static void device_create_release(struct device *dev) -{ - pr_debug("device: '%s': %s\n", dev_name(dev), __func__); - kfree(dev); -} - -static struct device * -device_create_groups_vargs(struct class *class, struct device *parent, - dev_t devt, void *drvdata, - const struct attribute_group **groups, - const char *fmt, va_list args) -{ - struct device *dev = NULL; - int retval = -ENODEV; - - if (class == NULL || IS_ERR(class)) - goto error; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - retval = -ENOMEM; - goto error; - } - - device_initialize(dev); - dev->devt = devt; - dev->class = class; - dev->parent = parent; - dev->groups = groups; - dev->release = device_create_release; - dev_set_drvdata(dev, drvdata); - - retval = kobject_set_name_vargs(&dev->kobj, fmt, args); - if (retval) - goto error; - - retval = device_add(dev); - if (retval) - goto error; - - return dev; - -error: - put_device(dev); - return ERR_PTR(retval); -} - -/** - * device_create_vargs - creates a device and registers it with sysfs - * @class: pointer to the struct class that this device should be registered to - * @parent: pointer to the parent struct device of this new device, if any - * @devt: the dev_t for the char device to be added - * @drvdata: the data to be added to the device for callbacks - * @fmt: string for the device's name - * @args: va_list for the device's name - * - * This function can be used by char device classes. A struct device - * will be created in sysfs, registered to the specified class. - * - * A "dev" file will be created, showing the dev_t for the device, if - * the dev_t is not 0,0. - * If a pointer to a parent struct device is passed in, the newly created - * struct device will be a child of that device in sysfs. - * The pointer to the struct device will be returned from the call. - * Any further sysfs files that might be required can be created using this - * pointer. - * - * Returns &struct device pointer on success, or ERR_PTR() on error. - * - * Note: the struct class passed to this function must have previously - * been created with a call to class_create(). - */ -struct device *device_create_vargs(struct class *class, struct device *parent, - dev_t devt, void *drvdata, const char *fmt, - va_list args) -{ - return device_create_groups_vargs(class, parent, devt, drvdata, NULL, - fmt, args); -} -EXPORT_SYMBOL_GPL(device_create_vargs); - -/** - * device_create - creates a device and registers it with sysfs - * @class: pointer to the struct class that this device should be registered to - * @parent: pointer to the parent struct device of this new device, if any - * @devt: the dev_t for the char device to be added - * @drvdata: the data to be added to the device for callbacks - * @fmt: string for the device's name - * - * This function can be used by char device classes. A struct device - * will be created in sysfs, registered to the specified class. - * - * A "dev" file will be created, showing the dev_t for the device, if - * the dev_t is not 0,0. - * If a pointer to a parent struct device is passed in, the newly created - * struct device will be a child of that device in sysfs. - * The pointer to the struct device will be returned from the call. - * Any further sysfs files that might be required can be created using this - * pointer. - * - * Returns &struct device pointer on success, or ERR_PTR() on error. - * - * Note: the struct class passed to this function must have previously - * been created with a call to class_create(). - */ -struct device *device_create(struct class *class, struct device *parent, - dev_t devt, void *drvdata, const char *fmt, ...) -{ - va_list vargs; - struct device *dev; - - va_start(vargs, fmt); - dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs); - va_end(vargs); - return dev; -} -EXPORT_SYMBOL_GPL(device_create); - -/** - * device_create_with_groups - creates a device and registers it with sysfs - * @class: pointer to the struct class that this device should be registered to - * @parent: pointer to the parent struct device of this new device, if any - * @devt: the dev_t for the char device to be added - * @drvdata: the data to be added to the device for callbacks - * @groups: NULL-terminated list of attribute groups to be created - * @fmt: string for the device's name - * - * This function can be used by char device classes. A struct device - * will be created in sysfs, registered to the specified class. - * Additional attributes specified in the groups parameter will also - * be created automatically. - * - * A "dev" file will be created, showing the dev_t for the device, if - * the dev_t is not 0,0. - * If a pointer to a parent struct device is passed in, the newly created - * struct device will be a child of that device in sysfs. - * The pointer to the struct device will be returned from the call. - * Any further sysfs files that might be required can be created using this - * pointer. - * - * Returns &struct device pointer on success, or ERR_PTR() on error. - * - * Note: the struct class passed to this function must have previously - * been created with a call to class_create(). - */ -struct device *device_create_with_groups(struct class *class, - struct device *parent, dev_t devt, - void *drvdata, - const struct attribute_group **groups, - const char *fmt, ...) -{ - va_list vargs; - struct device *dev; - - va_start(vargs, fmt); - dev = device_create_groups_vargs(class, parent, devt, drvdata, groups, - fmt, vargs); - va_end(vargs); - return dev; -} -EXPORT_SYMBOL_GPL(device_create_with_groups); - -static int __match_devt(struct device *dev, const void *data) -{ - const dev_t *devt = data; - - return dev->devt == *devt; -} - -/** - * device_destroy - removes a device that was created with device_create() - * @class: pointer to the struct class that this device was registered with - * @devt: the dev_t of the device that was previously registered - * - * This call unregisters and cleans up a device that was created with a - * call to device_create(). - */ -void device_destroy(struct class *class, dev_t devt) -{ - struct device *dev; - - dev = class_find_device(class, NULL, &devt, __match_devt); - if (dev) { - put_device(dev); - device_unregister(dev); - } -} -EXPORT_SYMBOL_GPL(device_destroy); - -/** - * device_rename - renames a device - * @dev: the pointer to the struct device to be renamed - * @new_name: the new name of the device - * - * It is the responsibility of the caller to provide mutual - * exclusion between two different calls of device_rename - * on the same device to ensure that new_name is valid and - * won't conflict with other devices. - * - * Note: Don't call this function. Currently, the networking layer calls this - * function, but that will change. The following text from Kay Sievers offers - * some insight: - * - * Renaming devices is racy at many levels, symlinks and other stuff are not - * replaced atomically, and you get a "move" uevent, but it's not easy to - * connect the event to the old and new device. Device nodes are not renamed at - * all, there isn't even support for that in the kernel now. - * - * In the meantime, during renaming, your target name might be taken by another - * driver, creating conflicts. Or the old name is taken directly after you - * renamed it -- then you get events for the same DEVPATH, before you even see - * the "move" event. It's just a mess, and nothing new should ever rely on - * kernel device renaming. Besides that, it's not even implemented now for - * other things than (driver-core wise very simple) network devices. - * - * We are currently about to change network renaming in udev to completely - * disallow renaming of devices in the same namespace as the kernel uses, - * because we can't solve the problems properly, that arise with swapping names - * of multiple interfaces without races. Means, renaming of eth[0-9]* will only - * be allowed to some other name than eth[0-9]*, for the aforementioned - * reasons. - * - * Make up a "real" name in the driver before you register anything, or add - * some other attributes for userspace to find the device, or use udev to add - * symlinks -- but never rename kernel devices later, it's a complete mess. We - * don't even want to get into that and try to implement the missing pieces in - * the core. We really have other pieces to fix in the driver core mess. :) - */ -int device_rename(struct device *dev, const char *new_name) -{ - struct kobject *kobj = &dev->kobj; - char *old_device_name = NULL; - int error; - - dev = get_device(dev); - if (!dev) - return -EINVAL; - - dev_dbg(dev, "renaming to %s\n", new_name); - - old_device_name = kstrdup(dev_name(dev), GFP_KERNEL); - if (!old_device_name) { - error = -ENOMEM; - goto out; - } - - if (dev->class) { - error = sysfs_rename_link_ns(&dev->class->p->subsys.kobj, - kobj, old_device_name, - new_name, kobject_namespace(kobj)); - if (error) - goto out; - } - - error = kobject_rename(kobj, new_name); - if (error) - goto out; - -out: - put_device(dev); - - kfree(old_device_name); - - return error; -} -EXPORT_SYMBOL_GPL(device_rename); - -static int device_move_class_links(struct device *dev, - struct device *old_parent, - struct device *new_parent) -{ - int error = 0; - - if (old_parent) - sysfs_remove_link(&dev->kobj, "device"); - if (new_parent) - error = sysfs_create_link(&dev->kobj, &new_parent->kobj, - "device"); - return error; -} - -/** - * device_move - moves a device to a new parent - * @dev: the pointer to the struct device to be moved - * @new_parent: the new parent of the device (can by NULL) - * @dpm_order: how to reorder the dpm_list - */ -int device_move(struct device *dev, struct device *new_parent, - enum dpm_order dpm_order) -{ - int error; - struct device *old_parent; - struct kobject *new_parent_kobj; - - dev = get_device(dev); - if (!dev) - return -EINVAL; - - device_pm_lock(); - new_parent = get_device(new_parent); - new_parent_kobj = get_device_parent(dev, new_parent); - - pr_debug("device: '%s': %s: moving to '%s'\n", dev_name(dev), - __func__, new_parent ? dev_name(new_parent) : ""); - error = kobject_move(&dev->kobj, new_parent_kobj); - if (error) { - cleanup_glue_dir(dev, new_parent_kobj); - put_device(new_parent); - goto out; - } - old_parent = dev->parent; - dev->parent = new_parent; - if (old_parent) - klist_remove(&dev->p->knode_parent); - if (new_parent) { - klist_add_tail(&dev->p->knode_parent, - &new_parent->p->klist_children); - set_dev_node(dev, dev_to_node(new_parent)); - } - - if (dev->class) { - error = device_move_class_links(dev, old_parent, new_parent); - if (error) { - /* We ignore errors on cleanup since we're hosed anyway... */ - device_move_class_links(dev, new_parent, old_parent); - if (!kobject_move(&dev->kobj, &old_parent->kobj)) { - if (new_parent) - klist_remove(&dev->p->knode_parent); - dev->parent = old_parent; - if (old_parent) { - klist_add_tail(&dev->p->knode_parent, - &old_parent->p->klist_children); - set_dev_node(dev, dev_to_node(old_parent)); - } - } - cleanup_glue_dir(dev, new_parent_kobj); - put_device(new_parent); - goto out; - } - } - switch (dpm_order) { - case DPM_ORDER_NONE: - break; - case DPM_ORDER_DEV_AFTER_PARENT: - device_pm_move_after(dev, new_parent); - devices_kset_move_after(dev, new_parent); - break; - case DPM_ORDER_PARENT_BEFORE_DEV: - device_pm_move_before(new_parent, dev); - devices_kset_move_before(new_parent, dev); - break; - case DPM_ORDER_DEV_LAST: - device_pm_move_last(dev); - devices_kset_move_last(dev); - break; - } - - put_device(old_parent); -out: - device_pm_unlock(); - put_device(dev); - return error; -} -EXPORT_SYMBOL_GPL(device_move); - -/** - * device_shutdown - call ->shutdown() on each device to shutdown. - */ -void device_shutdown(void) -{ - struct device *dev, *parent; - - spin_lock(&devices_kset->list_lock); - /* - * Walk the devices list backward, shutting down each in turn. - * Beware that device unplug events may also start pulling - * devices offline, even as the system is shutting down. - */ - while (!list_empty(&devices_kset->list)) { - dev = list_entry(devices_kset->list.prev, struct device, - kobj.entry); - - /* - * hold reference count of device's parent to - * prevent it from being freed because parent's - * lock is to be held - */ - parent = get_device(dev->parent); - get_device(dev); - /* - * Make sure the device is off the kset list, in the - * event that dev->*->shutdown() doesn't remove it. - */ - list_del_init(&dev->kobj.entry); - spin_unlock(&devices_kset->list_lock); - - /* hold lock to avoid race with probe/release */ - if (parent) - device_lock(parent); - device_lock(dev); - - /* Don't allow any more runtime suspends */ - pm_runtime_get_noresume(dev); - pm_runtime_barrier(dev); - - if (dev->bus && dev->bus->shutdown) { - if (initcall_debug) - dev_info(dev, "shutdown\n"); - dev->bus->shutdown(dev); - } else if (dev->driver && dev->driver->shutdown) { - if (initcall_debug) - dev_info(dev, "shutdown\n"); - dev->driver->shutdown(dev); - } - - device_unlock(dev); - if (parent) - device_unlock(parent); - - put_device(dev); - put_device(parent); - - spin_lock(&devices_kset->list_lock); - } - spin_unlock(&devices_kset->list_lock); -} - -/* - * Device logging functions - */ - -#ifdef CONFIG_PRINTK -static int -create_syslog_header(const struct device *dev, char *hdr, size_t hdrlen) -{ - const char *subsys; - size_t pos = 0; - - if (dev->class) - subsys = dev->class->name; - else if (dev->bus) - subsys = dev->bus->name; - else - return 0; - - pos += snprintf(hdr + pos, hdrlen - pos, "SUBSYSTEM=%s", subsys); - if (pos >= hdrlen) - goto overflow; - - /* - * Add device identifier DEVICE=: - * b12:8 block dev_t - * c127:3 char dev_t - * n8 netdev ifindex - * +sound:card0 subsystem:devname - */ - if (MAJOR(dev->devt)) { - char c; - - if (strcmp(subsys, "block") == 0) - c = 'b'; - else - c = 'c'; - pos++; - pos += snprintf(hdr + pos, hdrlen - pos, - "DEVICE=%c%u:%u", - c, MAJOR(dev->devt), MINOR(dev->devt)); - } else if (strcmp(subsys, "net") == 0) { - struct net_device *net = to_net_dev(dev); - - pos++; - pos += snprintf(hdr + pos, hdrlen - pos, - "DEVICE=n%u", net->ifindex); - } else { - pos++; - pos += snprintf(hdr + pos, hdrlen - pos, - "DEVICE=+%s:%s", subsys, dev_name(dev)); - } - - if (pos >= hdrlen) - goto overflow; - - return pos; - -overflow: - dev_WARN(dev, "device/subsystem name too long"); - return 0; -} - -int dev_vprintk_emit(int level, const struct device *dev, - const char *fmt, va_list args) -{ - char hdr[128]; - size_t hdrlen; - - hdrlen = create_syslog_header(dev, hdr, sizeof(hdr)); - - return vprintk_emit(0, level, hdrlen ? hdr : NULL, hdrlen, fmt, args); -} -EXPORT_SYMBOL(dev_vprintk_emit); - -int dev_printk_emit(int level, const struct device *dev, const char *fmt, ...) -{ - va_list args; - int r; - - va_start(args, fmt); - - r = dev_vprintk_emit(level, dev, fmt, args); - - va_end(args); - - return r; -} -EXPORT_SYMBOL(dev_printk_emit); - -static void __dev_printk(const char *level, const struct device *dev, - struct va_format *vaf) -{ - if (dev) - dev_printk_emit(level[1] - '0', dev, "%s %s: %pV", - dev_driver_string(dev), dev_name(dev), vaf); - else - printk("%s(NULL device *): %pV", level, vaf); -} - -void dev_printk(const char *level, const struct device *dev, - const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - __dev_printk(level, dev, &vaf); - - va_end(args); -} -EXPORT_SYMBOL(dev_printk); - -#define define_dev_printk_level(func, kern_level) \ -void func(const struct device *dev, const char *fmt, ...) \ -{ \ - struct va_format vaf; \ - va_list args; \ - \ - va_start(args, fmt); \ - \ - vaf.fmt = fmt; \ - vaf.va = &args; \ - \ - __dev_printk(kern_level, dev, &vaf); \ - \ - va_end(args); \ -} \ -EXPORT_SYMBOL(func); - -define_dev_printk_level(dev_emerg, KERN_EMERG); -define_dev_printk_level(dev_alert, KERN_ALERT); -define_dev_printk_level(dev_crit, KERN_CRIT); -define_dev_printk_level(dev_err, KERN_ERR); -define_dev_printk_level(dev_warn, KERN_WARNING); -define_dev_printk_level(dev_notice, KERN_NOTICE); -define_dev_printk_level(_dev_info, KERN_INFO); - -#endif - -static inline bool fwnode_is_primary(struct fwnode_handle *fwnode) -{ - return fwnode && !IS_ERR(fwnode->secondary); -} - -/** - * set_primary_fwnode - Change the primary firmware node of a given device. - * @dev: Device to handle. - * @fwnode: New primary firmware node of the device. - * - * Set the device's firmware node pointer to @fwnode, but if a secondary - * firmware node of the device is present, preserve it. - */ -void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode) -{ - if (fwnode) { - struct fwnode_handle *fn = dev->fwnode; - - if (fwnode_is_primary(fn)) - fn = fn->secondary; - - if (fn) { - WARN_ON(fwnode->secondary); - fwnode->secondary = fn; - } - dev->fwnode = fwnode; - } else { - dev->fwnode = fwnode_is_primary(dev->fwnode) ? - dev->fwnode->secondary : NULL; - } -} -EXPORT_SYMBOL_GPL(set_primary_fwnode); - -/** - * set_secondary_fwnode - Change the secondary firmware node of a given device. - * @dev: Device to handle. - * @fwnode: New secondary firmware node of the device. - * - * If a primary firmware node of the device is present, set its secondary - * pointer to @fwnode. Otherwise, set the device's firmware node pointer to - * @fwnode. - */ -void set_secondary_fwnode(struct device *dev, struct fwnode_handle *fwnode) -{ - if (fwnode) - fwnode->secondary = ERR_PTR(-ENODEV); - - if (fwnode_is_primary(dev->fwnode)) - dev->fwnode->secondary = fwnode; - else - dev->fwnode = fwnode; -} diff --git a/src/linux/drivers/base/cpu.c b/src/linux/drivers/base/cpu.c deleted file mode 100644 index 4c28e1a..0000000 --- a/src/linux/drivers/base/cpu.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - * CPU subsystem support - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "base.h" - -static DEFINE_PER_CPU(struct device *, cpu_sys_devices); - -static int cpu_subsys_match(struct device *dev, struct device_driver *drv) -{ - /* ACPI style match is the only one that may succeed. */ - if (acpi_driver_match_device(dev, drv)) - return 1; - - return 0; -} - -#ifdef CONFIG_HOTPLUG_CPU -static void change_cpu_under_node(struct cpu *cpu, - unsigned int from_nid, unsigned int to_nid) -{ - int cpuid = cpu->dev.id; - unregister_cpu_under_node(cpuid, from_nid); - register_cpu_under_node(cpuid, to_nid); - cpu->node_id = to_nid; -} - -static int cpu_subsys_online(struct device *dev) -{ - struct cpu *cpu = container_of(dev, struct cpu, dev); - int cpuid = dev->id; - int from_nid, to_nid; - int ret; - - from_nid = cpu_to_node(cpuid); - if (from_nid == NUMA_NO_NODE) - return -ENODEV; - - ret = cpu_up(cpuid); - /* - * When hot adding memory to memoryless node and enabling a cpu - * on the node, node number of the cpu may internally change. - */ - to_nid = cpu_to_node(cpuid); - if (from_nid != to_nid) - change_cpu_under_node(cpu, from_nid, to_nid); - - return ret; -} - -static int cpu_subsys_offline(struct device *dev) -{ - return cpu_down(dev->id); -} - -void unregister_cpu(struct cpu *cpu) -{ - int logical_cpu = cpu->dev.id; - - unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu)); - - device_unregister(&cpu->dev); - per_cpu(cpu_sys_devices, logical_cpu) = NULL; - return; -} - -#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE -static ssize_t cpu_probe_store(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) -{ - ssize_t cnt; - int ret; - - ret = lock_device_hotplug_sysfs(); - if (ret) - return ret; - - cnt = arch_cpu_probe(buf, count); - - unlock_device_hotplug(); - return cnt; -} - -static ssize_t cpu_release_store(struct device *dev, - struct device_attribute *attr, - const char *buf, - size_t count) -{ - ssize_t cnt; - int ret; - - ret = lock_device_hotplug_sysfs(); - if (ret) - return ret; - - cnt = arch_cpu_release(buf, count); - - unlock_device_hotplug(); - return cnt; -} - -static DEVICE_ATTR(probe, S_IWUSR, NULL, cpu_probe_store); -static DEVICE_ATTR(release, S_IWUSR, NULL, cpu_release_store); -#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ -#endif /* CONFIG_HOTPLUG_CPU */ - -struct bus_type cpu_subsys = { - .name = "cpu", - .dev_name = "cpu", - .match = cpu_subsys_match, -#ifdef CONFIG_HOTPLUG_CPU - .online = cpu_subsys_online, - .offline = cpu_subsys_offline, -#endif -}; -EXPORT_SYMBOL_GPL(cpu_subsys); - -#ifdef CONFIG_KEXEC -#include - -static ssize_t show_crash_notes(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct cpu *cpu = container_of(dev, struct cpu, dev); - ssize_t rc; - unsigned long long addr; - int cpunum; - - cpunum = cpu->dev.id; - - /* - * Might be reading other cpu's data based on which cpu read thread - * has been scheduled. But cpu data (memory) is allocated once during - * boot up and this data does not change there after. Hence this - * operation should be safe. No locking required. - */ - addr = per_cpu_ptr_to_phys(per_cpu_ptr(crash_notes, cpunum)); - rc = sprintf(buf, "%Lx\n", addr); - return rc; -} -static DEVICE_ATTR(crash_notes, 0400, show_crash_notes, NULL); - -static ssize_t show_crash_notes_size(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - ssize_t rc; - - rc = sprintf(buf, "%zu\n", sizeof(note_buf_t)); - return rc; -} -static DEVICE_ATTR(crash_notes_size, 0400, show_crash_notes_size, NULL); - -static struct attribute *crash_note_cpu_attrs[] = { - &dev_attr_crash_notes.attr, - &dev_attr_crash_notes_size.attr, - NULL -}; - -static struct attribute_group crash_note_cpu_attr_group = { - .attrs = crash_note_cpu_attrs, -}; -#endif - -static const struct attribute_group *common_cpu_attr_groups[] = { -#ifdef CONFIG_KEXEC - &crash_note_cpu_attr_group, -#endif - NULL -}; - -static const struct attribute_group *hotplugable_cpu_attr_groups[] = { -#ifdef CONFIG_KEXEC - &crash_note_cpu_attr_group, -#endif - NULL -}; - -/* - * Print cpu online, possible, present, and system maps - */ - -struct cpu_attr { - struct device_attribute attr; - const struct cpumask *const map; -}; - -static ssize_t show_cpus_attr(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct cpu_attr *ca = container_of(attr, struct cpu_attr, attr); - - return cpumap_print_to_pagebuf(true, buf, ca->map); -} - -#define _CPU_ATTR(name, map) \ - { __ATTR(name, 0444, show_cpus_attr, NULL), map } - -/* Keep in sync with cpu_subsys_attrs */ -static struct cpu_attr cpu_attrs[] = { - _CPU_ATTR(online, &__cpu_online_mask), - _CPU_ATTR(possible, &__cpu_possible_mask), - _CPU_ATTR(present, &__cpu_present_mask), -}; - -/* - * Print values for NR_CPUS and offlined cpus - */ -static ssize_t print_cpus_kernel_max(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int n = snprintf(buf, PAGE_SIZE-2, "%d\n", NR_CPUS - 1); - return n; -} -static DEVICE_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL); - -/* arch-optional setting to enable display of offline cpus >= nr_cpu_ids */ -unsigned int total_cpus; - -static ssize_t print_cpus_offline(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int n = 0, len = PAGE_SIZE-2; - cpumask_var_t offline; - - /* display offline cpus < nr_cpu_ids */ - if (!alloc_cpumask_var(&offline, GFP_KERNEL)) - return -ENOMEM; - cpumask_andnot(offline, cpu_possible_mask, cpu_online_mask); - n = scnprintf(buf, len, "%*pbl", cpumask_pr_args(offline)); - free_cpumask_var(offline); - - /* display offline cpus >= nr_cpu_ids */ - if (total_cpus && nr_cpu_ids < total_cpus) { - if (n && n < len) - buf[n++] = ','; - - if (nr_cpu_ids == total_cpus-1) - n += snprintf(&buf[n], len - n, "%d", nr_cpu_ids); - else - n += snprintf(&buf[n], len - n, "%d-%d", - nr_cpu_ids, total_cpus-1); - } - - n += snprintf(&buf[n], len - n, "\n"); - return n; -} -static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL); - -static ssize_t print_cpus_isolated(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int n = 0, len = PAGE_SIZE-2; - - n = scnprintf(buf, len, "%*pbl\n", cpumask_pr_args(cpu_isolated_map)); - - return n; -} -static DEVICE_ATTR(isolated, 0444, print_cpus_isolated, NULL); - -#ifdef CONFIG_NO_HZ_FULL -static ssize_t print_cpus_nohz_full(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int n = 0, len = PAGE_SIZE-2; - - n = scnprintf(buf, len, "%*pbl\n", cpumask_pr_args(tick_nohz_full_mask)); - - return n; -} -static DEVICE_ATTR(nohz_full, 0444, print_cpus_nohz_full, NULL); -#endif - -static void cpu_device_release(struct device *dev) -{ - /* - * This is an empty function to prevent the driver core from spitting a - * warning at us. Yes, I know this is directly opposite of what the - * documentation for the driver core and kobjects say, and the author - * of this code has already been publically ridiculed for doing - * something as foolish as this. However, at this point in time, it is - * the only way to handle the issue of statically allocated cpu - * devices. The different architectures will have their cpu device - * code reworked to properly handle this in the near future, so this - * function will then be changed to correctly free up the memory held - * by the cpu device. - * - * Never copy this way of doing things, or you too will be made fun of - * on the linux-kernel list, you have been warned. - */ -} - -#ifdef CONFIG_GENERIC_CPU_AUTOPROBE -static ssize_t print_cpu_modalias(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - ssize_t n; - u32 i; - - n = sprintf(buf, "cpu:type:" CPU_FEATURE_TYPEFMT ":feature:", - CPU_FEATURE_TYPEVAL); - - for (i = 0; i < MAX_CPU_FEATURES; i++) - if (cpu_have_feature(i)) { - if (PAGE_SIZE < n + sizeof(",XXXX\n")) { - WARN(1, "CPU features overflow page\n"); - break; - } - n += sprintf(&buf[n], ",%04X", i); - } - buf[n++] = '\n'; - return n; -} - -static int cpu_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (buf) { - print_cpu_modalias(NULL, NULL, buf); - add_uevent_var(env, "MODALIAS=%s", buf); - kfree(buf); - } - return 0; -} -#endif - -/* - * register_cpu - Setup a sysfs device for a CPU. - * @cpu - cpu->hotpluggable field set to 1 will generate a control file in - * sysfs for this CPU. - * @num - CPU number to use when creating the device. - * - * Initialize and register the CPU device. - */ -int register_cpu(struct cpu *cpu, int num) -{ - int error; - - cpu->node_id = cpu_to_node(num); - memset(&cpu->dev, 0x00, sizeof(struct device)); - cpu->dev.id = num; - cpu->dev.bus = &cpu_subsys; - cpu->dev.release = cpu_device_release; - cpu->dev.offline_disabled = !cpu->hotpluggable; - cpu->dev.offline = !cpu_online(num); - cpu->dev.of_node = of_get_cpu_node(num, NULL); -#ifdef CONFIG_GENERIC_CPU_AUTOPROBE - cpu->dev.bus->uevent = cpu_uevent; -#endif - cpu->dev.groups = common_cpu_attr_groups; - if (cpu->hotpluggable) - cpu->dev.groups = hotplugable_cpu_attr_groups; - error = device_register(&cpu->dev); - if (error) - return error; - - per_cpu(cpu_sys_devices, num) = &cpu->dev; - register_cpu_under_node(num, cpu_to_node(num)); - - return 0; -} - -struct device *get_cpu_device(unsigned cpu) -{ - if (cpu < nr_cpu_ids && cpu_possible(cpu)) - return per_cpu(cpu_sys_devices, cpu); - else - return NULL; -} -EXPORT_SYMBOL_GPL(get_cpu_device); - -static void device_create_release(struct device *dev) -{ - kfree(dev); -} - -static struct device * -__cpu_device_create(struct device *parent, void *drvdata, - const struct attribute_group **groups, - const char *fmt, va_list args) -{ - struct device *dev = NULL; - int retval = -ENODEV; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - retval = -ENOMEM; - goto error; - } - - device_initialize(dev); - dev->parent = parent; - dev->groups = groups; - dev->release = device_create_release; - dev_set_drvdata(dev, drvdata); - - retval = kobject_set_name_vargs(&dev->kobj, fmt, args); - if (retval) - goto error; - - retval = device_add(dev); - if (retval) - goto error; - - return dev; - -error: - put_device(dev); - return ERR_PTR(retval); -} - -struct device *cpu_device_create(struct device *parent, void *drvdata, - const struct attribute_group **groups, - const char *fmt, ...) -{ - va_list vargs; - struct device *dev; - - va_start(vargs, fmt); - dev = __cpu_device_create(parent, drvdata, groups, fmt, vargs); - va_end(vargs); - return dev; -} -EXPORT_SYMBOL_GPL(cpu_device_create); - -#ifdef CONFIG_GENERIC_CPU_AUTOPROBE -static DEVICE_ATTR(modalias, 0444, print_cpu_modalias, NULL); -#endif - -static struct attribute *cpu_root_attrs[] = { -#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE - &dev_attr_probe.attr, - &dev_attr_release.attr, -#endif - &cpu_attrs[0].attr.attr, - &cpu_attrs[1].attr.attr, - &cpu_attrs[2].attr.attr, - &dev_attr_kernel_max.attr, - &dev_attr_offline.attr, - &dev_attr_isolated.attr, -#ifdef CONFIG_NO_HZ_FULL - &dev_attr_nohz_full.attr, -#endif -#ifdef CONFIG_GENERIC_CPU_AUTOPROBE - &dev_attr_modalias.attr, -#endif - NULL -}; - -static struct attribute_group cpu_root_attr_group = { - .attrs = cpu_root_attrs, -}; - -static const struct attribute_group *cpu_root_attr_groups[] = { - &cpu_root_attr_group, - NULL, -}; - -bool cpu_is_hotpluggable(unsigned cpu) -{ - struct device *dev = get_cpu_device(cpu); - return dev && container_of(dev, struct cpu, dev)->hotpluggable; -} -EXPORT_SYMBOL_GPL(cpu_is_hotpluggable); - -#ifdef CONFIG_GENERIC_CPU_DEVICES -static DEFINE_PER_CPU(struct cpu, cpu_devices); -#endif - -static void __init cpu_dev_register_generic(void) -{ -#ifdef CONFIG_GENERIC_CPU_DEVICES - int i; - - for_each_possible_cpu(i) { - if (register_cpu(&per_cpu(cpu_devices, i), i)) - panic("Failed to register CPU device"); - } -#endif -} - -void __init cpu_dev_init(void) -{ - if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups)) - panic("Failed to register CPU subsystem"); - - cpu_dev_register_generic(); -} diff --git a/src/linux/drivers/base/dd.c b/src/linux/drivers/base/dd.c deleted file mode 100644 index d76cd97..0000000 --- a/src/linux/drivers/base/dd.c +++ /dev/null @@ -1,867 +0,0 @@ -/* - * drivers/base/dd.c - The core device/driver interactions. - * - * This file contains the (sometimes tricky) code that controls the - * interactions between devices and drivers, which primarily includes - * driver binding and unbinding. - * - * All of this code used to exist in drivers/base/bus.c, but was - * relocated to here in the name of compartmentalization (since it wasn't - * strictly code just for the 'struct bus_type'. - * - * Copyright (c) 2002-5 Patrick Mochel - * Copyright (c) 2002-3 Open Source Development Labs - * Copyright (c) 2007-2009 Greg Kroah-Hartman - * Copyright (c) 2007-2009 Novell Inc. - * - * This file is released under the GPLv2 - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "base.h" -#include "power/power.h" - -/* - * Deferred Probe infrastructure. - * - * Sometimes driver probe order matters, but the kernel doesn't always have - * dependency information which means some drivers will get probed before a - * resource it depends on is available. For example, an SDHCI driver may - * first need a GPIO line from an i2c GPIO controller before it can be - * initialized. If a required resource is not available yet, a driver can - * request probing to be deferred by returning -EPROBE_DEFER from its probe hook - * - * Deferred probe maintains two lists of devices, a pending list and an active - * list. A driver returning -EPROBE_DEFER causes the device to be added to the - * pending list. A successful driver probe will trigger moving all devices - * from the pending to the active list so that the workqueue will eventually - * retry them. - * - * The deferred_probe_mutex must be held any time the deferred_probe_*_list - * of the (struct device*)->p->deferred_probe pointers are manipulated - */ -static DEFINE_MUTEX(deferred_probe_mutex); -static LIST_HEAD(deferred_probe_pending_list); -static LIST_HEAD(deferred_probe_active_list); -static atomic_t deferred_trigger_count = ATOMIC_INIT(0); - -/* - * In some cases, like suspend to RAM or hibernation, It might be reasonable - * to prohibit probing of devices as it could be unsafe. - * Once defer_all_probes is true all drivers probes will be forcibly deferred. - */ -static bool defer_all_probes; - -/* - * deferred_probe_work_func() - Retry probing devices in the active list. - */ -static void deferred_probe_work_func(struct work_struct *work) -{ - struct device *dev; - struct device_private *private; - /* - * This block processes every device in the deferred 'active' list. - * Each device is removed from the active list and passed to - * bus_probe_device() to re-attempt the probe. The loop continues - * until every device in the active list is removed and retried. - * - * Note: Once the device is removed from the list and the mutex is - * released, it is possible for the device get freed by another thread - * and cause a illegal pointer dereference. This code uses - * get/put_device() to ensure the device structure cannot disappear - * from under our feet. - */ - mutex_lock(&deferred_probe_mutex); - while (!list_empty(&deferred_probe_active_list)) { - private = list_first_entry(&deferred_probe_active_list, - typeof(*dev->p), deferred_probe); - dev = private->device; - list_del_init(&private->deferred_probe); - - get_device(dev); - - /* - * Drop the mutex while probing each device; the probe path may - * manipulate the deferred list - */ - mutex_unlock(&deferred_probe_mutex); - - /* - * Force the device to the end of the dpm_list since - * the PM code assumes that the order we add things to - * the list is a good order for suspend but deferred - * probe makes that very unsafe. - */ - device_pm_lock(); - device_pm_move_last(dev); - device_pm_unlock(); - - dev_dbg(dev, "Retrying from deferred list\n"); - bus_probe_device(dev); - - mutex_lock(&deferred_probe_mutex); - - put_device(dev); - } - mutex_unlock(&deferred_probe_mutex); -} -static DECLARE_WORK(deferred_probe_work, deferred_probe_work_func); - -static void driver_deferred_probe_add(struct device *dev) -{ - mutex_lock(&deferred_probe_mutex); - if (list_empty(&dev->p->deferred_probe)) { - dev_dbg(dev, "Added to deferred list\n"); - list_add_tail(&dev->p->deferred_probe, &deferred_probe_pending_list); - } - mutex_unlock(&deferred_probe_mutex); -} - -void driver_deferred_probe_del(struct device *dev) -{ - mutex_lock(&deferred_probe_mutex); - if (!list_empty(&dev->p->deferred_probe)) { - dev_dbg(dev, "Removed from deferred list\n"); - list_del_init(&dev->p->deferred_probe); - } - mutex_unlock(&deferred_probe_mutex); -} - -static bool driver_deferred_probe_enable = false; -/** - * driver_deferred_probe_trigger() - Kick off re-probing deferred devices - * - * This functions moves all devices from the pending list to the active - * list and schedules the deferred probe workqueue to process them. It - * should be called anytime a driver is successfully bound to a device. - * - * Note, there is a race condition in multi-threaded probe. In the case where - * more than one device is probing at the same time, it is possible for one - * probe to complete successfully while another is about to defer. If the second - * depends on the first, then it will get put on the pending list after the - * trigger event has already occurred and will be stuck there. - * - * The atomic 'deferred_trigger_count' is used to determine if a successful - * trigger has occurred in the midst of probing a driver. If the trigger count - * changes in the midst of a probe, then deferred processing should be triggered - * again. - */ -static void driver_deferred_probe_trigger(void) -{ - if (!driver_deferred_probe_enable) - return; - - /* - * A successful probe means that all the devices in the pending list - * should be triggered to be reprobed. Move all the deferred devices - * into the active list so they can be retried by the workqueue - */ - mutex_lock(&deferred_probe_mutex); - atomic_inc(&deferred_trigger_count); - list_splice_tail_init(&deferred_probe_pending_list, - &deferred_probe_active_list); - mutex_unlock(&deferred_probe_mutex); - - /* - * Kick the re-probe thread. It may already be scheduled, but it is - * safe to kick it again. - */ - schedule_work(&deferred_probe_work); -} - -/** - * device_block_probing() - Block/defere device's probes - * - * It will disable probing of devices and defer their probes instead. - */ -void device_block_probing(void) -{ - defer_all_probes = true; - /* sync with probes to avoid races. */ - wait_for_device_probe(); -} - -/** - * device_unblock_probing() - Unblock/enable device's probes - * - * It will restore normal behavior and trigger re-probing of deferred - * devices. - */ -void device_unblock_probing(void) -{ - defer_all_probes = false; - driver_deferred_probe_trigger(); -} - -/** - * deferred_probe_initcall() - Enable probing of deferred devices - * - * We don't want to get in the way when the bulk of drivers are getting probed. - * Instead, this initcall makes sure that deferred probing is delayed until - * late_initcall time. - */ -static int deferred_probe_initcall(void) -{ - driver_deferred_probe_enable = true; - driver_deferred_probe_trigger(); - /* Sort as many dependencies as possible before exiting initcalls */ - flush_work(&deferred_probe_work); - return 0; -} -late_initcall(deferred_probe_initcall); - -/** - * device_is_bound() - Check if device is bound to a driver - * @dev: device to check - * - * Returns true if passed device has already finished probing successfully - * against a driver. - * - * This function must be called with the device lock held. - */ -bool device_is_bound(struct device *dev) -{ - return dev->p && klist_node_attached(&dev->p->knode_driver); -} - -static void driver_bound(struct device *dev) -{ - if (device_is_bound(dev)) { - printk(KERN_WARNING "%s: device %s already bound\n", - __func__, kobject_name(&dev->kobj)); - return; - } - - pr_debug("driver: '%s': %s: bound to device '%s'\n", dev->driver->name, - __func__, dev_name(dev)); - - klist_add_tail(&dev->p->knode_driver, &dev->driver->p->klist_devices); - - device_pm_check_callbacks(dev); - - /* - * Make sure the device is no longer in one of the deferred lists and - * kick off retrying all pending devices - */ - driver_deferred_probe_del(dev); - driver_deferred_probe_trigger(); - - if (dev->bus) - blocking_notifier_call_chain(&dev->bus->p->bus_notifier, - BUS_NOTIFY_BOUND_DRIVER, dev); -} - -static int driver_sysfs_add(struct device *dev) -{ - int ret; - - if (dev->bus) - blocking_notifier_call_chain(&dev->bus->p->bus_notifier, - BUS_NOTIFY_BIND_DRIVER, dev); - - ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj, - kobject_name(&dev->kobj)); - if (ret == 0) { - ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj, - "driver"); - if (ret) - sysfs_remove_link(&dev->driver->p->kobj, - kobject_name(&dev->kobj)); - } - return ret; -} - -static void driver_sysfs_remove(struct device *dev) -{ - struct device_driver *drv = dev->driver; - - if (drv) { - sysfs_remove_link(&drv->p->kobj, kobject_name(&dev->kobj)); - sysfs_remove_link(&dev->kobj, "driver"); - } -} - -/** - * device_bind_driver - bind a driver to one device. - * @dev: device. - * - * Allow manual attachment of a driver to a device. - * Caller must have already set @dev->driver. - * - * Note that this does not modify the bus reference count - * nor take the bus's rwsem. Please verify those are accounted - * for before calling this. (It is ok to call with no other effort - * from a driver's probe() method.) - * - * This function must be called with the device lock held. - */ -int device_bind_driver(struct device *dev) -{ - int ret; - - ret = driver_sysfs_add(dev); - if (!ret) - driver_bound(dev); - else if (dev->bus) - blocking_notifier_call_chain(&dev->bus->p->bus_notifier, - BUS_NOTIFY_DRIVER_NOT_BOUND, dev); - return ret; -} -EXPORT_SYMBOL_GPL(device_bind_driver); - -static atomic_t probe_count = ATOMIC_INIT(0); -static DECLARE_WAIT_QUEUE_HEAD(probe_waitqueue); - -static int really_probe(struct device *dev, struct device_driver *drv) -{ - int ret = -EPROBE_DEFER; - int local_trigger_count = atomic_read(&deferred_trigger_count); - bool test_remove = IS_ENABLED(CONFIG_DEBUG_TEST_DRIVER_REMOVE) && - !drv->suppress_bind_attrs; - - if (defer_all_probes) { - /* - * Value of defer_all_probes can be set only by - * device_defer_all_probes_enable() which, in turn, will call - * wait_for_device_probe() right after that to avoid any races. - */ - dev_dbg(dev, "Driver %s force probe deferral\n", drv->name); - driver_deferred_probe_add(dev); - return ret; - } - - atomic_inc(&probe_count); - pr_debug("bus: '%s': %s: probing driver %s with device %s\n", - drv->bus->name, __func__, drv->name, dev_name(dev)); - WARN_ON(!list_empty(&dev->devres_head)); - -re_probe: - dev->driver = drv; - - /* If using pinctrl, bind pins now before probing */ - ret = pinctrl_bind_pins(dev); - if (ret) - goto pinctrl_bind_failed; - - if (driver_sysfs_add(dev)) { - printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n", - __func__, dev_name(dev)); - goto probe_failed; - } - - if (dev->pm_domain && dev->pm_domain->activate) { - ret = dev->pm_domain->activate(dev); - if (ret) - goto probe_failed; - } - - /* - * Ensure devices are listed in devices_kset in correct order - * It's important to move Dev to the end of devices_kset before - * calling .probe, because it could be recursive and parent Dev - * should always go first - */ - devices_kset_move_last(dev); - - if (dev->bus->probe) { - ret = dev->bus->probe(dev); - if (ret) - goto probe_failed; - } else if (drv->probe) { - ret = drv->probe(dev); - if (ret) - goto probe_failed; - } - - if (test_remove) { - test_remove = false; - - if (dev->bus->remove) - dev->bus->remove(dev); - else if (drv->remove) - drv->remove(dev); - - devres_release_all(dev); - driver_sysfs_remove(dev); - dev->driver = NULL; - dev_set_drvdata(dev, NULL); - if (dev->pm_domain && dev->pm_domain->dismiss) - dev->pm_domain->dismiss(dev); - pm_runtime_reinit(dev); - - goto re_probe; - } - - pinctrl_init_done(dev); - - if (dev->pm_domain && dev->pm_domain->sync) - dev->pm_domain->sync(dev); - - driver_bound(dev); - ret = 1; - pr_debug("bus: '%s': %s: bound device %s to driver %s\n", - drv->bus->name, __func__, dev_name(dev), drv->name); - goto done; - -probe_failed: - if (dev->bus) - blocking_notifier_call_chain(&dev->bus->p->bus_notifier, - BUS_NOTIFY_DRIVER_NOT_BOUND, dev); -pinctrl_bind_failed: - devres_release_all(dev); - driver_sysfs_remove(dev); - dev->driver = NULL; - dev_set_drvdata(dev, NULL); - if (dev->pm_domain && dev->pm_domain->dismiss) - dev->pm_domain->dismiss(dev); - pm_runtime_reinit(dev); - - switch (ret) { - case -EPROBE_DEFER: - /* Driver requested deferred probing */ - dev_dbg(dev, "Driver %s requests probe deferral\n", drv->name); - driver_deferred_probe_add(dev); - /* Did a trigger occur while probing? Need to re-trigger if yes */ - if (local_trigger_count != atomic_read(&deferred_trigger_count)) - driver_deferred_probe_trigger(); - break; - case -ENODEV: - case -ENXIO: - pr_debug("%s: probe of %s rejects match %d\n", - drv->name, dev_name(dev), ret); - break; - default: - /* driver matched but the probe failed */ - printk(KERN_WARNING - "%s: probe of %s failed with error %d\n", - drv->name, dev_name(dev), ret); - } - /* - * Ignore errors returned by ->probe so that the next driver can try - * its luck. - */ - ret = 0; -done: - atomic_dec(&probe_count); - wake_up(&probe_waitqueue); - return ret; -} - -/** - * driver_probe_done - * Determine if the probe sequence is finished or not. - * - * Should somehow figure out how to use a semaphore, not an atomic variable... - */ -int driver_probe_done(void) -{ - pr_debug("%s: probe_count = %d\n", __func__, - atomic_read(&probe_count)); - if (atomic_read(&probe_count)) - return -EBUSY; - return 0; -} - -/** - * wait_for_device_probe - * Wait for device probing to be completed. - */ -void wait_for_device_probe(void) -{ - /* wait for the deferred probe workqueue to finish */ - flush_work(&deferred_probe_work); - - /* wait for the known devices to complete their probing */ - wait_event(probe_waitqueue, atomic_read(&probe_count) == 0); - async_synchronize_full(); -} -EXPORT_SYMBOL_GPL(wait_for_device_probe); - -/** - * driver_probe_device - attempt to bind device & driver together - * @drv: driver to bind a device to - * @dev: device to try to bind to the driver - * - * This function returns -ENODEV if the device is not registered, - * 1 if the device is bound successfully and 0 otherwise. - * - * This function must be called with @dev lock held. When called for a - * USB interface, @dev->parent lock must be held as well. - * - * If the device has a parent, runtime-resume the parent before driver probing. - */ -int driver_probe_device(struct device_driver *drv, struct device *dev) -{ - int ret = 0; - - if (!device_is_registered(dev)) - return -ENODEV; - - pr_debug("bus: '%s': %s: matched device %s with driver %s\n", - drv->bus->name, __func__, dev_name(dev), drv->name); - - if (dev->parent) - pm_runtime_get_sync(dev->parent); - - pm_runtime_barrier(dev); - ret = really_probe(dev, drv); - pm_request_idle(dev); - - if (dev->parent) - pm_runtime_put(dev->parent); - - return ret; -} - -bool driver_allows_async_probing(struct device_driver *drv) -{ - switch (drv->probe_type) { - case PROBE_PREFER_ASYNCHRONOUS: - return true; - - case PROBE_FORCE_SYNCHRONOUS: - return false; - - default: - if (module_requested_async_probing(drv->owner)) - return true; - - return false; - } -} - -struct device_attach_data { - struct device *dev; - - /* - * Indicates whether we are are considering asynchronous probing or - * not. Only initial binding after device or driver registration - * (including deferral processing) may be done asynchronously, the - * rest is always synchronous, as we expect it is being done by - * request from userspace. - */ - bool check_async; - - /* - * Indicates if we are binding synchronous or asynchronous drivers. - * When asynchronous probing is enabled we'll execute 2 passes - * over drivers: first pass doing synchronous probing and second - * doing asynchronous probing (if synchronous did not succeed - - * most likely because there was no driver requiring synchronous - * probing - and we found asynchronous driver during first pass). - * The 2 passes are done because we can't shoot asynchronous - * probe for given device and driver from bus_for_each_drv() since - * driver pointer is not guaranteed to stay valid once - * bus_for_each_drv() iterates to the next driver on the bus. - */ - bool want_async; - - /* - * We'll set have_async to 'true' if, while scanning for matching - * driver, we'll encounter one that requests asynchronous probing. - */ - bool have_async; -}; - -static int __device_attach_driver(struct device_driver *drv, void *_data) -{ - struct device_attach_data *data = _data; - struct device *dev = data->dev; - bool async_allowed; - int ret; - - /* - * Check if device has already been claimed. This may - * happen with driver loading, device discovery/registration, - * and deferred probe processing happens all at once with - * multiple threads. - */ - if (dev->driver) - return -EBUSY; - - ret = driver_match_device(drv, dev); - if (ret == 0) { - /* no match */ - return 0; - } else if (ret == -EPROBE_DEFER) { - dev_dbg(dev, "Device match requests probe deferral\n"); - driver_deferred_probe_add(dev); - } else if (ret < 0) { - dev_dbg(dev, "Bus failed to match device: %d", ret); - return ret; - } /* ret > 0 means positive match */ - - async_allowed = driver_allows_async_probing(drv); - - if (async_allowed) - data->have_async = true; - - if (data->check_async && async_allowed != data->want_async) - return 0; - - return driver_probe_device(drv, dev); -} - -static void __device_attach_async_helper(void *_dev, async_cookie_t cookie) -{ - struct device *dev = _dev; - struct device_attach_data data = { - .dev = dev, - .check_async = true, - .want_async = true, - }; - - device_lock(dev); - - if (dev->parent) - pm_runtime_get_sync(dev->parent); - - bus_for_each_drv(dev->bus, NULL, &data, __device_attach_driver); - dev_dbg(dev, "async probe completed\n"); - - pm_request_idle(dev); - - if (dev->parent) - pm_runtime_put(dev->parent); - - device_unlock(dev); - - put_device(dev); -} - -static int __device_attach(struct device *dev, bool allow_async) -{ - int ret = 0; - - device_lock(dev); - if (dev->driver) { - if (device_is_bound(dev)) { - ret = 1; - goto out_unlock; - } - ret = device_bind_driver(dev); - if (ret == 0) - ret = 1; - else { - dev->driver = NULL; - ret = 0; - } - } else { - struct device_attach_data data = { - .dev = dev, - .check_async = allow_async, - .want_async = false, - }; - - if (dev->parent) - pm_runtime_get_sync(dev->parent); - - ret = bus_for_each_drv(dev->bus, NULL, &data, - __device_attach_driver); - if (!ret && allow_async && data.have_async) { - /* - * If we could not find appropriate driver - * synchronously and we are allowed to do - * async probes and there are drivers that - * want to probe asynchronously, we'll - * try them. - */ - dev_dbg(dev, "scheduling asynchronous probe\n"); - get_device(dev); - async_schedule(__device_attach_async_helper, dev); - } else { - pm_request_idle(dev); - } - - if (dev->parent) - pm_runtime_put(dev->parent); - } -out_unlock: - device_unlock(dev); - return ret; -} - -/** - * device_attach - try to attach device to a driver. - * @dev: device. - * - * Walk the list of drivers that the bus has and call - * driver_probe_device() for each pair. If a compatible - * pair is found, break out and return. - * - * Returns 1 if the device was bound to a driver; - * 0 if no matching driver was found; - * -ENODEV if the device is not registered. - * - * When called for a USB interface, @dev->parent lock must be held. - */ -int device_attach(struct device *dev) -{ - return __device_attach(dev, false); -} -EXPORT_SYMBOL_GPL(device_attach); - -void device_initial_probe(struct device *dev) -{ - __device_attach(dev, true); -} - -static int __driver_attach(struct device *dev, void *data) -{ - struct device_driver *drv = data; - int ret; - - /* - * Lock device and try to bind to it. We drop the error - * here and always return 0, because we need to keep trying - * to bind to devices and some drivers will return an error - * simply if it didn't support the device. - * - * driver_probe_device() will spit a warning if there - * is an error. - */ - - ret = driver_match_device(drv, dev); - if (ret == 0) { - /* no match */ - return 0; - } else if (ret == -EPROBE_DEFER) { - dev_dbg(dev, "Device match requests probe deferral\n"); - driver_deferred_probe_add(dev); - } else if (ret < 0) { - dev_dbg(dev, "Bus failed to match device: %d", ret); - return ret; - } /* ret > 0 means positive match */ - - if (dev->parent) /* Needed for USB */ - device_lock(dev->parent); - device_lock(dev); - if (!dev->driver) - driver_probe_device(drv, dev); - device_unlock(dev); - if (dev->parent) - device_unlock(dev->parent); - - return 0; -} - -/** - * driver_attach - try to bind driver to devices. - * @drv: driver. - * - * Walk the list of devices that the bus has on it and try to - * match the driver with each one. If driver_probe_device() - * returns 0 and the @dev->driver is set, we've found a - * compatible pair. - */ -int driver_attach(struct device_driver *drv) -{ - return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); -} -EXPORT_SYMBOL_GPL(driver_attach); - -/* - * __device_release_driver() must be called with @dev lock held. - * When called for a USB interface, @dev->parent lock must be held as well. - */ -static void __device_release_driver(struct device *dev) -{ - struct device_driver *drv; - - drv = dev->driver; - if (drv) { - if (driver_allows_async_probing(drv)) - async_synchronize_full(); - - pm_runtime_get_sync(dev); - - driver_sysfs_remove(dev); - - if (dev->bus) - blocking_notifier_call_chain(&dev->bus->p->bus_notifier, - BUS_NOTIFY_UNBIND_DRIVER, - dev); - - pm_runtime_put_sync(dev); - - if (dev->bus && dev->bus->remove) - dev->bus->remove(dev); - else if (drv->remove) - drv->remove(dev); - devres_release_all(dev); - dev->driver = NULL; - dev_set_drvdata(dev, NULL); - if (dev->pm_domain && dev->pm_domain->dismiss) - dev->pm_domain->dismiss(dev); - pm_runtime_reinit(dev); - - klist_remove(&dev->p->knode_driver); - device_pm_check_callbacks(dev); - if (dev->bus) - blocking_notifier_call_chain(&dev->bus->p->bus_notifier, - BUS_NOTIFY_UNBOUND_DRIVER, - dev); - } -} - -/** - * device_release_driver - manually detach device from driver. - * @dev: device. - * - * Manually detach device from driver. - * When called for a USB interface, @dev->parent lock must be held. - */ -void device_release_driver(struct device *dev) -{ - /* - * If anyone calls device_release_driver() recursively from - * within their ->remove callback for the same device, they - * will deadlock right here. - */ - device_lock(dev); - __device_release_driver(dev); - device_unlock(dev); -} -EXPORT_SYMBOL_GPL(device_release_driver); - -/** - * driver_detach - detach driver from all devices it controls. - * @drv: driver. - */ -void driver_detach(struct device_driver *drv) -{ - struct device_private *dev_prv; - struct device *dev; - - for (;;) { - spin_lock(&drv->p->klist_devices.k_lock); - if (list_empty(&drv->p->klist_devices.k_list)) { - spin_unlock(&drv->p->klist_devices.k_lock); - break; - } - dev_prv = list_entry(drv->p->klist_devices.k_list.prev, - struct device_private, - knode_driver.n_node); - dev = dev_prv->device; - get_device(dev); - spin_unlock(&drv->p->klist_devices.k_lock); - - if (dev->parent) /* Needed for USB */ - device_lock(dev->parent); - device_lock(dev); - if (dev->driver == drv) - __device_release_driver(dev); - device_unlock(dev); - if (dev->parent) - device_unlock(dev->parent); - put_device(dev); - } -} diff --git a/src/linux/drivers/base/devres.c b/src/linux/drivers/base/devres.c deleted file mode 100644 index 8fc654f..0000000 --- a/src/linux/drivers/base/devres.c +++ /dev/null @@ -1,987 +0,0 @@ -/* - * drivers/base/devres.c - device resource management - * - * Copyright (c) 2006 SUSE Linux Products GmbH - * Copyright (c) 2006 Tejun Heo - * - * This file is released under the GPLv2. - */ - -#include -#include -#include - -#include "base.h" - -struct devres_node { - struct list_head entry; - dr_release_t release; -#ifdef CONFIG_DEBUG_DEVRES - const char *name; - size_t size; -#endif -}; - -struct devres { - struct devres_node node; - /* -- 3 pointers */ - unsigned long long data[]; /* guarantee ull alignment */ -}; - -struct devres_group { - struct devres_node node[2]; - void *id; - int color; - /* -- 8 pointers */ -}; - -#ifdef CONFIG_DEBUG_DEVRES -static int log_devres = 0; -module_param_named(log, log_devres, int, S_IRUGO | S_IWUSR); - -static void set_node_dbginfo(struct devres_node *node, const char *name, - size_t size) -{ - node->name = name; - node->size = size; -} - -static void devres_log(struct device *dev, struct devres_node *node, - const char *op) -{ - if (unlikely(log_devres)) - dev_err(dev, "DEVRES %3s %p %s (%lu bytes)\n", - op, node, node->name, (unsigned long)node->size); -} -#else /* CONFIG_DEBUG_DEVRES */ -#define set_node_dbginfo(node, n, s) do {} while (0) -#define devres_log(dev, node, op) do {} while (0) -#endif /* CONFIG_DEBUG_DEVRES */ - -/* - * Release functions for devres group. These callbacks are used only - * for identification. - */ -static void group_open_release(struct device *dev, void *res) -{ - /* noop */ -} - -static void group_close_release(struct device *dev, void *res) -{ - /* noop */ -} - -static struct devres_group * node_to_group(struct devres_node *node) -{ - if (node->release == &group_open_release) - return container_of(node, struct devres_group, node[0]); - if (node->release == &group_close_release) - return container_of(node, struct devres_group, node[1]); - return NULL; -} - -static __always_inline struct devres * alloc_dr(dr_release_t release, - size_t size, gfp_t gfp, int nid) -{ - size_t tot_size = sizeof(struct devres) + size; - struct devres *dr; - - dr = kmalloc_node_track_caller(tot_size, gfp, nid); - if (unlikely(!dr)) - return NULL; - - memset(dr, 0, offsetof(struct devres, data)); - - INIT_LIST_HEAD(&dr->node.entry); - dr->node.release = release; - return dr; -} - -static void add_dr(struct device *dev, struct devres_node *node) -{ - devres_log(dev, node, "ADD"); - BUG_ON(!list_empty(&node->entry)); - list_add_tail(&node->entry, &dev->devres_head); -} - -#ifdef CONFIG_DEBUG_DEVRES -void * __devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid, - const char *name) -{ - struct devres *dr; - - dr = alloc_dr(release, size, gfp | __GFP_ZERO, nid); - if (unlikely(!dr)) - return NULL; - set_node_dbginfo(&dr->node, name, size); - return dr->data; -} -EXPORT_SYMBOL_GPL(__devres_alloc_node); -#else -/** - * devres_alloc - Allocate device resource data - * @release: Release function devres will be associated with - * @size: Allocation size - * @gfp: Allocation flags - * @nid: NUMA node - * - * Allocate devres of @size bytes. The allocated area is zeroed, then - * associated with @release. The returned pointer can be passed to - * other devres_*() functions. - * - * RETURNS: - * Pointer to allocated devres on success, NULL on failure. - */ -void * devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, int nid) -{ - struct devres *dr; - - dr = alloc_dr(release, size, gfp | __GFP_ZERO, nid); - if (unlikely(!dr)) - return NULL; - return dr->data; -} -EXPORT_SYMBOL_GPL(devres_alloc_node); -#endif - -/** - * devres_for_each_res - Resource iterator - * @dev: Device to iterate resource from - * @release: Look for resources associated with this release function - * @match: Match function (optional) - * @match_data: Data for the match function - * @fn: Function to be called for each matched resource. - * @data: Data for @fn, the 3rd parameter of @fn - * - * Call @fn for each devres of @dev which is associated with @release - * and for which @match returns 1. - * - * RETURNS: - * void - */ -void devres_for_each_res(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data, - void (*fn)(struct device *, void *, void *), - void *data) -{ - struct devres_node *node; - struct devres_node *tmp; - unsigned long flags; - - if (!fn) - return; - - spin_lock_irqsave(&dev->devres_lock, flags); - list_for_each_entry_safe_reverse(node, tmp, - &dev->devres_head, entry) { - struct devres *dr = container_of(node, struct devres, node); - - if (node->release != release) - continue; - if (match && !match(dev, dr->data, match_data)) - continue; - fn(dev, dr->data, data); - } - spin_unlock_irqrestore(&dev->devres_lock, flags); -} -EXPORT_SYMBOL_GPL(devres_for_each_res); - -/** - * devres_free - Free device resource data - * @res: Pointer to devres data to free - * - * Free devres created with devres_alloc(). - */ -void devres_free(void *res) -{ - if (res) { - struct devres *dr = container_of(res, struct devres, data); - - BUG_ON(!list_empty(&dr->node.entry)); - kfree(dr); - } -} -EXPORT_SYMBOL_GPL(devres_free); - -/** - * devres_add - Register device resource - * @dev: Device to add resource to - * @res: Resource to register - * - * Register devres @res to @dev. @res should have been allocated - * using devres_alloc(). On driver detach, the associated release - * function will be invoked and devres will be freed automatically. - */ -void devres_add(struct device *dev, void *res) -{ - struct devres *dr = container_of(res, struct devres, data); - unsigned long flags; - - spin_lock_irqsave(&dev->devres_lock, flags); - add_dr(dev, &dr->node); - spin_unlock_irqrestore(&dev->devres_lock, flags); -} -EXPORT_SYMBOL_GPL(devres_add); - -static struct devres *find_dr(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data) -{ - struct devres_node *node; - - list_for_each_entry_reverse(node, &dev->devres_head, entry) { - struct devres *dr = container_of(node, struct devres, node); - - if (node->release != release) - continue; - if (match && !match(dev, dr->data, match_data)) - continue; - return dr; - } - - return NULL; -} - -/** - * devres_find - Find device resource - * @dev: Device to lookup resource from - * @release: Look for resources associated with this release function - * @match: Match function (optional) - * @match_data: Data for the match function - * - * Find the latest devres of @dev which is associated with @release - * and for which @match returns 1. If @match is NULL, it's considered - * to match all. - * - * RETURNS: - * Pointer to found devres, NULL if not found. - */ -void * devres_find(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data) -{ - struct devres *dr; - unsigned long flags; - - spin_lock_irqsave(&dev->devres_lock, flags); - dr = find_dr(dev, release, match, match_data); - spin_unlock_irqrestore(&dev->devres_lock, flags); - - if (dr) - return dr->data; - return NULL; -} -EXPORT_SYMBOL_GPL(devres_find); - -/** - * devres_get - Find devres, if non-existent, add one atomically - * @dev: Device to lookup or add devres for - * @new_res: Pointer to new initialized devres to add if not found - * @match: Match function (optional) - * @match_data: Data for the match function - * - * Find the latest devres of @dev which has the same release function - * as @new_res and for which @match return 1. If found, @new_res is - * freed; otherwise, @new_res is added atomically. - * - * RETURNS: - * Pointer to found or added devres. - */ -void * devres_get(struct device *dev, void *new_res, - dr_match_t match, void *match_data) -{ - struct devres *new_dr = container_of(new_res, struct devres, data); - struct devres *dr; - unsigned long flags; - - spin_lock_irqsave(&dev->devres_lock, flags); - dr = find_dr(dev, new_dr->node.release, match, match_data); - if (!dr) { - add_dr(dev, &new_dr->node); - dr = new_dr; - new_res = NULL; - } - spin_unlock_irqrestore(&dev->devres_lock, flags); - devres_free(new_res); - - return dr->data; -} -EXPORT_SYMBOL_GPL(devres_get); - -/** - * devres_remove - Find a device resource and remove it - * @dev: Device to find resource from - * @release: Look for resources associated with this release function - * @match: Match function (optional) - * @match_data: Data for the match function - * - * Find the latest devres of @dev associated with @release and for - * which @match returns 1. If @match is NULL, it's considered to - * match all. If found, the resource is removed atomically and - * returned. - * - * RETURNS: - * Pointer to removed devres on success, NULL if not found. - */ -void * devres_remove(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data) -{ - struct devres *dr; - unsigned long flags; - - spin_lock_irqsave(&dev->devres_lock, flags); - dr = find_dr(dev, release, match, match_data); - if (dr) { - list_del_init(&dr->node.entry); - devres_log(dev, &dr->node, "REM"); - } - spin_unlock_irqrestore(&dev->devres_lock, flags); - - if (dr) - return dr->data; - return NULL; -} -EXPORT_SYMBOL_GPL(devres_remove); - -/** - * devres_destroy - Find a device resource and destroy it - * @dev: Device to find resource from - * @release: Look for resources associated with this release function - * @match: Match function (optional) - * @match_data: Data for the match function - * - * Find the latest devres of @dev associated with @release and for - * which @match returns 1. If @match is NULL, it's considered to - * match all. If found, the resource is removed atomically and freed. - * - * Note that the release function for the resource will not be called, - * only the devres-allocated data will be freed. The caller becomes - * responsible for freeing any other data. - * - * RETURNS: - * 0 if devres is found and freed, -ENOENT if not found. - */ -int devres_destroy(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data) -{ - void *res; - - res = devres_remove(dev, release, match, match_data); - if (unlikely(!res)) - return -ENOENT; - - devres_free(res); - return 0; -} -EXPORT_SYMBOL_GPL(devres_destroy); - - -/** - * devres_release - Find a device resource and destroy it, calling release - * @dev: Device to find resource from - * @release: Look for resources associated with this release function - * @match: Match function (optional) - * @match_data: Data for the match function - * - * Find the latest devres of @dev associated with @release and for - * which @match returns 1. If @match is NULL, it's considered to - * match all. If found, the resource is removed atomically, the - * release function called and the resource freed. - * - * RETURNS: - * 0 if devres is found and freed, -ENOENT if not found. - */ -int devres_release(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data) -{ - void *res; - - res = devres_remove(dev, release, match, match_data); - if (unlikely(!res)) - return -ENOENT; - - (*release)(dev, res); - devres_free(res); - return 0; -} -EXPORT_SYMBOL_GPL(devres_release); - -static int remove_nodes(struct device *dev, - struct list_head *first, struct list_head *end, - struct list_head *todo) -{ - int cnt = 0, nr_groups = 0; - struct list_head *cur; - - /* First pass - move normal devres entries to @todo and clear - * devres_group colors. - */ - cur = first; - while (cur != end) { - struct devres_node *node; - struct devres_group *grp; - - node = list_entry(cur, struct devres_node, entry); - cur = cur->next; - - grp = node_to_group(node); - if (grp) { - /* clear color of group markers in the first pass */ - grp->color = 0; - nr_groups++; - } else { - /* regular devres entry */ - if (&node->entry == first) - first = first->next; - list_move_tail(&node->entry, todo); - cnt++; - } - } - - if (!nr_groups) - return cnt; - - /* Second pass - Scan groups and color them. A group gets - * color value of two iff the group is wholly contained in - * [cur, end). That is, for a closed group, both opening and - * closing markers should be in the range, while just the - * opening marker is enough for an open group. - */ - cur = first; - while (cur != end) { - struct devres_node *node; - struct devres_group *grp; - - node = list_entry(cur, struct devres_node, entry); - cur = cur->next; - - grp = node_to_group(node); - BUG_ON(!grp || list_empty(&grp->node[0].entry)); - - grp->color++; - if (list_empty(&grp->node[1].entry)) - grp->color++; - - BUG_ON(grp->color <= 0 || grp->color > 2); - if (grp->color == 2) { - /* No need to update cur or end. The removed - * nodes are always before both. - */ - list_move_tail(&grp->node[0].entry, todo); - list_del_init(&grp->node[1].entry); - } - } - - return cnt; -} - -static int release_nodes(struct device *dev, struct list_head *first, - struct list_head *end, unsigned long flags) - __releases(&dev->devres_lock) -{ - LIST_HEAD(todo); - int cnt; - struct devres *dr, *tmp; - - cnt = remove_nodes(dev, first, end, &todo); - - spin_unlock_irqrestore(&dev->devres_lock, flags); - - /* Release. Note that both devres and devres_group are - * handled as devres in the following loop. This is safe. - */ - list_for_each_entry_safe_reverse(dr, tmp, &todo, node.entry) { - devres_log(dev, &dr->node, "REL"); - dr->node.release(dev, dr->data); - kfree(dr); - } - - return cnt; -} - -/** - * devres_release_all - Release all managed resources - * @dev: Device to release resources for - * - * Release all resources associated with @dev. This function is - * called on driver detach. - */ -int devres_release_all(struct device *dev) -{ - unsigned long flags; - - /* Looks like an uninitialized device structure */ - if (WARN_ON(dev->devres_head.next == NULL)) - return -ENODEV; - spin_lock_irqsave(&dev->devres_lock, flags); - return release_nodes(dev, dev->devres_head.next, &dev->devres_head, - flags); -} - -/** - * devres_open_group - Open a new devres group - * @dev: Device to open devres group for - * @id: Separator ID - * @gfp: Allocation flags - * - * Open a new devres group for @dev with @id. For @id, using a - * pointer to an object which won't be used for another group is - * recommended. If @id is NULL, address-wise unique ID is created. - * - * RETURNS: - * ID of the new group, NULL on failure. - */ -void * devres_open_group(struct device *dev, void *id, gfp_t gfp) -{ - struct devres_group *grp; - unsigned long flags; - - grp = kmalloc(sizeof(*grp), gfp); - if (unlikely(!grp)) - return NULL; - - grp->node[0].release = &group_open_release; - grp->node[1].release = &group_close_release; - INIT_LIST_HEAD(&grp->node[0].entry); - INIT_LIST_HEAD(&grp->node[1].entry); - set_node_dbginfo(&grp->node[0], "grp<", 0); - set_node_dbginfo(&grp->node[1], "grp>", 0); - grp->id = grp; - if (id) - grp->id = id; - - spin_lock_irqsave(&dev->devres_lock, flags); - add_dr(dev, &grp->node[0]); - spin_unlock_irqrestore(&dev->devres_lock, flags); - return grp->id; -} -EXPORT_SYMBOL_GPL(devres_open_group); - -/* Find devres group with ID @id. If @id is NULL, look for the latest. */ -static struct devres_group * find_group(struct device *dev, void *id) -{ - struct devres_node *node; - - list_for_each_entry_reverse(node, &dev->devres_head, entry) { - struct devres_group *grp; - - if (node->release != &group_open_release) - continue; - - grp = container_of(node, struct devres_group, node[0]); - - if (id) { - if (grp->id == id) - return grp; - } else if (list_empty(&grp->node[1].entry)) - return grp; - } - - return NULL; -} - -/** - * devres_close_group - Close a devres group - * @dev: Device to close devres group for - * @id: ID of target group, can be NULL - * - * Close the group identified by @id. If @id is NULL, the latest open - * group is selected. - */ -void devres_close_group(struct device *dev, void *id) -{ - struct devres_group *grp; - unsigned long flags; - - spin_lock_irqsave(&dev->devres_lock, flags); - - grp = find_group(dev, id); - if (grp) - add_dr(dev, &grp->node[1]); - else - WARN_ON(1); - - spin_unlock_irqrestore(&dev->devres_lock, flags); -} -EXPORT_SYMBOL_GPL(devres_close_group); - -/** - * devres_remove_group - Remove a devres group - * @dev: Device to remove group for - * @id: ID of target group, can be NULL - * - * Remove the group identified by @id. If @id is NULL, the latest - * open group is selected. Note that removing a group doesn't affect - * any other resources. - */ -void devres_remove_group(struct device *dev, void *id) -{ - struct devres_group *grp; - unsigned long flags; - - spin_lock_irqsave(&dev->devres_lock, flags); - - grp = find_group(dev, id); - if (grp) { - list_del_init(&grp->node[0].entry); - list_del_init(&grp->node[1].entry); - devres_log(dev, &grp->node[0], "REM"); - } else - WARN_ON(1); - - spin_unlock_irqrestore(&dev->devres_lock, flags); - - kfree(grp); -} -EXPORT_SYMBOL_GPL(devres_remove_group); - -/** - * devres_release_group - Release resources in a devres group - * @dev: Device to release group for - * @id: ID of target group, can be NULL - * - * Release all resources in the group identified by @id. If @id is - * NULL, the latest open group is selected. The selected group and - * groups properly nested inside the selected group are removed. - * - * RETURNS: - * The number of released non-group resources. - */ -int devres_release_group(struct device *dev, void *id) -{ - struct devres_group *grp; - unsigned long flags; - int cnt = 0; - - spin_lock_irqsave(&dev->devres_lock, flags); - - grp = find_group(dev, id); - if (grp) { - struct list_head *first = &grp->node[0].entry; - struct list_head *end = &dev->devres_head; - - if (!list_empty(&grp->node[1].entry)) - end = grp->node[1].entry.next; - - cnt = release_nodes(dev, first, end, flags); - } else { - WARN_ON(1); - spin_unlock_irqrestore(&dev->devres_lock, flags); - } - - return cnt; -} -EXPORT_SYMBOL_GPL(devres_release_group); - -/* - * Custom devres actions allow inserting a simple function call - * into the teadown sequence. - */ - -struct action_devres { - void *data; - void (*action)(void *); -}; - -static int devm_action_match(struct device *dev, void *res, void *p) -{ - struct action_devres *devres = res; - struct action_devres *target = p; - - return devres->action == target->action && - devres->data == target->data; -} - -static void devm_action_release(struct device *dev, void *res) -{ - struct action_devres *devres = res; - - devres->action(devres->data); -} - -/** - * devm_add_action() - add a custom action to list of managed resources - * @dev: Device that owns the action - * @action: Function that should be called - * @data: Pointer to data passed to @action implementation - * - * This adds a custom action to the list of managed resources so that - * it gets executed as part of standard resource unwinding. - */ -int devm_add_action(struct device *dev, void (*action)(void *), void *data) -{ - struct action_devres *devres; - - devres = devres_alloc(devm_action_release, - sizeof(struct action_devres), GFP_KERNEL); - if (!devres) - return -ENOMEM; - - devres->data = data; - devres->action = action; - - devres_add(dev, devres); - return 0; -} -EXPORT_SYMBOL_GPL(devm_add_action); - -/** - * devm_remove_action() - removes previously added custom action - * @dev: Device that owns the action - * @action: Function implementing the action - * @data: Pointer to data passed to @action implementation - * - * Removes instance of @action previously added by devm_add_action(). - * Both action and data should match one of the existing entries. - */ -void devm_remove_action(struct device *dev, void (*action)(void *), void *data) -{ - struct action_devres devres = { - .data = data, - .action = action, - }; - - WARN_ON(devres_destroy(dev, devm_action_release, devm_action_match, - &devres)); - -} -EXPORT_SYMBOL_GPL(devm_remove_action); - -/* - * Managed kmalloc/kfree - */ -static void devm_kmalloc_release(struct device *dev, void *res) -{ - /* noop */ -} - -static int devm_kmalloc_match(struct device *dev, void *res, void *data) -{ - return res == data; -} - -/** - * devm_kmalloc - Resource-managed kmalloc - * @dev: Device to allocate memory for - * @size: Allocation size - * @gfp: Allocation gfp flags - * - * Managed kmalloc. Memory allocated with this function is - * automatically freed on driver detach. Like all other devres - * resources, guaranteed alignment is unsigned long long. - * - * RETURNS: - * Pointer to allocated memory on success, NULL on failure. - */ -void * devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) -{ - struct devres *dr; - - /* use raw alloc_dr for kmalloc caller tracing */ - dr = alloc_dr(devm_kmalloc_release, size, gfp, dev_to_node(dev)); - if (unlikely(!dr)) - return NULL; - - /* - * This is named devm_kzalloc_release for historical reasons - * The initial implementation did not support kmalloc, only kzalloc - */ - set_node_dbginfo(&dr->node, "devm_kzalloc_release", size); - devres_add(dev, dr->data); - return dr->data; -} -EXPORT_SYMBOL_GPL(devm_kmalloc); - -/** - * devm_kstrdup - Allocate resource managed space and - * copy an existing string into that. - * @dev: Device to allocate memory for - * @s: the string to duplicate - * @gfp: the GFP mask used in the devm_kmalloc() call when - * allocating memory - * RETURNS: - * Pointer to allocated string on success, NULL on failure. - */ -char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) -{ - size_t size; - char *buf; - - if (!s) - return NULL; - - size = strlen(s) + 1; - buf = devm_kmalloc(dev, size, gfp); - if (buf) - memcpy(buf, s, size); - return buf; -} -EXPORT_SYMBOL_GPL(devm_kstrdup); - -/** - * devm_kvasprintf - Allocate resource managed space and format a string - * into that. - * @dev: Device to allocate memory for - * @gfp: the GFP mask used in the devm_kmalloc() call when - * allocating memory - * @fmt: The printf()-style format string - * @ap: Arguments for the format string - * RETURNS: - * Pointer to allocated string on success, NULL on failure. - */ -char *devm_kvasprintf(struct device *dev, gfp_t gfp, const char *fmt, - va_list ap) -{ - unsigned int len; - char *p; - va_list aq; - - va_copy(aq, ap); - len = vsnprintf(NULL, 0, fmt, aq); - va_end(aq); - - p = devm_kmalloc(dev, len+1, gfp); - if (!p) - return NULL; - - vsnprintf(p, len+1, fmt, ap); - - return p; -} -EXPORT_SYMBOL(devm_kvasprintf); - -/** - * devm_kasprintf - Allocate resource managed space and format a string - * into that. - * @dev: Device to allocate memory for - * @gfp: the GFP mask used in the devm_kmalloc() call when - * allocating memory - * @fmt: The printf()-style format string - * @...: Arguments for the format string - * RETURNS: - * Pointer to allocated string on success, NULL on failure. - */ -char *devm_kasprintf(struct device *dev, gfp_t gfp, const char *fmt, ...) -{ - va_list ap; - char *p; - - va_start(ap, fmt); - p = devm_kvasprintf(dev, gfp, fmt, ap); - va_end(ap); - - return p; -} -EXPORT_SYMBOL_GPL(devm_kasprintf); - -/** - * devm_kfree - Resource-managed kfree - * @dev: Device this memory belongs to - * @p: Memory to free - * - * Free memory allocated with devm_kmalloc(). - */ -void devm_kfree(struct device *dev, void *p) -{ - int rc; - - rc = devres_destroy(dev, devm_kmalloc_release, devm_kmalloc_match, p); - WARN_ON(rc); -} -EXPORT_SYMBOL_GPL(devm_kfree); - -/** - * devm_kmemdup - Resource-managed kmemdup - * @dev: Device this memory belongs to - * @src: Memory region to duplicate - * @len: Memory region length - * @gfp: GFP mask to use - * - * Duplicate region of a memory using resource managed kmalloc - */ -void *devm_kmemdup(struct device *dev, const void *src, size_t len, gfp_t gfp) -{ - void *p; - - p = devm_kmalloc(dev, len, gfp); - if (p) - memcpy(p, src, len); - - return p; -} -EXPORT_SYMBOL_GPL(devm_kmemdup); - -struct pages_devres { - unsigned long addr; - unsigned int order; -}; - -static int devm_pages_match(struct device *dev, void *res, void *p) -{ - struct pages_devres *devres = res; - struct pages_devres *target = p; - - return devres->addr == target->addr; -} - -static void devm_pages_release(struct device *dev, void *res) -{ - struct pages_devres *devres = res; - - free_pages(devres->addr, devres->order); -} - -/** - * devm_get_free_pages - Resource-managed __get_free_pages - * @dev: Device to allocate memory for - * @gfp_mask: Allocation gfp flags - * @order: Allocation size is (1 << order) pages - * - * Managed get_free_pages. Memory allocated with this function is - * automatically freed on driver detach. - * - * RETURNS: - * Address of allocated memory on success, 0 on failure. - */ - -unsigned long devm_get_free_pages(struct device *dev, - gfp_t gfp_mask, unsigned int order) -{ - struct pages_devres *devres; - unsigned long addr; - - addr = __get_free_pages(gfp_mask, order); - - if (unlikely(!addr)) - return 0; - - devres = devres_alloc(devm_pages_release, - sizeof(struct pages_devres), GFP_KERNEL); - if (unlikely(!devres)) { - free_pages(addr, order); - return 0; - } - - devres->addr = addr; - devres->order = order; - - devres_add(dev, devres); - return addr; -} -EXPORT_SYMBOL_GPL(devm_get_free_pages); - -/** - * devm_free_pages - Resource-managed free_pages - * @dev: Device this memory belongs to - * @addr: Memory to free - * - * Free memory allocated with devm_get_free_pages(). Unlike free_pages, - * there is no need to supply the @order. - */ -void devm_free_pages(struct device *dev, unsigned long addr) -{ - struct pages_devres devres = { .addr = addr }; - - WARN_ON(devres_release(dev, devm_pages_release, devm_pages_match, - &devres)); -} -EXPORT_SYMBOL_GPL(devm_free_pages); diff --git a/src/linux/drivers/base/dma-mapping.c b/src/linux/drivers/base/dma-mapping.c deleted file mode 100644 index 8f8b68c..0000000 --- a/src/linux/drivers/base/dma-mapping.c +++ /dev/null @@ -1,343 +0,0 @@ -/* - * drivers/base/dma-mapping.c - arch-independent dma-mapping routines - * - * Copyright (c) 2006 SUSE Linux Products GmbH - * Copyright (c) 2006 Tejun Heo - * - * This file is released under the GPLv2. - */ - -#include -#include -#include -#include -#include - -/* - * Managed DMA API - */ -struct dma_devres { - size_t size; - void *vaddr; - dma_addr_t dma_handle; -}; - -static void dmam_coherent_release(struct device *dev, void *res) -{ - struct dma_devres *this = res; - - dma_free_coherent(dev, this->size, this->vaddr, this->dma_handle); -} - -static void dmam_noncoherent_release(struct device *dev, void *res) -{ - struct dma_devres *this = res; - - dma_free_noncoherent(dev, this->size, this->vaddr, this->dma_handle); -} - -static int dmam_match(struct device *dev, void *res, void *match_data) -{ - struct dma_devres *this = res, *match = match_data; - - if (this->vaddr == match->vaddr) { - WARN_ON(this->size != match->size || - this->dma_handle != match->dma_handle); - return 1; - } - return 0; -} - -/** - * dmam_alloc_coherent - Managed dma_alloc_coherent() - * @dev: Device to allocate coherent memory for - * @size: Size of allocation - * @dma_handle: Out argument for allocated DMA handle - * @gfp: Allocation flags - * - * Managed dma_alloc_coherent(). Memory allocated using this function - * will be automatically released on driver detach. - * - * RETURNS: - * Pointer to allocated memory on success, NULL on failure. - */ -void *dmam_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp) -{ - struct dma_devres *dr; - void *vaddr; - - dr = devres_alloc(dmam_coherent_release, sizeof(*dr), gfp); - if (!dr) - return NULL; - - vaddr = dma_alloc_coherent(dev, size, dma_handle, gfp); - if (!vaddr) { - devres_free(dr); - return NULL; - } - - dr->vaddr = vaddr; - dr->dma_handle = *dma_handle; - dr->size = size; - - devres_add(dev, dr); - - return vaddr; -} -EXPORT_SYMBOL(dmam_alloc_coherent); - -/** - * dmam_free_coherent - Managed dma_free_coherent() - * @dev: Device to free coherent memory for - * @size: Size of allocation - * @vaddr: Virtual address of the memory to free - * @dma_handle: DMA handle of the memory to free - * - * Managed dma_free_coherent(). - */ -void dmam_free_coherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) -{ - struct dma_devres match_data = { size, vaddr, dma_handle }; - - dma_free_coherent(dev, size, vaddr, dma_handle); - WARN_ON(devres_destroy(dev, dmam_coherent_release, dmam_match, - &match_data)); -} -EXPORT_SYMBOL(dmam_free_coherent); - -/** - * dmam_alloc_non_coherent - Managed dma_alloc_non_coherent() - * @dev: Device to allocate non_coherent memory for - * @size: Size of allocation - * @dma_handle: Out argument for allocated DMA handle - * @gfp: Allocation flags - * - * Managed dma_alloc_non_coherent(). Memory allocated using this - * function will be automatically released on driver detach. - * - * RETURNS: - * Pointer to allocated memory on success, NULL on failure. - */ -void *dmam_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp) -{ - struct dma_devres *dr; - void *vaddr; - - dr = devres_alloc(dmam_noncoherent_release, sizeof(*dr), gfp); - if (!dr) - return NULL; - - vaddr = dma_alloc_noncoherent(dev, size, dma_handle, gfp); - if (!vaddr) { - devres_free(dr); - return NULL; - } - - dr->vaddr = vaddr; - dr->dma_handle = *dma_handle; - dr->size = size; - - devres_add(dev, dr); - - return vaddr; -} -EXPORT_SYMBOL(dmam_alloc_noncoherent); - -/** - * dmam_free_coherent - Managed dma_free_noncoherent() - * @dev: Device to free noncoherent memory for - * @size: Size of allocation - * @vaddr: Virtual address of the memory to free - * @dma_handle: DMA handle of the memory to free - * - * Managed dma_free_noncoherent(). - */ -void dmam_free_noncoherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle) -{ - struct dma_devres match_data = { size, vaddr, dma_handle }; - - dma_free_noncoherent(dev, size, vaddr, dma_handle); - WARN_ON(!devres_destroy(dev, dmam_noncoherent_release, dmam_match, - &match_data)); -} -EXPORT_SYMBOL(dmam_free_noncoherent); - -#ifdef CONFIG_HAVE_GENERIC_DMA_COHERENT - -static void dmam_coherent_decl_release(struct device *dev, void *res) -{ - dma_release_declared_memory(dev); -} - -/** - * dmam_declare_coherent_memory - Managed dma_declare_coherent_memory() - * @dev: Device to declare coherent memory for - * @phys_addr: Physical address of coherent memory to be declared - * @device_addr: Device address of coherent memory to be declared - * @size: Size of coherent memory to be declared - * @flags: Flags - * - * Managed dma_declare_coherent_memory(). - * - * RETURNS: - * 0 on success, -errno on failure. - */ -int dmam_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, - dma_addr_t device_addr, size_t size, int flags) -{ - void *res; - int rc; - - res = devres_alloc(dmam_coherent_decl_release, 0, GFP_KERNEL); - if (!res) - return -ENOMEM; - - rc = dma_declare_coherent_memory(dev, phys_addr, device_addr, size, - flags); - if (rc) { - devres_add(dev, res); - rc = 0; - } else { - devres_free(res); - rc = -ENOMEM; - } - - return rc; -} -EXPORT_SYMBOL(dmam_declare_coherent_memory); - -/** - * dmam_release_declared_memory - Managed dma_release_declared_memory(). - * @dev: Device to release declared coherent memory for - * - * Managed dmam_release_declared_memory(). - */ -void dmam_release_declared_memory(struct device *dev) -{ - WARN_ON(devres_destroy(dev, dmam_coherent_decl_release, NULL, NULL)); -} -EXPORT_SYMBOL(dmam_release_declared_memory); - -#endif - -/* - * Create scatter-list for the already allocated DMA buffer. - */ -int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, - void *cpu_addr, dma_addr_t handle, size_t size) -{ - struct page *page = virt_to_page(cpu_addr); - int ret; - - ret = sg_alloc_table(sgt, 1, GFP_KERNEL); - if (unlikely(ret)) - return ret; - - sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0); - return 0; -} -EXPORT_SYMBOL(dma_common_get_sgtable); - -/* - * Create userspace mapping for the DMA-coherent memory. - */ -int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, - void *cpu_addr, dma_addr_t dma_addr, size_t size) -{ - int ret = -ENXIO; -#if defined(CONFIG_MMU) && !defined(CONFIG_ARCH_NO_COHERENT_DMA_MMAP) - unsigned long user_count = vma_pages(vma); - unsigned long count = PAGE_ALIGN(size) >> PAGE_SHIFT; - unsigned long pfn = page_to_pfn(virt_to_page(cpu_addr)); - unsigned long off = vma->vm_pgoff; - - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - - if (dma_mmap_from_coherent(dev, vma, cpu_addr, size, &ret)) - return ret; - - if (off < count && user_count <= (count - off)) { - ret = remap_pfn_range(vma, vma->vm_start, - pfn + off, - user_count << PAGE_SHIFT, - vma->vm_page_prot); - } -#endif /* CONFIG_MMU && !CONFIG_ARCH_NO_COHERENT_DMA_MMAP */ - - return ret; -} -EXPORT_SYMBOL(dma_common_mmap); - -#ifdef CONFIG_MMU -/* - * remaps an array of PAGE_SIZE pages into another vm_area - * Cannot be used in non-sleeping contexts - */ -void *dma_common_pages_remap(struct page **pages, size_t size, - unsigned long vm_flags, pgprot_t prot, - const void *caller) -{ - struct vm_struct *area; - - area = get_vm_area_caller(size, vm_flags, caller); - if (!area) - return NULL; - - area->pages = pages; - - if (map_vm_area(area, prot, pages)) { - vunmap(area->addr); - return NULL; - } - - return area->addr; -} - -/* - * remaps an allocated contiguous region into another vm_area. - * Cannot be used in non-sleeping contexts - */ - -void *dma_common_contiguous_remap(struct page *page, size_t size, - unsigned long vm_flags, - pgprot_t prot, const void *caller) -{ - int i; - struct page **pages; - void *ptr; - unsigned long pfn; - - pages = kmalloc(sizeof(struct page *) << get_order(size), GFP_KERNEL); - if (!pages) - return NULL; - - for (i = 0, pfn = page_to_pfn(page); i < (size >> PAGE_SHIFT); i++) - pages[i] = pfn_to_page(pfn + i); - - ptr = dma_common_pages_remap(pages, size, vm_flags, prot, caller); - - kfree(pages); - - return ptr; -} - -/* - * unmaps a range previously mapped by dma_common_*_remap - */ -void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags) -{ - struct vm_struct *area = find_vm_area(cpu_addr); - - if (!area || (area->flags & vm_flags) != vm_flags) { - WARN(1, "trying to free invalid coherent area: %p\n", cpu_addr); - return; - } - - unmap_kernel_range((unsigned long)cpu_addr, PAGE_ALIGN(size)); - vunmap(cpu_addr); -} -#endif diff --git a/src/linux/drivers/base/driver.c b/src/linux/drivers/base/driver.c deleted file mode 100644 index 4eabfe2..0000000 --- a/src/linux/drivers/base/driver.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - * driver.c - centralized device driver management - * - * Copyright (c) 2002-3 Patrick Mochel - * Copyright (c) 2002-3 Open Source Development Labs - * Copyright (c) 2007 Greg Kroah-Hartman - * Copyright (c) 2007 Novell Inc. - * - * This file is released under the GPLv2 - * - */ - -#include -#include -#include -#include -#include -#include -#include "base.h" - -static struct device *next_device(struct klist_iter *i) -{ - struct klist_node *n = klist_next(i); - struct device *dev = NULL; - struct device_private *dev_prv; - - if (n) { - dev_prv = to_device_private_driver(n); - dev = dev_prv->device; - } - return dev; -} - -/** - * driver_for_each_device - Iterator for devices bound to a driver. - * @drv: Driver we're iterating. - * @start: Device to begin with - * @data: Data to pass to the callback. - * @fn: Function to call for each device. - * - * Iterate over the @drv's list of devices calling @fn for each one. - */ -int driver_for_each_device(struct device_driver *drv, struct device *start, - void *data, int (*fn)(struct device *, void *)) -{ - struct klist_iter i; - struct device *dev; - int error = 0; - - if (!drv) - return -EINVAL; - - klist_iter_init_node(&drv->p->klist_devices, &i, - start ? &start->p->knode_driver : NULL); - while ((dev = next_device(&i)) && !error) - error = fn(dev, data); - klist_iter_exit(&i); - return error; -} -EXPORT_SYMBOL_GPL(driver_for_each_device); - -/** - * driver_find_device - device iterator for locating a particular device. - * @drv: The device's driver - * @start: Device to begin with - * @data: Data to pass to match function - * @match: Callback function to check device - * - * This is similar to the driver_for_each_device() function above, but - * it returns a reference to a device that is 'found' for later use, as - * determined by the @match callback. - * - * The callback should return 0 if the device doesn't match and non-zero - * if it does. If the callback returns non-zero, this function will - * return to the caller and not iterate over any more devices. - */ -struct device *driver_find_device(struct device_driver *drv, - struct device *start, void *data, - int (*match)(struct device *dev, void *data)) -{ - struct klist_iter i; - struct device *dev; - - if (!drv || !drv->p) - return NULL; - - klist_iter_init_node(&drv->p->klist_devices, &i, - (start ? &start->p->knode_driver : NULL)); - while ((dev = next_device(&i))) - if (match(dev, data) && get_device(dev)) - break; - klist_iter_exit(&i); - return dev; -} -EXPORT_SYMBOL_GPL(driver_find_device); - -/** - * driver_create_file - create sysfs file for driver. - * @drv: driver. - * @attr: driver attribute descriptor. - */ -int driver_create_file(struct device_driver *drv, - const struct driver_attribute *attr) -{ - int error; - - if (drv) - error = sysfs_create_file(&drv->p->kobj, &attr->attr); - else - error = -EINVAL; - return error; -} -EXPORT_SYMBOL_GPL(driver_create_file); - -/** - * driver_remove_file - remove sysfs file for driver. - * @drv: driver. - * @attr: driver attribute descriptor. - */ -void driver_remove_file(struct device_driver *drv, - const struct driver_attribute *attr) -{ - if (drv) - sysfs_remove_file(&drv->p->kobj, &attr->attr); -} -EXPORT_SYMBOL_GPL(driver_remove_file); - -int driver_add_groups(struct device_driver *drv, - const struct attribute_group **groups) -{ - return sysfs_create_groups(&drv->p->kobj, groups); -} - -void driver_remove_groups(struct device_driver *drv, - const struct attribute_group **groups) -{ - sysfs_remove_groups(&drv->p->kobj, groups); -} - -/** - * driver_register - register driver with bus - * @drv: driver to register - * - * We pass off most of the work to the bus_add_driver() call, - * since most of the things we have to do deal with the bus - * structures. - */ -int driver_register(struct device_driver *drv) -{ - int ret; - struct device_driver *other; - - BUG_ON(!drv->bus->p); - - if ((drv->bus->probe && drv->probe) || - (drv->bus->remove && drv->remove) || - (drv->bus->shutdown && drv->shutdown)) - printk(KERN_WARNING "Driver '%s' needs updating - please use " - "bus_type methods\n", drv->name); - - other = driver_find(drv->name, drv->bus); - if (other) { - printk(KERN_ERR "Error: Driver '%s' is already registered, " - "aborting...\n", drv->name); - return -EBUSY; - } - - ret = bus_add_driver(drv); - if (ret) - return ret; - ret = driver_add_groups(drv, drv->groups); - if (ret) { - bus_remove_driver(drv); - return ret; - } - kobject_uevent(&drv->p->kobj, KOBJ_ADD); - - return ret; -} -EXPORT_SYMBOL_GPL(driver_register); - -/** - * driver_unregister - remove driver from system. - * @drv: driver. - * - * Again, we pass off most of the work to the bus-level call. - */ -void driver_unregister(struct device_driver *drv) -{ - if (!drv || !drv->p) { - WARN(1, "Unexpected driver unregister!\n"); - return; - } - driver_remove_groups(drv, drv->groups); - bus_remove_driver(drv); -} -EXPORT_SYMBOL_GPL(driver_unregister); - -/** - * driver_find - locate driver on a bus by its name. - * @name: name of the driver. - * @bus: bus to scan for the driver. - * - * Call kset_find_obj() to iterate over list of drivers on - * a bus to find driver by name. Return driver if found. - * - * This routine provides no locking to prevent the driver it returns - * from being unregistered or unloaded while the caller is using it. - * The caller is responsible for preventing this. - */ -struct device_driver *driver_find(const char *name, struct bus_type *bus) -{ - struct kobject *k = kset_find_obj(bus->p->drivers_kset, name); - struct driver_private *priv; - - if (k) { - /* Drop reference added by kset_find_obj() */ - kobject_put(k); - priv = to_driver(k); - return priv->driver; - } - return NULL; -} -EXPORT_SYMBOL_GPL(driver_find); diff --git a/src/linux/drivers/base/firmware.c b/src/linux/drivers/base/firmware.c deleted file mode 100644 index 1138155..0000000 --- a/src/linux/drivers/base/firmware.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * firmware.c - firmware subsystem hoohaw. - * - * Copyright (c) 2002-3 Patrick Mochel - * Copyright (c) 2002-3 Open Source Development Labs - * Copyright (c) 2007 Greg Kroah-Hartman - * Copyright (c) 2007 Novell Inc. - * - * This file is released under the GPLv2 - */ -#include -#include -#include -#include - -#include "base.h" - -struct kobject *firmware_kobj; -EXPORT_SYMBOL_GPL(firmware_kobj); - -int __init firmware_init(void) -{ - firmware_kobj = kobject_create_and_add("firmware", NULL); - if (!firmware_kobj) - return -ENOMEM; - return 0; -} diff --git a/src/linux/drivers/base/init.c b/src/linux/drivers/base/init.c deleted file mode 100644 index 48c0e22..0000000 --- a/src/linux/drivers/base/init.c +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2002-3 Patrick Mochel - * Copyright (c) 2002-3 Open Source Development Labs - * - * This file is released under the GPLv2 - */ - -#include -#include -#include -#include - -#include "base.h" - -/** - * driver_init - initialize driver model. - * - * Call the driver model init functions to initialize their - * subsystems. Called early from init/main.c. - */ -void __init driver_init(void) -{ - /* These are the core pieces */ - devtmpfs_init(); - devices_init(); - buses_init(); - classes_init(); - firmware_init(); - hypervisor_init(); - - /* These are also core pieces, but must come after the - * core core pieces. - */ - platform_bus_init(); - cpu_dev_init(); - memory_dev_init(); - container_dev_init(); - of_core_init(); -} diff --git a/src/linux/drivers/base/map.c b/src/linux/drivers/base/map.c deleted file mode 100644 index c1d3823..0000000 --- a/src/linux/drivers/base/map.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * linux/drivers/base/map.c - * - * (C) Copyright Al Viro 2002,2003 - * Released under GPL v2. - * - * NOTE: data structure needs to be changed. It works, but for large dev_t - * it will be too slow. It is isolated, though, so these changes will be - * local to that file. - */ - -#include -#include -#include -#include -#include -#include - -struct kobj_map { - struct probe { - struct probe *next; - dev_t dev; - unsigned long range; - struct module *owner; - kobj_probe_t *get; - int (*lock)(dev_t, void *); - void *data; - } *probes[255]; - struct mutex *lock; -}; - -int kobj_map(struct kobj_map *domain, dev_t dev, unsigned long range, - struct module *module, kobj_probe_t *probe, - int (*lock)(dev_t, void *), void *data) -{ - unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1; - unsigned index = MAJOR(dev); - unsigned i; - struct probe *p; - - if (n > 255) - n = 255; - - p = kmalloc_array(n, sizeof(struct probe), GFP_KERNEL); - if (p == NULL) - return -ENOMEM; - - for (i = 0; i < n; i++, p++) { - p->owner = module; - p->get = probe; - p->lock = lock; - p->dev = dev; - p->range = range; - p->data = data; - } - mutex_lock(domain->lock); - for (i = 0, p -= n; i < n; i++, p++, index++) { - struct probe **s = &domain->probes[index % 255]; - while (*s && (*s)->range < range) - s = &(*s)->next; - p->next = *s; - *s = p; - } - mutex_unlock(domain->lock); - return 0; -} - -void kobj_unmap(struct kobj_map *domain, dev_t dev, unsigned long range) -{ - unsigned n = MAJOR(dev + range - 1) - MAJOR(dev) + 1; - unsigned index = MAJOR(dev); - unsigned i; - struct probe *found = NULL; - - if (n > 255) - n = 255; - - mutex_lock(domain->lock); - for (i = 0; i < n; i++, index++) { - struct probe **s; - for (s = &domain->probes[index % 255]; *s; s = &(*s)->next) { - struct probe *p = *s; - if (p->dev == dev && p->range == range) { - *s = p->next; - if (!found) - found = p; - break; - } - } - } - mutex_unlock(domain->lock); - kfree(found); -} - -struct kobject *kobj_lookup(struct kobj_map *domain, dev_t dev, int *index) -{ - struct kobject *kobj; - struct probe *p; - unsigned long best = ~0UL; - -retry: - mutex_lock(domain->lock); - for (p = domain->probes[MAJOR(dev) % 255]; p; p = p->next) { - struct kobject *(*probe)(dev_t, int *, void *); - struct module *owner; - void *data; - - if (p->dev > dev || p->dev + p->range - 1 < dev) - continue; - if (p->range - 1 >= best) - break; - if (!try_module_get(p->owner)) - continue; - owner = p->owner; - data = p->data; - probe = p->get; - best = p->range - 1; - *index = dev - p->dev; - if (p->lock && p->lock(dev, data) < 0) { - module_put(owner); - continue; - } - mutex_unlock(domain->lock); - kobj = probe(dev, index, data); - /* Currently ->owner protects _only_ ->probe() itself. */ - module_put(owner); - if (kobj) - return kobj; - goto retry; - } - mutex_unlock(domain->lock); - return NULL; -} - -struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock) -{ - struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL); - struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL); - int i; - - if ((p == NULL) || (base == NULL)) { - kfree(p); - kfree(base); - return NULL; - } - - base->dev = 1; - base->range = ~0; - base->get = base_probe; - for (i = 0; i < 255; i++) - p->probes[i] = base; - p->lock = lock; - return p; -} diff --git a/src/linux/drivers/base/platform.c b/src/linux/drivers/base/platform.c deleted file mode 100644 index c4af003..0000000 --- a/src/linux/drivers/base/platform.c +++ /dev/null @@ -1,1453 +0,0 @@ -/* - * platform.c - platform 'pseudo' bus for legacy devices - * - * Copyright (c) 2002-3 Patrick Mochel - * Copyright (c) 2002-3 Open Source Development Labs - * - * This file is released under the GPLv2 - * - * Please see Documentation/driver-model/platform.txt for more - * information. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "base.h" -#include "power/power.h" - -/* For automatically allocated device IDs */ -static DEFINE_IDA(platform_devid_ida); - -struct device platform_bus = { - .init_name = "platform", -}; -EXPORT_SYMBOL_GPL(platform_bus); - -/** - * arch_setup_pdev_archdata - Allow manipulation of archdata before its used - * @pdev: platform device - * - * This is called before platform_device_add() such that any pdev_archdata may - * be setup before the platform_notifier is called. So if a user needs to - * manipulate any relevant information in the pdev_archdata they can do: - * - * platform_device_alloc() - * ... manipulate ... - * platform_device_add() - * - * And if they don't care they can just call platform_device_register() and - * everything will just work out. - */ -void __weak arch_setup_pdev_archdata(struct platform_device *pdev) -{ -} - -/** - * platform_get_resource - get a resource for a device - * @dev: platform device - * @type: resource type - * @num: resource index - */ -struct resource *platform_get_resource(struct platform_device *dev, - unsigned int type, unsigned int num) -{ - int i; - - for (i = 0; i < dev->num_resources; i++) { - struct resource *r = &dev->resource[i]; - - if (type == resource_type(r) && num-- == 0) - return r; - } - return NULL; -} -EXPORT_SYMBOL_GPL(platform_get_resource); - -/** - * platform_get_irq - get an IRQ for a device - * @dev: platform device - * @num: IRQ number index - */ -int platform_get_irq(struct platform_device *dev, unsigned int num) -{ -#ifdef CONFIG_SPARC - /* sparc does not have irqs represented as IORESOURCE_IRQ resources */ - if (!dev || num >= dev->archdata.num_irqs) - return -ENXIO; - return dev->archdata.irqs[num]; -#else - struct resource *r; - if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) { - int ret; - - ret = of_irq_get(dev->dev.of_node, num); - if (ret > 0 || ret == -EPROBE_DEFER) - return ret; - } - - r = platform_get_resource(dev, IORESOURCE_IRQ, num); - /* - * The resources may pass trigger flags to the irqs that need - * to be set up. It so happens that the trigger flags for - * IORESOURCE_BITS correspond 1-to-1 to the IRQF_TRIGGER* - * settings. - */ - if (r && r->flags & IORESOURCE_BITS) { - struct irq_data *irqd; - - irqd = irq_get_irq_data(r->start); - if (!irqd) - return -ENXIO; - irqd_set_trigger_type(irqd, r->flags & IORESOURCE_BITS); - } - - return r ? r->start : -ENXIO; -#endif -} -EXPORT_SYMBOL_GPL(platform_get_irq); - -/** - * platform_irq_count - Count the number of IRQs a platform device uses - * @dev: platform device - * - * Return: Number of IRQs a platform device uses or EPROBE_DEFER - */ -int platform_irq_count(struct platform_device *dev) -{ - int ret, nr = 0; - - while ((ret = platform_get_irq(dev, nr)) >= 0) - nr++; - - if (ret == -EPROBE_DEFER) - return ret; - - return nr; -} -EXPORT_SYMBOL_GPL(platform_irq_count); - -/** - * platform_get_resource_byname - get a resource for a device by name - * @dev: platform device - * @type: resource type - * @name: resource name - */ -struct resource *platform_get_resource_byname(struct platform_device *dev, - unsigned int type, - const char *name) -{ - int i; - - for (i = 0; i < dev->num_resources; i++) { - struct resource *r = &dev->resource[i]; - - if (unlikely(!r->name)) - continue; - - if (type == resource_type(r) && !strcmp(r->name, name)) - return r; - } - return NULL; -} -EXPORT_SYMBOL_GPL(platform_get_resource_byname); - -/** - * platform_get_irq_byname - get an IRQ for a device by name - * @dev: platform device - * @name: IRQ name - */ -int platform_get_irq_byname(struct platform_device *dev, const char *name) -{ - struct resource *r; - - if (IS_ENABLED(CONFIG_OF_IRQ) && dev->dev.of_node) { - int ret; - - ret = of_irq_get_byname(dev->dev.of_node, name); - if (ret > 0 || ret == -EPROBE_DEFER) - return ret; - } - - r = platform_get_resource_byname(dev, IORESOURCE_IRQ, name); - return r ? r->start : -ENXIO; -} -EXPORT_SYMBOL_GPL(platform_get_irq_byname); - -/** - * platform_add_devices - add a numbers of platform devices - * @devs: array of platform devices to add - * @num: number of platform devices in array - */ -int platform_add_devices(struct platform_device **devs, int num) -{ - int i, ret = 0; - - for (i = 0; i < num; i++) { - ret = platform_device_register(devs[i]); - if (ret) { - while (--i >= 0) - platform_device_unregister(devs[i]); - break; - } - } - - return ret; -} -EXPORT_SYMBOL_GPL(platform_add_devices); - -struct platform_object { - struct platform_device pdev; - char name[]; -}; - -/** - * platform_device_put - destroy a platform device - * @pdev: platform device to free - * - * Free all memory associated with a platform device. This function must - * _only_ be externally called in error cases. All other usage is a bug. - */ -void platform_device_put(struct platform_device *pdev) -{ - if (pdev) - put_device(&pdev->dev); -} -EXPORT_SYMBOL_GPL(platform_device_put); - -static void platform_device_release(struct device *dev) -{ - struct platform_object *pa = container_of(dev, struct platform_object, - pdev.dev); - - of_device_node_put(&pa->pdev.dev); - kfree(pa->pdev.dev.platform_data); - kfree(pa->pdev.mfd_cell); - kfree(pa->pdev.resource); - kfree(pa->pdev.driver_override); - kfree(pa); -} - -/** - * platform_device_alloc - create a platform device - * @name: base name of the device we're adding - * @id: instance id - * - * Create a platform device object which can have other objects attached - * to it, and which will have attached objects freed when it is released. - */ -struct platform_device *platform_device_alloc(const char *name, int id) -{ - struct platform_object *pa; - - pa = kzalloc(sizeof(*pa) + strlen(name) + 1, GFP_KERNEL); - if (pa) { - strcpy(pa->name, name); - pa->pdev.name = pa->name; - pa->pdev.id = id; - device_initialize(&pa->pdev.dev); - pa->pdev.dev.release = platform_device_release; - arch_setup_pdev_archdata(&pa->pdev); - } - - return pa ? &pa->pdev : NULL; -} -EXPORT_SYMBOL_GPL(platform_device_alloc); - -/** - * platform_device_add_resources - add resources to a platform device - * @pdev: platform device allocated by platform_device_alloc to add resources to - * @res: set of resources that needs to be allocated for the device - * @num: number of resources - * - * Add a copy of the resources to the platform device. The memory - * associated with the resources will be freed when the platform device is - * released. - */ -int platform_device_add_resources(struct platform_device *pdev, - const struct resource *res, unsigned int num) -{ - struct resource *r = NULL; - - if (res) { - r = kmemdup(res, sizeof(struct resource) * num, GFP_KERNEL); - if (!r) - return -ENOMEM; - } - - kfree(pdev->resource); - pdev->resource = r; - pdev->num_resources = num; - return 0; -} -EXPORT_SYMBOL_GPL(platform_device_add_resources); - -/** - * platform_device_add_data - add platform-specific data to a platform device - * @pdev: platform device allocated by platform_device_alloc to add resources to - * @data: platform specific data for this platform device - * @size: size of platform specific data - * - * Add a copy of platform specific data to the platform device's - * platform_data pointer. The memory associated with the platform data - * will be freed when the platform device is released. - */ -int platform_device_add_data(struct platform_device *pdev, const void *data, - size_t size) -{ - void *d = NULL; - - if (data) { - d = kmemdup(data, size, GFP_KERNEL); - if (!d) - return -ENOMEM; - } - - kfree(pdev->dev.platform_data); - pdev->dev.platform_data = d; - return 0; -} -EXPORT_SYMBOL_GPL(platform_device_add_data); - -/** - * platform_device_add_properties - add built-in properties to a platform device - * @pdev: platform device to add properties to - * @properties: null terminated array of properties to add - * - * The function will take deep copy of @properties and attach the copy to the - * platform device. The memory associated with properties will be freed when the - * platform device is released. - */ -int platform_device_add_properties(struct platform_device *pdev, - struct property_entry *properties) -{ - return device_add_properties(&pdev->dev, properties); -} -EXPORT_SYMBOL_GPL(platform_device_add_properties); - -/** - * platform_device_add - add a platform device to device hierarchy - * @pdev: platform device we're adding - * - * This is part 2 of platform_device_register(), though may be called - * separately _iff_ pdev was allocated by platform_device_alloc(). - */ -int platform_device_add(struct platform_device *pdev) -{ - int i, ret; - - if (!pdev) - return -EINVAL; - - if (!pdev->dev.parent) - pdev->dev.parent = &platform_bus; - - pdev->dev.bus = &platform_bus_type; - - switch (pdev->id) { - default: - dev_set_name(&pdev->dev, "%s.%d", pdev->name, pdev->id); - break; - case PLATFORM_DEVID_NONE: - dev_set_name(&pdev->dev, "%s", pdev->name); - break; - case PLATFORM_DEVID_AUTO: - /* - * Automatically allocated device ID. We mark it as such so - * that we remember it must be freed, and we append a suffix - * to avoid namespace collision with explicit IDs. - */ - ret = ida_simple_get(&platform_devid_ida, 0, 0, GFP_KERNEL); - if (ret < 0) - goto err_out; - pdev->id = ret; - pdev->id_auto = true; - dev_set_name(&pdev->dev, "%s.%d.auto", pdev->name, pdev->id); - break; - } - - for (i = 0; i < pdev->num_resources; i++) { - struct resource *p, *r = &pdev->resource[i]; - - if (r->name == NULL) - r->name = dev_name(&pdev->dev); - - p = r->parent; - if (!p) { - if (resource_type(r) == IORESOURCE_MEM) - p = &iomem_resource; - else if (resource_type(r) == IORESOURCE_IO) - p = &ioport_resource; - } - - if (p && insert_resource(p, r)) { - dev_err(&pdev->dev, "failed to claim resource %d\n", i); - ret = -EBUSY; - goto failed; - } - } - - pr_debug("Registering platform device '%s'. Parent at %s\n", - dev_name(&pdev->dev), dev_name(pdev->dev.parent)); - - ret = device_add(&pdev->dev); - if (ret == 0) - return ret; - - failed: - if (pdev->id_auto) { - ida_simple_remove(&platform_devid_ida, pdev->id); - pdev->id = PLATFORM_DEVID_AUTO; - } - - while (--i >= 0) { - struct resource *r = &pdev->resource[i]; - if (r->parent) - release_resource(r); - } - - err_out: - return ret; -} -EXPORT_SYMBOL_GPL(platform_device_add); - -/** - * platform_device_del - remove a platform-level device - * @pdev: platform device we're removing - * - * Note that this function will also release all memory- and port-based - * resources owned by the device (@dev->resource). This function must - * _only_ be externally called in error cases. All other usage is a bug. - */ -void platform_device_del(struct platform_device *pdev) -{ - int i; - - if (pdev) { - device_remove_properties(&pdev->dev); - device_del(&pdev->dev); - - if (pdev->id_auto) { - ida_simple_remove(&platform_devid_ida, pdev->id); - pdev->id = PLATFORM_DEVID_AUTO; - } - - for (i = 0; i < pdev->num_resources; i++) { - struct resource *r = &pdev->resource[i]; - if (r->parent) - release_resource(r); - } - } -} -EXPORT_SYMBOL_GPL(platform_device_del); - -/** - * platform_device_register - add a platform-level device - * @pdev: platform device we're adding - */ -int platform_device_register(struct platform_device *pdev) -{ - device_initialize(&pdev->dev); - arch_setup_pdev_archdata(pdev); - return platform_device_add(pdev); -} -EXPORT_SYMBOL_GPL(platform_device_register); - -/** - * platform_device_unregister - unregister a platform-level device - * @pdev: platform device we're unregistering - * - * Unregistration is done in 2 steps. First we release all resources - * and remove it from the subsystem, then we drop reference count by - * calling platform_device_put(). - */ -void platform_device_unregister(struct platform_device *pdev) -{ - platform_device_del(pdev); - platform_device_put(pdev); -} -EXPORT_SYMBOL_GPL(platform_device_unregister); - -/** - * platform_device_register_full - add a platform-level device with - * resources and platform-specific data - * - * @pdevinfo: data used to create device - * - * Returns &struct platform_device pointer on success, or ERR_PTR() on error. - */ -struct platform_device *platform_device_register_full( - const struct platform_device_info *pdevinfo) -{ - int ret = -ENOMEM; - struct platform_device *pdev; - - pdev = platform_device_alloc(pdevinfo->name, pdevinfo->id); - if (!pdev) - goto err_alloc; - - pdev->dev.parent = pdevinfo->parent; - pdev->dev.fwnode = pdevinfo->fwnode; - - if (pdevinfo->dma_mask) { - /* - * This memory isn't freed when the device is put, - * I don't have a nice idea for that though. Conceptually - * dma_mask in struct device should not be a pointer. - * See http://thread.gmane.org/gmane.linux.kernel.pci/9081 - */ - pdev->dev.dma_mask = - kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL); - if (!pdev->dev.dma_mask) - goto err; - - *pdev->dev.dma_mask = pdevinfo->dma_mask; - pdev->dev.coherent_dma_mask = pdevinfo->dma_mask; - } - - ret = platform_device_add_resources(pdev, - pdevinfo->res, pdevinfo->num_res); - if (ret) - goto err; - - ret = platform_device_add_data(pdev, - pdevinfo->data, pdevinfo->size_data); - if (ret) - goto err; - - if (pdevinfo->properties) { - ret = platform_device_add_properties(pdev, - pdevinfo->properties); - if (ret) - goto err; - } - - ret = platform_device_add(pdev); - if (ret) { -err: - ACPI_COMPANION_SET(&pdev->dev, NULL); - kfree(pdev->dev.dma_mask); - -err_alloc: - platform_device_put(pdev); - return ERR_PTR(ret); - } - - return pdev; -} -EXPORT_SYMBOL_GPL(platform_device_register_full); - -static int platform_drv_probe(struct device *_dev) -{ - struct platform_driver *drv = to_platform_driver(_dev->driver); - struct platform_device *dev = to_platform_device(_dev); - int ret; - - ret = of_clk_set_defaults(_dev->of_node, false); - if (ret < 0) - return ret; - - ret = dev_pm_domain_attach(_dev, true); - if (ret != -EPROBE_DEFER) { - if (drv->probe) { - ret = drv->probe(dev); - if (ret) - dev_pm_domain_detach(_dev, true); - } else { - /* don't fail if just dev_pm_domain_attach failed */ - ret = 0; - } - } - - if (drv->prevent_deferred_probe && ret == -EPROBE_DEFER) { - dev_warn(_dev, "probe deferral not supported\n"); - ret = -ENXIO; - } - - return ret; -} - -static int platform_drv_probe_fail(struct device *_dev) -{ - return -ENXIO; -} - -static int platform_drv_remove(struct device *_dev) -{ - struct platform_driver *drv = to_platform_driver(_dev->driver); - struct platform_device *dev = to_platform_device(_dev); - int ret = 0; - - if (drv->remove) - ret = drv->remove(dev); - dev_pm_domain_detach(_dev, true); - - return ret; -} - -static void platform_drv_shutdown(struct device *_dev) -{ - struct platform_driver *drv = to_platform_driver(_dev->driver); - struct platform_device *dev = to_platform_device(_dev); - - if (drv->shutdown) - drv->shutdown(dev); -} - -/** - * __platform_driver_register - register a driver for platform-level devices - * @drv: platform driver structure - * @owner: owning module/driver - */ -int __platform_driver_register(struct platform_driver *drv, - struct module *owner) -{ - drv->driver.owner = owner; - drv->driver.bus = &platform_bus_type; - drv->driver.probe = platform_drv_probe; - drv->driver.remove = platform_drv_remove; - drv->driver.shutdown = platform_drv_shutdown; - - return driver_register(&drv->driver); -} -EXPORT_SYMBOL_GPL(__platform_driver_register); - -/** - * platform_driver_unregister - unregister a driver for platform-level devices - * @drv: platform driver structure - */ -void platform_driver_unregister(struct platform_driver *drv) -{ - driver_unregister(&drv->driver); -} -EXPORT_SYMBOL_GPL(platform_driver_unregister); - -/** - * __platform_driver_probe - register driver for non-hotpluggable device - * @drv: platform driver structure - * @probe: the driver probe routine, probably from an __init section - * @module: module which will be the owner of the driver - * - * Use this instead of platform_driver_register() when you know the device - * is not hotpluggable and has already been registered, and you want to - * remove its run-once probe() infrastructure from memory after the driver - * has bound to the device. - * - * One typical use for this would be with drivers for controllers integrated - * into system-on-chip processors, where the controller devices have been - * configured as part of board setup. - * - * Note that this is incompatible with deferred probing. - * - * Returns zero if the driver registered and bound to a device, else returns - * a negative error code and with the driver not registered. - */ -int __init_or_module __platform_driver_probe(struct platform_driver *drv, - int (*probe)(struct platform_device *), struct module *module) -{ - int retval, code; - - if (drv->driver.probe_type == PROBE_PREFER_ASYNCHRONOUS) { - pr_err("%s: drivers registered with %s can not be probed asynchronously\n", - drv->driver.name, __func__); - return -EINVAL; - } - - /* - * We have to run our probes synchronously because we check if - * we find any devices to bind to and exit with error if there - * are any. - */ - drv->driver.probe_type = PROBE_FORCE_SYNCHRONOUS; - - /* - * Prevent driver from requesting probe deferral to avoid further - * futile probe attempts. - */ - drv->prevent_deferred_probe = true; - - /* make sure driver won't have bind/unbind attributes */ - drv->driver.suppress_bind_attrs = true; - - /* temporary section violation during probe() */ - drv->probe = probe; - retval = code = __platform_driver_register(drv, module); - - /* - * Fixup that section violation, being paranoid about code scanning - * the list of drivers in order to probe new devices. Check to see - * if the probe was successful, and make sure any forced probes of - * new devices fail. - */ - spin_lock(&drv->driver.bus->p->klist_drivers.k_lock); - drv->probe = NULL; - if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list)) - retval = -ENODEV; - drv->driver.probe = platform_drv_probe_fail; - spin_unlock(&drv->driver.bus->p->klist_drivers.k_lock); - - if (code != retval) - platform_driver_unregister(drv); - return retval; -} -EXPORT_SYMBOL_GPL(__platform_driver_probe); - -/** - * __platform_create_bundle - register driver and create corresponding device - * @driver: platform driver structure - * @probe: the driver probe routine, probably from an __init section - * @res: set of resources that needs to be allocated for the device - * @n_res: number of resources - * @data: platform specific data for this platform device - * @size: size of platform specific data - * @module: module which will be the owner of the driver - * - * Use this in legacy-style modules that probe hardware directly and - * register a single platform device and corresponding platform driver. - * - * Returns &struct platform_device pointer on success, or ERR_PTR() on error. - */ -struct platform_device * __init_or_module __platform_create_bundle( - struct platform_driver *driver, - int (*probe)(struct platform_device *), - struct resource *res, unsigned int n_res, - const void *data, size_t size, struct module *module) -{ - struct platform_device *pdev; - int error; - - pdev = platform_device_alloc(driver->driver.name, -1); - if (!pdev) { - error = -ENOMEM; - goto err_out; - } - - error = platform_device_add_resources(pdev, res, n_res); - if (error) - goto err_pdev_put; - - error = platform_device_add_data(pdev, data, size); - if (error) - goto err_pdev_put; - - error = platform_device_add(pdev); - if (error) - goto err_pdev_put; - - error = __platform_driver_probe(driver, probe, module); - if (error) - goto err_pdev_del; - - return pdev; - -err_pdev_del: - platform_device_del(pdev); -err_pdev_put: - platform_device_put(pdev); -err_out: - return ERR_PTR(error); -} -EXPORT_SYMBOL_GPL(__platform_create_bundle); - -/** - * __platform_register_drivers - register an array of platform drivers - * @drivers: an array of drivers to register - * @count: the number of drivers to register - * @owner: module owning the drivers - * - * Registers platform drivers specified by an array. On failure to register a - * driver, all previously registered drivers will be unregistered. Callers of - * this API should use platform_unregister_drivers() to unregister drivers in - * the reverse order. - * - * Returns: 0 on success or a negative error code on failure. - */ -int __platform_register_drivers(struct platform_driver * const *drivers, - unsigned int count, struct module *owner) -{ - unsigned int i; - int err; - - for (i = 0; i < count; i++) { - pr_debug("registering platform driver %ps\n", drivers[i]); - - err = __platform_driver_register(drivers[i], owner); - if (err < 0) { - pr_err("failed to register platform driver %ps: %d\n", - drivers[i], err); - goto error; - } - } - - return 0; - -error: - while (i--) { - pr_debug("unregistering platform driver %ps\n", drivers[i]); - platform_driver_unregister(drivers[i]); - } - - return err; -} -EXPORT_SYMBOL_GPL(__platform_register_drivers); - -/** - * platform_unregister_drivers - unregister an array of platform drivers - * @drivers: an array of drivers to unregister - * @count: the number of drivers to unregister - * - * Unegisters platform drivers specified by an array. This is typically used - * to complement an earlier call to platform_register_drivers(). Drivers are - * unregistered in the reverse order in which they were registered. - */ -void platform_unregister_drivers(struct platform_driver * const *drivers, - unsigned int count) -{ - while (count--) { - pr_debug("unregistering platform driver %ps\n", drivers[count]); - platform_driver_unregister(drivers[count]); - } -} -EXPORT_SYMBOL_GPL(platform_unregister_drivers); - -/* modalias support enables more hands-off userspace setup: - * (a) environment variable lets new-style hotplug events work once system is - * fully running: "modprobe $MODALIAS" - * (b) sysfs attribute lets new-style coldplug recover from hotplug events - * mishandled before system is fully running: "modprobe $(cat modalias)" - */ -static ssize_t modalias_show(struct device *dev, struct device_attribute *a, - char *buf) -{ - struct platform_device *pdev = to_platform_device(dev); - int len; - - len = of_device_get_modalias(dev, buf, PAGE_SIZE -1); - if (len != -ENODEV) - return len; - - len = acpi_device_modalias(dev, buf, PAGE_SIZE -1); - if (len != -ENODEV) - return len; - - len = snprintf(buf, PAGE_SIZE, "platform:%s\n", pdev->name); - - return (len >= PAGE_SIZE) ? (PAGE_SIZE - 1) : len; -} -static DEVICE_ATTR_RO(modalias); - -static ssize_t driver_override_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct platform_device *pdev = to_platform_device(dev); - char *driver_override, *old = pdev->driver_override, *cp; - - if (count > PATH_MAX) - return -EINVAL; - - driver_override = kstrndup(buf, count, GFP_KERNEL); - if (!driver_override) - return -ENOMEM; - - cp = strchr(driver_override, '\n'); - if (cp) - *cp = '\0'; - - if (strlen(driver_override)) { - pdev->driver_override = driver_override; - } else { - kfree(driver_override); - pdev->driver_override = NULL; - } - - kfree(old); - - return count; -} - -static ssize_t driver_override_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct platform_device *pdev = to_platform_device(dev); - - return sprintf(buf, "%s\n", pdev->driver_override); -} -static DEVICE_ATTR_RW(driver_override); - - -static struct attribute *platform_dev_attrs[] = { - &dev_attr_modalias.attr, - &dev_attr_driver_override.attr, - NULL, -}; -ATTRIBUTE_GROUPS(platform_dev); - -static int platform_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct platform_device *pdev = to_platform_device(dev); - int rc; - - /* Some devices have extra OF data and an OF-style MODALIAS */ - rc = of_device_uevent_modalias(dev, env); - if (rc != -ENODEV) - return rc; - - rc = acpi_device_uevent_modalias(dev, env); - if (rc != -ENODEV) - return rc; - - add_uevent_var(env, "MODALIAS=%s%s", PLATFORM_MODULE_PREFIX, - pdev->name); - return 0; -} - -static const struct platform_device_id *platform_match_id( - const struct platform_device_id *id, - struct platform_device *pdev) -{ - while (id->name[0]) { - if (strcmp(pdev->name, id->name) == 0) { - pdev->id_entry = id; - return id; - } - id++; - } - return NULL; -} - -/** - * platform_match - bind platform device to platform driver. - * @dev: device. - * @drv: driver. - * - * Platform device IDs are assumed to be encoded like this: - * "", where is a short description of the type of - * device, like "pci" or "floppy", and is the enumerated - * instance of the device, like '0' or '42'. Driver IDs are simply - * "". So, extract the from the platform_device structure, - * and compare it against the name of the driver. Return whether they match - * or not. - */ -static int platform_match(struct device *dev, struct device_driver *drv) -{ - struct platform_device *pdev = to_platform_device(dev); - struct platform_driver *pdrv = to_platform_driver(drv); - - /* When driver_override is set, only bind to the matching driver */ - if (pdev->driver_override) - return !strcmp(pdev->driver_override, drv->name); - - /* Attempt an OF style match first */ - if (of_driver_match_device(dev, drv)) - return 1; - - /* Then try ACPI style match */ - if (acpi_driver_match_device(dev, drv)) - return 1; - - /* Then try to match against the id table */ - if (pdrv->id_table) - return platform_match_id(pdrv->id_table, pdev) != NULL; - - /* fall-back to driver name match */ - return (strcmp(pdev->name, drv->name) == 0); -} - -#ifdef CONFIG_PM_SLEEP - -static int platform_legacy_suspend(struct device *dev, pm_message_t mesg) -{ - struct platform_driver *pdrv = to_platform_driver(dev->driver); - struct platform_device *pdev = to_platform_device(dev); - int ret = 0; - - if (dev->driver && pdrv->suspend) - ret = pdrv->suspend(pdev, mesg); - - return ret; -} - -static int platform_legacy_resume(struct device *dev) -{ - struct platform_driver *pdrv = to_platform_driver(dev->driver); - struct platform_device *pdev = to_platform_device(dev); - int ret = 0; - - if (dev->driver && pdrv->resume) - ret = pdrv->resume(pdev); - - return ret; -} - -#endif /* CONFIG_PM_SLEEP */ - -#ifdef CONFIG_SUSPEND - -int platform_pm_suspend(struct device *dev) -{ - struct device_driver *drv = dev->driver; - int ret = 0; - - if (!drv) - return 0; - - if (drv->pm) { - if (drv->pm->suspend) - ret = drv->pm->suspend(dev); - } else { - ret = platform_legacy_suspend(dev, PMSG_SUSPEND); - } - - return ret; -} - -int platform_pm_resume(struct device *dev) -{ - struct device_driver *drv = dev->driver; - int ret = 0; - - if (!drv) - return 0; - - if (drv->pm) { - if (drv->pm->resume) - ret = drv->pm->resume(dev); - } else { - ret = platform_legacy_resume(dev); - } - - return ret; -} - -#endif /* CONFIG_SUSPEND */ - -#ifdef CONFIG_HIBERNATE_CALLBACKS - -int platform_pm_freeze(struct device *dev) -{ - struct device_driver *drv = dev->driver; - int ret = 0; - - if (!drv) - return 0; - - if (drv->pm) { - if (drv->pm->freeze) - ret = drv->pm->freeze(dev); - } else { - ret = platform_legacy_suspend(dev, PMSG_FREEZE); - } - - return ret; -} - -int platform_pm_thaw(struct device *dev) -{ - struct device_driver *drv = dev->driver; - int ret = 0; - - if (!drv) - return 0; - - if (drv->pm) { - if (drv->pm->thaw) - ret = drv->pm->thaw(dev); - } else { - ret = platform_legacy_resume(dev); - } - - return ret; -} - -int platform_pm_poweroff(struct device *dev) -{ - struct device_driver *drv = dev->driver; - int ret = 0; - - if (!drv) - return 0; - - if (drv->pm) { - if (drv->pm->poweroff) - ret = drv->pm->poweroff(dev); - } else { - ret = platform_legacy_suspend(dev, PMSG_HIBERNATE); - } - - return ret; -} - -int platform_pm_restore(struct device *dev) -{ - struct device_driver *drv = dev->driver; - int ret = 0; - - if (!drv) - return 0; - - if (drv->pm) { - if (drv->pm->restore) - ret = drv->pm->restore(dev); - } else { - ret = platform_legacy_resume(dev); - } - - return ret; -} - -#endif /* CONFIG_HIBERNATE_CALLBACKS */ - -static const struct dev_pm_ops platform_dev_pm_ops = { - .runtime_suspend = pm_generic_runtime_suspend, - .runtime_resume = pm_generic_runtime_resume, - USE_PLATFORM_PM_SLEEP_OPS -}; - -struct bus_type platform_bus_type = { - .name = "platform", - .dev_groups = platform_dev_groups, - .match = platform_match, - .uevent = platform_uevent, - .pm = &platform_dev_pm_ops, -}; -EXPORT_SYMBOL_GPL(platform_bus_type); - -int __init platform_bus_init(void) -{ - int error; - - early_platform_cleanup(); - - error = device_register(&platform_bus); - if (error) - return error; - error = bus_register(&platform_bus_type); - if (error) - device_unregister(&platform_bus); - of_platform_register_reconfig_notifier(); - return error; -} - -#ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK -u64 dma_get_required_mask(struct device *dev) -{ - u32 low_totalram = ((max_pfn - 1) << PAGE_SHIFT); - u32 high_totalram = ((max_pfn - 1) >> (32 - PAGE_SHIFT)); - u64 mask; - - if (!high_totalram) { - /* convert to mask just covering totalram */ - low_totalram = (1 << (fls(low_totalram) - 1)); - low_totalram += low_totalram - 1; - mask = low_totalram; - } else { - high_totalram = (1 << (fls(high_totalram) - 1)); - high_totalram += high_totalram - 1; - mask = (((u64)high_totalram) << 32) + 0xffffffff; - } - return mask; -} -EXPORT_SYMBOL_GPL(dma_get_required_mask); -#endif - -static __initdata LIST_HEAD(early_platform_driver_list); -static __initdata LIST_HEAD(early_platform_device_list); - -/** - * early_platform_driver_register - register early platform driver - * @epdrv: early_platform driver structure - * @buf: string passed from early_param() - * - * Helper function for early_platform_init() / early_platform_init_buffer() - */ -int __init early_platform_driver_register(struct early_platform_driver *epdrv, - char *buf) -{ - char *tmp; - int n; - - /* Simply add the driver to the end of the global list. - * Drivers will by default be put on the list in compiled-in order. - */ - if (!epdrv->list.next) { - INIT_LIST_HEAD(&epdrv->list); - list_add_tail(&epdrv->list, &early_platform_driver_list); - } - - /* If the user has specified device then make sure the driver - * gets prioritized. The driver of the last device specified on - * command line will be put first on the list. - */ - n = strlen(epdrv->pdrv->driver.name); - if (buf && !strncmp(buf, epdrv->pdrv->driver.name, n)) { - list_move(&epdrv->list, &early_platform_driver_list); - - /* Allow passing parameters after device name */ - if (buf[n] == '\0' || buf[n] == ',') - epdrv->requested_id = -1; - else { - epdrv->requested_id = simple_strtoul(&buf[n + 1], - &tmp, 10); - - if (buf[n] != '.' || (tmp == &buf[n + 1])) { - epdrv->requested_id = EARLY_PLATFORM_ID_ERROR; - n = 0; - } else - n += strcspn(&buf[n + 1], ",") + 1; - } - - if (buf[n] == ',') - n++; - - if (epdrv->bufsize) { - memcpy(epdrv->buffer, &buf[n], - min_t(int, epdrv->bufsize, strlen(&buf[n]) + 1)); - epdrv->buffer[epdrv->bufsize - 1] = '\0'; - } - } - - return 0; -} - -/** - * early_platform_add_devices - adds a number of early platform devices - * @devs: array of early platform devices to add - * @num: number of early platform devices in array - * - * Used by early architecture code to register early platform devices and - * their platform data. - */ -void __init early_platform_add_devices(struct platform_device **devs, int num) -{ - struct device *dev; - int i; - - /* simply add the devices to list */ - for (i = 0; i < num; i++) { - dev = &devs[i]->dev; - - if (!dev->devres_head.next) { - pm_runtime_early_init(dev); - INIT_LIST_HEAD(&dev->devres_head); - list_add_tail(&dev->devres_head, - &early_platform_device_list); - } - } -} - -/** - * early_platform_driver_register_all - register early platform drivers - * @class_str: string to identify early platform driver class - * - * Used by architecture code to register all early platform drivers - * for a certain class. If omitted then only early platform drivers - * with matching kernel command line class parameters will be registered. - */ -void __init early_platform_driver_register_all(char *class_str) -{ - /* The "class_str" parameter may or may not be present on the kernel - * command line. If it is present then there may be more than one - * matching parameter. - * - * Since we register our early platform drivers using early_param() - * we need to make sure that they also get registered in the case - * when the parameter is missing from the kernel command line. - * - * We use parse_early_options() to make sure the early_param() gets - * called at least once. The early_param() may be called more than - * once since the name of the preferred device may be specified on - * the kernel command line. early_platform_driver_register() handles - * this case for us. - */ - parse_early_options(class_str); -} - -/** - * early_platform_match - find early platform device matching driver - * @epdrv: early platform driver structure - * @id: id to match against - */ -static struct platform_device * __init -early_platform_match(struct early_platform_driver *epdrv, int id) -{ - struct platform_device *pd; - - list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) - if (platform_match(&pd->dev, &epdrv->pdrv->driver)) - if (pd->id == id) - return pd; - - return NULL; -} - -/** - * early_platform_left - check if early platform driver has matching devices - * @epdrv: early platform driver structure - * @id: return true if id or above exists - */ -static int __init early_platform_left(struct early_platform_driver *epdrv, - int id) -{ - struct platform_device *pd; - - list_for_each_entry(pd, &early_platform_device_list, dev.devres_head) - if (platform_match(&pd->dev, &epdrv->pdrv->driver)) - if (pd->id >= id) - return 1; - - return 0; -} - -/** - * early_platform_driver_probe_id - probe drivers matching class_str and id - * @class_str: string to identify early platform driver class - * @id: id to match against - * @nr_probe: number of platform devices to successfully probe before exiting - */ -static int __init early_platform_driver_probe_id(char *class_str, - int id, - int nr_probe) -{ - struct early_platform_driver *epdrv; - struct platform_device *match; - int match_id; - int n = 0; - int left = 0; - - list_for_each_entry(epdrv, &early_platform_driver_list, list) { - /* only use drivers matching our class_str */ - if (strcmp(class_str, epdrv->class_str)) - continue; - - if (id == -2) { - match_id = epdrv->requested_id; - left = 1; - - } else { - match_id = id; - left += early_platform_left(epdrv, id); - - /* skip requested id */ - switch (epdrv->requested_id) { - case EARLY_PLATFORM_ID_ERROR: - case EARLY_PLATFORM_ID_UNSET: - break; - default: - if (epdrv->requested_id == id) - match_id = EARLY_PLATFORM_ID_UNSET; - } - } - - switch (match_id) { - case EARLY_PLATFORM_ID_ERROR: - pr_warn("%s: unable to parse %s parameter\n", - class_str, epdrv->pdrv->driver.name); - /* fall-through */ - case EARLY_PLATFORM_ID_UNSET: - match = NULL; - break; - default: - match = early_platform_match(epdrv, match_id); - } - - if (match) { - /* - * Set up a sensible init_name to enable - * dev_name() and others to be used before the - * rest of the driver core is initialized. - */ - if (!match->dev.init_name && slab_is_available()) { - if (match->id != -1) - match->dev.init_name = - kasprintf(GFP_KERNEL, "%s.%d", - match->name, - match->id); - else - match->dev.init_name = - kasprintf(GFP_KERNEL, "%s", - match->name); - - if (!match->dev.init_name) - return -ENOMEM; - } - - if (epdrv->pdrv->probe(match)) - pr_warn("%s: unable to probe %s early.\n", - class_str, match->name); - else - n++; - } - - if (n >= nr_probe) - break; - } - - if (left) - return n; - else - return -ENODEV; -} - -/** - * early_platform_driver_probe - probe a class of registered drivers - * @class_str: string to identify early platform driver class - * @nr_probe: number of platform devices to successfully probe before exiting - * @user_only: only probe user specified early platform devices - * - * Used by architecture code to probe registered early platform drivers - * within a certain class. For probe to happen a registered early platform - * device matching a registered early platform driver is needed. - */ -int __init early_platform_driver_probe(char *class_str, - int nr_probe, - int user_only) -{ - int k, n, i; - - n = 0; - for (i = -2; n < nr_probe; i++) { - k = early_platform_driver_probe_id(class_str, i, nr_probe - n); - - if (k < 0) - break; - - n += k; - - if (user_only) - break; - } - - return n; -} - -/** - * early_platform_cleanup - clean up early platform code - */ -void __init early_platform_cleanup(void) -{ - struct platform_device *pd, *pd2; - - /* clean up the devres list used to chain devices */ - list_for_each_entry_safe(pd, pd2, &early_platform_device_list, - dev.devres_head) { - list_del(&pd->dev.devres_head); - memset(&pd->dev.devres_head, 0, sizeof(pd->dev.devres_head)); - } -} - diff --git a/src/linux/drivers/base/power/Makefile b/src/linux/drivers/base/power/Makefile deleted file mode 100644 index 5998c53..0000000 --- a/src/linux/drivers/base/power/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -obj-$(CONFIG_PM) += sysfs.o generic_ops.o common.o qos.o runtime.o wakeirq.o -obj-$(CONFIG_PM_SLEEP) += main.o wakeup.o -obj-$(CONFIG_PM_TRACE_RTC) += trace.o -obj-$(CONFIG_PM_OPP) += opp/ -obj-$(CONFIG_PM_GENERIC_DOMAINS) += domain.o domain_governor.o -obj-$(CONFIG_HAVE_CLK) += clock_ops.o - -ccflags-$(CONFIG_DEBUG_DRIVER) := -DDEBUG diff --git a/src/linux/drivers/base/power/power.h b/src/linux/drivers/base/power/power.h deleted file mode 100644 index 50e30e7..0000000 --- a/src/linux/drivers/base/power/power.h +++ /dev/null @@ -1,156 +0,0 @@ -#include - -static inline void device_pm_init_common(struct device *dev) -{ - if (!dev->power.early_init) { - spin_lock_init(&dev->power.lock); - dev->power.qos = NULL; - dev->power.early_init = true; - } -} - -#ifdef CONFIG_PM - -static inline void pm_runtime_early_init(struct device *dev) -{ - dev->power.disable_depth = 1; - device_pm_init_common(dev); -} - -extern void pm_runtime_init(struct device *dev); -extern void pm_runtime_reinit(struct device *dev); -extern void pm_runtime_remove(struct device *dev); - -struct wake_irq { - struct device *dev; - int irq; - bool dedicated_irq:1; -}; - -extern void dev_pm_arm_wake_irq(struct wake_irq *wirq); -extern void dev_pm_disarm_wake_irq(struct wake_irq *wirq); - -#ifdef CONFIG_PM_SLEEP - -extern int device_wakeup_attach_irq(struct device *dev, - struct wake_irq *wakeirq); -extern void device_wakeup_detach_irq(struct device *dev); -extern void device_wakeup_arm_wake_irqs(void); -extern void device_wakeup_disarm_wake_irqs(void); - -#else - -static inline int -device_wakeup_attach_irq(struct device *dev, - struct wake_irq *wakeirq) -{ - return 0; -} - -static inline void device_wakeup_detach_irq(struct device *dev) -{ -} - -static inline void device_wakeup_arm_wake_irqs(void) -{ -} - -static inline void device_wakeup_disarm_wake_irqs(void) -{ -} - -#endif /* CONFIG_PM_SLEEP */ - -/* - * sysfs.c - */ - -extern int dpm_sysfs_add(struct device *dev); -extern void dpm_sysfs_remove(struct device *dev); -extern void rpm_sysfs_remove(struct device *dev); -extern int wakeup_sysfs_add(struct device *dev); -extern void wakeup_sysfs_remove(struct device *dev); -extern int pm_qos_sysfs_add_resume_latency(struct device *dev); -extern void pm_qos_sysfs_remove_resume_latency(struct device *dev); -extern int pm_qos_sysfs_add_flags(struct device *dev); -extern void pm_qos_sysfs_remove_flags(struct device *dev); -extern int pm_qos_sysfs_add_latency_tolerance(struct device *dev); -extern void pm_qos_sysfs_remove_latency_tolerance(struct device *dev); - -#else /* CONFIG_PM */ - -static inline void pm_runtime_early_init(struct device *dev) -{ - device_pm_init_common(dev); -} - -static inline void pm_runtime_init(struct device *dev) {} -static inline void pm_runtime_reinit(struct device *dev) {} -static inline void pm_runtime_remove(struct device *dev) {} - -static inline int dpm_sysfs_add(struct device *dev) { return 0; } -static inline void dpm_sysfs_remove(struct device *dev) {} -static inline void rpm_sysfs_remove(struct device *dev) {} -static inline int wakeup_sysfs_add(struct device *dev) { return 0; } -static inline void wakeup_sysfs_remove(struct device *dev) {} -static inline int pm_qos_sysfs_add(struct device *dev) { return 0; } -static inline void pm_qos_sysfs_remove(struct device *dev) {} - -static inline void dev_pm_arm_wake_irq(struct wake_irq *wirq) -{ -} - -static inline void dev_pm_disarm_wake_irq(struct wake_irq *wirq) -{ -} - -#endif - -#ifdef CONFIG_PM_SLEEP - -/* kernel/power/main.c */ -extern int pm_async_enabled; - -/* drivers/base/power/main.c */ -extern struct list_head dpm_list; /* The active device list */ - -static inline struct device *to_device(struct list_head *entry) -{ - return container_of(entry, struct device, power.entry); -} - -extern void device_pm_sleep_init(struct device *dev); -extern void device_pm_add(struct device *); -extern void device_pm_remove(struct device *); -extern void device_pm_move_before(struct device *, struct device *); -extern void device_pm_move_after(struct device *, struct device *); -extern void device_pm_move_last(struct device *); -extern void device_pm_check_callbacks(struct device *dev); - -#else /* !CONFIG_PM_SLEEP */ - -static inline void device_pm_sleep_init(struct device *dev) {} - -static inline void device_pm_add(struct device *dev) {} - -static inline void device_pm_remove(struct device *dev) -{ - pm_runtime_remove(dev); -} - -static inline void device_pm_move_before(struct device *deva, - struct device *devb) {} -static inline void device_pm_move_after(struct device *deva, - struct device *devb) {} -static inline void device_pm_move_last(struct device *dev) {} - -static inline void device_pm_check_callbacks(struct device *dev) {} - -#endif /* !CONFIG_PM_SLEEP */ - -static inline void device_pm_init(struct device *dev) -{ - device_pm_init_common(dev); - device_pm_sleep_init(dev); - pm_runtime_init(dev); -} diff --git a/src/linux/drivers/base/property.c b/src/linux/drivers/base/property.c deleted file mode 100644 index 43a36d6..0000000 --- a/src/linux/drivers/base/property.c +++ /dev/null @@ -1,1054 +0,0 @@ -/* - * property.c - Unified device property interface. - * - * Copyright (C) 2014, Intel Corporation - * Authors: Rafael J. Wysocki - * Mika Westerberg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -struct property_set { - struct fwnode_handle fwnode; - struct property_entry *properties; -}; - -static inline bool is_pset_node(struct fwnode_handle *fwnode) -{ - return !IS_ERR_OR_NULL(fwnode) && fwnode->type == FWNODE_PDATA; -} - -static inline struct property_set *to_pset_node(struct fwnode_handle *fwnode) -{ - return is_pset_node(fwnode) ? - container_of(fwnode, struct property_set, fwnode) : NULL; -} - -static struct property_entry *pset_prop_get(struct property_set *pset, - const char *name) -{ - struct property_entry *prop; - - if (!pset || !pset->properties) - return NULL; - - for (prop = pset->properties; prop->name; prop++) - if (!strcmp(name, prop->name)) - return prop; - - return NULL; -} - -static void *pset_prop_find(struct property_set *pset, const char *propname, - size_t length) -{ - struct property_entry *prop; - void *pointer; - - prop = pset_prop_get(pset, propname); - if (!prop) - return ERR_PTR(-EINVAL); - if (prop->is_array) - pointer = prop->pointer.raw_data; - else - pointer = &prop->value.raw_data; - if (!pointer) - return ERR_PTR(-ENODATA); - if (length > prop->length) - return ERR_PTR(-EOVERFLOW); - return pointer; -} - -static int pset_prop_read_u8_array(struct property_set *pset, - const char *propname, - u8 *values, size_t nval) -{ - void *pointer; - size_t length = nval * sizeof(*values); - - pointer = pset_prop_find(pset, propname, length); - if (IS_ERR(pointer)) - return PTR_ERR(pointer); - - memcpy(values, pointer, length); - return 0; -} - -static int pset_prop_read_u16_array(struct property_set *pset, - const char *propname, - u16 *values, size_t nval) -{ - void *pointer; - size_t length = nval * sizeof(*values); - - pointer = pset_prop_find(pset, propname, length); - if (IS_ERR(pointer)) - return PTR_ERR(pointer); - - memcpy(values, pointer, length); - return 0; -} - -static int pset_prop_read_u32_array(struct property_set *pset, - const char *propname, - u32 *values, size_t nval) -{ - void *pointer; - size_t length = nval * sizeof(*values); - - pointer = pset_prop_find(pset, propname, length); - if (IS_ERR(pointer)) - return PTR_ERR(pointer); - - memcpy(values, pointer, length); - return 0; -} - -static int pset_prop_read_u64_array(struct property_set *pset, - const char *propname, - u64 *values, size_t nval) -{ - void *pointer; - size_t length = nval * sizeof(*values); - - pointer = pset_prop_find(pset, propname, length); - if (IS_ERR(pointer)) - return PTR_ERR(pointer); - - memcpy(values, pointer, length); - return 0; -} - -static int pset_prop_count_elems_of_size(struct property_set *pset, - const char *propname, size_t length) -{ - struct property_entry *prop; - - prop = pset_prop_get(pset, propname); - if (!prop) - return -EINVAL; - - return prop->length / length; -} - -static int pset_prop_read_string_array(struct property_set *pset, - const char *propname, - const char **strings, size_t nval) -{ - void *pointer; - size_t length = nval * sizeof(*strings); - - pointer = pset_prop_find(pset, propname, length); - if (IS_ERR(pointer)) - return PTR_ERR(pointer); - - memcpy(strings, pointer, length); - return 0; -} - -static int pset_prop_read_string(struct property_set *pset, - const char *propname, const char **strings) -{ - struct property_entry *prop; - const char **pointer; - - prop = pset_prop_get(pset, propname); - if (!prop) - return -EINVAL; - if (!prop->is_string) - return -EILSEQ; - if (prop->is_array) { - pointer = prop->pointer.str; - if (!pointer) - return -ENODATA; - } else { - pointer = &prop->value.str; - if (*pointer && strnlen(*pointer, prop->length) >= prop->length) - return -EILSEQ; - } - - *strings = *pointer; - return 0; -} - -static inline struct fwnode_handle *dev_fwnode(struct device *dev) -{ - return IS_ENABLED(CONFIG_OF) && dev->of_node ? - &dev->of_node->fwnode : dev->fwnode; -} - -/** - * device_property_present - check if a property of a device is present - * @dev: Device whose property is being checked - * @propname: Name of the property - * - * Check if property @propname is present in the device firmware description. - */ -bool device_property_present(struct device *dev, const char *propname) -{ - return fwnode_property_present(dev_fwnode(dev), propname); -} -EXPORT_SYMBOL_GPL(device_property_present); - -static bool __fwnode_property_present(struct fwnode_handle *fwnode, - const char *propname) -{ - if (is_of_node(fwnode)) - return of_property_read_bool(to_of_node(fwnode), propname); - else if (is_acpi_node(fwnode)) - return !acpi_node_prop_get(fwnode, propname, NULL); - else if (is_pset_node(fwnode)) - return !!pset_prop_get(to_pset_node(fwnode), propname); - return false; -} - -/** - * fwnode_property_present - check if a property of a firmware node is present - * @fwnode: Firmware node whose property to check - * @propname: Name of the property - */ -bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname) -{ - bool ret; - - ret = __fwnode_property_present(fwnode, propname); - if (ret == false && !IS_ERR_OR_NULL(fwnode) && - !IS_ERR_OR_NULL(fwnode->secondary)) - ret = __fwnode_property_present(fwnode->secondary, propname); - return ret; -} -EXPORT_SYMBOL_GPL(fwnode_property_present); - -/** - * device_property_read_u8_array - return a u8 array property of a device - * @dev: Device to get the property of - * @propname: Name of the property - * @val: The values are stored here or %NULL to return the number of values - * @nval: Size of the @val array - * - * Function reads an array of u8 properties with @propname from the device - * firmware description and stores them to @val if found. - * - * Return: number of values if @val was %NULL, - * %0 if the property was found (success), - * %-EINVAL if given arguments are not valid, - * %-ENODATA if the property does not have a value, - * %-EPROTO if the property is not an array of numbers, - * %-EOVERFLOW if the size of the property is not as expected. - * %-ENXIO if no suitable firmware interface is present. - */ -int device_property_read_u8_array(struct device *dev, const char *propname, - u8 *val, size_t nval) -{ - return fwnode_property_read_u8_array(dev_fwnode(dev), propname, val, nval); -} -EXPORT_SYMBOL_GPL(device_property_read_u8_array); - -/** - * device_property_read_u16_array - return a u16 array property of a device - * @dev: Device to get the property of - * @propname: Name of the property - * @val: The values are stored here or %NULL to return the number of values - * @nval: Size of the @val array - * - * Function reads an array of u16 properties with @propname from the device - * firmware description and stores them to @val if found. - * - * Return: number of values if @val was %NULL, - * %0 if the property was found (success), - * %-EINVAL if given arguments are not valid, - * %-ENODATA if the property does not have a value, - * %-EPROTO if the property is not an array of numbers, - * %-EOVERFLOW if the size of the property is not as expected. - * %-ENXIO if no suitable firmware interface is present. - */ -int device_property_read_u16_array(struct device *dev, const char *propname, - u16 *val, size_t nval) -{ - return fwnode_property_read_u16_array(dev_fwnode(dev), propname, val, nval); -} -EXPORT_SYMBOL_GPL(device_property_read_u16_array); - -/** - * device_property_read_u32_array - return a u32 array property of a device - * @dev: Device to get the property of - * @propname: Name of the property - * @val: The values are stored here or %NULL to return the number of values - * @nval: Size of the @val array - * - * Function reads an array of u32 properties with @propname from the device - * firmware description and stores them to @val if found. - * - * Return: number of values if @val was %NULL, - * %0 if the property was found (success), - * %-EINVAL if given arguments are not valid, - * %-ENODATA if the property does not have a value, - * %-EPROTO if the property is not an array of numbers, - * %-EOVERFLOW if the size of the property is not as expected. - * %-ENXIO if no suitable firmware interface is present. - */ -int device_property_read_u32_array(struct device *dev, const char *propname, - u32 *val, size_t nval) -{ - return fwnode_property_read_u32_array(dev_fwnode(dev), propname, val, nval); -} -EXPORT_SYMBOL_GPL(device_property_read_u32_array); - -/** - * device_property_read_u64_array - return a u64 array property of a device - * @dev: Device to get the property of - * @propname: Name of the property - * @val: The values are stored here or %NULL to return the number of values - * @nval: Size of the @val array - * - * Function reads an array of u64 properties with @propname from the device - * firmware description and stores them to @val if found. - * - * Return: number of values if @val was %NULL, - * %0 if the property was found (success), - * %-EINVAL if given arguments are not valid, - * %-ENODATA if the property does not have a value, - * %-EPROTO if the property is not an array of numbers, - * %-EOVERFLOW if the size of the property is not as expected. - * %-ENXIO if no suitable firmware interface is present. - */ -int device_property_read_u64_array(struct device *dev, const char *propname, - u64 *val, size_t nval) -{ - return fwnode_property_read_u64_array(dev_fwnode(dev), propname, val, nval); -} -EXPORT_SYMBOL_GPL(device_property_read_u64_array); - -/** - * device_property_read_string_array - return a string array property of device - * @dev: Device to get the property of - * @propname: Name of the property - * @val: The values are stored here or %NULL to return the number of values - * @nval: Size of the @val array - * - * Function reads an array of string properties with @propname from the device - * firmware description and stores them to @val if found. - * - * Return: number of values if @val was %NULL, - * %0 if the property was found (success), - * %-EINVAL if given arguments are not valid, - * %-ENODATA if the property does not have a value, - * %-EPROTO or %-EILSEQ if the property is not an array of strings, - * %-EOVERFLOW if the size of the property is not as expected. - * %-ENXIO if no suitable firmware interface is present. - */ -int device_property_read_string_array(struct device *dev, const char *propname, - const char **val, size_t nval) -{ - return fwnode_property_read_string_array(dev_fwnode(dev), propname, val, nval); -} -EXPORT_SYMBOL_GPL(device_property_read_string_array); - -/** - * device_property_read_string - return a string property of a device - * @dev: Device to get the property of - * @propname: Name of the property - * @val: The value is stored here - * - * Function reads property @propname from the device firmware description and - * stores the value into @val if found. The value is checked to be a string. - * - * Return: %0 if the property was found (success), - * %-EINVAL if given arguments are not valid, - * %-ENODATA if the property does not have a value, - * %-EPROTO or %-EILSEQ if the property type is not a string. - * %-ENXIO if no suitable firmware interface is present. - */ -int device_property_read_string(struct device *dev, const char *propname, - const char **val) -{ - return fwnode_property_read_string(dev_fwnode(dev), propname, val); -} -EXPORT_SYMBOL_GPL(device_property_read_string); - -/** - * device_property_match_string - find a string in an array and return index - * @dev: Device to get the property of - * @propname: Name of the property holding the array - * @string: String to look for - * - * Find a given string in a string array and if it is found return the - * index back. - * - * Return: %0 if the property was found (success), - * %-EINVAL if given arguments are not valid, - * %-ENODATA if the property does not have a value, - * %-EPROTO if the property is not an array of strings, - * %-ENXIO if no suitable firmware interface is present. - */ -int device_property_match_string(struct device *dev, const char *propname, - const char *string) -{ - return fwnode_property_match_string(dev_fwnode(dev), propname, string); -} -EXPORT_SYMBOL_GPL(device_property_match_string); - -#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \ - (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \ - : of_property_count_elems_of_size((node), (propname), sizeof(type)) - -#define PSET_PROP_READ_ARRAY(node, propname, type, val, nval) \ - (val) ? pset_prop_read_##type##_array((node), (propname), (val), (nval)) \ - : pset_prop_count_elems_of_size((node), (propname), sizeof(type)) - -#define FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \ -({ \ - int _ret_; \ - if (is_of_node(_fwnode_)) \ - _ret_ = OF_DEV_PROP_READ_ARRAY(to_of_node(_fwnode_), _propname_, \ - _type_, _val_, _nval_); \ - else if (is_acpi_node(_fwnode_)) \ - _ret_ = acpi_node_prop_read(_fwnode_, _propname_, _proptype_, \ - _val_, _nval_); \ - else if (is_pset_node(_fwnode_)) \ - _ret_ = PSET_PROP_READ_ARRAY(to_pset_node(_fwnode_), _propname_, \ - _type_, _val_, _nval_); \ - else \ - _ret_ = -ENXIO; \ - _ret_; \ -}) - -#define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \ -({ \ - int _ret_; \ - _ret_ = FWNODE_PROP_READ(_fwnode_, _propname_, _type_, _proptype_, \ - _val_, _nval_); \ - if (_ret_ == -EINVAL && !IS_ERR_OR_NULL(_fwnode_) && \ - !IS_ERR_OR_NULL(_fwnode_->secondary)) \ - _ret_ = FWNODE_PROP_READ(_fwnode_->secondary, _propname_, _type_, \ - _proptype_, _val_, _nval_); \ - _ret_; \ -}) - -/** - * fwnode_property_read_u8_array - return a u8 array property of firmware node - * @fwnode: Firmware node to get the property of - * @propname: Name of the property - * @val: The values are stored here or %NULL to return the number of values - * @nval: Size of the @val array - * - * Read an array of u8 properties with @propname from @fwnode and stores them to - * @val if found. - * - * Return: number of values if @val was %NULL, - * %0 if the property was found (success), - * %-EINVAL if given arguments are not valid, - * %-ENODATA if the property does not have a value, - * %-EPROTO if the property is not an array of numbers, - * %-EOVERFLOW if the size of the property is not as expected, - * %-ENXIO if no suitable firmware interface is present. - */ -int fwnode_property_read_u8_array(struct fwnode_handle *fwnode, - const char *propname, u8 *val, size_t nval) -{ - return FWNODE_PROP_READ_ARRAY(fwnode, propname, u8, DEV_PROP_U8, - val, nval); -} -EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array); - -/** - * fwnode_property_read_u16_array - return a u16 array property of firmware node - * @fwnode: Firmware node to get the property of - * @propname: Name of the property - * @val: The values are stored here or %NULL to return the number of values - * @nval: Size of the @val array - * - * Read an array of u16 properties with @propname from @fwnode and store them to - * @val if found. - * - * Return: number of values if @val was %NULL, - * %0 if the property was found (success), - * %-EINVAL if given arguments are not valid, - * %-ENODATA if the property does not have a value, - * %-EPROTO if the property is not an array of numbers, - * %-EOVERFLOW if the size of the property is not as expected, - * %-ENXIO if no suitable firmware interface is present. - */ -int fwnode_property_read_u16_array(struct fwnode_handle *fwnode, - const char *propname, u16 *val, size_t nval) -{ - return FWNODE_PROP_READ_ARRAY(fwnode, propname, u16, DEV_PROP_U16, - val, nval); -} -EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array); - -/** - * fwnode_property_read_u32_array - return a u32 array property of firmware node - * @fwnode: Firmware node to get the property of - * @propname: Name of the property - * @val: The values are stored here or %NULL to return the number of values - * @nval: Size of the @val array - * - * Read an array of u32 properties with @propname from @fwnode store them to - * @val if found. - * - * Return: number of values if @val was %NULL, - * %0 if the property was found (success), - * %-EINVAL if given arguments are not valid, - * %-ENODATA if the property does not have a value, - * %-EPROTO if the property is not an array of numbers, - * %-EOVERFLOW if the size of the property is not as expected, - * %-ENXIO if no suitable firmware interface is present. - */ -int fwnode_property_read_u32_array(struct fwnode_handle *fwnode, - const char *propname, u32 *val, size_t nval) -{ - return FWNODE_PROP_READ_ARRAY(fwnode, propname, u32, DEV_PROP_U32, - val, nval); -} -EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array); - -/** - * fwnode_property_read_u64_array - return a u64 array property firmware node - * @fwnode: Firmware node to get the property of - * @propname: Name of the property - * @val: The values are stored here or %NULL to return the number of values - * @nval: Size of the @val array - * - * Read an array of u64 properties with @propname from @fwnode and store them to - * @val if found. - * - * Return: number of values if @val was %NULL, - * %0 if the property was found (success), - * %-EINVAL if given arguments are not valid, - * %-ENODATA if the property does not have a value, - * %-EPROTO if the property is not an array of numbers, - * %-EOVERFLOW if the size of the property is not as expected, - * %-ENXIO if no suitable firmware interface is present. - */ -int fwnode_property_read_u64_array(struct fwnode_handle *fwnode, - const char *propname, u64 *val, size_t nval) -{ - return FWNODE_PROP_READ_ARRAY(fwnode, propname, u64, DEV_PROP_U64, - val, nval); -} -EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array); - -static int __fwnode_property_read_string_array(struct fwnode_handle *fwnode, - const char *propname, - const char **val, size_t nval) -{ - if (is_of_node(fwnode)) - return val ? - of_property_read_string_array(to_of_node(fwnode), - propname, val, nval) : - of_property_count_strings(to_of_node(fwnode), propname); - else if (is_acpi_node(fwnode)) - return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, - val, nval); - else if (is_pset_node(fwnode)) - return val ? - pset_prop_read_string_array(to_pset_node(fwnode), - propname, val, nval) : - pset_prop_count_elems_of_size(to_pset_node(fwnode), - propname, - sizeof(const char *)); - return -ENXIO; -} - -static int __fwnode_property_read_string(struct fwnode_handle *fwnode, - const char *propname, const char **val) -{ - if (is_of_node(fwnode)) - return of_property_read_string(to_of_node(fwnode), propname, val); - else if (is_acpi_node(fwnode)) - return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING, - val, 1); - else if (is_pset_node(fwnode)) - return pset_prop_read_string(to_pset_node(fwnode), propname, val); - return -ENXIO; -} - -/** - * fwnode_property_read_string_array - return string array property of a node - * @fwnode: Firmware node to get the property of - * @propname: Name of the property - * @val: The values are stored here or %NULL to return the number of values - * @nval: Size of the @val array - * - * Read an string list property @propname from the given firmware node and store - * them to @val if found. - * - * Return: number of values if @val was %NULL, - * %0 if the property was found (success), - * %-EINVAL if given arguments are not valid, - * %-ENODATA if the property does not have a value, - * %-EPROTO if the property is not an array of strings, - * %-EOVERFLOW if the size of the property is not as expected, - * %-ENXIO if no suitable firmware interface is present. - */ -int fwnode_property_read_string_array(struct fwnode_handle *fwnode, - const char *propname, const char **val, - size_t nval) -{ - int ret; - - ret = __fwnode_property_read_string_array(fwnode, propname, val, nval); - if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) && - !IS_ERR_OR_NULL(fwnode->secondary)) - ret = __fwnode_property_read_string_array(fwnode->secondary, - propname, val, nval); - return ret; -} -EXPORT_SYMBOL_GPL(fwnode_property_read_string_array); - -/** - * fwnode_property_read_string - return a string property of a firmware node - * @fwnode: Firmware node to get the property of - * @propname: Name of the property - * @val: The value is stored here - * - * Read property @propname from the given firmware node and store the value into - * @val if found. The value is checked to be a string. - * - * Return: %0 if the property was found (success), - * %-EINVAL if given arguments are not valid, - * %-ENODATA if the property does not have a value, - * %-EPROTO or %-EILSEQ if the property is not a string, - * %-ENXIO if no suitable firmware interface is present. - */ -int fwnode_property_read_string(struct fwnode_handle *fwnode, - const char *propname, const char **val) -{ - int ret; - - ret = __fwnode_property_read_string(fwnode, propname, val); - if (ret == -EINVAL && !IS_ERR_OR_NULL(fwnode) && - !IS_ERR_OR_NULL(fwnode->secondary)) - ret = __fwnode_property_read_string(fwnode->secondary, - propname, val); - return ret; -} -EXPORT_SYMBOL_GPL(fwnode_property_read_string); - -/** - * fwnode_property_match_string - find a string in an array and return index - * @fwnode: Firmware node to get the property of - * @propname: Name of the property holding the array - * @string: String to look for - * - * Find a given string in a string array and if it is found return the - * index back. - * - * Return: %0 if the property was found (success), - * %-EINVAL if given arguments are not valid, - * %-ENODATA if the property does not have a value, - * %-EPROTO if the property is not an array of strings, - * %-ENXIO if no suitable firmware interface is present. - */ -int fwnode_property_match_string(struct fwnode_handle *fwnode, - const char *propname, const char *string) -{ - const char **values; - int nval, ret; - - nval = fwnode_property_read_string_array(fwnode, propname, NULL, 0); - if (nval < 0) - return nval; - - if (nval == 0) - return -ENODATA; - - values = kcalloc(nval, sizeof(*values), GFP_KERNEL); - if (!values) - return -ENOMEM; - - ret = fwnode_property_read_string_array(fwnode, propname, values, nval); - if (ret < 0) - goto out; - - ret = match_string(values, nval, string); - if (ret < 0) - ret = -ENODATA; -out: - kfree(values); - return ret; -} -EXPORT_SYMBOL_GPL(fwnode_property_match_string); - -/** - * pset_free_set - releases memory allocated for copied property set - * @pset: Property set to release - * - * Function takes previously copied property set and releases all the - * memory allocated to it. - */ -static void pset_free_set(struct property_set *pset) -{ - const struct property_entry *prop; - size_t i, nval; - - if (!pset) - return; - - for (prop = pset->properties; prop->name; prop++) { - if (prop->is_array) { - if (prop->is_string && prop->pointer.str) { - nval = prop->length / sizeof(const char *); - for (i = 0; i < nval; i++) - kfree(prop->pointer.str[i]); - } - kfree(prop->pointer.raw_data); - } else if (prop->is_string) { - kfree(prop->value.str); - } - kfree(prop->name); - } - - kfree(pset->properties); - kfree(pset); -} - -static int pset_copy_entry(struct property_entry *dst, - const struct property_entry *src) -{ - const char **d, **s; - size_t i, nval; - - dst->name = kstrdup(src->name, GFP_KERNEL); - if (!dst->name) - return -ENOMEM; - - if (src->is_array) { - if (!src->length) - return -ENODATA; - - if (src->is_string) { - nval = src->length / sizeof(const char *); - dst->pointer.str = kcalloc(nval, sizeof(const char *), - GFP_KERNEL); - if (!dst->pointer.str) - return -ENOMEM; - - d = dst->pointer.str; - s = src->pointer.str; - for (i = 0; i < nval; i++) { - d[i] = kstrdup(s[i], GFP_KERNEL); - if (!d[i] && s[i]) - return -ENOMEM; - } - } else { - dst->pointer.raw_data = kmemdup(src->pointer.raw_data, - src->length, GFP_KERNEL); - if (!dst->pointer.raw_data) - return -ENOMEM; - } - } else if (src->is_string) { - dst->value.str = kstrdup(src->value.str, GFP_KERNEL); - if (!dst->value.str && src->value.str) - return -ENOMEM; - } else { - dst->value.raw_data = src->value.raw_data; - } - - dst->length = src->length; - dst->is_array = src->is_array; - dst->is_string = src->is_string; - - return 0; -} - -/** - * pset_copy_set - copies property set - * @pset: Property set to copy - * - * This function takes a deep copy of the given property set and returns - * pointer to the copy. Call device_free_property_set() to free resources - * allocated in this function. - * - * Return: Pointer to the new property set or error pointer. - */ -static struct property_set *pset_copy_set(const struct property_set *pset) -{ - const struct property_entry *entry; - struct property_set *p; - size_t i, n = 0; - - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) - return ERR_PTR(-ENOMEM); - - while (pset->properties[n].name) - n++; - - p->properties = kcalloc(n + 1, sizeof(*entry), GFP_KERNEL); - if (!p->properties) { - kfree(p); - return ERR_PTR(-ENOMEM); - } - - for (i = 0; i < n; i++) { - int ret = pset_copy_entry(&p->properties[i], - &pset->properties[i]); - if (ret) { - pset_free_set(p); - return ERR_PTR(ret); - } - } - - return p; -} - -/** - * device_remove_properties - Remove properties from a device object. - * @dev: Device whose properties to remove. - * - * The function removes properties previously associated to the device - * secondary firmware node with device_add_properties(). Memory allocated - * to the properties will also be released. - */ -void device_remove_properties(struct device *dev) -{ - struct fwnode_handle *fwnode; - - fwnode = dev_fwnode(dev); - if (!fwnode) - return; - /* - * Pick either primary or secondary node depending which one holds - * the pset. If there is no real firmware node (ACPI/DT) primary - * will hold the pset. - */ - if (is_pset_node(fwnode)) { - set_primary_fwnode(dev, NULL); - pset_free_set(to_pset_node(fwnode)); - } else { - fwnode = fwnode->secondary; - if (!IS_ERR(fwnode) && is_pset_node(fwnode)) { - set_secondary_fwnode(dev, NULL); - pset_free_set(to_pset_node(fwnode)); - } - } -} -EXPORT_SYMBOL_GPL(device_remove_properties); - -/** - * device_add_properties - Add a collection of properties to a device object. - * @dev: Device to add properties to. - * @properties: Collection of properties to add. - * - * Associate a collection of device properties represented by @properties with - * @dev as its secondary firmware node. The function takes a copy of - * @properties. - */ -int device_add_properties(struct device *dev, struct property_entry *properties) -{ - struct property_set *p, pset; - - if (!properties) - return -EINVAL; - - pset.properties = properties; - - p = pset_copy_set(&pset); - if (IS_ERR(p)) - return PTR_ERR(p); - - p->fwnode.type = FWNODE_PDATA; - set_secondary_fwnode(dev, &p->fwnode); - return 0; -} -EXPORT_SYMBOL_GPL(device_add_properties); - -/** - * device_get_next_child_node - Return the next child node handle for a device - * @dev: Device to find the next child node for. - * @child: Handle to one of the device's child nodes or a null handle. - */ -struct fwnode_handle *device_get_next_child_node(struct device *dev, - struct fwnode_handle *child) -{ - if (IS_ENABLED(CONFIG_OF) && dev->of_node) { - struct device_node *node; - - node = of_get_next_available_child(dev->of_node, to_of_node(child)); - if (node) - return &node->fwnode; - } else if (IS_ENABLED(CONFIG_ACPI)) { - return acpi_get_next_subnode(dev, child); - } - return NULL; -} -EXPORT_SYMBOL_GPL(device_get_next_child_node); - -/** - * device_get_named_child_node - Return first matching named child node handle - * @dev: Device to find the named child node for. - * @childname: String to match child node name against. - */ -struct fwnode_handle *device_get_named_child_node(struct device *dev, - const char *childname) -{ - struct fwnode_handle *child; - - /* - * Find first matching named child node of this device. - * For ACPI this will be a data only sub-node. - */ - device_for_each_child_node(dev, child) { - if (is_of_node(child)) { - if (!of_node_cmp(to_of_node(child)->name, childname)) - return child; - } else if (is_acpi_data_node(child)) { - if (acpi_data_node_match(child, childname)) - return child; - } - } - - return NULL; -} -EXPORT_SYMBOL_GPL(device_get_named_child_node); - -/** - * fwnode_handle_put - Drop reference to a device node - * @fwnode: Pointer to the device node to drop the reference to. - * - * This has to be used when terminating device_for_each_child_node() iteration - * with break or return to prevent stale device node references from being left - * behind. - */ -void fwnode_handle_put(struct fwnode_handle *fwnode) -{ - if (is_of_node(fwnode)) - of_node_put(to_of_node(fwnode)); -} -EXPORT_SYMBOL_GPL(fwnode_handle_put); - -/** - * device_get_child_node_count - return the number of child nodes for device - * @dev: Device to cound the child nodes for - */ -unsigned int device_get_child_node_count(struct device *dev) -{ - struct fwnode_handle *child; - unsigned int count = 0; - - device_for_each_child_node(dev, child) - count++; - - return count; -} -EXPORT_SYMBOL_GPL(device_get_child_node_count); - -bool device_dma_supported(struct device *dev) -{ - /* For DT, this is always supported. - * For ACPI, this depends on CCA, which - * is determined by the acpi_dma_supported(). - */ - if (IS_ENABLED(CONFIG_OF) && dev->of_node) - return true; - - return acpi_dma_supported(ACPI_COMPANION(dev)); -} -EXPORT_SYMBOL_GPL(device_dma_supported); - -enum dev_dma_attr device_get_dma_attr(struct device *dev) -{ - enum dev_dma_attr attr = DEV_DMA_NOT_SUPPORTED; - - if (IS_ENABLED(CONFIG_OF) && dev->of_node) { - if (of_dma_is_coherent(dev->of_node)) - attr = DEV_DMA_COHERENT; - else - attr = DEV_DMA_NON_COHERENT; - } else - attr = acpi_get_dma_attr(ACPI_COMPANION(dev)); - - return attr; -} -EXPORT_SYMBOL_GPL(device_get_dma_attr); - -/** - * device_get_phy_mode - Get phy mode for given device - * @dev: Pointer to the given device - * - * The function gets phy interface string from property 'phy-mode' or - * 'phy-connection-type', and return its index in phy_modes table, or errno in - * error case. - */ -int device_get_phy_mode(struct device *dev) -{ - const char *pm; - int err, i; - - err = device_property_read_string(dev, "phy-mode", &pm); - if (err < 0) - err = device_property_read_string(dev, - "phy-connection-type", &pm); - if (err < 0) - return err; - - for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) - if (!strcasecmp(pm, phy_modes(i))) - return i; - - return -ENODEV; -} -EXPORT_SYMBOL_GPL(device_get_phy_mode); - -static void *device_get_mac_addr(struct device *dev, - const char *name, char *addr, - int alen) -{ - int ret = device_property_read_u8_array(dev, name, addr, alen); - - if (ret == 0 && alen == ETH_ALEN && is_valid_ether_addr(addr)) - return addr; - return NULL; -} - -/** - * device_get_mac_address - Get the MAC for a given device - * @dev: Pointer to the device - * @addr: Address of buffer to store the MAC in - * @alen: Length of the buffer pointed to by addr, should be ETH_ALEN - * - * Search the firmware node for the best MAC address to use. 'mac-address' is - * checked first, because that is supposed to contain to "most recent" MAC - * address. If that isn't set, then 'local-mac-address' is checked next, - * because that is the default address. If that isn't set, then the obsolete - * 'address' is checked, just in case we're using an old device tree. - * - * Note that the 'address' property is supposed to contain a virtual address of - * the register set, but some DTS files have redefined that property to be the - * MAC address. - * - * All-zero MAC addresses are rejected, because those could be properties that - * exist in the firmware tables, but were not updated by the firmware. For - * example, the DTS could define 'mac-address' and 'local-mac-address', with - * zero MAC addresses. Some older U-Boots only initialized 'local-mac-address'. - * In this case, the real MAC is in 'local-mac-address', and 'mac-address' - * exists but is all zeros. -*/ -void *device_get_mac_address(struct device *dev, char *addr, int alen) -{ - char *res; - - res = device_get_mac_addr(dev, "mac-address", addr, alen); - if (res) - return res; - - res = device_get_mac_addr(dev, "local-mac-address", addr, alen); - if (res) - return res; - - return device_get_mac_addr(dev, "address", addr, alen); -} -EXPORT_SYMBOL(device_get_mac_address); diff --git a/src/linux/drivers/base/regmap/Kconfig b/src/linux/drivers/base/regmap/Kconfig deleted file mode 100644 index db9d00c..0000000 --- a/src/linux/drivers/base/regmap/Kconfig +++ /dev/null @@ -1,31 +0,0 @@ -# Generic register map support. There are no user servicable options here, -# this is an API intended to be used by other kernel subsystems. These -# subsystems should select the appropriate symbols. - -config REGMAP - default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ) - select LZO_COMPRESS - select LZO_DECOMPRESS - select IRQ_DOMAIN if REGMAP_IRQ - bool - -config REGMAP_AC97 - tristate - -config REGMAP_I2C - tristate - depends on I2C - -config REGMAP_SPI - tristate - depends on SPI - -config REGMAP_SPMI - tristate - depends on SPMI - -config REGMAP_MMIO - tristate - -config REGMAP_IRQ - bool diff --git a/src/linux/drivers/base/syscore.c b/src/linux/drivers/base/syscore.c deleted file mode 100644 index 8d98a32..0000000 --- a/src/linux/drivers/base/syscore.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * syscore.c - Execution of system core operations. - * - * Copyright (C) 2011 Rafael J. Wysocki , Novell Inc. - * - * This file is released under the GPLv2. - */ - -#include -#include -#include -#include -#include - -static LIST_HEAD(syscore_ops_list); -static DEFINE_MUTEX(syscore_ops_lock); - -/** - * register_syscore_ops - Register a set of system core operations. - * @ops: System core operations to register. - */ -void register_syscore_ops(struct syscore_ops *ops) -{ - mutex_lock(&syscore_ops_lock); - list_add_tail(&ops->node, &syscore_ops_list); - mutex_unlock(&syscore_ops_lock); -} -EXPORT_SYMBOL_GPL(register_syscore_ops); - -/** - * unregister_syscore_ops - Unregister a set of system core operations. - * @ops: System core operations to unregister. - */ -void unregister_syscore_ops(struct syscore_ops *ops) -{ - mutex_lock(&syscore_ops_lock); - list_del(&ops->node); - mutex_unlock(&syscore_ops_lock); -} -EXPORT_SYMBOL_GPL(unregister_syscore_ops); - -#ifdef CONFIG_PM_SLEEP -/** - * syscore_suspend - Execute all the registered system core suspend callbacks. - * - * This function is executed with one CPU on-line and disabled interrupts. - */ -int syscore_suspend(void) -{ - struct syscore_ops *ops; - int ret = 0; - - trace_suspend_resume(TPS("syscore_suspend"), 0, true); - pr_debug("Checking wakeup interrupts\n"); - - /* Return error code if there are any wakeup interrupts pending. */ - if (pm_wakeup_pending()) - return -EBUSY; - - WARN_ONCE(!irqs_disabled(), - "Interrupts enabled before system core suspend.\n"); - - list_for_each_entry_reverse(ops, &syscore_ops_list, node) - if (ops->suspend) { - if (initcall_debug) - pr_info("PM: Calling %pF\n", ops->suspend); - ret = ops->suspend(); - if (ret) - goto err_out; - WARN_ONCE(!irqs_disabled(), - "Interrupts enabled after %pF\n", ops->suspend); - } - - trace_suspend_resume(TPS("syscore_suspend"), 0, false); - return 0; - - err_out: - pr_err("PM: System core suspend callback %pF failed.\n", ops->suspend); - - list_for_each_entry_continue(ops, &syscore_ops_list, node) - if (ops->resume) - ops->resume(); - - return ret; -} -EXPORT_SYMBOL_GPL(syscore_suspend); - -/** - * syscore_resume - Execute all the registered system core resume callbacks. - * - * This function is executed with one CPU on-line and disabled interrupts. - */ -void syscore_resume(void) -{ - struct syscore_ops *ops; - - trace_suspend_resume(TPS("syscore_resume"), 0, true); - WARN_ONCE(!irqs_disabled(), - "Interrupts enabled before system core resume.\n"); - - list_for_each_entry(ops, &syscore_ops_list, node) - if (ops->resume) { - if (initcall_debug) - pr_info("PM: Calling %pF\n", ops->resume); - ops->resume(); - WARN_ONCE(!irqs_disabled(), - "Interrupts enabled after %pF\n", ops->resume); - } - trace_suspend_resume(TPS("syscore_resume"), 0, false); -} -EXPORT_SYMBOL_GPL(syscore_resume); -#endif /* CONFIG_PM_SLEEP */ - -/** - * syscore_shutdown - Execute all the registered system core shutdown callbacks. - */ -void syscore_shutdown(void) -{ - struct syscore_ops *ops; - - mutex_lock(&syscore_ops_lock); - - list_for_each_entry_reverse(ops, &syscore_ops_list, node) - if (ops->shutdown) { - if (initcall_debug) - pr_info("PM: Calling %pF\n", ops->shutdown); - ops->shutdown(); - } - - mutex_unlock(&syscore_ops_lock); -} diff --git a/src/linux/drivers/base/topology.c b/src/linux/drivers/base/topology.c deleted file mode 100644 index df3c97c..0000000 --- a/src/linux/drivers/base/topology.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * driver/base/topology.c - Populate sysfs with cpu topology information - * - * Written by: Zhang Yanmin, Intel Corporation - * - * Copyright (C) 2006, Intel Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ -#include -#include -#include -#include -#include - -#define define_id_show_func(name) \ -static ssize_t name##_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - return sprintf(buf, "%d\n", topology_##name(dev->id)); \ -} - -#define define_siblings_show_map(name, mask) \ -static ssize_t name##_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - return cpumap_print_to_pagebuf(false, buf, topology_##mask(dev->id));\ -} - -#define define_siblings_show_list(name, mask) \ -static ssize_t name##_list_show(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - return cpumap_print_to_pagebuf(true, buf, topology_##mask(dev->id));\ -} - -#define define_siblings_show_func(name, mask) \ - define_siblings_show_map(name, mask); \ - define_siblings_show_list(name, mask) - -define_id_show_func(physical_package_id); -static DEVICE_ATTR_RO(physical_package_id); - -define_id_show_func(core_id); -static DEVICE_ATTR_RO(core_id); - -define_siblings_show_func(thread_siblings, sibling_cpumask); -static DEVICE_ATTR_RO(thread_siblings); -static DEVICE_ATTR_RO(thread_siblings_list); - -define_siblings_show_func(core_siblings, core_cpumask); -static DEVICE_ATTR_RO(core_siblings); -static DEVICE_ATTR_RO(core_siblings_list); - -#ifdef CONFIG_SCHED_BOOK -define_id_show_func(book_id); -static DEVICE_ATTR_RO(book_id); -define_siblings_show_func(book_siblings, book_cpumask); -static DEVICE_ATTR_RO(book_siblings); -static DEVICE_ATTR_RO(book_siblings_list); -#endif - -#ifdef CONFIG_SCHED_DRAWER -define_id_show_func(drawer_id); -static DEVICE_ATTR_RO(drawer_id); -define_siblings_show_func(drawer_siblings, drawer_cpumask); -static DEVICE_ATTR_RO(drawer_siblings); -static DEVICE_ATTR_RO(drawer_siblings_list); -#endif - -static struct attribute *default_attrs[] = { - &dev_attr_physical_package_id.attr, - &dev_attr_core_id.attr, - &dev_attr_thread_siblings.attr, - &dev_attr_thread_siblings_list.attr, - &dev_attr_core_siblings.attr, - &dev_attr_core_siblings_list.attr, -#ifdef CONFIG_SCHED_BOOK - &dev_attr_book_id.attr, - &dev_attr_book_siblings.attr, - &dev_attr_book_siblings_list.attr, -#endif -#ifdef CONFIG_SCHED_DRAWER - &dev_attr_drawer_id.attr, - &dev_attr_drawer_siblings.attr, - &dev_attr_drawer_siblings_list.attr, -#endif - NULL -}; - -static struct attribute_group topology_attr_group = { - .attrs = default_attrs, - .name = "topology" -}; - -/* Add/Remove cpu_topology interface for CPU device */ -static int topology_add_dev(unsigned int cpu) -{ - struct device *dev = get_cpu_device(cpu); - - return sysfs_create_group(&dev->kobj, &topology_attr_group); -} - -static void topology_remove_dev(unsigned int cpu) -{ - struct device *dev = get_cpu_device(cpu); - - sysfs_remove_group(&dev->kobj, &topology_attr_group); -} - -static int topology_cpu_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) -{ - unsigned int cpu = (unsigned long)hcpu; - int rc = 0; - - switch (action) { - case CPU_UP_PREPARE: - case CPU_UP_PREPARE_FROZEN: - rc = topology_add_dev(cpu); - break; - case CPU_UP_CANCELED: - case CPU_UP_CANCELED_FROZEN: - case CPU_DEAD: - case CPU_DEAD_FROZEN: - topology_remove_dev(cpu); - break; - } - return notifier_from_errno(rc); -} - -static int topology_sysfs_init(void) -{ - int cpu; - int rc = 0; - - cpu_notifier_register_begin(); - - for_each_online_cpu(cpu) { - rc = topology_add_dev(cpu); - if (rc) - goto out; - } - __hotcpu_notifier(topology_cpu_callback, 0); - -out: - cpu_notifier_register_done(); - return rc; -} - -device_initcall(topology_sysfs_init); diff --git a/src/linux/drivers/base/transport_class.c b/src/linux/drivers/base/transport_class.c deleted file mode 100644 index f6c453c..0000000 --- a/src/linux/drivers/base/transport_class.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * transport_class.c - implementation of generic transport classes - * using attribute_containers - * - * Copyright (c) 2005 - James Bottomley - * - * This file is licensed under GPLv2 - * - * The basic idea here is to allow any "device controller" (which - * would most often be a Host Bus Adapter to use the services of one - * or more tranport classes for performing transport specific - * services. Transport specific services are things that the generic - * command layer doesn't want to know about (speed settings, line - * condidtioning, etc), but which the user might be interested in. - * Thus, the HBA's use the routines exported by the transport classes - * to perform these functions. The transport classes export certain - * values to the user via sysfs using attribute containers. - * - * Note: because not every HBA will care about every transport - * attribute, there's a many to one relationship that goes like this: - * - * transport class<-----attribute container<----class device - * - * Usually the attribute container is per-HBA, but the design doesn't - * mandate that. Although most of the services will be specific to - * the actual external storage connection used by the HBA, the generic - * transport class is framed entirely in terms of generic devices to - * allow it to be used by any physical HBA in the system. - */ -#include -#include -#include - -/** - * transport_class_register - register an initial transport class - * - * @tclass: a pointer to the transport class structure to be initialised - * - * The transport class contains an embedded class which is used to - * identify it. The caller should initialise this structure with - * zeros and then generic class must have been initialised with the - * actual transport class unique name. There's a macro - * DECLARE_TRANSPORT_CLASS() to do this (declared classes still must - * be registered). - * - * Returns 0 on success or error on failure. - */ -int transport_class_register(struct transport_class *tclass) -{ - return class_register(&tclass->class); -} -EXPORT_SYMBOL_GPL(transport_class_register); - -/** - * transport_class_unregister - unregister a previously registered class - * - * @tclass: The transport class to unregister - * - * Must be called prior to deallocating the memory for the transport - * class. - */ -void transport_class_unregister(struct transport_class *tclass) -{ - class_unregister(&tclass->class); -} -EXPORT_SYMBOL_GPL(transport_class_unregister); - -static int anon_transport_dummy_function(struct transport_container *tc, - struct device *dev, - struct device *cdev) -{ - /* do nothing */ - return 0; -} - -/** - * anon_transport_class_register - register an anonymous class - * - * @atc: The anon transport class to register - * - * The anonymous transport class contains both a transport class and a - * container. The idea of an anonymous class is that it never - * actually has any device attributes associated with it (and thus - * saves on container storage). So it can only be used for triggering - * events. Use prezero and then use DECLARE_ANON_TRANSPORT_CLASS() to - * initialise the anon transport class storage. - */ -int anon_transport_class_register(struct anon_transport_class *atc) -{ - int error; - atc->container.class = &atc->tclass.class; - attribute_container_set_no_classdevs(&atc->container); - error = attribute_container_register(&atc->container); - if (error) - return error; - atc->tclass.setup = anon_transport_dummy_function; - atc->tclass.remove = anon_transport_dummy_function; - return 0; -} -EXPORT_SYMBOL_GPL(anon_transport_class_register); - -/** - * anon_transport_class_unregister - unregister an anon class - * - * @atc: Pointer to the anon transport class to unregister - * - * Must be called prior to deallocating the memory for the anon - * transport class. - */ -void anon_transport_class_unregister(struct anon_transport_class *atc) -{ - if (unlikely(attribute_container_unregister(&atc->container))) - BUG(); -} -EXPORT_SYMBOL_GPL(anon_transport_class_unregister); - -static int transport_setup_classdev(struct attribute_container *cont, - struct device *dev, - struct device *classdev) -{ - struct transport_class *tclass = class_to_transport_class(cont->class); - struct transport_container *tcont = attribute_container_to_transport_container(cont); - - if (tclass->setup) - tclass->setup(tcont, dev, classdev); - - return 0; -} - -/** - * transport_setup_device - declare a new dev for transport class association but don't make it visible yet. - * @dev: the generic device representing the entity being added - * - * Usually, dev represents some component in the HBA system (either - * the HBA itself or a device remote across the HBA bus). This - * routine is simply a trigger point to see if any set of transport - * classes wishes to associate with the added device. This allocates - * storage for the class device and initialises it, but does not yet - * add it to the system or add attributes to it (you do this with - * transport_add_device). If you have no need for a separate setup - * and add operations, use transport_register_device (see - * transport_class.h). - */ - -void transport_setup_device(struct device *dev) -{ - attribute_container_add_device(dev, transport_setup_classdev); -} -EXPORT_SYMBOL_GPL(transport_setup_device); - -static int transport_add_class_device(struct attribute_container *cont, - struct device *dev, - struct device *classdev) -{ - int error = attribute_container_add_class_device(classdev); - struct transport_container *tcont = - attribute_container_to_transport_container(cont); - - if (!error && tcont->statistics) - error = sysfs_create_group(&classdev->kobj, tcont->statistics); - - return error; -} - - -/** - * transport_add_device - declare a new dev for transport class association - * - * @dev: the generic device representing the entity being added - * - * Usually, dev represents some component in the HBA system (either - * the HBA itself or a device remote across the HBA bus). This - * routine is simply a trigger point used to add the device to the - * system and register attributes for it. - */ - -void transport_add_device(struct device *dev) -{ - attribute_container_device_trigger(dev, transport_add_class_device); -} -EXPORT_SYMBOL_GPL(transport_add_device); - -static int transport_configure(struct attribute_container *cont, - struct device *dev, - struct device *cdev) -{ - struct transport_class *tclass = class_to_transport_class(cont->class); - struct transport_container *tcont = attribute_container_to_transport_container(cont); - - if (tclass->configure) - tclass->configure(tcont, dev, cdev); - - return 0; -} - -/** - * transport_configure_device - configure an already set up device - * - * @dev: generic device representing device to be configured - * - * The idea of configure is simply to provide a point within the setup - * process to allow the transport class to extract information from a - * device after it has been setup. This is used in SCSI because we - * have to have a setup device to begin using the HBA, but after we - * send the initial inquiry, we use configure to extract the device - * parameters. The device need not have been added to be configured. - */ -void transport_configure_device(struct device *dev) -{ - attribute_container_device_trigger(dev, transport_configure); -} -EXPORT_SYMBOL_GPL(transport_configure_device); - -static int transport_remove_classdev(struct attribute_container *cont, - struct device *dev, - struct device *classdev) -{ - struct transport_container *tcont = - attribute_container_to_transport_container(cont); - struct transport_class *tclass = class_to_transport_class(cont->class); - - if (tclass->remove) - tclass->remove(tcont, dev, classdev); - - if (tclass->remove != anon_transport_dummy_function) { - if (tcont->statistics) - sysfs_remove_group(&classdev->kobj, tcont->statistics); - attribute_container_class_device_del(classdev); - } - - return 0; -} - - -/** - * transport_remove_device - remove the visibility of a device - * - * @dev: generic device to remove - * - * This call removes the visibility of the device (to the user from - * sysfs), but does not destroy it. To eliminate a device entirely - * you must also call transport_destroy_device. If you don't need to - * do remove and destroy as separate operations, use - * transport_unregister_device() (see transport_class.h) which will - * perform both calls for you. - */ -void transport_remove_device(struct device *dev) -{ - attribute_container_device_trigger(dev, transport_remove_classdev); -} -EXPORT_SYMBOL_GPL(transport_remove_device); - -static void transport_destroy_classdev(struct attribute_container *cont, - struct device *dev, - struct device *classdev) -{ - struct transport_class *tclass = class_to_transport_class(cont->class); - - if (tclass->remove != anon_transport_dummy_function) - put_device(classdev); -} - - -/** - * transport_destroy_device - destroy a removed device - * - * @dev: device to eliminate from the transport class. - * - * This call triggers the elimination of storage associated with the - * transport classdev. Note: all it really does is relinquish a - * reference to the classdev. The memory will not be freed until the - * last reference goes to zero. Note also that the classdev retains a - * reference count on dev, so dev too will remain for as long as the - * transport class device remains around. - */ -void transport_destroy_device(struct device *dev) -{ - attribute_container_remove_device(dev, transport_destroy_classdev); -} -EXPORT_SYMBOL_GPL(transport_destroy_device); diff --git a/src/linux/drivers/bcma/Kconfig b/src/linux/drivers/bcma/Kconfig deleted file mode 100644 index b5c48a8..0000000 --- a/src/linux/drivers/bcma/Kconfig +++ /dev/null @@ -1,121 +0,0 @@ -config BCMA_POSSIBLE - bool - depends on HAS_IOMEM && HAS_DMA - default y - -menu "Broadcom specific AMBA" - depends on BCMA_POSSIBLE - -config BCMA - tristate "BCMA support" - depends on BCMA_POSSIBLE - help - Bus driver for Broadcom specific Advanced Microcontroller Bus - Architecture. - -# Support for Block-I/O. SELECT this from the driver that needs it. -config BCMA_BLOCKIO - bool - depends on BCMA - -config BCMA_HOST_PCI_POSSIBLE - bool - depends on BCMA && PCI = y - default y - -config BCMA_HOST_PCI - bool "Support for BCMA on PCI-host bus" - depends on BCMA_HOST_PCI_POSSIBLE - select BCMA_DRIVER_PCI - default y - -config BCMA_HOST_SOC - bool "Support for BCMA in a SoC" - depends on BCMA - help - Host interface for a Broadcom AIX bus directly mapped into - the memory. This only works with the Broadcom SoCs from the - BCM47XX line. - - If unsure, say N - -config BCMA_DRIVER_PCI - bool "BCMA Broadcom PCI core driver" - depends on BCMA && PCI - default y - help - BCMA bus may have many versions of PCIe core. This driver - supports: - 1) PCIe core working in clientmode - 2) PCIe Gen 2 clientmode core - - In general PCIe (Gen 2) clientmode core is required on PCIe - hosted buses. It's responsible for initialization and basic - hardware management. - This driver is also prerequisite for a hostmode PCIe core - support. - -config BCMA_DRIVER_PCI_HOSTMODE - bool "Driver for PCI core working in hostmode" - depends on BCMA && MIPS && BCMA_DRIVER_PCI - help - PCI core hostmode operation (external PCI bus). - -config BCMA_DRIVER_MIPS - bool "BCMA Broadcom MIPS core driver" - depends on BCMA && MIPS - help - Driver for the Broadcom MIPS core attached to Broadcom specific - Advanced Microcontroller Bus. - - If unsure, say N - -config BCMA_PFLASH - bool - depends on BCMA_DRIVER_MIPS - default y - -config BCMA_SFLASH - bool "ChipCommon-attached serial flash support" - depends on BCMA_HOST_SOC - default y - help - Some cheap devices have serial flash connected to the ChipCommon - instead of independent SPI controller. It requires using a separated - driver that implements ChipCommon specific interface communication. - - Enabling this symbol will let bcma recognize serial flash and register - it as platform device. - -config BCMA_NFLASH - bool - depends on BCMA_DRIVER_MIPS - default y - -config BCMA_DRIVER_GMAC_CMN - bool "BCMA Broadcom GBIT MAC COMMON core driver" - depends on BCMA - help - Driver for the Broadcom GBIT MAC COMMON core attached to Broadcom - specific Advanced Microcontroller Bus. - - If unsure, say N - -config BCMA_DRIVER_GPIO - bool "BCMA GPIO driver" - depends on BCMA && GPIOLIB - select GPIOLIB_IRQCHIP if BCMA_HOST_SOC - help - Driver to provide access to the GPIO pins of the bcma bus. - - If unsure, say N - -config BCMA_DEBUG - bool "BCMA debugging" - depends on BCMA - help - This turns on additional debugging messages. - - If unsure, say N - -endmenu diff --git a/src/linux/drivers/block/Kconfig b/src/linux/drivers/block/Kconfig deleted file mode 100644 index 39dd30b..0000000 --- a/src/linux/drivers/block/Kconfig +++ /dev/null @@ -1,540 +0,0 @@ -# -# Block device driver configuration -# - -menuconfig BLK_DEV - bool "Block devices" - depends on BLOCK - default y - ---help--- - Say Y here to get to see options for various different block device - drivers. This option alone does not add any kernel code. - - If you say N, all options in this submenu will be skipped and disabled; - only do this if you know what you are doing. - -if BLK_DEV - -config BLK_DEV_NULL_BLK - tristate "Null test block driver" - -config BLK_DEV_FD - tristate "Normal floppy disk support" - depends on ARCH_MAY_HAVE_PC_FDC - ---help--- - If you want to use the floppy disk drive(s) of your PC under Linux, - say Y. Information about this driver, especially important for IBM - Thinkpad users, is contained in - . - That file also contains the location of the Floppy driver FAQ as - well as location of the fdutils package used to configure additional - parameters of the driver at run time. - - To compile this driver as a module, choose M here: the - module will be called floppy. - -config AMIGA_FLOPPY - tristate "Amiga floppy support" - depends on AMIGA - -config ATARI_FLOPPY - tristate "Atari floppy support" - depends on ATARI - -config MAC_FLOPPY - tristate "Support for PowerMac floppy" - depends on PPC_PMAC && !PPC_PMAC64 - help - If you have a SWIM-3 (Super Woz Integrated Machine 3; from Apple) - floppy controller, say Y here. Most commonly found in PowerMacs. - -config BLK_DEV_SWIM - tristate "Support for SWIM Macintosh floppy" - depends on M68K && MAC - help - You should select this option if you want floppy support - and you don't have a II, IIfx, Q900, Q950 or AV series. - -config AMIGA_Z2RAM - tristate "Amiga Zorro II ramdisk support" - depends on ZORRO - help - This enables support for using Chip RAM and Zorro II RAM as a - ramdisk or as a swap partition. Say Y if you want to include this - driver in the kernel. - - To compile this driver as a module, choose M here: the - module will be called z2ram. - -config GDROM - tristate "SEGA Dreamcast GD-ROM drive" - depends on SH_DREAMCAST - help - A standard SEGA Dreamcast comes with a modified CD ROM drive called a - "GD-ROM" by SEGA to signify it is capable of reading special disks - with up to 1 GB of data. This drive will also read standard CD ROM - disks. Select this option to access any disks in your GD ROM drive. - Most users will want to say "Y" here. - You can also build this as a module which will be called gdrom. - -config PARIDE - tristate "Parallel port IDE device support" - depends on PARPORT_PC - ---help--- - There are many external CD-ROM and disk devices that connect through - your computer's parallel port. Most of them are actually IDE devices - using a parallel port IDE adapter. This option enables the PARIDE - subsystem which contains drivers for many of these external drives. - Read for more information. - - If you have said Y to the "Parallel-port support" configuration - option, you may share a single port between your printer and other - parallel port devices. Answer Y to build PARIDE support into your - kernel, or M if you would like to build it as a loadable module. If - your parallel port support is in a loadable module, you must build - PARIDE as a module. If you built PARIDE support into your kernel, - you may still build the individual protocol modules and high-level - drivers as loadable modules. If you build this support as a module, - it will be called paride. - - To use the PARIDE support, you must say Y or M here and also to at - least one high-level driver (e.g. "Parallel port IDE disks", - "Parallel port ATAPI CD-ROMs", "Parallel port ATAPI disks" etc.) and - to at least one protocol driver (e.g. "ATEN EH-100 protocol", - "MicroSolutions backpack protocol", "DataStor Commuter protocol" - etc.). - -source "drivers/block/paride/Kconfig" - -source "drivers/block/mtip32xx/Kconfig" - -source "drivers/block/zram/Kconfig" - -config BLK_CPQ_CISS_DA - tristate "Compaq Smart Array 5xxx support" - depends on PCI - select CHECK_SIGNATURE - help - This is the driver for Compaq Smart Array 5xxx controllers. - Everyone using these boards should say Y here. - See for the current list of - boards supported by this driver, and for further information - on the use of this driver. - -config CISS_SCSI_TAPE - bool "SCSI tape drive support for Smart Array 5xxx" - depends on BLK_CPQ_CISS_DA && PROC_FS - depends on SCSI=y || SCSI=BLK_CPQ_CISS_DA - help - When enabled (Y), this option allows SCSI tape drives and SCSI medium - changers (tape robots) to be accessed via a Compaq 5xxx array - controller. (See for more details.) - - "SCSI support" and "SCSI tape support" must also be enabled for this - option to work. - - When this option is disabled (N), the SCSI portion of the driver - is not compiled. - -config BLK_DEV_DAC960 - tristate "Mylex DAC960/DAC1100 PCI RAID Controller support" - depends on PCI - help - This driver adds support for the Mylex DAC960, AcceleRAID, and - eXtremeRAID PCI RAID controllers. See the file - for further information - about this driver. - - To compile this driver as a module, choose M here: the - module will be called DAC960. - -config BLK_DEV_UMEM - tristate "Micro Memory MM5415 Battery Backed RAM support" - depends on PCI - ---help--- - Saying Y here will include support for the MM5415 family of - battery backed (Non-volatile) RAM cards. - - - The cards appear as block devices that can be partitioned into - as many as 15 partitions. - - To compile this driver as a module, choose M here: the - module will be called umem. - - The umem driver has not yet been allocated a MAJOR number, so - one is chosen dynamically. - -config BLK_DEV_UBD - bool "Virtual block device" - depends on UML - ---help--- - The User-Mode Linux port includes a driver called UBD which will let - you access arbitrary files on the host computer as block devices. - Unless you know that you do not need such virtual block devices say - Y here. - -config BLK_DEV_UBD_SYNC - bool "Always do synchronous disk IO for UBD" - depends on BLK_DEV_UBD - ---help--- - Writes to the virtual block device are not immediately written to the - host's disk; this may cause problems if, for example, the User-Mode - Linux 'Virtual Machine' uses a journalling filesystem and the host - computer crashes. - - Synchronous operation (i.e. always writing data to the host's disk - immediately) is configurable on a per-UBD basis by using a special - kernel command line option. Alternatively, you can say Y here to - turn on synchronous operation by default for all block devices. - - If you're running a journalling file system (like reiserfs, for - example) in your virtual machine, you will want to say Y here. If - you care for the safety of the data in your virtual machine, Y is a - wise choice too. In all other cases (for example, if you're just - playing around with User-Mode Linux) you can choose N. - -config BLK_DEV_COW_COMMON - bool - default BLK_DEV_UBD - -config BLK_DEV_LOOP - tristate "Loopback device support" - ---help--- - Saying Y here will allow you to use a regular file as a block - device; you can then create a file system on that block device and - mount it just as you would mount other block devices such as hard - drive partitions, CD-ROM drives or floppy drives. The loop devices - are block special device files with major number 7 and typically - called /dev/loop0, /dev/loop1 etc. - - This is useful if you want to check an ISO 9660 file system before - burning the CD, or if you want to use floppy images without first - writing them to floppy. Furthermore, some Linux distributions avoid - the need for a dedicated Linux partition by keeping their complete - root file system inside a DOS FAT file using this loop device - driver. - - To use the loop device, you need the losetup utility, found in the - util-linux package, see - . - - The loop device driver can also be used to "hide" a file system in - a disk partition, floppy, or regular file, either using encryption - (scrambling the data) or steganography (hiding the data in the low - bits of, say, a sound file). This is also safe if the file resides - on a remote file server. - - There are several ways of encrypting disks. Some of these require - kernel patches. The vanilla kernel offers the cryptoloop option - and a Device Mapper target (which is superior, as it supports all - file systems). If you want to use the cryptoloop, say Y to both - LOOP and CRYPTOLOOP, and make sure you have a recent (version 2.12 - or later) version of util-linux. Additionally, be aware that - the cryptoloop is not safe for storing journaled filesystems. - - Note that this loop device has nothing to do with the loopback - device used for network connections from the machine to itself. - - To compile this driver as a module, choose M here: the - module will be called loop. - - Most users will answer N here. - -config BLK_DEV_LOOP_MIN_COUNT - int "Number of loop devices to pre-create at init time" - depends on BLK_DEV_LOOP - default 8 - help - Static number of loop devices to be unconditionally pre-created - at init time. - - This default value can be overwritten on the kernel command - line or with module-parameter loop.max_loop. - - The historic default is 8. If a late 2011 version of losetup(8) - is used, it can be set to 0, since needed loop devices can be - dynamically allocated with the /dev/loop-control interface. - -config BLK_DEV_CRYPTOLOOP - tristate "Cryptoloop Support" - select CRYPTO - select CRYPTO_CBC - depends on BLK_DEV_LOOP - ---help--- - Say Y here if you want to be able to use the ciphers that are - provided by the CryptoAPI as loop transformation. This might be - used as hard disk encryption. - - WARNING: This device is not safe for journaled file systems like - ext3 or Reiserfs. Please use the Device Mapper crypto module - instead, which can be configured to be on-disk compatible with the - cryptoloop device. - -source "drivers/block/drbd/Kconfig" - -config BLK_DEV_NBD - tristate "Network block device support" - depends on NET - ---help--- - Saying Y here will allow your computer to be a client for network - block devices, i.e. it will be able to use block devices exported by - servers (mount file systems on them etc.). Communication between - client and server works over TCP/IP networking, but to the client - program this is hidden: it looks like a regular local file access to - a block device special file such as /dev/nd0. - - Network block devices also allows you to run a block-device in - userland (making server and client physically the same computer, - communicating using the loopback network device). - - Read for more information, - especially about where to find the server code, which runs in user - space and does not need special kernel support. - - Note that this has nothing to do with the network file systems NFS - or Coda; you can say N here even if you intend to use NFS or Coda. - - To compile this driver as a module, choose M here: the - module will be called nbd. - - If unsure, say N. - -config BLK_DEV_SKD - tristate "STEC S1120 Block Driver" - depends on PCI - depends on 64BIT - ---help--- - Saying Y or M here will enable support for the - STEC, Inc. S1120 PCIe SSD. - - Use device /dev/skd$N amd /dev/skd$Np$M. - -config BLK_DEV_OSD - tristate "OSD object-as-blkdev support" - depends on SCSI_OSD_ULD - ---help--- - Saying Y or M here will allow the exporting of a single SCSI - OSD (object-based storage) object as a Linux block device. - - For example, if you create a 2G object on an OSD device, - you can then use this module to present that 2G object as - a Linux block device. - - To compile this driver as a module, choose M here: the - module will be called osdblk. - - If unsure, say N. - -config BLK_DEV_SX8 - tristate "Promise SATA SX8 support" - depends on PCI - ---help--- - Saying Y or M here will enable support for the - Promise SATA SX8 controllers. - - Use devices /dev/sx8/$N and /dev/sx8/$Np$M. - -config BLK_DEV_RAM - tristate "RAM block device support" - ---help--- - Saying Y here will allow you to use a portion of your RAM memory as - a block device, so that you can make file systems on it, read and - write to it and do all the other things that you can do with normal - block devices (such as hard drives). It is usually used to load and - store a copy of a minimal root file system off of a floppy into RAM - during the initial install of Linux. - - Note that the kernel command line option "ramdisk=XX" is now obsolete. - For details, read . - - To compile this driver as a module, choose M here: the - module will be called brd. An alias "rd" has been defined - for historical reasons. - - Most normal users won't need the RAM disk functionality, and can - thus say N here. - -config BLK_DEV_RAM_COUNT - int "Default number of RAM disks" - default "16" - depends on BLK_DEV_RAM - help - The default value is 16 RAM disks. Change this if you know what you - are doing. If you boot from a filesystem that needs to be extracted - in memory, you will need at least one RAM disk (e.g. root on cramfs). - -config BLK_DEV_RAM_SIZE - int "Default RAM disk size (kbytes)" - depends on BLK_DEV_RAM - default "4096" - help - The default value is 4096 kilobytes. Only change this if you know - what you are doing. - -config BLK_DEV_RAM_DAX - bool "Support Direct Access (DAX) to RAM block devices" - depends on BLK_DEV_RAM && FS_DAX - default n - help - Support filesystems using DAX to access RAM block devices. This - avoids double-buffering data in the page cache before copying it - to the block device. Answering Y will slightly enlarge the kernel, - and will prevent RAM block device backing store memory from being - allocated from highmem (only a problem for highmem systems). - -config CDROM_PKTCDVD - tristate "Packet writing on CD/DVD media" - depends on !UML - help - If you have a CDROM/DVD drive that supports packet writing, say - Y to include support. It should work with any MMC/Mt Fuji - compliant ATAPI or SCSI drive, which is just about any newer - DVD/CD writer. - - Currently only writing to CD-RW, DVD-RW, DVD+RW and DVDRAM discs - is possible. - DVD-RW disks must be in restricted overwrite mode. - - See the file - for further information on the use of this driver. - - To compile this driver as a module, choose M here: the - module will be called pktcdvd. - -config CDROM_PKTCDVD_BUFFERS - int "Free buffers for data gathering" - depends on CDROM_PKTCDVD - default "8" - help - This controls the maximum number of active concurrent packets. More - concurrent packets can increase write performance, but also require - more memory. Each concurrent packet will require approximately 64Kb - of non-swappable kernel memory, memory which will be allocated when - a disc is opened for writing. - -config CDROM_PKTCDVD_WCACHE - bool "Enable write caching" - depends on CDROM_PKTCDVD - help - If enabled, write caching will be set for the CD-R/W device. For now - this option is dangerous unless the CD-RW media is known good, as we - don't do deferred write error handling yet. - -config ATA_OVER_ETH - tristate "ATA over Ethernet support" - depends on NET - help - This driver provides Support for ATA over Ethernet block - devices like the Coraid EtherDrive (R) Storage Blade. - -config MG_DISK - tristate "mGine mflash, gflash support" - depends on ARM && GPIOLIB - help - mGine mFlash(gFlash) block device driver - -config MG_DISK_RES - int "Size of reserved area before MBR" - depends on MG_DISK - default 0 - help - Define size of reserved area that usually used for boot. Unit is KB. - All of the block device operation will be taken this value as start - offset - Examples: - 1024 => 1 MB - -config SUNVDC - tristate "Sun Virtual Disk Client support" - depends on SUN_LDOMS - help - Support for virtual disk devices as a client under Sun - Logical Domains. - -source "drivers/s390/block/Kconfig" - -config XILINX_SYSACE - tristate "Xilinx SystemACE support" - depends on 4xx || MICROBLAZE - help - Include support for the Xilinx SystemACE CompactFlash interface - -config XEN_BLKDEV_FRONTEND - tristate "Xen virtual block device support" - depends on XEN - default y - select XEN_XENBUS_FRONTEND - help - This driver implements the front-end of the Xen virtual - block device driver. It communicates with a back-end driver - in another domain which drives the actual block device. - -config XEN_BLKDEV_BACKEND - tristate "Xen block-device backend driver" - depends on XEN_BACKEND - help - The block-device backend driver allows the kernel to export its - block devices to other guests via a high-performance shared-memory - interface. - - The corresponding Linux frontend driver is enabled by the - CONFIG_XEN_BLKDEV_FRONTEND configuration option. - - The backend driver attaches itself to a any block device specified - in the XenBus configuration. There are no limits to what the block - device as long as it has a major and minor. - - If you are compiling a kernel to run in a Xen block backend driver - domain (often this is domain 0) you should say Y here. To - compile this driver as a module, chose M here: the module - will be called xen-blkback. - - -config VIRTIO_BLK - tristate "Virtio block driver" - depends on VIRTIO - ---help--- - This is the virtual block driver for virtio. It can be used with - lguest or QEMU based VMMs (like KVM or Xen). Say Y or M. - -config BLK_DEV_HD - bool "Very old hard disk (MFM/RLL/IDE) driver" - depends on HAVE_IDE - depends on !ARM || ARCH_RPC || BROKEN - help - This is a very old hard disk driver that lacks the enhanced - functionality of the newer ones. - - It is required for systems with ancient MFM/RLL/ESDI drives. - - If unsure, say N. - -config BLK_DEV_RBD - tristate "Rados block device (RBD)" - depends on INET && BLOCK - select CEPH_LIB - select LIBCRC32C - select CRYPTO_AES - select CRYPTO - default n - help - Say Y here if you want include the Rados block device, which stripes - a block device over objects stored in the Ceph distributed object - store. - - More information at http://ceph.newdream.net/. - - If unsure, say N. - -config BLK_DEV_RSXX - tristate "IBM Flash Adapter 900GB Full Height PCIe Device Driver" - depends on PCI - help - Device driver for IBM's high speed PCIe SSD - storage device: Flash Adapter 900GB Full Height. - - To compile this driver as a module, choose M here: the - module will be called rsxx. - -endif # BLK_DEV diff --git a/src/linux/drivers/block/Makefile b/src/linux/drivers/block/Makefile deleted file mode 100644 index 1e9661e..0000000 --- a/src/linux/drivers/block/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -# -# Makefile for the kernel block device drivers. -# -# 12 June 2000, Christoph Hellwig -# Rewritten to use lists instead of if-statements. -# - -obj-$(CONFIG_MAC_FLOPPY) += swim3.o -obj-$(CONFIG_BLK_DEV_SWIM) += swim_mod.o -obj-$(CONFIG_BLK_DEV_FD) += floppy.o -obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o -obj-$(CONFIG_PS3_DISK) += ps3disk.o -obj-$(CONFIG_PS3_VRAM) += ps3vram.o -obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o -obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o -obj-$(CONFIG_BLK_DEV_RAM) += brd.o -obj-$(CONFIG_BLK_DEV_LOOP) += loop.o -obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o -obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o -obj-$(CONFIG_XILINX_SYSACE) += xsysace.o -obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o -obj-$(CONFIG_MG_DISK) += mg_disk.o -obj-$(CONFIG_SUNVDC) += sunvdc.o -obj-$(CONFIG_BLK_DEV_SKD) += skd.o -obj-$(CONFIG_BLK_DEV_OSD) += osdblk.o - -obj-$(CONFIG_BLK_DEV_UMEM) += umem.o -obj-$(CONFIG_BLK_DEV_NBD) += nbd.o -obj-$(CONFIG_BLK_DEV_CRYPTOLOOP) += cryptoloop.o -obj-$(CONFIG_VIRTIO_BLK) += virtio_blk.o - -obj-$(CONFIG_BLK_DEV_SX8) += sx8.o -obj-$(CONFIG_BLK_DEV_HD) += hd.o - -obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o -obj-$(CONFIG_XEN_BLKDEV_BACKEND) += xen-blkback/ -obj-$(CONFIG_BLK_DEV_DRBD) += drbd/ -obj-$(CONFIG_BLK_DEV_RBD) += rbd.o -obj-$(CONFIG_BLK_DEV_PCIESSD_MTIP32XX) += mtip32xx/ - -obj-$(CONFIG_BLK_DEV_RSXX) += rsxx/ -obj-$(CONFIG_BLK_DEV_NULL_BLK) += null_blk.o -obj-$(CONFIG_ZRAM) += zram/ - -skd-y := skd_main.o -swim_mod-y := swim.o swim_asm.o diff --git a/src/linux/drivers/block/drbd/Kconfig b/src/linux/drivers/block/drbd/Kconfig deleted file mode 100644 index 7845bd6..0000000 --- a/src/linux/drivers/block/drbd/Kconfig +++ /dev/null @@ -1,73 +0,0 @@ -# -# DRBD device driver configuration -# - -comment "DRBD disabled because PROC_FS or INET not selected" - depends on PROC_FS='n' || INET='n' - -config BLK_DEV_DRBD - tristate "DRBD Distributed Replicated Block Device support" - depends on PROC_FS && INET - select LRU_CACHE - select LIBCRC32C - default n - help - - NOTE: In order to authenticate connections you have to select - CRYPTO_HMAC and a hash function as well. - - DRBD is a shared-nothing, synchronously replicated block device. It - is designed to serve as a building block for high availability - clusters and in this context, is a "drop-in" replacement for shared - storage. Simplistically, you could see it as a network RAID 1. - - Each minor device has a role, which can be 'primary' or 'secondary'. - On the node with the primary device the application is supposed to - run and to access the device (/dev/drbdX). Every write is sent to - the local 'lower level block device' and, across the network, to the - node with the device in 'secondary' state. The secondary device - simply writes the data to its lower level block device. - - DRBD can also be used in dual-Primary mode (device writable on both - nodes), which means it can exhibit shared disk semantics in a - shared-nothing cluster. Needless to say, on top of dual-Primary - DRBD utilizing a cluster file system is necessary to maintain for - cache coherency. - - For automatic failover you need a cluster manager (e.g. heartbeat). - See also: http://www.drbd.org/, http://www.linux-ha.org - - If unsure, say N. - -config DRBD_FAULT_INJECTION - bool "DRBD fault injection" - depends on BLK_DEV_DRBD - help - - Say Y here if you want to simulate IO errors, in order to test DRBD's - behavior. - - The actual simulation of IO errors is done by writing 3 values to - /sys/module/drbd/parameters/ - - enable_faults: bitmask of... - 1 meta data write - 2 read - 4 resync data write - 8 read - 16 data write - 32 data read - 64 read ahead - 128 kmalloc of bitmap - 256 allocation of peer_requests - 512 insert data corruption on receiving side - - fault_devs: bitmask of minor numbers - fault_rate: frequency in percent - - Example: Simulate data write errors on /dev/drbd0 with a probability of 5%. - echo 16 > /sys/module/drbd/parameters/enable_faults - echo 1 > /sys/module/drbd/parameters/fault_devs - echo 5 > /sys/module/drbd/parameters/fault_rate - - If unsure, say N. diff --git a/src/linux/drivers/block/mtip32xx/Kconfig b/src/linux/drivers/block/mtip32xx/Kconfig deleted file mode 100644 index 0ba837f..0000000 --- a/src/linux/drivers/block/mtip32xx/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -# -# mtip32xx device driver configuration -# - -config BLK_DEV_PCIESSD_MTIP32XX - tristate "Block Device Driver for Micron PCIe SSDs" - depends on PCI - help - This enables the block driver for Micron PCIe SSDs. diff --git a/src/linux/drivers/block/paride/Kconfig b/src/linux/drivers/block/paride/Kconfig deleted file mode 100644 index efefb5a..0000000 --- a/src/linux/drivers/block/paride/Kconfig +++ /dev/null @@ -1,300 +0,0 @@ -# -# PARIDE configuration -# -# PARIDE doesn't need PARPORT, but if PARPORT is configured as a module, -# PARIDE must also be a module. -# PARIDE only supports PC style parports. Tough for USB or other parports... - -comment "Parallel IDE high-level drivers" - depends on PARIDE - -config PARIDE_PD - tristate "Parallel port IDE disks" - depends on PARIDE - help - This option enables the high-level driver for IDE-type disk devices - connected through a parallel port. If you chose to build PARIDE - support into your kernel, you may answer Y here to build in the - parallel port IDE driver, otherwise you should answer M to build - it as a loadable module. The module will be called pd. You - must also have at least one parallel port protocol driver in your - system. Among the devices supported by this driver are the SyQuest - EZ-135, EZ-230 and SparQ drives, the Avatar Shark and the backpack - hard drives from MicroSolutions. - -config PARIDE_PCD - tristate "Parallel port ATAPI CD-ROMs" - depends on PARIDE - ---help--- - This option enables the high-level driver for ATAPI CD-ROM devices - connected through a parallel port. If you chose to build PARIDE - support into your kernel, you may answer Y here to build in the - parallel port ATAPI CD-ROM driver, otherwise you should answer M to - build it as a loadable module. The module will be called pcd. You - must also have at least one parallel port protocol driver in your - system. Among the devices supported by this driver are the - MicroSolutions backpack CD-ROM drives and the Freecom Power CD. If - you have such a CD-ROM drive, you should also say Y or M to "ISO - 9660 CD-ROM file system support" below, because that's the file - system used on CD-ROMs. - -config PARIDE_PF - tristate "Parallel port ATAPI disks" - depends on PARIDE - help - This option enables the high-level driver for ATAPI disk devices - connected through a parallel port. If you chose to build PARIDE - support into your kernel, you may answer Y here to build in the - parallel port ATAPI disk driver, otherwise you should answer M - to build it as a loadable module. The module will be called pf. - You must also have at least one parallel port protocol driver in - your system. Among the devices supported by this driver are the - MicroSolutions backpack PD/CD drive and the Imation Superdisk - LS-120 drive. - -config PARIDE_PT - tristate "Parallel port ATAPI tapes" - depends on PARIDE - help - This option enables the high-level driver for ATAPI tape devices - connected through a parallel port. If you chose to build PARIDE - support into your kernel, you may answer Y here to build in the - parallel port ATAPI disk driver, otherwise you should answer M - to build it as a loadable module. The module will be called pt. - You must also have at least one parallel port protocol driver in - your system. Among the devices supported by this driver is the - parallel port version of the HP 5GB drive. - -config PARIDE_PG - tristate "Parallel port generic ATAPI devices" - depends on PARIDE - ---help--- - This option enables a special high-level driver for generic ATAPI - devices connected through a parallel port. The driver allows user - programs, such as cdrtools, to send ATAPI commands directly to a - device. - - If you chose to build PARIDE support into your kernel, you may - answer Y here to build in the parallel port generic ATAPI driver, - otherwise you should answer M to build it as a loadable module. The - module will be called pg. - - You must also have at least one parallel port protocol driver in - your system. - - This driver implements an API loosely related to the generic SCSI - driver. See . for details. - - You can obtain the most recent version of cdrtools from - . Versions 1.6.1a3 and - later fully support this driver. - -comment "Parallel IDE protocol modules" - depends on PARIDE - -config PARIDE_ATEN - tristate "ATEN EH-100 protocol" - depends on PARIDE - help - This option enables support for the ATEN EH-100 parallel port IDE - protocol. This protocol is used in some inexpensive low performance - parallel port kits made in Hong Kong. If you chose to build PARIDE - support into your kernel, you may answer Y here to build in the - protocol driver, otherwise you should answer M to build it as a - loadable module. The module will be called aten. You must also - have a high-level driver for the type of device that you want to - support. - -config PARIDE_BPCK - tristate "MicroSolutions backpack (Series 5) protocol" - depends on PARIDE - ---help--- - This option enables support for the Micro Solutions BACKPACK - parallel port Series 5 IDE protocol. (Most BACKPACK drives made - before 1999 were Series 5) Series 5 drives will NOT always have the - Series noted on the bottom of the drive. Series 6 drivers will. - - In other words, if your BACKPACK drive doesn't say "Series 6" on the - bottom, enable this option. - - If you chose to build PARIDE support into your kernel, you may - answer Y here to build in the protocol driver, otherwise you should - answer M to build it as a loadable module. The module will be - called bpck. You must also have a high-level driver for the type - of device that you want to support. - -config PARIDE_BPCK6 - tristate "MicroSolutions backpack (Series 6) protocol" - depends on PARIDE && !64BIT - ---help--- - This option enables support for the Micro Solutions BACKPACK - parallel port Series 6 IDE protocol. (Most BACKPACK drives made - after 1999 were Series 6) Series 6 drives will have the Series noted - on the bottom of the drive. Series 5 drivers don't always have it - noted. - - In other words, if your BACKPACK drive says "Series 6" on the - bottom, enable this option. - - If you chose to build PARIDE support into your kernel, you may - answer Y here to build in the protocol driver, otherwise you should - answer M to build it as a loadable module. The module will be - called bpck6. You must also have a high-level driver for the type - of device that you want to support. - -config PARIDE_COMM - tristate "DataStor Commuter protocol" - depends on PARIDE - help - This option enables support for the Commuter parallel port IDE - protocol from DataStor. If you chose to build PARIDE support - into your kernel, you may answer Y here to build in the protocol - driver, otherwise you should answer M to build it as a loadable - module. The module will be called comm. You must also have - a high-level driver for the type of device that you want to support. - -config PARIDE_DSTR - tristate "DataStor EP-2000 protocol" - depends on PARIDE - help - This option enables support for the EP-2000 parallel port IDE - protocol from DataStor. If you chose to build PARIDE support - into your kernel, you may answer Y here to build in the protocol - driver, otherwise you should answer M to build it as a loadable - module. The module will be called dstr. You must also have - a high-level driver for the type of device that you want to support. - -config PARIDE_FIT2 - tristate "FIT TD-2000 protocol" - depends on PARIDE - help - This option enables support for the TD-2000 parallel port IDE - protocol from Fidelity International Technology. This is a simple - (low speed) adapter that is used in some portable hard drives. If - you chose to build PARIDE support into your kernel, you may answer Y - here to build in the protocol driver, otherwise you should answer M - to build it as a loadable module. The module will be called ktti. - You must also have a high-level driver for the type of device that - you want to support. - -config PARIDE_FIT3 - tristate "FIT TD-3000 protocol" - depends on PARIDE - help - This option enables support for the TD-3000 parallel port IDE - protocol from Fidelity International Technology. This protocol is - used in newer models of their portable disk, CD-ROM and PD/CD - devices. If you chose to build PARIDE support into your kernel, you - may answer Y here to build in the protocol driver, otherwise you - should answer M to build it as a loadable module. The module will be - called fit3. You must also have a high-level driver for the type - of device that you want to support. - -config PARIDE_EPAT - tristate "Shuttle EPAT/EPEZ protocol" - depends on PARIDE - help - This option enables support for the EPAT parallel port IDE protocol. - EPAT is a parallel port IDE adapter manufactured by Shuttle - Technology and widely used in devices from major vendors such as - Hewlett-Packard, SyQuest, Imation and Avatar. If you chose to build - PARIDE support into your kernel, you may answer Y here to build in - the protocol driver, otherwise you should answer M to build it as a - loadable module. The module will be called epat. You must also - have a high-level driver for the type of device that you want to - support. - -config PARIDE_EPATC8 - bool "Support c7/c8 chips" - depends on PARIDE_EPAT - help - This option enables support for the newer Shuttle EP1284 (aka c7 and - c8) chip. You need this if you are using any recent Imation SuperDisk - (LS-120) drive. - -config PARIDE_EPIA - tristate "Shuttle EPIA protocol" - depends on PARIDE - help - This option enables support for the (obsolete) EPIA parallel port - IDE protocol from Shuttle Technology. This adapter can still be - found in some no-name kits. If you chose to build PARIDE support - into your kernel, you may answer Y here to build in the protocol - driver, otherwise you should answer M to build it as a loadable - module. The module will be called epia. You must also have a - high-level driver for the type of device that you want to support. - -config PARIDE_FRIQ - tristate "Freecom IQ ASIC-2 protocol" - depends on PARIDE - help - This option enables support for version 2 of the Freecom IQ parallel - port IDE adapter. This adapter is used by the Maxell Superdisk - drive. If you chose to build PARIDE support into your kernel, you - may answer Y here to build in the protocol driver, otherwise you - should answer M to build it as a loadable module. The module will be - called friq. You must also have a high-level driver for the type - of device that you want to support. - -config PARIDE_FRPW - tristate "FreeCom power protocol" - depends on PARIDE - help - This option enables support for the Freecom power parallel port IDE - protocol. If you chose to build PARIDE support into your kernel, you - may answer Y here to build in the protocol driver, otherwise you - should answer M to build it as a loadable module. The module will be - called frpw. You must also have a high-level driver for the type - of device that you want to support. - -config PARIDE_KBIC - tristate "KingByte KBIC-951A/971A protocols" - depends on PARIDE - help - This option enables support for the KBIC-951A and KBIC-971A parallel - port IDE protocols from KingByte Information Corp. KingByte's - adapters appear in many no-name portable disk and CD-ROM products, - especially in Europe. If you chose to build PARIDE support into your - kernel, you may answer Y here to build in the protocol driver, - otherwise you should answer M to build it as a loadable module. The - module will be called kbic. You must also have a high-level driver - for the type of device that you want to support. - -config PARIDE_KTTI - tristate "KT PHd protocol" - depends on PARIDE - help - This option enables support for the "PHd" parallel port IDE protocol - from KT Technology. This is a simple (low speed) adapter that is - used in some 2.5" portable hard drives. If you chose to build PARIDE - support into your kernel, you may answer Y here to build in the - protocol driver, otherwise you should answer M to build it as a - loadable module. The module will be called ktti. You must also - have a high-level driver for the type of device that you want to - support. - -config PARIDE_ON20 - tristate "OnSpec 90c20 protocol" - depends on PARIDE - help - This option enables support for the (obsolete) 90c20 parallel port - IDE protocol from OnSpec (often marketed under the ValuStore brand - name). If you chose to build PARIDE support into your kernel, you - may answer Y here to build in the protocol driver, otherwise you - should answer M to build it as a loadable module. The module will - be called on20. You must also have a high-level driver for the - type of device that you want to support. - -config PARIDE_ON26 - tristate "OnSpec 90c26 protocol" - depends on PARIDE - help - This option enables support for the 90c26 parallel port IDE protocol - from OnSpec Electronics (often marketed under the ValuStore brand - name). If you chose to build PARIDE support into your kernel, you - may answer Y here to build in the protocol driver, otherwise you - should answer M to build it as a loadable module. The module will be - called on26. You must also have a high-level driver for the type - of device that you want to support. - -# diff --git a/src/linux/drivers/block/virtio_blk.c b/src/linux/drivers/block/virtio_blk.c deleted file mode 100644 index 5545a67..0000000 --- a/src/linux/drivers/block/virtio_blk.c +++ /dev/null @@ -1,887 +0,0 @@ -//#define DEBUG -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PART_BITS 4 -#define VQ_NAME_LEN 16 - -static int major; -static DEFINE_IDA(vd_index_ida); - -static struct workqueue_struct *virtblk_wq; - -struct virtio_blk_vq { - struct virtqueue *vq; - spinlock_t lock; - char name[VQ_NAME_LEN]; -} ____cacheline_aligned_in_smp; - -struct virtio_blk { - struct virtio_device *vdev; - - /* The disk structure for the kernel. */ - struct gendisk *disk; - - /* Block layer tags. */ - struct blk_mq_tag_set tag_set; - - /* Process context for config space updates */ - struct work_struct config_work; - - /* What host tells us, plus 2 for header & tailer. */ - unsigned int sg_elems; - - /* Ida index - used to track minor number allocations. */ - int index; - - /* num of vqs */ - int num_vqs; - struct virtio_blk_vq *vqs; -}; - -struct virtblk_req { - struct request *req; - struct virtio_blk_outhdr out_hdr; - struct virtio_scsi_inhdr in_hdr; - u8 status; - struct scatterlist sg[]; -}; - -static inline int virtblk_result(struct virtblk_req *vbr) -{ - switch (vbr->status) { - case VIRTIO_BLK_S_OK: - return 0; - case VIRTIO_BLK_S_UNSUPP: - return -ENOTTY; - default: - return -EIO; - } -} - -static int __virtblk_add_req(struct virtqueue *vq, - struct virtblk_req *vbr, - struct scatterlist *data_sg, - bool have_data) -{ - struct scatterlist hdr, status, cmd, sense, inhdr, *sgs[6]; - unsigned int num_out = 0, num_in = 0; - __virtio32 type = vbr->out_hdr.type & ~cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT); - - sg_init_one(&hdr, &vbr->out_hdr, sizeof(vbr->out_hdr)); - sgs[num_out++] = &hdr; - - /* - * If this is a packet command we need a couple of additional headers. - * Behind the normal outhdr we put a segment with the scsi command - * block, and before the normal inhdr we put the sense data and the - * inhdr with additional status information. - */ - if (type == cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_SCSI_CMD)) { - sg_init_one(&cmd, vbr->req->cmd, vbr->req->cmd_len); - sgs[num_out++] = &cmd; - } - - if (have_data) { - if (vbr->out_hdr.type & cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT)) - sgs[num_out++] = data_sg; - else - sgs[num_out + num_in++] = data_sg; - } - - if (type == cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_SCSI_CMD)) { - sg_init_one(&sense, vbr->req->sense, SCSI_SENSE_BUFFERSIZE); - sgs[num_out + num_in++] = &sense; - sg_init_one(&inhdr, &vbr->in_hdr, sizeof(vbr->in_hdr)); - sgs[num_out + num_in++] = &inhdr; - } - - sg_init_one(&status, &vbr->status, sizeof(vbr->status)); - sgs[num_out + num_in++] = &status; - - return virtqueue_add_sgs(vq, sgs, num_out, num_in, vbr, GFP_ATOMIC); -} - -static inline void virtblk_request_done(struct request *req) -{ - struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); - struct virtio_blk *vblk = req->q->queuedata; - int error = virtblk_result(vbr); - - if (req->cmd_type == REQ_TYPE_BLOCK_PC) { - req->resid_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.residual); - req->sense_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.sense_len); - req->errors = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.errors); - } else if (req->cmd_type == REQ_TYPE_DRV_PRIV) { - req->errors = (error != 0); - } - - blk_mq_end_request(req, error); -} - -static void virtblk_done(struct virtqueue *vq) -{ - struct virtio_blk *vblk = vq->vdev->priv; - bool req_done = false; - int qid = vq->index; - struct virtblk_req *vbr; - unsigned long flags; - unsigned int len; - - spin_lock_irqsave(&vblk->vqs[qid].lock, flags); - do { - virtqueue_disable_cb(vq); - while ((vbr = virtqueue_get_buf(vblk->vqs[qid].vq, &len)) != NULL) { - blk_mq_complete_request(vbr->req, vbr->req->errors); - req_done = true; - } - if (unlikely(virtqueue_is_broken(vq))) - break; - } while (!virtqueue_enable_cb(vq)); - - /* In case queue is stopped waiting for more buffers. */ - if (req_done) - blk_mq_start_stopped_hw_queues(vblk->disk->queue, true); - spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags); -} - -static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, - const struct blk_mq_queue_data *bd) -{ - struct virtio_blk *vblk = hctx->queue->queuedata; - struct request *req = bd->rq; - struct virtblk_req *vbr = blk_mq_rq_to_pdu(req); - unsigned long flags; - unsigned int num; - int qid = hctx->queue_num; - int err; - bool notify = false; - - BUG_ON(req->nr_phys_segments + 2 > vblk->sg_elems); - - vbr->req = req; - if (req_op(req) == REQ_OP_FLUSH) { - vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_FLUSH); - vbr->out_hdr.sector = 0; - vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req)); - } else { - switch (req->cmd_type) { - case REQ_TYPE_FS: - vbr->out_hdr.type = 0; - vbr->out_hdr.sector = cpu_to_virtio64(vblk->vdev, blk_rq_pos(vbr->req)); - vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req)); - break; - case REQ_TYPE_BLOCK_PC: - vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_SCSI_CMD); - vbr->out_hdr.sector = 0; - vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req)); - break; - case REQ_TYPE_DRV_PRIV: - vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID); - vbr->out_hdr.sector = 0; - vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req)); - break; - default: - /* We don't put anything else in the queue. */ - BUG(); - } - } - - blk_mq_start_request(req); - - num = blk_rq_map_sg(hctx->queue, vbr->req, vbr->sg); - if (num) { - if (rq_data_dir(vbr->req) == WRITE) - vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_OUT); - else - vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_IN); - } - - spin_lock_irqsave(&vblk->vqs[qid].lock, flags); - err = __virtblk_add_req(vblk->vqs[qid].vq, vbr, vbr->sg, num); - if (err) { - virtqueue_kick(vblk->vqs[qid].vq); - blk_mq_stop_hw_queue(hctx); - spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags); - /* Out of mem doesn't actually happen, since we fall back - * to direct descriptors */ - if (err == -ENOMEM || err == -ENOSPC) - return BLK_MQ_RQ_QUEUE_BUSY; - return BLK_MQ_RQ_QUEUE_ERROR; - } - - if (bd->last && virtqueue_kick_prepare(vblk->vqs[qid].vq)) - notify = true; - spin_unlock_irqrestore(&vblk->vqs[qid].lock, flags); - - if (notify) - virtqueue_notify(vblk->vqs[qid].vq); - return BLK_MQ_RQ_QUEUE_OK; -} - -/* return id (s/n) string for *disk to *id_str - */ -static int virtblk_get_id(struct gendisk *disk, char *id_str) -{ - struct virtio_blk *vblk = disk->private_data; - struct request_queue *q = vblk->disk->queue; - struct request *req; - int err; - - req = blk_get_request(q, READ, GFP_KERNEL); - if (IS_ERR(req)) - return PTR_ERR(req); - req->cmd_type = REQ_TYPE_DRV_PRIV; - - err = blk_rq_map_kern(q, req, id_str, VIRTIO_BLK_ID_BYTES, GFP_KERNEL); - if (err) - goto out; - - err = blk_execute_rq(vblk->disk->queue, vblk->disk, req, false); -out: - blk_put_request(req); - return err; -} - -static int virtblk_ioctl(struct block_device *bdev, fmode_t mode, - unsigned int cmd, unsigned long data) -{ - struct gendisk *disk = bdev->bd_disk; - struct virtio_blk *vblk = disk->private_data; - - /* - * Only allow the generic SCSI ioctls if the host can support it. - */ - if (!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_SCSI)) - return -ENOTTY; - - return scsi_cmd_blk_ioctl(bdev, mode, cmd, - (void __user *)data); -} - -/* We provide getgeo only to please some old bootloader/partitioning tools */ -static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo) -{ - struct virtio_blk *vblk = bd->bd_disk->private_data; - - /* see if the host passed in geometry config */ - if (virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_GEOMETRY)) { - virtio_cread(vblk->vdev, struct virtio_blk_config, - geometry.cylinders, &geo->cylinders); - virtio_cread(vblk->vdev, struct virtio_blk_config, - geometry.heads, &geo->heads); - virtio_cread(vblk->vdev, struct virtio_blk_config, - geometry.sectors, &geo->sectors); - } else { - /* some standard values, similar to sd */ - geo->heads = 1 << 6; - geo->sectors = 1 << 5; - geo->cylinders = get_capacity(bd->bd_disk) >> 11; - } - return 0; -} - -static const struct block_device_operations virtblk_fops = { - .ioctl = virtblk_ioctl, - .owner = THIS_MODULE, - .getgeo = virtblk_getgeo, -}; - -static int index_to_minor(int index) -{ - return index << PART_BITS; -} - -static int minor_to_index(int minor) -{ - return minor >> PART_BITS; -} - -static ssize_t virtblk_serial_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct gendisk *disk = dev_to_disk(dev); - int err; - - /* sysfs gives us a PAGE_SIZE buffer */ - BUILD_BUG_ON(PAGE_SIZE < VIRTIO_BLK_ID_BYTES); - - buf[VIRTIO_BLK_ID_BYTES] = '\0'; - err = virtblk_get_id(disk, buf); - if (!err) - return strlen(buf); - - if (err == -EIO) /* Unsupported? Make it empty. */ - return 0; - - return err; -} - -static DEVICE_ATTR(serial, S_IRUGO, virtblk_serial_show, NULL); - -static void virtblk_config_changed_work(struct work_struct *work) -{ - struct virtio_blk *vblk = - container_of(work, struct virtio_blk, config_work); - struct virtio_device *vdev = vblk->vdev; - struct request_queue *q = vblk->disk->queue; - char cap_str_2[10], cap_str_10[10]; - char *envp[] = { "RESIZE=1", NULL }; - u64 capacity; - - /* Host must always specify the capacity. */ - virtio_cread(vdev, struct virtio_blk_config, capacity, &capacity); - - /* If capacity is too big, truncate with warning. */ - if ((sector_t)capacity != capacity) { - dev_warn(&vdev->dev, "Capacity %llu too large: truncating\n", - (unsigned long long)capacity); - capacity = (sector_t)-1; - } - - string_get_size(capacity, queue_logical_block_size(q), - STRING_UNITS_2, cap_str_2, sizeof(cap_str_2)); - string_get_size(capacity, queue_logical_block_size(q), - STRING_UNITS_10, cap_str_10, sizeof(cap_str_10)); - - dev_notice(&vdev->dev, - "new size: %llu %d-byte logical blocks (%s/%s)\n", - (unsigned long long)capacity, - queue_logical_block_size(q), - cap_str_10, cap_str_2); - - set_capacity(vblk->disk, capacity); - revalidate_disk(vblk->disk); - kobject_uevent_env(&disk_to_dev(vblk->disk)->kobj, KOBJ_CHANGE, envp); -} - -static void virtblk_config_changed(struct virtio_device *vdev) -{ - struct virtio_blk *vblk = vdev->priv; - - queue_work(virtblk_wq, &vblk->config_work); -} - -static int init_vq(struct virtio_blk *vblk) -{ - int err; - int i; - vq_callback_t **callbacks; - const char **names; - struct virtqueue **vqs; - unsigned short num_vqs; - struct virtio_device *vdev = vblk->vdev; - - err = virtio_cread_feature(vdev, VIRTIO_BLK_F_MQ, - struct virtio_blk_config, num_queues, - &num_vqs); - if (err) - num_vqs = 1; - - vblk->vqs = kmalloc_array(num_vqs, sizeof(*vblk->vqs), GFP_KERNEL); - if (!vblk->vqs) - return -ENOMEM; - - names = kmalloc_array(num_vqs, sizeof(*names), GFP_KERNEL); - callbacks = kmalloc_array(num_vqs, sizeof(*callbacks), GFP_KERNEL); - vqs = kmalloc_array(num_vqs, sizeof(*vqs), GFP_KERNEL); - if (!names || !callbacks || !vqs) { - err = -ENOMEM; - goto out; - } - - for (i = 0; i < num_vqs; i++) { - callbacks[i] = virtblk_done; - snprintf(vblk->vqs[i].name, VQ_NAME_LEN, "req.%d", i); - names[i] = vblk->vqs[i].name; - } - - /* Discover virtqueues and write information to configuration. */ - err = vdev->config->find_vqs(vdev, num_vqs, vqs, callbacks, names); - if (err) - goto out; - - for (i = 0; i < num_vqs; i++) { - spin_lock_init(&vblk->vqs[i].lock); - vblk->vqs[i].vq = vqs[i]; - } - vblk->num_vqs = num_vqs; - -out: - kfree(vqs); - kfree(callbacks); - kfree(names); - if (err) - kfree(vblk->vqs); - return err; -} - -/* - * Legacy naming scheme used for virtio devices. We are stuck with it for - * virtio blk but don't ever use it for any new driver. - */ -static int virtblk_name_format(char *prefix, int index, char *buf, int buflen) -{ - const int base = 'z' - 'a' + 1; - char *begin = buf + strlen(prefix); - char *end = buf + buflen; - char *p; - int unit; - - p = end - 1; - *p = '\0'; - unit = base; - do { - if (p == begin) - return -EINVAL; - *--p = 'a' + (index % unit); - index = (index / unit) - 1; - } while (index >= 0); - - memmove(begin, p, end - p); - memcpy(buf, prefix, strlen(prefix)); - - return 0; -} - -static int virtblk_get_cache_mode(struct virtio_device *vdev) -{ - u8 writeback; - int err; - - err = virtio_cread_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE, - struct virtio_blk_config, wce, - &writeback); - - /* - * If WCE is not configurable and flush is not available, - * assume no writeback cache is in use. - */ - if (err) - writeback = virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH); - - return writeback; -} - -static void virtblk_update_cache_mode(struct virtio_device *vdev) -{ - u8 writeback = virtblk_get_cache_mode(vdev); - struct virtio_blk *vblk = vdev->priv; - - blk_queue_write_cache(vblk->disk->queue, writeback, false); - revalidate_disk(vblk->disk); -} - -static const char *const virtblk_cache_types[] = { - "write through", "write back" -}; - -static ssize_t -virtblk_cache_type_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct gendisk *disk = dev_to_disk(dev); - struct virtio_blk *vblk = disk->private_data; - struct virtio_device *vdev = vblk->vdev; - int i; - - BUG_ON(!virtio_has_feature(vblk->vdev, VIRTIO_BLK_F_CONFIG_WCE)); - for (i = ARRAY_SIZE(virtblk_cache_types); --i >= 0; ) - if (sysfs_streq(buf, virtblk_cache_types[i])) - break; - - if (i < 0) - return -EINVAL; - - virtio_cwrite8(vdev, offsetof(struct virtio_blk_config, wce), i); - virtblk_update_cache_mode(vdev); - return count; -} - -static ssize_t -virtblk_cache_type_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct gendisk *disk = dev_to_disk(dev); - struct virtio_blk *vblk = disk->private_data; - u8 writeback = virtblk_get_cache_mode(vblk->vdev); - - BUG_ON(writeback >= ARRAY_SIZE(virtblk_cache_types)); - return snprintf(buf, 40, "%s\n", virtblk_cache_types[writeback]); -} - -static const struct device_attribute dev_attr_cache_type_ro = - __ATTR(cache_type, S_IRUGO, - virtblk_cache_type_show, NULL); -static const struct device_attribute dev_attr_cache_type_rw = - __ATTR(cache_type, S_IRUGO|S_IWUSR, - virtblk_cache_type_show, virtblk_cache_type_store); - -static int virtblk_init_request(void *data, struct request *rq, - unsigned int hctx_idx, unsigned int request_idx, - unsigned int numa_node) -{ - struct virtio_blk *vblk = data; - struct virtblk_req *vbr = blk_mq_rq_to_pdu(rq); - - sg_init_table(vbr->sg, vblk->sg_elems); - return 0; -} - -static struct blk_mq_ops virtio_mq_ops = { - .queue_rq = virtio_queue_rq, - .complete = virtblk_request_done, - .init_request = virtblk_init_request, -}; - -static unsigned int virtblk_queue_depth; -module_param_named(queue_depth, virtblk_queue_depth, uint, 0444); - -static int virtblk_probe(struct virtio_device *vdev) -{ - struct virtio_blk *vblk; - struct request_queue *q; - int err, index; - - u64 cap; - u32 v, blk_size, sg_elems, opt_io_size; - u16 min_io_size; - u8 physical_block_exp, alignment_offset; - - if (!vdev->config->get) { - dev_err(&vdev->dev, "%s failure: config access disabled\n", - __func__); - return -EINVAL; - } - - err = ida_simple_get(&vd_index_ida, 0, minor_to_index(1 << MINORBITS), - GFP_KERNEL); - if (err < 0) - goto out; - index = err; - - /* We need to know how many segments before we allocate. */ - err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SEG_MAX, - struct virtio_blk_config, seg_max, - &sg_elems); - - /* We need at least one SG element, whatever they say. */ - if (err || !sg_elems) - sg_elems = 1; - - /* We need an extra sg elements at head and tail. */ - sg_elems += 2; - vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL); - if (!vblk) { - err = -ENOMEM; - goto out_free_index; - } - - vblk->vdev = vdev; - vblk->sg_elems = sg_elems; - - INIT_WORK(&vblk->config_work, virtblk_config_changed_work); - - err = init_vq(vblk); - if (err) - goto out_free_vblk; - - /* FIXME: How many partitions? How long is a piece of string? */ - vblk->disk = alloc_disk(1 << PART_BITS); - if (!vblk->disk) { - err = -ENOMEM; - goto out_free_vq; - } - - /* Default queue sizing is to fill the ring. */ - if (!virtblk_queue_depth) { - virtblk_queue_depth = vblk->vqs[0].vq->num_free; - /* ... but without indirect descs, we use 2 descs per req */ - if (!virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC)) - virtblk_queue_depth /= 2; - } - - memset(&vblk->tag_set, 0, sizeof(vblk->tag_set)); - vblk->tag_set.ops = &virtio_mq_ops; - vblk->tag_set.queue_depth = virtblk_queue_depth; - vblk->tag_set.numa_node = NUMA_NO_NODE; - vblk->tag_set.flags = BLK_MQ_F_SHOULD_MERGE; - vblk->tag_set.cmd_size = - sizeof(struct virtblk_req) + - sizeof(struct scatterlist) * sg_elems; - vblk->tag_set.driver_data = vblk; - vblk->tag_set.nr_hw_queues = vblk->num_vqs; - - err = blk_mq_alloc_tag_set(&vblk->tag_set); - if (err) - goto out_put_disk; - - q = vblk->disk->queue = blk_mq_init_queue(&vblk->tag_set); - if (IS_ERR(q)) { - err = -ENOMEM; - goto out_free_tags; - } - - q->queuedata = vblk; - - virtblk_name_format("vd", index, vblk->disk->disk_name, DISK_NAME_LEN); - - vblk->disk->major = major; - vblk->disk->first_minor = index_to_minor(index); - vblk->disk->private_data = vblk; - vblk->disk->fops = &virtblk_fops; - vblk->disk->flags |= GENHD_FL_EXT_DEVT; - vblk->index = index; - - /* configure queue flush support */ - virtblk_update_cache_mode(vdev); - - /* If disk is read-only in the host, the guest should obey */ - if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO)) - set_disk_ro(vblk->disk, 1); - - /* Host must always specify the capacity. */ - virtio_cread(vdev, struct virtio_blk_config, capacity, &cap); - - /* If capacity is too big, truncate with warning. */ - if ((sector_t)cap != cap) { - dev_warn(&vdev->dev, "Capacity %llu too large: truncating\n", - (unsigned long long)cap); - cap = (sector_t)-1; - } - set_capacity(vblk->disk, cap); - - /* We can handle whatever the host told us to handle. */ - blk_queue_max_segments(q, vblk->sg_elems-2); - - /* No need to bounce any requests */ - blk_queue_bounce_limit(q, BLK_BOUNCE_ANY); - - /* No real sector limit. */ - blk_queue_max_hw_sectors(q, -1U); - - /* Host can optionally specify maximum segment size and number of - * segments. */ - err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SIZE_MAX, - struct virtio_blk_config, size_max, &v); - if (!err) - blk_queue_max_segment_size(q, v); - else - blk_queue_max_segment_size(q, -1U); - - /* Host can optionally specify the block size of the device */ - err = virtio_cread_feature(vdev, VIRTIO_BLK_F_BLK_SIZE, - struct virtio_blk_config, blk_size, - &blk_size); - if (!err) - blk_queue_logical_block_size(q, blk_size); - else - blk_size = queue_logical_block_size(q); - - /* Use topology information if available */ - err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY, - struct virtio_blk_config, physical_block_exp, - &physical_block_exp); - if (!err && physical_block_exp) - blk_queue_physical_block_size(q, - blk_size * (1 << physical_block_exp)); - - err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY, - struct virtio_blk_config, alignment_offset, - &alignment_offset); - if (!err && alignment_offset) - blk_queue_alignment_offset(q, blk_size * alignment_offset); - - err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY, - struct virtio_blk_config, min_io_size, - &min_io_size); - if (!err && min_io_size) - blk_queue_io_min(q, blk_size * min_io_size); - - err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY, - struct virtio_blk_config, opt_io_size, - &opt_io_size); - if (!err && opt_io_size) - blk_queue_io_opt(q, blk_size * opt_io_size); - - virtio_device_ready(vdev); - - device_add_disk(&vdev->dev, vblk->disk); - err = device_create_file(disk_to_dev(vblk->disk), &dev_attr_serial); - if (err) - goto out_del_disk; - - if (virtio_has_feature(vdev, VIRTIO_BLK_F_CONFIG_WCE)) - err = device_create_file(disk_to_dev(vblk->disk), - &dev_attr_cache_type_rw); - else - err = device_create_file(disk_to_dev(vblk->disk), - &dev_attr_cache_type_ro); - if (err) - goto out_del_disk; - return 0; - -out_del_disk: - del_gendisk(vblk->disk); - blk_cleanup_queue(vblk->disk->queue); -out_free_tags: - blk_mq_free_tag_set(&vblk->tag_set); -out_put_disk: - put_disk(vblk->disk); -out_free_vq: - vdev->config->del_vqs(vdev); -out_free_vblk: - kfree(vblk); -out_free_index: - ida_simple_remove(&vd_index_ida, index); -out: - return err; -} - -static void virtblk_remove(struct virtio_device *vdev) -{ - struct virtio_blk *vblk = vdev->priv; - int index = vblk->index; - int refc; - - /* Make sure no work handler is accessing the device. */ - flush_work(&vblk->config_work); - - del_gendisk(vblk->disk); - blk_cleanup_queue(vblk->disk->queue); - - blk_mq_free_tag_set(&vblk->tag_set); - - /* Stop all the virtqueues. */ - vdev->config->reset(vdev); - - refc = atomic_read(&disk_to_dev(vblk->disk)->kobj.kref.refcount); - put_disk(vblk->disk); - vdev->config->del_vqs(vdev); - kfree(vblk->vqs); - kfree(vblk); - - /* Only free device id if we don't have any users */ - if (refc == 1) - ida_simple_remove(&vd_index_ida, index); -} - -#ifdef CONFIG_PM_SLEEP -static int virtblk_freeze(struct virtio_device *vdev) -{ - struct virtio_blk *vblk = vdev->priv; - - /* Ensure we don't receive any more interrupts */ - vdev->config->reset(vdev); - - /* Make sure no work handler is accessing the device. */ - flush_work(&vblk->config_work); - - blk_mq_stop_hw_queues(vblk->disk->queue); - - vdev->config->del_vqs(vdev); - return 0; -} - -static int virtblk_restore(struct virtio_device *vdev) -{ - struct virtio_blk *vblk = vdev->priv; - int ret; - - ret = init_vq(vdev->priv); - if (ret) - return ret; - - virtio_device_ready(vdev); - - blk_mq_start_stopped_hw_queues(vblk->disk->queue, true); - return 0; -} -#endif - -static const struct virtio_device_id id_table[] = { - { VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID }, - { 0 }, -}; - -static unsigned int features_legacy[] = { - VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY, - VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_SCSI, - VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE, - VIRTIO_BLK_F_MQ, -} -; -static unsigned int features[] = { - VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY, - VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, - VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE, - VIRTIO_BLK_F_MQ, -}; - -static struct virtio_driver virtio_blk = { - .feature_table = features, - .feature_table_size = ARRAY_SIZE(features), - .feature_table_legacy = features_legacy, - .feature_table_size_legacy = ARRAY_SIZE(features_legacy), - .driver.name = KBUILD_MODNAME, - .driver.owner = THIS_MODULE, - .id_table = id_table, - .probe = virtblk_probe, - .remove = virtblk_remove, - .config_changed = virtblk_config_changed, -#ifdef CONFIG_PM_SLEEP - .freeze = virtblk_freeze, - .restore = virtblk_restore, -#endif -}; - -static int __init init(void) -{ - int error; - - virtblk_wq = alloc_workqueue("virtio-blk", 0, 0); - if (!virtblk_wq) - return -ENOMEM; - - major = register_blkdev(0, "virtblk"); - if (major < 0) { - error = major; - goto out_destroy_workqueue; - } - - error = register_virtio_driver(&virtio_blk); - if (error) - goto out_unregister_blkdev; - return 0; - -out_unregister_blkdev: - unregister_blkdev(major, "virtblk"); -out_destroy_workqueue: - destroy_workqueue(virtblk_wq); - return error; -} - -static void __exit fini(void) -{ - unregister_virtio_driver(&virtio_blk); - unregister_blkdev(major, "virtblk"); - destroy_workqueue(virtblk_wq); -} -module_init(init); -module_exit(fini); - -MODULE_DEVICE_TABLE(virtio, id_table); -MODULE_DESCRIPTION("Virtio block driver"); -MODULE_LICENSE("GPL"); diff --git a/src/linux/drivers/block/zram/Kconfig b/src/linux/drivers/block/zram/Kconfig deleted file mode 100644 index b8ecba6..0000000 --- a/src/linux/drivers/block/zram/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -config ZRAM - tristate "Compressed RAM block device support" - depends on BLOCK && SYSFS && ZSMALLOC && CRYPTO - select CRYPTO_LZO - default n - help - Creates virtual block devices called /dev/zramX (X = 0, 1, ...). - Pages written to these disks are compressed and stored in memory - itself. These disks allow very fast I/O and compression provides - good amounts of memory savings. - - It has several use cases, for example: /tmp storage, use as swap - disks and maybe many more. - - See zram.txt for more information. diff --git a/src/linux/drivers/bluetooth/Kconfig b/src/linux/drivers/bluetooth/Kconfig deleted file mode 100644 index 3cc9bff..0000000 --- a/src/linux/drivers/bluetooth/Kconfig +++ /dev/null @@ -1,357 +0,0 @@ - -menu "Bluetooth device drivers" - depends on BT - -config BT_INTEL - tristate - select REGMAP - -config BT_BCM - tristate - select FW_LOADER - -config BT_RTL - tristate - select FW_LOADER - -config BT_QCA - tristate - select FW_LOADER - -config BT_HCIBTUSB - tristate "HCI USB driver" - depends on USB - select BT_INTEL - help - Bluetooth HCI USB driver. - This driver is required if you want to use Bluetooth devices with - USB interface. - - Say Y here to compile support for Bluetooth USB devices into the - kernel or say M to compile it as module (btusb). - -config BT_HCIBTUSB_BCM - bool "Broadcom protocol support" - depends on BT_HCIBTUSB - select BT_BCM - default y - help - The Broadcom protocol support enables firmware and patchram - download support for Broadcom Bluetooth controllers. - - Say Y here to compile support for Broadcom protocol. - -config BT_HCIBTUSB_RTL - bool "Realtek protocol support" - depends on BT_HCIBTUSB - select BT_RTL - default y - help - The Realtek protocol support enables firmware and configuration - download support for Realtek Bluetooth controllers. - - Say Y here to compile support for Realtek protocol. - -config BT_HCIBTSDIO - tristate "HCI SDIO driver" - depends on MMC - help - Bluetooth HCI SDIO driver. - This driver is required if you want to use Bluetooth device with - SDIO interface. - - Say Y here to compile support for Bluetooth SDIO devices into the - kernel or say M to compile it as module (btsdio). - -config BT_HCIUART - tristate "HCI UART driver" - depends on TTY - help - Bluetooth HCI UART driver. - This driver is required if you want to use Bluetooth devices with - serial port interface. You will also need this driver if you have - UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card - adapter and BrainBoxes Bluetooth PC Card. - - Say Y here to compile support for Bluetooth UART devices into the - kernel or say M to compile it as module (hci_uart). - -config BT_HCIUART_H4 - bool "UART (H4) protocol support" - depends on BT_HCIUART - help - UART (H4) is serial protocol for communication between Bluetooth - device and host. This protocol is required for most Bluetooth devices - with UART interface, including PCMCIA and CF cards. - - Say Y here to compile support for HCI UART (H4) protocol. - -config BT_HCIUART_BCSP - bool "BCSP protocol support" - depends on BT_HCIUART - select BITREVERSE - help - BCSP (BlueCore Serial Protocol) is serial protocol for communication - between Bluetooth device and host. This protocol is required for non - USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and - CF cards. - - Say Y here to compile support for HCI BCSP protocol. - -config BT_HCIUART_ATH3K - bool "Atheros AR300x serial support" - depends on BT_HCIUART - select BT_HCIUART_H4 - help - HCIATH3K (HCI Atheros AR300x) is a serial protocol for - communication between host and Atheros AR300x Bluetooth devices. - This protocol enables AR300x chips to be enabled with - power management support. - Enable this if you have Atheros AR300x serial Bluetooth device. - - Say Y here to compile support for HCI UART ATH3K protocol. - -config BT_HCIUART_LL - bool "HCILL protocol support" - depends on BT_HCIUART - help - HCILL (HCI Low Level) is a serial protocol for communication - between Bluetooth device and host. This protocol is required for - serial Bluetooth devices that are based on Texas Instruments' - BRF chips. - - Say Y here to compile support for HCILL protocol. - -config BT_HCIUART_3WIRE - bool "Three-wire UART (H5) protocol support" - depends on BT_HCIUART - help - The HCI Three-wire UART Transport Layer makes it possible to - user the Bluetooth HCI over a serial port interface. The HCI - Three-wire UART Transport Layer assumes that the UART - communication may have bit errors, overrun errors or burst - errors and thereby making CTS/RTS lines unnecessary. - - Say Y here to compile support for Three-wire UART protocol. - -config BT_HCIUART_INTEL - bool "Intel protocol support" - depends on BT_HCIUART - select BT_HCIUART_H4 - select BT_INTEL - help - The Intel protocol support enables Bluetooth HCI over serial - port interface for Intel Bluetooth controllers. - - Say Y here to compile support for Intel protocol. - -config BT_HCIUART_BCM - bool "Broadcom protocol support" - depends on BT_HCIUART - select BT_HCIUART_H4 - select BT_BCM - help - The Broadcom protocol support enables Bluetooth HCI over serial - port interface for Broadcom Bluetooth controllers. - - Say Y here to compile support for Broadcom protocol. - -config BT_HCIUART_QCA - bool "Qualcomm Atheros protocol support" - depends on BT_HCIUART - select BT_HCIUART_H4 - select BT_QCA - help - The Qualcomm Atheros protocol supports HCI In-Band Sleep feature - over serial port interface(H4) between controller and host. - This protocol is required for UART clock control for QCA Bluetooth - devices. - - Say Y here to compile support for QCA protocol. - -config BT_HCIUART_AG6XX - bool "Intel AG6XX protocol support" - depends on BT_HCIUART - select BT_HCIUART_H4 - select BT_INTEL - help - The Intel/AG6XX protocol support enables Bluetooth HCI over serial - port interface for Intel ibt 2.1 Bluetooth controllers. - - Say Y here to compile support for Intel AG6XX protocol. - -config BT_HCIUART_MRVL - bool "Marvell protocol support" - depends on BT_HCIUART - select BT_HCIUART_H4 - help - Marvell is serial protocol for communication between Bluetooth - device and host. This protocol is required for most Marvell Bluetooth - devices with UART interface. - - Say Y here to compile support for HCI MRVL protocol. - -config BT_HCIBCM203X - tristate "HCI BCM203x USB driver" - depends on USB - select FW_LOADER - help - Bluetooth HCI BCM203x USB driver. - This driver provides the firmware loading mechanism for the Broadcom - Blutonium based devices. - - Say Y here to compile support for HCI BCM203x devices into the - kernel or say M to compile it as module (bcm203x). - -config BT_HCIBPA10X - tristate "HCI BPA10x USB driver" - depends on USB && BT_HCIUART - select BT_HCIUART_H4 - help - Bluetooth HCI BPA10x USB driver. - This driver provides support for the Digianswer BPA 100/105 Bluetooth - sniffer devices. - - Say Y here to compile support for HCI BPA10x devices into the - kernel or say M to compile it as module (bpa10x). - -config BT_HCIBFUSB - tristate "HCI BlueFRITZ! USB driver" - depends on USB - select FW_LOADER - help - Bluetooth HCI BlueFRITZ! USB driver. - This driver provides support for Bluetooth USB devices with AVM - interface: - AVM BlueFRITZ! USB - - Say Y here to compile support for HCI BFUSB devices into the - kernel or say M to compile it as module (bfusb). - -config BT_HCIDTL1 - tristate "HCI DTL1 (PC Card) driver" - depends on PCMCIA - help - Bluetooth HCI DTL1 (PC Card) driver. - This driver provides support for Bluetooth PCMCIA devices with - Nokia DTL1 interface: - Nokia Bluetooth Card - Socket Bluetooth CF Card - - Say Y here to compile support for HCI DTL1 devices into the - kernel or say M to compile it as module (dtl1_cs). - -config BT_HCIBT3C - tristate "HCI BT3C (PC Card) driver" - depends on PCMCIA - select FW_LOADER - help - Bluetooth HCI BT3C (PC Card) driver. - This driver provides support for Bluetooth PCMCIA devices with - 3Com BT3C interface: - 3Com Bluetooth Card (3CRWB6096) - HP Bluetooth Card - - Say Y here to compile support for HCI BT3C devices into the - kernel or say M to compile it as module (bt3c_cs). - -config BT_HCIBLUECARD - tristate "HCI BlueCard (PC Card) driver" - depends on PCMCIA - help - Bluetooth HCI BlueCard (PC Card) driver. - This driver provides support for Bluetooth PCMCIA devices with - Anycom BlueCard interface: - Anycom Bluetooth PC Card - Anycom Bluetooth CF Card - - Say Y here to compile support for HCI BlueCard devices into the - kernel or say M to compile it as module (bluecard_cs). - -config BT_HCIBTUART - tristate "HCI UART (PC Card) device driver" - depends on PCMCIA - help - Bluetooth HCI UART (PC Card) driver. - This driver provides support for Bluetooth PCMCIA devices with - an UART interface: - Xircom CreditCard Bluetooth Adapter - Xircom RealPort2 Bluetooth Adapter - Sphinx PICO Card - H-Soft blue+Card - Cyber-blue Compact Flash Card - - Say Y here to compile support for HCI UART devices into the - kernel or say M to compile it as module (btuart_cs). - -config BT_HCIVHCI - tristate "HCI VHCI (Virtual HCI device) driver" - help - Bluetooth Virtual HCI device driver. - This driver is required if you want to use HCI Emulation software. - - Say Y here to compile support for virtual HCI devices into the - kernel or say M to compile it as module (hci_vhci). - -config BT_MRVL - tristate "Marvell Bluetooth driver support" - help - The core driver to support Marvell Bluetooth devices. - - This driver is required if you want to support - Marvell Bluetooth devices, such as 8688/8787/8797/8887/8897/8997. - - Say Y here to compile Marvell Bluetooth driver - into the kernel or say M to compile it as module. - -config BT_MRVL_SDIO - tristate "Marvell BT-over-SDIO driver" - depends on BT_MRVL && MMC - select FW_LOADER - select WANT_DEV_COREDUMP - help - The driver for Marvell Bluetooth chipsets with SDIO interface. - - This driver is required if you want to use Marvell Bluetooth - devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8887/SD8897/SD8997 - chipsets are supported. - - Say Y here to compile support for Marvell BT-over-SDIO driver - into the kernel or say M to compile it as module. - -config BT_ATH3K - tristate "Atheros firmware download driver" - depends on BT_HCIBTUSB - select FW_LOADER - help - Bluetooth firmware download driver. - This driver loads the firmware into the Atheros Bluetooth - chipset. - - Say Y here to compile support for "Atheros firmware download driver" - into the kernel or say M to compile it as module (ath3k). - -config BT_WILINK - tristate "Texas Instruments WiLink7 driver" - depends on TI_ST - help - This enables the Bluetooth driver for Texas Instrument's BT/FM/GPS - combo devices. This makes use of shared transport line discipline - core driver to communicate with the BT core of the combo chip. - - Say Y here to compile support for Texas Instrument's WiLink7 driver - into the kernel or say M to compile it as module (btwilink). - -config BT_QCOMSMD - tristate "Qualcomm SMD based HCI support" - depends on QCOM_SMD && QCOM_WCNSS_CTRL - select BT_QCA - help - Qualcomm SMD based HCI driver. - This driver is used to bridge HCI data onto the shared memory - channels to the WCNSS core. - - Say Y here to compile support for HCI over Qualcomm SMD into the - kernel or say M to compile as a module. - -endmenu diff --git a/src/linux/drivers/bus/Kconfig b/src/linux/drivers/bus/Kconfig deleted file mode 100644 index 7875105..0000000 --- a/src/linux/drivers/bus/Kconfig +++ /dev/null @@ -1,170 +0,0 @@ -# -# Bus Devices -# - -menu "Bus devices" - -config ARM_CCI - bool - -config ARM_CCI_PMU - bool - select ARM_CCI - -config ARM_CCI400_COMMON - bool - select ARM_CCI - -config ARM_CCI400_PMU - bool "ARM CCI400 PMU support" - depends on (ARM && CPU_V7) || ARM64 - depends on PERF_EVENTS - select ARM_CCI400_COMMON - select ARM_CCI_PMU - help - Support for PMU events monitoring on the ARM CCI-400 (cache coherent - interconnect). CCI-400 supports counting events related to the - connected slave/master interfaces. - -config ARM_CCI400_PORT_CTRL - bool - depends on ARM && OF && CPU_V7 - select ARM_CCI400_COMMON - help - Low level power management driver for CCI400 cache coherent - interconnect for ARM platforms. - -config ARM_CCI5xx_PMU - bool "ARM CCI-500/CCI-550 PMU support" - depends on (ARM && CPU_V7) || ARM64 - depends on PERF_EVENTS - select ARM_CCI_PMU - help - Support for PMU events monitoring on the ARM CCI-500/CCI-550 cache - coherent interconnects. Both of them provide 8 independent event counters, - which can count events pertaining to the slave/master interfaces as well - as the internal events to the CCI. - - If unsure, say Y - -config ARM_CCN - tristate "ARM CCN driver support" - depends on ARM || ARM64 - depends on PERF_EVENTS - help - PMU (perf) driver supporting the ARM CCN (Cache Coherent Network) - interconnect. - -config BRCMSTB_GISB_ARB - bool "Broadcom STB GISB bus arbiter" - depends on ARM || MIPS - default ARCH_BRCMSTB || BMIPS_GENERIC - help - Driver for the Broadcom Set Top Box System-on-a-chip internal bus - arbiter. This driver provides timeout and target abort error handling - and internal bus master decoding. - -config IMX_WEIM - bool "Freescale EIM DRIVER" - depends on ARCH_MXC - help - Driver for i.MX WEIM controller. - The WEIM(Wireless External Interface Module) works like a bus. - You can attach many different devices on it, such as NOR, onenand. - -config MIPS_CDMM - bool "MIPS Common Device Memory Map (CDMM) Driver" - depends on CPU_MIPSR2 - help - Driver needed for the MIPS Common Device Memory Map bus in MIPS - cores. This bus is for per-CPU tightly coupled devices such as the - Fast Debug Channel (FDC). - - For this to work, either your bootloader needs to enable the CDMM - region at an unused physical address on the boot CPU, or else your - platform code needs to implement mips_cdmm_phys_base() (see - asm/cdmm.h). - -config MVEBU_MBUS - bool - depends on PLAT_ORION - help - Driver needed for the MBus configuration on Marvell EBU SoCs - (Kirkwood, Dove, Orion5x, MV78XX0 and Armada 370/XP). - -config OMAP_INTERCONNECT - tristate "OMAP INTERCONNECT DRIVER" - depends on ARCH_OMAP2PLUS - - help - Driver to enable OMAP interconnect error handling driver. - -config OMAP_OCP2SCP - tristate "OMAP OCP2SCP DRIVER" - depends on ARCH_OMAP2PLUS - help - Driver to enable ocp2scp module which transforms ocp interface - protocol to scp protocol. In OMAP4, USB PHY is connected via - OCP2SCP and in OMAP5, both USB PHY and SATA PHY is connected via - OCP2SCP. - -config QCOM_EBI2 - bool "Qualcomm External Bus Interface 2 (EBI2)" - depends on HAS_IOMEM - depends on ARCH_QCOM || COMPILE_TEST - help - Say y here to enable support for the Qualcomm External Bus - Interface 2, which can be used to connect things like NAND Flash, - SRAM, ethernet adapters, FPGAs and LCD displays. - -config SIMPLE_PM_BUS - bool "Simple Power-Managed Bus Driver" - depends on OF && PM - depends on ARCH_RENESAS || COMPILE_TEST - help - Driver for transparent busses that don't need a real driver, but - where the bus controller is part of a PM domain, or under the control - of a functional clock, and thus relies on runtime PM for managing - this PM domain and/or clock. - An example of such a bus controller is the Renesas Bus State - Controller (BSC, sometimes called "LBSC within Bus Bridge", or - "External Bus Interface") as found on several Renesas ARM SoCs. - -config SUNXI_RSB - tristate "Allwinner sunXi Reduced Serial Bus Driver" - default MACH_SUN8I || MACH_SUN9I - depends on ARCH_SUNXI - select REGMAP - help - Say y here to enable support for Allwinner's Reduced Serial Bus - (RSB) support. This controller is responsible for communicating - with various RSB based devices, such as AXP223, AXP8XX PMICs, - and AC100/AC200 ICs. - -config TEGRA_ACONNECT - tristate "Tegra ACONNECT Bus Driver" - depends on ARCH_TEGRA_210_SOC - depends on OF && PM - select PM_CLK - help - Driver for the Tegra ACONNECT bus which is used to interface with - the devices inside the Audio Processing Engine (APE) for Tegra210. - -config UNIPHIER_SYSTEM_BUS - tristate "UniPhier System Bus driver" - depends on ARCH_UNIPHIER && OF - default y - help - Support for UniPhier System Bus, a simple external bus. This is - needed to use on-board devices connected to UniPhier SoCs. - -config VEXPRESS_CONFIG - bool "Versatile Express configuration bus" - default y if ARCH_VEXPRESS - depends on ARM || ARM64 - depends on OF - select REGMAP - help - Platform configuration infrastructure for the ARM Ltd. - Versatile Express. -endmenu diff --git a/src/linux/drivers/bus/Makefile b/src/linux/drivers/bus/Makefile deleted file mode 100644 index c6cfa6b..0000000 --- a/src/linux/drivers/bus/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -# -# Makefile for the bus drivers. -# - -# Interconnect bus drivers for ARM platforms -obj-$(CONFIG_ARM_CCI) += arm-cci.o -obj-$(CONFIG_ARM_CCN) += arm-ccn.o - -obj-$(CONFIG_BRCMSTB_GISB_ARB) += brcmstb_gisb.o -obj-$(CONFIG_IMX_WEIM) += imx-weim.o -obj-$(CONFIG_MIPS_CDMM) += mips_cdmm.o -obj-$(CONFIG_MVEBU_MBUS) += mvebu-mbus.o - -# Interconnect bus driver for OMAP SoCs. -obj-$(CONFIG_OMAP_INTERCONNECT) += omap_l3_smx.o omap_l3_noc.o - -obj-$(CONFIG_OMAP_OCP2SCP) += omap-ocp2scp.o -obj-$(CONFIG_QCOM_EBI2) += qcom-ebi2.o -obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o -obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o -obj-$(CONFIG_TEGRA_ACONNECT) += tegra-aconnect.o -obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o -obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o diff --git a/src/linux/drivers/cdrom/Makefile b/src/linux/drivers/cdrom/Makefile deleted file mode 100644 index 8ffde4f..0000000 --- a/src/linux/drivers/cdrom/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# Makefile for the kernel cdrom device drivers. -# -# 30 Jan 1998, Michael Elizabeth Chastain, -# Rewritten to use lists instead of if-statements. - -# Each configuration option enables a list of files. - -obj-$(CONFIG_BLK_DEV_IDECD) += cdrom.o -obj-$(CONFIG_BLK_DEV_SR) += cdrom.o -obj-$(CONFIG_PARIDE_PCD) += cdrom.o -obj-$(CONFIG_CDROM_PKTCDVD) += cdrom.o - -obj-$(CONFIG_GDROM) += gdrom.o cdrom.o diff --git a/src/linux/drivers/char/Kconfig b/src/linux/drivers/char/Kconfig deleted file mode 100644 index dcc0973..0000000 --- a/src/linux/drivers/char/Kconfig +++ /dev/null @@ -1,594 +0,0 @@ -# -# Character device configuration -# - -menu "Character devices" - -source "drivers/tty/Kconfig" - -config DEVMEM - bool "/dev/mem virtual device support" - default y - help - Say Y here if you want to support the /dev/mem device. - The /dev/mem device is used to access areas of physical - memory. - When in doubt, say "Y". - -config DEVKMEM - bool "/dev/kmem virtual device support" - default y - help - Say Y here if you want to support the /dev/kmem device. The - /dev/kmem device is rarely used, but can be used for certain - kind of kernel debugging operations. - When in doubt, say "N". - -config SGI_SNSC - bool "SGI Altix system controller communication support" - depends on (IA64_SGI_SN2 || IA64_GENERIC) - help - If you have an SGI Altix and you want to enable system - controller communication from user space (you want this!), - say Y. Otherwise, say N. - -config SGI_TIOCX - bool "SGI TIO CX driver support" - depends on (IA64_SGI_SN2 || IA64_GENERIC) - help - If you have an SGI Altix and you have fpga devices attached - to your TIO, say Y here, otherwise say N. - -config SGI_MBCS - tristate "SGI FPGA Core Services driver support" - depends on SGI_TIOCX - help - If you have an SGI Altix with an attached SABrick - say Y or M here, otherwise say N. - -source "drivers/tty/serial/Kconfig" - -config TTY_PRINTK - tristate "TTY driver to output user messages via printk" - depends on EXPERT && TTY - default n - ---help--- - If you say Y here, the support for writing user messages (i.e. - console messages) via printk is available. - - The feature is useful to inline user messages with kernel - messages. - In order to use this feature, you should output user messages - to /dev/ttyprintk or redirect console to this TTY. - - If unsure, say N. - -config BFIN_OTP - tristate "Blackfin On-Chip OTP Memory Support" - depends on BLACKFIN && (BF51x || BF52x || BF54x) - default y - help - If you say Y here, you will get support for a character device - interface into the One Time Programmable memory pages that are - stored on the Blackfin processor. This will not get you access - to the secure memory pages however. You will need to write your - own secure code and reader for that. - - To compile this driver as a module, choose M here: the module - will be called bfin-otp. - - If unsure, it is safe to say Y. - -config BFIN_OTP_WRITE_ENABLE - bool "Enable writing support of OTP pages" - depends on BFIN_OTP - default n - help - If you say Y here, you will enable support for writing of the - OTP pages. This is dangerous by nature as you can only program - the pages once, so only enable this option when you actually - need it so as to not inadvertently clobber data. - - If unsure, say N. - -config PRINTER - tristate "Parallel printer support" - depends on PARPORT - ---help--- - If you intend to attach a printer to the parallel port of your Linux - box (as opposed to using a serial printer; if the connector at the - printer has 9 or 25 holes ["female"], then it's serial), say Y. - Also read the Printing-HOWTO, available from - . - - It is possible to share one parallel port among several devices - (e.g. printer and ZIP drive) and it is safe to compile the - corresponding drivers into the kernel. - - To compile this driver as a module, choose M here and read - . The module will be called lp. - - If you have several parallel ports, you can specify which ports to - use with the "lp" kernel command line option. (Try "man bootparam" - or see the documentation of your boot loader (lilo or loadlin) about - how to pass options to the kernel at boot time.) The syntax of the - "lp" command line option can be found in . - - If you have more than 8 printers, you need to increase the LP_NO - macro in lp.c and the PARPORT_MAX macro in parport.h. - -config LP_CONSOLE - bool "Support for console on line printer" - depends on PRINTER - ---help--- - If you want kernel messages to be printed out as they occur, you - can have a console on the printer. This option adds support for - doing that; to actually get it to happen you need to pass the - option "console=lp0" to the kernel at boot time. - - If the printer is out of paper (or off, or unplugged, or too - busy..) the kernel will stall until the printer is ready again. - By defining CONSOLE_LP_STRICT to 0 (at your own risk) you - can make the kernel continue when this happens, - but it'll lose the kernel messages. - - If unsure, say N. - -config PPDEV - tristate "Support for user-space parallel port device drivers" - depends on PARPORT - ---help--- - Saying Y to this adds support for /dev/parport device nodes. This - is needed for programs that want portable access to the parallel - port, for instance deviceid (which displays Plug-and-Play device - IDs). - - This is the parallel port equivalent of SCSI generic support (sg). - It is safe to say N to this -- it is not needed for normal printing - or parallel port CD-ROM/disk support. - - To compile this driver as a module, choose M here: the - module will be called ppdev. - - If unsure, say N. - -source "drivers/tty/hvc/Kconfig" - -config VIRTIO_CONSOLE - tristate "Virtio console" - depends on VIRTIO && TTY - select HVC_DRIVER - help - Virtio console for use with lguest and other hypervisors. - - Also serves as a general-purpose serial device for data - transfer between the guest and host. Character devices at - /dev/vportNpn will be created when corresponding ports are - found, where N is the device number and n is the port number - within that device. If specified by the host, a sysfs - attribute called 'name' will be populated with a name for - the port which can be used by udev scripts to create a - symlink to the device. - -config IBM_BSR - tristate "IBM POWER Barrier Synchronization Register support" - depends on PPC_PSERIES - help - This devices exposes a hardware mechanism for fast synchronization - of threads across a large system which avoids bouncing a cacheline - between several cores on a system - -config POWERNV_OP_PANEL - tristate "IBM POWERNV Operator Panel Display support" - depends on PPC_POWERNV - default m - help - If you say Y here, a special character device node, /dev/op_panel, - will be created which exposes the operator panel display on IBM - Power Systems machines with FSPs. - - If you don't require access to the operator panel display from user - space, say N. - - If unsure, say M here to build it as a module called powernv-op-panel. - -source "drivers/char/ipmi/Kconfig" - -config DS1620 - tristate "NetWinder thermometer support" - depends on ARCH_NETWINDER - help - Say Y here to include support for the thermal management hardware - found in the NetWinder. This driver allows the user to control the - temperature set points and to read the current temperature. - - It is also possible to say M here to build it as a module (ds1620) - It is recommended to be used on a NetWinder, but it is not a - necessity. - -config NWBUTTON - tristate "NetWinder Button" - depends on ARCH_NETWINDER - ---help--- - If you say Y here and create a character device node /dev/nwbutton - with major and minor numbers 10 and 158 ("man mknod"), then every - time the orange button is pressed a number of times, the number of - times the button was pressed will be written to that device. - - This is most useful for applications, as yet unwritten, which - perform actions based on how many times the button is pressed in a - row. - - Do not hold the button down for too long, as the driver does not - alter the behaviour of the hardware reset circuitry attached to the - button; it will still execute a hard reset if the button is held - down for longer than approximately five seconds. - - To compile this driver as a module, choose M here: the - module will be called nwbutton. - - Most people will answer Y to this question and "Reboot Using Button" - below to be able to initiate a system shutdown from the button. - -config NWBUTTON_REBOOT - bool "Reboot Using Button" - depends on NWBUTTON - help - If you say Y here, then you will be able to initiate a system - shutdown and reboot by pressing the orange button a number of times. - The number of presses to initiate the shutdown is two by default, - but this can be altered by modifying the value of NUM_PRESSES_REBOOT - in nwbutton.h and recompiling the driver or, if you compile the - driver as a module, you can specify the number of presses at load - time with "insmod button reboot_count=". - -config NWFLASH - tristate "NetWinder flash support" - depends on ARCH_NETWINDER - ---help--- - If you say Y here and create a character device /dev/flash with - major 10 and minor 160 you can manipulate the flash ROM containing - the NetWinder firmware. Be careful as accidentally overwriting the - flash contents can render your computer unbootable. On no account - allow random users access to this device. :-) - - To compile this driver as a module, choose M here: the - module will be called nwflash. - - If you're not sure, say N. - -source "drivers/char/hw_random/Kconfig" - -config NVRAM - tristate "/dev/nvram support" - depends on ATARI || X86 || (ARM && RTC_DRV_CMOS) || GENERIC_NVRAM - ---help--- - If you say Y here and create a character special file /dev/nvram - with major number 10 and minor number 144 using mknod ("man mknod"), - you get read and write access to the extra bytes of non-volatile - memory in the real time clock (RTC), which is contained in every PC - and most Ataris. The actual number of bytes varies, depending on the - nvram in the system, but is usually 114 (128-14 for the RTC). - - This memory is conventionally called "CMOS RAM" on PCs and "NVRAM" - on Ataris. /dev/nvram may be used to view settings there, or to - change them (with some utility). It could also be used to frequently - save a few bits of very important data that may not be lost over - power-off and for which writing to disk is too insecure. Note - however that most NVRAM space in a PC belongs to the BIOS and you - should NEVER idly tamper with it. See Ralf Brown's interrupt list - for a guide to the use of CMOS bytes by your BIOS. - - On Atari machines, /dev/nvram is always configured and does not need - to be selected. - - To compile this driver as a module, choose M here: the - module will be called nvram. - -# -# These legacy RTC drivers just cause too many conflicts with the generic -# RTC framework ... let's not even try to coexist any more. -# -if RTC_LIB=n - -config RTC - tristate "Enhanced Real Time Clock Support (legacy PC RTC driver)" - depends on ALPHA || (MIPS && MACH_LOONGSON64) - ---help--- - If you say Y here and create a character special file /dev/rtc with - major number 10 and minor number 135 using mknod ("man mknod"), you - will get access to the real time clock (or hardware clock) built - into your computer. - - Every PC has such a clock built in. It can be used to generate - signals from as low as 1Hz up to 8192Hz, and can also be used - as a 24 hour alarm. It reports status information via the file - /proc/driver/rtc and its behaviour is set by various ioctls on - /dev/rtc. - - If you run Linux on a multiprocessor machine and said Y to - "Symmetric Multi Processing" above, you should say Y here to read - and set the RTC in an SMP compatible fashion. - - If you think you have a use for such a device (such as periodic data - sampling), then say Y here, and read - for details. - - To compile this driver as a module, choose M here: the - module will be called rtc. - -config JS_RTC - tristate "Enhanced Real Time Clock Support" - depends on SPARC32 && PCI - ---help--- - If you say Y here and create a character special file /dev/rtc with - major number 10 and minor number 135 using mknod ("man mknod"), you - will get access to the real time clock (or hardware clock) built - into your computer. - - Every PC has such a clock built in. It can be used to generate - signals from as low as 1Hz up to 8192Hz, and can also be used - as a 24 hour alarm. It reports status information via the file - /proc/driver/rtc and its behaviour is set by various ioctls on - /dev/rtc. - - If you think you have a use for such a device (such as periodic data - sampling), then say Y here, and read - for details. - - To compile this driver as a module, choose M here: the - module will be called js-rtc. - -config EFI_RTC - bool "EFI Real Time Clock Services" - depends on IA64 - -config DS1302 - tristate "DS1302 RTC support" - depends on M32R && (PLAT_M32700UT || PLAT_OPSPUT) - help - If you say Y here and create a character special file /dev/rtc with - major number 121 and minor number 0 using mknod ("man mknod"), you - will get access to the real time clock (or hardware clock) built - into your computer. - -endif # RTC_LIB - -config DTLK - tristate "Double Talk PC internal speech card support" - depends on ISA - help - This driver is for the DoubleTalk PC, a speech synthesizer - manufactured by RC Systems (). It is also - called the `internal DoubleTalk'. - - To compile this driver as a module, choose M here: the - module will be called dtlk. - -config XILINX_HWICAP - tristate "Xilinx HWICAP Support" - depends on XILINX_VIRTEX || MICROBLAZE - help - This option enables support for Xilinx Internal Configuration - Access Port (ICAP) driver. The ICAP is used on Xilinx Virtex - FPGA platforms to partially reconfigure the FPGA at runtime. - - If unsure, say N. - -config R3964 - tristate "Siemens R3964 line discipline" - depends on TTY - ---help--- - This driver allows synchronous communication with devices using the - Siemens R3964 packet protocol. Unless you are dealing with special - hardware like PLCs, you are unlikely to need this. - - To compile this driver as a module, choose M here: the - module will be called n_r3964. - - If unsure, say N. - -config APPLICOM - tristate "Applicom intelligent fieldbus card support" - depends on PCI - ---help--- - This driver provides the kernel-side support for the intelligent - fieldbus cards made by Applicom International. More information - about these cards can be found on the WWW at the address - , or by email from David Woodhouse - . - - To compile this driver as a module, choose M here: the - module will be called applicom. - - If unsure, say N. - -config SONYPI - tristate "Sony Vaio Programmable I/O Control Device support" - depends on X86_32 && PCI && INPUT - ---help--- - This driver enables access to the Sony Programmable I/O Control - Device which can be found in many (all ?) Sony Vaio laptops. - - If you have one of those laptops, read - , and say Y or M here. - - To compile this driver as a module, choose M here: the - module will be called sonypi. - -config GPIO_TB0219 - tristate "TANBAC TB0219 GPIO support" - depends on TANBAC_TB022X - select GPIO_VR41XX - -source "drivers/char/pcmcia/Kconfig" - -config MWAVE - tristate "ACP Modem (Mwave) support" - depends on X86 && TTY - select SERIAL_8250 - ---help--- - The ACP modem (Mwave) for Linux is a WinModem. It is composed of a - kernel driver and a user level application. Together these components - support direct attachment to public switched telephone networks (PSTNs) - and support selected world wide countries. - - This version of the ACP Modem driver supports the IBM Thinkpad 600E, - 600, and 770 that include on board ACP modem hardware. - - The modem also supports the standard communications port interface - (ttySx) and is compatible with the Hayes AT Command Set. - - The user level application needed to use this driver can be found at - the IBM Linux Technology Center (LTC) web site: - . - - If you own one of the above IBM Thinkpads which has the Mwave chipset - in it, say Y. - - To compile this driver as a module, choose M here: the - module will be called mwave. - -config SCx200_GPIO - tristate "NatSemi SCx200 GPIO Support" - depends on SCx200 - select NSC_GPIO - help - Give userspace access to the GPIO pins on the National - Semiconductor SCx200 processors. - - If compiled as a module, it will be called scx200_gpio. - -config PC8736x_GPIO - tristate "NatSemi PC8736x GPIO Support" - depends on X86_32 && !UML - default SCx200_GPIO # mostly N - select NSC_GPIO # needed for support routines - help - Give userspace access to the GPIO pins on the National - Semiconductor PC-8736x (x=[03456]) SuperIO chip. The chip - has multiple functional units, inc several managed by - hwmon/pc87360 driver. Tested with PC-87366 - - If compiled as a module, it will be called pc8736x_gpio. - -config NSC_GPIO - tristate "NatSemi Base GPIO Support" - depends on X86_32 - # selected by SCx200_GPIO and PC8736x_GPIO - # what about 2 selectors differing: m != y - help - Common support used (and needed) by scx200_gpio and - pc8736x_gpio drivers. If those drivers are built as - modules, this one will be too, named nsc_gpio - -config RAW_DRIVER - tristate "RAW driver (/dev/raw/rawN)" - depends on BLOCK - help - The raw driver permits block devices to be bound to /dev/raw/rawN. - Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. - See the raw(8) manpage for more details. - - Applications should preferably open the device (eg /dev/hda1) - with the O_DIRECT flag. - -config MAX_RAW_DEVS - int "Maximum number of RAW devices to support (1-65536)" - depends on RAW_DRIVER - range 1 65536 - default "256" - help - The maximum number of RAW devices that are supported. - Default is 256. Increase this number in case you need lots of - raw devices. - -config HPET - bool "HPET - High Precision Event Timer" if (X86 || IA64) - default n - depends on ACPI - help - If you say Y here, you will have a miscdevice named "/dev/hpet/". Each - open selects one of the timers supported by the HPET. The timers are - non-periodic and/or periodic. - -config HPET_MMAP - bool "Allow mmap of HPET" - default y - depends on HPET - help - If you say Y here, user applications will be able to mmap - the HPET registers. - -config HPET_MMAP_DEFAULT - bool "Enable HPET MMAP access by default" - default y - depends on HPET_MMAP - help - In some hardware implementations, the page containing HPET - registers may also contain other things that shouldn't be - exposed to the user. This option selects the default (if - kernel parameter hpet_mmap is not set) user access to the - registers for applications that require it. - -config HANGCHECK_TIMER - tristate "Hangcheck timer" - depends on X86 || IA64 || PPC64 || S390 - help - The hangcheck-timer module detects when the system has gone - out to lunch past a certain margin. It can reboot the system - or merely print a warning. - -config MMTIMER - tristate "MMTIMER Memory mapped RTC for SGI Altix" - depends on IA64_GENERIC || IA64_SGI_SN2 - default y - help - The mmtimer device allows direct userspace access to the - Altix system timer. - -config UV_MMTIMER - tristate "UV_MMTIMER Memory mapped RTC for SGI UV" - depends on X86_UV - default m - help - The uv_mmtimer device allows direct userspace access to the - UV system timer. - -source "drivers/char/tpm/Kconfig" - -config TELCLOCK - tristate "Telecom clock driver for ATCA SBC" - depends on X86 - default n - help - The telecom clock device is specific to the MPCBL0010 and MPCBL0050 - ATCA computers and allows direct userspace access to the - configuration of the telecom clock configuration settings. This - device is used for hardware synchronization across the ATCA backplane - fabric. Upon loading, the driver exports a sysfs directory, - /sys/devices/platform/telco_clock, with a number of files for - controlling the behavior of this hardware. - -config DEVPORT - bool - depends on ISA || PCI - default y - -source "drivers/s390/char/Kconfig" - -config TILE_SROM - bool "Character-device access via hypervisor to the Tilera SPI ROM" - depends on TILE - default y - ---help--- - This device provides character-level read-write access - to the SROM, typically via the "0", "1", and "2" devices - in /dev/srom/. The Tilera hypervisor makes the flash - device appear much like a simple EEPROM, and knows - how to partition a single ROM for multiple purposes. - -source "drivers/char/xillybus/Kconfig" - -endmenu - diff --git a/src/linux/drivers/char/Makefile b/src/linux/drivers/char/Makefile deleted file mode 100644 index 6e6c244..0000000 --- a/src/linux/drivers/char/Makefile +++ /dev/null @@ -1,62 +0,0 @@ -# -# Makefile for the kernel character device drivers. -# - -obj-y += mem.o random.o -obj-$(CONFIG_TTY_PRINTK) += ttyprintk.o -obj-y += misc.o -obj-$(CONFIG_ATARI_DSP56K) += dsp56k.o -obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o -obj-$(CONFIG_RAW_DRIVER) += raw.o -obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o -obj-$(CONFIG_MSPEC) += mspec.o -obj-$(CONFIG_MMTIMER) += mmtimer.o -obj-$(CONFIG_UV_MMTIMER) += uv_mmtimer.o -obj-$(CONFIG_IBM_BSR) += bsr.o -obj-$(CONFIG_SGI_MBCS) += mbcs.o -obj-$(CONFIG_BFIN_OTP) += bfin-otp.o - -obj-$(CONFIG_PRINTER) += lp.o - -obj-$(CONFIG_APM_EMULATION) += apm-emulation.o - -obj-$(CONFIG_DTLK) += dtlk.o -obj-$(CONFIG_APPLICOM) += applicom.o -obj-$(CONFIG_SONYPI) += sonypi.o -obj-$(CONFIG_RTC) += rtc.o -obj-$(CONFIG_HPET) += hpet.o -obj-$(CONFIG_EFI_RTC) += efirtc.o -obj-$(CONFIG_DS1302) += ds1302.o -obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap/ -ifeq ($(CONFIG_GENERIC_NVRAM),y) - obj-$(CONFIG_NVRAM) += generic_nvram.o -else - obj-$(CONFIG_NVRAM) += nvram.o -endif -obj-$(CONFIG_TOSHIBA) += toshiba.o -obj-$(CONFIG_DS1620) += ds1620.o -obj-$(CONFIG_HW_RANDOM) += hw_random/ -obj-$(CONFIG_PPDEV) += ppdev.o -obj-$(CONFIG_NWBUTTON) += nwbutton.o -obj-$(CONFIG_NWFLASH) += nwflash.o -obj-$(CONFIG_SCx200_GPIO) += scx200_gpio.o -obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o -obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o -obj-$(CONFIG_GPIO_TB0219) += tb0219.o -obj-$(CONFIG_TELCLOCK) += tlclk.o - -obj-$(CONFIG_MWAVE) += mwave/ -obj-y += agp/ -obj-$(CONFIG_PCMCIA) += pcmcia/ - -obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o -obj-$(CONFIG_TCG_TPM) += tpm/ - -obj-$(CONFIG_PS3_FLASH) += ps3flash.o - -obj-$(CONFIG_JS_RTC) += js-rtc.o -js-rtc-y = rtc.o - -obj-$(CONFIG_TILE_SROM) += tile-srom.o -obj-$(CONFIG_XILLYBUS) += xillybus/ -obj-$(CONFIG_POWERNV_OP_PANEL) += powernv-op-panel.o diff --git a/src/linux/drivers/char/agp/Kconfig b/src/linux/drivers/char/agp/Kconfig deleted file mode 100644 index c528f96..0000000 --- a/src/linux/drivers/char/agp/Kconfig +++ /dev/null @@ -1,162 +0,0 @@ -menuconfig AGP - tristate "/dev/agpgart (AGP Support)" - depends on ALPHA || IA64 || PARISC || PPC || X86 - depends on PCI - ---help--- - AGP (Accelerated Graphics Port) is a bus system mainly used to - connect graphics cards to the rest of the system. - - If you have an AGP system and you say Y here, it will be possible to - use the AGP features of your 3D rendering video card. This code acts - as a sort of "AGP driver" for the motherboard's chipset. - - If you need more texture memory than you can get with the AGP GART - (theoretically up to 256 MB, but in practice usually 64 or 128 MB - due to kernel allocation issues), you could use PCI accesses - and have up to a couple gigs of texture space. - - Note that this is the only means to have X/GLX use - write-combining with MTRR support on the AGP bus. Without it, OpenGL - direct rendering will be a lot slower but still faster than PIO. - - To compile this driver as a module, choose M here: the - module will be called agpgart. - - You should say Y here if you want to use GLX or DRI. - - If unsure, say N. - -config AGP_ALI - tristate "ALI chipset support" - depends on AGP && X86_32 - ---help--- - This option gives you AGP support for the GLX component of - X on the following ALi chipsets. The supported chipsets - include M1541, M1621, M1631, M1632, M1641,M1647,and M1651. - For the ALi-chipset question, ALi suggests you refer to - . - - The M1541 chipset can do AGP 1x and 2x, but note that there is an - acknowledged incompatibility with Matrox G200 cards. Due to - timing issues, this chipset cannot do AGP 2x with the G200. - This is a hardware limitation. AGP 1x seems to be fine, though. - -config AGP_ATI - tristate "ATI chipset support" - depends on AGP && X86_32 - ---help--- - This option gives you AGP support for the GLX component of - X on the ATI RadeonIGP family of chipsets. - -config AGP_AMD - tristate "AMD Irongate, 761, and 762 chipset support" - depends on AGP && X86_32 - help - This option gives you AGP support for the GLX component of - X on AMD Irongate, 761, and 762 chipsets. - -config AGP_AMD64 - tristate "AMD Opteron/Athlon64 on-CPU GART support" - depends on AGP && X86 && AMD_NB - help - This option gives you AGP support for the GLX component of - X using the on-CPU northbridge of the AMD Athlon64/Opteron CPUs. - You still need an external AGP bridge like the AMD 8151, VIA - K8T400M, SiS755. It may also support other AGP bridges when loaded - with agp_try_unsupported=1. - -config AGP_INTEL - tristate "Intel 440LX/BX/GX, I8xx and E7x05 chipset support" - depends on AGP && X86 - select INTEL_GTT - help - This option gives you AGP support for the GLX component of X - on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850, 860, 875, - E7205 and E7505 chipsets and full support for the 810, 815, 830M, - 845G, 852GM, 855GM, 865G and I915 integrated graphics chipsets. - - - -config AGP_NVIDIA - tristate "NVIDIA nForce/nForce2 chipset support" - depends on AGP && X86_32 - help - This option gives you AGP support for the GLX component of - X on NVIDIA chipsets including nForce and nForce2 - -config AGP_SIS - tristate "SiS chipset support" - depends on AGP && X86 - help - This option gives you AGP support for the GLX component of - X on Silicon Integrated Systems [SiS] chipsets. - - Note that 5591/5592 AGP chipsets are NOT supported. - - -config AGP_SWORKS - tristate "Serverworks LE/HE chipset support" - depends on AGP && X86_32 - help - Say Y here to support the Serverworks AGP card. See - for product descriptions and images. - -config AGP_VIA - tristate "VIA chipset support" - depends on AGP && X86 - help - This option gives you AGP support for the GLX component of - X on VIA MVP3/Apollo Pro chipsets. - -config AGP_I460 - tristate "Intel 460GX chipset support" - depends on AGP && (IA64_DIG || IA64_GENERIC) - help - This option gives you AGP GART support for the Intel 460GX chipset - for IA64 processors. - -config AGP_HP_ZX1 - tristate "HP ZX1 chipset AGP support" - depends on AGP && (IA64_HP_ZX1 || IA64_HP_ZX1_SWIOTLB || IA64_GENERIC) - help - This option gives you AGP GART support for the HP ZX1 chipset - for IA64 processors. - -config AGP_PARISC - tristate "HP Quicksilver AGP support" - depends on AGP && PARISC && 64BIT - help - This option gives you AGP GART support for the HP Quicksilver - AGP bus adapter on HP PA-RISC machines (Ok, just on the C8000 - workstation...) - -config AGP_ALPHA_CORE - tristate "Alpha AGP support" - depends on AGP && (ALPHA_GENERIC || ALPHA_TITAN || ALPHA_MARVEL) - default AGP - -config AGP_UNINORTH - tristate "Apple UniNorth & U3 AGP support" - depends on AGP && PPC_PMAC - help - This option gives you AGP support for Apple machines with a - UniNorth or U3 (Apple G5) bridge. - -config AGP_EFFICEON - tristate "Transmeta Efficeon support" - depends on AGP && X86_32 - help - This option gives you AGP support for the Transmeta Efficeon - series processors with integrated northbridges. - -config AGP_SGI_TIOCA - tristate "SGI TIO chipset AGP support" - depends on AGP && (IA64_SGI_SN2 || IA64_GENERIC) - help - This option gives you AGP GART support for the SGI TIO chipset - for IA64 processors. - -config INTEL_GTT - tristate - depends on X86 && PCI - diff --git a/src/linux/drivers/char/agp/Makefile b/src/linux/drivers/char/agp/Makefile deleted file mode 100644 index 604489b..0000000 --- a/src/linux/drivers/char/agp/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -agpgart-y := backend.o frontend.o generic.o isoch.o - -agpgart-$(CONFIG_COMPAT) += compat_ioctl.o - -obj-$(CONFIG_AGP) += agpgart.o -obj-$(CONFIG_AGP_ALI) += ali-agp.o -obj-$(CONFIG_AGP_ATI) += ati-agp.o -obj-$(CONFIG_AGP_AMD) += amd-k7-agp.o -obj-$(CONFIG_AGP_AMD64) += amd64-agp.o -obj-$(CONFIG_AGP_ALPHA_CORE) += alpha-agp.o -obj-$(CONFIG_AGP_EFFICEON) += efficeon-agp.o -obj-$(CONFIG_AGP_HP_ZX1) += hp-agp.o -obj-$(CONFIG_AGP_PARISC) += parisc-agp.o -obj-$(CONFIG_AGP_I460) += i460-agp.o -obj-$(CONFIG_AGP_INTEL) += intel-agp.o -obj-$(CONFIG_INTEL_GTT) += intel-gtt.o -obj-$(CONFIG_AGP_NVIDIA) += nvidia-agp.o -obj-$(CONFIG_AGP_SGI_TIOCA) += sgi-agp.o -obj-$(CONFIG_AGP_SIS) += sis-agp.o -obj-$(CONFIG_AGP_SWORKS) += sworks-agp.o -obj-$(CONFIG_AGP_UNINORTH) += uninorth-agp.o -obj-$(CONFIG_AGP_VIA) += via-agp.o diff --git a/src/linux/drivers/char/hw_random/Kconfig b/src/linux/drivers/char/hw_random/Kconfig deleted file mode 100644 index 200dab5..0000000 --- a/src/linux/drivers/char/hw_random/Kconfig +++ /dev/null @@ -1,441 +0,0 @@ -# -# Hardware Random Number Generator (RNG) configuration -# - -menuconfig HW_RANDOM - tristate "Hardware Random Number Generator Core support" - default m - ---help--- - Hardware Random Number Generator Core infrastructure. - - To compile this driver as a module, choose M here: the - module will be called rng-core. This provides a device - that's usually called /dev/hwrng, and which exposes one - of possibly several hardware random number generators. - - These hardware random number generators do not feed directly - into the kernel's random number generator. That is usually - handled by the "rngd" daemon. Documentation/hw_random.txt - has more information. - - If unsure, say Y. - -if HW_RANDOM - -config HW_RANDOM_TIMERIOMEM - tristate "Timer IOMEM HW Random Number Generator support" - depends on HAS_IOMEM - ---help--- - This driver provides kernel-side support for a generic Random - Number Generator used by reading a 'dumb' iomem address that - is to be read no faster than, for example, once a second; - the default FPGA bitstream on the TS-7800 has such functionality. - - To compile this driver as a module, choose M here: the - module will be called timeriomem-rng. - - If unsure, say Y. - -config HW_RANDOM_INTEL - tristate "Intel HW Random Number Generator support" - depends on (X86 || IA64) && PCI - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on Intel i8xx-based motherboards. - - To compile this driver as a module, choose M here: the - module will be called intel-rng. - - If unsure, say Y. - -config HW_RANDOM_AMD - tristate "AMD HW Random Number Generator support" - depends on (X86 || PPC_MAPLE) && PCI - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on AMD 76x-based motherboards. - - To compile this driver as a module, choose M here: the - module will be called amd-rng. - - If unsure, say Y. - -config HW_RANDOM_ATMEL - tristate "Atmel Random Number Generator support" - depends on ARCH_AT91 && HAVE_CLK && OF - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on Atmel AT91 devices. - - To compile this driver as a module, choose M here: the - module will be called atmel-rng. - - If unsure, say Y. - -config HW_RANDOM_BCM63XX - tristate "Broadcom BCM63xx Random Number Generator support" - depends on BCM63XX || BMIPS_GENERIC - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on the Broadcom BCM63xx SoCs. - - To compile this driver as a module, choose M here: the - module will be called bcm63xx-rng - - If unusure, say Y. - -config HW_RANDOM_BCM2835 - tristate "Broadcom BCM2835 Random Number Generator support" - depends on ARCH_BCM2835 || ARCH_BCM_NSP || ARCH_BCM_5301X - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on the Broadcom BCM2835 SoCs. - - To compile this driver as a module, choose M here: the - module will be called bcm2835-rng - - If unsure, say Y. - -config HW_RANDOM_IPROC_RNG200 - tristate "Broadcom iProc RNG200 support" - depends on ARCH_BCM_IPROC - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the RNG200 - hardware found on the Broadcom iProc SoCs. - - To compile this driver as a module, choose M here: the - module will be called iproc-rng200 - - If unsure, say Y. - -config HW_RANDOM_GEODE - tristate "AMD Geode HW Random Number Generator support" - depends on X86_32 && PCI - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on the AMD Geode LX. - - To compile this driver as a module, choose M here: the - module will be called geode-rng. - - If unsure, say Y. - -config HW_RANDOM_N2RNG - tristate "Niagara2 Random Number Generator support" - depends on SPARC64 - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on Niagara2 cpus. - - To compile this driver as a module, choose M here: the - module will be called n2-rng. - - If unsure, say Y. - -config HW_RANDOM_VIA - tristate "VIA HW Random Number Generator support" - depends on X86 - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on VIA based motherboards. - - To compile this driver as a module, choose M here: the - module will be called via-rng. - - If unsure, say Y. - -config HW_RANDOM_IXP4XX - tristate "Intel IXP4xx NPU HW Pseudo-Random Number Generator support" - depends on ARCH_IXP4XX - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Pseudo-Random - Number Generator hardware found on the Intel IXP45x/46x NPU. - - To compile this driver as a module, choose M here: the - module will be called ixp4xx-rng. - - If unsure, say Y. - -config HW_RANDOM_OMAP - tristate "OMAP Random Number Generator support" - depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on OMAP16xx, OMAP2/3/4/5 and AM33xx/AM43xx - multimedia processors. - - To compile this driver as a module, choose M here: the - module will be called omap-rng. - - If unsure, say Y. - -config HW_RANDOM_OMAP3_ROM - tristate "OMAP3 ROM Random Number Generator support" - depends on ARCH_OMAP3 - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on OMAP34xx processors. - - To compile this driver as a module, choose M here: the - module will be called omap3-rom-rng. - - If unsure, say Y. - -config HW_RANDOM_OCTEON - tristate "Octeon Random Number Generator support" - depends on CAVIUM_OCTEON_SOC - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on Octeon processors. - - To compile this driver as a module, choose M here: the - module will be called octeon-rng. - - If unsure, say Y. - -config HW_RANDOM_PASEMI - tristate "PA Semi HW Random Number Generator support" - depends on PPC_PASEMI - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on PA Semi PWRficient SoCs. - - To compile this driver as a module, choose M here: the - module will be called pasemi-rng. - - If unsure, say Y. - -config HW_RANDOM_VIRTIO - tristate "VirtIO Random Number Generator support" - depends on VIRTIO - ---help--- - This driver provides kernel-side support for the virtual Random Number - Generator hardware. - - To compile this driver as a module, choose M here: the - module will be called virtio-rng. If unsure, say N. - -config HW_RANDOM_TX4939 - tristate "TX4939 Random Number Generator support" - depends on SOC_TX4939 - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on TX4939 SoC. - - To compile this driver as a module, choose M here: the - module will be called tx4939-rng. - - If unsure, say Y. - -config HW_RANDOM_MXC_RNGA - tristate "Freescale i.MX RNGA Random Number Generator" - depends on SOC_IMX31 - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on Freescale i.MX processors. - - To compile this driver as a module, choose M here: the - module will be called mxc-rnga. - - If unsure, say Y. - -config HW_RANDOM_NOMADIK - tristate "ST-Ericsson Nomadik Random Number Generator support" - depends on ARCH_NOMADIK - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on ST-Ericsson SoCs (8815 and 8500). - - To compile this driver as a module, choose M here: the - module will be called nomadik-rng. - - If unsure, say Y. - -config HW_RANDOM_PSERIES - tristate "pSeries HW Random Number Generator support" - depends on PPC64 && IBMVIO - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on POWER7+ machines and above - - To compile this driver as a module, choose M here: the - module will be called pseries-rng. - - If unsure, say Y. - -config HW_RANDOM_POWERNV - tristate "PowerNV Random Number Generator support" - depends on PPC_POWERNV - default HW_RANDOM - ---help--- - This is the driver for Random Number Generator hardware found - in POWER7+ and above machines for PowerNV platform. - - To compile this driver as a module, choose M here: the - module will be called powernv-rng. - - If unsure, say Y. - -config HW_RANDOM_EXYNOS - tristate "EXYNOS HW random number generator support" - depends on ARCH_EXYNOS || COMPILE_TEST - depends on HAS_IOMEM - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on EXYNOS SOCs. - - To compile this driver as a module, choose M here: the - module will be called exynos-rng. - - If unsure, say Y. - -config HW_RANDOM_TPM - tristate "TPM HW Random Number Generator support" - depends on TCG_TPM - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator in the Trusted Platform Module - - To compile this driver as a module, choose M here: the - module will be called tpm-rng. - - If unsure, say Y. - -config HW_RANDOM_HISI - tristate "Hisilicon Random Number Generator support" - depends on HW_RANDOM && ARCH_HISI - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on Hisilicon Hip04 and Hip05 SoC. - - To compile this driver as a module, choose M here: the - module will be called hisi-rng. - - If unsure, say Y. - -config HW_RANDOM_MSM - tristate "Qualcomm SoCs Random Number Generator support" - depends on HW_RANDOM && ARCH_QCOM - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on Qualcomm SoCs. - - To compile this driver as a module, choose M here. the - module will be called msm-rng. - - If unsure, say Y. - -config HW_RANDOM_ST - tristate "ST Microelectronics HW Random Number Generator support" - depends on HW_RANDOM && ARCH_STI - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on STi series of SoCs. - - To compile this driver as a module, choose M here: the - module will be called st-rng. - -config HW_RANDOM_XGENE - tristate "APM X-Gene True Random Number Generator (TRNG) support" - depends on HW_RANDOM && ARCH_XGENE - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on APM X-Gene SoC. - - To compile this driver as a module, choose M here: the - module will be called xgene_rng. - - If unsure, say Y. - -config HW_RANDOM_STM32 - tristate "STMicroelectronics STM32 random number generator" - depends on HW_RANDOM && (ARCH_STM32 || COMPILE_TEST) - depends on HAS_IOMEM - help - This driver provides kernel-side support for the Random Number - Generator hardware found on STM32 microcontrollers. - - To compile this driver as a module, choose M here: the - module will be called stm32-rng. - - If unsure, say N. - -config HW_RANDOM_PIC32 - tristate "Microchip PIC32 Random Number Generator support" - depends on HW_RANDOM && MACH_PIC32 - default y - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on a PIC32. - - To compile this driver as a module, choose M here. the - module will be called pic32-rng. - - If unsure, say Y. - -config HW_RANDOM_MESON - tristate "Amlogic Meson Random Number Generator support" - depends on HW_RANDOM - depends on ARCH_MESON || COMPILE_TEST - default y - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on Amlogic Meson SoCs. - - To compile this driver as a module, choose M here. the - module will be called meson-rng. - - If unsure, say Y. - -config HW_RANDOM_CAVIUM - tristate "Cavium ThunderX Random Number Generator support" - depends on HW_RANDOM && PCI && (ARM64 || (COMPILE_TEST && 64BIT)) - default HW_RANDOM - ---help--- - This driver provides kernel-side support for the Random Number - Generator hardware found on Cavium SoCs. - - To compile this driver as a module, choose M here: the - module will be called cavium_rng. - - If unsure, say Y. - -endif # HW_RANDOM - -config UML_RANDOM - depends on UML - tristate "Hardware random number generator" - help - This option enables UML's "hardware" random number generator. It - attaches itself to the host's /dev/random, supplying as much entropy - as the host has, rather than the small amount the UML gets from its - own drivers. It registers itself as a standard hardware random number - generator, major 10, minor 183, and the canonical device name is - /dev/hwrng. - The way to make use of this is to install the rng-tools package - (check your distro, or download from - http://sourceforge.net/projects/gkernel/). rngd periodically reads - /dev/hwrng and injects the entropy into /dev/random. diff --git a/src/linux/drivers/char/hw_random/Makefile b/src/linux/drivers/char/hw_random/Makefile deleted file mode 100644 index 5f52b1e..0000000 --- a/src/linux/drivers/char/hw_random/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -# -# Makefile for HW Random Number Generator (RNG) device drivers. -# - -obj-$(CONFIG_HW_RANDOM) += rng-core.o -rng-core-y := core.o -obj-$(CONFIG_HW_RANDOM_TIMERIOMEM) += timeriomem-rng.o -obj-$(CONFIG_HW_RANDOM_INTEL) += intel-rng.o -obj-$(CONFIG_HW_RANDOM_AMD) += amd-rng.o -obj-$(CONFIG_HW_RANDOM_ATMEL) += atmel-rng.o -obj-$(CONFIG_HW_RANDOM_BCM63XX) += bcm63xx-rng.o -obj-$(CONFIG_HW_RANDOM_GEODE) += geode-rng.o -obj-$(CONFIG_HW_RANDOM_N2RNG) += n2-rng.o -n2-rng-y := n2-drv.o n2-asm.o -obj-$(CONFIG_HW_RANDOM_VIA) += via-rng.o -obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o -obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o -obj-$(CONFIG_HW_RANDOM_OMAP3_ROM) += omap3-rom-rng.o -obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o -obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o -obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o -obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o -obj-$(CONFIG_HW_RANDOM_OCTEON) += octeon-rng.o -obj-$(CONFIG_HW_RANDOM_NOMADIK) += nomadik-rng.o -obj-$(CONFIG_HW_RANDOM_PSERIES) += pseries-rng.o -obj-$(CONFIG_HW_RANDOM_POWERNV) += powernv-rng.o -obj-$(CONFIG_HW_RANDOM_EXYNOS) += exynos-rng.o -obj-$(CONFIG_HW_RANDOM_HISI) += hisi-rng.o -obj-$(CONFIG_HW_RANDOM_TPM) += tpm-rng.o -obj-$(CONFIG_HW_RANDOM_BCM2835) += bcm2835-rng.o -obj-$(CONFIG_HW_RANDOM_IPROC_RNG200) += iproc-rng200.o -obj-$(CONFIG_HW_RANDOM_MSM) += msm-rng.o -obj-$(CONFIG_HW_RANDOM_ST) += st-rng.o -obj-$(CONFIG_HW_RANDOM_XGENE) += xgene-rng.o -obj-$(CONFIG_HW_RANDOM_STM32) += stm32-rng.o -obj-$(CONFIG_HW_RANDOM_PIC32) += pic32-rng.o -obj-$(CONFIG_HW_RANDOM_MESON) += meson-rng.o -obj-$(CONFIG_HW_RANDOM_CAVIUM) += cavium-rng.o cavium-rng-vf.o diff --git a/src/linux/drivers/char/hw_random/core.c b/src/linux/drivers/char/hw_random/core.c deleted file mode 100644 index d2d2c89..0000000 --- a/src/linux/drivers/char/hw_random/core.c +++ /dev/null @@ -1,597 +0,0 @@ -/* - Added support for the AMD Geode LX RNG - (c) Copyright 2004-2005 Advanced Micro Devices, Inc. - - derived from - - Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG) - (c) Copyright 2003 Red Hat Inc - - derived from - - Hardware driver for the AMD 768 Random Number Generator (RNG) - (c) Copyright 2001 Red Hat Inc - - derived from - - Hardware driver for Intel i810 Random Number Generator (RNG) - Copyright 2000,2001 Jeff Garzik - Copyright 2000,2001 Philipp Rumpf - - Added generic RNG API - Copyright 2006 Michael Buesch - Copyright 2005 (c) MontaVista Software, Inc. - - Please read Documentation/hw_random.txt for details on use. - - ---------------------------------------------------------- - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - - */ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#define RNG_MODULE_NAME "hw_random" -#define PFX RNG_MODULE_NAME ": " -#define RNG_MISCDEV_MINOR 183 /* official */ - - -static struct hwrng *current_rng; -static struct task_struct *hwrng_fill; -static LIST_HEAD(rng_list); -/* Protects rng_list and current_rng */ -static DEFINE_MUTEX(rng_mutex); -/* Protects rng read functions, data_avail, rng_buffer and rng_fillbuf */ -static DEFINE_MUTEX(reading_mutex); -static int data_avail; -static u8 *rng_buffer, *rng_fillbuf; -static unsigned short current_quality; -static unsigned short default_quality; /* = 0; default to "off" */ - -module_param(current_quality, ushort, 0644); -MODULE_PARM_DESC(current_quality, - "current hwrng entropy estimation per mill"); -module_param(default_quality, ushort, 0644); -MODULE_PARM_DESC(default_quality, - "default entropy content of hwrng per mill"); - -static void drop_current_rng(void); -static int hwrng_init(struct hwrng *rng); -static void start_khwrngd(void); - -static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, - int wait); - -static size_t rng_buffer_size(void) -{ - return SMP_CACHE_BYTES < 32 ? 32 : SMP_CACHE_BYTES; -} - -static void add_early_randomness(struct hwrng *rng) -{ - int bytes_read; - size_t size = min_t(size_t, 16, rng_buffer_size()); - - mutex_lock(&reading_mutex); - bytes_read = rng_get_data(rng, rng_buffer, size, 1); - mutex_unlock(&reading_mutex); - if (bytes_read > 0) - add_device_randomness(rng_buffer, bytes_read); -} - -static inline void cleanup_rng(struct kref *kref) -{ - struct hwrng *rng = container_of(kref, struct hwrng, ref); - - if (rng->cleanup) - rng->cleanup(rng); - - complete(&rng->cleanup_done); -} - -static int set_current_rng(struct hwrng *rng) -{ - int err; - - BUG_ON(!mutex_is_locked(&rng_mutex)); - - err = hwrng_init(rng); - if (err) - return err; - - drop_current_rng(); - current_rng = rng; - - return 0; -} - -static void drop_current_rng(void) -{ - BUG_ON(!mutex_is_locked(&rng_mutex)); - if (!current_rng) - return; - - /* decrease last reference for triggering the cleanup */ - kref_put(¤t_rng->ref, cleanup_rng); - current_rng = NULL; -} - -/* Returns ERR_PTR(), NULL or refcounted hwrng */ -static struct hwrng *get_current_rng(void) -{ - struct hwrng *rng; - - if (mutex_lock_interruptible(&rng_mutex)) - return ERR_PTR(-ERESTARTSYS); - - rng = current_rng; - if (rng) - kref_get(&rng->ref); - - mutex_unlock(&rng_mutex); - return rng; -} - -static void put_rng(struct hwrng *rng) -{ - /* - * Hold rng_mutex here so we serialize in case they set_current_rng - * on rng again immediately. - */ - mutex_lock(&rng_mutex); - if (rng) - kref_put(&rng->ref, cleanup_rng); - mutex_unlock(&rng_mutex); -} - -static int hwrng_init(struct hwrng *rng) -{ - if (kref_get_unless_zero(&rng->ref)) - goto skip_init; - - if (rng->init) { - int ret; - - ret = rng->init(rng); - if (ret) - return ret; - } - - kref_init(&rng->ref); - reinit_completion(&rng->cleanup_done); - -skip_init: - add_early_randomness(rng); - - current_quality = rng->quality ? : default_quality; - if (current_quality > 1024) - current_quality = 1024; - - if (current_quality == 0 && hwrng_fill) - kthread_stop(hwrng_fill); - if (current_quality > 0 && !hwrng_fill) - start_khwrngd(); - - return 0; -} - -static int rng_dev_open(struct inode *inode, struct file *filp) -{ - /* enforce read-only access to this chrdev */ - if ((filp->f_mode & FMODE_READ) == 0) - return -EINVAL; - if (filp->f_mode & FMODE_WRITE) - return -EINVAL; - return 0; -} - -static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size, - int wait) { - int present; - - BUG_ON(!mutex_is_locked(&reading_mutex)); - if (rng->read) - return rng->read(rng, (void *)buffer, size, wait); - - if (rng->data_present) - present = rng->data_present(rng, wait); - else - present = 1; - - if (present) - return rng->data_read(rng, (u32 *)buffer); - - return 0; -} - -static ssize_t rng_dev_read(struct file *filp, char __user *buf, - size_t size, loff_t *offp) -{ - ssize_t ret = 0; - int err = 0; - int bytes_read, len; - struct hwrng *rng; - - while (size) { - rng = get_current_rng(); - if (IS_ERR(rng)) { - err = PTR_ERR(rng); - goto out; - } - if (!rng) { - err = -ENODEV; - goto out; - } - - if (mutex_lock_interruptible(&reading_mutex)) { - err = -ERESTARTSYS; - goto out_put; - } - if (!data_avail) { - bytes_read = rng_get_data(rng, rng_buffer, - rng_buffer_size(), - !(filp->f_flags & O_NONBLOCK)); - if (bytes_read < 0) { - err = bytes_read; - goto out_unlock_reading; - } - data_avail = bytes_read; - } - - if (!data_avail) { - if (filp->f_flags & O_NONBLOCK) { - err = -EAGAIN; - goto out_unlock_reading; - } - } else { - len = data_avail; - if (len > size) - len = size; - - data_avail -= len; - - if (copy_to_user(buf + ret, rng_buffer + data_avail, - len)) { - err = -EFAULT; - goto out_unlock_reading; - } - - size -= len; - ret += len; - } - - mutex_unlock(&reading_mutex); - put_rng(rng); - - if (need_resched()) - schedule_timeout_interruptible(1); - - if (signal_pending(current)) { - err = -ERESTARTSYS; - goto out; - } - } -out: - return ret ? : err; - -out_unlock_reading: - mutex_unlock(&reading_mutex); -out_put: - put_rng(rng); - goto out; -} - - -static const struct file_operations rng_chrdev_ops = { - .owner = THIS_MODULE, - .open = rng_dev_open, - .read = rng_dev_read, - .llseek = noop_llseek, -}; - -static const struct attribute_group *rng_dev_groups[]; - -static struct miscdevice rng_miscdev = { - .minor = RNG_MISCDEV_MINOR, - .name = RNG_MODULE_NAME, - .nodename = "hwrng", - .fops = &rng_chrdev_ops, - .groups = rng_dev_groups, -}; - - -static ssize_t hwrng_attr_current_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - int err; - struct hwrng *rng; - - err = mutex_lock_interruptible(&rng_mutex); - if (err) - return -ERESTARTSYS; - err = -ENODEV; - list_for_each_entry(rng, &rng_list, list) { - if (sysfs_streq(rng->name, buf)) { - err = 0; - if (rng != current_rng) - err = set_current_rng(rng); - break; - } - } - mutex_unlock(&rng_mutex); - - return err ? : len; -} - -static ssize_t hwrng_attr_current_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - ssize_t ret; - struct hwrng *rng; - - rng = get_current_rng(); - if (IS_ERR(rng)) - return PTR_ERR(rng); - - ret = snprintf(buf, PAGE_SIZE, "%s\n", rng ? rng->name : "none"); - put_rng(rng); - - return ret; -} - -static ssize_t hwrng_attr_available_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - int err; - struct hwrng *rng; - - err = mutex_lock_interruptible(&rng_mutex); - if (err) - return -ERESTARTSYS; - buf[0] = '\0'; - list_for_each_entry(rng, &rng_list, list) { - strlcat(buf, rng->name, PAGE_SIZE); - strlcat(buf, " ", PAGE_SIZE); - } - strlcat(buf, "\n", PAGE_SIZE); - mutex_unlock(&rng_mutex); - - return strlen(buf); -} - -static DEVICE_ATTR(rng_current, S_IRUGO | S_IWUSR, - hwrng_attr_current_show, - hwrng_attr_current_store); -static DEVICE_ATTR(rng_available, S_IRUGO, - hwrng_attr_available_show, - NULL); - -static struct attribute *rng_dev_attrs[] = { - &dev_attr_rng_current.attr, - &dev_attr_rng_available.attr, - NULL -}; - -ATTRIBUTE_GROUPS(rng_dev); - -static void __exit unregister_miscdev(void) -{ - misc_deregister(&rng_miscdev); -} - -static int __init register_miscdev(void) -{ - return misc_register(&rng_miscdev); -} - -static int hwrng_fillfn(void *unused) -{ - long rc; - - while (!kthread_should_stop()) { - struct hwrng *rng; - - rng = get_current_rng(); - if (IS_ERR(rng) || !rng) - break; - mutex_lock(&reading_mutex); - rc = rng_get_data(rng, rng_fillbuf, - rng_buffer_size(), 1); - mutex_unlock(&reading_mutex); - put_rng(rng); - if (rc <= 0) { - pr_warn("hwrng: no data available\n"); - msleep_interruptible(10000); - continue; - } - /* Outside lock, sure, but y'know: randomness. */ - add_hwgenerator_randomness((void *)rng_fillbuf, rc, - rc * current_quality * 8 >> 10); - } - hwrng_fill = NULL; - return 0; -} - -static void start_khwrngd(void) -{ - hwrng_fill = kthread_run(hwrng_fillfn, NULL, "hwrng"); - if (IS_ERR(hwrng_fill)) { - pr_err("hwrng_fill thread creation failed"); - hwrng_fill = NULL; - } -} - -int hwrng_register(struct hwrng *rng) -{ - int err = -EINVAL; - struct hwrng *old_rng, *tmp; - - if (rng->name == NULL || - (rng->data_read == NULL && rng->read == NULL)) - goto out; - - mutex_lock(&rng_mutex); - /* Must not register two RNGs with the same name. */ - err = -EEXIST; - list_for_each_entry(tmp, &rng_list, list) { - if (strcmp(tmp->name, rng->name) == 0) - goto out_unlock; - } - - init_completion(&rng->cleanup_done); - complete(&rng->cleanup_done); - - old_rng = current_rng; - err = 0; - if (!old_rng) { - err = set_current_rng(rng); - if (err) - goto out_unlock; - } - list_add_tail(&rng->list, &rng_list); - - if (old_rng && !rng->init) { - /* - * Use a new device's input to add some randomness to - * the system. If this rng device isn't going to be - * used right away, its init function hasn't been - * called yet; so only use the randomness from devices - * that don't need an init callback. - */ - add_early_randomness(rng); - } - -out_unlock: - mutex_unlock(&rng_mutex); -out: - return err; -} -EXPORT_SYMBOL_GPL(hwrng_register); - -void hwrng_unregister(struct hwrng *rng) -{ - mutex_lock(&rng_mutex); - - list_del(&rng->list); - if (current_rng == rng) { - drop_current_rng(); - if (!list_empty(&rng_list)) { - struct hwrng *tail; - - tail = list_entry(rng_list.prev, struct hwrng, list); - - set_current_rng(tail); - } - } - - if (list_empty(&rng_list)) { - mutex_unlock(&rng_mutex); - if (hwrng_fill) - kthread_stop(hwrng_fill); - } else - mutex_unlock(&rng_mutex); - - wait_for_completion(&rng->cleanup_done); -} -EXPORT_SYMBOL_GPL(hwrng_unregister); - -static void devm_hwrng_release(struct device *dev, void *res) -{ - hwrng_unregister(*(struct hwrng **)res); -} - -static int devm_hwrng_match(struct device *dev, void *res, void *data) -{ - struct hwrng **r = res; - - if (WARN_ON(!r || !*r)) - return 0; - - return *r == data; -} - -int devm_hwrng_register(struct device *dev, struct hwrng *rng) -{ - struct hwrng **ptr; - int error; - - ptr = devres_alloc(devm_hwrng_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return -ENOMEM; - - error = hwrng_register(rng); - if (error) { - devres_free(ptr); - return error; - } - - *ptr = rng; - devres_add(dev, ptr); - return 0; -} -EXPORT_SYMBOL_GPL(devm_hwrng_register); - -void devm_hwrng_unregister(struct device *dev, struct hwrng *rng) -{ - devres_release(dev, devm_hwrng_release, devm_hwrng_match, rng); -} -EXPORT_SYMBOL_GPL(devm_hwrng_unregister); - -static int __init hwrng_modinit(void) -{ - int ret = -ENOMEM; - - /* kmalloc makes this safe for virt_to_page() in virtio_rng.c */ - rng_buffer = kmalloc(rng_buffer_size(), GFP_KERNEL); - if (!rng_buffer) - return -ENOMEM; - - rng_fillbuf = kmalloc(rng_buffer_size(), GFP_KERNEL); - if (!rng_fillbuf) { - kfree(rng_buffer); - return -ENOMEM; - } - - ret = register_miscdev(); - if (ret) { - kfree(rng_fillbuf); - kfree(rng_buffer); - } - - return ret; -} - -static void __exit hwrng_modexit(void) -{ - mutex_lock(&rng_mutex); - BUG_ON(current_rng); - kfree(rng_buffer); - kfree(rng_fillbuf); - mutex_unlock(&rng_mutex); - - unregister_miscdev(); -} - -module_init(hwrng_modinit); -module_exit(hwrng_modexit); - -MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver"); -MODULE_LICENSE("GPL"); diff --git a/src/linux/drivers/char/ipmi/Kconfig b/src/linux/drivers/char/ipmi/Kconfig deleted file mode 100644 index 7f81665..0000000 --- a/src/linux/drivers/char/ipmi/Kconfig +++ /dev/null @@ -1,86 +0,0 @@ -# -# IPMI device configuration -# - -menuconfig IPMI_HANDLER - tristate 'IPMI top-level message handler' - depends on HAS_IOMEM - help - This enables the central IPMI message handler, required for IPMI - to work. - - IPMI is a standard for managing sensors (temperature, - voltage, etc.) in a system. - - See for more details on the driver. - - If unsure, say N. - -if IPMI_HANDLER - -config IPMI_PANIC_EVENT - bool 'Generate a panic event to all BMCs on a panic' - help - When a panic occurs, this will cause the IPMI message handler to - generate an IPMI event describing the panic to each interface - registered with the message handler. - -config IPMI_PANIC_STRING - bool 'Generate OEM events containing the panic string' - depends on IPMI_PANIC_EVENT - help - When a panic occurs, this will cause the IPMI message handler to - generate IPMI OEM type f0 events holding the IPMB address of the - panic generator (byte 4 of the event), a sequence number for the - string (byte 5 of the event) and part of the string (the rest of the - event). Bytes 1, 2, and 3 are the normal usage for an OEM event. - You can fetch these events and use the sequence numbers to piece the - string together. - -config IPMI_DEVICE_INTERFACE - tristate 'Device interface for IPMI' - help - This provides an IOCTL interface to the IPMI message handler so - userland processes may use IPMI. It supports poll() and select(). - -config IPMI_SI - tristate 'IPMI System Interface handler' - help - Provides a driver for System Interfaces (KCS, SMIC, BT). - Currently, only KCS and SMIC are supported. If - you are using IPMI, you should probably say "y" here. - -config IPMI_SSIF - tristate 'IPMI SMBus handler (SSIF)' - select I2C - help - Provides a driver for a SMBus interface to a BMC, meaning that you - have a driver that must be accessed over an I2C bus instead of a - standard interface. This module requires I2C support. - -config IPMI_POWERNV - depends on PPC_POWERNV - tristate 'POWERNV (OPAL firmware) IPMI interface' - help - Provides a driver for OPAL firmware-based IPMI interfaces. - -config IPMI_WATCHDOG - tristate 'IPMI Watchdog Timer' - help - This enables the IPMI watchdog timer. - -config IPMI_POWEROFF - tristate 'IPMI Poweroff' - help - This enables a function to power off the system with IPMI if - the IPMI management controller is capable of this. - -endif # IPMI_HANDLER - -config ASPEED_BT_IPMI_BMC - depends on ARCH_ASPEED - tristate "BT IPMI bmc driver" - help - Provides a driver for the BT (Block Transfer) IPMI interface - found on Aspeed SOCs (AST2400 and AST2500). The driver - implements the BMC side of the BT interface. diff --git a/src/linux/drivers/char/ipmi/Makefile b/src/linux/drivers/char/ipmi/Makefile deleted file mode 100644 index 0d98cd9..0000000 --- a/src/linux/drivers/char/ipmi/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# -# Makefile for the ipmi drivers. -# - -ipmi_si-y := ipmi_si_intf.o ipmi_kcs_sm.o ipmi_smic_sm.o ipmi_bt_sm.o - -obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o -obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o -obj-$(CONFIG_IPMI_SI) += ipmi_si.o -obj-$(CONFIG_IPMI_SSIF) += ipmi_ssif.o -obj-$(CONFIG_IPMI_POWERNV) += ipmi_powernv.o -obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o -obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o -obj-$(CONFIG_ASPEED_BT_IPMI_BMC) += bt-bmc.o diff --git a/src/linux/drivers/char/mem.c b/src/linux/drivers/char/mem.c deleted file mode 100644 index 5bb1985..0000000 --- a/src/linux/drivers/char/mem.c +++ /dev/null @@ -1,898 +0,0 @@ -/* - * linux/drivers/char/mem.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Added devfs support. - * Jan-11-1998, C. Scott Ananian - * Shared /dev/zero mmapping support, Feb 2000, Kanoj Sarcar - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef CONFIG_IA64 -# include -#endif - -#define DEVPORT_MINOR 4 - -static inline unsigned long size_inside_page(unsigned long start, - unsigned long size) -{ - unsigned long sz; - - sz = PAGE_SIZE - (start & (PAGE_SIZE - 1)); - - return min(sz, size); -} - -#ifndef ARCH_HAS_VALID_PHYS_ADDR_RANGE -static inline int valid_phys_addr_range(phys_addr_t addr, size_t count) -{ - return addr + count <= __pa(high_memory); -} - -static inline int valid_mmap_phys_addr_range(unsigned long pfn, size_t size) -{ - return 1; -} -#endif - -#ifdef CONFIG_STRICT_DEVMEM -static inline int range_is_allowed(unsigned long pfn, unsigned long size) -{ - u64 from = ((u64)pfn) << PAGE_SHIFT; - u64 to = from + size; - u64 cursor = from; - - while (cursor < to) { - if (!devmem_is_allowed(pfn)) - return 0; - cursor += PAGE_SIZE; - pfn++; - } - return 1; -} -#else -static inline int range_is_allowed(unsigned long pfn, unsigned long size) -{ - return 1; -} -#endif - -#ifndef unxlate_dev_mem_ptr -#define unxlate_dev_mem_ptr unxlate_dev_mem_ptr -void __weak unxlate_dev_mem_ptr(phys_addr_t phys, void *addr) -{ -} -#endif - -/* - * This funcion reads the *physical* memory. The f_pos points directly to the - * memory location. - */ -static ssize_t read_mem(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - phys_addr_t p = *ppos; - ssize_t read, sz; - void *ptr; - - if (p != *ppos) - return 0; - - if (!valid_phys_addr_range(p, count)) - return -EFAULT; - read = 0; -#ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED - /* we don't have page 0 mapped on sparc and m68k.. */ - if (p < PAGE_SIZE) { - sz = size_inside_page(p, count); - if (sz > 0) { - if (clear_user(buf, sz)) - return -EFAULT; - buf += sz; - p += sz; - count -= sz; - read += sz; - } - } -#endif - - while (count > 0) { - unsigned long remaining; - - sz = size_inside_page(p, count); - - if (!range_is_allowed(p >> PAGE_SHIFT, count)) - return -EPERM; - - /* - * On ia64 if a page has been mapped somewhere as uncached, then - * it must also be accessed uncached by the kernel or data - * corruption may occur. - */ - ptr = xlate_dev_mem_ptr(p); - if (!ptr) - return -EFAULT; - - remaining = copy_to_user(buf, ptr, sz); - unxlate_dev_mem_ptr(p, ptr); - if (remaining) - return -EFAULT; - - buf += sz; - p += sz; - count -= sz; - read += sz; - } - - *ppos += read; - return read; -} - -static ssize_t write_mem(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - phys_addr_t p = *ppos; - ssize_t written, sz; - unsigned long copied; - void *ptr; - - if (p != *ppos) - return -EFBIG; - - if (!valid_phys_addr_range(p, count)) - return -EFAULT; - - written = 0; - -#ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED - /* we don't have page 0 mapped on sparc and m68k.. */ - if (p < PAGE_SIZE) { - sz = size_inside_page(p, count); - /* Hmm. Do something? */ - buf += sz; - p += sz; - count -= sz; - written += sz; - } -#endif - - while (count > 0) { - sz = size_inside_page(p, count); - - if (!range_is_allowed(p >> PAGE_SHIFT, sz)) - return -EPERM; - - /* - * On ia64 if a page has been mapped somewhere as uncached, then - * it must also be accessed uncached by the kernel or data - * corruption may occur. - */ - ptr = xlate_dev_mem_ptr(p); - if (!ptr) { - if (written) - break; - return -EFAULT; - } - - copied = copy_from_user(ptr, buf, sz); - unxlate_dev_mem_ptr(p, ptr); - if (copied) { - written += sz - copied; - if (written) - break; - return -EFAULT; - } - - buf += sz; - p += sz; - count -= sz; - written += sz; - } - - *ppos += written; - return written; -} - -int __weak phys_mem_access_prot_allowed(struct file *file, - unsigned long pfn, unsigned long size, pgprot_t *vma_prot) -{ - return 1; -} - -#ifndef __HAVE_PHYS_MEM_ACCESS_PROT - -/* - * Architectures vary in how they handle caching for addresses - * outside of main memory. - * - */ -#ifdef pgprot_noncached -static int uncached_access(struct file *file, phys_addr_t addr) -{ -#if defined(CONFIG_IA64) - /* - * On ia64, we ignore O_DSYNC because we cannot tolerate memory - * attribute aliases. - */ - return !(efi_mem_attributes(addr) & EFI_MEMORY_WB); -#elif defined(CONFIG_MIPS) - { - extern int __uncached_access(struct file *file, - unsigned long addr); - - return __uncached_access(file, addr); - } -#else - /* - * Accessing memory above the top the kernel knows about or through a - * file pointer - * that was marked O_DSYNC will be done non-cached. - */ - if (file->f_flags & O_DSYNC) - return 1; - return addr >= __pa(high_memory); -#endif -} -#endif - -static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn, - unsigned long size, pgprot_t vma_prot) -{ -#ifdef pgprot_noncached - phys_addr_t offset = pfn << PAGE_SHIFT; - - if (uncached_access(file, offset)) - return pgprot_noncached(vma_prot); -#endif - return vma_prot; -} -#endif - -#ifndef CONFIG_MMU -static unsigned long get_unmapped_area_mem(struct file *file, - unsigned long addr, - unsigned long len, - unsigned long pgoff, - unsigned long flags) -{ - if (!valid_mmap_phys_addr_range(pgoff, len)) - return (unsigned long) -EINVAL; - return pgoff << PAGE_SHIFT; -} - -/* permit direct mmap, for read, write or exec */ -static unsigned memory_mmap_capabilities(struct file *file) -{ - return NOMMU_MAP_DIRECT | - NOMMU_MAP_READ | NOMMU_MAP_WRITE | NOMMU_MAP_EXEC; -} - -static unsigned zero_mmap_capabilities(struct file *file) -{ - return NOMMU_MAP_COPY; -} - -/* can't do an in-place private mapping if there's no MMU */ -static inline int private_mapping_ok(struct vm_area_struct *vma) -{ - return vma->vm_flags & VM_MAYSHARE; -} -#else - -static inline int private_mapping_ok(struct vm_area_struct *vma) -{ - return 1; -} -#endif - -static const struct vm_operations_struct mmap_mem_ops = { -#ifdef CONFIG_HAVE_IOREMAP_PROT - .access = generic_access_phys -#endif -}; - -static int mmap_mem(struct file *file, struct vm_area_struct *vma) -{ - size_t size = vma->vm_end - vma->vm_start; - - if (!valid_mmap_phys_addr_range(vma->vm_pgoff, size)) - return -EINVAL; - - if (!private_mapping_ok(vma)) - return -ENOSYS; - - if (!range_is_allowed(vma->vm_pgoff, size)) - return -EPERM; - - if (!phys_mem_access_prot_allowed(file, vma->vm_pgoff, size, - &vma->vm_page_prot)) - return -EINVAL; - - vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, - size, - vma->vm_page_prot); - - vma->vm_ops = &mmap_mem_ops; - - /* Remap-pfn-range will mark the range VM_IO */ - if (remap_pfn_range(vma, - vma->vm_start, - vma->vm_pgoff, - size, - vma->vm_page_prot)) { - return -EAGAIN; - } - return 0; -} - -static int mmap_kmem(struct file *file, struct vm_area_struct *vma) -{ - unsigned long pfn; - - /* Turn a kernel-virtual address into a physical page frame */ - pfn = __pa((u64)vma->vm_pgoff << PAGE_SHIFT) >> PAGE_SHIFT; - - /* - * RED-PEN: on some architectures there is more mapped memory than - * available in mem_map which pfn_valid checks for. Perhaps should add a - * new macro here. - * - * RED-PEN: vmalloc is not supported right now. - */ - if (!pfn_valid(pfn)) - return -EIO; - - vma->vm_pgoff = pfn; - return mmap_mem(file, vma); -} - -/* - * This function reads the *virtual* memory as seen by the kernel. - */ -static ssize_t read_kmem(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - unsigned long p = *ppos; - ssize_t low_count, read, sz; - char *kbuf; /* k-addr because vread() takes vmlist_lock rwlock */ - int err = 0; - - if (!pfn_valid(PFN_DOWN(p))) - return -EIO; - - read = 0; - if (p < (unsigned long) high_memory) { - low_count = count; - if (count > (unsigned long)high_memory - p) - low_count = (unsigned long)high_memory - p; - -#ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED - /* we don't have page 0 mapped on sparc and m68k.. */ - if (p < PAGE_SIZE && low_count > 0) { - sz = size_inside_page(p, low_count); - if (clear_user(buf, sz)) - return -EFAULT; - buf += sz; - p += sz; - read += sz; - low_count -= sz; - count -= sz; - } -#endif - while (low_count > 0) { - sz = size_inside_page(p, low_count); - - /* - * On ia64 if a page has been mapped somewhere as - * uncached, then it must also be accessed uncached - * by the kernel or data corruption may occur - */ - kbuf = xlate_dev_kmem_ptr((void *)p); - - if (copy_to_user(buf, kbuf, sz)) - return -EFAULT; - buf += sz; - p += sz; - read += sz; - low_count -= sz; - count -= sz; - } - } - - if (count > 0) { - kbuf = (char *)__get_free_page(GFP_KERNEL); - if (!kbuf) - return -ENOMEM; - while (count > 0) { - sz = size_inside_page(p, count); - if (!is_vmalloc_or_module_addr((void *)p)) { - err = -ENXIO; - break; - } - sz = vread(kbuf, (char *)p, sz); - if (!sz) - break; - if (copy_to_user(buf, kbuf, sz)) { - err = -EFAULT; - break; - } - count -= sz; - buf += sz; - read += sz; - p += sz; - } - free_page((unsigned long)kbuf); - } - *ppos = p; - return read ? read : err; -} - - -static ssize_t do_write_kmem(unsigned long p, const char __user *buf, - size_t count, loff_t *ppos) -{ - ssize_t written, sz; - unsigned long copied; - - written = 0; -#ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED - /* we don't have page 0 mapped on sparc and m68k.. */ - if (p < PAGE_SIZE) { - sz = size_inside_page(p, count); - /* Hmm. Do something? */ - buf += sz; - p += sz; - count -= sz; - written += sz; - } -#endif - - while (count > 0) { - void *ptr; - - sz = size_inside_page(p, count); - - /* - * On ia64 if a page has been mapped somewhere as uncached, then - * it must also be accessed uncached by the kernel or data - * corruption may occur. - */ - ptr = xlate_dev_kmem_ptr((void *)p); - - copied = copy_from_user(ptr, buf, sz); - if (copied) { - written += sz - copied; - if (written) - break; - return -EFAULT; - } - buf += sz; - p += sz; - count -= sz; - written += sz; - } - - *ppos += written; - return written; -} - -/* - * This function writes to the *virtual* memory as seen by the kernel. - */ -static ssize_t write_kmem(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - unsigned long p = *ppos; - ssize_t wrote = 0; - ssize_t virtr = 0; - char *kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ - int err = 0; - - if (!pfn_valid(PFN_DOWN(p))) - return -EIO; - - if (p < (unsigned long) high_memory) { - unsigned long to_write = min_t(unsigned long, count, - (unsigned long)high_memory - p); - wrote = do_write_kmem(p, buf, to_write, ppos); - if (wrote != to_write) - return wrote; - p += wrote; - buf += wrote; - count -= wrote; - } - - if (count > 0) { - kbuf = (char *)__get_free_page(GFP_KERNEL); - if (!kbuf) - return wrote ? wrote : -ENOMEM; - while (count > 0) { - unsigned long sz = size_inside_page(p, count); - unsigned long n; - - if (!is_vmalloc_or_module_addr((void *)p)) { - err = -ENXIO; - break; - } - n = copy_from_user(kbuf, buf, sz); - if (n) { - err = -EFAULT; - break; - } - vwrite(kbuf, (char *)p, sz); - count -= sz; - buf += sz; - virtr += sz; - p += sz; - } - free_page((unsigned long)kbuf); - } - - *ppos = p; - return virtr + wrote ? : err; -} - -static ssize_t read_port(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - unsigned long i = *ppos; - char __user *tmp = buf; - - if (!access_ok(VERIFY_WRITE, buf, count)) - return -EFAULT; - while (count-- > 0 && i < 65536) { - if (__put_user(inb(i), tmp) < 0) - return -EFAULT; - i++; - tmp++; - } - *ppos = i; - return tmp-buf; -} - -static ssize_t write_port(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - unsigned long i = *ppos; - const char __user *tmp = buf; - - if (!access_ok(VERIFY_READ, buf, count)) - return -EFAULT; - while (count-- > 0 && i < 65536) { - char c; - - if (__get_user(c, tmp)) { - if (tmp > buf) - break; - return -EFAULT; - } - outb(c, i); - i++; - tmp++; - } - *ppos = i; - return tmp-buf; -} - -static ssize_t read_null(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - return 0; -} - -static ssize_t write_null(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - return count; -} - -static ssize_t read_iter_null(struct kiocb *iocb, struct iov_iter *to) -{ - return 0; -} - -static ssize_t write_iter_null(struct kiocb *iocb, struct iov_iter *from) -{ - size_t count = iov_iter_count(from); - iov_iter_advance(from, count); - return count; -} - -static int pipe_to_null(struct pipe_inode_info *info, struct pipe_buffer *buf, - struct splice_desc *sd) -{ - return sd->len; -} - -static ssize_t splice_write_null(struct pipe_inode_info *pipe, struct file *out, - loff_t *ppos, size_t len, unsigned int flags) -{ - return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_null); -} - -static ssize_t read_iter_zero(struct kiocb *iocb, struct iov_iter *iter) -{ - size_t written = 0; - - while (iov_iter_count(iter)) { - size_t chunk = iov_iter_count(iter), n; - - if (chunk > PAGE_SIZE) - chunk = PAGE_SIZE; /* Just for latency reasons */ - n = iov_iter_zero(chunk, iter); - if (!n && iov_iter_count(iter)) - return written ? written : -EFAULT; - written += n; - if (signal_pending(current)) - return written ? written : -ERESTARTSYS; - cond_resched(); - } - return written; -} - -static int mmap_zero(struct file *file, struct vm_area_struct *vma) -{ -#ifndef CONFIG_MMU - return -ENOSYS; -#endif - if (vma->vm_flags & VM_SHARED) - return shmem_zero_setup(vma); - return 0; -} - -static unsigned long get_unmapped_area_zero(struct file *file, - unsigned long addr, unsigned long len, - unsigned long pgoff, unsigned long flags) -{ -#ifdef CONFIG_MMU - if (flags & MAP_SHARED) { - /* - * mmap_zero() will call shmem_zero_setup() to create a file, - * so use shmem's get_unmapped_area in case it can be huge; - * and pass NULL for file as in mmap.c's get_unmapped_area(), - * so as not to confuse shmem with our handle on "/dev/zero". - */ - return shmem_get_unmapped_area(NULL, addr, len, pgoff, flags); - } - - /* Otherwise flags & MAP_PRIVATE: with no shmem object beneath it */ - return current->mm->get_unmapped_area(file, addr, len, pgoff, flags); -#else - return -ENOSYS; -#endif -} - -static ssize_t write_full(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - return -ENOSPC; -} - -/* - * Special lseek() function for /dev/null and /dev/zero. Most notably, you - * can fopen() both devices with "a" now. This was previously impossible. - * -- SRB. - */ -static loff_t null_lseek(struct file *file, loff_t offset, int orig) -{ - return file->f_pos = 0; -} - -/* - * The memory devices use the full 32/64 bits of the offset, and so we cannot - * check against negative addresses: they are ok. The return value is weird, - * though, in that case (0). - * - * also note that seeking relative to the "end of file" isn't supported: - * it has no meaning, so it returns -EINVAL. - */ -static loff_t memory_lseek(struct file *file, loff_t offset, int orig) -{ - loff_t ret; - - inode_lock(file_inode(file)); - switch (orig) { - case SEEK_CUR: - offset += file->f_pos; - case SEEK_SET: - /* to avoid userland mistaking f_pos=-9 as -EBADF=-9 */ - if ((unsigned long long)offset >= -MAX_ERRNO) { - ret = -EOVERFLOW; - break; - } - file->f_pos = offset; - ret = file->f_pos; - force_successful_syscall_return(); - break; - default: - ret = -EINVAL; - } - inode_unlock(file_inode(file)); - return ret; -} - -static int open_port(struct inode *inode, struct file *filp) -{ - return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; -} - -#define zero_lseek null_lseek -#define full_lseek null_lseek -#define write_zero write_null -#define write_iter_zero write_iter_null -#define open_mem open_port -#define open_kmem open_mem - -static const struct file_operations __maybe_unused mem_fops = { - .llseek = memory_lseek, - .read = read_mem, - .write = write_mem, - .mmap = mmap_mem, - .open = open_mem, -#ifndef CONFIG_MMU - .get_unmapped_area = get_unmapped_area_mem, - .mmap_capabilities = memory_mmap_capabilities, -#endif -}; - -static const struct file_operations __maybe_unused kmem_fops = { - .llseek = memory_lseek, - .read = read_kmem, - .write = write_kmem, - .mmap = mmap_kmem, - .open = open_kmem, -#ifndef CONFIG_MMU - .get_unmapped_area = get_unmapped_area_mem, - .mmap_capabilities = memory_mmap_capabilities, -#endif -}; - -static const struct file_operations null_fops = { - .llseek = null_lseek, - .read = read_null, - .write = write_null, - .read_iter = read_iter_null, - .write_iter = write_iter_null, - .splice_write = splice_write_null, -}; - -static const struct file_operations __maybe_unused port_fops = { - .llseek = memory_lseek, - .read = read_port, - .write = write_port, - .open = open_port, -}; - -static const struct file_operations zero_fops = { - .llseek = zero_lseek, - .write = write_zero, - .read_iter = read_iter_zero, - .write_iter = write_iter_zero, - .mmap = mmap_zero, - .get_unmapped_area = get_unmapped_area_zero, -#ifndef CONFIG_MMU - .mmap_capabilities = zero_mmap_capabilities, -#endif -}; - -static const struct file_operations full_fops = { - .llseek = full_lseek, - .read_iter = read_iter_zero, - .write = write_full, -}; - -static const struct memdev { - const char *name; - umode_t mode; - const struct file_operations *fops; - fmode_t fmode; -} devlist[] = { -#ifdef CONFIG_DEVMEM - [1] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET }, -#endif -#ifdef CONFIG_DEVKMEM - [2] = { "kmem", 0, &kmem_fops, FMODE_UNSIGNED_OFFSET }, -#endif - [3] = { "null", 0666, &null_fops, 0 }, -#ifdef CONFIG_DEVPORT - [4] = { "port", 0, &port_fops, 0 }, -#endif - [5] = { "zero", 0666, &zero_fops, 0 }, - [7] = { "full", 0666, &full_fops, 0 }, - [8] = { "random", 0666, &random_fops, 0 }, - [9] = { "urandom", 0666, &urandom_fops, 0 }, -#ifdef CONFIG_PRINTK - [11] = { "kmsg", 0644, &kmsg_fops, 0 }, -#endif -}; - -static int memory_open(struct inode *inode, struct file *filp) -{ - int minor; - const struct memdev *dev; - - minor = iminor(inode); - if (minor >= ARRAY_SIZE(devlist)) - return -ENXIO; - - dev = &devlist[minor]; - if (!dev->fops) - return -ENXIO; - - filp->f_op = dev->fops; - filp->f_mode |= dev->fmode; - - if (dev->fops->open) - return dev->fops->open(inode, filp); - - return 0; -} - -static const struct file_operations memory_fops = { - .open = memory_open, - .llseek = noop_llseek, -}; - -static char *mem_devnode(struct device *dev, umode_t *mode) -{ - if (mode && devlist[MINOR(dev->devt)].mode) - *mode = devlist[MINOR(dev->devt)].mode; - return NULL; -} - -static struct class *mem_class; - -static int __init chr_dev_init(void) -{ - int minor; - - if (register_chrdev(MEM_MAJOR, "mem", &memory_fops)) - printk("unable to get major %d for memory devs\n", MEM_MAJOR); - - mem_class = class_create(THIS_MODULE, "mem"); - if (IS_ERR(mem_class)) - return PTR_ERR(mem_class); - - mem_class->devnode = mem_devnode; - for (minor = 1; minor < ARRAY_SIZE(devlist); minor++) { - if (!devlist[minor].name) - continue; - - /* - * Create /dev/port? - */ - if ((minor == DEVPORT_MINOR) && !arch_has_dev_port()) - continue; - - device_create(mem_class, NULL, MKDEV(MEM_MAJOR, minor), - NULL, devlist[minor].name); - } - - return tty_init(); -} - -fs_initcall(chr_dev_init); diff --git a/src/linux/drivers/char/misc.c b/src/linux/drivers/char/misc.c deleted file mode 100644 index 8069b36..0000000 --- a/src/linux/drivers/char/misc.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * linux/drivers/char/misc.c - * - * Generic misc open routine by Johan Myreen - * - * Based on code from Linus - * - * Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's - * changes incorporated into 0.97pl4 - * by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92) - * See busmouse.c for particulars. - * - * Made things a lot mode modular - easy to compile in just one or two - * of the misc drivers, as they are now completely independent. Linus. - * - * Support for loadable modules. 8-Sep-95 Philip Blundell - * - * Fixed a failing symbol register to free the device registration - * Alan Cox 21-Jan-96 - * - * Dynamic minors and /proc/mice by Alessandro Rubini. 26-Mar-96 - * - * Renamed to misc and miscdevice to be more accurate. Alan Cox 26-Mar-96 - * - * Handling of mouse minor numbers for kerneld: - * Idea by Jacques Gelinas , - * adapted by Bjorn Ekwall - * corrected by Alan Cox - * - * Changes for kmod (from kerneld): - * Cyrus Durgin - * - * Added devfs support. Richard Gooch 10-Jan-1998 - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Head entry for the doubly linked miscdevice list - */ -static LIST_HEAD(misc_list); -static DEFINE_MUTEX(misc_mtx); - -/* - * Assigned numbers, used for dynamic minors - */ -#define DYNAMIC_MINORS 64 /* like dynamic majors */ -static DECLARE_BITMAP(misc_minors, DYNAMIC_MINORS); - -#ifdef CONFIG_PROC_FS -static void *misc_seq_start(struct seq_file *seq, loff_t *pos) -{ - mutex_lock(&misc_mtx); - return seq_list_start(&misc_list, *pos); -} - -static void *misc_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return seq_list_next(v, &misc_list, pos); -} - -static void misc_seq_stop(struct seq_file *seq, void *v) -{ - mutex_unlock(&misc_mtx); -} - -static int misc_seq_show(struct seq_file *seq, void *v) -{ - const struct miscdevice *p = list_entry(v, struct miscdevice, list); - - seq_printf(seq, "%3i %s\n", p->minor, p->name ? p->name : ""); - return 0; -} - - -static const struct seq_operations misc_seq_ops = { - .start = misc_seq_start, - .next = misc_seq_next, - .stop = misc_seq_stop, - .show = misc_seq_show, -}; - -static int misc_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &misc_seq_ops); -} - -static const struct file_operations misc_proc_fops = { - .owner = THIS_MODULE, - .open = misc_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; -#endif - -static int misc_open(struct inode * inode, struct file * file) -{ - int minor = iminor(inode); - struct miscdevice *c; - int err = -ENODEV; - const struct file_operations *new_fops = NULL; - - mutex_lock(&misc_mtx); - - list_for_each_entry(c, &misc_list, list) { - if (c->minor == minor) { - new_fops = fops_get(c->fops); - break; - } - } - - if (!new_fops) { - mutex_unlock(&misc_mtx); - request_module("char-major-%d-%d", MISC_MAJOR, minor); - mutex_lock(&misc_mtx); - - list_for_each_entry(c, &misc_list, list) { - if (c->minor == minor) { - new_fops = fops_get(c->fops); - break; - } - } - if (!new_fops) - goto fail; - } - - /* - * Place the miscdevice in the file's - * private_data so it can be used by the - * file operations, including f_op->open below - */ - file->private_data = c; - - err = 0; - replace_fops(file, new_fops); - if (file->f_op->open) - err = file->f_op->open(inode,file); -fail: - mutex_unlock(&misc_mtx); - return err; -} - -static struct class *misc_class; - -static const struct file_operations misc_fops = { - .owner = THIS_MODULE, - .open = misc_open, - .llseek = noop_llseek, -}; - -/** - * misc_register - register a miscellaneous device - * @misc: device structure - * - * Register a miscellaneous device with the kernel. If the minor - * number is set to %MISC_DYNAMIC_MINOR a minor number is assigned - * and placed in the minor field of the structure. For other cases - * the minor number requested is used. - * - * The structure passed is linked into the kernel and may not be - * destroyed until it has been unregistered. By default, an open() - * syscall to the device sets file->private_data to point to the - * structure. Drivers don't need open in fops for this. - * - * A zero is returned on success and a negative errno code for - * failure. - */ - -int misc_register(struct miscdevice * misc) -{ - dev_t dev; - int err = 0; - bool is_dynamic = (misc->minor == MISC_DYNAMIC_MINOR); - - INIT_LIST_HEAD(&misc->list); - - mutex_lock(&misc_mtx); - - if (is_dynamic) { - int i = find_first_zero_bit(misc_minors, DYNAMIC_MINORS); - if (i >= DYNAMIC_MINORS) { - err = -EBUSY; - goto out; - } - misc->minor = DYNAMIC_MINORS - i - 1; - set_bit(i, misc_minors); - } else { - struct miscdevice *c; - - list_for_each_entry(c, &misc_list, list) { - if (c->minor == misc->minor) { - err = -EBUSY; - goto out; - } - } - } - - dev = MKDEV(MISC_MAJOR, misc->minor); - - misc->this_device = - device_create_with_groups(misc_class, misc->parent, dev, - misc, misc->groups, "%s", misc->name); - if (IS_ERR(misc->this_device)) { - if (is_dynamic) { - int i = DYNAMIC_MINORS - misc->minor - 1; - - if (i < DYNAMIC_MINORS && i >= 0) - clear_bit(i, misc_minors); - misc->minor = MISC_DYNAMIC_MINOR; - } - err = PTR_ERR(misc->this_device); - goto out; - } - - /* - * Add it to the front, so that later devices can "override" - * earlier defaults - */ - list_add(&misc->list, &misc_list); - out: - mutex_unlock(&misc_mtx); - return err; -} - -/** - * misc_deregister - unregister a miscellaneous device - * @misc: device to unregister - * - * Unregister a miscellaneous device that was previously - * successfully registered with misc_register(). - */ - -void misc_deregister(struct miscdevice *misc) -{ - int i = DYNAMIC_MINORS - misc->minor - 1; - - if (WARN_ON(list_empty(&misc->list))) - return; - - mutex_lock(&misc_mtx); - list_del(&misc->list); - device_destroy(misc_class, MKDEV(MISC_MAJOR, misc->minor)); - if (i < DYNAMIC_MINORS && i >= 0) - clear_bit(i, misc_minors); - mutex_unlock(&misc_mtx); -} - -EXPORT_SYMBOL(misc_register); -EXPORT_SYMBOL(misc_deregister); - -static char *misc_devnode(struct device *dev, umode_t *mode) -{ - struct miscdevice *c = dev_get_drvdata(dev); - - if (mode && c->mode) - *mode = c->mode; - if (c->nodename) - return kstrdup(c->nodename, GFP_KERNEL); - return NULL; -} - -static int __init misc_init(void) -{ - int err; - struct proc_dir_entry *ret; - - ret = proc_create("misc", 0, NULL, &misc_proc_fops); - misc_class = class_create(THIS_MODULE, "misc"); - err = PTR_ERR(misc_class); - if (IS_ERR(misc_class)) - goto fail_remove; - - err = -EIO; - if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) - goto fail_printk; - misc_class->devnode = misc_devnode; - return 0; - -fail_printk: - printk("unable to get major %d for misc devices\n", MISC_MAJOR); - class_destroy(misc_class); -fail_remove: - if (ret) - remove_proc_entry("misc", NULL); - return err; -} -subsys_initcall(misc_init); diff --git a/src/linux/drivers/char/pcmcia/Kconfig b/src/linux/drivers/char/pcmcia/Kconfig deleted file mode 100644 index 8d3dfb0..0000000 --- a/src/linux/drivers/char/pcmcia/Kconfig +++ /dev/null @@ -1,56 +0,0 @@ -# -# PCMCIA character device configuration -# - -menu "PCMCIA character devices" - depends on PCMCIA!=n - -config SYNCLINK_CS - tristate "SyncLink PC Card support" - depends on PCMCIA && TTY - help - Enable support for the SyncLink PC Card serial adapter, running - asynchronous and HDLC communications up to 512Kbps. The port is - selectable for RS-232, V.35, RS-449, RS-530, and X.21 - - This driver may be built as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called synclink_cs. If you want to do that, say M - here. - -config CARDMAN_4000 - tristate "Omnikey Cardman 4000 support" - depends on PCMCIA - select BITREVERSE - help - Enable support for the Omnikey Cardman 4000 PCMCIA Smartcard - reader. - - This kernel driver requires additional userspace support, either - by the vendor-provided PC/SC ifd_handler (http://www.omnikey.com/), - or via the cm4000 backend of OpenCT (http://www.opensc-project.org/opensc). - -config CARDMAN_4040 - tristate "Omnikey CardMan 4040 support" - depends on PCMCIA - help - Enable support for the Omnikey CardMan 4040 PCMCIA Smartcard - reader. - - This card is basically a USB CCID device connected to a FIFO - in I/O space. To use the kernel driver, you will need either the - PC/SC ifdhandler provided from the Omnikey homepage - (http://www.omnikey.com/), or a current development version of OpenCT - (http://www.opensc-project.org/opensc). - -config IPWIRELESS - tristate "IPWireless 3G UMTS PCMCIA card support" - depends on PCMCIA && NETDEVICES && TTY - select PPP - help - This is a driver for 3G UMTS PCMCIA card from IPWireless company. In - some countries (for example Czech Republic, T-Mobile ISP) this card - is shipped for service called UMTS 4G. - -endmenu - diff --git a/src/linux/drivers/char/random.c b/src/linux/drivers/char/random.c deleted file mode 100644 index d6876d5..0000000 --- a/src/linux/drivers/char/random.c +++ /dev/null @@ -1,2159 +0,0 @@ -/* - * random.c -- A strong random number generator - * - * Copyright Matt Mackall , 2003, 2004, 2005 - * - * Copyright Theodore Ts'o, 1994, 1995, 1996, 1997, 1998, 1999. All - * rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU General Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - */ - -/* - * (now, with legal B.S. out of the way.....) - * - * This routine gathers environmental noise from device drivers, etc., - * and returns good random numbers, suitable for cryptographic use. - * Besides the obvious cryptographic uses, these numbers are also good - * for seeding TCP sequence numbers, and other places where it is - * desirable to have numbers which are not only random, but hard to - * predict by an attacker. - * - * Theory of operation - * =================== - * - * Computers are very predictable devices. Hence it is extremely hard - * to produce truly random numbers on a computer --- as opposed to - * pseudo-random numbers, which can easily generated by using a - * algorithm. Unfortunately, it is very easy for attackers to guess - * the sequence of pseudo-random number generators, and for some - * applications this is not acceptable. So instead, we must try to - * gather "environmental noise" from the computer's environment, which - * must be hard for outside attackers to observe, and use that to - * generate random numbers. In a Unix environment, this is best done - * from inside the kernel. - * - * Sources of randomness from the environment include inter-keyboard - * timings, inter-interrupt timings from some interrupts, and other - * events which are both (a) non-deterministic and (b) hard for an - * outside observer to measure. Randomness from these sources are - * added to an "entropy pool", which is mixed using a CRC-like function. - * This is not cryptographically strong, but it is adequate assuming - * the randomness is not chosen maliciously, and it is fast enough that - * the overhead of doing it on every interrupt is very reasonable. - * As random bytes are mixed into the entropy pool, the routines keep - * an *estimate* of how many bits of randomness have been stored into - * the random number generator's internal state. - * - * When random bytes are desired, they are obtained by taking the SHA - * hash of the contents of the "entropy pool". The SHA hash avoids - * exposing the internal state of the entropy pool. It is believed to - * be computationally infeasible to derive any useful information - * about the input of SHA from its output. Even if it is possible to - * analyze SHA in some clever way, as long as the amount of data - * returned from the generator is less than the inherent entropy in - * the pool, the output data is totally unpredictable. For this - * reason, the routine decreases its internal estimate of how many - * bits of "true randomness" are contained in the entropy pool as it - * outputs random numbers. - * - * If this estimate goes to zero, the routine can still generate - * random numbers; however, an attacker may (at least in theory) be - * able to infer the future output of the generator from prior - * outputs. This requires successful cryptanalysis of SHA, which is - * not believed to be feasible, but there is a remote possibility. - * Nonetheless, these numbers should be useful for the vast majority - * of purposes. - * - * Exported interfaces ---- output - * =============================== - * - * There are three exported interfaces; the first is one designed to - * be used from within the kernel: - * - * void get_random_bytes(void *buf, int nbytes); - * - * This interface will return the requested number of random bytes, - * and place it in the requested buffer. - * - * The two other interfaces are two character devices /dev/random and - * /dev/urandom. /dev/random is suitable for use when very high - * quality randomness is desired (for example, for key generation or - * one-time pads), as it will only return a maximum of the number of - * bits of randomness (as estimated by the random number generator) - * contained in the entropy pool. - * - * The /dev/urandom device does not have this limit, and will return - * as many bytes as are requested. As more and more random bytes are - * requested without giving time for the entropy pool to recharge, - * this will result in random numbers that are merely cryptographically - * strong. For many applications, however, this is acceptable. - * - * Exported interfaces ---- input - * ============================== - * - * The current exported interfaces for gathering environmental noise - * from the devices are: - * - * void add_device_randomness(const void *buf, unsigned int size); - * void add_input_randomness(unsigned int type, unsigned int code, - * unsigned int value); - * void add_interrupt_randomness(int irq, int irq_flags); - * void add_disk_randomness(struct gendisk *disk); - * - * add_device_randomness() is for adding data to the random pool that - * is likely to differ between two devices (or possibly even per boot). - * This would be things like MAC addresses or serial numbers, or the - * read-out of the RTC. This does *not* add any actual entropy to the - * pool, but it initializes the pool to different values for devices - * that might otherwise be identical and have very little entropy - * available to them (particularly common in the embedded world). - * - * add_input_randomness() uses the input layer interrupt timing, as well as - * the event type information from the hardware. - * - * add_interrupt_randomness() uses the interrupt timing as random - * inputs to the entropy pool. Using the cycle counters and the irq source - * as inputs, it feeds the randomness roughly once a second. - * - * add_disk_randomness() uses what amounts to the seek time of block - * layer request events, on a per-disk_devt basis, as input to the - * entropy pool. Note that high-speed solid state drives with very low - * seek times do not make for good sources of entropy, as their seek - * times are usually fairly consistent. - * - * All of these routines try to estimate how many bits of randomness a - * particular randomness source. They do this by keeping track of the - * first and second order deltas of the event timings. - * - * Ensuring unpredictability at system startup - * ============================================ - * - * When any operating system starts up, it will go through a sequence - * of actions that are fairly predictable by an adversary, especially - * if the start-up does not involve interaction with a human operator. - * This reduces the actual number of bits of unpredictability in the - * entropy pool below the value in entropy_count. In order to - * counteract this effect, it helps to carry information in the - * entropy pool across shut-downs and start-ups. To do this, put the - * following lines an appropriate script which is run during the boot - * sequence: - * - * echo "Initializing random number generator..." - * random_seed=/var/run/random-seed - * # Carry a random seed from start-up to start-up - * # Load and then save the whole entropy pool - * if [ -f $random_seed ]; then - * cat $random_seed >/dev/urandom - * else - * touch $random_seed - * fi - * chmod 600 $random_seed - * dd if=/dev/urandom of=$random_seed count=1 bs=512 - * - * and the following lines in an appropriate script which is run as - * the system is shutdown: - * - * # Carry a random seed from shut-down to start-up - * # Save the whole entropy pool - * echo "Saving random seed..." - * random_seed=/var/run/random-seed - * touch $random_seed - * chmod 600 $random_seed - * dd if=/dev/urandom of=$random_seed count=1 bs=512 - * - * For example, on most modern systems using the System V init - * scripts, such code fragments would be found in - * /etc/rc.d/init.d/random. On older Linux systems, the correct script - * location might be in /etc/rcb.d/rc.local or /etc/rc.d/rc.0. - * - * Effectively, these commands cause the contents of the entropy pool - * to be saved at shut-down time and reloaded into the entropy pool at - * start-up. (The 'dd' in the addition to the bootup script is to - * make sure that /etc/random-seed is different for every start-up, - * even if the system crashes without executing rc.0.) Even with - * complete knowledge of the start-up activities, predicting the state - * of the entropy pool requires knowledge of the previous history of - * the system. - * - * Configuring the /dev/random driver under Linux - * ============================================== - * - * The /dev/random driver under Linux uses minor numbers 8 and 9 of - * the /dev/mem major number (#1). So if your system does not have - * /dev/random and /dev/urandom created already, they can be created - * by using the commands: - * - * mknod /dev/random c 1 8 - * mknod /dev/urandom c 1 9 - * - * Acknowledgements: - * ================= - * - * Ideas for constructing this random number generator were derived - * from Pretty Good Privacy's random number generator, and from private - * discussions with Phil Karn. Colin Plumb provided a faster random - * number generator, which speed up the mixing function of the entropy - * pool, taken from PGPfone. Dale Worley has also contributed many - * useful ideas and suggestions to improve this driver. - * - * Any flaws in the design are solely my responsibility, and should - * not be attributed to the Phil, Colin, or any of authors of PGP. - * - * Further background information on this topic may be obtained from - * RFC 1750, "Randomness Recommendations for Security", by Donald - * Eastlake, Steve Crocker, and Jeff Schiller. - */ - -#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 - -#include -#include -#include -#include -#include - -#define CREATE_TRACE_POINTS -#include - -/* #define ADD_INTERRUPT_BENCH */ - -/* - * Configuration information - */ -#define INPUT_POOL_SHIFT 12 -#define INPUT_POOL_WORDS (1 << (INPUT_POOL_SHIFT-5)) -#define OUTPUT_POOL_SHIFT 10 -#define OUTPUT_POOL_WORDS (1 << (OUTPUT_POOL_SHIFT-5)) -#define SEC_XFER_SIZE 512 -#define EXTRACT_SIZE 10 - -#define DEBUG_RANDOM_BOOT 0 - -#define LONGS(x) (((x) + sizeof(unsigned long) - 1)/sizeof(unsigned long)) - -/* - * To allow fractional bits to be tracked, the entropy_count field is - * denominated in units of 1/8th bits. - * - * 2*(ENTROPY_SHIFT + log2(poolbits)) must <= 31, or the multiply in - * credit_entropy_bits() needs to be 64 bits wide. - */ -#define ENTROPY_SHIFT 3 -#define ENTROPY_BITS(r) ((r)->entropy_count >> ENTROPY_SHIFT) - -/* - * The minimum number of bits of entropy before we wake up a read on - * /dev/random. Should be enough to do a significant reseed. - */ -static int random_read_wakeup_bits = 64; - -/* - * If the entropy count falls under this number of bits, then we - * should wake up processes which are selecting or polling on write - * access to /dev/random. - */ -static int random_write_wakeup_bits = 28 * OUTPUT_POOL_WORDS; - -/* - * The minimum number of seconds between urandom pool reseeding. We - * do this to limit the amount of entropy that can be drained from the - * input pool even if there are heavy demands on /dev/urandom. - */ -static int random_min_urandom_seed = 60; - -/* - * Originally, we used a primitive polynomial of degree .poolwords - * over GF(2). The taps for various sizes are defined below. They - * were chosen to be evenly spaced except for the last tap, which is 1 - * to get the twisting happening as fast as possible. - * - * For the purposes of better mixing, we use the CRC-32 polynomial as - * well to make a (modified) twisted Generalized Feedback Shift - * Register. (See M. Matsumoto & Y. Kurita, 1992. Twisted GFSR - * generators. ACM Transactions on Modeling and Computer Simulation - * 2(3):179-194. Also see M. Matsumoto & Y. Kurita, 1994. Twisted - * GFSR generators II. ACM Transactions on Modeling and Computer - * Simulation 4:254-266) - * - * Thanks to Colin Plumb for suggesting this. - * - * The mixing operation is much less sensitive than the output hash, - * where we use SHA-1. All that we want of mixing operation is that - * it be a good non-cryptographic hash; i.e. it not produce collisions - * when fed "random" data of the sort we expect to see. As long as - * the pool state differs for different inputs, we have preserved the - * input entropy and done a good job. The fact that an intelligent - * attacker can construct inputs that will produce controlled - * alterations to the pool's state is not important because we don't - * consider such inputs to contribute any randomness. The only - * property we need with respect to them is that the attacker can't - * increase his/her knowledge of the pool's state. Since all - * additions are reversible (knowing the final state and the input, - * you can reconstruct the initial state), if an attacker has any - * uncertainty about the initial state, he/she can only shuffle that - * uncertainty about, but never cause any collisions (which would - * decrease the uncertainty). - * - * Our mixing functions were analyzed by Lacharme, Roeck, Strubel, and - * Videau in their paper, "The Linux Pseudorandom Number Generator - * Revisited" (see: http://eprint.iacr.org/2012/251.pdf). In their - * paper, they point out that we are not using a true Twisted GFSR, - * since Matsumoto & Kurita used a trinomial feedback polynomial (that - * is, with only three taps, instead of the six that we are using). - * As a result, the resulting polynomial is neither primitive nor - * irreducible, and hence does not have a maximal period over - * GF(2**32). They suggest a slight change to the generator - * polynomial which improves the resulting TGFSR polynomial to be - * irreducible, which we have made here. - */ -static struct poolinfo { - int poolbitshift, poolwords, poolbytes, poolbits, poolfracbits; -#define S(x) ilog2(x)+5, (x), (x)*4, (x)*32, (x) << (ENTROPY_SHIFT+5) - int tap1, tap2, tap3, tap4, tap5; -} poolinfo_table[] = { - /* was: x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 */ - /* x^128 + x^104 + x^76 + x^51 +x^25 + x + 1 */ - { S(128), 104, 76, 51, 25, 1 }, - /* was: x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 */ - /* x^32 + x^26 + x^19 + x^14 + x^7 + x + 1 */ - { S(32), 26, 19, 14, 7, 1 }, -#if 0 - /* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1 -- 115 */ - { S(2048), 1638, 1231, 819, 411, 1 }, - - /* x^1024 + x^817 + x^615 + x^412 + x^204 + x + 1 -- 290 */ - { S(1024), 817, 615, 412, 204, 1 }, - - /* x^1024 + x^819 + x^616 + x^410 + x^207 + x^2 + 1 -- 115 */ - { S(1024), 819, 616, 410, 207, 2 }, - - /* x^512 + x^411 + x^308 + x^208 + x^104 + x + 1 -- 225 */ - { S(512), 411, 308, 208, 104, 1 }, - - /* x^512 + x^409 + x^307 + x^206 + x^102 + x^2 + 1 -- 95 */ - { S(512), 409, 307, 206, 102, 2 }, - /* x^512 + x^409 + x^309 + x^205 + x^103 + x^2 + 1 -- 95 */ - { S(512), 409, 309, 205, 103, 2 }, - - /* x^256 + x^205 + x^155 + x^101 + x^52 + x + 1 -- 125 */ - { S(256), 205, 155, 101, 52, 1 }, - - /* x^128 + x^103 + x^78 + x^51 + x^27 + x^2 + 1 -- 70 */ - { S(128), 103, 78, 51, 27, 2 }, - - /* x^64 + x^52 + x^39 + x^26 + x^14 + x + 1 -- 15 */ - { S(64), 52, 39, 26, 14, 1 }, -#endif -}; - -/* - * Static global variables - */ -static DECLARE_WAIT_QUEUE_HEAD(random_read_wait); -static DECLARE_WAIT_QUEUE_HEAD(random_write_wait); -static DECLARE_WAIT_QUEUE_HEAD(urandom_init_wait); -static struct fasync_struct *fasync; - -static DEFINE_SPINLOCK(random_ready_list_lock); -static LIST_HEAD(random_ready_list); - -struct crng_state { - __u32 state[16]; - unsigned long init_time; - spinlock_t lock; -}; - -struct crng_state primary_crng = { - .lock = __SPIN_LOCK_UNLOCKED(primary_crng.lock), -}; - -/* - * crng_init = 0 --> Uninitialized - * 1 --> Initialized - * 2 --> Initialized from input_pool - * - * crng_init is protected by primary_crng->lock, and only increases - * its value (from 0->1->2). - */ -static int crng_init = 0; -#define crng_ready() (likely(crng_init > 0)) -static int crng_init_cnt = 0; -#define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE) -static void _extract_crng(struct crng_state *crng, - __u8 out[CHACHA20_BLOCK_SIZE]); -static void _crng_backtrack_protect(struct crng_state *crng, - __u8 tmp[CHACHA20_BLOCK_SIZE], int used); -static void process_random_ready_list(void); - -/********************************************************************** - * - * OS independent entropy store. Here are the functions which handle - * storing entropy in an entropy pool. - * - **********************************************************************/ - -struct entropy_store; -struct entropy_store { - /* read-only data: */ - const struct poolinfo *poolinfo; - __u32 *pool; - const char *name; - struct entropy_store *pull; - struct work_struct push_work; - - /* read-write data: */ - unsigned long last_pulled; - spinlock_t lock; - unsigned short add_ptr; - unsigned short input_rotate; - int entropy_count; - int entropy_total; - unsigned int initialized:1; - unsigned int limit:1; - unsigned int last_data_init:1; - __u8 last_data[EXTRACT_SIZE]; -}; - -static ssize_t extract_entropy(struct entropy_store *r, void *buf, - size_t nbytes, int min, int rsvd); -static ssize_t _extract_entropy(struct entropy_store *r, void *buf, - size_t nbytes, int fips); - -static void crng_reseed(struct crng_state *crng, struct entropy_store *r); -static void push_to_pool(struct work_struct *work); -static __u32 input_pool_data[INPUT_POOL_WORDS] __latent_entropy; -static __u32 blocking_pool_data[OUTPUT_POOL_WORDS] __latent_entropy; - -static struct entropy_store input_pool = { - .poolinfo = &poolinfo_table[0], - .name = "input", - .limit = 1, - .lock = __SPIN_LOCK_UNLOCKED(input_pool.lock), - .pool = input_pool_data -}; - -static struct entropy_store blocking_pool = { - .poolinfo = &poolinfo_table[1], - .name = "blocking", - .limit = 1, - .pull = &input_pool, - .lock = __SPIN_LOCK_UNLOCKED(blocking_pool.lock), - .pool = blocking_pool_data, - .push_work = __WORK_INITIALIZER(blocking_pool.push_work, - push_to_pool), -}; - -static __u32 const twist_table[8] = { - 0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158, - 0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278 }; - -/* - * This function adds bytes into the entropy "pool". It does not - * update the entropy estimate. The caller should call - * credit_entropy_bits if this is appropriate. - * - * The pool is stirred with a primitive polynomial of the appropriate - * degree, and then twisted. We twist by three bits at a time because - * it's cheap to do so and helps slightly in the expected case where - * the entropy is concentrated in the low-order bits. - */ -static void _mix_pool_bytes(struct entropy_store *r, const void *in, - int nbytes) -{ - unsigned long i, tap1, tap2, tap3, tap4, tap5; - int input_rotate; - int wordmask = r->poolinfo->poolwords - 1; - const char *bytes = in; - __u32 w; - - tap1 = r->poolinfo->tap1; - tap2 = r->poolinfo->tap2; - tap3 = r->poolinfo->tap3; - tap4 = r->poolinfo->tap4; - tap5 = r->poolinfo->tap5; - - input_rotate = r->input_rotate; - i = r->add_ptr; - - /* mix one byte at a time to simplify size handling and churn faster */ - while (nbytes--) { - w = rol32(*bytes++, input_rotate); - i = (i - 1) & wordmask; - - /* XOR in the various taps */ - w ^= r->pool[i]; - w ^= r->pool[(i + tap1) & wordmask]; - w ^= r->pool[(i + tap2) & wordmask]; - w ^= r->pool[(i + tap3) & wordmask]; - w ^= r->pool[(i + tap4) & wordmask]; - w ^= r->pool[(i + tap5) & wordmask]; - - /* Mix the result back in with a twist */ - r->pool[i] = (w >> 3) ^ twist_table[w & 7]; - - /* - * Normally, we add 7 bits of rotation to the pool. - * At the beginning of the pool, add an extra 7 bits - * rotation, so that successive passes spread the - * input bits across the pool evenly. - */ - input_rotate = (input_rotate + (i ? 7 : 14)) & 31; - } - - r->input_rotate = input_rotate; - r->add_ptr = i; -} - -static void __mix_pool_bytes(struct entropy_store *r, const void *in, - int nbytes) -{ - trace_mix_pool_bytes_nolock(r->name, nbytes, _RET_IP_); - _mix_pool_bytes(r, in, nbytes); -} - -static void mix_pool_bytes(struct entropy_store *r, const void *in, - int nbytes) -{ - unsigned long flags; - - trace_mix_pool_bytes(r->name, nbytes, _RET_IP_); - spin_lock_irqsave(&r->lock, flags); - _mix_pool_bytes(r, in, nbytes); - spin_unlock_irqrestore(&r->lock, flags); -} - -struct fast_pool { - __u32 pool[4]; - unsigned long last; - unsigned short reg_idx; - unsigned char count; -}; - -/* - * This is a fast mixing routine used by the interrupt randomness - * collector. It's hardcoded for an 128 bit pool and assumes that any - * locks that might be needed are taken by the caller. - */ -static void fast_mix(struct fast_pool *f) -{ - __u32 a = f->pool[0], b = f->pool[1]; - __u32 c = f->pool[2], d = f->pool[3]; - - a += b; c += d; - b = rol32(b, 6); d = rol32(d, 27); - d ^= a; b ^= c; - - a += b; c += d; - b = rol32(b, 16); d = rol32(d, 14); - d ^= a; b ^= c; - - a += b; c += d; - b = rol32(b, 6); d = rol32(d, 27); - d ^= a; b ^= c; - - a += b; c += d; - b = rol32(b, 16); d = rol32(d, 14); - d ^= a; b ^= c; - - f->pool[0] = a; f->pool[1] = b; - f->pool[2] = c; f->pool[3] = d; - f->count++; -} - -static void process_random_ready_list(void) -{ - unsigned long flags; - struct random_ready_callback *rdy, *tmp; - - spin_lock_irqsave(&random_ready_list_lock, flags); - list_for_each_entry_safe(rdy, tmp, &random_ready_list, list) { - struct module *owner = rdy->owner; - - list_del_init(&rdy->list); - rdy->func(rdy); - module_put(owner); - } - spin_unlock_irqrestore(&random_ready_list_lock, flags); -} - -/* - * Credit (or debit) the entropy store with n bits of entropy. - * Use credit_entropy_bits_safe() if the value comes from userspace - * or otherwise should be checked for extreme values. - */ -static void credit_entropy_bits(struct entropy_store *r, int nbits) -{ - int entropy_count, orig; - const int pool_size = r->poolinfo->poolfracbits; - int nfrac = nbits << ENTROPY_SHIFT; - - if (!nbits) - return; - -retry: - entropy_count = orig = ACCESS_ONCE(r->entropy_count); - if (nfrac < 0) { - /* Debit */ - entropy_count += nfrac; - } else { - /* - * Credit: we have to account for the possibility of - * overwriting already present entropy. Even in the - * ideal case of pure Shannon entropy, new contributions - * approach the full value asymptotically: - * - * entropy <- entropy + (pool_size - entropy) * - * (1 - exp(-add_entropy/pool_size)) - * - * For add_entropy <= pool_size/2 then - * (1 - exp(-add_entropy/pool_size)) >= - * (add_entropy/pool_size)*0.7869... - * so we can approximate the exponential with - * 3/4*add_entropy/pool_size and still be on the - * safe side by adding at most pool_size/2 at a time. - * - * The use of pool_size-2 in the while statement is to - * prevent rounding artifacts from making the loop - * arbitrarily long; this limits the loop to log2(pool_size)*2 - * turns no matter how large nbits is. - */ - int pnfrac = nfrac; - const int s = r->poolinfo->poolbitshift + ENTROPY_SHIFT + 2; - /* The +2 corresponds to the /4 in the denominator */ - - do { - unsigned int anfrac = min(pnfrac, pool_size/2); - unsigned int add = - ((pool_size - entropy_count)*anfrac*3) >> s; - - entropy_count += add; - pnfrac -= anfrac; - } while (unlikely(entropy_count < pool_size-2 && pnfrac)); - } - - if (unlikely(entropy_count < 0)) { - pr_warn("random: negative entropy/overflow: pool %s count %d\n", - r->name, entropy_count); - WARN_ON(1); - entropy_count = 0; - } else if (entropy_count > pool_size) - entropy_count = pool_size; - if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) - goto retry; - - r->entropy_total += nbits; - if (!r->initialized && r->entropy_total > 128) { - r->initialized = 1; - r->entropy_total = 0; - } - - trace_credit_entropy_bits(r->name, nbits, - entropy_count >> ENTROPY_SHIFT, - r->entropy_total, _RET_IP_); - - if (r == &input_pool) { - int entropy_bits = entropy_count >> ENTROPY_SHIFT; - - if (crng_init < 2 && entropy_bits >= 128) { - crng_reseed(&primary_crng, r); - entropy_bits = r->entropy_count >> ENTROPY_SHIFT; - } - - /* should we wake readers? */ - if (entropy_bits >= random_read_wakeup_bits) { - wake_up_interruptible(&random_read_wait); - kill_fasync(&fasync, SIGIO, POLL_IN); - } - /* If the input pool is getting full, send some - * entropy to the blocking pool until it is 75% full. - */ - if (entropy_bits > random_write_wakeup_bits && - r->initialized && - r->entropy_total >= 2*random_read_wakeup_bits) { - struct entropy_store *other = &blocking_pool; - - if (other->entropy_count <= - 3 * other->poolinfo->poolfracbits / 4) { - schedule_work(&other->push_work); - r->entropy_total = 0; - } - } - } -} - -static int credit_entropy_bits_safe(struct entropy_store *r, int nbits) -{ - const int nbits_max = (int)(~0U >> (ENTROPY_SHIFT + 1)); - - if (nbits < 0) - return -EINVAL; - - /* Cap the value to avoid overflows */ - nbits = min(nbits, nbits_max); - - credit_entropy_bits(r, nbits); - return 0; -} - -/********************************************************************* - * - * CRNG using CHACHA20 - * - *********************************************************************/ - -#define CRNG_RESEED_INTERVAL (300*HZ) - -static DECLARE_WAIT_QUEUE_HEAD(crng_init_wait); - -#ifdef CONFIG_NUMA -/* - * Hack to deal with crazy userspace progams when they are all trying - * to access /dev/urandom in parallel. The programs are almost - * certainly doing something terribly wrong, but we'll work around - * their brain damage. - */ -static struct crng_state **crng_node_pool __read_mostly; -#endif - -static void crng_initialize(struct crng_state *crng) -{ - int i; - unsigned long rv; - - memcpy(&crng->state[0], "expand 32-byte k", 16); - if (crng == &primary_crng) - _extract_entropy(&input_pool, &crng->state[4], - sizeof(__u32) * 12, 0); - else - get_random_bytes(&crng->state[4], sizeof(__u32) * 12); - for (i = 4; i < 16; i++) { - if (!arch_get_random_seed_long(&rv) && - !arch_get_random_long(&rv)) - rv = random_get_entropy(); - crng->state[i] ^= rv; - } - crng->init_time = jiffies - CRNG_RESEED_INTERVAL - 1; -} - -static int crng_fast_load(const char *cp, size_t len) -{ - unsigned long flags; - char *p; - - if (!spin_trylock_irqsave(&primary_crng.lock, flags)) - return 0; - if (crng_ready()) { - spin_unlock_irqrestore(&primary_crng.lock, flags); - return 0; - } - p = (unsigned char *) &primary_crng.state[4]; - while (len > 0 && crng_init_cnt < CRNG_INIT_CNT_THRESH) { - p[crng_init_cnt % CHACHA20_KEY_SIZE] ^= *cp; - cp++; crng_init_cnt++; len--; - } - if (crng_init_cnt >= CRNG_INIT_CNT_THRESH) { - crng_init = 1; - wake_up_interruptible(&crng_init_wait); - pr_notice("random: fast init done\n"); - } - spin_unlock_irqrestore(&primary_crng.lock, flags); - return 1; -} - -static void crng_reseed(struct crng_state *crng, struct entropy_store *r) -{ - unsigned long flags; - int i, num; - union { - __u8 block[CHACHA20_BLOCK_SIZE]; - __u32 key[8]; - } buf; - - if (r) { - num = extract_entropy(r, &buf, 32, 16, 0); - if (num == 0) - return; - } else { - _extract_crng(&primary_crng, buf.block); - _crng_backtrack_protect(&primary_crng, buf.block, - CHACHA20_KEY_SIZE); - } - spin_lock_irqsave(&primary_crng.lock, flags); - for (i = 0; i < 8; i++) { - unsigned long rv; - if (!arch_get_random_seed_long(&rv) && - !arch_get_random_long(&rv)) - rv = random_get_entropy(); - crng->state[i+4] ^= buf.key[i] ^ rv; - } - memzero_explicit(&buf, sizeof(buf)); - crng->init_time = jiffies; - if (crng == &primary_crng && crng_init < 2) { - crng_init = 2; - process_random_ready_list(); - wake_up_interruptible(&crng_init_wait); - pr_notice("random: crng init done\n"); - } - spin_unlock_irqrestore(&primary_crng.lock, flags); -} - -static inline void maybe_reseed_primary_crng(void) -{ - if (crng_init > 2 && - time_after(jiffies, primary_crng.init_time + CRNG_RESEED_INTERVAL)) - crng_reseed(&primary_crng, &input_pool); -} - -static inline void crng_wait_ready(void) -{ - wait_event_interruptible(crng_init_wait, crng_ready()); -} - -static void _extract_crng(struct crng_state *crng, - __u8 out[CHACHA20_BLOCK_SIZE]) -{ - unsigned long v, flags; - - if (crng_init > 1 && - time_after(jiffies, crng->init_time + CRNG_RESEED_INTERVAL)) - crng_reseed(crng, crng == &primary_crng ? &input_pool : NULL); - spin_lock_irqsave(&crng->lock, flags); - if (arch_get_random_long(&v)) - crng->state[14] ^= v; - chacha20_block(&crng->state[0], out); - if (crng->state[12] == 0) - crng->state[13]++; - spin_unlock_irqrestore(&crng->lock, flags); -} - -static void extract_crng(__u8 out[CHACHA20_BLOCK_SIZE]) -{ - struct crng_state *crng = NULL; - -#ifdef CONFIG_NUMA - if (crng_node_pool) - crng = crng_node_pool[numa_node_id()]; - if (crng == NULL) -#endif - crng = &primary_crng; - _extract_crng(crng, out); -} - -/* - * Use the leftover bytes from the CRNG block output (if there is - * enough) to mutate the CRNG key to provide backtracking protection. - */ -static void _crng_backtrack_protect(struct crng_state *crng, - __u8 tmp[CHACHA20_BLOCK_SIZE], int used) -{ - unsigned long flags; - __u32 *s, *d; - int i; - - used = round_up(used, sizeof(__u32)); - if (used + CHACHA20_KEY_SIZE > CHACHA20_BLOCK_SIZE) { - extract_crng(tmp); - used = 0; - } - spin_lock_irqsave(&crng->lock, flags); - s = (__u32 *) &tmp[used]; - d = &crng->state[4]; - for (i=0; i < 8; i++) - *d++ ^= *s++; - spin_unlock_irqrestore(&crng->lock, flags); -} - -static void crng_backtrack_protect(__u8 tmp[CHACHA20_BLOCK_SIZE], int used) -{ - struct crng_state *crng = NULL; - -#ifdef CONFIG_NUMA - if (crng_node_pool) - crng = crng_node_pool[numa_node_id()]; - if (crng == NULL) -#endif - crng = &primary_crng; - _crng_backtrack_protect(crng, tmp, used); -} - -static ssize_t extract_crng_user(void __user *buf, size_t nbytes) -{ - ssize_t ret = 0, i = CHACHA20_BLOCK_SIZE; - __u8 tmp[CHACHA20_BLOCK_SIZE]; - int large_request = (nbytes > 256); - - while (nbytes) { - if (large_request && need_resched()) { - if (signal_pending(current)) { - if (ret == 0) - ret = -ERESTARTSYS; - break; - } - schedule(); - } - - extract_crng(tmp); - i = min_t(int, nbytes, CHACHA20_BLOCK_SIZE); - if (copy_to_user(buf, tmp, i)) { - ret = -EFAULT; - break; - } - - nbytes -= i; - buf += i; - ret += i; - } - crng_backtrack_protect(tmp, i); - - /* Wipe data just written to memory */ - memzero_explicit(tmp, sizeof(tmp)); - - return ret; -} - - -/********************************************************************* - * - * Entropy input management - * - *********************************************************************/ - -/* There is one of these per entropy source */ -struct timer_rand_state { - cycles_t last_time; - long last_delta, last_delta2; - unsigned dont_count_entropy:1; -}; - -#define INIT_TIMER_RAND_STATE { INITIAL_JIFFIES, }; - -/* - * Add device- or boot-specific data to the input pool to help - * initialize it. - * - * None of this adds any entropy; it is meant to avoid the problem of - * the entropy pool having similar initial state across largely - * identical devices. - */ -void add_device_randomness(const void *buf, unsigned int size) -{ - unsigned long time = random_get_entropy() ^ jiffies; - unsigned long flags; - - trace_add_device_randomness(size, _RET_IP_); - spin_lock_irqsave(&input_pool.lock, flags); - _mix_pool_bytes(&input_pool, buf, size); - _mix_pool_bytes(&input_pool, &time, sizeof(time)); - spin_unlock_irqrestore(&input_pool.lock, flags); -} -EXPORT_SYMBOL(add_device_randomness); - -static struct timer_rand_state input_timer_state = INIT_TIMER_RAND_STATE; - -/* - * This function adds entropy to the entropy "pool" by using timing - * delays. It uses the timer_rand_state structure to make an estimate - * of how many bits of entropy this call has added to the pool. - * - * The number "num" is also added to the pool - it should somehow describe - * the type of event which just happened. This is currently 0-255 for - * keyboard scan codes, and 256 upwards for interrupts. - * - */ -static void add_timer_randomness(struct timer_rand_state *state, unsigned num) -{ - struct entropy_store *r; - struct { - long jiffies; - unsigned cycles; - unsigned num; - } sample; - long delta, delta2, delta3; - - preempt_disable(); - - sample.jiffies = jiffies; - sample.cycles = random_get_entropy(); - sample.num = num; - r = &input_pool; - mix_pool_bytes(r, &sample, sizeof(sample)); - - /* - * Calculate number of bits of randomness we probably added. - * We take into account the first, second and third-order deltas - * in order to make our estimate. - */ - - if (!state->dont_count_entropy) { - delta = sample.jiffies - state->last_time; - state->last_time = sample.jiffies; - - delta2 = delta - state->last_delta; - state->last_delta = delta; - - delta3 = delta2 - state->last_delta2; - state->last_delta2 = delta2; - - if (delta < 0) - delta = -delta; - if (delta2 < 0) - delta2 = -delta2; - if (delta3 < 0) - delta3 = -delta3; - if (delta > delta2) - delta = delta2; - if (delta > delta3) - delta = delta3; - - /* - * delta is now minimum absolute delta. - * Round down by 1 bit on general principles, - * and limit entropy entimate to 12 bits. - */ - credit_entropy_bits(r, min_t(int, fls(delta>>1), 11)); - } - preempt_enable(); -} - -void add_input_randomness(unsigned int type, unsigned int code, - unsigned int value) -{ - static unsigned char last_value; - - /* ignore autorepeat and the like */ - if (value == last_value) - return; - - last_value = value; - add_timer_randomness(&input_timer_state, - (type << 4) ^ code ^ (code >> 4) ^ value); - trace_add_input_randomness(ENTROPY_BITS(&input_pool)); -} -EXPORT_SYMBOL_GPL(add_input_randomness); - -static DEFINE_PER_CPU(struct fast_pool, irq_randomness); - -#ifdef ADD_INTERRUPT_BENCH -static unsigned long avg_cycles, avg_deviation; - -#define AVG_SHIFT 8 /* Exponential average factor k=1/256 */ -#define FIXED_1_2 (1 << (AVG_SHIFT-1)) - -static void add_interrupt_bench(cycles_t start) -{ - long delta = random_get_entropy() - start; - - /* Use a weighted moving average */ - delta = delta - ((avg_cycles + FIXED_1_2) >> AVG_SHIFT); - avg_cycles += delta; - /* And average deviation */ - delta = abs(delta) - ((avg_deviation + FIXED_1_2) >> AVG_SHIFT); - avg_deviation += delta; -} -#else -#define add_interrupt_bench(x) -#endif - -static __u32 get_reg(struct fast_pool *f, struct pt_regs *regs) -{ - __u32 *ptr = (__u32 *) regs; - - if (regs == NULL) - return 0; - if (f->reg_idx >= sizeof(struct pt_regs) / sizeof(__u32)) - f->reg_idx = 0; - return *(ptr + f->reg_idx++); -} - -void add_interrupt_randomness(int irq, int irq_flags) -{ - struct entropy_store *r; - struct fast_pool *fast_pool = this_cpu_ptr(&irq_randomness); - struct pt_regs *regs = get_irq_regs(); - unsigned long now = jiffies; - cycles_t cycles = random_get_entropy(); - __u32 c_high, j_high; - __u64 ip; - unsigned long seed; - int credit = 0; - - if (cycles == 0) - cycles = get_reg(fast_pool, regs); - c_high = (sizeof(cycles) > 4) ? cycles >> 32 : 0; - j_high = (sizeof(now) > 4) ? now >> 32 : 0; - fast_pool->pool[0] ^= cycles ^ j_high ^ irq; - fast_pool->pool[1] ^= now ^ c_high; - ip = regs ? instruction_pointer(regs) : _RET_IP_; - fast_pool->pool[2] ^= ip; - fast_pool->pool[3] ^= (sizeof(ip) > 4) ? ip >> 32 : - get_reg(fast_pool, regs); - - fast_mix(fast_pool); - add_interrupt_bench(cycles); - - if (!crng_ready()) { - if ((fast_pool->count >= 64) && - crng_fast_load((char *) fast_pool->pool, - sizeof(fast_pool->pool))) { - fast_pool->count = 0; - fast_pool->last = now; - } - return; - } - - if ((fast_pool->count < 64) && - !time_after(now, fast_pool->last + HZ)) - return; - - r = &input_pool; - if (!spin_trylock(&r->lock)) - return; - - fast_pool->last = now; - __mix_pool_bytes(r, &fast_pool->pool, sizeof(fast_pool->pool)); - - /* - * If we have architectural seed generator, produce a seed and - * add it to the pool. For the sake of paranoia don't let the - * architectural seed generator dominate the input from the - * interrupt noise. - */ - if (arch_get_random_seed_long(&seed)) { - __mix_pool_bytes(r, &seed, sizeof(seed)); - credit = 1; - } - spin_unlock(&r->lock); - - fast_pool->count = 0; - - /* award one bit for the contents of the fast pool */ - credit_entropy_bits(r, credit + 1); -} -EXPORT_SYMBOL_GPL(add_interrupt_randomness); - -#ifdef CONFIG_BLOCK -void add_disk_randomness(struct gendisk *disk) -{ - if (!disk || !disk->random) - return; - /* first major is 1, so we get >= 0x200 here */ - add_timer_randomness(disk->random, 0x100 + disk_devt(disk)); - trace_add_disk_randomness(disk_devt(disk), ENTROPY_BITS(&input_pool)); -} -EXPORT_SYMBOL_GPL(add_disk_randomness); -#endif - -/********************************************************************* - * - * Entropy extraction routines - * - *********************************************************************/ - -/* - * This utility inline function is responsible for transferring entropy - * from the primary pool to the secondary extraction pool. We make - * sure we pull enough for a 'catastrophic reseed'. - */ -static void _xfer_secondary_pool(struct entropy_store *r, size_t nbytes); -static void xfer_secondary_pool(struct entropy_store *r, size_t nbytes) -{ - if (!r->pull || - r->entropy_count >= (nbytes << (ENTROPY_SHIFT + 3)) || - r->entropy_count > r->poolinfo->poolfracbits) - return; - - if (r->limit == 0 && random_min_urandom_seed) { - unsigned long now = jiffies; - - if (time_before(now, - r->last_pulled + random_min_urandom_seed * HZ)) - return; - r->last_pulled = now; - } - - _xfer_secondary_pool(r, nbytes); -} - -static void _xfer_secondary_pool(struct entropy_store *r, size_t nbytes) -{ - __u32 tmp[OUTPUT_POOL_WORDS]; - - /* For /dev/random's pool, always leave two wakeups' worth */ - int rsvd_bytes = r->limit ? 0 : random_read_wakeup_bits / 4; - int bytes = nbytes; - - /* pull at least as much as a wakeup */ - bytes = max_t(int, bytes, random_read_wakeup_bits / 8); - /* but never more than the buffer size */ - bytes = min_t(int, bytes, sizeof(tmp)); - - trace_xfer_secondary_pool(r->name, bytes * 8, nbytes * 8, - ENTROPY_BITS(r), ENTROPY_BITS(r->pull)); - bytes = extract_entropy(r->pull, tmp, bytes, - random_read_wakeup_bits / 8, rsvd_bytes); - mix_pool_bytes(r, tmp, bytes); - credit_entropy_bits(r, bytes*8); -} - -/* - * Used as a workqueue function so that when the input pool is getting - * full, we can "spill over" some entropy to the output pools. That - * way the output pools can store some of the excess entropy instead - * of letting it go to waste. - */ -static void push_to_pool(struct work_struct *work) -{ - struct entropy_store *r = container_of(work, struct entropy_store, - push_work); - BUG_ON(!r); - _xfer_secondary_pool(r, random_read_wakeup_bits/8); - trace_push_to_pool(r->name, r->entropy_count >> ENTROPY_SHIFT, - r->pull->entropy_count >> ENTROPY_SHIFT); -} - -/* - * This function decides how many bytes to actually take from the - * given pool, and also debits the entropy count accordingly. - */ -static size_t account(struct entropy_store *r, size_t nbytes, int min, - int reserved) -{ - int entropy_count, orig; - size_t ibytes, nfrac; - - BUG_ON(r->entropy_count > r->poolinfo->poolfracbits); - - /* Can we pull enough? */ -retry: - entropy_count = orig = ACCESS_ONCE(r->entropy_count); - ibytes = nbytes; - /* If limited, never pull more than available */ - if (r->limit) { - int have_bytes = entropy_count >> (ENTROPY_SHIFT + 3); - - if ((have_bytes -= reserved) < 0) - have_bytes = 0; - ibytes = min_t(size_t, ibytes, have_bytes); - } - if (ibytes < min) - ibytes = 0; - - if (unlikely(entropy_count < 0)) { - pr_warn("random: negative entropy count: pool %s count %d\n", - r->name, entropy_count); - WARN_ON(1); - entropy_count = 0; - } - nfrac = ibytes << (ENTROPY_SHIFT + 3); - if ((size_t) entropy_count > nfrac) - entropy_count -= nfrac; - else - entropy_count = 0; - - if (cmpxchg(&r->entropy_count, orig, entropy_count) != orig) - goto retry; - - trace_debit_entropy(r->name, 8 * ibytes); - if (ibytes && - (r->entropy_count >> ENTROPY_SHIFT) < random_write_wakeup_bits) { - wake_up_interruptible(&random_write_wait); - kill_fasync(&fasync, SIGIO, POLL_OUT); - } - - return ibytes; -} - -/* - * This function does the actual extraction for extract_entropy and - * extract_entropy_user. - * - * Note: we assume that .poolwords is a multiple of 16 words. - */ -static void extract_buf(struct entropy_store *r, __u8 *out) -{ - int i; - union { - __u32 w[5]; - unsigned long l[LONGS(20)]; - } hash; - __u32 workspace[SHA_WORKSPACE_WORDS]; - unsigned long flags; - - /* - * If we have an architectural hardware random number - * generator, use it for SHA's initial vector - */ - sha_init(hash.w); - for (i = 0; i < LONGS(20); i++) { - unsigned long v; - if (!arch_get_random_long(&v)) - break; - hash.l[i] = v; - } - - /* Generate a hash across the pool, 16 words (512 bits) at a time */ - spin_lock_irqsave(&r->lock, flags); - for (i = 0; i < r->poolinfo->poolwords; i += 16) - sha_transform(hash.w, (__u8 *)(r->pool + i), workspace); - - /* - * We mix the hash back into the pool to prevent backtracking - * attacks (where the attacker knows the state of the pool - * plus the current outputs, and attempts to find previous - * ouputs), unless the hash function can be inverted. By - * mixing at least a SHA1 worth of hash data back, we make - * brute-forcing the feedback as hard as brute-forcing the - * hash. - */ - __mix_pool_bytes(r, hash.w, sizeof(hash.w)); - spin_unlock_irqrestore(&r->lock, flags); - - memzero_explicit(workspace, sizeof(workspace)); - - /* - * In case the hash function has some recognizable output - * pattern, we fold it in half. Thus, we always feed back - * twice as much data as we output. - */ - hash.w[0] ^= hash.w[3]; - hash.w[1] ^= hash.w[4]; - hash.w[2] ^= rol32(hash.w[2], 16); - - memcpy(out, &hash, EXTRACT_SIZE); - memzero_explicit(&hash, sizeof(hash)); -} - -static ssize_t _extract_entropy(struct entropy_store *r, void *buf, - size_t nbytes, int fips) -{ - ssize_t ret = 0, i; - __u8 tmp[EXTRACT_SIZE]; - unsigned long flags; - - while (nbytes) { - extract_buf(r, tmp); - - if (fips) { - spin_lock_irqsave(&r->lock, flags); - if (!memcmp(tmp, r->last_data, EXTRACT_SIZE)) - panic("Hardware RNG duplicated output!\n"); - memcpy(r->last_data, tmp, EXTRACT_SIZE); - spin_unlock_irqrestore(&r->lock, flags); - } - i = min_t(int, nbytes, EXTRACT_SIZE); - memcpy(buf, tmp, i); - nbytes -= i; - buf += i; - ret += i; - } - - /* Wipe data just returned from memory */ - memzero_explicit(tmp, sizeof(tmp)); - - return ret; -} - -/* - * This function extracts randomness from the "entropy pool", and - * returns it in a buffer. - * - * The min parameter specifies the minimum amount we can pull before - * failing to avoid races that defeat catastrophic reseeding while the - * reserved parameter indicates how much entropy we must leave in the - * pool after each pull to avoid starving other readers. - */ -static ssize_t extract_entropy(struct entropy_store *r, void *buf, - size_t nbytes, int min, int reserved) -{ - __u8 tmp[EXTRACT_SIZE]; - unsigned long flags; - - /* if last_data isn't primed, we need EXTRACT_SIZE extra bytes */ - if (fips_enabled) { - spin_lock_irqsave(&r->lock, flags); - if (!r->last_data_init) { - r->last_data_init = 1; - spin_unlock_irqrestore(&r->lock, flags); - trace_extract_entropy(r->name, EXTRACT_SIZE, - ENTROPY_BITS(r), _RET_IP_); - xfer_secondary_pool(r, EXTRACT_SIZE); - extract_buf(r, tmp); - spin_lock_irqsave(&r->lock, flags); - memcpy(r->last_data, tmp, EXTRACT_SIZE); - } - spin_unlock_irqrestore(&r->lock, flags); - } - - trace_extract_entropy(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_); - xfer_secondary_pool(r, nbytes); - nbytes = account(r, nbytes, min, reserved); - - return _extract_entropy(r, buf, nbytes, fips_enabled); -} - -/* - * This function extracts randomness from the "entropy pool", and - * returns it in a userspace buffer. - */ -static ssize_t extract_entropy_user(struct entropy_store *r, void __user *buf, - size_t nbytes) -{ - ssize_t ret = 0, i; - __u8 tmp[EXTRACT_SIZE]; - int large_request = (nbytes > 256); - - trace_extract_entropy_user(r->name, nbytes, ENTROPY_BITS(r), _RET_IP_); - xfer_secondary_pool(r, nbytes); - nbytes = account(r, nbytes, 0, 0); - - while (nbytes) { - if (large_request && need_resched()) { - if (signal_pending(current)) { - if (ret == 0) - ret = -ERESTARTSYS; - break; - } - schedule(); - } - - extract_buf(r, tmp); - i = min_t(int, nbytes, EXTRACT_SIZE); - if (copy_to_user(buf, tmp, i)) { - ret = -EFAULT; - break; - } - - nbytes -= i; - buf += i; - ret += i; - } - - /* Wipe data just returned from memory */ - memzero_explicit(tmp, sizeof(tmp)); - - return ret; -} - -/* - * This function is the exported kernel interface. It returns some - * number of good random numbers, suitable for key generation, seeding - * TCP sequence numbers, etc. It does not rely on the hardware random - * number generator. For random bytes direct from the hardware RNG - * (when available), use get_random_bytes_arch(). - */ -void get_random_bytes(void *buf, int nbytes) -{ - __u8 tmp[CHACHA20_BLOCK_SIZE]; - -#if DEBUG_RANDOM_BOOT > 0 - if (!crng_ready()) - printk(KERN_NOTICE "random: %pF get_random_bytes called " - "with crng_init = %d\n", (void *) _RET_IP_, crng_init); -#endif - trace_get_random_bytes(nbytes, _RET_IP_); - - while (nbytes >= CHACHA20_BLOCK_SIZE) { - extract_crng(buf); - buf += CHACHA20_BLOCK_SIZE; - nbytes -= CHACHA20_BLOCK_SIZE; - } - - if (nbytes > 0) { - extract_crng(tmp); - memcpy(buf, tmp, nbytes); - crng_backtrack_protect(tmp, nbytes); - } else - crng_backtrack_protect(tmp, CHACHA20_BLOCK_SIZE); - memzero_explicit(tmp, sizeof(tmp)); -} -EXPORT_SYMBOL(get_random_bytes); - -/* - * Add a callback function that will be invoked when the nonblocking - * pool is initialised. - * - * returns: 0 if callback is successfully added - * -EALREADY if pool is already initialised (callback not called) - * -ENOENT if module for callback is not alive - */ -int add_random_ready_callback(struct random_ready_callback *rdy) -{ - struct module *owner; - unsigned long flags; - int err = -EALREADY; - - if (crng_ready()) - return err; - - owner = rdy->owner; - if (!try_module_get(owner)) - return -ENOENT; - - spin_lock_irqsave(&random_ready_list_lock, flags); - if (crng_ready()) - goto out; - - owner = NULL; - - list_add(&rdy->list, &random_ready_list); - err = 0; - -out: - spin_unlock_irqrestore(&random_ready_list_lock, flags); - - module_put(owner); - - return err; -} -EXPORT_SYMBOL(add_random_ready_callback); - -/* - * Delete a previously registered readiness callback function. - */ -void del_random_ready_callback(struct random_ready_callback *rdy) -{ - unsigned long flags; - struct module *owner = NULL; - - spin_lock_irqsave(&random_ready_list_lock, flags); - if (!list_empty(&rdy->list)) { - list_del_init(&rdy->list); - owner = rdy->owner; - } - spin_unlock_irqrestore(&random_ready_list_lock, flags); - - module_put(owner); -} -EXPORT_SYMBOL(del_random_ready_callback); - -/* - * This function will use the architecture-specific hardware random - * number generator if it is available. The arch-specific hw RNG will - * almost certainly be faster than what we can do in software, but it - * is impossible to verify that it is implemented securely (as - * opposed, to, say, the AES encryption of a sequence number using a - * key known by the NSA). So it's useful if we need the speed, but - * only if we're willing to trust the hardware manufacturer not to - * have put in a back door. - */ -void get_random_bytes_arch(void *buf, int nbytes) -{ - char *p = buf; - - trace_get_random_bytes_arch(nbytes, _RET_IP_); - while (nbytes) { - unsigned long v; - int chunk = min(nbytes, (int)sizeof(unsigned long)); - - if (!arch_get_random_long(&v)) - break; - - memcpy(p, &v, chunk); - p += chunk; - nbytes -= chunk; - } - - if (nbytes) - get_random_bytes(p, nbytes); -} -EXPORT_SYMBOL(get_random_bytes_arch); - - -/* - * init_std_data - initialize pool with system data - * - * @r: pool to initialize - * - * This function clears the pool's entropy count and mixes some system - * data into the pool to prepare it for use. The pool is not cleared - * as that can only decrease the entropy in the pool. - */ -static void init_std_data(struct entropy_store *r) -{ - int i; - ktime_t now = ktime_get_real(); - unsigned long rv; - - r->last_pulled = jiffies; - mix_pool_bytes(r, &now, sizeof(now)); - for (i = r->poolinfo->poolbytes; i > 0; i -= sizeof(rv)) { - if (!arch_get_random_seed_long(&rv) && - !arch_get_random_long(&rv)) - rv = random_get_entropy(); - mix_pool_bytes(r, &rv, sizeof(rv)); - } - mix_pool_bytes(r, utsname(), sizeof(*(utsname()))); -} - -/* - * Note that setup_arch() may call add_device_randomness() - * long before we get here. This allows seeding of the pools - * with some platform dependent data very early in the boot - * process. But it limits our options here. We must use - * statically allocated structures that already have all - * initializations complete at compile time. We should also - * take care not to overwrite the precious per platform data - * we were given. - */ -static int rand_initialize(void) -{ -#ifdef CONFIG_NUMA - int i; - struct crng_state *crng; - struct crng_state **pool; -#endif - - init_std_data(&input_pool); - init_std_data(&blocking_pool); - crng_initialize(&primary_crng); - -#ifdef CONFIG_NUMA - pool = kcalloc(nr_node_ids, sizeof(*pool), GFP_KERNEL|__GFP_NOFAIL); - for_each_online_node(i) { - crng = kmalloc_node(sizeof(struct crng_state), - GFP_KERNEL | __GFP_NOFAIL, i); - spin_lock_init(&crng->lock); - crng_initialize(crng); - pool[i] = crng; - } - mb(); - crng_node_pool = pool; -#endif - return 0; -} -early_initcall(rand_initialize); - -#ifdef CONFIG_BLOCK -void rand_initialize_disk(struct gendisk *disk) -{ - struct timer_rand_state *state; - - /* - * If kzalloc returns null, we just won't use that entropy - * source. - */ - state = kzalloc(sizeof(struct timer_rand_state), GFP_KERNEL); - if (state) { - state->last_time = INITIAL_JIFFIES; - disk->random = state; - } -} -#endif - -static ssize_t -_random_read(int nonblock, char __user *buf, size_t nbytes) -{ - ssize_t n; - - if (nbytes == 0) - return 0; - - nbytes = min_t(size_t, nbytes, SEC_XFER_SIZE); - while (1) { - n = extract_entropy_user(&blocking_pool, buf, nbytes); - if (n < 0) - return n; - trace_random_read(n*8, (nbytes-n)*8, - ENTROPY_BITS(&blocking_pool), - ENTROPY_BITS(&input_pool)); - if (n > 0) - return n; - - /* Pool is (near) empty. Maybe wait and retry. */ - if (nonblock) - return -EAGAIN; - - wait_event_interruptible(random_read_wait, - ENTROPY_BITS(&input_pool) >= - random_read_wakeup_bits); - if (signal_pending(current)) - return -ERESTARTSYS; - } -} - -static ssize_t -random_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) -{ - return _random_read(file->f_flags & O_NONBLOCK, buf, nbytes); -} - -static ssize_t -urandom_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos) -{ - unsigned long flags; - static int maxwarn = 10; - int ret; - - if (!crng_ready() && maxwarn > 0) { - maxwarn--; - printk(KERN_NOTICE "random: %s: uninitialized urandom read " - "(%zd bytes read)\n", - current->comm, nbytes); - spin_lock_irqsave(&primary_crng.lock, flags); - crng_init_cnt = 0; - spin_unlock_irqrestore(&primary_crng.lock, flags); - } - nbytes = min_t(size_t, nbytes, INT_MAX >> (ENTROPY_SHIFT + 3)); - ret = extract_crng_user(buf, nbytes); - trace_urandom_read(8 * nbytes, 0, ENTROPY_BITS(&input_pool)); - return ret; -} - -static unsigned int -random_poll(struct file *file, poll_table * wait) -{ - unsigned int mask; - - poll_wait(file, &random_read_wait, wait); - poll_wait(file, &random_write_wait, wait); - mask = 0; - if (ENTROPY_BITS(&input_pool) >= random_read_wakeup_bits) - mask |= POLLIN | POLLRDNORM; - if (ENTROPY_BITS(&input_pool) < random_write_wakeup_bits) - mask |= POLLOUT | POLLWRNORM; - return mask; -} - -static int -write_pool(struct entropy_store *r, const char __user *buffer, size_t count) -{ - size_t bytes; - __u32 buf[16]; - const char __user *p = buffer; - - while (count > 0) { - bytes = min(count, sizeof(buf)); - if (copy_from_user(&buf, p, bytes)) - return -EFAULT; - - count -= bytes; - p += bytes; - - mix_pool_bytes(r, buf, bytes); - cond_resched(); - } - - return 0; -} - -static ssize_t random_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) -{ - size_t ret; - - ret = write_pool(&input_pool, buffer, count); - if (ret) - return ret; - - return (ssize_t)count; -} - -static long random_ioctl(struct file *f, unsigned int cmd, unsigned long arg) -{ - int size, ent_count; - int __user *p = (int __user *)arg; - int retval; - - switch (cmd) { - case RNDGETENTCNT: - /* inherently racy, no point locking */ - ent_count = ENTROPY_BITS(&input_pool); - if (put_user(ent_count, p)) - return -EFAULT; - return 0; - case RNDADDTOENTCNT: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (get_user(ent_count, p)) - return -EFAULT; - return credit_entropy_bits_safe(&input_pool, ent_count); - case RNDADDENTROPY: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (get_user(ent_count, p++)) - return -EFAULT; - if (ent_count < 0) - return -EINVAL; - if (get_user(size, p++)) - return -EFAULT; - retval = write_pool(&input_pool, (const char __user *)p, - size); - if (retval < 0) - return retval; - return credit_entropy_bits_safe(&input_pool, ent_count); - case RNDZAPENTCNT: - case RNDCLEARPOOL: - /* - * Clear the entropy pool counters. We no longer clear - * the entropy pool, as that's silly. - */ - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - input_pool.entropy_count = 0; - blocking_pool.entropy_count = 0; - return 0; - default: - return -EINVAL; - } -} - -static int random_fasync(int fd, struct file *filp, int on) -{ - return fasync_helper(fd, filp, on, &fasync); -} - -const struct file_operations random_fops = { - .read = random_read, - .write = random_write, - .poll = random_poll, - .unlocked_ioctl = random_ioctl, - .fasync = random_fasync, - .llseek = noop_llseek, -}; - -const struct file_operations urandom_fops = { - .read = urandom_read, - .write = random_write, - .unlocked_ioctl = random_ioctl, - .fasync = random_fasync, - .llseek = noop_llseek, -}; - -SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count, - unsigned int, flags) -{ - if (flags & ~(GRND_NONBLOCK|GRND_RANDOM)) - return -EINVAL; - - if (count > INT_MAX) - count = INT_MAX; - - if (flags & GRND_RANDOM) - return _random_read(flags & GRND_NONBLOCK, buf, count); - - if (!crng_ready()) { - if (flags & GRND_NONBLOCK) - return -EAGAIN; - crng_wait_ready(); - if (signal_pending(current)) - return -ERESTARTSYS; - } - return urandom_read(NULL, buf, count, NULL); -} - -/******************************************************************** - * - * Sysctl interface - * - ********************************************************************/ - -#ifdef CONFIG_SYSCTL - -#include - -static int min_read_thresh = 8, min_write_thresh; -static int max_read_thresh = OUTPUT_POOL_WORDS * 32; -static int max_write_thresh = INPUT_POOL_WORDS * 32; -static char sysctl_bootid[16]; - -/* - * This function is used to return both the bootid UUID, and random - * UUID. The difference is in whether table->data is NULL; if it is, - * then a new UUID is generated and returned to the user. - * - * If the user accesses this via the proc interface, the UUID will be - * returned as an ASCII string in the standard UUID format; if via the - * sysctl system call, as 16 bytes of binary data. - */ -static int proc_do_uuid(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - struct ctl_table fake_table; - unsigned char buf[64], tmp_uuid[16], *uuid; - - uuid = table->data; - if (!uuid) { - uuid = tmp_uuid; - generate_random_uuid(uuid); - } else { - static DEFINE_SPINLOCK(bootid_spinlock); - - spin_lock(&bootid_spinlock); - if (!uuid[8]) - generate_random_uuid(uuid); - spin_unlock(&bootid_spinlock); - } - - sprintf(buf, "%pU", uuid); - - fake_table.data = buf; - fake_table.maxlen = sizeof(buf); - - return proc_dostring(&fake_table, write, buffer, lenp, ppos); -} - -/* - * Return entropy available scaled to integral bits - */ -static int proc_do_entropy(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - struct ctl_table fake_table; - int entropy_count; - - entropy_count = *(int *)table->data >> ENTROPY_SHIFT; - - fake_table.data = &entropy_count; - fake_table.maxlen = sizeof(entropy_count); - - return proc_dointvec(&fake_table, write, buffer, lenp, ppos); -} - -static int sysctl_poolsize = INPUT_POOL_WORDS * 32; -extern struct ctl_table random_table[]; -struct ctl_table random_table[] = { - { - .procname = "poolsize", - .data = &sysctl_poolsize, - .maxlen = sizeof(int), - .mode = 0444, - .proc_handler = proc_dointvec, - }, - { - .procname = "entropy_avail", - .maxlen = sizeof(int), - .mode = 0444, - .proc_handler = proc_do_entropy, - .data = &input_pool.entropy_count, - }, - { - .procname = "read_wakeup_threshold", - .data = &random_read_wakeup_bits, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_read_thresh, - .extra2 = &max_read_thresh, - }, - { - .procname = "write_wakeup_threshold", - .data = &random_write_wakeup_bits, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_write_thresh, - .extra2 = &max_write_thresh, - }, - { - .procname = "urandom_min_reseed_secs", - .data = &random_min_urandom_seed, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "boot_id", - .data = &sysctl_bootid, - .maxlen = 16, - .mode = 0444, - .proc_handler = proc_do_uuid, - }, - { - .procname = "uuid", - .maxlen = 16, - .mode = 0444, - .proc_handler = proc_do_uuid, - }, -#ifdef ADD_INTERRUPT_BENCH - { - .procname = "add_interrupt_avg_cycles", - .data = &avg_cycles, - .maxlen = sizeof(avg_cycles), - .mode = 0444, - .proc_handler = proc_doulongvec_minmax, - }, - { - .procname = "add_interrupt_avg_deviation", - .data = &avg_deviation, - .maxlen = sizeof(avg_deviation), - .mode = 0444, - .proc_handler = proc_doulongvec_minmax, - }, -#endif - { } -}; -#endif /* CONFIG_SYSCTL */ - -static u32 random_int_secret[MD5_MESSAGE_BYTES / 4] ____cacheline_aligned; - -int random_int_secret_init(void) -{ - get_random_bytes(random_int_secret, sizeof(random_int_secret)); - return 0; -} - -static DEFINE_PER_CPU(__u32 [MD5_DIGEST_WORDS], get_random_int_hash) - __aligned(sizeof(unsigned long)); - -/* - * Get a random word for internal kernel use only. Similar to urandom but - * with the goal of minimal entropy pool depletion. As a result, the random - * value is not cryptographically secure but for several uses the cost of - * depleting entropy is too high - */ -unsigned int get_random_int(void) -{ - __u32 *hash; - unsigned int ret; - - if (arch_get_random_int(&ret)) - return ret; - - hash = get_cpu_var(get_random_int_hash); - - hash[0] += current->pid + jiffies + random_get_entropy(); - md5_transform(hash, random_int_secret); - ret = hash[0]; - put_cpu_var(get_random_int_hash); - - return ret; -} -EXPORT_SYMBOL(get_random_int); - -/* - * Same as get_random_int(), but returns unsigned long. - */ -unsigned long get_random_long(void) -{ - __u32 *hash; - unsigned long ret; - - if (arch_get_random_long(&ret)) - return ret; - - hash = get_cpu_var(get_random_int_hash); - - hash[0] += current->pid + jiffies + random_get_entropy(); - md5_transform(hash, random_int_secret); - ret = *(unsigned long *)hash; - put_cpu_var(get_random_int_hash); - - return ret; -} -EXPORT_SYMBOL(get_random_long); - -/** - * randomize_page - Generate a random, page aligned address - * @start: The smallest acceptable address the caller will take. - * @range: The size of the area, starting at @start, within which the - * random address must fall. - * - * If @start + @range would overflow, @range is capped. - * - * NOTE: Historical use of randomize_range, which this replaces, presumed that - * @start was already page aligned. We now align it regardless. - * - * Return: A page aligned address within [start, start + range). On error, - * @start is returned. - */ -unsigned long -randomize_page(unsigned long start, unsigned long range) -{ - if (!PAGE_ALIGNED(start)) { - range -= PAGE_ALIGN(start) - start; - start = PAGE_ALIGN(start); - } - - if (start > ULONG_MAX - range) - range = ULONG_MAX - start; - - range >>= PAGE_SHIFT; - - if (range == 0) - return start; - - return start + (get_random_long() % range << PAGE_SHIFT); -} - -/* Interface for in-kernel drivers of true hardware RNGs. - * Those devices may produce endless random bits and will be throttled - * when our pool is full. - */ -void add_hwgenerator_randomness(const char *buffer, size_t count, - size_t entropy) -{ - struct entropy_store *poolp = &input_pool; - - if (!crng_ready()) { - crng_fast_load(buffer, count); - return; - } - - /* Suspend writing if we're above the trickle threshold. - * We'll be woken up again once below random_write_wakeup_thresh, - * or when the calling thread is about to terminate. - */ - wait_event_interruptible(random_write_wait, kthread_should_stop() || - ENTROPY_BITS(&input_pool) <= random_write_wakeup_bits); - mix_pool_bytes(poolp, buffer, count); - credit_entropy_bits(poolp, entropy); -} -EXPORT_SYMBOL_GPL(add_hwgenerator_randomness); diff --git a/src/linux/drivers/char/tpm/Kconfig b/src/linux/drivers/char/tpm/Kconfig deleted file mode 100644 index 9faa0b1..0000000 --- a/src/linux/drivers/char/tpm/Kconfig +++ /dev/null @@ -1,156 +0,0 @@ -# -# TPM device configuration -# - -menuconfig TCG_TPM - tristate "TPM Hardware Support" - depends on HAS_IOMEM - select SECURITYFS - ---help--- - If you have a TPM security chip in your system, which - implements the Trusted Computing Group's specification, - say Yes and it will be accessible from within Linux. For - more information see . - An implementation of the Trusted Software Stack (TSS), the - userspace enablement piece of the specification, can be - obtained at: . To - compile this driver as a module, choose M here; the module - will be called tpm. If unsure, say N. - Notes: - 1) For more TPM drivers enable CONFIG_PNP, CONFIG_ACPI - and CONFIG_PNPACPI. - 2) Without ACPI enabled, the BIOS event log won't be accessible, - which is required to validate the PCR 0-7 values. - -if TCG_TPM - -config TCG_TIS_CORE - tristate - ---help--- - TCG TIS TPM core driver. It implements the TPM TCG TIS logic and hooks - into the TPM kernel APIs. Physical layers will register against it. - -config TCG_TIS - tristate "TPM Interface Specification 1.2 Interface / TPM 2.0 FIFO Interface" - depends on X86 - select TCG_TIS_CORE - ---help--- - If you have a TPM security chip that is compliant with the - TCG TIS 1.2 TPM specification (TPM1.2) or the TCG PTP FIFO - specification (TPM2.0) say Yes and it will be accessible from - within Linux. To compile this driver as a module, choose M here; - the module will be called tpm_tis. - -config TCG_TIS_SPI - tristate "TPM Interface Specification 1.3 Interface / TPM 2.0 FIFO Interface - (SPI)" - depends on SPI - select TCG_TIS_CORE - ---help--- - If you have a TPM security chip which is connected to a regular, - non-tcg SPI master (i.e. most embedded platforms) that is compliant with the - TCG TIS 1.3 TPM specification (TPM1.2) or the TCG PTP FIFO - specification (TPM2.0) say Yes and it will be accessible from - within Linux. To compile this driver as a module, choose M here; - the module will be called tpm_tis_spi. - -config TCG_TIS_I2C_ATMEL - tristate "TPM Interface Specification 1.2 Interface (I2C - Atmel)" - depends on I2C - ---help--- - If you have an Atmel I2C TPM security chip say Yes and it will be - accessible from within Linux. - To compile this driver as a module, choose M here; the module will - be called tpm_tis_i2c_atmel. - -config TCG_TIS_I2C_INFINEON - tristate "TPM Interface Specification 1.2 Interface (I2C - Infineon)" - depends on I2C - ---help--- - If you have a TPM security chip that is compliant with the - TCG TIS 1.2 TPM specification and Infineon's I2C Protocol Stack - Specification 0.20 say Yes and it will be accessible from within - Linux. - To compile this driver as a module, choose M here; the module - will be called tpm_i2c_infineon. - -config TCG_TIS_I2C_NUVOTON - tristate "TPM Interface Specification 1.2 Interface (I2C - Nuvoton)" - depends on I2C - ---help--- - If you have a TPM security chip with an I2C interface from - Nuvoton Technology Corp. say Yes and it will be accessible - from within Linux. - To compile this driver as a module, choose M here; the module - will be called tpm_i2c_nuvoton. - -config TCG_NSC - tristate "National Semiconductor TPM Interface" - depends on X86 - ---help--- - If you have a TPM security chip from National Semiconductor - say Yes and it will be accessible from within Linux. To - compile this driver as a module, choose M here; the module - will be called tpm_nsc. - -config TCG_ATMEL - tristate "Atmel TPM Interface" - depends on PPC64 || HAS_IOPORT_MAP - ---help--- - If you have a TPM security chip from Atmel say Yes and it - will be accessible from within Linux. To compile this driver - as a module, choose M here; the module will be called tpm_atmel. - -config TCG_INFINEON - tristate "Infineon Technologies TPM Interface" - depends on PNP - ---help--- - If you have a TPM security chip from Infineon Technologies - (either SLD 9630 TT 1.1 or SLB 9635 TT 1.2) say Yes and it - will be accessible from within Linux. - To compile this driver as a module, choose M here; the module - will be called tpm_infineon. - Further information on this driver and the supported hardware - can be found at http://www.trust.rub.de/projects/linux-device-driver-infineon-tpm/ - -config TCG_IBMVTPM - tristate "IBM VTPM Interface" - depends on PPC_PSERIES - ---help--- - If you have IBM virtual TPM (VTPM) support say Yes and it - will be accessible from within Linux. To compile this driver - as a module, choose M here; the module will be called tpm_ibmvtpm. - -config TCG_XEN - tristate "XEN TPM Interface" - depends on TCG_TPM && XEN - select XEN_XENBUS_FRONTEND - ---help--- - If you want to make TPM support available to a Xen user domain, - say Yes and it will be accessible from within Linux. See - the manpages for xl, xl.conf, and docs/misc/vtpm.txt in - the Xen source repository for more details. - To compile this driver as a module, choose M here; the module - will be called xen-tpmfront. - -config TCG_CRB - tristate "TPM 2.0 CRB Interface" - depends on X86 && ACPI - ---help--- - If you have a TPM security chip that is compliant with the - TCG CRB 2.0 TPM specification say Yes and it will be accessible - from within Linux. To compile this driver as a module, choose - M here; the module will be called tpm_crb. - -config TCG_VTPM_PROXY - tristate "VTPM Proxy Interface" - depends on TCG_TPM - select ANON_INODES - ---help--- - This driver proxies for an emulated TPM (vTPM) running in userspace. - A device /dev/vtpmx is provided that creates a device pair - /dev/vtpmX and a server-side file descriptor on which the vTPM - can receive commands. - - -source "drivers/char/tpm/st33zp24/Kconfig" -endif # TCG_TPM diff --git a/src/linux/drivers/char/tpm/st33zp24/Kconfig b/src/linux/drivers/char/tpm/st33zp24/Kconfig deleted file mode 100644 index e74c6f2..0000000 --- a/src/linux/drivers/char/tpm/st33zp24/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -config TCG_TIS_ST33ZP24 - tristate - ---help--- - STMicroelectronics ST33ZP24 core driver. It implements the core - TPM1.2 logic and hooks into the TPM kernel APIs. Physical layers will - register against it. - - To compile this driver as a module, choose m here. The module will be called - tpm_st33zp24. - -config TCG_TIS_ST33ZP24_I2C - tristate "STMicroelectronics TPM Interface Specification 1.2 Interface (I2C)" - depends on I2C - select TCG_TIS_ST33ZP24 - ---help--- - This module adds support for the STMicroelectronics TPM security chip - ST33ZP24 with i2c interface. - To compile this driver as a module, choose M here; the module will be - called tpm_st33zp24_i2c. - -config TCG_TIS_ST33ZP24_SPI - tristate "STMicroelectronics TPM Interface Specification 1.2 Interface (SPI)" - depends on SPI - select TCG_TIS_ST33ZP24 - ---help--- - This module adds support for the STMicroelectronics TPM security chip - ST33ZP24 with spi interface. - To compile this driver as a module, choose M here; the module will be - called tpm_st33zp24_spi. diff --git a/src/linux/drivers/char/xillybus/Kconfig b/src/linux/drivers/char/xillybus/Kconfig deleted file mode 100644 index b302684..0000000 --- a/src/linux/drivers/char/xillybus/Kconfig +++ /dev/null @@ -1,33 +0,0 @@ -# -# Xillybus devices -# - -config XILLYBUS - tristate "Xillybus generic FPGA interface" - depends on PCI || (OF_ADDRESS && OF_IRQ) - select CRC32 - help - Xillybus is a generic interface for peripherals designed on - programmable logic (FPGA). The driver probes the hardware for - its capabilities, and creates device files accordingly. - - If unsure, say N. - -if XILLYBUS - -config XILLYBUS_PCIE - tristate "Xillybus over PCIe" - depends on PCI_MSI - help - Set to M if you want Xillybus to use PCI Express for communicating - with the FPGA. - -config XILLYBUS_OF - tristate "Xillybus over Device Tree" - depends on OF_ADDRESS && OF_IRQ && HAS_DMA - help - Set to M if you want Xillybus to find its resources from the - Open Firmware Flattened Device Tree. If the target is an embedded - system, say M. - -endif # if XILLYBUS diff --git a/src/linux/drivers/clk/Kconfig b/src/linux/drivers/clk/Kconfig deleted file mode 100644 index 6a8ac04..0000000 --- a/src/linux/drivers/clk/Kconfig +++ /dev/null @@ -1,214 +0,0 @@ - -config CLKDEV_LOOKUP - bool - select HAVE_CLK - -config HAVE_CLK_PREPARE - bool - -config COMMON_CLK - bool - select HAVE_CLK_PREPARE - select CLKDEV_LOOKUP - select SRCU - select RATIONAL - ---help--- - The common clock framework is a single definition of struct - clk, useful across many platforms, as well as an - implementation of the clock API in include/linux/clk.h. - Architectures utilizing the common struct clk should select - this option. - -menu "Common Clock Framework" - depends on COMMON_CLK - -config COMMON_CLK_WM831X - tristate "Clock driver for WM831x/2x PMICs" - depends on MFD_WM831X - ---help--- - Supports the clocking subsystem of the WM831x/2x series of - PMICs from Wolfson Microelectronics. - -source "drivers/clk/versatile/Kconfig" - -config COMMON_CLK_MAX77686 - tristate "Clock driver for Maxim 77620/77686/77802 MFD" - depends on MFD_MAX77686 || MFD_MAX77620 - ---help--- - This driver supports Maxim 77620/77686/77802 crystal oscillator - clock. - -config COMMON_CLK_RK808 - tristate "Clock driver for RK808/RK818" - depends on MFD_RK808 - ---help--- - This driver supports RK808 and RK818 crystal oscillator clock. These - multi-function devices have two fixed-rate oscillators, - clocked at 32KHz each. Clkout1 is always on, Clkout2 can off - by control register. - -config COMMON_CLK_SCPI - tristate "Clock driver controlled via SCPI interface" - depends on ARM_SCPI_PROTOCOL || COMPILE_TEST - ---help--- - This driver provides support for clocks that are controlled - by firmware that implements the SCPI interface. - - This driver uses SCPI Message Protocol to interact with the - firmware providing all the clock controls. - -config COMMON_CLK_SI5351 - tristate "Clock driver for SiLabs 5351A/B/C" - depends on I2C - select REGMAP_I2C - select RATIONAL - ---help--- - This driver supports Silicon Labs 5351A/B/C programmable clock - generators. - -config COMMON_CLK_SI514 - tristate "Clock driver for SiLabs 514 devices" - depends on I2C - depends on OF - select REGMAP_I2C - help - ---help--- - This driver supports the Silicon Labs 514 programmable clock - generator. - -config COMMON_CLK_SI570 - tristate "Clock driver for SiLabs 570 and compatible devices" - depends on I2C - depends on OF - select REGMAP_I2C - help - ---help--- - This driver supports Silicon Labs 570/571/598/599 programmable - clock generators. - -config COMMON_CLK_CDCE706 - tristate "Clock driver for TI CDCE706 clock synthesizer" - depends on I2C - select REGMAP_I2C - select RATIONAL - ---help--- - This driver supports TI CDCE706 programmable 3-PLL clock synthesizer. - -config COMMON_CLK_CDCE925 - tristate "Clock driver for TI CDCE925 devices" - depends on I2C - depends on OF - select REGMAP_I2C - help - ---help--- - This driver supports the TI CDCE925 programmable clock synthesizer. - The chip contains two PLLs with spread-spectrum clocking support and - five output dividers. The driver only supports the following setup, - and uses a fixed setting for the output muxes. - Y1 is derived from the input clock - Y2 and Y3 derive from PLL1 - Y4 and Y5 derive from PLL2 - Given a target output frequency, the driver will set the PLL and - divider to best approximate the desired output. - -config COMMON_CLK_CS2000_CP - tristate "Clock driver for CS2000 Fractional-N Clock Synthesizer & Clock Multiplier" - depends on I2C - help - If you say yes here you get support for the CS2000 clock multiplier. - -config COMMON_CLK_S2MPS11 - tristate "Clock driver for S2MPS1X/S5M8767 MFD" - depends on MFD_SEC_CORE - ---help--- - This driver supports S2MPS11/S2MPS14/S5M8767 crystal oscillator - clock. These multi-function devices have two (S2MPS14) or three - (S2MPS11, S5M8767) fixed-rate oscillators, clocked at 32KHz each. - -config CLK_TWL6040 - tristate "External McPDM functional clock from twl6040" - depends on TWL6040_CORE - ---help--- - Enable the external functional clock support on OMAP4+ platforms for - McPDM. McPDM module is using the external bit clock on the McPDM bus - as functional clock. - -config COMMON_CLK_AXI_CLKGEN - tristate "AXI clkgen driver" - depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST - help - ---help--- - Support for the Analog Devices axi-clkgen pcore clock generator for Xilinx - FPGAs. It is commonly used in Analog Devices' reference designs. - -config CLK_QORIQ - bool "Clock driver for Freescale QorIQ platforms" - depends on (PPC_E500MC || ARM || ARM64 || COMPILE_TEST) && OF - ---help--- - This adds the clock driver support for Freescale QorIQ platforms - using common clock framework. - -config COMMON_CLK_XGENE - bool "Clock driver for APM XGene SoC" - default y - depends on ARM64 || COMPILE_TEST - ---help--- - Sypport for the APM X-Gene SoC reference, PLL, and device clocks. - -config COMMON_CLK_KEYSTONE - tristate "Clock drivers for Keystone based SOCs" - depends on (ARCH_KEYSTONE || COMPILE_TEST) && OF - ---help--- - Supports clock drivers for Keystone based SOCs. These SOCs have local - a power sleep control module that gate the clock to the IPs and PLLs. - -config COMMON_CLK_NXP - def_bool COMMON_CLK && (ARCH_LPC18XX || ARCH_LPC32XX) - select REGMAP_MMIO if ARCH_LPC32XX - select MFD_SYSCON if ARCH_LPC18XX - ---help--- - Support for clock providers on NXP platforms. - -config COMMON_CLK_PALMAS - tristate "Clock driver for TI Palmas devices" - depends on MFD_PALMAS - ---help--- - This driver supports TI Palmas devices 32KHz output KG and KG_AUDIO - using common clock framework. - -config COMMON_CLK_PWM - tristate "Clock driver for PWMs used as clock outputs" - depends on PWM - ---help--- - Adapter driver so that any PWM output can be (mis)used as clock signal - at 50% duty cycle. - -config COMMON_CLK_PXA - def_bool COMMON_CLK && ARCH_PXA - ---help--- - Support for the Marvell PXA SoC. - -config COMMON_CLK_PIC32 - def_bool COMMON_CLK && MACH_PIC32 - -config COMMON_CLK_OXNAS - bool "Clock driver for the OXNAS SoC Family" - depends on ARCH_OXNAS || COMPILE_TEST - select MFD_SYSCON - ---help--- - Support for the OXNAS SoC Family clocks. - -source "drivers/clk/bcm/Kconfig" -source "drivers/clk/hisilicon/Kconfig" -source "drivers/clk/mediatek/Kconfig" -source "drivers/clk/meson/Kconfig" -source "drivers/clk/mvebu/Kconfig" -source "drivers/clk/qcom/Kconfig" -source "drivers/clk/renesas/Kconfig" -source "drivers/clk/samsung/Kconfig" -source "drivers/clk/sunxi-ng/Kconfig" -source "drivers/clk/tegra/Kconfig" -source "drivers/clk/ti/Kconfig" -source "drivers/clk/uniphier/Kconfig" - -endmenu diff --git a/src/linux/drivers/clk/Makefile b/src/linux/drivers/clk/Makefile deleted file mode 100644 index 925081e..0000000 --- a/src/linux/drivers/clk/Makefile +++ /dev/null @@ -1,92 +0,0 @@ -# common clock types -obj-$(CONFIG_HAVE_CLK) += clk-devres.o -obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o -obj-$(CONFIG_COMMON_CLK) += clk.o -obj-$(CONFIG_COMMON_CLK) += clk-divider.o -obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o -obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o -obj-$(CONFIG_COMMON_CLK) += clk-gate.o -obj-$(CONFIG_COMMON_CLK) += clk-multiplier.o -obj-$(CONFIG_COMMON_CLK) += clk-mux.o -obj-$(CONFIG_COMMON_CLK) += clk-composite.o -obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o -obj-$(CONFIG_COMMON_CLK) += clk-gpio.o -ifeq ($(CONFIG_OF), y) -obj-$(CONFIG_COMMON_CLK) += clk-conf.o -endif - -# hardware specific clock types -# please keep this section sorted lexicographically by file path name -obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o -obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o -obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o -obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o -obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o -obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o -obj-$(CONFIG_COMMON_CLK_CS2000_CP) += clk-cs2000-cp.o -obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o -obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o -obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o -obj-$(CONFIG_ARCH_MB86S7X) += clk-mb86s7x.o -obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o -obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o -obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o -obj-$(CONFIG_COMMON_CLK_OXNAS) += clk-oxnas.o -obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o -obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o -obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o -obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o -obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o -obj-$(CONFIG_COMMON_CLK_SCPI) += clk-scpi.o -obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o -obj-$(CONFIG_COMMON_CLK_SI514) += clk-si514.o -obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o -obj-$(CONFIG_ARCH_STM32) += clk-stm32f4.o -obj-$(CONFIG_ARCH_TANGO) += clk-tango4.o -obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o -obj-$(CONFIG_ARCH_U300) += clk-u300.o -obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o -obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o -obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o - -# please keep this section sorted lexicographically by directory path name -obj-$(CONFIG_COMMON_CLK_AT91) += at91/ -obj-$(CONFIG_ARCH_ARTPEC) += axis/ -obj-$(CONFIG_ARC_PLAT_AXS10X) += axs10x/ -obj-y += bcm/ -obj-$(CONFIG_ARCH_BERLIN) += berlin/ -obj-$(CONFIG_H8300) += h8300/ -obj-$(CONFIG_ARCH_HISI) += hisilicon/ -obj-$(CONFIG_ARCH_MXC) += imx/ -obj-$(CONFIG_MACH_INGENIC) += ingenic/ -obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ -obj-$(CONFIG_MACH_LOONGSON32) += loongson1/ -obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ -obj-$(CONFIG_COMMON_CLK_AMLOGIC) += meson/ -obj-$(CONFIG_MACH_PIC32) += microchip/ -ifeq ($(CONFIG_COMMON_CLK), y) -obj-$(CONFIG_ARCH_MMP) += mmp/ -endif -obj-y += mvebu/ -obj-$(CONFIG_ARCH_MXS) += mxs/ -obj-$(CONFIG_COMMON_CLK_NXP) += nxp/ -obj-$(CONFIG_MACH_PISTACHIO) += pistachio/ -obj-$(CONFIG_COMMON_CLK_PXA) += pxa/ -obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ -obj-$(CONFIG_ARCH_RENESAS) += renesas/ -obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ -obj-$(CONFIG_COMMON_CLK_SAMSUNG) += samsung/ -obj-$(CONFIG_ARCH_SIRF) += sirf/ -obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/ -obj-$(CONFIG_PLAT_SPEAR) += spear/ -obj-$(CONFIG_ARCH_STI) += st/ -obj-$(CONFIG_ARCH_SUNXI) += sunxi/ -obj-$(CONFIG_ARCH_SUNXI) += sunxi-ng/ -obj-$(CONFIG_ARCH_TEGRA) += tegra/ -obj-y += ti/ -obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ -obj-$(CONFIG_ARCH_U8500) += ux500/ -obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/ -obj-$(CONFIG_X86) += x86/ -obj-$(CONFIG_ARCH_ZX) += zte/ -obj-$(CONFIG_ARCH_ZYNQ) += zynq/ diff --git a/src/linux/drivers/clk/bcm/Kconfig b/src/linux/drivers/clk/bcm/Kconfig deleted file mode 100644 index e3eed5a..0000000 --- a/src/linux/drivers/clk/bcm/Kconfig +++ /dev/null @@ -1,54 +0,0 @@ -config CLK_BCM_63XX - bool "Broadcom BCM63xx clock support" - depends on ARCH_BCM_63XX || COMPILE_TEST - depends on COMMON_CLK - select COMMON_CLK_IPROC - default ARCH_BCM_63XX - help - Enable common clock framework support for Broadcom BCM63xx DSL SoCs - based on the ARM architecture - -config CLK_BCM_KONA - bool "Broadcom Kona CCU clock support" - depends on ARCH_BCM_MOBILE || COMPILE_TEST - depends on COMMON_CLK - default y - help - Enable common clock framework support for Broadcom SoCs - using "Kona" style clock control units, including those - in the BCM281xx and BCM21664 families. - -config COMMON_CLK_IPROC - bool "Broadcom iProc clock support" - depends on ARCH_BCM_IPROC || ARCH_BCM_63XX || COMPILE_TEST - depends on COMMON_CLK - default ARCH_BCM_IPROC - help - Enable common clock framework support for Broadcom SoCs - based on the iProc architecture - -if COMMON_CLK_IPROC - -config CLK_BCM_CYGNUS - bool "Broadcom Cygnus clock support" - depends on ARCH_BCM_CYGNUS || COMPILE_TEST - default ARCH_BCM_CYGNUS - help - Enable common clock framework support for the Broadcom Cygnus SoC - -config CLK_BCM_NSP - bool "Broadcom Northstar/Northstar Plus clock support" - depends on ARCH_BCM_5301X || ARCH_BCM_NSP || COMPILE_TEST - default ARCH_BCM_5301X || ARCH_BCM_NSP - help - Enable common clock framework support for the Broadcom Northstar and - Northstar Plus SoCs - -config CLK_BCM_NS2 - bool "Broadcom Northstar 2 clock support" - depends on ARCH_BCM_IPROC || COMPILE_TEST - default ARCH_BCM_IPROC - help - Enable common clock framework support for the Broadcom Northstar 2 SoC - -endif diff --git a/src/linux/drivers/clk/bcm/Makefile b/src/linux/drivers/clk/bcm/Makefile deleted file mode 100644 index d9dc848..0000000 --- a/src/linux/drivers/clk/bcm/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -obj-$(CONFIG_CLK_BCM_63XX) += clk-bcm63xx.o -obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o -obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o -obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o -obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o -obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o -obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o -obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835-aux.o -obj-$(CONFIG_ARCH_BCM_53573) += clk-bcm53573-ilp.o -obj-$(CONFIG_CLK_BCM_CYGNUS) += clk-cygnus.o -obj-$(CONFIG_CLK_BCM_NSP) += clk-nsp.o -obj-$(CONFIG_CLK_BCM_NS2) += clk-ns2.o diff --git a/src/linux/drivers/clk/hisilicon/Kconfig b/src/linux/drivers/clk/hisilicon/Kconfig deleted file mode 100644 index 3f537a0..0000000 --- a/src/linux/drivers/clk/hisilicon/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -config COMMON_CLK_HI3519 - tristate "Hi3519 Clock Driver" - depends on ARCH_HISI || COMPILE_TEST - select RESET_HISI - default ARCH_HISI - help - Build the clock driver for hi3519. - -config COMMON_CLK_HI6220 - bool "Hi6220 Clock Driver" - depends on ARCH_HISI || COMPILE_TEST - default ARCH_HISI - help - Build the Hisilicon Hi6220 clock driver based on the common clock framework. - -config RESET_HISI - bool "HiSilicon Reset Controller Driver" - depends on ARCH_HISI || COMPILE_TEST - select RESET_CONTROLLER - help - Build reset controller driver for HiSilicon device chipsets. - -config STUB_CLK_HI6220 - bool "Hi6220 Stub Clock Driver" - depends on COMMON_CLK_HI6220 && MAILBOX - help - Build the Hisilicon Hi6220 stub clock driver. diff --git a/src/linux/drivers/clk/mediatek/Kconfig b/src/linux/drivers/clk/mediatek/Kconfig deleted file mode 100644 index f042bd2..0000000 --- a/src/linux/drivers/clk/mediatek/Kconfig +++ /dev/null @@ -1,23 +0,0 @@ -# -# MediaTek SoC drivers -# -config COMMON_CLK_MEDIATEK - bool - ---help--- - Mediatek SoCs' clock support. - -config COMMON_CLK_MT8135 - bool "Clock driver for Mediatek MT8135" - depends on ARCH_MEDIATEK || COMPILE_TEST - select COMMON_CLK_MEDIATEK - default ARCH_MEDIATEK - ---help--- - This driver supports Mediatek MT8135 clocks. - -config COMMON_CLK_MT8173 - bool "Clock driver for Mediatek MT8173" - depends on ARCH_MEDIATEK || COMPILE_TEST - select COMMON_CLK_MEDIATEK - default ARCH_MEDIATEK - ---help--- - This driver supports Mediatek MT8173 clocks. diff --git a/src/linux/drivers/clk/meson/Kconfig b/src/linux/drivers/clk/meson/Kconfig deleted file mode 100644 index 19480bc..0000000 --- a/src/linux/drivers/clk/meson/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -config COMMON_CLK_AMLOGIC - bool - depends on OF - depends on ARCH_MESON || COMPILE_TEST - -config COMMON_CLK_MESON8B - bool - depends on COMMON_CLK_AMLOGIC - help - Support for the clock controller on AmLogic S805 devices, aka - meson8b. Say Y if you want peripherals and CPU frequency scaling to - work. - -config COMMON_CLK_GXBB - bool - depends on COMMON_CLK_AMLOGIC - help - Support for the clock controller on AmLogic S905 devices, aka gxbb. - Say Y if you want peripherals and CPU frequency scaling to work. diff --git a/src/linux/drivers/clk/mvebu/Kconfig b/src/linux/drivers/clk/mvebu/Kconfig deleted file mode 100644 index fddc8ac..0000000 --- a/src/linux/drivers/clk/mvebu/Kconfig +++ /dev/null @@ -1,51 +0,0 @@ -config MVEBU_CLK_COMMON - bool - -config MVEBU_CLK_CPU - bool - -config MVEBU_CLK_COREDIV - bool - -config ARMADA_370_CLK - bool - select MVEBU_CLK_COMMON - select MVEBU_CLK_CPU - -config ARMADA_375_CLK - bool - select MVEBU_CLK_COMMON - -config ARMADA_38X_CLK - bool - select MVEBU_CLK_COMMON - -config ARMADA_39X_CLK - bool - select MVEBU_CLK_COMMON - -config ARMADA_37XX_CLK - bool - -config ARMADA_XP_CLK - bool - select MVEBU_CLK_COMMON - select MVEBU_CLK_CPU - -config ARMADA_AP806_SYSCON - bool - -config ARMADA_CP110_SYSCON - bool - -config DOVE_CLK - bool - select MVEBU_CLK_COMMON - -config KIRKWOOD_CLK - bool - select MVEBU_CLK_COMMON - -config ORION_CLK - bool - select MVEBU_CLK_COMMON diff --git a/src/linux/drivers/clk/mvebu/Makefile b/src/linux/drivers/clk/mvebu/Makefile deleted file mode 100644 index d9ae97f..0000000 --- a/src/linux/drivers/clk/mvebu/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -obj-$(CONFIG_MVEBU_CLK_COMMON) += common.o -obj-$(CONFIG_MVEBU_CLK_CPU) += clk-cpu.o -obj-$(CONFIG_MVEBU_CLK_COREDIV) += clk-corediv.o - -obj-$(CONFIG_ARMADA_370_CLK) += armada-370.o -obj-$(CONFIG_ARMADA_375_CLK) += armada-375.o -obj-$(CONFIG_ARMADA_38X_CLK) += armada-38x.o -obj-$(CONFIG_ARMADA_39X_CLK) += armada-39x.o -obj-$(CONFIG_ARMADA_37XX_CLK) += armada-37xx-xtal.o -obj-$(CONFIG_ARMADA_37XX_CLK) += armada-37xx-tbg.o -obj-$(CONFIG_ARMADA_37XX_CLK) += armada-37xx-periph.o -obj-$(CONFIG_ARMADA_XP_CLK) += armada-xp.o -obj-$(CONFIG_ARMADA_AP806_SYSCON) += ap806-system-controller.o -obj-$(CONFIG_ARMADA_CP110_SYSCON) += cp110-system-controller.o -obj-$(CONFIG_DOVE_CLK) += dove.o dove-divider.o -obj-$(CONFIG_KIRKWOOD_CLK) += kirkwood.o -obj-$(CONFIG_ORION_CLK) += orion.o diff --git a/src/linux/drivers/clk/qcom/Kconfig b/src/linux/drivers/clk/qcom/Kconfig deleted file mode 100644 index 0146d3c..0000000 --- a/src/linux/drivers/clk/qcom/Kconfig +++ /dev/null @@ -1,152 +0,0 @@ -config QCOM_GDSC - bool - select PM_GENERIC_DOMAINS if PM - -config COMMON_CLK_QCOM - tristate "Support for Qualcomm's clock controllers" - depends on OF - depends on ARCH_QCOM || COMPILE_TEST - select REGMAP_MMIO - select RESET_CONTROLLER - -config APQ_GCC_8084 - tristate "APQ8084 Global Clock Controller" - select QCOM_GDSC - depends on COMMON_CLK_QCOM - help - Support for the global clock controller on apq8084 devices. - Say Y if you want to use peripheral devices such as UART, SPI, - i2c, USB, SD/eMMC, SATA, PCIe, etc. - -config APQ_MMCC_8084 - tristate "APQ8084 Multimedia Clock Controller" - select APQ_GCC_8084 - select QCOM_GDSC - depends on COMMON_CLK_QCOM - help - Support for the multimedia clock controller on apq8084 devices. - Say Y if you want to support multimedia devices such as display, - graphics, video encode/decode, camera, etc. - -config IPQ_GCC_4019 - tristate "IPQ4019 Global Clock Controller" - depends on COMMON_CLK_QCOM - help - Support for the global clock controller on ipq4019 devices. - Say Y if you want to use peripheral devices such as UART, SPI, - i2c, USB, SD/eMMC, etc. - -config IPQ_GCC_806X - tristate "IPQ806x Global Clock Controller" - depends on COMMON_CLK_QCOM - help - Support for the global clock controller on ipq806x devices. - Say Y if you want to use peripheral devices such as UART, SPI, - i2c, USB, SD/eMMC, etc. - -config IPQ_LCC_806X - tristate "IPQ806x LPASS Clock Controller" - select IPQ_GCC_806X - depends on COMMON_CLK_QCOM - help - Support for the LPASS clock controller on ipq806x devices. - Say Y if you want to use audio devices such as i2s, pcm, - S/PDIF, etc. - -config MSM_GCC_8660 - tristate "MSM8660 Global Clock Controller" - depends on COMMON_CLK_QCOM - help - Support for the global clock controller on msm8660 devices. - Say Y if you want to use peripheral devices such as UART, SPI, - i2c, USB, SD/eMMC, etc. - -config MSM_GCC_8916 - tristate "MSM8916 Global Clock Controller" - select QCOM_GDSC - depends on COMMON_CLK_QCOM - help - Support for the global clock controller on msm8916 devices. - Say Y if you want to use devices such as UART, SPI i2c, USB, - SD/eMMC, display, graphics, camera etc. - -config MSM_GCC_8960 - tristate "APQ8064/MSM8960 Global Clock Controller" - depends on COMMON_CLK_QCOM - help - Support for the global clock controller on apq8064/msm8960 devices. - Say Y if you want to use peripheral devices such as UART, SPI, - i2c, USB, SD/eMMC, SATA, PCIe, etc. - -config MSM_LCC_8960 - tristate "APQ8064/MSM8960 LPASS Clock Controller" - select MSM_GCC_8960 - depends on COMMON_CLK_QCOM - help - Support for the LPASS clock controller on apq8064/msm8960 devices. - Say Y if you want to use audio devices such as i2s, pcm, - SLIMBus, etc. - -config MDM_GCC_9615 - tristate "MDM9615 Global Clock Controller" - depends on COMMON_CLK_QCOM - help - Support for the global clock controller on mdm9615 devices. - Say Y if you want to use peripheral devices such as UART, SPI, - i2c, USB, SD/eMMC, etc. - -config MDM_LCC_9615 - tristate "MDM9615 LPASS Clock Controller" - select MDM_GCC_9615 - depends on COMMON_CLK_QCOM - help - Support for the LPASS clock controller on mdm9615 devices. - Say Y if you want to use audio devices such as i2s, pcm, - SLIMBus, etc. - -config MSM_MMCC_8960 - tristate "MSM8960 Multimedia Clock Controller" - select MSM_GCC_8960 - depends on COMMON_CLK_QCOM - help - Support for the multimedia clock controller on msm8960 devices. - Say Y if you want to support multimedia devices such as display, - graphics, video encode/decode, camera, etc. - -config MSM_GCC_8974 - tristate "MSM8974 Global Clock Controller" - select QCOM_GDSC - depends on COMMON_CLK_QCOM - help - Support for the global clock controller on msm8974 devices. - Say Y if you want to use peripheral devices such as UART, SPI, - i2c, USB, SD/eMMC, SATA, PCIe, etc. - -config MSM_MMCC_8974 - tristate "MSM8974 Multimedia Clock Controller" - select MSM_GCC_8974 - select QCOM_GDSC - depends on COMMON_CLK_QCOM - help - Support for the multimedia clock controller on msm8974 devices. - Say Y if you want to support multimedia devices such as display, - graphics, video encode/decode, camera, etc. - -config MSM_GCC_8996 - tristate "MSM8996 Global Clock Controller" - select QCOM_GDSC - depends on COMMON_CLK_QCOM - help - Support for the global clock controller on msm8996 devices. - Say Y if you want to use peripheral devices such as UART, SPI, - i2c, USB, UFS, SD/eMMC, PCIe, etc. - -config MSM_MMCC_8996 - tristate "MSM8996 Multimedia Clock Controller" - select MSM_GCC_8996 - select QCOM_GDSC - depends on COMMON_CLK_QCOM - help - Support for the multimedia clock controller on msm8996 devices. - Say Y if you want to support multimedia devices such as display, - graphics, video encode/decode, camera, etc. diff --git a/src/linux/drivers/clk/renesas/Kconfig b/src/linux/drivers/clk/renesas/Kconfig deleted file mode 100644 index 41a12d3..0000000 --- a/src/linux/drivers/clk/renesas/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config CLK_RENESAS_CPG_MSSR - bool - default y if ARCH_R8A7795 - default y if ARCH_R8A7796 - -config CLK_RENESAS_CPG_MSTP - bool - default y if ARCH_R7S72100 - default y if ARCH_R8A73A4 - default y if ARCH_R8A7740 - default y if ARCH_R8A7778 - default y if ARCH_R8A7779 - default y if ARCH_R8A7790 - default y if ARCH_R8A7791 - default y if ARCH_R8A7792 - default y if ARCH_R8A7793 - default y if ARCH_R8A7794 - default y if ARCH_SH73A0 diff --git a/src/linux/drivers/clk/samsung/Kconfig b/src/linux/drivers/clk/samsung/Kconfig deleted file mode 100644 index addc652..0000000 --- a/src/linux/drivers/clk/samsung/Kconfig +++ /dev/null @@ -1,42 +0,0 @@ -# Recent Exynos platforms should just select COMMON_CLK_SAMSUNG: -config COMMON_CLK_SAMSUNG - bool "Samsung Exynos clock controller support" if COMPILE_TEST - # Clocks on ARM64 SoCs (e.g. Exynos5433, Exynos7) are chosen by - # EXYNOS_ARM64_COMMON_CLK to avoid building them on ARMv7: - select EXYNOS_ARM64_COMMON_CLK if ARM64 && ARCH_EXYNOS - -config EXYNOS_ARM64_COMMON_CLK - bool "Samsung Exynos ARMv8-family clock controller support" if COMPILE_TEST - depends on COMMON_CLK_SAMSUNG - -config EXYNOS_AUDSS_CLK_CON - tristate "Samsung Exynos AUDSS clock controller support" - depends on COMMON_CLK_SAMSUNG - default y if ARCH_EXYNOS - help - Support for the Audio Subsystem CLKCON clock controller present - on some Exynos SoC variants. Choose M or Y here if you want to - use audio devices such as I2S, PCM, etc. - -# For S3C24XX platforms, select following symbols: -config S3C2410_COMMON_CLK - bool "Samsung S3C2410 clock controller support" if COMPILE_TEST - select COMMON_CLK_SAMSUNG - help - Build the s3c2410 clock driver based on the common clock framework. - -config S3C2410_COMMON_DCLK - bool - select COMMON_CLK_SAMSUNG - select REGMAP_MMIO - help - Temporary symbol to build the dclk driver based on the common clock - framework. - -config S3C2412_COMMON_CLK - bool "Samsung S3C2412 clock controller support" if COMPILE_TEST - select COMMON_CLK_SAMSUNG - -config S3C2443_COMMON_CLK - bool "Samsung S3C2443 clock controller support" if COMPILE_TEST - select COMMON_CLK_SAMSUNG diff --git a/src/linux/drivers/clk/sunxi-ng/Kconfig b/src/linux/drivers/clk/sunxi-ng/Kconfig deleted file mode 100644 index 254d952..0000000 --- a/src/linux/drivers/clk/sunxi-ng/Kconfig +++ /dev/null @@ -1,104 +0,0 @@ -config SUNXI_CCU - bool "Clock support for Allwinner SoCs" - depends on ARCH_SUNXI || COMPILE_TEST - default ARCH_SUNXI - -if SUNXI_CCU - -# Base clock types - -config SUNXI_CCU_DIV - bool - select SUNXI_CCU_MUX - -config SUNXI_CCU_FRAC - bool - -config SUNXI_CCU_GATE - bool - -config SUNXI_CCU_MUX - bool - -config SUNXI_CCU_MULT - bool - select SUNXI_CCU_MUX - -config SUNXI_CCU_PHASE - bool - -# Multi-factor clocks - -config SUNXI_CCU_NK - bool - select SUNXI_CCU_GATE - -config SUNXI_CCU_NKM - bool - select RATIONAL - select SUNXI_CCU_GATE - -config SUNXI_CCU_NKMP - bool - select RATIONAL - select SUNXI_CCU_GATE - -config SUNXI_CCU_NM - bool - select RATIONAL - select SUNXI_CCU_FRAC - select SUNXI_CCU_GATE - -config SUNXI_CCU_MP - bool - select SUNXI_CCU_GATE - select SUNXI_CCU_MUX - -# SoC Drivers - -config SUN6I_A31_CCU - bool "Support for the Allwinner A31/A31s CCU" - select SUNXI_CCU_DIV - select SUNXI_CCU_NK - select SUNXI_CCU_NKM - select SUNXI_CCU_NM - select SUNXI_CCU_MP - select SUNXI_CCU_PHASE - default MACH_SUN6I - -config SUN8I_A23_CCU - bool "Support for the Allwinner A23 CCU" - select SUNXI_CCU_DIV - select SUNXI_CCU_MULT - select SUNXI_CCU_NK - select SUNXI_CCU_NKM - select SUNXI_CCU_NKMP - select SUNXI_CCU_NM - select SUNXI_CCU_MP - select SUNXI_CCU_PHASE - default MACH_SUN8I - -config SUN8I_A33_CCU - bool "Support for the Allwinner A33 CCU" - select SUNXI_CCU_DIV - select SUNXI_CCU_MULT - select SUNXI_CCU_NK - select SUNXI_CCU_NKM - select SUNXI_CCU_NKMP - select SUNXI_CCU_NM - select SUNXI_CCU_MP - select SUNXI_CCU_PHASE - default MACH_SUN8I - -config SUN8I_H3_CCU - bool "Support for the Allwinner H3 CCU" - select SUNXI_CCU_DIV - select SUNXI_CCU_NK - select SUNXI_CCU_NKM - select SUNXI_CCU_NKMP - select SUNXI_CCU_NM - select SUNXI_CCU_MP - select SUNXI_CCU_PHASE - default MACH_SUN8I - -endif diff --git a/src/linux/drivers/clk/tegra/Kconfig b/src/linux/drivers/clk/tegra/Kconfig deleted file mode 100644 index 1ba30d1..0000000 --- a/src/linux/drivers/clk/tegra/Kconfig +++ /dev/null @@ -1,3 +0,0 @@ -config TEGRA_CLK_EMC - def_bool y - depends on TEGRA124_EMC diff --git a/src/linux/drivers/clk/ti/Kconfig b/src/linux/drivers/clk/ti/Kconfig deleted file mode 100644 index 2713417..0000000 --- a/src/linux/drivers/clk/ti/Kconfig +++ /dev/null @@ -1,6 +0,0 @@ -config COMMON_CLK_TI_ADPLL - tristate "Clock driver for dm814x ADPLL" - depends on ARCH_OMAP2PLUS || COMPILE_TEST - default y if SOC_TI81XX - ---help--- - ADPLL clock driver for the dm814x SoC using common clock framework. diff --git a/src/linux/drivers/clk/ti/Makefile b/src/linux/drivers/clk/ti/Makefile deleted file mode 100644 index 0deac98..0000000 --- a/src/linux/drivers/clk/ti/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -ifeq ($(CONFIG_ARCH_OMAP2PLUS), y) - -obj-y += clk.o autoidle.o clockdomain.o -clk-common = dpll.o composite.o divider.o gate.o \ - fixed-factor.o mux.o apll.o \ - clkt_dpll.o clkt_iclk.o clkt_dflt.o -obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o dpll3xxx.o -obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-814x.o clk-816x.o -obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o -obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o \ - clk-3xxx.o dpll3xxx.o -obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o \ - dpll3xxx.o dpll44xx.o -obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o \ - dpll3xxx.o dpll44xx.o -obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \ - clk-dra7-atl.o dpll3xxx.o dpll44xx.o -obj-$(CONFIG_SOC_AM43XX) += $(clk-common) dpll3xxx.o clk-43xx.o - -ifdef CONFIG_ATAGS -obj-$(CONFIG_ARCH_OMAP3) += clk-3xxx-legacy.o -endif - -endif # CONFIG_ARCH_OMAP2PLUS - -obj-$(CONFIG_COMMON_CLK_TI_ADPLL) += adpll.o diff --git a/src/linux/drivers/clk/uniphier/Kconfig b/src/linux/drivers/clk/uniphier/Kconfig deleted file mode 100644 index 5512377..0000000 --- a/src/linux/drivers/clk/uniphier/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config CLK_UNIPHIER - bool "Clock driver for UniPhier SoCs" - depends on ARCH_UNIPHIER || COMPILE_TEST - depends on OF && MFD_SYSCON - default ARCH_UNIPHIER - help - Support for clock controllers on UniPhier SoCs. - Say Y if you want to control clocks provided by System Control - block, Media I/O block, Peripheral Block. diff --git a/src/linux/drivers/clk/versatile/Kconfig b/src/linux/drivers/clk/versatile/Kconfig deleted file mode 100644 index a6da2aa..0000000 --- a/src/linux/drivers/clk/versatile/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -config COMMON_CLK_VERSATILE - bool "Clock driver for ARM Reference designs" - depends on ARCH_INTEGRATOR || ARCH_REALVIEW || \ - ARCH_VERSATILE || ARCH_VEXPRESS || ARM64 || \ - COMPILE_TEST - select REGMAP_MMIO - ---help--- - Supports clocking on ARM Reference designs: - - Integrator/AP and Integrator/CP - - RealView PB1176, EB, PB11MP and PBX - - Versatile Express - -config CLK_SP810 - bool "Clock driver for ARM SP810 System Controller" - depends on COMMON_CLK_VERSATILE - default y if ARCH_VEXPRESS - ---help--- - Supports clock muxing (REFCLK/TIMCLK to TIMERCLKEN0-3) capabilities - of the ARM SP810 System Controller cell. - -config CLK_VEXPRESS_OSC - bool "Clock driver for Versatile Express OSC clock generators" - depends on COMMON_CLK_VERSATILE - depends on VEXPRESS_CONFIG - default y if ARCH_VEXPRESS - ---help--- - Simple regmap-based driver driving clock generators on Versatile - Express platforms hidden behind its configuration infrastructure, - commonly known as OSCs. diff --git a/src/linux/drivers/clocksource/Kconfig b/src/linux/drivers/clocksource/Kconfig deleted file mode 100644 index e2c6e43..0000000 --- a/src/linux/drivers/clocksource/Kconfig +++ /dev/null @@ -1,544 +0,0 @@ -menu "Clock Source drivers" - depends on !ARCH_USES_GETTIMEOFFSET - -config CLKSRC_OF - bool - select CLKSRC_PROBE - -config CLKSRC_ACPI - bool - select CLKSRC_PROBE - -config CLKSRC_PROBE - bool - -config CLKSRC_I8253 - bool - -config CLKEVT_I8253 - bool - -config I8253_LOCK - bool - -config CLKBLD_I8253 - def_bool y if CLKSRC_I8253 || CLKEVT_I8253 || I8253_LOCK - -config CLKSRC_MMIO - bool - -config BCM2835_TIMER - bool "BCM2835 timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - select CLKSRC_MMIO - help - Enables the support for the BCM2835 timer driver. - -config BCM_KONA_TIMER - bool "BCM mobile timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - select CLKSRC_MMIO - help - Enables the support for the BCM Kona mobile timer driver. - -config DIGICOLOR_TIMER - bool "Digicolor timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - select CLKSRC_MMIO - depends on HAS_IOMEM - help - Enables the support for the digicolor timer driver. - -config DW_APB_TIMER - bool "DW APB timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - help - Enables the support for the dw_apb timer. - -config DW_APB_TIMER_OF - bool - select DW_APB_TIMER - select CLKSRC_OF - -config ROCKCHIP_TIMER - bool "Rockchip timer driver" if COMPILE_TEST - depends on ARM || ARM64 - select CLKSRC_OF - help - Enables the support for the rockchip timer driver. - -config ARMADA_370_XP_TIMER - bool "Armada 370 and XP timer driver" if COMPILE_TEST - depends on ARM - select CLKSRC_OF - select CLKSRC_MMIO - help - Enables the support for the Armada 370 and XP timer driver. - -config MESON6_TIMER - bool "Meson6 timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - select CLKSRC_MMIO - help - Enables the support for the Meson6 timer driver. - -config ORION_TIMER - bool "Orion timer driver" if COMPILE_TEST - depends on ARM - select CLKSRC_OF - select CLKSRC_MMIO - help - Enables the support for the Orion timer driver - -config SUN4I_TIMER - bool "Sun4i timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - depends on HAS_IOMEM - select CLKSRC_MMIO - help - Enables support for the Sun4i timer. - -config SUN5I_HSTIMER - bool "Sun5i timer driver" if COMPILE_TEST - select CLKSRC_MMIO - depends on COMMON_CLK - help - Enables support the Sun5i timer. - -config TEGRA_TIMER - bool "Tegra timer driver" if COMPILE_TEST - select CLKSRC_MMIO - depends on ARM - help - Enables support for the Tegra driver. - -config VT8500_TIMER - bool "VT8500 timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - depends on HAS_IOMEM - help - Enables support for the VT8500 driver. - -config CADENCE_TTC_TIMER - bool "Cadence TTC timer driver" if COMPILE_TEST - depends on COMMON_CLK - help - Enables support for the cadence ttc driver. - -config ASM9260_TIMER - bool "ASM9260 timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - select CLKSRC_MMIO - select CLKSRC_OF - help - Enables support for the ASM9260 timer. - -config CLKSRC_NOMADIK_MTU - bool "Nomakdik clocksource driver" if COMPILE_TEST - depends on ARM - select CLKSRC_MMIO - help - Support for Multi Timer Unit. MTU provides access - to multiple interrupt generating programmable - 32-bit free running decrementing counters. - -config CLKSRC_NOMADIK_MTU_SCHED_CLOCK - bool - depends on CLKSRC_NOMADIK_MTU - help - Use the Multi Timer Unit as the sched_clock. - -config CLKSRC_DBX500_PRCMU - bool "Clocksource PRCMU Timer" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - depends on HAS_IOMEM - help - Use the always on PRCMU Timer as clocksource - -config CLPS711X_TIMER - bool "Cirrus logic timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - select CLKSRC_MMIO - help - Enables support for the Cirrus Logic PS711 timer. - -config ATLAS7_TIMER - bool "Atlas7 timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - select CLKSRC_MMIO - help - Enables support for the Atlas7 timer. - -config MOXART_TIMER - bool "Moxart timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - select CLKSRC_MMIO - help - Enables support for the Moxart timer. - -config MXS_TIMER - bool "Mxs timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - select CLKSRC_MMIO - select STMP_DEVICE - help - Enables support for the Mxs timer. - -config PRIMA2_TIMER - bool "Prima2 timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - select CLKSRC_MMIO - help - Enables support for the Prima2 timer. - -config U300_TIMER - bool "U300 timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - depends on ARM - select CLKSRC_MMIO - help - Enables support for the U300 timer. - -config NSPIRE_TIMER - bool "NSpire timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - select CLKSRC_MMIO - help - Enables support for the Nspire timer. - -config KEYSTONE_TIMER - bool "Keystone timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - depends on ARM || ARM64 - select CLKSRC_MMIO - help - Enables support for the Keystone timer. - -config INTEGRATOR_AP_TIMER - bool "Integrator-ap timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - select CLKSRC_MMIO - help - Enables support for the Integrator-ap timer. - -config CLKSRC_DBX500_PRCMU_SCHED_CLOCK - bool "Clocksource PRCMU Timer sched_clock" - depends on (CLKSRC_DBX500_PRCMU && !CLKSRC_NOMADIK_MTU_SCHED_CLOCK) - default y - help - Use the always on PRCMU Timer as sched_clock - -config CLKSRC_EFM32 - bool "Clocksource for Energy Micro's EFM32 SoCs" if !ARCH_EFM32 - depends on OF && ARM && (ARCH_EFM32 || COMPILE_TEST) - select CLKSRC_MMIO - default ARCH_EFM32 - help - Support to use the timers of EFM32 SoCs as clock source and clock - event device. - -config CLKSRC_LPC32XX - bool "Clocksource for LPC32XX" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS && HAS_IOMEM - depends on ARM - select CLKSRC_MMIO - select CLKSRC_OF - help - Support for the LPC32XX clocksource. - -config CLKSRC_PISTACHIO - bool "Clocksource for Pistachio SoC" if COMPILE_TEST - depends on HAS_IOMEM - select CLKSRC_OF - help - Enables the clocksource for the Pistachio SoC. - -config CLKSRC_TI_32K - bool "Texas Instruments 32.768 Hz Clocksource" if COMPILE_TEST - depends on GENERIC_SCHED_CLOCK - select CLKSRC_OF if OF - help - This option enables support for Texas Instruments 32.768 Hz clocksource - available on many OMAP-like platforms. - -config CLKSRC_NPS - bool "NPS400 clocksource driver" if COMPILE_TEST - depends on !PHYS_ADDR_T_64BIT - select CLKSRC_MMIO - select CLKSRC_OF if OF - help - NPS400 clocksource support. - Got 64 bit counter with update rate up to 1000MHz. - This counter is accessed via couple of 32 bit memory mapped registers. - -config CLKSRC_STM32 - bool "Clocksource for STM32 SoCs" if !ARCH_STM32 - depends on OF && ARM && (ARCH_STM32 || COMPILE_TEST) - select CLKSRC_MMIO - -config CLKSRC_MPS2 - bool "Clocksource for MPS2 SoCs" if COMPILE_TEST - depends on GENERIC_SCHED_CLOCK - select CLKSRC_MMIO - select CLKSRC_OF - -config ARM_ARCH_TIMER - bool - select CLKSRC_OF if OF - select CLKSRC_ACPI if ACPI - -config ARM_ARCH_TIMER_EVTSTREAM - bool "Enable ARM architected timer event stream generation by default" - default y if ARM_ARCH_TIMER - depends on ARM_ARCH_TIMER - help - This option enables support by default for event stream generation - based on the ARM architected timer. It is used for waking up CPUs - executing the wfe instruction at a frequency represented as a - power-of-2 divisor of the clock rate. The behaviour can also be - overridden on the command line using the - clocksource.arm_arch_timer.evtstream parameter. - The main use of the event stream is wfe-based timeouts of userspace - locking implementations. It might also be useful for imposing timeout - on wfe to safeguard against any programming errors in case an expected - event is not generated. - This must be disabled for hardware validation purposes to detect any - hardware anomalies of missing events. - -config FSL_ERRATUM_A008585 - bool "Workaround for Freescale/NXP Erratum A-008585" - default y - depends on ARM_ARCH_TIMER && ARM64 - help - This option enables a workaround for Freescale/NXP Erratum - A-008585 ("ARM generic timer may contain an erroneous - value"). The workaround will only be active if the - fsl,erratum-a008585 property is found in the timer node. - -config ARM_GLOBAL_TIMER - bool "Support for the ARM global timer" if COMPILE_TEST - select CLKSRC_OF if OF - depends on ARM - help - This options enables support for the ARM global timer unit - -config ARM_TIMER_SP804 - bool "Support for Dual Timer SP804 module" - depends on GENERIC_SCHED_CLOCK && CLKDEV_LOOKUP - select CLKSRC_MMIO - select CLKSRC_OF if OF - -config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK - bool - depends on ARM_GLOBAL_TIMER - default y - help - Use ARM global timer clock source as sched_clock - -config ARMV7M_SYSTICK - bool "Support for the ARMv7M system time" if COMPILE_TEST - select CLKSRC_OF if OF - select CLKSRC_MMIO - help - This options enables support for the ARMv7M system timer unit - -config ATMEL_PIT - select CLKSRC_OF if OF - def_bool SOC_AT91SAM9 || SOC_SAMA5 - -config ATMEL_ST - bool "Atmel ST timer support" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - select CLKSRC_OF - select MFD_SYSCON - help - Support for the Atmel ST timer. - -config CLKSRC_METAG_GENERIC - def_bool y if METAG - help - This option enables support for the Meta per-thread timers. - -config CLKSRC_EXYNOS_MCT - bool "Exynos multi core timer driver" if COMPILE_TEST - depends on ARM || ARM64 - help - Support for Multi Core Timer controller on Exynos SoCs. - -config CLKSRC_SAMSUNG_PWM - bool "PWM timer driver for Samsung S3C, S5P" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - depends on HAS_IOMEM - help - This is a new clocksource driver for the PWM timer found in - Samsung S3C, S5P and Exynos SoCs, replacing an earlier driver - for all devicetree enabled platforms. This driver will be - needed only on systems that do not have the Exynos MCT available. - -config FSL_FTM_TIMER - bool "Freescale FlexTimer Module driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - depends on HAS_IOMEM - select CLKSRC_MMIO - help - Support for Freescale FlexTimer Module (FTM) timer. - -config VF_PIT_TIMER - bool - select CLKSRC_MMIO - help - Support for Period Interrupt Timer on Freescale Vybrid Family SoCs. - -config OXNAS_RPS_TIMER - bool "Oxford Semiconductor OXNAS RPS Timers driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - select CLKSRC_OF - select CLKSRC_MMIO - help - This enables support for the Oxford Semiconductor OXNAS RPS timers. - -config SYS_SUPPORTS_SH_CMT - bool - -config MTK_TIMER - bool "Mediatek timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS && HAS_IOMEM - select CLKSRC_OF - select CLKSRC_MMIO - help - Support for Mediatek timer driver. - -config SYS_SUPPORTS_SH_MTU2 - bool - -config SYS_SUPPORTS_SH_TMU - bool - -config SYS_SUPPORTS_EM_STI - bool - -config CLKSRC_JCORE_PIT - bool "J-Core PIT timer driver" if COMPILE_TEST - depends on OF - depends on GENERIC_CLOCKEVENTS - depends on HAS_IOMEM - select CLKSRC_MMIO - help - This enables build of clocksource and clockevent driver for - the integrated PIT in the J-Core synthesizable, open source SoC. - -config SH_TIMER_CMT - bool "Renesas CMT timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - depends on HAS_IOMEM - default SYS_SUPPORTS_SH_CMT - help - This enables build of a clocksource and clockevent driver for - the Compare Match Timer (CMT) hardware available in 16/32/48-bit - variants on a wide range of Mobile and Automotive SoCs from Renesas. - -config SH_TIMER_MTU2 - bool "Renesas MTU2 timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - depends on HAS_IOMEM - default SYS_SUPPORTS_SH_MTU2 - help - This enables build of a clockevent driver for the Multi-Function - Timer Pulse Unit 2 (MTU2) hardware available on SoCs from Renesas. - This hardware comes with 16 bit-timer registers. - -config SH_TIMER_TMU - bool "Renesas TMU timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - depends on HAS_IOMEM - default SYS_SUPPORTS_SH_TMU - help - This enables build of a clocksource and clockevent driver for - the 32-bit Timer Unit (TMU) hardware available on a wide range - SoCs from Renesas. - -config EM_TIMER_STI - bool "Renesas STI timer driver" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS && HAS_IOMEM - default SYS_SUPPORTS_EM_STI - help - This enables build of a clocksource and clockevent driver for - the 48-bit System Timer (STI) hardware available on a SoCs - such as EMEV2 from former NEC Electronics. - -config CLKSRC_QCOM - bool "Qualcomm MSM timer" if COMPILE_TEST - depends on ARM - select CLKSRC_OF - help - This enables the clocksource and the per CPU clockevent driver for the - Qualcomm SoCs. - -config CLKSRC_VERSATILE - bool "ARM Versatile (Express) reference platforms clock source" if COMPILE_TEST - depends on GENERIC_SCHED_CLOCK && !ARCH_USES_GETTIMEOFFSET - select CLKSRC_OF - default y if MFD_VEXPRESS_SYSREG - help - This option enables clock source based on free running - counter available in the "System Registers" block of - ARM Versatile, RealView and Versatile Express reference - platforms. - -config CLKSRC_MIPS_GIC - bool - depends on MIPS_GIC - select CLKSRC_OF - -config CLKSRC_TANGO_XTAL - bool "Clocksource for Tango SoC" if COMPILE_TEST - depends on ARM - select CLKSRC_OF - select CLKSRC_MMIO - help - This enables the clocksource for Tango SoC - -config CLKSRC_PXA - bool "Clocksource for PXA or SA-11x0 platform" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS - depends on HAS_IOMEM - select CLKSRC_MMIO - help - This enables OST0 support available on PXA and SA-11x0 - platforms. - -config H8300_TMR8 - bool "Clockevent timer for the H8300 platform" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS && HAS_IOMEM - help - This enables the 8 bits timer for the H8300 platform. - -config H8300_TMR16 - bool "Clockevent timer for the H83069 platform" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS && HAS_IOMEM - help - This enables the 16 bits timer for the H8300 platform with the - H83069 cpu. - -config H8300_TPU - bool "Clocksource for the H8300 platform" if COMPILE_TEST - depends on GENERIC_CLOCKEVENTS && HAS_IOMEM - help - This enables the clocksource for the H8300 platform with the - H8S2678 cpu. - -config CLKSRC_IMX_GPT - bool "Clocksource using i.MX GPT" if COMPILE_TEST - depends on ARM && CLKDEV_LOOKUP - select CLKSRC_MMIO - -config CLKSRC_ST_LPC - bool "Low power clocksource found in the LPC" if COMPILE_TEST - select CLKSRC_OF if OF - depends on HAS_IOMEM - select CLKSRC_MMIO - help - Enable this option to use the Low Power controller timer - as clocksource. - -endmenu diff --git a/src/linux/drivers/clocksource/Makefile b/src/linux/drivers/clocksource/Makefile deleted file mode 100644 index cf87f40..0000000 --- a/src/linux/drivers/clocksource/Makefile +++ /dev/null @@ -1,71 +0,0 @@ -obj-$(CONFIG_CLKSRC_PROBE) += clksrc-probe.o -obj-$(CONFIG_ATMEL_PIT) += timer-atmel-pit.o -obj-$(CONFIG_ATMEL_ST) += timer-atmel-st.o -obj-$(CONFIG_ATMEL_TCB_CLKSRC) += tcb_clksrc.o -obj-$(CONFIG_X86_PM_TIMER) += acpi_pm.o -obj-$(CONFIG_SCx200HR_TIMER) += scx200_hrt.o -obj-$(CONFIG_CS5535_CLOCK_EVENT_SRC) += cs5535-clockevt.o -obj-$(CONFIG_CLKSRC_JCORE_PIT) += jcore-pit.o -obj-$(CONFIG_SH_TIMER_CMT) += sh_cmt.o -obj-$(CONFIG_SH_TIMER_MTU2) += sh_mtu2.o -obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o -obj-$(CONFIG_EM_TIMER_STI) += em_sti.o -obj-$(CONFIG_CLKBLD_I8253) += i8253.o -obj-$(CONFIG_CLKSRC_MMIO) += mmio.o -obj-$(CONFIG_DIGICOLOR_TIMER) += timer-digicolor.o -obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o -obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o -obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o -obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o -obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o -obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o -obj-$(CONFIG_ORION_TIMER) += time-orion.o -obj-$(CONFIG_BCM2835_TIMER) += bcm2835_timer.o -obj-$(CONFIG_CLPS711X_TIMER) += clps711x-timer.o -obj-$(CONFIG_ATLAS7_TIMER) += timer-atlas7.o -obj-$(CONFIG_MOXART_TIMER) += moxart_timer.o -obj-$(CONFIG_MXS_TIMER) += mxs_timer.o -obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o -obj-$(CONFIG_PRIMA2_TIMER) += timer-prima2.o -obj-$(CONFIG_U300_TIMER) += timer-u300.o -obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o -obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o -obj-$(CONFIG_MESON6_TIMER) += meson6_timer.o -obj-$(CONFIG_TEGRA_TIMER) += tegra20_timer.o -obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o -obj-$(CONFIG_NSPIRE_TIMER) += zevio-timer.o -obj-$(CONFIG_BCM_KONA_TIMER) += bcm_kona_timer.o -obj-$(CONFIG_CADENCE_TTC_TIMER) += cadence_ttc_timer.o -obj-$(CONFIG_CLKSRC_EFM32) += time-efm32.o -obj-$(CONFIG_CLKSRC_STM32) += timer-stm32.o -obj-$(CONFIG_CLKSRC_EXYNOS_MCT) += exynos_mct.o -obj-$(CONFIG_CLKSRC_LPC32XX) += time-lpc32xx.o -obj-$(CONFIG_CLKSRC_MPS2) += mps2-timer.o -obj-$(CONFIG_CLKSRC_SAMSUNG_PWM) += samsung_pwm_timer.o -obj-$(CONFIG_FSL_FTM_TIMER) += fsl_ftm_timer.o -obj-$(CONFIG_VF_PIT_TIMER) += vf_pit_timer.o -obj-$(CONFIG_CLKSRC_QCOM) += qcom-timer.o -obj-$(CONFIG_MTK_TIMER) += mtk_timer.o -obj-$(CONFIG_CLKSRC_PISTACHIO) += time-pistachio.o -obj-$(CONFIG_CLKSRC_TI_32K) += timer-ti-32k.o -obj-$(CONFIG_CLKSRC_NPS) += timer-nps.o -obj-$(CONFIG_OXNAS_RPS_TIMER) += timer-oxnas-rps.o - -obj-$(CONFIG_ARM_ARCH_TIMER) += arm_arch_timer.o -obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o -obj-$(CONFIG_ARMV7M_SYSTICK) += armv7m_systick.o -obj-$(CONFIG_ARM_TIMER_SP804) += timer-sp804.o -obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o -obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o -obj-$(CONFIG_KEYSTONE_TIMER) += timer-keystone.o -obj-$(CONFIG_INTEGRATOR_AP_TIMER) += timer-integrator-ap.o -obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o -obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o -obj-$(CONFIG_CLKSRC_TANGO_XTAL) += tango_xtal.o -obj-$(CONFIG_CLKSRC_IMX_GPT) += timer-imx-gpt.o -obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o -obj-$(CONFIG_H8300_TMR8) += h8300_timer8.o -obj-$(CONFIG_H8300_TMR16) += h8300_timer16.o -obj-$(CONFIG_H8300_TPU) += h8300_tpu.o -obj-$(CONFIG_CLKSRC_ST_LPC) += clksrc_st_lpc.o -obj-$(CONFIG_X86_NUMACHIP) += numachip.o diff --git a/src/linux/drivers/connector/Kconfig b/src/linux/drivers/connector/Kconfig deleted file mode 100644 index 3de5f3a..0000000 --- a/src/linux/drivers/connector/Kconfig +++ /dev/null @@ -1,22 +0,0 @@ - -menuconfig CONNECTOR - tristate "Connector - unified userspace <-> kernelspace linker" - depends on NET - ---help--- - This is unified userspace <-> kernelspace connector working on top - of the netlink socket protocol. - - Connector support can also be built as a module. If so, the module - will be called cn. - -if CONNECTOR - -config PROC_EVENTS - bool "Report process events to userspace" - depends on CONNECTOR=y - default y - ---help--- - Provide a connector that reports process events to userspace. Send - events such as fork, exec, id change (uid, gid, suid, etc), and exit. - -endif # CONNECTOR diff --git a/src/linux/drivers/crypto/Kconfig b/src/linux/drivers/crypto/Kconfig deleted file mode 100644 index 4d2b81f..0000000 --- a/src/linux/drivers/crypto/Kconfig +++ /dev/null @@ -1,558 +0,0 @@ - -menuconfig CRYPTO_HW - bool "Hardware crypto devices" - default y - ---help--- - Say Y here to get to see options for hardware crypto devices and - processors. This option alone does not add any kernel code. - - If you say N, all options in this submenu will be skipped and disabled. - -if CRYPTO_HW - -config CRYPTO_DEV_PADLOCK - tristate "Support for VIA PadLock ACE" - depends on X86 && !UML - help - Some VIA processors come with an integrated crypto engine - (so called VIA PadLock ACE, Advanced Cryptography Engine) - that provides instructions for very fast cryptographic - operations with supported algorithms. - - The instructions are used only when the CPU supports them. - Otherwise software encryption is used. - -config CRYPTO_DEV_PADLOCK_AES - tristate "PadLock driver for AES algorithm" - depends on CRYPTO_DEV_PADLOCK - select CRYPTO_BLKCIPHER - select CRYPTO_AES - help - Use VIA PadLock for AES algorithm. - - Available in VIA C3 and newer CPUs. - - If unsure say M. The compiled module will be - called padlock-aes. - -config CRYPTO_DEV_PADLOCK_SHA - tristate "PadLock driver for SHA1 and SHA256 algorithms" - depends on CRYPTO_DEV_PADLOCK - select CRYPTO_HASH - select CRYPTO_SHA1 - select CRYPTO_SHA256 - help - Use VIA PadLock for SHA1/SHA256 algorithms. - - Available in VIA C7 and newer processors. - - If unsure say M. The compiled module will be - called padlock-sha. - -config CRYPTO_DEV_GEODE - tristate "Support for the Geode LX AES engine" - depends on X86_32 && PCI - select CRYPTO_ALGAPI - select CRYPTO_BLKCIPHER - help - Say 'Y' here to use the AMD Geode LX processor on-board AES - engine for the CryptoAPI AES algorithm. - - To compile this driver as a module, choose M here: the module - will be called geode-aes. - -config ZCRYPT - tristate "Support for PCI-attached cryptographic adapters" - depends on S390 - select HW_RANDOM - help - Select this option if you want to use a PCI-attached cryptographic - adapter like: - + PCI Cryptographic Accelerator (PCICA) - + PCI Cryptographic Coprocessor (PCICC) - + PCI-X Cryptographic Coprocessor (PCIXCC) - + Crypto Express2 Coprocessor (CEX2C) - + Crypto Express2 Accelerator (CEX2A) - + Crypto Express3 Coprocessor (CEX3C) - + Crypto Express3 Accelerator (CEX3A) - -config CRYPTO_SHA1_S390 - tristate "SHA1 digest algorithm" - depends on S390 - select CRYPTO_HASH - help - This is the s390 hardware accelerated implementation of the - SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). - - It is available as of z990. - -config CRYPTO_SHA256_S390 - tristate "SHA256 digest algorithm" - depends on S390 - select CRYPTO_HASH - help - This is the s390 hardware accelerated implementation of the - SHA256 secure hash standard (DFIPS 180-2). - - It is available as of z9. - -config CRYPTO_SHA512_S390 - tristate "SHA384 and SHA512 digest algorithm" - depends on S390 - select CRYPTO_HASH - help - This is the s390 hardware accelerated implementation of the - SHA512 secure hash standard. - - It is available as of z10. - -config CRYPTO_DES_S390 - tristate "DES and Triple DES cipher algorithms" - depends on S390 - select CRYPTO_ALGAPI - select CRYPTO_BLKCIPHER - select CRYPTO_DES - help - This is the s390 hardware accelerated implementation of the - DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). - - As of z990 the ECB and CBC mode are hardware accelerated. - As of z196 the CTR mode is hardware accelerated. - -config CRYPTO_AES_S390 - tristate "AES cipher algorithms" - depends on S390 - select CRYPTO_ALGAPI - select CRYPTO_BLKCIPHER - help - This is the s390 hardware accelerated implementation of the - AES cipher algorithms (FIPS-197). - - As of z9 the ECB and CBC modes are hardware accelerated - for 128 bit keys. - As of z10 the ECB and CBC modes are hardware accelerated - for all AES key sizes. - As of z196 the CTR mode is hardware accelerated for all AES - key sizes and XTS mode is hardware accelerated for 256 and - 512 bit keys. - -config S390_PRNG - tristate "Pseudo random number generator device driver" - depends on S390 - default "m" - help - Select this option if you want to use the s390 pseudo random number - generator. The PRNG is part of the cryptographic processor functions - and uses triple-DES to generate secure random numbers like the - ANSI X9.17 standard. User-space programs access the - pseudo-random-number device through the char device /dev/prandom. - - It is available as of z9. - -config CRYPTO_GHASH_S390 - tristate "GHASH digest algorithm" - depends on S390 - select CRYPTO_HASH - help - This is the s390 hardware accelerated implementation of the - GHASH message digest algorithm for GCM (Galois/Counter Mode). - - It is available as of z196. - -config CRYPTO_CRC32_S390 - tristate "CRC-32 algorithms" - depends on S390 - select CRYPTO_HASH - select CRC32 - help - Select this option if you want to use hardware accelerated - implementations of CRC algorithms. With this option, you - can optimize the computation of CRC-32 (IEEE 802.3 Ethernet) - and CRC-32C (Castagnoli). - - It is available with IBM z13 or later. - -config CRYPTO_DEV_MV_CESA - tristate "Marvell's Cryptographic Engine" - depends on PLAT_ORION - select CRYPTO_AES - select CRYPTO_BLKCIPHER - select CRYPTO_HASH - select SRAM - help - This driver allows you to utilize the Cryptographic Engines and - Security Accelerator (CESA) which can be found on the Marvell Orion - and Kirkwood SoCs, such as QNAP's TS-209. - - Currently the driver supports AES in ECB and CBC mode without DMA. - -config CRYPTO_DEV_MARVELL_CESA - tristate "New Marvell's Cryptographic Engine driver" - depends on PLAT_ORION || ARCH_MVEBU - select CRYPTO_AES - select CRYPTO_DES - select CRYPTO_BLKCIPHER - select CRYPTO_HASH - select SRAM - help - This driver allows you to utilize the Cryptographic Engines and - Security Accelerator (CESA) which can be found on the Armada 370. - This driver supports CPU offload through DMA transfers. - - This driver is aimed at replacing the mv_cesa driver. This will only - happen once it has received proper testing. - -config CRYPTO_DEV_NIAGARA2 - tristate "Niagara2 Stream Processing Unit driver" - select CRYPTO_DES - select CRYPTO_BLKCIPHER - select CRYPTO_HASH - select CRYPTO_MD5 - select CRYPTO_SHA1 - select CRYPTO_SHA256 - depends on SPARC64 - help - Each core of a Niagara2 processor contains a Stream - Processing Unit, which itself contains several cryptographic - sub-units. One set provides the Modular Arithmetic Unit, - used for SSL offload. The other set provides the Cipher - Group, which can perform encryption, decryption, hashing, - checksumming, and raw copies. - -config CRYPTO_DEV_HIFN_795X - tristate "Driver HIFN 795x crypto accelerator chips" - select CRYPTO_DES - select CRYPTO_BLKCIPHER - select HW_RANDOM if CRYPTO_DEV_HIFN_795X_RNG - depends on PCI - depends on !ARCH_DMA_ADDR_T_64BIT - help - This option allows you to have support for HIFN 795x crypto adapters. - -config CRYPTO_DEV_HIFN_795X_RNG - bool "HIFN 795x random number generator" - depends on CRYPTO_DEV_HIFN_795X - help - Select this option if you want to enable the random number generator - on the HIFN 795x crypto adapters. - -source drivers/crypto/caam/Kconfig - -config CRYPTO_DEV_TALITOS - tristate "Talitos Freescale Security Engine (SEC)" - select CRYPTO_AEAD - select CRYPTO_AUTHENC - select CRYPTO_BLKCIPHER - select CRYPTO_HASH - select HW_RANDOM - depends on FSL_SOC - help - Say 'Y' here to use the Freescale Security Engine (SEC) - to offload cryptographic algorithm computation. - - The Freescale SEC is present on PowerQUICC 'E' processors, such - as the MPC8349E and MPC8548E. - - To compile this driver as a module, choose M here: the module - will be called talitos. - -config CRYPTO_DEV_TALITOS1 - bool "SEC1 (SEC 1.0 and SEC Lite 1.2)" - depends on CRYPTO_DEV_TALITOS - depends on PPC_8xx || PPC_82xx - default y - help - Say 'Y' here to use the Freescale Security Engine (SEC) version 1.0 - found on MPC82xx or the Freescale Security Engine (SEC Lite) - version 1.2 found on MPC8xx - -config CRYPTO_DEV_TALITOS2 - bool "SEC2+ (SEC version 2.0 or upper)" - depends on CRYPTO_DEV_TALITOS - default y if !PPC_8xx - help - Say 'Y' here to use the Freescale Security Engine (SEC) - version 2 and following as found on MPC83xx, MPC85xx, etc ... - -config CRYPTO_DEV_IXP4XX - tristate "Driver for IXP4xx crypto hardware acceleration" - depends on ARCH_IXP4XX && IXP4XX_QMGR && IXP4XX_NPE - select CRYPTO_DES - select CRYPTO_AEAD - select CRYPTO_AUTHENC - select CRYPTO_BLKCIPHER - help - Driver for the IXP4xx NPE crypto engine. - -config CRYPTO_DEV_PPC4XX - tristate "Driver AMCC PPC4xx crypto accelerator" - depends on PPC && 4xx - select CRYPTO_HASH - select CRYPTO_BLKCIPHER - help - This option allows you to have support for AMCC crypto acceleration. - -config HW_RANDOM_PPC4XX - bool "PowerPC 4xx generic true random number generator support" - depends on CRYPTO_DEV_PPC4XX && HW_RANDOM - default y - ---help--- - This option provides the kernel-side support for the TRNG hardware - found in the security function of some PowerPC 4xx SoCs. - -config CRYPTO_DEV_OMAP_SHAM - tristate "Support for OMAP MD5/SHA1/SHA2 hw accelerator" - depends on ARCH_OMAP2PLUS - select CRYPTO_SHA1 - select CRYPTO_MD5 - select CRYPTO_SHA256 - select CRYPTO_SHA512 - select CRYPTO_HMAC - help - OMAP processors have MD5/SHA1/SHA2 hw accelerator. Select this if you - want to use the OMAP module for MD5/SHA1/SHA2 algorithms. - -config CRYPTO_DEV_OMAP_AES - tristate "Support for OMAP AES hw engine" - depends on ARCH_OMAP2 || ARCH_OMAP3 || ARCH_OMAP2PLUS - select CRYPTO_AES - select CRYPTO_BLKCIPHER - select CRYPTO_ENGINE - select CRYPTO_CBC - select CRYPTO_ECB - select CRYPTO_CTR - help - OMAP processors have AES module accelerator. Select this if you - want to use the OMAP module for AES algorithms. - -config CRYPTO_DEV_OMAP_DES - tristate "Support for OMAP DES/3DES hw engine" - depends on ARCH_OMAP2PLUS - select CRYPTO_DES - select CRYPTO_BLKCIPHER - select CRYPTO_ENGINE - help - OMAP processors have DES/3DES module accelerator. Select this if you - want to use the OMAP module for DES and 3DES algorithms. Currently - the ECB and CBC modes of operation are supported by the driver. Also - accesses made on unaligned boundaries are supported. - -config CRYPTO_DEV_PICOXCELL - tristate "Support for picoXcell IPSEC and Layer2 crypto engines" - depends on ARCH_PICOXCELL && HAVE_CLK - select CRYPTO_AEAD - select CRYPTO_AES - select CRYPTO_AUTHENC - select CRYPTO_BLKCIPHER - select CRYPTO_DES - select CRYPTO_CBC - select CRYPTO_ECB - select CRYPTO_SEQIV - help - This option enables support for the hardware offload engines in the - Picochip picoXcell SoC devices. Select this for IPSEC ESP offload - and for 3gpp Layer 2 ciphering support. - - Saying m here will build a module named pipcoxcell_crypto. - -config CRYPTO_DEV_SAHARA - tristate "Support for SAHARA crypto accelerator" - depends on ARCH_MXC && OF - select CRYPTO_BLKCIPHER - select CRYPTO_AES - select CRYPTO_ECB - help - This option enables support for the SAHARA HW crypto accelerator - found in some Freescale i.MX chips. - -config CRYPTO_DEV_MXC_SCC - tristate "Support for Freescale Security Controller (SCC)" - depends on ARCH_MXC && OF - select CRYPTO_BLKCIPHER - select CRYPTO_DES - help - This option enables support for the Security Controller (SCC) - found in Freescale i.MX25 chips. - -config CRYPTO_DEV_S5P - tristate "Support for Samsung S5PV210/Exynos crypto accelerator" - depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST - depends on HAS_IOMEM && HAS_DMA - select CRYPTO_AES - select CRYPTO_BLKCIPHER - help - This option allows you to have support for S5P crypto acceleration. - Select this to offload Samsung S5PV210 or S5PC110, Exynos from AES - algorithms execution. - -config CRYPTO_DEV_NX - bool "Support for IBM PowerPC Nest (NX) cryptographic acceleration" - depends on PPC64 - help - This enables support for the NX hardware cryptographic accelerator - coprocessor that is in IBM PowerPC P7+ or later processors. This - does not actually enable any drivers, it only allows you to select - which acceleration type (encryption and/or compression) to enable. - -if CRYPTO_DEV_NX - source "drivers/crypto/nx/Kconfig" -endif - -config CRYPTO_DEV_UX500 - tristate "Driver for ST-Ericsson UX500 crypto hardware acceleration" - depends on ARCH_U8500 - help - Driver for ST-Ericsson UX500 crypto engine. - -if CRYPTO_DEV_UX500 - source "drivers/crypto/ux500/Kconfig" -endif # if CRYPTO_DEV_UX500 - -config CRYPTO_DEV_BFIN_CRC - tristate "Support for Blackfin CRC hardware" - depends on BF60x - help - Newer Blackfin processors have CRC hardware. Select this if you - want to use the Blackfin CRC module. - -config CRYPTO_DEV_ATMEL_AES - tristate "Support for Atmel AES hw accelerator" - depends on HAS_DMA - depends on AT_XDMAC || AT_HDMAC || COMPILE_TEST - select CRYPTO_AES - select CRYPTO_AEAD - select CRYPTO_BLKCIPHER - help - Some Atmel processors have AES hw accelerator. - Select this if you want to use the Atmel module for - AES algorithms. - - To compile this driver as a module, choose M here: the module - will be called atmel-aes. - -config CRYPTO_DEV_ATMEL_TDES - tristate "Support for Atmel DES/TDES hw accelerator" - depends on ARCH_AT91 - select CRYPTO_DES - select CRYPTO_BLKCIPHER - help - Some Atmel processors have DES/TDES hw accelerator. - Select this if you want to use the Atmel module for - DES/TDES algorithms. - - To compile this driver as a module, choose M here: the module - will be called atmel-tdes. - -config CRYPTO_DEV_ATMEL_SHA - tristate "Support for Atmel SHA hw accelerator" - depends on ARCH_AT91 - select CRYPTO_HASH - help - Some Atmel processors have SHA1/SHA224/SHA256/SHA384/SHA512 - hw accelerator. - Select this if you want to use the Atmel module for - SHA1/SHA224/SHA256/SHA384/SHA512 algorithms. - - To compile this driver as a module, choose M here: the module - will be called atmel-sha. - -config CRYPTO_DEV_CCP - bool "Support for AMD Cryptographic Coprocessor" - depends on ((X86 && PCI) || (ARM64 && (OF_ADDRESS || ACPI))) && HAS_IOMEM - help - The AMD Cryptographic Coprocessor provides hardware offload support - for encryption, hashing and related operations. - -if CRYPTO_DEV_CCP - source "drivers/crypto/ccp/Kconfig" -endif - -config CRYPTO_DEV_MXS_DCP - tristate "Support for Freescale MXS DCP" - depends on (ARCH_MXS || ARCH_MXC) - select STMP_DEVICE - select CRYPTO_CBC - select CRYPTO_ECB - select CRYPTO_AES - select CRYPTO_BLKCIPHER - select CRYPTO_HASH - help - The Freescale i.MX23/i.MX28 has SHA1/SHA256 and AES128 CBC/ECB - co-processor on the die. - - To compile this driver as a module, choose M here: the module - will be called mxs-dcp. - -source "drivers/crypto/qat/Kconfig" - -config CRYPTO_DEV_QCE - tristate "Qualcomm crypto engine accelerator" - depends on (ARCH_QCOM || COMPILE_TEST) && HAS_DMA && HAS_IOMEM - select CRYPTO_AES - select CRYPTO_DES - select CRYPTO_ECB - select CRYPTO_CBC - select CRYPTO_XTS - select CRYPTO_CTR - select CRYPTO_BLKCIPHER - help - This driver supports Qualcomm crypto engine accelerator - hardware. To compile this driver as a module, choose M here. The - module will be called qcrypto. - -config CRYPTO_DEV_VMX - bool "Support for VMX cryptographic acceleration instructions" - depends on PPC64 && VSX - help - Support for VMX cryptographic acceleration instructions. - -source "drivers/crypto/vmx/Kconfig" - -config CRYPTO_DEV_IMGTEC_HASH - tristate "Imagination Technologies hardware hash accelerator" - depends on MIPS || COMPILE_TEST - depends on HAS_DMA - select CRYPTO_MD5 - select CRYPTO_SHA1 - select CRYPTO_SHA256 - select CRYPTO_HASH - help - This driver interfaces with the Imagination Technologies - hardware hash accelerator. Supporting MD5/SHA1/SHA224/SHA256 - hashing algorithms. - -config CRYPTO_DEV_SUN4I_SS - tristate "Support for Allwinner Security System cryptographic accelerator" - depends on ARCH_SUNXI && !64BIT - select CRYPTO_MD5 - select CRYPTO_SHA1 - select CRYPTO_AES - select CRYPTO_DES - select CRYPTO_BLKCIPHER - help - Some Allwinner SoC have a crypto accelerator named - Security System. Select this if you want to use it. - The Security System handle AES/DES/3DES ciphers in CBC mode - and SHA1 and MD5 hash algorithms. - - To compile this driver as a module, choose M here: the module - will be called sun4i-ss. - -config CRYPTO_DEV_ROCKCHIP - tristate "Rockchip's Cryptographic Engine driver" - depends on OF && ARCH_ROCKCHIP - select CRYPTO_AES - select CRYPTO_DES - select CRYPTO_MD5 - select CRYPTO_SHA1 - select CRYPTO_SHA256 - select CRYPTO_HASH - select CRYPTO_BLKCIPHER - - help - This driver interfaces with the hardware crypto accelerator. - Supporting cbc/ecb chainmode, and aes/des/des3_ede cipher mode. - -source "drivers/crypto/chelsio/Kconfig" - -endif # CRYPTO_HW diff --git a/src/linux/drivers/crypto/Makefile b/src/linux/drivers/crypto/Makefile deleted file mode 100644 index ad7250f..0000000 --- a/src/linux/drivers/crypto/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -obj-$(CONFIG_CRYPTO_DEV_ATMEL_AES) += atmel-aes.o -obj-$(CONFIG_CRYPTO_DEV_ATMEL_SHA) += atmel-sha.o -obj-$(CONFIG_CRYPTO_DEV_ATMEL_TDES) += atmel-tdes.o -obj-$(CONFIG_CRYPTO_DEV_BFIN_CRC) += bfin_crc.o -obj-$(CONFIG_CRYPTO_DEV_CCP) += ccp/ -obj-$(CONFIG_CRYPTO_DEV_FSL_CAAM) += caam/ -obj-$(CONFIG_CRYPTO_DEV_GEODE) += geode-aes.o -obj-$(CONFIG_CRYPTO_DEV_HIFN_795X) += hifn_795x.o -obj-$(CONFIG_CRYPTO_DEV_IMGTEC_HASH) += img-hash.o -obj-$(CONFIG_CRYPTO_DEV_IXP4XX) += ixp4xx_crypto.o -obj-$(CONFIG_CRYPTO_DEV_MV_CESA) += mv_cesa.o -obj-$(CONFIG_CRYPTO_DEV_MARVELL_CESA) += marvell/ -obj-$(CONFIG_CRYPTO_DEV_MXS_DCP) += mxs-dcp.o -obj-$(CONFIG_CRYPTO_DEV_NIAGARA2) += n2_crypto.o -n2_crypto-y := n2_core.o n2_asm.o -obj-$(CONFIG_CRYPTO_DEV_NX) += nx/ -obj-$(CONFIG_CRYPTO_DEV_OMAP_AES) += omap-aes.o -obj-$(CONFIG_CRYPTO_DEV_OMAP_DES) += omap-des.o -obj-$(CONFIG_CRYPTO_DEV_OMAP_SHAM) += omap-sham.o -obj-$(CONFIG_CRYPTO_DEV_PADLOCK_AES) += padlock-aes.o -obj-$(CONFIG_CRYPTO_DEV_PADLOCK_SHA) += padlock-sha.o -obj-$(CONFIG_CRYPTO_DEV_PICOXCELL) += picoxcell_crypto.o -obj-$(CONFIG_CRYPTO_DEV_PPC4XX) += amcc/ -obj-$(CONFIG_CRYPTO_DEV_S5P) += s5p-sss.o -obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o -obj-$(CONFIG_CRYPTO_DEV_MXC_SCC) += mxc-scc.o -obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o -obj-$(CONFIG_CRYPTO_DEV_UX500) += ux500/ -obj-$(CONFIG_CRYPTO_DEV_QAT) += qat/ -obj-$(CONFIG_CRYPTO_DEV_QCE) += qce/ -obj-$(CONFIG_CRYPTO_DEV_VMX) += vmx/ -obj-$(CONFIG_CRYPTO_DEV_SUN4I_SS) += sunxi-ss/ -obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP) += rockchip/ -obj-$(CONFIG_CRYPTO_DEV_CHELSIO) += chelsio/ diff --git a/src/linux/drivers/crypto/caam/Kconfig b/src/linux/drivers/crypto/caam/Kconfig deleted file mode 100644 index 64bf302..0000000 --- a/src/linux/drivers/crypto/caam/Kconfig +++ /dev/null @@ -1,136 +0,0 @@ -config CRYPTO_DEV_FSL_CAAM - tristate "Freescale CAAM-Multicore driver backend" - depends on FSL_SOC || ARCH_MXC || ARCH_LAYERSCAPE - help - Enables the driver module for Freescale's Cryptographic Accelerator - and Assurance Module (CAAM), also known as the SEC version 4 (SEC4). - This module creates job ring devices, and configures h/w - to operate as a DPAA component automatically, depending - on h/w feature availability. - - To compile this driver as a module, choose M here: the module - will be called caam. - -config CRYPTO_DEV_FSL_CAAM_JR - tristate "Freescale CAAM Job Ring driver backend" - depends on CRYPTO_DEV_FSL_CAAM - default y - help - Enables the driver module for Job Rings which are part of - Freescale's Cryptographic Accelerator - and Assurance Module (CAAM). This module adds a job ring operation - interface. - - To compile this driver as a module, choose M here: the module - will be called caam_jr. - -config CRYPTO_DEV_FSL_CAAM_RINGSIZE - int "Job Ring size" - depends on CRYPTO_DEV_FSL_CAAM_JR - range 2 9 - default "9" - help - Select size of Job Rings as a power of 2, within the - range 2-9 (ring size 4-512). - Examples: - 2 => 4 - 3 => 8 - 4 => 16 - 5 => 32 - 6 => 64 - 7 => 128 - 8 => 256 - 9 => 512 - -config CRYPTO_DEV_FSL_CAAM_INTC - bool "Job Ring interrupt coalescing" - depends on CRYPTO_DEV_FSL_CAAM_JR - help - Enable the Job Ring's interrupt coalescing feature. - - Note: the driver already provides adequate - interrupt coalescing in software. - -config CRYPTO_DEV_FSL_CAAM_INTC_COUNT_THLD - int "Job Ring interrupt coalescing count threshold" - depends on CRYPTO_DEV_FSL_CAAM_INTC - range 1 255 - default 255 - help - Select number of descriptor completions to queue before - raising an interrupt, in the range 1-255. Note that a selection - of 1 functionally defeats the coalescing feature, and a selection - equal or greater than the job ring size will force timeouts. - -config CRYPTO_DEV_FSL_CAAM_INTC_TIME_THLD - int "Job Ring interrupt coalescing timer threshold" - depends on CRYPTO_DEV_FSL_CAAM_INTC - range 1 65535 - default 2048 - help - Select number of bus clocks/64 to timeout in the case that one or - more descriptor completions are queued without reaching the count - threshold. Range is 1-65535. - -config CRYPTO_DEV_FSL_CAAM_CRYPTO_API - tristate "Register algorithm implementations with the Crypto API" - depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR - default y - select CRYPTO_AEAD - select CRYPTO_AUTHENC - select CRYPTO_BLKCIPHER - help - Selecting this will offload crypto for users of the - scatterlist crypto API (such as the linux native IPSec - stack) to the SEC4 via job ring. - - To compile this as a module, choose M here: the module - will be called caamalg. - -config CRYPTO_DEV_FSL_CAAM_AHASH_API - tristate "Register hash algorithm implementations with Crypto API" - depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR - default y - select CRYPTO_HASH - help - Selecting this will offload ahash for users of the - scatterlist crypto API to the SEC4 via job ring. - - To compile this as a module, choose M here: the module - will be called caamhash. - -config CRYPTO_DEV_FSL_CAAM_PKC_API - tristate "Register public key cryptography implementations with Crypto API" - depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR - default y - select CRYPTO_RSA - help - Selecting this will allow SEC Public key support for RSA. - Supported cryptographic primitives: encryption, decryption, - signature and verification. - To compile this as a module, choose M here: the module - will be called caam_pkc. - -config CRYPTO_DEV_FSL_CAAM_RNG_API - tristate "Register caam device for hwrng API" - depends on CRYPTO_DEV_FSL_CAAM && CRYPTO_DEV_FSL_CAAM_JR - default y - select CRYPTO_RNG - select HW_RANDOM - help - Selecting this will register the SEC4 hardware rng to - the hw_random API for suppying the kernel entropy pool. - - To compile this as a module, choose M here: the module - will be called caamrng. - -config CRYPTO_DEV_FSL_CAAM_IMX - def_bool SOC_IMX6 || SOC_IMX7D - depends on CRYPTO_DEV_FSL_CAAM - -config CRYPTO_DEV_FSL_CAAM_DEBUG - bool "Enable debug output in CAAM driver" - depends on CRYPTO_DEV_FSL_CAAM - help - Selecting this will enable printing of various debug - information in the CAAM driver. diff --git a/src/linux/drivers/crypto/ccp/Kconfig b/src/linux/drivers/crypto/ccp/Kconfig deleted file mode 100644 index 2238f77..0000000 --- a/src/linux/drivers/crypto/ccp/Kconfig +++ /dev/null @@ -1,26 +0,0 @@ -config CRYPTO_DEV_CCP_DD - tristate "Cryptographic Coprocessor device driver" - depends on CRYPTO_DEV_CCP - default m - select HW_RANDOM - select DMA_ENGINE - select DMADEVICES - select CRYPTO_SHA1 - select CRYPTO_SHA256 - help - Provides the interface to use the AMD Cryptographic Coprocessor - which can be used to offload encryption operations such as SHA, - AES and more. If you choose 'M' here, this module will be called - ccp. - -config CRYPTO_DEV_CCP_CRYPTO - tristate "Encryption and hashing offload support" - depends on CRYPTO_DEV_CCP_DD - default m - select CRYPTO_HASH - select CRYPTO_BLKCIPHER - select CRYPTO_AUTHENC - help - Support for using the cryptographic API with the AMD Cryptographic - Coprocessor. This module supports offload of SHA and AES algorithms. - If you choose 'M' here, this module will be called ccp_crypto. diff --git a/src/linux/drivers/crypto/chelsio/Kconfig b/src/linux/drivers/crypto/chelsio/Kconfig deleted file mode 100644 index 4ce67fb..0000000 --- a/src/linux/drivers/crypto/chelsio/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -config CRYPTO_DEV_CHELSIO - tristate "Chelsio Crypto Co-processor Driver" - depends on CHELSIO_T4 - select CRYPTO_SHA1 - select CRYPTO_SHA256 - select CRYPTO_SHA512 - ---help--- - The Chelsio Crypto Co-processor driver for T6 adapters. - - For general information about Chelsio and our products, visit - our website at . - - For customer support, please visit our customer support page at - . - - Please send feedback to . - - To compile this driver as a module, choose M here: the module - will be called chcr. diff --git a/src/linux/drivers/crypto/nx/Kconfig b/src/linux/drivers/crypto/nx/Kconfig deleted file mode 100644 index ad7552a..0000000 --- a/src/linux/drivers/crypto/nx/Kconfig +++ /dev/null @@ -1,48 +0,0 @@ - -config CRYPTO_DEV_NX_ENCRYPT - tristate "Encryption acceleration support on pSeries platform" - depends on PPC_PSERIES && IBMVIO && !CPU_LITTLE_ENDIAN - default y - select CRYPTO_AES - select CRYPTO_CCM - help - Support for PowerPC Nest (NX) encryption acceleration. This - module supports acceleration for AES and SHA2 algorithms on - the pSeries platform. If you choose 'M' here, this module - will be called nx_crypto. - -config CRYPTO_DEV_NX_COMPRESS - tristate "Compression acceleration support" - default y - select CRYPTO_ALGAPI - select 842_DECOMPRESS - help - Support for PowerPC Nest (NX) compression acceleration. This - module supports acceleration for compressing memory with the 842 - algorithm using the cryptographic API. One of the platform - drivers must be selected also. If you choose 'M' here, this - module will be called nx_compress. - -if CRYPTO_DEV_NX_COMPRESS - -config CRYPTO_DEV_NX_COMPRESS_PSERIES - tristate "Compression acceleration support on pSeries platform" - depends on PPC_PSERIES && IBMVIO - default y - help - Support for PowerPC Nest (NX) compression acceleration. This - module supports acceleration for compressing memory with the 842 - algorithm. This supports NX hardware on the pSeries platform. - If you choose 'M' here, this module will be called nx_compress_pseries. - -config CRYPTO_DEV_NX_COMPRESS_POWERNV - tristate "Compression acceleration support on PowerNV platform" - depends on PPC_POWERNV - default y - help - Support for PowerPC Nest (NX) compression acceleration. This - module supports acceleration for compressing memory with the 842 - algorithm. This supports NX hardware on the PowerNV platform. - If you choose 'M' here, this module will be called nx_compress_powernv. - -endif diff --git a/src/linux/drivers/crypto/qat/Kconfig b/src/linux/drivers/crypto/qat/Kconfig deleted file mode 100644 index ce3cae4..0000000 --- a/src/linux/drivers/crypto/qat/Kconfig +++ /dev/null @@ -1,83 +0,0 @@ -config CRYPTO_DEV_QAT - tristate - select CRYPTO_AEAD - select CRYPTO_AUTHENC - select CRYPTO_BLKCIPHER - select CRYPTO_AKCIPHER - select CRYPTO_DH - select CRYPTO_HMAC - select CRYPTO_RSA - select CRYPTO_SHA1 - select CRYPTO_SHA256 - select CRYPTO_SHA512 - select FW_LOADER - -config CRYPTO_DEV_QAT_DH895xCC - tristate "Support for Intel(R) DH895xCC" - depends on X86 && PCI - select CRYPTO_DEV_QAT - help - Support for Intel(R) DH895xcc with Intel(R) QuickAssist Technology - for accelerating crypto and compression workloads. - - To compile this as a module, choose M here: the module - will be called qat_dh895xcc. - -config CRYPTO_DEV_QAT_C3XXX - tristate "Support for Intel(R) C3XXX" - depends on X86 && PCI - select CRYPTO_DEV_QAT - help - Support for Intel(R) C3xxx with Intel(R) QuickAssist Technology - for accelerating crypto and compression workloads. - - To compile this as a module, choose M here: the module - will be called qat_c3xxx. - -config CRYPTO_DEV_QAT_C62X - tristate "Support for Intel(R) C62X" - depends on X86 && PCI - select CRYPTO_DEV_QAT - help - Support for Intel(R) C62x with Intel(R) QuickAssist Technology - for accelerating crypto and compression workloads. - - To compile this as a module, choose M here: the module - will be called qat_c62x. - -config CRYPTO_DEV_QAT_DH895xCCVF - tristate "Support for Intel(R) DH895xCC Virtual Function" - depends on X86 && PCI - select PCI_IOV - select CRYPTO_DEV_QAT - - help - Support for Intel(R) DH895xcc with Intel(R) QuickAssist Technology - Virtual Function for accelerating crypto and compression workloads. - - To compile this as a module, choose M here: the module - will be called qat_dh895xccvf. - -config CRYPTO_DEV_QAT_C3XXXVF - tristate "Support for Intel(R) C3XXX Virtual Function" - depends on X86 && PCI - select PCI_IOV - select CRYPTO_DEV_QAT - help - Support for Intel(R) C3xxx with Intel(R) QuickAssist Technology - Virtual Function for accelerating crypto and compression workloads. - - To compile this as a module, choose M here: the module - will be called qat_c3xxxvf. - -config CRYPTO_DEV_QAT_C62XVF - tristate "Support for Intel(R) C62X Virtual Function" - depends on X86 && PCI - select PCI_IOV - select CRYPTO_DEV_QAT - help - Support for Intel(R) C62x with Intel(R) QuickAssist Technology - Virtual Function for accelerating crypto and compression workloads. - - To compile this as a module, choose M here: the module - will be called qat_c62xvf. diff --git a/src/linux/drivers/crypto/qat/qat_common/.gitignore b/src/linux/drivers/crypto/qat/qat_common/.gitignore deleted file mode 100644 index ee32837..0000000 --- a/src/linux/drivers/crypto/qat/qat_common/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*-asn1.[ch] diff --git a/src/linux/drivers/crypto/ux500/Kconfig b/src/linux/drivers/crypto/ux500/Kconfig deleted file mode 100644 index 0e338bf..0000000 --- a/src/linux/drivers/crypto/ux500/Kconfig +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright (C) ST-Ericsson SA 2010 -# Author: Shujuan Chen (shujuan.chen@stericsson.com) -# License terms: GNU General Public License (GPL) version 2 -# - -config CRYPTO_DEV_UX500_CRYP - tristate "UX500 crypto driver for CRYP block" - depends on CRYPTO_DEV_UX500 - select CRYPTO_ALGAPI - select CRYPTO_BLKCIPHER - select CRYPTO_DES - help - This selects the crypto driver for the UX500_CRYP hardware. It supports - AES-ECB, CBC and CTR with keys sizes of 128, 192 and 256 bit sizes. - -config CRYPTO_DEV_UX500_HASH - tristate "UX500 crypto driver for HASH block" - depends on CRYPTO_DEV_UX500 - select CRYPTO_HASH - select CRYPTO_SHA1 - select CRYPTO_SHA256 - help - This selects the hash driver for the UX500_HASH hardware. - Depends on UX500/STM DMA if running in DMA mode. - -config CRYPTO_DEV_UX500_DEBUG - bool "Activate ux500 platform debug-mode for crypto and hash block" - depends on CRYPTO_DEV_UX500_CRYP || CRYPTO_DEV_UX500_HASH - help - Say Y if you want to add debug prints to ux500_hash and - ux500_cryp devices. diff --git a/src/linux/drivers/crypto/vmx/.gitignore b/src/linux/drivers/crypto/vmx/.gitignore deleted file mode 100644 index af4a7ce..0000000 --- a/src/linux/drivers/crypto/vmx/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -aesp8-ppc.S -ghashp8-ppc.S diff --git a/src/linux/drivers/crypto/vmx/Kconfig b/src/linux/drivers/crypto/vmx/Kconfig deleted file mode 100644 index c3d524e..0000000 --- a/src/linux/drivers/crypto/vmx/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config CRYPTO_DEV_VMX_ENCRYPT - tristate "Encryption acceleration support on P8 CPU" - depends on CRYPTO_DEV_VMX - select CRYPTO_GHASH - default m - help - Support for VMX cryptographic acceleration instructions on Power8 CPU. - This module supports acceleration for AES and GHASH in hardware. If you - choose 'M' here, this module will be called vmx-crypto. diff --git a/src/linux/drivers/dax/Kconfig b/src/linux/drivers/dax/Kconfig deleted file mode 100644 index 3e2ab3b..0000000 --- a/src/linux/drivers/dax/Kconfig +++ /dev/null @@ -1,31 +0,0 @@ -menuconfig DEV_DAX - tristate "DAX: direct access to differentiated memory" - default m if NVDIMM_DAX - depends on TRANSPARENT_HUGEPAGE - help - Support raw access to differentiated (persistence, bandwidth, - latency...) memory via an mmap(2) capable character - device. Platform firmware or a device driver may identify a - platform memory resource that is differentiated from the - baseline memory pool. Mappings of a /dev/daxX.Y device impose - restrictions that make the mapping behavior deterministic. - -if DEV_DAX - -config DEV_DAX_PMEM - tristate "PMEM DAX: direct access to persistent memory" - depends on LIBNVDIMM && NVDIMM_DAX - default DEV_DAX - help - Support raw access to persistent memory. Note that this - driver consumes memory ranges allocated and exported by the - libnvdimm sub-system. - - Say Y if unsure - -config NR_DEV_DAX - int "Maximum number of Device-DAX instances" - default 32768 - range 256 2147483647 - -endif diff --git a/src/linux/drivers/dca/Kconfig b/src/linux/drivers/dca/Kconfig deleted file mode 100644 index 94f0364..0000000 --- a/src/linux/drivers/dca/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -# -# DCA server configuration -# - -config DCA - tristate - diff --git a/src/linux/drivers/devfreq/Kconfig b/src/linux/drivers/devfreq/Kconfig deleted file mode 100644 index 41254e7..0000000 --- a/src/linux/drivers/devfreq/Kconfig +++ /dev/null @@ -1,117 +0,0 @@ -menuconfig PM_DEVFREQ - bool "Generic Dynamic Voltage and Frequency Scaling (DVFS) support" - select SRCU - help - A device may have a list of frequencies and voltages available. - devfreq, a generic DVFS framework can be registered for a device - in order to let the governor provided to devfreq choose an - operating frequency based on the device driver's policy. - - Each device may have its own governor and policy. Devfreq can - reevaluate the device state periodically and/or based on the - notification to "nb", a notifier block, of devfreq. - - Like some CPUs with CPUfreq, a device may have multiple clocks. - However, because the clock frequencies of a single device are - determined by the single device's state, an instance of devfreq - is attached to a single device and returns a "representative" - clock frequency of the device, which is also attached - to a device by 1-to-1. The device registering devfreq takes the - responsibility to "interpret" the representative frequency and - to set its every clock accordingly with the "target" callback - given to devfreq. - - When OPP is used with the devfreq device, it is recommended to - register devfreq's nb to the OPP's notifier head. If OPP is - used with the devfreq device, you may use OPP helper - functions defined in devfreq.h. - -if PM_DEVFREQ - -comment "DEVFREQ Governors" - -config DEVFREQ_GOV_SIMPLE_ONDEMAND - tristate "Simple Ondemand" - help - Chooses frequency based on the recent load on the device. Works - similar as ONDEMAND governor of CPUFREQ does. A device with - Simple-Ondemand should be able to provide busy/total counter - values that imply the usage rate. A device may provide tuned - values to the governor with data field at devfreq_add_device(). - -config DEVFREQ_GOV_PERFORMANCE - tristate "Performance" - help - Sets the frequency at the maximum available frequency. - This governor always returns UINT_MAX as frequency so that - the DEVFREQ framework returns the highest frequency available - at any time. - -config DEVFREQ_GOV_POWERSAVE - tristate "Powersave" - help - Sets the frequency at the minimum available frequency. - This governor always returns 0 as frequency so that - the DEVFREQ framework returns the lowest frequency available - at any time. - -config DEVFREQ_GOV_USERSPACE - tristate "Userspace" - help - Sets the frequency at the user specified one. - This governor returns the user configured frequency if there - has been an input to /sys/devices/.../power/devfreq_set_freq. - Otherwise, the governor does not change the frequency - given at the initialization. - -config DEVFREQ_GOV_PASSIVE - tristate "Passive" - help - Sets the frequency based on the frequency of its parent devfreq - device. This governor does not change the frequency by itself - through sysfs entries. The passive governor recommends that - devfreq device uses the OPP table to get the frequency/voltage. - -comment "DEVFREQ Drivers" - -config ARM_EXYNOS_BUS_DEVFREQ - tristate "ARM EXYNOS Generic Memory Bus DEVFREQ Driver" - depends on ARCH_EXYNOS || COMPILE_TEST - select DEVFREQ_GOV_SIMPLE_ONDEMAND - select DEVFREQ_GOV_PASSIVE - select DEVFREQ_EVENT_EXYNOS_PPMU - select PM_DEVFREQ_EVENT - select PM_OPP - help - This adds the common DEVFREQ driver for Exynos Memory bus. Exynos - Memory bus has one more group of memory bus (e.g, MIF and INT block). - Each memory bus group could contain many memoby bus block. It reads - PPMU counters of memory controllers by using DEVFREQ-event device - and adjusts the operating frequencies and voltages with OPP support. - This does not yet operate with optimal voltages. - -config ARM_TEGRA_DEVFREQ - tristate "Tegra DEVFREQ Driver" - depends on ARCH_TEGRA_124_SOC - select DEVFREQ_GOV_SIMPLE_ONDEMAND - select PM_OPP - help - This adds the DEVFREQ driver for the Tegra family of SoCs. - It reads ACTMON counters of memory controllers and adjusts the - operating frequencies and voltages with OPP support. - -config ARM_RK3399_DMC_DEVFREQ - tristate "ARM RK3399 DMC DEVFREQ Driver" - depends on ARCH_ROCKCHIP - select DEVFREQ_EVENT_ROCKCHIP_DFI - select DEVFREQ_GOV_SIMPLE_ONDEMAND - select PM_DEVFREQ_EVENT - select PM_OPP - help - This adds the DEVFREQ driver for the RK3399 DMC(Dynamic Memory Controller). - It sets the frequency for the memory controller and reads the usage counts - from hardware. - -source "drivers/devfreq/event/Kconfig" - -endif # PM_DEVFREQ diff --git a/src/linux/drivers/devfreq/event/Kconfig b/src/linux/drivers/devfreq/event/Kconfig deleted file mode 100644 index cd94980..0000000 --- a/src/linux/drivers/devfreq/event/Kconfig +++ /dev/null @@ -1,41 +0,0 @@ -menuconfig PM_DEVFREQ_EVENT - bool "DEVFREQ-Event device Support" - help - The devfreq-event device provide the raw data and events which - indicate the current state of devfreq-event device. The provided - data from devfreq-event device is used to monitor the state of - device and determine the suitable size of resource to reduce the - wasted resource. - - The devfreq-event device can support the various type of events - (e.g., raw data, utilization, latency, bandwidth). The events - may be used by devfreq governor and other subsystem. - -if PM_DEVFREQ_EVENT - -config DEVFREQ_EVENT_EXYNOS_NOCP - tristate "EXYNOS NoC (Network On Chip) Probe DEVFREQ event Driver" - depends on ARCH_EXYNOS || COMPILE_TEST - select PM_OPP - select REGMAP_MMIO - help - This add the devfreq-event driver for Exynos SoC. It provides NoC - (Network on Chip) Probe counters to measure the bandwidth of AXI bus. - -config DEVFREQ_EVENT_EXYNOS_PPMU - tristate "EXYNOS PPMU (Platform Performance Monitoring Unit) DEVFREQ event Driver" - depends on ARCH_EXYNOS || COMPILE_TEST - select PM_OPP - help - This add the devfreq-event driver for Exynos SoC. It provides PPMU - (Platform Performance Monitoring Unit) counters to estimate the - utilization of each module. - -config DEVFREQ_EVENT_ROCKCHIP_DFI - tristate "ROCKCHIP DFI DEVFREQ event Driver" - depends on ARCH_ROCKCHIP - help - This add the devfreq-event driver for Rockchip SoC. It provides DFI - (DDR Monitor Module) driver to count ddr load. - -endif # PM_DEVFREQ_EVENT diff --git a/src/linux/drivers/dma-buf/Kconfig b/src/linux/drivers/dma-buf/Kconfig deleted file mode 100644 index 2585821..0000000 --- a/src/linux/drivers/dma-buf/Kconfig +++ /dev/null @@ -1,33 +0,0 @@ -menu "DMABUF options" - -config SYNC_FILE - bool "Explicit Synchronization Framework" - default n - select ANON_INODES - select DMA_SHARED_BUFFER - ---help--- - The Sync File Framework adds explicit syncronization via - userspace. It enables send/receive 'struct fence' objects to/from - userspace via Sync File fds for synchronization between drivers via - userspace components. It has been ported from Android. - - The first and main user for this is graphics in which a fence is - associated with a buffer. When a job is submitted to the GPU a fence - is attached to the buffer and is transferred via userspace, using Sync - Files fds, to the DRM driver for example. More details at - Documentation/sync_file.txt. - -config SW_SYNC - bool "Sync File Validation Framework" - default n - depends on SYNC_FILE - depends on DEBUG_FS - ---help--- - A sync object driver that uses a 32bit counter to coordinate - synchronization. Useful when there is no hardware primitive backing - the synchronization. - - WARNING: improper use of this can result in deadlocking kernel - drivers from userspace. Intended for test and debug only. - -endmenu diff --git a/src/linux/drivers/dma/Kconfig b/src/linux/drivers/dma/Kconfig deleted file mode 100644 index 141aefb..0000000 --- a/src/linux/drivers/dma/Kconfig +++ /dev/null @@ -1,604 +0,0 @@ -# -# DMA engine configuration -# - -menuconfig DMADEVICES - bool "DMA Engine support" - depends on HAS_DMA - help - DMA engines can do asynchronous data transfers without - involving the host CPU. Currently, this framework can be - used to offload memory copies in the network stack and - RAID operations in the MD driver. This menu only presents - DMA Device drivers supported by the configured arch, it may - be empty in some cases. - -config DMADEVICES_DEBUG - bool "DMA Engine debugging" - depends on DMADEVICES != n - help - This is an option for use by developers; most people should - say N here. This enables DMA engine core and driver debugging. - -config DMADEVICES_VDEBUG - bool "DMA Engine verbose debugging" - depends on DMADEVICES_DEBUG != n - help - This is an option for use by developers; most people should - say N here. This enables deeper (more verbose) debugging of - the DMA engine core and drivers. - - -if DMADEVICES - -comment "DMA Devices" - -#core -config ASYNC_TX_ENABLE_CHANNEL_SWITCH - bool - -config ARCH_HAS_ASYNC_TX_FIND_CHANNEL - bool - -config DMA_ENGINE - bool - -config DMA_VIRTUAL_CHANNELS - tristate - -config DMA_ACPI - def_bool y - depends on ACPI - -config DMA_OF - def_bool y - depends on OF - select DMA_ENGINE - -#devices -config AMBA_PL08X - bool "ARM PrimeCell PL080 or PL081 support" - depends on ARM_AMBA - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Platform has a PL08x DMAC device - which can provide DMA engine support - -config AMCC_PPC440SPE_ADMA - tristate "AMCC PPC440SPe ADMA support" - depends on 440SPe || 440SP - select DMA_ENGINE - select DMA_ENGINE_RAID - select ARCH_HAS_ASYNC_TX_FIND_CHANNEL - select ASYNC_TX_ENABLE_CHANNEL_SWITCH - help - Enable support for the AMCC PPC440SPe RAID engines. - -config AT_HDMAC - tristate "Atmel AHB DMA support" - depends on ARCH_AT91 - select DMA_ENGINE - help - Support the Atmel AHB DMA controller. - -config AT_XDMAC - tristate "Atmel XDMA support" - depends on ARCH_AT91 - select DMA_ENGINE - help - Support the Atmel XDMA controller. - -config AXI_DMAC - tristate "Analog Devices AXI-DMAC DMA support" - depends on MICROBLAZE || NIOS2 || ARCH_ZYNQ || ARCH_SOCFPGA || COMPILE_TEST - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Enable support for the Analog Devices AXI-DMAC peripheral. This DMA - controller is often used in Analog Device's reference designs for FPGA - platforms. - -config COH901318 - bool "ST-Ericsson COH901318 DMA support" - select DMA_ENGINE - depends on ARCH_U300 || COMPILE_TEST - help - Enable support for ST-Ericsson COH 901 318 DMA. - -config DMA_BCM2835 - tristate "BCM2835 DMA engine support" - depends on ARCH_BCM2835 - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - -config DMA_JZ4740 - tristate "JZ4740 DMA support" - depends on MACH_JZ4740 || COMPILE_TEST - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - -config DMA_JZ4780 - tristate "JZ4780 DMA support" - depends on MACH_JZ4780 || COMPILE_TEST - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - This selects support for the DMA controller in Ingenic JZ4780 SoCs. - If you have a board based on such a SoC and wish to use DMA for - devices which can use the DMA controller, say Y or M here. - -config DMA_OMAP - tristate "OMAP DMA support" - depends on ARCH_OMAP || COMPILE_TEST - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - select TI_DMA_CROSSBAR if (SOC_DRA7XX || COMPILE_TEST) - -config DMA_SA11X0 - tristate "SA-11x0 DMA support" - depends on ARCH_SA1100 || COMPILE_TEST - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Support the DMA engine found on Intel StrongARM SA-1100 and - SA-1110 SoCs. This DMA engine can only be used with on-chip - devices. - -config DMA_SUN4I - tristate "Allwinner A10 DMA SoCs support" - depends on MACH_SUN4I || MACH_SUN5I || MACH_SUN7I - default (MACH_SUN4I || MACH_SUN5I || MACH_SUN7I) - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Enable support for the DMA controller present in the sun4i, - sun5i and sun7i Allwinner ARM SoCs. - -config DMA_SUN6I - tristate "Allwinner A31 SoCs DMA support" - depends on MACH_SUN6I || MACH_SUN8I || COMPILE_TEST - depends on RESET_CONTROLLER - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Support for the DMA engine first found in Allwinner A31 SoCs. - -config EP93XX_DMA - bool "Cirrus Logic EP93xx DMA support" - depends on ARCH_EP93XX || COMPILE_TEST - select DMA_ENGINE - help - Enable support for the Cirrus Logic EP93xx M2P/M2M DMA controller. - -config FSL_DMA - tristate "Freescale Elo series DMA support" - depends on FSL_SOC - select DMA_ENGINE - select ASYNC_TX_ENABLE_CHANNEL_SWITCH - ---help--- - Enable support for the Freescale Elo series DMA controllers. - The Elo is the DMA controller on some mpc82xx and mpc83xx parts, the - EloPlus is on mpc85xx and mpc86xx and Pxxx parts, and the Elo3 is on - some Txxx and Bxxx parts. - -config FSL_EDMA - tristate "Freescale eDMA engine support" - depends on OF - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Support the Freescale eDMA engine with programmable channel - multiplexing capability for DMA request sources(slot). - This module can be found on Freescale Vybrid and LS-1 SoCs. - -config FSL_RAID - tristate "Freescale RAID engine Support" - depends on FSL_SOC && !ASYNC_TX_ENABLE_CHANNEL_SWITCH - select DMA_ENGINE - select DMA_ENGINE_RAID - ---help--- - Enable support for Freescale RAID Engine. RAID Engine is - available on some QorIQ SoCs (like P5020/P5040). It has - the capability to offload memcpy, xor and pq computation - for raid5/6. - -config IMG_MDC_DMA - tristate "IMG MDC support" - depends on MIPS || COMPILE_TEST - depends on MFD_SYSCON - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Enable support for the IMG multi-threaded DMA controller (MDC). - -config IMX_DMA - tristate "i.MX DMA support" - depends on ARCH_MXC - select DMA_ENGINE - help - Support the i.MX DMA engine. This engine is integrated into - Freescale i.MX1/21/27 chips. - -config IMX_SDMA - tristate "i.MX SDMA support" - depends on ARCH_MXC - select DMA_ENGINE - help - Support the i.MX SDMA engine. This engine is integrated into - Freescale i.MX25/31/35/51/53/6 chips. - -config INTEL_IDMA64 - tristate "Intel integrated DMA 64-bit support" - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Enable DMA support for Intel Low Power Subsystem such as found on - Intel Skylake PCH. - -config INTEL_IOATDMA - tristate "Intel I/OAT DMA support" - depends on PCI && X86_64 - select DMA_ENGINE - select DMA_ENGINE_RAID - select DCA - help - Enable support for the Intel(R) I/OAT DMA engine present - in recent Intel Xeon chipsets. - - Say Y here if you have such a chipset. - - If unsure, say N. - -config INTEL_IOP_ADMA - tristate "Intel IOP ADMA support" - depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IOP13XX - select DMA_ENGINE - select ASYNC_TX_ENABLE_CHANNEL_SWITCH - help - Enable support for the Intel(R) IOP Series RAID engines. - -config INTEL_MIC_X100_DMA - tristate "Intel MIC X100 DMA Driver" - depends on 64BIT && X86 && INTEL_MIC_BUS - select DMA_ENGINE - help - This enables DMA support for the Intel Many Integrated Core - (MIC) family of PCIe form factor coprocessor X100 devices that - run a 64 bit Linux OS. This driver will be used by both MIC - host and card drivers. - - If you are building host kernel with a MIC device or a card - kernel for a MIC device, then say M (recommended) or Y, else - say N. If unsure say N. - - More information about the Intel MIC family as well as the Linux - OS and tools for MIC to use with this driver are available from - . - -config K3_DMA - tristate "Hisilicon K3 DMA support" - depends on ARCH_HI3xxx || ARCH_HISI || COMPILE_TEST - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Support the DMA engine for Hisilicon K3 platform - devices. - -config LPC18XX_DMAMUX - bool "NXP LPC18xx/43xx DMA MUX for PL080" - depends on ARCH_LPC18XX || COMPILE_TEST - depends on OF && AMBA_PL08X - select MFD_SYSCON - help - Enable support for DMA on NXP LPC18xx/43xx platforms - with PL080 and multiplexed DMA request lines. - -config MMP_PDMA - bool "MMP PDMA support" - depends on ARCH_MMP || ARCH_PXA || COMPILE_TEST - select DMA_ENGINE - help - Support the MMP PDMA engine for PXA and MMP platform. - -config MMP_TDMA - bool "MMP Two-Channel DMA support" - depends on ARCH_MMP || COMPILE_TEST - select DMA_ENGINE - select MMP_SRAM if ARCH_MMP - select GENERIC_ALLOCATOR - help - Support the MMP Two-Channel DMA engine. - This engine used for MMP Audio DMA and pxa910 SQU. - It needs sram driver under mach-mmp. - -config MOXART_DMA - tristate "MOXART DMA support" - depends on ARCH_MOXART - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Enable support for the MOXA ART SoC DMA controller. - - Say Y here if you enabled MMP ADMA, otherwise say N. - -config MPC512X_DMA - tristate "Freescale MPC512x built-in DMA engine support" - depends on PPC_MPC512x || PPC_MPC831x - select DMA_ENGINE - ---help--- - Enable support for the Freescale MPC512x built-in DMA engine. - -config MV_XOR - bool "Marvell XOR engine support" - depends on PLAT_ORION || ARCH_MVEBU || COMPILE_TEST - select DMA_ENGINE - select DMA_ENGINE_RAID - select ASYNC_TX_ENABLE_CHANNEL_SWITCH - ---help--- - Enable support for the Marvell XOR engine. - -config MV_XOR_V2 - bool "Marvell XOR engine version 2 support " - depends on ARM64 - select DMA_ENGINE - select DMA_ENGINE_RAID - select ASYNC_TX_ENABLE_CHANNEL_SWITCH - select GENERIC_MSI_IRQ_DOMAIN - ---help--- - Enable support for the Marvell version 2 XOR engine. - - This engine provides acceleration for copy, XOR and RAID6 - operations, and is available on Marvell Armada 7K and 8K - platforms. - -config MXS_DMA - bool "MXS DMA support" - depends on SOC_IMX23 || SOC_IMX28 || SOC_IMX6Q || SOC_IMX6UL - select STMP_DEVICE - select DMA_ENGINE - help - Support the MXS DMA engine. This engine including APBH-DMA - and APBX-DMA is integrated into Freescale - i.MX23/28/MX6Q/MX6DL/MX6UL chips. - -config MX3_IPU - bool "MX3x Image Processing Unit support" - depends on ARCH_MXC - select DMA_ENGINE - default y - help - If you plan to use the Image Processing unit in the i.MX3x, say - Y here. If unsure, select Y. - -config MX3_IPU_IRQS - int "Number of dynamically mapped interrupts for IPU" - depends on MX3_IPU - range 2 137 - default 4 - help - Out of 137 interrupt sources on i.MX31 IPU only very few are used. - To avoid bloating the irq_desc[] array we allocate a sufficient - number of IRQ slots and map them dynamically to specific sources. - -config NBPFAXI_DMA - tristate "Renesas Type-AXI NBPF DMA support" - select DMA_ENGINE - depends on ARM || COMPILE_TEST - help - Support for "Type-AXI" NBPF DMA IPs from Renesas - -config PCH_DMA - tristate "Intel EG20T PCH / LAPIS Semicon IOH(ML7213/ML7223/ML7831) DMA" - depends on PCI && (X86_32 || COMPILE_TEST) - select DMA_ENGINE - help - Enable support for Intel EG20T PCH DMA engine. - - This driver also can be used for LAPIS Semiconductor IOH(Input/ - Output Hub), ML7213, ML7223 and ML7831. - ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is - for MP(Media Phone) use and ML7831 IOH is for general purpose use. - ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series. - ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH. - -config PL330_DMA - tristate "DMA API Driver for PL330" - select DMA_ENGINE - depends on ARM_AMBA - help - Select if your platform has one or more PL330 DMACs. - You need to provide platform specific settings via - platform_data for a dma-pl330 device. - -config PXA_DMA - bool "PXA DMA support" - depends on (ARCH_MMP || ARCH_PXA) - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Support the DMA engine for PXA. It is also compatible with MMP PDMA - platform. The internal DMA IP of all PXA variants is supported, with - 16 to 32 channels for peripheral to memory or memory to memory - transfers. - -config SIRF_DMA - tristate "CSR SiRFprimaII/SiRFmarco DMA support" - depends on ARCH_SIRF - select DMA_ENGINE - help - Enable support for the CSR SiRFprimaII DMA engine. - -config STE_DMA40 - bool "ST-Ericsson DMA40 support" - depends on ARCH_U8500 - select DMA_ENGINE - help - Support for ST-Ericsson DMA40 controller - -config STM32_DMA - bool "STMicroelectronics STM32 DMA support" - depends on ARCH_STM32 || COMPILE_TEST - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Enable support for the on-chip DMA controller on STMicroelectronics - STM32 MCUs. - If you have a board based on such a MCU and wish to use DMA say Y or M - here. - -config S3C24XX_DMAC - bool "Samsung S3C24XX DMA support" - depends on ARCH_S3C24XX || COMPILE_TEST - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Support for the Samsung S3C24XX DMA controller driver. The - DMA controller is having multiple DMA channels which can be - configured for different peripherals like audio, UART, SPI. - The DMA controller can transfer data from memory to peripheral, - periphal to memory, periphal to periphal and memory to memory. - -config TXX9_DMAC - tristate "Toshiba TXx9 SoC DMA support" - depends on MACH_TX49XX || MACH_TX39XX - select DMA_ENGINE - help - Support the TXx9 SoC internal DMA controller. This can be - integrated in chips such as the Toshiba TX4927/38/39. - -config TEGRA20_APB_DMA - bool "NVIDIA Tegra20 APB DMA support" - depends on ARCH_TEGRA - select DMA_ENGINE - help - Support for the NVIDIA Tegra20 APB DMA controller driver. The - DMA controller is having multiple DMA channel which can be - configured for different peripherals like audio, UART, SPI, - I2C etc which is in APB bus. - This DMA controller transfers data from memory to peripheral fifo - or vice versa. It does not support memory to memory data transfer. - -config TEGRA210_ADMA - bool "NVIDIA Tegra210 ADMA support" - depends on (ARCH_TEGRA_210_SOC || COMPILE_TEST) && PM_CLK - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Support for the NVIDIA Tegra210 ADMA controller driver. The - DMA controller has multiple DMA channels and is used to service - various audio clients in the Tegra210 audio processing engine - (APE). This DMA controller transfers data from memory to - peripheral and vice versa. It does not support memory to - memory data transfer. - -config TIMB_DMA - tristate "Timberdale FPGA DMA support" - depends on MFD_TIMBERDALE || COMPILE_TEST - select DMA_ENGINE - help - Enable support for the Timberdale FPGA DMA engine. - -config TI_CPPI41 - tristate "AM33xx CPPI41 DMA support" - depends on ARCH_OMAP - select DMA_ENGINE - help - The Communications Port Programming Interface (CPPI) 4.1 DMA engine - is currently used by the USB driver on AM335x platforms. - -config TI_DMA_CROSSBAR - bool - -config TI_EDMA - bool "TI EDMA support" - depends on ARCH_DAVINCI || ARCH_OMAP || ARCH_KEYSTONE || COMPILE_TEST - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - select TI_DMA_CROSSBAR if (ARCH_OMAP || COMPILE_TEST) - default n - help - Enable support for the TI EDMA controller. This DMA - engine is found on TI DaVinci and AM33xx parts. - -config XGENE_DMA - tristate "APM X-Gene DMA support" - depends on ARCH_XGENE || COMPILE_TEST - select DMA_ENGINE - select DMA_ENGINE_RAID - select ASYNC_TX_ENABLE_CHANNEL_SWITCH - help - Enable support for the APM X-Gene SoC DMA engine. - -config XILINX_DMA - tristate "Xilinx AXI DMAS Engine" - depends on (ARCH_ZYNQ || MICROBLAZE || ARM64) - select DMA_ENGINE - help - Enable support for Xilinx AXI VDMA Soft IP. - - AXI VDMA engine provides high-bandwidth direct memory access - between memory and AXI4-Stream video type target - peripherals including peripherals which support AXI4- - Stream Video Protocol. It has two stream interfaces/ - channels, Memory Mapped to Stream (MM2S) and Stream to - Memory Mapped (S2MM) for the data transfers. - AXI CDMA engine provides high-bandwidth direct memory access - between a memory-mapped source address and a memory-mapped - destination address. - AXI DMA engine provides high-bandwidth one dimensional direct - memory access between memory and AXI4-Stream target peripherals. - -config XILINX_ZYNQMP_DMA - tristate "Xilinx ZynqMP DMA Engine" - depends on (ARCH_ZYNQ || MICROBLAZE || ARM64) - select DMA_ENGINE - help - Enable support for Xilinx ZynqMP DMA controller. - -config ZX_DMA - tristate "ZTE ZX296702 DMA support" - depends on ARCH_ZX || COMPILE_TEST - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - help - Support the DMA engine for ZTE ZX296702 platform devices. - - -# driver files -source "drivers/dma/bestcomm/Kconfig" - -source "drivers/dma/qcom/Kconfig" - -source "drivers/dma/dw/Kconfig" - -source "drivers/dma/hsu/Kconfig" - -source "drivers/dma/sh/Kconfig" - -# clients -comment "DMA Clients" - depends on DMA_ENGINE - -config ASYNC_TX_DMA - bool "Async_tx: Offload support for the async_tx api" - depends on DMA_ENGINE - help - This allows the async_tx api to take advantage of offload engines for - memcpy, memset, xor, and raid6 p+q operations. If your platform has - a dma engine that can perform raid operations and you have enabled - MD_RAID456 say Y. - - If unsure, say N. - -config DMATEST - tristate "DMA Test client" - depends on DMA_ENGINE - help - Simple DMA test client. Say N unless you're debugging a - DMA Device driver. - -config DMA_ENGINE_RAID - bool - -endif diff --git a/src/linux/drivers/dma/bestcomm/Kconfig b/src/linux/drivers/dma/bestcomm/Kconfig deleted file mode 100644 index 29e4270..0000000 --- a/src/linux/drivers/dma/bestcomm/Kconfig +++ /dev/null @@ -1,36 +0,0 @@ -# -# Kconfig options for Bestcomm -# - -config PPC_BESTCOMM - tristate "Bestcomm DMA engine support" - depends on PPC_MPC52xx - default n - select PPC_LIB_RHEAP - help - BestComm is the name of the communication coprocessor found - on the Freescale MPC5200 family of processor. Its usage is - optional for some drivers (like ATA), but required for - others (like FEC). - - If you want to use drivers that require DMA operations, - answer Y or M. Otherwise say N. - -config PPC_BESTCOMM_ATA - tristate - depends on PPC_BESTCOMM - help - This option enables the support for the ATA task. - -config PPC_BESTCOMM_FEC - tristate - depends on PPC_BESTCOMM - help - This option enables the support for the FEC tasks. - -config PPC_BESTCOMM_GEN_BD - tristate - depends on PPC_BESTCOMM - help - This option enables the support for the GenBD tasks. - diff --git a/src/linux/drivers/dma/dw/Kconfig b/src/linux/drivers/dma/dw/Kconfig deleted file mode 100644 index e00c9b0..0000000 --- a/src/linux/drivers/dma/dw/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -# -# DMA engine configuration for dw -# - -config DW_DMAC_CORE - tristate - select DMA_ENGINE - -config DW_DMAC_BIG_ENDIAN_IO - bool - -config DW_DMAC - tristate "Synopsys DesignWare AHB DMA platform driver" - select DW_DMAC_CORE - select DW_DMAC_BIG_ENDIAN_IO if AVR32 - default y if CPU_AT32AP7000 - help - Support the Synopsys DesignWare AHB DMA controller. This - can be integrated in chips such as the Atmel AT32ap7000. - -config DW_DMAC_PCI - tristate "Synopsys DesignWare AHB DMA PCI driver" - depends on PCI - select DW_DMAC_CORE - help - Support the Synopsys DesignWare AHB DMA controller on the - platfroms that enumerate it as a PCI device. For example, - Intel Medfield has integrated this GPDMA controller. diff --git a/src/linux/drivers/dma/hsu/Kconfig b/src/linux/drivers/dma/hsu/Kconfig deleted file mode 100644 index c708417..0000000 --- a/src/linux/drivers/dma/hsu/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -# DMA engine configuration for hsu -config HSU_DMA - tristate - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - -config HSU_DMA_PCI - tristate - depends on HSU_DMA && PCI diff --git a/src/linux/drivers/dma/qcom/Kconfig b/src/linux/drivers/dma/qcom/Kconfig deleted file mode 100644 index a7761c4..0000000 --- a/src/linux/drivers/dma/qcom/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -config QCOM_BAM_DMA - tristate "QCOM BAM DMA support" - depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM) - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - ---help--- - Enable support for the QCOM BAM DMA controller. This controller - provides DMA capabilities for a variety of on-chip devices. - -config QCOM_HIDMA_MGMT - tristate "Qualcomm Technologies HIDMA Management support" - select DMA_ENGINE - help - Enable support for the Qualcomm Technologies HIDMA Management. - Each DMA device requires one management interface driver - for basic initialization before QCOM_HIDMA channel driver can - start managing the channels. In a virtualized environment, - the guest OS would run QCOM_HIDMA channel driver and the - host would run the QCOM_HIDMA_MGMT management driver. - -config QCOM_HIDMA - tristate "Qualcomm Technologies HIDMA Channel support" - select DMA_ENGINE - help - Enable support for the Qualcomm Technologies HIDMA controller. - The HIDMA controller supports optimized buffer copies - (user to kernel, kernel to kernel, etc.). It only supports - memcpy interface. The core is not intended for general - purpose slave DMA. diff --git a/src/linux/drivers/dma/sh/Kconfig b/src/linux/drivers/dma/sh/Kconfig deleted file mode 100644 index 6e0685f..0000000 --- a/src/linux/drivers/dma/sh/Kconfig +++ /dev/null @@ -1,63 +0,0 @@ -# -# DMA engine configuration for sh -# - -config RENESAS_DMA - bool - select DMA_ENGINE - -# -# DMA Engine Helpers -# - -config SH_DMAE_BASE - bool "Renesas SuperH DMA Engine support" - depends on SUPERH || ARCH_RENESAS || COMPILE_TEST - depends on !SUPERH || SH_DMA - depends on !SH_DMA_API - default y - select RENESAS_DMA - help - Enable support for the Renesas SuperH DMA controllers. - -# -# DMA Controllers -# - -config SH_DMAE - tristate "Renesas SuperH DMAC support" - depends on SH_DMAE_BASE - help - Enable support for the Renesas SuperH DMA controllers. - -if SH_DMAE - -config SH_DMAE_R8A73A4 - def_bool y - depends on ARCH_R8A73A4 - depends on OF - -endif - -config RCAR_DMAC - tristate "Renesas R-Car Gen2 DMA Controller" - depends on ARCH_RENESAS || COMPILE_TEST - select RENESAS_DMA - help - This driver supports the general purpose DMA controller found in the - Renesas R-Car second generation SoCs. - -config RENESAS_USB_DMAC - tristate "Renesas USB-DMA Controller" - depends on ARCH_RENESAS || COMPILE_TEST - select RENESAS_DMA - select DMA_VIRTUAL_CHANNELS - help - This driver supports the USB-DMA controller found in the Renesas - SoCs. - -config SUDMAC - tristate "Renesas SUDMAC support" - depends on SH_DMAE_BASE - help - Enable support for the Renesas SUDMAC controllers. diff --git a/src/linux/drivers/edac/Kconfig b/src/linux/drivers/edac/Kconfig deleted file mode 100644 index 82d85cc..0000000 --- a/src/linux/drivers/edac/Kconfig +++ /dev/null @@ -1,465 +0,0 @@ -# -# EDAC Kconfig -# Copyright (c) 2008 Doug Thompson www.softwarebitmaker.com -# Licensed and distributed under the GPL - -config EDAC_ATOMIC_SCRUB - bool - -config EDAC_SUPPORT - bool - -menuconfig EDAC - bool "EDAC (Error Detection And Correction) reporting" - depends on HAS_IOMEM && EDAC_SUPPORT - help - EDAC is designed to report errors in the core system. - These are low-level errors that are reported in the CPU or - supporting chipset or other subsystems: - memory errors, cache errors, PCI errors, thermal throttling, etc.. - If unsure, select 'Y'. - - If this code is reporting problems on your system, please - see the EDAC project web pages for more information at: - - - - and: - - - - There is also a mailing list for the EDAC project, which can - be found via the sourceforge page. - -if EDAC - -config EDAC_LEGACY_SYSFS - bool "EDAC legacy sysfs" - default y - help - Enable the compatibility sysfs nodes. - Use 'Y' if your edac utilities aren't ported to work with the newer - structures. - -config EDAC_DEBUG - bool "Debugging" - help - This turns on debugging information for the entire EDAC subsystem. - You do so by inserting edac_module with "edac_debug_level=x." Valid - levels are 0-4 (from low to high) and by default it is set to 2. - Usually you should select 'N' here. - -config EDAC_DECODE_MCE - tristate "Decode MCEs in human-readable form (only on AMD for now)" - depends on CPU_SUP_AMD && X86_MCE_AMD - default y - ---help--- - Enable this option if you want to decode Machine Check Exceptions - occurring on your machine in human-readable form. - - You should definitely say Y here in case you want to decode MCEs - which occur really early upon boot, before the module infrastructure - has been initialized. - -config EDAC_MM_EDAC - tristate "Main Memory EDAC (Error Detection And Correction) reporting" - select RAS - help - Some systems are able to detect and correct errors in main - memory. EDAC can report statistics on memory error - detection and correction (EDAC - or commonly referred to ECC - errors). EDAC will also try to decode where these errors - occurred so that a particular failing memory module can be - replaced. If unsure, select 'Y'. - -config EDAC_GHES - bool "Output ACPI APEI/GHES BIOS detected errors via EDAC" - depends on ACPI_APEI_GHES && (EDAC_MM_EDAC=y) - default y - help - Not all machines support hardware-driven error report. Some of those - provide a BIOS-driven error report mechanism via ACPI, using the - APEI/GHES driver. By enabling this option, the error reports provided - by GHES are sent to userspace via the EDAC API. - - When this option is enabled, it will disable the hardware-driven - mechanisms, if a GHES BIOS is detected, entering into the - "Firmware First" mode. - - It should be noticed that keeping both GHES and a hardware-driven - error mechanism won't work well, as BIOS will race with OS, while - reading the error registers. So, if you want to not use "Firmware - first" GHES error mechanism, you should disable GHES either at - compilation time or by passing "ghes.disable=1" Kernel parameter - at boot time. - - In doubt, say 'Y'. - -config EDAC_AMD64 - tristate "AMD64 (Opteron, Athlon64)" - depends on EDAC_MM_EDAC && AMD_NB && EDAC_DECODE_MCE - help - Support for error detection and correction of DRAM ECC errors on - the AMD64 families (>= K8) of memory controllers. - -config EDAC_AMD64_ERROR_INJECTION - bool "Sysfs HW Error injection facilities" - depends on EDAC_AMD64 - help - Recent Opterons (Family 10h and later) provide for Memory Error - Injection into the ECC detection circuits. The amd64_edac module - allows the operator/user to inject Uncorrectable and Correctable - errors into DRAM. - - When enabled, in each of the respective memory controller directories - (/sys/devices/system/edac/mc/mcX), there are 3 input files: - - - inject_section (0..3, 16-byte section of 64-byte cacheline), - - inject_word (0..8, 16-bit word of 16-byte section), - - inject_ecc_vector (hex ecc vector: select bits of inject word) - - In addition, there are two control files, inject_read and inject_write, - which trigger the DRAM ECC Read and Write respectively. - -config EDAC_AMD76X - tristate "AMD 76x (760, 762, 768)" - depends on EDAC_MM_EDAC && PCI && X86_32 - help - Support for error detection and correction on the AMD 76x - series of chipsets used with the Athlon processor. - -config EDAC_E7XXX - tristate "Intel e7xxx (e7205, e7500, e7501, e7505)" - depends on EDAC_MM_EDAC && PCI && X86_32 - help - Support for error detection and correction on the Intel - E7205, E7500, E7501 and E7505 server chipsets. - -config EDAC_E752X - tristate "Intel e752x (e7520, e7525, e7320) and 3100" - depends on EDAC_MM_EDAC && PCI && X86 - help - Support for error detection and correction on the Intel - E7520, E7525, E7320 server chipsets. - -config EDAC_I82443BXGX - tristate "Intel 82443BX/GX (440BX/GX)" - depends on EDAC_MM_EDAC && PCI && X86_32 - depends on BROKEN - help - Support for error detection and correction on the Intel - 82443BX/GX memory controllers (440BX/GX chipsets). - -config EDAC_I82875P - tristate "Intel 82875p (D82875P, E7210)" - depends on EDAC_MM_EDAC && PCI && X86_32 - help - Support for error detection and correction on the Intel - DP82785P and E7210 server chipsets. - -config EDAC_I82975X - tristate "Intel 82975x (D82975x)" - depends on EDAC_MM_EDAC && PCI && X86 - help - Support for error detection and correction on the Intel - DP82975x server chipsets. - -config EDAC_I3000 - tristate "Intel 3000/3010" - depends on EDAC_MM_EDAC && PCI && X86 - help - Support for error detection and correction on the Intel - 3000 and 3010 server chipsets. - -config EDAC_I3200 - tristate "Intel 3200" - depends on EDAC_MM_EDAC && PCI && X86 - help - Support for error detection and correction on the Intel - 3200 and 3210 server chipsets. - -config EDAC_IE31200 - tristate "Intel e312xx" - depends on EDAC_MM_EDAC && PCI && X86 - help - Support for error detection and correction on the Intel - E3-1200 based DRAM controllers. - -config EDAC_X38 - tristate "Intel X38" - depends on EDAC_MM_EDAC && PCI && X86 - help - Support for error detection and correction on the Intel - X38 server chipsets. - -config EDAC_I5400 - tristate "Intel 5400 (Seaburg) chipsets" - depends on EDAC_MM_EDAC && PCI && X86 - help - Support for error detection and correction the Intel - i5400 MCH chipset (Seaburg). - -config EDAC_I7CORE - tristate "Intel i7 Core (Nehalem) processors" - depends on EDAC_MM_EDAC && PCI && X86 && X86_MCE_INTEL - help - Support for error detection and correction the Intel - i7 Core (Nehalem) Integrated Memory Controller that exists on - newer processors like i7 Core, i7 Core Extreme, Xeon 35xx - and Xeon 55xx processors. - -config EDAC_I82860 - tristate "Intel 82860" - depends on EDAC_MM_EDAC && PCI && X86_32 - help - Support for error detection and correction on the Intel - 82860 chipset. - -config EDAC_R82600 - tristate "Radisys 82600 embedded chipset" - depends on EDAC_MM_EDAC && PCI && X86_32 - help - Support for error detection and correction on the Radisys - 82600 embedded chipset. - -config EDAC_I5000 - tristate "Intel Greencreek/Blackford chipset" - depends on EDAC_MM_EDAC && X86 && PCI - help - Support for error detection and correction the Intel - Greekcreek/Blackford chipsets. - -config EDAC_I5100 - tristate "Intel San Clemente MCH" - depends on EDAC_MM_EDAC && X86 && PCI - help - Support for error detection and correction the Intel - San Clemente MCH. - -config EDAC_I7300 - tristate "Intel Clarksboro MCH" - depends on EDAC_MM_EDAC && X86 && PCI - help - Support for error detection and correction the Intel - Clarksboro MCH (Intel 7300 chipset). - -config EDAC_SBRIDGE - tristate "Intel Sandy-Bridge/Ivy-Bridge/Haswell Integrated MC" - depends on EDAC_MM_EDAC && PCI && X86_64 && X86_MCE_INTEL - depends on PCI_MMCONFIG - help - Support for error detection and correction the Intel - Sandy Bridge, Ivy Bridge and Haswell Integrated Memory Controllers. - -config EDAC_SKX - tristate "Intel Skylake server Integrated MC" - depends on EDAC_MM_EDAC && PCI && X86_64 && X86_MCE_INTEL - depends on PCI_MMCONFIG - help - Support for error detection and correction the Intel - Skylake server Integrated Memory Controllers. - -config EDAC_MPC85XX - tristate "Freescale MPC83xx / MPC85xx" - depends on EDAC_MM_EDAC && FSL_SOC - help - Support for error detection and correction on the Freescale - MPC8349, MPC8560, MPC8540, MPC8548, T4240 - -config EDAC_LAYERSCAPE - tristate "Freescale Layerscape DDR" - depends on EDAC_MM_EDAC && ARCH_LAYERSCAPE - help - Support for error detection and correction on Freescale memory - controllers on Layerscape SoCs. - -config EDAC_MV64X60 - tristate "Marvell MV64x60" - depends on EDAC_MM_EDAC && MV64X60 - help - Support for error detection and correction on the Marvell - MV64360 and MV64460 chipsets. - -config EDAC_PASEMI - tristate "PA Semi PWRficient" - depends on EDAC_MM_EDAC && PCI - depends on PPC_PASEMI - help - Support for error detection and correction on PA Semi - PWRficient. - -config EDAC_CELL - tristate "Cell Broadband Engine memory controller" - depends on EDAC_MM_EDAC && PPC_CELL_COMMON - help - Support for error detection and correction on the - Cell Broadband Engine internal memory controller - on platform without a hypervisor - -config EDAC_PPC4XX - tristate "PPC4xx IBM DDR2 Memory Controller" - depends on EDAC_MM_EDAC && 4xx - help - This enables support for EDAC on the ECC memory used - with the IBM DDR2 memory controller found in various - PowerPC 4xx embedded processors such as the 405EX[r], - 440SP, 440SPe, 460EX, 460GT and 460SX. - -config EDAC_AMD8131 - tristate "AMD8131 HyperTransport PCI-X Tunnel" - depends on EDAC_MM_EDAC && PCI && PPC_MAPLE - help - Support for error detection and correction on the - AMD8131 HyperTransport PCI-X Tunnel chip. - Note, add more Kconfig dependency if it's adopted - on some machine other than Maple. - -config EDAC_AMD8111 - tristate "AMD8111 HyperTransport I/O Hub" - depends on EDAC_MM_EDAC && PCI && PPC_MAPLE - help - Support for error detection and correction on the - AMD8111 HyperTransport I/O Hub chip. - Note, add more Kconfig dependency if it's adopted - on some machine other than Maple. - -config EDAC_CPC925 - tristate "IBM CPC925 Memory Controller (PPC970FX)" - depends on EDAC_MM_EDAC && PPC64 - help - Support for error detection and correction on the - IBM CPC925 Bridge and Memory Controller, which is - a companion chip to the PowerPC 970 family of - processors. - -config EDAC_TILE - tristate "Tilera Memory Controller" - depends on EDAC_MM_EDAC && TILE - default y - help - Support for error detection and correction on the - Tilera memory controller. - -config EDAC_HIGHBANK_MC - tristate "Highbank Memory Controller" - depends on EDAC_MM_EDAC && ARCH_HIGHBANK - help - Support for error detection and correction on the - Calxeda Highbank memory controller. - -config EDAC_HIGHBANK_L2 - tristate "Highbank L2 Cache" - depends on EDAC_MM_EDAC && ARCH_HIGHBANK - help - Support for error detection and correction on the - Calxeda Highbank memory controller. - -config EDAC_OCTEON_PC - tristate "Cavium Octeon Primary Caches" - depends on EDAC_MM_EDAC && CPU_CAVIUM_OCTEON - help - Support for error detection and correction on the primary caches of - the cnMIPS cores of Cavium Octeon family SOCs. - -config EDAC_OCTEON_L2C - tristate "Cavium Octeon Secondary Caches (L2C)" - depends on EDAC_MM_EDAC && CAVIUM_OCTEON_SOC - help - Support for error detection and correction on the - Cavium Octeon family of SOCs. - -config EDAC_OCTEON_LMC - tristate "Cavium Octeon DRAM Memory Controller (LMC)" - depends on EDAC_MM_EDAC && CAVIUM_OCTEON_SOC - help - Support for error detection and correction on the - Cavium Octeon family of SOCs. - -config EDAC_OCTEON_PCI - tristate "Cavium Octeon PCI Controller" - depends on EDAC_MM_EDAC && PCI && CAVIUM_OCTEON_SOC - help - Support for error detection and correction on the - Cavium Octeon family of SOCs. - -config EDAC_ALTERA - bool "Altera SOCFPGA ECC" - depends on EDAC_MM_EDAC=y && ARCH_SOCFPGA - help - Support for error detection and correction on the - Altera SOCs. This must be selected for SDRAM ECC. - Note that the preloader must initialize the SDRAM - before loading the kernel. - -config EDAC_ALTERA_L2C - bool "Altera L2 Cache ECC" - depends on EDAC_ALTERA=y && CACHE_L2X0 - help - Support for error detection and correction on the - Altera L2 cache Memory for Altera SoCs. This option - requires L2 cache. - -config EDAC_ALTERA_OCRAM - bool "Altera On-Chip RAM ECC" - depends on EDAC_ALTERA=y && SRAM && GENERIC_ALLOCATOR - help - Support for error detection and correction on the - Altera On-Chip RAM Memory for Altera SoCs. - -config EDAC_ALTERA_ETHERNET - bool "Altera Ethernet FIFO ECC" - depends on EDAC_ALTERA=y - help - Support for error detection and correction on the - Altera Ethernet FIFO Memory for Altera SoCs. - -config EDAC_ALTERA_NAND - bool "Altera NAND FIFO ECC" - depends on EDAC_ALTERA=y && MTD_NAND_DENALI - help - Support for error detection and correction on the - Altera NAND FIFO Memory for Altera SoCs. - -config EDAC_ALTERA_DMA - bool "Altera DMA FIFO ECC" - depends on EDAC_ALTERA=y && PL330_DMA=y - help - Support for error detection and correction on the - Altera DMA FIFO Memory for Altera SoCs. - -config EDAC_ALTERA_USB - bool "Altera USB FIFO ECC" - depends on EDAC_ALTERA=y && USB_DWC2 - help - Support for error detection and correction on the - Altera USB FIFO Memory for Altera SoCs. - -config EDAC_ALTERA_QSPI - bool "Altera QSPI FIFO ECC" - depends on EDAC_ALTERA=y && SPI_CADENCE_QUADSPI - help - Support for error detection and correction on the - Altera QSPI FIFO Memory for Altera SoCs. - -config EDAC_ALTERA_SDMMC - bool "Altera SDMMC FIFO ECC" - depends on EDAC_ALTERA=y && MMC_DW - help - Support for error detection and correction on the - Altera SDMMC FIFO Memory for Altera SoCs. - -config EDAC_SYNOPSYS - tristate "Synopsys DDR Memory Controller" - depends on EDAC_MM_EDAC && ARCH_ZYNQ - help - Support for error detection and correction on the Synopsys DDR - memory controller. - -config EDAC_XGENE - tristate "APM X-Gene SoC" - depends on EDAC_MM_EDAC && (ARM64 || COMPILE_TEST) - help - Support for error detection and correction on the - APM X-Gene family of SOCs. - -endif # EDAC diff --git a/src/linux/drivers/eisa/.gitignore b/src/linux/drivers/eisa/.gitignore deleted file mode 100644 index 4b335c0..0000000 --- a/src/linux/drivers/eisa/.gitignore +++ /dev/null @@ -1 +0,0 @@ -devlist.h diff --git a/src/linux/drivers/extcon/Kconfig b/src/linux/drivers/extcon/Kconfig deleted file mode 100644 index 04788d9..0000000 --- a/src/linux/drivers/extcon/Kconfig +++ /dev/null @@ -1,135 +0,0 @@ -menuconfig EXTCON - tristate "External Connector Class (extcon) support" - help - Say Y here to enable external connector class (extcon) support. - This allows monitoring external connectors by userspace - via sysfs and uevent and supports external connectors with - multiple states; i.e., an extcon that may have multiple - cables attached. For example, an external connector of a device - may be used to connect an HDMI cable and a AC adaptor, and to - host USB ports. Many of 30-pin connectors including PDMI are - also good examples. - -if EXTCON - -comment "Extcon Device Drivers" - -config EXTCON_ADC_JACK - tristate "ADC Jack extcon support" - depends on IIO - help - Say Y here to enable extcon device driver based on ADC values. - -config EXTCON_ARIZONA - tristate "Wolfson Arizona EXTCON support" - depends on MFD_ARIZONA && INPUT && SND_SOC - help - Say Y here to enable support for external accessory detection - with Wolfson Arizona devices. These are audio CODECs with - advanced audio accessory detection support. - -config EXTCON_AXP288 - tristate "X-Power AXP288 EXTCON support" - depends on MFD_AXP20X && USB_PHY - help - Say Y here to enable support for USB peripheral detection - and USB MUX switching by X-Power AXP288 PMIC. - -config EXTCON_GPIO - tristate "GPIO extcon support" - depends on GPIOLIB || COMPILE_TEST - help - Say Y here to enable GPIO based extcon support. Note that GPIO - extcon supports single state per extcon instance. - -config EXTCON_MAX14577 - tristate "Maxim MAX14577/77836 EXTCON Support" - depends on MFD_MAX14577 - select IRQ_DOMAIN - select REGMAP_I2C - help - If you say yes here you get support for the MUIC device of - Maxim MAX14577/77836. The MAX14577/77836 MUIC is a USB port accessory - detector and switch. - -config EXTCON_MAX3355 - tristate "Maxim MAX3355 USB OTG EXTCON Support" - depends on GPIOLIB || COMPILE_TEST - help - If you say yes here you get support for the USB OTG role detection by - MAX3355. The MAX3355 chip integrates a charge pump and comparators to - enable a system with an integrated USB OTG dual-role transceiver to - function as an USB OTG dual-role device. - -config EXTCON_MAX77693 - tristate "Maxim MAX77693 EXTCON Support" - depends on MFD_MAX77693 && INPUT - select IRQ_DOMAIN - select REGMAP_I2C - help - If you say yes here you get support for the MUIC device of - Maxim MAX77693 PMIC. The MAX77693 MUIC is a USB port accessory - detector and switch. - -config EXTCON_MAX77843 - tristate "Maxim MAX77843 EXTCON Support" - depends on MFD_MAX77843 - select IRQ_DOMAIN - select REGMAP_I2C - help - If you say yes here you get support for the MUIC device of - Maxim MAX77843. The MAX77843 MUIC is a USB port accessory - detector add switch. - -config EXTCON_MAX8997 - tristate "Maxim MAX8997 EXTCON Support" - depends on MFD_MAX8997 && IRQ_DOMAIN - help - If you say yes here you get support for the MUIC device of - Maxim MAX8997 PMIC. The MAX8997 MUIC is a USB port accessory - detector and switch. - -config EXTCON_PALMAS - tristate "Palmas USB EXTCON support" - depends on MFD_PALMAS - help - Say Y here to enable support for USB peripheral and USB host - detection by palmas usb. - -config EXTCON_QCOM_SPMI_MISC - tristate "Qualcomm USB extcon support" - help - Say Y here to enable SPMI PMIC based USB cable detection - support on Qualcomm PMICs such as PM8941. - -config EXTCON_RT8973A - tristate "Richtek RT8973A EXTCON support" - depends on I2C - select IRQ_DOMAIN - select REGMAP_I2C - select REGMAP_IRQ - help - If you say yes here you get support for the MUIC device of - Richtek RT8973A. The RT8973A is a USB port accessory detector - and switch that is optimized to protect low voltage system - from abnormal high input voltage (up to 28V). - -config EXTCON_SM5502 - tristate "Silicon Mitus SM5502 EXTCON support" - depends on I2C - select IRQ_DOMAIN - select REGMAP_I2C - select REGMAP_IRQ - help - If you say yes here you get support for the MUIC device of - Silicon Mitus SM5502. The SM5502 is a USB port accessory - detector and switch. - -config EXTCON_USB_GPIO - tristate "USB GPIO extcon support" - depends on GPIOLIB || COMPILE_TEST - help - Say Y here to enable GPIO based USB cable detection extcon support. - Used typically if GPIO is used for USB ID pin detection. - -endif diff --git a/src/linux/drivers/firewire/Kconfig b/src/linux/drivers/firewire/Kconfig deleted file mode 100644 index 145974f..0000000 --- a/src/linux/drivers/firewire/Kconfig +++ /dev/null @@ -1,83 +0,0 @@ -menu "IEEE 1394 (FireWire) support" - depends on HAS_DMA - depends on PCI || COMPILE_TEST - # firewire-core does not depend on PCI but is - # not useful without PCI controller driver - -config FIREWIRE - tristate "FireWire driver stack" - select CRC_ITU_T - help - This is the new-generation IEEE 1394 (FireWire) driver stack - a.k.a. Juju, a new implementation designed for robustness and - simplicity. - See http://ieee1394.wiki.kernel.org/index.php/Juju_Migration - for information about migration from the older Linux 1394 stack - to the new driver stack. - - To compile this driver as a module, say M here: the module will be - called firewire-core. - -config FIREWIRE_OHCI - tristate "OHCI-1394 controllers" - depends on PCI && FIREWIRE && MMU - help - Enable this driver if you have a FireWire controller based - on the OHCI specification. For all practical purposes, this - is the only chipset in use, so say Y here. - - To compile this driver as a module, say M here: The module will be - called firewire-ohci. - -config FIREWIRE_SBP2 - tristate "Storage devices (SBP-2 protocol)" - depends on FIREWIRE && SCSI - help - This option enables you to use SBP-2 devices connected to a - FireWire bus. SBP-2 devices include storage devices like - harddisks and DVD drives, also some other FireWire devices - like scanners. - - To compile this driver as a module, say M here: The module will be - called firewire-sbp2. - - You should also enable support for disks, CD-ROMs, etc. in the SCSI - configuration section. - -config FIREWIRE_NET - tristate "IP networking over 1394" - depends on FIREWIRE && INET - help - This enables IPv4/IPv6 over IEEE 1394, providing IP connectivity - with other implementations of RFC 2734/3146 as found on several - operating systems. Multicast support is currently limited. - - To compile this driver as a module, say M here: The module will be - called firewire-net. - -config FIREWIRE_NOSY - tristate "Nosy - a FireWire traffic sniffer for PCILynx cards" - depends on PCI - help - Nosy is an IEEE 1394 packet sniffer that is used for protocol - analysis and in development of IEEE 1394 drivers, applications, - or firmwares. - - This driver lets you use a Texas Instruments PCILynx 1394 to PCI - link layer controller TSB12LV21/A/B as a low-budget bus analyzer. - PCILynx is a nowadays very rare IEEE 1394 controller which is - not OHCI 1394 compliant. - - The following cards are known to be based on PCILynx or PCILynx-2: - IOI IOI-1394TT (PCI card), Unibrain Fireboard 400 PCI Lynx-2 - (PCI card), Newer Technology FireWire 2 Go (CardBus card), - Apple Power Mac G3 blue & white and G4 with PCI graphics - (onboard controller). - - To compile this driver as a module, say M here: The module will be - called nosy. Source code of a userspace interface to nosy, called - nosy-dump, can be found in tools/firewire/ of the kernel sources. - - If unsure, say N. - -endmenu diff --git a/src/linux/drivers/firewire/Makefile b/src/linux/drivers/firewire/Makefile deleted file mode 100644 index e3870d5..0000000 --- a/src/linux/drivers/firewire/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# -# Makefile for the Linux IEEE 1394 implementation -# - -firewire-core-y += core-card.o core-cdev.o core-device.o \ - core-iso.o core-topology.o core-transaction.o -firewire-ohci-y += ohci.o -firewire-sbp2-y += sbp2.o -firewire-net-y += net.o - -obj-$(CONFIG_FIREWIRE) += firewire-core.o -obj-$(CONFIG_FIREWIRE_OHCI) += firewire-ohci.o -obj-$(CONFIG_FIREWIRE_SBP2) += firewire-sbp2.o -obj-$(CONFIG_FIREWIRE_NET) += firewire-net.o -obj-$(CONFIG_FIREWIRE_NOSY) += nosy.o -obj-$(CONFIG_PROVIDE_OHCI1394_DMA_INIT) += init_ohci1394_dma.o diff --git a/src/linux/drivers/firmware/Makefile b/src/linux/drivers/firmware/Makefile deleted file mode 100644 index 898ac41..0000000 --- a/src/linux/drivers/firmware/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -# -# Makefile for the linux kernel. -# -obj-$(CONFIG_ARM_PSCI_FW) += psci.o -obj-$(CONFIG_ARM_SCPI_PROTOCOL) += arm_scpi.o -obj-$(CONFIG_ARM_SCPI_POWER_DOMAIN) += scpi_pm_domain.o -obj-$(CONFIG_DMI) += dmi_scan.o -obj-$(CONFIG_DMI_SYSFS) += dmi-sysfs.o -obj-$(CONFIG_EDD) += edd.o -obj-$(CONFIG_EFI_PCDP) += pcdp.o -obj-$(CONFIG_DELL_RBU) += dell_rbu.o -obj-$(CONFIG_DCDBAS) += dcdbas.o -obj-$(CONFIG_DMIID) += dmi-id.o -obj-$(CONFIG_ISCSI_IBFT_FIND) += iscsi_ibft_find.o -obj-$(CONFIG_ISCSI_IBFT) += iscsi_ibft.o -obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.o -obj-$(CONFIG_RASPBERRYPI_FIRMWARE) += raspberrypi.o -obj-$(CONFIG_FW_CFG_SYSFS) += qemu_fw_cfg.o -obj-$(CONFIG_QCOM_SCM) += qcom_scm.o -obj-$(CONFIG_QCOM_SCM_64) += qcom_scm-64.o -obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o -CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a - -obj-y += broadcom/ -obj-y += meson/ -obj-$(CONFIG_GOOGLE_FIRMWARE) += google/ -obj-$(CONFIG_EFI) += efi/ -obj-$(CONFIG_UEFI_CPER) += efi/ diff --git a/src/linux/drivers/firmware/broadcom/Makefile b/src/linux/drivers/firmware/broadcom/Makefile deleted file mode 100644 index f93efc4..0000000 --- a/src/linux/drivers/firmware/broadcom/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-$(CONFIG_BCM47XX_NVRAM) += bcm47xx_nvram.o -obj-$(CONFIG_BCM47XX_SPROM) += bcm47xx_sprom.o diff --git a/src/linux/drivers/firmware/meson/Makefile b/src/linux/drivers/firmware/meson/Makefile deleted file mode 100644 index 9ab3884..0000000 --- a/src/linux/drivers/firmware/meson/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_MESON_SM) += meson_sm.o diff --git a/src/linux/drivers/fmc/Kconfig b/src/linux/drivers/fmc/Kconfig deleted file mode 100644 index 3a75f42..0000000 --- a/src/linux/drivers/fmc/Kconfig +++ /dev/null @@ -1,51 +0,0 @@ -# -# FMC (ANSI-VITA 57.1) bus support -# - -menuconfig FMC - tristate "FMC support" - help - - FMC (FPGA Mezzanine Carrier) is a mechanical and electrical - standard for mezzanine cards that plug into a carrier board. - This kernel subsystem supports the matching between carrier - and mezzanine based on identifiers stored in the internal I2C - EEPROM, as well as having carrier-independent drivers. - - The framework was born outside of the kernel and at this time - the off-tree code base is more complete. Code and documentation - is at git://ohwr.org/fmc-projects/fmc-bus.git . - -if FMC - -config FMC_FAKEDEV - tristate "FMC fake device (software testing)" - help - This is a fake carrier, bringing a default EEPROM content - that can be rewritten at run time and usef for matching - mezzanines. - -config FMC_TRIVIAL - tristate "FMC trivial mezzanine driver (software testing)" - help - This is a fake mezzanine driver, to show how FMC works and test it. - The driver also handles interrupts (we used it with a real carrier - before the mezzanines were produced) - -config FMC_WRITE_EEPROM - tristate "FMC mezzanine driver to write I2C EEPROM" - help - This driver matches every mezzanine device and can write the - internal EEPROM of the PCB, using the firmware loader to get - its binary and the function carrier->reprogram to actually do it. - It is useful when the mezzanines are produced. - -config FMC_CHARDEV - tristate "FMC mezzanine driver that registers a char device" - help - This driver matches every mezzanine device and allows user - space to read and write registers using a char device. It - can be used to write user-space drivers, or just get - acquainted with a mezzanine before writing its specific driver. - -endif # FMC diff --git a/src/linux/drivers/fpga/Kconfig b/src/linux/drivers/fpga/Kconfig deleted file mode 100644 index cd84934..0000000 --- a/src/linux/drivers/fpga/Kconfig +++ /dev/null @@ -1,31 +0,0 @@ -# -# FPGA framework configuration -# - -menu "FPGA Configuration Support" - -config FPGA - tristate "FPGA Configuration Framework" - help - Say Y here if you want support for configuring FPGAs from the - kernel. The FPGA framework adds a FPGA manager class and FPGA - manager drivers. - -if FPGA - -config FPGA_MGR_SOCFPGA - tristate "Altera SOCFPGA FPGA Manager" - depends on ARCH_SOCFPGA - help - FPGA manager driver support for Altera SOCFPGA. - -config FPGA_MGR_ZYNQ_FPGA - tristate "Xilinx Zynq FPGA" - depends on ARCH_ZYNQ || COMPILE_TEST - depends on HAS_DMA - help - FPGA manager driver support for Xilinx Zynq FPGAs. - -endif # FPGA - -endmenu diff --git a/src/linux/drivers/gpio/Kconfig b/src/linux/drivers/gpio/Kconfig deleted file mode 100644 index ed37e59..0000000 --- a/src/linux/drivers/gpio/Kconfig +++ /dev/null @@ -1,1214 +0,0 @@ -# -# GPIO infrastructure and drivers -# - -config ARCH_HAVE_CUSTOM_GPIO_H - bool - help - Selecting this config option from the architecture Kconfig allows - the architecture to provide a custom asm/gpio.h implementation - overriding the default implementations. New uses of this are - strongly discouraged. - -menuconfig GPIOLIB - bool "GPIO Support" - select ANON_INODES - help - This enables GPIO support through the generic GPIO library. - You only need to enable this, if you also want to enable - one or more of the GPIO drivers below. - - If unsure, say N. - -if GPIOLIB - -config OF_GPIO - def_bool y - depends on OF - depends on HAS_IOMEM - -config GPIO_ACPI - def_bool y - depends on ACPI - -config GPIOLIB_IRQCHIP - select IRQ_DOMAIN - bool - -config DEBUG_GPIO - bool "Debug GPIO calls" - depends on DEBUG_KERNEL - help - Say Y here to add some extra checks and diagnostics to GPIO calls. - These checks help ensure that GPIOs have been properly initialized - before they are used, and that sleeping calls are not made from - non-sleeping contexts. They can make bitbanged serial protocols - slower. The diagnostics help catch the type of setup errors - that are most common when setting up new platforms or boards. - -config GPIO_SYSFS - bool "/sys/class/gpio/... (sysfs interface)" - depends on SYSFS - help - Say Y here to add a sysfs interface for GPIOs. - - This is mostly useful to work around omissions in a system's - kernel support. Those are common in custom and semicustom - hardware assembled using standard kernels with a minimum of - custom patches. In those cases, userspace code may import - a given GPIO from the kernel, if no kernel driver requested it. - - Kernel drivers may also request that a particular GPIO be - exported to userspace; this can be useful when debugging. - -config GPIO_GENERIC - depends on HAS_IOMEM # Only for IOMEM drivers - tristate - -# put drivers in the right section, in alphabetical order - -# This symbol is selected by both I2C and SPI expanders -config GPIO_MAX730X - tristate - -menu "Memory mapped GPIO drivers" - depends on HAS_IOMEM - -config GPIO_74XX_MMIO - tristate "GPIO driver for 74xx-ICs with MMIO access" - depends on OF_GPIO - select GPIO_GENERIC - help - Say yes here to support GPIO functionality for 74xx-compatible ICs - with MMIO access. Compatible models include: - 1 bit: 741G125 (Input), 741G74 (Output) - 2 bits: 742G125 (Input), 7474 (Output) - 4 bits: 74125 (Input), 74175 (Output) - 6 bits: 74365 (Input), 74174 (Output) - 8 bits: 74244 (Input), 74273 (Output) - 16 bits: 741624 (Input), 7416374 (Output) - -config GPIO_ALTERA - tristate "Altera GPIO" - depends on OF_GPIO - select GPIOLIB_IRQCHIP - help - Say Y or M here to build support for the Altera PIO device. - - If driver is built as a module it will be called gpio-altera. - -config GPIO_AMDPT - tristate "AMD Promontory GPIO support" - depends on ACPI - select GPIO_GENERIC - help - driver for GPIO functionality on Promontory IOHub - Require ACPI ASL code to enumerate as a platform device. - -config GPIO_ASPEED - tristate "Aspeed GPIO support" - depends on (ARCH_ASPEED || COMPILE_TEST) && OF_GPIO - select GPIOLIB_IRQCHIP - help - Say Y here to support Aspeed AST2400 and AST2500 GPIO controllers. - -config GPIO_ATH79 - tristate "Atheros AR71XX/AR724X/AR913X GPIO support" - default y if ATH79 - depends on ATH79 || COMPILE_TEST - select GPIO_GENERIC - select GPIOLIB_IRQCHIP - help - Select this option to enable GPIO driver for - Atheros AR71XX/AR724X/AR913X SoC devices. - -config GPIO_AXP209 - tristate "X-Powers AXP209 PMIC GPIO Support" - depends on MFD_AXP20X - help - Say yes to enable GPIO support for the AXP209 PMIC - -config GPIO_BCM_KONA - bool "Broadcom Kona GPIO" - depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST) - help - Turn on GPIO support for Broadcom "Kona" chips. - -config GPIO_BRCMSTB - tristate "BRCMSTB GPIO support" - default y if (ARCH_BRCMSTB || BMIPS_GENERIC) - depends on OF_GPIO && (ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST) - select GPIO_GENERIC - select GPIOLIB_IRQCHIP - help - Say yes here to enable GPIO support for Broadcom STB (BCM7XXX) SoCs. - -config GPIO_CLPS711X - tristate "CLPS711X GPIO support" - depends on ARCH_CLPS711X || COMPILE_TEST - select GPIO_GENERIC - help - Say yes here to support GPIO on CLPS711X SoCs. - -config GPIO_DAVINCI - bool "TI Davinci/Keystone GPIO support" - default y if ARCH_DAVINCI - depends on ARM && (ARCH_DAVINCI || ARCH_KEYSTONE) - help - Say yes here to enable GPIO support for TI Davinci/Keystone SoCs. - -config GPIO_DWAPB - tristate "Synopsys DesignWare APB GPIO driver" - select GPIO_GENERIC - select GENERIC_IRQ_CHIP - help - Say Y or M here to build support for the Synopsys DesignWare APB - GPIO block. - -config GPIO_EM - tristate "Emma Mobile GPIO" - depends on ARM && OF_GPIO - help - Say yes here to support GPIO on Renesas Emma Mobile SoCs. - -config GPIO_EP93XX - def_bool y - depends on ARCH_EP93XX - select GPIO_GENERIC - -config GPIO_ETRAXFS - bool "Axis ETRAX FS General I/O" - depends on CRIS || COMPILE_TEST - depends on OF_GPIO - select GPIO_GENERIC - select GPIOLIB_IRQCHIP - help - Say yes here to support the GPIO controller on Axis ETRAX FS SoCs. - -config GPIO_GE_FPGA - bool "GE FPGA based GPIO" - depends on GE_FPGA - select GPIO_GENERIC - help - Support for common GPIO functionality provided on some GE Single Board - Computers. - - This driver provides basic support (configure as input or output, read - and write pin state) for GPIO implemented in a number of GE single - board computers. - -config GPIO_GENERIC_PLATFORM - tristate "Generic memory-mapped GPIO controller support (MMIO platform device)" - select GPIO_GENERIC - help - Say yes here to support basic platform_device memory-mapped GPIO controllers. - -config GPIO_GRGPIO - tristate "Aeroflex Gaisler GRGPIO support" - depends on OF_GPIO - select GPIO_GENERIC - select IRQ_DOMAIN - help - Select this to support Aeroflex Gaisler GRGPIO cores from the GRLIB - VHDL IP core library. - -config GPIO_ICH - tristate "Intel ICH GPIO" - depends on PCI && X86 - select MFD_CORE - select LPC_ICH - help - Say yes here to support the GPIO functionality of a number of Intel - ICH-based chipsets. Currently supported devices: ICH6, ICH7, ICH8 - ICH9, ICH10, Series 5/3400 (eg Ibex Peak), Series 6/C200 (eg - Cougar Point), NM10 (Tiger Point), and 3100 (Whitmore Lake). - - If unsure, say N. - -config GPIO_IOP - tristate "Intel IOP GPIO" - depends on ARCH_IOP32X || ARCH_IOP33X || COMPILE_TEST - select GPIO_GENERIC - help - Say yes here to support the GPIO functionality of a number of Intel - IOP32X or IOP33X. - - If unsure, say N. - -config GPIO_LOONGSON - bool "Loongson-2/3 GPIO support" - depends on CPU_LOONGSON2 || CPU_LOONGSON3 - help - driver for GPIO functionality on Loongson-2F/3A/3B processors. - -config GPIO_LPC18XX - tristate "NXP LPC18XX/43XX GPIO support" - default y if ARCH_LPC18XX - depends on OF_GPIO && (ARCH_LPC18XX || COMPILE_TEST) - help - Select this option to enable GPIO driver for - NXP LPC18XX/43XX devices. - -config GPIO_LYNXPOINT - tristate "Intel Lynxpoint GPIO support" - depends on ACPI && X86 - select GPIOLIB_IRQCHIP - help - driver for GPIO functionality on Intel Lynxpoint PCH chipset - Requires ACPI device enumeration code to set up a platform device. - -config GPIO_MB86S7X - bool "GPIO support for Fujitsu MB86S7x Platforms" - depends on ARCH_MB86S7X || COMPILE_TEST - help - Say yes here to support the GPIO controller in Fujitsu MB86S70 SoCs. - -config GPIO_MENZ127 - tristate "MEN 16Z127 GPIO support" - depends on MCB - select GPIO_GENERIC - help - Say yes here to support the MEN 16Z127 GPIO Controller - -config GPIO_MM_LANTIQ - bool "Lantiq Memory mapped GPIOs" - depends on LANTIQ && SOC_XWAY - help - This enables support for memory mapped GPIOs on the External Bus Unit - (EBU) found on Lantiq SoCs. The gpios are output only as they are - created by attaching a 16bit latch to the bus. - -config GPIO_MOCKUP - tristate "GPIO Testing Driver" - depends on GPIOLIB && SYSFS - select GPIO_SYSFS - help - This enables GPIO Testing driver, which provides a way to test GPIO - subsystem through sysfs(or char device) and debugfs. GPIO_SYSFS - must be selected for this test. - User could use it through the script in - tools/testing/selftests/gpio/gpio-mockup.sh. Reference the usage in - it. - -config GPIO_MOXART - bool "MOXART GPIO support" - depends on ARCH_MOXART || COMPILE_TEST - select GPIO_GENERIC - help - Select this option to enable GPIO driver for - MOXA ART SoC devices. - -config GPIO_MPC5200 - def_bool y - depends on PPC_MPC52xx - -config GPIO_MPC8XXX - bool "MPC512x/MPC8xxx/QorIQ GPIO support" - depends on PPC_MPC512x || PPC_MPC831x || PPC_MPC834x || PPC_MPC837x || \ - FSL_SOC_BOOKE || PPC_86xx || ARCH_LAYERSCAPE || ARM || \ - COMPILE_TEST - select GPIO_GENERIC - select IRQ_DOMAIN - help - Say Y here if you're going to use hardware that connects to the - MPC512x/831x/834x/837x/8572/8610/QorIQ GPIOs. - -config GPIO_MVEBU - def_bool y - depends on PLAT_ORION - depends on OF_GPIO - select GENERIC_IRQ_CHIP - -config GPIO_MXC - def_bool y - depends on ARCH_MXC - select GPIO_GENERIC - select GENERIC_IRQ_CHIP - -config GPIO_MXS - def_bool y - depends on ARCH_MXS - select GPIO_GENERIC - select GENERIC_IRQ_CHIP - -config GPIO_OCTEON - tristate "Cavium OCTEON GPIO" - depends on GPIOLIB && CAVIUM_OCTEON_SOC - default y - help - Say yes here to support the on-chip GPIO lines on the OCTEON - family of SOCs. - -config GPIO_OMAP - tristate "TI OMAP GPIO support" if ARCH_OMAP2PLUS || COMPILE_TEST - default y if ARCH_OMAP - depends on ARM - select GENERIC_IRQ_CHIP - select GPIOLIB_IRQCHIP - help - Say yes here to enable GPIO support for TI OMAP SoCs. - -config GPIO_PL061 - bool "PrimeCell PL061 GPIO support" - depends on ARM_AMBA - select IRQ_DOMAIN - select GPIOLIB_IRQCHIP - help - Say yes here to support the PrimeCell PL061 GPIO device - -config GPIO_PXA - bool "PXA GPIO support" - depends on ARCH_PXA || ARCH_MMP - help - Say yes here to support the PXA GPIO device - -config GPIO_RCAR - tristate "Renesas R-Car GPIO" - depends on ARCH_RENESAS || COMPILE_TEST - select GPIOLIB_IRQCHIP - help - Say yes here to support GPIO on Renesas R-Car SoCs. - -config GPIO_SPEAR_SPICS - bool "ST SPEAr13xx SPI Chip Select as GPIO support" - depends on PLAT_SPEAR - select GENERIC_IRQ_CHIP - help - Say yes here to support ST SPEAr SPI Chip Select as GPIO device - -config GPIO_STA2X11 - bool "STA2x11/ConneXt GPIO support" - depends on MFD_STA2X11 - select GENERIC_IRQ_CHIP - help - Say yes here to support the STA2x11/ConneXt GPIO device. - The GPIO module has 128 GPIO pins with alternate functions. - -config GPIO_STP_XWAY - bool "XWAY STP GPIOs" - depends on SOC_XWAY - help - This enables support for the Serial To Parallel (STP) unit found on - XWAY SoC. The STP allows the SoC to drive a shift registers cascade, - that can be up to 24 bit. This peripheral is aimed at driving leds. - Some of the gpios/leds can be auto updated by the soc with dsl and - phy status. - -config GPIO_SYSCON - tristate "GPIO based on SYSCON" - depends on MFD_SYSCON && OF - help - Say yes here to support GPIO functionality though SYSCON driver. - -config GPIO_TB10X - bool - select GENERIC_IRQ_CHIP - select OF_GPIO - -config GPIO_TEGRA - bool "NVIDIA Tegra GPIO support" - default ARCH_TEGRA - depends on ARCH_TEGRA || COMPILE_TEST - depends on OF_GPIO - help - Say yes here to support GPIO pins on NVIDIA Tegra SoCs. - -config GPIO_TS4800 - tristate "TS-4800 DIO blocks and compatibles" - depends on OF_GPIO - depends on SOC_IMX51 || COMPILE_TEST - select GPIO_GENERIC - help - This driver support TS-4800 FPGA GPIO controllers. - -config GPIO_TZ1090 - bool "Toumaz Xenif TZ1090 GPIO support" - depends on SOC_TZ1090 - select GENERIC_IRQ_CHIP - default y - help - Say yes here to support Toumaz Xenif TZ1090 GPIOs. - -config GPIO_TZ1090_PDC - bool "Toumaz Xenif TZ1090 PDC GPIO support" - depends on SOC_TZ1090 - default y - help - Say yes here to support Toumaz Xenif TZ1090 PDC GPIOs. - -config GPIO_VF610 - def_bool y - depends on ARCH_MXC && SOC_VF610 - select GPIOLIB_IRQCHIP - help - Say yes here to support Vybrid vf610 GPIOs. - -config GPIO_VR41XX - tristate "NEC VR4100 series General-purpose I/O Uint support" - depends on CPU_VR41XX - help - Say yes here to support the NEC VR4100 series General-purpose I/O Uint - -config GPIO_VX855 - tristate "VIA VX855/VX875 GPIO" - depends on PCI - select MFD_CORE - select MFD_VX855 - help - Support access to the VX855/VX875 GPIO lines through the gpio library. - - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the - functionality of the device. - -config GPIO_XGENE - bool "APM X-Gene GPIO controller support" - depends on ARM64 && OF_GPIO - help - This driver is to support the GPIO block within the APM X-Gene SoC - platform's generic flash controller. The GPIO pins are muxed with - the generic flash controller's address and data pins. Say yes - here to enable the GFC GPIO functionality. - -config GPIO_XGENE_SB - tristate "APM X-Gene GPIO standby controller support" - depends on ARCH_XGENE && OF_GPIO - select GPIO_GENERIC - select GPIOLIB_IRQCHIP - help - This driver supports the GPIO block within the APM X-Gene - Standby Domain. Say yes here to enable the GPIO functionality. - -config GPIO_XILINX - tristate "Xilinx GPIO support" - depends on OF_GPIO - help - Say yes here to support the Xilinx FPGA GPIO device - -config GPIO_XLP - tristate "Netlogic XLP GPIO support" - depends on OF_GPIO && (CPU_XLP || ARCH_VULCAN || COMPILE_TEST) - select GPIOLIB_IRQCHIP - help - This driver provides support for GPIO interface on Netlogic XLP MIPS64 - SoCs. Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX, - XLP9XX and XLP5XX. - - If unsure, say N. - -config GPIO_XTENSA - bool "Xtensa GPIO32 support" - depends on XTENSA - depends on HAVE_XTENSA_GPIO32 - depends on !SMP - help - Say yes here to support the Xtensa internal GPIO32 IMPWIRE (input) - and EXPSTATE (output) ports - -config GPIO_ZEVIO - bool "LSI ZEVIO SoC memory mapped GPIOs" - depends on ARM && OF_GPIO - help - Say yes here to support the GPIO controller in LSI ZEVIO SoCs. - -config GPIO_ZYNQ - tristate "Xilinx Zynq GPIO support" - depends on ARCH_ZYNQ || ARCH_ZYNQMP - select GPIOLIB_IRQCHIP - help - Say yes here to support Xilinx Zynq GPIO controller. - -config GPIO_ZX - bool "ZTE ZX GPIO support" - select GPIOLIB_IRQCHIP - help - Say yes here to support the GPIO device on ZTE ZX SoCs. - -config GPIO_LOONGSON1 - tristate "Loongson1 GPIO support" - depends on MACH_LOONGSON32 - select GPIO_GENERIC - help - Say Y or M here to support GPIO on Loongson1 SoCs. - -endmenu - -menu "Port-mapped I/O GPIO drivers" - depends on X86 # Unconditional I/O space access - -config GPIO_104_DIO_48E - tristate "ACCES 104-DIO-48E GPIO support" - depends on ISA_BUS_API - select GPIOLIB_IRQCHIP - help - Enables GPIO support for the ACCES 104-DIO-48E series (104-DIO-48E, - 104-DIO-24E). The base port addresses for the devices may be - configured via the base module parameter. The interrupt line numbers - for the devices may be configured via the irq module parameter. - -config GPIO_104_IDIO_16 - tristate "ACCES 104-IDIO-16 GPIO support" - depends on ISA_BUS_API - select GPIOLIB_IRQCHIP - help - Enables GPIO support for the ACCES 104-IDIO-16 family (104-IDIO-16, - 104-IDIO-16E, 104-IDO-16, 104-IDIO-8, 104-IDIO-8E, 104-IDO-8). The - base port addresses for the devices may be configured via the base - module parameter. The interrupt line numbers for the devices may be - configured via the irq module parameter. - -config GPIO_104_IDI_48 - tristate "ACCES 104-IDI-48 GPIO support" - depends on ISA_BUS_API - select GPIOLIB_IRQCHIP - help - Enables GPIO support for the ACCES 104-IDI-48 family (104-IDI-48A, - 104-IDI-48AC, 104-IDI-48B, 104-IDI-48BC). The base port addresses for - the devices may be configured via the base module parameter. The - interrupt line numbers for the devices may be configured via the irq - module parameter. - -config GPIO_F7188X - tristate "F71869, F71869A, F71882FG, F71889F and F81866 GPIO support" - help - This option enables support for GPIOs found on Fintek Super-I/O - chips F71869, F71869A, F71882FG, F71889F and F81866. - - To compile this driver as a module, choose M here: the module will - be called f7188x-gpio. - -config GPIO_GPIO_MM - tristate "Diamond Systems GPIO-MM GPIO support" - depends on ISA_BUS_API - help - Enables GPIO support for the Diamond Systems GPIO-MM and GPIO-MM-12. - - The Diamond Systems GPIO-MM device features 48 lines of digital I/O - via the emulation of dual 82C55A PPI chips. This driver provides GPIO - support for these 48 channels of digital I/O. - - The base port addresses for the devices may be configured via the base - array module parameter. - -config GPIO_IT87 - tristate "IT87xx GPIO support" - help - Say yes here to support GPIO functionality of IT87xx Super I/O chips. - - This driver is tested with ITE IT8728 and IT8732 Super I/O chips, and - supports the IT8761E, IT8620E and IT8628E Super I/O chip as well. - - To compile this driver as a module, choose M here: the module will - be called gpio_it87 - -config GPIO_SCH - tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO" - depends on PCI - select MFD_CORE - select LPC_SCH - help - Say yes here to support GPIO interface on Intel Poulsbo SCH, - Intel Tunnel Creek processor, Intel Centerton processor or - Intel Quark X1000 SoC. - - The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are - powered by the core power rail and are turned off during sleep - modes (S3 and higher). The remaining four GPIOs are powered by - the Intel SCH suspend power supply. These GPIOs remain - active during S3. The suspend powered GPIOs can be used to wake the - system from the Suspend-to-RAM state. - - The Intel Tunnel Creek processor has 5 GPIOs powered by the - core power rail and 9 from suspend power supply. - - The Intel Centerton processor has a total of 30 GPIO pins. - Twenty-one are powered by the core power rail and 9 from the - suspend power supply. - - The Intel Quark X1000 SoC has 2 GPIOs powered by the core - power well and 6 from the suspend power well. - -config GPIO_SCH311X - tristate "SMSC SCH311x SuperI/O GPIO" - help - Driver to enable the GPIOs found on SMSC SMSC SCH3112, SCH3114 and - SCH3116 "Super I/O" chipsets. - - To compile this driver as a module, choose M here: the module will - be called gpio-sch311x. - -config GPIO_TS5500 - tristate "TS-5500 DIO blocks and compatibles" - depends on TS5500 || COMPILE_TEST - help - This driver supports Digital I/O exposed by pin blocks found on some - Technologic Systems platforms. It includes, but is not limited to, 3 - blocks of the TS-5500: DIO1, DIO2 and the LCD port, and the TS-5600 - LCD port. - -config GPIO_WS16C48 - tristate "WinSystems WS16C48 GPIO support" - depends on ISA_BUS_API - select GPIOLIB_IRQCHIP - help - Enables GPIO support for the WinSystems WS16C48. The base port - addresses for the devices may be configured via the base module - parameter. The interrupt line numbers for the devices may be - configured via the irq module parameter. - -endmenu - -menu "I2C GPIO expanders" - depends on I2C - -config GPIO_ADP5588 - tristate "ADP5588 I2C GPIO expander" - help - This option enables support for 18 GPIOs found - on Analog Devices ADP5588 GPIO Expanders. - -config GPIO_ADP5588_IRQ - bool "Interrupt controller support for ADP5588" - depends on GPIO_ADP5588=y - help - Say yes here to enable the adp5588 to be used as an interrupt - controller. It requires the driver to be built in the kernel. - -config GPIO_ADNP - tristate "Avionic Design N-bit GPIO expander" - depends on OF_GPIO - select GPIOLIB_IRQCHIP - help - This option enables support for N GPIOs found on Avionic Design - I2C GPIO expanders. The register space will be extended by powers - of two, so the controller will need to accommodate for that. For - example: if a controller provides 48 pins, 6 registers will be - enough to represent all pins, but the driver will assume a - register layout for 64 pins (8 registers). - -config GPIO_MAX7300 - tristate "Maxim MAX7300 GPIO expander" - select GPIO_MAX730X - help - GPIO driver for Maxim MAX7300 I2C-based GPIO expander. - -config GPIO_MAX732X - tristate "MAX7319, MAX7320-7327 I2C Port Expanders" - help - Say yes here to support the MAX7319, MAX7320-7327 series of I2C - Port Expanders. Each IO port on these chips has a fixed role of - Input (designated by 'I'), Push-Pull Output ('O'), or Open-Drain - Input and Output (designed by 'P'). The combinations are listed - below: - - 8 bits: max7319 (8I), max7320 (8O), max7321 (8P), - max7322 (4I4O), max7323 (4P4O) - - 16 bits: max7324 (8I8O), max7325 (8P8O), - max7326 (4I12O), max7327 (4P12O) - - Board setup code must specify the model to use, and the start - number for these GPIOs. - -config GPIO_MAX732X_IRQ - bool "Interrupt controller support for MAX732x" - depends on GPIO_MAX732X=y - select GPIOLIB_IRQCHIP - help - Say yes here to enable the max732x to be used as an interrupt - controller. It requires the driver to be built in the kernel. - -config GPIO_MC9S08DZ60 - bool "MX35 3DS BOARD MC9S08DZ60 GPIO functions" - depends on I2C=y && MACH_MX35_3DS - help - Select this to enable the MC9S08DZ60 GPIO driver - -config GPIO_PCA953X - tristate "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports" - help - Say yes here to provide access to several register-oriented - SMBus I/O expanders, made mostly by NXP or TI. Compatible - models include: - - 4 bits: pca9536, pca9537 - - 8 bits: max7310, max7315, pca6107, pca9534, pca9538, pca9554, - pca9556, pca9557, pca9574, tca6408, xra1202 - - 16 bits: max7312, max7313, pca9535, pca9539, pca9555, pca9575, - tca6416 - - 24 bits: tca6424 - - 40 bits: pca9505, pca9698 - -config GPIO_PCA953X_IRQ - bool "Interrupt controller support for PCA953x" - depends on GPIO_PCA953X=y - select GPIOLIB_IRQCHIP - help - Say yes here to enable the pca953x to be used as an interrupt - controller. It requires the driver to be built in the kernel. - -config GPIO_PCF857X - tristate "PCF857x, PCA{85,96}7x, and MAX732[89] I2C GPIO expanders" - select GPIOLIB_IRQCHIP - select IRQ_DOMAIN - help - Say yes here to provide access to most "quasi-bidirectional" I2C - GPIO expanders used for additional digital outputs or inputs. - Most of these parts are from NXP, though TI is a second source for - some of them. Compatible models include: - - 8 bits: pcf8574, pcf8574a, pca8574, pca8574a, - pca9670, pca9672, pca9674, pca9674a, - max7328, max7329 - - 16 bits: pcf8575, pcf8575c, pca8575, - pca9671, pca9673, pca9675 - - Your board setup code will need to declare the expanders in - use, and assign numbers to the GPIOs they expose. Those GPIOs - can then be used from drivers and other kernel code, just like - other GPIOs, but only accessible from task contexts. - - This driver provides an in-kernel interface to those GPIOs using - platform-neutral GPIO calls. - -config GPIO_SX150X - bool "Semtech SX150x I2C GPIO expander" - depends on I2C=y - select GPIOLIB_IRQCHIP - default n - help - Say yes here to provide support for Semtech SX150-series I2C - GPIO expanders. Compatible models include: - - 8 bits: sx1508q - 16 bits: sx1509q - -config GPIO_TPIC2810 - tristate "TPIC2810 8-Bit I2C GPO expander" - help - Say yes here to enable the GPO driver for the TI TPIC2810 chip. - - To compile this driver as a module, choose M here: the module will - be called gpio-tpic2810. - -config GPIO_TS4900 - tristate "Technologic Systems FPGA I2C GPIO" - select REGMAP_I2C - help - Say yes here to enabled the GPIO driver for Technologic's FPGA core. - Series supported include TS-4100, TS-4900, TS-7970 and TS-7990. - -endmenu - -menu "MFD GPIO expanders" - -config GPIO_ADP5520 - tristate "GPIO Support for ADP5520 PMIC" - depends on PMIC_ADP5520 - help - This option enables support for on-chip GPIO found - on Analog Devices ADP5520 PMICs. - -config GPIO_ARIZONA - tristate "Wolfson Microelectronics Arizona class devices" - depends on MFD_ARIZONA - help - Support for GPIOs on Wolfson Arizona class devices. - -config GPIO_CRYSTAL_COVE - tristate "GPIO support for Crystal Cove PMIC" - depends on INTEL_SOC_PMIC - select GPIOLIB_IRQCHIP - help - Support for GPIO pins on Crystal Cove PMIC. - - Say Yes if you have a Intel SoC based tablet with Crystal Cove PMIC - inside. - - This driver can also be built as a module. If so, the module will be - called gpio-crystalcove. - -config GPIO_CS5535 - tristate "AMD CS5535/CS5536 GPIO support" - depends on MFD_CS5535 - help - The AMD CS5535 and CS5536 southbridges support 28 GPIO pins that - can be used for quite a number of things. The CS5535/6 is found on - AMD Geode and Lemote Yeeloong devices. - - If unsure, say N. - -config GPIO_DA9052 - tristate "Dialog DA9052 GPIO" - depends on PMIC_DA9052 - help - Say yes here to enable the GPIO driver for the DA9052 chip. - -config GPIO_DA9055 - tristate "Dialog Semiconductor DA9055 GPIO" - depends on MFD_DA9055 - help - Say yes here to enable the GPIO driver for the DA9055 chip. - - The Dialog DA9055 PMIC chip has 3 GPIO pins that can be - be controller by this driver. - - If driver is built as a module it will be called gpio-da9055. - -config GPIO_DLN2 - tristate "Diolan DLN2 GPIO support" - depends on MFD_DLN2 - select GPIOLIB_IRQCHIP - - help - Select this option to enable GPIO driver for the Diolan DLN2 - board. - - This driver can also be built as a module. If so, the module - will be called gpio-dln2. - -config HTC_EGPIO - bool "HTC EGPIO support" - depends on GPIOLIB && ARM - help - This driver supports the CPLD egpio chip present on - several HTC phones. It provides basic support for input - pins, output pins, and irqs. - -config GPIO_JANZ_TTL - tristate "Janz VMOD-TTL Digital IO Module" - depends on MFD_JANZ_CMODIO - help - This enables support for the Janz VMOD-TTL Digital IO module. - This driver provides support for driving the pins in output - mode only. Input mode is not supported. - -config GPIO_KEMPLD - tristate "Kontron ETX / COMexpress GPIO" - depends on MFD_KEMPLD - help - This enables support for the PLD GPIO interface on some Kontron ETX - and COMexpress (ETXexpress) modules. - - This driver can also be built as a module. If so, the module will be - called gpio-kempld. - -config GPIO_LP3943 - tristate "TI/National Semiconductor LP3943 GPIO expander" - depends on MFD_LP3943 - help - GPIO driver for LP3943 MFD. - LP3943 can be used as a GPIO expander which provides up to 16 GPIOs. - Open drain outputs are required for this usage. - -config GPIO_LP873X - tristate "TI LP873X GPO" - depends on MFD_TI_LP873X - help - This driver supports the GPO on TI Lp873x PMICs. 2 GPOs are present - on LP873X PMICs. - - This driver can also be built as a module. If so, the module will be - called gpio-lp873x. - -config GPIO_MAX77620 - tristate "GPIO support for PMIC MAX77620 and MAX20024" - depends on MFD_MAX77620 - help - GPIO driver for MAX77620 and MAX20024 PMIC from Maxim Semiconductor. - MAX77620 PMIC has 8 pins that can be configured as GPIOs. The - driver also provides interrupt support for each of the gpios. - Say yes here to enable the max77620 to be used as gpio controller. - -config GPIO_MSIC - bool "Intel MSIC mixed signal gpio support" - depends on MFD_INTEL_MSIC - help - Enable support for GPIO on intel MSIC controllers found in - intel MID devices - -config GPIO_PALMAS - bool "TI PALMAS series PMICs GPIO" - depends on MFD_PALMAS - help - Select this option to enable GPIO driver for the TI PALMAS - series chip family. - -config GPIO_RC5T583 - bool "RICOH RC5T583 GPIO" - depends on MFD_RC5T583 - help - Select this option to enable GPIO driver for the Ricoh RC5T583 - chip family. - This driver provides the support for driving/reading the gpio pins - of RC5T583 device through standard gpio library. - -config GPIO_STMPE - bool "STMPE GPIOs" - depends on MFD_STMPE - depends on OF_GPIO - select GPIOLIB_IRQCHIP - help - This enables support for the GPIOs found on the STMPE I/O - Expanders. - -config GPIO_TC3589X - bool "TC3589X GPIOs" - depends on MFD_TC3589X - depends on OF_GPIO - select GPIOLIB_IRQCHIP - help - This enables support for the GPIOs found on the TC3589X - I/O Expander. - -config GPIO_TIMBERDALE - bool "Support for timberdale GPIO IP" - depends on MFD_TIMBERDALE - ---help--- - Add support for the GPIO IP in the timberdale FPGA. - -config GPIO_TPS65086 - tristate "TI TPS65086 GPO" - depends on MFD_TPS65086 - help - This driver supports the GPO on TI TPS65086x PMICs. - -config GPIO_TPS65218 - tristate "TPS65218 GPIO" - depends on MFD_TPS65218 - help - Select this option to enable GPIO driver for the TPS65218 - chip family. - -config GPIO_TPS6586X - bool "TPS6586X GPIO" - depends on MFD_TPS6586X - help - Select this option to enable GPIO driver for the TPS6586X - chip family. - -config GPIO_TPS65910 - bool "TPS65910 GPIO" - depends on MFD_TPS65910 - help - Select this option to enable GPIO driver for the TPS65910 - chip family. - -config GPIO_TPS65912 - tristate "TI TPS65912 GPIO" - depends on MFD_TPS65912 - help - This driver supports TPS65912 gpio chip - -config GPIO_TWL4030 - tristate "TWL4030, TWL5030, and TPS659x0 GPIOs" - depends on TWL4030_CORE - help - Say yes here to access the GPIO signals of various multi-function - power management chips from Texas Instruments. - -config GPIO_TWL6040 - tristate "TWL6040 GPO" - depends on TWL6040_CORE - help - Say yes here to access the GPO signals of twl6040 - audio chip from Texas Instruments. - -config GPIO_UCB1400 - tristate "Philips UCB1400 GPIO" - depends on UCB1400_CORE - help - This enables support for the Philips UCB1400 GPIO pins. - The UCB1400 is an AC97 audio codec. - -config GPIO_WHISKEY_COVE - tristate "GPIO support for Whiskey Cove PMIC" - depends on INTEL_SOC_PMIC - select GPIOLIB_IRQCHIP - help - Support for GPIO pins on Whiskey Cove PMIC. - - Say Yes if you have a Intel SoC based tablet with Whiskey Cove PMIC - inside. - - This driver can also be built as a module. If so, the module will be - called gpio-wcove. - -config GPIO_WM831X - tristate "WM831x GPIOs" - depends on MFD_WM831X - help - Say yes here to access the GPIO signals of WM831x power management - chips from Wolfson Microelectronics. - -config GPIO_WM8350 - tristate "WM8350 GPIOs" - depends on MFD_WM8350 - help - Say yes here to access the GPIO signals of WM8350 power management - chips from Wolfson Microelectronics. - -config GPIO_WM8994 - tristate "WM8994 GPIOs" - depends on MFD_WM8994 - help - Say yes here to access the GPIO signals of WM8994 audio hub - CODECs from Wolfson Microelectronics. - -endmenu - -menu "PCI GPIO expanders" - depends on PCI - -config GPIO_AMD8111 - tristate "AMD 8111 GPIO driver" - help - The AMD 8111 south bridge contains 32 GPIO pins which can be used. - - Note, that usually system firmware/ACPI handles GPIO pins on their - own and users might easily break their systems with uncarefull usage - of this driver! - - If unsure, say N - -config GPIO_BT8XX - tristate "BT8XX GPIO abuser" - depends on VIDEO_BT848=n - help - The BT8xx frame grabber chip has 24 GPIO pins that can be abused - as a cheap PCI GPIO card. - - This chip can be found on Miro, Hauppauge and STB TV-cards. - - The card needs to be physically altered for using it as a - GPIO card. For more information on how to build a GPIO card - from a BT8xx TV card, see the documentation file at - Documentation/bt8xxgpio.txt - - If unsure, say N. - -config GPIO_INTEL_MID - bool "Intel MID GPIO support" - depends on X86_INTEL_MID - select GPIOLIB_IRQCHIP - help - Say Y here to support Intel MID GPIO. - -config GPIO_MERRIFIELD - tristate "Intel Merrifield GPIO support" - depends on X86_INTEL_MID - select GPIOLIB_IRQCHIP - help - Say Y here to support Intel Merrifield GPIO. - -config GPIO_ML_IOH - tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support" - select GENERIC_IRQ_CHIP - help - ML7213 is companion chip for Intel Atom E6xx series. - This driver can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/Output - Hub) which is for IVI(In-Vehicle Infotainment) use. - This driver can access the IOH's GPIO device. - -config GPIO_PCH - tristate "Intel EG20T PCH/LAPIS Semiconductor IOH(ML7223/ML7831) GPIO" - depends on X86_32 || MIPS || COMPILE_TEST - select GENERIC_IRQ_CHIP - help - This driver is for PCH(Platform controller Hub) GPIO of Intel Topcliff - which is an IOH(Input/Output Hub) for x86 embedded processor. - This driver can access PCH GPIO device. - - This driver also can be used for LAPIS Semiconductor IOH(Input/ - Output Hub), ML7223 and ML7831. - ML7223 IOH is for MP(Media Phone) use. - ML7831 IOH is for general purpose use. - ML7223/ML7831 is companion chip for Intel Atom E6xx series. - ML7223/ML7831 is completely compatible for Intel EG20T PCH. - -config GPIO_RDC321X - tristate "RDC R-321x GPIO support" - select MFD_CORE - select MFD_RDC321X - help - Support for the RDC R321x SoC GPIOs over southbridge - PCI configuration space. - -config GPIO_SODAVILLE - bool "Intel Sodaville GPIO support" - depends on X86 && OF - select GPIO_GENERIC - select GENERIC_IRQ_CHIP - help - Say Y here to support Intel Sodaville GPIO. - -endmenu - -menu "SPI GPIO expanders" - depends on SPI_MASTER - -config GPIO_74X164 - tristate "74x164 serial-in/parallel-out 8-bits shift register" - depends on OF_GPIO - help - Driver for 74x164 compatible serial-in/parallel-out 8-outputs - shift registers. This driver can be used to provide access - to more gpio outputs. - -config GPIO_MAX7301 - tristate "Maxim MAX7301 GPIO expander" - select GPIO_MAX730X - help - GPIO driver for Maxim MAX7301 SPI-based GPIO expander. - -config GPIO_MC33880 - tristate "Freescale MC33880 high-side/low-side switch" - help - SPI driver for Freescale MC33880 high-side/low-side switch. - This provides GPIO interface supporting inputs and outputs. - -config GPIO_PISOSR - tristate "Generic parallel-in/serial-out shift register" - help - GPIO driver for SPI compatible parallel-in/serial-out shift - registers. These are input only devices. - -endmenu - -menu "SPI or I2C GPIO expanders" - depends on (SPI_MASTER && !I2C) || I2C - -config GPIO_MCP23S08 - tristate "Microchip MCP23xxx I/O expander" - depends on OF_GPIO - select GPIOLIB_IRQCHIP - help - SPI/I2C driver for Microchip MCP23S08/MCP23S17/MCP23008/MCP23017 - I/O expanders. - This provides a GPIO interface supporting inputs and outputs. - The I2C versions of the chips can be used as interrupt-controller. - -endmenu - -menu "USB GPIO expanders" - depends on USB - -config GPIO_VIPERBOARD - tristate "Viperboard GPIO a & b support" - depends on MFD_VIPERBOARD - help - Say yes here to access the GPIO signals of Nano River - Technologies Viperboard. There are two GPIO chips on the - board: gpioa and gpiob. - See viperboard API specification and Nano - River Tech's viperboard.h for detailed meaning - of the module parameters. - -endmenu - -endif diff --git a/src/linux/drivers/gpu/Makefile b/src/linux/drivers/gpu/Makefile deleted file mode 100644 index e9ed439..0000000 --- a/src/linux/drivers/gpu/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# drm/tegra depends on host1x, so if both drivers are built-in care must be -# taken to initialize them in the correct order. Link order is the only way -# to ensure this currently. -obj-$(CONFIG_TEGRA_HOST1X) += host1x/ -obj-y += drm/ vga/ -obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/ diff --git a/src/linux/drivers/gpu/drm/Kconfig b/src/linux/drivers/gpu/drm/Kconfig deleted file mode 100644 index 483059a..0000000 --- a/src/linux/drivers/gpu/drm/Kconfig +++ /dev/null @@ -1,302 +0,0 @@ -# -# Drm device configuration -# -# This driver provides support for the -# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. -# -menuconfig DRM - tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)" - depends on (AGP || AGP=n) && !EMULATED_CMPXCHG && MMU && HAS_DMA - select HDMI - select FB_CMDLINE - select I2C - select I2C_ALGOBIT - select DMA_SHARED_BUFFER - help - Kernel-level support for the Direct Rendering Infrastructure (DRI) - introduced in XFree86 4.0. If you say Y here, you need to select - the module that's right for your graphics card from the list below. - These modules provide support for synchronization, security, and - DMA transfers. Please see for more - details. You should also select and configure AGP - (/dev/agpgart) support if it is available for your platform. - -config DRM_MIPI_DSI - bool - depends on DRM - -config DRM_DP_AUX_CHARDEV - bool "DRM DP AUX Interface" - depends on DRM - help - Choose this option to enable a /dev/drm_dp_auxN node that allows to - read and write values to arbitrary DPCD registers on the DP aux - channel. - -config DRM_KMS_HELPER - tristate - depends on DRM - help - CRTC helpers for KMS drivers. - -config DRM_KMS_FB_HELPER - bool - depends on DRM_KMS_HELPER - select FB - select FRAMEBUFFER_CONSOLE if !EXPERT - select FRAMEBUFFER_CONSOLE_DETECT_PRIMARY if FRAMEBUFFER_CONSOLE - select FB_SYS_FOPS - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_DEFERRED_IO - help - FBDEV helpers for KMS drivers. - -config DRM_FBDEV_EMULATION - bool "Enable legacy fbdev support for your modesetting driver" - depends on DRM - select DRM_KMS_HELPER - select DRM_KMS_FB_HELPER - default y - help - Choose this option if you have a need for the legacy fbdev - support. Note that this support also provides the linux console - support on top of your modesetting driver. - - If in doubt, say "Y". - -config DRM_LOAD_EDID_FIRMWARE - bool "Allow to specify an EDID data set instead of probing for it" - depends on DRM_KMS_HELPER - help - Say Y here, if you want to use EDID data to be loaded from the - /lib/firmware directory or one of the provided built-in - data sets. This may be necessary, if the graphics adapter or - monitor are unable to provide appropriate EDID data. Since this - feature is provided as a workaround for broken hardware, the - default case is N. Details and instructions how to build your own - EDID data are given in Documentation/EDID/HOWTO.txt. - -config DRM_TTM - tristate - depends on DRM - help - GPU memory management subsystem for devices with multiple - GPU memory types. Will be enabled automatically if a device driver - uses it. - -config DRM_GEM_CMA_HELPER - bool - depends on DRM - help - Choose this if you need the GEM CMA helper functions - -config DRM_KMS_CMA_HELPER - bool - depends on DRM - select DRM_GEM_CMA_HELPER - select DRM_KMS_FB_HELPER - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - help - Choose this if you need the KMS CMA helper functions - -source "drivers/gpu/drm/i2c/Kconfig" - -source "drivers/gpu/drm/arm/Kconfig" - -config DRM_RADEON - tristate "ATI Radeon" - depends on DRM && PCI - select FW_LOADER - select DRM_KMS_HELPER - select DRM_TTM - select POWER_SUPPLY - select HWMON - select BACKLIGHT_CLASS_DEVICE - select BACKLIGHT_LCD_SUPPORT - select INTERVAL_TREE - help - Choose this option if you have an ATI Radeon graphics card. There - are both PCI and AGP versions. You don't need to choose this to - run the Radeon in plain VGA mode. - - If M is selected, the module will be called radeon. - -source "drivers/gpu/drm/radeon/Kconfig" - -config DRM_AMDGPU - tristate "AMD GPU" - depends on DRM && PCI - select FW_LOADER - select DRM_KMS_HELPER - select DRM_TTM - select POWER_SUPPLY - select HWMON - select BACKLIGHT_CLASS_DEVICE - select BACKLIGHT_LCD_SUPPORT - select INTERVAL_TREE - help - Choose this option if you have a recent AMD Radeon graphics card. - - If M is selected, the module will be called amdgpu. - -source "drivers/gpu/drm/amd/amdgpu/Kconfig" - -source "drivers/gpu/drm/nouveau/Kconfig" - -source "drivers/gpu/drm/i915/Kconfig" - -config DRM_VGEM - tristate "Virtual GEM provider" - depends on DRM - help - Choose this option to get a virtual graphics memory manager, - as used by Mesa's software renderer for enhanced performance. - If M is selected the module will be called vgem. - - -source "drivers/gpu/drm/exynos/Kconfig" - -source "drivers/gpu/drm/rockchip/Kconfig" - -source "drivers/gpu/drm/vmwgfx/Kconfig" - -source "drivers/gpu/drm/gma500/Kconfig" - -source "drivers/gpu/drm/udl/Kconfig" - -source "drivers/gpu/drm/ast/Kconfig" - -source "drivers/gpu/drm/mgag200/Kconfig" - -source "drivers/gpu/drm/cirrus/Kconfig" - -source "drivers/gpu/drm/armada/Kconfig" - -source "drivers/gpu/drm/atmel-hlcdc/Kconfig" - -source "drivers/gpu/drm/rcar-du/Kconfig" - -source "drivers/gpu/drm/shmobile/Kconfig" - -source "drivers/gpu/drm/sun4i/Kconfig" - -source "drivers/gpu/drm/omapdrm/Kconfig" - -source "drivers/gpu/drm/tilcdc/Kconfig" - -source "drivers/gpu/drm/qxl/Kconfig" - -source "drivers/gpu/drm/bochs/Kconfig" - -source "drivers/gpu/drm/virtio/Kconfig" - -source "drivers/gpu/drm/msm/Kconfig" - -source "drivers/gpu/drm/fsl-dcu/Kconfig" - -source "drivers/gpu/drm/tegra/Kconfig" - -source "drivers/gpu/drm/panel/Kconfig" - -source "drivers/gpu/drm/bridge/Kconfig" - -source "drivers/gpu/drm/sti/Kconfig" - -source "drivers/gpu/drm/amd/amdkfd/Kconfig" - -source "drivers/gpu/drm/imx/Kconfig" - -source "drivers/gpu/drm/vc4/Kconfig" - -source "drivers/gpu/drm/etnaviv/Kconfig" - -source "drivers/gpu/drm/arc/Kconfig" - -source "drivers/gpu/drm/hisilicon/Kconfig" - -source "drivers/gpu/drm/mediatek/Kconfig" - -# Keep legacy drivers last - -menuconfig DRM_LEGACY - bool "Enable legacy drivers (DANGEROUS)" - depends on DRM - help - Enable legacy DRI1 drivers. Those drivers expose unsafe and dangerous - APIs to user-space, which can be used to circumvent access - restrictions and other security measures. For backwards compatibility - those drivers are still available, but their use is highly - inadvisable and might harm your system. - - You are recommended to use the safe modeset-only drivers instead, and - perform 3D emulation in user-space. - - Unless you have strong reasons to go rogue, say "N". - -if DRM_LEGACY - -config DRM_TDFX - tristate "3dfx Banshee/Voodoo3+" - depends on DRM && PCI - help - Choose this option if you have a 3dfx Banshee or Voodoo3 (or later), - graphics card. If M is selected, the module will be called tdfx. - -config DRM_R128 - tristate "ATI Rage 128" - depends on DRM && PCI - select FW_LOADER - help - Choose this option if you have an ATI Rage 128 graphics card. If M - is selected, the module will be called r128. AGP support for - this card is strongly suggested (unless you have a PCI version). - -config DRM_I810 - tristate "Intel I810" - # !PREEMPT because of missing ioctl locking - depends on DRM && AGP && AGP_INTEL && (!PREEMPT || BROKEN) - help - Choose this option if you have an Intel I810 graphics card. If M is - selected, the module will be called i810. AGP support is required - for this driver to work. - -config DRM_MGA - tristate "Matrox g200/g400" - depends on DRM && PCI - select FW_LOADER - help - Choose this option if you have a Matrox G200, G400 or G450 graphics - card. If M is selected, the module will be called mga. AGP - support is required for this driver to work. - -config DRM_SIS - tristate "SiS video cards" - depends on DRM && AGP - depends on FB_SIS || FB_SIS=n - help - Choose this option if you have a SiS 630 or compatible video - chipset. If M is selected the module will be called sis. AGP - support is required for this driver to work. - -config DRM_VIA - tristate "Via unichrome video cards" - depends on DRM && PCI - help - Choose this option if you have a Via unichrome or compatible video - chipset. If M is selected the module will be called via. - -config DRM_SAVAGE - tristate "Savage video cards" - depends on DRM && PCI - help - Choose this option if you have a Savage3D/4/SuperSavage/Pro/Twister - chipset. If M is selected the module will be called savage. - -endif # DRM_LEGACY diff --git a/src/linux/drivers/gpu/drm/Makefile b/src/linux/drivers/gpu/drm/Makefile deleted file mode 100644 index 25c7204..0000000 --- a/src/linux/drivers/gpu/drm/Makefile +++ /dev/null @@ -1,88 +0,0 @@ - -# Makefile for the drm device driver. This driver provides support for the -# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher. - -drm-y := drm_auth.o drm_bufs.o drm_cache.o \ - drm_context.o drm_dma.o \ - drm_fops.o drm_gem.o drm_ioctl.o drm_irq.o \ - drm_lock.o drm_memory.o drm_drv.o drm_vm.o \ - drm_scatter.o drm_pci.o \ - drm_platform.o drm_sysfs.o drm_hashtab.o drm_mm.o \ - drm_crtc.o drm_fourcc.o drm_modes.o drm_edid.o \ - drm_info.o drm_debugfs.o drm_encoder_slave.o \ - drm_trace_points.o drm_global.o drm_prime.o \ - drm_rect.o drm_vma_manager.o drm_flip_work.o \ - drm_modeset_lock.o drm_atomic.o drm_bridge.o \ - drm_framebuffer.o drm_connector.o drm_blend.o \ - drm_encoder.o drm_mode_object.o drm_property.o \ - drm_plane.o drm_color_mgmt.o - -drm-$(CONFIG_COMPAT) += drm_ioc32.o -drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o -drm-$(CONFIG_PCI) += ati_pcigart.o -drm-$(CONFIG_DRM_PANEL) += drm_panel.o -drm-$(CONFIG_OF) += drm_of.o -drm-$(CONFIG_AGP) += drm_agpsupport.o - -drm_kms_helper-y := drm_crtc_helper.o drm_dp_helper.o drm_probe_helper.o \ - drm_plane_helper.o drm_dp_mst_topology.o drm_atomic_helper.o \ - drm_kms_helper_common.o drm_dp_dual_mode_helper.o \ - drm_simple_kms_helper.o drm_modeset_helper.o - -drm_kms_helper-$(CONFIG_DRM_LOAD_EDID_FIRMWARE) += drm_edid_load.o -drm_kms_helper-$(CONFIG_DRM_FBDEV_EMULATION) += drm_fb_helper.o -drm_kms_helper-$(CONFIG_DRM_KMS_CMA_HELPER) += drm_fb_cma_helper.o -drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o - -obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o - -CFLAGS_drm_trace_points.o := -I$(src) - -obj-$(CONFIG_DRM) += drm.o -obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o -obj-$(CONFIG_DRM_ARM) += arm/ -obj-$(CONFIG_DRM_TTM) += ttm/ -obj-$(CONFIG_DRM_TDFX) += tdfx/ -obj-$(CONFIG_DRM_R128) += r128/ -obj-$(CONFIG_HSA_AMD) += amd/amdkfd/ -obj-$(CONFIG_DRM_RADEON)+= radeon/ -obj-$(CONFIG_DRM_AMDGPU)+= amd/amdgpu/ -obj-$(CONFIG_DRM_MGA) += mga/ -obj-$(CONFIG_DRM_I810) += i810/ -obj-$(CONFIG_DRM_I915) += i915/ -obj-$(CONFIG_DRM_MGAG200) += mgag200/ -obj-$(CONFIG_DRM_VC4) += vc4/ -obj-$(CONFIG_DRM_CIRRUS_QEMU) += cirrus/ -obj-$(CONFIG_DRM_SIS) += sis/ -obj-$(CONFIG_DRM_SAVAGE)+= savage/ -obj-$(CONFIG_DRM_VMWGFX)+= vmwgfx/ -obj-$(CONFIG_DRM_VIA) +=via/ -obj-$(CONFIG_DRM_VGEM) += vgem/ -obj-$(CONFIG_DRM_NOUVEAU) +=nouveau/ -obj-$(CONFIG_DRM_EXYNOS) +=exynos/ -obj-$(CONFIG_DRM_ROCKCHIP) +=rockchip/ -obj-$(CONFIG_DRM_GMA500) += gma500/ -obj-$(CONFIG_DRM_UDL) += udl/ -obj-$(CONFIG_DRM_AST) += ast/ -obj-$(CONFIG_DRM_ARMADA) += armada/ -obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc/ -obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/ -obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/ -obj-y += omapdrm/ -obj-$(CONFIG_DRM_SUN4I) += sun4i/ -obj-y += tilcdc/ -obj-$(CONFIG_DRM_QXL) += qxl/ -obj-$(CONFIG_DRM_BOCHS) += bochs/ -obj-$(CONFIG_DRM_VIRTIO_GPU) += virtio/ -obj-$(CONFIG_DRM_MSM) += msm/ -obj-$(CONFIG_DRM_TEGRA) += tegra/ -obj-$(CONFIG_DRM_STI) += sti/ -obj-$(CONFIG_DRM_IMX) += imx/ -obj-$(CONFIG_DRM_MEDIATEK) += mediatek/ -obj-y += i2c/ -obj-y += panel/ -obj-y += bridge/ -obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/ -obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/ -obj-$(CONFIG_DRM_ARCPGU)+= arc/ -obj-y += hisilicon/ diff --git a/src/linux/drivers/gpu/drm/amd/acp/Kconfig b/src/linux/drivers/gpu/drm/amd/acp/Kconfig deleted file mode 100644 index e503e3d..0000000 --- a/src/linux/drivers/gpu/drm/amd/acp/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -menu "ACP (Audio CoProcessor) Configuration" - -config DRM_AMD_ACP - bool "Enable AMD Audio CoProcessor IP support" - depends on DRM_AMDGPU - select MFD_CORE - select PM_GENERIC_DOMAINS if PM - help - Choose this option to enable ACP IP support for AMD SOCs. - This adds the ACP (Audio CoProcessor) IP driver and wires - it up into the amdgpu driver. The ACP block provides the DMA - engine for the i2s-based ALSA driver. It is required for audio - on APUs which utilize an i2s codec. - -endmenu diff --git a/src/linux/drivers/gpu/drm/amd/amdgpu/Kconfig b/src/linux/drivers/gpu/drm/amd/amdgpu/Kconfig deleted file mode 100644 index 61360e2..0000000 --- a/src/linux/drivers/gpu/drm/amd/amdgpu/Kconfig +++ /dev/null @@ -1,35 +0,0 @@ -config DRM_AMDGPU_SI - bool "Enable amdgpu support for SI parts" - depends on DRM_AMDGPU - help - Choose this option if you want to enable experimental support - for SI asics. - -config DRM_AMDGPU_CIK - bool "Enable amdgpu support for CIK parts" - depends on DRM_AMDGPU - help - Choose this option if you want to enable experimental support - for CIK asics. - - CIK is already supported in radeon. CIK support in amdgpu - is for experimentation and testing. - -config DRM_AMDGPU_USERPTR - bool "Always enable userptr write support" - depends on DRM_AMDGPU - select MMU_NOTIFIER - help - This option selects CONFIG_MMU_NOTIFIER if it isn't already - selected to enabled full userptr support. - -config DRM_AMDGPU_GART_DEBUGFS - bool "Allow GART access through debugfs" - depends on DRM_AMDGPU - depends on DEBUG_FS - default n - help - Selecting this option creates a debugfs file to inspect the mapped - pages. Uses more memory for housekeeping, enable only for debugging. - -source "drivers/gpu/drm/amd/acp/Kconfig" diff --git a/src/linux/drivers/gpu/drm/amd/amdkfd/Kconfig b/src/linux/drivers/gpu/drm/amd/amdkfd/Kconfig deleted file mode 100644 index e13c67c..0000000 --- a/src/linux/drivers/gpu/drm/amd/amdkfd/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -# -# Heterogenous system architecture configuration -# - -config HSA_AMD - tristate "HSA kernel driver for AMD GPU devices" - depends on (DRM_RADEON || DRM_AMDGPU) && AMD_IOMMU_V2 && X86_64 - help - Enable this if you want to use HSA features on AMD GPU devices. diff --git a/src/linux/drivers/gpu/drm/arc/Kconfig b/src/linux/drivers/gpu/drm/arc/Kconfig deleted file mode 100644 index f47d88b..0000000 --- a/src/linux/drivers/gpu/drm/arc/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config DRM_ARCPGU - tristate "ARC PGU" - depends on DRM && OF - select DRM_KMS_CMA_HELPER - select DRM_KMS_HELPER - help - Choose this option if you have an ARC PGU controller. - - If M is selected the module will be called arcpgu. diff --git a/src/linux/drivers/gpu/drm/arm/Kconfig b/src/linux/drivers/gpu/drm/arm/Kconfig deleted file mode 100644 index 9a18e1b..0000000 --- a/src/linux/drivers/gpu/drm/arm/Kconfig +++ /dev/null @@ -1,42 +0,0 @@ -config DRM_ARM - bool - help - Choose this option to select drivers for ARM's devices - -config DRM_HDLCD - tristate "ARM HDLCD" - depends on DRM && OF && (ARM || ARM64) - depends on COMMON_CLK - select DRM_ARM - select DRM_KMS_HELPER - select DRM_KMS_CMA_HELPER - help - Choose this option if you have an ARM High Definition Colour LCD - controller. - - If M is selected the module will be called hdlcd. - -config DRM_HDLCD_SHOW_UNDERRUN - bool "Show underrun conditions" - depends on DRM_HDLCD - default n - help - Enable this option to show in red colour the pixels that the - HDLCD device did not fetch from framebuffer due to underrun - conditions. - -config DRM_MALI_DISPLAY - tristate "ARM Mali Display Processor" - depends on DRM && OF && (ARM || ARM64) - depends on COMMON_CLK - select DRM_ARM - select DRM_KMS_HELPER - select DRM_KMS_CMA_HELPER - select DRM_GEM_CMA_HELPER - select VIDEOMODE_HELPERS - help - Choose this option if you want to compile the ARM Mali Display - Processor driver. It supports the DP500, DP550 and DP650 variants - of the hardware. - - If compiled as a module it will be called mali-dp. diff --git a/src/linux/drivers/gpu/drm/armada/Kconfig b/src/linux/drivers/gpu/drm/armada/Kconfig deleted file mode 100644 index 15f3ecf..0000000 --- a/src/linux/drivers/gpu/drm/armada/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config DRM_ARMADA - tristate "DRM support for Marvell Armada SoCs" - depends on DRM && HAVE_CLK && ARM - select DRM_KMS_HELPER - help - Support the "LCD" controllers found on the Marvell Armada 510 - devices. There are two controllers on the device, each controller - supports graphics and video overlays. - - This driver provides no built-in acceleration; acceleration is - performed by other IP found on the SoC. This driver provides - kernel mode setting and buffer management to userspace. diff --git a/src/linux/drivers/gpu/drm/ast/Kconfig b/src/linux/drivers/gpu/drm/ast/Kconfig deleted file mode 100644 index 15f6ce7..0000000 --- a/src/linux/drivers/gpu/drm/ast/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config DRM_AST - tristate "AST server chips" - depends on DRM && PCI - select DRM_TTM - select DRM_KMS_HELPER - select DRM_TTM - help - Say yes for experimental AST GPU driver. Do not enable - this driver without having a working -modesetting, - and a version of AST that knows to fail if KMS - is bound to the driver. These GPUs are commonly found - in server chipsets. - diff --git a/src/linux/drivers/gpu/drm/atmel-hlcdc/Kconfig b/src/linux/drivers/gpu/drm/atmel-hlcdc/Kconfig deleted file mode 100644 index 32bcc4b..0000000 --- a/src/linux/drivers/gpu/drm/atmel-hlcdc/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config DRM_ATMEL_HLCDC - tristate "DRM Support for ATMEL HLCDC Display Controller" - depends on DRM && OF && COMMON_CLK && MFD_ATMEL_HLCDC && ARM - select DRM_GEM_CMA_HELPER - select DRM_KMS_HELPER - select DRM_KMS_CMA_HELPER - select DRM_PANEL - help - Choose this option if you have an ATMEL SoC with an HLCDC display - controller (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family). diff --git a/src/linux/drivers/gpu/drm/bochs/Kconfig b/src/linux/drivers/gpu/drm/bochs/Kconfig deleted file mode 100644 index f739763..0000000 --- a/src/linux/drivers/gpu/drm/bochs/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config DRM_BOCHS - tristate "DRM Support for bochs dispi vga interface (qemu stdvga)" - depends on DRM && PCI - select DRM_KMS_HELPER - select DRM_TTM - help - Choose this option for qemu. - If M is selected the module will be called bochs-drm. diff --git a/src/linux/drivers/gpu/drm/bridge/Kconfig b/src/linux/drivers/gpu/drm/bridge/Kconfig deleted file mode 100644 index 10e12e7..0000000 --- a/src/linux/drivers/gpu/drm/bridge/Kconfig +++ /dev/null @@ -1,81 +0,0 @@ -config DRM_BRIDGE - def_bool y - depends on DRM - help - Bridge registration and lookup framework. - -menu "Display Interface Bridges" - depends on DRM && DRM_BRIDGE - -config DRM_ANALOGIX_ANX78XX - tristate "Analogix ANX78XX bridge" - select DRM_KMS_HELPER - select REGMAP_I2C - ---help--- - ANX78XX is an ultra-low Full-HD SlimPort transmitter - designed for portable devices. The ANX78XX transforms - the HDMI output of an application processor to MyDP - or DisplayPort. - -config DRM_DUMB_VGA_DAC - tristate "Dumb VGA DAC Bridge support" - depends on OF - select DRM_KMS_HELPER - help - Support for RGB to VGA DAC based bridges - -config DRM_DW_HDMI - tristate - select DRM_KMS_HELPER - -config DRM_DW_HDMI_AHB_AUDIO - tristate "Synopsis Designware AHB Audio interface" - depends on DRM_DW_HDMI && SND - select SND_PCM - select SND_PCM_ELD - select SND_PCM_IEC958 - help - Support the AHB Audio interface which is part of the Synopsis - Designware HDMI block. This is used in conjunction with - the i.MX6 HDMI driver. - -config DRM_NXP_PTN3460 - tristate "NXP PTN3460 DP/LVDS bridge" - depends on OF - select DRM_KMS_HELPER - select DRM_PANEL - ---help--- - NXP PTN3460 eDP-LVDS bridge chip driver. - -config DRM_PARADE_PS8622 - tristate "Parade eDP/LVDS bridge" - depends on OF - select DRM_PANEL - select DRM_KMS_HELPER - select BACKLIGHT_LCD_SUPPORT - select BACKLIGHT_CLASS_DEVICE - ---help--- - Parade eDP-LVDS bridge chip driver. - -config DRM_SII902X - tristate "Silicon Image sii902x RGB/HDMI bridge" - depends on OF - select DRM_KMS_HELPER - select REGMAP_I2C - ---help--- - Silicon Image sii902x bridge chip driver. - -config DRM_TOSHIBA_TC358767 - tristate "Toshiba TC358767 eDP bridge" - depends on OF - select DRM_KMS_HELPER - select REGMAP_I2C - select DRM_PANEL - ---help--- - Toshiba TC358767 eDP bridge chip driver. - -source "drivers/gpu/drm/bridge/analogix/Kconfig" - -source "drivers/gpu/drm/bridge/adv7511/Kconfig" - -endmenu diff --git a/src/linux/drivers/gpu/drm/bridge/Makefile b/src/linux/drivers/gpu/drm/bridge/Makefile deleted file mode 100644 index cdf3a3c..0000000 --- a/src/linux/drivers/gpu/drm/bridge/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -ccflags-y := -Iinclude/drm - -obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o -obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o -obj-$(CONFIG_DRM_DW_HDMI) += dw-hdmi.o -obj-$(CONFIG_DRM_DW_HDMI_AHB_AUDIO) += dw-hdmi-ahb-audio.o -obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o -obj-$(CONFIG_DRM_PARADE_PS8622) += parade-ps8622.o -obj-$(CONFIG_DRM_SII902X) += sii902x.o -obj-$(CONFIG_DRM_TOSHIBA_TC358767) += tc358767.o -obj-$(CONFIG_DRM_ANALOGIX_DP) += analogix/ -obj-$(CONFIG_DRM_I2C_ADV7511) += adv7511/ diff --git a/src/linux/drivers/gpu/drm/bridge/adv7511/Kconfig b/src/linux/drivers/gpu/drm/bridge/adv7511/Kconfig deleted file mode 100644 index d2b0499..0000000 --- a/src/linux/drivers/gpu/drm/bridge/adv7511/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -config DRM_I2C_ADV7511 - tristate "AV7511 encoder" - depends on OF - select DRM_KMS_HELPER - select REGMAP_I2C - help - Support for the Analog Device ADV7511(W) and ADV7513 HDMI encoders. - -config DRM_I2C_ADV7533 - bool "ADV7533 encoder" - depends on DRM_I2C_ADV7511 - select DRM_MIPI_DSI - default y - help - Support for the Analog Devices ADV7533 DSI to HDMI encoder. diff --git a/src/linux/drivers/gpu/drm/bridge/analogix/Kconfig b/src/linux/drivers/gpu/drm/bridge/analogix/Kconfig deleted file mode 100644 index 80f286f..0000000 --- a/src/linux/drivers/gpu/drm/bridge/analogix/Kconfig +++ /dev/null @@ -1,3 +0,0 @@ -config DRM_ANALOGIX_DP - tristate - depends on DRM diff --git a/src/linux/drivers/gpu/drm/cirrus/Kconfig b/src/linux/drivers/gpu/drm/cirrus/Kconfig deleted file mode 100644 index 04b3c16..0000000 --- a/src/linux/drivers/gpu/drm/cirrus/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config DRM_CIRRUS_QEMU - tristate "Cirrus driver for QEMU emulated device" - depends on DRM && PCI - select DRM_KMS_HELPER - select DRM_TTM - help - This is a KMS driver for emulated cirrus device in qemu. - It is *NOT* intended for real cirrus devices. This requires - the modesetting userspace X.org driver. diff --git a/src/linux/drivers/gpu/drm/etnaviv/Kconfig b/src/linux/drivers/gpu/drm/etnaviv/Kconfig deleted file mode 100644 index 2cde7a5..0000000 --- a/src/linux/drivers/gpu/drm/etnaviv/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ - -config DRM_ETNAVIV - tristate "ETNAVIV (DRM support for Vivante GPU IP cores)" - depends on DRM - depends on ARCH_MXC || ARCH_DOVE - select SHMEM - select TMPFS - select IOMMU_API - select IOMMU_SUPPORT - select WANT_DEV_COREDUMP - help - DRM driver for Vivante GPUs. - -config DRM_ETNAVIV_REGISTER_LOGGING - bool "enable ETNAVIV register logging" - depends on DRM_ETNAVIV - help - Compile in support for logging register reads/writes in a format - that can be parsed by envytools demsm tool. If enabled, register - logging can be switched on via etnaviv.reglog=y module param. diff --git a/src/linux/drivers/gpu/drm/exynos/Kconfig b/src/linux/drivers/gpu/drm/exynos/Kconfig deleted file mode 100644 index 465d344..0000000 --- a/src/linux/drivers/gpu/drm/exynos/Kconfig +++ /dev/null @@ -1,121 +0,0 @@ -config DRM_EXYNOS - tristate "DRM Support for Samsung SoC EXYNOS Series" - depends on OF && DRM && (ARCH_S3C64XX || ARCH_EXYNOS || ARCH_MULTIPLATFORM) - select DRM_KMS_HELPER - select VIDEOMODE_HELPERS - help - Choose this option if you have a Samsung SoC EXYNOS chipset. - If M is selected the module will be called exynosdrm. - -if DRM_EXYNOS - -config DRM_EXYNOS_IOMMU - bool - depends on EXYNOS_IOMMU - default y - -comment "CRTCs" - -config DRM_EXYNOS_FIMD - bool "FIMD" - depends on !FB_S3C - select FB_MODE_HELPERS - select MFD_SYSCON - help - Choose this option if you want to use Exynos FIMD for DRM. - -config DRM_EXYNOS5433_DECON - bool "DECON on Exynos5433" - help - Choose this option if you want to use Exynos5433 DECON for DRM. - -config DRM_EXYNOS7_DECON - bool "DECON on Exynos7" - depends on !FB_S3C - select FB_MODE_HELPERS - help - Choose this option if you want to use Exynos DECON for DRM. - -config DRM_EXYNOS_MIXER - bool "Mixer" - help - Choose this option if you want to use Exynos Mixer for DRM. - -config DRM_EXYNOS_VIDI - bool "Virtual Display" - help - Choose this option if you want to use Exynos VIDI for DRM. - -comment "Encoders and Bridges" - -config DRM_EXYNOS_DPI - bool "Parallel output" - depends on DRM_EXYNOS_FIMD - select DRM_PANEL - default n - help - This enables support for Exynos parallel output. - -config DRM_EXYNOS_DSI - bool "MIPI-DSI host" - depends on DRM_EXYNOS_FIMD || DRM_EXYNOS5433_DECON || DRM_EXYNOS7_DECON - select DRM_MIPI_DSI - select DRM_PANEL - default n - help - This enables support for Exynos MIPI-DSI device. - -config DRM_EXYNOS_DP - bool "EXYNOS specific extensions for Analogix DP driver" - depends on DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON - select DRM_ANALOGIX_DP - default DRM_EXYNOS - select DRM_PANEL - help - This enables support for DP device. - -config DRM_EXYNOS_HDMI - bool "HDMI" - depends on DRM_EXYNOS_MIXER || DRM_EXYNOS5433_DECON - help - Choose this option if you want to use Exynos HDMI for DRM. - -config DRM_EXYNOS_MIC - bool "Mobile Image Compressor" - depends on DRM_EXYNOS5433_DECON - help - Choose this option if you want to use Exynos MIC for DRM. - -comment "Sub-drivers" - -config DRM_EXYNOS_G2D - bool "G2D" - depends on VIDEO_SAMSUNG_S5P_G2D=n - select FRAME_VECTOR - help - Choose this option if you want to use Exynos G2D for DRM. - -config DRM_EXYNOS_IPP - bool "Image Post Processor" - help - Choose this option if you want to use IPP feature for DRM. - -config DRM_EXYNOS_FIMC - bool "FIMC" - depends on DRM_EXYNOS_IPP && MFD_SYSCON - help - Choose this option if you want to use Exynos FIMC for DRM. - -config DRM_EXYNOS_ROTATOR - bool "Rotator" - depends on DRM_EXYNOS_IPP - help - Choose this option if you want to use Exynos Rotator for DRM. - -config DRM_EXYNOS_GSC - bool "GScaler" - depends on DRM_EXYNOS_IPP && ARCH_EXYNOS5 && !VIDEO_SAMSUNG_EXYNOS_GSC - help - Choose this option if you want to use Exynos GSC for DRM. - -endif diff --git a/src/linux/drivers/gpu/drm/fsl-dcu/Kconfig b/src/linux/drivers/gpu/drm/fsl-dcu/Kconfig deleted file mode 100644 index 14a72c4..0000000 --- a/src/linux/drivers/gpu/drm/fsl-dcu/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config DRM_FSL_DCU - tristate "DRM Support for Freescale DCU" - depends on DRM && OF && ARM && COMMON_CLK - select BACKLIGHT_CLASS_DEVICE - select BACKLIGHT_LCD_SUPPORT - select DRM_KMS_HELPER - select DRM_KMS_CMA_HELPER - select DRM_PANEL - select REGMAP_MMIO - select VIDEOMODE_HELPERS - help - Choose this option if you have an Freescale DCU chipset. - If M is selected the module will be called fsl-dcu-drm. diff --git a/src/linux/drivers/gpu/drm/gma500/Kconfig b/src/linux/drivers/gpu/drm/gma500/Kconfig deleted file mode 100644 index 8906d67..0000000 --- a/src/linux/drivers/gpu/drm/gma500/Kconfig +++ /dev/null @@ -1,34 +0,0 @@ -config DRM_GMA500 - tristate "Intel GMA5/600 KMS Framebuffer" - depends on DRM && PCI && X86 - select DRM_KMS_HELPER - select DRM_TTM - # GMA500 depends on ACPI_VIDEO when ACPI is enabled, just like i915 - select ACPI_VIDEO if ACPI - select BACKLIGHT_CLASS_DEVICE if ACPI - select INPUT if ACPI - help - Say yes for an experimental 2D KMS framebuffer driver for the - Intel GMA500 ('Poulsbo') and other Intel IMG based graphics - devices. - -config DRM_GMA600 - bool "Intel GMA600 support (Experimental)" - depends on DRM_GMA500 - help - Say yes to include support for GMA600 (Intel Moorestown/Oaktrail) - platforms with LVDS ports. MIPI is not currently supported. - -config DRM_GMA3600 - bool "Intel GMA3600/3650 support (Experimental)" - depends on DRM_GMA500 - help - Say yes to include basic support for Intel GMA3600/3650 (Intel - Cedar Trail) platforms. - -config DRM_MEDFIELD - bool "Intel Medfield support (Experimental)" - depends on DRM_GMA500 && X86_INTEL_MID - help - Say yes to include support for the Intel Medfield platform. - diff --git a/src/linux/drivers/gpu/drm/hisilicon/Kconfig b/src/linux/drivers/gpu/drm/hisilicon/Kconfig deleted file mode 100644 index 558c61b..0000000 --- a/src/linux/drivers/gpu/drm/hisilicon/Kconfig +++ /dev/null @@ -1,5 +0,0 @@ -# -# hisilicon drm device configuration. -# Please keep this list sorted alphabetically - -source "drivers/gpu/drm/hisilicon/kirin/Kconfig" diff --git a/src/linux/drivers/gpu/drm/hisilicon/Makefile b/src/linux/drivers/gpu/drm/hisilicon/Makefile deleted file mode 100644 index e3f6d49..0000000 --- a/src/linux/drivers/gpu/drm/hisilicon/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# -# Makefile for hisilicon drm drivers. -# Please keep this list sorted alphabetically - -obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/ diff --git a/src/linux/drivers/gpu/drm/hisilicon/kirin/Kconfig b/src/linux/drivers/gpu/drm/hisilicon/kirin/Kconfig deleted file mode 100644 index 499f644..0000000 --- a/src/linux/drivers/gpu/drm/hisilicon/kirin/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -config DRM_HISI_KIRIN - tristate "DRM Support for Hisilicon Kirin series SoCs Platform" - depends on DRM && OF && ARM64 - select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER - select DRM_KMS_CMA_HELPER - select HISI_KIRIN_DW_DSI - help - Choose this option if you have a hisilicon Kirin chipsets(hi6220). - If M is selected the module will be called kirin-drm. - -config HISI_KIRIN_DW_DSI - tristate "HiSilicon Kirin specific extensions for Synopsys DW MIPI DSI" - depends on DRM_HISI_KIRIN - select DRM_MIPI_DSI - help - This selects support for HiSilicon Kirin SoC specific extensions for - the Synopsys DesignWare DSI driver. If you want to enable MIPI DSI on - hi6220 based SoC, you should selet this option. diff --git a/src/linux/drivers/gpu/drm/i2c/Kconfig b/src/linux/drivers/gpu/drm/i2c/Kconfig deleted file mode 100644 index a6c92be..0000000 --- a/src/linux/drivers/gpu/drm/i2c/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -menu "I2C encoder or helper chips" - depends on DRM && DRM_KMS_HELPER && I2C - -config DRM_I2C_CH7006 - tristate "Chrontel ch7006 TV encoder" - default m if DRM_NOUVEAU - help - Support for Chrontel ch7006 and similar TV encoders, found - on some nVidia video cards. - - This driver is currently only useful if you're also using - the nouveau driver. - -config DRM_I2C_SIL164 - tristate "Silicon Image sil164 TMDS transmitter" - default m if DRM_NOUVEAU - help - Support for sil164 and similar single-link (or dual-link - when used in pairs) TMDS transmitters, used in some nVidia - video cards. - -config DRM_I2C_NXP_TDA998X - tristate "NXP Semiconductors TDA998X HDMI encoder" - default m if DRM_TILCDC - select SND_SOC_HDMI_CODEC if SND_SOC - help - Support for NXP Semiconductors TDA998X HDMI encoders. - -endmenu diff --git a/src/linux/drivers/gpu/drm/i2c/Makefile b/src/linux/drivers/gpu/drm/i2c/Makefile deleted file mode 100644 index 43aa33b..0000000 --- a/src/linux/drivers/gpu/drm/i2c/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -ccflags-y := -Iinclude/drm - -ch7006-y := ch7006_drv.o ch7006_mode.o -obj-$(CONFIG_DRM_I2C_CH7006) += ch7006.o - -sil164-y := sil164_drv.o -obj-$(CONFIG_DRM_I2C_SIL164) += sil164.o - -tda998x-y := tda998x_drv.o -obj-$(CONFIG_DRM_I2C_NXP_TDA998X) += tda998x.o diff --git a/src/linux/drivers/gpu/drm/i915/Kconfig b/src/linux/drivers/gpu/drm/i915/Kconfig deleted file mode 100644 index 7769e46..0000000 --- a/src/linux/drivers/gpu/drm/i915/Kconfig +++ /dev/null @@ -1,86 +0,0 @@ -config DRM_I915 - tristate "Intel 8xx/9xx/G3x/G4x/HD Graphics" - depends on DRM - depends on X86 && PCI - select INTEL_GTT - select INTERVAL_TREE - # we need shmfs for the swappable backing store, and in particular - # the shmem_readpage() which depends upon tmpfs - select SHMEM - select TMPFS - select DRM_KMS_HELPER - select DRM_PANEL - select DRM_MIPI_DSI - # i915 depends on ACPI_VIDEO when ACPI is enabled - # but for select to work, need to select ACPI_VIDEO's dependencies, ick - select BACKLIGHT_LCD_SUPPORT if ACPI - select BACKLIGHT_CLASS_DEVICE if ACPI - select INPUT if ACPI - select ACPI_VIDEO if ACPI - select ACPI_BUTTON if ACPI - help - Choose this option if you have a system that has "Intel Graphics - Media Accelerator" or "HD Graphics" integrated graphics, - including 830M, 845G, 852GM, 855GM, 865G, 915G, 945G, 965G, - G35, G41, G43, G45 chipsets and Celeron, Pentium, Core i3, - Core i5, Core i7 as well as Atom CPUs with integrated graphics. - If M is selected, the module will be called i915. AGP support - is required for this driver to work. This driver is used by - the Intel driver in X.org 6.8 and XFree86 4.4 and above. It - replaces the older i830 module that supported a subset of the - hardware in older X.org releases. - - Note that the older i810/i815 chipsets require the use of the - i810 driver instead, and the Atom z5xx series has an entirely - different implementation. - -config DRM_I915_PRELIMINARY_HW_SUPPORT - bool "Enable preliminary support for prerelease Intel hardware by default" - depends on DRM_I915 - default n - help - Choose this option if you have prerelease Intel hardware and want the - i915 driver to support it by default. You can enable such support at - runtime with the module option i915.preliminary_hw_support=1; this - option changes the default for that module option. - - If in doubt, say "N". - -config DRM_I915_USERPTR - bool "Always enable userptr support" - depends on DRM_I915 - select MMU_NOTIFIER - default y - help - This option selects CONFIG_MMU_NOTIFIER if it isn't already - selected to enabled full userptr support. - - If in doubt, say "Y". - -config DRM_I915_GVT - bool "Enable Intel GVT-g graphics virtualization host support" - depends on DRM_I915 - default n - help - Choose this option if you want to enable Intel GVT-g graphics - virtualization technology host support with integrated graphics. - With GVT-g, it's possible to have one integrated graphics - device shared by multiple VMs under different hypervisors. - - Note that at least one hypervisor like Xen or KVM is required for - this driver to work, and it only supports newer device from - Broadwell+. For further information and setup guide, you can - visit: http://01.org/igvt-g. - - Now it's just a stub to support the modifications of i915 for - GVT device model. It requires at least one MPT modules for Xen/KVM - and other components of GVT device model to work. Use it under - you own risk. - - If in doubt, say "N". - -menu "drm/i915 Debugging" -depends on DRM_I915 -depends on EXPERT -source drivers/gpu/drm/i915/Kconfig.debug -endmenu diff --git a/src/linux/drivers/gpu/drm/i915/Kconfig.debug b/src/linux/drivers/gpu/drm/i915/Kconfig.debug deleted file mode 100644 index cee87bf..0000000 --- a/src/linux/drivers/gpu/drm/i915/Kconfig.debug +++ /dev/null @@ -1,44 +0,0 @@ -config DRM_I915_WERROR - bool "Force GCC to throw an error instead of a warning when compiling" - # As this may inadvertently break the build, only allow the user - # to shoot oneself in the foot iff they aim really hard - depends on EXPERT - # We use the dependency on !COMPILE_TEST to not be enabled in - # allmodconfig or allyesconfig configurations - depends on !COMPILE_TEST - default n - help - Add -Werror to the build flags for (and only for) i915.ko. - Do not enable this unless you are writing code for the i915.ko module. - - Recommended for driver developers only. - - If in doubt, say "N". - -config DRM_I915_DEBUG - bool "Enable additional driver debugging" - depends on DRM_I915 - select PREEMPT_COUNT - select X86_MSR # used by igt/pm_rpm - select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks) - default n - help - Choose this option to turn on extra driver debugging that may affect - performance but will catch some internal issues. - - Recommended for driver developers only. - - If in doubt, say "N". - -config DRM_I915_DEBUG_GEM - bool "Insert extra checks into the GEM internals" - default n - depends on DRM_I915_WERROR - help - Enable extra sanity checks (including BUGs) along the GEM driver - paths that may slow the system down and if hit hang the machine. - - Recommended for driver developers only. - - If in doubt, say "N". - diff --git a/src/linux/drivers/gpu/drm/imx/Kconfig b/src/linux/drivers/gpu/drm/imx/Kconfig deleted file mode 100644 index f2c9ae8..0000000 --- a/src/linux/drivers/gpu/drm/imx/Kconfig +++ /dev/null @@ -1,46 +0,0 @@ -config DRM_IMX - tristate "DRM Support for Freescale i.MX" - select DRM_KMS_HELPER - select VIDEOMODE_HELPERS - select DRM_GEM_CMA_HELPER - select DRM_KMS_CMA_HELPER - depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM) - depends on IMX_IPUV3_CORE - help - enable i.MX graphics support - -config DRM_IMX_PARALLEL_DISPLAY - tristate "Support for parallel displays" - select DRM_PANEL - depends on DRM_IMX - select VIDEOMODE_HELPERS - -config DRM_IMX_TVE - tristate "Support for TV and VGA displays" - depends on DRM_IMX - select REGMAP_MMIO - help - Choose this to enable the internal Television Encoder (TVe) - found on i.MX53 processors. - -config DRM_IMX_LDB - tristate "Support for LVDS displays" - depends on DRM_IMX && MFD_SYSCON - select DRM_PANEL - help - Choose this to enable the internal LVDS Display Bridge (LDB) - found on i.MX53 and i.MX6 processors. - -config DRM_IMX_IPUV3 - tristate - depends on DRM_IMX - depends on IMX_IPUV3_CORE - default y if DRM_IMX=y - default m if DRM_IMX=m - -config DRM_IMX_HDMI - tristate "Freescale i.MX DRM HDMI" - select DRM_DW_HDMI - depends on DRM_IMX - help - Choose this if you want to use HDMI on i.MX6. diff --git a/src/linux/drivers/gpu/drm/mediatek/Kconfig b/src/linux/drivers/gpu/drm/mediatek/Kconfig deleted file mode 100644 index 294de45..0000000 --- a/src/linux/drivers/gpu/drm/mediatek/Kconfig +++ /dev/null @@ -1,26 +0,0 @@ -config DRM_MEDIATEK - tristate "DRM Support for Mediatek SoCs" - depends on DRM - depends on ARCH_MEDIATEK || (ARM && COMPILE_TEST) - depends on COMMON_CLK - depends on HAVE_ARM_SMCCC - depends on OF - select DRM_GEM_CMA_HELPER - select DRM_KMS_HELPER - select DRM_MIPI_DSI - select DRM_PANEL - select MEMORY - select MTK_SMI - help - Choose this option if you have a Mediatek SoCs. - The module will be called mediatek-drm - This driver provides kernel mode setting and - buffer management to userspace. - -config DRM_MEDIATEK_HDMI - tristate "DRM HDMI Support for Mediatek SoCs" - depends on DRM_MEDIATEK - select SND_SOC_HDMI_CODEC if SND_SOC - select GENERIC_PHY - help - DRM/KMS HDMI driver for Mediatek SoCs diff --git a/src/linux/drivers/gpu/drm/mgag200/Kconfig b/src/linux/drivers/gpu/drm/mgag200/Kconfig deleted file mode 100644 index 520e5e6..0000000 --- a/src/linux/drivers/gpu/drm/mgag200/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config DRM_MGAG200 - tristate "Kernel modesetting driver for MGA G200 server engines" - depends on DRM && PCI - select DRM_KMS_HELPER - select DRM_TTM - help - This is a KMS driver for the MGA G200 server chips, it - does not support the original MGA G200 or any of the desktop - chips. It requires 0.3.0 of the modesetting userspace driver, - and a version of mga driver that will fail on KMS enabled - devices. - diff --git a/src/linux/drivers/gpu/drm/msm/Kconfig b/src/linux/drivers/gpu/drm/msm/Kconfig deleted file mode 100644 index d96b2b6..0000000 --- a/src/linux/drivers/gpu/drm/msm/Kconfig +++ /dev/null @@ -1,73 +0,0 @@ - -config DRM_MSM - tristate "MSM DRM" - depends on DRM - depends on ARCH_QCOM || (ARM && COMPILE_TEST) - depends on OF && COMMON_CLK - select REGULATOR - select DRM_KMS_HELPER - select DRM_PANEL - select SHMEM - select TMPFS - select QCOM_SCM - select SND_SOC_HDMI_CODEC if SND_SOC - select SYNC_FILE - default y - help - DRM/KMS driver for MSM/snapdragon. - -config DRM_MSM_REGISTER_LOGGING - bool "MSM DRM register logging" - depends on DRM_MSM - default n - help - Compile in support for logging register reads/writes in a format - that can be parsed by envytools demsm tool. If enabled, register - logging can be switched on via msm.reglog=y module param. - -config DRM_MSM_HDMI_HDCP - bool "Enable HDMI HDCP support in MSM DRM driver" - depends on DRM_MSM && QCOM_SCM - default y - help - Choose this option to enable HDCP state machine - -config DRM_MSM_DSI - bool "Enable DSI support in MSM DRM driver" - depends on DRM_MSM - select DRM_PANEL - select DRM_MIPI_DSI - default y - help - Choose this option if you have a need for MIPI DSI connector - support. - -config DRM_MSM_DSI_PLL - bool "Enable DSI PLL driver in MSM DRM" - depends on DRM_MSM_DSI && COMMON_CLK - default y - help - Choose this option to enable DSI PLL driver which provides DSI - source clocks under common clock framework. - -config DRM_MSM_DSI_28NM_PHY - bool "Enable DSI 28nm PHY driver in MSM DRM" - depends on DRM_MSM_DSI - default y - help - Choose this option if the 28nm DSI PHY is used on the platform. - -config DRM_MSM_DSI_20NM_PHY - bool "Enable DSI 20nm PHY driver in MSM DRM" - depends on DRM_MSM_DSI - default y - help - Choose this option if the 20nm DSI PHY is used on the platform. - -config DRM_MSM_DSI_28NM_8960_PHY - bool "Enable DSI 28nm 8960 PHY driver in MSM DRM" - depends on DRM_MSM_DSI - default y - help - Choose this option if the 28nm DSI PHY 8960 variant is used on the - platform. diff --git a/src/linux/drivers/gpu/drm/nouveau/Kconfig b/src/linux/drivers/gpu/drm/nouveau/Kconfig deleted file mode 100644 index 2922a82..0000000 --- a/src/linux/drivers/gpu/drm/nouveau/Kconfig +++ /dev/null @@ -1,64 +0,0 @@ -config DRM_NOUVEAU - tristate "Nouveau (NVIDIA) cards" - depends on DRM && PCI - select FW_LOADER - select DRM_KMS_HELPER - select DRM_TTM - select FB_BACKLIGHT if DRM_NOUVEAU_BACKLIGHT - select ACPI_VIDEO if ACPI && X86 && BACKLIGHT_CLASS_DEVICE && INPUT - select X86_PLATFORM_DEVICES if ACPI && X86 - select ACPI_WMI if ACPI && X86 - select MXM_WMI if ACPI && X86 - select POWER_SUPPLY - # Similar to i915, we need to select ACPI_VIDEO and it's dependencies - select BACKLIGHT_LCD_SUPPORT if ACPI && X86 - select BACKLIGHT_CLASS_DEVICE if ACPI && X86 - select INPUT if ACPI && X86 - select THERMAL if ACPI && X86 - select ACPI_VIDEO if ACPI && X86 - help - Choose this option for open-source NVIDIA support. - -config NOUVEAU_PLATFORM_DRIVER - bool "Nouveau (NVIDIA) SoC GPUs" - depends on DRM_NOUVEAU && ARCH_TEGRA - default y - help - Support for Nouveau platform driver, used for SoC GPUs as found - on NVIDIA Tegra K1. - -config NOUVEAU_DEBUG - int "Maximum debug level" - depends on DRM_NOUVEAU - range 0 7 - default 5 - help - Selects the maximum debug level to compile support for. - - 0 - fatal - 1 - error - 2 - warning - 3 - info - 4 - debug - 5 - trace (recommended) - 6 - paranoia - 7 - spam - - The paranoia and spam levels will add a lot of extra checks which - may potentially slow down driver operation. - -config NOUVEAU_DEBUG_DEFAULT - int "Default debug level" - depends on DRM_NOUVEAU - range 0 7 - default 3 - help - Selects the default debug level - -config DRM_NOUVEAU_BACKLIGHT - bool "Support for backlight control" - depends on DRM_NOUVEAU - default y - help - Say Y here if you want to control the backlight of your display - (e.g. a laptop panel). diff --git a/src/linux/drivers/gpu/drm/omapdrm/Kconfig b/src/linux/drivers/gpu/drm/omapdrm/Kconfig deleted file mode 100644 index 556f81f..0000000 --- a/src/linux/drivers/gpu/drm/omapdrm/Kconfig +++ /dev/null @@ -1,25 +0,0 @@ -config DRM_OMAP - tristate "OMAP DRM" - depends on DRM - depends on ARCH_OMAP2PLUS || ARCH_MULTIPLATFORM - select OMAP2_DSS - select DRM_KMS_HELPER - default n - help - DRM display driver for OMAP2/3/4 based boards. - -if DRM_OMAP - -config DRM_OMAP_NUM_CRTCS - int "Number of CRTCs" - range 1 10 - default 1 if ARCH_OMAP2 || ARCH_OMAP3 - default 2 if ARCH_OMAP4 - help - Select the number of video overlays which can be used as framebuffers. - The remaining overlays are reserved for video. - -source "drivers/gpu/drm/omapdrm/dss/Kconfig" -source "drivers/gpu/drm/omapdrm/displays/Kconfig" - -endif diff --git a/src/linux/drivers/gpu/drm/omapdrm/Makefile b/src/linux/drivers/gpu/drm/omapdrm/Makefile deleted file mode 100644 index 48b7b75..0000000 --- a/src/linux/drivers/gpu/drm/omapdrm/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# -# Makefile for the drm device driver. This driver provides support for the -# Direct Rendering Infrastructure (DRI) -# - -obj-y += dss/ -obj-y += displays/ - -ccflags-y := -Iinclude/drm -omapdrm-y := omap_drv.o \ - omap_irq.o \ - omap_debugfs.o \ - omap_crtc.o \ - omap_plane.o \ - omap_encoder.o \ - omap_connector.o \ - omap_fb.o \ - omap_gem.o \ - omap_gem_dmabuf.o \ - omap_dmm_tiler.o \ - tcm-sita.o - -omapdrm-$(CONFIG_DRM_FBDEV_EMULATION) += omap_fbdev.o - -obj-$(CONFIG_DRM_OMAP) += omapdrm.o diff --git a/src/linux/drivers/gpu/drm/omapdrm/displays/Kconfig b/src/linux/drivers/gpu/drm/omapdrm/displays/Kconfig deleted file mode 100644 index c226da1..0000000 --- a/src/linux/drivers/gpu/drm/omapdrm/displays/Kconfig +++ /dev/null @@ -1,85 +0,0 @@ -menu "OMAPDRM External Display Device Drivers" - -config DRM_OMAP_ENCODER_OPA362 - tristate "OPA362 external analog amplifier" - help - Driver for OPA362 external analog TV amplifier controlled - through a GPIO. - -config DRM_OMAP_ENCODER_TFP410 - tristate "TFP410 DPI to DVI Encoder" - help - Driver for TFP410 DPI to DVI encoder. - -config DRM_OMAP_ENCODER_TPD12S015 - tristate "TPD12S015 HDMI ESD protection and level shifter" - help - Driver for TPD12S015, which offers HDMI ESD protection and level - shifting. - -config DRM_OMAP_CONNECTOR_DVI - tristate "DVI Connector" - depends on I2C - help - Driver for a generic DVI connector. - -config DRM_OMAP_CONNECTOR_HDMI - tristate "HDMI Connector" - help - Driver for a generic HDMI connector. - -config DRM_OMAP_CONNECTOR_ANALOG_TV - tristate "Analog TV Connector" - help - Driver for a generic analog TV connector. - -config DRM_OMAP_PANEL_DPI - tristate "Generic DPI panel" - help - Driver for generic DPI panels. - -config DRM_OMAP_PANEL_DSI_CM - tristate "Generic DSI Command Mode Panel" - depends on BACKLIGHT_CLASS_DEVICE - help - Driver for generic DSI command mode panels. - -config DRM_OMAP_PANEL_SONY_ACX565AKM - tristate "ACX565AKM Panel" - depends on SPI && BACKLIGHT_CLASS_DEVICE - help - This is the LCD panel used on Nokia N900 - -config DRM_OMAP_PANEL_LGPHILIPS_LB035Q02 - tristate "LG.Philips LB035Q02 LCD Panel" - depends on SPI - help - LCD Panel used on the Gumstix Overo Palo35 - -config DRM_OMAP_PANEL_SHARP_LS037V7DW01 - tristate "Sharp LS037V7DW01 LCD Panel" - depends on BACKLIGHT_CLASS_DEVICE - help - LCD Panel used in TI's SDP3430 and EVM boards - -config DRM_OMAP_PANEL_TPO_TD028TTEC1 - tristate "TPO TD028TTEC1 LCD Panel" - depends on SPI - help - LCD panel used in Openmoko. - -config DRM_OMAP_PANEL_TPO_TD043MTEA1 - tristate "TPO TD043MTEA1 LCD Panel" - depends on SPI - help - LCD Panel used in OMAP3 Pandora - -config DRM_OMAP_PANEL_NEC_NL8048HL11 - tristate "NEC NL8048HL11 Panel" - depends on SPI - depends on BACKLIGHT_CLASS_DEVICE - help - This NEC NL8048HL11 panel is TFT LCD used in the - Zoom2/3/3630 sdp boards. - -endmenu diff --git a/src/linux/drivers/gpu/drm/omapdrm/displays/Makefile b/src/linux/drivers/gpu/drm/omapdrm/displays/Makefile deleted file mode 100644 index 46baafb..0000000 --- a/src/linux/drivers/gpu/drm/omapdrm/displays/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -obj-$(CONFIG_DRM_OMAP_ENCODER_OPA362) += encoder-opa362.o -obj-$(CONFIG_DRM_OMAP_ENCODER_TFP410) += encoder-tfp410.o -obj-$(CONFIG_DRM_OMAP_ENCODER_TPD12S015) += encoder-tpd12s015.o -obj-$(CONFIG_DRM_OMAP_CONNECTOR_DVI) += connector-dvi.o -obj-$(CONFIG_DRM_OMAP_CONNECTOR_HDMI) += connector-hdmi.o -obj-$(CONFIG_DRM_OMAP_CONNECTOR_ANALOG_TV) += connector-analog-tv.o -obj-$(CONFIG_DRM_OMAP_PANEL_DPI) += panel-dpi.o -obj-$(CONFIG_DRM_OMAP_PANEL_DSI_CM) += panel-dsi-cm.o -obj-$(CONFIG_DRM_OMAP_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o -obj-$(CONFIG_DRM_OMAP_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o -obj-$(CONFIG_DRM_OMAP_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o -obj-$(CONFIG_DRM_OMAP_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o -obj-$(CONFIG_DRM_OMAP_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o -obj-$(CONFIG_DRM_OMAP_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o diff --git a/src/linux/drivers/gpu/drm/omapdrm/dss/Kconfig b/src/linux/drivers/gpu/drm/omapdrm/dss/Kconfig deleted file mode 100644 index d1fa730..0000000 --- a/src/linux/drivers/gpu/drm/omapdrm/dss/Kconfig +++ /dev/null @@ -1,135 +0,0 @@ -config OMAP2_DSS_INIT - bool - -menuconfig OMAP2_DSS - tristate "OMAP2+ Display Subsystem support" - select VIDEOMODE_HELPERS - select OMAP2_DSS_INIT - select HDMI - help - OMAP2+ Display Subsystem support. - -if OMAP2_DSS - -config OMAP2_DSS_DEBUG - bool "Debug support" - default n - help - This enables printing of debug messages. Alternatively, debug messages - can also be enabled by setting CONFIG_DYNAMIC_DEBUG and then setting - appropriate flags in /dynamic_debug/control. - -config OMAP2_DSS_DEBUGFS - bool "Debugfs filesystem support" - depends on DEBUG_FS - default n - help - This enables debugfs for OMAPDSS at /omapdss. This enables - querying about clock configuration and register configuration of dss, - dispc, dsi, hdmi and rfbi. - -config OMAP2_DSS_COLLECT_IRQ_STATS - bool "Collect DSS IRQ statistics" - depends on OMAP2_DSS_DEBUGFS - default n - help - Collect DSS IRQ statistics, printable via debugfs. - - The statistics can be found from - /omapdss/dispc_irq for DISPC interrupts, and - /omapdss/dsi_irq for DSI interrupts. - -config OMAP2_DSS_DPI - bool "DPI support" - default y - help - DPI Interface. This is the Parallel Display Interface. - -config OMAP2_DSS_RFBI - bool "RFBI support" - depends on BROKEN - default n - help - MIPI DBI support (RFBI, Remote Framebuffer Interface, in Texas - Instrument's terminology). - - DBI is a bus between the host processor and a peripheral, - such as a display or a framebuffer chip. - - See http://www.mipi.org/ for DBI specifications. - -config OMAP2_DSS_VENC - bool "VENC support" - default y - help - OMAP Video Encoder support for S-Video and composite TV-out. - -config OMAP2_DSS_HDMI_COMMON - bool - -config OMAP4_DSS_HDMI - bool "HDMI support for OMAP4" - default y - select OMAP2_DSS_HDMI_COMMON - help - HDMI support for OMAP4 based SoCs. - -config OMAP5_DSS_HDMI - bool "HDMI support for OMAP5" - default n - select OMAP2_DSS_HDMI_COMMON - help - HDMI Interface for OMAP5 and similar cores. This adds the High - Definition Multimedia Interface. See http://www.hdmi.org/ for HDMI - specification. - -config OMAP2_DSS_SDI - bool "SDI support" - default n - help - SDI (Serial Display Interface) support. - - SDI is a high speed one-way display serial bus between the host - processor and a display. - -config OMAP2_DSS_DSI - bool "DSI support" - default n - help - MIPI DSI (Display Serial Interface) support. - - DSI is a high speed half-duplex serial interface between the host - processor and a peripheral, such as a display or a framebuffer chip. - - See http://www.mipi.org/ for DSI specifications. - -config OMAP2_DSS_MIN_FCK_PER_PCK - int "Minimum FCK/PCK ratio (for scaling)" - range 0 32 - default 0 - help - This can be used to adjust the minimum FCK/PCK ratio. - - With this you can make sure that DISPC FCK is at least - n x PCK. Video plane scaling requires higher FCK than - normally. - - If this is set to 0, there's no extra constraint on the - DISPC FCK. However, the FCK will at minimum be - 2xPCK (if active matrix) or 3xPCK (if passive matrix). - - Max FCK is 173MHz, so this doesn't work if your PCK - is very high. - -config OMAP2_DSS_SLEEP_AFTER_VENC_RESET - bool "Sleep 20ms after VENC reset" - default y - help - There is a 20ms sleep after VENC reset which seemed to fix the - reset. The reason for the bug is unclear, and it's also unclear - on what platforms this happens. - - This option enables the sleep, and is enabled by default. You can - disable the sleep if it doesn't cause problems on your platform. - -endif diff --git a/src/linux/drivers/gpu/drm/omapdrm/dss/Makefile b/src/linux/drivers/gpu/drm/omapdrm/dss/Makefile deleted file mode 100644 index b651ec9..0000000 --- a/src/linux/drivers/gpu/drm/omapdrm/dss/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o -obj-$(CONFIG_OMAP2_DSS) += omapdss.o -# Core DSS files -omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ - output.o dss-of.o pll.o video-pll.o -omapdss-$(CONFIG_OMAP2_DSS_DPI) += dpi.o -omapdss-$(CONFIG_OMAP2_DSS_RFBI) += rfbi.o -omapdss-$(CONFIG_OMAP2_DSS_VENC) += venc.o -omapdss-$(CONFIG_OMAP2_DSS_SDI) += sdi.o -omapdss-$(CONFIG_OMAP2_DSS_DSI) += dsi.o -omapdss-$(CONFIG_OMAP2_DSS_HDMI_COMMON) += hdmi_common.o hdmi_wp.o hdmi_pll.o \ - hdmi_phy.o -omapdss-$(CONFIG_OMAP4_DSS_HDMI) += hdmi4.o hdmi4_core.o -omapdss-$(CONFIG_OMAP5_DSS_HDMI) += hdmi5.o hdmi5_core.o -ccflags-$(CONFIG_OMAP2_DSS_DEBUG) += -DDEBUG diff --git a/src/linux/drivers/gpu/drm/panel/Kconfig b/src/linux/drivers/gpu/drm/panel/Kconfig deleted file mode 100644 index 62aba97..0000000 --- a/src/linux/drivers/gpu/drm/panel/Kconfig +++ /dev/null @@ -1,84 +0,0 @@ -config DRM_PANEL - bool - depends on DRM - help - Panel registration and lookup framework. - -menu "Display Panels" - depends on DRM && DRM_PANEL - -config DRM_PANEL_SIMPLE - tristate "support for simple panels" - depends on OF - depends on BACKLIGHT_CLASS_DEVICE - select VIDEOMODE_HELPERS - help - DRM panel driver for dumb panels that need at most a regulator and - a GPIO to be powered up. Optionally a backlight can be attached so - that it can be automatically turned off when the panel goes into a - low power state. - -config DRM_PANEL_JDI_LT070ME05000 - tristate "JDI LT070ME05000 WUXGA DSI panel" - depends on OF - depends on DRM_MIPI_DSI - depends on BACKLIGHT_CLASS_DEVICE - help - Say Y here if you want to enable support for JDI DSI video mode - panel as found in Google Nexus 7 (2013) devices. - The panel has a 1200(RGB)×1920 (WUXGA) resolution and uses - 24 bit per pixel. - -config DRM_PANEL_SAMSUNG_LD9040 - tristate "Samsung LD9040 RGB/SPI panel" - depends on OF && SPI - select VIDEOMODE_HELPERS - -config DRM_PANEL_LG_LG4573 - tristate "LG4573 RGB/SPI panel" - depends on OF && SPI - select VIDEOMODE_HELPERS - help - Say Y here if you want to enable support for LG4573 RGB panel. - To compile this driver as a module, choose M here. - -config DRM_PANEL_PANASONIC_VVX10F034N00 - tristate "Panasonic VVX10F034N00 1920x1200 video mode panel" - depends on OF - depends on DRM_MIPI_DSI - depends on BACKLIGHT_CLASS_DEVICE - help - Say Y here if you want to enable support for Panasonic VVX10F034N00 - WUXGA (1920x1200) Novatek NT1397-based DSI panel as found in some - Xperia Z2 tablets - -config DRM_PANEL_SAMSUNG_S6E8AA0 - tristate "Samsung S6E8AA0 DSI video mode panel" - depends on OF - select DRM_MIPI_DSI - select VIDEOMODE_HELPERS - -config DRM_PANEL_SHARP_LQ101R1SX01 - tristate "Sharp LQ101R1SX01 panel" - depends on OF - depends on DRM_MIPI_DSI - depends on BACKLIGHT_CLASS_DEVICE - help - Say Y here if you want to enable support for Sharp LQ101R1SX01 - TFT-LCD modules. The panel has a 2560x1600 resolution and uses - 24 bit RGB per pixel. It provides a dual MIPI DSI interface to - the host and has a built-in LED backlight. - - To compile this driver as a module, choose M here: the module - will be called panel-sharp-lq101r1sx01. - -config DRM_PANEL_SHARP_LS043T1LE01 - tristate "Sharp LS043T1LE01 qHD video mode panel" - depends on OF - depends on DRM_MIPI_DSI - depends on BACKLIGHT_CLASS_DEVICE - help - Say Y here if you want to enable support for Sharp LS043T1LE01 qHD - (540x960) DSI panel as found on the Qualcomm APQ8074 Dragonboard - -endmenu diff --git a/src/linux/drivers/gpu/drm/panel/Makefile b/src/linux/drivers/gpu/drm/panel/Makefile deleted file mode 100644 index a5c7ec0..0000000 --- a/src/linux/drivers/gpu/drm/panel/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o -obj-$(CONFIG_DRM_PANEL_JDI_LT070ME05000) += panel-jdi-lt070me05000.o -obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o -obj-$(CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00) += panel-panasonic-vvx10f034n00.o -obj-$(CONFIG_DRM_PANEL_SAMSUNG_LD9040) += panel-samsung-ld9040.o -obj-$(CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0) += panel-samsung-s6e8aa0.o -obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o -obj-$(CONFIG_DRM_PANEL_SHARP_LS043T1LE01) += panel-sharp-ls043t1le01.o diff --git a/src/linux/drivers/gpu/drm/qxl/Kconfig b/src/linux/drivers/gpu/drm/qxl/Kconfig deleted file mode 100644 index da45b11..0000000 --- a/src/linux/drivers/gpu/drm/qxl/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config DRM_QXL - tristate "QXL virtual GPU" - depends on DRM && PCI - select DRM_KMS_HELPER - select DRM_TTM - select CRC32 - help - QXL virtual GPU for Spice virtualization desktop integration. - Do not enable this driver unless your distro ships a corresponding - X.org QXL driver that can handle kernel modesetting. diff --git a/src/linux/drivers/gpu/drm/radeon/.gitignore b/src/linux/drivers/gpu/drm/radeon/.gitignore deleted file mode 100644 index 403eb3a..0000000 --- a/src/linux/drivers/gpu/drm/radeon/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -mkregtable -*_reg_safe.h - diff --git a/src/linux/drivers/gpu/drm/radeon/Kconfig b/src/linux/drivers/gpu/drm/radeon/Kconfig deleted file mode 100644 index 9909f5c..0000000 --- a/src/linux/drivers/gpu/drm/radeon/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -config DRM_RADEON_USERPTR - bool "Always enable userptr support" - depends on DRM_RADEON - select MMU_NOTIFIER - help - This option selects CONFIG_MMU_NOTIFIER if it isn't already - selected to enabled full userptr support. diff --git a/src/linux/drivers/gpu/drm/rcar-du/Kconfig b/src/linux/drivers/gpu/drm/rcar-du/Kconfig deleted file mode 100644 index 4c2fd05..0000000 --- a/src/linux/drivers/gpu/drm/rcar-du/Kconfig +++ /dev/null @@ -1,31 +0,0 @@ -config DRM_RCAR_DU - tristate "DRM Support for R-Car Display Unit" - depends on DRM && OF - depends on ARM || ARM64 - depends on ARCH_RENESAS || COMPILE_TEST - select DRM_KMS_HELPER - select DRM_KMS_CMA_HELPER - select DRM_GEM_CMA_HELPER - select VIDEOMODE_HELPERS - help - Choose this option if you have an R-Car chipset. - If M is selected the module will be called rcar-du-drm. - -config DRM_RCAR_HDMI - bool "R-Car DU HDMI Encoder Support" - depends on DRM_RCAR_DU - help - Enable support for external HDMI encoders. - -config DRM_RCAR_LVDS - bool "R-Car DU LVDS Encoder Support" - depends on DRM_RCAR_DU - help - Enable support for the R-Car Display Unit embedded LVDS encoders. - -config DRM_RCAR_VSP - bool "R-Car DU VSP Compositor Support" - depends on DRM_RCAR_DU - depends on VIDEO_RENESAS_VSP1=y || (VIDEO_RENESAS_VSP1 && DRM_RCAR_DU=m) - help - Enable support to expose the R-Car VSP Compositor as KMS planes. diff --git a/src/linux/drivers/gpu/drm/rockchip/Kconfig b/src/linux/drivers/gpu/drm/rockchip/Kconfig deleted file mode 100644 index 3c58669..0000000 --- a/src/linux/drivers/gpu/drm/rockchip/Kconfig +++ /dev/null @@ -1,51 +0,0 @@ -config DRM_ROCKCHIP - tristate "DRM Support for Rockchip" - depends on DRM && ROCKCHIP_IOMMU - depends on RESET_CONTROLLER - select DRM_GEM_CMA_HELPER - select DRM_KMS_HELPER - select DRM_PANEL - select VIDEOMODE_HELPERS - help - Choose this option if you have a Rockchip soc chipset. - This driver provides kernel mode setting and buffer - management to userspace. This driver does not provide - 2D or 3D acceleration; acceleration is performed by other - IP found on the SoC. - -config ROCKCHIP_ANALOGIX_DP - tristate "Rockchip specific extensions for Analogix DP driver" - depends on DRM_ROCKCHIP - select DRM_ANALOGIX_DP - help - This selects support for Rockchip SoC specific extensions - for the Analogix Core DP driver. If you want to enable DP - on RK3288 based SoC, you should selet this option. - -config ROCKCHIP_DW_HDMI - tristate "Rockchip specific extensions for Synopsys DW HDMI" - depends on DRM_ROCKCHIP - select DRM_DW_HDMI - help - This selects support for Rockchip SoC specific extensions - for the Synopsys DesignWare HDMI driver. If you want to - enable HDMI on RK3288 based SoC, you should selet this - option. - -config ROCKCHIP_DW_MIPI_DSI - tristate "Rockchip specific extensions for Synopsys DW MIPI DSI" - depends on DRM_ROCKCHIP - select DRM_MIPI_DSI - help - This selects support for Rockchip SoC specific extensions - for the Synopsys DesignWare HDMI driver. If you want to - enable MIPI DSI on RK3288 based SoC, you should selet this - option. - -config ROCKCHIP_INNO_HDMI - tristate "Rockchip specific extensions for Innosilicon HDMI" - depends on DRM_ROCKCHIP - help - This selects support for Rockchip SoC specific extensions - for the Innosilicon HDMI driver. If you want to enable - HDMI on RK3036 based SoC, you should select this option. diff --git a/src/linux/drivers/gpu/drm/shmobile/Kconfig b/src/linux/drivers/gpu/drm/shmobile/Kconfig deleted file mode 100644 index c987c82..0000000 --- a/src/linux/drivers/gpu/drm/shmobile/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config DRM_SHMOBILE - tristate "DRM Support for SH Mobile" - depends on DRM && ARM - depends on ARCH_SHMOBILE || COMPILE_TEST - depends on FB_SH_MOBILE_MERAM || !FB_SH_MOBILE_MERAM - select BACKLIGHT_CLASS_DEVICE - select BACKLIGHT_LCD_SUPPORT - select DRM_KMS_HELPER - select DRM_KMS_CMA_HELPER - select DRM_GEM_CMA_HELPER - help - Choose this option if you have an SH Mobile chipset. - If M is selected the module will be called shmob-drm. - diff --git a/src/linux/drivers/gpu/drm/sti/Kconfig b/src/linux/drivers/gpu/drm/sti/Kconfig deleted file mode 100644 index acd7286..0000000 --- a/src/linux/drivers/gpu/drm/sti/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config DRM_STI - tristate "DRM Support for STMicroelectronics SoC stiH4xx Series" - depends on DRM && (ARCH_STI || ARCH_MULTIPLATFORM) - select RESET_CONTROLLER - select DRM_KMS_HELPER - select DRM_GEM_CMA_HELPER - select DRM_KMS_CMA_HELPER - select DRM_PANEL - select FW_LOADER - select SND_SOC_HDMI_CODEC if SND_SOC - help - Choose this option to enable DRM on STM stiH4xx chipset diff --git a/src/linux/drivers/gpu/drm/sun4i/Kconfig b/src/linux/drivers/gpu/drm/sun4i/Kconfig deleted file mode 100644 index a4b357d..0000000 --- a/src/linux/drivers/gpu/drm/sun4i/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config DRM_SUN4I - tristate "DRM Support for Allwinner A10 Display Engine" - depends on DRM && ARM && COMMON_CLK - depends on ARCH_SUNXI || COMPILE_TEST - select DRM_GEM_CMA_HELPER - select DRM_KMS_HELPER - select DRM_KMS_CMA_HELPER - select DRM_PANEL - select REGMAP_MMIO - select VIDEOMODE_HELPERS - help - Choose this option if you have an Allwinner SoC with a - Display Engine. If M is selected the module will be called - sun4i-drm. diff --git a/src/linux/drivers/gpu/drm/tegra/Kconfig b/src/linux/drivers/gpu/drm/tegra/Kconfig deleted file mode 100644 index 63ebb15..0000000 --- a/src/linux/drivers/gpu/drm/tegra/Kconfig +++ /dev/null @@ -1,32 +0,0 @@ -config DRM_TEGRA - tristate "NVIDIA Tegra DRM" - depends on ARCH_TEGRA || (ARM && COMPILE_TEST) - depends on COMMON_CLK - depends on DRM - depends on RESET_CONTROLLER - select DRM_KMS_HELPER - select DRM_MIPI_DSI - select DRM_PANEL - select TEGRA_HOST1X - help - Choose this option if you have an NVIDIA Tegra SoC. - - To compile this driver as a module, choose M here: the module - will be called tegra-drm. - -if DRM_TEGRA - -config DRM_TEGRA_DEBUG - bool "NVIDIA Tegra DRM debug support" - help - Say yes here to enable debugging support. - -config DRM_TEGRA_STAGING - bool "Enable HOST1X interface" - depends on STAGING - help - Say yes if HOST1X should be available for userspace DRM users. - - If unsure, choose N. - -endif diff --git a/src/linux/drivers/gpu/drm/tilcdc/Kconfig b/src/linux/drivers/gpu/drm/tilcdc/Kconfig deleted file mode 100644 index 28fed7e..0000000 --- a/src/linux/drivers/gpu/drm/tilcdc/Kconfig +++ /dev/null @@ -1,25 +0,0 @@ -config DRM_TILCDC - tristate "DRM Support for TI LCDC Display Controller" - depends on DRM && OF && ARM - select DRM_KMS_HELPER - select DRM_KMS_CMA_HELPER - select DRM_GEM_CMA_HELPER - select VIDEOMODE_HELPERS - select BACKLIGHT_CLASS_DEVICE - select BACKLIGHT_LCD_SUPPORT - help - Choose this option if you have an TI SoC with LCDC display - controller, for example AM33xx in beagle-bone, DA8xx, or - OMAP-L1xx. This driver replaces the FB_DA8XX fbdev driver. - -config DRM_TILCDC_SLAVE_COMPAT - bool "Support device tree blobs using TI LCDC Slave binding" - depends on DRM_TILCDC - default y - select OF_RESOLVE - select OF_OVERLAY - help - Choose this option if you need a kernel that is compatible - with device tree blobs using the obsolete "ti,tilcdc,slave" - binding. If you find "ti,tilcdc,slave"-string from your DTB, - you probably need this. Otherwise you do not. diff --git a/src/linux/drivers/gpu/drm/tilcdc/Makefile b/src/linux/drivers/gpu/drm/tilcdc/Makefile deleted file mode 100644 index 6f67517..0000000 --- a/src/linux/drivers/gpu/drm/tilcdc/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -ccflags-y := -Iinclude/drm -ifeq (, $(findstring -W,$(EXTRA_CFLAGS))) - ccflags-y += -Werror -endif - -obj-$(CONFIG_DRM_TILCDC_SLAVE_COMPAT) += tilcdc_slave_compat.o \ - tilcdc_slave_compat.dtb.o - -tilcdc-y := \ - tilcdc_plane.o \ - tilcdc_crtc.o \ - tilcdc_tfp410.o \ - tilcdc_panel.o \ - tilcdc_external.o \ - tilcdc_drv.o - -obj-$(CONFIG_DRM_TILCDC) += tilcdc.o diff --git a/src/linux/drivers/gpu/drm/udl/Kconfig b/src/linux/drivers/gpu/drm/udl/Kconfig deleted file mode 100644 index 1616ec4..0000000 --- a/src/linux/drivers/gpu/drm/udl/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config DRM_UDL - tristate "DisplayLink" - depends on DRM - depends on USB_SUPPORT - depends on USB_ARCH_HAS_HCD - select USB - select DRM_KMS_HELPER - help - This is a KMS driver for the USB displaylink video adapters. - Say M/Y to add support for these devices via drm/kms interfaces. diff --git a/src/linux/drivers/gpu/drm/vc4/Kconfig b/src/linux/drivers/gpu/drm/vc4/Kconfig deleted file mode 100644 index e53df59..0000000 --- a/src/linux/drivers/gpu/drm/vc4/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -config DRM_VC4 - tristate "Broadcom VC4 Graphics" - depends on ARCH_BCM2835 || COMPILE_TEST - depends on DRM - select DRM_KMS_HELPER - select DRM_KMS_CMA_HELPER - select DRM_GEM_CMA_HELPER - select DRM_PANEL - help - Choose this option if you have a system that has a Broadcom - VC4 GPU, such as the Raspberry Pi or other BCM2708/BCM2835. - - This driver requires that "avoid_warnings=2" be present in - the config.txt for the firmware, to keep it from smashing - our display setup. diff --git a/src/linux/drivers/gpu/drm/virtio/Kconfig b/src/linux/drivers/gpu/drm/virtio/Kconfig deleted file mode 100644 index e1afc3d..0000000 --- a/src/linux/drivers/gpu/drm/virtio/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config DRM_VIRTIO_GPU - tristate "Virtio GPU driver" - depends on DRM && VIRTIO - select DRM_KMS_HELPER - select DRM_TTM - help - This is the virtual GPU driver for virtio. It can be used with - QEMU based VMMs (like KVM or Xen). - - If unsure say M. diff --git a/src/linux/drivers/gpu/drm/vmwgfx/Kconfig b/src/linux/drivers/gpu/drm/vmwgfx/Kconfig deleted file mode 100644 index fb7b82a..0000000 --- a/src/linux/drivers/gpu/drm/vmwgfx/Kconfig +++ /dev/null @@ -1,26 +0,0 @@ -config DRM_VMWGFX - tristate "DRM driver for VMware Virtual GPU" - depends on DRM && PCI && X86 - select FB_DEFERRED_IO - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select DRM_TTM - select FB - # Only needed for the transitional use of drm_crtc_init - can be removed - # again once vmwgfx sets up the primary plane itself. - select DRM_KMS_HELPER - help - Choose this option if you would like to run 3D acceleration - in a VMware virtual machine. - This is a KMS enabled DRM driver for the VMware SVGA2 - virtual hardware. - The compiled module will be called "vmwgfx.ko". - -config DRM_VMWGFX_FBCON - depends on DRM_VMWGFX && FB - bool "Enable framebuffer console under vmwgfx by default" - help - Choose this option if you are shipping a new vmwgfx - userspace driver that supports using the kernel driver. - diff --git a/src/linux/drivers/gpu/host1x/Kconfig b/src/linux/drivers/gpu/host1x/Kconfig deleted file mode 100644 index b2fd029..0000000 --- a/src/linux/drivers/gpu/host1x/Kconfig +++ /dev/null @@ -1,22 +0,0 @@ -config TEGRA_HOST1X - tristate "NVIDIA Tegra host1x driver" - depends on ARCH_TEGRA || (ARM && COMPILE_TEST) - help - Driver for the NVIDIA Tegra host1x hardware. - - The Tegra host1x module is the DMA engine for register access to - Tegra's graphics- and multimedia-related modules. The modules served - by host1x are referred to as clients. host1x includes some other - functionality, such as synchronization. - -if TEGRA_HOST1X - -config TEGRA_HOST1X_FIREWALL - bool "Enable HOST1X security firewall" - default y - help - Say yes if kernel should protect command streams from tampering. - - If unsure, choose Y. - -endif diff --git a/src/linux/drivers/gpu/ipu-v3/Kconfig b/src/linux/drivers/gpu/ipu-v3/Kconfig deleted file mode 100644 index aefdff9..0000000 --- a/src/linux/drivers/gpu/ipu-v3/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config IMX_IPUV3_CORE - tristate "IPUv3 core support" - depends on SOC_IMX5 || SOC_IMX6Q || ARCH_MULTIPLATFORM - depends on RESET_CONTROLLER - select GENERIC_IRQ_CHIP - help - Choose this if you have a i.MX5/6 system and want to use the Image - Processing Unit. This option only enables IPU base support. diff --git a/src/linux/drivers/gpu/vga/Kconfig b/src/linux/drivers/gpu/vga/Kconfig deleted file mode 100644 index 29437ea..0000000 --- a/src/linux/drivers/gpu/vga/Kconfig +++ /dev/null @@ -1,30 +0,0 @@ -config VGA_ARB - bool "VGA Arbitration" if EXPERT - default y - depends on (PCI && !S390) - help - Some "legacy" VGA devices implemented on PCI typically have the same - hard-decoded addresses as they did on ISA. When multiple PCI devices - are accessed at same time they need some kind of coordination. Please - see Documentation/vgaarbiter.txt for more details. Select this to - enable VGA arbiter. - -config VGA_ARB_MAX_GPUS - int "Maximum number of GPUs" - default 16 - depends on VGA_ARB - help - Reserves space in the kernel to maintain resource locking for - multiple GPUS. The overhead for each GPU is very small. - -config VGA_SWITCHEROO - bool "Laptop Hybrid Graphics - GPU switching support" - depends on X86 - depends on ACPI - select VGA_ARB - help - Many laptops released in 2008/9/10 have two GPUs with a multiplexer - to switch between them. This adds support for dynamic switching when - X isn't running and delayed switching until the next logoff. This - feature is called hybrid graphics, ATI PowerXpress, and Nvidia - HybridPower. diff --git a/src/linux/drivers/gpu/vga/Makefile b/src/linux/drivers/gpu/vga/Makefile deleted file mode 100644 index 14ca30b..0000000 --- a/src/linux/drivers/gpu/vga/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-$(CONFIG_VGA_ARB) += vgaarb.o -obj-$(CONFIG_VGA_SWITCHEROO) += vga_switcheroo.o diff --git a/src/linux/drivers/hid/Kconfig b/src/linux/drivers/hid/Kconfig deleted file mode 100644 index cd4599c..0000000 --- a/src/linux/drivers/hid/Kconfig +++ /dev/null @@ -1,978 +0,0 @@ -# -# HID driver configuration -# -menu "HID support" - depends on INPUT - -config HID - tristate "HID bus support" - depends on INPUT - default y - ---help--- - A human interface device (HID) is a type of computer device that - interacts directly with and takes input from humans. The term "HID" - most commonly used to refer to the USB-HID specification, but other - devices (such as, but not strictly limited to, Bluetooth) are - designed using HID specification (this involves certain keyboards, - mice, tablets, etc). This option adds the HID bus to the kernel, - together with generic HID layer code. The HID devices are added and - removed from the HID bus by the transport-layer drivers, such as - usbhid (USB_HID) and hidp (BT_HIDP). - - For docs and specs, see http://www.usb.org/developers/hidpage/ - - If unsure, say Y. - -if HID - -config HID_BATTERY_STRENGTH - bool "Battery level reporting for HID devices" - depends on HID - select POWER_SUPPLY - default n - ---help--- - This option adds support of reporting battery strength (for HID devices - that support this feature) through power_supply class so that userspace - tools, such as upower, can display it. - -config HIDRAW - bool "/dev/hidraw raw HID device support" - depends on HID - ---help--- - Say Y here if you want to support HID devices (from the USB - specification standpoint) that aren't strictly user interface - devices, like monitor controls and Uninterruptable Power Supplies. - - This module supports these devices separately using a separate - event interface on /dev/hidraw. - - There is also a /dev/hiddev configuration option in the USB HID - configuration menu. In comparison to hiddev, this device does not process - the hid events at all (no parsing, no lookups). This lets applications - to work on raw hid events when they want to, and avoid using transport-specific - userspace libhid/libusb libraries. - - If unsure, say Y. - -config UHID - tristate "User-space I/O driver support for HID subsystem" - depends on HID - default n - ---help--- - Say Y here if you want to provide HID I/O Drivers from user-space. - This allows to write I/O drivers in user-space and feed the data from - the device into the kernel. The kernel parses the HID reports, loads the - corresponding HID Device Driver or provides input devices on top of your - user-space device. - - This driver cannot be used to parse HID-reports in user-space and write - special HID-drivers. You should use hidraw for that. - Instead, this driver allows to write the transport-layer driver in - user-space like USB-HID and Bluetooth-HID do in kernel-space. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called uhid. - -config HID_GENERIC - tristate "Generic HID driver" - depends on HID - default HID - ---help--- - Support for generic devices on the HID bus. This includes most - keyboards and mice, joysticks, tablets and digitizers. - - To compile this driver as a module, choose M here: the module - will be called hid-generic. - - If unsure, say Y. - -menu "Special HID drivers" - depends on HID - -config HID_A4TECH - tristate "A4 tech mice" - depends on HID - default !EXPERT - ---help--- - Support for A4 tech X5 and WOP-35 / Trust 450L mice. - -config HID_ACRUX - tristate "ACRUX game controller support" - depends on HID - ---help--- - Say Y here if you want to enable support for ACRUX game controllers. - -config HID_ACRUX_FF - bool "ACRUX force feedback support" - depends on HID_ACRUX - select INPUT_FF_MEMLESS - ---help--- - Say Y here if you want to enable force feedback support for ACRUX - game controllers. - -config HID_APPLE - tristate "Apple {i,Power,Mac}Books" - depends on HID - default !EXPERT - ---help--- - Support for some Apple devices which less or more break - HID specification. - - Say Y here if you want support for keyboards of Apple iBooks, PowerBooks, - MacBooks, MacBook Pros and Apple Aluminum. - -config HID_APPLEIR - tristate "Apple infrared receiver" - depends on (USB_HID) - ---help--- - Support for Apple infrared remote control. All the Apple computers from - 2005 onwards include such a port, except the unibody Macbook (2009), - and Mac Pros. This receiver is also used in the Apple TV set-top box - prior to the 2010 model. - - Say Y here if you want support for Apple infrared remote control. - -config HID_ASUS - tristate "Asus" - depends on I2C_HID - ---help--- - Support for Asus notebook built-in keyboard via i2c. - - Supported devices: - - EeeBook X205TA - - VivoBook E200HA - -config HID_AUREAL - tristate "Aureal" - depends on HID - ---help--- - Support for Aureal Cy se W-01RN Remote Controller and other Aureal derived remotes. - -config HID_BELKIN - tristate "Belkin Flip KVM and Wireless keyboard" - depends on HID - default !EXPERT - ---help--- - Support for Belkin Flip KVM and Wireless keyboard. - -config HID_BETOP_FF - tristate "Betop Production Inc. force feedback support" - depends on USB_HID - select INPUT_FF_MEMLESS - ---help--- - Say Y here if you want to enable force feedback support for devices by - BETOP Production Ltd. - Currently the following devices are known to be supported: - - BETOP 2185 PC & BFM MODE - -config HID_CHERRY - tristate "Cherry Cymotion keyboard" - depends on HID - default !EXPERT - ---help--- - Support for Cherry Cymotion keyboard. - -config HID_CHICONY - tristate "Chicony Tactical pad" - depends on HID - default !EXPERT - ---help--- - Support for Chicony Tactical pad. - -config HID_CORSAIR - tristate "Corsair devices" - depends on HID && USB && LEDS_CLASS - ---help--- - Support for Corsair devices that are not fully compliant with the - HID standard. - - Supported devices: - - Vengeance K90 - -config HID_PRODIKEYS - tristate "Prodikeys PC-MIDI Keyboard support" - depends on HID && SND - select SND_RAWMIDI - ---help--- - Support for Prodikeys PC-MIDI Keyboard device support. - Say Y here to enable support for this device. - - Prodikeys PC-MIDI keyboard. - The Prodikeys PC-MIDI acts as a USB Audio device, with one MIDI - input and one MIDI output. These MIDI jacks appear as - a sound "card" in the ALSA sound system. - Note: if you say N here, this device will still function as a basic - multimedia keyboard, but will lack support for the musical keyboard - and some additional multimedia keys. - -config HID_CMEDIA - tristate "CMedia CM6533 HID audio jack controls" - depends on HID - ---help--- - Support for CMedia CM6533 HID audio jack controls. - -config HID_CP2112 - tristate "Silicon Labs CP2112 HID USB-to-SMBus Bridge support" - depends on USB_HID && I2C && GPIOLIB - ---help--- - Support for Silicon Labs CP2112 HID USB to SMBus Master Bridge. - This is a HID device driver which registers as an i2c adapter - and gpiochip to expose these functions of the CP2112. The - customizable USB descriptor fields are exposed as sysfs attributes. - -config HID_CYPRESS - tristate "Cypress mouse and barcode readers" - depends on HID - default !EXPERT - ---help--- - Support for cypress mouse and barcode readers. - -config HID_DRAGONRISE - tristate "DragonRise Inc. game controller" - depends on HID - ---help--- - Say Y here if you have DragonRise Inc. game controllers. - These might be branded as: - - Tesun USB-703 - - Media-tech MT1504 "Rogue" - - DVTech JS19 "Gear" - - Defender Game Master - -config DRAGONRISE_FF - bool "DragonRise Inc. force feedback" - depends on HID_DRAGONRISE - select INPUT_FF_MEMLESS - ---help--- - Say Y here if you want to enable force feedback support for DragonRise Inc. - game controllers. - -config HID_EMS_FF - tristate "EMS Production Inc. force feedback support" - depends on HID - select INPUT_FF_MEMLESS - ---help--- - Say Y here if you want to enable force feedback support for devices by - EMS Production Ltd. - Currently the following devices are known to be supported: - - Trio Linker Plus II - -config HID_ELECOM - tristate "ELECOM BM084 bluetooth mouse" - depends on HID - ---help--- - Support for the ELECOM BM084 (bluetooth mouse). - -config HID_ELO - tristate "ELO USB 4000/4500 touchscreen" - depends on USB_HID - ---help--- - Support for the ELO USB 4000/4500 touchscreens. Note that this is for - different devices than those handled by CONFIG_TOUCHSCREEN_USB_ELO. - -config HID_EZKEY - tristate "Ezkey BTC 8193 keyboard" - depends on HID - default !EXPERT - ---help--- - Support for Ezkey BTC 8193 keyboard. - -config HID_GEMBIRD - tristate "Gembird Joypad" - depends on HID - ---help--- - Support for Gembird JPD-DualForce 2. - -config HID_GFRM - tristate "Google Fiber TV Box remote control support" - depends on HID - ---help--- - Support for Google Fiber TV Box remote controls - -config HID_HOLTEK - tristate "Holtek HID devices" - depends on USB_HID - ---help--- - Support for Holtek based devices: - - Holtek On Line Grip based game controller - - Trust GXT 18 Gaming Keyboard - - Sharkoon Drakonia / Perixx MX-2000 gaming mice - - Tracer Sniper TRM-503 / NOVA Gaming Slider X200 / - Zalman ZM-GM1 - - SHARKOON DarkGlider Gaming mouse - - LEETGION Hellion Gaming Mouse - -config HOLTEK_FF - bool "Holtek On Line Grip force feedback support" - depends on HID_HOLTEK - select INPUT_FF_MEMLESS - ---help--- - Say Y here if you have a Holtek On Line Grip based game controller - and want to have force feedback support for it. - -config HID_GT683R - tristate "MSI GT68xR LED support" - depends on LEDS_CLASS && USB_HID - ---help--- - Say Y here if you want to enable support for the three MSI GT68xR LEDs - - This driver support following modes: - - Normal: LEDs are fully on when enabled - - Audio: LEDs brightness depends on sound level - - Breathing: LEDs brightness varies at human breathing rate - - Currently the following devices are know to be supported: - - MSI GT683R - -config HID_KEYTOUCH - tristate "Keytouch HID devices" - depends on HID - ---help--- - Support for Keytouch HID devices not fully compliant with - the specification. Currently supported: - - Keytouch IEC 60945 - -config HID_KYE - tristate "KYE/Genius devices" - depends on HID - ---help--- - Support for KYE/Genius devices not fully compliant with HID standard: - - Ergo Mouse - - EasyPen i405X tablet - - MousePen i608X tablet - - EasyPen M610X tablet - -config HID_UCLOGIC - tristate "UC-Logic" - depends on USB_HID - ---help--- - Support for UC-Logic and Huion tablets. - -config HID_WALTOP - tristate "Waltop" - depends on HID - ---help--- - Support for Waltop tablets. - -config HID_GYRATION - tristate "Gyration remote control" - depends on HID - ---help--- - Support for Gyration remote control. - -config HID_ICADE - tristate "ION iCade arcade controller" - depends on HID - ---help--- - Support for the ION iCade arcade controller to work as a joystick. - - To compile this driver as a module, choose M here: the - module will be called hid-icade. - -config HID_TWINHAN - tristate "Twinhan IR remote control" - depends on HID - ---help--- - Support for Twinhan IR remote control. - -config HID_KENSINGTON - tristate "Kensington Slimblade Trackball" - depends on HID - default !EXPERT - ---help--- - Support for Kensington Slimblade Trackball. - -config HID_LCPOWER - tristate "LC-Power" - depends on HID - ---help--- - Support for LC-Power RC1000MCE RF remote control. - -config HID_LED - tristate "Simple RGB LED support" - depends on HID - depends on LEDS_CLASS - ---help--- - Support for simple RGB LED devices. Currently supported are: - - Riso Kagaku Webmail Notifier - - Dream Cheeky Webmail Notifier and Friends Alert - - ThingM blink(1) - - Delcom Visual Signal Indicator Generation 2 - - Greynut Luxafor - - To compile this driver as a module, choose M here: the - module will be called hid-led. - -config HID_LENOVO - tristate "Lenovo / Thinkpad devices" - depends on HID - select NEW_LEDS - select LEDS_CLASS - ---help--- - Support for Lenovo devices that are not fully compliant with HID standard. - - Say Y if you want support for the non-compliant features of the Lenovo - Thinkpad standalone keyboards, e.g: - - ThinkPad USB Keyboard with TrackPoint (supports extra LEDs and trackpoint - configuration) - - ThinkPad Compact Bluetooth Keyboard with TrackPoint (supports Fn keys) - - ThinkPad Compact USB Keyboard with TrackPoint (supports Fn keys) - -config HID_LOGITECH - tristate "Logitech devices" - depends on HID - default !EXPERT - ---help--- - Support for Logitech devices that are not fully compliant with HID standard. - -config HID_LOGITECH_DJ - tristate "Logitech Unifying receivers full support" - depends on HIDRAW - depends on HID_LOGITECH - select HID_LOGITECH_HIDPP - ---help--- - Say Y if you want support for Logitech Unifying receivers and devices. - Unifying receivers are capable of pairing up to 6 Logitech compliant - devices to the same receiver. Without this driver it will be handled by - generic USB_HID driver and all incoming events will be multiplexed - into a single mouse and a single keyboard device. - -config HID_LOGITECH_HIDPP - tristate "Logitech HID++ devices support" - depends on HID_LOGITECH - ---help--- - Support for Logitech devices relyingon the HID++ Logitech specification - - Say Y if you want support for Logitech devices relying on the HID++ - specification. Such devices are the various Logitech Touchpads (T650, - T651, TK820), some mice (Zone Touch mouse), or even keyboards (Solar - Keyboard). - -config LOGITECH_FF - bool "Logitech force feedback support" - depends on HID_LOGITECH - select INPUT_FF_MEMLESS - help - Say Y here if you have one of these devices: - - Logitech WingMan Cordless RumblePad - - Logitech WingMan Cordless RumblePad 2 - - Logitech WingMan Force 3D - - and if you want to enable force feedback for them. - Note: if you say N here, this device will still be supported, but without - force feedback. - -config LOGIRUMBLEPAD2_FF - bool "Logitech force feedback support (variant 2)" - depends on HID_LOGITECH - select INPUT_FF_MEMLESS - help - Say Y here if you want to enable force feedback support for: - - Logitech RumblePad - - Logitech Rumblepad 2 - - Logitech Formula Vibration Feedback Wheel - -config LOGIG940_FF - bool "Logitech Flight System G940 force feedback support" - depends on HID_LOGITECH - select INPUT_FF_MEMLESS - help - Say Y here if you want to enable force feedback support for Logitech - Flight System G940 devices. - -config LOGIWHEELS_FF - bool "Logitech wheels configuration and force feedback support" - depends on HID_LOGITECH - select INPUT_FF_MEMLESS - default LOGITECH_FF - help - Say Y here if you want to enable force feedback and range setting(*) - support for following Logitech wheels: - - Logitech G25 (*) - - Logitech G27 (*) - - Logitech G29 (*) - - Logitech Driving Force - - Logitech Driving Force Pro (*) - - Logitech Driving Force GT (*) - - Logitech Driving Force EX/RX - - Logitech Driving Force Wireless - - Logitech Speed Force Wireless - - Logitech MOMO Force - - Logitech MOMO Racing Force - - Logitech Formula Force GP - - Logitech Formula Force EX/RX - - Logitech Wingman Formula Force GP - -config HID_MAGICMOUSE - tristate "Apple Magic Mouse/Trackpad multi-touch support" - depends on HID - ---help--- - Support for the Apple Magic Mouse/Trackpad multi-touch. - - Say Y here if you want support for the multi-touch features of the - Apple Wireless "Magic" Mouse and the Apple Wireless "Magic" Trackpad. - -config HID_MICROSOFT - tristate "Microsoft non-fully HID-compliant devices" - depends on HID - default !EXPERT - ---help--- - Support for Microsoft devices that are not fully compliant with HID standard. - -config HID_MONTEREY - tristate "Monterey Genius KB29E keyboard" - depends on HID - default !EXPERT - ---help--- - Support for Monterey Genius KB29E. - -config HID_MULTITOUCH - tristate "HID Multitouch panels" - depends on HID - ---help--- - Generic support for HID multitouch panels. - - Say Y here if you have one of the following devices: - - 3M PCT touch screens - - ActionStar dual touch panels - - Atmel panels - - Cando dual touch panels - - Chunghwa panels - - CJTouch panels - - CVTouch panels - - Cypress TrueTouch panels - - Elan Microelectronics touch panels - - Elo TouchSystems IntelliTouch Plus panels - - GeneralTouch 'Sensing Win7-TwoFinger' panels - - GoodTouch panels - - Hanvon dual touch panels - - Ilitek dual touch panels - - IrTouch Infrared USB panels - - LG Display panels (Dell ST2220Tc) - - Lumio CrystalTouch panels - - MosArt dual-touch panels - - Panasonic multitouch panels - - PenMount dual touch panels - - Perixx Peripad 701 touchpad - - PixArt optical touch screen - - Pixcir dual touch panels - - Quanta panels - - eGalax dual-touch panels, including the Joojoo and Wetab tablets - - SiS multitouch panels - - Stantum multitouch panels - - Touch International Panels - - Unitec Panels - - Wistron optical touch panels - - XAT optical touch panels - - Xiroku optical touch panels - - Zytronic touch panels - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called hid-multitouch. - -config HID_NTRIG - tristate "N-Trig touch screen" - depends on USB_HID - ---help--- - Support for N-Trig touch screen. - -config HID_ORTEK - tristate "Ortek PKB-1700/WKB-2000/Skycable wireless keyboard and mouse trackpad" - depends on HID - ---help--- - There are certain devices which have LogicalMaximum wrong in the keyboard - usage page of their report descriptor. The most prevailing ones so far - are manufactured by Ortek, thus the name of the driver. Currently - supported devices by this driver are - - - Ortek PKB-1700 - - Ortek WKB-2000 - - Skycable wireless presenter - -config HID_PANTHERLORD - tristate "Pantherlord/GreenAsia game controller" - depends on HID - ---help--- - Say Y here if you have a PantherLord/GreenAsia based game controller - or adapter. - -config PANTHERLORD_FF - bool "Pantherlord force feedback support" - depends on HID_PANTHERLORD - select INPUT_FF_MEMLESS - ---help--- - Say Y here if you have a PantherLord/GreenAsia based game controller - or adapter and want to enable force feedback support for it. - -config HID_PENMOUNT - tristate "Penmount touch device" - depends on USB_HID - ---help--- - This selects a driver for the PenMount 6000 touch controller. - - The driver works around a problem in the report descript allowing - the userspace to touch events instead of mouse events. - - Say Y here if you have a Penmount based touch controller. - -config HID_PETALYNX - tristate "Petalynx Maxter remote control" - depends on HID - ---help--- - Support for Petalynx Maxter remote control. - -config HID_PICOLCD - tristate "PicoLCD (graphic version)" - depends on HID - ---help--- - This provides support for Minibox PicoLCD devices, currently - only the graphical ones are supported. - - This includes support for the following device features: - - Keypad - - Switching between Firmware and Flash mode - - EEProm / Flash access (via debugfs) - Features selectively enabled: - - Framebuffer for monochrome 256x64 display - - Backlight control - - Contrast control - - General purpose outputs - Features that are not (yet) supported: - - IR - -config HID_PICOLCD_FB - bool "Framebuffer support" if EXPERT - default !EXPERT - depends on HID_PICOLCD - depends on HID_PICOLCD=FB || FB=y - select FB_DEFERRED_IO - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - ---help--- - Provide access to PicoLCD's 256x64 monochrome display via a - framebuffer device. - -config HID_PICOLCD_BACKLIGHT - bool "Backlight control" if EXPERT - default !EXPERT - depends on HID_PICOLCD - depends on HID_PICOLCD=BACKLIGHT_CLASS_DEVICE || BACKLIGHT_CLASS_DEVICE=y - ---help--- - Provide access to PicoLCD's backlight control via backlight - class. - -config HID_PICOLCD_LCD - bool "Contrast control" if EXPERT - default !EXPERT - depends on HID_PICOLCD - depends on HID_PICOLCD=LCD_CLASS_DEVICE || LCD_CLASS_DEVICE=y - ---help--- - Provide access to PicoLCD's LCD contrast via lcd class. - -config HID_PICOLCD_LEDS - bool "GPO via leds class" if EXPERT - default !EXPERT - depends on HID_PICOLCD - depends on HID_PICOLCD=LEDS_CLASS || LEDS_CLASS=y - ---help--- - Provide access to PicoLCD's GPO pins via leds class. - -config HID_PICOLCD_CIR - bool "CIR via RC class" if EXPERT - default !EXPERT - depends on HID_PICOLCD - depends on HID_PICOLCD=RC_CORE || RC_CORE=y - ---help--- - Provide access to PicoLCD's CIR interface via remote control (LIRC). - -config HID_PLANTRONICS - tristate "Plantronics USB HID Driver" - depends on HID - ---help--- - Provides HID support for Plantronics USB audio devices. - Correctly maps vendor unique volume up/down HID usages to - KEY_VOLUMEUP and KEY_VOLUMEDOWN events and prevents core mapping - of other vendor unique HID usages to random mouse events. - - Say M here if you may ever plug in a Plantronics USB audio device. - -config HID_PRIMAX - tristate "Primax non-fully HID-compliant devices" - depends on HID - ---help--- - Support for Primax devices that are not fully compliant with the - HID standard. - -config HID_ROCCAT - tristate "Roccat device support" - depends on USB_HID - ---help--- - Support for Roccat devices. - Say Y here if you have a Roccat mouse or keyboard and want - support for its special functionalities. - -config HID_SAITEK - tristate "Saitek (Mad Catz) non-fully HID-compliant devices" - depends on HID - ---help--- - Support for Saitek devices that are not fully compliant with the - HID standard. - - Supported devices: - - PS1000 Dual Analog Pad - - Saitek R.A.T.7, R.A.T.9, M.M.O.7 Gaming Mice - - Mad Catz R.A.T.5, R.A.T.9 Gaming Mice - -config HID_SAMSUNG - tristate "Samsung InfraRed remote control or keyboards" - depends on HID - ---help--- - Support for Samsung InfraRed remote control or keyboards. - -config HID_SONY - tristate "Sony PS2/3/4 accessories" - depends on USB_HID - depends on NEW_LEDS - depends on LEDS_CLASS - select POWER_SUPPLY - ---help--- - Support for - - * Sony PS3 6-axis controllers - * Sony PS4 DualShock 4 controllers - * Buzz controllers - * Sony PS3 Blue-ray Disk Remote Control (Bluetooth) - * Logitech Harmony adapter for Sony Playstation 3 (Bluetooth) - -config SONY_FF - bool "Sony PS2/3/4 accessories force feedback support" - depends on HID_SONY - select INPUT_FF_MEMLESS - ---help--- - Say Y here if you have a Sony PS2/3/4 accessory and want to enable - force feedback support for it. - -config HID_SPEEDLINK - tristate "Speedlink VAD Cezanne mouse support" - depends on HID - ---help--- - Support for Speedlink Vicious and Divine Cezanne mouse. - -config HID_STEELSERIES - tristate "Steelseries SRW-S1 steering wheel support" - depends on HID - ---help--- - Support for Steelseries SRW-S1 steering wheel - -config HID_SUNPLUS - tristate "Sunplus wireless desktop" - depends on HID - ---help--- - Support for Sunplus wireless desktop. - -config HID_RMI - tristate "Synaptics RMI4 device support" - depends on HID - ---help--- - Support for Synaptics RMI4 touchpads. - Say Y here if you have a Synaptics RMI4 touchpads over i2c-hid or usbhid - and want support for its special functionalities. - -config HID_GREENASIA - tristate "GreenAsia (Product ID 0x12) game controller support" - depends on HID - ---help--- - Say Y here if you have a GreenAsia (Product ID 0x12) based game - controller or adapter. - -config GREENASIA_FF - bool "GreenAsia (Product ID 0x12) force feedback support" - depends on HID_GREENASIA - select INPUT_FF_MEMLESS - ---help--- - Say Y here if you have a GreenAsia (Product ID 0x12) based game controller - (like MANTA Warrior MM816 and SpeedLink Strike2 SL-6635) or adapter - and want to enable force feedback support for it. - -config HID_HYPERV_MOUSE - tristate "Microsoft Hyper-V mouse driver" - depends on HYPERV - ---help--- - Select this option to enable the Hyper-V mouse driver. - -config HID_SMARTJOYPLUS - tristate "SmartJoy PLUS PS2/USB adapter support" - depends on HID - ---help--- - Support for SmartJoy PLUS PS2/USB adapter, Super Dual Box, - Super Joy Box 3 Pro, Super Dual Box Pro, and Super Joy Box 5 Pro. - - Note that DDR (Dance Dance Revolution) mode is not supported, nor - is pressure sensitive buttons on the pro models. - -config SMARTJOYPLUS_FF - bool "SmartJoy PLUS PS2/USB adapter force feedback support" - depends on HID_SMARTJOYPLUS - select INPUT_FF_MEMLESS - ---help--- - Say Y here if you have a SmartJoy PLUS PS2/USB adapter and want to - enable force feedback support for it. - -config HID_TIVO - tristate "TiVo Slide Bluetooth remote control support" - depends on HID - ---help--- - Say Y if you have a TiVo Slide Bluetooth remote control. - -config HID_TOPSEED - tristate "TopSeed Cyberlink, BTC Emprex, Conceptronic remote control support" - depends on HID - ---help--- - Say Y if you have a TopSeed Cyberlink or BTC Emprex or Conceptronic - CLLRCMCE remote control. - -config HID_THINGM - tristate "ThingM blink(1) USB RGB LED" - depends on HID - depends on LEDS_CLASS - select HID_LED - ---help--- - Support for the ThingM blink(1) USB RGB LED. This driver has been - merged into the generic hid led driver. Config symbol HID_THINGM - just selects HID_LED and will be removed soon. - -config HID_THRUSTMASTER - tristate "ThrustMaster devices support" - depends on HID - ---help--- - Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or - a THRUSTMASTER Ferrari GT Rumble Wheel. - -config THRUSTMASTER_FF - bool "ThrustMaster devices force feedback support" - depends on HID_THRUSTMASTER - select INPUT_FF_MEMLESS - ---help--- - Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or 3, - a THRUSTMASTER Dual Trigger 3-in-1 or a THRUSTMASTER Ferrari GT - Rumble Force or Force Feedback Wheel. - -config HID_WACOM - tristate "Wacom Intuos/Graphire tablet support (USB)" - depends on HID - select POWER_SUPPLY - select NEW_LEDS - select LEDS_CLASS - select LEDS_TRIGGERS - help - Say Y here if you want to use the USB or BT version of the Wacom Intuos - or Graphire tablet. - - To compile this driver as a module, choose M here: the - module will be called wacom. - -config HID_WIIMOTE - tristate "Nintendo Wii / Wii U peripherals" - depends on HID - depends on LEDS_CLASS - select POWER_SUPPLY - select INPUT_FF_MEMLESS - ---help--- - Support for Nintendo Wii and Wii U Bluetooth peripherals. Supported - devices are the Wii Remote and its extension devices, but also devices - based on the Wii Remote like the Wii U Pro Controller or the - Wii Balance Board. - - Support for all official Nintendo extensions is available, however, 3rd - party extensions might not be supported. Please report these devices to: - http://github.com/dvdhrm/xwiimote/issues - - Other Nintendo Wii U peripherals that are IEEE 802.11 based (including - the Wii U Gamepad) might be supported in the future. But currently - support is limited to Bluetooth based devices. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called hid-wiimote. - -config HID_XINMO - tristate "Xin-Mo non-fully compliant devices" - depends on HID - ---help--- - Support for Xin-Mo devices that are not fully compliant with the HID - standard. Currently only supports the Xin-Mo Dual Arcade. Say Y here - if you have a Xin-Mo Dual Arcade controller. - -config HID_ZEROPLUS - tristate "Zeroplus based game controller support" - depends on HID - ---help--- - Say Y here if you have a Zeroplus based game controller. - -config ZEROPLUS_FF - bool "Zeroplus based game controller force feedback support" - depends on HID_ZEROPLUS - select INPUT_FF_MEMLESS - ---help--- - Say Y here if you have a Zeroplus based game controller and want - to have force feedback support for it. - -config HID_ZYDACRON - tristate "Zydacron remote control support" - depends on HID - ---help--- - Support for Zydacron remote control. - -config HID_SENSOR_HUB - tristate "HID Sensors framework support" - depends on HID && HAS_IOMEM - select MFD_CORE - default n - ---help--- - Support for HID Sensor framework. This creates a MFD instance - for a sensor hub and identifies all the sensors connected to it. - Each sensor is registered as a MFD cell, so that sensor specific - processing can be done in a separate driver. Each sensor - drivers can use the service provided by this driver to register - for events and handle data streams. Each sensor driver can format - data and present to user mode using input or IIO interface. - -config HID_SENSOR_CUSTOM_SENSOR - tristate "HID Sensors hub custom sensor support" - depends on HID_SENSOR_HUB - default n - ---help--- - HID Sensor hub specification allows definition of some custom and - generic sensors. Unlike other HID sensors, they can't be exported - via Linux IIO because of custom fields. This is up to the manufacturer - to decide how to interpret these special sensor ids and process in - the user space. Currently some manufacturers are using these ids for - sensor calibration and debugging other sensors. Manufacturers - should't use these special custom sensor ids to export any of the - standard sensors. - Select this config option for custom/generic sensor support. - -config HID_ALPS - tristate "Alps HID device support" - depends on HID - ---help--- - Support for Alps I2C HID touchpads and StickPointer. - Say Y here if you have a Alps touchpads over i2c-hid or usbhid - and want support for its special functionalities. - -endmenu - -endif # HID - -source "drivers/hid/usbhid/Kconfig" - -source "drivers/hid/i2c-hid/Kconfig" - -source "drivers/hid/intel-ish-hid/Kconfig" - -endmenu diff --git a/src/linux/drivers/hid/Makefile b/src/linux/drivers/hid/Makefile deleted file mode 100644 index 86b2b57..0000000 --- a/src/linux/drivers/hid/Makefile +++ /dev/null @@ -1,117 +0,0 @@ -# -# Makefile for the HID driver -# -hid-y := hid-core.o hid-input.o -hid-$(CONFIG_DEBUG_FS) += hid-debug.o - -obj-$(CONFIG_HID) += hid.o -obj-$(CONFIG_UHID) += uhid.o - -obj-$(CONFIG_HID_GENERIC) += hid-generic.o - -hid-$(CONFIG_HIDRAW) += hidraw.o - -hid-logitech-y := hid-lg.o -hid-logitech-$(CONFIG_LOGITECH_FF) += hid-lgff.o -hid-logitech-$(CONFIG_LOGIRUMBLEPAD2_FF) += hid-lg2ff.o -hid-logitech-$(CONFIG_LOGIG940_FF) += hid-lg3ff.o -hid-logitech-$(CONFIG_LOGIWHEELS_FF) += hid-lg4ff.o - -hid-wiimote-y := hid-wiimote-core.o hid-wiimote-modules.o -hid-wiimote-$(CONFIG_DEBUG_FS) += hid-wiimote-debug.o - -obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o -obj-$(CONFIG_HID_ALPS) += hid-alps.o -obj-$(CONFIG_HID_ACRUX) += hid-axff.o -obj-$(CONFIG_HID_APPLE) += hid-apple.o -obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o -obj-$(CONFIG_HID_ASUS) += hid-asus.o -obj-$(CONFIG_HID_AUREAL) += hid-aureal.o -obj-$(CONFIG_HID_BELKIN) += hid-belkin.o -obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o -obj-$(CONFIG_HID_CHERRY) += hid-cherry.o -obj-$(CONFIG_HID_CHICONY) += hid-chicony.o -obj-$(CONFIG_HID_CMEDIA) += hid-cmedia.o -obj-$(CONFIG_HID_CORSAIR) += hid-corsair.o -obj-$(CONFIG_HID_CP2112) += hid-cp2112.o -obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o -obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o -obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o -obj-$(CONFIG_HID_ELECOM) += hid-elecom.o -obj-$(CONFIG_HID_ELO) += hid-elo.o -obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o -obj-$(CONFIG_HID_GEMBIRD) += hid-gembird.o -obj-$(CONFIG_HID_GFRM) += hid-gfrm.o -obj-$(CONFIG_HID_GT683R) += hid-gt683r.o -obj-$(CONFIG_HID_GYRATION) += hid-gyration.o -obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o -obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o -obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o -obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o -obj-$(CONFIG_HID_ICADE) += hid-icade.o -obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o -obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o -obj-$(CONFIG_HID_KYE) += hid-kye.o -obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o -obj-$(CONFIG_HID_LENOVO) += hid-lenovo.o -obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o -obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o -obj-$(CONFIG_HID_LOGITECH_HIDPP) += hid-logitech-hidpp.o -obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o -obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o -obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o -obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o -obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o -obj-$(CONFIG_HID_ORTEK) += hid-ortek.o -obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o -obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o -obj-$(CONFIG_HID_PENMOUNT) += hid-penmount.o -obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o -obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o -hid-picolcd-y += hid-picolcd_core.o -hid-picolcd-$(CONFIG_HID_PICOLCD_FB) += hid-picolcd_fb.o -hid-picolcd-$(CONFIG_HID_PICOLCD_BACKLIGHT) += hid-picolcd_backlight.o -hid-picolcd-$(CONFIG_HID_PICOLCD_LCD) += hid-picolcd_lcd.o -hid-picolcd-$(CONFIG_HID_PICOLCD_LEDS) += hid-picolcd_leds.o -hid-picolcd-$(CONFIG_HID_PICOLCD_CIR) += hid-picolcd_cir.o -hid-picolcd-$(CONFIG_DEBUG_FS) += hid-picolcd_debugfs.o - -obj-$(CONFIG_HID_PLANTRONICS) += hid-plantronics.o -obj-$(CONFIG_HID_PRIMAX) += hid-primax.o -obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \ - hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \ - hid-roccat-koneplus.o hid-roccat-konepure.o hid-roccat-kovaplus.o \ - hid-roccat-lua.o hid-roccat-pyra.o hid-roccat-ryos.o hid-roccat-savu.o -obj-$(CONFIG_HID_RMI) += hid-rmi.o -obj-$(CONFIG_HID_SAITEK) += hid-saitek.o -obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o -obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o -obj-$(CONFIG_HID_SONY) += hid-sony.o -obj-$(CONFIG_HID_SPEEDLINK) += hid-speedlink.o -obj-$(CONFIG_HID_STEELSERIES) += hid-steelseries.o -obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o -obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o -obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o -obj-$(CONFIG_HID_TIVO) += hid-tivo.o -obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o -obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o -obj-$(CONFIG_HID_UCLOGIC) += hid-uclogic.o -obj-$(CONFIG_HID_LED) += hid-led.o -obj-$(CONFIG_HID_XINMO) += hid-xinmo.o -obj-$(CONFIG_HID_ZEROPLUS) += hid-zpff.o -obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o - -wacom-objs := wacom_wac.o wacom_sys.o -obj-$(CONFIG_HID_WACOM) += wacom.o -obj-$(CONFIG_HID_WALTOP) += hid-waltop.o -obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o -obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o -obj-$(CONFIG_HID_SENSOR_CUSTOM_SENSOR) += hid-sensor-custom.o - -obj-$(CONFIG_USB_HID) += usbhid/ -obj-$(CONFIG_USB_MOUSE) += usbhid/ -obj-$(CONFIG_USB_KBD) += usbhid/ - -obj-$(CONFIG_I2C_HID) += i2c-hid/ - -obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ diff --git a/src/linux/drivers/hid/hid-core.c b/src/linux/drivers/hid/hid-core.c deleted file mode 100644 index 2b89c70..0000000 --- a/src/linux/drivers/hid/hid-core.c +++ /dev/null @@ -1,2860 +0,0 @@ -/* - * HID support for Linux - * - * Copyright (c) 1999 Andreas Gal - * Copyright (c) 2000-2005 Vojtech Pavlik - * Copyright (c) 2005 Michael Haboustak for Concept2, Inc - * Copyright (c) 2006-2012 Jiri Kosina - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "hid-ids.h" - -/* - * Version Information - */ - -#define DRIVER_DESC "HID core driver" -#define DRIVER_LICENSE "GPL" - -int hid_debug = 0; -module_param_named(debug, hid_debug, int, 0600); -MODULE_PARM_DESC(debug, "toggle HID debugging messages"); -EXPORT_SYMBOL_GPL(hid_debug); - -static int hid_ignore_special_drivers = 0; -module_param_named(ignore_special_drivers, hid_ignore_special_drivers, int, 0600); -MODULE_PARM_DESC(ignore_special_drivers, "Ignore any special drivers and handle all devices by generic driver"); - -/* - * Register a new report for a device. - */ - -struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id) -{ - struct hid_report_enum *report_enum = device->report_enum + type; - struct hid_report *report; - - if (id >= HID_MAX_IDS) - return NULL; - if (report_enum->report_id_hash[id]) - return report_enum->report_id_hash[id]; - - report = kzalloc(sizeof(struct hid_report), GFP_KERNEL); - if (!report) - return NULL; - - if (id != 0) - report_enum->numbered = 1; - - report->id = id; - report->type = type; - report->size = 0; - report->device = device; - report_enum->report_id_hash[id] = report; - - list_add_tail(&report->list, &report_enum->report_list); - - return report; -} -EXPORT_SYMBOL_GPL(hid_register_report); - -/* - * Register a new field for this report. - */ - -static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values) -{ - struct hid_field *field; - - if (report->maxfield == HID_MAX_FIELDS) { - hid_err(report->device, "too many fields in report\n"); - return NULL; - } - - field = kzalloc((sizeof(struct hid_field) + - usages * sizeof(struct hid_usage) + - values * sizeof(unsigned)), GFP_KERNEL); - if (!field) - return NULL; - - field->index = report->maxfield++; - report->field[field->index] = field; - field->usage = (struct hid_usage *)(field + 1); - field->value = (s32 *)(field->usage + usages); - field->report = report; - - return field; -} - -/* - * Open a collection. The type/usage is pushed on the stack. - */ - -static int open_collection(struct hid_parser *parser, unsigned type) -{ - struct hid_collection *collection; - unsigned usage; - - usage = parser->local.usage[0]; - - if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) { - hid_err(parser->device, "collection stack overflow\n"); - return -EINVAL; - } - - if (parser->device->maxcollection == parser->device->collection_size) { - collection = kmalloc(sizeof(struct hid_collection) * - parser->device->collection_size * 2, GFP_KERNEL); - if (collection == NULL) { - hid_err(parser->device, "failed to reallocate collection array\n"); - return -ENOMEM; - } - memcpy(collection, parser->device->collection, - sizeof(struct hid_collection) * - parser->device->collection_size); - memset(collection + parser->device->collection_size, 0, - sizeof(struct hid_collection) * - parser->device->collection_size); - kfree(parser->device->collection); - parser->device->collection = collection; - parser->device->collection_size *= 2; - } - - parser->collection_stack[parser->collection_stack_ptr++] = - parser->device->maxcollection; - - collection = parser->device->collection + - parser->device->maxcollection++; - collection->type = type; - collection->usage = usage; - collection->level = parser->collection_stack_ptr - 1; - - if (type == HID_COLLECTION_APPLICATION) - parser->device->maxapplication++; - - return 0; -} - -/* - * Close a collection. - */ - -static int close_collection(struct hid_parser *parser) -{ - if (!parser->collection_stack_ptr) { - hid_err(parser->device, "collection stack underflow\n"); - return -EINVAL; - } - parser->collection_stack_ptr--; - return 0; -} - -/* - * Climb up the stack, search for the specified collection type - * and return the usage. - */ - -static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type) -{ - struct hid_collection *collection = parser->device->collection; - int n; - - for (n = parser->collection_stack_ptr - 1; n >= 0; n--) { - unsigned index = parser->collection_stack[n]; - if (collection[index].type == type) - return collection[index].usage; - } - return 0; /* we know nothing about this usage type */ -} - -/* - * Add a usage to the temporary parser table. - */ - -static int hid_add_usage(struct hid_parser *parser, unsigned usage) -{ - if (parser->local.usage_index >= HID_MAX_USAGES) { - hid_err(parser->device, "usage index exceeded\n"); - return -1; - } - parser->local.usage[parser->local.usage_index] = usage; - parser->local.collection_index[parser->local.usage_index] = - parser->collection_stack_ptr ? - parser->collection_stack[parser->collection_stack_ptr - 1] : 0; - parser->local.usage_index++; - return 0; -} - -/* - * Register a new field for this report. - */ - -static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags) -{ - struct hid_report *report; - struct hid_field *field; - unsigned usages; - unsigned offset; - unsigned i; - - report = hid_register_report(parser->device, report_type, parser->global.report_id); - if (!report) { - hid_err(parser->device, "hid_register_report failed\n"); - return -1; - } - - /* Handle both signed and unsigned cases properly */ - if ((parser->global.logical_minimum < 0 && - parser->global.logical_maximum < - parser->global.logical_minimum) || - (parser->global.logical_minimum >= 0 && - (__u32)parser->global.logical_maximum < - (__u32)parser->global.logical_minimum)) { - dbg_hid("logical range invalid 0x%x 0x%x\n", - parser->global.logical_minimum, - parser->global.logical_maximum); - return -1; - } - - offset = report->size; - report->size += parser->global.report_size * parser->global.report_count; - - if (!parser->local.usage_index) /* Ignore padding fields */ - return 0; - - usages = max_t(unsigned, parser->local.usage_index, - parser->global.report_count); - - field = hid_register_field(report, usages, parser->global.report_count); - if (!field) - return 0; - - field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL); - field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL); - field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION); - - for (i = 0; i < usages; i++) { - unsigned j = i; - /* Duplicate the last usage we parsed if we have excess values */ - if (i >= parser->local.usage_index) - j = parser->local.usage_index - 1; - field->usage[i].hid = parser->local.usage[j]; - field->usage[i].collection_index = - parser->local.collection_index[j]; - field->usage[i].usage_index = i; - } - - field->maxusage = usages; - field->flags = flags; - field->report_offset = offset; - field->report_type = report_type; - field->report_size = parser->global.report_size; - field->report_count = parser->global.report_count; - field->logical_minimum = parser->global.logical_minimum; - field->logical_maximum = parser->global.logical_maximum; - field->physical_minimum = parser->global.physical_minimum; - field->physical_maximum = parser->global.physical_maximum; - field->unit_exponent = parser->global.unit_exponent; - field->unit = parser->global.unit; - - return 0; -} - -/* - * Read data value from item. - */ - -static u32 item_udata(struct hid_item *item) -{ - switch (item->size) { - case 1: return item->data.u8; - case 2: return item->data.u16; - case 4: return item->data.u32; - } - return 0; -} - -static s32 item_sdata(struct hid_item *item) -{ - switch (item->size) { - case 1: return item->data.s8; - case 2: return item->data.s16; - case 4: return item->data.s32; - } - return 0; -} - -/* - * Process a global item. - */ - -static int hid_parser_global(struct hid_parser *parser, struct hid_item *item) -{ - __s32 raw_value; - switch (item->tag) { - case HID_GLOBAL_ITEM_TAG_PUSH: - - if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) { - hid_err(parser->device, "global environment stack overflow\n"); - return -1; - } - - memcpy(parser->global_stack + parser->global_stack_ptr++, - &parser->global, sizeof(struct hid_global)); - return 0; - - case HID_GLOBAL_ITEM_TAG_POP: - - if (!parser->global_stack_ptr) { - hid_err(parser->device, "global environment stack underflow\n"); - return -1; - } - - memcpy(&parser->global, parser->global_stack + - --parser->global_stack_ptr, sizeof(struct hid_global)); - return 0; - - case HID_GLOBAL_ITEM_TAG_USAGE_PAGE: - parser->global.usage_page = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM: - parser->global.logical_minimum = item_sdata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM: - if (parser->global.logical_minimum < 0) - parser->global.logical_maximum = item_sdata(item); - else - parser->global.logical_maximum = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM: - parser->global.physical_minimum = item_sdata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM: - if (parser->global.physical_minimum < 0) - parser->global.physical_maximum = item_sdata(item); - else - parser->global.physical_maximum = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: - /* Many devices provide unit exponent as a two's complement - * nibble due to the common misunderstanding of HID - * specification 1.11, 6.2.2.7 Global Items. Attempt to handle - * both this and the standard encoding. */ - raw_value = item_sdata(item); - if (!(raw_value & 0xfffffff0)) - parser->global.unit_exponent = hid_snto32(raw_value, 4); - else - parser->global.unit_exponent = raw_value; - return 0; - - case HID_GLOBAL_ITEM_TAG_UNIT: - parser->global.unit = item_udata(item); - return 0; - - case HID_GLOBAL_ITEM_TAG_REPORT_SIZE: - parser->global.report_size = item_udata(item); - if (parser->global.report_size > 128) { - hid_err(parser->device, "invalid report_size %d\n", - parser->global.report_size); - return -1; - } - return 0; - - case HID_GLOBAL_ITEM_TAG_REPORT_COUNT: - parser->global.report_count = item_udata(item); - if (parser->global.report_count > HID_MAX_USAGES) { - hid_err(parser->device, "invalid report_count %d\n", - parser->global.report_count); - return -1; - } - return 0; - - case HID_GLOBAL_ITEM_TAG_REPORT_ID: - parser->global.report_id = item_udata(item); - if (parser->global.report_id == 0 || - parser->global.report_id >= HID_MAX_IDS) { - hid_err(parser->device, "report_id %u is invalid\n", - parser->global.report_id); - return -1; - } - return 0; - - default: - hid_err(parser->device, "unknown global tag 0x%x\n", item->tag); - return -1; - } -} - -/* - * Process a local item. - */ - -static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) -{ - __u32 data; - unsigned n; - __u32 count; - - data = item_udata(item); - - switch (item->tag) { - case HID_LOCAL_ITEM_TAG_DELIMITER: - - if (data) { - /* - * We treat items before the first delimiter - * as global to all usage sets (branch 0). - * In the moment we process only these global - * items and the first delimiter set. - */ - if (parser->local.delimiter_depth != 0) { - hid_err(parser->device, "nested delimiters\n"); - return -1; - } - parser->local.delimiter_depth++; - parser->local.delimiter_branch++; - } else { - if (parser->local.delimiter_depth < 1) { - hid_err(parser->device, "bogus close delimiter\n"); - return -1; - } - parser->local.delimiter_depth--; - } - return 0; - - case HID_LOCAL_ITEM_TAG_USAGE: - - if (parser->local.delimiter_branch > 1) { - dbg_hid("alternative usage ignored\n"); - return 0; - } - - if (item->size <= 2) - data = (parser->global.usage_page << 16) + data; - - return hid_add_usage(parser, data); - - case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: - - if (parser->local.delimiter_branch > 1) { - dbg_hid("alternative usage ignored\n"); - return 0; - } - - if (item->size <= 2) - data = (parser->global.usage_page << 16) + data; - - parser->local.usage_minimum = data; - return 0; - - case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: - - if (parser->local.delimiter_branch > 1) { - dbg_hid("alternative usage ignored\n"); - return 0; - } - - if (item->size <= 2) - data = (parser->global.usage_page << 16) + data; - - count = data - parser->local.usage_minimum; - if (count + parser->local.usage_index >= HID_MAX_USAGES) { - /* - * We do not warn if the name is not set, we are - * actually pre-scanning the device. - */ - if (dev_name(&parser->device->dev)) - hid_warn(parser->device, - "ignoring exceeding usage max\n"); - data = HID_MAX_USAGES - parser->local.usage_index + - parser->local.usage_minimum - 1; - if (data <= 0) { - hid_err(parser->device, - "no more usage index available\n"); - return -1; - } - } - - for (n = parser->local.usage_minimum; n <= data; n++) - if (hid_add_usage(parser, n)) { - dbg_hid("hid_add_usage failed\n"); - return -1; - } - return 0; - - default: - - dbg_hid("unknown local item tag 0x%x\n", item->tag); - return 0; - } - return 0; -} - -/* - * Process a main item. - */ - -static int hid_parser_main(struct hid_parser *parser, struct hid_item *item) -{ - __u32 data; - int ret; - - data = item_udata(item); - - switch (item->tag) { - case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: - ret = open_collection(parser, data & 0xff); - break; - case HID_MAIN_ITEM_TAG_END_COLLECTION: - ret = close_collection(parser); - break; - case HID_MAIN_ITEM_TAG_INPUT: - ret = hid_add_field(parser, HID_INPUT_REPORT, data); - break; - case HID_MAIN_ITEM_TAG_OUTPUT: - ret = hid_add_field(parser, HID_OUTPUT_REPORT, data); - break; - case HID_MAIN_ITEM_TAG_FEATURE: - ret = hid_add_field(parser, HID_FEATURE_REPORT, data); - break; - default: - hid_err(parser->device, "unknown main item tag 0x%x\n", item->tag); - ret = 0; - } - - memset(&parser->local, 0, sizeof(parser->local)); /* Reset the local parser environment */ - - return ret; -} - -/* - * Process a reserved item. - */ - -static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item) -{ - dbg_hid("reserved item type, tag 0x%x\n", item->tag); - return 0; -} - -/* - * Free a report and all registered fields. The field->usage and - * field->value table's are allocated behind the field, so we need - * only to free(field) itself. - */ - -static void hid_free_report(struct hid_report *report) -{ - unsigned n; - - for (n = 0; n < report->maxfield; n++) - kfree(report->field[n]); - kfree(report); -} - -/* - * Close report. This function returns the device - * state to the point prior to hid_open_report(). - */ -static void hid_close_report(struct hid_device *device) -{ - unsigned i, j; - - for (i = 0; i < HID_REPORT_TYPES; i++) { - struct hid_report_enum *report_enum = device->report_enum + i; - - for (j = 0; j < HID_MAX_IDS; j++) { - struct hid_report *report = report_enum->report_id_hash[j]; - if (report) - hid_free_report(report); - } - memset(report_enum, 0, sizeof(*report_enum)); - INIT_LIST_HEAD(&report_enum->report_list); - } - - kfree(device->rdesc); - device->rdesc = NULL; - device->rsize = 0; - - kfree(device->collection); - device->collection = NULL; - device->collection_size = 0; - device->maxcollection = 0; - device->maxapplication = 0; - - device->status &= ~HID_STAT_PARSED; -} - -/* - * Free a device structure, all reports, and all fields. - */ - -static void hid_device_release(struct device *dev) -{ - struct hid_device *hid = to_hid_device(dev); - - hid_close_report(hid); - kfree(hid->dev_rdesc); - kfree(hid); -} - -/* - * Fetch a report description item from the data stream. We support long - * items, though they are not used yet. - */ - -static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) -{ - u8 b; - - if ((end - start) <= 0) - return NULL; - - b = *start++; - - item->type = (b >> 2) & 3; - item->tag = (b >> 4) & 15; - - if (item->tag == HID_ITEM_TAG_LONG) { - - item->format = HID_ITEM_FORMAT_LONG; - - if ((end - start) < 2) - return NULL; - - item->size = *start++; - item->tag = *start++; - - if ((end - start) < item->size) - return NULL; - - item->data.longdata = start; - start += item->size; - return start; - } - - item->format = HID_ITEM_FORMAT_SHORT; - item->size = b & 3; - - switch (item->size) { - case 0: - return start; - - case 1: - if ((end - start) < 1) - return NULL; - item->data.u8 = *start++; - return start; - - case 2: - if ((end - start) < 2) - return NULL; - item->data.u16 = get_unaligned_le16(start); - start = (__u8 *)((__le16 *)start + 1); - return start; - - case 3: - item->size++; - if ((end - start) < 4) - return NULL; - item->data.u32 = get_unaligned_le32(start); - start = (__u8 *)((__le32 *)start + 1); - return start; - } - - return NULL; -} - -static void hid_scan_input_usage(struct hid_parser *parser, u32 usage) -{ - struct hid_device *hid = parser->device; - - if (usage == HID_DG_CONTACTID) - hid->group = HID_GROUP_MULTITOUCH; -} - -static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage) -{ - if (usage == 0xff0000c5 && parser->global.report_count == 256 && - parser->global.report_size == 8) - parser->scan_flags |= HID_SCAN_FLAG_MT_WIN_8; -} - -static void hid_scan_collection(struct hid_parser *parser, unsigned type) -{ - struct hid_device *hid = parser->device; - int i; - - if (((parser->global.usage_page << 16) == HID_UP_SENSOR) && - type == HID_COLLECTION_PHYSICAL) - hid->group = HID_GROUP_SENSOR_HUB; - - if (hid->vendor == USB_VENDOR_ID_MICROSOFT && - (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 || - hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 || - hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP || - hid->product == USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP || - hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 || - hid->product == USB_DEVICE_ID_MS_POWER_COVER) && - hid->group == HID_GROUP_MULTITOUCH) - hid->group = HID_GROUP_GENERIC; - - if ((parser->global.usage_page << 16) == HID_UP_GENDESK) - for (i = 0; i < parser->local.usage_index; i++) - if (parser->local.usage[i] == HID_GD_POINTER) - parser->scan_flags |= HID_SCAN_FLAG_GD_POINTER; - - if ((parser->global.usage_page << 16) >= HID_UP_MSVENDOR) - parser->scan_flags |= HID_SCAN_FLAG_VENDOR_SPECIFIC; -} - -static int hid_scan_main(struct hid_parser *parser, struct hid_item *item) -{ - __u32 data; - int i; - - data = item_udata(item); - - switch (item->tag) { - case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION: - hid_scan_collection(parser, data & 0xff); - break; - case HID_MAIN_ITEM_TAG_END_COLLECTION: - break; - case HID_MAIN_ITEM_TAG_INPUT: - /* ignore constant inputs, they will be ignored by hid-input */ - if (data & HID_MAIN_ITEM_CONSTANT) - break; - for (i = 0; i < parser->local.usage_index; i++) - hid_scan_input_usage(parser, parser->local.usage[i]); - break; - case HID_MAIN_ITEM_TAG_OUTPUT: - break; - case HID_MAIN_ITEM_TAG_FEATURE: - for (i = 0; i < parser->local.usage_index; i++) - hid_scan_feature_usage(parser, parser->local.usage[i]); - break; - } - - /* Reset the local parser environment */ - memset(&parser->local, 0, sizeof(parser->local)); - - return 0; -} - -/* - * Scan a report descriptor before the device is added to the bus. - * Sets device groups and other properties that determine what driver - * to load. - */ -static int hid_scan_report(struct hid_device *hid) -{ - struct hid_parser *parser; - struct hid_item item; - __u8 *start = hid->dev_rdesc; - __u8 *end = start + hid->dev_rsize; - static int (*dispatch_type[])(struct hid_parser *parser, - struct hid_item *item) = { - hid_scan_main, - hid_parser_global, - hid_parser_local, - hid_parser_reserved - }; - - parser = vzalloc(sizeof(struct hid_parser)); - if (!parser) - return -ENOMEM; - - parser->device = hid; - hid->group = HID_GROUP_GENERIC; - - /* - * The parsing is simpler than the one in hid_open_report() as we should - * be robust against hid errors. Those errors will be raised by - * hid_open_report() anyway. - */ - while ((start = fetch_item(start, end, &item)) != NULL) - dispatch_type[item.type](parser, &item); - - /* - * Handle special flags set during scanning. - */ - if ((parser->scan_flags & HID_SCAN_FLAG_MT_WIN_8) && - (hid->group == HID_GROUP_MULTITOUCH)) - hid->group = HID_GROUP_MULTITOUCH_WIN_8; - - /* - * Vendor specific handlings - */ - switch (hid->vendor) { - case USB_VENDOR_ID_WACOM: - hid->group = HID_GROUP_WACOM; - break; - case USB_VENDOR_ID_SYNAPTICS: - if (hid->group == HID_GROUP_GENERIC) - if ((parser->scan_flags & HID_SCAN_FLAG_VENDOR_SPECIFIC) - && (parser->scan_flags & HID_SCAN_FLAG_GD_POINTER)) - /* - * hid-rmi should take care of them, - * not hid-generic - */ - hid->group = HID_GROUP_RMI; - break; - } - - vfree(parser); - return 0; -} - -/** - * hid_parse_report - parse device report - * - * @device: hid device - * @start: report start - * @size: report size - * - * Allocate the device report as read by the bus driver. This function should - * only be called from parse() in ll drivers. - */ -int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size) -{ - hid->dev_rdesc = kmemdup(start, size, GFP_KERNEL); - if (!hid->dev_rdesc) - return -ENOMEM; - hid->dev_rsize = size; - return 0; -} -EXPORT_SYMBOL_GPL(hid_parse_report); - -static const char * const hid_report_names[] = { - "HID_INPUT_REPORT", - "HID_OUTPUT_REPORT", - "HID_FEATURE_REPORT", -}; -/** - * hid_validate_values - validate existing device report's value indexes - * - * @device: hid device - * @type: which report type to examine - * @id: which report ID to examine (0 for first) - * @field_index: which report field to examine - * @report_counts: expected number of values - * - * Validate the number of values in a given field of a given report, after - * parsing. - */ -struct hid_report *hid_validate_values(struct hid_device *hid, - unsigned int type, unsigned int id, - unsigned int field_index, - unsigned int report_counts) -{ - struct hid_report *report; - - if (type > HID_FEATURE_REPORT) { - hid_err(hid, "invalid HID report type %u\n", type); - return NULL; - } - - if (id >= HID_MAX_IDS) { - hid_err(hid, "invalid HID report id %u\n", id); - return NULL; - } - - /* - * Explicitly not using hid_get_report() here since it depends on - * ->numbered being checked, which may not always be the case when - * drivers go to access report values. - */ - if (id == 0) { - /* - * Validating on id 0 means we should examine the first - * report in the list. - */ - report = list_entry( - hid->report_enum[type].report_list.next, - struct hid_report, list); - } else { - report = hid->report_enum[type].report_id_hash[id]; - } - if (!report) { - hid_err(hid, "missing %s %u\n", hid_report_names[type], id); - return NULL; - } - if (report->maxfield <= field_index) { - hid_err(hid, "not enough fields in %s %u\n", - hid_report_names[type], id); - return NULL; - } - if (report->field[field_index]->report_count < report_counts) { - hid_err(hid, "not enough values in %s %u field %u\n", - hid_report_names[type], id, field_index); - return NULL; - } - return report; -} -EXPORT_SYMBOL_GPL(hid_validate_values); - -/** - * hid_open_report - open a driver-specific device report - * - * @device: hid device - * - * Parse a report description into a hid_device structure. Reports are - * enumerated, fields are attached to these reports. - * 0 returned on success, otherwise nonzero error value. - * - * This function (or the equivalent hid_parse() macro) should only be - * called from probe() in drivers, before starting the device. - */ -int hid_open_report(struct hid_device *device) -{ - struct hid_parser *parser; - struct hid_item item; - unsigned int size; - __u8 *start; - __u8 *buf; - __u8 *end; - int ret; - static int (*dispatch_type[])(struct hid_parser *parser, - struct hid_item *item) = { - hid_parser_main, - hid_parser_global, - hid_parser_local, - hid_parser_reserved - }; - - if (WARN_ON(device->status & HID_STAT_PARSED)) - return -EBUSY; - - start = device->dev_rdesc; - if (WARN_ON(!start)) - return -ENODEV; - size = device->dev_rsize; - - buf = kmemdup(start, size, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - if (device->driver->report_fixup) - start = device->driver->report_fixup(device, buf, &size); - else - start = buf; - - start = kmemdup(start, size, GFP_KERNEL); - kfree(buf); - if (start == NULL) - return -ENOMEM; - - device->rdesc = start; - device->rsize = size; - - parser = vzalloc(sizeof(struct hid_parser)); - if (!parser) { - ret = -ENOMEM; - goto err; - } - - parser->device = device; - - end = start + size; - - device->collection = kcalloc(HID_DEFAULT_NUM_COLLECTIONS, - sizeof(struct hid_collection), GFP_KERNEL); - if (!device->collection) { - ret = -ENOMEM; - goto err; - } - device->collection_size = HID_DEFAULT_NUM_COLLECTIONS; - - ret = -EINVAL; - while ((start = fetch_item(start, end, &item)) != NULL) { - - if (item.format != HID_ITEM_FORMAT_SHORT) { - hid_err(device, "unexpected long global item\n"); - goto err; - } - - if (dispatch_type[item.type](parser, &item)) { - hid_err(device, "item %u %u %u %u parsing failed\n", - item.format, (unsigned)item.size, - (unsigned)item.type, (unsigned)item.tag); - goto err; - } - - if (start == end) { - if (parser->collection_stack_ptr) { - hid_err(device, "unbalanced collection at end of report description\n"); - goto err; - } - if (parser->local.delimiter_depth) { - hid_err(device, "unbalanced delimiter at end of report description\n"); - goto err; - } - vfree(parser); - device->status |= HID_STAT_PARSED; - return 0; - } - } - - hid_err(device, "item fetching failed at offset %d\n", (int)(end - start)); -err: - vfree(parser); - hid_close_report(device); - return ret; -} -EXPORT_SYMBOL_GPL(hid_open_report); - -/* - * Convert a signed n-bit integer to signed 32-bit integer. Common - * cases are done through the compiler, the screwed things has to be - * done by hand. - */ - -static s32 snto32(__u32 value, unsigned n) -{ - switch (n) { - case 8: return ((__s8)value); - case 16: return ((__s16)value); - case 32: return ((__s32)value); - } - return value & (1 << (n - 1)) ? value | (-1 << n) : value; -} - -s32 hid_snto32(__u32 value, unsigned n) -{ - return snto32(value, n); -} -EXPORT_SYMBOL_GPL(hid_snto32); - -/* - * Convert a signed 32-bit integer to a signed n-bit integer. - */ - -static u32 s32ton(__s32 value, unsigned n) -{ - s32 a = value >> (n - 1); - if (a && a != -1) - return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1; - return value & ((1 << n) - 1); -} - -/* - * Extract/implement a data field from/to a little endian report (bit array). - * - * Code sort-of follows HID spec: - * http://www.usb.org/developers/hidpage/HID1_11.pdf - * - * While the USB HID spec allows unlimited length bit fields in "report - * descriptors", most devices never use more than 16 bits. - * One model of UPS is claimed to report "LINEV" as a 32-bit field. - * Search linux-kernel and linux-usb-devel archives for "hid-core extract". - */ - -static u32 __extract(u8 *report, unsigned offset, int n) -{ - unsigned int idx = offset / 8; - unsigned int bit_nr = 0; - unsigned int bit_shift = offset % 8; - int bits_to_copy = 8 - bit_shift; - u32 value = 0; - u32 mask = n < 32 ? (1U << n) - 1 : ~0U; - - while (n > 0) { - value |= ((u32)report[idx] >> bit_shift) << bit_nr; - n -= bits_to_copy; - bit_nr += bits_to_copy; - bits_to_copy = 8; - bit_shift = 0; - idx++; - } - - return value & mask; -} - -u32 hid_field_extract(const struct hid_device *hid, u8 *report, - unsigned offset, unsigned n) -{ - if (n > 32) { - hid_warn(hid, "hid_field_extract() called with n (%d) > 32! (%s)\n", - n, current->comm); - n = 32; - } - - return __extract(report, offset, n); -} -EXPORT_SYMBOL_GPL(hid_field_extract); - -/* - * "implement" : set bits in a little endian bit stream. - * Same concepts as "extract" (see comments above). - * The data mangled in the bit stream remains in little endian - * order the whole time. It make more sense to talk about - * endianness of register values by considering a register - * a "cached" copy of the little endian bit stream. - */ - -static void __implement(u8 *report, unsigned offset, int n, u32 value) -{ - unsigned int idx = offset / 8; - unsigned int bit_shift = offset % 8; - int bits_to_set = 8 - bit_shift; - - while (n - bits_to_set >= 0) { - report[idx] &= ~(0xff << bit_shift); - report[idx] |= value << bit_shift; - value >>= bits_to_set; - n -= bits_to_set; - bits_to_set = 8; - bit_shift = 0; - idx++; - } - - /* last nibble */ - if (n) { - u8 bit_mask = ((1U << n) - 1); - report[idx] &= ~(bit_mask << bit_shift); - report[idx] |= value << bit_shift; - } -} - -static void implement(const struct hid_device *hid, u8 *report, - unsigned offset, unsigned n, u32 value) -{ - if (unlikely(n > 32)) { - hid_warn(hid, "%s() called with n (%d) > 32! (%s)\n", - __func__, n, current->comm); - n = 32; - } else if (n < 32) { - u32 m = (1U << n) - 1; - - if (unlikely(value > m)) { - hid_warn(hid, - "%s() called with too large value %d (n: %d)! (%s)\n", - __func__, value, n, current->comm); - WARN_ON(1); - value &= m; - } - } - - __implement(report, offset, n, value); -} - -/* - * Search an array for a value. - */ - -static int search(__s32 *array, __s32 value, unsigned n) -{ - while (n--) { - if (*array++ == value) - return 0; - } - return -1; -} - -/** - * hid_match_report - check if driver's raw_event should be called - * - * @hid: hid device - * @report_type: type to match against - * - * compare hid->driver->report_table->report_type to report->type - */ -static int hid_match_report(struct hid_device *hid, struct hid_report *report) -{ - const struct hid_report_id *id = hid->driver->report_table; - - if (!id) /* NULL means all */ - return 1; - - for (; id->report_type != HID_TERMINATOR; id++) - if (id->report_type == HID_ANY_ID || - id->report_type == report->type) - return 1; - return 0; -} - -/** - * hid_match_usage - check if driver's event should be called - * - * @hid: hid device - * @usage: usage to match against - * - * compare hid->driver->usage_table->usage_{type,code} to - * usage->usage_{type,code} - */ -static int hid_match_usage(struct hid_device *hid, struct hid_usage *usage) -{ - const struct hid_usage_id *id = hid->driver->usage_table; - - if (!id) /* NULL means all */ - return 1; - - for (; id->usage_type != HID_ANY_ID - 1; id++) - if ((id->usage_hid == HID_ANY_ID || - id->usage_hid == usage->hid) && - (id->usage_type == HID_ANY_ID || - id->usage_type == usage->type) && - (id->usage_code == HID_ANY_ID || - id->usage_code == usage->code)) - return 1; - return 0; -} - -static void hid_process_event(struct hid_device *hid, struct hid_field *field, - struct hid_usage *usage, __s32 value, int interrupt) -{ - struct hid_driver *hdrv = hid->driver; - int ret; - - if (!list_empty(&hid->debug_list)) - hid_dump_input(hid, usage, value); - - if (hdrv && hdrv->event && hid_match_usage(hid, usage)) { - ret = hdrv->event(hid, field, usage, value); - if (ret != 0) { - if (ret < 0) - hid_err(hid, "%s's event failed with %d\n", - hdrv->name, ret); - return; - } - } - - if (hid->claimed & HID_CLAIMED_INPUT) - hidinput_hid_event(hid, field, usage, value); - if (hid->claimed & HID_CLAIMED_HIDDEV && interrupt && hid->hiddev_hid_event) - hid->hiddev_hid_event(hid, field, usage, value); -} - -/* - * Analyse a received field, and fetch the data from it. The field - * content is stored for next report processing (we do differential - * reporting to the layer). - */ - -static void hid_input_field(struct hid_device *hid, struct hid_field *field, - __u8 *data, int interrupt) -{ - unsigned n; - unsigned count = field->report_count; - unsigned offset = field->report_offset; - unsigned size = field->report_size; - __s32 min = field->logical_minimum; - __s32 max = field->logical_maximum; - __s32 *value; - - value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC); - if (!value) - return; - - for (n = 0; n < count; n++) { - - value[n] = min < 0 ? - snto32(hid_field_extract(hid, data, offset + n * size, - size), size) : - hid_field_extract(hid, data, offset + n * size, size); - - /* Ignore report if ErrorRollOver */ - if (!(field->flags & HID_MAIN_ITEM_VARIABLE) && - value[n] >= min && value[n] <= max && - value[n] - min < field->maxusage && - field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) - goto exit; - } - - for (n = 0; n < count; n++) { - - if (HID_MAIN_ITEM_VARIABLE & field->flags) { - hid_process_event(hid, field, &field->usage[n], value[n], interrupt); - continue; - } - - if (field->value[n] >= min && field->value[n] <= max - && field->value[n] - min < field->maxusage - && field->usage[field->value[n] - min].hid - && search(value, field->value[n], count)) - hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt); - - if (value[n] >= min && value[n] <= max - && value[n] - min < field->maxusage - && field->usage[value[n] - min].hid - && search(field->value, value[n], count)) - hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt); - } - - memcpy(field->value, value, count * sizeof(__s32)); -exit: - kfree(value); -} - -/* - * Output the field into the report. - */ - -static void hid_output_field(const struct hid_device *hid, - struct hid_field *field, __u8 *data) -{ - unsigned count = field->report_count; - unsigned offset = field->report_offset; - unsigned size = field->report_size; - unsigned n; - - for (n = 0; n < count; n++) { - if (field->logical_minimum < 0) /* signed values */ - implement(hid, data, offset + n * size, size, - s32ton(field->value[n], size)); - else /* unsigned values */ - implement(hid, data, offset + n * size, size, - field->value[n]); - } -} - -/* - * Create a report. 'data' has to be allocated using - * hid_alloc_report_buf() so that it has proper size. - */ - -void hid_output_report(struct hid_report *report, __u8 *data) -{ - unsigned n; - - if (report->id > 0) - *data++ = report->id; - - memset(data, 0, ((report->size - 1) >> 3) + 1); - for (n = 0; n < report->maxfield; n++) - hid_output_field(report->device, report->field[n], data); -} -EXPORT_SYMBOL_GPL(hid_output_report); - -/* - * Allocator for buffer that is going to be passed to hid_output_report() - */ -u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags) -{ - /* - * 7 extra bytes are necessary to achieve proper functionality - * of implement() working on 8 byte chunks - */ - - int len = hid_report_len(report) + 7; - - return kmalloc(len, flags); -} -EXPORT_SYMBOL_GPL(hid_alloc_report_buf); - -/* - * Set a field value. The report this field belongs to has to be - * created and transferred to the device, to set this value in the - * device. - */ - -int hid_set_field(struct hid_field *field, unsigned offset, __s32 value) -{ - unsigned size; - - if (!field) - return -1; - - size = field->report_size; - - hid_dump_input(field->report->device, field->usage + offset, value); - - if (offset >= field->report_count) { - hid_err(field->report->device, "offset (%d) exceeds report_count (%d)\n", - offset, field->report_count); - return -1; - } - if (field->logical_minimum < 0) { - if (value != snto32(s32ton(value, size), size)) { - hid_err(field->report->device, "value %d is out of range\n", value); - return -1; - } - } - field->value[offset] = value; - return 0; -} -EXPORT_SYMBOL_GPL(hid_set_field); - -static struct hid_report *hid_get_report(struct hid_report_enum *report_enum, - const u8 *data) -{ - struct hid_report *report; - unsigned int n = 0; /* Normally report number is 0 */ - - /* Device uses numbered reports, data[0] is report number */ - if (report_enum->numbered) - n = *data; - - report = report_enum->report_id_hash[n]; - if (report == NULL) - dbg_hid("undefined report_id %u received\n", n); - - return report; -} - -/* - * Implement a generic .request() callback, using .raw_request() - * DO NOT USE in hid drivers directly, but through hid_hw_request instead. - */ -void __hid_request(struct hid_device *hid, struct hid_report *report, - int reqtype) -{ - char *buf; - int ret; - int len; - - buf = hid_alloc_report_buf(report, GFP_KERNEL); - if (!buf) - return; - - len = hid_report_len(report); - - if (reqtype == HID_REQ_SET_REPORT) - hid_output_report(report, buf); - - ret = hid->ll_driver->raw_request(hid, report->id, buf, len, - report->type, reqtype); - if (ret < 0) { - dbg_hid("unable to complete request: %d\n", ret); - goto out; - } - - if (reqtype == HID_REQ_GET_REPORT) - hid_input_report(hid, report->type, buf, ret, 0); - -out: - kfree(buf); -} -EXPORT_SYMBOL_GPL(__hid_request); - -int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, - int interrupt) -{ - struct hid_report_enum *report_enum = hid->report_enum + type; - struct hid_report *report; - struct hid_driver *hdrv; - unsigned int a; - int rsize, csize = size; - u8 *cdata = data; - int ret = 0; - - report = hid_get_report(report_enum, data); - if (!report) - goto out; - - if (report_enum->numbered) { - cdata++; - csize--; - } - - rsize = ((report->size - 1) >> 3) + 1; - - if (rsize > HID_MAX_BUFFER_SIZE) - rsize = HID_MAX_BUFFER_SIZE; - - if (csize < rsize) { - dbg_hid("report %d is too short, (%d < %d)\n", report->id, - csize, rsize); - memset(cdata + csize, 0, rsize - csize); - } - - if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_report_event) - hid->hiddev_report_event(hid, report); - if (hid->claimed & HID_CLAIMED_HIDRAW) { - ret = hidraw_report_event(hid, data, size); - if (ret) - goto out; - } - - if (hid->claimed != HID_CLAIMED_HIDRAW && report->maxfield) { - for (a = 0; a < report->maxfield; a++) - hid_input_field(hid, report->field[a], cdata, interrupt); - hdrv = hid->driver; - if (hdrv && hdrv->report) - hdrv->report(hid, report); - } - - if (hid->claimed & HID_CLAIMED_INPUT) - hidinput_report_event(hid, report); -out: - return ret; -} -EXPORT_SYMBOL_GPL(hid_report_raw_event); - -/** - * hid_input_report - report data from lower layer (usb, bt...) - * - * @hid: hid device - * @type: HID report type (HID_*_REPORT) - * @data: report contents - * @size: size of data parameter - * @interrupt: distinguish between interrupt and control transfers - * - * This is data entry for lower layers. - */ -int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int interrupt) -{ - struct hid_report_enum *report_enum; - struct hid_driver *hdrv; - struct hid_report *report; - int ret = 0; - - if (!hid) - return -ENODEV; - - if (down_trylock(&hid->driver_input_lock)) - return -EBUSY; - - if (!hid->driver) { - ret = -ENODEV; - goto unlock; - } - report_enum = hid->report_enum + type; - hdrv = hid->driver; - - if (!size) { - dbg_hid("empty report\n"); - ret = -1; - goto unlock; - } - - /* Avoid unnecessary overhead if debugfs is disabled */ - if (!list_empty(&hid->debug_list)) - hid_dump_report(hid, type, data, size); - - report = hid_get_report(report_enum, data); - - if (!report) { - ret = -1; - goto unlock; - } - - if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { - ret = hdrv->raw_event(hid, report, data, size); - if (ret < 0) - goto unlock; - } - - ret = hid_report_raw_event(hid, type, data, size, interrupt); - -unlock: - up(&hid->driver_input_lock); - return ret; -} -EXPORT_SYMBOL_GPL(hid_input_report); - -static bool hid_match_one_id(struct hid_device *hdev, - const struct hid_device_id *id) -{ - return (id->bus == HID_BUS_ANY || id->bus == hdev->bus) && - (id->group == HID_GROUP_ANY || id->group == hdev->group) && - (id->vendor == HID_ANY_ID || id->vendor == hdev->vendor) && - (id->product == HID_ANY_ID || id->product == hdev->product); -} - -const struct hid_device_id *hid_match_id(struct hid_device *hdev, - const struct hid_device_id *id) -{ - for (; id->bus; id++) - if (hid_match_one_id(hdev, id)) - return id; - - return NULL; -} - -static const struct hid_device_id hid_hiddev_list[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1) }, - { } -}; - -static bool hid_hiddev(struct hid_device *hdev) -{ - return !!hid_match_id(hdev, hid_hiddev_list); -} - - -static ssize_t -read_report_descriptor(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, - char *buf, loff_t off, size_t count) -{ - struct device *dev = kobj_to_dev(kobj); - struct hid_device *hdev = to_hid_device(dev); - - if (off >= hdev->rsize) - return 0; - - if (off + count > hdev->rsize) - count = hdev->rsize - off; - - memcpy(buf, hdev->rdesc + off, count); - - return count; -} - -static ssize_t -show_country(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct hid_device *hdev = to_hid_device(dev); - - return sprintf(buf, "%02x\n", hdev->country & 0xff); -} - -static struct bin_attribute dev_bin_attr_report_desc = { - .attr = { .name = "report_descriptor", .mode = 0444 }, - .read = read_report_descriptor, - .size = HID_MAX_DESCRIPTOR_SIZE, -}; - -static struct device_attribute dev_attr_country = { - .attr = { .name = "country", .mode = 0444 }, - .show = show_country, -}; - -int hid_connect(struct hid_device *hdev, unsigned int connect_mask) -{ - static const char *types[] = { "Device", "Pointer", "Mouse", "Device", - "Joystick", "Gamepad", "Keyboard", "Keypad", - "Multi-Axis Controller" - }; - const char *type, *bus; - char buf[64] = ""; - unsigned int i; - int len; - int ret; - - if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE) - connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV); - if (hdev->quirks & HID_QUIRK_HIDINPUT_FORCE) - connect_mask |= HID_CONNECT_HIDINPUT_FORCE; - if (hdev->bus != BUS_USB) - connect_mask &= ~HID_CONNECT_HIDDEV; - if (hid_hiddev(hdev)) - connect_mask |= HID_CONNECT_HIDDEV_FORCE; - - if ((connect_mask & HID_CONNECT_HIDINPUT) && !hidinput_connect(hdev, - connect_mask & HID_CONNECT_HIDINPUT_FORCE)) - hdev->claimed |= HID_CLAIMED_INPUT; - - if ((connect_mask & HID_CONNECT_HIDDEV) && hdev->hiddev_connect && - !hdev->hiddev_connect(hdev, - connect_mask & HID_CONNECT_HIDDEV_FORCE)) - hdev->claimed |= HID_CLAIMED_HIDDEV; - if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev)) - hdev->claimed |= HID_CLAIMED_HIDRAW; - - if (connect_mask & HID_CONNECT_DRIVER) - hdev->claimed |= HID_CLAIMED_DRIVER; - - /* Drivers with the ->raw_event callback set are not required to connect - * to any other listener. */ - if (!hdev->claimed && !hdev->driver->raw_event) { - hid_err(hdev, "device has no listeners, quitting\n"); - return -ENODEV; - } - - if ((hdev->claimed & HID_CLAIMED_INPUT) && - (connect_mask & HID_CONNECT_FF) && hdev->ff_init) - hdev->ff_init(hdev); - - len = 0; - if (hdev->claimed & HID_CLAIMED_INPUT) - len += sprintf(buf + len, "input"); - if (hdev->claimed & HID_CLAIMED_HIDDEV) - len += sprintf(buf + len, "%shiddev%d", len ? "," : "", - hdev->minor); - if (hdev->claimed & HID_CLAIMED_HIDRAW) - len += sprintf(buf + len, "%shidraw%d", len ? "," : "", - ((struct hidraw *)hdev->hidraw)->minor); - - type = "Device"; - for (i = 0; i < hdev->maxcollection; i++) { - struct hid_collection *col = &hdev->collection[i]; - if (col->type == HID_COLLECTION_APPLICATION && - (col->usage & HID_USAGE_PAGE) == HID_UP_GENDESK && - (col->usage & 0xffff) < ARRAY_SIZE(types)) { - type = types[col->usage & 0xffff]; - break; - } - } - - switch (hdev->bus) { - case BUS_USB: - bus = "USB"; - break; - case BUS_BLUETOOTH: - bus = "BLUETOOTH"; - break; - case BUS_I2C: - bus = "I2C"; - break; - default: - bus = ""; - } - - ret = device_create_file(&hdev->dev, &dev_attr_country); - if (ret) - hid_warn(hdev, - "can't create sysfs country code attribute err: %d\n", ret); - - hid_info(hdev, "%s: %s HID v%x.%02x %s [%s] on %s\n", - buf, bus, hdev->version >> 8, hdev->version & 0xff, - type, hdev->name, hdev->phys); - - return 0; -} -EXPORT_SYMBOL_GPL(hid_connect); - -void hid_disconnect(struct hid_device *hdev) -{ - device_remove_file(&hdev->dev, &dev_attr_country); - if (hdev->claimed & HID_CLAIMED_INPUT) - hidinput_disconnect(hdev); - if (hdev->claimed & HID_CLAIMED_HIDDEV) - hdev->hiddev_disconnect(hdev); - if (hdev->claimed & HID_CLAIMED_HIDRAW) - hidraw_disconnect(hdev); - hdev->claimed = 0; -} -EXPORT_SYMBOL_GPL(hid_disconnect); - -/* - * A list of devices for which there is a specialized driver on HID bus. - * - * Please note that for multitouch devices (driven by hid-multitouch driver), - * there is a proper autodetection and autoloading in place (based on presence - * of HID_DG_CONTACTID), so those devices don't need to be added to this list, - * as we are doing the right thing in hid_scan_usage(). - * - * Autodetection for (USB) HID sensor hubs exists too. If a collection of type - * physical is found inside a usage page of type sensor, hid-sensor-hub will be - * used as a driver. See hid_scan_report(). - */ -static const struct hid_device_id hid_have_special_driver[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, - { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, - { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0xf705) }, - { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_MINI_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, - { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) }, - { HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) }, - { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) }, - { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185PC, 0x5506) }, - { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2PC, 0x1850) }, - { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2BFM, 0x5500) }, - { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_ACER_SWITCH12) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_CORSAIR_K90) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_CP2112) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_4) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_DELCOM, USB_DEVICE_ID_DELCOM_VISUAL_IND) }, - { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, - { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) }, - { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_WN) }, - { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_FA) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0009) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ELO, 0x0030) }, - { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) }, - { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GEMBIRD, USB_DEVICE_ID_GEMBIRD_JPD_DUALFORCE2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) }, - { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A) }, - { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067) }, - { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A070) }, - { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072) }, - { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081) }, - { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A0C2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) }, - { HID_USB_DEVICE(USB_VENDOR_ID_JESS2, USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ION, USB_DEVICE_ID_ICADE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) }, - { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_MANTICORE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_GENIUS_GX_IMPERATOR) }, - { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, - { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_I405X) }, - { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X) }, - { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) }, - { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_PENSKETCH_M912) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) }, -#if IS_ENABLED(CONFIG_HID_LENOVO) - { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CUSBKBD) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPPRODOCK) }, -#endif - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_T651) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_MINI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_ELITE_KBD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_EXTREME_3D) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DUAL_ACTION) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G29_WHEEL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFGT_WHEEL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G27_WHEEL) }, -#if IS_ENABLED(CONFIG_HID_LOGITECH_DJ) - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2) }, -#endif - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_LUXAFOR) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_KEYBOARD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE7K) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_600) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_3) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_4) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_5) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_6) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_7) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_8) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_9) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_10) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_11) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_12) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_13) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_14) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_15) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_16) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_17) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) }, - { HID_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, USB_DEVICE_ID_PENMOUNT_6000) }, - { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, HID_ANY_ID) }, - { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_KEYBOARD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_RISO_KAGAKU, USB_DEVICE_ID_RI_KA_WEBMAIL) }, -#if IS_ENABLED(CONFIG_HID_ROCCAT) - { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKUFX) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE_OPTICAL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEXTD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_LUA) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_RYOS_MK) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_RYOS_MK_GLOW) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_RYOS_MK_PRO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) }, -#endif -#if IS_ENABLED(CONFIG_HID_SAITEK) - { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7_OLD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT9) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT5) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9) }, -#endif - { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SKYCABLE, USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_PS3_BDREMOTE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_BUZZ_CONTROLLER) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SINO_LITE, USB_DEVICE_ID_SINO_LITE_CONTROLLER) }, - { HID_USB_DEVICE(USB_VENDOR_ID_STEELSERIES, USB_DEVICE_ID_STEELSERIES_SRWS1) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_THINGM, USB_DEVICE_ID_BLINK1) }, - { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) }, - { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) }, - { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) }, - { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb324) }, - { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) }, - { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb653) }, - { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) }, - { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_BT) }, - { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_TIVO, USB_DEVICE_ID_TIVO_SLIDE_PRO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) }, - { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_YIYNOVA_TABLET) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UGEE_TABLET_81) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UGEE_TABLET_45) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3) }, - { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_GP0610) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SUPER_JOY_BOX_3) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_DUAL_BOX_PRO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_Q_PAD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_PID_0038) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) }, - { HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_XIN_MO, USB_DEVICE_ID_XIN_MO_DUAL_ARCADE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) }, - - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM6533) }, - { } -}; - -struct hid_dynid { - struct list_head list; - struct hid_device_id id; -}; - -/** - * store_new_id - add a new HID device ID to this driver and re-probe devices - * @driver: target device driver - * @buf: buffer for scanning device ID data - * @count: input size - * - * Adds a new dynamic hid device ID to this driver, - * and causes the driver to probe for all devices again. - */ -static ssize_t store_new_id(struct device_driver *drv, const char *buf, - size_t count) -{ - struct hid_driver *hdrv = to_hid_driver(drv); - struct hid_dynid *dynid; - __u32 bus, vendor, product; - unsigned long driver_data = 0; - int ret; - - ret = sscanf(buf, "%x %x %x %lx", - &bus, &vendor, &product, &driver_data); - if (ret < 3) - return -EINVAL; - - dynid = kzalloc(sizeof(*dynid), GFP_KERNEL); - if (!dynid) - return -ENOMEM; - - dynid->id.bus = bus; - dynid->id.group = HID_GROUP_ANY; - dynid->id.vendor = vendor; - dynid->id.product = product; - dynid->id.driver_data = driver_data; - - spin_lock(&hdrv->dyn_lock); - list_add_tail(&dynid->list, &hdrv->dyn_list); - spin_unlock(&hdrv->dyn_lock); - - ret = driver_attach(&hdrv->driver); - - return ret ? : count; -} -static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id); - -static void hid_free_dynids(struct hid_driver *hdrv) -{ - struct hid_dynid *dynid, *n; - - spin_lock(&hdrv->dyn_lock); - list_for_each_entry_safe(dynid, n, &hdrv->dyn_list, list) { - list_del(&dynid->list); - kfree(dynid); - } - spin_unlock(&hdrv->dyn_lock); -} - -static const struct hid_device_id *hid_match_device(struct hid_device *hdev, - struct hid_driver *hdrv) -{ - struct hid_dynid *dynid; - - spin_lock(&hdrv->dyn_lock); - list_for_each_entry(dynid, &hdrv->dyn_list, list) { - if (hid_match_one_id(hdev, &dynid->id)) { - spin_unlock(&hdrv->dyn_lock); - return &dynid->id; - } - } - spin_unlock(&hdrv->dyn_lock); - - return hid_match_id(hdev, hdrv->id_table); -} - -static int hid_bus_match(struct device *dev, struct device_driver *drv) -{ - struct hid_driver *hdrv = to_hid_driver(drv); - struct hid_device *hdev = to_hid_device(dev); - - return hid_match_device(hdev, hdrv) != NULL; -} - -static int hid_device_probe(struct device *dev) -{ - struct hid_driver *hdrv = to_hid_driver(dev->driver); - struct hid_device *hdev = to_hid_device(dev); - const struct hid_device_id *id; - int ret = 0; - - if (down_interruptible(&hdev->driver_lock)) - return -EINTR; - if (down_interruptible(&hdev->driver_input_lock)) { - ret = -EINTR; - goto unlock_driver_lock; - } - hdev->io_started = false; - - if (!hdev->driver) { - id = hid_match_device(hdev, hdrv); - if (id == NULL) { - ret = -ENODEV; - goto unlock; - } - - hdev->driver = hdrv; - if (hdrv->probe) { - ret = hdrv->probe(hdev, id); - } else { /* default probe */ - ret = hid_open_report(hdev); - if (!ret) - ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); - } - if (ret) { - hid_close_report(hdev); - hdev->driver = NULL; - } - } -unlock: - if (!hdev->io_started) - up(&hdev->driver_input_lock); -unlock_driver_lock: - up(&hdev->driver_lock); - return ret; -} - -static int hid_device_remove(struct device *dev) -{ - struct hid_device *hdev = to_hid_device(dev); - struct hid_driver *hdrv; - int ret = 0; - - if (down_interruptible(&hdev->driver_lock)) - return -EINTR; - if (down_interruptible(&hdev->driver_input_lock)) { - ret = -EINTR; - goto unlock_driver_lock; - } - hdev->io_started = false; - - hdrv = hdev->driver; - if (hdrv) { - if (hdrv->remove) - hdrv->remove(hdev); - else /* default remove */ - hid_hw_stop(hdev); - hid_close_report(hdev); - hdev->driver = NULL; - } - - if (!hdev->io_started) - up(&hdev->driver_input_lock); -unlock_driver_lock: - up(&hdev->driver_lock); - return ret; -} - -static ssize_t modalias_show(struct device *dev, struct device_attribute *a, - char *buf) -{ - struct hid_device *hdev = container_of(dev, struct hid_device, dev); - - return scnprintf(buf, PAGE_SIZE, "hid:b%04Xg%04Xv%08Xp%08X\n", - hdev->bus, hdev->group, hdev->vendor, hdev->product); -} -static DEVICE_ATTR_RO(modalias); - -static struct attribute *hid_dev_attrs[] = { - &dev_attr_modalias.attr, - NULL, -}; -static struct bin_attribute *hid_dev_bin_attrs[] = { - &dev_bin_attr_report_desc, - NULL -}; -static const struct attribute_group hid_dev_group = { - .attrs = hid_dev_attrs, - .bin_attrs = hid_dev_bin_attrs, -}; -__ATTRIBUTE_GROUPS(hid_dev); - -static int hid_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct hid_device *hdev = to_hid_device(dev); - - if (add_uevent_var(env, "HID_ID=%04X:%08X:%08X", - hdev->bus, hdev->vendor, hdev->product)) - return -ENOMEM; - - if (add_uevent_var(env, "HID_NAME=%s", hdev->name)) - return -ENOMEM; - - if (add_uevent_var(env, "HID_PHYS=%s", hdev->phys)) - return -ENOMEM; - - if (add_uevent_var(env, "HID_UNIQ=%s", hdev->uniq)) - return -ENOMEM; - - if (add_uevent_var(env, "MODALIAS=hid:b%04Xg%04Xv%08Xp%08X", - hdev->bus, hdev->group, hdev->vendor, hdev->product)) - return -ENOMEM; - - return 0; -} - -static struct bus_type hid_bus_type = { - .name = "hid", - .dev_groups = hid_dev_groups, - .match = hid_bus_match, - .probe = hid_device_probe, - .remove = hid_device_remove, - .uevent = hid_uevent, -}; - -/* a list of devices that shouldn't be handled by HID core at all */ -static const struct hid_device_id hid_ignore_list[] = { - { HID_USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ADS_TECH, USB_DEVICE_ID_ADS_TECH_RADIO_SI470X) }, - { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_01) }, - { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_10) }, - { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_20) }, - { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_21) }, - { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_22) }, - { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_23) }, - { HID_USB_DEVICE(USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_24) }, - { HID_USB_DEVICE(USB_VENDOR_ID_AIRCABLE, USB_DEVICE_ID_AIRCABLE1) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ALCOR, USB_DEVICE_ID_ALCOR_USBRS232) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM)}, - { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_LCM2)}, - { HID_USB_DEVICE(USB_VENDOR_ID_AVERMEDIA, USB_DEVICE_ID_AVER_FM_MR800) }, - { HID_USB_DEVICE(USB_VENDOR_ID_AXENTIA, USB_DEVICE_ID_AXENTIA_FM_RADIO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI4713) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM) }, - { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_DEALEXTREAME, USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701) }, - { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) }, - { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0400) }, - { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, 0x0401) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0004) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_SUPER_Q2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_GOGOPEN) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_PENPOWER) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GRETAGMACBETH, USB_DEVICE_ID_GRETAGMACBETH_HUEY) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_RADIOSHARK) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_90) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_100) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_101) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_103) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_104) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_105) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_106) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_107) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_108) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_200) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_201) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_202) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_203) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_204) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_205) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_206) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_207) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_300) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_301) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_302) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_303) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_304) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_305) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_306) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_307) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_308) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_309) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_400) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_401) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_402) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_403) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_404) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_405) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_500) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_501) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_502) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_503) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_504) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1000) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1001) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1002) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1003) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1004) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1005) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1006) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GTCO, USB_DEVICE_ID_GTCO_1007) }, - { HID_USB_DEVICE(USB_VENDOR_ID_IMATION, USB_DEVICE_ID_DISC_STAKKA) }, - { HID_USB_DEVICE(USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_SPEAK_410) }, - { HID_USB_DEVICE(USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_SPEAK_510) }, - { HID_USB_DEVICE(USB_VENDOR_ID_JABRA, USB_DEVICE_ID_JABRA_GN9350E) }, - { HID_USB_DEVICE(USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_KWORLD, USB_DEVICE_ID_KWORLD_RADIO_FM700) }, - { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_GPEN_560) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_KYE, 0x0058) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYVOLTAGE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYCURRENT) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTIME) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MICROCASSYPH) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_JWM) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_DMMP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIC) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_UMIB) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_XRAY2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_VIDEOCOM) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOTOR) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_COM3LAB) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_TELEPORT) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_NETWORKANALYSER) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POWERCONTROL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MACHINETEST) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOSTANALYSER) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOSTANALYSER2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_ABSESP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_AUTODATABUS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MCT) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HYBRID) }, - { HID_USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HEATCONTROL) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_BEATPAD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICK16F1454) }, - { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICK16F1454_V2) }, - { HID_USB_DEVICE(USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 30) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 108) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 118) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 300) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 400) }, - { HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 500) }, - { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0001) }, - { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0002) }, - { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0003) }, - { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) }, - { HID_USB_DEVICE(USB_VENDOR_ID_PHILIPS, USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) }, -#if IS_ENABLED(CONFIG_MOUSE_SYNAPTICS_USB) - { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_INT_TP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_CPAD) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_STICK) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_WP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_COMP_TP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_WTP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DPAD) }, -#endif - { HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) }, - { } -}; - -/** - * hid_mouse_ignore_list - mouse devices which should not be handled by the hid layer - * - * There are composite devices for which we want to ignore only a certain - * interface. This is a list of devices for which only the mouse interface will - * be ignored. This allows a dedicated driver to take care of the interface. - */ -static const struct hid_device_id hid_mouse_ignore_list[] = { - /* appletouch driver */ - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING8_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) }, - { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) }, - { } -}; - -bool hid_ignore(struct hid_device *hdev) -{ - if (hdev->quirks & HID_QUIRK_NO_IGNORE) - return false; - if (hdev->quirks & HID_QUIRK_IGNORE) - return true; - - switch (hdev->vendor) { - case USB_VENDOR_ID_CODEMERCS: - /* ignore all Code Mercenaries IOWarrior devices */ - if (hdev->product >= USB_DEVICE_ID_CODEMERCS_IOW_FIRST && - hdev->product <= USB_DEVICE_ID_CODEMERCS_IOW_LAST) - return true; - break; - case USB_VENDOR_ID_LOGITECH: - if (hdev->product >= USB_DEVICE_ID_LOGITECH_HARMONY_FIRST && - hdev->product <= USB_DEVICE_ID_LOGITECH_HARMONY_LAST) - return true; - /* - * The Keene FM transmitter USB device has the same USB ID as - * the Logitech AudioHub Speaker, but it should ignore the hid. - * Check if the name is that of the Keene device. - * For reference: the name of the AudioHub is - * "HOLTEK AudioHub Speaker". - */ - if (hdev->product == USB_DEVICE_ID_LOGITECH_AUDIOHUB && - !strcmp(hdev->name, "HOLTEK B-LINK USB Audio ")) - return true; - break; - case USB_VENDOR_ID_SOUNDGRAPH: - if (hdev->product >= USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST && - hdev->product <= USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST) - return true; - break; - case USB_VENDOR_ID_HANWANG: - if (hdev->product >= USB_DEVICE_ID_HANWANG_TABLET_FIRST && - hdev->product <= USB_DEVICE_ID_HANWANG_TABLET_LAST) - return true; - break; - case USB_VENDOR_ID_JESS: - if (hdev->product == USB_DEVICE_ID_JESS_YUREX && - hdev->type == HID_TYPE_USBNONE) - return true; - break; - case USB_VENDOR_ID_VELLEMAN: - /* These are not HID devices. They are handled by comedi. */ - if ((hdev->product >= USB_DEVICE_ID_VELLEMAN_K8055_FIRST && - hdev->product <= USB_DEVICE_ID_VELLEMAN_K8055_LAST) || - (hdev->product >= USB_DEVICE_ID_VELLEMAN_K8061_FIRST && - hdev->product <= USB_DEVICE_ID_VELLEMAN_K8061_LAST)) - return true; - break; - case USB_VENDOR_ID_ATMEL_V_USB: - /* Masterkit MA901 usb radio based on Atmel tiny85 chip and - * it has the same USB ID as many Atmel V-USB devices. This - * usb radio is handled by radio-ma901.c driver so we want - * ignore the hid. Check the name, bus, product and ignore - * if we have MA901 usb radio. - */ - if (hdev->product == USB_DEVICE_ID_ATMEL_V_USB && - hdev->bus == BUS_USB && - strncmp(hdev->name, "www.masterkit.ru MA901", 22) == 0) - return true; - break; - } - - if (hdev->type == HID_TYPE_USBMOUSE && - hid_match_id(hdev, hid_mouse_ignore_list)) - return true; - - return !!hid_match_id(hdev, hid_ignore_list); -} -EXPORT_SYMBOL_GPL(hid_ignore); - -int hid_add_device(struct hid_device *hdev) -{ - static atomic_t id = ATOMIC_INIT(0); - int ret; - - if (WARN_ON(hdev->status & HID_STAT_ADDED)) - return -EBUSY; - - /* we need to kill them here, otherwise they will stay allocated to - * wait for coming driver */ - if (hid_ignore(hdev)) - return -ENODEV; - - /* - * Check for the mandatory transport channel. - */ - if (!hdev->ll_driver->raw_request) { - hid_err(hdev, "transport driver missing .raw_request()\n"); - return -EINVAL; - } - - /* - * Read the device report descriptor once and use as template - * for the driver-specific modifications. - */ - ret = hdev->ll_driver->parse(hdev); - if (ret) - return ret; - if (!hdev->dev_rdesc) - return -ENODEV; - - /* - * Scan generic devices for group information - */ - if (hid_ignore_special_drivers) { - hdev->group = HID_GROUP_GENERIC; - } else if (!hdev->group && - !hid_match_id(hdev, hid_have_special_driver)) { - ret = hid_scan_report(hdev); - if (ret) - hid_warn(hdev, "bad device descriptor (%d)\n", ret); - } - - /* XXX hack, any other cleaner solution after the driver core - * is converted to allow more than 20 bytes as the device name? */ - dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus, - hdev->vendor, hdev->product, atomic_inc_return(&id)); - - hid_debug_register(hdev, dev_name(&hdev->dev)); - ret = device_add(&hdev->dev); - if (!ret) - hdev->status |= HID_STAT_ADDED; - else - hid_debug_unregister(hdev); - - return ret; -} -EXPORT_SYMBOL_GPL(hid_add_device); - -/** - * hid_allocate_device - allocate new hid device descriptor - * - * Allocate and initialize hid device, so that hid_destroy_device might be - * used to free it. - * - * New hid_device pointer is returned on success, otherwise ERR_PTR encoded - * error value. - */ -struct hid_device *hid_allocate_device(void) -{ - struct hid_device *hdev; - int ret = -ENOMEM; - - hdev = kzalloc(sizeof(*hdev), GFP_KERNEL); - if (hdev == NULL) - return ERR_PTR(ret); - - device_initialize(&hdev->dev); - hdev->dev.release = hid_device_release; - hdev->dev.bus = &hid_bus_type; - device_enable_async_suspend(&hdev->dev); - - hid_close_report(hdev); - - init_waitqueue_head(&hdev->debug_wait); - INIT_LIST_HEAD(&hdev->debug_list); - spin_lock_init(&hdev->debug_list_lock); - sema_init(&hdev->driver_lock, 1); - sema_init(&hdev->driver_input_lock, 1); - - return hdev; -} -EXPORT_SYMBOL_GPL(hid_allocate_device); - -static void hid_remove_device(struct hid_device *hdev) -{ - if (hdev->status & HID_STAT_ADDED) { - device_del(&hdev->dev); - hid_debug_unregister(hdev); - hdev->status &= ~HID_STAT_ADDED; - } - kfree(hdev->dev_rdesc); - hdev->dev_rdesc = NULL; - hdev->dev_rsize = 0; -} - -/** - * hid_destroy_device - free previously allocated device - * - * @hdev: hid device - * - * If you allocate hid_device through hid_allocate_device, you should ever - * free by this function. - */ -void hid_destroy_device(struct hid_device *hdev) -{ - hid_remove_device(hdev); - put_device(&hdev->dev); -} -EXPORT_SYMBOL_GPL(hid_destroy_device); - -int __hid_register_driver(struct hid_driver *hdrv, struct module *owner, - const char *mod_name) -{ - int ret; - - hdrv->driver.name = hdrv->name; - hdrv->driver.bus = &hid_bus_type; - hdrv->driver.owner = owner; - hdrv->driver.mod_name = mod_name; - - INIT_LIST_HEAD(&hdrv->dyn_list); - spin_lock_init(&hdrv->dyn_lock); - - ret = driver_register(&hdrv->driver); - if (ret) - return ret; - - ret = driver_create_file(&hdrv->driver, &driver_attr_new_id); - if (ret) - driver_unregister(&hdrv->driver); - - return ret; -} -EXPORT_SYMBOL_GPL(__hid_register_driver); - -void hid_unregister_driver(struct hid_driver *hdrv) -{ - driver_remove_file(&hdrv->driver, &driver_attr_new_id); - driver_unregister(&hdrv->driver); - hid_free_dynids(hdrv); -} -EXPORT_SYMBOL_GPL(hid_unregister_driver); - -int hid_check_keys_pressed(struct hid_device *hid) -{ - struct hid_input *hidinput; - int i; - - if (!(hid->claimed & HID_CLAIMED_INPUT)) - return 0; - - list_for_each_entry(hidinput, &hid->inputs, list) { - for (i = 0; i < BITS_TO_LONGS(KEY_MAX); i++) - if (hidinput->input->key[i]) - return 1; - } - - return 0; -} - -EXPORT_SYMBOL_GPL(hid_check_keys_pressed); - -static int __init hid_init(void) -{ - int ret; - - if (hid_debug) - pr_warn("hid_debug is now used solely for parser and driver debugging.\n" - "debugfs is now used for inspecting the device (report descriptor, reports)\n"); - - ret = bus_register(&hid_bus_type); - if (ret) { - pr_err("can't register hid bus\n"); - goto err; - } - - ret = hidraw_init(); - if (ret) - goto err_bus; - - hid_debug_init(); - - return 0; -err_bus: - bus_unregister(&hid_bus_type); -err: - return ret; -} - -static void __exit hid_exit(void) -{ - hid_debug_exit(); - hidraw_exit(); - bus_unregister(&hid_bus_type); -} - -module_init(hid_init); -module_exit(hid_exit); - -MODULE_AUTHOR("Andreas Gal"); -MODULE_AUTHOR("Vojtech Pavlik"); -MODULE_AUTHOR("Jiri Kosina"); -MODULE_LICENSE(DRIVER_LICENSE); - diff --git a/src/linux/drivers/hid/hid-generic.c b/src/linux/drivers/hid/hid-generic.c deleted file mode 100644 index e288a4a..0000000 --- a/src/linux/drivers/hid/hid-generic.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * HID support for Linux - * - * Copyright (c) 1999 Andreas Gal - * Copyright (c) 2000-2005 Vojtech Pavlik - * Copyright (c) 2005 Michael Haboustak for Concept2, Inc - * Copyright (c) 2007-2008 Oliver Neukum - * Copyright (c) 2006-2012 Jiri Kosina - * Copyright (c) 2012 Henrik Rydberg - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - */ - -#include -#include -#include -#include -#include - -#include - -static const struct hid_device_id hid_table[] = { - { HID_DEVICE(HID_BUS_ANY, HID_GROUP_GENERIC, HID_ANY_ID, HID_ANY_ID) }, - { } -}; -MODULE_DEVICE_TABLE(hid, hid_table); - -static struct hid_driver hid_generic = { - .name = "hid-generic", - .id_table = hid_table, -}; -module_hid_driver(hid_generic); - -MODULE_AUTHOR("Henrik Rydberg"); -MODULE_DESCRIPTION("HID generic driver"); -MODULE_LICENSE("GPL"); diff --git a/src/linux/drivers/hid/hid-ids.h b/src/linux/drivers/hid/hid-ids.h deleted file mode 100644 index 575aa65..0000000 --- a/src/linux/drivers/hid/hid-ids.h +++ /dev/null @@ -1,1102 +0,0 @@ -/* - * USB HID quirks support for Linux - * - * Copyright (c) 1999 Andreas Gal - * Copyright (c) 2000-2005 Vojtech Pavlik - * Copyright (c) 2005 Michael Haboustak for Concept2, Inc - * Copyright (c) 2006-2007 Jiri Kosina - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - */ - -#ifndef HID_IDS_H_FILE -#define HID_IDS_H_FILE - -#define USB_VENDOR_ID_3M 0x0596 -#define USB_DEVICE_ID_3M1968 0x0500 -#define USB_DEVICE_ID_3M2256 0x0502 -#define USB_DEVICE_ID_3M3266 0x0506 - -#define USB_VENDOR_ID_A4TECH 0x09da -#define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006 -#define USB_DEVICE_ID_A4TECH_X5_005D 0x000a -#define USB_DEVICE_ID_A4TECH_RP_649 0x001a - -#define USB_VENDOR_ID_AASHIMA 0x06d6 -#define USB_DEVICE_ID_AASHIMA_GAMEPAD 0x0025 -#define USB_DEVICE_ID_AASHIMA_PREDATOR 0x0026 - -#define USB_VENDOR_ID_ACECAD 0x0460 -#define USB_DEVICE_ID_ACECAD_FLAIR 0x0004 -#define USB_DEVICE_ID_ACECAD_302 0x0008 - -#define USB_VENDOR_ID_ACRUX 0x1a34 - -#define USB_VENDOR_ID_ACTIONSTAR 0x2101 -#define USB_DEVICE_ID_ACTIONSTAR_1011 0x1011 - -#define USB_VENDOR_ID_ADS_TECH 0x06e1 -#define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155 - -#define USB_VENDOR_ID_AFATECH 0x15a4 -#define USB_DEVICE_ID_AFATECH_AF9016 0x9016 - -#define USB_VENDOR_ID_AIPTEK 0x08ca -#define USB_DEVICE_ID_AIPTEK_01 0x0001 -#define USB_DEVICE_ID_AIPTEK_10 0x0010 -#define USB_DEVICE_ID_AIPTEK_20 0x0020 -#define USB_DEVICE_ID_AIPTEK_21 0x0021 -#define USB_DEVICE_ID_AIPTEK_22 0x0022 -#define USB_DEVICE_ID_AIPTEK_23 0x0023 -#define USB_DEVICE_ID_AIPTEK_24 0x0024 - -#define USB_VENDOR_ID_AIRCABLE 0x16CA -#define USB_DEVICE_ID_AIRCABLE1 0x1502 - -#define USB_VENDOR_ID_AIREN 0x1a2c -#define USB_DEVICE_ID_AIREN_SLIMPLUS 0x0002 - -#define USB_VENDOR_ID_AKAI 0x2011 -#define USB_DEVICE_ID_AKAI_MPKMINI2 0x0715 - -#define USB_VENDOR_ID_AKAI_09E8 0x09E8 -#define USB_DEVICE_ID_AKAI_09E8_MIDIMIX 0x0031 - -#define USB_VENDOR_ID_ALCOR 0x058f -#define USB_DEVICE_ID_ALCOR_USBRS232 0x9720 - -#define USB_VENDOR_ID_ALPS 0x0433 -#define USB_DEVICE_ID_IBM_GAMEPAD 0x1101 - -#define USB_VENDOR_ID_ALPS_JP 0x044E -#define HID_DEVICE_ID_ALPS_U1_DUAL 0x120B - -#define USB_VENDOR_ID_ANTON 0x1130 -#define USB_DEVICE_ID_ANTON_TOUCH_PAD 0x3101 - -#define USB_VENDOR_ID_APPLE 0x05ac -#define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304 -#define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d -#define USB_DEVICE_ID_APPLE_MAGICTRACKPAD 0x030e -#define USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI 0x020e -#define USB_DEVICE_ID_APPLE_FOUNTAIN_ISO 0x020f -#define USB_DEVICE_ID_APPLE_GEYSER_ANSI 0x0214 -#define USB_DEVICE_ID_APPLE_GEYSER_ISO 0x0215 -#define USB_DEVICE_ID_APPLE_GEYSER_JIS 0x0216 -#define USB_DEVICE_ID_APPLE_GEYSER3_ANSI 0x0217 -#define USB_DEVICE_ID_APPLE_GEYSER3_ISO 0x0218 -#define USB_DEVICE_ID_APPLE_GEYSER3_JIS 0x0219 -#define USB_DEVICE_ID_APPLE_GEYSER4_ANSI 0x021a -#define USB_DEVICE_ID_APPLE_GEYSER4_ISO 0x021b -#define USB_DEVICE_ID_APPLE_GEYSER4_JIS 0x021c -#define USB_DEVICE_ID_APPLE_ALU_MINI_ANSI 0x021d -#define USB_DEVICE_ID_APPLE_ALU_MINI_ISO 0x021e -#define USB_DEVICE_ID_APPLE_ALU_MINI_JIS 0x021f -#define USB_DEVICE_ID_APPLE_ALU_ANSI 0x0220 -#define USB_DEVICE_ID_APPLE_ALU_ISO 0x0221 -#define USB_DEVICE_ID_APPLE_ALU_JIS 0x0222 -#define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI 0x0223 -#define USB_DEVICE_ID_APPLE_WELLSPRING_ISO 0x0224 -#define USB_DEVICE_ID_APPLE_WELLSPRING_JIS 0x0225 -#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI 0x0229 -#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO 0x022a -#define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS 0x022b -#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI 0x022c -#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO 0x022d -#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS 0x022e -#define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230 -#define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231 -#define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232 -#define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236 -#define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237 -#define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238 -#define USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI 0x023f -#define USB_DEVICE_ID_APPLE_WELLSPRING4_ISO 0x0240 -#define USB_DEVICE_ID_APPLE_WELLSPRING4_JIS 0x0241 -#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI 0x0242 -#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO 0x0243 -#define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS 0x0244 -#define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI 0x0245 -#define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO 0x0246 -#define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS 0x0247 -#define USB_DEVICE_ID_APPLE_ALU_REVB_ANSI 0x024f -#define USB_DEVICE_ID_APPLE_ALU_REVB_ISO 0x0250 -#define USB_DEVICE_ID_APPLE_ALU_REVB_JIS 0x0251 -#define USB_DEVICE_ID_APPLE_WELLSPRING5A_ANSI 0x0252 -#define USB_DEVICE_ID_APPLE_WELLSPRING5A_ISO 0x0253 -#define USB_DEVICE_ID_APPLE_WELLSPRING5A_JIS 0x0254 -#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ANSI 0x0259 -#define USB_DEVICE_ID_APPLE_WELLSPRING7A_ISO 0x025a -#define USB_DEVICE_ID_APPLE_WELLSPRING7A_JIS 0x025b -#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ANSI 0x0249 -#define USB_DEVICE_ID_APPLE_WELLSPRING6A_ISO 0x024a -#define USB_DEVICE_ID_APPLE_WELLSPRING6A_JIS 0x024b -#define USB_DEVICE_ID_APPLE_WELLSPRING6_ANSI 0x024c -#define USB_DEVICE_ID_APPLE_WELLSPRING6_ISO 0x024d -#define USB_DEVICE_ID_APPLE_WELLSPRING6_JIS 0x024e -#define USB_DEVICE_ID_APPLE_WELLSPRING7_ANSI 0x0262 -#define USB_DEVICE_ID_APPLE_WELLSPRING7_ISO 0x0263 -#define USB_DEVICE_ID_APPLE_WELLSPRING7_JIS 0x0264 -#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239 -#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a -#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b -#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI 0x0255 -#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO 0x0256 -#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS 0x0257 -#define USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_ANSI 0x0267 -#define USB_DEVICE_ID_APPLE_WELLSPRING8_ANSI 0x0290 -#define USB_DEVICE_ID_APPLE_WELLSPRING8_ISO 0x0291 -#define USB_DEVICE_ID_APPLE_WELLSPRING8_JIS 0x0292 -#define USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI 0x0272 -#define USB_DEVICE_ID_APPLE_WELLSPRING9_ISO 0x0273 -#define USB_DEVICE_ID_APPLE_WELLSPRING9_JIS 0x0274 -#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a -#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b -#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240 -#define USB_DEVICE_ID_APPLE_IRCONTROL2 0x1440 -#define USB_DEVICE_ID_APPLE_IRCONTROL3 0x8241 -#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242 -#define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243 - -#define USB_VENDOR_ID_ASUS 0x0486 -#define USB_DEVICE_ID_ASUS_T91MT 0x0185 -#define USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO 0x0186 - -#define USB_VENDOR_ID_ASUSTEK 0x0b05 -#define USB_DEVICE_ID_ASUSTEK_LCM 0x1726 -#define USB_DEVICE_ID_ASUSTEK_LCM2 0x175b -#define USB_DEVICE_ID_ASUSTEK_NOTEBOOK_KEYBOARD 0x8585 - -#define USB_VENDOR_ID_ATEN 0x0557 -#define USB_DEVICE_ID_ATEN_UC100KM 0x2004 -#define USB_DEVICE_ID_ATEN_CS124U 0x2202 -#define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204 -#define USB_DEVICE_ID_ATEN_4PORTKVM 0x2205 -#define USB_DEVICE_ID_ATEN_4PORTKVMC 0x2208 -#define USB_DEVICE_ID_ATEN_CS682 0x2213 -#define USB_DEVICE_ID_ATEN_CS692 0x8021 - -#define USB_VENDOR_ID_ATMEL 0x03eb -#define USB_DEVICE_ID_ATMEL_MULTITOUCH 0x211c -#define USB_DEVICE_ID_ATMEL_MXT_DIGITIZER 0x2118 -#define USB_VENDOR_ID_ATMEL_V_USB 0x16c0 -#define USB_DEVICE_ID_ATMEL_V_USB 0x05df - -#define USB_VENDOR_ID_AUREAL 0x0755 -#define USB_DEVICE_ID_AUREAL_W01RN 0x2626 - -#define USB_VENDOR_ID_AVERMEDIA 0x07ca -#define USB_DEVICE_ID_AVER_FM_MR800 0xb800 - -#define USB_VENDOR_ID_AXENTIA 0x12cf -#define USB_DEVICE_ID_AXENTIA_FM_RADIO 0x7111 - -#define USB_VENDOR_ID_BAANTO 0x2453 -#define USB_DEVICE_ID_BAANTO_MT_190W2 0x0100 - -#define USB_VENDOR_ID_BELKIN 0x050d -#define USB_DEVICE_ID_FLIP_KVM 0x3201 - -#define USB_VENDOR_ID_BERKSHIRE 0x0c98 -#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 - -#define USB_VENDOR_ID_BETOP_2185BFM 0x11c2 -#define USB_VENDOR_ID_BETOP_2185PC 0x11c0 -#define USB_VENDOR_ID_BETOP_2185V2PC 0x8380 -#define USB_VENDOR_ID_BETOP_2185V2BFM 0x20bc - -#define USB_VENDOR_ID_BTC 0x046e -#define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578 -#define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577 - -#define USB_VENDOR_ID_CANDO 0x2087 -#define USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH 0x0703 -#define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01 -#define USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1 0x0a02 -#define USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6 0x0b03 -#define USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6 0x0f01 - -#define USB_VENDOR_ID_CH 0x068e -#define USB_DEVICE_ID_CH_PRO_THROTTLE 0x00f1 -#define USB_DEVICE_ID_CH_PRO_PEDALS 0x00f2 -#define USB_DEVICE_ID_CH_FIGHTERSTICK 0x00f3 -#define USB_DEVICE_ID_CH_COMBATSTICK 0x00f4 -#define USB_DEVICE_ID_CH_FLIGHT_SIM_ECLIPSE_YOKE 0x0051 -#define USB_DEVICE_ID_CH_FLIGHT_SIM_YOKE 0x00ff -#define USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK 0x00d3 -#define USB_DEVICE_ID_CH_AXIS_295 0x001c - -#define USB_VENDOR_ID_CHERRY 0x046a -#define USB_DEVICE_ID_CHERRY_CYMOTION 0x0023 -#define USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR 0x0027 - -#define USB_VENDOR_ID_CHIC 0x05fe -#define USB_DEVICE_ID_CHIC_GAMEPAD 0x0014 - -#define USB_VENDOR_ID_CHICONY 0x04f2 -#define USB_DEVICE_ID_CHICONY_TACTICAL_PAD 0x0418 -#define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d -#define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618 -#define USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE 0x1053 -#define USB_DEVICE_ID_CHICONY_WIRELESS2 0x1123 -#define USB_DEVICE_ID_CHICONY_AK1D 0x1125 -#define USB_DEVICE_ID_CHICONY_ACER_SWITCH12 0x1421 - -#define USB_VENDOR_ID_CHUNGHWAT 0x2247 -#define USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH 0x0001 - -#define USB_VENDOR_ID_CIDC 0x1677 - -#define USB_VENDOR_ID_CJTOUCH 0x24b8 -#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020 0x0020 -#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040 0x0040 - -#define USB_VENDOR_ID_CMEDIA 0x0d8c -#define USB_DEVICE_ID_CM109 0x000e -#define USB_DEVICE_ID_CM6533 0x0022 - -#define USB_VENDOR_ID_CODEMERCS 0x07c0 -#define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500 -#define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff - -#define USB_VENDOR_ID_CORSAIR 0x1b1c -#define USB_DEVICE_ID_CORSAIR_K90 0x1b02 - -#define USB_VENDOR_ID_CORSAIR 0x1b1c -#define USB_DEVICE_ID_CORSAIR_K70R 0x1b09 -#define USB_DEVICE_ID_CORSAIR_K95RGB 0x1b11 -#define USB_DEVICE_ID_CORSAIR_M65RGB 0x1b12 -#define USB_DEVICE_ID_CORSAIR_K70RGB 0x1b13 -#define USB_DEVICE_ID_CORSAIR_STRAFE 0x1b15 -#define USB_DEVICE_ID_CORSAIR_K65RGB 0x1b17 - -#define USB_VENDOR_ID_CREATIVELABS 0x041e -#define USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51 0x322c -#define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801 - -#define USB_VENDOR_ID_CVTOUCH 0x1ff7 -#define USB_DEVICE_ID_CVTOUCH_SCREEN 0x0013 - -#define USB_VENDOR_ID_CYGNAL 0x10c4 -#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a -#define USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH 0x81b9 -#define USB_DEVICE_ID_CYGNAL_CP2112 0xea90 - -#define USB_DEVICE_ID_CYGNAL_RADIO_SI4713 0x8244 - -#define USB_VENDOR_ID_CYPRESS 0x04b4 -#define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001 -#define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500 -#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE 0x7417 -#define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61 -#define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64 -#define USB_DEVICE_ID_CYPRESS_BARCODE_3 0xbca1 -#define USB_DEVICE_ID_CYPRESS_BARCODE_4 0xed81 -#define USB_DEVICE_ID_CYPRESS_TRUETOUCH 0xc001 - -#define USB_VENDOR_ID_DATA_MODUL 0x7374 -#define USB_VENDOR_ID_DATA_MODUL_EASYMAXTOUCH 0x1201 - -#define USB_VENDOR_ID_DEALEXTREAME 0x10c5 -#define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701 0x819a - -#define USB_VENDOR_ID_DELCOM 0x0fc5 -#define USB_DEVICE_ID_DELCOM_VISUAL_IND 0xb080 - -#define USB_VENDOR_ID_DELORME 0x1163 -#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100 -#define USB_DEVICE_ID_DELORME_EM_LT20 0x0200 - -#define USB_VENDOR_ID_DMI 0x0c0b -#define USB_DEVICE_ID_DMI_ENC 0x5fab - -#define USB_VENDOR_ID_DRAGONRISE 0x0079 -#define USB_DEVICE_ID_DRAGONRISE_WIIU 0x1800 - -#define USB_VENDOR_ID_DWAV 0x0eef -#define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001 -#define USB_DEVICE_ID_DWAV_TOUCHCONTROLLER 0x0002 -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D 0x480d -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E 0x480e -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7207 0x7207 -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C 0x720c -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7224 0x7224 -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_722A 0x722A -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_725E 0x725e -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7262 0x7262 -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B 0x726b -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1 0x72a1 -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72AA 0x72aa -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72C4 0x72c4 -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72D0 0x72d0 -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA 0x72fa -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302 0x7302 -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7349 0x7349 -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_73F7 0x73f7 -#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001 - -#define USB_VENDOR_ID_ELAN 0x04f3 - -#define USB_VENDOR_ID_ELECOM 0x056e -#define USB_DEVICE_ID_ELECOM_BM084 0x0061 - -#define USB_VENDOR_ID_DREAM_CHEEKY 0x1d34 -#define USB_DEVICE_ID_DREAM_CHEEKY_WN 0x0004 -#define USB_DEVICE_ID_DREAM_CHEEKY_FA 0x000a - -#define USB_VENDOR_ID_ELITEGROUP 0x03fc -#define USB_DEVICE_ID_ELITEGROUP_05D8 0x05d8 - -#define USB_VENDOR_ID_ELO 0x04E7 -#define USB_DEVICE_ID_ELO_TS2515 0x0022 -#define USB_DEVICE_ID_ELO_TS2700 0x0020 - -#define USB_VENDOR_ID_EMS 0x2006 -#define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118 - -#define USB_VENDOR_ID_FLATFROG 0x25b5 -#define USB_DEVICE_ID_MULTITOUCH_3200 0x0002 - -#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f -#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 - -#define USB_VENDOR_ID_ETT 0x0664 -#define USB_DEVICE_ID_TC5UH 0x0309 -#define USB_DEVICE_ID_TC4UM 0x0306 - -#define USB_VENDOR_ID_ETURBOTOUCH 0x22b9 -#define USB_DEVICE_ID_ETURBOTOUCH 0x0006 -#define USB_DEVICE_ID_ETURBOTOUCH_2968 0x2968 - -#define USB_VENDOR_ID_EZKEY 0x0518 -#define USB_DEVICE_ID_BTC_8193 0x0002 - -#define USB_VENDOR_ID_FORMOSA 0x147a -#define USB_DEVICE_ID_FORMOSA_IR_RECEIVER 0xe03e - -#define USB_VENDOR_ID_FREESCALE 0x15A2 -#define USB_DEVICE_ID_FREESCALE_MX28 0x004F - -#define USB_VENDOR_ID_FRUCTEL 0x25B6 -#define USB_DEVICE_ID_GAMETEL_MT_MODE 0x0002 - -#define USB_VENDOR_ID_GAMERON 0x0810 -#define USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR 0x0001 -#define USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR 0x0002 - -#define USB_VENDOR_ID_GEMBIRD 0x11ff -#define USB_DEVICE_ID_GEMBIRD_JPD_DUALFORCE2 0x3331 - -#define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc -#define USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS 0x0003 -#define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PWT_TENFINGERS 0x0100 -#define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0101 0x0101 -#define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0102 0x0102 -#define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_0106 0x0106 -#define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_010A 0x010a -#define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_E100 0xe100 - -#define USB_VENDOR_ID_GOODTOUCH 0x1aad -#define USB_DEVICE_ID_GOODTOUCH_000f 0x000f - -#define USB_VENDOR_ID_GOTOP 0x08f2 -#define USB_DEVICE_ID_SUPER_Q2 0x007f -#define USB_DEVICE_ID_GOGOPEN 0x00ce -#define USB_DEVICE_ID_PENPOWER 0x00f4 - -#define USB_VENDOR_ID_GREENASIA 0x0e8f -#define USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD 0x3013 - -#define USB_VENDOR_ID_GRETAGMACBETH 0x0971 -#define USB_DEVICE_ID_GRETAGMACBETH_HUEY 0x2005 - -#define USB_VENDOR_ID_GRIFFIN 0x077d -#define USB_DEVICE_ID_POWERMATE 0x0410 -#define USB_DEVICE_ID_SOUNDKNOB 0x04AA -#define USB_DEVICE_ID_RADIOSHARK 0x627a - -#define USB_VENDOR_ID_GTCO 0x078c -#define USB_DEVICE_ID_GTCO_90 0x0090 -#define USB_DEVICE_ID_GTCO_100 0x0100 -#define USB_DEVICE_ID_GTCO_101 0x0101 -#define USB_DEVICE_ID_GTCO_103 0x0103 -#define USB_DEVICE_ID_GTCO_104 0x0104 -#define USB_DEVICE_ID_GTCO_105 0x0105 -#define USB_DEVICE_ID_GTCO_106 0x0106 -#define USB_DEVICE_ID_GTCO_107 0x0107 -#define USB_DEVICE_ID_GTCO_108 0x0108 -#define USB_DEVICE_ID_GTCO_200 0x0200 -#define USB_DEVICE_ID_GTCO_201 0x0201 -#define USB_DEVICE_ID_GTCO_202 0x0202 -#define USB_DEVICE_ID_GTCO_203 0x0203 -#define USB_DEVICE_ID_GTCO_204 0x0204 -#define USB_DEVICE_ID_GTCO_205 0x0205 -#define USB_DEVICE_ID_GTCO_206 0x0206 -#define USB_DEVICE_ID_GTCO_207 0x0207 -#define USB_DEVICE_ID_GTCO_300 0x0300 -#define USB_DEVICE_ID_GTCO_301 0x0301 -#define USB_DEVICE_ID_GTCO_302 0x0302 -#define USB_DEVICE_ID_GTCO_303 0x0303 -#define USB_DEVICE_ID_GTCO_304 0x0304 -#define USB_DEVICE_ID_GTCO_305 0x0305 -#define USB_DEVICE_ID_GTCO_306 0x0306 -#define USB_DEVICE_ID_GTCO_307 0x0307 -#define USB_DEVICE_ID_GTCO_308 0x0308 -#define USB_DEVICE_ID_GTCO_309 0x0309 -#define USB_DEVICE_ID_GTCO_400 0x0400 -#define USB_DEVICE_ID_GTCO_401 0x0401 -#define USB_DEVICE_ID_GTCO_402 0x0402 -#define USB_DEVICE_ID_GTCO_403 0x0403 -#define USB_DEVICE_ID_GTCO_404 0x0404 -#define USB_DEVICE_ID_GTCO_405 0x0405 -#define USB_DEVICE_ID_GTCO_500 0x0500 -#define USB_DEVICE_ID_GTCO_501 0x0501 -#define USB_DEVICE_ID_GTCO_502 0x0502 -#define USB_DEVICE_ID_GTCO_503 0x0503 -#define USB_DEVICE_ID_GTCO_504 0x0504 -#define USB_DEVICE_ID_GTCO_1000 0x1000 -#define USB_DEVICE_ID_GTCO_1001 0x1001 -#define USB_DEVICE_ID_GTCO_1002 0x1002 -#define USB_DEVICE_ID_GTCO_1003 0x1003 -#define USB_DEVICE_ID_GTCO_1004 0x1004 -#define USB_DEVICE_ID_GTCO_1005 0x1005 -#define USB_DEVICE_ID_GTCO_1006 0x1006 -#define USB_DEVICE_ID_GTCO_1007 0x1007 - -#define USB_VENDOR_ID_GYRATION 0x0c16 -#define USB_DEVICE_ID_GYRATION_REMOTE 0x0002 -#define USB_DEVICE_ID_GYRATION_REMOTE_2 0x0003 -#define USB_DEVICE_ID_GYRATION_REMOTE_3 0x0008 - -#define USB_VENDOR_ID_HANWANG 0x0b57 -#define USB_DEVICE_ID_HANWANG_TABLET_FIRST 0x5000 -#define USB_DEVICE_ID_HANWANG_TABLET_LAST 0x8fff - -#define USB_VENDOR_ID_HANVON 0x20b3 -#define USB_DEVICE_ID_HANVON_MULTITOUCH 0x0a18 - -#define USB_VENDOR_ID_HANVON_ALT 0x22ed -#define USB_DEVICE_ID_HANVON_ALT_MULTITOUCH 0x1010 - -#define USB_VENDOR_ID_HAPP 0x078b -#define USB_DEVICE_ID_UGCI_DRIVING 0x0010 -#define USB_DEVICE_ID_UGCI_FLYING 0x0020 -#define USB_DEVICE_ID_UGCI_FIGHTING 0x0030 - -#define USB_VENDOR_ID_HP 0x03f0 -#define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A 0x0a4a -#define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A 0x0b4a -#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE 0x134a - -#define USB_VENDOR_ID_HUION 0x256c -#define USB_DEVICE_ID_HUION_TABLET 0x006e - -#define USB_VENDOR_ID_IDEACOM 0x1cb6 -#define USB_DEVICE_ID_IDEACOM_IDC6650 0x6650 -#define USB_DEVICE_ID_IDEACOM_IDC6651 0x6651 - -#define USB_VENDOR_ID_ILITEK 0x222a -#define USB_DEVICE_ID_ILITEK_MULTITOUCH 0x0001 - -#define USB_VENDOR_ID_INTEL_0 0x8086 -#define USB_VENDOR_ID_INTEL_1 0x8087 -#define USB_DEVICE_ID_INTEL_HID_SENSOR_0 0x09fa -#define USB_DEVICE_ID_INTEL_HID_SENSOR_1 0x0a04 - -#define USB_VENDOR_ID_STM_0 0x0483 -#define USB_DEVICE_ID_STM_HID_SENSOR 0x91d1 -#define USB_DEVICE_ID_STM_HID_SENSOR_1 0x9100 - -#define USB_VENDOR_ID_ION 0x15e4 -#define USB_DEVICE_ID_ICADE 0x0132 - -#define USB_VENDOR_ID_HOLTEK 0x1241 -#define USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP 0x5015 - -#define USB_VENDOR_ID_HOLTEK_ALT 0x04d9 -#define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD 0xa055 -#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A04A 0xa04a -#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A067 0xa067 -#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A070 0xa070 -#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A072 0xa072 -#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A081 0xa081 -#define USB_DEVICE_ID_HOLTEK_ALT_MOUSE_A0C2 0xa0c2 -#define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096 0xa096 - -#define USB_VENDOR_ID_IMATION 0x0718 -#define USB_DEVICE_ID_DISC_STAKKA 0xd000 - -#define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615 -#define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070 - -#define USB_VENDOR_ID_ITE 0x048d -#define USB_DEVICE_ID_ITE_LENOVO_YOGA 0x8386 -#define USB_DEVICE_ID_ITE_LENOVO_YOGA2 0x8350 -#define USB_DEVICE_ID_ITE_LENOVO_YOGA900 0x8396 - -#define USB_VENDOR_ID_JABRA 0x0b0e -#define USB_DEVICE_ID_JABRA_SPEAK_410 0x0412 -#define USB_DEVICE_ID_JABRA_SPEAK_510 0x0420 -#define USB_DEVICE_ID_JABRA_GN9350E 0x9350 - -#define USB_VENDOR_ID_JESS 0x0c45 -#define USB_DEVICE_ID_JESS_YUREX 0x1010 - -#define USB_VENDOR_ID_JESS2 0x0f30 -#define USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD 0x0111 - -#define USB_VENDOR_ID_KBGEAR 0x084e -#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001 - -#define USB_VENDOR_ID_KENSINGTON 0x047d -#define USB_DEVICE_ID_KS_SLIMBLADE 0x2041 - -#define USB_VENDOR_ID_KWORLD 0x1b80 -#define USB_DEVICE_ID_KWORLD_RADIO_FM700 0xd700 - -#define USB_VENDOR_ID_KEYTOUCH 0x0926 -#define USB_DEVICE_ID_KEYTOUCH_IEC 0x3333 - -#define USB_VENDOR_ID_KYE 0x0458 -#define USB_DEVICE_ID_KYE_ERGO_525V 0x0087 -#define USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE 0x0138 -#define USB_DEVICE_ID_GENIUS_MANTICORE 0x0153 -#define USB_DEVICE_ID_GENIUS_GX_IMPERATOR 0x4018 -#define USB_DEVICE_ID_KYE_GPEN_560 0x5003 -#define USB_DEVICE_ID_KYE_EASYPEN_I405X 0x5010 -#define USB_DEVICE_ID_KYE_MOUSEPEN_I608X 0x5011 -#define USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2 0x501a -#define USB_DEVICE_ID_KYE_EASYPEN_M610X 0x5013 -#define USB_DEVICE_ID_KYE_PENSKETCH_M912 0x5015 - -#define USB_VENDOR_ID_LABTEC 0x1020 -#define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006 - -#define USB_VENDOR_ID_LCPOWER 0x1241 -#define USB_DEVICE_ID_LCPOWER_LC1000 0xf767 - -#define USB_VENDOR_ID_LD 0x0f11 -#define USB_DEVICE_ID_LD_CASSY 0x1000 -#define USB_DEVICE_ID_LD_CASSY2 0x1001 -#define USB_DEVICE_ID_LD_POCKETCASSY 0x1010 -#define USB_DEVICE_ID_LD_POCKETCASSY2 0x1011 -#define USB_DEVICE_ID_LD_MOBILECASSY 0x1020 -#define USB_DEVICE_ID_LD_MOBILECASSY2 0x1021 -#define USB_DEVICE_ID_LD_MICROCASSYVOLTAGE 0x1031 -#define USB_DEVICE_ID_LD_MICROCASSYCURRENT 0x1032 -#define USB_DEVICE_ID_LD_MICROCASSYTIME 0x1033 -#define USB_DEVICE_ID_LD_MICROCASSYTEMPERATURE 0x1035 -#define USB_DEVICE_ID_LD_MICROCASSYPH 0x1038 -#define USB_DEVICE_ID_LD_JWM 0x1080 -#define USB_DEVICE_ID_LD_DMMP 0x1081 -#define USB_DEVICE_ID_LD_UMIP 0x1090 -#define USB_DEVICE_ID_LD_UMIC 0x10A0 -#define USB_DEVICE_ID_LD_UMIB 0x10B0 -#define USB_DEVICE_ID_LD_XRAY 0x1100 -#define USB_DEVICE_ID_LD_XRAY2 0x1101 -#define USB_DEVICE_ID_LD_XRAYCT 0x1110 -#define USB_DEVICE_ID_LD_VIDEOCOM 0x1200 -#define USB_DEVICE_ID_LD_MOTOR 0x1210 -#define USB_DEVICE_ID_LD_COM3LAB 0x2000 -#define USB_DEVICE_ID_LD_TELEPORT 0x2010 -#define USB_DEVICE_ID_LD_NETWORKANALYSER 0x2020 -#define USB_DEVICE_ID_LD_POWERCONTROL 0x2030 -#define USB_DEVICE_ID_LD_MACHINETEST 0x2040 -#define USB_DEVICE_ID_LD_MOSTANALYSER 0x2050 -#define USB_DEVICE_ID_LD_MOSTANALYSER2 0x2051 -#define USB_DEVICE_ID_LD_ABSESP 0x2060 -#define USB_DEVICE_ID_LD_AUTODATABUS 0x2070 -#define USB_DEVICE_ID_LD_MCT 0x2080 -#define USB_DEVICE_ID_LD_HYBRID 0x2090 -#define USB_DEVICE_ID_LD_HEATCONTROL 0x20A0 - -#define USB_VENDOR_ID_LENOVO 0x17ef -#define USB_DEVICE_ID_LENOVO_TPKBD 0x6009 -#define USB_DEVICE_ID_LENOVO_CUSBKBD 0x6047 -#define USB_DEVICE_ID_LENOVO_CBTKBD 0x6048 -#define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067 - -#define USB_VENDOR_ID_LG 0x1fd2 -#define USB_DEVICE_ID_LG_MULTITOUCH 0x0064 - -#define USB_VENDOR_ID_LOGITECH 0x046d -#define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e -#define USB_DEVICE_ID_LOGITECH_T651 0xb00c -#define USB_DEVICE_ID_LOGITECH_C077 0xc007 -#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 -#define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110 -#define USB_DEVICE_ID_LOGITECH_HARMONY_LAST 0xc14f -#define USB_DEVICE_ID_LOGITECH_HARMONY_PS3 0x0306 -#define USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS 0xc24d -#define USB_DEVICE_ID_LOGITECH_MOUSE_C01A 0xc01a -#define USB_DEVICE_ID_LOGITECH_MOUSE_C05A 0xc05a -#define USB_DEVICE_ID_LOGITECH_MOUSE_C06A 0xc06a -#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD 0xc20a -#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD 0xc211 -#define USB_DEVICE_ID_LOGITECH_EXTREME_3D 0xc215 -#define USB_DEVICE_ID_LOGITECH_DUAL_ACTION 0xc216 -#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218 -#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2 0xc219 -#define USB_DEVICE_ID_LOGITECH_G29_WHEEL 0xc24f -#define USB_DEVICE_ID_LOGITECH_G920_WHEEL 0xc262 -#define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283 -#define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286 -#define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 0xc287 -#define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293 -#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294 -#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295 -#define USB_DEVICE_ID_LOGITECH_DFP_WHEEL 0xc298 -#define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299 -#define USB_DEVICE_ID_LOGITECH_DFGT_WHEEL 0xc29a -#define USB_DEVICE_ID_LOGITECH_G27_WHEEL 0xc29b -#define USB_DEVICE_ID_LOGITECH_WII_WHEEL 0xc29c -#define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a -#define USB_DEVICE_ID_S510_RECEIVER 0xc50c -#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517 -#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512 -#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513 -#define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER 0xc52b -#define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2 0xc532 -#define USB_DEVICE_ID_SPACETRAVELLER 0xc623 -#define USB_DEVICE_ID_SPACENAVIGATOR 0xc626 -#define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704 -#define USB_DEVICE_ID_DINOVO_EDGE 0xc714 -#define USB_DEVICE_ID_DINOVO_MINI 0xc71f -#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2 0xca03 -#define USB_DEVICE_ID_LOGITECH_VIBRATION_WHEEL 0xca04 - -#define USB_VENDOR_ID_LUMIO 0x202e -#define USB_DEVICE_ID_CRYSTALTOUCH 0x0006 -#define USB_DEVICE_ID_CRYSTALTOUCH_DUAL 0x0007 - -#define USB_VENDOR_ID_MADCATZ 0x0738 -#define USB_DEVICE_ID_MADCATZ_BEATPAD 0x4540 -#define USB_DEVICE_ID_MADCATZ_RAT5 0x1705 -#define USB_DEVICE_ID_MADCATZ_RAT9 0x1709 - -#define USB_VENDOR_ID_MCC 0x09db -#define USB_DEVICE_ID_MCC_PMD1024LS 0x0076 -#define USB_DEVICE_ID_MCC_PMD1208LS 0x007a - -#define USB_VENDOR_ID_MGE 0x0463 -#define USB_DEVICE_ID_MGE_UPS 0xffff -#define USB_DEVICE_ID_MGE_UPS1 0x0001 - -#define USB_VENDOR_ID_MICROCHIP 0x04d8 -#define USB_DEVICE_ID_PICKIT1 0x0032 -#define USB_DEVICE_ID_PICKIT2 0x0033 -#define USB_DEVICE_ID_PICOLCD 0xc002 -#define USB_DEVICE_ID_PICOLCD_BOOTLOADER 0xf002 -#define USB_DEVICE_ID_PICK16F1454 0x0042 -#define USB_DEVICE_ID_PICK16F1454_V2 0xf2f7 -#define USB_DEVICE_ID_LUXAFOR 0xf372 - -#define USB_VENDOR_ID_MICROSOFT 0x045e -#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b -#define USB_DEVICE_ID_MS_OFFICE_KB 0x0048 -#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d -#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_7K 0x00b4 -#define USB_DEVICE_ID_MS_NE4K 0x00db -#define USB_DEVICE_ID_MS_NE4K_JP 0x00dc -#define USB_DEVICE_ID_MS_LK6K 0x00f9 -#define USB_DEVICE_ID_MS_PRESENTER_8K_BT 0x0701 -#define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713 -#define USB_DEVICE_ID_MS_NE7K 0x071d -#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K 0x0730 -#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3KV1 0x0732 -#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_600 0x0750 -#define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500 0x076c -#define USB_DEVICE_ID_MS_COMFORT_KEYBOARD 0x00e3 -#define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799 -#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7 -#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 -#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3 0x07dc -#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_2 0x07e2 -#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_3_JP 0x07dd -#define USB_DEVICE_ID_MS_TYPE_COVER_PRO_4_JP 0x07e9 -#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07de -#define USB_DEVICE_ID_MS_POWER_COVER 0x07da - -#define USB_VENDOR_ID_MOJO 0x8282 -#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 - -#define USB_VENDOR_ID_MONTEREY 0x0566 -#define USB_DEVICE_ID_GENIUS_KB29E 0x3004 - -#define USB_VENDOR_ID_MSI 0x1770 -#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 - -#define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 -#define USB_DEVICE_ID_N_S_HARMONY 0xc359 - -#define USB_VENDOR_ID_NATSU 0x08b7 -#define USB_DEVICE_ID_NATSU_GAMEPAD 0x0001 - -#define USB_VENDOR_ID_NCR 0x0404 -#define USB_DEVICE_ID_NCR_FIRST 0x0300 -#define USB_DEVICE_ID_NCR_LAST 0x03ff - -#define USB_VENDOR_ID_NEC 0x073e -#define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301 - -#define USB_VENDOR_ID_NEXIO 0x1870 -#define USB_DEVICE_ID_NEXIO_MULTITOUCH_420 0x010d -#define USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750 0x0110 - -#define USB_VENDOR_ID_NEXTWINDOW 0x1926 -#define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN 0x0003 - -#define USB_VENDOR_ID_NINTENDO 0x057e -#define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306 -#define USB_DEVICE_ID_NINTENDO_WIIMOTE2 0x0330 - -#define USB_VENDOR_ID_NOVATEK 0x0603 -#define USB_DEVICE_ID_NOVATEK_PCT 0x0600 -#define USB_DEVICE_ID_NOVATEK_MOUSE 0x1602 - -#define USB_VENDOR_ID_NTRIG 0x1b96 -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001 -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1 0x0003 -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2 0x0004 -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_3 0x0005 -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_4 0x0006 -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_5 0x0007 -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_6 0x0008 -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_7 0x0009 -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_8 0x000A -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_9 0x000B -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_10 0x000C -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_11 0x000D -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_12 0x000E -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_13 0x000F -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_14 0x0010 -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_15 0x0011 -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_16 0x0012 -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_17 0x0013 -#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18 0x0014 -#define USB_DEVICE_ID_NTRIG_DUOSENSE 0x1500 - -#define USB_VENDOR_ID_ONTRAK 0x0a07 -#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064 - -#define USB_VENDOR_ID_ORTEK 0x05a4 -#define USB_DEVICE_ID_ORTEK_PKB1700 0x1700 -#define USB_DEVICE_ID_ORTEK_WKB2000 0x2000 - -#define USB_VENDOR_ID_PLANTRONICS 0x047f - -#define USB_VENDOR_ID_PANASONIC 0x04da -#define USB_DEVICE_ID_PANABOARD_UBT780 0x1044 -#define USB_DEVICE_ID_PANABOARD_UBT880 0x104d - -#define USB_VENDOR_ID_PANJIT 0x134c - -#define USB_VENDOR_ID_PANTHERLORD 0x0810 -#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK 0x0001 - -#define USB_VENDOR_ID_PENMOUNT 0x14e1 -#define USB_DEVICE_ID_PENMOUNT_PCI 0x3500 -#define USB_DEVICE_ID_PENMOUNT_1610 0x1610 -#define USB_DEVICE_ID_PENMOUNT_1640 0x1640 -#define USB_DEVICE_ID_PENMOUNT_6000 0x6000 - -#define USB_VENDOR_ID_PETALYNX 0x18b1 -#define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037 - -#define USB_VENDOR_ID_PHILIPS 0x0471 -#define USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE 0x0617 - -#define USB_VENDOR_ID_PI_ENGINEERING 0x05f3 -#define USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL 0xff - -#define USB_VENDOR_ID_PIXART 0x093a -#define USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE_ID2 0x0137 -#define USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE 0x2510 -#define USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN 0x8001 -#define USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1 0x8002 -#define USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2 0x8003 - -#define USB_VENDOR_ID_PLAYDOTCOM 0x0b43 -#define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII 0x0003 - -#define USB_VENDOR_ID_POWERCOM 0x0d9f -#define USB_DEVICE_ID_POWERCOM_UPS 0x0002 - -#define USB_VENDOR_ID_PRODIGE 0x05af -#define USB_DEVICE_ID_PRODIGE_CORDLESS 0x3062 - -#define USB_VENDOR_ID_QUANTA 0x0408 -#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH 0x3000 -#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001 0x3001 -#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3003 0x3003 -#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008 0x3008 - -#define USB_VENDOR_ID_RAZER 0x1532 -#define USB_DEVICE_ID_RAZER_BLADE_14 0x011D - -#define USB_VENDOR_ID_REALTEK 0x0bda -#define USB_DEVICE_ID_REALTEK_READER 0x0152 - -#define USB_VENDOR_ID_ROCCAT 0x1e7d -#define USB_DEVICE_ID_ROCCAT_ARVO 0x30d4 -#define USB_DEVICE_ID_ROCCAT_ISKU 0x319c -#define USB_DEVICE_ID_ROCCAT_ISKUFX 0x3264 -#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced -#define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51 -#define USB_DEVICE_ID_ROCCAT_KONEPURE 0x2dbe -#define USB_DEVICE_ID_ROCCAT_KONEPURE_OPTICAL 0x2db4 -#define USB_DEVICE_ID_ROCCAT_KONEXTD 0x2e22 -#define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50 -#define USB_DEVICE_ID_ROCCAT_LUA 0x2c2e -#define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24 -#define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6 -#define USB_DEVICE_ID_ROCCAT_RYOS_MK 0x3138 -#define USB_DEVICE_ID_ROCCAT_RYOS_MK_GLOW 0x31ce -#define USB_DEVICE_ID_ROCCAT_RYOS_MK_PRO 0x3232 -#define USB_DEVICE_ID_ROCCAT_SAVU 0x2d5a - -#define USB_VENDOR_ID_SAITEK 0x06a3 -#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 -#define USB_DEVICE_ID_SAITEK_PS1000 0x0621 -#define USB_DEVICE_ID_SAITEK_RAT7_OLD 0x0ccb -#define USB_DEVICE_ID_SAITEK_RAT7 0x0cd7 -#define USB_DEVICE_ID_SAITEK_RAT9 0x0cfa -#define USB_DEVICE_ID_SAITEK_MMO7 0x0cd0 - -#define USB_VENDOR_ID_SAMSUNG 0x0419 -#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 -#define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600 - -#define USB_VENDOR_ID_SEMICO 0x1a2c -#define USB_DEVICE_ID_SEMICO_USB_KEYKOARD 0x0023 -#define USB_DEVICE_ID_SEMICO_USB_KEYKOARD2 0x0027 - -#define USB_VENDOR_ID_SENNHEISER 0x1395 -#define USB_DEVICE_ID_SENNHEISER_BTD500USB 0x002c - -#define USB_VENDOR_ID_SIGMA_MICRO 0x1c4f -#define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD 0x0002 - -#define USB_VENDOR_ID_SIGMATEL 0x066F -#define USB_DEVICE_ID_SIGMATEL_STMP3780 0x3780 - -#define USB_VENDOR_ID_SIS_TOUCH 0x0457 -#define USB_DEVICE_ID_SIS9200_TOUCH 0x9200 -#define USB_DEVICE_ID_SIS817_TOUCH 0x0817 -#define USB_DEVICE_ID_SIS_TS 0x1013 -#define USB_DEVICE_ID_SIS1030_TOUCH 0x1030 - -#define USB_VENDOR_ID_SKYCABLE 0x1223 -#define USB_DEVICE_ID_SKYCABLE_WIRELESS_PRESENTER 0x3F07 - -#define USB_VENDOR_ID_SMK 0x0609 -#define USB_DEVICE_ID_SMK_PS3_BDREMOTE 0x0306 - -#define USB_VENDOR_ID_SONY 0x054c -#define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b -#define USB_DEVICE_ID_SONY_VAIO_VGP_MOUSE 0x0374 -#define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306 -#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 -#define USB_DEVICE_ID_SONY_PS4_CONTROLLER 0x05c4 -#define USB_DEVICE_ID_SONY_MOTION_CONTROLLER 0x03d5 -#define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f -#define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002 -#define USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER 0x1000 - -#define USB_VENDOR_ID_SINO_LITE 0x1345 -#define USB_DEVICE_ID_SINO_LITE_CONTROLLER 0x3008 - -#define USB_VENDOR_ID_SOUNDGRAPH 0x15c2 -#define USB_DEVICE_ID_SOUNDGRAPH_IMON_FIRST 0x0034 -#define USB_DEVICE_ID_SOUNDGRAPH_IMON_LAST 0x0046 - -#define USB_VENDOR_ID_STANTUM 0x1f87 -#define USB_DEVICE_ID_MTP 0x0002 - -#define USB_VENDOR_ID_STANTUM_STM 0x0483 -#define USB_DEVICE_ID_MTP_STM 0x3261 - -#define USB_VENDOR_ID_STANTUM_SITRONIX 0x1403 -#define USB_DEVICE_ID_MTP_SITRONIX 0x5001 - -#define USB_VENDOR_ID_STEELSERIES 0x1038 -#define USB_DEVICE_ID_STEELSERIES_SRWS1 0x1410 - -#define USB_VENDOR_ID_SUN 0x0430 -#define USB_DEVICE_ID_RARITAN_KVM_DONGLE 0xcdab - -#define USB_VENDOR_ID_SUNPLUS 0x04fc -#define USB_DEVICE_ID_SUNPLUS_WDESKTOP 0x05d8 - -#define USB_VENDOR_ID_SYMBOL 0x05e0 -#define USB_DEVICE_ID_SYMBOL_SCANNER_1 0x0800 -#define USB_DEVICE_ID_SYMBOL_SCANNER_2 0x1300 - -#define USB_VENDOR_ID_SYNAPTICS 0x06cb -#define USB_DEVICE_ID_SYNAPTICS_TP 0x0001 -#define USB_DEVICE_ID_SYNAPTICS_INT_TP 0x0002 -#define USB_DEVICE_ID_SYNAPTICS_CPAD 0x0003 -#define USB_DEVICE_ID_SYNAPTICS_TS 0x0006 -#define USB_DEVICE_ID_SYNAPTICS_STICK 0x0007 -#define USB_DEVICE_ID_SYNAPTICS_WP 0x0008 -#define USB_DEVICE_ID_SYNAPTICS_COMP_TP 0x0009 -#define USB_DEVICE_ID_SYNAPTICS_WTP 0x0010 -#define USB_DEVICE_ID_SYNAPTICS_DPAD 0x0013 -#define USB_DEVICE_ID_SYNAPTICS_LTS1 0x0af8 -#define USB_DEVICE_ID_SYNAPTICS_LTS2 0x1d10 -#define USB_DEVICE_ID_SYNAPTICS_HD 0x0ac3 -#define USB_DEVICE_ID_SYNAPTICS_QUAD_HD 0x1ac3 -#define USB_DEVICE_ID_SYNAPTICS_TP_V103 0x5710 - -#define USB_VENDOR_ID_TEXAS_INSTRUMENTS 0x2047 -#define USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA 0x0855 - -#define USB_VENDOR_ID_THINGM 0x27b8 -#define USB_DEVICE_ID_BLINK1 0x01ed - -#define USB_VENDOR_ID_THRUSTMASTER 0x044f - -#define USB_VENDOR_ID_TIVO 0x150a -#define USB_DEVICE_ID_TIVO_SLIDE_BT 0x1200 -#define USB_DEVICE_ID_TIVO_SLIDE 0x1201 -#define USB_DEVICE_ID_TIVO_SLIDE_PRO 0x1203 - -#define USB_VENDOR_ID_TOPSEED 0x0766 -#define USB_DEVICE_ID_TOPSEED_CYBERLINK 0x0204 - -#define USB_VENDOR_ID_TOPSEED2 0x1784 -#define USB_DEVICE_ID_TOPSEED2_RF_COMBO 0x0004 -#define USB_DEVICE_ID_TOPSEED2_PERIPAD_701 0x0016 - -#define USB_VENDOR_ID_TOPMAX 0x0663 -#define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103 - -#define USB_VENDOR_ID_TOUCH_INTL 0x1e5e -#define USB_DEVICE_ID_TOUCH_INTL_MULTI_TOUCH 0x0313 - -#define USB_VENDOR_ID_TOUCHPACK 0x1bfd -#define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688 - -#define USB_VENDOR_ID_TPV 0x25aa -#define USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882 0x8882 -#define USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8883 0x8883 - -#define USB_VENDOR_ID_TURBOX 0x062a -#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201 -#define USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART 0x7100 - -#define USB_VENDOR_ID_TWINHAN 0x6253 -#define USB_DEVICE_ID_TWINHAN_IR_REMOTE 0x0100 - -#define USB_VENDOR_ID_UCLOGIC 0x5543 -#define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 0x0042 -#define USB_DEVICE_ID_UCLOGIC_TABLET_KNA5 0x6001 -#define USB_DEVICE_ID_UCLOGIC_TABLET_TWA60 0x0064 -#define USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U 0x0003 -#define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004 -#define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005 -#define USB_DEVICE_ID_UCLOGIC_TABLET_WP1062 0x0064 -#define USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850 0x0522 -#define USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60 0x0781 -#define USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3 0x3031 -#define USB_DEVICE_ID_UGEE_TABLET_81 0x0081 -#define USB_DEVICE_ID_UGEE_TABLET_45 0x0045 -#define USB_DEVICE_ID_YIYNOVA_TABLET 0x004d - -#define USB_VENDOR_ID_UNITEC 0x227d -#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0709 0x0709 -#define USB_DEVICE_ID_UNITEC_USB_TOUCH_0A19 0x0a19 - -#define USB_VENDOR_ID_VELLEMAN 0x10cf -#define USB_DEVICE_ID_VELLEMAN_K8055_FIRST 0x5500 -#define USB_DEVICE_ID_VELLEMAN_K8055_LAST 0x5503 -#define USB_DEVICE_ID_VELLEMAN_K8061_FIRST 0x8061 -#define USB_DEVICE_ID_VELLEMAN_K8061_LAST 0x8068 - -#define USB_VENDOR_ID_VTL 0x0306 -#define USB_DEVICE_ID_VTL_MULTITOUCH_FF3F 0xff3f - -#define USB_VENDOR_ID_WACOM 0x056a -#define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81 -#define USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH 0x00BD - -#define USB_VENDOR_ID_WALTOP 0x172f -#define USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH 0x0032 -#define USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH 0x0034 -#define USB_DEVICE_ID_WALTOP_Q_PAD 0x0037 -#define USB_DEVICE_ID_WALTOP_PID_0038 0x0038 -#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH 0x0501 -#define USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH 0x0500 -#define USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET 0x0502 - -#define USB_VENDOR_ID_WISEGROUP 0x0925 -#define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005 -#define USB_DEVICE_ID_SUPER_JOY_BOX_3 0x8888 -#define USB_DEVICE_ID_QUAD_USB_JOYPAD 0x8800 -#define USB_DEVICE_ID_DUAL_USB_JOYPAD 0x8866 - -#define USB_VENDOR_ID_WISEGROUP_LTD 0x6666 -#define USB_VENDOR_ID_WISEGROUP_LTD2 0x6677 -#define USB_DEVICE_ID_SMARTJOY_DUAL_PLUS 0x8802 -#define USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO 0x8801 -#define USB_DEVICE_ID_SUPER_DUAL_BOX_PRO 0x8802 -#define USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO 0x8804 - -#define USB_VENDOR_ID_WISTRON 0x0fb8 -#define USB_DEVICE_ID_WISTRON_OPTICAL_TOUCH 0x1109 - -#define USB_VENDOR_ID_X_TENSIONS 0x1ae7 -#define USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE 0x9001 - -#define USB_VENDOR_ID_XAT 0x2505 -#define USB_DEVICE_ID_XAT_CSR 0x0220 - -#define USB_VENDOR_ID_XIN_MO 0x16c0 -#define USB_DEVICE_ID_XIN_MO_DUAL_ARCADE 0x05e1 - -#define USB_VENDOR_ID_XIROKU 0x1477 -#define USB_DEVICE_ID_XIROKU_SPX 0x1006 -#define USB_DEVICE_ID_XIROKU_MPX 0x1007 -#define USB_DEVICE_ID_XIROKU_CSR 0x100e -#define USB_DEVICE_ID_XIROKU_SPX1 0x1021 -#define USB_DEVICE_ID_XIROKU_CSR1 0x1022 -#define USB_DEVICE_ID_XIROKU_MPX1 0x1023 -#define USB_DEVICE_ID_XIROKU_SPX2 0x1024 -#define USB_DEVICE_ID_XIROKU_CSR2 0x1025 -#define USB_DEVICE_ID_XIROKU_MPX2 0x1026 - -#define USB_VENDOR_ID_YEALINK 0x6993 -#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001 - -#define USB_VENDOR_ID_ZEROPLUS 0x0c12 - -#define USB_VENDOR_ID_ZYDACRON 0x13EC -#define USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL 0x0006 - -#define USB_VENDOR_ID_ZYTRONIC 0x14c8 -#define USB_DEVICE_ID_ZYTRONIC_ZXY100 0x0005 - -#define USB_VENDOR_ID_PRIMAX 0x0461 -#define USB_DEVICE_ID_PRIMAX_MOUSE_4D22 0x4d22 -#define USB_DEVICE_ID_PRIMAX_KEYBOARD 0x4e05 - - -#define USB_VENDOR_ID_RISO_KAGAKU 0x1294 /* Riso Kagaku Corp. */ -#define USB_DEVICE_ID_RI_KA_WEBMAIL 0x1320 /* Webmail Notifier */ - -#define USB_VENDOR_ID_MULTIPLE_1781 0x1781 -#define USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD 0x0a9d - -#define USB_VENDOR_ID_DRACAL_RAPHNET 0x289b -#define USB_DEVICE_ID_RAPHNET_2NES2SNES 0x0002 -#define USB_DEVICE_ID_RAPHNET_4NES4SNES 0x0003 - -#define USB_VENDOR_ID_UGTIZER 0x2179 -#define USB_DEVICE_ID_UGTIZER_TABLET_GP0610 0x0053 - -#endif diff --git a/src/linux/drivers/hid/hid-input.c b/src/linux/drivers/hid/hid-input.c deleted file mode 100644 index fb9ace1..0000000 --- a/src/linux/drivers/hid/hid-input.c +++ /dev/null @@ -1,1597 +0,0 @@ -/* - * Copyright (c) 2000-2001 Vojtech Pavlik - * Copyright (c) 2006-2010 Jiri Kosina - * - * HID to Linux Input mapping - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#include -#include -#include - -#include -#include - -#include "hid-ids.h" - -#define unk KEY_UNKNOWN - -static const unsigned char hid_keyboard[256] = { - 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, - 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, - 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, - 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, - 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, - 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, - 115,114,unk,unk,unk,121,unk, 89, 93,124, 92, 94, 95,unk,unk,unk, - 122,123, 90, 91, 85,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,179,180,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk, - unk,unk,unk,unk,unk,unk,unk,unk,111,unk,unk,unk,unk,unk,unk,unk, - 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, - 150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk -}; - -static const struct { - __s32 x; - __s32 y; -} hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; - -#define map_abs(c) hid_map_usage(hidinput, usage, &bit, &max, EV_ABS, (c)) -#define map_rel(c) hid_map_usage(hidinput, usage, &bit, &max, EV_REL, (c)) -#define map_key(c) hid_map_usage(hidinput, usage, &bit, &max, EV_KEY, (c)) -#define map_led(c) hid_map_usage(hidinput, usage, &bit, &max, EV_LED, (c)) - -#define map_abs_clear(c) hid_map_usage_clear(hidinput, usage, &bit, \ - &max, EV_ABS, (c)) -#define map_key_clear(c) hid_map_usage_clear(hidinput, usage, &bit, \ - &max, EV_KEY, (c)) - -static bool match_scancode(struct hid_usage *usage, - unsigned int cur_idx, unsigned int scancode) -{ - return (usage->hid & (HID_USAGE_PAGE | HID_USAGE)) == scancode; -} - -static bool match_keycode(struct hid_usage *usage, - unsigned int cur_idx, unsigned int keycode) -{ - /* - * We should exclude unmapped usages when doing lookup by keycode. - */ - return (usage->type == EV_KEY && usage->code == keycode); -} - -static bool match_index(struct hid_usage *usage, - unsigned int cur_idx, unsigned int idx) -{ - return cur_idx == idx; -} - -typedef bool (*hid_usage_cmp_t)(struct hid_usage *usage, - unsigned int cur_idx, unsigned int val); - -static struct hid_usage *hidinput_find_key(struct hid_device *hid, - hid_usage_cmp_t match, - unsigned int value, - unsigned int *usage_idx) -{ - unsigned int i, j, k, cur_idx = 0; - struct hid_report *report; - struct hid_usage *usage; - - for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { - list_for_each_entry(report, &hid->report_enum[k].report_list, list) { - for (i = 0; i < report->maxfield; i++) { - for (j = 0; j < report->field[i]->maxusage; j++) { - usage = report->field[i]->usage + j; - if (usage->type == EV_KEY || usage->type == 0) { - if (match(usage, cur_idx, value)) { - if (usage_idx) - *usage_idx = cur_idx; - return usage; - } - cur_idx++; - } - } - } - } - } - return NULL; -} - -static struct hid_usage *hidinput_locate_usage(struct hid_device *hid, - const struct input_keymap_entry *ke, - unsigned int *index) -{ - struct hid_usage *usage; - unsigned int scancode; - - if (ke->flags & INPUT_KEYMAP_BY_INDEX) - usage = hidinput_find_key(hid, match_index, ke->index, index); - else if (input_scancode_to_scalar(ke, &scancode) == 0) - usage = hidinput_find_key(hid, match_scancode, scancode, index); - else - usage = NULL; - - return usage; -} - -static int hidinput_getkeycode(struct input_dev *dev, - struct input_keymap_entry *ke) -{ - struct hid_device *hid = input_get_drvdata(dev); - struct hid_usage *usage; - unsigned int scancode, index; - - usage = hidinput_locate_usage(hid, ke, &index); - if (usage) { - ke->keycode = usage->type == EV_KEY ? - usage->code : KEY_RESERVED; - ke->index = index; - scancode = usage->hid & (HID_USAGE_PAGE | HID_USAGE); - ke->len = sizeof(scancode); - memcpy(ke->scancode, &scancode, sizeof(scancode)); - return 0; - } - - return -EINVAL; -} - -static int hidinput_setkeycode(struct input_dev *dev, - const struct input_keymap_entry *ke, - unsigned int *old_keycode) -{ - struct hid_device *hid = input_get_drvdata(dev); - struct hid_usage *usage; - - usage = hidinput_locate_usage(hid, ke, NULL); - if (usage) { - *old_keycode = usage->type == EV_KEY ? - usage->code : KEY_RESERVED; - usage->code = ke->keycode; - - clear_bit(*old_keycode, dev->keybit); - set_bit(usage->code, dev->keybit); - dbg_hid("Assigned keycode %d to HID usage code %x\n", - usage->code, usage->hid); - - /* - * Set the keybit for the old keycode if the old keycode is used - * by another key - */ - if (hidinput_find_key(hid, match_keycode, *old_keycode, NULL)) - set_bit(*old_keycode, dev->keybit); - - return 0; - } - - return -EINVAL; -} - - -/** - * hidinput_calc_abs_res - calculate an absolute axis resolution - * @field: the HID report field to calculate resolution for - * @code: axis code - * - * The formula is: - * (logical_maximum - logical_minimum) - * resolution = ---------------------------------------------------------- - * (physical_maximum - physical_minimum) * 10 ^ unit_exponent - * - * as seen in the HID specification v1.11 6.2.2.7 Global Items. - * - * Only exponent 1 length units are processed. Centimeters and inches are - * converted to millimeters. Degrees are converted to radians. - */ -__s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code) -{ - __s32 unit_exponent = field->unit_exponent; - __s32 logical_extents = field->logical_maximum - - field->logical_minimum; - __s32 physical_extents = field->physical_maximum - - field->physical_minimum; - __s32 prev; - - /* Check if the extents are sane */ - if (logical_extents <= 0 || physical_extents <= 0) - return 0; - - /* - * Verify and convert units. - * See HID specification v1.11 6.2.2.7 Global Items for unit decoding - */ - switch (code) { - case ABS_X: - case ABS_Y: - case ABS_Z: - case ABS_MT_POSITION_X: - case ABS_MT_POSITION_Y: - case ABS_MT_TOOL_X: - case ABS_MT_TOOL_Y: - case ABS_MT_TOUCH_MAJOR: - case ABS_MT_TOUCH_MINOR: - if (field->unit == 0x11) { /* If centimeters */ - /* Convert to millimeters */ - unit_exponent += 1; - } else if (field->unit == 0x13) { /* If inches */ - /* Convert to millimeters */ - prev = physical_extents; - physical_extents *= 254; - if (physical_extents < prev) - return 0; - unit_exponent -= 1; - } else { - return 0; - } - break; - - case ABS_RX: - case ABS_RY: - case ABS_RZ: - case ABS_TILT_X: - case ABS_TILT_Y: - if (field->unit == 0x14) { /* If degrees */ - /* Convert to radians */ - prev = logical_extents; - logical_extents *= 573; - if (logical_extents < prev) - return 0; - unit_exponent += 1; - } else if (field->unit != 0x12) { /* If not radians */ - return 0; - } - break; - - default: - return 0; - } - - /* Apply negative unit exponent */ - for (; unit_exponent < 0; unit_exponent++) { - prev = logical_extents; - logical_extents *= 10; - if (logical_extents < prev) - return 0; - } - /* Apply positive unit exponent */ - for (; unit_exponent > 0; unit_exponent--) { - prev = physical_extents; - physical_extents *= 10; - if (physical_extents < prev) - return 0; - } - - /* Calculate resolution */ - return DIV_ROUND_CLOSEST(logical_extents, physical_extents); -} -EXPORT_SYMBOL_GPL(hidinput_calc_abs_res); - -#ifdef CONFIG_HID_BATTERY_STRENGTH -static enum power_supply_property hidinput_battery_props[] = { - POWER_SUPPLY_PROP_PRESENT, - POWER_SUPPLY_PROP_ONLINE, - POWER_SUPPLY_PROP_CAPACITY, - POWER_SUPPLY_PROP_MODEL_NAME, - POWER_SUPPLY_PROP_STATUS, - POWER_SUPPLY_PROP_SCOPE, -}; - -#define HID_BATTERY_QUIRK_PERCENT (1 << 0) /* always reports percent */ -#define HID_BATTERY_QUIRK_FEATURE (1 << 1) /* ask for feature report */ -#define HID_BATTERY_QUIRK_IGNORE (1 << 2) /* completely ignore the battery */ - -static const struct hid_device_id hid_battery_quirks[] = { - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, - USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO), - HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, - USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI), - HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, - USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI), - HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, - USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO), - HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, - USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI), - HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, - USB_DEVICE_ID_ELECOM_BM084), - HID_BATTERY_QUIRK_IGNORE }, - {} -}; - -static unsigned find_battery_quirk(struct hid_device *hdev) -{ - unsigned quirks = 0; - const struct hid_device_id *match; - - match = hid_match_id(hdev, hid_battery_quirks); - if (match != NULL) - quirks = match->driver_data; - - return quirks; -} - -static int hidinput_get_battery_property(struct power_supply *psy, - enum power_supply_property prop, - union power_supply_propval *val) -{ - struct hid_device *dev = power_supply_get_drvdata(psy); - int ret = 0; - __u8 *buf; - - switch (prop) { - case POWER_SUPPLY_PROP_PRESENT: - case POWER_SUPPLY_PROP_ONLINE: - val->intval = 1; - break; - - case POWER_SUPPLY_PROP_CAPACITY: - - buf = kmalloc(2 * sizeof(__u8), GFP_KERNEL); - if (!buf) { - ret = -ENOMEM; - break; - } - ret = hid_hw_raw_request(dev, dev->battery_report_id, buf, 2, - dev->battery_report_type, - HID_REQ_GET_REPORT); - - if (ret != 2) { - ret = -ENODATA; - kfree(buf); - break; - } - ret = 0; - - if (dev->battery_min < dev->battery_max && - buf[1] >= dev->battery_min && - buf[1] <= dev->battery_max) - val->intval = (100 * (buf[1] - dev->battery_min)) / - (dev->battery_max - dev->battery_min); - kfree(buf); - break; - - case POWER_SUPPLY_PROP_MODEL_NAME: - val->strval = dev->name; - break; - - case POWER_SUPPLY_PROP_STATUS: - val->intval = POWER_SUPPLY_STATUS_DISCHARGING; - break; - - case POWER_SUPPLY_PROP_SCOPE: - val->intval = POWER_SUPPLY_SCOPE_DEVICE; - break; - - default: - ret = -EINVAL; - break; - } - - return ret; -} - -static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field) -{ - struct power_supply_desc *psy_desc = NULL; - struct power_supply_config psy_cfg = { .drv_data = dev, }; - unsigned quirks; - s32 min, max; - - if (field->usage->hid != HID_DC_BATTERYSTRENGTH) - return false; /* no match */ - - if (dev->battery != NULL) - goto out; /* already initialized? */ - - quirks = find_battery_quirk(dev); - - hid_dbg(dev, "device %x:%x:%x %d quirks %d\n", - dev->bus, dev->vendor, dev->product, dev->version, quirks); - - if (quirks & HID_BATTERY_QUIRK_IGNORE) - goto out; - - psy_desc = kzalloc(sizeof(*psy_desc), GFP_KERNEL); - if (psy_desc == NULL) - goto out; - - psy_desc->name = kasprintf(GFP_KERNEL, "hid-%s-battery", dev->uniq); - if (psy_desc->name == NULL) { - kfree(psy_desc); - goto out; - } - - psy_desc->type = POWER_SUPPLY_TYPE_BATTERY; - psy_desc->properties = hidinput_battery_props; - psy_desc->num_properties = ARRAY_SIZE(hidinput_battery_props); - psy_desc->use_for_apm = 0; - psy_desc->get_property = hidinput_get_battery_property; - - min = field->logical_minimum; - max = field->logical_maximum; - - if (quirks & HID_BATTERY_QUIRK_PERCENT) { - min = 0; - max = 100; - } - - if (quirks & HID_BATTERY_QUIRK_FEATURE) - report_type = HID_FEATURE_REPORT; - - dev->battery_min = min; - dev->battery_max = max; - dev->battery_report_type = report_type; - dev->battery_report_id = field->report->id; - - dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg); - if (IS_ERR(dev->battery)) { - hid_warn(dev, "can't register power supply: %ld\n", - PTR_ERR(dev->battery)); - kfree(psy_desc->name); - kfree(psy_desc); - dev->battery = NULL; - } else { - power_supply_powers(dev->battery, &dev->dev); - } - -out: - return true; -} - -static void hidinput_cleanup_battery(struct hid_device *dev) -{ - const struct power_supply_desc *psy_desc; - - if (!dev->battery) - return; - - psy_desc = dev->battery->desc; - power_supply_unregister(dev->battery); - kfree(psy_desc->name); - kfree(psy_desc); - dev->battery = NULL; -} -#else /* !CONFIG_HID_BATTERY_STRENGTH */ -static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type, - struct hid_field *field) -{ - return false; -} - -static void hidinput_cleanup_battery(struct hid_device *dev) -{ -} -#endif /* CONFIG_HID_BATTERY_STRENGTH */ - -static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, - struct hid_usage *usage) -{ - struct input_dev *input = hidinput->input; - struct hid_device *device = input_get_drvdata(input); - int max = 0, code; - unsigned long *bit = NULL; - - field->hidinput = hidinput; - - if (field->flags & HID_MAIN_ITEM_CONSTANT) - goto ignore; - - /* Ignore if report count is out of bounds. */ - if (field->report_count < 1) - goto ignore; - - /* only LED usages are supported in output fields */ - if (field->report_type == HID_OUTPUT_REPORT && - (usage->hid & HID_USAGE_PAGE) != HID_UP_LED) { - goto ignore; - } - - if (device->driver->input_mapping) { - int ret = device->driver->input_mapping(device, hidinput, field, - usage, &bit, &max); - if (ret > 0) - goto mapped; - if (ret < 0) - goto ignore; - } - - switch (usage->hid & HID_USAGE_PAGE) { - case HID_UP_UNDEFINED: - goto ignore; - - case HID_UP_KEYBOARD: - set_bit(EV_REP, input->evbit); - - if ((usage->hid & HID_USAGE) < 256) { - if (!hid_keyboard[usage->hid & HID_USAGE]) goto ignore; - map_key_clear(hid_keyboard[usage->hid & HID_USAGE]); - } else - map_key(KEY_UNKNOWN); - - break; - - case HID_UP_BUTTON: - code = ((usage->hid - 1) & HID_USAGE); - - switch (field->application) { - case HID_GD_MOUSE: - case HID_GD_POINTER: code += BTN_MOUSE; break; - case HID_GD_JOYSTICK: - if (code <= 0xf) - code += BTN_JOYSTICK; - else - code += BTN_TRIGGER_HAPPY - 0x10; - break; - case HID_GD_GAMEPAD: - if (code <= 0xf) - code += BTN_GAMEPAD; - else - code += BTN_TRIGGER_HAPPY - 0x10; - break; - default: - switch (field->physical) { - case HID_GD_MOUSE: - case HID_GD_POINTER: code += BTN_MOUSE; break; - case HID_GD_JOYSTICK: code += BTN_JOYSTICK; break; - case HID_GD_GAMEPAD: code += BTN_GAMEPAD; break; - default: code += BTN_MISC; - } - } - - map_key(code); - break; - - case HID_UP_SIMULATION: - switch (usage->hid & 0xffff) { - case 0xba: map_abs(ABS_RUDDER); break; - case 0xbb: map_abs(ABS_THROTTLE); break; - case 0xc4: map_abs(ABS_GAS); break; - case 0xc5: map_abs(ABS_BRAKE); break; - case 0xc8: map_abs(ABS_WHEEL); break; - default: goto ignore; - } - break; - - case HID_UP_GENDESK: - if ((usage->hid & 0xf0) == 0x80) { /* SystemControl */ - switch (usage->hid & 0xf) { - case 0x1: map_key_clear(KEY_POWER); break; - case 0x2: map_key_clear(KEY_SLEEP); break; - case 0x3: map_key_clear(KEY_WAKEUP); break; - case 0x4: map_key_clear(KEY_CONTEXT_MENU); break; - case 0x5: map_key_clear(KEY_MENU); break; - case 0x6: map_key_clear(KEY_PROG1); break; - case 0x7: map_key_clear(KEY_HELP); break; - case 0x8: map_key_clear(KEY_EXIT); break; - case 0x9: map_key_clear(KEY_SELECT); break; - case 0xa: map_key_clear(KEY_RIGHT); break; - case 0xb: map_key_clear(KEY_LEFT); break; - case 0xc: map_key_clear(KEY_UP); break; - case 0xd: map_key_clear(KEY_DOWN); break; - case 0xe: map_key_clear(KEY_POWER2); break; - case 0xf: map_key_clear(KEY_RESTART); break; - default: goto unknown; - } - break; - } - - /* - * Some lazy vendors declare 255 usages for System Control, - * leading to the creation of ABS_X|Y axis and too many others. - * It wouldn't be a problem if joydev doesn't consider the - * device as a joystick then. - */ - if (field->application == HID_GD_SYSTEM_CONTROL) - goto ignore; - - if ((usage->hid & 0xf0) == 0x90) { /* D-pad */ - switch (usage->hid) { - case HID_GD_UP: usage->hat_dir = 1; break; - case HID_GD_DOWN: usage->hat_dir = 5; break; - case HID_GD_RIGHT: usage->hat_dir = 3; break; - case HID_GD_LEFT: usage->hat_dir = 7; break; - default: goto unknown; - } - if (field->dpad) { - map_abs(field->dpad); - goto ignore; - } - map_abs(ABS_HAT0X); - break; - } - - switch (usage->hid) { - /* These usage IDs map directly to the usage codes. */ - case HID_GD_X: case HID_GD_Y: case HID_GD_Z: - case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ: - if (field->flags & HID_MAIN_ITEM_RELATIVE) - map_rel(usage->hid & 0xf); - else - map_abs_clear(usage->hid & 0xf); - break; - - case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL: - if (field->flags & HID_MAIN_ITEM_RELATIVE) - map_rel(usage->hid & 0xf); - else - map_abs(usage->hid & 0xf); - break; - - case HID_GD_HATSWITCH: - usage->hat_min = field->logical_minimum; - usage->hat_max = field->logical_maximum; - map_abs(ABS_HAT0X); - break; - - case HID_GD_START: map_key_clear(BTN_START); break; - case HID_GD_SELECT: map_key_clear(BTN_SELECT); break; - - default: goto unknown; - } - - break; - - case HID_UP_LED: - switch (usage->hid & 0xffff) { /* HID-Value: */ - case 0x01: map_led (LED_NUML); break; /* "Num Lock" */ - case 0x02: map_led (LED_CAPSL); break; /* "Caps Lock" */ - case 0x03: map_led (LED_SCROLLL); break; /* "Scroll Lock" */ - case 0x04: map_led (LED_COMPOSE); break; /* "Compose" */ - case 0x05: map_led (LED_KANA); break; /* "Kana" */ - case 0x27: map_led (LED_SLEEP); break; /* "Stand-By" */ - case 0x4c: map_led (LED_SUSPEND); break; /* "System Suspend" */ - case 0x09: map_led (LED_MUTE); break; /* "Mute" */ - case 0x4b: map_led (LED_MISC); break; /* "Generic Indicator" */ - case 0x19: map_led (LED_MAIL); break; /* "Message Waiting" */ - case 0x4d: map_led (LED_CHARGING); break; /* "External Power Connected" */ - - default: goto ignore; - } - break; - - case HID_UP_DIGITIZER: - switch (usage->hid & 0xff) { - case 0x00: /* Undefined */ - goto ignore; - - case 0x30: /* TipPressure */ - if (!test_bit(BTN_TOUCH, input->keybit)) { - device->quirks |= HID_QUIRK_NOTOUCH; - set_bit(EV_KEY, input->evbit); - set_bit(BTN_TOUCH, input->keybit); - } - map_abs_clear(ABS_PRESSURE); - break; - - case 0x32: /* InRange */ - switch (field->physical & 0xff) { - case 0x21: map_key(BTN_TOOL_MOUSE); break; - case 0x22: map_key(BTN_TOOL_FINGER); break; - default: map_key(BTN_TOOL_PEN); break; - } - break; - - case 0x3c: /* Invert */ - map_key_clear(BTN_TOOL_RUBBER); - break; - - case 0x3d: /* X Tilt */ - map_abs_clear(ABS_TILT_X); - break; - - case 0x3e: /* Y Tilt */ - map_abs_clear(ABS_TILT_Y); - break; - - case 0x33: /* Touch */ - case 0x42: /* TipSwitch */ - case 0x43: /* TipSwitch2 */ - device->quirks &= ~HID_QUIRK_NOTOUCH; - map_key_clear(BTN_TOUCH); - break; - - case 0x44: /* BarrelSwitch */ - map_key_clear(BTN_STYLUS); - break; - - case 0x46: /* TabletPick */ - case 0x5a: /* SecondaryBarrelSwitch */ - map_key_clear(BTN_STYLUS2); - break; - - case 0x5b: /* TransducerSerialNumber */ - usage->type = EV_MSC; - usage->code = MSC_SERIAL; - bit = input->mscbit; - max = MSC_MAX; - break; - - default: goto unknown; - } - break; - - case HID_UP_TELEPHONY: - switch (usage->hid & HID_USAGE) { - case 0x2f: map_key_clear(KEY_MICMUTE); break; - case 0xb0: map_key_clear(KEY_NUMERIC_0); break; - case 0xb1: map_key_clear(KEY_NUMERIC_1); break; - case 0xb2: map_key_clear(KEY_NUMERIC_2); break; - case 0xb3: map_key_clear(KEY_NUMERIC_3); break; - case 0xb4: map_key_clear(KEY_NUMERIC_4); break; - case 0xb5: map_key_clear(KEY_NUMERIC_5); break; - case 0xb6: map_key_clear(KEY_NUMERIC_6); break; - case 0xb7: map_key_clear(KEY_NUMERIC_7); break; - case 0xb8: map_key_clear(KEY_NUMERIC_8); break; - case 0xb9: map_key_clear(KEY_NUMERIC_9); break; - case 0xba: map_key_clear(KEY_NUMERIC_STAR); break; - case 0xbb: map_key_clear(KEY_NUMERIC_POUND); break; - case 0xbc: map_key_clear(KEY_NUMERIC_A); break; - case 0xbd: map_key_clear(KEY_NUMERIC_B); break; - case 0xbe: map_key_clear(KEY_NUMERIC_C); break; - case 0xbf: map_key_clear(KEY_NUMERIC_D); break; - default: goto ignore; - } - break; - - case HID_UP_CONSUMER: /* USB HUT v1.12, pages 75-84 */ - switch (usage->hid & HID_USAGE) { - case 0x000: goto ignore; - case 0x030: map_key_clear(KEY_POWER); break; - case 0x031: map_key_clear(KEY_RESTART); break; - case 0x032: map_key_clear(KEY_SLEEP); break; - case 0x034: map_key_clear(KEY_SLEEP); break; - case 0x035: map_key_clear(KEY_KBDILLUMTOGGLE); break; - case 0x036: map_key_clear(BTN_MISC); break; - - case 0x040: map_key_clear(KEY_MENU); break; /* Menu */ - case 0x041: map_key_clear(KEY_SELECT); break; /* Menu Pick */ - case 0x042: map_key_clear(KEY_UP); break; /* Menu Up */ - case 0x043: map_key_clear(KEY_DOWN); break; /* Menu Down */ - case 0x044: map_key_clear(KEY_LEFT); break; /* Menu Left */ - case 0x045: map_key_clear(KEY_RIGHT); break; /* Menu Right */ - case 0x046: map_key_clear(KEY_ESC); break; /* Menu Escape */ - case 0x047: map_key_clear(KEY_KPPLUS); break; /* Menu Value Increase */ - case 0x048: map_key_clear(KEY_KPMINUS); break; /* Menu Value Decrease */ - - case 0x060: map_key_clear(KEY_INFO); break; /* Data On Screen */ - case 0x061: map_key_clear(KEY_SUBTITLE); break; /* Closed Caption */ - case 0x063: map_key_clear(KEY_VCR); break; /* VCR/TV */ - case 0x065: map_key_clear(KEY_CAMERA); break; /* Snapshot */ - case 0x069: map_key_clear(KEY_RED); break; - case 0x06a: map_key_clear(KEY_GREEN); break; - case 0x06b: map_key_clear(KEY_BLUE); break; - case 0x06c: map_key_clear(KEY_YELLOW); break; - case 0x06d: map_key_clear(KEY_ZOOM); break; - - case 0x06f: map_key_clear(KEY_BRIGHTNESSUP); break; - case 0x070: map_key_clear(KEY_BRIGHTNESSDOWN); break; - case 0x072: map_key_clear(KEY_BRIGHTNESS_TOGGLE); break; - case 0x073: map_key_clear(KEY_BRIGHTNESS_MIN); break; - case 0x074: map_key_clear(KEY_BRIGHTNESS_MAX); break; - case 0x075: map_key_clear(KEY_BRIGHTNESS_AUTO); break; - - case 0x082: map_key_clear(KEY_VIDEO_NEXT); break; - case 0x083: map_key_clear(KEY_LAST); break; - case 0x084: map_key_clear(KEY_ENTER); break; - case 0x088: map_key_clear(KEY_PC); break; - case 0x089: map_key_clear(KEY_TV); break; - case 0x08a: map_key_clear(KEY_WWW); break; - case 0x08b: map_key_clear(KEY_DVD); break; - case 0x08c: map_key_clear(KEY_PHONE); break; - case 0x08d: map_key_clear(KEY_PROGRAM); break; - case 0x08e: map_key_clear(KEY_VIDEOPHONE); break; - case 0x08f: map_key_clear(KEY_GAMES); break; - case 0x090: map_key_clear(KEY_MEMO); break; - case 0x091: map_key_clear(KEY_CD); break; - case 0x092: map_key_clear(KEY_VCR); break; - case 0x093: map_key_clear(KEY_TUNER); break; - case 0x094: map_key_clear(KEY_EXIT); break; - case 0x095: map_key_clear(KEY_HELP); break; - case 0x096: map_key_clear(KEY_TAPE); break; - case 0x097: map_key_clear(KEY_TV2); break; - case 0x098: map_key_clear(KEY_SAT); break; - case 0x09a: map_key_clear(KEY_PVR); break; - - case 0x09c: map_key_clear(KEY_CHANNELUP); break; - case 0x09d: map_key_clear(KEY_CHANNELDOWN); break; - case 0x0a0: map_key_clear(KEY_VCR2); break; - - case 0x0b0: map_key_clear(KEY_PLAY); break; - case 0x0b1: map_key_clear(KEY_PAUSE); break; - case 0x0b2: map_key_clear(KEY_RECORD); break; - case 0x0b3: map_key_clear(KEY_FASTFORWARD); break; - case 0x0b4: map_key_clear(KEY_REWIND); break; - case 0x0b5: map_key_clear(KEY_NEXTSONG); break; - case 0x0b6: map_key_clear(KEY_PREVIOUSSONG); break; - case 0x0b7: map_key_clear(KEY_STOPCD); break; - case 0x0b8: map_key_clear(KEY_EJECTCD); break; - case 0x0bc: map_key_clear(KEY_MEDIA_REPEAT); break; - case 0x0b9: map_key_clear(KEY_SHUFFLE); break; - case 0x0bf: map_key_clear(KEY_SLOW); break; - - case 0x0cd: map_key_clear(KEY_PLAYPAUSE); break; - case 0x0cf: map_key_clear(KEY_VOICECOMMAND); break; - case 0x0e0: map_abs_clear(ABS_VOLUME); break; - case 0x0e2: map_key_clear(KEY_MUTE); break; - case 0x0e5: map_key_clear(KEY_BASSBOOST); break; - case 0x0e9: map_key_clear(KEY_VOLUMEUP); break; - case 0x0ea: map_key_clear(KEY_VOLUMEDOWN); break; - case 0x0f5: map_key_clear(KEY_SLOW); break; - - case 0x181: map_key_clear(KEY_BUTTONCONFIG); break; - case 0x182: map_key_clear(KEY_BOOKMARKS); break; - case 0x183: map_key_clear(KEY_CONFIG); break; - case 0x184: map_key_clear(KEY_WORDPROCESSOR); break; - case 0x185: map_key_clear(KEY_EDITOR); break; - case 0x186: map_key_clear(KEY_SPREADSHEET); break; - case 0x187: map_key_clear(KEY_GRAPHICSEDITOR); break; - case 0x188: map_key_clear(KEY_PRESENTATION); break; - case 0x189: map_key_clear(KEY_DATABASE); break; - case 0x18a: map_key_clear(KEY_MAIL); break; - case 0x18b: map_key_clear(KEY_NEWS); break; - case 0x18c: map_key_clear(KEY_VOICEMAIL); break; - case 0x18d: map_key_clear(KEY_ADDRESSBOOK); break; - case 0x18e: map_key_clear(KEY_CALENDAR); break; - case 0x18f: map_key_clear(KEY_TASKMANAGER); break; - case 0x190: map_key_clear(KEY_JOURNAL); break; - case 0x191: map_key_clear(KEY_FINANCE); break; - case 0x192: map_key_clear(KEY_CALC); break; - case 0x193: map_key_clear(KEY_PLAYER); break; - case 0x194: map_key_clear(KEY_FILE); break; - case 0x196: map_key_clear(KEY_WWW); break; - case 0x199: map_key_clear(KEY_CHAT); break; - case 0x19c: map_key_clear(KEY_LOGOFF); break; - case 0x19e: map_key_clear(KEY_COFFEE); break; - case 0x19f: map_key_clear(KEY_CONTROLPANEL); break; - case 0x1a2: map_key_clear(KEY_APPSELECT); break; - case 0x1a3: map_key_clear(KEY_NEXT); break; - case 0x1a4: map_key_clear(KEY_PREVIOUS); break; - case 0x1a6: map_key_clear(KEY_HELP); break; - case 0x1a7: map_key_clear(KEY_DOCUMENTS); break; - case 0x1ab: map_key_clear(KEY_SPELLCHECK); break; - case 0x1ae: map_key_clear(KEY_KEYBOARD); break; - case 0x1b1: map_key_clear(KEY_SCREENSAVER); break; - case 0x1b4: map_key_clear(KEY_FILE); break; - case 0x1b6: map_key_clear(KEY_IMAGES); break; - case 0x1b7: map_key_clear(KEY_AUDIO); break; - case 0x1b8: map_key_clear(KEY_VIDEO); break; - case 0x1bc: map_key_clear(KEY_MESSENGER); break; - case 0x1bd: map_key_clear(KEY_INFO); break; - case 0x201: map_key_clear(KEY_NEW); break; - case 0x202: map_key_clear(KEY_OPEN); break; - case 0x203: map_key_clear(KEY_CLOSE); break; - case 0x204: map_key_clear(KEY_EXIT); break; - case 0x207: map_key_clear(KEY_SAVE); break; - case 0x208: map_key_clear(KEY_PRINT); break; - case 0x209: map_key_clear(KEY_PROPS); break; - case 0x21a: map_key_clear(KEY_UNDO); break; - case 0x21b: map_key_clear(KEY_COPY); break; - case 0x21c: map_key_clear(KEY_CUT); break; - case 0x21d: map_key_clear(KEY_PASTE); break; - case 0x21f: map_key_clear(KEY_FIND); break; - case 0x221: map_key_clear(KEY_SEARCH); break; - case 0x222: map_key_clear(KEY_GOTO); break; - case 0x223: map_key_clear(KEY_HOMEPAGE); break; - case 0x224: map_key_clear(KEY_BACK); break; - case 0x225: map_key_clear(KEY_FORWARD); break; - case 0x226: map_key_clear(KEY_STOP); break; - case 0x227: map_key_clear(KEY_REFRESH); break; - case 0x22a: map_key_clear(KEY_BOOKMARKS); break; - case 0x22d: map_key_clear(KEY_ZOOMIN); break; - case 0x22e: map_key_clear(KEY_ZOOMOUT); break; - case 0x22f: map_key_clear(KEY_ZOOMRESET); break; - case 0x233: map_key_clear(KEY_SCROLLUP); break; - case 0x234: map_key_clear(KEY_SCROLLDOWN); break; - case 0x238: map_rel(REL_HWHEEL); break; - case 0x23d: map_key_clear(KEY_EDIT); break; - case 0x25f: map_key_clear(KEY_CANCEL); break; - case 0x269: map_key_clear(KEY_INSERT); break; - case 0x26a: map_key_clear(KEY_DELETE); break; - case 0x279: map_key_clear(KEY_REDO); break; - - case 0x289: map_key_clear(KEY_REPLY); break; - case 0x28b: map_key_clear(KEY_FORWARDMAIL); break; - case 0x28c: map_key_clear(KEY_SEND); break; - - case 0x2c7: map_key_clear(KEY_KBDINPUTASSIST_PREV); break; - case 0x2c8: map_key_clear(KEY_KBDINPUTASSIST_NEXT); break; - case 0x2c9: map_key_clear(KEY_KBDINPUTASSIST_PREVGROUP); break; - case 0x2ca: map_key_clear(KEY_KBDINPUTASSIST_NEXTGROUP); break; - case 0x2cb: map_key_clear(KEY_KBDINPUTASSIST_ACCEPT); break; - case 0x2cc: map_key_clear(KEY_KBDINPUTASSIST_CANCEL); break; - - default: map_key_clear(KEY_UNKNOWN); - } - break; - - case HID_UP_GENDEVCTRLS: - if (hidinput_setup_battery(device, HID_INPUT_REPORT, field)) - goto ignore; - else - goto unknown; - break; - - case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */ - set_bit(EV_REP, input->evbit); - switch (usage->hid & HID_USAGE) { - case 0x021: map_key_clear(KEY_PRINT); break; - case 0x070: map_key_clear(KEY_HP); break; - case 0x071: map_key_clear(KEY_CAMERA); break; - case 0x072: map_key_clear(KEY_SOUND); break; - case 0x073: map_key_clear(KEY_QUESTION); break; - case 0x080: map_key_clear(KEY_EMAIL); break; - case 0x081: map_key_clear(KEY_CHAT); break; - case 0x082: map_key_clear(KEY_SEARCH); break; - case 0x083: map_key_clear(KEY_CONNECT); break; - case 0x084: map_key_clear(KEY_FINANCE); break; - case 0x085: map_key_clear(KEY_SPORT); break; - case 0x086: map_key_clear(KEY_SHOP); break; - default: goto ignore; - } - break; - - case HID_UP_HPVENDOR2: - set_bit(EV_REP, input->evbit); - switch (usage->hid & HID_USAGE) { - case 0x001: map_key_clear(KEY_MICMUTE); break; - case 0x003: map_key_clear(KEY_BRIGHTNESSDOWN); break; - case 0x004: map_key_clear(KEY_BRIGHTNESSUP); break; - default: goto ignore; - } - break; - - case HID_UP_MSVENDOR: - goto ignore; - - case HID_UP_CUSTOM: /* Reported on Logitech and Apple USB keyboards */ - set_bit(EV_REP, input->evbit); - goto ignore; - - case HID_UP_LOGIVENDOR: - /* intentional fallback */ - case HID_UP_LOGIVENDOR2: - /* intentional fallback */ - case HID_UP_LOGIVENDOR3: - goto ignore; - - case HID_UP_PID: - switch (usage->hid & HID_USAGE) { - case 0xa4: map_key_clear(BTN_DEAD); break; - default: goto ignore; - } - break; - - default: - unknown: - if (field->report_size == 1) { - if (field->report->type == HID_OUTPUT_REPORT) { - map_led(LED_MISC); - break; - } - map_key(BTN_MISC); - break; - } - if (field->flags & HID_MAIN_ITEM_RELATIVE) { - map_rel(REL_MISC); - break; - } - map_abs(ABS_MISC); - break; - } - -mapped: - if (device->driver->input_mapped && device->driver->input_mapped(device, - hidinput, field, usage, &bit, &max) < 0) - goto ignore; - - set_bit(usage->type, input->evbit); - - while (usage->code <= max && test_and_set_bit(usage->code, bit)) - usage->code = find_next_zero_bit(bit, max + 1, usage->code); - - if (usage->code > max) - goto ignore; - - - if (usage->type == EV_ABS) { - - int a = field->logical_minimum; - int b = field->logical_maximum; - - if ((device->quirks & HID_QUIRK_BADPAD) && (usage->code == ABS_X || usage->code == ABS_Y)) { - a = field->logical_minimum = 0; - b = field->logical_maximum = 255; - } - - if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK) - input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4); - else input_set_abs_params(input, usage->code, a, b, 0, 0); - - input_abs_set_res(input, usage->code, - hidinput_calc_abs_res(field, usage->code)); - - /* use a larger default input buffer for MT devices */ - if (usage->code == ABS_MT_POSITION_X && input->hint_events_per_packet == 0) - input_set_events_per_packet(input, 60); - } - - if (usage->type == EV_ABS && - (usage->hat_min < usage->hat_max || usage->hat_dir)) { - int i; - for (i = usage->code; i < usage->code + 2 && i <= max; i++) { - input_set_abs_params(input, i, -1, 1, 0, 0); - set_bit(i, input->absbit); - } - if (usage->hat_dir && !field->dpad) - field->dpad = usage->code; - } - - /* for those devices which produce Consumer volume usage as relative, - * we emulate pressing volumeup/volumedown appropriate number of times - * in hidinput_hid_event() - */ - if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) && - (usage->code == ABS_VOLUME)) { - set_bit(KEY_VOLUMEUP, input->keybit); - set_bit(KEY_VOLUMEDOWN, input->keybit); - } - - if (usage->type == EV_KEY) { - set_bit(EV_MSC, input->evbit); - set_bit(MSC_SCAN, input->mscbit); - } - -ignore: - return; - -} - -void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) -{ - struct input_dev *input; - unsigned *quirks = &hid->quirks; - - if (!field->hidinput) - return; - - input = field->hidinput->input; - - if (!usage->type) - return; - - if (usage->hat_min < usage->hat_max || usage->hat_dir) { - int hat_dir = usage->hat_dir; - if (!hat_dir) - hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1; - if (hat_dir < 0 || hat_dir > 8) hat_dir = 0; - input_event(input, usage->type, usage->code , hid_hat_to_axis[hat_dir].x); - input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y); - return; - } - - if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */ - *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT); - return; - } - - if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */ - if (value) { - input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1); - return; - } - input_event(input, usage->type, usage->code, 0); - input_event(input, usage->type, BTN_TOOL_RUBBER, 0); - return; - } - - if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */ - int a = field->logical_minimum; - int b = field->logical_maximum; - input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3)); - } - - if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */ - dbg_hid("Maximum Effects - %d\n",value); - return; - } - - if (usage->hid == (HID_UP_PID | 0x7fUL)) { - dbg_hid("PID Pool Report\n"); - return; - } - - if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */ - return; - - if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) && - (usage->code == ABS_VOLUME)) { - int count = abs(value); - int direction = value > 0 ? KEY_VOLUMEUP : KEY_VOLUMEDOWN; - int i; - - for (i = 0; i < count; i++) { - input_event(input, EV_KEY, direction, 1); - input_sync(input); - input_event(input, EV_KEY, direction, 0); - input_sync(input); - } - return; - } - - /* - * Ignore out-of-range values as per HID specification, - * section 5.10 and 6.2.25. - * - * The logical_minimum < logical_maximum check is done so that we - * don't unintentionally discard values sent by devices which - * don't specify logical min and max. - */ - if ((field->flags & HID_MAIN_ITEM_VARIABLE) && - (field->logical_minimum < field->logical_maximum) && - (value < field->logical_minimum || - value > field->logical_maximum)) { - dbg_hid("Ignoring out-of-range value %x\n", value); - return; - } - - /* - * Ignore reports for absolute data if the data didn't change. This is - * not only an optimization but also fixes 'dead' key reports. Some - * RollOver implementations for localized keys (like BACKSLASH/PIPE; HID - * 0x31 and 0x32) report multiple keys, even though a localized keyboard - * can only have one of them physically available. The 'dead' keys - * report constant 0. As all map to the same keycode, they'd confuse - * the input layer. If we filter the 'dead' keys on the HID level, we - * skip the keycode translation and only forward real events. - */ - if (!(field->flags & (HID_MAIN_ITEM_RELATIVE | - HID_MAIN_ITEM_BUFFERED_BYTE)) && - (field->flags & HID_MAIN_ITEM_VARIABLE) && - usage->usage_index < field->maxusage && - value == field->value[usage->usage_index]) - return; - - /* report the usage code as scancode if the key status has changed */ - if (usage->type == EV_KEY && - (!test_bit(usage->code, input->key)) == value) - input_event(input, EV_MSC, MSC_SCAN, usage->hid); - - input_event(input, usage->type, usage->code, value); - - if ((field->flags & HID_MAIN_ITEM_RELATIVE) && - usage->type == EV_KEY && value) { - input_sync(input); - input_event(input, usage->type, usage->code, 0); - } -} - -void hidinput_report_event(struct hid_device *hid, struct hid_report *report) -{ - struct hid_input *hidinput; - - if (hid->quirks & HID_QUIRK_NO_INPUT_SYNC) - return; - - list_for_each_entry(hidinput, &hid->inputs, list) - input_sync(hidinput->input); -} -EXPORT_SYMBOL_GPL(hidinput_report_event); - -int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field) -{ - struct hid_report *report; - int i, j; - - list_for_each_entry(report, &hid->report_enum[HID_OUTPUT_REPORT].report_list, list) { - for (i = 0; i < report->maxfield; i++) { - *field = report->field[i]; - for (j = 0; j < (*field)->maxusage; j++) - if ((*field)->usage[j].type == type && (*field)->usage[j].code == code) - return j; - } - } - return -1; -} -EXPORT_SYMBOL_GPL(hidinput_find_field); - -struct hid_field *hidinput_get_led_field(struct hid_device *hid) -{ - struct hid_report *report; - struct hid_field *field; - int i, j; - - list_for_each_entry(report, - &hid->report_enum[HID_OUTPUT_REPORT].report_list, - list) { - for (i = 0; i < report->maxfield; i++) { - field = report->field[i]; - for (j = 0; j < field->maxusage; j++) - if (field->usage[j].type == EV_LED) - return field; - } - } - return NULL; -} -EXPORT_SYMBOL_GPL(hidinput_get_led_field); - -unsigned int hidinput_count_leds(struct hid_device *hid) -{ - struct hid_report *report; - struct hid_field *field; - int i, j; - unsigned int count = 0; - - list_for_each_entry(report, - &hid->report_enum[HID_OUTPUT_REPORT].report_list, - list) { - for (i = 0; i < report->maxfield; i++) { - field = report->field[i]; - for (j = 0; j < field->maxusage; j++) - if (field->usage[j].type == EV_LED && - field->value[j]) - count += 1; - } - } - return count; -} -EXPORT_SYMBOL_GPL(hidinput_count_leds); - -static void hidinput_led_worker(struct work_struct *work) -{ - struct hid_device *hid = container_of(work, struct hid_device, - led_work); - struct hid_field *field; - struct hid_report *report; - int len, ret; - __u8 *buf; - - field = hidinput_get_led_field(hid); - if (!field) - return; - - /* - * field->report is accessed unlocked regarding HID core. So there might - * be another incoming SET-LED request from user-space, which changes - * the LED state while we assemble our outgoing buffer. However, this - * doesn't matter as hid_output_report() correctly converts it into a - * boolean value no matter what information is currently set on the LED - * field (even garbage). So the remote device will always get a valid - * request. - * And in case we send a wrong value, a next led worker is spawned - * for every SET-LED request so the following worker will send the - * correct value, guaranteed! - */ - - report = field->report; - - /* use custom SET_REPORT request if possible (asynchronous) */ - if (hid->ll_driver->request) - return hid->ll_driver->request(hid, report, HID_REQ_SET_REPORT); - - /* fall back to generic raw-output-report */ - len = hid_report_len(report); - buf = hid_alloc_report_buf(report, GFP_KERNEL); - if (!buf) - return; - - hid_output_report(report, buf); - /* synchronous output report */ - ret = hid_hw_output_report(hid, buf, len); - if (ret == -ENOSYS) - hid_hw_raw_request(hid, report->id, buf, len, HID_OUTPUT_REPORT, - HID_REQ_SET_REPORT); - kfree(buf); -} - -static int hidinput_input_event(struct input_dev *dev, unsigned int type, - unsigned int code, int value) -{ - struct hid_device *hid = input_get_drvdata(dev); - struct hid_field *field; - int offset; - - if (type == EV_FF) - return input_ff_event(dev, type, code, value); - - if (type != EV_LED) - return -1; - - if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) { - hid_warn(dev, "event field not found\n"); - return -1; - } - - hid_set_field(field, offset, value); - - schedule_work(&hid->led_work); - return 0; -} - -static int hidinput_open(struct input_dev *dev) -{ - struct hid_device *hid = input_get_drvdata(dev); - - return hid_hw_open(hid); -} - -static void hidinput_close(struct input_dev *dev) -{ - struct hid_device *hid = input_get_drvdata(dev); - - hid_hw_close(hid); -} - -static void report_features(struct hid_device *hid) -{ - struct hid_driver *drv = hid->driver; - struct hid_report_enum *rep_enum; - struct hid_report *rep; - int i, j; - - rep_enum = &hid->report_enum[HID_FEATURE_REPORT]; - list_for_each_entry(rep, &rep_enum->report_list, list) - for (i = 0; i < rep->maxfield; i++) { - /* Ignore if report count is out of bounds. */ - if (rep->field[i]->report_count < 1) - continue; - - for (j = 0; j < rep->field[i]->maxusage; j++) { - /* Verify if Battery Strength feature is available */ - hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]); - - if (drv->feature_mapping) - drv->feature_mapping(hid, rep->field[i], - rep->field[i]->usage + j); - } - } -} - -static struct hid_input *hidinput_allocate(struct hid_device *hid) -{ - struct hid_input *hidinput = kzalloc(sizeof(*hidinput), GFP_KERNEL); - struct input_dev *input_dev = input_allocate_device(); - if (!hidinput || !input_dev) { - kfree(hidinput); - input_free_device(input_dev); - hid_err(hid, "Out of memory during hid input probe\n"); - return NULL; - } - - input_set_drvdata(input_dev, hid); - input_dev->event = hidinput_input_event; - input_dev->open = hidinput_open; - input_dev->close = hidinput_close; - input_dev->setkeycode = hidinput_setkeycode; - input_dev->getkeycode = hidinput_getkeycode; - - input_dev->name = hid->name; - input_dev->phys = hid->phys; - input_dev->uniq = hid->uniq; - input_dev->id.bustype = hid->bus; - input_dev->id.vendor = hid->vendor; - input_dev->id.product = hid->product; - input_dev->id.version = hid->version; - input_dev->dev.parent = &hid->dev; - hidinput->input = input_dev; - list_add_tail(&hidinput->list, &hid->inputs); - - return hidinput; -} - -static bool hidinput_has_been_populated(struct hid_input *hidinput) -{ - int i; - unsigned long r = 0; - - for (i = 0; i < BITS_TO_LONGS(EV_CNT); i++) - r |= hidinput->input->evbit[i]; - - for (i = 0; i < BITS_TO_LONGS(KEY_CNT); i++) - r |= hidinput->input->keybit[i]; - - for (i = 0; i < BITS_TO_LONGS(REL_CNT); i++) - r |= hidinput->input->relbit[i]; - - for (i = 0; i < BITS_TO_LONGS(ABS_CNT); i++) - r |= hidinput->input->absbit[i]; - - for (i = 0; i < BITS_TO_LONGS(MSC_CNT); i++) - r |= hidinput->input->mscbit[i]; - - for (i = 0; i < BITS_TO_LONGS(LED_CNT); i++) - r |= hidinput->input->ledbit[i]; - - for (i = 0; i < BITS_TO_LONGS(SND_CNT); i++) - r |= hidinput->input->sndbit[i]; - - for (i = 0; i < BITS_TO_LONGS(FF_CNT); i++) - r |= hidinput->input->ffbit[i]; - - for (i = 0; i < BITS_TO_LONGS(SW_CNT); i++) - r |= hidinput->input->swbit[i]; - - return !!r; -} - -static void hidinput_cleanup_hidinput(struct hid_device *hid, - struct hid_input *hidinput) -{ - struct hid_report *report; - int i, k; - - list_del(&hidinput->list); - input_free_device(hidinput->input); - - for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { - if (k == HID_OUTPUT_REPORT && - hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS) - continue; - - list_for_each_entry(report, &hid->report_enum[k].report_list, - list) { - - for (i = 0; i < report->maxfield; i++) - if (report->field[i]->hidinput == hidinput) - report->field[i]->hidinput = NULL; - } - } - - kfree(hidinput); -} - -/* - * Register the input device; print a message. - * Configure the input layer interface - * Read all reports and initialize the absolute field values. - */ - -int hidinput_connect(struct hid_device *hid, unsigned int force) -{ - struct hid_driver *drv = hid->driver; - struct hid_report *report; - struct hid_input *hidinput = NULL; - int i, j, k; - - INIT_LIST_HEAD(&hid->inputs); - INIT_WORK(&hid->led_work, hidinput_led_worker); - - if (!force) { - for (i = 0; i < hid->maxcollection; i++) { - struct hid_collection *col = &hid->collection[i]; - if (col->type == HID_COLLECTION_APPLICATION || - col->type == HID_COLLECTION_PHYSICAL) - if (IS_INPUT_APPLICATION(col->usage)) - break; - } - - if (i == hid->maxcollection) - return -1; - } - - report_features(hid); - - for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { - if (k == HID_OUTPUT_REPORT && - hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS) - continue; - - list_for_each_entry(report, &hid->report_enum[k].report_list, list) { - - if (!report->maxfield) - continue; - - if (!hidinput) { - hidinput = hidinput_allocate(hid); - if (!hidinput) - goto out_unwind; - } - - for (i = 0; i < report->maxfield; i++) - for (j = 0; j < report->field[i]->maxusage; j++) - hidinput_configure_usage(hidinput, report->field[i], - report->field[i]->usage + j); - - if ((hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) && - !hidinput_has_been_populated(hidinput)) - continue; - - if (hid->quirks & HID_QUIRK_MULTI_INPUT) { - /* This will leave hidinput NULL, so that it - * allocates another one if we have more inputs on - * the same interface. Some devices (e.g. Happ's - * UGCI) cram a lot of unrelated inputs into the - * same interface. */ - hidinput->report = report; - if (drv->input_configured && - drv->input_configured(hid, hidinput)) - goto out_cleanup; - if (input_register_device(hidinput->input)) - goto out_cleanup; - hidinput = NULL; - } - } - } - - if (hidinput && (hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) && - !hidinput_has_been_populated(hidinput)) { - /* no need to register an input device not populated */ - hidinput_cleanup_hidinput(hid, hidinput); - hidinput = NULL; - } - - if (list_empty(&hid->inputs)) { - hid_err(hid, "No inputs registered, leaving\n"); - goto out_unwind; - } - - if (hidinput) { - if (drv->input_configured && - drv->input_configured(hid, hidinput)) - goto out_cleanup; - if (input_register_device(hidinput->input)) - goto out_cleanup; - } - - return 0; - -out_cleanup: - list_del(&hidinput->list); - input_free_device(hidinput->input); - kfree(hidinput); -out_unwind: - /* unwind the ones we already registered */ - hidinput_disconnect(hid); - - return -1; -} -EXPORT_SYMBOL_GPL(hidinput_connect); - -void hidinput_disconnect(struct hid_device *hid) -{ - struct hid_input *hidinput, *next; - - hidinput_cleanup_battery(hid); - - list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { - list_del(&hidinput->list); - input_unregister_device(hidinput->input); - kfree(hidinput); - } - - /* led_work is spawned by input_dev callbacks, but doesn't access the - * parent input_dev at all. Once all input devices are removed, we - * know that led_work will never get restarted, so we can cancel it - * synchronously and are safe. */ - cancel_work_sync(&hid->led_work); -} -EXPORT_SYMBOL_GPL(hidinput_disconnect); - diff --git a/src/linux/drivers/hid/i2c-hid/Kconfig b/src/linux/drivers/hid/i2c-hid/Kconfig deleted file mode 100644 index b66617a..0000000 --- a/src/linux/drivers/hid/i2c-hid/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -menu "I2C HID support" - depends on I2C - -config I2C_HID - tristate "HID over I2C transport layer" - default n - depends on I2C && INPUT - select HID - ---help--- - Say Y here if you use a keyboard, a touchpad, a touchscreen, or any - other HID based devices which is connected to your computer via I2C. - - If unsure, say N. - - This support is also available as a module. If so, the module - will be called i2c-hid. - -endmenu diff --git a/src/linux/drivers/hid/intel-ish-hid/Kconfig b/src/linux/drivers/hid/intel-ish-hid/Kconfig deleted file mode 100644 index ea065b3..0000000 --- a/src/linux/drivers/hid/intel-ish-hid/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -menu "Intel ISH HID support" - depends on X86_64 && PCI - -config INTEL_ISH_HID - tristate "Intel Integrated Sensor Hub" - default n - select HID - help - The Integrated Sensor Hub (ISH) enables the ability to offload - sensor polling and algorithm processing to a dedicated low power - processor in the chipset. This allows the core processor to go into - low power modes more often, resulting in the increased battery life. - The current processors that support ISH are: Cherrytrail, Skylake, - Broxton and Kaby Lake. - - Say Y here if you want to support Intel ISH. If unsure, say N. -endmenu diff --git a/src/linux/drivers/hid/usbhid/Kconfig b/src/linux/drivers/hid/usbhid/Kconfig deleted file mode 100644 index 0108c59..0000000 --- a/src/linux/drivers/hid/usbhid/Kconfig +++ /dev/null @@ -1,84 +0,0 @@ -menu "USB HID support" - depends on USB - -config USB_HID - tristate "USB HID transport layer" - default y - depends on USB && INPUT - select HID - ---help--- - Say Y here if you want to connect USB keyboards, - mice, joysticks, graphic tablets, or any other HID based devices - to your computer via USB, as well as Uninterruptible Power Supply - (UPS) and monitor control devices. - - You can't use this driver and the HIDBP (Boot Protocol) keyboard - and mouse drivers at the same time. More information is available: - . - - If unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called usbhid. - -comment "Input core support is needed for USB HID input layer or HIDBP support" - depends on USB_HID && INPUT=n - -config HID_PID - bool "PID device support" - help - Say Y here if you have a PID-compliant device and wish to enable force - feedback for it. Microsoft Sidewinder Force Feedback 2 is one of such - devices. - -config USB_HIDDEV - bool "/dev/hiddev raw HID device support" - depends on USB_HID - help - Say Y here if you want to support HID devices (from the USB - specification standpoint) that aren't strictly user interface - devices, like monitor controls and Uninterruptable Power Supplies. - - This module supports these devices separately using a separate - event interface on /dev/usb/hiddevX (char 180:96 to 180:111). - - If unsure, say Y. - -menu "USB HID Boot Protocol drivers" - depends on USB!=n && USB_HID!=y && EXPERT - -config USB_KBD - tristate "USB HIDBP Keyboard (simple Boot) support" - depends on USB && INPUT - ---help--- - Say Y here only if you are absolutely sure that you don't want - to use the generic HID driver for your USB keyboard and prefer - to use the keyboard in its limited Boot Protocol mode instead. - - This is almost certainly not what you want. This is mostly - useful for embedded applications or simple keyboards. - - To compile this driver as a module, choose M here: the - module will be called usbkbd. - - If even remotely unsure, say N. - -config USB_MOUSE - tristate "USB HIDBP Mouse (simple Boot) support" - depends on USB && INPUT - ---help--- - Say Y here only if you are absolutely sure that you don't want - to use the generic HID driver for your USB mouse and prefer - to use the mouse in its limited Boot Protocol mode instead. - - This is almost certainly not what you want. This is mostly - useful for embedded applications or simple mice. - - To compile this driver as a module, choose M here: the - module will be called usbmouse. - - If even remotely unsure, say N. - -endmenu - -endmenu diff --git a/src/linux/drivers/hsi/Kconfig b/src/linux/drivers/hsi/Kconfig deleted file mode 100644 index 2c76de4..0000000 --- a/src/linux/drivers/hsi/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -# -# HSI driver configuration -# -menuconfig HSI - tristate "HSI support" - ---help--- - The "High speed synchronous Serial Interface" is - synchronous serial interface used mainly to connect - application engines and cellular modems. - -if HSI - -config HSI_BOARDINFO - bool - default y - -source "drivers/hsi/controllers/Kconfig" -source "drivers/hsi/clients/Kconfig" - -endif # HSI diff --git a/src/linux/drivers/hsi/clients/Kconfig b/src/linux/drivers/hsi/clients/Kconfig deleted file mode 100644 index d612620..0000000 --- a/src/linux/drivers/hsi/clients/Kconfig +++ /dev/null @@ -1,40 +0,0 @@ -# -# HSI clients configuration -# - -comment "HSI clients" - -config NOKIA_MODEM - tristate "Nokia Modem" - depends on HSI && SSI_PROTOCOL && CMT_SPEECH - help - Say Y here if you want to add support for the modem on Nokia - N900 (Nokia RX-51) hardware. - - If unsure, say N. - -config CMT_SPEECH - tristate "CMT speech" - depends on HSI && SSI_PROTOCOL - help - If you say Y here, you will enable the CMT speech protocol used - by Nokia modems. If you say M the protocol will be available as - module named cmt_speech. - - If unsure, say N. - -config SSI_PROTOCOL - tristate "SSI protocol" - depends on HSI && PHONET && OMAP_SSI - help - If you say Y here, you will enable the SSI protocol aka McSAAB. - - If unsure, say N. - -config HSI_CHAR - tristate "HSI/SSI character driver" - depends on HSI - ---help--- - If you say Y here, you will enable the HSI/SSI character driver. - This driver provides a simple character device interface for - serial communication with the cellular modem over HSI/SSI bus. diff --git a/src/linux/drivers/hsi/controllers/Kconfig b/src/linux/drivers/hsi/controllers/Kconfig deleted file mode 100644 index 48e4eda..0000000 --- a/src/linux/drivers/hsi/controllers/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -# -# HSI controllers configuration -# -comment "HSI controllers" - -config OMAP_SSI - tristate "OMAP SSI hardware driver" - depends on HSI && OF && ARM && COMMON_CLK - depends on ARCH_OMAP3 || COMPILE_TEST - ---help--- - SSI is a legacy version of HSI. It is usually used to connect - an application engine with a cellular modem. - If you say Y here, you will enable the OMAP SSI hardware driver. - - If unsure, say N. diff --git a/src/linux/drivers/hv/Kconfig b/src/linux/drivers/hv/Kconfig deleted file mode 100644 index 0403b51..0000000 --- a/src/linux/drivers/hv/Kconfig +++ /dev/null @@ -1,22 +0,0 @@ -menu "Microsoft Hyper-V guest support" - -config HYPERV - tristate "Microsoft Hyper-V client drivers" - depends on X86 && ACPI && PCI && X86_LOCAL_APIC && HYPERVISOR_GUEST - help - Select this option to run Linux as a Hyper-V client operating - system. - -config HYPERV_UTILS - tristate "Microsoft Hyper-V Utilities driver" - depends on HYPERV && CONNECTOR && NLS - help - Select this option to enable the Hyper-V Utilities. - -config HYPERV_BALLOON - tristate "Microsoft Hyper-V Balloon driver" - depends on HYPERV - help - Select this option to enable Hyper-V Balloon driver. - -endmenu diff --git a/src/linux/drivers/hwmon/Kconfig b/src/linux/drivers/hwmon/Kconfig deleted file mode 100644 index 45cef3d..0000000 --- a/src/linux/drivers/hwmon/Kconfig +++ /dev/null @@ -1,1860 +0,0 @@ -# -# Hardware monitoring chip drivers configuration -# - -menuconfig HWMON - tristate "Hardware Monitoring support" - depends on HAS_IOMEM - default y - help - Hardware monitoring devices let you monitor the hardware health - of a system. Most modern motherboards include such a device. It - can include temperature sensors, voltage sensors, fan speed - sensors and various additional features such as the ability to - control the speed of the fans. If you want this support you - should say Y here and also to the specific driver(s) for your - sensors chip(s) below. - - To find out which specific driver(s) you need, use the - sensors-detect script from the lm_sensors package. Read - for details. - - This support can also be built as a module. If so, the module - will be called hwmon. - -if HWMON - -config HWMON_VID - tristate - default n - -config HWMON_DEBUG_CHIP - bool "Hardware Monitoring Chip debugging messages" - default n - help - Say Y here if you want the I2C chip drivers to produce a bunch of - debug messages to the system log. Select this if you are having - a problem with I2C support and want to see more of what is going - on. - -comment "Native drivers" - -config SENSORS_AB8500 - tristate "AB8500 thermal monitoring" - depends on AB8500_GPADC && AB8500_BM - default n - help - If you say yes here you get support for the thermal sensor part - of the AB8500 chip. The driver includes thermal management for - AB8500 die and two GPADC channels. The GPADC channel are preferably - used to access sensors outside the AB8500 chip. - - This driver can also be built as a module. If so, the module - will be called abx500-temp. - -config SENSORS_ABITUGURU - tristate "Abit uGuru (rev 1 & 2)" - depends on X86 && DMI - help - If you say yes here you get support for the sensor part of the first - and second revision of the Abit uGuru chip. The voltage and frequency - control parts of the Abit uGuru are not supported. The Abit uGuru - chip can be found on Abit uGuru featuring motherboards (most modern - Abit motherboards from before end 2005). For more info and a list - of which motherboards have which revision see - Documentation/hwmon/abituguru - - This driver can also be built as a module. If so, the module - will be called abituguru. - -config SENSORS_ABITUGURU3 - tristate "Abit uGuru (rev 3)" - depends on X86 && DMI - help - If you say yes here you get support for the sensor part of the - third revision of the Abit uGuru chip. Only reading the sensors - and their settings is supported. The third revision of the Abit - uGuru chip can be found on recent Abit motherboards (since end - 2005). For more info and a list of which motherboards have which - revision see Documentation/hwmon/abituguru3 - - This driver can also be built as a module. If so, the module - will be called abituguru3. - -config SENSORS_AD7314 - tristate "Analog Devices AD7314 and compatibles" - depends on SPI - help - If you say yes here you get support for the Analog Devices - AD7314, ADT7301 and ADT7302 temperature sensors. - - This driver can also be built as a module. If so, the module - will be called ad7314. - -config SENSORS_AD7414 - tristate "Analog Devices AD7414" - depends on I2C - help - If you say yes here you get support for the Analog Devices - AD7414 temperature monitoring chip. - - This driver can also be built as a module. If so, the module - will be called ad7414. - -config SENSORS_AD7418 - tristate "Analog Devices AD7416, AD7417 and AD7418" - depends on I2C - help - If you say yes here you get support for the Analog Devices - AD7416, AD7417 and AD7418 temperature monitoring chips. - - This driver can also be built as a module. If so, the module - will be called ad7418. - -config SENSORS_ADM1021 - tristate "Analog Devices ADM1021 and compatibles" - depends on I2C - help - If you say yes here you get support for Analog Devices ADM1021 - and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A, - Genesys Logic GL523SM, National Semiconductor LM84 and TI THMC10. - - This driver can also be built as a module. If so, the module - will be called adm1021. - -config SENSORS_ADM1025 - tristate "Analog Devices ADM1025 and compatibles" - depends on I2C - select HWMON_VID - help - If you say yes here you get support for Analog Devices ADM1025 - and Philips NE1619 sensor chips. - - This driver can also be built as a module. If so, the module - will be called adm1025. - -config SENSORS_ADM1026 - tristate "Analog Devices ADM1026 and compatibles" - depends on I2C - select HWMON_VID - help - If you say yes here you get support for Analog Devices ADM1026 - sensor chip. - - This driver can also be built as a module. If so, the module - will be called adm1026. - -config SENSORS_ADM1029 - tristate "Analog Devices ADM1029" - depends on I2C - help - If you say yes here you get support for Analog Devices ADM1029 - sensor chip. - Very rare chip, please let us know you use it. - - This driver can also be built as a module. If so, the module - will be called adm1029. - -config SENSORS_ADM1031 - tristate "Analog Devices ADM1031 and compatibles" - depends on I2C - help - If you say yes here you get support for Analog Devices ADM1031 - and ADM1030 sensor chips. - - This driver can also be built as a module. If so, the module - will be called adm1031. - -config SENSORS_ADM9240 - tristate "Analog Devices ADM9240 and compatibles" - depends on I2C - select HWMON_VID - help - If you say yes here you get support for Analog Devices ADM9240, - Dallas DS1780, National Semiconductor LM81 sensor chips. - - This driver can also be built as a module. If so, the module - will be called adm9240. - -config SENSORS_ADT7X10 - tristate - help - This module contains common code shared by the ADT7310/ADT7320 and - ADT7410/ADT7420 temperature monitoring chip drivers. - - If build as a module, the module will be called adt7x10. - -config SENSORS_ADT7310 - tristate "Analog Devices ADT7310/ADT7320" - depends on SPI_MASTER - select SENSORS_ADT7X10 - help - If you say yes here you get support for the Analog Devices - ADT7310 and ADT7320 temperature monitoring chips. - - This driver can also be built as a module. If so, the module - will be called adt7310. - -config SENSORS_ADT7410 - tristate "Analog Devices ADT7410/ADT7420" - depends on I2C - select SENSORS_ADT7X10 - help - If you say yes here you get support for the Analog Devices - ADT7410 and ADT7420 temperature monitoring chips. - - This driver can also be built as a module. If so, the module - will be called adt7410. - -config SENSORS_ADT7411 - tristate "Analog Devices ADT7411" - depends on I2C - help - If you say yes here you get support for the Analog Devices - ADT7411 voltage and temperature monitoring chip. - - This driver can also be built as a module. If so, the module - will be called adt7411. - -config SENSORS_ADT7462 - tristate "Analog Devices ADT7462" - depends on I2C - help - If you say yes here you get support for the Analog Devices - ADT7462 temperature monitoring chips. - - This driver can also be built as a module. If so, the module - will be called adt7462. - -config SENSORS_ADT7470 - tristate "Analog Devices ADT7470" - depends on I2C - help - If you say yes here you get support for the Analog Devices - ADT7470 temperature monitoring chips. - - This driver can also be built as a module. If so, the module - will be called adt7470. - -config SENSORS_ADT7475 - tristate "Analog Devices ADT7473, ADT7475, ADT7476 and ADT7490" - depends on I2C - select HWMON_VID - help - If you say yes here you get support for the Analog Devices - ADT7473, ADT7475, ADT7476 and ADT7490 hardware monitoring - chips. - - This driver can also be build as a module. If so, the module - will be called adt7475. - -config SENSORS_ASC7621 - tristate "Andigilog aSC7621" - depends on I2C - help - If you say yes here you get support for the aSC7621 - family of SMBus sensors chip found on most Intel X38, X48, X58, - 945, 965 and 975 desktop boards. Currently supported chips: - aSC7621 - aSC7621a - - This driver can also be built as a module. If so, the module - will be called asc7621. - -config SENSORS_K8TEMP - tristate "AMD Athlon64/FX or Opteron temperature sensor" - depends on X86 && PCI - help - If you say yes here you get support for the temperature - sensor(s) inside your CPU. Supported is whole AMD K8 - microarchitecture. Please note that you will need at least - lm-sensors 2.10.1 for proper userspace support. - - This driver can also be built as a module. If so, the module - will be called k8temp. - -config SENSORS_K10TEMP - tristate "AMD Family 10h+ temperature sensor" - depends on X86 && PCI - help - If you say yes here you get support for the temperature - sensor(s) inside your CPU. Supported are later revisions of - the AMD Family 10h and all revisions of the AMD Family 11h, - 12h (Llano), 14h (Brazos), 15h (Bulldozer/Trinity/Kaveri/Carrizo) - and 16h (Kabini/Mullins) microarchitectures. - - This driver can also be built as a module. If so, the module - will be called k10temp. - -config SENSORS_FAM15H_POWER - tristate "AMD Family 15h processor power" - depends on X86 && PCI && CPU_SUP_AMD - help - If you say yes here you get support for processor power - information of your AMD family 15h CPU. - - This driver can also be built as a module. If so, the module - will be called fam15h_power. - -config SENSORS_APPLESMC - tristate "Apple SMC (Motion sensor, light sensor, keyboard backlight)" - depends on INPUT && X86 - select NEW_LEDS - select LEDS_CLASS - select INPUT_POLLDEV - default n - help - This driver provides support for the Apple System Management - Controller, which provides an accelerometer (Apple Sudden Motion - Sensor), light sensors, temperature sensors, keyboard backlight - control and fan control. - - Only Intel-based Apple's computers are supported (MacBook Pro, - MacBook, MacMini). - - Data from the different sensors, keyboard backlight control and fan - control are accessible via sysfs. - - This driver also provides an absolute input class device, allowing - the laptop to act as a pinball machine-esque joystick. - - Say Y here if you have an applicable laptop and want to experience - the awesome power of applesmc. - -config SENSORS_ARM_SCPI - tristate "ARM SCPI Sensors" - depends on ARM_SCPI_PROTOCOL - depends on THERMAL || !THERMAL_OF - help - This driver provides support for temperature, voltage, current - and power sensors available on ARM Ltd's SCP based platforms. The - actual number and type of sensors exported depend on the platform. - -config SENSORS_ASB100 - tristate "Asus ASB100 Bach" - depends on X86 && I2C - select HWMON_VID - help - If you say yes here you get support for the ASB100 Bach sensor - chip found on some Asus mainboards. - - This driver can also be built as a module. If so, the module - will be called asb100. - -config SENSORS_ATXP1 - tristate "Attansic ATXP1 VID controller" - depends on I2C - select HWMON_VID - help - If you say yes here you get support for the Attansic ATXP1 VID - controller. - - If your board have such a chip, you are able to control your CPU - core and other voltages. - - This driver can also be built as a module. If so, the module - will be called atxp1. - -config SENSORS_DS620 - tristate "Dallas Semiconductor DS620" - depends on I2C - help - If you say yes here you get support for Dallas Semiconductor - DS620 sensor chip. - - This driver can also be built as a module. If so, the module - will be called ds620. - -config SENSORS_DS1621 - tristate "Dallas Semiconductor DS1621 and compatibles" - depends on I2C - help - If you say yes here you get support for Dallas Semiconductor/Maxim - Integrated DS1621 sensor chips and compatible models including: - - - Dallas Semiconductor DS1625 - - Maxim Integrated DS1631 - - Maxim Integrated DS1721 - - Maxim Integrated DS1731 - - This driver can also be built as a module. If so, the module - will be called ds1621. - -config SENSORS_DELL_SMM - tristate "Dell laptop SMM BIOS hwmon driver" - depends on X86 - help - This hwmon driver adds support for reporting temperature of different - sensors and controls the fans on Dell laptops via System Management - Mode provided by Dell BIOS. - - When option I8K is also enabled this driver provides legacy /proc/i8k - userspace interface for i8kutils package. - -config SENSORS_DA9052_ADC - tristate "Dialog DA9052/DA9053 ADC" - depends on PMIC_DA9052 - help - Say y here to support the ADC found on Dialog Semiconductor - DA9052-BC and DA9053-AA/Bx PMICs. - - This driver can also be built as module. If so, the module - will be called da9052-hwmon. - -config SENSORS_DA9055 - tristate "Dialog Semiconductor DA9055 ADC" - depends on MFD_DA9055 - help - If you say yes here you get support for ADC on the Dialog - Semiconductor DA9055 PMIC. - - This driver can also be built as a module. If so, the module - will be called da9055-hwmon. - -config SENSORS_I5K_AMB - tristate "FB-DIMM AMB temperature sensor on Intel 5000 series chipsets" - depends on PCI - help - If you say yes here you get support for FB-DIMM AMB temperature - monitoring chips on systems with the Intel 5000 series chipset. - - This driver can also be built as a module. If so, the module - will be called i5k_amb. - -config SENSORS_F71805F - tristate "Fintek F71805F/FG, F71806F/FG and F71872F/FG" - depends on !PPC - help - If you say yes here you get support for hardware monitoring - features of the Fintek F71805F/FG, F71806F/FG and F71872F/FG - Super-I/O chips. - - This driver can also be built as a module. If so, the module - will be called f71805f. - -config SENSORS_F71882FG - tristate "Fintek F71882FG and compatibles" - depends on !PPC - help - If you say yes here you get support for hardware monitoring - features of many Fintek Super-I/O (LPC) chips. The currently - supported chips are: - F71808E/A - F71858FG - F71862FG - F71863FG - F71869F/E/A - F71882FG - F71883FG - F71889FG/ED/A - F8000 - F81801U - F81865F - - This driver can also be built as a module. If so, the module - will be called f71882fg. - -config SENSORS_F75375S - tristate "Fintek F75375S/SP, F75373 and F75387" - depends on I2C - help - If you say yes here you get support for hardware monitoring - features of the Fintek F75375S/SP, F75373 and F75387 - - This driver can also be built as a module. If so, the module - will be called f75375s. - -config SENSORS_MC13783_ADC - tristate "Freescale MC13783/MC13892 ADC" - depends on MFD_MC13XXX - help - Support for the A/D converter on MC13783 and MC13892 PMIC. - -config SENSORS_FSCHMD - tristate "Fujitsu Siemens Computers sensor chips" - depends on X86 && I2C - help - If you say yes here you get support for the following Fujitsu - Siemens Computers (FSC) sensor chips: Poseidon, Scylla, Hermes, - Heimdall, Heracles, Hades and Syleus including support for the - integrated watchdog. - - This is a merged driver for FSC sensor chips replacing the fscpos, - fscscy and fscher drivers and adding support for several other FSC - sensor chips. - - This driver can also be built as a module. If so, the module - will be called fschmd. - -config SENSORS_FTSTEUTATES - tristate "Fujitsu Technology Solutions sensor chip Teutates" - depends on I2C && WATCHDOG - select WATCHDOG_CORE - help - If you say yes here you get support for the Fujitsu Technology - Solutions (FTS) sensor chip "Teutates" including support for - the integrated watchdog. - - This driver can also be built as a module. If so, the module - will be called ftsteutates. - -config SENSORS_GL518SM - tristate "Genesys Logic GL518SM" - depends on I2C - help - If you say yes here you get support for Genesys Logic GL518SM - sensor chips. - - This driver can also be built as a module. If so, the module - will be called gl518sm. - -config SENSORS_GL520SM - tristate "Genesys Logic GL520SM" - depends on I2C - select HWMON_VID - help - If you say yes here you get support for Genesys Logic GL520SM - sensor chips. - - This driver can also be built as a module. If so, the module - will be called gl520sm. - -config SENSORS_G760A - tristate "GMT G760A" - depends on I2C - help - If you say yes here you get support for Global Mixed-mode - Technology Inc G760A fan speed PWM controller chips. - - This driver can also be built as a module. If so, the module - will be called g760a. - -config SENSORS_G762 - tristate "GMT G762 and G763" - depends on I2C - help - If you say yes here you get support for Global Mixed-mode - Technology Inc G762 and G763 fan speed PWM controller chips. - - This driver can also be built as a module. If so, the module - will be called g762. - -config SENSORS_GPIO_FAN - tristate "GPIO fan" - depends on GPIOLIB || COMPILE_TEST - depends on THERMAL || THERMAL=n - help - If you say yes here you get support for fans connected to GPIO lines. - - This driver can also be built as a module. If so, the module - will be called gpio-fan. - -config SENSORS_HIH6130 - tristate "Honeywell Humidicon HIH-6130 humidity/temperature sensor" - depends on I2C - help - If you say yes here you get support for Honeywell Humidicon - HIH-6130 and HIH-6131 Humidicon humidity sensors. - - This driver can also be built as a module. If so, the module - will be called hih6130. - -config SENSORS_IBMAEM - tristate "IBM Active Energy Manager temperature/power sensors and control" - select IPMI_SI - depends on IPMI_HANDLER - help - If you say yes here you get support for the temperature and - power sensors and capping hardware in various IBM System X - servers that support Active Energy Manager. This includes - the x3350, x3550, x3650, x3655, x3755, x3850 M2, x3950 M2, - and certain HC10/HS2x/LS2x/QS2x blades. - - This driver can also be built as a module. If so, the module - will be called ibmaem. - -config SENSORS_IBMPEX - tristate "IBM PowerExecutive temperature/power sensors" - select IPMI_SI - depends on IPMI_HANDLER - help - If you say yes here you get support for the temperature and - power sensors in various IBM System X servers that support - PowerExecutive. So far this includes the x3350, x3550, x3650, - x3655, and x3755; the x3800, x3850, and x3950 models that have - PCI Express; and some of the HS2x, LS2x, and QS2x blades. - - This driver can also be built as a module. If so, the module - will be called ibmpex. - -config SENSORS_IBMPOWERNV - tristate "IBM POWERNV platform sensors" - depends on PPC_POWERNV - default y - help - If you say yes here you get support for the temperature/fan/power - sensors on your PowerNV platform. - - This driver can also be built as a module. If so, the module - will be called ibmpowernv. - -config SENSORS_IIO_HWMON - tristate "Hwmon driver that uses channels specified via iio maps" - depends on IIO - help - This is a platform driver that in combination with a suitable - map allows IIO devices to provide basic hwmon functionality - for those channels specified in the map. This map can be provided - either via platform data or the device tree bindings. - -config SENSORS_I5500 - tristate "Intel 5500/5520/X58 temperature sensor" - depends on X86 && PCI - help - If you say yes here you get support for the temperature - sensor inside the Intel 5500, 5520 and X58 chipsets. - - This driver can also be built as a module. If so, the module - will be called i5500_temp. - -config SENSORS_CORETEMP - tristate "Intel Core/Core2/Atom temperature sensor" - depends on X86 - help - If you say yes here you get support for the temperature - sensor inside your CPU. Most of the family 6 CPUs - are supported. Check Documentation/hwmon/coretemp for details. - -config SENSORS_IT87 - tristate "ITE IT87xx and compatibles" - depends on !PPC - select HWMON_VID - help - If you say yes here you get support for ITE IT8705F, IT8712F, IT8716F, - IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8732F, IT8758E, - IT8771E, IT8772E, IT8781F, IT8782F, IT8783E/F, IT8786E, IT8790E, - IT8603E, IT8620E, IT8623E, and IT8628E sensor chips, and the SiS950 - clone. - - This driver can also be built as a module. If so, the module - will be called it87. - -config SENSORS_JZ4740 - tristate "Ingenic JZ4740 SoC ADC driver" - depends on MACH_JZ4740 && MFD_JZ4740_ADC - help - If you say yes here you get support for reading adc values from the ADCIN - pin on Ingenic JZ4740 SoC based boards. - - This driver can also be build as a module. If so, the module will be - called jz4740-hwmon. - -config SENSORS_JC42 - tristate "JEDEC JC42.4 compliant memory module temperature sensors" - depends on I2C - help - If you say yes here, you get support for JEDEC JC42.4 compliant - temperature sensors, which are used on many DDR3 memory modules for - mobile devices and servers. Support will include, but not be limited - to, ADT7408, AT30TS00, CAT34TS02, CAT6095, MAX6604, MCP9804, MCP9805, - MCP9808, MCP98242, MCP98243, MCP98244, MCP9843, SE97, SE98, - STTS424(E), STTS2002, STTS3000, TSE2002, TSE2004, TS3000, and TS3001. - - This driver can also be built as a module. If so, the module - will be called jc42. - -config SENSORS_POWR1220 - tristate "Lattice POWR1220 Power Monitoring" - depends on I2C - default n - help - If you say yes here you get access to the hardware monitoring - functions of the Lattice POWR1220 isp Power Supply Monitoring, - Sequencing and Margining Controller. - - This driver can also be built as a module. If so, the module - will be called powr1220. - -config SENSORS_LINEAGE - tristate "Lineage Compact Power Line Power Entry Module" - depends on I2C - help - If you say yes here you get support for the Lineage Compact Power Line - series of DC/DC and AC/DC converters such as CP1800, CP2000AC, - CP2000DC, CP2725, and others. - - This driver can also be built as a module. If so, the module - will be called lineage-pem. - -config SENSORS_LTC2945 - tristate "Linear Technology LTC2945" - depends on I2C - select REGMAP_I2C - default n - help - If you say yes here you get support for Linear Technology LTC2945 - I2C System Monitor. - - This driver can also be built as a module. If so, the module will - be called ltc2945. - -config SENSORS_LTC2990 - tristate "Linear Technology LTC2990 (current monitoring mode only)" - depends on I2C - help - If you say yes here you get support for Linear Technology LTC2990 - I2C System Monitor. The LTC2990 supports a combination of voltage, - current and temperature monitoring, but in addition to the Vcc supply - voltage and chip temperature, this driver currently only supports - reading two currents by measuring two differential voltages across - series resistors. - - This driver can also be built as a module. If so, the module will - be called ltc2990. - -config SENSORS_LTC4151 - tristate "Linear Technology LTC4151" - depends on I2C - default n - help - If you say yes here you get support for Linear Technology LTC4151 - High Voltage I2C Current and Voltage Monitor interface. - - This driver can also be built as a module. If so, the module will - be called ltc4151. - -config SENSORS_LTC4215 - tristate "Linear Technology LTC4215" - depends on I2C - default n - help - If you say yes here you get support for Linear Technology LTC4215 - Hot Swap Controller I2C interface. - - This driver can also be built as a module. If so, the module will - be called ltc4215. - -config SENSORS_LTC4222 - tristate "Linear Technology LTC4222" - depends on I2C - select REGMAP_I2C - default n - help - If you say yes here you get support for Linear Technology LTC4222 - Dual Hot Swap Controller I2C interface. - - This driver can also be built as a module. If so, the module will - be called ltc4222. - -config SENSORS_LTC4245 - tristate "Linear Technology LTC4245" - depends on I2C - default n - help - If you say yes here you get support for Linear Technology LTC4245 - Multiple Supply Hot Swap Controller I2C interface. - - This driver can also be built as a module. If so, the module will - be called ltc4245. - -config SENSORS_LTC4260 - tristate "Linear Technology LTC4260" - depends on I2C - select REGMAP_I2C - default n - help - If you say yes here you get support for Linear Technology LTC4260 - Positive Voltage Hot Swap Controller I2C interface. - - This driver can also be built as a module. If so, the module will - be called ltc4260. - -config SENSORS_LTC4261 - tristate "Linear Technology LTC4261" - depends on I2C - default n - help - If you say yes here you get support for Linear Technology LTC4261 - Negative Voltage Hot Swap Controller I2C interface. - - This driver can also be built as a module. If so, the module will - be called ltc4261. - -config SENSORS_MAX1111 - tristate "Maxim MAX1111 Serial 8-bit ADC chip and compatibles" - depends on SPI_MASTER - help - Say y here to support Maxim's MAX1110, MAX1111, MAX1112, and MAX1113 - ADC chips. - - This driver can also be built as a module. If so, the module - will be called max1111. - -config SENSORS_MAX16065 - tristate "Maxim MAX16065 System Manager and compatibles" - depends on I2C - help - If you say yes here you get support for hardware monitoring - capabilities of the following Maxim System Manager chips. - MAX16065 - MAX16066 - MAX16067 - MAX16068 - MAX16070 - MAX16071 - - This driver can also be built as a module. If so, the module - will be called max16065. - -config SENSORS_MAX1619 - tristate "Maxim MAX1619 sensor chip" - depends on I2C - help - If you say yes here you get support for MAX1619 sensor chip. - - This driver can also be built as a module. If so, the module - will be called max1619. - -config SENSORS_MAX1668 - tristate "Maxim MAX1668 and compatibles" - depends on I2C - help - If you say yes here you get support for MAX1668, MAX1989 and - MAX1805 chips. - - This driver can also be built as a module. If so, the module - will be called max1668. - -config SENSORS_MAX197 - tristate "Maxim MAX197 and compatibles" - help - Support for the Maxim MAX197 A/D converter. - Support will include, but not be limited to, MAX197, and MAX199. - - This driver can also be built as a module. If so, the module - will be called max197. - -config SENSORS_MAX31722 -tristate "MAX31722 temperature sensor" - depends on SPI - help - Support for the Maxim Integrated MAX31722/MAX31723 digital - thermometers/thermostats operating over an SPI interface. - - This driver can also be built as a module. If so, the module - will be called max31722. - -config SENSORS_MAX6639 - tristate "Maxim MAX6639 sensor chip" - depends on I2C - help - If you say yes here you get support for the MAX6639 - sensor chips. - - This driver can also be built as a module. If so, the module - will be called max6639. - -config SENSORS_MAX6642 - tristate "Maxim MAX6642 sensor chip" - depends on I2C - help - If you say yes here you get support for MAX6642 sensor chip. - MAX6642 is a SMBus-Compatible Remote/Local Temperature Sensor - with Overtemperature Alarm from Maxim. - - This driver can also be built as a module. If so, the module - will be called max6642. - -config SENSORS_MAX6650 - tristate "Maxim MAX6650 sensor chip" - depends on I2C - help - If you say yes here you get support for the MAX6650 / MAX6651 - sensor chips. - - This driver can also be built as a module. If so, the module - will be called max6650. - -config SENSORS_MAX6697 - tristate "Maxim MAX6697 and compatibles" - depends on I2C - help - If you say yes here you get support for MAX6581, MAX6602, MAX6622, - MAX6636, MAX6689, MAX6693, MAX6694, MAX6697, MAX6698, and MAX6699 - temperature sensor chips. - - This driver can also be built as a module. If so, the module - will be called max6697. - -config SENSORS_MAX31790 - tristate "Maxim MAX31790 sensor chip" - depends on I2C - help - If you say yes here you get support for 6-Channel PWM-Output - Fan RPM Controller. - - This driver can also be built as a module. If so, the module - will be called max31790. - -config SENSORS_MCP3021 - tristate "Microchip MCP3021 and compatibles" - depends on I2C - help - If you say yes here you get support for MCP3021 and MCP3221. - The MCP3021 is a A/D converter (ADC) with 10-bit and the MCP3221 - with 12-bit resolution. - - This driver can also be built as a module. If so, the module - will be called mcp3021. - -config SENSORS_MENF21BMC_HWMON - tristate "MEN 14F021P00 BMC Hardware Monitoring" - depends on MFD_MENF21BMC - help - Say Y here to include support for the MEN 14F021P00 BMC - hardware monitoring. - - This driver can also be built as a module. If so the module - will be called menf21bmc_hwmon. - -config SENSORS_ADCXX - tristate "National Semiconductor ADCxxxSxxx" - depends on SPI_MASTER - help - If you say yes here you get support for the National Semiconductor - ADCS chip family, where - * bb is the resolution in number of bits (8, 10, 12) - * c is the number of channels (1, 2, 4, 8) - * sss is the maximum conversion speed (021 for 200 kSPS, 051 for 500 - kSPS and 101 for 1 MSPS) - - Examples : ADC081S101, ADC124S501, ... - - This driver can also be built as a module. If so, the module - will be called adcxx. - -config SENSORS_LM63 - tristate "National Semiconductor LM63 and compatibles" - depends on I2C - help - If you say yes here you get support for the National - Semiconductor LM63, LM64, and LM96163 remote diode digital temperature - sensors with integrated fan control. Such chips are found - on the Tyan S4882 (Thunder K8QS Pro) motherboard, among - others. - - This driver can also be built as a module. If so, the module - will be called lm63. - -config SENSORS_LM70 - tristate "National Semiconductor LM70 and compatibles" - depends on SPI_MASTER - help - If you say yes here you get support for the National Semiconductor - LM70, LM71, LM74 and Texas Instruments TMP121/TMP123 digital tempera- - ture sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm70. - -config SENSORS_LM73 - tristate "National Semiconductor LM73" - depends on I2C - help - If you say yes here you get support for National Semiconductor LM73 - sensor chips. - This driver can also be built as a module. If so, the module - will be called lm73. - -config SENSORS_LM75 - tristate "National Semiconductor LM75 and compatibles" - depends on I2C - select REGMAP_I2C - help - If you say yes here you get support for one common type of - temperature sensor chip, with models including: - - - Analog Devices ADT75 - - Dallas Semiconductor DS75, DS1775 and DS7505 - - Global Mixed-mode Technology (GMT) G751 - - Maxim MAX6625 and MAX6626 - - Microchip MCP980x - - National Semiconductor LM75, LM75A - - NXP's LM75A - - ST Microelectronics STDS75 - - TelCom (now Microchip) TCN75 - - Texas Instruments TMP100, TMP101, TMP105, TMP112, TMP75, - TMP175, TMP275 - - This driver supports driver model based binding through board - specific I2C device tables. - - It also supports the "legacy" style of driver binding. To use - that with some chips which don't replicate LM75 quirks exactly, - you may need the "force" module parameter. - - This driver can also be built as a module. If so, the module - will be called lm75. - -config SENSORS_LM77 - tristate "National Semiconductor LM77" - depends on I2C - help - If you say yes here you get support for National Semiconductor LM77 - sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm77. - -config SENSORS_LM78 - tristate "National Semiconductor LM78 and compatibles" - depends on I2C - select HWMON_VID - help - If you say yes here you get support for National Semiconductor LM78, - LM78-J and LM79. - - This driver can also be built as a module. If so, the module - will be called lm78. - -config SENSORS_LM80 - tristate "National Semiconductor LM80 and LM96080" - depends on I2C - help - If you say yes here you get support for National Semiconductor - LM80 and LM96080 sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm80. - -config SENSORS_LM83 - tristate "National Semiconductor LM83 and compatibles" - depends on I2C - help - If you say yes here you get support for National Semiconductor - LM82 and LM83 sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm83. - -config SENSORS_LM85 - tristate "National Semiconductor LM85 and compatibles" - depends on I2C - select HWMON_VID - help - If you say yes here you get support for National Semiconductor LM85 - sensor chips and clones: ADM1027, ADT7463, ADT7468, EMC6D100, - EMC6D101, EMC6D102, and EMC6D103. - - This driver can also be built as a module. If so, the module - will be called lm85. - -config SENSORS_LM87 - tristate "National Semiconductor LM87 and compatibles" - depends on I2C - select HWMON_VID - help - If you say yes here you get support for National Semiconductor LM87 - and Analog Devices ADM1024 sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm87. - -config SENSORS_LM90 - tristate "National Semiconductor LM90 and compatibles" - depends on I2C - help - If you say yes here you get support for National Semiconductor LM90, - LM86, LM89 and LM99, Analog Devices ADM1032, ADT7461, and ADT7461A, - Maxim MAX6646, MAX6647, MAX6648, MAX6649, MAX6657, MAX6658, MAX6659, - MAX6680, MAX6681, MAX6692, MAX6695, MAX6696, ON Semiconductor NCT1008, - Winbond/Nuvoton W83L771W/G/AWG/ASG, Philips SA56004, and GMT G781 - sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm90. - -config SENSORS_LM92 - tristate "National Semiconductor LM92 and compatibles" - depends on I2C - help - If you say yes here you get support for National Semiconductor LM92 - and Maxim MAX6635 sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm92. - -config SENSORS_LM93 - tristate "National Semiconductor LM93 and compatibles" - depends on I2C - select HWMON_VID - help - If you say yes here you get support for National Semiconductor LM93, - LM94, and compatible sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm93. - -config SENSORS_LM95234 - tristate "National Semiconductor LM95234 and compatibles" - depends on I2C - help - If you say yes here you get support for the LM95233 and LM95234 - temperature sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm95234. - -config SENSORS_LM95241 - tristate "National Semiconductor LM95241 and compatibles" - depends on I2C - help - If you say yes here you get support for LM95231 and LM95241 sensor - chips. - - This driver can also be built as a module. If so, the module - will be called lm95241. - -config SENSORS_LM95245 - tristate "National Semiconductor LM95245 and compatibles" - depends on I2C - select REGMAP_I2C - help - If you say yes here you get support for LM95235 and LM95245 - temperature sensor chips. - - This driver can also be built as a module. If so, the module - will be called lm95245. - -config SENSORS_PC87360 - tristate "National Semiconductor PC87360 family" - depends on !PPC - select HWMON_VID - help - If you say yes here you get access to the hardware monitoring - functions of the National Semiconductor PC8736x Super-I/O chips. - The PC87360, PC87363 and PC87364 only have fan monitoring and - control. The PC87365 and PC87366 additionally have voltage and - temperature monitoring. - - This driver can also be built as a module. If so, the module - will be called pc87360. - -config SENSORS_PC87427 - tristate "National Semiconductor PC87427" - depends on !PPC - help - If you say yes here you get access to the hardware monitoring - functions of the National Semiconductor PC87427 Super-I/O chip. - The chip has two distinct logical devices, one for fan speed - monitoring and control, and one for voltage and temperature - monitoring. Fan speed monitoring and control are supported, as - well as temperature monitoring. Voltages aren't supported yet. - - This driver can also be built as a module. If so, the module - will be called pc87427. - -config SENSORS_NTC_THERMISTOR - tristate "NTC thermistor support from Murata" - depends on !OF || IIO=n || IIO - depends on THERMAL || !THERMAL_OF - help - This driver supports NTC thermistors sensor reading and its - interpretation. The driver can also monitor the temperature and - send notifications about the temperature. - - Currently, this driver supports - NCP15WB473, NCP18WB473, NCP21WB473, NCP03WB473, NCP15WL333, - NCP03WF104 and NCP15XH103 from Murata and B57330V2103 from EPCOS. - - This driver can also be built as a module. If so, the module - will be called ntc-thermistor. - -config SENSORS_NCT6683 - tristate "Nuvoton NCT6683D" - depends on !PPC - help - If you say yes here you get support for the hardware monitoring - functionality of the Nuvoton NCT6683D eSIO chip. - - This driver can also be built as a module. If so, the module - will be called nct6683. - -config SENSORS_NCT6775 - tristate "Nuvoton NCT6775F and compatibles" - depends on !PPC - select HWMON_VID - help - If you say yes here you get support for the hardware monitoring - functionality of the Nuvoton NCT6106D, NCT6775F, NCT6776F, NCT6779D, - NCT6791D, NCT6792D, NCT6793D, and compatible Super-I/O chips. This - driver replaces the w83627ehf driver for NCT6775F and NCT6776F. - - This driver can also be built as a module. If so, the module - will be called nct6775. - -config SENSORS_NCT7802 - tristate "Nuvoton NCT7802Y" - depends on I2C - select REGMAP_I2C - help - If you say yes here you get support for the Nuvoton NCT7802Y - hardware monitoring chip. - - This driver can also be built as a module. If so, the module - will be called nct7802. - -config SENSORS_NCT7904 - tristate "Nuvoton NCT7904" - depends on I2C - help - If you say yes here you get support for the Nuvoton NCT7904 - hardware monitoring chip, including manual fan speed control. - - This driver can also be built as a module. If so, the module - will be called nct7904. - -config SENSORS_NSA320 - tristate "ZyXEL NSA320 and compatible fan speed and temperature sensors" - depends on GPIOLIB && OF - depends on MACH_KIRKWOOD || COMPILE_TEST - help - If you say yes here you get support for hardware monitoring - for the ZyXEL NSA320 Media Server and other compatible devices - (probably the NSA325 and some NSA310 variants). - - The sensor data is taken from a Holtek HT46R065 microcontroller - connected to GPIO lines. - - This driver can also be built as a module. If so, the module - will be called nsa320-hwmon. - -config SENSORS_PCF8591 - tristate "Philips PCF8591 ADC/DAC" - depends on I2C - default n - help - If you say yes here you get support for Philips PCF8591 4-channel - ADC, 1-channel DAC chips. - - This driver can also be built as a module. If so, the module - will be called pcf8591. - - These devices are hard to detect and rarely found on mainstream - hardware. If unsure, say N. - -source drivers/hwmon/pmbus/Kconfig - -config SENSORS_PWM_FAN - tristate "PWM fan" - depends on (PWM && OF) || COMPILE_TEST - depends on THERMAL || THERMAL=n - help - If you say yes here you get support for fans connected to PWM lines. - The driver uses the generic PWM interface, thus it will work on a - variety of SoCs. - - This driver can also be built as a module. If so, the module - will be called pwm-fan. - -config SENSORS_SHT15 - tristate "Sensiron humidity and temperature sensors. SHT15 and compat." - depends on GPIOLIB || COMPILE_TEST - select BITREVERSE - help - If you say yes here you get support for the Sensiron SHT10, SHT11, - SHT15, SHT71, SHT75 humidity and temperature sensors. - - This driver can also be built as a module. If so, the module - will be called sht15. - -config SENSORS_SHT21 - tristate "Sensiron humidity and temperature sensors. SHT21 and compat." - depends on I2C - help - If you say yes here you get support for the Sensiron SHT21, SHT25 - humidity and temperature sensors. - - This driver can also be built as a module. If so, the module - will be called sht21. - -config SENSORS_SHT3x - tristate "Sensiron humidity and temperature sensors. SHT3x and compat." - depends on I2C - select CRC8 - help - If you say yes here you get support for the Sensiron SHT30 and SHT31 - humidity and temperature sensors. - - This driver can also be built as a module. If so, the module - will be called sht3x. - -config SENSORS_SHTC1 - tristate "Sensiron humidity and temperature sensors. SHTC1 and compat." - depends on I2C - help - If you say yes here you get support for the Sensiron SHTC1 and SHTW1 - humidity and temperature sensors. - - This driver can also be built as a module. If so, the module - will be called shtc1. - -config SENSORS_S3C - tristate "Samsung built-in ADC" - depends on S3C_ADC - help - If you say yes here you get support for the on-board ADCs of - the Samsung S3C24XX, S3C64XX and other series of SoC - - This driver can also be built as a module. If so, the module - will be called s3c-hwmon. - -config SENSORS_S3C_RAW - bool "Include raw channel attributes in sysfs" - depends on SENSORS_S3C - help - Say Y here if you want to include raw copies of all the ADC - channels in sysfs. - -config SENSORS_SIS5595 - tristate "Silicon Integrated Systems Corp. SiS5595" - depends on PCI - help - If you say yes here you get support for the integrated sensors in - SiS5595 South Bridges. - - This driver can also be built as a module. If so, the module - will be called sis5595. - -config SENSORS_DME1737 - tristate "SMSC DME1737, SCH311x and compatibles" - depends on I2C && !PPC - select HWMON_VID - help - If you say yes here you get support for the hardware monitoring - and fan control features of the SMSC DME1737, SCH311x, SCH5027, and - Asus A8000 Super-I/O chips. - - This driver can also be built as a module. If so, the module - will be called dme1737. - -config SENSORS_EMC1403 - tristate "SMSC EMC1403/23 thermal sensor" - depends on I2C - select REGMAP_I2C - help - If you say yes here you get support for the SMSC EMC1403/23 - temperature monitoring chip. - - Threshold values can be configured using sysfs. - Data from the different diodes are accessible via sysfs. - -config SENSORS_EMC2103 - tristate "SMSC EMC2103" - depends on I2C - help - If you say yes here you get support for the temperature - and fan sensors of the SMSC EMC2103 chips. - - This driver can also be built as a module. If so, the module - will be called emc2103. - -config SENSORS_EMC6W201 - tristate "SMSC EMC6W201" - depends on I2C - help - If you say yes here you get support for the SMSC EMC6W201 - hardware monitoring chip. - - This driver can also be built as a module. If so, the module - will be called emc6w201. - -config SENSORS_SMSC47M1 - tristate "SMSC LPC47M10x and compatibles" - depends on !PPC - help - If you say yes here you get support for the integrated fan - monitoring and control capabilities of the SMSC LPC47B27x, - LPC47M10x, LPC47M112, LPC47M13x, LPC47M14x, LPC47M15x, - LPC47M192, LPC47M292 and LPC47M997 chips. - - The temperature and voltage sensor features of the LPC47M15x, - LPC47M192, LPC47M292 and LPC47M997 are supported by another - driver, select also "SMSC LPC47M192 and compatibles" below for - those. - - This driver can also be built as a module. If so, the module - will be called smsc47m1. - -config SENSORS_SMSC47M192 - tristate "SMSC LPC47M192 and compatibles" - depends on I2C - select HWMON_VID - help - If you say yes here you get support for the temperature and - voltage sensors of the SMSC LPC47M192, LPC47M15x, LPC47M292 - and LPC47M997 chips. - - The fan monitoring and control capabilities of these chips - are supported by another driver, select - "SMSC LPC47M10x and compatibles" above. You need both drivers - if you want fan control and voltage/temperature sensor support. - - This driver can also be built as a module. If so, the module - will be called smsc47m192. - -config SENSORS_SMSC47B397 - tristate "SMSC LPC47B397-NC" - depends on !PPC - help - If you say yes here you get support for the SMSC LPC47B397-NC - sensor chip. - - This driver can also be built as a module. If so, the module - will be called smsc47b397. - -config SENSORS_SCH56XX_COMMON - tristate - default n - -config SENSORS_SCH5627 - tristate "SMSC SCH5627" - depends on !PPC && WATCHDOG - select SENSORS_SCH56XX_COMMON - select WATCHDOG_CORE - help - If you say yes here you get support for the hardware monitoring - features of the SMSC SCH5627 Super-I/O chip including support for - the integrated watchdog. - - This driver can also be built as a module. If so, the module - will be called sch5627. - -config SENSORS_SCH5636 - tristate "SMSC SCH5636" - depends on !PPC && WATCHDOG - select SENSORS_SCH56XX_COMMON - select WATCHDOG_CORE - help - SMSC SCH5636 Super I/O chips include an embedded microcontroller for - hardware monitoring solutions, allowing motherboard manufacturers to - create their own custom hwmon solution based upon the SCH5636. - - Currently this driver only supports the Fujitsu Theseus SCH5636 based - hwmon solution. Say yes here if you want support for the Fujitsu - Theseus' hardware monitoring features including support for the - integrated watchdog. - - This driver can also be built as a module. If so, the module - will be called sch5636. - -config SENSORS_SMM665 - tristate "Summit Microelectronics SMM665" - depends on I2C - default n - help - If you say yes here you get support for the hardware monitoring - features of the Summit Microelectronics SMM665/SMM665B Six-Channel - Active DC Output Controller / Monitor. - - Other supported chips are SMM465, SMM665C, SMM764, and SMM766. - Support for those chips is untested. - - This driver can also be built as a module. If so, the module will - be called smm665. - -config SENSORS_ADC128D818 - tristate "Texas Instruments ADC128D818" - depends on I2C - help - If you say yes here you get support for the Texas Instruments - ADC128D818 System Monitor with Temperature Sensor chip. - - This driver can also be built as a module. If so, the module - will be called adc128d818. - -config SENSORS_ADS1015 - tristate "Texas Instruments ADS1015" - depends on I2C - help - If you say yes here you get support for Texas Instruments - ADS1015/ADS1115 12/16-bit 4-input ADC device. - - This driver can also be built as a module. If so, the module - will be called ads1015. - -config SENSORS_ADS7828 - tristate "Texas Instruments ADS7828 and compatibles" - depends on I2C - select REGMAP_I2C - help - If you say yes here you get support for Texas Instruments ADS7828 and - ADS7830 8-channel A/D converters. ADS7828 resolution is 12-bit, while - it is 8-bit on ADS7830. - - This driver can also be built as a module. If so, the module - will be called ads7828. - -config SENSORS_ADS7871 - tristate "Texas Instruments ADS7871 A/D converter" - depends on SPI - help - If you say yes here you get support for TI ADS7871 & ADS7870 - - This driver can also be built as a module. If so, the module - will be called ads7871. - -config SENSORS_AMC6821 - tristate "Texas Instruments AMC6821" - depends on I2C - help - If you say yes here you get support for the Texas Instruments - AMC6821 hardware monitoring chips. - - This driver can also be build as a module. If so, the module - will be called amc6821. - -config SENSORS_INA209 - tristate "TI / Burr Brown INA209" - depends on I2C - help - If you say yes here you get support for the TI / Burr Brown INA209 - voltage / current / power monitor I2C interface. - - This driver can also be built as a module. If so, the module will - be called ina209. - -config SENSORS_INA2XX - tristate "Texas Instruments INA219 and compatibles" - depends on I2C - select REGMAP_I2C - help - If you say yes here you get support for INA219, INA220, INA226, - INA230, and INA231 power monitor chips. - - The INA2xx driver is configured for the default configuration of - the part as described in the datasheet. - Default value for Rshunt is 10 mOhms. - This driver can also be built as a module. If so, the module - will be called ina2xx. - -config SENSORS_INA3221 - tristate "Texas Instruments INA3221 Triple Power Monitor" - depends on I2C - select REGMAP_I2C - help - If you say yes here you get support for the TI INA3221 Triple Power - Monitor. - - This driver can also be built as a module. If so, the module - will be called ina3221. - -config SENSORS_TC74 - tristate "Microchip TC74" - depends on I2C - help - If you say yes here you get support for Microchip TC74 single - input temperature sensor chips. - - This driver can also be built as a module. If so, the module - will be called tc74. - -config SENSORS_THMC50 - tristate "Texas Instruments THMC50 / Analog Devices ADM1022" - depends on I2C - help - If you say yes here you get support for Texas Instruments THMC50 - sensor chips and clones: the Analog Devices ADM1022. - - This driver can also be built as a module. If so, the module - will be called thmc50. - -config SENSORS_TMP102 - tristate "Texas Instruments TMP102" - depends on I2C - select REGMAP_I2C - help - If you say yes here you get support for Texas Instruments TMP102 - sensor chips. - - This driver can also be built as a module. If so, the module - will be called tmp102. - -config SENSORS_TMP103 - tristate "Texas Instruments TMP103" - depends on I2C - select REGMAP_I2C - help - If you say yes here you get support for Texas Instruments TMP103 - sensor chips. - - This driver can also be built as a module. If so, the module - will be called tmp103. - -config SENSORS_TMP401 - tristate "Texas Instruments TMP401 and compatibles" - depends on I2C - help - If you say yes here you get support for Texas Instruments TMP401, - TMP411, TMP431, TMP432, TMP435, and TMP461 temperature sensor chips. - - This driver can also be built as a module. If so, the module - will be called tmp401. - -config SENSORS_TMP421 - tristate "Texas Instruments TMP421 and compatible" - depends on I2C - help - If you say yes here you get support for Texas Instruments TMP421, - TMP422, TMP423, TMP441, and TMP442 temperature sensor chips. - - This driver can also be built as a module. If so, the module - will be called tmp421. - -config SENSORS_TWL4030_MADC - tristate "Texas Instruments TWL4030 MADC Hwmon" - depends on TWL4030_MADC - help - If you say yes here you get hwmon support for triton - TWL4030-MADC. - - This driver can also be built as a module. If so it will be called - twl4030-madc-hwmon. - -config SENSORS_VEXPRESS - tristate "Versatile Express" - depends on VEXPRESS_CONFIG - help - This driver provides support for hardware sensors available on - the ARM Ltd's Versatile Express platform. It can provide wide - range of information like temperature, power, energy. - -config SENSORS_VIA_CPUTEMP - tristate "VIA CPU temperature sensor" - depends on X86 - select HWMON_VID - help - If you say yes here you get support for the temperature - sensor inside your CPU. Supported are all known variants of - the VIA C7 and Nano. - -config SENSORS_VIA686A - tristate "VIA686A" - depends on PCI - help - If you say yes here you get support for the integrated sensors in - Via 686A/B South Bridges. - - This driver can also be built as a module. If so, the module - will be called via686a. - -config SENSORS_VT1211 - tristate "VIA VT1211" - depends on !PPC - select HWMON_VID - help - If you say yes here then you get support for hardware monitoring - features of the VIA VT1211 Super-I/O chip. - - This driver can also be built as a module. If so, the module - will be called vt1211. - -config SENSORS_VT8231 - tristate "VIA VT8231" - depends on PCI - select HWMON_VID - help - If you say yes here then you get support for the integrated sensors - in the VIA VT8231 device. - - This driver can also be built as a module. If so, the module - will be called vt8231. - -config SENSORS_W83781D - tristate "Winbond W83781D, W83782D, W83783S, Asus AS99127F" - depends on I2C - select HWMON_VID - help - If you say yes here you get support for the Winbond W8378x series - of sensor chips: the W83781D, W83782D and W83783S, and the similar - Asus AS99127F. - - This driver can also be built as a module. If so, the module - will be called w83781d. - -config SENSORS_W83791D - tristate "Winbond W83791D" - depends on I2C - select HWMON_VID - help - If you say yes here you get support for the Winbond W83791D chip. - - This driver can also be built as a module. If so, the module - will be called w83791d. - -config SENSORS_W83792D - tristate "Winbond W83792D" - depends on I2C - help - If you say yes here you get support for the Winbond W83792D chip. - - This driver can also be built as a module. If so, the module - will be called w83792d. - -config SENSORS_W83793 - tristate "Winbond W83793" - depends on I2C - select HWMON_VID - help - If you say yes here you get support for the Winbond W83793 - hardware monitoring chip, including support for the integrated - watchdog. - - This driver can also be built as a module. If so, the module - will be called w83793. - -config SENSORS_W83795 - tristate "Winbond/Nuvoton W83795G/ADG" - depends on I2C - help - If you say yes here you get support for the Winbond W83795G and - W83795ADG hardware monitoring chip, including manual fan speed - control. - - This driver can also be built as a module. If so, the module - will be called w83795. - -config SENSORS_W83795_FANCTRL - bool "Include automatic fan control support (DANGEROUS)" - depends on SENSORS_W83795 - default n - help - If you say yes here, support for automatic fan speed control - will be included in the driver. - - This part of the code wasn't carefully reviewed and tested yet, - so enabling this option is strongly discouraged on production - servers. Only developers and testers should enable it for the - time being. - - Please also note that this option will create sysfs attribute - files which may change in the future, so you shouldn't rely - on them being stable. - -config SENSORS_W83L785TS - tristate "Winbond W83L785TS-S" - depends on I2C - help - If you say yes here you get support for the Winbond W83L785TS-S - sensor chip, which is used on the Asus A7N8X, among other - motherboards. - - This driver can also be built as a module. If so, the module - will be called w83l785ts. - -config SENSORS_W83L786NG - tristate "Winbond W83L786NG, W83L786NR" - depends on I2C - help - If you say yes here you get support for the Winbond W83L786NG - and W83L786NR sensor chips. - - This driver can also be built as a module. If so, the module - will be called w83l786ng. - -config SENSORS_W83627HF - tristate "Winbond W83627HF, W83627THF, W83637HF, W83687THF, W83697HF" - depends on !PPC - select HWMON_VID - help - If you say yes here you get support for the Winbond W836X7 series - of sensor chips: the W83627HF, W83627THF, W83637HF, W83687THF and - W83697HF. - - This driver can also be built as a module. If so, the module - will be called w83627hf. - -config SENSORS_W83627EHF - tristate "Winbond W83627EHF/EHG/DHG/UHG, W83667HG, NCT6775F, NCT6776F" - depends on !PPC - select HWMON_VID - help - If you say yes here you get support for the hardware - monitoring functionality of the Winbond W83627EHF Super-I/O chip. - - This driver also supports the W83627EHG, which is the lead-free - version of the W83627EHF, and the W83627DHG, which is a similar - chip suited for specific Intel processors that use PECI such as - the Core 2 Duo. And also the W83627UHG, which is a stripped down - version of the W83627DHG (as far as hardware monitoring goes.) - - This driver also supports Nuvoton W83667HG, W83667HG-B, NCT6775F - (also known as W83667HG-I), and NCT6776F. - - This driver can also be built as a module. If so, the module - will be called w83627ehf. - -config SENSORS_WM831X - tristate "WM831x PMICs" - depends on MFD_WM831X - help - If you say yes here you get support for the hardware - monitoring functionality of the Wolfson Microelectronics - WM831x series of PMICs. - - This driver can also be built as a module. If so, the module - will be called wm831x-hwmon. - -config SENSORS_WM8350 - tristate "Wolfson Microelectronics WM835x" - depends on MFD_WM8350 - help - If you say yes here you get support for the hardware - monitoring features of the WM835x series of PMICs. - - This driver can also be built as a module. If so, the module - will be called wm8350-hwmon. - -config SENSORS_ULTRA45 - tristate "Sun Ultra45 PIC16F747" - depends on SPARC64 - help - This driver provides support for the Ultra45 workstation environmental - sensors. - -config SENSORS_XGENE - tristate "APM X-Gene SoC hardware monitoring driver" - depends on XGENE_SLIMPRO_MBOX || PCC - help - If you say yes here you get support for the temperature - and power sensors for APM X-Gene SoC. - -if ACPI - -comment "ACPI drivers" - -config SENSORS_ACPI_POWER - tristate "ACPI 4.0 power meter" - help - This driver exposes ACPI 4.0 power meters as hardware monitoring - devices. Say Y (or M) if you have a computer with ACPI 4.0 firmware - and a power meter. - - To compile this driver as a module, choose M here: - the module will be called acpi_power_meter. - -config SENSORS_ATK0110 - tristate "ASUS ATK0110" - depends on X86 - help - If you say yes here you get support for the ACPI hardware - monitoring interface found in many ASUS motherboards. This - driver will provide readings of fans, voltages and temperatures - through the system firmware. - - This driver can also be built as a module. If so, the module - will be called asus_atk0110. - -endif # ACPI - -endif # HWMON diff --git a/src/linux/drivers/hwmon/Makefile b/src/linux/drivers/hwmon/Makefile deleted file mode 100644 index aecf4ba..0000000 --- a/src/linux/drivers/hwmon/Makefile +++ /dev/null @@ -1,173 +0,0 @@ -# -# Makefile for sensor chip drivers. -# - -obj-$(CONFIG_HWMON) += hwmon.o -obj-$(CONFIG_HWMON_VID) += hwmon-vid.o - -# APCI drivers -obj-$(CONFIG_SENSORS_ACPI_POWER) += acpi_power_meter.o -obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o - -# Native drivers -# asb100, then w83781d go first, as they can override other drivers' addresses. -obj-$(CONFIG_SENSORS_ASB100) += asb100.o -obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o -obj-$(CONFIG_SENSORS_W83792D) += w83792d.o -obj-$(CONFIG_SENSORS_W83793) += w83793.o -obj-$(CONFIG_SENSORS_W83795) += w83795.o -obj-$(CONFIG_SENSORS_W83781D) += w83781d.o -obj-$(CONFIG_SENSORS_W83791D) += w83791d.o - -obj-$(CONFIG_SENSORS_AB8500) += abx500.o ab8500.o -obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o -obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o -obj-$(CONFIG_SENSORS_AD7314) += ad7314.o -obj-$(CONFIG_SENSORS_AD7414) += ad7414.o -obj-$(CONFIG_SENSORS_AD7418) += ad7418.o -obj-$(CONFIG_SENSORS_ADC128D818) += adc128d818.o -obj-$(CONFIG_SENSORS_ADCXX) += adcxx.o -obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o -obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o -obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o -obj-$(CONFIG_SENSORS_ADM1029) += adm1029.o -obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o -obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o -obj-$(CONFIG_SENSORS_ADS1015) += ads1015.o -obj-$(CONFIG_SENSORS_ADS7828) += ads7828.o -obj-$(CONFIG_SENSORS_ADS7871) += ads7871.o -obj-$(CONFIG_SENSORS_ADT7X10) += adt7x10.o -obj-$(CONFIG_SENSORS_ADT7310) += adt7310.o -obj-$(CONFIG_SENSORS_ADT7410) += adt7410.o -obj-$(CONFIG_SENSORS_ADT7411) += adt7411.o -obj-$(CONFIG_SENSORS_ADT7462) += adt7462.o -obj-$(CONFIG_SENSORS_ADT7470) += adt7470.o -obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o -obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o -obj-$(CONFIG_SENSORS_ARM_SCPI) += scpi-hwmon.o -obj-$(CONFIG_SENSORS_ASC7621) += asc7621.o -obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o -obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o -obj-$(CONFIG_SENSORS_DA9052_ADC)+= da9052-hwmon.o -obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o -obj-$(CONFIG_SENSORS_DELL_SMM) += dell-smm-hwmon.o -obj-$(CONFIG_SENSORS_DME1737) += dme1737.o -obj-$(CONFIG_SENSORS_DS620) += ds620.o -obj-$(CONFIG_SENSORS_DS1621) += ds1621.o -obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o -obj-$(CONFIG_SENSORS_EMC2103) += emc2103.o -obj-$(CONFIG_SENSORS_EMC6W201) += emc6w201.o -obj-$(CONFIG_SENSORS_F71805F) += f71805f.o -obj-$(CONFIG_SENSORS_F71882FG) += f71882fg.o -obj-$(CONFIG_SENSORS_F75375S) += f75375s.o -obj-$(CONFIG_SENSORS_FAM15H_POWER) += fam15h_power.o -obj-$(CONFIG_SENSORS_FSCHMD) += fschmd.o -obj-$(CONFIG_SENSORS_FTSTEUTATES) += ftsteutates.o -obj-$(CONFIG_SENSORS_G760A) += g760a.o -obj-$(CONFIG_SENSORS_G762) += g762.o -obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o -obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o -obj-$(CONFIG_SENSORS_GPIO_FAN) += gpio-fan.o -obj-$(CONFIG_SENSORS_HIH6130) += hih6130.o -obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o -obj-$(CONFIG_SENSORS_I5500) += i5500_temp.o -obj-$(CONFIG_SENSORS_I5K_AMB) += i5k_amb.o -obj-$(CONFIG_SENSORS_IBMAEM) += ibmaem.o -obj-$(CONFIG_SENSORS_IBMPEX) += ibmpex.o -obj-$(CONFIG_SENSORS_IBMPOWERNV)+= ibmpowernv.o -obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o -obj-$(CONFIG_SENSORS_INA209) += ina209.o -obj-$(CONFIG_SENSORS_INA2XX) += ina2xx.o -obj-$(CONFIG_SENSORS_INA3221) += ina3221.o -obj-$(CONFIG_SENSORS_IT87) += it87.o -obj-$(CONFIG_SENSORS_JC42) += jc42.o -obj-$(CONFIG_SENSORS_JZ4740) += jz4740-hwmon.o -obj-$(CONFIG_SENSORS_K8TEMP) += k8temp.o -obj-$(CONFIG_SENSORS_K10TEMP) += k10temp.o -obj-$(CONFIG_SENSORS_LINEAGE) += lineage-pem.o -obj-$(CONFIG_SENSORS_LM63) += lm63.o -obj-$(CONFIG_SENSORS_LM70) += lm70.o -obj-$(CONFIG_SENSORS_LM73) += lm73.o -obj-$(CONFIG_SENSORS_LM75) += lm75.o -obj-$(CONFIG_SENSORS_LM77) += lm77.o -obj-$(CONFIG_SENSORS_LM78) += lm78.o -obj-$(CONFIG_SENSORS_LM80) += lm80.o -obj-$(CONFIG_SENSORS_LM83) += lm83.o -obj-$(CONFIG_SENSORS_LM85) += lm85.o -obj-$(CONFIG_SENSORS_LM87) += lm87.o -obj-$(CONFIG_SENSORS_LM90) += lm90.o -obj-$(CONFIG_SENSORS_LM92) += lm92.o -obj-$(CONFIG_SENSORS_LM93) += lm93.o -obj-$(CONFIG_SENSORS_LM95234) += lm95234.o -obj-$(CONFIG_SENSORS_LM95241) += lm95241.o -obj-$(CONFIG_SENSORS_LM95245) += lm95245.o -obj-$(CONFIG_SENSORS_LTC2945) += ltc2945.o -obj-$(CONFIG_SENSORS_LTC2990) += ltc2990.o -obj-$(CONFIG_SENSORS_LTC4151) += ltc4151.o -obj-$(CONFIG_SENSORS_LTC4215) += ltc4215.o -obj-$(CONFIG_SENSORS_LTC4222) += ltc4222.o -obj-$(CONFIG_SENSORS_LTC4245) += ltc4245.o -obj-$(CONFIG_SENSORS_LTC4260) += ltc4260.o -obj-$(CONFIG_SENSORS_LTC4261) += ltc4261.o -obj-$(CONFIG_SENSORS_MAX1111) += max1111.o -obj-$(CONFIG_SENSORS_MAX16065) += max16065.o -obj-$(CONFIG_SENSORS_MAX1619) += max1619.o -obj-$(CONFIG_SENSORS_MAX1668) += max1668.o -obj-$(CONFIG_SENSORS_MAX197) += max197.o -obj-$(CONFIG_SENSORS_MAX31722) += max31722.o -obj-$(CONFIG_SENSORS_MAX6639) += max6639.o -obj-$(CONFIG_SENSORS_MAX6642) += max6642.o -obj-$(CONFIG_SENSORS_MAX6650) += max6650.o -obj-$(CONFIG_SENSORS_MAX6697) += max6697.o -obj-$(CONFIG_SENSORS_MAX31790) += max31790.o -obj-$(CONFIG_SENSORS_MC13783_ADC)+= mc13783-adc.o -obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o -obj-$(CONFIG_SENSORS_MENF21BMC_HWMON) += menf21bmc_hwmon.o -obj-$(CONFIG_SENSORS_NCT6683) += nct6683.o -obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o -obj-$(CONFIG_SENSORS_NCT7802) += nct7802.o -obj-$(CONFIG_SENSORS_NCT7904) += nct7904.o -obj-$(CONFIG_SENSORS_NSA320) += nsa320-hwmon.o -obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o -obj-$(CONFIG_SENSORS_PC87360) += pc87360.o -obj-$(CONFIG_SENSORS_PC87427) += pc87427.o -obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o -obj-$(CONFIG_SENSORS_POWR1220) += powr1220.o -obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o -obj-$(CONFIG_SENSORS_S3C) += s3c-hwmon.o -obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o -obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o -obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o -obj-$(CONFIG_SENSORS_SHT15) += sht15.o -obj-$(CONFIG_SENSORS_SHT21) += sht21.o -obj-$(CONFIG_SENSORS_SHT3x) += sht3x.o -obj-$(CONFIG_SENSORS_SHTC1) += shtc1.o -obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o -obj-$(CONFIG_SENSORS_SMM665) += smm665.o -obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o -obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o -obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o -obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o -obj-$(CONFIG_SENSORS_TC74) += tc74.o -obj-$(CONFIG_SENSORS_THMC50) += thmc50.o -obj-$(CONFIG_SENSORS_TMP102) += tmp102.o -obj-$(CONFIG_SENSORS_TMP103) += tmp103.o -obj-$(CONFIG_SENSORS_TMP401) += tmp401.o -obj-$(CONFIG_SENSORS_TMP421) += tmp421.o -obj-$(CONFIG_SENSORS_TWL4030_MADC)+= twl4030-madc-hwmon.o -obj-$(CONFIG_SENSORS_VEXPRESS) += vexpress-hwmon.o -obj-$(CONFIG_SENSORS_VIA_CPUTEMP)+= via-cputemp.o -obj-$(CONFIG_SENSORS_VIA686A) += via686a.o -obj-$(CONFIG_SENSORS_VT1211) += vt1211.o -obj-$(CONFIG_SENSORS_VT8231) += vt8231.o -obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o -obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o -obj-$(CONFIG_SENSORS_W83L786NG) += w83l786ng.o -obj-$(CONFIG_SENSORS_WM831X) += wm831x-hwmon.o -obj-$(CONFIG_SENSORS_WM8350) += wm8350-hwmon.o -obj-$(CONFIG_SENSORS_XGENE) += xgene-hwmon.o - -obj-$(CONFIG_PMBUS) += pmbus/ - -ccflags-$(CONFIG_HWMON_DEBUG_CHIP) := -DDEBUG - diff --git a/src/linux/drivers/hwmon/hwmon.c b/src/linux/drivers/hwmon/hwmon.c deleted file mode 100644 index a74c075..0000000 --- a/src/linux/drivers/hwmon/hwmon.c +++ /dev/null @@ -1,841 +0,0 @@ -/* - * hwmon.c - part of lm_sensors, Linux kernel modules for hardware monitoring - * - * This file defines the sysfs class "hwmon", for use by sensors drivers. - * - * Copyright (C) 2005 Mark M. Hoffman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define HWMON_ID_PREFIX "hwmon" -#define HWMON_ID_FORMAT HWMON_ID_PREFIX "%d" - -struct hwmon_device { - const char *name; - struct device dev; - const struct hwmon_chip_info *chip; - - struct attribute_group group; - const struct attribute_group **groups; -}; - -#define to_hwmon_device(d) container_of(d, struct hwmon_device, dev) - -struct hwmon_device_attribute { - struct device_attribute dev_attr; - const struct hwmon_ops *ops; - enum hwmon_sensor_types type; - u32 attr; - int index; -}; - -#define to_hwmon_attr(d) \ - container_of(d, struct hwmon_device_attribute, dev_attr) - -/* - * Thermal zone information - * In addition to the reference to the hwmon device, - * also provides the sensor index. - */ -struct hwmon_thermal_data { - struct hwmon_device *hwdev; /* Reference to hwmon device */ - int index; /* sensor index */ -}; - -static ssize_t -show_name(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s\n", to_hwmon_device(dev)->name); -} -static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); - -static struct attribute *hwmon_dev_attrs[] = { - &dev_attr_name.attr, - NULL -}; - -static umode_t hwmon_dev_name_is_visible(struct kobject *kobj, - struct attribute *attr, int n) -{ - struct device *dev = container_of(kobj, struct device, kobj); - - if (to_hwmon_device(dev)->name == NULL) - return 0; - - return attr->mode; -} - -static struct attribute_group hwmon_dev_attr_group = { - .attrs = hwmon_dev_attrs, - .is_visible = hwmon_dev_name_is_visible, -}; - -static const struct attribute_group *hwmon_dev_attr_groups[] = { - &hwmon_dev_attr_group, - NULL -}; - -static void hwmon_dev_release(struct device *dev) -{ - kfree(to_hwmon_device(dev)); -} - -static struct class hwmon_class = { - .name = "hwmon", - .owner = THIS_MODULE, - .dev_groups = hwmon_dev_attr_groups, - .dev_release = hwmon_dev_release, -}; - -static DEFINE_IDA(hwmon_ida); - -/* Thermal zone handling */ - -/* - * The complex conditional is necessary to avoid a cyclic dependency - * between hwmon and thermal_sys modules. - */ -#if IS_REACHABLE(CONFIG_THERMAL) && defined(CONFIG_THERMAL_OF) && \ - (!defined(CONFIG_THERMAL_HWMON) || \ - !(defined(MODULE) && IS_MODULE(CONFIG_THERMAL))) -static int hwmon_thermal_get_temp(void *data, int *temp) -{ - struct hwmon_thermal_data *tdata = data; - struct hwmon_device *hwdev = tdata->hwdev; - int ret; - long t; - - ret = hwdev->chip->ops->read(&hwdev->dev, hwmon_temp, hwmon_temp_input, - tdata->index, &t); - if (ret < 0) - return ret; - - *temp = t; - - return 0; -} - -static struct thermal_zone_of_device_ops hwmon_thermal_ops = { - .get_temp = hwmon_thermal_get_temp, -}; - -static int hwmon_thermal_add_sensor(struct device *dev, - struct hwmon_device *hwdev, int index) -{ - struct hwmon_thermal_data *tdata; - - tdata = devm_kzalloc(dev, sizeof(*tdata), GFP_KERNEL); - if (!tdata) - return -ENOMEM; - - tdata->hwdev = hwdev; - tdata->index = index; - - devm_thermal_zone_of_sensor_register(&hwdev->dev, index, tdata, - &hwmon_thermal_ops); - - return 0; -} -#else -static int hwmon_thermal_add_sensor(struct device *dev, - struct hwmon_device *hwdev, int index) -{ - return 0; -} -#endif /* IS_REACHABLE(CONFIG_THERMAL) && ... */ - -/* sysfs attribute management */ - -static ssize_t hwmon_attr_show(struct device *dev, - struct device_attribute *devattr, char *buf) -{ - struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); - long val; - int ret; - - ret = hattr->ops->read(dev, hattr->type, hattr->attr, hattr->index, - &val); - if (ret < 0) - return ret; - - return sprintf(buf, "%ld\n", val); -} - -static ssize_t hwmon_attr_store(struct device *dev, - struct device_attribute *devattr, - const char *buf, size_t count) -{ - struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); - long val; - int ret; - - ret = kstrtol(buf, 10, &val); - if (ret < 0) - return ret; - - ret = hattr->ops->write(dev, hattr->type, hattr->attr, hattr->index, - val); - if (ret < 0) - return ret; - - return count; -} - -static int hwmon_attr_base(enum hwmon_sensor_types type) -{ - if (type == hwmon_in) - return 0; - return 1; -} - -static struct attribute *hwmon_genattr(struct device *dev, - const void *drvdata, - enum hwmon_sensor_types type, - u32 attr, - int index, - const char *template, - const struct hwmon_ops *ops) -{ - struct hwmon_device_attribute *hattr; - struct device_attribute *dattr; - struct attribute *a; - umode_t mode; - char *name; - - /* The attribute is invisible if there is no template string */ - if (!template) - return ERR_PTR(-ENOENT); - - mode = ops->is_visible(drvdata, type, attr, index); - if (!mode) - return ERR_PTR(-ENOENT); - - if ((mode & S_IRUGO) && !ops->read) - return ERR_PTR(-EINVAL); - if ((mode & S_IWUGO) && !ops->write) - return ERR_PTR(-EINVAL); - - if (type == hwmon_chip) { - name = (char *)template; - } else { - name = devm_kzalloc(dev, strlen(template) + 16, GFP_KERNEL); - if (!name) - return ERR_PTR(-ENOMEM); - scnprintf(name, strlen(template) + 16, template, - index + hwmon_attr_base(type)); - } - - hattr = devm_kzalloc(dev, sizeof(*hattr), GFP_KERNEL); - if (!hattr) - return ERR_PTR(-ENOMEM); - - hattr->type = type; - hattr->attr = attr; - hattr->index = index; - hattr->ops = ops; - - dattr = &hattr->dev_attr; - dattr->show = hwmon_attr_show; - dattr->store = hwmon_attr_store; - - a = &dattr->attr; - sysfs_attr_init(a); - a->name = name; - a->mode = mode; - - return a; -} - -static const char * const hwmon_chip_attr_templates[] = { - [hwmon_chip_temp_reset_history] = "temp_reset_history", - [hwmon_chip_in_reset_history] = "in_reset_history", - [hwmon_chip_curr_reset_history] = "curr_reset_history", - [hwmon_chip_power_reset_history] = "power_reset_history", - [hwmon_chip_update_interval] = "update_interval", - [hwmon_chip_alarms] = "alarms", -}; - -static const char * const hwmon_temp_attr_templates[] = { - [hwmon_temp_input] = "temp%d_input", - [hwmon_temp_type] = "temp%d_type", - [hwmon_temp_lcrit] = "temp%d_lcrit", - [hwmon_temp_lcrit_hyst] = "temp%d_lcrit_hyst", - [hwmon_temp_min] = "temp%d_min", - [hwmon_temp_min_hyst] = "temp%d_min_hyst", - [hwmon_temp_max] = "temp%d_max", - [hwmon_temp_max_hyst] = "temp%d_max_hyst", - [hwmon_temp_crit] = "temp%d_crit", - [hwmon_temp_crit_hyst] = "temp%d_crit_hyst", - [hwmon_temp_emergency] = "temp%d_emergency", - [hwmon_temp_emergency_hyst] = "temp%d_emergency_hyst", - [hwmon_temp_alarm] = "temp%d_alarm", - [hwmon_temp_lcrit_alarm] = "temp%d_lcrit_alarm", - [hwmon_temp_min_alarm] = "temp%d_min_alarm", - [hwmon_temp_max_alarm] = "temp%d_max_alarm", - [hwmon_temp_crit_alarm] = "temp%d_crit_alarm", - [hwmon_temp_emergency_alarm] = "temp%d_emergency_alarm", - [hwmon_temp_fault] = "temp%d_fault", - [hwmon_temp_offset] = "temp%d_offset", - [hwmon_temp_label] = "temp%d_label", - [hwmon_temp_lowest] = "temp%d_lowest", - [hwmon_temp_highest] = "temp%d_highest", - [hwmon_temp_reset_history] = "temp%d_reset_history", -}; - -static const char * const hwmon_in_attr_templates[] = { - [hwmon_in_input] = "in%d_input", - [hwmon_in_min] = "in%d_min", - [hwmon_in_max] = "in%d_max", - [hwmon_in_lcrit] = "in%d_lcrit", - [hwmon_in_crit] = "in%d_crit", - [hwmon_in_average] = "in%d_average", - [hwmon_in_lowest] = "in%d_lowest", - [hwmon_in_highest] = "in%d_highest", - [hwmon_in_reset_history] = "in%d_reset_history", - [hwmon_in_label] = "in%d_label", - [hwmon_in_alarm] = "in%d_alarm", - [hwmon_in_min_alarm] = "in%d_min_alarm", - [hwmon_in_max_alarm] = "in%d_max_alarm", - [hwmon_in_lcrit_alarm] = "in%d_lcrit_alarm", - [hwmon_in_crit_alarm] = "in%d_crit_alarm", -}; - -static const char * const hwmon_curr_attr_templates[] = { - [hwmon_curr_input] = "curr%d_input", - [hwmon_curr_min] = "curr%d_min", - [hwmon_curr_max] = "curr%d_max", - [hwmon_curr_lcrit] = "curr%d_lcrit", - [hwmon_curr_crit] = "curr%d_crit", - [hwmon_curr_average] = "curr%d_average", - [hwmon_curr_lowest] = "curr%d_lowest", - [hwmon_curr_highest] = "curr%d_highest", - [hwmon_curr_reset_history] = "curr%d_reset_history", - [hwmon_curr_label] = "curr%d_label", - [hwmon_curr_alarm] = "curr%d_alarm", - [hwmon_curr_min_alarm] = "curr%d_min_alarm", - [hwmon_curr_max_alarm] = "curr%d_max_alarm", - [hwmon_curr_lcrit_alarm] = "curr%d_lcrit_alarm", - [hwmon_curr_crit_alarm] = "curr%d_crit_alarm", -}; - -static const char * const hwmon_power_attr_templates[] = { - [hwmon_power_average] = "power%d_average", - [hwmon_power_average_interval] = "power%d_average_interval", - [hwmon_power_average_interval_max] = "power%d_interval_max", - [hwmon_power_average_interval_min] = "power%d_interval_min", - [hwmon_power_average_highest] = "power%d_average_highest", - [hwmon_power_average_lowest] = "power%d_average_lowest", - [hwmon_power_average_max] = "power%d_average_max", - [hwmon_power_average_min] = "power%d_average_min", - [hwmon_power_input] = "power%d_input", - [hwmon_power_input_highest] = "power%d_input_highest", - [hwmon_power_input_lowest] = "power%d_input_lowest", - [hwmon_power_reset_history] = "power%d_reset_history", - [hwmon_power_accuracy] = "power%d_accuracy", - [hwmon_power_cap] = "power%d_cap", - [hwmon_power_cap_hyst] = "power%d_cap_hyst", - [hwmon_power_cap_max] = "power%d_cap_max", - [hwmon_power_cap_min] = "power%d_cap_min", - [hwmon_power_max] = "power%d_max", - [hwmon_power_crit] = "power%d_crit", - [hwmon_power_label] = "power%d_label", - [hwmon_power_alarm] = "power%d_alarm", - [hwmon_power_cap_alarm] = "power%d_cap_alarm", - [hwmon_power_max_alarm] = "power%d_max_alarm", - [hwmon_power_crit_alarm] = "power%d_crit_alarm", -}; - -static const char * const hwmon_energy_attr_templates[] = { - [hwmon_energy_input] = "energy%d_input", - [hwmon_energy_label] = "energy%d_label", -}; - -static const char * const hwmon_humidity_attr_templates[] = { - [hwmon_humidity_input] = "humidity%d_input", - [hwmon_humidity_label] = "humidity%d_label", - [hwmon_humidity_min] = "humidity%d_min", - [hwmon_humidity_min_hyst] = "humidity%d_min_hyst", - [hwmon_humidity_max] = "humidity%d_max", - [hwmon_humidity_max_hyst] = "humidity%d_max_hyst", - [hwmon_humidity_alarm] = "humidity%d_alarm", - [hwmon_humidity_fault] = "humidity%d_fault", -}; - -static const char * const hwmon_fan_attr_templates[] = { - [hwmon_fan_input] = "fan%d_input", - [hwmon_fan_label] = "fan%d_label", - [hwmon_fan_min] = "fan%d_min", - [hwmon_fan_max] = "fan%d_max", - [hwmon_fan_div] = "fan%d_div", - [hwmon_fan_pulses] = "fan%d_pulses", - [hwmon_fan_target] = "fan%d_target", - [hwmon_fan_alarm] = "fan%d_alarm", - [hwmon_fan_min_alarm] = "fan%d_min_alarm", - [hwmon_fan_max_alarm] = "fan%d_max_alarm", - [hwmon_fan_fault] = "fan%d_fault", -}; - -static const char * const hwmon_pwm_attr_templates[] = { - [hwmon_pwm_input] = "pwm%d", - [hwmon_pwm_enable] = "pwm%d_enable", - [hwmon_pwm_mode] = "pwm%d_mode", - [hwmon_pwm_freq] = "pwm%d_freq", -}; - -static const char * const *__templates[] = { - [hwmon_chip] = hwmon_chip_attr_templates, - [hwmon_temp] = hwmon_temp_attr_templates, - [hwmon_in] = hwmon_in_attr_templates, - [hwmon_curr] = hwmon_curr_attr_templates, - [hwmon_power] = hwmon_power_attr_templates, - [hwmon_energy] = hwmon_energy_attr_templates, - [hwmon_humidity] = hwmon_humidity_attr_templates, - [hwmon_fan] = hwmon_fan_attr_templates, - [hwmon_pwm] = hwmon_pwm_attr_templates, -}; - -static const int __templates_size[] = { - [hwmon_chip] = ARRAY_SIZE(hwmon_chip_attr_templates), - [hwmon_temp] = ARRAY_SIZE(hwmon_temp_attr_templates), - [hwmon_in] = ARRAY_SIZE(hwmon_in_attr_templates), - [hwmon_curr] = ARRAY_SIZE(hwmon_curr_attr_templates), - [hwmon_power] = ARRAY_SIZE(hwmon_power_attr_templates), - [hwmon_energy] = ARRAY_SIZE(hwmon_energy_attr_templates), - [hwmon_humidity] = ARRAY_SIZE(hwmon_humidity_attr_templates), - [hwmon_fan] = ARRAY_SIZE(hwmon_fan_attr_templates), - [hwmon_pwm] = ARRAY_SIZE(hwmon_pwm_attr_templates), -}; - -static int hwmon_num_channel_attrs(const struct hwmon_channel_info *info) -{ - int i, n; - - for (i = n = 0; info->config[i]; i++) - n += hweight32(info->config[i]); - - return n; -} - -static int hwmon_genattrs(struct device *dev, - const void *drvdata, - struct attribute **attrs, - const struct hwmon_ops *ops, - const struct hwmon_channel_info *info) -{ - const char * const *templates; - int template_size; - int i, aindex = 0; - - if (info->type >= ARRAY_SIZE(__templates)) - return -EINVAL; - - templates = __templates[info->type]; - template_size = __templates_size[info->type]; - - for (i = 0; info->config[i]; i++) { - u32 attr_mask = info->config[i]; - u32 attr; - - while (attr_mask) { - struct attribute *a; - - attr = __ffs(attr_mask); - attr_mask &= ~BIT(attr); - if (attr >= template_size) - return -EINVAL; - a = hwmon_genattr(dev, drvdata, info->type, attr, i, - templates[attr], ops); - if (IS_ERR(a)) { - if (PTR_ERR(a) != -ENOENT) - return PTR_ERR(a); - continue; - } - attrs[aindex++] = a; - } - } - return aindex; -} - -static struct attribute ** -__hwmon_create_attrs(struct device *dev, const void *drvdata, - const struct hwmon_chip_info *chip) -{ - int ret, i, aindex = 0, nattrs = 0; - struct attribute **attrs; - - for (i = 0; chip->info[i]; i++) - nattrs += hwmon_num_channel_attrs(chip->info[i]); - - if (nattrs == 0) - return ERR_PTR(-EINVAL); - - attrs = devm_kcalloc(dev, nattrs + 1, sizeof(*attrs), GFP_KERNEL); - if (!attrs) - return ERR_PTR(-ENOMEM); - - for (i = 0; chip->info[i]; i++) { - ret = hwmon_genattrs(dev, drvdata, &attrs[aindex], chip->ops, - chip->info[i]); - if (ret < 0) - return ERR_PTR(ret); - aindex += ret; - } - - return attrs; -} - -static struct device * -__hwmon_device_register(struct device *dev, const char *name, void *drvdata, - const struct hwmon_chip_info *chip, - const struct attribute_group **groups) -{ - struct hwmon_device *hwdev; - struct device *hdev; - int i, j, err, id; - - /* Do not accept invalid characters in hwmon name attribute */ - if (name && (!strlen(name) || strpbrk(name, "-* \t\n"))) - return ERR_PTR(-EINVAL); - - id = ida_simple_get(&hwmon_ida, 0, 0, GFP_KERNEL); - if (id < 0) - return ERR_PTR(id); - - hwdev = kzalloc(sizeof(*hwdev), GFP_KERNEL); - if (hwdev == NULL) { - err = -ENOMEM; - goto ida_remove; - } - - hdev = &hwdev->dev; - - if (chip && chip->ops->is_visible) { - struct attribute **attrs; - int ngroups = 2; - - if (groups) - for (i = 0; groups[i]; i++) - ngroups++; - - hwdev->groups = devm_kcalloc(dev, ngroups, sizeof(*groups), - GFP_KERNEL); - if (!hwdev->groups) { - err = -ENOMEM; - goto free_hwmon; - } - - attrs = __hwmon_create_attrs(dev, drvdata, chip); - if (IS_ERR(attrs)) { - err = PTR_ERR(attrs); - goto free_hwmon; - } - - hwdev->group.attrs = attrs; - ngroups = 0; - hwdev->groups[ngroups++] = &hwdev->group; - - if (groups) { - for (i = 0; groups[i]; i++) - hwdev->groups[ngroups++] = groups[i]; - } - - hdev->groups = hwdev->groups; - } else { - hdev->groups = groups; - } - - hwdev->name = name; - hdev->class = &hwmon_class; - hdev->parent = dev; - hdev->of_node = dev ? dev->of_node : NULL; - hwdev->chip = chip; - dev_set_drvdata(hdev, drvdata); - dev_set_name(hdev, HWMON_ID_FORMAT, id); - err = device_register(hdev); - if (err) - goto free_hwmon; - - if (chip && chip->ops->is_visible && chip->ops->read && - chip->info[0]->type == hwmon_chip && - (chip->info[0]->config[0] & HWMON_C_REGISTER_TZ)) { - const struct hwmon_channel_info **info = chip->info; - - for (i = 1; info[i]; i++) { - if (info[i]->type != hwmon_temp) - continue; - - for (j = 0; info[i]->config[j]; j++) { - if (!chip->ops->is_visible(drvdata, hwmon_temp, - hwmon_temp_input, j)) - continue; - if (info[i]->config[j] & HWMON_T_INPUT) - hwmon_thermal_add_sensor(dev, hwdev, j); - } - } - } - - return hdev; - -free_hwmon: - kfree(hwdev); -ida_remove: - ida_simple_remove(&hwmon_ida, id); - return ERR_PTR(err); -} - -/** - * hwmon_device_register_with_groups - register w/ hwmon - * @dev: the parent device - * @name: hwmon name attribute - * @drvdata: driver data to attach to created device - * @groups: List of attribute groups to create - * - * hwmon_device_unregister() must be called when the device is no - * longer needed. - * - * Returns the pointer to the new device. - */ -struct device * -hwmon_device_register_with_groups(struct device *dev, const char *name, - void *drvdata, - const struct attribute_group **groups) -{ - return __hwmon_device_register(dev, name, drvdata, NULL, groups); -} -EXPORT_SYMBOL_GPL(hwmon_device_register_with_groups); - -/** - * hwmon_device_register_with_info - register w/ hwmon - * @dev: the parent device - * @name: hwmon name attribute - * @drvdata: driver data to attach to created device - * @info: Pointer to hwmon chip information - * @groups - pointer to list of driver specific attribute groups - * - * hwmon_device_unregister() must be called when the device is no - * longer needed. - * - * Returns the pointer to the new device. - */ -struct device * -hwmon_device_register_with_info(struct device *dev, const char *name, - void *drvdata, - const struct hwmon_chip_info *chip, - const struct attribute_group **groups) -{ - if (chip && (!chip->ops || !chip->info)) - return ERR_PTR(-EINVAL); - - return __hwmon_device_register(dev, name, drvdata, chip, groups); -} -EXPORT_SYMBOL_GPL(hwmon_device_register_with_info); - -/** - * hwmon_device_register - register w/ hwmon - * @dev: the device to register - * - * hwmon_device_unregister() must be called when the device is no - * longer needed. - * - * Returns the pointer to the new device. - */ -struct device *hwmon_device_register(struct device *dev) -{ - return hwmon_device_register_with_groups(dev, NULL, NULL, NULL); -} -EXPORT_SYMBOL_GPL(hwmon_device_register); - -/** - * hwmon_device_unregister - removes the previously registered class device - * - * @dev: the class device to destroy - */ -void hwmon_device_unregister(struct device *dev) -{ - int id; - - if (likely(sscanf(dev_name(dev), HWMON_ID_FORMAT, &id) == 1)) { - device_unregister(dev); - ida_simple_remove(&hwmon_ida, id); - } else - dev_dbg(dev->parent, - "hwmon_device_unregister() failed: bad class ID!\n"); -} -EXPORT_SYMBOL_GPL(hwmon_device_unregister); - -static void devm_hwmon_release(struct device *dev, void *res) -{ - struct device *hwdev = *(struct device **)res; - - hwmon_device_unregister(hwdev); -} - -/** - * devm_hwmon_device_register_with_groups - register w/ hwmon - * @dev: the parent device - * @name: hwmon name attribute - * @drvdata: driver data to attach to created device - * @groups: List of attribute groups to create - * - * Returns the pointer to the new device. The new device is automatically - * unregistered with the parent device. - */ -struct device * -devm_hwmon_device_register_with_groups(struct device *dev, const char *name, - void *drvdata, - const struct attribute_group **groups) -{ - struct device **ptr, *hwdev; - - if (!dev) - return ERR_PTR(-EINVAL); - - ptr = devres_alloc(devm_hwmon_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); - - hwdev = hwmon_device_register_with_groups(dev, name, drvdata, groups); - if (IS_ERR(hwdev)) - goto error; - - *ptr = hwdev; - devres_add(dev, ptr); - return hwdev; - -error: - devres_free(ptr); - return hwdev; -} -EXPORT_SYMBOL_GPL(devm_hwmon_device_register_with_groups); - -/** - * devm_hwmon_device_register_with_info - register w/ hwmon - * @dev: the parent device - * @name: hwmon name attribute - * @drvdata: driver data to attach to created device - * @info: Pointer to hwmon chip information - * @groups - pointer to list of driver specific attribute groups - * - * Returns the pointer to the new device. The new device is automatically - * unregistered with the parent device. - */ -struct device * -devm_hwmon_device_register_with_info(struct device *dev, const char *name, - void *drvdata, - const struct hwmon_chip_info *chip, - const struct attribute_group **groups) -{ - struct device **ptr, *hwdev; - - if (!dev) - return ERR_PTR(-EINVAL); - - ptr = devres_alloc(devm_hwmon_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); - - hwdev = hwmon_device_register_with_info(dev, name, drvdata, chip, - groups); - if (IS_ERR(hwdev)) - goto error; - - *ptr = hwdev; - devres_add(dev, ptr); - - return hwdev; - -error: - devres_free(ptr); - return hwdev; -} -EXPORT_SYMBOL_GPL(devm_hwmon_device_register_with_info); - -static int devm_hwmon_match(struct device *dev, void *res, void *data) -{ - struct device **hwdev = res; - - return *hwdev == data; -} - -/** - * devm_hwmon_device_unregister - removes a previously registered hwmon device - * - * @dev: the parent device of the device to unregister - */ -void devm_hwmon_device_unregister(struct device *dev) -{ - WARN_ON(devres_release(dev, devm_hwmon_release, devm_hwmon_match, dev)); -} -EXPORT_SYMBOL_GPL(devm_hwmon_device_unregister); - -static void __init hwmon_pci_quirks(void) -{ -#if defined CONFIG_X86 && defined CONFIG_PCI - struct pci_dev *sb; - u16 base; - u8 enable; - - /* Open access to 0x295-0x296 on MSI MS-7031 */ - sb = pci_get_device(PCI_VENDOR_ID_ATI, 0x436c, NULL); - if (sb) { - if (sb->subsystem_vendor == 0x1462 && /* MSI */ - sb->subsystem_device == 0x0031) { /* MS-7031 */ - pci_read_config_byte(sb, 0x48, &enable); - pci_read_config_word(sb, 0x64, &base); - - if (base == 0 && !(enable & BIT(2))) { - dev_info(&sb->dev, - "Opening wide generic port at 0x295\n"); - pci_write_config_word(sb, 0x64, 0x295); - pci_write_config_byte(sb, 0x48, - enable | BIT(2)); - } - } - pci_dev_put(sb); - } -#endif -} - -static int __init hwmon_init(void) -{ - int err; - - hwmon_pci_quirks(); - - err = class_register(&hwmon_class); - if (err) { - pr_err("couldn't register hwmon sysfs class\n"); - return err; - } - return 0; -} - -static void __exit hwmon_exit(void) -{ - class_unregister(&hwmon_class); -} - -subsys_initcall(hwmon_init); -module_exit(hwmon_exit); - -MODULE_AUTHOR("Mark M. Hoffman "); -MODULE_DESCRIPTION("hardware monitoring sysfs/class support"); -MODULE_LICENSE("GPL"); - diff --git a/src/linux/drivers/hwmon/pmbus/Kconfig b/src/linux/drivers/hwmon/pmbus/Kconfig deleted file mode 100644 index cad1229..0000000 --- a/src/linux/drivers/hwmon/pmbus/Kconfig +++ /dev/null @@ -1,162 +0,0 @@ -# -# PMBus chip drivers configuration -# - -menuconfig PMBUS - tristate "PMBus support" - depends on I2C - default n - help - Say yes here if you want to enable PMBus support. - - This driver can also be built as a module. If so, the module will - be called pmbus_core. - -if PMBUS - -config SENSORS_PMBUS - tristate "Generic PMBus devices" - default y - help - If you say yes here you get hardware monitoring support for generic - PMBus devices, including but not limited to ADP4000, BMR453, BMR454, - MDT040, NCP4200, NCP4208, PDT003, PDT006, PDT012, TPS40400, TPS544B20, - TPS544B25, TPS544C20, TPS544C25, and UDT020. - - This driver can also be built as a module. If so, the module will - be called pmbus. - -config SENSORS_ADM1275 - tristate "Analog Devices ADM1275 and compatibles" - default n - help - If you say yes here you get hardware monitoring support for Analog - Devices ADM1075, ADM1275, ADM1276, ADM1278, ADM1293, and ADM1294 - Hot-Swap Controller and Digital Power Monitors. - - This driver can also be built as a module. If so, the module will - be called adm1275. - -config SENSORS_LM25066 - tristate "National Semiconductor LM25066 and compatibles" - default n - help - If you say yes here you get hardware monitoring support for National - Semiconductor LM25056, LM25066, LM5064, and LM5066. - - This driver can also be built as a module. If so, the module will - be called lm25066. - -config SENSORS_LTC2978 - tristate "Linear Technologies LTC2978 and compatibles" - default n - help - If you say yes here you get hardware monitoring support for Linear - Technology LTC2974, LTC2975, LTC2977, LTC2978, LTC2980, LTC3880, - LTC3883, LTC3886, LTC3887, LTCM2987, LTM4675, and LTM4676. - - This driver can also be built as a module. If so, the module will - be called ltc2978. - -config SENSORS_LTC2978_REGULATOR - bool "Regulator support for LTC2978 and compatibles" - depends on SENSORS_LTC2978 && REGULATOR - help - If you say yes here you get regulator support for Linear - Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, and LTM4676. - -config SENSORS_LTC3815 - tristate "Linear Technologies LTC3815" - default n - help - If you say yes here you get hardware monitoring support for Linear - Technology LTC3815. - - This driver can also be built as a module. If so, the module will - be called ltc3815. - -config SENSORS_MAX16064 - tristate "Maxim MAX16064" - default n - help - If you say yes here you get hardware monitoring support for Maxim - MAX16064. - - This driver can also be built as a module. If so, the module will - be called max16064. - -config SENSORS_MAX20751 - tristate "Maxim MAX20751" - default n - help - If you say yes here you get hardware monitoring support for Maxim - MAX20751. - - This driver can also be built as a module. If so, the module will - be called max20751. - -config SENSORS_MAX34440 - tristate "Maxim MAX34440 and compatibles" - default n - help - If you say yes here you get hardware monitoring support for Maxim - MAX34440, MAX34441, MAX34446, MAX34460, and MAX34461. - - This driver can also be built as a module. If so, the module will - be called max34440. - -config SENSORS_MAX8688 - tristate "Maxim MAX8688" - default n - help - If you say yes here you get hardware monitoring support for Maxim - MAX8688. - - This driver can also be built as a module. If so, the module will - be called max8688. - -config SENSORS_TPS40422 - tristate "TI TPS40422" - default n - help - If you say yes here you get hardware monitoring support for TI - TPS40422. - - This driver can also be built as a module. If so, the module will - be called tps40422. - -config SENSORS_UCD9000 - tristate "TI UCD90120, UCD90124, UCD90160, UCD9090, UCD90910" - default n - help - If you say yes here you get hardware monitoring support for TI - UCD90120, UCD90124, UCD90160, UCD9090, UCD90910, Sequencer and System - Health Controllers. - - This driver can also be built as a module. If so, the module will - be called ucd9000. - -config SENSORS_UCD9200 - tristate "TI UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, UCD9248" - default n - help - If you say yes here you get hardware monitoring support for TI - UCD9220, UCD9222, UCD9224, UCD9240, UCD9244, UCD9246, and UCD9248 - Digital PWM System Controllers. - - This driver can also be built as a module. If so, the module will - be called ucd9200. - -config SENSORS_ZL6100 - tristate "Intersil ZL6100 and compatibles" - default n - help - If you say yes here you get hardware monitoring support for Intersil - ZL2004, ZL2005, ZL2006, ZL2008, ZL2105, ZL2106, ZL6100, ZL6105, - ZL9101M, and ZL9117M Digital DC/DC Controllers, as well as for - Ericsson BMR450, BMR451, BMR462, BMR463, and BMR464. - - This driver can also be built as a module. If so, the module will - be called zl6100. - -endif # PMBUS diff --git a/src/linux/drivers/hwspinlock/Kconfig b/src/linux/drivers/hwspinlock/Kconfig deleted file mode 100644 index 73a4016..0000000 --- a/src/linux/drivers/hwspinlock/Kconfig +++ /dev/null @@ -1,56 +0,0 @@ -# -# Generic HWSPINLOCK framework -# - -# HWSPINLOCK always gets selected by whoever wants it. -config HWSPINLOCK - tristate - -menu "Hardware Spinlock drivers" - -config HWSPINLOCK_OMAP - tristate "OMAP Hardware Spinlock device" - depends on ARCH_OMAP4 || SOC_OMAP5 || SOC_DRA7XX || SOC_AM33XX || SOC_AM43XX - select HWSPINLOCK - help - Say y here to support the OMAP Hardware Spinlock device (firstly - introduced in OMAP4). - - If unsure, say N. - -config HWSPINLOCK_QCOM - tristate "Qualcomm Hardware Spinlock device" - depends on ARCH_QCOM - select HWSPINLOCK - select MFD_SYSCON - help - Say y here to support the Qualcomm Hardware Mutex functionality, which - provides a synchronisation mechanism for the various processors on - the SoC. - - If unsure, say N. - -config HWSPINLOCK_SIRF - tristate "SIRF Hardware Spinlock device" - depends on ARCH_SIRF - select HWSPINLOCK - help - Say y here to support the SIRF Hardware Spinlock device, which - provides a synchronisation mechanism for the various processors - on the SoC. - - It's safe to say n here if you're not interested in SIRF hardware - spinlock or just want a bare minimum kernel. - -config HSEM_U8500 - tristate "STE Hardware Semaphore functionality" - depends on ARCH_U8500 - select HWSPINLOCK - help - Say y here to support the STE Hardware Semaphore functionality, which - provides a synchronisation mechanism for the various processor on the - SoC. - - If unsure, say N. - -endmenu diff --git a/src/linux/drivers/hwtracing/intel_th/Kconfig b/src/linux/drivers/hwtracing/intel_th/Kconfig deleted file mode 100644 index 1b412f8..0000000 --- a/src/linux/drivers/hwtracing/intel_th/Kconfig +++ /dev/null @@ -1,73 +0,0 @@ -config INTEL_TH - tristate "Intel(R) Trace Hub controller" - depends on HAS_DMA && HAS_IOMEM - help - Intel(R) Trace Hub (TH) is a set of hardware blocks (subdevices) that - produce, switch and output trace data from multiple hardware and - software sources over several types of trace output ports encoded - in System Trace Protocol (MIPI STPv2) and is intended to perform - full system debugging. - - This option enables intel_th bus and common code used by TH - subdevices to interact with each other and hardware and for - platform glue layers to drive Intel TH devices. - - Say Y here to enable Intel(R) Trace Hub controller support. - -if INTEL_TH - -config INTEL_TH_PCI - tristate "Intel(R) Trace Hub PCI controller" - depends on PCI - help - Intel(R) Trace Hub may exist as a PCI device. This option enables - support glue layer for PCI-based Intel TH. - - Say Y here to enable PCI Intel TH support. - -config INTEL_TH_GTH - tristate "Intel(R) Trace Hub Global Trace Hub" - help - Global Trace Hub (GTH) is the central component of the - Intel TH infrastructure and acts as a switch for source - and output devices. This driver is required for other - Intel TH subdevices to initialize. - - Say Y here to enable GTH subdevice of Intel(R) Trace Hub. - -config INTEL_TH_STH - tristate "Intel(R) Trace Hub Software Trace Hub support" - depends on STM - help - Software Trace Hub (STH) enables trace data from software - trace sources to be sent out via Intel(R) Trace Hub. It - uses stm class device to interface with its sources. - - Say Y here to enable STH subdevice of Intel(R) Trace Hub. - -config INTEL_TH_MSU - tristate "Intel(R) Trace Hub Memory Storage Unit" - help - Memory Storage Unit (MSU) trace output device enables - storing STP traces to system memory. It supports single - and multiblock modes of operation and provides read() - and mmap() access to the collected data. - - Say Y here to enable MSU output device for Intel TH. - -config INTEL_TH_PTI - tristate "Intel(R) Trace Hub PTI output" - help - Parallel Trace Interface unit (PTI) is a trace output device - of Intel TH architecture that facilitates STP trace output via - a PTI port. - - Say Y to enable PTI output of Intel TH data. - -config INTEL_TH_DEBUG - bool "Intel(R) Trace Hub debugging" - depends on DEBUG_FS - help - Say Y here to enable debugging. - -endif diff --git a/src/linux/drivers/hwtracing/intel_th/Makefile b/src/linux/drivers/hwtracing/intel_th/Makefile deleted file mode 100644 index 81d42fe..0000000 --- a/src/linux/drivers/hwtracing/intel_th/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -obj-$(CONFIG_INTEL_TH) += intel_th.o -intel_th-y := core.o -intel_th-$(CONFIG_INTEL_TH_DEBUG) += debug.o - -obj-$(CONFIG_INTEL_TH_PCI) += intel_th_pci.o -intel_th_pci-y := pci.o - -obj-$(CONFIG_INTEL_TH_GTH) += intel_th_gth.o -intel_th_gth-y := gth.o - -obj-$(CONFIG_INTEL_TH_STH) += intel_th_sth.o -intel_th_sth-y := sth.o - -obj-$(CONFIG_INTEL_TH_MSU) += intel_th_msu.o -intel_th_msu-y := msu.o - -obj-$(CONFIG_INTEL_TH_PTI) += intel_th_pti.o -intel_th_pti-y := pti.o diff --git a/src/linux/drivers/hwtracing/stm/Kconfig b/src/linux/drivers/hwtracing/stm/Kconfig deleted file mode 100644 index 847a39b..0000000 --- a/src/linux/drivers/hwtracing/stm/Kconfig +++ /dev/null @@ -1,42 +0,0 @@ -config STM - tristate "System Trace Module devices" - select CONFIGFS_FS - select SRCU - help - A System Trace Module (STM) is a device exporting data in System - Trace Protocol (STP) format as defined by MIPI STP standards. - Examples of such devices are Intel(R) Trace Hub and Coresight STM. - - Say Y here to enable System Trace Module device support. - -if STM - -config STM_DUMMY - tristate "Dummy STM driver" - help - This is a simple dummy device that pretends to be an stm device - and discards your data. Use for stm class testing. - - If you don't know what this is, say N. - -config STM_SOURCE_CONSOLE - tristate "Kernel console over STM devices" - help - This is a kernel space trace source that sends kernel log - messages to trace hosts over STM devices. - - If you want to send kernel console messages over STM devices, - say Y. - -config STM_SOURCE_HEARTBEAT - tristate "Heartbeat over STM devices" - help - This is a kernel space trace source that sends periodic - heartbeat messages to trace hosts over STM devices. It is - also useful for testing stm class drivers and the stm class - framework itself. - - If you want to send heartbeat messages over STM devices, - say Y. - -endif diff --git a/src/linux/drivers/i2c/Kconfig b/src/linux/drivers/i2c/Kconfig deleted file mode 100644 index 11edabf..0000000 --- a/src/linux/drivers/i2c/Kconfig +++ /dev/null @@ -1,148 +0,0 @@ -# -# I2C subsystem configuration -# - -menu "I2C support" - -config I2C - tristate "I2C support" - select RT_MUTEXES - ---help--- - I2C (pronounce: I-squared-C) is a slow serial bus protocol used in - many micro controller applications and developed by Philips. SMBus, - or System Management Bus is a subset of the I2C protocol. More - information is contained in the directory , - especially in the file called "summary" there. - - Both I2C and SMBus are supported here. You will need this for - hardware sensors support, and also for Video For Linux support. - - If you want I2C support, you should say Y here and also to the - specific driver for your bus adapter(s) below. - - This I2C support can also be built as a module. If so, the module - will be called i2c-core. - -config ACPI_I2C_OPREGION - bool "ACPI I2C Operation region support" - depends on I2C=y && ACPI - default y - help - Say Y here if you want to enable ACPI I2C operation region support. - Operation Regions allow firmware (BIOS) code to access I2C slave devices, - such as smart batteries through an I2C host controller driver. - -if I2C - -config I2C_BOARDINFO - bool - default y - -config I2C_COMPAT - bool "Enable compatibility bits for old user-space" - default y - help - Say Y here if you intend to run lm-sensors 3.1.1 or older, or any - other user-space package which expects i2c adapters to be class - devices. If you don't know, say Y. - -config I2C_CHARDEV - tristate "I2C device interface" - help - Say Y here to use i2c-* device files, usually found in the /dev - directory on your system. They make it possible to have user-space - programs use the I2C bus. Information on how to do this is - contained in the file . - - This support is also available as a module. If so, the module - will be called i2c-dev. - -config I2C_MUX - tristate "I2C bus multiplexing support" - help - Say Y here if you want the I2C core to support the ability to - handle multiplexed I2C bus topologies, by presenting each - multiplexed segment as a I2C adapter. - - This support is also available as a module. If so, the module - will be called i2c-mux. - -source drivers/i2c/muxes/Kconfig - -config I2C_HELPER_AUTO - bool "Autoselect pertinent helper modules" - default y - help - Some I2C bus drivers require so-called "I2C algorithm" modules - to work. These are basically software-only abstractions of generic - I2C interfaces. This option will autoselect them so that you don't - have to care. - - Unselect this only if you need to enable additional helper - modules, for example for use with external I2C bus drivers. - - In doubt, say Y. - -config I2C_SMBUS - tristate "SMBus-specific protocols" if !I2C_HELPER_AUTO - help - Say Y here if you want support for SMBus extensions to the I2C - specification. At the moment, two extensions are supported: - the SMBus Alert protocol and the SMBus Host Notify protocol. - - This support is also available as a module. If so, the module - will be called i2c-smbus. - -source drivers/i2c/algos/Kconfig -source drivers/i2c/busses/Kconfig - -config I2C_STUB - tristate "I2C/SMBus Test Stub" - depends on m - default 'n' - help - This module may be useful to developers of SMBus client drivers, - especially for certain kinds of sensor chips. - - If you do build this module, be sure to read the notes and warnings - in . - - If you don't know what to do here, definitely say N. - -config I2C_SLAVE - bool "I2C slave support" - -if I2C_SLAVE - -config I2C_SLAVE_EEPROM - tristate "I2C eeprom slave driver" - -endif - -config I2C_DEBUG_CORE - bool "I2C Core debugging messages" - help - Say Y here if you want the I2C core to produce a bunch of debug - messages to the system log. Select this if you are having a - problem with I2C support and want to see more of what is going on. - -config I2C_DEBUG_ALGO - bool "I2C Algorithm debugging messages" - help - Say Y here if you want the I2C algorithm drivers to produce a bunch - of debug messages to the system log. Select this if you are having - a problem with I2C support and want to see more of what is going - on. - -config I2C_DEBUG_BUS - bool "I2C Bus debugging messages" - depends on HAS_IOMEM - help - Say Y here if you want the I2C bus drivers to produce a bunch of - debug messages to the system log. Select this if you are having - a problem with I2C support and want to see more of what is going - on. - -endif # I2C - -endmenu diff --git a/src/linux/drivers/i2c/Makefile b/src/linux/drivers/i2c/Makefile deleted file mode 100644 index 45095b3..0000000 --- a/src/linux/drivers/i2c/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -# -# Makefile for the i2c core. -# - -obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o -obj-$(CONFIG_I2C) += i2c-core.o -obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o -obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o -obj-$(CONFIG_I2C_MUX) += i2c-mux.o -obj-y += algos/ busses/ muxes/ -obj-$(CONFIG_I2C_STUB) += i2c-stub.o -obj-$(CONFIG_I2C_SLAVE_EEPROM) += i2c-slave-eeprom.o - -ccflags-$(CONFIG_I2C_DEBUG_CORE) := -DDEBUG -CFLAGS_i2c-core.o := -Wno-deprecated-declarations diff --git a/src/linux/drivers/i2c/algos/Kconfig b/src/linux/drivers/i2c/algos/Kconfig deleted file mode 100644 index f1cfe7e..0000000 --- a/src/linux/drivers/i2c/algos/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -# -# I2C algorithm drivers configuration -# - -menu "I2C Algorithms" - visible if !I2C_HELPER_AUTO - -config I2C_ALGOBIT - tristate "I2C bit-banging interfaces" - -config I2C_ALGOPCF - tristate "I2C PCF 8584 interfaces" - -config I2C_ALGOPCA - tristate "I2C PCA 9564 interfaces" - -endmenu diff --git a/src/linux/drivers/i2c/algos/Makefile b/src/linux/drivers/i2c/algos/Makefile deleted file mode 100644 index 215303f..0000000 --- a/src/linux/drivers/i2c/algos/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for the i2c algorithms -# - -obj-$(CONFIG_I2C_ALGOBIT) += i2c-algo-bit.o -obj-$(CONFIG_I2C_ALGOPCF) += i2c-algo-pcf.o -obj-$(CONFIG_I2C_ALGOPCA) += i2c-algo-pca.o - -ccflags-$(CONFIG_I2C_DEBUG_ALGO) := -DDEBUG diff --git a/src/linux/drivers/i2c/busses/Kconfig b/src/linux/drivers/i2c/busses/Kconfig deleted file mode 100644 index d252276..0000000 --- a/src/linux/drivers/i2c/busses/Kconfig +++ /dev/null @@ -1,1217 +0,0 @@ -# -# Sensor device configuration -# - -menu "I2C Hardware Bus support" - depends on HAS_IOMEM - -comment "PC SMBus host controller drivers" - depends on PCI - -config I2C_ALI1535 - tristate "ALI 1535" - depends on PCI - help - If you say yes to this option, support will be included for the SMB - Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB - controller is part of the 7101 device, which is an ACPI-compliant - Power Management Unit (PMU). - - This driver can also be built as a module. If so, the module - will be called i2c-ali1535. - -config I2C_ALI1563 - tristate "ALI 1563" - depends on PCI - help - If you say yes to this option, support will be included for the SMB - Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB - controller is part of the 7101 device, which is an ACPI-compliant - Power Management Unit (PMU). - - This driver can also be built as a module. If so, the module - will be called i2c-ali1563. - -config I2C_ALI15X3 - tristate "ALI 15x3" - depends on PCI - help - If you say yes to this option, support will be included for the - Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces. - - This driver can also be built as a module. If so, the module - will be called i2c-ali15x3. - -config I2C_AMD756 - tristate "AMD 756/766/768/8111 and nVidia nForce" - depends on PCI - help - If you say yes to this option, support will be included for the AMD - 756/766/768 mainboard I2C interfaces. The driver also includes - support for the first (SMBus 1.0) I2C interface of the AMD 8111 and - the nVidia nForce I2C interface. - - This driver can also be built as a module. If so, the module - will be called i2c-amd756. - -config I2C_AMD756_S4882 - tristate "SMBus multiplexing on the Tyan S4882" - depends on I2C_AMD756 && X86 - help - Enabling this option will add specific SMBus support for the Tyan - S4882 motherboard. On this 4-CPU board, the SMBus is multiplexed - over 8 different channels, where the various memory module EEPROMs - and temperature sensors live. Saying yes here will give you access - to these in addition to the trunk. - - This driver can also be built as a module. If so, the module - will be called i2c-amd756-s4882. - -config I2C_AMD8111 - tristate "AMD 8111" - depends on PCI - help - If you say yes to this option, support will be included for the - second (SMBus 2.0) AMD 8111 mainboard I2C interface. - - This driver can also be built as a module. If so, the module - will be called i2c-amd8111. - -config I2C_HIX5HD2 - tristate "Hix5hd2 high-speed I2C driver" - depends on ARCH_HISI || ARCH_HIX5HD2 || COMPILE_TEST - help - Say Y here to include support for the high-speed I2C controller - used in HiSilicon hix5hd2 SoCs. - - This driver can also be built as a module. If so, the module - will be called i2c-hix5hd2. - -config I2C_I801 - tristate "Intel 82801 (ICH/PCH)" - depends on PCI - select CHECK_SIGNATURE if X86 && DMI - select I2C_SMBUS - help - If you say yes to this option, support will be included for the Intel - 801 family of mainboard I2C interfaces. Specifically, the following - versions of the chipset are supported: - 82801AA - 82801AB - 82801BA - 82801CA/CAM - 82801DB - 82801EB/ER (ICH5/ICH5R) - 6300ESB - ICH6 - ICH7 - ESB2 - ICH8 - ICH9 - EP80579 (Tolapai) - ICH10 - 5/3400 Series (PCH) - 6 Series (PCH) - Patsburg (PCH) - DH89xxCC (PCH) - Panther Point (PCH) - Lynx Point (PCH) - Lynx Point-LP (PCH) - Avoton (SOC) - Wellsburg (PCH) - Coleto Creek (PCH) - Wildcat Point (PCH) - Wildcat Point-LP (PCH) - BayTrail (SOC) - Sunrise Point-H (PCH) - Sunrise Point-LP (PCH) - DNV (SOC) - Broxton (SOC) - Lewisburg (PCH) - - This driver can also be built as a module. If so, the module - will be called i2c-i801. - -config I2C_ISCH - tristate "Intel SCH SMBus 1.0" - depends on PCI - select LPC_SCH - help - Say Y here if you want to use SMBus controller on the Intel SCH - based systems. - - This driver can also be built as a module. If so, the module - will be called i2c-isch. - -config I2C_ISMT - tristate "Intel iSMT SMBus Controller" - depends on PCI && X86 - help - If you say yes to this option, support will be included for the Intel - iSMT SMBus host controller interface. - - This driver can also be built as a module. If so, the module will be - called i2c-ismt. - -config I2C_PIIX4 - tristate "Intel PIIX4 and compatible (ATI/AMD/Serverworks/Broadcom/SMSC)" - depends on PCI - help - If you say yes to this option, support will be included for the Intel - PIIX4 family of mainboard I2C interfaces. Specifically, the following - versions of the chipset are supported (note that Serverworks is part - of Broadcom): - Intel PIIX4 - Intel 440MX - ATI IXP200 - ATI IXP300 - ATI IXP400 - ATI SB600 - ATI SB700/SP5100 - ATI SB800 - AMD Hudson-2 - AMD ML - AMD CZ - Serverworks OSB4 - Serverworks CSB5 - Serverworks CSB6 - Serverworks HT-1000 - Serverworks HT-1100 - SMSC Victory66 - - Some AMD chipsets contain two PIIX4-compatible SMBus - controllers. This driver will attempt to use both controllers - on the SB700/SP5100, if they have been initialized by the BIOS. - - This driver can also be built as a module. If so, the module - will be called i2c-piix4. - -config I2C_NFORCE2 - tristate "Nvidia nForce2, nForce3 and nForce4" - depends on PCI - help - If you say yes to this option, support will be included for the Nvidia - nForce2, nForce3 and nForce4 families of mainboard I2C interfaces. - - This driver can also be built as a module. If so, the module - will be called i2c-nforce2. - -config I2C_NFORCE2_S4985 - tristate "SMBus multiplexing on the Tyan S4985" - depends on I2C_NFORCE2 && X86 - help - Enabling this option will add specific SMBus support for the Tyan - S4985 motherboard. On this 4-CPU board, the SMBus is multiplexed - over 4 different channels, where the various memory module EEPROMs - live. Saying yes here will give you access to these in addition - to the trunk. - - This driver can also be built as a module. If so, the module - will be called i2c-nforce2-s4985. - -config I2C_SIS5595 - tristate "SiS 5595" - depends on PCI - help - If you say yes to this option, support will be included for the - SiS5595 SMBus (a subset of I2C) interface. - - This driver can also be built as a module. If so, the module - will be called i2c-sis5595. - -config I2C_SIS630 - tristate "SiS 630/730/964" - depends on PCI - help - If you say yes to this option, support will be included for the - SiS630, SiS730 and SiS964 SMBus (a subset of I2C) interface. - - This driver can also be built as a module. If so, the module - will be called i2c-sis630. - -config I2C_SIS96X - tristate "SiS 96x" - depends on PCI - help - If you say yes to this option, support will be included for the SiS - 96x SMBus (a subset of I2C) interfaces. Specifically, the following - chipsets are supported: - 645/961 - 645DX/961 - 645DX/962 - 648/961 - 650/961 - 735 - 745 - - This driver can also be built as a module. If so, the module - will be called i2c-sis96x. - -config I2C_VIA - tristate "VIA VT82C586B" - depends on PCI - select I2C_ALGOBIT - help - If you say yes to this option, support will be included for the VIA - 82C586B I2C interface - - This driver can also be built as a module. If so, the module - will be called i2c-via. - -config I2C_VIAPRO - tristate "VIA VT82C596/82C686/82xx and CX700/VX8xx/VX900" - depends on PCI - help - If you say yes to this option, support will be included for the VIA - VT82C596 and later SMBus interface. Specifically, the following - chipsets are supported: - VT82C596A/B - VT82C686A/B - VT8231 - VT8233/A - VT8235 - VT8237R/A/S - VT8251 - CX700 - VX800/VX820 - VX855/VX875 - VX900 - - This driver can also be built as a module. If so, the module - will be called i2c-viapro. - -if ACPI - -comment "ACPI drivers" - -config I2C_SCMI - tristate "SMBus Control Method Interface" - help - This driver supports the SMBus Control Method Interface. It needs the - BIOS to declare ACPI control methods as described in the SMBus Control - Method Interface specification. - - To compile this driver as a module, choose M here: - the module will be called i2c-scmi. - -endif # ACPI - -comment "Mac SMBus host controller drivers" - depends on PPC_CHRP || PPC_PMAC - -config I2C_HYDRA - tristate "CHRP Apple Hydra Mac I/O I2C interface" - depends on PCI && PPC_CHRP - select I2C_ALGOBIT - help - This supports the use of the I2C interface in the Apple Hydra Mac - I/O chip on some CHRP machines (e.g. the LongTrail). Say Y if you - have such a machine. - - This support is also available as a module. If so, the module - will be called i2c-hydra. - -config I2C_POWERMAC - tristate "Powermac I2C interface" - depends on PPC_PMAC - default y - help - This exposes the various PowerMac i2c interfaces to the linux i2c - layer and to userland. It is used by various drivers on the PowerMac - platform, and should generally be enabled. - - This support is also available as a module. If so, the module - will be called i2c-powermac. - -comment "I2C system bus drivers (mostly embedded / system-on-chip)" - -config I2C_AT91 - tristate "Atmel AT91 I2C Two-Wire interface (TWI)" - depends on ARCH_AT91 - help - This supports the use of the I2C interface on Atmel AT91 - processors. - - A serious problem is that there is no documented way to issue - repeated START conditions for more than two messages, as needed - to support combined I2C messages. Use the i2c-gpio driver - unless your system can cope with this limitation. - - Caution! at91rm9200, at91sam9261, at91sam9260, at91sam9263 devices - don't have clock stretching in transmission mode. For that reason, - you can encounter underrun issues causing premature stop sendings if - the latency to fill the transmission register is too long. If you - are facing this situation, use the i2c-gpio driver. - -config I2C_AU1550 - tristate "Au1550/Au1200/Au1300 SMBus interface" - depends on MIPS_ALCHEMY - help - If you say yes to this option, support will be included for the - Au1550/Au1200/Au1300 SMBus interface. - - This driver can also be built as a module. If so, the module - will be called i2c-au1550. - -config I2C_AXXIA - tristate "Axxia I2C controller" - depends on ARCH_AXXIA || COMPILE_TEST - default ARCH_AXXIA - help - Say yes if you want to support the I2C bus on Axxia platforms. - - Please note that this controller is limited to transfers of maximum - 255 bytes in length. Any attempt to to a larger transfer will return - an error. - -config I2C_BCM2835 - tristate "Broadcom BCM2835 I2C controller" - depends on ARCH_BCM2835 - help - If you say yes to this option, support will be included for the - BCM2835 I2C controller. - - If you don't know what to do here, say N. - - This support is also available as a module. If so, the module - will be called i2c-bcm2835. - -config I2C_BCM_IPROC - tristate "Broadcom iProc I2C controller" - depends on ARCH_BCM_IPROC || COMPILE_TEST - default ARCH_BCM_IPROC - help - If you say yes to this option, support will be included for the - Broadcom iProc I2C controller. - - If you don't know what to do here, say N. - -config I2C_BCM_KONA - tristate "BCM Kona I2C adapter" - depends on ARCH_BCM_MOBILE - default y - help - If you say yes to this option, support will be included for the - I2C interface on the Broadcom Kona family of processors. - - If you do not need KONA I2C interface, say N. - -config I2C_BRCMSTB - tristate "BRCM Settop I2C controller" - depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST - default y - help - If you say yes to this option, support will be included for the - I2C interface on the Broadcom Settop SoCs. - - If you do not need I2C interface, say N. - -config I2C_BLACKFIN_TWI - tristate "Blackfin TWI I2C support" - depends on BLACKFIN - depends on !BF561 && !BF531 && !BF532 && !BF533 - help - This is the I2C bus driver for Blackfin on-chip TWI interface. - - This driver can also be built as a module. If so, the module - will be called i2c-bfin-twi. - -config I2C_BLACKFIN_TWI_CLK_KHZ - int "Blackfin TWI I2C clock (kHz)" - depends on I2C_BLACKFIN_TWI - range 21 400 - default 50 - help - The unit of the TWI clock is kHz. - -config I2C_CADENCE - tristate "Cadence I2C Controller" - depends on ARCH_ZYNQ || ARM64 - help - Say yes here to select Cadence I2C Host Controller. This controller is - e.g. used by Xilinx Zynq. - -config I2C_CBUS_GPIO - tristate "CBUS I2C driver" - depends on GPIOLIB || COMPILE_TEST - help - Support for CBUS access using I2C API. Mostly relevant for Nokia - Internet Tablets (770, N800 and N810). - - This driver can also be built as a module. If so, the module - will be called i2c-cbus-gpio. - -config I2C_CPM - tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)" - depends on CPM1 || CPM2 - help - This supports the use of the I2C interface on Freescale - processors with CPM1 or CPM2. - - This driver can also be built as a module. If so, the module - will be called i2c-cpm. - -config I2C_DAVINCI - tristate "DaVinci I2C driver" - depends on ARCH_DAVINCI || ARCH_KEYSTONE - help - Support for TI DaVinci I2C controller driver. - - This driver can also be built as a module. If so, the module - will be called i2c-davinci. - - Please note that this driver might be needed to bring up other - devices such as DaVinci NIC. - For details please see http://www.ti.com/davinci - -config I2C_DESIGNWARE_CORE - tristate - -config I2C_DESIGNWARE_PLATFORM - tristate "Synopsys DesignWare Platform" - select I2C_DESIGNWARE_CORE - depends on (ACPI && COMMON_CLK) || !ACPI - help - If you say yes to this option, support will be included for the - Synopsys DesignWare I2C adapter. Only master mode is supported. - - This driver can also be built as a module. If so, the module - will be called i2c-designware-platform. - -config I2C_DESIGNWARE_PCI - tristate "Synopsys DesignWare PCI" - depends on PCI - select I2C_DESIGNWARE_CORE - help - If you say yes to this option, support will be included for the - Synopsys DesignWare I2C adapter. Only master mode is supported. - - This driver can also be built as a module. If so, the module - will be called i2c-designware-pci. - -config I2C_DESIGNWARE_BAYTRAIL - bool "Intel Baytrail I2C semaphore support" - depends on ACPI - depends on (I2C_DESIGNWARE_PLATFORM=m && IOSF_MBI) || \ - (I2C_DESIGNWARE_PLATFORM=y && IOSF_MBI=y) - help - This driver enables managed host access to the PMIC I2C bus on select - Intel BayTrail platforms using the X-Powers AXP288 PMIC. It allows - the host to request uninterrupted access to the PMIC's I2C bus from - the platform firmware controlling it. You should say Y if running on - a BayTrail system using the AXP288. - -config I2C_DIGICOLOR - tristate "Conexant Digicolor I2C driver" - depends on ARCH_DIGICOLOR - help - Support for Conexant Digicolor SoCs (CX92755) I2C controller driver. - - This driver can also be built as a module. If so, the module - will be called i2c-digicolor. - -config I2C_EFM32 - tristate "EFM32 I2C controller" - depends on ARCH_EFM32 || COMPILE_TEST - help - This driver supports the i2c block found in Energy Micro's EFM32 - SoCs. - -config I2C_EG20T - tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C" - depends on PCI && (X86_32 || MIPS || COMPILE_TEST) - help - This driver is for PCH(Platform controller Hub) I2C of EG20T which - is an IOH(Input/Output Hub) for x86 embedded processor. - This driver can access PCH I2C bus device. - - This driver also can be used for LAPIS Semiconductor IOH(Input/ - Output Hub), ML7213, ML7223 and ML7831. - ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is - for MP(Media Phone) use and ML7831 IOH is for general purpose use. - ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series. - ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH. - -config I2C_EMEV2 - tristate "EMMA Mobile series I2C adapter" - depends on HAVE_CLK - select I2C_SLAVE - help - If you say yes to this option, support will be included for the - I2C interface on the Renesas Electronics EM/EV family of processors. - -config I2C_EXYNOS5 - tristate "Exynos5 high-speed I2C driver" - depends on ARCH_EXYNOS && OF - default y - help - High-speed I2C controller on Exynos5 based Samsung SoCs. - -config I2C_GPIO - tristate "GPIO-based bitbanging I2C" - depends on GPIOLIB || COMPILE_TEST - select I2C_ALGOBIT - help - This is a very simple bitbanging I2C driver utilizing the - arch-neutral GPIO API to control the SCL and SDA lines. - -config I2C_HIGHLANDER - tristate "Highlander FPGA SMBus interface" - depends on SH_HIGHLANDER - help - If you say yes to this option, support will be included for - the SMBus interface located in the FPGA on various Highlander - boards, particularly the R0P7780LC0011RL and R0P7785LC0011RL - FPGAs. This is wholly unrelated to the SoC I2C. - - This driver can also be built as a module. If so, the module - will be called i2c-highlander. - -config I2C_IBM_IIC - tristate "IBM PPC 4xx on-chip I2C interface" - depends on 4xx - help - Say Y here if you want to use IIC peripheral found on - embedded IBM PPC 4xx based systems. - - This driver can also be built as a module. If so, the module - will be called i2c-ibm_iic. - -config I2C_IMG - tristate "Imagination Technologies I2C SCB Controller" - depends on MIPS || METAG || COMPILE_TEST - help - Say Y here if you want to use the IMG I2C SCB controller, - available on the TZ1090 and other IMG SoCs. - - This driver can also be built as a module. If so, the module - will be called i2c-img-scb. - -config I2C_IMX - tristate "IMX I2C interface" - depends on ARCH_MXC || ARCH_LAYERSCAPE || COLDFIRE - help - Say Y here if you want to use the IIC bus controller on - the Freescale i.MX/MXC, Layerscape or ColdFire processors. - - This driver can also be built as a module. If so, the module - will be called i2c-imx. - -config I2C_IOP3XX - tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface" - depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX - help - Say Y here if you want to use the IIC bus controller on - the Intel IOPx3xx I/O Processors or IXP4xx Network Processors. - - This driver can also be built as a module. If so, the module - will be called i2c-iop3xx. - -config I2C_JZ4780 - tristate "JZ4780 I2C controller interface support" - depends on MACH_JZ4780 || COMPILE_TEST - help - If you say yes to this option, support will be included for the - Ingenic JZ4780 I2C controller. - - If you don't know what to do here, say N. - -config I2C_KEMPLD - tristate "Kontron COM I2C Controller" - depends on MFD_KEMPLD - help - This enables support for the I2C bus interface on some Kontron ETX - and COMexpress (ETXexpress) modules. - - This driver can also be built as a module. If so, the module - will be called i2c-kempld. - -config I2C_LPC2K - tristate "I2C bus support for NXP LPC2K/LPC178x/18xx/43xx" - depends on OF && (ARCH_LPC18XX || COMPILE_TEST) - help - This driver supports the I2C interface found several NXP - devices including LPC2xxx, LPC178x/7x and LPC18xx/43xx. - - This driver can also be built as a module. If so, the module - will be called i2c-lpc2k. - -config I2C_MESON - tristate "Amlogic Meson I2C controller" - depends on ARCH_MESON || COMPILE_TEST - help - If you say yes to this option, support will be included for the - I2C interface on the Amlogic Meson family of SoCs. - -config I2C_MPC - tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx" - depends on PPC - help - If you say yes to this option, support will be included for the - built-in I2C interface on the MPC107, Tsi107, MPC512x, MPC52xx, - MPC8240, MPC8245, MPC83xx, MPC85xx and MPC8641 family processors. - - This driver can also be built as a module. If so, the module - will be called i2c-mpc. - -config I2C_MT65XX - tristate "MediaTek I2C adapter" - depends on ARCH_MEDIATEK || COMPILE_TEST - depends on HAS_DMA - help - This selects the MediaTek(R) Integrated Inter Circuit bus driver - for MT65xx and MT81xx. - If you want to use MediaTek(R) I2C interface, say Y or M here. - If unsure, say N. - -config I2C_MV64XXX - tristate "Marvell mv64xxx I2C Controller" - depends on MV64X60 || PLAT_ORION || ARCH_SUNXI || ARCH_MVEBU - help - If you say yes to this option, support will be included for the - built-in I2C interface on the Marvell 64xxx line of host bridges. - This driver is also used for Allwinner SoCs I2C controllers. - - This driver can also be built as a module. If so, the module - will be called i2c-mv64xxx. - -config I2C_MXS - tristate "Freescale i.MX28 I2C interface" - depends on SOC_IMX28 - select STMP_DEVICE - help - Say Y here if you want to use the I2C bus controller on - the Freescale i.MX28 processors. - - This driver can also be built as a module. If so, the module - will be called i2c-mxs. - -config I2C_NOMADIK - tristate "ST-Ericsson Nomadik/Ux500 I2C Controller" - depends on ARM_AMBA - help - If you say yes to this option, support will be included for the - I2C interface from ST-Ericsson's Nomadik and Ux500 architectures, - as well as the STA2X11 PCIe I/O HUB. - -config I2C_OCORES - tristate "OpenCores I2C Controller" - help - If you say yes to this option, support will be included for the - OpenCores I2C controller. For details see - http://www.opencores.org/projects.cgi/web/i2c/overview - - This driver can also be built as a module. If so, the module - will be called i2c-ocores. - -config I2C_OMAP - tristate "OMAP I2C adapter" - depends on ARCH_OMAP - default y if MACH_OMAP_H3 || MACH_OMAP_OSK - help - If you say yes to this option, support will be included for the - I2C interface on the Texas Instruments OMAP1/2 family of processors. - Like OMAP1510/1610/1710/5912 and OMAP242x. - For details see http://www.ti.com/omap. - -config I2C_PASEMI - tristate "PA Semi SMBus interface" - depends on PPC_PASEMI && PCI - help - Supports the PA Semi PWRficient on-chip SMBus interfaces. - -config I2C_PCA_PLATFORM - tristate "PCA9564/PCA9665 as platform device" - select I2C_ALGOPCA - default n - help - This driver supports a memory mapped Philips PCA9564/PCA9665 - parallel bus to I2C bus controller. - - This driver can also be built as a module. If so, the module - will be called i2c-pca-platform. - -config I2C_PMCMSP - tristate "PMC MSP I2C TWI Controller" - depends on PMC_MSP - help - This driver supports the PMC TWI controller on MSP devices. - - This driver can also be built as module. If so, the module - will be called i2c-pmcmsp. - -config I2C_PNX - tristate "I2C bus support for Philips PNX and NXP LPC targets" - depends on ARCH_LPC32XX - help - This driver supports the Philips IP3204 I2C IP block master and/or - slave controller - - This driver can also be built as a module. If so, the module - will be called i2c-pnx. - -config I2C_PUV3 - tristate "PKUnity v3 I2C bus support" - depends on UNICORE32 && ARCH_PUV3 - select I2C_ALGOBIT - help - This driver supports the I2C IP inside the PKUnity-v3 SoC. - This I2C bus controller is under AMBA/AXI bus. - - This driver can also be built as a module. If so, the module - will be called i2c-puv3. - -config I2C_PXA - tristate "Intel PXA2XX I2C adapter" - depends on ARCH_PXA || ARCH_MMP || (X86_32 && PCI && OF) - help - If you have devices in the PXA I2C bus, say yes to this option. - This driver can also be built as a module. If so, the module - will be called i2c-pxa. - -config I2C_PXA_PCI - def_bool I2C_PXA && X86_32 && PCI && OF - -config I2C_PXA_SLAVE - bool "Intel PXA2XX I2C Slave comms support" - depends on I2C_PXA && !X86_32 - help - Support I2C slave mode communications on the PXA I2C bus. This - is necessary for systems where the PXA may be a target on the - I2C bus. - -config I2C_QUP - tristate "Qualcomm QUP based I2C controller" - depends on ARCH_QCOM - help - If you say yes to this option, support will be included for the - built-in I2C interface on the Qualcomm SoCs. - - This driver can also be built as a module. If so, the module - will be called i2c-qup. - -config I2C_RIIC - tristate "Renesas RIIC adapter" - depends on ARCH_RENESAS || COMPILE_TEST - help - If you say yes to this option, support will be included for the - Renesas RIIC I2C interface. - - This driver can also be built as a module. If so, the module - will be called i2c-riic. - -config I2C_RK3X - tristate "Rockchip RK3xxx I2C adapter" - depends on OF && COMMON_CLK - help - Say Y here to include support for the I2C adapter in Rockchip RK3xxx - SoCs. - - This driver can also be built as a module. If so, the module will - be called i2c-rk3x. - -config HAVE_S3C2410_I2C - bool - help - This will include I2C support for Samsung SoCs. If you want to - include I2C support for any machine, kindly select this in the - respective Kconfig file. - -config I2C_S3C2410 - tristate "S3C2410 I2C Driver" - depends on HAVE_S3C2410_I2C - help - Say Y here to include support for I2C controller in the - Samsung SoCs. - -config I2C_SH7760 - tristate "Renesas SH7760 I2C Controller" - depends on CPU_SUBTYPE_SH7760 - help - This driver supports the 2 I2C interfaces on the Renesas SH7760. - - This driver can also be built as a module. If so, the module - will be called i2c-sh7760. - -config I2C_SH_MOBILE - tristate "SuperH Mobile I2C Controller" - depends on HAS_DMA - depends on ARCH_SHMOBILE || ARCH_RENESAS || COMPILE_TEST - help - If you say yes to this option, support will be included for the - built-in I2C interface on the Renesas SH-Mobile processor. - - This driver can also be built as a module. If so, the module - will be called i2c-sh_mobile. - -config I2C_SIMTEC - tristate "Simtec Generic I2C interface" - select I2C_ALGOBIT - help - If you say yes to this option, support will be included for - the Simtec Generic I2C interface. This driver is for the - simple I2C bus used on newer Simtec products for general - I2C, such as DDC on the Simtec BBD2016A. - - This driver can also be built as a module. If so, the module - will be called i2c-simtec. - -config I2C_SIRF - tristate "CSR SiRFprimaII I2C interface" - depends on ARCH_SIRF - help - If you say yes to this option, support will be included for the - CSR SiRFprimaII I2C interface. - - This driver can also be built as a module. If so, the module - will be called i2c-sirf. - -config I2C_ST - tristate "STMicroelectronics SSC I2C support" - depends on ARCH_STI - help - Enable this option to add support for STMicroelectronics SoCs - hardware SSC (Synchronous Serial Controller) as an I2C controller. - - This driver can also be built as module. If so, the module - will be called i2c-st. - -config I2C_STU300 - tristate "ST Microelectronics DDC I2C interface" - depends on MACH_U300 - default y if MACH_U300 - help - If you say yes to this option, support will be included for the - I2C interface from ST Microelectronics simply called "DDC I2C" - supporting both I2C and DDC, used in e.g. the U300 series - mobile platforms. - - This driver can also be built as a module. If so, the module - will be called i2c-stu300. - -config I2C_SUN6I_P2WI - tristate "Allwinner sun6i internal P2WI controller" - depends on RESET_CONTROLLER - depends on MACH_SUN6I || COMPILE_TEST - help - If you say yes to this option, support will be included for the - P2WI (Push/Pull 2 Wire Interface) controller embedded in some sunxi - SOCs. - The P2WI looks like an SMBus controller (which supports only byte - accesses), except that it only supports one slave device. - This interface is used to connect to specific PMIC devices (like the - AXP221). - -config I2C_TEGRA - tristate "NVIDIA Tegra internal I2C controller" - depends on ARCH_TEGRA - help - If you say yes to this option, support will be included for the - I2C controller embedded in NVIDIA Tegra SOCs - -config I2C_UNIPHIER - tristate "UniPhier FIFO-less I2C controller" - depends on ARCH_UNIPHIER || COMPILE_TEST - help - If you say yes to this option, support will be included for - the UniPhier FIFO-less I2C interface embedded in PH1-LD4, PH1-sLD8, - or older UniPhier SoCs. - -config I2C_UNIPHIER_F - tristate "UniPhier FIFO-builtin I2C controller" - depends on ARCH_UNIPHIER || COMPILE_TEST - help - If you say yes to this option, support will be included for - the UniPhier FIFO-builtin I2C interface embedded in PH1-Pro4, - PH1-Pro5, or newer UniPhier SoCs. - -config I2C_VERSATILE - tristate "ARM Versatile/Realview I2C bus support" - depends on ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS || COMPILE_TEST - select I2C_ALGOBIT - help - Say yes if you want to support the I2C serial bus on ARMs Versatile - range of platforms. - - This driver can also be built as a module. If so, the module - will be called i2c-versatile. - -config I2C_WMT - tristate "Wondermedia WM8xxx SoC I2C bus support" - depends on ARCH_VT8500 - help - Say yes if you want to support the I2C bus on Wondermedia 8xxx-series - SoCs. - - This driver can also be built as a module. If so, the module will be - called i2c-wmt. - -config I2C_OCTEON - tristate "Cavium OCTEON I2C bus support" - depends on CAVIUM_OCTEON_SOC - help - Say yes if you want to support the I2C serial bus on Cavium - OCTEON SOC. - - This driver can also be built as a module. If so, the module - will be called i2c-octeon. - -config I2C_THUNDERX - tristate "Cavium ThunderX I2C bus support" - depends on 64BIT && PCI && (ARM64 || COMPILE_TEST) - select I2C_SMBUS - help - Say yes if you want to support the I2C serial bus on Cavium - ThunderX SOC. - - This driver can also be built as a module. If so, the module - will be called i2c-thunderx. - -config I2C_XILINX - tristate "Xilinx I2C Controller" - depends on HAS_IOMEM - help - If you say yes to this option, support will be included for the - Xilinx I2C controller. - - This driver can also be built as a module. If so, the module - will be called xilinx_i2c. - -config I2C_XLR - tristate "Netlogic XLR and Sigma Designs I2C support" - depends on CPU_XLR || ARCH_TANGO - help - This driver enables support for the on-chip I2C interface of - the Netlogic XLR/XLS MIPS processors and Sigma Designs SOCs. - - This driver can also be built as a module. If so, the module - will be called i2c-xlr. - -config I2C_XLP9XX - tristate "XLP9XX I2C support" - depends on CPU_XLP || ARCH_VULCAN || COMPILE_TEST - help - This driver enables support for the on-chip I2C interface of - the Broadcom XLP9xx/XLP5xx MIPS and Vulcan ARM64 processors. - - This driver can also be built as a module. If so, the module will - be called i2c-xlp9xx. - -config I2C_RCAR - tristate "Renesas R-Car I2C Controller" - depends on HAS_DMA - depends on ARCH_RENESAS || COMPILE_TEST - select I2C_SLAVE - help - If you say yes to this option, support will be included for the - R-Car I2C controller. - - This driver can also be built as a module. If so, the module - will be called i2c-rcar. - -comment "External I2C/SMBus adapter drivers" - -config I2C_DIOLAN_U2C - tristate "Diolan U2C-12 USB adapter" - depends on USB - help - If you say yes to this option, support will be included for Diolan - U2C-12, a USB to I2C interface. - - This driver can also be built as a module. If so, the module - will be called i2c-diolan-u2c. - -config I2C_DLN2 - tristate "Diolan DLN-2 USB I2C adapter" - depends on MFD_DLN2 - help - If you say yes to this option, support will be included for Diolan - DLN2, a USB to I2C interface. - - This driver can also be built as a module. If so, the module - will be called i2c-dln2. - -config I2C_PARPORT - tristate "Parallel port adapter" - depends on PARPORT - select I2C_ALGOBIT - select I2C_SMBUS - help - This supports parallel port I2C adapters such as the ones made by - Philips or Velleman, Analog Devices evaluation boards, and more. - Basically any adapter using the parallel port as an I2C bus with - no extra chipset is supported by this driver, or could be. - - This driver is a replacement for (and was inspired by) an older - driver named i2c-philips-par. The new driver supports more devices, - and makes it easier to add support for new devices. - - An adapter type parameter is now mandatory. Please read the file - Documentation/i2c/busses/i2c-parport for details. - - Another driver exists, named i2c-parport-light, which doesn't depend - on the parport driver. This is meant for embedded systems. Don't say - Y here if you intend to say Y or M there. - - This support is also available as a module. If so, the module - will be called i2c-parport. - -config I2C_PARPORT_LIGHT - tristate "Parallel port adapter (light)" - select I2C_ALGOBIT - select I2C_SMBUS - help - This supports parallel port I2C adapters such as the ones made by - Philips or Velleman, Analog Devices evaluation boards, and more. - Basically any adapter using the parallel port as an I2C bus with - no extra chipset is supported by this driver, or could be. - - This driver is a light version of i2c-parport. It doesn't depend - on the parport driver, and uses direct I/O access instead. This - might be preferred on embedded systems where wasting memory for - the clean but heavy parport handling is not an option. The - drawback is a reduced portability and the impossibility to - daisy-chain other parallel port devices. - - Don't say Y here if you said Y or M to i2c-parport. Saying M to - both is possible but both modules should not be loaded at the same - time. - - This support is also available as a module. If so, the module - will be called i2c-parport-light. - -config I2C_ROBOTFUZZ_OSIF - tristate "RobotFuzz Open Source InterFace USB adapter" - depends on USB - help - If you say yes to this option, support will be included for the - RobotFuzz Open Source InterFace USB to I2C interface. - - This driver can also be built as a module. If so, the module - will be called i2c-osif. - -config I2C_TAOS_EVM - tristate "TAOS evaluation module" - depends on TTY - select SERIO - select SERIO_SERPORT - default n - help - This supports TAOS evaluation modules on serial port. In order to - use this driver, you will need the inputattach tool, which is part - of the input-utils package. - - If unsure, say N. - - This support is also available as a module. If so, the module - will be called i2c-taos-evm. - -config I2C_TINY_USB - tristate "Tiny-USB adapter" - depends on USB - help - If you say yes to this option, support will be included for the - i2c-tiny-usb, a simple do-it-yourself USB to I2C interface. See - http://www.harbaum.org/till/i2c_tiny_usb for hardware details. - - This driver can also be built as a module. If so, the module - will be called i2c-tiny-usb. - -config I2C_VIPERBOARD - tristate "Viperboard I2C master support" - depends on MFD_VIPERBOARD && USB - help - Say yes here to access the I2C part of the Nano River - Technologies Viperboard as I2C master. - See viperboard API specification and Nano - River Tech's viperboard.h for detailed meaning - of the module parameters. - -comment "Other I2C/SMBus bus drivers" - -config I2C_ACORN - tristate "Acorn IOC/IOMD I2C bus support" - depends on ARCH_ACORN - default y - select I2C_ALGOBIT - help - Say yes if you want to support the I2C bus on Acorn platforms. - - If you don't know, say Y. - -config I2C_ELEKTOR - tristate "Elektor ISA card" - depends on ISA && HAS_IOPORT_MAP && BROKEN_ON_SMP - select I2C_ALGOPCF - help - This supports the PCF8584 ISA bus I2C adapter. Say Y if you own - such an adapter. - - This support is also available as a module. If so, the module - will be called i2c-elektor. - -config I2C_PCA_ISA - tristate "PCA9564/PCA9665 on an ISA bus" - depends on ISA - select I2C_ALGOPCA - default n - help - This driver supports ISA boards using the Philips PCA9564/PCA9665 - parallel bus to I2C bus controller. - - This driver can also be built as a module. If so, the module - will be called i2c-pca-isa. - - This device is almost undetectable and using this driver on a - system which doesn't have this device will result in long - delays when I2C/SMBus chip drivers are loaded (e.g. at boot - time). If unsure, say N. - -config I2C_SIBYTE - tristate "SiByte SMBus interface" - depends on SIBYTE_SB1xxx_SOC - help - Supports the SiByte SOC on-chip I2C interfaces (2 channels). - -config I2C_CROS_EC_TUNNEL - tristate "ChromeOS EC tunnel I2C bus" - depends on MFD_CROS_EC - help - If you say yes here you get an I2C bus that will tunnel i2c commands - through to the other side of the ChromeOS EC to the i2c bus - connected there. This will work whatever the interface used to - talk to the EC (SPI, I2C or LPC). - -config I2C_XGENE_SLIMPRO - tristate "APM X-Gene SoC I2C SLIMpro devices support" - depends on ARCH_XGENE && MAILBOX - help - Enable I2C bus access using the APM X-Gene SoC SLIMpro - co-processor. The I2C device access the I2C bus via the X-Gene - to SLIMpro (On chip coprocessor) mailbox mechanism. - If unsure, say N. - -config SCx200_ACB - tristate "Geode ACCESS.bus support" - depends on X86_32 && PCI - help - Enable the use of the ACCESS.bus controllers on the Geode SCx200 and - SC1100 processors and the CS5535 and CS5536 Geode companion devices. - - If you don't know what to do here, say N. - - This support is also available as a module. If so, the module - will be called scx200_acb. - -config I2C_OPAL - tristate "IBM OPAL I2C driver" - depends on PPC_POWERNV - default y - help - This exposes the PowerNV platform i2c busses to the linux i2c layer, - the driver is based on the OPAL interfaces. - - This driver can also be built as a module. If so, the module will be - called as i2c-opal. - -endmenu diff --git a/src/linux/drivers/i2c/busses/Makefile b/src/linux/drivers/i2c/busses/Makefile deleted file mode 100644 index 29764cc..0000000 --- a/src/linux/drivers/i2c/busses/Makefile +++ /dev/null @@ -1,125 +0,0 @@ -# -# Makefile for the i2c bus drivers. -# - -# ACPI drivers -obj-$(CONFIG_I2C_SCMI) += i2c-scmi.o - -# PC SMBus host controller drivers -obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o -obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o -obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o -obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o -obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o -obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o -obj-$(CONFIG_I2C_I801) += i2c-i801.o -obj-$(CONFIG_I2C_ISCH) += i2c-isch.o -obj-$(CONFIG_I2C_ISMT) += i2c-ismt.o -obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o -obj-$(CONFIG_I2C_NFORCE2_S4985) += i2c-nforce2-s4985.o -obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o -obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o -obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o -obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o -obj-$(CONFIG_I2C_VIA) += i2c-via.o -obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o - -# Mac SMBus host controller drivers -obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o -obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o - -# Embedded system I2C/SMBus host controller drivers -obj-$(CONFIG_I2C_AT91) += i2c-at91.o -obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o -obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o -obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o -obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o -obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o -obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o -obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o -obj-$(CONFIG_I2C_CPM) += i2c-cpm.o -obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o -obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o -obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o -i2c-designware-platform-objs := i2c-designware-platdrv.o -i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o -obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o -i2c-designware-pci-objs := i2c-designware-pcidrv.o -obj-$(CONFIG_I2C_DIGICOLOR) += i2c-digicolor.o -obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o -obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o -obj-$(CONFIG_I2C_EMEV2) += i2c-emev2.o -obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o -obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o -obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o -obj-$(CONFIG_I2C_HIX5HD2) += i2c-hix5hd2.o -obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o -obj-$(CONFIG_I2C_IMG) += i2c-img-scb.o -obj-$(CONFIG_I2C_IMX) += i2c-imx.o -obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o -obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o -obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o -obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o -obj-$(CONFIG_I2C_MESON) += i2c-meson.o -obj-$(CONFIG_I2C_MPC) += i2c-mpc.o -obj-$(CONFIG_I2C_MT65XX) += i2c-mt65xx.o -obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o -obj-$(CONFIG_I2C_MXS) += i2c-mxs.o -obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o -obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o -obj-$(CONFIG_I2C_OMAP) += i2c-omap.o -obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o -obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o -obj-$(CONFIG_I2C_PMCMSP) += i2c-pmcmsp.o -obj-$(CONFIG_I2C_PNX) += i2c-pnx.o -obj-$(CONFIG_I2C_PUV3) += i2c-puv3.o -obj-$(CONFIG_I2C_PXA) += i2c-pxa.o -obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o -obj-$(CONFIG_I2C_QUP) += i2c-qup.o -obj-$(CONFIG_I2C_RIIC) += i2c-riic.o -obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o -obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o -obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o -obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o -obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o -obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o -obj-$(CONFIG_I2C_ST) += i2c-st.o -obj-$(CONFIG_I2C_STU300) += i2c-stu300.o -obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o -obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o -obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o -obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o -obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o -obj-$(CONFIG_I2C_WMT) += i2c-wmt.o -i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o -obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o -i2c-thunderx-objs := i2c-octeon-core.o i2c-thunderx-pcidrv.o -obj-$(CONFIG_I2C_THUNDERX) += i2c-thunderx.o -obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o -obj-$(CONFIG_I2C_XLR) += i2c-xlr.o -obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o -obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o - -# External I2C/SMBus adapter drivers -obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o -obj-$(CONFIG_I2C_DLN2) += i2c-dln2.o -obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o -obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o -obj-$(CONFIG_I2C_ROBOTFUZZ_OSIF) += i2c-robotfuzz-osif.o -obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o -obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o -obj-$(CONFIG_I2C_VIPERBOARD) += i2c-viperboard.o - -# Other I2C/SMBus bus drivers -obj-$(CONFIG_I2C_ACORN) += i2c-acorn.o -obj-$(CONFIG_I2C_BCM_KONA) += i2c-bcm-kona.o -obj-$(CONFIG_I2C_BRCMSTB) += i2c-brcmstb.o -obj-$(CONFIG_I2C_CROS_EC_TUNNEL) += i2c-cros-ec-tunnel.o -obj-$(CONFIG_I2C_ELEKTOR) += i2c-elektor.o -obj-$(CONFIG_I2C_OPAL) += i2c-opal.o -obj-$(CONFIG_I2C_PCA_ISA) += i2c-pca-isa.o -obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o -obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o -obj-$(CONFIG_SCx200_ACB) += scx200_acb.o - -ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG diff --git a/src/linux/drivers/i2c/muxes/Kconfig b/src/linux/drivers/i2c/muxes/Kconfig deleted file mode 100644 index 96de9ce..0000000 --- a/src/linux/drivers/i2c/muxes/Kconfig +++ /dev/null @@ -1,85 +0,0 @@ -# -# Multiplexer I2C chip drivers configuration -# - -menu "Multiplexer I2C Chip support" - depends on I2C_MUX - -config I2C_ARB_GPIO_CHALLENGE - tristate "GPIO-based I2C arbitration" - depends on GPIOLIB || COMPILE_TEST - depends on OF - help - If you say yes to this option, support will be included for an - I2C multimaster arbitration scheme using GPIOs and a challenge & - response mechanism where masters have to claim the bus by asserting - a GPIO. - - This driver can also be built as a module. If so, the module - will be called i2c-arb-gpio-challenge. - -config I2C_MUX_GPIO - tristate "GPIO-based I2C multiplexer" - depends on GPIOLIB - help - If you say yes to this option, support will be included for a - GPIO based I2C multiplexer. This driver provides access to - I2C busses connected through a MUX, which is controlled - through GPIO pins. - - This driver can also be built as a module. If so, the module - will be called i2c-mux-gpio. - -config I2C_MUX_PCA9541 - tristate "NXP PCA9541 I2C Master Selector" - help - If you say yes here you get support for the NXP PCA9541 - I2C Master Selector. - - This driver can also be built as a module. If so, the module - will be called i2c-mux-pca9541. - -config I2C_MUX_PCA954x - tristate "Philips PCA954x I2C Mux/switches" - depends on GPIOLIB || COMPILE_TEST - help - If you say yes here you get support for the Philips PCA954x - I2C mux/switch devices. - - This driver can also be built as a module. If so, the module - will be called i2c-mux-pca954x. - -config I2C_MUX_PINCTRL - tristate "pinctrl-based I2C multiplexer" - depends on PINCTRL - help - If you say yes to this option, support will be included for an I2C - multiplexer that uses the pinctrl subsystem, i.e. pin multiplexing. - This is useful for SoCs whose I2C module's signals can be routed to - different sets of pins at run-time. - - This driver can also be built as a module. If so, the module will be - called pinctrl-i2cmux. - -config I2C_MUX_REG - tristate "Register-based I2C multiplexer" - depends on HAS_IOMEM - help - If you say yes to this option, support will be included for a - register based I2C multiplexer. This driver provides access to - I2C busses connected through a MUX, which is controlled - by a single register. - - This driver can also be built as a module. If so, the module - will be called i2c-mux-reg. - -config I2C_DEMUX_PINCTRL - tristate "pinctrl-based I2C demultiplexer" - depends on PINCTRL && OF - select OF_DYNAMIC - help - If you say yes to this option, support will be included for an I2C - demultiplexer that uses the pinctrl subsystem. This is useful if you - want to change the I2C master at run-time depending on features. - -endmenu diff --git a/src/linux/drivers/i2c/muxes/Makefile b/src/linux/drivers/i2c/muxes/Makefile deleted file mode 100644 index 7c267c2..0000000 --- a/src/linux/drivers/i2c/muxes/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# -# Makefile for multiplexer I2C chip drivers. - -obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o - -obj-$(CONFIG_I2C_DEMUX_PINCTRL) += i2c-demux-pinctrl.o - -obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o -obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o -obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o -obj-$(CONFIG_I2C_MUX_PINCTRL) += i2c-mux-pinctrl.o -obj-$(CONFIG_I2C_MUX_REG) += i2c-mux-reg.o - -ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG diff --git a/src/linux/drivers/ide/Kconfig b/src/linux/drivers/ide/Kconfig deleted file mode 100644 index 39ea67f..0000000 --- a/src/linux/drivers/ide/Kconfig +++ /dev/null @@ -1,871 +0,0 @@ -# -# IDE ATA ATAPI Block device driver configuration -# - -# Select HAVE_IDE if IDE is supported -config HAVE_IDE - bool - -menuconfig IDE - tristate "ATA/ATAPI/MFM/RLL support (DEPRECATED)" - depends on HAVE_IDE - depends on BLOCK - ---help--- - If you say Y here, your kernel will be able to manage ATA/(E)IDE and - ATAPI units. The most common cases are IDE hard drives and ATAPI - CD-ROM drives. - - This subsystem is currently in maintenance mode with only bug fix - changes applied. Users of ATA hardware are encouraged to migrate to - the newer ATA subsystem ("Serial ATA (prod) and Parallel ATA - (experimental) drivers") which is more actively maintained. - - To compile this driver as a module, choose M here: the - module will be called ide-core. - - For further information, please read . - - If unsure, say N. - -if IDE - -comment "Please see Documentation/ide/ide.txt for help/info on IDE drives" - -config IDE_XFER_MODE - bool - -config IDE_TIMINGS - bool - select IDE_XFER_MODE - -config IDE_ATAPI - bool - -config IDE_LEGACY - bool - -config BLK_DEV_IDE_SATA - bool "Support for SATA (deprecated; conflicts with libata SATA driver)" - default n - ---help--- - There are two drivers for Serial ATA controllers. - - The main driver, "libata", uses the SCSI subsystem - and supports most modern SATA controllers. In order to use it - you may take a look at "Serial ATA (prod) and Parallel ATA - (experimental) drivers". - - The IDE driver (which you are currently configuring) supports - a few first-generation SATA controllers. - - In order to eliminate conflicts between the two subsystems, - this config option enables the IDE driver's SATA support. - Normally this is disabled, as it is preferred that libata - supports SATA controllers, and this (IDE) driver supports - PATA controllers. - - If unsure, say N. - -config IDE_GD - tristate "generic ATA/ATAPI disk support" - default y - help - Support for ATA/ATAPI disks (including ATAPI floppy drives). - - To compile this driver as a module, choose M here. - The module will be called ide-gd_mod. - - If unsure, say Y. - -config IDE_GD_ATA - bool "ATA disk support" - depends on IDE_GD - default y - help - This will include support for ATA hard disks. - - If unsure, say Y. - -config IDE_GD_ATAPI - bool "ATAPI floppy support" - depends on IDE_GD - select IDE_ATAPI - help - This will include support for ATAPI floppy drives - (i.e. Iomega ZIP or MKE LS-120). - - For information about jumper settings and the question - of when a ZIP drive uses a partition table, see - . - - If unsure, say N. - -config BLK_DEV_IDECS - tristate "PCMCIA IDE support" - depends on PCMCIA - help - Support for Compact Flash cards, outboard IDE disks, tape drives, - and CD-ROM drives connected through a PCMCIA card. - -config BLK_DEV_DELKIN - tristate "Cardbus IDE support (Delkin/ASKA/Workbit)" - depends on CARDBUS && PCI - help - Support for Delkin, ASKA, and Workbit Cardbus CompactFlash - Adapters. This may also work for similar SD and XD adapters. - -config BLK_DEV_IDECD - tristate "Include IDE/ATAPI CDROM support" - select IDE_ATAPI - ---help--- - If you have a CD-ROM drive using the ATAPI protocol, say Y. ATAPI is - a newer protocol used by IDE CD-ROM and TAPE drives, similar to the - SCSI protocol. Most new CD-ROM drives use ATAPI, including the - NEC-260, Mitsumi FX400, Sony 55E, and just about all non-SCSI - double(2X) or better speed drives. - - If you say Y here, the CD-ROM drive will be identified at boot time - along with other IDE devices, as "hdb" or "hdc", or something - similar (check the boot messages with dmesg). If this is your only - CD-ROM drive, you can say N to all other CD-ROM options, but be sure - to say Y or M to "ISO 9660 CD-ROM file system support". - - To compile this driver as a module, choose M here: the - module will be called ide-cd. - -config BLK_DEV_IDECD_VERBOSE_ERRORS - bool "Verbose error logging for IDE/ATAPI CDROM driver" if EXPERT - depends on BLK_DEV_IDECD - default y - help - Turn this on to have the driver print out the meanings of the - ATAPI error codes. This will use up additional 8kB of kernel-space - memory, though. - -config BLK_DEV_IDETAPE - tristate "Include IDE/ATAPI TAPE support" - select IDE_ATAPI - help - If you have an IDE tape drive using the ATAPI protocol, say Y. - ATAPI is a newer protocol used by IDE tape and CD-ROM drives, - similar to the SCSI protocol. If you have an SCSI tape drive - however, you can say N here. - - You should also say Y if you have an OnStream DI-30 tape drive; this - will not work with the SCSI protocol, until there is support for the - SC-30 and SC-50 versions. - - If you say Y here, the tape drive will be identified at boot time - along with other IDE devices, as "hdb" or "hdc", or something - similar, and will be mapped to a character device such as "ht0" - (check the boot messages with dmesg). Be sure to consult the - and - files for usage information. - - To compile this driver as a module, choose M here: the - module will be called ide-tape. - -config BLK_DEV_IDEACPI - bool "IDE ACPI support" - depends on ACPI - ---help--- - Implement ACPI support for generic IDE devices. On modern - machines ACPI support is required to properly handle ACPI S3 states. - -config IDE_TASK_IOCTL - bool "IDE Taskfile Access" - help - This is a direct raw access to the media. It is a complex but - elegant solution to test and validate the domain of the hardware and - perform below the driver data recovery if needed. This is the most - basic form of media-forensics. - - If you are unsure, say N here. - -config IDE_PROC_FS - bool "legacy /proc/ide/ support" - depends on IDE && PROC_FS - default y - help - This option enables support for the various files in - /proc/ide. In Linux 2.6 this has been superseded by - files in sysfs but many legacy applications rely on this. - - If unsure say Y. - -comment "IDE chipset support/bugfixes" - -config IDE_GENERIC - tristate "generic/default IDE chipset support" - depends on ALPHA || X86 || IA64 || M32R || MIPS || ARCH_RPC - default ARM && ARCH_RPC - help - This is the generic IDE driver. This driver attaches to the - fixed legacy ports (e.g. on PCs 0x1f0/0x170, 0x1e8/0x168 and - so on). Please note that if this driver is built into the - kernel or loaded before other ATA (IDE or libata) drivers - and the controller is located at legacy ports, this driver - may grab those ports and thus can prevent the controller - specific driver from attaching. - - Also, currently, IDE generic doesn't allow IRQ sharing - meaning that the IRQs it grabs won't be available to other - controllers sharing those IRQs which usually makes drivers - for those controllers fail. Generally, it's not a good idea - to load IDE generic driver on modern systems. - - If unsure, say N. - -config BLK_DEV_PLATFORM - tristate "Platform driver for IDE interfaces" - help - This is the platform IDE driver, used mostly for Memory Mapped - IDE devices, like Compact Flashes running in True IDE mode. - - If unsure, say N. - -config BLK_DEV_CMD640 - tristate "CMD640 chipset bugfix/support" - depends on X86 - select IDE_TIMINGS - ---help--- - The CMD-Technologies CMD640 IDE chip is used on many common 486 and - Pentium motherboards, usually in combination with a "Neptune" or - "SiS" chipset. Unfortunately, it has a number of rather nasty - design flaws that can cause severe data corruption under many common - conditions. Say Y here to include code which tries to automatically - detect and correct the problems under Linux. This option also - enables access to the secondary IDE ports in some CMD640 based - systems. - - This driver will work automatically in PCI based systems (most new - systems have PCI slots). But if your system uses VESA local bus - (VLB) instead of PCI, you must also supply a kernel boot parameter - to enable the CMD640 bugfix/support: "cmd640.probe_vlb". (Try "man - bootparam" or see the documentation of your boot loader about how to - pass options to the kernel.) - - The CMD640 chip is also used on add-in cards by Acculogic, and on - the "CSA-6400E PCI to IDE controller" that some people have. For - details, read . - -config BLK_DEV_CMD640_ENHANCED - bool "CMD640 enhanced support" - depends on BLK_DEV_CMD640 - help - This option includes support for setting/autotuning PIO modes and - prefetch on CMD640 IDE interfaces. For details, read - . If you have a CMD640 IDE interface - and your BIOS does not already do this for you, then say Y here. - Otherwise say N. - -config BLK_DEV_IDEPNP - tristate "PNP EIDE support" - depends on PNP - help - If you have a PnP (Plug and Play) compatible EIDE card and - would like the kernel to automatically detect and activate - it, say Y here. - -config BLK_DEV_IDEDMA_SFF - bool - -if PCI - -comment "PCI IDE chipsets support" - -config BLK_DEV_IDEPCI - bool - -config IDEPCI_PCIBUS_ORDER - bool "Probe IDE PCI devices in the PCI bus order (DEPRECATED)" - depends on IDE=y && BLK_DEV_IDEPCI - default y - help - Probe IDE PCI devices in the order in which they appear on the - PCI bus (i.e. 00:1f.1 PCI device before 02:01.0 PCI device) - instead of the order in which IDE PCI host drivers are loaded. - - Please note that this method of assuring stable naming of - IDE devices is unreliable and use other means for achieving - it (i.e. udev). - - If in doubt, say N. - -# TODO: split it on per host driver config options (or module parameters) -config BLK_DEV_OFFBOARD - bool "Boot off-board chipsets first support (DEPRECATED)" - depends on BLK_DEV_IDEPCI && (BLK_DEV_AEC62XX || BLK_DEV_GENERIC || BLK_DEV_HPT366 || BLK_DEV_PDC202XX_NEW || BLK_DEV_PDC202XX_OLD || BLK_DEV_TC86C001) - help - Normally, IDE controllers built into the motherboard (on-board - controllers) are assigned to ide0 and ide1 while those on add-in PCI - cards (off-board controllers) are relegated to ide2 and ide3. - Answering Y here will allow you to reverse the situation, with - off-board controllers on ide0/1 and on-board controllers on ide2/3. - This can improve the usability of some boot managers such as lilo - when booting from a drive on an off-board controller. - - Note that, if you do this, the order of the hd* devices will be - rearranged which may require modification of fstab and other files. - - Please also note that this method of assuring stable naming of - IDE devices is unreliable and use other means for achieving it - (i.e. udev). - - If in doubt, say N. - -config BLK_DEV_GENERIC - tristate "Generic PCI IDE Chipset Support" - select BLK_DEV_IDEPCI - help - This option provides generic support for various PCI IDE Chipsets - which otherwise might not be supported. - -config BLK_DEV_OPTI621 - tristate "OPTi 82C621 chipset enhanced support" - select BLK_DEV_IDEPCI - help - This is a driver for the OPTi 82C621 EIDE controller. - Please read the comments at the top of . - -config BLK_DEV_RZ1000 - tristate "RZ1000 chipset bugfix/support" - depends on X86 - select BLK_DEV_IDEPCI - help - The PC-Technologies RZ1000 IDE chip is used on many common 486 and - Pentium motherboards, usually along with the "Neptune" chipset. - Unfortunately, it has a rather nasty design flaw that can cause - severe data corruption under many conditions. Say Y here to include - code which automatically detects and corrects the problem under - Linux. This may slow disk throughput by a few percent, but at least - things will operate 100% reliably. - -config BLK_DEV_IDEDMA_PCI - bool - select BLK_DEV_IDEPCI - select BLK_DEV_IDEDMA_SFF - -config BLK_DEV_AEC62XX - tristate "AEC62XX chipset support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds explicit support for Acard AEC62xx (Artop ATP8xx) - IDE controllers. This allows the kernel to change PIO, DMA and UDMA - speeds and to configure the chip to optimum performance. - -config BLK_DEV_ALI15X3 - tristate "ALI M15x3 chipset support" - select IDE_TIMINGS - select BLK_DEV_IDEDMA_PCI - help - This driver ensures (U)DMA support for ALI 1533, 1543 and 1543C - onboard chipsets. It also tests for Simplex mode and enables - normal dual channel support. - - Please read the comments at the top of - . - - If unsure, say N. - -config BLK_DEV_AMD74XX - tristate "AMD and nVidia IDE support" - depends on !ARM - select IDE_TIMINGS - select BLK_DEV_IDEDMA_PCI - help - This driver adds explicit support for AMD-7xx and AMD-8111 chips - and also for the nVidia nForce chip. This allows the kernel to - change PIO, DMA and UDMA speeds and to configure the chip to - optimum performance. - -config BLK_DEV_ATIIXP - tristate "ATI IXP chipset IDE support" - depends on X86 - select BLK_DEV_IDEDMA_PCI - help - This driver adds explicit support for ATI IXP chipset. - This allows the kernel to change PIO, DMA and UDMA speeds - and to configure the chip to optimum performance. - - Say Y here if you have an ATI IXP chipset IDE controller. - -config BLK_DEV_CMD64X - tristate "CMD64{3|6|8|9} chipset support" - select IDE_TIMINGS - select BLK_DEV_IDEDMA_PCI - help - Say Y here if you have an IDE controller which uses any of these - chipsets: CMD643, CMD646, or CMD648. - -config BLK_DEV_TRIFLEX - tristate "Compaq Triflex IDE support" - select BLK_DEV_IDEDMA_PCI - help - Say Y here if you have a Compaq Triflex IDE controller, such - as those commonly found on Compaq Pentium-Pro systems - -config BLK_DEV_CY82C693 - tristate "CY82C693 chipset support" - depends on ALPHA - select IDE_TIMINGS - select BLK_DEV_IDEDMA_PCI - help - This driver adds detection and support for the CY82C693 chipset - used on Digital's PC-Alpha 164SX boards. - -config BLK_DEV_CS5520 - tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)" - depends on X86_32 || COMPILE_TEST - select BLK_DEV_IDEDMA_PCI - help - Include support for PIO tuning and virtual DMA on the Cyrix MediaGX - 5510/5520 chipset. This will automatically be detected and - configured if found. - - It is safe to say Y to this question. - -config BLK_DEV_CS5530 - tristate "Cyrix/National Semiconductor CS5530 MediaGX chipset support" - depends on X86_32 || COMPILE_TEST - select BLK_DEV_IDEDMA_PCI - help - Include support for UDMA on the Cyrix MediaGX 5530 chipset. This - will automatically be detected and configured if found. - - It is safe to say Y to this question. - -config BLK_DEV_CS5535 - tristate "AMD CS5535 chipset support" - depends on X86_32 - select BLK_DEV_IDEDMA_PCI - help - Include support for UDMA on the NSC/AMD CS5535 companion chipset. - This will automatically be detected and configured if found. - - It is safe to say Y to this question. - -config BLK_DEV_CS5536 - tristate "CS5536 chipset support" - depends on X86_32 - select BLK_DEV_IDEDMA_PCI - help - This option enables support for the AMD CS5536 - companion chip used with the Geode LX processor family. - - If unsure, say N. - -config BLK_DEV_HPT366 - tristate "HPT36X/37X chipset support" - select BLK_DEV_IDEDMA_PCI - help - HPT366 is an Ultra DMA chipset for ATA-66. - HPT368 is an Ultra DMA chipset for ATA-66 RAID Based. - HPT370 is an Ultra DMA chipset for ATA-100. - HPT372 is an Ultra DMA chipset for ATA-100. - HPT374 is an Ultra DMA chipset for ATA-100. - - This driver adds up to 4 more EIDE devices sharing a single - interrupt. - - The HPT366 chipset in its current form is bootable. One solution - for this problem are special LILO commands for redirecting the - reference to device 0x80. The other solution is to say Y to "Boot - off-board chipsets first support" (CONFIG_BLK_DEV_OFFBOARD) unless - your mother board has the chipset natively mounted. Regardless one - should use the fore mentioned option and call at LILO. - - This driver requires dynamic tuning of the chipset during the - ide-probe at boot. It is reported to support DVD II drives, by the - manufacturer. - -config BLK_DEV_JMICRON - tristate "JMicron JMB36x support" - select BLK_DEV_IDEDMA_PCI - help - Basic support for the JMicron ATA controllers. For full support - use the libata drivers. - -config BLK_DEV_SC1200 - tristate "National SCx200 chipset support" - depends on X86_32 || COMPILE_TEST - select BLK_DEV_IDEDMA_PCI - help - This driver adds support for the on-board IDE controller on the - National SCx200 series of embedded x86 "Geode" systems. - -config BLK_DEV_PIIX - tristate "Intel PIIX/ICH chipsets support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds explicit support for Intel PIIX and ICH chips. - This allows the kernel to change PIO, DMA and UDMA speeds and to - configure the chip to optimum performance. - -config BLK_DEV_IT8172 - tristate "IT8172 IDE support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds support for the IDE controller on the - IT8172 System Controller. - -config BLK_DEV_IT8213 - tristate "IT8213 IDE support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds support for the ITE 8213 IDE controller. - -config BLK_DEV_IT821X - tristate "IT821X IDE support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds support for the ITE 8211 IDE controller and the - IT 8212 IDE RAID controller in both RAID and pass-through mode. - -config BLK_DEV_NS87415 - tristate "NS87415 chipset support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds detection and support for the NS87415 chip - (used mainly on SPARC64 and PA-RISC machines). - - Please read the comments at the top of . - -config BLK_DEV_PDC202XX_OLD - tristate "PROMISE PDC202{46|62|65|67} support" - select BLK_DEV_IDEDMA_PCI - help - Promise Ultra33 or PDC20246 - Promise Ultra66 or PDC20262 - Promise Ultra100 or PDC20265/PDC20267/PDC20268 - - This driver adds up to 4 more EIDE devices sharing a single - interrupt. This add-on card is a bootable PCI UDMA controller. Since - multiple cards can be installed and there are BIOS ROM problems that - happen if the BIOS revisions of all installed cards (three-max) do - not match, the driver attempts to do dynamic tuning of the chipset - at boot-time for max-speed. Ultra33 BIOS 1.25 or newer is required - for more than one card. - - Please read the comments at the top of - . - - If unsure, say N. - -config BLK_DEV_PDC202XX_NEW - tristate "PROMISE PDC202{68|69|70|71|75|76|77} support" - select BLK_DEV_IDEDMA_PCI - -config BLK_DEV_SVWKS - tristate "ServerWorks OSB4/CSB5/CSB6 chipsets support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds PIO/(U)DMA support for the ServerWorks OSB4/CSB5 - chipsets. - -config BLK_DEV_SGIIOC4 - tristate "Silicon Graphics IOC4 chipset ATA/ATAPI support" - depends on (IA64_SGI_SN2 || IA64_GENERIC) && SGI_IOC4 - select BLK_DEV_IDEDMA_PCI - help - This driver adds PIO & MultiMode DMA-2 support for the SGI IOC4 - chipset, which has one channel and can support two devices. - Please say Y here if you have an Altix System from SGI. - -config BLK_DEV_SIIMAGE - tristate "Silicon Image chipset support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds PIO/(U)DMA support for the SI CMD680 and SII - 3112 (Serial ATA) chips. - -config BLK_DEV_SIS5513 - tristate "SiS5513 chipset support" - depends on X86 - select BLK_DEV_IDEDMA_PCI - help - This driver ensures (U)DMA support for SIS5513 chipset family based - mainboards. - - The following chipsets are supported: - ATA16: SiS5511, SiS5513 - ATA33: SiS5591, SiS5597, SiS5598, SiS5600 - ATA66: SiS530, SiS540, SiS620, SiS630, SiS640 - ATA100: SiS635, SiS645, SiS650, SiS730, SiS735, SiS740, - SiS745, SiS750 - - Please read the comments at the top of . - -config BLK_DEV_SL82C105 - tristate "Winbond SL82c105 support" - depends on (PPC || ARM) - select IDE_TIMINGS - select BLK_DEV_IDEDMA_PCI - help - If you have a Winbond SL82c105 IDE controller, say Y here to enable - special configuration for this chip. This is common on various CHRP - motherboards, but could be used elsewhere. If in doubt, say Y. - -config BLK_DEV_SLC90E66 - tristate "SLC90E66 chipset support" - select BLK_DEV_IDEDMA_PCI - help - This driver ensures (U)DMA support for Victory66 SouthBridges for - SMsC with Intel NorthBridges. This is an Ultra66 based chipset. - The nice thing about it is that you can mix Ultra/DMA/PIO devices - and it will handle timing cycles. Since this is an improved - look-a-like to the PIIX4 it should be a nice addition. - - Please read the comments at the top of - . - -config BLK_DEV_TRM290 - tristate "Tekram TRM290 chipset support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds support for bus master DMA transfers - using the Tekram TRM290 PCI IDE chip. Volunteers are - needed for further tweaking and development. - Please read the comments at the top of . - -config BLK_DEV_VIA82CXXX - tristate "VIA82CXXX chipset support" - select IDE_TIMINGS - select BLK_DEV_IDEDMA_PCI - help - This driver adds explicit support for VIA BusMastering IDE chips. - This allows the kernel to change PIO, DMA and UDMA speeds and to - configure the chip to optimum performance. - -config BLK_DEV_TC86C001 - tristate "Toshiba TC86C001 support" - select BLK_DEV_IDEDMA_PCI - help - This driver adds support for Toshiba TC86C001 GOKU-S chip. - -endif - -# TODO: BLK_DEV_IDEDMA_PCI -> BLK_DEV_IDEDMA_SFF -config BLK_DEV_IDE_PMAC - tristate "PowerMac on-board IDE support" - depends on PPC_PMAC - select IDE_TIMINGS - select BLK_DEV_IDEDMA_PCI - help - This driver provides support for the on-board IDE controller on - most of the recent Apple Power Macintoshes and PowerBooks. - If unsure, say Y. - -config BLK_DEV_IDE_PMAC_ATA100FIRST - bool "Probe on-board ATA/100 (Kauai) first" - depends on BLK_DEV_IDE_PMAC - help - This option will cause the ATA/100 controller found in UniNorth2 - based machines (Windtunnel PowerMac, Aluminium PowerBooks, ...) - to be probed before the ATA/66 and ATA/33 controllers. Without - these, those machine used to have the hard disk on hdc and the - CD-ROM on hda. This option changes this to more natural hda for - hard disk and hdc for CD-ROM. - -config BLK_DEV_IDE_AU1XXX - bool "IDE for AMD Alchemy Au1200" - depends on MIPS_ALCHEMY - select IDE_XFER_MODE -choice - prompt "IDE Mode for AMD Alchemy Au1200" - default BLK_DEV_IDE_AU1XXX_PIO_DBDMA - depends on BLK_DEV_IDE_AU1XXX - -config BLK_DEV_IDE_AU1XXX_PIO_DBDMA - bool "PIO+DbDMA IDE for AMD Alchemy Au1200" - -config BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA - bool "MDMA2+DbDMA IDE for AMD Alchemy Au1200" - depends on BLK_DEV_IDE_AU1XXX -endchoice - -config BLK_DEV_IDE_TX4938 - tristate "TX4938 internal IDE support" - depends on SOC_TX4938 - select IDE_TIMINGS - -config BLK_DEV_IDE_TX4939 - tristate "TX4939 internal IDE support" - depends on SOC_TX4939 - select BLK_DEV_IDEDMA_SFF - -config BLK_DEV_IDE_ICSIDE - tristate "ICS IDE interface support" - depends on ARM && ARCH_ACORN - help - On Acorn systems, say Y here if you wish to use the ICS IDE - interface card. This is not required for ICS partition support. - If you are unsure, say N to this. - -config BLK_DEV_IDEDMA_ICS - bool "ICS DMA support" - depends on BLK_DEV_IDE_ICSIDE - help - Say Y here if you want to add DMA (Direct Memory Access) support to - the ICS IDE driver. - -config BLK_DEV_IDE_RAPIDE - tristate "RapIDE interface support" - depends on ARM && ARCH_ACORN - help - Say Y here if you want to support the Yellowstone RapIDE controller - manufactured for use with Acorn computers. - -config BLK_DEV_GAYLE - tristate "Amiga Gayle IDE interface support" - depends on AMIGA - help - This is the IDE driver for the Amiga Gayle IDE interface. It supports - both the `A1200 style' and `A4000 style' of the Gayle IDE interface, - This includes on-board IDE interfaces on some Amiga models (A600, - A1200, A4000, and A4000T), and IDE interfaces on the Zorro expansion - bus (M-Tech E-Matrix 530 expansion card). - - It also provides support for the so-called `IDE doublers' (made - by various manufacturers, e.g. Eyetech) that can be connected to - the on-board IDE interface of some Amiga models. Using such an IDE - doubler, you can connect up to four instead of two IDE devices to - the Amiga's on-board IDE interface. The feature is enabled at kernel - runtime using the "gayle.doubler" kernel boot parameter. - - Say Y if you have an Amiga with a Gayle IDE interface and want to use - IDE devices (hard disks, CD-ROM drives, etc.) that are connected to - it. - - Note that you also have to enable Zorro bus support if you want to - use Gayle IDE interfaces on the Zorro expansion bus. - -config BLK_DEV_BUDDHA - tristate "Buddha/Catweasel/X-Surf IDE interface support" - depends on ZORRO - help - This is the IDE driver for the IDE interfaces on the Buddha, Catweasel - and X-Surf expansion boards. It supports up to two interfaces on the - Buddha, three on the Catweasel and two on the X-Surf. - - Say Y if you have a Buddha or Catweasel expansion board and want to - use IDE devices (hard disks, CD-ROM drives, etc.) that are connected - to one of its IDE interfaces. - -config BLK_DEV_FALCON_IDE - tristate "Falcon IDE interface support" - depends on ATARI - help - This is the IDE driver for the on-board IDE interface on the Atari - Falcon. Say Y if you have a Falcon and want to use IDE devices (hard - disks, CD-ROM drives, etc.) that are connected to the on-board IDE - interface. - -config BLK_DEV_MAC_IDE - tristate "Macintosh Quadra/Powerbook IDE interface support" - depends on MAC - help - This is the IDE driver for the on-board IDE interface on some m68k - Macintosh models. It supports both the `Quadra style' (used in - Quadra/ Centris 630 and Performa 588 models) and `Powerbook style' - (used in the Powerbook 150 and 190 models) IDE interface. - - Say Y if you have such an Macintosh model and want to use IDE - devices (hard disks, CD-ROM drives, etc.) that are connected to the - on-board IDE interface. - -config BLK_DEV_Q40IDE - tristate "Q40/Q60 IDE interface support" - depends on Q40 - help - Enable the on-board IDE controller in the Q40/Q60. This should - normally be on; disable it only if you are running a custom hard - drive subsystem through an expansion card. - -config BLK_DEV_PALMCHIP_BK3710 - tristate "Palmchip bk3710 IDE controller support" - depends on ARCH_DAVINCI - select IDE_TIMINGS - select BLK_DEV_IDEDMA_SFF - help - Say Y here if you want to support the onchip IDE controller on the - TI DaVinci SoC - -# no isa -> no vlb -if ISA && (ALPHA || X86 || MIPS) - -comment "Other IDE chipsets support" -comment "Note: most of these also require special kernel boot parameters" - -config BLK_DEV_4DRIVES - tristate "Generic 4 drives/port support" - help - Certain older chipsets, including the Tekram 690CD, use a single set - of I/O ports at 0x1f0 to control up to four drives, instead of the - customary two drives per port. Support for this can be enabled at - runtime using the "ide-4drives.probe" kernel boot parameter if you - say Y here. - -config BLK_DEV_ALI14XX - tristate "ALI M14xx support" - select IDE_TIMINGS - select IDE_LEGACY - help - This driver is enabled at runtime using the "ali14xx.probe" kernel - boot parameter. It enables support for the secondary IDE interface - of the ALI M1439/1443/1445/1487/1489 chipsets, and permits faster - I/O speeds to be set as well. - See the files and - for more info. - -config BLK_DEV_DTC2278 - tristate "DTC-2278 support" - select IDE_XFER_MODE - select IDE_LEGACY - help - This driver is enabled at runtime using the "dtc2278.probe" kernel - boot parameter. It enables support for the secondary IDE interface - of the DTC-2278 card, and permits faster I/O speeds to be set as - well. See the and - files for more info. - -config BLK_DEV_HT6560B - tristate "Holtek HT6560B support" - select IDE_TIMINGS - select IDE_LEGACY - help - This driver is enabled at runtime using the "ht6560b.probe" kernel - boot parameter. It enables support for the secondary IDE interface - of the Holtek card, and permits faster I/O speeds to be set as well. - See the and - files for more info. - -config BLK_DEV_QD65XX - tristate "QDI QD65xx support" - select IDE_TIMINGS - select IDE_LEGACY - help - This driver is enabled at runtime using the "qd65xx.probe" kernel - boot parameter. It permits faster I/O speeds to be set. See the - and - for more info. - -config BLK_DEV_UMC8672 - tristate "UMC-8672 support" - select IDE_XFER_MODE - select IDE_LEGACY - help - This driver is enabled at runtime using the "umc8672.probe" kernel - boot parameter. It enables support for the secondary IDE interface - of the UMC-8672, and permits faster I/O speeds to be set as well. - See the files and - for more info. - -endif - -config BLK_DEV_IDEDMA - def_bool BLK_DEV_IDEDMA_SFF || \ - BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA - select IDE_XFER_MODE - -endif # IDE diff --git a/src/linux/drivers/idle/Makefile b/src/linux/drivers/idle/Makefile deleted file mode 100644 index 23d295c..0000000 --- a/src/linux/drivers/idle/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_I7300_IDLE) += i7300_idle.o -obj-$(CONFIG_INTEL_IDLE) += intel_idle.o - diff --git a/src/linux/drivers/iio/Kconfig b/src/linux/drivers/iio/Kconfig deleted file mode 100644 index 6743b18..0000000 --- a/src/linux/drivers/iio/Kconfig +++ /dev/null @@ -1,94 +0,0 @@ -# -# Industrial I/O subsystem configuration -# - -menuconfig IIO - tristate "Industrial I/O support" - select ANON_INODES - help - The industrial I/O subsystem provides a unified framework for - drivers for many different types of embedded sensors using a - number of different physical interfaces (i2c, spi, etc). - -if IIO - -config IIO_BUFFER - bool "Enable buffer support within IIO" - help - Provide core support for various buffer based data - acquisition methods. - -if IIO_BUFFER - source "drivers/iio/buffer/Kconfig" -endif # IIO_BUFFER - -config IIO_CONFIGFS - tristate "Enable IIO configuration via configfs" - select CONFIGFS_FS - help - This allows configuring various IIO bits through configfs - (e.g. software triggers). For more info see - Documentation/iio/iio_configfs.txt. - -config IIO_TRIGGER - bool "Enable triggered sampling support" - help - Provides IIO core support for triggers. Currently these - are used to initialize capture of samples to push into - buffers. The triggers are effectively a 'capture - data now' interrupt. - -config IIO_CONSUMERS_PER_TRIGGER - int "Maximum number of consumers per trigger" - depends on IIO_TRIGGER - default "2" - help - This value controls the maximum number of consumers that a - given trigger may handle. Default is 2. - -config IIO_SW_DEVICE - tristate "Enable software IIO device support" - select IIO_CONFIGFS - help - Provides IIO core support for software devices. A software - device can be created via configfs or directly by a driver - using the API provided. - -config IIO_SW_TRIGGER - tristate "Enable software triggers support" - select IIO_CONFIGFS - help - Provides IIO core support for software triggers. A software - trigger can be created via configfs or directly by a driver - using the API provided. - -config IIO_TRIGGERED_EVENT - tristate - select IIO_TRIGGER - help - Provides helper functions for setting up triggered events. - -source "drivers/iio/accel/Kconfig" -source "drivers/iio/adc/Kconfig" -source "drivers/iio/amplifiers/Kconfig" -source "drivers/iio/chemical/Kconfig" -source "drivers/iio/common/Kconfig" -source "drivers/iio/dac/Kconfig" -source "drivers/iio/dummy/Kconfig" -source "drivers/iio/frequency/Kconfig" -source "drivers/iio/gyro/Kconfig" -source "drivers/iio/health/Kconfig" -source "drivers/iio/humidity/Kconfig" -source "drivers/iio/imu/Kconfig" -source "drivers/iio/light/Kconfig" -source "drivers/iio/magnetometer/Kconfig" -source "drivers/iio/orientation/Kconfig" -if IIO_TRIGGER - source "drivers/iio/trigger/Kconfig" -endif #IIO_TRIGGER -source "drivers/iio/potentiometer/Kconfig" -source "drivers/iio/pressure/Kconfig" -source "drivers/iio/proximity/Kconfig" -source "drivers/iio/temperature/Kconfig" - -endif # IIO diff --git a/src/linux/drivers/iio/accel/Kconfig b/src/linux/drivers/iio/accel/Kconfig deleted file mode 100644 index 2b791fe..0000000 --- a/src/linux/drivers/iio/accel/Kconfig +++ /dev/null @@ -1,300 +0,0 @@ -# -# Accelerometer drivers -# -# When adding new entries keep the list in alphabetical order - -menu "Accelerometers" - -config BMA180 - tristate "Bosch BMA180/BMA250 3-Axis Accelerometer Driver" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say Y here if you want to build a driver for the Bosch BMA180 or - BMA250 triaxial acceleration sensor. - - To compile this driver as a module, choose M here: the - module will be called bma180. - -config BMA220 - tristate "Bosch BMA220 3-Axis Accelerometer Driver" - depends on SPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to add support for the Bosch BMA220 triaxial - acceleration sensor. - - To compile this driver as a module, choose M here: the - module will be called bma220_spi. - -config BMC150_ACCEL - tristate "Bosch BMC150 Accelerometer Driver" - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select REGMAP - select BMC150_ACCEL_I2C if I2C - select BMC150_ACCEL_SPI if SPI - help - Say yes here to build support for the following Bosch accelerometers: - BMC150, BMI055, BMA250E, BMA222E, BMA255, BMA280. - - This is a combo module with both accelerometer and magnetometer. - This driver is only implementing accelerometer part, which has - its own address and register map. - -config BMC150_ACCEL_I2C - tristate - select REGMAP_I2C - -config BMC150_ACCEL_SPI - tristate - select REGMAP_SPI - -config DMARD06 - tristate "Domintech DMARD06 Digital Accelerometer Driver" - depends on OF || COMPILE_TEST - depends on I2C - help - Say yes here to build support for the Domintech low-g tri-axial - digital accelerometers: DMARD05, DMARD06, DMARD07. - - To compile this driver as a module, choose M here: the - module will be called dmard06. - -config DMARD09 - tristate "Domintech DMARD09 3-axis Accelerometer Driver" - depends on I2C - help - Say yes here to get support for the Domintech DMARD09 3-axis - accelerometer. - - Choosing M will build the driver as a module. If so, the module - will be called dmard09. - -config HID_SENSOR_ACCEL_3D - depends on HID_SENSOR_HUB - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select HID_SENSOR_IIO_COMMON - select HID_SENSOR_IIO_TRIGGER - tristate "HID Accelerometers 3D" - help - Say yes here to build support for the HID SENSOR - accelerometers 3D. - - To compile this driver as a module, choose M here: the - module will be called hid-sensor-accel-3d. - -config IIO_ST_ACCEL_3AXIS - tristate "STMicroelectronics accelerometers 3-Axis Driver" - depends on (I2C || SPI_MASTER) && SYSFS - select IIO_ST_SENSORS_CORE - select IIO_ST_ACCEL_I2C_3AXIS if (I2C) - select IIO_ST_ACCEL_SPI_3AXIS if (SPI_MASTER) - select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) - help - Say yes here to build support for STMicroelectronics accelerometers: - LSM303DLH, LSM303DLHC, LIS3DH, LSM330D, LSM330DL, LSM330DLC, - LIS331DLH, LSM303DL, LSM303DLM, LSM330, LIS2DH12, H3LIS331DL. - - This driver can also be built as a module. If so, these modules - will be created: - - st_accel (core functions for the driver [it is mandatory]); - - st_accel_i2c (necessary for the I2C devices [optional*]); - - st_accel_spi (necessary for the SPI devices [optional*]); - - (*) one of these is necessary to do something. - -config IIO_ST_ACCEL_I2C_3AXIS - tristate - depends on IIO_ST_ACCEL_3AXIS - depends on IIO_ST_SENSORS_I2C - -config IIO_ST_ACCEL_SPI_3AXIS - tristate - depends on IIO_ST_ACCEL_3AXIS - depends on IIO_ST_SENSORS_SPI - -config KXSD9 - tristate "Kionix KXSD9 Accelerometer Driver" - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for the Kionix KXSD9 accelerometer. - It can be accessed using an (optional) SPI or I2C interface. - - To compile this driver as a module, choose M here: the module - will be called kxsd9. - -config KXSD9_SPI - tristate "Kionix KXSD9 SPI transport" - depends on KXSD9 - depends on SPI - default KXSD9 - select REGMAP_SPI - help - Say yes here to enable the Kionix KXSD9 accelerometer - SPI transport channel. - -config KXSD9_I2C - tristate "Kionix KXSD9 I2C transport" - depends on KXSD9 - depends on I2C - default KXSD9 - select REGMAP_I2C - help - Say yes here to enable the Kionix KXSD9 accelerometer - I2C transport channel. - -config KXCJK1013 - tristate "Kionix 3-Axis Accelerometer Driver" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say Y here if you want to build a driver for the Kionix KXCJK-1013 - triaxial acceleration sensor. This driver also supports KXCJ9-1008 - and KXTJ2-1009. - - To compile this driver as a module, choose M here: the module will - be called kxcjk-1013. - -config MC3230 - tristate "mCube MC3230 Digital Accelerometer Driver" - depends on I2C - help - Say yes here to build support for the mCube MC3230 low-g tri-axial - digital accelerometer. - - To compile this driver as a module, choose M here: the - module will be called mc3230. - -config MMA7455 - tristate - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - -config MMA7455_I2C - tristate "Freescale MMA7455L/MMA7456L Accelerometer I2C Driver" - depends on I2C - select MMA7455 - select REGMAP_I2C - help - Say yes here to build support for the Freescale MMA7455L and - MMA7456L 3-axis accelerometer. - - To compile this driver as a module, choose M here: the module - will be called mma7455_i2c. - -config MMA7455_SPI - tristate "Freescale MMA7455L/MMA7456L Accelerometer SPI Driver" - depends on SPI_MASTER - select MMA7455 - select REGMAP_SPI - help - Say yes here to build support for the Freescale MMA7455L and - MMA7456L 3-axis accelerometer. - - To compile this driver as a module, choose M here: the module - will be called mma7455_spi. - -config MMA7660 - tristate "Freescale MMA7660FC 3-Axis Accelerometer Driver" - depends on I2C - help - Say yes here to get support for the Freescale MMA7660FC 3-Axis - accelerometer. - - Choosing M will build the driver as a module. If so, the module - will be called mma7660. - -config MMA8452 - tristate "Freescale / NXP MMA8452Q and similar Accelerometers Driver" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for the following Freescale / NXP 3-axis - accelerometers: MMA8451Q, MMA8452Q, MMA8453Q, MMA8652FC, MMA8653FC, - FXLS8471Q. - - To compile this driver as a module, choose M here: the module - will be called mma8452. - -config MMA9551_CORE - tristate - -config MMA9551 - tristate "Freescale MMA9551L Intelligent Motion-Sensing Platform Driver" - depends on I2C - select MMA9551_CORE - - help - Say yes here to build support for the Freescale MMA9551L - Intelligent Motion-Sensing Platform Driver. - - To compile this driver as a module, choose M here: the module - will be called mma9551. - -config MMA9553 - tristate "Freescale MMA9553L Intelligent Pedometer Platform Driver" - depends on I2C - select MMA9551_CORE - help - Say yes here to build support for the Freescale MMA9553L - Intelligent Pedometer Platform Driver. - - To compile this driver as a module, choose M here: the module - will be called mma9553. - -config MXC4005 - tristate "Memsic MXC4005XC 3-Axis Accelerometer Driver" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select REGMAP_I2C - help - Say yes here to build support for the Memsic MXC4005XC 3-axis - accelerometer. - - To compile this driver as a module, choose M. The module will be - called mxc4005. - -config MXC6255 - tristate "Memsic MXC6255 Orientation Sensing Accelerometer Driver" - depends on I2C - select REGMAP_I2C - help - Say yes here to build support for the Memsic MXC6255 Orientation - Sensing Accelerometer Driver. - - To compile this driver as a module, choose M here: the module will be - called mxc6255. - -config STK8312 - tristate "Sensortek STK8312 3-Axis Accelerometer Driver" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to get support for the Sensortek STK8312 3-axis - accelerometer. - - Choosing M will build the driver as a module. If so, the module - will be called stk8312. - -config STK8BA50 - tristate "Sensortek STK8BA50 3-Axis Accelerometer Driver" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to get support for the Sensortek STK8BA50 3-axis - accelerometer. - - Choosing M will build the driver as a module. If so, the module - will be called stk8ba50. - -endmenu diff --git a/src/linux/drivers/iio/adc/Kconfig b/src/linux/drivers/iio/adc/Kconfig deleted file mode 100644 index 99c0514..0000000 --- a/src/linux/drivers/iio/adc/Kconfig +++ /dev/null @@ -1,588 +0,0 @@ -# -# ADC drivers -# -# When adding new entries keep the list in alphabetical order - -menu "Analog to digital converters" - -config AD_SIGMA_DELTA - tristate - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - -config AD7266 - tristate "Analog Devices AD7265/AD7266 ADC driver" - depends on SPI_MASTER - select IIO_BUFFER - select IIO_TRIGGER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for Analog Devices AD7265 and AD7266 - ADCs. - - To compile this driver as a module, choose M here: the module will be - called ad7266. - -config AD7291 - tristate "Analog Devices AD7291 ADC driver" - depends on I2C - help - Say yes here to build support for Analog Devices AD7291 - 8 Channel ADC with temperature sensor. - - To compile this driver as a module, choose M here: the - module will be called ad7291. - -config AD7298 - tristate "Analog Devices AD7298 ADC driver" - depends on SPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for Analog Devices AD7298 - 8 Channel ADC with temperature sensor. - - To compile this driver as a module, choose M here: the - module will be called ad7298. - -config AD7476 - tristate "Analog Devices AD7476 and similar 1-channel ADCs driver" - depends on SPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for Analog Devices AD7273, AD7274, AD7276, - AD7277, AD7278, AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468, - AD7495, AD7910, AD7920, AD7920 SPI analog to digital converters (ADC). - - To compile this driver as a module, choose M here: the - module will be called ad7476. - -config AD7791 - tristate "Analog Devices AD7791 ADC driver" - depends on SPI - select AD_SIGMA_DELTA - help - Say yes here to build support for Analog Devices AD7787, AD7788, AD7789, - AD7790 and AD7791 SPI analog to digital converters (ADC). - - To compile this driver as a module, choose M here: the module will be - called ad7791. - -config AD7793 - tristate "Analog Devices AD7793 and similar ADCs driver" - depends on SPI - select AD_SIGMA_DELTA - help - Say yes here to build support for Analog Devices AD7785, AD7792, AD7793, - AD7794 and AD7795 SPI analog to digital converters (ADC). - - To compile this driver as a module, choose M here: the - module will be called AD7793. - -config AD7887 - tristate "Analog Devices AD7887 ADC driver" - depends on SPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for Analog Devices - AD7887 SPI analog to digital converter (ADC). - - To compile this driver as a module, choose M here: the - module will be called ad7887. - -config AD7923 - tristate "Analog Devices AD7923 and similar ADCs driver" - depends on SPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for Analog Devices - AD7904, AD7914, AD7923, AD7924 4 Channel ADCs. - - To compile this driver as a module, choose M here: the - module will be called ad7923. - -config AD799X - tristate "Analog Devices AD799x ADC driver" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for Analog Devices: - ad7991, ad7995, ad7999, ad7992, ad7993, ad7994, ad7997, ad7998 - i2c analog to digital converters (ADC). Provides direct access - via sysfs. - - To compile this driver as a module, choose M here: the module will be - called ad799x. - -config AT91_ADC - tristate "Atmel AT91 ADC" - depends on ARCH_AT91 - depends on INPUT - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select SYSFS - help - Say yes here to build support for Atmel AT91 ADC. - - To compile this driver as a module, choose M here: the module will be - called at91_adc. - -config AT91_SAMA5D2_ADC - tristate "Atmel AT91 SAMA5D2 ADC" - depends on ARCH_AT91 || COMPILE_TEST - depends on HAS_IOMEM - help - Say yes here to build support for Atmel SAMA5D2 ADC which is - available on SAMA5D2 SoC family. - - To compile this driver as a module, choose M here: the module will be - called at91-sama5d2_adc. - -config AXP288_ADC - tristate "X-Powers AXP288 ADC driver" - depends on MFD_AXP20X - help - Say yes here to have support for X-Powers power management IC (PMIC) ADC - device. Depending on platform configuration, this general purpose ADC can - be used for sampling sensors such as thermal resistors. - - To compile this driver as a module, choose M here: the module will be - called axp288_adc. - -config BCM_IPROC_ADC - tristate "Broadcom IPROC ADC driver" - depends on ARCH_BCM_IPROC || COMPILE_TEST - depends on MFD_SYSCON - default ARCH_BCM_CYGNUS - help - Say Y here if you want to add support for the Broadcom static - ADC driver. - - Broadcom iProc ADC driver. Broadcom iProc ADC controller has 8 - channels. The driver allows the user to read voltage values. - -config BERLIN2_ADC - tristate "Marvell Berlin2 ADC driver" - depends on ARCH_BERLIN - help - Marvell Berlin2 ADC driver. This ADC has 8 channels, with one used for - temperature measurement. - -config CC10001_ADC - tristate "Cosmic Circuits 10001 ADC driver" - depends on HAS_IOMEM && HAVE_CLK && REGULATOR - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for Cosmic Circuits 10001 ADC. - - This driver can also be built as a module. If so, the module will be - called cc10001_adc. - -config DA9150_GPADC - tristate "Dialog DA9150 GPADC driver support" - depends on MFD_DA9150 - help - Say yes here to build support for Dialog DA9150 GPADC. - - This driver can also be built as a module. If chosen, the module name - will be da9150-gpadc. - - To compile this driver as a module, choose M here: the module will be - called berlin2-adc. - -config EXYNOS_ADC - tristate "Exynos ADC driver support" - depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST) - depends on HAS_IOMEM - help - Core support for the ADC block found in the Samsung EXYNOS series - of SoCs for drivers such as the touchscreen and hwmon to use to share - this resource. - - To compile this driver as a module, choose M here: the module will be - called exynos_adc. - -config FSL_MX25_ADC - tristate "Freescale MX25 ADC driver" - depends on MFD_MX25_TSADC - help - Generic Conversion Queue driver used for general purpose ADC in the - MX25. This driver supports single measurements using the MX25 ADC. - -config HI8435 - tristate "Holt Integrated Circuits HI-8435 threshold detector" - select IIO_TRIGGERED_EVENT - depends on SPI - help - If you say yes here you get support for Holt Integrated Circuits - HI-8435 chip. - - This driver can also be built as a module. If so, the module will be - called hi8435. - -config INA2XX_ADC - tristate "Texas Instruments INA2xx Power Monitors IIO driver" - depends on I2C && !SENSORS_INA2XX - select REGMAP_I2C - select IIO_BUFFER - select IIO_KFIFO_BUF - help - Say yes here to build support for TI INA2xx family of Power Monitors. - This driver is mutually exclusive with the HWMON version. - -config IMX7D_ADC - tristate "IMX7D ADC driver" - depends on ARCH_MXC || COMPILE_TEST - depends on HAS_IOMEM - help - Say yes here to build support for IMX7D ADC. - - This driver can also be built as a module. If so, the module will be - called imx7d_adc. - -config LP8788_ADC - tristate "LP8788 ADC driver" - depends on MFD_LP8788 - help - Say yes here to build support for TI LP8788 ADC. - - To compile this driver as a module, choose M here: the module will be - called lp8788_adc. - -config LPC18XX_ADC - tristate "NXP LPC18xx ADC driver" - depends on ARCH_LPC18XX || COMPILE_TEST - depends on OF && HAS_IOMEM - help - Say yes here to build support for NXP LPC18XX ADC. - - To compile this driver as a module, choose M here: the module will be - called lpc18xx_adc. - -config LTC2485 - tristate "Linear Technology LTC2485 ADC driver" - depends on I2C - help - Say yes here to build support for Linear Technology LTC2485 ADC. - - To compile this driver as a module, choose M here: the module will be - called ltc2485. - -config MAX1027 - tristate "Maxim max1027 ADC driver" - depends on SPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for Maxim SPI ADC models - max1027, max1029 and max1031. - - To compile this driver as a module, choose M here: the module will be - called max1027. - -config MAX1363 - tristate "Maxim max1363 ADC driver" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for many Maxim i2c analog to digital - converters (ADC). (max1361, max1362, max1363, max1364, max1036, - max1037, max1038, max1039, max1136, max1136, max1137, max1138, - max1139, max1236, max1237, max11238, max1239, max11600, max11601, - max11602, max11603, max11604, max11605, max11606, max11607, - max11608, max11609, max11610, max11611, max11612, max11613, - max11614, max11615, max11616, max11617, max11644, max11645, - max11646, max11647) Provides direct access via sysfs and buffered - data via the iio dev interface. - - To compile this driver as a module, choose M here: the module will be - called max1363. - -config MCP320X - tristate "Microchip Technology MCP3x01/02/04/08" - depends on SPI - help - Say yes here to build support for Microchip Technology's - MCP3001, MCP3002, MCP3004, MCP3008, MCP3201, MCP3202, MCP3204, - MCP3208 or MCP3301 analog to digital converter. - - This driver can also be built as a module. If so, the module will be - called mcp320x. - -config MCP3422 - tristate "Microchip Technology MCP3421/2/3/4/5/6/7/8 driver" - depends on I2C - help - Say yes here to build support for Microchip Technology's MCP3421 - MCP3422, MCP3423, MCP3424, MCP3425, MCP3426, MCP3427 or MCP3428 - analog to digital converters. - - This driver can also be built as a module. If so, the module will be - called mcp3422. - -config MEDIATEK_MT6577_AUXADC - tristate "MediaTek AUXADC driver" - depends on ARCH_MEDIATEK || COMPILE_TEST - depends on HAS_IOMEM - help - Say yes here to enable support for MediaTek mt65xx AUXADC. - - The driver supports immediate mode operation to read from one of sixteen - channels (external or internal). - - This driver can also be built as a module. If so, the module will be - called mt6577_auxadc. - -config MEN_Z188_ADC - tristate "MEN 16z188 ADC IP Core support" - depends on MCB - help - Say yes here to enable support for the MEN 16z188 ADC IP-Core on a MCB - carrier. - - This driver can also be built as a module. If so, the module will be - called men_z188_adc. - -config MXS_LRADC - tristate "Freescale i.MX23/i.MX28 LRADC" - depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM - depends on INPUT - select STMP_DEVICE - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for i.MX23/i.MX28 LRADC convertor - built into these chips. - - To compile this driver as a module, choose M here: the - module will be called mxs-lradc. - -config NAU7802 - tristate "Nuvoton NAU7802 ADC driver" - depends on I2C - help - Say yes here to build support for Nuvoton NAU7802 ADC. - - To compile this driver as a module, choose M here: the - module will be called nau7802. - -config PALMAS_GPADC - tristate "TI Palmas General Purpose ADC" - depends on MFD_PALMAS - help - Palmas series pmic chip by Texas Instruments (twl6035/6037) - is used in smartphones and tablets and supports a 16 channel - general purpose ADC. - -config QCOM_SPMI_IADC - tristate "Qualcomm SPMI PMIC current ADC" - depends on SPMI - select REGMAP_SPMI - help - This is the IIO Current ADC driver for Qualcomm QPNP IADC Chip. - - The driver supports single mode operation to read from one of two - channels (external or internal). Hardware have additional - channels internally used for gain and offset calibration. - - To compile this driver as a module, choose M here: the module will - be called qcom-spmi-iadc. - -config QCOM_SPMI_VADC - tristate "Qualcomm SPMI PMIC voltage ADC" - depends on SPMI - select REGMAP_SPMI - help - This is the IIO Voltage ADC driver for Qualcomm QPNP VADC Chip. - - The driver supports multiple channels read. The VADC is a 15-bit - sigma-delta ADC. Some of the channels are internally used for - calibration. - - To compile this driver as a module, choose M here: the module will - be called qcom-spmi-vadc. - -config ROCKCHIP_SARADC - tristate "Rockchip SARADC driver" - depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST) - depends on RESET_CONTROLLER - help - Say yes here to build support for the SARADC found in SoCs from - Rockchip. - - To compile this driver as a module, choose M here: the - module will be called rockchip_saradc. - -config STX104 - tristate "Apex Embedded Systems STX104 driver" - depends on X86 && ISA_BUS_API - select GPIOLIB - help - Say yes here to build support for the Apex Embedded Systems STX104 - integrated analog PC/104 card. - - This driver supports the 16 channels of single-ended (8 channels of - differential) analog inputs, 2 channels of analog output, 4 digital - inputs, and 4 digital outputs provided by the STX104. - - The base port addresses for the devices may be configured via the base - array module parameter. - -config TI_ADC081C - tristate "Texas Instruments ADC081C/ADC101C/ADC121C family" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - If you say yes here you get support for Texas Instruments ADC081C, - ADC101C and ADC121C ADC chips. - - This driver can also be built as a module. If so, the module will be - called ti-adc081c. - -config TI_ADC0832 - tristate "Texas Instruments ADC0831/ADC0832/ADC0834/ADC0838" - depends on SPI - help - If you say yes here you get support for Texas Instruments ADC0831, - ADC0832, ADC0834, ADC0838 ADC chips. - - This driver can also be built as a module. If so, the module will be - called ti-adc0832. - -config TI_ADC12138 - tristate "Texas Instruments ADC12130/ADC12132/ADC12138" - depends on SPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - If you say yes here you get support for Texas Instruments ADC12130, - ADC12132 and ADC12138 chips. - - This driver can also be built as a module. If so, the module will be - called ti-adc12138. - -config TI_ADC128S052 - tristate "Texas Instruments ADC128S052/ADC122S021/ADC124S021" - depends on SPI - help - If you say yes here you get support for Texas Instruments ADC128S052, - ADC122S021 and ADC124S021 chips. - - This driver can also be built as a module. If so, the module will be - called ti-adc128s052. - -config TI_ADC161S626 - tristate "Texas Instruments ADC161S626 1-channel differential ADC" - depends on SPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - If you say yes here you get support for Texas Instruments ADC141S626, - and ADC161S626 chips. - - This driver can also be built as a module. If so, the module will be - called ti-adc161s626. - -config TI_ADS1015 - tristate "Texas Instruments ADS1015 ADC" - depends on I2C && !SENSORS_ADS1015 - select REGMAP_I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - If you say yes here you get support for Texas Instruments ADS1015 - ADC chip. - - This driver can also be built as a module. If so, the module will be - called ti-ads1015. - -config TI_ADS8688 - tristate "Texas Instruments ADS8688" - depends on SPI && OF - help - If you say yes here you get support for Texas Instruments ADS8684 and - and ADS8688 ADC chips - - This driver can also be built as a module. If so, the module will be - called ti-ads8688. - -config TI_AM335X_ADC - tristate "TI's AM335X ADC driver" - depends on MFD_TI_AM335X_TSCADC - select IIO_BUFFER - select IIO_KFIFO_BUF - help - Say yes here to build support for Texas Instruments ADC - driver which is also a MFD client. - - To compile this driver as a module, choose M here: the module will be - called ti_am335x_adc. - -config TWL4030_MADC - tristate "TWL4030 MADC (Monitoring A/D Converter)" - depends on TWL4030_CORE - help - This driver provides support for Triton TWL4030-MADC. The - driver supports both RT and SW conversion methods. - - This driver can also be built as a module. If so, the module will be - called twl4030-madc. - -config TWL6030_GPADC - tristate "TWL6030 GPADC (General Purpose A/D Converter) Support" - depends on TWL4030_CORE - default n - help - Say yes here if you want support for the TWL6030/TWL6032 General - Purpose A/D Converter. This will add support for battery type - detection, battery voltage and temperature measurement, die - temperature measurement, system supply voltage, audio accessory, - USB ID detection. - - This driver can also be built as a module. If so, the module will be - called twl6030-gpadc. - -config VF610_ADC - tristate "Freescale vf610 ADC driver" - depends on OF - depends on HAS_IOMEM - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to support for Vybrid board analog-to-digital converter. - Since the IP is used for i.MX6SLX, the driver also support i.MX6SLX. - - This driver can also be built as a module. If so, the module will be - called vf610_adc. - -config VIPERBOARD_ADC - tristate "Viperboard ADC support" - depends on MFD_VIPERBOARD && USB - help - Say yes here to access the ADC part of the Nano River - Technologies Viperboard. - - To compile this driver as a module, choose M here: the module will be - called viperboard_adc. - -config XILINX_XADC - tristate "Xilinx XADC driver" - depends on ARCH_ZYNQ || MICROBLAZE || COMPILE_TEST - depends on HAS_IOMEM - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to have support for the Xilinx XADC. The driver does support - both the ZYNQ interface to the XADC as well as the AXI-XADC interface. - - The driver can also be build as a module. If so, the module will be called - xilinx-xadc. - -endmenu diff --git a/src/linux/drivers/iio/amplifiers/Kconfig b/src/linux/drivers/iio/amplifiers/Kconfig deleted file mode 100644 index e9c5f2c..0000000 --- a/src/linux/drivers/iio/amplifiers/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -# -# Gain Amplifiers, etc. -# -# When adding new entries keep the list in alphabetical order - -menu "Amplifiers" - -config AD8366 - tristate "Analog Devices AD8366 VGA" - depends on SPI - select BITREVERSE - help - Say yes here to build support for Analog Devices AD8366 - SPI Dual-Digital Variable Gain Amplifier (VGA). - - To compile this driver as a module, choose M here: the - module will be called ad8366. - -endmenu diff --git a/src/linux/drivers/iio/buffer/Kconfig b/src/linux/drivers/iio/buffer/Kconfig deleted file mode 100644 index 4ffd3db..0000000 --- a/src/linux/drivers/iio/buffer/Kconfig +++ /dev/null @@ -1,44 +0,0 @@ -# -# Industrial I/O generic buffer implementations -# -# When adding new entries keep the list in alphabetical order - -config IIO_BUFFER_CB - tristate "IIO callback buffer used for push in-kernel interfaces" - help - Should be selected by any drivers that do in-kernel push - usage. That is, those where the data is pushed to the consumer. - -config IIO_BUFFER_DMA - tristate - help - Provides the generic IIO DMA buffer infrastructure that can be used by - drivers for devices with DMA support to implement the IIO buffer. - - Should be selected by drivers that want to use the generic DMA buffer - infrastructure. - -config IIO_BUFFER_DMAENGINE - tristate - select IIO_BUFFER_DMA - help - Provides a bonding of the generic IIO DMA buffer infrastructure with the - DMAengine framework. This can be used by converter drivers with a DMA port - connected to an external DMA controller which is supported by the - DMAengine framework. - - Should be selected by drivers that want to use this functionality. - -config IIO_KFIFO_BUF - tristate "Industrial I/O buffering based on kfifo" - help - A simple fifo based on kfifo. Note that this currently provides - no buffer events so it is up to userspace to work out how - often to read from the buffer. - -config IIO_TRIGGERED_BUFFER - tristate - select IIO_TRIGGER - select IIO_KFIFO_BUF - help - Provides helper functions for setting up triggered buffers. diff --git a/src/linux/drivers/iio/chemical/Kconfig b/src/linux/drivers/iio/chemical/Kconfig deleted file mode 100644 index cea7f98..0000000 --- a/src/linux/drivers/iio/chemical/Kconfig +++ /dev/null @@ -1,40 +0,0 @@ -# -# Chemical sensors -# - -menu "Chemical Sensors" - -config ATLAS_PH_SENSOR - tristate "Atlas Scientific OEM SM sensors" - depends on I2C - select REGMAP_I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select IRQ_WORK - help - Say Y here to build I2C interface support for the following - Atlas Scientific OEM SM sensors: - * pH SM sensor - * EC SM sensor - * ORP SM sensor - - To compile this driver as module, choose M here: the - module will be called atlas-ph-sensor. - -config IAQCORE - tristate "AMS iAQ-Core VOC sensors" - depends on I2C - help - Say Y here to build I2C interface support for the AMS - iAQ-Core Continuous/Pulsed VOC (Volatile Organic Compounds) - sensors - -config VZ89X - tristate "SGX Sensortech MiCS VZ89X VOC sensor" - depends on I2C - help - Say Y here to build I2C interface support for the SGX - Sensortech MiCS VZ89X VOC (Volatile Organic Compounds) - sensors - -endmenu diff --git a/src/linux/drivers/iio/common/Kconfig b/src/linux/drivers/iio/common/Kconfig deleted file mode 100644 index 26a6026..0000000 --- a/src/linux/drivers/iio/common/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -# -# IIO common modules -# - -source "drivers/iio/common/hid-sensors/Kconfig" -source "drivers/iio/common/ms_sensors/Kconfig" -source "drivers/iio/common/ssp_sensors/Kconfig" -source "drivers/iio/common/st_sensors/Kconfig" diff --git a/src/linux/drivers/iio/common/hid-sensors/Kconfig b/src/linux/drivers/iio/common/hid-sensors/Kconfig deleted file mode 100644 index 39188b7..0000000 --- a/src/linux/drivers/iio/common/hid-sensors/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -# -# Hid Sensor common modules -# -menu "Hid Sensor IIO Common" - -config HID_SENSOR_IIO_COMMON - tristate "Common modules for all HID Sensor IIO drivers" - depends on HID_SENSOR_HUB - select HID_SENSOR_IIO_TRIGGER if IIO_BUFFER - help - Say yes here to build support for HID sensor to use - HID sensor common processing for attributes and IIO triggers. - There are many attributes which can be shared among multiple - HID sensor drivers, this module contains processing for those - attributes. - -config HID_SENSOR_IIO_TRIGGER - tristate "Common module (trigger) for all HID Sensor IIO drivers" - depends on HID_SENSOR_HUB && HID_SENSOR_IIO_COMMON - select IIO_TRIGGER - help - Say yes here to build trigger support for HID sensors. - Triggers will be send if all requested attributes were read. - - If this driver is compiled as a module, it will be named - hid-sensor-trigger. - -endmenu diff --git a/src/linux/drivers/iio/common/ms_sensors/Kconfig b/src/linux/drivers/iio/common/ms_sensors/Kconfig deleted file mode 100644 index b28a92b..0000000 --- a/src/linux/drivers/iio/common/ms_sensors/Kconfig +++ /dev/null @@ -1,6 +0,0 @@ -# -# Measurements Specialties sensors common library -# - -config IIO_MS_SENSORS_I2C - tristate diff --git a/src/linux/drivers/iio/common/ssp_sensors/Kconfig b/src/linux/drivers/iio/common/ssp_sensors/Kconfig deleted file mode 100644 index 0ea4faf..0000000 --- a/src/linux/drivers/iio/common/ssp_sensors/Kconfig +++ /dev/null @@ -1,26 +0,0 @@ -# -# SSP sensor drivers and commons configuration -# -menu "SSP Sensor Common" - -config IIO_SSP_SENSORS_COMMONS - tristate "Commons for all SSP Sensor IIO drivers" - depends on IIO_SSP_SENSORHUB - select IIO_BUFFER - select IIO_KFIFO_BUF - help - Say yes here to build commons for SSP sensors. - To compile this as a module, choose M here: the module - will be called ssp_iio. - -config IIO_SSP_SENSORHUB - tristate "Samsung Sensorhub driver" - depends on SPI - select MFD_CORE - help - SSP driver for sensorhub. - If you say yes here you get ssp support for sensorhub. - To compile this driver as a module, choose M here: the - module will be called sensorhub. - -endmenu diff --git a/src/linux/drivers/iio/common/st_sensors/Kconfig b/src/linux/drivers/iio/common/st_sensors/Kconfig deleted file mode 100644 index 865f1ca..0000000 --- a/src/linux/drivers/iio/common/st_sensors/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -# -# STMicroelectronics sensors common library -# - -config IIO_ST_SENSORS_I2C - tristate - -config IIO_ST_SENSORS_SPI - tristate - -config IIO_ST_SENSORS_CORE - tristate - select IIO_ST_SENSORS_I2C if I2C - select IIO_ST_SENSORS_SPI if SPI_MASTER diff --git a/src/linux/drivers/iio/dac/Kconfig b/src/linux/drivers/iio/dac/Kconfig deleted file mode 100644 index 120b244..0000000 --- a/src/linux/drivers/iio/dac/Kconfig +++ /dev/null @@ -1,277 +0,0 @@ -# -# DAC drivers -# -# When adding new entries keep the list in alphabetical order - -menu "Digital to analog converters" - -config AD5064 - tristate "Analog Devices AD5064 and similar multi-channel DAC driver" - depends on (SPI_MASTER && I2C!=m) || I2C - help - Say yes here to build support for Analog Devices AD5024, AD5025, AD5044, - AD5045, AD5064, AD5064-1, AD5065, AD5625, AD5625R, AD5627, AD5627R, - AD5628, AD5629R, AD5645R, AD5647R, AD5648, AD5665, AD5665R, AD5666, - AD5667, AD5667R, AD5668, AD5669R, LTC2606, LTC2607, LTC2609, LTC2616, - LTC2617, LTC2619, LTC2626, LTC2627, LTC2629 Digital to Analog Converter. - - To compile this driver as a module, choose M here: the - module will be called ad5064. - -config AD5360 - tristate "Analog Devices AD5360/61/62/63/70/71/73 DAC driver" - depends on SPI - help - Say yes here to build support for Analog Devices AD5360, AD5361, - AD5362, AD5363, AD5370, AD5371, AD5373 multi-channel - Digital to Analog Converters (DAC). - - To compile this driver as module choose M here: the module will be called - ad5360. - -config AD5380 - tristate "Analog Devices AD5380/81/82/83/84/90/91/92 DAC driver" - depends on (SPI_MASTER && I2C!=m) || I2C - select REGMAP_I2C if I2C - select REGMAP_SPI if SPI_MASTER - help - Say yes here to build support for Analog Devices AD5380, AD5381, - AD5382, AD5383, AD5384, AD5390, AD5391, AD5392 multi-channel - Digital to Analog Converters (DAC). - - To compile this driver as module choose M here: the module will be called - ad5380. - -config AD5421 - tristate "Analog Devices AD5421 DAC driver" - depends on SPI - help - Say yes here to build support for Analog Devices AD5421 loop-powered - digital-to-analog convertors (DAC). - - To compile this driver as module choose M here: the module will be called - ad5421. - -config AD5446 - tristate "Analog Devices AD5446 and similar single channel DACs driver" - depends on (SPI_MASTER && I2C!=m) || I2C - help - Say yes here to build support for Analog Devices AD5300, AD5301, AD5310, - AD5311, AD5320, AD5321, AD5444, AD5446, AD5450, AD5451, AD5452, AD5453, - AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, AD5602, AD5611, AD5612, - AD5620, AD5621, AD5622, AD5640, AD5641, AD5660, AD5662 DACs. - - To compile this driver as a module, choose M here: the - module will be called ad5446. - -config AD5449 - tristate "Analog Devices AD5449 and similar DACs driver" - depends on SPI_MASTER - help - Say yes here to build support for Analog Devices AD5415, AD5426, AD5429, - AD5432, AD5439, AD5443, AD5449 Digital to Analog Converters. - - To compile this driver as a module, choose M here: the - module will be called ad5449. - -config AD5592R_BASE - tristate - -config AD5592R - tristate "Analog Devices AD5592R ADC/DAC driver" - depends on SPI_MASTER - select GPIOLIB - select AD5592R_BASE - help - Say yes here to build support for Analog Devices AD5592R - Digital to Analog / Analog to Digital Converter. - - To compile this driver as a module, choose M here: the - module will be called ad5592r. - -config AD5593R - tristate "Analog Devices AD5593R ADC/DAC driver" - depends on I2C - select GPIOLIB - select AD5592R_BASE - help - Say yes here to build support for Analog Devices AD5593R - Digital to Analog / Analog to Digital Converter. - - To compile this driver as a module, choose M here: the - module will be called ad5593r. - -config AD5504 - tristate "Analog Devices AD5504/AD5501 DAC SPI driver" - depends on SPI - help - Say yes here to build support for Analog Devices AD5504, AD5501, - High Voltage Digital to Analog Converter. - - To compile this driver as a module, choose M here: the - module will be called ad5504. - -config AD5624R_SPI - tristate "Analog Devices AD5624/44/64R DAC spi driver" - depends on SPI - help - Say yes here to build support for Analog Devices AD5624R, AD5644R and - AD5664R converters (DAC). This driver uses the common SPI interface. - -config AD5686 - tristate "Analog Devices AD5686R/AD5685R/AD5684R DAC SPI driver" - depends on SPI - help - Say yes here to build support for Analog Devices AD5686R, AD5685R, - AD5684R, AD5791 Voltage Output Digital to - Analog Converter. - - To compile this driver as a module, choose M here: the - module will be called ad5686. - -config AD5755 - tristate "Analog Devices AD5755/AD5755-1/AD5757/AD5735/AD5737 DAC driver" - depends on SPI_MASTER - help - Say yes here to build support for Analog Devices AD5755, AD5755-1, - AD5757, AD5735, AD5737 quad channel Digital to - Analog Converter. - - To compile this driver as a module, choose M here: the - module will be called ad5755. - -config AD5761 - tristate "Analog Devices AD5761/61R/21/21R DAC driver" - depends on SPI_MASTER - help - Say yes here to build support for Analog Devices AD5761, AD5761R, AD5721, - AD5721R Digital to Analog Converter. - - To compile this driver as a module, choose M here: the - module will be called ad5761. - -config AD5764 - tristate "Analog Devices AD5764/64R/44/44R DAC driver" - depends on SPI_MASTER - help - Say yes here to build support for Analog Devices AD5764, AD5764R, AD5744, - AD5744R Digital to Analog Converter. - - To compile this driver as a module, choose M here: the - module will be called ad5764. - -config AD5791 - tristate "Analog Devices AD5760/AD5780/AD5781/AD5790/AD5791 DAC SPI driver" - depends on SPI - help - Say yes here to build support for Analog Devices AD5760, AD5780, - AD5781, AD5790, AD5791 High Resolution Voltage Output Digital to - Analog Converter. - - To compile this driver as a module, choose M here: the - module will be called ad5791. - -config AD7303 - tristate "Analog Devices AD7303 DAC driver" - depends on SPI - help - Say yes here to build support for Analog Devices AD7303 Digital to Analog - Converters (DAC). - - To compile this driver as module choose M here: the module will be called - ad7303. - -config CIO_DAC - tristate "Measurement Computing CIO-DAC IIO driver" - depends on X86 && ISA_BUS_API - help - Say yes here to build support for the Measurement Computing CIO-DAC - analog output device family (CIO-DAC16, CIO-DAC08, PC104-DAC06). The - base port addresses for the devices may be configured via the base - array module parameter. - -config AD8801 - tristate "Analog Devices AD8801/AD8803 DAC driver" - depends on SPI_MASTER - help - Say yes here to build support for Analog Devices AD8801, AD8803 Digital to - Analog Converters (DAC). - - To compile this driver as a module choose M here: the module will be called - ad8801. - -config LPC18XX_DAC - tristate "NXP LPC18xx DAC driver" - depends on ARCH_LPC18XX || COMPILE_TEST - depends on OF && HAS_IOMEM - help - Say yes here to build support for NXP LPC18XX DAC. - - To compile this driver as a module, choose M here: the module will be - called lpc18xx_dac. - -config M62332 - tristate "Mitsubishi M62332 DAC driver" - depends on I2C - help - If you say yes here you get support for the Mitsubishi M62332 - (I2C 8-Bit DACs with rail-to-rail outputs). - - This driver can also be built as a module. If so, the module - will be called m62332. - -config MAX517 - tristate "Maxim MAX517/518/519/520/521 DAC driver" - depends on I2C - help - If you say yes here you get support for the following Maxim chips - (I2C 8-Bit DACs with rail-to-rail outputs): - MAX517 - Single channel, single reference - MAX518 - Dual channel, ref=Vdd - MAX519 - Dual channel, dual reference - MAX520 - Quad channel, quad reference - MAX521 - Octal channel, independent ref for ch0-3, shared ref for ch4-7 - - This driver can also be built as a module. If so, the module - will be called max517. - -config MAX5821 - tristate "Maxim MAX5821 DAC driver" - depends on I2C - depends on OF - help - Say yes here to build support for Maxim MAX5821 - 10 bits DAC. - -config MCP4725 - tristate "MCP4725/6 DAC driver" - depends on I2C - ---help--- - Say Y here if you want to build a driver for the Microchip - MCP 4725/6 12-bit digital-to-analog converter (DAC) with I2C - interface. - - To compile this driver as a module, choose M here: the module - will be called mcp4725. - -config MCP4922 - tristate "MCP4902, MCP4912, MCP4922 DAC driver" - depends on SPI - help - Say yes here to build the driver for the Microchip MCP4902 - MCP4912, and MCP4922 DAC devices. - - To compile this driver as a module, choose M here: the module - will be called mcp4922. - -config VF610_DAC - tristate "Vybrid vf610 DAC driver" - depends on OF - depends on HAS_IOMEM - help - Say yes here to support Vybrid board digital-to-analog converter. - - This driver can also be built as a module. If so, the module will - be called vf610_dac. - -endmenu diff --git a/src/linux/drivers/iio/dummy/Kconfig b/src/linux/drivers/iio/dummy/Kconfig deleted file mode 100644 index aa5824d..0000000 --- a/src/linux/drivers/iio/dummy/Kconfig +++ /dev/null @@ -1,37 +0,0 @@ -# -# Industrial I/O subsystem Dummy Driver configuration -# -menu "IIO dummy driver" - depends on IIO - -config IIO_DUMMY_EVGEN - select IRQ_WORK - tristate - -config IIO_SIMPLE_DUMMY - tristate "An example driver with no hardware requirements" - depends on IIO_SW_DEVICE - help - Driver intended mainly as documentation for how to write - a driver. May also be useful for testing userspace code - without hardware. - -if IIO_SIMPLE_DUMMY - -config IIO_SIMPLE_DUMMY_EVENTS - bool "Event generation support" - select IIO_DUMMY_EVGEN - help - Add some dummy events to the simple dummy driver. - -config IIO_SIMPLE_DUMMY_BUFFER - bool "Buffered capture support" - select IIO_BUFFER - select IIO_TRIGGER - select IIO_KFIFO_BUF - help - Add buffered data capture to the simple dummy driver. - -endif # IIO_SIMPLE_DUMMY - -endmenu diff --git a/src/linux/drivers/iio/frequency/Kconfig b/src/linux/drivers/iio/frequency/Kconfig deleted file mode 100644 index dc5e0b7..0000000 --- a/src/linux/drivers/iio/frequency/Kconfig +++ /dev/null @@ -1,42 +0,0 @@ -# -# Frequency -# Direct Digital Synthesis drivers (DDS) -# Clock Distribution device drivers -# Phase-Locked Loop (PLL) frequency synthesizers -# -# When adding new entries keep the list in alphabetical order - -menu "Frequency Synthesizers DDS/PLL" - -menu "Clock Generator/Distribution" - -config AD9523 - tristate "Analog Devices AD9523 Low Jitter Clock Generator" - depends on SPI - help - Say yes here to build support for Analog Devices AD9523 Low Jitter - Clock Generator. The driver provides direct access via sysfs. - - To compile this driver as a module, choose M here: the - module will be called ad9523. - -endmenu - -# -# Phase-Locked Loop (PLL) frequency synthesizers -# - -menu "Phase-Locked Loop (PLL) frequency synthesizers" - -config ADF4350 - tristate "Analog Devices ADF4350/ADF4351 Wideband Synthesizers" - depends on SPI - help - Say yes here to build support for Analog Devices ADF4350/ADF4351 - Wideband Synthesizers. The driver provides direct access via sysfs. - - To compile this driver as a module, choose M here: the - module will be called adf4350. - -endmenu -endmenu diff --git a/src/linux/drivers/iio/gyro/Kconfig b/src/linux/drivers/iio/gyro/Kconfig deleted file mode 100644 index 205a844..0000000 --- a/src/linux/drivers/iio/gyro/Kconfig +++ /dev/null @@ -1,124 +0,0 @@ -# -# IIO Digital Gyroscope Sensor drivers configuration -# -# When adding new entries keep the list in alphabetical order - -menu "Digital gyroscope sensors" - -config ADIS16080 - tristate "Analog Devices ADIS16080/100 Yaw Rate Gyroscope with SPI driver" - depends on SPI - help - Say yes here to build support for Analog Devices ADIS16080, ADIS16100 Yaw - Rate Gyroscope with SPI. - -config ADIS16130 - tristate "Analog Devices ADIS16130 High Precision Angular Rate Sensor driver" - depends on SPI - help - Say yes here to build support for Analog Devices ADIS16130 High Precision - Angular Rate Sensor driver. - -config ADIS16136 - tristate "Analog devices ADIS16136 and similar gyroscopes driver" - depends on SPI_MASTER - select IIO_ADIS_LIB - select IIO_ADIS_LIB_BUFFER if IIO_BUFFER - help - Say yes here to build support for the Analog Devices ADIS16133, ADIS16135, - ADIS16136 gyroscope devices. - -config ADIS16260 - tristate "Analog Devices ADIS16260 Digital Gyroscope Sensor SPI driver" - depends on SPI - select IIO_ADIS_LIB - select IIO_ADIS_LIB_BUFFER if IIO_BUFFER - help - Say yes here to build support for Analog Devices ADIS16260 ADIS16265 - ADIS16250 ADIS16255 and ADIS16251 programmable digital gyroscope sensors. - - This driver can also be built as a module. If so, the module - will be called adis16260. - -config ADXRS450 - tristate "Analog Devices ADXRS450/3 Digital Output Gyroscope SPI driver" - depends on SPI - help - Say yes here to build support for Analog Devices ADXRS450 and ADXRS453 - programmable digital output gyroscope. - - This driver can also be built as a module. If so, the module - will be called adxrs450. - -config BMG160 - tristate "BOSCH BMG160 Gyro Sensor" - depends on (I2C || SPI_MASTER) - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select BMG160_I2C if (I2C) - select BMG160_SPI if (SPI) - help - Say yes here to build support for BOSCH BMG160 Tri-axis Gyro Sensor - driver connected via I2C or SPI. This driver also supports BMI055 - gyroscope. - - This driver can also be built as a module. If so, the module - will be called bmg160_i2c or bmg160_spi. - -config BMG160_I2C - tristate - select REGMAP_I2C - -config BMG160_SPI - tristate - select REGMAP_SPI - -config HID_SENSOR_GYRO_3D - depends on HID_SENSOR_HUB - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select HID_SENSOR_IIO_COMMON - select HID_SENSOR_IIO_TRIGGER - tristate "HID Gyroscope 3D" - help - Say yes here to build support for the HID SENSOR - Gyroscope 3D. - -config IIO_ST_GYRO_3AXIS - tristate "STMicroelectronics gyroscopes 3-Axis Driver" - depends on (I2C || SPI_MASTER) && SYSFS - select IIO_ST_SENSORS_CORE - select IIO_ST_GYRO_I2C_3AXIS if (I2C) - select IIO_ST_GYRO_SPI_3AXIS if (SPI_MASTER) - select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) - help - Say yes here to build support for STMicroelectronics gyroscopes: - L3G4200D, LSM330DL, L3GD20, LSM330DLC, L3G4IS, LSM330, LSM9DS0. - - This driver can also be built as a module. If so, these modules - will be created: - - st_gyro (core functions for the driver [it is mandatory]); - - st_gyro_i2c (necessary for the I2C devices [optional*]); - - st_gyro_spi (necessary for the SPI devices [optional*]); - - (*) one of these is necessary to do something. - -config IIO_ST_GYRO_I2C_3AXIS - tristate - depends on IIO_ST_GYRO_3AXIS - depends on IIO_ST_SENSORS_I2C - -config IIO_ST_GYRO_SPI_3AXIS - tristate - depends on IIO_ST_GYRO_3AXIS - depends on IIO_ST_SENSORS_SPI - -config ITG3200 - tristate "InvenSense ITG3200 Digital 3-Axis Gyroscope I2C driver" - depends on I2C - select IIO_TRIGGERED_BUFFER if IIO_BUFFER - help - Say yes here to add support for the InvenSense ITG3200 digital - 3-axis gyroscope sensor. - -endmenu diff --git a/src/linux/drivers/iio/health/Kconfig b/src/linux/drivers/iio/health/Kconfig deleted file mode 100644 index c5f004a..0000000 --- a/src/linux/drivers/iio/health/Kconfig +++ /dev/null @@ -1,51 +0,0 @@ -# -# Health sensors -# -# When adding new entries keep the list in alphabetical order - -menu "Health Sensors" - -menu "Heart Rate Monitors" - -config AFE4403 - tristate "TI AFE4403 Heart Rate Monitor" - depends on SPI_MASTER - select REGMAP_SPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes to choose the Texas Instruments AFE4403 - heart rate monitor and low-cost pulse oximeter. - - To compile this driver as a module, choose M here: the - module will be called afe4403. - -config AFE4404 - tristate "TI AFE4404 heart rate and pulse oximeter sensor" - depends on I2C - select REGMAP_I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes to choose the Texas Instruments AFE4404 - heart rate monitor and low-cost pulse oximeter. - - To compile this driver as a module, choose M here: the - module will be called afe4404. - -config MAX30100 - tristate "MAX30100 heart rate and pulse oximeter sensor" - depends on I2C - select REGMAP_I2C - select IIO_BUFFER - select IIO_KFIFO_BUF - help - Say Y here to build I2C interface support for the Maxim - MAX30100 heart rate, and pulse oximeter sensor. - - To compile this driver as a module, choose M here: the - module will be called max30100. - -endmenu - -endmenu diff --git a/src/linux/drivers/iio/humidity/Kconfig b/src/linux/drivers/iio/humidity/Kconfig deleted file mode 100644 index b17e2e2..0000000 --- a/src/linux/drivers/iio/humidity/Kconfig +++ /dev/null @@ -1,72 +0,0 @@ -# -# humidity sensor drivers -# -menu "Humidity sensors" - -config AM2315 - tristate "Aosong AM2315 relative humidity and temperature sensor" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - If you say yes here you get support for the Aosong AM2315 - relative humidity and ambient temperature sensor. - - This driver can also be built as a module. If so, the module will - be called am2315. - -config DHT11 - tristate "DHT11 (and compatible sensors) driver" - depends on GPIOLIB || COMPILE_TEST - help - This driver supports reading data via a single interrupt - generating GPIO line. Currently tested are DHT11 and DHT22. - Other sensors should work as well as long as they speak the - same protocol. - -config HDC100X - tristate "TI HDC100x relative humidity and temperature sensor" - depends on I2C - help - Say yes here to build support for the Texas Instruments - HDC1000 and HDC1008 relative humidity and temperature sensors. - - To compile this driver as a module, choose M here: the module - will be called hdc100x. - -config HTU21 - tristate "Measurement Specialties HTU21 humidity & temperature sensor" - depends on I2C - select IIO_MS_SENSORS_I2C - help - If you say yes here you get support for the Measurement Specialties - HTU21 humidity and temperature sensor. - This driver is also used for MS8607 temperature, pressure & humidity - sensor - - This driver can also be built as a module. If so, the module will - be called htu21. - -config SI7005 - tristate "SI7005 relative humidity and temperature sensor" - depends on I2C - help - Say yes here to build support for the Silabs Si7005 relative - humidity and temperature sensor. - - To compile this driver as a module, choose M here: the module - will be called si7005. This driver also - supports Hoperf TH02 Humidity and Temperature Sensor. - -config SI7020 - tristate "Si7013/20/21 Relative Humidity and Temperature Sensors" - depends on I2C - help - Say yes here to build support for the Silicon Labs Si7013/20/21 - Relative Humidity and Temperature Sensors. This driver also - supports Hoperf TH06 Humidity and Temperature Sensor. - - To compile this driver as a module, choose M here: the module - will be called si7020. - -endmenu diff --git a/src/linux/drivers/iio/imu/Kconfig b/src/linux/drivers/iio/imu/Kconfig deleted file mode 100644 index 1f1ad41..0000000 --- a/src/linux/drivers/iio/imu/Kconfig +++ /dev/null @@ -1,55 +0,0 @@ -# -# IIO imu drivers configuration -# -# When adding new entries keep the list in alphabetical order - -menu "Inertial measurement units" - -config ADIS16400 - tristate "Analog Devices ADIS16400 and similar IMU SPI driver" - depends on SPI - select IIO_ADIS_LIB - select IIO_ADIS_LIB_BUFFER if IIO_BUFFER - help - Say yes here to build support for Analog Devices adis16300, adis16344, - adis16350, adis16354, adis16355, adis16360, adis16362, adis16364, - adis16365, adis16400 and adis16405 triaxial inertial sensors - (adis16400 series also have magnetometers). - -config ADIS16480 - tristate "Analog Devices ADIS16480 and similar IMU driver" - depends on SPI - select IIO_ADIS_LIB - select IIO_ADIS_LIB_BUFFER if IIO_BUFFER - help - Say yes here to build support for Analog Devices ADIS16375, ADIS16480, - ADIS16485, ADIS16488 inertial sensors. - -source "drivers/iio/imu/bmi160/Kconfig" - -config KMX61 - tristate "Kionix KMX61 6-axis accelerometer and magnetometer" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say Y here if you want to build a driver for Kionix KMX61 6-axis - accelerometer and magnetometer. - To compile this driver as module, choose M here: the module will - be called kmx61. - -source "drivers/iio/imu/inv_mpu6050/Kconfig" - -endmenu - -config IIO_ADIS_LIB - tristate - help - A set of IO helper functions for the Analog Devices ADIS* device family. - -config IIO_ADIS_LIB_BUFFER - bool - select IIO_TRIGGERED_BUFFER - help - A set of buffer helper functions for the Analog Devices ADIS* device - family. diff --git a/src/linux/drivers/iio/imu/bmi160/Kconfig b/src/linux/drivers/iio/imu/bmi160/Kconfig deleted file mode 100644 index 005c17c..0000000 --- a/src/linux/drivers/iio/imu/bmi160/Kconfig +++ /dev/null @@ -1,32 +0,0 @@ -# -# BMI160 IMU driver -# - -config BMI160 - tristate - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - -config BMI160_I2C - tristate "Bosch BMI160 I2C driver" - depends on I2C - select BMI160 - select REGMAP_I2C - help - If you say yes here you get support for BMI160 IMU on I2C with - accelerometer, gyroscope and external BMG160 magnetometer. - - This driver can also be built as a module. If so, the module will be - called bmi160_i2c. - -config BMI160_SPI - tristate "Bosch BMI160 SPI driver" - depends on SPI - select BMI160 - select REGMAP_SPI - help - If you say yes here you get support for BMI160 IMU on SPI with - accelerometer, gyroscope and external BMG160 magnetometer. - - This driver can also be built as a module. If so, the module will be - called bmi160_spi. diff --git a/src/linux/drivers/iio/imu/inv_mpu6050/Kconfig b/src/linux/drivers/iio/imu/inv_mpu6050/Kconfig deleted file mode 100644 index 5483b2e..0000000 --- a/src/linux/drivers/iio/imu/inv_mpu6050/Kconfig +++ /dev/null @@ -1,30 +0,0 @@ -# -# inv-mpu6050 drivers for Invensense MPU devices and combos -# - -config INV_MPU6050_IIO - tristate - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - -config INV_MPU6050_I2C - tristate "Invensense MPU6050 devices (I2C)" - depends on I2C_MUX - select INV_MPU6050_IIO - select REGMAP_I2C - help - This driver supports the Invensense MPU6050/6500/9150 and ICM20608 - motion tracking devices over I2C. - This driver can be built as a module. The module will be called - inv-mpu6050-i2c. - -config INV_MPU6050_SPI - tristate "Invensense MPU6050 devices (SPI)" - depends on SPI_MASTER - select INV_MPU6050_IIO - select REGMAP_SPI - help - This driver supports the Invensense MPU6050/6500/9150 and ICM20608 - motion tracking devices over SPI. - This driver can be built as a module. The module will be called - inv-mpu6050-spi. diff --git a/src/linux/drivers/iio/light/Kconfig b/src/linux/drivers/iio/light/Kconfig deleted file mode 100644 index ba2e64d..0000000 --- a/src/linux/drivers/iio/light/Kconfig +++ /dev/null @@ -1,369 +0,0 @@ -# -# Light sensors -# -# When adding new entries keep the list in alphabetical order - -menu "Light sensors" - -config ACPI_ALS - tristate "ACPI Ambient Light Sensor" - depends on ACPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select IIO_KFIFO_BUF - help - Say Y here if you want to build a driver for the ACPI0008 - Ambient Light Sensor. - - To compile this driver as a module, choose M here: the module will - be called acpi-als. - -config ADJD_S311 - tristate "ADJD-S311-CR999 digital color sensor" - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - depends on I2C - help - If you say yes here you get support for the Avago ADJD-S311-CR999 - digital color light sensor. - - This driver can also be built as a module. If so, the module - will be called adjd_s311. - -config AL3320A - tristate "AL3320A ambient light sensor" - depends on I2C - help - Say Y here if you want to build a driver for the Dyna Image AL3320A - ambient light sensor. - - To compile this driver as a module, choose M here: the - module will be called al3320a. - -config APDS9300 - tristate "APDS9300 ambient light sensor" - depends on I2C - help - Say Y here if you want to build a driver for the Avago APDS9300 - ambient light sensor. - - To compile this driver as a module, choose M here: the - module will be called apds9300. - -config APDS9960 - tristate "Avago APDS9960 gesture/RGB/ALS/proximity sensor" - select REGMAP_I2C - select IIO_BUFFER - select IIO_KFIFO_BUF - depends on I2C - help - Say Y here to build I2C interface support for the Avago - APDS9960 gesture/RGB/ALS/proximity sensor. - - To compile this driver as a module, choose M here: the - module will be called apds9960 - -config BH1750 - tristate "ROHM BH1750 ambient light sensor" - depends on I2C - help - Say Y here to build support for the ROHM BH1710, BH1715, BH1721, - BH1750, BH1751 ambient light sensors. - - To compile this driver as a module, choose M here: the module will - be called bh1750. - -config BH1780 - tristate "ROHM BH1780 ambient light sensor" - depends on I2C - help - Say Y here to build support for the ROHM BH1780GLI ambient - light sensor. - - To compile this driver as a module, choose M here: the module will - be called bh1780. - -config CM32181 - depends on I2C - tristate "CM32181 driver" - help - Say Y here if you use cm32181. - This option enables ambient light sensor using - Capella cm32181 device driver. - - To compile this driver as a module, choose M here: - the module will be called cm32181. - -config CM3232 - depends on I2C - tristate "CM3232 ambient light sensor" - help - Say Y here if you use cm3232. - This option enables ambient light sensor using - Capella Microsystems cm3232 device driver. - - To compile this driver as a module, choose M here: - the module will be called cm3232. - -config CM3323 - depends on I2C - tristate "Capella CM3323 color light sensor" - help - Say Y here if you want to build a driver for Capella CM3323 - color sensor. - - To compile this driver as a module, choose M here: the module will - be called cm3323. - -config CM36651 - depends on I2C - tristate "CM36651 driver" - help - Say Y here if you use cm36651. - This option enables proximity & RGB sensor using - Capella cm36651 device driver. - - To compile this driver as a module, choose M here: - the module will be called cm36651. - -config GP2AP020A00F - tristate "Sharp GP2AP020A00F Proximity/ALS sensor" - depends on I2C - select REGMAP_I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select IRQ_WORK - help - Say Y here if you have a Sharp GP2AP020A00F proximity/ALS combo-chip - hooked to an I2C bus. - - To compile this driver as a module, choose M here: the - module will be called gp2ap020a00f. - -config ISL29125 - tristate "Intersil ISL29125 digital color light sensor" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say Y here if you want to build a driver for the Intersil ISL29125 - RGB light sensor for I2C. - - To compile this driver as a module, choose M here: the module will be - called isl29125. - -config HID_SENSOR_ALS - depends on HID_SENSOR_HUB - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select HID_SENSOR_IIO_COMMON - select HID_SENSOR_IIO_TRIGGER - tristate "HID ALS" - help - Say yes here to build support for the HID SENSOR - Ambient light sensor. - - To compile this driver as a module, choose M here: the - module will be called hid-sensor-als. - -config HID_SENSOR_PROX - depends on HID_SENSOR_HUB - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select HID_SENSOR_IIO_COMMON - select HID_SENSOR_IIO_TRIGGER - tristate "HID PROX" - help - Say yes here to build support for the HID SENSOR - Proximity sensor. - - To compile this driver as a module, choose M here: the - module will be called hid-sensor-prox. - -config JSA1212 - tristate "JSA1212 ALS and proximity sensor driver" - depends on I2C - select REGMAP_I2C - help - Say Y here if you want to build a IIO driver for JSA1212 - proximity & ALS sensor device. - - To compile this driver as a module, choose M here: - the module will be called jsa1212. - -config RPR0521 - tristate "ROHM RPR0521 ALS and proximity sensor driver" - depends on I2C - select REGMAP_I2C - help - Say Y here if you want to build support for ROHM's RPR0521 - ambient light and proximity sensor device. - - To compile this driver as a module, choose M here: - the module will be called rpr0521. - -config SENSORS_LM3533 - tristate "LM3533 ambient light sensor" - depends on MFD_LM3533 - help - If you say yes here you get support for the ambient light sensor - interface on National Semiconductor / TI LM3533 Lighting Power - chips. - - The sensor interface can be used to control the LEDs and backlights - of the chip through defining five light zones and three sets of - corresponding output-current values. - - The driver provides raw and mean adc readings along with the current - light zone through sysfs. A threshold event can be generated on zone - changes. The ALS-control output values can be set per zone for the - three current output channels. - -config LTR501 - tristate "LTR-501ALS-01 light sensor" - depends on I2C - select REGMAP_I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - If you say yes here you get support for the Lite-On LTR-501ALS-01 - ambient light and proximity sensor. This driver also supports LTR-559 - ALS/PS or LTR-301 ALS sensors. - - This driver can also be built as a module. If so, the module - will be called ltr501. - -config MAX44000 - tristate "MAX44000 Ambient and Infrared Proximity Sensor" - depends on I2C - select REGMAP_I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say Y here if you want to build support for Maxim Integrated's - MAX44000 ambient and infrared proximity sensor device. - - To compile this driver as a module, choose M here: - the module will be called max44000. - -config OPT3001 - tristate "Texas Instruments OPT3001 Light Sensor" - depends on I2C - help - If you say Y or M here, you get support for Texas Instruments - OPT3001 Ambient Light Sensor. - - If built as a dynamically linked module, it will be called - opt3001. - -config PA12203001 - tristate "TXC PA12203001 light and proximity sensor" - depends on I2C - select REGMAP_I2C - help - If you say yes here you get support for the TXC PA12203001 - ambient light and proximity sensor. - - This driver can also be built as a module. If so, the module - will be called pa12203001. - -config SI1145 - tristate "SI1132 and SI1141/2/3/5/6/7 combined ALS, UV index and proximity sensor" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say Y here if you want to build a driver for the Silicon Labs SI1132 or - SI1141/2/3/5/6/7 combined ambient light, UV index and proximity sensor - chips. - - To compile this driver as a module, choose M here: the module will be - called si1145. - -config STK3310 - tristate "STK3310 ALS and proximity sensor" - depends on I2C - select REGMAP_I2C - help - Say yes here to get support for the Sensortek STK3310 ambient light - and proximity sensor. The STK3311 model is also supported by this - driver. - - Choosing M will build the driver as a module. If so, the module - will be called stk3310. - -config TCS3414 - tristate "TAOS TCS3414 digital color sensor" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - If you say yes here you get support for the TAOS TCS3414 - family of digital color sensors. - - This driver can also be built as a module. If so, the module - will be called tcs3414. - -config TCS3472 - tristate "TAOS TCS3472 color light-to-digital converter" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - If you say yes here you get support for the TAOS TCS3472 - family of color light-to-digital converters with IR filter. - - This driver can also be built as a module. If so, the module - will be called tcs3472. - -config SENSORS_TSL2563 - tristate "TAOS TSL2560, TSL2561, TSL2562 and TSL2563 ambient light sensors" - depends on I2C - help - If you say yes here you get support for the Taos TSL2560, - TSL2561, TSL2562 and TSL2563 ambient light sensors. - - This driver can also be built as a module. If so, the module - will be called tsl2563. - -config TSL4531 - tristate "TAOS TSL4531 ambient light sensors" - depends on I2C - help - Say Y here if you want to build a driver for the TAOS TSL4531 family - of ambient light sensors with direct lux output. - - To compile this driver as a module, choose M here: the - module will be called tsl4531. - -config US5182D - tristate "UPISEMI light and proximity sensor" - depends on I2C - help - If you say yes here you get support for the UPISEMI US5182D - ambient light and proximity sensor. - - This driver can also be built as a module. If so, the module - will be called us5182d. - -config VCNL4000 - tristate "VCNL4000/4010/4020 combined ALS and proximity sensor" - depends on I2C - help - Say Y here if you want to build a driver for the Vishay VCNL4000, - VCNL4010, VCNL4020 combined ambient light and proximity sensor. - - To compile this driver as a module, choose M here: the - module will be called vcnl4000. - -config VEML6070 - tristate "VEML6070 UV A light sensor" - depends on I2C - help - Say Y here if you want to build a driver for the Vishay VEML6070 UV A - light sensor. - - To compile this driver as a module, choose M here: the - module will be called veml6070. - -endmenu diff --git a/src/linux/drivers/iio/magnetometer/Kconfig b/src/linux/drivers/iio/magnetometer/Kconfig deleted file mode 100644 index 421ad90..0000000 --- a/src/linux/drivers/iio/magnetometer/Kconfig +++ /dev/null @@ -1,178 +0,0 @@ -# -# Magnetometer sensors -# -# When adding new entries keep the list in alphabetical order - -menu "Magnetometer sensors" - -config AK8974 - tristate "Asahi Kasei AK8974 3-Axis Magnetometer" - depends on I2C - depends on OF - select REGMAP_I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for Asahi Kasei AK8974 or - AMI305 I2C-based 3-axis magnetometer chips. - - To compile this driver as a module, choose M here: the module - will be called ak8974. - -config AK8975 - tristate "Asahi Kasei AK8975 3-Axis Magnetometer" - depends on I2C - depends on GPIOLIB || COMPILE_TEST - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for Asahi Kasei AK8975, AK8963, - AK09911 or AK09912 3-Axis Magnetometer. - - To compile this driver as a module, choose M here: the module - will be called ak8975. - -config AK09911 - tristate "Asahi Kasei AK09911 3-axis Compass" - depends on I2C - depends on GPIOLIB || COMPILE_TEST - select AK8975 - help - Deprecated: AK09911 is now supported by AK8975 driver. - -config BMC150_MAGN - tristate - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - -config BMC150_MAGN_I2C - tristate "Bosch BMC150 I2C Magnetometer Driver" - depends on I2C - select BMC150_MAGN - select REGMAP_I2C - help - Say yes here to build support for the BMC150 magnetometer with - I2C interface. - - This is a combo module with both accelerometer and magnetometer. - This driver is only implementing magnetometer part, which has - its own address and register map. - - This driver also supports I2C Bosch BMC156 and BMM150 chips. - To compile this driver as a module, choose M here: the module will be - called bmc150_magn_i2c. - -config BMC150_MAGN_SPI - tristate "Bosch BMC150 SPI Magnetometer Driver" - depends on SPI - select BMC150_MAGN - select REGMAP_SPI - help - Say yes here to build support for the BMC150 magnetometer with - SPI interface. - - This is a combo module with both accelerometer and magnetometer. - This driver is only implementing magnetometer part, which has - its own address and register map. - - This driver also supports SPI Bosch BMC156 and BMM150 chips. - To compile this driver as a module, choose M here: the module will be - called bmc150_magn_spi. - -config MAG3110 - tristate "Freescale MAG3110 3-Axis Magnetometer" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for the Freescale MAG3110 3-Axis - magnetometer. - - To compile this driver as a module, choose M here: the module - will be called mag3110. - -config HID_SENSOR_MAGNETOMETER_3D - depends on HID_SENSOR_HUB - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select HID_SENSOR_IIO_COMMON - select HID_SENSOR_IIO_TRIGGER - tristate "HID Magenetometer 3D" - help - Say yes here to build support for the HID SENSOR - Magnetometer 3D. - -config MMC35240 - tristate "MEMSIC MMC35240 3-axis magnetic sensor" - select REGMAP_I2C - depends on I2C - help - Say yes here to build support for the MEMSIC MMC35240 3-axis - magnetic sensor. - - To compile this driver as a module, choose M here: the module - will be called mmc35240. - -config IIO_ST_MAGN_3AXIS - tristate "STMicroelectronics magnetometers 3-Axis Driver" - depends on (I2C || SPI_MASTER) && SYSFS - select IIO_ST_SENSORS_CORE - select IIO_ST_MAGN_I2C_3AXIS if (I2C) - select IIO_ST_MAGN_SPI_3AXIS if (SPI_MASTER) - select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) - help - Say yes here to build support for STMicroelectronics magnetometers: - LSM303DLHC, LSM303DLM, LIS3MDL. - - This driver can also be built as a module. If so, these modules - will be created: - - st_magn (core functions for the driver [it is mandatory]); - - st_magn_i2c (necessary for the I2C devices [optional*]); - - st_magn_spi (necessary for the SPI devices [optional*]); - - (*) one of these is necessary to do something. - -config IIO_ST_MAGN_I2C_3AXIS - tristate - depends on IIO_ST_MAGN_3AXIS - depends on IIO_ST_SENSORS_I2C - -config IIO_ST_MAGN_SPI_3AXIS - tristate - depends on IIO_ST_MAGN_3AXIS - depends on IIO_ST_SENSORS_SPI - -config SENSORS_HMC5843 - tristate - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - -config SENSORS_HMC5843_I2C - tristate "Honeywell HMC5843/5883/5883L 3-Axis Magnetometer (I2C)" - depends on I2C - select SENSORS_HMC5843 - select REGMAP_I2C - help - Say Y here to add support for the Honeywell HMC5843, HMC5883 and - HMC5883L 3-Axis Magnetometer (digital compass). - - This driver can also be compiled as a set of modules. - If so, these modules will be created: - - hmc5843_core (core functions) - - hmc5843_i2c (support for HMC5843, HMC5883, HMC5883L and HMC5983) - -config SENSORS_HMC5843_SPI - tristate "Honeywell HMC5983 3-Axis Magnetometer (SPI)" - depends on SPI_MASTER - select SENSORS_HMC5843 - select REGMAP_SPI - help - Say Y here to add support for the Honeywell HMC5983 3-Axis Magnetometer - (digital compass). - - This driver can also be compiled as a set of modules. - If so, these modules will be created: - - hmc5843_core (core functions) - - hmc5843_spi (support for HMC5983) - -endmenu diff --git a/src/linux/drivers/iio/orientation/Kconfig b/src/linux/drivers/iio/orientation/Kconfig deleted file mode 100644 index e3aa1e5..0000000 --- a/src/linux/drivers/iio/orientation/Kconfig +++ /dev/null @@ -1,31 +0,0 @@ -# -# Inclinometer sensors -# -# When adding new entries keep the list in alphabetical order - -menu "Inclinometer sensors" - -config HID_SENSOR_INCLINOMETER_3D - depends on HID_SENSOR_HUB - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select HID_SENSOR_IIO_COMMON - select HID_SENSOR_IIO_TRIGGER - tristate "HID Inclinometer 3D" - help - Say yes here to build support for the HID SENSOR - Inclinometer 3D. - -config HID_SENSOR_DEVICE_ROTATION - depends on HID_SENSOR_HUB - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select HID_SENSOR_IIO_COMMON - select HID_SENSOR_IIO_TRIGGER - tristate "HID Device Rotation" - help - Say yes here to build support for the HID SENSOR - device rotation. The output of a device rotation sensor - is presented using quaternion format. - -endmenu diff --git a/src/linux/drivers/iio/potentiometer/Kconfig b/src/linux/drivers/iio/potentiometer/Kconfig deleted file mode 100644 index 2e9da1c..0000000 --- a/src/linux/drivers/iio/potentiometer/Kconfig +++ /dev/null @@ -1,73 +0,0 @@ -# -# Potentiometer drivers -# -# When adding new entries keep the list in alphabetical order - -menu "Digital potentiometers" - -config DS1803 - tristate "Maxim Integrated DS1803 Digital Potentiometer driver" - depends on I2C - help - Say yes here to build support for the Maxim Integrated DS1803 - digital potentiometer chip. - - To compile this driver as a module, choose M here: the - module will be called ds1803. - -config MAX5487 - tristate "Maxim MAX5487/MAX5488/MAX5489 Digital Potentiometer driver" - depends on SPI - help - Say yes here to build support for the Maxim - MAX5487, MAX5488, MAX5489 digital potentiometer - chips. - - To compile this driver as a module, choose M here: the - module will be called max5487. - -config MCP4131 - tristate "Microchip MCP413X/414X/415X/416X/423X/424X/425X/426X Digital Potentiometer driver" - depends on SPI - help - Say yes here to build support for the Microchip - MCP4131, MCP4132, - MCP4141, MCP4142, - MCP4151, MCP4152, - MCP4161, MCP4162, - MCP4231, MCP4232, - MCP4241, MCP4242, - MCP4251, MCP4252, - MCP4261, MCP4262, - digital potentiometer chips. - - To compile this driver as a module, choose M here: the - module will be called mcp4131. - -config MCP4531 - tristate "Microchip MCP45xx/MCP46xx Digital Potentiometer driver" - depends on I2C - help - Say yes here to build support for the Microchip - MCP4531, MCP4532, MCP4541, MCP4542, - MCP4551, MCP4552, MCP4561, MCP4562, - MCP4631, MCP4632, MCP4641, MCP4642, - MCP4651, MCP4652, MCP4661, MCP4662 - digital potentiometer chips. - - To compile this driver as a module, choose M here: the - module will be called mcp4531. - -config TPL0102 - tristate "Texas Instruments digital potentiometer driver" - depends on I2C - select REGMAP_I2C - help - Say yes here to build support for the Texas Instruments - TPL0102, TPL0402 - digital potentiometer chips. - - To compile this driver as a module, choose M here: the - module will be called tpl0102. - -endmenu diff --git a/src/linux/drivers/iio/pressure/Kconfig b/src/linux/drivers/iio/pressure/Kconfig deleted file mode 100644 index 15cd416..0000000 --- a/src/linux/drivers/iio/pressure/Kconfig +++ /dev/null @@ -1,210 +0,0 @@ -# -# Pressure drivers -# -# When adding new entries keep the list in alphabetical order - -menu "Pressure sensors" - -config BMP280 - tristate "Bosch Sensortec BMP180/BMP280 pressure sensor I2C driver" - depends on (I2C || SPI_MASTER) - select REGMAP - select BMP280_I2C if (I2C) - select BMP280_SPI if (SPI_MASTER) - help - Say yes here to build support for Bosch Sensortec BMP180 and BMP280 - pressure and temperature sensors. Also supports the BE280 with - an additional humidity sensor channel. - - To compile this driver as a module, choose M here: the core module - will be called bmp280 and you will also get bmp280-i2c for I2C - and/or bmp280-spi for SPI support. - -config BMP280_I2C - tristate - depends on BMP280 - depends on I2C - select REGMAP_I2C - -config BMP280_SPI - tristate - depends on BMP280 - depends on SPI_MASTER - select REGMAP - -config HID_SENSOR_PRESS - depends on HID_SENSOR_HUB - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select HID_SENSOR_IIO_COMMON - select HID_SENSOR_IIO_TRIGGER - tristate "HID PRESS" - help - Say yes here to build support for the HID SENSOR - Pressure driver - - To compile this driver as a module, choose M here: the module - will be called hid-sensor-press. - -config HP03 - tristate "Hope RF HP03 temperature and pressure sensor driver" - depends on I2C - select REGMAP_I2C - help - Say yes here to build support for Hope RF HP03 pressure and - temperature sensor. - - To compile this driver as a module, choose M here: the module - will be called hp03. - -config MPL115 - tristate - -config MPL115_I2C - tristate "Freescale MPL115A2 pressure sensor driver" - depends on I2C - select MPL115 - help - Say yes here to build support for the Freescale MPL115A2 - pressure sensor connected via I2C. - - To compile this driver as a module, choose M here: the module - will be called mpl115_i2c. - -config MPL115_SPI - tristate "Freescale MPL115A1 pressure sensor driver" - depends on SPI_MASTER - select MPL115 - help - Say yes here to build support for the Freescale MPL115A1 - pressure sensor connected via SPI. - - To compile this driver as a module, choose M here: the module - will be called mpl115_spi. - -config MPL3115 - tristate "Freescale MPL3115A2 pressure sensor driver" - depends on I2C - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for the Freescale MPL3115A2 - pressure sensor / altimeter. - - To compile this driver as a module, choose M here: the module - will be called mpl3115. - -config MS5611 - tristate "Measurement Specialties MS5611 pressure sensor driver" - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say Y here to build support for the Measurement Specialties - MS5611, MS5607 pressure and temperature sensors. - - To compile this driver as a module, choose M here: the module will - be called ms5611_core. - -config MS5611_I2C - tristate "support I2C bus connection" - depends on I2C && MS5611 - help - Say Y here to build I2C bus support for MS5611. - - To compile this driver as a module, choose M here: the module will - be called ms5611_i2c. - -config MS5611_SPI - tristate "support SPI bus connection" - depends on SPI_MASTER && MS5611 - help - Say Y here to build SPI bus support for MS5611. - - To compile this driver as a module, choose M here: the module will - be called ms5611_spi. - -config MS5637 - tristate "Measurement Specialties MS5637 pressure & temperature sensor" - depends on I2C - select IIO_MS_SENSORS_I2C - help - If you say yes here you get support for the Measurement Specialties - MS5637 pressure and temperature sensor. - This driver is also used for MS8607 temperature, pressure & humidity - sensor - - This driver can also be built as a module. If so, the module will - be called ms5637. - -config IIO_ST_PRESS - tristate "STMicroelectronics pressure sensor Driver" - depends on (I2C || SPI_MASTER) && SYSFS - select IIO_ST_SENSORS_CORE - select IIO_ST_PRESS_I2C if (I2C) - select IIO_ST_PRESS_SPI if (SPI_MASTER) - select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) - help - Say yes here to build support for STMicroelectronics pressure - sensors: LPS001WP, LPS25H, LPS331AP, LPS22HB. - - This driver can also be built as a module. If so, these modules - will be created: - - st_pressure (core functions for the driver [it is mandatory]); - - st_pressure_i2c (necessary for the I2C devices [optional*]); - - st_pressure_spi (necessary for the SPI devices [optional*]); - - (*) one of these is necessary to do something. - -config IIO_ST_PRESS_I2C - tristate - depends on IIO_ST_PRESS - depends on IIO_ST_SENSORS_I2C - -config IIO_ST_PRESS_SPI - tristate - depends on IIO_ST_PRESS - depends on IIO_ST_SENSORS_SPI - -config T5403 - tristate "EPCOS T5403 digital barometric pressure sensor driver" - depends on I2C - help - Say yes here to build support for the EPCOS T5403 pressure sensor - connected via I2C. - - To compile this driver as a module, choose M here: the module - will be called t5403. - -config HP206C - tristate "HOPERF HP206C precision barometer and altimeter sensor" - depends on I2C - help - Say yes here to build support for the HOPREF HP206C precision - barometer and altimeter sensor. - - This driver can also be built as a module. If so, the module will - be called hp206c. - -config ZPA2326 - tristate "Murata ZPA2326 pressure sensor driver" - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select REGMAP - select ZPA2326_I2C if I2C - select ZPA2326_SPI if SPI_MASTER - help - Say Y here to build support for the Murata ZPA2326 pressure and - temperature sensor. - - To compile this driver as a module, choose M here: the module will - be called zpa2326. - -config ZPA2326_I2C - tristate - select REGMAP_I2C - -config ZPA2326_SPI - tristate - select REGMAP_SPI - -endmenu diff --git a/src/linux/drivers/iio/proximity/Kconfig b/src/linux/drivers/iio/proximity/Kconfig deleted file mode 100644 index ef4c73d..0000000 --- a/src/linux/drivers/iio/proximity/Kconfig +++ /dev/null @@ -1,48 +0,0 @@ -# -# Proximity sensors -# - -menu "Lightning sensors" - -config AS3935 - tristate "AS3935 Franklin lightning sensor" - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - depends on SPI - help - Say Y here to build SPI interface support for the Austrian - Microsystems AS3935 lightning detection sensor. - - To compile this driver as a module, choose M here: the - module will be called as3935 - -endmenu - -menu "Proximity sensors" - -config LIDAR_LITE_V2 - tristate "PulsedLight LIDAR sensor" - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - depends on I2C - help - Say Y to build a driver for PulsedLight LIDAR range finding - sensor. - - To compile this driver as a module, choose M here: the - module will be called pulsedlight-lite-v2 - -config SX9500 - tristate "SX9500 Semtech proximity sensor" - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - select REGMAP_I2C - depends on I2C - help - Say Y here to build a driver for Semtech's SX9500 capacitive - proximity/button sensor. - - To compile this driver as a module, choose M here: the - module will be called sx9500. - -endmenu diff --git a/src/linux/drivers/iio/temperature/Kconfig b/src/linux/drivers/iio/temperature/Kconfig deleted file mode 100644 index 5ea77a7..0000000 --- a/src/linux/drivers/iio/temperature/Kconfig +++ /dev/null @@ -1,64 +0,0 @@ -# -# Temperature sensor drivers -# -menu "Temperature sensors" - -config MAXIM_THERMOCOUPLE - tristate "Maxim thermocouple sensors" - depends on SPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - If you say yes here you get support for the Maxim series of - thermocouple sensors connected via SPI. - - Supported sensors: - * MAX6675 - * MAX31855 - - This driver can also be built as a module. If so, the module will - be called maxim_thermocouple. - -config MLX90614 - tristate "MLX90614 contact-less infrared sensor" - depends on I2C - help - If you say yes here you get support for the Melexis - MLX90614 contact-less infrared sensor connected with I2C. - - This driver can also be built as a module. If so, the module will - be called mlx90614. - -config TMP006 - tristate "TMP006 infrared thermopile sensor" - depends on I2C - help - If you say yes here you get support for the Texas Instruments - TMP006 infrared thermopile sensor. - - This driver can also be built as a module. If so, the module will - be called tmp006. - -config TSYS01 - tristate "Measurement Specialties TSYS01 temperature sensor using I2C bus connection" - depends on I2C - select IIO_MS_SENSORS_I2C - help - If you say yes here you get support for the Measurement Specialties - TSYS01 I2C temperature sensor. - - This driver can also be built as a module. If so, the module will - be called tsys01. - -config TSYS02D - tristate "Measurement Specialties TSYS02D temperature sensor" - depends on I2C - select IIO_MS_SENSORS_I2C - help - If you say yes here you get support for the Measurement Specialties - TSYS02D temperature sensor. - - This driver can also be built as a module. If so, the module will - be called tsys02d. - -endmenu diff --git a/src/linux/drivers/iio/trigger/Kconfig b/src/linux/drivers/iio/trigger/Kconfig deleted file mode 100644 index 809b2e7..0000000 --- a/src/linux/drivers/iio/trigger/Kconfig +++ /dev/null @@ -1,50 +0,0 @@ -# -# Industrial I/O standalone triggers -# -# When adding new entries keep the list in alphabetical order - -menu "Triggers - standalone" - -config IIO_HRTIMER_TRIGGER - tristate "High resolution timer trigger" - depends on IIO_SW_TRIGGER - help - Provides a frequency based IIO trigger using high resolution - timers as interrupt source. - - To compile this driver as a module, choose M here: the - module will be called iio-trig-hrtimer. - -config IIO_INTERRUPT_TRIGGER - tristate "Generic interrupt trigger" - help - Provides support for using an interrupt of any type as an IIO - trigger. This may be provided by a gpio driver for example. - - To compile this driver as a module, choose M here: the - module will be called iio-trig-interrupt. - -config IIO_TIGHTLOOP_TRIGGER - tristate "A kthread based hammering loop trigger" - depends on IIO_SW_TRIGGER - help - An experimental trigger, used to allow sensors to be sampled as fast - as possible under the limitations of whatever else is going on. - Uses a tight loop in a kthread. Will only work with lower half only - trigger consumers. - - To compile this driver as a module, choose M here: the - module will be called iio-trig-loop. - -config IIO_SYSFS_TRIGGER - tristate "SYSFS trigger" - depends on SYSFS - select IRQ_WORK - help - Provides support for using SYSFS entries as IIO triggers. - If unsure, say N (but it's safe to say "Y"). - - To compile this driver as a module, choose M here: the - module will be called iio-trig-sysfs. - -endmenu diff --git a/src/linux/drivers/infiniband/Kconfig b/src/linux/drivers/infiniband/Kconfig deleted file mode 100644 index fb3fb89..0000000 --- a/src/linux/drivers/infiniband/Kconfig +++ /dev/null @@ -1,94 +0,0 @@ -menuconfig INFINIBAND - tristate "InfiniBand support" - depends on PCI || BROKEN - depends on HAS_IOMEM - depends on NET - depends on INET - depends on m || IPV6 != m - select IRQ_POLL - ---help--- - Core support for InfiniBand (IB). Make sure to also select - any protocols you wish to use as well as drivers for your - InfiniBand hardware. - -if INFINIBAND - -config INFINIBAND_USER_MAD - tristate "InfiniBand userspace MAD support" - depends on INFINIBAND - ---help--- - Userspace InfiniBand Management Datagram (MAD) support. This - is the kernel side of the userspace MAD support, which allows - userspace processes to send and receive MADs. You will also - need libibumad from . - -config INFINIBAND_USER_ACCESS - tristate "InfiniBand userspace access (verbs and CM)" - select ANON_INODES - ---help--- - Userspace InfiniBand access support. This enables the - kernel side of userspace verbs and the userspace - communication manager (CM). This allows userspace processes - to set up connections and directly access InfiniBand - hardware for fast-path operations. You will also need - libibverbs, libibcm and a hardware driver library from - . - -config INFINIBAND_USER_MEM - bool - depends on INFINIBAND_USER_ACCESS != n - default y - -config INFINIBAND_ON_DEMAND_PAGING - bool "InfiniBand on-demand paging support" - depends on INFINIBAND_USER_MEM - select MMU_NOTIFIER - default y - ---help--- - On demand paging support for the InfiniBand subsystem. - Together with driver support this allows registration of - memory regions without pinning their pages, fetching the - pages on demand instead. - -config INFINIBAND_ADDR_TRANS - bool - depends on INFINIBAND - default y - -config INFINIBAND_ADDR_TRANS_CONFIGFS - bool - depends on INFINIBAND_ADDR_TRANS && CONFIGFS_FS && !(INFINIBAND=y && CONFIGFS_FS=m) - default y - ---help--- - ConfigFS support for RDMA communication manager (CM). - This allows the user to config the default GID type that the CM - uses for each device, when initiaing new connections. - -source "drivers/infiniband/hw/mthca/Kconfig" -source "drivers/infiniband/hw/qib/Kconfig" -source "drivers/infiniband/hw/cxgb3/Kconfig" -source "drivers/infiniband/hw/cxgb4/Kconfig" -source "drivers/infiniband/hw/i40iw/Kconfig" -source "drivers/infiniband/hw/mlx4/Kconfig" -source "drivers/infiniband/hw/mlx5/Kconfig" -source "drivers/infiniband/hw/nes/Kconfig" -source "drivers/infiniband/hw/ocrdma/Kconfig" -source "drivers/infiniband/hw/usnic/Kconfig" -source "drivers/infiniband/hw/hns/Kconfig" - -source "drivers/infiniband/ulp/ipoib/Kconfig" - -source "drivers/infiniband/ulp/srp/Kconfig" -source "drivers/infiniband/ulp/srpt/Kconfig" - -source "drivers/infiniband/ulp/iser/Kconfig" -source "drivers/infiniband/ulp/isert/Kconfig" - -source "drivers/infiniband/sw/rdmavt/Kconfig" -source "drivers/infiniband/sw/rxe/Kconfig" - -source "drivers/infiniband/hw/hfi1/Kconfig" - -source "drivers/infiniband/hw/qedr/Kconfig" - -endif # INFINIBAND diff --git a/src/linux/drivers/infiniband/hw/cxgb3/Kconfig b/src/linux/drivers/infiniband/hw/cxgb3/Kconfig deleted file mode 100644 index 2b6352b..0000000 --- a/src/linux/drivers/infiniband/hw/cxgb3/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -config INFINIBAND_CXGB3 - tristate "Chelsio RDMA Driver" - depends on CHELSIO_T3 && INET - select GENERIC_ALLOCATOR - ---help--- - This is an iWARP/RDMA driver for the Chelsio T3 1GbE and - 10GbE adapters. - - For general information about Chelsio and our products, visit - our website at . - - For customer support, please visit our customer support page at - . - - Please send feedback to . - - To compile this driver as a module, choose M here: the module - will be called iw_cxgb3. - -config INFINIBAND_CXGB3_DEBUG - bool "Verbose debugging output" - depends on INFINIBAND_CXGB3 - default n - ---help--- - This option causes the Chelsio RDMA driver to produce copious - amounts of debug messages. Select this if you are developing - the driver or trying to diagnose a problem. diff --git a/src/linux/drivers/infiniband/hw/cxgb4/Kconfig b/src/linux/drivers/infiniband/hw/cxgb4/Kconfig deleted file mode 100644 index afe8b28..0000000 --- a/src/linux/drivers/infiniband/hw/cxgb4/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -config INFINIBAND_CXGB4 - tristate "Chelsio T4/T5 RDMA Driver" - depends on CHELSIO_T4 && INET && (IPV6 || IPV6=n) - select CHELSIO_LIB - select GENERIC_ALLOCATOR - ---help--- - This is an iWARP/RDMA driver for the Chelsio T4 and T5 - 1GbE, 10GbE adapters and T5 40GbE adapter. - - For general information about Chelsio and our products, visit - our website at . - - For customer support, please visit our customer support page at - . - - Please send feedback to . - - To compile this driver as a module, choose M here: the module - will be called iw_cxgb4. diff --git a/src/linux/drivers/infiniband/hw/hfi1/Kconfig b/src/linux/drivers/infiniband/hw/hfi1/Kconfig deleted file mode 100644 index f6ea088..0000000 --- a/src/linux/drivers/infiniband/hw/hfi1/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -config INFINIBAND_HFI1 - tristate "Intel OPA Gen1 support" - depends on X86_64 && INFINIBAND_RDMAVT && I2C - select MMU_NOTIFIER - select CRC32 - select I2C_ALGOBIT - ---help--- - This is a low-level driver for Intel OPA Gen1 adapter. -config HFI1_DEBUG_SDMA_ORDER - bool "HFI1 SDMA Order debug" - depends on INFINIBAND_HFI1 - default n - ---help--- - This is a debug flag to test for out of order - sdma completions for unit testing -config HFI1_VERBS_31BIT_PSN - bool "HFI1 enable 31 bit PSN" - depends on INFINIBAND_HFI1 - default y - ---help--- - Setting this enables 31 BIT PSN - For verbs RC/UC -config SDMA_VERBOSITY - bool "Config SDMA Verbosity" - depends on INFINIBAND_HFI1 - default n - ---help--- - This is a configuration flag to enable verbose - SDMA debug diff --git a/src/linux/drivers/infiniband/hw/hns/Kconfig b/src/linux/drivers/infiniband/hw/hns/Kconfig deleted file mode 100644 index e1a6e05..0000000 --- a/src/linux/drivers/infiniband/hw/hns/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config INFINIBAND_HNS - tristate "HNS RoCE Driver" - depends on NET_VENDOR_HISILICON - depends on ARM64 && HNS && HNS_DSAF && HNS_ENET - ---help--- - This is a RoCE/RDMA driver for the Hisilicon RoCE engine. The engine - is used in Hisilicon Hi1610 and more further ICT SoC. - - To compile this driver as a module, choose M here: the module - will be called hns-roce. diff --git a/src/linux/drivers/infiniband/hw/i40iw/Kconfig b/src/linux/drivers/infiniband/hw/i40iw/Kconfig deleted file mode 100644 index 6e7d27a..0000000 --- a/src/linux/drivers/infiniband/hw/i40iw/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -config INFINIBAND_I40IW - tristate "Intel(R) Ethernet X722 iWARP Driver" - depends on INET && I40E - select GENERIC_ALLOCATOR - ---help--- - Intel(R) Ethernet X722 iWARP Driver - INET && I40IW && INFINIBAND && I40E diff --git a/src/linux/drivers/infiniband/hw/mlx4/Kconfig b/src/linux/drivers/infiniband/hw/mlx4/Kconfig deleted file mode 100644 index db4aa13..0000000 --- a/src/linux/drivers/infiniband/hw/mlx4/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config MLX4_INFINIBAND - tristate "Mellanox ConnectX HCA support" - depends on NETDEVICES && ETHERNET && PCI && INET - depends on MAY_USE_DEVLINK - select NET_VENDOR_MELLANOX - select MLX4_CORE - ---help--- - This driver provides low-level InfiniBand support for - Mellanox ConnectX PCI Express host channel adapters (HCAs). - This is required to use InfiniBand protocols such as - IP-over-IB or SRP with these devices. diff --git a/src/linux/drivers/infiniband/hw/mlx5/Kconfig b/src/linux/drivers/infiniband/hw/mlx5/Kconfig deleted file mode 100644 index bce263b..0000000 --- a/src/linux/drivers/infiniband/hw/mlx5/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config MLX5_INFINIBAND - tristate "Mellanox Connect-IB HCA support" - depends on NETDEVICES && ETHERNET && PCI && MLX5_CORE - ---help--- - This driver provides low-level InfiniBand support for - Mellanox Connect-IB PCI Express host channel adapters (HCAs). - This is required to use InfiniBand protocols such as - IP-over-IB or SRP with these devices. diff --git a/src/linux/drivers/infiniband/hw/mthca/Kconfig b/src/linux/drivers/infiniband/hw/mthca/Kconfig deleted file mode 100644 index da314c3..0000000 --- a/src/linux/drivers/infiniband/hw/mthca/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -config INFINIBAND_MTHCA - tristate "Mellanox HCA support" - depends on PCI - ---help--- - This is a low-level driver for Mellanox InfiniHost host - channel adapters (HCAs), including the MT23108 PCI-X HCA - ("Tavor") and the MT25208 PCI Express HCA ("Arbel"). - -config INFINIBAND_MTHCA_DEBUG - bool "Verbose debugging output" if EXPERT - depends on INFINIBAND_MTHCA - default y - ---help--- - This option causes debugging code to be compiled into the - mthca driver. The output can be turned on via the - debug_level module parameter (which can also be set after - the driver is loaded through sysfs). diff --git a/src/linux/drivers/infiniband/hw/nes/Kconfig b/src/linux/drivers/infiniband/hw/nes/Kconfig deleted file mode 100644 index 7964eba..0000000 --- a/src/linux/drivers/infiniband/hw/nes/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -config INFINIBAND_NES - tristate "NetEffect RNIC Driver" - depends on PCI && INET && INFINIBAND - select LIBCRC32C - ---help--- - This is the RDMA Network Interface Card (RNIC) driver for - NetEffect Ethernet Cluster Server Adapters. - -config INFINIBAND_NES_DEBUG - bool "Verbose debugging output" - depends on INFINIBAND_NES - default n - ---help--- - This option enables debug messages from the NetEffect RNIC - driver. Select this if you are diagnosing a problem. diff --git a/src/linux/drivers/infiniband/hw/ocrdma/Kconfig b/src/linux/drivers/infiniband/hw/ocrdma/Kconfig deleted file mode 100644 index c0cddc0..0000000 --- a/src/linux/drivers/infiniband/hw/ocrdma/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config INFINIBAND_OCRDMA - tristate "Emulex One Connect HCA support" - depends on ETHERNET && NETDEVICES && PCI && INET && (IPV6 || IPV6=n) - select NET_VENDOR_EMULEX - select BE2NET - ---help--- - This driver provides low-level InfiniBand over Ethernet - support for Emulex One Connect host channel adapters (HCAs). diff --git a/src/linux/drivers/infiniband/hw/qedr/Kconfig b/src/linux/drivers/infiniband/hw/qedr/Kconfig deleted file mode 100644 index 6c9f392..0000000 --- a/src/linux/drivers/infiniband/hw/qedr/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config INFINIBAND_QEDR - tristate "QLogic RoCE driver" - depends on 64BIT && QEDE - select QED_LL2 - select QED_RDMA - ---help--- - This driver provides low-level InfiniBand over Ethernet - support for QLogic QED host channel adapters (HCAs). diff --git a/src/linux/drivers/infiniband/hw/qib/Kconfig b/src/linux/drivers/infiniband/hw/qib/Kconfig deleted file mode 100644 index e0fdb92..0000000 --- a/src/linux/drivers/infiniband/hw/qib/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -config INFINIBAND_QIB - tristate "Intel PCIe HCA support" - depends on 64BIT && INFINIBAND_RDMAVT - ---help--- - This is a low-level driver for Intel PCIe QLE InfiniBand host - channel adapters. This driver does not support the Intel - HyperTransport card (model QHT7140). - -config INFINIBAND_QIB_DCA - bool "QIB DCA support" - depends on INFINIBAND_QIB && DCA && SMP && !(INFINIBAND_QIB=y && DCA=m) - default y - ---help--- - Setting this enables DCA support on some Intel chip sets - with the iba7322 HCA. diff --git a/src/linux/drivers/infiniband/hw/usnic/Kconfig b/src/linux/drivers/infiniband/hw/usnic/Kconfig deleted file mode 100644 index 29ab11c..0000000 --- a/src/linux/drivers/infiniband/hw/usnic/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config INFINIBAND_USNIC - tristate "Verbs support for Cisco VIC" - depends on NETDEVICES && ETHERNET && INET && PCI && INTEL_IOMMU - select ENIC - select NET_VENDOR_CISCO - select PCI_IOV - select INFINIBAND_USER_ACCESS - ---help--- - This is a low-level driver for Cisco's Virtual Interface - Cards (VICs), including the VIC 1240 and 1280 cards. diff --git a/src/linux/drivers/infiniband/sw/rdmavt/Kconfig b/src/linux/drivers/infiniband/sw/rdmavt/Kconfig deleted file mode 100644 index 1da8d01..0000000 --- a/src/linux/drivers/infiniband/sw/rdmavt/Kconfig +++ /dev/null @@ -1,5 +0,0 @@ -config INFINIBAND_RDMAVT - tristate "RDMA verbs transport library" - depends on 64BIT - ---help--- - This is a common software verbs provider for RDMA networks. diff --git a/src/linux/drivers/infiniband/sw/rxe/Kconfig b/src/linux/drivers/infiniband/sw/rxe/Kconfig deleted file mode 100644 index 1e4e628..0000000 --- a/src/linux/drivers/infiniband/sw/rxe/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -config RDMA_RXE - tristate "Software RDMA over Ethernet (RoCE) driver" - depends on INET && PCI && INFINIBAND - depends on NET_UDP_TUNNEL - ---help--- - This driver implements the InfiniBand RDMA transport over - the Linux network stack. It enables a system with a - standard Ethernet adapter to interoperate with a RoCE - adapter or with another system running the RXE driver. - Documentation on InfiniBand and RoCE can be downloaded at - www.infinibandta.org and www.openfabrics.org. (See also - siw which is a similar software driver for iWARP.) - - The driver is split into two layers, one interfaces with the - Linux RDMA stack and implements a kernel or user space - verbs API. The user space verbs API requires a support - library named librxe which is loaded by the generic user - space verbs API, libibverbs. The other layer interfaces - with the Linux network stack at layer 3. - - To configure and work with soft-RoCE driver please use the - following wiki page under "configure Soft-RoCE (RXE)" section: - - https://github.com/SoftRoCE/rxe-dev/wiki/rxe-dev:-Home diff --git a/src/linux/drivers/infiniband/ulp/ipoib/Kconfig b/src/linux/drivers/infiniband/ulp/ipoib/Kconfig deleted file mode 100644 index cda8eac..0000000 --- a/src/linux/drivers/infiniband/ulp/ipoib/Kconfig +++ /dev/null @@ -1,49 +0,0 @@ -config INFINIBAND_IPOIB - tristate "IP-over-InfiniBand" - depends on NETDEVICES && INET && (IPV6 || IPV6=n) - ---help--- - Support for the IP-over-InfiniBand protocol (IPoIB). This - transports IP packets over InfiniBand so you can use your IB - device as a fancy NIC. - - See Documentation/infiniband/ipoib.txt for more information - -config INFINIBAND_IPOIB_CM - bool "IP-over-InfiniBand Connected Mode support" - depends on INFINIBAND_IPOIB - default n - ---help--- - This option enables support for IPoIB connected mode. After - enabling this option, you need to switch to connected mode - through /sys/class/net/ibXXX/mode to actually create - connections, and then increase the interface MTU with - e.g. ifconfig ib0 mtu 65520. - - WARNING: Enabling connected mode will trigger some packet - drops for multicast and UD mode traffic from this interface, - unless you limit mtu for these destinations to 2044. - -config INFINIBAND_IPOIB_DEBUG - bool "IP-over-InfiniBand debugging" if EXPERT - depends on INFINIBAND_IPOIB - default y - ---help--- - This option causes debugging code to be compiled into the - IPoIB driver. The output can be turned on via the - debug_level and mcast_debug_level module parameters (which - can also be set after the driver is loaded through sysfs). - - This option also creates a directory tree under ipoib/ in - debugfs, which contains files that expose debugging - information about IB multicast groups used by the IPoIB - driver. - -config INFINIBAND_IPOIB_DEBUG_DATA - bool "IP-over-InfiniBand data path debugging" - depends on INFINIBAND_IPOIB_DEBUG - ---help--- - This option compiles debugging code into the data path - of the IPoIB driver. The output can be turned on via the - data_debug_level module parameter; however, even with output - turned off, this debugging code will have some performance - impact. diff --git a/src/linux/drivers/infiniband/ulp/iser/Kconfig b/src/linux/drivers/infiniband/ulp/iser/Kconfig deleted file mode 100644 index d00af71..0000000 --- a/src/linux/drivers/infiniband/ulp/iser/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config INFINIBAND_ISER - tristate "iSCSI Extensions for RDMA (iSER)" - depends on SCSI && INET && INFINIBAND_ADDR_TRANS - select SCSI_ISCSI_ATTRS - ---help--- - Support for the iSCSI Extensions for RDMA (iSER) Protocol - over InfiniBand. This allows you to access storage devices - that speak iSCSI over iSER over InfiniBand. - - The iSER protocol is defined by IETF. - See - and diff --git a/src/linux/drivers/infiniband/ulp/isert/Kconfig b/src/linux/drivers/infiniband/ulp/isert/Kconfig deleted file mode 100644 index 02f9759..0000000 --- a/src/linux/drivers/infiniband/ulp/isert/Kconfig +++ /dev/null @@ -1,5 +0,0 @@ -config INFINIBAND_ISERT - tristate "iSCSI Extensions for RDMA (iSER) target support" - depends on INET && INFINIBAND_ADDR_TRANS && TARGET_CORE && ISCSI_TARGET - ---help--- - Support for iSCSI Extensions for RDMA (iSER) Target on Infiniband fabrics. diff --git a/src/linux/drivers/infiniband/ulp/srp/Kconfig b/src/linux/drivers/infiniband/ulp/srp/Kconfig deleted file mode 100644 index c74ee96..0000000 --- a/src/linux/drivers/infiniband/ulp/srp/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config INFINIBAND_SRP - tristate "InfiniBand SCSI RDMA Protocol" - depends on SCSI - select SCSI_SRP_ATTRS - ---help--- - Support for the SCSI RDMA Protocol over InfiniBand. This - allows you to access storage devices that speak SRP over - InfiniBand. - - The SRP protocol is defined by the INCITS T10 technical - committee. See . - diff --git a/src/linux/drivers/infiniband/ulp/srpt/Kconfig b/src/linux/drivers/infiniband/ulp/srpt/Kconfig deleted file mode 100644 index 31ee83d..0000000 --- a/src/linux/drivers/infiniband/ulp/srpt/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config INFINIBAND_SRPT - tristate "InfiniBand SCSI RDMA Protocol target support" - depends on INFINIBAND && TARGET_CORE - ---help--- - - Support for the SCSI RDMA Protocol (SRP) Target driver. The - SRP protocol is a protocol that allows an initiator to access - a block storage device on another host (target) over a network - that supports the RDMA protocol. Currently the RDMA protocol is - supported by InfiniBand and by iWarp network hardware. More - information about the SRP protocol can be found on the website - of the INCITS T10 technical committee (http://www.t10.org/). diff --git a/src/linux/drivers/input/Kconfig b/src/linux/drivers/input/Kconfig deleted file mode 100644 index 6261874..0000000 --- a/src/linux/drivers/input/Kconfig +++ /dev/null @@ -1,217 +0,0 @@ -# -# Input device configuration -# - -menu "Input device support" - depends on !UML - -config INPUT - tristate "Generic input layer (needed for keyboard, mouse, ...)" if EXPERT - default y - help - Say Y here if you have any input device (mouse, keyboard, tablet, - joystick, steering wheel ...) connected to your system and want - it to be available to applications. This includes standard PS/2 - keyboard and mouse. - - Say N here if you have a headless (no monitor, no keyboard) system. - - More information is available: - - If unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called input. - -if INPUT - -config INPUT_LEDS - tristate "Export input device LEDs in sysfs" - depends on LEDS_CLASS - default INPUT - help - Say Y here if you would like to export LEDs on input devices - as standard LED class devices in sysfs. - - If unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called input-leds. - -config INPUT_FF_MEMLESS - tristate "Support for memoryless force-feedback devices" - help - Say Y here if you have memoryless force-feedback input device - such as Logitech WingMan Force 3D, ThrustMaster FireStorm Dual - Power 2, or similar. You will also need to enable hardware-specific - driver. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called ff-memless. - -config INPUT_POLLDEV - tristate "Polled input device skeleton" - help - Say Y here if you are using a driver for an input - device that periodically polls hardware state. This - option is only useful for out-of-tree drivers since - in-tree drivers select it automatically. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called input-polldev. - -config INPUT_SPARSEKMAP - tristate "Sparse keymap support library" - help - Say Y here if you are using a driver for an input - device that uses sparse keymap. This option is only - useful for out-of-tree drivers since in-tree drivers - select it automatically. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called sparse-keymap. - -config INPUT_MATRIXKMAP - tristate "Matrix keymap support library" - help - Say Y here if you are using a driver for an input - device that uses matrix keymap. This option is only - useful for out-of-tree drivers since in-tree drivers - select it automatically. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called matrix-keymap. - -comment "Userland interfaces" - -config INPUT_MOUSEDEV - tristate "Mouse interface" - default y - help - Say Y here if you want your mouse to be accessible as char devices - 13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice as an - emulated IntelliMouse Explorer PS/2 mouse. That way, all user space - programs (including SVGAlib, GPM and X) will be able to use your - mouse. - - If unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called mousedev. - -config INPUT_MOUSEDEV_PSAUX - bool "Provide legacy /dev/psaux device" - default y - depends on INPUT_MOUSEDEV - help - Say Y here if you want your mouse also be accessible as char device - 10:1 - /dev/psaux. The data available through /dev/psaux is exactly - the same as the data from /dev/input/mice. - - If unsure, say Y. - - -config INPUT_MOUSEDEV_SCREEN_X - int "Horizontal screen resolution" - depends on INPUT_MOUSEDEV - default "1024" - help - If you're using a digitizer, or a graphic tablet, and want to use - it as a mouse then the mousedev driver needs to know the X window - screen resolution you are using to correctly scale the data. If - you're not using a digitizer, this value is ignored. - -config INPUT_MOUSEDEV_SCREEN_Y - int "Vertical screen resolution" - depends on INPUT_MOUSEDEV - default "768" - help - If you're using a digitizer, or a graphic tablet, and want to use - it as a mouse then the mousedev driver needs to know the X window - screen resolution you are using to correctly scale the data. If - you're not using a digitizer, this value is ignored. - -config INPUT_JOYDEV - tristate "Joystick interface" - help - Say Y here if you want your joystick or gamepad to be - accessible as char device 13:0+ - /dev/input/jsX device. - - If unsure, say Y. - - More information is available: - - To compile this driver as a module, choose M here: the - module will be called joydev. - -config INPUT_EVDEV - tristate "Event interface" - help - Say Y here if you want your input device events be accessible - under char device 13:64+ - /dev/input/eventX in a generic way. - - To compile this driver as a module, choose M here: the - module will be called evdev. - -config INPUT_EVBUG - tristate "Event debugging" - help - Say Y here if you have a problem with the input subsystem and - want all events (keypresses, mouse movements), to be output to - the system log. While this is useful for debugging, it's also - a security threat - your keypresses include your passwords, of - course. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called evbug. - -config INPUT_APMPOWER - tristate "Input Power Event -> APM Bridge" if EXPERT - depends on INPUT && APM_EMULATION - help - Say Y here if you want suspend key events to trigger a user - requested suspend through APM. This is useful on embedded - systems where such behaviour is desired without userspace - interaction. If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called apm-power. - -comment "Input Device Drivers" - -source "drivers/input/keyboard/Kconfig" - -source "drivers/input/mouse/Kconfig" - -source "drivers/input/joystick/Kconfig" - -source "drivers/input/tablet/Kconfig" - -source "drivers/input/touchscreen/Kconfig" - -source "drivers/input/misc/Kconfig" - -source "drivers/input/rmi4/Kconfig" - -endif - -menu "Hardware I/O ports" - -source "drivers/input/serio/Kconfig" - -source "drivers/input/gameport/Kconfig" - -endmenu - -endmenu - diff --git a/src/linux/drivers/input/Makefile b/src/linux/drivers/input/Makefile deleted file mode 100644 index 595820b..0000000 --- a/src/linux/drivers/input/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# -# Makefile for the input core drivers. -# - -# Each configuration option enables a list of files. - -obj-$(CONFIG_INPUT) += input-core.o -input-core-y := input.o input-compat.o input-mt.o ff-core.o - -obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o -obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o -obj-$(CONFIG_INPUT_SPARSEKMAP) += sparse-keymap.o -obj-$(CONFIG_INPUT_MATRIXKMAP) += matrix-keymap.o - -obj-$(CONFIG_INPUT_LEDS) += input-leds.o -obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.o -obj-$(CONFIG_INPUT_JOYDEV) += joydev.o -obj-$(CONFIG_INPUT_EVDEV) += evdev.o -obj-$(CONFIG_INPUT_EVBUG) += evbug.o - -obj-$(CONFIG_INPUT_KEYBOARD) += keyboard/ -obj-$(CONFIG_INPUT_MOUSE) += mouse/ -obj-$(CONFIG_INPUT_JOYSTICK) += joystick/ -obj-$(CONFIG_INPUT_TABLET) += tablet/ -obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ -obj-$(CONFIG_INPUT_MISC) += misc/ - -obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o - -obj-$(CONFIG_RMI4_CORE) += rmi4/ diff --git a/src/linux/drivers/input/ff-core.c b/src/linux/drivers/input/ff-core.c deleted file mode 100644 index 8f20424..0000000 --- a/src/linux/drivers/input/ff-core.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Force feedback support for Linux input subsystem - * - * Copyright (c) 2006 Anssi Hannula - * Copyright (c) 2006 Dmitry Torokhov - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* #define DEBUG */ - -#include -#include -#include -#include -#include - -/* - * Check that the effect_id is a valid effect and whether the user - * is the owner - */ -static int check_effect_access(struct ff_device *ff, int effect_id, - struct file *file) -{ - if (effect_id < 0 || effect_id >= ff->max_effects || - !ff->effect_owners[effect_id]) - return -EINVAL; - - if (file && ff->effect_owners[effect_id] != file) - return -EACCES; - - return 0; -} - -/* - * Checks whether 2 effects can be combined together - */ -static inline int check_effects_compatible(struct ff_effect *e1, - struct ff_effect *e2) -{ - return e1->type == e2->type && - (e1->type != FF_PERIODIC || - e1->u.periodic.waveform == e2->u.periodic.waveform); -} - -/* - * Convert an effect into compatible one - */ -static int compat_effect(struct ff_device *ff, struct ff_effect *effect) -{ - int magnitude; - - switch (effect->type) { - case FF_RUMBLE: - if (!test_bit(FF_PERIODIC, ff->ffbit)) - return -EINVAL; - - /* - * calculate magnitude of sine wave as average of rumble's - * 2/3 of strong magnitude and 1/3 of weak magnitude - */ - magnitude = effect->u.rumble.strong_magnitude / 3 + - effect->u.rumble.weak_magnitude / 6; - - effect->type = FF_PERIODIC; - effect->u.periodic.waveform = FF_SINE; - effect->u.periodic.period = 50; - effect->u.periodic.magnitude = max(magnitude, 0x7fff); - effect->u.periodic.offset = 0; - effect->u.periodic.phase = 0; - effect->u.periodic.envelope.attack_length = 0; - effect->u.periodic.envelope.attack_level = 0; - effect->u.periodic.envelope.fade_length = 0; - effect->u.periodic.envelope.fade_level = 0; - - return 0; - - default: - /* Let driver handle conversion */ - return 0; - } -} - -/** - * input_ff_upload() - upload effect into force-feedback device - * @dev: input device - * @effect: effect to be uploaded - * @file: owner of the effect - */ -int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, - struct file *file) -{ - struct ff_device *ff = dev->ff; - struct ff_effect *old; - int ret = 0; - int id; - - if (!test_bit(EV_FF, dev->evbit)) - return -ENOSYS; - - if (effect->type < FF_EFFECT_MIN || effect->type > FF_EFFECT_MAX || - !test_bit(effect->type, dev->ffbit)) { - dev_dbg(&dev->dev, "invalid or not supported effect type in upload\n"); - return -EINVAL; - } - - if (effect->type == FF_PERIODIC && - (effect->u.periodic.waveform < FF_WAVEFORM_MIN || - effect->u.periodic.waveform > FF_WAVEFORM_MAX || - !test_bit(effect->u.periodic.waveform, dev->ffbit))) { - dev_dbg(&dev->dev, "invalid or not supported wave form in upload\n"); - return -EINVAL; - } - - if (!test_bit(effect->type, ff->ffbit)) { - ret = compat_effect(ff, effect); - if (ret) - return ret; - } - - mutex_lock(&ff->mutex); - - if (effect->id == -1) { - for (id = 0; id < ff->max_effects; id++) - if (!ff->effect_owners[id]) - break; - - if (id >= ff->max_effects) { - ret = -ENOSPC; - goto out; - } - - effect->id = id; - old = NULL; - - } else { - id = effect->id; - - ret = check_effect_access(ff, id, file); - if (ret) - goto out; - - old = &ff->effects[id]; - - if (!check_effects_compatible(effect, old)) { - ret = -EINVAL; - goto out; - } - } - - ret = ff->upload(dev, effect, old); - if (ret) - goto out; - - spin_lock_irq(&dev->event_lock); - ff->effects[id] = *effect; - ff->effect_owners[id] = file; - spin_unlock_irq(&dev->event_lock); - - out: - mutex_unlock(&ff->mutex); - return ret; -} -EXPORT_SYMBOL_GPL(input_ff_upload); - -/* - * Erases the effect if the requester is also the effect owner. The mutex - * should already be locked before calling this function. - */ -static int erase_effect(struct input_dev *dev, int effect_id, - struct file *file) -{ - struct ff_device *ff = dev->ff; - int error; - - error = check_effect_access(ff, effect_id, file); - if (error) - return error; - - spin_lock_irq(&dev->event_lock); - ff->playback(dev, effect_id, 0); - ff->effect_owners[effect_id] = NULL; - spin_unlock_irq(&dev->event_lock); - - if (ff->erase) { - error = ff->erase(dev, effect_id); - if (error) { - spin_lock_irq(&dev->event_lock); - ff->effect_owners[effect_id] = file; - spin_unlock_irq(&dev->event_lock); - - return error; - } - } - - return 0; -} - -/** - * input_ff_erase - erase a force-feedback effect from device - * @dev: input device to erase effect from - * @effect_id: id of the effect to be erased - * @file: purported owner of the request - * - * This function erases a force-feedback effect from specified device. - * The effect will only be erased if it was uploaded through the same - * file handle that is requesting erase. - */ -int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file) -{ - struct ff_device *ff = dev->ff; - int ret; - - if (!test_bit(EV_FF, dev->evbit)) - return -ENOSYS; - - mutex_lock(&ff->mutex); - ret = erase_effect(dev, effect_id, file); - mutex_unlock(&ff->mutex); - - return ret; -} -EXPORT_SYMBOL_GPL(input_ff_erase); - -/* - * flush_effects - erase all effects owned by a file handle - */ -static int flush_effects(struct input_dev *dev, struct file *file) -{ - struct ff_device *ff = dev->ff; - int i; - - dev_dbg(&dev->dev, "flushing now\n"); - - mutex_lock(&ff->mutex); - - for (i = 0; i < ff->max_effects; i++) - erase_effect(dev, i, file); - - mutex_unlock(&ff->mutex); - - return 0; -} - -/** - * input_ff_event() - generic handler for force-feedback events - * @dev: input device to send the effect to - * @type: event type (anything but EV_FF is ignored) - * @code: event code - * @value: event value - */ -int input_ff_event(struct input_dev *dev, unsigned int type, - unsigned int code, int value) -{ - struct ff_device *ff = dev->ff; - - if (type != EV_FF) - return 0; - - switch (code) { - case FF_GAIN: - if (!test_bit(FF_GAIN, dev->ffbit) || value > 0xffffU) - break; - - ff->set_gain(dev, value); - break; - - case FF_AUTOCENTER: - if (!test_bit(FF_AUTOCENTER, dev->ffbit) || value > 0xffffU) - break; - - ff->set_autocenter(dev, value); - break; - - default: - if (check_effect_access(ff, code, NULL) == 0) - ff->playback(dev, code, value); - break; - } - - return 0; -} -EXPORT_SYMBOL_GPL(input_ff_event); - -/** - * input_ff_create() - create force-feedback device - * @dev: input device supporting force-feedback - * @max_effects: maximum number of effects supported by the device - * - * This function allocates all necessary memory for a force feedback - * portion of an input device and installs all default handlers. - * @dev->ffbit should be already set up before calling this function. - * Once ff device is created you need to setup its upload, erase, - * playback and other handlers before registering input device - */ -int input_ff_create(struct input_dev *dev, unsigned int max_effects) -{ - struct ff_device *ff; - size_t ff_dev_size; - int i; - - if (!max_effects) { - dev_err(&dev->dev, "cannot allocate device without any effects\n"); - return -EINVAL; - } - - if (max_effects > FF_MAX_EFFECTS) { - dev_err(&dev->dev, "cannot allocate more than FF_MAX_EFFECTS effects\n"); - return -EINVAL; - } - - ff_dev_size = sizeof(struct ff_device) + - max_effects * sizeof(struct file *); - if (ff_dev_size < max_effects) /* overflow */ - return -EINVAL; - - ff = kzalloc(ff_dev_size, GFP_KERNEL); - if (!ff) - return -ENOMEM; - - ff->effects = kcalloc(max_effects, sizeof(struct ff_effect), - GFP_KERNEL); - if (!ff->effects) { - kfree(ff); - return -ENOMEM; - } - - ff->max_effects = max_effects; - mutex_init(&ff->mutex); - - dev->ff = ff; - dev->flush = flush_effects; - dev->event = input_ff_event; - __set_bit(EV_FF, dev->evbit); - - /* Copy "true" bits into ff device bitmap */ - for_each_set_bit(i, dev->ffbit, FF_CNT) - __set_bit(i, ff->ffbit); - - /* we can emulate RUMBLE with periodic effects */ - if (test_bit(FF_PERIODIC, ff->ffbit)) - __set_bit(FF_RUMBLE, dev->ffbit); - - return 0; -} -EXPORT_SYMBOL_GPL(input_ff_create); - -/** - * input_ff_destroy() - frees force feedback portion of input device - * @dev: input device supporting force feedback - * - * This function is only needed in error path as input core will - * automatically free force feedback structures when device is - * destroyed. - */ -void input_ff_destroy(struct input_dev *dev) -{ - struct ff_device *ff = dev->ff; - - __clear_bit(EV_FF, dev->evbit); - if (ff) { - if (ff->destroy) - ff->destroy(ff); - kfree(ff->private); - kfree(ff->effects); - kfree(ff); - dev->ff = NULL; - } -} -EXPORT_SYMBOL_GPL(input_ff_destroy); diff --git a/src/linux/drivers/input/gameport/Kconfig b/src/linux/drivers/input/gameport/Kconfig deleted file mode 100644 index d279454..0000000 --- a/src/linux/drivers/input/gameport/Kconfig +++ /dev/null @@ -1,63 +0,0 @@ -# -# Gameport configuration -# -config GAMEPORT - tristate "Gameport support" - ---help--- - Gameport support is for the standard 15-pin PC gameport. If you - have a joystick, gamepad, gameport card, a soundcard with a gameport - or anything else that uses the gameport, say Y or M here and also to - at least one of the hardware specific drivers. - - For Ensoniq AudioPCI (ES1370), AudioPCI 97 (ES1371), ESS Solo1, - S3 SonicVibes, Trident 4DWave, SiS7018, and ALi 5451 gameport - support is provided by the sound drivers, so you won't need any - from the below listed modules. You still need to say Y here. - - If unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called gameport. - -if GAMEPORT - -config GAMEPORT_NS558 - tristate "Classic ISA and PnP gameport support" - help - Say Y here if you have an ISA or PnP gameport. - - If unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called ns558. - -config GAMEPORT_L4 - tristate "PDPI Lightning 4 gamecard support" - help - Say Y here if you have a PDPI Lightning 4 gamecard. - - To compile this driver as a module, choose M here: the - module will be called lightning. - -config GAMEPORT_EMU10K1 - tristate "SB Live and Audigy gameport support" - depends on PCI - help - Say Y here if you have a SoundBlaster Live! or SoundBlaster - Audigy card and want to use its gameport. - - To compile this driver as a module, choose M here: the - module will be called emu10k1-gp. - -config GAMEPORT_FM801 - tristate "ForteMedia FM801 gameport support" - depends on PCI - help - Say Y here if you have ForteMedia FM801 PCI audio controller - (Abit AU10, Genius Sound Maker, HP Workstation zx2000, - and others), and want to use its gameport. - - To compile this driver as a module, choose M here: the - module will be called fm801-gp. - -endif diff --git a/src/linux/drivers/input/input-compat.c b/src/linux/drivers/input/input-compat.c deleted file mode 100644 index d84d20b..0000000 --- a/src/linux/drivers/input/input-compat.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * 32bit compatibility wrappers for the input subsystem. - * - * Very heavily based on evdev.c - Copyright (c) 1999-2002 Vojtech Pavlik - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#include -#include -#include "input-compat.h" - -#ifdef CONFIG_COMPAT - -int input_event_from_user(const char __user *buffer, - struct input_event *event) -{ - if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) { - struct input_event_compat compat_event; - - if (copy_from_user(&compat_event, buffer, - sizeof(struct input_event_compat))) - return -EFAULT; - - event->time.tv_sec = compat_event.time.tv_sec; - event->time.tv_usec = compat_event.time.tv_usec; - event->type = compat_event.type; - event->code = compat_event.code; - event->value = compat_event.value; - - } else { - if (copy_from_user(event, buffer, sizeof(struct input_event))) - return -EFAULT; - } - - return 0; -} - -int input_event_to_user(char __user *buffer, - const struct input_event *event) -{ - if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) { - struct input_event_compat compat_event; - - compat_event.time.tv_sec = event->time.tv_sec; - compat_event.time.tv_usec = event->time.tv_usec; - compat_event.type = event->type; - compat_event.code = event->code; - compat_event.value = event->value; - - if (copy_to_user(buffer, &compat_event, - sizeof(struct input_event_compat))) - return -EFAULT; - - } else { - if (copy_to_user(buffer, event, sizeof(struct input_event))) - return -EFAULT; - } - - return 0; -} - -int input_ff_effect_from_user(const char __user *buffer, size_t size, - struct ff_effect *effect) -{ - if (in_compat_syscall()) { - struct ff_effect_compat *compat_effect; - - if (size != sizeof(struct ff_effect_compat)) - return -EINVAL; - - /* - * It so happens that the pointer which needs to be changed - * is the last field in the structure, so we can retrieve the - * whole thing and replace just the pointer. - */ - compat_effect = (struct ff_effect_compat *)effect; - - if (copy_from_user(compat_effect, buffer, - sizeof(struct ff_effect_compat))) - return -EFAULT; - - if (compat_effect->type == FF_PERIODIC && - compat_effect->u.periodic.waveform == FF_CUSTOM) - effect->u.periodic.custom_data = - compat_ptr(compat_effect->u.periodic.custom_data); - } else { - if (size != sizeof(struct ff_effect)) - return -EINVAL; - - if (copy_from_user(effect, buffer, sizeof(struct ff_effect))) - return -EFAULT; - } - - return 0; -} - -#else - -int input_event_from_user(const char __user *buffer, - struct input_event *event) -{ - if (copy_from_user(event, buffer, sizeof(struct input_event))) - return -EFAULT; - - return 0; -} - -int input_event_to_user(char __user *buffer, - const struct input_event *event) -{ - if (copy_to_user(buffer, event, sizeof(struct input_event))) - return -EFAULT; - - return 0; -} - -int input_ff_effect_from_user(const char __user *buffer, size_t size, - struct ff_effect *effect) -{ - if (size != sizeof(struct ff_effect)) - return -EINVAL; - - if (copy_from_user(effect, buffer, sizeof(struct ff_effect))) - return -EFAULT; - - return 0; -} - -#endif /* CONFIG_COMPAT */ - -EXPORT_SYMBOL_GPL(input_event_from_user); -EXPORT_SYMBOL_GPL(input_event_to_user); -EXPORT_SYMBOL_GPL(input_ff_effect_from_user); diff --git a/src/linux/drivers/input/input-compat.h b/src/linux/drivers/input/input-compat.h deleted file mode 100644 index 1563160..0000000 --- a/src/linux/drivers/input/input-compat.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef _INPUT_COMPAT_H -#define _INPUT_COMPAT_H - -/* - * 32bit compatibility wrappers for the input subsystem. - * - * Very heavily based on evdev.c - Copyright (c) 1999-2002 Vojtech Pavlik - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#include -#include -#include - -#ifdef CONFIG_COMPAT - -struct input_event_compat { - struct compat_timeval time; - __u16 type; - __u16 code; - __s32 value; -}; - -struct ff_periodic_effect_compat { - __u16 waveform; - __u16 period; - __s16 magnitude; - __s16 offset; - __u16 phase; - - struct ff_envelope envelope; - - __u32 custom_len; - compat_uptr_t custom_data; -}; - -struct ff_effect_compat { - __u16 type; - __s16 id; - __u16 direction; - struct ff_trigger trigger; - struct ff_replay replay; - - union { - struct ff_constant_effect constant; - struct ff_ramp_effect ramp; - struct ff_periodic_effect_compat periodic; - struct ff_condition_effect condition[2]; /* One for each axis */ - struct ff_rumble_effect rumble; - } u; -}; - -static inline size_t input_event_size(void) -{ - return (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) ? - sizeof(struct input_event_compat) : sizeof(struct input_event); -} - -#else - -static inline size_t input_event_size(void) -{ - return sizeof(struct input_event); -} - -#endif /* CONFIG_COMPAT */ - -int input_event_from_user(const char __user *buffer, - struct input_event *event); - -int input_event_to_user(char __user *buffer, - const struct input_event *event); - -int input_ff_effect_from_user(const char __user *buffer, size_t size, - struct ff_effect *effect); - -#endif /* _INPUT_COMPAT_H */ diff --git a/src/linux/drivers/input/input-mt.c b/src/linux/drivers/input/input-mt.c deleted file mode 100644 index a1bbec9..0000000 --- a/src/linux/drivers/input/input-mt.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Input Multitouch Library - * - * Copyright (c) 2008-2010 Henrik Rydberg - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#include -#include -#include - -#define TRKID_SGN ((TRKID_MAX + 1) >> 1) - -static void copy_abs(struct input_dev *dev, unsigned int dst, unsigned int src) -{ - if (dev->absinfo && test_bit(src, dev->absbit)) { - dev->absinfo[dst] = dev->absinfo[src]; - dev->absinfo[dst].fuzz = 0; - dev->absbit[BIT_WORD(dst)] |= BIT_MASK(dst); - } -} - -/** - * input_mt_init_slots() - initialize MT input slots - * @dev: input device supporting MT events and finger tracking - * @num_slots: number of slots used by the device - * @flags: mt tasks to handle in core - * - * This function allocates all necessary memory for MT slot handling - * in the input device, prepares the ABS_MT_SLOT and - * ABS_MT_TRACKING_ID events for use and sets up appropriate buffers. - * Depending on the flags set, it also performs pointer emulation and - * frame synchronization. - * - * May be called repeatedly. Returns -EINVAL if attempting to - * reinitialize with a different number of slots. - */ -int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots, - unsigned int flags) -{ - struct input_mt *mt = dev->mt; - int i; - - if (!num_slots) - return 0; - if (mt) - return mt->num_slots != num_slots ? -EINVAL : 0; - - mt = kzalloc(sizeof(*mt) + num_slots * sizeof(*mt->slots), GFP_KERNEL); - if (!mt) - goto err_mem; - - mt->num_slots = num_slots; - mt->flags = flags; - input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0); - input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0); - - if (flags & (INPUT_MT_POINTER | INPUT_MT_DIRECT)) { - __set_bit(EV_KEY, dev->evbit); - __set_bit(BTN_TOUCH, dev->keybit); - - copy_abs(dev, ABS_X, ABS_MT_POSITION_X); - copy_abs(dev, ABS_Y, ABS_MT_POSITION_Y); - copy_abs(dev, ABS_PRESSURE, ABS_MT_PRESSURE); - } - if (flags & INPUT_MT_POINTER) { - __set_bit(BTN_TOOL_FINGER, dev->keybit); - __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); - if (num_slots >= 3) - __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); - if (num_slots >= 4) - __set_bit(BTN_TOOL_QUADTAP, dev->keybit); - if (num_slots >= 5) - __set_bit(BTN_TOOL_QUINTTAP, dev->keybit); - __set_bit(INPUT_PROP_POINTER, dev->propbit); - } - if (flags & INPUT_MT_DIRECT) - __set_bit(INPUT_PROP_DIRECT, dev->propbit); - if (flags & INPUT_MT_SEMI_MT) - __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); - if (flags & INPUT_MT_TRACK) { - unsigned int n2 = num_slots * num_slots; - mt->red = kcalloc(n2, sizeof(*mt->red), GFP_KERNEL); - if (!mt->red) - goto err_mem; - } - - /* Mark slots as 'inactive' */ - for (i = 0; i < num_slots; i++) - input_mt_set_value(&mt->slots[i], ABS_MT_TRACKING_ID, -1); - - /* Mark slots as 'unused' */ - mt->frame = 1; - - dev->mt = mt; - return 0; -err_mem: - kfree(mt); - return -ENOMEM; -} -EXPORT_SYMBOL(input_mt_init_slots); - -/** - * input_mt_destroy_slots() - frees the MT slots of the input device - * @dev: input device with allocated MT slots - * - * This function is only needed in error path as the input core will - * automatically free the MT slots when the device is destroyed. - */ -void input_mt_destroy_slots(struct input_dev *dev) -{ - if (dev->mt) { - kfree(dev->mt->red); - kfree(dev->mt); - } - dev->mt = NULL; -} -EXPORT_SYMBOL(input_mt_destroy_slots); - -/** - * input_mt_report_slot_state() - report contact state - * @dev: input device with allocated MT slots - * @tool_type: the tool type to use in this slot - * @active: true if contact is active, false otherwise - * - * Reports a contact via ABS_MT_TRACKING_ID, and optionally - * ABS_MT_TOOL_TYPE. If active is true and the slot is currently - * inactive, or if the tool type is changed, a new tracking id is - * assigned to the slot. The tool type is only reported if the - * corresponding absbit field is set. - */ -void input_mt_report_slot_state(struct input_dev *dev, - unsigned int tool_type, bool active) -{ - struct input_mt *mt = dev->mt; - struct input_mt_slot *slot; - int id; - - if (!mt) - return; - - slot = &mt->slots[mt->slot]; - slot->frame = mt->frame; - - if (!active) { - input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); - return; - } - - id = input_mt_get_value(slot, ABS_MT_TRACKING_ID); - if (id < 0 || input_mt_get_value(slot, ABS_MT_TOOL_TYPE) != tool_type) - id = input_mt_new_trkid(mt); - - input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id); - input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type); -} -EXPORT_SYMBOL(input_mt_report_slot_state); - -/** - * input_mt_report_finger_count() - report contact count - * @dev: input device with allocated MT slots - * @count: the number of contacts - * - * Reports the contact count via BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP, - * BTN_TOOL_TRIPLETAP and BTN_TOOL_QUADTAP. - * - * The input core ensures only the KEY events already setup for - * this device will produce output. - */ -void input_mt_report_finger_count(struct input_dev *dev, int count) -{ - input_event(dev, EV_KEY, BTN_TOOL_FINGER, count == 1); - input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2); - input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == 3); - input_event(dev, EV_KEY, BTN_TOOL_QUADTAP, count == 4); - input_event(dev, EV_KEY, BTN_TOOL_QUINTTAP, count == 5); -} -EXPORT_SYMBOL(input_mt_report_finger_count); - -/** - * input_mt_report_pointer_emulation() - common pointer emulation - * @dev: input device with allocated MT slots - * @use_count: report number of active contacts as finger count - * - * Performs legacy pointer emulation via BTN_TOUCH, ABS_X, ABS_Y and - * ABS_PRESSURE. Touchpad finger count is emulated if use_count is true. - * - * The input core ensures only the KEY and ABS axes already setup for - * this device will produce output. - */ -void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) -{ - struct input_mt *mt = dev->mt; - struct input_mt_slot *oldest; - int oldid, count, i; - - if (!mt) - return; - - oldest = NULL; - oldid = mt->trkid; - count = 0; - - for (i = 0; i < mt->num_slots; ++i) { - struct input_mt_slot *ps = &mt->slots[i]; - int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID); - - if (id < 0) - continue; - if ((id - oldid) & TRKID_SGN) { - oldest = ps; - oldid = id; - } - count++; - } - - input_event(dev, EV_KEY, BTN_TOUCH, count > 0); - - if (use_count) { - if (count == 0 && - !test_bit(ABS_MT_DISTANCE, dev->absbit) && - test_bit(ABS_DISTANCE, dev->absbit) && - input_abs_get_val(dev, ABS_DISTANCE) != 0) { - /* - * Force reporting BTN_TOOL_FINGER for devices that - * only report general hover (and not per-contact - * distance) when contact is in proximity but not - * on the surface. - */ - count = 1; - } - - input_mt_report_finger_count(dev, count); - } - - if (oldest) { - int x = input_mt_get_value(oldest, ABS_MT_POSITION_X); - int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y); - - input_event(dev, EV_ABS, ABS_X, x); - input_event(dev, EV_ABS, ABS_Y, y); - - if (test_bit(ABS_MT_PRESSURE, dev->absbit)) { - int p = input_mt_get_value(oldest, ABS_MT_PRESSURE); - input_event(dev, EV_ABS, ABS_PRESSURE, p); - } - } else { - if (test_bit(ABS_MT_PRESSURE, dev->absbit)) - input_event(dev, EV_ABS, ABS_PRESSURE, 0); - } -} -EXPORT_SYMBOL(input_mt_report_pointer_emulation); - -static void __input_mt_drop_unused(struct input_dev *dev, struct input_mt *mt) -{ - int i; - - for (i = 0; i < mt->num_slots; i++) { - if (!input_mt_is_used(mt, &mt->slots[i])) { - input_mt_slot(dev, i); - input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); - } - } -} - -/** - * input_mt_drop_unused() - Inactivate slots not seen in this frame - * @dev: input device with allocated MT slots - * - * Lift all slots not seen since the last call to this function. - */ -void input_mt_drop_unused(struct input_dev *dev) -{ - struct input_mt *mt = dev->mt; - - if (mt) { - __input_mt_drop_unused(dev, mt); - mt->frame++; - } -} -EXPORT_SYMBOL(input_mt_drop_unused); - -/** - * input_mt_sync_frame() - synchronize mt frame - * @dev: input device with allocated MT slots - * - * Close the frame and prepare the internal state for a new one. - * Depending on the flags, marks unused slots as inactive and performs - * pointer emulation. - */ -void input_mt_sync_frame(struct input_dev *dev) -{ - struct input_mt *mt = dev->mt; - bool use_count = false; - - if (!mt) - return; - - if (mt->flags & INPUT_MT_DROP_UNUSED) - __input_mt_drop_unused(dev, mt); - - if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT)) - use_count = true; - - input_mt_report_pointer_emulation(dev, use_count); - - mt->frame++; -} -EXPORT_SYMBOL(input_mt_sync_frame); - -static int adjust_dual(int *begin, int step, int *end, int eq, int mu) -{ - int f, *p, s, c; - - if (begin == end) - return 0; - - f = *begin; - p = begin + step; - s = p == end ? f + 1 : *p; - - for (; p != end; p += step) - if (*p < f) - s = f, f = *p; - else if (*p < s) - s = *p; - - c = (f + s + 1) / 2; - if (c == 0 || (c > mu && (!eq || mu > 0))) - return 0; - /* Improve convergence for positive matrices by penalizing overcovers */ - if (s < 0 && mu <= 0) - c *= 2; - - for (p = begin; p != end; p += step) - *p -= c; - - return (c < s && s <= 0) || (f >= 0 && f < c); -} - -static void find_reduced_matrix(int *w, int nr, int nc, int nrc, int mu) -{ - int i, k, sum; - - for (k = 0; k < nrc; k++) { - for (i = 0; i < nr; i++) - adjust_dual(w + i, nr, w + i + nrc, nr <= nc, mu); - sum = 0; - for (i = 0; i < nrc; i += nr) - sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr, mu); - if (!sum) - break; - } -} - -static int input_mt_set_matrix(struct input_mt *mt, - const struct input_mt_pos *pos, int num_pos, - int mu) -{ - const struct input_mt_pos *p; - struct input_mt_slot *s; - int *w = mt->red; - int x, y; - - for (s = mt->slots; s != mt->slots + mt->num_slots; s++) { - if (!input_mt_is_active(s)) - continue; - x = input_mt_get_value(s, ABS_MT_POSITION_X); - y = input_mt_get_value(s, ABS_MT_POSITION_Y); - for (p = pos; p != pos + num_pos; p++) { - int dx = x - p->x, dy = y - p->y; - *w++ = dx * dx + dy * dy - mu; - } - } - - return w - mt->red; -} - -static void input_mt_set_slots(struct input_mt *mt, - int *slots, int num_pos) -{ - struct input_mt_slot *s; - int *w = mt->red, j; - - for (j = 0; j != num_pos; j++) - slots[j] = -1; - - for (s = mt->slots; s != mt->slots + mt->num_slots; s++) { - if (!input_mt_is_active(s)) - continue; - - for (j = 0; j != num_pos; j++) { - if (w[j] < 0) { - slots[j] = s - mt->slots; - break; - } - } - - w += num_pos; - } - - for (s = mt->slots; s != mt->slots + mt->num_slots; s++) { - if (input_mt_is_active(s)) - continue; - - for (j = 0; j != num_pos; j++) { - if (slots[j] < 0) { - slots[j] = s - mt->slots; - break; - } - } - } -} - -/** - * input_mt_assign_slots() - perform a best-match assignment - * @dev: input device with allocated MT slots - * @slots: the slot assignment to be filled - * @pos: the position array to match - * @num_pos: number of positions - * @dmax: maximum ABS_MT_POSITION displacement (zero for infinite) - * - * Performs a best match against the current contacts and returns - * the slot assignment list. New contacts are assigned to unused - * slots. - * - * The assignments are balanced so that all coordinate displacements are - * below the euclidian distance dmax. If no such assignment can be found, - * some contacts are assigned to unused slots. - * - * Returns zero on success, or negative error in case of failure. - */ -int input_mt_assign_slots(struct input_dev *dev, int *slots, - const struct input_mt_pos *pos, int num_pos, - int dmax) -{ - struct input_mt *mt = dev->mt; - int mu = 2 * dmax * dmax; - int nrc; - - if (!mt || !mt->red) - return -ENXIO; - if (num_pos > mt->num_slots) - return -EINVAL; - if (num_pos < 1) - return 0; - - nrc = input_mt_set_matrix(mt, pos, num_pos, mu); - find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc, mu); - input_mt_set_slots(mt, slots, num_pos); - - return 0; -} -EXPORT_SYMBOL(input_mt_assign_slots); - -/** - * input_mt_get_slot_by_key() - return slot matching key - * @dev: input device with allocated MT slots - * @key: the key of the sought slot - * - * Returns the slot of the given key, if it exists, otherwise - * set the key on the first unused slot and return. - * - * If no available slot can be found, -1 is returned. - * Note that for this function to work properly, input_mt_sync_frame() has - * to be called at each frame. - */ -int input_mt_get_slot_by_key(struct input_dev *dev, int key) -{ - struct input_mt *mt = dev->mt; - struct input_mt_slot *s; - - if (!mt) - return -1; - - for (s = mt->slots; s != mt->slots + mt->num_slots; s++) - if (input_mt_is_active(s) && s->key == key) - return s - mt->slots; - - for (s = mt->slots; s != mt->slots + mt->num_slots; s++) - if (!input_mt_is_active(s) && !input_mt_is_used(mt, s)) { - s->key = key; - return s - mt->slots; - } - - return -1; -} -EXPORT_SYMBOL(input_mt_get_slot_by_key); diff --git a/src/linux/drivers/input/input.c b/src/linux/drivers/input/input.c deleted file mode 100644 index d95c34e..0000000 --- a/src/linux/drivers/input/input.c +++ /dev/null @@ -1,2453 +0,0 @@ -/* - * The input core - * - * Copyright (c) 1999-2002 Vojtech Pavlik - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "input-compat.h" - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Input core"); -MODULE_LICENSE("GPL"); - -#define INPUT_MAX_CHAR_DEVICES 1024 -#define INPUT_FIRST_DYNAMIC_DEV 256 -static DEFINE_IDA(input_ida); - -static LIST_HEAD(input_dev_list); -static LIST_HEAD(input_handler_list); - -/* - * input_mutex protects access to both input_dev_list and input_handler_list. - * This also causes input_[un]register_device and input_[un]register_handler - * be mutually exclusive which simplifies locking in drivers implementing - * input handlers. - */ -static DEFINE_MUTEX(input_mutex); - -static const struct input_value input_value_sync = { EV_SYN, SYN_REPORT, 1 }; - -static inline int is_event_supported(unsigned int code, - unsigned long *bm, unsigned int max) -{ - return code <= max && test_bit(code, bm); -} - -static int input_defuzz_abs_event(int value, int old_val, int fuzz) -{ - if (fuzz) { - if (value > old_val - fuzz / 2 && value < old_val + fuzz / 2) - return old_val; - - if (value > old_val - fuzz && value < old_val + fuzz) - return (old_val * 3 + value) / 4; - - if (value > old_val - fuzz * 2 && value < old_val + fuzz * 2) - return (old_val + value) / 2; - } - - return value; -} - -static void input_start_autorepeat(struct input_dev *dev, int code) -{ - if (test_bit(EV_REP, dev->evbit) && - dev->rep[REP_PERIOD] && dev->rep[REP_DELAY] && - dev->timer.data) { - dev->repeat_key = code; - mod_timer(&dev->timer, - jiffies + msecs_to_jiffies(dev->rep[REP_DELAY])); - } -} - -static void input_stop_autorepeat(struct input_dev *dev) -{ - del_timer(&dev->timer); -} - -/* - * Pass event first through all filters and then, if event has not been - * filtered out, through all open handles. This function is called with - * dev->event_lock held and interrupts disabled. - */ -static unsigned int input_to_handler(struct input_handle *handle, - struct input_value *vals, unsigned int count) -{ - struct input_handler *handler = handle->handler; - struct input_value *end = vals; - struct input_value *v; - - if (handler->filter) { - for (v = vals; v != vals + count; v++) { - if (handler->filter(handle, v->type, v->code, v->value)) - continue; - if (end != v) - *end = *v; - end++; - } - count = end - vals; - } - - if (!count) - return 0; - - if (handler->events) - handler->events(handle, vals, count); - else if (handler->event) - for (v = vals; v != vals + count; v++) - handler->event(handle, v->type, v->code, v->value); - - return count; -} - -/* - * Pass values first through all filters and then, if event has not been - * filtered out, through all open handles. This function is called with - * dev->event_lock held and interrupts disabled. - */ -static void input_pass_values(struct input_dev *dev, - struct input_value *vals, unsigned int count) -{ - struct input_handle *handle; - struct input_value *v; - - if (!count) - return; - - rcu_read_lock(); - - handle = rcu_dereference(dev->grab); - if (handle) { - count = input_to_handler(handle, vals, count); - } else { - list_for_each_entry_rcu(handle, &dev->h_list, d_node) - if (handle->open) { - count = input_to_handler(handle, vals, count); - if (!count) - break; - } - } - - rcu_read_unlock(); - - /* trigger auto repeat for key events */ - if (test_bit(EV_REP, dev->evbit) && test_bit(EV_KEY, dev->evbit)) { - for (v = vals; v != vals + count; v++) { - if (v->type == EV_KEY && v->value != 2) { - if (v->value) - input_start_autorepeat(dev, v->code); - else - input_stop_autorepeat(dev); - } - } - } -} - -static void input_pass_event(struct input_dev *dev, - unsigned int type, unsigned int code, int value) -{ - struct input_value vals[] = { { type, code, value } }; - - input_pass_values(dev, vals, ARRAY_SIZE(vals)); -} - -/* - * Generate software autorepeat event. Note that we take - * dev->event_lock here to avoid racing with input_event - * which may cause keys get "stuck". - */ -static void input_repeat_key(unsigned long data) -{ - struct input_dev *dev = (void *) data; - unsigned long flags; - - spin_lock_irqsave(&dev->event_lock, flags); - - if (test_bit(dev->repeat_key, dev->key) && - is_event_supported(dev->repeat_key, dev->keybit, KEY_MAX)) { - struct input_value vals[] = { - { EV_KEY, dev->repeat_key, 2 }, - input_value_sync - }; - - input_pass_values(dev, vals, ARRAY_SIZE(vals)); - - if (dev->rep[REP_PERIOD]) - mod_timer(&dev->timer, jiffies + - msecs_to_jiffies(dev->rep[REP_PERIOD])); - } - - spin_unlock_irqrestore(&dev->event_lock, flags); -} - -#define INPUT_IGNORE_EVENT 0 -#define INPUT_PASS_TO_HANDLERS 1 -#define INPUT_PASS_TO_DEVICE 2 -#define INPUT_SLOT 4 -#define INPUT_FLUSH 8 -#define INPUT_PASS_TO_ALL (INPUT_PASS_TO_HANDLERS | INPUT_PASS_TO_DEVICE) - -static int input_handle_abs_event(struct input_dev *dev, - unsigned int code, int *pval) -{ - struct input_mt *mt = dev->mt; - bool is_mt_event; - int *pold; - - if (code == ABS_MT_SLOT) { - /* - * "Stage" the event; we'll flush it later, when we - * get actual touch data. - */ - if (mt && *pval >= 0 && *pval < mt->num_slots) - mt->slot = *pval; - - return INPUT_IGNORE_EVENT; - } - - is_mt_event = input_is_mt_value(code); - - if (!is_mt_event) { - pold = &dev->absinfo[code].value; - } else if (mt) { - pold = &mt->slots[mt->slot].abs[code - ABS_MT_FIRST]; - } else { - /* - * Bypass filtering for multi-touch events when - * not employing slots. - */ - pold = NULL; - } - - if (pold) { - *pval = input_defuzz_abs_event(*pval, *pold, - dev->absinfo[code].fuzz); - if (*pold == *pval) - return INPUT_IGNORE_EVENT; - - *pold = *pval; - } - - /* Flush pending "slot" event */ - if (is_mt_event && mt && mt->slot != input_abs_get_val(dev, ABS_MT_SLOT)) { - input_abs_set_val(dev, ABS_MT_SLOT, mt->slot); - return INPUT_PASS_TO_HANDLERS | INPUT_SLOT; - } - - return INPUT_PASS_TO_HANDLERS; -} - -static int input_get_disposition(struct input_dev *dev, - unsigned int type, unsigned int code, int *pval) -{ - int disposition = INPUT_IGNORE_EVENT; - int value = *pval; - - switch (type) { - - case EV_SYN: - switch (code) { - case SYN_CONFIG: - disposition = INPUT_PASS_TO_ALL; - break; - - case SYN_REPORT: - disposition = INPUT_PASS_TO_HANDLERS | INPUT_FLUSH; - break; - case SYN_MT_REPORT: - disposition = INPUT_PASS_TO_HANDLERS; - break; - } - break; - - case EV_KEY: - if (is_event_supported(code, dev->keybit, KEY_MAX)) { - - /* auto-repeat bypasses state updates */ - if (value == 2) { - disposition = INPUT_PASS_TO_HANDLERS; - break; - } - - if (!!test_bit(code, dev->key) != !!value) { - - __change_bit(code, dev->key); - disposition = INPUT_PASS_TO_HANDLERS; - } - } - break; - - case EV_SW: - if (is_event_supported(code, dev->swbit, SW_MAX) && - !!test_bit(code, dev->sw) != !!value) { - - __change_bit(code, dev->sw); - disposition = INPUT_PASS_TO_HANDLERS; - } - break; - - case EV_ABS: - if (is_event_supported(code, dev->absbit, ABS_MAX)) - disposition = input_handle_abs_event(dev, code, &value); - - break; - - case EV_REL: - if (is_event_supported(code, dev->relbit, REL_MAX) && value) - disposition = INPUT_PASS_TO_HANDLERS; - - break; - - case EV_MSC: - if (is_event_supported(code, dev->mscbit, MSC_MAX)) - disposition = INPUT_PASS_TO_ALL; - - break; - - case EV_LED: - if (is_event_supported(code, dev->ledbit, LED_MAX) && - !!test_bit(code, dev->led) != !!value) { - - __change_bit(code, dev->led); - disposition = INPUT_PASS_TO_ALL; - } - break; - - case EV_SND: - if (is_event_supported(code, dev->sndbit, SND_MAX)) { - - if (!!test_bit(code, dev->snd) != !!value) - __change_bit(code, dev->snd); - disposition = INPUT_PASS_TO_ALL; - } - break; - - case EV_REP: - if (code <= REP_MAX && value >= 0 && dev->rep[code] != value) { - dev->rep[code] = value; - disposition = INPUT_PASS_TO_ALL; - } - break; - - case EV_FF: - if (value >= 0) - disposition = INPUT_PASS_TO_ALL; - break; - - case EV_PWR: - disposition = INPUT_PASS_TO_ALL; - break; - } - - *pval = value; - return disposition; -} - -static void input_handle_event(struct input_dev *dev, - unsigned int type, unsigned int code, int value) -{ - int disposition = input_get_disposition(dev, type, code, &value); - - if (disposition != INPUT_IGNORE_EVENT && type != EV_SYN) - add_input_randomness(type, code, value); - - if ((disposition & INPUT_PASS_TO_DEVICE) && dev->event) - dev->event(dev, type, code, value); - - if (!dev->vals) - return; - - if (disposition & INPUT_PASS_TO_HANDLERS) { - struct input_value *v; - - if (disposition & INPUT_SLOT) { - v = &dev->vals[dev->num_vals++]; - v->type = EV_ABS; - v->code = ABS_MT_SLOT; - v->value = dev->mt->slot; - } - - v = &dev->vals[dev->num_vals++]; - v->type = type; - v->code = code; - v->value = value; - } - - if (disposition & INPUT_FLUSH) { - if (dev->num_vals >= 2) - input_pass_values(dev, dev->vals, dev->num_vals); - dev->num_vals = 0; - } else if (dev->num_vals >= dev->max_vals - 2) { - dev->vals[dev->num_vals++] = input_value_sync; - input_pass_values(dev, dev->vals, dev->num_vals); - dev->num_vals = 0; - } - -} - -/** - * input_event() - report new input event - * @dev: device that generated the event - * @type: type of the event - * @code: event code - * @value: value of the event - * - * This function should be used by drivers implementing various input - * devices to report input events. See also input_inject_event(). - * - * NOTE: input_event() may be safely used right after input device was - * allocated with input_allocate_device(), even before it is registered - * with input_register_device(), but the event will not reach any of the - * input handlers. Such early invocation of input_event() may be used - * to 'seed' initial state of a switch or initial position of absolute - * axis, etc. - */ -void input_event(struct input_dev *dev, - unsigned int type, unsigned int code, int value) -{ - unsigned long flags; - - if (is_event_supported(type, dev->evbit, EV_MAX)) { - - spin_lock_irqsave(&dev->event_lock, flags); - input_handle_event(dev, type, code, value); - spin_unlock_irqrestore(&dev->event_lock, flags); - } -} -EXPORT_SYMBOL(input_event); - -/** - * input_inject_event() - send input event from input handler - * @handle: input handle to send event through - * @type: type of the event - * @code: event code - * @value: value of the event - * - * Similar to input_event() but will ignore event if device is - * "grabbed" and handle injecting event is not the one that owns - * the device. - */ -void input_inject_event(struct input_handle *handle, - unsigned int type, unsigned int code, int value) -{ - struct input_dev *dev = handle->dev; - struct input_handle *grab; - unsigned long flags; - - if (is_event_supported(type, dev->evbit, EV_MAX)) { - spin_lock_irqsave(&dev->event_lock, flags); - - rcu_read_lock(); - grab = rcu_dereference(dev->grab); - if (!grab || grab == handle) - input_handle_event(dev, type, code, value); - rcu_read_unlock(); - - spin_unlock_irqrestore(&dev->event_lock, flags); - } -} -EXPORT_SYMBOL(input_inject_event); - -/** - * input_alloc_absinfo - allocates array of input_absinfo structs - * @dev: the input device emitting absolute events - * - * If the absinfo struct the caller asked for is already allocated, this - * functions will not do anything. - */ -void input_alloc_absinfo(struct input_dev *dev) -{ - if (!dev->absinfo) - dev->absinfo = kcalloc(ABS_CNT, sizeof(struct input_absinfo), - GFP_KERNEL); - - WARN(!dev->absinfo, "%s(): kcalloc() failed?\n", __func__); -} -EXPORT_SYMBOL(input_alloc_absinfo); - -void input_set_abs_params(struct input_dev *dev, unsigned int axis, - int min, int max, int fuzz, int flat) -{ - struct input_absinfo *absinfo; - - input_alloc_absinfo(dev); - if (!dev->absinfo) - return; - - absinfo = &dev->absinfo[axis]; - absinfo->minimum = min; - absinfo->maximum = max; - absinfo->fuzz = fuzz; - absinfo->flat = flat; - - __set_bit(EV_ABS, dev->evbit); - __set_bit(axis, dev->absbit); -} -EXPORT_SYMBOL(input_set_abs_params); - - -/** - * input_grab_device - grabs device for exclusive use - * @handle: input handle that wants to own the device - * - * When a device is grabbed by an input handle all events generated by - * the device are delivered only to this handle. Also events injected - * by other input handles are ignored while device is grabbed. - */ -int input_grab_device(struct input_handle *handle) -{ - struct input_dev *dev = handle->dev; - int retval; - - retval = mutex_lock_interruptible(&dev->mutex); - if (retval) - return retval; - - if (dev->grab) { - retval = -EBUSY; - goto out; - } - - rcu_assign_pointer(dev->grab, handle); - - out: - mutex_unlock(&dev->mutex); - return retval; -} -EXPORT_SYMBOL(input_grab_device); - -static void __input_release_device(struct input_handle *handle) -{ - struct input_dev *dev = handle->dev; - struct input_handle *grabber; - - grabber = rcu_dereference_protected(dev->grab, - lockdep_is_held(&dev->mutex)); - if (grabber == handle) { - rcu_assign_pointer(dev->grab, NULL); - /* Make sure input_pass_event() notices that grab is gone */ - synchronize_rcu(); - - list_for_each_entry(handle, &dev->h_list, d_node) - if (handle->open && handle->handler->start) - handle->handler->start(handle); - } -} - -/** - * input_release_device - release previously grabbed device - * @handle: input handle that owns the device - * - * Releases previously grabbed device so that other input handles can - * start receiving input events. Upon release all handlers attached - * to the device have their start() method called so they have a change - * to synchronize device state with the rest of the system. - */ -void input_release_device(struct input_handle *handle) -{ - struct input_dev *dev = handle->dev; - - mutex_lock(&dev->mutex); - __input_release_device(handle); - mutex_unlock(&dev->mutex); -} -EXPORT_SYMBOL(input_release_device); - -/** - * input_open_device - open input device - * @handle: handle through which device is being accessed - * - * This function should be called by input handlers when they - * want to start receive events from given input device. - */ -int input_open_device(struct input_handle *handle) -{ - struct input_dev *dev = handle->dev; - int retval; - - retval = mutex_lock_interruptible(&dev->mutex); - if (retval) - return retval; - - if (dev->going_away) { - retval = -ENODEV; - goto out; - } - - handle->open++; - - if (!dev->users++ && dev->open) - retval = dev->open(dev); - - if (retval) { - dev->users--; - if (!--handle->open) { - /* - * Make sure we are not delivering any more events - * through this handle - */ - synchronize_rcu(); - } - } - - out: - mutex_unlock(&dev->mutex); - return retval; -} -EXPORT_SYMBOL(input_open_device); - -int input_flush_device(struct input_handle *handle, struct file *file) -{ - struct input_dev *dev = handle->dev; - int retval; - - retval = mutex_lock_interruptible(&dev->mutex); - if (retval) - return retval; - - if (dev->flush) - retval = dev->flush(dev, file); - - mutex_unlock(&dev->mutex); - return retval; -} -EXPORT_SYMBOL(input_flush_device); - -/** - * input_close_device - close input device - * @handle: handle through which device is being accessed - * - * This function should be called by input handlers when they - * want to stop receive events from given input device. - */ -void input_close_device(struct input_handle *handle) -{ - struct input_dev *dev = handle->dev; - - mutex_lock(&dev->mutex); - - __input_release_device(handle); - - if (!--dev->users && dev->close) - dev->close(dev); - - if (!--handle->open) { - /* - * synchronize_rcu() makes sure that input_pass_event() - * completed and that no more input events are delivered - * through this handle - */ - synchronize_rcu(); - } - - mutex_unlock(&dev->mutex); -} -EXPORT_SYMBOL(input_close_device); - -/* - * Simulate keyup events for all keys that are marked as pressed. - * The function must be called with dev->event_lock held. - */ -static void input_dev_release_keys(struct input_dev *dev) -{ - bool need_sync = false; - int code; - - if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) { - for_each_set_bit(code, dev->key, KEY_CNT) { - input_pass_event(dev, EV_KEY, code, 0); - need_sync = true; - } - - if (need_sync) - input_pass_event(dev, EV_SYN, SYN_REPORT, 1); - - memset(dev->key, 0, sizeof(dev->key)); - } -} - -/* - * Prepare device for unregistering - */ -static void input_disconnect_device(struct input_dev *dev) -{ - struct input_handle *handle; - - /* - * Mark device as going away. Note that we take dev->mutex here - * not to protect access to dev->going_away but rather to ensure - * that there are no threads in the middle of input_open_device() - */ - mutex_lock(&dev->mutex); - dev->going_away = true; - mutex_unlock(&dev->mutex); - - spin_lock_irq(&dev->event_lock); - - /* - * Simulate keyup events for all pressed keys so that handlers - * are not left with "stuck" keys. The driver may continue - * generate events even after we done here but they will not - * reach any handlers. - */ - input_dev_release_keys(dev); - - list_for_each_entry(handle, &dev->h_list, d_node) - handle->open = 0; - - spin_unlock_irq(&dev->event_lock); -} - -/** - * input_scancode_to_scalar() - converts scancode in &struct input_keymap_entry - * @ke: keymap entry containing scancode to be converted. - * @scancode: pointer to the location where converted scancode should - * be stored. - * - * This function is used to convert scancode stored in &struct keymap_entry - * into scalar form understood by legacy keymap handling methods. These - * methods expect scancodes to be represented as 'unsigned int'. - */ -int input_scancode_to_scalar(const struct input_keymap_entry *ke, - unsigned int *scancode) -{ - switch (ke->len) { - case 1: - *scancode = *((u8 *)ke->scancode); - break; - - case 2: - *scancode = *((u16 *)ke->scancode); - break; - - case 4: - *scancode = *((u32 *)ke->scancode); - break; - - default: - return -EINVAL; - } - - return 0; -} -EXPORT_SYMBOL(input_scancode_to_scalar); - -/* - * Those routines handle the default case where no [gs]etkeycode() is - * defined. In this case, an array indexed by the scancode is used. - */ - -static unsigned int input_fetch_keycode(struct input_dev *dev, - unsigned int index) -{ - switch (dev->keycodesize) { - case 1: - return ((u8 *)dev->keycode)[index]; - - case 2: - return ((u16 *)dev->keycode)[index]; - - default: - return ((u32 *)dev->keycode)[index]; - } -} - -static int input_default_getkeycode(struct input_dev *dev, - struct input_keymap_entry *ke) -{ - unsigned int index; - int error; - - if (!dev->keycodesize) - return -EINVAL; - - if (ke->flags & INPUT_KEYMAP_BY_INDEX) - index = ke->index; - else { - error = input_scancode_to_scalar(ke, &index); - if (error) - return error; - } - - if (index >= dev->keycodemax) - return -EINVAL; - - ke->keycode = input_fetch_keycode(dev, index); - ke->index = index; - ke->len = sizeof(index); - memcpy(ke->scancode, &index, sizeof(index)); - - return 0; -} - -static int input_default_setkeycode(struct input_dev *dev, - const struct input_keymap_entry *ke, - unsigned int *old_keycode) -{ - unsigned int index; - int error; - int i; - - if (!dev->keycodesize) - return -EINVAL; - - if (ke->flags & INPUT_KEYMAP_BY_INDEX) { - index = ke->index; - } else { - error = input_scancode_to_scalar(ke, &index); - if (error) - return error; - } - - if (index >= dev->keycodemax) - return -EINVAL; - - if (dev->keycodesize < sizeof(ke->keycode) && - (ke->keycode >> (dev->keycodesize * 8))) - return -EINVAL; - - switch (dev->keycodesize) { - case 1: { - u8 *k = (u8 *)dev->keycode; - *old_keycode = k[index]; - k[index] = ke->keycode; - break; - } - case 2: { - u16 *k = (u16 *)dev->keycode; - *old_keycode = k[index]; - k[index] = ke->keycode; - break; - } - default: { - u32 *k = (u32 *)dev->keycode; - *old_keycode = k[index]; - k[index] = ke->keycode; - break; - } - } - - __clear_bit(*old_keycode, dev->keybit); - __set_bit(ke->keycode, dev->keybit); - - for (i = 0; i < dev->keycodemax; i++) { - if (input_fetch_keycode(dev, i) == *old_keycode) { - __set_bit(*old_keycode, dev->keybit); - break; /* Setting the bit twice is useless, so break */ - } - } - - return 0; -} - -/** - * input_get_keycode - retrieve keycode currently mapped to a given scancode - * @dev: input device which keymap is being queried - * @ke: keymap entry - * - * This function should be called by anyone interested in retrieving current - * keymap. Presently evdev handlers use it. - */ -int input_get_keycode(struct input_dev *dev, struct input_keymap_entry *ke) -{ - unsigned long flags; - int retval; - - spin_lock_irqsave(&dev->event_lock, flags); - retval = dev->getkeycode(dev, ke); - spin_unlock_irqrestore(&dev->event_lock, flags); - - return retval; -} -EXPORT_SYMBOL(input_get_keycode); - -/** - * input_set_keycode - attribute a keycode to a given scancode - * @dev: input device which keymap is being updated - * @ke: new keymap entry - * - * This function should be called by anyone needing to update current - * keymap. Presently keyboard and evdev handlers use it. - */ -int input_set_keycode(struct input_dev *dev, - const struct input_keymap_entry *ke) -{ - unsigned long flags; - unsigned int old_keycode; - int retval; - - if (ke->keycode > KEY_MAX) - return -EINVAL; - - spin_lock_irqsave(&dev->event_lock, flags); - - retval = dev->setkeycode(dev, ke, &old_keycode); - if (retval) - goto out; - - /* Make sure KEY_RESERVED did not get enabled. */ - __clear_bit(KEY_RESERVED, dev->keybit); - - /* - * Simulate keyup event if keycode is not present - * in the keymap anymore - */ - if (test_bit(EV_KEY, dev->evbit) && - !is_event_supported(old_keycode, dev->keybit, KEY_MAX) && - __test_and_clear_bit(old_keycode, dev->key)) { - struct input_value vals[] = { - { EV_KEY, old_keycode, 0 }, - input_value_sync - }; - - input_pass_values(dev, vals, ARRAY_SIZE(vals)); - } - - out: - spin_unlock_irqrestore(&dev->event_lock, flags); - - return retval; -} -EXPORT_SYMBOL(input_set_keycode); - -static const struct input_device_id *input_match_device(struct input_handler *handler, - struct input_dev *dev) -{ - const struct input_device_id *id; - - for (id = handler->id_table; id->flags || id->driver_info; id++) { - - if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) - if (id->bustype != dev->id.bustype) - continue; - - if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR) - if (id->vendor != dev->id.vendor) - continue; - - if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT) - if (id->product != dev->id.product) - continue; - - if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION) - if (id->version != dev->id.version) - continue; - - if (!bitmap_subset(id->evbit, dev->evbit, EV_MAX)) - continue; - - if (!bitmap_subset(id->keybit, dev->keybit, KEY_MAX)) - continue; - - if (!bitmap_subset(id->relbit, dev->relbit, REL_MAX)) - continue; - - if (!bitmap_subset(id->absbit, dev->absbit, ABS_MAX)) - continue; - - if (!bitmap_subset(id->mscbit, dev->mscbit, MSC_MAX)) - continue; - - if (!bitmap_subset(id->ledbit, dev->ledbit, LED_MAX)) - continue; - - if (!bitmap_subset(id->sndbit, dev->sndbit, SND_MAX)) - continue; - - if (!bitmap_subset(id->ffbit, dev->ffbit, FF_MAX)) - continue; - - if (!bitmap_subset(id->swbit, dev->swbit, SW_MAX)) - continue; - - if (!handler->match || handler->match(handler, dev)) - return id; - } - - return NULL; -} - -static int input_attach_handler(struct input_dev *dev, struct input_handler *handler) -{ - const struct input_device_id *id; - int error; - - id = input_match_device(handler, dev); - if (!id) - return -ENODEV; - - error = handler->connect(handler, dev, id); - if (error && error != -ENODEV) - pr_err("failed to attach handler %s to device %s, error: %d\n", - handler->name, kobject_name(&dev->dev.kobj), error); - - return error; -} - -#ifdef CONFIG_COMPAT - -static int input_bits_to_string(char *buf, int buf_size, - unsigned long bits, bool skip_empty) -{ - int len = 0; - - if (in_compat_syscall()) { - u32 dword = bits >> 32; - if (dword || !skip_empty) - len += snprintf(buf, buf_size, "%x ", dword); - - dword = bits & 0xffffffffUL; - if (dword || !skip_empty || len) - len += snprintf(buf + len, max(buf_size - len, 0), - "%x", dword); - } else { - if (bits || !skip_empty) - len += snprintf(buf, buf_size, "%lx", bits); - } - - return len; -} - -#else /* !CONFIG_COMPAT */ - -static int input_bits_to_string(char *buf, int buf_size, - unsigned long bits, bool skip_empty) -{ - return bits || !skip_empty ? - snprintf(buf, buf_size, "%lx", bits) : 0; -} - -#endif - -#ifdef CONFIG_PROC_FS - -static struct proc_dir_entry *proc_bus_input_dir; -static DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait); -static int input_devices_state; - -static inline void input_wakeup_procfs_readers(void) -{ - input_devices_state++; - wake_up(&input_devices_poll_wait); -} - -static unsigned int input_proc_devices_poll(struct file *file, poll_table *wait) -{ - poll_wait(file, &input_devices_poll_wait, wait); - if (file->f_version != input_devices_state) { - file->f_version = input_devices_state; - return POLLIN | POLLRDNORM; - } - - return 0; -} - -union input_seq_state { - struct { - unsigned short pos; - bool mutex_acquired; - }; - void *p; -}; - -static void *input_devices_seq_start(struct seq_file *seq, loff_t *pos) -{ - union input_seq_state *state = (union input_seq_state *)&seq->private; - int error; - - /* We need to fit into seq->private pointer */ - BUILD_BUG_ON(sizeof(union input_seq_state) != sizeof(seq->private)); - - error = mutex_lock_interruptible(&input_mutex); - if (error) { - state->mutex_acquired = false; - return ERR_PTR(error); - } - - state->mutex_acquired = true; - - return seq_list_start(&input_dev_list, *pos); -} - -static void *input_devices_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return seq_list_next(v, &input_dev_list, pos); -} - -static void input_seq_stop(struct seq_file *seq, void *v) -{ - union input_seq_state *state = (union input_seq_state *)&seq->private; - - if (state->mutex_acquired) - mutex_unlock(&input_mutex); -} - -static void input_seq_print_bitmap(struct seq_file *seq, const char *name, - unsigned long *bitmap, int max) -{ - int i; - bool skip_empty = true; - char buf[18]; - - seq_printf(seq, "B: %s=", name); - - for (i = BITS_TO_LONGS(max) - 1; i >= 0; i--) { - if (input_bits_to_string(buf, sizeof(buf), - bitmap[i], skip_empty)) { - skip_empty = false; - seq_printf(seq, "%s%s", buf, i > 0 ? " " : ""); - } - } - - /* - * If no output was produced print a single 0. - */ - if (skip_empty) - seq_puts(seq, "0"); - - seq_putc(seq, '\n'); -} - -static int input_devices_seq_show(struct seq_file *seq, void *v) -{ - struct input_dev *dev = container_of(v, struct input_dev, node); - const char *path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); - struct input_handle *handle; - - seq_printf(seq, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n", - dev->id.bustype, dev->id.vendor, dev->id.product, dev->id.version); - - seq_printf(seq, "N: Name=\"%s\"\n", dev->name ? dev->name : ""); - seq_printf(seq, "P: Phys=%s\n", dev->phys ? dev->phys : ""); - seq_printf(seq, "S: Sysfs=%s\n", path ? path : ""); - seq_printf(seq, "U: Uniq=%s\n", dev->uniq ? dev->uniq : ""); - seq_printf(seq, "H: Handlers="); - - list_for_each_entry(handle, &dev->h_list, d_node) - seq_printf(seq, "%s ", handle->name); - seq_putc(seq, '\n'); - - input_seq_print_bitmap(seq, "PROP", dev->propbit, INPUT_PROP_MAX); - - input_seq_print_bitmap(seq, "EV", dev->evbit, EV_MAX); - if (test_bit(EV_KEY, dev->evbit)) - input_seq_print_bitmap(seq, "KEY", dev->keybit, KEY_MAX); - if (test_bit(EV_REL, dev->evbit)) - input_seq_print_bitmap(seq, "REL", dev->relbit, REL_MAX); - if (test_bit(EV_ABS, dev->evbit)) - input_seq_print_bitmap(seq, "ABS", dev->absbit, ABS_MAX); - if (test_bit(EV_MSC, dev->evbit)) - input_seq_print_bitmap(seq, "MSC", dev->mscbit, MSC_MAX); - if (test_bit(EV_LED, dev->evbit)) - input_seq_print_bitmap(seq, "LED", dev->ledbit, LED_MAX); - if (test_bit(EV_SND, dev->evbit)) - input_seq_print_bitmap(seq, "SND", dev->sndbit, SND_MAX); - if (test_bit(EV_FF, dev->evbit)) - input_seq_print_bitmap(seq, "FF", dev->ffbit, FF_MAX); - if (test_bit(EV_SW, dev->evbit)) - input_seq_print_bitmap(seq, "SW", dev->swbit, SW_MAX); - - seq_putc(seq, '\n'); - - kfree(path); - return 0; -} - -static const struct seq_operations input_devices_seq_ops = { - .start = input_devices_seq_start, - .next = input_devices_seq_next, - .stop = input_seq_stop, - .show = input_devices_seq_show, -}; - -static int input_proc_devices_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &input_devices_seq_ops); -} - -static const struct file_operations input_devices_fileops = { - .owner = THIS_MODULE, - .open = input_proc_devices_open, - .poll = input_proc_devices_poll, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static void *input_handlers_seq_start(struct seq_file *seq, loff_t *pos) -{ - union input_seq_state *state = (union input_seq_state *)&seq->private; - int error; - - /* We need to fit into seq->private pointer */ - BUILD_BUG_ON(sizeof(union input_seq_state) != sizeof(seq->private)); - - error = mutex_lock_interruptible(&input_mutex); - if (error) { - state->mutex_acquired = false; - return ERR_PTR(error); - } - - state->mutex_acquired = true; - state->pos = *pos; - - return seq_list_start(&input_handler_list, *pos); -} - -static void *input_handlers_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - union input_seq_state *state = (union input_seq_state *)&seq->private; - - state->pos = *pos + 1; - return seq_list_next(v, &input_handler_list, pos); -} - -static int input_handlers_seq_show(struct seq_file *seq, void *v) -{ - struct input_handler *handler = container_of(v, struct input_handler, node); - union input_seq_state *state = (union input_seq_state *)&seq->private; - - seq_printf(seq, "N: Number=%u Name=%s", state->pos, handler->name); - if (handler->filter) - seq_puts(seq, " (filter)"); - if (handler->legacy_minors) - seq_printf(seq, " Minor=%d", handler->minor); - seq_putc(seq, '\n'); - - return 0; -} - -static const struct seq_operations input_handlers_seq_ops = { - .start = input_handlers_seq_start, - .next = input_handlers_seq_next, - .stop = input_seq_stop, - .show = input_handlers_seq_show, -}; - -static int input_proc_handlers_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &input_handlers_seq_ops); -} - -static const struct file_operations input_handlers_fileops = { - .owner = THIS_MODULE, - .open = input_proc_handlers_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int __init input_proc_init(void) -{ - struct proc_dir_entry *entry; - - proc_bus_input_dir = proc_mkdir("bus/input", NULL); - if (!proc_bus_input_dir) - return -ENOMEM; - - entry = proc_create("devices", 0, proc_bus_input_dir, - &input_devices_fileops); - if (!entry) - goto fail1; - - entry = proc_create("handlers", 0, proc_bus_input_dir, - &input_handlers_fileops); - if (!entry) - goto fail2; - - return 0; - - fail2: remove_proc_entry("devices", proc_bus_input_dir); - fail1: remove_proc_entry("bus/input", NULL); - return -ENOMEM; -} - -static void input_proc_exit(void) -{ - remove_proc_entry("devices", proc_bus_input_dir); - remove_proc_entry("handlers", proc_bus_input_dir); - remove_proc_entry("bus/input", NULL); -} - -#else /* !CONFIG_PROC_FS */ -static inline void input_wakeup_procfs_readers(void) { } -static inline int input_proc_init(void) { return 0; } -static inline void input_proc_exit(void) { } -#endif - -#define INPUT_DEV_STRING_ATTR_SHOW(name) \ -static ssize_t input_dev_show_##name(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct input_dev *input_dev = to_input_dev(dev); \ - \ - return scnprintf(buf, PAGE_SIZE, "%s\n", \ - input_dev->name ? input_dev->name : ""); \ -} \ -static DEVICE_ATTR(name, S_IRUGO, input_dev_show_##name, NULL) - -INPUT_DEV_STRING_ATTR_SHOW(name); -INPUT_DEV_STRING_ATTR_SHOW(phys); -INPUT_DEV_STRING_ATTR_SHOW(uniq); - -static int input_print_modalias_bits(char *buf, int size, - char name, unsigned long *bm, - unsigned int min_bit, unsigned int max_bit) -{ - int len = 0, i; - - len += snprintf(buf, max(size, 0), "%c", name); - for (i = min_bit; i < max_bit; i++) - if (bm[BIT_WORD(i)] & BIT_MASK(i)) - len += snprintf(buf + len, max(size - len, 0), "%X,", i); - return len; -} - -static int input_print_modalias(char *buf, int size, struct input_dev *id, - int add_cr) -{ - int len; - - len = snprintf(buf, max(size, 0), - "input:b%04Xv%04Xp%04Xe%04X-", - id->id.bustype, id->id.vendor, - id->id.product, id->id.version); - - len += input_print_modalias_bits(buf + len, size - len, - 'e', id->evbit, 0, EV_MAX); - len += input_print_modalias_bits(buf + len, size - len, - 'k', id->keybit, KEY_MIN_INTERESTING, KEY_MAX); - len += input_print_modalias_bits(buf + len, size - len, - 'r', id->relbit, 0, REL_MAX); - len += input_print_modalias_bits(buf + len, size - len, - 'a', id->absbit, 0, ABS_MAX); - len += input_print_modalias_bits(buf + len, size - len, - 'm', id->mscbit, 0, MSC_MAX); - len += input_print_modalias_bits(buf + len, size - len, - 'l', id->ledbit, 0, LED_MAX); - len += input_print_modalias_bits(buf + len, size - len, - 's', id->sndbit, 0, SND_MAX); - len += input_print_modalias_bits(buf + len, size - len, - 'f', id->ffbit, 0, FF_MAX); - len += input_print_modalias_bits(buf + len, size - len, - 'w', id->swbit, 0, SW_MAX); - - if (add_cr) - len += snprintf(buf + len, max(size - len, 0), "\n"); - - return len; -} - -static ssize_t input_dev_show_modalias(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct input_dev *id = to_input_dev(dev); - ssize_t len; - - len = input_print_modalias(buf, PAGE_SIZE, id, 1); - - return min_t(int, len, PAGE_SIZE); -} -static DEVICE_ATTR(modalias, S_IRUGO, input_dev_show_modalias, NULL); - -static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap, - int max, int add_cr); - -static ssize_t input_dev_show_properties(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct input_dev *input_dev = to_input_dev(dev); - int len = input_print_bitmap(buf, PAGE_SIZE, input_dev->propbit, - INPUT_PROP_MAX, true); - return min_t(int, len, PAGE_SIZE); -} -static DEVICE_ATTR(properties, S_IRUGO, input_dev_show_properties, NULL); - -static struct attribute *input_dev_attrs[] = { - &dev_attr_name.attr, - &dev_attr_phys.attr, - &dev_attr_uniq.attr, - &dev_attr_modalias.attr, - &dev_attr_properties.attr, - NULL -}; - -static struct attribute_group input_dev_attr_group = { - .attrs = input_dev_attrs, -}; - -#define INPUT_DEV_ID_ATTR(name) \ -static ssize_t input_dev_show_id_##name(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct input_dev *input_dev = to_input_dev(dev); \ - return scnprintf(buf, PAGE_SIZE, "%04x\n", input_dev->id.name); \ -} \ -static DEVICE_ATTR(name, S_IRUGO, input_dev_show_id_##name, NULL) - -INPUT_DEV_ID_ATTR(bustype); -INPUT_DEV_ID_ATTR(vendor); -INPUT_DEV_ID_ATTR(product); -INPUT_DEV_ID_ATTR(version); - -static struct attribute *input_dev_id_attrs[] = { - &dev_attr_bustype.attr, - &dev_attr_vendor.attr, - &dev_attr_product.attr, - &dev_attr_version.attr, - NULL -}; - -static struct attribute_group input_dev_id_attr_group = { - .name = "id", - .attrs = input_dev_id_attrs, -}; - -static int input_print_bitmap(char *buf, int buf_size, unsigned long *bitmap, - int max, int add_cr) -{ - int i; - int len = 0; - bool skip_empty = true; - - for (i = BITS_TO_LONGS(max) - 1; i >= 0; i--) { - len += input_bits_to_string(buf + len, max(buf_size - len, 0), - bitmap[i], skip_empty); - if (len) { - skip_empty = false; - if (i > 0) - len += snprintf(buf + len, max(buf_size - len, 0), " "); - } - } - - /* - * If no output was produced print a single 0. - */ - if (len == 0) - len = snprintf(buf, buf_size, "%d", 0); - - if (add_cr) - len += snprintf(buf + len, max(buf_size - len, 0), "\n"); - - return len; -} - -#define INPUT_DEV_CAP_ATTR(ev, bm) \ -static ssize_t input_dev_show_cap_##bm(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct input_dev *input_dev = to_input_dev(dev); \ - int len = input_print_bitmap(buf, PAGE_SIZE, \ - input_dev->bm##bit, ev##_MAX, \ - true); \ - return min_t(int, len, PAGE_SIZE); \ -} \ -static DEVICE_ATTR(bm, S_IRUGO, input_dev_show_cap_##bm, NULL) - -INPUT_DEV_CAP_ATTR(EV, ev); -INPUT_DEV_CAP_ATTR(KEY, key); -INPUT_DEV_CAP_ATTR(REL, rel); -INPUT_DEV_CAP_ATTR(ABS, abs); -INPUT_DEV_CAP_ATTR(MSC, msc); -INPUT_DEV_CAP_ATTR(LED, led); -INPUT_DEV_CAP_ATTR(SND, snd); -INPUT_DEV_CAP_ATTR(FF, ff); -INPUT_DEV_CAP_ATTR(SW, sw); - -static struct attribute *input_dev_caps_attrs[] = { - &dev_attr_ev.attr, - &dev_attr_key.attr, - &dev_attr_rel.attr, - &dev_attr_abs.attr, - &dev_attr_msc.attr, - &dev_attr_led.attr, - &dev_attr_snd.attr, - &dev_attr_ff.attr, - &dev_attr_sw.attr, - NULL -}; - -static struct attribute_group input_dev_caps_attr_group = { - .name = "capabilities", - .attrs = input_dev_caps_attrs, -}; - -static const struct attribute_group *input_dev_attr_groups[] = { - &input_dev_attr_group, - &input_dev_id_attr_group, - &input_dev_caps_attr_group, - NULL -}; - -static void input_dev_release(struct device *device) -{ - struct input_dev *dev = to_input_dev(device); - - input_ff_destroy(dev); - input_mt_destroy_slots(dev); - kfree(dev->absinfo); - kfree(dev->vals); - kfree(dev); - - module_put(THIS_MODULE); -} - -/* - * Input uevent interface - loading event handlers based on - * device bitfields. - */ -static int input_add_uevent_bm_var(struct kobj_uevent_env *env, - const char *name, unsigned long *bitmap, int max) -{ - int len; - - if (add_uevent_var(env, "%s", name)) - return -ENOMEM; - - len = input_print_bitmap(&env->buf[env->buflen - 1], - sizeof(env->buf) - env->buflen, - bitmap, max, false); - if (len >= (sizeof(env->buf) - env->buflen)) - return -ENOMEM; - - env->buflen += len; - return 0; -} - -static int input_add_uevent_modalias_var(struct kobj_uevent_env *env, - struct input_dev *dev) -{ - int len; - - if (add_uevent_var(env, "MODALIAS=")) - return -ENOMEM; - - len = input_print_modalias(&env->buf[env->buflen - 1], - sizeof(env->buf) - env->buflen, - dev, 0); - if (len >= (sizeof(env->buf) - env->buflen)) - return -ENOMEM; - - env->buflen += len; - return 0; -} - -#define INPUT_ADD_HOTPLUG_VAR(fmt, val...) \ - do { \ - int err = add_uevent_var(env, fmt, val); \ - if (err) \ - return err; \ - } while (0) - -#define INPUT_ADD_HOTPLUG_BM_VAR(name, bm, max) \ - do { \ - int err = input_add_uevent_bm_var(env, name, bm, max); \ - if (err) \ - return err; \ - } while (0) - -#define INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev) \ - do { \ - int err = input_add_uevent_modalias_var(env, dev); \ - if (err) \ - return err; \ - } while (0) - -static int input_dev_uevent(struct device *device, struct kobj_uevent_env *env) -{ - struct input_dev *dev = to_input_dev(device); - - INPUT_ADD_HOTPLUG_VAR("PRODUCT=%x/%x/%x/%x", - dev->id.bustype, dev->id.vendor, - dev->id.product, dev->id.version); - if (dev->name) - INPUT_ADD_HOTPLUG_VAR("NAME=\"%s\"", dev->name); - if (dev->phys) - INPUT_ADD_HOTPLUG_VAR("PHYS=\"%s\"", dev->phys); - if (dev->uniq) - INPUT_ADD_HOTPLUG_VAR("UNIQ=\"%s\"", dev->uniq); - - INPUT_ADD_HOTPLUG_BM_VAR("PROP=", dev->propbit, INPUT_PROP_MAX); - - INPUT_ADD_HOTPLUG_BM_VAR("EV=", dev->evbit, EV_MAX); - if (test_bit(EV_KEY, dev->evbit)) - INPUT_ADD_HOTPLUG_BM_VAR("KEY=", dev->keybit, KEY_MAX); - if (test_bit(EV_REL, dev->evbit)) - INPUT_ADD_HOTPLUG_BM_VAR("REL=", dev->relbit, REL_MAX); - if (test_bit(EV_ABS, dev->evbit)) - INPUT_ADD_HOTPLUG_BM_VAR("ABS=", dev->absbit, ABS_MAX); - if (test_bit(EV_MSC, dev->evbit)) - INPUT_ADD_HOTPLUG_BM_VAR("MSC=", dev->mscbit, MSC_MAX); - if (test_bit(EV_LED, dev->evbit)) - INPUT_ADD_HOTPLUG_BM_VAR("LED=", dev->ledbit, LED_MAX); - if (test_bit(EV_SND, dev->evbit)) - INPUT_ADD_HOTPLUG_BM_VAR("SND=", dev->sndbit, SND_MAX); - if (test_bit(EV_FF, dev->evbit)) - INPUT_ADD_HOTPLUG_BM_VAR("FF=", dev->ffbit, FF_MAX); - if (test_bit(EV_SW, dev->evbit)) - INPUT_ADD_HOTPLUG_BM_VAR("SW=", dev->swbit, SW_MAX); - - INPUT_ADD_HOTPLUG_MODALIAS_VAR(dev); - - return 0; -} - -#define INPUT_DO_TOGGLE(dev, type, bits, on) \ - do { \ - int i; \ - bool active; \ - \ - if (!test_bit(EV_##type, dev->evbit)) \ - break; \ - \ - for_each_set_bit(i, dev->bits##bit, type##_CNT) { \ - active = test_bit(i, dev->bits); \ - if (!active && !on) \ - continue; \ - \ - dev->event(dev, EV_##type, i, on ? active : 0); \ - } \ - } while (0) - -static void input_dev_toggle(struct input_dev *dev, bool activate) -{ - if (!dev->event) - return; - - INPUT_DO_TOGGLE(dev, LED, led, activate); - INPUT_DO_TOGGLE(dev, SND, snd, activate); - - if (activate && test_bit(EV_REP, dev->evbit)) { - dev->event(dev, EV_REP, REP_PERIOD, dev->rep[REP_PERIOD]); - dev->event(dev, EV_REP, REP_DELAY, dev->rep[REP_DELAY]); - } -} - -/** - * input_reset_device() - reset/restore the state of input device - * @dev: input device whose state needs to be reset - * - * This function tries to reset the state of an opened input device and - * bring internal state and state if the hardware in sync with each other. - * We mark all keys as released, restore LED state, repeat rate, etc. - */ -void input_reset_device(struct input_dev *dev) -{ - unsigned long flags; - - mutex_lock(&dev->mutex); - spin_lock_irqsave(&dev->event_lock, flags); - - input_dev_toggle(dev, true); - input_dev_release_keys(dev); - - spin_unlock_irqrestore(&dev->event_lock, flags); - mutex_unlock(&dev->mutex); -} -EXPORT_SYMBOL(input_reset_device); - -#ifdef CONFIG_PM_SLEEP -static int input_dev_suspend(struct device *dev) -{ - struct input_dev *input_dev = to_input_dev(dev); - - spin_lock_irq(&input_dev->event_lock); - - /* - * Keys that are pressed now are unlikely to be - * still pressed when we resume. - */ - input_dev_release_keys(input_dev); - - /* Turn off LEDs and sounds, if any are active. */ - input_dev_toggle(input_dev, false); - - spin_unlock_irq(&input_dev->event_lock); - - return 0; -} - -static int input_dev_resume(struct device *dev) -{ - struct input_dev *input_dev = to_input_dev(dev); - - spin_lock_irq(&input_dev->event_lock); - - /* Restore state of LEDs and sounds, if any were active. */ - input_dev_toggle(input_dev, true); - - spin_unlock_irq(&input_dev->event_lock); - - return 0; -} - -static int input_dev_freeze(struct device *dev) -{ - struct input_dev *input_dev = to_input_dev(dev); - - spin_lock_irq(&input_dev->event_lock); - - /* - * Keys that are pressed now are unlikely to be - * still pressed when we resume. - */ - input_dev_release_keys(input_dev); - - spin_unlock_irq(&input_dev->event_lock); - - return 0; -} - -static int input_dev_poweroff(struct device *dev) -{ - struct input_dev *input_dev = to_input_dev(dev); - - spin_lock_irq(&input_dev->event_lock); - - /* Turn off LEDs and sounds, if any are active. */ - input_dev_toggle(input_dev, false); - - spin_unlock_irq(&input_dev->event_lock); - - return 0; -} - -static const struct dev_pm_ops input_dev_pm_ops = { - .suspend = input_dev_suspend, - .resume = input_dev_resume, - .freeze = input_dev_freeze, - .poweroff = input_dev_poweroff, - .restore = input_dev_resume, -}; -#endif /* CONFIG_PM */ - -static struct device_type input_dev_type = { - .groups = input_dev_attr_groups, - .release = input_dev_release, - .uevent = input_dev_uevent, -#ifdef CONFIG_PM_SLEEP - .pm = &input_dev_pm_ops, -#endif -}; - -static char *input_devnode(struct device *dev, umode_t *mode) -{ - return kasprintf(GFP_KERNEL, "input/%s", dev_name(dev)); -} - -struct class input_class = { - .name = "input", - .devnode = input_devnode, -}; -EXPORT_SYMBOL_GPL(input_class); - -/** - * input_allocate_device - allocate memory for new input device - * - * Returns prepared struct input_dev or %NULL. - * - * NOTE: Use input_free_device() to free devices that have not been - * registered; input_unregister_device() should be used for already - * registered devices. - */ -struct input_dev *input_allocate_device(void) -{ - static atomic_t input_no = ATOMIC_INIT(-1); - struct input_dev *dev; - - dev = kzalloc(sizeof(struct input_dev), GFP_KERNEL); - if (dev) { - dev->dev.type = &input_dev_type; - dev->dev.class = &input_class; - device_initialize(&dev->dev); - mutex_init(&dev->mutex); - spin_lock_init(&dev->event_lock); - init_timer(&dev->timer); - INIT_LIST_HEAD(&dev->h_list); - INIT_LIST_HEAD(&dev->node); - - dev_set_name(&dev->dev, "input%lu", - (unsigned long)atomic_inc_return(&input_no)); - - __module_get(THIS_MODULE); - } - - return dev; -} -EXPORT_SYMBOL(input_allocate_device); - -struct input_devres { - struct input_dev *input; -}; - -static int devm_input_device_match(struct device *dev, void *res, void *data) -{ - struct input_devres *devres = res; - - return devres->input == data; -} - -static void devm_input_device_release(struct device *dev, void *res) -{ - struct input_devres *devres = res; - struct input_dev *input = devres->input; - - dev_dbg(dev, "%s: dropping reference to %s\n", - __func__, dev_name(&input->dev)); - input_put_device(input); -} - -/** - * devm_input_allocate_device - allocate managed input device - * @dev: device owning the input device being created - * - * Returns prepared struct input_dev or %NULL. - * - * Managed input devices do not need to be explicitly unregistered or - * freed as it will be done automatically when owner device unbinds from - * its driver (or binding fails). Once managed input device is allocated, - * it is ready to be set up and registered in the same fashion as regular - * input device. There are no special devm_input_device_[un]register() - * variants, regular ones work with both managed and unmanaged devices, - * should you need them. In most cases however, managed input device need - * not be explicitly unregistered or freed. - * - * NOTE: the owner device is set up as parent of input device and users - * should not override it. - */ -struct input_dev *devm_input_allocate_device(struct device *dev) -{ - struct input_dev *input; - struct input_devres *devres; - - devres = devres_alloc(devm_input_device_release, - sizeof(struct input_devres), GFP_KERNEL); - if (!devres) - return NULL; - - input = input_allocate_device(); - if (!input) { - devres_free(devres); - return NULL; - } - - input->dev.parent = dev; - input->devres_managed = true; - - devres->input = input; - devres_add(dev, devres); - - return input; -} -EXPORT_SYMBOL(devm_input_allocate_device); - -/** - * input_free_device - free memory occupied by input_dev structure - * @dev: input device to free - * - * This function should only be used if input_register_device() - * was not called yet or if it failed. Once device was registered - * use input_unregister_device() and memory will be freed once last - * reference to the device is dropped. - * - * Device should be allocated by input_allocate_device(). - * - * NOTE: If there are references to the input device then memory - * will not be freed until last reference is dropped. - */ -void input_free_device(struct input_dev *dev) -{ - if (dev) { - if (dev->devres_managed) - WARN_ON(devres_destroy(dev->dev.parent, - devm_input_device_release, - devm_input_device_match, - dev)); - input_put_device(dev); - } -} -EXPORT_SYMBOL(input_free_device); - -/** - * input_set_capability - mark device as capable of a certain event - * @dev: device that is capable of emitting or accepting event - * @type: type of the event (EV_KEY, EV_REL, etc...) - * @code: event code - * - * In addition to setting up corresponding bit in appropriate capability - * bitmap the function also adjusts dev->evbit. - */ -void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code) -{ - switch (type) { - case EV_KEY: - __set_bit(code, dev->keybit); - break; - - case EV_REL: - __set_bit(code, dev->relbit); - break; - - case EV_ABS: - input_alloc_absinfo(dev); - if (!dev->absinfo) - return; - - __set_bit(code, dev->absbit); - break; - - case EV_MSC: - __set_bit(code, dev->mscbit); - break; - - case EV_SW: - __set_bit(code, dev->swbit); - break; - - case EV_LED: - __set_bit(code, dev->ledbit); - break; - - case EV_SND: - __set_bit(code, dev->sndbit); - break; - - case EV_FF: - __set_bit(code, dev->ffbit); - break; - - case EV_PWR: - /* do nothing */ - break; - - default: - pr_err("input_set_capability: unknown type %u (code %u)\n", - type, code); - dump_stack(); - return; - } - - __set_bit(type, dev->evbit); -} -EXPORT_SYMBOL(input_set_capability); - -static unsigned int input_estimate_events_per_packet(struct input_dev *dev) -{ - int mt_slots; - int i; - unsigned int events; - - if (dev->mt) { - mt_slots = dev->mt->num_slots; - } else if (test_bit(ABS_MT_TRACKING_ID, dev->absbit)) { - mt_slots = dev->absinfo[ABS_MT_TRACKING_ID].maximum - - dev->absinfo[ABS_MT_TRACKING_ID].minimum + 1, - mt_slots = clamp(mt_slots, 2, 32); - } else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) { - mt_slots = 2; - } else { - mt_slots = 0; - } - - events = mt_slots + 1; /* count SYN_MT_REPORT and SYN_REPORT */ - - if (test_bit(EV_ABS, dev->evbit)) - for_each_set_bit(i, dev->absbit, ABS_CNT) - events += input_is_mt_axis(i) ? mt_slots : 1; - - if (test_bit(EV_REL, dev->evbit)) - events += bitmap_weight(dev->relbit, REL_CNT); - - /* Make room for KEY and MSC events */ - events += 7; - - return events; -} - -#define INPUT_CLEANSE_BITMASK(dev, type, bits) \ - do { \ - if (!test_bit(EV_##type, dev->evbit)) \ - memset(dev->bits##bit, 0, \ - sizeof(dev->bits##bit)); \ - } while (0) - -static void input_cleanse_bitmasks(struct input_dev *dev) -{ - INPUT_CLEANSE_BITMASK(dev, KEY, key); - INPUT_CLEANSE_BITMASK(dev, REL, rel); - INPUT_CLEANSE_BITMASK(dev, ABS, abs); - INPUT_CLEANSE_BITMASK(dev, MSC, msc); - INPUT_CLEANSE_BITMASK(dev, LED, led); - INPUT_CLEANSE_BITMASK(dev, SND, snd); - INPUT_CLEANSE_BITMASK(dev, FF, ff); - INPUT_CLEANSE_BITMASK(dev, SW, sw); -} - -static void __input_unregister_device(struct input_dev *dev) -{ - struct input_handle *handle, *next; - - input_disconnect_device(dev); - - mutex_lock(&input_mutex); - - list_for_each_entry_safe(handle, next, &dev->h_list, d_node) - handle->handler->disconnect(handle); - WARN_ON(!list_empty(&dev->h_list)); - - del_timer_sync(&dev->timer); - list_del_init(&dev->node); - - input_wakeup_procfs_readers(); - - mutex_unlock(&input_mutex); - - device_del(&dev->dev); -} - -static void devm_input_device_unregister(struct device *dev, void *res) -{ - struct input_devres *devres = res; - struct input_dev *input = devres->input; - - dev_dbg(dev, "%s: unregistering device %s\n", - __func__, dev_name(&input->dev)); - __input_unregister_device(input); -} - -/** - * input_enable_softrepeat - enable software autorepeat - * @dev: input device - * @delay: repeat delay - * @period: repeat period - * - * Enable software autorepeat on the input device. - */ -void input_enable_softrepeat(struct input_dev *dev, int delay, int period) -{ - dev->timer.data = (unsigned long) dev; - dev->timer.function = input_repeat_key; - dev->rep[REP_DELAY] = delay; - dev->rep[REP_PERIOD] = period; -} -EXPORT_SYMBOL(input_enable_softrepeat); - -/** - * input_register_device - register device with input core - * @dev: device to be registered - * - * This function registers device with input core. The device must be - * allocated with input_allocate_device() and all it's capabilities - * set up before registering. - * If function fails the device must be freed with input_free_device(). - * Once device has been successfully registered it can be unregistered - * with input_unregister_device(); input_free_device() should not be - * called in this case. - * - * Note that this function is also used to register managed input devices - * (ones allocated with devm_input_allocate_device()). Such managed input - * devices need not be explicitly unregistered or freed, their tear down - * is controlled by the devres infrastructure. It is also worth noting - * that tear down of managed input devices is internally a 2-step process: - * registered managed input device is first unregistered, but stays in - * memory and can still handle input_event() calls (although events will - * not be delivered anywhere). The freeing of managed input device will - * happen later, when devres stack is unwound to the point where device - * allocation was made. - */ -int input_register_device(struct input_dev *dev) -{ - struct input_devres *devres = NULL; - struct input_handler *handler; - unsigned int packet_size; - const char *path; - int error; - - if (dev->devres_managed) { - devres = devres_alloc(devm_input_device_unregister, - sizeof(struct input_devres), GFP_KERNEL); - if (!devres) - return -ENOMEM; - - devres->input = dev; - } - - /* Every input device generates EV_SYN/SYN_REPORT events. */ - __set_bit(EV_SYN, dev->evbit); - - /* KEY_RESERVED is not supposed to be transmitted to userspace. */ - __clear_bit(KEY_RESERVED, dev->keybit); - - /* Make sure that bitmasks not mentioned in dev->evbit are clean. */ - input_cleanse_bitmasks(dev); - - packet_size = input_estimate_events_per_packet(dev); - if (dev->hint_events_per_packet < packet_size) - dev->hint_events_per_packet = packet_size; - - dev->max_vals = dev->hint_events_per_packet + 2; - dev->vals = kcalloc(dev->max_vals, sizeof(*dev->vals), GFP_KERNEL); - if (!dev->vals) { - error = -ENOMEM; - goto err_devres_free; - } - - /* - * If delay and period are pre-set by the driver, then autorepeating - * is handled by the driver itself and we don't do it in input.c. - */ - if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) - input_enable_softrepeat(dev, 250, 33); - - if (!dev->getkeycode) - dev->getkeycode = input_default_getkeycode; - - if (!dev->setkeycode) - dev->setkeycode = input_default_setkeycode; - - error = device_add(&dev->dev); - if (error) - goto err_free_vals; - - path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL); - pr_info("%s as %s\n", - dev->name ? dev->name : "Unspecified device", - path ? path : "N/A"); - kfree(path); - - error = mutex_lock_interruptible(&input_mutex); - if (error) - goto err_device_del; - - list_add_tail(&dev->node, &input_dev_list); - - list_for_each_entry(handler, &input_handler_list, node) - input_attach_handler(dev, handler); - - input_wakeup_procfs_readers(); - - mutex_unlock(&input_mutex); - - if (dev->devres_managed) { - dev_dbg(dev->dev.parent, "%s: registering %s with devres.\n", - __func__, dev_name(&dev->dev)); - devres_add(dev->dev.parent, devres); - } - return 0; - -err_device_del: - device_del(&dev->dev); -err_free_vals: - kfree(dev->vals); - dev->vals = NULL; -err_devres_free: - devres_free(devres); - return error; -} -EXPORT_SYMBOL(input_register_device); - -/** - * input_unregister_device - unregister previously registered device - * @dev: device to be unregistered - * - * This function unregisters an input device. Once device is unregistered - * the caller should not try to access it as it may get freed at any moment. - */ -void input_unregister_device(struct input_dev *dev) -{ - if (dev->devres_managed) { - WARN_ON(devres_destroy(dev->dev.parent, - devm_input_device_unregister, - devm_input_device_match, - dev)); - __input_unregister_device(dev); - /* - * We do not do input_put_device() here because it will be done - * when 2nd devres fires up. - */ - } else { - __input_unregister_device(dev); - input_put_device(dev); - } -} -EXPORT_SYMBOL(input_unregister_device); - -/** - * input_register_handler - register a new input handler - * @handler: handler to be registered - * - * This function registers a new input handler (interface) for input - * devices in the system and attaches it to all input devices that - * are compatible with the handler. - */ -int input_register_handler(struct input_handler *handler) -{ - struct input_dev *dev; - int error; - - error = mutex_lock_interruptible(&input_mutex); - if (error) - return error; - - INIT_LIST_HEAD(&handler->h_list); - - list_add_tail(&handler->node, &input_handler_list); - - list_for_each_entry(dev, &input_dev_list, node) - input_attach_handler(dev, handler); - - input_wakeup_procfs_readers(); - - mutex_unlock(&input_mutex); - return 0; -} -EXPORT_SYMBOL(input_register_handler); - -/** - * input_unregister_handler - unregisters an input handler - * @handler: handler to be unregistered - * - * This function disconnects a handler from its input devices and - * removes it from lists of known handlers. - */ -void input_unregister_handler(struct input_handler *handler) -{ - struct input_handle *handle, *next; - - mutex_lock(&input_mutex); - - list_for_each_entry_safe(handle, next, &handler->h_list, h_node) - handler->disconnect(handle); - WARN_ON(!list_empty(&handler->h_list)); - - list_del_init(&handler->node); - - input_wakeup_procfs_readers(); - - mutex_unlock(&input_mutex); -} -EXPORT_SYMBOL(input_unregister_handler); - -/** - * input_handler_for_each_handle - handle iterator - * @handler: input handler to iterate - * @data: data for the callback - * @fn: function to be called for each handle - * - * Iterate over @bus's list of devices, and call @fn for each, passing - * it @data and stop when @fn returns a non-zero value. The function is - * using RCU to traverse the list and therefore may be using in atomic - * contexts. The @fn callback is invoked from RCU critical section and - * thus must not sleep. - */ -int input_handler_for_each_handle(struct input_handler *handler, void *data, - int (*fn)(struct input_handle *, void *)) -{ - struct input_handle *handle; - int retval = 0; - - rcu_read_lock(); - - list_for_each_entry_rcu(handle, &handler->h_list, h_node) { - retval = fn(handle, data); - if (retval) - break; - } - - rcu_read_unlock(); - - return retval; -} -EXPORT_SYMBOL(input_handler_for_each_handle); - -/** - * input_register_handle - register a new input handle - * @handle: handle to register - * - * This function puts a new input handle onto device's - * and handler's lists so that events can flow through - * it once it is opened using input_open_device(). - * - * This function is supposed to be called from handler's - * connect() method. - */ -int input_register_handle(struct input_handle *handle) -{ - struct input_handler *handler = handle->handler; - struct input_dev *dev = handle->dev; - int error; - - /* - * We take dev->mutex here to prevent race with - * input_release_device(). - */ - error = mutex_lock_interruptible(&dev->mutex); - if (error) - return error; - - /* - * Filters go to the head of the list, normal handlers - * to the tail. - */ - if (handler->filter) - list_add_rcu(&handle->d_node, &dev->h_list); - else - list_add_tail_rcu(&handle->d_node, &dev->h_list); - - mutex_unlock(&dev->mutex); - - /* - * Since we are supposed to be called from ->connect() - * which is mutually exclusive with ->disconnect() - * we can't be racing with input_unregister_handle() - * and so separate lock is not needed here. - */ - list_add_tail_rcu(&handle->h_node, &handler->h_list); - - if (handler->start) - handler->start(handle); - - return 0; -} -EXPORT_SYMBOL(input_register_handle); - -/** - * input_unregister_handle - unregister an input handle - * @handle: handle to unregister - * - * This function removes input handle from device's - * and handler's lists. - * - * This function is supposed to be called from handler's - * disconnect() method. - */ -void input_unregister_handle(struct input_handle *handle) -{ - struct input_dev *dev = handle->dev; - - list_del_rcu(&handle->h_node); - - /* - * Take dev->mutex to prevent race with input_release_device(). - */ - mutex_lock(&dev->mutex); - list_del_rcu(&handle->d_node); - mutex_unlock(&dev->mutex); - - synchronize_rcu(); -} -EXPORT_SYMBOL(input_unregister_handle); - -/** - * input_get_new_minor - allocates a new input minor number - * @legacy_base: beginning or the legacy range to be searched - * @legacy_num: size of legacy range - * @allow_dynamic: whether we can also take ID from the dynamic range - * - * This function allocates a new device minor for from input major namespace. - * Caller can request legacy minor by specifying @legacy_base and @legacy_num - * parameters and whether ID can be allocated from dynamic range if there are - * no free IDs in legacy range. - */ -int input_get_new_minor(int legacy_base, unsigned int legacy_num, - bool allow_dynamic) -{ - /* - * This function should be called from input handler's ->connect() - * methods, which are serialized with input_mutex, so no additional - * locking is needed here. - */ - if (legacy_base >= 0) { - int minor = ida_simple_get(&input_ida, - legacy_base, - legacy_base + legacy_num, - GFP_KERNEL); - if (minor >= 0 || !allow_dynamic) - return minor; - } - - return ida_simple_get(&input_ida, - INPUT_FIRST_DYNAMIC_DEV, INPUT_MAX_CHAR_DEVICES, - GFP_KERNEL); -} -EXPORT_SYMBOL(input_get_new_minor); - -/** - * input_free_minor - release previously allocated minor - * @minor: minor to be released - * - * This function releases previously allocated input minor so that it can be - * reused later. - */ -void input_free_minor(unsigned int minor) -{ - ida_simple_remove(&input_ida, minor); -} -EXPORT_SYMBOL(input_free_minor); - -static int __init input_init(void) -{ - int err; - - err = class_register(&input_class); - if (err) { - pr_err("unable to register input_dev class\n"); - return err; - } - - err = input_proc_init(); - if (err) - goto fail1; - - err = register_chrdev_region(MKDEV(INPUT_MAJOR, 0), - INPUT_MAX_CHAR_DEVICES, "input"); - if (err) { - pr_err("unable to register char major %d", INPUT_MAJOR); - goto fail2; - } - - return 0; - - fail2: input_proc_exit(); - fail1: class_unregister(&input_class); - return err; -} - -static void __exit input_exit(void) -{ - input_proc_exit(); - unregister_chrdev_region(MKDEV(INPUT_MAJOR, 0), - INPUT_MAX_CHAR_DEVICES); - class_unregister(&input_class); -} - -subsys_initcall(input_init); -module_exit(input_exit); diff --git a/src/linux/drivers/input/joystick/Kconfig b/src/linux/drivers/input/joystick/Kconfig deleted file mode 100644 index 4215b53..0000000 --- a/src/linux/drivers/input/joystick/Kconfig +++ /dev/null @@ -1,333 +0,0 @@ -# -# Joystick driver configuration -# -menuconfig INPUT_JOYSTICK - bool "Joysticks/Gamepads" - help - If you have a joystick, 6dof controller, gamepad, steering wheel, - weapon control system or something like that you can say Y here - and the list of supported devices will be displayed. This option - doesn't affect the kernel. - - Please read the file which - contains more information. - -if INPUT_JOYSTICK - -config JOYSTICK_ANALOG - tristate "Classic PC analog joysticks and gamepads" - select GAMEPORT - ---help--- - Say Y here if you have a joystick that connects to the PC - gameport. In addition to the usual PC analog joystick, this driver - supports many extensions, including joysticks with throttle control, - with rudders, additional hats and buttons compatible with CH - Flightstick Pro, ThrustMaster FCS, 6 and 8 button gamepads, or - Saitek Cyborg joysticks. - - Please read the file which - contains more information. - - To compile this driver as a module, choose M here: the - module will be called analog. - -config JOYSTICK_A3D - tristate "Assassin 3D and MadCatz Panther devices" - select GAMEPORT - help - Say Y here if you have an FPGaming or MadCatz controller using the - A3D protocol over the PC gameport. - - To compile this driver as a module, choose M here: the - module will be called a3d. - -config JOYSTICK_ADI - tristate "Logitech ADI digital joysticks and gamepads" - select GAMEPORT - help - Say Y here if you have a Logitech controller using the ADI - protocol over the PC gameport. - - To compile this driver as a module, choose M here: the - module will be called adi. - -config JOYSTICK_COBRA - tristate "Creative Labs Blaster Cobra gamepad" - select GAMEPORT - help - Say Y here if you have a Creative Labs Blaster Cobra gamepad. - - To compile this driver as a module, choose M here: the - module will be called cobra. - -config JOYSTICK_GF2K - tristate "Genius Flight2000 Digital joysticks and gamepads" - select GAMEPORT - help - Say Y here if you have a Genius Flight2000 or MaxFighter digitally - communicating joystick or gamepad. - - To compile this driver as a module, choose M here: the - module will be called gf2k. - -config JOYSTICK_GRIP - tristate "Gravis GrIP joysticks and gamepads" - select GAMEPORT - help - Say Y here if you have a Gravis controller using the GrIP protocol - over the PC gameport. - - To compile this driver as a module, choose M here: the - module will be called grip. - -config JOYSTICK_GRIP_MP - tristate "Gravis GrIP MultiPort" - select GAMEPORT - help - Say Y here if you have the original Gravis GrIP MultiPort, a hub - that connects to the gameport and you connect gamepads to it. - - To compile this driver as a module, choose M here: the - module will be called grip_mp. - -config JOYSTICK_GUILLEMOT - tristate "Guillemot joysticks and gamepads" - select GAMEPORT - help - Say Y here if you have a Guillemot joystick using a digital - protocol over the PC gameport. - - To compile this driver as a module, choose M here: the - module will be called guillemot. - -config JOYSTICK_INTERACT - tristate "InterAct digital joysticks and gamepads" - select GAMEPORT - help - Say Y here if you have an InterAct gameport or joystick - communicating digitally over the gameport. - - To compile this driver as a module, choose M here: the - module will be called interact. - -config JOYSTICK_SIDEWINDER - tristate "Microsoft SideWinder digital joysticks and gamepads" - select GAMEPORT - help - Say Y here if you have a Microsoft controller using the Digital - Overdrive protocol over PC gameport. - - To compile this driver as a module, choose M here: the - module will be called sidewinder. - -config JOYSTICK_TMDC - tristate "ThrustMaster DirectConnect joysticks and gamepads" - select GAMEPORT - help - Say Y here if you have a ThrustMaster controller using the - DirectConnect (BSP) protocol over the PC gameport. - - To compile this driver as a module, choose M here: the - module will be called tmdc. - -source "drivers/input/joystick/iforce/Kconfig" - -config JOYSTICK_WARRIOR - tristate "Logitech WingMan Warrior joystick" - select SERIO - help - Say Y here if you have a Logitech WingMan Warrior joystick connected - to your computer's serial port. - - To compile this driver as a module, choose M here: the - module will be called warrior. - -config JOYSTICK_MAGELLAN - tristate "LogiCad3d Magellan/SpaceMouse 6dof controllers" - select SERIO - help - Say Y here if you have a Magellan or Space Mouse 6DOF controller - connected to your computer's serial port. - - To compile this driver as a module, choose M here: the - module will be called magellan. - -config JOYSTICK_SPACEORB - tristate "SpaceTec SpaceOrb/Avenger 6dof controllers" - select SERIO - help - Say Y here if you have a SpaceOrb 360 or SpaceBall Avenger 6DOF - controller connected to your computer's serial port. - - To compile this driver as a module, choose M here: the - module will be called spaceorb. - -config JOYSTICK_SPACEBALL - tristate "SpaceTec SpaceBall 6dof controllers" - select SERIO - help - Say Y here if you have a SpaceTec SpaceBall 2003/3003/4000 FLX - controller connected to your computer's serial port. For the - SpaceBall 4000 USB model, use the USB HID driver. - - To compile this driver as a module, choose M here: the - module will be called spaceball. - -config JOYSTICK_STINGER - tristate "Gravis Stinger gamepad" - select SERIO - help - Say Y here if you have a Gravis Stinger connected to one of your - serial ports. - - To compile this driver as a module, choose M here: the - module will be called stinger. - -config JOYSTICK_TWIDJOY - tristate "Twiddler as a joystick" - select SERIO - help - Say Y here if you have a Handykey Twiddler connected to your - computer's serial port and want to use it as a joystick. - - To compile this driver as a module, choose M here: the - module will be called twidjoy. - -config JOYSTICK_ZHENHUA - tristate "5-byte Zhenhua RC transmitter" - select SERIO - select BITREVERSE - help - Say Y here if you have a Zhen Hua PPM-4CH transmitter which is - supplied with a ready to fly micro electric indoor helicopters - such as EasyCopter, Lama, MiniCopter, DragonFly or Jabo and want - to use it via serial cable as a joystick. - - To compile this driver as a module, choose M here: the - module will be called zhenhua. - -config JOYSTICK_DB9 - tristate "Multisystem, Sega Genesis, Saturn joysticks and gamepads" - depends on PARPORT - help - Say Y here if you have a Sega Master System gamepad, Sega Genesis - gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga, - Commodore, Amstrad CPC joystick connected to your parallel port. - For more information on how to use the driver please read - . - - To compile this driver as a module, choose M here: the - module will be called db9. - -config JOYSTICK_GAMECON - tristate "Multisystem, NES, SNES, N64, PSX joysticks and gamepads" - depends on PARPORT - select INPUT_FF_MEMLESS - ---help--- - Say Y here if you have a Nintendo Entertainment System gamepad, - Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad, - Sony PlayStation gamepad or a Multisystem -- Atari, Amiga, - Commodore, Amstrad CPC joystick connected to your parallel port. - For more information on how to use the driver please read - . - - To compile this driver as a module, choose M here: the - module will be called gamecon. - -config JOYSTICK_TURBOGRAFX - tristate "Multisystem joysticks via TurboGraFX device" - depends on PARPORT - help - Say Y here if you have the TurboGraFX interface by Steffen Schwenke, - and want to use it with Multisystem -- Atari, Amiga, Commodore, - Amstrad CPC joystick. For more information on how to use the driver - please read . - - To compile this driver as a module, choose M here: the - module will be called turbografx. - -config JOYSTICK_AMIGA - tristate "Amiga joysticks" - depends on AMIGA - help - Say Y here if you have an Amiga with a digital joystick connected - to it. - - To compile this driver as a module, choose M here: the - module will be called amijoy. - -config JOYSTICK_AS5011 - tristate "Austria Microsystem AS5011 joystick" - depends on I2C - help - Say Y here if you have an AS5011 digital joystick connected to your - system. - - To compile this driver as a module, choose M here: the - module will be called as5011. - -config JOYSTICK_JOYDUMP - tristate "Gameport data dumper" - select GAMEPORT - help - Say Y here if you want to dump data from your joystick into the system - log for debugging purposes. Say N if you are making a production - configuration or aren't sure. - - To compile this driver as a module, choose M here: the - module will be called joydump. - -config JOYSTICK_XPAD - tristate "X-Box gamepad support" - depends on USB_ARCH_HAS_HCD - select USB - help - Say Y here if you want to use the X-Box pad with your computer. - Make sure to say Y to "Joystick support" (CONFIG_INPUT_JOYDEV) - and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well. - - For information about how to connect the X-Box pad to USB, see - . - - To compile this driver as a module, choose M here: the - module will be called xpad. - -config JOYSTICK_XPAD_FF - bool "X-Box gamepad rumble support" - depends on JOYSTICK_XPAD && INPUT - select INPUT_FF_MEMLESS - ---help--- - Say Y here if you want to take advantage of xbox 360 rumble features. - -config JOYSTICK_XPAD_LEDS - bool "LED Support for Xbox360 controller 'BigX' LED" - depends on JOYSTICK_XPAD && (LEDS_CLASS=y || LEDS_CLASS=JOYSTICK_XPAD) - ---help--- - This option enables support for the LED which surrounds the Big X on - XBox 360 controller. - -config JOYSTICK_WALKERA0701 - tristate "Walkera WK-0701 RC transmitter" - depends on HIGH_RES_TIMERS && PARPORT - help - Say Y or M here if you have a Walkera WK-0701 transmitter which is - supplied with a ready to fly Walkera helicopters such as HM36, - HM37, HM60 and want to use it via parport as a joystick. More - information is available: - - To compile this driver as a module, choose M here: the - module will be called walkera0701. - -config JOYSTICK_MAPLE - tristate "Dreamcast control pad" - depends on MAPLE - help - Say Y here if you have a SEGA Dreamcast and want to use your - controller as a joystick. - - Most Dreamcast users will say Y. - - To compile this as a module choose M here: the module will be called - maplecontrol. - -endif diff --git a/src/linux/drivers/input/joystick/iforce/Kconfig b/src/linux/drivers/input/joystick/iforce/Kconfig deleted file mode 100644 index 8fde22a..0000000 --- a/src/linux/drivers/input/joystick/iforce/Kconfig +++ /dev/null @@ -1,32 +0,0 @@ -# -# I-Force driver configuration -# -config JOYSTICK_IFORCE - tristate "I-Force devices" - depends on INPUT && INPUT_JOYSTICK - help - Say Y here if you have an I-Force joystick or steering wheel - - You also must choose at least one of the two options below. - - To compile this driver as a module, choose M here: the - module will be called iforce. - -config JOYSTICK_IFORCE_USB - bool "I-Force USB joysticks and wheels" - depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || USB=y) && USB - help - Say Y here if you have an I-Force joystick or steering wheel - connected to your USB port. - -config JOYSTICK_IFORCE_232 - bool "I-Force Serial joysticks and wheels" - depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || SERIO=y) && SERIO - help - Say Y here if you have an I-Force joystick or steering wheel - connected to your serial (COM) port. - - You will need an additional utility called inputattach, see - - and . - diff --git a/src/linux/drivers/input/keyboard/Kconfig b/src/linux/drivers/input/keyboard/Kconfig deleted file mode 100644 index cbd75cf..0000000 --- a/src/linux/drivers/input/keyboard/Kconfig +++ /dev/null @@ -1,737 +0,0 @@ -# -# Input core configuration -# -menuconfig INPUT_KEYBOARD - bool "Keyboards" - default y - help - Say Y here, and a list of supported keyboards will be displayed. - This option doesn't affect the kernel. - - If unsure, say Y. - -if INPUT_KEYBOARD - -config KEYBOARD_ADC - tristate "ADC Ladder Buttons" - depends on IIO - select INPUT_POLLDEV - help - This driver implements support for buttons connected - to an ADC using a resistor ladder. - - Say Y here if your device has such buttons connected to an ADC. Your - board-specific setup logic must also provide a configuration data - for mapping voltages to buttons. - - To compile this driver as a module, choose M here: the - module will be called adc_keys. - -config KEYBOARD_ADP5520 - tristate "Keypad Support for ADP5520 PMIC" - depends on PMIC_ADP5520 - help - This option enables support for the keypad scan matrix - on Analog Devices ADP5520 PMICs. - - To compile this driver as a module, choose M here: the module will - be called adp5520-keys. - -config KEYBOARD_ADP5588 - tristate "ADP5588/87 I2C QWERTY Keypad and IO Expander" - depends on I2C - help - Say Y here if you want to use a ADP5588/87 attached to your - system I2C bus. - - To compile this driver as a module, choose M here: the - module will be called adp5588-keys. - -config KEYBOARD_ADP5589 - tristate "ADP5585/ADP5589 I2C QWERTY Keypad and IO Expander" - depends on I2C - help - Say Y here if you want to use a ADP5585/ADP5589 attached to your - system I2C bus. - - To compile this driver as a module, choose M here: the - module will be called adp5589-keys. - -config KEYBOARD_AMIGA - tristate "Amiga keyboard" - depends on AMIGA - help - Say Y here if you are running Linux on any AMIGA and have a keyboard - attached. - - To compile this driver as a module, choose M here: the - module will be called amikbd. - -config ATARI_KBD_CORE - bool - -config KEYBOARD_ATARI - tristate "Atari keyboard" - depends on ATARI - select ATARI_KBD_CORE - help - Say Y here if you are running Linux on any Atari and have a keyboard - attached. - - To compile this driver as a module, choose M here: the - module will be called atakbd. - -config KEYBOARD_ATKBD - tristate "AT keyboard" - default y - select SERIO - select SERIO_LIBPS2 - select SERIO_I8042 if ARCH_MIGHT_HAVE_PC_SERIO - select SERIO_GSCPS2 if GSC - help - Say Y here if you want to use a standard AT or PS/2 keyboard. Usually - you'll need this, unless you have a different type keyboard (USB, ADB - or other). This also works for AT and PS/2 keyboards connected over a - PS/2 to serial converter. - - If unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called atkbd. - -config KEYBOARD_ATKBD_HP_KEYCODES - bool "Use HP keyboard scancodes" - depends on PARISC && KEYBOARD_ATKBD - default y - help - Say Y here if you have a PA-RISC machine and want to use an AT or - PS/2 keyboard, and your keyboard uses keycodes that are specific to - PA-RISC keyboards. - - Say N if you use a standard keyboard. - -config KEYBOARD_ATKBD_RDI_KEYCODES - bool "Use PrecisionBook keyboard scancodes" - depends on KEYBOARD_ATKBD_HP_KEYCODES - default n - help - If you have an RDI PrecisionBook, say Y here if you want to use its - built-in keyboard (as opposed to an external keyboard). - - The PrecisionBook has five keys that conflict with those used by most - AT and PS/2 keyboards. These are as follows: - - PrecisionBook Standard AT or PS/2 - - F1 F12 - Left Ctrl Left Alt - Caps Lock Left Ctrl - Right Ctrl Caps Lock - Left 102nd key (the key to the right of Left Shift) - - If you say N here, and use the PrecisionBook keyboard, then each key - in the left-hand column will be interpreted as the corresponding key - in the right-hand column. - - If you say Y here, and use an external keyboard, then each key in the - right-hand column will be interpreted as the key shown in the - left-hand column. - -config KEYBOARD_QT1070 - tristate "Atmel AT42QT1070 Touch Sensor Chip" - depends on I2C - help - Say Y here if you want to use Atmel AT42QT1070 QTouch - Sensor chip as input device. - - To compile this driver as a module, choose M here: - the module will be called qt1070 - -config KEYBOARD_QT2160 - tristate "Atmel AT42QT2160 Touch Sensor Chip" - depends on I2C - help - If you say yes here you get support for Atmel AT42QT2160 Touch - Sensor chip as a keyboard input. - - This driver can also be built as a module. If so, the module - will be called qt2160. - -config KEYBOARD_BFIN - tristate "Blackfin BF54x keypad support" - depends on (BF54x && !BF544) - help - Say Y here if you want to use the BF54x keypad. - - To compile this driver as a module, choose M here: the - module will be called bf54x-keys. - -config KEYBOARD_CLPS711X - tristate "CLPS711X Keypad support" - depends on OF_GPIO && (ARCH_CLPS711X || COMPILE_TEST) - select INPUT_MATRIXKMAP - select INPUT_POLLDEV - help - Say Y here to enable the matrix keypad on the Cirrus Logic - CLPS711X CPUs. - - To compile this driver as a module, choose M here: the - module will be called clps711x-keypad. - -config KEYBOARD_LKKBD - tristate "DECstation/VAXstation LK201/LK401 keyboard" - select SERIO - help - Say Y here if you want to use a LK201 or LK401 style serial - keyboard. This keyboard is also useable on PCs if you attach - it with the inputattach program. The connector pinout is - described within lkkbd.c. - - To compile this driver as a module, choose M here: the - module will be called lkkbd. - -config KEYBOARD_EP93XX - tristate "EP93xx Matrix Keypad support" - depends on ARCH_EP93XX - select INPUT_MATRIXKMAP - help - Say Y here to enable the matrix keypad on the Cirrus EP93XX. - - To compile this driver as a module, choose M here: the - module will be called ep93xx_keypad. - -config KEYBOARD_GPIO - tristate "GPIO Buttons" - depends on GPIOLIB || COMPILE_TEST - help - This driver implements support for buttons connected - to GPIO pins of various CPUs (and some other chips). - - Say Y here if your device has buttons connected - directly to such GPIO pins. Your board-specific - setup logic must also provide a platform device, - with configuration data saying which GPIOs are used. - - To compile this driver as a module, choose M here: the - module will be called gpio_keys. - -config KEYBOARD_GPIO_POLLED - tristate "Polled GPIO buttons" - depends on GPIOLIB - select INPUT_POLLDEV - help - This driver implements support for buttons connected - to GPIO pins that are not capable of generating interrupts. - - Say Y here if your device has buttons connected - directly to such GPIO pins. Your board-specific - setup logic must also provide a platform device, - with configuration data saying which GPIOs are used. - - To compile this driver as a module, choose M here: the - module will be called gpio_keys_polled. - -config KEYBOARD_TCA6416 - tristate "TCA6416/TCA6408A Keypad Support" - depends on I2C - help - This driver implements basic keypad functionality - for keys connected through TCA6416/TCA6408A IO expanders. - - Say Y here if your device has keys connected to - TCA6416/TCA6408A IO expander. Your board-specific setup logic - must also provide pin-mask details(of which TCA6416 pins - are used for keypad). - - If enabled the entire TCA6416 device will be managed through - this driver. - - To compile this driver as a module, choose M here: the - module will be called tca6416_keypad. - -config KEYBOARD_TCA8418 - tristate "TCA8418 Keypad Support" - depends on I2C - select INPUT_MATRIXKMAP - help - This driver implements basic keypad functionality - for keys connected through TCA8418 keypad decoder. - - Say Y here if your device has keys connected to - TCA8418 keypad decoder. - - If enabled the complete TCA8418 device will be managed through - this driver. - - To compile this driver as a module, choose M here: the - module will be called tca8418_keypad. - -config KEYBOARD_MATRIX - tristate "GPIO driven matrix keypad support" - depends on GPIOLIB || COMPILE_TEST - select INPUT_MATRIXKMAP - help - Enable support for GPIO driven matrix keypad. - - To compile this driver as a module, choose M here: the - module will be called matrix_keypad. - -config KEYBOARD_HIL_OLD - tristate "HP HIL keyboard support (simple driver)" - depends on GSC || HP300 - default y - help - The "Human Interface Loop" is a older, 8-channel USB-like - controller used in several Hewlett Packard models. This driver - was adapted from the one written for m68k/hp300, and implements - support for a keyboard attached to the HIL port, but not for - any other types of HIL input devices like mice or tablets. - However, it has been thoroughly tested and is stable. - - If you want full HIL support including support for multiple - keyboards, mice, and tablets, you have to enable the - "HP System Device Controller i8042 Support" in the input/serio - submenu. - -config KEYBOARD_HIL - tristate "HP HIL keyboard/pointer support" - depends on GSC || HP300 - default y - select HP_SDC - select HIL_MLC - select SERIO - help - The "Human Interface Loop" is a older, 8-channel USB-like - controller used in several Hewlett Packard models. - This driver implements support for HIL-keyboards and pointing - devices (mice, tablets, touchscreens) attached - to your machine, so normally you should say Y here. - -config KEYBOARD_HP6XX - tristate "HP Jornada 6xx keyboard" - depends on SH_HP6XX - select INPUT_POLLDEV - help - Say Y here if you have a HP Jornada 620/660/680/690 and want to - support the built-in keyboard. - - To compile this driver as a module, choose M here: the - module will be called jornada680_kbd. - -config KEYBOARD_HP7XX - tristate "HP Jornada 7xx keyboard" - depends on SA1100_JORNADA720_SSP && SA1100_SSP - help - Say Y here if you have a HP Jornada 710/720/728 and want to - support the built-in keyboard. - - To compile this driver as a module, choose M here: the - module will be called jornada720_kbd. - -config KEYBOARD_LM8323 - tristate "LM8323 keypad chip" - depends on I2C - depends on LEDS_CLASS - help - If you say yes here you get support for the National Semiconductor - LM8323 keypad controller. - - To compile this driver as a module, choose M here: the - module will be called lm8323. - -config KEYBOARD_LM8333 - tristate "LM8333 keypad chip" - depends on I2C - select INPUT_MATRIXKMAP - help - If you say yes here you get support for the National Semiconductor - LM8333 keypad controller. - - To compile this driver as a module, choose M here: the - module will be called lm8333. - -config KEYBOARD_LOCOMO - tristate "LoCoMo Keyboard Support" - depends on SHARP_LOCOMO - help - Say Y here if you are running Linux on a Sharp Zaurus Collie or Poodle based PDA - - To compile this driver as a module, choose M here: the - module will be called locomokbd. - -config KEYBOARD_LPC32XX - tristate "LPC32XX matrix key scanner support" - depends on ARCH_LPC32XX && OF - select INPUT_MATRIXKMAP - help - Say Y here if you want to use NXP LPC32XX SoC key scanner interface, - connected to a key matrix. - - To compile this driver as a module, choose M here: the - module will be called lpc32xx-keys. - -config KEYBOARD_MAPLE - tristate "Maple bus keyboard" - depends on SH_DREAMCAST && MAPLE - help - Say Y here if you have a Dreamcast console running Linux and have - a keyboard attached to its Maple bus. - - To compile this driver as a module, choose M here: the - module will be called maple_keyb. - -config KEYBOARD_MAX7359 - tristate "Maxim MAX7359 Key Switch Controller" - select INPUT_MATRIXKMAP - depends on I2C - help - If you say yes here you get support for the Maxim MAX7359 Key - Switch Controller chip. This providers microprocessors with - management of up to 64 key switches - - To compile this driver as a module, choose M here: the - module will be called max7359_keypad. - -config KEYBOARD_MCS - tristate "MELFAS MCS Touchkey" - depends on I2C - help - Say Y here if you have the MELFAS MCS5000/5080 touchkey controller - chip in your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called mcs_touchkey. - -config KEYBOARD_MPR121 - tristate "Freescale MPR121 Touchkey" - depends on I2C - help - Say Y here if you have Freescale MPR121 touchkey controller - chip in your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called mpr121_touchkey. - -config KEYBOARD_SNVS_PWRKEY - tristate "IMX SNVS Power Key Driver" - depends on SOC_IMX6SX - depends on OF - help - This is the snvs powerkey driver for the Freescale i.MX application - processors that are newer than i.MX6 SX. - - To compile this driver as a module, choose M here; the - module will be called snvs_pwrkey. - -config KEYBOARD_IMX - tristate "IMX keypad support" - depends on ARCH_MXC - select INPUT_MATRIXKMAP - help - Enable support for IMX keypad port. - - To compile this driver as a module, choose M here: the - module will be called imx_keypad. - -config KEYBOARD_NEWTON - tristate "Newton keyboard" - select SERIO - help - Say Y here if you have a Newton keyboard on a serial port. - - To compile this driver as a module, choose M here: the - module will be called newtonkbd. - -config KEYBOARD_NOMADIK - tristate "ST-Ericsson Nomadik SKE keyboard" - depends on (ARCH_NOMADIK || ARCH_U8500) - select INPUT_MATRIXKMAP - help - Say Y here if you want to use a keypad provided on the SKE controller - used on the Ux500 and Nomadik platforms - - To compile this driver as a module, choose M here: the - module will be called nmk-ske-keypad. - -config KEYBOARD_NSPIRE - tristate "TI-NSPIRE built-in keyboard" - depends on ARCH_NSPIRE && OF - select INPUT_MATRIXKMAP - help - Say Y here if you want to use the built-in keypad on TI-NSPIRE. - - To compile this driver as a module, choose M here: the - module will be called nspire-keypad. - -config KEYBOARD_TEGRA - tristate "NVIDIA Tegra internal matrix keyboard controller support" - depends on ARCH_TEGRA && OF - select INPUT_MATRIXKMAP - help - Say Y here if you want to use a matrix keyboard connected directly - to the internal keyboard controller on Tegra SoCs. - - To compile this driver as a module, choose M here: the - module will be called tegra-kbc. - -config KEYBOARD_OPENCORES - tristate "OpenCores Keyboard Controller" - depends on HAS_IOMEM - help - Say Y here if you want to use the OpenCores Keyboard Controller - http://www.opencores.org/project,keyboardcontroller - - To compile this driver as a module, choose M here; the - module will be called opencores-kbd. - -config KEYBOARD_PXA27x - tristate "PXA27x/PXA3xx keypad support" - depends on PXA27x || PXA3xx || ARCH_MMP - select INPUT_MATRIXKMAP - help - Enable support for PXA27x/PXA3xx keypad controller. - - To compile this driver as a module, choose M here: the - module will be called pxa27x_keypad. - -config KEYBOARD_PXA930_ROTARY - tristate "PXA930/PXA935 Enhanced Rotary Controller Support" - depends on CPU_PXA930 || CPU_PXA935 - help - Enable support for PXA930/PXA935 Enhanced Rotary Controller. - - To compile this driver as a module, choose M here: the - module will be called pxa930_rotary. - -config KEYBOARD_PMIC8XXX - tristate "Qualcomm PMIC8XXX keypad support" - depends on MFD_PM8XXX - select INPUT_MATRIXKMAP - help - Say Y here if you want to enable the driver for the PMIC8XXX - keypad provided as a reference design from Qualcomm. This is intended - to support upto 18x8 matrix based keypad design. - - To compile this driver as a module, choose M here: the module will - be called pmic8xxx-keypad. - -config KEYBOARD_SAMSUNG - tristate "Samsung keypad support" - depends on HAVE_CLK - select INPUT_MATRIXKMAP - help - Say Y here if you want to use the keypad on your Samsung mobile - device. - - To compile this driver as a module, choose M here: the - module will be called samsung-keypad. - -config KEYBOARD_GOLDFISH_EVENTS - depends on GOLDFISH || COMPILE_TEST - tristate "Generic Input Event device for Goldfish" - help - Say Y here to get an input event device for the Goldfish virtual - device emulator. - - To compile this driver as a module, choose M here: the - module will be called goldfish-events. - -config KEYBOARD_STOWAWAY - tristate "Stowaway keyboard" - select SERIO - help - Say Y here if you have a Stowaway keyboard on a serial port. - Stowaway compatible keyboards like Dicota Input-PDA keyboard - are also supported by this driver. - - To compile this driver as a module, choose M here: the - module will be called stowaway. - -config KEYBOARD_ST_KEYSCAN - tristate "STMicroelectronics keyscan support" - depends on ARCH_STI || COMPILE_TEST - select INPUT_MATRIXKMAP - help - Say Y here if you want to use a keypad attached to the keyscan block - on some STMicroelectronics SoC devices. - - To compile this driver as a module, choose M here: the - module will be called st-keyscan. - -config KEYBOARD_SUNKBD - tristate "Sun Type 4 and Type 5 keyboard" - select SERIO - help - Say Y here if you want to use a Sun Type 4 or Type 5 keyboard, - connected either to the Sun keyboard connector or to an serial - (RS-232) port via a simple adapter. - - To compile this driver as a module, choose M here: the - module will be called sunkbd. - -config KEYBOARD_SH_KEYSC - tristate "SuperH KEYSC keypad support" - depends on ARCH_SHMOBILE || COMPILE_TEST - help - Say Y here if you want to use a keypad attached to the KEYSC block - on SuperH processors such as sh7722 and sh7343. - - To compile this driver as a module, choose M here: the - module will be called sh_keysc. - -config KEYBOARD_STMPE - tristate "STMPE keypad support" - depends on MFD_STMPE - depends on OF - select INPUT_MATRIXKMAP - help - Say Y here if you want to use the keypad controller on STMPE I/O - expanders. - - To compile this driver as a module, choose M here: the module will be - called stmpe-keypad. - -config KEYBOARD_SUN4I_LRADC - tristate "Allwinner sun4i low res adc attached tablet keys support" - depends on ARCH_SUNXI - help - This selects support for the Allwinner low res adc attached tablet - keys found on Allwinner sunxi SoCs. - - To compile this driver as a module, choose M here: the - module will be called sun4i-lradc-keys. - -config KEYBOARD_DAVINCI - tristate "TI DaVinci Key Scan" - depends on ARCH_DAVINCI_DM365 - help - Say Y to enable keypad module support for the TI DaVinci - platforms (DM365). - - To compile this driver as a module, choose M here: the - module will be called davinci_keyscan. - -config KEYBOARD_IPAQ_MICRO - tristate "Buttons on Micro SoC (iPaq h3100,h3600,h3700)" - depends on MFD_IPAQ_MICRO - help - Say Y to enable support for the buttons attached to - Micro peripheral controller on iPAQ h3100/h3600/h3700 - - To compile this driver as a module, choose M here: the - module will be called ipaq-micro-keys. - -config KEYBOARD_OMAP - tristate "TI OMAP keypad support" - depends on ARCH_OMAP1 - select INPUT_MATRIXKMAP - help - Say Y here if you want to use the OMAP keypad. - - To compile this driver as a module, choose M here: the - module will be called omap-keypad. - -config KEYBOARD_OMAP4 - tristate "TI OMAP4+ keypad support" - depends on OF || ARCH_OMAP2PLUS - select INPUT_MATRIXKMAP - help - Say Y here if you want to use the OMAP4+ keypad. - - To compile this driver as a module, choose M here: the - module will be called omap4-keypad. - -config KEYBOARD_SPEAR - tristate "ST SPEAR keyboard support" - depends on PLAT_SPEAR - select INPUT_MATRIXKMAP - help - Say Y here if you want to use the SPEAR keyboard. - - To compile this driver as a module, choose M here: the - module will be called spear-keboard. - -config KEYBOARD_TC3589X - tristate "TC3589X Keypad support" - depends on MFD_TC3589X - select INPUT_MATRIXKMAP - help - Say Y here if you want to use the keypad controller on - TC35892/3 I/O expander. - - To compile this driver as a module, choose M here: the - module will be called tc3589x-keypad. - -config KEYBOARD_TWL4030 - tristate "TI TWL4030/TWL5030/TPS659x0 keypad support" - depends on TWL4030_CORE - select INPUT_MATRIXKMAP - help - Say Y here if your board use the keypad controller on - TWL4030 family chips. It's safe to say enable this - even on boards that don't use the keypad controller. - - To compile this driver as a module, choose M here: the - module will be called twl4030_keypad. - -config KEYBOARD_XTKBD - tristate "XT keyboard" - select SERIO - help - Say Y here if you want to use the old IBM PC/XT keyboard (or - compatible) on your system. This is only possible with a - parallel port keyboard adapter, you cannot connect it to the - keyboard port on a PC that runs Linux. - - To compile this driver as a module, choose M here: the - module will be called xtkbd. - -config KEYBOARD_W90P910 - tristate "W90P910 Matrix Keypad support" - depends on ARCH_W90X900 - select INPUT_MATRIXKMAP - help - Say Y here to enable the matrix keypad on evaluation board - based on W90P910. - - To compile this driver as a module, choose M here: the - module will be called w90p910_keypad. - -config KEYBOARD_CROS_EC - tristate "ChromeOS EC keyboard" - select INPUT_MATRIXKMAP - depends on MFD_CROS_EC - help - Say Y here to enable the matrix keyboard used by ChromeOS devices - and implemented on the ChromeOS EC. You must enable one bus option - (MFD_CROS_EC_I2C or MFD_CROS_EC_SPI) to use this. - - To compile this driver as a module, choose M here: the - module will be called cros_ec_keyb. - -config KEYBOARD_CAP11XX - tristate "Microchip CAP11XX based touch sensors" - depends on OF && I2C - select REGMAP_I2C - help - Say Y here to enable the CAP11XX touch sensor driver. - - To compile this driver as a module, choose M here: the - module will be called cap11xx. - -config KEYBOARD_BCM - tristate "Broadcom keypad driver" - depends on OF && HAVE_CLK - select INPUT_MATRIXKMAP - default ARCH_BCM_CYGNUS - help - Say Y here if you want to use Broadcom keypad. - - To compile this driver as a module, choose M here: the - module will be called bcm-keypad. - -endif diff --git a/src/linux/drivers/input/keyboard/Makefile b/src/linux/drivers/input/keyboard/Makefile deleted file mode 100644 index d9f4cfc..0000000 --- a/src/linux/drivers/input/keyboard/Makefile +++ /dev/null @@ -1,66 +0,0 @@ -# -# Makefile for the input core drivers. -# - -# Each configuration option enables a list of files. - -obj-$(CONFIG_KEYBOARD_ADC) += adc-keys.o -obj-$(CONFIG_KEYBOARD_ADP5520) += adp5520-keys.o -obj-$(CONFIG_KEYBOARD_ADP5588) += adp5588-keys.o -obj-$(CONFIG_KEYBOARD_ADP5589) += adp5589-keys.o -obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o -obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o -obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o -obj-$(CONFIG_KEYBOARD_BCM) += bcm-keypad.o -obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o -obj-$(CONFIG_KEYBOARD_CAP11XX) += cap11xx.o -obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o -obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o -obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o -obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o -obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o -obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o -obj-$(CONFIG_KEYBOARD_GPIO_POLLED) += gpio_keys_polled.o -obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o -obj-$(CONFIG_KEYBOARD_TCA8418) += tca8418_keypad.o -obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o -obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o -obj-$(CONFIG_KEYBOARD_IPAQ_MICRO) += ipaq-micro-keys.o -obj-$(CONFIG_KEYBOARD_IMX) += imx_keypad.o -obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o -obj-$(CONFIG_KEYBOARD_HP7XX) += jornada720_kbd.o -obj-$(CONFIG_KEYBOARD_LKKBD) += lkkbd.o -obj-$(CONFIG_KEYBOARD_LM8323) += lm8323.o -obj-$(CONFIG_KEYBOARD_LM8333) += lm8333.o -obj-$(CONFIG_KEYBOARD_LOCOMO) += locomokbd.o -obj-$(CONFIG_KEYBOARD_LPC32XX) += lpc32xx-keys.o -obj-$(CONFIG_KEYBOARD_MAPLE) += maple_keyb.o -obj-$(CONFIG_KEYBOARD_MATRIX) += matrix_keypad.o -obj-$(CONFIG_KEYBOARD_MAX7359) += max7359_keypad.o -obj-$(CONFIG_KEYBOARD_MCS) += mcs_touchkey.o -obj-$(CONFIG_KEYBOARD_MPR121) += mpr121_touchkey.o -obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o -obj-$(CONFIG_KEYBOARD_NOMADIK) += nomadik-ske-keypad.o -obj-$(CONFIG_KEYBOARD_NSPIRE) += nspire-keypad.o -obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o -obj-$(CONFIG_KEYBOARD_OMAP4) += omap4-keypad.o -obj-$(CONFIG_KEYBOARD_OPENCORES) += opencores-kbd.o -obj-$(CONFIG_KEYBOARD_PMIC8XXX) += pmic8xxx-keypad.o -obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o -obj-$(CONFIG_KEYBOARD_PXA930_ROTARY) += pxa930_rotary.o -obj-$(CONFIG_KEYBOARD_QT1070) += qt1070.o -obj-$(CONFIG_KEYBOARD_QT2160) += qt2160.o -obj-$(CONFIG_KEYBOARD_SAMSUNG) += samsung-keypad.o -obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o -obj-$(CONFIG_KEYBOARD_SNVS_PWRKEY) += snvs_pwrkey.o -obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o -obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o -obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o -obj-$(CONFIG_KEYBOARD_ST_KEYSCAN) += st-keyscan.o -obj-$(CONFIG_KEYBOARD_SUN4I_LRADC) += sun4i-lradc-keys.o -obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o -obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o -obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o -obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o -obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o -obj-$(CONFIG_KEYBOARD_W90P910) += w90p910_keypad.o diff --git a/src/linux/drivers/input/keyboard/atkbd.c b/src/linux/drivers/input/keyboard/atkbd.c deleted file mode 100644 index ec876b5..0000000 --- a/src/linux/drivers/input/keyboard/atkbd.c +++ /dev/null @@ -1,1821 +0,0 @@ -/* - * AT and PS/2 keyboard driver - * - * Copyright (c) 1999-2002 Vojtech Pavlik - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -/* - * This driver can handle standard AT keyboards and PS/2 keyboards in - * Translated and Raw Set 2 and Set 3, as well as AT keyboards on dumb - * input-only controllers and AT keyboards connected over a one way RS232 - * converter. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_DESC "AT and PS/2 keyboard driver" - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -static int atkbd_set = 2; -module_param_named(set, atkbd_set, int, 0); -MODULE_PARM_DESC(set, "Select keyboard code set (2 = default, 3 = PS/2 native)"); - -#if defined(__i386__) || defined(__x86_64__) || defined(__hppa__) -static bool atkbd_reset; -#else -static bool atkbd_reset = true; -#endif -module_param_named(reset, atkbd_reset, bool, 0); -MODULE_PARM_DESC(reset, "Reset keyboard during initialization"); - -static bool atkbd_softrepeat; -module_param_named(softrepeat, atkbd_softrepeat, bool, 0); -MODULE_PARM_DESC(softrepeat, "Use software keyboard repeat"); - -static bool atkbd_softraw = true; -module_param_named(softraw, atkbd_softraw, bool, 0); -MODULE_PARM_DESC(softraw, "Use software generated rawmode"); - -static bool atkbd_scroll; -module_param_named(scroll, atkbd_scroll, bool, 0); -MODULE_PARM_DESC(scroll, "Enable scroll-wheel on MS Office and similar keyboards"); - -static bool atkbd_extra; -module_param_named(extra, atkbd_extra, bool, 0); -MODULE_PARM_DESC(extra, "Enable extra LEDs and keys on IBM RapidAcces, EzKey and similar keyboards"); - -static bool atkbd_terminal; -module_param_named(terminal, atkbd_terminal, bool, 0); -MODULE_PARM_DESC(terminal, "Enable break codes on an IBM Terminal keyboard connected via AT/PS2"); - -/* - * Scancode to keycode tables. These are just the default setting, and - * are loadable via a userland utility. - */ - -#define ATKBD_KEYMAP_SIZE 512 - -static const unsigned short atkbd_set2_keycode[ATKBD_KEYMAP_SIZE] = { - -#ifdef CONFIG_KEYBOARD_ATKBD_HP_KEYCODES - -/* XXX: need a more general approach */ - -#include "hpps2atkbd.h" /* include the keyboard scancodes */ - -#else - 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117, - 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0, - 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183, - 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185, - 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0, - 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85, - 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0, - 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125, - 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127, - 159, 0,115, 0,164, 0, 0,116,158, 0,172,166, 0, 0, 0,142, - 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0, - 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112, - 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0, - - 0, 0, 0, 65, 99, -#endif -}; - -static const unsigned short atkbd_set3_keycode[ATKBD_KEYMAP_SIZE] = { - - 0, 0, 0, 0, 0, 0, 0, 59, 1,138,128,129,130, 15, 41, 60, - 131, 29, 42, 86, 58, 16, 2, 61,133, 56, 44, 31, 30, 17, 3, 62, - 134, 46, 45, 32, 18, 5, 4, 63,135, 57, 47, 33, 20, 19, 6, 64, - 136, 49, 48, 35, 34, 21, 7, 65,137,100, 50, 36, 22, 8, 9, 66, - 125, 51, 37, 23, 24, 11, 10, 67,126, 52, 53, 38, 39, 25, 12, 68, - 113,114, 40, 43, 26, 13, 87, 99, 97, 54, 28, 27, 43, 43, 88, 70, - 108,105,119,103,111,107, 14,110, 0, 79,106, 75, 71,109,102,104, - 82, 83, 80, 76, 77, 72, 69, 98, 0, 96, 81, 0, 78, 73, 55,183, - - 184,185,186,187, 74, 94, 92, 93, 0, 0, 0,125,126,127,112, 0, - 0,139,172,163,165,115,152,172,166,140,160,154,113,114,167,168, - 148,149,147,140 -}; - -static const unsigned short atkbd_unxlate_table[128] = { - 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13, - 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27, - 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42, - 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3, - 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105, - 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63, - 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111, - 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110 -}; - -#define ATKBD_CMD_SETLEDS 0x10ed -#define ATKBD_CMD_GSCANSET 0x11f0 -#define ATKBD_CMD_SSCANSET 0x10f0 -#define ATKBD_CMD_GETID 0x02f2 -#define ATKBD_CMD_SETREP 0x10f3 -#define ATKBD_CMD_ENABLE 0x00f4 -#define ATKBD_CMD_RESET_DIS 0x00f5 /* Reset to defaults and disable */ -#define ATKBD_CMD_RESET_DEF 0x00f6 /* Reset to defaults */ -#define ATKBD_CMD_SETALL_MB 0x00f8 /* Set all keys to give break codes */ -#define ATKBD_CMD_SETALL_MBR 0x00fa /* ... and repeat */ -#define ATKBD_CMD_RESET_BAT 0x02ff -#define ATKBD_CMD_RESEND 0x00fe -#define ATKBD_CMD_EX_ENABLE 0x10ea -#define ATKBD_CMD_EX_SETLEDS 0x20eb -#define ATKBD_CMD_OK_GETID 0x02e8 - -#define ATKBD_RET_ACK 0xfa -#define ATKBD_RET_NAK 0xfe -#define ATKBD_RET_BAT 0xaa -#define ATKBD_RET_EMUL0 0xe0 -#define ATKBD_RET_EMUL1 0xe1 -#define ATKBD_RET_RELEASE 0xf0 -#define ATKBD_RET_HANJA 0xf1 -#define ATKBD_RET_HANGEUL 0xf2 -#define ATKBD_RET_ERR 0xff - -#define ATKBD_KEY_UNKNOWN 0 -#define ATKBD_KEY_NULL 255 - -#define ATKBD_SCR_1 0xfffe -#define ATKBD_SCR_2 0xfffd -#define ATKBD_SCR_4 0xfffc -#define ATKBD_SCR_8 0xfffb -#define ATKBD_SCR_CLICK 0xfffa -#define ATKBD_SCR_LEFT 0xfff9 -#define ATKBD_SCR_RIGHT 0xfff8 - -#define ATKBD_SPECIAL ATKBD_SCR_RIGHT - -#define ATKBD_LED_EVENT_BIT 0 -#define ATKBD_REP_EVENT_BIT 1 - -#define ATKBD_XL_ERR 0x01 -#define ATKBD_XL_BAT 0x02 -#define ATKBD_XL_ACK 0x04 -#define ATKBD_XL_NAK 0x08 -#define ATKBD_XL_HANGEUL 0x10 -#define ATKBD_XL_HANJA 0x20 - -static const struct { - unsigned short keycode; - unsigned char set2; -} atkbd_scroll_keys[] = { - { ATKBD_SCR_1, 0xc5 }, - { ATKBD_SCR_2, 0x9d }, - { ATKBD_SCR_4, 0xa4 }, - { ATKBD_SCR_8, 0x9b }, - { ATKBD_SCR_CLICK, 0xe0 }, - { ATKBD_SCR_LEFT, 0xcb }, - { ATKBD_SCR_RIGHT, 0xd2 }, -}; - -/* - * The atkbd control structure - */ - -struct atkbd { - - struct ps2dev ps2dev; - struct input_dev *dev; - - /* Written only during init */ - char name[64]; - char phys[32]; - - unsigned short id; - unsigned short keycode[ATKBD_KEYMAP_SIZE]; - DECLARE_BITMAP(force_release_mask, ATKBD_KEYMAP_SIZE); - unsigned char set; - bool translated; - bool extra; - bool write; - bool softrepeat; - bool softraw; - bool scroll; - bool enabled; - - /* Accessed only from interrupt */ - unsigned char emul; - bool resend; - bool release; - unsigned long xl_bit; - unsigned int last; - unsigned long time; - unsigned long err_count; - - struct delayed_work event_work; - unsigned long event_jiffies; - unsigned long event_mask; - - /* Serializes reconnect(), attr->set() and event work */ - struct mutex mutex; -}; - -/* - * System-specific keymap fixup routine - */ -static void (*atkbd_platform_fixup)(struct atkbd *, const void *data); -static void *atkbd_platform_fixup_data; -static unsigned int (*atkbd_platform_scancode_fixup)(struct atkbd *, unsigned int); - -/* - * Certain keyboards to not like ATKBD_CMD_RESET_DIS and stop responding - * to many commands until full reset (ATKBD_CMD_RESET_BAT) is performed. - */ -static bool atkbd_skip_deactivate; - -static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, - ssize_t (*handler)(struct atkbd *, char *)); -static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count, - ssize_t (*handler)(struct atkbd *, const char *, size_t)); -#define ATKBD_DEFINE_ATTR(_name) \ -static ssize_t atkbd_show_##_name(struct atkbd *, char *); \ -static ssize_t atkbd_set_##_name(struct atkbd *, const char *, size_t); \ -static ssize_t atkbd_do_show_##_name(struct device *d, \ - struct device_attribute *attr, char *b) \ -{ \ - return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \ -} \ -static ssize_t atkbd_do_set_##_name(struct device *d, \ - struct device_attribute *attr, const char *b, size_t s) \ -{ \ - return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \ -} \ -static struct device_attribute atkbd_attr_##_name = \ - __ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name); - -ATKBD_DEFINE_ATTR(extra); -ATKBD_DEFINE_ATTR(force_release); -ATKBD_DEFINE_ATTR(scroll); -ATKBD_DEFINE_ATTR(set); -ATKBD_DEFINE_ATTR(softrepeat); -ATKBD_DEFINE_ATTR(softraw); - -#define ATKBD_DEFINE_RO_ATTR(_name) \ -static ssize_t atkbd_show_##_name(struct atkbd *, char *); \ -static ssize_t atkbd_do_show_##_name(struct device *d, \ - struct device_attribute *attr, char *b) \ -{ \ - return atkbd_attr_show_helper(d, b, atkbd_show_##_name); \ -} \ -static struct device_attribute atkbd_attr_##_name = \ - __ATTR(_name, S_IRUGO, atkbd_do_show_##_name, NULL); - -ATKBD_DEFINE_RO_ATTR(err_count); - -static struct attribute *atkbd_attributes[] = { - &atkbd_attr_extra.attr, - &atkbd_attr_force_release.attr, - &atkbd_attr_scroll.attr, - &atkbd_attr_set.attr, - &atkbd_attr_softrepeat.attr, - &atkbd_attr_softraw.attr, - &atkbd_attr_err_count.attr, - NULL -}; - -static struct attribute_group atkbd_attribute_group = { - .attrs = atkbd_attributes, -}; - -static const unsigned int xl_table[] = { - ATKBD_RET_BAT, ATKBD_RET_ERR, ATKBD_RET_ACK, - ATKBD_RET_NAK, ATKBD_RET_HANJA, ATKBD_RET_HANGEUL, -}; - -/* - * Checks if we should mangle the scancode to extract 'release' bit - * in translated mode. - */ -static bool atkbd_need_xlate(unsigned long xl_bit, unsigned char code) -{ - int i; - - if (code == ATKBD_RET_EMUL0 || code == ATKBD_RET_EMUL1) - return false; - - for (i = 0; i < ARRAY_SIZE(xl_table); i++) - if (code == xl_table[i]) - return test_bit(i, &xl_bit); - - return true; -} - -/* - * Calculates new value of xl_bit so the driver can distinguish - * between make/break pair of scancodes for select keys and PS/2 - * protocol responses. - */ -static void atkbd_calculate_xl_bit(struct atkbd *atkbd, unsigned char code) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(xl_table); i++) { - if (!((code ^ xl_table[i]) & 0x7f)) { - if (code & 0x80) - __clear_bit(i, &atkbd->xl_bit); - else - __set_bit(i, &atkbd->xl_bit); - break; - } - } -} - -/* - * Encode the scancode, 0xe0 prefix, and high bit into a single integer, - * keeping kernel 2.4 compatibility for set 2 - */ -static unsigned int atkbd_compat_scancode(struct atkbd *atkbd, unsigned int code) -{ - if (atkbd->set == 3) { - if (atkbd->emul == 1) - code |= 0x100; - } else { - code = (code & 0x7f) | ((code & 0x80) << 1); - if (atkbd->emul == 1) - code |= 0x80; - } - - return code; -} - -/* - * atkbd_interrupt(). Here takes place processing of data received from - * the keyboard into events. - */ - -static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data, - unsigned int flags) -{ - struct atkbd *atkbd = serio_get_drvdata(serio); - struct input_dev *dev = atkbd->dev; - unsigned int code = data; - int scroll = 0, hscroll = 0, click = -1; - int value; - unsigned short keycode; - - dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, flags); - -#if !defined(__i386__) && !defined (__x86_64__) - if ((flags & (SERIO_FRAME | SERIO_PARITY)) && (~flags & SERIO_TIMEOUT) && !atkbd->resend && atkbd->write) { - dev_warn(&serio->dev, "Frame/parity error: %02x\n", flags); - serio_write(serio, ATKBD_CMD_RESEND); - atkbd->resend = true; - goto out; - } - - if (!flags && data == ATKBD_RET_ACK) - atkbd->resend = false; -#endif - - if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_ACK)) - if (ps2_handle_ack(&atkbd->ps2dev, data)) - goto out; - - if (unlikely(atkbd->ps2dev.flags & PS2_FLAG_CMD)) - if (ps2_handle_response(&atkbd->ps2dev, data)) - goto out; - - if (!atkbd->enabled) - goto out; - - input_event(dev, EV_MSC, MSC_RAW, code); - - if (atkbd_platform_scancode_fixup) - code = atkbd_platform_scancode_fixup(atkbd, code); - - if (atkbd->translated) { - - if (atkbd->emul || atkbd_need_xlate(atkbd->xl_bit, code)) { - atkbd->release = code >> 7; - code &= 0x7f; - } - - if (!atkbd->emul) - atkbd_calculate_xl_bit(atkbd, data); - } - - switch (code) { - case ATKBD_RET_BAT: - atkbd->enabled = false; - serio_reconnect(atkbd->ps2dev.serio); - goto out; - case ATKBD_RET_EMUL0: - atkbd->emul = 1; - goto out; - case ATKBD_RET_EMUL1: - atkbd->emul = 2; - goto out; - case ATKBD_RET_RELEASE: - atkbd->release = true; - goto out; - case ATKBD_RET_ACK: - case ATKBD_RET_NAK: - if (printk_ratelimit()) - dev_warn(&serio->dev, - "Spurious %s on %s. " - "Some program might be trying to access hardware directly.\n", - data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); - goto out; - case ATKBD_RET_ERR: - atkbd->err_count++; - dev_dbg(&serio->dev, "Keyboard on %s reports too many keys pressed.\n", - serio->phys); - goto out; - } - - code = atkbd_compat_scancode(atkbd, code); - - if (atkbd->emul && --atkbd->emul) - goto out; - - keycode = atkbd->keycode[code]; - - if (!(atkbd->release && test_bit(code, atkbd->force_release_mask))) - if (keycode != ATKBD_KEY_NULL) - input_event(dev, EV_MSC, MSC_SCAN, code); - - switch (keycode) { - case ATKBD_KEY_NULL: - break; - case ATKBD_KEY_UNKNOWN: - dev_warn(&serio->dev, - "Unknown key %s (%s set %d, code %#x on %s).\n", - atkbd->release ? "released" : "pressed", - atkbd->translated ? "translated" : "raw", - atkbd->set, code, serio->phys); - dev_warn(&serio->dev, - "Use 'setkeycodes %s%02x ' to make it known.\n", - code & 0x80 ? "e0" : "", code & 0x7f); - input_sync(dev); - break; - case ATKBD_SCR_1: - scroll = 1; - break; - case ATKBD_SCR_2: - scroll = 2; - break; - case ATKBD_SCR_4: - scroll = 4; - break; - case ATKBD_SCR_8: - scroll = 8; - break; - case ATKBD_SCR_CLICK: - click = !atkbd->release; - break; - case ATKBD_SCR_LEFT: - hscroll = -1; - break; - case ATKBD_SCR_RIGHT: - hscroll = 1; - break; - default: - if (atkbd->release) { - value = 0; - atkbd->last = 0; - } else if (!atkbd->softrepeat && test_bit(keycode, dev->key)) { - /* Workaround Toshiba laptop multiple keypress */ - value = time_before(jiffies, atkbd->time) && atkbd->last == code ? 1 : 2; - } else { - value = 1; - atkbd->last = code; - atkbd->time = jiffies + msecs_to_jiffies(dev->rep[REP_DELAY]) / 2; - } - - input_event(dev, EV_KEY, keycode, value); - input_sync(dev); - - if (value && test_bit(code, atkbd->force_release_mask)) { - input_event(dev, EV_MSC, MSC_SCAN, code); - input_report_key(dev, keycode, 0); - input_sync(dev); - } - } - - if (atkbd->scroll) { - if (click != -1) - input_report_key(dev, BTN_MIDDLE, click); - input_report_rel(dev, REL_WHEEL, - atkbd->release ? -scroll : scroll); - input_report_rel(dev, REL_HWHEEL, hscroll); - input_sync(dev); - } - - atkbd->release = false; -out: - return IRQ_HANDLED; -} - -static int atkbd_set_repeat_rate(struct atkbd *atkbd) -{ - const short period[32] = - { 33, 37, 42, 46, 50, 54, 58, 63, 67, 75, 83, 92, 100, 109, 116, 125, - 133, 149, 167, 182, 200, 217, 232, 250, 270, 303, 333, 370, 400, 435, 470, 500 }; - const short delay[4] = - { 250, 500, 750, 1000 }; - - struct input_dev *dev = atkbd->dev; - unsigned char param; - int i = 0, j = 0; - - while (i < ARRAY_SIZE(period) - 1 && period[i] < dev->rep[REP_PERIOD]) - i++; - dev->rep[REP_PERIOD] = period[i]; - - while (j < ARRAY_SIZE(delay) - 1 && delay[j] < dev->rep[REP_DELAY]) - j++; - dev->rep[REP_DELAY] = delay[j]; - - param = i | (j << 5); - return ps2_command(&atkbd->ps2dev, ¶m, ATKBD_CMD_SETREP); -} - -static int atkbd_set_leds(struct atkbd *atkbd) -{ - struct input_dev *dev = atkbd->dev; - unsigned char param[2]; - - param[0] = (test_bit(LED_SCROLLL, dev->led) ? 1 : 0) - | (test_bit(LED_NUML, dev->led) ? 2 : 0) - | (test_bit(LED_CAPSL, dev->led) ? 4 : 0); - if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_SETLEDS)) - return -1; - - if (atkbd->extra) { - param[0] = 0; - param[1] = (test_bit(LED_COMPOSE, dev->led) ? 0x01 : 0) - | (test_bit(LED_SLEEP, dev->led) ? 0x02 : 0) - | (test_bit(LED_SUSPEND, dev->led) ? 0x04 : 0) - | (test_bit(LED_MISC, dev->led) ? 0x10 : 0) - | (test_bit(LED_MUTE, dev->led) ? 0x20 : 0); - if (ps2_command(&atkbd->ps2dev, param, ATKBD_CMD_EX_SETLEDS)) - return -1; - } - - return 0; -} - -/* - * atkbd_event_work() is used to complete processing of events that - * can not be processed by input_event() which is often called from - * interrupt context. - */ - -static void atkbd_event_work(struct work_struct *work) -{ - struct atkbd *atkbd = container_of(work, struct atkbd, event_work.work); - - mutex_lock(&atkbd->mutex); - - if (!atkbd->enabled) { - /* - * Serio ports are resumed asynchronously so while driver core - * thinks that device is already fully operational in reality - * it may not be ready yet. In this case we need to keep - * rescheduling till reconnect completes. - */ - schedule_delayed_work(&atkbd->event_work, - msecs_to_jiffies(100)); - } else { - if (test_and_clear_bit(ATKBD_LED_EVENT_BIT, &atkbd->event_mask)) - atkbd_set_leds(atkbd); - - if (test_and_clear_bit(ATKBD_REP_EVENT_BIT, &atkbd->event_mask)) - atkbd_set_repeat_rate(atkbd); - } - - mutex_unlock(&atkbd->mutex); -} - -/* - * Schedule switch for execution. We need to throttle requests, - * otherwise keyboard may become unresponsive. - */ -static void atkbd_schedule_event_work(struct atkbd *atkbd, int event_bit) -{ - unsigned long delay = msecs_to_jiffies(50); - - if (time_after(jiffies, atkbd->event_jiffies + delay)) - delay = 0; - - atkbd->event_jiffies = jiffies; - set_bit(event_bit, &atkbd->event_mask); - mb(); - schedule_delayed_work(&atkbd->event_work, delay); -} - -/* - * Event callback from the input module. Events that change the state of - * the hardware are processed here. If action can not be performed in - * interrupt context it is offloaded to atkbd_event_work. - */ - -static int atkbd_event(struct input_dev *dev, - unsigned int type, unsigned int code, int value) -{ - struct atkbd *atkbd = input_get_drvdata(dev); - - if (!atkbd->write) - return -1; - - switch (type) { - - case EV_LED: - atkbd_schedule_event_work(atkbd, ATKBD_LED_EVENT_BIT); - return 0; - - case EV_REP: - if (!atkbd->softrepeat) - atkbd_schedule_event_work(atkbd, ATKBD_REP_EVENT_BIT); - return 0; - - default: - return -1; - } -} - -/* - * atkbd_enable() signals that interrupt handler is allowed to - * generate input events. - */ - -static inline void atkbd_enable(struct atkbd *atkbd) -{ - serio_pause_rx(atkbd->ps2dev.serio); - atkbd->enabled = true; - serio_continue_rx(atkbd->ps2dev.serio); -} - -/* - * atkbd_disable() tells input handler that all incoming data except - * for ACKs and command response should be dropped. - */ - -static inline void atkbd_disable(struct atkbd *atkbd) -{ - serio_pause_rx(atkbd->ps2dev.serio); - atkbd->enabled = false; - serio_continue_rx(atkbd->ps2dev.serio); -} - -static int atkbd_activate(struct atkbd *atkbd) -{ - struct ps2dev *ps2dev = &atkbd->ps2dev; - -/* - * Enable the keyboard to receive keystrokes. - */ - - if (ps2_command(ps2dev, NULL, ATKBD_CMD_ENABLE)) { - dev_err(&ps2dev->serio->dev, - "Failed to enable keyboard on %s\n", - ps2dev->serio->phys); - return -1; - } - - return 0; -} - -/* - * atkbd_deactivate() resets and disables the keyboard from sending - * keystrokes. - */ - -static void atkbd_deactivate(struct atkbd *atkbd) -{ - struct ps2dev *ps2dev = &atkbd->ps2dev; - - if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_DIS)) - dev_err(&ps2dev->serio->dev, - "Failed to deactivate keyboard on %s\n", - ps2dev->serio->phys); -} - -/* - * atkbd_probe() probes for an AT keyboard on a serio port. - */ - -static int atkbd_probe(struct atkbd *atkbd) -{ - struct ps2dev *ps2dev = &atkbd->ps2dev; - unsigned char param[2]; - -/* - * Some systems, where the bit-twiddling when testing the io-lines of the - * controller may confuse the keyboard need a full reset of the keyboard. On - * these systems the BIOS also usually doesn't do it for us. - */ - - if (atkbd_reset) - if (ps2_command(ps2dev, NULL, ATKBD_CMD_RESET_BAT)) - dev_warn(&ps2dev->serio->dev, - "keyboard reset failed on %s\n", - ps2dev->serio->phys); - -/* - * Then we check the keyboard ID. We should get 0xab83 under normal conditions. - * Some keyboards report different values, but the first byte is always 0xab or - * 0xac. Some old AT keyboards don't report anything. If a mouse is connected, this - * should make sure we don't try to set the LEDs on it. - */ - - param[0] = param[1] = 0xa5; /* initialize with invalid values */ - if (ps2_command(ps2dev, param, ATKBD_CMD_GETID)) { - -/* - * If the get ID command failed, we check if we can at least set the LEDs on - * the keyboard. This should work on every keyboard out there. It also turns - * the LEDs off, which we want anyway. - */ - param[0] = 0; - if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS)) - return -1; - atkbd->id = 0xabba; - return 0; - } - - if (!ps2_is_keyboard_id(param[0])) - return -1; - - atkbd->id = (param[0] << 8) | param[1]; - - if (atkbd->id == 0xaca1 && atkbd->translated) { - dev_err(&ps2dev->serio->dev, - "NCD terminal keyboards are only supported on non-translating controllers. " - "Use i8042.direct=1 to disable translation.\n"); - return -1; - } - -/* - * Make sure nothing is coming from the keyboard and disturbs our - * internal state. - */ - if (!atkbd_skip_deactivate) - atkbd_deactivate(atkbd); - - return 0; -} - -/* - * atkbd_select_set checks if a keyboard has a working Set 3 support, and - * sets it into that. Unfortunately there are keyboards that can be switched - * to Set 3, but don't work well in that (BTC Multimedia ...) - */ - -static int atkbd_select_set(struct atkbd *atkbd, int target_set, int allow_extra) -{ - struct ps2dev *ps2dev = &atkbd->ps2dev; - unsigned char param[2]; - - atkbd->extra = false; -/* - * For known special keyboards we can go ahead and set the correct set. - * We check for NCD PS/2 Sun, NorthGate OmniKey 101 and - * IBM RapidAccess / IBM EzButton / Chicony KBP-8993 keyboards. - */ - - if (atkbd->translated) - return 2; - - if (atkbd->id == 0xaca1) { - param[0] = 3; - ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET); - return 3; - } - - if (allow_extra) { - param[0] = 0x71; - if (!ps2_command(ps2dev, param, ATKBD_CMD_EX_ENABLE)) { - atkbd->extra = true; - return 2; - } - } - - if (atkbd_terminal) { - ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MB); - return 3; - } - - if (target_set != 3) - return 2; - - if (!ps2_command(ps2dev, param, ATKBD_CMD_OK_GETID)) { - atkbd->id = param[0] << 8 | param[1]; - return 2; - } - - param[0] = 3; - if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET)) - return 2; - - param[0] = 0; - if (ps2_command(ps2dev, param, ATKBD_CMD_GSCANSET)) - return 2; - - if (param[0] != 3) { - param[0] = 2; - if (ps2_command(ps2dev, param, ATKBD_CMD_SSCANSET)) - return 2; - } - - ps2_command(ps2dev, param, ATKBD_CMD_SETALL_MBR); - - return 3; -} - -static int atkbd_reset_state(struct atkbd *atkbd) -{ - struct ps2dev *ps2dev = &atkbd->ps2dev; - unsigned char param[1]; - -/* - * Set the LEDs to a predefined state (all off). - */ - - param[0] = 0; - if (ps2_command(ps2dev, param, ATKBD_CMD_SETLEDS)) - return -1; - -/* - * Set autorepeat to fastest possible. - */ - - param[0] = 0; - if (ps2_command(ps2dev, param, ATKBD_CMD_SETREP)) - return -1; - - return 0; -} - -/* - * atkbd_cleanup() restores the keyboard state so that BIOS is happy after a - * reboot. - */ - -static void atkbd_cleanup(struct serio *serio) -{ - struct atkbd *atkbd = serio_get_drvdata(serio); - - atkbd_disable(atkbd); - ps2_command(&atkbd->ps2dev, NULL, ATKBD_CMD_RESET_DEF); -} - - -/* - * atkbd_disconnect() closes and frees. - */ - -static void atkbd_disconnect(struct serio *serio) -{ - struct atkbd *atkbd = serio_get_drvdata(serio); - - sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group); - - atkbd_disable(atkbd); - - input_unregister_device(atkbd->dev); - - /* - * Make sure we don't have a command in flight. - * Note that since atkbd->enabled is false event work will keep - * rescheduling itself until it gets canceled and will not try - * accessing freed input device or serio port. - */ - cancel_delayed_work_sync(&atkbd->event_work); - - serio_close(serio); - serio_set_drvdata(serio, NULL); - kfree(atkbd); -} - -/* - * generate release events for the keycodes given in data - */ -static void atkbd_apply_forced_release_keylist(struct atkbd* atkbd, - const void *data) -{ - const unsigned int *keys = data; - unsigned int i; - - if (atkbd->set == 2) - for (i = 0; keys[i] != -1U; i++) - __set_bit(keys[i], atkbd->force_release_mask); -} - -/* - * Most special keys (Fn+F?) on Dell laptops do not generate release - * events so we have to do it ourselves. - */ -static unsigned int atkbd_dell_laptop_forced_release_keys[] = { - 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93, -1U -}; - -/* - * Perform fixup for HP system that doesn't generate release - * for its video switch - */ -static unsigned int atkbd_hp_forced_release_keys[] = { - 0x94, -1U -}; - -/* - * Samsung NC10,NC20 with Fn+F? key release not working - */ -static unsigned int atkbd_samsung_forced_release_keys[] = { - 0x82, 0x83, 0x84, 0x86, 0x88, 0x89, 0xb3, 0xf7, 0xf9, -1U -}; - -/* - * Amilo Pi 3525 key release for Fn+Volume keys not working - */ -static unsigned int atkbd_amilo_pi3525_forced_release_keys[] = { - 0x20, 0xa0, 0x2e, 0xae, 0x30, 0xb0, -1U -}; - -/* - * Amilo Xi 3650 key release for light touch bar not working - */ -static unsigned int atkbd_amilo_xi3650_forced_release_keys[] = { - 0x67, 0xed, 0x90, 0xa2, 0x99, 0xa4, 0xae, 0xb0, -1U -}; - -/* - * Soltech TA12 system with broken key release on volume keys and mute key - */ -static unsigned int atkdb_soltech_ta12_forced_release_keys[] = { - 0xa0, 0xae, 0xb0, -1U -}; - -/* - * Many notebooks don't send key release event for volume up/down - * keys, with key list below common among them - */ -static unsigned int atkbd_volume_forced_release_keys[] = { - 0xae, 0xb0, -1U -}; - -/* - * OQO 01+ multimedia keys (64--66) generate e0 6x upon release whereas - * they should be generating e4-e6 (0x80 | code). - */ -static unsigned int atkbd_oqo_01plus_scancode_fixup(struct atkbd *atkbd, - unsigned int code) -{ - if (atkbd->translated && atkbd->emul == 1 && - (code == 0x64 || code == 0x65 || code == 0x66)) { - atkbd->emul = 0; - code |= 0x80; - } - - return code; -} - -/* - * atkbd_set_keycode_table() initializes keyboard's keycode table - * according to the selected scancode set - */ - -static void atkbd_set_keycode_table(struct atkbd *atkbd) -{ - unsigned int scancode; - int i, j; - - memset(atkbd->keycode, 0, sizeof(atkbd->keycode)); - bitmap_zero(atkbd->force_release_mask, ATKBD_KEYMAP_SIZE); - - if (atkbd->translated) { - for (i = 0; i < 128; i++) { - scancode = atkbd_unxlate_table[i]; - atkbd->keycode[i] = atkbd_set2_keycode[scancode]; - atkbd->keycode[i | 0x80] = atkbd_set2_keycode[scancode | 0x80]; - if (atkbd->scroll) - for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++) - if ((scancode | 0x80) == atkbd_scroll_keys[j].set2) - atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode; - } - } else if (atkbd->set == 3) { - memcpy(atkbd->keycode, atkbd_set3_keycode, sizeof(atkbd->keycode)); - } else { - memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode)); - - if (atkbd->scroll) - for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) { - scancode = atkbd_scroll_keys[i].set2; - atkbd->keycode[scancode] = atkbd_scroll_keys[i].keycode; - } - } - -/* - * HANGEUL and HANJA keys do not send release events so we need to - * generate such events ourselves - */ - scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL); - atkbd->keycode[scancode] = KEY_HANGEUL; - __set_bit(scancode, atkbd->force_release_mask); - - scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA); - atkbd->keycode[scancode] = KEY_HANJA; - __set_bit(scancode, atkbd->force_release_mask); - -/* - * Perform additional fixups - */ - if (atkbd_platform_fixup) - atkbd_platform_fixup(atkbd, atkbd_platform_fixup_data); -} - -/* - * atkbd_set_device_attrs() sets up keyboard's input device structure - */ - -static void atkbd_set_device_attrs(struct atkbd *atkbd) -{ - struct input_dev *input_dev = atkbd->dev; - int i; - - if (atkbd->extra) - snprintf(atkbd->name, sizeof(atkbd->name), - "AT Set 2 Extra keyboard"); - else - snprintf(atkbd->name, sizeof(atkbd->name), - "AT %s Set %d keyboard", - atkbd->translated ? "Translated" : "Raw", atkbd->set); - - snprintf(atkbd->phys, sizeof(atkbd->phys), - "%s/input0", atkbd->ps2dev.serio->phys); - - input_dev->name = atkbd->name; - input_dev->phys = atkbd->phys; - input_dev->id.bustype = BUS_I8042; - input_dev->id.vendor = 0x0001; - input_dev->id.product = atkbd->translated ? 1 : atkbd->set; - input_dev->id.version = atkbd->id; - input_dev->event = atkbd_event; - input_dev->dev.parent = &atkbd->ps2dev.serio->dev; - - input_set_drvdata(input_dev, atkbd); - - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | - BIT_MASK(EV_MSC); - - if (atkbd->write) { - input_dev->evbit[0] |= BIT_MASK(EV_LED); - input_dev->ledbit[0] = BIT_MASK(LED_NUML) | - BIT_MASK(LED_CAPSL) | BIT_MASK(LED_SCROLLL); - } - - if (atkbd->extra) - input_dev->ledbit[0] |= BIT_MASK(LED_COMPOSE) | - BIT_MASK(LED_SUSPEND) | BIT_MASK(LED_SLEEP) | - BIT_MASK(LED_MUTE) | BIT_MASK(LED_MISC); - - if (!atkbd->softrepeat) { - input_dev->rep[REP_DELAY] = 250; - input_dev->rep[REP_PERIOD] = 33; - } - - input_dev->mscbit[0] = atkbd->softraw ? BIT_MASK(MSC_SCAN) : - BIT_MASK(MSC_RAW) | BIT_MASK(MSC_SCAN); - - if (atkbd->scroll) { - input_dev->evbit[0] |= BIT_MASK(EV_REL); - input_dev->relbit[0] = BIT_MASK(REL_WHEEL) | - BIT_MASK(REL_HWHEEL); - __set_bit(BTN_MIDDLE, input_dev->keybit); - } - - input_dev->keycode = atkbd->keycode; - input_dev->keycodesize = sizeof(unsigned short); - input_dev->keycodemax = ARRAY_SIZE(atkbd_set2_keycode); - - for (i = 0; i < ATKBD_KEYMAP_SIZE; i++) { - if (atkbd->keycode[i] != KEY_RESERVED && - atkbd->keycode[i] != ATKBD_KEY_NULL && - atkbd->keycode[i] < ATKBD_SPECIAL) { - __set_bit(atkbd->keycode[i], input_dev->keybit); - } - } -} - -/* - * atkbd_connect() is called when the serio module finds an interface - * that isn't handled yet by an appropriate device driver. We check if - * there is an AT keyboard out there and if yes, we register ourselves - * to the input module. - */ - -static int atkbd_connect(struct serio *serio, struct serio_driver *drv) -{ - struct atkbd *atkbd; - struct input_dev *dev; - int err = -ENOMEM; - - atkbd = kzalloc(sizeof(struct atkbd), GFP_KERNEL); - dev = input_allocate_device(); - if (!atkbd || !dev) - goto fail1; - - atkbd->dev = dev; - ps2_init(&atkbd->ps2dev, serio); - INIT_DELAYED_WORK(&atkbd->event_work, atkbd_event_work); - mutex_init(&atkbd->mutex); - - switch (serio->id.type) { - - case SERIO_8042_XL: - atkbd->translated = true; - /* Fall through */ - - case SERIO_8042: - if (serio->write) - atkbd->write = true; - break; - } - - atkbd->softraw = atkbd_softraw; - atkbd->softrepeat = atkbd_softrepeat; - atkbd->scroll = atkbd_scroll; - - if (atkbd->softrepeat) - atkbd->softraw = true; - - serio_set_drvdata(serio, atkbd); - - err = serio_open(serio, drv); - if (err) - goto fail2; - - if (atkbd->write) { - - if (atkbd_probe(atkbd)) { - err = -ENODEV; - goto fail3; - } - - atkbd->set = atkbd_select_set(atkbd, atkbd_set, atkbd_extra); - atkbd_reset_state(atkbd); - - } else { - atkbd->set = 2; - atkbd->id = 0xab00; - } - - atkbd_set_keycode_table(atkbd); - atkbd_set_device_attrs(atkbd); - - err = sysfs_create_group(&serio->dev.kobj, &atkbd_attribute_group); - if (err) - goto fail3; - - atkbd_enable(atkbd); - if (serio->write) - atkbd_activate(atkbd); - - err = input_register_device(atkbd->dev); - if (err) - goto fail4; - - return 0; - - fail4: sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group); - fail3: serio_close(serio); - fail2: serio_set_drvdata(serio, NULL); - fail1: input_free_device(dev); - kfree(atkbd); - return err; -} - -/* - * atkbd_reconnect() tries to restore keyboard into a sane state and is - * most likely called on resume. - */ - -static int atkbd_reconnect(struct serio *serio) -{ - struct atkbd *atkbd = serio_get_drvdata(serio); - struct serio_driver *drv = serio->drv; - int retval = -1; - - if (!atkbd || !drv) { - dev_dbg(&serio->dev, - "reconnect request, but serio is disconnected, ignoring...\n"); - return -1; - } - - mutex_lock(&atkbd->mutex); - - atkbd_disable(atkbd); - - if (atkbd->write) { - if (atkbd_probe(atkbd)) - goto out; - - if (atkbd->set != atkbd_select_set(atkbd, atkbd->set, atkbd->extra)) - goto out; - - /* - * Restore LED state and repeat rate. While input core - * will do this for us at resume time reconnect may happen - * because user requested it via sysfs or simply because - * keyboard was unplugged and plugged in again so we need - * to do it ourselves here. - */ - atkbd_set_leds(atkbd); - if (!atkbd->softrepeat) - atkbd_set_repeat_rate(atkbd); - - } - - /* - * Reset our state machine in case reconnect happened in the middle - * of multi-byte scancode. - */ - atkbd->xl_bit = 0; - atkbd->emul = 0; - - atkbd_enable(atkbd); - if (atkbd->write) - atkbd_activate(atkbd); - - retval = 0; - - out: - mutex_unlock(&atkbd->mutex); - return retval; -} - -static struct serio_device_id atkbd_serio_ids[] = { - { - .type = SERIO_8042, - .proto = SERIO_ANY, - .id = SERIO_ANY, - .extra = SERIO_ANY, - }, - { - .type = SERIO_8042_XL, - .proto = SERIO_ANY, - .id = SERIO_ANY, - .extra = SERIO_ANY, - }, - { - .type = SERIO_RS232, - .proto = SERIO_PS2SER, - .id = SERIO_ANY, - .extra = SERIO_ANY, - }, - { 0 } -}; - -MODULE_DEVICE_TABLE(serio, atkbd_serio_ids); - -static struct serio_driver atkbd_drv = { - .driver = { - .name = "atkbd", - }, - .description = DRIVER_DESC, - .id_table = atkbd_serio_ids, - .interrupt = atkbd_interrupt, - .connect = atkbd_connect, - .reconnect = atkbd_reconnect, - .disconnect = atkbd_disconnect, - .cleanup = atkbd_cleanup, -}; - -static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf, - ssize_t (*handler)(struct atkbd *, char *)) -{ - struct serio *serio = to_serio_port(dev); - struct atkbd *atkbd = serio_get_drvdata(serio); - - return handler(atkbd, buf); -} - -static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count, - ssize_t (*handler)(struct atkbd *, const char *, size_t)) -{ - struct serio *serio = to_serio_port(dev); - struct atkbd *atkbd = serio_get_drvdata(serio); - int retval; - - retval = mutex_lock_interruptible(&atkbd->mutex); - if (retval) - return retval; - - atkbd_disable(atkbd); - retval = handler(atkbd, buf, count); - atkbd_enable(atkbd); - - mutex_unlock(&atkbd->mutex); - - return retval; -} - -static ssize_t atkbd_show_extra(struct atkbd *atkbd, char *buf) -{ - return sprintf(buf, "%d\n", atkbd->extra ? 1 : 0); -} - -static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t count) -{ - struct input_dev *old_dev, *new_dev; - unsigned int value; - int err; - bool old_extra; - unsigned char old_set; - - if (!atkbd->write) - return -EIO; - - err = kstrtouint(buf, 10, &value); - if (err) - return err; - - if (value > 1) - return -EINVAL; - - if (atkbd->extra != value) { - /* - * Since device's properties will change we need to - * unregister old device. But allocate and register - * new one first to make sure we have it. - */ - old_dev = atkbd->dev; - old_extra = atkbd->extra; - old_set = atkbd->set; - - new_dev = input_allocate_device(); - if (!new_dev) - return -ENOMEM; - - atkbd->dev = new_dev; - atkbd->set = atkbd_select_set(atkbd, atkbd->set, value); - atkbd_reset_state(atkbd); - atkbd_activate(atkbd); - atkbd_set_keycode_table(atkbd); - atkbd_set_device_attrs(atkbd); - - err = input_register_device(atkbd->dev); - if (err) { - input_free_device(new_dev); - - atkbd->dev = old_dev; - atkbd->set = atkbd_select_set(atkbd, old_set, old_extra); - atkbd_set_keycode_table(atkbd); - atkbd_set_device_attrs(atkbd); - - return err; - } - input_unregister_device(old_dev); - - } - return count; -} - -static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf) -{ - size_t len = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", - ATKBD_KEYMAP_SIZE, atkbd->force_release_mask); - - buf[len++] = '\n'; - buf[len] = '\0'; - - return len; -} - -static ssize_t atkbd_set_force_release(struct atkbd *atkbd, - const char *buf, size_t count) -{ - /* 64 bytes on stack should be acceptable */ - DECLARE_BITMAP(new_mask, ATKBD_KEYMAP_SIZE); - int err; - - err = bitmap_parselist(buf, new_mask, ATKBD_KEYMAP_SIZE); - if (err) - return err; - - memcpy(atkbd->force_release_mask, new_mask, sizeof(atkbd->force_release_mask)); - return count; -} - - -static ssize_t atkbd_show_scroll(struct atkbd *atkbd, char *buf) -{ - return sprintf(buf, "%d\n", atkbd->scroll ? 1 : 0); -} - -static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t count) -{ - struct input_dev *old_dev, *new_dev; - unsigned int value; - int err; - bool old_scroll; - - err = kstrtouint(buf, 10, &value); - if (err) - return err; - - if (value > 1) - return -EINVAL; - - if (atkbd->scroll != value) { - old_dev = atkbd->dev; - old_scroll = atkbd->scroll; - - new_dev = input_allocate_device(); - if (!new_dev) - return -ENOMEM; - - atkbd->dev = new_dev; - atkbd->scroll = value; - atkbd_set_keycode_table(atkbd); - atkbd_set_device_attrs(atkbd); - - err = input_register_device(atkbd->dev); - if (err) { - input_free_device(new_dev); - - atkbd->scroll = old_scroll; - atkbd->dev = old_dev; - atkbd_set_keycode_table(atkbd); - atkbd_set_device_attrs(atkbd); - - return err; - } - input_unregister_device(old_dev); - } - return count; -} - -static ssize_t atkbd_show_set(struct atkbd *atkbd, char *buf) -{ - return sprintf(buf, "%d\n", atkbd->set); -} - -static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) -{ - struct input_dev *old_dev, *new_dev; - unsigned int value; - int err; - unsigned char old_set; - bool old_extra; - - if (!atkbd->write) - return -EIO; - - err = kstrtouint(buf, 10, &value); - if (err) - return err; - - if (value != 2 && value != 3) - return -EINVAL; - - if (atkbd->set != value) { - old_dev = atkbd->dev; - old_extra = atkbd->extra; - old_set = atkbd->set; - - new_dev = input_allocate_device(); - if (!new_dev) - return -ENOMEM; - - atkbd->dev = new_dev; - atkbd->set = atkbd_select_set(atkbd, value, atkbd->extra); - atkbd_reset_state(atkbd); - atkbd_activate(atkbd); - atkbd_set_keycode_table(atkbd); - atkbd_set_device_attrs(atkbd); - - err = input_register_device(atkbd->dev); - if (err) { - input_free_device(new_dev); - - atkbd->dev = old_dev; - atkbd->set = atkbd_select_set(atkbd, old_set, old_extra); - atkbd_set_keycode_table(atkbd); - atkbd_set_device_attrs(atkbd); - - return err; - } - input_unregister_device(old_dev); - } - return count; -} - -static ssize_t atkbd_show_softrepeat(struct atkbd *atkbd, char *buf) -{ - return sprintf(buf, "%d\n", atkbd->softrepeat ? 1 : 0); -} - -static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t count) -{ - struct input_dev *old_dev, *new_dev; - unsigned int value; - int err; - bool old_softrepeat, old_softraw; - - if (!atkbd->write) - return -EIO; - - err = kstrtouint(buf, 10, &value); - if (err) - return err; - - if (value > 1) - return -EINVAL; - - if (atkbd->softrepeat != value) { - old_dev = atkbd->dev; - old_softrepeat = atkbd->softrepeat; - old_softraw = atkbd->softraw; - - new_dev = input_allocate_device(); - if (!new_dev) - return -ENOMEM; - - atkbd->dev = new_dev; - atkbd->softrepeat = value; - if (atkbd->softrepeat) - atkbd->softraw = true; - atkbd_set_device_attrs(atkbd); - - err = input_register_device(atkbd->dev); - if (err) { - input_free_device(new_dev); - - atkbd->dev = old_dev; - atkbd->softrepeat = old_softrepeat; - atkbd->softraw = old_softraw; - atkbd_set_device_attrs(atkbd); - - return err; - } - input_unregister_device(old_dev); - } - return count; -} - - -static ssize_t atkbd_show_softraw(struct atkbd *atkbd, char *buf) -{ - return sprintf(buf, "%d\n", atkbd->softraw ? 1 : 0); -} - -static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t count) -{ - struct input_dev *old_dev, *new_dev; - unsigned int value; - int err; - bool old_softraw; - - err = kstrtouint(buf, 10, &value); - if (err) - return err; - - if (value > 1) - return -EINVAL; - - if (atkbd->softraw != value) { - old_dev = atkbd->dev; - old_softraw = atkbd->softraw; - - new_dev = input_allocate_device(); - if (!new_dev) - return -ENOMEM; - - atkbd->dev = new_dev; - atkbd->softraw = value; - atkbd_set_device_attrs(atkbd); - - err = input_register_device(atkbd->dev); - if (err) { - input_free_device(new_dev); - - atkbd->dev = old_dev; - atkbd->softraw = old_softraw; - atkbd_set_device_attrs(atkbd); - - return err; - } - input_unregister_device(old_dev); - } - return count; -} - -static ssize_t atkbd_show_err_count(struct atkbd *atkbd, char *buf) -{ - return sprintf(buf, "%lu\n", atkbd->err_count); -} - -static int __init atkbd_setup_forced_release(const struct dmi_system_id *id) -{ - atkbd_platform_fixup = atkbd_apply_forced_release_keylist; - atkbd_platform_fixup_data = id->driver_data; - - return 1; -} - -static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id) -{ - atkbd_platform_scancode_fixup = id->driver_data; - - return 1; -} - -static int __init atkbd_deactivate_fixup(const struct dmi_system_id *id) -{ - atkbd_skip_deactivate = true; - return 1; -} - -/* - * NOTE: do not add any more "force release" quirks to this table. The - * task of adjusting list of keys that should be "released" automatically - * by the driver is now delegated to userspace tools, such as udev, so - * submit such quirks there. - */ -static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = { - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ - }, - .callback = atkbd_setup_forced_release, - .driver_data = atkbd_dell_laptop_forced_release_keys, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"), - DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */ - }, - .callback = atkbd_setup_forced_release, - .driver_data = atkbd_dell_laptop_forced_release_keys, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "HP 2133"), - }, - .callback = atkbd_setup_forced_release, - .driver_data = atkbd_hp_forced_release_keys, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "Pavilion ZV6100"), - }, - .callback = atkbd_setup_forced_release, - .driver_data = atkbd_volume_forced_release_keys, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4000"), - }, - .callback = atkbd_setup_forced_release, - .driver_data = atkbd_volume_forced_release_keys, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4100"), - }, - .callback = atkbd_setup_forced_release, - .driver_data = atkbd_volume_forced_release_keys, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), - DMI_MATCH(DMI_PRODUCT_NAME, "Presario R4200"), - }, - .callback = atkbd_setup_forced_release, - .driver_data = atkbd_volume_forced_release_keys, - }, - { - /* Inventec Symphony */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "INVENTEC"), - DMI_MATCH(DMI_PRODUCT_NAME, "SYMPHONY 6.0/7.0"), - }, - .callback = atkbd_setup_forced_release, - .driver_data = atkbd_volume_forced_release_keys, - }, - { - /* Samsung NC10 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "NC10"), - }, - .callback = atkbd_setup_forced_release, - .driver_data = atkbd_samsung_forced_release_keys, - }, - { - /* Samsung NC20 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "NC20"), - }, - .callback = atkbd_setup_forced_release, - .driver_data = atkbd_samsung_forced_release_keys, - }, - { - /* Samsung SQ45S70S */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."), - DMI_MATCH(DMI_PRODUCT_NAME, "SQ45S70S"), - }, - .callback = atkbd_setup_forced_release, - .driver_data = atkbd_samsung_forced_release_keys, - }, - { - /* Fujitsu Amilo PA 1510 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pa 1510"), - }, - .callback = atkbd_setup_forced_release, - .driver_data = atkbd_volume_forced_release_keys, - }, - { - /* Fujitsu Amilo Pi 3525 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pi 3525"), - }, - .callback = atkbd_setup_forced_release, - .driver_data = atkbd_amilo_pi3525_forced_release_keys, - }, - { - /* Fujitsu Amilo Xi 3650 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), - DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Xi 3650"), - }, - .callback = atkbd_setup_forced_release, - .driver_data = atkbd_amilo_xi3650_forced_release_keys, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Soltech Corporation"), - DMI_MATCH(DMI_PRODUCT_NAME, "TA12"), - }, - .callback = atkbd_setup_forced_release, - .driver_data = atkdb_soltech_ta12_forced_release_keys, - }, - { - /* OQO Model 01+ */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "OQO"), - DMI_MATCH(DMI_PRODUCT_NAME, "ZEPTO"), - }, - .callback = atkbd_setup_scancode_fixup, - .driver_data = atkbd_oqo_01plus_scancode_fixup, - }, - { - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "LG Electronics"), - }, - .callback = atkbd_deactivate_fixup, - }, - { } -}; - -static int __init atkbd_init(void) -{ - dmi_check_system(atkbd_dmi_quirk_table); - - return serio_register_driver(&atkbd_drv); -} - -static void __exit atkbd_exit(void) -{ - serio_unregister_driver(&atkbd_drv); -} - -module_init(atkbd_init); -module_exit(atkbd_exit); diff --git a/src/linux/drivers/input/misc/Kconfig b/src/linux/drivers/input/misc/Kconfig deleted file mode 100644 index 7ffb614..0000000 --- a/src/linux/drivers/input/misc/Kconfig +++ /dev/null @@ -1,834 +0,0 @@ -# -# Input misc drivers configuration -# -menuconfig INPUT_MISC - bool "Miscellaneous devices" - help - Say Y here, and a list of miscellaneous input drivers will be displayed. - Everything that didn't fit into the other categories is here. This option - doesn't affect the kernel. - - If unsure, say Y. - -if INPUT_MISC - -config INPUT_88PM860X_ONKEY - tristate "88PM860x ONKEY support" - depends on MFD_88PM860X - help - Support the ONKEY of Marvell 88PM860x PMICs as an input device - reporting power button status. - - To compile this driver as a module, choose M here: the module - will be called 88pm860x_onkey. - -config INPUT_88PM80X_ONKEY - tristate "88PM80x ONKEY support" - depends on MFD_88PM800 - help - Support the ONKEY of Marvell 88PM80x PMICs as an input device - reporting power button status. - - To compile this driver as a module, choose M here: the module - will be called 88pm80x_onkey. - -config INPUT_AB8500_PONKEY - tristate "AB8500 Pon (PowerOn) Key" - depends on AB8500_CORE - help - Say Y here to use the PowerOn Key for ST-Ericsson's AB8500 - Mix-Sig PMIC. - - To compile this driver as a module, choose M here: the module - will be called ab8500-ponkey. - -config INPUT_AD714X - tristate "Analog Devices AD714x Capacitance Touch Sensor" - help - Say Y here if you want to support an AD7142/3/7/8/7A touch sensor. - - You should select a bus connection too. - - To compile this driver as a module, choose M here: the - module will be called ad714x. - -config INPUT_AD714X_I2C - tristate "support I2C bus connection" - depends on INPUT_AD714X && I2C - default y - help - Say Y here if you have AD7142/AD7147 hooked to an I2C bus. - - To compile this driver as a module, choose M here: the - module will be called ad714x-i2c. - -config INPUT_AD714X_SPI - tristate "support SPI bus connection" - depends on INPUT_AD714X && SPI - default y - help - Say Y here if you have AD7142/AD7147 hooked to a SPI bus. - - To compile this driver as a module, choose M here: the - module will be called ad714x-spi. - -config INPUT_ARIZONA_HAPTICS - tristate "Arizona haptics support" - depends on MFD_ARIZONA && SND_SOC - select INPUT_FF_MEMLESS - help - Say Y to enable support for the haptics module in Arizona CODECs. - - To compile this driver as a module, choose M here: the - module will be called arizona-haptics. - -config INPUT_ATMEL_CAPTOUCH - tristate "Atmel Capacitive Touch Button Driver" - depends on OF || COMPILE_TEST - depends on I2C - help - Say Y here if an Atmel Capacitive Touch Button device which - implements "captouch" protocol is connected to I2C bus. Typically - this device consists of Atmel Touch sensor controlled by AtMegaXX - MCU running firmware based on Qtouch library. - One should find "atmel,captouch" node in the board specific DTS. - - To compile this driver as a module, choose M here: the - module will be called atmel_captouch. - -config INPUT_BMA150 - tristate "BMA150/SMB380 acceleration sensor support" - depends on I2C - select INPUT_POLLDEV - help - Say Y here if you have Bosch Sensortec's BMA150 or SMB380 - acceleration sensor hooked to an I2C bus. - - To compile this driver as a module, choose M here: the - module will be called bma150. - -config INPUT_E3X0_BUTTON - tristate "NI Ettus Research USRP E3xx Button support." - default n - help - Say Y here to enable support for the NI Ettus Research - USRP E3xx Button. - - To compile this driver as a module, choose M here: the - module will be called e3x0_button. - -config INPUT_PCSPKR - tristate "PC Speaker support" - depends on PCSPKR_PLATFORM - help - Say Y here if you want the standard PC Speaker to be used for - bells and whistles. - - If unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called pcspkr. - -config INPUT_PM8941_PWRKEY - tristate "Qualcomm PM8941 power key support" - depends on MFD_SPMI_PMIC - help - Say Y here if you want support for the power key usually found - on boards using a Qualcomm PM8941 compatible PMIC. - - If unsure, say Y. - - To compile this driver as a module, choose M here: the module - will be called pm8941-pwrkey. - -config INPUT_PM8XXX_VIBRATOR - tristate "Qualcomm PM8XXX vibrator support" - depends on MFD_PM8XXX - select INPUT_FF_MEMLESS - help - This option enables device driver support for the vibrator - on Qualcomm PM8xxx chip. This driver supports ff-memless interface - from input framework. - - To compile this driver as module, choose M here: the - module will be called pm8xxx-vibrator. - -config INPUT_PMIC8XXX_PWRKEY - tristate "PMIC8XXX power key support" - depends on MFD_PM8XXX - help - Say Y here if you want support for the PMIC8XXX power key. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called pmic8xxx-pwrkey. - -config INPUT_SPARCSPKR - tristate "SPARC Speaker support" - depends on PCI && SPARC64 - help - Say Y here if you want the standard Speaker on Sparc PCI systems - to be used for bells and whistles. - - If unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called sparcspkr. - -config INPUT_M68K_BEEP - tristate "M68k Beeper support" - depends on M68K - -config INPUT_MAX77693_HAPTIC - tristate "MAXIM MAX77693/MAX77843 haptic controller support" - depends on (MFD_MAX77693 || MFD_MAX77843) && PWM - select INPUT_FF_MEMLESS - help - This option enables support for the haptic controller on - MAXIM MAX77693 and MAX77843 chips. - - To compile this driver as module, choose M here: the - module will be called max77693-haptic. - -config INPUT_MAX8925_ONKEY - tristate "MAX8925 ONKEY support" - depends on MFD_MAX8925 - help - Support the ONKEY of MAX8925 PMICs as an input device - reporting power button status. - - To compile this driver as a module, choose M here: the module - will be called max8925_onkey. - -config INPUT_MAX8997_HAPTIC - tristate "MAXIM MAX8997 haptic controller support" - depends on PWM && MFD_MAX8997 - select INPUT_FF_MEMLESS - help - This option enables device driver support for the haptic controller - on MAXIM MAX8997 chip. This driver supports ff-memless interface - from input framework. - - To compile this driver as module, choose M here: the - module will be called max8997-haptic. - -config INPUT_MC13783_PWRBUTTON - tristate "MC13783 ON buttons" - depends on MFD_MC13XXX - help - Support the ON buttons of MC13783 PMIC as an input device - reporting power button status. - - To compile this driver as a module, choose M here: the module - will be called mc13783-pwrbutton. - -config INPUT_MMA8450 - tristate "MMA8450 - Freescale's 3-Axis, 8/12-bit Digital Accelerometer" - depends on I2C - select INPUT_POLLDEV - help - Say Y here if you want to support Freescale's MMA8450 Accelerometer - through I2C interface. - - To compile this driver as a module, choose M here: the - module will be called mma8450. - -config INPUT_MPU3050 - tristate "MPU3050 Triaxial gyroscope sensor" - depends on I2C - help - Say Y here if you want to support InvenSense MPU3050 - connected via an I2C bus. - - To compile this driver as a module, choose M here: the - module will be called mpu3050. - -config INPUT_APANEL - tristate "Fujitsu Lifebook Application Panel buttons" - depends on X86 && I2C && LEDS_CLASS - select INPUT_POLLDEV - select CHECK_SIGNATURE - help - Say Y here for support of the Application Panel buttons, used on - Fujitsu Lifebook. These are attached to the mainboard through - an SMBus interface managed by the I2C Intel ICH (i801) driver, - which you should also build for this kernel. - - To compile this driver as a module, choose M here: the module will - be called apanel. - -config INPUT_GP2A - tristate "Sharp GP2AP002A00F I2C Proximity/Opto sensor driver" - depends on I2C - depends on GPIOLIB || COMPILE_TEST - help - Say Y here if you have a Sharp GP2AP002A00F proximity/als combo-chip - hooked to an I2C bus. - - To compile this driver as a module, choose M here: the - module will be called gp2ap002a00f. - -config INPUT_GPIO_BEEPER - tristate "Generic GPIO Beeper support" - depends on GPIOLIB || COMPILE_TEST - help - Say Y here if you have a beeper connected to a GPIO pin. - - To compile this driver as a module, choose M here: the - module will be called gpio-beeper. - -config INPUT_GPIO_TILT_POLLED - tristate "Polled GPIO tilt switch" - depends on GPIOLIB || COMPILE_TEST - select INPUT_POLLDEV - help - This driver implements support for tilt switches connected - to GPIO pins that are not capable of generating interrupts. - - The list of gpios to use and the mapping of their states - to specific angles is done via platform data. - - To compile this driver as a module, choose M here: the - module will be called gpio_tilt_polled. - -config INPUT_GPIO_DECODER - tristate "Polled GPIO Decoder Input driver" - depends on GPIOLIB || COMPILE_TEST - select INPUT_POLLDEV - help - Say Y here if you want driver to read status of multiple GPIO - lines and report the encoded value as an absolute integer to - input subsystem. - - To compile this driver as a module, choose M here: the module - will be called gpio_decoder. - -config INPUT_IXP4XX_BEEPER - tristate "IXP4XX Beeper support" - depends on ARCH_IXP4XX - help - If you say yes here, you can connect a beeper to the - ixp4xx gpio pins. This is used by the LinkSys NSLU2. - - If unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called ixp4xx-beeper. - -config INPUT_COBALT_BTNS - tristate "Cobalt button interface" - depends on MIPS_COBALT - select INPUT_POLLDEV - help - Say Y here if you want to support MIPS Cobalt button interface. - - To compile this driver as a module, choose M here: the - module will be called cobalt_btns. - -config INPUT_WISTRON_BTNS - tristate "x86 Wistron laptop button interface" - depends on X86_32 - select INPUT_POLLDEV - select INPUT_SPARSEKMAP - select NEW_LEDS - select LEDS_CLASS - select CHECK_SIGNATURE - help - Say Y here for support of Wistron laptop button interfaces, used on - laptops of various brands, including Acer and Fujitsu-Siemens. If - available, mail and wifi LEDs will be controllable via /sys/class/leds. - - To compile this driver as a module, choose M here: the module will - be called wistron_btns. - -config INPUT_ATLAS_BTNS - tristate "x86 Atlas button interface" - depends on X86 && ACPI - help - Say Y here for support of Atlas wallmount touchscreen buttons. - The events will show up as scancodes F1 through F9 via evdev. - - To compile this driver as a module, choose M here: the module will - be called atlas_btns. - -config INPUT_ATI_REMOTE2 - tristate "ATI / Philips USB RF remote control" - depends on USB_ARCH_HAS_HCD - select USB - help - Say Y here if you want to use an ATI or Philips USB RF remote control. - These are RF remotes with USB receivers. - ATI Remote Wonder II comes with some ATI's All-In-Wonder video cards - and is also available as a separate product. - This driver provides mouse pointer, left and right mouse buttons, - and maps all the other remote buttons to keypress events. - - To compile this driver as a module, choose M here: the module will be - called ati_remote2. - -config INPUT_KEYSPAN_REMOTE - tristate "Keyspan DMR USB remote control" - depends on USB_ARCH_HAS_HCD - select USB - help - Say Y here if you want to use a Keyspan DMR USB remote control. - Currently only the UIA-11 type of receiver has been tested. The tag - on the receiver that connects to the USB port should have a P/N that - will tell you what type of DMR you have. The UIA-10 type is not - supported at this time. This driver maps all buttons to keypress - events. - - To compile this driver as a module, choose M here: the module will - be called keyspan_remote. - -config INPUT_KXTJ9 - tristate "Kionix KXTJ9 tri-axis digital accelerometer" - depends on I2C - help - Say Y here to enable support for the Kionix KXTJ9 digital tri-axis - accelerometer. - - To compile this driver as a module, choose M here: the module will - be called kxtj9. - -config INPUT_KXTJ9_POLLED_MODE - bool "Enable polling mode support" - depends on INPUT_KXTJ9 - select INPUT_POLLDEV - help - Say Y here if you need accelerometer to work in polling mode. - -config INPUT_POWERMATE - tristate "Griffin PowerMate and Contour Jog support" - depends on USB_ARCH_HAS_HCD - select USB - help - Say Y here if you want to use Griffin PowerMate or Contour Jog devices. - These are aluminum dials which can measure clockwise and anticlockwise - rotation. The dial also acts as a pushbutton. The base contains an LED - which can be instructed to pulse or to switch to a particular intensity. - - You can download userspace tools from - . - - To compile this driver as a module, choose M here: the - module will be called powermate. - -config INPUT_YEALINK - tristate "Yealink usb-p1k voip phone" - depends on USB_ARCH_HAS_HCD - select USB - help - Say Y here if you want to enable keyboard and LCD functions of the - Yealink usb-p1k usb phones. The audio part is enabled by the generic - usb sound driver, so you might want to enable that as well. - - For information about how to use these additional functions, see - . - - To compile this driver as a module, choose M here: the module will be - called yealink. - -config INPUT_CM109 - tristate "C-Media CM109 USB I/O Controller" - depends on USB_ARCH_HAS_HCD - select USB - help - Say Y here if you want to enable keyboard and buzzer functions of the - C-Media CM109 usb phones. The audio part is enabled by the generic - usb sound driver, so you might want to enable that as well. - - To compile this driver as a module, choose M here: the module will be - called cm109. - -config INPUT_REGULATOR_HAPTIC - tristate "Regulator haptics support" - depends on REGULATOR - select INPUT_FF_MEMLESS - help - This option enables device driver support for the haptic controlled - by a regulator. This driver supports ff-memless interface - from input framework. - - To compile this driver as a module, choose M here: the - module will be called regulator-haptic. - -config INPUT_RETU_PWRBUTTON - tristate "Retu Power button Driver" - depends on MFD_RETU - help - Say Y here if you want to enable power key reporting via the - Retu chips found in Nokia Internet Tablets (770, N800, N810). - - To compile this driver as a module, choose M here. The module will - be called retu-pwrbutton. - -config INPUT_TPS65218_PWRBUTTON - tristate "TPS65218 Power button driver" - depends on (MFD_TPS65217 || MFD_TPS65218) - help - Say Y here if you want to enable power buttong reporting for - TPS65217 and TPS65218 Power Management IC devices. - - To compile this driver as a module, choose M here. The module will - be called tps65218-pwrbutton. - -config INPUT_AXP20X_PEK - tristate "X-Powers AXP20X power button driver" - depends on MFD_AXP20X - help - Say Y here if you want to enable power key reporting via the - AXP20X PMIC. - - To compile this driver as a module, choose M here. The module will - be called axp20x-pek. - - -config INPUT_TWL4030_PWRBUTTON - tristate "TWL4030 Power button Driver" - depends on TWL4030_CORE - help - Say Y here if you want to enable power key reporting via the - TWL4030 family of chips. - - To compile this driver as a module, choose M here. The module will - be called twl4030_pwrbutton. - -config INPUT_TWL4030_VIBRA - tristate "Support for TWL4030 Vibrator" - depends on TWL4030_CORE - select MFD_TWL4030_AUDIO - select INPUT_FF_MEMLESS - help - This option enables support for TWL4030 Vibrator Driver. - - To compile this driver as a module, choose M here. The module will - be called twl4030_vibra. - -config INPUT_TWL6040_VIBRA - tristate "Support for TWL6040 Vibrator" - depends on TWL6040_CORE - select INPUT_FF_MEMLESS - help - This option enables support for TWL6040 Vibrator Driver. - - To compile this driver as a module, choose M here. The module will - be called twl6040_vibra. - -config INPUT_UINPUT - tristate "User level driver support" - help - Say Y here if you want to support user level drivers for input - subsystem accessible under char device 10:223 - /dev/input/uinput. - - To compile this driver as a module, choose M here: the - module will be called uinput. - -config INPUT_SGI_BTNS - tristate "SGI Indy/O2 volume button interface" - depends on SGI_IP22 || SGI_IP32 - select INPUT_POLLDEV - help - Say Y here if you want to support SGI Indy/O2 volume button interface. - - To compile this driver as a module, choose M here: the - module will be called sgi_btns. - -config HP_SDC_RTC - tristate "HP SDC Real Time Clock" - depends on (GSC || HP300) && SERIO - select HP_SDC - help - Say Y here if you want to support the built-in real time clock - of the HP SDC controller. - -config INPUT_PALMAS_PWRBUTTON - tristate "Palmas Power button Driver" - depends on MFD_PALMAS - help - Say Y here if you want to enable power key reporting via the - Palmas family of PMICs. - - To compile this driver as a module, choose M here. The module will - be called palmas_pwrbutton. - -config INPUT_PCF50633_PMU - tristate "PCF50633 PMU events" - depends on MFD_PCF50633 - help - Say Y to include support for delivering PMU events via input - layer on NXP PCF50633. - -config INPUT_PCF8574 - tristate "PCF8574 Keypad input device" - depends on I2C - help - Say Y here if you want to support a keypad connected via I2C - with a PCF8574. - - To compile this driver as a module, choose M here: the - module will be called pcf8574_keypad. - -config INPUT_PWM_BEEPER - tristate "PWM beeper support" - depends on PWM - help - Say Y here to get support for PWM based beeper devices. - - If unsure, say N. - - To compile this driver as a module, choose M here: the module will be - called pwm-beeper. - -config INPUT_GPIO_ROTARY_ENCODER - tristate "Rotary encoders connected to GPIO pins" - depends on GPIOLIB || COMPILE_TEST - help - Say Y here to add support for rotary encoders connected to GPIO lines. - Check file:Documentation/input/rotary-encoder.txt for more - information. - - To compile this driver as a module, choose M here: the - module will be called rotary_encoder. - -config INPUT_RB532_BUTTON - tristate "Mikrotik Routerboard 532 button interface" - depends on MIKROTIK_RB532 - depends on GPIOLIB - select INPUT_POLLDEV - help - Say Y here if you want support for the S1 button built into - Mikrotik's Routerboard 532. - - To compile this driver as a module, choose M here: the - module will be called rb532_button. - -config INPUT_DA9052_ONKEY - tristate "Dialog DA9052/DA9053 Onkey" - depends on PMIC_DA9052 - help - Support the ONKEY of Dialog DA9052 PMICs as an input device - reporting power button status. - - To compile this driver as a module, choose M here: the - module will be called da9052_onkey. - -config INPUT_DA9055_ONKEY - tristate "Dialog Semiconductor DA9055 ONKEY" - depends on MFD_DA9055 - help - Support the ONKEY of DA9055 PMICs as an input device - reporting power button status. - - To compile this driver as a module, choose M here: the module - will be called da9055_onkey. - -config INPUT_DA9063_ONKEY - tristate "Dialog DA9062/63 OnKey" - depends on MFD_DA9063 || MFD_DA9062 - help - Support the ONKEY of Dialog DA9063 and DA9062 Power Management ICs - as an input device capable of reporting the power button status. - - To compile this driver as a module, choose M here: the module - will be called da9063_onkey. - -config INPUT_DM355EVM - tristate "TI DaVinci DM355 EVM Keypad and IR Remote" - depends on MFD_DM355EVM_MSP - select INPUT_SPARSEKMAP - help - Supports the pushbuttons and IR remote used with - the DM355 EVM board. - - To compile this driver as a module, choose M here: the - module will be called dm355evm_keys. - -config INPUT_BFIN_ROTARY - tristate "Blackfin Rotary support" - depends on BF54x || BF52x - help - Say Y here if you want to use the Blackfin Rotary. - - To compile this driver as a module, choose M here: the - module will be called bfin-rotary. - -config INPUT_WM831X_ON - tristate "WM831X ON pin" - depends on MFD_WM831X - help - Support the ON pin of WM831X PMICs as an input device - reporting power button status. - - To compile this driver as a module, choose M here: the module - will be called wm831x_on. - -config INPUT_PCAP - tristate "Motorola EZX PCAP misc input events" - depends on EZX_PCAP - help - Say Y here if you want to use Power key and Headphone button - on Motorola EZX phones. - - To compile this driver as a module, choose M here: the - module will be called pcap_keys. - -config INPUT_ADXL34X - tristate "Analog Devices ADXL34x Three-Axis Digital Accelerometer" - default n - help - Say Y here if you have a Accelerometer interface using the - ADXL345/6 controller, and your board-specific initialization - code includes that in its table of devices. - - This driver can use either I2C or SPI communication to the - ADXL345/6 controller. Select the appropriate method for - your system. - - If unsure, say N (but it's safe to say "Y"). - - To compile this driver as a module, choose M here: the - module will be called adxl34x. - -config INPUT_ADXL34X_I2C - tristate "support I2C bus connection" - depends on INPUT_ADXL34X && I2C - default y - help - Say Y here if you have ADXL345/6 hooked to an I2C bus. - - To compile this driver as a module, choose M here: the - module will be called adxl34x-i2c. - -config INPUT_ADXL34X_SPI - tristate "support SPI bus connection" - depends on INPUT_ADXL34X && SPI - default y - help - Say Y here if you have ADXL345/6 hooked to a SPI bus. - - To compile this driver as a module, choose M here: the - module will be called adxl34x-spi. - -config INPUT_IMS_PCU - tristate "IMS Passenger Control Unit driver" - depends on USB - depends on LEDS_CLASS - help - Say Y here if you have system with IMS Rave Passenger Control Unit. - - To compile this driver as a module, choose M here: the module will be - called ims_pcu. - -config INPUT_CMA3000 - tristate "VTI CMA3000 Tri-axis accelerometer" - help - Say Y here if you want to use VTI CMA3000_D0x Accelerometer - driver - - This driver currently only supports I2C interface to the - controller. Also select the I2C method. - - If unsure, say N - - To compile this driver as a module, choose M here: the - module will be called cma3000_d0x. - -config INPUT_CMA3000_I2C - tristate "Support I2C bus connection" - depends on INPUT_CMA3000 && I2C - help - Say Y here if you want to use VTI CMA3000_D0x Accelerometer - through I2C interface. - - To compile this driver as a module, choose M here: the - module will be called cma3000_d0x_i2c. - -config INPUT_XEN_KBDDEV_FRONTEND - tristate "Xen virtual keyboard and mouse support" - depends on XEN - default y - select XEN_XENBUS_FRONTEND - help - This driver implements the front-end of the Xen virtual - keyboard and mouse device driver. It communicates with a back-end - in another domain. - - To compile this driver as a module, choose M here: the - module will be called xen-kbdfront. - -config INPUT_SIRFSOC_ONKEY - tristate "CSR SiRFSoC power on/off/suspend key support" - depends on ARCH_SIRF && OF - default y - help - Say Y here if you want to support for the SiRFSoC power on/off/suspend key - in Linux, after you press the onkey, system will suspend. - - If unsure, say N. - -config INPUT_IDEAPAD_SLIDEBAR - tristate "IdeaPad Laptop Slidebar" - depends on INPUT - depends on SERIO_I8042 - help - Say Y here if you have an IdeaPad laptop with a slidebar. - - To compile this driver as a module, choose M here: the - module will be called ideapad_slidebar. - -config INPUT_SOC_BUTTON_ARRAY - tristate "Windows-compatible SoC Button Array" - depends on KEYBOARD_GPIO - help - Say Y here if you have a SoC-based tablet that originally - runs Windows 8. - - To compile this driver as a module, choose M here: the - module will be called soc_button_array. - -config INPUT_DRV260X_HAPTICS - tristate "TI DRV260X haptics support" - depends on INPUT && I2C - depends on GPIOLIB || COMPILE_TEST - select INPUT_FF_MEMLESS - select REGMAP_I2C - help - Say Y to enable support for the TI DRV260X haptics driver. - - To compile this driver as a module, choose M here: the - module will be called drv260x-haptics. - -config INPUT_DRV2665_HAPTICS - tristate "TI DRV2665 haptics support" - depends on INPUT && I2C - select INPUT_FF_MEMLESS - select REGMAP_I2C - help - Say Y to enable support for the TI DRV2665 haptics driver. - - To compile this driver as a module, choose M here: the - module will be called drv2665-haptics. - -config INPUT_DRV2667_HAPTICS - tristate "TI DRV2667 haptics support" - depends on INPUT && I2C - select INPUT_FF_MEMLESS - select REGMAP_I2C - help - Say Y to enable support for the TI DRV2667 haptics driver. - - To compile this driver as a module, choose M here: the - module will be called drv2667-haptics. - -config INPUT_HISI_POWERKEY - tristate "Hisilicon PMIC ONKEY support" - depends on ARCH_HISI || COMPILE_TEST - help - Say Y to enable support for PMIC ONKEY. - - To compile this driver as a module, choose M here: the - module will be called hisi_powerkey. - -endif diff --git a/src/linux/drivers/input/mouse/Kconfig b/src/linux/drivers/input/mouse/Kconfig deleted file mode 100644 index 096abb4..0000000 --- a/src/linux/drivers/input/mouse/Kconfig +++ /dev/null @@ -1,432 +0,0 @@ -# -# Mouse driver configuration -# -menuconfig INPUT_MOUSE - bool "Mice" - default y - help - Say Y here, and a list of supported mice will be displayed. - This option doesn't affect the kernel. - - If unsure, say Y. - -if INPUT_MOUSE - -config MOUSE_PS2 - tristate "PS/2 mouse" - default y - select SERIO - select SERIO_LIBPS2 - select SERIO_I8042 if ARCH_MIGHT_HAVE_PC_SERIO - select SERIO_GSCPS2 if GSC - help - Say Y here if you have a PS/2 mouse connected to your system. This - includes the standard 2 or 3-button PS/2 mouse, as well as PS/2 - mice with wheels and extra buttons, Microsoft, Logitech or Genius - compatible. - - Synaptics, ALPS or Elantech TouchPad users might be interested - in a specialized Xorg/XFree86 driver at: - - and a new version of GPM at: - - - to take advantage of the advanced features of the touchpad. - - If unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called psmouse. - -config MOUSE_PS2_ALPS - bool "ALPS PS/2 mouse protocol extension" if EXPERT - default y - depends on MOUSE_PS2 - help - Say Y here if you have an ALPS PS/2 touchpad connected to - your system. - - If unsure, say Y. - -config MOUSE_PS2_BYD - bool "BYD PS/2 mouse protocol extension" if EXPERT - default y - depends on MOUSE_PS2 - help - Say Y here if you have a BYD PS/2 touchpad connected to - your system. - - If unsure, say Y. - -config MOUSE_PS2_LOGIPS2PP - bool "Logitech PS/2++ mouse protocol extension" if EXPERT - default y - depends on MOUSE_PS2 - help - Say Y here if you have a Logitech PS/2++ mouse connected to - your system. - - If unsure, say Y. - -config MOUSE_PS2_SYNAPTICS - bool "Synaptics PS/2 mouse protocol extension" if EXPERT - default y - depends on MOUSE_PS2 - help - Say Y here if you have a Synaptics PS/2 TouchPad connected to - your system. - - If unsure, say Y. - -config MOUSE_PS2_CYPRESS - bool "Cypress PS/2 mouse protocol extension" if EXPERT - default y - depends on MOUSE_PS2 - help - Say Y here if you have a Cypress PS/2 Trackpad connected to - your system. - - If unsure, say Y. - -config MOUSE_PS2_LIFEBOOK - bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EXPERT - default y - depends on MOUSE_PS2 && X86 && DMI - help - Say Y here if you have a Fujitsu B-series Lifebook PS/2 - TouchScreen connected to your system. - - If unsure, say Y. - -config MOUSE_PS2_TRACKPOINT - bool "IBM Trackpoint PS/2 mouse protocol extension" if EXPERT - default y - depends on MOUSE_PS2 - help - Say Y here if you have an IBM Trackpoint PS/2 mouse connected - to your system. - - If unsure, say Y. - -config MOUSE_PS2_ELANTECH - bool "Elantech PS/2 protocol extension" - depends on MOUSE_PS2 - help - Say Y here if you have an Elantech PS/2 touchpad connected - to your system. - - This driver exposes some configuration registers via sysfs - entries. For further information, - see . - - If unsure, say N. - -config MOUSE_PS2_SENTELIC - bool "Sentelic Finger Sensing Pad PS/2 protocol extension" - depends on MOUSE_PS2 - help - Say Y here if you have a laptop (such as MSI WIND Netbook) - with Sentelic Finger Sensing Pad touchpad. - - If unsure, say N. - -config MOUSE_PS2_TOUCHKIT - bool "eGalax TouchKit PS/2 protocol extension" - depends on MOUSE_PS2 - help - Say Y here if you have an eGalax TouchKit PS/2 touchscreen - connected to your system. - - If unsure, say N. - -config MOUSE_PS2_OLPC - bool "OLPC PS/2 mouse protocol extension" - depends on MOUSE_PS2 && OLPC - help - Say Y here if you have an OLPC XO-1 laptop (with built-in - PS/2 touchpad/tablet device). The manufacturer calls the - touchpad an HGPK. - - If unsure, say N. - -config MOUSE_PS2_FOCALTECH - bool "FocalTech PS/2 mouse protocol extension" if EXPERT - default y - depends on MOUSE_PS2 - help - Say Y here if you have a FocalTech PS/2 TouchPad connected to - your system. - - If unsure, say Y. - -config MOUSE_PS2_VMMOUSE - bool "Virtual mouse (vmmouse)" - depends on MOUSE_PS2 && X86 && HYPERVISOR_GUEST - help - Say Y here if you are running under control of VMware hypervisor - (ESXi, Workstation or Fusion). Also make sure that when you enable - this option, you remove the xf86-input-vmmouse user-space driver - or upgrade it to at least xf86-input-vmmouse 13.1.0, which doesn't - load in the presence of an in-kernel vmmouse driver. - - If unsure, say N. - -config MOUSE_SERIAL - tristate "Serial mouse" - select SERIO - help - Say Y here if you have a serial (RS-232, COM port) mouse connected - to your system. This includes Sun, MouseSystems, Microsoft, - Logitech and all other compatible serial mice. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called sermouse. - -config MOUSE_APPLETOUCH - tristate "Apple USB Touchpad support" - depends on USB_ARCH_HAS_HCD - select USB - help - Say Y here if you want to use an Apple USB Touchpad. - - These are the touchpads that can be found on post-February 2005 - Apple Powerbooks (prior models have a Synaptics touchpad connected - to the ADB bus). - - This driver provides a basic mouse driver but can be interfaced - with the synaptics X11 driver to provide acceleration and - scrolling in X11. - - For further information, see - . - - To compile this driver as a module, choose M here: the - module will be called appletouch. - -config MOUSE_BCM5974 - tristate "Apple USB BCM5974 Multitouch trackpad support" - depends on USB_ARCH_HAS_HCD - select USB - help - Say Y here if you have an Apple USB BCM5974 Multitouch - trackpad. - - The BCM5974 is the multitouch trackpad found in the Macbook - Air (JAN2008) and Macbook Pro Penryn (FEB2008) laptops. - - It is also found in the IPhone (2007) and Ipod Touch (2008). - - This driver provides multitouch functionality together with - the synaptics X11 driver. - - The interface is currently identical to the appletouch interface, - for further information, see - . - - To compile this driver as a module, choose M here: the - module will be called bcm5974. - -config MOUSE_CYAPA - tristate "Cypress APA I2C Trackpad support" - depends on I2C - select CRC_ITU_T - help - This driver adds support for Cypress All Points Addressable (APA) - I2C Trackpads, including the ones used in 2012 Samsung Chromebooks. - - Say Y here if you have a Cypress APA I2C Trackpad. - - To compile this driver as a module, choose M here: the module will be - called cyapa. - -config MOUSE_ELAN_I2C - tristate "ELAN I2C Touchpad support" - depends on I2C - help - This driver adds support for Elan I2C/SMbus Trackpads. - - Say Y here if you have a ELAN I2C/SMbus Touchpad. - - To compile this driver as a module, choose M here: the module will be - called elan_i2c. - -config MOUSE_ELAN_I2C_I2C - bool "Enable I2C support" - depends on MOUSE_ELAN_I2C - default y - help - Say Y here if Elan Touchpad in your system is connected to - a standard I2C controller. - - If unsure, say Y. - -config MOUSE_ELAN_I2C_SMBUS - bool "Enable SMbus support" - depends on MOUSE_ELAN_I2C - help - Say Y here if Elan Touchpad in your system is connected to - a SMbus adapter. - - If unsure, say Y. - -config MOUSE_INPORT - tristate "InPort/MS/ATIXL busmouse" - depends on ISA - help - Say Y here if you have an InPort, Microsoft or ATI XL busmouse. - They are rather rare these days. - - To compile this driver as a module, choose M here: the - module will be called inport. - -config MOUSE_ATIXL - bool "ATI XL variant" - depends on MOUSE_INPORT - help - Say Y here if your mouse is of the ATI XL variety. - -config MOUSE_LOGIBM - tristate "Logitech busmouse" - depends on ISA - help - Say Y here if you have a Logitech busmouse. - They are rather rare these days. - - To compile this driver as a module, choose M here: the - module will be called logibm. - -config MOUSE_PC110PAD - tristate "IBM PC110 touchpad" - depends on ISA - help - Say Y if you have the IBM PC-110 micro-notebook and want its - touchpad supported. - - To compile this driver as a module, choose M here: the - module will be called pc110pad. - -config MOUSE_AMIGA - tristate "Amiga mouse" - depends on AMIGA - help - Say Y here if you have an Amiga and want its native mouse - supported by the kernel. - - To compile this driver as a module, choose M here: the - module will be called amimouse. - -config MOUSE_ATARI - tristate "Atari mouse" - depends on ATARI - select ATARI_KBD_CORE - help - Say Y here if you have an Atari and want its native mouse - supported by the kernel. - - To compile this driver as a module, choose M here: the - module will be called atarimouse. - -config MOUSE_RISCPC - tristate "Acorn RiscPC mouse" - depends on ARCH_ACORN - help - Say Y here if you have the Acorn RiscPC computer and want its - native mouse supported. - - To compile this driver as a module, choose M here: the - module will be called rpcmouse. - -config MOUSE_VSXXXAA - tristate "DEC VSXXX-AA/GA mouse and VSXXX-AB tablet" - select SERIO - help - Say Y (or M) if you want to use a DEC VSXXX-AA (hockey - puck) or a VSXXX-GA (rectangular) mouse. Theses mice are - typically used on DECstations or VAXstations, but can also - be used on any box capable of RS232 (with some adaptor - described in the source file). This driver also works with the - digitizer (VSXXX-AB) DEC produced. - -config MOUSE_GPIO - tristate "GPIO mouse" - depends on GPIOLIB || COMPILE_TEST - select INPUT_POLLDEV - help - This driver simulates a mouse on GPIO lines of various CPUs (and some - other chips). - - Say Y here if your device has buttons or a simple joystick connected - directly to GPIO lines. Your board-specific setup logic must also - provide a platform device and platform data saying which GPIOs are - used. - - To compile this driver as a module, choose M here: the - module will be called gpio_mouse. - -config MOUSE_PXA930_TRKBALL - tristate "PXA930 Trackball mouse" - depends on CPU_PXA930 || CPU_PXA935 - help - Say Y here to support PXA930 Trackball mouse. - -config MOUSE_MAPLE - tristate "Maple mouse (for the Dreamcast)" - depends on MAPLE - help - This driver supports the Maple mouse on the SEGA Dreamcast. - - Most Dreamcast users, who have a mouse, will say Y here. - - To compile this driver as a module choose M here: the module will be - called maplemouse. - -config MOUSE_SYNAPTICS_I2C - tristate "Synaptics I2C Touchpad support" - depends on I2C - help - This driver supports Synaptics I2C touchpad controller on eXeda - mobile device. - The device will not work the synaptics X11 driver because - (i) it reports only relative coordinates and has no capabilities - to report absolute coordinates - (ii) the eXeda device itself uses Xfbdev as X Server and it does - not allow using xf86-input-* drivers. - - Say y here if you have eXeda device and want to use a Synaptics - I2C Touchpad. - - To compile this driver as a module, choose M here: the - module will be called synaptics_i2c. - -config MOUSE_SYNAPTICS_USB - tristate "Synaptics USB device support" - depends on USB_ARCH_HAS_HCD - select USB - help - Say Y here if you want to use a Synaptics USB touchpad or pointing - stick. - - While these devices emulate an USB mouse by default and can be used - with standard usbhid driver, this driver, together with its X.Org - counterpart, allows you to fully utilize capabilities of the device. - More information can be found at: - - - To compile this driver as a module, choose M here: the - module will be called synaptics_usb. - -config MOUSE_NAVPOINT_PXA27x - tristate "Synaptics NavPoint (PXA27x SSP/SPI)" - depends on PXA27x && PXA_SSP - help - This driver adds support for the Synaptics NavPoint touchpad connected - to a PXA27x SSP port in SPI slave mode. The device emulates a mouse; - a tap or tap-and-a-half drag gesture emulates the left mouse button. - For example, use the xf86-input-evdev driver for an X pointing device. - - To compile this driver as a module, choose M here: the - module will be called navpoint. - -endif diff --git a/src/linux/drivers/input/mouse/Makefile b/src/linux/drivers/input/mouse/Makefile deleted file mode 100644 index 6168b13..0000000 --- a/src/linux/drivers/input/mouse/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -# -# Makefile for the mouse drivers. -# - -# Each configuration option enables a list of files. - -obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o -obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o -obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o -obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o -obj-$(CONFIG_MOUSE_CYAPA) += cyapatp.o -obj-$(CONFIG_MOUSE_ELAN_I2C) += elan_i2c.o -obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o -obj-$(CONFIG_MOUSE_INPORT) += inport.o -obj-$(CONFIG_MOUSE_LOGIBM) += logibm.o -obj-$(CONFIG_MOUSE_MAPLE) += maplemouse.o -obj-$(CONFIG_MOUSE_NAVPOINT_PXA27x) += navpoint.o -obj-$(CONFIG_MOUSE_PC110PAD) += pc110pad.o -obj-$(CONFIG_MOUSE_PS2) += psmouse.o -obj-$(CONFIG_MOUSE_PXA930_TRKBALL) += pxa930_trkball.o -obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o -obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o -obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o -obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o -obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o - -cyapatp-objs := cyapa.o cyapa_gen3.o cyapa_gen5.o cyapa_gen6.o -psmouse-objs := psmouse-base.o synaptics.o focaltech.o - -psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o -psmouse-$(CONFIG_MOUSE_PS2_BYD) += byd.o -psmouse-$(CONFIG_MOUSE_PS2_ELANTECH) += elantech.o -psmouse-$(CONFIG_MOUSE_PS2_OLPC) += hgpk.o -psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o -psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o -psmouse-$(CONFIG_MOUSE_PS2_SENTELIC) += sentelic.o -psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o -psmouse-$(CONFIG_MOUSE_PS2_TOUCHKIT) += touchkit_ps2.o -psmouse-$(CONFIG_MOUSE_PS2_CYPRESS) += cypress_ps2.o -psmouse-$(CONFIG_MOUSE_PS2_VMMOUSE) += vmmouse.o - -elan_i2c-objs := elan_i2c_core.o -elan_i2c-$(CONFIG_MOUSE_ELAN_I2C_I2C) += elan_i2c_i2c.o -elan_i2c-$(CONFIG_MOUSE_ELAN_I2C_SMBUS) += elan_i2c_smbus.o diff --git a/src/linux/drivers/input/mouse/alps.c b/src/linux/drivers/input/mouse/alps.c deleted file mode 100644 index 6d7de9b..0000000 --- a/src/linux/drivers/input/mouse/alps.c +++ /dev/null @@ -1,3109 +0,0 @@ -/* - * ALPS touchpad PS/2 mouse driver - * - * Copyright (c) 2003 Neil Brown - * Copyright (c) 2003-2005 Peter Osterlund - * Copyright (c) 2004 Dmitry Torokhov - * Copyright (c) 2005 Vojtech Pavlik - * Copyright (c) 2009 Sebastian Kapfer - * - * ALPS detection, tap switching and status querying info is taken from - * tpconfig utility (by C. Scott Ananian and Bruce Kall). - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -#include "psmouse.h" -#include "alps.h" - -/* - * Definitions for ALPS version 3 and 4 command mode protocol - */ -#define ALPS_CMD_NIBBLE_10 0x01f2 - -#define ALPS_REG_BASE_RUSHMORE 0xc2c0 -#define ALPS_REG_BASE_V7 0xc2c0 -#define ALPS_REG_BASE_PINNACLE 0x0000 - -static const struct alps_nibble_commands alps_v3_nibble_commands[] = { - { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */ - { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */ - { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* 2 */ - { PSMOUSE_CMD_SETRATE, 0x0a }, /* 3 */ - { PSMOUSE_CMD_SETRATE, 0x14 }, /* 4 */ - { PSMOUSE_CMD_SETRATE, 0x28 }, /* 5 */ - { PSMOUSE_CMD_SETRATE, 0x3c }, /* 6 */ - { PSMOUSE_CMD_SETRATE, 0x50 }, /* 7 */ - { PSMOUSE_CMD_SETRATE, 0x64 }, /* 8 */ - { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 9 */ - { ALPS_CMD_NIBBLE_10, 0x00 }, /* a */ - { PSMOUSE_CMD_SETRES, 0x00 }, /* b */ - { PSMOUSE_CMD_SETRES, 0x01 }, /* c */ - { PSMOUSE_CMD_SETRES, 0x02 }, /* d */ - { PSMOUSE_CMD_SETRES, 0x03 }, /* e */ - { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */ -}; - -static const struct alps_nibble_commands alps_v4_nibble_commands[] = { - { PSMOUSE_CMD_ENABLE, 0x00 }, /* 0 */ - { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */ - { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* 2 */ - { PSMOUSE_CMD_SETRATE, 0x0a }, /* 3 */ - { PSMOUSE_CMD_SETRATE, 0x14 }, /* 4 */ - { PSMOUSE_CMD_SETRATE, 0x28 }, /* 5 */ - { PSMOUSE_CMD_SETRATE, 0x3c }, /* 6 */ - { PSMOUSE_CMD_SETRATE, 0x50 }, /* 7 */ - { PSMOUSE_CMD_SETRATE, 0x64 }, /* 8 */ - { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 9 */ - { ALPS_CMD_NIBBLE_10, 0x00 }, /* a */ - { PSMOUSE_CMD_SETRES, 0x00 }, /* b */ - { PSMOUSE_CMD_SETRES, 0x01 }, /* c */ - { PSMOUSE_CMD_SETRES, 0x02 }, /* d */ - { PSMOUSE_CMD_SETRES, 0x03 }, /* e */ - { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */ -}; - -static const struct alps_nibble_commands alps_v6_nibble_commands[] = { - { PSMOUSE_CMD_ENABLE, 0x00 }, /* 0 */ - { PSMOUSE_CMD_SETRATE, 0x0a }, /* 1 */ - { PSMOUSE_CMD_SETRATE, 0x14 }, /* 2 */ - { PSMOUSE_CMD_SETRATE, 0x28 }, /* 3 */ - { PSMOUSE_CMD_SETRATE, 0x3c }, /* 4 */ - { PSMOUSE_CMD_SETRATE, 0x50 }, /* 5 */ - { PSMOUSE_CMD_SETRATE, 0x64 }, /* 6 */ - { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 7 */ - { PSMOUSE_CMD_GETID, 0x00 }, /* 8 */ - { PSMOUSE_CMD_GETINFO, 0x00 }, /* 9 */ - { PSMOUSE_CMD_SETRES, 0x00 }, /* a */ - { PSMOUSE_CMD_SETRES, 0x01 }, /* b */ - { PSMOUSE_CMD_SETRES, 0x02 }, /* c */ - { PSMOUSE_CMD_SETRES, 0x03 }, /* d */ - { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* e */ - { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */ -}; - - -#define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */ -#define ALPS_PASS 0x04 /* device has a pass-through port */ - -#define ALPS_WHEEL 0x08 /* hardware wheel present */ -#define ALPS_FW_BK_1 0x10 /* front & back buttons present */ -#define ALPS_FW_BK_2 0x20 /* front & back buttons present */ -#define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */ -#define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with - 6-byte ALPS packet */ -#define ALPS_STICK_BITS 0x100 /* separate stick button bits */ -#define ALPS_BUTTONPAD 0x200 /* device is a clickpad */ -#define ALPS_DUALPOINT_WITH_PRESSURE 0x400 /* device can report trackpoint pressure */ - -static const struct alps_model_info alps_model_data[] = { - { { 0x32, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Toshiba Salellite Pro M10 */ - { { 0x33, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V1, 0x88, 0xf8, 0 } }, /* UMAX-530T */ - { { 0x53, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x53, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x60, 0x03, 0xc8 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, /* HP ze1115 */ - { { 0x63, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x63, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x63, 0x02, 0x28 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Fujitsu Siemens S6010 */ - { { 0x63, 0x02, 0x3c }, 0x00, { ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL } }, /* Toshiba Satellite S2400-103 */ - { { 0x63, 0x02, 0x50 }, 0x00, { ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 } }, /* NEC Versa L320 */ - { { 0x63, 0x02, 0x64 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x63, 0x03, 0xc8 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D800 */ - { { 0x73, 0x00, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT } }, /* ThinkPad R61 8918-5QG */ - { { 0x73, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, - { { 0x73, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Ahtec Laptop */ - - /* - * XXX This entry is suspicious. First byte has zero lower nibble, - * which is what a normal mouse would report. Also, the value 0x0e - * isn't valid per PS/2 spec. - */ - { { 0x20, 0x02, 0x0e }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, - - { { 0x22, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, - { { 0x22, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D600 */ - /* Dell Latitude E5500, E6400, E6500, Precision M4400 */ - { { 0x62, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xcf, 0xcf, - ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, - { { 0x73, 0x00, 0x14 }, 0x00, { ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT } }, /* Dell XT2 */ - { { 0x73, 0x02, 0x50 }, 0x00, { ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS } }, /* Dell Vostro 1400 */ - { { 0x52, 0x01, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xff, 0xff, - ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, /* Toshiba Tecra A11-11L */ - { { 0x73, 0x02, 0x64 }, 0x8a, { ALPS_PROTO_V4, 0x8f, 0x8f, 0 } }, -}; - -static const struct alps_protocol_info alps_v3_protocol_data = { - ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT -}; - -static const struct alps_protocol_info alps_v3_rushmore_data = { - ALPS_PROTO_V3_RUSHMORE, 0x8f, 0x8f, ALPS_DUALPOINT -}; - -static const struct alps_protocol_info alps_v5_protocol_data = { - ALPS_PROTO_V5, 0xc8, 0xd8, 0 -}; - -static const struct alps_protocol_info alps_v7_protocol_data = { - ALPS_PROTO_V7, 0x48, 0x48, ALPS_DUALPOINT -}; - -static const struct alps_protocol_info alps_v8_protocol_data = { - ALPS_PROTO_V8, 0x18, 0x18, 0 -}; - -/* - * Some v2 models report the stick buttons in separate bits - */ -static const struct dmi_system_id alps_dmi_has_separate_stick_buttons[] = { -#if defined(CONFIG_DMI) && defined(CONFIG_X86) - { - /* Extrapolated from other entries */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D420"), - }, - }, - { - /* Reported-by: Hans de Bruin */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D430"), - }, - }, - { - /* Reported-by: Hans de Goede */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D620"), - }, - }, - { - /* Extrapolated from other entries */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), - DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D630"), - }, - }, -#endif - { } -}; - -static void alps_set_abs_params_st(struct alps_data *priv, - struct input_dev *dev1); -static void alps_set_abs_params_semi_mt(struct alps_data *priv, - struct input_dev *dev1); -static void alps_set_abs_params_v7(struct alps_data *priv, - struct input_dev *dev1); -static void alps_set_abs_params_ss4_v2(struct alps_data *priv, - struct input_dev *dev1); - -/* Packet formats are described in Documentation/input/alps.txt */ - -static bool alps_is_valid_first_byte(struct alps_data *priv, - unsigned char data) -{ - return (data & priv->mask0) == priv->byte0; -} - -static void alps_report_buttons(struct input_dev *dev1, struct input_dev *dev2, - int left, int right, int middle) -{ - struct input_dev *dev; - - /* - * If shared button has already been reported on the - * other device (dev2) then this event should be also - * sent through that device. - */ - dev = (dev2 && test_bit(BTN_LEFT, dev2->key)) ? dev2 : dev1; - input_report_key(dev, BTN_LEFT, left); - - dev = (dev2 && test_bit(BTN_RIGHT, dev2->key)) ? dev2 : dev1; - input_report_key(dev, BTN_RIGHT, right); - - dev = (dev2 && test_bit(BTN_MIDDLE, dev2->key)) ? dev2 : dev1; - input_report_key(dev, BTN_MIDDLE, middle); - - /* - * Sync the _other_ device now, we'll do the first - * device later once we report the rest of the events. - */ - if (dev2) - input_sync(dev2); -} - -static void alps_process_packet_v1_v2(struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - unsigned char *packet = psmouse->packet; - struct input_dev *dev = psmouse->dev; - struct input_dev *dev2 = priv->dev2; - int x, y, z, ges, fin, left, right, middle; - int back = 0, forward = 0; - - if (priv->proto_version == ALPS_PROTO_V1) { - left = packet[2] & 0x10; - right = packet[2] & 0x08; - middle = 0; - x = packet[1] | ((packet[0] & 0x07) << 7); - y = packet[4] | ((packet[3] & 0x07) << 7); - z = packet[5]; - } else { - left = packet[3] & 1; - right = packet[3] & 2; - middle = packet[3] & 4; - x = packet[1] | ((packet[2] & 0x78) << (7 - 3)); - y = packet[4] | ((packet[3] & 0x70) << (7 - 4)); - z = packet[5]; - } - - if (priv->flags & ALPS_FW_BK_1) { - back = packet[0] & 0x10; - forward = packet[2] & 4; - } - - if (priv->flags & ALPS_FW_BK_2) { - back = packet[3] & 4; - forward = packet[2] & 4; - if ((middle = forward && back)) - forward = back = 0; - } - - ges = packet[2] & 1; - fin = packet[2] & 2; - - if ((priv->flags & ALPS_DUALPOINT) && z == 127) { - input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x)); - input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y)); - - alps_report_buttons(dev2, dev, left, right, middle); - - input_sync(dev2); - return; - } - - /* Some models have separate stick button bits */ - if (priv->flags & ALPS_STICK_BITS) { - left |= packet[0] & 1; - right |= packet[0] & 2; - middle |= packet[0] & 4; - } - - alps_report_buttons(dev, dev2, left, right, middle); - - /* Convert hardware tap to a reasonable Z value */ - if (ges && !fin) - z = 40; - - /* - * A "tap and drag" operation is reported by the hardware as a transition - * from (!fin && ges) to (fin && ges). This should be translated to the - * sequence Z>0, Z==0, Z>0, so the Z==0 event has to be generated manually. - */ - if (ges && fin && !priv->prev_fin) { - input_report_abs(dev, ABS_X, x); - input_report_abs(dev, ABS_Y, y); - input_report_abs(dev, ABS_PRESSURE, 0); - input_report_key(dev, BTN_TOOL_FINGER, 0); - input_sync(dev); - } - priv->prev_fin = fin; - - if (z > 30) - input_report_key(dev, BTN_TOUCH, 1); - if (z < 25) - input_report_key(dev, BTN_TOUCH, 0); - - if (z > 0) { - input_report_abs(dev, ABS_X, x); - input_report_abs(dev, ABS_Y, y); - } - - input_report_abs(dev, ABS_PRESSURE, z); - input_report_key(dev, BTN_TOOL_FINGER, z > 0); - - if (priv->flags & ALPS_WHEEL) - input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07)); - - if (priv->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { - input_report_key(dev, BTN_FORWARD, forward); - input_report_key(dev, BTN_BACK, back); - } - - if (priv->flags & ALPS_FOUR_BUTTONS) { - input_report_key(dev, BTN_0, packet[2] & 4); - input_report_key(dev, BTN_1, packet[0] & 0x10); - input_report_key(dev, BTN_2, packet[3] & 4); - input_report_key(dev, BTN_3, packet[0] & 0x20); - } - - input_sync(dev); -} - -static void alps_get_bitmap_points(unsigned int map, - struct alps_bitmap_point *low, - struct alps_bitmap_point *high, - int *fingers) -{ - struct alps_bitmap_point *point; - int i, bit, prev_bit = 0; - - point = low; - for (i = 0; map != 0; i++, map >>= 1) { - bit = map & 1; - if (bit) { - if (!prev_bit) { - point->start_bit = i; - point->num_bits = 0; - (*fingers)++; - } - point->num_bits++; - } else { - if (prev_bit) - point = high; - } - prev_bit = bit; - } -} - -/* - * Process bitmap data from semi-mt protocols. Returns the number of - * fingers detected. A return value of 0 means at least one of the - * bitmaps was empty. - * - * The bitmaps don't have enough data to track fingers, so this function - * only generates points representing a bounding box of all contacts. - * These points are returned in fields->mt when the return value - * is greater than 0. - */ -static int alps_process_bitmap(struct alps_data *priv, - struct alps_fields *fields) -{ - int i, fingers_x = 0, fingers_y = 0, fingers, closest; - struct alps_bitmap_point x_low = {0,}, x_high = {0,}; - struct alps_bitmap_point y_low = {0,}, y_high = {0,}; - struct input_mt_pos corner[4]; - - if (!fields->x_map || !fields->y_map) - return 0; - - alps_get_bitmap_points(fields->x_map, &x_low, &x_high, &fingers_x); - alps_get_bitmap_points(fields->y_map, &y_low, &y_high, &fingers_y); - - /* - * Fingers can overlap, so we use the maximum count of fingers - * on either axis as the finger count. - */ - fingers = max(fingers_x, fingers_y); - - /* - * If an axis reports only a single contact, we have overlapping or - * adjacent fingers. Divide the single contact between the two points. - */ - if (fingers_x == 1) { - i = (x_low.num_bits - 1) / 2; - x_low.num_bits = x_low.num_bits - i; - x_high.start_bit = x_low.start_bit + i; - x_high.num_bits = max(i, 1); - } - if (fingers_y == 1) { - i = (y_low.num_bits - 1) / 2; - y_low.num_bits = y_low.num_bits - i; - y_high.start_bit = y_low.start_bit + i; - y_high.num_bits = max(i, 1); - } - - /* top-left corner */ - corner[0].x = - (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) / - (2 * (priv->x_bits - 1)); - corner[0].y = - (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) / - (2 * (priv->y_bits - 1)); - - /* top-right corner */ - corner[1].x = - (priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) / - (2 * (priv->x_bits - 1)); - corner[1].y = - (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) / - (2 * (priv->y_bits - 1)); - - /* bottom-right corner */ - corner[2].x = - (priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) / - (2 * (priv->x_bits - 1)); - corner[2].y = - (priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) / - (2 * (priv->y_bits - 1)); - - /* bottom-left corner */ - corner[3].x = - (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) / - (2 * (priv->x_bits - 1)); - corner[3].y = - (priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) / - (2 * (priv->y_bits - 1)); - - /* x-bitmap order is reversed on v5 touchpads */ - if (priv->proto_version == ALPS_PROTO_V5) { - for (i = 0; i < 4; i++) - corner[i].x = priv->x_max - corner[i].x; - } - - /* y-bitmap order is reversed on v3 and v4 touchpads */ - if (priv->proto_version == ALPS_PROTO_V3 || - priv->proto_version == ALPS_PROTO_V4) { - for (i = 0; i < 4; i++) - corner[i].y = priv->y_max - corner[i].y; - } - - /* - * We only select a corner for the second touch once per 2 finger - * touch sequence to avoid the chosen corner (and thus the coordinates) - * jumping around when the first touch is in the middle. - */ - if (priv->second_touch == -1) { - /* Find corner closest to our st coordinates */ - closest = 0x7fffffff; - for (i = 0; i < 4; i++) { - int dx = fields->st.x - corner[i].x; - int dy = fields->st.y - corner[i].y; - int distance = dx * dx + dy * dy; - - if (distance < closest) { - priv->second_touch = i; - closest = distance; - } - } - /* And select the opposite corner to use for the 2nd touch */ - priv->second_touch = (priv->second_touch + 2) % 4; - } - - fields->mt[0] = fields->st; - fields->mt[1] = corner[priv->second_touch]; - - return fingers; -} - -static void alps_set_slot(struct input_dev *dev, int slot, int x, int y) -{ - input_mt_slot(dev, slot); - input_mt_report_slot_state(dev, MT_TOOL_FINGER, true); - input_report_abs(dev, ABS_MT_POSITION_X, x); - input_report_abs(dev, ABS_MT_POSITION_Y, y); -} - -static void alps_report_mt_data(struct psmouse *psmouse, int n) -{ - struct alps_data *priv = psmouse->private; - struct input_dev *dev = psmouse->dev; - struct alps_fields *f = &priv->f; - int i, slot[MAX_TOUCHES]; - - input_mt_assign_slots(dev, slot, f->mt, n, 0); - for (i = 0; i < n; i++) - alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y); - - input_mt_sync_frame(dev); -} - -static void alps_report_semi_mt_data(struct psmouse *psmouse, int fingers) -{ - struct alps_data *priv = psmouse->private; - struct input_dev *dev = psmouse->dev; - struct alps_fields *f = &priv->f; - - /* Use st data when we don't have mt data */ - if (fingers < 2) { - f->mt[0].x = f->st.x; - f->mt[0].y = f->st.y; - fingers = f->pressure > 0 ? 1 : 0; - priv->second_touch = -1; - } - - if (fingers >= 1) - alps_set_slot(dev, 0, f->mt[0].x, f->mt[0].y); - if (fingers >= 2) - alps_set_slot(dev, 1, f->mt[1].x, f->mt[1].y); - input_mt_sync_frame(dev); - - input_mt_report_finger_count(dev, fingers); - - input_report_key(dev, BTN_LEFT, f->left); - input_report_key(dev, BTN_RIGHT, f->right); - input_report_key(dev, BTN_MIDDLE, f->middle); - - input_report_abs(dev, ABS_PRESSURE, f->pressure); - - input_sync(dev); -} - -static void alps_process_trackstick_packet_v3(struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - unsigned char *packet = psmouse->packet; - struct input_dev *dev = priv->dev2; - int x, y, z, left, right, middle; - - /* It should be a DualPoint when received trackstick packet */ - if (!(priv->flags & ALPS_DUALPOINT)) { - psmouse_warn(psmouse, - "Rejected trackstick packet from non DualPoint device"); - return; - } - - /* Sanity check packet */ - if (!(packet[0] & 0x40)) { - psmouse_dbg(psmouse, "Bad trackstick packet, discarding\n"); - return; - } - - /* - * There's a special packet that seems to indicate the end - * of a stream of trackstick data. Filter these out. - */ - if (packet[1] == 0x7f && packet[2] == 0x7f && packet[4] == 0x7f) - return; - - x = (s8)(((packet[0] & 0x20) << 2) | (packet[1] & 0x7f)); - y = (s8)(((packet[0] & 0x10) << 3) | (packet[2] & 0x7f)); - z = (packet[4] & 0x7c) >> 2; - - /* - * The x and y values tend to be quite large, and when used - * alone the trackstick is difficult to use. Scale them down - * to compensate. - */ - x /= 8; - y /= 8; - - input_report_rel(dev, REL_X, x); - input_report_rel(dev, REL_Y, -y); - - /* - * Most ALPS models report the trackstick buttons in the touchpad - * packets, but a few report them here. No reliable way has been - * found to differentiate between the models upfront, so we enable - * the quirk in response to seeing a button press in the trackstick - * packet. - */ - left = packet[3] & 0x01; - right = packet[3] & 0x02; - middle = packet[3] & 0x04; - - if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS) && - (left || right || middle)) - priv->quirks |= ALPS_QUIRK_TRACKSTICK_BUTTONS; - - if (priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS) { - input_report_key(dev, BTN_LEFT, left); - input_report_key(dev, BTN_RIGHT, right); - input_report_key(dev, BTN_MIDDLE, middle); - } - - input_sync(dev); - return; -} - -static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p) -{ - f->left = !!(p[3] & 0x01); - f->right = !!(p[3] & 0x02); - f->middle = !!(p[3] & 0x04); - - f->ts_left = !!(p[3] & 0x10); - f->ts_right = !!(p[3] & 0x20); - f->ts_middle = !!(p[3] & 0x40); -} - -static int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p, - struct psmouse *psmouse) -{ - f->first_mp = !!(p[4] & 0x40); - f->is_mp = !!(p[0] & 0x40); - - if (f->is_mp) { - f->fingers = (p[5] & 0x3) + 1; - f->x_map = ((p[4] & 0x7e) << 8) | - ((p[1] & 0x7f) << 2) | - ((p[0] & 0x30) >> 4); - f->y_map = ((p[3] & 0x70) << 4) | - ((p[2] & 0x7f) << 1) | - (p[4] & 0x01); - } else { - f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) | - ((p[0] & 0x30) >> 4); - f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f); - f->pressure = p[5] & 0x7f; - - alps_decode_buttons_v3(f, p); - } - - return 0; -} - -static int alps_decode_rushmore(struct alps_fields *f, unsigned char *p, - struct psmouse *psmouse) -{ - f->first_mp = !!(p[4] & 0x40); - f->is_mp = !!(p[5] & 0x40); - - if (f->is_mp) { - f->fingers = max((p[5] & 0x3), ((p[5] >> 2) & 0x3)) + 1; - f->x_map = ((p[5] & 0x10) << 11) | - ((p[4] & 0x7e) << 8) | - ((p[1] & 0x7f) << 2) | - ((p[0] & 0x30) >> 4); - f->y_map = ((p[5] & 0x20) << 6) | - ((p[3] & 0x70) << 4) | - ((p[2] & 0x7f) << 1) | - (p[4] & 0x01); - } else { - f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) | - ((p[0] & 0x30) >> 4); - f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f); - f->pressure = p[5] & 0x7f; - - alps_decode_buttons_v3(f, p); - } - - return 0; -} - -static int alps_decode_dolphin(struct alps_fields *f, unsigned char *p, - struct psmouse *psmouse) -{ - u64 palm_data = 0; - struct alps_data *priv = psmouse->private; - - f->first_mp = !!(p[0] & 0x02); - f->is_mp = !!(p[0] & 0x20); - - if (!f->is_mp) { - f->st.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7)); - f->st.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3)); - f->pressure = (p[0] & 4) ? 0 : p[5] & 0x7f; - alps_decode_buttons_v3(f, p); - } else { - f->fingers = ((p[0] & 0x6) >> 1 | - (p[0] & 0x10) >> 2); - - palm_data = (p[1] & 0x7f) | - ((p[2] & 0x7f) << 7) | - ((p[4] & 0x7f) << 14) | - ((p[5] & 0x7f) << 21) | - ((p[3] & 0x07) << 28) | - (((u64)p[3] & 0x70) << 27) | - (((u64)p[0] & 0x01) << 34); - - /* Y-profile is stored in P(0) to p(n-1), n = y_bits; */ - f->y_map = palm_data & (BIT(priv->y_bits) - 1); - - /* X-profile is stored in p(n) to p(n+m-1), m = x_bits; */ - f->x_map = (palm_data >> priv->y_bits) & - (BIT(priv->x_bits) - 1); - } - - return 0; -} - -static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - unsigned char *packet = psmouse->packet; - struct input_dev *dev2 = priv->dev2; - struct alps_fields *f = &priv->f; - int fingers = 0; - - memset(f, 0, sizeof(*f)); - - priv->decode_fields(f, packet, psmouse); - - /* - * There's no single feature of touchpad position and bitmap packets - * that can be used to distinguish between them. We rely on the fact - * that a bitmap packet should always follow a position packet with - * bit 6 of packet[4] set. - */ - if (priv->multi_packet) { - /* - * Sometimes a position packet will indicate a multi-packet - * sequence, but then what follows is another position - * packet. Check for this, and when it happens process the - * position packet as usual. - */ - if (f->is_mp) { - fingers = f->fingers; - /* - * Bitmap processing uses position packet's coordinate - * data, so we need to do decode it first. - */ - priv->decode_fields(f, priv->multi_data, psmouse); - if (alps_process_bitmap(priv, f) == 0) - fingers = 0; /* Use st data */ - } else { - priv->multi_packet = 0; - } - } - - /* - * Bit 6 of byte 0 is not usually set in position packets. The only - * times it seems to be set is in situations where the data is - * suspect anyway, e.g. a palm resting flat on the touchpad. Given - * this combined with the fact that this bit is useful for filtering - * out misidentified bitmap packets, we reject anything with this - * bit set. - */ - if (f->is_mp) - return; - - if (!priv->multi_packet && f->first_mp) { - priv->multi_packet = 1; - memcpy(priv->multi_data, packet, sizeof(priv->multi_data)); - return; - } - - priv->multi_packet = 0; - - /* - * Sometimes the hardware sends a single packet with z = 0 - * in the middle of a stream. Real releases generate packets - * with x, y, and z all zero, so these seem to be flukes. - * Ignore them. - */ - if (f->st.x && f->st.y && !f->pressure) - return; - - alps_report_semi_mt_data(psmouse, fingers); - - if ((priv->flags & ALPS_DUALPOINT) && - !(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) { - input_report_key(dev2, BTN_LEFT, f->ts_left); - input_report_key(dev2, BTN_RIGHT, f->ts_right); - input_report_key(dev2, BTN_MIDDLE, f->ts_middle); - input_sync(dev2); - } -} - -static void alps_process_packet_v3(struct psmouse *psmouse) -{ - unsigned char *packet = psmouse->packet; - - /* - * v3 protocol packets come in three types, two representing - * touchpad data and one representing trackstick data. - * Trackstick packets seem to be distinguished by always - * having 0x3f in the last byte. This value has never been - * observed in the last byte of either of the other types - * of packets. - */ - if (packet[5] == 0x3f) { - alps_process_trackstick_packet_v3(psmouse); - return; - } - - alps_process_touchpad_packet_v3_v5(psmouse); -} - -static void alps_process_packet_v6(struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - unsigned char *packet = psmouse->packet; - struct input_dev *dev = psmouse->dev; - struct input_dev *dev2 = priv->dev2; - int x, y, z, left, right, middle; - - /* - * We can use Byte5 to distinguish if the packet is from Touchpad - * or Trackpoint. - * Touchpad: 0 - 0x7E - * Trackpoint: 0x7F - */ - if (packet[5] == 0x7F) { - /* It should be a DualPoint when received Trackpoint packet */ - if (!(priv->flags & ALPS_DUALPOINT)) { - psmouse_warn(psmouse, - "Rejected trackstick packet from non DualPoint device"); - return; - } - - /* Trackpoint packet */ - x = packet[1] | ((packet[3] & 0x20) << 2); - y = packet[2] | ((packet[3] & 0x40) << 1); - z = packet[4]; - left = packet[3] & 0x01; - right = packet[3] & 0x02; - middle = packet[3] & 0x04; - - /* To prevent the cursor jump when finger lifted */ - if (x == 0x7F && y == 0x7F && z == 0x7F) - x = y = z = 0; - - /* Divide 4 since trackpoint's speed is too fast */ - input_report_rel(dev2, REL_X, (char)x / 4); - input_report_rel(dev2, REL_Y, -((char)y / 4)); - - input_report_key(dev2, BTN_LEFT, left); - input_report_key(dev2, BTN_RIGHT, right); - input_report_key(dev2, BTN_MIDDLE, middle); - - input_sync(dev2); - return; - } - - /* Touchpad packet */ - x = packet[1] | ((packet[3] & 0x78) << 4); - y = packet[2] | ((packet[4] & 0x78) << 4); - z = packet[5]; - left = packet[3] & 0x01; - right = packet[3] & 0x02; - - if (z > 30) - input_report_key(dev, BTN_TOUCH, 1); - if (z < 25) - input_report_key(dev, BTN_TOUCH, 0); - - if (z > 0) { - input_report_abs(dev, ABS_X, x); - input_report_abs(dev, ABS_Y, y); - } - - input_report_abs(dev, ABS_PRESSURE, z); - input_report_key(dev, BTN_TOOL_FINGER, z > 0); - - /* v6 touchpad does not have middle button */ - input_report_key(dev, BTN_LEFT, left); - input_report_key(dev, BTN_RIGHT, right); - - input_sync(dev); -} - -static void alps_process_packet_v4(struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - unsigned char *packet = psmouse->packet; - struct alps_fields *f = &priv->f; - int offset; - - /* - * v4 has a 6-byte encoding for bitmap data, but this data is - * broken up between 3 normal packets. Use priv->multi_packet to - * track our position in the bitmap packet. - */ - if (packet[6] & 0x40) { - /* sync, reset position */ - priv->multi_packet = 0; - } - - if (WARN_ON_ONCE(priv->multi_packet > 2)) - return; - - offset = 2 * priv->multi_packet; - priv->multi_data[offset] = packet[6]; - priv->multi_data[offset + 1] = packet[7]; - - f->left = !!(packet[4] & 0x01); - f->right = !!(packet[4] & 0x02); - - f->st.x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) | - ((packet[0] & 0x30) >> 4); - f->st.y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f); - f->pressure = packet[5] & 0x7f; - - if (++priv->multi_packet > 2) { - priv->multi_packet = 0; - - f->x_map = ((priv->multi_data[2] & 0x1f) << 10) | - ((priv->multi_data[3] & 0x60) << 3) | - ((priv->multi_data[0] & 0x3f) << 2) | - ((priv->multi_data[1] & 0x60) >> 5); - f->y_map = ((priv->multi_data[5] & 0x01) << 10) | - ((priv->multi_data[3] & 0x1f) << 5) | - (priv->multi_data[1] & 0x1f); - - f->fingers = alps_process_bitmap(priv, f); - } - - alps_report_semi_mt_data(psmouse, f->fingers); -} - -static bool alps_is_valid_package_v7(struct psmouse *psmouse) -{ - switch (psmouse->pktcnt) { - case 3: - return (psmouse->packet[2] & 0x40) == 0x40; - case 4: - return (psmouse->packet[3] & 0x48) == 0x48; - case 6: - return (psmouse->packet[5] & 0x40) == 0x00; - } - return true; -} - -static unsigned char alps_get_packet_id_v7(char *byte) -{ - unsigned char packet_id; - - if (byte[4] & 0x40) - packet_id = V7_PACKET_ID_TWO; - else if (byte[4] & 0x01) - packet_id = V7_PACKET_ID_MULTI; - else if ((byte[0] & 0x10) && !(byte[4] & 0x43)) - packet_id = V7_PACKET_ID_NEW; - else if (byte[1] == 0x00 && byte[4] == 0x00) - packet_id = V7_PACKET_ID_IDLE; - else - packet_id = V7_PACKET_ID_UNKNOWN; - - return packet_id; -} - -static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt, - unsigned char *pkt, - unsigned char pkt_id) -{ - mt[0].x = ((pkt[2] & 0x80) << 4); - mt[0].x |= ((pkt[2] & 0x3F) << 5); - mt[0].x |= ((pkt[3] & 0x30) >> 1); - mt[0].x |= (pkt[3] & 0x07); - mt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07); - - mt[1].x = ((pkt[3] & 0x80) << 4); - mt[1].x |= ((pkt[4] & 0x80) << 3); - mt[1].x |= ((pkt[4] & 0x3F) << 4); - mt[1].y = ((pkt[5] & 0x80) << 3); - mt[1].y |= ((pkt[5] & 0x3F) << 4); - - switch (pkt_id) { - case V7_PACKET_ID_TWO: - mt[1].x &= ~0x000F; - mt[1].y |= 0x000F; - /* Detect false-postive touches where x & y report max value */ - if (mt[1].y == 0x7ff && mt[1].x == 0xff0) { - mt[1].x = 0; - /* y gets set to 0 at the end of this function */ - } - break; - - case V7_PACKET_ID_MULTI: - mt[1].x &= ~0x003F; - mt[1].y &= ~0x0020; - mt[1].y |= ((pkt[4] & 0x02) << 4); - mt[1].y |= 0x001F; - break; - - case V7_PACKET_ID_NEW: - mt[1].x &= ~0x003F; - mt[1].x |= (pkt[0] & 0x20); - mt[1].y |= 0x000F; - break; - } - - mt[0].y = 0x7FF - mt[0].y; - mt[1].y = 0x7FF - mt[1].y; -} - -static int alps_get_mt_count(struct input_mt_pos *mt) -{ - int i, fingers = 0; - - for (i = 0; i < MAX_TOUCHES; i++) { - if (mt[i].x != 0 || mt[i].y != 0) - fingers++; - } - - return fingers; -} - -static int alps_decode_packet_v7(struct alps_fields *f, - unsigned char *p, - struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - unsigned char pkt_id; - - pkt_id = alps_get_packet_id_v7(p); - if (pkt_id == V7_PACKET_ID_IDLE) - return 0; - if (pkt_id == V7_PACKET_ID_UNKNOWN) - return -1; - /* - * NEW packets are send to indicate a discontinuity in the finger - * coordinate reporting. Specifically a finger may have moved from - * slot 0 to 1 or vice versa. INPUT_MT_TRACK takes care of this for - * us. - * - * NEW packets have 3 problems: - * 1) They do not contain middle / right button info (on non clickpads) - * this can be worked around by preserving the old button state - * 2) They do not contain an accurate fingercount, and they are - * typically send when the number of fingers changes. We cannot use - * the old finger count as that may mismatch with the amount of - * touch coordinates we've available in the NEW packet - * 3) Their x data for the second touch is inaccurate leading to - * a possible jump of the x coordinate by 16 units when the first - * non NEW packet comes in - * Since problems 2 & 3 cannot be worked around, just ignore them. - */ - if (pkt_id == V7_PACKET_ID_NEW) - return 1; - - alps_get_finger_coordinate_v7(f->mt, p, pkt_id); - - if (pkt_id == V7_PACKET_ID_TWO) - f->fingers = alps_get_mt_count(f->mt); - else /* pkt_id == V7_PACKET_ID_MULTI */ - f->fingers = 3 + (p[5] & 0x03); - - f->left = (p[0] & 0x80) >> 7; - if (priv->flags & ALPS_BUTTONPAD) { - if (p[0] & 0x20) - f->fingers++; - if (p[0] & 0x10) - f->fingers++; - } else { - f->right = (p[0] & 0x20) >> 5; - f->middle = (p[0] & 0x10) >> 4; - } - - /* Sometimes a single touch is reported in mt[1] rather then mt[0] */ - if (f->fingers == 1 && f->mt[0].x == 0 && f->mt[0].y == 0) { - f->mt[0].x = f->mt[1].x; - f->mt[0].y = f->mt[1].y; - f->mt[1].x = 0; - f->mt[1].y = 0; - } - - return 0; -} - -static void alps_process_trackstick_packet_v7(struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - unsigned char *packet = psmouse->packet; - struct input_dev *dev2 = priv->dev2; - int x, y, z, left, right, middle; - - /* It should be a DualPoint when received trackstick packet */ - if (!(priv->flags & ALPS_DUALPOINT)) { - psmouse_warn(psmouse, - "Rejected trackstick packet from non DualPoint device"); - return; - } - - x = ((packet[2] & 0xbf)) | ((packet[3] & 0x10) << 2); - y = (packet[3] & 0x07) | (packet[4] & 0xb8) | - ((packet[3] & 0x20) << 1); - z = (packet[5] & 0x3f) | ((packet[3] & 0x80) >> 1); - - left = (packet[1] & 0x01); - right = (packet[1] & 0x02) >> 1; - middle = (packet[1] & 0x04) >> 2; - - input_report_rel(dev2, REL_X, (char)x); - input_report_rel(dev2, REL_Y, -((char)y)); - - input_report_key(dev2, BTN_LEFT, left); - input_report_key(dev2, BTN_RIGHT, right); - input_report_key(dev2, BTN_MIDDLE, middle); - - input_sync(dev2); -} - -static void alps_process_touchpad_packet_v7(struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - struct input_dev *dev = psmouse->dev; - struct alps_fields *f = &priv->f; - - memset(f, 0, sizeof(*f)); - - if (priv->decode_fields(f, psmouse->packet, psmouse)) - return; - - alps_report_mt_data(psmouse, alps_get_mt_count(f->mt)); - - input_mt_report_finger_count(dev, f->fingers); - - input_report_key(dev, BTN_LEFT, f->left); - input_report_key(dev, BTN_RIGHT, f->right); - input_report_key(dev, BTN_MIDDLE, f->middle); - - input_sync(dev); -} - -static void alps_process_packet_v7(struct psmouse *psmouse) -{ - unsigned char *packet = psmouse->packet; - - if (packet[0] == 0x48 && (packet[4] & 0x47) == 0x06) - alps_process_trackstick_packet_v7(psmouse); - else - alps_process_touchpad_packet_v7(psmouse); -} - -static unsigned char alps_get_pkt_id_ss4_v2(unsigned char *byte) -{ - unsigned char pkt_id = SS4_PACKET_ID_IDLE; - - switch (byte[3] & 0x30) { - case 0x00: - if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 && - (byte[3] & 0x88) == 0x08 && byte[4] == 0x10 && - byte[5] == 0x00) { - pkt_id = SS4_PACKET_ID_IDLE; - } else { - pkt_id = SS4_PACKET_ID_ONE; - } - break; - case 0x10: - /* two-finger finger positions */ - pkt_id = SS4_PACKET_ID_TWO; - break; - case 0x20: - /* stick pointer */ - pkt_id = SS4_PACKET_ID_STICK; - break; - case 0x30: - /* third and fourth finger positions */ - pkt_id = SS4_PACKET_ID_MULTI; - break; - } - - return pkt_id; -} - -static int alps_decode_ss4_v2(struct alps_fields *f, - unsigned char *p, struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - unsigned char pkt_id; - unsigned int no_data_x, no_data_y; - - pkt_id = alps_get_pkt_id_ss4_v2(p); - - /* Current packet is 1Finger coordinate packet */ - switch (pkt_id) { - case SS4_PACKET_ID_ONE: - f->mt[0].x = SS4_1F_X_V2(p); - f->mt[0].y = SS4_1F_Y_V2(p); - f->pressure = ((SS4_1F_Z_V2(p)) * 2) & 0x7f; - /* - * When a button is held the device will give us events - * with x, y, and pressure of 0. This causes annoying jumps - * if a touch is released while the button is held. - * Handle this by claiming zero contacts. - */ - f->fingers = f->pressure > 0 ? 1 : 0; - f->first_mp = 0; - f->is_mp = 0; - break; - - case SS4_PACKET_ID_TWO: - if (priv->flags & ALPS_BUTTONPAD) { - f->mt[0].x = SS4_BTL_MF_X_V2(p, 0); - f->mt[0].y = SS4_BTL_MF_Y_V2(p, 0); - f->mt[1].x = SS4_BTL_MF_X_V2(p, 1); - f->mt[1].y = SS4_BTL_MF_Y_V2(p, 1); - } else { - f->mt[0].x = SS4_STD_MF_X_V2(p, 0); - f->mt[0].y = SS4_STD_MF_Y_V2(p, 0); - f->mt[1].x = SS4_STD_MF_X_V2(p, 1); - f->mt[1].y = SS4_STD_MF_Y_V2(p, 1); - } - f->pressure = SS4_MF_Z_V2(p, 0) ? 0x30 : 0; - - if (SS4_IS_MF_CONTINUE(p)) { - f->first_mp = 1; - } else { - f->fingers = 2; - f->first_mp = 0; - } - f->is_mp = 0; - - break; - - case SS4_PACKET_ID_MULTI: - if (priv->flags & ALPS_BUTTONPAD) { - f->mt[2].x = SS4_BTL_MF_X_V2(p, 0); - f->mt[2].y = SS4_BTL_MF_Y_V2(p, 0); - f->mt[3].x = SS4_BTL_MF_X_V2(p, 1); - f->mt[3].y = SS4_BTL_MF_Y_V2(p, 1); - no_data_x = SS4_MFPACKET_NO_AX_BL; - no_data_y = SS4_MFPACKET_NO_AY_BL; - } else { - f->mt[2].x = SS4_STD_MF_X_V2(p, 0); - f->mt[2].y = SS4_STD_MF_Y_V2(p, 0); - f->mt[3].x = SS4_STD_MF_X_V2(p, 1); - f->mt[3].y = SS4_STD_MF_Y_V2(p, 1); - no_data_x = SS4_MFPACKET_NO_AX; - no_data_y = SS4_MFPACKET_NO_AY; - } - - f->first_mp = 0; - f->is_mp = 1; - - if (SS4_IS_5F_DETECTED(p)) { - f->fingers = 5; - } else if (f->mt[3].x == no_data_x && - f->mt[3].y == no_data_y) { - f->mt[3].x = 0; - f->mt[3].y = 0; - f->fingers = 3; - } else { - f->fingers = 4; - } - break; - - case SS4_PACKET_ID_STICK: - if (!(priv->flags & ALPS_DUALPOINT)) { - psmouse_warn(psmouse, - "Rejected trackstick packet from non DualPoint device"); - } else { - int x = (s8)(((p[0] & 1) << 7) | (p[1] & 0x7f)); - int y = (s8)(((p[3] & 1) << 7) | (p[2] & 0x7f)); - int pressure = (s8)(p[4] & 0x7f); - - input_report_rel(priv->dev2, REL_X, x); - input_report_rel(priv->dev2, REL_Y, -y); - input_report_abs(priv->dev2, ABS_PRESSURE, pressure); - } - break; - - case SS4_PACKET_ID_IDLE: - default: - memset(f, 0, sizeof(struct alps_fields)); - break; - } - - /* handle buttons */ - if (pkt_id == SS4_PACKET_ID_STICK) { - f->ts_left = !!(SS4_BTN_V2(p) & 0x01); - if (!(priv->flags & ALPS_BUTTONPAD)) { - f->ts_right = !!(SS4_BTN_V2(p) & 0x02); - f->ts_middle = !!(SS4_BTN_V2(p) & 0x04); - } - } else { - f->left = !!(SS4_BTN_V2(p) & 0x01); - if (!(priv->flags & ALPS_BUTTONPAD)) { - f->right = !!(SS4_BTN_V2(p) & 0x02); - f->middle = !!(SS4_BTN_V2(p) & 0x04); - } - } - - return 0; -} - -static void alps_process_packet_ss4_v2(struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - unsigned char *packet = psmouse->packet; - struct input_dev *dev = psmouse->dev; - struct input_dev *dev2 = priv->dev2; - struct alps_fields *f = &priv->f; - - memset(f, 0, sizeof(struct alps_fields)); - priv->decode_fields(f, packet, psmouse); - if (priv->multi_packet) { - /* - * Sometimes the first packet will indicate a multi-packet - * sequence, but sometimes the next multi-packet would not - * come. Check for this, and when it happens process the - * position packet as usual. - */ - if (f->is_mp) { - /* Now process the 1st packet */ - priv->decode_fields(f, priv->multi_data, psmouse); - } else { - priv->multi_packet = 0; - } - } - - /* - * "f.is_mp" would always be '0' after merging the 1st and 2nd packet. - * When it is set, it means 2nd packet comes without 1st packet come. - */ - if (f->is_mp) - return; - - /* Save the first packet */ - if (!priv->multi_packet && f->first_mp) { - priv->multi_packet = 1; - memcpy(priv->multi_data, packet, sizeof(priv->multi_data)); - return; - } - - priv->multi_packet = 0; - - alps_report_mt_data(psmouse, (f->fingers <= 4) ? f->fingers : 4); - - input_mt_report_finger_count(dev, f->fingers); - - input_report_key(dev, BTN_LEFT, f->left); - input_report_key(dev, BTN_RIGHT, f->right); - input_report_key(dev, BTN_MIDDLE, f->middle); - - input_report_abs(dev, ABS_PRESSURE, f->pressure); - input_sync(dev); - - if (priv->flags & ALPS_DUALPOINT) { - input_report_key(dev2, BTN_LEFT, f->ts_left); - input_report_key(dev2, BTN_RIGHT, f->ts_right); - input_report_key(dev2, BTN_MIDDLE, f->ts_middle); - input_sync(dev2); - } -} - -static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse) -{ - if (psmouse->pktcnt == 4 && ((psmouse->packet[3] & 0x08) != 0x08)) - return false; - if (psmouse->pktcnt == 6 && ((psmouse->packet[5] & 0x10) != 0x0)) - return false; - return true; -} - -static DEFINE_MUTEX(alps_mutex); - -static void alps_register_bare_ps2_mouse(struct work_struct *work) -{ - struct alps_data *priv = - container_of(work, struct alps_data, dev3_register_work.work); - struct psmouse *psmouse = priv->psmouse; - struct input_dev *dev3; - int error = 0; - - mutex_lock(&alps_mutex); - - if (priv->dev3) - goto out; - - dev3 = input_allocate_device(); - if (!dev3) { - psmouse_err(psmouse, "failed to allocate secondary device\n"); - error = -ENOMEM; - goto out; - } - - snprintf(priv->phys3, sizeof(priv->phys3), "%s/%s", - psmouse->ps2dev.serio->phys, - (priv->dev2 ? "input2" : "input1")); - dev3->phys = priv->phys3; - - /* - * format of input device name is: "protocol vendor name" - * see function psmouse_switch_protocol() in psmouse-base.c - */ - dev3->name = "PS/2 ALPS Mouse"; - - dev3->id.bustype = BUS_I8042; - dev3->id.vendor = 0x0002; - dev3->id.product = PSMOUSE_PS2; - dev3->id.version = 0x0000; - dev3->dev.parent = &psmouse->ps2dev.serio->dev; - - input_set_capability(dev3, EV_REL, REL_X); - input_set_capability(dev3, EV_REL, REL_Y); - input_set_capability(dev3, EV_KEY, BTN_LEFT); - input_set_capability(dev3, EV_KEY, BTN_RIGHT); - input_set_capability(dev3, EV_KEY, BTN_MIDDLE); - - __set_bit(INPUT_PROP_POINTER, dev3->propbit); - - error = input_register_device(dev3); - if (error) { - psmouse_err(psmouse, - "failed to register secondary device: %d\n", - error); - input_free_device(dev3); - goto out; - } - - priv->dev3 = dev3; - -out: - /* - * Save the error code so that we can detect that we - * already tried to create the device. - */ - if (error) - priv->dev3 = ERR_PTR(error); - - mutex_unlock(&alps_mutex); -} - -static void alps_report_bare_ps2_packet(struct psmouse *psmouse, - unsigned char packet[], - bool report_buttons) -{ - struct alps_data *priv = psmouse->private; - struct input_dev *dev, *dev2 = NULL; - - /* Figure out which device to use to report the bare packet */ - if (priv->proto_version == ALPS_PROTO_V2 && - (priv->flags & ALPS_DUALPOINT)) { - /* On V2 devices the DualPoint Stick reports bare packets */ - dev = priv->dev2; - dev2 = psmouse->dev; - } else if (unlikely(IS_ERR_OR_NULL(priv->dev3))) { - /* Register dev3 mouse if we received PS/2 packet first time */ - if (!IS_ERR(priv->dev3)) - psmouse_queue_work(psmouse, &priv->dev3_register_work, - 0); - return; - } else { - dev = priv->dev3; - } - - if (report_buttons) - alps_report_buttons(dev, dev2, - packet[0] & 1, packet[0] & 2, packet[0] & 4); - - input_report_rel(dev, REL_X, - packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0); - input_report_rel(dev, REL_Y, - packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0); - - input_sync(dev); -} - -static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - - if (psmouse->pktcnt < 6) - return PSMOUSE_GOOD_DATA; - - if (psmouse->pktcnt == 6) { - /* - * Start a timer to flush the packet if it ends up last - * 6-byte packet in the stream. Timer needs to fire - * psmouse core times out itself. 20 ms should be enough - * to decide if we are getting more data or not. - */ - mod_timer(&priv->timer, jiffies + msecs_to_jiffies(20)); - return PSMOUSE_GOOD_DATA; - } - - del_timer(&priv->timer); - - if (psmouse->packet[6] & 0x80) { - - /* - * Highest bit is set - that means we either had - * complete ALPS packet and this is start of the - * next packet or we got garbage. - */ - - if (((psmouse->packet[3] | - psmouse->packet[4] | - psmouse->packet[5]) & 0x80) || - (!alps_is_valid_first_byte(priv, psmouse->packet[6]))) { - psmouse_dbg(psmouse, - "refusing packet %4ph (suspected interleaved ps/2)\n", - psmouse->packet + 3); - return PSMOUSE_BAD_DATA; - } - - priv->process_packet(psmouse); - - /* Continue with the next packet */ - psmouse->packet[0] = psmouse->packet[6]; - psmouse->pktcnt = 1; - - } else { - - /* - * High bit is 0 - that means that we indeed got a PS/2 - * packet in the middle of ALPS packet. - * - * There is also possibility that we got 6-byte ALPS - * packet followed by 3-byte packet from trackpoint. We - * can not distinguish between these 2 scenarios but - * because the latter is unlikely to happen in course of - * normal operation (user would need to press all - * buttons on the pad and start moving trackpoint - * without touching the pad surface) we assume former. - * Even if we are wrong the wost thing that would happen - * the cursor would jump but we should not get protocol - * de-synchronization. - */ - - alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3], - false); - - /* - * Continue with the standard ALPS protocol handling, - * but make sure we won't process it as an interleaved - * packet again, which may happen if all buttons are - * pressed. To avoid this let's reset the 4th bit which - * is normally 1. - */ - psmouse->packet[3] = psmouse->packet[6] & 0xf7; - psmouse->pktcnt = 4; - } - - return PSMOUSE_GOOD_DATA; -} - -static void alps_flush_packet(unsigned long data) -{ - struct psmouse *psmouse = (struct psmouse *)data; - struct alps_data *priv = psmouse->private; - - serio_pause_rx(psmouse->ps2dev.serio); - - if (psmouse->pktcnt == psmouse->pktsize) { - - /* - * We did not any more data in reasonable amount of time. - * Validate the last 3 bytes and process as a standard - * ALPS packet. - */ - if ((psmouse->packet[3] | - psmouse->packet[4] | - psmouse->packet[5]) & 0x80) { - psmouse_dbg(psmouse, - "refusing packet %3ph (suspected interleaved ps/2)\n", - psmouse->packet + 3); - } else { - priv->process_packet(psmouse); - } - psmouse->pktcnt = 0; - } - - serio_continue_rx(psmouse->ps2dev.serio); -} - -static psmouse_ret_t alps_process_byte(struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - - /* - * Check if we are dealing with a bare PS/2 packet, presumably from - * a device connected to the external PS/2 port. Because bare PS/2 - * protocol does not have enough constant bits to self-synchronize - * properly we only do this if the device is fully synchronized. - * Can not distinguish V8's first byte from PS/2 packet's - */ - if (priv->proto_version != ALPS_PROTO_V8 && - !psmouse->out_of_sync_cnt && - (psmouse->packet[0] & 0xc8) == 0x08) { - - if (psmouse->pktcnt == 3) { - alps_report_bare_ps2_packet(psmouse, psmouse->packet, - true); - return PSMOUSE_FULL_PACKET; - } - return PSMOUSE_GOOD_DATA; - } - - /* Check for PS/2 packet stuffed in the middle of ALPS packet. */ - - if ((priv->flags & ALPS_PS2_INTERLEAVED) && - psmouse->pktcnt >= 4 && (psmouse->packet[3] & 0x0f) == 0x0f) { - return alps_handle_interleaved_ps2(psmouse); - } - - if (!alps_is_valid_first_byte(priv, psmouse->packet[0])) { - psmouse_dbg(psmouse, - "refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n", - psmouse->packet[0], priv->mask0, priv->byte0); - return PSMOUSE_BAD_DATA; - } - - /* Bytes 2 - pktsize should have 0 in the highest bit */ - if (priv->proto_version < ALPS_PROTO_V5 && - psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize && - (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) { - psmouse_dbg(psmouse, "refusing packet[%i] = %x\n", - psmouse->pktcnt - 1, - psmouse->packet[psmouse->pktcnt - 1]); - - if (priv->proto_version == ALPS_PROTO_V3_RUSHMORE && - psmouse->pktcnt == psmouse->pktsize) { - /* - * Some Dell boxes, such as Latitude E6440 or E7440 - * with closed lid, quite often smash last byte of - * otherwise valid packet with 0xff. Given that the - * next packet is very likely to be valid let's - * report PSMOUSE_FULL_PACKET but not process data, - * rather than reporting PSMOUSE_BAD_DATA and - * filling the logs. - */ - return PSMOUSE_FULL_PACKET; - } - - return PSMOUSE_BAD_DATA; - } - - if ((priv->proto_version == ALPS_PROTO_V7 && - !alps_is_valid_package_v7(psmouse)) || - (priv->proto_version == ALPS_PROTO_V8 && - !alps_is_valid_package_ss4_v2(psmouse))) { - psmouse_dbg(psmouse, "refusing packet[%i] = %x\n", - psmouse->pktcnt - 1, - psmouse->packet[psmouse->pktcnt - 1]); - return PSMOUSE_BAD_DATA; - } - - if (psmouse->pktcnt == psmouse->pktsize) { - priv->process_packet(psmouse); - return PSMOUSE_FULL_PACKET; - } - - return PSMOUSE_GOOD_DATA; -} - -static int alps_command_mode_send_nibble(struct psmouse *psmouse, int nibble) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - struct alps_data *priv = psmouse->private; - int command; - unsigned char *param; - unsigned char dummy[4]; - - BUG_ON(nibble > 0xf); - - command = priv->nibble_commands[nibble].command; - param = (command & 0x0f00) ? - dummy : (unsigned char *)&priv->nibble_commands[nibble].data; - - if (ps2_command(ps2dev, param, command)) - return -1; - - return 0; -} - -static int alps_command_mode_set_addr(struct psmouse *psmouse, int addr) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - struct alps_data *priv = psmouse->private; - int i, nibble; - - if (ps2_command(ps2dev, NULL, priv->addr_command)) - return -1; - - for (i = 12; i >= 0; i -= 4) { - nibble = (addr >> i) & 0xf; - if (alps_command_mode_send_nibble(psmouse, nibble)) - return -1; - } - - return 0; -} - -static int __alps_command_mode_read_reg(struct psmouse *psmouse, int addr) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[4]; - - if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) - return -1; - - /* - * The address being read is returned in the first two bytes - * of the result. Check that this address matches the expected - * address. - */ - if (addr != ((param[0] << 8) | param[1])) - return -1; - - return param[2]; -} - -static int alps_command_mode_read_reg(struct psmouse *psmouse, int addr) -{ - if (alps_command_mode_set_addr(psmouse, addr)) - return -1; - return __alps_command_mode_read_reg(psmouse, addr); -} - -static int __alps_command_mode_write_reg(struct psmouse *psmouse, u8 value) -{ - if (alps_command_mode_send_nibble(psmouse, (value >> 4) & 0xf)) - return -1; - if (alps_command_mode_send_nibble(psmouse, value & 0xf)) - return -1; - return 0; -} - -static int alps_command_mode_write_reg(struct psmouse *psmouse, int addr, - u8 value) -{ - if (alps_command_mode_set_addr(psmouse, addr)) - return -1; - return __alps_command_mode_write_reg(psmouse, value); -} - -static int alps_rpt_cmd(struct psmouse *psmouse, int init_command, - int repeated_command, unsigned char *param) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - - param[0] = 0; - if (init_command && ps2_command(ps2dev, param, init_command)) - return -EIO; - - if (ps2_command(ps2dev, NULL, repeated_command) || - ps2_command(ps2dev, NULL, repeated_command) || - ps2_command(ps2dev, NULL, repeated_command)) - return -EIO; - - param[0] = param[1] = param[2] = 0xff; - if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) - return -EIO; - - psmouse_dbg(psmouse, "%2.2X report: %3ph\n", - repeated_command, param); - return 0; -} - -static bool alps_check_valid_firmware_id(unsigned char id[]) -{ - if (id[0] == 0x73) - return true; - - if (id[0] == 0x88 && - (id[1] == 0x07 || - id[1] == 0x08 || - (id[1] & 0xf0) == 0xb0 || - (id[1] & 0xf0) == 0xc0)) { - return true; - } - - return false; -} - -static int alps_enter_command_mode(struct psmouse *psmouse) -{ - unsigned char param[4]; - - if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_RESET_WRAP, param)) { - psmouse_err(psmouse, "failed to enter command mode\n"); - return -1; - } - - if (!alps_check_valid_firmware_id(param)) { - psmouse_dbg(psmouse, - "unknown response while entering command mode\n"); - return -1; - } - return 0; -} - -static inline int alps_exit_command_mode(struct psmouse *psmouse) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) - return -1; - return 0; -} - -/* - * For DualPoint devices select the device that should respond to - * subsequent commands. It looks like glidepad is behind stickpointer, - * I'd thought it would be other way around... - */ -static int alps_passthrough_mode_v2(struct psmouse *psmouse, bool enable) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11; - - if (ps2_command(ps2dev, NULL, cmd) || - ps2_command(ps2dev, NULL, cmd) || - ps2_command(ps2dev, NULL, cmd) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE)) - return -1; - - /* we may get 3 more bytes, just ignore them */ - ps2_drain(ps2dev, 3, 100); - - return 0; -} - -static int alps_absolute_mode_v1_v2(struct psmouse *psmouse) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - - /* Try ALPS magic knock - 4 disable before enable */ - if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) - return -1; - - /* - * Switch mouse to poll (remote) mode so motion data will not - * get in our way - */ - return ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETPOLL); -} - -static int alps_monitor_mode_send_word(struct psmouse *psmouse, u16 word) -{ - int i, nibble; - - /* - * b0-b11 are valid bits, send sequence is inverse. - * e.g. when word = 0x0123, nibble send sequence is 3, 2, 1 - */ - for (i = 0; i <= 8; i += 4) { - nibble = (word >> i) & 0xf; - if (alps_command_mode_send_nibble(psmouse, nibble)) - return -1; - } - - return 0; -} - -static int alps_monitor_mode_write_reg(struct psmouse *psmouse, - u16 addr, u16 value) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - - /* 0x0A0 is the command to write the word */ - if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE) || - alps_monitor_mode_send_word(psmouse, 0x0A0) || - alps_monitor_mode_send_word(psmouse, addr) || - alps_monitor_mode_send_word(psmouse, value) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE)) - return -1; - - return 0; -} - -static int alps_monitor_mode(struct psmouse *psmouse, bool enable) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - - if (enable) { - /* EC E9 F5 F5 E7 E6 E7 E9 to enter monitor mode */ - if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_GETINFO) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_GETINFO)) - return -1; - } else { - /* EC to exit monitor mode */ - if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP)) - return -1; - } - - return 0; -} - -static int alps_absolute_mode_v6(struct psmouse *psmouse) -{ - u16 reg_val = 0x181; - int ret = -1; - - /* enter monitor mode, to write the register */ - if (alps_monitor_mode(psmouse, true)) - return -1; - - ret = alps_monitor_mode_write_reg(psmouse, 0x000, reg_val); - - if (alps_monitor_mode(psmouse, false)) - ret = -1; - - return ret; -} - -static int alps_get_status(struct psmouse *psmouse, char *param) -{ - /* Get status: 0xF5 0xF5 0xF5 0xE9 */ - if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_DISABLE, param)) - return -1; - - return 0; -} - -/* - * Turn touchpad tapping on or off. The sequences are: - * 0xE9 0xF5 0xF5 0xF3 0x0A to enable, - * 0xE9 0xF5 0xF5 0xE8 0x00 to disable. - * My guess that 0xE9 (GetInfo) is here as a sync point. - * For models that also have stickpointer (DualPoints) its tapping - * is controlled separately (0xE6 0xE6 0xE6 0xF3 0x14|0x0A) but - * we don't fiddle with it. - */ -static int alps_tap_mode(struct psmouse *psmouse, int enable) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - int cmd = enable ? PSMOUSE_CMD_SETRATE : PSMOUSE_CMD_SETRES; - unsigned char tap_arg = enable ? 0x0A : 0x00; - unsigned char param[4]; - - if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) || - ps2_command(ps2dev, &tap_arg, cmd)) - return -1; - - if (alps_get_status(psmouse, param)) - return -1; - - return 0; -} - -/* - * alps_poll() - poll the touchpad for current motion packet. - * Used in resync. - */ -static int alps_poll(struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - unsigned char buf[sizeof(psmouse->packet)]; - bool poll_failed; - - if (priv->flags & ALPS_PASS) - alps_passthrough_mode_v2(psmouse, true); - - poll_failed = ps2_command(&psmouse->ps2dev, buf, - PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0; - - if (priv->flags & ALPS_PASS) - alps_passthrough_mode_v2(psmouse, false); - - if (poll_failed || (buf[0] & priv->mask0) != priv->byte0) - return -1; - - if ((psmouse->badbyte & 0xc8) == 0x08) { -/* - * Poll the track stick ... - */ - if (ps2_command(&psmouse->ps2dev, buf, PSMOUSE_CMD_POLL | (3 << 8))) - return -1; - } - - memcpy(psmouse->packet, buf, sizeof(buf)); - return 0; -} - -static int alps_hw_init_v1_v2(struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - - if ((priv->flags & ALPS_PASS) && - alps_passthrough_mode_v2(psmouse, true)) { - return -1; - } - - if (alps_tap_mode(psmouse, true)) { - psmouse_warn(psmouse, "Failed to enable hardware tapping\n"); - return -1; - } - - if (alps_absolute_mode_v1_v2(psmouse)) { - psmouse_err(psmouse, "Failed to enable absolute mode\n"); - return -1; - } - - if ((priv->flags & ALPS_PASS) && - alps_passthrough_mode_v2(psmouse, false)) { - return -1; - } - - /* ALPS needs stream mode, otherwise it won't report any data */ - if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) { - psmouse_err(psmouse, "Failed to enable stream mode\n"); - return -1; - } - - return 0; -} - -static int alps_hw_init_v6(struct psmouse *psmouse) -{ - unsigned char param[2] = {0xC8, 0x14}; - - /* Enter passthrough mode to let trackpoint enter 6byte raw mode */ - if (alps_passthrough_mode_v2(psmouse, true)) - return -1; - - if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || - ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || - ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || - ps2_command(&psmouse->ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || - ps2_command(&psmouse->ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE)) - return -1; - - if (alps_passthrough_mode_v2(psmouse, false)) - return -1; - - if (alps_absolute_mode_v6(psmouse)) { - psmouse_err(psmouse, "Failed to enable absolute mode\n"); - return -1; - } - - return 0; -} - -/* - * Enable or disable passthrough mode to the trackstick. - */ -static int alps_passthrough_mode_v3(struct psmouse *psmouse, - int reg_base, bool enable) -{ - int reg_val, ret = -1; - - if (alps_enter_command_mode(psmouse)) - return -1; - - reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x0008); - if (reg_val == -1) - goto error; - - if (enable) - reg_val |= 0x01; - else - reg_val &= ~0x01; - - ret = __alps_command_mode_write_reg(psmouse, reg_val); - -error: - if (alps_exit_command_mode(psmouse)) - ret = -1; - return ret; -} - -/* Must be in command mode when calling this function */ -static int alps_absolute_mode_v3(struct psmouse *psmouse) -{ - int reg_val; - - reg_val = alps_command_mode_read_reg(psmouse, 0x0004); - if (reg_val == -1) - return -1; - - reg_val |= 0x06; - if (__alps_command_mode_write_reg(psmouse, reg_val)) - return -1; - - return 0; -} - -static int alps_probe_trackstick_v3_v7(struct psmouse *psmouse, int reg_base) -{ - int ret = -EIO, reg_val; - - if (alps_enter_command_mode(psmouse)) - goto error; - - reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x08); - if (reg_val == -1) - goto error; - - /* bit 7: trackstick is present */ - ret = reg_val & 0x80 ? 0 : -ENODEV; - -error: - alps_exit_command_mode(psmouse); - return ret; -} - -static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - int ret = 0; - unsigned char param[4]; - - if (alps_passthrough_mode_v3(psmouse, reg_base, true)) - return -EIO; - - /* - * E7 report for the trackstick - * - * There have been reports of failures to seem to trace back - * to the above trackstick check failing. When these occur - * this E7 report fails, so when that happens we continue - * with the assumption that there isn't a trackstick after - * all. - */ - if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_SETSCALE21, param)) { - psmouse_warn(psmouse, "Failed to initialize trackstick (E7 report failed)\n"); - ret = -ENODEV; - } else { - psmouse_dbg(psmouse, "trackstick E7 report: %3ph\n", param); - - /* - * Not sure what this does, but it is absolutely - * essential. Without it, the touchpad does not - * work at all and the trackstick just emits normal - * PS/2 packets. - */ - if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || - alps_command_mode_send_nibble(psmouse, 0x9) || - alps_command_mode_send_nibble(psmouse, 0x4)) { - psmouse_err(psmouse, - "Error sending magic E6 sequence\n"); - ret = -EIO; - goto error; - } - - /* - * This ensures the trackstick packets are in the format - * supported by this driver. If bit 1 isn't set the packet - * format is different. - */ - if (alps_enter_command_mode(psmouse) || - alps_command_mode_write_reg(psmouse, - reg_base + 0x08, 0x82) || - alps_exit_command_mode(psmouse)) - ret = -EIO; - } - -error: - if (alps_passthrough_mode_v3(psmouse, reg_base, false)) - ret = -EIO; - - return ret; -} - -static int alps_hw_init_v3(struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - struct ps2dev *ps2dev = &psmouse->ps2dev; - int reg_val; - unsigned char param[4]; - - if ((priv->flags & ALPS_DUALPOINT) && - alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO) - goto error; - - if (alps_enter_command_mode(psmouse) || - alps_absolute_mode_v3(psmouse)) { - psmouse_err(psmouse, "Failed to enter absolute mode\n"); - goto error; - } - - reg_val = alps_command_mode_read_reg(psmouse, 0x0006); - if (reg_val == -1) - goto error; - if (__alps_command_mode_write_reg(psmouse, reg_val | 0x01)) - goto error; - - reg_val = alps_command_mode_read_reg(psmouse, 0x0007); - if (reg_val == -1) - goto error; - if (__alps_command_mode_write_reg(psmouse, reg_val | 0x01)) - goto error; - - if (alps_command_mode_read_reg(psmouse, 0x0144) == -1) - goto error; - if (__alps_command_mode_write_reg(psmouse, 0x04)) - goto error; - - if (alps_command_mode_read_reg(psmouse, 0x0159) == -1) - goto error; - if (__alps_command_mode_write_reg(psmouse, 0x03)) - goto error; - - if (alps_command_mode_read_reg(psmouse, 0x0163) == -1) - goto error; - if (alps_command_mode_write_reg(psmouse, 0x0163, 0x03)) - goto error; - - if (alps_command_mode_read_reg(psmouse, 0x0162) == -1) - goto error; - if (alps_command_mode_write_reg(psmouse, 0x0162, 0x04)) - goto error; - - alps_exit_command_mode(psmouse); - - /* Set rate and enable data reporting */ - param[0] = 0x64; - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { - psmouse_err(psmouse, "Failed to enable data reporting\n"); - return -1; - } - - return 0; - -error: - /* - * Leaving the touchpad in command mode will essentially render - * it unusable until the machine reboots, so exit it here just - * to be safe - */ - alps_exit_command_mode(psmouse); - return -1; -} - -static int alps_get_v3_v7_resolution(struct psmouse *psmouse, int reg_pitch) -{ - int reg, x_pitch, y_pitch, x_electrode, y_electrode, x_phys, y_phys; - struct alps_data *priv = psmouse->private; - - reg = alps_command_mode_read_reg(psmouse, reg_pitch); - if (reg < 0) - return reg; - - x_pitch = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */ - x_pitch = 50 + 2 * x_pitch; /* In 0.1 mm units */ - - y_pitch = (char)reg >> 4; /* sign extend upper 4 bits */ - y_pitch = 36 + 2 * y_pitch; /* In 0.1 mm units */ - - reg = alps_command_mode_read_reg(psmouse, reg_pitch + 1); - if (reg < 0) - return reg; - - x_electrode = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */ - x_electrode = 17 + x_electrode; - - y_electrode = (char)reg >> 4; /* sign extend upper 4 bits */ - y_electrode = 13 + y_electrode; - - x_phys = x_pitch * (x_electrode - 1); /* In 0.1 mm units */ - y_phys = y_pitch * (y_electrode - 1); /* In 0.1 mm units */ - - priv->x_res = priv->x_max * 10 / x_phys; /* units / mm */ - priv->y_res = priv->y_max * 10 / y_phys; /* units / mm */ - - psmouse_dbg(psmouse, - "pitch %dx%d num-electrodes %dx%d physical size %dx%d mm res %dx%d\n", - x_pitch, y_pitch, x_electrode, y_electrode, - x_phys / 10, y_phys / 10, priv->x_res, priv->y_res); - - return 0; -} - -static int alps_hw_init_rushmore_v3(struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - struct ps2dev *ps2dev = &psmouse->ps2dev; - int reg_val, ret = -1; - - if (priv->flags & ALPS_DUALPOINT) { - reg_val = alps_setup_trackstick_v3(psmouse, - ALPS_REG_BASE_RUSHMORE); - if (reg_val == -EIO) - goto error; - } - - if (alps_enter_command_mode(psmouse) || - alps_command_mode_read_reg(psmouse, 0xc2d9) == -1 || - alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00)) - goto error; - - if (alps_get_v3_v7_resolution(psmouse, 0xc2da)) - goto error; - - reg_val = alps_command_mode_read_reg(psmouse, 0xc2c6); - if (reg_val == -1) - goto error; - if (__alps_command_mode_write_reg(psmouse, reg_val & 0xfd)) - goto error; - - if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64)) - goto error; - - /* enter absolute mode */ - reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4); - if (reg_val == -1) - goto error; - if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02)) - goto error; - - alps_exit_command_mode(psmouse); - return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); - -error: - alps_exit_command_mode(psmouse); - return ret; -} - -/* Must be in command mode when calling this function */ -static int alps_absolute_mode_v4(struct psmouse *psmouse) -{ - int reg_val; - - reg_val = alps_command_mode_read_reg(psmouse, 0x0004); - if (reg_val == -1) - return -1; - - reg_val |= 0x02; - if (__alps_command_mode_write_reg(psmouse, reg_val)) - return -1; - - return 0; -} - -static int alps_hw_init_v4(struct psmouse *psmouse) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[4]; - - if (alps_enter_command_mode(psmouse)) - goto error; - - if (alps_absolute_mode_v4(psmouse)) { - psmouse_err(psmouse, "Failed to enter absolute mode\n"); - goto error; - } - - if (alps_command_mode_write_reg(psmouse, 0x0007, 0x8c)) - goto error; - - if (alps_command_mode_write_reg(psmouse, 0x0149, 0x03)) - goto error; - - if (alps_command_mode_write_reg(psmouse, 0x0160, 0x03)) - goto error; - - if (alps_command_mode_write_reg(psmouse, 0x017f, 0x15)) - goto error; - - if (alps_command_mode_write_reg(psmouse, 0x0151, 0x01)) - goto error; - - if (alps_command_mode_write_reg(psmouse, 0x0168, 0x03)) - goto error; - - if (alps_command_mode_write_reg(psmouse, 0x014a, 0x03)) - goto error; - - if (alps_command_mode_write_reg(psmouse, 0x0161, 0x03)) - goto error; - - alps_exit_command_mode(psmouse); - - /* - * This sequence changes the output from a 9-byte to an - * 8-byte format. All the same data seems to be present, - * just in a more compact format. - */ - param[0] = 0xc8; - param[1] = 0x64; - param[2] = 0x50; - if (ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || - ps2_command(ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE) || - ps2_command(ps2dev, ¶m[2], PSMOUSE_CMD_SETRATE) || - ps2_command(ps2dev, param, PSMOUSE_CMD_GETID)) - return -1; - - /* Set rate and enable data reporting */ - param[0] = 0x64; - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { - psmouse_err(psmouse, "Failed to enable data reporting\n"); - return -1; - } - - return 0; - -error: - /* - * Leaving the touchpad in command mode will essentially render - * it unusable until the machine reboots, so exit it here just - * to be safe - */ - alps_exit_command_mode(psmouse); - return -1; -} - -static int alps_get_otp_values_ss4_v2(struct psmouse *psmouse, - unsigned char index, unsigned char otp[]) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - - switch (index) { - case 0: - if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) || - ps2_command(ps2dev, otp, PSMOUSE_CMD_GETINFO)) - return -1; - - break; - - case 1: - if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || - ps2_command(ps2dev, otp, PSMOUSE_CMD_GETINFO)) - return -1; - - break; - } - - return 0; -} - -static int alps_update_device_area_ss4_v2(unsigned char otp[][4], - struct alps_data *priv) -{ - int num_x_electrode; - int num_y_electrode; - int x_pitch, y_pitch, x_phys, y_phys; - - num_x_electrode = SS4_NUMSENSOR_XOFFSET + (otp[1][0] & 0x0F); - num_y_electrode = SS4_NUMSENSOR_YOFFSET + ((otp[1][0] >> 4) & 0x0F); - - priv->x_max = (num_x_electrode - 1) * SS4_COUNT_PER_ELECTRODE; - priv->y_max = (num_y_electrode - 1) * SS4_COUNT_PER_ELECTRODE; - - x_pitch = ((otp[1][2] >> 2) & 0x07) + SS4_MIN_PITCH_MM; - y_pitch = ((otp[1][2] >> 5) & 0x07) + SS4_MIN_PITCH_MM; - - x_phys = x_pitch * (num_x_electrode - 1); /* In 0.1 mm units */ - y_phys = y_pitch * (num_y_electrode - 1); /* In 0.1 mm units */ - - priv->x_res = priv->x_max * 10 / x_phys; /* units / mm */ - priv->y_res = priv->y_max * 10 / y_phys; /* units / mm */ - - return 0; -} - -static int alps_update_btn_info_ss4_v2(unsigned char otp[][4], - struct alps_data *priv) -{ - unsigned char is_btnless; - - is_btnless = (otp[1][1] >> 3) & 0x01; - - if (is_btnless) - priv->flags |= ALPS_BUTTONPAD; - - return 0; -} - -static int alps_set_defaults_ss4_v2(struct psmouse *psmouse, - struct alps_data *priv) -{ - unsigned char otp[2][4]; - - memset(otp, 0, sizeof(otp)); - - if (alps_get_otp_values_ss4_v2(psmouse, 0, &otp[0][0]) || - alps_get_otp_values_ss4_v2(psmouse, 1, &otp[1][0])) - return -1; - - alps_update_device_area_ss4_v2(otp, priv); - - alps_update_btn_info_ss4_v2(otp, priv); - - return 0; -} - -static int alps_dolphin_get_device_area(struct psmouse *psmouse, - struct alps_data *priv) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[4] = {0}; - int num_x_electrode, num_y_electrode; - - if (alps_enter_command_mode(psmouse)) - return -1; - - param[0] = 0x0a; - if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) || - ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || - ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE)) - return -1; - - if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) - return -1; - - /* - * Dolphin's sensor line number is not fixed. It can be calculated - * by adding the device's register value with DOLPHIN_PROFILE_X/YOFFSET. - * Further more, we can get device's x_max and y_max by multiplying - * sensor line number with DOLPHIN_COUNT_PER_ELECTRODE. - * - * e.g. When we get register's sensor_x = 11 & sensor_y = 8, - * real sensor line number X = 11 + 8 = 19, and - * real sensor line number Y = 8 + 1 = 9. - * So, x_max = (19 - 1) * 64 = 1152, and - * y_max = (9 - 1) * 64 = 512. - */ - num_x_electrode = DOLPHIN_PROFILE_XOFFSET + (param[2] & 0x0F); - num_y_electrode = DOLPHIN_PROFILE_YOFFSET + ((param[2] >> 4) & 0x0F); - priv->x_bits = num_x_electrode; - priv->y_bits = num_y_electrode; - priv->x_max = (num_x_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE; - priv->y_max = (num_y_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE; - - if (alps_exit_command_mode(psmouse)) - return -1; - - return 0; -} - -static int alps_hw_init_dolphin_v1(struct psmouse *psmouse) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[2]; - - /* This is dolphin "v1" as empirically defined by florin9doi */ - param[0] = 0x64; - param[1] = 0x28; - - if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) || - ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || - ps2_command(ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE)) - return -1; - - return 0; -} - -static int alps_hw_init_v7(struct psmouse *psmouse) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - int reg_val, ret = -1; - - if (alps_enter_command_mode(psmouse) || - alps_command_mode_read_reg(psmouse, 0xc2d9) == -1) - goto error; - - if (alps_get_v3_v7_resolution(psmouse, 0xc397)) - goto error; - - if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64)) - goto error; - - reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4); - if (reg_val == -1) - goto error; - if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02)) - goto error; - - alps_exit_command_mode(psmouse); - return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); - -error: - alps_exit_command_mode(psmouse); - return ret; -} - -static int alps_hw_init_ss4_v2(struct psmouse *psmouse) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - char param[2] = {0x64, 0x28}; - int ret = -1; - - /* enter absolute mode */ - if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) || - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) || - ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) || - ps2_command(ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE)) { - goto error; - } - - /* T.B.D. Decread noise packet number, delete in the future */ - if (alps_exit_command_mode(psmouse) || - alps_enter_command_mode(psmouse) || - alps_command_mode_write_reg(psmouse, 0x001D, 0x20)) { - goto error; - } - alps_exit_command_mode(psmouse); - - return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE); - -error: - alps_exit_command_mode(psmouse); - return ret; -} - -static int alps_set_protocol(struct psmouse *psmouse, - struct alps_data *priv, - const struct alps_protocol_info *protocol) -{ - psmouse->private = priv; - - setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse); - - priv->proto_version = protocol->version; - priv->byte0 = protocol->byte0; - priv->mask0 = protocol->mask0; - priv->flags = protocol->flags; - - priv->x_max = 2000; - priv->y_max = 1400; - priv->x_bits = 15; - priv->y_bits = 11; - - switch (priv->proto_version) { - case ALPS_PROTO_V1: - case ALPS_PROTO_V2: - priv->hw_init = alps_hw_init_v1_v2; - priv->process_packet = alps_process_packet_v1_v2; - priv->set_abs_params = alps_set_abs_params_st; - priv->x_max = 1023; - priv->y_max = 767; - if (dmi_check_system(alps_dmi_has_separate_stick_buttons)) - priv->flags |= ALPS_STICK_BITS; - break; - - case ALPS_PROTO_V3: - priv->hw_init = alps_hw_init_v3; - priv->process_packet = alps_process_packet_v3; - priv->set_abs_params = alps_set_abs_params_semi_mt; - priv->decode_fields = alps_decode_pinnacle; - priv->nibble_commands = alps_v3_nibble_commands; - priv->addr_command = PSMOUSE_CMD_RESET_WRAP; - - if (alps_probe_trackstick_v3_v7(psmouse, - ALPS_REG_BASE_PINNACLE) < 0) - priv->flags &= ~ALPS_DUALPOINT; - - break; - - case ALPS_PROTO_V3_RUSHMORE: - priv->hw_init = alps_hw_init_rushmore_v3; - priv->process_packet = alps_process_packet_v3; - priv->set_abs_params = alps_set_abs_params_semi_mt; - priv->decode_fields = alps_decode_rushmore; - priv->nibble_commands = alps_v3_nibble_commands; - priv->addr_command = PSMOUSE_CMD_RESET_WRAP; - priv->x_bits = 16; - priv->y_bits = 12; - - if (alps_probe_trackstick_v3_v7(psmouse, - ALPS_REG_BASE_RUSHMORE) < 0) - priv->flags &= ~ALPS_DUALPOINT; - - break; - - case ALPS_PROTO_V4: - priv->hw_init = alps_hw_init_v4; - priv->process_packet = alps_process_packet_v4; - priv->set_abs_params = alps_set_abs_params_semi_mt; - priv->nibble_commands = alps_v4_nibble_commands; - priv->addr_command = PSMOUSE_CMD_DISABLE; - break; - - case ALPS_PROTO_V5: - priv->hw_init = alps_hw_init_dolphin_v1; - priv->process_packet = alps_process_touchpad_packet_v3_v5; - priv->decode_fields = alps_decode_dolphin; - priv->set_abs_params = alps_set_abs_params_semi_mt; - priv->nibble_commands = alps_v3_nibble_commands; - priv->addr_command = PSMOUSE_CMD_RESET_WRAP; - priv->x_bits = 23; - priv->y_bits = 12; - - if (alps_dolphin_get_device_area(psmouse, priv)) - return -EIO; - - break; - - case ALPS_PROTO_V6: - priv->hw_init = alps_hw_init_v6; - priv->process_packet = alps_process_packet_v6; - priv->set_abs_params = alps_set_abs_params_st; - priv->nibble_commands = alps_v6_nibble_commands; - priv->x_max = 2047; - priv->y_max = 1535; - break; - - case ALPS_PROTO_V7: - priv->hw_init = alps_hw_init_v7; - priv->process_packet = alps_process_packet_v7; - priv->decode_fields = alps_decode_packet_v7; - priv->set_abs_params = alps_set_abs_params_v7; - priv->nibble_commands = alps_v3_nibble_commands; - priv->addr_command = PSMOUSE_CMD_RESET_WRAP; - priv->x_max = 0xfff; - priv->y_max = 0x7ff; - - if (priv->fw_ver[1] != 0xba) - priv->flags |= ALPS_BUTTONPAD; - - if (alps_probe_trackstick_v3_v7(psmouse, ALPS_REG_BASE_V7) < 0) - priv->flags &= ~ALPS_DUALPOINT; - - break; - - case ALPS_PROTO_V8: - priv->hw_init = alps_hw_init_ss4_v2; - priv->process_packet = alps_process_packet_ss4_v2; - priv->decode_fields = alps_decode_ss4_v2; - priv->set_abs_params = alps_set_abs_params_ss4_v2; - priv->nibble_commands = alps_v3_nibble_commands; - priv->addr_command = PSMOUSE_CMD_RESET_WRAP; - - if (alps_set_defaults_ss4_v2(psmouse, priv)) - return -EIO; - - if (priv->fw_ver[1] == 0x1) - priv->flags |= ALPS_DUALPOINT | - ALPS_DUALPOINT_WITH_PRESSURE; - - break; - } - - return 0; -} - -static const struct alps_protocol_info *alps_match_table(unsigned char *e7, - unsigned char *ec) -{ - const struct alps_model_info *model; - int i; - - for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) { - model = &alps_model_data[i]; - - if (!memcmp(e7, model->signature, sizeof(model->signature)) && - (!model->command_mode_resp || - model->command_mode_resp == ec[2])) { - - return &model->protocol_info; - } - } - - return NULL; -} - -static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) -{ - const struct alps_protocol_info *protocol; - unsigned char e6[4], e7[4], ec[4]; - int error; - - /* - * First try "E6 report". - * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed. - * The bits 0-2 of the first byte will be 1s if some buttons are - * pressed. - */ - if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES, - PSMOUSE_CMD_SETSCALE11, e6)) - return -EIO; - - if ((e6[0] & 0xf8) != 0 || e6[1] != 0 || (e6[2] != 10 && e6[2] != 100)) - return -EINVAL; - - /* - * Now get the "E7" and "EC" reports. These will uniquely identify - * most ALPS touchpads. - */ - if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES, - PSMOUSE_CMD_SETSCALE21, e7) || - alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES, - PSMOUSE_CMD_RESET_WRAP, ec) || - alps_exit_command_mode(psmouse)) - return -EIO; - - protocol = alps_match_table(e7, ec); - if (!protocol) { - if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 && - ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) { - protocol = &alps_v5_protocol_data; - } else if (ec[0] == 0x88 && - ((ec[1] & 0xf0) == 0xb0 || (ec[1] & 0xf0) == 0xc0)) { - protocol = &alps_v7_protocol_data; - } else if (ec[0] == 0x88 && ec[1] == 0x08) { - protocol = &alps_v3_rushmore_data; - } else if (ec[0] == 0x88 && ec[1] == 0x07 && - ec[2] >= 0x90 && ec[2] <= 0x9d) { - protocol = &alps_v3_protocol_data; - } else if (e7[0] == 0x73 && e7[1] == 0x03 && - e7[2] == 0x14 && ec[1] == 0x02) { - protocol = &alps_v8_protocol_data; - } else if (e7[0] == 0x73 && e7[1] == 0x03 && - e7[2] == 0x28 && ec[1] == 0x01) { - protocol = &alps_v8_protocol_data; - } else { - psmouse_dbg(psmouse, - "Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec); - return -EINVAL; - } - } - - if (priv) { - /* Save the Firmware version */ - memcpy(priv->fw_ver, ec, 3); - error = alps_set_protocol(psmouse, priv, protocol); - if (error) - return error; - } - - return 0; -} - -static int alps_reconnect(struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - - psmouse_reset(psmouse); - - if (alps_identify(psmouse, priv) < 0) - return -1; - - return priv->hw_init(psmouse); -} - -static void alps_disconnect(struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - - psmouse_reset(psmouse); - del_timer_sync(&priv->timer); - if (priv->dev2) - input_unregister_device(priv->dev2); - if (!IS_ERR_OR_NULL(priv->dev3)) - input_unregister_device(priv->dev3); - kfree(priv); -} - -static void alps_set_abs_params_st(struct alps_data *priv, - struct input_dev *dev1) -{ - input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0); - input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0); - input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); -} - -static void alps_set_abs_params_mt_common(struct alps_data *priv, - struct input_dev *dev1) -{ - input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0); - input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0); - - input_abs_set_res(dev1, ABS_MT_POSITION_X, priv->x_res); - input_abs_set_res(dev1, ABS_MT_POSITION_Y, priv->y_res); - - set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit); - set_bit(BTN_TOOL_QUADTAP, dev1->keybit); -} - -static void alps_set_abs_params_semi_mt(struct alps_data *priv, - struct input_dev *dev1) -{ - alps_set_abs_params_mt_common(priv, dev1); - input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); - - input_mt_init_slots(dev1, MAX_TOUCHES, - INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED | - INPUT_MT_SEMI_MT); -} - -static void alps_set_abs_params_v7(struct alps_data *priv, - struct input_dev *dev1) -{ - alps_set_abs_params_mt_common(priv, dev1); - set_bit(BTN_TOOL_QUINTTAP, dev1->keybit); - - input_mt_init_slots(dev1, MAX_TOUCHES, - INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED | - INPUT_MT_TRACK); - - set_bit(BTN_TOOL_QUINTTAP, dev1->keybit); -} - -static void alps_set_abs_params_ss4_v2(struct alps_data *priv, - struct input_dev *dev1) -{ - alps_set_abs_params_mt_common(priv, dev1); - input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0); - set_bit(BTN_TOOL_QUINTTAP, dev1->keybit); - - input_mt_init_slots(dev1, MAX_TOUCHES, - INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED | - INPUT_MT_TRACK); -} - -int alps_init(struct psmouse *psmouse) -{ - struct alps_data *priv = psmouse->private; - struct input_dev *dev1 = psmouse->dev; - int error; - - error = priv->hw_init(psmouse); - if (error) - goto init_fail; - - /* - * Undo part of setup done for us by psmouse core since touchpad - * is not a relative device. - */ - __clear_bit(EV_REL, dev1->evbit); - __clear_bit(REL_X, dev1->relbit); - __clear_bit(REL_Y, dev1->relbit); - - /* - * Now set up our capabilities. - */ - dev1->evbit[BIT_WORD(EV_KEY)] |= BIT_MASK(EV_KEY); - dev1->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH); - dev1->keybit[BIT_WORD(BTN_TOOL_FINGER)] |= BIT_MASK(BTN_TOOL_FINGER); - dev1->keybit[BIT_WORD(BTN_LEFT)] |= - BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT); - - dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS); - - priv->set_abs_params(priv, dev1); - - if (priv->flags & ALPS_WHEEL) { - dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL); - dev1->relbit[BIT_WORD(REL_WHEEL)] |= BIT_MASK(REL_WHEEL); - } - - if (priv->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) { - dev1->keybit[BIT_WORD(BTN_FORWARD)] |= BIT_MASK(BTN_FORWARD); - dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK); - } - - if (priv->flags & ALPS_FOUR_BUTTONS) { - dev1->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0); - dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1); - dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2); - dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3); - } else if (priv->flags & ALPS_BUTTONPAD) { - set_bit(INPUT_PROP_BUTTONPAD, dev1->propbit); - clear_bit(BTN_RIGHT, dev1->keybit); - } else { - dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE); - } - - if (priv->flags & ALPS_DUALPOINT) { - struct input_dev *dev2; - - dev2 = input_allocate_device(); - if (!dev2) { - psmouse_err(psmouse, - "failed to allocate trackstick device\n"); - error = -ENOMEM; - goto init_fail; - } - - snprintf(priv->phys2, sizeof(priv->phys2), "%s/input1", - psmouse->ps2dev.serio->phys); - dev2->phys = priv->phys2; - - /* - * format of input device name is: "protocol vendor name" - * see function psmouse_switch_protocol() in psmouse-base.c - */ - dev2->name = "AlpsPS/2 ALPS DualPoint Stick"; - - dev2->id.bustype = BUS_I8042; - dev2->id.vendor = 0x0002; - dev2->id.product = PSMOUSE_ALPS; - dev2->id.version = priv->proto_version; - dev2->dev.parent = &psmouse->ps2dev.serio->dev; - - input_set_capability(dev2, EV_REL, REL_X); - input_set_capability(dev2, EV_REL, REL_Y); - if (priv->flags & ALPS_DUALPOINT_WITH_PRESSURE) { - input_set_capability(dev2, EV_ABS, ABS_PRESSURE); - input_set_abs_params(dev2, ABS_PRESSURE, 0, 127, 0, 0); - } - input_set_capability(dev2, EV_KEY, BTN_LEFT); - input_set_capability(dev2, EV_KEY, BTN_RIGHT); - input_set_capability(dev2, EV_KEY, BTN_MIDDLE); - - __set_bit(INPUT_PROP_POINTER, dev2->propbit); - __set_bit(INPUT_PROP_POINTING_STICK, dev2->propbit); - - error = input_register_device(dev2); - if (error) { - psmouse_err(psmouse, - "failed to register trackstick device: %d\n", - error); - input_free_device(dev2); - goto init_fail; - } - - priv->dev2 = dev2; - } - - priv->psmouse = psmouse; - - INIT_DELAYED_WORK(&priv->dev3_register_work, - alps_register_bare_ps2_mouse); - - psmouse->protocol_handler = alps_process_byte; - psmouse->poll = alps_poll; - psmouse->disconnect = alps_disconnect; - psmouse->reconnect = alps_reconnect; - psmouse->pktsize = priv->proto_version == ALPS_PROTO_V4 ? 8 : 6; - - /* We are having trouble resyncing ALPS touchpads so disable it for now */ - psmouse->resync_time = 0; - - /* Allow 2 invalid packets without resetting device */ - psmouse->resetafter = psmouse->pktsize * 2; - - return 0; - -init_fail: - psmouse_reset(psmouse); - /* - * Even though we did not allocate psmouse->private we do free - * it here. - */ - kfree(psmouse->private); - psmouse->private = NULL; - return error; -} - -int alps_detect(struct psmouse *psmouse, bool set_properties) -{ - struct alps_data *priv; - int error; - - error = alps_identify(psmouse, NULL); - if (error) - return error; - - /* - * Reset the device to make sure it is fully operational: - * on some laptops, like certain Dell Latitudes, we may - * fail to properly detect presence of trackstick if device - * has not been reset. - */ - psmouse_reset(psmouse); - - priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - error = alps_identify(psmouse, priv); - if (error) { - kfree(priv); - return error; - } - - if (set_properties) { - psmouse->vendor = "ALPS"; - psmouse->name = priv->flags & ALPS_DUALPOINT ? - "DualPoint TouchPad" : "GlidePoint"; - psmouse->model = priv->proto_version; - } else { - /* - * Destroy alps_data structure we allocated earlier since - * this was just a "trial run". Otherwise we'll keep it - * to be used by alps_init() which has to be called if - * we succeed and set_properties is true. - */ - kfree(priv); - psmouse->private = NULL; - } - - return 0; -} - diff --git a/src/linux/drivers/input/mouse/alps.h b/src/linux/drivers/input/mouse/alps.h deleted file mode 100644 index b9417e2..0000000 --- a/src/linux/drivers/input/mouse/alps.h +++ /dev/null @@ -1,306 +0,0 @@ -/* - * ALPS touchpad PS/2 mouse driver - * - * Copyright (c) 2003 Peter Osterlund - * Copyright (c) 2005 Vojtech Pavlik - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#ifndef _ALPS_H -#define _ALPS_H - -#include - -#define ALPS_PROTO_V1 0x100 -#define ALPS_PROTO_V2 0x200 -#define ALPS_PROTO_V3 0x300 -#define ALPS_PROTO_V3_RUSHMORE 0x310 -#define ALPS_PROTO_V4 0x400 -#define ALPS_PROTO_V5 0x500 -#define ALPS_PROTO_V6 0x600 -#define ALPS_PROTO_V7 0x700 /* t3btl t4s */ -#define ALPS_PROTO_V8 0x800 /* SS4btl SS4s */ - -#define MAX_TOUCHES 4 - -#define DOLPHIN_COUNT_PER_ELECTRODE 64 -#define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */ -#define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */ - -/* - * enum SS4_PACKET_ID - defines the packet type for V8 - * SS4_PACKET_ID_IDLE: There's no finger and no button activity. - * SS4_PACKET_ID_ONE: There's one finger on touchpad - * or there's button activities. - * SS4_PACKET_ID_TWO: There's two or more fingers on touchpad - * SS4_PACKET_ID_MULTI: There's three or more fingers on touchpad - * SS4_PACKET_ID_STICK: A stick pointer packet -*/ -enum SS4_PACKET_ID { - SS4_PACKET_ID_IDLE = 0, - SS4_PACKET_ID_ONE, - SS4_PACKET_ID_TWO, - SS4_PACKET_ID_MULTI, - SS4_PACKET_ID_STICK, -}; - -#define SS4_COUNT_PER_ELECTRODE 256 -#define SS4_NUMSENSOR_XOFFSET 7 -#define SS4_NUMSENSOR_YOFFSET 7 -#define SS4_MIN_PITCH_MM 50 - -#define SS4_MASK_NORMAL_BUTTONS 0x07 - -#define SS4_1F_X_V2(_b) ((_b[0] & 0x0007) | \ - ((_b[1] << 3) & 0x0078) | \ - ((_b[1] << 2) & 0x0380) | \ - ((_b[2] << 5) & 0x1C00) \ - ) - -#define SS4_1F_Y_V2(_b) (((_b[2]) & 0x000F) | \ - ((_b[3] >> 2) & 0x0030) | \ - ((_b[4] << 6) & 0x03C0) | \ - ((_b[4] << 5) & 0x0C00) \ - ) - -#define SS4_1F_Z_V2(_b) (((_b[5]) & 0x0F) | \ - ((_b[5] >> 1) & 0x70) | \ - ((_b[4]) & 0x80) \ - ) - -#define SS4_1F_LFB_V2(_b) (((_b[2] >> 4) & 0x01) == 0x01) - -#define SS4_MF_LF_V2(_b, _i) ((_b[1 + (_i) * 3] & 0x0004) == 0x0004) - -#define SS4_BTN_V2(_b) ((_b[0] >> 5) & SS4_MASK_NORMAL_BUTTONS) - -#define SS4_STD_MF_X_V2(_b, _i) (((_b[0 + (_i) * 3] << 5) & 0x00E0) | \ - ((_b[1 + _i * 3] << 5) & 0x1F00) \ - ) - -#define SS4_STD_MF_Y_V2(_b, _i) (((_b[1 + (_i) * 3] << 3) & 0x0010) | \ - ((_b[2 + (_i) * 3] << 5) & 0x01E0) | \ - ((_b[2 + (_i) * 3] << 4) & 0x0E00) \ - ) - -#define SS4_BTL_MF_X_V2(_b, _i) (SS4_STD_MF_X_V2(_b, _i) | \ - ((_b[0 + (_i) * 3] >> 3) & 0x0010) \ - ) - -#define SS4_BTL_MF_Y_V2(_b, _i) (SS4_STD_MF_Y_V2(_b, _i) | \ - ((_b[0 + (_i) * 3] >> 3) & 0x0008) \ - ) - -#define SS4_MF_Z_V2(_b, _i) (((_b[1 + (_i) * 3]) & 0x0001) | \ - ((_b[1 + (_i) * 3] >> 1) & 0x0002) \ - ) - -#define SS4_IS_MF_CONTINUE(_b) ((_b[2] & 0x10) == 0x10) -#define SS4_IS_5F_DETECTED(_b) ((_b[2] & 0x10) == 0x10) - - -#define SS4_MFPACKET_NO_AX 8160 /* X-Coordinate value */ -#define SS4_MFPACKET_NO_AY 4080 /* Y-Coordinate value */ -#define SS4_MFPACKET_NO_AX_BL 8176 /* Buttonless X-Coordinate value */ -#define SS4_MFPACKET_NO_AY_BL 4088 /* Buttonless Y-Coordinate value */ - -/* - * enum V7_PACKET_ID - defines the packet type for V7 - * V7_PACKET_ID_IDLE: There's no finger and no button activity. - * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad - * or there's button activities. - * V7_PACKET_ID_MULTI: There are at least three non-resting fingers. - * V7_PACKET_ID_NEW: The finger position in slot is not continues from - * previous packet. -*/ -enum V7_PACKET_ID { - V7_PACKET_ID_IDLE, - V7_PACKET_ID_TWO, - V7_PACKET_ID_MULTI, - V7_PACKET_ID_NEW, - V7_PACKET_ID_UNKNOWN, -}; - -/** - * struct alps_protocol_info - information about protocol used by a device - * @version: Indicates V1/V2/V3/... - * @byte0: Helps figure out whether a position report packet matches the - * known format for this model. The first byte of the report, ANDed with - * mask0, should match byte0. - * @mask0: The mask used to check the first byte of the report. - * @flags: Additional device capabilities (passthrough port, trackstick, etc.). - */ -struct alps_protocol_info { - u16 version; - u8 byte0, mask0; - unsigned int flags; -}; - -/** - * struct alps_model_info - touchpad ID table - * @signature: E7 response string to match. - * @command_mode_resp: For V3/V4 touchpads, the final byte of the EC response - * (aka command mode response) identifies the firmware minor version. This - * can be used to distinguish different hardware models which are not - * uniquely identifiable through their E7 responses. - * @protocol_info: information about protcol used by the device. - * - * Many (but not all) ALPS touchpads can be identified by looking at the - * values returned in the "E7 report" and/or the "EC report." This table - * lists a number of such touchpads. - */ -struct alps_model_info { - u8 signature[3]; - u8 command_mode_resp; - struct alps_protocol_info protocol_info; -}; - -/** - * struct alps_nibble_commands - encodings for register accesses - * @command: PS/2 command used for the nibble - * @data: Data supplied as an argument to the PS/2 command, if applicable - * - * The ALPS protocol uses magic sequences to transmit binary data to the - * touchpad, as it is generally not OK to send arbitrary bytes out the - * PS/2 port. Each of the sequences in this table sends one nibble of the - * register address or (write) data. Different versions of the ALPS protocol - * use slightly different encodings. - */ -struct alps_nibble_commands { - int command; - unsigned char data; -}; - -struct alps_bitmap_point { - int start_bit; - int num_bits; -}; - -/** - * struct alps_fields - decoded version of the report packet - * @x_map: Bitmap of active X positions for MT. - * @y_map: Bitmap of active Y positions for MT. - * @fingers: Number of fingers for MT. - * @pressure: Pressure. - * @st: position for ST. - * @mt: position for MT. - * @first_mp: Packet is the first of a multi-packet report. - * @is_mp: Packet is part of a multi-packet report. - * @left: Left touchpad button is active. - * @right: Right touchpad button is active. - * @middle: Middle touchpad button is active. - * @ts_left: Left trackstick button is active. - * @ts_right: Right trackstick button is active. - * @ts_middle: Middle trackstick button is active. - */ -struct alps_fields { - unsigned int x_map; - unsigned int y_map; - unsigned int fingers; - - int pressure; - struct input_mt_pos st; - struct input_mt_pos mt[MAX_TOUCHES]; - - unsigned int first_mp:1; - unsigned int is_mp:1; - - unsigned int left:1; - unsigned int right:1; - unsigned int middle:1; - - unsigned int ts_left:1; - unsigned int ts_right:1; - unsigned int ts_middle:1; -}; - -/** - * struct alps_data - private data structure for the ALPS driver - * @psmouse: Pointer to parent psmouse device - * @dev2: Trackstick device (can be NULL). - * @dev3: Generic PS/2 mouse (can be NULL, delayed registering). - * @phys2: Physical path for the trackstick device. - * @phys3: Physical path for the generic PS/2 mouse. - * @dev3_register_work: Delayed work for registering PS/2 mouse. - * @nibble_commands: Command mapping used for touchpad register accesses. - * @addr_command: Command used to tell the touchpad that a register address - * follows. - * @proto_version: Indicates V1/V2/V3/... - * @byte0: Helps figure out whether a position report packet matches the - * known format for this model. The first byte of the report, ANDed with - * mask0, should match byte0. - * @mask0: The mask used to check the first byte of the report. - * @fw_ver: cached copy of firmware version (EC report) - * @flags: Additional device capabilities (passthrough port, trackstick, etc.). - * @x_max: Largest possible X position value. - * @y_max: Largest possible Y position value. - * @x_bits: Number of X bits in the MT bitmap. - * @y_bits: Number of Y bits in the MT bitmap. - * @hw_init: Protocol-specific hardware init function. - * @process_packet: Protocol-specific function to process a report packet. - * @decode_fields: Protocol-specific function to read packet bitfields. - * @set_abs_params: Protocol-specific function to configure the input_dev. - * @prev_fin: Finger bit from previous packet. - * @multi_packet: Multi-packet data in progress. - * @multi_data: Saved multi-packet data. - * @f: Decoded packet data fields. - * @quirks: Bitmap of ALPS_QUIRK_*. - * @timer: Timer for flushing out the final report packet in the stream. - */ -struct alps_data { - struct psmouse *psmouse; - struct input_dev *dev2; - struct input_dev *dev3; - char phys2[32]; - char phys3[32]; - struct delayed_work dev3_register_work; - - /* these are autodetected when the device is identified */ - const struct alps_nibble_commands *nibble_commands; - int addr_command; - u16 proto_version; - u8 byte0, mask0; - u8 fw_ver[3]; - int flags; - int x_max; - int y_max; - int x_bits; - int y_bits; - unsigned int x_res; - unsigned int y_res; - - int (*hw_init)(struct psmouse *psmouse); - void (*process_packet)(struct psmouse *psmouse); - int (*decode_fields)(struct alps_fields *f, unsigned char *p, - struct psmouse *psmouse); - void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1); - - int prev_fin; - int multi_packet; - int second_touch; - unsigned char multi_data[6]; - struct alps_fields f; - u8 quirks; - struct timer_list timer; -}; - -#define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in trackstick packet */ - -#ifdef CONFIG_MOUSE_PS2_ALPS -int alps_detect(struct psmouse *psmouse, bool set_properties); -int alps_init(struct psmouse *psmouse); -#else -inline int alps_detect(struct psmouse *psmouse, bool set_properties) -{ - return -ENOSYS; -} -inline int alps_init(struct psmouse *psmouse) -{ - return -ENOSYS; -} -#endif /* CONFIG_MOUSE_PS2_ALPS */ - -#endif diff --git a/src/linux/drivers/input/mouse/byd.c b/src/linux/drivers/input/mouse/byd.c deleted file mode 100644 index b27aa63..0000000 --- a/src/linux/drivers/input/mouse/byd.c +++ /dev/null @@ -1,511 +0,0 @@ -/* - * BYD TouchPad PS/2 mouse driver - * - * Copyright (C) 2015 Chris Diamand - * Copyright (C) 2015 Richard Pospesel - * Copyright (C) 2015 Tai Chi Minh Ralph Eastwood - * Copyright (C) 2015 Martin Wimpress - * Copyright (C) 2015 Jay Kuri - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#include -#include -#include -#include -#include - -#include "psmouse.h" -#include "byd.h" - -/* PS2 Bits */ -#define PS2_Y_OVERFLOW BIT_MASK(7) -#define PS2_X_OVERFLOW BIT_MASK(6) -#define PS2_Y_SIGN BIT_MASK(5) -#define PS2_X_SIGN BIT_MASK(4) -#define PS2_ALWAYS_1 BIT_MASK(3) -#define PS2_MIDDLE BIT_MASK(2) -#define PS2_RIGHT BIT_MASK(1) -#define PS2_LEFT BIT_MASK(0) - -/* - * BYD pad constants - */ - -/* - * True device resolution is unknown, however experiments show the - * resolution is about 111 units/mm. - * Absolute coordinate packets are in the range 0-255 for both X and Y - * we pick ABS_X/ABS_Y dimensions which are multiples of 256 and in - * the right ballpark given the touchpad's physical dimensions and estimate - * resolution per spec sheet, device active area dimensions are - * 101.6 x 60.1 mm. - */ -#define BYD_PAD_WIDTH 11264 -#define BYD_PAD_HEIGHT 6656 -#define BYD_PAD_RESOLUTION 111 - -/* - * Given the above dimensions, relative packets velocity is in multiples of - * 1 unit / 11 milliseconds. We use this dt to estimate distance traveled - */ -#define BYD_DT 11 -/* Time in jiffies used to timeout various touch events (64 ms) */ -#define BYD_TOUCH_TIMEOUT msecs_to_jiffies(64) - -/* BYD commands reverse engineered from windows driver */ - -/* - * Swipe gesture from off-pad to on-pad - * 0 : disable - * 1 : enable - */ -#define BYD_CMD_SET_OFFSCREEN_SWIPE 0x10cc -/* - * Tap and drag delay time - * 0 : disable - * 1 - 8 : least to most delay - */ -#define BYD_CMD_SET_TAP_DRAG_DELAY_TIME 0x10cf -/* - * Physical buttons function mapping - * 0 : enable - * 4 : normal - * 5 : left button custom command - * 6 : right button custom command - * 8 : disable - */ -#define BYD_CMD_SET_PHYSICAL_BUTTONS 0x10d0 -/* - * Absolute mode (1 byte X/Y resolution) - * 0 : disable - * 2 : enable - */ -#define BYD_CMD_SET_ABSOLUTE_MODE 0x10d1 -/* - * Two finger scrolling - * 1 : vertical - * 2 : horizontal - * 3 : vertical + horizontal - * 4 : disable - */ -#define BYD_CMD_SET_TWO_FINGER_SCROLL 0x10d2 -/* - * Handedness - * 1 : right handed - * 2 : left handed - */ -#define BYD_CMD_SET_HANDEDNESS 0x10d3 -/* - * Tap to click - * 1 : enable - * 2 : disable - */ -#define BYD_CMD_SET_TAP 0x10d4 -/* - * Tap and drag - * 1 : tap and hold to drag - * 2 : tap and hold to drag + lock - * 3 : disable - */ -#define BYD_CMD_SET_TAP_DRAG 0x10d5 -/* - * Touch sensitivity - * 1 - 7 : least to most sensitive - */ -#define BYD_CMD_SET_TOUCH_SENSITIVITY 0x10d6 -/* - * One finger scrolling - * 1 : vertical - * 2 : horizontal - * 3 : vertical + horizontal - * 4 : disable - */ -#define BYD_CMD_SET_ONE_FINGER_SCROLL 0x10d7 -/* - * One finger scrolling function - * 1 : free scrolling - * 2 : edge motion - * 3 : free scrolling + edge motion - * 4 : disable - */ -#define BYD_CMD_SET_ONE_FINGER_SCROLL_FUNC 0x10d8 -/* - * Sliding speed - * 1 - 5 : slowest to fastest - */ -#define BYD_CMD_SET_SLIDING_SPEED 0x10da -/* - * Edge motion - * 1 : disable - * 2 : enable when dragging - * 3 : enable when dragging and pointing - */ -#define BYD_CMD_SET_EDGE_MOTION 0x10db -/* - * Left edge region size - * 0 - 7 : smallest to largest width - */ -#define BYD_CMD_SET_LEFT_EDGE_REGION 0x10dc -/* - * Top edge region size - * 0 - 9 : smallest to largest height - */ -#define BYD_CMD_SET_TOP_EDGE_REGION 0x10dd -/* - * Disregard palm press as clicks - * 1 - 6 : smallest to largest - */ -#define BYD_CMD_SET_PALM_CHECK 0x10de -/* - * Right edge region size - * 0 - 7 : smallest to largest width - */ -#define BYD_CMD_SET_RIGHT_EDGE_REGION 0x10df -/* - * Bottom edge region size - * 0 - 9 : smallest to largest height - */ -#define BYD_CMD_SET_BOTTOM_EDGE_REGION 0x10e1 -/* - * Multitouch gestures - * 1 : enable - * 2 : disable - */ -#define BYD_CMD_SET_MULTITOUCH 0x10e3 -/* - * Edge motion speed - * 0 : control with finger pressure - * 1 - 9 : slowest to fastest - */ -#define BYD_CMD_SET_EDGE_MOTION_SPEED 0x10e4 -/* - * Two finger scolling function - * 0 : free scrolling - * 1 : free scrolling (with momentum) - * 2 : edge motion - * 3 : free scrolling (with momentum) + edge motion - * 4 : disable - */ -#define BYD_CMD_SET_TWO_FINGER_SCROLL_FUNC 0x10e5 - -/* - * The touchpad generates a mixture of absolute and relative packets, indicated - * by the the last byte of each packet being set to one of the following: - */ -#define BYD_PACKET_ABSOLUTE 0xf8 -#define BYD_PACKET_RELATIVE 0x00 -/* Multitouch gesture packets */ -#define BYD_PACKET_PINCH_IN 0xd8 -#define BYD_PACKET_PINCH_OUT 0x28 -#define BYD_PACKET_ROTATE_CLOCKWISE 0x29 -#define BYD_PACKET_ROTATE_ANTICLOCKWISE 0xd7 -#define BYD_PACKET_TWO_FINGER_SCROLL_RIGHT 0x2a -#define BYD_PACKET_TWO_FINGER_SCROLL_DOWN 0x2b -#define BYD_PACKET_TWO_FINGER_SCROLL_UP 0xd5 -#define BYD_PACKET_TWO_FINGER_SCROLL_LEFT 0xd6 -#define BYD_PACKET_THREE_FINGER_SWIPE_RIGHT 0x2c -#define BYD_PACKET_THREE_FINGER_SWIPE_DOWN 0x2d -#define BYD_PACKET_THREE_FINGER_SWIPE_UP 0xd3 -#define BYD_PACKET_THREE_FINGER_SWIPE_LEFT 0xd4 -#define BYD_PACKET_FOUR_FINGER_DOWN 0x33 -#define BYD_PACKET_FOUR_FINGER_UP 0xcd -#define BYD_PACKET_REGION_SCROLL_RIGHT 0x35 -#define BYD_PACKET_REGION_SCROLL_DOWN 0x36 -#define BYD_PACKET_REGION_SCROLL_UP 0xca -#define BYD_PACKET_REGION_SCROLL_LEFT 0xcb -#define BYD_PACKET_RIGHT_CORNER_CLICK 0xd2 -#define BYD_PACKET_LEFT_CORNER_CLICK 0x2e -#define BYD_PACKET_LEFT_AND_RIGHT_CORNER_CLICK 0x2f -#define BYD_PACKET_ONTO_PAD_SWIPE_RIGHT 0x37 -#define BYD_PACKET_ONTO_PAD_SWIPE_DOWN 0x30 -#define BYD_PACKET_ONTO_PAD_SWIPE_UP 0xd0 -#define BYD_PACKET_ONTO_PAD_SWIPE_LEFT 0xc9 - -struct byd_data { - struct timer_list timer; - s32 abs_x; - s32 abs_y; - typeof(jiffies) last_touch_time; - bool btn_left; - bool btn_right; - bool touch; -}; - -static void byd_report_input(struct psmouse *psmouse) -{ - struct byd_data *priv = psmouse->private; - struct input_dev *dev = psmouse->dev; - - input_report_key(dev, BTN_TOUCH, priv->touch); - input_report_key(dev, BTN_TOOL_FINGER, priv->touch); - - input_report_abs(dev, ABS_X, priv->abs_x); - input_report_abs(dev, ABS_Y, priv->abs_y); - input_report_key(dev, BTN_LEFT, priv->btn_left); - input_report_key(dev, BTN_RIGHT, priv->btn_right); - - input_sync(dev); -} - -static void byd_clear_touch(unsigned long data) -{ - struct psmouse *psmouse = (struct psmouse *)data; - struct byd_data *priv = psmouse->private; - - serio_pause_rx(psmouse->ps2dev.serio); - priv->touch = false; - - byd_report_input(psmouse); - - serio_continue_rx(psmouse->ps2dev.serio); - - /* - * Move cursor back to center of pad when we lose touch - this - * specifically improves user experience when moving cursor with one - * finger, and pressing a button with another. - */ - priv->abs_x = BYD_PAD_WIDTH / 2; - priv->abs_y = BYD_PAD_HEIGHT / 2; -} - -static psmouse_ret_t byd_process_byte(struct psmouse *psmouse) -{ - struct byd_data *priv = psmouse->private; - u8 *pkt = psmouse->packet; - - if (psmouse->pktcnt > 0 && !(pkt[0] & PS2_ALWAYS_1)) { - psmouse_warn(psmouse, "Always_1 bit not 1. pkt[0] = %02x\n", - pkt[0]); - return PSMOUSE_BAD_DATA; - } - - if (psmouse->pktcnt < psmouse->pktsize) - return PSMOUSE_GOOD_DATA; - - /* Otherwise, a full packet has been received */ - switch (pkt[3]) { - case BYD_PACKET_ABSOLUTE: - /* Only use absolute packets for the start of movement. */ - if (!priv->touch) { - /* needed to detect tap */ - typeof(jiffies) tap_time = - priv->last_touch_time + BYD_TOUCH_TIMEOUT; - priv->touch = time_after(jiffies, tap_time); - - /* init abs position */ - priv->abs_x = pkt[1] * (BYD_PAD_WIDTH / 256); - priv->abs_y = (255 - pkt[2]) * (BYD_PAD_HEIGHT / 256); - } - break; - case BYD_PACKET_RELATIVE: { - /* Standard packet */ - /* Sign-extend if a sign bit is set. */ - u32 signx = pkt[0] & PS2_X_SIGN ? ~0xFF : 0; - u32 signy = pkt[0] & PS2_Y_SIGN ? ~0xFF : 0; - s32 dx = signx | (int) pkt[1]; - s32 dy = signy | (int) pkt[2]; - - /* Update position based on velocity */ - priv->abs_x += dx * BYD_DT; - priv->abs_y -= dy * BYD_DT; - - priv->touch = true; - break; - } - default: - psmouse_warn(psmouse, - "Unrecognized Z: pkt = %02x %02x %02x %02x\n", - psmouse->packet[0], psmouse->packet[1], - psmouse->packet[2], psmouse->packet[3]); - return PSMOUSE_BAD_DATA; - } - - priv->btn_left = pkt[0] & PS2_LEFT; - priv->btn_right = pkt[0] & PS2_RIGHT; - - byd_report_input(psmouse); - - /* Reset time since last touch. */ - if (priv->touch) { - priv->last_touch_time = jiffies; - mod_timer(&priv->timer, jiffies + BYD_TOUCH_TIMEOUT); - } - - return PSMOUSE_FULL_PACKET; -} - -static int byd_reset_touchpad(struct psmouse *psmouse) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - u8 param[4]; - size_t i; - - const struct { - u16 command; - u8 arg; - } seq[] = { - /* - * Intellimouse initialization sequence, to get 4-byte instead - * of 3-byte packets. - */ - { PSMOUSE_CMD_SETRATE, 0xC8 }, - { PSMOUSE_CMD_SETRATE, 0x64 }, - { PSMOUSE_CMD_SETRATE, 0x50 }, - { PSMOUSE_CMD_GETID, 0 }, - { PSMOUSE_CMD_ENABLE, 0 }, - /* - * BYD-specific initialization, which enables absolute mode and - * (if desired), the touchpad's built-in gesture detection. - */ - { 0x10E2, 0x00 }, - { 0x10E0, 0x02 }, - /* The touchpad should reply with 4 seemingly-random bytes */ - { 0x14E0, 0x01 }, - /* Pairs of parameters and values. */ - { BYD_CMD_SET_HANDEDNESS, 0x01 }, - { BYD_CMD_SET_PHYSICAL_BUTTONS, 0x04 }, - { BYD_CMD_SET_TAP, 0x02 }, - { BYD_CMD_SET_ONE_FINGER_SCROLL, 0x04 }, - { BYD_CMD_SET_ONE_FINGER_SCROLL_FUNC, 0x04 }, - { BYD_CMD_SET_EDGE_MOTION, 0x01 }, - { BYD_CMD_SET_PALM_CHECK, 0x00 }, - { BYD_CMD_SET_MULTITOUCH, 0x02 }, - { BYD_CMD_SET_TWO_FINGER_SCROLL, 0x04 }, - { BYD_CMD_SET_TWO_FINGER_SCROLL_FUNC, 0x04 }, - { BYD_CMD_SET_LEFT_EDGE_REGION, 0x00 }, - { BYD_CMD_SET_TOP_EDGE_REGION, 0x00 }, - { BYD_CMD_SET_RIGHT_EDGE_REGION, 0x00 }, - { BYD_CMD_SET_BOTTOM_EDGE_REGION, 0x00 }, - { BYD_CMD_SET_ABSOLUTE_MODE, 0x02 }, - /* Finalize initialization. */ - { 0x10E0, 0x00 }, - { 0x10E2, 0x01 }, - }; - - for (i = 0; i < ARRAY_SIZE(seq); ++i) { - memset(param, 0, sizeof(param)); - param[0] = seq[i].arg; - if (ps2_command(ps2dev, param, seq[i].command)) - return -EIO; - } - - psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); - return 0; -} - -static int byd_reconnect(struct psmouse *psmouse) -{ - int retry = 0, error = 0; - - psmouse_dbg(psmouse, "Reconnect\n"); - do { - psmouse_reset(psmouse); - if (retry) - ssleep(1); - error = byd_detect(psmouse, 0); - } while (error && ++retry < 3); - - if (error) - return error; - - psmouse_dbg(psmouse, "Reconnected after %d attempts\n", retry); - - error = byd_reset_touchpad(psmouse); - if (error) { - psmouse_err(psmouse, "Unable to initialize device\n"); - return error; - } - - return 0; -} - -static void byd_disconnect(struct psmouse *psmouse) -{ - struct byd_data *priv = psmouse->private; - - if (priv) { - del_timer(&priv->timer); - kfree(psmouse->private); - psmouse->private = NULL; - } -} - -int byd_detect(struct psmouse *psmouse, bool set_properties) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - u8 param[4] = {0x03, 0x00, 0x00, 0x00}; - - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) - return -1; - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) - return -1; - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) - return -1; - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) - return -1; - if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) - return -1; - - if (param[1] != 0x03 || param[2] != 0x64) - return -ENODEV; - - psmouse_dbg(psmouse, "BYD touchpad detected\n"); - - if (set_properties) { - psmouse->vendor = "BYD"; - psmouse->name = "TouchPad"; - } - - return 0; -} - -int byd_init(struct psmouse *psmouse) -{ - struct input_dev *dev = psmouse->dev; - struct byd_data *priv; - - if (psmouse_reset(psmouse)) - return -EIO; - - if (byd_reset_touchpad(psmouse)) - return -EIO; - - priv = kzalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - setup_timer(&priv->timer, byd_clear_touch, (unsigned long) psmouse); - - psmouse->private = priv; - psmouse->disconnect = byd_disconnect; - psmouse->reconnect = byd_reconnect; - psmouse->protocol_handler = byd_process_byte; - psmouse->pktsize = 4; - psmouse->resync_time = 0; - - __set_bit(INPUT_PROP_POINTER, dev->propbit); - /* Touchpad */ - __set_bit(BTN_TOUCH, dev->keybit); - __set_bit(BTN_TOOL_FINGER, dev->keybit); - /* Buttons */ - __set_bit(BTN_LEFT, dev->keybit); - __set_bit(BTN_RIGHT, dev->keybit); - __clear_bit(BTN_MIDDLE, dev->keybit); - - /* Absolute position */ - __set_bit(EV_ABS, dev->evbit); - input_set_abs_params(dev, ABS_X, 0, BYD_PAD_WIDTH, 0, 0); - input_set_abs_params(dev, ABS_Y, 0, BYD_PAD_HEIGHT, 0, 0); - input_abs_set_res(dev, ABS_X, BYD_PAD_RESOLUTION); - input_abs_set_res(dev, ABS_Y, BYD_PAD_RESOLUTION); - /* No relative support */ - __clear_bit(EV_REL, dev->evbit); - __clear_bit(REL_X, dev->relbit); - __clear_bit(REL_Y, dev->relbit); - - return 0; -} diff --git a/src/linux/drivers/input/mouse/byd.h b/src/linux/drivers/input/mouse/byd.h deleted file mode 100644 index d6c120c..0000000 --- a/src/linux/drivers/input/mouse/byd.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _BYD_H -#define _BYD_H - -#ifdef CONFIG_MOUSE_PS2_BYD -int byd_detect(struct psmouse *psmouse, bool set_properties); -int byd_init(struct psmouse *psmouse); -#else -static inline int byd_detect(struct psmouse *psmouse, bool set_properties) -{ - return -ENOSYS; -} -static inline int byd_init(struct psmouse *psmouse) -{ - return -ENOSYS; -} -#endif /* CONFIG_MOUSE_PS2_BYD */ - -#endif /* _BYD_H */ diff --git a/src/linux/drivers/input/mouse/cypress_ps2.c b/src/linux/drivers/input/mouse/cypress_ps2.c deleted file mode 100644 index 28dcfc8..0000000 --- a/src/linux/drivers/input/mouse/cypress_ps2.c +++ /dev/null @@ -1,712 +0,0 @@ -/* - * Cypress Trackpad PS/2 mouse driver - * - * Copyright (c) 2012 Cypress Semiconductor Corporation. - * - * Author: - * Dudley Du - * - * Additional contributors include: - * Kamal Mostafa - * Kyle Fazzari - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cypress_ps2.h" - -#undef CYTP_DEBUG_VERBOSE /* define this and DEBUG for more verbose dump */ - -static void cypress_set_packet_size(struct psmouse *psmouse, unsigned int n) -{ - struct cytp_data *cytp = psmouse->private; - cytp->pkt_size = n; -} - -static const unsigned char cytp_rate[] = {10, 20, 40, 60, 100, 200}; -static const unsigned char cytp_resolution[] = {0x00, 0x01, 0x02, 0x03}; - -static int cypress_ps2_sendbyte(struct psmouse *psmouse, int value) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - - if (ps2_sendbyte(ps2dev, value & 0xff, CYTP_CMD_TIMEOUT) < 0) { - psmouse_dbg(psmouse, - "sending command 0x%02x failed, resp 0x%02x\n", - value & 0xff, ps2dev->nak); - if (ps2dev->nak == CYTP_PS2_RETRY) - return CYTP_PS2_RETRY; - else - return CYTP_PS2_ERROR; - } - -#ifdef CYTP_DEBUG_VERBOSE - psmouse_dbg(psmouse, "sending command 0x%02x succeeded, resp 0xfa\n", - value & 0xff); -#endif - - return 0; -} - -static int cypress_ps2_ext_cmd(struct psmouse *psmouse, unsigned short cmd, - unsigned char data) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - int tries = CYTP_PS2_CMD_TRIES; - int rc; - - ps2_begin_command(ps2dev); - - do { - /* - * Send extension command byte (0xE8 or 0xF3). - * If sending the command fails, send recovery command - * to make the device return to the ready state. - */ - rc = cypress_ps2_sendbyte(psmouse, cmd & 0xff); - if (rc == CYTP_PS2_RETRY) { - rc = cypress_ps2_sendbyte(psmouse, 0x00); - if (rc == CYTP_PS2_RETRY) - rc = cypress_ps2_sendbyte(psmouse, 0x0a); - } - if (rc == CYTP_PS2_ERROR) - continue; - - rc = cypress_ps2_sendbyte(psmouse, data); - if (rc == CYTP_PS2_RETRY) - rc = cypress_ps2_sendbyte(psmouse, data); - if (rc == CYTP_PS2_ERROR) - continue; - else - break; - } while (--tries > 0); - - ps2_end_command(ps2dev); - - return rc; -} - -static int cypress_ps2_read_cmd_status(struct psmouse *psmouse, - unsigned char cmd, - unsigned char *param) -{ - int rc; - struct ps2dev *ps2dev = &psmouse->ps2dev; - enum psmouse_state old_state; - int pktsize; - - ps2_begin_command(&psmouse->ps2dev); - - old_state = psmouse->state; - psmouse->state = PSMOUSE_CMD_MODE; - psmouse->pktcnt = 0; - - pktsize = (cmd == CYTP_CMD_READ_TP_METRICS) ? 8 : 3; - memset(param, 0, pktsize); - - rc = cypress_ps2_sendbyte(psmouse, 0xe9); - if (rc < 0) - goto out; - - wait_event_timeout(ps2dev->wait, - (psmouse->pktcnt >= pktsize), - msecs_to_jiffies(CYTP_CMD_TIMEOUT)); - - memcpy(param, psmouse->packet, pktsize); - - psmouse_dbg(psmouse, "Command 0x%02x response data (0x): %*ph\n", - cmd, pktsize, param); - -out: - psmouse->state = old_state; - psmouse->pktcnt = 0; - - ps2_end_command(&psmouse->ps2dev); - - return rc; -} - -static bool cypress_verify_cmd_state(struct psmouse *psmouse, - unsigned char cmd, unsigned char *param) -{ - bool rate_match = false; - bool resolution_match = false; - int i; - - /* callers will do further checking. */ - if (cmd == CYTP_CMD_READ_CYPRESS_ID || - cmd == CYTP_CMD_STANDARD_MODE || - cmd == CYTP_CMD_READ_TP_METRICS) - return true; - - if ((~param[0] & DFLT_RESP_BITS_VALID) == DFLT_RESP_BITS_VALID && - (param[0] & DFLT_RESP_BIT_MODE) == DFLT_RESP_STREAM_MODE) { - for (i = 0; i < sizeof(cytp_resolution); i++) - if (cytp_resolution[i] == param[1]) - resolution_match = true; - - for (i = 0; i < sizeof(cytp_rate); i++) - if (cytp_rate[i] == param[2]) - rate_match = true; - - if (resolution_match && rate_match) - return true; - } - - psmouse_dbg(psmouse, "verify cmd state failed.\n"); - return false; -} - -static int cypress_send_ext_cmd(struct psmouse *psmouse, unsigned char cmd, - unsigned char *param) -{ - int tries = CYTP_PS2_CMD_TRIES; - int rc; - - psmouse_dbg(psmouse, "send extension cmd 0x%02x, [%d %d %d %d]\n", - cmd, DECODE_CMD_AA(cmd), DECODE_CMD_BB(cmd), - DECODE_CMD_CC(cmd), DECODE_CMD_DD(cmd)); - - do { - cypress_ps2_ext_cmd(psmouse, - PSMOUSE_CMD_SETRES, DECODE_CMD_DD(cmd)); - cypress_ps2_ext_cmd(psmouse, - PSMOUSE_CMD_SETRES, DECODE_CMD_CC(cmd)); - cypress_ps2_ext_cmd(psmouse, - PSMOUSE_CMD_SETRES, DECODE_CMD_BB(cmd)); - cypress_ps2_ext_cmd(psmouse, - PSMOUSE_CMD_SETRES, DECODE_CMD_AA(cmd)); - - rc = cypress_ps2_read_cmd_status(psmouse, cmd, param); - if (rc) - continue; - - if (cypress_verify_cmd_state(psmouse, cmd, param)) - return 0; - - } while (--tries > 0); - - return -EIO; -} - -int cypress_detect(struct psmouse *psmouse, bool set_properties) -{ - unsigned char param[3]; - - if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_CYPRESS_ID, param)) - return -ENODEV; - - /* Check for Cypress Trackpad signature bytes: 0x33 0xCC */ - if (param[0] != 0x33 || param[1] != 0xCC) - return -ENODEV; - - if (set_properties) { - psmouse->vendor = "Cypress"; - psmouse->name = "Trackpad"; - } - - return 0; -} - -static int cypress_read_fw_version(struct psmouse *psmouse) -{ - struct cytp_data *cytp = psmouse->private; - unsigned char param[3]; - - if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_CYPRESS_ID, param)) - return -ENODEV; - - /* Check for Cypress Trackpad signature bytes: 0x33 0xCC */ - if (param[0] != 0x33 || param[1] != 0xCC) - return -ENODEV; - - cytp->fw_version = param[2] & FW_VERSION_MASX; - cytp->tp_metrics_supported = (param[2] & TP_METRICS_MASK) ? 1 : 0; - - /* - * Trackpad fw_version 11 (in Dell XPS12) yields a bogus response to - * CYTP_CMD_READ_TP_METRICS so do not try to use it. LP: #1103594. - */ - if (cytp->fw_version >= 11) - cytp->tp_metrics_supported = 0; - - psmouse_dbg(psmouse, "cytp->fw_version = %d\n", cytp->fw_version); - psmouse_dbg(psmouse, "cytp->tp_metrics_supported = %d\n", - cytp->tp_metrics_supported); - - return 0; -} - -static int cypress_read_tp_metrics(struct psmouse *psmouse) -{ - struct cytp_data *cytp = psmouse->private; - unsigned char param[8]; - - /* set default values for tp metrics. */ - cytp->tp_width = CYTP_DEFAULT_WIDTH; - cytp->tp_high = CYTP_DEFAULT_HIGH; - cytp->tp_max_abs_x = CYTP_ABS_MAX_X; - cytp->tp_max_abs_y = CYTP_ABS_MAX_Y; - cytp->tp_min_pressure = CYTP_MIN_PRESSURE; - cytp->tp_max_pressure = CYTP_MAX_PRESSURE; - cytp->tp_res_x = cytp->tp_max_abs_x / cytp->tp_width; - cytp->tp_res_y = cytp->tp_max_abs_y / cytp->tp_high; - - if (!cytp->tp_metrics_supported) - return 0; - - memset(param, 0, sizeof(param)); - if (cypress_send_ext_cmd(psmouse, CYTP_CMD_READ_TP_METRICS, param) == 0) { - /* Update trackpad parameters. */ - cytp->tp_max_abs_x = (param[1] << 8) | param[0]; - cytp->tp_max_abs_y = (param[3] << 8) | param[2]; - cytp->tp_min_pressure = param[4]; - cytp->tp_max_pressure = param[5]; - } - - if (!cytp->tp_max_pressure || - cytp->tp_max_pressure < cytp->tp_min_pressure || - !cytp->tp_width || !cytp->tp_high || - !cytp->tp_max_abs_x || - cytp->tp_max_abs_x < cytp->tp_width || - !cytp->tp_max_abs_y || - cytp->tp_max_abs_y < cytp->tp_high) - return -EINVAL; - - cytp->tp_res_x = cytp->tp_max_abs_x / cytp->tp_width; - cytp->tp_res_y = cytp->tp_max_abs_y / cytp->tp_high; - -#ifdef CYTP_DEBUG_VERBOSE - psmouse_dbg(psmouse, "Dump trackpad hardware configuration as below:\n"); - psmouse_dbg(psmouse, "cytp->tp_width = %d\n", cytp->tp_width); - psmouse_dbg(psmouse, "cytp->tp_high = %d\n", cytp->tp_high); - psmouse_dbg(psmouse, "cytp->tp_max_abs_x = %d\n", cytp->tp_max_abs_x); - psmouse_dbg(psmouse, "cytp->tp_max_abs_y = %d\n", cytp->tp_max_abs_y); - psmouse_dbg(psmouse, "cytp->tp_min_pressure = %d\n", cytp->tp_min_pressure); - psmouse_dbg(psmouse, "cytp->tp_max_pressure = %d\n", cytp->tp_max_pressure); - psmouse_dbg(psmouse, "cytp->tp_res_x = %d\n", cytp->tp_res_x); - psmouse_dbg(psmouse, "cytp->tp_res_y = %d\n", cytp->tp_res_y); - - psmouse_dbg(psmouse, "tp_type_APA = %d\n", - (param[6] & TP_METRICS_BIT_APA) ? 1 : 0); - psmouse_dbg(psmouse, "tp_type_MTG = %d\n", - (param[6] & TP_METRICS_BIT_MTG) ? 1 : 0); - psmouse_dbg(psmouse, "tp_palm = %d\n", - (param[6] & TP_METRICS_BIT_PALM) ? 1 : 0); - psmouse_dbg(psmouse, "tp_stubborn = %d\n", - (param[6] & TP_METRICS_BIT_STUBBORN) ? 1 : 0); - psmouse_dbg(psmouse, "tp_1f_jitter = %d\n", - (param[6] & TP_METRICS_BIT_1F_JITTER) >> 2); - psmouse_dbg(psmouse, "tp_2f_jitter = %d\n", - (param[6] & TP_METRICS_BIT_2F_JITTER) >> 4); - psmouse_dbg(psmouse, "tp_1f_spike = %d\n", - param[7] & TP_METRICS_BIT_1F_SPIKE); - psmouse_dbg(psmouse, "tp_2f_spike = %d\n", - (param[7] & TP_METRICS_BIT_2F_SPIKE) >> 2); - psmouse_dbg(psmouse, "tp_abs_packet_format_set = %d\n", - (param[7] & TP_METRICS_BIT_ABS_PKT_FORMAT_SET) >> 4); -#endif - - return 0; -} - -static int cypress_query_hardware(struct psmouse *psmouse) -{ - int ret; - - ret = cypress_read_fw_version(psmouse); - if (ret) - return ret; - - ret = cypress_read_tp_metrics(psmouse); - if (ret) - return ret; - - return 0; -} - -static int cypress_set_absolute_mode(struct psmouse *psmouse) -{ - struct cytp_data *cytp = psmouse->private; - unsigned char param[3]; - - if (cypress_send_ext_cmd(psmouse, CYTP_CMD_ABS_WITH_PRESSURE_MODE, param) < 0) - return -1; - - cytp->mode = (cytp->mode & ~CYTP_BIT_ABS_REL_MASK) - | CYTP_BIT_ABS_PRESSURE; - cypress_set_packet_size(psmouse, 5); - - return 0; -} - -/* - * Reset trackpad device. - * This is also the default mode when trackpad powered on. - */ -static void cypress_reset(struct psmouse *psmouse) -{ - struct cytp_data *cytp = psmouse->private; - - cytp->mode = 0; - - psmouse_reset(psmouse); -} - -static int cypress_set_input_params(struct input_dev *input, - struct cytp_data *cytp) -{ - int ret; - - if (!cytp->tp_res_x || !cytp->tp_res_y) - return -EINVAL; - - __set_bit(EV_ABS, input->evbit); - input_set_abs_params(input, ABS_X, 0, cytp->tp_max_abs_x, 0, 0); - input_set_abs_params(input, ABS_Y, 0, cytp->tp_max_abs_y, 0, 0); - input_set_abs_params(input, ABS_PRESSURE, - cytp->tp_min_pressure, cytp->tp_max_pressure, 0, 0); - input_set_abs_params(input, ABS_TOOL_WIDTH, 0, 255, 0, 0); - - /* finger position */ - input_set_abs_params(input, ABS_MT_POSITION_X, 0, cytp->tp_max_abs_x, 0, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cytp->tp_max_abs_y, 0, 0); - input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0); - - ret = input_mt_init_slots(input, CYTP_MAX_MT_SLOTS, - INPUT_MT_DROP_UNUSED|INPUT_MT_TRACK); - if (ret < 0) - return ret; - - __set_bit(INPUT_PROP_SEMI_MT, input->propbit); - - input_abs_set_res(input, ABS_X, cytp->tp_res_x); - input_abs_set_res(input, ABS_Y, cytp->tp_res_y); - - input_abs_set_res(input, ABS_MT_POSITION_X, cytp->tp_res_x); - input_abs_set_res(input, ABS_MT_POSITION_Y, cytp->tp_res_y); - - __set_bit(BTN_TOUCH, input->keybit); - __set_bit(BTN_TOOL_FINGER, input->keybit); - __set_bit(BTN_TOOL_DOUBLETAP, input->keybit); - __set_bit(BTN_TOOL_TRIPLETAP, input->keybit); - __set_bit(BTN_TOOL_QUADTAP, input->keybit); - __set_bit(BTN_TOOL_QUINTTAP, input->keybit); - - __clear_bit(EV_REL, input->evbit); - __clear_bit(REL_X, input->relbit); - __clear_bit(REL_Y, input->relbit); - - __set_bit(EV_KEY, input->evbit); - __set_bit(BTN_LEFT, input->keybit); - __set_bit(BTN_RIGHT, input->keybit); - __set_bit(BTN_MIDDLE, input->keybit); - - input_set_drvdata(input, cytp); - - return 0; -} - -static int cypress_get_finger_count(unsigned char header_byte) -{ - unsigned char bits6_7; - int finger_count; - - bits6_7 = header_byte >> 6; - finger_count = bits6_7 & 0x03; - - if (finger_count == 1) - return 1; - - if (header_byte & ABS_HSCROLL_BIT) { - /* HSCROLL gets added on to 0 finger count. */ - switch (finger_count) { - case 0: return 4; - case 2: return 5; - default: - /* Invalid contact (e.g. palm). Ignore it. */ - return 0; - } - } - - return finger_count; -} - - -static int cypress_parse_packet(struct psmouse *psmouse, - struct cytp_data *cytp, struct cytp_report_data *report_data) -{ - unsigned char *packet = psmouse->packet; - unsigned char header_byte = packet[0]; - - memset(report_data, 0, sizeof(struct cytp_report_data)); - - report_data->contact_cnt = cypress_get_finger_count(header_byte); - report_data->tap = (header_byte & ABS_MULTIFINGER_TAP) ? 1 : 0; - - if (report_data->contact_cnt == 1) { - report_data->contacts[0].x = - ((packet[1] & 0x70) << 4) | packet[2]; - report_data->contacts[0].y = - ((packet[1] & 0x07) << 8) | packet[3]; - if (cytp->mode & CYTP_BIT_ABS_PRESSURE) - report_data->contacts[0].z = packet[4]; - - } else if (report_data->contact_cnt >= 2) { - report_data->contacts[0].x = - ((packet[1] & 0x70) << 4) | packet[2]; - report_data->contacts[0].y = - ((packet[1] & 0x07) << 8) | packet[3]; - if (cytp->mode & CYTP_BIT_ABS_PRESSURE) - report_data->contacts[0].z = packet[4]; - - report_data->contacts[1].x = - ((packet[5] & 0xf0) << 4) | packet[6]; - report_data->contacts[1].y = - ((packet[5] & 0x0f) << 8) | packet[7]; - if (cytp->mode & CYTP_BIT_ABS_PRESSURE) - report_data->contacts[1].z = report_data->contacts[0].z; - } - - report_data->left = (header_byte & BTN_LEFT_BIT) ? 1 : 0; - report_data->right = (header_byte & BTN_RIGHT_BIT) ? 1 : 0; - - /* - * This is only true if one of the mouse buttons were tapped. Make - * sure it doesn't turn into a click. The regular tap-to-click - * functionality will handle that on its own. If we don't do this, - * disabling tap-to-click won't affect the mouse button zones. - */ - if (report_data->tap) - report_data->left = 0; - -#ifdef CYTP_DEBUG_VERBOSE - { - int i; - int n = report_data->contact_cnt; - psmouse_dbg(psmouse, "Dump parsed report data as below:\n"); - psmouse_dbg(psmouse, "contact_cnt = %d\n", - report_data->contact_cnt); - if (n > CYTP_MAX_MT_SLOTS) - n = CYTP_MAX_MT_SLOTS; - for (i = 0; i < n; i++) - psmouse_dbg(psmouse, "contacts[%d] = {%d, %d, %d}\n", i, - report_data->contacts[i].x, - report_data->contacts[i].y, - report_data->contacts[i].z); - psmouse_dbg(psmouse, "left = %d\n", report_data->left); - psmouse_dbg(psmouse, "right = %d\n", report_data->right); - psmouse_dbg(psmouse, "middle = %d\n", report_data->middle); - } -#endif - - return 0; -} - -static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt) -{ - int i; - struct input_dev *input = psmouse->dev; - struct cytp_data *cytp = psmouse->private; - struct cytp_report_data report_data; - struct cytp_contact *contact; - struct input_mt_pos pos[CYTP_MAX_MT_SLOTS]; - int slots[CYTP_MAX_MT_SLOTS]; - int n; - - cypress_parse_packet(psmouse, cytp, &report_data); - - n = report_data.contact_cnt; - if (n > CYTP_MAX_MT_SLOTS) - n = CYTP_MAX_MT_SLOTS; - - for (i = 0; i < n; i++) { - contact = &report_data.contacts[i]; - pos[i].x = contact->x; - pos[i].y = contact->y; - } - - input_mt_assign_slots(input, slots, pos, n, 0); - - for (i = 0; i < n; i++) { - contact = &report_data.contacts[i]; - input_mt_slot(input, slots[i]); - input_mt_report_slot_state(input, MT_TOOL_FINGER, true); - input_report_abs(input, ABS_MT_POSITION_X, contact->x); - input_report_abs(input, ABS_MT_POSITION_Y, contact->y); - input_report_abs(input, ABS_MT_PRESSURE, contact->z); - } - - input_mt_sync_frame(input); - - input_mt_report_finger_count(input, report_data.contact_cnt); - - input_report_key(input, BTN_LEFT, report_data.left); - input_report_key(input, BTN_RIGHT, report_data.right); - input_report_key(input, BTN_MIDDLE, report_data.middle); - - input_sync(input); -} - -static psmouse_ret_t cypress_validate_byte(struct psmouse *psmouse) -{ - int contact_cnt; - int index = psmouse->pktcnt - 1; - unsigned char *packet = psmouse->packet; - struct cytp_data *cytp = psmouse->private; - - if (index < 0 || index > cytp->pkt_size) - return PSMOUSE_BAD_DATA; - - if (index == 0 && (packet[0] & 0xfc) == 0) { - /* call packet process for reporting finger leave. */ - cypress_process_packet(psmouse, 1); - return PSMOUSE_FULL_PACKET; - } - - /* - * Perform validation (and adjust packet size) based only on the - * first byte; allow all further bytes through. - */ - if (index != 0) - return PSMOUSE_GOOD_DATA; - - /* - * If absolute/relative mode bit has not been set yet, just pass - * the byte through. - */ - if ((cytp->mode & CYTP_BIT_ABS_REL_MASK) == 0) - return PSMOUSE_GOOD_DATA; - - if ((packet[0] & 0x08) == 0x08) - return PSMOUSE_BAD_DATA; - - contact_cnt = cypress_get_finger_count(packet[0]); - if (cytp->mode & CYTP_BIT_ABS_NO_PRESSURE) - cypress_set_packet_size(psmouse, contact_cnt == 2 ? 7 : 4); - else - cypress_set_packet_size(psmouse, contact_cnt == 2 ? 8 : 5); - - return PSMOUSE_GOOD_DATA; -} - -static psmouse_ret_t cypress_protocol_handler(struct psmouse *psmouse) -{ - struct cytp_data *cytp = psmouse->private; - - if (psmouse->pktcnt >= cytp->pkt_size) { - cypress_process_packet(psmouse, 0); - return PSMOUSE_FULL_PACKET; - } - - return cypress_validate_byte(psmouse); -} - -static void cypress_set_rate(struct psmouse *psmouse, unsigned int rate) -{ - struct cytp_data *cytp = psmouse->private; - - if (rate >= 80) { - psmouse->rate = 80; - cytp->mode |= CYTP_BIT_HIGH_RATE; - } else { - psmouse->rate = 40; - cytp->mode &= ~CYTP_BIT_HIGH_RATE; - } - - ps2_command(&psmouse->ps2dev, (unsigned char *)&psmouse->rate, - PSMOUSE_CMD_SETRATE); -} - -static void cypress_disconnect(struct psmouse *psmouse) -{ - cypress_reset(psmouse); - kfree(psmouse->private); - psmouse->private = NULL; -} - -static int cypress_reconnect(struct psmouse *psmouse) -{ - int tries = CYTP_PS2_CMD_TRIES; - int rc; - - do { - cypress_reset(psmouse); - rc = cypress_detect(psmouse, false); - } while (rc && (--tries > 0)); - - if (rc) { - psmouse_err(psmouse, "Reconnect: unable to detect trackpad.\n"); - return -1; - } - - if (cypress_set_absolute_mode(psmouse)) { - psmouse_err(psmouse, "Reconnect: Unable to initialize Cypress absolute mode.\n"); - return -1; - } - - return 0; -} - -int cypress_init(struct psmouse *psmouse) -{ - struct cytp_data *cytp; - - cytp = kzalloc(sizeof(struct cytp_data), GFP_KERNEL); - if (!cytp) - return -ENOMEM; - - psmouse->private = cytp; - psmouse->pktsize = 8; - - cypress_reset(psmouse); - - if (cypress_query_hardware(psmouse)) { - psmouse_err(psmouse, "Unable to query Trackpad hardware.\n"); - goto err_exit; - } - - if (cypress_set_absolute_mode(psmouse)) { - psmouse_err(psmouse, "init: Unable to initialize Cypress absolute mode.\n"); - goto err_exit; - } - - if (cypress_set_input_params(psmouse->dev, cytp) < 0) { - psmouse_err(psmouse, "init: Unable to set input params.\n"); - goto err_exit; - } - - psmouse->model = 1; - psmouse->protocol_handler = cypress_protocol_handler; - psmouse->set_rate = cypress_set_rate; - psmouse->disconnect = cypress_disconnect; - psmouse->reconnect = cypress_reconnect; - psmouse->cleanup = cypress_reset; - psmouse->resync_time = 0; - - return 0; - -err_exit: - /* - * Reset Cypress Trackpad as a standard mouse. Then - * let psmouse driver commmunicating with it as default PS2 mouse. - */ - cypress_reset(psmouse); - - psmouse->private = NULL; - kfree(cytp); - - return -1; -} diff --git a/src/linux/drivers/input/mouse/cypress_ps2.h b/src/linux/drivers/input/mouse/cypress_ps2.h deleted file mode 100644 index 81f68aa..0000000 --- a/src/linux/drivers/input/mouse/cypress_ps2.h +++ /dev/null @@ -1,186 +0,0 @@ -#ifndef _CYPRESS_PS2_H -#define _CYPRESS_PS2_H - -#include "psmouse.h" - -#define CMD_BITS_MASK 0x03 -#define COMPOSIT(x, s) (((x) & CMD_BITS_MASK) << (s)) - -#define ENCODE_CMD(aa, bb, cc, dd) \ - (COMPOSIT((aa), 6) | COMPOSIT((bb), 4) | COMPOSIT((cc), 2) | COMPOSIT((dd), 0)) -#define CYTP_CMD_ABS_NO_PRESSURE_MODE ENCODE_CMD(0, 1, 0, 0) -#define CYTP_CMD_ABS_WITH_PRESSURE_MODE ENCODE_CMD(0, 1, 0, 1) -#define CYTP_CMD_SMBUS_MODE ENCODE_CMD(0, 1, 1, 0) -#define CYTP_CMD_STANDARD_MODE ENCODE_CMD(0, 2, 0, 0) /* not implemented yet. */ -#define CYTP_CMD_CYPRESS_REL_MODE ENCODE_CMD(1, 1, 1, 1) /* not implemented yet. */ -#define CYTP_CMD_READ_CYPRESS_ID ENCODE_CMD(0, 0, 0, 0) -#define CYTP_CMD_READ_TP_METRICS ENCODE_CMD(0, 0, 0, 1) -#define CYTP_CMD_SET_HSCROLL_WIDTH(w) ENCODE_CMD(1, 1, 0, (w)) -#define CYTP_CMD_SET_HSCROLL_MASK ENCODE_CMD(1, 1, 0, 0) -#define CYTP_CMD_SET_VSCROLL_WIDTH(w) ENCODE_CMD(1, 2, 0, (w)) -#define CYTP_CMD_SET_VSCROLL_MASK ENCODE_CMD(1, 2, 0, 0) -#define CYTP_CMD_SET_PALM_GEOMETRY(e) ENCODE_CMD(1, 2, 1, (e)) -#define CYTP_CMD_PALM_GEMMETRY_MASK ENCODE_CMD(1, 2, 1, 0) -#define CYTP_CMD_SET_PALM_SENSITIVITY(s) ENCODE_CMD(1, 2, 2, (s)) -#define CYTP_CMD_PALM_SENSITIVITY_MASK ENCODE_CMD(1, 2, 2, 0) -#define CYTP_CMD_SET_MOUSE_SENSITIVITY(s) ENCODE_CMD(1, 3, ((s) >> 2), (s)) -#define CYTP_CMD_MOUSE_SENSITIVITY_MASK ENCODE_CMD(1, 3, 0, 0) -#define CYTP_CMD_REQUEST_BASELINE_STATUS ENCODE_CMD(2, 0, 0, 1) -#define CYTP_CMD_REQUEST_RECALIBRATION ENCODE_CMD(2, 0, 0, 3) - -#define DECODE_CMD_AA(x) (((x) >> 6) & CMD_BITS_MASK) -#define DECODE_CMD_BB(x) (((x) >> 4) & CMD_BITS_MASK) -#define DECODE_CMD_CC(x) (((x) >> 2) & CMD_BITS_MASK) -#define DECODE_CMD_DD(x) ((x) & CMD_BITS_MASK) - -/* Cypress trackpad working mode. */ -#define CYTP_BIT_ABS_PRESSURE (1 << 3) -#define CYTP_BIT_ABS_NO_PRESSURE (1 << 2) -#define CYTP_BIT_CYPRESS_REL (1 << 1) -#define CYTP_BIT_STANDARD_REL (1 << 0) -#define CYTP_BIT_REL_MASK (CYTP_BIT_CYPRESS_REL | CYTP_BIT_STANDARD_REL) -#define CYTP_BIT_ABS_MASK (CYTP_BIT_ABS_PRESSURE | CYTP_BIT_ABS_NO_PRESSURE) -#define CYTP_BIT_ABS_REL_MASK (CYTP_BIT_ABS_MASK | CYTP_BIT_REL_MASK) - -#define CYTP_BIT_HIGH_RATE (1 << 4) -/* - * report mode bit is set, firmware working in Remote Mode. - * report mode bit is cleared, firmware working in Stream Mode. - */ -#define CYTP_BIT_REPORT_MODE (1 << 5) - -/* scrolling width values for set HSCROLL and VSCROLL width command. */ -#define SCROLL_WIDTH_NARROW 1 -#define SCROLL_WIDTH_NORMAL 2 -#define SCROLL_WIDTH_WIDE 3 - -#define PALM_GEOMETRY_ENABLE 1 -#define PALM_GEOMETRY_DISABLE 0 - -#define TP_METRICS_MASK 0x80 -#define FW_VERSION_MASX 0x7f -#define FW_VER_HIGH_MASK 0x70 -#define FW_VER_LOW_MASK 0x0f - -/* Times to retry a ps2_command and millisecond delay between tries. */ -#define CYTP_PS2_CMD_TRIES 3 -#define CYTP_PS2_CMD_DELAY 500 - -/* time out for PS/2 command only in milliseconds. */ -#define CYTP_CMD_TIMEOUT 200 -#define CYTP_DATA_TIMEOUT 30 - -#define CYTP_EXT_CMD 0xe8 -#define CYTP_PS2_RETRY 0xfe -#define CYTP_PS2_ERROR 0xfc - -#define CYTP_RESP_RETRY 0x01 -#define CYTP_RESP_ERROR 0xfe - - -#define CYTP_105001_WIDTH 97 /* Dell XPS 13 */ -#define CYTP_105001_HIGH 59 -#define CYTP_DEFAULT_WIDTH (CYTP_105001_WIDTH) -#define CYTP_DEFAULT_HIGH (CYTP_105001_HIGH) - -#define CYTP_ABS_MAX_X 1600 -#define CYTP_ABS_MAX_Y 900 -#define CYTP_MAX_PRESSURE 255 -#define CYTP_MIN_PRESSURE 0 - -/* header byte bits of relative package. */ -#define BTN_LEFT_BIT 0x01 -#define BTN_RIGHT_BIT 0x02 -#define BTN_MIDDLE_BIT 0x04 -#define REL_X_SIGN_BIT 0x10 -#define REL_Y_SIGN_BIT 0x20 - -/* header byte bits of absolute package. */ -#define ABS_VSCROLL_BIT 0x10 -#define ABS_HSCROLL_BIT 0x20 -#define ABS_MULTIFINGER_TAP 0x04 -#define ABS_EDGE_MOTION_MASK 0x80 - -#define DFLT_RESP_BITS_VALID 0x88 /* SMBus bit should not be set. */ -#define DFLT_RESP_SMBUS_BIT 0x80 -#define DFLT_SMBUS_MODE 0x80 -#define DFLT_PS2_MODE 0x00 -#define DFLT_RESP_BIT_MODE 0x40 -#define DFLT_RESP_REMOTE_MODE 0x40 -#define DFLT_RESP_STREAM_MODE 0x00 -#define DFLT_RESP_BIT_REPORTING 0x20 -#define DFLT_RESP_BIT_SCALING 0x10 - -#define TP_METRICS_BIT_PALM 0x80 -#define TP_METRICS_BIT_STUBBORN 0x40 -#define TP_METRICS_BIT_2F_JITTER 0x30 -#define TP_METRICS_BIT_1F_JITTER 0x0c -#define TP_METRICS_BIT_APA 0x02 -#define TP_METRICS_BIT_MTG 0x01 -#define TP_METRICS_BIT_ABS_PKT_FORMAT_SET 0xf0 -#define TP_METRICS_BIT_2F_SPIKE 0x0c -#define TP_METRICS_BIT_1F_SPIKE 0x03 - -/* bits of first byte response of E9h-Status Request command. */ -#define RESP_BTN_RIGHT_BIT 0x01 -#define RESP_BTN_MIDDLE_BIT 0x02 -#define RESP_BTN_LEFT_BIT 0x04 -#define RESP_SCALING_BIT 0x10 -#define RESP_ENABLE_BIT 0x20 -#define RESP_REMOTE_BIT 0x40 -#define RESP_SMBUS_BIT 0x80 - -#define CYTP_MAX_MT_SLOTS 2 - -struct cytp_contact { - int x; - int y; - int z; /* also named as touch pressure. */ -}; - -/* The structure of Cypress Trackpad event data. */ -struct cytp_report_data { - int contact_cnt; - struct cytp_contact contacts[CYTP_MAX_MT_SLOTS]; - unsigned int left:1; - unsigned int right:1; - unsigned int middle:1; - unsigned int tap:1; /* multi-finger tap detected. */ -}; - -/* The structure of Cypress Trackpad device private data. */ -struct cytp_data { - int fw_version; - - int pkt_size; - int mode; - - int tp_min_pressure; - int tp_max_pressure; - int tp_width; /* X direction physical size in mm. */ - int tp_high; /* Y direction physical size in mm. */ - int tp_max_abs_x; /* Max X absolute units that can be reported. */ - int tp_max_abs_y; /* Max Y absolute units that can be reported. */ - - int tp_res_x; /* X resolution in units/mm. */ - int tp_res_y; /* Y resolution in units/mm. */ - - int tp_metrics_supported; -}; - - -#ifdef CONFIG_MOUSE_PS2_CYPRESS -int cypress_detect(struct psmouse *psmouse, bool set_properties); -int cypress_init(struct psmouse *psmouse); -#else -inline int cypress_detect(struct psmouse *psmouse, bool set_properties) -{ - return -ENOSYS; -} -inline int cypress_init(struct psmouse *psmouse) -{ - return -ENOSYS; -} -#endif /* CONFIG_MOUSE_PS2_CYPRESS */ - -#endif /* _CYPRESS_PS2_H */ diff --git a/src/linux/drivers/input/mouse/elantech.h b/src/linux/drivers/input/mouse/elantech.h deleted file mode 100644 index e1cbf40..0000000 --- a/src/linux/drivers/input/mouse/elantech.h +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Elantech Touchpad driver (v6) - * - * Copyright (C) 2007-2009 Arjan Opmeer - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * - * Trademarks are the property of their respective owners. - */ - -#ifndef _ELANTECH_H -#define _ELANTECH_H - -/* - * Command values for Synaptics style queries - */ -#define ETP_FW_ID_QUERY 0x00 -#define ETP_FW_VERSION_QUERY 0x01 -#define ETP_CAPABILITIES_QUERY 0x02 -#define ETP_SAMPLE_QUERY 0x03 -#define ETP_RESOLUTION_QUERY 0x04 - -/* - * Command values for register reading or writing - */ -#define ETP_REGISTER_READ 0x10 -#define ETP_REGISTER_WRITE 0x11 -#define ETP_REGISTER_READWRITE 0x00 - -/* - * Hardware version 2 custom PS/2 command value - */ -#define ETP_PS2_CUSTOM_COMMAND 0xf8 - -/* - * Times to retry a ps2_command and millisecond delay between tries - */ -#define ETP_PS2_COMMAND_TRIES 3 -#define ETP_PS2_COMMAND_DELAY 500 - -/* - * Times to try to read back a register and millisecond delay between tries - */ -#define ETP_READ_BACK_TRIES 5 -#define ETP_READ_BACK_DELAY 2000 - -/* - * Register bitmasks for hardware version 1 - */ -#define ETP_R10_ABSOLUTE_MODE 0x04 -#define ETP_R11_4_BYTE_MODE 0x02 - -/* - * Capability bitmasks - */ -#define ETP_CAP_HAS_ROCKER 0x04 - -/* - * One hard to find application note states that X axis range is 0 to 576 - * and Y axis range is 0 to 384 for harware version 1. - * Edge fuzz might be necessary because of bezel around the touchpad - */ -#define ETP_EDGE_FUZZ_V1 32 - -#define ETP_XMIN_V1 ( 0 + ETP_EDGE_FUZZ_V1) -#define ETP_XMAX_V1 (576 - ETP_EDGE_FUZZ_V1) -#define ETP_YMIN_V1 ( 0 + ETP_EDGE_FUZZ_V1) -#define ETP_YMAX_V1 (384 - ETP_EDGE_FUZZ_V1) - -/* - * The resolution for older v2 hardware doubled. - * (newer v2's firmware provides command so we can query) - */ -#define ETP_XMIN_V2 0 -#define ETP_XMAX_V2 1152 -#define ETP_YMIN_V2 0 -#define ETP_YMAX_V2 768 - -#define ETP_PMIN_V2 0 -#define ETP_PMAX_V2 255 -#define ETP_WMIN_V2 0 -#define ETP_WMAX_V2 15 - -/* - * v3 hardware has 2 kinds of packet types, - * v4 hardware has 3. - */ -#define PACKET_UNKNOWN 0x01 -#define PACKET_DEBOUNCE 0x02 -#define PACKET_V3_HEAD 0x03 -#define PACKET_V3_TAIL 0x04 -#define PACKET_V4_HEAD 0x05 -#define PACKET_V4_MOTION 0x06 -#define PACKET_V4_STATUS 0x07 -#define PACKET_TRACKPOINT 0x08 - -/* - * track up to 5 fingers for v4 hardware - */ -#define ETP_MAX_FINGERS 5 - -/* - * weight value for v4 hardware - */ -#define ETP_WEIGHT_VALUE 5 - -/* - * The base position for one finger, v4 hardware - */ -struct finger_pos { - unsigned int x; - unsigned int y; -}; - -struct elantech_data { - struct input_dev *tp_dev; /* Relative device for trackpoint */ - char tp_phys[32]; - unsigned char reg_07; - unsigned char reg_10; - unsigned char reg_11; - unsigned char reg_20; - unsigned char reg_21; - unsigned char reg_22; - unsigned char reg_23; - unsigned char reg_24; - unsigned char reg_25; - unsigned char reg_26; - unsigned char debug; - unsigned char capabilities[3]; - unsigned char samples[3]; - bool paritycheck; - bool jumpy_cursor; - bool reports_pressure; - bool crc_enabled; - bool set_hw_resolution; - unsigned char hw_version; - unsigned int fw_version; - unsigned int single_finger_reports; - unsigned int y_max; - unsigned int width; - struct finger_pos mt[ETP_MAX_FINGERS]; - unsigned char parity[256]; - int (*send_cmd)(struct psmouse *psmouse, unsigned char c, unsigned char *param); - void (*original_set_rate)(struct psmouse *psmouse, unsigned int rate); -}; - -#ifdef CONFIG_MOUSE_PS2_ELANTECH -int elantech_detect(struct psmouse *psmouse, bool set_properties); -int elantech_init(struct psmouse *psmouse); -#else -static inline int elantech_detect(struct psmouse *psmouse, bool set_properties) -{ - return -ENOSYS; -} -static inline int elantech_init(struct psmouse *psmouse) -{ - return -ENOSYS; -} -#endif /* CONFIG_MOUSE_PS2_ELANTECH */ - -#endif diff --git a/src/linux/drivers/input/mouse/focaltech.c b/src/linux/drivers/input/mouse/focaltech.c deleted file mode 100644 index a7d3968..0000000 --- a/src/linux/drivers/input/mouse/focaltech.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - * Focaltech TouchPad PS/2 mouse driver - * - * Copyright (c) 2014 Red Hat Inc. - * Copyright (c) 2014 Mathias Gottschlag - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Red Hat authors: - * - * Hans de Goede - */ - - -#include -#include -#include -#include -#include -#include "psmouse.h" -#include "focaltech.h" - -static const char * const focaltech_pnp_ids[] = { - "FLT0101", - "FLT0102", - "FLT0103", - NULL -}; - -/* - * Even if the kernel is built without support for Focaltech PS/2 touchpads (or - * when the real driver fails to recognize the device), we still have to detect - * them in order to avoid further detection attempts confusing the touchpad. - * This way it at least works in PS/2 mouse compatibility mode. - */ -int focaltech_detect(struct psmouse *psmouse, bool set_properties) -{ - if (!psmouse_matches_pnp_id(psmouse, focaltech_pnp_ids)) - return -ENODEV; - - if (set_properties) { - psmouse->vendor = "FocalTech"; - psmouse->name = "Touchpad"; - } - - return 0; -} - -#ifdef CONFIG_MOUSE_PS2_FOCALTECH - -/* - * Packet types - the numbers are not consecutive, so we might be missing - * something here. - */ -#define FOC_TOUCH 0x3 /* bitmap of active fingers */ -#define FOC_ABS 0x6 /* absolute position of one finger */ -#define FOC_REL 0x9 /* relative position of 1-2 fingers */ - -#define FOC_MAX_FINGERS 5 - -/* - * Current state of a single finger on the touchpad. - */ -struct focaltech_finger_state { - /* The touchpad has generated a touch event for the finger */ - bool active; - - /* - * The touchpad has sent position data for the finger. The - * flag is 0 when the finger is not active, and there is a - * time between the first touch event for the finger and the - * following absolute position packet for the finger where the - * touchpad has declared the finger to be valid, but we do not - * have any valid position yet. - */ - bool valid; - - /* - * Absolute position (from the bottom left corner) of the - * finger. - */ - unsigned int x; - unsigned int y; -}; - -/* - * Description of the current state of the touchpad hardware. - */ -struct focaltech_hw_state { - /* - * The touchpad tracks the positions of the fingers for us, - * the array indices correspond to the finger indices returned - * in the report packages. - */ - struct focaltech_finger_state fingers[FOC_MAX_FINGERS]; - - /* - * Finger width 0-7 and 15 for a very big contact area. - * 15 value stays until the finger is released. - * Width is reported only in absolute packets. - * Since hardware reports width only for last touching finger, - * there is no need to store width for every specific finger, - * so we keep only last value reported. - */ - unsigned int width; - - /* True if the clickpad has been pressed. */ - bool pressed; -}; - -struct focaltech_data { - unsigned int x_max, y_max; - struct focaltech_hw_state state; -}; - -static void focaltech_report_state(struct psmouse *psmouse) -{ - struct focaltech_data *priv = psmouse->private; - struct focaltech_hw_state *state = &priv->state; - struct input_dev *dev = psmouse->dev; - int i; - - for (i = 0; i < FOC_MAX_FINGERS; i++) { - struct focaltech_finger_state *finger = &state->fingers[i]; - bool active = finger->active && finger->valid; - - input_mt_slot(dev, i); - input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); - if (active) { - unsigned int clamped_x, clamped_y; - /* - * The touchpad might report invalid data, so we clamp - * the resulting values so that we do not confuse - * userspace. - */ - clamped_x = clamp(finger->x, 0U, priv->x_max); - clamped_y = clamp(finger->y, 0U, priv->y_max); - input_report_abs(dev, ABS_MT_POSITION_X, clamped_x); - input_report_abs(dev, ABS_MT_POSITION_Y, - priv->y_max - clamped_y); - input_report_abs(dev, ABS_TOOL_WIDTH, state->width); - } - } - input_mt_report_pointer_emulation(dev, true); - - input_report_key(dev, BTN_LEFT, state->pressed); - input_sync(dev); -} - -static void focaltech_process_touch_packet(struct psmouse *psmouse, - unsigned char *packet) -{ - struct focaltech_data *priv = psmouse->private; - struct focaltech_hw_state *state = &priv->state; - unsigned char fingers = packet[1]; - int i; - - state->pressed = (packet[0] >> 4) & 1; - - /* the second byte contains a bitmap of all fingers touching the pad */ - for (i = 0; i < FOC_MAX_FINGERS; i++) { - state->fingers[i].active = fingers & 0x1; - if (!state->fingers[i].active) { - /* - * Even when the finger becomes active again, we still - * will have to wait for the first valid position. - */ - state->fingers[i].valid = false; - } - fingers >>= 1; - } -} - -static void focaltech_process_abs_packet(struct psmouse *psmouse, - unsigned char *packet) -{ - struct focaltech_data *priv = psmouse->private; - struct focaltech_hw_state *state = &priv->state; - unsigned int finger; - - finger = (packet[1] >> 4) - 1; - if (finger >= FOC_MAX_FINGERS) { - psmouse_err(psmouse, "Invalid finger in abs packet: %d\n", - finger); - return; - } - - state->pressed = (packet[0] >> 4) & 1; - - state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2]; - state->fingers[finger].y = (packet[3] << 8) | packet[4]; - state->width = packet[5] >> 4; - state->fingers[finger].valid = true; -} - -static void focaltech_process_rel_packet(struct psmouse *psmouse, - unsigned char *packet) -{ - struct focaltech_data *priv = psmouse->private; - struct focaltech_hw_state *state = &priv->state; - int finger1, finger2; - - state->pressed = packet[0] >> 7; - finger1 = ((packet[0] >> 4) & 0x7) - 1; - if (finger1 < FOC_MAX_FINGERS) { - state->fingers[finger1].x += (char)packet[1]; - state->fingers[finger1].y += (char)packet[2]; - } else { - psmouse_err(psmouse, "First finger in rel packet invalid: %d\n", - finger1); - } - - /* - * If there is an odd number of fingers, the last relative - * packet only contains one finger. In this case, the second - * finger index in the packet is 0 (we subtract 1 in the lines - * above to create array indices, so the finger will overflow - * and be above FOC_MAX_FINGERS). - */ - finger2 = ((packet[3] >> 4) & 0x7) - 1; - if (finger2 < FOC_MAX_FINGERS) { - state->fingers[finger2].x += (char)packet[4]; - state->fingers[finger2].y += (char)packet[5]; - } -} - -static void focaltech_process_packet(struct psmouse *psmouse) -{ - unsigned char *packet = psmouse->packet; - - switch (packet[0] & 0xf) { - case FOC_TOUCH: - focaltech_process_touch_packet(psmouse, packet); - break; - - case FOC_ABS: - focaltech_process_abs_packet(psmouse, packet); - break; - - case FOC_REL: - focaltech_process_rel_packet(psmouse, packet); - break; - - default: - psmouse_err(psmouse, "Unknown packet type: %02x\n", packet[0]); - break; - } - - focaltech_report_state(psmouse); -} - -static psmouse_ret_t focaltech_process_byte(struct psmouse *psmouse) -{ - if (psmouse->pktcnt >= 6) { /* Full packet received */ - focaltech_process_packet(psmouse); - return PSMOUSE_FULL_PACKET; - } - - /* - * We might want to do some validation of the data here, but - * we do not know the protocol well enough - */ - return PSMOUSE_GOOD_DATA; -} - -static int focaltech_switch_protocol(struct psmouse *psmouse) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[3]; - - param[0] = 0; - if (ps2_command(ps2dev, param, 0x10f8)) - return -EIO; - - if (ps2_command(ps2dev, param, 0x10f8)) - return -EIO; - - if (ps2_command(ps2dev, param, 0x10f8)) - return -EIO; - - param[0] = 1; - if (ps2_command(ps2dev, param, 0x10f8)) - return -EIO; - - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETSCALE11)) - return -EIO; - - if (ps2_command(ps2dev, param, PSMOUSE_CMD_ENABLE)) - return -EIO; - - return 0; -} - -static void focaltech_reset(struct psmouse *psmouse) -{ - ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); - psmouse_reset(psmouse); -} - -static void focaltech_disconnect(struct psmouse *psmouse) -{ - focaltech_reset(psmouse); - kfree(psmouse->private); - psmouse->private = NULL; -} - -static int focaltech_reconnect(struct psmouse *psmouse) -{ - int error; - - focaltech_reset(psmouse); - - error = focaltech_switch_protocol(psmouse); - if (error) { - psmouse_err(psmouse, "Unable to initialize the device\n"); - return error; - } - - return 0; -} - -static void focaltech_set_input_params(struct psmouse *psmouse) -{ - struct input_dev *dev = psmouse->dev; - struct focaltech_data *priv = psmouse->private; - - /* - * Undo part of setup done for us by psmouse core since touchpad - * is not a relative device. - */ - __clear_bit(EV_REL, dev->evbit); - __clear_bit(REL_X, dev->relbit); - __clear_bit(REL_Y, dev->relbit); - __clear_bit(BTN_RIGHT, dev->keybit); - __clear_bit(BTN_MIDDLE, dev->keybit); - - /* - * Now set up our capabilities. - */ - __set_bit(EV_ABS, dev->evbit); - input_set_abs_params(dev, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0); - input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0); - input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0); - input_mt_init_slots(dev, 5, INPUT_MT_POINTER); - __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); -} - -static int focaltech_read_register(struct ps2dev *ps2dev, int reg, - unsigned char *param) -{ - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETSCALE11)) - return -EIO; - - param[0] = 0; - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) - return -EIO; - - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) - return -EIO; - - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) - return -EIO; - - param[0] = reg; - if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES)) - return -EIO; - - if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) - return -EIO; - - return 0; -} - -static int focaltech_read_size(struct psmouse *psmouse) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - struct focaltech_data *priv = psmouse->private; - char param[3]; - - if (focaltech_read_register(ps2dev, 2, param)) - return -EIO; - - /* not sure whether this is 100% correct */ - priv->x_max = (unsigned char)param[1] * 128; - priv->y_max = (unsigned char)param[2] * 128; - - return 0; -} - -static void focaltech_set_resolution(struct psmouse *psmouse, - unsigned int resolution) -{ - /* not supported yet */ -} - -static void focaltech_set_rate(struct psmouse *psmouse, unsigned int rate) -{ - /* not supported yet */ -} - -static void focaltech_set_scale(struct psmouse *psmouse, - enum psmouse_scale scale) -{ - /* not supported yet */ -} - -int focaltech_init(struct psmouse *psmouse) -{ - struct focaltech_data *priv; - int error; - - psmouse->private = priv = kzalloc(sizeof(struct focaltech_data), - GFP_KERNEL); - if (!priv) - return -ENOMEM; - - focaltech_reset(psmouse); - - error = focaltech_read_size(psmouse); - if (error) { - psmouse_err(psmouse, - "Unable to read the size of the touchpad\n"); - goto fail; - } - - error = focaltech_switch_protocol(psmouse); - if (error) { - psmouse_err(psmouse, "Unable to initialize the device\n"); - goto fail; - } - - focaltech_set_input_params(psmouse); - - psmouse->protocol_handler = focaltech_process_byte; - psmouse->pktsize = 6; - psmouse->disconnect = focaltech_disconnect; - psmouse->reconnect = focaltech_reconnect; - psmouse->cleanup = focaltech_reset; - /* resync is not supported yet */ - psmouse->resync_time = 0; - /* - * rate/resolution/scale changes are not supported yet, and - * the generic implementations of these functions seem to - * confuse some touchpads - */ - psmouse->set_resolution = focaltech_set_resolution; - psmouse->set_rate = focaltech_set_rate; - psmouse->set_scale = focaltech_set_scale; - - return 0; - -fail: - focaltech_reset(psmouse); - kfree(priv); - return error; -} -#endif /* CONFIG_MOUSE_PS2_FOCALTECH */ diff --git a/src/linux/drivers/input/mouse/focaltech.h b/src/linux/drivers/input/mouse/focaltech.h deleted file mode 100644 index 783b28e..0000000 --- a/src/linux/drivers/input/mouse/focaltech.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Focaltech TouchPad PS/2 mouse driver - * - * Copyright (c) 2014 Red Hat Inc. - * Copyright (c) 2014 Mathias Gottschlag - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Red Hat authors: - * - * Hans de Goede - */ - -#ifndef _FOCALTECH_H -#define _FOCALTECH_H - -int focaltech_detect(struct psmouse *psmouse, bool set_properties); - -#ifdef CONFIG_MOUSE_PS2_FOCALTECH -int focaltech_init(struct psmouse *psmouse); -#else -static inline int focaltech_init(struct psmouse *psmouse) -{ - return -ENOSYS; -} -#endif - -#endif diff --git a/src/linux/drivers/input/mouse/hgpk.h b/src/linux/drivers/input/mouse/hgpk.h deleted file mode 100644 index dd68677..0000000 --- a/src/linux/drivers/input/mouse/hgpk.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * OLPC HGPK (XO-1) touchpad PS/2 mouse driver - */ - -#ifndef _HGPK_H -#define _HGPK_H - -#define HGPK_GS 0xff /* The GlideSensor */ -#define HGPK_PT 0xcf /* The PenTablet */ - -enum hgpk_model_t { - HGPK_MODEL_PREA = 0x0a, /* pre-B1s */ - HGPK_MODEL_A = 0x14, /* found on B1s, PT disabled in hardware */ - HGPK_MODEL_B = 0x28, /* B2s, has capacitance issues */ - HGPK_MODEL_C = 0x3c, - HGPK_MODEL_D = 0x50, /* C1, mass production */ -}; - -enum hgpk_spew_flag { - NO_SPEW, - MAYBE_SPEWING, - SPEW_DETECTED, - RECALIBRATING, -}; - -#define SPEW_WATCH_COUNT 42 /* at 12ms/packet, this is 1/2 second */ - -enum hgpk_mode { - HGPK_MODE_MOUSE, - HGPK_MODE_GLIDESENSOR, - HGPK_MODE_PENTABLET, - HGPK_MODE_INVALID -}; - -struct hgpk_data { - struct psmouse *psmouse; - enum hgpk_mode mode; - bool powered; - enum hgpk_spew_flag spew_flag; - int spew_count, x_tally, y_tally; /* spew detection */ - unsigned long recalib_window; - struct delayed_work recalib_wq; - int abs_x, abs_y; - int dupe_count; - int xbigj, ybigj, xlast, ylast; /* jumpiness detection */ - int xsaw_secondary, ysaw_secondary; /* jumpiness detection */ -}; - -#ifdef CONFIG_MOUSE_PS2_OLPC -void hgpk_module_init(void); -int hgpk_detect(struct psmouse *psmouse, bool set_properties); -int hgpk_init(struct psmouse *psmouse); -#else -static inline void hgpk_module_init(void) -{ -} -static inline int hgpk_detect(struct psmouse *psmouse, bool set_properties) -{ - return -ENODEV; -} -static inline int hgpk_init(struct psmouse *psmouse) -{ - return -ENODEV; -} -#endif - -#endif diff --git a/src/linux/drivers/input/mouse/lifebook.h b/src/linux/drivers/input/mouse/lifebook.h deleted file mode 100644 index 0baf02a..0000000 --- a/src/linux/drivers/input/mouse/lifebook.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Fujitsu B-series Lifebook PS/2 TouchScreen driver - * - * Copyright (c) 2005 Vojtech Pavlik - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#ifndef _LIFEBOOK_H -#define _LIFEBOOK_H - -#ifdef CONFIG_MOUSE_PS2_LIFEBOOK -void lifebook_module_init(void); -int lifebook_detect(struct psmouse *psmouse, bool set_properties); -int lifebook_init(struct psmouse *psmouse); -#else -static inline void lifebook_module_init(void) -{ -} -static inline int lifebook_detect(struct psmouse *psmouse, bool set_properties) -{ - return -ENOSYS; -} -static inline int lifebook_init(struct psmouse *psmouse) -{ - return -ENOSYS; -} -#endif - -#endif diff --git a/src/linux/drivers/input/mouse/logips2pp.c b/src/linux/drivers/input/mouse/logips2pp.c deleted file mode 100644 index 422da1c..0000000 --- a/src/linux/drivers/input/mouse/logips2pp.c +++ /dev/null @@ -1,425 +0,0 @@ -/* - * Logitech PS/2++ mouse driver - * - * Copyright (c) 1999-2003 Vojtech Pavlik - * Copyright (c) 2003 Eric Wong - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#include -#include -#include -#include "psmouse.h" -#include "logips2pp.h" - -/* Logitech mouse types */ -#define PS2PP_KIND_WHEEL 1 -#define PS2PP_KIND_MX 2 -#define PS2PP_KIND_TP3 3 -#define PS2PP_KIND_TRACKMAN 4 - -/* Logitech mouse features */ -#define PS2PP_WHEEL 0x01 -#define PS2PP_HWHEEL 0x02 -#define PS2PP_SIDE_BTN 0x04 -#define PS2PP_EXTRA_BTN 0x08 -#define PS2PP_TASK_BTN 0x10 -#define PS2PP_NAV_BTN 0x20 - -struct ps2pp_info { - u8 model; - u8 kind; - u16 features; -}; - -/* - * Process a PS2++ or PS2T++ packet. - */ - -static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse) -{ - struct input_dev *dev = psmouse->dev; - unsigned char *packet = psmouse->packet; - - if (psmouse->pktcnt < 3) - return PSMOUSE_GOOD_DATA; - -/* - * Full packet accumulated, process it - */ - - if ((packet[0] & 0x48) == 0x48 && (packet[1] & 0x02) == 0x02) { - - /* Logitech extended packet */ - switch ((packet[1] >> 4) | (packet[0] & 0x30)) { - - case 0x0d: /* Mouse extra info */ - - input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL, - (int) (packet[2] & 8) - (int) (packet[2] & 7)); - input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1); - input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1); - - break; - - case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */ - - input_report_key(dev, BTN_SIDE, (packet[2]) & 1); - input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1); - input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1); - input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1); - input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1); - - break; - - case 0x0f: /* TouchPad extra info */ - - input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL, - (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7)); - packet[0] = packet[2] | 0x08; - break; - - default: - psmouse_dbg(psmouse, - "Received PS2++ packet #%x, but don't know how to handle.\n", - (packet[1] >> 4) | (packet[0] & 0x30)); - break; - } - } else { - /* Standard PS/2 motion data */ - input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0); - input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0); - } - - input_report_key(dev, BTN_LEFT, packet[0] & 1); - input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1); - input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1); - - input_sync(dev); - - return PSMOUSE_FULL_PACKET; - -} - -/* - * ps2pp_cmd() sends a PS2++ command, sliced into two bit - * pieces through the SETRES command. This is needed to send extended - * commands to mice on notebooks that try to understand the PS/2 protocol - * Ugly. - */ - -static int ps2pp_cmd(struct psmouse *psmouse, unsigned char *param, unsigned char command) -{ - if (psmouse_sliced_command(psmouse, command)) - return -1; - - if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_POLL | 0x0300)) - return -1; - - return 0; -} - -/* - * SmartScroll / CruiseControl for some newer Logitech mice Defaults to - * enabled if we do nothing to it. Of course I put this in because I want it - * disabled :P - * 1 - enabled (if previously disabled, also default) - * 0 - disabled - */ - -static void ps2pp_set_smartscroll(struct psmouse *psmouse, bool smartscroll) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[4]; - - ps2pp_cmd(psmouse, param, 0x32); - - param[0] = 0; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); - - param[0] = smartscroll; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); -} - -static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse, - void *data, char *buf) -{ - return sprintf(buf, "%d\n", psmouse->smartscroll); -} - -static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data, - const char *buf, size_t count) -{ - unsigned int value; - int err; - - err = kstrtouint(buf, 10, &value); - if (err) - return err; - - if (value > 1) - return -EINVAL; - - ps2pp_set_smartscroll(psmouse, value); - psmouse->smartscroll = value; - return count; -} - -PSMOUSE_DEFINE_ATTR(smartscroll, S_IWUSR | S_IRUGO, NULL, - ps2pp_attr_show_smartscroll, ps2pp_attr_set_smartscroll); - -/* - * Support 800 dpi resolution _only_ if the user wants it (there are good - * reasons to not use it even if the mouse supports it, and of course there are - * also good reasons to use it, let the user decide). - */ - -static void ps2pp_set_resolution(struct psmouse *psmouse, unsigned int resolution) -{ - if (resolution > 400) { - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param = 3; - - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); - ps2_command(ps2dev, ¶m, PSMOUSE_CMD_SETRES); - psmouse->resolution = 800; - } else - psmouse_set_resolution(psmouse, resolution); -} - -static void ps2pp_disconnect(struct psmouse *psmouse) -{ - device_remove_file(&psmouse->ps2dev.serio->dev, &psmouse_attr_smartscroll.dattr); -} - -static const struct ps2pp_info *get_model_info(unsigned char model) -{ - static const struct ps2pp_info ps2pp_list[] = { - { 1, 0, 0 }, /* Simple 2-button mouse */ - { 12, 0, PS2PP_SIDE_BTN}, - { 13, 0, 0 }, - { 15, PS2PP_KIND_MX, /* MX1000 */ - PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | - PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL }, - { 40, 0, PS2PP_SIDE_BTN }, - { 41, 0, PS2PP_SIDE_BTN }, - { 42, 0, PS2PP_SIDE_BTN }, - { 43, 0, PS2PP_SIDE_BTN }, - { 50, 0, 0 }, - { 51, 0, 0 }, - { 52, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, - { 53, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, - { 56, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, /* Cordless MouseMan Wheel */ - { 61, PS2PP_KIND_MX, /* MX700 */ - PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | - PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, - { 66, PS2PP_KIND_MX, /* MX3100 receiver */ - PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | - PS2PP_EXTRA_BTN | PS2PP_NAV_BTN | PS2PP_HWHEEL }, - { 72, PS2PP_KIND_TRACKMAN, 0 }, /* T-CH11: TrackMan Marble */ - { 73, PS2PP_KIND_TRACKMAN, PS2PP_SIDE_BTN }, /* TrackMan FX */ - { 75, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, - { 76, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, - { 79, PS2PP_KIND_TRACKMAN, PS2PP_WHEEL }, /* TrackMan with wheel */ - { 80, PS2PP_KIND_WHEEL, PS2PP_SIDE_BTN | PS2PP_WHEEL }, - { 81, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, - { 83, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, - { 85, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, - { 86, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, - { 87, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, - { 88, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, - { 96, 0, 0 }, - { 97, PS2PP_KIND_TP3, PS2PP_WHEEL | PS2PP_HWHEEL }, - { 99, PS2PP_KIND_WHEEL, PS2PP_WHEEL }, - { 100, PS2PP_KIND_MX, /* MX510 */ - PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | - PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, - { 111, PS2PP_KIND_MX, PS2PP_WHEEL | PS2PP_SIDE_BTN }, /* MX300 reports task button as side */ - { 112, PS2PP_KIND_MX, /* MX500 */ - PS2PP_WHEEL | PS2PP_SIDE_BTN | PS2PP_TASK_BTN | - PS2PP_EXTRA_BTN | PS2PP_NAV_BTN }, - { 114, PS2PP_KIND_MX, /* MX310 */ - PS2PP_WHEEL | PS2PP_SIDE_BTN | - PS2PP_TASK_BTN | PS2PP_EXTRA_BTN } - }; - int i; - - for (i = 0; i < ARRAY_SIZE(ps2pp_list); i++) - if (model == ps2pp_list[i].model) - return &ps2pp_list[i]; - - return NULL; -} - -/* - * Set up input device's properties based on the detected mouse model. - */ - -static void ps2pp_set_model_properties(struct psmouse *psmouse, - const struct ps2pp_info *model_info, - bool using_ps2pp) -{ - struct input_dev *input_dev = psmouse->dev; - - if (model_info->features & PS2PP_SIDE_BTN) - __set_bit(BTN_SIDE, input_dev->keybit); - - if (model_info->features & PS2PP_EXTRA_BTN) - __set_bit(BTN_EXTRA, input_dev->keybit); - - if (model_info->features & PS2PP_TASK_BTN) - __set_bit(BTN_TASK, input_dev->keybit); - - if (model_info->features & PS2PP_NAV_BTN) { - __set_bit(BTN_FORWARD, input_dev->keybit); - __set_bit(BTN_BACK, input_dev->keybit); - } - - if (model_info->features & PS2PP_WHEEL) - __set_bit(REL_WHEEL, input_dev->relbit); - - if (model_info->features & PS2PP_HWHEEL) - __set_bit(REL_HWHEEL, input_dev->relbit); - - switch (model_info->kind) { - - case PS2PP_KIND_WHEEL: - psmouse->name = "Wheel Mouse"; - break; - - case PS2PP_KIND_MX: - psmouse->name = "MX Mouse"; - break; - - case PS2PP_KIND_TP3: - psmouse->name = "TouchPad 3"; - break; - - case PS2PP_KIND_TRACKMAN: - psmouse->name = "TrackMan"; - break; - - default: - /* - * Set name to "Mouse" only when using PS2++, - * otherwise let other protocols define suitable - * name - */ - if (using_ps2pp) - psmouse->name = "Mouse"; - break; - } -} - - -/* - * Logitech magic init. Detect whether the mouse is a Logitech one - * and its exact model and try turning on extended protocol for ones - * that support it. - */ - -int ps2pp_detect(struct psmouse *psmouse, bool set_properties) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[4]; - unsigned char model, buttons; - const struct ps2pp_info *model_info; - bool use_ps2pp = false; - int error; - - param[0] = 0; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); - param[1] = 0; - ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO); - - model = ((param[0] >> 4) & 0x07) | ((param[0] << 3) & 0x78); - buttons = param[1]; - - if (!model || !buttons) - return -1; - - model_info = get_model_info(model); - if (model_info) { - -/* - * Do Logitech PS2++ / PS2T++ magic init. - */ - if (model_info->kind == PS2PP_KIND_TP3) { /* Touch Pad 3 */ - - /* Unprotect RAM */ - param[0] = 0x11; param[1] = 0x04; param[2] = 0x68; - ps2_command(ps2dev, param, 0x30d1); - /* Enable features */ - param[0] = 0x11; param[1] = 0x05; param[2] = 0x0b; - ps2_command(ps2dev, param, 0x30d1); - /* Enable PS2++ */ - param[0] = 0x11; param[1] = 0x09; param[2] = 0xc3; - ps2_command(ps2dev, param, 0x30d1); - - param[0] = 0; - if (!ps2_command(ps2dev, param, 0x13d1) && - param[0] == 0x06 && param[1] == 0x00 && param[2] == 0x14) { - use_ps2pp = true; - } - - } else { - - param[0] = param[1] = param[2] = 0; - ps2pp_cmd(psmouse, param, 0x39); /* Magic knock */ - ps2pp_cmd(psmouse, param, 0xDB); - - if ((param[0] & 0x78) == 0x48 && - (param[1] & 0xf3) == 0xc2 && - (param[2] & 0x03) == ((param[1] >> 2) & 3)) { - ps2pp_set_smartscroll(psmouse, false); - use_ps2pp = true; - } - } - - } else { - psmouse_warn(psmouse, "Detected unknown Logitech mouse model %d\n", model); - } - - if (set_properties) { - psmouse->vendor = "Logitech"; - psmouse->model = model; - - if (use_ps2pp) { - psmouse->protocol_handler = ps2pp_process_byte; - psmouse->pktsize = 3; - - if (model_info->kind != PS2PP_KIND_TP3) { - psmouse->set_resolution = ps2pp_set_resolution; - psmouse->disconnect = ps2pp_disconnect; - - error = device_create_file(&psmouse->ps2dev.serio->dev, - &psmouse_attr_smartscroll.dattr); - if (error) { - psmouse_err(psmouse, - "failed to create smartscroll sysfs attribute, error: %d\n", - error); - return -1; - } - } - } - - if (buttons >= 3) - __set_bit(BTN_MIDDLE, psmouse->dev->keybit); - - if (model_info) - ps2pp_set_model_properties(psmouse, model_info, use_ps2pp); - } - - return use_ps2pp ? 0 : -1; -} - diff --git a/src/linux/drivers/input/mouse/logips2pp.h b/src/linux/drivers/input/mouse/logips2pp.h deleted file mode 100644 index bf62945..0000000 --- a/src/linux/drivers/input/mouse/logips2pp.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Logitech PS/2++ mouse driver header - * - * Copyright (c) 2003 Vojtech Pavlik - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#ifndef _LOGIPS2PP_H -#define _LOGIPS2PP_H - -#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP -int ps2pp_detect(struct psmouse *psmouse, bool set_properties); -#else -static inline int ps2pp_detect(struct psmouse *psmouse, bool set_properties) -{ - return -ENOSYS; -} -#endif /* CONFIG_MOUSE_PS2_LOGIPS2PP */ - -#endif diff --git a/src/linux/drivers/input/mouse/psmouse-base.c b/src/linux/drivers/input/mouse/psmouse-base.c deleted file mode 100644 index bee2674..0000000 --- a/src/linux/drivers/input/mouse/psmouse-base.c +++ /dev/null @@ -1,1935 +0,0 @@ -/* - * PS/2 mouse driver - * - * Copyright (c) 1999-2002 Vojtech Pavlik - * Copyright (c) 2003-2004 Dmitry Torokhov - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#define psmouse_fmt(fmt) fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "psmouse.h" -#include "synaptics.h" -#include "logips2pp.h" -#include "alps.h" -#include "hgpk.h" -#include "lifebook.h" -#include "trackpoint.h" -#include "touchkit_ps2.h" -#include "elantech.h" -#include "sentelic.h" -#include "cypress_ps2.h" -#include "focaltech.h" -#include "vmmouse.h" -#include "byd.h" - -#define DRIVER_DESC "PS/2 mouse driver" - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -static unsigned int psmouse_max_proto = PSMOUSE_AUTO; -static int psmouse_set_maxproto(const char *val, const struct kernel_param *); -static int psmouse_get_maxproto(char *buffer, const struct kernel_param *kp); -static const struct kernel_param_ops param_ops_proto_abbrev = { - .set = psmouse_set_maxproto, - .get = psmouse_get_maxproto, -}; -#define param_check_proto_abbrev(name, p) __param_check(name, p, unsigned int) -module_param_named(proto, psmouse_max_proto, proto_abbrev, 0644); -MODULE_PARM_DESC(proto, "Highest protocol extension to probe (bare, imps, exps, any). Useful for KVM switches."); - -static unsigned int psmouse_resolution = 200; -module_param_named(resolution, psmouse_resolution, uint, 0644); -MODULE_PARM_DESC(resolution, "Resolution, in dpi."); - -static unsigned int psmouse_rate = 100; -module_param_named(rate, psmouse_rate, uint, 0644); -MODULE_PARM_DESC(rate, "Report rate, in reports per second."); - -static bool psmouse_smartscroll = true; -module_param_named(smartscroll, psmouse_smartscroll, bool, 0644); -MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled."); - -static unsigned int psmouse_resetafter = 5; -module_param_named(resetafter, psmouse_resetafter, uint, 0644); -MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never)."); - -static unsigned int psmouse_resync_time; -module_param_named(resync_time, psmouse_resync_time, uint, 0644); -MODULE_PARM_DESC(resync_time, "How long can mouse stay idle before forcing resync (in seconds, 0 = never)."); - -PSMOUSE_DEFINE_ATTR(protocol, S_IWUSR | S_IRUGO, - NULL, - psmouse_attr_show_protocol, psmouse_attr_set_protocol); -PSMOUSE_DEFINE_ATTR(rate, S_IWUSR | S_IRUGO, - (void *) offsetof(struct psmouse, rate), - psmouse_show_int_attr, psmouse_attr_set_rate); -PSMOUSE_DEFINE_ATTR(resolution, S_IWUSR | S_IRUGO, - (void *) offsetof(struct psmouse, resolution), - psmouse_show_int_attr, psmouse_attr_set_resolution); -PSMOUSE_DEFINE_ATTR(resetafter, S_IWUSR | S_IRUGO, - (void *) offsetof(struct psmouse, resetafter), - psmouse_show_int_attr, psmouse_set_int_attr); -PSMOUSE_DEFINE_ATTR(resync_time, S_IWUSR | S_IRUGO, - (void *) offsetof(struct psmouse, resync_time), - psmouse_show_int_attr, psmouse_set_int_attr); - -static struct attribute *psmouse_attributes[] = { - &psmouse_attr_protocol.dattr.attr, - &psmouse_attr_rate.dattr.attr, - &psmouse_attr_resolution.dattr.attr, - &psmouse_attr_resetafter.dattr.attr, - &psmouse_attr_resync_time.dattr.attr, - NULL -}; - -static struct attribute_group psmouse_attribute_group = { - .attrs = psmouse_attributes, -}; - -/* - * psmouse_mutex protects all operations changing state of mouse - * (connecting, disconnecting, changing rate or resolution via - * sysfs). We could use a per-device semaphore but since there - * rarely more than one PS/2 mouse connected and since semaphore - * is taken in "slow" paths it is not worth it. - */ -static DEFINE_MUTEX(psmouse_mutex); - -static struct workqueue_struct *kpsmoused_wq; - -struct psmouse_protocol { - enum psmouse_type type; - bool maxproto; - bool ignore_parity; /* Protocol should ignore parity errors from KBC */ - bool try_passthru; /* Try protocol also on passthrough ports */ - const char *name; - const char *alias; - int (*detect)(struct psmouse *, bool); - int (*init)(struct psmouse *); -}; - -/* - * psmouse_process_byte() analyzes the PS/2 data stream and reports - * relevant events to the input module once full packet has arrived. - */ -psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) -{ - struct input_dev *dev = psmouse->dev; - unsigned char *packet = psmouse->packet; - - if (psmouse->pktcnt < psmouse->pktsize) - return PSMOUSE_GOOD_DATA; - - /* Full packet accumulated, process it */ - - switch (psmouse->type) { - case PSMOUSE_IMPS: - /* IntelliMouse has scroll wheel */ - input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]); - break; - - case PSMOUSE_IMEX: - /* Scroll wheel and buttons on IntelliMouse Explorer */ - switch (packet[3] & 0xC0) { - case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */ - input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31)); - break; - case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */ - input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31)); - break; - case 0x00: - case 0xC0: - input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7)); - input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1); - input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1); - break; - } - break; - - case PSMOUSE_GENPS: - /* Report scroll buttons on NetMice */ - input_report_rel(dev, REL_WHEEL, -(signed char) packet[3]); - - /* Extra buttons on Genius NewNet 3D */ - input_report_key(dev, BTN_SIDE, (packet[0] >> 6) & 1); - input_report_key(dev, BTN_EXTRA, (packet[0] >> 7) & 1); - break; - - case PSMOUSE_THINKPS: - /* Extra button on ThinkingMouse */ - input_report_key(dev, BTN_EXTRA, (packet[0] >> 3) & 1); - - /* - * Without this bit of weirdness moving up gives wildly - * high Y changes. - */ - packet[1] |= (packet[0] & 0x40) << 1; - break; - - case PSMOUSE_CORTRON: - /* - * Cortron PS2 Trackball reports SIDE button in the - * 4th bit of the first byte. - */ - input_report_key(dev, BTN_SIDE, (packet[0] >> 3) & 1); - packet[0] |= 0x08; - break; - - default: - break; - } - - /* Generic PS/2 Mouse */ - input_report_key(dev, BTN_LEFT, packet[0] & 1); - input_report_key(dev, BTN_MIDDLE, (packet[0] >> 2) & 1); - input_report_key(dev, BTN_RIGHT, (packet[0] >> 1) & 1); - - input_report_rel(dev, REL_X, packet[1] ? (int) packet[1] - (int) ((packet[0] << 4) & 0x100) : 0); - input_report_rel(dev, REL_Y, packet[2] ? (int) ((packet[0] << 3) & 0x100) - (int) packet[2] : 0); - - input_sync(dev); - - return PSMOUSE_FULL_PACKET; -} - -void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work, - unsigned long delay) -{ - queue_delayed_work(kpsmoused_wq, work, delay); -} - -/* - * __psmouse_set_state() sets new psmouse state and resets all flags. - */ -static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) -{ - psmouse->state = new_state; - psmouse->pktcnt = psmouse->out_of_sync_cnt = 0; - psmouse->ps2dev.flags = 0; - psmouse->last = jiffies; -} - -/* - * psmouse_set_state() sets new psmouse state and resets all flags and - * counters while holding serio lock so fighting with interrupt handler - * is not a concern. - */ -void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) -{ - serio_pause_rx(psmouse->ps2dev.serio); - __psmouse_set_state(psmouse, new_state); - serio_continue_rx(psmouse->ps2dev.serio); -} - -/* - * psmouse_handle_byte() processes one byte of the input data stream - * by calling corresponding protocol handler. - */ -static int psmouse_handle_byte(struct psmouse *psmouse) -{ - psmouse_ret_t rc = psmouse->protocol_handler(psmouse); - - switch (rc) { - case PSMOUSE_BAD_DATA: - if (psmouse->state == PSMOUSE_ACTIVATED) { - psmouse_warn(psmouse, - "%s at %s lost sync at byte %d\n", - psmouse->name, psmouse->phys, - psmouse->pktcnt); - if (++psmouse->out_of_sync_cnt == psmouse->resetafter) { - __psmouse_set_state(psmouse, PSMOUSE_IGNORE); - psmouse_notice(psmouse, - "issuing reconnect request\n"); - serio_reconnect(psmouse->ps2dev.serio); - return -1; - } - } - psmouse->pktcnt = 0; - break; - - case PSMOUSE_FULL_PACKET: - psmouse->pktcnt = 0; - if (psmouse->out_of_sync_cnt) { - psmouse->out_of_sync_cnt = 0; - psmouse_notice(psmouse, - "%s at %s - driver resynced.\n", - psmouse->name, psmouse->phys); - } - break; - - case PSMOUSE_GOOD_DATA: - break; - } - return 0; -} - -/* - * psmouse_interrupt() handles incoming characters, either passing them - * for normal processing or gathering them as command response. - */ -static irqreturn_t psmouse_interrupt(struct serio *serio, - unsigned char data, unsigned int flags) -{ - struct psmouse *psmouse = serio_get_drvdata(serio); - - if (psmouse->state == PSMOUSE_IGNORE) - goto out; - - if (unlikely((flags & SERIO_TIMEOUT) || - ((flags & SERIO_PARITY) && !psmouse->ignore_parity))) { - - if (psmouse->state == PSMOUSE_ACTIVATED) - psmouse_warn(psmouse, - "bad data from KBC -%s%s\n", - flags & SERIO_TIMEOUT ? " timeout" : "", - flags & SERIO_PARITY ? " bad parity" : ""); - ps2_cmd_aborted(&psmouse->ps2dev); - goto out; - } - - if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_ACK)) - if (ps2_handle_ack(&psmouse->ps2dev, data)) - goto out; - - if (unlikely(psmouse->ps2dev.flags & PS2_FLAG_CMD)) - if (ps2_handle_response(&psmouse->ps2dev, data)) - goto out; - - if (psmouse->state <= PSMOUSE_RESYNCING) - goto out; - - if (psmouse->state == PSMOUSE_ACTIVATED && - psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) { - psmouse_info(psmouse, "%s at %s lost synchronization, throwing %d bytes away.\n", - psmouse->name, psmouse->phys, psmouse->pktcnt); - psmouse->badbyte = psmouse->packet[0]; - __psmouse_set_state(psmouse, PSMOUSE_RESYNCING); - psmouse_queue_work(psmouse, &psmouse->resync_work, 0); - goto out; - } - - psmouse->packet[psmouse->pktcnt++] = data; - - /* Check if this is a new device announcement (0xAA 0x00) */ - if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) { - if (psmouse->pktcnt == 1) { - psmouse->last = jiffies; - goto out; - } - - if (psmouse->packet[1] == PSMOUSE_RET_ID || - (psmouse->type == PSMOUSE_HGPK && - psmouse->packet[1] == PSMOUSE_RET_BAT)) { - __psmouse_set_state(psmouse, PSMOUSE_IGNORE); - serio_reconnect(serio); - goto out; - } - - /* Not a new device, try processing first byte normally */ - psmouse->pktcnt = 1; - if (psmouse_handle_byte(psmouse)) - goto out; - - psmouse->packet[psmouse->pktcnt++] = data; - } - - /* - * See if we need to force resync because mouse was idle for - * too long. - */ - if (psmouse->state == PSMOUSE_ACTIVATED && - psmouse->pktcnt == 1 && psmouse->resync_time && - time_after(jiffies, psmouse->last + psmouse->resync_time * HZ)) { - psmouse->badbyte = psmouse->packet[0]; - __psmouse_set_state(psmouse, PSMOUSE_RESYNCING); - psmouse_queue_work(psmouse, &psmouse->resync_work, 0); - goto out; - } - - psmouse->last = jiffies; - psmouse_handle_byte(psmouse); - - out: - return IRQ_HANDLED; -} - -/* - * psmouse_sliced_command() sends an extended PS/2 command to the mouse - * using sliced syntax, understood by advanced devices, such as Logitech - * or Synaptics touchpads. The command is encoded as: - * 0xE6 0xE8 rr 0xE8 ss 0xE8 tt 0xE8 uu where (rr*64)+(ss*16)+(tt*4)+uu - * is the command. - */ -int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command) -{ - int i; - - if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11)) - return -1; - - for (i = 6; i >= 0; i -= 2) { - unsigned char d = (command >> i) & 3; - if (ps2_command(&psmouse->ps2dev, &d, PSMOUSE_CMD_SETRES)) - return -1; - } - - return 0; -} - -/* - * psmouse_reset() resets the mouse into power-on state. - */ -int psmouse_reset(struct psmouse *psmouse) -{ - unsigned char param[2]; - - if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_RESET_BAT)) - return -1; - - if (param[0] != PSMOUSE_RET_BAT && param[1] != PSMOUSE_RET_ID) - return -1; - - return 0; -} - -/* - * Here we set the mouse resolution. - */ -void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution) -{ - static const unsigned char params[] = { 0, 1, 2, 2, 3 }; - unsigned char p; - - if (resolution == 0 || resolution > 200) - resolution = 200; - - p = params[resolution / 50]; - ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES); - psmouse->resolution = 25 << p; -} - -/* - * Here we set the mouse report rate. - */ -static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate) -{ - static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 }; - unsigned char r; - int i = 0; - - while (rates[i] > rate) i++; - r = rates[i]; - ps2_command(&psmouse->ps2dev, &r, PSMOUSE_CMD_SETRATE); - psmouse->rate = r; -} - -/* - * Here we set the mouse scaling. - */ -static void psmouse_set_scale(struct psmouse *psmouse, enum psmouse_scale scale) -{ - ps2_command(&psmouse->ps2dev, NULL, - scale == PSMOUSE_SCALE21 ? PSMOUSE_CMD_SETSCALE21 : - PSMOUSE_CMD_SETSCALE11); -} - -/* - * psmouse_poll() - default poll handler. Everyone except for ALPS uses it. - */ -static int psmouse_poll(struct psmouse *psmouse) -{ - return ps2_command(&psmouse->ps2dev, psmouse->packet, - PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)); -} - -static bool psmouse_check_pnp_id(const char *id, const char * const ids[]) -{ - int i; - - for (i = 0; ids[i]; i++) - if (!strcasecmp(id, ids[i])) - return true; - - return false; -} - -/* - * psmouse_matches_pnp_id - check if psmouse matches one of the passed in ids. - */ -bool psmouse_matches_pnp_id(struct psmouse *psmouse, const char * const ids[]) -{ - struct serio *serio = psmouse->ps2dev.serio; - char *p, *fw_id_copy, *save_ptr; - bool found = false; - - if (strncmp(serio->firmware_id, "PNP: ", 5)) - return false; - - fw_id_copy = kstrndup(&serio->firmware_id[5], - sizeof(serio->firmware_id) - 5, - GFP_KERNEL); - if (!fw_id_copy) - return false; - - save_ptr = fw_id_copy; - while ((p = strsep(&fw_id_copy, " ")) != NULL) { - if (psmouse_check_pnp_id(p, ids)) { - found = true; - break; - } - } - - kfree(save_ptr); - return found; -} - -/* - * Genius NetMouse magic init. - */ -static int genius_detect(struct psmouse *psmouse, bool set_properties) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[4]; - - param[0] = 3; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); - ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11); - ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO); - - if (param[0] != 0x00 || param[1] != 0x33 || param[2] != 0x55) - return -1; - - if (set_properties) { - __set_bit(BTN_MIDDLE, psmouse->dev->keybit); - __set_bit(BTN_EXTRA, psmouse->dev->keybit); - __set_bit(BTN_SIDE, psmouse->dev->keybit); - __set_bit(REL_WHEEL, psmouse->dev->relbit); - - psmouse->vendor = "Genius"; - psmouse->name = "Mouse"; - psmouse->pktsize = 4; - } - - return 0; -} - -/* - * IntelliMouse magic init. - */ -static int intellimouse_detect(struct psmouse *psmouse, bool set_properties) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[2]; - - param[0] = 200; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); - param[0] = 100; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); - param[0] = 80; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); - ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); - - if (param[0] != 3) - return -1; - - if (set_properties) { - __set_bit(BTN_MIDDLE, psmouse->dev->keybit); - __set_bit(REL_WHEEL, psmouse->dev->relbit); - - if (!psmouse->vendor) - psmouse->vendor = "Generic"; - if (!psmouse->name) - psmouse->name = "Wheel Mouse"; - psmouse->pktsize = 4; - } - - return 0; -} - -/* - * Try IntelliMouse/Explorer magic init. - */ -static int im_explorer_detect(struct psmouse *psmouse, bool set_properties) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[2]; - - intellimouse_detect(psmouse, 0); - - param[0] = 200; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); - param[0] = 200; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); - param[0] = 80; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); - ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); - - if (param[0] != 4) - return -1; - - /* Magic to enable horizontal scrolling on IntelliMouse 4.0 */ - param[0] = 200; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); - param[0] = 80; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); - param[0] = 40; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); - - if (set_properties) { - __set_bit(BTN_MIDDLE, psmouse->dev->keybit); - __set_bit(REL_WHEEL, psmouse->dev->relbit); - __set_bit(REL_HWHEEL, psmouse->dev->relbit); - __set_bit(BTN_SIDE, psmouse->dev->keybit); - __set_bit(BTN_EXTRA, psmouse->dev->keybit); - - if (!psmouse->vendor) - psmouse->vendor = "Generic"; - if (!psmouse->name) - psmouse->name = "Explorer Mouse"; - psmouse->pktsize = 4; - } - - return 0; -} - -/* - * Kensington ThinkingMouse / ExpertMouse magic init. - */ -static int thinking_detect(struct psmouse *psmouse, bool set_properties) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[2]; - static const unsigned char seq[] = { 20, 60, 40, 20, 20, 60, 40, 20, 20 }; - int i; - - param[0] = 10; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); - param[0] = 0; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); - for (i = 0; i < ARRAY_SIZE(seq); i++) { - param[0] = seq[i]; - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); - } - ps2_command(ps2dev, param, PSMOUSE_CMD_GETID); - - if (param[0] != 2) - return -1; - - if (set_properties) { - __set_bit(BTN_MIDDLE, psmouse->dev->keybit); - __set_bit(BTN_EXTRA, psmouse->dev->keybit); - - psmouse->vendor = "Kensington"; - psmouse->name = "ThinkingMouse"; - } - - return 0; -} - -/* - * Bare PS/2 protocol "detection". Always succeeds. - */ -static int ps2bare_detect(struct psmouse *psmouse, bool set_properties) -{ - if (set_properties) { - if (!psmouse->vendor) - psmouse->vendor = "Generic"; - if (!psmouse->name) - psmouse->name = "Mouse"; - - /* - * We have no way of figuring true number of buttons so let's - * assume that the device has 3. - */ - __set_bit(BTN_MIDDLE, psmouse->dev->keybit); - } - - return 0; -} - -/* - * Cortron PS/2 protocol detection. There's no special way to detect it, so it - * must be forced by sysfs protocol writing. - */ -static int cortron_detect(struct psmouse *psmouse, bool set_properties) -{ - if (set_properties) { - psmouse->vendor = "Cortron"; - psmouse->name = "PS/2 Trackball"; - - __set_bit(BTN_MIDDLE, psmouse->dev->keybit); - __set_bit(BTN_SIDE, psmouse->dev->keybit); - } - - return 0; -} - -static const struct psmouse_protocol psmouse_protocols[] = { - { - .type = PSMOUSE_PS2, - .name = "PS/2", - .alias = "bare", - .maxproto = true, - .ignore_parity = true, - .detect = ps2bare_detect, - .try_passthru = true, - }, -#ifdef CONFIG_MOUSE_PS2_LOGIPS2PP - { - .type = PSMOUSE_PS2PP, - .name = "PS2++", - .alias = "logitech", - .detect = ps2pp_detect, - }, -#endif - { - .type = PSMOUSE_THINKPS, - .name = "ThinkPS/2", - .alias = "thinkps", - .detect = thinking_detect, - }, -#ifdef CONFIG_MOUSE_PS2_CYPRESS - { - .type = PSMOUSE_CYPRESS, - .name = "CyPS/2", - .alias = "cypress", - .detect = cypress_detect, - .init = cypress_init, - }, -#endif - { - .type = PSMOUSE_GENPS, - .name = "GenPS/2", - .alias = "genius", - .detect = genius_detect, - }, - { - .type = PSMOUSE_IMPS, - .name = "ImPS/2", - .alias = "imps", - .maxproto = true, - .ignore_parity = true, - .detect = intellimouse_detect, - .try_passthru = true, - }, - { - .type = PSMOUSE_IMEX, - .name = "ImExPS/2", - .alias = "exps", - .maxproto = true, - .ignore_parity = true, - .detect = im_explorer_detect, - .try_passthru = true, - }, -#ifdef CONFIG_MOUSE_PS2_SYNAPTICS - { - .type = PSMOUSE_SYNAPTICS, - .name = "SynPS/2", - .alias = "synaptics", - .detect = synaptics_detect, - .init = synaptics_init, - }, - { - .type = PSMOUSE_SYNAPTICS_RELATIVE, - .name = "SynRelPS/2", - .alias = "synaptics-relative", - .detect = synaptics_detect, - .init = synaptics_init_relative, - }, -#endif -#ifdef CONFIG_MOUSE_PS2_ALPS - { - .type = PSMOUSE_ALPS, - .name = "AlpsPS/2", - .alias = "alps", - .detect = alps_detect, - .init = alps_init, - }, -#endif -#ifdef CONFIG_MOUSE_PS2_LIFEBOOK - { - .type = PSMOUSE_LIFEBOOK, - .name = "LBPS/2", - .alias = "lifebook", - .detect = lifebook_detect, - .init = lifebook_init, - }, -#endif -#ifdef CONFIG_MOUSE_PS2_TRACKPOINT - { - .type = PSMOUSE_TRACKPOINT, - .name = "TPPS/2", - .alias = "trackpoint", - .detect = trackpoint_detect, - .try_passthru = true, - }, -#endif -#ifdef CONFIG_MOUSE_PS2_TOUCHKIT - { - .type = PSMOUSE_TOUCHKIT_PS2, - .name = "touchkitPS/2", - .alias = "touchkit", - .detect = touchkit_ps2_detect, - }, -#endif -#ifdef CONFIG_MOUSE_PS2_OLPC - { - .type = PSMOUSE_HGPK, - .name = "OLPC HGPK", - .alias = "hgpk", - .detect = hgpk_detect, - }, -#endif -#ifdef CONFIG_MOUSE_PS2_ELANTECH - { - .type = PSMOUSE_ELANTECH, - .name = "ETPS/2", - .alias = "elantech", - .detect = elantech_detect, - .init = elantech_init, - }, -#endif -#ifdef CONFIG_MOUSE_PS2_SENTELIC - { - .type = PSMOUSE_FSP, - .name = "FSPPS/2", - .alias = "fsp", - .detect = fsp_detect, - .init = fsp_init, - }, -#endif - { - .type = PSMOUSE_CORTRON, - .name = "CortronPS/2", - .alias = "cortps", - .detect = cortron_detect, - }, -#ifdef CONFIG_MOUSE_PS2_FOCALTECH - { - .type = PSMOUSE_FOCALTECH, - .name = "FocalTechPS/2", - .alias = "focaltech", - .detect = focaltech_detect, - .init = focaltech_init, - }, -#endif -#ifdef CONFIG_MOUSE_PS2_VMMOUSE - { - .type = PSMOUSE_VMMOUSE, - .name = VMMOUSE_PSNAME, - .alias = "vmmouse", - .detect = vmmouse_detect, - .init = vmmouse_init, - }, -#endif -#ifdef CONFIG_MOUSE_PS2_BYD - { - .type = PSMOUSE_BYD, - .name = "BYDPS/2", - .alias = "byd", - .detect = byd_detect, - .init = byd_init, - }, -#endif - { - .type = PSMOUSE_AUTO, - .name = "auto", - .alias = "any", - .maxproto = true, - }, -}; - -static const struct psmouse_protocol *__psmouse_protocol_by_type(enum psmouse_type type) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) - if (psmouse_protocols[i].type == type) - return &psmouse_protocols[i]; - - return NULL; -} - -static const struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type) -{ - const struct psmouse_protocol *proto; - - proto = __psmouse_protocol_by_type(type); - if (proto) - return proto; - - WARN_ON(1); - return &psmouse_protocols[0]; -} - -static const struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len) -{ - const struct psmouse_protocol *p; - int i; - - for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) { - p = &psmouse_protocols[i]; - - if ((strlen(p->name) == len && !strncmp(p->name, name, len)) || - (strlen(p->alias) == len && !strncmp(p->alias, name, len))) - return &psmouse_protocols[i]; - } - - return NULL; -} - -/* - * Apply default settings to the psmouse structure. Most of them will - * be overridden by individual protocol initialization routines. - */ -static void psmouse_apply_defaults(struct psmouse *psmouse) -{ - struct input_dev *input_dev = psmouse->dev; - - memset(input_dev->evbit, 0, sizeof(input_dev->evbit)); - memset(input_dev->keybit, 0, sizeof(input_dev->keybit)); - memset(input_dev->relbit, 0, sizeof(input_dev->relbit)); - memset(input_dev->absbit, 0, sizeof(input_dev->absbit)); - memset(input_dev->mscbit, 0, sizeof(input_dev->mscbit)); - - __set_bit(EV_KEY, input_dev->evbit); - __set_bit(EV_REL, input_dev->evbit); - - __set_bit(BTN_LEFT, input_dev->keybit); - __set_bit(BTN_RIGHT, input_dev->keybit); - - __set_bit(REL_X, input_dev->relbit); - __set_bit(REL_Y, input_dev->relbit); - - __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - - psmouse->set_rate = psmouse_set_rate; - psmouse->set_resolution = psmouse_set_resolution; - psmouse->set_scale = psmouse_set_scale; - psmouse->poll = psmouse_poll; - psmouse->protocol_handler = psmouse_process_byte; - psmouse->pktsize = 3; - psmouse->reconnect = NULL; - psmouse->disconnect = NULL; - psmouse->cleanup = NULL; - psmouse->pt_activate = NULL; - psmouse->pt_deactivate = NULL; -} - -static bool psmouse_try_protocol(struct psmouse *psmouse, - enum psmouse_type type, - unsigned int *max_proto, - bool set_properties, bool init_allowed) -{ - const struct psmouse_protocol *proto; - - proto = __psmouse_protocol_by_type(type); - if (!proto) - return false; - - if (psmouse->ps2dev.serio->id.type == SERIO_PS_PSTHRU && - !proto->try_passthru) { - return false; - } - - if (set_properties) - psmouse_apply_defaults(psmouse); - - if (proto->detect(psmouse, set_properties) != 0) - return false; - - if (set_properties && proto->init && init_allowed) { - if (proto->init(psmouse) != 0) { - /* - * We detected device, but init failed. Adjust - * max_proto so we only try standard protocols. - */ - if (*max_proto > PSMOUSE_IMEX) - *max_proto = PSMOUSE_IMEX; - - return false; - } - } - - return true; -} - -/* - * psmouse_extensions() probes for any extensions to the basic PS/2 protocol - * the mouse may have. - */ -static int psmouse_extensions(struct psmouse *psmouse, - unsigned int max_proto, bool set_properties) -{ - bool synaptics_hardware = false; - - /* - * Always check for focaltech, this is safe as it uses pnp-id - * matching. - */ - if (psmouse_try_protocol(psmouse, PSMOUSE_FOCALTECH, - &max_proto, set_properties, false)) { - if (max_proto > PSMOUSE_IMEX && - IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH) && - (!set_properties || focaltech_init(psmouse) == 0)) { - return PSMOUSE_FOCALTECH; - } - /* - * Restrict psmouse_max_proto so that psmouse_initialize() - * does not try to reset rate and resolution, because even - * that upsets the device. - * This also causes us to basically fall through to basic - * protocol detection, where we fully reset the mouse, - * and set it up as bare PS/2 protocol device. - */ - psmouse_max_proto = max_proto = PSMOUSE_PS2; - } - - /* - * We always check for LifeBook because it does not disturb mouse - * (it only checks DMI information). - */ - if (psmouse_try_protocol(psmouse, PSMOUSE_LIFEBOOK, &max_proto, - set_properties, max_proto > PSMOUSE_IMEX)) - return PSMOUSE_LIFEBOOK; - - if (psmouse_try_protocol(psmouse, PSMOUSE_VMMOUSE, &max_proto, - set_properties, max_proto > PSMOUSE_IMEX)) - return PSMOUSE_VMMOUSE; - - /* - * Try Kensington ThinkingMouse (we try first, because Synaptics - * probe upsets the ThinkingMouse). - */ - if (max_proto > PSMOUSE_IMEX && - psmouse_try_protocol(psmouse, PSMOUSE_THINKPS, &max_proto, - set_properties, true)) { - return PSMOUSE_THINKPS; - } - - /* - * Try Synaptics TouchPad. Note that probing is done even if - * Synaptics protocol support is disabled in config - we need to - * know if it is Synaptics so we can reset it properly after - * probing for IntelliMouse. - */ - if (max_proto > PSMOUSE_PS2 && - psmouse_try_protocol(psmouse, PSMOUSE_SYNAPTICS, &max_proto, - set_properties, false)) { - synaptics_hardware = true; - - if (max_proto > PSMOUSE_IMEX) { - /* - * Try activating protocol, but check if support is - * enabled first, since we try detecting Synaptics - * even when protocol is disabled. - */ - if (IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS) && - (!set_properties || synaptics_init(psmouse) == 0)) { - return PSMOUSE_SYNAPTICS; - } - - /* - * Some Synaptics touchpads can emulate extended - * protocols (like IMPS/2). Unfortunately - * Logitech/Genius probes confuse some firmware - * versions so we'll have to skip them. - */ - max_proto = PSMOUSE_IMEX; - } - - /* - * Make sure that touchpad is in relative mode, gestures - * (taps) are enabled. - */ - synaptics_reset(psmouse); - } - - /* - * Try Cypress Trackpad. We must try it before Finger Sensing Pad - * because Finger Sensing Pad probe upsets some modules of Cypress - * Trackpads. - */ - if (max_proto > PSMOUSE_IMEX && - psmouse_try_protocol(psmouse, PSMOUSE_CYPRESS, &max_proto, - set_properties, true)) { - return PSMOUSE_CYPRESS; - } - - /* Try ALPS TouchPad */ - if (max_proto > PSMOUSE_IMEX) { - ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); - if (psmouse_try_protocol(psmouse, PSMOUSE_ALPS, - &max_proto, set_properties, true)) - return PSMOUSE_ALPS; - } - - /* Try OLPC HGPK touchpad */ - if (max_proto > PSMOUSE_IMEX && - psmouse_try_protocol(psmouse, PSMOUSE_HGPK, &max_proto, - set_properties, true)) { - return PSMOUSE_HGPK; - } - - /* Try Elantech touchpad */ - if (max_proto > PSMOUSE_IMEX && - psmouse_try_protocol(psmouse, PSMOUSE_ELANTECH, - &max_proto, set_properties, true)) { - return PSMOUSE_ELANTECH; - } - - if (max_proto > PSMOUSE_IMEX) { - if (psmouse_try_protocol(psmouse, PSMOUSE_GENPS, - &max_proto, set_properties, true)) - return PSMOUSE_GENPS; - - if (psmouse_try_protocol(psmouse, PSMOUSE_PS2PP, - &max_proto, set_properties, true)) - return PSMOUSE_PS2PP; - - if (psmouse_try_protocol(psmouse, PSMOUSE_TRACKPOINT, - &max_proto, set_properties, true)) - return PSMOUSE_TRACKPOINT; - - if (psmouse_try_protocol(psmouse, PSMOUSE_TOUCHKIT_PS2, - &max_proto, set_properties, true)) - return PSMOUSE_TOUCHKIT_PS2; - } - - /* - * Try Finger Sensing Pad. We do it here because its probe upsets - * Trackpoint devices (causing TP_READ_ID command to time out). - */ - if (max_proto > PSMOUSE_IMEX && - psmouse_try_protocol(psmouse, PSMOUSE_FSP, - &max_proto, set_properties, true)) { - return PSMOUSE_FSP; - } - - /* - * Reset to defaults in case the device got confused by extended - * protocol probes. Note that we follow up with full reset because - * some mice put themselves to sleep when they see PSMOUSE_RESET_DIS. - */ - ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); - psmouse_reset(psmouse); - - if (max_proto >= PSMOUSE_IMEX && - psmouse_try_protocol(psmouse, PSMOUSE_IMEX, - &max_proto, set_properties, true)) { - return PSMOUSE_IMEX; - } - - if (max_proto >= PSMOUSE_IMPS && - psmouse_try_protocol(psmouse, PSMOUSE_IMPS, - &max_proto, set_properties, true)) { - return PSMOUSE_IMPS; - } - - /* - * Okay, all failed, we have a standard mouse here. The number of - * the buttons is still a question, though. We assume 3. - */ - psmouse_try_protocol(psmouse, PSMOUSE_PS2, - &max_proto, set_properties, true); - - if (synaptics_hardware) { - /* - * We detected Synaptics hardware but it did not respond to - * IMPS/2 probes. We need to reset the touchpad because if - * there is a track point on the pass through port it could - * get disabled while probing for protocol extensions. - */ - psmouse_reset(psmouse); - } - - return PSMOUSE_PS2; -} - -/* - * psmouse_probe() probes for a PS/2 mouse. - */ -static int psmouse_probe(struct psmouse *psmouse) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[2]; - - /* - * First, we check if it's a mouse. It should send 0x00 or 0x03 in - * case of an IntelliMouse in 4-byte mode or 0x04 for IM Explorer. - * Sunrex K8561 IR Keyboard/Mouse reports 0xff on second and - * subsequent ID queries, probably due to a firmware bug. - */ - param[0] = 0xa5; - if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETID)) - return -1; - - if (param[0] != 0x00 && param[0] != 0x03 && - param[0] != 0x04 && param[0] != 0xff) - return -1; - - /* - * Then we reset and disable the mouse so that it doesn't generate - * events. - */ - if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS)) - psmouse_warn(psmouse, "Failed to reset mouse on %s\n", - ps2dev->serio->phys); - - return 0; -} - -/* - * psmouse_initialize() initializes the mouse to a sane state. - */ -static void psmouse_initialize(struct psmouse *psmouse) -{ - /* - * We set the mouse report rate, resolution and scaling. - */ - if (psmouse_max_proto != PSMOUSE_PS2) { - psmouse->set_rate(psmouse, psmouse->rate); - psmouse->set_resolution(psmouse, psmouse->resolution); - psmouse->set_scale(psmouse, PSMOUSE_SCALE11); - } -} - -/* - * psmouse_activate() enables the mouse so that we get motion reports from it. - */ -int psmouse_activate(struct psmouse *psmouse) -{ - if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { - psmouse_warn(psmouse, "Failed to enable mouse on %s\n", - psmouse->ps2dev.serio->phys); - return -1; - } - - psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); - return 0; -} - -/* - * psmouse_deactivate() puts the mouse into poll mode so that we don't get - * motion reports from it unless we explicitly request it. - */ -int psmouse_deactivate(struct psmouse *psmouse) -{ - if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) { - psmouse_warn(psmouse, "Failed to deactivate mouse on %s\n", - psmouse->ps2dev.serio->phys); - return -1; - } - - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - return 0; -} - -/* - * psmouse_resync() attempts to re-validate current protocol. - */ -static void psmouse_resync(struct work_struct *work) -{ - struct psmouse *parent = NULL, *psmouse = - container_of(work, struct psmouse, resync_work.work); - struct serio *serio = psmouse->ps2dev.serio; - psmouse_ret_t rc = PSMOUSE_GOOD_DATA; - bool failed = false, enabled = false; - int i; - - mutex_lock(&psmouse_mutex); - - if (psmouse->state != PSMOUSE_RESYNCING) - goto out; - - if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { - parent = serio_get_drvdata(serio->parent); - psmouse_deactivate(parent); - } - - /* - * Some mice don't ACK commands sent while they are in the middle of - * transmitting motion packet. To avoid delay we use ps2_sendbyte() - * instead of ps2_command() which would wait for 200ms for an ACK - * that may never come. - * As an additional quirk ALPS touchpads may not only forget to ACK - * disable command but will stop reporting taps, so if we see that - * mouse at least once ACKs disable we will do full reconnect if ACK - * is missing. - */ - psmouse->num_resyncs++; - - if (ps2_sendbyte(&psmouse->ps2dev, PSMOUSE_CMD_DISABLE, 20)) { - if (psmouse->num_resyncs < 3 || psmouse->acks_disable_command) - failed = true; - } else - psmouse->acks_disable_command = true; - - /* - * Poll the mouse. If it was reset the packet will be shorter than - * psmouse->pktsize and ps2_command will fail. We do not expect and - * do not handle scenario when mouse "upgrades" its protocol while - * disconnected since it would require additional delay. If we ever - * see a mouse that does it we'll adjust the code. - */ - if (!failed) { - if (psmouse->poll(psmouse)) - failed = true; - else { - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - for (i = 0; i < psmouse->pktsize; i++) { - psmouse->pktcnt++; - rc = psmouse->protocol_handler(psmouse); - if (rc != PSMOUSE_GOOD_DATA) - break; - } - if (rc != PSMOUSE_FULL_PACKET) - failed = true; - psmouse_set_state(psmouse, PSMOUSE_RESYNCING); - } - } - - /* - * Now try to enable mouse. We try to do that even if poll failed - * and also repeat our attempts 5 times, otherwise we may be left - * out with disabled mouse. - */ - for (i = 0; i < 5; i++) { - if (!ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { - enabled = true; - break; - } - msleep(200); - } - - if (!enabled) { - psmouse_warn(psmouse, "failed to re-enable mouse on %s\n", - psmouse->ps2dev.serio->phys); - failed = true; - } - - if (failed) { - psmouse_set_state(psmouse, PSMOUSE_IGNORE); - psmouse_info(psmouse, - "resync failed, issuing reconnect request\n"); - serio_reconnect(serio); - } else - psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); - - if (parent) - psmouse_activate(parent); - out: - mutex_unlock(&psmouse_mutex); -} - -/* - * psmouse_cleanup() resets the mouse into power-on state. - */ -static void psmouse_cleanup(struct serio *serio) -{ - struct psmouse *psmouse = serio_get_drvdata(serio); - struct psmouse *parent = NULL; - - mutex_lock(&psmouse_mutex); - - if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { - parent = serio_get_drvdata(serio->parent); - psmouse_deactivate(parent); - } - - psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); - - /* - * Disable stream mode so cleanup routine can proceed undisturbed. - */ - if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) - psmouse_warn(psmouse, "Failed to disable mouse on %s\n", - psmouse->ps2dev.serio->phys); - - if (psmouse->cleanup) - psmouse->cleanup(psmouse); - - /* - * Reset the mouse to defaults (bare PS/2 protocol). - */ - ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); - - /* - * Some boxes, such as HP nx7400, get terribly confused if mouse - * is not fully enabled before suspending/shutting down. - */ - ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE); - - if (parent) { - if (parent->pt_deactivate) - parent->pt_deactivate(parent); - - psmouse_activate(parent); - } - - mutex_unlock(&psmouse_mutex); -} - -/* - * psmouse_disconnect() closes and frees. - */ -static void psmouse_disconnect(struct serio *serio) -{ - struct psmouse *psmouse, *parent = NULL; - - psmouse = serio_get_drvdata(serio); - - sysfs_remove_group(&serio->dev.kobj, &psmouse_attribute_group); - - mutex_lock(&psmouse_mutex); - - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - - /* make sure we don't have a resync in progress */ - mutex_unlock(&psmouse_mutex); - flush_workqueue(kpsmoused_wq); - mutex_lock(&psmouse_mutex); - - if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { - parent = serio_get_drvdata(serio->parent); - psmouse_deactivate(parent); - } - - if (psmouse->disconnect) - psmouse->disconnect(psmouse); - - if (parent && parent->pt_deactivate) - parent->pt_deactivate(parent); - - psmouse_set_state(psmouse, PSMOUSE_IGNORE); - - serio_close(serio); - serio_set_drvdata(serio, NULL); - input_unregister_device(psmouse->dev); - kfree(psmouse); - - if (parent) - psmouse_activate(parent); - - mutex_unlock(&psmouse_mutex); -} - -static int psmouse_switch_protocol(struct psmouse *psmouse, - const struct psmouse_protocol *proto) -{ - const struct psmouse_protocol *selected_proto; - struct input_dev *input_dev = psmouse->dev; - - input_dev->dev.parent = &psmouse->ps2dev.serio->dev; - - if (proto && (proto->detect || proto->init)) { - psmouse_apply_defaults(psmouse); - - if (proto->detect && proto->detect(psmouse, true) < 0) - return -1; - - if (proto->init && proto->init(psmouse) < 0) - return -1; - - psmouse->type = proto->type; - selected_proto = proto; - } else { - psmouse->type = psmouse_extensions(psmouse, - psmouse_max_proto, true); - selected_proto = psmouse_protocol_by_type(psmouse->type); - } - - psmouse->ignore_parity = selected_proto->ignore_parity; - - /* - * If mouse's packet size is 3 there is no point in polling the - * device in hopes to detect protocol reset - we won't get less - * than 3 bytes response anyhow. - */ - if (psmouse->pktsize == 3) - psmouse->resync_time = 0; - - /* - * Some smart KVMs fake response to POLL command returning just - * 3 bytes and messing up our resync logic, so if initial poll - * fails we won't try polling the device anymore. Hopefully - * such KVM will maintain initially selected protocol. - */ - if (psmouse->resync_time && psmouse->poll(psmouse)) - psmouse->resync_time = 0; - - snprintf(psmouse->devname, sizeof(psmouse->devname), "%s %s %s", - selected_proto->name, psmouse->vendor, psmouse->name); - - input_dev->name = psmouse->devname; - input_dev->phys = psmouse->phys; - input_dev->id.bustype = BUS_I8042; - input_dev->id.vendor = 0x0002; - input_dev->id.product = psmouse->type; - input_dev->id.version = psmouse->model; - - return 0; -} - -/* - * psmouse_connect() is a callback from the serio module when - * an unhandled serio port is found. - */ -static int psmouse_connect(struct serio *serio, struct serio_driver *drv) -{ - struct psmouse *psmouse, *parent = NULL; - struct input_dev *input_dev; - int retval = 0, error = -ENOMEM; - - mutex_lock(&psmouse_mutex); - - /* - * If this is a pass-through port deactivate parent so the device - * connected to this port can be successfully identified - */ - if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { - parent = serio_get_drvdata(serio->parent); - psmouse_deactivate(parent); - } - - psmouse = kzalloc(sizeof(struct psmouse), GFP_KERNEL); - input_dev = input_allocate_device(); - if (!psmouse || !input_dev) - goto err_free; - - ps2_init(&psmouse->ps2dev, serio); - INIT_DELAYED_WORK(&psmouse->resync_work, psmouse_resync); - psmouse->dev = input_dev; - snprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys); - - psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); - - serio_set_drvdata(serio, psmouse); - - error = serio_open(serio, drv); - if (error) - goto err_clear_drvdata; - - /* give PT device some time to settle down before probing */ - if (serio->id.type == SERIO_PS_PSTHRU) - usleep_range(10000, 15000); - - if (psmouse_probe(psmouse) < 0) { - error = -ENODEV; - goto err_close_serio; - } - - psmouse->rate = psmouse_rate; - psmouse->resolution = psmouse_resolution; - psmouse->resetafter = psmouse_resetafter; - psmouse->resync_time = parent ? 0 : psmouse_resync_time; - psmouse->smartscroll = psmouse_smartscroll; - - psmouse_switch_protocol(psmouse, NULL); - - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - psmouse_initialize(psmouse); - - error = input_register_device(psmouse->dev); - if (error) - goto err_protocol_disconnect; - - if (parent && parent->pt_activate) - parent->pt_activate(parent); - - error = sysfs_create_group(&serio->dev.kobj, &psmouse_attribute_group); - if (error) - goto err_pt_deactivate; - - psmouse_activate(psmouse); - - out: - /* If this is a pass-through port the parent needs to be re-activated */ - if (parent) - psmouse_activate(parent); - - mutex_unlock(&psmouse_mutex); - return retval; - - err_pt_deactivate: - if (parent && parent->pt_deactivate) - parent->pt_deactivate(parent); - input_unregister_device(psmouse->dev); - input_dev = NULL; /* so we don't try to free it below */ - err_protocol_disconnect: - if (psmouse->disconnect) - psmouse->disconnect(psmouse); - psmouse_set_state(psmouse, PSMOUSE_IGNORE); - err_close_serio: - serio_close(serio); - err_clear_drvdata: - serio_set_drvdata(serio, NULL); - err_free: - input_free_device(input_dev); - kfree(psmouse); - - retval = error; - goto out; -} - -static int psmouse_reconnect(struct serio *serio) -{ - struct psmouse *psmouse = serio_get_drvdata(serio); - struct psmouse *parent = NULL; - unsigned char type; - int rc = -1; - - mutex_lock(&psmouse_mutex); - - if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { - parent = serio_get_drvdata(serio->parent); - psmouse_deactivate(parent); - } - - psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); - - if (psmouse->reconnect) { - if (psmouse->reconnect(psmouse)) - goto out; - } else { - psmouse_reset(psmouse); - - if (psmouse_probe(psmouse) < 0) - goto out; - - type = psmouse_extensions(psmouse, psmouse_max_proto, false); - if (psmouse->type != type) - goto out; - } - - /* - * OK, the device type (and capabilities) match the old one, - * we can continue using it, complete initialization - */ - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - - psmouse_initialize(psmouse); - - if (parent && parent->pt_activate) - parent->pt_activate(parent); - - psmouse_activate(psmouse); - rc = 0; - -out: - /* If this is a pass-through port the parent waits to be activated */ - if (parent) - psmouse_activate(parent); - - mutex_unlock(&psmouse_mutex); - return rc; -} - -static struct serio_device_id psmouse_serio_ids[] = { - { - .type = SERIO_8042, - .proto = SERIO_ANY, - .id = SERIO_ANY, - .extra = SERIO_ANY, - }, - { - .type = SERIO_PS_PSTHRU, - .proto = SERIO_ANY, - .id = SERIO_ANY, - .extra = SERIO_ANY, - }, - { 0 } -}; - -MODULE_DEVICE_TABLE(serio, psmouse_serio_ids); - -static struct serio_driver psmouse_drv = { - .driver = { - .name = "psmouse", - }, - .description = DRIVER_DESC, - .id_table = psmouse_serio_ids, - .interrupt = psmouse_interrupt, - .connect = psmouse_connect, - .reconnect = psmouse_reconnect, - .disconnect = psmouse_disconnect, - .cleanup = psmouse_cleanup, -}; - -ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *devattr, - char *buf) -{ - struct serio *serio = to_serio_port(dev); - struct psmouse_attribute *attr = to_psmouse_attr(devattr); - struct psmouse *psmouse; - - psmouse = serio_get_drvdata(serio); - - return attr->show(psmouse, attr->data, buf); -} - -ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *devattr, - const char *buf, size_t count) -{ - struct serio *serio = to_serio_port(dev); - struct psmouse_attribute *attr = to_psmouse_attr(devattr); - struct psmouse *psmouse, *parent = NULL; - int retval; - - retval = mutex_lock_interruptible(&psmouse_mutex); - if (retval) - goto out; - - psmouse = serio_get_drvdata(serio); - - if (attr->protect) { - if (psmouse->state == PSMOUSE_IGNORE) { - retval = -ENODEV; - goto out_unlock; - } - - if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { - parent = serio_get_drvdata(serio->parent); - psmouse_deactivate(parent); - } - - psmouse_deactivate(psmouse); - } - - retval = attr->set(psmouse, attr->data, buf, count); - - if (attr->protect) { - if (retval != -ENODEV) - psmouse_activate(psmouse); - - if (parent) - psmouse_activate(parent); - } - - out_unlock: - mutex_unlock(&psmouse_mutex); - out: - return retval; -} - -static ssize_t psmouse_show_int_attr(struct psmouse *psmouse, void *offset, char *buf) -{ - unsigned int *field = (unsigned int *)((char *)psmouse + (size_t)offset); - - return sprintf(buf, "%u\n", *field); -} - -static ssize_t psmouse_set_int_attr(struct psmouse *psmouse, void *offset, const char *buf, size_t count) -{ - unsigned int *field = (unsigned int *)((char *)psmouse + (size_t)offset); - unsigned int value; - int err; - - err = kstrtouint(buf, 10, &value); - if (err) - return err; - - *field = value; - - return count; -} - -static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, void *data, char *buf) -{ - return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name); -} - -static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, const char *buf, size_t count) -{ - struct serio *serio = psmouse->ps2dev.serio; - struct psmouse *parent = NULL; - struct input_dev *old_dev, *new_dev; - const struct psmouse_protocol *proto, *old_proto; - int error; - int retry = 0; - - proto = psmouse_protocol_by_name(buf, count); - if (!proto) - return -EINVAL; - - if (psmouse->type == proto->type) - return count; - - new_dev = input_allocate_device(); - if (!new_dev) - return -ENOMEM; - - while (!list_empty(&serio->children)) { - if (++retry > 3) { - psmouse_warn(psmouse, - "failed to destroy children ports, protocol change aborted.\n"); - input_free_device(new_dev); - return -EIO; - } - - mutex_unlock(&psmouse_mutex); - serio_unregister_child_port(serio); - mutex_lock(&psmouse_mutex); - - if (serio->drv != &psmouse_drv) { - input_free_device(new_dev); - return -ENODEV; - } - - if (psmouse->type == proto->type) { - input_free_device(new_dev); - return count; /* switched by other thread */ - } - } - - if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { - parent = serio_get_drvdata(serio->parent); - if (parent->pt_deactivate) - parent->pt_deactivate(parent); - } - - old_dev = psmouse->dev; - old_proto = psmouse_protocol_by_type(psmouse->type); - - if (psmouse->disconnect) - psmouse->disconnect(psmouse); - - psmouse_set_state(psmouse, PSMOUSE_IGNORE); - - psmouse->dev = new_dev; - psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); - - if (psmouse_switch_protocol(psmouse, proto) < 0) { - psmouse_reset(psmouse); - /* default to PSMOUSE_PS2 */ - psmouse_switch_protocol(psmouse, &psmouse_protocols[0]); - } - - psmouse_initialize(psmouse); - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - - error = input_register_device(psmouse->dev); - if (error) { - if (psmouse->disconnect) - psmouse->disconnect(psmouse); - - psmouse_set_state(psmouse, PSMOUSE_IGNORE); - input_free_device(new_dev); - psmouse->dev = old_dev; - psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); - psmouse_switch_protocol(psmouse, old_proto); - psmouse_initialize(psmouse); - psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); - - return error; - } - - input_unregister_device(old_dev); - - if (parent && parent->pt_activate) - parent->pt_activate(parent); - - return count; -} - -static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, void *data, const char *buf, size_t count) -{ - unsigned int value; - int err; - - err = kstrtouint(buf, 10, &value); - if (err) - return err; - - psmouse->set_rate(psmouse, value); - return count; -} - -static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data, const char *buf, size_t count) -{ - unsigned int value; - int err; - - err = kstrtouint(buf, 10, &value); - if (err) - return err; - - psmouse->set_resolution(psmouse, value); - return count; -} - - -static int psmouse_set_maxproto(const char *val, const struct kernel_param *kp) -{ - const struct psmouse_protocol *proto; - - if (!val) - return -EINVAL; - - proto = psmouse_protocol_by_name(val, strlen(val)); - - if (!proto || !proto->maxproto) - return -EINVAL; - - *((unsigned int *)kp->arg) = proto->type; - - return 0; -} - -static int psmouse_get_maxproto(char *buffer, const struct kernel_param *kp) -{ - int type = *((unsigned int *)kp->arg); - - return sprintf(buffer, "%s", psmouse_protocol_by_type(type)->name); -} - -static int __init psmouse_init(void) -{ - int err; - - lifebook_module_init(); - synaptics_module_init(); - hgpk_module_init(); - - kpsmoused_wq = alloc_ordered_workqueue("kpsmoused", 0); - if (!kpsmoused_wq) { - pr_err("failed to create kpsmoused workqueue\n"); - return -ENOMEM; - } - - err = serio_register_driver(&psmouse_drv); - if (err) - destroy_workqueue(kpsmoused_wq); - - return err; -} - -static void __exit psmouse_exit(void) -{ - serio_unregister_driver(&psmouse_drv); - destroy_workqueue(kpsmoused_wq); -} - -module_init(psmouse_init); -module_exit(psmouse_exit); diff --git a/src/linux/drivers/input/mouse/psmouse.h b/src/linux/drivers/input/mouse/psmouse.h deleted file mode 100644 index e0ca6cd..0000000 --- a/src/linux/drivers/input/mouse/psmouse.h +++ /dev/null @@ -1,194 +0,0 @@ -#ifndef _PSMOUSE_H -#define _PSMOUSE_H - -#define PSMOUSE_CMD_SETSCALE11 0x00e6 -#define PSMOUSE_CMD_SETSCALE21 0x00e7 -#define PSMOUSE_CMD_SETRES 0x10e8 -#define PSMOUSE_CMD_GETINFO 0x03e9 -#define PSMOUSE_CMD_SETSTREAM 0x00ea -#define PSMOUSE_CMD_SETPOLL 0x00f0 -#define PSMOUSE_CMD_POLL 0x00eb /* caller sets number of bytes to receive */ -#define PSMOUSE_CMD_RESET_WRAP 0x00ec -#define PSMOUSE_CMD_GETID 0x02f2 -#define PSMOUSE_CMD_SETRATE 0x10f3 -#define PSMOUSE_CMD_ENABLE 0x00f4 -#define PSMOUSE_CMD_DISABLE 0x00f5 -#define PSMOUSE_CMD_RESET_DIS 0x00f6 -#define PSMOUSE_CMD_RESET_BAT 0x02ff - -#define PSMOUSE_RET_BAT 0xaa -#define PSMOUSE_RET_ID 0x00 -#define PSMOUSE_RET_ACK 0xfa -#define PSMOUSE_RET_NAK 0xfe - -enum psmouse_state { - PSMOUSE_IGNORE, - PSMOUSE_INITIALIZING, - PSMOUSE_RESYNCING, - PSMOUSE_CMD_MODE, - PSMOUSE_ACTIVATED, -}; - -/* psmouse protocol handler return codes */ -typedef enum { - PSMOUSE_BAD_DATA, - PSMOUSE_GOOD_DATA, - PSMOUSE_FULL_PACKET -} psmouse_ret_t; - -enum psmouse_scale { - PSMOUSE_SCALE11, - PSMOUSE_SCALE21 -}; - -struct psmouse { - void *private; - struct input_dev *dev; - struct ps2dev ps2dev; - struct delayed_work resync_work; - char *vendor; - char *name; - unsigned char packet[8]; - unsigned char badbyte; - unsigned char pktcnt; - unsigned char pktsize; - unsigned char type; - bool ignore_parity; - bool acks_disable_command; - unsigned int model; - unsigned long last; - unsigned long out_of_sync_cnt; - unsigned long num_resyncs; - enum psmouse_state state; - char devname[64]; - char phys[32]; - - unsigned int rate; - unsigned int resolution; - unsigned int resetafter; - unsigned int resync_time; - bool smartscroll; /* Logitech only */ - - psmouse_ret_t (*protocol_handler)(struct psmouse *psmouse); - void (*set_rate)(struct psmouse *psmouse, unsigned int rate); - void (*set_resolution)(struct psmouse *psmouse, unsigned int resolution); - void (*set_scale)(struct psmouse *psmouse, enum psmouse_scale scale); - - int (*reconnect)(struct psmouse *psmouse); - void (*disconnect)(struct psmouse *psmouse); - void (*cleanup)(struct psmouse *psmouse); - int (*poll)(struct psmouse *psmouse); - - void (*pt_activate)(struct psmouse *psmouse); - void (*pt_deactivate)(struct psmouse *psmouse); -}; - -enum psmouse_type { - PSMOUSE_NONE, - PSMOUSE_PS2, - PSMOUSE_PS2PP, - PSMOUSE_THINKPS, - PSMOUSE_GENPS, - PSMOUSE_IMPS, - PSMOUSE_IMEX, - PSMOUSE_SYNAPTICS, - PSMOUSE_ALPS, - PSMOUSE_LIFEBOOK, - PSMOUSE_TRACKPOINT, - PSMOUSE_TOUCHKIT_PS2, - PSMOUSE_CORTRON, - PSMOUSE_HGPK, - PSMOUSE_ELANTECH, - PSMOUSE_FSP, - PSMOUSE_SYNAPTICS_RELATIVE, - PSMOUSE_CYPRESS, - PSMOUSE_FOCALTECH, - PSMOUSE_VMMOUSE, - PSMOUSE_BYD, - PSMOUSE_AUTO /* This one should always be last */ -}; - -void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work, - unsigned long delay); -int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command); -int psmouse_reset(struct psmouse *psmouse); -void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state); -void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution); -psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse); -int psmouse_activate(struct psmouse *psmouse); -int psmouse_deactivate(struct psmouse *psmouse); -bool psmouse_matches_pnp_id(struct psmouse *psmouse, const char * const ids[]); - -struct psmouse_attribute { - struct device_attribute dattr; - void *data; - ssize_t (*show)(struct psmouse *psmouse, void *data, char *buf); - ssize_t (*set)(struct psmouse *psmouse, void *data, - const char *buf, size_t count); - bool protect; -}; -#define to_psmouse_attr(a) container_of((a), struct psmouse_attribute, dattr) - -ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *attr, - char *buf); -ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count); - -#define __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, _set, _protect) \ -static struct psmouse_attribute psmouse_attr_##_name = { \ - .dattr = { \ - .attr = { \ - .name = __stringify(_name), \ - .mode = _mode, \ - }, \ - .show = psmouse_attr_show_helper, \ - .store = psmouse_attr_set_helper, \ - }, \ - .data = _data, \ - .show = _show, \ - .set = _set, \ - .protect = _protect, \ -} - -#define __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, _protect) \ - static ssize_t _show(struct psmouse *, void *, char *); \ - static ssize_t _set(struct psmouse *, void *, const char *, size_t); \ - __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, _set, _protect) - -#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set) \ - __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, true) - -#define PSMOUSE_DEFINE_RO_ATTR(_name, _mode, _data, _show) \ - static ssize_t _show(struct psmouse *, void *, char *); \ - __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, _show, NULL, true) - -#define PSMOUSE_DEFINE_WO_ATTR(_name, _mode, _data, _set) \ - static ssize_t _set(struct psmouse *, void *, const char *, size_t); \ - __PSMOUSE_DEFINE_ATTR_VAR(_name, _mode, _data, NULL, _set, true) - -#ifndef psmouse_fmt -#define psmouse_fmt(fmt) KBUILD_BASENAME ": " fmt -#endif - -#define psmouse_dbg(psmouse, format, ...) \ - dev_dbg(&(psmouse)->ps2dev.serio->dev, \ - psmouse_fmt(format), ##__VA_ARGS__) -#define psmouse_info(psmouse, format, ...) \ - dev_info(&(psmouse)->ps2dev.serio->dev, \ - psmouse_fmt(format), ##__VA_ARGS__) -#define psmouse_warn(psmouse, format, ...) \ - dev_warn(&(psmouse)->ps2dev.serio->dev, \ - psmouse_fmt(format), ##__VA_ARGS__) -#define psmouse_err(psmouse, format, ...) \ - dev_err(&(psmouse)->ps2dev.serio->dev, \ - psmouse_fmt(format), ##__VA_ARGS__) -#define psmouse_notice(psmouse, format, ...) \ - dev_notice(&(psmouse)->ps2dev.serio->dev, \ - psmouse_fmt(format), ##__VA_ARGS__) -#define psmouse_printk(level, psmouse, format, ...) \ - dev_printk(level, \ - &(psmouse)->ps2dev.serio->dev, \ - psmouse_fmt(format), ##__VA_ARGS__) - - -#endif /* _PSMOUSE_H */ diff --git a/src/linux/drivers/input/mouse/sentelic.h b/src/linux/drivers/input/mouse/sentelic.h deleted file mode 100644 index 42df9e3..0000000 --- a/src/linux/drivers/input/mouse/sentelic.h +++ /dev/null @@ -1,138 +0,0 @@ -/*- - * Finger Sensing Pad PS/2 mouse driver. - * - * Copyright (C) 2005-2007 Asia Vital Components Co., Ltd. - * Copyright (C) 2005-2012 Tai-hwa Liang, Sentelic Corporation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef __SENTELIC_H -#define __SENTELIC_H - -/* Finger-sensing Pad information registers */ -#define FSP_REG_DEVICE_ID 0x00 -#define FSP_REG_VERSION 0x01 -#define FSP_REG_REVISION 0x04 -#define FSP_REG_TMOD_STATUS1 0x0B -#define FSP_BIT_NO_ROTATION BIT(3) -#define FSP_REG_PAGE_CTRL 0x0F - -/* Finger-sensing Pad control registers */ -#define FSP_REG_SYSCTL1 0x10 -#define FSP_BIT_EN_REG_CLK BIT(5) -#define FSP_REG_TMOD_STATUS 0x20 -#define FSP_REG_OPC_QDOWN 0x31 -#define FSP_BIT_EN_OPC_TAG BIT(7) -#define FSP_REG_OPTZ_XLO 0x34 -#define FSP_REG_OPTZ_XHI 0x35 -#define FSP_REG_OPTZ_YLO 0x36 -#define FSP_REG_OPTZ_YHI 0x37 -#define FSP_REG_SYSCTL5 0x40 -#define FSP_BIT_90_DEGREE BIT(0) -#define FSP_BIT_EN_MSID6 BIT(1) -#define FSP_BIT_EN_MSID7 BIT(2) -#define FSP_BIT_EN_MSID8 BIT(3) -#define FSP_BIT_EN_AUTO_MSID8 BIT(5) -#define FSP_BIT_EN_PKT_G0 BIT(6) - -#define FSP_REG_ONPAD_CTL 0x43 -#define FSP_BIT_ONPAD_ENABLE BIT(0) -#define FSP_BIT_ONPAD_FBBB BIT(1) -#define FSP_BIT_FIX_VSCR BIT(3) -#define FSP_BIT_FIX_HSCR BIT(5) -#define FSP_BIT_DRAG_LOCK BIT(6) - -#define FSP_REG_SWC1 (0x90) -#define FSP_BIT_SWC1_EN_ABS_1F BIT(0) -#define FSP_BIT_SWC1_EN_GID BIT(1) -#define FSP_BIT_SWC1_EN_ABS_2F BIT(2) -#define FSP_BIT_SWC1_EN_FUP_OUT BIT(3) -#define FSP_BIT_SWC1_EN_ABS_CON BIT(4) -#define FSP_BIT_SWC1_GST_GRP0 BIT(5) -#define FSP_BIT_SWC1_GST_GRP1 BIT(6) -#define FSP_BIT_SWC1_BX_COMPAT BIT(7) - -#define FSP_PAGE_0B (0x0b) -#define FSP_PAGE_82 (0x82) -#define FSP_PAGE_DEFAULT FSP_PAGE_82 - -#define FSP_REG_SN0 (0x40) -#define FSP_REG_SN1 (0x41) -#define FSP_REG_SN2 (0x42) - -/* Finger-sensing Pad packet formating related definitions */ - -/* absolute packet type */ -#define FSP_PKT_TYPE_NORMAL (0x00) -#define FSP_PKT_TYPE_ABS (0x01) -#define FSP_PKT_TYPE_NOTIFY (0x02) -#define FSP_PKT_TYPE_NORMAL_OPC (0x03) -#define FSP_PKT_TYPE_SHIFT (6) - -/* bit definitions for the first byte of report packet */ -#define FSP_PB0_LBTN BIT(0) -#define FSP_PB0_RBTN BIT(1) -#define FSP_PB0_MBTN BIT(2) -#define FSP_PB0_MFMC_FGR2 FSP_PB0_MBTN -#define FSP_PB0_MUST_SET BIT(3) -#define FSP_PB0_PHY_BTN BIT(4) -#define FSP_PB0_MFMC BIT(5) - -/* hardware revisions */ -#define FSP_VER_STL3888_A4 (0xC1) -#define FSP_VER_STL3888_B0 (0xD0) -#define FSP_VER_STL3888_B1 (0xD1) -#define FSP_VER_STL3888_B2 (0xD2) -#define FSP_VER_STL3888_C0 (0xE0) -#define FSP_VER_STL3888_C1 (0xE1) -#define FSP_VER_STL3888_D0 (0xE2) -#define FSP_VER_STL3888_D1 (0xE3) -#define FSP_VER_STL3888_E0 (0xE4) - -#ifdef __KERNEL__ - -struct fsp_data { - unsigned char ver; /* hardware version */ - unsigned char rev; /* hardware revison */ - unsigned int buttons; /* Number of buttons */ - unsigned int flags; -#define FSPDRV_FLAG_EN_OPC (0x001) /* enable on-pad clicking */ - - bool vscroll; /* Vertical scroll zone enabled */ - bool hscroll; /* Horizontal scroll zone enabled */ - - unsigned char last_reg; /* Last register we requested read from */ - unsigned char last_val; - unsigned int last_mt_fgr; /* Last seen finger(multitouch) */ -}; - -#ifdef CONFIG_MOUSE_PS2_SENTELIC -extern int fsp_detect(struct psmouse *psmouse, bool set_properties); -extern int fsp_init(struct psmouse *psmouse); -#else -static inline int fsp_detect(struct psmouse *psmouse, bool set_properties) -{ - return -ENOSYS; -} -static inline int fsp_init(struct psmouse *psmouse) -{ - return -ENOSYS; -} -#endif - -#endif /* __KERNEL__ */ - -#endif /* !__SENTELIC_H */ diff --git a/src/linux/drivers/input/mouse/synaptics.c b/src/linux/drivers/input/mouse/synaptics.c deleted file mode 100644 index a41d832..0000000 --- a/src/linux/drivers/input/mouse/synaptics.c +++ /dev/null @@ -1,1577 +0,0 @@ -/* - * Synaptics TouchPad PS/2 mouse driver - * - * 2003 Dmitry Torokhov - * Added support for pass-through port. Special thanks to Peter Berg Larsen - * for explaining various Synaptics quirks. - * - * 2003 Peter Osterlund - * Ported to 2.5 input device infrastructure. - * - * Copyright (C) 2001 Stefan Gmeiner - * start merging tpconfig and gpm code to a xfree-input module - * adding some changes and extensions (ex. 3rd and 4th button) - * - * Copyright (c) 1997 C. Scott Ananian - * Copyright (c) 1998-2000 Bruce Kalk - * code for the special synaptics commands (from the tpconfig-source) - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * Trademarks are the property of their respective owners. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "psmouse.h" -#include "synaptics.h" - -/* - * The x/y limits are taken from the Synaptics TouchPad interfacing Guide, - * section 2.3.2, which says that they should be valid regardless of the - * actual size of the sensor. - * Note that newer firmware allows querying device for maximum useable - * coordinates. - */ -#define XMIN 0 -#define XMAX 6143 -#define YMIN 0 -#define YMAX 6143 -#define XMIN_NOMINAL 1472 -#define XMAX_NOMINAL 5472 -#define YMIN_NOMINAL 1408 -#define YMAX_NOMINAL 4448 - -/* Size in bits of absolute position values reported by the hardware */ -#define ABS_POS_BITS 13 - -/* - * These values should represent the absolute maximum value that will - * be reported for a positive position value. Some Synaptics firmware - * uses this value to indicate a finger near the edge of the touchpad - * whose precise position cannot be determined. - * - * At least one touchpad is known to report positions in excess of this - * value which are actually negative values truncated to the 13-bit - * reporting range. These values have never been observed to be lower - * than 8184 (i.e. -8), so we treat all values greater than 8176 as - * negative and any other value as positive. - */ -#define X_MAX_POSITIVE 8176 -#define Y_MAX_POSITIVE 8176 - -/* maximum ABS_MT_POSITION displacement (in mm) */ -#define DMAX 10 - -/***************************************************************************** - * Stuff we need even when we do not want native Synaptics support - ****************************************************************************/ - -/* - * Set the synaptics touchpad mode byte by special commands - */ -static int synaptics_mode_cmd(struct psmouse *psmouse, unsigned char mode) -{ - unsigned char param[1]; - - if (psmouse_sliced_command(psmouse, mode)) - return -1; - param[0] = SYN_PS_SET_MODE2; - if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE)) - return -1; - return 0; -} - -int synaptics_detect(struct psmouse *psmouse, bool set_properties) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char param[4]; - - param[0] = 0; - - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); - ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES); - ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO); - - if (param[1] != 0x47) - return -ENODEV; - - if (set_properties) { - psmouse->vendor = "Synaptics"; - psmouse->name = "TouchPad"; - } - - return 0; -} - -void synaptics_reset(struct psmouse *psmouse) -{ - /* reset touchpad back to relative mode, gestures enabled */ - synaptics_mode_cmd(psmouse, 0); -} - -#ifdef CONFIG_MOUSE_PS2_SYNAPTICS - -static bool cr48_profile_sensor; - -#define ANY_BOARD_ID 0 -struct min_max_quirk { - const char * const *pnp_ids; - struct { - unsigned long int min, max; - } board_id; - int x_min, x_max, y_min, y_max; -}; - -static const struct min_max_quirk min_max_pnpid_table[] = { - { - (const char * const []){"LEN0033", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1024, 5052, 2258, 4832 - }, - { - (const char * const []){"LEN0042", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1232, 5710, 1156, 4696 - }, - { - (const char * const []){"LEN0034", "LEN0036", "LEN0037", - "LEN0039", "LEN2002", "LEN2004", - NULL}, - {ANY_BOARD_ID, 2961}, - 1024, 5112, 2024, 4832 - }, - { - (const char * const []){"LEN2000", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1024, 5113, 2021, 4832 - }, - { - (const char * const []){"LEN2001", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1024, 5022, 2508, 4832 - }, - { - (const char * const []){"LEN2006", NULL}, - {2691, 2691}, - 1024, 5045, 2457, 4832 - }, - { - (const char * const []){"LEN2006", NULL}, - {ANY_BOARD_ID, ANY_BOARD_ID}, - 1264, 5675, 1171, 4688 - }, - { } -}; - -/* This list has been kindly provided by Synaptics. */ -static const char * const topbuttonpad_pnp_ids[] = { - "LEN0017", - "LEN0018", - "LEN0019", - "LEN0023", - "LEN002A", - "LEN002B", - "LEN002C", - "LEN002D", - "LEN002E", - "LEN0033", /* Helix */ - "LEN0034", /* T431s, L440, L540, T540, W540, X1 Carbon 2nd */ - "LEN0035", /* X240 */ - "LEN0036", /* T440 */ - "LEN0037", /* X1 Carbon 2nd */ - "LEN0038", - "LEN0039", /* T440s */ - "LEN0041", - "LEN0042", /* Yoga */ - "LEN0045", - "LEN0047", - "LEN0049", - "LEN2000", /* S540 */ - "LEN2001", /* Edge E431 */ - "LEN2002", /* Edge E531 */ - "LEN2003", - "LEN2004", /* L440 */ - "LEN2005", - "LEN2006", /* Edge E440/E540 */ - "LEN2007", - "LEN2008", - "LEN2009", - "LEN200A", - "LEN200B", - NULL -}; - -/* This list has been kindly provided by Synaptics. */ -static const char * const forcepad_pnp_ids[] = { - "SYN300D", - "SYN3014", - NULL -}; - -/***************************************************************************** - * Synaptics communications functions - ****************************************************************************/ - -/* - * Synaptics touchpads report the y coordinate from bottom to top, which is - * opposite from what userspace expects. - * This function is used to invert y before reporting. - */ -static int synaptics_invert_y(int y) -{ - return YMAX_NOMINAL + YMIN_NOMINAL - y; -} - -/* - * Send a command to the synpatics touchpad by special commands - */ -static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, unsigned char *param) -{ - if (psmouse_sliced_command(psmouse, c)) - return -1; - if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) - return -1; - return 0; -} - -/* - * Read the model-id bytes from the touchpad - * see also SYN_MODEL_* macros - */ -static int synaptics_model_id(struct psmouse *psmouse) -{ - struct synaptics_data *priv = psmouse->private; - unsigned char mi[3]; - - if (synaptics_send_cmd(psmouse, SYN_QUE_MODEL, mi)) - return -1; - priv->model_id = (mi[0]<<16) | (mi[1]<<8) | mi[2]; - return 0; -} - -static int synaptics_more_extended_queries(struct psmouse *psmouse) -{ - struct synaptics_data *priv = psmouse->private; - unsigned char buf[3]; - - if (synaptics_send_cmd(psmouse, SYN_QUE_MEXT_CAPAB_10, buf)) - return -1; - - priv->ext_cap_10 = (buf[0]<<16) | (buf[1]<<8) | buf[2]; - - return 0; -} - -/* - * Read the board id and the "More Extended Queries" from the touchpad - * The board id is encoded in the "QUERY MODES" response - */ -static int synaptics_query_modes(struct psmouse *psmouse) -{ - struct synaptics_data *priv = psmouse->private; - unsigned char bid[3]; - - /* firmwares prior 7.5 have no board_id encoded */ - if (SYN_ID_FULL(priv->identity) < 0x705) - return 0; - - if (synaptics_send_cmd(psmouse, SYN_QUE_MODES, bid)) - return -1; - priv->board_id = ((bid[0] & 0xfc) << 6) | bid[1]; - - if (SYN_MEXT_CAP_BIT(bid[0])) - return synaptics_more_extended_queries(psmouse); - - return 0; -} - -/* - * Read the firmware id from the touchpad - */ -static int synaptics_firmware_id(struct psmouse *psmouse) -{ - struct synaptics_data *priv = psmouse->private; - unsigned char fwid[3]; - - if (synaptics_send_cmd(psmouse, SYN_QUE_FIRMWARE_ID, fwid)) - return -1; - priv->firmware_id = (fwid[0] << 16) | (fwid[1] << 8) | fwid[2]; - return 0; -} - -/* - * Read the capability-bits from the touchpad - * see also the SYN_CAP_* macros - */ -static int synaptics_capability(struct psmouse *psmouse) -{ - struct synaptics_data *priv = psmouse->private; - unsigned char cap[3]; - - if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap)) - return -1; - priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2]; - priv->ext_cap = priv->ext_cap_0c = 0; - - /* - * Older firmwares had submodel ID fixed to 0x47 - */ - if (SYN_ID_FULL(priv->identity) < 0x705 && - SYN_CAP_SUBMODEL_ID(priv->capabilities) != 0x47) { - return -1; - } - - /* - * Unless capExtended is set the rest of the flags should be ignored - */ - if (!SYN_CAP_EXTENDED(priv->capabilities)) - priv->capabilities = 0; - - if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) { - if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) { - psmouse_warn(psmouse, - "device claims to have extended capabilities, but I'm not able to read them.\n"); - } else { - priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2]; - - /* - * if nExtBtn is greater than 8 it should be considered - * invalid and treated as 0 - */ - if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 8) - priv->ext_cap &= 0xff0fff; - } - } - - if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 4) { - if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap)) { - psmouse_warn(psmouse, - "device claims to have extended capability 0x0c, but I'm not able to read it.\n"); - } else { - priv->ext_cap_0c = (cap[0] << 16) | (cap[1] << 8) | cap[2]; - } - } - - return 0; -} - -/* - * Identify Touchpad - * See also the SYN_ID_* macros - */ -static int synaptics_identify(struct psmouse *psmouse) -{ - struct synaptics_data *priv = psmouse->private; - unsigned char id[3]; - - if (synaptics_send_cmd(psmouse, SYN_QUE_IDENTIFY, id)) - return -1; - priv->identity = (id[0]<<16) | (id[1]<<8) | id[2]; - if (SYN_ID_IS_SYNAPTICS(priv->identity)) - return 0; - return -1; -} - -/* - * Read touchpad resolution and maximum reported coordinates - * Resolution is left zero if touchpad does not support the query - */ - -static int synaptics_resolution(struct psmouse *psmouse) -{ - struct synaptics_data *priv = psmouse->private; - unsigned char resp[3]; - - if (SYN_ID_MAJOR(priv->identity) < 4) - return 0; - - if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, resp) == 0) { - if (resp[0] != 0 && (resp[1] & 0x80) && resp[2] != 0) { - priv->x_res = resp[0]; /* x resolution in units/mm */ - priv->y_res = resp[2]; /* y resolution in units/mm */ - } - } - - if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 && - SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) { - if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) { - psmouse_warn(psmouse, - "device claims to have max coordinates query, but I'm not able to read it.\n"); - } else { - priv->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); - priv->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); - psmouse_info(psmouse, - "queried max coordinates: x [..%d], y [..%d]\n", - priv->x_max, priv->y_max); - } - } - - if (SYN_CAP_MIN_DIMENSIONS(priv->ext_cap_0c) && - (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 7 || - /* - * Firmware v8.1 does not report proper number of extended - * capabilities, but has been proven to report correct min - * coordinates. - */ - SYN_ID_FULL(priv->identity) == 0x801)) { - if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MIN_COORDS, resp)) { - psmouse_warn(psmouse, - "device claims to have min coordinates query, but I'm not able to read it.\n"); - } else { - priv->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); - priv->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); - psmouse_info(psmouse, - "queried min coordinates: x [%d..], y [%d..]\n", - priv->x_min, priv->y_min); - } - } - - return 0; -} - -/* - * Apply quirk(s) if the hardware matches - */ - -static void synaptics_apply_quirks(struct psmouse *psmouse) -{ - struct synaptics_data *priv = psmouse->private; - int i; - - for (i = 0; min_max_pnpid_table[i].pnp_ids; i++) { - if (!psmouse_matches_pnp_id(psmouse, - min_max_pnpid_table[i].pnp_ids)) - continue; - - if (min_max_pnpid_table[i].board_id.min != ANY_BOARD_ID && - priv->board_id < min_max_pnpid_table[i].board_id.min) - continue; - - if (min_max_pnpid_table[i].board_id.max != ANY_BOARD_ID && - priv->board_id > min_max_pnpid_table[i].board_id.max) - continue; - - priv->x_min = min_max_pnpid_table[i].x_min; - priv->x_max = min_max_pnpid_table[i].x_max; - priv->y_min = min_max_pnpid_table[i].y_min; - priv->y_max = min_max_pnpid_table[i].y_max; - psmouse_info(psmouse, - "quirked min/max coordinates: x [%d..%d], y [%d..%d]\n", - priv->x_min, priv->x_max, - priv->y_min, priv->y_max); - break; - } -} - -static int synaptics_query_hardware(struct psmouse *psmouse) -{ - if (synaptics_identify(psmouse)) - return -1; - if (synaptics_model_id(psmouse)) - return -1; - if (synaptics_firmware_id(psmouse)) - return -1; - if (synaptics_query_modes(psmouse)) - return -1; - if (synaptics_capability(psmouse)) - return -1; - if (synaptics_resolution(psmouse)) - return -1; - - synaptics_apply_quirks(psmouse); - - return 0; -} - -static int synaptics_set_advanced_gesture_mode(struct psmouse *psmouse) -{ - static unsigned char param = 0xc8; - struct synaptics_data *priv = psmouse->private; - - if (!(SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) || - SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c))) - return 0; - - if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL)) - return -1; - - if (ps2_command(&psmouse->ps2dev, ¶m, PSMOUSE_CMD_SETRATE)) - return -1; - - /* Advanced gesture mode also sends multi finger data */ - priv->capabilities |= BIT(1); - - return 0; -} - -static int synaptics_set_mode(struct psmouse *psmouse) -{ - struct synaptics_data *priv = psmouse->private; - - priv->mode = 0; - if (priv->absolute_mode) - priv->mode |= SYN_BIT_ABSOLUTE_MODE; - if (priv->disable_gesture) - priv->mode |= SYN_BIT_DISABLE_GESTURE; - if (psmouse->rate >= 80) - priv->mode |= SYN_BIT_HIGH_RATE; - if (SYN_CAP_EXTENDED(priv->capabilities)) - priv->mode |= SYN_BIT_W_MODE; - - if (synaptics_mode_cmd(psmouse, priv->mode)) - return -1; - - if (priv->absolute_mode && - synaptics_set_advanced_gesture_mode(psmouse)) { - psmouse_err(psmouse, "Advanced gesture mode init failed.\n"); - return -1; - } - - return 0; -} - -static void synaptics_set_rate(struct psmouse *psmouse, unsigned int rate) -{ - struct synaptics_data *priv = psmouse->private; - - if (rate >= 80) { - priv->mode |= SYN_BIT_HIGH_RATE; - psmouse->rate = 80; - } else { - priv->mode &= ~SYN_BIT_HIGH_RATE; - psmouse->rate = 40; - } - - synaptics_mode_cmd(psmouse, priv->mode); -} - -/***************************************************************************** - * Synaptics pass-through PS/2 port support - ****************************************************************************/ -static int synaptics_pt_write(struct serio *serio, unsigned char c) -{ - struct psmouse *parent = serio_get_drvdata(serio->parent); - char rate_param = SYN_PS_CLIENT_CMD; /* indicates that we want pass-through port */ - - if (psmouse_sliced_command(parent, c)) - return -1; - if (ps2_command(&parent->ps2dev, &rate_param, PSMOUSE_CMD_SETRATE)) - return -1; - return 0; -} - -static int synaptics_pt_start(struct serio *serio) -{ - struct psmouse *parent = serio_get_drvdata(serio->parent); - struct synaptics_data *priv = parent->private; - - serio_pause_rx(parent->ps2dev.serio); - priv->pt_port = serio; - serio_continue_rx(parent->ps2dev.serio); - - return 0; -} - -static void synaptics_pt_stop(struct serio *serio) -{ - struct psmouse *parent = serio_get_drvdata(serio->parent); - struct synaptics_data *priv = parent->private; - - serio_pause_rx(parent->ps2dev.serio); - priv->pt_port = NULL; - serio_continue_rx(parent->ps2dev.serio); -} - -static int synaptics_is_pt_packet(unsigned char *buf) -{ - return (buf[0] & 0xFC) == 0x84 && (buf[3] & 0xCC) == 0xC4; -} - -static void synaptics_pass_pt_packet(struct psmouse *psmouse, - struct serio *ptport, - unsigned char *packet) -{ - struct synaptics_data *priv = psmouse->private; - struct psmouse *child = serio_get_drvdata(ptport); - - if (child && child->state == PSMOUSE_ACTIVATED) { - serio_interrupt(ptport, packet[1] | priv->pt_buttons, 0); - serio_interrupt(ptport, packet[4], 0); - serio_interrupt(ptport, packet[5], 0); - if (child->pktsize == 4) - serio_interrupt(ptport, packet[2], 0); - } else { - serio_interrupt(ptport, packet[1], 0); - } -} - -static void synaptics_pt_activate(struct psmouse *psmouse) -{ - struct synaptics_data *priv = psmouse->private; - struct psmouse *child = serio_get_drvdata(priv->pt_port); - - /* adjust the touchpad to child's choice of protocol */ - if (child) { - if (child->pktsize == 4) - priv->mode |= SYN_BIT_FOUR_BYTE_CLIENT; - else - priv->mode &= ~SYN_BIT_FOUR_BYTE_CLIENT; - - if (synaptics_mode_cmd(psmouse, priv->mode)) - psmouse_warn(psmouse, - "failed to switch guest protocol\n"); - } -} - -static void synaptics_pt_create(struct psmouse *psmouse) -{ - struct serio *serio; - - serio = kzalloc(sizeof(struct serio), GFP_KERNEL); - if (!serio) { - psmouse_err(psmouse, - "not enough memory for pass-through port\n"); - return; - } - - serio->id.type = SERIO_PS_PSTHRU; - strlcpy(serio->name, "Synaptics pass-through", sizeof(serio->name)); - strlcpy(serio->phys, "synaptics-pt/serio0", sizeof(serio->name)); - serio->write = synaptics_pt_write; - serio->start = synaptics_pt_start; - serio->stop = synaptics_pt_stop; - serio->parent = psmouse->ps2dev.serio; - - psmouse->pt_activate = synaptics_pt_activate; - - psmouse_info(psmouse, "serio: %s port at %s\n", - serio->name, psmouse->phys); - serio_register_port(serio); -} - -/***************************************************************************** - * Functions to interpret the absolute mode packets - ****************************************************************************/ - -static void synaptics_parse_agm(const unsigned char buf[], - struct synaptics_data *priv, - struct synaptics_hw_state *hw) -{ - struct synaptics_hw_state *agm = &priv->agm; - int agm_packet_type; - - agm_packet_type = (buf[5] & 0x30) >> 4; - switch (agm_packet_type) { - case 1: - /* Gesture packet: (x, y, z) half resolution */ - agm->w = hw->w; - agm->x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1; - agm->y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1; - agm->z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1; - break; - - case 2: - /* AGM-CONTACT packet: we are only interested in the count */ - priv->agm_count = buf[1]; - break; - - default: - break; - } -} - -static void synaptics_parse_ext_buttons(const unsigned char buf[], - struct synaptics_data *priv, - struct synaptics_hw_state *hw) -{ - unsigned int ext_bits = - (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1; - unsigned int ext_mask = GENMASK(ext_bits - 1, 0); - - hw->ext_buttons = buf[4] & ext_mask; - hw->ext_buttons |= (buf[5] & ext_mask) << ext_bits; -} - -static int synaptics_parse_hw_state(const unsigned char buf[], - struct synaptics_data *priv, - struct synaptics_hw_state *hw) -{ - memset(hw, 0, sizeof(struct synaptics_hw_state)); - - if (SYN_MODEL_NEWABS(priv->model_id)) { - hw->w = (((buf[0] & 0x30) >> 2) | - ((buf[0] & 0x04) >> 1) | - ((buf[3] & 0x04) >> 2)); - - if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) || - SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) && - hw->w == 2) { - synaptics_parse_agm(buf, priv, hw); - return 1; - } - - hw->x = (((buf[3] & 0x10) << 8) | - ((buf[1] & 0x0f) << 8) | - buf[4]); - hw->y = (((buf[3] & 0x20) << 7) | - ((buf[1] & 0xf0) << 4) | - buf[5]); - hw->z = buf[2]; - - hw->left = (buf[0] & 0x01) ? 1 : 0; - hw->right = (buf[0] & 0x02) ? 1 : 0; - - if (priv->is_forcepad) { - /* - * ForcePads, like Clickpads, use middle button - * bits to report primary button clicks. - * Unfortunately they report primary button not - * only when user presses on the pad above certain - * threshold, but also when there are more than one - * finger on the touchpad, which interferes with - * out multi-finger gestures. - */ - if (hw->z == 0) { - /* No contacts */ - priv->press = priv->report_press = false; - } else if (hw->w >= 4 && ((buf[0] ^ buf[3]) & 0x01)) { - /* - * Single-finger touch with pressure above - * the threshold. If pressure stays long - * enough, we'll start reporting primary - * button. We rely on the device continuing - * sending data even if finger does not - * move. - */ - if (!priv->press) { - priv->press_start = jiffies; - priv->press = true; - } else if (time_after(jiffies, - priv->press_start + - msecs_to_jiffies(50))) { - priv->report_press = true; - } - } else { - priv->press = false; - } - - hw->left = priv->report_press; - - } else if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { - /* - * Clickpad's button is transmitted as middle button, - * however, since it is primary button, we will report - * it as BTN_LEFT. - */ - hw->left = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; - - } else if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { - hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; - if (hw->w == 2) - hw->scroll = (signed char)(buf[1]); - } - - if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { - hw->up = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; - hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0; - } - - if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) > 0 && - ((buf[0] ^ buf[3]) & 0x02)) { - synaptics_parse_ext_buttons(buf, priv, hw); - } - } else { - hw->x = (((buf[1] & 0x1f) << 8) | buf[2]); - hw->y = (((buf[4] & 0x1f) << 8) | buf[5]); - - hw->z = (((buf[0] & 0x30) << 2) | (buf[3] & 0x3F)); - hw->w = (((buf[1] & 0x80) >> 4) | ((buf[0] & 0x04) >> 1)); - - hw->left = (buf[0] & 0x01) ? 1 : 0; - hw->right = (buf[0] & 0x02) ? 1 : 0; - } - - /* - * Convert wrap-around values to negative. (X|Y)_MAX_POSITIVE - * is used by some firmware to indicate a finger at the edge of - * the touchpad whose precise position cannot be determined, so - * convert these values to the maximum axis value. - */ - if (hw->x > X_MAX_POSITIVE) - hw->x -= 1 << ABS_POS_BITS; - else if (hw->x == X_MAX_POSITIVE) - hw->x = XMAX; - - if (hw->y > Y_MAX_POSITIVE) - hw->y -= 1 << ABS_POS_BITS; - else if (hw->y == Y_MAX_POSITIVE) - hw->y = YMAX; - - return 0; -} - -static void synaptics_report_semi_mt_slot(struct input_dev *dev, int slot, - bool active, int x, int y) -{ - input_mt_slot(dev, slot); - input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); - if (active) { - input_report_abs(dev, ABS_MT_POSITION_X, x); - input_report_abs(dev, ABS_MT_POSITION_Y, synaptics_invert_y(y)); - } -} - -static void synaptics_report_semi_mt_data(struct input_dev *dev, - const struct synaptics_hw_state *a, - const struct synaptics_hw_state *b, - int num_fingers) -{ - if (num_fingers >= 2) { - synaptics_report_semi_mt_slot(dev, 0, true, min(a->x, b->x), - min(a->y, b->y)); - synaptics_report_semi_mt_slot(dev, 1, true, max(a->x, b->x), - max(a->y, b->y)); - } else if (num_fingers == 1) { - synaptics_report_semi_mt_slot(dev, 0, true, a->x, a->y); - synaptics_report_semi_mt_slot(dev, 1, false, 0, 0); - } else { - synaptics_report_semi_mt_slot(dev, 0, false, 0, 0); - synaptics_report_semi_mt_slot(dev, 1, false, 0, 0); - } -} - -static void synaptics_report_ext_buttons(struct psmouse *psmouse, - const struct synaptics_hw_state *hw) -{ - struct input_dev *dev = psmouse->dev; - struct synaptics_data *priv = psmouse->private; - int ext_bits = (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) + 1) >> 1; - char buf[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - int i; - - if (!SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap)) - return; - - /* Bug in FW 8.1 & 8.2, buttons are reported only when ExtBit is 1 */ - if ((SYN_ID_FULL(priv->identity) == 0x801 || - SYN_ID_FULL(priv->identity) == 0x802) && - !((psmouse->packet[0] ^ psmouse->packet[3]) & 0x02)) - return; - - if (!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10)) { - for (i = 0; i < ext_bits; i++) { - input_report_key(dev, BTN_0 + 2 * i, - hw->ext_buttons & (1 << i)); - input_report_key(dev, BTN_1 + 2 * i, - hw->ext_buttons & (1 << (i + ext_bits))); - } - return; - } - - /* - * This generation of touchpads has the trackstick buttons - * physically wired to the touchpad. Re-route them through - * the pass-through interface. - */ - if (!priv->pt_port) - return; - - /* The trackstick expects at most 3 buttons */ - priv->pt_buttons = SYN_CAP_EXT_BUTTON_STICK_L(hw->ext_buttons) | - SYN_CAP_EXT_BUTTON_STICK_R(hw->ext_buttons) << 1 | - SYN_CAP_EXT_BUTTON_STICK_M(hw->ext_buttons) << 2; - - synaptics_pass_pt_packet(psmouse, priv->pt_port, buf); -} - -static void synaptics_report_buttons(struct psmouse *psmouse, - const struct synaptics_hw_state *hw) -{ - struct input_dev *dev = psmouse->dev; - struct synaptics_data *priv = psmouse->private; - - input_report_key(dev, BTN_LEFT, hw->left); - input_report_key(dev, BTN_RIGHT, hw->right); - - if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) - input_report_key(dev, BTN_MIDDLE, hw->middle); - - if (SYN_CAP_FOUR_BUTTON(priv->capabilities)) { - input_report_key(dev, BTN_FORWARD, hw->up); - input_report_key(dev, BTN_BACK, hw->down); - } - - synaptics_report_ext_buttons(psmouse, hw); -} - -static void synaptics_report_mt_data(struct psmouse *psmouse, - const struct synaptics_hw_state *sgm, - int num_fingers) -{ - struct input_dev *dev = psmouse->dev; - struct synaptics_data *priv = psmouse->private; - const struct synaptics_hw_state *hw[2] = { sgm, &priv->agm }; - struct input_mt_pos pos[2]; - int slot[2], nsemi, i; - - nsemi = clamp_val(num_fingers, 0, 2); - - for (i = 0; i < nsemi; i++) { - pos[i].x = hw[i]->x; - pos[i].y = synaptics_invert_y(hw[i]->y); - } - - input_mt_assign_slots(dev, slot, pos, nsemi, DMAX * priv->x_res); - - for (i = 0; i < nsemi; i++) { - input_mt_slot(dev, slot[i]); - input_mt_report_slot_state(dev, MT_TOOL_FINGER, true); - input_report_abs(dev, ABS_MT_POSITION_X, pos[i].x); - input_report_abs(dev, ABS_MT_POSITION_Y, pos[i].y); - input_report_abs(dev, ABS_MT_PRESSURE, hw[i]->z); - } - - input_mt_drop_unused(dev); - - /* Don't use active slot count to generate BTN_TOOL events. */ - input_mt_report_pointer_emulation(dev, false); - - /* Send the number of fingers reported by touchpad itself. */ - input_mt_report_finger_count(dev, num_fingers); - - synaptics_report_buttons(psmouse, sgm); - - input_sync(dev); -} - -static void synaptics_image_sensor_process(struct psmouse *psmouse, - struct synaptics_hw_state *sgm) -{ - struct synaptics_data *priv = psmouse->private; - int num_fingers; - - /* - * Update mt_state using the new finger count and current mt_state. - */ - if (sgm->z == 0) - num_fingers = 0; - else if (sgm->w >= 4) - num_fingers = 1; - else if (sgm->w == 0) - num_fingers = 2; - else if (sgm->w == 1) - num_fingers = priv->agm_count ? priv->agm_count : 3; - else - num_fingers = 4; - - /* Send resulting input events to user space */ - synaptics_report_mt_data(psmouse, sgm, num_fingers); -} - -/* - * called for each full received packet from the touchpad - */ -static void synaptics_process_packet(struct psmouse *psmouse) -{ - struct input_dev *dev = psmouse->dev; - struct synaptics_data *priv = psmouse->private; - struct synaptics_hw_state hw; - int num_fingers; - int finger_width; - - if (synaptics_parse_hw_state(psmouse->packet, priv, &hw)) - return; - - if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { - synaptics_image_sensor_process(psmouse, &hw); - return; - } - - if (hw.scroll) { - priv->scroll += hw.scroll; - - while (priv->scroll >= 4) { - input_report_key(dev, BTN_BACK, !hw.down); - input_sync(dev); - input_report_key(dev, BTN_BACK, hw.down); - input_sync(dev); - priv->scroll -= 4; - } - while (priv->scroll <= -4) { - input_report_key(dev, BTN_FORWARD, !hw.up); - input_sync(dev); - input_report_key(dev, BTN_FORWARD, hw.up); - input_sync(dev); - priv->scroll += 4; - } - return; - } - - if (hw.z > 0 && hw.x > 1) { - num_fingers = 1; - finger_width = 5; - if (SYN_CAP_EXTENDED(priv->capabilities)) { - switch (hw.w) { - case 0 ... 1: - if (SYN_CAP_MULTIFINGER(priv->capabilities)) - num_fingers = hw.w + 2; - break; - case 2: - if (SYN_MODEL_PEN(priv->model_id)) - ; /* Nothing, treat a pen as a single finger */ - break; - case 4 ... 15: - if (SYN_CAP_PALMDETECT(priv->capabilities)) - finger_width = hw.w; - break; - } - } - } else { - num_fingers = 0; - finger_width = 0; - } - - if (cr48_profile_sensor) { - synaptics_report_mt_data(psmouse, &hw, num_fingers); - return; - } - - if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) - synaptics_report_semi_mt_data(dev, &hw, &priv->agm, - num_fingers); - - /* Post events - * BTN_TOUCH has to be first as mousedev relies on it when doing - * absolute -> relative conversion - */ - if (hw.z > 30) input_report_key(dev, BTN_TOUCH, 1); - if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0); - - if (num_fingers > 0) { - input_report_abs(dev, ABS_X, hw.x); - input_report_abs(dev, ABS_Y, synaptics_invert_y(hw.y)); - } - input_report_abs(dev, ABS_PRESSURE, hw.z); - - if (SYN_CAP_PALMDETECT(priv->capabilities)) - input_report_abs(dev, ABS_TOOL_WIDTH, finger_width); - - input_report_key(dev, BTN_TOOL_FINGER, num_fingers == 1); - if (SYN_CAP_MULTIFINGER(priv->capabilities)) { - input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); - input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3); - } - - synaptics_report_buttons(psmouse, &hw); - - input_sync(dev); -} - -static int synaptics_validate_byte(struct psmouse *psmouse, - int idx, unsigned char pkt_type) -{ - static const unsigned char newabs_mask[] = { 0xC8, 0x00, 0x00, 0xC8, 0x00 }; - static const unsigned char newabs_rel_mask[] = { 0xC0, 0x00, 0x00, 0xC0, 0x00 }; - static const unsigned char newabs_rslt[] = { 0x80, 0x00, 0x00, 0xC0, 0x00 }; - static const unsigned char oldabs_mask[] = { 0xC0, 0x60, 0x00, 0xC0, 0x60 }; - static const unsigned char oldabs_rslt[] = { 0xC0, 0x00, 0x00, 0x80, 0x00 }; - const char *packet = psmouse->packet; - - if (idx < 0 || idx > 4) - return 0; - - switch (pkt_type) { - - case SYN_NEWABS: - case SYN_NEWABS_RELAXED: - return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx]; - - case SYN_NEWABS_STRICT: - return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx]; - - case SYN_OLDABS: - return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx]; - - default: - psmouse_err(psmouse, "unknown packet type %d\n", pkt_type); - return 0; - } -} - -static unsigned char synaptics_detect_pkt_type(struct psmouse *psmouse) -{ - int i; - - for (i = 0; i < 5; i++) - if (!synaptics_validate_byte(psmouse, i, SYN_NEWABS_STRICT)) { - psmouse_info(psmouse, "using relaxed packet validation\n"); - return SYN_NEWABS_RELAXED; - } - - return SYN_NEWABS_STRICT; -} - -static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse) -{ - struct synaptics_data *priv = psmouse->private; - - if (psmouse->pktcnt >= 6) { /* Full packet received */ - if (unlikely(priv->pkt_type == SYN_NEWABS)) - priv->pkt_type = synaptics_detect_pkt_type(psmouse); - - if (SYN_CAP_PASS_THROUGH(priv->capabilities) && - synaptics_is_pt_packet(psmouse->packet)) { - if (priv->pt_port) - synaptics_pass_pt_packet(psmouse, priv->pt_port, - psmouse->packet); - } else - synaptics_process_packet(psmouse); - - return PSMOUSE_FULL_PACKET; - } - - return synaptics_validate_byte(psmouse, psmouse->pktcnt - 1, priv->pkt_type) ? - PSMOUSE_GOOD_DATA : PSMOUSE_BAD_DATA; -} - -/***************************************************************************** - * Driver initialization/cleanup functions - ****************************************************************************/ -static void set_abs_position_params(struct input_dev *dev, - struct synaptics_data *priv, int x_code, - int y_code) -{ - int x_min = priv->x_min ?: XMIN_NOMINAL; - int x_max = priv->x_max ?: XMAX_NOMINAL; - int y_min = priv->y_min ?: YMIN_NOMINAL; - int y_max = priv->y_max ?: YMAX_NOMINAL; - int fuzz = SYN_CAP_REDUCED_FILTERING(priv->ext_cap_0c) ? - SYN_REDUCED_FILTER_FUZZ : 0; - - input_set_abs_params(dev, x_code, x_min, x_max, fuzz, 0); - input_set_abs_params(dev, y_code, y_min, y_max, fuzz, 0); - input_abs_set_res(dev, x_code, priv->x_res); - input_abs_set_res(dev, y_code, priv->y_res); -} - -static void set_input_params(struct psmouse *psmouse, - struct synaptics_data *priv) -{ - struct input_dev *dev = psmouse->dev; - int i; - - /* Things that apply to both modes */ - __set_bit(INPUT_PROP_POINTER, dev->propbit); - __set_bit(EV_KEY, dev->evbit); - __set_bit(BTN_LEFT, dev->keybit); - __set_bit(BTN_RIGHT, dev->keybit); - - if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) - __set_bit(BTN_MIDDLE, dev->keybit); - - if (!priv->absolute_mode) { - /* Relative mode */ - __set_bit(EV_REL, dev->evbit); - __set_bit(REL_X, dev->relbit); - __set_bit(REL_Y, dev->relbit); - return; - } - - /* Absolute mode */ - __set_bit(EV_ABS, dev->evbit); - set_abs_position_params(dev, priv, ABS_X, ABS_Y); - input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); - - if (cr48_profile_sensor) - input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); - - if (SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) { - set_abs_position_params(dev, priv, ABS_MT_POSITION_X, - ABS_MT_POSITION_Y); - /* Image sensors can report per-contact pressure */ - input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); - input_mt_init_slots(dev, 2, INPUT_MT_POINTER | INPUT_MT_TRACK); - - /* Image sensors can signal 4 and 5 finger clicks */ - __set_bit(BTN_TOOL_QUADTAP, dev->keybit); - __set_bit(BTN_TOOL_QUINTTAP, dev->keybit); - } else if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { - set_abs_position_params(dev, priv, ABS_MT_POSITION_X, - ABS_MT_POSITION_Y); - /* - * Profile sensor in CR-48 tracks contacts reasonably well, - * other non-image sensors with AGM use semi-mt. - */ - input_mt_init_slots(dev, 2, - INPUT_MT_POINTER | - (cr48_profile_sensor ? - INPUT_MT_TRACK : INPUT_MT_SEMI_MT)); - } - - if (SYN_CAP_PALMDETECT(priv->capabilities)) - input_set_abs_params(dev, ABS_TOOL_WIDTH, 0, 15, 0, 0); - - __set_bit(BTN_TOUCH, dev->keybit); - __set_bit(BTN_TOOL_FINGER, dev->keybit); - - if (SYN_CAP_MULTIFINGER(priv->capabilities)) { - __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); - __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); - } - - if (SYN_CAP_FOUR_BUTTON(priv->capabilities) || - SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { - __set_bit(BTN_FORWARD, dev->keybit); - __set_bit(BTN_BACK, dev->keybit); - } - - if (!SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10)) - for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++) - __set_bit(BTN_0 + i, dev->keybit); - - __clear_bit(EV_REL, dev->evbit); - __clear_bit(REL_X, dev->relbit); - __clear_bit(REL_Y, dev->relbit); - - if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { - __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit); - if (psmouse_matches_pnp_id(psmouse, topbuttonpad_pnp_ids) && - !SYN_CAP_EXT_BUTTONS_STICK(priv->ext_cap_10)) - __set_bit(INPUT_PROP_TOPBUTTONPAD, dev->propbit); - /* Clickpads report only left button */ - __clear_bit(BTN_RIGHT, dev->keybit); - __clear_bit(BTN_MIDDLE, dev->keybit); - } -} - -static ssize_t synaptics_show_disable_gesture(struct psmouse *psmouse, - void *data, char *buf) -{ - struct synaptics_data *priv = psmouse->private; - - return sprintf(buf, "%c\n", priv->disable_gesture ? '1' : '0'); -} - -static ssize_t synaptics_set_disable_gesture(struct psmouse *psmouse, - void *data, const char *buf, - size_t len) -{ - struct synaptics_data *priv = psmouse->private; - unsigned int value; - int err; - - err = kstrtouint(buf, 10, &value); - if (err) - return err; - - if (value > 1) - return -EINVAL; - - if (value == priv->disable_gesture) - return len; - - priv->disable_gesture = value; - if (value) - priv->mode |= SYN_BIT_DISABLE_GESTURE; - else - priv->mode &= ~SYN_BIT_DISABLE_GESTURE; - - if (synaptics_mode_cmd(psmouse, priv->mode)) - return -EIO; - - return len; -} - -PSMOUSE_DEFINE_ATTR(disable_gesture, S_IWUSR | S_IRUGO, NULL, - synaptics_show_disable_gesture, - synaptics_set_disable_gesture); - -static void synaptics_disconnect(struct psmouse *psmouse) -{ - struct synaptics_data *priv = psmouse->private; - - if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->identity)) - device_remove_file(&psmouse->ps2dev.serio->dev, - &psmouse_attr_disable_gesture.dattr); - - synaptics_reset(psmouse); - kfree(priv); - psmouse->private = NULL; -} - -static int synaptics_reconnect(struct psmouse *psmouse) -{ - struct synaptics_data *priv = psmouse->private; - struct synaptics_data old_priv = *priv; - unsigned char param[2]; - int retry = 0; - int error; - - do { - psmouse_reset(psmouse); - if (retry) { - /* - * On some boxes, right after resuming, the touchpad - * needs some time to finish initializing (I assume - * it needs time to calibrate) and start responding - * to Synaptics-specific queries, so let's wait a - * bit. - */ - ssleep(1); - } - ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETID); - error = synaptics_detect(psmouse, 0); - } while (error && ++retry < 3); - - if (error) - return -1; - - if (retry > 1) - psmouse_dbg(psmouse, "reconnected after %d tries\n", retry); - - if (synaptics_query_hardware(psmouse)) { - psmouse_err(psmouse, "Unable to query device.\n"); - return -1; - } - - if (synaptics_set_mode(psmouse)) { - psmouse_err(psmouse, "Unable to initialize device.\n"); - return -1; - } - - if (old_priv.identity != priv->identity || - old_priv.model_id != priv->model_id || - old_priv.capabilities != priv->capabilities || - old_priv.ext_cap != priv->ext_cap) { - psmouse_err(psmouse, - "hardware appears to be different: id(%ld-%ld), model(%ld-%ld), caps(%lx-%lx), ext(%lx-%lx).\n", - old_priv.identity, priv->identity, - old_priv.model_id, priv->model_id, - old_priv.capabilities, priv->capabilities, - old_priv.ext_cap, priv->ext_cap); - return -1; - } - - return 0; -} - -static bool impaired_toshiba_kbc; - -static const struct dmi_system_id toshiba_dmi_table[] __initconst = { -#if defined(CONFIG_DMI) && defined(CONFIG_X86) - { - /* Toshiba Satellite */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_NAME, "Satellite"), - }, - }, - { - /* Toshiba Dynabook */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_NAME, "dynabook"), - }, - }, - { - /* Toshiba Portege M300 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M300"), - }, - - }, - { - /* Toshiba Portege M300 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_NAME, "Portable PC"), - DMI_MATCH(DMI_PRODUCT_VERSION, "Version 1.0"), - }, - - }, -#endif - { } -}; - -static bool broken_olpc_ec; - -static const struct dmi_system_id olpc_dmi_table[] __initconst = { -#if defined(CONFIG_DMI) && defined(CONFIG_OLPC) - { - /* OLPC XO-1 or XO-1.5 */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "OLPC"), - DMI_MATCH(DMI_PRODUCT_NAME, "XO"), - }, - }, -#endif - { } -}; - -static const struct dmi_system_id __initconst cr48_dmi_table[] = { -#if defined(CONFIG_DMI) && defined(CONFIG_X86) - { - /* Cr-48 Chromebook (Codename Mario) */ - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "IEC"), - DMI_MATCH(DMI_PRODUCT_NAME, "Mario"), - }, - }, -#endif - { } -}; - -void __init synaptics_module_init(void) -{ - impaired_toshiba_kbc = dmi_check_system(toshiba_dmi_table); - broken_olpc_ec = dmi_check_system(olpc_dmi_table); - cr48_profile_sensor = dmi_check_system(cr48_dmi_table); -} - -static int __synaptics_init(struct psmouse *psmouse, bool absolute_mode) -{ - struct synaptics_data *priv; - int err = -1; - - /* - * The OLPC XO has issues with Synaptics' absolute mode; the constant - * packet spew overloads the EC such that key presses on the keyboard - * are missed. Given that, don't even attempt to use Absolute mode. - * Relative mode seems to work just fine. - */ - if (absolute_mode && broken_olpc_ec) { - psmouse_info(psmouse, - "OLPC XO detected, not enabling Synaptics protocol.\n"); - return -ENODEV; - } - - psmouse->private = priv = kzalloc(sizeof(struct synaptics_data), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - psmouse_reset(psmouse); - - if (synaptics_query_hardware(psmouse)) { - psmouse_err(psmouse, "Unable to query device.\n"); - goto init_fail; - } - - priv->absolute_mode = absolute_mode; - if (SYN_ID_DISGEST_SUPPORTED(priv->identity)) - priv->disable_gesture = true; - - /* - * Unfortunately ForcePad capability is not exported over PS/2, - * so we have to resort to checking PNP IDs. - */ - priv->is_forcepad = psmouse_matches_pnp_id(psmouse, forcepad_pnp_ids); - - if (synaptics_set_mode(psmouse)) { - psmouse_err(psmouse, "Unable to initialize device.\n"); - goto init_fail; - } - - priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; - - psmouse_info(psmouse, - "Touchpad model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx/%#lx, board id: %lu, fw id: %lu\n", - SYN_ID_MODEL(priv->identity), - SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity), - priv->model_id, - priv->capabilities, priv->ext_cap, priv->ext_cap_0c, - priv->ext_cap_10, priv->board_id, priv->firmware_id); - - set_input_params(psmouse, priv); - - /* - * Encode touchpad model so that it can be used to set - * input device->id.version and be visible to userspace. - * Because version is __u16 we have to drop something. - * Hardware info bits seem to be good candidates as they - * are documented to be for Synaptics corp. internal use. - */ - psmouse->model = ((priv->model_id & 0x00ff0000) >> 8) | - (priv->model_id & 0x000000ff); - - if (absolute_mode) { - psmouse->protocol_handler = synaptics_process_byte; - psmouse->pktsize = 6; - } else { - /* Relative mode follows standard PS/2 mouse protocol */ - psmouse->protocol_handler = psmouse_process_byte; - psmouse->pktsize = 3; - } - - psmouse->set_rate = synaptics_set_rate; - psmouse->disconnect = synaptics_disconnect; - psmouse->reconnect = synaptics_reconnect; - psmouse->cleanup = synaptics_reset; - /* Synaptics can usually stay in sync without extra help */ - psmouse->resync_time = 0; - - if (SYN_CAP_PASS_THROUGH(priv->capabilities)) - synaptics_pt_create(psmouse); - - /* - * Toshiba's KBC seems to have trouble handling data from - * Synaptics at full rate. Switch to a lower rate (roughly - * the same rate as a standard PS/2 mouse). - */ - if (psmouse->rate >= 80 && impaired_toshiba_kbc) { - psmouse_info(psmouse, - "Toshiba %s detected, limiting rate to 40pps.\n", - dmi_get_system_info(DMI_PRODUCT_NAME)); - psmouse->rate = 40; - } - - if (!priv->absolute_mode && SYN_ID_DISGEST_SUPPORTED(priv->identity)) { - err = device_create_file(&psmouse->ps2dev.serio->dev, - &psmouse_attr_disable_gesture.dattr); - if (err) { - psmouse_err(psmouse, - "Failed to create disable_gesture attribute (%d)", - err); - goto init_fail; - } - } - - return 0; - - init_fail: - kfree(priv); - return err; -} - -int synaptics_init(struct psmouse *psmouse) -{ - return __synaptics_init(psmouse, true); -} - -int synaptics_init_relative(struct psmouse *psmouse) -{ - return __synaptics_init(psmouse, false); -} - -#else /* CONFIG_MOUSE_PS2_SYNAPTICS */ - -void __init synaptics_module_init(void) -{ -} - -int synaptics_init(struct psmouse *psmouse) -{ - return -ENOSYS; -} - -#endif /* CONFIG_MOUSE_PS2_SYNAPTICS */ diff --git a/src/linux/drivers/input/mouse/synaptics.h b/src/linux/drivers/input/mouse/synaptics.h deleted file mode 100644 index 56faa7e..0000000 --- a/src/linux/drivers/input/mouse/synaptics.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Synaptics TouchPad PS/2 mouse driver - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#ifndef _SYNAPTICS_H -#define _SYNAPTICS_H - -/* synaptics queries */ -#define SYN_QUE_IDENTIFY 0x00 -#define SYN_QUE_MODES 0x01 -#define SYN_QUE_CAPABILITIES 0x02 -#define SYN_QUE_MODEL 0x03 -#define SYN_QUE_SERIAL_NUMBER_PREFIX 0x06 -#define SYN_QUE_SERIAL_NUMBER_SUFFIX 0x07 -#define SYN_QUE_RESOLUTION 0x08 -#define SYN_QUE_EXT_CAPAB 0x09 -#define SYN_QUE_FIRMWARE_ID 0x0a -#define SYN_QUE_EXT_CAPAB_0C 0x0c -#define SYN_QUE_EXT_MAX_COORDS 0x0d -#define SYN_QUE_EXT_MIN_COORDS 0x0f -#define SYN_QUE_MEXT_CAPAB_10 0x10 - -/* synatics modes */ -#define SYN_BIT_ABSOLUTE_MODE (1 << 7) -#define SYN_BIT_HIGH_RATE (1 << 6) -#define SYN_BIT_SLEEP_MODE (1 << 3) -#define SYN_BIT_DISABLE_GESTURE (1 << 2) -#define SYN_BIT_FOUR_BYTE_CLIENT (1 << 1) -#define SYN_BIT_W_MODE (1 << 0) - -/* synaptics model ID bits */ -#define SYN_MODEL_ROT180(m) ((m) & (1 << 23)) -#define SYN_MODEL_PORTRAIT(m) ((m) & (1 << 22)) -#define SYN_MODEL_SENSOR(m) (((m) >> 16) & 0x3f) -#define SYN_MODEL_HARDWARE(m) (((m) >> 9) & 0x7f) -#define SYN_MODEL_NEWABS(m) ((m) & (1 << 7)) -#define SYN_MODEL_PEN(m) ((m) & (1 << 6)) -#define SYN_MODEL_SIMPLIC(m) ((m) & (1 << 5)) -#define SYN_MODEL_GEOMETRY(m) ((m) & 0x0f) - -/* synaptics capability bits */ -#define SYN_CAP_EXTENDED(c) ((c) & (1 << 23)) -#define SYN_CAP_MIDDLE_BUTTON(c) ((c) & (1 << 18)) -#define SYN_CAP_PASS_THROUGH(c) ((c) & (1 << 7)) -#define SYN_CAP_SLEEP(c) ((c) & (1 << 4)) -#define SYN_CAP_FOUR_BUTTON(c) ((c) & (1 << 3)) -#define SYN_CAP_MULTIFINGER(c) ((c) & (1 << 1)) -#define SYN_CAP_PALMDETECT(c) ((c) & (1 << 0)) -#define SYN_CAP_SUBMODEL_ID(c) (((c) & 0x00ff00) >> 8) -#define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20) -#define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12) -#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16) -#define SYN_MEXT_CAP_BIT(m) ((m) & (1 << 1)) - -/* - * The following describes response for the 0x0c query. - * - * byte mask name meaning - * ---- ---- ------- ------------ - * 1 0x01 adjustable threshold capacitive button sensitivity - * can be adjusted - * 1 0x02 report max query 0x0d gives max coord reported - * 1 0x04 clearpad sensor is ClearPad product - * 1 0x08 advanced gesture not particularly meaningful - * 1 0x10 clickpad bit 0 1-button ClickPad - * 1 0x60 multifinger mode identifies firmware finger counting - * (not reporting!) algorithm. - * Not particularly meaningful - * 1 0x80 covered pad W clipped to 14, 15 == pad mostly covered - * 2 0x01 clickpad bit 1 2-button ClickPad - * 2 0x02 deluxe LED controls touchpad support LED commands - * ala multimedia control bar - * 2 0x04 reduced filtering firmware does less filtering on - * position data, driver should watch - * for noise. - * 2 0x08 image sensor image sensor tracks 5 fingers, but only - * reports 2. - * 2 0x01 uniform clickpad whole clickpad moves instead of being - * hinged at the top. - * 2 0x20 report min query 0x0f gives min coord reported - */ -#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */ -#define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */ -#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000) -#define SYN_CAP_MIN_DIMENSIONS(ex0c) ((ex0c) & 0x002000) -#define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000) -#define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400) -#define SYN_CAP_IMAGE_SENSOR(ex0c) ((ex0c) & 0x000800) - -/* - * The following descibes response for the 0x10 query. - * - * byte mask name meaning - * ---- ---- ------- ------------ - * 1 0x01 ext buttons are stick buttons exported in the extended - * capability are actually meant to be used - * by the tracktick (pass-through). - * 1 0x02 SecurePad the touchpad is a SecurePad, so it - * contains a built-in fingerprint reader. - * 1 0xe0 more ext count how many more extented queries are - * available after this one. - * 2 0xff SecurePad width the width of the SecurePad fingerprint - * reader. - * 3 0xff SecurePad height the height of the SecurePad fingerprint - * reader. - */ -#define SYN_CAP_EXT_BUTTONS_STICK(ex10) ((ex10) & 0x010000) -#define SYN_CAP_SECUREPAD(ex10) ((ex10) & 0x020000) - -#define SYN_CAP_EXT_BUTTON_STICK_L(eb) (!!((eb) & 0x01)) -#define SYN_CAP_EXT_BUTTON_STICK_M(eb) (!!((eb) & 0x02)) -#define SYN_CAP_EXT_BUTTON_STICK_R(eb) (!!((eb) & 0x04)) - -/* synaptics modes query bits */ -#define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) -#define SYN_MODE_RATE(m) ((m) & (1 << 6)) -#define SYN_MODE_BAUD_SLEEP(m) ((m) & (1 << 3)) -#define SYN_MODE_DISABLE_GESTURE(m) ((m) & (1 << 2)) -#define SYN_MODE_PACKSIZE(m) ((m) & (1 << 1)) -#define SYN_MODE_WMODE(m) ((m) & (1 << 0)) - -/* synaptics identify query bits */ -#define SYN_ID_MODEL(i) (((i) >> 4) & 0x0f) -#define SYN_ID_MAJOR(i) ((i) & 0x0f) -#define SYN_ID_MINOR(i) (((i) >> 16) & 0xff) -#define SYN_ID_FULL(i) ((SYN_ID_MAJOR(i) << 8) | SYN_ID_MINOR(i)) -#define SYN_ID_IS_SYNAPTICS(i) ((((i) >> 8) & 0xff) == 0x47) -#define SYN_ID_DISGEST_SUPPORTED(i) (SYN_ID_MAJOR(i) >= 4) - -/* synaptics special commands */ -#define SYN_PS_SET_MODE2 0x14 -#define SYN_PS_CLIENT_CMD 0x28 - -/* synaptics packet types */ -#define SYN_NEWABS 0 -#define SYN_NEWABS_STRICT 1 -#define SYN_NEWABS_RELAXED 2 -#define SYN_OLDABS 3 - -/* amount to fuzz position data when touchpad reports reduced filtering */ -#define SYN_REDUCED_FILTER_FUZZ 8 - -/* - * A structure to describe the state of the touchpad hardware (buttons and pad) - */ -struct synaptics_hw_state { - int x; - int y; - int z; - int w; - unsigned int left:1; - unsigned int right:1; - unsigned int middle:1; - unsigned int up:1; - unsigned int down:1; - unsigned char ext_buttons; - signed char scroll; -}; - -struct synaptics_data { - /* Data read from the touchpad */ - unsigned long int model_id; /* Model-ID */ - unsigned long int firmware_id; /* Firmware-ID */ - unsigned long int board_id; /* Board-ID */ - unsigned long int capabilities; /* Capabilities */ - unsigned long int ext_cap; /* Extended Capabilities */ - unsigned long int ext_cap_0c; /* Ext Caps from 0x0c query */ - unsigned long int ext_cap_10; /* Ext Caps from 0x10 query */ - unsigned long int identity; /* Identification */ - unsigned int x_res, y_res; /* X/Y resolution in units/mm */ - unsigned int x_max, y_max; /* Max coordinates (from FW) */ - unsigned int x_min, y_min; /* Min coordinates (from FW) */ - - unsigned char pkt_type; /* packet type - old, new, etc */ - unsigned char mode; /* current mode byte */ - int scroll; - - bool absolute_mode; /* run in Absolute mode */ - bool disable_gesture; /* disable gestures */ - - struct serio *pt_port; /* Pass-through serio port */ - unsigned char pt_buttons; /* Pass-through buttons */ - - /* - * Last received Advanced Gesture Mode (AGM) packet. An AGM packet - * contains position data for a second contact, at half resolution. - */ - struct synaptics_hw_state agm; - unsigned int agm_count; /* finger count reported by agm */ - - /* ForcePad handling */ - unsigned long press_start; - bool press; - bool report_press; - bool is_forcepad; -}; - -void synaptics_module_init(void); -int synaptics_detect(struct psmouse *psmouse, bool set_properties); -int synaptics_init(struct psmouse *psmouse); -int synaptics_init_relative(struct psmouse *psmouse); -void synaptics_reset(struct psmouse *psmouse); - -#endif /* _SYNAPTICS_H */ diff --git a/src/linux/drivers/input/mouse/touchkit_ps2.h b/src/linux/drivers/input/mouse/touchkit_ps2.h deleted file mode 100644 index 2efe9ea..0000000 --- a/src/linux/drivers/input/mouse/touchkit_ps2.h +++ /dev/null @@ -1,25 +0,0 @@ -/* ---------------------------------------------------------------------------- - * touchkit_ps2.h -- Driver for eGalax TouchKit PS/2 Touchscreens - * - * Copyright (C) 2005 by Stefan Lucke - * Copyright (c) 2005 Vojtech Pavlik - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#ifndef _TOUCHKIT_PS2_H -#define _TOUCHKIT_PS2_H - -#ifdef CONFIG_MOUSE_PS2_TOUCHKIT -int touchkit_ps2_detect(struct psmouse *psmouse, bool set_properties); -#else -static inline int touchkit_ps2_detect(struct psmouse *psmouse, - bool set_properties) -{ - return -ENOSYS; -} -#endif /* CONFIG_MOUSE_PS2_TOUCHKIT */ - -#endif diff --git a/src/linux/drivers/input/mouse/trackpoint.c b/src/linux/drivers/input/mouse/trackpoint.c deleted file mode 100644 index 354d47e..0000000 --- a/src/linux/drivers/input/mouse/trackpoint.c +++ /dev/null @@ -1,428 +0,0 @@ -/* - * Stephen Evanchik - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - * - * Trademarks are the property of their respective owners. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "psmouse.h" -#include "trackpoint.h" - -/* - * Power-on Reset: Resets all trackpoint parameters, including RAM values, - * to defaults. - * Returns zero on success, non-zero on failure. - */ -static int trackpoint_power_on_reset(struct ps2dev *ps2dev) -{ - unsigned char results[2]; - int tries = 0; - - /* Issue POR command, and repeat up to once if 0xFC00 received */ - do { - if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || - ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 2, TP_POR))) - return -1; - } while (results[0] == 0xFC && results[1] == 0x00 && ++tries < 2); - - /* Check for success response -- 0xAA00 */ - if (results[0] != 0xAA || results[1] != 0x00) - return -1; - - return 0; -} - -/* - * Device IO: read, write and toggle bit - */ -static int trackpoint_read(struct ps2dev *ps2dev, - unsigned char loc, unsigned char *results) -{ - if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || - ps2_command(ps2dev, results, MAKE_PS2_CMD(0, 1, loc))) { - return -1; - } - - return 0; -} - -static int trackpoint_write(struct ps2dev *ps2dev, - unsigned char loc, unsigned char val) -{ - if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || - ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_WRITE_MEM)) || - ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) || - ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, val))) { - return -1; - } - - return 0; -} - -static int trackpoint_toggle_bit(struct ps2dev *ps2dev, - unsigned char loc, unsigned char mask) -{ - /* Bad things will happen if the loc param isn't in this range */ - if (loc < 0x20 || loc >= 0x2F) - return -1; - - if (ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_COMMAND)) || - ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, TP_TOGGLE)) || - ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, loc)) || - ps2_command(ps2dev, NULL, MAKE_PS2_CMD(0, 0, mask))) { - return -1; - } - - return 0; -} - -static int trackpoint_update_bit(struct ps2dev *ps2dev, unsigned char loc, - unsigned char mask, unsigned char value) -{ - int retval = 0; - unsigned char data; - - trackpoint_read(ps2dev, loc, &data); - if (((data & mask) == mask) != !!value) - retval = trackpoint_toggle_bit(ps2dev, loc, mask); - - return retval; -} - -/* - * Trackpoint-specific attributes - */ -struct trackpoint_attr_data { - size_t field_offset; - unsigned char command; - unsigned char mask; - unsigned char inverted; - unsigned char power_on_default; -}; - -static ssize_t trackpoint_show_int_attr(struct psmouse *psmouse, void *data, char *buf) -{ - struct trackpoint_data *tp = psmouse->private; - struct trackpoint_attr_data *attr = data; - unsigned char value = *(unsigned char *)((char *)tp + attr->field_offset); - - if (attr->inverted) - value = !value; - - return sprintf(buf, "%u\n", value); -} - -static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data, - const char *buf, size_t count) -{ - struct trackpoint_data *tp = psmouse->private; - struct trackpoint_attr_data *attr = data; - unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset); - unsigned char value; - int err; - - err = kstrtou8(buf, 10, &value); - if (err) - return err; - - *field = value; - trackpoint_write(&psmouse->ps2dev, attr->command, value); - - return count; -} - -#define TRACKPOINT_INT_ATTR(_name, _command, _default) \ - static struct trackpoint_attr_data trackpoint_attr_##_name = { \ - .field_offset = offsetof(struct trackpoint_data, _name), \ - .command = _command, \ - .power_on_default = _default, \ - }; \ - PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ - &trackpoint_attr_##_name, \ - trackpoint_show_int_attr, trackpoint_set_int_attr) - -static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data, - const char *buf, size_t count) -{ - struct trackpoint_data *tp = psmouse->private; - struct trackpoint_attr_data *attr = data; - unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset); - unsigned int value; - int err; - - err = kstrtouint(buf, 10, &value); - if (err) - return err; - - if (value > 1) - return -EINVAL; - - if (attr->inverted) - value = !value; - - if (*field != value) { - *field = value; - trackpoint_toggle_bit(&psmouse->ps2dev, attr->command, attr->mask); - } - - return count; -} - - -#define TRACKPOINT_BIT_ATTR(_name, _command, _mask, _inv, _default) \ -static struct trackpoint_attr_data trackpoint_attr_##_name = { \ - .field_offset = offsetof(struct trackpoint_data, \ - _name), \ - .command = _command, \ - .mask = _mask, \ - .inverted = _inv, \ - .power_on_default = _default, \ - }; \ -PSMOUSE_DEFINE_ATTR(_name, S_IWUSR | S_IRUGO, \ - &trackpoint_attr_##_name, \ - trackpoint_show_int_attr, trackpoint_set_bit_attr) - -#define TRACKPOINT_UPDATE_BIT(_psmouse, _tp, _name) \ -do { \ - struct trackpoint_attr_data *_attr = &trackpoint_attr_##_name; \ - \ - trackpoint_update_bit(&_psmouse->ps2dev, \ - _attr->command, _attr->mask, _tp->_name); \ -} while (0) - -#define TRACKPOINT_UPDATE(_power_on, _psmouse, _tp, _name) \ -do { \ - if (!_power_on || \ - _tp->_name != trackpoint_attr_##_name.power_on_default) { \ - if (!trackpoint_attr_##_name.mask) \ - trackpoint_write(&_psmouse->ps2dev, \ - trackpoint_attr_##_name.command, \ - _tp->_name); \ - else \ - TRACKPOINT_UPDATE_BIT(_psmouse, _tp, _name); \ - } \ -} while (0) - -#define TRACKPOINT_SET_POWER_ON_DEFAULT(_tp, _name) \ - (_tp->_name = trackpoint_attr_##_name.power_on_default) - -TRACKPOINT_INT_ATTR(sensitivity, TP_SENS, TP_DEF_SENS); -TRACKPOINT_INT_ATTR(speed, TP_SPEED, TP_DEF_SPEED); -TRACKPOINT_INT_ATTR(inertia, TP_INERTIA, TP_DEF_INERTIA); -TRACKPOINT_INT_ATTR(reach, TP_REACH, TP_DEF_REACH); -TRACKPOINT_INT_ATTR(draghys, TP_DRAGHYS, TP_DEF_DRAGHYS); -TRACKPOINT_INT_ATTR(mindrag, TP_MINDRAG, TP_DEF_MINDRAG); -TRACKPOINT_INT_ATTR(thresh, TP_THRESH, TP_DEF_THRESH); -TRACKPOINT_INT_ATTR(upthresh, TP_UP_THRESH, TP_DEF_UP_THRESH); -TRACKPOINT_INT_ATTR(ztime, TP_Z_TIME, TP_DEF_Z_TIME); -TRACKPOINT_INT_ATTR(jenks, TP_JENKS_CURV, TP_DEF_JENKS_CURV); -TRACKPOINT_INT_ATTR(drift_time, TP_DRIFT_TIME, TP_DEF_DRIFT_TIME); - -TRACKPOINT_BIT_ATTR(press_to_select, TP_TOGGLE_PTSON, TP_MASK_PTSON, 0, - TP_DEF_PTSON); -TRACKPOINT_BIT_ATTR(skipback, TP_TOGGLE_SKIPBACK, TP_MASK_SKIPBACK, 0, - TP_DEF_SKIPBACK); -TRACKPOINT_BIT_ATTR(ext_dev, TP_TOGGLE_EXT_DEV, TP_MASK_EXT_DEV, 1, - TP_DEF_EXT_DEV); - -static struct attribute *trackpoint_attrs[] = { - &psmouse_attr_sensitivity.dattr.attr, - &psmouse_attr_speed.dattr.attr, - &psmouse_attr_inertia.dattr.attr, - &psmouse_attr_reach.dattr.attr, - &psmouse_attr_draghys.dattr.attr, - &psmouse_attr_mindrag.dattr.attr, - &psmouse_attr_thresh.dattr.attr, - &psmouse_attr_upthresh.dattr.attr, - &psmouse_attr_ztime.dattr.attr, - &psmouse_attr_jenks.dattr.attr, - &psmouse_attr_drift_time.dattr.attr, - &psmouse_attr_press_to_select.dattr.attr, - &psmouse_attr_skipback.dattr.attr, - &psmouse_attr_ext_dev.dattr.attr, - NULL -}; - -static struct attribute_group trackpoint_attr_group = { - .attrs = trackpoint_attrs, -}; - -static int trackpoint_start_protocol(struct psmouse *psmouse, unsigned char *firmware_id) -{ - unsigned char param[2] = { 0 }; - - if (ps2_command(&psmouse->ps2dev, param, MAKE_PS2_CMD(0, 2, TP_READ_ID))) - return -1; - - if (param[0] != TP_MAGIC_IDENT) - return -1; - - if (firmware_id) - *firmware_id = param[1]; - - return 0; -} - -/* - * Write parameters to trackpad. - * in_power_on_state: Set to true if TP is in default / power-on state (ex. if - * power-on reset was run). If so, values will only be - * written to TP if they differ from power-on default. - */ -static int trackpoint_sync(struct psmouse *psmouse, bool in_power_on_state) -{ - struct trackpoint_data *tp = psmouse->private; - - if (!in_power_on_state) { - /* - * Disable features that may make device unusable - * with this driver. - */ - trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_TWOHAND, - TP_MASK_TWOHAND, TP_DEF_TWOHAND); - - trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_SOURCE_TAG, - TP_MASK_SOURCE_TAG, TP_DEF_SOURCE_TAG); - - trackpoint_update_bit(&psmouse->ps2dev, TP_TOGGLE_MB, - TP_MASK_MB, TP_DEF_MB); - } - - /* - * These properties can be changed in this driver. Only - * configure them if the values are non-default or if the TP is in - * an unknown state. - */ - TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, sensitivity); - TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, inertia); - TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, speed); - TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, reach); - TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, draghys); - TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, mindrag); - TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, thresh); - TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, upthresh); - TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, ztime); - TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, jenks); - TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, drift_time); - - /* toggles */ - TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, press_to_select); - TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, skipback); - TRACKPOINT_UPDATE(in_power_on_state, psmouse, tp, ext_dev); - - return 0; -} - -static void trackpoint_defaults(struct trackpoint_data *tp) -{ - TRACKPOINT_SET_POWER_ON_DEFAULT(tp, sensitivity); - TRACKPOINT_SET_POWER_ON_DEFAULT(tp, speed); - TRACKPOINT_SET_POWER_ON_DEFAULT(tp, reach); - TRACKPOINT_SET_POWER_ON_DEFAULT(tp, draghys); - TRACKPOINT_SET_POWER_ON_DEFAULT(tp, mindrag); - TRACKPOINT_SET_POWER_ON_DEFAULT(tp, thresh); - TRACKPOINT_SET_POWER_ON_DEFAULT(tp, upthresh); - TRACKPOINT_SET_POWER_ON_DEFAULT(tp, ztime); - TRACKPOINT_SET_POWER_ON_DEFAULT(tp, jenks); - TRACKPOINT_SET_POWER_ON_DEFAULT(tp, drift_time); - TRACKPOINT_SET_POWER_ON_DEFAULT(tp, inertia); - - /* toggles */ - TRACKPOINT_SET_POWER_ON_DEFAULT(tp, press_to_select); - TRACKPOINT_SET_POWER_ON_DEFAULT(tp, skipback); - TRACKPOINT_SET_POWER_ON_DEFAULT(tp, ext_dev); -} - -static void trackpoint_disconnect(struct psmouse *psmouse) -{ - sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, &trackpoint_attr_group); - - kfree(psmouse->private); - psmouse->private = NULL; -} - -static int trackpoint_reconnect(struct psmouse *psmouse) -{ - int reset_fail; - - if (trackpoint_start_protocol(psmouse, NULL)) - return -1; - - reset_fail = trackpoint_power_on_reset(&psmouse->ps2dev); - if (trackpoint_sync(psmouse, !reset_fail)) - return -1; - - return 0; -} - -int trackpoint_detect(struct psmouse *psmouse, bool set_properties) -{ - struct ps2dev *ps2dev = &psmouse->ps2dev; - unsigned char firmware_id; - unsigned char button_info; - int error; - - if (trackpoint_start_protocol(psmouse, &firmware_id)) - return -1; - - if (!set_properties) - return 0; - - if (trackpoint_read(&psmouse->ps2dev, TP_EXT_BTN, &button_info)) { - psmouse_warn(psmouse, "failed to get extended button data\n"); - button_info = 0; - } - - psmouse->private = kzalloc(sizeof(struct trackpoint_data), GFP_KERNEL); - if (!psmouse->private) - return -ENOMEM; - - psmouse->vendor = "IBM"; - psmouse->name = "TrackPoint"; - - psmouse->reconnect = trackpoint_reconnect; - psmouse->disconnect = trackpoint_disconnect; - - if ((button_info & 0x0f) >= 3) - __set_bit(BTN_MIDDLE, psmouse->dev->keybit); - - __set_bit(INPUT_PROP_POINTER, psmouse->dev->propbit); - __set_bit(INPUT_PROP_POINTING_STICK, psmouse->dev->propbit); - - trackpoint_defaults(psmouse->private); - - error = trackpoint_power_on_reset(&psmouse->ps2dev); - - /* Write defaults to TP only if reset fails. */ - if (error) - trackpoint_sync(psmouse, false); - - error = sysfs_create_group(&ps2dev->serio->dev.kobj, &trackpoint_attr_group); - if (error) { - psmouse_err(psmouse, - "failed to create sysfs attributes, error: %d\n", - error); - kfree(psmouse->private); - psmouse->private = NULL; - return -1; - } - - psmouse_info(psmouse, - "IBM TrackPoint firmware: 0x%02x, buttons: %d/%d\n", - firmware_id, - (button_info & 0xf0) >> 4, button_info & 0x0f); - - return 0; -} - diff --git a/src/linux/drivers/input/mouse/trackpoint.h b/src/linux/drivers/input/mouse/trackpoint.h deleted file mode 100644 index 5617ed3..0000000 --- a/src/linux/drivers/input/mouse/trackpoint.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * IBM TrackPoint PS/2 mouse driver - * - * Stephen Evanchik - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#ifndef _TRACKPOINT_H -#define _TRACKPOINT_H - -/* - * These constants are from the TrackPoint System - * Engineering documentation Version 4 from IBM Watson - * research: - * http://wwwcssrv.almaden.ibm.com/trackpoint/download.html - */ - -#define TP_COMMAND 0xE2 /* Commands start with this */ - -#define TP_READ_ID 0xE1 /* Sent for device identification */ -#define TP_MAGIC_IDENT 0x01 /* Sent after a TP_READ_ID followed */ - /* by the firmware ID */ - - -/* - * Commands - */ -#define TP_RECALIB 0x51 /* Recalibrate */ -#define TP_POWER_DOWN 0x44 /* Can only be undone through HW reset */ -#define TP_EXT_DEV 0x21 /* Determines if external device is connected (RO) */ -#define TP_EXT_BTN 0x4B /* Read extended button status */ -#define TP_POR 0x7F /* Execute Power on Reset */ -#define TP_POR_RESULTS 0x25 /* Read Power on Self test results */ -#define TP_DISABLE_EXT 0x40 /* Disable external pointing device */ -#define TP_ENABLE_EXT 0x41 /* Enable external pointing device */ - -/* - * Mode manipulation - */ -#define TP_SET_SOFT_TRANS 0x4E /* Set mode */ -#define TP_CANCEL_SOFT_TRANS 0xB9 /* Cancel mode */ -#define TP_SET_HARD_TRANS 0x45 /* Mode can only be set */ - - -/* - * Register oriented commands/properties - */ -#define TP_WRITE_MEM 0x81 -#define TP_READ_MEM 0x80 /* Not used in this implementation */ - -/* -* RAM Locations for properties - */ -#define TP_SENS 0x4A /* Sensitivity */ -#define TP_MB 0x4C /* Read Middle Button Status (RO) */ -#define TP_INERTIA 0x4D /* Negative Inertia */ -#define TP_SPEED 0x60 /* Speed of TP Cursor */ -#define TP_REACH 0x57 /* Backup for Z-axis press */ -#define TP_DRAGHYS 0x58 /* Drag Hysteresis */ - /* (how hard it is to drag */ - /* with Z-axis pressed) */ - -#define TP_MINDRAG 0x59 /* Minimum amount of force needed */ - /* to trigger dragging */ - -#define TP_THRESH 0x5C /* Minimum value for a Z-axis press */ -#define TP_UP_THRESH 0x5A /* Used to generate a 'click' on Z-axis */ -#define TP_Z_TIME 0x5E /* How sharp of a press */ -#define TP_JENKS_CURV 0x5D /* Minimum curvature for double click */ -#define TP_DRIFT_TIME 0x5F /* How long a 'hands off' condition */ - /* must last (x*107ms) for drift */ - /* correction to occur */ - -/* - * Toggling Flag bits - */ -#define TP_TOGGLE 0x47 /* Toggle command */ - -#define TP_TOGGLE_MB 0x23 /* Disable/Enable Middle Button */ -#define TP_MASK_MB 0x01 -#define TP_TOGGLE_EXT_DEV 0x23 /* Disable external device */ -#define TP_MASK_EXT_DEV 0x02 -#define TP_TOGGLE_DRIFT 0x23 /* Drift Correction */ -#define TP_MASK_DRIFT 0x80 -#define TP_TOGGLE_BURST 0x28 /* Burst Mode */ -#define TP_MASK_BURST 0x80 -#define TP_TOGGLE_PTSON 0x2C /* Press to Select */ -#define TP_MASK_PTSON 0x01 -#define TP_TOGGLE_HARD_TRANS 0x2C /* Alternate method to set Hard Transparency */ -#define TP_MASK_HARD_TRANS 0x80 -#define TP_TOGGLE_TWOHAND 0x2D /* Two handed */ -#define TP_MASK_TWOHAND 0x01 -#define TP_TOGGLE_STICKY_TWO 0x2D /* Sticky two handed */ -#define TP_MASK_STICKY_TWO 0x04 -#define TP_TOGGLE_SKIPBACK 0x2D /* Suppress movement after drag release */ -#define TP_MASK_SKIPBACK 0x08 -#define TP_TOGGLE_SOURCE_TAG 0x20 /* Bit 3 of the first packet will be set to - to the origin of the packet (external or TP) */ -#define TP_MASK_SOURCE_TAG 0x80 -#define TP_TOGGLE_EXT_TAG 0x22 /* Bit 3 of the first packet coming from the - external device will be forced to 1 */ -#define TP_MASK_EXT_TAG 0x04 - - -/* Power on Self Test Results */ -#define TP_POR_SUCCESS 0x3B - -/* - * Default power on values - */ -#define TP_DEF_SENS 0x80 -#define TP_DEF_INERTIA 0x06 -#define TP_DEF_SPEED 0x61 -#define TP_DEF_REACH 0x0A - -#define TP_DEF_DRAGHYS 0xFF -#define TP_DEF_MINDRAG 0x14 - -#define TP_DEF_THRESH 0x08 -#define TP_DEF_UP_THRESH 0xFF -#define TP_DEF_Z_TIME 0x26 -#define TP_DEF_JENKS_CURV 0x87 -#define TP_DEF_DRIFT_TIME 0x05 - -/* Toggles */ -#define TP_DEF_MB 0x00 -#define TP_DEF_PTSON 0x00 -#define TP_DEF_SKIPBACK 0x00 -#define TP_DEF_EXT_DEV 0x00 /* 0 means enabled */ -#define TP_DEF_TWOHAND 0x00 -#define TP_DEF_SOURCE_TAG 0x00 - -#define MAKE_PS2_CMD(params, results, cmd) ((params<<12) | (results<<8) | (cmd)) - -struct trackpoint_data -{ - unsigned char sensitivity, speed, inertia, reach; - unsigned char draghys, mindrag; - unsigned char thresh, upthresh; - unsigned char ztime, jenks; - unsigned char drift_time; - - /* toggles */ - unsigned char press_to_select; - unsigned char skipback; - unsigned char ext_dev; -}; - -#ifdef CONFIG_MOUSE_PS2_TRACKPOINT -int trackpoint_detect(struct psmouse *psmouse, bool set_properties); -#else -inline int trackpoint_detect(struct psmouse *psmouse, bool set_properties) -{ - return -ENOSYS; -} -#endif /* CONFIG_MOUSE_PS2_TRACKPOINT */ - -#endif /* _TRACKPOINT_H */ diff --git a/src/linux/drivers/input/mouse/vmmouse.h b/src/linux/drivers/input/mouse/vmmouse.h deleted file mode 100644 index 6f12601..0000000 --- a/src/linux/drivers/input/mouse/vmmouse.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Driver for Virtual PS/2 Mouse on VMware and QEMU hypervisors. - * - * Copyright (C) 2014, VMware, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#ifndef _VMMOUSE_H -#define _VMMOUSE_H - -#ifdef CONFIG_MOUSE_PS2_VMMOUSE -#define VMMOUSE_PSNAME "VirtualPS/2" - -int vmmouse_detect(struct psmouse *psmouse, bool set_properties); -int vmmouse_init(struct psmouse *psmouse); -#else -static inline int vmmouse_detect(struct psmouse *psmouse, bool set_properties) -{ - return -ENOSYS; -} -static inline int vmmouse_init(struct psmouse *psmouse) -{ - return -ENOSYS; -} -#endif - -#endif diff --git a/src/linux/drivers/input/mousedev.c b/src/linux/drivers/input/mousedev.c deleted file mode 100644 index b604564..0000000 --- a/src/linux/drivers/input/mousedev.c +++ /dev/null @@ -1,1128 +0,0 @@ -/* - * Input driver to ExplorerPS/2 device driver module. - * - * Copyright (c) 1999-2002 Vojtech Pavlik - * Copyright (c) 2004 Dmitry Torokhov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#define MOUSEDEV_MINOR_BASE 32 -#define MOUSEDEV_MINORS 31 -#define MOUSEDEV_MIX 63 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Mouse (ExplorerPS/2) device interfaces"); -MODULE_LICENSE("GPL"); - -#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X -#define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 -#endif -#ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y -#define CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768 -#endif - -static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X; -module_param(xres, uint, 0644); -MODULE_PARM_DESC(xres, "Horizontal screen resolution"); - -static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y; -module_param(yres, uint, 0644); -MODULE_PARM_DESC(yres, "Vertical screen resolution"); - -static unsigned tap_time = 200; -module_param(tap_time, uint, 0644); -MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)"); - -struct mousedev_hw_data { - int dx, dy, dz; - int x, y; - int abs_event; - unsigned long buttons; -}; - -struct mousedev { - int open; - struct input_handle handle; - wait_queue_head_t wait; - struct list_head client_list; - spinlock_t client_lock; /* protects client_list */ - struct mutex mutex; - struct device dev; - struct cdev cdev; - bool exist; - - struct list_head mixdev_node; - bool opened_by_mixdev; - - struct mousedev_hw_data packet; - unsigned int pkt_count; - int old_x[4], old_y[4]; - int frac_dx, frac_dy; - unsigned long touch; - - int (*open_device)(struct mousedev *mousedev); - void (*close_device)(struct mousedev *mousedev); -}; - -enum mousedev_emul { - MOUSEDEV_EMUL_PS2, - MOUSEDEV_EMUL_IMPS, - MOUSEDEV_EMUL_EXPS -}; - -struct mousedev_motion { - int dx, dy, dz; - unsigned long buttons; -}; - -#define PACKET_QUEUE_LEN 16 -struct mousedev_client { - struct fasync_struct *fasync; - struct mousedev *mousedev; - struct list_head node; - - struct mousedev_motion packets[PACKET_QUEUE_LEN]; - unsigned int head, tail; - spinlock_t packet_lock; - int pos_x, pos_y; - - signed char ps2[6]; - unsigned char ready, buffer, bufsiz; - unsigned char imexseq, impsseq; - enum mousedev_emul mode; - unsigned long last_buttons; -}; - -#define MOUSEDEV_SEQ_LEN 6 - -static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 }; -static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; - -static struct mousedev *mousedev_mix; -static LIST_HEAD(mousedev_mix_list); - -#define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) -#define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03]) - -static void mousedev_touchpad_event(struct input_dev *dev, - struct mousedev *mousedev, - unsigned int code, int value) -{ - int size, tmp; - enum { FRACTION_DENOM = 128 }; - - switch (code) { - - case ABS_X: - - fx(0) = value; - if (mousedev->touch && mousedev->pkt_count >= 2) { - size = input_abs_get_max(dev, ABS_X) - - input_abs_get_min(dev, ABS_X); - if (size == 0) - size = 256 * 2; - - tmp = ((value - fx(2)) * 256 * FRACTION_DENOM) / size; - tmp += mousedev->frac_dx; - mousedev->packet.dx = tmp / FRACTION_DENOM; - mousedev->frac_dx = - tmp - mousedev->packet.dx * FRACTION_DENOM; - } - break; - - case ABS_Y: - fy(0) = value; - if (mousedev->touch && mousedev->pkt_count >= 2) { - /* use X size for ABS_Y to keep the same scale */ - size = input_abs_get_max(dev, ABS_X) - - input_abs_get_min(dev, ABS_X); - if (size == 0) - size = 256 * 2; - - tmp = -((value - fy(2)) * 256 * FRACTION_DENOM) / size; - tmp += mousedev->frac_dy; - mousedev->packet.dy = tmp / FRACTION_DENOM; - mousedev->frac_dy = tmp - - mousedev->packet.dy * FRACTION_DENOM; - } - break; - } -} - -static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, - unsigned int code, int value) -{ - int min, max, size; - - switch (code) { - - case ABS_X: - min = input_abs_get_min(dev, ABS_X); - max = input_abs_get_max(dev, ABS_X); - - size = max - min; - if (size == 0) - size = xres ? : 1; - - value = clamp(value, min, max); - - mousedev->packet.x = ((value - min) * xres) / size; - mousedev->packet.abs_event = 1; - break; - - case ABS_Y: - min = input_abs_get_min(dev, ABS_Y); - max = input_abs_get_max(dev, ABS_Y); - - size = max - min; - if (size == 0) - size = yres ? : 1; - - value = clamp(value, min, max); - - mousedev->packet.y = yres - ((value - min) * yres) / size; - mousedev->packet.abs_event = 1; - break; - } -} - -static void mousedev_rel_event(struct mousedev *mousedev, - unsigned int code, int value) -{ - switch (code) { - case REL_X: - mousedev->packet.dx += value; - break; - - case REL_Y: - mousedev->packet.dy -= value; - break; - - case REL_WHEEL: - mousedev->packet.dz -= value; - break; - } -} - -static void mousedev_key_event(struct mousedev *mousedev, - unsigned int code, int value) -{ - int index; - - switch (code) { - - case BTN_TOUCH: - case BTN_0: - case BTN_LEFT: index = 0; break; - - case BTN_STYLUS: - case BTN_1: - case BTN_RIGHT: index = 1; break; - - case BTN_2: - case BTN_FORWARD: - case BTN_STYLUS2: - case BTN_MIDDLE: index = 2; break; - - case BTN_3: - case BTN_BACK: - case BTN_SIDE: index = 3; break; - - case BTN_4: - case BTN_EXTRA: index = 4; break; - - default: return; - } - - if (value) { - set_bit(index, &mousedev->packet.buttons); - set_bit(index, &mousedev_mix->packet.buttons); - } else { - clear_bit(index, &mousedev->packet.buttons); - clear_bit(index, &mousedev_mix->packet.buttons); - } -} - -static void mousedev_notify_readers(struct mousedev *mousedev, - struct mousedev_hw_data *packet) -{ - struct mousedev_client *client; - struct mousedev_motion *p; - unsigned int new_head; - int wake_readers = 0; - - rcu_read_lock(); - list_for_each_entry_rcu(client, &mousedev->client_list, node) { - - /* Just acquire the lock, interrupts already disabled */ - spin_lock(&client->packet_lock); - - p = &client->packets[client->head]; - if (client->ready && p->buttons != mousedev->packet.buttons) { - new_head = (client->head + 1) % PACKET_QUEUE_LEN; - if (new_head != client->tail) { - p = &client->packets[client->head = new_head]; - memset(p, 0, sizeof(struct mousedev_motion)); - } - } - - if (packet->abs_event) { - p->dx += packet->x - client->pos_x; - p->dy += packet->y - client->pos_y; - client->pos_x = packet->x; - client->pos_y = packet->y; - } - - client->pos_x += packet->dx; - client->pos_x = client->pos_x < 0 ? - 0 : (client->pos_x >= xres ? xres : client->pos_x); - client->pos_y += packet->dy; - client->pos_y = client->pos_y < 0 ? - 0 : (client->pos_y >= yres ? yres : client->pos_y); - - p->dx += packet->dx; - p->dy += packet->dy; - p->dz += packet->dz; - p->buttons = mousedev->packet.buttons; - - if (p->dx || p->dy || p->dz || - p->buttons != client->last_buttons) - client->ready = 1; - - spin_unlock(&client->packet_lock); - - if (client->ready) { - kill_fasync(&client->fasync, SIGIO, POLL_IN); - wake_readers = 1; - } - } - rcu_read_unlock(); - - if (wake_readers) - wake_up_interruptible(&mousedev->wait); -} - -static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) -{ - if (!value) { - if (mousedev->touch && - time_before(jiffies, - mousedev->touch + msecs_to_jiffies(tap_time))) { - /* - * Toggle left button to emulate tap. - * We rely on the fact that mousedev_mix always has 0 - * motion packet so we won't mess current position. - */ - set_bit(0, &mousedev->packet.buttons); - set_bit(0, &mousedev_mix->packet.buttons); - mousedev_notify_readers(mousedev, &mousedev_mix->packet); - mousedev_notify_readers(mousedev_mix, - &mousedev_mix->packet); - clear_bit(0, &mousedev->packet.buttons); - clear_bit(0, &mousedev_mix->packet.buttons); - } - mousedev->touch = mousedev->pkt_count = 0; - mousedev->frac_dx = 0; - mousedev->frac_dy = 0; - - } else if (!mousedev->touch) - mousedev->touch = jiffies; -} - -static void mousedev_event(struct input_handle *handle, - unsigned int type, unsigned int code, int value) -{ - struct mousedev *mousedev = handle->private; - - switch (type) { - - case EV_ABS: - /* Ignore joysticks */ - if (test_bit(BTN_TRIGGER, handle->dev->keybit)) - return; - - if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) - mousedev_touchpad_event(handle->dev, - mousedev, code, value); - else - mousedev_abs_event(handle->dev, mousedev, code, value); - - break; - - case EV_REL: - mousedev_rel_event(mousedev, code, value); - break; - - case EV_KEY: - if (value != 2) { - if (code == BTN_TOUCH && - test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) - mousedev_touchpad_touch(mousedev, value); - else - mousedev_key_event(mousedev, code, value); - } - break; - - case EV_SYN: - if (code == SYN_REPORT) { - if (mousedev->touch) { - mousedev->pkt_count++; - /* - * Input system eats duplicate events, - * but we need all of them to do correct - * averaging so apply present one forward - */ - fx(0) = fx(1); - fy(0) = fy(1); - } - - mousedev_notify_readers(mousedev, &mousedev->packet); - mousedev_notify_readers(mousedev_mix, &mousedev->packet); - - mousedev->packet.dx = mousedev->packet.dy = - mousedev->packet.dz = 0; - mousedev->packet.abs_event = 0; - } - break; - } -} - -static int mousedev_fasync(int fd, struct file *file, int on) -{ - struct mousedev_client *client = file->private_data; - - return fasync_helper(fd, file, on, &client->fasync); -} - -static void mousedev_free(struct device *dev) -{ - struct mousedev *mousedev = container_of(dev, struct mousedev, dev); - - input_put_device(mousedev->handle.dev); - kfree(mousedev); -} - -static int mousedev_open_device(struct mousedev *mousedev) -{ - int retval; - - retval = mutex_lock_interruptible(&mousedev->mutex); - if (retval) - return retval; - - if (!mousedev->exist) - retval = -ENODEV; - else if (!mousedev->open++) { - retval = input_open_device(&mousedev->handle); - if (retval) - mousedev->open--; - } - - mutex_unlock(&mousedev->mutex); - return retval; -} - -static void mousedev_close_device(struct mousedev *mousedev) -{ - mutex_lock(&mousedev->mutex); - - if (mousedev->exist && !--mousedev->open) - input_close_device(&mousedev->handle); - - mutex_unlock(&mousedev->mutex); -} - -/* - * Open all available devices so they can all be multiplexed in one. - * stream. Note that this function is called with mousedev_mix->mutex - * held. - */ -static int mixdev_open_devices(struct mousedev *mixdev) -{ - int error; - - error = mutex_lock_interruptible(&mixdev->mutex); - if (error) - return error; - - if (!mixdev->open++) { - struct mousedev *mousedev; - - list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { - if (!mousedev->opened_by_mixdev) { - if (mousedev_open_device(mousedev)) - continue; - - mousedev->opened_by_mixdev = true; - } - } - } - - mutex_unlock(&mixdev->mutex); - return 0; -} - -/* - * Close all devices that were opened as part of multiplexed - * device. Note that this function is called with mousedev_mix->mutex - * held. - */ -static void mixdev_close_devices(struct mousedev *mixdev) -{ - mutex_lock(&mixdev->mutex); - - if (!--mixdev->open) { - struct mousedev *mousedev; - - list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { - if (mousedev->opened_by_mixdev) { - mousedev->opened_by_mixdev = false; - mousedev_close_device(mousedev); - } - } - } - - mutex_unlock(&mixdev->mutex); -} - - -static void mousedev_attach_client(struct mousedev *mousedev, - struct mousedev_client *client) -{ - spin_lock(&mousedev->client_lock); - list_add_tail_rcu(&client->node, &mousedev->client_list); - spin_unlock(&mousedev->client_lock); -} - -static void mousedev_detach_client(struct mousedev *mousedev, - struct mousedev_client *client) -{ - spin_lock(&mousedev->client_lock); - list_del_rcu(&client->node); - spin_unlock(&mousedev->client_lock); - synchronize_rcu(); -} - -static int mousedev_release(struct inode *inode, struct file *file) -{ - struct mousedev_client *client = file->private_data; - struct mousedev *mousedev = client->mousedev; - - mousedev_detach_client(mousedev, client); - kfree(client); - - mousedev->close_device(mousedev); - - return 0; -} - -static int mousedev_open(struct inode *inode, struct file *file) -{ - struct mousedev_client *client; - struct mousedev *mousedev; - int error; - -#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX - if (imajor(inode) == MISC_MAJOR) - mousedev = mousedev_mix; - else -#endif - mousedev = container_of(inode->i_cdev, struct mousedev, cdev); - - client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); - if (!client) - return -ENOMEM; - - spin_lock_init(&client->packet_lock); - client->pos_x = xres / 2; - client->pos_y = yres / 2; - client->mousedev = mousedev; - mousedev_attach_client(mousedev, client); - - error = mousedev->open_device(mousedev); - if (error) - goto err_free_client; - - file->private_data = client; - nonseekable_open(inode, file); - - return 0; - - err_free_client: - mousedev_detach_client(mousedev, client); - kfree(client); - return error; -} - -static inline int mousedev_limit_delta(int delta, int limit) -{ - return delta > limit ? limit : (delta < -limit ? -limit : delta); -} - -static void mousedev_packet(struct mousedev_client *client, - signed char *ps2_data) -{ - struct mousedev_motion *p = &client->packets[client->tail]; - - ps2_data[0] = 0x08 | - ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07); - ps2_data[1] = mousedev_limit_delta(p->dx, 127); - ps2_data[2] = mousedev_limit_delta(p->dy, 127); - p->dx -= ps2_data[1]; - p->dy -= ps2_data[2]; - - switch (client->mode) { - case MOUSEDEV_EMUL_EXPS: - ps2_data[3] = mousedev_limit_delta(p->dz, 7); - p->dz -= ps2_data[3]; - ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); - client->bufsiz = 4; - break; - - case MOUSEDEV_EMUL_IMPS: - ps2_data[0] |= - ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); - ps2_data[3] = mousedev_limit_delta(p->dz, 127); - p->dz -= ps2_data[3]; - client->bufsiz = 4; - break; - - case MOUSEDEV_EMUL_PS2: - default: - ps2_data[0] |= - ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); - p->dz = 0; - client->bufsiz = 3; - break; - } - - if (!p->dx && !p->dy && !p->dz) { - if (client->tail == client->head) { - client->ready = 0; - client->last_buttons = p->buttons; - } else - client->tail = (client->tail + 1) % PACKET_QUEUE_LEN; - } -} - -static void mousedev_generate_response(struct mousedev_client *client, - int command) -{ - client->ps2[0] = 0xfa; /* ACK */ - - switch (command) { - - case 0xeb: /* Poll */ - mousedev_packet(client, &client->ps2[1]); - client->bufsiz++; /* account for leading ACK */ - break; - - case 0xf2: /* Get ID */ - switch (client->mode) { - case MOUSEDEV_EMUL_PS2: - client->ps2[1] = 0; - break; - case MOUSEDEV_EMUL_IMPS: - client->ps2[1] = 3; - break; - case MOUSEDEV_EMUL_EXPS: - client->ps2[1] = 4; - break; - } - client->bufsiz = 2; - break; - - case 0xe9: /* Get info */ - client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200; - client->bufsiz = 4; - break; - - case 0xff: /* Reset */ - client->impsseq = client->imexseq = 0; - client->mode = MOUSEDEV_EMUL_PS2; - client->ps2[1] = 0xaa; client->ps2[2] = 0x00; - client->bufsiz = 3; - break; - - default: - client->bufsiz = 1; - break; - } - client->buffer = client->bufsiz; -} - -static ssize_t mousedev_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) -{ - struct mousedev_client *client = file->private_data; - unsigned char c; - unsigned int i; - - for (i = 0; i < count; i++) { - - if (get_user(c, buffer + i)) - return -EFAULT; - - spin_lock_irq(&client->packet_lock); - - if (c == mousedev_imex_seq[client->imexseq]) { - if (++client->imexseq == MOUSEDEV_SEQ_LEN) { - client->imexseq = 0; - client->mode = MOUSEDEV_EMUL_EXPS; - } - } else - client->imexseq = 0; - - if (c == mousedev_imps_seq[client->impsseq]) { - if (++client->impsseq == MOUSEDEV_SEQ_LEN) { - client->impsseq = 0; - client->mode = MOUSEDEV_EMUL_IMPS; - } - } else - client->impsseq = 0; - - mousedev_generate_response(client, c); - - spin_unlock_irq(&client->packet_lock); - } - - kill_fasync(&client->fasync, SIGIO, POLL_IN); - wake_up_interruptible(&client->mousedev->wait); - - return count; -} - -static ssize_t mousedev_read(struct file *file, char __user *buffer, - size_t count, loff_t *ppos) -{ - struct mousedev_client *client = file->private_data; - struct mousedev *mousedev = client->mousedev; - signed char data[sizeof(client->ps2)]; - int retval = 0; - - if (!client->ready && !client->buffer && mousedev->exist && - (file->f_flags & O_NONBLOCK)) - return -EAGAIN; - - retval = wait_event_interruptible(mousedev->wait, - !mousedev->exist || client->ready || client->buffer); - if (retval) - return retval; - - if (!mousedev->exist) - return -ENODEV; - - spin_lock_irq(&client->packet_lock); - - if (!client->buffer && client->ready) { - mousedev_packet(client, client->ps2); - client->buffer = client->bufsiz; - } - - if (count > client->buffer) - count = client->buffer; - - memcpy(data, client->ps2 + client->bufsiz - client->buffer, count); - client->buffer -= count; - - spin_unlock_irq(&client->packet_lock); - - if (copy_to_user(buffer, data, count)) - return -EFAULT; - - return count; -} - -/* No kernel lock - fine */ -static unsigned int mousedev_poll(struct file *file, poll_table *wait) -{ - struct mousedev_client *client = file->private_data; - struct mousedev *mousedev = client->mousedev; - unsigned int mask; - - poll_wait(file, &mousedev->wait, wait); - - mask = mousedev->exist ? POLLOUT | POLLWRNORM : POLLHUP | POLLERR; - if (client->ready || client->buffer) - mask |= POLLIN | POLLRDNORM; - - return mask; -} - -static const struct file_operations mousedev_fops = { - .owner = THIS_MODULE, - .read = mousedev_read, - .write = mousedev_write, - .poll = mousedev_poll, - .open = mousedev_open, - .release = mousedev_release, - .fasync = mousedev_fasync, - .llseek = noop_llseek, -}; - -/* - * Mark device non-existent. This disables writes, ioctls and - * prevents new users from opening the device. Already posted - * blocking reads will stay, however new ones will fail. - */ -static void mousedev_mark_dead(struct mousedev *mousedev) -{ - mutex_lock(&mousedev->mutex); - mousedev->exist = false; - mutex_unlock(&mousedev->mutex); -} - -/* - * Wake up users waiting for IO so they can disconnect from - * dead device. - */ -static void mousedev_hangup(struct mousedev *mousedev) -{ - struct mousedev_client *client; - - spin_lock(&mousedev->client_lock); - list_for_each_entry(client, &mousedev->client_list, node) - kill_fasync(&client->fasync, SIGIO, POLL_HUP); - spin_unlock(&mousedev->client_lock); - - wake_up_interruptible(&mousedev->wait); -} - -static void mousedev_cleanup(struct mousedev *mousedev) -{ - struct input_handle *handle = &mousedev->handle; - - mousedev_mark_dead(mousedev); - mousedev_hangup(mousedev); - - cdev_del(&mousedev->cdev); - - /* mousedev is marked dead so no one else accesses mousedev->open */ - if (mousedev->open) - input_close_device(handle); -} - -static int mousedev_reserve_minor(bool mixdev) -{ - int minor; - - if (mixdev) { - minor = input_get_new_minor(MOUSEDEV_MIX, 1, false); - if (minor < 0) - pr_err("failed to reserve mixdev minor: %d\n", minor); - } else { - minor = input_get_new_minor(MOUSEDEV_MINOR_BASE, - MOUSEDEV_MINORS, true); - if (minor < 0) - pr_err("failed to reserve new minor: %d\n", minor); - } - - return minor; -} - -static struct mousedev *mousedev_create(struct input_dev *dev, - struct input_handler *handler, - bool mixdev) -{ - struct mousedev *mousedev; - int minor; - int error; - - minor = mousedev_reserve_minor(mixdev); - if (minor < 0) { - error = minor; - goto err_out; - } - - mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL); - if (!mousedev) { - error = -ENOMEM; - goto err_free_minor; - } - - INIT_LIST_HEAD(&mousedev->client_list); - INIT_LIST_HEAD(&mousedev->mixdev_node); - spin_lock_init(&mousedev->client_lock); - mutex_init(&mousedev->mutex); - lockdep_set_subclass(&mousedev->mutex, - mixdev ? SINGLE_DEPTH_NESTING : 0); - init_waitqueue_head(&mousedev->wait); - - if (mixdev) { - dev_set_name(&mousedev->dev, "mice"); - - mousedev->open_device = mixdev_open_devices; - mousedev->close_device = mixdev_close_devices; - } else { - int dev_no = minor; - /* Normalize device number if it falls into legacy range */ - if (dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS) - dev_no -= MOUSEDEV_MINOR_BASE; - dev_set_name(&mousedev->dev, "mouse%d", dev_no); - - mousedev->open_device = mousedev_open_device; - mousedev->close_device = mousedev_close_device; - } - - mousedev->exist = true; - mousedev->handle.dev = input_get_device(dev); - mousedev->handle.name = dev_name(&mousedev->dev); - mousedev->handle.handler = handler; - mousedev->handle.private = mousedev; - - mousedev->dev.class = &input_class; - if (dev) - mousedev->dev.parent = &dev->dev; - mousedev->dev.devt = MKDEV(INPUT_MAJOR, minor); - mousedev->dev.release = mousedev_free; - device_initialize(&mousedev->dev); - - if (!mixdev) { - error = input_register_handle(&mousedev->handle); - if (error) - goto err_free_mousedev; - } - - cdev_init(&mousedev->cdev, &mousedev_fops); - mousedev->cdev.kobj.parent = &mousedev->dev.kobj; - error = cdev_add(&mousedev->cdev, mousedev->dev.devt, 1); - if (error) - goto err_unregister_handle; - - error = device_add(&mousedev->dev); - if (error) - goto err_cleanup_mousedev; - - return mousedev; - - err_cleanup_mousedev: - mousedev_cleanup(mousedev); - err_unregister_handle: - if (!mixdev) - input_unregister_handle(&mousedev->handle); - err_free_mousedev: - put_device(&mousedev->dev); - err_free_minor: - input_free_minor(minor); - err_out: - return ERR_PTR(error); -} - -static void mousedev_destroy(struct mousedev *mousedev) -{ - device_del(&mousedev->dev); - mousedev_cleanup(mousedev); - input_free_minor(MINOR(mousedev->dev.devt)); - if (mousedev != mousedev_mix) - input_unregister_handle(&mousedev->handle); - put_device(&mousedev->dev); -} - -static int mixdev_add_device(struct mousedev *mousedev) -{ - int retval; - - retval = mutex_lock_interruptible(&mousedev_mix->mutex); - if (retval) - return retval; - - if (mousedev_mix->open) { - retval = mousedev_open_device(mousedev); - if (retval) - goto out; - - mousedev->opened_by_mixdev = true; - } - - get_device(&mousedev->dev); - list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list); - - out: - mutex_unlock(&mousedev_mix->mutex); - return retval; -} - -static void mixdev_remove_device(struct mousedev *mousedev) -{ - mutex_lock(&mousedev_mix->mutex); - - if (mousedev->opened_by_mixdev) { - mousedev->opened_by_mixdev = false; - mousedev_close_device(mousedev); - } - - list_del_init(&mousedev->mixdev_node); - mutex_unlock(&mousedev_mix->mutex); - - put_device(&mousedev->dev); -} - -static int mousedev_connect(struct input_handler *handler, - struct input_dev *dev, - const struct input_device_id *id) -{ - struct mousedev *mousedev; - int error; - - mousedev = mousedev_create(dev, handler, false); - if (IS_ERR(mousedev)) - return PTR_ERR(mousedev); - - error = mixdev_add_device(mousedev); - if (error) { - mousedev_destroy(mousedev); - return error; - } - - return 0; -} - -static void mousedev_disconnect(struct input_handle *handle) -{ - struct mousedev *mousedev = handle->private; - - mixdev_remove_device(mousedev); - mousedev_destroy(mousedev); -} - -static const struct input_device_id mousedev_ids[] = { - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | - INPUT_DEVICE_ID_MATCH_KEYBIT | - INPUT_DEVICE_ID_MATCH_RELBIT, - .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) }, - .keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) }, - .relbit = { BIT_MASK(REL_X) | BIT_MASK(REL_Y) }, - }, /* A mouse like device, at least one button, - two relative axes */ - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | - INPUT_DEVICE_ID_MATCH_RELBIT, - .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_REL) }, - .relbit = { BIT_MASK(REL_WHEEL) }, - }, /* A separate scrollwheel */ - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | - INPUT_DEVICE_ID_MATCH_KEYBIT | - INPUT_DEVICE_ID_MATCH_ABSBIT, - .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) }, - .keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) }, - .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) }, - }, /* A tablet like device, at least touch detection, - two absolute axes */ - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | - INPUT_DEVICE_ID_MATCH_KEYBIT | - INPUT_DEVICE_ID_MATCH_ABSBIT, - .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) }, - .keybit = { [BIT_WORD(BTN_TOOL_FINGER)] = - BIT_MASK(BTN_TOOL_FINGER) }, - .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | - BIT_MASK(ABS_PRESSURE) | - BIT_MASK(ABS_TOOL_WIDTH) }, - }, /* A touchpad */ - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT | - INPUT_DEVICE_ID_MATCH_KEYBIT | - INPUT_DEVICE_ID_MATCH_ABSBIT, - .evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) }, - .keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) }, - .absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) }, - }, /* Mouse-like device with absolute X and Y but ordinary - clicks, like hp ILO2 High Performance mouse */ - - { }, /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(input, mousedev_ids); - -static struct input_handler mousedev_handler = { - .event = mousedev_event, - .connect = mousedev_connect, - .disconnect = mousedev_disconnect, - .legacy_minors = true, - .minor = MOUSEDEV_MINOR_BASE, - .name = "mousedev", - .id_table = mousedev_ids, -}; - -#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX -#include - -static struct miscdevice psaux_mouse = { - .minor = PSMOUSE_MINOR, - .name = "psaux", - .fops = &mousedev_fops, -}; - -static bool psaux_registered; - -static void __init mousedev_psaux_register(void) -{ - int error; - - error = misc_register(&psaux_mouse); - if (error) - pr_warn("could not register psaux device, error: %d\n", - error); - else - psaux_registered = true; -} - -static void __exit mousedev_psaux_unregister(void) -{ - if (psaux_registered) - misc_deregister(&psaux_mouse); -} -#else -static inline void mousedev_psaux_register(void) { } -static inline void mousedev_psaux_unregister(void) { } -#endif - -static int __init mousedev_init(void) -{ - int error; - - mousedev_mix = mousedev_create(NULL, &mousedev_handler, true); - if (IS_ERR(mousedev_mix)) - return PTR_ERR(mousedev_mix); - - error = input_register_handler(&mousedev_handler); - if (error) { - mousedev_destroy(mousedev_mix); - return error; - } - - mousedev_psaux_register(); - - pr_info("PS/2 mouse device common for all mice\n"); - - return 0; -} - -static void __exit mousedev_exit(void) -{ - mousedev_psaux_unregister(); - input_unregister_handler(&mousedev_handler); - mousedev_destroy(mousedev_mix); -} - -module_init(mousedev_init); -module_exit(mousedev_exit); diff --git a/src/linux/drivers/input/rmi4/Kconfig b/src/linux/drivers/input/rmi4/Kconfig deleted file mode 100644 index 4c8a558..0000000 --- a/src/linux/drivers/input/rmi4/Kconfig +++ /dev/null @@ -1,74 +0,0 @@ -# -# RMI4 configuration -# -config RMI4_CORE - tristate "Synaptics RMI4 bus support" - help - Say Y here if you want to support the Synaptics RMI4 bus. This is - required for all RMI4 device support. - - If unsure, say Y. - -config RMI4_I2C - tristate "RMI4 I2C Support" - depends on RMI4_CORE && I2C - help - Say Y here if you want to support RMI4 devices connected to an I2C - bus. - - If unsure, say Y. - -config RMI4_SPI - tristate "RMI4 SPI Support" - depends on RMI4_CORE && SPI - help - Say Y here if you want to support RMI4 devices connected to a SPI - bus. - - If unsure, say N. - -config RMI4_2D_SENSOR - bool - depends on RMI4_CORE - -config RMI4_F11 - bool "RMI4 Function 11 (2D pointing)" - select RMI4_2D_SENSOR - depends on RMI4_CORE - help - Say Y here if you want to add support for RMI4 function 11. - - Function 11 provides 2D multifinger pointing for touchscreens and - touchpads. For sensors that support relative pointing, F11 also - provides mouse input. - -config RMI4_F12 - bool "RMI4 Function 12 (2D pointing)" - select RMI4_2D_SENSOR - depends on RMI4_CORE - help - Say Y here if you want to add support for RMI4 function 12. - - Function 12 provides 2D multifinger pointing for touchscreens and - touchpads. For sensors that support relative pointing, F12 also - provides mouse input. - -config RMI4_F30 - bool "RMI4 Function 30 (GPIO LED)" - depends on RMI4_CORE - help - Say Y here if you want to add support for RMI4 function 30. - - Function 30 provides GPIO and LED support for RMI4 devices. This - includes support for buttons on TouchPads and ClickPads. - -config RMI4_F54 - bool "RMI4 Function 54 (Analog diagnostics)" - depends on RMI4_CORE - depends on VIDEO_V4L2=y || (RMI4_CORE=m && VIDEO_V4L2=m) - select VIDEOBUF2_VMALLOC - help - Say Y here if you want to add support for RMI4 function 54 - - Function 54 provides access to various diagnostic features in certain - RMI4 touch sensors. diff --git a/src/linux/drivers/input/serio/Kconfig b/src/linux/drivers/input/serio/Kconfig deleted file mode 100644 index c3d05b4..0000000 --- a/src/linux/drivers/input/serio/Kconfig +++ /dev/null @@ -1,309 +0,0 @@ -# -# Input core configuration -# -config SERIO - tristate "Serial I/O support" - default y - help - Say Yes here if you have any input device that uses serial I/O to - communicate with the system. This includes the - * standard AT keyboard and PS/2 mouse * - as well as serial mice, Sun keyboards, some joysticks and 6dof - devices and more. - - If unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called serio. - -config ARCH_MIGHT_HAVE_PC_SERIO - bool - help - Select this config option from the architecture Kconfig if - the architecture might use a PC serio device (i8042) to - communicate with keyboard, mouse, etc. - -if SERIO - -config SERIO_I8042 - tristate "i8042 PC Keyboard controller" - default y - depends on ARCH_MIGHT_HAVE_PC_SERIO - help - i8042 is the chip over which the standard AT keyboard and PS/2 - mouse are connected to the computer. If you use these devices, - you'll need to say Y here. - - If unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called i8042. - -config SERIO_SERPORT - tristate "Serial port line discipline" - default y - depends on TTY - help - Say Y here if you plan to use an input device (mouse, joystick, - tablet, 6dof) that communicates over the RS232 serial (COM) port. - - More information is available: - - If unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called serport. - -config SERIO_CT82C710 - tristate "ct82c710 Aux port controller" - depends on X86 - help - Say Y here if you have a Texas Instruments TravelMate notebook - equipped with the ct82c710 chip and want to use a mouse connected - to the "QuickPort". - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called ct82c710. - -config SERIO_Q40KBD - tristate "Q40 keyboard controller" - depends on Q40 - -config SERIO_PARKBD - tristate "Parallel port keyboard adapter" - depends on PARPORT - help - Say Y here if you built a simple parallel port adapter to attach - an additional AT keyboard, XT keyboard or PS/2 mouse. - - More information is available: - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called parkbd. - -config SERIO_RPCKBD - tristate "Acorn RiscPC keyboard controller" - depends on ARCH_ACORN - default y - help - Say Y here if you have the Acorn RiscPC and want to use an AT - keyboard connected to its keyboard controller. - - To compile this driver as a module, choose M here: the - module will be called rpckbd. - -config SERIO_AT32PSIF - tristate "AVR32 PSIF PS/2 keyboard and mouse controller" - depends on AVR32 - help - Say Y here if you want to use the PSIF peripheral on AVR32 devices - and connect a PS/2 keyboard and/or mouse to it. - - To compile this driver as a module, choose M here: the module will - be called at32psif. - -config SERIO_AMBAKMI - tristate "AMBA KMI keyboard controller" - depends on ARM_AMBA - -config SERIO_SA1111 - tristate "Intel SA1111 keyboard controller" - depends on SA1111 - -config SERIO_GSCPS2 - tristate "HP GSC PS/2 keyboard and PS/2 mouse controller" - depends on GSC - default y - help - This driver provides support for the PS/2 ports on PA-RISC machines - over which HP PS/2 keyboards and PS/2 mice may be connected. - If you use these devices, you'll need to say Y here. - - It's safe to enable this driver, so if unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called gscps2. - -config HP_SDC - tristate "HP System Device Controller i8042 Support" - depends on (GSC || HP300) && SERIO - default y - help - This option enables support for the "System Device - Controller", an i8042 carrying microcode to manage a - few miscellaneous devices on some Hewlett Packard systems. - The SDC itself contains a 10ms resolution timer/clock capable - of delivering interrupts on a periodic and one-shot basis. - The SDC may also be connected to a battery-backed real-time - clock, a basic audio waveform generator, and an HP-HIL Master - Link Controller serving up to seven input devices. - - By itself this option is rather useless, but enabling it will - enable selection of drivers for the abovementioned devices. - It is, however, incompatible with the old, reliable HIL keyboard - driver, and the new HIL driver is experimental, so if you plan - to use a HIL keyboard as your primary keyboard, you may wish - to keep using that driver until the new HIL drivers have had - more testing. - -config HIL_MLC - tristate "HIL MLC Support (needed for HIL input devices)" - depends on HP_SDC - -config SERIO_PCIPS2 - tristate "PCI PS/2 keyboard and PS/2 mouse controller" - depends on PCI - help - Say Y here if you have a Mobility Docking station with PS/2 - keyboard and mice ports. - - To compile this driver as a module, choose M here: the - module will be called pcips2. - -config SERIO_MACEPS2 - tristate "SGI O2 MACE PS/2 controller" - depends on SGI_IP32 - help - Say Y here if you have SGI O2 workstation and want to use its - PS/2 ports. - - To compile this driver as a module, choose M here: the - module will be called maceps2. - -config SERIO_LIBPS2 - tristate "PS/2 driver library" - depends on SERIO_I8042 || SERIO_I8042=n - help - Say Y here if you are using a driver for device connected - to a PS/2 port, such as PS/2 mouse or standard AT keyboard. - - To compile this driver as a module, choose M here: the - module will be called libps2. - -config SERIO_RAW - tristate "Raw access to serio ports" - help - Say Y here if you want to have raw access to serio ports, such as - AUX ports on i8042 keyboard controller. Each serio port that is - bound to this driver will be accessible via a char device with - major 10 and dynamically allocated minor. The driver will try - allocating minor 1 (that historically corresponds to /dev/psaux) - first. To bind this driver to a serio port use sysfs interface: - - echo -n "serio_raw" > /sys/bus/serio/devices/serioX/drvctl - - To compile this driver as a module, choose M here: the - module will be called serio_raw. - -config SERIO_XILINX_XPS_PS2 - tristate "Xilinx XPS PS/2 Controller Support" - depends on PPC || MICROBLAZE - help - This driver supports XPS PS/2 IP from the Xilinx EDK on - PowerPC platform. - - To compile this driver as a module, choose M here: the - module will be called xilinx_ps2. - -config SERIO_ALTERA_PS2 - tristate "Altera UP PS/2 controller" - depends on HAS_IOMEM - help - Say Y here if you have Altera University Program PS/2 ports. - - To compile this driver as a module, choose M here: the - module will be called altera_ps2. - -config SERIO_AMS_DELTA - tristate "Amstrad Delta (E3) mailboard support" - depends on MACH_AMS_DELTA - default y - ---help--- - Say Y here if you have an E3 and want to use its mailboard, - or any standard AT keyboard connected to the mailboard port. - - When used for the E3 mailboard, a non-standard key table - must be loaded from userspace, possibly using udev extras - provided keymap helper utility. - - To compile this driver as a module, choose M here; - the module will be called ams_delta_serio. - -config SERIO_PS2MULT - tristate "TQC PS/2 multiplexer" - help - Say Y here if you have the PS/2 line multiplexer like the one - present on TQC boards. - - To compile this driver as a module, choose M here: the - module will be called ps2mult. - -config SERIO_ARC_PS2 - tristate "ARC PS/2 support" - depends on HAS_IOMEM - help - Say Y here if you have an ARC FPGA platform with a PS/2 - controller in it. - - To compile this driver as a module, choose M here; the module - will be called arc_ps2. - -config SERIO_APBPS2 - tristate "GRLIB APBPS2 PS/2 keyboard/mouse controller" - depends on OF - help - Say Y here if you want support for GRLIB APBPS2 peripherals used - to connect to PS/2 keyboard and/or mouse. - - To compile this driver as a module, choose M here: the module will - be called apbps2. - -config SERIO_OLPC_APSP - tristate "OLPC AP-SP input support" - depends on OLPC || COMPILE_TEST - help - Say Y here if you want support for the keyboard and touchpad included - in the OLPC XO-1.75 and XO-4 laptops. - - To compile this driver as a module, choose M here: the module will - be called olpc_apsp. - -config HYPERV_KEYBOARD - tristate "Microsoft Synthetic Keyboard driver" - depends on HYPERV - default HYPERV - help - Select this option to enable the Hyper-V Keyboard driver. - - To compile this driver as a module, choose M here: the module will - be called hyperv_keyboard. - -config SERIO_SUN4I_PS2 - tristate "Allwinner A10 PS/2 controller support" - depends on ARCH_SUNXI || COMPILE_TEST - help - This selects support for the PS/2 Host Controller on - Allwinner A10. - - To compile this driver as a module, choose M here: the - module will be called sun4i-ps2. - -config USERIO - tristate "User space serio port driver support" - help - Say Y here if you want to support user level drivers for serio - subsystem accessible under char device 10:240 - /dev/userio. Using - this facility userspace programs can implement serio ports that - will be used by the standard in-kernel serio consumer drivers, - such as psmouse and atkbd. - - To compile this driver as a module, choose M here: the module will be - called userio. - - If you are unsure, say N. - -endif diff --git a/src/linux/drivers/input/serio/Makefile b/src/linux/drivers/input/serio/Makefile deleted file mode 100644 index 2374ef9..0000000 --- a/src/linux/drivers/input/serio/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# -# Makefile for the input core drivers. -# - -# Each configuration option enables a list of files. - -obj-$(CONFIG_SERIO) += serio.o -obj-$(CONFIG_SERIO_I8042) += i8042.o -obj-$(CONFIG_SERIO_PARKBD) += parkbd.o -obj-$(CONFIG_SERIO_SERPORT) += serport.o -obj-$(CONFIG_SERIO_CT82C710) += ct82c710.o -obj-$(CONFIG_SERIO_RPCKBD) += rpckbd.o -obj-$(CONFIG_SERIO_SA1111) += sa1111ps2.o -obj-$(CONFIG_SERIO_AMBAKMI) += ambakmi.o -obj-$(CONFIG_SERIO_AT32PSIF) += at32psif.o -obj-$(CONFIG_SERIO_Q40KBD) += q40kbd.o -obj-$(CONFIG_SERIO_GSCPS2) += gscps2.o -obj-$(CONFIG_HP_SDC) += hp_sdc.o -obj-$(CONFIG_HIL_MLC) += hp_sdc_mlc.o hil_mlc.o -obj-$(CONFIG_SERIO_PCIPS2) += pcips2.o -obj-$(CONFIG_SERIO_PS2MULT) += ps2mult.o -obj-$(CONFIG_SERIO_MACEPS2) += maceps2.o -obj-$(CONFIG_SERIO_LIBPS2) += libps2.o -obj-$(CONFIG_SERIO_RAW) += serio_raw.o -obj-$(CONFIG_SERIO_AMS_DELTA) += ams_delta_serio.o -obj-$(CONFIG_SERIO_XILINX_XPS_PS2) += xilinx_ps2.o -obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_ps2.o -obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o -obj-$(CONFIG_SERIO_APBPS2) += apbps2.o -obj-$(CONFIG_SERIO_OLPC_APSP) += olpc_apsp.o -obj-$(CONFIG_HYPERV_KEYBOARD) += hyperv-keyboard.o -obj-$(CONFIG_SERIO_SUN4I_PS2) += sun4i-ps2.o -obj-$(CONFIG_USERIO) += userio.o diff --git a/src/linux/drivers/input/serio/libps2.c b/src/linux/drivers/input/serio/libps2.c deleted file mode 100644 index 83e9c66..0000000 --- a/src/linux/drivers/input/serio/libps2.c +++ /dev/null @@ -1,378 +0,0 @@ -/* - * PS/2 driver library - * - * Copyright (c) 1999-2002 Vojtech Pavlik - * Copyright (c) 2004 Dmitry Torokhov - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_DESC "PS/2 driver library" - -MODULE_AUTHOR("Dmitry Torokhov "); -MODULE_DESCRIPTION("PS/2 driver library"); -MODULE_LICENSE("GPL"); - -/* - * ps2_sendbyte() sends a byte to the device and waits for acknowledge. - * It doesn't handle retransmission, though it could - because if there - * is a need for retransmissions device has to be replaced anyway. - * - * ps2_sendbyte() can only be called from a process context. - */ - -int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout) -{ - serio_pause_rx(ps2dev->serio); - ps2dev->nak = 1; - ps2dev->flags |= PS2_FLAG_ACK; - serio_continue_rx(ps2dev->serio); - - if (serio_write(ps2dev->serio, byte) == 0) - wait_event_timeout(ps2dev->wait, - !(ps2dev->flags & PS2_FLAG_ACK), - msecs_to_jiffies(timeout)); - - serio_pause_rx(ps2dev->serio); - ps2dev->flags &= ~PS2_FLAG_ACK; - serio_continue_rx(ps2dev->serio); - - return -ps2dev->nak; -} -EXPORT_SYMBOL(ps2_sendbyte); - -void ps2_begin_command(struct ps2dev *ps2dev) -{ - struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex; - - mutex_lock(m); -} -EXPORT_SYMBOL(ps2_begin_command); - -void ps2_end_command(struct ps2dev *ps2dev) -{ - struct mutex *m = ps2dev->serio->ps2_cmd_mutex ?: &ps2dev->cmd_mutex; - - mutex_unlock(m); -} -EXPORT_SYMBOL(ps2_end_command); - -/* - * ps2_drain() waits for device to transmit requested number of bytes - * and discards them. - */ - -void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout) -{ - if (maxbytes > sizeof(ps2dev->cmdbuf)) { - WARN_ON(1); - maxbytes = sizeof(ps2dev->cmdbuf); - } - - ps2_begin_command(ps2dev); - - serio_pause_rx(ps2dev->serio); - ps2dev->flags = PS2_FLAG_CMD; - ps2dev->cmdcnt = maxbytes; - serio_continue_rx(ps2dev->serio); - - wait_event_timeout(ps2dev->wait, - !(ps2dev->flags & PS2_FLAG_CMD), - msecs_to_jiffies(timeout)); - - ps2_end_command(ps2dev); -} -EXPORT_SYMBOL(ps2_drain); - -/* - * ps2_is_keyboard_id() checks received ID byte against the list of - * known keyboard IDs. - */ - -int ps2_is_keyboard_id(char id_byte) -{ - static const char keyboard_ids[] = { - 0xab, /* Regular keyboards */ - 0xac, /* NCD Sun keyboard */ - 0x2b, /* Trust keyboard, translated */ - 0x5d, /* Trust keyboard */ - 0x60, /* NMB SGI keyboard, translated */ - 0x47, /* NMB SGI keyboard */ - }; - - return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL; -} -EXPORT_SYMBOL(ps2_is_keyboard_id); - -/* - * ps2_adjust_timeout() is called after receiving 1st byte of command - * response and tries to reduce remaining timeout to speed up command - * completion. - */ - -static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout) -{ - switch (command) { - case PS2_CMD_RESET_BAT: - /* - * Device has sent the first response byte after - * reset command, reset is thus done, so we can - * shorten the timeout. - * The next byte will come soon (keyboard) or not - * at all (mouse). - */ - if (timeout > msecs_to_jiffies(100)) - timeout = msecs_to_jiffies(100); - break; - - case PS2_CMD_GETID: - /* - * Microsoft Natural Elite keyboard responds to - * the GET ID command as it were a mouse, with - * a single byte. Fail the command so atkbd will - * use alternative probe to detect it. - */ - if (ps2dev->cmdbuf[1] == 0xaa) { - serio_pause_rx(ps2dev->serio); - ps2dev->flags = 0; - serio_continue_rx(ps2dev->serio); - timeout = 0; - } - - /* - * If device behind the port is not a keyboard there - * won't be 2nd byte of ID response. - */ - if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) { - serio_pause_rx(ps2dev->serio); - ps2dev->flags = ps2dev->cmdcnt = 0; - serio_continue_rx(ps2dev->serio); - timeout = 0; - } - break; - - default: - break; - } - - return timeout; -} - -/* - * ps2_command() sends a command and its parameters to the mouse, - * then waits for the response and puts it in the param array. - * - * ps2_command() can only be called from a process context - */ - -int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) -{ - int timeout; - int send = (command >> 12) & 0xf; - int receive = (command >> 8) & 0xf; - int rc = -1; - int i; - - if (receive > sizeof(ps2dev->cmdbuf)) { - WARN_ON(1); - return -1; - } - - if (send && !param) { - WARN_ON(1); - return -1; - } - - serio_pause_rx(ps2dev->serio); - ps2dev->flags = command == PS2_CMD_GETID ? PS2_FLAG_WAITID : 0; - ps2dev->cmdcnt = receive; - if (receive && param) - for (i = 0; i < receive; i++) - ps2dev->cmdbuf[(receive - 1) - i] = param[i]; - serio_continue_rx(ps2dev->serio); - - /* - * Some devices (Synaptics) peform the reset before - * ACKing the reset command, and so it can take a long - * time before the ACK arrives. - */ - if (ps2_sendbyte(ps2dev, command & 0xff, - command == PS2_CMD_RESET_BAT ? 1000 : 200)) { - serio_pause_rx(ps2dev->serio); - goto out_reset_flags; - } - - for (i = 0; i < send; i++) { - if (ps2_sendbyte(ps2dev, param[i], 200)) { - serio_pause_rx(ps2dev->serio); - goto out_reset_flags; - } - } - - /* - * The reset command takes a long time to execute. - */ - timeout = msecs_to_jiffies(command == PS2_CMD_RESET_BAT ? 4000 : 500); - - timeout = wait_event_timeout(ps2dev->wait, - !(ps2dev->flags & PS2_FLAG_CMD1), timeout); - - if (ps2dev->cmdcnt && !(ps2dev->flags & PS2_FLAG_CMD1)) { - - timeout = ps2_adjust_timeout(ps2dev, command, timeout); - wait_event_timeout(ps2dev->wait, - !(ps2dev->flags & PS2_FLAG_CMD), timeout); - } - - serio_pause_rx(ps2dev->serio); - - if (param) - for (i = 0; i < receive; i++) - param[i] = ps2dev->cmdbuf[(receive - 1) - i]; - - if (ps2dev->cmdcnt && (command != PS2_CMD_RESET_BAT || ps2dev->cmdcnt != 1)) - goto out_reset_flags; - - rc = 0; - - out_reset_flags: - ps2dev->flags = 0; - serio_continue_rx(ps2dev->serio); - - return rc; -} -EXPORT_SYMBOL(__ps2_command); - -int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command) -{ - int rc; - - ps2_begin_command(ps2dev); - rc = __ps2_command(ps2dev, param, command); - ps2_end_command(ps2dev); - - return rc; -} -EXPORT_SYMBOL(ps2_command); - -/* - * ps2_init() initializes ps2dev structure - */ - -void ps2_init(struct ps2dev *ps2dev, struct serio *serio) -{ - mutex_init(&ps2dev->cmd_mutex); - lockdep_set_subclass(&ps2dev->cmd_mutex, serio->depth); - init_waitqueue_head(&ps2dev->wait); - ps2dev->serio = serio; -} -EXPORT_SYMBOL(ps2_init); - -/* - * ps2_handle_ack() is supposed to be used in interrupt handler - * to properly process ACK/NAK of a command from a PS/2 device. - */ - -int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data) -{ - switch (data) { - case PS2_RET_ACK: - ps2dev->nak = 0; - break; - - case PS2_RET_NAK: - ps2dev->flags |= PS2_FLAG_NAK; - ps2dev->nak = PS2_RET_NAK; - break; - - case PS2_RET_ERR: - if (ps2dev->flags & PS2_FLAG_NAK) { - ps2dev->flags &= ~PS2_FLAG_NAK; - ps2dev->nak = PS2_RET_ERR; - break; - } - - /* - * Workaround for mice which don't ACK the Get ID command. - * These are valid mouse IDs that we recognize. - */ - case 0x00: - case 0x03: - case 0x04: - if (ps2dev->flags & PS2_FLAG_WAITID) { - ps2dev->nak = 0; - break; - } - /* Fall through */ - default: - return 0; - } - - - if (!ps2dev->nak) { - ps2dev->flags &= ~PS2_FLAG_NAK; - if (ps2dev->cmdcnt) - ps2dev->flags |= PS2_FLAG_CMD | PS2_FLAG_CMD1; - } - - ps2dev->flags &= ~PS2_FLAG_ACK; - wake_up(&ps2dev->wait); - - if (data != PS2_RET_ACK) - ps2_handle_response(ps2dev, data); - - return 1; -} -EXPORT_SYMBOL(ps2_handle_ack); - -/* - * ps2_handle_response() is supposed to be used in interrupt handler - * to properly store device's response to a command and notify process - * waiting for completion of the command. - */ - -int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data) -{ - if (ps2dev->cmdcnt) - ps2dev->cmdbuf[--ps2dev->cmdcnt] = data; - - if (ps2dev->flags & PS2_FLAG_CMD1) { - ps2dev->flags &= ~PS2_FLAG_CMD1; - if (ps2dev->cmdcnt) - wake_up(&ps2dev->wait); - } - - if (!ps2dev->cmdcnt) { - ps2dev->flags &= ~PS2_FLAG_CMD; - wake_up(&ps2dev->wait); - } - - return 1; -} -EXPORT_SYMBOL(ps2_handle_response); - -void ps2_cmd_aborted(struct ps2dev *ps2dev) -{ - if (ps2dev->flags & PS2_FLAG_ACK) - ps2dev->nak = 1; - - if (ps2dev->flags & (PS2_FLAG_ACK | PS2_FLAG_CMD)) - wake_up(&ps2dev->wait); - - /* reset all flags except last nack */ - ps2dev->flags &= PS2_FLAG_NAK; -} -EXPORT_SYMBOL(ps2_cmd_aborted); diff --git a/src/linux/drivers/input/serio/serio.c b/src/linux/drivers/input/serio/serio.c deleted file mode 100644 index 1ca7f55..0000000 --- a/src/linux/drivers/input/serio/serio.c +++ /dev/null @@ -1,1057 +0,0 @@ -/* - * The Serio abstraction module - * - * Copyright (c) 1999-2004 Vojtech Pavlik - * Copyright (c) 2004 Dmitry Torokhov - * Copyright (c) 2003 Daniele Bellucci - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Serio abstraction core"); -MODULE_LICENSE("GPL"); - -/* - * serio_mutex protects entire serio subsystem and is taken every time - * serio port or driver registered or unregistered. - */ -static DEFINE_MUTEX(serio_mutex); - -static LIST_HEAD(serio_list); - -static void serio_add_port(struct serio *serio); -static int serio_reconnect_port(struct serio *serio); -static void serio_disconnect_port(struct serio *serio); -static void serio_reconnect_subtree(struct serio *serio); -static void serio_attach_driver(struct serio_driver *drv); - -static int serio_connect_driver(struct serio *serio, struct serio_driver *drv) -{ - int retval; - - mutex_lock(&serio->drv_mutex); - retval = drv->connect(serio, drv); - mutex_unlock(&serio->drv_mutex); - - return retval; -} - -static int serio_reconnect_driver(struct serio *serio) -{ - int retval = -1; - - mutex_lock(&serio->drv_mutex); - if (serio->drv && serio->drv->reconnect) - retval = serio->drv->reconnect(serio); - mutex_unlock(&serio->drv_mutex); - - return retval; -} - -static void serio_disconnect_driver(struct serio *serio) -{ - mutex_lock(&serio->drv_mutex); - if (serio->drv) - serio->drv->disconnect(serio); - mutex_unlock(&serio->drv_mutex); -} - -static int serio_match_port(const struct serio_device_id *ids, struct serio *serio) -{ - while (ids->type || ids->proto) { - if ((ids->type == SERIO_ANY || ids->type == serio->id.type) && - (ids->proto == SERIO_ANY || ids->proto == serio->id.proto) && - (ids->extra == SERIO_ANY || ids->extra == serio->id.extra) && - (ids->id == SERIO_ANY || ids->id == serio->id.id)) - return 1; - ids++; - } - return 0; -} - -/* - * Basic serio -> driver core mappings - */ - -static int serio_bind_driver(struct serio *serio, struct serio_driver *drv) -{ - int error; - - if (serio_match_port(drv->id_table, serio)) { - - serio->dev.driver = &drv->driver; - if (serio_connect_driver(serio, drv)) { - serio->dev.driver = NULL; - return -ENODEV; - } - - error = device_bind_driver(&serio->dev); - if (error) { - dev_warn(&serio->dev, - "device_bind_driver() failed for %s (%s) and %s, error: %d\n", - serio->phys, serio->name, - drv->description, error); - serio_disconnect_driver(serio); - serio->dev.driver = NULL; - return error; - } - } - return 0; -} - -static void serio_find_driver(struct serio *serio) -{ - int error; - - error = device_attach(&serio->dev); - if (error < 0 && error != -EPROBE_DEFER) - dev_warn(&serio->dev, - "device_attach() failed for %s (%s), error: %d\n", - serio->phys, serio->name, error); -} - - -/* - * Serio event processing. - */ - -enum serio_event_type { - SERIO_RESCAN_PORT, - SERIO_RECONNECT_PORT, - SERIO_RECONNECT_SUBTREE, - SERIO_REGISTER_PORT, - SERIO_ATTACH_DRIVER, -}; - -struct serio_event { - enum serio_event_type type; - void *object; - struct module *owner; - struct list_head node; -}; - -static DEFINE_SPINLOCK(serio_event_lock); /* protects serio_event_list */ -static LIST_HEAD(serio_event_list); - -static struct serio_event *serio_get_event(void) -{ - struct serio_event *event = NULL; - unsigned long flags; - - spin_lock_irqsave(&serio_event_lock, flags); - - if (!list_empty(&serio_event_list)) { - event = list_first_entry(&serio_event_list, - struct serio_event, node); - list_del_init(&event->node); - } - - spin_unlock_irqrestore(&serio_event_lock, flags); - return event; -} - -static void serio_free_event(struct serio_event *event) -{ - module_put(event->owner); - kfree(event); -} - -static void serio_remove_duplicate_events(void *object, - enum serio_event_type type) -{ - struct serio_event *e, *next; - unsigned long flags; - - spin_lock_irqsave(&serio_event_lock, flags); - - list_for_each_entry_safe(e, next, &serio_event_list, node) { - if (object == e->object) { - /* - * If this event is of different type we should not - * look further - we only suppress duplicate events - * that were sent back-to-back. - */ - if (type != e->type) - break; - - list_del_init(&e->node); - serio_free_event(e); - } - } - - spin_unlock_irqrestore(&serio_event_lock, flags); -} - -static void serio_handle_event(struct work_struct *work) -{ - struct serio_event *event; - - mutex_lock(&serio_mutex); - - while ((event = serio_get_event())) { - - switch (event->type) { - - case SERIO_REGISTER_PORT: - serio_add_port(event->object); - break; - - case SERIO_RECONNECT_PORT: - serio_reconnect_port(event->object); - break; - - case SERIO_RESCAN_PORT: - serio_disconnect_port(event->object); - serio_find_driver(event->object); - break; - - case SERIO_RECONNECT_SUBTREE: - serio_reconnect_subtree(event->object); - break; - - case SERIO_ATTACH_DRIVER: - serio_attach_driver(event->object); - break; - } - - serio_remove_duplicate_events(event->object, event->type); - serio_free_event(event); - } - - mutex_unlock(&serio_mutex); -} - -static DECLARE_WORK(serio_event_work, serio_handle_event); - -static int serio_queue_event(void *object, struct module *owner, - enum serio_event_type event_type) -{ - unsigned long flags; - struct serio_event *event; - int retval = 0; - - spin_lock_irqsave(&serio_event_lock, flags); - - /* - * Scan event list for the other events for the same serio port, - * starting with the most recent one. If event is the same we - * do not need add new one. If event is of different type we - * need to add this event and should not look further because - * we need to preseve sequence of distinct events. - */ - list_for_each_entry_reverse(event, &serio_event_list, node) { - if (event->object == object) { - if (event->type == event_type) - goto out; - break; - } - } - - event = kmalloc(sizeof(struct serio_event), GFP_ATOMIC); - if (!event) { - pr_err("Not enough memory to queue event %d\n", event_type); - retval = -ENOMEM; - goto out; - } - - if (!try_module_get(owner)) { - pr_warning("Can't get module reference, dropping event %d\n", - event_type); - kfree(event); - retval = -EINVAL; - goto out; - } - - event->type = event_type; - event->object = object; - event->owner = owner; - - list_add_tail(&event->node, &serio_event_list); - queue_work(system_long_wq, &serio_event_work); - -out: - spin_unlock_irqrestore(&serio_event_lock, flags); - return retval; -} - -/* - * Remove all events that have been submitted for a given - * object, be it serio port or driver. - */ -static void serio_remove_pending_events(void *object) -{ - struct serio_event *event, *next; - unsigned long flags; - - spin_lock_irqsave(&serio_event_lock, flags); - - list_for_each_entry_safe(event, next, &serio_event_list, node) { - if (event->object == object) { - list_del_init(&event->node); - serio_free_event(event); - } - } - - spin_unlock_irqrestore(&serio_event_lock, flags); -} - -/* - * Locate child serio port (if any) that has not been fully registered yet. - * - * Children are registered by driver's connect() handler so there can't be a - * grandchild pending registration together with a child. - */ -static struct serio *serio_get_pending_child(struct serio *parent) -{ - struct serio_event *event; - struct serio *serio, *child = NULL; - unsigned long flags; - - spin_lock_irqsave(&serio_event_lock, flags); - - list_for_each_entry(event, &serio_event_list, node) { - if (event->type == SERIO_REGISTER_PORT) { - serio = event->object; - if (serio->parent == parent) { - child = serio; - break; - } - } - } - - spin_unlock_irqrestore(&serio_event_lock, flags); - return child; -} - -/* - * Serio port operations - */ - -static ssize_t serio_show_description(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct serio *serio = to_serio_port(dev); - return sprintf(buf, "%s\n", serio->name); -} - -static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct serio *serio = to_serio_port(dev); - - return sprintf(buf, "serio:ty%02Xpr%02Xid%02Xex%02X\n", - serio->id.type, serio->id.proto, serio->id.id, serio->id.extra); -} - -static ssize_t type_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct serio *serio = to_serio_port(dev); - return sprintf(buf, "%02x\n", serio->id.type); -} - -static ssize_t proto_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct serio *serio = to_serio_port(dev); - return sprintf(buf, "%02x\n", serio->id.proto); -} - -static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct serio *serio = to_serio_port(dev); - return sprintf(buf, "%02x\n", serio->id.id); -} - -static ssize_t extra_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct serio *serio = to_serio_port(dev); - return sprintf(buf, "%02x\n", serio->id.extra); -} - -static ssize_t drvctl_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct serio *serio = to_serio_port(dev); - struct device_driver *drv; - int error; - - error = mutex_lock_interruptible(&serio_mutex); - if (error) - return error; - - if (!strncmp(buf, "none", count)) { - serio_disconnect_port(serio); - } else if (!strncmp(buf, "reconnect", count)) { - serio_reconnect_subtree(serio); - } else if (!strncmp(buf, "rescan", count)) { - serio_disconnect_port(serio); - serio_find_driver(serio); - serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT); - } else if ((drv = driver_find(buf, &serio_bus)) != NULL) { - serio_disconnect_port(serio); - error = serio_bind_driver(serio, to_serio_driver(drv)); - serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT); - } else { - error = -EINVAL; - } - - mutex_unlock(&serio_mutex); - - return error ? error : count; -} - -static ssize_t serio_show_bind_mode(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct serio *serio = to_serio_port(dev); - return sprintf(buf, "%s\n", serio->manual_bind ? "manual" : "auto"); -} - -static ssize_t serio_set_bind_mode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) -{ - struct serio *serio = to_serio_port(dev); - int retval; - - retval = count; - if (!strncmp(buf, "manual", count)) { - serio->manual_bind = true; - } else if (!strncmp(buf, "auto", count)) { - serio->manual_bind = false; - } else { - retval = -EINVAL; - } - - return retval; -} - -static ssize_t firmware_id_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - struct serio *serio = to_serio_port(dev); - - return sprintf(buf, "%s\n", serio->firmware_id); -} - -static DEVICE_ATTR_RO(type); -static DEVICE_ATTR_RO(proto); -static DEVICE_ATTR_RO(id); -static DEVICE_ATTR_RO(extra); - -static struct attribute *serio_device_id_attrs[] = { - &dev_attr_type.attr, - &dev_attr_proto.attr, - &dev_attr_id.attr, - &dev_attr_extra.attr, - NULL -}; - -static struct attribute_group serio_id_attr_group = { - .name = "id", - .attrs = serio_device_id_attrs, -}; - -static DEVICE_ATTR_RO(modalias); -static DEVICE_ATTR_WO(drvctl); -static DEVICE_ATTR(description, S_IRUGO, serio_show_description, NULL); -static DEVICE_ATTR(bind_mode, S_IWUSR | S_IRUGO, serio_show_bind_mode, serio_set_bind_mode); -static DEVICE_ATTR_RO(firmware_id); - -static struct attribute *serio_device_attrs[] = { - &dev_attr_modalias.attr, - &dev_attr_description.attr, - &dev_attr_drvctl.attr, - &dev_attr_bind_mode.attr, - &dev_attr_firmware_id.attr, - NULL -}; - -static struct attribute_group serio_device_attr_group = { - .attrs = serio_device_attrs, -}; - -static const struct attribute_group *serio_device_attr_groups[] = { - &serio_id_attr_group, - &serio_device_attr_group, - NULL -}; - -static void serio_release_port(struct device *dev) -{ - struct serio *serio = to_serio_port(dev); - - kfree(serio); - module_put(THIS_MODULE); -} - -/* - * Prepare serio port for registration. - */ -static void serio_init_port(struct serio *serio) -{ - static atomic_t serio_no = ATOMIC_INIT(-1); - - __module_get(THIS_MODULE); - - INIT_LIST_HEAD(&serio->node); - INIT_LIST_HEAD(&serio->child_node); - INIT_LIST_HEAD(&serio->children); - spin_lock_init(&serio->lock); - mutex_init(&serio->drv_mutex); - device_initialize(&serio->dev); - dev_set_name(&serio->dev, "serio%lu", - (unsigned long)atomic_inc_return(&serio_no)); - serio->dev.bus = &serio_bus; - serio->dev.release = serio_release_port; - serio->dev.groups = serio_device_attr_groups; - if (serio->parent) { - serio->dev.parent = &serio->parent->dev; - serio->depth = serio->parent->depth + 1; - } else - serio->depth = 0; - lockdep_set_subclass(&serio->lock, serio->depth); -} - -/* - * Complete serio port registration. - * Driver core will attempt to find appropriate driver for the port. - */ -static void serio_add_port(struct serio *serio) -{ - struct serio *parent = serio->parent; - int error; - - if (parent) { - serio_pause_rx(parent); - list_add_tail(&serio->child_node, &parent->children); - serio_continue_rx(parent); - } - - list_add_tail(&serio->node, &serio_list); - - if (serio->start) - serio->start(serio); - - error = device_add(&serio->dev); - if (error) - dev_err(&serio->dev, - "device_add() failed for %s (%s), error: %d\n", - serio->phys, serio->name, error); -} - -/* - * serio_destroy_port() completes unregistration process and removes - * port from the system - */ -static void serio_destroy_port(struct serio *serio) -{ - struct serio *child; - - while ((child = serio_get_pending_child(serio)) != NULL) { - serio_remove_pending_events(child); - put_device(&child->dev); - } - - if (serio->stop) - serio->stop(serio); - - if (serio->parent) { - serio_pause_rx(serio->parent); - list_del_init(&serio->child_node); - serio_continue_rx(serio->parent); - serio->parent = NULL; - } - - if (device_is_registered(&serio->dev)) - device_del(&serio->dev); - - list_del_init(&serio->node); - serio_remove_pending_events(serio); - put_device(&serio->dev); -} - -/* - * Reconnect serio port (re-initialize attached device). - * If reconnect fails (old device is no longer attached or - * there was no device to begin with) we do full rescan in - * hope of finding a driver for the port. - */ -static int serio_reconnect_port(struct serio *serio) -{ - int error = serio_reconnect_driver(serio); - - if (error) { - serio_disconnect_port(serio); - serio_find_driver(serio); - } - - return error; -} - -/* - * Reconnect serio port and all its children (re-initialize attached - * devices). - */ -static void serio_reconnect_subtree(struct serio *root) -{ - struct serio *s = root; - int error; - - do { - error = serio_reconnect_port(s); - if (!error) { - /* - * Reconnect was successful, move on to do the - * first child. - */ - if (!list_empty(&s->children)) { - s = list_first_entry(&s->children, - struct serio, child_node); - continue; - } - } - - /* - * Either it was a leaf node or reconnect failed and it - * became a leaf node. Continue reconnecting starting with - * the next sibling of the parent node. - */ - while (s != root) { - struct serio *parent = s->parent; - - if (!list_is_last(&s->child_node, &parent->children)) { - s = list_entry(s->child_node.next, - struct serio, child_node); - break; - } - - s = parent; - } - } while (s != root); -} - -/* - * serio_disconnect_port() unbinds a port from its driver. As a side effect - * all children ports are unbound and destroyed. - */ -static void serio_disconnect_port(struct serio *serio) -{ - struct serio *s = serio; - - /* - * Children ports should be disconnected and destroyed - * first; we travel the tree in depth-first order. - */ - while (!list_empty(&serio->children)) { - - /* Locate a leaf */ - while (!list_empty(&s->children)) - s = list_first_entry(&s->children, - struct serio, child_node); - - /* - * Prune this leaf node unless it is the one we - * started with. - */ - if (s != serio) { - struct serio *parent = s->parent; - - device_release_driver(&s->dev); - serio_destroy_port(s); - - s = parent; - } - } - - /* - * OK, no children left, now disconnect this port. - */ - device_release_driver(&serio->dev); -} - -void serio_rescan(struct serio *serio) -{ - serio_queue_event(serio, NULL, SERIO_RESCAN_PORT); -} -EXPORT_SYMBOL(serio_rescan); - -void serio_reconnect(struct serio *serio) -{ - serio_queue_event(serio, NULL, SERIO_RECONNECT_SUBTREE); -} -EXPORT_SYMBOL(serio_reconnect); - -/* - * Submits register request to kseriod for subsequent execution. - * Note that port registration is always asynchronous. - */ -void __serio_register_port(struct serio *serio, struct module *owner) -{ - serio_init_port(serio); - serio_queue_event(serio, owner, SERIO_REGISTER_PORT); -} -EXPORT_SYMBOL(__serio_register_port); - -/* - * Synchronously unregisters serio port. - */ -void serio_unregister_port(struct serio *serio) -{ - mutex_lock(&serio_mutex); - serio_disconnect_port(serio); - serio_destroy_port(serio); - mutex_unlock(&serio_mutex); -} -EXPORT_SYMBOL(serio_unregister_port); - -/* - * Safely unregisters children ports if they are present. - */ -void serio_unregister_child_port(struct serio *serio) -{ - struct serio *s, *next; - - mutex_lock(&serio_mutex); - list_for_each_entry_safe(s, next, &serio->children, child_node) { - serio_disconnect_port(s); - serio_destroy_port(s); - } - mutex_unlock(&serio_mutex); -} -EXPORT_SYMBOL(serio_unregister_child_port); - - -/* - * Serio driver operations - */ - -static ssize_t description_show(struct device_driver *drv, char *buf) -{ - struct serio_driver *driver = to_serio_driver(drv); - return sprintf(buf, "%s\n", driver->description ? driver->description : "(none)"); -} -static DRIVER_ATTR_RO(description); - -static ssize_t bind_mode_show(struct device_driver *drv, char *buf) -{ - struct serio_driver *serio_drv = to_serio_driver(drv); - return sprintf(buf, "%s\n", serio_drv->manual_bind ? "manual" : "auto"); -} - -static ssize_t bind_mode_store(struct device_driver *drv, const char *buf, size_t count) -{ - struct serio_driver *serio_drv = to_serio_driver(drv); - int retval; - - retval = count; - if (!strncmp(buf, "manual", count)) { - serio_drv->manual_bind = true; - } else if (!strncmp(buf, "auto", count)) { - serio_drv->manual_bind = false; - } else { - retval = -EINVAL; - } - - return retval; -} -static DRIVER_ATTR_RW(bind_mode); - -static struct attribute *serio_driver_attrs[] = { - &driver_attr_description.attr, - &driver_attr_bind_mode.attr, - NULL, -}; -ATTRIBUTE_GROUPS(serio_driver); - -static int serio_driver_probe(struct device *dev) -{ - struct serio *serio = to_serio_port(dev); - struct serio_driver *drv = to_serio_driver(dev->driver); - - return serio_connect_driver(serio, drv); -} - -static int serio_driver_remove(struct device *dev) -{ - struct serio *serio = to_serio_port(dev); - - serio_disconnect_driver(serio); - return 0; -} - -static void serio_cleanup(struct serio *serio) -{ - mutex_lock(&serio->drv_mutex); - if (serio->drv && serio->drv->cleanup) - serio->drv->cleanup(serio); - mutex_unlock(&serio->drv_mutex); -} - -static void serio_shutdown(struct device *dev) -{ - struct serio *serio = to_serio_port(dev); - - serio_cleanup(serio); -} - -static void serio_attach_driver(struct serio_driver *drv) -{ - int error; - - error = driver_attach(&drv->driver); - if (error) - pr_warning("driver_attach() failed for %s with error %d\n", - drv->driver.name, error); -} - -int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name) -{ - bool manual_bind = drv->manual_bind; - int error; - - drv->driver.bus = &serio_bus; - drv->driver.owner = owner; - drv->driver.mod_name = mod_name; - - /* - * Temporarily disable automatic binding because probing - * takes long time and we are better off doing it in kseriod - */ - drv->manual_bind = true; - - error = driver_register(&drv->driver); - if (error) { - pr_err("driver_register() failed for %s, error: %d\n", - drv->driver.name, error); - return error; - } - - /* - * Restore original bind mode and let kseriod bind the - * driver to free ports - */ - if (!manual_bind) { - drv->manual_bind = false; - error = serio_queue_event(drv, NULL, SERIO_ATTACH_DRIVER); - if (error) { - driver_unregister(&drv->driver); - return error; - } - } - - return 0; -} -EXPORT_SYMBOL(__serio_register_driver); - -void serio_unregister_driver(struct serio_driver *drv) -{ - struct serio *serio; - - mutex_lock(&serio_mutex); - - drv->manual_bind = true; /* so serio_find_driver ignores it */ - serio_remove_pending_events(drv); - -start_over: - list_for_each_entry(serio, &serio_list, node) { - if (serio->drv == drv) { - serio_disconnect_port(serio); - serio_find_driver(serio); - /* we could've deleted some ports, restart */ - goto start_over; - } - } - - driver_unregister(&drv->driver); - mutex_unlock(&serio_mutex); -} -EXPORT_SYMBOL(serio_unregister_driver); - -static void serio_set_drv(struct serio *serio, struct serio_driver *drv) -{ - serio_pause_rx(serio); - serio->drv = drv; - serio_continue_rx(serio); -} - -static int serio_bus_match(struct device *dev, struct device_driver *drv) -{ - struct serio *serio = to_serio_port(dev); - struct serio_driver *serio_drv = to_serio_driver(drv); - - if (serio->manual_bind || serio_drv->manual_bind) - return 0; - - return serio_match_port(serio_drv->id_table, serio); -} - -#define SERIO_ADD_UEVENT_VAR(fmt, val...) \ - do { \ - int err = add_uevent_var(env, fmt, val); \ - if (err) \ - return err; \ - } while (0) - -static int serio_uevent(struct device *dev, struct kobj_uevent_env *env) -{ - struct serio *serio; - - if (!dev) - return -ENODEV; - - serio = to_serio_port(dev); - - SERIO_ADD_UEVENT_VAR("SERIO_TYPE=%02x", serio->id.type); - SERIO_ADD_UEVENT_VAR("SERIO_PROTO=%02x", serio->id.proto); - SERIO_ADD_UEVENT_VAR("SERIO_ID=%02x", serio->id.id); - SERIO_ADD_UEVENT_VAR("SERIO_EXTRA=%02x", serio->id.extra); - - SERIO_ADD_UEVENT_VAR("MODALIAS=serio:ty%02Xpr%02Xid%02Xex%02X", - serio->id.type, serio->id.proto, serio->id.id, serio->id.extra); - - if (serio->firmware_id[0]) - SERIO_ADD_UEVENT_VAR("SERIO_FIRMWARE_ID=%s", - serio->firmware_id); - - return 0; -} -#undef SERIO_ADD_UEVENT_VAR - -#ifdef CONFIG_PM -static int serio_suspend(struct device *dev) -{ - struct serio *serio = to_serio_port(dev); - - serio_cleanup(serio); - - return 0; -} - -static int serio_resume(struct device *dev) -{ - struct serio *serio = to_serio_port(dev); - - /* - * Driver reconnect can take a while, so better let kseriod - * deal with it. - */ - serio_queue_event(serio, NULL, SERIO_RECONNECT_PORT); - - return 0; -} - -static const struct dev_pm_ops serio_pm_ops = { - .suspend = serio_suspend, - .resume = serio_resume, - .poweroff = serio_suspend, - .restore = serio_resume, -}; -#endif /* CONFIG_PM */ - -/* called from serio_driver->connect/disconnect methods under serio_mutex */ -int serio_open(struct serio *serio, struct serio_driver *drv) -{ - serio_set_drv(serio, drv); - - if (serio->open && serio->open(serio)) { - serio_set_drv(serio, NULL); - return -1; - } - return 0; -} -EXPORT_SYMBOL(serio_open); - -/* called from serio_driver->connect/disconnect methods under serio_mutex */ -void serio_close(struct serio *serio) -{ - if (serio->close) - serio->close(serio); - - serio_set_drv(serio, NULL); -} -EXPORT_SYMBOL(serio_close); - -irqreturn_t serio_interrupt(struct serio *serio, - unsigned char data, unsigned int dfl) -{ - unsigned long flags; - irqreturn_t ret = IRQ_NONE; - - spin_lock_irqsave(&serio->lock, flags); - - if (likely(serio->drv)) { - ret = serio->drv->interrupt(serio, data, dfl); - } else if (!dfl && device_is_registered(&serio->dev)) { - serio_rescan(serio); - ret = IRQ_HANDLED; - } - - spin_unlock_irqrestore(&serio->lock, flags); - - return ret; -} -EXPORT_SYMBOL(serio_interrupt); - -struct bus_type serio_bus = { - .name = "serio", - .drv_groups = serio_driver_groups, - .match = serio_bus_match, - .uevent = serio_uevent, - .probe = serio_driver_probe, - .remove = serio_driver_remove, - .shutdown = serio_shutdown, -#ifdef CONFIG_PM - .pm = &serio_pm_ops, -#endif -}; -EXPORT_SYMBOL(serio_bus); - -static int __init serio_init(void) -{ - int error; - - error = bus_register(&serio_bus); - if (error) { - pr_err("Failed to register serio bus, error: %d\n", error); - return error; - } - - return 0; -} - -static void __exit serio_exit(void) -{ - bus_unregister(&serio_bus); - - /* - * There should not be any outstanding events but work may - * still be scheduled so simply cancel it. - */ - cancel_work_sync(&serio_event_work); -} - -subsys_initcall(serio_init); -module_exit(serio_exit); diff --git a/src/linux/drivers/input/serio/serport.c b/src/linux/drivers/input/serio/serport.c deleted file mode 100644 index d189843..0000000 --- a/src/linux/drivers/input/serio/serport.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Input device TTY line discipline - * - * Copyright (c) 1999-2002 Vojtech Pavlik - * - * This is a module that converts a tty line into a much simpler - * 'serial io port' abstraction that the input device drivers use. - */ - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Input device TTY line discipline"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_LDISC(N_MOUSE); - -#define SERPORT_BUSY 1 -#define SERPORT_ACTIVE 2 -#define SERPORT_DEAD 3 - -struct serport { - struct tty_struct *tty; - wait_queue_head_t wait; - struct serio *serio; - struct serio_device_id id; - spinlock_t lock; - unsigned long flags; -}; - -/* - * Callback functions from the serio code. - */ - -static int serport_serio_write(struct serio *serio, unsigned char data) -{ - struct serport *serport = serio->port_data; - return -(serport->tty->ops->write(serport->tty, &data, 1) != 1); -} - -static int serport_serio_open(struct serio *serio) -{ - struct serport *serport = serio->port_data; - unsigned long flags; - - spin_lock_irqsave(&serport->lock, flags); - set_bit(SERPORT_ACTIVE, &serport->flags); - spin_unlock_irqrestore(&serport->lock, flags); - - return 0; -} - - -static void serport_serio_close(struct serio *serio) -{ - struct serport *serport = serio->port_data; - unsigned long flags; - - spin_lock_irqsave(&serport->lock, flags); - clear_bit(SERPORT_ACTIVE, &serport->flags); - spin_unlock_irqrestore(&serport->lock, flags); -} - -/* - * serport_ldisc_open() is the routine that is called upon setting our line - * discipline on a tty. It prepares the serio struct. - */ - -static int serport_ldisc_open(struct tty_struct *tty) -{ - struct serport *serport; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - serport = kzalloc(sizeof(struct serport), GFP_KERNEL); - if (!serport) - return -ENOMEM; - - serport->tty = tty; - spin_lock_init(&serport->lock); - init_waitqueue_head(&serport->wait); - - tty->disc_data = serport; - tty->receive_room = 256; - set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - - return 0; -} - -/* - * serport_ldisc_close() is the opposite of serport_ldisc_open() - */ - -static void serport_ldisc_close(struct tty_struct *tty) -{ - struct serport *serport = (struct serport *) tty->disc_data; - - kfree(serport); -} - -/* - * serport_ldisc_receive() is called by the low level tty driver when characters - * are ready for us. We forward the characters and flags, one by one to the - * 'interrupt' routine. - */ - -static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) -{ - struct serport *serport = (struct serport*) tty->disc_data; - unsigned long flags; - unsigned int ch_flags = 0; - int i; - - spin_lock_irqsave(&serport->lock, flags); - - if (!test_bit(SERPORT_ACTIVE, &serport->flags)) - goto out; - - for (i = 0; i < count; i++) { - if (fp) { - switch (fp[i]) { - case TTY_FRAME: - ch_flags = SERIO_FRAME; - break; - - case TTY_PARITY: - ch_flags = SERIO_PARITY; - break; - - default: - ch_flags = 0; - break; - } - } - - serio_interrupt(serport->serio, cp[i], ch_flags); - } - -out: - spin_unlock_irqrestore(&serport->lock, flags); -} - -/* - * serport_ldisc_read() just waits indefinitely if everything goes well. - * However, when the serio driver closes the serio port, it finishes, - * returning 0 characters. - */ - -static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char __user * buf, size_t nr) -{ - struct serport *serport = (struct serport*) tty->disc_data; - struct serio *serio; - - if (test_and_set_bit(SERPORT_BUSY, &serport->flags)) - return -EBUSY; - - serport->serio = serio = kzalloc(sizeof(struct serio), GFP_KERNEL); - if (!serio) - return -ENOMEM; - - strlcpy(serio->name, "Serial port", sizeof(serio->name)); - snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", tty_name(tty)); - serio->id = serport->id; - serio->id.type = SERIO_RS232; - serio->write = serport_serio_write; - serio->open = serport_serio_open; - serio->close = serport_serio_close; - serio->port_data = serport; - serio->dev.parent = tty->dev; - - serio_register_port(serport->serio); - printk(KERN_INFO "serio: Serial port %s\n", tty_name(tty)); - - wait_event_interruptible(serport->wait, test_bit(SERPORT_DEAD, &serport->flags)); - serio_unregister_port(serport->serio); - serport->serio = NULL; - - clear_bit(SERPORT_DEAD, &serport->flags); - clear_bit(SERPORT_BUSY, &serport->flags); - - return 0; -} - -static void serport_set_type(struct tty_struct *tty, unsigned long type) -{ - struct serport *serport = tty->disc_data; - - serport->id.proto = type & 0x000000ff; - serport->id.id = (type & 0x0000ff00) >> 8; - serport->id.extra = (type & 0x00ff0000) >> 16; -} - -/* - * serport_ldisc_ioctl() allows to set the port protocol, and device ID - */ - -static int serport_ldisc_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - if (cmd == SPIOCSTYPE) { - unsigned long type; - - if (get_user(type, (unsigned long __user *) arg)) - return -EFAULT; - - serport_set_type(tty, type); - return 0; - } - - return -EINVAL; -} - -#ifdef CONFIG_COMPAT -#define COMPAT_SPIOCSTYPE _IOW('q', 0x01, compat_ulong_t) -static long serport_ldisc_compat_ioctl(struct tty_struct *tty, - struct file *file, - unsigned int cmd, unsigned long arg) -{ - if (cmd == COMPAT_SPIOCSTYPE) { - void __user *uarg = compat_ptr(arg); - compat_ulong_t compat_type; - - if (get_user(compat_type, (compat_ulong_t __user *)uarg)) - return -EFAULT; - - serport_set_type(tty, compat_type); - return 0; - } - - return -EINVAL; -} -#endif - -static int serport_ldisc_hangup(struct tty_struct *tty) -{ - struct serport *serport = (struct serport *) tty->disc_data; - unsigned long flags; - - spin_lock_irqsave(&serport->lock, flags); - set_bit(SERPORT_DEAD, &serport->flags); - spin_unlock_irqrestore(&serport->lock, flags); - - wake_up_interruptible(&serport->wait); - return 0; -} - -static void serport_ldisc_write_wakeup(struct tty_struct * tty) -{ - struct serport *serport = (struct serport *) tty->disc_data; - unsigned long flags; - - spin_lock_irqsave(&serport->lock, flags); - if (test_bit(SERPORT_ACTIVE, &serport->flags)) - serio_drv_write_wakeup(serport->serio); - spin_unlock_irqrestore(&serport->lock, flags); -} - -/* - * The line discipline structure. - */ - -static struct tty_ldisc_ops serport_ldisc = { - .owner = THIS_MODULE, - .name = "input", - .open = serport_ldisc_open, - .close = serport_ldisc_close, - .read = serport_ldisc_read, - .ioctl = serport_ldisc_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = serport_ldisc_compat_ioctl, -#endif - .receive_buf = serport_ldisc_receive, - .hangup = serport_ldisc_hangup, - .write_wakeup = serport_ldisc_write_wakeup -}; - -/* - * The functions for insering/removing us as a module. - */ - -static int __init serport_init(void) -{ - int retval; - retval = tty_register_ldisc(N_MOUSE, &serport_ldisc); - if (retval) - printk(KERN_ERR "serport.c: Error registering line discipline.\n"); - - return retval; -} - -static void __exit serport_exit(void) -{ - tty_unregister_ldisc(N_MOUSE); -} - -module_init(serport_init); -module_exit(serport_exit); diff --git a/src/linux/drivers/input/tablet/Kconfig b/src/linux/drivers/input/tablet/Kconfig deleted file mode 100644 index a2b9f97..0000000 --- a/src/linux/drivers/input/tablet/Kconfig +++ /dev/null @@ -1,101 +0,0 @@ -# -# Tablet driver configuration -# -menuconfig INPUT_TABLET - bool "Tablets" - help - Say Y here, and a list of supported tablets will be displayed. - This option doesn't affect the kernel. - - If unsure, say Y. - -if INPUT_TABLET - -config TABLET_USB_ACECAD - tristate "Acecad Flair tablet support (USB)" - depends on USB_ARCH_HAS_HCD - select USB - help - Say Y here if you want to use the USB version of the Acecad Flair - tablet. Make sure to say Y to "Mouse support" - (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" - (CONFIG_INPUT_EVDEV) as well. - - To compile this driver as a module, choose M here: the - module will be called acecad. - -config TABLET_USB_AIPTEK - tristate "Aiptek 6000U/8000U and Genius G_PEN tablet support (USB)" - depends on USB_ARCH_HAS_HCD - select USB - help - Say Y here if you want to use the USB version of the Aiptek 6000U, - Aiptek 8000U or Genius G-PEN 560 tablet. Make sure to say Y to - "Mouse support" (CONFIG_INPUT_MOUSEDEV) and/or "Event interface - support" (CONFIG_INPUT_EVDEV) as well. - - To compile this driver as a module, choose M here: the - module will be called aiptek. - -config TABLET_USB_GTCO - tristate "GTCO CalComp/InterWrite USB Support" - depends on USB && INPUT - help - Say Y here if you want to use the USB version of the GTCO - CalComp/InterWrite Tablet. Make sure to say Y to "Mouse support" - (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" - (CONFIG_INPUT_EVDEV) as well. - - To compile this driver as a module, choose M here: the - module will be called gtco. - -config TABLET_USB_HANWANG - tristate "Hanwang Art Master III tablet support (USB)" - depends on USB_ARCH_HAS_HCD - select USB - help - Say Y here if you want to use the USB version of the Hanwang Art - Master III tablet. - - To compile this driver as a module, choose M here: the - module will be called hanwang. - -config TABLET_USB_KBTAB - tristate "KB Gear JamStudio tablet support (USB)" - depends on USB_ARCH_HAS_HCD - select USB - help - Say Y here if you want to use the USB version of the KB Gear - JamStudio tablet. Make sure to say Y to "Mouse support" - (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support" - (CONFIG_INPUT_EVDEV) as well. - - To compile this driver as a module, choose M here: the - module will be called kbtab. - -config TABLET_USB_PEGASUS - tristate "Pegasus Mobile Notetaker Pen input tablet support" - depends on USB_ARCH_HAS_HCD - select USB - help - Say Y here if you want to use the Pegasus Mobile Notetaker, - also known as: - Genie e-note The Notetaker, - Staedtler Digital ballpoint pen 990 01, - IRISnotes Express or - NEWLink Digital Note Taker. - - To compile this driver as a module, choose M here: the - module will be called pegasus_notetaker. - -config TABLET_SERIAL_WACOM4 - tristate "Wacom protocol 4 serial tablet support" - select SERIO - help - Say Y here if you want to use Wacom protocol 4 serial tablets. - E.g. serial versions of the Cintiq, Graphire or Penpartner. - - To compile this driver as a module, choose M here: the - module will be called wacom_serial4. - -endif diff --git a/src/linux/drivers/input/touchscreen/Kconfig b/src/linux/drivers/input/touchscreen/Kconfig deleted file mode 100644 index efca013..0000000 --- a/src/linux/drivers/input/touchscreen/Kconfig +++ /dev/null @@ -1,1217 +0,0 @@ -# -# Touchscreen driver configuration -# -menuconfig INPUT_TOUCHSCREEN - bool "Touchscreens" - help - Say Y here, and a list of supported touchscreens will be displayed. - This option doesn't affect the kernel. - - If unsure, say Y. - -if INPUT_TOUCHSCREEN - -config TOUCHSCREEN_PROPERTIES - def_tristate INPUT - depends on INPUT - -config TOUCHSCREEN_88PM860X - tristate "Marvell 88PM860x touchscreen" - depends on MFD_88PM860X - help - Say Y here if you have a 88PM860x PMIC and want to enable - support for the built-in touchscreen. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called 88pm860x-ts. - -config TOUCHSCREEN_ADS7846 - tristate "ADS7846/TSC2046/AD7873 and AD(S)7843 based touchscreens" - depends on SPI_MASTER - depends on HWMON = n || HWMON - help - Say Y here if you have a touchscreen interface using the - ADS7846/TSC2046/AD7873 or ADS7843/AD7843 controller, - and your board-specific setup code includes that in its - table of SPI devices. - - If HWMON is selected, and the driver is told the reference voltage - on your board, you will also get hwmon interfaces for the voltage - (and on ads7846/tsc2046/ad7873, temperature) sensors of this chip. - - If unsure, say N (but it's safe to say "Y"). - - To compile this driver as a module, choose M here: the - module will be called ads7846. - -config TOUCHSCREEN_AD7877 - tristate "AD7877 based touchscreens" - depends on SPI_MASTER - help - Say Y here if you have a touchscreen interface using the - AD7877 controller, and your board-specific initialization - code includes that in its table of SPI devices. - - If unsure, say N (but it's safe to say "Y"). - - To compile this driver as a module, choose M here: the - module will be called ad7877. - -config TOUCHSCREEN_AD7879 - tristate "Analog Devices AD7879-1/AD7889-1 touchscreen interface" - help - Say Y here if you want to support a touchscreen interface using - the AD7879-1/AD7889-1 controller. - - You should select a bus connection too. - - To compile this driver as a module, choose M here: the - module will be called ad7879. - -config TOUCHSCREEN_AD7879_I2C - tristate "support I2C bus connection" - depends on TOUCHSCREEN_AD7879 && I2C - help - Say Y here if you have AD7879-1/AD7889-1 hooked to an I2C bus. - - To compile this driver as a module, choose M here: the - module will be called ad7879-i2c. - -config TOUCHSCREEN_AD7879_SPI - tristate "support SPI bus connection" - depends on TOUCHSCREEN_AD7879 && SPI_MASTER - help - Say Y here if you have AD7879-1/AD7889-1 hooked to a SPI bus. - - If unsure, say N (but it's safe to say "Y"). - - To compile this driver as a module, choose M here: the - module will be called ad7879-spi. - -config TOUCHSCREEN_AR1021_I2C - tristate "Microchip AR1021 i2c touchscreen" - depends on I2C && OF - help - Say Y here if you have the Microchip AR1021 touchscreen controller - chip in your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called ar1021_i2c. - -config TOUCHSCREEN_ATMEL_MXT - tristate "Atmel mXT I2C Touchscreen" - depends on I2C - select FW_LOADER - help - Say Y here if you have Atmel mXT series I2C touchscreen, - such as AT42QT602240/ATMXT224, connected to your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called atmel_mxt_ts. - -config TOUCHSCREEN_ATMEL_MXT_T37 - bool "Support T37 Diagnostic Data" - depends on TOUCHSCREEN_ATMEL_MXT - depends on VIDEO_V4L2=y || (TOUCHSCREEN_ATMEL_MXT=m && VIDEO_V4L2=m) - select VIDEOBUF2_VMALLOC - help - Say Y here if you want support to output data from the T37 - Diagnostic Data object using a V4L device. - -config TOUCHSCREEN_AUO_PIXCIR - tristate "AUO in-cell touchscreen using Pixcir ICs" - depends on I2C - depends on GPIOLIB || COMPILE_TEST - help - Say Y here if you have a AUO display with in-cell touchscreen - using Pixcir ICs. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called auo-pixcir-ts. - -config TOUCHSCREEN_BU21013 - tristate "BU21013 based touch panel controllers" - depends on I2C - help - Say Y here if you have a bu21013 touchscreen connected to - your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called bu21013_ts. - -config TOUCHSCREEN_CHIPONE_ICN8318 - tristate "chipone icn8318 touchscreen controller" - depends on GPIOLIB || COMPILE_TEST - depends on I2C - depends on OF - help - Say Y here if you have a ChipOne icn8318 based I2C touchscreen. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called chipone_icn8318. - -config TOUCHSCREEN_CY8CTMG110 - tristate "cy8ctmg110 touchscreen" - depends on I2C - depends on GPIOLIB || COMPILE_TEST - help - Say Y here if you have a cy8ctmg110 capacitive touchscreen on - an AAVA device. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called cy8ctmg110_ts. - -config TOUCHSCREEN_CYTTSP_CORE - tristate "Cypress TTSP touchscreen" - help - Say Y here if you have a touchscreen using controller from - the Cypress TrueTouch(tm) Standard Product family connected - to your system. You will also need to select appropriate - bus connection below. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called cyttsp_core. - -config TOUCHSCREEN_CYTTSP_I2C - tristate "support I2C bus connection" - depends on TOUCHSCREEN_CYTTSP_CORE && I2C - help - Say Y here if the touchscreen is connected via I2C bus. - - To compile this driver as a module, choose M here: the - module will be called cyttsp_i2c. - -config TOUCHSCREEN_CYTTSP_SPI - tristate "support SPI bus connection" - depends on TOUCHSCREEN_CYTTSP_CORE && SPI_MASTER - help - Say Y here if the touchscreen is connected via SPI bus. - - To compile this driver as a module, choose M here: the - module will be called cyttsp_spi. - -config TOUCHSCREEN_CYTTSP4_CORE - tristate "Cypress TrueTouch Gen4 Touchscreen Driver" - help - Core driver for Cypress TrueTouch(tm) Standard Product - Generation4 touchscreen controllers. - - Say Y here if you have a Cypress Gen4 touchscreen. - - If unsure, say N. - - To compile this driver as a module, choose M here. - -config TOUCHSCREEN_CYTTSP4_I2C - tristate "support I2C bus connection" - depends on TOUCHSCREEN_CYTTSP4_CORE && I2C - help - Say Y here if the touchscreen is connected via I2C bus. - - To compile this driver as a module, choose M here: the - module will be called cyttsp4_i2c. - -config TOUCHSCREEN_CYTTSP4_SPI - tristate "support SPI bus connection" - depends on TOUCHSCREEN_CYTTSP4_CORE && SPI_MASTER - help - Say Y here if the touchscreen is connected via SPI bus. - - To compile this driver as a module, choose M here: the - module will be called cyttsp4_spi. - -config TOUCHSCREEN_DA9034 - tristate "Touchscreen support for Dialog Semiconductor DA9034" - depends on PMIC_DA903X - default y - help - Say Y here to enable the support for the touchscreen found - on Dialog Semiconductor DA9034 PMIC. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called da9034-ts. - -config TOUCHSCREEN_DA9052 - tristate "Dialog DA9052/DA9053 TSI" - depends on PMIC_DA9052 - help - Say Y here to support the touchscreen found on Dialog Semiconductor - DA9052-BC and DA9053-AA/Bx PMICs. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called da9052_tsi. - -config TOUCHSCREEN_DYNAPRO - tristate "Dynapro serial touchscreen" - select SERIO - help - Say Y here if you have a Dynapro serial touchscreen connected to - your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called dynapro. - -config TOUCHSCREEN_HAMPSHIRE - tristate "Hampshire serial touchscreen" - select SERIO - help - Say Y here if you have a Hampshire serial touchscreen connected to - your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called hampshire. - -config TOUCHSCREEN_EETI - tristate "EETI touchscreen panel support" - depends on I2C - help - Say Y here to enable support for I2C connected EETI touch panels. - - To compile this driver as a module, choose M here: the - module will be called eeti_ts. - -config TOUCHSCREEN_EGALAX - tristate "EETI eGalax multi-touch panel support" - depends on I2C && OF - help - Say Y here to enable support for I2C connected EETI - eGalax multi-touch panels. - - To compile this driver as a module, choose M here: the - module will be called egalax_ts. - -config TOUCHSCREEN_EGALAX_SERIAL - tristate "EETI eGalax serial touchscreen" - select SERIO - help - Say Y here to enable support for serial connected EETI - eGalax touch panels. - - To compile this driver as a module, choose M here: the - module will be called egalax_ts_serial. - -config TOUCHSCREEN_FUJITSU - tristate "Fujitsu serial touchscreen" - select SERIO - help - Say Y here if you have the Fujitsu touchscreen (such as one - installed in Lifebook P series laptop) connected to your - system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called fujitsu-ts. - -config TOUCHSCREEN_GOODIX - tristate "Goodix I2C touchscreen" - depends on I2C - depends on GPIOLIB || COMPILE_TEST - help - Say Y here if you have the Goodix touchscreen (such as one - installed in Onda v975w tablets) connected to your - system. It also supports 5-finger chip models, which can be - found on ARM tablets, like Wexler TAB7200 and MSI Primo73. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called goodix. - -config TOUCHSCREEN_ILI210X - tristate "Ilitek ILI210X based touchscreen" - depends on I2C - help - Say Y here if you have a ILI210X based touchscreen - controller. This driver supports models ILI2102, - ILI2102s, ILI2103, ILI2103s and ILI2105. - Such kind of chipsets can be found in Amazon Kindle Fire - touchscreens. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called ili210x. - -config TOUCHSCREEN_IPROC - tristate "IPROC touch panel driver support" - depends on ARCH_BCM_IPROC || COMPILE_TEST - help - Say Y here if you want to add support for the IPROC touch - controller to your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called bcm_iproc_tsc. - -config TOUCHSCREEN_S3C2410 - tristate "Samsung S3C2410/generic touchscreen input driver" - depends on ARCH_S3C24XX || SAMSUNG_DEV_TS - depends on S3C_ADC - help - Say Y here if you have the s3c2410 touchscreen. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called s3c2410_ts. - -config TOUCHSCREEN_GUNZE - tristate "Gunze AHL-51S touchscreen" - select SERIO - help - Say Y here if you have the Gunze AHL-51 touchscreen connected to - your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called gunze. - -config TOUCHSCREEN_EKTF2127 - tristate "Elan eKTF2127 I2C touchscreen" - depends on I2C - help - Say Y here if you have an Elan eKTF2127 touchscreen - connected to your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called ektf2127. - -config TOUCHSCREEN_ELAN - tristate "Elan eKTH I2C touchscreen" - depends on I2C - help - Say Y here if you have an Elan eKTH I2C touchscreen - connected to your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called elants_i2c. - -config TOUCHSCREEN_ELO - tristate "Elo serial touchscreens" - select SERIO - help - Say Y here if you have an Elo serial touchscreen connected to - your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called elo. - -config TOUCHSCREEN_WACOM_W8001 - tristate "Wacom W8001 penabled serial touchscreen" - select SERIO - help - Say Y here if you have an Wacom W8001 penabled serial touchscreen - connected to your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called wacom_w8001. - -config TOUCHSCREEN_WACOM_I2C - tristate "Wacom Tablet support (I2C)" - depends on I2C - help - Say Y here if you want to use the I2C version of the Wacom - Pen Tablet. - - If unsure, say N. - - To compile this driver as a module, choose M here: the module - will be called wacom_i2c. - -config TOUCHSCREEN_LPC32XX - tristate "LPC32XX touchscreen controller" - depends on ARCH_LPC32XX - help - Say Y here if you have a LPC32XX device and want - to support the built-in touchscreen. - - To compile this driver as a module, choose M here: the - module will be called lpc32xx_ts. - -config TOUCHSCREEN_MAX11801 - tristate "MAX11801 based touchscreens" - depends on I2C - help - Say Y here if you have a MAX11801 based touchscreen - controller. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called max11801_ts. - -config TOUCHSCREEN_MCS5000 - tristate "MELFAS MCS-5000 touchscreen" - depends on I2C - help - Say Y here if you have the MELFAS MCS-5000 touchscreen controller - chip in your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called mcs5000_ts. - -config TOUCHSCREEN_MMS114 - tristate "MELFAS MMS114 touchscreen" - depends on I2C - help - Say Y here if you have the MELFAS MMS114 touchscreen controller - chip in your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called mms114. - -config TOUCHSCREEN_MELFAS_MIP4 - tristate "MELFAS MIP4 Touchscreen" - depends on I2C - help - Say Y here if you have a MELFAS MIP4 Touchscreen device. - - If unsure, say N. - - To compile this driver as a module, choose M here: - the module will be called melfas_mip4. - -config TOUCHSCREEN_MTOUCH - tristate "MicroTouch serial touchscreens" - select SERIO - help - Say Y here if you have a MicroTouch (3M) serial touchscreen connected to - your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called mtouch. - -config TOUCHSCREEN_IMX6UL_TSC - tristate "Freescale i.MX6UL touchscreen controller" - depends on (OF && GPIOLIB) || COMPILE_TEST - help - Say Y here if you have a Freescale i.MX6UL, and want to - use the internal touchscreen controller. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called imx6ul_tsc. - -config TOUCHSCREEN_INEXIO - tristate "iNexio serial touchscreens" - select SERIO - help - Say Y here if you have an iNexio serial touchscreen connected to - your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called inexio. - -config TOUCHSCREEN_INTEL_MID - tristate "Intel MID platform resistive touchscreen" - depends on INTEL_SCU_IPC - help - Say Y here if you have a Intel MID based touchscreen in - your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called intel_mid_touch. - -config TOUCHSCREEN_MK712 - tristate "ICS MicroClock MK712 touchscreen" - help - Say Y here if you have the ICS MicroClock MK712 touchscreen - controller chip in your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called mk712. - -config TOUCHSCREEN_HP600 - tristate "HP Jornada 6xx touchscreen" - depends on SH_HP6XX && SH_ADC - help - Say Y here if you have a HP Jornada 620/660/680/690 and want to - support the built-in touchscreen. - - To compile this driver as a module, choose M here: the - module will be called hp680_ts_input. - -config TOUCHSCREEN_HP7XX - tristate "HP Jornada 7xx touchscreen" - depends on SA1100_JORNADA720_SSP - help - Say Y here if you have a HP Jornada 710/720/728 and want - to support the built-in touchscreen. - - To compile this driver as a module, choose M here: the - module will be called jornada720_ts. - -config TOUCHSCREEN_IPAQ_MICRO - tristate "HP iPAQ Atmel Micro ASIC touchscreen" - depends on MFD_IPAQ_MICRO - help - Say Y here to enable support for the touchscreen attached to - the Atmel Micro peripheral controller on iPAQ h3100/h3600/h3700 - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called ipaq-micro-ts. - -config TOUCHSCREEN_HTCPEN - tristate "HTC Shift X9500 touchscreen" - depends on ISA - help - Say Y here if you have an HTC Shift UMPC also known as HTC X9500 - Clio / Shangrila and want to support the built-in touchscreen. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called htcpen. - -config TOUCHSCREEN_PENMOUNT - tristate "Penmount serial touchscreen" - select SERIO - help - Say Y here if you have a Penmount serial touchscreen connected to - your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called penmount. - -config TOUCHSCREEN_EDT_FT5X06 - tristate "EDT FocalTech FT5x06 I2C Touchscreen support" - depends on I2C - help - Say Y here if you have an EDT "Polytouch" touchscreen based - on the FocalTech FT5x06 family of controllers connected to - your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called edt-ft5x06. - -config TOUCHSCREEN_MIGOR - tristate "Renesas MIGO-R touchscreen" - depends on (SH_MIGOR || COMPILE_TEST) && I2C - help - Say Y here to enable MIGO-R touchscreen support. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called migor_ts. - -config TOUCHSCREEN_TOUCHRIGHT - tristate "Touchright serial touchscreen" - select SERIO - help - Say Y here if you have a Touchright serial touchscreen connected to - your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called touchright. - -config TOUCHSCREEN_TOUCHWIN - tristate "Touchwin serial touchscreen" - select SERIO - help - Say Y here if you have a Touchwin serial touchscreen connected to - your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called touchwin. - -config TOUCHSCREEN_TI_AM335X_TSC - tristate "TI Touchscreen Interface" - depends on MFD_TI_AM335X_TSCADC - help - Say Y here if you have 4/5/8 wire touchscreen controller - to be connected to the ADC controller on your TI AM335x SoC. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called ti_am335x_tsc. - -config TOUCHSCREEN_UCB1400 - tristate "Philips UCB1400 touchscreen" - depends on AC97_BUS - depends on UCB1400_CORE - help - This enables support for the Philips UCB1400 touchscreen interface. - The UCB1400 is an AC97 audio codec. The touchscreen interface - will be initialized only after the ALSA subsystem has been - brought up and the UCB1400 detected. You therefore have to - configure ALSA support as well (either built-in or modular, - independently of whether this driver is itself built-in or - modular) for this driver to work. - - To compile this driver as a module, choose M here: the - module will be called ucb1400_ts. - -config TOUCHSCREEN_PIXCIR - tristate "PIXCIR I2C touchscreens" - depends on I2C - help - Say Y here if you have a pixcir i2c touchscreen - controller. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called pixcir_i2c_ts. - -config TOUCHSCREEN_WDT87XX_I2C - tristate "Weida HiTech I2C touchscreen" - depends on I2C - help - Say Y here if you have a Weida WDT87XX I2C touchscreen - connected to your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called wdt87xx_i2c. - -config TOUCHSCREEN_WM831X - tristate "Support for WM831x touchscreen controllers" - depends on MFD_WM831X - help - This enables support for the touchscreen controller on the WM831x - series of PMICs. - - To compile this driver as a module, choose M here: the - module will be called wm831x-ts. - -config TOUCHSCREEN_WM97XX - tristate "Support for WM97xx AC97 touchscreen controllers" - depends on AC97_BUS - help - Say Y here if you have a Wolfson Microelectronics WM97xx - touchscreen connected to your system. Note that this option - only enables core driver, you will also need to select - support for appropriate chip below. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called wm97xx-ts. - -config TOUCHSCREEN_WM9705 - bool "WM9705 Touchscreen interface support" - depends on TOUCHSCREEN_WM97XX - default y - help - Say Y here to enable support for the Wolfson Microelectronics - WM9705 touchscreen controller. - -config TOUCHSCREEN_WM9712 - bool "WM9712 Touchscreen interface support" - depends on TOUCHSCREEN_WM97XX - default y - help - Say Y here to enable support for the Wolfson Microelectronics - WM9712 touchscreen controller. - -config TOUCHSCREEN_WM9713 - bool "WM9713 Touchscreen interface support" - depends on TOUCHSCREEN_WM97XX - default y - help - Say Y here to enable support for the Wolfson Microelectronics - WM9713 touchscreen controller. - -config TOUCHSCREEN_WM97XX_ATMEL - tristate "WM97xx Atmel accelerated touch" - depends on TOUCHSCREEN_WM97XX && AVR32 - help - Say Y here for support for streaming mode with WM97xx touchscreens - on Atmel AT91 or AVR32 systems with an AC97C module. - - Be aware that this will use channel B in the controller for - streaming data, this must not conflict with other AC97C drivers. - - If unsure, say N. - - To compile this driver as a module, choose M here: the module will - be called atmel-wm97xx. - -config TOUCHSCREEN_WM97XX_MAINSTONE - tristate "WM97xx Mainstone/Palm accelerated touch" - depends on TOUCHSCREEN_WM97XX && ARCH_PXA - help - Say Y here for support for streaming mode with WM97xx touchscreens - on Mainstone, Palm Tungsten T5, TX and LifeDrive systems. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called mainstone-wm97xx. - -config TOUCHSCREEN_WM97XX_ZYLONITE - tristate "Zylonite accelerated touch" - depends on TOUCHSCREEN_WM97XX && MACH_ZYLONITE - select TOUCHSCREEN_WM9713 - help - Say Y here for support for streaming mode with the touchscreen - on Zylonite systems. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called zylonite-wm97xx. - -config TOUCHSCREEN_USB_COMPOSITE - tristate "USB Touchscreen Driver" - depends on USB_ARCH_HAS_HCD - select USB - help - USB Touchscreen driver for: - - eGalax Touchkit USB (also includes eTurboTouch CT-410/510/700) - - PanJit TouchSet USB - - 3M MicroTouch USB (EX II series) - - ITM - - some other eTurboTouch - - Gunze AHL61 - - DMC TSC-10/25 - - IRTOUCHSYSTEMS/UNITOP - - IdealTEK URTC1000 - - GoTop Super_Q2/GogoPen/PenPower tablets - - JASTEC USB Touch Controller/DigiTech DTR-02U - - Zytronic controllers - - Elo TouchSystems 2700 IntelliTouch - - EasyTouch USB Touch Controller from Data Modul - - e2i (Mimo monitors) - - Have a look at for - a usage description and the required user-space stuff. - - To compile this driver as a module, choose M here: the - module will be called usbtouchscreen. - -config TOUCHSCREEN_MX25 - tristate "Freescale i.MX25 touchscreen input driver" - depends on MFD_MX25_TSADC - help - Enable support for touchscreen connected to your i.MX25. - - To compile this driver as a module, choose M here: the - module will be called fsl-imx25-tcq. - -config TOUCHSCREEN_MC13783 - tristate "Freescale MC13783 touchscreen input driver" - depends on MFD_MC13XXX - help - Say Y here if you have an Freescale MC13783 PMIC on your - board and want to use its touchscreen - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called mc13783_ts. - -config TOUCHSCREEN_USB_EGALAX - default y - bool "eGalax, eTurboTouch CT-410/510/700 device support" if EXPERT - depends on TOUCHSCREEN_USB_COMPOSITE - -config TOUCHSCREEN_USB_PANJIT - default y - bool "PanJit device support" if EXPERT - depends on TOUCHSCREEN_USB_COMPOSITE - -config TOUCHSCREEN_USB_3M - default y - bool "3M/Microtouch EX II series device support" if EXPERT - depends on TOUCHSCREEN_USB_COMPOSITE - -config TOUCHSCREEN_USB_ITM - default y - bool "ITM device support" if EXPERT - depends on TOUCHSCREEN_USB_COMPOSITE - -config TOUCHSCREEN_USB_ETURBO - default y - bool "eTurboTouch (non-eGalax compatible) device support" if EXPERT - depends on TOUCHSCREEN_USB_COMPOSITE - -config TOUCHSCREEN_USB_GUNZE - default y - bool "Gunze AHL61 device support" if EXPERT - depends on TOUCHSCREEN_USB_COMPOSITE - -config TOUCHSCREEN_USB_DMC_TSC10 - default y - bool "DMC TSC-10/25 device support" if EXPERT - depends on TOUCHSCREEN_USB_COMPOSITE - -config TOUCHSCREEN_USB_IRTOUCH - default y - bool "IRTOUCHSYSTEMS/UNITOP device support" if EXPERT - depends on TOUCHSCREEN_USB_COMPOSITE - -config TOUCHSCREEN_USB_IDEALTEK - default y - bool "IdealTEK URTC1000 device support" if EXPERT - depends on TOUCHSCREEN_USB_COMPOSITE - -config TOUCHSCREEN_USB_GENERAL_TOUCH - default y - bool "GeneralTouch Touchscreen device support" if EXPERT - depends on TOUCHSCREEN_USB_COMPOSITE - -config TOUCHSCREEN_USB_GOTOP - default y - bool "GoTop Super_Q2/GogoPen/PenPower tablet device support" if EXPERT - depends on TOUCHSCREEN_USB_COMPOSITE - -config TOUCHSCREEN_USB_JASTEC - default y - bool "JASTEC/DigiTech DTR-02U USB touch controller device support" if EXPERT - depends on TOUCHSCREEN_USB_COMPOSITE - -config TOUCHSCREEN_USB_ELO - default y - bool "Elo TouchSystems 2700 IntelliTouch controller device support" if EXPERT - depends on TOUCHSCREEN_USB_COMPOSITE - -config TOUCHSCREEN_USB_E2I - default y - bool "e2i Touchscreen controller (e.g. from Mimo 740)" if EXPERT - depends on TOUCHSCREEN_USB_COMPOSITE - -config TOUCHSCREEN_USB_ZYTRONIC - default y - bool "Zytronic controller" if EXPERT - depends on TOUCHSCREEN_USB_COMPOSITE - -config TOUCHSCREEN_USB_ETT_TC45USB - default y - bool "ET&T USB series TC4UM/TC5UH touchscreen controller support" if EXPERT - depends on TOUCHSCREEN_USB_COMPOSITE - -config TOUCHSCREEN_USB_NEXIO - default y - bool "NEXIO/iNexio device support" if EXPERT - depends on TOUCHSCREEN_USB_COMPOSITE - -config TOUCHSCREEN_USB_EASYTOUCH - default y - bool "EasyTouch USB Touch controller device support" if EMBEDDED - depends on TOUCHSCREEN_USB_COMPOSITE - help - Say Y here if you have an EasyTouch USB Touch controller. - If unsure, say N. - -config TOUCHSCREEN_TOUCHIT213 - tristate "Sahara TouchIT-213 touchscreen" - select SERIO - help - Say Y here if you have a Sahara TouchIT-213 Tablet PC. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called touchit213. - -config TOUCHSCREEN_TS4800 - tristate "TS-4800 touchscreen" - depends on HAS_IOMEM && OF - depends on SOC_IMX51 || COMPILE_TEST - select MFD_SYSCON - select INPUT_POLLDEV - help - Say Y here if you have a touchscreen on a TS-4800 board. - - On TS-4800, the touchscreen is not handled directly by Linux but by - a companion FPGA. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called ts4800_ts. - -config TOUCHSCREEN_TSC_SERIO - tristate "TSC-10/25/40 serial touchscreen support" - select SERIO - help - Say Y here if you have a TSC-10, 25 or 40 serial touchscreen connected - to your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called tsc40. - -config TOUCHSCREEN_TSC200X_CORE - tristate - -config TOUCHSCREEN_TSC2004 - tristate "TSC2004 based touchscreens" - depends on I2C - select REGMAP_I2C - select TOUCHSCREEN_TSC200X_CORE - help - Say Y here if you have a TSC2004 based touchscreen. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called tsc2004. - -config TOUCHSCREEN_TSC2005 - tristate "TSC2005 based touchscreens" - depends on SPI_MASTER - select REGMAP_SPI - select TOUCHSCREEN_TSC200X_CORE - help - Say Y here if you have a TSC2005 based touchscreen. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called tsc2005. - -config TOUCHSCREEN_TSC2007 - tristate "TSC2007 based touchscreens" - depends on I2C - help - Say Y here if you have a TSC2007 based touchscreen. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called tsc2007. - -config TOUCHSCREEN_W90X900 - tristate "W90P910 touchscreen driver" - depends on ARCH_W90X900 - help - Say Y here if you have a W90P910 based touchscreen. - - To compile this driver as a module, choose M here: the - module will be called w90p910_ts. - -config TOUCHSCREEN_PCAP - tristate "Motorola PCAP touchscreen" - depends on EZX_PCAP - help - Say Y here if you have a Motorola EZX telephone and - want to enable support for the built-in touchscreen. - - To compile this driver as a module, choose M here: the - module will be called pcap_ts. - -config TOUCHSCREEN_RM_TS - tristate "Raydium I2C Touchscreen" - depends on I2C - depends on GPIOLIB || COMPILE_TEST - help - Say Y here if you have Raydium series I2C touchscreen, - such as RM32380, connected to your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called raydium_i2c_ts. - -config TOUCHSCREEN_SILEAD - tristate "Silead I2C touchscreen" - depends on I2C - help - Say Y here if you have the Silead touchscreen connected to - your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called silead. - -config TOUCHSCREEN_SIS_I2C - tristate "SiS 9200 family I2C touchscreen" - depends on I2C - select CRC_ITU_T - depends on GPIOLIB || COMPILE_TEST - help - This enables support for SiS 9200 family over I2C based touchscreens. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called sis_i2c. - -config TOUCHSCREEN_ST1232 - tristate "Sitronix ST1232 touchscreen controllers" - depends on I2C - help - Say Y here if you want to support Sitronix ST1232 - touchscreen controller. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called st1232_ts. - -config TOUCHSCREEN_STMPE - tristate "STMicroelectronics STMPE touchscreens" - depends on MFD_STMPE - depends on (OF || COMPILE_TEST) - help - Say Y here if you want support for STMicroelectronics - STMPE touchscreen controllers. - - To compile this driver as a module, choose M here: the - module will be called stmpe-ts. - -config TOUCHSCREEN_SUN4I - tristate "Allwinner sun4i resistive touchscreen controller support" - depends on ARCH_SUNXI || COMPILE_TEST - depends on HWMON - depends on THERMAL || !THERMAL_OF - help - This selects support for the resistive touchscreen controller - found on Allwinner sunxi SoCs. - - To compile this driver as a module, choose M here: the - module will be called sun4i-ts. - -config TOUCHSCREEN_SUR40 - tristate "Samsung SUR40 (Surface 2.0/PixelSense) touchscreen" - depends on USB && MEDIA_USB_SUPPORT && HAS_DMA - depends on VIDEO_V4L2 - select INPUT_POLLDEV - select VIDEOBUF2_DMA_SG - help - Say Y here if you want support for the Samsung SUR40 touchscreen - (also known as Microsoft Surface 2.0 or Microsoft PixelSense). - - To compile this driver as a module, choose M here: the - module will be called sur40. - -config TOUCHSCREEN_SURFACE3_SPI - tristate "Ntrig/Microsoft Surface 3 SPI touchscreen" - depends on SPI - depends on GPIOLIB || COMPILE_TEST - help - Say Y here if you have the Ntrig/Microsoft SPI touchscreen - controller chip as found on the Surface 3 in your system. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called surface3_spi. - -config TOUCHSCREEN_SX8654 - tristate "Semtech SX8654 touchscreen" - depends on I2C - help - Say Y here if you have a Semtech SX8654 touchscreen controller. - - If unsure, say N - - To compile this driver as a module, choose M here: the - module will be called sx8654. - -config TOUCHSCREEN_TPS6507X - tristate "TPS6507x based touchscreens" - depends on I2C - select INPUT_POLLDEV - help - Say Y here if you have a TPS6507x based touchscreen - controller. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called tps6507x_ts. - -config TOUCHSCREEN_ZFORCE - tristate "Neonode zForce infrared touchscreens" - depends on I2C - depends on GPIOLIB || COMPILE_TEST - help - Say Y here if you have a touchscreen using the zforce - infraread technology from Neonode. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called zforce_ts. - -config TOUCHSCREEN_COLIBRI_VF50 - tristate "Toradex Colibri on board touchscreen driver" - depends on IIO && VF610_ADC - depends on GPIOLIB || COMPILE_TEST - help - Say Y here if you have a Colibri VF50 and plan to use - the on-board provided 4-wire touchscreen driver. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called colibri_vf50_ts. - -config TOUCHSCREEN_ROHM_BU21023 - tristate "ROHM BU21023/24 Dual touch support resistive touchscreens" - depends on I2C - help - Say Y here if you have a touchscreen using ROHM BU21023/24. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called bu21023_ts. - -endif diff --git a/src/linux/drivers/iommu/Kconfig b/src/linux/drivers/iommu/Kconfig deleted file mode 100644 index 8ee54d7..0000000 --- a/src/linux/drivers/iommu/Kconfig +++ /dev/null @@ -1,365 +0,0 @@ -# IOMMU_API always gets selected by whoever wants it. -config IOMMU_API - bool - -menuconfig IOMMU_SUPPORT - bool "IOMMU Hardware Support" - depends on MMU - default y - ---help--- - Say Y here if you want to compile device drivers for IO Memory - Management Units into the kernel. These devices usually allow to - remap DMA requests and/or remap interrupts from other devices on the - system. - -if IOMMU_SUPPORT - -menu "Generic IOMMU Pagetable Support" - -# Selected by the actual pagetable implementations -config IOMMU_IO_PGTABLE - bool - -config IOMMU_IO_PGTABLE_LPAE - bool "ARMv7/v8 Long Descriptor Format" - select IOMMU_IO_PGTABLE - depends on HAS_DMA && (ARM || ARM64 || COMPILE_TEST) - help - Enable support for the ARM long descriptor pagetable format. - This allocator supports 4K/2M/1G, 16K/32M and 64K/512M page - sizes at both stage-1 and stage-2, as well as address spaces - up to 48-bits in size. - -config IOMMU_IO_PGTABLE_LPAE_SELFTEST - bool "LPAE selftests" - depends on IOMMU_IO_PGTABLE_LPAE - help - Enable self-tests for LPAE page table allocator. This performs - a series of page-table consistency checks during boot. - - If unsure, say N here. - -config IOMMU_IO_PGTABLE_ARMV7S - bool "ARMv7/v8 Short Descriptor Format" - select IOMMU_IO_PGTABLE - depends on HAS_DMA && (ARM || ARM64 || COMPILE_TEST) - help - Enable support for the ARM Short-descriptor pagetable format. - This supports 32-bit virtual and physical addresses mapped using - 2-level tables with 4KB pages/1MB sections, and contiguous entries - for 64KB pages/16MB supersections if indicated by the IOMMU driver. - -config IOMMU_IO_PGTABLE_ARMV7S_SELFTEST - bool "ARMv7s selftests" - depends on IOMMU_IO_PGTABLE_ARMV7S - help - Enable self-tests for ARMv7s page table allocator. This performs - a series of page-table consistency checks during boot. - - If unsure, say N here. - -endmenu - -config IOMMU_IOVA - tristate - -config OF_IOMMU - def_bool y - depends on OF && IOMMU_API - -# IOMMU-agnostic DMA-mapping layer -config IOMMU_DMA - bool - select IOMMU_API - select IOMMU_IOVA - select NEED_SG_DMA_LENGTH - -config FSL_PAMU - bool "Freescale IOMMU support" - depends on PPC_E500MC || (COMPILE_TEST && PPC) - select IOMMU_API - select GENERIC_ALLOCATOR - help - Freescale PAMU support. PAMU is the IOMMU present on Freescale QorIQ platforms. - PAMU can authorize memory access, remap the memory address, and remap I/O - transaction types. - -# MSM IOMMU support -config MSM_IOMMU - bool "MSM IOMMU Support" - depends on ARM - depends on ARCH_MSM8X60 || ARCH_MSM8960 || COMPILE_TEST - select IOMMU_API - select IOMMU_IO_PGTABLE_ARMV7S - help - Support for the IOMMUs found on certain Qualcomm SOCs. - These IOMMUs allow virtualization of the address space used by most - cores within the multimedia subsystem. - - If unsure, say N here. - -config IOMMU_PGTABLES_L2 - def_bool y - depends on MSM_IOMMU && MMU && SMP && CPU_DCACHE_DISABLE=n - -# AMD IOMMU support -config AMD_IOMMU - bool "AMD IOMMU support" - select SWIOTLB - select PCI_MSI - select PCI_ATS - select PCI_PRI - select PCI_PASID - select IOMMU_API - select IOMMU_IOVA - depends on X86_64 && PCI && ACPI - ---help--- - With this option you can enable support for AMD IOMMU hardware in - your system. An IOMMU is a hardware component which provides - remapping of DMA memory accesses from devices. With an AMD IOMMU you - can isolate the DMA memory of different devices and protect the - system from misbehaving device drivers or hardware. - - You can find out if your system has an AMD IOMMU if you look into - your BIOS for an option to enable it or if you have an IVRS ACPI - table. - -config AMD_IOMMU_V2 - tristate "AMD IOMMU Version 2 driver" - depends on AMD_IOMMU - select MMU_NOTIFIER - ---help--- - This option enables support for the AMD IOMMUv2 features of the IOMMU - hardware. Select this option if you want to use devices that support - the PCI PRI and PASID interface. - -# Intel IOMMU support -config DMAR_TABLE - bool - -config INTEL_IOMMU - bool "Support for Intel IOMMU using DMA Remapping Devices" - depends on PCI_MSI && ACPI && (X86 || IA64_GENERIC) - select IOMMU_API - select IOMMU_IOVA - select DMAR_TABLE - help - DMA remapping (DMAR) devices support enables independent address - translations for Direct Memory Access (DMA) from devices. - These DMA remapping devices are reported via ACPI tables - and include PCI device scope covered by these DMA - remapping devices. - -config INTEL_IOMMU_SVM - bool "Support for Shared Virtual Memory with Intel IOMMU" - depends on INTEL_IOMMU && X86 - select PCI_PASID - select MMU_NOTIFIER - help - Shared Virtual Memory (SVM) provides a facility for devices - to access DMA resources through process address space by - means of a Process Address Space ID (PASID). - -config INTEL_IOMMU_DEFAULT_ON - def_bool y - prompt "Enable Intel DMA Remapping Devices by default" - depends on INTEL_IOMMU - help - Selecting this option will enable a DMAR device at boot time if - one is found. If this option is not selected, DMAR support can - be enabled by passing intel_iommu=on to the kernel. - -config INTEL_IOMMU_BROKEN_GFX_WA - bool "Workaround broken graphics drivers (going away soon)" - depends on INTEL_IOMMU && BROKEN && X86 - ---help--- - Current Graphics drivers tend to use physical address - for DMA and avoid using DMA APIs. Setting this config - option permits the IOMMU driver to set a unity map for - all the OS-visible memory. Hence the driver can continue - to use physical addresses for DMA, at least until this - option is removed in the 2.6.32 kernel. - -config INTEL_IOMMU_FLOPPY_WA - def_bool y - depends on INTEL_IOMMU && X86 - ---help--- - Floppy disk drivers are known to bypass DMA API calls - thereby failing to work when IOMMU is enabled. This - workaround will setup a 1:1 mapping for the first - 16MiB to make floppy (an ISA device) work. - -config IRQ_REMAP - bool "Support for Interrupt Remapping" - depends on X86_64 && X86_IO_APIC && PCI_MSI && ACPI - select DMAR_TABLE - ---help--- - Supports Interrupt remapping for IO-APIC and MSI devices. - To use x2apic mode in the CPU's which support x2APIC enhancements or - to support platforms with CPU's having > 8 bit APIC ID, say Y. - -# OMAP IOMMU support -config OMAP_IOMMU - bool "OMAP IOMMU Support" - depends on ARM && MMU - depends on ARCH_OMAP2PLUS || COMPILE_TEST - select IOMMU_API - ---help--- - The OMAP3 media platform drivers depend on iommu support, - if you need them say Y here. - -config OMAP_IOMMU_DEBUG - bool "Export OMAP IOMMU internals in DebugFS" - depends on OMAP_IOMMU && DEBUG_FS - ---help--- - Select this to see extensive information about - the internal state of OMAP IOMMU in debugfs. - - Say N unless you know you need this. - -config ROCKCHIP_IOMMU - bool "Rockchip IOMMU Support" - depends on ARM - depends on ARCH_ROCKCHIP || COMPILE_TEST - select IOMMU_API - select ARM_DMA_USE_IOMMU - help - Support for IOMMUs found on Rockchip rk32xx SOCs. - These IOMMUs allow virtualization of the address space used by most - cores within the multimedia subsystem. - Say Y here if you are using a Rockchip SoC that includes an IOMMU - device. - -config TEGRA_IOMMU_GART - bool "Tegra GART IOMMU Support" - depends on ARCH_TEGRA_2x_SOC - select IOMMU_API - help - Enables support for remapping discontiguous physical memory - shared with the operating system into contiguous I/O virtual - space through the GART (Graphics Address Relocation Table) - hardware included on Tegra SoCs. - -config TEGRA_IOMMU_SMMU - bool "NVIDIA Tegra SMMU Support" - depends on ARCH_TEGRA - depends on TEGRA_AHB - depends on TEGRA_MC - select IOMMU_API - help - This driver supports the IOMMU hardware (SMMU) found on NVIDIA Tegra - SoCs (Tegra30 up to Tegra210). - -config EXYNOS_IOMMU - bool "Exynos IOMMU Support" - depends on ARCH_EXYNOS && MMU - select IOMMU_API - select ARM_DMA_USE_IOMMU - help - Support for the IOMMU (System MMU) of Samsung Exynos application - processor family. This enables H/W multimedia accelerators to see - non-linear physical memory chunks as linear memory in their - address space. - - If unsure, say N here. - -config EXYNOS_IOMMU_DEBUG - bool "Debugging log for Exynos IOMMU" - depends on EXYNOS_IOMMU - help - Select this to see the detailed log message that shows what - happens in the IOMMU driver. - - Say N unless you need kernel log message for IOMMU debugging. - -config IPMMU_VMSA - bool "Renesas VMSA-compatible IPMMU" - depends on ARM_LPAE - depends on ARCH_RENESAS || COMPILE_TEST - select IOMMU_API - select IOMMU_IO_PGTABLE_LPAE - select ARM_DMA_USE_IOMMU - help - Support for the Renesas VMSA-compatible IPMMU Renesas found in the - R-Mobile APE6 and R-Car H2/M2 SoCs. - - If unsure, say N. - -config SPAPR_TCE_IOMMU - bool "sPAPR TCE IOMMU Support" - depends on PPC_POWERNV || PPC_PSERIES - select IOMMU_API - help - Enables bits of IOMMU API required by VFIO. The iommu_ops - is not implemented as it is not necessary for VFIO. - -# ARM IOMMU support -config ARM_SMMU - bool "ARM Ltd. System MMU (SMMU) Support" - depends on (ARM64 || ARM) && MMU - select IOMMU_API - select IOMMU_IO_PGTABLE_LPAE - select ARM_DMA_USE_IOMMU if ARM - help - Support for implementations of the ARM System MMU architecture - versions 1 and 2. - - Say Y here if your SoC includes an IOMMU device implementing - the ARM SMMU architecture. - -config ARM_SMMU_V3 - bool "ARM Ltd. System MMU Version 3 (SMMUv3) Support" - depends on ARM64 - select IOMMU_API - select IOMMU_IO_PGTABLE_LPAE - select GENERIC_MSI_IRQ_DOMAIN - help - Support for implementations of the ARM System MMU architecture - version 3 providing translation support to a PCIe root complex. - - Say Y here if your system includes an IOMMU device implementing - the ARM SMMUv3 architecture. - -config S390_IOMMU - def_bool y if S390 && PCI - depends on S390 && PCI - select IOMMU_API - help - Support for the IOMMU API for s390 PCI devices. - -config MTK_IOMMU - bool "MTK IOMMU Support" - depends on ARM || ARM64 - depends on ARCH_MEDIATEK || COMPILE_TEST - select ARM_DMA_USE_IOMMU - select IOMMU_API - select IOMMU_DMA - select IOMMU_IO_PGTABLE_ARMV7S - select MEMORY - select MTK_SMI - help - Support for the M4U on certain Mediatek SOCs. M4U is MultiMedia - Memory Management Unit. This option enables remapping of DMA memory - accesses for the multimedia subsystem. - - If unsure, say N here. - -config MTK_IOMMU_V1 - bool "MTK IOMMU Version 1 (M4U gen1) Support" - depends on ARM - depends on ARCH_MEDIATEK || COMPILE_TEST - select ARM_DMA_USE_IOMMU - select IOMMU_API - select MEMORY - select MTK_SMI - select COMMON_CLK_MT2701_MMSYS - select COMMON_CLK_MT2701_IMGSYS - select COMMON_CLK_MT2701_VDECSYS - help - Support for the M4U on certain Mediatek SoCs. M4U generation 1 HW is - Multimedia Memory Managememt Unit. This option enables remapping of - DMA memory accesses for the multimedia subsystem. - - if unsure, say N here. - -endif # IOMMU_SUPPORT diff --git a/src/linux/drivers/ipack/Kconfig b/src/linux/drivers/ipack/Kconfig deleted file mode 100644 index 3949e55..0000000 --- a/src/linux/drivers/ipack/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -# -# IPACK configuration. -# - -menuconfig IPACK_BUS - tristate "IndustryPack bus support" - depends on HAS_IOMEM - ---help--- - This option provides support for the IndustryPack framework. There - are IndustryPack carrier boards, which interface another bus (such as - PCI) to an IndustryPack bus, and IndustryPack modules, that are - hosted on these buses. While IndustryPack modules can provide a - large variety of functionality, they are most often found in - industrial control applications. - - Say N if unsure. - -if IPACK_BUS - -source "drivers/ipack/carriers/Kconfig" - -source "drivers/ipack/devices/Kconfig" - -endif # IPACK diff --git a/src/linux/drivers/ipack/carriers/Kconfig b/src/linux/drivers/ipack/carriers/Kconfig deleted file mode 100644 index 922ff5c..0000000 --- a/src/linux/drivers/ipack/carriers/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -config BOARD_TPCI200 - tristate "Support for the TEWS TPCI-200 IndustryPack carrier board" - depends on IPACK_BUS - depends on PCI - help - This driver adds support for the TEWS TPCI200 IndustryPack carrier board. - default n diff --git a/src/linux/drivers/ipack/devices/Kconfig b/src/linux/drivers/ipack/devices/Kconfig deleted file mode 100644 index 907a8cb..0000000 --- a/src/linux/drivers/ipack/devices/Kconfig +++ /dev/null @@ -1,6 +0,0 @@ -config SERIAL_IPOCTAL - tristate "IndustryPack IP-OCTAL uart support" - depends on IPACK_BUS && TTY - help - This driver supports the IPOCTAL serial port device for the IndustryPack bus. - default n diff --git a/src/linux/drivers/irqchip/Kconfig b/src/linux/drivers/irqchip/Kconfig deleted file mode 100644 index bc0af33..0000000 --- a/src/linux/drivers/irqchip/Kconfig +++ /dev/null @@ -1,281 +0,0 @@ -config IRQCHIP - def_bool y - depends on OF_IRQ - -config ARM_GIC - bool - select IRQ_DOMAIN - select IRQ_DOMAIN_HIERARCHY - select MULTI_IRQ_HANDLER - -config ARM_GIC_PM - bool - depends on PM - select ARM_GIC - select PM_CLK - -config ARM_GIC_MAX_NR - int - default 2 if ARCH_REALVIEW - default 1 - -config ARM_GIC_V2M - bool - depends on PCI - select ARM_GIC - select PCI_MSI - -config GIC_NON_BANKED - bool - -config ARM_GIC_V3 - bool - select IRQ_DOMAIN - select MULTI_IRQ_HANDLER - select IRQ_DOMAIN_HIERARCHY - select PARTITION_PERCPU - -config ARM_GIC_V3_ITS - bool - depends on PCI - depends on PCI_MSI - select ACPI_IORT if ACPI - -config ARM_NVIC - bool - select IRQ_DOMAIN - select IRQ_DOMAIN_HIERARCHY - select GENERIC_IRQ_CHIP - -config ARM_VIC - bool - select IRQ_DOMAIN - select MULTI_IRQ_HANDLER - -config ARM_VIC_NR - int - default 4 if ARCH_S5PV210 - default 2 - depends on ARM_VIC - help - The maximum number of VICs available in the system, for - power management. - -config ARMADA_370_XP_IRQ - bool - select GENERIC_IRQ_CHIP - select PCI_MSI if PCI - -config ALPINE_MSI - bool - depends on PCI - select PCI_MSI - select GENERIC_IRQ_CHIP - -config ATMEL_AIC_IRQ - bool - select GENERIC_IRQ_CHIP - select IRQ_DOMAIN - select MULTI_IRQ_HANDLER - select SPARSE_IRQ - -config ATMEL_AIC5_IRQ - bool - select GENERIC_IRQ_CHIP - select IRQ_DOMAIN - select MULTI_IRQ_HANDLER - select SPARSE_IRQ - -config I8259 - bool - select IRQ_DOMAIN - -config BCM6345_L1_IRQ - bool - select GENERIC_IRQ_CHIP - select IRQ_DOMAIN - -config BCM7038_L1_IRQ - bool - select GENERIC_IRQ_CHIP - select IRQ_DOMAIN - -config BCM7120_L2_IRQ - bool - select GENERIC_IRQ_CHIP - select IRQ_DOMAIN - -config BRCMSTB_L2_IRQ - bool - select GENERIC_IRQ_CHIP - select IRQ_DOMAIN - -config DW_APB_ICTL - bool - select GENERIC_IRQ_CHIP - select IRQ_DOMAIN - -config HISILICON_IRQ_MBIGEN - bool - select ARM_GIC_V3 - select ARM_GIC_V3_ITS - -config IMGPDC_IRQ - bool - select GENERIC_IRQ_CHIP - select IRQ_DOMAIN - -config IRQ_MIPS_CPU - bool - select GENERIC_IRQ_CHIP - select IRQ_DOMAIN - -config CLPS711X_IRQCHIP - bool - depends on ARCH_CLPS711X - select IRQ_DOMAIN - select MULTI_IRQ_HANDLER - select SPARSE_IRQ - default y - -config OR1K_PIC - bool - select IRQ_DOMAIN - -config OMAP_IRQCHIP - bool - select GENERIC_IRQ_CHIP - select IRQ_DOMAIN - -config ORION_IRQCHIP - bool - select IRQ_DOMAIN - select MULTI_IRQ_HANDLER - -config PIC32_EVIC - bool - select GENERIC_IRQ_CHIP - select IRQ_DOMAIN - -config JCORE_AIC - bool "J-Core integrated AIC" if COMPILE_TEST - depends on OF - select IRQ_DOMAIN - help - Support for the J-Core integrated AIC. - -config RENESAS_INTC_IRQPIN - bool - select IRQ_DOMAIN - -config RENESAS_IRQC - bool - select GENERIC_IRQ_CHIP - select IRQ_DOMAIN - -config ST_IRQCHIP - bool - select REGMAP - select MFD_SYSCON - help - Enables SysCfg Controlled IRQs on STi based platforms. - -config TANGO_IRQ - bool - select IRQ_DOMAIN - select GENERIC_IRQ_CHIP - -config TB10X_IRQC - bool - select IRQ_DOMAIN - select GENERIC_IRQ_CHIP - -config TS4800_IRQ - tristate "TS-4800 IRQ controller" - select IRQ_DOMAIN - depends on HAS_IOMEM - depends on SOC_IMX51 || COMPILE_TEST - help - Support for the TS-4800 FPGA IRQ controller - -config VERSATILE_FPGA_IRQ - bool - select IRQ_DOMAIN - -config VERSATILE_FPGA_IRQ_NR - int - default 4 - depends on VERSATILE_FPGA_IRQ - -config XTENSA_MX - bool - select IRQ_DOMAIN - -config IRQ_CROSSBAR - bool - help - Support for a CROSSBAR ip that precedes the main interrupt controller. - The primary irqchip invokes the crossbar's callback which inturn allocates - a free irq and configures the IP. Thus the peripheral interrupts are - routed to one of the free irqchip interrupt lines. - -config KEYSTONE_IRQ - tristate "Keystone 2 IRQ controller IP" - depends on ARCH_KEYSTONE - help - Support for Texas Instruments Keystone 2 IRQ controller IP which - is part of the Keystone 2 IPC mechanism - -config MIPS_GIC - bool - select GENERIC_IRQ_IPI - select IRQ_DOMAIN_HIERARCHY - select MIPS_CM - -config INGENIC_IRQ - bool - depends on MACH_INGENIC - default y - -config RENESAS_H8300H_INTC - bool - select IRQ_DOMAIN - -config RENESAS_H8S_INTC - bool - select IRQ_DOMAIN - -config IMX_GPCV2 - bool - select IRQ_DOMAIN - help - Enables the wakeup IRQs for IMX platforms with GPCv2 block - -config IRQ_MXS - def_bool y if MACH_ASM9260 || ARCH_MXS - select IRQ_DOMAIN - select STMP_DEVICE - -config MVEBU_ODMI - bool - -config MVEBU_PIC - bool - -config LS_SCFG_MSI - def_bool y if SOC_LS1021A || ARCH_LAYERSCAPE - depends on PCI && PCI_MSI - -config PARTITION_PERCPU - bool - -config EZNPS_GIC - bool "NPS400 Global Interrupt Manager (GIM)" - depends on ARC || (COMPILE_TEST && !64BIT) - select IRQ_DOMAIN - help - Support the EZchip NPS400 global interrupt controller - -config STM32_EXTI - bool - select IRQ_DOMAIN diff --git a/src/linux/drivers/irqchip/Makefile b/src/linux/drivers/irqchip/Makefile deleted file mode 100644 index e4dbfc8..0000000 --- a/src/linux/drivers/irqchip/Makefile +++ /dev/null @@ -1,76 +0,0 @@ -obj-$(CONFIG_IRQCHIP) += irqchip.o - -obj-$(CONFIG_ALPINE_MSI) += irq-alpine-msi.o -obj-$(CONFIG_ATH79) += irq-ath79-cpu.o -obj-$(CONFIG_ATH79) += irq-ath79-misc.o -obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2835.o -obj-$(CONFIG_ARCH_BCM2835) += irq-bcm2836.o -obj-$(CONFIG_ARCH_EXYNOS) += exynos-combiner.o -obj-$(CONFIG_ARCH_HIP04) += irq-hip04.o -obj-$(CONFIG_ARCH_LPC32XX) += irq-lpc32xx.o -obj-$(CONFIG_ARCH_MMP) += irq-mmp.o -obj-$(CONFIG_IRQ_MXS) += irq-mxs.o -obj-$(CONFIG_ARCH_TEGRA) += irq-tegra.o -obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o -obj-$(CONFIG_DW_APB_ICTL) += irq-dw-apb-ictl.o -obj-$(CONFIG_METAG) += irq-metag-ext.o -obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o -obj-$(CONFIG_ARCH_MOXART) += irq-moxart.o -obj-$(CONFIG_CLPS711X_IRQCHIP) += irq-clps711x.o -obj-$(CONFIG_OR1K_PIC) += irq-or1k-pic.o -obj-$(CONFIG_ORION_IRQCHIP) += irq-orion.o -obj-$(CONFIG_OMAP_IRQCHIP) += irq-omap-intc.o -obj-$(CONFIG_ARCH_SUNXI) += irq-sun4i.o -obj-$(CONFIG_ARCH_SUNXI) += irq-sunxi-nmi.o -obj-$(CONFIG_ARCH_SPEAR3XX) += spear-shirq.o -obj-$(CONFIG_ARM_GIC) += irq-gic.o irq-gic-common.o -obj-$(CONFIG_ARM_GIC_PM) += irq-gic-pm.o -obj-$(CONFIG_ARCH_REALVIEW) += irq-gic-realview.o -obj-$(CONFIG_ARM_GIC_V2M) += irq-gic-v2m.o -obj-$(CONFIG_ARM_GIC_V3) += irq-gic-v3.o irq-gic-common.o -obj-$(CONFIG_ARM_GIC_V3_ITS) += irq-gic-v3-its.o irq-gic-v3-its-pci-msi.o irq-gic-v3-its-platform-msi.o -obj-$(CONFIG_PARTITION_PERCPU) += irq-partition-percpu.o -obj-$(CONFIG_HISILICON_IRQ_MBIGEN) += irq-mbigen.o -obj-$(CONFIG_ARM_NVIC) += irq-nvic.o -obj-$(CONFIG_ARM_VIC) += irq-vic.o -obj-$(CONFIG_ARMADA_370_XP_IRQ) += irq-armada-370-xp.o -obj-$(CONFIG_ATMEL_AIC_IRQ) += irq-atmel-aic-common.o irq-atmel-aic.o -obj-$(CONFIG_ATMEL_AIC5_IRQ) += irq-atmel-aic-common.o irq-atmel-aic5.o -obj-$(CONFIG_I8259) += irq-i8259.o -obj-$(CONFIG_IMGPDC_IRQ) += irq-imgpdc.o -obj-$(CONFIG_IRQ_MIPS_CPU) += irq-mips-cpu.o -obj-$(CONFIG_SIRF_IRQ) += irq-sirfsoc.o -obj-$(CONFIG_JCORE_AIC) += irq-jcore-aic.o -obj-$(CONFIG_RENESAS_INTC_IRQPIN) += irq-renesas-intc-irqpin.o -obj-$(CONFIG_RENESAS_IRQC) += irq-renesas-irqc.o -obj-$(CONFIG_VERSATILE_FPGA_IRQ) += irq-versatile-fpga.o -obj-$(CONFIG_ARCH_NSPIRE) += irq-zevio.o -obj-$(CONFIG_ARCH_VT8500) += irq-vt8500.o -obj-$(CONFIG_ST_IRQCHIP) += irq-st.o -obj-$(CONFIG_TANGO_IRQ) += irq-tango.o -obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o -obj-$(CONFIG_TS4800_IRQ) += irq-ts4800.o -obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o -obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o -obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o -obj-$(CONFIG_SOC_VF610) += irq-vf610-mscm-ir.o -obj-$(CONFIG_BCM6345_L1_IRQ) += irq-bcm6345-l1.o -obj-$(CONFIG_BCM7038_L1_IRQ) += irq-bcm7038-l1.o -obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o -obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o -obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o -obj-$(CONFIG_MIPS_GIC) += irq-mips-gic.o -obj-$(CONFIG_ARCH_MEDIATEK) += irq-mtk-sysirq.o -obj-$(CONFIG_ARCH_DIGICOLOR) += irq-digicolor.o -obj-$(CONFIG_RENESAS_H8300H_INTC) += irq-renesas-h8300h.o -obj-$(CONFIG_RENESAS_H8S_INTC) += irq-renesas-h8s.o -obj-$(CONFIG_ARCH_SA1100) += irq-sa11x0.o -obj-$(CONFIG_INGENIC_IRQ) += irq-ingenic.o -obj-$(CONFIG_IMX_GPCV2) += irq-imx-gpcv2.o -obj-$(CONFIG_PIC32_EVIC) += irq-pic32-evic.o -obj-$(CONFIG_MVEBU_ODMI) += irq-mvebu-odmi.o -obj-$(CONFIG_MVEBU_PIC) += irq-mvebu-pic.o -obj-$(CONFIG_LS_SCFG_MSI) += irq-ls-scfg-msi.o -obj-$(CONFIG_EZNPS_GIC) += irq-eznps.o -obj-$(CONFIG_ARCH_ASPEED) += irq-aspeed-vic.o -obj-$(CONFIG_STM32_EXTI) += irq-stm32-exti.o diff --git a/src/linux/drivers/isdn/Kconfig b/src/linux/drivers/isdn/Kconfig deleted file mode 100644 index ef661ac..0000000 --- a/src/linux/drivers/isdn/Kconfig +++ /dev/null @@ -1,78 +0,0 @@ -# -# ISDN device configuration -# - -menuconfig ISDN - bool "ISDN support" - depends on NET && NETDEVICES - depends on !S390 && !UML - ---help--- - ISDN ("Integrated Services Digital Network", called RNIS in France) - is a fully digital telephone service that can be used for voice and - data connections. If your computer is equipped with an ISDN - adapter you can use it to connect to your Internet service provider - (with SLIP or PPP) faster than via a conventional telephone modem - (though still much slower than with DSL) or to make and accept - voice calls (eg. turning your PC into a software answering machine - or PABX). - - Select this option if you want your kernel to support ISDN. - -if ISDN - -menuconfig ISDN_I4L - tristate "Old ISDN4Linux (deprecated)" - depends on TTY - ---help--- - This driver allows you to use an ISDN adapter for networking - connections and as dialin/out device. The isdn-tty's have a built - in AT-compatible modem emulator. Network devices support autodial, - channel-bundling, callback and caller-authentication without having - a daemon running. A reduced T.70 protocol is supported with tty's - suitable for German BTX. On D-Channel, the protocols EDSS1 - (Euro-ISDN) and 1TR6 (German style) are supported. See - for more information. - - ISDN support in the linux kernel is moving towards a new API, - called CAPI (Common ISDN Application Programming Interface). - Therefore the old ISDN4Linux layer will eventually become obsolete. - It is still available, though, for use with adapters that are not - supported by the new CAPI subsystem yet. - -source "drivers/isdn/i4l/Kconfig" - -menuconfig ISDN_CAPI - tristate "CAPI 2.0 subsystem" - help - This provides CAPI (the Common ISDN Application Programming - Interface) Version 2.0, a standard making it easy for programs to - access ISDN hardware in a device independent way. (For details see - .) CAPI supports making and accepting voice - and data connections, controlling call options and protocols, - as well as ISDN supplementary services like call forwarding or - three-party conferences (if supported by the specific hardware - driver). - - Select this option and the appropriate hardware driver below if - you have an ISDN adapter supported by the CAPI subsystem. - -if ISDN_CAPI - -source "drivers/isdn/capi/Kconfig" - -source "drivers/isdn/hardware/Kconfig" - -endif # ISDN_CAPI - -source "drivers/isdn/gigaset/Kconfig" - -source "drivers/isdn/hysdn/Kconfig" - -source "drivers/isdn/mISDN/Kconfig" - -config ISDN_HDLC - tristate - select CRC_CCITT - select BITREVERSE - -endif # ISDN diff --git a/src/linux/drivers/isdn/capi/Kconfig b/src/linux/drivers/isdn/capi/Kconfig deleted file mode 100644 index 7641b30..0000000 --- a/src/linux/drivers/isdn/capi/Kconfig +++ /dev/null @@ -1,44 +0,0 @@ -config CAPI_TRACE - bool "CAPI trace support" - default y - help - If you say Y here, the kernelcapi driver can make verbose traces - of CAPI messages. This feature can be enabled/disabled via IOCTL for - every controller (default disabled). - This will increase the size of the kernelcapi module by 20 KB. - If unsure, say Y. - -config ISDN_CAPI_CAPI20 - tristate "CAPI2.0 /dev/capi20 support" - help - This option will provide the CAPI 2.0 interface to userspace - applications via /dev/capi20. Applications should use the - standardized libcapi20 to access this functionality. You should say - Y/M here. - -config ISDN_CAPI_MIDDLEWARE - bool "CAPI2.0 Middleware support" - depends on ISDN_CAPI_CAPI20 && TTY - help - This option will enhance the capabilities of the /dev/capi20 - interface. It will provide a means of moving a data connection, - established via the usual /dev/capi20 interface to a special tty - device. If you want to use pppd with pppdcapiplugin to dial up to - your ISP, say Y here. - -config ISDN_CAPI_CAPIDRV - tristate "CAPI2.0 capidrv interface support" - depends on ISDN_I4L - help - This option provides the glue code to hook up CAPI driven cards to - the legacy isdn4linux link layer. If you have a card which is - supported by a CAPI driver, but still want to use old features like - ippp interfaces or ttyI emulation, say Y/M here. - -config ISDN_CAPI_CAPIDRV_VERBOSE - bool "Verbose reason code reporting" - depends on ISDN_CAPI_CAPIDRV - help - If you say Y here, the capidrv interface will give verbose reasons - for disconnecting. This will increase the size of the kernel by 7 KB. - If unsure, say N. diff --git a/src/linux/drivers/isdn/gigaset/Kconfig b/src/linux/drivers/isdn/gigaset/Kconfig deleted file mode 100644 index 83f62b8..0000000 --- a/src/linux/drivers/isdn/gigaset/Kconfig +++ /dev/null @@ -1,70 +0,0 @@ -menuconfig ISDN_DRV_GIGASET - tristate "Siemens Gigaset support" - depends on TTY - select CRC_CCITT - select BITREVERSE - help - This driver supports the Siemens Gigaset SX205/255 family of - ISDN DECT bases, including the predecessors Gigaset 3070/3075 - and 4170/4175 and their T-Com versions Sinus 45isdn and Sinus - 721X. - If you have one of these devices, say M here and for at least - one of the connection specific parts that follow. - This will build a module called "gigaset". - Note: If you build your ISDN subsystem (ISDN_CAPI or ISDN_I4L) - as a module, you have to build this driver as a module too, - otherwise the Gigaset device won't show up as an ISDN device. - -if ISDN_DRV_GIGASET - -config GIGASET_CAPI - bool "Gigaset CAPI support" - depends on ISDN_CAPI='y'||(ISDN_CAPI='m'&&ISDN_DRV_GIGASET='m') - default 'y' - help - Build the Gigaset driver as a CAPI 2.0 driver interfacing with - the Kernel CAPI subsystem. To use it with the old ISDN4Linux - subsystem you'll have to enable the capidrv glue driver. - (select ISDN_CAPI_CAPIDRV.) - Say N to build the old native ISDN4Linux variant. - If unsure, say Y. - -config GIGASET_I4L - bool - depends on ISDN_I4L='y'||(ISDN_I4L='m'&&ISDN_DRV_GIGASET='m') - default !GIGASET_CAPI - -config GIGASET_DUMMYLL - bool - default !GIGASET_CAPI&&!GIGASET_I4L - -config GIGASET_BASE - tristate "Gigaset base station support" - depends on USB - help - Say M here if you want to use the USB interface of the Gigaset - base for connection to your system. - This will build a module called "bas_gigaset". - -config GIGASET_M105 - tristate "Gigaset M105 support" - depends on USB - help - Say M here if you want to connect to the Gigaset base via DECT - using a Gigaset M105 (Sinus 45 Data 2) USB DECT device. - This will build a module called "usb_gigaset". - -config GIGASET_M101 - tristate "Gigaset M101 support" - help - Say M here if you want to connect to the Gigaset base via DECT - using a Gigaset M101 (Sinus 45 Data 1) RS232 DECT device. - This will build a module called "ser_gigaset". - -config GIGASET_DEBUG - bool "Gigaset debugging" - help - This enables debugging code in the Gigaset drivers. - If in doubt, say yes. - -endif # ISDN_DRV_GIGASET diff --git a/src/linux/drivers/isdn/hardware/Kconfig b/src/linux/drivers/isdn/hardware/Kconfig deleted file mode 100644 index 30d028d..0000000 --- a/src/linux/drivers/isdn/hardware/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -# -# ISDN hardware drivers -# -comment "CAPI hardware drivers" - -source "drivers/isdn/hardware/avm/Kconfig" - -source "drivers/isdn/hardware/eicon/Kconfig" - diff --git a/src/linux/drivers/isdn/hardware/avm/Kconfig b/src/linux/drivers/isdn/hardware/avm/Kconfig deleted file mode 100644 index b99b906..0000000 --- a/src/linux/drivers/isdn/hardware/avm/Kconfig +++ /dev/null @@ -1,64 +0,0 @@ -# -# ISDN AVM drivers -# - -menuconfig CAPI_AVM - bool "Active AVM cards" - help - Enable support for AVM active ISDN cards. - -if CAPI_AVM - -config ISDN_DRV_AVMB1_B1ISA - tristate "AVM B1 ISA support" - depends on ISA - help - Enable support for the ISA version of the AVM B1 card. - -config ISDN_DRV_AVMB1_B1PCI - tristate "AVM B1 PCI support" - depends on PCI - help - Enable support for the PCI version of the AVM B1 card. - -config ISDN_DRV_AVMB1_B1PCIV4 - bool "AVM B1 PCI V4 support" - depends on ISDN_DRV_AVMB1_B1PCI - help - Enable support for the V4 version of AVM B1 PCI card. - -config ISDN_DRV_AVMB1_T1ISA - tristate "AVM T1/T1-B ISA support" - depends on ISA - help - Enable support for the AVM T1 T1B card. - Note: This is a PRI card and handle 30 B-channels. - -config ISDN_DRV_AVMB1_B1PCMCIA - tristate "AVM B1/M1/M2 PCMCIA support" - depends on PCMCIA - help - Enable support for the PCMCIA version of the AVM B1 card. - -config ISDN_DRV_AVMB1_AVM_CS - tristate "AVM B1/M1/M2 PCMCIA cs module" - depends on ISDN_DRV_AVMB1_B1PCMCIA - help - Enable the PCMCIA client driver for the AVM B1/M1/M2 - PCMCIA cards. - -config ISDN_DRV_AVMB1_T1PCI - tristate "AVM T1/T1-B PCI support" - depends on PCI - help - Enable support for the AVM T1 T1B card. - Note: This is a PRI card and handle 30 B-channels. - -config ISDN_DRV_AVMB1_C4 - tristate "AVM C4/C2 support" - depends on PCI - help - Enable support for the AVM C4/C2 PCI cards. - These cards handle 4/2 BRI ISDN lines (8/4 channels). - -endif # CAPI_AVM diff --git a/src/linux/drivers/isdn/hardware/eicon/Kconfig b/src/linux/drivers/isdn/hardware/eicon/Kconfig deleted file mode 100644 index 6082b6a..0000000 --- a/src/linux/drivers/isdn/hardware/eicon/Kconfig +++ /dev/null @@ -1,51 +0,0 @@ -# -# ISDN DIVAS Eicon driver -# - -menuconfig CAPI_EICON - bool "Active Eicon DIVA Server cards" - help - Enable support for Eicon Networks active ISDN cards. - -if CAPI_EICON - -config ISDN_DIVAS - tristate "Support Eicon DIVA Server cards" - depends on PROC_FS && PCI - help - Say Y here if you have an Eicon Networks DIVA Server PCI ISDN card. - In order to use this card, additional firmware is necessary, which - has to be downloaded into the card using the divactrl utility. - -if ISDN_DIVAS - -config ISDN_DIVAS_BRIPCI - bool "DIVA Server BRI/PCI support" - help - Enable support for DIVA Server BRI-PCI. - -config ISDN_DIVAS_PRIPCI - bool "DIVA Server PRI/PCI support" - help - Enable support for DIVA Server PRI-PCI. - -config ISDN_DIVAS_DIVACAPI - tristate "DIVA CAPI2.0 interface support" - help - You need this to provide the CAPI interface - for DIVA Server cards. - -config ISDN_DIVAS_USERIDI - tristate "DIVA User-IDI interface support" - help - Enable support for user-mode IDI interface. - -config ISDN_DIVAS_MAINT - tristate "DIVA Maint driver support" - depends on m - help - Enable Divas Maintenance driver. - -endif # ISDN_DIVAS - -endif # CAPI_EICON diff --git a/src/linux/drivers/isdn/hardware/mISDN/Kconfig b/src/linux/drivers/isdn/hardware/mISDN/Kconfig deleted file mode 100644 index 09df54f..0000000 --- a/src/linux/drivers/isdn/hardware/mISDN/Kconfig +++ /dev/null @@ -1,94 +0,0 @@ -# -# Hardware for mISDN -# -comment "mISDN hardware drivers" - -config MISDN_HFCPCI - tristate "Support for HFC PCI cards" - depends on MISDN - depends on PCI - help - Enable support for cards with Cologne Chip AG's - HFC PCI chip. - -config MISDN_HFCMULTI - tristate "Support for HFC multiport cards (HFC-4S/8S/E1)" - depends on PCI || 8xx - depends on MISDN - help - Enable support for cards with Cologne Chip AG's HFC multiport - chip. There are three types of chips that are quite similar, - but the interface is different: - * HFC-4S (4 S/T interfaces on one chip) - * HFC-8S (8 S/T interfaces on one chip) - * HFC-E1 (E1 interface for 2Mbit ISDN) - -config MISDN_HFCMULTI_8xx - bool "Support for XHFC embedded board in HFC multiport driver" - depends on MISDN - depends on MISDN_HFCMULTI - depends on 8xx - default 8xx - help - Enable support for the XHFC embedded solution from Speech Design. - -config MISDN_HFCUSB - tristate "Support for HFC-S USB based TAs" - depends on USB - help - Enable support for USB ISDN TAs with Cologne Chip AG's - HFC-S USB ISDN Controller - -config MISDN_AVMFRITZ - tristate "Support for AVM FRITZ!CARD PCI" - depends on MISDN - depends on PCI - select MISDN_IPAC - help - Enable support for AVMs FRITZ!CARD PCI cards - -config MISDN_SPEEDFAX - tristate "Support for Sedlbauer Speedfax+" - depends on MISDN - depends on PCI - select MISDN_IPAC - select MISDN_ISAR - help - Enable support for Sedlbauer Speedfax+. - -config MISDN_INFINEON - tristate "Support for cards with Infineon chipset" - depends on MISDN - depends on PCI - select MISDN_IPAC - help - Enable support for cards with ISAC + HSCX, IPAC or IPAC-SX - chip from Infineon (former manufacturer Siemens). - -config MISDN_W6692 - tristate "Support for cards with Winbond 6692" - depends on MISDN - depends on PCI - help - Enable support for Winbond 6692 PCI chip based cards. - -config MISDN_NETJET - tristate "Support for NETJet cards" - depends on MISDN - depends on PCI - depends on TTY - select MISDN_IPAC - select ISDN_HDLC - select ISDN_I4L - help - Enable support for Traverse Technologies NETJet PCI cards. - - -config MISDN_IPAC - tristate - depends on MISDN - -config MISDN_ISAR - tristate - depends on MISDN - diff --git a/src/linux/drivers/isdn/hisax/Kconfig b/src/linux/drivers/isdn/hisax/Kconfig deleted file mode 100644 index eb83d94..0000000 --- a/src/linux/drivers/isdn/hisax/Kconfig +++ /dev/null @@ -1,422 +0,0 @@ - -menu "Passive cards" - -config ISDN_DRV_HISAX - tristate "HiSax SiemensChipSet driver support" - select CRC_CCITT - ---help--- - This is a driver supporting the Siemens chipset on various - ISDN-cards (like AVM A1, Elsa ISDN cards, Teles S0-16.0, Teles - S0-16.3, Teles S0-8, Teles/Creatix PnP, ITK micro ix1 and many - compatibles). - - HiSax is just the name of this driver, not the name of any hardware. - - If you have a card with such a chipset, you should say Y here and - also to the configuration option of the driver for your particular - card, below. - -if ISDN_DRV_HISAX - -comment "D-channel protocol features" - -config HISAX_EURO - bool "HiSax Support for EURO/DSS1" - help - Say Y or N according to the D-channel protocol which your local - telephone service company provides. - - The call control protocol E-DSS1 is used in most European countries. - If unsure, say Y. - -config DE_AOC - bool "Support for german chargeinfo" - depends on HISAX_EURO - help - If you want that the HiSax hardware driver sends messages to the - upper level of the isdn code on each AOCD (Advice Of Charge, During - the call -- transmission of the fee information during a call) and - on each AOCE (Advice Of Charge, at the End of the call -- - transmission of fee information at the end of the call), say Y here. - This works only in Germany. - -config HISAX_NO_SENDCOMPLETE - bool "Disable sending complete" - depends on HISAX_EURO - help - If you have trouble with some ugly exchanges or you live in - Australia select this option. - -config HISAX_NO_LLC - bool "Disable sending low layer compatibility" - depends on HISAX_EURO - help - If you have trouble with some ugly exchanges try to select this - option. - -config HISAX_NO_KEYPAD - bool "Disable keypad protocol option" - depends on HISAX_EURO - help - If you like to send special dial strings including * or # without - using the keypad protocol, select this option. - -config HISAX_1TR6 - bool "HiSax Support for german 1TR6" - help - Say Y or N according to the D-channel protocol which your local - telephone service company provides. - - 1TR6 is an old call control protocol which was used in Germany - before E-DSS1 was established. Nowadays, all new lines in Germany - use E-DSS1. - -config HISAX_NI1 - bool "HiSax Support for US NI1" - help - Enable this if you like to use ISDN in US on a NI1 basic rate - interface. - -config HISAX_MAX_CARDS - int "Maximum number of cards supported by HiSax" - default "8" - help - This option allows you to specify the maximum number of cards which - the HiSax driver will be able to handle. - -comment "HiSax supported cards" - -config HISAX_16_0 - bool "Teles 16.0/8.0" - depends on ISA - help - This enables HiSax support for the Teles ISDN-cards S0-16.0, S0-8 - and many compatibles. - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port/shmem settings. - -config HISAX_16_3 - bool "Teles 16.3 or PNP or PCMCIA" - help - This enables HiSax support for the Teles ISDN-cards S0-16.3 the - Teles/Creatix PnP and the Teles PCMCIA. - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_TELESPCI - bool "Teles PCI" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV || (XTENSA && !CPU_LITTLE_ENDIAN))) - help - This enables HiSax support for the Teles PCI. - See on how to configure it. - -config HISAX_S0BOX - bool "Teles S0Box" - help - This enables HiSax support for the Teles/Creatix parallel port - S0BOX. See on how to - configure it. - -config HISAX_AVM_A1 - bool "AVM A1 (Fritz)" - depends on ISA - help - This enables HiSax support for the AVM A1 (aka "Fritz"). - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_FRITZPCI - bool "AVM PnP/PCI (Fritz!PnP/PCI)" - depends on BROKEN || !PPC64 - help - This enables HiSax support for the AVM "Fritz!PnP" and "Fritz!PCI". - See on how to configure it. - -config HISAX_AVM_A1_PCMCIA - bool "AVM A1 PCMCIA (Fritz)" - help - This enables HiSax support for the AVM A1 "Fritz!PCMCIA"). - See on how to configure it. - -config HISAX_ELSA - bool "Elsa cards" - help - This enables HiSax support for the Elsa Mircolink ISA cards, for the - Elsa Quickstep series cards and Elsa PCMCIA. - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_IX1MICROR2 - bool "ITK ix1-micro Revision 2" - depends on ISA - help - This enables HiSax support for the ITK ix1-micro Revision 2 card. - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_DIEHLDIVA - bool "Eicon.Diehl Diva cards" - help - This enables HiSax support for the Eicon.Diehl Diva none PRO - versions passive ISDN cards. - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_ASUSCOM - bool "ASUSCOM ISA cards" - depends on ISA - help - This enables HiSax support for the AsusCom and their OEM versions - passive ISDN ISA cards. - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_TELEINT - bool "TELEINT cards" - depends on ISA - help - This enables HiSax support for the TELEINT SA1 semiactiv ISDN card. - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_HFCS - bool "HFC-S based cards" - depends on ISA - help - This enables HiSax support for the HFC-S 2BDS0 based cards, like - teles 16.3c. - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_SEDLBAUER - bool "Sedlbauer cards" - help - This enables HiSax support for the Sedlbauer passive ISDN cards. - - See on how to configure it - using the different cards, a different D-channel protocol, or - non-standard IRQ/port settings. - -config HISAX_SPORTSTER - bool "USR Sportster internal TA" - depends on ISA - help - This enables HiSax support for the USR Sportster internal TA card. - - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_MIC - bool "MIC card" - depends on ISA - help - This enables HiSax support for the ITH MIC card. - - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_NETJET - bool "NETjet card" - depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE)) - depends on VIRT_TO_BUS - help - This enables HiSax support for the NetJet from Traverse - Technologies. - - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_NETJET_U - bool "NETspider U card" - depends on PCI && (BROKEN || !(PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV || (XTENSA && !CPU_LITTLE_ENDIAN) || MICROBLAZE)) - depends on VIRT_TO_BUS - help - This enables HiSax support for the Netspider U interface ISDN card - from Traverse Technologies. - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_NICCY - bool "Niccy PnP/PCI card" - help - This enables HiSax support for the Dr. Neuhaus Niccy PnP or PCI. - - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_ISURF - bool "Siemens I-Surf card" - depends on ISA - help - This enables HiSax support for the Siemens I-Talk/I-Surf card with - ISAR chip. - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_HSTSAPHIR - bool "HST Saphir card" - depends on ISA - help - This enables HiSax support for the HST Saphir card. - - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_BKM_A4T - bool "Telekom A4T card" - depends on PCI - help - This enables HiSax support for the Telekom A4T card. - - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_SCT_QUADRO - bool "Scitel Quadro card" - depends on PCI - help - This enables HiSax support for the Scitel Quadro card. - - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_GAZEL - bool "Gazel cards" - help - This enables HiSax support for the Gazel cards. - - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_HFC_PCI - bool "HFC PCI-Bus cards" - depends on PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV || (XTENSA && !CPU_LITTLE_ENDIAN))) - help - This enables HiSax support for the HFC-S PCI 2BDS0 based cards. - - For more information see under - . - -config HISAX_W6692 - bool "Winbond W6692 based cards" - depends on PCI - help - This enables HiSax support for Winbond W6692 based PCI ISDN cards. - - See on how to configure it - using a different D-channel protocol, or non-standard IRQ/port - settings. - -config HISAX_HFC_SX - bool "HFC-S+, HFC-SP, HFC-PCMCIA cards" - help - This enables HiSax support for the HFC-S+, HFC-SP and HFC-PCMCIA - cards. This code is not finished yet. - -config HISAX_ENTERNOW_PCI - bool "Formula-n enter:now PCI card" - depends on HISAX_NETJET && PCI && (BROKEN || !(SPARC || PPC || PARISC || M68K || (MIPS && !CPU_LITTLE_ENDIAN) || FRV || (XTENSA && !CPU_LITTLE_ENDIAN))) - help - This enables HiSax support for the Formula-n enter:now PCI - ISDN card. - -config HISAX_DEBUG - bool "HiSax debugging" - help - This enables debugging code in the new-style HiSax drivers, i.e. - the ST5481 USB driver currently. - If in doubt, say yes. - -comment "HiSax PCMCIA card service modules" - -config HISAX_SEDLBAUER_CS - tristate "Sedlbauer PCMCIA cards" - depends on PCMCIA && HISAX_SEDLBAUER - help - This enables the PCMCIA client driver for the Sedlbauer Speed Star - and Speed Star II cards. - -config HISAX_ELSA_CS - tristate "ELSA PCMCIA MicroLink cards" - depends on PCMCIA && HISAX_ELSA - help - This enables the PCMCIA client driver for the Elsa PCMCIA MicroLink - card. - -config HISAX_AVM_A1_CS - tristate "AVM A1 PCMCIA cards" - depends on PCMCIA && ISDN_DRV_HISAX - help - This enables the PCMCIA client driver for the AVM A1 / Fritz!Card - PCMCIA cards. - -config HISAX_TELES_CS - tristate "TELES PCMCIA cards" - depends on PCMCIA && HISAX_16_3 - help - This enables the PCMCIA client driver for the Teles PCMCIA cards. - -comment "HiSax sub driver modules" - -config HISAX_ST5481 - tristate "ST5481 USB ISDN modem" - depends on USB - select ISDN_HDLC - select CRC_CCITT - select BITREVERSE - help - This enables the driver for ST5481 based USB ISDN adapters, - e.g. the BeWan Gazel 128 USB - -config HISAX_HFCUSB - tristate "HFC USB based ISDN modems" - depends on USB - help - This enables the driver for HFC USB based ISDN modems. - -config HISAX_HFC4S8S - tristate "HFC-4S/8S based ISDN cards" - help - This enables the driver for HFC-4S/8S based ISDN cards. - -config HISAX_FRITZ_PCIPNP - tristate "AVM Fritz!Card PCI/PCIv2/PnP support" - depends on PCI - help - This enables the driver for the AVM Fritz!Card PCI, - Fritz!Card PCI v2 and Fritz!Card PnP. - (the latter also needs you to select "ISA Plug and Play support" - from the menu "Plug and Play configuration") - -endif - -endmenu - diff --git a/src/linux/drivers/isdn/hysdn/Kconfig b/src/linux/drivers/isdn/hysdn/Kconfig deleted file mode 100644 index e86bc65..0000000 --- a/src/linux/drivers/isdn/hysdn/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config HYSDN - tristate "Hypercope HYSDN cards (Champ, Ergo, Metro) support (module only)" - depends on m && PROC_FS && PCI - help - Say Y here if you have one of Hypercope's active PCI ISDN cards - Champ, Ergo and Metro. You will then get a module called hysdn. - Please read the file for more - information. - -config HYSDN_CAPI - bool "HYSDN CAPI 2.0 support" - depends on HYSDN && ISDN_CAPI - help - Say Y here if you like to use Hypercope's CAPI 2.0 interface. diff --git a/src/linux/drivers/isdn/i4l/Kconfig b/src/linux/drivers/isdn/i4l/Kconfig deleted file mode 100644 index 68e54d9..0000000 --- a/src/linux/drivers/isdn/i4l/Kconfig +++ /dev/null @@ -1,128 +0,0 @@ -# -# Old ISDN4Linux config -# - -if ISDN_I4L - -config ISDN_PPP - bool "Support synchronous PPP" - depends on INET - select SLHC - help - Over digital connections such as ISDN, there is no need to - synchronize sender and recipient's clocks with start and stop bits - as is done over analog telephone lines. Instead, one can use - "synchronous PPP". Saying Y here will include this protocol. This - protocol is used by Cisco and Sun for example. So you want to say Y - here if the other end of your ISDN connection supports it. You will - need a special version of pppd (called ipppd) for using this - feature. See and - for more information. - -config ISDN_PPP_VJ - bool "Use VJ-compression with synchronous PPP" - depends on ISDN_PPP - help - This enables Van Jacobson header compression for synchronous PPP. - Say Y if the other end of the connection supports it. - -config ISDN_MPP - bool "Support generic MP (RFC 1717)" - depends on ISDN_PPP - help - With synchronous PPP enabled, it is possible to increase throughput - by bundling several ISDN-connections, using this protocol. See - for more information. - -config IPPP_FILTER - bool "Filtering for synchronous PPP" - depends on ISDN_PPP - help - Say Y here if you want to be able to filter the packets passing over - IPPP interfaces. This allows you to control which packets count as - activity (i.e. which packets will reset the idle timer or bring up - a demand-dialled link) and which packets are to be dropped entirely. - You need to say Y here if you wish to use the pass-filter and - active-filter options to ipppd. - -config ISDN_PPP_BSDCOMP - tristate "Support BSD compression" - depends on ISDN_PPP - help - Support for the BSD-Compress compression method for PPP, which uses - the LZW compression method to compress each PPP packet before it is - sent over the wire. The machine at the other end of the PPP link - (usually your ISP) has to support the BSD-Compress compression - method as well for this to be useful. Even if they don't support it, - it is safe to say Y here. - -config ISDN_AUDIO - bool "Support audio via ISDN" - help - If you say Y here, the modem-emulator will support a subset of the - EIA Class 8 Voice commands. Using a getty with voice-support - (mgetty+sendfax by with an extension, available - with the ISDN utility package for example), you will be able to use - your Linux box as an ISDN-answering machine. Of course, this must be - supported by the lowlevel driver also. Currently, the HiSax driver - is the only voice-supporting driver. See - for more information. - -config ISDN_TTY_FAX - bool "Support AT-Fax Class 1 and 2 commands" - depends on ISDN_AUDIO - help - If you say Y here, the modem-emulator will support a subset of the - Fax Class 1 and 2 commands. Using a getty with fax-support - (mgetty+sendfax, hylafax), you will be able to use your Linux box as - an ISDN-fax-machine. This must be supported by the lowlevel driver - also. See for more information. - -config ISDN_X25 - bool "X.25 PLP on top of ISDN" - depends on X25 - help - This feature provides the X.25 protocol over ISDN connections. - See for more information - if you are thinking about using this. - - -menu "ISDN feature submodules" - -config ISDN_DRV_LOOP - tristate "isdnloop support" - depends on BROKEN_ON_SMP - help - This driver provides a virtual ISDN card. Its primary purpose is - testing of linklevel features or configuration without getting - charged by your service-provider for lots of phone calls. - You need will need the loopctrl utility from the latest isdn4k-utils - package to set up this driver. - -config ISDN_DIVERSION - tristate "Support isdn diversion services" - help - This option allows you to use some supplementary diversion - services in conjunction with the HiSax driver on an EURO/DSS1 - line. - - Supported options are CD (call deflection), CFU (Call forward - unconditional), CFB (Call forward when busy) and CFNR (call forward - not reachable). Additionally the actual CFU, CFB and CFNR state may - be interrogated. - - The use of CFU, CFB, CFNR and interrogation may be limited to some - countries. The keypad protocol is still not implemented. CD should - work in all countries if the service has been subscribed to. - - Please read the file . - -endmenu - -comment "ISDN4Linux hardware drivers" - -source "drivers/isdn/hisax/Kconfig" - -# end ISDN_I4L -endif - diff --git a/src/linux/drivers/isdn/mISDN/Kconfig b/src/linux/drivers/isdn/mISDN/Kconfig deleted file mode 100644 index c0730d5..0000000 --- a/src/linux/drivers/isdn/mISDN/Kconfig +++ /dev/null @@ -1,46 +0,0 @@ -# -# modularer ISDN driver -# - -menuconfig MISDN - tristate "Modular ISDN driver" - help - Enable support for the modular ISDN driver. - -if MISDN != n - -config MISDN_DSP - tristate "Digital Audio Processing of transparent data" - depends on MISDN - help - Enable support for digital audio processing capability. - - This module may be used for special applications that require - cross connecting of bchannels, conferencing, dtmf decoding, - echo cancellation, tone generation, and Blowfish encryption and - decryption. It may use hardware features if available. - - E.g. it is required for PBX4Linux. Go to http://isdn.eversberg.eu - and get more information about this module and its usage. - - If unsure, say 'N'. - -config MISDN_L1OIP - tristate "ISDN over IP tunnel" - depends on MISDN - help - Enable support for ISDN over IP tunnel. - - It features: - - dynamic IP exchange, if one or both peers have dynamic IPs - - BRI (S0) and PRI (S2M) interface - - layer 1 control via network keepalive frames - - direct tunneling of physical interface via IP - - NOTE: This protocol is called 'Layer 1 over IP' and is not - compatible with ISDNoIP (Agfeo) or TDMoIP. Protocol description is - provided in the source code. - -source "drivers/isdn/hardware/mISDN/Kconfig" - -endif #MISDN diff --git a/src/linux/drivers/leds/Kconfig b/src/linux/drivers/leds/Kconfig deleted file mode 100644 index 7a628c6..0000000 --- a/src/linux/drivers/leds/Kconfig +++ /dev/null @@ -1,665 +0,0 @@ -config LEDS_GPIO_REGISTER - bool - help - This option provides the function gpio_led_register_device. - As this function is used by arch code it must not be compiled as a - module. - -menuconfig NEW_LEDS - bool "LED Support" - help - Say Y to enable Linux LED support. This allows control of supported - LEDs from both userspace and optionally, by kernel events (triggers). - -if NEW_LEDS - -config LEDS_CLASS - tristate "LED Class Support" - help - This option enables the led sysfs class in /sys/class/leds. You'll - need this to do anything useful with LEDs. If unsure, say N. - -config LEDS_CLASS_FLASH - tristate "LED Flash Class Support" - depends on LEDS_CLASS - help - This option enables the flash led sysfs class in /sys/class/leds. - It wrapps LED Class and adds flash LEDs specific sysfs attributes - and kernel internal API to it. You'll need this to provide support - for the flash related features of a LED device. It can be built - as a module. - -comment "LED drivers" - -config LEDS_88PM860X - tristate "LED Support for Marvell 88PM860x PMIC" - depends on LEDS_CLASS - depends on MFD_88PM860X - help - This option enables support for on-chip LED drivers found on Marvell - Semiconductor 88PM8606 PMIC. - -config LEDS_AAT1290 - tristate "LED support for the AAT1290" - depends on LEDS_CLASS_FLASH - depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS - depends on GPIOLIB || COMPILE_TEST - depends on OF - depends on PINCTRL - help - This option enables support for the LEDs on the AAT1290. - -config LEDS_BCM6328 - tristate "LED Support for Broadcom BCM6328" - depends on LEDS_CLASS - depends on HAS_IOMEM - depends on OF - help - This option enables support for LEDs connected to the BCM6328 - LED HW controller accessed via MMIO registers. - -config LEDS_BCM6358 - tristate "LED Support for Broadcom BCM6358" - depends on LEDS_CLASS - depends on HAS_IOMEM - depends on OF - help - This option enables support for LEDs connected to the BCM6358 - LED HW controller accessed via MMIO registers. - -config LEDS_LM3530 - tristate "LCD Backlight driver for LM3530" - depends on LEDS_CLASS - depends on I2C - help - This option enables support for the LCD backlight using - LM3530 ambient light sensor chip. This ALS chip can be - controlled manually or using PWM input or using ambient - light automatically. - -config LEDS_LM3533 - tristate "LED support for LM3533" - depends on LEDS_CLASS - depends on MFD_LM3533 - help - This option enables support for the LEDs on National Semiconductor / - TI LM3533 Lighting Power chips. - - The LEDs can be controlled directly, through PWM input, or by the - ambient-light-sensor interface. The chip supports - hardware-accelerated blinking with maximum on and off periods of 9.8 - and 77 seconds respectively. - -config LEDS_LM3642 - tristate "LED support for LM3642 Chip" - depends on LEDS_CLASS && I2C - select REGMAP_I2C - help - This option enables support for LEDs connected to LM3642. - The LM3642 is a 4MHz fixed-frequency synchronous boost - converter plus 1.5A constant current driver for a high-current - white LED. - - -config LEDS_LOCOMO - tristate "LED Support for Locomo device" - depends on LEDS_CLASS - depends on SHARP_LOCOMO - help - This option enables support for the LEDs on Sharp Locomo. - Zaurus models SL-5500 and SL-5600. - -config LEDS_MIKROTIK_RB532 - tristate "LED Support for Mikrotik Routerboard 532" - depends on LEDS_CLASS - depends on MIKROTIK_RB532 - help - This option enables support for the so called "User LED" of - Mikrotik's Routerboard 532. - -config LEDS_S3C24XX - tristate "LED Support for Samsung S3C24XX GPIO LEDs" - depends on LEDS_CLASS - depends on ARCH_S3C24XX - help - This option enables support for LEDs connected to GPIO lines - on Samsung S3C24XX series CPUs, such as the S3C2410 and S3C2440. - -config LEDS_NET48XX - tristate "LED Support for Soekris net48xx series Error LED" - depends on LEDS_CLASS - depends on SCx200_GPIO - help - This option enables support for the Soekris net4801 and net4826 error - LED. - -config LEDS_FSG - tristate "LED Support for the Freecom FSG-3" - depends on LEDS_CLASS - depends on MACH_FSG - help - This option enables support for the LEDs on the Freecom FSG-3. - -config LEDS_WRAP - tristate "LED Support for the WRAP series LEDs" - depends on LEDS_CLASS - depends on SCx200_GPIO - help - This option enables support for the PCEngines WRAP programmable LEDs. - -config LEDS_COBALT_QUBE - tristate "LED Support for the Cobalt Qube series front LED" - depends on LEDS_CLASS - depends on MIPS_COBALT - help - This option enables support for the front LED on Cobalt Qube series - -config LEDS_COBALT_RAQ - bool "LED Support for the Cobalt Raq series" - depends on LEDS_CLASS=y && MIPS_COBALT - select LEDS_TRIGGERS - help - This option enables support for the Cobalt Raq series LEDs. - -config LEDS_SUNFIRE - tristate "LED support for SunFire servers." - depends on LEDS_CLASS - depends on SPARC64 - select LEDS_TRIGGERS - help - This option enables support for the Left, Middle, and Right - LEDs on the I/O and CPU boards of SunFire UltraSPARC servers. - -config LEDS_IPAQ_MICRO - tristate "LED Support for the Compaq iPAQ h3xxx" - depends on LEDS_CLASS - depends on MFD_IPAQ_MICRO - help - Choose this option if you want to use the notification LED on - Compaq/HP iPAQ h3100 and h3600. - -config LEDS_HP6XX - tristate "LED Support for the HP Jornada 6xx" - depends on LEDS_CLASS - depends on SH_HP6XX - help - This option enables LED support for the handheld - HP Jornada 620/660/680/690. - -config LEDS_PCA9532 - tristate "LED driver for PCA9532 dimmer" - depends on LEDS_CLASS - depends on I2C && INPUT - help - This option enables support for NXP pca9532 - LED controller. It is generally only useful - as a platform driver - -config LEDS_PCA9532_GPIO - bool "Enable GPIO support for PCA9532" - depends on LEDS_PCA9532 - depends on GPIOLIB - help - Allow unused pins on PCA9532 to be used as gpio. - - To use a pin as gpio pca9532_type in pca9532_platform data needs to - set to PCA9532_TYPE_GPIO. - -config LEDS_GPIO - tristate "LED Support for GPIO connected LEDs" - depends on LEDS_CLASS - depends on GPIOLIB || COMPILE_TEST - help - This option enables support for the LEDs connected to GPIO - outputs. To be useful the particular board must have LEDs - and they must be connected to the GPIO lines. The LEDs must be - defined as platform devices and/or OpenFirmware platform devices. - The code to use these bindings can be selected below. - -config LEDS_LP3944 - tristate "LED Support for N.S. LP3944 (Fun Light) I2C chip" - depends on LEDS_CLASS - depends on I2C - help - This option enables support for LEDs connected to the National - Semiconductor LP3944 Lighting Management Unit (LMU) also known as - Fun Light Chip. - - To compile this driver as a module, choose M here: the - module will be called leds-lp3944. - -config LEDS_LP3952 - tristate "LED Support for TI LP3952 2 channel LED driver" - depends on LEDS_CLASS - depends on I2C - depends on ACPI - depends on GPIOLIB - select REGMAP_I2C - help - This option enables support for LEDs connected to the Texas - Instruments LP3952 LED driver. - - To compile this driver as a module, choose M here: the - module will be called leds-lp3952. - -config LEDS_LP55XX_COMMON - tristate "Common Driver for TI/National LP5521/5523/55231/5562/8501" - depends on LEDS_LP5521 || LEDS_LP5523 || LEDS_LP5562 || LEDS_LP8501 - select FW_LOADER - select FW_LOADER_USER_HELPER - help - This option supports common operations for LP5521/5523/55231/5562/8501 - devices. - -config LEDS_LP5521 - tristate "LED Support for N.S. LP5521 LED driver chip" - depends on LEDS_CLASS && I2C - select LEDS_LP55XX_COMMON - help - If you say yes here you get support for the National Semiconductor - LP5521 LED driver. It is 3 channel chip with programmable engines. - Driver provides direct control via LED class and interface for - programming the engines. - -config LEDS_LP5523 - tristate "LED Support for TI/National LP5523/55231 LED driver chip" - depends on LEDS_CLASS && I2C - select LEDS_LP55XX_COMMON - help - If you say yes here you get support for TI/National Semiconductor - LP5523/55231 LED driver. - It is 9 channel chip with programmable engines. - Driver provides direct control via LED class and interface for - programming the engines. - -config LEDS_LP5562 - tristate "LED Support for TI LP5562 LED driver chip" - depends on LEDS_CLASS && I2C - select LEDS_LP55XX_COMMON - help - If you say yes here you get support for TI LP5562 LED driver. - It is 4 channels chip with programmable engines. - Driver provides direct control via LED class and interface for - programming the engines. - -config LEDS_LP8501 - tristate "LED Support for TI LP8501 LED driver chip" - depends on LEDS_CLASS && I2C - select LEDS_LP55XX_COMMON - help - If you say yes here you get support for TI LP8501 LED driver. - It is 9 channel chip with programmable engines. - Driver provides direct control via LED class and interface for - programming the engines. - It is similar as LP5523, but output power selection is available. - And register layout and engine program schemes are different. - -config LEDS_LP8788 - tristate "LED support for the TI LP8788 PMIC" - depends on LEDS_CLASS - depends on MFD_LP8788 - help - This option enables support for the Keyboard LEDs on the LP8788 PMIC. - -config LEDS_LP8860 - tristate "LED support for the TI LP8860 4 channel LED driver" - depends on LEDS_CLASS && I2C - select REGMAP_I2C - help - If you say yes here you get support for the TI LP8860 4 channel - LED driver. - This option enables support for the display cluster LEDs - on the LP8860 4 channel LED driver using the I2C communication - bus. - -config LEDS_CLEVO_MAIL - tristate "Mail LED on Clevo notebook" - depends on LEDS_CLASS - depends on X86 && SERIO_I8042 && DMI - help - This driver makes the mail LED accessible from userspace - programs through the leds subsystem. This LED have three - known mode: off, blink at 0.5Hz and blink at 1Hz. - - The driver supports two kinds of interface: using ledtrig-timer - or through /sys/class/leds/clevo::mail/brightness. As this LED - cannot change it's brightness it blinks instead. The brightness - value 0 means off, 1..127 means blink at 0.5Hz and 128..255 means - blink at 1Hz. - - This module can drive the mail LED for the following notebooks: - - Clevo D400P - Clevo D410J - Clevo D410V - Clevo D400V/D470V (not tested, but might work) - Clevo M540N - Clevo M5x0N (not tested, but might work) - Positivo Mobile (Clevo M5x0V) - - If your model is not listed here you can try the "nodetect" - module parameter. - - To compile this driver as a module, choose M here: the - module will be called leds-clevo-mail. - -config LEDS_PCA955X - tristate "LED Support for PCA955x I2C chips" - depends on LEDS_CLASS - depends on I2C - help - This option enables support for LEDs connected to PCA955x - LED driver chips accessed via the I2C bus. Supported - devices include PCA9550, PCA9551, PCA9552, and PCA9553. - -config LEDS_PCA963X - tristate "LED support for PCA963x I2C chip" - depends on LEDS_CLASS - depends on I2C - help - This option enables support for LEDs connected to the PCA963x - LED driver chip accessed via the I2C bus. Supported - devices include PCA9633 and PCA9634 - -config LEDS_WM831X_STATUS - tristate "LED support for status LEDs on WM831x PMICs" - depends on LEDS_CLASS - depends on MFD_WM831X - help - This option enables support for the status LEDs of the WM831x - series of PMICs. - -config LEDS_WM8350 - tristate "LED Support for WM8350 AudioPlus PMIC" - depends on LEDS_CLASS - depends on MFD_WM8350 - help - This option enables support for LEDs driven by the Wolfson - Microelectronics WM8350 AudioPlus PMIC. - -config LEDS_DA903X - tristate "LED Support for DA9030/DA9034 PMIC" - depends on LEDS_CLASS - depends on PMIC_DA903X - help - This option enables support for on-chip LED drivers found - on Dialog Semiconductor DA9030/DA9034 PMICs. - -config LEDS_DA9052 - tristate "Dialog DA9052/DA9053 LEDS" - depends on LEDS_CLASS - depends on PMIC_DA9052 - help - This option enables support for on-chip LED drivers found - on Dialog Semiconductor DA9052-BC and DA9053-AA/Bx PMICs. - -config LEDS_DAC124S085 - tristate "LED Support for DAC124S085 SPI DAC" - depends on LEDS_CLASS - depends on SPI - help - This option enables support for DAC124S085 SPI DAC from NatSemi, - which can be used to control up to four LEDs. - -config LEDS_PWM - tristate "PWM driven LED Support" - depends on LEDS_CLASS - depends on PWM - help - This option enables support for pwm driven LEDs - -config LEDS_REGULATOR - tristate "REGULATOR driven LED support" - depends on LEDS_CLASS - depends on REGULATOR - help - This option enables support for regulator driven LEDs. - -config LEDS_BD2802 - tristate "LED driver for BD2802 RGB LED" - depends on LEDS_CLASS - depends on I2C - help - This option enables support for BD2802GU RGB LED driver chips - accessed via the I2C bus. - -config LEDS_INTEL_SS4200 - tristate "LED driver for Intel NAS SS4200 series" - depends on LEDS_CLASS - depends on PCI && DMI - depends on X86 - help - This option enables support for the Intel SS4200 series of - Network Attached Storage servers. You may control the hard - drive or power LEDs on the front panel. Using this driver - can stop the front LED from blinking after startup. - -config LEDS_LT3593 - tristate "LED driver for LT3593 controllers" - depends on LEDS_CLASS - depends on GPIOLIB || COMPILE_TEST - help - This option enables support for LEDs driven by a Linear Technology - LT3593 controller. This controller uses a special one-wire pulse - coding protocol to set the brightness. - -config LEDS_ADP5520 - tristate "LED Support for ADP5520/ADP5501 PMIC" - depends on LEDS_CLASS - depends on PMIC_ADP5520 - help - This option enables support for on-chip LED drivers found - on Analog Devices ADP5520/ADP5501 PMICs. - - To compile this driver as a module, choose M here: the module will - be called leds-adp5520. - -config LEDS_DELL_NETBOOKS - tristate "External LED on Dell Business Netbooks" - depends on LEDS_CLASS - depends on X86 && ACPI_WMI - depends on DELL_SMBIOS - help - This adds support for the Latitude 2100 and similar - notebooks that have an external LED. - -config LEDS_MC13783 - tristate "LED Support for MC13XXX PMIC" - depends on LEDS_CLASS - depends on MFD_MC13XXX - help - This option enable support for on-chip LED drivers found - on Freescale Semiconductor MC13783/MC13892/MC34708 PMIC. - -config LEDS_NS2 - tristate "LED support for Network Space v2 GPIO LEDs" - depends on LEDS_CLASS - depends on MACH_KIRKWOOD || MACH_ARMADA_370 - default y - help - This option enables support for the dual-GPIO LEDs found on the - following LaCie/Seagate boards: - - Network Space v2 (and parents: Max, Mini) - Internet Space v2 - d2 Network v2 - n090401 (Seagate NAS 4-Bay) - -config LEDS_NETXBIG - tristate "LED support for Big Network series LEDs" - depends on LEDS_CLASS - depends on MACH_KIRKWOOD - default y - help - This option enable support for LEDs found on the LaCie 2Big - and 5Big Network v2 boards. The LEDs are wired to a CPLD and are - controlled through a GPIO extension bus. - -config LEDS_ASIC3 - bool "LED support for the HTC ASIC3" - depends on LEDS_CLASS=y - depends on MFD_ASIC3 - default y - help - This option enables support for the LEDs on the HTC ASIC3. The HTC - ASIC3 LED GPIOs are inputs, not outputs, thus the leds-gpio driver - cannot be used. This driver supports hardware blinking with an on+off - period from 62ms to 125s. Say Y to enable LEDs on the HP iPAQ hx4700. - -config LEDS_TCA6507 - tristate "LED Support for TCA6507 I2C chip" - depends on LEDS_CLASS && I2C - help - This option enables support for LEDs connected to TC6507 - LED driver chips accessed via the I2C bus. - Driver support brightness control and hardware-assisted blinking. - -config LEDS_TLC591XX - tristate "LED driver for TLC59108 and TLC59116 controllers" - depends on LEDS_CLASS && I2C - select REGMAP_I2C - help - This option enables support for Texas Instruments TLC59108 - and TLC59116 LED controllers. - -config LEDS_MAX77693 - tristate "LED support for MAX77693 Flash" - depends on LEDS_CLASS_FLASH - depends on V4L2_FLASH_LED_CLASS || !V4L2_FLASH_LED_CLASS - depends on MFD_MAX77693 - depends on OF - help - This option enables support for the flash part of the MAX77693 - multifunction device. It has build in control for two leds in flash - and torch mode. - -config LEDS_MAX8997 - tristate "LED support for MAX8997 PMIC" - depends on LEDS_CLASS && MFD_MAX8997 - help - This option enables support for on-chip LED drivers on - MAXIM MAX8997 PMIC. - -config LEDS_LM355x - tristate "LED support for LM355x Chips, LM3554 and LM3556" - depends on LEDS_CLASS && I2C - select REGMAP_I2C - help - This option enables support for LEDs connected to LM355x. - LM355x includes Torch, Flash and Indicator functions. - -config LEDS_OT200 - tristate "LED support for the Bachmann OT200" - depends on LEDS_CLASS && HAS_IOMEM && (X86_32 || COMPILE_TEST) - help - This option enables support for the LEDs on the Bachmann OT200. - Say Y to enable LEDs on the Bachmann OT200. - -config LEDS_MENF21BMC - tristate "LED support for the MEN 14F021P00 BMC" - depends on LEDS_CLASS && MFD_MENF21BMC - help - Say Y here to include support for the MEN 14F021P00 BMC LEDs. - - This driver can also be built as a module. If so the module - will be called leds-menf21bmc. - -config LEDS_KTD2692 - tristate "LED support for KTD2692 flash LED controller" - depends on LEDS_CLASS_FLASH && OF - depends on GPIOLIB || COMPILE_TEST - help - This option enables support for KTD2692 LED flash connected - through ExpressWire interface. - - Say Y to enable this driver. - -config LEDS_SEAD3 - tristate "LED support for the MIPS SEAD 3 board" - depends on LEDS_CLASS && MIPS_SEAD3 - help - Say Y here to include support for the FLED and PLED LEDs on SEAD3 eval - boards. - - This driver can also be built as a module. If so the module - will be called leds-sead3. - -config LEDS_IS31FL319X - tristate "LED Support for ISSI IS31FL319x I2C LED controller family" - depends on LEDS_CLASS && I2C && OF - select REGMAP_I2C - help - This option enables support for LEDs connected to ISSI IS31FL319x - fancy LED driver chips accessed via the I2C bus. - Driver supports individual PWM brightness control for each channel. - - This driver can also be built as a module. If so the module will be - called leds-is31fl319x. - -config LEDS_IS31FL32XX - tristate "LED support for ISSI IS31FL32XX I2C LED controller family" - depends on LEDS_CLASS && I2C && OF - help - Say Y here to include support for ISSI IS31FL32XX and Si-En SN32xx - LED controllers. They are I2C devices with multiple constant-current - channels, each with independent 256-level PWM control. - -comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)" - -config LEDS_BLINKM - tristate "LED support for the BlinkM I2C RGB LED" - depends on LEDS_CLASS - depends on I2C - help - This option enables support for the BlinkM RGB LED connected - through I2C. Say Y to enable support for the BlinkM LED. - -config LEDS_POWERNV - tristate "LED support for PowerNV Platform" - depends on LEDS_CLASS - depends on PPC_POWERNV - depends on OF - help - This option enables support for the system LEDs present on - PowerNV platforms. Say 'y' to enable this support in kernel. - To compile this driver as a module, choose 'm' here: the module - will be called leds-powernv. - -config LEDS_SYSCON - bool "LED support for LEDs on system controllers" - depends on LEDS_CLASS=y - depends on MFD_SYSCON - depends on OF - help - This option enabled support for the LEDs on syscon type - devices. This will only work with device tree enabled - devices. - -config LEDS_VERSATILE - tristate "LED support for the ARM Versatile and RealView" - depends on ARCH_REALVIEW || ARCH_VERSATILE - depends on LEDS_CLASS - help - This option enabled support for the LEDs on the ARM Versatile - and RealView boards. Say Y to enabled these. - -config LEDS_PM8058 - tristate "LED Support for the Qualcomm PM8058 PMIC" - depends on MFD_PM8921_CORE - depends on LEDS_CLASS - help - Choose this option if you want to use the LED drivers in - the Qualcomm PM8058 PMIC. - -config LEDS_MLXCPLD - tristate "LED support for the Mellanox boards" - depends on X86_64 && DMI - depends on LEDS_CLASS - help - This option enabled support for the LEDs on the Mellanox - boards. Say Y to enabled these. - -comment "LED Triggers" -source "drivers/leds/trigger/Kconfig" - -endif # NEW_LEDS diff --git a/src/linux/drivers/leds/trigger/Kconfig b/src/linux/drivers/leds/trigger/Kconfig deleted file mode 100644 index 3f9ddb9..0000000 --- a/src/linux/drivers/leds/trigger/Kconfig +++ /dev/null @@ -1,129 +0,0 @@ -menuconfig LEDS_TRIGGERS - bool "LED Trigger support" - depends on LEDS_CLASS - help - This option enables trigger support for the leds class. - These triggers allow kernel events to drive the LEDs and can - be configured via sysfs. If unsure, say Y. - -if LEDS_TRIGGERS - -config LEDS_TRIGGER_TIMER - tristate "LED Timer Trigger" - depends on LEDS_TRIGGERS - help - This allows LEDs to be controlled by a programmable timer - via sysfs. Some LED hardware can be programmed to start - blinking the LED without any further software interaction. - For more details read Documentation/leds/leds-class.txt. - - If unsure, say Y. - -config LEDS_TRIGGER_ONESHOT - tristate "LED One-shot Trigger" - depends on LEDS_TRIGGERS - help - This allows LEDs to blink in one-shot pulses with parameters - controlled via sysfs. It's useful to notify the user on - sporadic events, when there are no clear begin and end trap points, - or on dense events, where this blinks the LED at constant rate if - rearmed continuously. - - It also shows how to use the led_blink_set_oneshot() function. - - If unsure, say Y. - -config LEDS_TRIGGER_DISK - bool "LED Disk Trigger" - depends on IDE_GD_ATA || ATA - depends on LEDS_TRIGGERS - help - This allows LEDs to be controlled by disk activity. - If unsure, say Y. - -config LEDS_TRIGGER_MTD - bool "LED MTD (NAND/NOR) Trigger" - depends on MTD - depends on LEDS_TRIGGERS - help - This allows LEDs to be controlled by MTD activity. - If unsure, say N. - -config LEDS_TRIGGER_HEARTBEAT - tristate "LED Heartbeat Trigger" - depends on LEDS_TRIGGERS - help - This allows LEDs to be controlled by a CPU load average. - The flash frequency is a hyperbolic function of the 1-minute - load average. - If unsure, say Y. - -config LEDS_TRIGGER_BACKLIGHT - tristate "LED backlight Trigger" - depends on LEDS_TRIGGERS - help - This allows LEDs to be controlled as a backlight device: they - turn off and on when the display is blanked and unblanked. - - If unsure, say N. - -config LEDS_TRIGGER_CPU - bool "LED CPU Trigger" - depends on LEDS_TRIGGERS - help - This allows LEDs to be controlled by active CPUs. This shows - the active CPUs across an array of LEDs so you can see which - CPUs are active on the system at any given moment. - - If unsure, say N. - -config LEDS_TRIGGER_GPIO - tristate "LED GPIO Trigger" - depends on LEDS_TRIGGERS - depends on GPIOLIB || COMPILE_TEST - help - This allows LEDs to be controlled by gpio events. It's good - when using gpios as switches and triggering the needed LEDs - from there. One use case is n810's keypad LEDs that could - be triggered by this trigger when user slides up to show - keypad. - - If unsure, say N. - -config LEDS_TRIGGER_DEFAULT_ON - tristate "LED Default ON Trigger" - depends on LEDS_TRIGGERS - help - This allows LEDs to be initialised in the ON state. - If unsure, say Y. - -comment "iptables trigger is under Netfilter config (LED target)" - depends on LEDS_TRIGGERS - -config LEDS_TRIGGER_TRANSIENT - tristate "LED Transient Trigger" - depends on LEDS_TRIGGERS - help - This allows one time activation of a transient state on - GPIO/PWM based hardware. - If unsure, say Y. - -config LEDS_TRIGGER_CAMERA - tristate "LED Camera Flash/Torch Trigger" - depends on LEDS_TRIGGERS - help - This allows LEDs to be controlled as a camera flash/torch device. - This enables direct flash/torch on/off by the driver, kernel space. - If unsure, say Y. - -config LEDS_TRIGGER_PANIC - bool "LED Panic Trigger" - depends on LEDS_TRIGGERS - help - This allows LEDs to be configured to blink on a kernel panic. - Enabling this option will allow to mark certain LEDs as panic indicators, - allowing to blink them on a kernel panic, even if they are set to - a different trigger. - If unsure, say Y. - -endif # LEDS_TRIGGERS diff --git a/src/linux/drivers/lguest/Makefile b/src/linux/drivers/lguest/Makefile deleted file mode 100644 index 16f52ee..0000000 --- a/src/linux/drivers/lguest/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -# Host requires the other files, which can be a module. -obj-$(CONFIG_LGUEST) += lg.o -lg-y = core.o hypercalls.o page_tables.o interrupts_and_traps.o \ - segments.o lguest_user.o - -lg-$(CONFIG_X86_32) += x86/switcher_32.o x86/core.o - -Preparation Preparation!: PREFIX=P -Guest: PREFIX=G -Drivers: PREFIX=D -Launcher: PREFIX=L -Host: PREFIX=H -Switcher: PREFIX=S -Mastery: PREFIX=M -Beer: - @for f in Preparation Guest Drivers Launcher Host Switcher Mastery; do echo "{==- $$f -==}"; make -s $$f; done; echo "{==-==}" -Preparation Preparation! Guest Drivers Launcher Host Switcher Mastery: - @sh ../../tools/lguest/extract $(PREFIX) `find ../../* -name '*.[chS]' -wholename '*lguest*'` -Puppy: - @clear - @printf " __ \n (___()'\`;\n /, /\`\n \\\\\\\"--\\\\\\ \n" - @sleep 2; clear; printf "\n\n Sit!\n\n"; sleep 1; clear - @printf " __ \n ()'\`; \n /\\|\` \n / | \n(/_)_|_ \n" - @sleep 2; clear; printf "\n\n Stand!\n\n"; sleep 1; clear - @printf " __ \n ()'\`; \n /\\|\` \n /._.= \n /| / \n(_\_)_ \n" - @sleep 2; clear; printf "\n\n Good puppy!\n\n"; sleep 1; clear diff --git a/src/linux/drivers/lightnvm/Kconfig b/src/linux/drivers/lightnvm/Kconfig deleted file mode 100644 index 2f5d5f4..0000000 --- a/src/linux/drivers/lightnvm/Kconfig +++ /dev/null @@ -1,45 +0,0 @@ -# -# Open-Channel SSD NVM configuration -# - -menuconfig NVM - bool "Open-Channel SSD target support" - depends on BLOCK && HAS_DMA - help - Say Y here to get to enable Open-channel SSDs. - - Open-Channel SSDs implement a set of extension to SSDs, that - exposes direct access to the underlying non-volatile memory. - - If you say N, all options in this submenu will be skipped and disabled - only do this if you know what you are doing. - -if NVM - -config NVM_DEBUG - bool "Open-Channel SSD debugging support" - default n - ---help--- - Exposes a debug management interface to create/remove targets at: - - /sys/module/lnvm/parameters/configure_debug - - It is required to create/remove targets without IOCTLs. - -config NVM_GENNVM - tristate "General Non-Volatile Memory Manager for Open-Channel SSDs" - ---help--- - Non-volatile memory media manager for Open-Channel SSDs that implements - physical media metadata management and block provisioning API. - - This is the standard media manager for using Open-Channel SSDs, and - required for targets to be instantiated. - -config NVM_RRPC - tristate "Round-robin Hybrid Open-Channel SSD target" - ---help--- - Allows an open-channel SSD to be exposed as a block device to the - host. The target is implemented using a linear mapping table and - cost-based garbage collection. It is optimized for 4K IO sizes. - -endif # NVM diff --git a/src/linux/drivers/macintosh/Kconfig b/src/linux/drivers/macintosh/Kconfig deleted file mode 100644 index d28690f..0000000 --- a/src/linux/drivers/macintosh/Kconfig +++ /dev/null @@ -1,294 +0,0 @@ - -menuconfig MACINTOSH_DRIVERS - bool "Macintosh device drivers" - depends on PPC || MAC || X86 - default y if (PPC_PMAC || MAC) - ---help--- - Say Y here to get to see options for devices used with Macintosh - computers. This option alone does not add any kernel code. - - If you say N, all options in this submenu will be skipped and disabled. - -if MACINTOSH_DRIVERS - -config ADB - bool "Apple Desktop Bus (ADB) support" - depends on MAC || (PPC_PMAC && PPC32) - help - Apple Desktop Bus (ADB) support is for support of devices which - are connected to an ADB port. ADB devices tend to have 4 pins. - If you have an Apple Macintosh prior to the iMac, an iBook or - PowerBook, or a "Blue and White G3", you probably want to say Y - here. Otherwise say N. - -config ADB_MACII - bool "Include Mac II ADB driver" - depends on ADB && MAC - help - Say Y here if want your kernel to support Macintosh systems that use - the Mac II style ADB. This includes the II, IIx, IIcx, SE/30, IIci, - Quadra 610, Quadra 650, Quadra 700, Quadra 800, Centris 610 and - Centris 650. - -config ADB_MACIISI - bool "Include Mac IIsi ADB driver" - depends on ADB && MAC && BROKEN - help - Say Y here if want your kernel to support Macintosh systems that use - the Mac IIsi style ADB. This includes the IIsi, IIvi, IIvx, Classic - II, LC, LC II, LC III, Performa 460, and the Performa 600. - -config ADB_IOP - bool "Include IOP (IIfx/Quadra 9x0) ADB driver" - depends on ADB && MAC - help - The I/O Processor (IOP) is an Apple custom IC designed to provide - intelligent support for I/O controllers. It is described at - to enable direct - support for it, say 'Y' here. - -config ADB_PMU68K - bool "Include PMU (Powerbook) ADB driver" - depends on ADB && MAC - help - Say Y here if want your kernel to support the m68k based Powerbooks. - This includes the PowerBook 140, PowerBook 145, PowerBook 150, - PowerBook 160, PowerBook 165, PowerBook 165c, PowerBook 170, - PowerBook 180, PowerBook, 180c, PowerBook 190cs, PowerBook 520, - PowerBook Duo 210, PowerBook Duo 230, PowerBook Duo 250, - PowerBook Duo 270c, PowerBook Duo 280 and PowerBook Duo 280c. - -# we want to change this to something like CONFIG_SYSCTRL_CUDA/PMU -config ADB_CUDA - bool "Support for CUDA based Macs and PowerMacs" - depends on (ADB || PPC_PMAC) && !PPC_PMAC64 - help - This provides support for CUDA based Macintosh and Power Macintosh - systems. This includes many m68k based Macs (Color Classic, Mac TV, - Performa 475, Performa 520, Performa 550, Performa 575, - Performa 588, Quadra 605, Quadra 630, Quadra/Centris 660AV, and - Quadra 840AV), most OldWorld PowerMacs, the first generation iMacs, - the Blue&White G3 and the "Yikes" G4 (PCI Graphics). All later - models should use CONFIG_ADB_PMU instead. It is safe to say Y here - even if your machine doesn't have a CUDA. - - If unsure say Y. - -config ADB_PMU - bool "Support for PMU based PowerMacs" - depends on PPC_PMAC - help - On PowerBooks, iBooks, and recent iMacs and Power Macintoshes, the - PMU is an embedded microprocessor whose primary function is to - control system power, and battery charging on the portable models. - The PMU also controls the ADB (Apple Desktop Bus) which connects to - the keyboard and mouse on some machines, as well as the non-volatile - RAM and the RTC (real time clock) chip. Say Y to enable support for - this device; you should do so if your machine is one of those - mentioned above. - -config ADB_PMU_LED - bool "Support for the Power/iBook front LED" - depends on ADB_PMU - select NEW_LEDS - select LEDS_CLASS - help - Support the front LED on Power/iBooks as a generic LED that can - be triggered by any of the supported triggers. To get the - behaviour of the old CONFIG_BLK_DEV_IDE_PMAC_BLINK, select this - and the disk LED trigger and configure appropriately through sysfs. - -config ADB_PMU_LED_DISK - bool "Use front LED as DISK LED by default" - depends on ADB_PMU_LED - depends on LEDS_CLASS - depends on IDE_GD_ATA - select LEDS_TRIGGERS - select LEDS_TRIGGER_DISK - help - This option makes the front LED default to the disk trigger - so that it blinks on disk activity. - -config PMAC_SMU - bool "Support for SMU based PowerMacs" - depends on PPC_PMAC64 - help - This option adds support for the newer G5 iMacs and PowerMacs based - on the "SMU" system control chip which replaces the old PMU. - If you don't know, say Y. - -config PMAC_APM_EMU - tristate "APM emulation" - select APM_EMULATION - depends on ADB_PMU && PM && PPC32 - -config PMAC_MEDIABAY - bool "Support PowerBook hotswap media bay" - depends on PPC_PMAC && PPC32 && BLOCK - help - This option adds support for older PowerBook's hotswap media bay - that can contains batteries, floppy drives, or IDE devices. PCI - devices are not fully supported in the bay as I never had one to - try with - -config PMAC_BACKLIGHT - bool "Backlight control for LCD screens" - depends on ADB_PMU && FB = y && (BROKEN || !PPC64) - select FB_BACKLIGHT - help - Say Y here to enable Macintosh specific extensions of the generic - backlight code. With this enabled, the brightness keys on older - PowerBooks will be enabled so you can change the screen brightness. - Newer models should use a userspace daemon like pbbuttonsd. - -config PMAC_BACKLIGHT_LEGACY - bool "Provide legacy ioctl's on /dev/pmu for the backlight" - depends on PMAC_BACKLIGHT && (BROKEN || !PPC64) - help - Say Y if you want to enable legacy ioctl's on /dev/pmu. This is for - programs which use this old interface. New and updated programs - should use the backlight classes in sysfs. - -config ADB_MACIO - bool "Include MacIO (CHRP) ADB driver" - depends on ADB && PPC_CHRP && !PPC_PMAC64 - help - Say Y here to include direct support for the ADB controller in the - Hydra chip used on PowerPC Macintoshes of the CHRP type. (The Hydra - also includes a MESH II SCSI controller, DBDMA controller, VIA chip, - OpenPIC controller and two RS422/Geoports.) - -config INPUT_ADBHID - bool "Support for ADB input devices (keyboard, mice, ...)" - depends on ADB && INPUT=y - help - Say Y here if you want to have ADB (Apple Desktop Bus) HID devices - such as keyboards, mice, joysticks, trackpads or graphic tablets - handled by the input layer. If you say Y here, make sure to say Y to - the corresponding drivers "Mouse Support" (CONFIG_INPUT_MOUSEDEV) and - "Event interface support" (CONFIG_INPUT_EVDEV) as well. - - If unsure, say Y. - -config MAC_EMUMOUSEBTN - tristate "Support for mouse button 2+3 emulation" - depends on SYSCTL && INPUT - help - This provides generic support for emulating the 2nd and 3rd mouse - button with keypresses. If you say Y here, the emulation is still - disabled by default. The emulation is controlled by these sysctl - entries: - /proc/sys/dev/mac_hid/mouse_button_emulation - /proc/sys/dev/mac_hid/mouse_button2_keycode - /proc/sys/dev/mac_hid/mouse_button3_keycode - - If you have an Apple machine with a 1-button mouse, say Y here. - - To compile this driver as a module, choose M here: the - module will be called mac_hid. - -config THERM_WINDTUNNEL - tristate "Support for thermal management on Windtunnel G4s" - depends on I2C && I2C_POWERMAC && PPC_PMAC && !PPC_PMAC64 - help - This driver provides some thermostat and fan control for the desktop - G4 "Windtunnel" - -config THERM_ADT746X - tristate "Support for thermal mgmnt on laptops with ADT 746x chipset" - depends on I2C && I2C_POWERMAC && PPC_PMAC && !PPC_PMAC64 - help - This driver provides some thermostat and fan control for the - iBook G4, and the ATI based aluminium PowerBooks, allowing slightly - better fan behaviour by default, and some manual control. - -config WINDFARM - tristate "New PowerMac thermal control infrastructure" - depends on PPC - -config WINDFARM_PM81 - tristate "Support for thermal management on iMac G5" - depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU - select I2C_POWERMAC - help - This driver provides thermal control for the iMacG5 - -config WINDFARM_PM72 - tristate "Support for thermal management on PowerMac G5 (AGP)" - depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && ADB_PMU - select I2C_POWERMAC - help - This driver provides thermal control for the PowerMac G5 - "AGP" variants (PowerMac 7,2 and 7,3) - -config WINDFARM_RM31 - tristate "Support for thermal management on Xserve G5" - depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && ADB_PMU - select I2C_POWERMAC - help - This driver provides thermal control for the Xserve G5 - (RackMac3,1) - -config WINDFARM_PM91 - tristate "Support for thermal management on PowerMac9,1" - depends on WINDFARM && I2C && CPU_FREQ_PMAC64 && PMAC_SMU - select I2C_POWERMAC - help - This driver provides thermal control for the PowerMac9,1 - which is the recent (SMU based) single CPU desktop G5 - -config WINDFARM_PM112 - tristate "Support for thermal management on PowerMac11,2" - depends on WINDFARM && I2C && PMAC_SMU - select I2C_POWERMAC - help - This driver provides thermal control for the PowerMac11,2 - which are the recent dual and quad G5 machines using the - 970MP dual-core processor. - -config WINDFARM_PM121 - tristate "Support for thermal management on PowerMac12,1" - depends on WINDFARM && I2C && PMAC_SMU - select I2C_POWERMAC - help - This driver provides thermal control for the PowerMac12,1 - which is the iMac G5 (iSight). - -config ANSLCD - tristate "Support for ANS LCD display" - depends on ADB_CUDA && PPC_PMAC - -config PMAC_RACKMETER - tristate "Support for Apple XServe front panel LEDs" - depends on PPC_PMAC - help - This driver provides some support to control the front panel - blue LEDs "vu-meter" of the XServer macs. - -config SENSORS_AMS - tristate "Apple Motion Sensor driver" - depends on PPC_PMAC && !PPC64 && INPUT && ((ADB_PMU && I2C = y) || (ADB_PMU && !I2C) || I2C) - select INPUT_POLLDEV - help - Support for the motion sensor included in PowerBooks. Includes - implementations for PMU and I2C. - - This driver can also be built as a module. If so, the module - will be called ams. - -config SENSORS_AMS_PMU - bool "PMU variant" - depends on SENSORS_AMS && ADB_PMU - default y - help - PMU variant of motion sensor, found in late 2005 PowerBooks. - -config SENSORS_AMS_I2C - bool "I2C variant" - depends on SENSORS_AMS && I2C - default y - help - I2C variant of motion sensor, found in early 2005 PowerBooks and - iBooks. - -endif # MACINTOSH_DRIVERS diff --git a/src/linux/drivers/macintosh/Makefile b/src/linux/drivers/macintosh/Makefile deleted file mode 100644 index 383ba92..0000000 --- a/src/linux/drivers/macintosh/Makefile +++ /dev/null @@ -1,66 +0,0 @@ -# -# Makefile for the Macintosh-specific device drivers. -# - -# Each configuration option enables a list of files. - -obj-$(CONFIG_PPC_PMAC) += macio_asic.o macio_sysfs.o - -obj-$(CONFIG_PMAC_MEDIABAY) += mediabay.o -obj-$(CONFIG_MAC_EMUMOUSEBTN) += mac_hid.o -obj-$(CONFIG_INPUT_ADBHID) += adbhid.o -obj-$(CONFIG_ANSLCD) += ans-lcd.o - -obj-$(CONFIG_ADB_PMU) += via-pmu.o via-pmu-event.o -obj-$(CONFIG_ADB_PMU_LED) += via-pmu-led.o -obj-$(CONFIG_PMAC_BACKLIGHT) += via-pmu-backlight.o -obj-$(CONFIG_ADB_CUDA) += via-cuda.o -obj-$(CONFIG_PMAC_APM_EMU) += apm_emu.o -obj-$(CONFIG_PMAC_SMU) += smu.o - -obj-$(CONFIG_ADB) += adb.o -obj-$(CONFIG_ADB_MACII) += via-macii.o -obj-$(CONFIG_ADB_MACIISI) += via-maciisi.o -obj-$(CONFIG_ADB_IOP) += adb-iop.o -obj-$(CONFIG_ADB_PMU68K) += via-pmu68k.o -obj-$(CONFIG_ADB_MACIO) += macio-adb.o - -obj-$(CONFIG_THERM_WINDTUNNEL) += therm_windtunnel.o -obj-$(CONFIG_THERM_ADT746X) += therm_adt746x.o -obj-$(CONFIG_WINDFARM) += windfarm_core.o -obj-$(CONFIG_WINDFARM_PM72) += windfarm_fcu_controls.o \ - windfarm_ad7417_sensor.o \ - windfarm_lm75_sensor.o \ - windfarm_max6690_sensor.o \ - windfarm_pid.o \ - windfarm_cpufreq_clamp.o \ - windfarm_pm72.o -obj-$(CONFIG_WINDFARM_RM31) += windfarm_fcu_controls.o \ - windfarm_ad7417_sensor.o \ - windfarm_lm75_sensor.o \ - windfarm_lm87_sensor.o \ - windfarm_max6690_sensor.o \ - windfarm_pid.o \ - windfarm_cpufreq_clamp.o \ - windfarm_rm31.o -obj-$(CONFIG_WINDFARM_PM81) += windfarm_smu_controls.o \ - windfarm_smu_sensors.o \ - windfarm_lm75_sensor.o windfarm_pid.o \ - windfarm_cpufreq_clamp.o windfarm_pm81.o -obj-$(CONFIG_WINDFARM_PM91) += windfarm_smu_controls.o \ - windfarm_smu_sensors.o \ - windfarm_lm75_sensor.o windfarm_pid.o \ - windfarm_cpufreq_clamp.o windfarm_pm91.o -obj-$(CONFIG_WINDFARM_PM112) += windfarm_pm112.o windfarm_smu_sat.o \ - windfarm_smu_controls.o \ - windfarm_smu_sensors.o \ - windfarm_max6690_sensor.o \ - windfarm_lm75_sensor.o windfarm_pid.o -obj-$(CONFIG_WINDFARM_PM121) += windfarm_pm121.o windfarm_smu_sat.o \ - windfarm_smu_controls.o \ - windfarm_smu_sensors.o \ - windfarm_max6690_sensor.o \ - windfarm_lm75_sensor.o windfarm_pid.o -obj-$(CONFIG_PMAC_RACKMETER) += rack-meter.o - -obj-$(CONFIG_SENSORS_AMS) += ams/ diff --git a/src/linux/drivers/mailbox/Kconfig b/src/linux/drivers/mailbox/Kconfig deleted file mode 100644 index 11eebfe..0000000 --- a/src/linux/drivers/mailbox/Kconfig +++ /dev/null @@ -1,146 +0,0 @@ -menuconfig MAILBOX - bool "Mailbox Hardware Support" - help - Mailbox is a framework to control hardware communication between - on-chip processors through queued messages and interrupt driven - signals. Say Y if your platform supports hardware mailboxes. - -if MAILBOX - -config ARM_MHU - tristate "ARM MHU Mailbox" - depends on ARM_AMBA - help - Say Y here if you want to build the ARM MHU controller driver. - The controller has 3 mailbox channels, the last of which can be - used in Secure mode only. - -config PLATFORM_MHU - tristate "Platform MHU Mailbox" - depends on OF - depends on HAS_IOMEM - help - Say Y here if you want to build a platform specific variant MHU - controller driver. - The controller has a maximum of 3 mailbox channels, the last of - which can be used in Secure mode only. - -config PL320_MBOX - bool "ARM PL320 Mailbox" - depends on ARM_AMBA - help - An implementation of the ARM PL320 Interprocessor Communication - Mailbox (IPCM), tailored for the Calxeda Highbank. It is used to - send short messages between Highbank's A9 cores and the EnergyCore - Management Engine, primarily for cpufreq. Say Y here if you want - to use the PL320 IPCM support. - -config OMAP2PLUS_MBOX - tristate "OMAP2+ Mailbox framework support" - depends on ARCH_OMAP2PLUS - help - Mailbox implementation for OMAP family chips with hardware for - interprocessor communication involving DSP, IVA1.0 and IVA2 in - OMAP2/3; or IPU, IVA HD and DSP in OMAP4/5. Say Y here if you - want to use OMAP2+ Mailbox framework support. - -config OMAP_MBOX_KFIFO_SIZE - int "Mailbox kfifo default buffer size (bytes)" - depends on OMAP2PLUS_MBOX - default 256 - help - Specify the default size of mailbox's kfifo buffers (bytes). - This can also be changed at runtime (via the mbox_kfifo_size - module parameter). - -config ROCKCHIP_MBOX - bool "Rockchip Soc Intergrated Mailbox Support" - depends on ARCH_ROCKCHIP || COMPILE_TEST - help - This driver provides support for inter-processor communication - between CPU cores and MCU processor on Some Rockchip SOCs. - Please check it that the Soc you use have Mailbox hardware. - Say Y here if you want to use the Rockchip Mailbox support. - -config PCC - bool "Platform Communication Channel Driver" - depends on ACPI - default n - help - ACPI 5.0+ spec defines a generic mode of communication - between the OS and a platform such as the BMC. This medium - (PCC) is typically used by CPPC (ACPI CPU Performance management), - RAS (ACPI reliability protocol) and MPST (ACPI Memory power - states). Select this driver if your platform implements the - PCC clients mentioned above. - -config ALTERA_MBOX - tristate "Altera Mailbox" - depends on HAS_IOMEM - help - An implementation of the Altera Mailbox soft core. It is used - to send message between processors. Say Y here if you want to use the - Altera mailbox support. - -config BCM2835_MBOX - tristate "BCM2835 Mailbox" - depends on ARCH_BCM2835 - help - An implementation of the BCM2385 Mailbox. It is used to invoke - the services of the Videocore. Say Y here if you want to use the - BCM2835 Mailbox. - -config STI_MBOX - tristate "STI Mailbox framework support" - depends on ARCH_STI && OF - help - Mailbox implementation for STMicroelectonics family chips with - hardware for interprocessor communication. - -config TI_MESSAGE_MANAGER - tristate "Texas Instruments Message Manager Driver" - depends on ARCH_KEYSTONE - help - An implementation of Message Manager slave driver for Keystone - architecture SoCs from Texas Instruments. Message Manager is a - communication entity found on few of Texas Instrument's keystone - architecture SoCs. These may be used for communication between - multiple processors within the SoC. Select this driver if your - platform has support for the hardware block. - -config HI6220_MBOX - tristate "Hi6220 Mailbox" - depends on ARCH_HISI - help - An implementation of the hi6220 mailbox. It is used to send message - between application processors and MCU. Say Y here if you want to - build Hi6220 mailbox controller driver. - -config MAILBOX_TEST - tristate "Mailbox Test Client" - depends on OF - depends on HAS_IOMEM - help - Test client to help with testing new Controller driver - implementations. - -config XGENE_SLIMPRO_MBOX - tristate "APM SoC X-Gene SLIMpro Mailbox Controller" - depends on ARCH_XGENE - help - An implementation of the APM X-Gene Interprocessor Communication - Mailbox (IPCM) between the ARM 64-bit cores and SLIMpro controller. - It is used to send short messages between ARM64-bit cores and - the SLIMpro Management Engine, primarily for PM. Say Y here if you - want to use the APM X-Gene SLIMpro IPCM support. - -config BCM_PDC_MBOX - tristate "Broadcom PDC Mailbox" - depends on ARM64 || COMPILE_TEST - depends on HAS_DMA - default ARCH_BCM_IPROC - help - Mailbox implementation for the Broadcom PDC ring manager, - which provides access to various offload engines on Broadcom - SoCs. Say Y here if you want to use the Broadcom PDC. -endif diff --git a/src/linux/drivers/mcb/Kconfig b/src/linux/drivers/mcb/Kconfig deleted file mode 100644 index 76d9c51..0000000 --- a/src/linux/drivers/mcb/Kconfig +++ /dev/null @@ -1,40 +0,0 @@ -# -# MEN Chameleon Bus (MCB) support -# - -menuconfig MCB - tristate "MCB support" - default n - depends on HAS_IOMEM - help - - The MCB (MEN Chameleon Bus) is a Bus specific to MEN Mikroelektronik - FPGA based devices. It is used to identify MCB based IP-Cores within - an FPGA and provide the necessary framework for instantiating drivers - for these devices. - - If build as a module, the module is called mcb.ko - -if MCB -config MCB_PCI - tristate "PCI based MCB carrier" - default n - depends on PCI - help - - This is a MCB carrier on a PCI device. Both PCI attached on-board - FPGAs as well as CompactPCI attached MCB FPGAs are supported with - this driver. - - If build as a module, the module is called mcb-pci.ko - -config MCB_LPC - tristate "LPC (non PCI) based MCB carrier" - default n - help - - This is a MCB carrier on a LPC or non PCI device. - - If build as a module, the module is called mcb-lpc.ko - -endif # MCB diff --git a/src/linux/drivers/md/Kconfig b/src/linux/drivers/md/Kconfig deleted file mode 100644 index 02a5345..0000000 --- a/src/linux/drivers/md/Kconfig +++ /dev/null @@ -1,503 +0,0 @@ -# -# Block device driver configuration -# - -menuconfig MD - bool "Multiple devices driver support (RAID and LVM)" - depends on BLOCK - select SRCU - help - Support multiple physical spindles through a single logical device. - Required for RAID and logical volume management. - -if MD - -config BLK_DEV_MD - tristate "RAID support" - ---help--- - This driver lets you combine several hard disk partitions into one - logical block device. This can be used to simply append one - partition to another one or to combine several redundant hard disks - into a RAID1/4/5 device so as to provide protection against hard - disk failures. This is called "Software RAID" since the combining of - the partitions is done by the kernel. "Hardware RAID" means that the - combining is done by a dedicated controller; if you have such a - controller, you do not need to say Y here. - - More information about Software RAID on Linux is contained in the - Software RAID mini-HOWTO, available from - . There you will also learn - where to get the supporting user space utilities raidtools. - - If unsure, say N. - -config MD_AUTODETECT - bool "Autodetect RAID arrays during kernel boot" - depends on BLK_DEV_MD=y - default y - ---help--- - If you say Y here, then the kernel will try to autodetect raid - arrays as part of its boot process. - - If you don't use raid and say Y, this autodetection can cause - a several-second delay in the boot time due to various - synchronisation steps that are part of this step. - - If unsure, say Y. - -config MD_LINEAR - tristate "Linear (append) mode" - depends on BLK_DEV_MD - ---help--- - If you say Y here, then your multiple devices driver will be able to - use the so-called linear mode, i.e. it will combine the hard disk - partitions by simply appending one to the other. - - To compile this as a module, choose M here: the module - will be called linear. - - If unsure, say Y. - -config MD_RAID0 - tristate "RAID-0 (striping) mode" - depends on BLK_DEV_MD - ---help--- - If you say Y here, then your multiple devices driver will be able to - use the so-called raid0 mode, i.e. it will combine the hard disk - partitions into one logical device in such a fashion as to fill them - up evenly, one chunk here and one chunk there. This will increase - the throughput rate if the partitions reside on distinct disks. - - Information about Software RAID on Linux is contained in the - Software-RAID mini-HOWTO, available from - . There you will also - learn where to get the supporting user space utilities raidtools. - - To compile this as a module, choose M here: the module - will be called raid0. - - If unsure, say Y. - -config MD_RAID1 - tristate "RAID-1 (mirroring) mode" - depends on BLK_DEV_MD - ---help--- - A RAID-1 set consists of several disk drives which are exact copies - of each other. In the event of a mirror failure, the RAID driver - will continue to use the operational mirrors in the set, providing - an error free MD (multiple device) to the higher levels of the - kernel. In a set with N drives, the available space is the capacity - of a single drive, and the set protects against a failure of (N - 1) - drives. - - Information about Software RAID on Linux is contained in the - Software-RAID mini-HOWTO, available from - . There you will also - learn where to get the supporting user space utilities raidtools. - - If you want to use such a RAID-1 set, say Y. To compile this code - as a module, choose M here: the module will be called raid1. - - If unsure, say Y. - -config MD_RAID10 - tristate "RAID-10 (mirrored striping) mode" - depends on BLK_DEV_MD - ---help--- - RAID-10 provides a combination of striping (RAID-0) and - mirroring (RAID-1) with easier configuration and more flexible - layout. - Unlike RAID-0, but like RAID-1, RAID-10 requires all devices to - be the same size (or at least, only as much as the smallest device - will be used). - RAID-10 provides a variety of layouts that provide different levels - of redundancy and performance. - - RAID-10 requires mdadm-1.7.0 or later, available at: - - ftp://ftp.kernel.org/pub/linux/utils/raid/mdadm/ - - If unsure, say Y. - -config MD_RAID456 - tristate "RAID-4/RAID-5/RAID-6 mode" - depends on BLK_DEV_MD - select RAID6_PQ - select LIBCRC32C - select ASYNC_MEMCPY - select ASYNC_XOR - select ASYNC_PQ - select ASYNC_RAID6_RECOV - ---help--- - A RAID-5 set of N drives with a capacity of C MB per drive provides - the capacity of C * (N - 1) MB, and protects against a failure - of a single drive. For a given sector (row) number, (N - 1) drives - contain data sectors, and one drive contains the parity protection. - For a RAID-4 set, the parity blocks are present on a single drive, - while a RAID-5 set distributes the parity across the drives in one - of the available parity distribution methods. - - A RAID-6 set of N drives with a capacity of C MB per drive - provides the capacity of C * (N - 2) MB, and protects - against a failure of any two drives. For a given sector - (row) number, (N - 2) drives contain data sectors, and two - drives contains two independent redundancy syndromes. Like - RAID-5, RAID-6 distributes the syndromes across the drives - in one of the available parity distribution methods. - - Information about Software RAID on Linux is contained in the - Software-RAID mini-HOWTO, available from - . There you will also - learn where to get the supporting user space utilities raidtools. - - If you want to use such a RAID-4/RAID-5/RAID-6 set, say Y. To - compile this code as a module, choose M here: the module - will be called raid456. - - If unsure, say Y. - -config MD_MULTIPATH - tristate "Multipath I/O support" - depends on BLK_DEV_MD - help - MD_MULTIPATH provides a simple multi-path personality for use - the MD framework. It is not under active development. New - projects should consider using DM_MULTIPATH which has more - features and more testing. - - If unsure, say N. - -config MD_FAULTY - tristate "Faulty test module for MD" - depends on BLK_DEV_MD - help - The "faulty" module allows for a block device that occasionally returns - read or write errors. It is useful for testing. - - In unsure, say N. - - -config MD_CLUSTER - tristate "Cluster Support for MD (EXPERIMENTAL)" - depends on BLK_DEV_MD - depends on DLM - default n - ---help--- - Clustering support for MD devices. This enables locking and - synchronization across multiple systems on the cluster, so all - nodes in the cluster can access the MD devices simultaneously. - - This brings the redundancy (and uptime) of RAID levels across the - nodes of the cluster. - - If unsure, say N. - -source "drivers/md/bcache/Kconfig" - -config BLK_DEV_DM_BUILTIN - bool - -config BLK_DEV_DM - tristate "Device mapper support" - select BLK_DEV_DM_BUILTIN - ---help--- - Device-mapper is a low level volume manager. It works by allowing - people to specify mappings for ranges of logical sectors. Various - mapping types are available, in addition people may write their own - modules containing custom mappings if they wish. - - Higher level volume managers such as LVM2 use this driver. - - To compile this as a module, choose M here: the module will be - called dm-mod. - - If unsure, say N. - -config DM_MQ_DEFAULT - bool "request-based DM: use blk-mq I/O path by default" - depends on BLK_DEV_DM - ---help--- - This option enables the blk-mq based I/O path for request-based - DM devices by default. With the option the dm_mod.use_blk_mq - module/boot option defaults to Y, without it to N, but it can - still be overriden either way. - - If unsure say N. - -config DM_DEBUG - bool "Device mapper debugging support" - depends on BLK_DEV_DM - ---help--- - Enable this for messages that may help debug device-mapper problems. - - If unsure, say N. - -config DM_BUFIO - tristate - depends on BLK_DEV_DM - ---help--- - This interface allows you to do buffered I/O on a device and acts - as a cache, holding recently-read blocks in memory and performing - delayed writes. - -config DM_DEBUG_BLOCK_STACK_TRACING - bool "Keep stack trace of persistent data block lock holders" - depends on STACKTRACE_SUPPORT && DM_BUFIO - select STACKTRACE - ---help--- - Enable this for messages that may help debug problems with the - block manager locking used by thin provisioning and caching. - - If unsure, say N. - -config DM_BIO_PRISON - tristate - depends on BLK_DEV_DM - ---help--- - Some bio locking schemes used by other device-mapper targets - including thin provisioning. - -source "drivers/md/persistent-data/Kconfig" - -config DM_CRYPT - tristate "Crypt target support" - depends on BLK_DEV_DM - select CRYPTO - select CRYPTO_CBC - ---help--- - This device-mapper target allows you to create a device that - transparently encrypts the data on it. You'll need to activate - the ciphers you're going to use in the cryptoapi configuration. - - For further information on dm-crypt and userspace tools see: - - - To compile this code as a module, choose M here: the module will - be called dm-crypt. - - If unsure, say N. - -config DM_SNAPSHOT - tristate "Snapshot target" - depends on BLK_DEV_DM - select DM_BUFIO - ---help--- - Allow volume managers to take writable snapshots of a device. - -config DM_THIN_PROVISIONING - tristate "Thin provisioning target" - depends on BLK_DEV_DM - select DM_PERSISTENT_DATA - select DM_BIO_PRISON - ---help--- - Provides thin provisioning and snapshots that share a data store. - -config DM_CACHE - tristate "Cache target (EXPERIMENTAL)" - depends on BLK_DEV_DM - default n - select DM_PERSISTENT_DATA - select DM_BIO_PRISON - ---help--- - dm-cache attempts to improve performance of a block device by - moving frequently used data to a smaller, higher performance - device. Different 'policy' plugins can be used to change the - algorithms used to select which blocks are promoted, demoted, - cleaned etc. It supports writeback and writethrough modes. - -config DM_CACHE_SMQ - tristate "Stochastic MQ Cache Policy (EXPERIMENTAL)" - depends on DM_CACHE - default y - ---help--- - A cache policy that uses a multiqueue ordered by recent hits - to select which blocks should be promoted and demoted. - This is meant to be a general purpose policy. It prioritises - reads over writes. This SMQ policy (vs MQ) offers the promise - of less memory utilization, improved performance and increased - adaptability in the face of changing workloads. - -config DM_CACHE_CLEANER - tristate "Cleaner Cache Policy (EXPERIMENTAL)" - depends on DM_CACHE - default y - ---help--- - A simple cache policy that writes back all data to the - origin. Used when decommissioning a dm-cache. - -config DM_ERA - tristate "Era target (EXPERIMENTAL)" - depends on BLK_DEV_DM - default n - select DM_PERSISTENT_DATA - select DM_BIO_PRISON - ---help--- - dm-era tracks which parts of a block device are written to - over time. Useful for maintaining cache coherency when using - vendor snapshots. - -config DM_MIRROR - tristate "Mirror target" - depends on BLK_DEV_DM - ---help--- - Allow volume managers to mirror logical volumes, also - needed for live data migration tools such as 'pvmove'. - -config DM_LOG_USERSPACE - tristate "Mirror userspace logging" - depends on DM_MIRROR && NET - select CONNECTOR - ---help--- - The userspace logging module provides a mechanism for - relaying the dm-dirty-log API to userspace. Log designs - which are more suited to userspace implementation (e.g. - shared storage logs) or experimental logs can be implemented - by leveraging this framework. - -config DM_RAID - tristate "RAID 1/4/5/6/10 target" - depends on BLK_DEV_DM - select MD_RAID1 - select MD_RAID10 - select MD_RAID456 - select BLK_DEV_MD - ---help--- - A dm target that supports RAID1, RAID10, RAID4, RAID5 and RAID6 mappings - - A RAID-5 set of N drives with a capacity of C MB per drive provides - the capacity of C * (N - 1) MB, and protects against a failure - of a single drive. For a given sector (row) number, (N - 1) drives - contain data sectors, and one drive contains the parity protection. - For a RAID-4 set, the parity blocks are present on a single drive, - while a RAID-5 set distributes the parity across the drives in one - of the available parity distribution methods. - - A RAID-6 set of N drives with a capacity of C MB per drive - provides the capacity of C * (N - 2) MB, and protects - against a failure of any two drives. For a given sector - (row) number, (N - 2) drives contain data sectors, and two - drives contains two independent redundancy syndromes. Like - RAID-5, RAID-6 distributes the syndromes across the drives - in one of the available parity distribution methods. - -config DM_ZERO - tristate "Zero target" - depends on BLK_DEV_DM - ---help--- - A target that discards writes, and returns all zeroes for - reads. Useful in some recovery situations. - -config DM_MULTIPATH - tristate "Multipath target" - depends on BLK_DEV_DM - # nasty syntax but means make DM_MULTIPATH independent - # of SCSI_DH if the latter isn't defined but if - # it is, DM_MULTIPATH must depend on it. We get a build - # error if SCSI_DH=m and DM_MULTIPATH=y - depends on !SCSI_DH || SCSI - ---help--- - Allow volume managers to support multipath hardware. - -config DM_MULTIPATH_QL - tristate "I/O Path Selector based on the number of in-flight I/Os" - depends on DM_MULTIPATH - ---help--- - This path selector is a dynamic load balancer which selects - the path with the least number of in-flight I/Os. - - If unsure, say N. - -config DM_MULTIPATH_ST - tristate "I/O Path Selector based on the service time" - depends on DM_MULTIPATH - ---help--- - This path selector is a dynamic load balancer which selects - the path expected to complete the incoming I/O in the shortest - time. - - If unsure, say N. - -config DM_DELAY - tristate "I/O delaying target" - depends on BLK_DEV_DM - ---help--- - A target that delays reads and/or writes and can send - them to different devices. Useful for testing. - - If unsure, say N. - -config DM_UEVENT - bool "DM uevents" - depends on BLK_DEV_DM - ---help--- - Generate udev events for DM events. - -config DM_FLAKEY - tristate "Flakey target" - depends on BLK_DEV_DM - ---help--- - A target that intermittently fails I/O for debugging purposes. - -config DM_VERITY - tristate "Verity target support" - depends on BLK_DEV_DM - select CRYPTO - select CRYPTO_HASH - select DM_BUFIO - ---help--- - This device-mapper target creates a read-only device that - transparently validates the data on one underlying device against - a pre-generated tree of cryptographic checksums stored on a second - device. - - You'll need to activate the digests you're going to use in the - cryptoapi configuration. - - To compile this code as a module, choose M here: the module will - be called dm-verity. - - If unsure, say N. - -config DM_VERITY_FEC - bool "Verity forward error correction support" - depends on DM_VERITY - select REED_SOLOMON - select REED_SOLOMON_DEC8 - ---help--- - Add forward error correction support to dm-verity. This option - makes it possible to use pre-generated error correction data to - recover from corrupted blocks. - - If unsure, say N. - -config DM_SWITCH - tristate "Switch target support (EXPERIMENTAL)" - depends on BLK_DEV_DM - ---help--- - This device-mapper target creates a device that supports an arbitrary - mapping of fixed-size regions of I/O across a fixed set of paths. - The path used for any specific region can be switched dynamically - by sending the target a message. - - To compile this code as a module, choose M here: the module will - be called dm-switch. - - If unsure, say N. - -config DM_LOG_WRITES - tristate "Log writes target support" - depends on BLK_DEV_DM - ---help--- - This device-mapper target takes two devices, one device to use - normally, one to log all write operations done to the first device. - This is for use by file system developers wishing to verify that - their fs is writing a consistent file system at all times by allowing - them to replay the log in a variety of ways and to check the - contents. - - To compile this code as a module, choose M here: the module will - be called dm-log-writes. - - If unsure, say N. - -endif # MD diff --git a/src/linux/drivers/md/bcache/Kconfig b/src/linux/drivers/md/bcache/Kconfig deleted file mode 100644 index 4d20088..0000000 --- a/src/linux/drivers/md/bcache/Kconfig +++ /dev/null @@ -1,26 +0,0 @@ - -config BCACHE - tristate "Block device as cache" - ---help--- - Allows a block device to be used as cache for other devices; uses - a btree for indexing and the layout is optimized for SSDs. - - See Documentation/bcache.txt for details. - -config BCACHE_DEBUG - bool "Bcache debugging" - depends on BCACHE - ---help--- - Don't select this option unless you're a developer - - Enables extra debugging tools, allows expensive runtime checks to be - turned on. - -config BCACHE_CLOSURES_DEBUG - bool "Debug closures" - depends on BCACHE - select DEBUG_FS - ---help--- - Keeps all active closures in a linked list and provides a debugfs - interface to list them, which makes it possible to see asynchronous - operations that get stuck. diff --git a/src/linux/drivers/md/persistent-data/Kconfig b/src/linux/drivers/md/persistent-data/Kconfig deleted file mode 100644 index a53cbc9..0000000 --- a/src/linux/drivers/md/persistent-data/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config DM_PERSISTENT_DATA - tristate - depends on BLK_DEV_DM - select LIBCRC32C - select DM_BUFIO - ---help--- - Library providing immutable on-disk data structure support for - device-mapper targets such as the thin provisioning target. - diff --git a/src/linux/drivers/media/Kconfig b/src/linux/drivers/media/Kconfig deleted file mode 100644 index 7b85402..0000000 --- a/src/linux/drivers/media/Kconfig +++ /dev/null @@ -1,223 +0,0 @@ -# -# Multimedia device configuration -# - -menuconfig MEDIA_SUPPORT - tristate "Multimedia support" - depends on HAS_IOMEM - help - If you want to use Webcams, Video grabber devices and/or TV devices - enable this option and other options below. - Additional info and docs are available on the web at - - -if MEDIA_SUPPORT - -comment "Multimedia core support" - -# -# Multimedia support - automatically enable V4L2 and DVB core -# -config MEDIA_CAMERA_SUPPORT - bool "Cameras/video grabbers support" - ---help--- - Enable support for webcams and video grabbers. - - Say Y when you have a webcam or a video capture grabber board. - -config MEDIA_ANALOG_TV_SUPPORT - bool "Analog TV support" - ---help--- - Enable analog TV support. - - Say Y when you have a TV board with analog support or with a - hybrid analog/digital TV chipset. - - Note: There are several DVB cards that are based on chips that - support both analog and digital TV. Disabling this option - will disable support for them. - -config MEDIA_DIGITAL_TV_SUPPORT - bool "Digital TV support" - ---help--- - Enable digital TV support. - - Say Y when you have a board with digital support or a board with - hybrid digital TV and analog TV. - -config MEDIA_RADIO_SUPPORT - bool "AM/FM radio receivers/transmitters support" - ---help--- - Enable AM/FM radio support. - - Additional info and docs are available on the web at - - - Say Y when you have a board with radio support. - - Note: There are several TV cards that are based on chips that - support radio reception. Disabling this option will - disable support for them. - -config MEDIA_SDR_SUPPORT - bool "Software defined radio support" - ---help--- - Enable software defined radio support. - - Say Y when you have a software defined radio device. - -config MEDIA_RC_SUPPORT - bool "Remote Controller support" - depends on INPUT - ---help--- - Enable support for Remote Controllers on Linux. This is - needed in order to support several video capture adapters, - standalone IR receivers/transmitters, and RF receivers. - - Enable this option if you have a video capture board even - if you don't need IR, as otherwise, you may not be able to - compile the driver for your adapter. - - Say Y when you have a TV or an IR device. - -config MEDIA_CEC_EDID - bool - -# -# Media controller -# Selectable only for webcam/grabbers, as other drivers don't use it -# - -config MEDIA_CONTROLLER - bool "Media Controller API" - depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT - ---help--- - Enable the media controller API used to query media devices internal - topology and configure it dynamically. - - This API is mostly used by camera interfaces in embedded platforms. - -config MEDIA_CONTROLLER_DVB - bool "Enable Media controller for DVB (EXPERIMENTAL)" - depends on MEDIA_CONTROLLER - ---help--- - Enable the media controller API support for DVB. - - This is currently experimental. - -# -# Video4Linux support -# Only enables if one of the V4L2 types (ATV, webcam, radio) is selected -# - -config VIDEO_DEV - tristate - depends on MEDIA_SUPPORT - depends on MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT - default y - -config VIDEO_V4L2_SUBDEV_API - bool "V4L2 sub-device userspace API" - depends on VIDEO_DEV && MEDIA_CONTROLLER - ---help--- - Enables the V4L2 sub-device pad-level userspace API used to configure - video format, size and frame rate between hardware blocks. - - This API is mostly used by camera interfaces in embedded platforms. - -source "drivers/media/v4l2-core/Kconfig" - -# -# DVB Core -# Only enables if one of DTV is selected -# - -config DVB_CORE - tristate - depends on MEDIA_SUPPORT - depends on MEDIA_DIGITAL_TV_SUPPORT - default y - select CRC32 - -config DVB_NET - bool "DVB Network Support" - default (NET && INET) - depends on NET && INET && DVB_CORE - help - This option enables DVB Network Support which is a part of the DVB - standard. It is used, for example, by automatic firmware updates used - on Set-Top-Boxes. It can also be used to access the Internet via the - DVB card, if the network provider supports it. - - You may want to disable the network support on embedded devices. If - unsure say Y. - -# This Kconfig option is used by both PCI and USB drivers -config TTPCI_EEPROM - tristate - depends on I2C - default n - -source "drivers/media/dvb-core/Kconfig" - -comment "Media drivers" -source "drivers/media/rc/Kconfig" - -# -# V4L platform/mem2mem drivers -# - -source "drivers/media/usb/Kconfig" -source "drivers/media/pci/Kconfig" -source "drivers/media/platform/Kconfig" -source "drivers/media/mmc/Kconfig" -source "drivers/media/radio/Kconfig" - -comment "Supported FireWire (IEEE 1394) Adapters" - depends on DVB_CORE && FIREWIRE -source "drivers/media/firewire/Kconfig" - -# Common driver options -source "drivers/media/common/Kconfig" - -comment "Media ancillary drivers (tuners, sensors, i2c, spi, frontends)" - -# -# Ancillary drivers (tuners, i2c, spi, frontends) -# - -config MEDIA_SUBDRV_AUTOSELECT - bool "Autoselect ancillary drivers (tuners, sensors, i2c, spi, frontends)" - depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_CAMERA_SUPPORT || MEDIA_SDR_SUPPORT - depends on HAS_IOMEM - select I2C - select I2C_MUX - default y - help - By default, a media driver auto-selects all possible ancillary - devices such as tuners, sensors, video encoders/decoders and - frontends, that are used by any of the supported devices. - - This is generally the right thing to do, except when there - are strict constraints with regards to the kernel size, - like on embedded systems. - - Use this option with care, as deselecting ancillary drivers which - are, in fact, necessary will result in the lack of the needed - functionality for your device (it may not tune or may not have - the needed demodulators). - - If unsure say Y. - -config MEDIA_ATTACH - bool - depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT - depends on MODULES - default MODULES - -source "drivers/media/i2c/Kconfig" -source "drivers/media/spi/Kconfig" -source "drivers/media/tuners/Kconfig" -source "drivers/media/dvb-frontends/Kconfig" - -endif # MEDIA_SUPPORT diff --git a/src/linux/drivers/media/Makefile b/src/linux/drivers/media/Makefile deleted file mode 100644 index 0deaa93..0000000 --- a/src/linux/drivers/media/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -# -# Makefile for the kernel multimedia device drivers. -# - -ifeq ($(CONFIG_MEDIA_CEC_EDID),y) - obj-$(CONFIG_MEDIA_SUPPORT) += cec-edid.o -endif - -media-objs := media-device.o media-devnode.o media-entity.o - -# -# I2C drivers should come before other drivers, otherwise they'll fail -# when compiled as builtin drivers -# -obj-y += i2c/ tuners/ -obj-$(CONFIG_DVB_CORE) += dvb-frontends/ - -# -# Now, let's link-in the media core -# -ifeq ($(CONFIG_MEDIA_CONTROLLER),y) - obj-$(CONFIG_MEDIA_SUPPORT) += media.o -endif - -obj-$(CONFIG_VIDEO_DEV) += v4l2-core/ -obj-$(CONFIG_DVB_CORE) += dvb-core/ - -# There are both core and drivers at RC subtree - merge before drivers -obj-y += rc/ - -# -# Finally, merge the drivers that require the core -# - -obj-y += common/ platform/ pci/ usb/ mmc/ firewire/ spi/ -obj-$(CONFIG_VIDEO_DEV) += radio/ - diff --git a/src/linux/drivers/media/common/Kconfig b/src/linux/drivers/media/common/Kconfig deleted file mode 100644 index 326df0a..0000000 --- a/src/linux/drivers/media/common/Kconfig +++ /dev/null @@ -1,22 +0,0 @@ -# Used by common drivers, when they need to ask questions -config MEDIA_COMMON_OPTIONS - bool - -comment "common driver options" - depends on MEDIA_COMMON_OPTIONS - -config VIDEO_CX2341X - tristate - -config VIDEO_TVEEPROM - tristate - depends on I2C - -config CYPRESS_FIRMWARE - tristate "Cypress firmware helper routines" - depends on USB - -source "drivers/media/common/b2c2/Kconfig" -source "drivers/media/common/saa7146/Kconfig" -source "drivers/media/common/siano/Kconfig" -source "drivers/media/common/v4l2-tpg/Kconfig" diff --git a/src/linux/drivers/media/common/Makefile b/src/linux/drivers/media/common/Makefile deleted file mode 100644 index 2d1b0a0..0000000 --- a/src/linux/drivers/media/common/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -obj-y += b2c2/ saa7146/ siano/ v4l2-tpg/ -obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o -obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o -obj-$(CONFIG_CYPRESS_FIRMWARE) += cypress_firmware.o diff --git a/src/linux/drivers/media/common/b2c2/Kconfig b/src/linux/drivers/media/common/b2c2/Kconfig deleted file mode 100644 index e593638..0000000 --- a/src/linux/drivers/media/common/b2c2/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -config DVB_B2C2_FLEXCOP - tristate - depends on DVB_CORE && I2C - depends on DVB_B2C2_FLEXCOP_PCI || DVB_B2C2_FLEXCOP_USB - default y - select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT - select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT - select DVB_MT312 if MEDIA_SUBDRV_AUTOSELECT - select DVB_NXT200X if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT - select DVB_BCM3510 if MEDIA_SUBDRV_AUTOSELECT - select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT - select DVB_S5H1420 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TUNER_ITD1000 if MEDIA_SUBDRV_AUTOSELECT - select DVB_ISL6421 if MEDIA_SUBDRV_AUTOSELECT - select DVB_CX24120 if MEDIA_SUBDRV_AUTOSELECT - select DVB_CX24123 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT - select DVB_TUNER_CX24113 if MEDIA_SUBDRV_AUTOSELECT - -# Selected via the PCI or USB flexcop drivers -config DVB_B2C2_FLEXCOP_DEBUG - bool diff --git a/src/linux/drivers/media/common/b2c2/Makefile b/src/linux/drivers/media/common/b2c2/Makefile deleted file mode 100644 index 24993a5..0000000 --- a/src/linux/drivers/media/common/b2c2/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -b2c2-flexcop-objs += flexcop.o flexcop-fe-tuner.o flexcop-i2c.o -b2c2-flexcop-objs += flexcop-sram.o flexcop-eeprom.o flexcop-misc.o -b2c2-flexcop-objs += flexcop-hw-filter.o -obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o - -ccflags-y += -Idrivers/media/dvb-core/ -ccflags-y += -Idrivers/media/dvb-frontends/ -ccflags-y += -Idrivers/media/tuners/ diff --git a/src/linux/drivers/media/common/saa7146/Kconfig b/src/linux/drivers/media/common/saa7146/Kconfig deleted file mode 100644 index 769c6f8..0000000 --- a/src/linux/drivers/media/common/saa7146/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config VIDEO_SAA7146 - tristate - depends on I2C && PCI - -config VIDEO_SAA7146_VV - tristate - depends on VIDEO_V4L2 - select VIDEOBUF_DMA_SG - select VIDEO_SAA7146 diff --git a/src/linux/drivers/media/common/saa7146/Makefile b/src/linux/drivers/media/common/saa7146/Makefile deleted file mode 100644 index 3219b00..0000000 --- a/src/linux/drivers/media/common/saa7146/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -saa7146-objs := saa7146_i2c.o saa7146_core.o -saa7146_vv-objs := saa7146_fops.o saa7146_video.o saa7146_hlp.o saa7146_vbi.o - -obj-$(CONFIG_VIDEO_SAA7146) += saa7146.o -obj-$(CONFIG_VIDEO_SAA7146_VV) += saa7146_vv.o diff --git a/src/linux/drivers/media/common/siano/Kconfig b/src/linux/drivers/media/common/siano/Kconfig deleted file mode 100644 index 4bfbd5f..0000000 --- a/src/linux/drivers/media/common/siano/Kconfig +++ /dev/null @@ -1,32 +0,0 @@ -# -# Siano Mobile Silicon Digital TV device configuration -# - -config SMS_SIANO_MDTV - tristate - depends on DVB_CORE && HAS_DMA - depends on !RC_CORE || RC_CORE - depends on SMS_USB_DRV || SMS_SDIO_DRV - default y - -config SMS_SIANO_RC - bool "Enable Remote Controller support for Siano devices" - depends on SMS_SIANO_MDTV && RC_CORE - depends on SMS_USB_DRV || SMS_SDIO_DRV - depends on MEDIA_COMMON_OPTIONS - default y - ---help--- - Choose Y to select Remote Controller support for Siano driver. - -config SMS_SIANO_DEBUGFS - bool "Enable debugfs for smsdvb" - depends on SMS_SIANO_MDTV - depends on DEBUG_FS - depends on SMS_USB_DRV = SMS_SDIO_DRV - - ---help--- - Choose Y to enable visualizing a dump of the frontend - statistics response packets via debugfs. Currently, works - only with Siano USB devices. - - Useful only for developers. In doubt, say N. diff --git a/src/linux/drivers/media/common/siano/Makefile b/src/linux/drivers/media/common/siano/Makefile deleted file mode 100644 index 4c0567f..0000000 --- a/src/linux/drivers/media/common/siano/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -smsmdtv-objs := smscoreapi.o sms-cards.o smsendian.o -smsdvb-objs := smsdvb-main.o - -obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o - -ifeq ($(CONFIG_SMS_SIANO_RC),y) - smsmdtv-objs += smsir.o -endif - -ifeq ($(CONFIG_SMS_SIANO_DEBUGFS),y) - smsdvb-objs += smsdvb-debugfs.o -endif - -ccflags-y += -Idrivers/media/dvb-core -ccflags-y += $(extra-cflags-y) $(extra-cflags-m) - diff --git a/src/linux/drivers/media/common/v4l2-tpg/Kconfig b/src/linux/drivers/media/common/v4l2-tpg/Kconfig deleted file mode 100644 index 7456fc1..0000000 --- a/src/linux/drivers/media/common/v4l2-tpg/Kconfig +++ /dev/null @@ -1,2 +0,0 @@ -config VIDEO_V4L2_TPG - tristate diff --git a/src/linux/drivers/media/common/v4l2-tpg/Makefile b/src/linux/drivers/media/common/v4l2-tpg/Makefile deleted file mode 100644 index f588df4..0000000 --- a/src/linux/drivers/media/common/v4l2-tpg/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -v4l2-tpg-objs := v4l2-tpg-core.o v4l2-tpg-colors.o - -obj-$(CONFIG_VIDEO_V4L2_TPG) += v4l2-tpg.o diff --git a/src/linux/drivers/media/dvb-core/Kconfig b/src/linux/drivers/media/dvb-core/Kconfig deleted file mode 100644 index fa7a249..0000000 --- a/src/linux/drivers/media/dvb-core/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -# -# DVB device configuration -# - -config DVB_MAX_ADAPTERS - int "maximum number of DVB/ATSC adapters" - depends on DVB_CORE - default 8 - range 1 255 - help - Maximum number of DVB/ATSC adapters. Increasing this number - increases the memory consumption of the DVB subsystem even - if a much lower number of DVB/ATSC adapters is present. - Only values in the range 4-32 are tested. - - If you are unsure about this, use the default value 8 - -config DVB_DYNAMIC_MINORS - bool "Dynamic DVB minor allocation" - depends on DVB_CORE - default n - help - If you say Y here, the DVB subsystem will use dynamic minor - allocation for any device that uses the DVB major number. - This means that you can have more than 4 of a single type - of device (like demuxes and frontends) per adapter, but udev - will be required to manage the device nodes. - - If you are unsure about this, say N here. diff --git a/src/linux/drivers/media/dvb-frontends/Kconfig b/src/linux/drivers/media/dvb-frontends/Kconfig deleted file mode 100644 index b71b747..0000000 --- a/src/linux/drivers/media/dvb-frontends/Kconfig +++ /dev/null @@ -1,883 +0,0 @@ -menu "Customise DVB Frontends" - visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST - -comment "Multistandard (satellite) frontends" - depends on DVB_CORE - -config DVB_STB0899 - tristate "STB0899 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S/S2/DSS Multistandard demodulator. Say Y when you want - to support this demodulator based frontends - -config DVB_STB6100 - tristate "STB6100 based tuners" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A Silicon tuner from ST used in conjunction with the STB0899 - demodulator. Say Y when you want to support this tuner. - -config DVB_STV090x - tristate "STV0900/STV0903(A/B) based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - DVB-S/S2/DSS Multistandard Professional/Broadcast demodulators. - Say Y when you want to support these frontends. - -config DVB_STV6110x - tristate "STV6110/(A) based tuners" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A Silicon tuner that supports DVB-S and DVB-S2 modes - -config DVB_M88DS3103 - tristate "Montage Technology M88DS3103" - depends on DVB_CORE && I2C && I2C_MUX - select REGMAP_I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y when you want to support this frontend. - -comment "Multistandard (cable + terrestrial) frontends" - depends on DVB_CORE - -config DVB_DRXK - tristate "Micronas DRXK based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Micronas DRX-K DVB-C/T demodulator. - - Say Y when you want to support this frontend. - -config DVB_TDA18271C2DD - tristate "NXP TDA18271C2 silicon tuner" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - NXP TDA18271 silicon tuner. - - Say Y when you want to support this tuner. - -config DVB_SI2165 - tristate "Silicon Labs si2165 based" - depends on DVB_CORE && I2C - select REGMAP_I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-C/T demodulator. - - Say Y when you want to support this frontend. - -config DVB_MN88472 - tristate "Panasonic MN88472" - depends on DVB_CORE && I2C - select REGMAP_I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y when you want to support this frontend. - -config DVB_MN88473 - tristate "Panasonic MN88473" - depends on DVB_CORE && I2C - select REGMAP_I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y when you want to support this frontend. - -comment "DVB-S (satellite) frontends" - depends on DVB_CORE - -config DVB_CX24110 - tristate "Conexant CX24110 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_CX24123 - tristate "Conexant CX24123 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_MT312 - tristate "Zarlink VP310/MT312/ZL10313 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_ZL10036 - tristate "Zarlink ZL10036 silicon tuner" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_ZL10039 - tristate "Zarlink ZL10039 silicon tuner" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_S5H1420 - tristate "Samsung S5H1420 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_STV0288 - tristate "ST STV0288 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_STB6000 - tristate "ST STB6000 silicon tuner" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S silicon tuner module. Say Y when you want to support this tuner. - -config DVB_STV0299 - tristate "ST STV0299 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_STV6110 - tristate "ST STV6110 silicon tuner" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S silicon tuner module. Say Y when you want to support this tuner. - -config DVB_STV0900 - tristate "ST STV0900 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S/S2 demodulator. Say Y when you want to support this frontend. - -config DVB_TDA8083 - tristate "Philips TDA8083 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_TDA10086 - tristate "Philips TDA10086 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_TDA8261 - tristate "Philips TDA8261 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_VES1X93 - tristate "VLSI VES1893 or VES1993 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_TUNER_ITD1000 - tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_TUNER_CX24113 - tristate "Conexant CX24113/CX24128 tuner for DVB-S/DSS" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S tuner module. Say Y when you want to support this frontend. - - -config DVB_TDA826X - tristate "Philips TDA826X silicon tuner" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S silicon tuner module. Say Y when you want to support this tuner. - -config DVB_TUA6100 - tristate "Infineon TUA6100 PLL" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S PLL chip. - -config DVB_CX24116 - tristate "Conexant CX24116 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S/S2 tuner module. Say Y when you want to support this frontend. - -config DVB_CX24117 - tristate "Conexant CX24117 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A Dual DVB-S/S2 tuner module. Say Y when you want to support this frontend. - -config DVB_CX24120 - tristate "Conexant CX24120 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S/S2 tuner module. Say Y when you want to support this frontend. - -config DVB_SI21XX - tristate "Silicon Labs SI21XX based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_TS2020 - tristate "Montage Tehnology TS2020 based tuners" - depends on DVB_CORE && I2C - select REGMAP_I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S/S2 silicon tuner. Say Y when you want to support this tuner. - -config DVB_DS3000 - tristate "Montage Tehnology DS3000 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S/S2 tuner module. Say Y when you want to support this frontend. - -config DVB_MB86A16 - tristate "Fujitsu MB86A16 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S/DSS Direct Conversion reveiver. - Say Y when you want to support this frontend. - -config DVB_TDA10071 - tristate "NXP TDA10071" - depends on DVB_CORE && I2C - select REGMAP_I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y when you want to support this frontend. - -comment "DVB-T (terrestrial) frontends" - depends on DVB_CORE - -config DVB_SP8870 - tristate "Spase sp8870 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T tuner module. Say Y when you want to support this frontend. - - This driver needs external firmware. Please use the command - "/Documentation/dvb/get_dvb_firmware sp8870" to - download/extract it, and then copy it to /usr/lib/hotplug/firmware - or /lib/firmware (depending on configuration of firmware hotplug). - -config DVB_SP887X - tristate "Spase sp887x based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T tuner module. Say Y when you want to support this frontend. - - This driver needs external firmware. Please use the command - "/Documentation/dvb/get_dvb_firmware sp887x" to - download/extract it, and then copy it to /usr/lib/hotplug/firmware - or /lib/firmware (depending on configuration of firmware hotplug). - -config DVB_CX22700 - tristate "Conexant CX22700 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T tuner module. Say Y when you want to support this frontend. - -config DVB_CX22702 - tristate "Conexant cx22702 demodulator (OFDM)" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T tuner module. Say Y when you want to support this frontend. - -config DVB_S5H1432 - tristate "Samsung s5h1432 demodulator (OFDM)" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T tuner module. Say Y when you want to support this frontend. - -config DVB_DRXD - tristate "Micronas DRXD driver" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T tuner module. Say Y when you want to support this frontend. - - Note: this driver was based on vendor driver reference code (released - under the GPL) as opposed to the existing drx397xd driver, which - was written via reverse engineering. - -config DVB_L64781 - tristate "LSI L64781" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T tuner module. Say Y when you want to support this frontend. - -config DVB_TDA1004X - tristate "Philips TDA10045H/TDA10046H based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T tuner module. Say Y when you want to support this frontend. - - This driver needs external firmware. Please use the commands - "/Documentation/dvb/get_dvb_firmware tda10045", - "/Documentation/dvb/get_dvb_firmware tda10046" to - download/extract them, and then copy them to /usr/lib/hotplug/firmware - or /lib/firmware (depending on configuration of firmware hotplug). - -config DVB_NXT6000 - tristate "NxtWave Communications NXT6000 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T tuner module. Say Y when you want to support this frontend. - -config DVB_MT352 - tristate "Zarlink MT352 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T tuner module. Say Y when you want to support this frontend. - -config DVB_ZL10353 - tristate "Zarlink ZL10353 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T tuner module. Say Y when you want to support this frontend. - -config DVB_DIB3000MB - tristate "DiBcom 3000M-B" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T tuner module. Designed for mobile usage. Say Y when you want - to support this frontend. - -config DVB_DIB3000MC - tristate "DiBcom 3000P/M-C" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T tuner module. Designed for mobile usage. Say Y when you want - to support this frontend. - -config DVB_DIB7000M - tristate "DiBcom 7000MA/MB/PA/PB/MC" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T tuner module. Designed for mobile usage. Say Y when you want - to support this frontend. - -config DVB_DIB7000P - tristate "DiBcom 7000PC" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T tuner module. Designed for mobile usage. Say Y when you want - to support this frontend. - -config DVB_DIB9000 - tristate "DiBcom 9000" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T tuner module. Designed for mobile usage. Say Y when you want - to support this frontend. - -config DVB_TDA10048 - tristate "Philips TDA10048HN based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T tuner module. Say Y when you want to support this frontend. - -config DVB_AF9013 - tristate "Afatech AF9013 demodulator" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y when you want to support this frontend. - -config DVB_EC100 - tristate "E3C EC100" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y when you want to support this frontend. - -config DVB_HD29L2 - tristate "HDIC HD29L2" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y when you want to support this frontend. - -config DVB_STV0367 - tristate "ST STV0367 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T/C tuner module. Say Y when you want to support this frontend. - -config DVB_CXD2820R - tristate "Sony CXD2820R" - depends on DVB_CORE && I2C - select REGMAP_I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y when you want to support this frontend. - -config DVB_CXD2841ER - tristate "Sony CXD2841ER" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y when you want to support this frontend. - -config DVB_RTL2830 - tristate "Realtek RTL2830 DVB-T" - depends on DVB_CORE && I2C && I2C_MUX - select REGMAP - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y when you want to support this frontend. - -config DVB_RTL2832 - tristate "Realtek RTL2832 DVB-T" - depends on DVB_CORE && I2C && I2C_MUX - select REGMAP - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y when you want to support this frontend. - -config DVB_RTL2832_SDR - tristate "Realtek RTL2832 SDR" - depends on DVB_CORE && I2C && I2C_MUX && VIDEO_V4L2 && MEDIA_SDR_SUPPORT && USB - select DVB_RTL2832 - select VIDEOBUF2_VMALLOC - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y when you want to support this SDR module. - -config DVB_SI2168 - tristate "Silicon Labs Si2168" - depends on DVB_CORE && I2C && I2C_MUX - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y when you want to support this frontend. - -config DVB_AS102_FE - tristate - depends on DVB_CORE - default DVB_AS102 - -config DVB_GP8PSK_FE - tristate - depends on DVB_CORE - default DVB_USB_GP8PSK - -comment "DVB-C (cable) frontends" - depends on DVB_CORE - -config DVB_VES1820 - tristate "VLSI VES1820 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-C tuner module. Say Y when you want to support this frontend. - -config DVB_TDA10021 - tristate "Philips TDA10021 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-C tuner module. Say Y when you want to support this frontend. - -config DVB_TDA10023 - tristate "Philips TDA10023 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-C tuner module. Say Y when you want to support this frontend. - -config DVB_STV0297 - tristate "ST STV0297 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-C tuner module. Say Y when you want to support this frontend. - -comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends" - depends on DVB_CORE - -config DVB_NXT200X - tristate "NxtWave Communications NXT2002/NXT2004 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want - to support this frontend. - - This driver needs external firmware. Please use the commands - "/Documentation/dvb/get_dvb_firmware nxt2002" and - "/Documentation/dvb/get_dvb_firmware nxt2004" to - download/extract them, and then copy them to /usr/lib/hotplug/firmware - or /lib/firmware (depending on configuration of firmware hotplug). - -config DVB_OR51211 - tristate "Oren OR51211 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - An ATSC 8VSB tuner module. Say Y when you want to support this frontend. - - This driver needs external firmware. Please use the command - "/Documentation/dvb/get_dvb_firmware or51211" to - download it, and then copy it to /usr/lib/hotplug/firmware - or /lib/firmware (depending on configuration of firmware hotplug). - -config DVB_OR51132 - tristate "Oren OR51132 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want - to support this frontend. - - This driver needs external firmware. Please use the commands - "/Documentation/dvb/get_dvb_firmware or51132_vsb" and/or - "/Documentation/dvb/get_dvb_firmware or51132_qam" to - download firmwares for 8VSB and QAM64/256, respectively. Copy them to - /usr/lib/hotplug/firmware or /lib/firmware (depending on - configuration of firmware hotplug). - -config DVB_BCM3510 - tristate "Broadcom BCM3510" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to - support this frontend. - -config DVB_LGDT330X - tristate "LG Electronics LGDT3302/LGDT3303 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want - to support this frontend. - -config DVB_LGDT3305 - tristate "LG Electronics LGDT3304 and LGDT3305 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want - to support this frontend. - -config DVB_LGDT3306A - tristate "LG Electronics LGDT3306A based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - An ATSC 8VSB and QAM-B 64/256 demodulator module. Say Y when you want - to support this frontend. - -config DVB_LG2160 - tristate "LG Electronics LG216x based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - An ATSC/MH demodulator module. Say Y when you want - to support this frontend. - -config DVB_S5H1409 - tristate "Samsung S5H1409 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want - to support this frontend. - -config DVB_AU8522 - depends on I2C - tristate - -config DVB_AU8522_DTV - tristate "Auvitek AU8522 based DTV demod" - depends on DVB_CORE && I2C - select DVB_AU8522 - default m if !MEDIA_SUBDRV_AUTOSELECT - help - An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when - you want to enable DTV demodulation support for this frontend. - -config DVB_AU8522_V4L - tristate "Auvitek AU8522 based ATV demod" - depends on VIDEO_V4L2 && I2C - select DVB_AU8522 - default m if !MEDIA_SUBDRV_AUTOSELECT - help - An ATSC 8VSB, QAM64/256 & NTSC demodulator module. Say Y when - you want to enable ATV demodulation support for this frontend. - -config DVB_S5H1411 - tristate "Samsung S5H1411 based" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want - to support this frontend. - -comment "ISDB-T (terrestrial) frontends" - depends on DVB_CORE - -config DVB_S921 - tristate "Sharp S921 frontend" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - AN ISDB-T DQPSK, QPSK, 16QAM and 64QAM 1seg tuner module. - Say Y when you want to support this frontend. - -config DVB_DIB8000 - tristate "DiBcom 8000MB/MC" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A driver for DiBcom's DiB8000 ISDB-T/ISDB-Tsb demodulator. - Say Y when you want to support this frontend. - -config DVB_MB86A20S - tristate "Fujitsu mb86a20s" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator. - Say Y when you want to support this frontend. - -comment "ISDB-S (satellite) & ISDB-T (terrestrial) frontends" - depends on DVB_CORE - -config DVB_TC90522 - tristate "Toshiba TC90522" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Toshiba TC90522 2xISDB-S 8PSK + 2xISDB-T OFDM demodulator. - Say Y when you want to support this frontend. - -comment "Digital terrestrial only tuners/PLL" - depends on DVB_CORE - -config DVB_PLL - tristate "Generic I2C PLL based tuners" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - This module drives a number of tuners based on PLL chips with a - common I2C interface. Say Y when you want to support these tuners. - -config DVB_TUNER_DIB0070 - tristate "DiBcom DiB0070 silicon base-band tuner" - depends on I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A driver for the silicon baseband tuner DiB0070 from DiBcom. - This device is only used inside a SiP called together with a - demodulator for now. - -config DVB_TUNER_DIB0090 - tristate "DiBcom DiB0090 silicon base-band tuner" - depends on I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A driver for the silicon baseband tuner DiB0090 from DiBcom. - This device is only used inside a SiP called together with a - demodulator for now. - -comment "SEC control devices for DVB-S" - depends on DVB_CORE - -source "drivers/media/dvb-frontends/drx39xyj/Kconfig" - -config DVB_LNBH25 - tristate "LNBH25 SEC controller" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - An SEC control chip. - Say Y when you want to support this chip. - -config DVB_LNBP21 - tristate "LNBP21/LNBH24 SEC controllers" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - An SEC control chips. - -config DVB_LNBP22 - tristate "LNBP22 SEC controllers" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - LNB power supply and control voltage - regulator chip with step-up converter - and I2C interface. - Say Y when you want to support this chip. - -config DVB_ISL6405 - tristate "ISL6405 SEC controller" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - An SEC control chip. - -config DVB_ISL6421 - tristate "ISL6421 SEC controller" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - An SEC control chip. - -config DVB_ISL6423 - tristate "ISL6423 SEC controller" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A SEC controller chip from Intersil - -config DVB_A8293 - tristate "Allegro A8293" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - -config DVB_SP2 - tristate "CIMaX SP2" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - CIMaX SP2/SP2HF Common Interface module. - -config DVB_LGS8GL5 - tristate "Silicon Legend LGS-8GL5 demodulator (OFDM)" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DMB-TH tuner module. Say Y when you want to support this frontend. - -config DVB_LGS8GXX - tristate "Legend Silicon LGS8913/LGS8GL5/LGS8GXX DMB-TH demodulator" - depends on DVB_CORE && I2C - select FW_LOADER - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DMB-TH tuner module. Say Y when you want to support this frontend. - -config DVB_ATBM8830 - tristate "AltoBeam ATBM8830/8831 DMB-TH demodulator" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DMB-TH tuner module. Say Y when you want to support this frontend. - -config DVB_TDA665x - tristate "TDA665x tuner" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Support for tuner modules based on Philips TDA6650/TDA6651 chips. - Say Y when you want to support this chip. - - Currently supported tuners: - * Panasonic ENV57H12D5 (ET-50DT) - -config DVB_IX2505V - tristate "Sharp IX2505V silicon tuner" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S tuner module. Say Y when you want to support this frontend. - -config DVB_M88RS2000 - tristate "M88RS2000 DVB-S demodulator and tuner" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-S tuner module. - Say Y when you want to support this frontend. - -config DVB_AF9033 - tristate "Afatech AF9033 DVB-T demodulator" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - -config DVB_HORUS3A - tristate "Sony Horus3A tuner" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y when you want to support this frontend. - -config DVB_ASCOT2E - tristate "Sony Ascot2E tuner" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y when you want to support this frontend. - -config DVB_HELENE - tristate "Sony HELENE Sat/Ter tuner (CXD2858ER)" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y when you want to support this frontend. - -comment "Tools to develop new frontends" - -config DVB_DUMMY_FE - tristate "Dummy frontend driver" - default n -endmenu diff --git a/src/linux/drivers/media/dvb-frontends/drx39xyj/Kconfig b/src/linux/drivers/media/dvb-frontends/drx39xyj/Kconfig deleted file mode 100644 index 6c2ccb6..0000000 --- a/src/linux/drivers/media/dvb-frontends/drx39xyj/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -config DVB_DRX39XYJ - tristate "Micronas DRX-J demodulator" - depends on DVB_CORE && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want - to support this frontend. diff --git a/src/linux/drivers/media/firewire/Kconfig b/src/linux/drivers/media/firewire/Kconfig deleted file mode 100644 index f3e9448..0000000 --- a/src/linux/drivers/media/firewire/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -config DVB_FIREDTV - tristate "FireDTV and FloppyDTV" - depends on DVB_CORE && FIREWIRE - help - Support for DVB receivers from Digital Everywhere - which are connected via IEEE 1394 (FireWire). - - These devices don't have an MPEG decoder built in, - so you need an external software decoder to watch TV. - - To compile this driver as a module, say M here: - the module will be called firedtv. - -if DVB_FIREDTV - -config DVB_FIREDTV_INPUT - def_bool INPUT = y || (INPUT = m && DVB_FIREDTV = m) - -endif # DVB_FIREDTV diff --git a/src/linux/drivers/media/firewire/Makefile b/src/linux/drivers/media/firewire/Makefile deleted file mode 100644 index 2394813..0000000 --- a/src/linux/drivers/media/firewire/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -obj-$(CONFIG_DVB_FIREDTV) += firedtv.o - -firedtv-y += firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o firedtv-fw.o -firedtv-$(CONFIG_DVB_FIREDTV_INPUT) += firedtv-rc.o - -ccflags-y += -Idrivers/media/dvb-core diff --git a/src/linux/drivers/media/i2c/Kconfig b/src/linux/drivers/media/i2c/Kconfig deleted file mode 100644 index 2669b4b..0000000 --- a/src/linux/drivers/media/i2c/Kconfig +++ /dev/null @@ -1,781 +0,0 @@ -# -# Multimedia Video device configuration -# - -if VIDEO_V4L2 - -config VIDEO_IR_I2C - tristate "I2C module for IR" if !MEDIA_SUBDRV_AUTOSELECT - depends on I2C && RC_CORE - default y - ---help--- - Most boards have an IR chip directly connected via GPIO. However, - some video boards have the IR connected via I2C bus. - - If your board doesn't have an I2C IR chip, you may disable this - option. - - In doubt, say Y. - -# -# Encoder / Decoder module configuration -# - -menu "I2C Encoders, decoders, sensors and other helper chips" - visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST - -comment "Audio decoders, processors and mixers" - -config VIDEO_TVAUDIO - tristate "Simple audio decoder chips" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for several audio decoder chips found on some bt8xx boards: - Philips: tda9840, tda9873h, tda9874h/a, tda9850, tda985x, tea6300, - tea6320, tea6420, tda8425, ta8874z. - Microchip: pic16c54 based design on ProVideo PV951 board. - - To compile this driver as a module, choose M here: the - module will be called tvaudio. - -config VIDEO_TDA7432 - tristate "Philips TDA7432 audio processor" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for tda7432 audio decoder chip found on some bt8xx boards. - - To compile this driver as a module, choose M here: the - module will be called tda7432. - -config VIDEO_TDA9840 - tristate "Philips TDA9840 audio processor" - depends on I2C - ---help--- - Support for tda9840 audio decoder chip found on some Zoran boards. - - To compile this driver as a module, choose M here: the - module will be called tda9840. - -config VIDEO_TEA6415C - tristate "Philips TEA6415C audio processor" - depends on I2C - ---help--- - Support for tea6415c audio decoder chip found on some bt8xx boards. - - To compile this driver as a module, choose M here: the - module will be called tea6415c. - -config VIDEO_TEA6420 - tristate "Philips TEA6420 audio processor" - depends on I2C - ---help--- - Support for tea6420 audio decoder chip found on some bt8xx boards. - - To compile this driver as a module, choose M here: the - module will be called tea6420. - -config VIDEO_MSP3400 - tristate "Micronas MSP34xx audio decoders" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Micronas MSP34xx series of audio decoders. - - To compile this driver as a module, choose M here: the - module will be called msp3400. - -config VIDEO_CS3308 - tristate "Cirrus Logic CS3308 audio ADC" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Cirrus Logic CS3308 High Performance 8-Channel - Analog Volume Control - - To compile this driver as a module, choose M here: the - module will be called cs3308. - -config VIDEO_CS5345 - tristate "Cirrus Logic CS5345 audio ADC" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Cirrus Logic CS5345 24-bit, 192 kHz - stereo A/D converter. - - To compile this driver as a module, choose M here: the - module will be called cs5345. - -config VIDEO_CS53L32A - tristate "Cirrus Logic CS53L32A audio ADC" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Cirrus Logic CS53L32A low voltage - stereo A/D converter. - - To compile this driver as a module, choose M here: the - module will be called cs53l32a. - -config VIDEO_TLV320AIC23B - tristate "Texas Instruments TLV320AIC23B audio codec" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Texas Instruments TLV320AIC23B audio codec. - - To compile this driver as a module, choose M here: the - module will be called tlv320aic23b. - -config VIDEO_UDA1342 - tristate "Philips UDA1342 audio codec" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Philips UDA1342 audio codec. - - To compile this driver as a module, choose M here: the - module will be called uda1342. - -config VIDEO_WM8775 - tristate "Wolfson Microelectronics WM8775 audio ADC with input mixer" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Wolfson Microelectronics WM8775 high - performance stereo A/D Converter with a 4 channel input mixer. - - To compile this driver as a module, choose M here: the - module will be called wm8775. - -config VIDEO_WM8739 - tristate "Wolfson Microelectronics WM8739 stereo audio ADC" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Wolfson Microelectronics WM8739 - stereo A/D Converter. - - To compile this driver as a module, choose M here: the - module will be called wm8739. - -config VIDEO_VP27SMPX - tristate "Panasonic VP27's internal MPX" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the internal MPX of the Panasonic VP27s tuner. - - To compile this driver as a module, choose M here: the - module will be called vp27smpx. - -config VIDEO_SONY_BTF_MPX - tristate "Sony BTF's internal MPX" - depends on VIDEO_V4L2 && I2C - help - Support for the internal MPX of the Sony BTF-PG472Z tuner. - - To compile this driver as a module, choose M here: the - module will be called sony-btf-mpx. - -comment "RDS decoders" - -config VIDEO_SAA6588 - tristate "SAA6588 Radio Chip RDS decoder support" - depends on VIDEO_V4L2 && I2C - - help - Support for this Radio Data System (RDS) decoder. This allows - seeing radio station identification transmitted using this - standard. - - To compile this driver as a module, choose M here: the - module will be called saa6588. - -comment "Video decoders" - -config VIDEO_ADV7180 - tristate "Analog Devices ADV7180 decoder" - depends on GPIOLIB && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API - ---help--- - Support for the Analog Devices ADV7180 video decoder. - - To compile this driver as a module, choose M here: the - module will be called adv7180. - -config VIDEO_ADV7183 - tristate "Analog Devices ADV7183 decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - V4l2 subdevice driver for the Analog Devices - ADV7183 video decoder. - - To compile this driver as a module, choose M here: the - module will be called adv7183. - -config VIDEO_ADV7604 - tristate "Analog Devices ADV7604 decoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API - depends on GPIOLIB || COMPILE_TEST - select HDMI - select MEDIA_CEC_EDID - ---help--- - Support for the Analog Devices ADV7604 video decoder. - - This is a Analog Devices Component/Graphics Digitizer - with 4:1 Multiplexed HDMI Receiver. - - To compile this driver as a module, choose M here: the - module will be called adv7604. - -config VIDEO_ADV7604_CEC - bool "Enable Analog Devices ADV7604 CEC support" - depends on VIDEO_ADV7604 && MEDIA_CEC - ---help--- - When selected the adv7604 will support the optional - HDMI CEC feature. - -config VIDEO_ADV7842 - tristate "Analog Devices ADV7842 decoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API - select HDMI - select MEDIA_CEC_EDID - ---help--- - Support for the Analog Devices ADV7842 video decoder. - - This is a Analog Devices Component/Graphics/SD Digitizer - with 2:1 Multiplexed HDMI Receiver. - - To compile this driver as a module, choose M here: the - module will be called adv7842. - -config VIDEO_ADV7842_CEC - bool "Enable Analog Devices ADV7842 CEC support" - depends on VIDEO_ADV7842 && MEDIA_CEC - ---help--- - When selected the adv7842 will support the optional - HDMI CEC feature. - -config VIDEO_BT819 - tristate "BT819A VideoStream decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for BT819A video decoder. - - To compile this driver as a module, choose M here: the - module will be called bt819. - -config VIDEO_BT856 - tristate "BT856 VideoStream decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for BT856 video decoder. - - To compile this driver as a module, choose M here: the - module will be called bt856. - -config VIDEO_BT866 - tristate "BT866 VideoStream decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for BT866 video decoder. - - To compile this driver as a module, choose M here: the - module will be called bt866. - -config VIDEO_KS0127 - tristate "KS0127 video decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for KS0127 video decoder. - - This chip is used on AverMedia AVS6EYES Zoran-based MJPEG - cards. - - To compile this driver as a module, choose M here: the - module will be called ks0127. - -config VIDEO_ML86V7667 - tristate "OKI ML86V7667 video decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the OKI Semiconductor ML86V7667 video decoder. - - To compile this driver as a module, choose M here: the - module will be called ml86v7667. - -config VIDEO_AD5820 - tristate "AD5820 lens voice coil support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER - ---help--- - This is a driver for the AD5820 camera lens voice coil. - It is used for example in Nokia N900 (RX-51). - -config VIDEO_SAA7110 - tristate "Philips SAA7110 video decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Philips SAA7110 video decoders. - - To compile this driver as a module, choose M here: the - module will be called saa7110. - -config VIDEO_SAA711X - tristate "Philips SAA7111/3/4/5 video decoders" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Philips SAA7111/3/4/5 video decoders. - - To compile this driver as a module, choose M here: the - module will be called saa7115. - -config VIDEO_TC358743 - tristate "Toshiba TC358743 decoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API - select HDMI - ---help--- - Support for the Toshiba TC358743 HDMI to MIPI CSI-2 bridge. - - To compile this driver as a module, choose M here: the - module will be called tc358743. - -config VIDEO_TVP514X - tristate "Texas Instruments TVP514x video decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - This is a Video4Linux2 sensor-level driver for the TI TVP5146/47 - decoder. It is currently working with the TI OMAP3 camera - controller. - - To compile this driver as a module, choose M here: the - module will be called tvp514x. - -config VIDEO_TVP5150 - tristate "Texas Instruments TVP5150 video decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Texas Instruments TVP5150 video decoder. - - To compile this driver as a module, choose M here: the - module will be called tvp5150. - -config VIDEO_TVP7002 - tristate "Texas Instruments TVP7002 video decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Texas Instruments TVP7002 video decoder. - - To compile this driver as a module, choose M here: the - module will be called tvp7002. - -config VIDEO_TW2804 - tristate "Techwell TW2804 multiple video decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Techwell tw2804 multiple video decoder. - - To compile this driver as a module, choose M here: the - module will be called tw2804. - -config VIDEO_TW9903 - tristate "Techwell TW9903 video decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Techwell tw9903 multi-standard video decoder - with high quality down scaler. - - To compile this driver as a module, choose M here: the - module will be called tw9903. - -config VIDEO_TW9906 - tristate "Techwell TW9906 video decoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Techwell tw9906 enhanced multi-standard comb filter - video decoder with YCbCr input support. - - To compile this driver as a module, choose M here: the - module will be called tw9906. - -config VIDEO_VPX3220 - tristate "vpx3220a, vpx3216b & vpx3214c video decoders" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for VPX322x video decoders. - - To compile this driver as a module, choose M here: the - module will be called vpx3220. - -comment "Video and audio decoders" - -config VIDEO_SAA717X - tristate "Philips SAA7171/3/4 audio/video decoders" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Philips SAA7171/3/4 audio/video decoders. - - To compile this driver as a module, choose M here: the - module will be called saa717x. - -source "drivers/media/i2c/cx25840/Kconfig" - -comment "Video encoders" - -config VIDEO_SAA7127 - tristate "Philips SAA7127/9 digital video encoders" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Philips SAA7127/9 digital video encoders. - - To compile this driver as a module, choose M here: the - module will be called saa7127. - -config VIDEO_SAA7185 - tristate "Philips SAA7185 video encoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Philips SAA7185 video encoder. - - To compile this driver as a module, choose M here: the - module will be called saa7185. - -config VIDEO_ADV7170 - tristate "Analog Devices ADV7170 video encoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Analog Devices ADV7170 video encoder driver - - To compile this driver as a module, choose M here: the - module will be called adv7170. - -config VIDEO_ADV7175 - tristate "Analog Devices ADV7175 video encoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Analog Devices ADV7175 video encoder driver - - To compile this driver as a module, choose M here: the - module will be called adv7175. - -config VIDEO_ADV7343 - tristate "ADV7343 video encoder" - depends on I2C - help - Support for Analog Devices I2C bus based ADV7343 encoder. - - To compile this driver as a module, choose M here: the - module will be called adv7343. - -config VIDEO_ADV7393 - tristate "ADV7393 video encoder" - depends on I2C - help - Support for Analog Devices I2C bus based ADV7393 encoder. - - To compile this driver as a module, choose M here: the - module will be called adv7393. - -config VIDEO_ADV7511 - tristate "Analog Devices ADV7511 encoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API - select HDMI - select MEDIA_CEC_EDID - ---help--- - Support for the Analog Devices ADV7511 video encoder. - - This is a Analog Devices HDMI transmitter. - - To compile this driver as a module, choose M here: the - module will be called adv7511. - -config VIDEO_ADV7511_CEC - bool "Enable Analog Devices ADV7511 CEC support" - depends on VIDEO_ADV7511 && MEDIA_CEC - ---help--- - When selected the adv7511 will support the optional - HDMI CEC feature. - -config VIDEO_AD9389B - tristate "Analog Devices AD9389B encoder" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API - ---help--- - Support for the Analog Devices AD9389B video encoder. - - This is a Analog Devices HDMI transmitter. - - To compile this driver as a module, choose M here: the - module will be called ad9389b. - -config VIDEO_AK881X - tristate "AK8813/AK8814 video encoders" - depends on I2C - help - Video output driver for AKM AK8813 and AK8814 TV encoders - -config VIDEO_THS8200 - tristate "Texas Instruments THS8200 video encoder" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Texas Instruments THS8200 video encoder. - - To compile this driver as a module, choose M here: the - module will be called ths8200. - -comment "Camera sensor devices" - -config VIDEO_APTINA_PLL - tristate - -config VIDEO_SMIAPP_PLL - tristate - -config VIDEO_OV2659 - tristate "OmniVision OV2659 sensor support" - depends on VIDEO_V4L2 && I2C - depends on MEDIA_CAMERA_SUPPORT - ---help--- - This is a Video4Linux2 sensor-level driver for the OmniVision - OV2659 camera. - - To compile this driver as a module, choose M here: the - module will be called ov2659. - -config VIDEO_OV7640 - tristate "OmniVision OV7640 sensor support" - depends on I2C && VIDEO_V4L2 - depends on MEDIA_CAMERA_SUPPORT - ---help--- - This is a Video4Linux2 sensor-level driver for the OmniVision - OV7640 camera. - - To compile this driver as a module, choose M here: the - module will be called ov7640. - -config VIDEO_OV7670 - tristate "OmniVision OV7670 sensor support" - depends on I2C && VIDEO_V4L2 - depends on MEDIA_CAMERA_SUPPORT - ---help--- - This is a Video4Linux2 sensor-level driver for the OmniVision - OV7670 VGA camera. It currently only works with the M88ALP01 - controller. - -config VIDEO_OV9650 - tristate "OmniVision OV9650/OV9652 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - ---help--- - This is a V4L2 sensor-level driver for the Omnivision - OV9650 and OV9652 camera sensors. - -config VIDEO_VS6624 - tristate "ST VS6624 sensor support" - depends on VIDEO_V4L2 && I2C - depends on MEDIA_CAMERA_SUPPORT - ---help--- - This is a Video4Linux2 sensor-level driver for the ST VS6624 - camera. - - To compile this driver as a module, choose M here: the - module will be called vs6624. - -config VIDEO_MT9M032 - tristate "MT9M032 camera sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT - select VIDEO_APTINA_PLL - ---help--- - This driver supports MT9M032 camera sensors from Aptina, monochrome - models only. - -config VIDEO_MT9M111 - tristate "mt9m111, mt9m112 and mt9m131 support" - depends on I2C && VIDEO_V4L2 - help - This driver supports MT9M111, MT9M112 and MT9M131 cameras from - Micron/Aptina - -config VIDEO_MT9P031 - tristate "Aptina MT9P031 support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT - select VIDEO_APTINA_PLL - ---help--- - This is a Video4Linux2 sensor-level driver for the Aptina - (Micron) mt9p031 5 Mpixel camera. - -config VIDEO_MT9T001 - tristate "Aptina MT9T001 support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT - ---help--- - This is a Video4Linux2 sensor-level driver for the Aptina - (Micron) mt0t001 3 Mpixel camera. - -config VIDEO_MT9V011 - tristate "Micron mt9v011 sensor support" - depends on I2C && VIDEO_V4L2 - depends on MEDIA_CAMERA_SUPPORT - ---help--- - This is a Video4Linux2 sensor-level driver for the Micron - mt0v011 1.3 Mpixel camera. It currently only works with the - em28xx driver. - -config VIDEO_MT9V032 - tristate "Micron MT9V032 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT - select REGMAP_I2C - ---help--- - This is a Video4Linux2 sensor-level driver for the Micron - MT9V032 752x480 CMOS sensor. - -config VIDEO_SR030PC30 - tristate "Siliconfile SR030PC30 sensor support" - depends on I2C && VIDEO_V4L2 - depends on MEDIA_CAMERA_SUPPORT - ---help--- - This driver supports SR030PC30 VGA camera from Siliconfile - -config VIDEO_NOON010PC30 - tristate "Siliconfile NOON010PC30 sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT - ---help--- - This driver supports NOON010PC30 CIF camera from Siliconfile - -source "drivers/media/i2c/m5mols/Kconfig" - -config VIDEO_S5K6AA - tristate "Samsung S5K6AAFX sensor support" - depends on MEDIA_CAMERA_SUPPORT - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - ---help--- - This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M - camera sensor with an embedded SoC image signal processor. - -config VIDEO_S5K6A3 - tristate "Samsung S5K6A3 sensor support" - depends on MEDIA_CAMERA_SUPPORT - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - ---help--- - This is a V4L2 sensor-level driver for Samsung S5K6A3 raw - camera sensor. - -config VIDEO_S5K4ECGX - tristate "Samsung S5K4ECGX sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - ---help--- - This is a V4L2 sensor-level driver for Samsung S5K4ECGX 5M - camera sensor with an embedded SoC image signal processor. - -config VIDEO_S5K5BAF - tristate "Samsung S5K5BAF sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - ---help--- - This is a V4L2 sensor-level driver for Samsung S5K5BAF 2M - camera sensor with an embedded SoC image signal processor. - -source "drivers/media/i2c/smiapp/Kconfig" - -config VIDEO_S5C73M3 - tristate "Samsung S5C73M3 sensor support" - depends on I2C && SPI && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - ---help--- - This is a V4L2 sensor-level driver for Samsung S5C73M3 - 8 Mpixel camera. - -comment "Flash devices" - -config VIDEO_ADP1653 - tristate "ADP1653 flash support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER - depends on MEDIA_CAMERA_SUPPORT - ---help--- - This is a driver for the ADP1653 flash controller. It is used for - example in Nokia N900. - -config VIDEO_AS3645A - tristate "AS3645A flash driver support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER - depends on MEDIA_CAMERA_SUPPORT - ---help--- - This is a driver for the AS3645A and LM3555 flash controllers. It has - build in control for flash, torch and indicator LEDs. - -config VIDEO_LM3560 - tristate "LM3560 dual flash driver support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER - depends on MEDIA_CAMERA_SUPPORT - select REGMAP_I2C - ---help--- - This is a driver for the lm3560 dual flash controllers. It controls - flash, torch LEDs. - -config VIDEO_LM3646 - tristate "LM3646 dual flash driver support" - depends on I2C && VIDEO_V4L2 && MEDIA_CONTROLLER - depends on MEDIA_CAMERA_SUPPORT - select REGMAP_I2C - ---help--- - This is a driver for the lm3646 dual flash controllers. It controls - flash, torch LEDs. - -comment "Video improvement chips" - -config VIDEO_UPD64031A - tristate "NEC Electronics uPD64031A Ghost Reduction" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the NEC Electronics uPD64031A Ghost Reduction - video chip. It is most often found in NTSC TV cards made for - Japan and is used to reduce the 'ghosting' effect that can - be present in analog TV broadcasts. - - To compile this driver as a module, choose M here: the - module will be called upd64031a. - -config VIDEO_UPD64083 - tristate "NEC Electronics uPD64083 3-Dimensional Y/C separation" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the NEC Electronics uPD64083 3-Dimensional Y/C - separation video chip. It is used to improve the quality of - the colors of a composite signal. - - To compile this driver as a module, choose M here: the - module will be called upd64083. - -comment "Audio/Video compression chips" - -config VIDEO_SAA6752HS - tristate "Philips SAA6752HS MPEG-2 Audio/Video Encoder" - depends on VIDEO_V4L2 && I2C - select CRC32 - ---help--- - Support for the Philips SAA6752HS MPEG-2 video and MPEG-audio/AC-3 - audio encoder with multiplexer. - - To compile this driver as a module, choose M here: the - module will be called saa6752hs. - -comment "Miscellaneous helper chips" - -config VIDEO_THS7303 - tristate "THS7303/53 Video Amplifier" - depends on VIDEO_V4L2 && I2C - help - Support for TI THS7303/53 video amplifier - - To compile this driver as a module, choose M here: the - module will be called ths7303. - -config VIDEO_M52790 - tristate "Mitsubishi M52790 A/V switch" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Mitsubishi M52790 A/V switch. - - To compile this driver as a module, choose M here: the - module will be called m52790. -endmenu - -menu "Sensors used on soc_camera driver" - -if SOC_CAMERA - source "drivers/media/i2c/soc_camera/Kconfig" -endif - -endmenu - -endif diff --git a/src/linux/drivers/media/i2c/Makefile b/src/linux/drivers/media/i2c/Makefile deleted file mode 100644 index 92773b2..0000000 --- a/src/linux/drivers/media/i2c/Makefile +++ /dev/null @@ -1,84 +0,0 @@ -msp3400-objs := msp3400-driver.o msp3400-kthreads.o -obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o - -obj-$(CONFIG_VIDEO_SMIAPP) += smiapp/ -obj-$(CONFIG_VIDEO_CX25840) += cx25840/ -obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ -obj-y += soc_camera/ - -obj-$(CONFIG_VIDEO_APTINA_PLL) += aptina-pll.o -obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o -obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o -obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o -obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o -obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o -obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o -obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o -obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o -obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o -obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o -obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o -obj-$(CONFIG_VIDEO_SAA6752HS) += saa6752hs.o -obj-$(CONFIG_VIDEO_AD5820) += ad5820.o -obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o -obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o -obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o -obj-$(CONFIG_VIDEO_ADV7183) += adv7183.o -obj-$(CONFIG_VIDEO_ADV7343) += adv7343.o -obj-$(CONFIG_VIDEO_ADV7393) += adv7393.o -obj-$(CONFIG_VIDEO_ADV7604) += adv7604.o -obj-$(CONFIG_VIDEO_ADV7842) += adv7842.o -obj-$(CONFIG_VIDEO_AD9389B) += ad9389b.o -obj-$(CONFIG_VIDEO_ADV7511) += adv7511.o -obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o -obj-$(CONFIG_VIDEO_VS6624) += vs6624.o -obj-$(CONFIG_VIDEO_BT819) += bt819.o -obj-$(CONFIG_VIDEO_BT856) += bt856.o -obj-$(CONFIG_VIDEO_BT866) += bt866.o -obj-$(CONFIG_VIDEO_KS0127) += ks0127.o -obj-$(CONFIG_VIDEO_THS7303) += ths7303.o -obj-$(CONFIG_VIDEO_THS8200) += ths8200.o -obj-$(CONFIG_VIDEO_TVP5150) += tvp5150.o -obj-$(CONFIG_VIDEO_TVP514X) += tvp514x.o -obj-$(CONFIG_VIDEO_TVP7002) += tvp7002.o -obj-$(CONFIG_VIDEO_TW2804) += tw2804.o -obj-$(CONFIG_VIDEO_TW9903) += tw9903.o -obj-$(CONFIG_VIDEO_TW9906) += tw9906.o -obj-$(CONFIG_VIDEO_CS3308) += cs3308.o -obj-$(CONFIG_VIDEO_CS5345) += cs5345.o -obj-$(CONFIG_VIDEO_CS53L32A) += cs53l32a.o -obj-$(CONFIG_VIDEO_M52790) += m52790.o -obj-$(CONFIG_VIDEO_TLV320AIC23B) += tlv320aic23b.o -obj-$(CONFIG_VIDEO_UDA1342) += uda1342.o -obj-$(CONFIG_VIDEO_WM8775) += wm8775.o -obj-$(CONFIG_VIDEO_WM8739) += wm8739.o -obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o -obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o -obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o -obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o -obj-$(CONFIG_VIDEO_OV7640) += ov7640.o -obj-$(CONFIG_VIDEO_OV7670) += ov7670.o -obj-$(CONFIG_VIDEO_OV9650) += ov9650.o -obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o -obj-$(CONFIG_VIDEO_MT9M111) += mt9m111.o -obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o -obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o -obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o -obj-$(CONFIG_VIDEO_MT9V032) += mt9v032.o -obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o -obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o -obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o -obj-$(CONFIG_VIDEO_S5K6A3) += s5k6a3.o -obj-$(CONFIG_VIDEO_S5K4ECGX) += s5k4ecgx.o -obj-$(CONFIG_VIDEO_S5K5BAF) += s5k5baf.o -obj-$(CONFIG_VIDEO_S5C73M3) += s5c73m3/ -obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o -obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o -obj-$(CONFIG_VIDEO_LM3560) += lm3560.o -obj-$(CONFIG_VIDEO_LM3646) += lm3646.o -obj-$(CONFIG_VIDEO_SMIAPP_PLL) += smiapp-pll.o -obj-$(CONFIG_VIDEO_AK881X) += ak881x.o -obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o -obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o -obj-$(CONFIG_VIDEO_OV2659) += ov2659.o -obj-$(CONFIG_VIDEO_TC358743) += tc358743.o diff --git a/src/linux/drivers/media/i2c/cx25840/Kconfig b/src/linux/drivers/media/i2c/cx25840/Kconfig deleted file mode 100644 index 451133a..0000000 --- a/src/linux/drivers/media/i2c/cx25840/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config VIDEO_CX25840 - tristate "Conexant CX2584x audio/video decoders" - depends on VIDEO_V4L2 && I2C - ---help--- - Support for the Conexant CX2584x audio/video decoders. - - To compile this driver as a module, choose M here: the - module will be called cx25840 diff --git a/src/linux/drivers/media/i2c/m5mols/Kconfig b/src/linux/drivers/media/i2c/m5mols/Kconfig deleted file mode 100644 index dc8c250..0000000 --- a/src/linux/drivers/media/i2c/m5mols/Kconfig +++ /dev/null @@ -1,6 +0,0 @@ -config VIDEO_M5MOLS - tristate "Fujitsu M-5MOLS 8MP sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on MEDIA_CAMERA_SUPPORT - ---help--- - This driver supports Fujitsu M-5MOLS camera sensor with ISP diff --git a/src/linux/drivers/media/i2c/smiapp/Kconfig b/src/linux/drivers/media/i2c/smiapp/Kconfig deleted file mode 100644 index 3149cda..0000000 --- a/src/linux/drivers/media/i2c/smiapp/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -config VIDEO_SMIAPP - tristate "SMIA++/SMIA sensor support" - depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAVE_CLK - depends on MEDIA_CAMERA_SUPPORT - select VIDEO_SMIAPP_PLL - ---help--- - This is a generic driver for SMIA++/SMIA camera modules. diff --git a/src/linux/drivers/media/i2c/soc_camera/Kconfig b/src/linux/drivers/media/i2c/soc_camera/Kconfig deleted file mode 100644 index 7704bcf..0000000 --- a/src/linux/drivers/media/i2c/soc_camera/Kconfig +++ /dev/null @@ -1,90 +0,0 @@ -comment "soc_camera sensor drivers" - -config SOC_CAMERA_IMX074 - tristate "imx074 support" - depends on SOC_CAMERA && I2C - help - This driver supports IMX074 cameras from Sony - -config SOC_CAMERA_MT9M001 - tristate "mt9m001 support" - depends on SOC_CAMERA && I2C - help - This driver supports MT9M001 cameras from Micron, monochrome - and colour models. - -config SOC_CAMERA_MT9M111 - tristate "legacy soc_camera mt9m111, mt9m112 and mt9m131 support" - depends on SOC_CAMERA && I2C - select VIDEO_MT9M111 - help - This driver supports MT9M111, MT9M112 and MT9M131 cameras from - Micron/Aptina. - This is the legacy configuration which shouldn't be used anymore, - while VIDEO_MT9M111 should be used instead. - -config SOC_CAMERA_MT9T031 - tristate "mt9t031 support" - depends on SOC_CAMERA && I2C - help - This driver supports MT9T031 cameras from Micron. - -config SOC_CAMERA_MT9T112 - tristate "mt9t112 support" - depends on SOC_CAMERA && I2C - help - This driver supports MT9T112 cameras from Aptina. - -config SOC_CAMERA_MT9V022 - tristate "mt9v022 and mt9v024 support" - depends on SOC_CAMERA && I2C - help - This driver supports MT9V022 cameras from Micron - -config SOC_CAMERA_OV2640 - tristate "ov2640 camera support" - depends on SOC_CAMERA && I2C - help - This is a ov2640 camera driver - -config SOC_CAMERA_OV5642 - tristate "ov5642 camera support" - depends on SOC_CAMERA && I2C - help - This is a V4L2 camera driver for the OmniVision OV5642 sensor - -config SOC_CAMERA_OV6650 - tristate "ov6650 sensor support" - depends on SOC_CAMERA && I2C - ---help--- - This is a V4L2 SoC camera driver for the OmniVision OV6650 sensor - -config SOC_CAMERA_OV772X - tristate "ov772x camera support" - depends on SOC_CAMERA && I2C - help - This is a ov772x camera driver - -config SOC_CAMERA_OV9640 - tristate "ov9640 camera support" - depends on SOC_CAMERA && I2C - help - This is a ov9640 camera driver - -config SOC_CAMERA_OV9740 - tristate "ov9740 camera support" - depends on SOC_CAMERA && I2C - help - This is a ov9740 camera driver - -config SOC_CAMERA_RJ54N1 - tristate "rj54n1cb0c support" - depends on SOC_CAMERA && I2C - help - This is a rj54n1cb0c video driver - -config SOC_CAMERA_TW9910 - tristate "tw9910 support" - depends on SOC_CAMERA && I2C - help - This is a tw9910 video driver diff --git a/src/linux/drivers/media/i2c/soc_camera/Makefile b/src/linux/drivers/media/i2c/soc_camera/Makefile deleted file mode 100644 index 6f994f9..0000000 --- a/src/linux/drivers/media/i2c/soc_camera/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.o -obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o -obj-$(CONFIG_SOC_CAMERA_MT9T031) += mt9t031.o -obj-$(CONFIG_SOC_CAMERA_MT9T112) += mt9t112.o -obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o -obj-$(CONFIG_SOC_CAMERA_OV2640) += ov2640.o -obj-$(CONFIG_SOC_CAMERA_OV5642) += ov5642.o -obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o -obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o -obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o -obj-$(CONFIG_SOC_CAMERA_OV9740) += ov9740.o -obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o -obj-$(CONFIG_SOC_CAMERA_TW9910) += tw9910.o diff --git a/src/linux/drivers/media/mmc/Kconfig b/src/linux/drivers/media/mmc/Kconfig deleted file mode 100644 index 8c30ada..0000000 --- a/src/linux/drivers/media/mmc/Kconfig +++ /dev/null @@ -1,2 +0,0 @@ -comment "Supported MMC/SDIO adapters" -source "drivers/media/mmc/siano/Kconfig" diff --git a/src/linux/drivers/media/mmc/Makefile b/src/linux/drivers/media/mmc/Makefile deleted file mode 100644 index 31e297a..0000000 --- a/src/linux/drivers/media/mmc/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-y += siano/ diff --git a/src/linux/drivers/media/mmc/siano/Kconfig b/src/linux/drivers/media/mmc/siano/Kconfig deleted file mode 100644 index 7693487..0000000 --- a/src/linux/drivers/media/mmc/siano/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# -# Siano Mobile Silicon Digital TV device configuration -# - -config SMS_SDIO_DRV - tristate "Siano SMS1xxx based MDTV via SDIO interface" - depends on DVB_CORE && HAS_DMA - depends on MMC - depends on !RC_CORE || RC_CORE - select MEDIA_COMMON_OPTIONS - select SMS_SIANO_MDTV - ---help--- - Choose if you would like to have Siano's support for SDIO interface diff --git a/src/linux/drivers/media/mmc/siano/Makefile b/src/linux/drivers/media/mmc/siano/Makefile deleted file mode 100644 index 0e01f97..0000000 --- a/src/linux/drivers/media/mmc/siano/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -obj-$(CONFIG_SMS_SDIO_DRV) += smssdio.o - -ccflags-y += -Idrivers/media/dvb-core -ccflags-y += -Idrivers/media/common/siano -ccflags-y += $(extra-cflags-y) $(extra-cflags-m) - diff --git a/src/linux/drivers/media/pci/Kconfig b/src/linux/drivers/media/pci/Kconfig deleted file mode 100644 index da28e68..0000000 --- a/src/linux/drivers/media/pci/Kconfig +++ /dev/null @@ -1,58 +0,0 @@ -if PCI && MEDIA_SUPPORT - -menuconfig MEDIA_PCI_SUPPORT - bool "Media PCI Adapters" - help - Enable media drivers for PCI/PCIe bus. - If you have such devices, say Y. - -if MEDIA_PCI_SUPPORT - -if MEDIA_CAMERA_SUPPORT - comment "Media capture support" -source "drivers/media/pci/meye/Kconfig" -source "drivers/media/pci/solo6x10/Kconfig" -source "drivers/media/pci/sta2x11/Kconfig" -source "drivers/media/pci/tw5864/Kconfig" -source "drivers/media/pci/tw68/Kconfig" -source "drivers/media/pci/tw686x/Kconfig" -source "drivers/media/pci/zoran/Kconfig" -endif - -if MEDIA_ANALOG_TV_SUPPORT - comment "Media capture/analog TV support" -source "drivers/media/pci/ivtv/Kconfig" -source "drivers/media/pci/saa7146/Kconfig" -source "drivers/media/pci/dt3155/Kconfig" -endif - -if MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT - comment "Media capture/analog/hybrid TV support" -source "drivers/media/pci/cx18/Kconfig" -source "drivers/media/pci/cx23885/Kconfig" -source "drivers/media/pci/cx25821/Kconfig" -source "drivers/media/pci/cx88/Kconfig" -source "drivers/media/pci/bt8xx/Kconfig" -source "drivers/media/pci/saa7134/Kconfig" -source "drivers/media/pci/saa7164/Kconfig" -source "drivers/media/pci/cobalt/Kconfig" - -endif - -if MEDIA_DIGITAL_TV_SUPPORT - comment "Media digital TV PCI Adapters" -source "drivers/media/pci/ttpci/Kconfig" -source "drivers/media/pci/b2c2/Kconfig" -source "drivers/media/pci/pluto2/Kconfig" -source "drivers/media/pci/dm1105/Kconfig" -source "drivers/media/pci/pt1/Kconfig" -source "drivers/media/pci/pt3/Kconfig" -source "drivers/media/pci/mantis/Kconfig" -source "drivers/media/pci/ngene/Kconfig" -source "drivers/media/pci/ddbridge/Kconfig" -source "drivers/media/pci/smipcie/Kconfig" -source "drivers/media/pci/netup_unidvb/Kconfig" -endif - -endif #MEDIA_PCI_SUPPORT -endif #PCI diff --git a/src/linux/drivers/media/pci/Makefile b/src/linux/drivers/media/pci/Makefile deleted file mode 100644 index a7e8af0..0000000 --- a/src/linux/drivers/media/pci/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -# -# Makefile for the kernel multimedia device drivers. -# - -obj-y += ttpci/ \ - b2c2/ \ - pluto2/ \ - dm1105/ \ - pt1/ \ - pt3/ \ - mantis/ \ - ngene/ \ - ddbridge/ \ - saa7146/ \ - smipcie/ \ - netup_unidvb/ - -obj-$(CONFIG_VIDEO_IVTV) += ivtv/ -obj-$(CONFIG_VIDEO_ZORAN) += zoran/ -obj-$(CONFIG_VIDEO_CX18) += cx18/ -obj-$(CONFIG_VIDEO_CX23885) += cx23885/ -obj-$(CONFIG_VIDEO_CX25821) += cx25821/ -obj-$(CONFIG_VIDEO_CX88) += cx88/ -obj-$(CONFIG_VIDEO_BT848) += bt8xx/ -obj-$(CONFIG_VIDEO_SAA7134) += saa7134/ -obj-$(CONFIG_VIDEO_SAA7164) += saa7164/ -obj-$(CONFIG_VIDEO_TW68) += tw68/ -obj-$(CONFIG_VIDEO_TW686X) += tw686x/ -obj-$(CONFIG_VIDEO_DT3155) += dt3155/ -obj-$(CONFIG_VIDEO_MEYE) += meye/ -obj-$(CONFIG_STA2X11_VIP) += sta2x11/ -obj-$(CONFIG_VIDEO_SOLO6X10) += solo6x10/ -obj-$(CONFIG_VIDEO_COBALT) += cobalt/ -obj-$(CONFIG_VIDEO_TW5864) += tw5864/ diff --git a/src/linux/drivers/media/pci/b2c2/Kconfig b/src/linux/drivers/media/pci/b2c2/Kconfig deleted file mode 100644 index 58761a2..0000000 --- a/src/linux/drivers/media/pci/b2c2/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -config DVB_B2C2_FLEXCOP_PCI - tristate "Technisat/B2C2 Air/Sky/Cable2PC PCI" - depends on DVB_CORE && I2C - help - Support for the Air/Sky/CableStar2 PCI card (DVB/ATSC) by Technisat/B2C2. - - Say Y if you own such a device and want to use it. - -config DVB_B2C2_FLEXCOP_PCI_DEBUG - bool "Enable debug for the B2C2 FlexCop drivers" - depends on DVB_B2C2_FLEXCOP_PCI - select DVB_B2C2_FLEXCOP_DEBUG - help - Say Y if you want to enable the module option to control debug messages - of all B2C2 FlexCop drivers. diff --git a/src/linux/drivers/media/pci/b2c2/Makefile b/src/linux/drivers/media/pci/b2c2/Makefile deleted file mode 100644 index b894320..0000000 --- a/src/linux/drivers/media/pci/b2c2/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -ifneq ($(CONFIG_DVB_B2C2_FLEXCOP_PCI),) -b2c2-flexcop-pci-objs += flexcop-dma.o -endif - -b2c2-flexcop-pci-objs += flexcop-pci.o -obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o - -ccflags-y += -Idrivers/media/dvb-core/ -ccflags-y += -Idrivers/media/common/b2c2/ diff --git a/src/linux/drivers/media/pci/bt8xx/Kconfig b/src/linux/drivers/media/pci/bt8xx/Kconfig deleted file mode 100644 index 4a93f6d..0000000 --- a/src/linux/drivers/media/pci/bt8xx/Kconfig +++ /dev/null @@ -1,45 +0,0 @@ -config VIDEO_BT848 - tristate "BT848 Video For Linux" - depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 - select I2C_ALGOBIT - select VIDEOBUF_DMA_SG - depends on RC_CORE - depends on MEDIA_RADIO_SUPPORT - select VIDEO_TUNER - select VIDEO_TVEEPROM - select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_TVAUDIO if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_TDA7432 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT - select RADIO_ADAPTERS - select RADIO_TEA575X - ---help--- - Support for BT848 based frame grabber/overlay boards. This includes - the Miro, Hauppauge and STB boards. Please read the material in - for more information. - - To compile this driver as a module, choose M here: the - module will be called bttv. - -config DVB_BT8XX - tristate "DVB/ATSC Support for bt878 based TV cards" - depends on DVB_CORE && PCI && I2C && VIDEO_BT848 - select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT - select DVB_SP887X if MEDIA_SUBDRV_AUTOSELECT - select DVB_NXT6000 if MEDIA_SUBDRV_AUTOSELECT - select DVB_CX24110 if MEDIA_SUBDRV_AUTOSELECT - select DVB_OR51211 if MEDIA_SUBDRV_AUTOSELECT - select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT - select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT - help - Support for PCI cards based on the Bt8xx PCI bridge. Examples are - the Nebula cards, the Pinnacle PCTV cards, the Twinhan DST cards, - the pcHDTV HD2000 cards, the DViCO FusionHDTV Lite cards, and - some AVerMedia cards. - - Since these cards have no MPEG decoder onboard, they transmit - only compressed MPEG data over the PCI bus, so you need - an external software decoder to watch TV on your computer. - - Say Y if you own such a device and want to use it. diff --git a/src/linux/drivers/media/pci/cobalt/Kconfig b/src/linux/drivers/media/pci/cobalt/Kconfig deleted file mode 100644 index 7034382..0000000 --- a/src/linux/drivers/media/pci/cobalt/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -config VIDEO_COBALT - tristate "Cisco Cobalt support" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API - depends on PCI_MSI && MTD_COMPLEX_MAPPINGS - depends on GPIOLIB || COMPILE_TEST - depends on SND - depends on MTD - select I2C_ALGOBIT - select VIDEO_ADV7604 - select VIDEO_ADV7511 - select VIDEO_ADV7842 - select VIDEOBUF2_DMA_SG - ---help--- - This is a video4linux driver for the Cisco PCIe Cobalt card. - - This board is sadly not available outside of Cisco, but it is - very useful as an example of a real driver that uses all the - latest frameworks and APIs. - - To compile this driver as a module, choose M here: the - module will be called cobalt. diff --git a/src/linux/drivers/media/pci/cx18/Kconfig b/src/linux/drivers/media/pci/cx18/Kconfig deleted file mode 100644 index c675b83..0000000 --- a/src/linux/drivers/media/pci/cx18/Kconfig +++ /dev/null @@ -1,35 +0,0 @@ -config VIDEO_CX18 - tristate "Conexant cx23418 MPEG encoder support" - depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C - select I2C_ALGOBIT - select VIDEOBUF_VMALLOC - depends on RC_CORE - select VIDEO_TUNER - select VIDEO_TVEEPROM - select VIDEO_CX2341X - select VIDEO_CS5345 - select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT - select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT - ---help--- - This is a video4linux driver for Conexant cx23418 based - PCI combo video recorder devices. - - This is used in devices such as the Hauppauge HVR-1600 - cards. - - To compile this driver as a module, choose M here: the - module will be called cx18. - -config VIDEO_CX18_ALSA - tristate "Conexant 23418 DMA audio support" - depends on VIDEO_CX18 && SND - select SND_PCM - ---help--- - This is a video4linux driver for direct (DMA) audio on - Conexant 23418 based TV cards using ALSA. - - To compile this driver as a module, choose M here: the - module will be called cx18-alsa. diff --git a/src/linux/drivers/media/pci/cx23885/Kconfig b/src/linux/drivers/media/pci/cx23885/Kconfig deleted file mode 100644 index 3435bba..0000000 --- a/src/linux/drivers/media/pci/cx23885/Kconfig +++ /dev/null @@ -1,61 +0,0 @@ -config VIDEO_CX23885 - tristate "Conexant cx23885 (2388x successor) support" - depends on DVB_CORE && VIDEO_DEV && PCI && I2C && INPUT && SND - select SND_PCM - select I2C_ALGOBIT - select VIDEO_TUNER - select VIDEO_TVEEPROM - depends on RC_CORE - select VIDEOBUF2_DVB - select VIDEOBUF2_DMA_SG - select VIDEO_CX25840 - select VIDEO_CX2341X - select VIDEO_CS3308 - select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT - select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT - select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT - select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT - select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT - select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT - select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT - select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT - select DVB_CX24117 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT - select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10071 if MEDIA_SUBDRV_AUTOSELECT - select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT - select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT - select DVB_SI2165 if MEDIA_SUBDRV_AUTOSELECT - select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT - select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MT2063 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_M88RS6000T if MEDIA_SUBDRV_AUTOSELECT - select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT - ---help--- - This is a video4linux driver for Conexant 23885 based - TV cards. - - To compile this driver as a module, choose M here: the - module will be called cx23885 - -config MEDIA_ALTERA_CI - tristate "Altera FPGA based CI module" - depends on VIDEO_CX23885 && DVB_CORE - select ALTERA_STAPL - ---help--- - An Altera FPGA CI module for NetUP Dual DVB-T/C RF CI card. - - To compile this driver as a module, choose M here: the - module will be called altera-ci diff --git a/src/linux/drivers/media/pci/cx25821/Kconfig b/src/linux/drivers/media/pci/cx25821/Kconfig deleted file mode 100644 index 1755d3d..0000000 --- a/src/linux/drivers/media/pci/cx25821/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -config VIDEO_CX25821 - tristate "Conexant cx25821 support" - depends on VIDEO_DEV && PCI && I2C - select I2C_ALGOBIT - select VIDEOBUF2_DMA_SG - ---help--- - This is a video4linux driver for Conexant 25821 based - TV cards. - - To compile this driver as a module, choose M here: the - module will be called cx25821 - -config VIDEO_CX25821_ALSA - tristate "Conexant 25821 DMA audio support" - depends on VIDEO_CX25821 && SND - select SND_PCM - ---help--- - This is a video4linux driver for direct (DMA) audio on - Conexant 25821 based capture cards using ALSA. - - It only works with boards with function 01 enabled. - To check if your board supports, use lspci -n. - If supported, you should see 14f1:8801 or 14f1:8811 - PCI device. - - To compile this driver as a module, choose M here: the - module will be called cx25821-alsa. - diff --git a/src/linux/drivers/media/pci/cx88/Kconfig b/src/linux/drivers/media/pci/cx88/Kconfig deleted file mode 100644 index 14b813d..0000000 --- a/src/linux/drivers/media/pci/cx88/Kconfig +++ /dev/null @@ -1,92 +0,0 @@ -config VIDEO_CX88 - tristate "Conexant 2388x (bt878 successor) support" - depends on VIDEO_DEV && PCI && I2C && RC_CORE - select I2C_ALGOBIT - select VIDEOBUF2_DMA_SG - select VIDEO_TUNER - select VIDEO_TVEEPROM - select VIDEO_WM8775 if MEDIA_SUBDRV_AUTOSELECT - ---help--- - This is a video4linux driver for Conexant 2388x based - TV cards. - - To compile this driver as a module, choose M here: the - module will be called cx8800 - -config VIDEO_CX88_ALSA - tristate "Conexant 2388x DMA audio support" - depends on VIDEO_CX88 && SND - select SND_PCM - ---help--- - This is a video4linux driver for direct (DMA) audio on - Conexant 2388x based TV cards using ALSA. - - It only works with boards with function 01 enabled. - To check if your board supports, use lspci -n. - If supported, you should see 14f1:8801 or 14f1:8811 - PCI device. - - To compile this driver as a module, choose M here: the - module will be called cx88-alsa. - -config VIDEO_CX88_BLACKBIRD - tristate "Blackbird MPEG encoder support (cx2388x + cx23416)" - depends on VIDEO_CX88 - select VIDEO_CX2341X - ---help--- - This adds support for MPEG encoder cards based on the - Blackbird reference design, using the Conexant 2388x - and 23416 chips. - - To compile this driver as a module, choose M here: the - module will be called cx88-blackbird. - -config VIDEO_CX88_DVB - tristate "DVB/ATSC Support for cx2388x based TV cards" - depends on VIDEO_CX88 && DVB_CORE - select VIDEOBUF2_DVB - select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT - select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT - select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT - select DVB_OR51132 if MEDIA_SUBDRV_AUTOSELECT - select DVB_CX22702 if MEDIA_SUBDRV_AUTOSELECT - select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT - select DVB_NXT200X if MEDIA_SUBDRV_AUTOSELECT - select DVB_CX24123 if MEDIA_SUBDRV_AUTOSELECT - select DVB_ISL6421 if MEDIA_SUBDRV_AUTOSELECT - select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT - select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT - select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT - ---help--- - This adds support for DVB/ATSC cards based on the - Conexant 2388x chip. - - To compile this driver as a module, choose M here: the - module will be called cx88-dvb. - -config VIDEO_CX88_ENABLE_VP3054 - bool "VP-3054 Secondary I2C Bus Support" - default y - depends on VIDEO_CX88_DVB && DVB_MT352 - ---help--- - This adds DVB-T support for cards based on the - Conexant 2388x chip and the MT352 demodulator, - which also require support for the VP-3054 - Secondary I2C bus, such at DNTV Live! DVB-T Pro. - -config VIDEO_CX88_VP3054 - tristate - depends on VIDEO_CX88_DVB && VIDEO_CX88_ENABLE_VP3054 - default y - -config VIDEO_CX88_MPEG - tristate - depends on VIDEO_CX88_DVB || VIDEO_CX88_BLACKBIRD - default y diff --git a/src/linux/drivers/media/pci/ddbridge/Kconfig b/src/linux/drivers/media/pci/ddbridge/Kconfig deleted file mode 100644 index 44e5dc1..0000000 --- a/src/linux/drivers/media/pci/ddbridge/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config DVB_DDBRIDGE - tristate "Digital Devices bridge support" - depends on DVB_CORE && PCI && I2C - select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT - select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT - ---help--- - Support for cards with the Digital Devices PCI express bridge: - - Octopus PCIe Bridge - - Octopus mini PCIe Bridge - - Octopus LE - - DuoFlex S2 Octopus - - DuoFlex CT Octopus - - cineS2(v6) - - Say Y if you own such a card and want to use it. diff --git a/src/linux/drivers/media/pci/ddbridge/Makefile b/src/linux/drivers/media/pci/ddbridge/Makefile deleted file mode 100644 index 7446c8b..0000000 --- a/src/linux/drivers/media/pci/ddbridge/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# -# Makefile for the ddbridge device driver -# - -ddbridge-objs := ddbridge-core.o - -obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o - -ccflags-y += -Idrivers/media/dvb-core/ -ccflags-y += -Idrivers/media/dvb-frontends/ -ccflags-y += -Idrivers/media/tuners/ - -# For the staging CI driver cxd2099 -ccflags-y += -Idrivers/staging/media/cxd2099/ diff --git a/src/linux/drivers/media/pci/dm1105/Kconfig b/src/linux/drivers/media/pci/dm1105/Kconfig deleted file mode 100644 index 173daf0..0000000 --- a/src/linux/drivers/media/pci/dm1105/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -config DVB_DM1105 - tristate "SDMC DM1105 based PCI cards" - depends on DVB_CORE && PCI && I2C - select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT - select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT - select DVB_SI21XX if MEDIA_SUBDRV_AUTOSELECT - select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT - depends on RC_CORE - help - Support for cards based on the SDMC DM1105 PCI chip like - DvbWorld 2002 - - Since these cards have no MPEG decoder onboard, they transmit - only compressed MPEG data over the PCI bus, so you need - an external software decoder to watch TV on your computer. - - Say Y or M if you own such a device and want to use it. diff --git a/src/linux/drivers/media/pci/dm1105/Makefile b/src/linux/drivers/media/pci/dm1105/Makefile deleted file mode 100644 index 3275851..0000000 --- a/src/linux/drivers/media/pci/dm1105/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_DVB_DM1105) += dm1105.o - -ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends diff --git a/src/linux/drivers/media/pci/dt3155/Kconfig b/src/linux/drivers/media/pci/dt3155/Kconfig deleted file mode 100644 index 5145e0d..0000000 --- a/src/linux/drivers/media/pci/dt3155/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config VIDEO_DT3155 - tristate "DT3155 frame grabber" - depends on PCI && VIDEO_DEV && VIDEO_V4L2 - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - default n - ---help--- - Enables dt3155 device driver for the DataTranslation DT3155 frame grabber. - Say Y here if you have this hardware. - In doubt, say N. - - To compile this driver as a module, choose M here: the - module will be called dt3155. diff --git a/src/linux/drivers/media/pci/ivtv/Kconfig b/src/linux/drivers/media/pci/ivtv/Kconfig deleted file mode 100644 index 6e5867c..0000000 --- a/src/linux/drivers/media/pci/ivtv/Kconfig +++ /dev/null @@ -1,64 +0,0 @@ -config VIDEO_IVTV - tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support" - depends on VIDEO_V4L2 && PCI && I2C - select I2C_ALGOBIT - depends on RC_CORE - select VIDEO_TUNER - select VIDEO_TVEEPROM - select VIDEO_CX2341X - select VIDEO_CX25840 - select VIDEO_MSP3400 - select VIDEO_SAA711X - select VIDEO_SAA717X - select VIDEO_SAA7127 - select VIDEO_CS53L32A - select VIDEO_M52790 - select VIDEO_WM8775 - select VIDEO_WM8739 - select VIDEO_VP27SMPX - select VIDEO_UPD64031A - select VIDEO_UPD64083 - ---help--- - This is a video4linux driver for Conexant cx23416 or cx23415 based - PCI personal video recorder devices. - - This is used in devices such as the Hauppauge PVR-150/250/350/500 - cards. There is a driver homepage at . - - To compile this driver as a module, choose M here: the - module will be called ivtv. - -config VIDEO_IVTV_ALSA - tristate "Conexant cx23415/cx23416 ALSA interface for PCM audio capture" - depends on VIDEO_IVTV && SND - select SND_PCM - ---help--- - This driver provides an ALSA interface as another method for user - applications to obtain PCM audio data from Conexant cx23415/cx23416 - based PCI TV cards supported by the ivtv driver. - - The ALSA interface has much wider use in user applications performing - PCM audio capture, than the V4L2 "/dev/video24" PCM audio interface - provided by the main ivtv driver. - - To compile this driver as a module, choose M here: the - module will be called ivtv-alsa. - -config VIDEO_FB_IVTV - tristate "Conexant cx23415 framebuffer support" - depends on VIDEO_IVTV && FB - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - This is a framebuffer driver for the Conexant cx23415 MPEG - encoder/decoder. - - This is used in the Hauppauge PVR-350 card. There is a driver - homepage at . - - In order to use this module, you will need to boot with PAT disabled - on x86 systems, using the nopat kernel parameter. - - To compile this driver as a module, choose M here: the - module will be called ivtvfb. diff --git a/src/linux/drivers/media/pci/mantis/Kconfig b/src/linux/drivers/media/pci/mantis/Kconfig deleted file mode 100644 index d3cc216..0000000 --- a/src/linux/drivers/media/pci/mantis/Kconfig +++ /dev/null @@ -1,38 +0,0 @@ -config MANTIS_CORE - tristate "Mantis/Hopper PCI bridge based devices" - depends on PCI && I2C && INPUT && RC_CORE - - help - Support for PCI cards based on the Mantis and Hopper PCi bridge. - - Say Y if you own such a device and want to use it. - -config DVB_MANTIS - tristate "MANTIS based cards" - depends on MANTIS_CORE && DVB_CORE && PCI && I2C - select DVB_MB86A16 if MEDIA_SUBDRV_AUTOSELECT - select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT - select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA665x if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10021 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT - select DVB_PLL - help - Support for PCI cards based on the Mantis PCI bridge. - Say Y when you have a Mantis based DVB card and want to use it. - - If unsure say N. - -config DVB_HOPPER - tristate "HOPPER based cards" - depends on MANTIS_CORE && DVB_CORE && PCI && I2C - select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT - select DVB_PLL - help - Support for PCI cards based on the Hopper PCI bridge. - Say Y when you have a Hopper based DVB card and want to use it. - - If unsure say N diff --git a/src/linux/drivers/media/pci/mantis/Makefile b/src/linux/drivers/media/pci/mantis/Makefile deleted file mode 100644 index f715051..0000000 --- a/src/linux/drivers/media/pci/mantis/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -mantis_core-objs := mantis_ioc.o \ - mantis_uart.o \ - mantis_dma.o \ - mantis_pci.o \ - mantis_i2c.o \ - mantis_dvb.o \ - mantis_evm.o \ - mantis_hif.o \ - mantis_ca.o \ - mantis_pcmcia.o \ - mantis_input.o - -mantis-objs := mantis_cards.o \ - mantis_vp1033.o \ - mantis_vp1034.o \ - mantis_vp1041.o \ - mantis_vp2033.o \ - mantis_vp2040.o \ - mantis_vp3030.o - -hopper-objs := hopper_cards.o \ - hopper_vp3028.o - -obj-$(CONFIG_MANTIS_CORE) += mantis_core.o -obj-$(CONFIG_DVB_MANTIS) += mantis.o -obj-$(CONFIG_DVB_HOPPER) += hopper.o - -ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/ diff --git a/src/linux/drivers/media/pci/meye/Kconfig b/src/linux/drivers/media/pci/meye/Kconfig deleted file mode 100644 index b4bf848..0000000 --- a/src/linux/drivers/media/pci/meye/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config VIDEO_MEYE - tristate "Sony Vaio Picturebook Motion Eye Video For Linux" - depends on PCI && SONY_LAPTOP && VIDEO_V4L2 - ---help--- - This is the video4linux driver for the Motion Eye camera found - in the Vaio Picturebook laptops. Please read the material in - for more information. - - If you say Y or M here, you need to say Y or M to "Sony Laptop - Extras" in the misc device section. - - To compile this driver as a module, choose M here: the - module will be called meye. diff --git a/src/linux/drivers/media/pci/netup_unidvb/Kconfig b/src/linux/drivers/media/pci/netup_unidvb/Kconfig deleted file mode 100644 index 0ad3771..0000000 --- a/src/linux/drivers/media/pci/netup_unidvb/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -config DVB_NETUP_UNIDVB - tristate "NetUP Universal DVB card support" - depends on DVB_CORE && VIDEO_DEV && PCI && I2C && SPI_MASTER - select VIDEOBUF2_DVB - select VIDEOBUF2_VMALLOC - select DVB_HORUS3A if MEDIA_SUBDRV_AUTOSELECT - select DVB_ASCOT2E if MEDIA_SUBDRV_AUTOSELECT - select DVB_HELENE if MEDIA_SUBDRV_AUTOSELECT - select DVB_LNBH25 if MEDIA_SUBDRV_AUTOSELECT - select DVB_CXD2841ER if MEDIA_SUBDRV_AUTOSELECT - ---help--- - Support for NetUP PCI express Universal DVB card. - help - Say Y when you want to support NetUP Dual Universal DVB card - Card can receive two independent streams in following standards: - DVB-S/S2, T/T2, C/C2 - Two CI slots available for CAM modules. diff --git a/src/linux/drivers/media/pci/netup_unidvb/Makefile b/src/linux/drivers/media/pci/netup_unidvb/Makefile deleted file mode 100644 index ee6ae05..0000000 --- a/src/linux/drivers/media/pci/netup_unidvb/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -netup-unidvb-objs += netup_unidvb_core.o -netup-unidvb-objs += netup_unidvb_i2c.o -netup-unidvb-objs += netup_unidvb_ci.o -netup-unidvb-objs += netup_unidvb_spi.o - -obj-$(CONFIG_DVB_NETUP_UNIDVB) += netup-unidvb.o - -ccflags-y += -Idrivers/media/dvb-core -ccflags-y += -Idrivers/media/dvb-frontends diff --git a/src/linux/drivers/media/pci/ngene/Kconfig b/src/linux/drivers/media/pci/ngene/Kconfig deleted file mode 100644 index 637d506..0000000 --- a/src/linux/drivers/media/pci/ngene/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config DVB_NGENE - tristate "Micronas nGene support" - depends on DVB_CORE && PCI && I2C - select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT - select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT - select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT - ---help--- - Support for Micronas PCI express cards with nGene bridge. - diff --git a/src/linux/drivers/media/pci/ngene/Makefile b/src/linux/drivers/media/pci/ngene/Makefile deleted file mode 100644 index 5c0b5d6..0000000 --- a/src/linux/drivers/media/pci/ngene/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# -# Makefile for the nGene device driver -# - -ngene-objs := ngene-core.o ngene-i2c.o ngene-cards.o ngene-dvb.o - -obj-$(CONFIG_DVB_NGENE) += ngene.o - -ccflags-y += -Idrivers/media/dvb-core/ -ccflags-y += -Idrivers/media/dvb-frontends/ -ccflags-y += -Idrivers/media/tuners/ - -# For the staging CI driver cxd2099 -ccflags-y += -Idrivers/staging/media/cxd2099/ diff --git a/src/linux/drivers/media/pci/pluto2/Kconfig b/src/linux/drivers/media/pci/pluto2/Kconfig deleted file mode 100644 index 7d8e6e8..0000000 --- a/src/linux/drivers/media/pci/pluto2/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -config DVB_PLUTO2 - tristate "Pluto2 cards" - depends on DVB_CORE && PCI && I2C - select I2C_ALGOBIT - select DVB_TDA1004X - help - Support for PCI cards based on the Pluto2 FPGA like the Satelco - Easywatch Mobile Terrestrial DVB-T Receiver. - - Since these cards have no MPEG decoder onboard, they transmit - only compressed MPEG data over the PCI bus, so you need - an external software decoder to watch TV on your computer. - - Say Y or M if you own such a device and want to use it. - diff --git a/src/linux/drivers/media/pci/pluto2/Makefile b/src/linux/drivers/media/pci/pluto2/Makefile deleted file mode 100644 index 524bf84..0000000 --- a/src/linux/drivers/media/pci/pluto2/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_DVB_PLUTO2) += pluto2.o - -ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/ diff --git a/src/linux/drivers/media/pci/pt1/Kconfig b/src/linux/drivers/media/pci/pt1/Kconfig deleted file mode 100644 index 24501d5..0000000 --- a/src/linux/drivers/media/pci/pt1/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config DVB_PT1 - tristate "PT1 cards" - depends on DVB_CORE && PCI && I2C - help - Support for Earthsoft PT1 PCI cards. - - Since these cards have no MPEG decoder onboard, they transmit - only compressed MPEG data over the PCI bus, so you need - an external software decoder to watch TV on your computer. - - Say Y or M if you own such a device and want to use it. - diff --git a/src/linux/drivers/media/pci/pt1/Makefile b/src/linux/drivers/media/pci/pt1/Makefile deleted file mode 100644 index 98e3912..0000000 --- a/src/linux/drivers/media/pci/pt1/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -earth-pt1-objs := pt1.o va1j5jf8007s.o va1j5jf8007t.o - -obj-$(CONFIG_DVB_PT1) += earth-pt1.o - -ccflags-y += -Idrivers/media/dvb-core -Idrivers/media/dvb-frontends diff --git a/src/linux/drivers/media/pci/pt3/Kconfig b/src/linux/drivers/media/pci/pt3/Kconfig deleted file mode 100644 index 16c208a..0000000 --- a/src/linux/drivers/media/pci/pt3/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config DVB_PT3 - tristate "Earthsoft PT3 cards" - depends on DVB_CORE && PCI && I2C - select DVB_TC90522 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_QM1D1C0042 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MXL301RF if MEDIA_SUBDRV_AUTOSELECT - help - Support for Earthsoft PT3 PCIe cards. - - Say Y or M if you own such a device and want to use it. diff --git a/src/linux/drivers/media/pci/pt3/Makefile b/src/linux/drivers/media/pci/pt3/Makefile deleted file mode 100644 index 396f146..0000000 --- a/src/linux/drivers/media/pci/pt3/Makefile +++ /dev/null @@ -1,8 +0,0 @@ - -earth-pt3-objs += pt3.o pt3_i2c.o pt3_dma.o - -obj-$(CONFIG_DVB_PT3) += earth-pt3.o - -ccflags-y += -Idrivers/media/dvb-core -ccflags-y += -Idrivers/media/dvb-frontends -ccflags-y += -Idrivers/media/tuners diff --git a/src/linux/drivers/media/pci/saa7134/Kconfig b/src/linux/drivers/media/pci/saa7134/Kconfig deleted file mode 100644 index b44e0d7..0000000 --- a/src/linux/drivers/media/pci/saa7134/Kconfig +++ /dev/null @@ -1,73 +0,0 @@ -config VIDEO_SAA7134 - tristate "Philips SAA7134 support" - depends on VIDEO_DEV && PCI && I2C - select VIDEOBUF2_DMA_SG - select VIDEO_TUNER - select VIDEO_TVEEPROM - select CRC32 - select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_SAA6752HS if MEDIA_SUBDRV_AUTOSELECT - ---help--- - This is a video4linux driver for Philips SAA713x based - TV cards. - - To compile this driver as a module, choose M here: the - module will be called saa7134. - -config VIDEO_SAA7134_ALSA - tristate "Philips SAA7134 DMA audio support" - depends on VIDEO_SAA7134 && SND - select SND_PCM - ---help--- - This is a video4linux driver for direct (DMA) audio in - Philips SAA713x based TV cards using ALSA - - To compile this driver as a module, choose M here: the - module will be called saa7134-alsa. - -config VIDEO_SAA7134_RC - bool "Philips SAA7134 Remote Controller support" - depends on RC_CORE - depends on VIDEO_SAA7134 - depends on !(RC_CORE=m && VIDEO_SAA7134=y) - default y - ---help--- - Enables Remote Controller support on saa7134 driver. - -config VIDEO_SAA7134_DVB - tristate "DVB/ATSC Support for saa7134 based TV cards" - depends on VIDEO_SAA7134 && DVB_CORE - select VIDEOBUF2_DVB - select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT - select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT - select DVB_NXT200X if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10086 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA826X if MEDIA_SUBDRV_AUTOSELECT - select DVB_ISL6421 if MEDIA_SUBDRV_AUTOSELECT - select DVB_ISL6405 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA827X if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT - select DVB_ZL10036 if MEDIA_SUBDRV_AUTOSELECT - select DVB_MT312 if MEDIA_SUBDRV_AUTOSELECT - select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT - select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT - select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT - select DVB_ZL10039 if MEDIA_SUBDRV_AUTOSELECT - ---help--- - This adds support for DVB cards based on the - Philips saa7134 chip. - - To compile this driver as a module, choose M here: the - module will be called saa7134-dvb. - -config VIDEO_SAA7134_GO7007 - tristate "go7007 support for saa7134 based TV cards" - depends on VIDEO_SAA7134 - depends on VIDEO_GO7007 - ---help--- - Enables saa7134 driver support for boards with go7007 - MPEG encoder (WIS Voyager or compatible). diff --git a/src/linux/drivers/media/pci/saa7146/Kconfig b/src/linux/drivers/media/pci/saa7146/Kconfig deleted file mode 100644 index da88b77..0000000 --- a/src/linux/drivers/media/pci/saa7146/Kconfig +++ /dev/null @@ -1,38 +0,0 @@ -config VIDEO_HEXIUM_GEMINI - tristate "Hexium Gemini frame grabber" - depends on PCI && VIDEO_V4L2 && I2C - select VIDEO_SAA7146_VV - ---help--- - This is a video4linux driver for the Hexium Gemini frame - grabber card by Hexium. Please note that the Gemini Dual - card is *not* fully supported. - - To compile this driver as a module, choose M here: the - module will be called hexium_gemini. - -config VIDEO_HEXIUM_ORION - tristate "Hexium HV-PCI6 and Orion frame grabber" - depends on PCI && VIDEO_V4L2 && I2C - select VIDEO_SAA7146_VV - ---help--- - This is a video4linux driver for the Hexium HV-PCI6 and - Orion frame grabber cards by Hexium. - - To compile this driver as a module, choose M here: the - module will be called hexium_orion. - -config VIDEO_MXB - tristate "Siemens-Nixdorf 'Multimedia eXtension Board'" - depends on PCI && VIDEO_V4L2 && I2C - select VIDEO_SAA7146_VV - select VIDEO_TUNER - select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_TDA9840 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_TEA6415C if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_TEA6420 if MEDIA_SUBDRV_AUTOSELECT - ---help--- - This is a video4linux driver for the 'Multimedia eXtension Board' - TV card by Siemens-Nixdorf. - - To compile this driver as a module, choose M here: the - module will be called mxb. diff --git a/src/linux/drivers/media/pci/saa7146/Makefile b/src/linux/drivers/media/pci/saa7146/Makefile deleted file mode 100644 index f3566a9..0000000 --- a/src/linux/drivers/media/pci/saa7146/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -obj-$(CONFIG_VIDEO_MXB) += mxb.o -obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o -obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o - -ccflags-y += -I$(srctree)/drivers/media/i2c diff --git a/src/linux/drivers/media/pci/saa7164/Kconfig b/src/linux/drivers/media/pci/saa7164/Kconfig deleted file mode 100644 index 9098ef5..0000000 --- a/src/linux/drivers/media/pci/saa7164/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -config VIDEO_SAA7164 - tristate "NXP SAA7164 support" - depends on DVB_CORE && VIDEO_DEV && PCI && I2C - select I2C_ALGOBIT - select FW_LOADER - select VIDEO_TUNER - select VIDEO_TVEEPROM - select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT - select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT - ---help--- - This is a video4linux driver for NXP SAA7164 based - TV cards. - - To compile this driver as a module, choose M here: the - module will be called saa7164 - diff --git a/src/linux/drivers/media/pci/smipcie/Kconfig b/src/linux/drivers/media/pci/smipcie/Kconfig deleted file mode 100644 index c11c772..0000000 --- a/src/linux/drivers/media/pci/smipcie/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config DVB_SMIPCIE - tristate "SMI PCIe DVBSky cards" - depends on DVB_CORE && PCI && I2C - select I2C_ALGOBIT - select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT - select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_M88RS6000T if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT - depends on RC_CORE - help - Support for cards with SMI PCIe bridge: - - DVBSky S950 V3 - - DVBSky S952 V3 - - DVBSky T9580 V3 - - Say Y or M if you own such a device and want to use it. - If unsure say N. diff --git a/src/linux/drivers/media/pci/smipcie/Makefile b/src/linux/drivers/media/pci/smipcie/Makefile deleted file mode 100644 index 013bc3f..0000000 --- a/src/linux/drivers/media/pci/smipcie/Makefile +++ /dev/null @@ -1,9 +0,0 @@ - -smipcie-objs := smipcie-main.o smipcie-ir.o - -obj-$(CONFIG_DVB_SMIPCIE) += smipcie.o - -ccflags-y += -Idrivers/media/tuners -ccflags-y += -Idrivers/media/dvb-core -ccflags-y += -Idrivers/media/dvb-frontends - diff --git a/src/linux/drivers/media/pci/solo6x10/Kconfig b/src/linux/drivers/media/pci/solo6x10/Kconfig deleted file mode 100644 index 0fb91dc..0000000 --- a/src/linux/drivers/media/pci/solo6x10/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -config VIDEO_SOLO6X10 - tristate "Bluecherry / Softlogic 6x10 capture cards (MPEG-4/H.264)" - depends on PCI && VIDEO_DEV && SND && I2C - depends on HAS_DMA - select BITREVERSE - select FONT_SUPPORT - select FONT_8x16 - select VIDEOBUF2_DMA_SG - select VIDEOBUF2_DMA_CONTIG - select SND_PCM - select FONT_8x16 - ---help--- - This driver supports the Bluecherry H.264 and MPEG-4 hardware - compression capture cards and other Softlogic-based ones. - - Following cards have been tested: - * Bluecherry BC-H16480A (PCIe, 16 port, H.264) - * Bluecherry BC-H04120A (PCIe, 4 port, H.264) - * Bluecherry BC-H04120A-MPCI (Mini-PCI, 4 port, H.264) - * Bluecherry BC-04120A (PCIe, 4 port, MPEG-4) diff --git a/src/linux/drivers/media/pci/sta2x11/Kconfig b/src/linux/drivers/media/pci/sta2x11/Kconfig deleted file mode 100644 index e03587b..0000000 --- a/src/linux/drivers/media/pci/sta2x11/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -config STA2X11_VIP - tristate "STA2X11 VIP Video For Linux" - depends on STA2X11 - depends on HAS_DMA - select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT - select VIDEOBUF2_DMA_CONTIG - depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS - depends on VIDEO_V4L2_SUBDEV_API - depends on I2C - help - Say Y for support for STA2X11 VIP (Video Input Port) capture - device. - - To compile this driver as a module, choose M here: the - module will be called sta2x11_vip. diff --git a/src/linux/drivers/media/pci/ttpci/Kconfig b/src/linux/drivers/media/pci/ttpci/Kconfig deleted file mode 100644 index 7b83151..0000000 --- a/src/linux/drivers/media/pci/ttpci/Kconfig +++ /dev/null @@ -1,158 +0,0 @@ -config DVB_AV7110_IR - bool - -config DVB_AV7110 - tristate "AV7110 cards" - depends on DVB_CORE && PCI && I2C - select TTPCI_EEPROM - select VIDEO_SAA7146_VV - select DVB_AV7110_IR if INPUT_EVDEV=y || INPUT_EVDEV=DVB_AV7110 - depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV - select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT - select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT - select DVB_SP8870 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT - select DVB_L64781 if MEDIA_SUBDRV_AUTOSELECT - select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT - help - Support for SAA7146 and AV7110 based DVB cards as produced - by Fujitsu-Siemens, Technotrend, Hauppauge and others. - - This driver only supports the fullfeatured cards with - onboard MPEG2 decoder. - - This driver needs an external firmware. Please use the script - "/Documentation/dvb/get_dvb_firmware av7110" to - download/extract it, and then copy it to /usr/lib/hotplug/firmware - or /lib/firmware (depending on configuration of firmware hotplug). - - Alternatively, you can download the file and use the kernel's - EXTRA_FIRMWARE configuration option to build it into your - kernel image by adding the filename to the EXTRA_FIRMWARE - configuration option string. - - Say Y if you own such a card and want to use it. - -config DVB_AV7110_OSD - bool "AV7110 OSD support" - depends on DVB_AV7110 - default y if DVB_AV7110=y || DVB_AV7110=m - help - The AV7110 firmware provides some code to generate an OnScreenDisplay - on the video output. This is kind of nonstandard and not guaranteed to - be maintained. - - Anyway, some popular DVB software like VDR uses this OSD to render - its menus, so say Y if you want to use this software. - - All other people say N. - -config DVB_BUDGET_CORE - tristate "SAA7146 DVB cards (aka Budget, Nova-PCI)" - depends on DVB_CORE && PCI && I2C - select VIDEO_SAA7146 - select TTPCI_EEPROM - help - Support for simple SAA7146 based DVB cards - (so called Budget- or Nova-PCI cards) without onboard - MPEG2 decoder. - -config DVB_BUDGET - tristate "Budget cards" - depends on DVB_BUDGET_CORE && I2C - select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT - select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT - select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT - select DVB_L64781 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT - select DVB_S5H1420 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10086 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA826X if MEDIA_SUBDRV_AUTOSELECT - select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT - select DVB_ISL6423 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT - help - Support for simple SAA7146 based DVB cards (so called Budget- - or Nova-PCI cards) without onboard MPEG2 decoder, and without - analog inputs or an onboard Common Interface connector. - - Say Y if you own such a card and want to use it. - - To compile this driver as a module, choose M here: the - module will be called budget. - -config DVB_BUDGET_CI - tristate "Budget cards with onboard CI connector" - depends on DVB_BUDGET_CORE && I2C - select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT - select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA827X if MEDIA_SUBDRV_AUTOSELECT - depends on RC_CORE - help - Support for simple SAA7146 based DVB cards - (so called Budget- or Nova-PCI cards) without onboard - MPEG2 decoder, but with onboard Common Interface connector. - - Note: The Common Interface is not yet supported by this driver - due to lack of information from the vendor. - - Say Y if you own such a card and want to use it. - - To compile this driver as a module, choose M here: the - module will be called budget-ci. - -config DVB_BUDGET_AV - tristate "Budget cards with analog video inputs" - depends on DVB_BUDGET_CORE && I2C - select VIDEO_SAA7146_VV - depends on VIDEO_DEV # dependencies of VIDEO_SAA7146_VV - select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10021 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA8261 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TUA6100 if MEDIA_SUBDRV_AUTOSELECT - help - Support for simple SAA7146 based DVB cards - (so called Budget- or Nova-PCI cards) without onboard - MPEG2 decoder, but with one or more analog video inputs. - - Say Y if you own such a card and want to use it. - - To compile this driver as a module, choose M here: the - module will be called budget-av. - -config DVB_BUDGET_PATCH - tristate "AV7110 cards with Budget Patch" - depends on DVB_BUDGET_CORE && I2C - depends on DVB_AV7110 - select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT - select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT - help - Support for Budget Patch (full TS) modification on - SAA7146+AV7110 based cards (DVB-S cards). This - driver doesn't use onboard MPEG2 decoder. The - card is driven in Budget-only mode. Card is - required to have loaded firmware to tune properly. - Firmware can be loaded by insertion and removal of - standard AV7110 driver prior to loading this - driver. - - Say Y if you own such a card and want to use it. - - To compile this driver as a module, choose M here: the - module will be called budget-patch. diff --git a/src/linux/drivers/media/pci/ttpci/Makefile b/src/linux/drivers/media/pci/ttpci/Makefile deleted file mode 100644 index 49f71b1..0000000 --- a/src/linux/drivers/media/pci/ttpci/Makefile +++ /dev/null @@ -1,21 +0,0 @@ -# -# Makefile for the kernel SAA7146 FULL TS DVB device driver -# and the AV7110 DVB device driver -# - -dvb-ttpci-objs := av7110_hw.o av7110_v4l.o av7110_av.o av7110_ca.o av7110.o av7110_ipack.o - -ifdef CONFIG_DVB_AV7110_IR -dvb-ttpci-objs += av7110_ir.o -endif - -obj-$(CONFIG_TTPCI_EEPROM) += ttpci-eeprom.o -obj-$(CONFIG_DVB_BUDGET_CORE) += budget-core.o -obj-$(CONFIG_DVB_BUDGET) += budget.o -obj-$(CONFIG_DVB_BUDGET_AV) += budget-av.o -obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o -obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o -obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o - -ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends/ -ccflags-y += -Idrivers/media/tuners diff --git a/src/linux/drivers/media/pci/tw5864/Kconfig b/src/linux/drivers/media/pci/tw5864/Kconfig deleted file mode 100644 index 87c8f32..0000000 --- a/src/linux/drivers/media/pci/tw5864/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config VIDEO_TW5864 - tristate "Techwell TW5864 video/audio grabber and encoder" - depends on VIDEO_DEV && PCI && VIDEO_V4L2 - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - ---help--- - Support for boards based on Techwell TW5864 chip which provides - multichannel video & audio grabbing and encoding (H.264, MJPEG, - ADPCM G.726). - - To compile this driver as a module, choose M here: the - module will be called tw5864. diff --git a/src/linux/drivers/media/pci/tw68/Kconfig b/src/linux/drivers/media/pci/tw68/Kconfig deleted file mode 100644 index 95d5d52..0000000 --- a/src/linux/drivers/media/pci/tw68/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config VIDEO_TW68 - tristate "Techwell tw68x Video For Linux" - depends on VIDEO_DEV && PCI && VIDEO_V4L2 - select VIDEOBUF2_DMA_SG - ---help--- - Support for Techwell tw68xx based frame grabber boards. - - To compile this driver as a module, choose M here: the - module will be called tw68. diff --git a/src/linux/drivers/media/pci/tw686x/Kconfig b/src/linux/drivers/media/pci/tw686x/Kconfig deleted file mode 100644 index 34ff377..0000000 --- a/src/linux/drivers/media/pci/tw686x/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -config VIDEO_TW686X - tristate "Intersil/Techwell TW686x video capture cards" - depends on PCI && VIDEO_DEV && VIDEO_V4L2 && SND - depends on HAS_DMA - select VIDEOBUF2_VMALLOC - select VIDEOBUF2_DMA_CONTIG - select VIDEOBUF2_DMA_SG - select SND_PCM - help - Support for Intersil/Techwell TW686x-based frame grabber cards. - - Currently supported chips: - - TW6864 (4 video channels), - - TW6865 (4 video channels, not tested, second generation chip), - - TW6868 (8 video channels but only 4 first channels using - built-in video decoder are supported, not tested), - - TW6869 (8 video channels, second generation chip). - - To compile this driver as a module, choose M here: the module - will be named tw686x. diff --git a/src/linux/drivers/media/pci/zoran/Kconfig b/src/linux/drivers/media/pci/zoran/Kconfig deleted file mode 100644 index 39ec35b..0000000 --- a/src/linux/drivers/media/pci/zoran/Kconfig +++ /dev/null @@ -1,75 +0,0 @@ -config VIDEO_ZORAN - tristate "Zoran ZR36057/36067 Video For Linux" - depends on PCI && I2C_ALGOBIT && VIDEO_V4L2 && VIRT_TO_BUS - depends on !ALPHA - help - Say Y for support for MJPEG capture cards based on the Zoran - 36057/36067 PCI controller chipset. This includes the Iomega - Buz, Pinnacle DC10+ and the Linux Media Labs LML33. There is - a driver homepage at . For - more information, check . - - To compile this driver as a module, choose M here: the - module will be called zr36067. - -config VIDEO_ZORAN_DC30 - tristate "Pinnacle/Miro DC30(+) support" - depends on VIDEO_ZORAN - select VIDEO_ADV7175 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_VPX3220 if MEDIA_SUBDRV_AUTOSELECT - help - Support for the Pinnacle/Miro DC30(+) MJPEG capture/playback - card. This also supports really old DC10 cards based on the - zr36050 MJPEG codec and zr36016 VFE. - -config VIDEO_ZORAN_ZR36060 - tristate "Zoran ZR36060" - depends on VIDEO_ZORAN - help - Say Y to support Zoran boards based on 36060 chips. - This includes Iomega Buz, Pinnacle DC10, Linux media Labs 33 - and 33 R10 and AverMedia 6 boards. - -config VIDEO_ZORAN_BUZ - tristate "Iomega Buz support" - depends on VIDEO_ZORAN_ZR36060 - select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_SAA7185 if MEDIA_SUBDRV_AUTOSELECT - help - Support for the Iomega Buz MJPEG capture/playback card. - -config VIDEO_ZORAN_DC10 - tristate "Pinnacle/Miro DC10(+) support" - depends on VIDEO_ZORAN_ZR36060 - select VIDEO_SAA7110 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_ADV7175 if MEDIA_SUBDRV_AUTOSELECT - help - Support for the Pinnacle/Miro DC10(+) MJPEG capture/playback - card. - -config VIDEO_ZORAN_LML33 - tristate "Linux Media Labs LML33 support" - depends on VIDEO_ZORAN_ZR36060 - select VIDEO_BT819 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_BT856 if MEDIA_SUBDRV_AUTOSELECT - help - Support for the Linux Media Labs LML33 MJPEG capture/playback - card. - -config VIDEO_ZORAN_LML33R10 - tristate "Linux Media Labs LML33R10 support" - depends on VIDEO_ZORAN_ZR36060 - select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_ADV7170 if MEDIA_SUBDRV_AUTOSELECT - help - support for the Linux Media Labs LML33R10 MJPEG capture/playback - card. - -config VIDEO_ZORAN_AVS6EYES - tristate "AverMedia 6 Eyes support" - depends on VIDEO_ZORAN_ZR36060 - select VIDEO_BT856 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_BT866 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_KS0127 if MEDIA_SUBDRV_AUTOSELECT - help - Support for the AverMedia 6 Eyes video surveillance card. diff --git a/src/linux/drivers/media/platform/Kconfig b/src/linux/drivers/media/platform/Kconfig deleted file mode 100644 index ce4a96f..0000000 --- a/src/linux/drivers/media/platform/Kconfig +++ /dev/null @@ -1,378 +0,0 @@ -# -# Platform drivers -# Most drivers here are currently for webcam support - -menuconfig V4L_PLATFORM_DRIVERS - bool "V4L platform devices" - depends on MEDIA_CAMERA_SUPPORT - default n - ---help--- - Say Y here to enable support for platform-specific V4L drivers. - -if V4L_PLATFORM_DRIVERS - -source "drivers/media/platform/marvell-ccic/Kconfig" - -config VIDEO_VIA_CAMERA - tristate "VIAFB camera controller support" - depends on FB_VIA - select VIDEOBUF_DMA_SG - select VIDEO_OV7670 - help - Driver support for the integrated camera controller in VIA - Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems - with ov7670 sensors. - -# -# Platform multimedia device configuration -# - -source "drivers/media/platform/davinci/Kconfig" - -source "drivers/media/platform/omap/Kconfig" - -source "drivers/media/platform/blackfin/Kconfig" - -config VIDEO_SH_VOU - tristate "SuperH VOU video output driver" - depends on MEDIA_CAMERA_SUPPORT - depends on VIDEO_DEV && I2C && HAS_DMA - depends on ARCH_SHMOBILE || COMPILE_TEST - select VIDEOBUF2_DMA_CONTIG - help - Support for the Video Output Unit (VOU) on SuperH SoCs. - -config VIDEO_VIU - tristate "Freescale VIU Video Driver" - depends on VIDEO_V4L2 && PPC_MPC512x - select VIDEOBUF_DMA_CONTIG - default y - ---help--- - Support for Freescale VIU video driver. This device captures - video data, or overlays video on DIU frame buffer. - - Say Y here if you want to enable VIU device on MPC5121e Rev2+. - In doubt, say N. - -config VIDEO_M32R_AR - tristate "AR devices" - depends on VIDEO_V4L2 - depends on M32R || COMPILE_TEST - ---help--- - This is a video4linux driver for the Renesas AR (Artificial Retina) - camera module. - -config VIDEO_M32R_AR_M64278 - tristate "AR device with color module M64278(VGA)" - depends on PLAT_M32700UT - select VIDEO_M32R_AR - ---help--- - This is a video4linux driver for the Renesas AR (Artificial - Retina) with M64278E-800 camera module. - This module supports VGA(640x480 pixels) resolutions. - - To compile this driver as a module, choose M here: the - module will be called arv. - -config VIDEO_OMAP3 - tristate "OMAP 3 Camera support" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3 - depends on HAS_DMA && OF - depends on OMAP_IOMMU - select ARM_DMA_USE_IOMMU - select VIDEOBUF2_DMA_CONTIG - select MFD_SYSCON - ---help--- - Driver for an OMAP 3 camera controller. - -config VIDEO_OMAP3_DEBUG - bool "OMAP 3 Camera debug messages" - depends on VIDEO_OMAP3 - ---help--- - Enable debug messages on OMAP 3 camera controller driver. - -config VIDEO_PXA27x - tristate "PXA27x Quick Capture Interface driver" - depends on VIDEO_DEV && HAS_DMA - depends on PXA27x || COMPILE_TEST - select VIDEOBUF2_DMA_SG - select SG_SPLIT - ---help--- - This is a v4l2 driver for the PXA27x Quick Capture Interface - -config VIDEO_S3C_CAMIF - tristate "Samsung S3C24XX/S3C64XX SoC Camera Interface driver" - depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API - depends on PM - depends on ARCH_S3C64XX || PLAT_S3C24XX || COMPILE_TEST - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - ---help--- - This is a v4l2 driver for s3c24xx and s3c64xx SoC series camera - host interface (CAMIF). - - To compile this driver as a module, choose M here: the module - will be called s3c-camif. - -source "drivers/media/platform/soc_camera/Kconfig" -source "drivers/media/platform/exynos4-is/Kconfig" -source "drivers/media/platform/am437x/Kconfig" -source "drivers/media/platform/xilinx/Kconfig" -source "drivers/media/platform/rcar-vin/Kconfig" -source "drivers/media/platform/atmel/Kconfig" - -config VIDEO_TI_CAL - tristate "TI CAL (Camera Adaptation Layer) driver" - depends on VIDEO_DEV && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on SOC_DRA7XX || COMPILE_TEST - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - default n - ---help--- - Support for the TI CAL (Camera Adaptation Layer) block - found on DRA72X SoC. - In TI Technical Reference Manual this module is referred as - Camera Interface Subsystem (CAMSS). - -endif # V4L_PLATFORM_DRIVERS - -menuconfig V4L_MEM2MEM_DRIVERS - bool "Memory-to-memory multimedia devices" - depends on VIDEO_V4L2 - depends on MEDIA_CAMERA_SUPPORT - default n - ---help--- - Say Y here to enable selecting drivers for V4L devices that - use system memory for both source and destination buffers, as opposed - to capture and output drivers, which use memory buffers for just - one of those. - -if V4L_MEM2MEM_DRIVERS - -config VIDEO_CODA - tristate "Chips&Media Coda multi-standard codec IP" - depends on VIDEO_DEV && VIDEO_V4L2 && ARCH_MXC - depends on HAS_DMA - select SRAM - select VIDEOBUF2_DMA_CONTIG - select VIDEOBUF2_VMALLOC - select V4L2_MEM2MEM_DEV - select GENERIC_ALLOCATOR - ---help--- - Coda is a range of video codec IPs that supports - H.264, MPEG-4, and other video formats. - -config VIDEO_MEDIATEK_VPU - tristate "Mediatek Video Processor Unit" - depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA - depends on ARCH_MEDIATEK || COMPILE_TEST - ---help--- - This driver provides downloading VPU firmware and - communicating with VPU. This driver for hw video - codec embedded in Mediatek's MT8173 SOCs. It is able - to handle video decoding/encoding in a range of formats. - - To compile this driver as a module, choose M here: the - module will be called mtk-vpu. - -config VIDEO_MEDIATEK_VCODEC - tristate "Mediatek Video Codec driver" - depends on MTK_IOMMU || COMPILE_TEST - depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA - depends on ARCH_MEDIATEK || COMPILE_TEST - select VIDEOBUF2_DMA_CONTIG - select V4L2_MEM2MEM_DEV - select VIDEO_MEDIATEK_VPU - default n - ---help--- - Mediatek video codec driver provides HW capability to - encode and decode in a range of video formats - This driver rely on VPU driver to communicate with VPU. - - To compile this driver as a module, choose M here: the - module will be called mtk-vcodec - -config VIDEO_MEM2MEM_DEINTERLACE - tristate "Deinterlace support" - depends on VIDEO_DEV && VIDEO_V4L2 && DMA_ENGINE - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - select V4L2_MEM2MEM_DEV - help - Generic deinterlacing V4L2 driver. - -config VIDEO_SAMSUNG_S5P_G2D - tristate "Samsung S5P and EXYNOS4 G2D 2d graphics accelerator driver" - depends on VIDEO_DEV && VIDEO_V4L2 - depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - select V4L2_MEM2MEM_DEV - default n - ---help--- - This is a v4l2 driver for Samsung S5P and EXYNOS4 G2D - 2d graphics accelerator. - -config VIDEO_SAMSUNG_S5P_JPEG - tristate "Samsung S5P/Exynos3250/Exynos4 JPEG codec driver" - depends on VIDEO_DEV && VIDEO_V4L2 - depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - select V4L2_MEM2MEM_DEV - ---help--- - This is a v4l2 driver for Samsung S5P, EXYNOS3250 - and EXYNOS4 JPEG codec - -config VIDEO_SAMSUNG_S5P_MFC - tristate "Samsung S5P MFC Video Codec" - depends on VIDEO_DEV && VIDEO_V4L2 - depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - default n - help - MFC 5.1 and 6.x driver for V4L2 - -config VIDEO_MX2_EMMAPRP - tristate "MX2 eMMa-PrP support" - depends on VIDEO_DEV && VIDEO_V4L2 - depends on SOC_IMX27 || COMPILE_TEST - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - select V4L2_MEM2MEM_DEV - help - MX2X chips have a PrP that can be used to process buffers from - memory to memory. Operations include resizing and format - conversion. - -config VIDEO_SAMSUNG_EXYNOS_GSC - tristate "Samsung Exynos G-Scaler driver" - depends on VIDEO_DEV && VIDEO_V4L2 - depends on ARCH_EXYNOS5 || COMPILE_TEST - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - select V4L2_MEM2MEM_DEV - help - This is a v4l2 driver for Samsung EXYNOS5 SoC G-Scaler. - -config VIDEO_STI_BDISP - tristate "STMicroelectronics BDISP 2D blitter driver" - depends on VIDEO_DEV && VIDEO_V4L2 - depends on HAS_DMA - depends on ARCH_STI || COMPILE_TEST - select VIDEOBUF2_DMA_CONTIG - select V4L2_MEM2MEM_DEV - help - This v4l2 mem2mem driver is a 2D blitter for STMicroelectronics SoC. - -config VIDEO_STI_HVA - tristate "STMicroelectronics HVA multi-format video encoder V4L2 driver" - depends on VIDEO_DEV && VIDEO_V4L2 - depends on HAS_DMA - depends on ARCH_STI || COMPILE_TEST - select VIDEOBUF2_DMA_CONTIG - select V4L2_MEM2MEM_DEV - help - This V4L2 driver enables HVA (Hardware Video Accelerator) multi-format - video encoder of STMicroelectronics SoC, allowing hardware encoding of - raw uncompressed formats in various compressed video bitstreams format. - - To compile this driver as a module, choose M here: - the module will be called st-hva. - -config VIDEO_SH_VEU - tristate "SuperH VEU mem2mem video processing driver" - depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA - select VIDEOBUF2_DMA_CONTIG - select V4L2_MEM2MEM_DEV - help - Support for the Video Engine Unit (VEU) on SuperH and - SH-Mobile SoCs. - -config VIDEO_RENESAS_JPU - tristate "Renesas JPEG Processing Unit" - depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA - depends on ARCH_RENESAS || COMPILE_TEST - select VIDEOBUF2_DMA_CONTIG - select V4L2_MEM2MEM_DEV - ---help--- - This is a V4L2 driver for the Renesas JPEG Processing Unit. - - To compile this driver as a module, choose M here: the module - will be called rcar_jpu. - -config VIDEO_RENESAS_FCP - tristate "Renesas Frame Compression Processor" - depends on ARCH_RENESAS || COMPILE_TEST - depends on OF - ---help--- - This is a driver for the Renesas Frame Compression Processor (FCP). - The FCP is a companion module of video processing modules in the - Renesas R-Car Gen3 SoCs. It handles memory access for the codec, - VSP and FDP modules. - - To compile this driver as a module, choose M here: the module - will be called rcar-fcp. - -config VIDEO_RENESAS_VSP1 - tristate "Renesas VSP1 Video Processing Engine" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA - depends on (ARCH_RENESAS && OF) || COMPILE_TEST - depends on (!ARM64 && !VIDEO_RENESAS_FCP) || VIDEO_RENESAS_FCP - select VIDEOBUF2_DMA_CONTIG - ---help--- - This is a V4L2 driver for the Renesas VSP1 video processing engine. - - To compile this driver as a module, choose M here: the module - will be called vsp1. - -config VIDEO_TI_VPE - tristate "TI VPE (Video Processing Engine) driver" - depends on VIDEO_DEV && VIDEO_V4L2 - depends on SOC_DRA7XX || COMPILE_TEST - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - select V4L2_MEM2MEM_DEV - default n - ---help--- - Support for the TI VPE(Video Processing Engine) block - found on DRA7XX SoC. - -config VIDEO_TI_VPE_DEBUG - bool "VPE debug messages" - depends on VIDEO_TI_VPE - ---help--- - Enable debug messages on VPE driver. - -endif # V4L_MEM2MEM_DRIVERS - -menuconfig V4L_TEST_DRIVERS - bool "Media test drivers" - depends on MEDIA_CAMERA_SUPPORT - -if V4L_TEST_DRIVERS - -source "drivers/media/platform/vivid/Kconfig" - -config VIDEO_VIM2M - tristate "Virtual Memory-to-Memory Driver" - depends on VIDEO_DEV && VIDEO_V4L2 - select VIDEOBUF2_VMALLOC - select V4L2_MEM2MEM_DEV - default n - ---help--- - This is a virtual test device for the memory-to-memory driver - framework. -endif #V4L_TEST_DRIVERS - -menuconfig DVB_PLATFORM_DRIVERS - bool "DVB platform devices" - depends on MEDIA_DIGITAL_TV_SUPPORT - default n - ---help--- - Say Y here to enable support for platform-specific Digital TV drivers. - -if DVB_PLATFORM_DRIVERS -source "drivers/media/platform/sti/c8sectpfe/Kconfig" -endif #DVB_PLATFORM_DRIVERS diff --git a/src/linux/drivers/media/platform/Makefile b/src/linux/drivers/media/platform/Makefile deleted file mode 100644 index 40b18d1..0000000 --- a/src/linux/drivers/media/platform/Makefile +++ /dev/null @@ -1,68 +0,0 @@ -# -# Makefile for the video capture/playback device drivers. -# - -obj-$(CONFIG_VIDEO_M32R_AR_M64278) += arv.o - -obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o -obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/ -obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/ - -obj-$(CONFIG_VIDEO_OMAP3) += omap3isp/ -obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o - -obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o - -obj-$(CONFIG_VIDEO_VIVID) += vivid/ -obj-$(CONFIG_VIDEO_VIM2M) += vim2m.o - -obj-$(CONFIG_VIDEO_TI_VPE) += ti-vpe/ - -obj-$(CONFIG_VIDEO_TI_CAL) += ti-vpe/ - -obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o -obj-$(CONFIG_VIDEO_CODA) += coda/ - -obj-$(CONFIG_VIDEO_SH_VEU) += sh_veu.o - -obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE) += m2m-deinterlace.o - -obj-$(CONFIG_VIDEO_S3C_CAMIF) += s3c-camif/ -obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS4_IS) += exynos4-is/ -obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg/ -obj-$(CONFIG_VIDEO_SAMSUNG_S5P_MFC) += s5p-mfc/ - -obj-$(CONFIG_VIDEO_SAMSUNG_S5P_G2D) += s5p-g2d/ -obj-$(CONFIG_VIDEO_SAMSUNG_EXYNOS_GSC) += exynos-gsc/ - -obj-$(CONFIG_VIDEO_STI_BDISP) += sti/bdisp/ -obj-$(CONFIG_VIDEO_STI_HVA) += sti/hva/ -obj-$(CONFIG_DVB_C8SECTPFE) += sti/c8sectpfe/ - -obj-$(CONFIG_BLACKFIN) += blackfin/ - -obj-$(CONFIG_ARCH_DAVINCI) += davinci/ - -obj-$(CONFIG_VIDEO_SH_VOU) += sh_vou.o - -obj-$(CONFIG_SOC_CAMERA) += soc_camera/ - -obj-$(CONFIG_VIDEO_RENESAS_FCP) += rcar-fcp.o -obj-$(CONFIG_VIDEO_RENESAS_JPU) += rcar_jpu.o -obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/ - -obj-y += omap/ - -obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/ - -obj-$(CONFIG_VIDEO_XILINX) += xilinx/ - -obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar-vin/ - -obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel/ - -ccflags-y += -I$(srctree)/drivers/media/i2c - -obj-$(CONFIG_VIDEO_MEDIATEK_VPU) += mtk-vpu/ - -obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec/ diff --git a/src/linux/drivers/media/platform/am437x/Kconfig b/src/linux/drivers/media/platform/am437x/Kconfig deleted file mode 100644 index 42d9c18..0000000 --- a/src/linux/drivers/media/platform/am437x/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config VIDEO_AM437X_VPFE - tristate "TI AM437x VPFE video capture driver" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA - depends on SOC_AM43XX || COMPILE_TEST - select VIDEOBUF2_DMA_CONTIG - help - Support for AM437x Video Processing Front End based Video - Capture Driver. - - To compile this driver as a module, choose M here. The module - will be called am437x-vpfe. diff --git a/src/linux/drivers/media/platform/atmel/Kconfig b/src/linux/drivers/media/platform/atmel/Kconfig deleted file mode 100644 index 867dca2..0000000 --- a/src/linux/drivers/media/platform/atmel/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config VIDEO_ATMEL_ISC - tristate "ATMEL Image Sensor Controller (ISC) support" - depends on VIDEO_V4L2 && COMMON_CLK && VIDEO_V4L2_SUBDEV_API && HAS_DMA - depends on ARCH_AT91 || COMPILE_TEST - select VIDEOBUF2_DMA_CONTIG - select REGMAP_MMIO - help - This module makes the ATMEL Image Sensor Controller available - as a v4l2 device. \ No newline at end of file diff --git a/src/linux/drivers/media/platform/blackfin/Kconfig b/src/linux/drivers/media/platform/blackfin/Kconfig deleted file mode 100644 index 68fa901..0000000 --- a/src/linux/drivers/media/platform/blackfin/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -config VIDEO_BLACKFIN_CAPTURE - tristate "Blackfin Video Capture Driver" - depends on VIDEO_V4L2 && BLACKFIN && I2C - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - help - V4L2 bridge driver for Blackfin video capture device. - Choose PPI or EPPI as its interface. - - To compile this driver as a module, choose M here: the - module will be called bfin_capture. - -config VIDEO_BLACKFIN_PPI - tristate - depends on VIDEO_BLACKFIN_CAPTURE - default VIDEO_BLACKFIN_CAPTURE diff --git a/src/linux/drivers/media/platform/davinci/Kconfig b/src/linux/drivers/media/platform/davinci/Kconfig deleted file mode 100644 index 554e710..0000000 --- a/src/linux/drivers/media/platform/davinci/Kconfig +++ /dev/null @@ -1,94 +0,0 @@ -config VIDEO_DAVINCI_VPIF_DISPLAY - tristate "TI DaVinci VPIF V4L2-Display driver" - depends on VIDEO_V4L2 - depends on ARCH_DAVINCI || COMPILE_TEST - depends on HAS_DMA - depends on I2C - select VIDEOBUF2_DMA_CONTIG - select VIDEO_ADV7343 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_THS7303 if MEDIA_SUBDRV_AUTOSELECT - help - Enables Davinci VPIF module used for display devices. - This module is used for display on TI DM6467/DA850/OMAPL138 - SoCs. - - To compile this driver as a module, choose M here. There will - be two modules called vpif.ko and vpif_display.ko - -config VIDEO_DAVINCI_VPIF_CAPTURE - tristate "TI DaVinci VPIF video capture driver" - depends on VIDEO_V4L2 - depends on ARCH_DAVINCI || COMPILE_TEST - depends on HAS_DMA - depends on I2C - select VIDEOBUF2_DMA_CONTIG - help - Enables Davinci VPIF module used for capture devices. - This module is used for capture on TI DM6467/DA850/OMAPL138 - SoCs. - - To compile this driver as a module, choose M here. There will - be two modules called vpif.ko and vpif_capture.ko - -config VIDEO_DM6446_CCDC - tristate "TI DM6446 CCDC video capture driver" - depends on VIDEO_V4L2 - depends on ARCH_DAVINCI || COMPILE_TEST - depends on HAS_DMA - depends on I2C - select VIDEOBUF_DMA_CONTIG - help - Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces - with decoder modules such as TVP5146 over BT656 or - sensor module such as MT9T001 over a raw interface. This - module configures the interface and CCDC/ISIF to do - video frame capture from slave decoders. - - To compile this driver as a module, choose M here. There will - be three modules called vpfe_capture.ko, vpss.ko and dm644x_ccdc.ko - -config VIDEO_DM355_CCDC - tristate "TI DM355 CCDC video capture driver" - depends on VIDEO_V4L2 - depends on ARCH_DAVINCI || COMPILE_TEST - depends on HAS_DMA - depends on I2C - select VIDEOBUF_DMA_CONTIG - help - Enables DM355 CCD hw module. DM355 CCDC hw interfaces - with decoder modules such as TVP5146 over BT656 or - sensor module such as MT9T001 over a raw interface. This - module configures the interface and CCDC/ISIF to do - video frame capture from a slave decoders - - To compile this driver as a module, choose M here. There will - be three modules called vpfe_capture.ko, vpss.ko and dm355_ccdc.ko - -config VIDEO_DM365_ISIF - tristate "TI DM365 ISIF video capture driver" - depends on VIDEO_V4L2 && ARCH_DAVINCI - depends on HAS_DMA - depends on I2C - select VIDEOBUF_DMA_CONTIG - help - Enables ISIF hw module. This is the hardware module for - configuring ISIF in VPFE to capture Raw Bayer RGB data from - a image sensor or YUV data from a YUV source. - - To compile this driver as a module, choose M here. There will - be three modules called vpfe_capture.ko, vpss.ko and isif.ko - -config VIDEO_DAVINCI_VPBE_DISPLAY - tristate "TI DaVinci VPBE V4L2-Display driver" - depends on VIDEO_V4L2 && ARCH_DAVINCI - depends on HAS_DMA - depends on I2C - select VIDEOBUF2_DMA_CONTIG - help - Enables Davinci VPBE module used for display devices. - This module is used for display on TI DM644x/DM365/DM355 - based display devices. - - To compile this driver as a module, choose M here. There will - be five modules created called vpss.ko, vpbe.ko, vpbe_osd.ko, - vpbe_venc.ko and vpbe_display.ko diff --git a/src/linux/drivers/media/platform/exynos4-is/Kconfig b/src/linux/drivers/media/platform/exynos4-is/Kconfig deleted file mode 100644 index 57d42c6..0000000 --- a/src/linux/drivers/media/platform/exynos4-is/Kconfig +++ /dev/null @@ -1,81 +0,0 @@ - -config VIDEO_SAMSUNG_EXYNOS4_IS - tristate "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST - depends on OF && COMMON_CLK - help - Say Y here to enable camera host interface devices for - Samsung S5P and EXYNOS SoC series. - -if VIDEO_SAMSUNG_EXYNOS4_IS - -config VIDEO_EXYNOS4_IS_COMMON - tristate - -config VIDEO_S5P_FIMC - tristate "S5P/EXYNOS4 FIMC/CAMIF camera interface driver" - depends on I2C - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - select V4L2_MEM2MEM_DEV - select MFD_SYSCON - select VIDEO_EXYNOS4_IS_COMMON - help - This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC camera host - interface and video postprocessor (FIMC) devices. - - To compile this driver as a module, choose M here: the - module will be called s5p-fimc. - -config VIDEO_S5P_MIPI_CSIS - tristate "S5P/EXYNOS MIPI-CSI2 receiver (MIPI-CSIS) driver" - depends on REGULATOR - select GENERIC_PHY - help - This is a V4L2 driver for Samsung S5P and EXYNOS4 SoC MIPI-CSI2 - receiver (MIPI-CSIS) devices. - - To compile this driver as a module, choose M here: the - module will be called s5p-csis. - -if SOC_EXYNOS4212 || SOC_EXYNOS4412 || SOC_EXYNOS5250 - -config VIDEO_EXYNOS_FIMC_LITE - tristate "EXYNOS FIMC-LITE camera interface driver" - depends on I2C - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - select VIDEO_EXYNOS4_IS_COMMON - help - This is a V4L2 driver for Samsung EXYNOS4/5 SoC FIMC-LITE camera - host interface. - - To compile this driver as a module, choose M here: the - module will be called exynos-fimc-lite. -endif - -config VIDEO_EXYNOS4_FIMC_IS - tristate "EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver" - depends on I2C - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - depends on OF - select FW_LOADER - help - This is a V4L2 driver for Samsung EXYNOS4x12 SoC series - FIMC-IS (Imaging Subsystem). - - To compile this driver as a module, choose M here: the - module will be called exynos4-fimc-is. - -config VIDEO_EXYNOS4_ISP_DMA_CAPTURE - bool "EXYNOS4x12 FIMC-IS ISP Direct DMA capture support" - depends on VIDEO_EXYNOS4_FIMC_IS - select VIDEO_EXYNOS4_IS_COMMON - default y - help - This option enables an additional video device node exposing a V4L2 - video capture interface for the FIMC-IS ISP raw (Bayer) capture DMA. - -endif # VIDEO_SAMSUNG_EXYNOS4_IS diff --git a/src/linux/drivers/media/platform/marvell-ccic/Kconfig b/src/linux/drivers/media/platform/marvell-ccic/Kconfig deleted file mode 100644 index 4bf5bd1..0000000 --- a/src/linux/drivers/media/platform/marvell-ccic/Kconfig +++ /dev/null @@ -1,26 +0,0 @@ -config VIDEO_CAFE_CCIC - tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support" - depends on PCI && I2C && VIDEO_V4L2 - depends on HAS_DMA - select VIDEO_OV7670 - select VIDEOBUF2_VMALLOC - select VIDEOBUF2_DMA_CONTIG - select VIDEOBUF2_DMA_SG - ---help--- - This is a video4linux2 driver for the Marvell 88ALP01 integrated - CMOS camera controller. This is the controller found on first- - generation OLPC systems. - -config VIDEO_MMP_CAMERA - tristate "Marvell Armada 610 integrated camera controller support" - depends on ARCH_MMP && I2C && VIDEO_V4L2 - depends on HAS_DMA && BROKEN - select VIDEO_OV7670 - select I2C_GPIO - select VIDEOBUF2_DMA_SG - ---help--- - This is a Video4Linux2 driver for the integrated camera - controller found on Marvell Armada 610 application - processors (and likely beyond). This is the controller found - in OLPC XO 1.75 systems. - diff --git a/src/linux/drivers/media/platform/omap/Kconfig b/src/linux/drivers/media/platform/omap/Kconfig deleted file mode 100644 index e8e2db1..0000000 --- a/src/linux/drivers/media/platform/omap/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -config VIDEO_OMAP2_VOUT_VRFB - bool - -config VIDEO_OMAP2_VOUT - tristate "OMAP2/OMAP3 V4L2-Display driver" - depends on MMU - depends on ARCH_OMAP2 || ARCH_OMAP3 - depends on FB_OMAP2 - select VIDEOBUF_GEN - select VIDEOBUF_DMA_CONTIG - select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 - select VIDEO_OMAP2_VOUT_VRFB if VIDEO_OMAP2_VOUT && OMAP2_VRFB - select FRAME_VECTOR - default n - ---help--- - V4L2 Display driver support for OMAP2/3 based boards. diff --git a/src/linux/drivers/media/platform/omap/Makefile b/src/linux/drivers/media/platform/omap/Makefile deleted file mode 100644 index d80df41..0000000 --- a/src/linux/drivers/media/platform/omap/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for the omap video device drivers. -# - -# OMAP2/3 Display driver -omap-vout-y += omap_vout.o omap_voutlib.o -omap-vout-$(CONFIG_VIDEO_OMAP2_VOUT_VRFB) += omap_vout_vrfb.o -obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout.o diff --git a/src/linux/drivers/media/platform/rcar-vin/Kconfig b/src/linux/drivers/media/platform/rcar-vin/Kconfig deleted file mode 100644 index 111d2a1..0000000 --- a/src/linux/drivers/media/platform/rcar-vin/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config VIDEO_RCAR_VIN - tristate "R-Car Video Input (VIN) Driver" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF && HAS_DMA && MEDIA_CONTROLLER - depends on ARCH_RENESAS || COMPILE_TEST - select VIDEOBUF2_DMA_CONTIG - ---help--- - Support for Renesas R-Car Video Input (VIN) driver. - Supports R-Car Gen2 SoCs. - - To compile this driver as a module, choose M here: the - module will be called rcar-vin. diff --git a/src/linux/drivers/media/platform/soc_camera/Kconfig b/src/linux/drivers/media/platform/soc_camera/Kconfig deleted file mode 100644 index 86d7478..0000000 --- a/src/linux/drivers/media/platform/soc_camera/Kconfig +++ /dev/null @@ -1,39 +0,0 @@ -config SOC_CAMERA - tristate "SoC camera support" - depends on VIDEO_V4L2 && HAS_DMA && I2C - select VIDEOBUF_GEN - select VIDEOBUF2_CORE - help - SoC Camera is a common API to several cameras, not connecting - over a bus like PCI or USB. For example some i2c camera connected - directly to the data bus of an SoC. - -config SOC_CAMERA_SCALE_CROP - tristate - -config SOC_CAMERA_PLATFORM - tristate "platform camera support" - depends on SOC_CAMERA - help - This is a generic SoC camera platform driver, useful for testing - -config VIDEO_SH_MOBILE_CEU - tristate "SuperH Mobile CEU Interface driver" - depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK - depends on ARCH_SHMOBILE || COMPILE_TEST - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - select SOC_CAMERA_SCALE_CROP - ---help--- - This is a v4l2 driver for the SuperH Mobile CEU Interface - -config VIDEO_ATMEL_ISI - tristate "ATMEL Image Sensor Interface (ISI) support" - depends on VIDEO_DEV && SOC_CAMERA - depends on ARCH_AT91 || COMPILE_TEST - depends on HAS_DMA - select VIDEOBUF2_DMA_CONTIG - ---help--- - This module makes the ATMEL Image Sensor Interface available - as a v4l2 device. - diff --git a/src/linux/drivers/media/platform/sti/c8sectpfe/Kconfig b/src/linux/drivers/media/platform/sti/c8sectpfe/Kconfig deleted file mode 100644 index 7420a50..0000000 --- a/src/linux/drivers/media/platform/sti/c8sectpfe/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -config DVB_C8SECTPFE - tristate "STMicroelectronics C8SECTPFE DVB support" - depends on PINCTRL && DVB_CORE && I2C - depends on ARCH_STI || ARCH_MULTIPLATFORM || COMPILE_TEST - select FW_LOADER - select DEBUG_FS - select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0367 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT - - ---help--- - This adds support for DVB front-end cards connected - to TS inputs of STiH407/410 SoC. - - The driver currently supports C8SECTPFE's TS input block, - memdma engine, and HW PID filtering. - - Supported DVB front-end cards are: - - STMicroelectronics DVB-T B2100A (STV0367 + TDA18212) - - STMicroelectronics DVB-S/S2 STV0903 + STV6110 + LNBP24 board - - To compile this driver as a module, choose M here: the - module will be called c8sectpfe. diff --git a/src/linux/drivers/media/platform/vivid/Kconfig b/src/linux/drivers/media/platform/vivid/Kconfig deleted file mode 100644 index 8e6918c..0000000 --- a/src/linux/drivers/media/platform/vivid/Kconfig +++ /dev/null @@ -1,39 +0,0 @@ -config VIDEO_VIVID - tristate "Virtual Video Test Driver" - depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 && FB - select FONT_SUPPORT - select FONT_8x16 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select MEDIA_CEC_EDID - select VIDEOBUF2_VMALLOC - select VIDEO_V4L2_TPG - default n - ---help--- - Enables a virtual video driver. This driver emulates a webcam, - TV, S-Video and HDMI capture hardware, including VBI support for - the SDTV inputs. Also video output, VBI output, radio receivers, - transmitters and software defined radio capture is emulated. - - It is highly configurable and is ideal for testing applications. - Error injection is supported to test rare errors that are hard - to reproduce in real hardware. - - Say Y here if you want to test video apps or debug V4L devices. - When in doubt, say N. - -config VIDEO_VIVID_CEC - bool "Enable CEC emulation support" - depends on VIDEO_VIVID && MEDIA_CEC - ---help--- - When selected the vivid module will emulate the optional - HDMI CEC feature. - -config VIDEO_VIVID_MAX_DEVS - int "Maximum number of devices" - depends on VIDEO_VIVID - default "64" - ---help--- - This allows you to specify the maximum number of devices supported - by the vivid driver. diff --git a/src/linux/drivers/media/platform/xilinx/Kconfig b/src/linux/drivers/media/platform/xilinx/Kconfig deleted file mode 100644 index 84bae79..0000000 --- a/src/linux/drivers/media/platform/xilinx/Kconfig +++ /dev/null @@ -1,23 +0,0 @@ -config VIDEO_XILINX - tristate "Xilinx Video IP (EXPERIMENTAL)" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && OF && HAS_DMA - select VIDEOBUF2_DMA_CONTIG - ---help--- - Driver for Xilinx Video IP Pipelines - -if VIDEO_XILINX - -config VIDEO_XILINX_TPG - tristate "Xilinx Video Test Pattern Generator" - depends on VIDEO_XILINX - select VIDEO_XILINX_VTC - ---help--- - Driver for the Xilinx Video Test Pattern Generator - -config VIDEO_XILINX_VTC - tristate "Xilinx Video Timing Controller" - depends on VIDEO_XILINX - ---help--- - Driver for the Xilinx Video Timing Controller - -endif #VIDEO_XILINX diff --git a/src/linux/drivers/media/radio/Kconfig b/src/linux/drivers/media/radio/Kconfig deleted file mode 100644 index 192f36f..0000000 --- a/src/linux/drivers/media/radio/Kconfig +++ /dev/null @@ -1,501 +0,0 @@ -# -# Multimedia Video device configuration -# - -menuconfig RADIO_ADAPTERS - bool "Radio Adapters" - depends on VIDEO_V4L2 - depends on MEDIA_RADIO_SUPPORT - default y - ---help--- - Say Y here to enable selecting AM/FM radio adapters. - -if RADIO_ADAPTERS && VIDEO_V4L2 - -config RADIO_TEA575X - tristate - -config RADIO_SI470X - bool "Silicon Labs Si470x FM Radio Receiver support" - depends on VIDEO_V4L2 - -source "drivers/media/radio/si470x/Kconfig" - -config RADIO_SI4713 - tristate "Silicon Labs Si4713 FM Radio with RDS Transmitter support" - depends on VIDEO_V4L2 - -source "drivers/media/radio/si4713/Kconfig" - -config RADIO_SI476X - tristate "Silicon Laboratories Si476x I2C FM Radio" - depends on I2C && VIDEO_V4L2 - depends on MFD_SI476X_CORE - depends on SND_SOC - select SND_SOC_SI476X - ---help--- - Choose Y here if you have this FM radio chip. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux 2 API. Information on - this API and pointers to "v4l2" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-si476x. - -config USB_MR800 - tristate "AverMedia MR 800 USB FM radio support" - depends on USB && VIDEO_V4L2 - ---help--- - Say Y here if you want to connect this type of radio to your - computer's USB port. Note that the audio is not digital, and - you must connect the line out connector to a sound card or a - set of speakers. - - To compile this driver as a module, choose M here: the - module will be called radio-mr800. - -config USB_DSBR - tristate "D-Link/GemTek USB FM radio support" - depends on USB && VIDEO_V4L2 - ---help--- - Say Y here if you want to connect this type of radio to your - computer's USB port. Note that the audio is not digital, and - you must connect the line out connector to a sound card or a - set of speakers. - - To compile this driver as a module, choose M here: the - module will be called dsbr100. - -config RADIO_MAXIRADIO - tristate "Guillemot MAXI Radio FM 2000 radio" - depends on VIDEO_V4L2 && PCI - select RADIO_TEA575X - ---help--- - Choose Y here if you have this radio card. This card may also be - found as Gemtek PCI FM. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-maxiradio. - -config RADIO_SHARK - tristate "Griffin radioSHARK USB radio receiver" - depends on USB - select RADIO_TEA575X - ---help--- - Choose Y here if you have this radio receiver. - - There are 2 versions of this device, this driver is for version 1, - which is white. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-shark. - -config RADIO_SHARK2 - tristate "Griffin radioSHARK2 USB radio receiver" - depends on USB - ---help--- - Choose Y here if you have this radio receiver. - - There are 2 versions of this device, this driver is for version 2, - which is black. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux API. Information on - this API and pointers to "v4l" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-shark2. - -config USB_KEENE - tristate "Keene FM Transmitter USB support" - depends on USB && VIDEO_V4L2 - ---help--- - Say Y here if you want to connect this type of FM transmitter - to your computer's USB port. - - To compile this driver as a module, choose M here: the - module will be called radio-keene. - -config USB_RAREMONO - tristate "Thanko's Raremono AM/FM/SW radio support" - depends on USB && VIDEO_V4L2 - ---help--- - The 'Thanko's Raremono' device contains the Si4734 chip from Silicon Labs Inc. - It is one of the very few or perhaps the only consumer USB radio device - to receive the AM/FM/SW bands. - - Say Y here if you want to connect this type of AM/FM/SW receiver - to your computer's USB port. - - To compile this driver as a module, choose M here: the - module will be called radio-raremono. - -config USB_MA901 - tristate "Masterkit MA901 USB FM radio support" - depends on USB && VIDEO_V4L2 - ---help--- - Say Y here if you want to connect this type of radio to your - computer's USB port. Note that the audio is not digital, and - you must connect the line out connector to a sound card or a - set of speakers or headphones. - - To compile this driver as a module, choose M here: the - module will be called radio-ma901. - -config RADIO_TEA5764 - tristate "TEA5764 I2C FM radio support" - depends on I2C && VIDEO_V4L2 - ---help--- - Say Y here if you want to use the TEA5764 FM chip found in - EZX phones. This FM chip is present in EZX phones from Motorola, - connected to internal pxa I2C bus. - - To compile this driver as a module, choose M here: the - module will be called radio-tea5764. - -config RADIO_TEA5764_XTAL - bool "TEA5764 crystal reference" - depends on RADIO_TEA5764=y - default y - help - Say Y here if TEA5764 have a 32768 Hz crystal in circuit, say N - here if TEA5764 reference frequency is connected in FREQIN. - -config RADIO_SAA7706H - tristate "SAA7706H Car Radio DSP" - depends on I2C && VIDEO_V4L2 - ---help--- - Say Y here if you want to use the SAA7706H Car radio Digital - Signal Processor, found for instance on the Russellville development - board. On the russellville the device is connected to internal - timberdale I2C bus. - - To compile this driver as a module, choose M here: the - module will be called SAA7706H. - -config RADIO_TEF6862 - tristate "TEF6862 Car Radio Enhanced Selectivity Tuner" - depends on I2C && VIDEO_V4L2 - ---help--- - Say Y here if you want to use the TEF6862 Car Radio Enhanced - Selectivity Tuner, found for instance on the Russellville development - board. On the russellville the device is connected to internal - timberdale I2C bus. - - To compile this driver as a module, choose M here: the - module will be called TEF6862. - -config RADIO_TIMBERDALE - tristate "Enable the Timberdale radio driver" - depends on MFD_TIMBERDALE && VIDEO_V4L2 - depends on I2C # for RADIO_SAA7706H - select RADIO_TEF6862 - select RADIO_SAA7706H - ---help--- - This is a kind of umbrella driver for the Radio Tuner and DSP - found behind the Timberdale FPGA on the Russellville board. - Enabling this driver will automatically select the DSP and tuner. - -config RADIO_WL1273 - tristate "Texas Instruments WL1273 I2C FM Radio" - depends on I2C && VIDEO_V4L2 - select MFD_CORE - select MFD_WL1273_CORE - select FW_LOADER - ---help--- - Choose Y here if you have this FM radio chip. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux 2 API. Information on - this API and pointers to "v4l2" programs may be found at - . - - To compile this driver as a module, choose M here: the - module will be called radio-wl1273. - -# TI's ST based wl128x FM radio -source "drivers/media/radio/wl128x/Kconfig" - -# -# ISA drivers configuration -# - -menuconfig V4L_RADIO_ISA_DRIVERS - bool "ISA radio devices" - depends on ISA - default n - ---help--- - Say Y here to enable support for these ISA drivers. - -if V4L_RADIO_ISA_DRIVERS - -config RADIO_ISA - depends on ISA - tristate - -config RADIO_CADET - tristate "ADS Cadet AM/FM Tuner" - depends on ISA && VIDEO_V4L2 - ---help--- - Choose Y here if you have one of these AM/FM radio cards, and then - fill in the port address below. - - To compile this driver as a module, choose M here: the - module will be called radio-cadet. - -config RADIO_RTRACK - tristate "AIMSlab RadioTrack (aka RadioReveal) support" - depends on ISA && VIDEO_V4L2 - select RADIO_ISA - ---help--- - Choose Y here if you have one of these FM radio cards, and then fill - in the port address below. - - Note that newer AIMSlab RadioTrack cards have a different chipset - and are not supported by this driver. For these cards, use the - RadioTrack II driver below. - - If you have a GemTeks combined (PnP) sound- and radio card you must - use this driver as a module and setup the card with isapnptools. - You must also pass the module a suitable io parameter, 0x248 has - been reported to be used by these cards. - - More information is contained in the file - . - - To compile this driver as a module, choose M here: the - module will be called radio-aimslab. - -config RADIO_RTRACK_PORT - hex "RadioTrack i/o port (0x20f or 0x30f)" - depends on RADIO_RTRACK=y - default "30f" - help - Enter either 0x30f or 0x20f here. The card default is 0x30f, if you - haven't changed the jumper setting on the card. - -config RADIO_RTRACK2 - tristate "AIMSlab RadioTrack II support" - depends on ISA && VIDEO_V4L2 - select RADIO_ISA - ---help--- - Choose Y here if you have this FM radio card, and then fill in the - port address below. - - Note: this driver hasn't been tested since a long time due to lack - of hardware. If you have this hardware, then please contact the - linux-media mailinglist. - - To compile this driver as a module, choose M here: the - module will be called radio-rtrack2. - -config RADIO_RTRACK2_PORT - hex "RadioTrack II i/o port (0x20c or 0x30c)" - depends on RADIO_RTRACK2=y - default "30c" - help - Enter either 0x30c or 0x20c here. The card default is 0x30c, if you - haven't changed the jumper setting on the card. - -config RADIO_AZTECH - tristate "Aztech/Packard Bell Radio" - depends on ISA && VIDEO_V4L2 - select RADIO_ISA - ---help--- - Choose Y here if you have one of these FM radio cards, and then fill - in the port address below. - - To compile this driver as a module, choose M here: the - module will be called radio-aztech. - -config RADIO_AZTECH_PORT - hex "Aztech/Packard Bell I/O port (0x350 or 0x358)" - depends on RADIO_AZTECH=y - default "350" - help - Enter either 0x350 or 0x358 here. The card default is 0x350, if you - haven't changed the setting of jumper JP3 on the card. Removing the - jumper sets the card to 0x358. - -config RADIO_GEMTEK - tristate "GemTek Radio card (or compatible) support" - depends on ISA && VIDEO_V4L2 - select RADIO_ISA - ---help--- - Choose Y here if you have this FM radio card, and then fill in the - I/O port address and settings below. The following cards either have - GemTek Radio tuner or are rebranded GemTek Radio cards: - - - Sound Vision 16 Gold with FM Radio - - Typhoon Radio card (some models) - - Hama Radio card - - To compile this driver as a module, choose M here: the - module will be called radio-gemtek. - -config RADIO_GEMTEK_PORT - hex "Fixed I/O port (0x20c, 0x30c, 0x24c, 0x34c, 0x248 or 0x28c)" - depends on RADIO_GEMTEK=y - default "34c" - help - Enter either 0x20c, 0x30c, 0x24c, 0x34c, 0x248 or 0x28c here. The - card default is 0x34c, if you haven't changed the jumper setting - on the card. - - On Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O - port is 0x20c, 0x248 or 0x28c. - - If automatic I/O port probing is enabled this port will be used only - in case of automatic probing failure, ie. as a fallback. - -config RADIO_GEMTEK_PROBE - bool "Automatic I/O port probing" - depends on RADIO_GEMTEK=y - default y - help - Say Y here to enable automatic probing for GemTek Radio card. The - following ports will be probed: 0x20c, 0x30c, 0x24c, 0x34c, 0x248 and - 0x28c. - -config RADIO_MIROPCM20 - tristate "miroSOUND PCM20 radio" - depends on ISA && ISA_DMA_API && VIDEO_V4L2 && SND - select SND_ISA - select SND_MIRO - ---help--- - Choose Y here if you have this FM radio card. You also need to enable - the ALSA sound system. This choice automatically selects the ALSA - sound card driver "Miro miroSOUND PCM1pro/PCM12/PCM20radio" as this - is required for the radio-miropcm20. - - To compile this driver as a module, choose M here: the - module will be called radio-miropcm20. - -config RADIO_SF16FMI - tristate "SF16-FMI/SF16-FMP/SF16-FMD Radio" - depends on ISA && VIDEO_V4L2 - ---help--- - Choose Y here if you have one of these FM radio cards. - - To compile this driver as a module, choose M here: the - module will be called radio-sf16fmi. - -config RADIO_SF16FMR2 - tristate "SF16-FMR2/SF16-FMD2 Radio" - depends on ISA && VIDEO_V4L2 - select RADIO_TEA575X - ---help--- - Choose Y here if you have one of these FM radio cards. - - To compile this driver as a module, choose M here: the - module will be called radio-sf16fmr2. - -config RADIO_TERRATEC - tristate "TerraTec ActiveRadio ISA Standalone" - depends on ISA && VIDEO_V4L2 - select RADIO_ISA - ---help--- - Choose Y here if you have this FM radio card. - - Note: this driver hasn't been tested since a long time due to lack - of hardware. If you have this hardware, then please contact the - linux-media mailinglist. - - To compile this driver as a module, choose M here: the - module will be called radio-terratec. - -config RADIO_TRUST - tristate "Trust FM radio card" - depends on ISA && VIDEO_V4L2 - select RADIO_ISA - help - This is a driver for the Trust FM radio cards. Say Y if you have - such a card and want to use it under Linux. - - Note: this driver hasn't been tested since a long time due to lack - of hardware. If you have this hardware, then please contact the - linux-media mailinglist. - - To compile this driver as a module, choose M here: the - module will be called radio-trust. - -config RADIO_TRUST_PORT - hex "Trust i/o port (usually 0x350 or 0x358)" - depends on RADIO_TRUST=y - default "350" - help - Enter the I/O port of your Trust FM radio card. If unsure, try the - values "0x350" or "0x358". - -config RADIO_TYPHOON - tristate "Typhoon Radio (a.k.a. EcoRadio)" - depends on ISA && VIDEO_V4L2 - select RADIO_ISA - ---help--- - Choose Y here if you have one of these FM radio cards, and then fill - in the port address and the frequency used for muting below. - - Note: this driver hasn't been tested since a long time due to lack - of hardware. If you have this hardware, then please contact the - linux-media mailinglist. - - To compile this driver as a module, choose M here: the - module will be called radio-typhoon. - -config RADIO_TYPHOON_PORT - hex "Typhoon I/O port (0x316 or 0x336)" - depends on RADIO_TYPHOON=y - default "316" - help - Enter the I/O port of your Typhoon or EcoRadio radio card. - -config RADIO_TYPHOON_MUTEFREQ - int "Typhoon frequency set when muting the device (kHz)" - depends on RADIO_TYPHOON=y - default "87500" - help - Enter the frequency used for muting the radio. The device is never - completely silent. If the volume is just turned down, you can still - hear silent voices and music. For that reason, the frequency of the - radio device is set to the frequency you can enter here whenever - the device is muted. There should be no local radio station at that - frequency. - -config RADIO_ZOLTRIX - tristate "Zoltrix Radio" - depends on ISA && VIDEO_V4L2 - select RADIO_ISA - ---help--- - Choose Y here if you have one of these FM radio cards, and then fill - in the port address below. - - Note: this driver hasn't been tested since a long time due to lack - of hardware. If you have this hardware, then please contact the - linux-media mailinglist. - - To compile this driver as a module, choose M here: the - module will be called radio-zoltrix. - -config RADIO_ZOLTRIX_PORT - hex "ZOLTRIX I/O port (0x20c or 0x30c)" - depends on RADIO_ZOLTRIX=y - default "20c" - help - Enter the I/O port of your Zoltrix radio card. - -endif # V4L_RADIO_ISA_DRIVERS - -endif # RADIO_ADAPTERS diff --git a/src/linux/drivers/media/radio/si470x/Kconfig b/src/linux/drivers/media/radio/si470x/Kconfig deleted file mode 100644 index a466654..0000000 --- a/src/linux/drivers/media/radio/si470x/Kconfig +++ /dev/null @@ -1,37 +0,0 @@ -config USB_SI470X - tristate "Silicon Labs Si470x FM Radio Receiver support with USB" - depends on USB && RADIO_SI470X - ---help--- - This is a driver for USB devices with the Silicon Labs SI470x - chip. Currently these devices are known to work: - - 10c4:818a: Silicon Labs USB FM Radio Reference Design - - 06e1:a155: ADS/Tech FM Radio Receiver (formerly Instant FM Music) - - 1b80:d700: KWorld USB FM Radio SnapMusic Mobile 700 (FM700) - - 10c5:819a: Sanei Electric FM USB Radio (aka DealExtreme.com PCear) - - Sound is provided by the ALSA USB Audio/MIDI driver. Therefore - if you don't want to use the device solely for RDS receiving, - it is recommended to also select SND_USB_AUDIO. - - Please have a look at the documentation, especially on how - to redirect the audio stream from the radio to your sound device: - Documentation/video4linux/si470x.txt - - Say Y here if you want to connect this type of radio to your - computer's USB port. - - To compile this driver as a module, choose M here: the - module will be called radio-usb-si470x. - -config I2C_SI470X - tristate "Silicon Labs Si470x FM Radio Receiver support with I2C" - depends on I2C && RADIO_SI470X && !USB_SI470X - ---help--- - This is a driver for I2C devices with the Silicon Labs SI470x - chip. - - Say Y here if you want to connect this type of radio to your - computer's I2C port. - - To compile this driver as a module, choose M here: the - module will be called radio-i2c-si470x. diff --git a/src/linux/drivers/media/radio/si4713/Kconfig b/src/linux/drivers/media/radio/si4713/Kconfig deleted file mode 100644 index 9c8b887..0000000 --- a/src/linux/drivers/media/radio/si4713/Kconfig +++ /dev/null @@ -1,40 +0,0 @@ -config USB_SI4713 - tristate "Silicon Labs Si4713 FM Radio Transmitter support with USB" - depends on USB && I2C && RADIO_SI4713 - select I2C_SI4713 - ---help--- - This is a driver for USB devices with the Silicon Labs SI4713 - chip. Currently these devices are known to work. - - 10c4:8244: Silicon Labs FM Transmitter USB device. - - Say Y here if you want to connect this type of radio to your - computer's USB port. - - To compile this driver as a module, choose M here: the - module will be called radio-usb-si4713. - -config PLATFORM_SI4713 - tristate "Silicon Labs Si4713 FM Radio Transmitter support with I2C" - depends on I2C && RADIO_SI4713 - select I2C_SI4713 - ---help--- - This is a driver for I2C devices with the Silicon Labs SI4713 - chip. - - Say Y here if you want to connect this type of radio to your - computer's I2C port. - - To compile this driver as a module, choose M here: the - module will be called radio-platform-si4713. - -config I2C_SI4713 - tristate "Silicon Labs Si4713 FM Radio Transmitter support" - depends on I2C && RADIO_SI4713 - ---help--- - Say Y here if you want support to Si4713 FM Radio Transmitter. - This device can transmit audio through FM. It can transmit - RDS and RBDS signals as well. This module is the v4l2 radio - interface for the i2c driver of this device. - - To compile this driver as a module, choose M here: the - module will be called si4713. diff --git a/src/linux/drivers/media/radio/wl128x/Kconfig b/src/linux/drivers/media/radio/wl128x/Kconfig deleted file mode 100644 index c9e349b..0000000 --- a/src/linux/drivers/media/radio/wl128x/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -# -# TI's wl128x FM driver based on TI's ST driver. -# -menu "Texas Instruments WL128x FM driver (ST based)" -config RADIO_WL128X - tristate "Texas Instruments WL128x FM Radio" - depends on VIDEO_V4L2 && RFKILL && TTY && TI_ST - depends on GPIOLIB || COMPILE_TEST - help - Choose Y here if you have this FM radio chip. - - In order to control your radio card, you will need to use programs - that are compatible with the Video For Linux 2 API. Information on - this API and pointers to "v4l2" programs may be found at - . - -endmenu diff --git a/src/linux/drivers/media/rc/Kconfig b/src/linux/drivers/media/rc/Kconfig deleted file mode 100644 index 370e16e..0000000 --- a/src/linux/drivers/media/rc/Kconfig +++ /dev/null @@ -1,392 +0,0 @@ -config RC_CORE - tristate - depends on MEDIA_RC_SUPPORT - depends on INPUT - default y - -source "drivers/media/rc/keymaps/Kconfig" - -menuconfig RC_DECODERS - bool "Remote controller decoders" - depends on RC_CORE - default y - -if RC_DECODERS -config LIRC - tristate "LIRC interface driver" - depends on RC_CORE - - ---help--- - Enable this option to build the Linux Infrared Remote - Control (LIRC) core device interface driver. The LIRC - interface passes raw IR to and from userspace, where the - LIRC daemon handles protocol decoding for IR reception and - encoding for IR transmitting (aka "blasting"). - -config IR_LIRC_CODEC - tristate "Enable IR to LIRC bridge" - depends on RC_CORE - depends on LIRC - default y - - ---help--- - Enable this option to pass raw IR to and from userspace via - the LIRC interface. - - -config IR_NEC_DECODER - tristate "Enable IR raw decoder for the NEC protocol" - depends on RC_CORE - select BITREVERSE - default y - - ---help--- - Enable this option if you have IR with NEC protocol, and - if the IR is decoded in software - -config IR_RC5_DECODER - tristate "Enable IR raw decoder for the RC-5 protocol" - depends on RC_CORE - select BITREVERSE - default y - - ---help--- - Enable this option if you have IR with RC-5 protocol, and - if the IR is decoded in software - -config IR_RC6_DECODER - tristate "Enable IR raw decoder for the RC6 protocol" - depends on RC_CORE - select BITREVERSE - default y - - ---help--- - Enable this option if you have an infrared remote control which - uses the RC6 protocol, and you need software decoding support. - -config IR_JVC_DECODER - tristate "Enable IR raw decoder for the JVC protocol" - depends on RC_CORE - select BITREVERSE - default y - - ---help--- - Enable this option if you have an infrared remote control which - uses the JVC protocol, and you need software decoding support. - -config IR_SONY_DECODER - tristate "Enable IR raw decoder for the Sony protocol" - depends on RC_CORE - select BITREVERSE - default y - - ---help--- - Enable this option if you have an infrared remote control which - uses the Sony protocol, and you need software decoding support. - -config IR_SANYO_DECODER - tristate "Enable IR raw decoder for the Sanyo protocol" - depends on RC_CORE - default y - - ---help--- - Enable this option if you have an infrared remote control which - uses the Sanyo protocol (Sanyo, Aiwa, Chinon remotes), - and you need software decoding support. - -config IR_SHARP_DECODER - tristate "Enable IR raw decoder for the Sharp protocol" - depends on RC_CORE - default y - - ---help--- - Enable this option if you have an infrared remote control which - uses the Sharp protocol (Sharp, Denon), and you need software - decoding support. - -config IR_MCE_KBD_DECODER - tristate "Enable IR raw decoder for the MCE keyboard/mouse protocol" - depends on RC_CORE - select BITREVERSE - default y - - ---help--- - Enable this option if you have a Microsoft Remote Keyboard for - Windows Media Center Edition, which you would like to use with - a raw IR receiver in your system. - -config IR_XMP_DECODER - tristate "Enable IR raw decoder for the XMP protocol" - depends on RC_CORE - select BITREVERSE - default y - - ---help--- - Enable this option if you have IR with XMP protocol, and - if the IR is decoded in software -endif #RC_DECODERS - -menuconfig RC_DEVICES - bool "Remote Controller devices" - depends on RC_CORE - -if RC_DEVICES - -config RC_ATI_REMOTE - tristate "ATI / X10 based USB RF remote controls" - depends on USB_ARCH_HAS_HCD - depends on RC_CORE - select USB - help - Say Y here if you want to use an X10 based USB remote control. - These are RF remotes with USB receivers. - - Such devices include the ATI remote that comes with many of ATI's - All-In-Wonder video cards, the X10 "Lola" remote, NVIDIA RF remote, - Medion RF remote, and SnapStream FireFly remote. - - This driver provides mouse pointer, left and right mouse buttons, - and maps all the other remote buttons to keypress events. - - To compile this driver as a module, choose M here: the module will be - called ati_remote. - -config IR_ENE - tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)" - depends on PNP - depends on RC_CORE - ---help--- - Say Y here to enable support for integrated infrared receiver - /transceiver made by ENE. - - You can see if you have it by looking at lspnp output. - Output should include ENE0100 ENE0200 or something similar. - - To compile this driver as a module, choose M here: the - module will be called ene_ir. - -config IR_HIX5HD2 - tristate "Hisilicon hix5hd2 IR remote control" - depends on RC_CORE - help - Say Y here if you want to use hisilicon hix5hd2 remote control. - To compile this driver as a module, choose M here: the module will be - called ir-hix5hd2. - - If you're not sure, select N here - -config IR_IMON - tristate "SoundGraph iMON Receiver and Display" - depends on USB_ARCH_HAS_HCD - depends on RC_CORE - select USB - ---help--- - Say Y here if you want to use a SoundGraph iMON (aka Antec Veris) - IR Receiver and/or LCD/VFD/VGA display. - - To compile this driver as a module, choose M here: the - module will be called imon. - -config IR_MCEUSB - tristate "Windows Media Center Ed. eHome Infrared Transceiver" - depends on USB_ARCH_HAS_HCD - depends on RC_CORE - select USB - ---help--- - Say Y here if you want to use a Windows Media Center Edition - eHome Infrared Transceiver. - - To compile this driver as a module, choose M here: the - module will be called mceusb. - -config IR_ITE_CIR - tristate "ITE Tech Inc. IT8712/IT8512 Consumer Infrared Transceiver" - depends on PNP - depends on RC_CORE - ---help--- - Say Y here to enable support for integrated infrared receivers - /transceivers made by ITE Tech Inc. These are found in - several ASUS devices, like the ASUS Digimatrix or the ASUS - EEEBox 1501U. - - To compile this driver as a module, choose M here: the - module will be called ite-cir. - -config IR_FINTEK - tristate "Fintek Consumer Infrared Transceiver" - depends on PNP - depends on RC_CORE - ---help--- - Say Y here to enable support for integrated infrared receiver - /transciever made by Fintek. This chip is found on assorted - Jetway motherboards (and of course, possibly others). - - To compile this driver as a module, choose M here: the - module will be called fintek-cir. - -config IR_MESON - tristate "Amlogic Meson IR remote receiver" - depends on RC_CORE - depends on ARCH_MESON || COMPILE_TEST - ---help--- - Say Y if you want to use the IR remote receiver available - on Amlogic Meson SoCs. - - To compile this driver as a module, choose M here: the - module will be called meson-ir. - -config IR_NUVOTON - tristate "Nuvoton w836x7hg Consumer Infrared Transceiver" - depends on PNP - depends on RC_CORE - ---help--- - Say Y here to enable support for integrated infrared receiver - /transciever made by Nuvoton (formerly Winbond). This chip is - found in the ASRock ION 330HT, as well as assorted Intel - DP55-series motherboards (and of course, possibly others). - - To compile this driver as a module, choose M here: the - module will be called nuvoton-cir. - -config IR_REDRAT3 - tristate "RedRat3 IR Transceiver" - depends on USB_ARCH_HAS_HCD - depends on RC_CORE - select NEW_LEDS - select LEDS_CLASS - select USB - ---help--- - Say Y here if you want to use a RedRat3 Infrared Transceiver. - - To compile this driver as a module, choose M here: the - module will be called redrat3. - -config IR_STREAMZAP - tristate "Streamzap PC Remote IR Receiver" - depends on USB_ARCH_HAS_HCD - depends on RC_CORE - select USB - ---help--- - Say Y here if you want to use a Streamzap PC Remote - Infrared Receiver. - - To compile this driver as a module, choose M here: the - module will be called streamzap. - -config IR_WINBOND_CIR - tristate "Winbond IR remote control" - depends on X86 && PNP - depends on RC_CORE - select NEW_LEDS - select LEDS_CLASS - select BITREVERSE - ---help--- - Say Y here if you want to use the IR remote functionality found - in some Winbond SuperI/O chips. Currently only the WPCD376I - chip is supported (included in some Intel Media series - motherboards). - - To compile this driver as a module, choose M here: the module will - be called winbond_cir. - -config IR_IGORPLUGUSB - tristate "IgorPlug-USB IR Receiver" - depends on USB_ARCH_HAS_HCD - depends on RC_CORE - select USB - ---help--- - Say Y here if you want to use the IgorPlug-USB IR Receiver by - Igor Cesko. This device is included on the Fit-PC2. - - Note that this device can only record bursts of 36 IR pulses and - spaces, which is not enough for the NEC, Sanyo and RC-6 protocol. - - To compile this driver as a module, choose M here: the module will - be called igorplugusb. - -config IR_IGUANA - tristate "IguanaWorks USB IR Transceiver" - depends on USB_ARCH_HAS_HCD - depends on RC_CORE - select USB - ---help--- - Say Y here if you want to use the IguanaWorks USB IR Transceiver. - Both infrared receive and send are supported. If you want to - change the ID or the pin config, use the user space driver from - IguanaWorks. - - Only firmware 0x0205 and later is supported. - - To compile this driver as a module, choose M here: the module will - be called iguanair. - -config IR_TTUSBIR - tristate "TechnoTrend USB IR Receiver" - depends on USB_ARCH_HAS_HCD - depends on RC_CORE - select USB - select NEW_LEDS - select LEDS_CLASS - ---help--- - Say Y here if you want to use the TechnoTrend USB IR Receiver. The - driver can control the led. - - To compile this driver as a module, choose M here: the module will - be called ttusbir. - -config IR_RX51 - tristate "Nokia N900 IR transmitter diode" - depends on OMAP_DM_TIMER && PWM_OMAP_DMTIMER && ARCH_OMAP2PLUS && LIRC - ---help--- - Say Y or M here if you want to enable support for the IR - transmitter diode built in the Nokia N900 (RX51) device. - - The driver uses omap DM timers for generating the carrier - wave and pulses. - -source "drivers/media/rc/img-ir/Kconfig" - -config RC_LOOPBACK - tristate "Remote Control Loopback Driver" - depends on RC_CORE - ---help--- - Say Y here if you want support for the remote control loopback - driver which allows TX data to be sent back as RX data. - This is mostly useful for debugging purposes. - - If you're not sure, select N here. - - To compile this driver as a module, choose M here: the module will - be called rc_loopback. - -config IR_GPIO_CIR - tristate "GPIO IR remote control" - depends on RC_CORE - ---help--- - Say Y if you want to use GPIO based IR Receiver. - - To compile this driver as a module, choose M here: the module will - be called gpio-ir-recv. - -config RC_ST - tristate "ST remote control receiver" - depends on RC_CORE - depends on ARCH_STI || COMPILE_TEST - ---help--- - Say Y here if you want support for ST remote control driver - which allows both IR and UHF RX. - The driver passes raw pulse and space information to the LIRC decoder. - - If you're not sure, select N here. - -config IR_SUNXI - tristate "SUNXI IR remote control" - depends on RC_CORE - depends on ARCH_SUNXI || COMPILE_TEST - ---help--- - Say Y if you want to use sunXi internal IR Controller - - To compile this driver as a module, choose M here: the module will - be called sunxi-ir. - -endif #RC_DEVICES diff --git a/src/linux/drivers/media/rc/Makefile b/src/linux/drivers/media/rc/Makefile deleted file mode 100644 index 379a5c0..0000000 --- a/src/linux/drivers/media/rc/Makefile +++ /dev/null @@ -1,39 +0,0 @@ -rc-core-objs := rc-main.o rc-ir-raw.o - -obj-y += keymaps/ - -obj-$(CONFIG_RC_CORE) += rc-core.o -obj-$(CONFIG_LIRC) += lirc_dev.o -obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o -obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o -obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o -obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o -obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o -obj-$(CONFIG_IR_SANYO_DECODER) += ir-sanyo-decoder.o -obj-$(CONFIG_IR_SHARP_DECODER) += ir-sharp-decoder.o -obj-$(CONFIG_IR_MCE_KBD_DECODER) += ir-mce_kbd-decoder.o -obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o -obj-$(CONFIG_IR_XMP_DECODER) += ir-xmp-decoder.o - -# stand-alone IR receivers/transmitters -obj-$(CONFIG_RC_ATI_REMOTE) += ati_remote.o -obj-$(CONFIG_IR_HIX5HD2) += ir-hix5hd2.o -obj-$(CONFIG_IR_IMON) += imon.o -obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o -obj-$(CONFIG_IR_MCEUSB) += mceusb.o -obj-$(CONFIG_IR_FINTEK) += fintek-cir.o -obj-$(CONFIG_IR_MESON) += meson-ir.o -obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o -obj-$(CONFIG_IR_ENE) += ene_ir.o -obj-$(CONFIG_IR_REDRAT3) += redrat3.o -obj-$(CONFIG_IR_RX51) += ir-rx51.o -obj-$(CONFIG_IR_STREAMZAP) += streamzap.o -obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o -obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o -obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o -obj-$(CONFIG_IR_IGORPLUGUSB) += igorplugusb.o -obj-$(CONFIG_IR_IGUANA) += iguanair.o -obj-$(CONFIG_IR_TTUSBIR) += ttusbir.o -obj-$(CONFIG_RC_ST) += st_rc.o -obj-$(CONFIG_IR_SUNXI) += sunxi-cir.o -obj-$(CONFIG_IR_IMG) += img-ir/ diff --git a/src/linux/drivers/media/rc/img-ir/Kconfig b/src/linux/drivers/media/rc/img-ir/Kconfig deleted file mode 100644 index a896d3c..0000000 --- a/src/linux/drivers/media/rc/img-ir/Kconfig +++ /dev/null @@ -1,77 +0,0 @@ -config IR_IMG - tristate "ImgTec IR Decoder" - depends on RC_CORE - depends on METAG || MIPS || COMPILE_TEST - select IR_IMG_HW if !IR_IMG_RAW - help - Say Y or M here if you want to use the ImgTec infrared decoder - functionality found in SoCs such as TZ1090. - -config IR_IMG_RAW - bool "Raw decoder" - depends on IR_IMG - help - Say Y here to enable the raw mode driver which passes raw IR signal - changes to the IR raw decoders for software decoding. This is much - less reliable (due to lack of timestamps) and consumes more - processing power than using hardware decode, but can be useful for - testing, debug, and to make more protocols available. - -config IR_IMG_HW - bool "Hardware decoder" - depends on IR_IMG - help - Say Y here to enable the hardware decode driver which decodes the IR - signals in hardware. This is more reliable, consumes less processing - power since only a single interrupt is received for each scancode, - and allows an IR scancode to be used as a wake event. - -config IR_IMG_NEC - bool "NEC protocol support" - depends on IR_IMG_HW - help - Say Y here to enable support for the NEC, extended NEC, and 32-bit - NEC protocols in the ImgTec infrared decoder block. - -config IR_IMG_JVC - bool "JVC protocol support" - depends on IR_IMG_HW - help - Say Y here to enable support for the JVC protocol in the ImgTec - infrared decoder block. - -config IR_IMG_SONY - bool "Sony protocol support" - depends on IR_IMG_HW - help - Say Y here to enable support for the Sony protocol in the ImgTec - infrared decoder block. - -config IR_IMG_SHARP - bool "Sharp protocol support" - depends on IR_IMG_HW - help - Say Y here to enable support for the Sharp protocol in the ImgTec - infrared decoder block. - -config IR_IMG_SANYO - bool "Sanyo protocol support" - depends on IR_IMG_HW - help - Say Y here to enable support for the Sanyo protocol (used by Sanyo, - Aiwa, Chinon remotes) in the ImgTec infrared decoder block. - -config IR_IMG_RC5 - bool "Philips RC5 protocol support" - depends on IR_IMG_HW - help - Say Y here to enable support for the RC5 protocol in the ImgTec - infrared decoder block. - -config IR_IMG_RC6 - bool "Philips RC6 protocol support" - depends on IR_IMG_HW - help - Say Y here to enable support for the RC6 protocol in the ImgTec - infrared decoder block. - Note: This version only supports mode 0. diff --git a/src/linux/drivers/media/rc/keymaps/Kconfig b/src/linux/drivers/media/rc/keymaps/Kconfig deleted file mode 100644 index 767423b..0000000 --- a/src/linux/drivers/media/rc/keymaps/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -config RC_MAP - tristate "Compile Remote Controller keymap modules" - depends on RC_CORE - default y - - ---help--- - This option enables the compilation of lots of Remote - Controller tables. They are short tables, but if you - don't use a remote controller, or prefer to load the - tables on userspace, you should disable it. - - The ir-keytable program, available at v4l-utils package - provide the tool and the same RC maps for load from - userspace. Its available at - http://git.linuxtv.org/cgit.cgi/v4l-utils.git/ diff --git a/src/linux/drivers/media/rc/keymaps/Makefile b/src/linux/drivers/media/rc/keymaps/Makefile deleted file mode 100644 index d7b13fa..0000000 --- a/src/linux/drivers/media/rc/keymaps/Makefile +++ /dev/null @@ -1,109 +0,0 @@ -obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \ - rc-alink-dtu-m.o \ - rc-anysee.o \ - rc-apac-viewcomp.o \ - rc-asus-pc39.o \ - rc-asus-ps3-100.o \ - rc-ati-tv-wonder-hd-600.o \ - rc-ati-x10.o \ - rc-avermedia-a16d.o \ - rc-avermedia.o \ - rc-avermedia-cardbus.o \ - rc-avermedia-dvbt.o \ - rc-avermedia-m135a.o \ - rc-avermedia-m733a-rm-k6.o \ - rc-avermedia-rm-ks.o \ - rc-avertv-303.o \ - rc-azurewave-ad-tu700.o \ - rc-behold.o \ - rc-behold-columbus.o \ - rc-budget-ci-old.o \ - rc-cec.o \ - rc-cinergy-1400.o \ - rc-cinergy.o \ - rc-delock-61959.o \ - rc-dib0700-nec.o \ - rc-dib0700-rc5.o \ - rc-digitalnow-tinytwin.o \ - rc-digittrade.o \ - rc-dm1105-nec.o \ - rc-dntv-live-dvb-t.o \ - rc-dntv-live-dvbt-pro.o \ - rc-dtt200u.o \ - rc-dvbsky.o \ - rc-em-terratec.o \ - rc-encore-enltv2.o \ - rc-encore-enltv.o \ - rc-encore-enltv-fm53.o \ - rc-evga-indtube.o \ - rc-eztv.o \ - rc-flydvb.o \ - rc-flyvideo.o \ - rc-fusionhdtv-mce.o \ - rc-gadmei-rm008z.o \ - rc-genius-tvgo-a11mce.o \ - rc-gotview7135.o \ - rc-imon-mce.o \ - rc-imon-pad.o \ - rc-iodata-bctv7e.o \ - rc-it913x-v1.o \ - rc-it913x-v2.o \ - rc-kaiomy.o \ - rc-kworld-315u.o \ - rc-kworld-pc150u.o \ - rc-kworld-plus-tv-analog.o \ - rc-leadtek-y04g0051.o \ - rc-lirc.o \ - rc-lme2510.o \ - rc-manli.o \ - rc-medion-x10.o \ - rc-medion-x10-digitainer.o \ - rc-medion-x10-or2x.o \ - rc-msi-digivox-ii.o \ - rc-msi-digivox-iii.o \ - rc-msi-tvanywhere.o \ - rc-msi-tvanywhere-plus.o \ - rc-nebula.o \ - rc-nec-terratec-cinergy-xs.o \ - rc-norwood.o \ - rc-npgtech.o \ - rc-pctv-sedna.o \ - rc-pinnacle-color.o \ - rc-pinnacle-grey.o \ - rc-pinnacle-pctv-hd.o \ - rc-pixelview.o \ - rc-pixelview-mk12.o \ - rc-pixelview-002t.o \ - rc-pixelview-new.o \ - rc-powercolor-real-angel.o \ - rc-proteus-2309.o \ - rc-purpletv.o \ - rc-pv951.o \ - rc-hauppauge.o \ - rc-rc6-mce.o \ - rc-real-audio-220-32-keys.o \ - rc-reddo.o \ - rc-snapstream-firefly.o \ - rc-streamzap.o \ - rc-tbs-nec.o \ - rc-technisat-ts35.o \ - rc-technisat-usb2.o \ - rc-terratec-cinergy-c-pci.o \ - rc-terratec-cinergy-s2-hd.o \ - rc-terratec-cinergy-xs.o \ - rc-terratec-slim.o \ - rc-terratec-slim-2.o \ - rc-tevii-nec.o \ - rc-tivo.o \ - rc-total-media-in-hand.o \ - rc-total-media-in-hand-02.o \ - rc-trekstor.o \ - rc-tt-1500.o \ - rc-twinhan-dtv-cab-ci.o \ - rc-twinhan1027.o \ - rc-videomate-m1f.o \ - rc-videomate-s350.o \ - rc-videomate-tv-pvr.o \ - rc-winfast.o \ - rc-winfast-usbii-deluxe.o \ - rc-su3000.o diff --git a/src/linux/drivers/media/spi/Kconfig b/src/linux/drivers/media/spi/Kconfig deleted file mode 100644 index a21f5a3..0000000 --- a/src/linux/drivers/media/spi/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -if VIDEO_V4L2 - -menu "SPI helper chips" - visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST - -config VIDEO_GS1662 - tristate "Gennum Serializers video" - depends on SPI && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - ---help--- - Enable the GS1662 driver which serializes video streams. - -endmenu - -endif diff --git a/src/linux/drivers/media/spi/Makefile b/src/linux/drivers/media/spi/Makefile deleted file mode 100644 index ea64013..0000000 --- a/src/linux/drivers/media/spi/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_VIDEO_GS1662) += gs1662.o diff --git a/src/linux/drivers/media/tuners/Kconfig b/src/linux/drivers/media/tuners/Kconfig deleted file mode 100644 index 05998f0..0000000 --- a/src/linux/drivers/media/tuners/Kconfig +++ /dev/null @@ -1,280 +0,0 @@ -# Analog TV tuners, auto-loaded via tuner.ko -config MEDIA_TUNER - tristate - depends on (MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT) && I2C - default y - select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_XC4000 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MT20XX if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TEA5761 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_RADIO_SUPPORT - select MEDIA_TUNER_TEA5767 if MEDIA_SUBDRV_AUTOSELECT && MEDIA_RADIO_SUPPORT - select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA9887 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MC44S803 if MEDIA_SUBDRV_AUTOSELECT - -menu "Customize TV tuners" - visible if !MEDIA_SUBDRV_AUTOSELECT || COMPILE_TEST - depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_RADIO_SUPPORT || MEDIA_SDR_SUPPORT - -config MEDIA_TUNER_SIMPLE - tristate "Simple tuner support" - depends on MEDIA_SUPPORT && I2C - select MEDIA_TUNER_TDA9887 - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to include support for various simple tuners. - -config MEDIA_TUNER_TDA8290 - tristate "TDA 8290/8295 + 8275(a)/18271 tuner combo" - depends on MEDIA_SUPPORT && I2C - select MEDIA_TUNER_TDA827X - select MEDIA_TUNER_TDA18271 - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to include support for Philips TDA8290+8275(a) tuner. - -config MEDIA_TUNER_TDA827X - tristate "Philips TDA827X silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A DVB-T silicon tuner module. Say Y when you want to support this tuner. - -config MEDIA_TUNER_TDA18271 - tristate "NXP TDA18271 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A silicon tuner module. Say Y when you want to support this tuner. - -config MEDIA_TUNER_TDA9887 - tristate "TDA 9885/6/7 analog IF demodulator" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to include support for Philips TDA9885/6/7 - analog IF demodulator. - -config MEDIA_TUNER_TEA5761 - tristate "TEA 5761 radio tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to include support for the Philips TEA5761 radio tuner. - -config MEDIA_TUNER_TEA5767 - tristate "TEA 5767 radio tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to include support for the Philips TEA5767 radio tuner. - -config MEDIA_TUNER_MSI001 - tristate "Mirics MSi001" - depends on MEDIA_SUPPORT && SPI && VIDEO_V4L2 - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Mirics MSi001 silicon tuner driver. - -config MEDIA_TUNER_MT20XX - tristate "Microtune 2032 / 2050 tuners" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to include support for the MT2032 / MT2050 tuner. - -config MEDIA_TUNER_MT2060 - tristate "Microtune MT2060 silicon IF tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A driver for the silicon IF tuner MT2060 from Microtune. - -config MEDIA_TUNER_MT2063 - tristate "Microtune MT2063 silicon IF tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A driver for the silicon IF tuner MT2063 from Microtune. - -config MEDIA_TUNER_MT2266 - tristate "Microtune MT2266 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A driver for the silicon baseband tuner MT2266 from Microtune. - -config MEDIA_TUNER_MT2131 - tristate "Microtune MT2131 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A driver for the silicon baseband tuner MT2131 from Microtune. - -config MEDIA_TUNER_QT1010 - tristate "Quantek QT1010 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A driver for the silicon tuner QT1010 from Quantek. - -config MEDIA_TUNER_XC2028 - tristate "XCeive xc2028/xc3028 tuners" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to include support for the xc2028/xc3028 tuners. - -config MEDIA_TUNER_XC5000 - tristate "Xceive XC5000 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A driver for the silicon tuner XC5000 from Xceive. - This device is only used inside a SiP called together with a - demodulator for now. - -config MEDIA_TUNER_XC4000 - tristate "Xceive XC4000 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A driver for the silicon tuner XC4000 from Xceive. - This device is only used inside a SiP called together with a - demodulator for now. - -config MEDIA_TUNER_MXL5005S - tristate "MaxLinear MSL5005S silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A driver for the silicon tuner MXL5005S from MaxLinear. - -config MEDIA_TUNER_MXL5007T - tristate "MaxLinear MxL5007T silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A driver for the silicon tuner MxL5007T from MaxLinear. - -config MEDIA_TUNER_MC44S803 - tristate "Freescale MC44S803 Low Power CMOS Broadband tuners" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the Freescale MC44S803 based tuners - -config MEDIA_TUNER_MAX2165 - tristate "Maxim MAX2165 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - A driver for the silicon tuner MAX2165 from Maxim. - -config MEDIA_TUNER_TDA18218 - tristate "NXP TDA18218 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - NXP TDA18218 silicon tuner driver. - -config MEDIA_TUNER_FC0011 - tristate "Fitipower FC0011 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Fitipower FC0011 silicon tuner driver. - -config MEDIA_TUNER_FC0012 - tristate "Fitipower FC0012 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Fitipower FC0012 silicon tuner driver. - -config MEDIA_TUNER_FC0013 - tristate "Fitipower FC0013 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Fitipower FC0013 silicon tuner driver. - -config MEDIA_TUNER_TDA18212 - tristate "NXP TDA18212 silicon tuner" - depends on MEDIA_SUPPORT && I2C - select REGMAP_I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - NXP TDA18212 silicon tuner driver. - -config MEDIA_TUNER_E4000 - tristate "Elonics E4000 silicon tuner" - depends on MEDIA_SUPPORT && I2C - select REGMAP_I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Elonics E4000 silicon tuner driver. - -config MEDIA_TUNER_FC2580 - tristate "FCI FC2580 silicon tuner" - depends on MEDIA_SUPPORT && I2C - select REGMAP_I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - FCI FC2580 silicon tuner driver. - -config MEDIA_TUNER_M88RS6000T - tristate "Montage M88RS6000 internal tuner" - depends on MEDIA_SUPPORT && I2C - select REGMAP_I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Montage M88RS6000 internal tuner. - -config MEDIA_TUNER_TUA9001 - tristate "Infineon TUA9001 silicon tuner" - depends on MEDIA_SUPPORT && I2C - select REGMAP_I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Infineon TUA 9001 silicon tuner driver. - -config MEDIA_TUNER_SI2157 - tristate "Silicon Labs Si2157 silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Silicon Labs Si2157 silicon tuner driver. - -config MEDIA_TUNER_IT913X - tristate "ITE Tech IT913x silicon tuner" - depends on MEDIA_SUPPORT && I2C - select REGMAP_I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - ITE Tech IT913x silicon tuner driver. - -config MEDIA_TUNER_R820T - tristate "Rafael Micro R820T silicon tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - select BITREVERSE - help - Rafael Micro R820T silicon tuner driver. - -config MEDIA_TUNER_MXL301RF - tristate "MaxLinear MxL301RF tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - MaxLinear MxL301RF OFDM tuner driver. - -config MEDIA_TUNER_QM1D1C0042 - tristate "Sharp QM1D1C0042 tuner" - depends on MEDIA_SUPPORT && I2C - default m if !MEDIA_SUBDRV_AUTOSELECT - help - Sharp QM1D1C0042 trellis coded 8PSK tuner driver. -endmenu diff --git a/src/linux/drivers/media/tuners/Makefile b/src/linux/drivers/media/tuners/Makefile deleted file mode 100644 index 06a9ab6..0000000 --- a/src/linux/drivers/media/tuners/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -# -# Makefile for common V4L/DVB tuners -# - -tda18271-objs := tda18271-maps.o tda18271-common.o tda18271-fe.o - -obj-$(CONFIG_MEDIA_TUNER_XC2028) += tuner-xc2028.o -obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-simple.o -# tuner-types will be merged into tuner-simple, in the future -obj-$(CONFIG_MEDIA_TUNER_SIMPLE) += tuner-types.o -obj-$(CONFIG_MEDIA_TUNER_MT20XX) += mt20xx.o -obj-$(CONFIG_MEDIA_TUNER_TDA8290) += tda8290.o -obj-$(CONFIG_MEDIA_TUNER_TEA5767) += tea5767.o -obj-$(CONFIG_MEDIA_TUNER_TEA5761) += tea5761.o -obj-$(CONFIG_MEDIA_TUNER_TDA9887) += tda9887.o -obj-$(CONFIG_MEDIA_TUNER_TDA827X) += tda827x.o -obj-$(CONFIG_MEDIA_TUNER_TDA18271) += tda18271.o -obj-$(CONFIG_MEDIA_TUNER_XC5000) += xc5000.o -obj-$(CONFIG_MEDIA_TUNER_XC4000) += xc4000.o -obj-$(CONFIG_MEDIA_TUNER_MSI001) += msi001.o -obj-$(CONFIG_MEDIA_TUNER_MT2060) += mt2060.o -obj-$(CONFIG_MEDIA_TUNER_MT2063) += mt2063.o -obj-$(CONFIG_MEDIA_TUNER_MT2266) += mt2266.o -obj-$(CONFIG_MEDIA_TUNER_QT1010) += qt1010.o -obj-$(CONFIG_MEDIA_TUNER_MT2131) += mt2131.o -obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o -obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o -obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o -obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o -obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o -obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o -obj-$(CONFIG_MEDIA_TUNER_E4000) += e4000.o -obj-$(CONFIG_MEDIA_TUNER_FC2580) += fc2580.o -obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o -obj-$(CONFIG_MEDIA_TUNER_SI2157) += si2157.o -obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o -obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o -obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o -obj-$(CONFIG_MEDIA_TUNER_IT913X) += it913x.o -obj-$(CONFIG_MEDIA_TUNER_R820T) += r820t.o -obj-$(CONFIG_MEDIA_TUNER_MXL301RF) += mxl301rf.o -obj-$(CONFIG_MEDIA_TUNER_QM1D1C0042) += qm1d1c0042.o -obj-$(CONFIG_MEDIA_TUNER_M88RS6000T) += m88rs6000t.o - -ccflags-y += -I$(srctree)/drivers/media/dvb-core -ccflags-y += -I$(srctree)/drivers/media/dvb-frontends diff --git a/src/linux/drivers/media/usb/Kconfig b/src/linux/drivers/media/usb/Kconfig deleted file mode 100644 index 7496f33..0000000 --- a/src/linux/drivers/media/usb/Kconfig +++ /dev/null @@ -1,64 +0,0 @@ -if USB && MEDIA_SUPPORT - -menuconfig MEDIA_USB_SUPPORT - bool "Media USB Adapters" - help - Enable media drivers for USB bus. - If you have such devices, say Y. - -if MEDIA_USB_SUPPORT - -if MEDIA_CAMERA_SUPPORT - comment "Webcam devices" -source "drivers/media/usb/uvc/Kconfig" -source "drivers/media/usb/gspca/Kconfig" -source "drivers/media/usb/pwc/Kconfig" -source "drivers/media/usb/cpia2/Kconfig" -source "drivers/media/usb/zr364xx/Kconfig" -source "drivers/media/usb/stkwebcam/Kconfig" -source "drivers/media/usb/s2255/Kconfig" -source "drivers/media/usb/usbtv/Kconfig" -endif - -if MEDIA_ANALOG_TV_SUPPORT - comment "Analog TV USB devices" -source "drivers/media/usb/pvrusb2/Kconfig" -source "drivers/media/usb/hdpvr/Kconfig" -source "drivers/media/usb/usbvision/Kconfig" -source "drivers/media/usb/stk1160/Kconfig" -source "drivers/media/usb/go7007/Kconfig" -endif - -if (MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT) - comment "Analog/digital TV USB devices" -source "drivers/media/usb/au0828/Kconfig" -source "drivers/media/usb/cx231xx/Kconfig" -source "drivers/media/usb/tm6000/Kconfig" -endif - - -if I2C && MEDIA_DIGITAL_TV_SUPPORT - comment "Digital TV USB devices" -source "drivers/media/usb/dvb-usb/Kconfig" -source "drivers/media/usb/dvb-usb-v2/Kconfig" -source "drivers/media/usb/ttusb-budget/Kconfig" -source "drivers/media/usb/ttusb-dec/Kconfig" -source "drivers/media/usb/siano/Kconfig" -source "drivers/media/usb/b2c2/Kconfig" -source "drivers/media/usb/as102/Kconfig" -endif - -if (MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT) - comment "Webcam, TV (analog/digital) USB devices" -source "drivers/media/usb/em28xx/Kconfig" -endif - -if MEDIA_SDR_SUPPORT - comment "Software defined radio USB devices" -source "drivers/media/usb/airspy/Kconfig" -source "drivers/media/usb/hackrf/Kconfig" -source "drivers/media/usb/msi2500/Kconfig" -endif - -endif #MEDIA_USB_SUPPORT -endif #USB diff --git a/src/linux/drivers/media/usb/Makefile b/src/linux/drivers/media/usb/Makefile deleted file mode 100644 index 8874ba7..0000000 --- a/src/linux/drivers/media/usb/Makefile +++ /dev/null @@ -1,26 +0,0 @@ -# -# Makefile for the USB media device drivers -# - -# DVB USB-only drivers -obj-y += ttusb-dec/ ttusb-budget/ dvb-usb/ dvb-usb-v2/ siano/ b2c2/ -obj-y += zr364xx/ stkwebcam/ s2255/ - -obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/ -obj-$(CONFIG_USB_GSPCA) += gspca/ -obj-$(CONFIG_USB_PWC) += pwc/ -obj-$(CONFIG_USB_AIRSPY) += airspy/ -obj-$(CONFIG_USB_HACKRF) += hackrf/ -obj-$(CONFIG_USB_MSI2500) += msi2500/ -obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ -obj-$(CONFIG_VIDEO_AU0828) += au0828/ -obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/ -obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/ -obj-$(CONFIG_VIDEO_USBVISION) += usbvision/ -obj-$(CONFIG_VIDEO_STK1160) += stk1160/ -obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/ -obj-$(CONFIG_VIDEO_TM6000) += tm6000/ -obj-$(CONFIG_VIDEO_EM28XX) += em28xx/ -obj-$(CONFIG_VIDEO_USBTV) += usbtv/ -obj-$(CONFIG_VIDEO_GO7007) += go7007/ -obj-$(CONFIG_DVB_AS102) += as102/ diff --git a/src/linux/drivers/media/usb/airspy/Kconfig b/src/linux/drivers/media/usb/airspy/Kconfig deleted file mode 100644 index 10b204c..0000000 --- a/src/linux/drivers/media/usb/airspy/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config USB_AIRSPY - tristate "AirSpy" - depends on VIDEO_V4L2 - select VIDEOBUF2_VMALLOC - ---help--- - This is a video4linux2 driver for AirSpy SDR device. - - To compile this driver as a module, choose M here: the - module will be called airspy - diff --git a/src/linux/drivers/media/usb/as102/Kconfig b/src/linux/drivers/media/usb/as102/Kconfig deleted file mode 100644 index 28aba00..0000000 --- a/src/linux/drivers/media/usb/as102/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config DVB_AS102 - tristate "Abilis AS102 DVB receiver" - depends on DVB_CORE && USB && I2C && INPUT - select FW_LOADER - help - Choose Y or M here if you have a device containing an AS102 - - To compile this driver as a module, choose M here diff --git a/src/linux/drivers/media/usb/au0828/Kconfig b/src/linux/drivers/media/usb/au0828/Kconfig deleted file mode 100644 index 78b797e..0000000 --- a/src/linux/drivers/media/usb/au0828/Kconfig +++ /dev/null @@ -1,36 +0,0 @@ - -config VIDEO_AU0828 - tristate "Auvitek AU0828 support" - depends on I2C && INPUT && DVB_CORE && USB - select I2C_ALGOBIT - select VIDEO_TVEEPROM - select VIDEOBUF2_VMALLOC - select DVB_AU8522_DTV if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT - ---help--- - This is a hybrid analog/digital tv capture driver for - Auvitek's AU0828 USB device. - - To compile this driver as a module, choose M here: the - module will be called au0828 - -config VIDEO_AU0828_V4L2 - bool "Auvitek AU0828 v4l2 analog video support" - depends on VIDEO_AU0828 && VIDEO_V4L2 - select DVB_AU8522_V4L if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_TUNER - default y - ---help--- - This is a video4linux driver for Auvitek's USB device. - - Choose Y here to include support for v4l2 analog video - capture within the au0828 driver. - -config VIDEO_AU0828_RC - bool "AU0828 Remote Controller support" - depends on RC_CORE - depends on VIDEO_AU0828 - ---help--- - Enables Remote Controller support on au0828 driver. diff --git a/src/linux/drivers/media/usb/b2c2/Kconfig b/src/linux/drivers/media/usb/b2c2/Kconfig deleted file mode 100644 index 17d3583..0000000 --- a/src/linux/drivers/media/usb/b2c2/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -config DVB_B2C2_FLEXCOP_USB - tristate "Technisat/B2C2 Air/Sky/Cable2PC USB" - depends on DVB_CORE && I2C - help - Support for the Air/Sky/Cable2PC USB1.1 box (DVB/ATSC) by Technisat/B2C2, - - Say Y if you own such a device and want to use it. - -config DVB_B2C2_FLEXCOP_USB_DEBUG - bool "Enable debug for the B2C2 FlexCop drivers" - depends on DVB_B2C2_FLEXCOP_USB - select DVB_B2C2_FLEXCOP_DEBUG - help - Say Y if you want to enable the module option to control debug messages - of all B2C2 FlexCop drivers. diff --git a/src/linux/drivers/media/usb/b2c2/Makefile b/src/linux/drivers/media/usb/b2c2/Makefile deleted file mode 100644 index 2778c19..0000000 --- a/src/linux/drivers/media/usb/b2c2/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -b2c2-flexcop-usb-objs := flexcop-usb.o -obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o - -ccflags-y += -Idrivers/media/dvb-core/ -ccflags-y += -Idrivers/media/common/b2c2/ diff --git a/src/linux/drivers/media/usb/cpia2/Kconfig b/src/linux/drivers/media/usb/cpia2/Kconfig deleted file mode 100644 index 66e9283..0000000 --- a/src/linux/drivers/media/usb/cpia2/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config VIDEO_CPIA2 - tristate "CPiA2 Video For Linux" - depends on VIDEO_DEV && USB && VIDEO_V4L2 - ---help--- - This is the video4linux driver for cameras based on Vision's CPiA2 - (Colour Processor Interface ASIC), such as the Digital Blue QX5 - Microscope. If you have one of these cameras, say Y here - - This driver is also available as a module (cpia2). diff --git a/src/linux/drivers/media/usb/cx231xx/Kconfig b/src/linux/drivers/media/usb/cx231xx/Kconfig deleted file mode 100644 index 0cced3e..0000000 --- a/src/linux/drivers/media/usb/cx231xx/Kconfig +++ /dev/null @@ -1,57 +0,0 @@ -config VIDEO_CX231XX - tristate "Conexant cx231xx USB video capture support" - depends on VIDEO_DEV && I2C - select VIDEO_TUNER - select VIDEO_TVEEPROM - depends on RC_CORE - select VIDEOBUF_VMALLOC - select VIDEO_CX25840 - select VIDEO_CX2341X - select I2C_MUX - - ---help--- - This is a video4linux driver for Conexant 231xx USB based TV cards. - - To compile this driver as a module, choose M here: the - module will be called cx231xx - -config VIDEO_CX231XX_RC - bool "Conexant cx231xx Remote Controller additional support" - depends on RC_CORE - depends on VIDEO_CX231XX - default y - ---help--- - cx231xx hardware has a builtin RX/TX support. However, a few - designs opted to not use it, but, instead, some other hardware. - This module enables the usage of those other hardware, like the - ones used with ISDB-T boards. - - On most cases, all you need for IR is mceusb module. - -config VIDEO_CX231XX_ALSA - tristate "Conexant Cx231xx ALSA audio module" - depends on VIDEO_CX231XX && SND - select SND_PCM - - ---help--- - This is an ALSA driver for Cx231xx USB based TV cards. - - To compile this driver as a module, choose M here: the - module will be called cx231xx-alsa - -config VIDEO_CX231XX_DVB - tristate "DVB/ATSC Support for Cx231xx based TV cards" - depends on VIDEO_CX231XX && DVB_CORE - select VIDEOBUF_DVB - select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT - select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT - select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT - select DVB_LGDT3306A if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT - select DVB_SI2165 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT - - ---help--- - This adds support for DVB cards based on the - Conexant cx231xx chips. diff --git a/src/linux/drivers/media/usb/dvb-usb-v2/Kconfig b/src/linux/drivers/media/usb/dvb-usb-v2/Kconfig deleted file mode 100644 index 524533d..0000000 --- a/src/linux/drivers/media/usb/dvb-usb-v2/Kconfig +++ /dev/null @@ -1,158 +0,0 @@ -config DVB_USB_V2 - tristate "Support for various USB DVB devices v2" - depends on DVB_CORE && USB && I2C && (RC_CORE || RC_CORE=n) - help - By enabling this you will be able to choose the various supported - USB1.1 and USB2.0 DVB devices. - - Almost every USB device needs a firmware, please look into - . - - For a complete list of supported USB devices see the LinuxTV DVB Wiki: - - - Say Y if you own a USB DVB device. - -config DVB_USB_AF9015 - tristate "Afatech AF9015 DVB-T USB2.0 support" - depends on DVB_USB_V2 - select DVB_AF9013 - select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MC44S803 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA18218 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver - -config DVB_USB_AF9035 - tristate "Afatech AF9035 DVB-T USB2.0 support" - depends on DVB_USB_V2 - select DVB_AF9033 - select MEDIA_TUNER_TUA9001 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_FC0011 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA18218 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_FC2580 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_IT913X if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the Afatech AF9035 based DVB USB receiver. - -config DVB_USB_ANYSEE - tristate "Anysee DVB-T/C USB2.0 support" - depends on DVB_USB_V2 - select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT - select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT - select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT - select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT - select DVB_ISL6423 if MEDIA_SUBDRV_AUTOSELECT - select DVB_CXD2820R if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the Anysee E30, Anysee E30 Plus or - Anysee E30 C Plus DVB USB2.0 receiver. - -config DVB_USB_AU6610 - tristate "Alcor Micro AU6610 USB2.0 support" - depends on DVB_USB_V2 - select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the Sigmatek DVB-110 DVB-T USB2.0 receiver. - -config DVB_USB_AZ6007 - tristate "AzureWave 6007 and clones DVB-T/C USB2.0 support" - depends on DVB_USB_V2 - select CYPRESS_FIRMWARE - select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MT2063 if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the AZ6007 receivers like Terratec H7. - -config DVB_USB_CE6230 - tristate "Intel CE6230 DVB-T USB2.0 support" - depends on DVB_USB_V2 - select DVB_ZL10353 - select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver - -config DVB_USB_EC168 - tristate "E3C EC168 DVB-T USB2.0 support" - depends on DVB_USB_V2 - select DVB_EC100 - select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the E3C EC168 DVB-T USB2.0 receiver. - -config DVB_USB_GL861 - tristate "Genesys Logic GL861 USB2.0 support" - depends on DVB_USB_V2 - select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the MSI Megasky 580 (55801) DVB-T USB2.0 - receiver with USB ID 0db0:5581. - -config DVB_USB_LME2510 - tristate "LME DM04/QQBOX DVB-S USB2.0 support" - depends on DVB_USB_V2 - depends on RC_CORE - select DVB_TDA10086 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA826X if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT - select DVB_IX2505V if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT - select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT - select DVB_M88RS2000 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 - -config DVB_USB_MXL111SF - tristate "MxL111SF DTV USB2.0 support" - depends on DVB_USB_V2 - select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT - select DVB_LG2160 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_TVEEPROM - help - Say Y here to support the MxL111SF USB2.0 DTV receiver. - -config DVB_USB_RTL28XXU - tristate "Realtek RTL28xxU DVB USB support" - depends on DVB_USB_V2 && I2C_MUX - select DVB_MN88472 if MEDIA_SUBDRV_AUTOSELECT - select DVB_MN88473 if MEDIA_SUBDRV_AUTOSELECT - select DVB_RTL2830 - select DVB_RTL2832 - select DVB_RTL2832_SDR if (MEDIA_SUBDRV_AUTOSELECT && MEDIA_SDR_SUPPORT) - select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_E4000 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_FC0012 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_FC0013 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_FC2580 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_R820T if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TUA9001 if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the Realtek RTL28xxU DVB USB receiver. - -config DVB_USB_DVBSKY - tristate "DVBSky USB support" - depends on DVB_USB_V2 - select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT - select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT - select DVB_SP2 if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the USB receivers from DVBSky. diff --git a/src/linux/drivers/media/usb/dvb-usb-v2/Makefile b/src/linux/drivers/media/usb/dvb-usb-v2/Makefile deleted file mode 100644 index f10d4df..0000000 --- a/src/linux/drivers/media/usb/dvb-usb-v2/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -dvb_usb_v2-objs := dvb_usb_core.o dvb_usb_urb.o usb_urb.o -obj-$(CONFIG_DVB_USB_V2) += dvb_usb_v2.o - -dvb-usb-af9015-objs := af9015.o -obj-$(CONFIG_DVB_USB_AF9015) += dvb-usb-af9015.o - -dvb-usb-af9035-objs := af9035.o -obj-$(CONFIG_DVB_USB_AF9035) += dvb-usb-af9035.o - -dvb-usb-anysee-objs := anysee.o -obj-$(CONFIG_DVB_USB_ANYSEE) += dvb-usb-anysee.o - -dvb-usb-au6610-objs := au6610.o -obj-$(CONFIG_DVB_USB_AU6610) += dvb-usb-au6610.o - -dvb-usb-az6007-objs := az6007.o -obj-$(CONFIG_DVB_USB_AZ6007) += dvb-usb-az6007.o - -dvb-usb-ce6230-objs := ce6230.o -obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o - -dvb-usb-ec168-objs := ec168.o -obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o - -dvb-usb-lmedm04-objs := lmedm04.o -obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o - -dvb-usb-gl861-objs := gl861.o -obj-$(CONFIG_DVB_USB_GL861) += dvb-usb-gl861.o - -dvb-usb-mxl111sf-objs += mxl111sf.o mxl111sf-phy.o mxl111sf-i2c.o -dvb-usb-mxl111sf-objs += mxl111sf-gpio.o -obj-$(CONFIG_DVB_USB_MXL111SF) += dvb-usb-mxl111sf.o -obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-demod.o -obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o - -dvb-usb-rtl28xxu-objs := rtl28xxu.o -obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o - -dvb-usb-dvbsky-objs := dvbsky.o -obj-$(CONFIG_DVB_USB_DVBSKY) += dvb-usb-dvbsky.o - -ccflags-y += -I$(srctree)/drivers/media/dvb-core -ccflags-y += -I$(srctree)/drivers/media/dvb-frontends -ccflags-y += -I$(srctree)/drivers/media/tuners -ccflags-y += -I$(srctree)/drivers/media/common diff --git a/src/linux/drivers/media/usb/dvb-usb/Kconfig b/src/linux/drivers/media/usb/dvb-usb/Kconfig deleted file mode 100644 index 959fa09..0000000 --- a/src/linux/drivers/media/usb/dvb-usb/Kconfig +++ /dev/null @@ -1,333 +0,0 @@ -config DVB_USB - tristate "Support for various USB DVB devices" - depends on DVB_CORE && USB && I2C && RC_CORE - help - By enabling this you will be able to choose the various supported - USB1.1 and USB2.0 DVB devices. - - Almost every USB device needs a firmware, please look into - . - - For a complete list of supported USB devices see the LinuxTV DVB Wiki: - - - Say Y if you own a USB DVB device. - -config DVB_USB_DEBUG - bool "Enable extended debug support for all DVB-USB devices" - depends on DVB_USB - help - Say Y if you want to enable debugging. See modinfo dvb-usb (and the - appropriate drivers) for debug levels. - -config DVB_USB_DIB3000MC - tristate - depends on DVB_USB - select DVB_DIB3000MC - help - This is a module with helper functions for accessing the - DIB3000MC from USB DVB devices. It must be a separate module - in case DVB_USB is built-in and DVB_DIB3000MC is a module, - and gets selected automatically when needed. - -config DVB_USB_A800 - tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)" - depends on DVB_USB - select DVB_USB_DIB3000MC - select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver. - -config DVB_USB_DIBUSB_MB - tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)" - depends on DVB_USB - select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT - select DVB_DIB3000MB - depends on DVB_DIB3000MC || !DVB_DIB3000MC - select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT - help - Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by - DiBcom () equipped with a DiB3000M-B demodulator. - - For an up-to-date list of devices supported by this driver, have a look - on the Linux-DVB Wiki at www.linuxtv.org. - - Say Y if you own such a device and want to use it. You should build it as - a module. - -config DVB_USB_DIBUSB_MB_FAULTY - bool "Support faulty USB IDs" - depends on DVB_USB_DIBUSB_MB - help - Support for faulty USB IDs due to an invalid EEPROM on some Artec devices. - -config DVB_USB_DIBUSB_MC - tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)" - depends on DVB_USB - select DVB_USB_DIB3000MC - select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT - help - Support for USB2.0 DVB-T receivers based on reference designs made by - DiBcom () equipped with a DiB3000M-C/P demodulator. - - For an up-to-date list of devices supported by this driver, have a look - on the Linux-DVB Wiki at www.linuxtv.org. - - Say Y if you own such a device and want to use it. You should build it as - a module. - -config DVB_USB_DIB0700 - tristate "DiBcom DiB0700 USB DVB devices (see help for supported devices)" - depends on DVB_USB - select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT - select DVB_DIB7000M if MEDIA_SUBDRV_AUTOSELECT - select DVB_DIB8000 if MEDIA_SUBDRV_AUTOSELECT - select DVB_USB_DIB3000MC if MEDIA_SUBDRV_AUTOSELECT - select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT - select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TUNER_DIB0090 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MT2266 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_XC4000 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT - help - Support for USB2.0/1.1 DVB receivers based on the DiB0700 USB bridge. The - USB bridge is also present in devices having the DiB7700 DVB-T-USB - silicon. This chip can be found in devices offered by Hauppauge, - Avermedia and other big and small companies. - - For an up-to-date list of devices supported by this driver, have a look - on the LinuxTV Wiki at www.linuxtv.org. - - Say Y if you own such a device and want to use it. You should build it as - a module. - -config DVB_USB_UMT_010 - tristate "HanfTek UMT-010 DVB-T USB2.0 support" - depends on DVB_USB - select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT - select DVB_USB_DIB3000MC - select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT - select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver. - -config DVB_USB_CXUSB - tristate "Conexant USB2.0 hybrid reference design support" - depends on DVB_USB - select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT - select DVB_CX22702 if MEDIA_SUBDRV_AUTOSELECT - select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT - select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT - select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT - select DVB_DIB7000P if MEDIA_SUBDRV_AUTOSELECT - select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT - select DVB_ATBM8830 if MEDIA_SUBDRV_AUTOSELECT - select DVB_LGS8GXX if MEDIA_SUBDRV_AUTOSELECT - select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MAX2165 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the Conexant USB2.0 hybrid reference design. - Currently, only DVB and ATSC modes are supported, analog mode - shall be added in the future. Devices that require this module: - - Medion MD95700 hybrid USB2.0 device. - DViCO FusionHDTV (Bluebird) USB2.0 devices - -config DVB_USB_M920X - tristate "Uli m920x DVB-T USB2.0 support" - depends on DVB_USB - select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA827X if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver. - Currently, only devices with a product id of - "DTV USB MINI" (in cold state) are supported. - Firmware required. - -config DVB_USB_DIGITV - tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support" - depends on DVB_USB - select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT - select DVB_NXT6000 if MEDIA_SUBDRV_AUTOSELECT - select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver. - -config DVB_USB_VP7045 - tristate "TwinhanDTV Alpha/MagicBoxII, DNTV tinyUSB2, Beetle USB2.0 support" - depends on DVB_USB - help - Say Y here to support the - - TwinhanDTV Alpha (stick) (VP-7045), - TwinhanDTV MagicBox II (VP-7046), - DigitalNow TinyUSB 2 DVB-t, - DigitalRise USB 2.0 Ter (Beetle) and - TYPHOON DVB-T USB DRIVE - - DVB-T USB2.0 receivers. - -config DVB_USB_VP702X - tristate "TwinhanDTV StarBox and clones DVB-S USB2.0 support" - depends on DVB_USB - help - Say Y here to support the - - TwinhanDTV StarBox, - DigitalRise USB Starbox and - TYPHOON DVB-S USB 2.0 BOX - - DVB-S USB2.0 receivers. - -config DVB_USB_GP8PSK - tristate "GENPIX 8PSK->USB module support" - depends on DVB_USB - help - Say Y here to support the - GENPIX 8psk module - - DVB-S USB2.0 receivers. - -config DVB_USB_NOVA_T_USB2 - tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" - depends on DVB_USB - select DVB_USB_DIB3000MC - select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver. - -config DVB_USB_TTUSB2 - tristate "Pinnacle 400e DVB-S USB2.0 support" - depends on DVB_USB - select DVB_TDA10086 if MEDIA_SUBDRV_AUTOSELECT - select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA826X if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA827X if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the Pinnacle 400e DVB-S USB2.0 receiver and - the TechnoTrend CT-3650 CI DVB-C/T USB2.0 receiver. The - firmware protocol used by this module is similar to the one used by the - old ttusb-driver - that's why the module is called dvb-usb-ttusb2. - -config DVB_USB_DTT200U - tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)" - depends on DVB_USB - help - Say Y here to support the WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver. - - The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan). - - The WT-220U and its clones are pen-sized. - -config DVB_USB_OPERA1 - tristate "Opera1 DVB-S USB2.0 receiver" - depends on DVB_USB - select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT - select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the Opera DVB-S USB2.0 receiver. - -config DVB_USB_AF9005 - tristate "Afatech AF9005 DVB-T USB1.1 support" - depends on DVB_USB - select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the Afatech AF9005 based DVB-T USB1.1 receiver - and the TerraTec Cinergy T USB XE (Rev.1) - -config DVB_USB_AF9005_REMOTE - tristate "Afatech AF9005 default remote control support" - depends on DVB_USB_AF9005 - help - Say Y here to support the default remote control decoding for the - Afatech AF9005 based receiver. - -config DVB_USB_PCTV452E - tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600" - depends on DVB_USB - select TTPCI_EEPROM - select DVB_LNBP22 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT - help - Support for external USB adapter designed by Pinnacle, - shipped under the brand name 'PCTV HDTV Pro USB'. - Also supports TT Connect S2-3600/3650 cards. - Say Y if you own such a device and want to use it. - -config DVB_USB_DW2102 - tristate "DvbWorld & TeVii DVB-S/S2 USB2.0 support" - depends on DVB_USB - select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0288 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB6000 if MEDIA_SUBDRV_AUTOSELECT - select DVB_CX24116 if MEDIA_SUBDRV_AUTOSELECT - select DVB_SI21XX if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT - select DVB_MT312 if MEDIA_SUBDRV_AUTOSELECT - select DVB_ZL10039 if MEDIA_SUBDRV_AUTOSELECT - select DVB_DS3000 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV6110 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0900 if MEDIA_SUBDRV_AUTOSELECT - select DVB_M88RS2000 if MEDIA_SUBDRV_AUTOSELECT - select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the DvbWorld, TeVii, Prof, TechnoTrend - DVB-S/S2 USB2.0 receivers. - -config DVB_USB_CINERGY_T2 - tristate "Terratec CinergyT2/qanu USB 2.0 DVB-T receiver" - depends on DVB_USB - help - Support for "TerraTec CinergyT2" USB2.0 Highspeed DVB Receivers - - Say Y if you own such a device and want to use it. - -config DVB_USB_DTV5100 - tristate "AME DTV-5100 USB2.0 DVB-T support" - depends on DVB_USB - select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the AME DTV-5100 USB2.0 DVB-T receiver. - -config DVB_USB_FRIIO - tristate "Friio ISDB-T USB2.0 Receiver support" - depends on DVB_USB - help - Say Y here to support the Japanese DTV receiver Friio. - -config DVB_USB_AZ6027 - tristate "Azurewave DVB-S/S2 USB2.0 AZ6027 support" - depends on DVB_USB - select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the AZ6027 device - -config DVB_USB_TECHNISAT_USB2 - tristate "Technisat DVB-S/S2 USB2.0 support" - depends on DVB_USB - select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT - help - Say Y here to support the Technisat USB2 DVB-S/S2 device diff --git a/src/linux/drivers/media/usb/dvb-usb/Makefile b/src/linux/drivers/media/usb/dvb-usb/Makefile deleted file mode 100644 index 3b3f32b..0000000 --- a/src/linux/drivers/media/usb/dvb-usb/Makefile +++ /dev/null @@ -1,86 +0,0 @@ -dvb-usb-objs += dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o -dvb-usb-objs += dvb-usb-dvb.o dvb-usb-remote.o usb-urb.o -obj-$(CONFIG_DVB_USB) += dvb-usb.o - -dvb-usb-vp7045-objs := vp7045.o vp7045-fe.o -obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o - -dvb-usb-vp702x-objs := vp702x.o vp702x-fe.o -obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o - -dvb-usb-gp8psk-objs := gp8psk.o -obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o - -dvb-usb-dtt200u-objs := dtt200u.o dtt200u-fe.o -obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o - -dvb-usb-dibusb-common-objs := dibusb-common.o - -dvb-usb-dibusb-mc-common-objs := dibusb-mc-common.o -obj-$(CONFIG_DVB_USB_DIB3000MC) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mc-common.o - -dvb-usb-a800-objs := a800.o -obj-$(CONFIG_DVB_USB_A800) += dvb-usb-a800.o - -dvb-usb-dibusb-mb-objs := dibusb-mb.o -obj-$(CONFIG_DVB_USB_DIBUSB_MB) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mb.o - -dvb-usb-dibusb-mc-objs := dibusb-mc.o -obj-$(CONFIG_DVB_USB_DIBUSB_MC) += dvb-usb-dibusb-mc.o - -dvb-usb-nova-t-usb2-objs := nova-t-usb2.o -obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-nova-t-usb2.o - -dvb-usb-umt-010-objs := umt-010.o -obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-umt-010.o - -dvb-usb-m920x-objs := m920x.o -obj-$(CONFIG_DVB_USB_M920X) += dvb-usb-m920x.o - -dvb-usb-digitv-objs := digitv.o -obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o - -dvb-usb-cxusb-objs := cxusb.o -obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o - -dvb-usb-ttusb2-objs := ttusb2.o -obj-$(CONFIG_DVB_USB_TTUSB2) += dvb-usb-ttusb2.o - -dvb-usb-dib0700-objs := dib0700_core.o dib0700_devices.o -obj-$(CONFIG_DVB_USB_DIB0700) += dvb-usb-dib0700.o - -dvb-usb-opera-objs := opera1.o -obj-$(CONFIG_DVB_USB_OPERA1) += dvb-usb-opera.o - -dvb-usb-af9005-objs := af9005.o af9005-fe.o -obj-$(CONFIG_DVB_USB_AF9005) += dvb-usb-af9005.o - -dvb-usb-af9005-remote-objs := af9005-remote.o -obj-$(CONFIG_DVB_USB_AF9005_REMOTE) += dvb-usb-af9005-remote.o - -dvb-usb-pctv452e-objs := pctv452e.o -obj-$(CONFIG_DVB_USB_PCTV452E) += dvb-usb-pctv452e.o - -dvb-usb-dw2102-objs := dw2102.o -obj-$(CONFIG_DVB_USB_DW2102) += dvb-usb-dw2102.o - -dvb-usb-dtv5100-objs := dtv5100.o -obj-$(CONFIG_DVB_USB_DTV5100) += dvb-usb-dtv5100.o - -dvb-usb-cinergyT2-objs := cinergyT2-core.o cinergyT2-fe.o -obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o - -dvb-usb-friio-objs := friio.o friio-fe.o -obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o - -dvb-usb-az6027-objs := az6027.o -obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o - -dvb-usb-technisat-usb2-objs := technisat-usb2.o -obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o - -ccflags-y += -I$(srctree)/drivers/media/dvb-core -ccflags-y += -I$(srctree)/drivers/media/dvb-frontends/ -# due to tuner-xc3028 -ccflags-y += -I$(srctree)/drivers/media/tuners -ccflags-y += -I$(srctree)/drivers/media/pci/ttpci diff --git a/src/linux/drivers/media/usb/em28xx/Kconfig b/src/linux/drivers/media/usb/em28xx/Kconfig deleted file mode 100644 index d917b0a..0000000 --- a/src/linux/drivers/media/usb/em28xx/Kconfig +++ /dev/null @@ -1,75 +0,0 @@ -config VIDEO_EM28XX - tristate "Empia EM28xx USB devices support" - depends on VIDEO_DEV && I2C - select VIDEO_TUNER - select VIDEO_TVEEPROM - -config VIDEO_EM28XX_V4L2 - tristate "Empia EM28xx analog TV, video capture and/or webcam support" - depends on VIDEO_EM28XX - select VIDEOBUF2_VMALLOC - select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_MT9V011 if MEDIA_SUBDRV_AUTOSELECT - - ---help--- - This is a video4linux driver for Empia 28xx based TV cards. - - To compile this driver as a module, choose M here: the - module will be called em28xx - -config VIDEO_EM28XX_ALSA - depends on VIDEO_EM28XX && SND - select SND_PCM - tristate "Empia EM28xx ALSA audio module" - ---help--- - This is an ALSA driver for some Empia 28xx based TV cards. - - This is not required for em2800/em2820/em2821 boards. However, - newer em28xx devices uses Vendor Class for audio, instead of - implementing the USB Audio Class. For those chips, this module - will enable digital audio. - - To compile this driver as a module, choose M here: the - module will be called em28xx-alsa - -config VIDEO_EM28XX_DVB - tristate "DVB/ATSC Support for em28xx based TV cards" - depends on VIDEO_EM28XX && DVB_CORE - select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT - select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT - select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10023 if MEDIA_SUBDRV_AUTOSELECT - select DVB_S921 if MEDIA_SUBDRV_AUTOSELECT - select DVB_DRXD if MEDIA_SUBDRV_AUTOSELECT - select DVB_CXD2820R if MEDIA_SUBDRV_AUTOSELECT - select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10071 if MEDIA_SUBDRV_AUTOSELECT - select DVB_A8293 if MEDIA_SUBDRV_AUTOSELECT - select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT - select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT - select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT - select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TS2020 if MEDIA_SUBDRV_AUTOSELECT - select DVB_DRX39XYJ if MEDIA_SUBDRV_AUTOSELECT - select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TC90522 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_QM1D1C0042 if MEDIA_SUBDRV_AUTOSELECT - ---help--- - This adds support for DVB cards based on the - Empiatech em28xx chips. - -config VIDEO_EM28XX_RC - tristate "EM28XX Remote Controller support" - depends on RC_CORE - depends on VIDEO_EM28XX - depends on !(RC_CORE=m && VIDEO_EM28XX=y) - default VIDEO_EM28XX - ---help--- - Enables Remote Controller support on em28xx driver. diff --git a/src/linux/drivers/media/usb/go7007/Kconfig b/src/linux/drivers/media/usb/go7007/Kconfig deleted file mode 100644 index 95a3af6..0000000 --- a/src/linux/drivers/media/usb/go7007/Kconfig +++ /dev/null @@ -1,51 +0,0 @@ -config VIDEO_GO7007 - tristate "WIS GO7007 MPEG encoder support" - depends on VIDEO_DEV && I2C - depends on SND && USB - select VIDEOBUF2_VMALLOC - select VIDEO_TUNER - select CYPRESS_FIRMWARE - select SND_PCM - select VIDEO_SONY_BTF_MPX if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_TW2804 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_TW9903 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_TW9906 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_OV7640 if MEDIA_SUBDRV_AUTOSELECT - select VIDEO_UDA1342 if MEDIA_SUBDRV_AUTOSELECT - ---help--- - This is a video4linux driver for the WIS GO7007 MPEG - encoder chip. - - To compile this driver as a module, choose M here: the - module will be called go7007. - -config VIDEO_GO7007_USB - tristate "WIS GO7007 USB support" - depends on VIDEO_GO7007 && USB - ---help--- - This is a video4linux driver for the WIS GO7007 MPEG - encoder chip over USB. - - To compile this driver as a module, choose M here: the - module will be called go7007-usb. - -config VIDEO_GO7007_LOADER - tristate "WIS GO7007 Loader support" - depends on VIDEO_GO7007 - default y - ---help--- - This is a go7007 firmware loader driver for the WIS GO7007 - MPEG encoder chip over USB. - - To compile this driver as a module, choose M here: the - module will be called go7007-loader. - -config VIDEO_GO7007_USB_S2250_BOARD - tristate "Sensoray 2250/2251 support" - depends on VIDEO_GO7007_USB && USB - ---help--- - This is a video4linux driver for the Sensoray 2250/2251 device. - - To compile this driver as a module, choose M here: the - module will be called s2250. diff --git a/src/linux/drivers/media/usb/gspca/Kconfig b/src/linux/drivers/media/usb/gspca/Kconfig deleted file mode 100644 index 3fd94fe..0000000 --- a/src/linux/drivers/media/usb/gspca/Kconfig +++ /dev/null @@ -1,455 +0,0 @@ -menuconfig USB_GSPCA - tristate "GSPCA based webcams" - depends on VIDEO_V4L2 - depends on INPUT || INPUT=n - default m - ---help--- - Say Y here if you want to enable selecting webcams based - on the GSPCA framework. - - See for more info. - - This driver uses the Video For Linux API. You must say Y or M to - "Video For Linux" to use this driver. - - To compile this driver as modules, choose M here: the - module will be called gspca_main. - - -if USB_GSPCA && VIDEO_V4L2 - -source "drivers/media/usb/gspca/m5602/Kconfig" -source "drivers/media/usb/gspca/stv06xx/Kconfig" -source "drivers/media/usb/gspca/gl860/Kconfig" - -config USB_GSPCA_BENQ - tristate "Benq USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for the Benq DC E300 camera. - - To compile this driver as a module, choose M here: the - module will be called gspca_benq. - -config USB_GSPCA_CONEX - tristate "Conexant Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the Conexant chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_conex. - -config USB_GSPCA_CPIA1 - tristate "cpia CPiA (version 1) Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for USB cameras based on the cpia - CPiA chip. Note that you need atleast version 0.6.4 of libv4l for - applications to understand the videoformat generated by this driver. - - To compile this driver as a module, choose M here: the - module will be called gspca_cpia1. - -config USB_GSPCA_DTCS033 - tristate "DTCS033 (Scopium) USB Astro-Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for the Scopium camera - for planetary astrophotography. - - To compile this driver as a module, choose M here: the - module will be called gspca_dtcs033. - -config USB_GSPCA_ETOMS - tristate "Etoms USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the Etoms chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_etoms. - -config USB_GSPCA_FINEPIX - tristate "Fujifilm FinePix USB V4L2 driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the FinePix chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_finepix. - -config USB_GSPCA_JEILINJ - tristate "Jeilin JPEG USB V4L2 driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on this Jeilin chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_jeilinj. - -config USB_GSPCA_JL2005BCD - tristate "JL2005B/C/D USB V4L2 driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based the - JL2005B, JL2005C, or JL2005D chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_jl2005bcd. - -config USB_GSPCA_KINECT - tristate "Kinect sensor device USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for the Microsoft Kinect sensor device. - - To compile this driver as a module, choose M here: the - module will be called gspca_kinect. - -config USB_GSPCA_KONICA - tristate "Konica USB Camera V4L2 driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the Konica chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_konica. - -config USB_GSPCA_MARS - tristate "Mars USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the Mars chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_mars. - -config USB_GSPCA_MR97310A - tristate "Mars-Semi MR97310A USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the MR97310A chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_mr97310a. - -config USB_GSPCA_NW80X - tristate "Divio based (NW80x) USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the NW80x chips. - - To compile this driver as a module, choose M here: the - module will be called gspca_nw80x. - -config USB_GSPCA_OV519 - tristate "OV51x / OVFX2 / W996xCF USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on one of these: - OV511(+), OV518(+), OV519, OVFX2, W9967CF, W9968CF - - To compile this driver as a module, choose M here: the - module will be called gspca_ov519. - -config USB_GSPCA_OV534 - tristate "OV534 OV772x USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the OV534 chip - and sensor OV772x (e.g. Sony Playstation EYE) - - To compile this driver as a module, choose M here: the - module will be called gspca_ov534. - -config USB_GSPCA_OV534_9 - tristate "OV534 OV965x USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the OV534 chip - and sensor OV965x (e.g. Hercules Dualpix) - - To compile this driver as a module, choose M here: the - module will be called gspca_ov534_9. - -config USB_GSPCA_PAC207 - tristate "Pixart PAC207 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the PAC207 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_pac207. - -config USB_GSPCA_PAC7302 - tristate "Pixart PAC7302 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the PAC7302 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_pac7302. - -config USB_GSPCA_PAC7311 - tristate "Pixart PAC7311 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the PAC7311 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_pac7311. - -config USB_GSPCA_SE401 - tristate "SE401 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the - Endpoints (formerly known as AOX) se401 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_se401. - -config USB_GSPCA_SN9C2028 - tristate "SONIX Dual-Mode USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want streaming support for Sonix SN9C2028 cameras. - These are supported as stillcams in libgphoto2/camlibs/sonix. - - To compile this driver as a module, choose M here: the - module will be called gspca_sn9c2028. - -config USB_GSPCA_SN9C20X - tristate "SN9C20X USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the - sn9c20x chips (SN9C201 and SN9C202). - - To compile this driver as a module, choose M here: the - module will be called gspca_sn9c20x. - -config USB_GSPCA_SONIXB - tristate "SONIX Bayer USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the Sonix - chips with Bayer format (SN9C101, SN9C102 and SN9C103). - - To compile this driver as a module, choose M here: the - module will be called gspca_sonixb. - -config USB_GSPCA_SONIXJ - tristate "SONIX JPEG USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the Sonix - chips with JPEG format (SN9C102P, SN9C105 and >= SN9C110). - - To compile this driver as a module, choose M here: the - module will be called gspca_sonixj - -config USB_GSPCA_SPCA500 - tristate "SPCA500 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SPCA500 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_spca500. - -config USB_GSPCA_SPCA501 - tristate "SPCA501 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SPCA501 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_spca501. - -config USB_GSPCA_SPCA505 - tristate "SPCA505 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SPCA505 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_spca505. - -config USB_GSPCA_SPCA506 - tristate "SPCA506 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SPCA506 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_spca506. - -config USB_GSPCA_SPCA508 - tristate "SPCA508 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SPCA508 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_spca508. - -config USB_GSPCA_SPCA561 - tristate "SPCA561 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SPCA561 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_spca561. - -config USB_GSPCA_SPCA1528 - tristate "SPCA1528 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SPCA1528 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_spca1528. - -config USB_GSPCA_SQ905 - tristate "SQ Technologies SQ905 based USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SQ905 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_sq905. - -config USB_GSPCA_SQ905C - tristate "SQ Technologies SQ905C based USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SQ905C chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_sq905c. - -config USB_GSPCA_SQ930X - tristate "SQ Technologies SQ930X based USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the SQ930X chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_sq930x. - -config USB_GSPCA_STK014 - tristate "Syntek DV4000 (STK014) USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the STK014 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_stk014. - -config USB_GSPCA_STK1135 - tristate "Syntek STK1135 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the STK1135 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_stk1135. - -config USB_GSPCA_STV0680 - tristate "STV0680 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the STV0680 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_stv0680. - -config USB_GSPCA_SUNPLUS - tristate "SUNPLUS USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the Sunplus - SPCA504(abc) SPCA533 SPCA536 chips. - - To compile this driver as a module, choose M here: the - module will be called gspca_sunplus. - -config USB_GSPCA_T613 - tristate "T613 (JPEG Compliance) USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the T613 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_t613. - -config USB_GSPCA_TOPRO - tristate "TOPRO USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the - TP6800 and TP6810 Topro chips. - - To compile this driver as a module, choose M here: the - module will be called gspca_topro. - -config USB_GSPCA_TOUPTEK - tristate "Touptek USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the ToupTek UCMOS - / AmScope MU series camera. - - To compile this driver as a module, choose M here: the - module will be called gspca_touptek. - -config USB_GSPCA_TV8532 - tristate "TV8532 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the TV8531 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_tv8532. - -config USB_GSPCA_VC032X - tristate "VC032X USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the VC032X chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_vc032x. - -config USB_GSPCA_VICAM - tristate "ViCam USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for the 3com homeconnect camera - (vicam). - - To compile this driver as a module, choose M here: the - module will be called gspca_vicam. - -config USB_GSPCA_XIRLINK_CIT - tristate "Xirlink C-It USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for Xirlink C-It bases cameras. - - To compile this driver as a module, choose M here: the - module will be called gspca_xirlink_cit. - -config USB_GSPCA_ZC3XX - tristate "ZC3XX USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the ZC3XX chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_zc3xx. - -endif diff --git a/src/linux/drivers/media/usb/gspca/gl860/Kconfig b/src/linux/drivers/media/usb/gspca/gl860/Kconfig deleted file mode 100644 index 22772f5..0000000 --- a/src/linux/drivers/media/usb/gspca/gl860/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config USB_GL860 - tristate "GL860 USB Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the GL860 chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_gl860. diff --git a/src/linux/drivers/media/usb/gspca/m5602/Kconfig b/src/linux/drivers/media/usb/gspca/m5602/Kconfig deleted file mode 100644 index 5a69016..0000000 --- a/src/linux/drivers/media/usb/gspca/m5602/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config USB_M5602 - tristate "ALi USB m5602 Camera Driver" - depends on VIDEO_V4L2 && USB_GSPCA - help - Say Y here if you want support for cameras based on the - ALi m5602 connected to various image sensors. - - See for more info. - - To compile this driver as a module, choose M here: the - module will be called gspca_m5602. diff --git a/src/linux/drivers/media/usb/gspca/stv06xx/Kconfig b/src/linux/drivers/media/usb/gspca/stv06xx/Kconfig deleted file mode 100644 index 634ad38..0000000 --- a/src/linux/drivers/media/usb/gspca/stv06xx/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config USB_STV06XX - tristate "STV06XX USB Camera Driver" - depends on USB_GSPCA - help - Say Y here if you want support for cameras based on - the ST STV06XX chip. - - To compile this driver as a module, choose M here: the - module will be called gspca_stv06xx. diff --git a/src/linux/drivers/media/usb/hackrf/Kconfig b/src/linux/drivers/media/usb/hackrf/Kconfig deleted file mode 100644 index 937e6f5..0000000 --- a/src/linux/drivers/media/usb/hackrf/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config USB_HACKRF - tristate "HackRF" - depends on VIDEO_V4L2 - select VIDEOBUF2_VMALLOC - ---help--- - This is a video4linux2 driver for HackRF SDR device. - - To compile this driver as a module, choose M here: the - module will be called hackrf - diff --git a/src/linux/drivers/media/usb/hdpvr/Kconfig b/src/linux/drivers/media/usb/hdpvr/Kconfig deleted file mode 100644 index d73d9a1..0000000 --- a/src/linux/drivers/media/usb/hdpvr/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ - -config VIDEO_HDPVR - tristate "Hauppauge HD PVR support" - depends on VIDEO_DEV && VIDEO_V4L2 - ---help--- - This is a video4linux driver for Hauppauge's HD PVR USB device. - - To compile this driver as a module, choose M here: the - module will be called hdpvr - diff --git a/src/linux/drivers/media/usb/msi2500/Kconfig b/src/linux/drivers/media/usb/msi2500/Kconfig deleted file mode 100644 index 9eff8a7..0000000 --- a/src/linux/drivers/media/usb/msi2500/Kconfig +++ /dev/null @@ -1,5 +0,0 @@ -config USB_MSI2500 - tristate "Mirics MSi2500" - depends on VIDEO_V4L2 && SPI - select VIDEOBUF2_VMALLOC - select MEDIA_TUNER_MSI001 diff --git a/src/linux/drivers/media/usb/pvrusb2/Kconfig b/src/linux/drivers/media/usb/pvrusb2/Kconfig deleted file mode 100644 index 60a2604..0000000 --- a/src/linux/drivers/media/usb/pvrusb2/Kconfig +++ /dev/null @@ -1,65 +0,0 @@ -config VIDEO_PVRUSB2 - tristate "Hauppauge WinTV-PVR USB2 support" - depends on VIDEO_V4L2 && I2C - select VIDEO_TUNER - select VIDEO_TVEEPROM - select VIDEO_CX2341X - select VIDEO_SAA711X - select VIDEO_CX25840 - select VIDEO_MSP3400 - select VIDEO_WM8775 - select VIDEO_CS53L32A - ---help--- - This is a video4linux driver for Conexant 23416 based - usb2 personal video recorder devices. - - To compile this driver as a module, choose M here: the - module will be called pvrusb2 - -config VIDEO_PVRUSB2_SYSFS - bool "pvrusb2 sysfs support" - default y - depends on VIDEO_PVRUSB2 && SYSFS - ---help--- - This option enables the operation of a sysfs based - interface for query and control of the pvrusb2 driver. - - This is not generally needed for v4l applications, - although certain applications are optimized to take - advantage of this feature. - - If you are in doubt, say Y. - - Note: This feature is experimental and subject to change. - -config VIDEO_PVRUSB2_DVB - bool "pvrusb2 ATSC/DVB support" - default y - depends on VIDEO_PVRUSB2 && DVB_CORE - select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT - select DVB_S5H1409 if MEDIA_SUBDRV_AUTOSELECT - select DVB_S5H1411 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA10048 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT - select MEDIA_TUNER_TDA8290 if MEDIA_SUBDRV_AUTOSELECT - ---help--- - - This option enables a DVB interface for the pvrusb2 driver. - If your device does not support digital television, this - feature will have no affect on the driver's operation. - - If you are in doubt, say Y. - -config VIDEO_PVRUSB2_DEBUGIFC - bool "pvrusb2 debug interface" - depends on VIDEO_PVRUSB2_SYSFS - ---help--- - This option enables the inclusion of a debug interface - in the pvrusb2 driver, hosted through sysfs. - - You do not need to select this option unless you plan - on debugging the driver or performing a manual firmware - extraction. - - If you are in doubt, say N. diff --git a/src/linux/drivers/media/usb/pwc/Kconfig b/src/linux/drivers/media/usb/pwc/Kconfig deleted file mode 100644 index d63d0a8..0000000 --- a/src/linux/drivers/media/usb/pwc/Kconfig +++ /dev/null @@ -1,48 +0,0 @@ -config USB_PWC - tristate "USB Philips Cameras" - depends on VIDEO_V4L2 - select VIDEOBUF2_VMALLOC - ---help--- - Say Y or M here if you want to use one of these Philips & OEM - webcams: - * Philips PCA645, PCA646 - * Philips PCVC675, PCVC680, PCVC690 - * Philips PCVC720/40, PCVC730, PCVC740, PCVC750 - * Philips SPC900NC - * Askey VC010 - * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro' - and 'Orbit'/'Sphere' - * Samsung MPC-C10, MPC-C30 - * Creative Webcam 5, Pro Ex - * SOTEC Afina Eye - * Visionite VCS-UC300, VCS-UM100 - - The PCA635, PCVC665 and PCVC720/20 are not supported by this driver - and never will be, but the 665 and 720/20 are supported by other - drivers. - - Some newer logitech webcams are not handled by this driver but by the - Usb Video Class driver (linux-uvc). - - The built-in microphone is enabled by selecting USB Audio support. - - To compile this driver as a module, choose M here: the - module will be called pwc. - -config USB_PWC_DEBUG - bool "USB Philips Cameras verbose debug" - depends on USB_PWC - help - Say Y here in order to have the pwc driver generate verbose debugging - messages. - A special module options 'trace' is used to control the verbosity. - -config USB_PWC_INPUT_EVDEV - bool "USB Philips Cameras input events device support" - default y - depends on USB_PWC && (USB_PWC=INPUT || INPUT=y) - ---help--- - This option makes USB Philips cameras register the snapshot button as - an input device to report button events. - - If you are in doubt, say Y. diff --git a/src/linux/drivers/media/usb/s2255/Kconfig b/src/linux/drivers/media/usb/s2255/Kconfig deleted file mode 100644 index 8c3fcee..0000000 --- a/src/linux/drivers/media/usb/s2255/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config USB_S2255 - tristate "USB Sensoray 2255 video capture device" - depends on VIDEO_V4L2 - select VIDEOBUF2_VMALLOC - default n - help - Say Y here if you want support for the Sensoray 2255 USB device. - This driver can be compiled as a module, called s2255drv. - diff --git a/src/linux/drivers/media/usb/s2255/Makefile b/src/linux/drivers/media/usb/s2255/Makefile deleted file mode 100644 index 197d0bb..0000000 --- a/src/linux/drivers/media/usb/s2255/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-$(CONFIG_USB_S2255) += s2255drv.o - diff --git a/src/linux/drivers/media/usb/siano/Kconfig b/src/linux/drivers/media/usb/siano/Kconfig deleted file mode 100644 index d37b742..0000000 --- a/src/linux/drivers/media/usb/siano/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# -# Siano Mobile Silicon Digital TV device configuration -# - -config SMS_USB_DRV - tristate "Siano SMS1xxx based MDTV receiver" - depends on DVB_CORE && HAS_DMA - depends on !RC_CORE || RC_CORE - select MEDIA_COMMON_OPTIONS - select SMS_SIANO_MDTV - ---help--- - Choose if you would like to have Siano's support for USB interface - diff --git a/src/linux/drivers/media/usb/siano/Makefile b/src/linux/drivers/media/usb/siano/Makefile deleted file mode 100644 index 758b6a0..0000000 --- a/src/linux/drivers/media/usb/siano/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -obj-$(CONFIG_SMS_USB_DRV) += smsusb.o - -ccflags-y += -Idrivers/media/dvb-core -ccflags-y += -Idrivers/media/common/siano -ccflags-y += $(extra-cflags-y) $(extra-cflags-m) - diff --git a/src/linux/drivers/media/usb/stk1160/Kconfig b/src/linux/drivers/media/usb/stk1160/Kconfig deleted file mode 100644 index 95584c1..0000000 --- a/src/linux/drivers/media/usb/stk1160/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -config VIDEO_STK1160_COMMON - tristate "STK1160 USB video capture support" - depends on VIDEO_DEV && I2C - - ---help--- - This is a video4linux driver for STK1160 based video capture devices. - - To compile this driver as a module, choose M here: the - module will be called stk1160 - -config VIDEO_STK1160_AC97 - bool "STK1160 AC97 codec support" - depends on VIDEO_STK1160_COMMON && SND - - ---help--- - Enables AC97 codec support for stk1160 driver. - -config VIDEO_STK1160 - tristate - depends on (!VIDEO_STK1160_AC97 || (SND='n') || SND) && VIDEO_STK1160_COMMON - default y - select VIDEOBUF2_VMALLOC - select VIDEO_SAA711X - select SND_AC97_CODEC if SND diff --git a/src/linux/drivers/media/usb/stkwebcam/Kconfig b/src/linux/drivers/media/usb/stkwebcam/Kconfig deleted file mode 100644 index a6a00aa..0000000 --- a/src/linux/drivers/media/usb/stkwebcam/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config USB_STKWEBCAM - tristate "USB Syntek DC1125 Camera support" - depends on VIDEO_V4L2 - ---help--- - Say Y here if you want to use this type of camera. - Supported devices are typically found in some Asus laptops, - with USB id 174f:a311 and 05e1:0501. Other Syntek cameras - may be supported by the stk11xx driver, from which this is - derived, see - - To compile this driver as a module, choose M here: the - module will be called stkwebcam. - diff --git a/src/linux/drivers/media/usb/stkwebcam/Makefile b/src/linux/drivers/media/usb/stkwebcam/Makefile deleted file mode 100644 index 20ef8a4..0000000 --- a/src/linux/drivers/media/usb/stkwebcam/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -stkwebcam-objs := stk-webcam.o stk-sensor.o - -obj-$(CONFIG_USB_STKWEBCAM) += stkwebcam.o - diff --git a/src/linux/drivers/media/usb/tm6000/Kconfig b/src/linux/drivers/media/usb/tm6000/Kconfig deleted file mode 100644 index a43b77a..0000000 --- a/src/linux/drivers/media/usb/tm6000/Kconfig +++ /dev/null @@ -1,33 +0,0 @@ -config VIDEO_TM6000 - tristate "TV Master TM5600/6000/6010 driver" - depends on VIDEO_DEV && I2C && INPUT && RC_CORE && USB - select VIDEO_TUNER - select MEDIA_TUNER_XC2028 - select MEDIA_TUNER_XC5000 - select VIDEOBUF_VMALLOC - help - Support for TM5600/TM6000/TM6010 USB Device - - Since these cards have no MPEG decoder onboard, they transmit - only compressed MPEG data over the usb bus, so you need - an external software decoder to watch TV on your computer. - - Say Y if you own such a device and want to use it. - -config VIDEO_TM6000_ALSA - tristate "TV Master TM5600/6000/6010 audio support" - depends on VIDEO_TM6000 && SND - select SND_PCM - ---help--- - This is a video4linux driver for direct (DMA) audio for - TM5600/TM6000/TM6010 USB Devices. - - To compile this driver as a module, choose M here: the - module will be called tm6000-alsa. - -config VIDEO_TM6000_DVB - tristate "DVB Support for tm6000 based TV cards" - depends on VIDEO_TM6000 && DVB_CORE && USB - select DVB_ZL10353 - ---help--- - This adds support for DVB cards based on the tm5600/tm6000 chip. diff --git a/src/linux/drivers/media/usb/ttusb-budget/Kconfig b/src/linux/drivers/media/usb/ttusb-budget/Kconfig deleted file mode 100644 index 97bad7d..0000000 --- a/src/linux/drivers/media/usb/ttusb-budget/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config DVB_TTUSB_BUDGET - tristate "Technotrend/Hauppauge Nova-USB devices" - depends on DVB_CORE && USB && I2C && PCI - select DVB_CX22700 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA1004X if MEDIA_SUBDRV_AUTOSELECT - select DVB_VES1820 if MEDIA_SUBDRV_AUTOSELECT - select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT - select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT - select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT - help - Support for external USB adapters designed by Technotrend and - produced by Hauppauge, shipped under the brand name 'Nova-USB'. - - These devices don't have a MPEG decoder built in, so you need - an external software decoder to watch TV. - - Say Y if you own such a device and want to use it. diff --git a/src/linux/drivers/media/usb/ttusb-budget/Makefile b/src/linux/drivers/media/usb/ttusb-budget/Makefile deleted file mode 100644 index f47bbf6..0000000 --- a/src/linux/drivers/media/usb/ttusb-budget/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o - -ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb-frontends diff --git a/src/linux/drivers/media/usb/ttusb-dec/Kconfig b/src/linux/drivers/media/usb/ttusb-dec/Kconfig deleted file mode 100644 index 290254a..0000000 --- a/src/linux/drivers/media/usb/ttusb-dec/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -config DVB_TTUSB_DEC - tristate "Technotrend/Hauppauge USB DEC devices" - depends on DVB_CORE && USB && INPUT && PCI - select CRC32 - help - Support for external USB adapters designed by Technotrend and - produced by Hauppauge, shipped under the brand name 'DEC2000-t' - and 'DEC3000-s'. - - Even if these devices have a MPEG decoder built in, they transmit - only compressed MPEG data over the USB bus, so you need - an external software decoder to watch TV on your computer. - - This driver needs external firmware. Please use the commands - "/Documentation/dvb/get_dvb_firmware dec2000t", - "/Documentation/dvb/get_dvb_firmware dec2540t", - "/Documentation/dvb/get_dvb_firmware dec3000s", - download/extract them, and then copy them to /usr/lib/hotplug/firmware - or /lib/firmware (depending on configuration of firmware hotplug). - - Say Y if you own such a device and want to use it. diff --git a/src/linux/drivers/media/usb/ttusb-dec/Makefile b/src/linux/drivers/media/usb/ttusb-dec/Makefile deleted file mode 100644 index 5352740..0000000 --- a/src/linux/drivers/media/usb/ttusb-dec/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o - -ccflags-y += -Idrivers/media/dvb-core/ diff --git a/src/linux/drivers/media/usb/usbtv/Kconfig b/src/linux/drivers/media/usb/usbtv/Kconfig deleted file mode 100644 index b833c5b..0000000 --- a/src/linux/drivers/media/usb/usbtv/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config VIDEO_USBTV - tristate "USBTV007 video capture support" - depends on VIDEO_V4L2 && SND - select SND_PCM - select VIDEOBUF2_VMALLOC - - ---help--- - This is a video4linux2 driver for USBTV007 based video capture devices. - - To compile this driver as a module, choose M here: the - module will be called usbtv diff --git a/src/linux/drivers/media/usb/usbvision/Kconfig b/src/linux/drivers/media/usb/usbvision/Kconfig deleted file mode 100644 index 6b6afc5..0000000 --- a/src/linux/drivers/media/usb/usbvision/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config VIDEO_USBVISION - tristate "USB video devices based on Nogatech NT1003/1004/1005" - depends on I2C && VIDEO_V4L2 - select VIDEO_TUNER - select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT - ---help--- - There are more than 50 different USB video devices based on - NT1003/1004/1005 USB Bridges. This driver enables using those - devices. - - To compile this driver as a module, choose M here: the - module will be called usbvision. diff --git a/src/linux/drivers/media/usb/uvc/Kconfig b/src/linux/drivers/media/usb/uvc/Kconfig deleted file mode 100644 index 6ed85ef..0000000 --- a/src/linux/drivers/media/usb/uvc/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -config USB_VIDEO_CLASS - tristate "USB Video Class (UVC)" - depends on VIDEO_V4L2 - select VIDEOBUF2_VMALLOC - ---help--- - Support for the USB Video Class (UVC). Currently only video - input devices, such as webcams, are supported. - - For more information see: - -config USB_VIDEO_CLASS_INPUT_EVDEV - bool "UVC input events device support" - default y - depends on USB_VIDEO_CLASS - depends on USB_VIDEO_CLASS=INPUT || INPUT=y - ---help--- - This option makes USB Video Class devices register an input device - to report button events. - - If you are in doubt, say Y. diff --git a/src/linux/drivers/media/usb/zr364xx/Kconfig b/src/linux/drivers/media/usb/zr364xx/Kconfig deleted file mode 100644 index 0f58566..0000000 --- a/src/linux/drivers/media/usb/zr364xx/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config USB_ZR364XX - tristate "USB ZR364XX Camera support" - depends on VIDEO_V4L2 - select VIDEOBUF_GEN - select VIDEOBUF_VMALLOC - ---help--- - Say Y here if you want to connect this type of camera to your - computer's USB port. - See for more info - and list of supported cameras. - - To compile this driver as a module, choose M here: the - module will be called zr364xx. - diff --git a/src/linux/drivers/media/usb/zr364xx/Makefile b/src/linux/drivers/media/usb/zr364xx/Makefile deleted file mode 100644 index a577788..0000000 --- a/src/linux/drivers/media/usb/zr364xx/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-$(CONFIG_USB_ZR364XX) += zr364xx.o - diff --git a/src/linux/drivers/media/v4l2-core/Kconfig b/src/linux/drivers/media/v4l2-core/Kconfig deleted file mode 100644 index 367523a..0000000 --- a/src/linux/drivers/media/v4l2-core/Kconfig +++ /dev/null @@ -1,109 +0,0 @@ -# -# Generic video config states -# - -# Enable the V4L2 core and API -config VIDEO_V4L2 - tristate - depends on (I2C || I2C=n) && VIDEO_DEV - default (I2C || I2C=n) && VIDEO_DEV - -config VIDEO_ADV_DEBUG - bool "Enable advanced debug functionality on V4L2 drivers" - default n - ---help--- - Say Y here to enable advanced debugging functionality on some - V4L devices. - In doubt, say N. - -config VIDEO_FIXED_MINOR_RANGES - bool "Enable old-style fixed minor ranges on drivers/video devices" - default n - ---help--- - Say Y here to enable the old-style fixed-range minor assignments. - Only useful if you rely on the old behavior and use mknod instead of udev. - - When in doubt, say N. - -config VIDEO_PCI_SKELETON - tristate "Skeleton PCI V4L2 driver" - depends on PCI - depends on VIDEO_V4L2 && VIDEOBUF2_CORE - depends on VIDEOBUF2_MEMOPS && VIDEOBUF2_DMA_CONTIG - ---help--- - Enable build of the skeleton PCI driver, used as a reference - when developing new drivers. - -# Used by drivers that need tuner.ko -config VIDEO_TUNER - tristate - -# Used by drivers that need v4l2-mem2mem.ko -config V4L2_MEM2MEM_DEV - tristate - depends on VIDEOBUF2_CORE - -# Used by LED subsystem flash drivers -config V4L2_FLASH_LED_CLASS - tristate "V4L2 flash API for LED flash class devices" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API - depends on LEDS_CLASS_FLASH - ---help--- - Say Y here to enable V4L2 flash API support for LED flash - class drivers. - - When in doubt, say N. - -# Used by drivers that need Videobuf modules -config VIDEOBUF_GEN - tristate - -config VIDEOBUF_DMA_SG - tristate - depends on HAS_DMA - select VIDEOBUF_GEN - -config VIDEOBUF_VMALLOC - tristate - select VIDEOBUF_GEN - -config VIDEOBUF_DMA_CONTIG - tristate - depends on HAS_DMA - select VIDEOBUF_GEN - -config VIDEOBUF_DVB - tristate - select VIDEOBUF_GEN - -# Used by drivers that need Videobuf2 modules -config VIDEOBUF2_CORE - select DMA_SHARED_BUFFER - tristate - -config VIDEOBUF2_MEMOPS - tristate - select FRAME_VECTOR - -config VIDEOBUF2_DMA_CONTIG - tristate - depends on HAS_DMA - select VIDEOBUF2_CORE - select VIDEOBUF2_MEMOPS - select DMA_SHARED_BUFFER - -config VIDEOBUF2_VMALLOC - tristate - select VIDEOBUF2_CORE - select VIDEOBUF2_MEMOPS - select DMA_SHARED_BUFFER - -config VIDEOBUF2_DMA_SG - tristate - depends on HAS_DMA - select VIDEOBUF2_CORE - select VIDEOBUF2_MEMOPS - -config VIDEOBUF2_DVB - tristate - select VIDEOBUF2_CORE diff --git a/src/linux/drivers/memory/Kconfig b/src/linux/drivers/memory/Kconfig deleted file mode 100644 index 4b4c0c3..0000000 --- a/src/linux/drivers/memory/Kconfig +++ /dev/null @@ -1,140 +0,0 @@ -# -# Memory devices -# - -menuconfig MEMORY - bool "Memory Controller drivers" - -if MEMORY - -config ARM_PL172_MPMC - tristate "ARM PL172 MPMC driver" - depends on ARM_AMBA && OF - help - This selects the ARM PrimeCell PL172 MultiPort Memory Controller. - If you have an embedded system with an AMBA bus and a PL172 - controller, say Y or M here. - -config ATMEL_SDRAMC - bool "Atmel (Multi-port DDR-)SDRAM Controller" - default y - depends on ARCH_AT91 && OF - help - This driver is for Atmel SDRAM Controller or Atmel Multi-port - DDR-SDRAM Controller available on Atmel AT91SAM9 and SAMA5 SoCs. - Starting with the at91sam9g45, this controller supports SDR, DDR and - LP-DDR memories. - -config ATMEL_EBI - bool "Atmel EBI driver" - default y - depends on ARCH_AT91 && OF - select MFD_SYSCON - help - Driver for Atmel EBI controller. - Used to configure the EBI (external bus interface) when the device- - tree is used. This bus supports NANDs, external ethernet controller, - SRAMs, ATA devices, etc. - -config TI_AEMIF - tristate "Texas Instruments AEMIF driver" - depends on (ARCH_DAVINCI || ARCH_KEYSTONE) && OF - help - This driver is for the AEMIF module available in Texas Instruments - SoCs. AEMIF stands for Asynchronous External Memory Interface and - is intended to provide a glue-less interface to a variety of - asynchronuous memory devices like ASRAM, NOR and NAND memory. A total - of 256M bytes of any of these memories can be accessed at a given - time via four chip selects with 64M byte access per chip select. - -config TI_EMIF - tristate "Texas Instruments EMIF driver" - depends on ARCH_OMAP2PLUS - select DDR - help - This driver is for the EMIF module available in Texas Instruments - SoCs. EMIF is an SDRAM controller that, based on its revision, - supports one or more of DDR2, DDR3, and LPDDR2 SDRAM protocols. - This driver takes care of only LPDDR2 memories presently. The - functions of the driver includes re-configuring AC timing - parameters and other settings during frequency, voltage and - temperature changes - -config OMAP_GPMC - bool - select GPIOLIB - help - This driver is for the General Purpose Memory Controller (GPMC) - present on Texas Instruments SoCs (e.g. OMAP2+). GPMC allows - interfacing to a variety of asynchronous as well as synchronous - memory drives like NOR, NAND, OneNAND, SRAM. - -config OMAP_GPMC_DEBUG - bool "Enable GPMC debug output and skip reset of GPMC during init" - depends on OMAP_GPMC - help - Enables verbose debugging mostly to decode the bootloader provided - timings. To preserve the bootloader provided timings, the reset - of GPMC is skipped during init. Enable this during development to - configure devices connected to the GPMC bus. - - NOTE: In addition to matching the register setup with the bootloader - you also need to match the GPMC FCLK frequency used by the - bootloader or else the GPMC timings won't be identical with the - bootloader timings. - -config MVEBU_DEVBUS - bool "Marvell EBU Device Bus Controller" - default y - depends on PLAT_ORION && OF - help - This driver is for the Device Bus controller available in some - Marvell EBU SoCs such as Discovery (mv78xx0), Orion (88f5xxx) and - Armada 370 and Armada XP. This controller allows to handle flash - devices such as NOR, NAND, SRAM, and FPGA. - -config TEGRA20_MC - bool "Tegra20 Memory Controller(MC) driver" - default y - depends on ARCH_TEGRA_2x_SOC - help - This driver is for the Memory Controller(MC) module available - in Tegra20 SoCs, mainly for a address translation fault - analysis, especially for IOMMU/GART(Graphics Address - Relocation Table) module. - -config FSL_CORENET_CF - tristate "Freescale CoreNet Error Reporting" - depends on FSL_SOC_BOOKE - help - Say Y for reporting of errors from the Freescale CoreNet - Coherency Fabric. Errors reported include accesses to - physical addresses that mapped by no local access window - (LAW) or an invalid LAW, as well as bad cache state that - represents a coherency violation. - -config FSL_IFC - bool - depends on FSL_SOC || ARCH_LAYERSCAPE - -config JZ4780_NEMC - bool "Ingenic JZ4780 SoC NEMC driver" - default y - depends on MACH_JZ4780 - help - This driver is for the NAND/External Memory Controller (NEMC) in - the Ingenic JZ4780. This controller is used to handle external - memory devices such as NAND and SRAM. - -config MTK_SMI - bool - depends on ARCH_MEDIATEK || COMPILE_TEST - help - This driver is for the Memory Controller module in MediaTek SoCs, - mainly help enable/disable iommu and control the power domain and - clocks for each local arbiter. - -source "drivers/memory/samsung/Kconfig" -source "drivers/memory/tegra/Kconfig" - -endif diff --git a/src/linux/drivers/memory/samsung/Kconfig b/src/linux/drivers/memory/samsung/Kconfig deleted file mode 100644 index 9de1222..0000000 --- a/src/linux/drivers/memory/samsung/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config SAMSUNG_MC - bool "Samsung Exynos Memory Controller support" if COMPILE_TEST - help - Support for the Memory Controller (MC) devices found on - Samsung Exynos SoCs. - -if SAMSUNG_MC - -config EXYNOS_SROM - bool "Exynos SROM controller driver" if COMPILE_TEST - depends on (ARM && ARCH_EXYNOS) || (COMPILE_TEST && HAS_IOMEM) - -endif diff --git a/src/linux/drivers/memory/tegra/Kconfig b/src/linux/drivers/memory/tegra/Kconfig deleted file mode 100644 index 6d74e49..0000000 --- a/src/linux/drivers/memory/tegra/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -config TEGRA_MC - bool "NVIDIA Tegra Memory Controller support" - default y - depends on ARCH_TEGRA - help - This driver supports the Memory Controller (MC) hardware found on - NVIDIA Tegra SoCs. - -config TEGRA124_EMC - bool "NVIDIA Tegra124 External Memory Controller driver" - default y - depends on TEGRA_MC && ARCH_TEGRA_124_SOC - help - This driver is for the External Memory Controller (EMC) found on - Tegra124 chips. The EMC controls the external DRAM on the board. - This driver is required to change memory timings / clock rate for - external memory. diff --git a/src/linux/drivers/memstick/Kconfig b/src/linux/drivers/memstick/Kconfig deleted file mode 100644 index 1314605..0000000 --- a/src/linux/drivers/memstick/Kconfig +++ /dev/null @@ -1,26 +0,0 @@ -# -# MemoryStick subsystem configuration -# - -menuconfig MEMSTICK - tristate "Sony MemoryStick card support" - help - Sony MemoryStick is a proprietary storage/extension card protocol. - - If you want MemoryStick support, you should say Y here and also - to the specific driver for your MemoryStick interface. - -if MEMSTICK - -config MEMSTICK_DEBUG - bool "MemoryStick debugging" - help - This is an option for use by developers; most people should - say N here. This enables MemoryStick core and driver debugging. - - -source "drivers/memstick/core/Kconfig" - -source "drivers/memstick/host/Kconfig" - -endif # MEMSTICK diff --git a/src/linux/drivers/memstick/core/Kconfig b/src/linux/drivers/memstick/core/Kconfig deleted file mode 100644 index 1d38949..0000000 --- a/src/linux/drivers/memstick/core/Kconfig +++ /dev/null @@ -1,38 +0,0 @@ -# -# MemoryStick core configuration -# - -comment "MemoryStick drivers" - -config MEMSTICK_UNSAFE_RESUME - bool "Allow unsafe resume (DANGEROUS)" - help - If you say Y here, the MemoryStick layer will assume that all - cards stayed in their respective slots during the suspend. The - normal behaviour is to remove them at suspend and - redetecting them at resume. Breaking this assumption will - in most cases result in data corruption. - - This option is usually just for embedded systems which use - a MemoryStick card for rootfs. Most people should say N here. - -config MSPRO_BLOCK - tristate "MemoryStick Pro block device driver" - depends on BLOCK - help - Say Y here to enable the MemoryStick Pro block device driver - support. This provides a block device driver, which you can use - to mount the filesystem. Almost everyone wishing MemoryStick - support should say Y or M here. - -config MS_BLOCK - tristate "MemoryStick Standard device driver" - depends on BLOCK - help - Say Y here to enable the MemoryStick Standard device driver - support. This provides a block device driver, which you can use - to mount the filesystem. - This driver works with old (bulky) MemoryStick and MemoryStick Duo - but not PRO. Say Y if you have such card. - Driver is new and not yet well tested, thus it can damage your card - (even permanently) diff --git a/src/linux/drivers/memstick/host/Kconfig b/src/linux/drivers/memstick/host/Kconfig deleted file mode 100644 index 7310e32..0000000 --- a/src/linux/drivers/memstick/host/Kconfig +++ /dev/null @@ -1,64 +0,0 @@ -# -# MemoryStick host controller drivers -# - -comment "MemoryStick Host Controller Drivers" - -config MEMSTICK_TIFM_MS - tristate "TI Flash Media MemoryStick Interface support " - depends on PCI - select TIFM_CORE - help - Say Y here if you want to be able to access MemoryStick cards with - the Texas Instruments(R) Flash Media card reader, found in many - laptops. - This option 'selects' (turns on, enables) 'TIFM_CORE', but you - probably also need appropriate card reader host adapter, such as - 'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support - (TIFM_7XX1)'. - - To compile this driver as a module, choose M here: the - module will be called tifm_ms. - -config MEMSTICK_JMICRON_38X - tristate "JMicron JMB38X MemoryStick interface support" - depends on PCI - - help - Say Y here if you want to be able to access MemoryStick cards with - the JMicron(R) JMB38X MemoryStick card reader. - - To compile this driver as a module, choose M here: the - module will be called jmb38x_ms. - -config MEMSTICK_R592 - tristate "Ricoh R5C592 MemoryStick interface support" - depends on PCI - - help - Say Y here if you want to be able to access MemoryStick cards with - the Ricoh R5C592 MemoryStick card reader (which is part of 5 in one - multifunction reader) - - To compile this driver as a module, choose M here: the module will - be called r592. - -config MEMSTICK_REALTEK_PCI - tristate "Realtek PCI-E Memstick Card Interface Driver" - depends on MFD_RTSX_PCI - help - Say Y here to include driver code to support Memstick card interface - of Realtek PCI-E card reader - - To compile this driver as a module, choose M here: the module will - be called rtsx_pci_ms. - -config MEMSTICK_REALTEK_USB - tristate "Realtek USB Memstick Card Interface Driver" - depends on MFD_RTSX_USB - help - Say Y here to include driver code to support Memstick card interface - of Realtek RTS5129/39 series USB card reader - - To compile this driver as a module, choose M here: the module will - be called rts5139_ms. diff --git a/src/linux/drivers/message/fusion/Kconfig b/src/linux/drivers/message/fusion/Kconfig deleted file mode 100644 index 63ca984..0000000 --- a/src/linux/drivers/message/fusion/Kconfig +++ /dev/null @@ -1,123 +0,0 @@ - -menuconfig FUSION - bool "Fusion MPT device support" - depends on PCI - ---help--- - Say Y here to get to see options for Fusion Message - Passing Technology (MPT) drivers. - This option alone does not add any kernel code. - - If you say N, all options in this submenu will be skipped and disabled. - -if FUSION - -config FUSION_SPI - tristate "Fusion MPT ScsiHost drivers for SPI" - depends on PCI && SCSI - select SCSI_SPI_ATTRS - ---help--- - SCSI HOST support for a parallel SCSI host adapters. - - List of supported controllers: - - LSI53C1020 - LSI53C1020A - LSI53C1030 - LSI53C1035 - ATTO UL4D - -config FUSION_FC - tristate "Fusion MPT ScsiHost drivers for FC" - depends on PCI && SCSI - depends on SCSI_FC_ATTRS - ---help--- - SCSI HOST support for a Fiber Channel host adapters. - - List of supported controllers: - - LSIFC909 - LSIFC919 - LSIFC919X - LSIFC929 - LSIFC929X - LSIFC929XL - LSIFC949X - LSIFC949E - Brocade FC 410/420 - -config FUSION_SAS - tristate "Fusion MPT ScsiHost drivers for SAS" - depends on PCI && SCSI - select SCSI_SAS_ATTRS - ---help--- - SCSI HOST support for a SAS host adapters. - - List of supported controllers: - - LSISAS1064 - LSISAS1068 - LSISAS1064E - LSISAS1068E - LSISAS1078 - -config FUSION_MAX_SGE - int "Maximum number of scatter gather entries (16 - 128)" - default "128" - range 16 128 - help - This option allows you to specify the maximum number of scatter- - gather entries per I/O. The driver default is 128, which matches - SCSI_MAX_PHYS_SEGMENTS. However, it may decreased down to 16. - Decreasing this parameter will reduce memory requirements - on a per controller instance. - -config FUSION_CTL - tristate "Fusion MPT misc device (ioctl) driver" - depends on FUSION_SPI || FUSION_FC || FUSION_SAS - ---help--- - The Fusion MPT misc device driver provides specialized control - of MPT adapters via system ioctl calls. Use of ioctl calls to - the MPT driver requires that you create and use a misc device - node ala: - mknod /dev/mptctl c 10 240 - - One use of this ioctl interface is to perform an upgrade (reflash) - of the MPT adapter firmware. Refer to readme file(s) distributed - with the Fusion MPT linux driver for additional details. - - If enabled by saying M to this, a driver named: mptctl - will be compiled. - - If unsure whether you really want or need this, say N. - -config FUSION_LAN - tristate "Fusion MPT LAN driver" - depends on FUSION_FC && NET_FC - ---help--- - This module supports LAN IP traffic over Fibre Channel port(s) - on Fusion MPT compatible hardware (LSIFC9xx chips). - The physical interface used is defined in RFC 2625. - Please refer to that document for details. - - Installing this driver requires the knowledge to configure and - activate a new network interface, "fc0", using standard Linux tools. - - If enabled by saying M to this, a driver named: mptlan - will be compiled. - - If unsure whether you really want or need this, say N. - -config FUSION_LOGGING - bool "Fusion MPT logging facility" - ---help--- - This turns on a logging facility that can be used to debug a number - of Fusion MPT related problems. - - The debug level can be programmed on the fly via SysFS (hex values) - - echo [level] > /sys/class/scsi_host/host#/debug_level - - There are various debug levels that can be found in the source: - file:drivers/message/fusion/mptdebug.h - -endif # FUSION diff --git a/src/linux/drivers/mfd/Kconfig b/src/linux/drivers/mfd/Kconfig deleted file mode 100644 index c6df644..0000000 --- a/src/linux/drivers/mfd/Kconfig +++ /dev/null @@ -1,1647 +0,0 @@ -# -# Multifunction miscellaneous devices -# - -if HAS_IOMEM -menu "Multifunction device drivers" - -config MFD_CORE - tristate - select IRQ_DOMAIN - default n - -config MFD_CS5535 - tristate "AMD CS5535 and CS5536 southbridge core functions" - select MFD_CORE - depends on PCI && (X86_32 || (X86 && COMPILE_TEST)) - ---help--- - This is the core driver for CS5535/CS5536 MFD functions. This is - necessary for using the board's GPIO and MFGPT functionality. - -config MFD_ALTERA_A10SR - bool "Altera Arria10 DevKit System Resource chip" - depends on ARCH_SOCFPGA && SPI_MASTER=y && OF - select REGMAP_SPI - select MFD_CORE - help - Support for the Altera Arria10 DevKit MAX5 System Resource chip - using the SPI interface. This driver provides common support for - accessing the external gpio extender (LEDs & buttons) and - power supply alarms (hwmon). - -config MFD_ACT8945A - tristate "Active-semi ACT8945A" - select MFD_CORE - select REGMAP_I2C - depends on I2C && OF - help - Support for the ACT8945A PMIC from Active-semi. This device - features three step-down DC/DC converters and four low-dropout - linear regulators, along with a complete ActivePath battery - charger. - -config MFD_AS3711 - bool "AMS AS3711" - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - depends on I2C=y - help - Support for the AS3711 PMIC from AMS - -config MFD_AS3722 - tristate "ams AS3722 Power Management IC" - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - depends on I2C=y && OF - help - The ams AS3722 is a compact system PMU suitable for mobile phones, - tablets etc. It has 4 DC/DC step-down regulators, 3 DC/DC step-down - controllers, 11 LDOs, RTC, automatic battery, temperature and - over current monitoring, GPIOs, ADC and a watchdog. - -config PMIC_ADP5520 - bool "Analog Devices ADP5520/01 MFD PMIC Core Support" - depends on I2C=y - help - Say yes here to add support for Analog Devices AD5520 and ADP5501, - Multifunction Power Management IC. This includes - the I2C driver and the core APIs _only_, you have to select - individual components like LCD backlight, LEDs, GPIOs and Kepad - under the corresponding menus. - -config MFD_AAT2870_CORE - bool "AnalogicTech AAT2870" - select MFD_CORE - depends on I2C=y - depends on GPIOLIB || COMPILE_TEST - help - If you say yes here you get support for the AAT2870. - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the - functionality of the device. - -config MFD_ATMEL_FLEXCOM - tristate "Atmel Flexcom (Flexible Serial Communication Unit)" - select MFD_CORE - depends on OF - help - Select this to get support for Atmel Flexcom. This is a wrapper - which embeds a SPI controller, a I2C controller and a USART. Only - one function can be used at a time. The choice is done at boot time - by the probe function of this MFD driver according to a device tree - property. - -config MFD_ATMEL_HLCDC - tristate "Atmel HLCDC (High-end LCD Controller)" - select MFD_CORE - select REGMAP_MMIO - depends on OF - help - If you say yes here you get support for the HLCDC block. - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the - functionality of the device. - -config MFD_BCM590XX - tristate "Broadcom BCM590xx PMUs" - select MFD_CORE - select REGMAP_I2C - depends on I2C - help - Support for the BCM590xx PMUs from Broadcom - -config MFD_AC100 - tristate "X-Powers AC100" - select MFD_CORE - depends on SUNXI_RSB - help - If you say Y here you get support for the X-Powers AC100 audio codec - IC. - This driver include only the core APIs. You have to select individual - components like codecs or RTC under the corresponding menus. - -config MFD_AXP20X - tristate - select MFD_CORE - select REGMAP_IRQ - -config MFD_AXP20X_I2C - tristate "X-Powers AXP series PMICs with I2C" - select MFD_AXP20X - select REGMAP_I2C - depends on I2C - help - If you say Y here you get support for the X-Powers AXP series power - management ICs (PMICs) controlled with I2C. - This driver include only the core APIs. You have to select individual - components like regulators or the PEK (Power Enable Key) under the - corresponding menus. - -config MFD_AXP20X_RSB - tristate "X-Powers AXP series PMICs with RSB" - select MFD_AXP20X - depends on SUNXI_RSB - help - If you say Y here you get support for the X-Powers AXP series power - management ICs (PMICs) controlled with RSB. - This driver include only the core APIs. You have to select individual - components like regulators or the PEK (Power Enable Key) under the - corresponding menus. - -config MFD_CROS_EC - tristate "ChromeOS Embedded Controller" - select MFD_CORE - select CHROME_PLATFORMS - select CROS_EC_PROTO - depends on X86 || ARM || ARM64 || COMPILE_TEST - help - If you say Y here you get support for the ChromeOS Embedded - Controller (EC) providing keyboard, battery and power services. - You also need to enable the driver for the bus you are using. The - protocol for talking to the EC is defined by the bus driver. - -config MFD_CROS_EC_I2C - tristate "ChromeOS Embedded Controller (I2C)" - depends on MFD_CROS_EC && I2C - - help - If you say Y here, you get support for talking to the ChromeOS - EC through an I2C bus. This uses a simple byte-level protocol with - a checksum. Failing accesses will be retried three times to - improve reliability. - -config MFD_CROS_EC_SPI - tristate "ChromeOS Embedded Controller (SPI)" - depends on MFD_CROS_EC && SPI - - ---help--- - If you say Y here, you get support for talking to the ChromeOS EC - through a SPI bus, using a byte-level protocol. Since the EC's - response time cannot be guaranteed, we support ignoring - 'pre-amble' bytes before the response actually starts. - -config MFD_ASIC3 - bool "Compaq ASIC3" - depends on GPIOLIB && ARM - select MFD_CORE - ---help--- - This driver supports the ASIC3 multifunction chip found on many - PDAs (mainly iPAQ and HTC based ones) - -config PMIC_DA903X - bool "Dialog Semiconductor DA9030/DA9034 PMIC Support" - depends on I2C=y - help - Say yes here to add support for Dialog Semiconductor DA9030 (a.k.a - ARAVA) and DA9034 (a.k.a MICCO), these are Power Management IC - usually found on PXA processors-based platforms. This includes - the I2C driver and the core APIs _only_, you have to select - individual components like LCD backlight, voltage regulators, - LEDs and battery-charger under the corresponding menus. - -config PMIC_DA9052 - bool - select MFD_CORE - -config MFD_DA9052_SPI - bool "Dialog Semiconductor DA9052/53 PMIC variants with SPI" - select REGMAP_SPI - select REGMAP_IRQ - select PMIC_DA9052 - depends on SPI_MASTER=y - help - Support for the Dialog Semiconductor DA9052 PMIC - when controlled using SPI. This driver provides common support - for accessing the device, additional drivers must be enabled in - order to use the functionality of the device. - -config MFD_DA9052_I2C - bool "Dialog Semiconductor DA9052/53 PMIC variants with I2C" - select REGMAP_I2C - select REGMAP_IRQ - select PMIC_DA9052 - depends on I2C=y - help - Support for the Dialog Semiconductor DA9052 PMIC - when controlled using I2C. This driver provides common support - for accessing the device, additional drivers must be enabled in - order to use the functionality of the device. - -config MFD_DA9055 - bool "Dialog Semiconductor DA9055 PMIC Support" - select REGMAP_I2C - select REGMAP_IRQ - select MFD_CORE - depends on I2C=y - help - Say yes here for support of Dialog Semiconductor DA9055. This is - a Power Management IC. This driver provides common support for - accessing the device as well as the I2C interface to the chip itself. - Additional drivers must be enabled in order to use the functionality - of the device. - - This driver can be built as a module. If built as a module it will be - called "da9055" - -config MFD_DA9062 - tristate "Dialog Semiconductor DA9062 PMIC Support" - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - depends on I2C - help - Say yes here for support for the Dialog Semiconductor DA9062 PMIC. - This includes the I2C driver and core APIs. - Additional drivers must be enabled in order to use the functionality - of the device. - -config MFD_DA9063 - tristate "Dialog Semiconductor DA9063 PMIC Support" - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - depends on I2C - help - Say yes here for support for the Dialog Semiconductor DA9063 PMIC. - This includes the I2C driver and core APIs. - Additional drivers must be enabled in order to use the functionality - of the device. - -config MFD_DA9150 - tristate "Dialog Semiconductor DA9150 Charger Fuel-Gauge chip" - depends on I2C - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - help - This adds support for the DA9150 integrated charger and fuel-gauge - chip. This driver provides common support for accessing the device. - Additional drivers must be enabled in order to use the specific - features of the device. - -config MFD_DLN2 - tristate "Diolan DLN2 support" - select MFD_CORE - depends on USB - help - This adds support for Diolan USB-I2C/SPI/GPIO Master Adapter - DLN-2. Additional drivers such as I2C_DLN2, GPIO_DLN2, - etc. must be enabled in order to use the functionality of - the device. - -config MFD_EXYNOS_LPASS - tristate "Samsung Exynos SoC Low Power Audio Subsystem" - select MFD_CORE - select REGMAP_MMIO - help - Select this option to enable support for Samsung Exynos Low Power - Audio Subsystem. - -config MFD_MC13XXX - tristate - depends on (SPI_MASTER || I2C) - select MFD_CORE - select REGMAP_IRQ - help - Enable support for the Freescale MC13783 and MC13892 PMICs. - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the - functionality of the device. - -config MFD_MC13XXX_SPI - tristate "Freescale MC13783 and MC13892 SPI interface" - depends on SPI_MASTER - select REGMAP_SPI - select MFD_MC13XXX - help - Select this if your MC13xxx is connected via an SPI bus. - -config MFD_MC13XXX_I2C - tristate "Freescale MC13892 I2C interface" - depends on I2C - select REGMAP_I2C - select MFD_MC13XXX - help - Select this if your MC13xxx is connected via an I2C bus. - -config MFD_MX25_TSADC - tristate "Freescale i.MX25 integrated Touchscreen and ADC unit" - select REGMAP_MMIO - depends on (SOC_IMX25 && OF) || COMPILE_TEST - help - Enable support for the integrated Touchscreen and ADC unit of the - i.MX25 processors. They consist of a conversion queue for general - purpose ADC and a queue for Touchscreens. - -config MFD_HI6421_PMIC - tristate "HiSilicon Hi6421 PMU/Codec IC" - depends on OF - select MFD_CORE - select REGMAP_MMIO - help - Add support for HiSilicon Hi6421 PMIC. Hi6421 includes multi- - functions, such as regulators, RTC, codec, Coulomb counter, etc. - This driver includes core APIs _only_. You have to select - individul components like voltage regulators under corresponding - menus in order to enable them. - We communicate with the Hi6421 via memory-mapped I/O. - -config MFD_HI655X_PMIC - tristate "HiSilicon Hi655X series PMU/Codec IC" - depends on ARCH_HISI || COMPILE_TEST - depends on OF - select MFD_CORE - select REGMAP_MMIO - select REGMAP_IRQ - help - Select this option to enable Hisilicon hi655x series pmic driver. - -config HTC_PASIC3 - tristate "HTC PASIC3 LED/DS1WM chip support" - select MFD_CORE - help - This core driver provides register access for the LED/DS1WM - chips labeled "AIC2" and "AIC3", found on HTC Blueangel and - HTC Magician devices, respectively. Actual functionality is - handled by the leds-pasic3 and ds1wm drivers. - -config HTC_I2CPLD - bool "HTC I2C PLD chip support" - depends on I2C=y && GPIOLIB - help - If you say yes here you get support for the supposed CPLD - found on omap850 HTC devices like the HTC Wizard and HTC Herald. - This device provides input and output GPIOs through an I2C - interface to one or more sub-chips. - -config MFD_INTEL_QUARK_I2C_GPIO - tristate "Intel Quark MFD I2C GPIO" - depends on PCI - depends on X86 - depends on COMMON_CLK - select MFD_CORE - help - This MFD provides support for I2C and GPIO that exist only - in a single PCI device. It splits the 2 IO devices to - their respective IO driver. - The GPIO exports a total amount of 8 interrupt-capable GPIOs. - -config LPC_ICH - tristate "Intel ICH LPC" - depends on PCI - select MFD_CORE - help - The LPC bridge function of the Intel ICH provides support for - many functional units. This driver provides needed support for - other drivers to control these functions, currently GPIO and - watchdog. - -config LPC_SCH - tristate "Intel SCH LPC" - depends on PCI - select MFD_CORE - help - LPC bridge function of the Intel SCH provides support for - System Management Bus and General Purpose I/O. - -config INTEL_SOC_PMIC - bool "Support for Intel Atom SoC PMIC" - depends on GPIOLIB - depends on I2C=y - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - help - Select this option to enable support for the PMIC device - on some Intel SoC systems. The PMIC provides ADC, GPIO, - thermal, charger and related power management functions - on these systems. - -config MFD_INTEL_LPSS - tristate - select COMMON_CLK - select MFD_CORE - -config MFD_INTEL_LPSS_ACPI - tristate "Intel Low Power Subsystem support in ACPI mode" - select MFD_INTEL_LPSS - depends on X86 && ACPI - help - This driver supports Intel Low Power Subsystem (LPSS) devices such as - I2C, SPI and HS-UART starting from Intel Sunrisepoint (Intel Skylake - PCH) in ACPI mode. - -config MFD_INTEL_LPSS_PCI - tristate "Intel Low Power Subsystem support in PCI mode" - select MFD_INTEL_LPSS - depends on X86 && PCI - help - This driver supports Intel Low Power Subsystem (LPSS) devices such as - I2C, SPI and HS-UART starting from Intel Sunrisepoint (Intel Skylake - PCH) in PCI mode. - -config MFD_INTEL_MSIC - bool "Intel MSIC" - depends on INTEL_SCU_IPC - select MFD_CORE - help - Select this option to enable access to Intel MSIC (Avatele - Passage) chip. This chip embeds audio, battery, GPIO, etc. - devices used in Intel Medfield platforms. - -config MFD_IPAQ_MICRO - bool "Atmel Micro ASIC (iPAQ h3100/h3600/h3700) Support" - depends on SA1100_H3100 || SA1100_H3600 - select MFD_CORE - help - Select this to get support for the Microcontroller found in - the Compaq iPAQ handheld computers. This is an Atmel - AT90LS8535 microcontroller flashed with a special iPAQ - firmware using the custom protocol implemented in this driver. - -config MFD_JANZ_CMODIO - tristate "Janz CMOD-IO PCI MODULbus Carrier Board" - select MFD_CORE - depends on PCI - help - This is the core driver for the Janz CMOD-IO PCI MODULbus - carrier board. This device is a PCI to MODULbus bridge which may - host many different types of MODULbus daughterboards, including - CAN and GPIO controllers. - -config MFD_JZ4740_ADC - bool "Janz JZ4740 ADC core" - select MFD_CORE - select GENERIC_IRQ_CHIP - depends on MACH_JZ4740 - help - Say yes here if you want support for the ADC unit in the JZ4740 SoC. - This driver is necessary for jz4740-battery and jz4740-hwmon driver. - -config MFD_KEMPLD - tristate "Kontron module PLD device" - select MFD_CORE - help - This is the core driver for the PLD (Programmable Logic Device) found - on some Kontron ETX and COMexpress (ETXexpress) modules. The PLD - device may provide functions like watchdog, GPIO, UART and I2C bus. - - The following modules are supported: - * COMe-bBL6 - * COMe-bHL6 - * COMe-bIP# - * COMe-bPC2 (ETXexpress-PC) - * COMe-bSC# (ETXexpress-SC T#) - * COMe-cBL6 - * COMe-cBT6 - * COMe-cBW6 - * COMe-cCT6 - * COMe-cDC2 (microETXexpress-DC) - * COMe-cHL6 - * COMe-cPC2 (microETXexpress-PC) - * COMe-cSL6 - * COMe-mAL10 - * COMe-mBT10 - * COMe-mCT10 - * COMe-mTT10 (nanoETXexpress-TT) - * ETX-OH - - This driver can also be built as a module. If so, the module - will be called kempld-core. - -config MFD_88PM800 - tristate "Marvell 88PM800" - depends on I2C - select REGMAP_I2C - select REGMAP_IRQ - select MFD_CORE - help - This supports for Marvell 88PM800 Power Management IC. - This includes the I2C driver and the core APIs _only_, you have to - select individual components like voltage regulators, RTC and - battery-charger under the corresponding menus. - -config MFD_88PM805 - tristate "Marvell 88PM805" - depends on I2C - select REGMAP_I2C - select REGMAP_IRQ - select MFD_CORE - help - This supports for Marvell 88PM805 Power Management IC. This includes - the I2C driver and the core APIs _only_, you have to select individual - components like codec device, headset/Mic device under the - corresponding menus. - -config MFD_88PM860X - bool "Marvell 88PM8606/88PM8607" - depends on I2C=y - select REGMAP_I2C - select MFD_CORE - help - This supports for Marvell 88PM8606/88PM8607 Power Management IC. - This includes the I2C driver and the core APIs _only_, you have to - select individual components like voltage regulators, RTC and - battery-charger under the corresponding menus. - -config MFD_MAX14577 - tristate "Maxim Semiconductor MAX14577/77836 MUIC + Charger Support" - depends on I2C - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - select IRQ_DOMAIN - help - Say yes here to add support for Maxim Semiconductor MAX14577 and - MAX77836 Micro-USB ICs with battery charger. - This driver provides common support for accessing the device; - additional drivers must be enabled in order to use the functionality - of the device. - -config MFD_MAX77620 - bool "Maxim Semiconductor MAX77620 and MAX20024 PMIC Support" - depends on I2C=y - depends on OF - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - select IRQ_DOMAIN - help - Say yes here to add support for Maxim Semiconductor MAX77620 and - MAX20024 which are Power Management IC with General purpose pins, - RTC, regulators, clock generator, watchdog etc. This driver - provides common support for accessing the device; additional drivers - must be enabled in order to use the functionality of the device. - -config MFD_MAX77686 - tristate "Maxim Semiconductor MAX77686/802 PMIC Support" - depends on I2C - depends on OF - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - select IRQ_DOMAIN - help - Say yes here to add support for Maxim Semiconductor MAX77686 and - MAX77802 which are Power Management IC with an RTC on chip. - This driver provides common support for accessing the device; - additional drivers must be enabled in order to use the functionality - of the device. - -config MFD_MAX77693 - tristate "Maxim Semiconductor MAX77693 PMIC Support" - depends on I2C - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - help - Say yes here to add support for Maxim Semiconductor MAX77693. - This is a companion Power Management IC with Flash, Haptic, Charger, - and MUIC(Micro USB Interface Controller) controls on chip. - This driver provides common support for accessing the device; - additional drivers must be enabled in order to use the functionality - of the device. - -config MFD_MAX77843 - bool "Maxim Semiconductor MAX77843 PMIC Support" - depends on I2C=y - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - help - Say yes here to add support for Maxim Semiconductor MAX77843. - This is companion Power Management IC with LEDs, Haptic, Charger, - Fuel Gauge, MUIC(Micro USB Interface Controller) controls on chip. - This driver provides common support for accessing the device; - additional drivers must be enabled in order to use the functionality - of the device. - -config MFD_MAX8907 - tristate "Maxim Semiconductor MAX8907 PMIC Support" - select MFD_CORE - depends on I2C - select REGMAP_I2C - select REGMAP_IRQ - help - Say yes here to add support for Maxim Semiconductor MAX8907. This is - a Power Management IC. This driver provides common support for - accessing the device; additional drivers must be enabled in order - to use the functionality of the device. - -config MFD_MAX8925 - bool "Maxim Semiconductor MAX8925 PMIC Support" - depends on I2C=y - select MFD_CORE - help - Say yes here to add support for Maxim Semiconductor MAX8925. This is - a Power Management IC. This driver provides common support for - accessing the device, additional drivers must be enabled in order - to use the functionality of the device. - -config MFD_MAX8997 - bool "Maxim Semiconductor MAX8997/8966 PMIC Support" - depends on I2C=y - select MFD_CORE - select IRQ_DOMAIN - help - Say yes here to add support for Maxim Semiconductor MAX8997/8966. - This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic, - MUIC controls on chip. - This driver provides common support for accessing the device; - additional drivers must be enabled in order to use the functionality - of the device. - -config MFD_MAX8998 - bool "Maxim Semiconductor MAX8998/National LP3974 PMIC Support" - depends on I2C=y - select MFD_CORE - select IRQ_DOMAIN - help - Say yes here to add support for Maxim Semiconductor MAX8998 and - National Semiconductor LP3974. This is a Power Management IC. - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the functionality - of the device. - -config MFD_MT6397 - tristate "MediaTek MT6397 PMIC Support" - select MFD_CORE - select IRQ_DOMAIN - help - Say yes here to add support for MediaTek MT6397 PMIC. This is - a Power Management IC. This driver provides common support for - accessing the device; additional drivers must be enabled in order - to use the functionality of the device. - -config MFD_MENF21BMC - tristate "MEN 14F021P00 Board Management Controller Support" - depends on I2C - select MFD_CORE - help - Say yes here to add support for the MEN 14F021P00 BMC - which is a Board Management Controller connected to the I2C bus. - The device supports multiple sub-devices like LED, HWMON and WDT. - This driver provides common support for accessing the devices; - additional drivers must be enabled in order to use the - functionality of the BMC device. - - This driver can also be built as a module. If so the module - will be called menf21bmc. - -config EZX_PCAP - bool "Motorola EZXPCAP Support" - depends on SPI_MASTER - help - This enables the PCAP ASIC present on EZX Phones. This is - needed for MMC, TouchScreen, Sound, USB, etc.. - -config MFD_VIPERBOARD - tristate "Nano River Technologies Viperboard" - select MFD_CORE - depends on USB - default n - help - Say yes here if you want support for Nano River Technologies - Viperboard. - There are mfd cell drivers available for i2c master, adc and - both gpios found on the board. The spi part does not yet - have a driver. - You need to select the mfd cell drivers separately. - The drivers do not support all features the board exposes. - -config MFD_RETU - tristate "Nokia Retu and Tahvo multi-function device" - select MFD_CORE - depends on I2C - select REGMAP_IRQ - help - Retu and Tahvo are a multi-function devices found on Nokia - Internet Tablets (770, N800 and N810). - -config MFD_PCF50633 - tristate "NXP PCF50633" - depends on I2C - select REGMAP_I2C - help - Say yes here if you have NXP PCF50633 chip on your board. - This core driver provides register access and IRQ handling - facilities, and registers devices for the various functions - so that function-specific drivers can bind to them. - -config PCF50633_ADC - tristate "NXP PCF50633 ADC" - depends on MFD_PCF50633 - help - Say yes here if you want to include support for ADC in the - NXP PCF50633 chip. - -config PCF50633_GPIO - tristate "NXP PCF50633 GPIO" - depends on MFD_PCF50633 - help - Say yes here if you want to include support GPIO for pins on - the PCF50633 chip. - -config UCB1400_CORE - tristate "Philips UCB1400 Core driver" - depends on AC97_BUS - depends on GPIOLIB - help - This enables support for the Philips UCB1400 core functions. - The UCB1400 is an AC97 audio codec. - - To compile this driver as a module, choose M here: the - module will be called ucb1400_core. - -config MFD_PM8XXX - tristate - -config MFD_PM8921_CORE - tristate "Qualcomm PM8921 PMIC chip" - depends on (ARM || HEXAGON) - select IRQ_DOMAIN - select MFD_CORE - select MFD_PM8XXX - select REGMAP - help - If you say yes to this option, support will be included for the - built-in PM8921 PMIC chip. - - This is required if your board has a PM8921 and uses its features, - such as: MPPs, GPIOs, regulators, interrupts, and PWM. - - Say M here if you want to include support for PM8921 chip as a module. - This will build a module called "pm8921-core". - -config MFD_QCOM_RPM - tristate "Qualcomm Resource Power Manager (RPM)" - depends on ARCH_QCOM && OF - help - If you say yes to this option, support will be included for the - Resource Power Manager system found in the Qualcomm 8660, 8960 and - 8064 based devices. - - This is required to access many regulators, clocks and bus - frequencies controlled by the RPM on these devices. - - Say M here if you want to include support for the Qualcomm RPM as a - module. This will build a module called "qcom_rpm". - -config MFD_SPMI_PMIC - tristate "Qualcomm SPMI PMICs" - depends on ARCH_QCOM || COMPILE_TEST - depends on OF - depends on SPMI - select REGMAP_SPMI - help - This enables support for the Qualcomm SPMI PMICs. - These PMICs are currently used with the Snapdragon 800 series of - SoCs. Note, that this will only be useful paired with descriptions - of the independent functions as children nodes in the device tree. - - Say M here if you want to include support for the SPMI PMIC - series as a module. The module will be called "qcom-spmi-pmic". - -config MFD_RDC321X - tristate "RDC R-321x southbridge" - select MFD_CORE - depends on PCI - help - Say yes here if you want to have support for the RDC R-321x SoC - southbridge which provides access to GPIOs and Watchdog using the - southbridge PCI device configuration space. - -config MFD_RTSX_PCI - tristate "Realtek PCI-E card reader" - depends on PCI - select MFD_CORE - help - This supports for Realtek PCI-Express card reader including rts5209, - rts5227, rts522A, rts5229, rts5249, rts524A, rts525A, rtl8411, etc. - Realtek card reader supports access to many types of memory cards, - such as Memory Stick, Memory Stick Pro, Secure Digital and - MultiMediaCard. - -config MFD_RT5033 - tristate "Richtek RT5033 Power Management IC" - depends on I2C - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - help - This driver provides for the Richtek RT5033 Power Management IC, - which includes the I2C driver and the Core APIs. This driver provides - common support for accessing the device. The device supports multiple - sub-devices like charger, fuel gauge, flash LED, current source, - LDO and Buck. - -config MFD_RTSX_USB - tristate "Realtek USB card reader" - depends on USB - select MFD_CORE - help - Select this option to get support for Realtek USB 2.0 card readers - including RTS5129, RTS5139, RTS5179 and RTS5170. - Realtek card reader supports access to many types of memory cards, - such as Memory Stick Pro, Secure Digital and MultiMediaCard. - -config MFD_RC5T583 - bool "Ricoh RC5T583 Power Management system device" - depends on I2C=y - select MFD_CORE - select REGMAP_I2C - help - Select this option to get support for the RICOH583 Power - Management system device. - This driver provides common support for accessing the device - through i2c interface. The device supports multiple sub-devices - like GPIO, interrupts, RTC, LDO and DCDC regulators, onkey. - Additional drivers must be enabled in order to use the - different functionality of the device. - -config MFD_RK808 - tristate "Rockchip RK808/RK818 Power Management Chip" - depends on I2C && OF - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - help - If you say yes here you get support for the RK808 and RK818 - Power Management chips. - This driver provides common support for accessing the device - through I2C interface. The device supports multiple sub-devices - including interrupts, RTC, LDO & DCDC regulators, and onkey. - -config MFD_RN5T618 - tristate "Ricoh RN5T567/618 PMIC" - depends on I2C - depends on OF - select MFD_CORE - select REGMAP_I2C - help - Say yes here to add support for the Ricoh RN5T567 or R5T618 PMIC. - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the - functionality of the device. - -config MFD_SEC_CORE - bool "SAMSUNG Electronics PMIC Series Support" - depends on I2C=y - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - help - Support for the Samsung Electronics MFD series. - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the functionality - of the device - -config MFD_SI476X_CORE - tristate "Silicon Laboratories 4761/64/68 AM/FM radio." - depends on I2C - select MFD_CORE - select REGMAP_I2C - help - This is the core driver for the SI476x series of AM/FM - radio. This MFD driver connects the radio-si476x V4L2 module - and the si476x audio codec. - - To compile this driver as a module, choose M here: the - module will be called si476x-core. - -config MFD_SM501 - tristate "Silicon Motion SM501" - ---help--- - This is the core driver for the Silicon Motion SM501 multimedia - companion chip. This device is a multifunction device which may - provide numerous interfaces including USB host controller, USB gadget, - asynchronous serial ports, audio functions, and a dual display video - interface. The device may be connected by PCI or local bus with - varying functions enabled. - -config MFD_SM501_GPIO - bool "Export GPIO via GPIO layer" - depends on MFD_SM501 && GPIOLIB - ---help--- - This option uses the gpio library layer to export the 64 GPIO - lines on the SM501. The platform data is used to supply the - base number for the first GPIO line to register. - -config MFD_SKY81452 - tristate "Skyworks Solutions SKY81452" - select MFD_CORE - select REGMAP_I2C - depends on I2C - help - This is the core driver for the Skyworks SKY81452 backlight and - voltage regulator device. - - This driver can also be built as a module. If so, the module - will be called sky81452. - -config MFD_SMSC - bool "SMSC ECE1099 series chips" - depends on I2C=y - select MFD_CORE - select REGMAP_I2C - help - If you say yes here you get support for the - ece1099 chips from SMSC. - - To compile this driver as a module, choose M here: the - module will be called smsc. - -config ABX500_CORE - bool "ST-Ericsson ABX500 Mixed Signal Circuit register functions" - default y if ARCH_U300 || ARCH_U8500 - help - Say yes here if you have the ABX500 Mixed Signal IC family - chips. This core driver expose register access functions. - Functionality specific drivers using these functions can - remain unchanged when IC changes. Binding of the functions to - actual register access is done by the IC core driver. - -config AB3100_CORE - bool "ST-Ericsson AB3100 Mixed Signal Circuit core functions" - depends on I2C=y && ABX500_CORE - select MFD_CORE - default y if ARCH_U300 - help - Select this to enable the AB3100 Mixed Signal IC core - functionality. This connects to a AB3100 on the I2C bus - and expose a number of symbols needed for dependent devices - to read and write registers and subscribe to events from - this multi-functional IC. This is needed to use other features - of the AB3100 such as battery-backed RTC, charging control, - LEDs, vibrator, system power and temperature, power management - and ALSA sound. - -config AB3100_OTP - tristate "ST-Ericsson AB3100 OTP functions" - depends on AB3100_CORE - default y if AB3100_CORE - help - Select this to enable the AB3100 Mixed Signal IC OTP (one-time - programmable memory) support. This exposes a sysfs file to read - out OTP values. - -config AB8500_CORE - bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" - depends on ABX500_CORE && MFD_DB8500_PRCMU - select POWER_SUPPLY - select MFD_CORE - select IRQ_DOMAIN - help - Select this option to enable access to AB8500 power management - chip. This connects to U8500 either on the SSP/SPI bus (deprecated - since hardware version v1.0) or the I2C bus via PRCMU. It also adds - the irq_chip parts for handling the Mixed Signal chip events. - This chip embeds various other multimedia funtionalities as well. - -config AB8500_DEBUG - bool "Enable debug info via debugfs" - depends on AB8500_GPADC && DEBUG_FS - default y if DEBUG_FS - help - Select this option if you want debug information using the debug - filesystem, debugfs. - -config AB8500_GPADC - bool "ST-Ericsson AB8500 GPADC driver" - depends on AB8500_CORE && REGULATOR_AB8500 - default y - help - AB8500 GPADC driver used to convert Acc and battery/ac/usb voltage - -config MFD_DB8500_PRCMU - bool "ST-Ericsson DB8500 Power Reset Control Management Unit" - depends on UX500_SOC_DB8500 - select MFD_CORE - help - Select this option to enable support for the DB8500 Power Reset - and Control Management Unit. This is basically an autonomous - system controller running an XP70 microprocessor, which is accessed - through a register map. - -config MFD_STMPE - bool "STMicroelectronics STMPE" - depends on (I2C=y || SPI_MASTER=y) - depends on OF - select MFD_CORE - help - Support for the STMPE family of I/O Expanders from - STMicroelectronics. - - Currently supported devices are: - - STMPE811: GPIO, Touchscreen - STMPE1601: GPIO, Keypad - STMPE1801: GPIO, Keypad - STMPE2401: GPIO, Keypad - STMPE2403: GPIO, Keypad - - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the functionality - of the device. Currently available sub drivers are: - - GPIO: stmpe-gpio - Keypad: stmpe-keypad - Touchscreen: stmpe-ts - -menu "STMicroelectronics STMPE Interface Drivers" -depends on MFD_STMPE - -config STMPE_I2C - bool "STMicroelectronics STMPE I2C Interface" - depends on I2C=y - default y - help - This is used to enable I2C interface of STMPE - -config STMPE_SPI - bool "STMicroelectronics STMPE SPI Interface" - depends on SPI_MASTER - help - This is used to enable SPI interface of STMPE -endmenu - -config MFD_STA2X11 - bool "STMicroelectronics STA2X11" - depends on STA2X11 - select MFD_CORE - select REGMAP_MMIO - -config MFD_SUN6I_PRCM - bool "Allwinner A31 PRCM controller" - depends on ARCH_SUNXI - select MFD_CORE - help - Support for the PRCM (Power/Reset/Clock Management) unit available - in A31 SoC. - -config MFD_SYSCON - bool "System Controller Register R/W Based on Regmap" - select REGMAP_MMIO - help - Select this option to enable accessing system control registers - via regmap. - -config MFD_DAVINCI_VOICECODEC - tristate - select MFD_CORE - select REGMAP_MMIO - -config MFD_TI_AM335X_TSCADC - tristate "TI ADC / Touch Screen chip support" - select MFD_CORE - select REGMAP - select REGMAP_MMIO - help - If you say yes here you get support for Texas Instruments series - of Touch Screen /ADC chips. - To compile this driver as a module, choose M here: the - module will be called ti_am335x_tscadc. - -config MFD_DM355EVM_MSP - bool "TI DaVinci DM355 EVM microcontroller" - depends on I2C=y && MACH_DAVINCI_DM355_EVM - help - This driver supports the MSP430 microcontroller used on these - boards. MSP430 firmware manages resets and power sequencing, - inputs from buttons and the IR remote, LEDs, an RTC, and more. - -config MFD_LP3943 - tristate "TI/National Semiconductor LP3943 MFD Driver" - depends on I2C - select MFD_CORE - select REGMAP_I2C - help - Support for the TI/National Semiconductor LP3943. - This driver consists of GPIO and PWM drivers. - With these functionalities, it can be used for LED string control or - general usage such like a GPIO controller and a PWM controller. - -config MFD_LP8788 - bool "TI LP8788 Power Management Unit Driver" - depends on I2C=y - select MFD_CORE - select REGMAP_I2C - select IRQ_DOMAIN - help - TI LP8788 PMU supports regulators, battery charger, RTC, - ADC, backlight driver and current sinks. - -config MFD_OMAP_USB_HOST - bool "TI OMAP USBHS core and TLL driver" - depends on USB_EHCI_HCD_OMAP || USB_OHCI_HCD_OMAP3 - default y - help - This is the core driver for the OAMP EHCI and OHCI drivers. - This MFD driver does the required setup functionalities for - OMAP USB Host drivers. - -config MFD_PALMAS - bool "TI Palmas series chips" - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - depends on I2C=y - help - If you say yes here you get support for the Palmas - series of PMIC chips from Texas Instruments. - -config TPS6105X - tristate "TI TPS61050/61052 Boost Converters" - depends on I2C - select REGMAP_I2C - select REGULATOR - select MFD_CORE - select REGULATOR_FIXED_VOLTAGE - help - This option enables a driver for the TP61050/TPS61052 - high-power "white LED driver". This boost converter is - sometimes used for other things than white LEDs, and - also contains a GPIO pin. - -config TPS65010 - tristate "TI TPS6501x Power Management chips" - depends on I2C && GPIOLIB - default y if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_OSK - help - If you say yes here you get support for the TPS6501x series of - Power Management chips. These include voltage regulators, - lithium ion/polymer battery charging, and other features that - are often used in portable devices like cell phones and cameras. - - This driver can also be built as a module. If so, the module - will be called tps65010. - -config TPS6507X - tristate "TI TPS6507x Power Management / Touch Screen chips" - select MFD_CORE - depends on I2C - help - If you say yes here you get support for the TPS6507x series of - Power Management / Touch Screen chips. These include voltage - regulators, lithium ion/polymer battery charging, touch screen - and other features that are often used in portable devices. - This driver can also be built as a module. If so, the module - will be called tps6507x. - -config MFD_TPS65086 - tristate "TI TPS65086 Power Management Integrated Chips (PMICs)" - select REGMAP - select REGMAP_IRQ - select REGMAP_I2C - depends on I2C - help - If you say yes here you get support for the TPS65086 series of - Power Management chips. - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the - functionality of the device. - -config TPS65911_COMPARATOR - tristate - -config MFD_TPS65090 - bool "TI TPS65090 Power Management chips" - depends on I2C=y - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - help - If you say yes here you get support for the TPS65090 series of - Power Management chips. - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the - functionality of the device. - -config MFD_TPS65217 - tristate "TI TPS65217 Power Management / White LED chips" - depends on I2C - select MFD_CORE - select REGMAP_I2C - select IRQ_DOMAIN - help - If you say yes here you get support for the TPS65217 series of - Power Management / White LED chips. - These include voltage regulators, lithium ion/polymer battery - charger, wled and other features that are often used in portable - devices. - - This driver can also be built as a module. If so, the module - will be called tps65217. - -config MFD_TI_LP873X - tristate "TI LP873X Power Management IC" - depends on I2C - select MFD_CORE - select REGMAP_I2C - help - If you say yes here then you get support for the LP873X series of - Power Management Integrated Circuits (PMIC). - These include voltage regulators, thermal protection, configurable - General Purpose Outputs (GPO) that are used in portable devices. - - This driver can also be built as a module. If so, the module - will be called lp873x. - -config MFD_TPS65218 - tristate "TI TPS65218 Power Management chips" - depends on I2C - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - help - If you say yes here you get support for the TPS65218 series of - Power Management chips. - These include voltage regulators, gpio and other features - that are often used in portable devices. Only regulator - component is currently supported. - - This driver can also be built as a module. If so, the module - will be called tps65218. - -config MFD_TPS6586X - bool "TI TPS6586x Power Management chips" - depends on I2C=y - select MFD_CORE - select REGMAP_I2C - help - If you say yes here you get support for the TPS6586X series of - Power Management chips. - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the - functionality of the device. - - This driver can also be built as a module. If so, the module - will be called tps6586x. - -config MFD_TPS65910 - bool "TI TPS65910 Power Management chip" - depends on I2C=y - depends on GPIOLIB || COMPILE_TEST - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - select IRQ_DOMAIN - help - if you say yes here you get support for the TPS65910 series of - Power Management chips. - -config MFD_TPS65912 - tristate - select MFD_CORE - select REGMAP - select REGMAP_IRQ - -config MFD_TPS65912_I2C - tristate "TI TPS65912 Power Management chip with I2C" - select MFD_TPS65912 - select REGMAP_I2C - depends on I2C - help - If you say yes here you get support for the TPS65912 series of - PM chips with I2C interface. - -config MFD_TPS65912_SPI - tristate "TI TPS65912 Power Management chip with SPI" - select MFD_TPS65912 - select REGMAP_SPI - depends on SPI_MASTER - help - If you say yes here you get support for the TPS65912 series of - PM chips with SPI interface. - -config MFD_TPS80031 - bool "TI TPS80031/TPS80032 Power Management chips" - depends on I2C=y - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - help - If you say yes here you get support for the Texas Instruments - TPS80031/ TPS80032 Fully Integrated Power Management with Power - Path and Battery Charger. The device provides five configurable - step-down converters, 11 general purpose LDOs, USB OTG Module, - ADC, RTC, 2 PWM, System Voltage Regulator/Battery Charger with - Power Path from USB, 32K clock generator. - -config TWL4030_CORE - bool "TI TWL4030/TWL5030/TWL6030/TPS659x0 Support" - depends on I2C=y - select IRQ_DOMAIN - select REGMAP_I2C - help - Say yes here if you have TWL4030 / TWL6030 family chip on your board. - This core driver provides register access and IRQ handling - facilities, and registers devices for the various functions - so that function-specific drivers can bind to them. - - These multi-function chips are found on many OMAP2 and OMAP3 - boards, providing power management, RTC, GPIO, keypad, a - high speed USB OTG transceiver, an audio codec (on most - versions) and many other features. - -config TWL4030_POWER - bool "TI TWL4030 power resources" - depends on TWL4030_CORE && ARM - help - Say yes here if you want to use the power resources on the - TWL4030 family chips. Most of these resources are regulators, - which have a separate driver; some are control signals, such - as clock request handshaking. - - This driver uses board-specific data to initialize the resources - and load scripts controlling which resources are switched off/on - or reset when a sleep, wakeup or warm reset event occurs. - -config MFD_TWL4030_AUDIO - bool "TI TWL4030 Audio" - depends on TWL4030_CORE - select MFD_CORE - default n - -config TWL6040_CORE - bool "TI TWL6040 audio codec" - depends on I2C=y - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - default n - help - Say yes here if you want support for Texas Instruments TWL6040 audio - codec. - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the - functionality of the device (audio, vibra). - -config MENELAUS - bool "TI TWL92330/Menelaus PM chip" - depends on I2C=y && ARCH_OMAP2 - help - If you say yes here you get support for the Texas Instruments - TWL92330/Menelaus Power Management chip. This include voltage - regulators, Dual slot memory card transceivers, real-time clock - and other features that are often used in portable devices like - cell phones and PDAs. - -config MFD_WL1273_CORE - tristate "TI WL1273 FM radio" - depends on I2C - select MFD_CORE - default n - help - This is the core driver for the TI WL1273 FM radio. This MFD - driver connects the radio-wl1273 V4L2 module and the wl1273 - audio codec. - -config MFD_LM3533 - tristate "TI/National Semiconductor LM3533 Lighting Power chip" - depends on I2C - select MFD_CORE - select REGMAP_I2C - help - Say yes here to enable support for National Semiconductor / TI - LM3533 Lighting Power chips. - - This driver provides common support for accessing the device; - additional drivers must be enabled in order to use the LED, - backlight or ambient-light-sensor functionality of the device. - -config MFD_TIMBERDALE - tristate "Timberdale FPGA" - select MFD_CORE - depends on PCI && GPIOLIB && (X86_32 || COMPILE_TEST) - ---help--- - This is the core driver for the timberdale FPGA. This device is a - multifunction device which exposes numerous platform devices. - - The timberdale FPGA can be found on the Intel Atom development board - for in-vehicle infontainment, called Russellville. - -config MFD_TC3589X - bool "Toshiba TC35892 and variants" - depends on I2C=y - depends on OF - select MFD_CORE - help - Support for the Toshiba TC35892 and variants I/O Expander. - - This driver provides common support for accessing the device, - additional drivers must be enabled in order to use the - functionality of the device. - -config MFD_TMIO - bool - default n - -config MFD_T7L66XB - bool "Toshiba T7L66XB" - depends on ARM && HAVE_CLK - select MFD_CORE - select MFD_TMIO - help - Support for Toshiba Mobile IO Controller T7L66XB - -config MFD_TC6387XB - bool "Toshiba TC6387XB" - depends on ARM && HAVE_CLK - select MFD_CORE - select MFD_TMIO - help - Support for Toshiba Mobile IO Controller TC6387XB - -config MFD_TC6393XB - bool "Toshiba TC6393XB" - depends on ARM && HAVE_CLK - select GPIOLIB - select MFD_CORE - select MFD_TMIO - help - Support for Toshiba Mobile IO Controller TC6393XB - -config MFD_VX855 - tristate "VIA VX855/VX875 integrated south bridge" - depends on PCI - select MFD_CORE - help - Say yes here to enable support for various functions of the - VIA VX855/VX875 south bridge. You will need to enable the vx855_spi - and/or vx855_gpio drivers for this to do anything useful. - -config MFD_ARIZONA - select REGMAP - select REGMAP_IRQ - select MFD_CORE - bool - -config MFD_ARIZONA_I2C - tristate "Cirrus Logic/Wolfson Microelectronics Arizona platform with I2C" - select MFD_ARIZONA - select REGMAP_I2C - depends on I2C - help - Support for the Cirrus Logic/Wolfson Microelectronics Arizona platform - audio SoC core functionality controlled via I2C. - -config MFD_ARIZONA_SPI - tristate "Cirrus Logic/Wolfson Microelectronics Arizona platform with SPI" - select MFD_ARIZONA - select REGMAP_SPI - depends on SPI_MASTER - help - Support for the Cirrus Logic/Wolfson Microelectronics Arizona platform - audio SoC core functionality controlled via SPI. - -config MFD_CS47L24 - bool "Cirrus Logic CS47L24 and WM1831" - depends on MFD_ARIZONA - help - Support for Cirrus Logic CS47L24 and WM1831 low power audio SoC - -config MFD_WM5102 - bool "Wolfson Microelectronics WM5102" - depends on MFD_ARIZONA - help - Support for Wolfson Microelectronics WM5102 low power audio SoC - -config MFD_WM5110 - bool "Wolfson Microelectronics WM5110 and WM8280/WM8281" - depends on MFD_ARIZONA - help - Support for Wolfson Microelectronics WM5110 and WM8280/WM8281 - low power audio SoC - -config MFD_WM8997 - bool "Wolfson Microelectronics WM8997" - depends on MFD_ARIZONA - help - Support for Wolfson Microelectronics WM8997 low power audio SoC - -config MFD_WM8998 - bool "Wolfson Microelectronics WM8998" - depends on MFD_ARIZONA - help - Support for Wolfson Microelectronics WM8998 low power audio SoC - -config MFD_WM8400 - bool "Wolfson Microelectronics WM8400" - select MFD_CORE - depends on I2C=y - select REGMAP_I2C - help - Support for the Wolfson Microelecronics WM8400 PMIC and audio - CODEC. This driver provides common support for accessing - the device, additional drivers must be enabled in order to use - the functionality of the device. - -config MFD_WM831X - bool - -config MFD_WM831X_I2C - bool "Wolfson Microelectronics WM831x/2x PMICs with I2C" - select MFD_CORE - select MFD_WM831X - select REGMAP_I2C - select IRQ_DOMAIN - depends on I2C=y - help - Support for the Wolfson Microelecronics WM831x and WM832x PMICs - when controlled using I2C. This driver provides common support - for accessing the device, additional drivers must be enabled in - order to use the functionality of the device. - -config MFD_WM831X_SPI - bool "Wolfson Microelectronics WM831x/2x PMICs with SPI" - select MFD_CORE - select MFD_WM831X - select REGMAP_SPI - select IRQ_DOMAIN - depends on SPI_MASTER - help - Support for the Wolfson Microelecronics WM831x and WM832x PMICs - when controlled using SPI. This driver provides common support - for accessing the device, additional drivers must be enabled in - order to use the functionality of the device. - -config MFD_WM8350 - bool - -config MFD_WM8350_I2C - bool "Wolfson Microelectronics WM8350 with I2C" - select MFD_WM8350 - select REGMAP_I2C - depends on I2C=y - help - The WM8350 is an integrated audio and power management - subsystem with watchdog and RTC functionality for embedded - systems. This option enables core support for the WM8350 with - I2C as the control interface. Additional options must be - selected to enable support for the functionality of the chip. - -config MFD_WM8994 - tristate "Wolfson Microelectronics WM8994" - select MFD_CORE - select REGMAP_I2C - select REGMAP_IRQ - depends on I2C - help - The WM8994 is a highly integrated hi-fi CODEC designed for - smartphone applications. As well as audio functionality it - has on board GPIO and regulator functionality which is - supported via the relevant subsystems. This driver provides - core support for the WM8994, in order to use the actual - functionaltiy of the device other drivers must be enabled. - -config MFD_STW481X - tristate "Support for ST Microelectronics STw481x" - depends on I2C && (ARCH_NOMADIK || COMPILE_TEST) - select REGMAP_I2C - select MFD_CORE - help - Select this option to enable the STw481x chip driver used - in various ST Microelectronics and ST-Ericsson embedded - Nomadik series. - -menu "Multimedia Capabilities Port drivers" - depends on ARCH_SA1100 - -config MCP - tristate - -# Interface drivers -config MCP_SA11X0 - tristate "Support SA11x0 MCP interface" - depends on ARCH_SA1100 - select MCP - -# Chip drivers -config MCP_UCB1200 - tristate "Support for UCB1200 / UCB1300" - depends on MCP_SA11X0 - select MCP - -config MCP_UCB1200_TS - tristate "Touchscreen interface support" - depends on MCP_UCB1200 && INPUT - -endmenu - -config MFD_VEXPRESS_SYSREG - bool "Versatile Express System Registers" - depends on VEXPRESS_CONFIG && GPIOLIB && !ARCH_USES_GETTIMEOFFSET - default y - select CLKSRC_MMIO - select GPIO_GENERIC_PLATFORM - select MFD_CORE - select MFD_SYSCON - help - System Registers are the platform configuration block - on the ARM Ltd. Versatile Express board. - -endmenu -endif diff --git a/src/linux/drivers/mfd/Makefile b/src/linux/drivers/mfd/Makefile deleted file mode 100644 index 9834e66..0000000 --- a/src/linux/drivers/mfd/Makefile +++ /dev/null @@ -1,213 +0,0 @@ -# -# Makefile for multifunction miscellaneous devices -# - -88pm860x-objs := 88pm860x-core.o 88pm860x-i2c.o -obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o -obj-$(CONFIG_MFD_88PM800) += 88pm800.o 88pm80x.o -obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o -obj-$(CONFIG_MFD_ACT8945A) += act8945a.o -obj-$(CONFIG_MFD_SM501) += sm501.o -obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o -obj-$(CONFIG_MFD_BCM590XX) += bcm590xx.o -obj-$(CONFIG_MFD_CROS_EC) += cros_ec.o -obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o -obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o -obj-$(CONFIG_MFD_EXYNOS_LPASS) += exynos-lpass.o - -rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o -obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o -obj-$(CONFIG_MFD_RTSX_USB) += rtsx_usb.o - -obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o -obj-$(CONFIG_HTC_I2CPLD) += htc-i2cpld.o - -obj-$(CONFIG_MFD_TI_LP873X) += lp873x.o - -obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o -obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o -obj-$(CONFIG_MFD_TI_AM335X_TSCADC) += ti_am335x_tscadc.o - -obj-$(CONFIG_MFD_STA2X11) += sta2x11-mfd.o -obj-$(CONFIG_MFD_STMPE) += stmpe.o -obj-$(CONFIG_STMPE_I2C) += stmpe-i2c.o -obj-$(CONFIG_STMPE_SPI) += stmpe-spi.o -obj-$(CONFIG_MFD_SUN6I_PRCM) += sun6i-prcm.o -obj-$(CONFIG_MFD_TC3589X) += tc3589x.o -obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o -obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o -obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o - -obj-$(CONFIG_MFD_ARIZONA) += arizona-core.o -obj-$(CONFIG_MFD_ARIZONA) += arizona-irq.o -obj-$(CONFIG_MFD_ARIZONA_I2C) += arizona-i2c.o -obj-$(CONFIG_MFD_ARIZONA_SPI) += arizona-spi.o -ifeq ($(CONFIG_MFD_WM5102),y) -obj-$(CONFIG_MFD_ARIZONA) += wm5102-tables.o -endif -ifeq ($(CONFIG_MFD_WM5110),y) -obj-$(CONFIG_MFD_ARIZONA) += wm5110-tables.o -endif -ifeq ($(CONFIG_MFD_WM8997),y) -obj-$(CONFIG_MFD_ARIZONA) += wm8997-tables.o -endif -ifeq ($(CONFIG_MFD_WM8998),y) -obj-$(CONFIG_MFD_ARIZONA) += wm8998-tables.o -endif -ifeq ($(CONFIG_MFD_CS47L24),y) -obj-$(CONFIG_MFD_ARIZONA) += cs47l24-tables.o -endif -obj-$(CONFIG_MFD_WM8400) += wm8400-core.o -wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o -wm831x-objs += wm831x-auxadc.o -obj-$(CONFIG_MFD_WM831X) += wm831x.o -obj-$(CONFIG_MFD_WM831X_I2C) += wm831x-i2c.o -obj-$(CONFIG_MFD_WM831X_SPI) += wm831x-spi.o -wm8350-objs := wm8350-core.o wm8350-regmap.o wm8350-gpio.o -wm8350-objs += wm8350-irq.o -obj-$(CONFIG_MFD_WM8350) += wm8350.o -obj-$(CONFIG_MFD_WM8350_I2C) += wm8350-i2c.o -wm8994-objs := wm8994-core.o wm8994-irq.o wm8994-regmap.o -obj-$(CONFIG_MFD_WM8994) += wm8994.o - -obj-$(CONFIG_TPS6105X) += tps6105x.o -obj-$(CONFIG_TPS65010) += tps65010.o -obj-$(CONFIG_TPS6507X) += tps6507x.o -obj-$(CONFIG_MFD_TPS65086) += tps65086.o -obj-$(CONFIG_MFD_TPS65217) += tps65217.o -obj-$(CONFIG_MFD_TPS65218) += tps65218.o -obj-$(CONFIG_MFD_TPS65910) += tps65910.o -obj-$(CONFIG_MFD_TPS65912) += tps65912-core.o -obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o -obj-$(CONFIG_MFD_TPS65912_SPI) += tps65912-spi.o -obj-$(CONFIG_MFD_TPS80031) += tps80031.o -obj-$(CONFIG_MENELAUS) += menelaus.o - -obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o -obj-$(CONFIG_TWL4030_POWER) += twl4030-power.o -obj-$(CONFIG_MFD_TWL4030_AUDIO) += twl4030-audio.o -obj-$(CONFIG_TWL6040_CORE) += twl6040.o - -obj-$(CONFIG_MFD_MX25_TSADC) += fsl-imx25-tsadc.o - -obj-$(CONFIG_MFD_MC13XXX) += mc13xxx-core.o -obj-$(CONFIG_MFD_MC13XXX_SPI) += mc13xxx-spi.o -obj-$(CONFIG_MFD_MC13XXX_I2C) += mc13xxx-i2c.o - -obj-$(CONFIG_MFD_CORE) += mfd-core.o - -obj-$(CONFIG_EZX_PCAP) += ezx-pcap.o - -obj-$(CONFIG_MCP) += mcp-core.o -obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o -obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o -obj-$(CONFIG_MFD_SMSC) += smsc-ece1099.o -obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o - -ifeq ($(CONFIG_SA1100_ASSABET),y) -obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o -endif -obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o - -obj-$(CONFIG_PMIC_DA903X) += da903x.o - -obj-$(CONFIG_PMIC_DA9052) += da9052-irq.o -obj-$(CONFIG_PMIC_DA9052) += da9052-core.o -obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o -obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o - -obj-$(CONFIG_MFD_AC100) += ac100.o -obj-$(CONFIG_MFD_AXP20X) += axp20x.o -obj-$(CONFIG_MFD_AXP20X_I2C) += axp20x-i2c.o -obj-$(CONFIG_MFD_AXP20X_RSB) += axp20x-rsb.o - -obj-$(CONFIG_MFD_LP3943) += lp3943.o -obj-$(CONFIG_MFD_LP8788) += lp8788.o lp8788-irq.o - -da9055-objs := da9055-core.o da9055-i2c.o -obj-$(CONFIG_MFD_DA9055) += da9055.o -obj-$(CONFIG_MFD_DA9062) += da9062-core.o -da9063-objs := da9063-core.o da9063-irq.o da9063-i2c.o -obj-$(CONFIG_MFD_DA9063) += da9063.o -obj-$(CONFIG_MFD_DA9150) += da9150-core.o - -obj-$(CONFIG_MFD_MAX14577) += max14577.o -obj-$(CONFIG_MFD_MAX77620) += max77620.o -obj-$(CONFIG_MFD_MAX77686) += max77686.o -obj-$(CONFIG_MFD_MAX77693) += max77693.o -obj-$(CONFIG_MFD_MAX77843) += max77843.o -obj-$(CONFIG_MFD_MAX8907) += max8907.o -max8925-objs := max8925-core.o max8925-i2c.o -obj-$(CONFIG_MFD_MAX8925) += max8925.o -obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o -obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o - -pcf50633-objs := pcf50633-core.o pcf50633-irq.o -obj-$(CONFIG_MFD_PCF50633) += pcf50633.o -obj-$(CONFIG_PCF50633_ADC) += pcf50633-adc.o -obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o -obj-$(CONFIG_ABX500_CORE) += abx500-core.o -obj-$(CONFIG_AB3100_CORE) += ab3100-core.o -obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o -obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o -obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o -obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o -# ab8500-core need to come after db8500-prcmu (which provides the channel) -obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o -obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o -obj-$(CONFIG_PMIC_ADP5520) += adp5520.o -obj-$(CONFIG_MFD_KEMPLD) += kempld-core.o -obj-$(CONFIG_MFD_INTEL_QUARK_I2C_GPIO) += intel_quark_i2c_gpio.o -obj-$(CONFIG_LPC_SCH) += lpc_sch.o -obj-$(CONFIG_LPC_ICH) += lpc_ich.o -obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o -obj-$(CONFIG_MFD_JANZ_CMODIO) += janz-cmodio.o -obj-$(CONFIG_MFD_JZ4740_ADC) += jz4740-adc.o -obj-$(CONFIG_MFD_TPS6586X) += tps6586x.o -obj-$(CONFIG_MFD_VX855) += vx855.o -obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o - -si476x-core-y := si476x-cmd.o si476x-prop.o si476x-i2c.o -obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o - -obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o -obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o -obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o ssbi.o -obj-$(CONFIG_MFD_QCOM_RPM) += qcom_rpm.o -obj-$(CONFIG_MFD_SPMI_PMIC) += qcom-spmi-pmic.o -obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o -obj-$(CONFIG_MFD_TPS65090) += tps65090.o -obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o -obj-$(CONFIG_MFD_ATMEL_FLEXCOM) += atmel-flexcom.o -obj-$(CONFIG_MFD_ATMEL_HLCDC) += atmel-hlcdc.o -obj-$(CONFIG_MFD_INTEL_LPSS) += intel-lpss.o -obj-$(CONFIG_MFD_INTEL_LPSS_PCI) += intel-lpss-pci.o -obj-$(CONFIG_MFD_INTEL_LPSS_ACPI) += intel-lpss-acpi.o -obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o -obj-$(CONFIG_MFD_PALMAS) += palmas.o -obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o -obj-$(CONFIG_MFD_RC5T583) += rc5t583.o rc5t583-irq.o -obj-$(CONFIG_MFD_RK808) += rk808.o -obj-$(CONFIG_MFD_RN5T618) += rn5t618.o -obj-$(CONFIG_MFD_SEC_CORE) += sec-core.o sec-irq.o -obj-$(CONFIG_MFD_SYSCON) += syscon.o -obj-$(CONFIG_MFD_LM3533) += lm3533-core.o lm3533-ctrlbank.o -obj-$(CONFIG_MFD_VEXPRESS_SYSREG) += vexpress-sysreg.o -obj-$(CONFIG_MFD_RETU) += retu-mfd.o -obj-$(CONFIG_MFD_AS3711) += as3711.o -obj-$(CONFIG_MFD_AS3722) += as3722.o -obj-$(CONFIG_MFD_STW481X) += stw481x.o -obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o -obj-$(CONFIG_MFD_MENF21BMC) += menf21bmc.o -obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o -obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o -obj-$(CONFIG_MFD_DLN2) += dln2.o -obj-$(CONFIG_MFD_RT5033) += rt5033.o -obj-$(CONFIG_MFD_SKY81452) += sky81452.o - -intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o -intel-soc-pmic-$(CONFIG_INTEL_PMC_IPC) += intel_soc_pmic_bxtwc.o -obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o -obj-$(CONFIG_MFD_MT6397) += mt6397-core.o - -obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o diff --git a/src/linux/drivers/misc/Kconfig b/src/linux/drivers/misc/Kconfig deleted file mode 100644 index 64971ba..0000000 --- a/src/linux/drivers/misc/Kconfig +++ /dev/null @@ -1,781 +0,0 @@ -# -# Misc strange devices -# - -menu "Misc devices" - -config SENSORS_LIS3LV02D - tristate - depends on INPUT - select INPUT_POLLDEV - default n - -config AD525X_DPOT - tristate "Analog Devices Digital Potentiometers" - depends on (I2C || SPI) && SYSFS - help - If you say yes here, you get support for the Analog Devices - AD5258, AD5259, AD5251, AD5252, AD5253, AD5254, AD5255 - AD5160, AD5161, AD5162, AD5165, AD5200, AD5201, AD5203, - AD5204, AD5206, AD5207, AD5231, AD5232, AD5233, AD5235, - AD5260, AD5262, AD5263, AD5290, AD5291, AD5292, AD5293, - AD7376, AD8400, AD8402, AD8403, ADN2850, AD5241, AD5242, - AD5243, AD5245, AD5246, AD5247, AD5248, AD5280, AD5282, - ADN2860, AD5273, AD5171, AD5170, AD5172, AD5173, AD5270, - AD5271, AD5272, AD5274 - digital potentiometer chips. - - See Documentation/misc-devices/ad525x_dpot.txt for the - userspace interface. - - This driver can also be built as a module. If so, the module - will be called ad525x_dpot. - -config AD525X_DPOT_I2C - tristate "support I2C bus connection" - depends on AD525X_DPOT && I2C - help - Say Y here if you have a digital potentiometers hooked to an I2C bus. - - To compile this driver as a module, choose M here: the - module will be called ad525x_dpot-i2c. - -config AD525X_DPOT_SPI - tristate "support SPI bus connection" - depends on AD525X_DPOT && SPI_MASTER - help - Say Y here if you have a digital potentiometers hooked to an SPI bus. - - If unsure, say N (but it's safe to say "Y"). - - To compile this driver as a module, choose M here: the - module will be called ad525x_dpot-spi. - -config ATMEL_TCLIB - bool "Atmel AT32/AT91 Timer/Counter Library" - depends on (AVR32 || ARCH_AT91) - help - Select this if you want a library to allocate the Timer/Counter - blocks found on many Atmel processors. This facilitates using - these blocks by different drivers despite processor differences. - -config ATMEL_TCB_CLKSRC - bool "TC Block Clocksource" - depends on ATMEL_TCLIB - default y - help - Select this to get a high precision clocksource based on a - TC block with a 5+ MHz base clock rate. Two timer channels - are combined to make a single 32-bit timer. - - When GENERIC_CLOCKEVENTS is defined, the third timer channel - may be used as a clock event device supporting oneshot mode - (delays of up to two seconds) based on the 32 KiHz clock. - -config ATMEL_TCB_CLKSRC_BLOCK - int - depends on ATMEL_TCB_CLKSRC - prompt "TC Block" if CPU_AT32AP700X - default 0 - range 0 1 - help - Some chips provide more than one TC block, so you have the - choice of which one to use for the clock framework. The other - TC can be used for other purposes, such as PWM generation and - interval timing. - -config DUMMY_IRQ - tristate "Dummy IRQ handler" - default n - ---help--- - This module accepts a single 'irq' parameter, which it should register for. - The sole purpose of this module is to help with debugging of systems on - which spurious IRQs would happen on disabled IRQ vector. - -config IBM_ASM - tristate "Device driver for IBM RSA service processor" - depends on X86 && PCI && INPUT - depends on SERIAL_8250 || SERIAL_8250=n - ---help--- - This option enables device driver support for in-band access to the - IBM RSA (Condor) service processor in eServer xSeries systems. - The ibmasm device driver allows user space application to access - ASM (Advanced Systems Management) functions on the service - processor. The driver is meant to be used in conjunction with - a user space API. - The ibmasm driver also enables the OS to use the UART on the - service processor board as a regular serial port. To make use of - this feature serial driver support (CONFIG_SERIAL_8250) must be - enabled. - - WARNING: This software may not be supported or function - correctly on your IBM server. Please consult the IBM ServerProven - website - for information on the specific driver level and support statement - for your IBM server. - -config PHANTOM - tristate "Sensable PHANToM (PCI)" - depends on PCI - help - Say Y here if you want to build a driver for Sensable PHANToM device. - - This driver is only for PCI PHANToMs. - - If you choose to build module, its name will be phantom. If unsure, - say N here. - -config INTEL_MID_PTI - tristate "Parallel Trace Interface for MIPI P1149.7 cJTAG standard" - depends on PCI && TTY && (X86_INTEL_MID || COMPILE_TEST) - default n - help - The PTI (Parallel Trace Interface) driver directs - trace data routed from various parts in the system out - through an Intel Penwell PTI port and out of the mobile - device for analysis with a debugging tool (Lauterbach or Fido). - - You should select this driver if the target kernel is meant for - an Intel Atom (non-netbook) mobile device containing a MIPI - P1149.7 standard implementation. - -config SGI_IOC4 - tristate "SGI IOC4 Base IO support" - depends on PCI - ---help--- - This option enables basic support for the IOC4 chip on certain - SGI IO controller cards (IO9, IO10, and PCI-RT). This option - does not enable any specific functions on such a card, but provides - necessary infrastructure for other drivers to utilize. - - If you have an SGI Altix with an IOC4-based card say Y. - Otherwise say N. - -config TIFM_CORE - tristate "TI Flash Media interface support" - depends on PCI - help - If you want support for Texas Instruments(R) Flash Media adapters - you should select this option and then also choose an appropriate - host adapter, such as 'TI Flash Media PCI74xx/PCI76xx host adapter - support', if you have a TI PCI74xx compatible card reader, for - example. - You will also have to select some flash card format drivers. MMC/SD - cards are supported via 'MMC/SD Card support: TI Flash Media MMC/SD - Interface support (MMC_TIFM_SD)'. - - To compile this driver as a module, choose M here: the module will - be called tifm_core. - -config TIFM_7XX1 - tristate "TI Flash Media PCI74xx/PCI76xx host adapter support" - depends on PCI && TIFM_CORE - default TIFM_CORE - help - This option enables support for Texas Instruments(R) PCI74xx and - PCI76xx families of Flash Media adapters, found in many laptops. - To make actual use of the device, you will have to select some - flash card format drivers, as outlined in the TIFM_CORE Help. - - To compile this driver as a module, choose M here: the module will - be called tifm_7xx1. - -config ICS932S401 - tristate "Integrated Circuits ICS932S401" - depends on I2C - help - If you say yes here you get support for the Integrated Circuits - ICS932S401 clock control chips. - - This driver can also be built as a module. If so, the module - will be called ics932s401. - -config ATMEL_SSC - tristate "Device driver for Atmel SSC peripheral" - depends on HAS_IOMEM && (AVR32 || ARCH_AT91 || COMPILE_TEST) - ---help--- - This option enables device driver support for Atmel Synchronized - Serial Communication peripheral (SSC). - - The SSC peripheral supports a wide variety of serial frame based - communications, i.e. I2S, SPI, etc. - - If unsure, say N. - -config ENCLOSURE_SERVICES - tristate "Enclosure Services" - default n - help - Provides support for intelligent enclosures (bays which - contain storage devices). You also need either a host - driver (SCSI/ATA) which supports enclosures - or a SCSI enclosure device (SES) to use these services. - -config SGI_XP - tristate "Support communication between SGI SSIs" - depends on NET - depends on (IA64_GENERIC || IA64_SGI_SN2 || IA64_SGI_UV || X86_UV) && SMP - select IA64_UNCACHED_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 - select GENERIC_ALLOCATOR if IA64_GENERIC || IA64_SGI_SN2 - select SGI_GRU if X86_64 && SMP - ---help--- - An SGI machine can be divided into multiple Single System - Images which act independently of each other and have - hardware based memory protection from the others. Enabling - this feature will allow for direct communication between SSIs - based on a network adapter and DMA messaging. - -config CS5535_MFGPT - tristate "CS5535/CS5536 Geode Multi-Function General Purpose Timer (MFGPT) support" - depends on MFD_CS5535 - default n - help - This driver provides access to MFGPT functionality for other - drivers that need timers. MFGPTs are available in the CS5535 and - CS5536 companion chips that are found in AMD Geode and several - other platforms. They have a better resolution and max interval - than the generic PIT, and are suitable for use as high-res timers. - You probably don't want to enable this manually; other drivers that - make use of it should enable it. - -config CS5535_MFGPT_DEFAULT_IRQ - int - depends on CS5535_MFGPT - default 7 - help - MFGPTs on the CS5535 require an interrupt. The selected IRQ - can be overridden as a module option as well as by driver that - use the cs5535_mfgpt_ API; however, different architectures might - want to use a different IRQ by default. This is here for - architectures to set as necessary. - -config CS5535_CLOCK_EVENT_SRC - tristate "CS5535/CS5536 high-res timer (MFGPT) events" - depends on GENERIC_CLOCKEVENTS && CS5535_MFGPT - help - This driver provides a clock event source based on the MFGPT - timer(s) in the CS5535 and CS5536 companion chips. - MFGPTs have a better resolution and max interval than the - generic PIT, and are suitable for use as high-res timers. - -config HP_ILO - tristate "Channel interface driver for the HP iLO processor" - depends on PCI - default n - help - The channel interface driver allows applications to communicate - with iLO management processors present on HP ProLiant servers. - Upon loading, the driver creates /dev/hpilo/dXccbN files, which - can be used to gather data from the management processor, via - read and write system calls. - - To compile this driver as a module, choose M here: the - module will be called hpilo. - -config QCOM_COINCELL - tristate "Qualcomm coincell charger support" - depends on MFD_SPMI_PMIC || COMPILE_TEST - help - This driver supports the coincell block found inside of - Qualcomm PMICs. The coincell charger provides a means to - charge a coincell battery or backup capacitor which is used - to maintain PMIC register and RTC state in the absence of - external power. - -config SGI_GRU - tristate "SGI GRU driver" - depends on X86_UV && SMP - default n - select MMU_NOTIFIER - ---help--- - The GRU is a hardware resource located in the system chipset. The GRU - contains memory that can be mmapped into the user address space. This memory is - used to communicate with the GRU to perform functions such as load/store, - scatter/gather, bcopy, AMOs, etc. The GRU is directly accessed by user - instructions using user virtual addresses. GRU instructions (ex., bcopy) use - user virtual addresses for operands. - - If you are not running on a SGI UV system, say N. - -config SGI_GRU_DEBUG - bool "SGI GRU driver debug" - depends on SGI_GRU - default n - ---help--- - This option enables additional debugging code for the SGI GRU driver. - If you are unsure, say N. - -config APDS9802ALS - tristate "Medfield Avago APDS9802 ALS Sensor module" - depends on I2C - help - If you say yes here you get support for the ALS APDS9802 ambient - light sensor. - - This driver can also be built as a module. If so, the module - will be called apds9802als. - -config ISL29003 - tristate "Intersil ISL29003 ambient light sensor" - depends on I2C && SYSFS - help - If you say yes here you get support for the Intersil ISL29003 - ambient light sensor. - - This driver can also be built as a module. If so, the module - will be called isl29003. - -config ISL29020 - tristate "Intersil ISL29020 ambient light sensor" - depends on I2C - help - If you say yes here you get support for the Intersil ISL29020 - ambient light sensor. - - This driver can also be built as a module. If so, the module - will be called isl29020. - -config SENSORS_TSL2550 - tristate "Taos TSL2550 ambient light sensor" - depends on I2C && SYSFS - help - If you say yes here you get support for the Taos TSL2550 - ambient light sensor. - - This driver can also be built as a module. If so, the module - will be called tsl2550. - -config SENSORS_BH1770 - tristate "BH1770GLC / SFH7770 combined ALS - Proximity sensor" - depends on I2C - ---help--- - Say Y here if you want to build a driver for BH1770GLC (ROHM) or - SFH7770 (Osram) combined ambient light and proximity sensor chip. - - To compile this driver as a module, choose M here: the - module will be called bh1770glc. If unsure, say N here. - -config SENSORS_APDS990X - tristate "APDS990X combined als and proximity sensors" - depends on I2C - default n - ---help--- - Say Y here if you want to build a driver for Avago APDS990x - combined ambient light and proximity sensor chip. - - To compile this driver as a module, choose M here: the - module will be called apds990x. If unsure, say N here. - -config HMC6352 - tristate "Honeywell HMC6352 compass" - depends on I2C - help - This driver provides support for the Honeywell HMC6352 compass, - providing configuration and heading data via sysfs. - -config DS1682 - tristate "Dallas DS1682 Total Elapsed Time Recorder with Alarm" - depends on I2C - help - If you say yes here you get support for Dallas Semiconductor - DS1682 Total Elapsed Time Recorder. - - This driver can also be built as a module. If so, the module - will be called ds1682. - -config SPEAR13XX_PCIE_GADGET - bool "PCIe gadget support for SPEAr13XX platform" - depends on ARCH_SPEAR13XX && BROKEN - default n - help - This option enables gadget support for PCIe controller. If - board file defines any controller as PCIe endpoint then a sysfs - entry will be created for that controller. User can use these - sysfs node to configure PCIe EP as per his requirements. - -config TI_DAC7512 - tristate "Texas Instruments DAC7512" - depends on SPI && SYSFS - help - If you say yes here you get support for the Texas Instruments - DAC7512 16-bit digital-to-analog converter. - - This driver can also be built as a module. If so, the module - will be called ti_dac7512. - -config VMWARE_BALLOON - tristate "VMware Balloon Driver" - depends on VMWARE_VMCI && X86 && HYPERVISOR_GUEST - help - This is VMware physical memory management driver which acts - like a "balloon" that can be inflated to reclaim physical pages - by reserving them in the guest and invalidating them in the - monitor, freeing up the underlying machine pages so they can - be allocated to other guests. The balloon can also be deflated - to allow the guest to use more physical memory. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called vmw_balloon. - -config ARM_CHARLCD - bool "ARM Ltd. Character LCD Driver" - depends on PLAT_VERSATILE - help - This is a driver for the character LCD found on the ARM Ltd. - Versatile and RealView Platform Baseboards. It doesn't do - very much more than display the text "ARM Linux" on the first - line and the Linux version on the second line, but that's - still useful. - -config PCH_PHUB - tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) PHUB" - select GENERIC_NET_UTILS - depends on PCI && (X86_32 || MIPS || COMPILE_TEST) - help - This driver is for PCH(Platform controller Hub) PHUB(Packet Hub) of - Intel Topcliff which is an IOH(Input/Output Hub) for x86 embedded - processor. The Topcliff has MAC address and Option ROM data in SROM. - This driver can access MAC address and Option ROM data in SROM. - - This driver also can be used for LAPIS Semiconductor's IOH, - ML7213/ML7223/ML7831. - ML7213 which is for IVI(In-Vehicle Infotainment) use. - ML7223 IOH is for MP(Media Phone) use. - ML7831 IOH is for general purpose use. - ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series. - ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH. - - To compile this driver as a module, choose M here: the module will - be called pch_phub. - -config USB_SWITCH_FSA9480 - tristate "FSA9480 USB Switch" - depends on I2C - help - The FSA9480 is a USB port accessory detector and switch. - The FSA9480 is fully controlled using I2C and enables USB data, - stereo and mono audio, video, microphone and UART data to use - a common connector port. - -config LATTICE_ECP3_CONFIG - tristate "Lattice ECP3 FPGA bitstream configuration via SPI" - depends on SPI && SYSFS - select FW_LOADER - default n - help - This option enables support for bitstream configuration (programming - or loading) of the Lattice ECP3 FPGA family via SPI. - - If unsure, say N. - -config SRAM - bool "Generic on-chip SRAM driver" - depends on HAS_IOMEM - select GENERIC_ALLOCATOR - help - This driver allows you to declare a memory region to be managed by - the genalloc API. It is supposed to be used for small on-chip SRAM - areas found on many SoCs. - -config VEXPRESS_SYSCFG - bool "Versatile Express System Configuration driver" - depends on VEXPRESS_CONFIG - default y - help - ARM Ltd. Versatile Express uses specialised platform configuration - bus. System Configuration interface is one of the possible means - of generating transactions on this bus. -config PANEL - tristate "Parallel port LCD/Keypad Panel support" - depends on PARPORT - ---help--- - Say Y here if you have an HD44780 or KS-0074 LCD connected to your - parallel port. This driver also features 4 and 6-key keypads. The LCD - is accessible through the /dev/lcd char device (10, 156), and the - keypad through /dev/keypad (10, 185). Both require misc device to be - enabled. This code can either be compiled as a module, or linked into - the kernel and started at boot. If you don't understand what all this - is about, say N. - -config PANEL_PARPORT - int "Default parallel port number (0=LPT1)" - depends on PANEL - range 0 255 - default "0" - ---help--- - This is the index of the parallel port the panel is connected to. One - driver instance only supports one parallel port, so if your keypad - and LCD are connected to two separate ports, you have to start two - modules with different arguments. Numbering starts with '0' for LPT1, - and so on. - -config PANEL_PROFILE - int "Default panel profile (0-5, 0=custom)" - depends on PANEL - range 0 5 - default "5" - ---help--- - To ease configuration, the driver supports different configuration - profiles for past and recent wirings. These profiles can also be - used to define an approximative configuration, completed by a few - other options. Here are the profiles : - - 0 = custom (see further) - 1 = 2x16 parallel LCD, old keypad - 2 = 2x16 serial LCD (KS-0074), new keypad - 3 = 2x16 parallel LCD (Hantronix), no keypad - 4 = 2x16 parallel LCD (Nexcom NSA1045) with Nexcom's keypad - 5 = 2x40 parallel LCD (old one), with old keypad - - Custom configurations allow you to define how your display is - wired to the parallel port, and how it works. This is only intended - for experts. - -config PANEL_KEYPAD - depends on PANEL && PANEL_PROFILE="0" - int "Keypad type (0=none, 1=old 6 keys, 2=new 6 keys, 3=Nexcom 4 keys)" - range 0 3 - default 0 - ---help--- - This enables and configures a keypad connected to the parallel port. - The keys will be read from character device 10,185. Valid values are : - - 0 : do not enable this driver - 1 : old 6 keys keypad - 2 : new 6 keys keypad, as used on the server at www.ant-computing.com - 3 : Nexcom NSA1045's 4 keys keypad - - New profiles can be described in the driver source. The driver also - supports simultaneous keys pressed when the keypad supports them. - -config PANEL_LCD - depends on PANEL && PANEL_PROFILE="0" - int "LCD type (0=none, 1=custom, 2=old //, 3=ks0074, 4=hantronix, 5=Nexcom)" - range 0 5 - default 0 - ---help--- - This enables and configures an LCD connected to the parallel port. - The driver includes an interpreter for escape codes starting with - '\e[L' which are specific to the LCD, and a few ANSI codes. The - driver will be registered as character device 10,156, usually - under the name '/dev/lcd'. There are a total of 6 supported types : - - 0 : do not enable the driver - 1 : custom configuration and wiring (see further) - 2 : 2x16 & 2x40 parallel LCD (old wiring) - 3 : 2x16 serial LCD (KS-0074 based) - 4 : 2x16 parallel LCD (Hantronix wiring) - 5 : 2x16 parallel LCD (Nexcom wiring) - - When type '1' is specified, other options will appear to configure - more precise aspects (wiring, dimensions, protocol, ...). Please note - that those values changed from the 2.4 driver for better consistency. - -config PANEL_LCD_HEIGHT - depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" - int "Number of lines on the LCD (1-2)" - range 1 2 - default 2 - ---help--- - This is the number of visible character lines on the LCD in custom profile. - It can either be 1 or 2. - -config PANEL_LCD_WIDTH - depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" - int "Number of characters per line on the LCD (1-40)" - range 1 40 - default 40 - ---help--- - This is the number of characters per line on the LCD in custom profile. - Common values are 16,20,24,40. - -config PANEL_LCD_BWIDTH - depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" - int "Internal LCD line width (1-40, 40 by default)" - range 1 40 - default 40 - ---help--- - Most LCDs use a standard controller which supports hardware lines of 40 - characters, although sometimes only 16, 20 or 24 of them are really wired - to the terminal. This results in some non-visible but addressable characters, - and is the case for most parallel LCDs. Other LCDs, and some serial ones, - however, use the same line width internally as what is visible. The KS0074 - for example, uses 16 characters per line for 16 visible characters per line. - - This option lets you configure the value used by your LCD in 'custom' profile. - If you don't know, put '40' here. - -config PANEL_LCD_HWIDTH - depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" - int "Hardware LCD line width (1-64, 64 by default)" - range 1 64 - default 64 - ---help--- - Most LCDs use a single address bit to differentiate line 0 and line 1. Since - some of them need to be able to address 40 chars with the lower bits, they - often use the immediately superior power of 2, which is 64, to address the - next line. - - If you don't know what your LCD uses, in doubt let 16 here for a 2x16, and - 64 here for a 2x40. - -config PANEL_LCD_CHARSET - depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" - int "LCD character set (0=normal, 1=KS0074)" - range 0 1 - default 0 - ---help--- - Some controllers such as the KS0074 use a somewhat strange character set - where many symbols are at unusual places. The driver knows how to map - 'standard' ASCII characters to the character sets used by these controllers. - Valid values are : - - 0 : normal (untranslated) character set - 1 : KS0074 character set - - If you don't know, use the normal one (0). - -config PANEL_LCD_PROTO - depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" - int "LCD communication mode (0=parallel 8 bits, 1=serial)" - range 0 1 - default 0 - ---help--- - This driver now supports any serial or parallel LCD wired to a parallel - port. But before assigning signals, the driver needs to know if it will - be driving a serial LCD or a parallel one. Serial LCDs only use 2 wires - (SDA/SCL), while parallel ones use 2 or 3 wires for the control signals - (E, RS, sometimes RW), and 4 or 8 for the data. Use 0 here for a 8 bits - parallel LCD, and 1 for a serial LCD. - -config PANEL_LCD_PIN_E - depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0" - int "Parallel port pin number & polarity connected to the LCD E signal (-17...17) " - range -17 17 - default 14 - ---help--- - This describes the number of the parallel port pin to which the LCD 'E' - signal has been connected. It can be : - - 0 : no connection (eg: connected to ground) - 1..17 : directly connected to any of these pins on the DB25 plug - -1..-17 : connected to the same pin through an inverter (eg: transistor). - - Default for the 'E' pin in custom profile is '14' (AUTOFEED). - -config PANEL_LCD_PIN_RS - depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0" - int "Parallel port pin number & polarity connected to the LCD RS signal (-17...17) " - range -17 17 - default 17 - ---help--- - This describes the number of the parallel port pin to which the LCD 'RS' - signal has been connected. It can be : - - 0 : no connection (eg: connected to ground) - 1..17 : directly connected to any of these pins on the DB25 plug - -1..-17 : connected to the same pin through an inverter (eg: transistor). - - Default for the 'RS' pin in custom profile is '17' (SELECT IN). - -config PANEL_LCD_PIN_RW - depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO="0" - int "Parallel port pin number & polarity connected to the LCD RW signal (-17...17) " - range -17 17 - default 16 - ---help--- - This describes the number of the parallel port pin to which the LCD 'RW' - signal has been connected. It can be : - - 0 : no connection (eg: connected to ground) - 1..17 : directly connected to any of these pins on the DB25 plug - -1..-17 : connected to the same pin through an inverter (eg: transistor). - - Default for the 'RW' pin in custom profile is '16' (INIT). - -config PANEL_LCD_PIN_SCL - depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO!="0" - int "Parallel port pin number & polarity connected to the LCD SCL signal (-17...17) " - range -17 17 - default 1 - ---help--- - This describes the number of the parallel port pin to which the serial - LCD 'SCL' signal has been connected. It can be : - - 0 : no connection (eg: connected to ground) - 1..17 : directly connected to any of these pins on the DB25 plug - -1..-17 : connected to the same pin through an inverter (eg: transistor). - - Default for the 'SCL' pin in custom profile is '1' (STROBE). - -config PANEL_LCD_PIN_SDA - depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" && PANEL_LCD_PROTO!="0" - int "Parallel port pin number & polarity connected to the LCD SDA signal (-17...17) " - range -17 17 - default 2 - ---help--- - This describes the number of the parallel port pin to which the serial - LCD 'SDA' signal has been connected. It can be : - - 0 : no connection (eg: connected to ground) - 1..17 : directly connected to any of these pins on the DB25 plug - -1..-17 : connected to the same pin through an inverter (eg: transistor). - - Default for the 'SDA' pin in custom profile is '2' (D0). - -config PANEL_LCD_PIN_BL - depends on PANEL && PANEL_PROFILE="0" && PANEL_LCD="1" - int "Parallel port pin number & polarity connected to the LCD backlight signal (-17...17) " - range -17 17 - default 0 - ---help--- - This describes the number of the parallel port pin to which the LCD 'BL' signal - has been connected. It can be : - - 0 : no connection (eg: connected to ground) - 1..17 : directly connected to any of these pins on the DB25 plug - -1..-17 : connected to the same pin through an inverter (eg: transistor). - - Default for the 'BL' pin in custom profile is '0' (uncontrolled). - -config PANEL_CHANGE_MESSAGE - depends on PANEL - bool "Change LCD initialization message ?" - default "n" - ---help--- - This allows you to replace the boot message indicating the kernel version - and the driver version with a custom message. This is useful on appliances - where a simple 'Starting system' message can be enough to stop a customer - from worrying. - - If you say 'Y' here, you'll be able to choose a message yourself. Otherwise, - say 'N' and keep the default message with the version. - -config PANEL_BOOT_MESSAGE - depends on PANEL && PANEL_CHANGE_MESSAGE="y" - string "New initialization message" - default "" - ---help--- - This allows you to replace the boot message indicating the kernel version - and the driver version with a custom message. This is useful on appliances - where a simple 'Starting system' message can be enough to stop a customer - from worrying. - - An empty message will only clear the display at driver init time. Any other - printf()-formatted message is valid with newline and escape codes. - -source "drivers/misc/c2port/Kconfig" -source "drivers/misc/eeprom/Kconfig" -source "drivers/misc/cb710/Kconfig" -source "drivers/misc/ti-st/Kconfig" -source "drivers/misc/lis3lv02d/Kconfig" -source "drivers/misc/altera-stapl/Kconfig" -source "drivers/misc/mei/Kconfig" -source "drivers/misc/vmw_vmci/Kconfig" -source "drivers/misc/mic/Kconfig" -source "drivers/misc/genwqe/Kconfig" -source "drivers/misc/echo/Kconfig" -source "drivers/misc/cxl/Kconfig" -endmenu diff --git a/src/linux/drivers/misc/Makefile b/src/linux/drivers/misc/Makefile deleted file mode 100644 index 3198336..0000000 --- a/src/linux/drivers/misc/Makefile +++ /dev/null @@ -1,70 +0,0 @@ -# -# Makefile for misc devices that really don't fit anywhere else. -# - -obj-$(CONFIG_IBM_ASM) += ibmasm/ -obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o -obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o -obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o -obj-$(CONFIG_INTEL_MID_PTI) += pti.o -obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o -obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o -obj-$(CONFIG_DUMMY_IRQ) += dummy-irq.o -obj-$(CONFIG_ICS932S401) += ics932s401.o -obj-$(CONFIG_LKDTM) += lkdtm.o -obj-$(CONFIG_TIFM_CORE) += tifm_core.o -obj-$(CONFIG_TIFM_7XX1) += tifm_7xx1.o -obj-$(CONFIG_PHANTOM) += phantom.o -obj-$(CONFIG_QCOM_COINCELL) += qcom-coincell.o -obj-$(CONFIG_SENSORS_BH1770) += bh1770glc.o -obj-$(CONFIG_SENSORS_APDS990X) += apds990x.o -obj-$(CONFIG_SGI_IOC4) += ioc4.o -obj-$(CONFIG_ENCLOSURE_SERVICES) += enclosure.o -obj-$(CONFIG_KGDB_TESTS) += kgdbts.o -obj-$(CONFIG_SGI_XP) += sgi-xp/ -obj-$(CONFIG_SGI_GRU) += sgi-gru/ -obj-$(CONFIG_CS5535_MFGPT) += cs5535-mfgpt.o -obj-$(CONFIG_HP_ILO) += hpilo.o -obj-$(CONFIG_APDS9802ALS) += apds9802als.o -obj-$(CONFIG_ISL29003) += isl29003.o -obj-$(CONFIG_ISL29020) += isl29020.o -obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o -obj-$(CONFIG_DS1682) += ds1682.o -obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o -obj-$(CONFIG_C2PORT) += c2port/ -obj-$(CONFIG_HMC6352) += hmc6352.o -obj-y += eeprom/ -obj-y += cb710/ -obj-$(CONFIG_SPEAR13XX_PCIE_GADGET) += spear13xx_pcie_gadget.o -obj-$(CONFIG_VMWARE_BALLOON) += vmw_balloon.o -obj-$(CONFIG_ARM_CHARLCD) += arm-charlcd.o -obj-$(CONFIG_PCH_PHUB) += pch_phub.o -obj-y += ti-st/ -obj-y += lis3lv02d/ -obj-$(CONFIG_USB_SWITCH_FSA9480) += fsa9480.o -obj-$(CONFIG_ALTERA_STAPL) +=altera-stapl/ -obj-$(CONFIG_INTEL_MEI) += mei/ -obj-$(CONFIG_VMWARE_VMCI) += vmw_vmci/ -obj-$(CONFIG_LATTICE_ECP3_CONFIG) += lattice-ecp3-config.o -obj-$(CONFIG_SRAM) += sram.o -obj-y += mic/ -obj-$(CONFIG_GENWQE) += genwqe/ -obj-$(CONFIG_ECHO) += echo/ -obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o -obj-$(CONFIG_CXL_BASE) += cxl/ -obj-$(CONFIG_PANEL) += panel.o - -lkdtm-$(CONFIG_LKDTM) += lkdtm_core.o -lkdtm-$(CONFIG_LKDTM) += lkdtm_bugs.o -lkdtm-$(CONFIG_LKDTM) += lkdtm_heap.o -lkdtm-$(CONFIG_LKDTM) += lkdtm_perms.o -lkdtm-$(CONFIG_LKDTM) += lkdtm_rodata_objcopy.o -lkdtm-$(CONFIG_LKDTM) += lkdtm_usercopy.o - -OBJCOPYFLAGS := -OBJCOPYFLAGS_lkdtm_rodata_objcopy.o := \ - --set-section-flags .text=alloc,readonly \ - --rename-section .text=.rodata -targets += lkdtm_rodata.o lkdtm_rodata_objcopy.o -$(obj)/lkdtm_rodata_objcopy.o: $(obj)/lkdtm_rodata.o FORCE - $(call if_changed,objcopy) diff --git a/src/linux/drivers/misc/altera-stapl/Kconfig b/src/linux/drivers/misc/altera-stapl/Kconfig deleted file mode 100644 index 7f01d8e..0000000 --- a/src/linux/drivers/misc/altera-stapl/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -comment "Altera FPGA firmware download module" - -config ALTERA_STAPL - tristate "Altera FPGA firmware download module" - depends on I2C - default n - help - An Altera FPGA module. Say Y when you want to support this tool. diff --git a/src/linux/drivers/misc/c2port/Kconfig b/src/linux/drivers/misc/c2port/Kconfig deleted file mode 100644 index 0dd690e..0000000 --- a/src/linux/drivers/misc/c2port/Kconfig +++ /dev/null @@ -1,34 +0,0 @@ -# -# C2 port devices -# - -menuconfig C2PORT - tristate "Silicon Labs C2 port support" - default n - help - This option enables support for Silicon Labs C2 port used to - program Silicon micro controller chips (and other 8051 compatible). - - If your board have no such micro controllers you don't need this - interface at all. - - To compile this driver as a module, choose M here: the module will - be called c2port_core. Note that you also need a client module - usually called c2port-*. - - If you are not sure, say N here. - -if C2PORT - -config C2PORT_DURAMAR_2150 - tristate "C2 port support for Eurotech's Duramar 2150" - depends on X86 - default n - help - This option enables C2 support for the Eurotech's Duramar 2150 - on board micro controller. - - To compile this driver as a module, choose M here: the module will - be called c2port-duramar2150. - -endif # C2PORT diff --git a/src/linux/drivers/misc/cb710/Kconfig b/src/linux/drivers/misc/cb710/Kconfig deleted file mode 100644 index 22429b8..0000000 --- a/src/linux/drivers/misc/cb710/Kconfig +++ /dev/null @@ -1,25 +0,0 @@ -config CB710_CORE - tristate "ENE CB710/720 Flash memory card reader support" - depends on PCI - help - This option enables support for PCI ENE CB710/720 Flash memory card - reader found in some laptops (ie. some versions of HP Compaq nx9500). - - You will also have to select some flash card format drivers (MMC/SD, - MemoryStick). - - This driver can also be built as a module. If so, the module - will be called cb710. - -config CB710_DEBUG - bool "Enable driver debugging" - depends on CB710_CORE != n - default n - help - This is an option for use by developers; most people should - say N here. This adds a lot of debugging output to dmesg. - -config CB710_DEBUG_ASSUMPTIONS - bool - depends on CB710_CORE != n - default y diff --git a/src/linux/drivers/misc/cb710/Makefile b/src/linux/drivers/misc/cb710/Makefile deleted file mode 100644 index 467c8e9..0000000 --- a/src/linux/drivers/misc/cb710/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -ccflags-$(CONFIG_CB710_DEBUG) := -DDEBUG - -obj-$(CONFIG_CB710_CORE) += cb710.o - -cb710-y := core.o sgbuf2.o -cb710-$(CONFIG_CB710_DEBUG) += debug.o diff --git a/src/linux/drivers/misc/cxl/Kconfig b/src/linux/drivers/misc/cxl/Kconfig deleted file mode 100644 index b75cf83..0000000 --- a/src/linux/drivers/misc/cxl/Kconfig +++ /dev/null @@ -1,38 +0,0 @@ -# -# IBM Coherent Accelerator (CXL) compatible devices -# - -config CXL_BASE - bool - default n - select PPC_COPRO_BASE - -config CXL_AFU_DRIVER_OPS - bool - default n - -config CXL - tristate "Support for IBM Coherent Accelerators (CXL)" - depends on PPC_POWERNV && PCI_MSI && EEH - select CXL_BASE - select CXL_AFU_DRIVER_OPS - default m - help - Select this option to enable driver support for IBM Coherent - Accelerators (CXL). CXL is otherwise known as Coherent Accelerator - Processor Interface (CAPI). CAPI allows accelerators in FPGAs to be - coherently attached to a CPU via an MMU. This driver enables - userspace programs to access these accelerators via /dev/cxl/afuM.N - devices. - - CAPI adapters are found in POWER8 based systems. - - If unsure, say N. - -config CXL_BIMODAL - bool "Support for bi-modal CAPI cards" - depends on HOTPLUG_PCI_POWERNV = y && CXL || HOTPLUG_PCI_POWERNV = m && CXL = m - default y - help - Select this option to enable support for bi-modal CAPI cards, such as - the Mellanox CX-4. diff --git a/src/linux/drivers/misc/echo/Kconfig b/src/linux/drivers/misc/echo/Kconfig deleted file mode 100644 index f1d41ea..0000000 --- a/src/linux/drivers/misc/echo/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config ECHO - tristate "Line Echo Canceller support" - default n - ---help--- - This driver provides line echo cancelling support for mISDN and - Zaptel drivers. - - To compile this driver as a module, choose M here. The module - will be called echo. diff --git a/src/linux/drivers/misc/eeprom/Kconfig b/src/linux/drivers/misc/eeprom/Kconfig deleted file mode 100644 index c4e41c2..0000000 --- a/src/linux/drivers/misc/eeprom/Kconfig +++ /dev/null @@ -1,103 +0,0 @@ -menu "EEPROM support" - -config EEPROM_AT24 - tristate "I2C EEPROMs / RAMs / ROMs from most vendors" - depends on I2C && SYSFS - select NVMEM - help - Enable this driver to get read/write support to most I2C EEPROMs - and compatible devices like FRAMs, SRAMs, ROMs etc. After you - configure the driver to know about each chip on your target - board. Use these generic chip names, instead of vendor-specific - ones like at24c64, 24lc02 or fm24c04: - - 24c00, 24c01, 24c02, spd (readonly 24c02), 24c04, 24c08, - 24c16, 24c32, 24c64, 24c128, 24c256, 24c512, 24c1024 - - Unless you like data loss puzzles, always be sure that any chip - you configure as a 24c32 (32 kbit) or larger is NOT really a - 24c16 (16 kbit) or smaller, and vice versa. Marking the chip - as read-only won't help recover from this. Also, if your chip - has any software write-protect mechanism you may want to review the - code to make sure this driver won't turn it on by accident. - - If you use this with an SMBus adapter instead of an I2C adapter, - full functionality is not available. Only smaller devices are - supported (24c16 and below, max 4 kByte). - - This driver can also be built as a module. If so, the module - will be called at24. - -config EEPROM_AT25 - tristate "SPI EEPROMs from most vendors" - depends on SPI && SYSFS - select NVMEM - help - Enable this driver to get read/write support to most SPI EEPROMs, - after you configure the board init code to know about each eeprom - on your target board. - - This driver can also be built as a module. If so, the module - will be called at25. - -config EEPROM_LEGACY - tristate "Old I2C EEPROM reader" - depends on I2C && SYSFS - help - If you say yes here you get read-only access to the EEPROM data - available on modern memory DIMMs and Sony Vaio laptops via I2C. Such - EEPROMs could theoretically be available on other devices as well. - - This driver can also be built as a module. If so, the module - will be called eeprom. - -config EEPROM_MAX6875 - tristate "Maxim MAX6874/5 power supply supervisor" - depends on I2C - help - If you say yes here you get read-only support for the user EEPROM of - the Maxim MAX6874/5 EEPROM-programmable, quad power-supply - sequencer/supervisor. - - All other features of this chip should be accessed via i2c-dev. - - This driver can also be built as a module. If so, the module - will be called max6875. - - -config EEPROM_93CX6 - tristate "EEPROM 93CX6 support" - help - This is a driver for the EEPROM chipsets 93c46 and 93c66. - The driver supports both read as well as write commands. - - If unsure, say N. - -config EEPROM_93XX46 - tristate "Microwire EEPROM 93XX46 support" - depends on SPI && SYSFS - select REGMAP - select NVMEM - help - Driver for the microwire EEPROM chipsets 93xx46x. The driver - supports both read and write commands and also the command to - erase the whole EEPROM. - - This driver can also be built as a module. If so, the module - will be called eeprom_93xx46. - - If unsure, say N. - -config EEPROM_DIGSY_MTC_CFG - bool "DigsyMTC display configuration EEPROMs device" - depends on GPIO_MPC5200 && SPI_GPIO - help - This option enables access to display configuration EEPROMs - on digsy_mtc board. You have to additionally select Microwire - EEPROM 93XX46 driver. sysfs entries will be created for that - EEPROM allowing to read/write the configuration data or to - erase the whole EEPROM. - - If unsure, say N. - -endmenu diff --git a/src/linux/drivers/misc/eeprom/Makefile b/src/linux/drivers/misc/eeprom/Makefile deleted file mode 100644 index fc1e81d..0000000 --- a/src/linux/drivers/misc/eeprom/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -obj-$(CONFIG_EEPROM_AT24) += at24.o -obj-$(CONFIG_EEPROM_AT25) += at25.o -obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o -obj-$(CONFIG_EEPROM_MAX6875) += max6875.o -obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o -obj-$(CONFIG_EEPROM_93XX46) += eeprom_93xx46.o -obj-$(CONFIG_EEPROM_DIGSY_MTC_CFG) += digsy_mtc_eeprom.o diff --git a/src/linux/drivers/misc/genwqe/Kconfig b/src/linux/drivers/misc/genwqe/Kconfig deleted file mode 100644 index 4c0a033..0000000 --- a/src/linux/drivers/misc/genwqe/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -# -# IBM Accelerator Family 'GenWQE' -# - -menuconfig GENWQE - tristate "GenWQE PCIe Accelerator" - depends on PCI && 64BIT - select CRC_ITU_T - default n - help - Enables PCIe card driver for IBM GenWQE accelerators. - The user-space interface is described in - include/linux/genwqe/genwqe_card.h. - -config GENWQE_PLATFORM_ERROR_RECOVERY - int "Use platform recovery procedures (0=off, 1=on)" - depends on GENWQE - default 1 if PPC64 - default 0 diff --git a/src/linux/drivers/misc/lis3lv02d/Kconfig b/src/linux/drivers/misc/lis3lv02d/Kconfig deleted file mode 100644 index 8f474e6..0000000 --- a/src/linux/drivers/misc/lis3lv02d/Kconfig +++ /dev/null @@ -1,37 +0,0 @@ -# -# STMicroelectonics LIS3LV02D and similar accelerometers -# - -config SENSORS_LIS3_SPI - tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (SPI)" - depends on !ACPI && SPI_MASTER && INPUT - select SENSORS_LIS3LV02D - default n - help - This driver provides support for the LIS3LV02Dx accelerometer connected - via SPI. The accelerometer data is readable via - /sys/devices/platform/lis3lv02d. - - This driver also provides an absolute input class device, allowing - the laptop to act as a pinball machine-esque joystick. - - This driver can also be built as modules. If so, the core module - will be called lis3lv02d and a specific module for the SPI transport - is called lis3lv02d_spi. - -config SENSORS_LIS3_I2C - tristate "STMicroeletronics LIS3LV02Dx three-axis digital accelerometer (I2C)" - depends on I2C && INPUT - select SENSORS_LIS3LV02D - default n - help - This driver provides support for the LIS3LV02Dx accelerometer connected - via I2C. The accelerometer data is readable via - /sys/devices/platform/lis3lv02d. - - This driver also provides an absolute input class device, allowing - the device to act as a pinball machine-esque joystick. - - This driver can also be built as modules. If so, the core module - will be called lis3lv02d and a specific module for the I2C transport - is called lis3lv02d_i2c. diff --git a/src/linux/drivers/misc/lis3lv02d/Makefile b/src/linux/drivers/misc/lis3lv02d/Makefile deleted file mode 100644 index 4bf58b1..0000000 --- a/src/linux/drivers/misc/lis3lv02d/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# STMicroelectonics LIS3LV02D and similar accelerometers -# - -obj-$(CONFIG_SENSORS_LIS3LV02D) += lis3lv02d.o -obj-$(CONFIG_SENSORS_LIS3_SPI) += lis3lv02d_spi.o -obj-$(CONFIG_SENSORS_LIS3_I2C) += lis3lv02d_i2c.o diff --git a/src/linux/drivers/misc/mei/Kconfig b/src/linux/drivers/misc/mei/Kconfig deleted file mode 100644 index c49e1d2..0000000 --- a/src/linux/drivers/misc/mei/Kconfig +++ /dev/null @@ -1,45 +0,0 @@ -config INTEL_MEI - tristate "Intel Management Engine Interface" - depends on X86 && PCI - help - The Intel Management Engine (Intel ME) provides Manageability, - Security and Media services for system containing Intel chipsets. - if selected /dev/mei misc device will be created. - - For more information see - - -config INTEL_MEI_ME - tristate "ME Enabled Intel Chipsets" - select INTEL_MEI - depends on X86 && PCI - help - MEI support for ME Enabled Intel chipsets. - - Supported Chipsets are: - 7 Series Chipset Family - 6 Series Chipset Family - 5 Series Chipset Family - 4 Series Chipset Family - Mobile 4 Series Chipset Family - ICH9 - 82946GZ/GL - 82G35 Express - 82Q963/Q965 - 82P965/G965 - Mobile PM965/GM965 - Mobile GME965/GLE960 - 82Q35 Express - 82G33/G31/P35/P31 Express - 82Q33 Express - 82X38/X48 Express - -config INTEL_MEI_TXE - tristate "Intel Trusted Execution Environment with ME Interface" - select INTEL_MEI - depends on X86 && PCI - help - MEI Support for Trusted Execution Environment device on Intel SoCs - - Supported SoCs: - Intel Bay Trail diff --git a/src/linux/drivers/misc/mic/Kconfig b/src/linux/drivers/misc/mic/Kconfig deleted file mode 100644 index 6fd9d36..0000000 --- a/src/linux/drivers/misc/mic/Kconfig +++ /dev/null @@ -1,152 +0,0 @@ -comment "Intel MIC Bus Driver" - -config INTEL_MIC_BUS - tristate "Intel MIC Bus Driver" - depends on 64BIT && PCI && X86 && X86_DEV_DMA_OPS - help - This option is selected by any driver which registers a - device or driver on the MIC Bus, such as CONFIG_INTEL_MIC_HOST, - CONFIG_INTEL_MIC_CARD, CONFIG_INTEL_MIC_X100_DMA etc. - - If you are building a host/card kernel with an Intel MIC device - then say M (recommended) or Y, else say N. If unsure say N. - - More information about the Intel MIC family as well as the Linux - OS and tools for MIC to use with this driver are available from - . - -comment "SCIF Bus Driver" - -config SCIF_BUS - tristate "SCIF Bus Driver" - depends on 64BIT && PCI && X86 && X86_DEV_DMA_OPS - help - This option is selected by any driver which registers a - device or driver on the SCIF Bus, such as CONFIG_INTEL_MIC_HOST - and CONFIG_INTEL_MIC_CARD. - - If you are building a host/card kernel with an Intel MIC device - then say M (recommended) or Y, else say N. If unsure say N. - - More information about the Intel MIC family as well as the Linux - OS and tools for MIC to use with this driver are available from - . - -comment "VOP Bus Driver" - -config VOP_BUS - tristate "VOP Bus Driver" - depends on 64BIT && PCI && X86 && X86_DEV_DMA_OPS - help - This option is selected by any driver which registers a - device or driver on the VOP Bus, such as CONFIG_INTEL_MIC_HOST - and CONFIG_INTEL_MIC_CARD. - - If you are building a host/card kernel with an Intel MIC device - then say M (recommended) or Y, else say N. If unsure say N. - - More information about the Intel MIC family as well as the Linux - OS and tools for MIC to use with this driver are available from - . - -comment "Intel MIC Host Driver" - -config INTEL_MIC_HOST - tristate "Intel MIC Host Driver" - depends on 64BIT && PCI && X86 - depends on INTEL_MIC_BUS && SCIF_BUS && MIC_COSM && VOP_BUS - help - This enables Host Driver support for the Intel Many Integrated - Core (MIC) family of PCIe form factor coprocessor devices that - run a 64 bit Linux OS. The driver manages card OS state and - enables communication between host and card. Intel MIC X100 - devices are currently supported. - - If you are building a host kernel with an Intel MIC device then - say M (recommended) or Y, else say N. If unsure say N. - - More information about the Intel MIC family as well as the Linux - OS and tools for MIC to use with this driver are available from - . - -comment "Intel MIC Card Driver" - -config INTEL_MIC_CARD - tristate "Intel MIC Card Driver" - depends on 64BIT && X86 - depends on INTEL_MIC_BUS && SCIF_BUS && MIC_COSM && VOP_BUS - select VIRTIO - help - This enables card driver support for the Intel Many Integrated - Core (MIC) device family. The card driver communicates shutdown/ - crash events to the host and allows registration/configuration of - virtio devices. Intel MIC X100 devices are currently supported. - - If you are building a card kernel for an Intel MIC device then - say M (recommended) or Y, else say N. If unsure say N. - - For more information see - . - -comment "SCIF Driver" - -config SCIF - tristate "SCIF Driver" - depends on 64BIT && PCI && X86 && SCIF_BUS && IOMMU_SUPPORT - select IOMMU_IOVA - help - This enables SCIF Driver support for the Intel Many Integrated - Core (MIC) family of PCIe form factor coprocessor devices that - run a 64 bit Linux OS. The Symmetric Communication Interface - (SCIF (pronounced as skiff)) is a low level communications API - across PCIe currently implemented for MIC. - - If you are building a host kernel with an Intel MIC device then - say M (recommended) or Y, else say N. If unsure say N. - - More information about the Intel MIC family as well as the Linux - OS and tools for MIC to use with this driver are available from - . - -comment "Intel MIC Coprocessor State Management (COSM) Drivers" - -config MIC_COSM - tristate "Intel MIC Coprocessor State Management (COSM) Drivers" - depends on 64BIT && PCI && X86 && SCIF - help - This enables COSM driver support for the Intel Many - Integrated Core (MIC) family of PCIe form factor coprocessor - devices. COSM drivers implement functions such as boot, - shutdown, reset and reboot of MIC devices. - - If you are building a host kernel with an Intel MIC device then - say M (recommended) or Y, else say N. If unsure say N. - - More information about the Intel MIC family as well as the Linux - OS and tools for MIC to use with this driver are available from - . - -comment "VOP Driver" - -config VOP - tristate "VOP Driver" - depends on 64BIT && PCI && X86 && VOP_BUS - select VHOST_RING - select VIRTIO - help - This enables VOP (Virtio over PCIe) Driver support for the Intel - Many Integrated Core (MIC) family of PCIe form factor coprocessor - devices. The VOP driver allows virtio drivers, e.g. net, console - and block drivers, on the card connect to user space virtio - devices on the host. - - If you are building a host kernel with an Intel MIC device then - say M (recommended) or Y, else say N. If unsure say N. - - More information about the Intel MIC family as well as the Linux - OS and tools for MIC to use with this driver are available from - . - -if VOP -source "drivers/vhost/Kconfig.vringh" -endif diff --git a/src/linux/drivers/misc/mic/Makefile b/src/linux/drivers/misc/mic/Makefile deleted file mode 100644 index f2b1323..0000000 --- a/src/linux/drivers/misc/mic/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile - Intel MIC Linux driver. -# Copyright(c) 2013, Intel Corporation. -# -obj-$(CONFIG_INTEL_MIC_HOST) += host/ -obj-$(CONFIG_INTEL_MIC_CARD) += card/ -obj-y += bus/ -obj-$(CONFIG_SCIF) += scif/ -obj-$(CONFIG_MIC_COSM) += cosm/ -obj-$(CONFIG_MIC_COSM) += cosm_client/ -obj-$(CONFIG_VOP) += vop/ diff --git a/src/linux/drivers/misc/mic/bus/Makefile b/src/linux/drivers/misc/mic/bus/Makefile deleted file mode 100644 index 8758a7d..0000000 --- a/src/linux/drivers/misc/mic/bus/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile - Intel MIC Linux driver. -# Copyright(c) 2014, Intel Corporation. -# -obj-$(CONFIG_INTEL_MIC_BUS) += mic_bus.o -obj-$(CONFIG_SCIF_BUS) += scif_bus.o -obj-$(CONFIG_MIC_COSM) += cosm_bus.o -obj-$(CONFIG_VOP_BUS) += vop_bus.o diff --git a/src/linux/drivers/misc/ti-st/Kconfig b/src/linux/drivers/misc/ti-st/Kconfig deleted file mode 100644 index f34dcc5..0000000 --- a/src/linux/drivers/misc/ti-st/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -# -# TI's shared transport line discipline and the protocol -# drivers (BT, FM and GPS) -# -menu "Texas Instruments shared transport line discipline" -config TI_ST - tristate "Shared transport core driver" - depends on NET && GPIOLIB && TTY - select FW_LOADER - help - This enables the shared transport core driver for TI - BT / FM and GPS combo chips. This enables protocol drivers - to register themselves with core and send data, the responses - are returned to relevant protocol drivers based on their - packet types. - -endmenu diff --git a/src/linux/drivers/misc/ti-st/Makefile b/src/linux/drivers/misc/ti-st/Makefile deleted file mode 100644 index 78d7ebb..0000000 --- a/src/linux/drivers/misc/ti-st/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# -# Makefile for TI's shared transport line discipline -# and its protocol drivers (BT, FM, GPS) -# -obj-$(CONFIG_TI_ST) += st_drv.o -st_drv-objs := st_core.o st_kim.o st_ll.o diff --git a/src/linux/drivers/misc/vmw_vmci/Kconfig b/src/linux/drivers/misc/vmw_vmci/Kconfig deleted file mode 100644 index 39c2eca..0000000 --- a/src/linux/drivers/misc/vmw_vmci/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# -# VMware VMCI device -# - -config VMWARE_VMCI - tristate "VMware VMCI Driver" - depends on X86 && PCI - help - This is VMware's Virtual Machine Communication Interface. It enables - high-speed communication between host and guest in a virtual - environment via the VMCI virtual device. - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called vmw_vmci. diff --git a/src/linux/drivers/mmc/Kconfig b/src/linux/drivers/mmc/Kconfig deleted file mode 100644 index f2eeb38..0000000 --- a/src/linux/drivers/mmc/Kconfig +++ /dev/null @@ -1,30 +0,0 @@ -# -# MMC subsystem configuration -# - -menuconfig MMC - tristate "MMC/SD/SDIO card support" - depends on HAS_IOMEM - help - This selects MultiMediaCard, Secure Digital and Secure - Digital I/O support. - - If you want MMC/SD/SDIO support, you should say Y here and - also to your specific host controller driver. - -config MMC_DEBUG - bool "MMC debugging" - depends on MMC != n - help - This is an option for use by developers; most people should - say N here. This enables MMC core and driver debugging. - -if MMC - -source "drivers/mmc/core/Kconfig" - -source "drivers/mmc/card/Kconfig" - -source "drivers/mmc/host/Kconfig" - -endif # MMC diff --git a/src/linux/drivers/mmc/Makefile b/src/linux/drivers/mmc/Makefile deleted file mode 100644 index 400756e..0000000 --- a/src/linux/drivers/mmc/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for the kernel mmc device drivers. -# - -subdir-ccflags-$(CONFIG_MMC_DEBUG) := -DDEBUG - -obj-$(CONFIG_MMC) += core/ -obj-$(CONFIG_MMC) += card/ -obj-$(subst m,y,$(CONFIG_MMC)) += host/ diff --git a/src/linux/drivers/mmc/card/Kconfig b/src/linux/drivers/mmc/card/Kconfig deleted file mode 100644 index 5562308..0000000 --- a/src/linux/drivers/mmc/card/Kconfig +++ /dev/null @@ -1,70 +0,0 @@ -# -# MMC/SD card drivers -# - -comment "MMC/SD/SDIO Card Drivers" - -config MMC_BLOCK - tristate "MMC block device driver" - depends on BLOCK - default y - help - Say Y here to enable the MMC block device driver support. - This provides a block device driver, which you can use to - mount the filesystem. Almost everyone wishing MMC support - should say Y or M here. - -config MMC_BLOCK_MINORS - int "Number of minors per block device" - depends on MMC_BLOCK - range 4 256 - default 8 - help - Number of minors per block device. One is needed for every - partition on the disk (plus one for the whole disk). - - Number of total MMC minors available is 256, so your number - of supported block devices will be limited to 256 divided - by this number. - - Default is 8 to be backwards compatible with previous - hardwired device numbering. - - If unsure, say 8 here. - -config MMC_BLOCK_BOUNCE - bool "Use bounce buffer for simple hosts" - depends on MMC_BLOCK - default y - help - SD/MMC is a high latency protocol where it is crucial to - send large requests in order to get high performance. Many - controllers, however, are restricted to continuous memory - (i.e. they can't do scatter-gather), something the kernel - rarely can provide. - - Say Y here to help these restricted hosts by bouncing - requests back and forth from a large buffer. You will get - a big performance gain at the cost of up to 64 KiB of - physical memory. - - If unsure, say Y here. - -config SDIO_UART - tristate "SDIO UART/GPS class support" - depends on TTY - help - SDIO function driver for SDIO cards that implements the UART - class, as well as the GPS class which appears like a UART. - -config MMC_TEST - tristate "MMC host test driver" - help - Development driver that performs a series of reads and writes - to a memory card in order to expose certain well known bugs - in host controllers. The tests are executed by writing to the - "test" file in debugfs under each card. Note that whatever is - on your card will be overwritten by these tests. - - This driver is only of interest to those developing or - testing a host driver. Most people should say N here. diff --git a/src/linux/drivers/mmc/core/Kconfig b/src/linux/drivers/mmc/core/Kconfig deleted file mode 100644 index 250f223..0000000 --- a/src/linux/drivers/mmc/core/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -# -# MMC core configuration -# -config PWRSEQ_EMMC - tristate "HW reset support for eMMC" - default y - depends on OF - help - This selects Hardware reset support aka pwrseq-emmc for eMMC - devices. By default this option is set to y. - - This driver can also be built as a module. If so, the module - will be called pwrseq_emmc. - -config PWRSEQ_SIMPLE - tristate "Simple HW reset support for MMC" - default y - depends on OF - help - This selects simple hardware reset support aka pwrseq-simple for MMC - devices. By default this option is set to y. - - This driver can also be built as a module. If so, the module - will be called pwrseq_simple. diff --git a/src/linux/drivers/mmc/host/Kconfig b/src/linux/drivers/mmc/host/Kconfig deleted file mode 100644 index 5274f50..0000000 --- a/src/linux/drivers/mmc/host/Kconfig +++ /dev/null @@ -1,800 +0,0 @@ -# -# MMC/SD host controller drivers -# - -comment "MMC/SD/SDIO Host Controller Drivers" - -config MMC_ARMMMCI - tristate "ARM AMBA Multimedia Card Interface support" - depends on ARM_AMBA - help - This selects the ARM(R) AMBA(R) PrimeCell Multimedia Card - Interface (PL180 and PL181) support. If you have an ARM(R) - platform with a Multimedia Card slot, say Y or M here. - - If unsure, say N. - -config MMC_QCOM_DML - tristate "Qualcomm Data Mover for SD Card Controller" - depends on MMC_ARMMMCI && QCOM_BAM_DMA - default y - help - This selects the Qualcomm Data Mover lite/local on SD Card controller. - This option will enable the dma to work correctly, if you are using - Qcom SOCs and MMC, you would probably need this option to get DMA working. - - if unsure, say N. - -config MMC_PXA - tristate "Intel PXA25x/26x/27x Multimedia Card Interface support" - depends on ARCH_PXA - help - This selects the Intel(R) PXA(R) Multimedia card Interface. - If you have a PXA(R) platform with a Multimedia Card slot, - say Y or M here. - - If unsure, say N. - -config MMC_SDHCI - tristate "Secure Digital Host Controller Interface support" - depends on HAS_DMA - help - This selects the generic Secure Digital Host Controller Interface. - It is used by manufacturers such as Texas Instruments(R), Ricoh(R) - and Toshiba(R). Most controllers found in laptops are of this type. - - If you have a controller with this interface, say Y or M here. You - also need to enable an appropriate bus interface. - - If unsure, say N. - -config MMC_SDHCI_IO_ACCESSORS - bool - depends on MMC_SDHCI - help - This is silent Kconfig symbol that is selected by the drivers that - need to overwrite SDHCI IO memory accessors. - -config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER - bool - depends on MMC_SDHCI - select MMC_SDHCI_IO_ACCESSORS - help - This option is selected by drivers running on big endian hosts - and performing I/O to a SDHCI controller through a bus that - implements a hardware byte swapper using a 32-bit datum. - This endian mapping mode is called "data invariance" and - has the effect of scrambling the addresses and formats of data - accessed in sizes other than the datum size. - - This is the case for the Nintendo Wii SDHCI. - -config MMC_SDHCI_PCI - tristate "SDHCI support on PCI bus" - depends on MMC_SDHCI && PCI - help - This selects the PCI Secure Digital Host Controller Interface. - Most controllers found today are PCI devices. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_RICOH_MMC - bool "Ricoh MMC Controller Disabler" - depends on MMC_SDHCI_PCI - default y - help - This adds a pci quirk to disable Ricoh MMC Controller. This - proprietary controller is unnecessary because the SDHCI driver - supports MMC cards on the SD controller, but if it is not - disabled, it will steal the MMC cards away - rendering them - useless. It is safe to select this even if you don't - have a Ricoh based card reader. - - If unsure, say Y. - -config MMC_SDHCI_ACPI - tristate "SDHCI support for ACPI enumerated SDHCI controllers" - depends on MMC_SDHCI && ACPI - select IOSF_MBI if X86 - help - This selects support for ACPI enumerated SDHCI controllers, - identified by ACPI Compatibility ID PNP0D40 or specific - ACPI Hardware IDs. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_PLTFM - tristate "SDHCI platform and OF driver helper" - depends on MMC_SDHCI - help - This selects the common helper functions support for Secure Digital - Host Controller Interface based platform and OF drivers. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_OF_ARASAN - tristate "SDHCI OF support for the Arasan SDHCI controllers" - depends on MMC_SDHCI_PLTFM - depends on OF - depends on COMMON_CLK - help - This selects the Arasan Secure Digital Host Controller Interface - (SDHCI). This hardware is found e.g. in Xilinx' Zynq SoC. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_OF_AT91 - tristate "SDHCI OF support for the Atmel SDMMC controller" - depends on MMC_SDHCI_PLTFM - depends on OF - select MMC_SDHCI_IO_ACCESSORS - help - This selects the Atmel SDMMC driver - -config MMC_SDHCI_OF_ESDHC - tristate "SDHCI OF support for the Freescale eSDHC controller" - depends on MMC_SDHCI_PLTFM - depends on PPC || ARCH_MXC || ARCH_LAYERSCAPE - select MMC_SDHCI_IO_ACCESSORS - help - This selects the Freescale eSDHC controller support. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_OF_HLWD - tristate "SDHCI OF support for the Nintendo Wii SDHCI controllers" - depends on MMC_SDHCI_PLTFM - depends on PPC - select MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER - help - This selects the Secure Digital Host Controller Interface (SDHCI) - found in the "Hollywood" chipset of the Nintendo Wii video game - console. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_CNS3XXX - tristate "SDHCI support on the Cavium Networks CNS3xxx SoC" - depends on ARCH_CNS3XXX - depends on MMC_SDHCI_PLTFM - help - This selects the SDHCI support for CNS3xxx System-on-Chip devices. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_ESDHC_IMX - tristate "SDHCI support for the Freescale eSDHC/uSDHC i.MX controller" - depends on ARCH_MXC - depends on MMC_SDHCI_PLTFM - select MMC_SDHCI_IO_ACCESSORS - help - This selects the Freescale eSDHC/uSDHC controller support - found on i.MX25, i.MX35 i.MX5x and i.MX6x. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_DOVE - tristate "SDHCI support on Marvell's Dove SoC" - depends on ARCH_DOVE || MACH_DOVE - depends on MMC_SDHCI_PLTFM - select MMC_SDHCI_IO_ACCESSORS - help - This selects the Secure Digital Host Controller Interface in - Marvell's Dove SoC. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_TEGRA - tristate "SDHCI platform support for the Tegra SD/MMC Controller" - depends on ARCH_TEGRA - depends on MMC_SDHCI_PLTFM - select MMC_SDHCI_IO_ACCESSORS - help - This selects the Tegra SD/MMC controller. If you have a Tegra - platform with SD or MMC devices, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_S3C - tristate "SDHCI support on Samsung S3C SoC" - depends on MMC_SDHCI && PLAT_SAMSUNG - help - This selects the Secure Digital Host Controller Interface (SDHCI) - often referrered to as the HSMMC block in some of the Samsung S3C - range of SoC. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_SIRF - tristate "SDHCI support on CSR SiRFprimaII and SiRFmarco SoCs" - depends on ARCH_SIRF - depends on MMC_SDHCI_PLTFM - select MMC_SDHCI_IO_ACCESSORS - help - This selects the SDHCI support for SiRF System-on-Chip devices. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_PXAV3 - tristate "Marvell MMP2 SD Host Controller support (PXAV3)" - depends on CLKDEV_LOOKUP - depends on MMC_SDHCI_PLTFM - depends on ARCH_BERLIN || ARCH_MMP || ARCH_MVEBU || COMPILE_TEST - default CPU_MMP2 - help - This selects the Marvell(R) PXAV3 SD Host Controller. - If you have a MMP2 platform with SD Host Controller - and a card slot, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_PXAV2 - tristate "Marvell PXA9XX SD Host Controller support (PXAV2)" - depends on CLKDEV_LOOKUP - depends on MMC_SDHCI_PLTFM - depends on ARCH_MMP || COMPILE_TEST - default CPU_PXA910 - help - This selects the Marvell(R) PXAV2 SD Host Controller. - If you have a PXA9XX platform with SD Host Controller - and a card slot, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_SPEAR - tristate "SDHCI support on ST SPEAr platform" - depends on MMC_SDHCI && PLAT_SPEAR - depends on OF - help - This selects the Secure Digital Host Controller Interface (SDHCI) - often referrered to as the HSMMC block in some of the ST SPEAR range - of SoC - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_S3C_DMA - bool "DMA support on S3C SDHCI" - depends on MMC_SDHCI_S3C - help - Enable DMA support on the Samsung S3C SDHCI glue. The DMA - has proved to be problematic if the controller encounters - certain errors, and thus should be treated with care. - - YMMV. - -config MMC_SDHCI_BCM_KONA - tristate "SDHCI support on Broadcom KONA platform" - depends on ARCH_BCM_MOBILE - depends on MMC_SDHCI_PLTFM - help - This selects the Broadcom Kona Secure Digital Host Controller - Interface(SDHCI) support. - This is used in Broadcom mobile SoCs. - - If you have a controller with this interface, say Y or M here. - -config MMC_SDHCI_F_SDH30 - tristate "SDHCI support for Fujitsu Semiconductor F_SDH30" - depends on MMC_SDHCI_PLTFM - depends on OF - help - This selects the Secure Digital Host Controller Interface (SDHCI) - Needed by some Fujitsu SoC for MMC / SD / SDIO support. - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_IPROC - tristate "SDHCI support for the BCM2835 & iProc SD/MMC Controller" - depends on ARCH_BCM2835 || ARCH_BCM_IPROC || COMPILE_TEST - depends on MMC_SDHCI_PLTFM - default ARCH_BCM_IPROC - select MMC_SDHCI_IO_ACCESSORS - help - This selects the iProc SD/MMC controller. - - If you have a BCM2835 or IPROC platform with SD or MMC devices, - say Y or M here. - - If unsure, say N. - -config MMC_MOXART - tristate "MOXART SD/MMC Host Controller support" - depends on ARCH_MOXART && MMC - help - This selects support for the MOXART SD/MMC Host Controller. - MOXA provides one multi-functional card reader which can - be found on some embedded hardware such as UC-7112-LX. - If you have a controller with this interface, say Y here. - -config MMC_SDHCI_ST - tristate "SDHCI support on STMicroelectronics SoC" - depends on ARCH_STI - depends on MMC_SDHCI_PLTFM - select MMC_SDHCI_IO_ACCESSORS - help - This selects the Secure Digital Host Controller Interface in - STMicroelectronics SoCs. - - If you have a controller with this interface, say Y or M here. - If unsure, say N. - -config MMC_OMAP - tristate "TI OMAP Multimedia Card Interface support" - depends on ARCH_OMAP - depends on TPS65010 || !MACH_OMAP_H2 - help - This selects the TI OMAP Multimedia card Interface. - If you have an OMAP board with a Multimedia Card slot, - say Y or M here. - - If unsure, say N. - -config MMC_OMAP_HS - tristate "TI OMAP High Speed Multimedia Card Interface support" - depends on HAS_DMA - depends on ARCH_OMAP2PLUS || ARCH_KEYSTONE || COMPILE_TEST - help - This selects the TI OMAP High Speed Multimedia card Interface. - If you have an omap2plus board with a Multimedia Card slot, - say Y or M here. - - If unsure, say N. - -config MMC_WBSD - tristate "Winbond W83L51xD SD/MMC Card Interface support" - depends on ISA_DMA_API - help - This selects the Winbond(R) W83L51xD Secure digital and - Multimedia card Interface. - If you have a machine with a integrated W83L518D or W83L519D - SD/MMC card reader, say Y or M here. - - If unsure, say N. - -config MMC_AU1X - tristate "Alchemy AU1XX0 MMC Card Interface support" - depends on MIPS_ALCHEMY - help - This selects the AMD Alchemy(R) Multimedia card interface. - If you have a Alchemy platform with a MMC slot, say Y or M here. - - If unsure, say N. - -config MMC_ATMELMCI - tristate "Atmel SD/MMC Driver (Multimedia Card Interface)" - depends on AVR32 || ARCH_AT91 - help - This selects the Atmel Multimedia Card Interface driver. If - you have an AT32 (AVR32) or AT91 platform with a Multimedia - Card slot, say Y or M here. - - If unsure, say N. - -config MMC_SDHCI_MSM - tristate "Qualcomm SDHCI Controller Support" - depends on ARCH_QCOM || (ARM && COMPILE_TEST) - depends on MMC_SDHCI_PLTFM - help - This selects the Secure Digital Host Controller Interface (SDHCI) - support present in Qualcomm SOCs. The controller supports - SD/MMC/SDIO devices. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_MXC - tristate "Freescale i.MX21/27/31 or MPC512x Multimedia Card support" - depends on ARCH_MXC || PPC_MPC512x - help - This selects the Freescale i.MX21, i.MX27, i.MX31 or MPC512x - Multimedia Card Interface. If you have an i.MX or MPC512x platform - with a Multimedia Card slot, say Y or M here. - - If unsure, say N. - -config MMC_MXS - tristate "Freescale MXS Multimedia Card Interface support" - depends on ARCH_MXS && MXS_DMA - help - This selects the Freescale SSP MMC controller found on MXS based - platforms like mx23/28. - - If unsure, say N. - -config MMC_TIFM_SD - tristate "TI Flash Media MMC/SD Interface support" - depends on PCI - select TIFM_CORE - help - Say Y here if you want to be able to access MMC/SD cards with - the Texas Instruments(R) Flash Media card reader, found in many - laptops. - This option 'selects' (turns on, enables) 'TIFM_CORE', but you - probably also need appropriate card reader host adapter, such as - 'Misc devices: TI Flash Media PCI74xx/PCI76xx host adapter support - (TIFM_7XX1)'. - - To compile this driver as a module, choose M here: the - module will be called tifm_sd. - -config MMC_MVSDIO - tristate "Marvell MMC/SD/SDIO host driver" - depends on PLAT_ORION - depends on OF - ---help--- - This selects the Marvell SDIO host driver. - SDIO may currently be found on the Kirkwood 88F6281 and 88F6192 - SoC controllers. - - To compile this driver as a module, choose M here: the - module will be called mvsdio. - -config MMC_DAVINCI - tristate "TI DAVINCI Multimedia Card Interface support" - depends on ARCH_DAVINCI - help - This selects the TI DAVINCI Multimedia card Interface. - If you have an DAVINCI board with a Multimedia Card slot, - say Y or M here. If unsure, say N. - -config MMC_GOLDFISH - tristate "goldfish qemu Multimedia Card Interface support" - depends on HAS_DMA - depends on GOLDFISH || COMPILE_TEST - help - This selects the Goldfish Multimedia card Interface emulation - found on the Goldfish Android virtual device emulation. - -config MMC_SPI - tristate "MMC/SD/SDIO over SPI" - depends on SPI_MASTER && !HIGHMEM && HAS_DMA - select CRC7 - select CRC_ITU_T - help - Some systems access MMC/SD/SDIO cards using a SPI controller - instead of using a "native" MMC/SD/SDIO controller. This has a - disadvantage of being relatively high overhead, but a compensating - advantage of working on many systems without dedicated MMC/SD/SDIO - controllers. - - If unsure, or if your system has no SPI master driver, say N. - -config MMC_S3C - tristate "Samsung S3C SD/MMC Card Interface support" - depends on ARCH_S3C24XX - depends on S3C24XX_DMAC - help - This selects a driver for the MCI interface found in - Samsung's S3C2410, S3C2412, S3C2440, S3C2442 CPUs. - If you have a board based on one of those and a MMC/SD - slot, say Y or M here. - - If unsure, say N. - -config MMC_S3C_HW_SDIO_IRQ - bool "Hardware support for SDIO IRQ" - depends on MMC_S3C - help - Enable the hardware support for SDIO interrupts instead of using - the generic polling code. - -choice - prompt "Samsung S3C SD/MMC transfer code" - depends on MMC_S3C - -config MMC_S3C_PIO - bool "Use PIO transfers only" - help - Use PIO to transfer data between memory and the hardware. - - PIO is slower than DMA as it requires CPU instructions to - move the data. This has been the traditional default for - the S3C MCI driver. - -config MMC_S3C_DMA - bool "Use DMA transfers only" - help - Use DMA to transfer data between memory and the hardare. - - Currently, the DMA support in this driver seems to not be - working properly and needs to be debugged before this - option is useful. - -endchoice - -config MMC_SDRICOH_CS - tristate "MMC/SD driver for Ricoh Bay1Controllers" - depends on PCI && PCMCIA - help - Say Y here if your Notebook reports a Ricoh Bay1Controller PCMCIA - card whenever you insert a MMC or SD card into the card slot. - - To compile this driver as a module, choose M here: the - module will be called sdricoh_cs. - -config MMC_TMIO_CORE - tristate - -config MMC_TMIO - tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support" - depends on MFD_TMIO || MFD_ASIC3 - select MMC_TMIO_CORE - help - This provides support for the SD/MMC cell found in TC6393XB, - T7L66XB and also HTC ASIC3 - -config MMC_SDHI - tristate "SH-Mobile SDHI SD/SDIO controller support" - depends on SUPERH || ARM || ARM64 - depends on SUPERH || ARCH_RENESAS || COMPILE_TEST - select MMC_TMIO_CORE - help - This provides support for the SDHI SD/SDIO controller found in - SuperH and ARM SH-Mobile SoCs - -config MMC_CB710 - tristate "ENE CB710 MMC/SD Interface support" - depends on PCI - select CB710_CORE - help - This option enables support for MMC/SD part of ENE CB710/720 Flash - memory card reader found in some laptops (ie. some versions of - HP Compaq nx9500). - - This driver can also be built as a module. If so, the module - will be called cb710-mmc. - -config MMC_VIA_SDMMC - tristate "VIA SD/MMC Card Reader Driver" - depends on PCI - help - This selects the VIA SD/MMC Card Reader driver, say Y or M here. - VIA provides one multi-functional card reader which integrated into - some motherboards manufactured by VIA. This card reader supports - SD/MMC/SDHC. - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config SDH_BFIN - tristate "Blackfin Secure Digital Host support" - depends on (BF54x && !BF544) || (BF51x && !BF512) - help - If you say yes here you will get support for the Blackfin on-chip - Secure Digital Host interface. This includes support for MMC and - SD cards. - - To compile this driver as a module, choose M here: the - module will be called bfin_sdh. - - If unsure, say N. - -config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND - bool "Blackfin EZkit Missing SDH_CMD Pull Up Resistor Workaround" - depends on SDH_BFIN - help - If you say yes here SD-Cards may work on the EZkit. - -config MMC_DW - tristate "Synopsys DesignWare Memory Card Interface" - depends on HAS_DMA - depends on ARC || ARM || ARM64 || MIPS || COMPILE_TEST - help - This selects support for the Synopsys DesignWare Mobile Storage IP - block, this provides host support for SD and MMC interfaces, in both - PIO, internal DMA mode and external DMA mode. - -config MMC_DW_PLTFM - tristate "Synopsys Designware MCI Support as platform device" - depends on MMC_DW - default y - help - This selects the common helper functions support for Host Controller - Interface based platform driver. Please select this option if the IP - is present as a platform device. This is the common interface for the - Synopsys Designware IP. - - If you have a controller with this interface, say Y or M here. - - If unsure, say Y. - -config MMC_DW_EXYNOS - tristate "Exynos specific extensions for Synopsys DW Memory Card Interface" - depends on MMC_DW - select MMC_DW_PLTFM - help - This selects support for Samsung Exynos SoC specific extensions to the - Synopsys DesignWare Memory Card Interface driver. Select this option - for platforms based on Exynos4 and Exynos5 SoC's. - -config MMC_DW_K3 - tristate "K3 specific extensions for Synopsys DW Memory Card Interface" - depends on MMC_DW - select MMC_DW_PLTFM - help - This selects support for Hisilicon K3 SoC specific extensions to the - Synopsys DesignWare Memory Card Interface driver. Select this option - for platforms based on Hisilicon K3 SoC's. - -config MMC_DW_PCI - tristate "Synopsys Designware MCI support on PCI bus" - depends on MMC_DW && PCI - help - This selects the PCI bus for the Synopsys Designware Mobile Storage IP. - Select this option if the IP is present on PCI platform. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config MMC_DW_ROCKCHIP - tristate "Rockchip specific extensions for Synopsys DW Memory Card Interface" - depends on MMC_DW && ARCH_ROCKCHIP - select MMC_DW_PLTFM - help - This selects support for Rockchip SoC specific extensions to the - Synopsys DesignWare Memory Card Interface driver. Select this option - for platforms based on RK3066, RK3188 and RK3288 SoC's. - -config MMC_SH_MMCIF - tristate "SuperH Internal MMCIF support" - depends on HAS_DMA - depends on SUPERH || ARCH_RENESAS || COMPILE_TEST - help - This selects the MMC Host Interface controller (MMCIF) found in various - Renesas SoCs for SH and ARM architectures. - - -config MMC_JZ4740 - tristate "JZ4740 SD/Multimedia Card Interface support" - depends on MACH_JZ4740 - help - This selects support for the SD/MMC controller on Ingenic JZ4740 - SoCs. - If you have a board based on such a SoC and with a SD/MMC slot, - say Y or M here. - -config MMC_VUB300 - tristate "VUB300 USB to SDIO/SD/MMC Host Controller support" - depends on USB - help - This selects support for Elan Digital Systems' VUB300 chip. - - The VUB300 is a USB-SDIO Host Controller Interface chip - that enables the host computer to use SDIO/SD/MMC cards - via a USB 2.0 or USB 1.1 host. - - The VUB300 chip will be found in both physically separate - USB to SDIO/SD/MMC adapters and embedded on some motherboards. - - The VUB300 chip supports SD and MMC memory cards in addition - to single and multifunction SDIO cards. - - Some SDIO cards will need a firmware file to be loaded and - sent to VUB300 chip in order to achieve better data throughput. - Download these "Offload Pseudocode" from Elan Digital Systems' - web-site http://www.elandigitalsystems.com/support/downloads.php - and put them in /lib/firmware. Note that without these additional - firmware files the VUB300 chip will still function, but not at - the best obtainable data rate. - - To compile this mmc host controller driver as a module, - choose M here: the module will be called vub300. - - If you have a computer with an embedded VUB300 chip - or if you intend connecting a USB adapter based on a - VUB300 chip say Y or M here. - -config MMC_USHC - tristate "USB SD Host Controller (USHC) support" - depends on USB - help - This selects support for USB SD Host Controllers based on - the Cypress Astoria chip with firmware compliant with CSR's - USB SD Host Controller specification (CS-118793-SP). - - CSR boards with this device include: USB<>SDIO (M1985v2), - and Ultrasira. - - Note: These controllers only support SDIO cards and do not - support MMC or SD memory cards. - -config MMC_WMT - tristate "Wondermedia SD/MMC Host Controller support" - depends on ARCH_VT8500 - default y - help - This selects support for the SD/MMC Host Controller on - Wondermedia WM8505/WM8650 based SoCs. - - To compile this driver as a module, choose M here: the - module will be called wmt-sdmmc. - -config MMC_USDHI6ROL0 - tristate "Renesas USDHI6ROL0 SD/SDIO Host Controller support" - depends on HAS_DMA - help - This selects support for the Renesas USDHI6ROL0 SD/SDIO - Host Controller - -config MMC_REALTEK_PCI - tristate "Realtek PCI-E SD/MMC Card Interface Driver" - depends on MFD_RTSX_PCI - help - Say Y here to include driver code to support SD/MMC card interface - of Realtek PCI-E card reader - -config MMC_REALTEK_USB - tristate "Realtek USB SD/MMC Card Interface Driver" - depends on MFD_RTSX_USB - help - Say Y here to include driver code to support SD/MMC card interface - of Realtek RTS5129/39 series card reader - -config MMC_SUNXI - tristate "Allwinner sunxi SD/MMC Host Controller support" - depends on ARCH_SUNXI - help - This selects support for the SD/MMC Host Controller on - Allwinner sunxi SoCs. - -config MMC_TOSHIBA_PCI - tristate "Toshiba Type A SD/MMC Card Interface Driver" - depends on PCI - help - -config MMC_MTK - tristate "MediaTek SD/MMC Card Interface support" - depends on HAS_DMA - help - This selects the MediaTek(R) Secure digital and Multimedia card Interface. - If you have a machine with a integrated SD/MMC card reader, say Y or M here. - This is needed if support for any SD/SDIO/MMC devices is required. - If unsure, say N. - -config MMC_SDHCI_MICROCHIP_PIC32 - tristate "Microchip PIC32MZDA SDHCI support" - depends on MMC_SDHCI && PIC32MZDA && MMC_SDHCI_PLTFM - help - This selects the Secure Digital Host Controller Interface (SDHCI) - for PIC32MZDA platform. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. -config MMC_SDHCI_BRCMSTB - tristate "Broadcom SDIO/SD/MMC support" - depends on ARCH_BRCMSTB || BMIPS_GENERIC - depends on MMC_SDHCI_PLTFM - default y - help - This selects support for the SDIO/SD/MMC Host Controller on - Broadcom STB SoCs. - - If unsure, say Y. diff --git a/src/linux/drivers/mtd/Kconfig b/src/linux/drivers/mtd/Kconfig deleted file mode 100644 index e83a279..0000000 --- a/src/linux/drivers/mtd/Kconfig +++ /dev/null @@ -1,341 +0,0 @@ -menuconfig MTD - tristate "Memory Technology Device (MTD) support" - depends on GENERIC_IO - help - Memory Technology Devices are flash, RAM and similar chips, often - used for solid state file systems on embedded devices. This option - will provide the generic support for MTD drivers to register - themselves with the kernel and for potential users of MTD devices - to enumerate the devices which are present and obtain a handle on - them. It will also allow you to select individual drivers for - particular hardware and users of MTD devices. If unsure, say N. - -if MTD - -config MTD_TESTS - tristate "MTD tests support (DANGEROUS)" - depends on m - help - This option includes various MTD tests into compilation. The tests - should normally be compiled as kernel modules. The modules perform - various checks and verifications when loaded. - - WARNING: some of the tests will ERASE entire MTD device which they - test. Do not use these tests unless you really know what you do. - -config MTD_REDBOOT_PARTS - tristate "RedBoot partition table parsing" - ---help--- - RedBoot is a ROM monitor and bootloader which deals with multiple - 'images' in flash devices by putting a table one of the erase - blocks on the device, similar to a partition table, which gives - the offsets, lengths and names of all the images stored in the - flash. - - If you need code which can detect and parse this table, and register - MTD 'partitions' corresponding to each image in the table, enable - this option. - - You will still need the parsing functions to be called by the driver - for your particular device. It won't happen automatically. The - SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for - example. - -if MTD_REDBOOT_PARTS - -config MTD_REDBOOT_DIRECTORY_BLOCK - int "Location of RedBoot partition table" - default "-1" - ---help--- - This option is the Linux counterpart to the - CYGNUM_REDBOOT_FIS_DIRECTORY_BLOCK RedBoot compile time - option. - - The option specifies which Flash sectors holds the RedBoot - partition table. A zero or positive value gives an absolute - erase block number. A negative value specifies a number of - sectors before the end of the device. - - For example "2" means block number 2, "-1" means the last - block and "-2" means the penultimate block. - -config MTD_REDBOOT_PARTS_UNALLOCATED - bool "Include unallocated flash regions" - help - If you need to register each unallocated flash region as a MTD - 'partition', enable this option. - -config MTD_REDBOOT_PARTS_READONLY - bool "Force read-only for RedBoot system images" - help - If you need to force read-only for 'RedBoot', 'RedBoot Config' and - 'FIS directory' images, enable this option. - -endif # MTD_REDBOOT_PARTS - -config MTD_CMDLINE_PARTS - tristate "Command line partition table parsing" - depends on MTD - ---help--- - Allow generic configuration of the MTD partition tables via the kernel - command line. Multiple flash resources are supported for hardware where - different kinds of flash memory are available. - - You will still need the parsing functions to be called by the driver - for your particular device. It won't happen automatically. The - SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for - example. - - The format for the command line is as follows: - - mtdparts=[; := :[,] - := [@offset][][ro] - := unique id used in mapping driver/device - := standard linux memsize OR "-" to denote all - remaining space - := (NAME) - - Due to the way Linux handles the command line, no spaces are - allowed in the partition definition, including mtd id's and partition - names. - - Examples: - - 1 flash resource (mtd-id "sa1100"), with 1 single writable partition: - mtdparts=sa1100:- - - Same flash, but 2 named partitions, the first one being read-only: - mtdparts=sa1100:256k(ARMboot)ro,-(root) - - If unsure, say 'N'. - -config MTD_AFS_PARTS - tristate "ARM Firmware Suite partition parsing" - depends on (ARM || ARM64) - ---help--- - The ARM Firmware Suite allows the user to divide flash devices into - multiple 'images'. Each such image has a header containing its name - and offset/size etc. - - If you need code which can detect and parse these tables, and - register MTD 'partitions' corresponding to each image detected, - enable this option. - - You will still need the parsing functions to be called by the driver - for your particular device. It won't happen automatically. The - 'physmap' map driver (CONFIG_MTD_PHYSMAP) does this, for example. - -config MTD_OF_PARTS - tristate "OpenFirmware partitioning information support" - default y - depends on OF - help - This provides a partition parsing function which derives - the partition map from the children of the flash node, - as described in Documentation/devicetree/bindings/mtd/partition.txt. - -config MTD_AR7_PARTS - tristate "TI AR7 partitioning support" - ---help--- - TI AR7 partitioning support - -config MTD_BCM63XX_PARTS - tristate "BCM63XX CFE partitioning support" - depends on BCM63XX || BMIPS_GENERIC || COMPILE_TEST - select CRC32 - help - This provides partions parsing for BCM63xx devices with CFE - bootloaders. - -config MTD_BCM47XX_PARTS - tristate "BCM47XX partitioning support" - depends on BCM47XX || ARCH_BCM_5301X - help - This provides partitions parser for devices based on BCM47xx - boards. - -comment "User Modules And Translation Layers" - -# -# MTD block device support is select'ed if needed -# -config MTD_BLKDEVS - tristate - -config MTD_BLOCK - tristate "Caching block device access to MTD devices" - depends on BLOCK - select MTD_BLKDEVS - ---help--- - Although most flash chips have an erase size too large to be useful - as block devices, it is possible to use MTD devices which are based - on RAM chips in this manner. This block device is a user of MTD - devices performing that function. - - At the moment, it is also required for the Journalling Flash File - System(s) to obtain a handle on the MTD device when it's mounted - (although JFFS and JFFS2 don't actually use any of the functionality - of the mtdblock device). - - Later, it may be extended to perform read/erase/modify/write cycles - on flash chips to emulate a smaller block size. Needless to say, - this is very unsafe, but could be useful for file systems which are - almost never written to. - - You do not need this option for use with the DiskOnChip devices. For - those, enable NFTL support (CONFIG_NFTL) instead. - -config MTD_BLOCK_RO - tristate "Readonly block device access to MTD devices" - depends on MTD_BLOCK!=y && BLOCK - select MTD_BLKDEVS - help - This allows you to mount read-only file systems (such as cramfs) - from an MTD device, without the overhead (and danger) of the caching - driver. - - You do not need this option for use with the DiskOnChip devices. For - those, enable NFTL support (CONFIG_NFTL) instead. - -config FTL - tristate "FTL (Flash Translation Layer) support" - depends on BLOCK - select MTD_BLKDEVS - ---help--- - This provides support for the original Flash Translation Layer which - is part of the PCMCIA specification. It uses a kind of pseudo- - file system on a flash device to emulate a block device with - 512-byte sectors, on top of which you put a 'normal' file system. - - You may find that the algorithms used in this code are patented - unless you live in the Free World where software patents aren't - legal - in the USA you are only permitted to use this on PCMCIA - hardware, although under the terms of the GPL you're obviously - permitted to copy, modify and distribute the code as you wish. Just - not use it. - -config NFTL - tristate "NFTL (NAND Flash Translation Layer) support" - depends on BLOCK - select MTD_BLKDEVS - ---help--- - This provides support for the NAND Flash Translation Layer which is - used on M-Systems' DiskOnChip devices. It uses a kind of pseudo- - file system on a flash device to emulate a block device with - 512-byte sectors, on top of which you put a 'normal' file system. - - You may find that the algorithms used in this code are patented - unless you live in the Free World where software patents aren't - legal - in the USA you are only permitted to use this on DiskOnChip - hardware, although under the terms of the GPL you're obviously - permitted to copy, modify and distribute the code as you wish. Just - not use it. - -config NFTL_RW - bool "Write support for NFTL" - depends on NFTL - help - Support for writing to the NAND Flash Translation Layer, as used - on the DiskOnChip. - -config INFTL - tristate "INFTL (Inverse NAND Flash Translation Layer) support" - depends on BLOCK - select MTD_BLKDEVS - ---help--- - This provides support for the Inverse NAND Flash Translation - Layer which is used on M-Systems' newer DiskOnChip devices. It - uses a kind of pseudo-file system on a flash device to emulate - a block device with 512-byte sectors, on top of which you put - a 'normal' file system. - - You may find that the algorithms used in this code are patented - unless you live in the Free World where software patents aren't - legal - in the USA you are only permitted to use this on DiskOnChip - hardware, although under the terms of the GPL you're obviously - permitted to copy, modify and distribute the code as you wish. Just - not use it. - -config RFD_FTL - tristate "Resident Flash Disk (Flash Translation Layer) support" - depends on BLOCK - select MTD_BLKDEVS - ---help--- - This provides support for the flash translation layer known - as the Resident Flash Disk (RFD), as used by the Embedded BIOS - of General Software. There is a blurb at: - - http://www.gensw.com/pages/prod/bios/rfd.htm - -config SSFDC - tristate "NAND SSFDC (SmartMedia) read only translation layer" - depends on BLOCK - select MTD_BLKDEVS - help - This enables read only access to SmartMedia formatted NAND - flash. You can mount it with FAT file system. - - -config SM_FTL - tristate "SmartMedia/xD new translation layer" - depends on BLOCK - select MTD_BLKDEVS - select MTD_NAND_ECC - help - This enables EXPERIMENTAL R/W support for SmartMedia/xD - FTL (Flash translation layer). - Write support is only lightly tested, therefore this driver - isn't recommended to use with valuable data (anyway if you have - valuable data, do backups regardless of software/hardware you - use, because you never know what will eat your data...) - If you only need R/O access, you can use older R/O driver - (CONFIG_SSFDC) - -config MTD_OOPS - tristate "Log panic/oops to an MTD buffer" - help - This enables panic and oops messages to be logged to a circular - buffer in a flash partition where it can be read back at some - later point. - -config MTD_SWAP - tristate "Swap on MTD device support" - depends on MTD && SWAP - select MTD_BLKDEVS - help - Provides volatile block device driver on top of mtd partition - suitable for swapping. The mapping of written blocks is not saved. - The driver provides wear leveling by storing erase counter into the - OOB. - -config MTD_PARTITIONED_MASTER - bool "Retain master device when partitioned" - default n - depends on MTD - help - For historical reasons, by default, either a master is present or - several partitions are present, but not both. The concern was that - data listed in multiple partitions was dangerous; however, SCSI does - this and it is frequently useful for applications. This config option - leaves the master in even if the device is partitioned. It also makes - the parent of the partition device be the master device, rather than - what lies behind the master. - -source "drivers/mtd/chips/Kconfig" - -source "drivers/mtd/maps/Kconfig" - -source "drivers/mtd/devices/Kconfig" - -source "drivers/mtd/nand/Kconfig" - -source "drivers/mtd/onenand/Kconfig" - -source "drivers/mtd/lpddr/Kconfig" - -source "drivers/mtd/spi-nor/Kconfig" - -source "drivers/mtd/ubi/Kconfig" - -endif # MTD diff --git a/src/linux/drivers/mtd/chips/Kconfig b/src/linux/drivers/mtd/chips/Kconfig deleted file mode 100644 index bbfa1f1..0000000 --- a/src/linux/drivers/mtd/chips/Kconfig +++ /dev/null @@ -1,240 +0,0 @@ -menu "RAM/ROM/Flash chip drivers" - depends on MTD!=n - -config MTD_CFI - tristate "Detect flash chips by Common Flash Interface (CFI) probe" - select MTD_GEN_PROBE - select MTD_CFI_UTIL - help - The Common Flash Interface specification was developed by Intel, - AMD and other flash manufactures that provides a universal method - for probing the capabilities of flash devices. If you wish to - support any device that is CFI-compliant, you need to enable this - option. Visit - for more information on CFI. - -config MTD_JEDECPROBE - tristate "Detect non-CFI AMD/JEDEC-compatible flash chips" - select MTD_GEN_PROBE - select MTD_CFI_UTIL - help - This option enables JEDEC-style probing of flash chips which are not - compatible with the Common Flash Interface, but will use the common - CFI-targeted flash drivers for any chips which are identified which - are in fact compatible in all but the probe method. This actually - covers most AMD/Fujitsu-compatible chips and also non-CFI - Intel chips. - -config MTD_GEN_PROBE - tristate - -config MTD_CFI_ADV_OPTIONS - bool "Flash chip driver advanced configuration options" - depends on MTD_GEN_PROBE - help - If you need to specify a specific endianness for access to flash - chips, or if you wish to reduce the size of the kernel by including - support for only specific arrangements of flash chips, say 'Y'. This - option does not directly affect the code, but will enable other - configuration options which allow you to do so. - - If unsure, say 'N'. - -choice - prompt "Flash cmd/query data swapping" - depends on MTD_CFI_ADV_OPTIONS - default MTD_CFI_NOSWAP - ---help--- - This option defines the way in which the CPU attempts to arrange - data bits when writing the 'magic' commands to the chips. Saying - 'NO', which is the default when CONFIG_MTD_CFI_ADV_OPTIONS isn't - enabled, means that the CPU will not do any swapping; the chips - are expected to be wired to the CPU in 'host-endian' form. - Specific arrangements are possible with the BIG_ENDIAN_BYTE and - LITTLE_ENDIAN_BYTE, if the bytes are reversed. - -config MTD_CFI_NOSWAP - bool "NO" - -config MTD_CFI_BE_BYTE_SWAP - bool "BIG_ENDIAN_BYTE" - -config MTD_CFI_LE_BYTE_SWAP - bool "LITTLE_ENDIAN_BYTE" - -endchoice - -config MTD_CFI_GEOMETRY - bool "Specific CFI Flash geometry selection" - depends on MTD_CFI_ADV_OPTIONS - select MTD_MAP_BANK_WIDTH_1 if !(MTD_MAP_BANK_WIDTH_2 || \ - MTD_MAP_BANK_WIDTH_4 || MTD_MAP_BANK_WIDTH_8 || \ - MTD_MAP_BANK_WIDTH_16 || MTD_MAP_BANK_WIDTH_32) - select MTD_CFI_I1 if !(MTD_CFI_I2 || MTD_CFI_I4 || MTD_CFI_I8) - help - This option does not affect the code directly, but will enable - some other configuration options which would allow you to reduce - the size of the kernel by including support for only certain - arrangements of CFI chips. If unsure, say 'N' and all options - which are supported by the current code will be enabled. - -config MTD_MAP_BANK_WIDTH_1 - bool "Support 8-bit buswidth" if MTD_CFI_GEOMETRY - default y - help - If you wish to support CFI devices on a physical bus which is - 8 bits wide, say 'Y'. - -config MTD_MAP_BANK_WIDTH_2 - bool "Support 16-bit buswidth" if MTD_CFI_GEOMETRY - default y - help - If you wish to support CFI devices on a physical bus which is - 16 bits wide, say 'Y'. - -config MTD_MAP_BANK_WIDTH_4 - bool "Support 32-bit buswidth" if MTD_CFI_GEOMETRY - default y - help - If you wish to support CFI devices on a physical bus which is - 32 bits wide, say 'Y'. - -config MTD_MAP_BANK_WIDTH_8 - bool "Support 64-bit buswidth" if MTD_CFI_GEOMETRY - default n - help - If you wish to support CFI devices on a physical bus which is - 64 bits wide, say 'Y'. - -config MTD_MAP_BANK_WIDTH_16 - bool "Support 128-bit buswidth" if MTD_CFI_GEOMETRY - default n - help - If you wish to support CFI devices on a physical bus which is - 128 bits wide, say 'Y'. - -config MTD_MAP_BANK_WIDTH_32 - bool "Support 256-bit buswidth" if MTD_CFI_GEOMETRY - select MTD_COMPLEX_MAPPINGS if HAS_IOMEM - default n - help - If you wish to support CFI devices on a physical bus which is - 256 bits wide, say 'Y'. - -config MTD_CFI_I1 - bool "Support 1-chip flash interleave" if MTD_CFI_GEOMETRY - default y - help - If your flash chips are not interleaved - i.e. you only have one - flash chip addressed by each bus cycle, then say 'Y'. - -config MTD_CFI_I2 - bool "Support 2-chip flash interleave" if MTD_CFI_GEOMETRY - default y - help - If your flash chips are interleaved in pairs - i.e. you have two - flash chips addressed by each bus cycle, then say 'Y'. - -config MTD_CFI_I4 - bool "Support 4-chip flash interleave" if MTD_CFI_GEOMETRY - default n - help - If your flash chips are interleaved in fours - i.e. you have four - flash chips addressed by each bus cycle, then say 'Y'. - -config MTD_CFI_I8 - bool "Support 8-chip flash interleave" if MTD_CFI_GEOMETRY - default n - help - If your flash chips are interleaved in eights - i.e. you have eight - flash chips addressed by each bus cycle, then say 'Y'. - -config MTD_OTP - bool "Protection Registers aka one-time programmable (OTP) bits" - depends on MTD_CFI_ADV_OPTIONS - default n - help - This enables support for reading, writing and locking so called - "Protection Registers" present on some flash chips. - A subset of them are pre-programmed at the factory with a - unique set of values. The rest is user-programmable. - - The user-programmable Protection Registers contain one-time - programmable (OTP) bits; when programmed, register bits cannot be - erased. Each Protection Register can be accessed multiple times to - program individual bits, as long as the register remains unlocked. - - Each Protection Register has an associated Lock Register bit. When a - Lock Register bit is programmed, the associated Protection Register - can only be read; it can no longer be programmed. Additionally, - because the Lock Register bits themselves are OTP, when programmed, - Lock Register bits cannot be erased. Therefore, when a Protection - Register is locked, it cannot be unlocked. - - This feature should therefore be used with extreme care. Any mistake - in the programming of OTP bits will waste them. - -config MTD_CFI_INTELEXT - tristate "Support for CFI command set 0001 (Intel/Sharp chips)" - depends on MTD_GEN_PROBE - select MTD_CFI_UTIL - help - The Common Flash Interface defines a number of different command - sets which a CFI-compliant chip may claim to implement. This code - provides support for command set 0001, used on Intel StrataFlash - and other parts. - -config MTD_CFI_AMDSTD - tristate "Support for CFI command set 0002 (AMD/Fujitsu/Spansion chips)" - depends on MTD_GEN_PROBE - select MTD_CFI_UTIL - help - The Common Flash Interface defines a number of different command - sets which a CFI-compliant chip may claim to implement. This code - provides support for command set 0002, used on chips including - the AMD Am29LV320. - -config MTD_CFI_STAA - tristate "Support for CFI command set 0020 (ST (Advanced Architecture) chips)" - depends on MTD_GEN_PROBE - select MTD_CFI_UTIL - help - The Common Flash Interface defines a number of different command - sets which a CFI-compliant chip may claim to implement. This code - provides support for command set 0020. - -config MTD_CFI_UTIL - tristate - -config MTD_RAM - tristate "Support for RAM chips in bus mapping" - help - This option enables basic support for RAM chips accessed through - a bus mapping driver. - -config MTD_ROM - tristate "Support for ROM chips in bus mapping" - help - This option enables basic support for ROM chips accessed through - a bus mapping driver. - -config MTD_ABSENT - tristate "Support for absent chips in bus mapping" - help - This option enables support for a dummy probing driver used to - allocated placeholder MTD devices on systems that have socketed - or removable media. Use of this driver as a fallback chip probe - preserves the expected registration order of MTD device nodes on - the system regardless of media presence. Device nodes created - with this driver will return -ENODEV upon access. - -config MTD_XIP - bool "XIP aware MTD support" - depends on !SMP && (MTD_CFI_INTELEXT || MTD_CFI_AMDSTD) && ARCH_MTD_XIP - default y if XIP_KERNEL - help - This allows MTD support to work with flash memory which is also - used for XIP purposes. If you're not sure what this is all about - then say N. - -endmenu diff --git a/src/linux/drivers/mtd/devices/Kconfig b/src/linux/drivers/mtd/devices/Kconfig deleted file mode 100644 index 58329d2..0000000 --- a/src/linux/drivers/mtd/devices/Kconfig +++ /dev/null @@ -1,224 +0,0 @@ -menu "Self-contained MTD device drivers" - depends on MTD!=n - depends on HAS_IOMEM - -config MTD_PMC551 - tristate "Ramix PMC551 PCI Mezzanine RAM card support" - depends on PCI - ---help--- - This provides a MTD device driver for the Ramix PMC551 RAM PCI card - from Ramix Inc. . - These devices come in memory configurations from 32M - 1G. If you - have one, you probably want to enable this. - - If this driver is compiled as a module you get the ability to select - the size of the aperture window pointing into the devices memory. - What this means is that if you have a 1G card, normally the kernel - will use a 1G memory map as its view of the device. As a module, - you can select a 1M window into the memory and the driver will - "slide" the window around the PMC551's memory. This was - particularly useful on the 2.2 kernels on PPC architectures as there - was limited kernel space to deal with. - -config MTD_PMC551_BUGFIX - bool "PMC551 256M DRAM Bugfix" - depends on MTD_PMC551 - help - Some of Ramix's PMC551 boards with 256M configurations have invalid - column and row mux values. This option will fix them, but will - break other memory configurations. If unsure say N. - -config MTD_PMC551_DEBUG - bool "PMC551 Debugging" - depends on MTD_PMC551 - help - This option makes the PMC551 more verbose during its operation and - is only really useful if you are developing on this driver or - suspect a possible hardware or driver bug. If unsure say N. - -config MTD_MS02NV - tristate "DEC MS02-NV NVRAM module support" - depends on MACH_DECSTATION - help - This is an MTD driver for the DEC's MS02-NV (54-20948-01) battery - backed-up NVRAM module. The module was originally meant as an NFS - accelerator. Say Y here if you have a DECstation 5000/2x0 or a - DECsystem 5900 equipped with such a module. - - If you want to compile this driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . - The module will be called ms02-nv. - -config MTD_DATAFLASH - tristate "Support for AT45xxx DataFlash" - depends on SPI_MASTER - help - This enables access to AT45xxx DataFlash chips, using SPI. - Sometimes DataFlash chips are packaged inside MMC-format - cards; at this writing, the MMC stack won't handle those. - -config MTD_DATAFLASH_WRITE_VERIFY - bool "Verify DataFlash page writes" - depends on MTD_DATAFLASH - help - This adds an extra check when data is written to the flash. - It may help if you are verifying chip setup (timings etc) on - your board. There is a rare possibility that even though the - device thinks the write was successful, a bit could have been - flipped accidentally due to device wear or something else. - -config MTD_DATAFLASH_OTP - bool "DataFlash OTP support (Security Register)" - depends on MTD_DATAFLASH - help - Newer DataFlash chips (revisions C and D) support 128 bytes of - one-time-programmable (OTP) data. The first half may be written - (once) with up to 64 bytes of data, such as a serial number or - other key product data. The second half is programmed with a - unique-to-each-chip bit pattern at the factory. - -config MTD_M25P80 - tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)" - depends on SPI_MASTER && MTD_SPI_NOR - help - This enables access to most modern SPI flash chips, used for - program and data storage. Series supported include Atmel AT26DF, - Spansion S25SL, SST 25VF, ST M25P, and Winbond W25X. Other chips - are supported as well. See the driver source for the current list, - or to add other chips. - - Note that the original DataFlash chips (AT45 series, not AT26DF), - need an entirely different driver. - - Set up your spi devices with the right board-specific platform data, - if you want to specify device partitioning or to use a device which - doesn't support the JEDEC ID instruction. - -config MTD_SPEAR_SMI - tristate "SPEAR MTD NOR Support through SMI controller" - depends on PLAT_SPEAR - default y - help - This enable SNOR support on SPEAR platforms using SMI controller - -config MTD_SST25L - tristate "Support SST25L (non JEDEC) SPI Flash chips" - depends on SPI_MASTER - help - This enables access to the non JEDEC SST25L SPI flash chips, used - for program and data storage. - - Set up your spi devices with the right board-specific platform data, - if you want to specify device partitioning. - -config MTD_BCM47XXSFLASH - tristate "Support for serial flash on BCMA bus" - depends on BCMA_SFLASH && (MIPS || ARM) - help - BCMA bus can have various flash memories attached, they are - registered by bcma as platform devices. This enables driver for - serial flash memories. - -config MTD_SLRAM - tristate "Uncached system RAM" - help - If your CPU cannot cache all of the physical memory in your machine, - you can still use it for storage or swap by using this driver to - present it to the system as a Memory Technology Device. - -config MTD_PHRAM - tristate "Physical system RAM" - help - This is a re-implementation of the slram driver above. - - Use this driver to access physical memory that the kernel proper - doesn't have access to, memory beyond the mem=xxx limit, nvram, - memory on the video card, etc... - -config MTD_LART - tristate "28F160xx flash driver for LART" - depends on SA1100_LART - help - This enables the flash driver for LART. Please note that you do - not need any mapping/chip driver for LART. This one does it all - for you, so go disable all of those if you enabled some of them (: - -config MTD_MTDRAM - tristate "Test driver using RAM" - help - This enables a test MTD device driver which uses vmalloc() to - provide storage. You probably want to say 'N' unless you're - testing stuff. - -config MTDRAM_TOTAL_SIZE - int "MTDRAM device size in KiB" - depends on MTD_MTDRAM - default "4096" - help - This allows you to configure the total size of the MTD device - emulated by the MTDRAM driver. If the MTDRAM driver is built - as a module, it is also possible to specify this as a parameter when - loading the module. - -config MTDRAM_ERASE_SIZE - int "MTDRAM erase block size in KiB" - depends on MTD_MTDRAM - default "128" - help - This allows you to configure the size of the erase blocks in the - device emulated by the MTDRAM driver. If the MTDRAM driver is built - as a module, it is also possible to specify this as a parameter when - loading the module. - -config MTD_BLOCK2MTD - tristate "MTD using block device" - depends on BLOCK - help - This driver allows a block device to appear as an MTD. It would - generally be used in the following cases: - - Using Compact Flash as an MTD, these usually present themselves to - the system as an ATA drive. - Testing MTD users (eg JFFS2) on large media and media that might - be removed during a write (using the floppy drive). - -config MTD_POWERNV_FLASH - tristate "powernv flash MTD driver" - depends on PPC_POWERNV - help - This provides an MTD device to access flash on powernv OPAL - platforms from Linux. This device abstracts away the - firmware interface for flash access. - -comment "Disk-On-Chip Device Drivers" - -config MTD_DOCG3 - tristate "M-Systems Disk-On-Chip G3" - select BCH - select BCH_CONST_PARAMS - select BITREVERSE - ---help--- - This provides an MTD device driver for the M-Systems DiskOnChip - G3 devices. - - The driver provides access to G3 DiskOnChip, distributed by - M-Systems and now Sandisk. The support is very experimental, - and doesn't give access to any write operations. - -config MTD_ST_SPI_FSM - tristate "ST Microelectronics SPI FSM Serial Flash Controller" - depends on ARCH_STI - help - This provides an MTD device driver for the ST Microelectronics - SPI Fast Sequence Mode (FSM) Serial Flash Controller and support - for a subset of connected Serial Flash devices. - -if MTD_DOCG3 -config BCH_CONST_M - default 14 -config BCH_CONST_T - default 4 -endif - -endmenu diff --git a/src/linux/drivers/mtd/lpddr/Kconfig b/src/linux/drivers/mtd/lpddr/Kconfig deleted file mode 100644 index 3a19cbe..0000000 --- a/src/linux/drivers/mtd/lpddr/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -menu "LPDDR & LPDDR2 PCM memory drivers" - depends on MTD - -config MTD_LPDDR - tristate "Support for LPDDR flash chips" - select MTD_QINFO_PROBE - help - This option enables support of LPDDR (Low power double data rate) - flash chips. Synonymous with Mobile-DDR. It is a new standard for - DDR memories, intended for battery-operated systems. - -config MTD_QINFO_PROBE - depends on MTD_LPDDR - tristate "Detect flash chips by QINFO probe" - help - Device Information for LPDDR chips is offered through the Overlay - Window QINFO interface, permits software to be used for entire - families of devices. This serves similar purpose of CFI on legacy - Flash products - -config MTD_LPDDR2_NVM - # ARM dependency is only for writel_relaxed() - depends on MTD && ARM - tristate "Support for LPDDR2-NVM flash chips" - help - This option enables support of PCM memories with a LPDDR2-NVM - (Low power double data rate 2) interface. - -endmenu diff --git a/src/linux/drivers/mtd/maps/Kconfig b/src/linux/drivers/mtd/maps/Kconfig deleted file mode 100644 index 5bcc896..0000000 --- a/src/linux/drivers/mtd/maps/Kconfig +++ /dev/null @@ -1,412 +0,0 @@ -menu "Mapping drivers for chip access" - depends on MTD!=n - depends on HAS_IOMEM - -config MTD_COMPLEX_MAPPINGS - bool "Support non-linear mappings of flash chips" - help - This causes the chip drivers to allow for complicated - paged mappings of flash chips. - -config MTD_PHYSMAP - tristate "Flash device in physical memory map" - depends on MTD_CFI || MTD_JEDECPROBE || MTD_ROM || MTD_LPDDR - help - This provides a 'mapping' driver which allows the NOR Flash and - ROM driver code to communicate with chips which are mapped - physically into the CPU's memory. You will need to configure - the physical address and size of the flash chips on your - particular board as well as the bus width, either statically - with config options or at run-time. - - To compile this driver as a module, choose M here: the - module will be called physmap. - -config MTD_PHYSMAP_COMPAT - bool "Physmap compat support" - depends on MTD_PHYSMAP - default n - help - Setup a simple mapping via the Kconfig options. Normally the - physmap configuration options are done via your board's - resource file. - - If unsure, say N here. - -config MTD_PHYSMAP_START - hex "Physical start address of flash mapping" - depends on MTD_PHYSMAP_COMPAT - default "0x8000000" - help - This is the physical memory location at which the flash chips - are mapped on your particular target board. Refer to the - memory map which should hopefully be in the documentation for - your board. - -config MTD_PHYSMAP_LEN - hex "Physical length of flash mapping" - depends on MTD_PHYSMAP_COMPAT - default "0" - help - This is the total length of the mapping of the flash chips on - your particular board. If there is space, or aliases, in the - physical memory map between the chips, this could be larger - than the total amount of flash present. Refer to the memory - map which should hopefully be in the documentation for your - board. - -config MTD_PHYSMAP_BANKWIDTH - int "Bank width in octets" - depends on MTD_PHYSMAP_COMPAT - default "2" - help - This is the total width of the data bus of the flash devices - in octets. For example, if you have a data bus width of 32 - bits, you would set the bus width octet value to 4. This is - used internally by the CFI drivers. - -config MTD_PHYSMAP_OF - tristate "Memory device in physical memory map based on OF description" - depends on OF && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM || MTD_RAM) - help - This provides a 'mapping' driver which allows the NOR Flash, ROM - and RAM driver code to communicate with chips which are mapped - physically into the CPU's memory. The mapping description here is - taken from OF device tree. - -config MTD_PHYSMAP_OF_VERSATILE - bool "Support ARM Versatile physmap OF" - depends on MTD_PHYSMAP_OF - depends on MFD_SYSCON - default y if (ARCH_INTEGRATOR || ARCH_VERSATILE || ARCH_REALVIEW) - help - This provides some extra DT physmap parsing for the ARM Versatile - platforms, basically to add a VPP (write protection) callback so - the flash can be taken out of write protection. - -config MTD_PMC_MSP_EVM - tristate "CFI Flash device mapped on PMC-Sierra MSP" - depends on PMC_MSP && MTD_CFI - help - This provides a 'mapping' driver which supports the way - in which user-programmable flash chips are connected on the - PMC-Sierra MSP eval/demo boards. - -choice - prompt "Maximum mappable memory available for flash IO" - depends on MTD_PMC_MSP_EVM - default MSP_FLASH_MAP_LIMIT_32M - -config MSP_FLASH_MAP_LIMIT_32M - bool "32M" - -endchoice - -config MSP_FLASH_MAP_LIMIT - hex - default "0x02000000" - depends on MSP_FLASH_MAP_LIMIT_32M - -config MTD_SUN_UFLASH - tristate "Sun Microsystems userflash support" - depends on SPARC && MTD_CFI && PCI - help - This provides a 'mapping' driver which supports the way in - which user-programmable flash chips are connected on various - Sun Microsystems boardsets. This driver will require CFI support - in the kernel, so if you did not enable CFI previously, do that now. - -config MTD_SC520CDP - tristate "CFI Flash device mapped on AMD SC520 CDP" - depends on (MELAN || COMPILE_TEST) && MTD_CFI - help - The SC520 CDP board has two banks of CFI-compliant chips and one - Dual-in-line JEDEC chip. This 'mapping' driver supports that - arrangement, implementing three MTD devices. - -config MTD_NETSC520 - tristate "CFI Flash device mapped on AMD NetSc520" - depends on (MELAN || COMPILE_TEST) && MTD_CFI - help - This enables access routines for the flash chips on the AMD NetSc520 - demonstration board. If you have one of these boards and would like - to use the flash chips on it, say 'Y'. - -config MTD_TS5500 - tristate "JEDEC Flash device mapped on Technologic Systems TS-5500" - depends on TS5500 || COMPILE_TEST - select MTD_JEDECPROBE - select MTD_CFI_AMDSTD - help - This provides a driver for the on-board flash of the Technologic - System's TS-5500 board. The 2MB flash is split into 3 partitions - which are accessed as separate MTD devices. - - mtd0 and mtd2 are the two BIOS drives, which use the resident - flash disk (RFD) flash translation layer. - - mtd1 allows you to reprogram your BIOS. BE VERY CAREFUL. - - Note that jumper 3 ("Write Enable Drive A") must be set - otherwise detection won't succeed. - -config MTD_SBC_GXX - tristate "CFI Flash device mapped on Arcom SBC-GXx boards" - depends on X86 && MTD_CFI_INTELEXT && MTD_COMPLEX_MAPPINGS - help - This provides a driver for the on-board flash of Arcom Control - Systems' SBC-GXn family of boards, formerly known as SBC-MediaGX. - By default the flash is split into 3 partitions which are accessed - as separate MTD devices. This board utilizes Intel StrataFlash. - More info at - . - -config MTD_PXA2XX - tristate "CFI Flash device mapped on Intel XScale PXA2xx based boards" - depends on (PXA25x || PXA27x) && MTD_CFI_INTELEXT - help - This provides a driver for the NOR flash attached to a PXA2xx chip. - -config MTD_SCx200_DOCFLASH - tristate "Flash device mapped with DOCCS on NatSemi SCx200" - depends on SCx200 && MTD_CFI - help - Enable support for a flash chip mapped using the DOCCS signal on a - National Semiconductor SCx200 processor. - - If you don't know what to do here, say N. - - If compiled as a module, it will be called scx200_docflash. - -config MTD_AMD76XROM - tristate "BIOS flash chip on AMD76x southbridge" - depends on X86 && MTD_JEDECPROBE - help - Support for treating the BIOS flash chip on AMD76x motherboards - as an MTD device - with this you can reprogram your BIOS. - - BE VERY CAREFUL. - -config MTD_ICHXROM - tristate "BIOS flash chip on Intel Controller Hub 2/3/4/5" - depends on X86 && MTD_JEDECPROBE - help - Support for treating the BIOS flash chip on ICHX motherboards - as an MTD device - with this you can reprogram your BIOS. - - BE VERY CAREFUL. - -config MTD_ESB2ROM - tristate "BIOS flash chip on Intel ESB Controller Hub 2" - depends on X86 && MTD_JEDECPROBE && PCI - help - Support for treating the BIOS flash chip on ESB2 motherboards - as an MTD device - with this you can reprogram your BIOS. - - BE VERY CAREFUL. - -config MTD_CK804XROM - tristate "BIOS flash chip on Nvidia CK804" - depends on X86 && MTD_JEDECPROBE && PCI - help - Support for treating the BIOS flash chip on nvidia motherboards - as an MTD device - with this you can reprogram your BIOS. - - BE VERY CAREFUL. - -config MTD_SCB2_FLASH - tristate "BIOS flash chip on Intel SCB2 boards" - depends on X86 && MTD_JEDECPROBE && PCI - help - Support for treating the BIOS flash chip on Intel SCB2 boards - as an MTD device - with this you can reprogram your BIOS. - - BE VERY CAREFUL. - -config MTD_TSUNAMI - tristate "Flash chips on Tsunami TIG bus" - depends on ALPHA_TSUNAMI && MTD_COMPLEX_MAPPINGS - help - Support for the flash chip on Tsunami TIG bus. - -config MTD_NETtel - tristate "CFI flash device on SnapGear/SecureEdge" - depends on X86 && MTD_JEDECPROBE - help - Support for flash chips on NETtel/SecureEdge/SnapGear boards. - -config MTD_LANTIQ - tristate "Lantiq SoC NOR support" - depends on LANTIQ - help - Support for NOR flash attached to the Lantiq SoC's External Bus Unit. - -config MTD_L440GX - tristate "BIOS flash chip on Intel L440GX boards" - depends on X86 && MTD_JEDECPROBE - help - Support for treating the BIOS flash chip on Intel L440GX motherboards - as an MTD device - with this you can reprogram your BIOS. - - BE VERY CAREFUL. - -config MTD_CFI_FLAGADM - tristate "CFI Flash device mapping on FlagaDM" - depends on PPC_8xx && MTD_CFI - help - Mapping for the Flaga digital module. If you don't have one, ignore - this setting. - -config MTD_SOLUTIONENGINE - tristate "CFI Flash device mapped on Hitachi SolutionEngine" - depends on SOLUTION_ENGINE && MTD_CFI && MTD_REDBOOT_PARTS - help - This enables access to the flash chips on the Hitachi SolutionEngine and - similar boards. Say 'Y' if you are building a kernel for such a board. - -config MTD_SA1100 - tristate "CFI Flash device mapped on StrongARM SA11x0" - depends on MTD_CFI && ARCH_SA1100 - help - This enables access to the flash chips on most platforms based on - the SA1100 and SA1110, including the Assabet and the Compaq iPAQ. - If you have such a board, say 'Y'. - -config MTD_DC21285 - tristate "CFI Flash device mapped on DC21285 Footbridge" - depends on MTD_CFI && ARCH_FOOTBRIDGE && MTD_COMPLEX_MAPPINGS - help - This provides a driver for the flash accessed using Intel's - 21285 bridge used with Intel's StrongARM processors. More info at - . - -config MTD_IXP4XX - tristate "CFI Flash device mapped on Intel IXP4xx based systems" - depends on MTD_CFI && MTD_COMPLEX_MAPPINGS && ARCH_IXP4XX - help - This enables MTD access to flash devices on platforms based - on Intel's IXP4xx family of network processors such as the - IXDP425 and Coyote. If you have an IXP4xx based board and - would like to use the flash chips on it, say 'Y'. - -config MTD_IMPA7 - tristate "JEDEC Flash device mapped on impA7" - depends on ARM && MTD_JEDECPROBE - help - This enables access to the NOR Flash on the impA7 board of - implementa GmbH. If you have such a board, say 'Y' here. - -# This needs CFI or JEDEC, depending on the cards found. -config MTD_PCI - tristate "PCI MTD driver" - depends on PCI && MTD_COMPLEX_MAPPINGS - help - Mapping for accessing flash devices on add-in cards like the Intel XScale - IQ80310 card, and the Intel EBSA285 card in blank ROM programming mode - (please see the manual for the link settings). - - If you are not sure, say N. - -config MTD_PCMCIA - tristate "PCMCIA MTD driver" - depends on PCMCIA && MTD_COMPLEX_MAPPINGS - help - Map driver for accessing PCMCIA linear flash memory cards. These - cards are usually around 4-16MiB in size. This does not include - Compact Flash cards which are treated as IDE devices. - -config MTD_PCMCIA_ANONYMOUS - bool "Use PCMCIA MTD drivers for anonymous PCMCIA cards" - depends on MTD_PCMCIA - help - If this option is enabled, PCMCIA cards which do not report - anything about themselves are assumed to be MTD cards. - - If unsure, say N. - -config MTD_BFIN_ASYNC - tristate "Blackfin BF533-STAMP Flash Chip Support" - depends on BFIN533_STAMP && MTD_CFI && MTD_COMPLEX_MAPPINGS - default y - help - Map driver which allows for simultaneous utilization of - ethernet and CFI parallel flash. - - If compiled as a module, it will be called bfin-async-flash. - -config MTD_GPIO_ADDR - tristate "GPIO-assisted Flash Chip Support" - depends on GPIOLIB || COMPILE_TEST - depends on MTD_COMPLEX_MAPPINGS - help - Map driver which allows flashes to be partially physically addressed - and assisted by GPIOs. - - If compiled as a module, it will be called gpio-addr-flash. - -config MTD_UCLINUX - bool "Generic uClinux RAM/ROM filesystem support" - depends on (MTD_RAM=y || MTD_ROM=y) && (!MMU || COLDFIRE) - help - Map driver to support image based filesystems for uClinux. - -config MTD_INTEL_VR_NOR - tristate "NOR flash on Intel Vermilion Range Expansion Bus CS0" - depends on PCI - help - Map driver for a NOR flash bank located on the Expansion Bus of the - Intel Vermilion Range chipset. - -config MTD_RBTX4939 - tristate "Map driver for RBTX4939 board" - depends on TOSHIBA_RBTX4939 && MTD_CFI && MTD_COMPLEX_MAPPINGS - help - Map driver for NOR flash chips on RBTX4939 board. - -config MTD_PLATRAM - tristate "Map driver for platform device RAM (mtd-ram)" - select MTD_RAM - help - Map driver for RAM areas described via the platform device - system. - - This selection automatically selects the map_ram driver. - -config MTD_VMU - tristate "Map driver for Dreamcast VMU" - depends on MAPLE - help - This driver enables access to the Dreamcast Visual Memory Unit (VMU). - - Most Dreamcast users will want to say Y here. - - To build this as a module select M here, the module will be called - vmu-flash. - -config MTD_PISMO - tristate "MTD discovery driver for PISMO modules" - depends on I2C - depends on ARCH_VERSATILE - help - This driver allows for discovery of PISMO modules - see - . These are small modules containing - up to five memory devices (eg, SRAM, flash, DOC) described by an - I2C EEPROM. - - This driver does not create any MTD maps itself; instead it - creates MTD physmap and MTD SRAM platform devices. If you - enable this option, you should consider enabling MTD_PHYSMAP - and/or MTD_PLATRAM according to the devices on your module. - - When built as a module, it will be called pismo.ko - -config MTD_LATCH_ADDR - tristate "Latch-assisted Flash Chip Support" - depends on MTD_COMPLEX_MAPPINGS - help - Map driver which allows flashes to be partially physically addressed - and have the upper address lines set by a board specific code. - - If compiled as a module, it will be called latch-addr-flash. - -endmenu diff --git a/src/linux/drivers/mtd/nand/Kconfig b/src/linux/drivers/mtd/nand/Kconfig deleted file mode 100644 index 7b7a887..0000000 --- a/src/linux/drivers/mtd/nand/Kconfig +++ /dev/null @@ -1,572 +0,0 @@ -config MTD_NAND_ECC - tristate - -config MTD_NAND_ECC_SMC - bool "NAND ECC Smart Media byte order" - depends on MTD_NAND_ECC - default n - help - Software ECC according to the Smart Media Specification. - The original Linux implementation had byte 0 and 1 swapped. - - -menuconfig MTD_NAND - tristate "NAND Device Support" - depends on MTD - select MTD_NAND_IDS - select MTD_NAND_ECC - help - This enables support for accessing all type of NAND flash - devices. For further information see - . - -if MTD_NAND - -config MTD_NAND_BCH - tristate - select BCH - depends on MTD_NAND_ECC_BCH - default MTD_NAND - -config MTD_NAND_ECC_BCH - bool "Support software BCH ECC" - default n - help - This enables support for software BCH error correction. Binary BCH - codes are more powerful and cpu intensive than traditional Hamming - ECC codes. They are used with NAND devices requiring more than 1 bit - of error correction. - -config MTD_SM_COMMON - tristate - default n - -config MTD_NAND_DENALI - tristate - -config MTD_NAND_DENALI_PCI - tristate "Support Denali NAND controller on Intel Moorestown" - select MTD_NAND_DENALI - depends on HAS_DMA && PCI - help - Enable the driver for NAND flash on Intel Moorestown, using the - Denali NAND controller core. - -config MTD_NAND_DENALI_DT - tristate "Support Denali NAND controller as a DT device" - select MTD_NAND_DENALI - depends on HAS_DMA && HAVE_CLK && OF - help - Enable the driver for NAND flash on platforms using a Denali NAND - controller as a DT device. - -config MTD_NAND_DENALI_SCRATCH_REG_ADDR - hex "Denali NAND size scratch register address" - default "0xFF108018" - depends on MTD_NAND_DENALI_PCI - help - Some platforms place the NAND chip size in a scratch register - because (some versions of) the driver aren't able to automatically - determine the size of certain chips. Set the address of the - scratch register here to enable this feature. On Intel Moorestown - boards, the scratch register is at 0xFF108018. - -config MTD_NAND_GPIO - tristate "GPIO assisted NAND Flash driver" - depends on GPIOLIB || COMPILE_TEST - depends on HAS_IOMEM - help - This enables a NAND flash driver where control signals are - connected to GPIO pins, and commands and data are communicated - via a memory mapped interface. - -config MTD_NAND_AMS_DELTA - tristate "NAND Flash device on Amstrad E3" - depends on MACH_AMS_DELTA - default y - help - Support for NAND flash on Amstrad E3 (Delta). - -config MTD_NAND_OMAP2 - tristate "NAND Flash device on OMAP2, OMAP3, OMAP4 and Keystone" - depends on (ARCH_OMAP2PLUS || ARCH_KEYSTONE) - help - Support for NAND flash on Texas Instruments OMAP2, OMAP3, OMAP4 - and Keystone platforms. - -config MTD_NAND_OMAP_BCH - depends on MTD_NAND_OMAP2 - bool "Support hardware based BCH error correction" - default n - select BCH - help - This config enables the ELM hardware engine, which can be used to - locate and correct errors when using BCH ECC scheme. This offloads - the cpu from doing ECC error searching and correction. However some - legacy OMAP families like OMAP2xxx, OMAP3xxx do not have ELM engine - so this is optional for them. - -config MTD_NAND_OMAP_BCH_BUILD - def_tristate MTD_NAND_OMAP2 && MTD_NAND_OMAP_BCH - -config MTD_NAND_IDS - tristate - -config MTD_NAND_RICOH - tristate "Ricoh xD card reader" - default n - depends on PCI - select MTD_SM_COMMON - help - Enable support for Ricoh R5C852 xD card reader - You also need to enable ether - NAND SSFDC (SmartMedia) read only translation layer' or new - expermental, readwrite - 'SmartMedia/xD new translation layer' - -config MTD_NAND_AU1550 - tristate "Au1550/1200 NAND support" - depends on MIPS_ALCHEMY - help - This enables the driver for the NAND flash controller on the - AMD/Alchemy 1550 SOC. - -config MTD_NAND_BF5XX - tristate "Blackfin on-chip NAND Flash Controller driver" - depends on BF54x || BF52x - help - This enables the Blackfin on-chip NAND flash controller - - No board specific support is done by this driver, each board - must advertise a platform_device for the driver to attach. - - This driver can also be built as a module. If so, the module - will be called bf5xx-nand. - -config MTD_NAND_BF5XX_HWECC - bool "BF5XX NAND Hardware ECC" - default y - depends on MTD_NAND_BF5XX - help - Enable the use of the BF5XX's internal ECC generator when - using NAND. - -config MTD_NAND_BF5XX_BOOTROM_ECC - bool "Use Blackfin BootROM ECC Layout" - default n - depends on MTD_NAND_BF5XX_HWECC - help - If you wish to modify NAND pages and allow the Blackfin on-chip - BootROM to boot from them, say Y here. This is only necessary - if you are booting U-Boot out of NAND and you wish to update - U-Boot from Linux' userspace. Otherwise, you should say N here. - - If unsure, say N. - -config MTD_NAND_S3C2410 - tristate "NAND Flash support for Samsung S3C SoCs" - depends on ARCH_S3C24XX || ARCH_S3C64XX - help - This enables the NAND flash controller on the S3C24xx and S3C64xx - SoCs - - No board specific support is done by this driver, each board - must advertise a platform_device for the driver to attach. - -config MTD_NAND_S3C2410_DEBUG - bool "Samsung S3C NAND driver debug" - depends on MTD_NAND_S3C2410 - help - Enable debugging of the S3C NAND driver - -config MTD_NAND_S3C2410_HWECC - bool "Samsung S3C NAND Hardware ECC" - depends on MTD_NAND_S3C2410 - help - Enable the use of the controller's internal ECC generator when - using NAND. Early versions of the chips have had problems with - incorrect ECC generation, and if using these, the default of - software ECC is preferable. - -config MTD_NAND_NDFC - tristate "NDFC NanD Flash Controller" - depends on 4xx - select MTD_NAND_ECC_SMC - help - NDFC Nand Flash Controllers are integrated in IBM/AMCC's 4xx SoCs - -config MTD_NAND_S3C2410_CLKSTOP - bool "Samsung S3C NAND IDLE clock stop" - depends on MTD_NAND_S3C2410 - default n - help - Stop the clock to the NAND controller when there is no chip - selected to save power. This will mean there is a small delay - when the is NAND chip selected or released, but will save - approximately 5mA of power when there is nothing happening. - -config MTD_NAND_DISKONCHIP - tristate "DiskOnChip 2000, Millennium and Millennium Plus (NAND reimplementation)" - depends on HAS_IOMEM - select REED_SOLOMON - select REED_SOLOMON_DEC16 - help - This is a reimplementation of M-Systems DiskOnChip 2000, - Millennium and Millennium Plus as a standard NAND device driver, - as opposed to the earlier self-contained MTD device drivers. - This should enable, among other things, proper JFFS2 operation on - these devices. - -config MTD_NAND_DISKONCHIP_PROBE_ADVANCED - bool "Advanced detection options for DiskOnChip" - depends on MTD_NAND_DISKONCHIP - help - This option allows you to specify nonstandard address at which to - probe for a DiskOnChip, or to change the detection options. You - are unlikely to need any of this unless you are using LinuxBIOS. - Say 'N'. - -config MTD_NAND_DISKONCHIP_PROBE_ADDRESS - hex "Physical address of DiskOnChip" if MTD_NAND_DISKONCHIP_PROBE_ADVANCED - depends on MTD_NAND_DISKONCHIP - default "0" - ---help--- - By default, the probe for DiskOnChip devices will look for a - DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000. - This option allows you to specify a single address at which to probe - for the device, which is useful if you have other devices in that - range which get upset when they are probed. - - (Note that on PowerPC, the normal probe will only check at - 0xE4000000.) - - Normally, you should leave this set to zero, to allow the probe at - the normal addresses. - -config MTD_NAND_DISKONCHIP_PROBE_HIGH - bool "Probe high addresses" - depends on MTD_NAND_DISKONCHIP_PROBE_ADVANCED - help - By default, the probe for DiskOnChip devices will look for a - DiskOnChip at every multiple of 0x2000 between 0xC8000 and 0xEE000. - This option changes to make it probe between 0xFFFC8000 and - 0xFFFEE000. Unless you are using LinuxBIOS, this is unlikely to be - useful to you. Say 'N'. - -config MTD_NAND_DISKONCHIP_BBTWRITE - bool "Allow BBT writes on DiskOnChip Millennium and 2000TSOP" - depends on MTD_NAND_DISKONCHIP - help - On DiskOnChip devices shipped with the INFTL filesystem (Millennium - and 2000 TSOP/Alon), Linux reserves some space at the end of the - device for the Bad Block Table (BBT). If you have existing INFTL - data on your device (created by non-Linux tools such as M-Systems' - DOS drivers), your data might overlap the area Linux wants to use for - the BBT. If this is a concern for you, leave this option disabled and - Linux will not write BBT data into this area. - The downside of leaving this option disabled is that if bad blocks - are detected by Linux, they will not be recorded in the BBT, which - could cause future problems. - Once you enable this option, new filesystems (INFTL or others, created - in Linux or other operating systems) will not use the reserved area. - The only reason not to enable this option is to prevent damage to - preexisting filesystems. - Even if you leave this disabled, you can enable BBT writes at module - load time (assuming you build diskonchip as a module) with the module - parameter "inftl_bbt_write=1". - -config MTD_NAND_DOCG4 - tristate "Support for DiskOnChip G4" - depends on HAS_IOMEM - select BCH - select BITREVERSE - help - Support for diskonchip G4 nand flash, found in various smartphones and - PDAs, among them the Palm Treo680, HTC Prophet and Wizard, Toshiba - Portege G900, Asus P526, and O2 XDA Zinc. - - With this driver you will be able to use UBI and create a ubifs on the - device, so you may wish to consider enabling UBI and UBIFS as well. - - These devices ship with the Mys/Sandisk SAFTL formatting, for which - there is currently no mtd parser, so you may want to use command line - partitioning to segregate write-protected blocks. On the Treo680, the - first five erase blocks (256KiB each) are write-protected, followed - by the block containing the saftl partition table. This is probably - typical. - -config MTD_NAND_SHARPSL - tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)" - depends on ARCH_PXA - -config MTD_NAND_CAFE - tristate "NAND support for OLPC CAFÉ chip" - depends on PCI - select REED_SOLOMON - select REED_SOLOMON_DEC16 - help - Use NAND flash attached to the CAFÉ chip designed for the OLPC - laptop. - -config MTD_NAND_CS553X - tristate "NAND support for CS5535/CS5536 (AMD Geode companion chip)" - depends on X86_32 - depends on !UML && HAS_IOMEM - help - The CS553x companion chips for the AMD Geode processor - include NAND flash controllers with built-in hardware ECC - capabilities; enabling this option will allow you to use - these. The driver will check the MSRs to verify that the - controller is enabled for NAND, and currently requires that - the controller be in MMIO mode. - - If you say "m", the module will be called cs553x_nand. - -config MTD_NAND_ATMEL - tristate "Support for NAND Flash / SmartMedia on AT91 and AVR32" - depends on ARCH_AT91 || AVR32 - help - Enables support for NAND Flash / Smart Media Card interface - on Atmel AT91 and AVR32 processors. - -config MTD_NAND_PXA3xx - tristate "NAND support on PXA3xx and Armada 370/XP" - depends on PXA3xx || ARCH_MMP || PLAT_ORION - help - This enables the driver for the NAND flash device found on - PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2). - -config MTD_NAND_SLC_LPC32XX - tristate "NXP LPC32xx SLC Controller" - depends on ARCH_LPC32XX - help - Enables support for NXP's LPC32XX SLC (i.e. for Single Level Cell - chips) NAND controller. This is the default for the PHYTEC 3250 - reference board which contains a NAND256R3A2CZA6 chip. - - Please check the actual NAND chip connected and its support - by the SLC NAND controller. - -config MTD_NAND_MLC_LPC32XX - tristate "NXP LPC32xx MLC Controller" - depends on ARCH_LPC32XX - help - Uses the LPC32XX MLC (i.e. for Multi Level Cell chips) NAND - controller. This is the default for the WORK92105 controller - board. - - Please check the actual NAND chip connected and its support - by the MLC NAND controller. - -config MTD_NAND_CM_X270 - tristate "Support for NAND Flash on CM-X270 modules" - depends on MACH_ARMCORE - -config MTD_NAND_PASEMI - tristate "NAND support for PA Semi PWRficient" - depends on PPC_PASEMI - help - Enables support for NAND Flash interface on PA Semi PWRficient - based boards - -config MTD_NAND_TMIO - tristate "NAND Flash device on Toshiba Mobile IO Controller" - depends on MFD_TMIO - help - Support for NAND flash connected to a Toshiba Mobile IO - Controller in some PDAs, including the Sharp SL6000x. - -config MTD_NAND_NANDSIM - tristate "Support for NAND Flash Simulator" - help - The simulator may simulate various NAND flash chips for the - MTD nand layer. - -config MTD_NAND_GPMI_NAND - tristate "GPMI NAND Flash Controller driver" - depends on MTD_NAND && MXS_DMA - help - Enables NAND Flash support for IMX23, IMX28 or IMX6. - The GPMI controller is very powerful, with the help of BCH - module, it can do the hardware ECC. The GPMI supports several - NAND flashs at the same time. The GPMI may conflicts with other - block, such as SD card. So pay attention to it when you enable - the GPMI. - -config MTD_NAND_BRCMNAND - tristate "Broadcom STB NAND controller" - depends on ARM || ARM64 || MIPS - help - Enables the Broadcom NAND controller driver. The controller was - originally designed for Set-Top Box but is used on various BCM7xxx, - BCM3xxx, BCM63xxx, iProc/Cygnus and more. - -config MTD_NAND_BCM47XXNFLASH - tristate "Support for NAND flash on BCM4706 BCMA bus" - depends on BCMA_NFLASH - help - BCMA bus can have various flash memories attached, they are - registered by bcma as platform devices. This enables driver for - NAND flash memories. For now only BCM4706 is supported. - -config MTD_NAND_PLATFORM - tristate "Support for generic platform NAND driver" - depends on HAS_IOMEM - help - This implements a generic NAND driver for on-SOC platform - devices. You will need to provide platform-specific functions - via platform_data. - -config MTD_NAND_ORION - tristate "NAND Flash support for Marvell Orion SoC" - depends on PLAT_ORION - help - This enables the NAND flash controller on Orion machines. - - No board specific support is done by this driver, each board - must advertise a platform_device for the driver to attach. - -config MTD_NAND_FSL_ELBC - tristate "NAND support for Freescale eLBC controllers" - depends on FSL_SOC - select FSL_LBC - help - Various Freescale chips, including the 8313, include a NAND Flash - Controller Module with built-in hardware ECC capabilities. - Enabling this option will enable you to use this to control - external NAND devices. - -config MTD_NAND_FSL_IFC - tristate "NAND support for Freescale IFC controller" - depends on FSL_SOC || ARCH_LAYERSCAPE - select FSL_IFC - select MEMORY - help - Various Freescale chips e.g P1010, include a NAND Flash machine - with built-in hardware ECC capabilities. - Enabling this option will enable you to use this to control - external NAND devices. - -config MTD_NAND_FSL_UPM - tristate "Support for NAND on Freescale UPM" - depends on PPC_83xx || PPC_85xx - select FSL_LBC - help - Enables support for NAND Flash chips wired onto Freescale PowerPC - processor localbus with User-Programmable Machine support. - -config MTD_NAND_MPC5121_NFC - tristate "MPC5121 built-in NAND Flash Controller support" - depends on PPC_MPC512x - help - This enables the driver for the NAND flash controller on the - MPC5121 SoC. - -config MTD_NAND_VF610_NFC - tristate "Support for Freescale NFC for VF610/MPC5125" - depends on (SOC_VF610 || COMPILE_TEST) - depends on HAS_IOMEM - help - Enables support for NAND Flash Controller on some Freescale - processors like the VF610, MPC5125, MCF54418 or Kinetis K70. - The driver supports a maximum 2k page size. With 2k pages and - 64 bytes or more of OOB, hardware ECC with up to 32-bit error - correction is supported. Hardware ECC is only enabled through - device tree. - -config MTD_NAND_MXC - tristate "MXC NAND support" - depends on ARCH_MXC - help - This enables the driver for the NAND flash controller on the - MXC processors. - -config MTD_NAND_SH_FLCTL - tristate "Support for NAND on Renesas SuperH FLCTL" - depends on SUPERH || COMPILE_TEST - depends on HAS_IOMEM - depends on HAS_DMA - help - Several Renesas SuperH CPU has FLCTL. This option enables support - for NAND Flash using FLCTL. - -config MTD_NAND_DAVINCI - tristate "Support NAND on DaVinci/Keystone SoC" - depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF) - help - Enable the driver for NAND flash chips on Texas Instruments - DaVinci/Keystone processors. - -config MTD_NAND_TXX9NDFMC - tristate "NAND Flash support for TXx9 SoC" - depends on SOC_TX4938 || SOC_TX4939 - help - This enables the NAND flash controller on the TXx9 SoCs. - -config MTD_NAND_SOCRATES - tristate "Support for NAND on Socrates board" - depends on SOCRATES - help - Enables support for NAND Flash chips wired onto Socrates board. - -config MTD_NAND_NUC900 - tristate "Support for NAND on Nuvoton NUC9xx/w90p910 evaluation boards." - depends on ARCH_W90X900 - help - This enables the driver for the NAND Flash on evaluation board based - on w90p910 / NUC9xx. - -config MTD_NAND_JZ4740 - tristate "Support for JZ4740 SoC NAND controller" - depends on MACH_JZ4740 - help - Enables support for NAND Flash on JZ4740 SoC based boards. - -config MTD_NAND_JZ4780 - tristate "Support for NAND on JZ4780 SoC" - depends on MACH_JZ4780 && JZ4780_NEMC - help - Enables support for NAND Flash connected to the NEMC on JZ4780 SoC - based boards, using the BCH controller for hardware error correction. - -config MTD_NAND_FSMC - tristate "Support for NAND on ST Micros FSMC" - depends on PLAT_SPEAR || ARCH_NOMADIK || ARCH_U8500 || MACH_U300 - help - Enables support for NAND Flash chips on the ST Microelectronics - Flexible Static Memory Controller (FSMC) - -config MTD_NAND_XWAY - tristate "Support for NAND on Lantiq XWAY SoC" - depends on LANTIQ && SOC_TYPE_XWAY - help - Enables support for NAND Flash chips on Lantiq XWAY SoCs. NAND is attached - to the External Bus Unit (EBU). - -config MTD_NAND_SUNXI - tristate "Support for NAND on Allwinner SoCs" - depends on ARCH_SUNXI - help - Enables support for NAND Flash chips on Allwinner SoCs. - -config MTD_NAND_HISI504 - tristate "Support for NAND controller on Hisilicon SoC Hip04" - depends on HAS_DMA - help - Enables support for NAND controller on Hisilicon SoC Hip04. - -config MTD_NAND_QCOM - tristate "Support for NAND on QCOM SoCs" - depends on ARCH_QCOM - help - Enables support for NAND flash chips on SoCs containing the EBI2 NAND - controller. This controller is found on IPQ806x SoC. - -config MTD_NAND_MTK - tristate "Support for NAND controller on MTK SoCs" - depends on HAS_DMA - help - Enables support for NAND controller on MTK SoCs. - This controller is found on mt27xx, mt81xx, mt65xx SoCs. - -endif # MTD_NAND diff --git a/src/linux/drivers/mtd/onenand/Kconfig b/src/linux/drivers/mtd/onenand/Kconfig deleted file mode 100644 index dcae2f6..0000000 --- a/src/linux/drivers/mtd/onenand/Kconfig +++ /dev/null @@ -1,70 +0,0 @@ -menuconfig MTD_ONENAND - tristate "OneNAND Device Support" - depends on MTD - depends on HAS_IOMEM - help - This enables support for accessing all type of OneNAND flash - devices. For further information see - - -if MTD_ONENAND - -config MTD_ONENAND_VERIFY_WRITE - bool "Verify OneNAND page writes" - help - This adds an extra check when data is written to the flash. The - OneNAND flash device internally checks only bits transitioning - from 1 to 0. There is a rare possibility that even though the - device thinks the write was successful, a bit could have been - flipped accidentally due to device wear or something else. - -config MTD_ONENAND_GENERIC - tristate "OneNAND Flash device via platform device driver" - help - Support for OneNAND flash via platform device driver. - -config MTD_ONENAND_OMAP2 - tristate "OneNAND on OMAP2/OMAP3 support" - depends on ARCH_OMAP2 || ARCH_OMAP3 - help - Support for a OneNAND flash device connected to an OMAP2/OMAP3 CPU - via the GPMC memory controller. - -config MTD_ONENAND_SAMSUNG - tristate "OneNAND on Samsung SOC controller support" - depends on ARCH_S3C64XX || ARCH_S5PV210 || ARCH_EXYNOS4 - help - Support for a OneNAND flash device connected to an Samsung SOC. - S3C64XX uses command mapping method. - S5PC110/S5PC210 use generic OneNAND method. - -config MTD_ONENAND_OTP - bool "OneNAND OTP Support" - help - One Block of the NAND Flash Array memory is reserved as - a One-Time Programmable Block memory area. - Also, 1st Block of NAND Flash Array can be used as OTP. - - The OTP block can be read, programmed and locked using the same - operations as any other NAND Flash Array memory block. - OTP block cannot be erased. - - OTP block is fully-guaranteed to be a valid block. - -config MTD_ONENAND_2X_PROGRAM - bool "OneNAND 2X program support" - help - The 2X Program is an extension of Program Operation. - Since the device is equipped with two DataRAMs, and two-plane NAND - Flash memory array, these two component enables simultaneous program - of 4KiB. Plane1 has only even blocks such as block0, block2, block4 - while Plane2 has only odd blocks such as block1, block3, block5. - So MTD regards it as 4KiB page size and 256KiB block size - - Now the following chips support it. (KFXXX16Q2M) - Demux: KFG2G16Q2M, KFH4G16Q2M, KFW8G16Q2M, - Mux: KFM2G16Q2M, KFN4G16Q2M, - - And more recent chips - -endif # MTD_ONENAND diff --git a/src/linux/drivers/mtd/spi-nor/Kconfig b/src/linux/drivers/mtd/spi-nor/Kconfig deleted file mode 100644 index 4a682ee..0000000 --- a/src/linux/drivers/mtd/spi-nor/Kconfig +++ /dev/null @@ -1,79 +0,0 @@ -menuconfig MTD_SPI_NOR - tristate "SPI-NOR device support" - depends on MTD - help - This is the framework for the SPI NOR which can be used by the SPI - device drivers and the SPI-NOR device driver. - -if MTD_SPI_NOR - -config MTD_MT81xx_NOR - tristate "Mediatek MT81xx SPI NOR flash controller" - depends on HAS_IOMEM - help - This enables access to SPI NOR flash, using MT81xx SPI NOR flash - controller. This controller does not support generic SPI BUS, it only - supports SPI NOR Flash. - -config MTD_SPI_NOR_USE_4K_SECTORS - bool "Use small 4096 B erase sectors" - default y - help - Many flash memories support erasing small (4096 B) sectors. Depending - on the usage this feature may provide performance gain in comparison - to erasing whole blocks (32/64 KiB). - Changing a small part of the flash's contents is usually faster with - small sectors. On the other hand erasing should be faster when using - 64 KiB block instead of 16 × 4 KiB sectors. - - Please note that some tools/drivers/filesystems may not work with - 4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum). - -config SPI_ATMEL_QUADSPI - tristate "Atmel Quad SPI Controller" - depends on ARCH_AT91 || (ARM && COMPILE_TEST) - depends on OF && HAS_IOMEM - help - This enables support for the Quad SPI controller in master mode. - This driver does not support generic SPI. The implementation only - supports SPI NOR. - -config SPI_CADENCE_QUADSPI - tristate "Cadence Quad SPI controller" - depends on OF && ARM - help - Enable support for the Cadence Quad SPI Flash controller. - - Cadence QSPI is a specialized controller for connecting an SPI - Flash over 1/2/4-bit wide bus. Enable this option if you have a - device with a Cadence QSPI controller and want to access the - Flash as an MTD device. - -config SPI_FSL_QUADSPI - tristate "Freescale Quad SPI controller" - depends on ARCH_MXC || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST - depends on HAS_IOMEM - help - This enables support for the Quad SPI controller in master mode. - This controller does not support generic SPI. It only supports - SPI NOR. - -config SPI_HISI_SFC - tristate "Hisilicon SPI-NOR Flash Controller(SFC)" - depends on ARCH_HISI || COMPILE_TEST - depends on HAS_IOMEM && HAS_DMA - help - This enables support for hisilicon SPI-NOR flash controller. - -config SPI_NXP_SPIFI - tristate "NXP SPI Flash Interface (SPIFI)" - depends on OF && (ARCH_LPC18XX || COMPILE_TEST) - depends on HAS_IOMEM - help - Enable support for the NXP LPC SPI Flash Interface controller. - - SPIFI is a specialized controller for connecting serial SPI - Flash. Enable this option if you have a device with a SPIFI - controller and want to access the Flash as a mtd device. - -endif # MTD_SPI_NOR diff --git a/src/linux/drivers/mtd/ubi/Kconfig b/src/linux/drivers/mtd/ubi/Kconfig deleted file mode 100644 index f0855ce..0000000 --- a/src/linux/drivers/mtd/ubi/Kconfig +++ /dev/null @@ -1,106 +0,0 @@ -menuconfig MTD_UBI - tristate "Enable UBI - Unsorted block images" - select CRC32 - help - UBI is a software layer above MTD layer which admits of LVM-like - logical volumes on top of MTD devices, hides some complexities of - flash chips like wear and bad blocks and provides some other useful - capabilities. Please, consult the MTD web site for more details - (www.linux-mtd.infradead.org). - -if MTD_UBI - -config MTD_UBI_WL_THRESHOLD - int "UBI wear-leveling threshold" - default 4096 - range 2 65536 - help - This parameter defines the maximum difference between the highest - erase counter value and the lowest erase counter value of eraseblocks - of UBI devices. When this threshold is exceeded, UBI starts performing - wear leveling by means of moving data from eraseblock with low erase - counter to eraseblocks with high erase counter. - - The default value should be OK for SLC NAND flashes, NOR flashes and - other flashes which have eraseblock life-cycle 100000 or more. - However, in case of MLC NAND flashes which typically have eraseblock - life-cycle less than 10000, the threshold should be lessened (e.g., - to 128 or 256, although it does not have to be power of 2). - -config MTD_UBI_BEB_LIMIT - int "Maximum expected bad eraseblock count per 1024 eraseblocks" - default 20 - range 0 768 - help - This option specifies the maximum bad physical eraseblocks UBI - expects on the MTD device (per 1024 eraseblocks). If the underlying - flash does not admit of bad eraseblocks (e.g. NOR flash), this value - is ignored. - - NAND datasheets often specify the minimum and maximum NVM (Number of - Valid Blocks) for the flashes' endurance lifetime. The maximum - expected bad eraseblocks per 1024 eraseblocks then can be calculated - as "1024 * (1 - MinNVB / MaxNVB)", which gives 20 for most NANDs - (MaxNVB is basically the total count of eraseblocks on the chip). - - To put it differently, if this value is 20, UBI will try to reserve - about 1.9% of physical eraseblocks for bad blocks handling. And that - will be 1.9% of eraseblocks on the entire NAND chip, not just the MTD - partition UBI attaches. This means that if you have, say, a NAND - flash chip admits maximum 40 bad eraseblocks, and it is split on two - MTD partitions of the same size, UBI will reserve 40 eraseblocks when - attaching a partition. - - This option can be overridden by the "mtd=" UBI module parameter or - by the "attach" ioctl. - - Leave the default value if unsure. - -config MTD_UBI_FASTMAP - bool "UBI Fastmap (Experimental feature)" - default n - help - Important: this feature is experimental so far and the on-flash - format for fastmap may change in the next kernel versions - - Fastmap is a mechanism which allows attaching an UBI device - in nearly constant time. Instead of scanning the whole MTD device it - only has to locate a checkpoint (called fastmap) on the device. - The on-flash fastmap contains all information needed to attach - the device. Using fastmap makes only sense on large devices where - attaching by scanning takes long. UBI will not automatically install - a fastmap on old images, but you can set the UBI module parameter - fm_autoconvert to 1 if you want so. Please note that fastmap-enabled - images are still usable with UBI implementations without - fastmap support. On typical flash devices the whole fastmap fits - into one PEB. UBI will reserve PEBs to hold two fastmaps. - - If in doubt, say "N". - -config MTD_UBI_GLUEBI - tristate "MTD devices emulation driver (gluebi)" - help - This option enables gluebi - an additional driver which emulates MTD - devices on top of UBI volumes: for each UBI volumes an MTD device is - created, and all I/O to this MTD device is redirected to the UBI - volume. This is handy to make MTD-oriented software (like JFFS2) - work on top of UBI. Do not enable this unless you use legacy - software. - -config MTD_UBI_BLOCK - bool "Read-only block devices on top of UBI volumes" - default n - depends on BLOCK - help - This option enables read-only UBI block devices support. UBI block - devices will be layered on top of UBI volumes, which means that the - UBI driver will transparently handle things like bad eraseblocks and - bit-flips. You can put any block-oriented file system on top of UBI - volumes in read-only mode (e.g., ext4), but it is probably most - practical for read-only file systems, like squashfs. - - When selected, this feature will be built in the UBI driver. - - If in doubt, say "N". - -endif # MTD_UBI diff --git a/src/linux/drivers/net/Kconfig b/src/linux/drivers/net/Kconfig deleted file mode 100644 index 95c32f2..0000000 --- a/src/linux/drivers/net/Kconfig +++ /dev/null @@ -1,454 +0,0 @@ -# -# Network device configuration -# - -menuconfig NETDEVICES - default y if UML - depends on NET - bool "Network device support" - ---help--- - You can say N here if you don't intend to connect your Linux box to - any other computer at all. - - You'll have to say Y if your computer contains a network card that - you want to use under Linux. If you are going to run SLIP or PPP over - telephone line or null modem cable you need say Y here. Connecting - two machines with parallel ports using PLIP needs this, as well as - AX.25/KISS for sending Internet traffic over amateur radio links. - - See also "The Linux Network Administrator's Guide" by Olaf Kirch and - Terry Dawson. Available at . - - If unsure, say Y. - -# All the following symbols are dependent on NETDEVICES - do not repeat -# that for each of the symbols. -if NETDEVICES - -config MII - tristate - -config NET_CORE - default y - bool "Network core driver support" - ---help--- - You can say N here if you do not intend to use any of the - networking core drivers (i.e. VLAN, bridging, bonding, etc.) - -if NET_CORE - -config BONDING - tristate "Bonding driver support" - depends on INET - depends on IPV6 || IPV6=n - ---help--- - Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet - Channels together. This is called 'Etherchannel' by Cisco, - 'Trunking' by Sun, 802.3ad by the IEEE, and 'Bonding' in Linux. - - The driver supports multiple bonding modes to allow for both high - performance and high availability operation. - - Refer to for more - information. - - To compile this driver as a module, choose M here: the module - will be called bonding. - -config DUMMY - tristate "Dummy net driver support" - ---help--- - This is essentially a bit-bucket device (i.e. traffic you send to - this device is consigned into oblivion) with a configurable IP - address. It is most commonly used in order to make your currently - inactive SLIP address seem like a real address for local programs. - If you use SLIP or PPP, you might want to say Y here. It won't - enlarge your kernel. What a deal. Read about it in the Network - Administrator's Guide, available from - . - - To compile this driver as a module, choose M here: the module - will be called dummy. - -config EQUALIZER - tristate "EQL (serial line load balancing) support" - ---help--- - If you have two serial connections to some other computer (this - usually requires two modems and two telephone lines) and you use - SLIP (the protocol for sending Internet traffic over telephone - lines) or PPP (a better SLIP) on them, you can make them behave like - one double speed connection using this driver. Naturally, this has - to be supported at the other end as well, either with a similar EQL - Linux driver or with a Livingston Portmaster 2e. - - Say Y if you want this and read - . You may also want to read - section 6.2 of the NET-3-HOWTO, available from - . - - To compile this driver as a module, choose M here: the module - will be called eql. If unsure, say N. - -config NET_FC - bool "Fibre Channel driver support" - depends on SCSI && PCI - help - Fibre Channel is a high speed serial protocol mainly used to connect - large storage devices to the computer; it is compatible with and - intended to replace SCSI. - - If you intend to use Fibre Channel, you need to have a Fibre channel - adaptor card in your computer; say Y here and to the driver for your - adaptor below. You also should have said Y to "SCSI support" and - "SCSI generic support". - -config IFB - tristate "Intermediate Functional Block support" - depends on NET_CLS_ACT - ---help--- - This is an intermediate driver that allows sharing of - resources. - To compile this driver as a module, choose M here: the module - will be called ifb. If you want to use more than one ifb - device at a time, you need to compile this driver as a module. - Instead of 'ifb', the devices will then be called 'ifb0', - 'ifb1' etc. - Look at the iproute2 documentation directory for usage etc - -source "drivers/net/team/Kconfig" - -config MACVLAN - tristate "MAC-VLAN support" - ---help--- - This allows one to create virtual interfaces that map packets to - or from specific MAC addresses to a particular interface. - - Macvlan devices can be added using the "ip" command from the - iproute2 package starting with the iproute2-2.6.23 release: - - "ip link add link [ address MAC ] [ NAME ] type macvlan" - - To compile this driver as a module, choose M here: the module - will be called macvlan. - -config MACVTAP - tristate "MAC-VLAN based tap driver" - depends on MACVLAN - depends on INET - help - This adds a specialized tap character device driver that is based - on the MAC-VLAN network interface, called macvtap. A macvtap device - can be added in the same way as a macvlan device, using 'type - macvtap', and then be accessed through the tap user space interface. - - To compile this driver as a module, choose M here: the module - will be called macvtap. - - -config IPVLAN - tristate "IP-VLAN support" - depends on INET - depends on IPV6 - depends on NETFILTER - depends on NET_L3_MASTER_DEV - ---help--- - This allows one to create virtual devices off of a main interface - and packets will be delivered based on the dest L3 (IPv6/IPv4 addr) - on packets. All interfaces (including the main interface) share L2 - making it transparent to the connected L2 switch. - - Ipvlan devices can be added using the "ip" command from the - iproute2 package starting with the iproute2-3.19 release: - - "ip link add link [ NAME ] type ipvlan" - - To compile this driver as a module, choose M here: the module - will be called ipvlan. - - -config VXLAN - tristate "Virtual eXtensible Local Area Network (VXLAN)" - depends on INET - select NET_UDP_TUNNEL - ---help--- - This allows one to create vxlan virtual interfaces that provide - Layer 2 Networks over Layer 3 Networks. VXLAN is often used - to tunnel virtual network infrastructure in virtualized environments. - For more information see: - http://tools.ietf.org/html/draft-mahalingam-dutt-dcops-vxlan-02 - - To compile this driver as a module, choose M here: the module - will be called vxlan. - -config GENEVE - tristate "Generic Network Virtualization Encapsulation" - depends on INET && NET_UDP_TUNNEL - select NET_IP_TUNNEL - ---help--- - This allows one to create geneve virtual interfaces that provide - Layer 2 Networks over Layer 3 Networks. GENEVE is often used - to tunnel virtual network infrastructure in virtualized environments. - For more information see: - http://tools.ietf.org/html/draft-gross-geneve-02 - - To compile this driver as a module, choose M here: the module - will be called geneve. - -config GTP - tristate "GPRS Tunneling Protocol datapath (GTP-U)" - depends on INET && NET_UDP_TUNNEL - select NET_IP_TUNNEL - ---help--- - This allows one to create gtp virtual interfaces that provide - the GPRS Tunneling Protocol datapath (GTP-U). This tunneling protocol - is used to prevent subscribers from accessing mobile carrier core - network infrastructure. This driver requires a userspace software that - implements the signaling protocol (GTP-C) to update its PDP context - base, such as OpenGGSN for details. - -config NETCONSOLE_DYNAMIC - bool "Dynamic reconfiguration of logging targets" - depends on NETCONSOLE && SYSFS && CONFIGFS_FS && \ - !(NETCONSOLE=y && CONFIGFS_FS=m) - help - This option enables the ability to dynamically reconfigure target - parameters (interface, IP addresses, port numbers, MAC addresses) - at runtime through a userspace interface exported using configfs. - See for details. - -config NETPOLL - def_bool NETCONSOLE - select SRCU - -config NET_POLL_CONTROLLER - def_bool NETPOLL - -config NTB_NETDEV - tristate "Virtual Ethernet over NTB Transport" - depends on NTB_TRANSPORT - -config RIONET - tristate "RapidIO Ethernet over messaging driver support" - depends on RAPIDIO - -config RIONET_TX_SIZE - int "Number of outbound queue entries" - depends on RIONET - default "128" - -config RIONET_RX_SIZE - int "Number of inbound queue entries" - depends on RIONET - default "128" - -config TUN - tristate "Universal TUN/TAP device driver support" - depends on INET - select CRC32 - ---help--- - TUN/TAP provides packet reception and transmission for user space - programs. It can be viewed as a simple Point-to-Point or Ethernet - device, which instead of receiving packets from a physical media, - receives them from user space program and instead of sending packets - via physical media writes them to the user space program. - - When a program opens /dev/net/tun, driver creates and registers - corresponding net device tunX or tapX. After a program closed above - devices, driver will automatically delete tunXX or tapXX device and - all routes corresponding to it. - - Please read for more - information. - - To compile this driver as a module, choose M here: the module - will be called tun. - - If you don't know what to use this for, you don't need it. - -config TUN_VNET_CROSS_LE - bool "Support for cross-endian vnet headers on little-endian kernels" - default n - ---help--- - This option allows TUN/TAP and MACVTAP device drivers in a - little-endian kernel to parse vnet headers that come from a - big-endian legacy virtio device. - - Userspace programs can control the feature using the TUNSETVNETBE - and TUNGETVNETBE ioctls. - - Unless you have a little-endian system hosting a big-endian virtual - machine with a legacy virtio NIC, you should say N. - -config VETH - tristate "Virtual ethernet pair device" - ---help--- - This device is a local ethernet tunnel. Devices are created in pairs. - When one end receives the packet it appears on its pair and vice - versa. - -config VIRTIO_NET - tristate "Virtio network driver" - depends on VIRTIO - ---help--- - This is the virtual network driver for virtio. It can be used with - lguest or QEMU based VMMs (like KVM or Xen). Say Y or M. - -config NLMON - tristate "Virtual netlink monitoring device" - ---help--- - This option enables a monitoring net device for netlink skbs. The - purpose of this is to analyze netlink messages with packet sockets. - Thus applications like tcpdump will be able to see local netlink - messages if they tap into the netlink device, record pcaps for further - diagnostics, etc. This is mostly intended for developers or support - to debug netlink issues. If unsure, say N. - -config NET_VRF - tristate "Virtual Routing and Forwarding (Lite)" - depends on IP_MULTIPLE_TABLES - depends on NET_L3_MASTER_DEV - depends on IPV6 || IPV6=n - depends on IPV6_MULTIPLE_TABLES || IPV6=n - ---help--- - This option enables the support for mapping interfaces into VRF's. The - support enables VRF devices. - -endif # NET_CORE - -config SUNGEM_PHY - tristate - -source "drivers/net/arcnet/Kconfig" - -source "drivers/atm/Kconfig" - -source "drivers/net/caif/Kconfig" - -source "drivers/net/dsa/Kconfig" - -source "drivers/net/ethernet/Kconfig" - -source "drivers/net/fddi/Kconfig" - -source "drivers/net/hippi/Kconfig" - -config NET_SB1000 - tristate "General Instruments Surfboard 1000" - depends on PNP - ---help--- - This is a driver for the General Instrument (also known as - NextLevel) SURFboard 1000 internal - cable modem. This is an ISA card which is used by a number of cable - TV companies to provide cable modem access. It's a one-way - downstream-only cable modem, meaning that your upstream net link is - provided by your regular phone modem. - - At present this driver only compiles as a module, so say M here if - you have this card. The module will be called sb1000. Then read - for information on how - to use this module, as it needs special ppp scripts for establishing - a connection. Further documentation and the necessary scripts can be - found at: - - - - - - If you don't have this card, of course say N. - -source "drivers/net/phy/Kconfig" - -source "drivers/net/plip/Kconfig" - -source "drivers/net/ppp/Kconfig" - -source "drivers/net/slip/Kconfig" - -source "drivers/s390/net/Kconfig" - -source "drivers/net/usb/Kconfig" - -source "drivers/net/wireless/Kconfig" - -source "drivers/net/wimax/Kconfig" - -source "drivers/net/wan/Kconfig" - -source "drivers/net/ieee802154/Kconfig" - -config XEN_NETDEV_FRONTEND - tristate "Xen network device frontend driver" - depends on XEN - select XEN_XENBUS_FRONTEND - default y - help - This driver provides support for Xen paravirtual network - devices exported by a Xen network driver domain (often - domain 0). - - The corresponding Linux backend driver is enabled by the - CONFIG_XEN_NETDEV_BACKEND option. - - If you are compiling a kernel for use as Xen guest, you - should say Y here. To compile this driver as a module, chose - M here: the module will be called xen-netfront. - -config XEN_NETDEV_BACKEND - tristate "Xen backend network device" - depends on XEN_BACKEND - help - This driver allows the kernel to act as a Xen network driver - domain which exports paravirtual network devices to other - Xen domains. These devices can be accessed by any operating - system that implements a compatible front end. - - The corresponding Linux frontend driver is enabled by the - CONFIG_XEN_NETDEV_FRONTEND configuration option. - - The backend driver presents a standard network device - endpoint for each paravirtual network device to the driver - domain network stack. These can then be bridged or routed - etc in order to provide full network connectivity. - - If you are compiling a kernel to run in a Xen network driver - domain (often this is domain 0) you should say Y here. To - compile this driver as a module, chose M here: the module - will be called xen-netback. - -config VMXNET3 - tristate "VMware VMXNET3 ethernet driver" - depends on PCI && INET - help - This driver supports VMware's vmxnet3 virtual ethernet NIC. - To compile this driver as a module, choose M here: the - module will be called vmxnet3. - -config FUJITSU_ES - tristate "FUJITSU Extended Socket Network Device driver" - depends on ACPI - help - This driver provides support for Extended Socket network device - on Extended Partitioning of FUJITSU PRIMEQUEST 2000 E2 series. - -source "drivers/net/hyperv/Kconfig" - -endif # NETDEVICES diff --git a/src/linux/drivers/net/Makefile b/src/linux/drivers/net/Makefile deleted file mode 100644 index 7336cbd..0000000 --- a/src/linux/drivers/net/Makefile +++ /dev/null @@ -1,74 +0,0 @@ -# -# Makefile for the Linux network device drivers. -# - -# -# Networking Core Drivers -# -obj-$(CONFIG_BONDING) += bonding/ -obj-$(CONFIG_IPVLAN) += ipvlan/ -obj-$(CONFIG_DUMMY) += dummy.o -obj-$(CONFIG_EQUALIZER) += eql.o -obj-$(CONFIG_IFB) += ifb.o -obj-$(CONFIG_MACSEC) += macsec.o -obj-$(CONFIG_MACVLAN) += macvlan.o -obj-$(CONFIG_MACVTAP) += macvtap.o -obj-$(CONFIG_MII) += mii.o -obj-$(CONFIG_MDIO) += mdio.o -obj-$(CONFIG_NET) += Space.o loopback.o -obj-$(CONFIG_NETCONSOLE) += netconsole.o -obj-$(CONFIG_PHYLIB) += phy/ -obj-$(CONFIG_RIONET) += rionet.o -obj-$(CONFIG_NET_TEAM) += team/ -obj-$(CONFIG_TUN) += tun.o -obj-$(CONFIG_VETH) += veth.o -obj-$(CONFIG_VIRTIO_NET) += virtio_net.o -obj-$(CONFIG_VXLAN) += vxlan.o -obj-$(CONFIG_GENEVE) += geneve.o -obj-$(CONFIG_GTP) += gtp.o -obj-$(CONFIG_NLMON) += nlmon.o -obj-$(CONFIG_NET_VRF) += vrf.o - -# -# Networking Drivers -# -obj-$(CONFIG_ARCNET) += arcnet/ -obj-$(CONFIG_DEV_APPLETALK) += appletalk/ -obj-$(CONFIG_CAIF) += caif/ -obj-$(CONFIG_CAN) += can/ -obj-$(CONFIG_ETRAX_ETHERNET) += cris/ -obj-$(CONFIG_NET_DSA) += dsa/ -obj-$(CONFIG_ETHERNET) += ethernet/ -obj-$(CONFIG_FDDI) += fddi/ -obj-$(CONFIG_HIPPI) += hippi/ -obj-$(CONFIG_HAMRADIO) += hamradio/ -obj-$(CONFIG_IRDA) += irda/ -obj-$(CONFIG_PLIP) += plip/ -obj-$(CONFIG_PPP) += ppp/ -obj-$(CONFIG_PPP_ASYNC) += ppp/ -obj-$(CONFIG_PPP_BSDCOMP) += ppp/ -obj-$(CONFIG_PPP_DEFLATE) += ppp/ -obj-$(CONFIG_PPP_MPPE) += ppp/ -obj-$(CONFIG_PPP_SYNC_TTY) += ppp/ -obj-$(CONFIG_PPPOE) += ppp/ -obj-$(CONFIG_PPPOL2TP) += ppp/ -obj-$(CONFIG_PPTP) += ppp/ -obj-$(CONFIG_SLIP) += slip/ -obj-$(CONFIG_SLHC) += slip/ -obj-$(CONFIG_NET_SB1000) += sb1000.o -obj-$(CONFIG_SUNGEM_PHY) += sungem_phy.o -obj-$(CONFIG_WAN) += wan/ -obj-$(CONFIG_WLAN) += wireless/ -obj-$(CONFIG_WIMAX) += wimax/ -obj-$(CONFIG_IEEE802154) += ieee802154/ - -obj-$(CONFIG_VMXNET3) += vmxnet3/ -obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o -obj-$(CONFIG_XEN_NETDEV_BACKEND) += xen-netback/ - -obj-$(CONFIG_USB_NET_DRIVERS) += usb/ - -obj-$(CONFIG_HYPERV_NET) += hyperv/ -obj-$(CONFIG_NTB_NETDEV) += ntb_netdev.o - -obj-$(CONFIG_FUJITSU_ES) += fjes/ diff --git a/src/linux/drivers/net/Space.c b/src/linux/drivers/net/Space.c deleted file mode 100644 index 11fe712..0000000 --- a/src/linux/drivers/net/Space.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Holds initial configuration information for devices. - * - * Version: @(#)Space.c 1.0.7 08/12/93 - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Donald J. Becker, - * - * Changelog: - * Stephen Hemminger (09/2003) - * - get rid of pre-linked dev list, dynamic device allocation - * Paul Gortmaker (03/2002) - * - struct init cleanup, enable multiple ISA autoprobes. - * Arnaldo Carvalho de Melo - 09/1999 - * - fix sbni: s/device/net_device/ - * Paul Gortmaker (06/98): - * - sort probes in a sane way, make sure all (safe) probes - * get run once & failed autoprobes don't autoprobe again. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include -#include -#include -#include - -/* A unified ethernet device probe. This is the easiest way to have every - * ethernet adaptor have the name "eth[0123...]". - */ - -struct devprobe2 { - struct net_device *(*probe)(int unit); - int status; /* non-zero if autoprobe has failed */ -}; - -static int __init probe_list2(int unit, struct devprobe2 *p, int autoprobe) -{ - struct net_device *dev; - - for (; p->probe; p++) { - if (autoprobe && p->status) - continue; - dev = p->probe(unit); - if (!IS_ERR(dev)) - return 0; - if (autoprobe) - p->status = PTR_ERR(dev); - } - return -ENODEV; -} - -/* ISA probes that touch addresses < 0x400 (including those that also - * look for EISA/PCI cards in addition to ISA cards). - */ -static struct devprobe2 isa_probes[] __initdata = { -#if defined(CONFIG_HP100) && defined(CONFIG_ISA) /* ISA, EISA */ - {hp100_probe, 0}, -#endif -#ifdef CONFIG_3C515 - {tc515_probe, 0}, -#endif -#ifdef CONFIG_ULTRA - {ultra_probe, 0}, -#endif -#ifdef CONFIG_WD80x3 - {wd_probe, 0}, -#endif -#if defined(CONFIG_NE2000) /* ISA (use ne2k-pci for PCI cards) */ - {ne_probe, 0}, -#endif -#ifdef CONFIG_LANCE /* ISA/VLB (use pcnet32 for PCI cards) */ - {lance_probe, 0}, -#endif -#ifdef CONFIG_SMC9194 - {smc_init, 0}, -#endif -#ifdef CONFIG_CS89x0 -#ifndef CONFIG_CS89x0_PLATFORM - {cs89x0_probe, 0}, -#endif -#endif -#if defined(CONFIG_MVME16x_NET) || defined(CONFIG_BVME6000_NET) /* Intel */ - {i82596_probe, 0}, /* I82596 */ -#endif -#ifdef CONFIG_NI65 - {ni65_probe, 0}, -#endif - {NULL, 0}, -}; - -static struct devprobe2 m68k_probes[] __initdata = { -#ifdef CONFIG_ATARILANCE /* Lance-based Atari ethernet boards */ - {atarilance_probe, 0}, -#endif -#ifdef CONFIG_SUN3LANCE /* sun3 onboard Lance chip */ - {sun3lance_probe, 0}, -#endif -#ifdef CONFIG_SUN3_82586 /* sun3 onboard Intel 82586 chip */ - {sun3_82586_probe, 0}, -#endif -#ifdef CONFIG_APNE /* A1200 PCMCIA NE2000 */ - {apne_probe, 0}, -#endif -#ifdef CONFIG_MVME147_NET /* MVME147 internal Ethernet */ - {mvme147lance_probe, 0}, -#endif -#ifdef CONFIG_MAC8390 /* NuBus NS8390-based cards */ - {mac8390_probe, 0}, -#endif -#ifdef CONFIG_MAC89x0 - {mac89x0_probe, 0}, -#endif - {NULL, 0}, -}; - -/* Unified ethernet device probe, segmented per architecture and - * per bus interface. This drives the legacy devices only for now. - */ - -static void __init ethif_probe2(int unit) -{ - unsigned long base_addr = netdev_boot_base("eth", unit); - - if (base_addr == 1) - return; - - (void)(probe_list2(unit, m68k_probes, base_addr == 0) && - probe_list2(unit, isa_probes, base_addr == 0)); -} - -/* Statically configured drivers -- order matters here. */ -static int __init net_olddevs_init(void) -{ - int num; - -#ifdef CONFIG_SBNI - for (num = 0; num < 8; ++num) - sbni_probe(num); -#endif - for (num = 0; num < 8; ++num) - ethif_probe2(num); - -#ifdef CONFIG_COPS - cops_probe(0); - cops_probe(1); - cops_probe(2); -#endif -#ifdef CONFIG_LTPC - ltpc_probe(); -#endif - - return 0; -} - -device_initcall(net_olddevs_init); diff --git a/src/linux/drivers/net/appletalk/Kconfig b/src/linux/drivers/net/appletalk/Kconfig deleted file mode 100644 index dc6b78e..0000000 --- a/src/linux/drivers/net/appletalk/Kconfig +++ /dev/null @@ -1,109 +0,0 @@ -# -# Appletalk driver configuration -# -config ATALK - tristate "Appletalk protocol support" - select LLC - ---help--- - AppleTalk is the protocol that Apple computers can use to communicate - on a network. If your Linux box is connected to such a network and you - wish to connect to it, say Y. You will need to use the netatalk package - so that your Linux box can act as a print and file server for Macs as - well as access AppleTalk printers. Check out - on the WWW for details. - EtherTalk is the name used for AppleTalk over Ethernet and the - cheaper and slower LocalTalk is AppleTalk over a proprietary Apple - network using serial links. EtherTalk and LocalTalk are fully - supported by Linux. - - General information about how to connect Linux, Windows machines and - Macs is on the WWW at . The - NET3-4-HOWTO, available from - , contains valuable - information as well. - - To compile this driver as a module, choose M here: the module will be - called appletalk. You almost certainly want to compile it as a - module so you can restart your AppleTalk stack without rebooting - your machine. I hear that the GNU boycott of Apple is over, so - even politically correct people are allowed to say Y here. - -config DEV_APPLETALK - tristate "Appletalk interfaces support" - depends on ATALK - help - AppleTalk is the protocol that Apple computers can use to communicate - on a network. If your Linux box is connected to such a network, and wish - to do IP over it, or you have a LocalTalk card and wish to use it to - connect to the AppleTalk network, say Y. - - -config LTPC - tristate "Apple/Farallon LocalTalk PC support" - depends on DEV_APPLETALK && (ISA || EISA) && ISA_DMA_API && VIRT_TO_BUS - help - This allows you to use the AppleTalk PC card to connect to LocalTalk - networks. The card is also known as the Farallon PhoneNet PC card. - If you are in doubt, this card is the one with the 65C02 chip on it. - You also need version 1.3.3 or later of the netatalk package. - This driver is experimental, which means that it may not work. - See the file . - -config COPS - tristate "COPS LocalTalk PC support" - depends on DEV_APPLETALK && (ISA || EISA) - help - This allows you to use COPS AppleTalk cards to connect to LocalTalk - networks. You also need version 1.3.3 or later of the netatalk - package. This driver is experimental, which means that it may not - work. This driver will only work if you choose "AppleTalk DDP" - networking support, above. - Please read the file . - -config COPS_DAYNA - bool "Dayna firmware support" - depends on COPS - help - Support COPS compatible cards with Dayna style firmware (Dayna - DL2000/ Daynatalk/PC (half length), COPS LT-95, Farallon PhoneNET PC - III, Farallon PhoneNET PC II). - -config COPS_TANGENT - bool "Tangent firmware support" - depends on COPS - help - Support COPS compatible cards with Tangent style firmware (Tangent - ATB_II, Novell NL-1000, Daystar Digital LT-200. - -config IPDDP - tristate "Appletalk-IP driver support" - depends on DEV_APPLETALK && ATALK - ---help--- - This allows IP networking for users who only have AppleTalk - networking available. This feature is experimental. With this - driver, you can encapsulate IP inside AppleTalk (e.g. if your Linux - box is stuck on an AppleTalk only network) or decapsulate (e.g. if - you want your Linux box to act as an Internet gateway for a zoo of - AppleTalk connected Macs). Please see the file - for more information. - - If you say Y here, the AppleTalk-IP support will be compiled into - the kernel. In this case, you can either use encapsulation or - decapsulation, but not both. With the following two questions, you - decide which one you want. - - To compile the AppleTalk-IP support as a module, choose M here: the - module will be called ipddp. - In this case, you will be able to use both encapsulation and - decapsulation simultaneously, by loading two copies of the module - and specifying different values for the module option ipddp_mode. - -config IPDDP_ENCAP - bool "IP to Appletalk-IP Encapsulation support" - depends on IPDDP - help - If you say Y here, the AppleTalk-IP code will be able to encapsulate - IP packets inside AppleTalk frames; this is useful if your Linux box - is stuck on an AppleTalk network (which hopefully contains a - decapsulator somewhere). Please see - for more information. diff --git a/src/linux/drivers/net/arcnet/Kconfig b/src/linux/drivers/net/arcnet/Kconfig deleted file mode 100644 index 39bd16f..0000000 --- a/src/linux/drivers/net/arcnet/Kconfig +++ /dev/null @@ -1,133 +0,0 @@ -# -# Arcnet configuration -# - -menuconfig ARCNET - depends on NETDEVICES && (ISA || PCI || PCMCIA) - tristate "ARCnet support" - ---help--- - If you have a network card of this type, say Y and check out the - (arguably) beautiful poetry in - . - - You need both this driver, and the driver for the particular ARCnet - chipset of your card. If you don't know, then it's probably a - COM90xx type card, so say Y (or M) to "ARCnet COM90xx chipset - support" below. - - To compile this driver as a module, choose M here. The module will - be called arcnet. - -if ARCNET - -config ARCNET_1201 - tristate "Enable standard ARCNet packet format (RFC 1201)" - help - This allows you to use RFC1201 with your ARCnet card via the virtual - arc0 device. You need to say Y here to communicate with - industry-standard RFC1201 implementations, like the arcether.com - packet driver or most DOS/Windows ODI drivers. Please read the - ARCnet documentation in - for more information about using arc0. - -config ARCNET_1051 - tristate "Enable old ARCNet packet format (RFC 1051)" - ---help--- - This allows you to use RFC1051 with your ARCnet card via the virtual - arc0s device. You only need arc0s if you want to talk to ARCnet - software complying with the "old" standard, specifically, the DOS - arcnet.com packet driver, Amigas running AmiTCP, and some variants - of NetBSD. You do not need to say Y here to communicate with - industry-standard RFC1201 implementations, like the arcether.com - packet driver or most DOS/Windows ODI drivers. RFC1201 is included - automatically as the arc0 device. Please read the ARCnet - documentation in for more - information about using arc0e and arc0s. - -config ARCNET_RAW - tristate "Enable raw mode packet interface" - help - ARCnet "raw mode" packet encapsulation, no soft headers. Unlikely - to work unless talking to a copy of the same Linux arcnet driver, - but perhaps marginally faster in that case. - -config ARCNET_CAP - tristate "Enable CAP mode packet interface" - help - ARCnet "cap mode" packet encapsulation. Used to get the hardware - acknowledge back to userspace. After the initial protocol byte every - packet is stuffed with an extra 4 byte "cookie" which doesn't - actually appear on the network. After transmit the driver will send - back a packet with protocol byte 0 containing the status of the - transmission: - 0=no hardware acknowledge - 1=excessive nak - 2=transmission accepted by the receiver hardware - - Received packets are also stuffed with the extra 4 bytes but it will - be random data. - - Cap only listens to protocol 1-8. - -config ARCNET_COM90xx - tristate "ARCnet COM90xx (normal) chipset driver" - help - This is the chipset driver for the standard COM90xx cards. If you - have always used the old ARCnet driver without knowing what type of - card you had, this is probably the one for you. - - To compile this driver as a module, choose M here. The module will - be called com90xx. - -config ARCNET_COM90xxIO - tristate "ARCnet COM90xx (IO mapped) chipset driver" - ---help--- - This is the chipset driver for the COM90xx cards, using them in - IO-mapped mode instead of memory-mapped mode. This is slower than - the normal driver. Only use it if your card doesn't support shared - memory. - - To compile this driver as a module, choose M here. The module will - be called com90io. - -config ARCNET_RIM_I - tristate "ARCnet COM90xx (RIM I) chipset driver" - ---help--- - This is yet another chipset driver for the COM90xx cards, but this - time only using memory-mapped mode, and no IO ports at all. This - driver is completely untested, so if you have one of these cards, - please mail , especially if it works! - - To compile this driver as a module, choose M here. The module will - be called arc-rimi. - -config ARCNET_COM20020 - tristate "ARCnet COM20020 chipset driver" - depends on LEDS_CLASS - help - This is the driver for the new COM20020 chipset. It supports such - things as promiscuous mode, so packet sniffing is possible, and - extra diagnostic information. - - To compile this driver as a module, choose M here. The module will - be called com20020. - -config ARCNET_COM20020_ISA - tristate "Support for COM20020 on ISA" - depends on ARCNET_COM20020 && ISA - -config ARCNET_COM20020_PCI - tristate "Support for COM20020 on PCI" - depends on ARCNET_COM20020 && PCI - -config ARCNET_COM20020_CS - tristate "COM20020 ARCnet PCMCIA support" - depends on ARCNET_COM20020 && PCMCIA - help - Say Y here if you intend to attach this type of ARCnet PCMCIA card - to your computer. - - To compile this driver as a module, choose M here: the module will be - called com20020_cs. If unsure, say N. - -endif # ARCNET diff --git a/src/linux/drivers/net/caif/Kconfig b/src/linux/drivers/net/caif/Kconfig deleted file mode 100644 index f81df91..0000000 --- a/src/linux/drivers/net/caif/Kconfig +++ /dev/null @@ -1,56 +0,0 @@ -# -# CAIF physical drivers -# - -comment "CAIF transport drivers" - -config CAIF_TTY - tristate "CAIF TTY transport driver" - depends on CAIF && TTY - default n - ---help--- - The CAIF TTY transport driver is a Line Discipline (ldisc) - identified as N_CAIF. When this ldisc is opened from user space - it will redirect the TTY's traffic into the CAIF stack. - -config CAIF_SPI_SLAVE - tristate "CAIF SPI transport driver for slave interface" - depends on CAIF && HAS_DMA - default n - ---help--- - The CAIF Link layer SPI Protocol driver for Slave SPI interface. - This driver implements a platform driver to accommodate for a - platform specific SPI device. A sample CAIF SPI Platform device is - provided in Documentation/networking/caif/spi_porting.txt - -config CAIF_SPI_SYNC - bool "Next command and length in start of frame" - depends on CAIF_SPI_SLAVE - default n - ---help--- - Putting the next command and length in the start of the frame can - help to synchronize to the next transfer in case of over or under-runs. - This option also needs to be enabled on the modem. - -config CAIF_HSI - tristate "CAIF HSI transport driver" - depends on CAIF - default n - ---help--- - The caif low level driver for CAIF over HSI. - Be aware that if you enable this then you also need to - enable a low-level HSI driver. - -config CAIF_VIRTIO - tristate "CAIF virtio transport driver" - depends on CAIF && HAS_DMA - select VHOST_RING - select VIRTIO - select GENERIC_ALLOCATOR - default n - ---help--- - The caif driver for CAIF over Virtio. - -if CAIF_VIRTIO -source "drivers/vhost/Kconfig.vringh" -endif diff --git a/src/linux/drivers/net/can/Kconfig b/src/linux/drivers/net/can/Kconfig deleted file mode 100644 index 22570ea..0000000 --- a/src/linux/drivers/net/can/Kconfig +++ /dev/null @@ -1,161 +0,0 @@ -menu "CAN Device Drivers" - -config CAN_VCAN - tristate "Virtual Local CAN Interface (vcan)" - ---help--- - Similar to the network loopback devices, vcan offers a - virtual local CAN interface. - - This driver can also be built as a module. If so, the module - will be called vcan. - -config CAN_SLCAN - tristate "Serial / USB serial CAN Adaptors (slcan)" - depends on TTY - ---help--- - CAN driver for several 'low cost' CAN interfaces that are attached - via serial lines or via USB-to-serial adapters using the LAWICEL - ASCII protocol. The driver implements the tty linediscipline N_SLCAN. - - As only the sending and receiving of CAN frames is implemented, this - driver should work with the (serial/USB) CAN hardware from: - www.canusb.com / www.can232.com / www.mictronics.de / www.canhack.de - - Userspace tools to attach the SLCAN line discipline (slcan_attach, - slcand) can be found in the can-utils at the SocketCAN SVN, see - http://developer.berlios.de/projects/socketcan for details. - - The slcan driver supports up to 10 CAN netdevices by default which - can be changed by the 'maxdev=xx' module option. This driver can - also be built as a module. If so, the module will be called slcan. - -config CAN_DEV - tristate "Platform CAN drivers with Netlink support" - default y - ---help--- - Enables the common framework for platform CAN drivers with Netlink - support. This is the standard library for CAN drivers. - If unsure, say Y. - -if CAN_DEV - -config CAN_CALC_BITTIMING - bool "CAN bit-timing calculation" - default y - ---help--- - If enabled, CAN bit-timing parameters will be calculated for the - bit-rate specified via Netlink argument "bitrate" when the device - get started. This works fine for the most common CAN controllers - with standard bit-rates but may fail for exotic bit-rates or CAN - source clock frequencies. Disabling saves some space, but then the - bit-timing parameters must be specified directly using the Netlink - arguments "tq", "prop_seg", "phase_seg1", "phase_seg2" and "sjw". - If unsure, say Y. - -config CAN_LEDS - bool "Enable LED triggers for Netlink based drivers" - depends on LEDS_CLASS - select LEDS_TRIGGERS - ---help--- - This option adds two LED triggers for packet receive and transmit - events on each supported CAN device. - - Say Y here if you are working on a system with led-class supported - LEDs and you want to use them as canbus activity indicators. - -config CAN_AT91 - tristate "Atmel AT91 onchip CAN controller" - depends on (ARCH_AT91 || COMPILE_TEST) && HAS_IOMEM - ---help--- - This is a driver for the SoC CAN controller in Atmel's AT91SAM9263 - and AT91SAM9X5 processors. - -config CAN_BFIN - depends on BF534 || BF536 || BF537 || BF538 || BF539 || BF54x - tristate "Analog Devices Blackfin on-chip CAN" - ---help--- - Driver for the Analog Devices Blackfin on-chip CAN controllers - - To compile this driver as a module, choose M here: the - module will be called bfin_can. - -config CAN_FLEXCAN - tristate "Support for Freescale FLEXCAN based chips" - depends on ARM || PPC - ---help--- - Say Y here if you want to support for Freescale FlexCAN. - -config CAN_GRCAN - tristate "Aeroflex Gaisler GRCAN and GRHCAN CAN devices" - depends on OF && HAS_DMA - ---help--- - Say Y here if you want to use Aeroflex Gaisler GRCAN or GRHCAN. - Note that the driver supports little endian, even though little - endian syntheses of the cores would need some modifications on - the hardware level to work. - -config CAN_JANZ_ICAN3 - tristate "Janz VMOD-ICAN3 Intelligent CAN controller" - depends on MFD_JANZ_CMODIO - ---help--- - Driver for Janz VMOD-ICAN3 Intelligent CAN controller module, which - connects to a MODULbus carrier board. - - This driver can also be built as a module. If so, the module will be - called janz-ican3.ko. - -config CAN_SUN4I - tristate "Allwinner A10 CAN controller" - depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST - ---help--- - Say Y here if you want to use CAN controller found on Allwinner - A10/A20 SoCs. - - To compile this driver as a module, choose M here: the module will - be called sun4i_can. - -config CAN_TI_HECC - depends on ARM - tristate "TI High End CAN Controller" - ---help--- - Driver for TI HECC (High End CAN Controller) module found on many - TI devices. The device specifications are available from www.ti.com - -config CAN_XILINXCAN - tristate "Xilinx CAN" - depends on ARCH_ZYNQ || ARM64 || MICROBLAZE || COMPILE_TEST - depends on COMMON_CLK && HAS_IOMEM - ---help--- - Xilinx CAN driver. This driver supports both soft AXI CAN IP and - Zynq CANPS IP. - -config PCH_CAN - tristate "Intel EG20T PCH CAN controller" - depends on PCI && (X86_32 || COMPILE_TEST) - ---help--- - This driver is for PCH CAN of Topcliff (Intel EG20T PCH) which - is an IOH for x86 embedded processor (Intel Atom E6xx series). - This driver can access CAN bus. - -source "drivers/net/can/c_can/Kconfig" -source "drivers/net/can/cc770/Kconfig" -source "drivers/net/can/ifi_canfd/Kconfig" -source "drivers/net/can/m_can/Kconfig" -source "drivers/net/can/mscan/Kconfig" -source "drivers/net/can/rcar/Kconfig" -source "drivers/net/can/sja1000/Kconfig" -source "drivers/net/can/softing/Kconfig" -source "drivers/net/can/spi/Kconfig" -source "drivers/net/can/usb/Kconfig" - -endif - -config CAN_DEBUG_DEVICES - bool "CAN devices debugging messages" - ---help--- - Say Y here if you want the CAN device drivers to produce a bunch of - debug messages to the system log. Select this if you are having - a problem with CAN support and want to see more of what is going - on. - -endmenu diff --git a/src/linux/drivers/net/can/c_can/Kconfig b/src/linux/drivers/net/can/c_can/Kconfig deleted file mode 100644 index 61ffc12..0000000 --- a/src/linux/drivers/net/can/c_can/Kconfig +++ /dev/null @@ -1,23 +0,0 @@ -menuconfig CAN_C_CAN - tristate "Bosch C_CAN/D_CAN devices" - depends on HAS_IOMEM - -if CAN_C_CAN - -config CAN_C_CAN_PLATFORM - tristate "Generic Platform Bus based C_CAN/D_CAN driver" - ---help--- - This driver adds support for the C_CAN/D_CAN chips connected - to the "platform bus" (Linux abstraction for directly to the - processor attached devices) which can be found on various - boards from ST Microelectronics (http://www.st.com) like the - SPEAr1310 and SPEAr320 evaluation boards & TI (www.ti.com) - boards like am335x, dm814x, dm813x and dm811x. - -config CAN_C_CAN_PCI - tristate "Generic PCI Bus based C_CAN/D_CAN driver" - depends on PCI - ---help--- - This driver adds support for the C_CAN/D_CAN chips connected - to the PCI bus. -endif diff --git a/src/linux/drivers/net/can/cc770/Kconfig b/src/linux/drivers/net/can/cc770/Kconfig deleted file mode 100644 index 6a9a5ba..0000000 --- a/src/linux/drivers/net/can/cc770/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -menuconfig CAN_CC770 - tristate "Bosch CC770 and Intel AN82527 devices" - depends on HAS_IOMEM - -if CAN_CC770 - -config CAN_CC770_ISA - tristate "ISA Bus based legacy CC770 driver" - ---help--- - This driver adds legacy support for CC770 and AN82527 chips - connected to the ISA bus using I/O port, memory mapped or - indirect access. - -config CAN_CC770_PLATFORM - tristate "Generic Platform Bus based CC770 driver" - ---help--- - This driver adds support for the CC770 and AN82527 chips - connected to the "platform bus" (Linux abstraction for directly - to the processor attached devices). - -endif diff --git a/src/linux/drivers/net/can/ifi_canfd/Kconfig b/src/linux/drivers/net/can/ifi_canfd/Kconfig deleted file mode 100644 index 9e8934f..0000000 --- a/src/linux/drivers/net/can/ifi_canfd/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config CAN_IFI_CANFD - depends on HAS_IOMEM - tristate "IFI CAN_FD IP" - ---help--- - This driver adds support for the I/F/I CAN_FD soft IP block - connected to the "platform bus" (Linux abstraction for directly - to the processor attached devices). The CAN_FD is most often - synthesised into an FPGA or CPLD. diff --git a/src/linux/drivers/net/can/m_can/Kconfig b/src/linux/drivers/net/can/m_can/Kconfig deleted file mode 100644 index 04f20dd..0000000 --- a/src/linux/drivers/net/can/m_can/Kconfig +++ /dev/null @@ -1,5 +0,0 @@ -config CAN_M_CAN - depends on HAS_IOMEM - tristate "Bosch M_CAN devices" - ---help--- - Say Y here if you want to support for Bosch M_CAN controller. diff --git a/src/linux/drivers/net/can/mscan/Kconfig b/src/linux/drivers/net/can/mscan/Kconfig deleted file mode 100644 index 81c7117..0000000 --- a/src/linux/drivers/net/can/mscan/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -config CAN_MSCAN - depends on PPC - tristate "Support for Freescale MSCAN based chips" - ---help--- - The Motorola Scalable Controller Area Network (MSCAN) definition - is based on the MSCAN12 definition which is the specific - implementation of the Motorola Scalable CAN concept targeted for - the Motorola MC68HC12 Microcontroller Family. - -if CAN_MSCAN - -config CAN_MPC5XXX - tristate "Freescale MPC5xxx onboard CAN controller" - depends on (PPC_MPC52xx || PPC_MPC512x) - ---help--- - If you say yes here you get support for Freescale's MPC5xxx - onboard CAN controller. Currently, the MPC5200, MPC5200B and - MPC5121 (Rev. 2 and later) are supported. - - This driver can also be built as a module. If so, the module - will be called mscan-mpc5xxx.ko. - -endif - diff --git a/src/linux/drivers/net/can/rcar/Kconfig b/src/linux/drivers/net/can/rcar/Kconfig deleted file mode 100644 index 7b03a3a..0000000 --- a/src/linux/drivers/net/can/rcar/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -config CAN_RCAR - tristate "Renesas R-Car CAN controller" - depends on ARCH_RENESAS || ARM - ---help--- - Say Y here if you want to use CAN controller found on Renesas R-Car - SoCs. - - To compile this driver as a module, choose M here: the module will - be called rcar_can. - -config CAN_RCAR_CANFD - tristate "Renesas R-Car CAN FD controller" - depends on ARCH_RENESAS || ARM - ---help--- - Say Y here if you want to use CAN FD controller found on - Renesas R-Car SoCs. The driver puts the controller in CAN FD only - mode, which can interoperate with CAN2.0 nodes but does not support - dedicated CAN 2.0 mode. - - To compile this driver as a module, choose M here: the module will - be called rcar_canfd. diff --git a/src/linux/drivers/net/can/sja1000/Kconfig b/src/linux/drivers/net/can/sja1000/Kconfig deleted file mode 100644 index 1e65cb6..0000000 --- a/src/linux/drivers/net/can/sja1000/Kconfig +++ /dev/null @@ -1,103 +0,0 @@ -menuconfig CAN_SJA1000 - tristate "Philips/NXP SJA1000 devices" - depends on HAS_IOMEM - -if CAN_SJA1000 - -config CAN_SJA1000_ISA - tristate "ISA Bus based legacy SJA1000 driver" - ---help--- - This driver adds legacy support for SJA1000 chips connected to - the ISA bus using I/O port, memory mapped or indirect access. - -config CAN_SJA1000_PLATFORM - tristate "Generic Platform Bus based SJA1000 driver" - ---help--- - This driver adds support for the SJA1000 chips connected to - the "platform bus" (Linux abstraction for directly to the - processor attached devices). Which can be found on various - boards from Phytec (http://www.phytec.de) like the PCM027, - PCM038. It also provides the OpenFirmware "platform bus" found - on embedded systems with OpenFirmware bindings, e.g. if you - have a PowerPC based system you may want to enable this option. - -config CAN_EMS_PCMCIA - tristate "EMS CPC-CARD Card" - depends on PCMCIA - ---help--- - This driver is for the one or two channel CPC-CARD cards from - EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de). - -config CAN_EMS_PCI - tristate "EMS CPC-PCI, CPC-PCIe and CPC-104P Card" - depends on PCI - ---help--- - This driver is for the one, two or four channel CPC-PCI, - CPC-PCIe and CPC-104P cards from EMS Dr. Thomas Wuensche - (http://www.ems-wuensche.de). - -config CAN_PEAK_PCMCIA - tristate "PEAK PCAN-PC Card" - depends on PCMCIA - depends on HAS_IOPORT_MAP - ---help--- - This driver is for the PCAN-PC Card PCMCIA adapter (1 or 2 channels) - from PEAK-System (http://www.peak-system.com). To compile this - driver as a module, choose M here: the module will be called - peak_pcmcia. - -config CAN_PEAK_PCI - tristate "PEAK PCAN-PCI/PCIe/miniPCI Cards" - depends on PCI - ---help--- - This driver is for the PCAN-PCI/PCIe/miniPCI cards - (1, 2, 3 or 4 channels) from PEAK-System Technik - (http://www.peak-system.com). - -config CAN_PEAK_PCIEC - bool "PEAK PCAN-ExpressCard Cards" - depends on CAN_PEAK_PCI - select I2C - select I2C_ALGOBIT - default y - ---help--- - Say Y here if you want to use a PCAN-ExpressCard from PEAK-System - Technik. This will also automatically select I2C and I2C_ALGO - configuration options. - -config CAN_KVASER_PCI - tristate "Kvaser PCIcanx and Kvaser PCIcan PCI Cards" - depends on PCI - ---help--- - This driver is for the PCIcanx and PCIcan cards (1, 2 or - 4 channel) from Kvaser (http://www.kvaser.com). - -config CAN_PLX_PCI - tristate "PLX90xx PCI-bridge based Cards" - depends on PCI - ---help--- - This driver is for CAN interface cards based on - the PLX90xx PCI bridge. - Driver supports now: - - Adlink PCI-7841/cPCI-7841 card (http://www.adlinktech.com/) - - Adlink PCI-7841/cPCI-7841 SE card - - esd CAN-PCI/CPCI/PCI104/200 (http://www.esd.eu/) - - esd CAN-PCI/PMC/266 - - esd CAN-PCIe/2000 - - Marathon CAN-bus-PCI card (http://www.marathon.ru/) - - TEWS TECHNOLOGIES TPMC810 card (http://www.tews.com/) - - IXXAT Automation PC-I 04/PCI card (http://www.ixxat.com/) - - Connect Tech Inc. CANpro/104-Plus Opto (CRG001) card (http://www.connecttech.com) - -config CAN_TSCAN1 - tristate "TS-CAN1 PC104 boards" - depends on ISA - help - This driver is for Technologic Systems' TSCAN-1 PC104 boards. - http://www.embeddedarm.com/products/board-detail.php?product=TS-CAN1 - The driver supports multiple boards and automatically configures them: - PLD IO base addresses are read from jumpers JP1 and JP2, - IRQ numbers are read from jumpers JP4 and JP5, - SJA1000 IO base addresses are chosen heuristically (first that works). - -endif diff --git a/src/linux/drivers/net/can/softing/Kconfig b/src/linux/drivers/net/can/softing/Kconfig deleted file mode 100644 index 96b6fe1..0000000 --- a/src/linux/drivers/net/can/softing/Kconfig +++ /dev/null @@ -1,30 +0,0 @@ -config CAN_SOFTING - tristate "Softing Gmbh CAN generic support" - depends on HAS_IOMEM - ---help--- - Support for CAN cards from Softing Gmbh & some cards - from Vector Gmbh. - Softing Gmbh CAN cards come with 1 or 2 physical busses. - Those cards typically use Dual Port RAM to communicate - with the host CPU. The interface is then identical for PCI - and PCMCIA cards. This driver operates on a platform device, - which has been created by softing_cs or softing_pci driver. - Warning: - The API of the card does not allow fine control per bus, but - controls the 2 busses on the card together. - As such, some actions (start/stop/busoff recovery) on 1 bus - must bring down the other bus too temporarily. - -config CAN_SOFTING_CS - tristate "Softing Gmbh CAN pcmcia cards" - depends on PCMCIA - depends on CAN_SOFTING - ---help--- - Support for PCMCIA cards from Softing Gmbh & some cards - from Vector Gmbh. - You need firmware for these, which you can get at - http://developer.berlios.de/projects/socketcan/ - This version of the driver is written against - firmware version 4.6 (softing-fw-4.6-binaries.tar.gz) - In order to use the card as CAN device, you need the Softing generic - support too. diff --git a/src/linux/drivers/net/can/spi/Kconfig b/src/linux/drivers/net/can/spi/Kconfig deleted file mode 100644 index 148cae5..0000000 --- a/src/linux/drivers/net/can/spi/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -menu "CAN SPI interfaces" - depends on SPI - -config CAN_MCP251X - tristate "Microchip MCP251x SPI CAN controllers" - depends on HAS_DMA - ---help--- - Driver for the Microchip MCP251x SPI CAN controllers. - -endmenu diff --git a/src/linux/drivers/net/can/usb/Kconfig b/src/linux/drivers/net/can/usb/Kconfig deleted file mode 100644 index 8483a40..0000000 --- a/src/linux/drivers/net/can/usb/Kconfig +++ /dev/null @@ -1,84 +0,0 @@ -menu "CAN USB interfaces" - depends on USB - -config CAN_EMS_USB - tristate "EMS CPC-USB/ARM7 CAN/USB interface" - ---help--- - This driver is for the one channel CPC-USB/ARM7 CAN/USB interface - from EMS Dr. Thomas Wuensche (http://www.ems-wuensche.de). - -config CAN_ESD_USB2 - tristate "ESD USB/2 CAN/USB interface" - ---help--- - This driver supports the CAN-USB/2 interface - from esd electronic system design gmbh (http://www.esd.eu). - -config CAN_GS_USB - tristate "Geschwister Schneider UG interfaces" - ---help--- - This driver supports the Geschwister Schneider and bytewerk.org - candleLight USB CAN interfaces USB/CAN devices - If unsure choose N, - choose Y for built in support, - M to compile as module (module will be named: gs_usb). - -config CAN_KVASER_USB - tristate "Kvaser CAN/USB interface" - ---help--- - This driver adds support for Kvaser CAN/USB devices like Kvaser - Leaf Light and Kvaser USBcan II. - - The driver provides support for the following devices: - - Kvaser Leaf Light - - Kvaser Leaf Professional HS - - Kvaser Leaf SemiPro HS - - Kvaser Leaf Professional LS - - Kvaser Leaf Professional SWC - - Kvaser Leaf Professional LIN - - Kvaser Leaf SemiPro LS - - Kvaser Leaf SemiPro SWC - - Kvaser Memorator II HS/HS - - Kvaser USBcan Professional HS/HS - - Kvaser Leaf Light GI - - Kvaser Leaf Professional HS (OBD-II connector) - - Kvaser Memorator Professional HS/LS - - Kvaser Leaf Light "China" - - Kvaser BlackBird SemiPro - - Kvaser USBcan R - - Kvaser Leaf Light v2 - - Kvaser Mini PCI Express HS - - Kvaser Mini PCI Express 2xHS - - Kvaser USBcan Light 2xHS - - Kvaser USBcan II HS/HS - - Kvaser USBcan II HS/LS - - Kvaser USBcan Rugged ("USBcan Rev B") - - Kvaser Memorator HS/HS - - Kvaser Memorator HS/LS - - Scania VCI2 (if you have the Kvaser logo on top) - - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called kvaser_usb. - -config CAN_PEAK_USB - tristate "PEAK PCAN-USB/USB Pro interfaces for CAN 2.0b/CAN-FD" - ---help--- - This driver supports the PEAK-System Technik USB adapters that enable - access to the CAN bus, with repect to the CAN 2.0b and/or CAN-FD - standards, that is: - - PCAN-USB single CAN 2.0b channel USB adapter - PCAN-USB Pro dual CAN 2.0b channels USB adapter - PCAN-USB FD single CAN-FD channel USB adapter - PCAN-USB Pro FD dual CAN-FD channels USB adapter - - (see also http://www.peak-system.com). - -config CAN_8DEV_USB - tristate "8 devices USB2CAN interface" - ---help--- - This driver supports the USB2CAN interface - from 8 devices (http://www.8devices.com). - -endmenu diff --git a/src/linux/drivers/net/dsa/Kconfig b/src/linux/drivers/net/dsa/Kconfig deleted file mode 100644 index 0659846..0000000 --- a/src/linux/drivers/net/dsa/Kconfig +++ /dev/null @@ -1,37 +0,0 @@ -menu "Distributed Switch Architecture drivers" - depends on HAVE_NET_DSA - -config NET_DSA_MV88E6060 - tristate "Marvell 88E6060 ethernet switch chip support" - depends on NET_DSA - select NET_DSA_TAG_TRAILER - ---help--- - This enables support for the Marvell 88E6060 ethernet switch - chip. - -config NET_DSA_BCM_SF2 - tristate "Broadcom Starfighter 2 Ethernet switch support" - depends on HAS_IOMEM && NET_DSA - select NET_DSA_TAG_BRCM - select FIXED_PHY - select BCM7XXX_PHY - select MDIO_BCM_UNIMAC - select B53 - ---help--- - This enables support for the Broadcom Starfighter 2 Ethernet - switch chips. - -source "drivers/net/dsa/b53/Kconfig" - -source "drivers/net/dsa/mv88e6xxx/Kconfig" - -config NET_DSA_QCA8K - tristate "Qualcomm Atheros QCA8K Ethernet switch family support" - depends on NET_DSA - select NET_DSA_TAG_QCA - select REGMAP - ---help--- - This enables support for the Qualcomm Atheros QCA8K Ethernet - switch chips. - -endmenu diff --git a/src/linux/drivers/net/dsa/b53/Kconfig b/src/linux/drivers/net/dsa/b53/Kconfig deleted file mode 100644 index 27f32a5..0000000 --- a/src/linux/drivers/net/dsa/b53/Kconfig +++ /dev/null @@ -1,33 +0,0 @@ -menuconfig B53 - tristate "Broadcom BCM53xx managed switch support" - depends on NET_DSA - help - This driver adds support for Broadcom managed switch chips. It supports - BCM5325E, BCM5365, BCM539x, BCM53115 and BCM53125 as well as BCM63XX - integrated switches. - -config B53_SPI_DRIVER - tristate "B53 SPI connected switch driver" - depends on B53 && SPI - help - Select to enable support for registering switches configured through SPI. - -config B53_MDIO_DRIVER - tristate "B53 MDIO connected switch driver" - depends on B53 - help - Select to enable support for registering switches configured through MDIO. - -config B53_MMAP_DRIVER - tristate "B53 MMAP connected switch driver" - depends on B53 && HAS_IOMEM - help - Select to enable support for memory-mapped switches like the BCM63XX - integrated switches. - -config B53_SRAB_DRIVER - tristate "B53 SRAB connected switch driver" - depends on B53 && HAS_IOMEM - help - Select to enable support for memory-mapped Switch Register Access - Bridge Registers (SRAB) like it is found on the BCM53010 diff --git a/src/linux/drivers/net/dsa/mv88e6xxx/Kconfig b/src/linux/drivers/net/dsa/mv88e6xxx/Kconfig deleted file mode 100644 index 4866688..0000000 --- a/src/linux/drivers/net/dsa/mv88e6xxx/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -config NET_DSA_MV88E6XXX - tristate "Marvell 88E6xxx Ethernet switch fabric support" - depends on NET_DSA - select NET_DSA_TAG_EDSA - select NET_DSA_TAG_DSA - help - This driver adds support for most of the Marvell 88E6xxx models of - Ethernet switch chips, except 88E6060. - -config NET_DSA_MV88E6XXX_GLOBAL2 - bool "Switch Global 2 Registers support" - default y - depends on NET_DSA_MV88E6XXX - help - This registers set at internal SMI address 0x1C provides extended - features like EEPROM interface, trunking, cross-chip setup, etc. - - It is required on most chips. If the chip you compile the support for - doesn't have such registers set, say N here. In doubt, say Y. diff --git a/src/linux/drivers/net/ethernet/3com/Kconfig b/src/linux/drivers/net/ethernet/3com/Kconfig deleted file mode 100644 index 5b7658b..0000000 --- a/src/linux/drivers/net/ethernet/3com/Kconfig +++ /dev/null @@ -1,99 +0,0 @@ -# -# 3Com Ethernet device configuration -# - -config NET_VENDOR_3COM - bool "3Com devices" - default y - depends on ISA || EISA || PCI || PCMCIA - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about 3Com cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_3COM - -config EL3 - tristate "3c509/3c579 \"EtherLink III\" support" - depends on (ISA || EISA) - ---help--- - If you have a network (Ethernet) card belonging to the 3Com - EtherLinkIII series, say Y here. - - If your card is not working you may need to use the DOS - setup disk to disable Plug & Play mode, and to select the default - media type. - - To compile this driver as a module, choose M here. The module - will be called 3c509. - -config 3C515 - tristate "3c515 ISA \"Fast EtherLink\"" - depends on ISA && ISA_DMA_API - ---help--- - If you have a 3Com ISA EtherLink XL "Corkscrew" 3c515 Fast Ethernet - network card, say Y here. - - To compile this driver as a module, choose M here. The module - will be called 3c515. - -config PCMCIA_3C574 - tristate "3Com 3c574 PCMCIA support" - depends on PCMCIA - ---help--- - Say Y here if you intend to attach a 3Com 3c574 or compatible PCMCIA - (PC-card) Fast Ethernet card to your computer. - - To compile this driver as a module, choose M here: the module will be - called 3c574_cs. If unsure, say N. - -config PCMCIA_3C589 - tristate "3Com 3c589 PCMCIA support" - depends on PCMCIA - ---help--- - Say Y here if you intend to attach a 3Com 3c589 or compatible PCMCIA - (PC-card) Ethernet card to your computer. - - To compile this driver as a module, choose M here: the module will be - called 3c589_cs. If unsure, say N. - -config VORTEX - tristate "3c590/3c900 series (592/595/597) \"Vortex/Boomerang\" support" - depends on (PCI || EISA) && HAS_IOPORT_MAP - select MII - ---help--- - This option enables driver support for a large number of 10Mbps and - 10/100Mbps EISA, PCI and Cardbus 3Com network cards: - - "Vortex" (Fast EtherLink 3c590/3c592/3c595/3c597) EISA and PCI - "Boomerang" (EtherLink XL 3c900 or 3c905) PCI - "Cyclone" (3c540/3c900/3c905/3c980/3c575/3c656) PCI and Cardbus - "Tornado" (3c905) PCI - "Hurricane" (3c555/3cSOHO) PCI - - If you have such a card, say Y here. More specific information is in - and in the comments at - the beginning of . - - To compile this support as a module, choose M here. - -config TYPHOON - tristate "3cr990 series \"Typhoon\" support" - depends on PCI - select CRC32 - ---help--- - This option enables driver support for the 3cr990 series of cards: - - 3C990-TX, 3CR990-TX-95, 3CR990-TX-97, 3CR990-FX-95, 3CR990-FX-97, - 3CR990SVR, 3CR990SVR95, 3CR990SVR97, 3CR990-FX-95 Server, - 3CR990-FX-97 Server, 3C990B-TX-M, 3C990BSVR - - If you have a network (Ethernet) card of this type, say Y here. - - To compile this driver as a module, choose M here. The module - will be called typhoon. - -endif # NET_VENDOR_3COM diff --git a/src/linux/drivers/net/ethernet/8390/Kconfig b/src/linux/drivers/net/ethernet/8390/Kconfig deleted file mode 100644 index 29c3075..0000000 --- a/src/linux/drivers/net/ethernet/8390/Kconfig +++ /dev/null @@ -1,196 +0,0 @@ -# -# 8390 device configuration -# - -config NET_VENDOR_8390 - bool "National Semi-conductor 8390 devices" - default y - depends on NET_VENDOR_NATSEMI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Western Digital cards. If you say Y, you will be - asked for your specific card in the following questions. - -if NET_VENDOR_8390 - -config PCMCIA_AXNET - tristate "Asix AX88190 PCMCIA support" - depends on PCMCIA - ---help--- - Say Y here if you intend to attach an Asix AX88190-based PCMCIA - (PC-card) Fast Ethernet card to your computer. These cards are - nearly NE2000 compatible but need a separate driver due to a few - misfeatures. - - To compile this driver as a module, choose M here: the module will be - called axnet_cs. If unsure, say N. - -config AX88796 - tristate "ASIX AX88796 NE2000 clone support" - depends on (ARM || MIPS || SUPERH) - select CRC32 - select PHYLIB - select MDIO_BITBANG - ---help--- - AX88796 driver, using platform bus to provide - chip detection and resources - -config AX88796_93CX6 - bool "ASIX AX88796 external 93CX6 eeprom support" - depends on AX88796 - select EEPROM_93CX6 - ---help--- - Select this if your platform comes with an external 93CX6 eeprom. - -config HYDRA - tristate "Hydra support" - depends on ZORRO - select CRC32 - ---help--- - If you have a Hydra Ethernet adapter, say Y. Otherwise, say N. - - To compile this driver as a module, choose M here: the module - will be called hydra. - -config ARM_ETHERH - tristate "I-cubed EtherH/ANT EtherM support" - depends on ARM && ARCH_ACORN - select CRC32 - ---help--- - If you have an Acorn system with one of these network cards, you - should say Y to this option if you wish to use it with Linux. - -config MAC8390 - tristate "Macintosh NS 8390 based ethernet cards" - depends on MAC - select CRC32 - ---help--- - If you want to include a driver to support Nubus or LC-PDS - Ethernet cards using an NS8390 chipset or its equivalent, say Y. - -config MCF8390 - tristate "ColdFire NS8390 based Ethernet support" - depends on COLDFIRE - select CRC32 - ---help--- - This driver is for Ethernet devices using an NS8390-compatible - chipset on many common ColdFire CPU based boards. Many of the older - Freescale dev boards use this, and some other common boards like - some SnapGear routers do as well. - - If you have one of these boards and want to use the network interface - on them then choose Y. To compile this driver as a module, choose M - here, the module will be called mcf8390. - -config NE2000 - tristate "NE2000/NE1000 support" - depends on (ISA || (Q40 && m) || M32R || MACH_TX49XX || \ - ATARI_ETHERNEC) - select CRC32 - ---help--- - If you have a network (Ethernet) card of this type, say Y here. - Many Ethernet cards without a specific driver are compatible with - the NE2000. - - If you have a PCI NE2000 card however, say N here and Y to "PCI - NE2000 and clone support" below. - - To compile this driver as a module, choose M here. The module - will be called ne. - -config NE2K_PCI - tristate "PCI NE2000 and clones support (see help)" - depends on PCI - select CRC32 - ---help--- - This driver is for NE2000 compatible PCI cards. It will not work - with ISA NE2000 cards (they have their own driver, "NE2000/NE1000 - support" below). If you have a PCI NE2000 network (Ethernet) card, - say Y here. - - This driver also works for the following NE2000 clone cards: - RealTek RTL-8029 Winbond 89C940 Compex RL2000 KTI ET32P2 - NetVin NV5000SC Via 86C926 SureCom NE34 Winbond - Holtek HT80232 Holtek HT80229 - - To compile this driver as a module, choose M here. The module - will be called ne2k-pci. - -config APNE - tristate "PCMCIA NE2000 support" - depends on AMIGA_PCMCIA - select CRC32 - ---help--- - If you have a PCMCIA NE2000 compatible adapter, say Y. Otherwise, - say N. - - To compile this driver as a module, choose M here: the module - will be called apne. - -config PCMCIA_PCNET - tristate "NE2000 compatible PCMCIA support" - depends on PCMCIA - select CRC32 - ---help--- - Say Y here if you intend to attach an NE2000 compatible PCMCIA - (PC-card) Ethernet or Fast Ethernet card to your computer. - - To compile this driver as a module, choose M here: the module will be - called pcnet_cs. If unsure, say N. - -config STNIC - tristate "National DP83902AV support" - depends on SUPERH - select CRC32 - ---help--- - Support for cards based on the National Semiconductor DP83902AV - ST-NIC Serial Network Interface Controller for Twisted Pair. This - is a 10Mbit/sec Ethernet controller. Product overview and specs at - . - - If unsure, say N. - -config ULTRA - tristate "SMC Ultra support" - depends on ISA - select CRC32 - ---help--- - If you have a network (Ethernet) card of this type, say Y here. - - Important: There have been many reports that, with some motherboards - mixing an SMC Ultra and an Adaptec AHA154x SCSI card (or compatible, - such as some BusLogic models) causes corruption problems with many - operating systems. The Linux smc-ultra driver has a work-around for - this but keep it in mind if you have such a SCSI card and have - problems. - - To compile this driver as a module, choose M here. The module - will be called smc-ultra. - -config WD80x3 - tristate "WD80*3 support" - depends on ISA - select CRC32 - ---help--- - If you have a network (Ethernet) card of this type, say Y here. - - To compile this driver as a module, choose M here. The module - will be called wd. - -config ZORRO8390 - tristate "Zorro NS8390-based Ethernet support" - depends on ZORRO - select CRC32 - ---help--- - This driver is for Zorro Ethernet cards using an NS8390-compatible - chipset, like the Village Tronic Ariadne II and the Individual - Computers X-Surf Ethernet cards. If you have such a card, say Y. - Otherwise, say N. - - To compile this driver as a module, choose M here: the module - will be called zorro8390. - -endif # NET_VENDOR_8390 diff --git a/src/linux/drivers/net/ethernet/Kconfig b/src/linux/drivers/net/ethernet/Kconfig deleted file mode 100644 index 8cc7467..0000000 --- a/src/linux/drivers/net/ethernet/Kconfig +++ /dev/null @@ -1,183 +0,0 @@ -# -# Ethernet LAN device configuration -# - -menuconfig ETHERNET - bool "Ethernet driver support" - depends on NET - default y - ---help--- - This section contains all the Ethernet device drivers. - -if ETHERNET - -config MDIO - tristate - -config SUNGEM_PHY - tristate - -source "drivers/net/ethernet/3com/Kconfig" -source "drivers/net/ethernet/adaptec/Kconfig" -source "drivers/net/ethernet/aeroflex/Kconfig" -source "drivers/net/ethernet/agere/Kconfig" -source "drivers/net/ethernet/allwinner/Kconfig" -source "drivers/net/ethernet/alteon/Kconfig" -source "drivers/net/ethernet/altera/Kconfig" -source "drivers/net/ethernet/amazon/Kconfig" -source "drivers/net/ethernet/amd/Kconfig" -source "drivers/net/ethernet/apm/Kconfig" -source "drivers/net/ethernet/apple/Kconfig" -source "drivers/net/ethernet/arc/Kconfig" -source "drivers/net/ethernet/atheros/Kconfig" -source "drivers/net/ethernet/aurora/Kconfig" -source "drivers/net/ethernet/cadence/Kconfig" -source "drivers/net/ethernet/adi/Kconfig" -source "drivers/net/ethernet/broadcom/Kconfig" -source "drivers/net/ethernet/brocade/Kconfig" -source "drivers/net/ethernet/calxeda/Kconfig" -source "drivers/net/ethernet/cavium/Kconfig" -source "drivers/net/ethernet/chelsio/Kconfig" -source "drivers/net/ethernet/cirrus/Kconfig" -source "drivers/net/ethernet/cisco/Kconfig" - -config CX_ECAT - tristate "Beckhoff CX5020 EtherCAT master support" - depends on PCI - depends on X86 || COMPILE_TEST - ---help--- - Driver for EtherCAT master module located on CCAT FPGA - that can be found on Beckhoff CX5020, and possibly other of CX - Beckhoff CX series industrial PCs. - - To compile this driver as a module, choose M here. The module - will be called ec_bhf. - -source "drivers/net/ethernet/davicom/Kconfig" - -config DNET - tristate "Dave ethernet support (DNET)" - depends on HAS_IOMEM - select PHYLIB - ---help--- - The Dave ethernet interface (DNET) is found on Qong Board FPGA. - Say Y to include support for the DNET chip. - - To compile this driver as a module, choose M here: the module - will be called dnet. - -source "drivers/net/ethernet/dec/Kconfig" -source "drivers/net/ethernet/dlink/Kconfig" -source "drivers/net/ethernet/emulex/Kconfig" -source "drivers/net/ethernet/ezchip/Kconfig" -source "drivers/net/ethernet/neterion/Kconfig" -source "drivers/net/ethernet/faraday/Kconfig" -source "drivers/net/ethernet/freescale/Kconfig" -source "drivers/net/ethernet/fujitsu/Kconfig" -source "drivers/net/ethernet/hisilicon/Kconfig" -source "drivers/net/ethernet/hp/Kconfig" -source "drivers/net/ethernet/ibm/Kconfig" -source "drivers/net/ethernet/intel/Kconfig" -source "drivers/net/ethernet/i825xx/Kconfig" -source "drivers/net/ethernet/xscale/Kconfig" - -config JME - tristate "JMicron(R) PCI-Express Gigabit Ethernet support" - depends on PCI - select CRC32 - select MII - ---help--- - This driver supports the PCI-Express gigabit ethernet adapters - based on JMicron JMC250 chipset. - - To compile this driver as a module, choose M here. The module - will be called jme. - -config KORINA - tristate "Korina (IDT RC32434) Ethernet support" - depends on MIKROTIK_RB532 - ---help--- - If you have a Mikrotik RouterBoard 500 or IDT RC32434 - based system say Y. Otherwise say N. - -config LANTIQ_ETOP - tristate "Lantiq SoC ETOP driver" - depends on SOC_TYPE_XWAY - ---help--- - Support for the MII0 inside the Lantiq SoC - -source "drivers/net/ethernet/marvell/Kconfig" -source "drivers/net/ethernet/mediatek/Kconfig" -source "drivers/net/ethernet/mellanox/Kconfig" -source "drivers/net/ethernet/micrel/Kconfig" -source "drivers/net/ethernet/microchip/Kconfig" -source "drivers/net/ethernet/moxa/Kconfig" -source "drivers/net/ethernet/myricom/Kconfig" - -config FEALNX - tristate "Myson MTD-8xx PCI Ethernet support" - depends on PCI - select CRC32 - select MII - ---help--- - Say Y here to support the Myson MTD-800 family of PCI-based Ethernet - cards. - -source "drivers/net/ethernet/natsemi/Kconfig" -source "drivers/net/ethernet/netronome/Kconfig" -source "drivers/net/ethernet/8390/Kconfig" - -config NET_NETX - tristate "NetX Ethernet support" - select MII - depends on ARCH_NETX - ---help--- - This is support for the Hilscher netX builtin Ethernet ports - - To compile this driver as a module, choose M here. The module - will be called netx-eth. - -source "drivers/net/ethernet/nuvoton/Kconfig" -source "drivers/net/ethernet/nvidia/Kconfig" -source "drivers/net/ethernet/nxp/Kconfig" -source "drivers/net/ethernet/oki-semi/Kconfig" - -config ETHOC - tristate "OpenCores 10/100 Mbps Ethernet MAC support" - depends on HAS_IOMEM && HAS_DMA - select MII - select PHYLIB - select CRC32 - select BITREVERSE - ---help--- - Say Y here if you want to use the OpenCores 10/100 Mbps Ethernet MAC. - -source "drivers/net/ethernet/packetengines/Kconfig" -source "drivers/net/ethernet/pasemi/Kconfig" -source "drivers/net/ethernet/qlogic/Kconfig" -source "drivers/net/ethernet/qualcomm/Kconfig" -source "drivers/net/ethernet/realtek/Kconfig" -source "drivers/net/ethernet/renesas/Kconfig" -source "drivers/net/ethernet/rdc/Kconfig" -source "drivers/net/ethernet/rocker/Kconfig" -source "drivers/net/ethernet/samsung/Kconfig" -source "drivers/net/ethernet/seeq/Kconfig" -source "drivers/net/ethernet/silan/Kconfig" -source "drivers/net/ethernet/sis/Kconfig" -source "drivers/net/ethernet/sfc/Kconfig" -source "drivers/net/ethernet/sgi/Kconfig" -source "drivers/net/ethernet/smsc/Kconfig" -source "drivers/net/ethernet/stmicro/Kconfig" -source "drivers/net/ethernet/sun/Kconfig" -source "drivers/net/ethernet/synopsys/Kconfig" -source "drivers/net/ethernet/tehuti/Kconfig" -source "drivers/net/ethernet/ti/Kconfig" -source "drivers/net/ethernet/tile/Kconfig" -source "drivers/net/ethernet/toshiba/Kconfig" -source "drivers/net/ethernet/tundra/Kconfig" -source "drivers/net/ethernet/via/Kconfig" -source "drivers/net/ethernet/wiznet/Kconfig" -source "drivers/net/ethernet/xilinx/Kconfig" -source "drivers/net/ethernet/xircom/Kconfig" - -endif # ETHERNET diff --git a/src/linux/drivers/net/ethernet/adaptec/Kconfig b/src/linux/drivers/net/ethernet/adaptec/Kconfig deleted file mode 100644 index 822cffb..0000000 --- a/src/linux/drivers/net/ethernet/adaptec/Kconfig +++ /dev/null @@ -1,33 +0,0 @@ -# -# Adaptec network device configuration -# - -config NET_VENDOR_ADAPTEC - bool "Adaptec devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Adaptec cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_ADAPTEC - -config ADAPTEC_STARFIRE - tristate "Adaptec Starfire/DuraLAN support" - depends on PCI - select CRC32 - select MII - ---help--- - Say Y here if you have an Adaptec Starfire (or DuraLAN) PCI network - adapter. The DuraLAN chip is used on the 64 bit PCI boards from - Adaptec e.g. the ANA-6922A. The older 32 bit boards use the tulip - driver. - - To compile this driver as a module, choose M here: the module - will be called starfire. This is recommended. - -endif # NET_VENDOR_ADAPTEC diff --git a/src/linux/drivers/net/ethernet/adi/Kconfig b/src/linux/drivers/net/ethernet/adi/Kconfig deleted file mode 100644 index 6b94ba6..0000000 --- a/src/linux/drivers/net/ethernet/adi/Kconfig +++ /dev/null @@ -1,66 +0,0 @@ -# -# Blackfin device configuration -# - -config NET_BFIN - bool "Blackfin devices" - depends on BF516 || BF518 || BF526 || BF527 || BF536 || BF537 - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - If unsure, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the remaining Blackfin card questions. If you say Y, you will be - asked for your specific card in the following questions. - -if NET_BFIN - -config BFIN_MAC - tristate "Blackfin on-chip MAC support" - depends on (BF516 || BF518 || BF526 || BF527 || BF536 || BF537) - select CRC32 - select MII - select PHYLIB - select BFIN_MAC_USE_L1 if DMA_UNCACHED_NONE - ---help--- - This is the driver for Blackfin on-chip mac device. Say Y if you want - it compiled into the kernel. This driver is also available as a - module ( = code which can be inserted in and removed from the running - kernel whenever you want). The module will be called bfin_mac. - -config BFIN_MAC_USE_L1 - bool "Use L1 memory for rx/tx packets" - depends on BFIN_MAC && (BF527 || BF537) - default y - ---help--- - To get maximum network performance, you should use L1 memory as rx/tx - buffers. Say N here if you want to reserve L1 memory for other uses. - -config BFIN_TX_DESC_NUM - int "Number of transmit buffer packets" - depends on BFIN_MAC - range 6 10 if BFIN_MAC_USE_L1 - range 10 100 - default "10" - ---help--- - Set the number of buffer packets used in driver. - -config BFIN_RX_DESC_NUM - int "Number of receive buffer packets" - depends on BFIN_MAC - range 20 64 - default "20" - ---help--- - Set the number of buffer packets used in driver. - -config BFIN_MAC_USE_HWSTAMP - bool "Use IEEE 1588 hwstamp" - depends on BFIN_MAC && BF518 - select PTP_1588_CLOCK - default y - ---help--- - To support the IEEE 1588 Precision Time Protocol (PTP), select y here - -endif # NET_BFIN diff --git a/src/linux/drivers/net/ethernet/aeroflex/Kconfig b/src/linux/drivers/net/ethernet/aeroflex/Kconfig deleted file mode 100644 index 4f4a8d7..0000000 --- a/src/linux/drivers/net/ethernet/aeroflex/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -# -# Aeroflex Gaisler network device configuration -# - -config GRETH - tristate "Aeroflex Gaisler GRETH Ethernet MAC support" - depends on SPARC - select PHYLIB - select CRC32 - ---help--- - Say Y here if you want to use the Aeroflex Gaisler GRETH Ethernet MAC. diff --git a/src/linux/drivers/net/ethernet/agere/Kconfig b/src/linux/drivers/net/ethernet/agere/Kconfig deleted file mode 100644 index b6fe920..0000000 --- a/src/linux/drivers/net/ethernet/agere/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -# -# Agere device configuration -# - -config NET_VENDOR_AGERE - bool "Agere devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Agere devices. If you say Y, you will be asked - for your specific card in the following questions. - -if NET_VENDOR_AGERE - -config ET131X - tristate "Agere ET-1310 Gigabit Ethernet support" - depends on PCI - select PHYLIB - ---help--- - This driver supports Agere ET-1310 ethernet adapters. - - To compile this driver as a module, choose M here. The module - will be called et131x. - -endif # NET_VENDOR_AGERE diff --git a/src/linux/drivers/net/ethernet/allwinner/Kconfig b/src/linux/drivers/net/ethernet/allwinner/Kconfig deleted file mode 100644 index 47da7e7..0000000 --- a/src/linux/drivers/net/ethernet/allwinner/Kconfig +++ /dev/null @@ -1,36 +0,0 @@ -# -# Allwinner device configuration -# - -config NET_VENDOR_ALLWINNER - bool "Allwinner devices" - default y - - depends on ARCH_SUNXI - ---help--- - If you have a network (Ethernet) card belonging to this - class, say Y here. - - Note that the answer to this question doesn't directly - affect the kernel: saying N will just cause the configurator - to skip all the questions about Allwinner cards. If you say Y, - you will be asked for your specific card in the following - questions. - -if NET_VENDOR_ALLWINNER - -config SUN4I_EMAC - tristate "Allwinner A10 EMAC support" - depends on ARCH_SUNXI - depends on OF - select CRC32 - select MII - select PHYLIB - select MDIO_SUN4I - ---help--- - Support for Allwinner A10 EMAC ethernet driver. - - To compile this driver as a module, choose M here. The module - will be called sun4i-emac. - -endif # NET_VENDOR_ALLWINNER diff --git a/src/linux/drivers/net/ethernet/alteon/Kconfig b/src/linux/drivers/net/ethernet/alteon/Kconfig deleted file mode 100644 index e06ccab..0000000 --- a/src/linux/drivers/net/ethernet/alteon/Kconfig +++ /dev/null @@ -1,46 +0,0 @@ -# -# Alteon network device configuration -# - -config NET_VENDOR_ALTEON - bool "Alteon devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Alteon cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_ALTEON - -config ACENIC - tristate "Alteon AceNIC/3Com 3C985/NetGear GA620 Gigabit support" - depends on PCI - ---help--- - Say Y here if you have an Alteon AceNIC, 3Com 3C985(B), NetGear - GA620, SGI Gigabit or Farallon PN9000-SX PCI Gigabit Ethernet - adapter. The driver allows for using the Jumbo Frame option (9000 - bytes/frame) however it requires that your switches can handle this - as well. To enable Jumbo Frames, add `mtu 9000' to your ifconfig - line. - - To compile this driver as a module, choose M here: the - module will be called acenic. - -config ACENIC_OMIT_TIGON_I - bool "Omit support for old Tigon I based AceNICs" - depends on ACENIC - ---help--- - Say Y here if you only have Tigon II based AceNICs and want to leave - out support for the older Tigon I based cards which are no longer - being sold (ie. the original Alteon AceNIC and 3Com 3C985 (non B - version)). This will reduce the size of the driver object by - app. 100KB. If you are not sure whether your card is a Tigon I or a - Tigon II, say N here. - - The safe and default value for this is N. - -endif # NET_VENDOR_ALTEON diff --git a/src/linux/drivers/net/ethernet/altera/Kconfig b/src/linux/drivers/net/ethernet/altera/Kconfig deleted file mode 100644 index fdddba5..0000000 --- a/src/linux/drivers/net/ethernet/altera/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config ALTERA_TSE - tristate "Altera Triple-Speed Ethernet MAC support" - depends on HAS_DMA - select PHYLIB - ---help--- - This driver supports the Altera Triple-Speed (TSE) Ethernet MAC. - - To compile this driver as a module, choose M here. The module - will be called alteratse. diff --git a/src/linux/drivers/net/ethernet/amazon/Kconfig b/src/linux/drivers/net/ethernet/amazon/Kconfig deleted file mode 100644 index 99b3035..0000000 --- a/src/linux/drivers/net/ethernet/amazon/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -# -# Amazon network device configuration -# - -config NET_VENDOR_AMAZON - bool "Amazon Devices" - default y - ---help--- - If you have a network (Ethernet) device belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Amazon devices. If you say Y, you will be asked - for your specific device in the following questions. - -if NET_VENDOR_AMAZON - -config ENA_ETHERNET - tristate "Elastic Network Adapter (ENA) support" - depends on (PCI_MSI && X86) - ---help--- - This driver supports Elastic Network Adapter (ENA)" - - To compile this driver as a module, choose M here. - The module will be called ena. - -endif #NET_VENDOR_AMAZON diff --git a/src/linux/drivers/net/ethernet/amd/Kconfig b/src/linux/drivers/net/ethernet/amd/Kconfig deleted file mode 100644 index 0038709..0000000 --- a/src/linux/drivers/net/ethernet/amd/Kconfig +++ /dev/null @@ -1,198 +0,0 @@ -# -# AMD network device configuration -# - -config NET_VENDOR_AMD - bool "AMD devices" - default y - depends on DIO || MACH_DECSTATION || MVME147 || ATARI || SUN3 || \ - SUN3X || SBUS || PCI || ZORRO || (ISA && ISA_DMA_API) || \ - (ARM && ARCH_EBSA110) || ISA || EISA || PCMCIA || ARM64 - ---help--- - If you have a network (Ethernet) chipset belonging to this class, - say Y. - - Note that the answer to this question does not directly affect - the kernel: saying N will just case the configurator to skip all - the questions regarding AMD chipsets. If you say Y, you will be asked - for your specific chipset/driver in the following questions. - -if NET_VENDOR_AMD - -config A2065 - tristate "A2065 support" - depends on ZORRO - select CRC32 - ---help--- - If you have a Commodore A2065 Ethernet adapter, say Y. Otherwise, - say N. - - To compile this driver as a module, choose M here: the module - will be called a2065. - -config AMD8111_ETH - tristate "AMD 8111 (new PCI LANCE) support" - depends on PCI - select CRC32 - select MII - ---help--- - If you have an AMD 8111-based PCI LANCE ethernet card, - answer Y here. - - To compile this driver as a module, choose M here. The module - will be called amd8111e. - -config LANCE - tristate "AMD LANCE and PCnet (AT1500 and NE2100) support" - depends on ISA && ISA_DMA_API && !ARM - ---help--- - If you have a network (Ethernet) card of this type, say Y here. - Some LinkSys cards are of this type. - - To compile this driver as a module, choose M here: the module - will be called lance. This is recommended. - -config PCNET32 - tristate "AMD PCnet32 PCI support" - depends on PCI - select CRC32 - select MII - ---help--- - If you have a PCnet32 or PCnetPCI based network (Ethernet) card, - answer Y here. - - To compile this driver as a module, choose M here. The module - will be called pcnet32. - -config ARIADNE - tristate "Ariadne support" - depends on ZORRO - ---help--- - If you have a Village Tronic Ariadne Ethernet adapter, say Y. - Otherwise, say N. - - To compile this driver as a module, choose M here: the module - will be called ariadne. - -config ARM_AM79C961A - bool "ARM EBSA110 AM79C961A support" - depends on ARM && ARCH_EBSA110 - select CRC32 - ---help--- - If you wish to compile a kernel for the EBSA-110, then you should - always answer Y to this. - -config ATARILANCE - tristate "Atari LANCE support" - depends on ATARI - ---help--- - Say Y to include support for several Atari Ethernet adapters based - on the AMD LANCE chipset: RieblCard (with or without battery), or - PAMCard VME (also the version by Rhotron, with different addresses). - -config DECLANCE - tristate "DEC LANCE ethernet controller support" - depends on MACH_DECSTATION - select CRC32 - ---help--- - This driver is for the series of Ethernet controllers produced by - DEC (now Compaq) based on the AMD LANCE chipset, including the - DEPCA series. (This chipset is better known via the NE2100 cards.) - -config HPLANCE - tristate "HP on-board LANCE support" - depends on DIO - select CRC32 - ---help--- - If you want to use the builtin "LANCE" Ethernet controller on an - HP300 machine, say Y here. - -config MIPS_AU1X00_ENET - tristate "MIPS AU1000 Ethernet support" - depends on MIPS_ALCHEMY - select PHYLIB - select CRC32 - ---help--- - If you have an Alchemy Semi AU1X00 based system - say Y. Otherwise, say N. - -config MVME147_NET - tristate "MVME147 (LANCE) Ethernet support" - depends on MVME147 - select CRC32 - ---help--- - Support for the on-board Ethernet interface on the Motorola MVME147 - single-board computer. Say Y here to include the - driver for this chip in your kernel. - To compile this driver as a module, choose M here. - -config PCMCIA_NMCLAN - tristate "New Media PCMCIA support" - depends on PCMCIA - help - Say Y here if you intend to attach a New Media Ethernet or LiveWire - PCMCIA (PC-card) Ethernet card to your computer. - - To compile this driver as a module, choose M here: the module will be - called nmclan_cs. If unsure, say N. - -config NI65 - tristate "NI6510 support" - depends on ISA && ISA_DMA_API && !ARM - ---help--- - If you have a network (Ethernet) card of this type, say Y here. - - To compile this driver as a module, choose M here. The module - will be called ni65. - -config SUN3LANCE - tristate "Sun3/Sun3x on-board LANCE support" - depends on (SUN3 || SUN3X) - ---help--- - Most Sun3 and Sun3x motherboards (including the 3/50, 3/60 and 3/80) - featured an AMD LANCE 10Mbit Ethernet controller on board; say Y - here to compile in the Linux driver for this and enable Ethernet. - General Linux information on the Sun 3 and 3x series (now - discontinued) is at - . - - If you're not building a kernel for a Sun 3, say N. - -config SUNLANCE - tristate "Sun LANCE support" - depends on SBUS - select CRC32 - ---help--- - This driver supports the "le" interface present on all 32-bit Sparc - systems, on some older Ultra systems and as an Sbus option. These - cards are based on the AMD LANCE chipset, which is better known - via the NE2100 cards. - - To compile this driver as a module, choose M here: the module - will be called sunlance. - -config AMD_XGBE - tristate "AMD 10GbE Ethernet driver" - depends on ((OF_NET && OF_ADDRESS) || ACPI) && HAS_IOMEM && HAS_DMA - depends on ARM64 || COMPILE_TEST - select BITREVERSE - select CRC32 - select PTP_1588_CLOCK - ---help--- - This driver supports the AMD 10GbE Ethernet device found on an - AMD SoC. - - To compile this driver as a module, choose M here: the module - will be called amd-xgbe. - -config AMD_XGBE_DCB - bool "Data Center Bridging (DCB) support" - default n - depends on AMD_XGBE && DCB - ---help--- - Say Y here to enable Data Center Bridging (DCB) support in the - driver. - - If unsure, say N. - -endif # NET_VENDOR_AMD diff --git a/src/linux/drivers/net/ethernet/apm/Kconfig b/src/linux/drivers/net/ethernet/apm/Kconfig deleted file mode 100644 index ec63d70..0000000 --- a/src/linux/drivers/net/ethernet/apm/Kconfig +++ /dev/null @@ -1 +0,0 @@ -source "drivers/net/ethernet/apm/xgene/Kconfig" diff --git a/src/linux/drivers/net/ethernet/apm/xgene/Kconfig b/src/linux/drivers/net/ethernet/apm/xgene/Kconfig deleted file mode 100644 index afccb03..0000000 --- a/src/linux/drivers/net/ethernet/apm/xgene/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config NET_XGENE - tristate "APM X-Gene SoC Ethernet Driver" - depends on HAS_DMA - depends on ARCH_XGENE || COMPILE_TEST - select PHYLIB - select MDIO_XGENE - select GPIOLIB - help - This is the Ethernet driver for the on-chip ethernet interface on the - APM X-Gene SoC. - - To compile this driver as a module, choose M here. This module will - be called xgene_enet. diff --git a/src/linux/drivers/net/ethernet/apple/Kconfig b/src/linux/drivers/net/ethernet/apple/Kconfig deleted file mode 100644 index 3107129..0000000 --- a/src/linux/drivers/net/ethernet/apple/Kconfig +++ /dev/null @@ -1,62 +0,0 @@ -# -# Apple device configuration -# - -config NET_VENDOR_APPLE - bool "Apple devices" - default y - depends on (PPC_PMAC && PPC32) || MAC - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about IBM devices. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_APPLE - -config MACE - tristate "MACE (Power Mac ethernet) support" - depends on PPC_PMAC && PPC32 - select CRC32 - ---help--- - Power Macintoshes and clones with Ethernet built-in on the - motherboard will usually use a MACE (Medium Access Control for - Ethernet) interface. Say Y to include support for the MACE chip. - - To compile this driver as a module, choose M here: the module - will be called mace. - -config MACE_AAUI_PORT - bool "Use AAUI port instead of TP by default" - depends on MACE - ---help--- - Some Apple machines (notably the Apple Network Server) which use the - MACE ethernet chip have an Apple AUI port (small 15-pin connector), - instead of an 8-pin RJ45 connector for twisted-pair ethernet. Say - Y here if you have such a machine. If unsure, say N. - The driver will default to AAUI on ANS anyway, and if you use it as - a module, you can provide the port_aaui=0|1 to force the driver. - -config BMAC - tristate "BMAC (G3 ethernet) support" - depends on PPC_PMAC && PPC32 - select CRC32 - ---help--- - Say Y for support of BMAC Ethernet interfaces. These are used on G3 - computers. - - To compile this driver as a module, choose M here: the module - will be called bmac. - -config MACMACE - tristate "Macintosh (AV) onboard MACE ethernet" - depends on MAC - select CRC32 - ---help--- - Support for the onboard AMD 79C940 MACE Ethernet controller used in - the 660AV and 840AV Macintosh. If you have one of these Macintoshes - say Y here. - -endif # NET_VENDOR_APPLE diff --git a/src/linux/drivers/net/ethernet/arc/Kconfig b/src/linux/drivers/net/ethernet/arc/Kconfig deleted file mode 100644 index 6890451..0000000 --- a/src/linux/drivers/net/ethernet/arc/Kconfig +++ /dev/null @@ -1,42 +0,0 @@ -# -# ARC EMAC network device configuration -# - -config NET_VENDOR_ARC - bool "ARC devices" - default y - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about ARC cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_ARC - -config ARC_EMAC_CORE - tristate - select MII - select PHYLIB - -config ARC_EMAC - tristate "ARC EMAC support" - select ARC_EMAC_CORE - depends on OF_IRQ && OF_NET && HAS_DMA - ---help--- - On some legacy ARC (Synopsys) FPGA boards such as ARCAngel4/ML50x - non-standard on-chip ethernet device ARC EMAC 10/100 is used. - Say Y here if you have such a board. If unsure, say N. - -config EMAC_ROCKCHIP - tristate "Rockchip EMAC support" - select ARC_EMAC_CORE - depends on OF_IRQ && OF_NET && REGULATOR && HAS_DMA - ---help--- - Support for Rockchip RK3036/RK3066/RK3188 EMAC ethernet controllers. - This selects Rockchip SoC glue layer support for the - emac device driver. This driver is used for RK3036/RK3066/RK3188 - EMAC ethernet controller. - -endif # NET_VENDOR_ARC diff --git a/src/linux/drivers/net/ethernet/atheros/Kconfig b/src/linux/drivers/net/ethernet/atheros/Kconfig deleted file mode 100644 index e05b256..0000000 --- a/src/linux/drivers/net/ethernet/atheros/Kconfig +++ /dev/null @@ -1,81 +0,0 @@ -# -# Atheros device configuration -# - -config NET_VENDOR_ATHEROS - bool "Atheros devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Atheros devices. If you say Y, you will be asked - for your specific card in the following questions. - -if NET_VENDOR_ATHEROS - -config ATL2 - tristate "Atheros L2 Fast Ethernet support" - depends on PCI - select CRC32 - select MII - ---help--- - This driver supports the Atheros L2 fast ethernet adapter. - - To compile this driver as a module, choose M here. The module - will be called atl2. - -config ATL1 - tristate "Atheros/Attansic L1 Gigabit Ethernet support" - depends on PCI - select CRC32 - select MII - ---help--- - This driver supports the Atheros/Attansic L1 gigabit ethernet - adapter. - - To compile this driver as a module, choose M here. The module - will be called atl1. - -config ATL1E - tristate "Atheros L1E Gigabit Ethernet support" - depends on PCI - select CRC32 - select MII - ---help--- - This driver supports the Atheros L1E gigabit ethernet adapter. - - To compile this driver as a module, choose M here. The module - will be called atl1e. - -config ATL1C - tristate "Atheros L1C Gigabit Ethernet support" - depends on PCI - select CRC32 - select MII - ---help--- - This driver supports the Atheros L1C gigabit ethernet adapter. - - To compile this driver as a module, choose M here. The module - will be called atl1c. - -config ALX - tristate "Qualcomm Atheros AR816x/AR817x support" - depends on PCI - select CRC32 - select MDIO - help - This driver supports the Qualcomm Atheros L1F ethernet adapter, - i.e. the following chipsets: - - 1969:1091 - AR8161 Gigabit Ethernet - 1969:1090 - AR8162 Fast Ethernet - 1969:10A1 - AR8171 Gigabit Ethernet - 1969:10A0 - AR8172 Fast Ethernet - - To compile this driver as a module, choose M here. The module - will be called alx. - -endif # NET_VENDOR_ATHEROS diff --git a/src/linux/drivers/net/ethernet/aurora/Kconfig b/src/linux/drivers/net/ethernet/aurora/Kconfig deleted file mode 100644 index 8ba7f8f..0000000 --- a/src/linux/drivers/net/ethernet/aurora/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -config NET_VENDOR_AURORA - bool "Aurora VLSI devices" - help - If you have a network (Ethernet) device belonging to this class, - say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - questions about Aurora devices. If you say Y, you will be asked - for your specific device in the following questions. - -if NET_VENDOR_AURORA - -config AURORA_NB8800 - tristate "Aurora AU-NB8800 support" - depends on HAS_DMA - select PHYLIB - help - Support for the AU-NB8800 gigabit Ethernet controller. - -endif diff --git a/src/linux/drivers/net/ethernet/broadcom/Kconfig b/src/linux/drivers/net/ethernet/broadcom/Kconfig deleted file mode 100644 index bd8c80c..0000000 --- a/src/linux/drivers/net/ethernet/broadcom/Kconfig +++ /dev/null @@ -1,206 +0,0 @@ -# -# Broadcom device configuration -# - -config NET_VENDOR_BROADCOM - bool "Broadcom devices" - default y - depends on (SSB_POSSIBLE && HAS_DMA) || PCI || BCM63XX || \ - SIBYTE_SB1xxx_SOC - ---help--- - If you have a network (Ethernet) chipset belonging to this class, - say Y. - - Note that the answer to this question does not directly affect - the kernel: saying N will just case the configurator to skip all - the questions regarding AMD chipsets. If you say Y, you will be asked - for your specific chipset/driver in the following questions. - -if NET_VENDOR_BROADCOM - -config B44 - tristate "Broadcom 440x/47xx ethernet support" - depends on SSB_POSSIBLE && HAS_DMA - select SSB - select MII - select PHYLIB - ---help--- - If you have a network (Ethernet) controller of this type, say Y - or M here. - - To compile this driver as a module, choose M here. The module - will be called b44. - -# Auto-select SSB PCI-HOST support, if possible -config B44_PCI_AUTOSELECT - bool - depends on B44 && SSB_PCIHOST_POSSIBLE - select SSB_PCIHOST - default y - -# Auto-select SSB PCICORE driver, if possible -config B44_PCICORE_AUTOSELECT - bool - depends on B44 && SSB_DRIVER_PCICORE_POSSIBLE - select SSB_DRIVER_PCICORE - default y - -config B44_PCI - bool - depends on B44_PCI_AUTOSELECT && B44_PCICORE_AUTOSELECT - default y - -config BCM63XX_ENET - tristate "Broadcom 63xx internal mac support" - depends on BCM63XX - select MII - select PHYLIB - help - This driver supports the ethernet MACs in the Broadcom 63xx - MIPS chipset family (BCM63XX). - -config BCMGENET - tristate "Broadcom GENET internal MAC support" - select MII - select PHYLIB - select FIXED_PHY - select BCM7XXX_PHY - help - This driver supports the built-in Ethernet MACs found in the - Broadcom BCM7xxx Set Top Box family chipset. - -config BNX2 - tristate "QLogic bnx2 support" - depends on PCI - select CRC32 - select FW_LOADER - ---help--- - This driver supports QLogic bnx2 gigabit Ethernet cards. - - To compile this driver as a module, choose M here: the module - will be called bnx2. This is recommended. - -config CNIC - tristate "QLogic CNIC support" - depends on PCI && (IPV6 || IPV6=n) - select BNX2 - select UIO - ---help--- - This driver supports offload features of QLogic bnx2 gigabit - Ethernet cards. - - To compile this driver as a module, choose M here: the module - will be called cnic. This is recommended. - -config SB1250_MAC - tristate "SB1250 Gigabit Ethernet support" - depends on SIBYTE_SB1xxx_SOC - select PHYLIB - ---help--- - This driver supports Gigabit Ethernet interfaces based on the - Broadcom SiByte family of System-On-a-Chip parts. They include - the BCM1120, BCM1125, BCM1125H, BCM1250, BCM1255, BCM1280, BCM1455 - and BCM1480 chips. - - To compile this driver as a module, choose M here: the module - will be called sb1250-mac. - -config TIGON3 - tristate "Broadcom Tigon3 support" - depends on PCI - select PHYLIB - select HWMON - select PTP_1588_CLOCK - ---help--- - This driver supports Broadcom Tigon3 based gigabit Ethernet cards. - - To compile this driver as a module, choose M here: the module - will be called tg3. This is recommended. - -config BNX2X - tristate "Broadcom NetXtremeII 10Gb support" - depends on PCI - select PTP_1588_CLOCK - select FW_LOADER - select ZLIB_INFLATE - select LIBCRC32C - select MDIO - ---help--- - This driver supports Broadcom NetXtremeII 10 gigabit Ethernet cards. - To compile this driver as a module, choose M here: the module - will be called bnx2x. This is recommended. - -config BNX2X_SRIOV - bool "Broadcom 578xx and 57712 SR-IOV support" - depends on BNX2X && PCI_IOV - default y - ---help--- - This configuration parameter enables Single Root Input Output - Virtualization support in the 578xx and 57712 products. This - allows for virtual function acceleration in virtual environments. - -config BGMAC - tristate - help - This enables the integrated ethernet controller support for many - Broadcom (mostly iProc) SoCs. An appropriate bus interface driver - needs to be enabled to select this. - -config BGMAC_BCMA - tristate "Broadcom iProc GBit BCMA support" - depends on BCMA && BCMA_HOST_SOC - depends on HAS_DMA - depends on BCM47XX || ARCH_BCM_5301X || COMPILE_TEST - select BGMAC - select PHYLIB - select FIXED_PHY - ---help--- - This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus. - They can be found on BCM47xx SoCs and provide gigabit ethernet. - In case of using this driver on BCM4706 it's also requires to enable - BCMA_DRIVER_GMAC_CMN to make it work. - -config BGMAC_PLATFORM - tristate "Broadcom iProc GBit platform support" - depends on HAS_DMA - depends on ARCH_BCM_IPROC || COMPILE_TEST - depends on OF - select BGMAC - select PHYLIB - select FIXED_PHY - default ARCH_BCM_IPROC - ---help--- - Say Y here if you want to use the Broadcom iProc Gigabit Ethernet - controller through the generic platform interface - -config SYSTEMPORT - tristate "Broadcom SYSTEMPORT internal MAC support" - depends on OF - select MII - select PHYLIB - select FIXED_PHY - help - This driver supports the built-in Ethernet MACs found in the - Broadcom BCM7xxx Set Top Box family chipset using an internal - Ethernet switch. - -config BNXT - tristate "Broadcom NetXtreme-C/E support" - depends on PCI - select FW_LOADER - select LIBCRC32C - ---help--- - This driver supports Broadcom NetXtreme-C/E 10/25/40/50 gigabit - Ethernet cards. To compile this driver as a module, choose M here: - the module will be called bnxt_en. This is recommended. - -config BNXT_SRIOV - bool "Broadcom NetXtreme-C/E SR-IOV support" - depends on BNXT && PCI_IOV - default y - ---help--- - This configuration parameter enables Single Root Input Output - Virtualization support in the NetXtreme-C/E products. This - allows for virtual function acceleration in virtual environments. - -endif # NET_VENDOR_BROADCOM diff --git a/src/linux/drivers/net/ethernet/brocade/Kconfig b/src/linux/drivers/net/ethernet/brocade/Kconfig deleted file mode 100644 index c4bbe54..0000000 --- a/src/linux/drivers/net/ethernet/brocade/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -# -# QLogic BR-series device configuration -# - -config NET_VENDOR_BROCADE - bool "QLogic BR-series devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about QLogic BR-series cards. If you say Y, you will be - asked for your specific card in the following questions. - -if NET_VENDOR_BROCADE - -source "drivers/net/ethernet/brocade/bna/Kconfig" - -endif # NET_VENDOR_BROCADE diff --git a/src/linux/drivers/net/ethernet/brocade/bna/Kconfig b/src/linux/drivers/net/ethernet/brocade/bna/Kconfig deleted file mode 100644 index fe01279..0000000 --- a/src/linux/drivers/net/ethernet/brocade/bna/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -# -# QLogic BR-series network device configuration -# - -config BNA - tristate "QLogic BR-series 1010/1020/1860 10Gb Ethernet Driver support" - depends on PCI - ---help--- - This driver supports QLogic BR-series 1010/1020/1860 10Gb CEE capable - Ethernet cards. - To compile this driver as a module, choose M here: the module - will be called bna. - - For general information and support, go to the QLogic support - website at: - - diff --git a/src/linux/drivers/net/ethernet/cadence/Kconfig b/src/linux/drivers/net/ethernet/cadence/Kconfig deleted file mode 100644 index f0bcb15..0000000 --- a/src/linux/drivers/net/ethernet/cadence/Kconfig +++ /dev/null @@ -1,34 +0,0 @@ -# -# Atmel device configuration -# - -config NET_CADENCE - bool "Cadence devices" - depends on HAS_IOMEM - default y - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - If unsure, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the remaining Atmel network card questions. If you say Y, you will be - asked for your specific card in the following questions. - -if NET_CADENCE - -config MACB - tristate "Cadence MACB/GEM support" - depends on HAS_DMA - select PHYLIB - ---help--- - The Cadence MACB ethernet interface is found on many Atmel AT32 and - AT91 parts. This driver also supports the Cadence GEM (Gigabit - Ethernet MAC found in some ARM SoC devices). Say Y to include - support for the MACB/GEM chip. - - To compile this driver as a module, choose M here: the module - will be called macb. - -endif # NET_CADENCE diff --git a/src/linux/drivers/net/ethernet/calxeda/Kconfig b/src/linux/drivers/net/ethernet/calxeda/Kconfig deleted file mode 100644 index 07d2201..0000000 --- a/src/linux/drivers/net/ethernet/calxeda/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config NET_CALXEDA_XGMAC - tristate "Calxeda 1G/10G XGMAC Ethernet driver" - depends on HAS_IOMEM && HAS_DMA - depends on ARCH_HIGHBANK || COMPILE_TEST - select CRC32 - help - This is the driver for the XGMAC Ethernet IP block found on Calxeda - Highbank platforms. diff --git a/src/linux/drivers/net/ethernet/cavium/Kconfig b/src/linux/drivers/net/ethernet/cavium/Kconfig deleted file mode 100644 index 92f411c..0000000 --- a/src/linux/drivers/net/ethernet/cavium/Kconfig +++ /dev/null @@ -1,77 +0,0 @@ -# -# Cavium ethernet device configuration -# - -config NET_VENDOR_CAVIUM - bool "Cavium ethernet drivers" - depends on PCI - default y - ---help--- - Select this option if you want enable Cavium network support. - - If you have a Cavium SoC or network adapter, say Y. - -if NET_VENDOR_CAVIUM - -config THUNDER_NIC_PF - tristate "Thunder Physical function driver" - depends on 64BIT - select THUNDER_NIC_BGX - ---help--- - This driver supports Thunder's NIC physical function. - The NIC provides the controller and DMA engines to - move network traffic to/from the memory. The NIC - works closely with TNS, BGX and SerDes to implement the - functions replacing and virtualizing those of a typical - standalone PCIe NIC chip. - -config THUNDER_NIC_VF - tristate "Thunder Virtual function driver" - depends on 64BIT - ---help--- - This driver supports Thunder's NIC virtual function - -config THUNDER_NIC_BGX - tristate "Thunder MAC interface driver (BGX)" - depends on 64BIT - select PHYLIB - select MDIO_THUNDER - select THUNDER_NIC_RGX - ---help--- - This driver supports programming and controlling of MAC - interface from NIC physical function driver. - -config THUNDER_NIC_RGX - tristate "Thunder MAC interface driver (RGX)" - depends on 64BIT - select PHYLIB - select MDIO_THUNDER - ---help--- - This driver supports configuring XCV block of RGX interface - present on CN81XX chip. - -config LIQUIDIO - tristate "Cavium LiquidIO support" - depends on 64BIT - select PTP_1588_CLOCK - select FW_LOADER - select LIBCRC32C - ---help--- - This driver supports Cavium LiquidIO Intelligent Server Adapters - based on CN66XX, CN68XX and CN23XX chips. - - To compile this driver as a module, choose M here: the module - will be called liquidio. This is recommended. - -config OCTEON_MGMT_ETHERNET - tristate "Octeon Management port ethernet driver (CN5XXX, CN6XXX)" - depends on CAVIUM_OCTEON_SOC - select PHYLIB - select MDIO_OCTEON - default y - help - Enable the ethernet driver for the management - port on Cavium Networks' Octeon CN57XX, CN56XX, CN55XX, - CN54XX, CN52XX, and CN6XXX chips. - -endif # NET_VENDOR_CAVIUM diff --git a/src/linux/drivers/net/ethernet/chelsio/Kconfig b/src/linux/drivers/net/ethernet/chelsio/Kconfig deleted file mode 100644 index 5713e83..0000000 --- a/src/linux/drivers/net/ethernet/chelsio/Kconfig +++ /dev/null @@ -1,134 +0,0 @@ -# -# Chelsio device configuration -# - -config NET_VENDOR_CHELSIO - bool "Chelsio devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Chelsio devices. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_CHELSIO - -config CHELSIO_T1 - tristate "Chelsio 10Gb Ethernet support" - depends on PCI - select CRC32 - select MDIO - ---help--- - This driver supports Chelsio gigabit and 10-gigabit - Ethernet cards. More information about adapter features and - performance tuning is in . - - For general information about Chelsio and our products, visit - our website at . - - For customer support, please visit our customer support page at - . - - Please send feedback to . - - To compile this driver as a module, choose M here: the module - will be called cxgb. - -config CHELSIO_T1_1G - bool "Chelsio gigabit Ethernet support" - depends on CHELSIO_T1 - ---help--- - Enables support for Chelsio's gigabit Ethernet PCI cards. If you - are using only 10G cards say 'N' here. - -config CHELSIO_T3 - tristate "Chelsio Communications T3 10Gb Ethernet support" - depends on PCI && INET - select FW_LOADER - select MDIO - ---help--- - This driver supports Chelsio T3-based gigabit and 10Gb Ethernet - adapters. - - For general information about Chelsio and our products, visit - our website at . - - For customer support, please visit our customer support page at - . - - Please send feedback to . - - To compile this driver as a module, choose M here: the module - will be called cxgb3. - -config CHELSIO_T4 - tristate "Chelsio Communications T4/T5/T6 Ethernet support" - depends on PCI && (IPV6 || IPV6=n) - select FW_LOADER - select MDIO - ---help--- - This driver supports Chelsio T4, T5 & T6 based gigabit, 10Gb Ethernet - adapter and T5/T6 based 40Gb and T6 based 25Gb, 50Gb and 100Gb - Ethernet adapters. - - For general information about Chelsio and our products, visit - our website at . - - For customer support, please visit our customer support page at - . - - Please send feedback to . - - To compile this driver as a module choose M here; the module - will be called cxgb4. - -config CHELSIO_T4_DCB - bool "Data Center Bridging (DCB) Support for Chelsio T4/T5/T6 cards" - default n - depends on CHELSIO_T4 && DCB - ---help--- - Enable DCB support through rtNetlink interface. - Say Y here if you want to enable Data Center Bridging (DCB) support - in the driver. - - If unsure, say N. - -config CHELSIO_T4_FCOE - bool "Fibre Channel over Ethernet (FCoE) Support for Chelsio T5 cards" - default n - depends on CHELSIO_T4 && CHELSIO_T4_DCB && FCOE - ---help--- - Enable FCoE offload features. - Say Y here if you want to enable Fibre Channel over Ethernet (FCoE) support - in the driver. - - If unsure, say N. - -config CHELSIO_T4VF - tristate "Chelsio Communications T4/T5/T6 Virtual Function Ethernet support" - depends on PCI - ---help--- - This driver supports Chelsio T4, T5 & T6 based gigabit, 10Gb Ethernet - adapters and T5/T6 based 40Gb and T6 based 25Gb, 50Gb and 100Gb - Ethernet adapters with PCI-E SR-IOV Virtual Functions. - - For general information about Chelsio and our products, visit - our website at . - - For customer support, please visit our customer support page at - . - - Please send feedback to . - - To compile this driver as a module choose M here; the module - will be called cxgb4vf. - -config CHELSIO_LIB - tristate - ---help--- - Common library for Chelsio drivers. - -endif # NET_VENDOR_CHELSIO diff --git a/src/linux/drivers/net/ethernet/cirrus/Kconfig b/src/linux/drivers/net/ethernet/cirrus/Kconfig deleted file mode 100644 index 5ab9129..0000000 --- a/src/linux/drivers/net/ethernet/cirrus/Kconfig +++ /dev/null @@ -1,59 +0,0 @@ -# -# Cirrus network device configuration -# - -config NET_VENDOR_CIRRUS - bool "Cirrus devices" - default y - depends on ISA || EISA || ARM || MAC - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Cirrus cards. If you say Y, you will be asked - for your specific card in the following questions. - -if NET_VENDOR_CIRRUS - -config CS89x0 - tristate "CS89x0 support" - depends on ISA || EISA || ARM - ---help--- - Support for CS89x0 chipset based Ethernet cards. If you have a - network (Ethernet) card of this type, say Y and read the file - . - - To compile this driver as a module, choose M here. The module - will be called cs89x0. - -config CS89x0_PLATFORM - bool "CS89x0 platform driver support" if HAS_IOPORT_MAP - default !HAS_IOPORT_MAP - depends on CS89x0 - help - Say Y to compile the cs89x0 driver as a platform driver. This - makes this driver suitable for use on certain evaluation boards - such as the iMX21ADS. - - If you are unsure, say N. - -config EP93XX_ETH - tristate "EP93xx Ethernet support" - depends on ARM && ARCH_EP93XX - select MII - help - This is a driver for the ethernet hardware included in EP93xx CPUs. - Say Y if you are building a kernel for EP93xx based devices. - -config MAC89x0 - tristate "Macintosh CS89x0 based ethernet cards" - depends on MAC - ---help--- - Support for CS89x0 chipset based Ethernet cards. If you have a - Nubus or LC-PDS network (Ethernet) card of this type, say Y here. - - To compile this driver as a module, choose M here. This module will - be called mac89x0. - -endif # NET_VENDOR_CIRRUS diff --git a/src/linux/drivers/net/ethernet/cisco/Kconfig b/src/linux/drivers/net/ethernet/cisco/Kconfig deleted file mode 100644 index 15b713a..0000000 --- a/src/linux/drivers/net/ethernet/cisco/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -# -# Cisco device configuration -# - -config NET_VENDOR_CISCO - bool "Cisco devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Cisco cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_CISCO - -source "drivers/net/ethernet/cisco/enic/Kconfig" - -endif # NET_VENDOR_CISCO diff --git a/src/linux/drivers/net/ethernet/cisco/enic/Kconfig b/src/linux/drivers/net/ethernet/cisco/enic/Kconfig deleted file mode 100644 index b63f8d8..0000000 --- a/src/linux/drivers/net/ethernet/cisco/enic/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -# -# Cisco device configuration -# - -config ENIC - tristate "Cisco VIC Ethernet NIC Support" - depends on PCI - ---help--- - This enables the support for the Cisco VIC Ethernet card. diff --git a/src/linux/drivers/net/ethernet/davicom/Kconfig b/src/linux/drivers/net/ethernet/davicom/Kconfig deleted file mode 100644 index 7ec2d74..0000000 --- a/src/linux/drivers/net/ethernet/davicom/Kconfig +++ /dev/null @@ -1,23 +0,0 @@ -# -# Davicom device configuration -# - -config DM9000 - tristate "DM9000 support" - depends on ARM || BLACKFIN || MIPS || COLDFIRE || NIOS2 - select CRC32 - select MII - ---help--- - Support for DM9000 chipset. - - To compile this driver as a module, choose M here. The module - will be called dm9000. - -config DM9000_FORCE_SIMPLE_PHY_POLL - bool "Force simple NSR based PHY polling" - depends on DM9000 - ---help--- - This configuration forces the DM9000 to use the NSR's LinkStatus - bit to determine if the link is up or down instead of the more - costly MII PHY reads. Note, this will not work if the chip is - operating with an external PHY. diff --git a/src/linux/drivers/net/ethernet/dec/Kconfig b/src/linux/drivers/net/ethernet/dec/Kconfig deleted file mode 100644 index 740bbad..0000000 --- a/src/linux/drivers/net/ethernet/dec/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -# -# Digital Equipment Inc network device configuration -# - -config NET_VENDOR_DEC - bool "Digital Equipment devices" - default y - depends on PCI || EISA || CARDBUS - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about DEC cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_DEC -source "drivers/net/ethernet/dec/tulip/Kconfig" -endif # NET_VENDOR_DEC diff --git a/src/linux/drivers/net/ethernet/dec/tulip/Kconfig b/src/linux/drivers/net/ethernet/dec/tulip/Kconfig deleted file mode 100644 index 1003201..0000000 --- a/src/linux/drivers/net/ethernet/dec/tulip/Kconfig +++ /dev/null @@ -1,168 +0,0 @@ -# -# Tulip family network device configuration -# - -config NET_TULIP - bool "DEC - Tulip devices" - depends on (PCI || EISA || CARDBUS) - ---help--- - This selects the "Tulip" family of EISA/PCI network cards. - -if NET_TULIP - -config DE2104X - tristate "Early DECchip Tulip (dc2104x) PCI support" - depends on PCI - select CRC32 - ---help--- - This driver is developed for the SMC EtherPower series Ethernet - cards and also works with cards based on the DECchip - 21040 (Tulip series) chips. Some LinkSys PCI cards are - of this type. (If your card is NOT SMC EtherPower 10/100 PCI - (smc9332dst), you can also try the driver for "Generic DECchip" - cards, below. However, most people with a network card of this type - will say Y here.) - - To compile this driver as a module, choose M here. The module will - be called de2104x. - -config DE2104X_DSL - int "Descriptor Skip Length in 32 bit longwords" - depends on DE2104X - range 0 31 - default 0 - ---help--- - Setting this value allows to align ring buffer descriptors into their - own cache lines. Value of 4 corresponds to the typical 32 byte line - (the descriptor is 16 bytes). This is necessary on systems that lack - cache coherence, an example is PowerMac 5500. Otherwise 0 is safe. - Default is 0, and range is 0 to 31. - -config TULIP - tristate "DECchip Tulip (dc2114x) PCI support" - depends on PCI - select CRC32 - ---help--- - This driver is developed for the SMC EtherPower series Ethernet - cards and also works with cards based on the DECchip - 21140 (Tulip series) chips. Some LinkSys PCI cards are - of this type. (If your card is NOT SMC EtherPower 10/100 PCI - (smc9332dst), you can also try the driver for "Generic DECchip" - cards, above. However, most people with a network card of this type - will say Y here.) - - To compile this driver as a module, choose M here. The module will - be called tulip. - -config TULIP_MWI - bool "New bus configuration" - depends on TULIP - ---help--- - This configures your Tulip card specifically for the card and - system cache line size type you are using. - - This is experimental code, not yet tested on many boards. - - If unsure, say N. - -config TULIP_MMIO - bool "Use PCI shared mem for NIC registers" - depends on TULIP - ---help--- - Use PCI shared memory for the NIC registers, rather than going through - the Tulip's PIO (programmed I/O ports). Faster, but could produce - obscure bugs if your mainboard has memory controller timing issues. - If in doubt, say N. - -config TULIP_NAPI - bool "Use RX polling (NAPI)" - depends on TULIP - ---help--- - NAPI is a new driver API designed to reduce CPU and interrupt load - when the driver is receiving lots of packets from the card. It is - still somewhat experimental and thus not yet enabled by default. - - If your estimated Rx load is 10kpps or more, or if the card will be - deployed on potentially unfriendly networks (e.g. in a firewall), - then say Y here. - - If in doubt, say N. - -config TULIP_NAPI_HW_MITIGATION - bool "Use Interrupt Mitigation" - depends on TULIP_NAPI - ---help--- - Use HW to reduce RX interrupts. Not strictly necessary since NAPI - reduces RX interrupts by itself. Interrupt mitigation reduces RX - interrupts even at low levels of traffic at the cost of a small - latency. - - If in doubt, say Y. - -config TULIP_DM910X - def_bool y - depends on TULIP && SPARC - -config DE4X5 - tristate "Generic DECchip & DIGITAL EtherWORKS PCI/EISA" - depends on (PCI || EISA) - depends on VIRT_TO_BUS || ALPHA || PPC || SPARC - select CRC32 - ---help--- - This is support for the DIGITAL series of PCI/EISA Ethernet cards. - These include the DE425, DE434, DE435, DE450 and DE500 models. If - you have a network card of this type, say Y. More specific - information is contained in - . - - To compile this driver as a module, choose M here. The module will - be called de4x5. - -config WINBOND_840 - tristate "Winbond W89c840 Ethernet support" - depends on PCI - select CRC32 - select MII - ---help--- - This driver is for the Winbond W89c840 chip. It also works with - the TX9882 chip on the Compex RL100-ATX board. - More specific information and updates are available from - . - -config DM9102 - tristate "Davicom DM910x/DM980x support" - depends on PCI - select CRC32 - ---help--- - This driver is for DM9102(A)/DM9132/DM9801 compatible PCI cards from - Davicom (). If you have such a network - (Ethernet) card, say Y. Some information is contained in the file - . - - To compile this driver as a module, choose M here. The module will - be called dmfe. - -config ULI526X - tristate "ULi M526x controller support" - depends on PCI - select CRC32 - ---help--- - This driver is for ULi M5261/M5263 10/100M Ethernet Controller - (). - - To compile this driver as a module, choose M here. The module will - be called uli526x. - -config PCMCIA_XIRCOM - tristate "Xircom CardBus support" - depends on CARDBUS - ---help--- - This driver is for the Digital "Tulip" Ethernet CardBus adapters. - It should work with most DEC 21*4*-based chips/ethercards, as well - as with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and - ASIX. - - To compile this driver as a module, choose M here. The module will - be called xircom_cb. If unsure, say N. - -endif # NET_TULIP diff --git a/src/linux/drivers/net/ethernet/dlink/Kconfig b/src/linux/drivers/net/ethernet/dlink/Kconfig deleted file mode 100644 index ebdc832..0000000 --- a/src/linux/drivers/net/ethernet/dlink/Kconfig +++ /dev/null @@ -1,54 +0,0 @@ -# -# D-Link device configuration -# - -config NET_VENDOR_DLINK - bool "D-Link devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about D-Link devices. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_DLINK - -config DL2K - tristate "DL2000/TC902x/IP1000A-based Gigabit Ethernet support" - depends on PCI - select CRC32 - ---help--- - This driver supports DL2000/TC902x/IP1000A-based Gigabit ethernet cards, - which includes - D-Link DGE-550T Gigabit Ethernet Adapter. - D-Link DL2000-based Gigabit Ethernet Adapter. - Sundance/Tamarack TC902x Gigabit Ethernet Adapter. - ICPlus IP1000A-based cards - - To compile this driver as a module, choose M here: the - module will be called dl2k. - -config SUNDANCE - tristate "Sundance Alta support" - depends on PCI - select CRC32 - select MII - ---help--- - This driver is for the Sundance "Alta" chip. - More specific information and updates are available from - . - -config SUNDANCE_MMIO - bool "Use MMIO instead of PIO" - depends on SUNDANCE - ---help--- - Enable memory-mapped I/O for interaction with Sundance NIC registers. - Do NOT enable this by default, PIO (enabled when MMIO is disabled) - is known to solve bugs on certain chips. - - If unsure, say N. - -endif # NET_VENDOR_DLINK diff --git a/src/linux/drivers/net/ethernet/emulex/Kconfig b/src/linux/drivers/net/ethernet/emulex/Kconfig deleted file mode 100644 index fdbb27c..0000000 --- a/src/linux/drivers/net/ethernet/emulex/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -# -# Emulex driver configuration -# - -config NET_VENDOR_EMULEX - bool "Emulex devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Emulex cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_EMULEX - -source "drivers/net/ethernet/emulex/benet/Kconfig" - -endif # NET_VENDOR_EMULEX diff --git a/src/linux/drivers/net/ethernet/emulex/benet/Kconfig b/src/linux/drivers/net/ethernet/emulex/benet/Kconfig deleted file mode 100644 index b4853ec..0000000 --- a/src/linux/drivers/net/ethernet/emulex/benet/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -config BE2NET - tristate "ServerEngines' 10Gbps NIC - BladeEngine" - depends on PCI - ---help--- - This driver implements the NIC functionality for ServerEngines' - 10Gbps network adapter - BladeEngine. - -config BE2NET_HWMON - bool "HWMON support for be2net driver" - depends on BE2NET && HWMON - depends on !(BE2NET=y && HWMON=m) - default y - ---help--- - Say Y here if you want to expose thermal sensor data on - be2net network adapter. diff --git a/src/linux/drivers/net/ethernet/ezchip/Kconfig b/src/linux/drivers/net/ethernet/ezchip/Kconfig deleted file mode 100644 index b423ad3..0000000 --- a/src/linux/drivers/net/ethernet/ezchip/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -# -# EZchip network device configuration -# - -config NET_VENDOR_EZCHIP - bool "EZchip devices" - default y - ---help--- - If you have a network (Ethernet) device belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about EZchip devices. If you say Y, you will be asked for - your specific device in the following questions. - -if NET_VENDOR_EZCHIP - -config EZCHIP_NPS_MANAGEMENT_ENET - tristate "EZchip NPS management enet support" - depends on OF_IRQ && OF_NET - depends on HAS_IOMEM - ---help--- - Simple LAN device for debug or management purposes. - Device supports interrupts for RX and TX(completion). - Device does not have DMA ability. - -endif diff --git a/src/linux/drivers/net/ethernet/faraday/Kconfig b/src/linux/drivers/net/ethernet/faraday/Kconfig deleted file mode 100644 index 040c7f1..0000000 --- a/src/linux/drivers/net/ethernet/faraday/Kconfig +++ /dev/null @@ -1,37 +0,0 @@ -# -# Faraday device configuration -# - -config NET_VENDOR_FARADAY - bool "Faraday devices" - default y - depends on ARM - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Faraday cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_FARADAY - -config FTMAC100 - tristate "Faraday FTMAC100 10/100 Ethernet support" - depends on ARM - select MII - ---help--- - This driver supports the FTMAC100 10/100 Ethernet controller - from Faraday. It is used on Faraday A320, Andes AG101 and some - other ARM/NDS32 SoC's. - -config FTGMAC100 - tristate "Faraday FTGMAC100 Gigabit Ethernet support" - depends on ARM - select PHYLIB - ---help--- - This driver supports the FTGMAC100 Gigabit Ethernet controller - from Faraday. It is used on Faraday A369, Andes AG102 and some - other ARM/NDS32 SoC's. - -endif # NET_VENDOR_FARADAY diff --git a/src/linux/drivers/net/ethernet/freescale/Kconfig b/src/linux/drivers/net/ethernet/freescale/Kconfig deleted file mode 100644 index d1ca45f..0000000 --- a/src/linux/drivers/net/ethernet/freescale/Kconfig +++ /dev/null @@ -1,96 +0,0 @@ -# -# Freescale device configuration -# - -config NET_VENDOR_FREESCALE - bool "Freescale devices" - default y - depends on FSL_SOC || QUICC_ENGINE || CPM1 || CPM2 || PPC_MPC512x || \ - M523x || M527x || M5272 || M528x || M520x || M532x || \ - ARCH_MXC || ARCH_MXS || (PPC_MPC52xx && PPC_BESTCOMM) || \ - ARCH_LAYERSCAPE - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Freescale devices. If you say Y, you will be - asked for your specific card in the following questions. - -if NET_VENDOR_FREESCALE - -config FEC - tristate "FEC ethernet controller (of ColdFire and some i.MX CPUs)" - depends on (M523x || M527x || M5272 || M528x || M520x || M532x || \ - ARCH_MXC || SOC_IMX28) - default ARCH_MXC || SOC_IMX28 if ARM - select PHYLIB - select PTP_1588_CLOCK - ---help--- - Say Y here if you want to use the built-in 10/100 Fast ethernet - controller on some Motorola ColdFire and Freescale i.MX processors. - -config FEC_MPC52xx - tristate "FEC MPC52xx driver" - depends on PPC_MPC52xx && PPC_BESTCOMM - select CRC32 - select PHYLIB - select PPC_BESTCOMM_FEC - ---help--- - This option enables support for the MPC5200's on-chip - Fast Ethernet Controller - If compiled as module, it will be called fec_mpc52xx. - -config FEC_MPC52xx_MDIO - bool "FEC MPC52xx MDIO bus driver" - depends on FEC_MPC52xx - default y - ---help--- - The MPC5200's FEC can connect to the Ethernet either with - an external MII PHY chip or 10 Mbps 7-wire interface - (Motorola? industry standard). - If your board uses an external PHY connected to FEC, enable this. - If not sure, enable. - If compiled as module, it will be called fec_mpc52xx_phy. - -source "drivers/net/ethernet/freescale/fs_enet/Kconfig" -source "drivers/net/ethernet/freescale/fman/Kconfig" - -config FSL_PQ_MDIO - tristate "Freescale PQ MDIO" - select PHYLIB - ---help--- - This driver supports the MDIO bus used by the gianfar and UCC drivers. - -config FSL_XGMAC_MDIO - tristate "Freescale XGMAC MDIO" - select PHYLIB - select OF_MDIO - ---help--- - This driver supports the MDIO bus on the Fman 10G Ethernet MACs, and - on the FMan mEMAC (which supports both Clauses 22 and 45) - -config UCC_GETH - tristate "Freescale QE Gigabit Ethernet" - depends on QUICC_ENGINE - select FSL_PQ_MDIO - select PHYLIB - ---help--- - This driver supports the Gigabit Ethernet mode of the QUICC Engine, - which is available on some Freescale SOCs. - -config UGETH_TX_ON_DEMAND - bool "Transmit on Demand support" - depends on UCC_GETH - -config GIANFAR - tristate "Gianfar Ethernet" - select FSL_PQ_MDIO - select PHYLIB - select CRC32 - ---help--- - This driver supports the Gigabit TSEC on the MPC83xx, MPC85xx, - and MPC86xx family of chips, the eTSEC on LS1021A and the FEC - on the 8540. - -endif # NET_VENDOR_FREESCALE diff --git a/src/linux/drivers/net/ethernet/freescale/fman/Kconfig b/src/linux/drivers/net/ethernet/freescale/fman/Kconfig deleted file mode 100644 index 79b7c84..0000000 --- a/src/linux/drivers/net/ethernet/freescale/fman/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config FSL_FMAN - tristate "FMan support" - depends on FSL_SOC || COMPILE_TEST - select GENERIC_ALLOCATOR - select PHYLIB - default n - help - Freescale Data-Path Acceleration Architecture Frame Manager - (FMan) support diff --git a/src/linux/drivers/net/ethernet/freescale/fs_enet/Kconfig b/src/linux/drivers/net/ethernet/freescale/fs_enet/Kconfig deleted file mode 100644 index be92229..0000000 --- a/src/linux/drivers/net/ethernet/freescale/fs_enet/Kconfig +++ /dev/null @@ -1,34 +0,0 @@ -config FS_ENET - tristate "Freescale Ethernet Driver" - depends on NET_VENDOR_FREESCALE && (CPM1 || CPM2 || PPC_MPC512x) - select MII - select PHYLIB - -config FS_ENET_MPC5121_FEC - def_bool y if (FS_ENET && PPC_MPC512x) - select FS_ENET_HAS_FEC - -config FS_ENET_HAS_SCC - bool "Chip has an SCC usable for ethernet" - depends on FS_ENET && (CPM1 || CPM2) - default y - -config FS_ENET_HAS_FCC - bool "Chip has an FCC usable for ethernet" - depends on FS_ENET && CPM2 - default y - -config FS_ENET_HAS_FEC - bool "Chip has an FEC usable for ethernet" - depends on FS_ENET && (CPM1 || FS_ENET_MPC5121_FEC) - select FS_ENET_MDIO_FEC - default y - -config FS_ENET_MDIO_FEC - tristate "MDIO driver for FEC" - depends on FS_ENET && (CPM1 || FS_ENET_MPC5121_FEC) - -config FS_ENET_MDIO_FCC - tristate "MDIO driver for FCC" - depends on FS_ENET && CPM2 - select MDIO_BITBANG diff --git a/src/linux/drivers/net/ethernet/fujitsu/Kconfig b/src/linux/drivers/net/ethernet/fujitsu/Kconfig deleted file mode 100644 index faee34e..0000000 --- a/src/linux/drivers/net/ethernet/fujitsu/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -# -# Fujitsu Network device configuration -# - -config NET_VENDOR_FUJITSU - bool "Fujitsu devices" - default y - depends on PCMCIA - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - the questions about Fujitsu cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_FUJITSU - -config PCMCIA_FMVJ18X - tristate "Fujitsu FMV-J18x PCMCIA support" - depends on PCMCIA - select CRC32 - ---help--- - Say Y here if you intend to attach a Fujitsu FMV-J18x or compatible - PCMCIA (PC-card) Ethernet card to your computer. - - To compile this driver as a module, choose M here: the module will be - called fmvj18x_cs. If unsure, say N. - -endif # NET_VENDOR_FUJITSU diff --git a/src/linux/drivers/net/ethernet/hisilicon/Kconfig b/src/linux/drivers/net/ethernet/hisilicon/Kconfig deleted file mode 100644 index d11287e..0000000 --- a/src/linux/drivers/net/ethernet/hisilicon/Kconfig +++ /dev/null @@ -1,79 +0,0 @@ -# -# HISILICON device configuration -# - -config NET_VENDOR_HISILICON - bool "Hisilicon devices" - default y - depends on (OF || ACPI) && HAS_DMA - depends on ARM || ARM64 || COMPILE_TEST - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Hisilicon devices. If you say Y, you will be asked - for your specific card in the following questions. - -if NET_VENDOR_HISILICON - -config HIX5HD2_GMAC - tristate "Hisilicon HIX5HD2 Family Network Device Support" - select PHYLIB - help - This selects the hix5hd2 mac family network device. - -config HISI_FEMAC - tristate "Hisilicon Fast Ethernet MAC device support" - depends on HAS_IOMEM - select PHYLIB - select RESET_CONTROLLER - help - This selects the Hisilicon Fast Ethernet MAC device(FEMAC). - The FEMAC receives and transmits data over Ethernet - ports at 10/100 Mbps in full-duplex or half-duplex mode. - The FEMAC exchanges data with the CPU, and supports - the energy efficient Ethernet (EEE). - -config HIP04_ETH - tristate "HISILICON P04 Ethernet support" - depends on HAS_IOMEM # For MFD_SYSCON - select MARVELL_PHY - select MFD_SYSCON - select HNS_MDIO - ---help--- - If you wish to compile a kernel for a hardware with hisilicon p04 SoC and - want to use the internal ethernet then you should answer Y to this. - -config HNS_MDIO - tristate - select PHYLIB - ---help--- - This selects the HNS MDIO support. It is needed by HNS_DSAF to access - the PHY - -config HNS - tristate "Hisilicon Network Subsystem Support (Framework)" - ---help--- - This selects the framework support for Hisilicon Network Subsystem. It - is needed by any driver which provides HNS acceleration engine or make - use of the engine - -config HNS_DSAF - tristate "Hisilicon HNS DSAF device Support" - select HNS - select HNS_MDIO - ---help--- - This selects the DSAF (Distributed System Area Frabric) network - acceleration engine support. The engine is used in Hisilicon hip05, - Hi1610 and further ICT SoC - -config HNS_ENET - tristate "Hisilicon HNS Ethernet Device Support" - select PHYLIB - select HNS - ---help--- - This selects the general ethernet driver for HNS. This module make - use of any HNS AE driver, such as HNS_DSAF - -endif # NET_VENDOR_HISILICON diff --git a/src/linux/drivers/net/ethernet/hp/Kconfig b/src/linux/drivers/net/ethernet/hp/Kconfig deleted file mode 100644 index d4df78c..0000000 --- a/src/linux/drivers/net/ethernet/hp/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -# -# HP network device configuration -# - -config NET_VENDOR_HP - bool "HP devices" - default y - depends on ISA || EISA || PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about HP cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_HP - -config HP100 - tristate "HP 10/100VG PCLAN (ISA, EISA, PCI) support" - depends on (ISA || EISA || PCI) - ---help--- - If you have a network (Ethernet) card of this type, say Y here. - - To compile this driver as a module, choose M here. The module - will be called hp100. - -endif # NET_VENDOR_HP diff --git a/src/linux/drivers/net/ethernet/i825xx/Kconfig b/src/linux/drivers/net/ethernet/i825xx/Kconfig deleted file mode 100644 index e8d61f6..0000000 --- a/src/linux/drivers/net/ethernet/i825xx/Kconfig +++ /dev/null @@ -1,67 +0,0 @@ -# -# Intel 82596/82593/82596 network device configuration -# - -config NET_VENDOR_I825XX - bool "Intel (82586/82593/82596) devices" - default y - depends on NET_VENDOR_INTEL - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question does not directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about these devices. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_I825XX - -config ARM_ETHER1 - tristate "Acorn Ether1 support" - depends on ARM && ARCH_ACORN - ---help--- - If you have an Acorn system with one of these (AKA25) network cards, - you should say Y to this option if you wish to use it with Linux. - -config BVME6000_NET - tristate "BVME6000 Ethernet support" - depends on BVME6000 - ---help--- - This is the driver for the Ethernet interface on BVME4000 and - BVME6000 VME boards. Say Y here to include the driver for this chip - in your kernel. - To compile this driver as a module, choose M here. - -config LASI_82596 - tristate "Lasi ethernet" - depends on GSC - ---help--- - Say Y here to support the builtin Intel 82596 ethernet controller - found in Hewlett-Packard PA-RISC machines with 10Mbit ethernet. - -config MVME16x_NET - tristate "MVME16x Ethernet support" - depends on MVME16x - ---help--- - This is the driver for the Ethernet interface on the Motorola - MVME162, 166, 167, 172 and 177 boards. Say Y here to include the - driver for this chip in your kernel. - To compile this driver as a module, choose M here. - -config SNI_82596 - tristate "SNI RM ethernet" - depends on SNI_RM - ---help--- - Say Y here to support the on-board Intel 82596 ethernet controller - built into SNI RM machines. - -config SUN3_82586 - bool "Sun3 on-board Intel 82586 support" - depends on SUN3 - ---help--- - This driver enables support for the on-board Intel 82586 based - Ethernet adapter found on Sun 3/1xx and 3/2xx motherboards. Note - that this driver does not support 82586-based adapters on additional - VME boards. - -endif # NET_VENDOR_I825XX diff --git a/src/linux/drivers/net/ethernet/ibm/Kconfig b/src/linux/drivers/net/ethernet/ibm/Kconfig deleted file mode 100644 index 37dceab..0000000 --- a/src/linux/drivers/net/ethernet/ibm/Kconfig +++ /dev/null @@ -1,50 +0,0 @@ -# -# IBM device configuration. -# - -config NET_VENDOR_IBM - bool "IBM devices" - default y - depends on PPC_PSERIES || PPC_DCR || (IBMEBUS && SPARSEMEM) - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about IBM devices. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_IBM - -config IBMVETH - tristate "IBM LAN Virtual Ethernet support" - depends on PPC_PSERIES - ---help--- - This driver supports virtual ethernet adapters on newer IBM iSeries - and pSeries systems. - - To compile this driver as a module, choose M here. The module will - be called ibmveth. - -source "drivers/net/ethernet/ibm/emac/Kconfig" - -config EHEA - tristate "eHEA Ethernet support" - depends on IBMEBUS && SPARSEMEM - ---help--- - This driver supports the IBM pSeries eHEA ethernet adapter. - - To compile the driver as a module, choose M here. The module - will be called ehea. - -config IBMVNIC - tristate "IBM Virtual NIC support" - depends on PPC_PSERIES - ---help--- - This driver supports Virtual NIC adapters on IBM i and IBM System p - systems. - - To compile this driver as a module, choose M here. The module will - be called ibmvnic. - -endif # NET_VENDOR_IBM diff --git a/src/linux/drivers/net/ethernet/ibm/emac/Kconfig b/src/linux/drivers/net/ethernet/ibm/emac/Kconfig deleted file mode 100644 index 3f44a30..0000000 --- a/src/linux/drivers/net/ethernet/ibm/emac/Kconfig +++ /dev/null @@ -1,76 +0,0 @@ -config IBM_EMAC - tristate "IBM EMAC Ethernet support" - depends on PPC_DCR - select CRC32 - help - This driver supports the IBM EMAC family of Ethernet controllers - typically found on 4xx embedded PowerPC chips, but also on the - Axon southbridge for Cell. - -config IBM_EMAC_RXB - int "Number of receive buffers" - depends on IBM_EMAC - default "128" - -config IBM_EMAC_TXB - int "Number of transmit buffers" - depends on IBM_EMAC - default "64" - -config IBM_EMAC_POLL_WEIGHT - int "MAL NAPI polling weight" - depends on IBM_EMAC - default "32" - -config IBM_EMAC_RX_COPY_THRESHOLD - int "RX skb copy threshold (bytes)" - depends on IBM_EMAC - default "256" - -config IBM_EMAC_RX_SKB_HEADROOM - int "Additional RX skb headroom (bytes)" - depends on IBM_EMAC - default "0" - help - Additional receive skb headroom. Note, that driver - will always reserve at least 2 bytes to make IP header - aligned, so usually there is no need to add any additional - headroom. - - If unsure, set to 0. - -config IBM_EMAC_DEBUG - bool "Debugging" - depends on IBM_EMAC - default n - -# The options below has to be select'ed by the respective -# processor types or platforms - -config IBM_EMAC_ZMII - bool - default n - -config IBM_EMAC_RGMII - bool - default n - -config IBM_EMAC_TAH - bool - default n - -config IBM_EMAC_EMAC4 - bool - default n - -config IBM_EMAC_NO_FLOW_CTRL - bool - default n - -config IBM_EMAC_MAL_CLR_ICINTSTAT - bool - default n - -config IBM_EMAC_MAL_COMMON_ERR - bool - default n diff --git a/src/linux/drivers/net/ethernet/intel/Kconfig b/src/linux/drivers/net/ethernet/intel/Kconfig deleted file mode 100644 index c0e1743..0000000 --- a/src/linux/drivers/net/ethernet/intel/Kconfig +++ /dev/null @@ -1,278 +0,0 @@ -# -# Intel network device configuration -# - -config NET_VENDOR_INTEL - bool "Intel devices" - default y - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Intel cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_INTEL - -config E100 - tristate "Intel(R) PRO/100+ support" - depends on PCI - select MII - ---help--- - This driver supports Intel(R) PRO/100 family of adapters. - To verify that your adapter is supported, find the board ID number - on the adapter. Look for a label that has a barcode and a number - in the format 123456-001 (six digits hyphen three digits). - - Use the above information and the Adapter & Driver ID Guide that - can be located at: - - - - to identify the adapter. - - More specific information on configuring the driver is in - . - - To compile this driver as a module, choose M here. The module - will be called e100. - -config E1000 - tristate "Intel(R) PRO/1000 Gigabit Ethernet support" - depends on PCI - ---help--- - This driver supports Intel(R) PRO/1000 gigabit ethernet family of - adapters. For more information on how to identify your adapter, go - to the Adapter & Driver ID Guide that can be located at: - - - - More specific information on configuring the driver is in - . - - To compile this driver as a module, choose M here. The module - will be called e1000. - -config E1000E - tristate "Intel(R) PRO/1000 PCI-Express Gigabit Ethernet support" - depends on PCI && (!SPARC32 || BROKEN) - select CRC32 - select PTP_1588_CLOCK - ---help--- - This driver supports the PCI-Express Intel(R) PRO/1000 gigabit - ethernet family of adapters. For PCI or PCI-X e1000 adapters, - use the regular e1000 driver For more information on how to - identify your adapter, go to the Adapter & Driver ID Guide that - can be located at: - - - - To compile this driver as a module, choose M here. The module - will be called e1000e. - -config E1000E_HWTS - bool "Support HW cross-timestamp on PCH devices" - default y - depends on E1000E && X86 - ---help--- - Say Y to enable hardware supported cross-timestamping on PCH - devices. The cross-timestamp is available through the PTP clock - driver precise cross-timestamp ioctl (PTP_SYS_OFFSET_PRECISE). - -config IGB - tristate "Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support" - depends on PCI - select PTP_1588_CLOCK - select I2C - select I2C_ALGOBIT - ---help--- - This driver supports Intel(R) 82575/82576 gigabit ethernet family of - adapters. For more information on how to identify your adapter, go - to the Adapter & Driver ID Guide that can be located at: - - - - More specific information on configuring the driver is in - . - - To compile this driver as a module, choose M here. The module - will be called igb. - -config IGB_HWMON - bool "Intel(R) PCI-Express Gigabit adapters HWMON support" - default y - depends on IGB && HWMON && !(IGB=y && HWMON=m) - ---help--- - Say Y if you want to expose thermal sensor data on Intel devices. - - Some of our devices contain thermal sensors, both external and internal. - This data is available via the hwmon sysfs interface and exposes - the onboard sensors. - -config IGB_DCA - bool "Direct Cache Access (DCA) Support" - default y - depends on IGB && DCA && !(IGB=y && DCA=m) - ---help--- - Say Y here if you want to use Direct Cache Access (DCA) in the - driver. DCA is a method for warming the CPU cache before data - is used, with the intent of lessening the impact of cache misses. - -config IGBVF - tristate "Intel(R) 82576 Virtual Function Ethernet support" - depends on PCI - ---help--- - This driver supports Intel(R) 82576 virtual functions. For more - information on how to identify your adapter, go to the Adapter & - Driver ID Guide that can be located at: - - - - More specific information on configuring the driver is in - . - - To compile this driver as a module, choose M here. The module - will be called igbvf. - -config IXGB - tristate "Intel(R) PRO/10GbE support" - depends on PCI - ---help--- - This driver supports Intel(R) PRO/10GbE family of adapters for - PCI-X type cards. For PCI-E type cards, use the "ixgbe" driver - instead. For more information on how to identify your adapter, go - to the Adapter & Driver ID Guide that can be located at: - - - - More specific information on configuring the driver is in - . - - To compile this driver as a module, choose M here. The module - will be called ixgb. - -config IXGBE - tristate "Intel(R) 10GbE PCI Express adapters support" - depends on PCI - select MDIO - select PTP_1588_CLOCK - ---help--- - This driver supports Intel(R) 10GbE PCI Express family of - adapters. For more information on how to identify your adapter, go - to the Adapter & Driver ID Guide that can be located at: - - - - To compile this driver as a module, choose M here. The module - will be called ixgbe. - -config IXGBE_HWMON - bool "Intel(R) 10GbE PCI Express adapters HWMON support" - default y - depends on IXGBE && HWMON && !(IXGBE=y && HWMON=m) - ---help--- - Say Y if you want to expose the thermal sensor data on some of - our cards, via a hwmon sysfs interface. - -config IXGBE_DCA - bool "Direct Cache Access (DCA) Support" - default y - depends on IXGBE && DCA && !(IXGBE=y && DCA=m) - ---help--- - Say Y here if you want to use Direct Cache Access (DCA) in the - driver. DCA is a method for warming the CPU cache before data - is used, with the intent of lessening the impact of cache misses. - -config IXGBE_DCB - bool "Data Center Bridging (DCB) Support" - default n - depends on IXGBE && DCB - ---help--- - Say Y here if you want to use Data Center Bridging (DCB) in the - driver. - - If unsure, say N. - -config IXGBEVF - tristate "Intel(R) 10GbE PCI Express Virtual Function Ethernet support" - depends on PCI_MSI - ---help--- - This driver supports Intel(R) PCI Express virtual functions for the - Intel(R) ixgbe driver. For more information on how to identify your - adapter, go to the Adapter & Driver ID Guide that can be located at: - - - - More specific information on configuring the driver is in - . - - To compile this driver as a module, choose M here. The module - will be called ixgbevf. MSI-X interrupt support is required - for this driver to work correctly. - -config I40E - tristate "Intel(R) Ethernet Controller XL710 Family support" - select PTP_1588_CLOCK - depends on PCI - ---help--- - This driver supports Intel(R) Ethernet Controller XL710 Family of - devices. For more information on how to identify your adapter, go - to the Adapter & Driver ID Guide that can be located at: - - - - To compile this driver as a module, choose M here. The module - will be called i40e. - -config I40E_DCB - bool "Data Center Bridging (DCB) Support" - default n - depends on I40E && DCB - ---help--- - Say Y here if you want to use Data Center Bridging (DCB) in the - driver. - - If unsure, say N. - -config I40E_FCOE - bool "Fibre Channel over Ethernet (FCoE)" - default n - depends on I40E && DCB && FCOE - ---help--- - Say Y here if you want to use Fibre Channel over Ethernet (FCoE) - in the driver. This will create new netdev for exclusive FCoE - use with XL710 FCoE offloads enabled. - - If unsure, say N. - -config I40EVF - tristate "Intel(R) XL710 X710 Virtual Function Ethernet support" - depends on PCI_MSI - ---help--- - This driver supports Intel(R) XL710 and X710 virtual functions. - For more information on how to identify your adapter, go to the - Adapter & Driver ID Guide that can be located at: - - - - To compile this driver as a module, choose M here. The module - will be called i40evf. MSI-X interrupt support is required - for this driver to work correctly. - -config FM10K - tristate "Intel(R) FM10000 Ethernet Switch Host Interface Support" - default n - depends on PCI_MSI - select PTP_1588_CLOCK - ---help--- - This driver supports Intel(R) FM10000 Ethernet Switch Host - Interface. For more information on how to identify your adapter, - go to the Adapter & Driver ID Guide that can be located at: - - - - To compile this driver as a module, choose M here. The module - will be called fm10k. MSI-X interrupt support is required - -endif # NET_VENDOR_INTEL diff --git a/src/linux/drivers/net/ethernet/marvell/Kconfig b/src/linux/drivers/net/ethernet/marvell/Kconfig deleted file mode 100644 index 2664827..0000000 --- a/src/linux/drivers/net/ethernet/marvell/Kconfig +++ /dev/null @@ -1,164 +0,0 @@ -# -# Marvell device configuration -# - -config NET_VENDOR_MARVELL - bool "Marvell devices" - default y - depends on PCI || CPU_PXA168 || MV64X60 || PPC32 || PLAT_ORION || INET - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Marvell devices. If you say Y, you will be - asked for your specific card in the following questions. - -if NET_VENDOR_MARVELL - -config MV643XX_ETH - tristate "Marvell Discovery (643XX) and Orion ethernet support" - depends on (MV64X60 || PPC32 || PLAT_ORION) && INET - select PHYLIB - select MVMDIO - ---help--- - This driver supports the gigabit ethernet MACs in the - Marvell Discovery PPC/MIPS chipset family (MV643XX) and - in the Marvell Orion ARM SoC family. - - Some boards that use the Discovery chipset are the Momenco - Ocelot C and Jaguar ATX and Pegasos II. - -config MVMDIO - tristate "Marvell MDIO interface support" - depends on HAS_IOMEM - select PHYLIB - ---help--- - This driver supports the MDIO interface found in the network - interface units of the Marvell EBU SoCs (Kirkwood, Orion5x, - Dove, Armada 370 and Armada XP). - - This driver is used by the MV643XX_ETH and MVNETA drivers. - -config MVNETA_BM_ENABLE - tristate "Marvell Armada 38x/XP network interface BM support" - depends on MVNETA - ---help--- - This driver supports auxiliary block of the network - interface units in the Marvell ARMADA XP and ARMADA 38x SoC - family, which is called buffer manager. - - This driver, when enabled, strictly cooperates with mvneta - driver and is common for all network ports of the devices, - even for Armada 370 SoC, which doesn't support hardware - buffer management. - -config MVNETA - tristate "Marvell Armada 370/38x/XP network interface support" - depends on PLAT_ORION - select MVMDIO - select FIXED_PHY - ---help--- - This driver supports the network interface units in the - Marvell ARMADA XP, ARMADA 370 and ARMADA 38x SoC family. - - Note that this driver is distinct from the mv643xx_eth - driver, which should be used for the older Marvell SoCs - (Dove, Orion, Discovery, Kirkwood). - -config MVNETA_BM - tristate - default y if MVNETA=y && MVNETA_BM_ENABLE!=n - default MVNETA_BM_ENABLE - select HWBM - help - MVNETA_BM must not be 'm' if MVNETA=y, so this symbol ensures - that all dependencies are met. - -config MVPP2 - tristate "Marvell Armada 375 network interface support" - depends on MACH_ARMADA_375 - select MVMDIO - ---help--- - This driver supports the network interface units in the - Marvell ARMADA 375 SoC. - -config PXA168_ETH - tristate "Marvell pxa168 ethernet support" - depends on HAS_IOMEM && HAS_DMA - depends on CPU_PXA168 || ARCH_BERLIN || COMPILE_TEST - select PHYLIB - ---help--- - This driver supports the pxa168 Ethernet ports. - - To compile this driver as a module, choose M here. The module - will be called pxa168_eth. - -config SKGE - tristate "Marvell Yukon Gigabit Ethernet support" - depends on PCI - select CRC32 - ---help--- - This driver support the Marvell Yukon or SysKonnect SK-98xx/SK-95xx - and related Gigabit Ethernet adapters. It is a new smaller driver - with better performance and more complete ethtool support. - - It does not support the link failover and network management - features that "portable" vendor supplied sk98lin driver does. - - This driver supports adapters based on the original Yukon chipset: - Marvell 88E8001, Belkin F5D5005, CNet GigaCard, DLink DGE-530T, - Linksys EG1032/EG1064, 3Com 3C940/3C940B, SysKonnect SK-9871/9872. - - It does not support the newer Yukon2 chipset: a separate driver, - sky2, is provided for these adapters. - - To compile this driver as a module, choose M here: the module - will be called skge. This is recommended. - -config SKGE_DEBUG - bool "Debugging interface" - depends on SKGE && DEBUG_FS - ---help--- - This option adds the ability to dump driver state for debugging. - The file /sys/kernel/debug/skge/ethX displays the state of the internal - transmit and receive rings. - - If unsure, say N. - -config SKGE_GENESIS - bool "Support for older SysKonnect Genesis boards" - depends on SKGE - ---help--- - This enables support for the older and uncommon SysKonnect Genesis - chips, which support MII via an external transceiver, instead of - an internal one. Disabling this option will save some memory - by making code smaller. If unsure say Y. - -config SKY2 - tristate "Marvell Yukon 2 support" - depends on PCI - select CRC32 - ---help--- - This driver supports Gigabit Ethernet adapters based on the - Marvell Yukon 2 chipset: - Marvell 88E8021/88E8022/88E8035/88E8036/88E8038/88E8050/88E8052/ - 88E8053/88E8055/88E8061/88E8062, SysKonnect SK-9E21D/SK-9S21 - - There is companion driver for the older Marvell Yukon and - SysKonnect Genesis based adapters: skge. - - To compile this driver as a module, choose M here: the module - will be called sky2. This is recommended. - -config SKY2_DEBUG - bool "Debugging interface" - depends on SKY2 && DEBUG_FS - ---help--- - This option adds the ability to dump driver state for debugging. - The file /sys/kernel/debug/sky2/ethX displays the state of the internal - transmit and receive rings. - - If unsure, say N. - -endif # NET_VENDOR_MARVELL diff --git a/src/linux/drivers/net/ethernet/mediatek/Kconfig b/src/linux/drivers/net/ethernet/mediatek/Kconfig deleted file mode 100644 index 698bb89..0000000 --- a/src/linux/drivers/net/ethernet/mediatek/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -config NET_VENDOR_MEDIATEK - bool "MediaTek ethernet driver" - depends on ARCH_MEDIATEK - ---help--- - If you have a Mediatek SoC with ethernet, say Y. - -if NET_VENDOR_MEDIATEK - -config NET_MEDIATEK_SOC - tristate "MediaTek MT7623 Gigabit ethernet support" - depends on NET_VENDOR_MEDIATEK && (MACH_MT7623 || MACH_MT2701) - select PHYLIB - ---help--- - This driver supports the gigabit ethernet MACs in the - MediaTek MT2701/MT7623 chipset family. - -endif #NET_VENDOR_MEDIATEK diff --git a/src/linux/drivers/net/ethernet/mellanox/Kconfig b/src/linux/drivers/net/ethernet/mellanox/Kconfig deleted file mode 100644 index d547010..0000000 --- a/src/linux/drivers/net/ethernet/mellanox/Kconfig +++ /dev/null @@ -1,23 +0,0 @@ -# -# Mellanox driver configuration -# - -config NET_VENDOR_MELLANOX - bool "Mellanox devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Mellanox cards. If you say Y, you will be asked - for your specific card in the following questions. - -if NET_VENDOR_MELLANOX - -source "drivers/net/ethernet/mellanox/mlx4/Kconfig" -source "drivers/net/ethernet/mellanox/mlx5/core/Kconfig" -source "drivers/net/ethernet/mellanox/mlxsw/Kconfig" - -endif # NET_VENDOR_MELLANOX diff --git a/src/linux/drivers/net/ethernet/mellanox/mlx4/Kconfig b/src/linux/drivers/net/ethernet/mellanox/mlx4/Kconfig deleted file mode 100644 index 5098e7f..0000000 --- a/src/linux/drivers/net/ethernet/mellanox/mlx4/Kconfig +++ /dev/null @@ -1,40 +0,0 @@ -# -# Mellanox driver configuration -# - -config MLX4_EN - tristate "Mellanox Technologies 1/10/40Gbit Ethernet support" - depends on MAY_USE_DEVLINK - depends on PCI - select MLX4_CORE - select PTP_1588_CLOCK - ---help--- - This driver supports Mellanox Technologies ConnectX Ethernet - devices. - -config MLX4_EN_DCB - bool "Data Center Bridging (DCB) Support" - default y - depends on MLX4_EN && DCB - ---help--- - Say Y here if you want to use Data Center Bridging (DCB) in the - driver. - If set to N, will not be able to configure QoS and ratelimit attributes. - This flag is depended on the kernel's DCB support. - - If unsure, set to Y - -config MLX4_CORE - tristate - depends on PCI - default n - -config MLX4_DEBUG - bool "Verbose debugging output" if (MLX4_CORE && EXPERT) - depends on MLX4_CORE - default y - ---help--- - This option causes debugging code to be compiled into the - mlx4_core driver. The output can be turned on via the - debug_level module parameter (which can also be set after - the driver is loaded through sysfs). diff --git a/src/linux/drivers/net/ethernet/mellanox/mlx5/core/Kconfig b/src/linux/drivers/net/ethernet/mellanox/mlx5/core/Kconfig deleted file mode 100644 index 521cfdb..0000000 --- a/src/linux/drivers/net/ethernet/mellanox/mlx5/core/Kconfig +++ /dev/null @@ -1,32 +0,0 @@ -# -# Mellanox driver configuration -# - -config MLX5_CORE - tristate "Mellanox Technologies ConnectX-4 and Connect-IB core driver" - depends on MAY_USE_DEVLINK - depends on PCI - default n - ---help--- - Core driver for low level functionality of the ConnectX-4 and - Connect-IB cards by Mellanox Technologies. - -config MLX5_CORE_EN - bool "Mellanox Technologies ConnectX-4 Ethernet support" - depends on NETDEVICES && ETHERNET && PCI && MLX5_CORE - select PTP_1588_CLOCK - default n - ---help--- - Ethernet support in Mellanox Technologies ConnectX-4 NIC. - -config MLX5_CORE_EN_DCB - bool "Data Center Bridging (DCB) Support" - default y - depends on MLX5_CORE_EN && DCB - ---help--- - Say Y here if you want to use Data Center Bridging (DCB) in the - driver. - If set to N, will not be able to configure QoS and ratelimit attributes. - This flag is depended on the kernel's DCB support. - - If unsure, set to Y diff --git a/src/linux/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/src/linux/drivers/net/ethernet/mellanox/mlxsw/Kconfig deleted file mode 100644 index 5989f7c..0000000 --- a/src/linux/drivers/net/ethernet/mellanox/mlxsw/Kconfig +++ /dev/null @@ -1,60 +0,0 @@ -# -# Mellanox switch drivers configuration -# - -config MLXSW_CORE - tristate "Mellanox Technologies Switch ASICs support" - depends on MAY_USE_DEVLINK - ---help--- - This driver supports Mellanox Technologies Switch ASICs family. - - To compile this driver as a module, choose M here: the - module will be called mlxsw_core. - -config MLXSW_CORE_HWMON - bool "HWMON support for Mellanox Technologies Switch ASICs" - depends on MLXSW_CORE && HWMON - depends on !(MLXSW_CORE=y && HWMON=m) - default y - ---help--- - Say Y here if you want to expose HWMON interface on mlxsw devices. - -config MLXSW_PCI - tristate "PCI bus implementation for Mellanox Technologies Switch ASICs" - depends on PCI && HAS_DMA && HAS_IOMEM && MLXSW_CORE - default m - ---help--- - This is PCI bus implementation for Mellanox Technologies Switch ASICs. - - To compile this driver as a module, choose M here: the - module will be called mlxsw_pci. - -config MLXSW_SWITCHX2 - tristate "Mellanox Technologies SwitchX-2 support" - depends on MLXSW_CORE && NET_SWITCHDEV - default m - ---help--- - This driver supports Mellanox Technologies SwitchX-2 Ethernet - Switch ASICs. - - To compile this driver as a module, choose M here: the - module will be called mlxsw_switchx2. - -config MLXSW_SPECTRUM - tristate "Mellanox Technologies Spectrum support" - depends on MLXSW_CORE && NET_SWITCHDEV && VLAN_8021Q - default m - ---help--- - This driver supports Mellanox Technologies Spectrum Ethernet - Switch ASICs. - - To compile this driver as a module, choose M here: the - module will be called mlxsw_spectrum. - -config MLXSW_SPECTRUM_DCB - bool "Data Center Bridging (DCB) support" - depends on MLXSW_SPECTRUM && DCB - default y - ---help--- - Say Y here if you want to use Data Center Bridging (DCB) in the - driver. diff --git a/src/linux/drivers/net/ethernet/micrel/Kconfig b/src/linux/drivers/net/ethernet/micrel/Kconfig deleted file mode 100644 index b7e2f49..0000000 --- a/src/linux/drivers/net/ethernet/micrel/Kconfig +++ /dev/null @@ -1,64 +0,0 @@ -# -# Micrel device configuration -# - -config NET_VENDOR_MICREL - bool "Micrel devices" - default y - depends on (HAS_IOMEM && DMA_ENGINE) || SPI || PCI || HAS_IOMEM || \ - (ARM && ARCH_KS8695) - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Micrel devices. If you say Y, you will be asked - for your specific card in the following questions. - -if NET_VENDOR_MICREL - -config ARM_KS8695_ETHER - tristate "KS8695 Ethernet support" - depends on ARM && ARCH_KS8695 - select MII - ---help--- - If you wish to compile a kernel for the KS8695 and want to - use the internal ethernet then you should answer Y to this. - -config KS8842 - tristate "Micrel KSZ8841/42 with generic bus interface" - depends on HAS_IOMEM && DMA_ENGINE - ---help--- - This platform driver is for KSZ8841(1-port) / KS8842(2-port) - ethernet switch chip (managed, VLAN, QoS) from Micrel or - Timberdale(FPGA). - -config KS8851 - tristate "Micrel KS8851 SPI" - depends on SPI - select MII - select CRC32 - select EEPROM_93CX6 - ---help--- - SPI driver for Micrel KS8851 SPI attached network chip. - -config KS8851_MLL - tristate "Micrel KS8851 MLL" - depends on HAS_IOMEM - select MII - ---help--- - This platform driver is for Micrel KS8851 Address/data bus - multiplexed network chip. - -config KSZ884X_PCI - tristate "Micrel KSZ8841/2 PCI" - depends on PCI - select MII - select CRC32 - ---help--- - This PCI driver is for Micrel KSZ8841/KSZ8842 PCI Ethernet chip. - - To compile this driver as a module, choose M here. The module - will be called ksz884x. - -endif # NET_VENDOR_MICREL diff --git a/src/linux/drivers/net/ethernet/microchip/Kconfig b/src/linux/drivers/net/ethernet/microchip/Kconfig deleted file mode 100644 index 36a09d9..0000000 --- a/src/linux/drivers/net/ethernet/microchip/Kconfig +++ /dev/null @@ -1,45 +0,0 @@ -# -# Microchip network device configuration -# - -config NET_VENDOR_MICROCHIP - bool "Microchip devices" - default y - depends on SPI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Microchip cards. If you say Y, you will be asked - for your specific card in the following questions. - -if NET_VENDOR_MICROCHIP - -config ENC28J60 - tristate "ENC28J60 support" - depends on SPI - select CRC32 - ---help--- - Support for the Microchip EN28J60 ethernet chip. - - To compile this driver as a module, choose M here. The module will be - called enc28j60. - -config ENC28J60_WRITEVERIFY - bool "Enable write verify" - depends on ENC28J60 - ---help--- - Enable the verify after the buffer write useful for debugging purpose. - If unsure, say N. - -config ENCX24J600 - tristate "ENCX24J600 support" - depends on SPI - ---help--- - Support for the Microchip ENC424J600/624J600 ethernet chip. - - To compile this driver as a module, choose M here. The module will be - called encx24j600. - -endif # NET_VENDOR_MICROCHIP diff --git a/src/linux/drivers/net/ethernet/moxa/Kconfig b/src/linux/drivers/net/ethernet/moxa/Kconfig deleted file mode 100644 index 5b531da..0000000 --- a/src/linux/drivers/net/ethernet/moxa/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -# -# MOXART device configuration -# - -config NET_VENDOR_MOXART - bool "MOXA ART devices" - default y - depends on (ARM && ARCH_MOXART) - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about MOXA ART devices. If you say Y, you will be asked - for your specific card in the following questions. - -if NET_VENDOR_MOXART - -config ARM_MOXART_ETHER - tristate "MOXART Ethernet support" - depends on ARM && ARCH_MOXART - select NET_CORE - ---help--- - If you wish to compile a kernel for a hardware with MOXA ART SoC and - want to use the internal ethernet then you should answer Y to this. - - -endif # NET_VENDOR_MOXART diff --git a/src/linux/drivers/net/ethernet/myricom/Kconfig b/src/linux/drivers/net/ethernet/myricom/Kconfig deleted file mode 100644 index 9645c72..0000000 --- a/src/linux/drivers/net/ethernet/myricom/Kconfig +++ /dev/null @@ -1,44 +0,0 @@ -# -# Myricom device configuration -# - -config NET_VENDOR_MYRI - bool "Myricom devices" - default y - depends on PCI && INET - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Myricom cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_MYRI - -config MYRI10GE - tristate "Myricom Myri-10G Ethernet support" - depends on PCI && INET - select FW_LOADER - select CRC32 - ---help--- - This driver supports Myricom Myri-10G Dual Protocol interface in - Ethernet mode. If the eeprom on your board is not recent enough, - you will need a newer firmware image. - You may get this image or more information, at: - - - - To compile this driver as a module, choose M here. The module - will be called myri10ge. - -config MYRI10GE_DCA - bool "Direct Cache Access (DCA) Support" - default y - depends on MYRI10GE && DCA && !(MYRI10GE=y && DCA=m) - ---help--- - Say Y here if you want to use Direct Cache Access (DCA) in the - driver. DCA is a method for warming the CPU cache before data - is used, with the intent of lessening the impact of cache misses. - -endif # NET_VENDOR_MYRI diff --git a/src/linux/drivers/net/ethernet/natsemi/Kconfig b/src/linux/drivers/net/ethernet/natsemi/Kconfig deleted file mode 100644 index a10ef50..0000000 --- a/src/linux/drivers/net/ethernet/natsemi/Kconfig +++ /dev/null @@ -1,64 +0,0 @@ -# -# National Semi-conductor device configuration -# - -config NET_VENDOR_NATSEMI - bool "National Semi-conductor devices" - default y - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about National Semi-conductor devices. If you say Y, - you will be asked for your specific card in the following questions. - -if NET_VENDOR_NATSEMI - -config MACSONIC - tristate "Macintosh SONIC based ethernet (onboard, NuBus, LC, CS)" - depends on MAC - ---help--- - Support for NatSemi SONIC based Ethernet devices. This includes - the onboard Ethernet in many Quadras as well as some LC-PDS, - a few Nubus and all known Comm Slot Ethernet cards. If you have - one of these say Y here. - - To compile this driver as a module, choose M here. This module will - be called macsonic. - -config MIPS_JAZZ_SONIC - tristate "MIPS JAZZ onboard SONIC Ethernet support" - depends on MACH_JAZZ - ---help--- - This is the driver for the onboard card of MIPS Magnum 4000, - Acer PICA, Olivetti M700-10 and a few other identical OEM systems. - -config NATSEMI - tristate "National Semiconductor DP8381x series PCI Ethernet support" - depends on PCI - select CRC32 - ---help--- - This driver is for the National Semiconductor DP83810 series, - which is used in cards from PureData, NetGear, Linksys - and others, including the 83815 chip. - More specific information and updates are available from - . - -config NS83820 - tristate "National Semiconductor DP83820 support" - depends on PCI - ---help--- - This is a driver for the National Semiconductor DP83820 series - of gigabit ethernet MACs. Cards using this chipset include - the D-Link DGE-500T, PureData's PDP8023Z-TG, SMC's SMC9462TX, - SOHO-GA2000T, SOHO-GA2500T. The driver supports the use of - zero copy. - -config XTENSA_XT2000_SONIC - tristate "Xtensa XT2000 onboard SONIC Ethernet support" - depends on XTENSA_PLATFORM_XT2000 - ---help--- - This is the driver for the onboard card of the Xtensa XT2000 board. - -endif # NET_VENDOR_NATSEMI diff --git a/src/linux/drivers/net/ethernet/neterion/Kconfig b/src/linux/drivers/net/ethernet/neterion/Kconfig deleted file mode 100644 index 7189900..0000000 --- a/src/linux/drivers/net/ethernet/neterion/Kconfig +++ /dev/null @@ -1,53 +0,0 @@ -# -# Exar device configuration -# - -config NET_VENDOR_EXAR - bool "Exar devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Exar cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_EXAR - -config S2IO - tristate "Exar Xframe 10Gb Ethernet Adapter" - depends on PCI - ---help--- - This driver supports Exar Corp's Xframe Series 10Gb Ethernet Adapters. - - More specific information on configuring the driver is in - . - - To compile this driver as a module, choose M here. The module - will be called s2io. - -config VXGE - tristate "Exar X3100 Series 10GbE PCIe Server Adapter" - depends on PCI - ---help--- - This driver supports Exar Corp's X3100 Series 10 GbE PCIe - I/O Virtualized Server Adapter. - - More specific information on configuring the driver is in - . - - To compile this driver as a module, choose M here. The module - will be called vxge. - -config VXGE_DEBUG_TRACE_ALL - bool "Enabling All Debug trace statements in driver" - default n - depends on VXGE - ---help--- - Say Y here if you want to enabling all the debug trace statements in - the vxge driver. By default only few debug trace statements are - enabled. - -endif # NET_VENDOR_EXAR diff --git a/src/linux/drivers/net/ethernet/netronome/Kconfig b/src/linux/drivers/net/ethernet/netronome/Kconfig deleted file mode 100644 index 9508ad7..0000000 --- a/src/linux/drivers/net/ethernet/netronome/Kconfig +++ /dev/null @@ -1,36 +0,0 @@ -# -# Netronome device configuration -# - -config NET_VENDOR_NETRONOME - bool "Netronome(R) devices" - default y - ---help--- - If you have a Netronome(R) network (Ethernet) card or device, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Netronome(R) cards. If you say Y, you will be - asked for your specific card in the following questions. - -if NET_VENDOR_NETRONOME - -config NFP_NETVF - tristate "Netronome(R) NFP4000/NFP6000 VF NIC driver" - depends on PCI && PCI_MSI - depends on VXLAN || VXLAN=n - ---help--- - This driver supports SR-IOV virtual functions of - the Netronome(R) NFP4000/NFP6000 cards working as - a advanced Ethernet NIC. - -config NFP_NET_DEBUG - bool "Debug support for Netronome(R) NFP3200/NFP6000 NIC drivers" - depends on NFP_NET || NFP_NETVF - ---help--- - Enable extra sanity checks and debugfs support in - Netronome(R) NFP3200/NFP6000 NIC PF and VF drivers. - Note: selecting this option may adversely impact - performance. - -endif diff --git a/src/linux/drivers/net/ethernet/nuvoton/Kconfig b/src/linux/drivers/net/ethernet/nuvoton/Kconfig deleted file mode 100644 index 71c973f..0000000 --- a/src/linux/drivers/net/ethernet/nuvoton/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -# -# Nuvoton network device configuration -# - -config NET_VENDOR_NUVOTON - bool "Nuvoton devices" - default y - depends on ARM && ARCH_W90X900 - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Nuvoton cards. If you say Y, you will be asked - for your specific card in the following questions. - -if NET_VENDOR_NUVOTON - -config W90P910_ETH - tristate "Nuvoton w90p910 Ethernet support" - depends on ARM && ARCH_W90X900 - select PHYLIB - select MII - ---help--- - Say Y here if you want to use built-in Ethernet ports - on w90p910 processor. - -endif # NET_VENDOR_NUVOTON diff --git a/src/linux/drivers/net/ethernet/nvidia/Kconfig b/src/linux/drivers/net/ethernet/nvidia/Kconfig deleted file mode 100644 index 4efc9fe..0000000 --- a/src/linux/drivers/net/ethernet/nvidia/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -# -# NVIDIA network device configuration -# - -config NET_VENDOR_NVIDIA - bool "NVIDIA devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about NVIDIA cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_NVIDIA - -config FORCEDETH - tristate "nForce Ethernet support" - depends on PCI - ---help--- - If you have a network (Ethernet) controller of this type, say Y here. - - To compile this driver as a module, choose M here. The module - will be called forcedeth. - -endif # NET_VENDOR_NVIDIA diff --git a/src/linux/drivers/net/ethernet/nxp/Kconfig b/src/linux/drivers/net/ethernet/nxp/Kconfig deleted file mode 100644 index 0d9baf9..0000000 --- a/src/linux/drivers/net/ethernet/nxp/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config LPC_ENET - tristate "NXP ethernet MAC on LPC devices" - depends on ARCH_LPC32XX - select PHYLIB - help - Say Y or M here if you want to use the NXP ethernet MAC included on - some NXP LPC devices. You can safely enable this option for LPC32xx - SoC. Also available as a module. diff --git a/src/linux/drivers/net/ethernet/oki-semi/Kconfig b/src/linux/drivers/net/ethernet/oki-semi/Kconfig deleted file mode 100644 index 5a975af..0000000 --- a/src/linux/drivers/net/ethernet/oki-semi/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -# -# OKI Semiconductor device configuration -# - -config NET_VENDOR_OKI - bool "OKI Semiconductor devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about OKI Semiconductor cards. If you say Y, you will - be asked for your specific card in the following questions. - -if NET_VENDOR_OKI - -source "drivers/net/ethernet/oki-semi/pch_gbe/Kconfig" - -endif # NET_VENDOR_OKI diff --git a/src/linux/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig b/src/linux/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig deleted file mode 100644 index 5f7a352..0000000 --- a/src/linux/drivers/net/ethernet/oki-semi/pch_gbe/Kconfig +++ /dev/null @@ -1,23 +0,0 @@ -# -# OKI Semiconductor device configuration -# - -config PCH_GBE - tristate "OKI SEMICONDUCTOR IOH(ML7223/ML7831) GbE" - depends on PCI && (X86_32 || COMPILE_TEST) - select MII - select PTP_1588_CLOCK_PCH - select NET_PTP_CLASSIFY - ---help--- - This is a gigabit ethernet driver for EG20T PCH. - EG20T PCH is the platform controller hub that is used in Intel's - general embedded platform. EG20T PCH has Gigabit Ethernet interface. - Using this interface, it is able to access system devices connected - to Gigabit Ethernet. This driver enables Gigabit Ethernet function. - - This driver also can be used for OKI SEMICONDUCTOR IOH(Input/ - Output Hub), ML7223/ML7831. - ML7223 IOH is for MP(Media Phone) use. ML7831 IOH is for general - purpose use. - ML7223/ML7831 is companion chip for Intel Atom E6xx series. - ML7223/ML7831 is completely compatible for Intel EG20T PCH. diff --git a/src/linux/drivers/net/ethernet/packetengines/Kconfig b/src/linux/drivers/net/ethernet/packetengines/Kconfig deleted file mode 100644 index b5ea2a5..0000000 --- a/src/linux/drivers/net/ethernet/packetengines/Kconfig +++ /dev/null @@ -1,43 +0,0 @@ -# -# Packet engine device configuration -# - -config NET_PACKET_ENGINE - bool "Packet Engine devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about packet engine devices. If you say Y, you will - be asked for your specific card in the following questions. - -if NET_PACKET_ENGINE - -config HAMACHI - tristate "Packet Engines Hamachi GNIC-II support" - depends on PCI - select MII - ---help--- - If you have a Gigabit Ethernet card of this type, say Y here. - - To compile this driver as a module, choose M here. The module will be - called hamachi. - -config YELLOWFIN - tristate "Packet Engines Yellowfin Gigabit-NIC support" - depends on PCI - select CRC32 - ---help--- - Say Y here if you have a Packet Engines G-NIC PCI Gigabit Ethernet - adapter or the SYM53C885 Ethernet controller. The Gigabit adapter is - used by the Beowulf Linux cluster project. See - for more - information about this driver in particular and Beowulf in general. - - To compile this driver as a module, choose M here: the module - will be called yellowfin. This is recommended. - -endif # NET_PACKET_ENGINE diff --git a/src/linux/drivers/net/ethernet/pasemi/Kconfig b/src/linux/drivers/net/ethernet/pasemi/Kconfig deleted file mode 100644 index 7c92e83..0000000 --- a/src/linux/drivers/net/ethernet/pasemi/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -# -# PA Semi network device configuration -# - -config NET_VENDOR_PASEMI - bool "PA Semi devices" - default y - depends on PPC_PASEMI && PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about PA Semi cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_PASEMI - -config PASEMI_MAC - tristate "PA Semi 1/10Gbit MAC" - depends on PPC_PASEMI && PCI - select PHYLIB - ---help--- - This driver supports the on-chip 1/10Gbit Ethernet controller on - PA Semi's PWRficient line of chips. - -endif # NET_VENDOR_PASEMI diff --git a/src/linux/drivers/net/ethernet/qlogic/Kconfig b/src/linux/drivers/net/ethernet/qlogic/Kconfig deleted file mode 100644 index 32f2a45..0000000 --- a/src/linux/drivers/net/ethernet/qlogic/Kconfig +++ /dev/null @@ -1,113 +0,0 @@ -# -# QLogic network device configuration -# - -config NET_VENDOR_QLOGIC - bool "QLogic devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about QLogic cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_QLOGIC - -config QLA3XXX - tristate "QLogic QLA3XXX Network Driver Support" - depends on PCI - ---help--- - This driver supports QLogic ISP3XXX gigabit Ethernet cards. - - To compile this driver as a module, choose M here: the module - will be called qla3xxx. - -config QLCNIC - tristate "QLOGIC QLCNIC 1/10Gb Converged Ethernet NIC Support" - depends on PCI - select FW_LOADER - ---help--- - This driver supports QLogic QLE8240 and QLE8242 Converged Ethernet - devices. - -config QLCNIC_SRIOV - bool "QLOGIC QLCNIC 83XX family SR-IOV Support" - depends on QLCNIC && PCI_IOV - default y - ---help--- - This configuration parameter enables Single Root Input Output - Virtualization support for QLE83XX Converged Ethernet devices. - This allows for virtual function acceleration in virtualized - environments. - -config QLCNIC_DCB - bool "QLOGIC QLCNIC 82XX and 83XX family DCB Support" - depends on QLCNIC && DCB - default y - ---help--- - This configuration parameter enables DCB support in QLE83XX - and QLE82XX Converged Ethernet devices. This allows for DCB - get operations support through rtNetlink interface. Only CEE - mode of DCB is supported. PG and PFC values are related only - to Tx. - -config QLCNIC_HWMON - bool "QLOGIC QLCNIC 82XX and 83XX family HWMON support" - depends on QLCNIC && HWMON && !(QLCNIC=y && HWMON=m) - default y - ---help--- - This configuration parameter can be used to read the - board temperature in Converged Ethernet devices - supported by qlcnic. - - This data is available via the hwmon sysfs interface. - -config QLGE - tristate "QLogic QLGE 10Gb Ethernet Driver Support" - depends on PCI - ---help--- - This driver supports QLogic ISP8XXX 10Gb Ethernet cards. - - To compile this driver as a module, choose M here: the module - will be called qlge. - -config NETXEN_NIC - tristate "NetXen Multi port (1/10) Gigabit Ethernet NIC" - depends on PCI - select FW_LOADER - ---help--- - This enables the support for NetXen's Gigabit Ethernet card. - -config QED - tristate "QLogic QED 25/40/100Gb core driver" - depends on PCI - select ZLIB_INFLATE - ---help--- - This enables the support for ... - -config QED_LL2 - bool - -config QED_SRIOV - bool "QLogic QED 25/40/100Gb SR-IOV support" - depends on QED && PCI_IOV - default y - ---help--- - This configuration parameter enables Single Root Input Output - Virtualization support for QED devices. - This allows for virtual function acceleration in virtualized - environments. - -config QEDE - tristate "QLogic QED 25/40/100Gb Ethernet NIC" - depends on QED - ---help--- - This enables the support for ... - -config QED_RDMA - bool - -endif # NET_VENDOR_QLOGIC diff --git a/src/linux/drivers/net/ethernet/qualcomm/Kconfig b/src/linux/drivers/net/ethernet/qualcomm/Kconfig deleted file mode 100644 index d7720bf..0000000 --- a/src/linux/drivers/net/ethernet/qualcomm/Kconfig +++ /dev/null @@ -1,40 +0,0 @@ -# -# Qualcomm network device configuration -# - -config NET_VENDOR_QUALCOMM - bool "Qualcomm devices" - default y - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Qualcomm cards. If you say Y, you will be asked - for your specific card in the following questions. - -if NET_VENDOR_QUALCOMM - -config QCA7000 - tristate "Qualcomm Atheros QCA7000 support" - depends on SPI_MASTER && OF - ---help--- - This SPI protocol driver supports the Qualcomm Atheros QCA7000. - - To compile this driver as a module, choose M here. The module - will be called qcaspi. - -config QCOM_EMAC - tristate "Qualcomm Technologies, Inc. EMAC Gigabit Ethernet support" - depends on HAS_DMA && HAS_IOMEM - select CRC32 - select PHYLIB - ---help--- - This driver supports the Qualcomm Technologies, Inc. Gigabit - Ethernet Media Access Controller (EMAC). The controller - supports IEEE 802.3-2002, half-duplex mode at 10/100 Mb/s, - full-duplex mode at 10/100/1000Mb/s, Wake On LAN (WOL) for - low power, Receive-Side Scaling (RSS), and IEEE 1588-2008 - Precision Clock Synchronization Protocol. - -endif # NET_VENDOR_QUALCOMM diff --git a/src/linux/drivers/net/ethernet/rdc/Kconfig b/src/linux/drivers/net/ethernet/rdc/Kconfig deleted file mode 100644 index a9c4e99..0000000 --- a/src/linux/drivers/net/ethernet/rdc/Kconfig +++ /dev/null @@ -1,32 +0,0 @@ -# -# RDC network device configuration -# - -config NET_VENDOR_RDC - bool "RDC devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about RDC cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_RDC - -config R6040 - tristate "RDC R6040 Fast Ethernet Adapter support" - depends on PCI - select CRC32 - select MII - select PHYLIB - ---help--- - This is a driver for the R6040 Fast Ethernet MACs found in the - the RDC R-321x System-on-chips. - - To compile this driver as a module, choose M here: the module - will be called r6040. This is recommended. - -endif # NET_VENDOR_RDC diff --git a/src/linux/drivers/net/ethernet/realtek/Kconfig b/src/linux/drivers/net/ethernet/realtek/Kconfig deleted file mode 100644 index 7c69f4c..0000000 --- a/src/linux/drivers/net/ethernet/realtek/Kconfig +++ /dev/null @@ -1,109 +0,0 @@ -# -# Realtek device configuration -# - -config NET_VENDOR_REALTEK - bool "Realtek devices" - default y - depends on PCI || (PARPORT && X86) - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Realtek devices. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_REALTEK - -config ATP - tristate "AT-LAN-TEC/RealTek pocket adapter support" - depends on PARPORT && X86 - select CRC32 - ---help--- - This is a network (Ethernet) device which attaches to your parallel - port. Read the file - if you want to use this. If you intend to use this driver, you - should have said N to the "Parallel printer support", because the two - drivers don't like each other. - - To compile this driver as a module, choose M here: the module - will be called atp. - -config 8139CP - tristate "RealTek RTL-8139 C+ PCI Fast Ethernet Adapter support" - depends on PCI - select CRC32 - select MII - ---help--- - This is a driver for the Fast Ethernet PCI network cards based on - the RTL8139C+ chips. If you have one of those, say Y here. - - To compile this driver as a module, choose M here: the module - will be called 8139cp. This is recommended. - -config 8139TOO - tristate "RealTek RTL-8129/8130/8139 PCI Fast Ethernet Adapter support" - depends on PCI - select CRC32 - select MII - ---help--- - This is a driver for the Fast Ethernet PCI network cards based on - the RTL 8129/8130/8139 chips. If you have one of those, say Y here. - - To compile this driver as a module, choose M here: the module - will be called 8139too. This is recommended. - -config 8139TOO_PIO - bool "Use PIO instead of MMIO" - default y - depends on 8139TOO - ---help--- - This instructs the driver to use programmed I/O ports (PIO) instead - of PCI shared memory (MMIO). This can possibly solve some problems - in case your mainboard has memory consistency issues. If unsure, - say N. - -config 8139TOO_TUNE_TWISTER - bool "Support for uncommon RTL-8139 rev. K (automatic channel equalization)" - depends on 8139TOO - ---help--- - This implements a function which might come in handy in case you - are using low quality on long cabling. It is required for RealTek - RTL-8139 revision K boards, and totally unused otherwise. It tries - to match the transceiver to the cable characteristics. This is - experimental since hardly documented by the manufacturer. - If unsure, say Y. - -config 8139TOO_8129 - bool "Support for older RTL-8129/8130 boards" - depends on 8139TOO - ---help--- - This enables support for the older and uncommon RTL-8129 and - RTL-8130 chips, which support MII via an external transceiver, - instead of an internal one. Disabling this option will save some - memory by making the code size smaller. If unsure, say Y. - -config 8139_OLD_RX_RESET - bool "Use older RX-reset method" - depends on 8139TOO - ---help--- - The 8139too driver was recently updated to contain a more rapid - reset sequence, in the face of severe receive errors. This "new" - RX-reset method should be adequate for all boards. But if you - experience problems, you can enable this option to restore the - old RX-reset behavior. If unsure, say N. - -config R8169 - tristate "Realtek 8169 gigabit ethernet support" - depends on PCI - select FW_LOADER - select CRC32 - select MII - ---help--- - Say Y here if you have a Realtek 8169 PCI Gigabit Ethernet adapter. - - To compile this driver as a module, choose M here: the module - will be called r8169. This is recommended. - -endif # NET_VENDOR_REALTEK diff --git a/src/linux/drivers/net/ethernet/renesas/Kconfig b/src/linux/drivers/net/ethernet/renesas/Kconfig deleted file mode 100644 index 85ec447..0000000 --- a/src/linux/drivers/net/ethernet/renesas/Kconfig +++ /dev/null @@ -1,46 +0,0 @@ -# -# Renesas device configuration -# - -config NET_VENDOR_RENESAS - bool "Renesas devices" - default y - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Renesas devices. If you say Y, you will be asked - for your specific device in the following questions. - -if NET_VENDOR_RENESAS - -config SH_ETH - tristate "Renesas SuperH Ethernet support" - depends on HAS_DMA - depends on ARCH_RENESAS || SUPERH || COMPILE_TEST - select CRC32 - select MII - select MDIO_BITBANG - select PHYLIB - ---help--- - Renesas SuperH Ethernet device driver. - This driver supporting CPUs are: - - SH7619, SH7710, SH7712, SH7724, SH7734, SH7763, SH7757, - R8A7740, R8A774x, R8A777x and R8A779x. - -config RAVB - tristate "Renesas Ethernet AVB support" - depends on HAS_DMA - depends on ARCH_RENESAS || COMPILE_TEST - select CRC32 - select MII - select MDIO_BITBANG - select PHYLIB - select PTP_1588_CLOCK - help - Renesas Ethernet AVB device driver. - This driver supports the following SoCs: - - R8A779x. - -endif # NET_VENDOR_RENESAS diff --git a/src/linux/drivers/net/ethernet/rocker/Kconfig b/src/linux/drivers/net/ethernet/rocker/Kconfig deleted file mode 100644 index b9952ef..0000000 --- a/src/linux/drivers/net/ethernet/rocker/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -# -# Rocker device configuration -# - -config NET_VENDOR_ROCKER - bool "Rocker devices" - default y - ---help--- - If you have a network device belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Rocker devices. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_ROCKER - -config ROCKER - tristate "Rocker switch driver (EXPERIMENTAL)" - depends on PCI && NET_SWITCHDEV && BRIDGE - ---help--- - This driver supports Rocker switch device. - - To compile this driver as a module, choose M here: the - module will be called rocker. - -endif # NET_VENDOR_ROCKER diff --git a/src/linux/drivers/net/ethernet/samsung/Kconfig b/src/linux/drivers/net/ethernet/samsung/Kconfig deleted file mode 100644 index 2360d81..0000000 --- a/src/linux/drivers/net/ethernet/samsung/Kconfig +++ /dev/null @@ -1,32 +0,0 @@ -# -# Samsung Ethernet device configuration -# - -config NET_VENDOR_SAMSUNG - bool "Samsung Ethernet devices" - default y - ---help--- - If you have a network (Ethernet) chipset belonging to this class, - say Y. - - Note that the answer to this question does not directly affect - the kernel: saying N will just case the configurator to skip all - the questions about Samsung chipsets. If you say Y, you will be asked - for your specific chipset/driver in the following questions. - -if NET_VENDOR_SAMSUNG - -config SXGBE_ETH - tristate "Samsung 10G/2.5G/1G SXGBE Ethernet driver" - depends on HAS_IOMEM && HAS_DMA - select PHYLIB - select CRC32 - select PTP_1588_CLOCK - ---help--- - This is the driver for the SXGBE 10G Ethernet IP block found on - Samsung platforms. - - To compile this driver as a module, choose M here: the module - will be called samsung-sxgbe. - -endif # NET_VENDOR_SAMSUNG diff --git a/src/linux/drivers/net/ethernet/seeq/Kconfig b/src/linux/drivers/net/ethernet/seeq/Kconfig deleted file mode 100644 index 69c62d8..0000000 --- a/src/linux/drivers/net/ethernet/seeq/Kconfig +++ /dev/null @@ -1,33 +0,0 @@ -# -# SEEQ device configuration -# - -config NET_VENDOR_SEEQ - bool "SEEQ devices" - default y - depends on HAS_IOMEM - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about SEEQ devices. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_SEEQ - -config ARM_ETHER3 - tristate "Acorn/ANT Ether3 support" - depends on ARM && ARCH_ACORN - ---help--- - If you have an Acorn system with one of these network cards, you - should say Y to this option if you wish to use it with Linux. - -config SGISEEQ - tristate "SGI Seeq ethernet controller support" - depends on SGI_HAS_SEEQ - ---help--- - Say Y here if you have an Seeq based Ethernet network card. This is - used in many Silicon Graphics machines. - -endif # NET_VENDOR_SEEQ diff --git a/src/linux/drivers/net/ethernet/sfc/Kconfig b/src/linux/drivers/net/ethernet/sfc/Kconfig deleted file mode 100644 index 4dd92b7..0000000 --- a/src/linux/drivers/net/ethernet/sfc/Kconfig +++ /dev/null @@ -1,47 +0,0 @@ -config SFC - tristate "Solarflare SFC4000/SFC9000/SFC9100-family support" - depends on PCI - select MDIO - select CRC32 - select I2C - select I2C_ALGOBIT - select PTP_1588_CLOCK - ---help--- - This driver supports 10/40-gigabit Ethernet cards based on - the Solarflare SFC4000, SFC9000-family and SFC9100-family - controllers. - - To compile this driver as a module, choose M here. The module - will be called sfc. -config SFC_MTD - bool "Solarflare SFC4000/SFC9000/SFC9100-family MTD support" - depends on SFC && MTD && !(SFC=y && MTD=m) - default y - ---help--- - This exposes the on-board flash and/or EEPROM as MTD devices - (e.g. /dev/mtd1). This is required to update the firmware or - the boot configuration under Linux. -config SFC_MCDI_MON - bool "Solarflare SFC9000/SFC9100-family hwmon support" - depends on SFC && HWMON && !(SFC=y && HWMON=m) - default y - ---help--- - This exposes the on-board firmware-managed sensors as a - hardware monitor device. -config SFC_SRIOV - bool "Solarflare SFC9000-family SR-IOV support" - depends on SFC && PCI_IOV - default y - ---help--- - This enables support for the SFC9000 I/O Virtualization - features, allowing accelerated network performance in - virtualized environments. -config SFC_MCDI_LOGGING - bool "Solarflare SFC9000/SFC9100-family MCDI logging support" - depends on SFC - default y - ---help--- - This enables support for tracing of MCDI (Management-Controller-to- - Driver-Interface) commands and responses, allowing debugging of - driver/firmware interaction. The tracing is actually enabled by - a sysfs file 'mcdi_logging' under the PCI device. diff --git a/src/linux/drivers/net/ethernet/sgi/Kconfig b/src/linux/drivers/net/ethernet/sgi/Kconfig deleted file mode 100644 index fbbb21c..0000000 --- a/src/linux/drivers/net/ethernet/sgi/Kconfig +++ /dev/null @@ -1,31 +0,0 @@ -# -# SGI device configuration -# - -config NET_VENDOR_SGI - bool "SGI devices" - default y - depends on (PCI && SGI_IP27) || SGI_IP32 - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about SGI devices. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_SGI - -config SGI_IOC3_ETH - bool "SGI IOC3 Ethernet" - depends on PCI && SGI_IP27 - select CRC32 - select MII - ---help--- - If you have a network (Ethernet) card of this type, say Y here. - -config SGI_O2MACE_ETH - tristate "SGI O2 MACE Fast Ethernet support" - depends on SGI_IP32=y - -endif # NET_VENDOR_SGI diff --git a/src/linux/drivers/net/ethernet/silan/Kconfig b/src/linux/drivers/net/ethernet/silan/Kconfig deleted file mode 100644 index ac982be..0000000 --- a/src/linux/drivers/net/ethernet/silan/Kconfig +++ /dev/null @@ -1,31 +0,0 @@ -# -# Silan device configuration -# - -config NET_VENDOR_SILAN - bool "Silan devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Silan devices. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_SILAN - -config SC92031 - tristate "Silan SC92031 PCI Fast Ethernet Adapter driver" - depends on PCI - select CRC32 - ---help--- - This is a driver for the Fast Ethernet PCI network cards based on - the Silan SC92031 chip (sometimes also called Rsltek 8139D). If you - have one of these, say Y here. - - To compile this driver as a module, choose M here: the module - will be called sc92031. This is recommended. - -endif # NET_VENDOR_SILAN diff --git a/src/linux/drivers/net/ethernet/sis/Kconfig b/src/linux/drivers/net/ethernet/sis/Kconfig deleted file mode 100644 index 22ec98e..0000000 --- a/src/linux/drivers/net/ethernet/sis/Kconfig +++ /dev/null @@ -1,49 +0,0 @@ -# -# Silicon Integrated Systems (SiS) device configuration -# - -config NET_VENDOR_SIS - bool "Silicon Integrated Systems (SiS) devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about SiS devices. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_SIS - -config SIS900 - tristate "SiS 900/7016 PCI Fast Ethernet Adapter support" - depends on PCI - select CRC32 - select MII - ---help--- - This is a driver for the Fast Ethernet PCI network cards based on - the SiS 900 and SiS 7016 chips. The SiS 900 core is also embedded in - SiS 630 and SiS 540 chipsets. - - This driver also supports AMD 79C901 HomePNA so that you can use - your phone line as a network cable. - - To compile this driver as a module, choose M here: the module - will be called sis900. This is recommended. - -config SIS190 - tristate "SiS190/SiS191 gigabit ethernet support" - depends on PCI - select CRC32 - select MII - ---help--- - Say Y here if you have a SiS 190 PCI Fast Ethernet adapter or - a SiS 191 PCI Gigabit Ethernet adapter. Both are expected to - appear in lan on motherboard designs which are based on SiS 965 - and SiS 966 south bridge. - - To compile this driver as a module, choose M here: the module - will be called sis190. This is recommended. - -endif # NET_VENDOR_SIS diff --git a/src/linux/drivers/net/ethernet/smsc/Kconfig b/src/linux/drivers/net/ethernet/smsc/Kconfig deleted file mode 100644 index 63aca9f..0000000 --- a/src/linux/drivers/net/ethernet/smsc/Kconfig +++ /dev/null @@ -1,125 +0,0 @@ -# -# Western Digital/SMC network device configuration -# - -config NET_VENDOR_SMSC - bool "SMC (SMSC)/Western Digital devices" - default y - depends on ARM || ARM64 || ATARI_ETHERNAT || BLACKFIN || COLDFIRE || \ - ISA || M32R || MAC || MIPS || MN10300 || NIOS2 || PCI || \ - PCMCIA || SUPERH || XTENSA || H8300 - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about SMC/Western Digital cards. If you say Y, you will - be asked for your specific card in the following questions. - -if NET_VENDOR_SMSC - -config SMC9194 - tristate "SMC 9194 support" - depends on (ISA || MAC && BROKEN) - select CRC32 - ---help--- - This is support for the SMC9xxx based Ethernet cards. Choose this - option if you have a DELL laptop with the docking station, or - another SMC9192/9194 based chipset. Say Y if you want it compiled - into the kernel, and read the file - . - - To compile this driver as a module, choose M here. The module - will be called smc9194. - -config SMC91X - tristate "SMC 91C9x/91C1xxx support" - select CRC32 - select MII - depends on !OF || GPIOLIB - depends on ARM || ARM64 || ATARI_ETHERNAT || BLACKFIN || COLDFIRE || \ - M32R || MIPS || MN10300 || NIOS2 || SUPERH || XTENSA || H8300 - ---help--- - This is a driver for SMC's 91x series of Ethernet chipsets, - including the SMC91C94 and the SMC91C111. Say Y if you want it - compiled into the kernel, and read the file - . - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called smc91x. If you want to compile it as a - module, say M here and read . - -config PCMCIA_SMC91C92 - tristate "SMC 91Cxx PCMCIA support" - depends on PCMCIA - select CRC32 - select MII - ---help--- - Say Y here if you intend to attach an SMC 91Cxx compatible PCMCIA - (PC-card) Ethernet or Fast Ethernet card to your computer. - - To compile this driver as a module, choose M here: the module will be - called smc91c92_cs. If unsure, say N. - -config EPIC100 - tristate "SMC EtherPower II" - depends on PCI - select CRC32 - select MII - ---help--- - This driver is for the SMC EtherPower II 9432 PCI Ethernet NIC, - which is based on the SMC83c17x (EPIC/100). - More specific information and updates are available from - . - -config SMC911X - tristate "SMSC LAN911[5678] support" - select CRC32 - select MII - depends on (ARM || SUPERH || MN10300) - ---help--- - This is a driver for SMSC's LAN911x series of Ethernet chipsets - including the new LAN9115, LAN9116, LAN9117, and LAN9118. - Say Y here if you want it compiled into the kernel. - - This driver is also available as a module. The module will be - called smc911x. If you want to compile it as a module, say M - here and read - -config SMSC911X - tristate "SMSC LAN911x/LAN921x families embedded ethernet support" - depends on HAS_IOMEM - select CRC32 - select MII - select PHYLIB - ---help--- - Say Y here if you want support for SMSC LAN911x and LAN921x families - of ethernet controllers. - - To compile this driver as a module, choose M here. The module - will be called smsc911x. - -config SMSC911X_ARCH_HOOKS - def_bool n - depends on SMSC911X - ---help--- - If the arch enables this, it allows the arch to implement various - hooks for more comprehensive interrupt control and also to override - the source of the MAC address. - -config SMSC9420 - tristate "SMSC LAN9420 PCI ethernet adapter support" - depends on PCI - select CRC32 - select PHYLIB - select SMSC_PHY - ---help--- - This is a driver for SMSC's LAN9420 PCI ethernet adapter. - Say Y here if you want it compiled into the kernel. - - This driver is also available as a module. The module will be - called smsc9420. If you want to compile it as a module, say M - here and read - -endif # NET_VENDOR_SMSC diff --git a/src/linux/drivers/net/ethernet/stmicro/Kconfig b/src/linux/drivers/net/ethernet/stmicro/Kconfig deleted file mode 100644 index 1c1157d..0000000 --- a/src/linux/drivers/net/ethernet/stmicro/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -# -# STMicroelectronics device configuration -# - -config NET_VENDOR_STMICRO - bool "STMicroelectronics devices" - default y - depends on HAS_IOMEM - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about STMicroelectronics cards. If you say Y, you will - be asked for your specific card in the following questions. - -if NET_VENDOR_STMICRO - -source "drivers/net/ethernet/stmicro/stmmac/Kconfig" - -endif # NET_VENDOR_STMICRO diff --git a/src/linux/drivers/net/ethernet/stmicro/stmmac/Kconfig b/src/linux/drivers/net/ethernet/stmicro/stmmac/Kconfig deleted file mode 100644 index 4b78168..0000000 --- a/src/linux/drivers/net/ethernet/stmicro/stmmac/Kconfig +++ /dev/null @@ -1,142 +0,0 @@ -config STMMAC_ETH - tristate "STMicroelectronics 10/100/1000 Ethernet driver" - depends on HAS_IOMEM && HAS_DMA - select MII - select PHYLIB - select CRC32 - select PTP_1588_CLOCK - select RESET_CONTROLLER - ---help--- - This is the driver for the Ethernet IPs are built around a - Synopsys IP Core and only tested on the STMicroelectronics - platforms. - -if STMMAC_ETH - -config STMMAC_PLATFORM - tristate "STMMAC Platform bus support" - depends on STMMAC_ETH - select MFD_SYSCON - default y - ---help--- - This selects the platform specific bus support for the stmmac driver. - This is the driver used on several SoCs: - STi, Allwinner, Amlogic Meson, Altera SOCFPGA. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -if STMMAC_PLATFORM - -config DWMAC_GENERIC - tristate "Generic driver for DWMAC" - default STMMAC_PLATFORM - ---help--- - Generic DWMAC driver for platforms that don't require any - platform specific code to function or is using platform - data for setup. - -config DWMAC_IPQ806X - tristate "QCA IPQ806x DWMAC support" - default ARCH_QCOM - depends on OF && (ARCH_QCOM || COMPILE_TEST) - select MFD_SYSCON - help - Support for QCA IPQ806X DWMAC Ethernet. - - This selects the IPQ806x SoC glue layer support for the stmmac - device driver. This driver does not use any of the hardware - acceleration features available on this SoC. Network devices - will behave like standard non-accelerated ethernet interfaces. - -config DWMAC_LPC18XX - tristate "NXP LPC18xx/43xx DWMAC support" - default ARCH_LPC18XX - depends on OF && (ARCH_LPC18XX || COMPILE_TEST) - select MFD_SYSCON - ---help--- - Support for NXP LPC18xx/43xx DWMAC Ethernet. - -config DWMAC_MESON - tristate "Amlogic Meson dwmac support" - default ARCH_MESON - depends on OF && COMMON_CLK && (ARCH_MESON || COMPILE_TEST) - help - Support for Ethernet controller on Amlogic Meson SoCs. - - This selects the Amlogic Meson SoC glue layer support for - the stmmac device driver. This driver is used for Meson6, - Meson8, Meson8b and GXBB SoCs. - -config DWMAC_ROCKCHIP - tristate "Rockchip dwmac support" - default ARCH_ROCKCHIP - depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST) - select MFD_SYSCON - help - Support for Ethernet controller on Rockchip RK3288 SoC. - - This selects the Rockchip RK3288 SoC glue layer support for - the stmmac device driver. - -config DWMAC_SOCFPGA - tristate "SOCFPGA dwmac support" - default ARCH_SOCFPGA - depends on OF && (ARCH_SOCFPGA || COMPILE_TEST) - select MFD_SYSCON - help - Support for ethernet controller on Altera SOCFPGA - - This selects the Altera SOCFPGA SoC glue layer support - for the stmmac device driver. This driver is used for - arria5 and cyclone5 FPGA SoCs. - -config DWMAC_STI - tristate "STi GMAC support" - default ARCH_STI - depends on OF && (ARCH_STI || COMPILE_TEST) - select MFD_SYSCON - ---help--- - Support for ethernet controller on STi SOCs. - - This selects STi SoC glue layer support for the stmmac - device driver. This driver is used on for the STi series - SOCs GMAC ethernet controller. - -config DWMAC_STM32 - tristate "STM32 DWMAC support" - default ARCH_STM32 - depends on OF && HAS_IOMEM && (ARCH_STM32 || COMPILE_TEST) - select MFD_SYSCON - ---help--- - Support for ethernet controller on STM32 SOCs. - - This selects STM32 SoC glue layer support for the stmmac - device driver. This driver is used on for the STM32 series - SOCs GMAC ethernet controller. - -config DWMAC_SUNXI - tristate "Allwinner GMAC support" - default ARCH_SUNXI - depends on OF && (ARCH_SUNXI || COMPILE_TEST) - ---help--- - Support for Allwinner A20/A31 GMAC ethernet controllers. - - This selects Allwinner SoC glue layer support for the - stmmac device driver. This driver is used for A20/A31 - GMAC ethernet controller. -endif - -config STMMAC_PCI - tristate "STMMAC PCI bus support" - depends on STMMAC_ETH && PCI - ---help--- - This is to select the Synopsys DWMAC available on PCI devices, - if you have a controller with this interface, say Y or M here. - - This PCI support is tested on XLINX XC2V3000 FF1152AMT0221 - D1215994A VIRTEX FPGA board. - - If unsure, say N. -endif diff --git a/src/linux/drivers/net/ethernet/sun/Kconfig b/src/linux/drivers/net/ethernet/sun/Kconfig deleted file mode 100644 index a4b40e3..0000000 --- a/src/linux/drivers/net/ethernet/sun/Kconfig +++ /dev/null @@ -1,102 +0,0 @@ -# -# Sun network device configuration -# - -config NET_VENDOR_SUN - bool "Sun devices" - default y - depends on SUN3 || SBUS || PCI || SUN_LDOMS - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Sun network interfaces. If you say Y, you will be - asked for your specific card in the following questions. - -if NET_VENDOR_SUN - -config HAPPYMEAL - tristate "Sun Happy Meal 10/100baseT support" - depends on (SBUS || PCI) - select CRC32 - ---help--- - This driver supports the "hme" interface present on most Ultra - systems and as an option on older Sbus systems. This driver supports - both PCI and Sbus devices. This driver also supports the "qfe" quad - 100baseT device available in both PCI and Sbus configurations. - - To compile this driver as a module, choose M here: the module - will be called sunhme. - -config SUNBMAC - tristate "Sun BigMAC 10/100baseT support" - depends on SBUS - select CRC32 - ---help--- - This driver supports the "be" interface available as an Sbus option. - This is Sun's older 100baseT Ethernet device. - - To compile this driver as a module, choose M here: the module - will be called sunbmac. - -config SUNQE - tristate "Sun QuadEthernet support" - depends on SBUS - select CRC32 - ---help--- - This driver supports the "qe" 10baseT Ethernet device, available as - an Sbus option. Note that this is not the same as Quad FastEthernet - "qfe" which is supported by the Happy Meal driver instead. - - To compile this driver as a module, choose M here: the module - will be called sunqe. - -config SUNGEM - tristate "Sun GEM support" - depends on PCI - select CRC32 - select SUNGEM_PHY - ---help--- - Support for the Sun GEM chip, aka Sun GigabitEthernet/P 2.0. See also - . - -config CASSINI - tristate "Sun Cassini support" - depends on PCI - select CRC32 - ---help--- - Support for the Sun Cassini chip, aka Sun GigaSwift Ethernet. See also - . - -config SUNVNET_COMMON - bool - depends on SUN_LDOMS - default y if SUN_LDOMS - -config SUNVNET - tristate "Sun Virtual Network support" - depends on SUN_LDOMS - ---help--- - Support for virtual network devices under Sun Logical Domains. - -config LDMVSW - tristate "Sun4v LDoms Virtual Switch support" - depends on SUN_LDOMS - ---help--- - Support for virtual switch devices under Sun4v Logical Domains. - This driver adds a network interface for every vsw-port node - found in the machine description of a service domain. - Linux bridge/switch software can use these interfaces for - guest domain network interconnectivity or guest domain - connection to a physical network on a service domain. - -config NIU - tristate "Sun Neptune 10Gbit Ethernet support" - depends on PCI - select CRC32 - ---help--- - This enables support for cards based upon Sun's - Neptune chipset. - -endif # NET_VENDOR_SUN diff --git a/src/linux/drivers/net/ethernet/synopsys/Kconfig b/src/linux/drivers/net/ethernet/synopsys/Kconfig deleted file mode 100644 index 8276ee5..0000000 --- a/src/linux/drivers/net/ethernet/synopsys/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -# -# Synopsys network device configuration -# - -config NET_VENDOR_SYNOPSYS - bool "Synopsys devices" - default y - ---help--- - If you have a network (Ethernet) device belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Synopsys devices. If you say Y, you will be asked - for your specific device in the following questions. - -if NET_VENDOR_SYNOPSYS - -config SYNOPSYS_DWC_ETH_QOS - tristate "Sypnopsys DWC Ethernet QOS v4.10a support" - select PHYLIB - select CRC32 - select MII - depends on OF && HAS_DMA - ---help--- - This driver supports the DWC Ethernet QoS from Synopsys - -endif # NET_VENDOR_SYNOPSYS diff --git a/src/linux/drivers/net/ethernet/tehuti/Kconfig b/src/linux/drivers/net/ethernet/tehuti/Kconfig deleted file mode 100644 index b17f0ca..0000000 --- a/src/linux/drivers/net/ethernet/tehuti/Kconfig +++ /dev/null @@ -1,25 +0,0 @@ -# -# Tehuti network device configuration -# - -config NET_VENDOR_TEHUTI - bool "Tehuti devices" - default y - depends on PCI - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Tehuti cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_TEHUTI - -config TEHUTI - tristate "Tehuti Networks 10G Ethernet" - depends on PCI - ---help--- - Tehuti Networks 10G Ethernet NIC - -endif # NET_VENDOR_TEHUTI diff --git a/src/linux/drivers/net/ethernet/ti/Kconfig b/src/linux/drivers/net/ethernet/ti/Kconfig deleted file mode 100644 index 9904d74..0000000 --- a/src/linux/drivers/net/ethernet/ti/Kconfig +++ /dev/null @@ -1,128 +0,0 @@ -# -# TI device configuration -# - -config NET_VENDOR_TI - bool "Texas Instruments (TI) devices" - default y - depends on PCI || EISA || AR7 || ARCH_DAVINCI || ARCH_OMAP2PLUS || ARCH_KEYSTONE - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about TI devices. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_TI - -config TI_DAVINCI_EMAC - tristate "TI DaVinci EMAC Support" - depends on ARM && ( ARCH_DAVINCI || ARCH_OMAP3 ) - select TI_DAVINCI_MDIO - select TI_DAVINCI_CPDMA - select PHYLIB - ---help--- - This driver supports TI's DaVinci Ethernet . - - To compile this driver as a module, choose M here: the module - will be called davinci_emac_driver. This is recommended. - -config TI_DAVINCI_MDIO - tristate "TI DaVinci MDIO Support" - depends on ARCH_DAVINCI || ARCH_OMAP2PLUS || ARCH_KEYSTONE - select PHYLIB - ---help--- - This driver supports TI's DaVinci MDIO module. - - To compile this driver as a module, choose M here: the module - will be called davinci_mdio. This is recommended. - -config TI_DAVINCI_CPDMA - tristate "TI DaVinci CPDMA Support" - depends on ARCH_DAVINCI || ARCH_OMAP2PLUS - ---help--- - This driver supports TI's DaVinci CPDMA dma engine. - - To compile this driver as a module, choose M here: the module - will be called davinci_cpdma. This is recommended. - -config TI_CPSW_PHY_SEL - bool - ---help--- - This driver supports configuring of the phy mode connected to - the CPSW. - -config TI_CPSW_ALE - tristate "TI CPSW ALE Support" - ---help--- - This driver supports TI's CPSW ALE module. - -config TI_CPSW - tristate "TI CPSW Switch Support" - depends on ARCH_DAVINCI || ARCH_OMAP2PLUS - select TI_DAVINCI_CPDMA - select TI_DAVINCI_MDIO - select TI_CPSW_PHY_SEL - select TI_CPSW_ALE - select MFD_SYSCON - select REGMAP - ---help--- - This driver supports TI's CPSW Ethernet Switch. - - To compile this driver as a module, choose M here: the module - will be called cpsw. - -config TI_CPTS - bool "TI Common Platform Time Sync (CPTS) Support" - depends on TI_CPSW - select PTP_1588_CLOCK - ---help--- - This driver supports the Common Platform Time Sync unit of - the CPSW Ethernet Switch. The unit can time stamp PTP UDP/IPv4 - and Layer 2 packets, and the driver offers a PTP Hardware Clock. - -config TI_KEYSTONE_NETCP - tristate "TI Keystone NETCP Core Support" - select TI_CPSW_ALE - select TI_DAVINCI_MDIO - depends on OF - depends on KEYSTONE_NAVIGATOR_DMA && KEYSTONE_NAVIGATOR_QMSS - ---help--- - This driver supports TI's Keystone NETCP Core. - - To compile this driver as a module, choose M here: the module - will be called keystone_netcp. - -config TI_KEYSTONE_NETCP_ETHSS - depends on TI_KEYSTONE_NETCP - tristate "TI Keystone NETCP Ethernet subsystem Support" - ---help--- - - To compile this driver as a module, choose M here: the module - will be called keystone_netcp_ethss. - -config TLAN - tristate "TI ThunderLAN support" - depends on (PCI || EISA) - ---help--- - If you have a PCI Ethernet network card based on the ThunderLAN chip - which is supported by this driver, say Y here. - - Devices currently supported by this driver are Compaq Netelligent, - Compaq NetFlex and Olicom cards. Please read the file - for more details. - - To compile this driver as a module, choose M here. The module - will be called tlan. - - Please email feedback to . - -config CPMAC - tristate "TI AR7 CPMAC Ethernet support" - depends on AR7 - select PHYLIB - ---help--- - TI AR7 CPMAC Ethernet support - -endif # NET_VENDOR_TI diff --git a/src/linux/drivers/net/ethernet/tile/Kconfig b/src/linux/drivers/net/ethernet/tile/Kconfig deleted file mode 100644 index f59a6c2..0000000 --- a/src/linux/drivers/net/ethernet/tile/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -# -# Tilera network device configuration -# - -config TILE_NET - tristate "Tilera GBE/XGBE network driver support" - depends on TILE - default y - select CRC32 - select TILE_GXIO_MPIPE if TILEGX - select HIGH_RES_TIMERS if TILEGX - select PTP_1588_CLOCK if TILEGX - ---help--- - This is a standard Linux network device driver for the - on-chip Tilera Gigabit Ethernet and XAUI interfaces. - - To compile this driver as a module, choose M here: the module - will be called tile_net. diff --git a/src/linux/drivers/net/ethernet/toshiba/Kconfig b/src/linux/drivers/net/ethernet/toshiba/Kconfig deleted file mode 100644 index 6f1d5b6..0000000 --- a/src/linux/drivers/net/ethernet/toshiba/Kconfig +++ /dev/null @@ -1,55 +0,0 @@ -# -# Toshiba network device configuration -# - -config NET_VENDOR_TOSHIBA - bool "Toshiba devices" - default y - depends on PCI && (PPC_IBM_CELL_BLADE || MIPS) || PPC_PS3 - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Toshiba cards. If you say Y, you will be asked - for your specific card in the following questions. - -if NET_VENDOR_TOSHIBA - -config GELIC_NET - tristate "PS3 Gigabit Ethernet driver" - depends on PPC_PS3 - select PS3_SYS_MANAGER - ---help--- - This driver supports the network device on the PS3 game - console. This driver has built-in support for Ethernet. - - To compile this driver as a module, choose M here: the - module will be called ps3_gelic. - -config GELIC_WIRELESS - bool "PS3 Wireless support" - depends on GELIC_NET && WLAN - select WIRELESS_EXT - ---help--- - This option adds the support for the wireless feature of PS3. - If you have the wireless-less model of PS3 or have no plan to - use wireless feature, disabling this option saves memory. As - the driver automatically distinguishes the models, you can - safely enable this option even if you have a wireless-less model. - -config SPIDER_NET - tristate "Spider Gigabit Ethernet driver" - depends on PCI && PPC_IBM_CELL_BLADE - select FW_LOADER - select SUNGEM_PHY - ---help--- - This driver supports the Gigabit Ethernet chips present on the - Cell Processor-Based Blades from IBM. - -config TC35815 - tristate "TOSHIBA TC35815 Ethernet support" - depends on PCI && MIPS - select PHYLIB - -endif # NET_VENDOR_TOSHIBA diff --git a/src/linux/drivers/net/ethernet/tundra/Kconfig b/src/linux/drivers/net/ethernet/tundra/Kconfig deleted file mode 100644 index 81d845e..0000000 --- a/src/linux/drivers/net/ethernet/tundra/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -# -# Tundra network device configuration -# - -config NET_VENDOR_TUNDRA - bool "Tundra devices" - default y - depends on TSI108_BRIDGE - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Tundra cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_TUNDRA - -config TSI108_ETH - tristate "Tundra TSI108 gigabit Ethernet support" - depends on TSI108_BRIDGE - ---help--- - This driver supports Tundra TSI108 gigabit Ethernet ports. - To compile this driver as a module, choose M here: the module - will be called tsi108_eth. - -endif # NET_VENDOR_TUNDRA diff --git a/src/linux/drivers/net/ethernet/via/Kconfig b/src/linux/drivers/net/ethernet/via/Kconfig deleted file mode 100644 index d3d0947..0000000 --- a/src/linux/drivers/net/ethernet/via/Kconfig +++ /dev/null @@ -1,56 +0,0 @@ -# -# VIA device configuration -# - -config NET_VENDOR_VIA - bool "VIA devices" - default y - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about VIA devices. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_VIA - -config VIA_RHINE - tristate "VIA Rhine support" - depends on PCI || (OF_IRQ && GENERIC_PCI_IOMAP) - depends on HAS_DMA - select CRC32 - select MII - ---help--- - If you have a VIA "Rhine" based network card (Rhine-I (VT86C100A), - Rhine-II (VT6102), or Rhine-III (VT6105)), say Y here. Rhine-type - Ethernet functions can also be found integrated on South Bridges - (e.g. VT8235). - - To compile this driver as a module, choose M here. The module - will be called via-rhine. - -config VIA_RHINE_MMIO - bool "Use MMIO instead of PIO" - depends on VIA_RHINE - ---help--- - This instructs the driver to use PCI shared memory (MMIO) instead of - programmed I/O ports (PIO). Enabling this gives an improvement in - processing time in parts of the driver. - - If unsure, say Y. - -config VIA_VELOCITY - tristate "VIA Velocity support" - depends on (PCI || (OF_ADDRESS && OF_IRQ)) - depends on HAS_DMA - select CRC32 - select CRC_CCITT - select MII - ---help--- - If you have a VIA "Velocity" based network card say Y here. - - To compile this driver as a module, choose M here. The module - will be called via-velocity. - -endif # NET_VENDOR_VIA diff --git a/src/linux/drivers/net/ethernet/wiznet/Kconfig b/src/linux/drivers/net/ethernet/wiznet/Kconfig deleted file mode 100644 index 1981e88..0000000 --- a/src/linux/drivers/net/ethernet/wiznet/Kconfig +++ /dev/null @@ -1,86 +0,0 @@ -# -# WIZnet devices configuration -# - -config NET_VENDOR_WIZNET - bool "WIZnet devices" - depends on HAS_IOMEM - default y - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about WIZnet devices. If you say Y, you will be asked - for your specific card in the following questions. - -if NET_VENDOR_WIZNET - -config WIZNET_W5100 - tristate "WIZnet W5100 Ethernet support" - depends on HAS_IOMEM - ---help--- - Support for WIZnet W5100 chips. - - W5100 is a single chip with integrated 10/100 Ethernet MAC, - PHY and hardware TCP/IP stack, but this driver is limited to - the MAC and PHY functions only, onchip TCP/IP is unused. - - To compile this driver as a module, choose M here: the module - will be called w5100. - -config WIZNET_W5300 - tristate "WIZnet W5300 Ethernet support" - depends on HAS_IOMEM - ---help--- - Support for WIZnet W5300 chips. - - W5300 is a single chip with integrated 10/100 Ethernet MAC, - PHY and hardware TCP/IP stack, but this driver is limited to - the MAC and PHY functions only, onchip TCP/IP is unused. - - To compile this driver as a module, choose M here: the module - will be called w5300. - -choice - prompt "WIZnet interface mode" - depends on WIZNET_W5100 || WIZNET_W5300 - default WIZNET_BUS_ANY - -config WIZNET_BUS_DIRECT - bool "Direct address bus mode" - ---help--- - In direct address mode host system can directly access all registers - after mapping to Memory-Mapped I/O space. - -config WIZNET_BUS_INDIRECT - bool "Indirect address bus mode" - ---help--- - In indirect address mode host system indirectly accesses registers - using Indirect Mode Address Register and Indirect Mode Data Register, - which are directly mapped to Memory-Mapped I/O space. - -config WIZNET_BUS_ANY - bool "Select interface mode in runtime" - ---help--- - If interface mode is unknown in compile time, it can be selected - in runtime from board/platform resources configuration. - - Performance may decrease compared to explicitly selected bus mode. -endchoice - -config WIZNET_W5100_SPI - tristate "WIZnet W5100/W5200/W5500 Ethernet support for SPI mode" - depends on WIZNET_BUS_ANY && WIZNET_W5100 - depends on SPI - ---help--- - In SPI mode host system accesses registers using SPI protocol - (mode 0) on the SPI bus. - - Performance decreases compared to other bus interface mode. - In W5100 SPI mode, burst READ/WRITE processing are not provided. - - To compile this driver as a module, choose M here: the module - will be called w5100-spi. - -endif # NET_VENDOR_WIZNET diff --git a/src/linux/drivers/net/ethernet/xilinx/Kconfig b/src/linux/drivers/net/ethernet/xilinx/Kconfig deleted file mode 100644 index 6d68c8a..0000000 --- a/src/linux/drivers/net/ethernet/xilinx/Kconfig +++ /dev/null @@ -1,42 +0,0 @@ -# -# Xilink device configuration -# - -config NET_VENDOR_XILINX - bool "Xilinx devices" - default y - depends on PPC || PPC32 || MICROBLAZE || ARCH_ZYNQ || MIPS - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Xilinx devices. If you say Y, you will be asked - for your specific card in the following questions. - -if NET_VENDOR_XILINX - -config XILINX_EMACLITE - tristate "Xilinx 10/100 Ethernet Lite support" - depends on PPC32 || MICROBLAZE || ARCH_ZYNQ || MIPS - select PHYLIB - ---help--- - This driver supports the 10/100 Ethernet Lite from Xilinx. - -config XILINX_AXI_EMAC - tristate "Xilinx 10/100/1000 AXI Ethernet support" - depends on MICROBLAZE - select PHYLIB - ---help--- - This driver supports the 10/100/1000 Ethernet from Xilinx for the - AXI bus interface used in Xilinx Virtex FPGAs. - -config XILINX_LL_TEMAC - tristate "Xilinx LL TEMAC (LocalLink Tri-mode Ethernet MAC) driver" - depends on (PPC || MICROBLAZE) - select PHYLIB - ---help--- - This driver supports the Xilinx 10/100/1000 LocalLink TEMAC - core used in Xilinx Spartan and Virtex FPGAs - -endif # NET_VENDOR_XILINX diff --git a/src/linux/drivers/net/ethernet/xircom/Kconfig b/src/linux/drivers/net/ethernet/xircom/Kconfig deleted file mode 100644 index d6208a4..0000000 --- a/src/linux/drivers/net/ethernet/xircom/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -# -# Xircom network device configuration -# - -config NET_VENDOR_XIRCOM - bool "Xircom devices" - default y - depends on PCMCIA - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about Xircom cards. If you say Y, you will be asked for - your specific card in the following questions. - -if NET_VENDOR_XIRCOM - -config PCMCIA_XIRC2PS - tristate "Xircom 16-bit PCMCIA support" - depends on PCMCIA - ---help--- - Say Y here if you intend to attach a Xircom 16-bit PCMCIA (PC-card) - Ethernet or Fast Ethernet card to your computer. - - To compile this driver as a module, choose M here: the module will be - called xirc2ps_cs. If unsure, say N. - -endif # NET_VENDOR_XIRCOM diff --git a/src/linux/drivers/net/ethernet/xscale/Kconfig b/src/linux/drivers/net/ethernet/xscale/Kconfig deleted file mode 100644 index af3432f..0000000 --- a/src/linux/drivers/net/ethernet/xscale/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -# -# Intel XScale IXP device configuration -# - -config NET_VENDOR_XSCALE - bool "Intel XScale IXP devices" - default y - depends on NET_VENDOR_INTEL && (ARM && ARCH_IXP4XX && \ - IXP4XX_NPE && IXP4XX_QMGR) - ---help--- - If you have a network (Ethernet) card belonging to this class, say Y. - - Note that the answer to this question does not directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about XSacle IXP devices. If you say Y, you will be - asked for your specific card in the following questions. - -if NET_VENDOR_XSCALE - -config IXP4XX_ETH - tristate "Intel IXP4xx Ethernet support" - depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR - select PHYLIB - select NET_PTP_CLASSIFY - ---help--- - Say Y here if you want to use built-in Ethernet ports - on IXP4xx processor. - -endif # NET_VENDOR_XSCALE diff --git a/src/linux/drivers/net/fddi/Kconfig b/src/linux/drivers/net/fddi/Kconfig deleted file mode 100644 index 3a424c8..0000000 --- a/src/linux/drivers/net/fddi/Kconfig +++ /dev/null @@ -1,77 +0,0 @@ -# -# FDDI network device configuration -# - -config FDDI - tristate "FDDI driver support" - depends on PCI || EISA || TC - ---help--- - Fiber Distributed Data Interface is a high speed local area network - design; essentially a replacement for high speed Ethernet. FDDI can - run over copper or fiber. If you are connected to such a network and - want a driver for the FDDI card in your computer, say Y here (and - then also Y to the driver for your FDDI card, below). Most people - will say N. - -if FDDI - -config DEFXX - tristate "Digital DEFTA/DEFEA/DEFPA adapter support" - depends on FDDI && (PCI || EISA || TC) - ---help--- - This is support for the DIGITAL series of TURBOchannel (DEFTA), - EISA (DEFEA) and PCI (DEFPA) controllers which can connect you - to a local FDDI network. - - To compile this driver as a module, choose M here: the module - will be called defxx. If unsure, say N. - -config DEFXX_MMIO - bool - prompt "Use MMIO instead of PIO" if PCI || EISA - depends on DEFXX - default n if PCI || EISA - default y - ---help--- - This instructs the driver to use EISA or PCI memory-mapped I/O - (MMIO) as appropriate instead of programmed I/O ports (PIO). - Enabling this gives an improvement in processing time in parts - of the driver, but it may cause problems with EISA (DEFEA) - adapters. TURBOchannel does not have the concept of I/O ports, - so MMIO is always used for these (DEFTA) adapters. - - If unsure, say N. - -config SKFP - tristate "SysKonnect FDDI PCI support" - depends on FDDI && PCI - select BITREVERSE - ---help--- - Say Y here if you have a SysKonnect FDDI PCI adapter. - The following adapters are supported by this driver: - - SK-5521 (SK-NET FDDI-UP) - - SK-5522 (SK-NET FDDI-UP DAS) - - SK-5541 (SK-NET FDDI-FP) - - SK-5543 (SK-NET FDDI-LP) - - SK-5544 (SK-NET FDDI-LP DAS) - - SK-5821 (SK-NET FDDI-UP64) - - SK-5822 (SK-NET FDDI-UP64 DAS) - - SK-5841 (SK-NET FDDI-FP64) - - SK-5843 (SK-NET FDDI-LP64) - - SK-5844 (SK-NET FDDI-LP64 DAS) - - Netelligent 100 FDDI DAS Fibre SC - - Netelligent 100 FDDI SAS Fibre SC - - Netelligent 100 FDDI DAS UTP - - Netelligent 100 FDDI SAS UTP - - Netelligent 100 FDDI SAS Fibre MIC - - Read for information about - the driver. - - Questions concerning this driver can be addressed to: - - - To compile this driver as a module, choose M here: the module - will be called skfp. This is recommended. - -endif # FDDI diff --git a/src/linux/drivers/net/hamradio/Kconfig b/src/linux/drivers/net/hamradio/Kconfig deleted file mode 100644 index bf5e596..0000000 --- a/src/linux/drivers/net/hamradio/Kconfig +++ /dev/null @@ -1,193 +0,0 @@ -config MKISS - tristate "Serial port KISS driver" - depends on AX25 && TTY - select CRC16 - ---help--- - KISS is a protocol used for the exchange of data between a computer - and a Terminal Node Controller (a small embedded system commonly - used for networking over AX.25 amateur radio connections; it - connects the computer's serial port with the radio's microphone - input and speaker output). - - Although KISS is less advanced than the 6pack protocol, it has - the advantage that it is already supported by most modern TNCs - without the need for a firmware upgrade. - - To compile this driver as a module, choose M here: the module - will be called mkiss. - -config 6PACK - tristate "Serial port 6PACK driver" - depends on AX25 && TTY - ---help--- - 6pack is a transmission protocol for the data exchange between your - PC and your TNC (the Terminal Node Controller acts as a kind of - modem connecting your computer's serial port to your radio's - microphone input and speaker output). This protocol can be used as - an alternative to KISS for networking over AX.25 amateur radio - connections, but it has some extended functionality. - - Note that this driver is still experimental and might cause - problems. For details about the features and the usage of the - driver, read . - - To compile this driver as a module, choose M here: the module - will be called 6pack. - -config BPQETHER - tristate "BPQ Ethernet driver" - depends on AX25 - help - AX.25 is the protocol used for computer communication over amateur - radio. If you say Y here, you will be able to send and receive AX.25 - traffic over Ethernet (also called "BPQ AX.25"), which could be - useful if some other computer on your local network has a direct - amateur radio connection. - -config DMASCC - tristate "High-speed (DMA) SCC driver for AX.25" - depends on ISA && AX25 && BROKEN_ON_SMP && ISA_DMA_API - ---help--- - This is a driver for high-speed SCC boards, i.e. those supporting - DMA on one port. You usually use those boards to connect your - computer to an amateur radio modem (such as the WA4DSY 56kbps - modem), in order to send and receive AX.25 packet radio network - traffic. - - Currently, this driver supports Ottawa PI/PI2, Paccomm/Gracilis - PackeTwin, and S5SCC/DMA boards. They are detected automatically. - If you have one of these cards, say Y here and read the AX25-HOWTO, - available from . - - This driver can operate multiple boards simultaneously. If you - compile it as a module (by saying M instead of Y), it will be called - dmascc. If you don't pass any parameter to the driver, all - possible I/O addresses are probed. This could irritate other devices - that are currently not in use. You may specify the list of addresses - to be probed by "dmascc.io=addr1,addr2,..." (when compiled into the - kernel image) or "io=addr1,addr2,..." (when loaded as a module). The - network interfaces will be called dmascc0 and dmascc1 for the board - detected first, dmascc2 and dmascc3 for the second one, and so on. - - Before you configure each interface with ifconfig, you MUST set - certain parameters, such as channel access timing, clock mode, and - DMA channel. This is accomplished with a small utility program, - dmascc_cfg, available at - . Please be sure to - get at least version 1.27 of dmascc_cfg, as older versions will not - work with the current driver. - -config SCC - tristate "Z8530 SCC driver" - depends on ISA && AX25 && ISA_DMA_API - ---help--- - These cards are used to connect your Linux box to an amateur radio - in order to communicate with other computers. If you want to use - this, read and the - AX25-HOWTO, available from - . Also make sure to say Y - to "Amateur Radio AX.25 Level 2" support. - - To compile this driver as a module, choose M here: the module - will be called scc. - -config SCC_DELAY - bool "additional delay for PA0HZP OptoSCC compatible boards" - depends on SCC - help - Say Y here if you experience problems with the SCC driver not - working properly; please read - for details. - - If unsure, say N. - -config SCC_TRXECHO - bool "support for TRX that feedback the tx signal to rx" - depends on SCC - help - Some transmitters feed the transmitted signal back to the receive - line. Say Y here to foil this by explicitly disabling the receiver - during data transmission. - - If in doubt, say Y. - -config BAYCOM_SER_FDX - tristate "BAYCOM ser12 fullduplex driver for AX.25" - depends on AX25 && !S390 - select CRC_CCITT - ---help--- - This is one of two drivers for Baycom style simple amateur radio - modems that connect to a serial interface. The driver supports the - ser12 design in full-duplex mode. In addition, it allows the - baudrate to be set between 300 and 4800 baud (however not all modems - support all baudrates). This is the preferred driver. The next - driver, "BAYCOM ser12 half-duplex driver for AX.25" is the old - driver and still provided in case this driver does not work with - your serial interface chip. To configure the driver, use the sethdlc - utility available in the standard ax25 utilities package. For - information on the modems, see and - . - - To compile this driver as a module, choose M here: the module - will be called baycom_ser_fdx. This is recommended. - -config BAYCOM_SER_HDX - tristate "BAYCOM ser12 halfduplex driver for AX.25" - depends on AX25 && !S390 - select CRC_CCITT - ---help--- - This is one of two drivers for Baycom style simple amateur radio - modems that connect to a serial interface. The driver supports the - ser12 design in half-duplex mode. This is the old driver. It is - still provided in case your serial interface chip does not work with - the full-duplex driver. This driver is deprecated. To configure - the driver, use the sethdlc utility available in the standard ax25 - utilities package. For information on the modems, see - and - . - - To compile this driver as a module, choose M here: the module - will be called baycom_ser_hdx. This is recommended. - -config BAYCOM_PAR - tristate "BAYCOM picpar and par96 driver for AX.25" - depends on PARPORT && AX25 - select CRC_CCITT - ---help--- - This is a driver for Baycom style simple amateur radio modems that - connect to a parallel interface. The driver supports the picpar and - par96 designs. To configure the driver, use the sethdlc utility - available in the standard ax25 utilities package. For information on - the modems, see and the file - . - - To compile this driver as a module, choose M here: the module - will be called baycom_par. This is recommended. - -config BAYCOM_EPP - tristate "BAYCOM epp driver for AX.25" - depends on PARPORT && AX25 && !64BIT - select CRC_CCITT - ---help--- - This is a driver for Baycom style simple amateur radio modems that - connect to a parallel interface. The driver supports the EPP - designs. To configure the driver, use the sethdlc utility available - in the standard ax25 utilities package. For information on the - modems, see and the file - . - - To compile this driver as a module, choose M here: the module - will be called baycom_epp. This is recommended. - -config YAM - tristate "YAM driver for AX.25" - depends on AX25 && !S390 - help - The YAM is a modem for packet radio which connects to the serial - port and includes some of the functions of a Terminal Node - Controller. If you have one of those, say Y here. - - To compile this driver as a module, choose M here: the module - will be called yam. - - diff --git a/src/linux/drivers/net/hippi/Kconfig b/src/linux/drivers/net/hippi/Kconfig deleted file mode 100644 index f71515d..0000000 --- a/src/linux/drivers/net/hippi/Kconfig +++ /dev/null @@ -1,39 +0,0 @@ -# -# HIPPI network device configuration -# - -config HIPPI - bool "HIPPI driver support" - depends on INET && PCI - ---help--- - HIgh Performance Parallel Interface (HIPPI) is a 800Mbit/sec and - 1600Mbit/sec dual-simplex switched or point-to-point network. HIPPI - can run over copper (25m) or fiber (300m on multi-mode or 10km on - single-mode). HIPPI networks are commonly used for clusters and to - connect to super computers. If you are connected to a HIPPI network - and have a HIPPI network card in your computer that you want to use - under Linux, say Y here (you must also remember to enable the driver - for your HIPPI card below). Most people will say N here. - -if HIPPI - -config ROADRUNNER - tristate "Essential RoadRunner HIPPI PCI adapter support" - depends on PCI - ---help--- - Say Y here if this is your PCI HIPPI network card. - - To compile this driver as a module, choose M here: the module - will be called rrunner. If unsure, say N. - -config ROADRUNNER_LARGE_RINGS - bool "Use large TX/RX rings" - depends on ROADRUNNER - ---help--- - If you say Y here, the RoadRunner driver will preallocate up to 2 MB - of additional memory to allow for fastest operation, both for - transmitting and receiving. This memory cannot be used by any other - kernel code or by user space programs. Say Y here only if you have - the memory. - -endif # HIPPI diff --git a/src/linux/drivers/net/hyperv/Kconfig b/src/linux/drivers/net/hyperv/Kconfig deleted file mode 100644 index 936968d..0000000 --- a/src/linux/drivers/net/hyperv/Kconfig +++ /dev/null @@ -1,5 +0,0 @@ -config HYPERV_NET - tristate "Microsoft Hyper-V virtual network driver" - depends on HYPERV - help - Select this option to enable the Hyper-V virtual network driver. diff --git a/src/linux/drivers/net/ieee802154/Kconfig b/src/linux/drivers/net/ieee802154/Kconfig deleted file mode 100644 index 3057a8d..0000000 --- a/src/linux/drivers/net/ieee802154/Kconfig +++ /dev/null @@ -1,84 +0,0 @@ -menuconfig IEEE802154_DRIVERS - tristate "IEEE 802.15.4 drivers" - depends on NETDEVICES && IEEE802154 - default y - ---help--- - Say Y here to get to see options for IEEE 802.15.4 Low-Rate - Wireless Personal Area Network device drivers. This option alone - does not add any kernel code. - - If you say N, all options in this submenu will be skipped and - disabled. - -config IEEE802154_FAKELB - depends on IEEE802154_DRIVERS && MAC802154 - tristate "IEEE 802.15.4 loopback driver" - ---help--- - Say Y here to enable the fake driver that can emulate a net - of several interconnected radio devices. - - This driver can also be built as a module. To do so say M here. - The module will be called 'fakelb'. - -config IEEE802154_AT86RF230 - depends on IEEE802154_DRIVERS && MAC802154 - tristate "AT86RF230/231/233/212 transceiver driver" - depends on SPI - select REGMAP_SPI - ---help--- - Say Y here to enable the at86rf230/231/233/212 SPI 802.15.4 wireless - controller. - - This driver can also be built as a module. To do so, say M here. - the module will be called 'at86rf230'. - -config IEEE802154_AT86RF230_DEBUGFS - depends on IEEE802154_AT86RF230 - bool "AT86RF230 debugfs interface" - depends on DEBUG_FS - ---help--- - This option compiles debugfs code for the at86rf230 driver. - -config IEEE802154_MRF24J40 - tristate "Microchip MRF24J40 transceiver driver" - depends on IEEE802154_DRIVERS && MAC802154 - depends on SPI - select REGMAP_SPI - ---help--- - Say Y here to enable the MRF24J20 SPI 802.15.4 wireless - controller. - - This driver can also be built as a module. To do so, say M here. - the module will be called 'mrf24j40'. - -config IEEE802154_CC2520 - depends on IEEE802154_DRIVERS && MAC802154 - tristate "CC2520 transceiver driver" - depends on SPI - ---help--- - Say Y here to enable the CC2520 SPI 802.15.4 wireless - controller. - - This driver can also be built as a module. To do so, say M here. - the module will be called 'cc2520'. - -config IEEE802154_ATUSB - tristate "ATUSB transceiver driver" - depends on IEEE802154_DRIVERS && MAC802154 && USB - ---help--- - Say Y here to enable the ATUSB IEEE 802.15.4 wireless - controller. - - This driver can also be built as a module. To do so say M here. - The module will be called 'atusb'. - -config IEEE802154_ADF7242 - tristate "ADF7242 transceiver driver" - depends on IEEE802154_DRIVERS && MAC802154 - depends on SPI - ---help--- - Say Y here to enable the ADF7242 SPI 802.15.4 wireless - controller. - - This driver can also be built as a module. To do so, say M here. - the module will be called 'adf7242'. diff --git a/src/linux/drivers/net/irda/Kconfig b/src/linux/drivers/net/irda/Kconfig deleted file mode 100644 index e070e12..0000000 --- a/src/linux/drivers/net/irda/Kconfig +++ /dev/null @@ -1,398 +0,0 @@ -menu "Infrared-port device drivers" - depends on IRDA!=n - -comment "SIR device drivers" - -config IRTTY_SIR - tristate "IrTTY (uses Linux serial driver)" - depends on IRDA && TTY - help - Say Y here if you want to build support for the IrTTY line - discipline. To compile it as a module, choose M here: the module - will be called irtty-sir. IrTTY makes it possible to use Linux's - own serial driver for all IrDA ports that are 16550 compatible. - Most IrDA chips are 16550 compatible so you should probably say Y - to this option. Using IrTTY will however limit the speed of the - connection to 115200 bps (IrDA SIR mode). - - If unsure, say Y. - -config BFIN_SIR - tristate "Blackfin SIR on UART" - depends on BLACKFIN && IRDA - default n - help - Say Y here if your want to enable SIR function on Blackfin UART - devices. - - To activate this driver you can start irattach like: - "irattach irda0 -s" - - Saying M, it will be built as a module named bfin_sir. - - Note that you need to turn off one of the serial drivers for SIR - to use that UART. - -config BFIN_SIR0 - bool "Blackfin SIR on UART0" - depends on BFIN_SIR && !SERIAL_BFIN_UART0 - -config BFIN_SIR1 - bool "Blackfin SIR on UART1" - depends on BFIN_SIR && !SERIAL_BFIN_UART1 && (!BF531 && !BF532 && !BF533 && !BF561) - -config BFIN_SIR2 - bool "Blackfin SIR on UART2" - depends on BFIN_SIR && !SERIAL_BFIN_UART2 && (BF54x || BF538 || BF539) - -config BFIN_SIR3 - bool "Blackfin SIR on UART3" - depends on BFIN_SIR && !SERIAL_BFIN_UART3 && (BF54x) - -choice - prompt "SIR Mode" - depends on BFIN_SIR - default SIR_BFIN_DMA - -config SIR_BFIN_DMA - bool "DMA mode" - depends on !DMA_UNCACHED_NONE - -config SIR_BFIN_PIO - bool "PIO mode" -endchoice - -config SH_SIR - tristate "SuperH SIR on UART" - depends on IRDA && SUPERH && \ - (CPU_SUBTYPE_SH7722 || CPU_SUBTYPE_SH7723 || \ - CPU_SUBTYPE_SH7724) - default n - help - Say Y here if your want to enable SIR function on SuperH UART - devices. - -comment "Dongle support" - -config DONGLE - bool "Serial dongle support" - depends on IRTTY_SIR - help - Say Y here if you have an infrared device that connects to your - computer's serial port. These devices are called dongles. Then say Y - or M to the driver for your particular dongle below. - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about serial dongles. - -config ESI_DONGLE - tristate "ESI JetEye PC dongle" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the Extended Systems - JetEye PC dongle. To compile it as a module, choose M here. The ESI - dongle attaches to the normal 9-pin serial port connector, and can - currently only be used by IrTTY. To activate support for ESI - dongles you will have to start irattach like this: - "irattach -d esi". - -config ACTISYS_DONGLE - tristate "ACTiSYS IR-220L and IR220L+ dongle" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the ACTiSYS IR-220L and - IR220L+ dongles. To compile it as a module, choose M here. The - ACTiSYS dongles attaches to the normal 9-pin serial port connector, - and can currently only be used by IrTTY. To activate support for - ACTiSYS dongles you will have to start irattach like this: - "irattach -d actisys" or "irattach -d actisys+". - -config TEKRAM_DONGLE - tristate "Tekram IrMate 210B dongle" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the Tekram IrMate 210B - dongle. To compile it as a module, choose M here. The Tekram dongle - attaches to the normal 9-pin serial port connector, and can - currently only be used by IrTTY. To activate support for Tekram - dongles you will have to start irattach like this: - "irattach -d tekram". - -config TOIM3232_DONGLE - tristate "TOIM3232 IrDa dongle" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the Vishay/Temic - TOIM3232 and TOIM4232 based dongles. - To compile it as a module, choose M here. - -config LITELINK_DONGLE - tristate "Parallax LiteLink dongle" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the Parallax Litelink - dongle. To compile it as a module, choose M here. The Parallax - dongle attaches to the normal 9-pin serial port connector, and can - currently only be used by IrTTY. To activate support for Parallax - dongles you will have to start irattach like this: - "irattach -d litelink". - -config MA600_DONGLE - tristate "Mobile Action MA600 dongle" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the Mobile Action MA600 - dongle. To compile it as a module, choose M here. The MA600 dongle - attaches to the normal 9-pin serial port connector, and can - currently only be used by IrTTY. The driver should also support - the MA620 USB version of the dongle, if the integrated USB-to-RS232 - converter is supported by usbserial. To activate support for - MA600 dongle you will have to start irattach like this: - "irattach -d ma600". - -config GIRBIL_DONGLE - tristate "Greenwich GIrBIL dongle" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the Greenwich GIrBIL - dongle. If you want to compile it as a module, choose M here. - The Greenwich dongle attaches to the normal 9-pin serial port - connector, and can currently only be used by IrTTY. To activate - support for Greenwich dongles you will have to start irattach - like this: "irattach -d girbil". - -config MCP2120_DONGLE - tristate "Microchip MCP2120" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the Microchip MCP2120 - dongle. If you want to compile it as a module, choose M here. - The MCP2120 dongle attaches to the normal 9-pin serial port - connector, and can currently only be used by IrTTY. To activate - support for MCP2120 dongles you will have to start irattach - like this: "irattach -d mcp2120". - - You must build this dongle yourself. For more information see: - - -config OLD_BELKIN_DONGLE - tristate "Old Belkin dongle" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the Adaptec Airport 1000 - and 2000 dongles. If you want to compile it as a module, choose - M here. Some information is contained in the comments - at the top of . - -config ACT200L_DONGLE - tristate "ACTiSYS IR-200L dongle" - depends on IRTTY_SIR && DONGLE && IRDA - help - Say Y here if you want to build support for the ACTiSYS IR-200L - dongle. If you want to compile it as a module, choose M here. - The ACTiSYS IR-200L dongle attaches to the normal 9-pin serial - port connector, and can currently only be used by IrTTY. - To activate support for ACTiSYS IR-200L dongle you will have to - start irattach like this: "irattach -d act200l". - -config KINGSUN_DONGLE - tristate "KingSun/DonShine DS-620 IrDA-USB dongle" - depends on IRDA && USB - help - Say Y or M here if you want to build support for the KingSun/DonShine - DS-620 IrDA-USB bridge device driver. - - This USB bridge does not conform to the IrDA-USB device class - specification, and therefore needs its own specific driver. This - dongle supports SIR speed only (9600 bps). - - To compile it as a module, choose M here: the module will be called - kingsun-sir. - -config KSDAZZLE_DONGLE - tristate "KingSun Dazzle IrDA-USB dongle" - depends on IRDA && USB - help - Say Y or M here if you want to build support for the KingSun Dazzle - IrDA-USB bridge device driver. - - This USB bridge does not conform to the IrDA-USB device class - specification, and therefore needs its own specific driver. This - dongle supports SIR speeds only (9600 through 115200 bps). - - To compile it as a module, choose M here: the module will be called - ksdazzle-sir. - -config KS959_DONGLE - tristate "KingSun KS-959 IrDA-USB dongle" - depends on IRDA && USB - help - Say Y or M here if you want to build support for the KingSun KS-959 - IrDA-USB bridge device driver. - - This USB bridge does not conform to the IrDA-USB device class - specification, and therefore needs its own specific driver. This - dongle supports SIR speeds only (9600 through 57600 bps). - - To compile it as a module, choose M here: the module will be called - ks959-sir. - -comment "FIR device drivers" - -config USB_IRDA - tristate "IrDA USB dongles" - depends on IRDA && USB - select FW_LOADER - ---help--- - Say Y here if you want to build support for the USB IrDA FIR Dongle - device driver. To compile it as a module, choose M here: the module - will be called irda-usb. IrDA-USB support the various IrDA USB - dongles available and most of their peculiarities. Those dongles - plug in the USB port of your computer, are plug and play, and - support SIR and FIR (4Mbps) speeds. On the other hand, those - dongles tend to be less efficient than a FIR chipset. - - Please note that the driver is still experimental. And of course, - you will need both USB and IrDA support in your kernel... - -config SIGMATEL_FIR - tristate "SigmaTel STIr4200 bridge" - depends on IRDA && USB - select CRC32 - ---help--- - Say Y here if you want to build support for the SigmaTel STIr4200 - USB IrDA FIR bridge device driver. - - USB bridge based on the SigmaTel STIr4200 don't conform to the - IrDA-USB device class specification, and therefore need their - own specific driver. Those dongles support SIR and FIR (4Mbps) - speeds. - - To compile it as a module, choose M here: the module will be called - stir4200. - -config NSC_FIR - tristate "NSC PC87108/PC87338" - depends on IRDA && ISA_DMA_API - help - Say Y here if you want to build support for the NSC PC87108 and - PC87338 IrDA chipsets. This driver supports SIR, - MIR and FIR (4Mbps) speeds. - - To compile it as a module, choose M here: the module will be called - nsc-ircc. - -config WINBOND_FIR - tristate "Winbond W83977AF (IR)" - depends on IRDA && ISA_DMA_API - help - Say Y here if you want to build IrDA support for the Winbond - W83977AF super-io chipset. This driver should be used for the IrDA - chipset in the Corel NetWinder. The driver supports SIR, MIR and - FIR (4Mbps) speeds. - - To compile it as a module, choose M here: the module will be called - w83977af_ir. - -config TOSHIBA_FIR - tristate "Toshiba Type-O IR Port" - depends on IRDA && PCI && !64BIT && VIRT_TO_BUS - help - Say Y here if you want to build support for the Toshiba Type-O IR - and Donau oboe chipsets. These chipsets are used by the Toshiba - Libretto 100/110CT, Tecra 8100, Portege 7020 and many more laptops. - To compile it as a module, choose M here: the module will be called - donauboe. - -config AU1000_FIR - tristate "Alchemy IrDA SIR/FIR" - depends on IRDA && MIPS_ALCHEMY - help - Say Y/M here to build support the IrDA peripheral on the - Alchemy Au1000 and Au1100 SoCs. - Say M to build a module; it will be called au1k_ir.ko - -config SMC_IRCC_FIR - tristate "SMSC IrCC" - depends on IRDA && ISA_DMA_API - help - Say Y here if you want to build support for the SMC Infrared - Communications Controller. It is used in a wide variety of - laptops (Fujitsu, Sony, Compaq and some Toshiba). - To compile it as a module, choose M here: the module will be called - smsc-ircc2.o. - -config ALI_FIR - tristate "ALi M5123 FIR" - depends on IRDA && ISA_DMA_API - help - Say Y here if you want to build support for the ALi M5123 FIR - Controller. The ALi M5123 FIR Controller is embedded in ALi M1543C, - M1535, M1535D, M1535+, M1535D South Bridge. This driver supports - SIR, MIR and FIR (4Mbps) speeds. - - To compile it as a module, choose M here: the module will be called - ali-ircc. - -config VLSI_FIR - tristate "VLSI 82C147 SIR/MIR/FIR" - depends on IRDA && PCI - help - Say Y here if you want to build support for the VLSI 82C147 - PCI-IrDA Controller. This controller is used by the HP OmniBook 800 - and 5500 notebooks. The driver provides support for SIR, MIR and - FIR (4Mbps) speeds. - - To compile it as a module, choose M here: the module will be called - vlsi_ir. - -config SA1100_FIR - tristate "SA1100 Internal IR" - depends on ARCH_SA1100 && IRDA && DMA_SA11X0 - -config VIA_FIR - tristate "VIA VT8231/VT1211 SIR/MIR/FIR" - depends on IRDA && ISA_DMA_API - help - Say Y here if you want to build support for the VIA VT8231 - and VIA VT1211 IrDA controllers, found on the motherboards using - those VIA chipsets. To use this controller, you will need - to plug a specific 5 pins FIR IrDA dongle in the specific - motherboard connector. The driver provides support for SIR, MIR - and FIR (4Mbps) speeds. - - You will need to specify the 'dongle_id' module parameter to - indicate the FIR dongle attached to the controller. - - To compile it as a module, choose M here: the module will be called - via-ircc. - -config PXA_FICP - tristate "Intel PXA2xx Internal FICP" - depends on ARCH_PXA && IRDA - help - Say Y or M here if you want to build support for the PXA2xx - built-in IRDA interface which can support both SIR and FIR. - This driver relies on platform specific helper routines so - available capabilities may vary from one PXA2xx target to - another. - -config MCS_FIR - tristate "MosChip MCS7780 IrDA-USB dongle" - depends on IRDA && USB - select CRC32 - help - Say Y or M here if you want to build support for the MosChip - MCS7780 IrDA-USB bridge device driver. - - USB bridge based on the MosChip MCS7780 don't conform to the - IrDA-USB device class specification, and therefore need their - own specific driver. Those dongles support SIR and FIR (4Mbps) - speeds. - - To compile it as a module, choose M here: the module will be called - mcs7780. - -endmenu - diff --git a/src/linux/drivers/net/loopback.c b/src/linux/drivers/net/loopback.c deleted file mode 100644 index 6255973..0000000 --- a/src/linux/drivers/net/loopback.c +++ /dev/null @@ -1,221 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Pseudo-driver for the loopback interface. - * - * Version: @(#)loopback.c 1.0.4b 08/16/93 - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Donald Becker, - * - * Alan Cox : Fixed oddments for NET3.014 - * Alan Cox : Rejig for NET3.029 snap #3 - * Alan Cox : Fixed NET3.029 bugs and sped up - * Larry McVoy : Tiny tweak to double performance - * Alan Cox : Backed out LMV's tweak - the linux mm - * can't take it... - * Michael Griffith: Don't bother computing the checksums - * on packets received on the loopback - * interface. - * Alexey Kuznetsov: Potential hang under some extreme - * cases removed. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include /* For the statistics structure. */ -#include /* For ARPHRD_ETHER */ -#include -#include -#include -#include -#include - -struct pcpu_lstats { - u64 packets; - u64 bytes; - struct u64_stats_sync syncp; -}; - -/* - * The higher levels take care of making this non-reentrant (it's - * called with bh's disabled). - */ -static netdev_tx_t loopback_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct pcpu_lstats *lb_stats; - int len; - - skb_orphan(skb); - - /* Before queueing this packet to netif_rx(), - * make sure dst is refcounted. - */ - skb_dst_force(skb); - - skb->protocol = eth_type_trans(skb, dev); - - /* it's OK to use per_cpu_ptr() because BHs are off */ - lb_stats = this_cpu_ptr(dev->lstats); - - len = skb->len; - if (likely(netif_rx(skb) == NET_RX_SUCCESS)) { - u64_stats_update_begin(&lb_stats->syncp); - lb_stats->bytes += len; - lb_stats->packets++; - u64_stats_update_end(&lb_stats->syncp); - } - - return NETDEV_TX_OK; -} - -static struct rtnl_link_stats64 *loopback_get_stats64(struct net_device *dev, - struct rtnl_link_stats64 *stats) -{ - u64 bytes = 0; - u64 packets = 0; - int i; - - for_each_possible_cpu(i) { - const struct pcpu_lstats *lb_stats; - u64 tbytes, tpackets; - unsigned int start; - - lb_stats = per_cpu_ptr(dev->lstats, i); - do { - start = u64_stats_fetch_begin_irq(&lb_stats->syncp); - tbytes = lb_stats->bytes; - tpackets = lb_stats->packets; - } while (u64_stats_fetch_retry_irq(&lb_stats->syncp, start)); - bytes += tbytes; - packets += tpackets; - } - stats->rx_packets = packets; - stats->tx_packets = packets; - stats->rx_bytes = bytes; - stats->tx_bytes = bytes; - return stats; -} - -static u32 always_on(struct net_device *dev) -{ - return 1; -} - -static const struct ethtool_ops loopback_ethtool_ops = { - .get_link = always_on, -}; - -static int loopback_dev_init(struct net_device *dev) -{ - dev->lstats = netdev_alloc_pcpu_stats(struct pcpu_lstats); - if (!dev->lstats) - return -ENOMEM; - return 0; -} - -static void loopback_dev_free(struct net_device *dev) -{ - dev_net(dev)->loopback_dev = NULL; - free_percpu(dev->lstats); - free_netdev(dev); -} - -static const struct net_device_ops loopback_ops = { - .ndo_init = loopback_dev_init, - .ndo_start_xmit= loopback_xmit, - .ndo_get_stats64 = loopback_get_stats64, - .ndo_set_mac_address = eth_mac_addr, -}; - -/* - * The loopback device is special. There is only one instance - * per network namespace. - */ -static void loopback_setup(struct net_device *dev) -{ - dev->mtu = 64 * 1024; - dev->hard_header_len = ETH_HLEN; /* 14 */ - dev->addr_len = ETH_ALEN; /* 6 */ - dev->type = ARPHRD_LOOPBACK; /* 0x0001*/ - dev->flags = IFF_LOOPBACK; - dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE; - netif_keep_dst(dev); - dev->hw_features = NETIF_F_GSO_SOFTWARE; - dev->features = NETIF_F_SG | NETIF_F_FRAGLIST - | NETIF_F_GSO_SOFTWARE - | NETIF_F_HW_CSUM - | NETIF_F_RXCSUM - | NETIF_F_SCTP_CRC - | NETIF_F_HIGHDMA - | NETIF_F_LLTX - | NETIF_F_NETNS_LOCAL - | NETIF_F_VLAN_CHALLENGED - | NETIF_F_LOOPBACK; - dev->ethtool_ops = &loopback_ethtool_ops; - dev->header_ops = ð_header_ops; - dev->netdev_ops = &loopback_ops; - dev->destructor = loopback_dev_free; -} - -/* Setup and register the loopback device. */ -static __net_init int loopback_net_init(struct net *net) -{ - struct net_device *dev; - int err; - - err = -ENOMEM; - dev = alloc_netdev(0, "lo", NET_NAME_UNKNOWN, loopback_setup); - if (!dev) - goto out; - - dev_net_set(dev, net); - err = register_netdev(dev); - if (err) - goto out_free_netdev; - - BUG_ON(dev->ifindex != LOOPBACK_IFINDEX); - net->loopback_dev = dev; - return 0; - - -out_free_netdev: - free_netdev(dev); -out: - if (net_eq(net, &init_net)) - panic("loopback: Failed to register netdevice: %d\n", err); - return err; -} - -/* Registered in net/core/dev.c */ -struct pernet_operations __net_initdata loopback_net_ops = { - .init = loopback_net_init, -}; diff --git a/src/linux/drivers/net/phy/Kconfig b/src/linux/drivers/net/phy/Kconfig deleted file mode 100644 index 2651c8d..0000000 --- a/src/linux/drivers/net/phy/Kconfig +++ /dev/null @@ -1,328 +0,0 @@ -# -# PHY Layer Configuration -# - -menuconfig PHYLIB - tristate "PHY Device support and infrastructure" - depends on NETDEVICES - help - Ethernet controllers are usually attached to PHY - devices. This option provides infrastructure for - managing PHY devices. - -if PHYLIB - -config SWPHY - bool - -comment "MDIO bus device drivers" - -config MDIO_BCM_IPROC - tristate "Broadcom iProc MDIO bus controller" - depends on ARCH_BCM_IPROC || COMPILE_TEST - depends on HAS_IOMEM && OF_MDIO - help - This module provides a driver for the MDIO busses found in the - Broadcom iProc SoC's. - -config MDIO_BCM_UNIMAC - tristate "Broadcom UniMAC MDIO bus controller" - depends on HAS_IOMEM - help - This module provides a driver for the Broadcom UniMAC MDIO busses. - This hardware can be found in the Broadcom GENET Ethernet MAC - controllers as well as some Broadcom Ethernet switches such as the - Starfighter 2 switches. - -config MDIO_BITBANG - tristate "Bitbanged MDIO buses" - help - This module implements the MDIO bus protocol in software, - for use by low level drivers that export the ability to - drive the relevant pins. - - If in doubt, say N. - -config MDIO_BUS_MUX - tristate - depends on OF_MDIO - help - This module provides a driver framework for MDIO bus - multiplexers which connect one of several child MDIO busses - to a parent bus. Switching between child busses is done by - device specific drivers. - -config MDIO_BUS_MUX_BCM_IPROC - tristate "Broadcom iProc based MDIO bus multiplexers" - depends on OF && OF_MDIO && (ARCH_BCM_IPROC || COMPILE_TEST) - select MDIO_BUS_MUX - default ARCH_BCM_IPROC - help - This module provides a driver for MDIO bus multiplexers found in - iProc based Broadcom SoCs. This multiplexer connects one of several - child MDIO bus to a parent bus. Buses could be internal as well as - external and selection logic lies inside the same multiplexer. - -config MDIO_BUS_MUX_GPIO - tristate "GPIO controlled MDIO bus multiplexers" - depends on OF_GPIO && OF_MDIO - select MDIO_BUS_MUX - help - This module provides a driver for MDIO bus multiplexers that - are controlled via GPIO lines. The multiplexer connects one of - several child MDIO busses to a parent bus. Child bus - selection is under the control of GPIO lines. - -config MDIO_BUS_MUX_MMIOREG - tristate "MMIO device-controlled MDIO bus multiplexers" - depends on OF_MDIO && HAS_IOMEM - select MDIO_BUS_MUX - help - This module provides a driver for MDIO bus multiplexers that - are controlled via a simple memory-mapped device, like an FPGA. - The multiplexer connects one of several child MDIO busses to a - parent bus. Child bus selection is under the control of one of - the FPGA's registers. - - Currently, only 8-bit registers are supported. - -config MDIO_CAVIUM - tristate - -config MDIO_GPIO - tristate "GPIO lib-based bitbanged MDIO buses" - depends on MDIO_BITBANG && GPIOLIB - ---help--- - Supports GPIO lib-based MDIO busses. - - To compile this driver as a module, choose M here: the module - will be called mdio-gpio. - -config MDIO_HISI_FEMAC - tristate "Hisilicon FEMAC MDIO bus controller" - depends on HAS_IOMEM && OF_MDIO - help - This module provides a driver for the MDIO busses found in the - Hisilicon SoC that have an Fast Ethernet MAC. - -config MDIO_MOXART - tristate "MOXA ART MDIO interface support" - depends on ARCH_MOXART - help - This driver supports the MDIO interface found in the network - interface units of the MOXA ART SoC - -config MDIO_OCTEON - tristate "Octeon and some ThunderX SOCs MDIO buses" - depends on 64BIT - depends on HAS_IOMEM - select MDIO_CAVIUM - help - This module provides a driver for the Octeon and ThunderX MDIO - buses. It is required by the Octeon and ThunderX ethernet device - drivers on some systems. - -config MDIO_SUN4I - tristate "Allwinner sun4i MDIO interface support" - depends on ARCH_SUNXI - help - This driver supports the MDIO interface found in the network - interface units of the Allwinner SoC that have an EMAC (A10, - A12, A10s, etc.) - -config MDIO_THUNDER - tristate "ThunderX SOCs MDIO buses" - depends on 64BIT - depends on PCI - select MDIO_CAVIUM - help - This driver supports the MDIO interfaces found on Cavium - ThunderX SoCs when the MDIO bus device appears as a PCI - device. - -config MDIO_XGENE - tristate "APM X-Gene SoC MDIO bus controller" - depends on ARCH_XGENE || COMPILE_TEST - help - This module provides a driver for the MDIO busses found in the - APM X-Gene SoC's. - -comment "MII PHY device drivers" - -config AMD_PHY - tristate "AMD PHYs" - ---help--- - Currently supports the am79c874 - -config AQUANTIA_PHY - tristate "Aquantia PHYs" - ---help--- - Currently supports the Aquantia AQ1202, AQ2104, AQR105, AQR405 - -config AT803X_PHY - tristate "AT803X PHYs" - ---help--- - Currently supports the AT8030 and AT8035 model - -config BCM63XX_PHY - tristate "Broadcom 63xx SOCs internal PHY" - depends on BCM63XX - select BCM_NET_PHYLIB - ---help--- - Currently supports the 6348 and 6358 PHYs. - -config BCM7XXX_PHY - tristate "Broadcom 7xxx SOCs internal PHYs" - select BCM_NET_PHYLIB - ---help--- - Currently supports the BCM7366, BCM7439, BCM7445, and - 40nm and 65nm generation of BCM7xxx Set Top Box SoCs. - -config BCM87XX_PHY - tristate "Broadcom BCM8706 and BCM8727 PHYs" - help - Currently supports the BCM8706 and BCM8727 10G Ethernet PHYs. - -config BCM_CYGNUS_PHY - tristate "Broadcom Cygnus SoC internal PHY" - depends on ARCH_BCM_CYGNUS || COMPILE_TEST - depends on MDIO_BCM_IPROC - select BCM_NET_PHYLIB - ---help--- - This PHY driver is for the 1G internal PHYs of the Broadcom - Cygnus Family SoC. - - Currently supports internal PHY's used in the BCM11300, - BCM11320, BCM11350, BCM11360, BCM58300, BCM58302, - BCM58303 & BCM58305 Broadcom Cygnus SoCs. - -config BCM_NET_PHYLIB - tristate - -config BROADCOM_PHY - tristate "Broadcom PHYs" - select BCM_NET_PHYLIB - ---help--- - Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464, - BCM5481 and BCM5482 PHYs. - -config CICADA_PHY - tristate "Cicada PHYs" - ---help--- - Currently supports the cis8204 - -config DAVICOM_PHY - tristate "Davicom PHYs" - ---help--- - Currently supports dm9161e and dm9131 - -config DP83848_PHY - tristate "Texas Instruments DP83848 PHY" - ---help--- - Supports the DP83848 PHY. - -config DP83867_PHY - tristate "Texas Instruments DP83867 Gigabit PHY" - ---help--- - Currently supports the DP83867 PHY. - -config FIXED_PHY - tristate "MDIO Bus/PHY emulation with fixed speed/link PHYs" - depends on PHYLIB - select SWPHY - ---help--- - Adds the platform "fixed" MDIO Bus to cover the boards that use - PHYs that are not connected to the real MDIO bus. - - Currently tested with mpc866ads and mpc8349e-mitx. - -config ICPLUS_PHY - tristate "ICPlus PHYs" - ---help--- - Currently supports the IP175C and IP1001 PHYs. - -config INTEL_XWAY_PHY - tristate "Intel XWAY PHYs" - ---help--- - Supports the Intel XWAY (former Lantiq) 11G and 22E PHYs. - These PHYs are marked as standalone chips under the names - PEF 7061, PEF 7071 and PEF 7072 or integrated into the Intel - SoCs xRX200, xRX300, xRX330, xRX350 and xRX550. - -config LSI_ET1011C_PHY - tristate "LSI ET1011C PHY" - ---help--- - Supports the LSI ET1011C PHY. - -config LXT_PHY - tristate "Intel LXT PHYs" - ---help--- - Currently supports the lxt970, lxt971 - -config MARVELL_PHY - tristate "Marvell PHYs" - ---help--- - Currently has a driver for the 88E1011S - -config MICREL_PHY - tristate "Micrel PHYs" - ---help--- - Supports the KSZ9021, VSC8201, KS8001 PHYs. - -config MICROCHIP_PHY - tristate "Microchip PHYs" - help - Supports the LAN88XX PHYs. - -config MICROSEMI_PHY - tristate "Microsemi PHYs" - ---help--- - Currently supports the VSC8531 and VSC8541 PHYs - -config NATIONAL_PHY - tristate "National Semiconductor PHYs" - ---help--- - Currently supports the DP83865 PHY. - -config QSEMI_PHY - tristate "Quality Semiconductor PHYs" - ---help--- - Currently supports the qs6612 - -config REALTEK_PHY - tristate "Realtek PHYs" - ---help--- - Supports the Realtek 821x PHY. - -config SMSC_PHY - tristate "SMSC PHYs" - ---help--- - Currently supports the LAN83C185, LAN8187 and LAN8700 PHYs - -config STE10XP - tristate "STMicroelectronics STe10Xp PHYs" - ---help--- - This is the driver for the STe100p and STe101p PHYs. - -config TERANETICS_PHY - tristate "Teranetics PHYs" - ---help--- - Currently supports the Teranetics TN2020 - -config VITESSE_PHY - tristate "Vitesse PHYs" - ---help--- - Currently supports the vsc8244 - -config XILINX_GMII2RGMII - tristate "Xilinx GMII2RGMII converter driver" - ---help--- - This driver support xilinx GMII to RGMII IP core it provides - the Reduced Gigabit Media Independent Interface(RGMII) between - Ethernet physical media devices and the Gigabit Ethernet controller. - -endif # PHYLIB - -config MICREL_KS8995MA - tristate "Micrel KS8995MA 5-ports 10/100 managed Ethernet switch" - depends on SPI diff --git a/src/linux/drivers/net/plip/Kconfig b/src/linux/drivers/net/plip/Kconfig deleted file mode 100644 index 80c4a33..0000000 --- a/src/linux/drivers/net/plip/Kconfig +++ /dev/null @@ -1,38 +0,0 @@ -# -# Parallel Line Internet Protocol (PLIP) network device configuration -# - -config PLIP - tristate "PLIP (parallel port) support" - depends on PARPORT - ---help--- - PLIP (Parallel Line Internet Protocol) is used to create a - reasonably fast mini network consisting of two (or, rarely, more) - local machines. A PLIP link from a Linux box is a popular means to - install a Linux distribution on a machine which doesn't have a - CD-ROM drive (a minimal system has to be transferred with floppies - first). The kernels on both machines need to have this PLIP option - enabled for this to work. - - The PLIP driver has two modes, mode 0 and mode 1. The parallel - ports (the connectors at the computers with 25 holes) are connected - with "null printer" or "Turbo Laplink" cables which can transmit 4 - bits at a time (mode 0) or with special PLIP cables, to be used on - bidirectional parallel ports only, which can transmit 8 bits at a - time (mode 1); you can find the wiring of these cables in - . The cables can be up to - 15m long. Mode 0 works also if one of the machines runs DOS/Windows - and has some PLIP software installed, e.g. the Crynwr PLIP packet - driver () - and winsock or NCSA's telnet. - - If you want to use PLIP, say Y and read the PLIP mini-HOWTO as well - as the NET-3-HOWTO, both available from - . Note that the PLIP - protocol has been changed and this PLIP driver won't work together - with the PLIP support in Linux versions 1.0.x. This option enlarges - your kernel by about 8 KB. - - To compile this driver as a module, choose M here. The module - will be called plip. If unsure, say Y or M, in case you buy - a laptop later. diff --git a/src/linux/drivers/net/ppp/Kconfig b/src/linux/drivers/net/ppp/Kconfig deleted file mode 100644 index 1373c6d..0000000 --- a/src/linux/drivers/net/ppp/Kconfig +++ /dev/null @@ -1,178 +0,0 @@ -# -# PPP network device configuration -# - -config PPP - tristate "PPP (point-to-point protocol) support" - select SLHC - ---help--- - PPP (Point to Point Protocol) is a newer and better SLIP. It serves - the same purpose: sending Internet traffic over telephone (and other - serial) lines. Ask your access provider if they support it, because - otherwise you can't use it; most Internet access providers these - days support PPP rather than SLIP. - - To use PPP, you need an additional program called pppd as described - in the PPP-HOWTO, available at - . Make sure that you have - the version of pppd recommended in . - The PPP option enlarges your kernel by about 16 KB. - - There are actually two versions of PPP: the traditional PPP for - asynchronous lines, such as regular analog phone lines, and - synchronous PPP which can be used over digital ISDN lines for - example. If you want to use PPP over phone lines or other - asynchronous serial lines, you need to say Y (or M) here and also to - the next option, "PPP support for async serial ports". For PPP over - synchronous lines, you should say Y (or M) here and to "Support - synchronous PPP", below. - - If you said Y to "Version information on all symbols" above, then - you cannot compile the PPP driver into the kernel; you can then only - compile it as a module. To compile this driver as a module, choose M - here. The module will be called ppp_generic. - -if PPP - -config PPP_BSDCOMP - tristate "PPP BSD-Compress compression" - depends on PPP - ---help--- - Support for the BSD-Compress compression method for PPP, which uses - the LZW compression method to compress each PPP packet before it is - sent over the wire. The machine at the other end of the PPP link - (usually your ISP) has to support the BSD-Compress compression - method as well for this to be useful. Even if they don't support it, - it is safe to say Y here. - - The PPP Deflate compression method ("PPP Deflate compression", - above) is preferable to BSD-Compress, because it compresses better - and is patent-free. - - Note that the BSD compression code will always be compiled as a - module; it is called bsd_comp and will show up in the directory - modules once you have said "make modules". If unsure, say N. - -config PPP_DEFLATE - tristate "PPP Deflate compression" - depends on PPP - select ZLIB_INFLATE - select ZLIB_DEFLATE - ---help--- - Support for the Deflate compression method for PPP, which uses the - Deflate algorithm (the same algorithm that gzip uses) to compress - each PPP packet before it is sent over the wire. The machine at the - other end of the PPP link (usually your ISP) has to support the - Deflate compression method as well for this to be useful. Even if - they don't support it, it is safe to say Y here. - - To compile this driver as a module, choose M here. - -config PPP_FILTER - bool "PPP filtering" - depends on PPP - ---help--- - Say Y here if you want to be able to filter the packets passing over - PPP interfaces. This allows you to control which packets count as - activity (i.e. which packets will reset the idle timer or bring up - a demand-dialed link) and which packets are to be dropped entirely. - You need to say Y here if you wish to use the pass-filter and - active-filter options to pppd. - - If unsure, say N. - -config PPP_MPPE - tristate "PPP MPPE compression (encryption)" - depends on PPP - select CRYPTO - select CRYPTO_SHA1 - select CRYPTO_ARC4 - select CRYPTO_ECB - ---help--- - Support for the MPPE Encryption protocol, as employed by the - Microsoft Point-to-Point Tunneling Protocol. - - See http://pptpclient.sourceforge.net/ for information on - configuring PPTP clients and servers to utilize this method. - -config PPP_MULTILINK - bool "PPP multilink support" - depends on PPP - ---help--- - PPP multilink is a protocol (defined in RFC 1990) which allows you - to combine several (logical or physical) lines into one logical PPP - connection, so that you can utilize your full bandwidth. - - This has to be supported at the other end as well and you need a - version of the pppd daemon which understands the multilink protocol. - - If unsure, say N. - -config PPPOATM - tristate "PPP over ATM" - depends on ATM && PPP - ---help--- - Support PPP (Point to Point Protocol) encapsulated in ATM frames. - This implementation does not yet comply with section 8 of RFC2364, - which can lead to bad results if the ATM peer loses state and - changes its encapsulation unilaterally. - -config PPPOE - tristate "PPP over Ethernet" - depends on PPP - ---help--- - Support for PPP over Ethernet. - - This driver requires the latest version of pppd from the CVS - repository at cvs.samba.org. Alternatively, see the - RoaringPenguin package () - which contains instruction on how to use this driver (under - the heading "Kernel mode PPPoE"). - -config PPTP - tristate "PPP over IPv4 (PPTP)" - depends on PPP && NET_IPGRE_DEMUX - ---help--- - Support for PPP over IPv4.(Point-to-Point Tunneling Protocol) - - This driver requires pppd plugin to work in client mode or - modified pptpd (poptop) to work in server mode. - See http://accel-pptp.sourceforge.net/ for information how to - utilize this module. - -config PPPOL2TP - tristate "PPP over L2TP" - depends on L2TP && PPP - ---help--- - Support for PPP-over-L2TP socket family. L2TP is a protocol - used by ISPs and enterprises to tunnel PPP traffic over UDP - tunnels. L2TP is replacing PPTP for VPN uses. -if TTY - -config PPP_ASYNC - tristate "PPP support for async serial ports" - depends on PPP - select CRC_CCITT - ---help--- - Say Y (or M) here if you want to be able to use PPP over standard - asynchronous serial ports, such as COM1 or COM2 on a PC. If you use - a modem (not a synchronous or ISDN modem) to contact your ISP, you - need this option. - - To compile this driver as a module, choose M here. - - If unsure, say Y. - -config PPP_SYNC_TTY - tristate "PPP support for sync tty ports" - depends on PPP - ---help--- - Say Y (or M) here if you want to be able to use PPP over synchronous - (HDLC) tty devices, such as the SyncLink adapter. These devices - are often used for high-speed leased lines like T1/E1. - - To compile this driver as a module, choose M here. - -endif # TTY - -endif # PPP diff --git a/src/linux/drivers/net/slip/Kconfig b/src/linux/drivers/net/slip/Kconfig deleted file mode 100644 index 48e6871..0000000 --- a/src/linux/drivers/net/slip/Kconfig +++ /dev/null @@ -1,80 +0,0 @@ -# -# SLIP network device configuration -# - -config SLIP - tristate "SLIP (serial line) support" - depends on TTY - ---help--- - Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to - connect to your Internet service provider or to connect to some - other local Unix box or if you want to configure your Linux box as a - Slip/CSlip server for other people to dial in. SLIP (Serial Line - Internet Protocol) is a protocol used to send Internet traffic over - serial connections such as telephone lines or null modem cables; - nowadays, the protocol PPP is more commonly used for this same - purpose. - - Normally, your access provider has to support SLIP in order for you - to be able to use it, but there is now a SLIP emulator called SLiRP - around (available from - ) which - allows you to use SLIP over a regular dial up shell connection. If - you plan to use SLiRP, make sure to say Y to CSLIP, below. The - NET-3-HOWTO, available from - , explains how to - configure SLIP. Note that you don't need this option if you just - want to run term (term is a program which gives you almost full - Internet connectivity if you have a regular dial up shell account on - some Internet connected Unix computer. Read - ). SLIP - support will enlarge your kernel by about 4 KB. If unsure, say N. - - To compile this driver as a module, choose M here. The module - will be called slip. - -config SLHC - tristate - ---help--- - This option enables Van Jacobsen serial line header compression - routines. - -if SLIP - -config SLIP_COMPRESSED - bool "CSLIP compressed headers" - depends on SLIP - select SLHC - ---help--- - This protocol is faster than SLIP because it uses compression on the - TCP/IP headers (not on the data itself), but it has to be supported - on both ends. Ask your access provider if you are not sure and - answer Y, just in case. You will still be able to use plain SLIP. If - you plan to use SLiRP, the SLIP emulator (available from - ) which - allows you to use SLIP over a regular dial up shell connection, you - definitely want to say Y here. The NET-3-HOWTO, available from - , explains how to configure - CSLIP. This won't enlarge your kernel. - -config SLIP_SMART - bool "Keepalive and linefill" - depends on SLIP - ---help--- - Adds additional capabilities to the SLIP driver to support the - RELCOM line fill and keepalive monitoring. Ideal on poor quality - analogue lines. - -config SLIP_MODE_SLIP6 - bool "Six bit SLIP encapsulation" - depends on SLIP - ---help--- - Just occasionally you may need to run IP over hostile serial - networks that don't pass all control characters or are only seven - bit. Saying Y here adds an extra mode you can use with SLIP: - "slip6". In this mode, SLIP will only send normal ASCII symbols over - the serial device. Naturally, this has to be supported at the other - end of the link as well. It's good enough, for example, to run IP - over the async ports of a Camtec JNT Pad. If unsure, say N. - -endif # SLIP diff --git a/src/linux/drivers/net/team/Kconfig b/src/linux/drivers/net/team/Kconfig deleted file mode 100644 index c853d84..0000000 --- a/src/linux/drivers/net/team/Kconfig +++ /dev/null @@ -1,76 +0,0 @@ -menuconfig NET_TEAM - tristate "Ethernet team driver support" - ---help--- - This allows one to create virtual interfaces that teams together - multiple ethernet devices. - - Team devices can be added using the "ip" command from the - iproute2 package: - - "ip link add link [ address MAC ] [ NAME ] type team" - - To compile this driver as a module, choose M here: the module - will be called team. - -if NET_TEAM - -config NET_TEAM_MODE_BROADCAST - tristate "Broadcast mode support" - depends on NET_TEAM - ---help--- - Basic mode where packets are transmitted always by all suitable ports. - - All added ports are setup to have team's device address. - - To compile this team mode as a module, choose M here: the module - will be called team_mode_broadcast. - -config NET_TEAM_MODE_ROUNDROBIN - tristate "Round-robin mode support" - depends on NET_TEAM - ---help--- - Basic mode where port used for transmitting packets is selected in - round-robin fashion using packet counter. - - All added ports are setup to have team's device address. - - To compile this team mode as a module, choose M here: the module - will be called team_mode_roundrobin. - -config NET_TEAM_MODE_RANDOM - tristate "Random mode support" - depends on NET_TEAM - ---help--- - Basic mode where port used for transmitting packets is selected - randomly. - - All added ports are setup to have team's device address. - - To compile this team mode as a module, choose M here: the module - will be called team_mode_random. - -config NET_TEAM_MODE_ACTIVEBACKUP - tristate "Active-backup mode support" - depends on NET_TEAM - ---help--- - Only one port is active at a time and the rest of ports are used - for backup. - - Mac addresses of ports are not modified. Userspace is responsible - to do so. - - To compile this team mode as a module, choose M here: the module - will be called team_mode_activebackup. - -config NET_TEAM_MODE_LOADBALANCE - tristate "Load-balance mode support" - depends on NET_TEAM - ---help--- - This mode provides load balancing functionality. Tx port selection - is done using BPF function set up from userspace (bpf_hash_func - option) - - To compile this team mode as a module, choose M here: the module - will be called team_mode_loadbalance. - -endif # NET_TEAM diff --git a/src/linux/drivers/net/usb/Kconfig b/src/linux/drivers/net/usb/Kconfig deleted file mode 100644 index cdde590..0000000 --- a/src/linux/drivers/net/usb/Kconfig +++ /dev/null @@ -1,610 +0,0 @@ -# -# USB Network devices configuration -# -comment "Host-side USB support is needed for USB Network Adapter support" - depends on !USB && NET - -menuconfig USB_NET_DRIVERS - tristate "USB Network Adapters" - default USB if USB - depends on USB && NET - -if USB_NET_DRIVERS - -config USB_CATC - tristate "USB CATC NetMate-based Ethernet device support" - select CRC32 - ---help--- - Say Y if you want to use one of the following 10Mbps USB Ethernet - device based on the EL1210A chip. Supported devices are: - Belkin F5U011 - Belkin F5U111 - CATC NetMate - CATC NetMate II - smartBridges smartNIC - - This driver makes the adapter appear as a normal Ethernet interface, - typically on eth0, if it is the only ethernet device, or perhaps on - eth1, if you have a PCI or ISA ethernet card installed. - - To compile this driver as a module, choose M here: the - module will be called catc. - -config USB_KAWETH - tristate "USB KLSI KL5USB101-based ethernet device support" - ---help--- - Say Y here if you want to use one of the following 10Mbps only - USB Ethernet adapters based on the KLSI KL5KUSB101B chipset: - 3Com 3C19250 - ADS USB-10BT - ATEN USB Ethernet - ASANTE USB To Ethernet Adapter - AOX Endpoints USB Ethernet - Correga K.K. - D-Link DSB-650C and DU-E10 - Entrega / Portgear E45 - I-O DATA USB-ET/T - Jaton USB Ethernet Device Adapter - Kingston Technology USB Ethernet Adapter - Linksys USB10T - Mobility USB-Ethernet Adapter - NetGear EA-101 - Peracom Enet and Enet2 - Portsmith Express Ethernet Adapter - Shark Pocket Adapter - SMC 2202USB - Sony Vaio port extender - - This driver is likely to work with most 10Mbps only USB Ethernet - adapters, including some "no brand" devices. It does NOT work on - SmartBridges smartNIC or on Belkin F5U111 devices - you should use - the CATC NetMate driver for those. If you are not sure which one - you need, select both, and the correct one should be selected for - you. - - This driver makes the adapter appear as a normal Ethernet interface, - typically on eth0, if it is the only ethernet device, or perhaps on - eth1, if you have a PCI or ISA ethernet card installed. - - To compile this driver as a module, choose M here: the - module will be called kaweth. - -config USB_PEGASUS - tristate "USB Pegasus/Pegasus-II based ethernet device support" - select MII - ---help--- - Say Y here if you know you have Pegasus or Pegasus-II based adapter. - If in doubt then look at for the - complete list of supported devices. - - If your particular adapter is not in the list and you are _sure_ it - is Pegasus or Pegasus II based then send me - vendor and device IDs. - - To compile this driver as a module, choose M here: the - module will be called pegasus. - -config USB_RTL8150 - tristate "USB RTL8150 based ethernet device support" - select MII - help - Say Y here if you have RTL8150 based usb-ethernet adapter. - Send me any comments you may have. - You can also check for updates at . - - To compile this driver as a module, choose M here: the - module will be called rtl8150. - -config USB_RTL8152 - tristate "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" - select MII - help - This option adds support for Realtek RTL8152 based USB 2.0 - 10/100 Ethernet adapters and RTL8153 based USB 3.0 10/100/1000 - Ethernet adapters. - - To compile this driver as a module, choose M here: the - module will be called r8152. - -config USB_LAN78XX - tristate "Microchip LAN78XX Based USB Ethernet Adapters" - select MII - select PHYLIB - select MICROCHIP_PHY - help - This option adds support for Microchip LAN78XX based USB 2 - & USB 3 10/100/1000 Ethernet adapters. - - To compile this driver as a module, choose M here: the - module will be called lan78xx. - -config USB_USBNET - tristate "Multi-purpose USB Networking Framework" - select MII - ---help--- - This driver supports several kinds of network links over USB, - with "minidrivers" built around a common network driver core - that supports deep queues for efficient transfers. (This gives - better performance with small packets and at high speeds). - - The USB host runs "usbnet", and the other end of the link might be: - - - Another USB host, when using USB "network" or "data transfer" - cables. These are often used to network laptops to PCs, like - "Laplink" parallel cables or some motherboards. These rely - on specialized chips from many suppliers. - - - An intelligent USB gadget, perhaps embedding a Linux system. - These include PDAs running Linux (iPaq, Yopy, Zaurus, and - others), and devices that interoperate using the standard - CDC-Ethernet specification (including many cable modems). - - - Network adapter hardware (like those for 10/100 Ethernet) which - uses this driver framework. - - The link will appear with a name like "usb0", when the link is - a two-node link, or "eth0" for most CDC-Ethernet devices. Those - two-node links are most easily managed with Ethernet Bridging - (CONFIG_BRIDGE) instead of routing. - - For more information see . - - To compile this driver as a module, choose M here: the - module will be called usbnet. - -config USB_NET_AX8817X - tristate "ASIX AX88xxx Based USB 2.0 Ethernet Adapters" - depends on USB_USBNET - select CRC32 - select PHYLIB - default y - help - This option adds support for ASIX AX88xxx based USB 2.0 - 10/100 Ethernet adapters. - - This driver should work with at least the following devices: - * Aten UC210T - * ASIX AX88172 - * Billionton Systems, USB2AR - * Billionton Systems, GUSB2AM-1G-B - * Buffalo LUA-U2-KTX - * Corega FEther USB2-TX - * D-Link DUB-E100 - * Hawking UF200 - * Linksys USB200M - * Netgear FA120 - * Sitecom LN-029 - * Sitecom LN-028 - * Intellinet USB 2.0 Ethernet - * ST Lab USB 2.0 Ethernet - * TrendNet TU2-ET100 - - This driver creates an interface named "ethX", where X depends on - what other networking devices you have in use. - -config USB_NET_AX88179_178A - tristate "ASIX AX88179/178A USB 3.0/2.0 to Gigabit Ethernet" - depends on USB_USBNET - select CRC32 - select PHYLIB - default y - help - This option adds support for ASIX AX88179 based USB 3.0/2.0 - to Gigabit Ethernet adapters. - - This driver should work with at least the following devices: - * ASIX AX88179 - * ASIX AX88178A - * Sitcomm LN-032 - - This driver creates an interface named "ethX", where X depends on - what other networking devices you have in use. - -config USB_NET_CDCETHER - tristate "CDC Ethernet support (smart devices such as cable modems)" - depends on USB_USBNET - default y - help - This option supports devices conforming to the Communication Device - Class (CDC) Ethernet Control Model, a specification that's easy to - implement in device firmware. The CDC specifications are available - from . - - CDC Ethernet is an implementation option for DOCSIS cable modems - that support USB connectivity, used for non-Microsoft USB hosts. - The Linux-USB CDC Ethernet Gadget driver is an open implementation. - This driver should work with at least the following devices: - - * Dell Wireless 5530 HSPA - * Ericsson PipeRider (all variants) - * Ericsson Mobile Broadband Module (all variants) - * Motorola (DM100 and SB4100) - * Broadcom Cable Modem (reference design) - * Toshiba (PCX1100U and F3507g/F3607gw) - * ... - - This driver creates an interface named "ethX", where X depends on - what other networking devices you have in use. However, if the - IEEE 802 "local assignment" bit is set in the address, a "usbX" - name is used instead. - -config USB_NET_CDC_EEM - tristate "CDC EEM support" - depends on USB_USBNET - help - This option supports devices conforming to the Communication Device - Class (CDC) Ethernet Emulation Model, a specification that's easy to - implement in device firmware. The CDC EEM specifications are available - from . - - This driver creates an interface named "ethX", where X depends on - what other networking devices you have in use. However, if the - IEEE 802 "local assignment" bit is set in the address, a "usbX" - name is used instead. - -config USB_NET_CDC_NCM - tristate "CDC NCM support" - depends on USB_USBNET - default y - help - This driver provides support for CDC NCM (Network Control Model - Device USB Class Specification). The CDC NCM specification is - available from . - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module. - - This driver should work with at least the following devices: - * ST-Ericsson M700 LTE FDD/TDD Mobile Broadband Modem (ref. design) - * ST-Ericsson M5730 HSPA+ Mobile Broadband Modem (reference design) - * ST-Ericsson M570 HSPA+ Mobile Broadband Modem (reference design) - * ST-Ericsson M343 HSPA Mobile Broadband Modem (reference design) - * Ericsson F5521gw Mobile Broadband Module - -config USB_NET_HUAWEI_CDC_NCM - tristate "Huawei NCM embedded AT channel support" - depends on USB_USBNET - select USB_WDM - select USB_NET_CDC_NCM - help - This driver supports huawei-style NCM devices, that use NCM as a - transport for other protocols, usually an embedded AT channel. - Good examples are: - * Huawei E3131 - * Huawei E3251 - - To compile this driver as a module, choose M here: the module will be - called huawei_cdc_ncm.ko. - -config USB_NET_CDC_MBIM - tristate "CDC MBIM support" - depends on USB_USBNET - select USB_WDM - select USB_NET_CDC_NCM - help - This driver provides support for CDC MBIM (Mobile Broadband - Interface Model) devices. The CDC MBIM specification is - available from . - - MBIM devices require configuration using the management - protocol defined by the MBIM specification. This driver - provides unfiltered access to the MBIM control channel - through the associated /dev/cdc-wdmx character device. - - To compile this driver as a module, choose M here: the - module will be called cdc_mbim. - -config USB_NET_DM9601 - tristate "Davicom DM96xx based USB 10/100 ethernet devices" - depends on USB_USBNET - select CRC32 - help - This option adds support for Davicom DM9601/DM9620/DM9621A - based USB 10/100 Ethernet adapters. - -config USB_NET_SR9700 - tristate "CoreChip-sz SR9700 based USB 1.1 10/100 ethernet devices" - depends on USB_USBNET - select CRC32 - help - This option adds support for CoreChip-sz SR9700 based USB 1.1 - 10/100 Ethernet adapters. - -config USB_NET_SR9800 - tristate "CoreChip-sz SR9800 based USB 2.0 10/100 ethernet devices" - depends on USB_USBNET - select CRC32 - ---help--- - Say Y if you want to use one of the following 100Mbps USB Ethernet - device based on the CoreChip-sz SR9800 chip. - - This driver makes the adapter appear as a normal Ethernet interface, - typically on eth0, if it is the only ethernet device, or perhaps on - eth1, if you have a PCI or ISA ethernet card installed. - - To compile this driver as a module, choose M here: the - module will be called sr9800. - -config USB_NET_SMSC75XX - tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices" - depends on USB_USBNET - select BITREVERSE - select CRC16 - select CRC32 - help - This option adds support for SMSC LAN75XX based USB 2.0 - Gigabit Ethernet adapters. - -config USB_NET_SMSC95XX - tristate "SMSC LAN95XX based USB 2.0 10/100 ethernet devices" - depends on USB_USBNET - select BITREVERSE - select CRC16 - select CRC32 - help - This option adds support for SMSC LAN95XX based USB 2.0 - 10/100 Ethernet adapters. - -config USB_NET_GL620A - tristate "GeneSys GL620USB-A based cables" - depends on USB_USBNET - help - Choose this option if you're using a host-to-host cable, - or PC2PC motherboard, with this chip. - - Note that the half-duplex "GL620USB" is not supported. - -config USB_NET_NET1080 - tristate "NetChip 1080 based cables (Laplink, ...)" - default y - depends on USB_USBNET - help - Choose this option if you're using a host-to-host cable based - on this design: one NetChip 1080 chip and supporting logic, - optionally with LEDs that indicate traffic - -config USB_NET_PLUSB - tristate "Prolific PL-2301/2302/25A1 based cables" - # if the handshake/init/reset problems, from original 'plusb', - # are ever resolved ... then remove "experimental" - depends on USB_USBNET - help - Choose this option if you're using a host-to-host cable - with one of these chips. - -config USB_NET_MCS7830 - tristate "MosChip MCS7830 based Ethernet adapters" - depends on USB_USBNET - help - Choose this option if you're using a 10/100 Ethernet USB2 - adapter based on the MosChip 7830 controller. This includes - adapters marketed under the DeLOCK brand. - -config USB_NET_RNDIS_HOST - tristate "Host for RNDIS and ActiveSync devices" - depends on USB_USBNET - select USB_NET_CDCETHER - help - This option enables hosting "Remote NDIS" USB networking links, - as encouraged by Microsoft (instead of CDC Ethernet!) for use in - various devices that may only support this protocol. A variant - of this protocol (with even less public documentation) seems to - be at the root of Microsoft's "ActiveSync" too. - - Avoid using this protocol unless you have no better options. - The protocol specification is incomplete, and is controlled by - (and for) Microsoft; it isn't an "Open" ecosystem or market. - -config USB_NET_CDC_SUBSET_ENABLE - tristate - depends on USB_NET_CDC_SUBSET - -config USB_NET_CDC_SUBSET - tristate "Simple USB Network Links (CDC Ethernet subset)" - depends on USB_USBNET - default y - help - This driver module supports USB network devices that can work - without any device-specific information. Select it if you have - one of these drivers. - - Note that while many USB host-to-host cables can work in this mode, - that may mean not being able to talk to Win32 systems or more - commonly not being able to handle certain events (like replugging - the host on the other end) very well. Also, these devices will - not generally have permanently assigned Ethernet addresses. - -config USB_ALI_M5632 - bool "ALi M5632 based 'USB 2.0 Data Link' cables" - depends on USB_NET_CDC_SUBSET - select USB_NET_CDC_SUBSET_ENABLE - help - Choose this option if you're using a host-to-host cable - based on this design, which supports USB 2.0 high speed. - -config USB_AN2720 - bool "AnchorChips 2720 based cables (Xircom PGUNET, ...)" - depends on USB_NET_CDC_SUBSET - select USB_NET_CDC_SUBSET_ENABLE - help - Choose this option if you're using a host-to-host cable - based on this design. Note that AnchorChips is now a - Cypress brand. - -config USB_BELKIN - bool "eTEK based host-to-host cables (Advance, Belkin, ...)" - depends on USB_NET_CDC_SUBSET - select USB_NET_CDC_SUBSET_ENABLE - default y - help - Choose this option if you're using a host-to-host cable - based on this design: two NetChip 2890 chips and an Atmel - microcontroller, with LEDs that indicate traffic. - -config USB_ARMLINUX - bool "Embedded ARM Linux links (iPaq, ...)" - depends on USB_NET_CDC_SUBSET - select USB_NET_CDC_SUBSET_ENABLE - default y - help - Choose this option to support the "usb-eth" networking driver - used by most of the ARM Linux community with device controllers - such as the SA-11x0 and PXA-25x UDCs, or the tftp capabilities - in some PXA versions of the "blob" boot loader. - - Linux-based "Gumstix" PXA-25x based systems use this protocol - to talk with other Linux systems. - - Although the ROMs shipped with Sharp Zaurus products use a - different link level framing protocol, you can have them use - this simpler protocol by installing a different kernel. - -config USB_EPSON2888 - bool "Epson 2888 based firmware (DEVELOPMENT)" - depends on USB_NET_CDC_SUBSET - select USB_NET_CDC_SUBSET_ENABLE - help - Choose this option to support the usb networking links used - by some sample firmware from Epson. - -config USB_KC2190 - bool "KT Technology KC2190 based cables (InstaNet)" - depends on USB_NET_CDC_SUBSET - select USB_NET_CDC_SUBSET_ENABLE - help - Choose this option if you're using a host-to-host cable - with one of these chips. - -config USB_NET_ZAURUS - tristate "Sharp Zaurus (stock ROMs) and compatible" - depends on USB_USBNET - select USB_NET_CDCETHER - select CRC32 - default y - help - Choose this option to support the usb networking links used by - Zaurus models like the SL-5000D, SL-5500, SL-5600, A-300, B-500. - This also supports some related device firmware, as used in some - PDAs from Olympus and some cell phones from Motorola. - - If you install an alternate image, such as the Linux 2.6 based - versions of OpenZaurus, you should no longer need to support this - protocol. Only the "eth-fd" or "net_fd" drivers in these devices - really need this non-conformant variant of CDC Ethernet (or in - some cases CDC MDLM) protocol, not "g_ether". - -config USB_NET_CX82310_ETH - tristate "Conexant CX82310 USB ethernet port" - depends on USB_USBNET - help - Choose this option if you're using a Conexant CX82310-based ADSL - router with USB ethernet port. This driver is for routers only, - it will not work with ADSL modems (use cxacru driver instead). - -config USB_NET_KALMIA - tristate "Samsung Kalmia based LTE USB modem" - depends on USB_USBNET - help - Choose this option if you have a Samsung Kalmia based USB modem - as Samsung GT-B3730. - - To compile this driver as a module, choose M here: the - module will be called kalmia. - -config USB_NET_QMI_WWAN - tristate "QMI WWAN driver for Qualcomm MSM based 3G and LTE modems" - depends on USB_USBNET - select USB_WDM - help - Support WWAN LTE/3G devices based on Qualcomm Mobile Data Modem - (MDM) chipsets. Examples of such devices are - * Huawei E392/E398 - - This driver will only drive the ethernet part of the chips. - The devices require additional configuration to be usable. - Multiple management interfaces with linux drivers are - available: - - * option: AT commands on /dev/ttyUSBx - * cdc-wdm: Qualcomm MSM Interface (QMI) protocol on /dev/cdc-wdmx - - A modem manager with support for QMI is recommended. - - To compile this driver as a module, choose M here: the - module will be called qmi_wwan. - -config USB_HSO - tristate "Option USB High Speed Mobile Devices" - depends on USB && RFKILL && TTY - default n - help - Choose this option if you have an Option HSDPA/HSUPA card. - These cards support downlink speeds of 7.2Mbps or greater. - - To compile this driver as a module, choose M here: the - module will be called hso. - -config USB_NET_INT51X1 - tristate "Intellon PLC based usb adapter" - depends on USB_USBNET - help - Choose this option if you're using a 14Mb USB-based PLC - (Powerline Communications) solution with an Intellon - INT51x1/INT5200 chip, like the "devolo dLan duo". - -config USB_CDC_PHONET - tristate "CDC Phonet support" - depends on PHONET && USB_USBNET - help - Choose this option to support the Phonet interface to a Nokia - cellular modem, as found on most Nokia handsets with the - "PC suite" USB profile. - -config USB_IPHETH - tristate "Apple iPhone USB Ethernet driver" - default n - ---help--- - Module used to share Internet connection (tethering) from your - iPhone (Original, 3G and 3GS) to your system. - Note that you need userspace libraries and programs that are needed - to pair your device with your system and that understand the iPhone - protocol. - - For more information: http://giagio.com/wiki/moin.cgi/iPhoneEthernetDriver - -config USB_SIERRA_NET - tristate "USB-to-WWAN Driver for Sierra Wireless modems" - depends on USB_USBNET - help - Choose this option if you have a Sierra Wireless USB-to-WWAN device. - - To compile this driver as a module, choose M here: the - module will be called sierra_net. - -config USB_VL600 - tristate "LG VL600 modem dongle" - depends on USB_NET_CDCETHER && TTY - select USB_ACM - help - Select this if you want to use an LG Electronics 4G/LTE usb modem - called VL600. This driver only handles the ethernet - interface exposed by the modem firmware. To establish a connection - you will first need a userspace program that sends the right - command to the modem through its CDC ACM port, and most - likely also a DHCP client. See this thread about using the - 4G modem from Verizon: - - http://ubuntuforums.org/showpost.php?p=10589647&postcount=17 - -config USB_NET_CH9200 - tristate "QingHeng CH9200 USB ethernet support" - depends on USB_USBNET - select MII - help - Choose this option if you have a USB ethernet adapter with a QinHeng - CH9200 chipset. - - To compile this driver as a module, choose M here: the - module will be called ch9200. - -endif # USB_NET_DRIVERS diff --git a/src/linux/drivers/net/virtio_net.c b/src/linux/drivers/net/virtio_net.c deleted file mode 100644 index cbf1c61..0000000 --- a/src/linux/drivers/net/virtio_net.c +++ /dev/null @@ -1,2132 +0,0 @@ -/* A network driver using virtio. - * - * Copyright 2007 Rusty Russell IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ -//#define DEBUG -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int napi_weight = NAPI_POLL_WEIGHT; -module_param(napi_weight, int, 0444); - -static bool csum = true, gso = true; -module_param(csum, bool, 0444); -module_param(gso, bool, 0444); - -/* FIXME: MTU in config. */ -#define GOOD_PACKET_LEN (ETH_HLEN + VLAN_HLEN + ETH_DATA_LEN) -#define GOOD_COPY_LEN 128 - -/* RX packet size EWMA. The average packet size is used to determine the packet - * buffer size when refilling RX rings. As the entire RX ring may be refilled - * at once, the weight is chosen so that the EWMA will be insensitive to short- - * term, transient changes in packet size. - */ -DECLARE_EWMA(pkt_len, 1, 64) - -/* Minimum alignment for mergeable packet buffers. */ -#define MERGEABLE_BUFFER_ALIGN max(L1_CACHE_BYTES, 256) - -#define VIRTNET_DRIVER_VERSION "1.0.0" - -struct virtnet_stats { - struct u64_stats_sync tx_syncp; - struct u64_stats_sync rx_syncp; - u64 tx_bytes; - u64 tx_packets; - - u64 rx_bytes; - u64 rx_packets; -}; - -/* Internal representation of a send virtqueue */ -struct send_queue { - /* Virtqueue associated with this send _queue */ - struct virtqueue *vq; - - /* TX: fragments + linear part + virtio header */ - struct scatterlist sg[MAX_SKB_FRAGS + 2]; - - /* Name of the send queue: output.$index */ - char name[40]; -}; - -/* Internal representation of a receive virtqueue */ -struct receive_queue { - /* Virtqueue associated with this receive_queue */ - struct virtqueue *vq; - - struct napi_struct napi; - - /* Chain pages by the private ptr. */ - struct page *pages; - - /* Average packet length for mergeable receive buffers. */ - struct ewma_pkt_len mrg_avg_pkt_len; - - /* Page frag for packet buffer allocation. */ - struct page_frag alloc_frag; - - /* RX: fragments + linear part + virtio header */ - struct scatterlist sg[MAX_SKB_FRAGS + 2]; - - /* Name of this receive queue: input.$index */ - char name[40]; -}; - -struct virtnet_info { - struct virtio_device *vdev; - struct virtqueue *cvq; - struct net_device *dev; - struct send_queue *sq; - struct receive_queue *rq; - unsigned int status; - - /* Max # of queue pairs supported by the device */ - u16 max_queue_pairs; - - /* # of queue pairs currently used by the driver */ - u16 curr_queue_pairs; - - /* I like... big packets and I cannot lie! */ - bool big_packets; - - /* Host will merge rx buffers for big packets (shake it! shake it!) */ - bool mergeable_rx_bufs; - - /* Has control virtqueue */ - bool has_cvq; - - /* Host can handle any s/g split between our header and packet data */ - bool any_header_sg; - - /* Packet virtio header size */ - u8 hdr_len; - - /* Active statistics */ - struct virtnet_stats __percpu *stats; - - /* Work struct for refilling if we run low on memory. */ - struct delayed_work refill; - - /* Work struct for config space updates */ - struct work_struct config_work; - - /* Does the affinity hint is set for virtqueues? */ - bool affinity_hint_set; - - /* CPU hotplug instances for online & dead */ - struct hlist_node node; - struct hlist_node node_dead; - - /* Control VQ buffers: protected by the rtnl lock */ - struct virtio_net_ctrl_hdr ctrl_hdr; - virtio_net_ctrl_ack ctrl_status; - struct virtio_net_ctrl_mq ctrl_mq; - u8 ctrl_promisc; - u8 ctrl_allmulti; - u16 ctrl_vid; - - /* Ethtool settings */ - u8 duplex; - u32 speed; -}; - -struct padded_vnet_hdr { - struct virtio_net_hdr_mrg_rxbuf hdr; - /* - * hdr is in a separate sg buffer, and data sg buffer shares same page - * with this header sg. This padding makes next sg 16 byte aligned - * after the header. - */ - char padding[4]; -}; - -/* Converting between virtqueue no. and kernel tx/rx queue no. - * 0:rx0 1:tx0 2:rx1 3:tx1 ... 2N:rxN 2N+1:txN 2N+2:cvq - */ -static int vq2txq(struct virtqueue *vq) -{ - return (vq->index - 1) / 2; -} - -static int txq2vq(int txq) -{ - return txq * 2 + 1; -} - -static int vq2rxq(struct virtqueue *vq) -{ - return vq->index / 2; -} - -static int rxq2vq(int rxq) -{ - return rxq * 2; -} - -static inline struct virtio_net_hdr_mrg_rxbuf *skb_vnet_hdr(struct sk_buff *skb) -{ - return (struct virtio_net_hdr_mrg_rxbuf *)skb->cb; -} - -/* - * private is used to chain pages for big packets, put the whole - * most recent used list in the beginning for reuse - */ -static void give_pages(struct receive_queue *rq, struct page *page) -{ - struct page *end; - - /* Find end of list, sew whole thing into vi->rq.pages. */ - for (end = page; end->private; end = (struct page *)end->private); - end->private = (unsigned long)rq->pages; - rq->pages = page; -} - -static struct page *get_a_page(struct receive_queue *rq, gfp_t gfp_mask) -{ - struct page *p = rq->pages; - - if (p) { - rq->pages = (struct page *)p->private; - /* clear private here, it is used to chain pages */ - p->private = 0; - } else - p = alloc_page(gfp_mask); - return p; -} - -static void skb_xmit_done(struct virtqueue *vq) -{ - struct virtnet_info *vi = vq->vdev->priv; - - /* Suppress further interrupts. */ - virtqueue_disable_cb(vq); - - /* We were probably waiting for more output buffers. */ - netif_wake_subqueue(vi->dev, vq2txq(vq)); -} - -static unsigned int mergeable_ctx_to_buf_truesize(unsigned long mrg_ctx) -{ - unsigned int truesize = mrg_ctx & (MERGEABLE_BUFFER_ALIGN - 1); - return (truesize + 1) * MERGEABLE_BUFFER_ALIGN; -} - -static void *mergeable_ctx_to_buf_address(unsigned long mrg_ctx) -{ - return (void *)(mrg_ctx & -MERGEABLE_BUFFER_ALIGN); - -} - -static unsigned long mergeable_buf_to_ctx(void *buf, unsigned int truesize) -{ - unsigned int size = truesize / MERGEABLE_BUFFER_ALIGN; - return (unsigned long)buf | (size - 1); -} - -/* Called from bottom half context */ -static struct sk_buff *page_to_skb(struct virtnet_info *vi, - struct receive_queue *rq, - struct page *page, unsigned int offset, - unsigned int len, unsigned int truesize) -{ - struct sk_buff *skb; - struct virtio_net_hdr_mrg_rxbuf *hdr; - unsigned int copy, hdr_len, hdr_padded_len; - char *p; - - p = page_address(page) + offset; - - /* copy small packet so we can reuse these pages for small data */ - skb = napi_alloc_skb(&rq->napi, GOOD_COPY_LEN); - if (unlikely(!skb)) - return NULL; - - hdr = skb_vnet_hdr(skb); - - hdr_len = vi->hdr_len; - if (vi->mergeable_rx_bufs) - hdr_padded_len = sizeof *hdr; - else - hdr_padded_len = sizeof(struct padded_vnet_hdr); - - memcpy(hdr, p, hdr_len); - - len -= hdr_len; - offset += hdr_padded_len; - p += hdr_padded_len; - - copy = len; - if (copy > skb_tailroom(skb)) - copy = skb_tailroom(skb); - memcpy(skb_put(skb, copy), p, copy); - - len -= copy; - offset += copy; - - if (vi->mergeable_rx_bufs) { - if (len) - skb_add_rx_frag(skb, 0, page, offset, len, truesize); - else - put_page(page); - return skb; - } - - /* - * Verify that we can indeed put this data into a skb. - * This is here to handle cases when the device erroneously - * tries to receive more than is possible. This is usually - * the case of a broken device. - */ - if (unlikely(len > MAX_SKB_FRAGS * PAGE_SIZE)) { - net_dbg_ratelimited("%s: too much data\n", skb->dev->name); - dev_kfree_skb(skb); - return NULL; - } - BUG_ON(offset >= PAGE_SIZE); - while (len) { - unsigned int frag_size = min((unsigned)PAGE_SIZE - offset, len); - skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page, offset, - frag_size, truesize); - len -= frag_size; - page = (struct page *)page->private; - offset = 0; - } - - if (page) - give_pages(rq, page); - - return skb; -} - -static struct sk_buff *receive_small(struct virtnet_info *vi, void *buf, unsigned int len) -{ - struct sk_buff * skb = buf; - - len -= vi->hdr_len; - skb_trim(skb, len); - - return skb; -} - -static struct sk_buff *receive_big(struct net_device *dev, - struct virtnet_info *vi, - struct receive_queue *rq, - void *buf, - unsigned int len) -{ - struct page *page = buf; - struct sk_buff *skb = page_to_skb(vi, rq, page, 0, len, PAGE_SIZE); - - if (unlikely(!skb)) - goto err; - - return skb; - -err: - dev->stats.rx_dropped++; - give_pages(rq, page); - return NULL; -} - -static struct sk_buff *receive_mergeable(struct net_device *dev, - struct virtnet_info *vi, - struct receive_queue *rq, - unsigned long ctx, - unsigned int len) -{ - void *buf = mergeable_ctx_to_buf_address(ctx); - struct virtio_net_hdr_mrg_rxbuf *hdr = buf; - u16 num_buf = virtio16_to_cpu(vi->vdev, hdr->num_buffers); - struct page *page = virt_to_head_page(buf); - int offset = buf - page_address(page); - unsigned int truesize = max(len, mergeable_ctx_to_buf_truesize(ctx)); - - struct sk_buff *head_skb = page_to_skb(vi, rq, page, offset, len, - truesize); - struct sk_buff *curr_skb = head_skb; - - if (unlikely(!curr_skb)) - goto err_skb; - while (--num_buf) { - int num_skb_frags; - - ctx = (unsigned long)virtqueue_get_buf(rq->vq, &len); - if (unlikely(!ctx)) { - pr_debug("%s: rx error: %d buffers out of %d missing\n", - dev->name, num_buf, - virtio16_to_cpu(vi->vdev, - hdr->num_buffers)); - dev->stats.rx_length_errors++; - goto err_buf; - } - - buf = mergeable_ctx_to_buf_address(ctx); - page = virt_to_head_page(buf); - - num_skb_frags = skb_shinfo(curr_skb)->nr_frags; - if (unlikely(num_skb_frags == MAX_SKB_FRAGS)) { - struct sk_buff *nskb = alloc_skb(0, GFP_ATOMIC); - - if (unlikely(!nskb)) - goto err_skb; - if (curr_skb == head_skb) - skb_shinfo(curr_skb)->frag_list = nskb; - else - curr_skb->next = nskb; - curr_skb = nskb; - head_skb->truesize += nskb->truesize; - num_skb_frags = 0; - } - truesize = max(len, mergeable_ctx_to_buf_truesize(ctx)); - if (curr_skb != head_skb) { - head_skb->data_len += len; - head_skb->len += len; - head_skb->truesize += truesize; - } - offset = buf - page_address(page); - if (skb_can_coalesce(curr_skb, num_skb_frags, page, offset)) { - put_page(page); - skb_coalesce_rx_frag(curr_skb, num_skb_frags - 1, - len, truesize); - } else { - skb_add_rx_frag(curr_skb, num_skb_frags, page, - offset, len, truesize); - } - } - - ewma_pkt_len_add(&rq->mrg_avg_pkt_len, head_skb->len); - return head_skb; - -err_skb: - put_page(page); - while (--num_buf) { - ctx = (unsigned long)virtqueue_get_buf(rq->vq, &len); - if (unlikely(!ctx)) { - pr_debug("%s: rx error: %d buffers missing\n", - dev->name, num_buf); - dev->stats.rx_length_errors++; - break; - } - page = virt_to_head_page(mergeable_ctx_to_buf_address(ctx)); - put_page(page); - } -err_buf: - dev->stats.rx_dropped++; - dev_kfree_skb(head_skb); - return NULL; -} - -static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq, - void *buf, unsigned int len) -{ - struct net_device *dev = vi->dev; - struct virtnet_stats *stats = this_cpu_ptr(vi->stats); - struct sk_buff *skb; - struct virtio_net_hdr_mrg_rxbuf *hdr; - - if (unlikely(len < vi->hdr_len + ETH_HLEN)) { - pr_debug("%s: short packet %i\n", dev->name, len); - dev->stats.rx_length_errors++; - if (vi->mergeable_rx_bufs) { - unsigned long ctx = (unsigned long)buf; - void *base = mergeable_ctx_to_buf_address(ctx); - put_page(virt_to_head_page(base)); - } else if (vi->big_packets) { - give_pages(rq, buf); - } else { - dev_kfree_skb(buf); - } - return; - } - - if (vi->mergeable_rx_bufs) - skb = receive_mergeable(dev, vi, rq, (unsigned long)buf, len); - else if (vi->big_packets) - skb = receive_big(dev, vi, rq, buf, len); - else - skb = receive_small(vi, buf, len); - - if (unlikely(!skb)) - return; - - hdr = skb_vnet_hdr(skb); - - u64_stats_update_begin(&stats->rx_syncp); - stats->rx_bytes += skb->len; - stats->rx_packets++; - u64_stats_update_end(&stats->rx_syncp); - - if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID) - skb->ip_summed = CHECKSUM_UNNECESSARY; - - if (virtio_net_hdr_to_skb(skb, &hdr->hdr, - virtio_is_little_endian(vi->vdev))) { - net_warn_ratelimited("%s: bad gso: type: %u, size: %u\n", - dev->name, hdr->hdr.gso_type, - hdr->hdr.gso_size); - goto frame_err; - } - - skb->protocol = eth_type_trans(skb, dev); - pr_debug("Receiving skb proto 0x%04x len %i type %i\n", - ntohs(skb->protocol), skb->len, skb->pkt_type); - - napi_gro_receive(&rq->napi, skb); - return; - -frame_err: - dev->stats.rx_frame_errors++; - dev_kfree_skb(skb); -} - -static int add_recvbuf_small(struct virtnet_info *vi, struct receive_queue *rq, - gfp_t gfp) -{ - struct sk_buff *skb; - struct virtio_net_hdr_mrg_rxbuf *hdr; - int err; - - skb = __netdev_alloc_skb_ip_align(vi->dev, GOOD_PACKET_LEN, gfp); - if (unlikely(!skb)) - return -ENOMEM; - - skb_put(skb, GOOD_PACKET_LEN); - - hdr = skb_vnet_hdr(skb); - sg_init_table(rq->sg, 2); - sg_set_buf(rq->sg, hdr, vi->hdr_len); - skb_to_sgvec(skb, rq->sg + 1, 0, skb->len); - - err = virtqueue_add_inbuf(rq->vq, rq->sg, 2, skb, gfp); - if (err < 0) - dev_kfree_skb(skb); - - return err; -} - -static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq, - gfp_t gfp) -{ - struct page *first, *list = NULL; - char *p; - int i, err, offset; - - sg_init_table(rq->sg, MAX_SKB_FRAGS + 2); - - /* page in rq->sg[MAX_SKB_FRAGS + 1] is list tail */ - for (i = MAX_SKB_FRAGS + 1; i > 1; --i) { - first = get_a_page(rq, gfp); - if (!first) { - if (list) - give_pages(rq, list); - return -ENOMEM; - } - sg_set_buf(&rq->sg[i], page_address(first), PAGE_SIZE); - - /* chain new page in list head to match sg */ - first->private = (unsigned long)list; - list = first; - } - - first = get_a_page(rq, gfp); - if (!first) { - give_pages(rq, list); - return -ENOMEM; - } - p = page_address(first); - - /* rq->sg[0], rq->sg[1] share the same page */ - /* a separated rq->sg[0] for header - required in case !any_header_sg */ - sg_set_buf(&rq->sg[0], p, vi->hdr_len); - - /* rq->sg[1] for data packet, from offset */ - offset = sizeof(struct padded_vnet_hdr); - sg_set_buf(&rq->sg[1], p + offset, PAGE_SIZE - offset); - - /* chain first in list head */ - first->private = (unsigned long)list; - err = virtqueue_add_inbuf(rq->vq, rq->sg, MAX_SKB_FRAGS + 2, - first, gfp); - if (err < 0) - give_pages(rq, first); - - return err; -} - -static unsigned int get_mergeable_buf_len(struct ewma_pkt_len *avg_pkt_len) -{ - const size_t hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf); - unsigned int len; - - len = hdr_len + clamp_t(unsigned int, ewma_pkt_len_read(avg_pkt_len), - GOOD_PACKET_LEN, PAGE_SIZE - hdr_len); - return ALIGN(len, MERGEABLE_BUFFER_ALIGN); -} - -static int add_recvbuf_mergeable(struct receive_queue *rq, gfp_t gfp) -{ - struct page_frag *alloc_frag = &rq->alloc_frag; - char *buf; - unsigned long ctx; - int err; - unsigned int len, hole; - - len = get_mergeable_buf_len(&rq->mrg_avg_pkt_len); - if (unlikely(!skb_page_frag_refill(len, alloc_frag, gfp))) - return -ENOMEM; - - buf = (char *)page_address(alloc_frag->page) + alloc_frag->offset; - ctx = mergeable_buf_to_ctx(buf, len); - get_page(alloc_frag->page); - alloc_frag->offset += len; - hole = alloc_frag->size - alloc_frag->offset; - if (hole < len) { - /* To avoid internal fragmentation, if there is very likely not - * enough space for another buffer, add the remaining space to - * the current buffer. This extra space is not included in - * the truesize stored in ctx. - */ - len += hole; - alloc_frag->offset += hole; - } - - sg_init_one(rq->sg, buf, len); - err = virtqueue_add_inbuf(rq->vq, rq->sg, 1, (void *)ctx, gfp); - if (err < 0) - put_page(virt_to_head_page(buf)); - - return err; -} - -/* - * Returns false if we couldn't fill entirely (OOM). - * - * Normally run in the receive path, but can also be run from ndo_open - * before we're receiving packets, or from refill_work which is - * careful to disable receiving (using napi_disable). - */ -static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq, - gfp_t gfp) -{ - int err; - bool oom; - - gfp |= __GFP_COLD; - do { - if (vi->mergeable_rx_bufs) - err = add_recvbuf_mergeable(rq, gfp); - else if (vi->big_packets) - err = add_recvbuf_big(vi, rq, gfp); - else - err = add_recvbuf_small(vi, rq, gfp); - - oom = err == -ENOMEM; - if (err) - break; - } while (rq->vq->num_free); - virtqueue_kick(rq->vq); - return !oom; -} - -static void skb_recv_done(struct virtqueue *rvq) -{ - struct virtnet_info *vi = rvq->vdev->priv; - struct receive_queue *rq = &vi->rq[vq2rxq(rvq)]; - - /* Schedule NAPI, Suppress further interrupts if successful. */ - if (napi_schedule_prep(&rq->napi)) { - virtqueue_disable_cb(rvq); - __napi_schedule(&rq->napi); - } -} - -static void virtnet_napi_enable(struct receive_queue *rq) -{ - napi_enable(&rq->napi); - - /* If all buffers were filled by other side before we napi_enabled, we - * won't get another interrupt, so process any outstanding packets - * now. virtnet_poll wants re-enable the queue, so we disable here. - * We synchronize against interrupts via NAPI_STATE_SCHED */ - if (napi_schedule_prep(&rq->napi)) { - virtqueue_disable_cb(rq->vq); - local_bh_disable(); - __napi_schedule(&rq->napi); - local_bh_enable(); - } -} - -static void refill_work(struct work_struct *work) -{ - struct virtnet_info *vi = - container_of(work, struct virtnet_info, refill.work); - bool still_empty; - int i; - - for (i = 0; i < vi->curr_queue_pairs; i++) { - struct receive_queue *rq = &vi->rq[i]; - - napi_disable(&rq->napi); - still_empty = !try_fill_recv(vi, rq, GFP_KERNEL); - virtnet_napi_enable(rq); - - /* In theory, this can happen: if we don't get any buffers in - * we will *never* try to fill again. - */ - if (still_empty) - schedule_delayed_work(&vi->refill, HZ/2); - } -} - -static int virtnet_receive(struct receive_queue *rq, int budget) -{ - struct virtnet_info *vi = rq->vq->vdev->priv; - unsigned int len, received = 0; - void *buf; - - while (received < budget && - (buf = virtqueue_get_buf(rq->vq, &len)) != NULL) { - receive_buf(vi, rq, buf, len); - received++; - } - - if (rq->vq->num_free > virtqueue_get_vring_size(rq->vq) / 2) { - if (!try_fill_recv(vi, rq, GFP_ATOMIC)) - schedule_delayed_work(&vi->refill, 0); - } - - return received; -} - -static int virtnet_poll(struct napi_struct *napi, int budget) -{ - struct receive_queue *rq = - container_of(napi, struct receive_queue, napi); - unsigned int r, received; - - received = virtnet_receive(rq, budget); - - /* Out of packets? */ - if (received < budget) { - r = virtqueue_enable_cb_prepare(rq->vq); - napi_complete_done(napi, received); - if (unlikely(virtqueue_poll(rq->vq, r)) && - napi_schedule_prep(napi)) { - virtqueue_disable_cb(rq->vq); - __napi_schedule(napi); - } - } - - return received; -} - -#ifdef CONFIG_NET_RX_BUSY_POLL -/* must be called with local_bh_disable()d */ -static int virtnet_busy_poll(struct napi_struct *napi) -{ - struct receive_queue *rq = - container_of(napi, struct receive_queue, napi); - struct virtnet_info *vi = rq->vq->vdev->priv; - int r, received = 0, budget = 4; - - if (!(vi->status & VIRTIO_NET_S_LINK_UP)) - return LL_FLUSH_FAILED; - - if (!napi_schedule_prep(napi)) - return LL_FLUSH_BUSY; - - virtqueue_disable_cb(rq->vq); - -again: - received += virtnet_receive(rq, budget); - - r = virtqueue_enable_cb_prepare(rq->vq); - clear_bit(NAPI_STATE_SCHED, &napi->state); - if (unlikely(virtqueue_poll(rq->vq, r)) && - napi_schedule_prep(napi)) { - virtqueue_disable_cb(rq->vq); - if (received < budget) { - budget -= received; - goto again; - } else { - __napi_schedule(napi); - } - } - - return received; -} -#endif /* CONFIG_NET_RX_BUSY_POLL */ - -static int virtnet_open(struct net_device *dev) -{ - struct virtnet_info *vi = netdev_priv(dev); - int i; - - for (i = 0; i < vi->max_queue_pairs; i++) { - if (i < vi->curr_queue_pairs) - /* Make sure we have some buffers: if oom use wq. */ - if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL)) - schedule_delayed_work(&vi->refill, 0); - virtnet_napi_enable(&vi->rq[i]); - } - - return 0; -} - -static void free_old_xmit_skbs(struct send_queue *sq) -{ - struct sk_buff *skb; - unsigned int len; - struct virtnet_info *vi = sq->vq->vdev->priv; - struct virtnet_stats *stats = this_cpu_ptr(vi->stats); - - while ((skb = virtqueue_get_buf(sq->vq, &len)) != NULL) { - pr_debug("Sent skb %p\n", skb); - - u64_stats_update_begin(&stats->tx_syncp); - stats->tx_bytes += skb->len; - stats->tx_packets++; - u64_stats_update_end(&stats->tx_syncp); - - dev_kfree_skb_any(skb); - } -} - -static int xmit_skb(struct send_queue *sq, struct sk_buff *skb) -{ - struct virtio_net_hdr_mrg_rxbuf *hdr; - const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; - struct virtnet_info *vi = sq->vq->vdev->priv; - unsigned num_sg; - unsigned hdr_len = vi->hdr_len; - bool can_push; - - pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest); - - can_push = vi->any_header_sg && - !((unsigned long)skb->data & (__alignof__(*hdr) - 1)) && - !skb_header_cloned(skb) && skb_headroom(skb) >= hdr_len; - /* Even if we can, don't push here yet as this would skew - * csum_start offset below. */ - if (can_push) - hdr = (struct virtio_net_hdr_mrg_rxbuf *)(skb->data - hdr_len); - else - hdr = skb_vnet_hdr(skb); - - if (virtio_net_hdr_from_skb(skb, &hdr->hdr, - virtio_is_little_endian(vi->vdev))) - BUG(); - - if (vi->mergeable_rx_bufs) - hdr->num_buffers = 0; - - sg_init_table(sq->sg, skb_shinfo(skb)->nr_frags + (can_push ? 1 : 2)); - if (can_push) { - __skb_push(skb, hdr_len); - num_sg = skb_to_sgvec(skb, sq->sg, 0, skb->len); - /* Pull header back to avoid skew in tx bytes calculations. */ - __skb_pull(skb, hdr_len); - } else { - sg_set_buf(sq->sg, hdr, hdr_len); - num_sg = skb_to_sgvec(skb, sq->sg + 1, 0, skb->len) + 1; - } - return virtqueue_add_outbuf(sq->vq, sq->sg, num_sg, skb, GFP_ATOMIC); -} - -static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct virtnet_info *vi = netdev_priv(dev); - int qnum = skb_get_queue_mapping(skb); - struct send_queue *sq = &vi->sq[qnum]; - int err; - struct netdev_queue *txq = netdev_get_tx_queue(dev, qnum); - bool kick = !skb->xmit_more; - - /* Free up any pending old buffers before queueing new ones. */ - free_old_xmit_skbs(sq); - - /* timestamp packet in software */ - skb_tx_timestamp(skb); - - /* Try to transmit */ - err = xmit_skb(sq, skb); - - /* This should not happen! */ - if (unlikely(err)) { - dev->stats.tx_fifo_errors++; - if (net_ratelimit()) - dev_warn(&dev->dev, - "Unexpected TXQ (%d) queue failure: %d\n", qnum, err); - dev->stats.tx_dropped++; - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; - } - - /* Don't wait up for transmitted skbs to be freed. */ - skb_orphan(skb); - nf_reset(skb); - - /* If running out of space, stop queue to avoid getting packets that we - * are then unable to transmit. - * An alternative would be to force queuing layer to requeue the skb by - * returning NETDEV_TX_BUSY. However, NETDEV_TX_BUSY should not be - * returned in a normal path of operation: it means that driver is not - * maintaining the TX queue stop/start state properly, and causes - * the stack to do a non-trivial amount of useless work. - * Since most packets only take 1 or 2 ring slots, stopping the queue - * early means 16 slots are typically wasted. - */ - if (sq->vq->num_free < 2+MAX_SKB_FRAGS) { - netif_stop_subqueue(dev, qnum); - if (unlikely(!virtqueue_enable_cb_delayed(sq->vq))) { - /* More just got used, free them then recheck. */ - free_old_xmit_skbs(sq); - if (sq->vq->num_free >= 2+MAX_SKB_FRAGS) { - netif_start_subqueue(dev, qnum); - virtqueue_disable_cb(sq->vq); - } - } - } - - if (kick || netif_xmit_stopped(txq)) - virtqueue_kick(sq->vq); - - return NETDEV_TX_OK; -} - -/* - * Send command via the control virtqueue and check status. Commands - * supported by the hypervisor, as indicated by feature bits, should - * never fail unless improperly formatted. - */ -static bool virtnet_send_command(struct virtnet_info *vi, u8 class, u8 cmd, - struct scatterlist *out) -{ - struct scatterlist *sgs[4], hdr, stat; - unsigned out_num = 0, tmp; - - /* Caller should know better */ - BUG_ON(!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ)); - - vi->ctrl_status = ~0; - vi->ctrl_hdr.class = class; - vi->ctrl_hdr.cmd = cmd; - /* Add header */ - sg_init_one(&hdr, &vi->ctrl_hdr, sizeof(vi->ctrl_hdr)); - sgs[out_num++] = &hdr; - - if (out) - sgs[out_num++] = out; - - /* Add return status. */ - sg_init_one(&stat, &vi->ctrl_status, sizeof(vi->ctrl_status)); - sgs[out_num] = &stat; - - BUG_ON(out_num + 1 > ARRAY_SIZE(sgs)); - virtqueue_add_sgs(vi->cvq, sgs, out_num, 1, vi, GFP_ATOMIC); - - if (unlikely(!virtqueue_kick(vi->cvq))) - return vi->ctrl_status == VIRTIO_NET_OK; - - /* Spin for a response, the kick causes an ioport write, trapping - * into the hypervisor, so the request should be handled immediately. - */ - while (!virtqueue_get_buf(vi->cvq, &tmp) && - !virtqueue_is_broken(vi->cvq)) - cpu_relax(); - - return vi->ctrl_status == VIRTIO_NET_OK; -} - -static int virtnet_set_mac_address(struct net_device *dev, void *p) -{ - struct virtnet_info *vi = netdev_priv(dev); - struct virtio_device *vdev = vi->vdev; - int ret; - struct sockaddr *addr; - struct scatterlist sg; - - addr = kmalloc(sizeof(*addr), GFP_KERNEL); - if (!addr) - return -ENOMEM; - memcpy(addr, p, sizeof(*addr)); - - ret = eth_prepare_mac_addr_change(dev, addr); - if (ret) - goto out; - - if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR)) { - sg_init_one(&sg, addr->sa_data, dev->addr_len); - if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC, - VIRTIO_NET_CTRL_MAC_ADDR_SET, &sg)) { - dev_warn(&vdev->dev, - "Failed to set mac address by vq command.\n"); - ret = -EINVAL; - goto out; - } - } else if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC) && - !virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) { - unsigned int i; - - /* Naturally, this has an atomicity problem. */ - for (i = 0; i < dev->addr_len; i++) - virtio_cwrite8(vdev, - offsetof(struct virtio_net_config, mac) + - i, addr->sa_data[i]); - } - - eth_commit_mac_addr_change(dev, p); - ret = 0; - -out: - kfree(addr); - return ret; -} - -static struct rtnl_link_stats64 *virtnet_stats(struct net_device *dev, - struct rtnl_link_stats64 *tot) -{ - struct virtnet_info *vi = netdev_priv(dev); - int cpu; - unsigned int start; - - for_each_possible_cpu(cpu) { - struct virtnet_stats *stats = per_cpu_ptr(vi->stats, cpu); - u64 tpackets, tbytes, rpackets, rbytes; - - do { - start = u64_stats_fetch_begin_irq(&stats->tx_syncp); - tpackets = stats->tx_packets; - tbytes = stats->tx_bytes; - } while (u64_stats_fetch_retry_irq(&stats->tx_syncp, start)); - - do { - start = u64_stats_fetch_begin_irq(&stats->rx_syncp); - rpackets = stats->rx_packets; - rbytes = stats->rx_bytes; - } while (u64_stats_fetch_retry_irq(&stats->rx_syncp, start)); - - tot->rx_packets += rpackets; - tot->tx_packets += tpackets; - tot->rx_bytes += rbytes; - tot->tx_bytes += tbytes; - } - - tot->tx_dropped = dev->stats.tx_dropped; - tot->tx_fifo_errors = dev->stats.tx_fifo_errors; - tot->rx_dropped = dev->stats.rx_dropped; - tot->rx_length_errors = dev->stats.rx_length_errors; - tot->rx_frame_errors = dev->stats.rx_frame_errors; - - return tot; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void virtnet_netpoll(struct net_device *dev) -{ - struct virtnet_info *vi = netdev_priv(dev); - int i; - - for (i = 0; i < vi->curr_queue_pairs; i++) - napi_schedule(&vi->rq[i].napi); -} -#endif - -static void virtnet_ack_link_announce(struct virtnet_info *vi) -{ - rtnl_lock(); - if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_ANNOUNCE, - VIRTIO_NET_CTRL_ANNOUNCE_ACK, NULL)) - dev_warn(&vi->dev->dev, "Failed to ack link announce.\n"); - rtnl_unlock(); -} - -static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs) -{ - struct scatterlist sg; - struct net_device *dev = vi->dev; - - if (!vi->has_cvq || !virtio_has_feature(vi->vdev, VIRTIO_NET_F_MQ)) - return 0; - - vi->ctrl_mq.virtqueue_pairs = cpu_to_virtio16(vi->vdev, queue_pairs); - sg_init_one(&sg, &vi->ctrl_mq, sizeof(vi->ctrl_mq)); - - if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MQ, - VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, &sg)) { - dev_warn(&dev->dev, "Fail to set num of queue pairs to %d\n", - queue_pairs); - return -EINVAL; - } else { - vi->curr_queue_pairs = queue_pairs; - /* virtnet_open() will refill when device is going to up. */ - if (dev->flags & IFF_UP) - schedule_delayed_work(&vi->refill, 0); - } - - return 0; -} - -static int virtnet_close(struct net_device *dev) -{ - struct virtnet_info *vi = netdev_priv(dev); - int i; - - /* Make sure refill_work doesn't re-enable napi! */ - cancel_delayed_work_sync(&vi->refill); - - for (i = 0; i < vi->max_queue_pairs; i++) - napi_disable(&vi->rq[i].napi); - - return 0; -} - -static void virtnet_set_rx_mode(struct net_device *dev) -{ - struct virtnet_info *vi = netdev_priv(dev); - struct scatterlist sg[2]; - struct virtio_net_ctrl_mac *mac_data; - struct netdev_hw_addr *ha; - int uc_count; - int mc_count; - void *buf; - int i; - - /* We can't dynamically set ndo_set_rx_mode, so return gracefully */ - if (!virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_RX)) - return; - - vi->ctrl_promisc = ((dev->flags & IFF_PROMISC) != 0); - vi->ctrl_allmulti = ((dev->flags & IFF_ALLMULTI) != 0); - - sg_init_one(sg, &vi->ctrl_promisc, sizeof(vi->ctrl_promisc)); - - if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX, - VIRTIO_NET_CTRL_RX_PROMISC, sg)) - dev_warn(&dev->dev, "Failed to %sable promisc mode.\n", - vi->ctrl_promisc ? "en" : "dis"); - - sg_init_one(sg, &vi->ctrl_allmulti, sizeof(vi->ctrl_allmulti)); - - if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_RX, - VIRTIO_NET_CTRL_RX_ALLMULTI, sg)) - dev_warn(&dev->dev, "Failed to %sable allmulti mode.\n", - vi->ctrl_allmulti ? "en" : "dis"); - - uc_count = netdev_uc_count(dev); - mc_count = netdev_mc_count(dev); - /* MAC filter - use one buffer for both lists */ - buf = kzalloc(((uc_count + mc_count) * ETH_ALEN) + - (2 * sizeof(mac_data->entries)), GFP_ATOMIC); - mac_data = buf; - if (!buf) - return; - - sg_init_table(sg, 2); - - /* Store the unicast list and count in the front of the buffer */ - mac_data->entries = cpu_to_virtio32(vi->vdev, uc_count); - i = 0; - netdev_for_each_uc_addr(ha, dev) - memcpy(&mac_data->macs[i++][0], ha->addr, ETH_ALEN); - - sg_set_buf(&sg[0], mac_data, - sizeof(mac_data->entries) + (uc_count * ETH_ALEN)); - - /* multicast list and count fill the end */ - mac_data = (void *)&mac_data->macs[uc_count][0]; - - mac_data->entries = cpu_to_virtio32(vi->vdev, mc_count); - i = 0; - netdev_for_each_mc_addr(ha, dev) - memcpy(&mac_data->macs[i++][0], ha->addr, ETH_ALEN); - - sg_set_buf(&sg[1], mac_data, - sizeof(mac_data->entries) + (mc_count * ETH_ALEN)); - - if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MAC, - VIRTIO_NET_CTRL_MAC_TABLE_SET, sg)) - dev_warn(&dev->dev, "Failed to set MAC filter table.\n"); - - kfree(buf); -} - -static int virtnet_vlan_rx_add_vid(struct net_device *dev, - __be16 proto, u16 vid) -{ - struct virtnet_info *vi = netdev_priv(dev); - struct scatterlist sg; - - vi->ctrl_vid = vid; - sg_init_one(&sg, &vi->ctrl_vid, sizeof(vi->ctrl_vid)); - - if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_VLAN, - VIRTIO_NET_CTRL_VLAN_ADD, &sg)) - dev_warn(&dev->dev, "Failed to add VLAN ID %d.\n", vid); - return 0; -} - -static int virtnet_vlan_rx_kill_vid(struct net_device *dev, - __be16 proto, u16 vid) -{ - struct virtnet_info *vi = netdev_priv(dev); - struct scatterlist sg; - - vi->ctrl_vid = vid; - sg_init_one(&sg, &vi->ctrl_vid, sizeof(vi->ctrl_vid)); - - if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_VLAN, - VIRTIO_NET_CTRL_VLAN_DEL, &sg)) - dev_warn(&dev->dev, "Failed to kill VLAN ID %d.\n", vid); - return 0; -} - -static void virtnet_clean_affinity(struct virtnet_info *vi, long hcpu) -{ - int i; - - if (vi->affinity_hint_set) { - for (i = 0; i < vi->max_queue_pairs; i++) { - virtqueue_set_affinity(vi->rq[i].vq, -1); - virtqueue_set_affinity(vi->sq[i].vq, -1); - } - - vi->affinity_hint_set = false; - } -} - -static void virtnet_set_affinity(struct virtnet_info *vi) -{ - int i; - int cpu; - - /* In multiqueue mode, when the number of cpu is equal to the number of - * queue pairs, we let the queue pairs to be private to one cpu by - * setting the affinity hint to eliminate the contention. - */ - if (vi->curr_queue_pairs == 1 || - vi->max_queue_pairs != num_online_cpus()) { - virtnet_clean_affinity(vi, -1); - return; - } - - i = 0; - for_each_online_cpu(cpu) { - virtqueue_set_affinity(vi->rq[i].vq, cpu); - virtqueue_set_affinity(vi->sq[i].vq, cpu); - netif_set_xps_queue(vi->dev, cpumask_of(cpu), i); - i++; - } - - vi->affinity_hint_set = true; -} - -static int virtnet_cpu_online(unsigned int cpu, struct hlist_node *node) -{ - struct virtnet_info *vi = hlist_entry_safe(node, struct virtnet_info, - node); - virtnet_set_affinity(vi); - return 0; -} - -static int virtnet_cpu_dead(unsigned int cpu, struct hlist_node *node) -{ - struct virtnet_info *vi = hlist_entry_safe(node, struct virtnet_info, - node_dead); - virtnet_set_affinity(vi); - return 0; -} - -static int virtnet_cpu_down_prep(unsigned int cpu, struct hlist_node *node) -{ - struct virtnet_info *vi = hlist_entry_safe(node, struct virtnet_info, - node); - - virtnet_clean_affinity(vi, cpu); - return 0; -} - -static enum cpuhp_state virtionet_online; - -static int virtnet_cpu_notif_add(struct virtnet_info *vi) -{ - int ret; - - ret = cpuhp_state_add_instance_nocalls(virtionet_online, &vi->node); - if (ret) - return ret; - ret = cpuhp_state_add_instance_nocalls(CPUHP_VIRT_NET_DEAD, - &vi->node_dead); - if (!ret) - return ret; - cpuhp_state_remove_instance_nocalls(virtionet_online, &vi->node); - return ret; -} - -static void virtnet_cpu_notif_remove(struct virtnet_info *vi) -{ - cpuhp_state_remove_instance_nocalls(virtionet_online, &vi->node); - cpuhp_state_remove_instance_nocalls(CPUHP_VIRT_NET_DEAD, - &vi->node_dead); -} - -static void virtnet_get_ringparam(struct net_device *dev, - struct ethtool_ringparam *ring) -{ - struct virtnet_info *vi = netdev_priv(dev); - - ring->rx_max_pending = virtqueue_get_vring_size(vi->rq[0].vq); - ring->tx_max_pending = virtqueue_get_vring_size(vi->sq[0].vq); - ring->rx_pending = ring->rx_max_pending; - ring->tx_pending = ring->tx_max_pending; -} - - -static void virtnet_get_drvinfo(struct net_device *dev, - struct ethtool_drvinfo *info) -{ - struct virtnet_info *vi = netdev_priv(dev); - struct virtio_device *vdev = vi->vdev; - - strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver)); - strlcpy(info->version, VIRTNET_DRIVER_VERSION, sizeof(info->version)); - strlcpy(info->bus_info, virtio_bus_name(vdev), sizeof(info->bus_info)); - -} - -/* TODO: Eliminate OOO packets during switching */ -static int virtnet_set_channels(struct net_device *dev, - struct ethtool_channels *channels) -{ - struct virtnet_info *vi = netdev_priv(dev); - u16 queue_pairs = channels->combined_count; - int err; - - /* We don't support separate rx/tx channels. - * We don't allow setting 'other' channels. - */ - if (channels->rx_count || channels->tx_count || channels->other_count) - return -EINVAL; - - if (queue_pairs > vi->max_queue_pairs || queue_pairs == 0) - return -EINVAL; - - get_online_cpus(); - err = virtnet_set_queues(vi, queue_pairs); - if (!err) { - netif_set_real_num_tx_queues(dev, queue_pairs); - netif_set_real_num_rx_queues(dev, queue_pairs); - - virtnet_set_affinity(vi); - } - put_online_cpus(); - - return err; -} - -static void virtnet_get_channels(struct net_device *dev, - struct ethtool_channels *channels) -{ - struct virtnet_info *vi = netdev_priv(dev); - - channels->combined_count = vi->curr_queue_pairs; - channels->max_combined = vi->max_queue_pairs; - channels->max_other = 0; - channels->rx_count = 0; - channels->tx_count = 0; - channels->other_count = 0; -} - -/* Check if the user is trying to change anything besides speed/duplex */ -static bool virtnet_validate_ethtool_cmd(const struct ethtool_cmd *cmd) -{ - struct ethtool_cmd diff1 = *cmd; - struct ethtool_cmd diff2 = {}; - - /* cmd is always set so we need to clear it, validate the port type - * and also without autonegotiation we can ignore advertising - */ - ethtool_cmd_speed_set(&diff1, 0); - diff2.port = PORT_OTHER; - diff1.advertising = 0; - diff1.duplex = 0; - diff1.cmd = 0; - - return !memcmp(&diff1, &diff2, sizeof(diff1)); -} - -static int virtnet_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct virtnet_info *vi = netdev_priv(dev); - u32 speed; - - speed = ethtool_cmd_speed(cmd); - /* don't allow custom speed and duplex */ - if (!ethtool_validate_speed(speed) || - !ethtool_validate_duplex(cmd->duplex) || - !virtnet_validate_ethtool_cmd(cmd)) - return -EINVAL; - vi->speed = speed; - vi->duplex = cmd->duplex; - - return 0; -} - -static int virtnet_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) -{ - struct virtnet_info *vi = netdev_priv(dev); - - ethtool_cmd_speed_set(cmd, vi->speed); - cmd->duplex = vi->duplex; - cmd->port = PORT_OTHER; - - return 0; -} - -static void virtnet_init_settings(struct net_device *dev) -{ - struct virtnet_info *vi = netdev_priv(dev); - - vi->speed = SPEED_UNKNOWN; - vi->duplex = DUPLEX_UNKNOWN; -} - -static const struct ethtool_ops virtnet_ethtool_ops = { - .get_drvinfo = virtnet_get_drvinfo, - .get_link = ethtool_op_get_link, - .get_ringparam = virtnet_get_ringparam, - .set_channels = virtnet_set_channels, - .get_channels = virtnet_get_channels, - .get_ts_info = ethtool_op_get_ts_info, - .get_settings = virtnet_get_settings, - .set_settings = virtnet_set_settings, -}; - -#define MIN_MTU 68 -#define MAX_MTU 65535 - -static int virtnet_change_mtu(struct net_device *dev, int new_mtu) -{ - if (new_mtu < MIN_MTU || new_mtu > MAX_MTU) - return -EINVAL; - dev->mtu = new_mtu; - return 0; -} - -static const struct net_device_ops virtnet_netdev = { - .ndo_open = virtnet_open, - .ndo_stop = virtnet_close, - .ndo_start_xmit = start_xmit, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = virtnet_set_mac_address, - .ndo_set_rx_mode = virtnet_set_rx_mode, - .ndo_change_mtu = virtnet_change_mtu, - .ndo_get_stats64 = virtnet_stats, - .ndo_vlan_rx_add_vid = virtnet_vlan_rx_add_vid, - .ndo_vlan_rx_kill_vid = virtnet_vlan_rx_kill_vid, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = virtnet_netpoll, -#endif -#ifdef CONFIG_NET_RX_BUSY_POLL - .ndo_busy_poll = virtnet_busy_poll, -#endif -}; - -static void virtnet_config_changed_work(struct work_struct *work) -{ - struct virtnet_info *vi = - container_of(work, struct virtnet_info, config_work); - u16 v; - - if (virtio_cread_feature(vi->vdev, VIRTIO_NET_F_STATUS, - struct virtio_net_config, status, &v) < 0) - return; - - if (v & VIRTIO_NET_S_ANNOUNCE) { - netdev_notify_peers(vi->dev); - virtnet_ack_link_announce(vi); - } - - /* Ignore unknown (future) status bits */ - v &= VIRTIO_NET_S_LINK_UP; - - if (vi->status == v) - return; - - vi->status = v; - - if (vi->status & VIRTIO_NET_S_LINK_UP) { - netif_carrier_on(vi->dev); - netif_tx_wake_all_queues(vi->dev); - } else { - netif_carrier_off(vi->dev); - netif_tx_stop_all_queues(vi->dev); - } -} - -static void virtnet_config_changed(struct virtio_device *vdev) -{ - struct virtnet_info *vi = vdev->priv; - - schedule_work(&vi->config_work); -} - -static void virtnet_free_queues(struct virtnet_info *vi) -{ - int i; - - for (i = 0; i < vi->max_queue_pairs; i++) { - napi_hash_del(&vi->rq[i].napi); - netif_napi_del(&vi->rq[i].napi); - } - - /* We called napi_hash_del() before netif_napi_del(), - * we need to respect an RCU grace period before freeing vi->rq - */ - synchronize_net(); - - kfree(vi->rq); - kfree(vi->sq); -} - -static void free_receive_bufs(struct virtnet_info *vi) -{ - int i; - - for (i = 0; i < vi->max_queue_pairs; i++) { - while (vi->rq[i].pages) - __free_pages(get_a_page(&vi->rq[i], GFP_KERNEL), 0); - } -} - -static void free_receive_page_frags(struct virtnet_info *vi) -{ - int i; - for (i = 0; i < vi->max_queue_pairs; i++) - if (vi->rq[i].alloc_frag.page) - put_page(vi->rq[i].alloc_frag.page); -} - -static void free_unused_bufs(struct virtnet_info *vi) -{ - void *buf; - int i; - - for (i = 0; i < vi->max_queue_pairs; i++) { - struct virtqueue *vq = vi->sq[i].vq; - while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) - dev_kfree_skb(buf); - } - - for (i = 0; i < vi->max_queue_pairs; i++) { - struct virtqueue *vq = vi->rq[i].vq; - - while ((buf = virtqueue_detach_unused_buf(vq)) != NULL) { - if (vi->mergeable_rx_bufs) { - unsigned long ctx = (unsigned long)buf; - void *base = mergeable_ctx_to_buf_address(ctx); - put_page(virt_to_head_page(base)); - } else if (vi->big_packets) { - give_pages(&vi->rq[i], buf); - } else { - dev_kfree_skb(buf); - } - } - } -} - -static void virtnet_del_vqs(struct virtnet_info *vi) -{ - struct virtio_device *vdev = vi->vdev; - - virtnet_clean_affinity(vi, -1); - - vdev->config->del_vqs(vdev); - - virtnet_free_queues(vi); -} - -static int virtnet_find_vqs(struct virtnet_info *vi) -{ - vq_callback_t **callbacks; - struct virtqueue **vqs; - int ret = -ENOMEM; - int i, total_vqs; - const char **names; - - /* We expect 1 RX virtqueue followed by 1 TX virtqueue, followed by - * possible N-1 RX/TX queue pairs used in multiqueue mode, followed by - * possible control vq. - */ - total_vqs = vi->max_queue_pairs * 2 + - virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VQ); - - /* Allocate space for find_vqs parameters */ - vqs = kzalloc(total_vqs * sizeof(*vqs), GFP_KERNEL); - if (!vqs) - goto err_vq; - callbacks = kmalloc(total_vqs * sizeof(*callbacks), GFP_KERNEL); - if (!callbacks) - goto err_callback; - names = kmalloc(total_vqs * sizeof(*names), GFP_KERNEL); - if (!names) - goto err_names; - - /* Parameters for control virtqueue, if any */ - if (vi->has_cvq) { - callbacks[total_vqs - 1] = NULL; - names[total_vqs - 1] = "control"; - } - - /* Allocate/initialize parameters for send/receive virtqueues */ - for (i = 0; i < vi->max_queue_pairs; i++) { - callbacks[rxq2vq(i)] = skb_recv_done; - callbacks[txq2vq(i)] = skb_xmit_done; - sprintf(vi->rq[i].name, "input.%d", i); - sprintf(vi->sq[i].name, "output.%d", i); - names[rxq2vq(i)] = vi->rq[i].name; - names[txq2vq(i)] = vi->sq[i].name; - } - - ret = vi->vdev->config->find_vqs(vi->vdev, total_vqs, vqs, callbacks, - names); - if (ret) - goto err_find; - - if (vi->has_cvq) { - vi->cvq = vqs[total_vqs - 1]; - if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_CTRL_VLAN)) - vi->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; - } - - for (i = 0; i < vi->max_queue_pairs; i++) { - vi->rq[i].vq = vqs[rxq2vq(i)]; - vi->sq[i].vq = vqs[txq2vq(i)]; - } - - kfree(names); - kfree(callbacks); - kfree(vqs); - - return 0; - -err_find: - kfree(names); -err_names: - kfree(callbacks); -err_callback: - kfree(vqs); -err_vq: - return ret; -} - -static int virtnet_alloc_queues(struct virtnet_info *vi) -{ - int i; - - vi->sq = kzalloc(sizeof(*vi->sq) * vi->max_queue_pairs, GFP_KERNEL); - if (!vi->sq) - goto err_sq; - vi->rq = kzalloc(sizeof(*vi->rq) * vi->max_queue_pairs, GFP_KERNEL); - if (!vi->rq) - goto err_rq; - - INIT_DELAYED_WORK(&vi->refill, refill_work); - for (i = 0; i < vi->max_queue_pairs; i++) { - vi->rq[i].pages = NULL; - netif_napi_add(vi->dev, &vi->rq[i].napi, virtnet_poll, - napi_weight); - - sg_init_table(vi->rq[i].sg, ARRAY_SIZE(vi->rq[i].sg)); - ewma_pkt_len_init(&vi->rq[i].mrg_avg_pkt_len); - sg_init_table(vi->sq[i].sg, ARRAY_SIZE(vi->sq[i].sg)); - } - - return 0; - -err_rq: - kfree(vi->sq); -err_sq: - return -ENOMEM; -} - -static int init_vqs(struct virtnet_info *vi) -{ - int ret; - - /* Allocate send & receive queues */ - ret = virtnet_alloc_queues(vi); - if (ret) - goto err; - - ret = virtnet_find_vqs(vi); - if (ret) - goto err_free; - - get_online_cpus(); - virtnet_set_affinity(vi); - put_online_cpus(); - - return 0; - -err_free: - virtnet_free_queues(vi); -err: - return ret; -} - -#ifdef CONFIG_SYSFS -static ssize_t mergeable_rx_buffer_size_show(struct netdev_rx_queue *queue, - struct rx_queue_attribute *attribute, char *buf) -{ - struct virtnet_info *vi = netdev_priv(queue->dev); - unsigned int queue_index = get_netdev_rx_queue_index(queue); - struct ewma_pkt_len *avg; - - BUG_ON(queue_index >= vi->max_queue_pairs); - avg = &vi->rq[queue_index].mrg_avg_pkt_len; - return sprintf(buf, "%u\n", get_mergeable_buf_len(avg)); -} - -static struct rx_queue_attribute mergeable_rx_buffer_size_attribute = - __ATTR_RO(mergeable_rx_buffer_size); - -static struct attribute *virtio_net_mrg_rx_attrs[] = { - &mergeable_rx_buffer_size_attribute.attr, - NULL -}; - -static const struct attribute_group virtio_net_mrg_rx_group = { - .name = "virtio_net", - .attrs = virtio_net_mrg_rx_attrs -}; -#endif - -static bool virtnet_fail_on_feature(struct virtio_device *vdev, - unsigned int fbit, - const char *fname, const char *dname) -{ - if (!virtio_has_feature(vdev, fbit)) - return false; - - dev_err(&vdev->dev, "device advertises feature %s but not %s", - fname, dname); - - return true; -} - -#define VIRTNET_FAIL_ON(vdev, fbit, dbit) \ - virtnet_fail_on_feature(vdev, fbit, #fbit, dbit) - -static bool virtnet_validate_features(struct virtio_device *vdev) -{ - if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ) && - (VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_RX, - "VIRTIO_NET_F_CTRL_VQ") || - VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_VLAN, - "VIRTIO_NET_F_CTRL_VQ") || - VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE, - "VIRTIO_NET_F_CTRL_VQ") || - VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_MQ, "VIRTIO_NET_F_CTRL_VQ") || - VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR, - "VIRTIO_NET_F_CTRL_VQ"))) { - return false; - } - - return true; -} - -static int virtnet_probe(struct virtio_device *vdev) -{ - int i, err; - struct net_device *dev; - struct virtnet_info *vi; - u16 max_queue_pairs; - int mtu; - - if (!vdev->config->get) { - dev_err(&vdev->dev, "%s failure: config access disabled\n", - __func__); - return -EINVAL; - } - - if (!virtnet_validate_features(vdev)) - return -EINVAL; - - /* Find if host supports multiqueue virtio_net device */ - err = virtio_cread_feature(vdev, VIRTIO_NET_F_MQ, - struct virtio_net_config, - max_virtqueue_pairs, &max_queue_pairs); - - /* We need at least 2 queue's */ - if (err || max_queue_pairs < VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN || - max_queue_pairs > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX || - !virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) - max_queue_pairs = 1; - - /* Allocate ourselves a network device with room for our info */ - dev = alloc_etherdev_mq(sizeof(struct virtnet_info), max_queue_pairs); - if (!dev) - return -ENOMEM; - - /* Set up network device as normal. */ - dev->priv_flags |= IFF_UNICAST_FLT | IFF_LIVE_ADDR_CHANGE; - dev->netdev_ops = &virtnet_netdev; - dev->features = NETIF_F_HIGHDMA; - - dev->ethtool_ops = &virtnet_ethtool_ops; - SET_NETDEV_DEV(dev, &vdev->dev); - - /* Do we support "hardware" checksums? */ - if (virtio_has_feature(vdev, VIRTIO_NET_F_CSUM)) { - /* This opens up the world of extra features. */ - dev->hw_features |= NETIF_F_HW_CSUM | NETIF_F_SG; - if (csum) - dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; - - if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) { - dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO - | NETIF_F_TSO_ECN | NETIF_F_TSO6; - } - /* Individual feature bits: what can host handle? */ - if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO4)) - dev->hw_features |= NETIF_F_TSO; - if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_TSO6)) - dev->hw_features |= NETIF_F_TSO6; - if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN)) - dev->hw_features |= NETIF_F_TSO_ECN; - if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO)) - dev->hw_features |= NETIF_F_UFO; - - dev->features |= NETIF_F_GSO_ROBUST; - - if (gso) - dev->features |= dev->hw_features & (NETIF_F_ALL_TSO|NETIF_F_UFO); - /* (!csum && gso) case will be fixed by register_netdev() */ - } - if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM)) - dev->features |= NETIF_F_RXCSUM; - - dev->vlan_features = dev->features; - - /* Configuration may specify what MAC to use. Otherwise random. */ - if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) - virtio_cread_bytes(vdev, - offsetof(struct virtio_net_config, mac), - dev->dev_addr, dev->addr_len); - else - eth_hw_addr_random(dev); - - /* Set up our device-specific information */ - vi = netdev_priv(dev); - vi->dev = dev; - vi->vdev = vdev; - vdev->priv = vi; - vi->stats = alloc_percpu(struct virtnet_stats); - err = -ENOMEM; - if (vi->stats == NULL) - goto free; - - for_each_possible_cpu(i) { - struct virtnet_stats *virtnet_stats; - virtnet_stats = per_cpu_ptr(vi->stats, i); - u64_stats_init(&virtnet_stats->tx_syncp); - u64_stats_init(&virtnet_stats->rx_syncp); - } - - INIT_WORK(&vi->config_work, virtnet_config_changed_work); - - /* If we can receive ANY GSO packets, we must allocate large ones. */ - if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) || - virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) || - virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) || - virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO)) - vi->big_packets = true; - - if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) - vi->mergeable_rx_bufs = true; - - if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) || - virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) - vi->hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf); - else - vi->hdr_len = sizeof(struct virtio_net_hdr); - - if (virtio_has_feature(vdev, VIRTIO_F_ANY_LAYOUT) || - virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) - vi->any_header_sg = true; - - if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ)) - vi->has_cvq = true; - - if (virtio_has_feature(vdev, VIRTIO_NET_F_MTU)) { - mtu = virtio_cread16(vdev, - offsetof(struct virtio_net_config, - mtu)); - if (virtnet_change_mtu(dev, mtu)) - __virtio_clear_bit(vdev, VIRTIO_NET_F_MTU); - } - - if (vi->any_header_sg) - dev->needed_headroom = vi->hdr_len; - - /* Use single tx/rx queue pair as default */ - vi->curr_queue_pairs = 1; - vi->max_queue_pairs = max_queue_pairs; - - /* Allocate/initialize the rx/tx queues, and invoke find_vqs */ - err = init_vqs(vi); - if (err) - goto free_stats; - -#ifdef CONFIG_SYSFS - if (vi->mergeable_rx_bufs) - dev->sysfs_rx_queue_group = &virtio_net_mrg_rx_group; -#endif - netif_set_real_num_tx_queues(dev, vi->curr_queue_pairs); - netif_set_real_num_rx_queues(dev, vi->curr_queue_pairs); - - virtnet_init_settings(dev); - - err = register_netdev(dev); - if (err) { - pr_debug("virtio_net: registering device failed\n"); - goto free_vqs; - } - - virtio_device_ready(vdev); - - err = virtnet_cpu_notif_add(vi); - if (err) { - pr_debug("virtio_net: registering cpu notifier failed\n"); - goto free_unregister_netdev; - } - - /* Assume link up if device can't report link status, - otherwise get link status from config. */ - if (virtio_has_feature(vi->vdev, VIRTIO_NET_F_STATUS)) { - netif_carrier_off(dev); - schedule_work(&vi->config_work); - } else { - vi->status = VIRTIO_NET_S_LINK_UP; - netif_carrier_on(dev); - } - - pr_debug("virtnet: registered device %s with %d RX and TX vq's\n", - dev->name, max_queue_pairs); - - return 0; - -free_unregister_netdev: - vi->vdev->config->reset(vdev); - - unregister_netdev(dev); -free_vqs: - cancel_delayed_work_sync(&vi->refill); - free_receive_page_frags(vi); - virtnet_del_vqs(vi); -free_stats: - free_percpu(vi->stats); -free: - free_netdev(dev); - return err; -} - -static void remove_vq_common(struct virtnet_info *vi) -{ - vi->vdev->config->reset(vi->vdev); - - /* Free unused buffers in both send and recv, if any. */ - free_unused_bufs(vi); - - free_receive_bufs(vi); - - free_receive_page_frags(vi); - - virtnet_del_vqs(vi); -} - -static void virtnet_remove(struct virtio_device *vdev) -{ - struct virtnet_info *vi = vdev->priv; - - virtnet_cpu_notif_remove(vi); - - /* Make sure no work handler is accessing the device. */ - flush_work(&vi->config_work); - - unregister_netdev(vi->dev); - - remove_vq_common(vi); - - free_percpu(vi->stats); - free_netdev(vi->dev); -} - -#ifdef CONFIG_PM_SLEEP -static int virtnet_freeze(struct virtio_device *vdev) -{ - struct virtnet_info *vi = vdev->priv; - int i; - - virtnet_cpu_notif_remove(vi); - - /* Make sure no work handler is accessing the device */ - flush_work(&vi->config_work); - - netif_device_detach(vi->dev); - cancel_delayed_work_sync(&vi->refill); - - if (netif_running(vi->dev)) { - for (i = 0; i < vi->max_queue_pairs; i++) - napi_disable(&vi->rq[i].napi); - } - - remove_vq_common(vi); - - return 0; -} - -static int virtnet_restore(struct virtio_device *vdev) -{ - struct virtnet_info *vi = vdev->priv; - int err, i; - - err = init_vqs(vi); - if (err) - return err; - - virtio_device_ready(vdev); - - if (netif_running(vi->dev)) { - for (i = 0; i < vi->curr_queue_pairs; i++) - if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL)) - schedule_delayed_work(&vi->refill, 0); - - for (i = 0; i < vi->max_queue_pairs; i++) - virtnet_napi_enable(&vi->rq[i]); - } - - netif_device_attach(vi->dev); - - rtnl_lock(); - virtnet_set_queues(vi, vi->curr_queue_pairs); - rtnl_unlock(); - - err = virtnet_cpu_notif_add(vi); - if (err) - return err; - - return 0; -} -#endif - -static struct virtio_device_id id_table[] = { - { VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID }, - { 0 }, -}; - -#define VIRTNET_FEATURES \ - VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM, \ - VIRTIO_NET_F_MAC, \ - VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, \ - VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, \ - VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO, \ - VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ, \ - VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN, \ - VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ, \ - VIRTIO_NET_F_CTRL_MAC_ADDR, \ - VIRTIO_NET_F_MTU - -static unsigned int features[] = { - VIRTNET_FEATURES, -}; - -static unsigned int features_legacy[] = { - VIRTNET_FEATURES, - VIRTIO_NET_F_GSO, - VIRTIO_F_ANY_LAYOUT, -}; - -static struct virtio_driver virtio_net_driver = { - .feature_table = features, - .feature_table_size = ARRAY_SIZE(features), - .feature_table_legacy = features_legacy, - .feature_table_size_legacy = ARRAY_SIZE(features_legacy), - .driver.name = KBUILD_MODNAME, - .driver.owner = THIS_MODULE, - .id_table = id_table, - .probe = virtnet_probe, - .remove = virtnet_remove, - .config_changed = virtnet_config_changed, -#ifdef CONFIG_PM_SLEEP - .freeze = virtnet_freeze, - .restore = virtnet_restore, -#endif -}; - -static __init int virtio_net_driver_init(void) -{ - int ret; - - ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, "AP_VIRT_NET_ONLINE", - virtnet_cpu_online, - virtnet_cpu_down_prep); - if (ret < 0) - goto out; - virtionet_online = ret; - ret = cpuhp_setup_state_multi(CPUHP_VIRT_NET_DEAD, "VIRT_NET_DEAD", - NULL, virtnet_cpu_dead); - if (ret) - goto err_dead; - - ret = register_virtio_driver(&virtio_net_driver); - if (ret) - goto err_virtio; - return 0; -err_virtio: - cpuhp_remove_multi_state(CPUHP_VIRT_NET_DEAD); -err_dead: - cpuhp_remove_multi_state(virtionet_online); -out: - return ret; -} -module_init(virtio_net_driver_init); - -static __exit void virtio_net_driver_exit(void) -{ - cpuhp_remove_multi_state(CPUHP_VIRT_NET_DEAD); - cpuhp_remove_multi_state(virtionet_online); - unregister_virtio_driver(&virtio_net_driver); -} -module_exit(virtio_net_driver_exit); - -MODULE_DEVICE_TABLE(virtio, id_table); -MODULE_DESCRIPTION("Virtio network driver"); -MODULE_LICENSE("GPL"); diff --git a/src/linux/drivers/net/wan/.gitignore b/src/linux/drivers/net/wan/.gitignore deleted file mode 100644 index dae3ea6..0000000 --- a/src/linux/drivers/net/wan/.gitignore +++ /dev/null @@ -1 +0,0 @@ -wanxlfw.inc diff --git a/src/linux/drivers/net/wan/Kconfig b/src/linux/drivers/net/wan/Kconfig deleted file mode 100644 index 4e9fe75..0000000 --- a/src/linux/drivers/net/wan/Kconfig +++ /dev/null @@ -1,441 +0,0 @@ -# -# wan devices configuration -# - -menuconfig WAN - bool "Wan interfaces support" - ---help--- - Wide Area Networks (WANs), such as X.25, Frame Relay and leased - lines, are used to interconnect Local Area Networks (LANs) over vast - distances with data transfer rates significantly higher than those - achievable with commonly used asynchronous modem connections. - - Usually, a quite expensive external device called a `WAN router' is - needed to connect to a WAN. As an alternative, a relatively - inexpensive WAN interface card can allow your Linux box to directly - connect to a WAN. - - If you have one of those cards and wish to use it under Linux, - say Y here and also to the WAN driver for your card. - - If unsure, say N. - -if WAN - -# There is no way to detect a comtrol sv11 - force it modular for now. -config HOSTESS_SV11 - tristate "Comtrol Hostess SV-11 support" - depends on ISA && m && ISA_DMA_API && INET && HDLC && VIRT_TO_BUS - help - Driver for Comtrol Hostess SV-11 network card which - operates on low speed synchronous serial links at up to - 256Kbps, supporting PPP and Cisco HDLC. - - The driver will be compiled as a module: the - module will be called hostess_sv11. - -# The COSA/SRP driver has not been tested as non-modular yet. -config COSA - tristate "COSA/SRP sync serial boards support" - depends on ISA && m && ISA_DMA_API && HDLC && VIRT_TO_BUS - ---help--- - Driver for COSA and SRP synchronous serial boards. - - These boards allow to connect synchronous serial devices (for example - base-band modems, or any other device with the X.21, V.24, V.35 or - V.36 interface) to your Linux box. The cards can work as the - character device, synchronous PPP network device, or the Cisco HDLC - network device. - - You will need user-space utilities COSA or SRP boards for downloading - the firmware to the cards and to set them up. Look at the - for more information. You can also - read the comment at the top of the for - details about the cards and the driver itself. - - The driver will be compiled as a module: the - module will be called cosa. - -# -# Lan Media's board. Currently 1000, 1200, 5200, 5245 -# -config LANMEDIA - tristate "LanMedia Corp. SSI/V.35, T1/E1, HSSI, T3 boards" - depends on PCI && VIRT_TO_BUS && HDLC - ---help--- - Driver for the following Lan Media family of serial boards: - - - LMC 1000 board allows you to connect synchronous serial devices - (for example base-band modems, or any other device with the X.21, - V.24, V.35 or V.36 interface) to your Linux box. - - - LMC 1200 with on board DSU board allows you to connect your Linux - box directly to a T1 or E1 circuit. - - - LMC 5200 board provides a HSSI interface capable of running up to - 52 Mbits per second. - - - LMC 5245 board connects directly to a T3 circuit saving the - additional external hardware. - - To change setting such as clock source you will need lmcctl. - It is available at (broken link). - - To compile this driver as a module, choose M here: the - module will be called lmc. - -# There is no way to detect a Sealevel board. Force it modular -config SEALEVEL_4021 - tristate "Sealevel Systems 4021 support" - depends on ISA && m && ISA_DMA_API && INET && HDLC && VIRT_TO_BUS - help - This is a driver for the Sealevel Systems ACB 56 serial I/O adapter. - - The driver will be compiled as a module: the - module will be called sealevel. - -# Generic HDLC -config HDLC - tristate "Generic HDLC layer" - help - Say Y to this option if your Linux box contains a WAN (Wide Area - Network) card supported by this driver and you are planning to - connect the box to a WAN. - - You will need supporting software from - . - Generic HDLC driver currently supports raw HDLC, Cisco HDLC, Frame - Relay, synchronous Point-to-Point Protocol (PPP) and X.25. - - To compile this driver as a module, choose M here: the - module will be called hdlc. - - If unsure, say N. - -config HDLC_RAW - tristate "Raw HDLC support" - depends on HDLC - help - Generic HDLC driver supporting raw HDLC over WAN connections. - - If unsure, say N. - -config HDLC_RAW_ETH - tristate "Raw HDLC Ethernet device support" - depends on HDLC - help - Generic HDLC driver supporting raw HDLC Ethernet device emulation - over WAN connections. - - You will need it for Ethernet over HDLC bridges. - - If unsure, say N. - -config HDLC_CISCO - tristate "Cisco HDLC support" - depends on HDLC - help - Generic HDLC driver supporting Cisco HDLC over WAN connections. - - If unsure, say N. - -config HDLC_FR - tristate "Frame Relay support" - depends on HDLC - help - Generic HDLC driver supporting Frame Relay over WAN connections. - - If unsure, say N. - -config HDLC_PPP - tristate "Synchronous Point-to-Point Protocol (PPP) support" - depends on HDLC - help - Generic HDLC driver supporting PPP over WAN connections. - - If unsure, say N. - -config HDLC_X25 - tristate "X.25 protocol support" - depends on HDLC && (LAPB=m && HDLC=m || LAPB=y) - help - Generic HDLC driver supporting X.25 over WAN connections. - - If unsure, say N. - -comment "X.25/LAPB support is disabled" - depends on HDLC && (LAPB!=m || HDLC!=m) && LAPB!=y - -config PCI200SYN - tristate "Goramo PCI200SYN support" - depends on HDLC && PCI - help - Driver for PCI200SYN cards by Goramo sp. j. - - If you have such a card, say Y here and see - . - - To compile this as a module, choose M here: the - module will be called pci200syn. - - If unsure, say N. - -config WANXL - tristate "SBE Inc. wanXL support" - depends on HDLC && PCI - help - Driver for wanXL PCI cards by SBE Inc. - - If you have such a card, say Y here and see - . - - To compile this as a module, choose M here: the - module will be called wanxl. - - If unsure, say N. - -config WANXL_BUILD_FIRMWARE - bool "rebuild wanXL firmware" - depends on WANXL && !PREVENT_FIRMWARE_BUILD - help - Allows you to rebuild firmware run by the QUICC processor. - It requires as68k, ld68k and hexdump programs. - - You should never need this option, say N. - -config PC300TOO - tristate "Cyclades PC300 RSV/X21 alternative support" - depends on HDLC && PCI - help - Alternative driver for PC300 RSV/X21 PCI cards made by - Cyclades, Inc. If you have such a card, say Y here and see - . - - To compile this as a module, choose M here: the module - will be called pc300too. - - If unsure, say N here. - -config N2 - tristate "SDL RISCom/N2 support" - depends on HDLC && ISA - help - Driver for RISCom/N2 single or dual channel ISA cards by - SDL Communications Inc. - - If you have such a card, say Y here and see - . - - Note that N2csu and N2dds cards are not supported by this driver. - - To compile this driver as a module, choose M here: the module - will be called n2. - - If unsure, say N. - -config C101 - tristate "Moxa C101 support" - depends on HDLC && ISA - help - Driver for C101 SuperSync ISA cards by Moxa Technologies Co., Ltd. - - If you have such a card, say Y here and see - . - - To compile this driver as a module, choose M here: the - module will be called c101. - - If unsure, say N. - -config FARSYNC - tristate "FarSync T-Series support" - depends on HDLC && PCI - ---help--- - Support for the FarSync T-Series X.21 (and V.35/V.24) cards by - FarSite Communications Ltd. - - Synchronous communication is supported on all ports at speeds up to - 8Mb/s (128K on V.24) using synchronous PPP, Cisco HDLC, raw HDLC, - Frame Relay or X.25/LAPB. - - If you want the module to be automatically loaded when the interface - is referenced then you should add "alias hdlcX farsync" to a file - in /etc/modprobe.d/ for each interface, where X is 0, 1, 2, ..., or - simply use "alias hdlc* farsync" to indicate all of them. - - To compile this driver as a module, choose M here: the - module will be called farsync. - -config DSCC4 - tristate "Etinc PCISYNC serial board support" - depends on HDLC && PCI && m - help - Driver for Etinc PCISYNC boards based on the Infineon (ex. Siemens) - DSCC4 chipset. - - This is supposed to work with the four port card. Take a look at - for further information about the - driver. - - To compile this driver as a module, choose M here: the - module will be called dscc4. - -config FSL_UCC_HDLC - tristate "Freescale QUICC Engine HDLC support" - depends on HDLC - depends on QUICC_ENGINE - help - Driver for Freescale QUICC Engine HDLC controller. The driver - supports HDLC in NMSI and TDM mode. - - To compile this driver as a module, choose M here: the - module will be called fsl_ucc_hdlc. - -config SLIC_DS26522 - tristate "Slic Maxim ds26522 card support" - depends on SPI - depends on FSL_SOC || ARCH_MXC || ARCH_LAYERSCAPE || COMPILE_TEST - help - This module initializes and configures the slic maxim card - in T1 or E1 mode. - - To compile this driver as a module, choose M here: the - module will be called slic_ds26522. - -config DSCC4_PCISYNC - bool "Etinc PCISYNC features" - depends on DSCC4 - help - Due to Etinc's design choice for its PCISYNC cards, some operations - are only allowed on specific ports of the DSCC4. This option is the - only way for the driver to know that it shouldn't return a success - code for these operations. - - Please say Y if your card is an Etinc's PCISYNC. - -config DSCC4_PCI_RST - bool "Hard reset support" - depends on DSCC4 - help - Various DSCC4 bugs forbid any reliable software reset of the ASIC. - As a replacement, some vendors provide a way to assert the PCI #RST - pin of DSCC4 through the GPIO port of the card. If you choose Y, - the driver will make use of this feature before module removal - (i.e. rmmod). The feature is known to be available on Commtech's - cards. Contact your manufacturer for details. - - Say Y if your card supports this feature. - -config IXP4XX_HSS - tristate "Intel IXP4xx HSS (synchronous serial port) support" - depends on HDLC && ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR - help - Say Y here if you want to use built-in HSS ports - on IXP4xx processor. - -config DLCI - tristate "Frame Relay DLCI support" - ---help--- - Support for the Frame Relay protocol. - - Frame Relay is a fast low-cost way to connect to a remote Internet - access provider or to form a private wide area network. The one - physical line from your box to the local "switch" (i.e. the entry - point to the Frame Relay network, usually at the phone company) can - carry several logical point-to-point connections to other computers - connected to the Frame Relay network. For a general explanation of - the protocol, check out . - - To use frame relay, you need supporting hardware (called FRAD) and - certain programs from the net-tools package as explained in - . - - To compile this driver as a module, choose M here: the - module will be called dlci. - -config DLCI_MAX - int "Max DLCI per device" - depends on DLCI - default "8" - help - How many logical point-to-point frame relay connections (the - identifiers of which are called DCLIs) should be handled by each - of your hardware frame relay access devices. - - Go with the default. - -config SDLA - tristate "SDLA (Sangoma S502/S508) support" - depends on DLCI && ISA - help - Driver for the Sangoma S502A, S502E, and S508 Frame Relay Access - Devices. - - These are multi-protocol cards, but only Frame Relay is supported - by the driver at this time. Please read - . - - To compile this driver as a module, choose M here: the - module will be called sdla. - -# X.25 network drivers -config LAPBETHER - tristate "LAPB over Ethernet driver" - depends on LAPB && X25 - ---help--- - Driver for a pseudo device (typically called /dev/lapb0) which allows - you to open an LAPB point-to-point connection to some other computer - on your Ethernet network. - - In order to do this, you need to say Y or M to the driver for your - Ethernet card as well as to "LAPB Data Link Driver". - - To compile this driver as a module, choose M here: the - module will be called lapbether. - - If unsure, say N. - -config X25_ASY - tristate "X.25 async driver" - depends on LAPB && X25 && TTY - ---help--- - Send and receive X.25 frames over regular asynchronous serial - lines such as telephone lines equipped with ordinary modems. - - Experts should note that this driver doesn't currently comply with - the asynchronous HDLS framing protocols in CCITT recommendation X.25. - - To compile this driver as a module, choose M here: the - module will be called x25_asy. - - If unsure, say N. - -config SBNI - tristate "Granch SBNI12 Leased Line adapter support" - depends on X86 - ---help--- - Driver for ISA SBNI12-xx cards which are low cost alternatives to - leased line modems. - - You can find more information and last versions of drivers and - utilities at . If you have any question you - can send email to . - - To compile this driver as a module, choose M here: the - module will be called sbni. - - If unsure, say N. - -config SBNI_MULTILINE - bool "Multiple line feature support" - depends on SBNI - help - Schedule traffic for some parallel lines, via SBNI12 adapters. - - If you have two computers connected with two parallel lines it's - possible to increase transfer rate nearly twice. You should have - a program named 'sbniconfig' to configure adapters. - - If unsure, say N. - -endif # WAN diff --git a/src/linux/drivers/net/wimax/Kconfig b/src/linux/drivers/net/wimax/Kconfig deleted file mode 100644 index 565018e..0000000 --- a/src/linux/drivers/net/wimax/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -# -# WiMAX LAN device drivers configuration -# - - -comment "Enable WiMAX (Networking options) to see the WiMAX drivers" - depends on WIMAX = n - -if WIMAX - -menu "WiMAX Wireless Broadband devices" - -source "drivers/net/wimax/i2400m/Kconfig" - -endmenu - -endif diff --git a/src/linux/drivers/net/wimax/i2400m/Kconfig b/src/linux/drivers/net/wimax/i2400m/Kconfig deleted file mode 100644 index 71453db..0000000 --- a/src/linux/drivers/net/wimax/i2400m/Kconfig +++ /dev/null @@ -1,36 +0,0 @@ - -config WIMAX_I2400M - tristate - depends on WIMAX - select FW_LOADER - -comment "Enable USB support to see WiMAX USB drivers" - depends on USB = n - -config WIMAX_I2400M_USB - tristate "Intel Wireless WiMAX Connection 2400 over USB (including 5x50)" - depends on WIMAX && USB - select WIMAX_I2400M - help - Select if you have a device based on the Intel WiMAX - Connection 2400 over USB (like any of the Intel Wireless - WiMAX/WiFi Link 5x50 series). - - If unsure, it is safe to select M (module). - -config WIMAX_I2400M_DEBUG_LEVEL - int "WiMAX i2400m debug level" - depends on WIMAX_I2400M - default 8 - help - - Select the maximum debug verbosity level to be compiled into - the WiMAX i2400m driver code. - - By default, this is disabled at runtime and can be - selectively enabled at runtime for different parts of the - code using the sysfs debug-levels file. - - If set at zero, this will compile out all the debug code. - - It is recommended that it is left at 8. diff --git a/src/linux/drivers/net/wireless/Kconfig b/src/linux/drivers/net/wireless/Kconfig deleted file mode 100644 index 8c8edaf..0000000 --- a/src/linux/drivers/net/wireless/Kconfig +++ /dev/null @@ -1,103 +0,0 @@ -# -# Wireless LAN device configuration -# - -menuconfig WLAN - bool "Wireless LAN" - depends on !S390 - depends on NET - select WIRELESS - default y - ---help--- - This section contains all the pre 802.11 and 802.11 wireless - device drivers. For a complete list of drivers and documentation - on them refer to the wireless wiki: - - http://wireless.kernel.org/en/users/Drivers - -if WLAN - -source "drivers/net/wireless/admtek/Kconfig" -source "drivers/net/wireless/ath/Kconfig" -source "drivers/net/wireless/atmel/Kconfig" -source "drivers/net/wireless/broadcom/Kconfig" -source "drivers/net/wireless/cisco/Kconfig" -source "drivers/net/wireless/intel/Kconfig" -source "drivers/net/wireless/intersil/Kconfig" -source "drivers/net/wireless/marvell/Kconfig" -source "drivers/net/wireless/mediatek/Kconfig" -source "drivers/net/wireless/ralink/Kconfig" -source "drivers/net/wireless/realtek/Kconfig" -source "drivers/net/wireless/rsi/Kconfig" -source "drivers/net/wireless/st/Kconfig" -source "drivers/net/wireless/ti/Kconfig" -source "drivers/net/wireless/zydas/Kconfig" - -config PCMCIA_RAYCS - tristate "Aviator/Raytheon 2.4GHz wireless support" - depends on PCMCIA - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - ---help--- - Say Y here if you intend to attach an Aviator/Raytheon PCMCIA - (PC-card) wireless Ethernet networking card to your computer. - Please read the file for - details. - - To compile this driver as a module, choose M here: the module will be - called ray_cs. If unsure, say N. - -config PCMCIA_WL3501 - tristate "Planet WL3501 PCMCIA cards" - depends on CFG80211 && PCMCIA - select WIRELESS_EXT - select WEXT_SPY - help - A driver for WL3501 PCMCIA 802.11 wireless cards made by Planet. - It has basic support for Linux wireless extensions and initial - micro support for ethtool. - -config MAC80211_HWSIM - tristate "Simulated radio testing tool for mac80211" - depends on MAC80211 - ---help--- - This driver is a developer testing tool that can be used to test - IEEE 802.11 networking stack (mac80211) functionality. This is not - needed for normal wireless LAN usage and is only for testing. See - Documentation/networking/mac80211_hwsim for more information on how - to use this tool. - - To compile this driver as a module, choose M here: the module will be - called mac80211_hwsim. If unsure, say N. - -config USB_NET_RNDIS_WLAN - tristate "Wireless RNDIS USB support" - depends on USB - depends on CFG80211 - select USB_NET_DRIVERS - select USB_USBNET - select USB_NET_CDCETHER - select USB_NET_RNDIS_HOST - ---help--- - This is a driver for wireless RNDIS devices. - These are USB based adapters found in devices such as: - - Buffalo WLI-U2-KG125S - U.S. Robotics USR5421 - Belkin F5D7051 - Linksys WUSB54GSv2 - Linksys WUSB54GSC - Asus WL169gE - Eminent EM4045 - BT Voyager 1055 - Linksys WUSB54GSv1 - U.S. Robotics USR5420 - BUFFALO WLI-USB-G54 - - All of these devices are based on Broadcom 4320 chip which is the - only wireless RNDIS chip known to date. - - If you choose to build a module, it'll be called rndis_wlan. - -endif # WLAN diff --git a/src/linux/drivers/net/wireless/admtek/Kconfig b/src/linux/drivers/net/wireless/admtek/Kconfig deleted file mode 100644 index d5a2dc7..0000000 --- a/src/linux/drivers/net/wireless/admtek/Kconfig +++ /dev/null @@ -1,41 +0,0 @@ -config WLAN_VENDOR_ADMTEK - bool "ADMtek devices" - default y - ---help--- - If you have a wireless card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for - your specific card in the following questions. - -if WLAN_VENDOR_ADMTEK - -config ADM8211 - tristate "ADMtek ADM8211 support" - depends on MAC80211 && PCI - select CRC32 - select EEPROM_93CX6 - ---help--- - This driver is for ADM8211A, ADM8211B, and ADM8211C based cards. - These are PCI/mini-PCI/Cardbus 802.11b chips found in cards such as: - - Xterasys Cardbus XN-2411b - Blitz NetWave Point PC - TrendNet 221pc - Belkin F5D6001 - SMC 2635W - Linksys WPC11 v1 - Fiberline FL-WL-200X - 3com Office Connect (3CRSHPW796) - Corega WLPCIB-11 - SMC 2602W V2 EU - D-Link DWL-520 Revision C - - However, some of these cards have been replaced with other chips - like the RTL8180L (Xterasys Cardbus XN-2411b, Belkin F5D6001) or - the Ralink RT2400 (SMC2635W) without a model number change. - - Thanks to Infineon-ADMtek for their support of this driver. - -endif # WLAN_VENDOR_ADMTEK diff --git a/src/linux/drivers/net/wireless/ath/Kconfig b/src/linux/drivers/net/wireless/ath/Kconfig deleted file mode 100644 index 44b2470..0000000 --- a/src/linux/drivers/net/wireless/ath/Kconfig +++ /dev/null @@ -1,65 +0,0 @@ -config ATH_COMMON - tristate - -config WLAN_VENDOR_ATH - bool "Atheros/Qualcomm devices" - default y - ---help--- - If you have a wireless card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for - your specific card in the following questions. - - For more information and documentation on this module you can visit: - - http://wireless.kernel.org/en/users/Drivers/ath - - For information on all Atheros wireless drivers visit: - - http://wireless.kernel.org/en/users/Drivers/Atheros - -if WLAN_VENDOR_ATH - -config ATH_DEBUG - bool "Atheros wireless debugging" - ---help--- - Say Y, if you want to debug atheros wireless drivers. - Right now only ath9k makes use of this. - -config ATH_TRACEPOINTS - bool "Atheros wireless tracing" - depends on ATH_DEBUG - depends on EVENT_TRACING - ---help--- - This option enables tracepoints for atheros wireless drivers. - Currently, ath9k makes use of this facility. - -config ATH_REG_DYNAMIC_USER_REG_HINTS - bool "Atheros dynamic user regulatory hints" - depends on CFG80211_CERTIFICATION_ONUS - default n - ---help--- - Say N. This should only be enabled in countries where - this feature is explicitly allowed and only on cards that - specifically have been tested for this. - -config ATH_REG_DYNAMIC_USER_CERT_TESTING - bool "Atheros dynamic user regulatory testing" - depends on ATH_REG_DYNAMIC_USER_REG_HINTS && CFG80211_CERTIFICATION_ONUS - default n - ---help--- - Say N. This should only be enabled on systems - undergoing certification testing. - -source "drivers/net/wireless/ath/ath5k/Kconfig" -source "drivers/net/wireless/ath/ath9k/Kconfig" -source "drivers/net/wireless/ath/carl9170/Kconfig" -source "drivers/net/wireless/ath/ath6kl/Kconfig" -source "drivers/net/wireless/ath/ar5523/Kconfig" -source "drivers/net/wireless/ath/wil6210/Kconfig" -source "drivers/net/wireless/ath/ath10k/Kconfig" -source "drivers/net/wireless/ath/wcn36xx/Kconfig" - -endif diff --git a/src/linux/drivers/net/wireless/ath/ar5523/Kconfig b/src/linux/drivers/net/wireless/ath/ar5523/Kconfig deleted file mode 100644 index 0d320cc..0000000 --- a/src/linux/drivers/net/wireless/ath/ar5523/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config AR5523 - tristate "Atheros AR5523 wireless driver support" - depends on MAC80211 && USB - select ATH_COMMON - select FW_LOADER - ---help--- - This module add support for AR5523 based USB dongles such as D-Link - DWL-G132, Netgear WPN111 and many more. diff --git a/src/linux/drivers/net/wireless/ath/ath10k/Kconfig b/src/linux/drivers/net/wireless/ath/ath10k/Kconfig deleted file mode 100644 index db1ca62..0000000 --- a/src/linux/drivers/net/wireless/ath/ath10k/Kconfig +++ /dev/null @@ -1,54 +0,0 @@ -config ATH10K - tristate "Atheros 802.11ac wireless cards support" - depends on MAC80211 && HAS_DMA - select ATH_COMMON - select CRC32 - ---help--- - This module adds support for wireless adapters based on - Atheros IEEE 802.11ac family of chipsets. - - If you choose to build a module, it'll be called ath10k. - -config ATH10K_PCI - tristate "Atheros ath10k PCI support" - depends on ATH10K && PCI - ---help--- - This module adds support for PCIE bus - -config ATH10K_AHB - bool "Atheros ath10k AHB support" - depends on ATH10K_PCI && OF && RESET_CONTROLLER - ---help--- - This module adds support for AHB bus - -config ATH10K_DEBUG - bool "Atheros ath10k debugging" - depends on ATH10K - ---help--- - Enables debug support - - If unsure, say Y to make it easier to debug problems. - -config ATH10K_DEBUGFS - bool "Atheros ath10k debugfs support" - depends on ATH10K && DEBUG_FS - select RELAY - ---help--- - Enabled debugfs support - - If unsure, say Y to make it easier to debug problems. - -config ATH10K_TRACING - bool "Atheros ath10k tracing support" - depends on ATH10K - depends on EVENT_TRACING - ---help--- - Select this to ath10k use tracing infrastructure. - -config ATH10K_DFS_CERTIFIED - bool "Atheros DFS support for certified platforms" - depends on ATH10K && CFG80211_CERTIFICATION_ONUS - default n - ---help--- - This option enables DFS support for initiating radiation on - ath10k. diff --git a/src/linux/drivers/net/wireless/ath/ath5k/Kconfig b/src/linux/drivers/net/wireless/ath/ath5k/Kconfig deleted file mode 100644 index b1278f9..0000000 --- a/src/linux/drivers/net/wireless/ath/ath5k/Kconfig +++ /dev/null @@ -1,74 +0,0 @@ -config ATH5K - tristate "Atheros 5xxx wireless cards support" - depends on (PCI || ATH25) && MAC80211 - select ATH_COMMON - select MAC80211_LEDS - select LEDS_CLASS - select NEW_LEDS - select ATH5K_AHB if ATH25 - select ATH5K_PCI if !ATH25 - ---help--- - This module adds support for wireless adapters based on - Atheros 5xxx chipset. - - Currently the following chip versions are supported: - - MAC: AR5211 AR5212 - PHY: RF5111/2111 RF5112/2112 RF5413/2413 - - This driver uses the kernel's mac80211 subsystem. - - If you choose to build a module, it'll be called ath5k. Say M if - unsure. - -config ATH5K_DEBUG - bool "Atheros 5xxx debugging" - depends on ATH5K - ---help--- - Atheros 5xxx debugging messages. - - Say Y, if and you will get debug options for ath5k. - To use this, you need to mount debugfs: - - mount -t debugfs debug /sys/kernel/debug - - You will get access to files under: - /sys/kernel/debug/ath5k/phy0/ - - To enable debug, pass the debug level to the debug module - parameter. For example: - - modprobe ath5k debug=0x00000400 - -config ATH5K_TRACER - bool "Atheros 5xxx tracer" - depends on ATH5K - depends on EVENT_TRACING - ---help--- - Say Y here to enable tracepoints for the ath5k driver - using the kernel tracing infrastructure. Select this - option if you are interested in debugging the driver. - - If unsure, say N. - -config ATH5K_AHB - bool "Atheros 5xxx AHB bus support" - depends on ATH25 - ---help--- - This adds support for WiSoC type chipsets of the 5xxx Atheros - family. - -config ATH5K_PCI - bool "Atheros 5xxx PCI bus support" - depends on (!ATH25 && PCI) - ---help--- - This adds support for PCI type chipsets of the 5xxx Atheros - family. - -config ATH5K_TEST_CHANNELS - bool "Enables testing channels on ath5k" - depends on ATH5K && CFG80211_CERTIFICATION_ONUS - ---help--- - This enables non-standard IEEE 802.11 channels on ath5k, which - can be used for research purposes. This option should be disabled - unless doing research. diff --git a/src/linux/drivers/net/wireless/ath/ath6kl/Kconfig b/src/linux/drivers/net/wireless/ath/ath6kl/Kconfig deleted file mode 100644 index 9c125ff..0000000 --- a/src/linux/drivers/net/wireless/ath/ath6kl/Kconfig +++ /dev/null @@ -1,65 +0,0 @@ -config ATH6KL - tristate "Atheros mobile chipsets support" - depends on CFG80211 - ---help--- - This module adds core support for wireless adapters based on - Atheros AR6003 and AR6004 chipsets. You still need separate - bus drivers for USB and SDIO to be able to use real devices. - - If you choose to build it as a module, it will be called - ath6kl_core. Please note that AR6002 and AR6001 are not - supported by this driver. - -config ATH6KL_SDIO - tristate "Atheros ath6kl SDIO support" - depends on ATH6KL - depends on MMC - ---help--- - This module adds support for wireless adapters based on - Atheros AR6003 and AR6004 chipsets running over SDIO. If you - choose to build it as a module, it will be called ath6kl_sdio. - Please note that AR6002 and AR6001 are not supported by this - driver. - -config ATH6KL_USB - tristate "Atheros ath6kl USB support" - depends on ATH6KL - depends on USB - ---help--- - This module adds support for wireless adapters based on - Atheros AR6004 chipset and chipsets based on it running over - USB. If you choose to build it as a module, it will be - called ath6kl_usb. - -config ATH6KL_DEBUG - bool "Atheros ath6kl debugging" - depends on ATH6KL - ---help--- - Enables ath6kl debug support, including debug messages - enabled with debug_mask module parameter and debugfs - interface. - - If unsure, say Y to make it easier to debug problems. - -config ATH6KL_TRACING - bool "Atheros ath6kl tracing support" - depends on ATH6KL - depends on EVENT_TRACING - ---help--- - Select this to ath6kl use tracing infrastructure which, for - example, can be enabled with help of trace-cmd. All debug - messages and commands are delivered to using individually - enablable trace points. - - If unsure, say Y to make it easier to debug problems. - -config ATH6KL_REGDOMAIN - bool "Atheros ath6kl regdomain support" - depends on ATH6KL - depends on CFG80211_CERTIFICATION_ONUS - ---help--- - Enabling this makes it possible to change the regdomain in - the firmware. This can be only enabled if regulatory requirements - are taken into account. - - If unsure, say N. diff --git a/src/linux/drivers/net/wireless/ath/ath9k/Kconfig b/src/linux/drivers/net/wireless/ath/ath9k/Kconfig deleted file mode 100644 index 8f231c6..0000000 --- a/src/linux/drivers/net/wireless/ath/ath9k/Kconfig +++ /dev/null @@ -1,189 +0,0 @@ -config ATH9K_HW - tristate -config ATH9K_COMMON - tristate - select ATH_COMMON - select DEBUG_FS - select RELAY -config ATH9K_DFS_DEBUGFS - def_bool y - depends on ATH9K_DEBUGFS && ATH9K_DFS_CERTIFIED - -config ATH9K_BTCOEX_SUPPORT - bool "Atheros bluetooth coexistence support" - depends on (ATH9K || ATH9K_HTC) - default y - ---help--- - Say Y, if you want to use the ath9k/ath9k_htc radios together with - Bluetooth modules in the same system. - -config ATH9K - tristate "Atheros 802.11n wireless cards support" - depends on MAC80211 && HAS_DMA - select ATH9K_HW - select MAC80211_LEDS - select LEDS_CLASS - select NEW_LEDS - select ATH9K_COMMON - ---help--- - This module adds support for wireless adapters based on - Atheros IEEE 802.11n AR5008, AR9001 and AR9002 family - of chipsets. For a specific list of supported external - cards, laptops that already ship with these cards and - APs that come with these cards refer to ath9k wiki - products page: - - http://wireless.kernel.org/en/users/Drivers/ath9k/products - - If you choose to build a module, it'll be called ath9k. - -config ATH9K_PCI - bool "Atheros ath9k PCI/PCIe bus support" - default y - depends on ATH9K && PCI - ---help--- - This option enables the PCI bus support in ath9k. - - Say Y, if you have a compatible PCI/PCIe wireless card. - -config ATH9K_AHB - bool "Atheros ath9k AHB bus support" - depends on ATH9K - default n - ---help--- - This option enables the AHB bus support in ath9k. - - Say Y, if you have a SoC with a compatible built-in - wireless MAC. Say N if unsure. - -config ATH9K_DEBUGFS - bool "Atheros ath9k debugging" - depends on ATH9K && DEBUG_FS - select MAC80211_DEBUGFS - select RELAY - ---help--- - Say Y, if you need access to ath9k's statistics for - interrupts, rate control, etc. - - Also required for changing debug message flags at run time. - -config ATH9K_STATION_STATISTICS - bool "Detailed station statistics" - depends on ATH9K && ATH9K_DEBUGFS && DEBUG_FS - select MAC80211_DEBUGFS - default n - ---help--- - This option enables detailed statistics for association stations. - -config ATH9K_TX99 - bool "Atheros ath9k TX99 testing support" - depends on ATH9K_DEBUGFS && CFG80211_CERTIFICATION_ONUS - default n - ---help--- - Say N. This should only be enabled on systems undergoing - certification testing and evaluation in a controlled environment. - Enabling this will only enable TX99 support, all other modes of - operation will be disabled. - - TX99 support enables Specific Absorption Rate (SAR) testing. - SAR is the unit of measurement for the amount of radio frequency(RF) - absorbed by the body when using a wireless device. The RF exposure - limits used are expressed in the terms of SAR, which is a measure - of the electric and magnetic field strength and power density for - transmitters operating at frequencies from 300 kHz to 100 GHz. - Regulatory bodies around the world require that wireless device - be evaluated to meet the RF exposure limits set forth in the - governmental SAR regulations. - -config ATH9K_DFS_CERTIFIED - bool "Atheros DFS support for certified platforms" - depends on ATH9K && CFG80211_CERTIFICATION_ONUS - default n - ---help--- - This option enables DFS support for initiating radiation on - ath9k. There is no way to dynamically detect if a card was DFS - certified and as such this is left as a build time option. This - option should only be enabled by system integrators that can - guarantee that all the platforms that their kernel will run on - have obtained appropriate regulatory body certification for a - respective Atheros card by using ath9k on the target shipping - platforms. - - This is currently only a placeholder for future DFS support, - as DFS support requires more components that still need to be - developed. At this point enabling this option won't do anything - except increase code size. - -config ATH9K_DYNACK - bool "Atheros ath9k ACK timeout estimation algorithm (EXPERIMENTAL)" - depends on ATH9K - default n - ---help--- - This option enables ath9k dynamic ACK timeout estimation algorithm - based on ACK frame RX timestamp, TX frame timestamp and frame - duration - -config ATH9K_WOW - bool "Wake on Wireless LAN support (EXPERIMENTAL)" - depends on ATH9K && PM - default n - ---help--- - This option enables Wake on Wireless LAN support for certain cards. - Currently, AR9462 is supported. - -config ATH9K_RFKILL - bool "Atheros ath9k rfkill support" if EXPERT - depends on ATH9K - depends on RFKILL=y || RFKILL=ATH9K - default y - help - Say Y to have ath9k poll the RF-Kill GPIO every couple of - seconds. Turn off to save power, but enable it if you have - a platform that can toggle the RF-Kill GPIO. - -config ATH9K_CHANNEL_CONTEXT - bool "Channel Context support" - depends on ATH9K - default n - ---help--- - This option enables channel context support in ath9k, which is needed - for multi-channel concurrency. Enable this if P2P PowerSave support - is required. - -config ATH9K_PCOEM - bool "Atheros ath9k support for PC OEM cards" if EXPERT - depends on ATH9K - default y - -config ATH9K_HTC - tristate "Atheros HTC based wireless cards support" - depends on USB && MAC80211 - select ATH9K_HW - select MAC80211_LEDS - select LEDS_CLASS - select NEW_LEDS - select ATH9K_COMMON - ---help--- - Support for Atheros HTC based cards. - Chipsets supported: AR9271 - - For more information: http://wireless.kernel.org/en/users/Drivers/ath9k_htc - - The built module will be ath9k_htc. - -config ATH9K_HTC_DEBUGFS - bool "Atheros ath9k_htc debugging" - depends on ATH9K_HTC && DEBUG_FS - ---help--- - Say Y, if you need access to ath9k_htc's statistics. - -config ATH9K_HWRNG - bool "Random number generator support" - depends on ATH9K && (HW_RANDOM = y || HW_RANDOM = ATH9K) - default n - ---help--- - This option incorporates the ADC register output as a source of - randomness into Linux entropy pool (/dev/urandom and /dev/random) - - Say Y, feeds the entropy directly from the WiFi driver to the input - pool. diff --git a/src/linux/drivers/net/wireless/ath/carl9170/Kconfig b/src/linux/drivers/net/wireless/ath/carl9170/Kconfig deleted file mode 100644 index 2e34bae..0000000 --- a/src/linux/drivers/net/wireless/ath/carl9170/Kconfig +++ /dev/null @@ -1,54 +0,0 @@ -config CARL9170 - tristate "Linux Community AR9170 802.11n USB support" - depends on USB && MAC80211 - select ATH_COMMON - select FW_LOADER - select CRC32 - help - This is the mainline driver for the Atheros "otus" 802.11n USB devices. - - It needs a special firmware (carl9170-1.fw), which can be downloaded - from our wiki here: - - - If you choose to build a module, it'll be called carl9170. - -config CARL9170_LEDS - bool "SoftLED Support" - depends on CARL9170 - select MAC80211_LEDS - select LEDS_CLASS - select NEW_LEDS - default y - help - This option is necessary, if you want your device' LEDs to blink - - Say Y, unless you need the LEDs for firmware debugging. - -config CARL9170_DEBUGFS - bool "DebugFS Support" - depends on CARL9170 && DEBUG_FS && MAC80211_DEBUGFS - default n - help - Export several driver and device internals to user space. - - Say N. - -config CARL9170_WPC - bool - depends on CARL9170 && (INPUT = y || INPUT = CARL9170) - default y - -config CARL9170_HWRNG - bool "Random number generator" - depends on CARL9170 && (HW_RANDOM = y || HW_RANDOM = CARL9170) - default n - help - Provides a hardware random number generator to the kernel. - - SECURITY WARNING: It's relatively easy to eavesdrop all - generated random numbers from the transport stream with - usbmon [software] or special usb sniffer hardware. - - Say N, unless your setup[i.e.: embedded system] has no - other rng source and you can afford to take the risk. diff --git a/src/linux/drivers/net/wireless/ath/wcn36xx/Kconfig b/src/linux/drivers/net/wireless/ath/wcn36xx/Kconfig deleted file mode 100644 index 591ebae..0000000 --- a/src/linux/drivers/net/wireless/ath/wcn36xx/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -config WCN36XX - tristate "Qualcomm Atheros WCN3660/3680 support" - depends on MAC80211 && HAS_DMA - ---help--- - This module adds support for wireless adapters based on - Qualcomm Atheros WCN3660 and WCN3680 mobile chipsets. - - If you choose to build a module, it'll be called wcn36xx. - -config WCN36XX_DEBUGFS - bool "WCN36XX debugfs support" - depends on WCN36XX - ---help--- - Enabled debugfs support - - If unsure, say Y to make it easier to debug problems. diff --git a/src/linux/drivers/net/wireless/ath/wil6210/Kconfig b/src/linux/drivers/net/wireless/ath/wil6210/Kconfig deleted file mode 100644 index 6dfedc8..0000000 --- a/src/linux/drivers/net/wireless/ath/wil6210/Kconfig +++ /dev/null @@ -1,42 +0,0 @@ -config WIL6210 - tristate "Wilocity 60g WiFi card wil6210 support" - select WANT_DEV_COREDUMP - depends on CFG80211 - depends on PCI - default n - ---help--- - This module adds support for wireless adapter based on - wil6210 chip by Wilocity. It supports operation on the - 60 GHz band, covered by the IEEE802.11ad standard. - - http://wireless.kernel.org/en/users/Drivers/wil6210 - - If you choose to build it as a module, it will be called - wil6210 - -config WIL6210_ISR_COR - bool "Use Clear-On-Read mode for ISR registers for wil6210" - depends on WIL6210 - default y - ---help--- - ISR registers on wil6210 chip may operate in either - COR (Clear-On-Read) or W1C (Write-1-to-Clear) mode. - For production code, use COR (say y); is default since - it saves extra target transaction; - For ISR debug, use W1C (say n); is allows to monitor ISR - registers with debugfs. If COR were used, ISR would - self-clear when accessed for debug purposes, it makes - such monitoring impossible. - Say y unless you debug interrupts - -config WIL6210_TRACING - bool "wil6210 tracing support" - depends on WIL6210 - depends on EVENT_TRACING - default y - ---help--- - Say Y here to enable tracepoints for the wil6210 driver - using the kernel tracing infrastructure. Select this - option if you are interested in debugging the driver. - - If unsure, say Y to make it easier to debug problems. diff --git a/src/linux/drivers/net/wireless/atmel/Kconfig b/src/linux/drivers/net/wireless/atmel/Kconfig deleted file mode 100644 index a43cfd1..0000000 --- a/src/linux/drivers/net/wireless/atmel/Kconfig +++ /dev/null @@ -1,57 +0,0 @@ -config WLAN_VENDOR_ATMEL - bool "Atmel devices" - default y - ---help--- - If you have a wireless card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for - your specific card in the following questions. - -if WLAN_VENDOR_ATMEL - -config ATMEL - tristate "Atmel at76c50x chipset 802.11b support" - depends on CFG80211 && (PCI || PCMCIA) - select WIRELESS_EXT - select WEXT_PRIV - select FW_LOADER - select CRC32 - ---help--- - A driver 802.11b wireless cards based on the Atmel fast-vnet - chips. This driver supports standard Linux wireless extensions. - - Many cards based on this chipset do not have flash memory - and need their firmware loaded at start-up. If yours is - one of these, you will need to provide a firmware image - to be loaded into the card by the driver. The Atmel - firmware package can be downloaded from - - -config PCI_ATMEL - tristate "Atmel at76c506 PCI cards" - depends on ATMEL && PCI - ---help--- - Enable support for PCI and mini-PCI cards containing the - Atmel at76c506 chip. - -config PCMCIA_ATMEL - tristate "Atmel at76c502/at76c504 PCMCIA cards" - depends on ATMEL && PCMCIA - select WIRELESS_EXT - select FW_LOADER - select CRC32 - ---help--- - Enable support for PCMCIA cards containing the - Atmel at76c502 and at76c504 chips. - -config AT76C50X_USB - tristate "Atmel at76c503/at76c505/at76c505a USB cards" - depends on MAC80211 && USB - select FW_LOADER - ---help--- - Enable support for USB Wireless devices using Atmel at76c503, - at76c505 or at76c505a chips. - -endif # WLAN_VENDOR_ATMEL diff --git a/src/linux/drivers/net/wireless/broadcom/Kconfig b/src/linux/drivers/net/wireless/broadcom/Kconfig deleted file mode 100644 index d3651ce..0000000 --- a/src/linux/drivers/net/wireless/broadcom/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config WLAN_VENDOR_BROADCOM - bool "Broadcom devices" - default y - ---help--- - If you have a wireless card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for - your specific card in the following questions. - -if WLAN_VENDOR_BROADCOM - -source "drivers/net/wireless/broadcom/b43/Kconfig" -source "drivers/net/wireless/broadcom/b43legacy/Kconfig" -source "drivers/net/wireless/broadcom/brcm80211/Kconfig" - -endif # WLAN_VENDOR_BROADCOM diff --git a/src/linux/drivers/net/wireless/broadcom/b43/Kconfig b/src/linux/drivers/net/wireless/broadcom/b43/Kconfig deleted file mode 100644 index fba8560..0000000 --- a/src/linux/drivers/net/wireless/broadcom/b43/Kconfig +++ /dev/null @@ -1,187 +0,0 @@ -config B43 - tristate "Broadcom 43xx wireless support (mac80211 stack)" - depends on (BCMA_POSSIBLE || SSB_POSSIBLE) && MAC80211 && HAS_DMA - select BCMA if B43_BCMA - select SSB if B43_SSB - select FW_LOADER - ---help--- - b43 is a driver for the Broadcom 43xx series wireless devices. - - Check "lspci" for something like - "Broadcom Corporation BCM43XX 802.11 Wireless LAN Controller" - to determine whether you own such a device. - - This driver supports the new BCM43xx IEEE 802.11G devices, but not - the old IEEE 802.11B devices. Old devices are supported by - the b43legacy driver. - Note that this has nothing to do with the standard that your AccessPoint - supports (A, B, G or a combination). - IEEE 802.11G devices can talk to IEEE 802.11B AccessPoints. - - It is safe to include both b43 and b43legacy as the underlying glue - layer will automatically load the correct version for your device. - - This driver uses V4 firmware, which must be installed separately using - b43-fwcutter. - - This driver can be built as a module (recommended) that will be called "b43". - If unsure, say M. - -config B43_BCMA - bool - -config B43_SSB - bool - -choice - prompt "Supported bus types" - depends on B43 - default B43_BUSES_BCMA_AND_SSB - -config B43_BUSES_BCMA_AND_SSB - bool "BCMA and SSB" - depends on BCMA_POSSIBLE && SSB_POSSIBLE - select B43_BCMA - select B43_SSB - -config B43_BUSES_BCMA - bool "BCMA only" - depends on BCMA_POSSIBLE - select B43_BCMA - -config B43_BUSES_SSB - bool "SSB only" - depends on SSB_POSSIBLE - select B43_SSB - -endchoice - -# Auto-select SSB PCI-HOST support, if possible -config B43_PCI_AUTOSELECT - bool - depends on B43 && SSB_PCIHOST_POSSIBLE - select SSB_PCIHOST - select SSB_B43_PCI_BRIDGE - default y - -# Auto-select SSB PCICORE driver, if possible -config B43_PCICORE_AUTOSELECT - bool - depends on B43 && SSB_DRIVER_PCICORE_POSSIBLE - select SSB_DRIVER_PCICORE - default y - -config B43_SDIO - bool "Broadcom 43xx SDIO device support" - depends on B43 && B43_SSB && SSB_SDIOHOST_POSSIBLE - select SSB_SDIOHOST - ---help--- - Broadcom 43xx device support for Soft-MAC SDIO devices. - - With this config option you can drive Soft-MAC b43 cards with a - Secure Digital I/O interface. - This includes the WLAN daughter card found on the Nintendo Wii - video game console. - Note that this does not support Broadcom 43xx Full-MAC devices. - - It's safe to select Y here, even if you don't have a B43 SDIO device. - - If unsure, say N. - -#Data transfers to the device via PIO. We want it as a fallback even -# if we can do DMA. -config B43_BCMA_PIO - bool - depends on B43 && B43_BCMA - select BCMA_BLOCKIO - default y - -config B43_PIO - bool - depends on B43 && B43_SSB - select SSB_BLOCKIO - default y - -config B43_PHY_G - bool "Support for G-PHY (802.11g) devices" - depends on B43 && B43_SSB - default y - ---help--- - This PHY type can be found in the following chipsets: - PCI: BCM4306, BCM4311, BCM4318 - SoC: BCM4712, BCM5352E - -config B43_PHY_N - bool "Support for N-PHY (the main 802.11n series) devices" - depends on B43 - default y - ---help--- - This PHY type can be found in the following chipsets: - PCI: BCM4321, BCM4322, - BCM43222, BCM43224, BCM43225, - BCM43131, BCM43217, BCM43227, BCM43228 - SoC: BCM4716, BCM4717, BCM4718, BCM5356, BCM5357, BCM5358 - -config B43_PHY_LP - bool "Support for LP-PHY (low-power 802.11g) devices" - depends on B43 && B43_SSB - default y - ---help--- - The LP-PHY is a low-power PHY built into some notebooks - and embedded devices. It supports 802.11a/b/g - (802.11a support is optional, and currently disabled). - -config B43_PHY_HT - bool "Support for HT-PHY (high throughput 802.11n) devices" - depends on B43 && B43_BCMA - default y - ---help--- - This PHY type with 3x3:3 MIMO can be found in the BCM4331 PCI chipset. - -config B43_PHY_LCN - bool "Support for LCN-PHY devices (BROKEN)" - depends on B43 && BROKEN - ---help--- - Support for the LCN-PHY. - - Say N, this is BROKEN and crashes driver. - -config B43_PHY_AC - bool "Support for AC-PHY (802.11ac) devices (BROKEN)" - depends on B43 && B43_BCMA && BROKEN - ---help--- - This PHY type can be found in the following chipsets: - PCI: BCM4352, BCM4360 - - Say N, this is BROKEN and crashes driver. - -# This config option automatically enables b43 LEDS support, -# if it's possible. -config B43_LEDS - bool - depends on B43 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43) - default y - -# This config option automatically enables b43 HW-RNG support, -# if the HW-RNG core is enabled. -config B43_HWRNG - bool - depends on B43 && (HW_RANDOM = y || HW_RANDOM = B43) - default y - -config B43_DEBUG - bool "Broadcom 43xx debugging" - depends on B43 - ---help--- - Broadcom 43xx debugging. - - This adds additional runtime sanity checks and statistics to the driver. - These checks and statistics might be expensive and hurt the runtime - performance of your system. - This also adds the b43 debugfs interface. - - Do not enable this, unless you are debugging the driver. - - Say N, if you are a distributor or user building a release kernel - for production use. - Only say Y, if you are debugging a problem in the b43 driver sourcecode. diff --git a/src/linux/drivers/net/wireless/broadcom/b43legacy/Kconfig b/src/linux/drivers/net/wireless/broadcom/b43legacy/Kconfig deleted file mode 100644 index 1ffa288..0000000 --- a/src/linux/drivers/net/wireless/broadcom/b43legacy/Kconfig +++ /dev/null @@ -1,104 +0,0 @@ -config B43LEGACY - tristate "Broadcom 43xx-legacy wireless support (mac80211 stack)" - depends on SSB_POSSIBLE && MAC80211 && HAS_DMA - select SSB - select FW_LOADER - ---help--- - b43legacy is a driver for 802.11b devices from Broadcom (BCM4301 and - BCM4303) and early model 802.11g chips (BCM4306 Ver. 2) used in the - Linksys WPC54G V1 PCMCIA devices. - - Newer 802.11g and 802.11a devices need b43. - - It is safe to include both b43 and b43legacy as the underlying glue - layer will automatically load the correct version for your device. - - This driver uses V3 firmware, which must be installed separately using - b43-fwcutter. - - This driver can be built as a module (recommended) that will be - called "b43legacy". If unsure, say M. - -# Auto-select SSB PCI-HOST support, if possible -config B43LEGACY_PCI_AUTOSELECT - bool - depends on B43LEGACY && SSB_PCIHOST_POSSIBLE - select SSB_PCIHOST - select SSB_B43_PCI_BRIDGE - default y - -# Auto-select SSB PCICORE driver, if possible -config B43LEGACY_PCICORE_AUTOSELECT - bool - depends on B43LEGACY && SSB_DRIVER_PCICORE_POSSIBLE - select SSB_DRIVER_PCICORE - default y - -# LED support -# This config option automatically enables b43legacy LEDS support, -# if it's possible. -config B43LEGACY_LEDS - bool - depends on B43LEGACY && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = B43LEGACY) - default y - -# This config option automatically enables b43 HW-RNG support, -# if the HW-RNG core is enabled. -config B43LEGACY_HWRNG - bool - depends on B43LEGACY && (HW_RANDOM = y || HW_RANDOM = B43LEGACY) - default y - -config B43LEGACY_DEBUG - bool "Broadcom 43xx-legacy debugging" - depends on B43LEGACY - default y - ---help--- - Say Y, because this information will help you get the driver running. - This option generates a minimum of log output. - -config B43LEGACY_DMA - bool - depends on B43LEGACY - -config B43LEGACY_PIO - bool - depends on B43LEGACY - -choice - prompt "Broadcom 43xx-legacy data transfer mode" - depends on B43LEGACY - default B43LEGACY_DMA_AND_PIO_MODE - -config B43LEGACY_DMA_AND_PIO_MODE - bool "DMA + PIO" - select B43LEGACY_DMA - select B43LEGACY_PIO - ---help--- - Include both, Direct Memory Access (DMA) and Programmed I/O (PIO) - data transfer modes. The mode actually used is selectable through - the module parameter "pio". With pio=0 as a module parameter, the - default DMA is used, otherwise PIO is used. - - If unsure, choose this option. - -config B43LEGACY_DMA_MODE - bool "DMA (Direct Memory Access) only" - select B43LEGACY_DMA - ---help--- - Only include Direct Memory Access (DMA). - This reduces the size of the driver module, by omitting the PIO code. - -config B43LEGACY_PIO_MODE - bool "PIO (Programmed I/O) only" - select B43LEGACY_PIO - ---help--- - Only include Programmed I/O (PIO). - This reduces the size of the driver module, by omitting the DMA code. - Please note that PIO transfers are slow (compared to DMA). - - Also note that not all devices of the b43legacy series support PIO. - - You should use PIO only if DMA does not work for you. - -endchoice diff --git a/src/linux/drivers/net/wireless/broadcom/brcm80211/Kconfig b/src/linux/drivers/net/wireless/broadcom/brcm80211/Kconfig deleted file mode 100644 index ab42b1f..0000000 --- a/src/linux/drivers/net/wireless/broadcom/brcm80211/Kconfig +++ /dev/null @@ -1,87 +0,0 @@ -config BRCMUTIL - tristate - -config BRCMSMAC - tristate "Broadcom IEEE802.11n PCIe SoftMAC WLAN driver" - depends on MAC80211 - depends on BCMA_POSSIBLE - select BCMA - select NEW_LEDS if BCMA_DRIVER_GPIO - select LEDS_CLASS if BCMA_DRIVER_GPIO - select BRCMUTIL - select FW_LOADER - select CORDIC - ---help--- - This module adds support for PCIe wireless adapters based on Broadcom - IEEE802.11n SoftMAC chipsets. It also has WLAN led support, which will - be available if you select BCMA_DRIVER_GPIO. If you choose to build a - module, the driver will be called brcmsmac.ko. - -config BRCMFMAC - tristate "Broadcom IEEE802.11n embedded FullMAC WLAN driver" - depends on CFG80211 - select BRCMUTIL - ---help--- - This module adds support for embedded wireless adapters based on - Broadcom IEEE802.11n FullMAC chipsets. It has to work with at least - one of the bus interface support. If you choose to build a module, - it'll be called brcmfmac.ko. - -config BRCMFMAC_PROTO_BCDC - bool - -config BRCMFMAC_PROTO_MSGBUF - bool - -config BRCMFMAC_SDIO - bool "SDIO bus interface support for FullMAC driver" - depends on (MMC = y || MMC = BRCMFMAC) - depends on BRCMFMAC - select BRCMFMAC_PROTO_BCDC - select FW_LOADER - default y - ---help--- - This option enables the SDIO bus interface support for Broadcom - IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to - use the driver for a SDIO wireless card. - -config BRCMFMAC_USB - bool "USB bus interface support for FullMAC driver" - depends on (USB = y || USB = BRCMFMAC) - depends on BRCMFMAC - select BRCMFMAC_PROTO_BCDC - select FW_LOADER - ---help--- - This option enables the USB bus interface support for Broadcom - IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to - use the driver for an USB wireless card. - -config BRCMFMAC_PCIE - bool "PCIE bus interface support for FullMAC driver" - depends on BRCMFMAC - depends on PCI - depends on HAS_DMA - select BRCMFMAC_PROTO_MSGBUF - select FW_LOADER - ---help--- - This option enables the PCIE bus interface support for Broadcom - IEEE802.11ac embedded FullMAC WLAN driver. Say Y if you want to - use the driver for an PCIE wireless card. - -config BRCM_TRACING - bool "Broadcom device tracing" - depends on BRCMSMAC || BRCMFMAC - ---help--- - If you say Y here, the Broadcom wireless drivers will register - with ftrace to dump event information into the trace ringbuffer. - Tracing can be enabled at runtime to aid in debugging wireless - issues. This option adds a small amount of overhead when tracing - is disabled. If unsure, say Y to allow developers to better help - you when wireless problems occur. - -config BRCMDBG - bool "Broadcom driver debug functions" - depends on BRCMSMAC || BRCMFMAC - select WANT_DEV_COREDUMP - ---help--- - Selecting this enables additional code for debug purposes. diff --git a/src/linux/drivers/net/wireless/cisco/Kconfig b/src/linux/drivers/net/wireless/cisco/Kconfig deleted file mode 100644 index b22567d..0000000 --- a/src/linux/drivers/net/wireless/cisco/Kconfig +++ /dev/null @@ -1,56 +0,0 @@ -config WLAN_VENDOR_CISCO - bool "Cisco devices" - default y - ---help--- - If you have a wireless card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for - your specific card in the following questions. - -if WLAN_VENDOR_CISCO - -config AIRO - tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" - depends on CFG80211 && ISA_DMA_API && (PCI || BROKEN) - select WIRELESS_EXT - select CRYPTO - select WEXT_SPY - select WEXT_PRIV - ---help--- - This is the standard Linux driver to support Cisco/Aironet ISA and - PCI 802.11 wireless cards. - It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X - - with or without encryption) as well as card before the Cisco - acquisition (Aironet 4500, Aironet 4800, Aironet 4800B). - - This driver support both the standard Linux Wireless Extensions - and Cisco proprietary API, so both the Linux Wireless Tools and the - Cisco Linux utilities can be used to configure the card. - - The driver can be compiled as a module and will be named "airo". - -config AIRO_CS - tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" - depends on CFG80211 && PCMCIA && (BROKEN || !M32R) - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - select CRYPTO - select CRYPTO_AES - ---help--- - This is the standard Linux driver to support Cisco/Aironet PCMCIA - 802.11 wireless cards. This driver is the same as the Aironet - driver part of the Linux Pcmcia package. - It supports the new 802.11b cards from Cisco (Cisco 34X, Cisco 35X - - with or without encryption) as well as card before the Cisco - acquisition (Aironet 4500, Aironet 4800, Aironet 4800B). It also - supports OEM of Cisco such as the DELL TrueMobile 4800 and Xircom - 802.11b cards. - - This driver support both the standard Linux Wireless Extensions - and Cisco proprietary API, so both the Linux Wireless Tools and the - Cisco Linux utilities can be used to configure the card. - -endif # WLAN_VENDOR_CISCO diff --git a/src/linux/drivers/net/wireless/intel/Kconfig b/src/linux/drivers/net/wireless/intel/Kconfig deleted file mode 100644 index 5b14f2f..0000000 --- a/src/linux/drivers/net/wireless/intel/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config WLAN_VENDOR_INTEL - bool "Intel devices" - default y - ---help--- - If you have a wireless card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for - your specific card in the following questions. - -if WLAN_VENDOR_INTEL - -source "drivers/net/wireless/intel/ipw2x00/Kconfig" -source "drivers/net/wireless/intel/iwlegacy/Kconfig" -source "drivers/net/wireless/intel/iwlwifi/Kconfig" - -endif # WLAN_VENDOR_INTEL diff --git a/src/linux/drivers/net/wireless/intel/ipw2x00/Kconfig b/src/linux/drivers/net/wireless/intel/ipw2x00/Kconfig deleted file mode 100644 index d6ec44d..0000000 --- a/src/linux/drivers/net/wireless/intel/ipw2x00/Kconfig +++ /dev/null @@ -1,198 +0,0 @@ -# -# Intel Centrino wireless drivers -# - -config IPW2100 - tristate "Intel PRO/Wireless 2100 Network Connection" - depends on PCI && CFG80211 - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - select FW_LOADER - select LIB80211 - select LIBIPW - ---help--- - A driver for the Intel PRO/Wireless 2100 Network - Connection 802.11b wireless network adapter. - - See for information on - the capabilities currently enabled in this driver and for tips - for debugging issues and problems. - - In order to use this driver, you will need a firmware image for it. - You can obtain the firmware from - . Once you have the firmware image, you - will need to place it in /lib/firmware. - - You will also very likely need the Wireless Tools in order to - configure your card: - - . - - It is recommended that you compile this driver as a module (M) - rather than built-in (Y). This driver requires firmware at device - initialization time, and when built-in this typically happens - before the filesystem is accessible (hence firmware will be - unavailable and initialization will fail). If you do choose to build - this driver into your kernel image, you can avoid this problem by - including the firmware and a firmware loader in an initramfs. - -config IPW2100_MONITOR - bool "Enable promiscuous mode" - depends on IPW2100 - ---help--- - Enables promiscuous/monitor mode support for the ipw2100 driver. - With this feature compiled into the driver, you can switch to - promiscuous mode via the Wireless Tool's Monitor mode. While in this - mode, no packets can be sent. - -config IPW2100_DEBUG - bool "Enable full debugging output in IPW2100 module." - depends on IPW2100 - ---help--- - This option will enable debug tracing output for the IPW2100. - - This will result in the kernel module being ~60k larger. You can - control which debug output is sent to the kernel log by setting the - value in - - /sys/bus/pci/drivers/ipw2100/debug_level - - This entry will only exist if this option is enabled. - - If you are not trying to debug or develop the IPW2100 driver, you - most likely want to say N here. - -config IPW2200 - tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" - depends on PCI && CFG80211 - select CFG80211_WEXT_EXPORT - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - select FW_LOADER - select LIB80211 - select LIBIPW - ---help--- - A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network - Connection adapters. - - See for - information on the capabilities currently enabled in this - driver and for tips for debugging issues and problems. - - In order to use this driver, you will need a firmware image for it. - You can obtain the firmware from - . See the above referenced README.ipw2200 - for information on where to install the firmware images. - - You will also very likely need the Wireless Tools in order to - configure your card: - - . - - It is recommended that you compile this driver as a module (M) - rather than built-in (Y). This driver requires firmware at device - initialization time, and when built-in this typically happens - before the filesystem is accessible (hence firmware will be - unavailable and initialization will fail). If you do choose to build - this driver into your kernel image, you can avoid this problem by - including the firmware and a firmware loader in an initramfs. - -config IPW2200_MONITOR - bool "Enable promiscuous mode" - depends on IPW2200 - ---help--- - Enables promiscuous/monitor mode support for the ipw2200 driver. - With this feature compiled into the driver, you can switch to - promiscuous mode via the Wireless Tool's Monitor mode. While in this - mode, no packets can be sent. - -config IPW2200_RADIOTAP - bool "Enable radiotap format 802.11 raw packet support" - depends on IPW2200_MONITOR - -config IPW2200_PROMISCUOUS - bool "Enable creation of a RF radiotap promiscuous interface" - depends on IPW2200_MONITOR - select IPW2200_RADIOTAP - ---help--- - Enables the creation of a second interface prefixed 'rtap'. - This second interface will provide every received in radiotap - format. - - This is useful for performing wireless network analysis while - maintaining an active association. - - Example usage: - - % modprobe ipw2200 rtap_iface=1 - % ifconfig rtap0 up - % tethereal -i rtap0 - - If you do not specify 'rtap_iface=1' as a module parameter then - the rtap interface will not be created and you will need to turn - it on via sysfs: - - % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface - -config IPW2200_QOS - bool "Enable QoS support" - depends on IPW2200 - -config IPW2200_DEBUG - bool "Enable full debugging output in IPW2200 module." - depends on IPW2200 - ---help--- - This option will enable low level debug tracing output for IPW2200. - - Note, normal debug code is already compiled in. This low level - debug option enables debug on hot paths (e.g Tx, Rx, ISR) and - will result in the kernel module being ~70 larger. Most users - will typically not need this high verbosity debug information. - - If you are not sure, say N here. - -config LIBIPW - tristate - depends on PCI && CFG80211 - select WIRELESS_EXT - select WEXT_SPY - select CRYPTO - select CRYPTO_ARC4 - select CRYPTO_ECB - select CRYPTO_AES - select CRYPTO_MICHAEL_MIC - select CRYPTO_ECB - select CRC32 - select LIB80211 - select LIB80211_CRYPT_WEP - select LIB80211_CRYPT_TKIP - select LIB80211_CRYPT_CCMP - ---help--- - This option enables the hardware independent IEEE 802.11 - networking stack. This component is deprecated in favor of the - mac80211 component. - -config LIBIPW_DEBUG - bool "Full debugging output for the LIBIPW component" - depends on LIBIPW - ---help--- - This option will enable debug tracing output for the - libipw component. - - This will result in the kernel module being ~70k larger. You - can control which debug output is sent to the kernel log by - setting the value in - - /proc/net/ieee80211/debug_level - - For example: - - % echo 0x00000FFO > /proc/net/ieee80211/debug_level - - For a list of values you can assign to debug_level, you - can look at the bit mask values in ieee80211.h - - If you are not trying to debug or develop the libipw - component, you most likely want to say N here. diff --git a/src/linux/drivers/net/wireless/intel/iwlegacy/Kconfig b/src/linux/drivers/net/wireless/intel/iwlegacy/Kconfig deleted file mode 100644 index fb91972..0000000 --- a/src/linux/drivers/net/wireless/intel/iwlegacy/Kconfig +++ /dev/null @@ -1,100 +0,0 @@ -config IWLEGACY - tristate - select FW_LOADER - select NEW_LEDS - select LEDS_CLASS - select LEDS_TRIGGERS - select MAC80211_LEDS - -config IWL4965 - tristate "Intel Wireless WiFi 4965AGN (iwl4965)" - depends on PCI && MAC80211 - select IWLEGACY - ---help--- - This option enables support for - - Select to build the driver supporting the: - - Intel Wireless WiFi Link 4965AGN - - This driver uses the kernel's mac80211 subsystem. - - In order to use this driver, you will need a microcode (uCode) - image for it. You can obtain the microcode from: - - . - - The microcode is typically installed in /lib/firmware. You can - look in the hotplug script /etc/hotplug/firmware.agent to - determine which directory FIRMWARE_DIR is set to when the script - runs. - - If you want to compile the driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The - module will be called iwl4965. - -config IWL3945 - tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)" - depends on PCI && MAC80211 - select IWLEGACY - ---help--- - Select to build the driver supporting the: - - Intel PRO/Wireless 3945ABG/BG Network Connection - - This driver uses the kernel's mac80211 subsystem. - - In order to use this driver, you will need a microcode (uCode) - image for it. You can obtain the microcode from: - - . - - The microcode is typically installed in /lib/firmware. You can - look in the hotplug script /etc/hotplug/firmware.agent to - determine which directory FIRMWARE_DIR is set to when the script - runs. - - If you want to compile the driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The - module will be called iwl3945. - -menu "iwl3945 / iwl4965 Debugging Options" - depends on IWLEGACY - -config IWLEGACY_DEBUG - bool "Enable full debugging output in iwlegacy (iwl 3945/4965) drivers" - depends on IWLEGACY - ---help--- - This option will enable debug tracing output for the iwlegacy - drivers. - - This will result in the kernel module being ~100k larger. You can - control which debug output is sent to the kernel log by setting the - value in - - /sys/class/net/wlan0/device/debug_level - - This entry will only exist if this option is enabled. - - To set a value, simply echo an 8-byte hex value to the same file: - - % echo 0x43fff > /sys/class/net/wlan0/device/debug_level - - You can find the list of debug mask values in: - drivers/net/wireless/iwlegacy/common.h - - If this is your first time using this driver, you should say Y here - as the debug information can assist others in helping you resolve - any problems you may encounter. - -config IWLEGACY_DEBUGFS - bool "iwlegacy (iwl 3945/4965) debugfs support" - depends on IWLEGACY && MAC80211_DEBUGFS - ---help--- - Enable creation of debugfs files for the iwlegacy drivers. This - is a low-impact option that allows getting insight into the - driver's state at runtime. - -endmenu diff --git a/src/linux/drivers/net/wireless/intel/iwlwifi/Kconfig b/src/linux/drivers/net/wireless/intel/iwlwifi/Kconfig deleted file mode 100644 index b64db47..0000000 --- a/src/linux/drivers/net/wireless/intel/iwlwifi/Kconfig +++ /dev/null @@ -1,156 +0,0 @@ -config IWLWIFI - tristate "Intel Wireless WiFi Next Gen AGN - Wireless-N/Advanced-N/Ultimate-N (iwlwifi) " - depends on PCI && MAC80211 && HAS_IOMEM - select FW_LOADER - ---help--- - Select to build the driver supporting the: - - Intel Wireless WiFi Link Next-Gen AGN - - This option enables support for use with the following hardware: - Intel Wireless WiFi Link 6250AGN Adapter - Intel 6000 Series Wi-Fi Adapters (6200AGN and 6300AGN) - Intel WiFi Link 1000BGN - Intel Wireless WiFi 5150AGN - Intel Wireless WiFi 5100AGN, 5300AGN, and 5350AGN - Intel 6005 Series Wi-Fi Adapters - Intel 6030 Series Wi-Fi Adapters - Intel Wireless WiFi Link 6150BGN 2 Adapter - Intel 100 Series Wi-Fi Adapters (100BGN and 130BGN) - Intel 2000 Series Wi-Fi Adapters - Intel 7260 Wi-Fi Adapter - Intel 3160 Wi-Fi Adapter - Intel 7265 Wi-Fi Adapter - Intel 8260 Wi-Fi Adapter - Intel 3165 Wi-Fi Adapter - - - This driver uses the kernel's mac80211 subsystem. - - In order to use this driver, you will need a firmware - image for it. You can obtain the microcode from: - - . - - The firmware is typically installed in /lib/firmware. You can - look in the hotplug script /etc/hotplug/firmware.agent to - determine which directory FIRMWARE_DIR is set to when the script - runs. - - If you want to compile the driver as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read . The - module will be called iwlwifi. - -if IWLWIFI - -config IWLWIFI_LEDS - bool - depends on LEDS_CLASS=y || LEDS_CLASS=IWLWIFI - select LEDS_TRIGGERS - select MAC80211_LEDS - default y - -config IWLDVM - tristate "Intel Wireless WiFi DVM Firmware support" - help - This is the driver that supports the DVM firmware. The list - of the devices that use this firmware is available here: - https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi#firmware - -config IWLMVM - tristate "Intel Wireless WiFi MVM Firmware support" - select WANT_DEV_COREDUMP - help - This is the driver that supports the MVM firmware. The list - of the devices that use this firmware is available here: - https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi#firmware - -# don't call it _MODULE -- will confuse Kconfig/fixdep/... -config IWLWIFI_OPMODE_MODULAR - bool - default y if IWLDVM=m - default y if IWLMVM=m - -comment "WARNING: iwlwifi is useless without IWLDVM or IWLMVM" - depends on IWLDVM=n && IWLMVM=n - -config IWLWIFI_BCAST_FILTERING - bool "Enable broadcast filtering" - depends on IWLMVM - help - Say Y here to enable default bcast filtering configuration. - - Enabling broadcast filtering will drop any incoming wireless - broadcast frames, except some very specific predefined - patterns (e.g. incoming arp requests). - - If unsure, don't enable this option, as some programs might - expect incoming broadcasts for their normal operations. - -config IWLWIFI_PCIE_RTPM - bool "Enable runtime power management mode for PCIe devices" - depends on IWLMVM && PM - default false - help - Say Y here to enable runtime power management for PCIe - devices. If enabled, the device will go into low power mode - when idle for a short period of time, allowing for improved - power saving during runtime. - - If unsure, say N. - -menu "Debugging Options" - -config IWLWIFI_DEBUG - bool "Enable full debugging output in the iwlwifi driver" - ---help--- - This option will enable debug tracing output for the iwlwifi drivers - - This will result in the kernel module being ~100k larger. You can - control which debug output is sent to the kernel log by setting the - value in - - /sys/module/iwlwifi/parameters/debug - - This entry will only exist if this option is enabled. - - To set a value, simply echo an 8-byte hex value to the same file: - - % echo 0x43fff > /sys/module/iwlwifi/parameters/debug - - You can find the list of debug mask values in: - drivers/net/wireless/iwlwifi/iwl-debug.h - - If this is your first time using this driver, you should say Y here - as the debug information can assist others in helping you resolve - any problems you may encounter. - -config IWLWIFI_DEBUGFS - bool "iwlwifi debugfs support" - depends on MAC80211_DEBUGFS - ---help--- - Enable creation of debugfs files for the iwlwifi drivers. This - is a low-impact option that allows getting insight into the - driver's state at runtime. - -config IWLWIFI_DEVICE_TRACING - bool "iwlwifi device access tracing" - depends on EVENT_TRACING - default y - help - Say Y here to trace all commands, including TX frames and IO - accesses, sent to the device. If you say yes, iwlwifi will - register with the ftrace framework for event tracing and dump - all this information to the ringbuffer, you may need to - increase the ringbuffer size. See the ftrace documentation - for more information. - - When tracing is not enabled, this option still has some - (though rather small) overhead. - - If unsure, say Y so we can help you better when problems - occur. -endmenu - -endif diff --git a/src/linux/drivers/net/wireless/intersil/Kconfig b/src/linux/drivers/net/wireless/intersil/Kconfig deleted file mode 100644 index 9da1360..0000000 --- a/src/linux/drivers/net/wireless/intersil/Kconfig +++ /dev/null @@ -1,38 +0,0 @@ -config WLAN_VENDOR_INTERSIL - bool "Intersil devices" - default y - ---help--- - If you have a wireless card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for - your specific card in the following questions. - -if WLAN_VENDOR_INTERSIL - -source "drivers/net/wireless/intersil/hostap/Kconfig" -source "drivers/net/wireless/intersil/orinoco/Kconfig" -source "drivers/net/wireless/intersil/p54/Kconfig" - -config PRISM54 - tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus (DEPRECATED)' - depends on PCI - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - select FW_LOADER - ---help--- - This enables support for FullMAC PCI/Cardbus prism54 devices. This - driver is now deprecated in favor for the SoftMAC driver, p54pci. - p54pci supports FullMAC PCI/Cardbus devices as well. - - For more information refer to the p54 wiki: - - http://wireless.kernel.org/en/users/Drivers/p54 - - Note: You need a motherboard with DMA support to use any of these cards - - When built as module you get the module prism54 - -endif # WLAN_VENDOR_INTERSIL diff --git a/src/linux/drivers/net/wireless/intersil/hostap/Kconfig b/src/linux/drivers/net/wireless/intersil/hostap/Kconfig deleted file mode 100644 index 287d827..0000000 --- a/src/linux/drivers/net/wireless/intersil/hostap/Kconfig +++ /dev/null @@ -1,98 +0,0 @@ -config HOSTAP - tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)" - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - select CRYPTO - select CRYPTO_ARC4 - select CRYPTO_ECB - select CRYPTO_AES - select CRYPTO_MICHAEL_MIC - select CRYPTO_ECB - select CRC32 - select LIB80211 - select LIB80211_CRYPT_WEP - select LIB80211_CRYPT_TKIP - select LIB80211_CRYPT_CCMP - ---help--- - Shared driver code for IEEE 802.11b wireless cards based on - Intersil Prism2/2.5/3 chipset. This driver supports so called - Host AP mode that allows the card to act as an IEEE 802.11 - access point. - - See for more information about the - Host AP driver configuration and tools. This site includes - information and tools (hostapd and wpa_supplicant) for WPA/WPA2 - support. - - This option includes the base Host AP driver code that is shared by - different hardware models. You will also need to enable support for - PLX/PCI/CS version of the driver to actually use the driver. - - The driver can be compiled as a module and it will be called - hostap. - -config HOSTAP_FIRMWARE - bool "Support downloading firmware images with Host AP driver" - depends on HOSTAP - ---help--- - Configure Host AP driver to include support for firmware image - download. This option by itself only enables downloading to the - volatile memory, i.e. the card RAM. This option is required to - support cards that don't have firmware in flash, such as D-Link - DWL-520 rev E and D-Link DWL-650 rev P. - - Firmware image downloading needs a user space tool, prism2_srec. - It is available from http://hostap.epitest.fi/. - -config HOSTAP_FIRMWARE_NVRAM - bool "Support for non-volatile firmware download" - depends on HOSTAP_FIRMWARE - ---help--- - Allow Host AP driver to write firmware images to the non-volatile - card memory, i.e. flash memory that survives power cycling. - Enable this option if you want to be able to change card firmware - permanently. - - Firmware image downloading needs a user space tool, prism2_srec. - It is available from http://hostap.epitest.fi/. - -config HOSTAP_PLX - tristate "Host AP driver for Prism2/2.5/3 in PLX9052 PCI adaptors" - depends on PCI && HOSTAP - ---help--- - Host AP driver's version for Prism2/2.5/3 PC Cards in PLX9052 based - PCI adaptors. - - "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this - driver and its help text includes more information about the Host AP - driver. - - The driver can be compiled as a module and will be named - hostap_plx. - -config HOSTAP_PCI - tristate "Host AP driver for Prism2.5 PCI adaptors" - depends on PCI && HOSTAP - ---help--- - Host AP driver's version for Prism2.5 PCI adaptors. - - "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this - driver and its help text includes more information about the Host AP - driver. - - The driver can be compiled as a module and will be named - hostap_pci. - -config HOSTAP_CS - tristate "Host AP driver for Prism2/2.5/3 PC Cards" - depends on PCMCIA && HOSTAP - ---help--- - Host AP driver's version for Prism2/2.5/3 PC Cards. - - "Host AP support for Prism2/2.5/3 IEEE 802.11b" is required for this - driver and its help text includes more information about the Host AP - driver. - - The driver can be compiled as a module and will be named - hostap_cs. diff --git a/src/linux/drivers/net/wireless/intersil/orinoco/Kconfig b/src/linux/drivers/net/wireless/intersil/orinoco/Kconfig deleted file mode 100644 index f6fa3f4..0000000 --- a/src/linux/drivers/net/wireless/intersil/orinoco/Kconfig +++ /dev/null @@ -1,142 +0,0 @@ -config HERMES - tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" - depends on (PPC_PMAC || PCI || PCMCIA) - depends on CFG80211 - select CFG80211_WEXT_EXPORT - select WIRELESS_EXT - select WEXT_SPY - select WEXT_PRIV - select FW_LOADER - select CRYPTO - select CRYPTO_MICHAEL_MIC - ---help--- - A driver for 802.11b wireless cards based on the "Hermes" or - Intersil HFA384x (Prism 2) MAC controller. This includes the vast - majority of the PCMCIA 802.11b cards (which are nearly all rebadges) - - except for the Cisco/Aironet cards. Cards supported include the - Apple Airport (not a PCMCIA card), WavelanIEEE/Orinoco, - Cabletron/EnteraSys Roamabout, ELSA AirLancer, MELCO Buffalo, Avaya, - IBM High Rate Wireless, Farralon Syyline, Samsung MagicLAN, Netgear - MA401, LinkSys WPC-11, D-Link DWL-650, 3Com AirConnect, Intel - IPW2011, and Symbol Spectrum24 High Rate amongst others. - - This option includes the guts of the driver, but in order to - actually use a card you will also need to enable support for PCMCIA - Hermes cards, PLX9052 based PCI adaptors or the Apple Airport below. - - You will also very likely also need the Wireless Tools in order to - configure your card and that /etc/pcmcia/wireless.opts works : - - -config HERMES_PRISM - bool "Support Prism 2/2.5 chipset" - depends on HERMES - ---help--- - - Say Y to enable support for Prism 2 and 2.5 chipsets. These - chipsets are better handled by the hostap driver. This driver - would not support WPA or firmware download for Prism chipset. - - If you are not sure, say N. - -config HERMES_CACHE_FW_ON_INIT - bool "Cache Hermes firmware on driver initialisation" - depends on HERMES - default y - ---help--- - Say Y to cache any firmware required by the Hermes drivers - on startup. The firmware will remain cached until the - driver is unloaded. The cache uses 64K of RAM. - - Otherwise load the firmware from userspace as required. In - this case the driver should be unloaded and restarted - whenever the firmware is changed. - - If you are not sure, say Y. - -config APPLE_AIRPORT - tristate "Apple Airport support (built-in)" - depends on PPC_PMAC && HERMES - help - Say Y here to support the Airport 802.11b wireless Ethernet hardware - built into the Macintosh iBook and other recent PowerPC-based - Macintosh machines. This is essentially a Lucent Orinoco card with - a non-standard interface. - - This driver does not support the Airport Extreme (802.11b/g). Use - the BCM43xx driver for Airport Extreme cards. - -config PLX_HERMES - tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)" - depends on PCI && HERMES - help - Enable support for PCMCIA cards supported by the "Hermes" (aka - orinoco) driver when used in PLX9052 based PCI adaptors. These - adaptors are not a full PCMCIA controller but act as a more limited - PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that - 802.11b PCMCIA cards can be used in desktop machines. The Netgear - MA301 is such an adaptor. - -config TMD_HERMES - tristate "Hermes in TMD7160 based PCI adaptor support" - depends on PCI && HERMES - help - Enable support for PCMCIA cards supported by the "Hermes" (aka - orinoco) driver when used in TMD7160 based PCI adaptors. These - adaptors are not a full PCMCIA controller but act as a more limited - PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that - 802.11b PCMCIA cards can be used in desktop machines. - -config NORTEL_HERMES - tristate "Nortel emobility PCI adaptor support" - depends on PCI && HERMES - help - Enable support for PCMCIA cards supported by the "Hermes" (aka - orinoco) driver when used in Nortel emobility PCI adaptors. These - adaptors are not full PCMCIA controllers, but act as a more limited - PCI <-> PCMCIA bridge. - -config PCI_HERMES - tristate "Prism 2.5 PCI 802.11b adaptor support" - depends on PCI && HERMES && HERMES_PRISM - help - Enable support for PCI and mini-PCI 802.11b wireless NICs based on - the Prism 2.5 chipset. These are true PCI cards, not the 802.11b - PCMCIA cards bundled with PCI<->PCMCIA adaptors which are also - common. Some of the built-in wireless adaptors in laptops are of - this variety. - -config PCMCIA_HERMES - tristate "Hermes PCMCIA card support" - depends on PCMCIA && HERMES && HAS_IOPORT_MAP - ---help--- - A driver for "Hermes" chipset based PCMCIA wireless adaptors, such - as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ - EnteraSys RoamAbout 802.11, ELSA Airlancer, Melco Buffalo and - others). It should also be usable on various Prism II based cards - such as the Linksys, D-Link and Farallon Skyline. It should also - work on Symbol cards such as the 3Com AirConnect and Ericsson WLAN. - - You will very likely need the Wireless Tools in order to - configure your card and that /etc/pcmcia/wireless.opts works: - . - -config PCMCIA_SPECTRUM - tristate "Symbol Spectrum24 Trilogy PCMCIA card support" - depends on PCMCIA && HERMES && HAS_IOPORT_MAP - ---help--- - - This is a driver for 802.11b cards using RAM-loadable Symbol - firmware, such as Symbol Wireless Networker LA4100, CompactFlash - cards by Socket Communications and Intel PRO/Wireless 2011B. - - This driver requires firmware download on startup. Utilities - for downloading Symbol firmware are available at - - -config ORINOCO_USB - tristate "Agere Orinoco USB support" - depends on USB && HERMES - select FW_LOADER - ---help--- - This driver is for USB versions of the Agere Orinoco card. diff --git a/src/linux/drivers/net/wireless/intersil/p54/Kconfig b/src/linux/drivers/net/wireless/intersil/p54/Kconfig deleted file mode 100644 index cdafb8c..0000000 --- a/src/linux/drivers/net/wireless/intersil/p54/Kconfig +++ /dev/null @@ -1,71 +0,0 @@ -config P54_COMMON - tristate "Softmac Prism54 support" - depends on MAC80211 - select FW_LOADER - select CRC_CCITT - ---help--- - This is common code for isl38xx/stlc45xx based modules. - This module does nothing by itself - the USB/PCI/SPI front-ends - also need to be enabled in order to support any devices. - - These devices require softmac firmware which can be found at - - - If you choose to build a module, it'll be called p54common. - -config P54_USB - tristate "Prism54 USB support" - depends on P54_COMMON && USB - select CRC32 - ---help--- - This driver is for USB isl38xx based wireless cards. - - These devices require softmac firmware which can be found at - - - If you choose to build a module, it'll be called p54usb. - -config P54_PCI - tristate "Prism54 PCI support" - depends on P54_COMMON && PCI - ---help--- - This driver is for PCI isl38xx based wireless cards. - This driver supports most devices that are supported by the - fullmac prism54 driver plus many devices which are not - supported by the fullmac driver/firmware. - - This driver requires softmac firmware which can be found at - - - If you choose to build a module, it'll be called p54pci. - -config P54_SPI - tristate "Prism54 SPI (stlc45xx) support" - depends on P54_COMMON && SPI_MASTER - ---help--- - This driver is for stlc4550 or stlc4560 based wireless chips - such as Nokia's N800/N810 Portable Internet Tablet. - - If you choose to build a module, it'll be called p54spi. - -config P54_SPI_DEFAULT_EEPROM - bool "Include fallback EEPROM blob" - depends on P54_SPI - default n - ---help--- - Unlike the PCI or USB devices, the SPI variants don't have - a dedicated EEPROM chip to store all device specific values - for calibration, country and interface settings. - - The driver will try to load the image "3826.eeprom", if the - file is put at the right place. (usually /lib/firmware.) - - Only if this request fails, this option will provide a - backup set of generic values to get the device working. - - Enabling this option adds about 4k to p54spi. - -config P54_LEDS - bool - depends on P54_COMMON && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = P54_COMMON) - default y diff --git a/src/linux/drivers/net/wireless/marvell/Kconfig b/src/linux/drivers/net/wireless/marvell/Kconfig deleted file mode 100644 index 4938c7e..0000000 --- a/src/linux/drivers/net/wireless/marvell/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -config WLAN_VENDOR_MARVELL - bool "Marvell devices" - default y - ---help--- - If you have a wireless card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for - your specific card in the following questions. - -if WLAN_VENDOR_MARVELL - -source "drivers/net/wireless/marvell/libertas/Kconfig" -source "drivers/net/wireless/marvell/libertas_tf/Kconfig" -source "drivers/net/wireless/marvell/mwifiex/Kconfig" - -config MWL8K - tristate "Marvell 88W8xxx PCI/PCIe Wireless support" - depends on MAC80211 && PCI - ---help--- - This driver supports Marvell TOPDOG 802.11 wireless cards. - - To compile this driver as a module, choose M here: the module - will be called mwl8k. If unsure, say N. - -endif # WLAN_VENDOR_MARVELL diff --git a/src/linux/drivers/net/wireless/marvell/libertas/Kconfig b/src/linux/drivers/net/wireless/marvell/libertas/Kconfig deleted file mode 100644 index e6268ce..0000000 --- a/src/linux/drivers/net/wireless/marvell/libertas/Kconfig +++ /dev/null @@ -1,45 +0,0 @@ -config LIBERTAS - tristate "Marvell 8xxx Libertas WLAN driver support" - depends on CFG80211 - select WIRELESS_EXT - select WEXT_SPY - select LIB80211 - select FW_LOADER - ---help--- - A library for Marvell Libertas 8xxx devices. - -config LIBERTAS_USB - tristate "Marvell Libertas 8388 USB 802.11b/g cards" - depends on LIBERTAS && USB - ---help--- - A driver for Marvell Libertas 8388 USB devices. - -config LIBERTAS_CS - tristate "Marvell Libertas 8385 CompactFlash 802.11b/g cards" - depends on LIBERTAS && PCMCIA && HAS_IOPORT_MAP - ---help--- - A driver for Marvell Libertas 8385 CompactFlash devices. - -config LIBERTAS_SDIO - tristate "Marvell Libertas 8385/8686/8688 SDIO 802.11b/g cards" - depends on LIBERTAS && MMC - ---help--- - A driver for Marvell Libertas 8385/8686/8688 SDIO devices. - -config LIBERTAS_SPI - tristate "Marvell Libertas 8686 SPI 802.11b/g cards" - depends on LIBERTAS && SPI - ---help--- - A driver for Marvell Libertas 8686 SPI devices. - -config LIBERTAS_DEBUG - bool "Enable full debugging output in the Libertas module." - depends on LIBERTAS - ---help--- - Debugging support. - -config LIBERTAS_MESH - bool "Enable mesh support" - depends on LIBERTAS - help - This enables Libertas' MESH support, used by e.g. the OLPC people. diff --git a/src/linux/drivers/net/wireless/marvell/libertas_tf/Kconfig b/src/linux/drivers/net/wireless/marvell/libertas_tf/Kconfig deleted file mode 100644 index b5557af..0000000 --- a/src/linux/drivers/net/wireless/marvell/libertas_tf/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config LIBERTAS_THINFIRM - tristate "Marvell 8xxx Libertas WLAN driver support with thin firmware" - depends on MAC80211 - select FW_LOADER - ---help--- - A library for Marvell Libertas 8xxx devices using thinfirm. - -config LIBERTAS_THINFIRM_DEBUG - bool "Enable full debugging output in the Libertas thin firmware module." - depends on LIBERTAS_THINFIRM - ---help--- - Debugging support. - -config LIBERTAS_THINFIRM_USB - tristate "Marvell Libertas 8388 USB 802.11b/g cards with thin firmware" - depends on LIBERTAS_THINFIRM && USB - ---help--- - A driver for Marvell Libertas 8388 USB devices using thinfirm. diff --git a/src/linux/drivers/net/wireless/marvell/mwifiex/Kconfig b/src/linux/drivers/net/wireless/marvell/mwifiex/Kconfig deleted file mode 100644 index 279167d..0000000 --- a/src/linux/drivers/net/wireless/marvell/mwifiex/Kconfig +++ /dev/null @@ -1,44 +0,0 @@ -config MWIFIEX - tristate "Marvell WiFi-Ex Driver" - depends on CFG80211 - ---help--- - This adds support for wireless adapters based on Marvell - 802.11n/ac chipsets. - - If you choose to build it as a module, it will be called - mwifiex. - -config MWIFIEX_SDIO - tristate "Marvell WiFi-Ex Driver for SD8786/SD8787/SD8797/SD8887/SD8897/SD8997" - depends on MWIFIEX && MMC - select FW_LOADER - select WANT_DEV_COREDUMP - ---help--- - This adds support for wireless adapters based on Marvell - 8786/8787/8797/8887/8897/8997 chipsets with SDIO interface. - - If you choose to build it as a module, it will be called - mwifiex_sdio. - -config MWIFIEX_PCIE - tristate "Marvell WiFi-Ex Driver for PCIE 8766/8897/8997" - depends on MWIFIEX && PCI - select FW_LOADER - select WANT_DEV_COREDUMP - ---help--- - This adds support for wireless adapters based on Marvell - 8766/8897/8997 chipsets with PCIe interface. - - If you choose to build it as a module, it will be called - mwifiex_pcie. - -config MWIFIEX_USB - tristate "Marvell WiFi-Ex Driver for USB8766/8797/8997" - depends on MWIFIEX && USB - select FW_LOADER - ---help--- - This adds support for wireless adapters based on Marvell - 8797/8997 chipset with USB interface. - - If you choose to build it as a module, it will be called - mwifiex_usb. diff --git a/src/linux/drivers/net/wireless/mediatek/Kconfig b/src/linux/drivers/net/wireless/mediatek/Kconfig deleted file mode 100644 index 28843fe..0000000 --- a/src/linux/drivers/net/wireless/mediatek/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config WLAN_VENDOR_MEDIATEK - bool "MediaTek devices" - default y - ---help--- - If you have a wireless card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for - your specific card in the following questions. - -if WLAN_VENDOR_MEDIATEK -source "drivers/net/wireless/mediatek/mt7601u/Kconfig" -endif # WLAN_VENDOR_MEDIATEK diff --git a/src/linux/drivers/net/wireless/mediatek/mt7601u/Kconfig b/src/linux/drivers/net/wireless/mediatek/mt7601u/Kconfig deleted file mode 100644 index f46bed9..0000000 --- a/src/linux/drivers/net/wireless/mediatek/mt7601u/Kconfig +++ /dev/null @@ -1,6 +0,0 @@ -config MT7601U - tristate "MediaTek MT7601U (USB) support" - depends on MAC80211 - depends on USB - ---help--- - This adds support for MT7601U-based wireless USB dongles. diff --git a/src/linux/drivers/net/wireless/ralink/Kconfig b/src/linux/drivers/net/wireless/ralink/Kconfig deleted file mode 100644 index 41dbf31..0000000 --- a/src/linux/drivers/net/wireless/ralink/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -config WLAN_VENDOR_RALINK - bool "Ralink devices" - default y - ---help--- - If you have a wireless card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for - your specific card in the following questions. - -if WLAN_VENDOR_RALINK - -source "drivers/net/wireless/ralink/rt2x00/Kconfig" - -endif # WLAN_VENDOR_RALINK diff --git a/src/linux/drivers/net/wireless/ralink/rt2x00/Kconfig b/src/linux/drivers/net/wireless/ralink/rt2x00/Kconfig deleted file mode 100644 index de62f5d..0000000 --- a/src/linux/drivers/net/wireless/ralink/rt2x00/Kconfig +++ /dev/null @@ -1,269 +0,0 @@ -menuconfig RT2X00 - tristate "Ralink driver support" - depends on MAC80211 && HAS_DMA - ---help--- - This will enable the support for the Ralink drivers, - developed in the rt2x00 project . - - These drivers make use of the mac80211 stack. - - When building one of the individual drivers, the rt2x00 library - will also be created. That library (when the driver is built as - a module) will be called rt2x00lib. - - Additionally PCI and USB libraries will also be build depending - on the types of drivers being selected, these libraries will be - called rt2x00pci and rt2x00usb. - -if RT2X00 - -config RT2400PCI - tristate "Ralink rt2400 (PCI/PCMCIA) support" - depends on PCI - select RT2X00_LIB_MMIO - select RT2X00_LIB_PCI - select EEPROM_93CX6 - ---help--- - This adds support for rt2400 wireless chipset family. - Supported chips: RT2460. - - When compiled as a module, this driver will be called rt2400pci. - -config RT2500PCI - tristate "Ralink rt2500 (PCI/PCMCIA) support" - depends on PCI - select RT2X00_LIB_MMIO - select RT2X00_LIB_PCI - select EEPROM_93CX6 - ---help--- - This adds support for rt2500 wireless chipset family. - Supported chips: RT2560. - - When compiled as a module, this driver will be called rt2500pci. - -config RT61PCI - tristate "Ralink rt2501/rt61 (PCI/PCMCIA) support" - depends on PCI - select RT2X00_LIB_PCI - select RT2X00_LIB_MMIO - select RT2X00_LIB_FIRMWARE - select RT2X00_LIB_CRYPTO - select CRC_ITU_T - select EEPROM_93CX6 - ---help--- - This adds support for rt2501 wireless chipset family. - Supported chips: RT2561, RT2561S & RT2661. - - When compiled as a module, this driver will be called rt61pci. - -config RT2800PCI - tristate "Ralink rt27xx/rt28xx/rt30xx (PCI/PCIe/PCMCIA) support" - depends on PCI - select RT2800_LIB - select RT2800_LIB_MMIO - select RT2X00_LIB_MMIO - select RT2X00_LIB_PCI - select RT2X00_LIB_FIRMWARE - select RT2X00_LIB_CRYPTO - select CRC_CCITT - select EEPROM_93CX6 - ---help--- - This adds support for rt27xx/rt28xx/rt30xx wireless chipset family. - Supported chips: RT2760, RT2790, RT2860, RT2880, RT2890, RT3052, - RT3090, RT3091 & RT3092 - - When compiled as a module, this driver will be called "rt2800pci.ko". - -if RT2800PCI - -config RT2800PCI_RT33XX - bool "rt2800pci - Include support for rt33xx devices" - default y - ---help--- - This adds support for rt33xx wireless chipset family to the - rt2800pci driver. - Supported chips: RT3390 - -config RT2800PCI_RT35XX - bool "rt2800pci - Include support for rt35xx devices (EXPERIMENTAL)" - default y - ---help--- - This adds support for rt35xx wireless chipset family to the - rt2800pci driver. - Supported chips: RT3060, RT3062, RT3562, RT3592 - - -config RT2800PCI_RT53XX - bool "rt2800pci - Include support for rt53xx devices (EXPERIMENTAL)" - default y - ---help--- - This adds support for rt53xx wireless chipset family to the - rt2800pci driver. - Supported chips: RT5390 - -config RT2800PCI_RT3290 - bool "rt2800pci - Include support for rt3290 devices (EXPERIMENTAL)" - default y - ---help--- - This adds support for rt3290 wireless chipset family to the - rt2800pci driver. - Supported chips: RT3290 -endif - -config RT2500USB - tristate "Ralink rt2500 (USB) support" - depends on USB - select RT2X00_LIB_USB - select RT2X00_LIB_CRYPTO - ---help--- - This adds support for rt2500 wireless chipset family. - Supported chips: RT2571 & RT2572. - - When compiled as a module, this driver will be called rt2500usb. - -config RT73USB - tristate "Ralink rt2501/rt73 (USB) support" - depends on USB - select RT2X00_LIB_USB - select RT2X00_LIB_FIRMWARE - select RT2X00_LIB_CRYPTO - select CRC_ITU_T - ---help--- - This adds support for rt2501 wireless chipset family. - Supported chips: RT2571W, RT2573 & RT2671. - - When compiled as a module, this driver will be called rt73usb. - -config RT2800USB - tristate "Ralink rt27xx/rt28xx/rt30xx (USB) support" - depends on USB - select RT2800_LIB - select RT2X00_LIB_USB - select RT2X00_LIB_FIRMWARE - select RT2X00_LIB_CRYPTO - select CRC_CCITT - ---help--- - This adds support for rt27xx/rt28xx/rt30xx wireless chipset family. - Supported chips: RT2770, RT2870 & RT3070, RT3071 & RT3072 - - When compiled as a module, this driver will be called "rt2800usb.ko". - -if RT2800USB - -config RT2800USB_RT33XX - bool "rt2800usb - Include support for rt33xx devices" - default y - ---help--- - This adds support for rt33xx wireless chipset family to the - rt2800usb driver. - Supported chips: RT3370 - -config RT2800USB_RT35XX - bool "rt2800usb - Include support for rt35xx devices (EXPERIMENTAL)" - default y - ---help--- - This adds support for rt35xx wireless chipset family to the - rt2800usb driver. - Supported chips: RT3572 - -config RT2800USB_RT3573 - bool "rt2800usb - Include support for rt3573 devices (EXPERIMENTAL)" - ---help--- - This enables support for RT3573 chipset based wireless USB devices - in the rt2800usb driver. - -config RT2800USB_RT53XX - bool "rt2800usb - Include support for rt53xx devices (EXPERIMENTAL)" - ---help--- - This adds support for rt53xx wireless chipset family to the - rt2800usb driver. - Supported chips: RT5370 - -config RT2800USB_RT55XX - bool "rt2800usb - Include support for rt55xx devices (EXPERIMENTAL)" - ---help--- - This adds support for rt55xx wireless chipset family to the - rt2800usb driver. - Supported chips: RT5572 - -config RT2800USB_UNKNOWN - bool "rt2800usb - Include support for unknown (USB) devices" - default n - ---help--- - This adds support for rt2800usb devices that are known to - have a rt28xx family compatible chipset, but for which the exact - chipset is unknown. - - Support status for these devices is unknown, and enabling these - devices may or may not work. - -endif - -config RT2800SOC - tristate "Ralink WiSoC support" - depends on SOC_RT288X || SOC_RT305X - select RT2X00_LIB_SOC - select RT2X00_LIB_MMIO - select RT2X00_LIB_CRYPTO - select RT2X00_LIB_FIRMWARE - select RT2800_LIB - select RT2800_LIB_MMIO - ---help--- - This adds support for Ralink WiSoC devices. - Supported chips: RT2880, RT3050, RT3052, RT3350, RT3352. - - When compiled as a module, this driver will be called rt2800soc. - - -config RT2800_LIB - tristate - -config RT2800_LIB_MMIO - tristate - select RT2X00_LIB_MMIO - select RT2800_LIB - -config RT2X00_LIB_MMIO - tristate - -config RT2X00_LIB_PCI - tristate - select RT2X00_LIB - -config RT2X00_LIB_SOC - tristate - select RT2X00_LIB - -config RT2X00_LIB_USB - tristate - select RT2X00_LIB - -config RT2X00_LIB - tristate - -config RT2X00_LIB_FIRMWARE - bool - select FW_LOADER - -config RT2X00_LIB_CRYPTO - bool - -config RT2X00_LIB_LEDS - bool - default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n) - -config RT2X00_LIB_DEBUGFS - bool "Ralink debugfs support" - depends on RT2X00_LIB && MAC80211_DEBUGFS - ---help--- - Enable creation of debugfs files for the rt2x00 drivers. - These debugfs files support both reading and writing of the - most important register types of the rt2x00 hardware. - -config RT2X00_DEBUG - bool "Ralink debug output" - depends on RT2X00_LIB - ---help--- - Enable debugging output for all rt2x00 modules - -endif diff --git a/src/linux/drivers/net/wireless/realtek/Kconfig b/src/linux/drivers/net/wireless/realtek/Kconfig deleted file mode 100644 index 8a8ba20..0000000 --- a/src/linux/drivers/net/wireless/realtek/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config WLAN_VENDOR_REALTEK - bool "Realtek devices" - default y - ---help--- - If you have a wireless card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for - your specific card in the following questions. - -if WLAN_VENDOR_REALTEK - -source "drivers/net/wireless/realtek/rtl818x/Kconfig" -source "drivers/net/wireless/realtek/rtlwifi/Kconfig" -source "drivers/net/wireless/realtek/rtl8xxxu/Kconfig" - -endif # WLAN_VENDOR_REALTEK diff --git a/src/linux/drivers/net/wireless/realtek/rtl818x/Kconfig b/src/linux/drivers/net/wireless/realtek/rtl818x/Kconfig deleted file mode 100644 index 1ce1d55..0000000 --- a/src/linux/drivers/net/wireless/realtek/rtl818x/Kconfig +++ /dev/null @@ -1,88 +0,0 @@ -# -# RTL818X Wireless LAN device configuration -# -config RTL8180 - tristate "Realtek 8180/8185/8187SE PCI support" - depends on MAC80211 && PCI - select EEPROM_93CX6 - ---help--- - This is a driver for RTL8180, RTL8185 and RTL8187SE based cards. - These are PCI based chips found in cards such as: - - (RTL8185 802.11g) - A-Link WL54PC - - (RTL8180 802.11b) - Belkin F5D6020 v3 - Belkin F5D6020 v3 - Dlink DWL-610 - Dlink DWL-510 - Netgear MA521 - Level-One WPC-0101 - Acer Aspire 1357 LMi - VCTnet PC-11B1 - Ovislink AirLive WL-1120PCM - Mentor WL-PCI - Linksys WPC11 v4 - TrendNET TEW-288PI - D-Link DWL-520 Rev D - Repotec RP-WP7126 - TP-Link TL-WN250/251 - Zonet ZEW1000 - Longshine LCS-8031-R - HomeLine HLW-PCC200 - GigaFast WF721-AEX - Planet WL-3553 - Encore ENLWI-PCI1-NT - TrendNET TEW-266PC - Gigabyte GN-WLMR101 - Siemens-fujitsu Amilo D1840W - Edimax EW-7126 - PheeNet WL-11PCIR - Tonze PC-2100T - Planet WL-8303 - Dlink DWL-650 v M1 - Edimax EW-7106 - Q-Tec 770WC - Topcom Skyr@cer 4011b - Roper FreeLan 802.11b (edition 2004) - Wistron Neweb Corp CB-200B - Pentagram HorNET - QTec 775WC - TwinMOS Booming B Series - Micronet SP906BB - Sweex LC700010 - Surecom EP-9428 - Safecom SWLCR-1100 - - Thanks to Realtek for their support! - -config RTL8187 - tristate "Realtek 8187 and 8187B USB support" - depends on MAC80211 && USB - select EEPROM_93CX6 - ---help--- - This is a driver for RTL8187 and RTL8187B based cards. - These are USB based chips found in devices such as: - - Netgear WG111v2 - Level 1 WNC-0301USB - Micronet SP907GK V5 - Encore ENUWI-G2 - Trendnet TEW-424UB - ASUS P5B Deluxe/P5K Premium motherboards - Toshiba Satellite Pro series of laptops - Asus Wireless Link - Linksys WUSB54GC-EU v2 - (v1 = rt73usb; v3 is rt2070-based, - use staging/rt3070 or try rt2800usb) - - Thanks to Realtek for their support! - -# If possible, automatically enable LEDs for RTL8187. - -config RTL8187_LEDS - bool - depends on RTL8187 && MAC80211_LEDS && (LEDS_CLASS = y || LEDS_CLASS = RTL8187) - default y - diff --git a/src/linux/drivers/net/wireless/realtek/rtl8xxxu/Kconfig b/src/linux/drivers/net/wireless/realtek/rtl8xxxu/Kconfig deleted file mode 100644 index 8f053c3..0000000 --- a/src/linux/drivers/net/wireless/realtek/rtl8xxxu/Kconfig +++ /dev/null @@ -1,34 +0,0 @@ -# -# RTL8XXXU Wireless LAN device configuration -# -config RTL8XXXU - tristate "RTL8723AU/RTL8188[CR]U/RTL819[12]CU (mac80211) support" - depends on MAC80211 && USB - ---help--- - This is an alternative driver for various Realtek RTL8XXX - parts written to utilize the Linux mac80211 stack. - The driver is known to work with a number of RTL8723AU, - RL8188CU, RTL8188RU, RTL8191CU, and RTL8192CU devices - - This driver is under development and has a limited feature - set. In particular it does not yet support 40MHz channels - and power management. However it should have a smaller - memory footprint than the vendor drivers and benefits - from the in kernel mac80211 stack. - - It can coexist with drivers from drivers/staging/rtl8723au, - drivers/staging/rtl8192u, and drivers/net/wireless/rtlwifi, - but you will need to control which module you wish to load. - - To compile this driver as a module, choose M here: the module will - be called r8xxxu. If unsure, say N. - -config RTL8XXXU_UNTESTED - bool "Include support for untested Realtek 8xxx USB devices (EXPERIMENTAL)" - depends on RTL8XXXU - ---help--- - This option enables detection of Realtek 8723/8188/8191/8192 WiFi - USB devices which have not been tested directly by the driver - author or reported to be working by third parties. - - Please report your results! diff --git a/src/linux/drivers/net/wireless/realtek/rtlwifi/Kconfig b/src/linux/drivers/net/wireless/realtek/rtlwifi/Kconfig deleted file mode 100644 index 73067ca..0000000 --- a/src/linux/drivers/net/wireless/realtek/rtlwifi/Kconfig +++ /dev/null @@ -1,154 +0,0 @@ -menuconfig RTL_CARDS - tristate "Realtek rtlwifi family of devices" - depends on MAC80211 && (PCI || USB) - default y - ---help--- - This option will enable support for the Realtek mac80211-based - wireless drivers. Drivers rtl8192ce, rtl8192cu, rtl8192se, rtl8192de, - rtl8723ae, rtl8723be, rtl8188ee, rtl8192ee, and rtl8821ae share - some common code. - -if RTL_CARDS - -config RTL8192CE - tristate "Realtek RTL8192CE/RTL8188CE Wireless Network Adapter" - depends on PCI - select RTL8192C_COMMON - select RTLWIFI - select RTLWIFI_PCI - ---help--- - This is the driver for Realtek RTL8192CE/RTL8188CE 802.11n PCIe - wireless network adapters. - - If you choose to build it as a module, it will be called rtl8192ce - -config RTL8192SE - tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter" - depends on PCI - select RTLWIFI - select RTLWIFI_PCI - ---help--- - This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe - wireless network adapters. - - If you choose to build it as a module, it will be called rtl8192se - -config RTL8192DE - tristate "Realtek RTL8192DE/RTL8188DE PCIe Wireless Network Adapter" - depends on PCI - select RTLWIFI - select RTLWIFI_PCI - ---help--- - This is the driver for Realtek RTL8192DE/RTL8188DE 802.11n PCIe - wireless network adapters. - - If you choose to build it as a module, it will be called rtl8192de - -config RTL8723AE - tristate "Realtek RTL8723AE PCIe Wireless Network Adapter" - depends on PCI - select RTLWIFI - select RTLWIFI_PCI - select RTL8723_COMMON - select RTLBTCOEXIST - ---help--- - This is the driver for Realtek RTL8723AE 802.11n PCIe - wireless network adapters. - - If you choose to build it as a module, it will be called rtl8723ae - -config RTL8723BE - tristate "Realtek RTL8723BE PCIe Wireless Network Adapter" - depends on PCI - select RTLWIFI - select RTLWIFI_PCI - select RTL8723_COMMON - select RTLBTCOEXIST - ---help--- - This is the driver for Realtek RTL8723BE 802.11n PCIe - wireless network adapters. - - If you choose to build it as a module, it will be called rtl8723be - -config RTL8188EE - tristate "Realtek RTL8188EE Wireless Network Adapter" - depends on PCI - select RTLWIFI - select RTLWIFI_PCI - ---help--- - This is the driver for Realtek RTL8188EE 802.11n PCIe - wireless network adapters. - - If you choose to build it as a module, it will be called rtl8188ee - -config RTL8192EE - tristate "Realtek RTL8192EE Wireless Network Adapter" - depends on PCI - select RTLWIFI - select RTLWIFI_PCI - select RTLBTCOEXIST - ---help--- - This is the driver for Realtek RTL8192EE 802.11n PCIe - wireless network adapters. - - If you choose to build it as a module, it will be called rtl8192ee - -config RTL8821AE - tristate "Realtek RTL8821AE/RTL8812AE Wireless Network Adapter" - depends on PCI - select RTLWIFI - select RTLWIFI_PCI - select RTLBTCOEXIST - ---help--- - This is the driver for Realtek RTL8821AE/RTL8812AE 802.11ac PCIe - wireless network adapters. - - If you choose to build it as a module, it will be called rtl8821ae - -config RTL8192CU - tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter" - depends on USB - select RTLWIFI - select RTLWIFI_USB - select RTL8192C_COMMON - ---help--- - This is the driver for Realtek RTL8192CU/RTL8188CU 802.11n USB - wireless network adapters. - - If you choose to build it as a module, it will be called rtl8192cu - -config RTLWIFI - tristate - select FW_LOADER - -config RTLWIFI_PCI - tristate - -config RTLWIFI_USB - tristate - -config RTLWIFI_DEBUG - bool "Debugging output for rtlwifi driver family" - depends on RTLWIFI - default y - ---help--- - To use the module option that sets the dynamic-debugging level for, - the front-end driver, this parameter must be "Y". For memory-limited - systems, choose "N". If in doubt, choose "Y". - -config RTL8192C_COMMON - tristate - depends on RTL8192CE || RTL8192CU - default y - -config RTL8723_COMMON - tristate - depends on RTL8723AE || RTL8723BE - default y - -config RTLBTCOEXIST - tristate - depends on RTL8723AE || RTL8723BE || RTL8821AE || RTL8192EE - default y - -endif diff --git a/src/linux/drivers/net/wireless/rsi/Kconfig b/src/linux/drivers/net/wireless/rsi/Kconfig deleted file mode 100644 index 7c5e4ca..0000000 --- a/src/linux/drivers/net/wireless/rsi/Kconfig +++ /dev/null @@ -1,45 +0,0 @@ -config WLAN_VENDOR_RSI - bool "Redpine Signals Inc devices" - default y - ---help--- - If you have a wireless card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for - your specific card in the following questions. - -if WLAN_VENDOR_RSI - -config RSI_91X - tristate "Redpine Signals Inc 91x WLAN driver support" - depends on MAC80211 - ---help--- - This option enabes support for RSI 1x1 devices. - Select M (recommended), if you have a RSI 1x1 wireless module. - -config RSI_DEBUGFS - bool "Redpine Signals Inc debug support" - depends on RSI_91X - default y - ---help--- - Say Y, if you would like to enable debug support. This option - creates debugfs entries - -config RSI_SDIO - tristate "Redpine Signals SDIO bus support" - depends on MMC && RSI_91X - default m - ---help--- - This option enables the SDIO bus support in rsi drivers. - Select M (recommended), if you have a RSI 1x1 wireless module. - -config RSI_USB - tristate "Redpine Signals USB bus support" - depends on USB && RSI_91X - default m - ---help--- - This option enables the USB bus support in rsi drivers. - Select M (recommended), if you have a RSI 1x1 wireless module. - -endif # WLAN_VENDOR_RSI diff --git a/src/linux/drivers/net/wireless/st/Kconfig b/src/linux/drivers/net/wireless/st/Kconfig deleted file mode 100644 index 969b4f6..0000000 --- a/src/linux/drivers/net/wireless/st/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -config WLAN_VENDOR_ST - bool "STMicroelectronics devices" - default y - ---help--- - If you have a wireless card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for - your specific card in the following questions. - -if WLAN_VENDOR_ST - -source "drivers/net/wireless/st/cw1200/Kconfig" - -endif # WLAN_VENDOR_ST diff --git a/src/linux/drivers/net/wireless/st/cw1200/Kconfig b/src/linux/drivers/net/wireless/st/cw1200/Kconfig deleted file mode 100644 index 0880742..0000000 --- a/src/linux/drivers/net/wireless/st/cw1200/Kconfig +++ /dev/null @@ -1,30 +0,0 @@ -config CW1200 - tristate "CW1200 WLAN support" - depends on MAC80211 && CFG80211 - help - This is a driver for the ST-E CW1100 & CW1200 WLAN chipsets. - This option just enables the driver core, see below for - specific bus support. - -if CW1200 - -config CW1200_WLAN_SDIO - tristate "Support SDIO platforms" - depends on CW1200 && MMC - help - Enable support for the CW1200 connected via an SDIO bus. - By default this driver only supports the Sagrad SG901-1091/1098 EVK - and similar designs that utilize a hardware reset circuit. To - support different CW1200 SDIO designs you will need to override - the default platform data by calling cw1200_sdio_set_platform_data() - in your board setup file. - -config CW1200_WLAN_SPI - tristate "Support SPI platforms" - depends on CW1200 && SPI - help - Enables support for the CW1200 connected via a SPI bus. You will - need to add appropriate platform data glue in your board setup - file. - -endif diff --git a/src/linux/drivers/net/wireless/ti/Kconfig b/src/linux/drivers/net/wireless/ti/Kconfig deleted file mode 100644 index 92fbd65..0000000 --- a/src/linux/drivers/net/wireless/ti/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -config WLAN_VENDOR_TI - bool "Texas Instrument devices" - default y - ---help--- - If you have a wireless card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for - your specific card in the following questions. - -if WLAN_VENDOR_TI -source "drivers/net/wireless/ti/wl1251/Kconfig" -source "drivers/net/wireless/ti/wl12xx/Kconfig" -source "drivers/net/wireless/ti/wl18xx/Kconfig" - -# keep last for automatic dependencies -source "drivers/net/wireless/ti/wlcore/Kconfig" - -config WILINK_PLATFORM_DATA - bool "TI WiLink platform data" - depends on WLCORE_SDIO || WL1251_SDIO - default y - ---help--- - Small platform data bit needed to pass data to the sdio modules. - - -endif # WLAN_VENDOR_TI diff --git a/src/linux/drivers/net/wireless/ti/wl1251/Kconfig b/src/linux/drivers/net/wireless/ti/wl1251/Kconfig deleted file mode 100644 index 7142ccf..0000000 --- a/src/linux/drivers/net/wireless/ti/wl1251/Kconfig +++ /dev/null @@ -1,33 +0,0 @@ -config WL1251 - tristate "TI wl1251 driver support" - depends on MAC80211 - select FW_LOADER - select CRC7 - ---help--- - This will enable TI wl1251 driver support. The drivers make - use of the mac80211 stack. - - If you choose to build a module, it'll be called wl1251. Say - N if unsure. - -config WL1251_SPI - tristate "TI wl1251 SPI support" - depends on WL1251 && SPI_MASTER - ---help--- - This module adds support for the SPI interface of adapters using - TI wl1251 chipset. Select this if your platform is using - the SPI bus. - - If you choose to build a module, it'll be called wl1251_spi. - Say N if unsure. - -config WL1251_SDIO - tristate "TI wl1251 SDIO support" - depends on WL1251 && MMC - ---help--- - This module adds support for the SDIO interface of adapters using - TI wl1251 chipset. Select this if your platform is using - the SDIO bus. - - If you choose to build a module, it'll be called - wl1251_sdio. Say N if unsure. diff --git a/src/linux/drivers/net/wireless/ti/wl12xx/Kconfig b/src/linux/drivers/net/wireless/ti/wl12xx/Kconfig deleted file mode 100644 index c218359..0000000 --- a/src/linux/drivers/net/wireless/ti/wl12xx/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config WL12XX - tristate "TI wl12xx support" - depends on MAC80211 - select WLCORE - ---help--- - This module adds support for wireless adapters based on TI wl1271, - wl1273, wl1281 and wl1283 chipsets. This module does *not* include - support for wl1251. For wl1251 support, use the separate homonymous - driver instead. diff --git a/src/linux/drivers/net/wireless/ti/wl18xx/Kconfig b/src/linux/drivers/net/wireless/ti/wl18xx/Kconfig deleted file mode 100644 index 1cfdb25..0000000 --- a/src/linux/drivers/net/wireless/ti/wl18xx/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -config WL18XX - tristate "TI wl18xx support" - depends on MAC80211 - select WLCORE - ---help--- - This module adds support for wireless adapters based on TI - WiLink 8 chipsets. diff --git a/src/linux/drivers/net/wireless/ti/wlcore/Kconfig b/src/linux/drivers/net/wireless/ti/wlcore/Kconfig deleted file mode 100644 index 8a8f1e7..0000000 --- a/src/linux/drivers/net/wireless/ti/wlcore/Kconfig +++ /dev/null @@ -1,35 +0,0 @@ -config WLCORE - tristate "TI wlcore support" - depends on MAC80211 - select FW_LOADER - ---help--- - This module contains the main code for TI WLAN chips. It abstracts - hardware-specific differences among different chipset families. - Each chipset family needs to implement its own lower-level module - that will depend on this module for the common code. - - If you choose to build a module, it will be called wlcore. Say N if - unsure. - -config WLCORE_SPI - tristate "TI wlcore SPI support" - depends on WLCORE && SPI_MASTER && OF - select CRC7 - ---help--- - This module adds support for the SPI interface of adapters using - TI WLAN chipsets. Select this if your platform is using - the SPI bus. - - If you choose to build a module, it'll be called wlcore_spi. - Say N if unsure. - -config WLCORE_SDIO - tristate "TI wlcore SDIO support" - depends on WLCORE && MMC - ---help--- - This module adds support for the SDIO interface of adapters using - TI WLAN chipsets. Select this if your platform is using - the SDIO bus. - - If you choose to build a module, it'll be called wlcore_sdio. - Say N if unsure. diff --git a/src/linux/drivers/net/wireless/zydas/Kconfig b/src/linux/drivers/net/wireless/zydas/Kconfig deleted file mode 100644 index a58c0f6..0000000 --- a/src/linux/drivers/net/wireless/zydas/Kconfig +++ /dev/null @@ -1,35 +0,0 @@ -config WLAN_VENDOR_ZYDAS - bool "ZyDAS devices" - default y - ---help--- - If you have a wireless card belonging to this class, say Y. - - Note that the answer to this question doesn't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about cards. If you say Y, you will be asked for - your specific card in the following questions. - -if WLAN_VENDOR_ZYDAS - -config USB_ZD1201 - tristate "USB ZD1201 based Wireless device support" - depends on CFG80211 && USB - select WIRELESS_EXT - select WEXT_PRIV - select FW_LOADER - ---help--- - Say Y if you want to use wireless LAN adapters based on the ZyDAS - ZD1201 chip. - - This driver makes the adapter appear as a normal Ethernet interface, - typically on wlan0. - - The zd1201 device requires external firmware to be loaded. - This can be found at http://linux-lc100020.sourceforge.net/ - - To compile this driver as a module, choose M here: the - module will be called zd1201. - -source "drivers/net/wireless/zydas/zd1211rw/Kconfig" - -endif # WLAN_VENDOR_ZYDAS diff --git a/src/linux/drivers/net/wireless/zydas/zd1211rw/Kconfig b/src/linux/drivers/net/wireless/zydas/zd1211rw/Kconfig deleted file mode 100644 index 9592058..0000000 --- a/src/linux/drivers/net/wireless/zydas/zd1211rw/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -config ZD1211RW - tristate "ZyDAS ZD1211/ZD1211B USB-wireless support" - depends on USB && MAC80211 - select FW_LOADER - ---help--- - This is a driver for the ZyDAS ZD1211/ZD1211B wireless - chip, present in many USB-wireless adapters. - - Device firmware is required alongside this driver. You can download - the firmware distribution from http://sf.net/projects/zd1211/files/ - -config ZD1211RW_DEBUG - bool "ZyDAS ZD1211 debugging" - depends on ZD1211RW - ---help--- - ZD1211 debugging messages. Choosing Y will result in additional debug - messages being saved to your kernel logs, which may help debug any - problems. - diff --git a/src/linux/drivers/nfc/Kconfig b/src/linux/drivers/nfc/Kconfig deleted file mode 100644 index 9d23692..0000000 --- a/src/linux/drivers/nfc/Kconfig +++ /dev/null @@ -1,72 +0,0 @@ -# -# Near Field Communication (NFC) devices -# - -menu "Near Field Communication (NFC) devices" - depends on NFC - -config NFC_WILINK - tristate "Texas Instruments NFC WiLink driver" - depends on TI_ST && NFC_NCI - help - This enables the NFC driver for Texas Instrument's BT/FM/GPS/NFC - combo devices. This makes use of shared transport line discipline - core driver to communicate with the NFC core of the combo chip. - - Say Y here to compile support for Texas Instrument's NFC WiLink driver - into the kernel or say M to compile it as module. - -config NFC_TRF7970A - tristate "Texas Instruments TRF7970a NFC driver" - depends on SPI && NFC_DIGITAL - help - This option enables the NFC driver for Texas Instruments' TRF7970a - device. Such device supports 5 different protocols: ISO14443A, - ISO14443B, FeLiCa, ISO15693 and ISO18000-3. - - Say Y here to compile support for TRF7970a into the kernel or - say M to compile it as a module. The module will be called - trf7970a.ko. - -config NFC_MEI_PHY - tristate "MEI bus NFC device support" - depends on INTEL_MEI && NFC_HCI - help - This adds support to use an mei bus nfc device. Select this if you - will use an HCI NFC driver for an NFC chip connected behind an - Intel's Management Engine chip. - - If unsure, say N. - -config NFC_SIM - tristate "NFC hardware simulator driver" - depends on NFC_DIGITAL - help - This driver declares two virtual NFC devices supporting NFC-DEP - protocol. An LLCP connection can be established between them and - all packets sent from one device is sent back to the other, acting as - loopback devices. - - If unsure, say N. - -config NFC_PORT100 - tristate "Sony NFC Port-100 Series USB device support" - depends on USB - depends on NFC_DIGITAL - help - This adds support for Sony Port-100 chip based USB devices such as the - RC-S380 dongle. - - If unsure, say N. - -source "drivers/nfc/fdp/Kconfig" -source "drivers/nfc/pn544/Kconfig" -source "drivers/nfc/pn533/Kconfig" -source "drivers/nfc/microread/Kconfig" -source "drivers/nfc/nfcmrvl/Kconfig" -source "drivers/nfc/st21nfca/Kconfig" -source "drivers/nfc/st-nci/Kconfig" -source "drivers/nfc/nxp-nci/Kconfig" -source "drivers/nfc/s3fwrn5/Kconfig" -source "drivers/nfc/st95hf/Kconfig" -endmenu diff --git a/src/linux/drivers/nfc/Makefile b/src/linux/drivers/nfc/Makefile deleted file mode 100644 index bab8ef0..0000000 --- a/src/linux/drivers/nfc/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# -# Makefile for nfc devices -# - -obj-$(CONFIG_NFC_FDP) += fdp/ -obj-$(CONFIG_NFC_PN544) += pn544/ -obj-$(CONFIG_NFC_MICROREAD) += microread/ -obj-$(CONFIG_NFC_PN533) += pn533/ -obj-$(CONFIG_NFC_WILINK) += nfcwilink.o -obj-$(CONFIG_NFC_MEI_PHY) += mei_phy.o -obj-$(CONFIG_NFC_SIM) += nfcsim.o -obj-$(CONFIG_NFC_PORT100) += port100.o -obj-$(CONFIG_NFC_MRVL) += nfcmrvl/ -obj-$(CONFIG_NFC_TRF7970A) += trf7970a.o -obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/ -obj-$(CONFIG_NFC_ST_NCI) += st-nci/ -obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci/ -obj-$(CONFIG_NFC_S3FWRN5) += s3fwrn5/ -obj-$(CONFIG_NFC_ST95HF) += st95hf/ diff --git a/src/linux/drivers/nfc/fdp/Kconfig b/src/linux/drivers/nfc/fdp/Kconfig deleted file mode 100644 index fbccd9d..0000000 --- a/src/linux/drivers/nfc/fdp/Kconfig +++ /dev/null @@ -1,23 +0,0 @@ -config NFC_FDP - tristate "Intel FDP NFC driver" - depends on NFC_NCI - select CRC_CCITT - default n - ---help--- - Intel Fields Peak NFC controller core driver. - This is a driver based on the NCI NFC kernel layers. - - To compile this driver as a module, choose m here. The module will - be called fdp. - Say N if unsure. - -config NFC_FDP_I2C - tristate "NFC FDP i2c support" - depends on NFC_FDP && I2C - ---help--- - This module adds support for the Intel Fields Peak NFC controller - i2c interface. - Select this if your platform is using the i2c bus. - - If you choose to build a module, it'll be called fdp_i2c. - Say N if unsure. diff --git a/src/linux/drivers/nfc/microread/Kconfig b/src/linux/drivers/nfc/microread/Kconfig deleted file mode 100644 index 2c6dbc9..0000000 --- a/src/linux/drivers/nfc/microread/Kconfig +++ /dev/null @@ -1,31 +0,0 @@ -config NFC_MICROREAD - tristate - select CRC_CCITT - ---help--- - This module contains the main code for Inside Secure microread - NFC chipsets. It implements the chipset HCI logic and hooks into - the NFC kernel APIs. Physical layers will register against it. - -config NFC_MICROREAD_I2C - tristate "Inside Secure Microread device support (I2C)" - depends on NFC_HCI && I2C && NFC_SHDLC - select NFC_MICROREAD - ---help--- - This module adds support for the i2c interface of adapters using - Inside microread chipsets. Select this if your platform is using - the i2c bus. - - If you choose to build a module, it'll be called microread_i2c. - Say N if unsure. - -config NFC_MICROREAD_MEI - tristate "Inside Secure Microread device support (MEI)" - depends on NFC_HCI && NFC_MEI_PHY - select NFC_MICROREAD - ---help--- - This module adds support for the mei interface of adapters using - Inside microread chipsets. Select this if your microread chipset - is handled by Intel's Management Engine Interface on your platform. - - If you choose to build a module, it'll be called microread_mei. - Say N if unsure. diff --git a/src/linux/drivers/nfc/nfcmrvl/Kconfig b/src/linux/drivers/nfc/nfcmrvl/Kconfig deleted file mode 100644 index 670af76..0000000 --- a/src/linux/drivers/nfc/nfcmrvl/Kconfig +++ /dev/null @@ -1,54 +0,0 @@ -config NFC_MRVL - tristate - help - The core driver to support Marvell NFC devices. - - This driver is required if you want to support - Marvell NFC device 8897. - -config NFC_MRVL_USB - tristate "Marvell NFC-over-USB driver" - depends on NFC_NCI && USB - select NFC_MRVL - help - Marvell NFC-over-USB driver. - - This driver provides support for Marvell NFC-over-USB devices: - 8897. - - Say Y here to compile support for Marvell NFC-over-USB driver - into the kernel or say M to compile it as module. - -config NFC_MRVL_UART - tristate "Marvell NFC-over-UART driver" - depends on NFC_NCI && NFC_NCI_UART - select NFC_MRVL - help - Marvell NFC-over-UART driver. - - This driver provides support for Marvell NFC-over-UART devices - - Say Y here to compile support for Marvell NFC-over-UART driver - into the kernel or say M to compile it as module. - -config NFC_MRVL_I2C - tristate "Marvell NFC-over-I2C driver" - depends on NFC_MRVL && I2C - help - Marvell NFC-over-I2C driver. - - This driver provides support for Marvell NFC-over-I2C devices. - - Say Y here to compile support for Marvell NFC-over-I2C driver - into the kernel or say M to compile it as module. - -config NFC_MRVL_SPI - tristate "Marvell NFC-over-SPI driver" - depends on NFC_MRVL && NFC_NCI_SPI - help - Marvell NFC-over-SPI driver. - - This driver provides support for Marvell NFC-over-SPI devices. - - Say Y here to compile support for Marvell NFC-over-SPI driver - into the kernel or say M to compile it as module. diff --git a/src/linux/drivers/nfc/nxp-nci/Kconfig b/src/linux/drivers/nfc/nxp-nci/Kconfig deleted file mode 100644 index 37b4061..0000000 --- a/src/linux/drivers/nfc/nxp-nci/Kconfig +++ /dev/null @@ -1,25 +0,0 @@ -config NFC_NXP_NCI - tristate "NXP-NCI NFC driver" - depends on NFC_NCI - default n - ---help--- - Generic core driver for NXP NCI chips such as the NPC100 - or PN7150 families. - This is a driver based on the NCI NFC kernel layers and - will thus not work with NXP libnfc library. - - To compile this driver as a module, choose m here. The module will - be called nxp_nci. - Say N if unsure. - -config NFC_NXP_NCI_I2C - tristate "NXP-NCI I2C support" - depends on NFC_NXP_NCI && I2C - ---help--- - This module adds support for an I2C interface to the NXP NCI - chips. - Select this if your platform is using the I2C bus. - - To compile this driver as a module, choose m here. The module will - be called nxp_nci_i2c. - Say Y if unsure. diff --git a/src/linux/drivers/nfc/pn533/Kconfig b/src/linux/drivers/nfc/pn533/Kconfig deleted file mode 100644 index d94122d..0000000 --- a/src/linux/drivers/nfc/pn533/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -config NFC_PN533 - tristate - help - NXP PN533 core driver. - This driver provides core functionality for NXP PN533 NFC devices. - -config NFC_PN533_USB - tristate "NFC PN533 device support (USB)" - depends on USB - select NFC_PN533 - ---help--- - This module adds support for the NXP pn533 USB interface. - Select this if your platform is using the USB bus. - - If you choose to build a module, it'll be called pn533_usb. - Say N if unsure. - -config NFC_PN533_I2C - tristate "NFC PN533 device support (I2C)" - depends on I2C - select NFC_PN533 - ---help--- - This module adds support for the NXP pn533 I2C interface. - Select this if your platform is using the I2C bus. - - If you choose to build a module, it'll be called pn533_i2c. - Say N if unsure. diff --git a/src/linux/drivers/nfc/pn544/Kconfig b/src/linux/drivers/nfc/pn544/Kconfig deleted file mode 100644 index 2b8bde3..0000000 --- a/src/linux/drivers/nfc/pn544/Kconfig +++ /dev/null @@ -1,30 +0,0 @@ -config NFC_PN544 - tristate - select CRC_CCITT - ---help--- - NXP PN544 core driver. - This is a driver based on the HCI NFC kernel layers and - will thus not work with NXP libnfc library. - -config NFC_PN544_I2C - tristate "NXP PN544 device support (I2C)" - depends on NFC_HCI && I2C && NFC_SHDLC - select NFC_PN544 - ---help--- - This module adds support for the NXP pn544 i2c interface. - Select this if your platform is using the i2c bus. - - If you choose to build a module, it'll be called pn544_i2c. - Say N if unsure. - -config NFC_PN544_MEI - tristate "NXP PN544 device support (MEI)" - depends on NFC_HCI && NFC_MEI_PHY - select NFC_PN544 - ---help--- - This module adds support for the mei interface of adapters using - NXP pn544 chipsets. Select this if your pn544 chipset - is handled by Intel's Management Engine Interface on your platform. - - If you choose to build a module, it'll be called pn544_mei. - Say N if unsure. diff --git a/src/linux/drivers/nfc/s3fwrn5/Kconfig b/src/linux/drivers/nfc/s3fwrn5/Kconfig deleted file mode 100644 index 1eef919..0000000 --- a/src/linux/drivers/nfc/s3fwrn5/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -config NFC_S3FWRN5 - tristate - select CRYPTO - ---help--- - Core driver for Samsung S3FWRN5 NFC chip. Contains core utilities - of chip. It's intended to be used by PHYs to avoid duplicating lots - of common code. - -config NFC_S3FWRN5_I2C - tristate "Samsung S3FWRN5 I2C support" - depends on NFC_NCI && I2C - select NFC_S3FWRN5 - default n - ---help--- - This module adds support for an I2C interface to the S3FWRN5 chip. - Select this if your platform is using the I2C bus. - - To compile this driver as a module, choose m here. The module will - be called s3fwrn5_i2c.ko. - Say N if unsure. diff --git a/src/linux/drivers/nfc/st-nci/Kconfig b/src/linux/drivers/nfc/st-nci/Kconfig deleted file mode 100644 index dc9b777..0000000 --- a/src/linux/drivers/nfc/st-nci/Kconfig +++ /dev/null @@ -1,30 +0,0 @@ -config NFC_ST_NCI - tristate - ---help--- - STMicroelectronics NFC NCI chips core driver. It implements the chipset - NCI logic and hooks into the NFC kernel APIs. Physical layers will - register against it. - -config NFC_ST_NCI_I2C - tristate "STMicroelectronics ST NCI NFC driver (I2C)" - depends on NFC_NCI && I2C - select NFC_ST_NCI - ---help--- - This module adds support for an I2C interface to the - STMicroelectronics NFC NCI chips familly. - Select this if your platform is using the i2c bus. - - If you choose to build a module, it'll be called st-nci_i2c. - Say N if unsure. - -config NFC_ST_NCI_SPI - tristate "STMicroelectronics ST NCI NFC driver (SPI)" - depends on NFC_NCI && SPI - select NFC_ST_NCI - ---help--- - This module adds support for an SPI interface to the - STMicroelectronics NFC NCI chips familly. - Select this if your platform is using the spi bus. - - If you choose to build a module, it'll be called st-nci_spi. - Say N if unsure. diff --git a/src/linux/drivers/nfc/st21nfca/Kconfig b/src/linux/drivers/nfc/st21nfca/Kconfig deleted file mode 100644 index cc3bd56..0000000 --- a/src/linux/drivers/nfc/st21nfca/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config NFC_ST21NFCA - tristate - select CRC_CCITT - ---help--- - STMicroelectronics ST21NFCA core driver. It implements the chipset - HCI logic and hooks into the NFC kernel APIs. Physical layers will - register against it. - -config NFC_ST21NFCA_I2C - tristate "STMicroelectronics ST21NFCA NFC driver (I2C)" - depends on NFC_HCI && I2C && NFC_SHDLC - select NFC_ST21NFCA - ---help--- - This module adds support for the STMicroelectronics st21nfca i2c interface. - Select this if your platform is using the i2c bus. - - If you choose to build a module, it'll be called st21nfca_i2c. - Say N if unsure. diff --git a/src/linux/drivers/nfc/st95hf/Kconfig b/src/linux/drivers/nfc/st95hf/Kconfig deleted file mode 100644 index 224f266..0000000 --- a/src/linux/drivers/nfc/st95hf/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config NFC_ST95HF - tristate "ST95HF NFC Transceiver driver" - depends on SPI && NFC_DIGITAL - help - This enables the ST NFC driver for ST95HF NFC transceiver. - This makes use of SPI framework to communicate with transceiver - and registered with NFC digital core to support Linux NFC framework. - - Say Y here to compile support for ST NFC transceiver ST95HF - linux driver into the kernel or say M to compile it as module. diff --git a/src/linux/drivers/ntb/Kconfig b/src/linux/drivers/ntb/Kconfig deleted file mode 100644 index 95944e5..0000000 --- a/src/linux/drivers/ntb/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -menuconfig NTB - tristate "Non-Transparent Bridge support" - depends on PCI - help - The PCI-E Non-transparent bridge hardware is a point-to-point PCI-E bus - connecting 2 systems. When configured, writes to the device's PCI - mapped memory will be mirrored to a buffer on the remote system. The - ntb Linux driver uses this point-to-point communication as a method to - transfer data from one system to the other. - - If unsure, say N. - -if NTB - -source "drivers/ntb/hw/Kconfig" - -source "drivers/ntb/test/Kconfig" - -config NTB_TRANSPORT - tristate "NTB Transport Client" - help - This is a transport driver that enables connected systems to exchange - messages over the ntb hardware. The transport exposes a queue pair api - to client drivers. - - If unsure, say N. - -endif # NTB diff --git a/src/linux/drivers/ntb/hw/Kconfig b/src/linux/drivers/ntb/hw/Kconfig deleted file mode 100644 index 7116472..0000000 --- a/src/linux/drivers/ntb/hw/Kconfig +++ /dev/null @@ -1,2 +0,0 @@ -source "drivers/ntb/hw/amd/Kconfig" -source "drivers/ntb/hw/intel/Kconfig" diff --git a/src/linux/drivers/ntb/hw/amd/Kconfig b/src/linux/drivers/ntb/hw/amd/Kconfig deleted file mode 100644 index cfe903c..0000000 --- a/src/linux/drivers/ntb/hw/amd/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -config NTB_AMD - tristate "AMD Non-Transparent Bridge support" - depends on X86_64 - help - This driver supports AMD NTB on capable Zeppelin hardware. - - If unsure, say N. diff --git a/src/linux/drivers/ntb/hw/intel/Kconfig b/src/linux/drivers/ntb/hw/intel/Kconfig deleted file mode 100644 index 91f995e..0000000 --- a/src/linux/drivers/ntb/hw/intel/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -config NTB_INTEL - tristate "Intel Non-Transparent Bridge support" - depends on X86_64 - help - This driver supports Intel NTB on capable Xeon and Atom hardware. - - If unsure, say N. diff --git a/src/linux/drivers/ntb/test/Kconfig b/src/linux/drivers/ntb/test/Kconfig deleted file mode 100644 index a5d0eda..0000000 --- a/src/linux/drivers/ntb/test/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -config NTB_PINGPONG - tristate "NTB Ping Pong Test Client" - help - This is a simple ping pong driver that exercises the scratchpads and - doorbells of the ntb hardware. This driver may be used to test that - your ntb hardware and drivers are functioning at a basic level. - - If unsure, say N. - -config NTB_TOOL - tristate "NTB Debugging Tool Test Client" - help - This is a simple debugging driver that enables the doorbell and - scratchpad registers to be read and written from the debugfs. This - enables more complicated debugging to be scripted from user space. - This driver may be used to test that your ntb hardware and drivers are - functioning at a basic level. - - If unsure, say N. - -config NTB_PERF - tristate "NTB RAW Perf Measuring Tool" - help - This is a tool to measure raw NTB performance by transferring data - to and from the window without additional software interaction. - - If unsure, say N. diff --git a/src/linux/drivers/nvdimm/Kconfig b/src/linux/drivers/nvdimm/Kconfig deleted file mode 100644 index 124c243..0000000 --- a/src/linux/drivers/nvdimm/Kconfig +++ /dev/null @@ -1,104 +0,0 @@ -menuconfig LIBNVDIMM - tristate "NVDIMM (Non-Volatile Memory Device) Support" - depends on PHYS_ADDR_T_64BIT - depends on HAS_IOMEM - depends on BLK_DEV - help - Generic support for non-volatile memory devices including - ACPI-6-NFIT defined resources. On platforms that define an - NFIT, or otherwise can discover NVDIMM resources, a libnvdimm - bus is registered to advertise PMEM (persistent memory) - namespaces (/dev/pmemX) and BLK (sliding mmio window(s)) - namespaces (/dev/ndblkX.Y). A PMEM namespace refers to a - memory resource that may span multiple DIMMs and support DAX - (see CONFIG_DAX). A BLK namespace refers to an NVDIMM control - region which exposes an mmio register set for windowed access - mode to non-volatile memory. - -if LIBNVDIMM - -config BLK_DEV_PMEM - tristate "PMEM: Persistent memory block device support" - default LIBNVDIMM - select ND_BTT if BTT - select ND_PFN if NVDIMM_PFN - help - Memory ranges for PMEM are described by either an NFIT - (NVDIMM Firmware Interface Table, see CONFIG_NFIT_ACPI), a - non-standard OEM-specific E820 memory type (type-12, see - CONFIG_X86_PMEM_LEGACY), or it is manually specified by the - 'memmap=nn[KMG]!ss[KMG]' kernel command line (see - Documentation/kernel-parameters.txt). This driver converts - these persistent memory ranges into block devices that are - capable of DAX (direct-access) file system mappings. See - Documentation/nvdimm/nvdimm.txt for more details. - - Say Y if you want to use an NVDIMM - -config ND_BLK - tristate "BLK: Block data window (aperture) device support" - default LIBNVDIMM - select ND_BTT if BTT - help - Support NVDIMMs, or other devices, that implement a BLK-mode - access capability. BLK-mode access uses memory-mapped-i/o - apertures to access persistent media. - - Say Y if your platform firmware emits an ACPI.NFIT table - (CONFIG_ACPI_NFIT), or otherwise exposes BLK-mode - capabilities. - -config ND_CLAIM - bool - -config ND_BTT - tristate - -config BTT - bool "BTT: Block Translation Table (atomic sector updates)" - default y if LIBNVDIMM - select ND_CLAIM - help - The Block Translation Table (BTT) provides atomic sector - update semantics for persistent memory devices, so that - applications that rely on sector writes not being torn (a - guarantee that typical disks provide) can continue to do so. - The BTT manifests itself as an alternate personality for an - NVDIMM namespace, i.e. a namespace can be in raw mode (pmemX, - ndblkX.Y, etc...), or 'sectored' mode, (pmemXs, ndblkX.Ys, - etc...). - - Select Y if unsure - -config ND_PFN - tristate - -config NVDIMM_PFN - bool "PFN: Map persistent (device) memory" - default LIBNVDIMM - depends on ZONE_DEVICE - select ND_CLAIM - help - Map persistent memory, i.e. advertise it to the memory - management sub-system. By default persistent memory does - not support direct I/O, RDMA, or any other usage that - requires a 'struct page' to mediate an I/O request. This - driver allocates and initializes the infrastructure needed - to support those use cases. - - Select Y if unsure - -config NVDIMM_DAX - bool "NVDIMM DAX: Raw access to persistent memory" - default LIBNVDIMM - depends on NVDIMM_PFN - help - Support raw device dax access to a persistent memory - namespace. For environments that want to hard partition - peristent memory, this capability provides a mechanism to - sub-divide a namespace into character devices that can only be - accessed via DAX (mmap(2)). - - Select Y if unsure - -endif diff --git a/src/linux/drivers/nvme/Kconfig b/src/linux/drivers/nvme/Kconfig deleted file mode 100644 index b7c78a5..0000000 --- a/src/linux/drivers/nvme/Kconfig +++ /dev/null @@ -1,2 +0,0 @@ -source "drivers/nvme/host/Kconfig" -source "drivers/nvme/target/Kconfig" diff --git a/src/linux/drivers/nvme/Makefile b/src/linux/drivers/nvme/Makefile deleted file mode 100644 index 0096a7f..0000000 --- a/src/linux/drivers/nvme/Makefile +++ /dev/null @@ -1,3 +0,0 @@ - -obj-y += host/ -obj-y += target/ diff --git a/src/linux/drivers/nvme/host/Kconfig b/src/linux/drivers/nvme/host/Kconfig deleted file mode 100644 index f7d37a6..0000000 --- a/src/linux/drivers/nvme/host/Kconfig +++ /dev/null @@ -1,45 +0,0 @@ -config NVME_CORE - tristate - -config BLK_DEV_NVME - tristate "NVM Express block device" - depends on PCI && BLOCK - select NVME_CORE - ---help--- - The NVM Express driver is for solid state drives directly - connected to the PCI or PCI Express bus. If you know you - don't have one of these, it is safe to answer N. - - To compile this driver as a module, choose M here: the - module will be called nvme. - -config BLK_DEV_NVME_SCSI - bool "SCSI emulation for NVMe device nodes" - depends on NVME_CORE - ---help--- - This adds support for the SG_IO ioctl on the NVMe character - and block devices nodes, as well as a translation for a small - number of selected SCSI commands to NVMe commands to the NVMe - driver. If you don't know what this means you probably want - to say N here, unless you run a distro that abuses the SCSI - emulation to provide stable device names for mount by id, like - some OpenSuSE and SLES versions. - -config NVME_FABRICS - tristate - -config NVME_RDMA - tristate "NVM Express over Fabrics RDMA host driver" - depends on INFINIBAND && BLOCK - select NVME_CORE - select NVME_FABRICS - select SG_POOL - help - This provides support for the NVMe over Fabrics protocol using - the RDMA (Infiniband, RoCE, iWarp) transport. This allows you - to use remote block devices exported using the NVMe protocol set. - - To configure a NVMe over Fabrics controller use the nvme-cli tool - from https://github.com/linux-nvme/nvme-cli. - - If unsure, say N. diff --git a/src/linux/drivers/nvme/host/Makefile b/src/linux/drivers/nvme/host/Makefile deleted file mode 100644 index 47abcec..0000000 --- a/src/linux/drivers/nvme/host/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -obj-$(CONFIG_NVME_CORE) += nvme-core.o -obj-$(CONFIG_BLK_DEV_NVME) += nvme.o -obj-$(CONFIG_NVME_FABRICS) += nvme-fabrics.o -obj-$(CONFIG_NVME_RDMA) += nvme-rdma.o - -nvme-core-y := core.o -nvme-core-$(CONFIG_BLK_DEV_NVME_SCSI) += scsi.o -nvme-core-$(CONFIG_NVM) += lightnvm.o - -nvme-y += pci.o - -nvme-fabrics-y += fabrics.o - -nvme-rdma-y += rdma.o diff --git a/src/linux/drivers/nvme/target/Kconfig b/src/linux/drivers/nvme/target/Kconfig deleted file mode 100644 index 3a5b9d0..0000000 --- a/src/linux/drivers/nvme/target/Kconfig +++ /dev/null @@ -1,36 +0,0 @@ - -config NVME_TARGET - tristate "NVMe Target support" - depends on BLOCK - depends on CONFIGFS_FS - help - This enabled target side support for the NVMe protocol, that is - it allows the Linux kernel to implement NVMe subsystems and - controllers and export Linux block devices as NVMe namespaces. - You need to select at least one of the transports below to make this - functionality useful. - - To configure the NVMe target you probably want to use the nvmetcli - tool from http://git.infradead.org/users/hch/nvmetcli.git. - -config NVME_TARGET_LOOP - tristate "NVMe loopback device support" - depends on NVME_TARGET - select NVME_CORE - select NVME_FABRICS - select SG_POOL - help - This enables the NVMe loopback device support, which can be useful - to test NVMe host and target side features. - - If unsure, say N. - -config NVME_TARGET_RDMA - tristate "NVMe over Fabrics RDMA target support" - depends on INFINIBAND - depends on NVME_TARGET - help - This enables the NVMe RDMA target support, which allows exporting NVMe - devices over RDMA. - - If unsure, say N. diff --git a/src/linux/drivers/nvme/target/Makefile b/src/linux/drivers/nvme/target/Makefile deleted file mode 100644 index b7a0623..0000000 --- a/src/linux/drivers/nvme/target/Makefile +++ /dev/null @@ -1,9 +0,0 @@ - -obj-$(CONFIG_NVME_TARGET) += nvmet.o -obj-$(CONFIG_NVME_TARGET_LOOP) += nvme-loop.o -obj-$(CONFIG_NVME_TARGET_RDMA) += nvmet-rdma.o - -nvmet-y += core.o configfs.o admin-cmd.o io-cmd.o fabrics-cmd.o \ - discovery.o -nvme-loop-y += loop.o -nvmet-rdma-y += rdma.o diff --git a/src/linux/drivers/nvmem/Kconfig b/src/linux/drivers/nvmem/Kconfig deleted file mode 100644 index ba140ea..0000000 --- a/src/linux/drivers/nvmem/Kconfig +++ /dev/null @@ -1,114 +0,0 @@ -menuconfig NVMEM - tristate "NVMEM Support" - help - Support for NVMEM(Non Volatile Memory) devices like EEPROM, EFUSES... - - This framework is designed to provide a generic interface to NVMEM - from both the Linux Kernel and the userspace. - - This driver can also be built as a module. If so, the module - will be called nvmem_core. - - If unsure, say no. - -if NVMEM - -config NVMEM_IMX_OCOTP - tristate "i.MX6 On-Chip OTP Controller support" - depends on SOC_IMX6 || COMPILE_TEST - depends on HAS_IOMEM - help - This is a driver for the On-Chip OTP Controller (OCOTP) available on - i.MX6 SoCs, providing access to 4 Kbits of one-time programmable - eFuses. - - This driver can also be built as a module. If so, the module - will be called nvmem-imx-ocotp. - -config NVMEM_LPC18XX_EEPROM - tristate "NXP LPC18XX EEPROM Memory Support" - depends on ARCH_LPC18XX || COMPILE_TEST - depends on HAS_IOMEM - help - Say Y here to include support for NXP LPC18xx EEPROM memory found in - NXP LPC185x/3x and LPC435x/3x/2x/1x devices. - To compile this driver as a module, choose M here: the module - will be called nvmem_lpc18xx_eeprom. - -config NVMEM_MXS_OCOTP - tristate "Freescale MXS On-Chip OTP Memory Support" - depends on ARCH_MXS || COMPILE_TEST - depends on HAS_IOMEM - help - If you say Y here, you will get readonly access to the - One Time Programmable memory pages that are stored - on the Freescale i.MX23/i.MX28 processor. - - This driver can also be built as a module. If so, the module - will be called nvmem-mxs-ocotp. - -config MTK_EFUSE - tristate "Mediatek SoCs EFUSE support" - depends on ARCH_MEDIATEK || COMPILE_TEST - depends on HAS_IOMEM - help - This is a driver to access hardware related data like sensor - calibration, HDMI impedance etc. - - This driver can also be built as a module. If so, the module - will be called efuse-mtk. - -config QCOM_QFPROM - tristate "QCOM QFPROM Support" - depends on ARCH_QCOM || COMPILE_TEST - depends on HAS_IOMEM - help - Say y here to enable QFPROM support. The QFPROM provides access - functions for QFPROM data to rest of the drivers via nvmem interface. - - This driver can also be built as a module. If so, the module - will be called nvmem_qfprom. - -config ROCKCHIP_EFUSE - tristate "Rockchip eFuse Support" - depends on ARCH_ROCKCHIP || COMPILE_TEST - depends on HAS_IOMEM - help - This is a simple drive to dump specified values of Rockchip SoC - from eFuse, such as cpu-leakage. - - This driver can also be built as a module. If so, the module - will be called nvmem_rockchip_efuse. - -config NVMEM_SUNXI_SID - tristate "Allwinner SoCs SID support" - depends on ARCH_SUNXI - help - This is a driver for the 'security ID' available on various Allwinner - devices. - - This driver can also be built as a module. If so, the module - will be called nvmem_sunxi_sid. - -config NVMEM_VF610_OCOTP - tristate "VF610 SoC OCOTP support" - depends on SOC_VF610 || COMPILE_TEST - depends on HAS_IOMEM - help - This is a driver for the 'OCOTP' peripheral available on Vybrid - devices like VF5xx and VF6xx. - - This driver can also be build as a module. If so, the module will - be called nvmem-vf610-ocotp. - -config MESON_EFUSE - tristate "Amlogic eFuse Support" - depends on (ARCH_MESON || COMPILE_TEST) && MESON_SM - help - This is a driver to retrieve specific values from the eFuse found on - the Amlogic Meson SoCs. - - This driver can also be built as a module. If so, the module - will be called nvmem_meson_efuse. - -endif diff --git a/src/linux/drivers/of/Kconfig b/src/linux/drivers/of/Kconfig deleted file mode 100644 index ba7b034..0000000 --- a/src/linux/drivers/of/Kconfig +++ /dev/null @@ -1,115 +0,0 @@ -config DTC - bool - -menuconfig OF - bool "Device Tree and Open Firmware support" - help - This option enables the device tree infrastructure. - It is automatically selected by platforms that need it or can - be enabled manually for unittests, overlays or - compile-coverage. - -if OF - -config OF_UNITTEST - bool "Device Tree runtime unit tests" - depends on OF_IRQ - select OF_EARLY_FLATTREE - select OF_RESOLVE - help - This option builds in test cases for the device tree infrastructure - that are executed once at boot time, and the results dumped to the - console. - - If unsure, say N here, but this option is safe to enable. - -config OF_ALL_DTBS - bool "Build all Device Tree Blobs" - depends on COMPILE_TEST - select DTC - help - This option builds all possible Device Tree Blobs (DTBs) for the - current architecture. - - If unsure, say N here, but this option is safe to enable. - -config OF_FLATTREE - bool - select DTC - select LIBFDT - select CRC32 - -config OF_EARLY_FLATTREE - bool - select OF_FLATTREE - -config OF_PROMTREE - bool - -# Hardly any platforms need this. It is safe to select, but only do so if you -# need it. -config OF_DYNAMIC - bool "Support for dynamic device trees" if OF_UNITTEST - help - On some platforms, the device tree can be manipulated at runtime. - While this option is selected automatically on such platforms, you - can enable it manually to improve device tree unit test coverage. - -config OF_ADDRESS - def_bool y - depends on !SPARC && HAS_IOMEM - select OF_ADDRESS_PCI if PCI - -config OF_ADDRESS_PCI - bool - -config OF_IRQ - def_bool y - depends on !SPARC && IRQ_DOMAIN - -config OF_NET - depends on NETDEVICES - def_bool y - -config OF_MDIO - def_tristate PHYLIB - depends on PHYLIB - select FIXED_PHY - help - OpenFirmware MDIO bus (Ethernet PHY) accessors - -config OF_PCI - def_tristate PCI - depends on PCI - help - OpenFirmware PCI bus accessors - -config OF_PCI_IRQ - def_tristate PCI - depends on OF_PCI && OF_IRQ - help - OpenFirmware PCI IRQ routing helpers - -config OF_RESERVED_MEM - depends on OF_EARLY_FLATTREE - bool - help - Helpers to allow for reservation of memory regions - -config OF_RESOLVE - bool - -config OF_OVERLAY - bool "Device Tree overlays" - select OF_DYNAMIC - select OF_RESOLVE - help - Overlays are a method to dynamically modify part of the kernel's - device tree with dynamically loaded data. - While this option is selected automatically when needed, you can - enable it manually to improve device tree unit test coverage. - -config OF_NUMA - bool - -endif # OF diff --git a/src/linux/drivers/of/unittest-data/.gitignore b/src/linux/drivers/of/unittest-data/.gitignore deleted file mode 100644 index 4b3cf8b..0000000 --- a/src/linux/drivers/of/unittest-data/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -testcases.dtb -testcases.dtb.S diff --git a/src/linux/drivers/parport/Kconfig b/src/linux/drivers/parport/Kconfig deleted file mode 100644 index 44333bd..0000000 --- a/src/linux/drivers/parport/Kconfig +++ /dev/null @@ -1,165 +0,0 @@ -# -# For a description of the syntax of this configuration file, -# see Documentation/kbuild/kconfig-language.txt. -# -# Parport configuration. -# - -config ARCH_MIGHT_HAVE_PC_PARPORT - bool - help - Select this config option from the architecture Kconfig if - the architecture might have PC parallel port hardware. - -menuconfig PARPORT - tristate "Parallel port support" - depends on HAS_IOMEM - ---help--- - If you want to use devices connected to your machine's parallel port - (the connector at the computer with 25 holes), e.g. printer, ZIP - drive, PLIP link (Parallel Line Internet Protocol is mainly used to - create a mini network by connecting the parallel ports of two local - machines) etc., then you need to say Y here; please read - and - . - - For extensive information about drivers for many devices attaching - to the parallel port see on - the WWW. - - It is possible to share a single parallel port among several devices - and it is safe to compile all the corresponding drivers into the - kernel. To compile parallel port support as a module, choose M here: - the module will be called parport. - If you have more than one parallel port and want to specify which - port and IRQ to be used by this driver at module load time, take a - look at . - - If unsure, say Y. - -if PARPORT - -config PARPORT_PC - tristate "PC-style hardware" - depends on ARCH_MIGHT_HAVE_PC_PARPORT - help - You should say Y here if you have a PC-style parallel port. All - IBM PC compatible computers and some Alphas have PC-style - parallel ports. PA-RISC owners should only say Y here if they - have a SuperIO parallel port. - - To compile this driver as a module, choose M here: the - module will be called parport_pc. - - If unsure, say Y. - -config PARPORT_SERIAL - tristate "Multi-IO cards (parallel and serial)" - depends on SERIAL_8250_PCI && PARPORT_PC && PCI - help - This adds support for multi-IO PCI cards that have parallel and - serial ports. You should say Y or M here. If you say M, the module - will be called parport_serial. - -config PARPORT_PC_FIFO - bool "Use FIFO/DMA if available" - depends on PARPORT_PC - help - Many parallel port chipsets provide hardware that can speed up - printing. Say Y here if you want to take advantage of that. - - As well as actually having a FIFO, or DMA capability, the kernel - will need to know which IRQ the parallel port has. By default, - parallel port interrupts will not be used, and so neither will the - FIFO. See to find out how to - specify which IRQ/DMA to use. - -config PARPORT_PC_SUPERIO - bool "SuperIO chipset support" - depends on PARPORT_PC && !PARISC - help - Saying Y here enables some probes for Super-IO chipsets in order to - find out things like base addresses, IRQ lines and DMA channels. It - is safe to say N. - -config PARPORT_PC_PCMCIA - tristate "Support for PCMCIA management for PC-style ports" - depends on PCMCIA && PARPORT_PC - help - Say Y here if you need PCMCIA support for your PC-style parallel - ports. If unsure, say N. - -config PARPORT_IP32 - tristate "SGI IP32 builtin port" - depends on SGI_IP32 - select PARPORT_NOT_PC - help - Say Y here if you need support for the parallel port on - SGI O2 machines. This code is also available as a module (say M), - called parport_ip32. If in doubt, saying N is the safe plan. - -config PARPORT_AMIGA - tristate "Amiga builtin port" - depends on AMIGA - select PARPORT_NOT_PC - help - Say Y here if you need support for the parallel port hardware on - Amiga machines. This code is also available as a module (say M), - called parport_amiga. If in doubt, saying N is the safe plan. - -config PARPORT_MFC3 - tristate "Multiface III parallel port" - depends on ZORRO - select PARPORT_NOT_PC - help - Say Y here if you need parallel port support for the MFC3 card. - This code is also available as a module (say M), called - parport_mfc3. If in doubt, saying N is the safe plan. - -config PARPORT_ATARI - tristate "Atari hardware" - depends on ATARI - select PARPORT_NOT_PC - help - Say Y here if you need support for the parallel port hardware on - Atari machines. This code is also available as a module (say M), - called parport_atari. If in doubt, saying N is the safe plan. - -config PARPORT_GSC - tristate - default GSC - select PARPORT_NOT_PC - -config PARPORT_SUNBPP - tristate "Sparc hardware" - depends on SBUS - select PARPORT_NOT_PC - help - This driver provides support for the bidirectional parallel port - found on many Sun machines. Note that many of the newer Ultras - actually have pc style hardware instead. - -config PARPORT_AX88796 - tristate "AX88796 Parallel Port" - select PARPORT_NOT_PC - help - Say Y here if you need support for the parallel port hardware on - the AX88796 network controller chip. This code is also available - as a module (say M), called parport_ax88796. - - The driver is not dependent on the AX88796 network driver, and - should not interfere with the networking functions of the chip. - -config PARPORT_1284 - bool "IEEE 1284 transfer modes" - help - If you have a printer that supports status readback or device ID, or - want to use a device that uses enhanced parallel port transfer modes - such as EPP and ECP, say Y here to enable advanced IEEE 1284 - transfer modes. Also say Y if you want device ID information to - appear in /proc/sys/dev/parport/*/autoprobe*. It is safe to say N. - -config PARPORT_NOT_PC - bool - -endif # PARPORT diff --git a/src/linux/drivers/perf/Kconfig b/src/linux/drivers/perf/Kconfig deleted file mode 100644 index 4d5c5f9..0000000 --- a/src/linux/drivers/perf/Kconfig +++ /dev/null @@ -1,22 +0,0 @@ -# -# Performance Monitor Drivers -# - -menu "Performance monitor support" - -config ARM_PMU - depends on PERF_EVENTS && (ARM || ARM64) - bool "ARM PMU framework" - default y - help - Say y if you want to use CPU performance monitors on ARM-based - systems. - -config XGENE_PMU - depends on PERF_EVENTS && ARCH_XGENE - bool "APM X-Gene SoC PMU" - default n - help - Say y if you want to use APM X-Gene SoC performance monitors. - -endmenu diff --git a/src/linux/drivers/phy/Kconfig b/src/linux/drivers/phy/Kconfig deleted file mode 100644 index fe00f91..0000000 --- a/src/linux/drivers/phy/Kconfig +++ /dev/null @@ -1,492 +0,0 @@ -# -# PHY -# - -menu "PHY Subsystem" - -config GENERIC_PHY - bool "PHY Core" - help - Generic PHY support. - - This framework is designed to provide a generic interface for PHY - devices present in the kernel. This layer will have the generic - API by which phy drivers can create PHY using the phy framework and - phy users can obtain reference to the PHY. All the users of this - framework should select this config. - -config PHY_BCM_NS_USB2 - tristate "Broadcom Northstar USB 2.0 PHY Driver" - depends on ARCH_BCM_IPROC || COMPILE_TEST - depends on HAS_IOMEM && OF - select GENERIC_PHY - help - Enable this to support Broadcom USB 2.0 PHY connected to the USB - controller on Northstar family. - -config PHY_BCM_NS_USB3 - tristate "Broadcom Northstar USB 3.0 PHY Driver" - depends on ARCH_BCM_IPROC || COMPILE_TEST - depends on HAS_IOMEM && OF - select GENERIC_PHY - help - Enable this to support Broadcom USB 3.0 PHY connected to the USB - controller on Northstar family. - -config PHY_BERLIN_USB - tristate "Marvell Berlin USB PHY Driver" - depends on ARCH_BERLIN && RESET_CONTROLLER && HAS_IOMEM && OF - select GENERIC_PHY - help - Enable this to support the USB PHY on Marvell Berlin SoCs. - -config PHY_BERLIN_SATA - tristate "Marvell Berlin SATA PHY driver" - depends on ARCH_BERLIN && HAS_IOMEM && OF - select GENERIC_PHY - help - Enable this to support the SATA PHY on Marvell Berlin SoCs. - -config ARMADA375_USBCLUSTER_PHY - def_bool y - depends on MACH_ARMADA_375 || COMPILE_TEST - depends on OF && HAS_IOMEM - select GENERIC_PHY - -config PHY_DA8XX_USB - tristate "TI DA8xx USB PHY Driver" - depends on ARCH_DAVINCI_DA8XX - select GENERIC_PHY - select MFD_SYSCON - help - Enable this to support the USB PHY on DA8xx SoCs. - - This driver controls both the USB 1.1 PHY and the USB 2.0 PHY. - -config PHY_DM816X_USB - tristate "TI dm816x USB PHY driver" - depends on ARCH_OMAP2PLUS - depends on USB_SUPPORT - select GENERIC_PHY - select USB_PHY - help - Enable this for dm816x USB to work. - -config PHY_EXYNOS_MIPI_VIDEO - tristate "S5P/EXYNOS SoC series MIPI CSI-2/DSI PHY driver" - depends on HAS_IOMEM - depends on ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST - select GENERIC_PHY - default y if ARCH_S5PV210 || ARCH_EXYNOS - help - Support for MIPI CSI-2 and MIPI DSI DPHY found on Samsung S5P - and EXYNOS SoCs. - -config PHY_LPC18XX_USB_OTG - tristate "NXP LPC18xx/43xx SoC USB OTG PHY driver" - depends on OF && (ARCH_LPC18XX || COMPILE_TEST) - depends on MFD_SYSCON - select GENERIC_PHY - help - Enable this to support NXP LPC18xx/43xx internal USB OTG PHY. - - This driver is need for USB0 support on LPC18xx/43xx and takes - care of enabling and clock setup. - -config PHY_PXA_28NM_HSIC - tristate "Marvell USB HSIC 28nm PHY Driver" - depends on HAS_IOMEM - select GENERIC_PHY - help - Enable this to support Marvell USB HSIC PHY driver for Marvell - SoC. This driver will do the PHY initialization and shutdown. - The PHY driver will be used by Marvell ehci driver. - - To compile this driver as a module, choose M here. - -config PHY_PXA_28NM_USB2 - tristate "Marvell USB 2.0 28nm PHY Driver" - depends on HAS_IOMEM - select GENERIC_PHY - help - Enable this to support Marvell USB 2.0 PHY driver for Marvell - SoC. This driver will do the PHY initialization and shutdown. - The PHY driver will be used by Marvell udc/ehci/otg driver. - - To compile this driver as a module, choose M here. - -config PHY_MVEBU_SATA - def_bool y - depends on ARCH_DOVE || MACH_DOVE || MACH_KIRKWOOD - depends on OF - select GENERIC_PHY - -config PHY_MIPHY28LP - tristate "STMicroelectronics MIPHY28LP PHY driver for STiH407" - depends on ARCH_STI - select GENERIC_PHY - help - Enable this to support the miphy transceiver (for SATA/PCIE/USB3) - that is part of STMicroelectronics STiH407 SoC. - -config PHY_MIPHY365X - tristate "STMicroelectronics MIPHY365X PHY driver for STiH41x series" - depends on ARCH_STI - depends on HAS_IOMEM - depends on OF - select GENERIC_PHY - help - Enable this to support the miphy transceiver (for SATA/PCIE) - that is part of STMicroelectronics STiH41x SoC series. - -config PHY_RCAR_GEN2 - tristate "Renesas R-Car generation 2 USB PHY driver" - depends on ARCH_RENESAS - depends on GENERIC_PHY - help - Support for USB PHY found on Renesas R-Car generation 2 SoCs. - -config PHY_RCAR_GEN3_USB2 - tristate "Renesas R-Car generation 3 USB 2.0 PHY driver" - depends on ARCH_RENESAS - depends on EXTCON - select GENERIC_PHY - help - Support for USB 2.0 PHY found on Renesas R-Car generation 3 SoCs. - -config OMAP_CONTROL_PHY - tristate "OMAP CONTROL PHY Driver" - depends on ARCH_OMAP2PLUS || COMPILE_TEST - help - Enable this to add support for the PHY part present in the control - module. This driver has API to power on the USB2 PHY and to write to - the mailbox. The mailbox is present only in omap4 and the register to - power on the USB2 PHY is present in OMAP4 and OMAP5. OMAP5 has an - additional register to power on USB3 PHY/SATA PHY/PCIE PHY - (PIPE3 PHY). - -config OMAP_USB2 - tristate "OMAP USB2 PHY Driver" - depends on ARCH_OMAP2PLUS - depends on USB_SUPPORT - select GENERIC_PHY - select USB_PHY - select OMAP_CONTROL_PHY - depends on OMAP_OCP2SCP - help - Enable this to support the transceiver that is part of SOC. This - driver takes care of all the PHY functionality apart from comparator. - The USB OTG controller communicates with the comparator using this - driver. - -config TI_PIPE3 - tristate "TI PIPE3 PHY Driver" - depends on ARCH_OMAP2PLUS || COMPILE_TEST - select GENERIC_PHY - select OMAP_CONTROL_PHY - depends on OMAP_OCP2SCP - help - Enable this to support the PIPE3 PHY that is part of TI SOCs. This - driver takes care of all the PHY functionality apart from comparator. - This driver interacts with the "OMAP Control PHY Driver" to power - on/off the PHY. - -config TWL4030_USB - tristate "TWL4030 USB Transceiver Driver" - depends on TWL4030_CORE && REGULATOR_TWL4030 && USB_MUSB_OMAP2PLUS - depends on USB_SUPPORT - depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't 'y' - select GENERIC_PHY - select USB_PHY - help - Enable this to support the USB OTG transceiver on TWL4030 - family chips (including the TWL5030 and TPS659x0 devices). - This transceiver supports high and full speed devices plus, - in host mode, low speed. - -config PHY_EXYNOS_DP_VIDEO - tristate "EXYNOS SoC series Display Port PHY driver" - depends on OF - depends on ARCH_EXYNOS || COMPILE_TEST - default ARCH_EXYNOS - select GENERIC_PHY - help - Support for Display Port PHY found on Samsung EXYNOS SoCs. - -config BCM_KONA_USB2_PHY - tristate "Broadcom Kona USB2 PHY Driver" - depends on HAS_IOMEM - select GENERIC_PHY - help - Enable this to support the Broadcom Kona USB 2.0 PHY. - -config PHY_EXYNOS5250_SATA - tristate "Exynos5250 Sata SerDes/PHY driver" - depends on SOC_EXYNOS5250 - depends on HAS_IOMEM - depends on OF - select GENERIC_PHY - select I2C - select I2C_S3C2410 - select MFD_SYSCON - help - Enable this to support SATA SerDes/Phy found on Samsung's - Exynos5250 based SoCs.This SerDes/Phy supports SATA 1.5 Gb/s, - SATA 3.0 Gb/s, SATA 6.0 Gb/s speeds. It supports one SATA host - port to accept one SATA device. - -config PHY_HIX5HD2_SATA - tristate "HIX5HD2 SATA PHY Driver" - depends on ARCH_HIX5HD2 && OF && HAS_IOMEM - select GENERIC_PHY - select MFD_SYSCON - help - Support for SATA PHY on Hisilicon hix5hd2 Soc. - -config PHY_MT65XX_USB3 - tristate "Mediatek USB3.0 PHY Driver" - depends on ARCH_MEDIATEK && OF - select GENERIC_PHY - help - Say 'Y' here to add support for Mediatek USB3.0 PHY driver, - it supports multiple usb2.0 and usb3.0 ports. - -config PHY_HI6220_USB - tristate "hi6220 USB PHY support" - depends on (ARCH_HISI && ARM64) || COMPILE_TEST - select GENERIC_PHY - select MFD_SYSCON - help - Enable this to support the HISILICON HI6220 USB PHY. - - To compile this driver as a module, choose M here. - -config PHY_SUN4I_USB - tristate "Allwinner sunxi SoC USB PHY driver" - depends on ARCH_SUNXI && HAS_IOMEM && OF - depends on RESET_CONTROLLER - depends on EXTCON - depends on POWER_SUPPLY - depends on USB_SUPPORT - select GENERIC_PHY - select USB_COMMON - help - Enable this to support the transceiver that is part of Allwinner - sunxi SoCs. - - This driver controls the entire USB PHY block, both the USB OTG - parts, as well as the 2 regular USB 2 host PHYs. - -config PHY_SUN9I_USB - tristate "Allwinner sun9i SoC USB PHY driver" - depends on ARCH_SUNXI && HAS_IOMEM && OF - depends on RESET_CONTROLLER - depends on USB_SUPPORT - select USB_COMMON - select GENERIC_PHY - help - Enable this to support the transceiver that is part of Allwinner - sun9i SoCs. - - This driver controls each individual USB 2 host PHY. - -config PHY_SAMSUNG_USB2 - tristate "Samsung USB 2.0 PHY driver" - depends on HAS_IOMEM - depends on USB_EHCI_EXYNOS || USB_OHCI_EXYNOS || USB_DWC2 - select GENERIC_PHY - select MFD_SYSCON - default ARCH_EXYNOS - help - Enable this to support the Samsung USB 2.0 PHY driver for Samsung - SoCs. This driver provides the interface for USB 2.0 PHY. Support - for particular PHYs will be enabled based on the SoC type in addition - to this driver. - -config PHY_S5PV210_USB2 - bool "Support for S5PV210" - depends on PHY_SAMSUNG_USB2 - depends on ARCH_S5PV210 - help - Enable USB PHY support for S5PV210. This option requires that Samsung - USB 2.0 PHY driver is enabled and means that support for this - particular SoC is compiled in the driver. In case of S5PV210 two phys - are available - device and host. - -config PHY_EXYNOS4210_USB2 - bool - depends on PHY_SAMSUNG_USB2 - default CPU_EXYNOS4210 - -config PHY_EXYNOS4X12_USB2 - bool - depends on PHY_SAMSUNG_USB2 - default SOC_EXYNOS3250 || SOC_EXYNOS4212 || SOC_EXYNOS4412 - -config PHY_EXYNOS5250_USB2 - bool - depends on PHY_SAMSUNG_USB2 - default SOC_EXYNOS5250 || SOC_EXYNOS5420 - -config PHY_EXYNOS5_USBDRD - tristate "Exynos5 SoC series USB DRD PHY driver" - depends on ARCH_EXYNOS && OF - depends on HAS_IOMEM - depends on USB_DWC3_EXYNOS - select GENERIC_PHY - select MFD_SYSCON - default y - help - Enable USB DRD PHY support for Exynos 5 SoC series. - This driver provides PHY interface for USB 3.0 DRD controller - present on Exynos5 SoC series. - -config PHY_PISTACHIO_USB - tristate "IMG Pistachio USB2.0 PHY driver" - depends on MACH_PISTACHIO - select GENERIC_PHY - help - Enable this to support the USB2.0 PHY on the IMG Pistachio SoC. - -config PHY_QCOM_APQ8064_SATA - tristate "Qualcomm APQ8064 SATA SerDes/PHY driver" - depends on ARCH_QCOM - depends on HAS_IOMEM - depends on OF - select GENERIC_PHY - -config PHY_QCOM_IPQ806X_SATA - tristate "Qualcomm IPQ806x SATA SerDes/PHY driver" - depends on ARCH_QCOM - depends on HAS_IOMEM - depends on OF - select GENERIC_PHY - -config PHY_ROCKCHIP_USB - tristate "Rockchip USB2 PHY Driver" - depends on ARCH_ROCKCHIP && OF - select GENERIC_PHY - help - Enable this to support the Rockchip USB 2.0 PHY. - -config PHY_ROCKCHIP_INNO_USB2 - tristate "Rockchip INNO USB2PHY Driver" - depends on (ARCH_ROCKCHIP || COMPILE_TEST) && OF - depends on COMMON_CLK - select GENERIC_PHY - help - Support for Rockchip USB2.0 PHY with Innosilicon IP block. - -config PHY_ROCKCHIP_EMMC - tristate "Rockchip EMMC PHY Driver" - depends on ARCH_ROCKCHIP && OF - select GENERIC_PHY - help - Enable this to support the Rockchip EMMC PHY. - -config PHY_ROCKCHIP_DP - tristate "Rockchip Display Port PHY Driver" - depends on ARCH_ROCKCHIP && OF - select GENERIC_PHY - help - Enable this to support the Rockchip Display Port PHY. - -config PHY_ROCKCHIP_PCIE - tristate "Rockchip PCIe PHY Driver" - depends on (ARCH_ROCKCHIP && OF) || COMPILE_TEST - select GENERIC_PHY - select MFD_SYSCON - help - Enable this to support the Rockchip PCIe PHY. - -config PHY_ROCKCHIP_TYPEC - tristate "Rockchip TYPEC PHY Driver" - depends on OF && (ARCH_ROCKCHIP || COMPILE_TEST) - select EXTCON - select GENERIC_PHY - select RESET_CONTROLLER - help - Enable this to support the Rockchip USB TYPEC PHY. - -config PHY_ST_SPEAR1310_MIPHY - tristate "ST SPEAR1310-MIPHY driver" - select GENERIC_PHY - depends on MACH_SPEAR1310 || COMPILE_TEST - help - Support for ST SPEAr1310 MIPHY which can be used for PCIe and SATA. - -config PHY_ST_SPEAR1340_MIPHY - tristate "ST SPEAR1340-MIPHY driver" - select GENERIC_PHY - depends on MACH_SPEAR1340 || COMPILE_TEST - help - Support for ST SPEAr1340 MIPHY which can be used for PCIe and SATA. - -config PHY_XGENE - tristate "APM X-Gene 15Gbps PHY support" - depends on HAS_IOMEM && OF && (ARM64 || COMPILE_TEST) - select GENERIC_PHY - help - This option enables support for APM X-Gene SoC multi-purpose PHY. - -config PHY_STIH407_USB - tristate "STMicroelectronics USB2 picoPHY driver for STiH407 family" - depends on RESET_CONTROLLER - depends on ARCH_STI || COMPILE_TEST - select GENERIC_PHY - help - Enable this support to enable the picoPHY device used by USB2 - and USB3 controllers on STMicroelectronics STiH407 SoC families. - -config PHY_STIH41X_USB - tristate "STMicroelectronics USB2 PHY driver for STiH41x series" - depends on ARCH_STI - select GENERIC_PHY - help - Enable this to support the USB transceiver that is part of - STMicroelectronics STiH41x SoC series. - -config PHY_QCOM_UFS - tristate "Qualcomm UFS PHY driver" - depends on OF && ARCH_QCOM - select GENERIC_PHY - help - Support for UFS PHY on QCOM chipsets. - -config PHY_TUSB1210 - tristate "TI TUSB1210 ULPI PHY module" - depends on USB_ULPI_BUS - select GENERIC_PHY - help - Support for TI TUSB1210 USB ULPI PHY. - -config PHY_BRCM_SATA - tristate "Broadcom SATA PHY driver" - depends on ARCH_BRCMSTB || ARCH_BCM_IPROC || BMIPS_GENERIC || COMPILE_TEST - depends on OF - select GENERIC_PHY - default ARCH_BCM_IPROC - help - Enable this to support the Broadcom SATA PHY. - If unsure, say N. - -config PHY_CYGNUS_PCIE - tristate "Broadcom Cygnus PCIe PHY driver" - depends on OF && (ARCH_BCM_CYGNUS || COMPILE_TEST) - select GENERIC_PHY - default ARCH_BCM_CYGNUS - help - Enable this to support the Broadcom Cygnus PCIe PHY. - If unsure, say N. - -source "drivers/phy/tegra/Kconfig" - -config PHY_NS2_PCIE - tristate "Broadcom Northstar2 PCIe PHY driver" - depends on OF && MDIO_BUS_MUX_BCM_IPROC - select GENERIC_PHY - default ARCH_BCM_IPROC - help - Enable this to support the Broadcom Northstar2 PCIe PHY. - If unsure, say N. -endmenu diff --git a/src/linux/drivers/phy/tegra/Kconfig b/src/linux/drivers/phy/tegra/Kconfig deleted file mode 100644 index a3b1de9..0000000 --- a/src/linux/drivers/phy/tegra/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config PHY_TEGRA_XUSB - tristate "NVIDIA Tegra XUSB pad controller driver" - depends on ARCH_TEGRA - help - Choose this option if you have an NVIDIA Tegra SoC. - - To compile this driver as a module, choose M here: the module will - be called phy-tegra-xusb. diff --git a/src/linux/drivers/pinctrl/Kconfig b/src/linux/drivers/pinctrl/Kconfig deleted file mode 100644 index 0e75d94..0000000 --- a/src/linux/drivers/pinctrl/Kconfig +++ /dev/null @@ -1,286 +0,0 @@ -# -# PINCTRL infrastructure and drivers -# - -config PINCTRL - bool - -menu "Pin controllers" - depends on PINCTRL - -config PINMUX - bool "Support pin multiplexing controllers" if COMPILE_TEST - -config PINCONF - bool "Support pin configuration controllers" if COMPILE_TEST - -config GENERIC_PINCONF - bool - select PINCONF - -config DEBUG_PINCTRL - bool "Debug PINCTRL calls" - depends on DEBUG_KERNEL - help - Say Y here to add some extra checks and diagnostics to PINCTRL calls. - -config PINCTRL_ADI2 - bool "ADI pin controller driver" - depends on BLACKFIN - select PINMUX - select IRQ_DOMAIN - help - This is the pin controller and gpio driver for ADI BF54x, BF60x and - future processors. This option is selected automatically when specific - machine and arch are selected to build. - -config PINCTRL_AS3722 - tristate "Pinctrl and GPIO driver for ams AS3722 PMIC" - depends on MFD_AS3722 && GPIOLIB - select PINMUX - select GENERIC_PINCONF - help - AS3722 device supports the configuration of GPIO pins for different - functionality. This driver supports the pinmux, push-pull and - open drain configuration for the GPIO pins of AS3722 devices. It also - supports the GPIO functionality through gpiolib. - -config PINCTRL_BF54x - def_bool y if BF54x - select PINCTRL_ADI2 - -config PINCTRL_BF60x - def_bool y if BF60x - select PINCTRL_ADI2 - -config PINCTRL_AT91 - bool "AT91 pinctrl driver" - depends on OF - depends on ARCH_AT91 - select PINMUX - select PINCONF - select GPIOLIB - select OF_GPIO - select GPIOLIB_IRQCHIP - help - Say Y here to enable the at91 pinctrl driver - -config PINCTRL_AT91PIO4 - bool "AT91 PIO4 pinctrl driver" - depends on OF - depends on ARCH_AT91 - select PINMUX - select GENERIC_PINCONF - select GPIOLIB - select GPIOLIB_IRQCHIP - select OF_GPIO - help - Say Y here to enable the at91 pinctrl/gpio driver for Atmel PIO4 - controller available on sama5d2 SoC. - -config PINCTRL_AMD - tristate "AMD GPIO pin control" - depends on GPIOLIB - select GPIOLIB_IRQCHIP - select PINCONF - select GENERIC_PINCONF - help - driver for memory mapped GPIO functionality on AMD platforms - (x86 or arm).Most pins are usually muxed to some other - functionality by firmware,so only a small amount is available - for gpio use. - - Requires ACPI/FDT device enumeration code to set up a platform - device. - -config PINCTRL_DIGICOLOR - bool - depends on OF && (ARCH_DIGICOLOR || COMPILE_TEST) - select PINMUX - select GENERIC_PINCONF - -config PINCTRL_LANTIQ - bool - depends on LANTIQ - select PINMUX - select PINCONF - -config PINCTRL_LPC18XX - bool "NXP LPC18XX/43XX SCU pinctrl driver" - depends on OF && (ARCH_LPC18XX || COMPILE_TEST) - default ARCH_LPC18XX - select PINMUX - select GENERIC_PINCONF - help - Pinctrl driver for NXP LPC18xx/43xx System Control Unit (SCU). - -config PINCTRL_FALCON - bool - depends on SOC_FALCON - depends on PINCTRL_LANTIQ - -config PINCTRL_MESON - bool - depends on OF - select PINMUX - select PINCONF - select GENERIC_PINCONF - select GPIOLIB - select OF_GPIO - select REGMAP_MMIO - -config PINCTRL_OXNAS - bool - depends on OF - select PINMUX - select PINCONF - select GENERIC_PINCONF - select GPIOLIB - select OF_GPIO - select GPIOLIB_IRQCHIP - select MFD_SYSCON - -config PINCTRL_ROCKCHIP - bool - select PINMUX - select GENERIC_PINCONF - select GENERIC_IRQ_CHIP - select MFD_SYSCON - -config PINCTRL_SINGLE - tristate "One-register-per-pin type device tree based pinctrl driver" - depends on OF - select PINMUX - select PINCONF - select GENERIC_PINCONF - help - This selects the device tree based generic pinctrl driver. - -config PINCTRL_SIRF - bool "CSR SiRFprimaII pin controller driver" - depends on ARCH_SIRF - select PINMUX - select PINCONF - select GENERIC_PINCONF - select GPIOLIB_IRQCHIP - -config PINCTRL_PISTACHIO - def_bool y if MACH_PISTACHIO - depends on GPIOLIB - select PINMUX - select GENERIC_PINCONF - select GPIOLIB_IRQCHIP - select OF_GPIO - -config PINCTRL_ST - bool - depends on OF - select PINMUX - select PINCONF - select GPIOLIB_IRQCHIP - -config PINCTRL_TZ1090 - bool "Toumaz Xenif TZ1090 pin control driver" - depends on SOC_TZ1090 - select PINMUX - select GENERIC_PINCONF - -config PINCTRL_TZ1090_PDC - bool "Toumaz Xenif TZ1090 PDC pin control driver" - depends on SOC_TZ1090 - select PINMUX - select PINCONF - -config PINCTRL_U300 - bool "U300 pin controller driver" - depends on ARCH_U300 - select PINMUX - select GENERIC_PINCONF - -config PINCTRL_COH901 - bool "ST-Ericsson U300 COH 901 335/571 GPIO" - depends on GPIOLIB && ARCH_U300 && PINCTRL_U300 - select GPIOLIB_IRQCHIP - help - Say yes here to support GPIO interface on ST-Ericsson U300. - The names of the two IP block variants supported are - COH 901 335 and COH 901 571/3. They contain 3, 5 or 7 - ports of 8 GPIO pins each. - -config PINCTRL_MAX77620 - tristate "MAX77620/MAX20024 Pincontrol support" - depends on MFD_MAX77620 - select PINMUX - select GENERIC_PINCONF - help - Say Yes here to enable Pin control support for Maxim PMIC MAX77620. - This PMIC has 8 GPIO pins that work as GPIO as well as special - function in alternate mode. This driver also configure push-pull, - open drain, FPS slots etc. - -config PINCTRL_PALMAS - tristate "Pinctrl driver for the PALMAS Series MFD devices" - depends on OF && MFD_PALMAS - select PINMUX - select GENERIC_PINCONF - help - Palmas device supports the configuration of pins for different - functionality. This driver supports the pinmux, push-pull and - open drain configuration for the Palmas series devices like - TPS65913, TPS80036 etc. - -config PINCTRL_PIC32 - bool "Microchip PIC32 pin controller driver" - depends on OF - depends on MACH_PIC32 - select PINMUX - select GENERIC_PINCONF - select GPIOLIB_IRQCHIP - select OF_GPIO - help - This is the pin controller and gpio driver for Microchip PIC32 - microcontrollers. This option is selected automatically when specific - machine and arch are selected to build. - -config PINCTRL_PIC32MZDA - def_bool y if PIC32MZDA - select PINCTRL_PIC32 - -config PINCTRL_ZYNQ - bool "Pinctrl driver for Xilinx Zynq" - depends on ARCH_ZYNQ - select PINMUX - select GENERIC_PINCONF - help - This selects the pinctrl driver for Xilinx Zynq. - -source "drivers/pinctrl/aspeed/Kconfig" -source "drivers/pinctrl/bcm/Kconfig" -source "drivers/pinctrl/berlin/Kconfig" -source "drivers/pinctrl/freescale/Kconfig" -source "drivers/pinctrl/intel/Kconfig" -source "drivers/pinctrl/mvebu/Kconfig" -source "drivers/pinctrl/nomadik/Kconfig" -source "drivers/pinctrl/pxa/Kconfig" -source "drivers/pinctrl/qcom/Kconfig" -source "drivers/pinctrl/samsung/Kconfig" -source "drivers/pinctrl/sh-pfc/Kconfig" -source "drivers/pinctrl/spear/Kconfig" -source "drivers/pinctrl/stm32/Kconfig" -source "drivers/pinctrl/sunxi/Kconfig" -source "drivers/pinctrl/tegra/Kconfig" -source "drivers/pinctrl/uniphier/Kconfig" -source "drivers/pinctrl/vt8500/Kconfig" -source "drivers/pinctrl/mediatek/Kconfig" - -config PINCTRL_XWAY - bool - depends on SOC_TYPE_XWAY - depends on PINCTRL_LANTIQ - -config PINCTRL_TB10X - bool - depends on OF && ARC_PLAT_TB10X - select GPIOLIB - -endmenu diff --git a/src/linux/drivers/pinctrl/aspeed/Kconfig b/src/linux/drivers/pinctrl/aspeed/Kconfig deleted file mode 100644 index 998eabe..0000000 --- a/src/linux/drivers/pinctrl/aspeed/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -config PINCTRL_ASPEED - bool - depends on (ARCH_ASPEED || COMPILE_TEST) && OF - depends on MFD_SYSCON - select PINMUX - select PINCONF - select GENERIC_PINCONF - select REGMAP_MMIO - -config PINCTRL_ASPEED_G4 - bool "Aspeed G4 SoC pin control" - depends on (MACH_ASPEED_G4 || COMPILE_TEST) && OF - select PINCTRL_ASPEED - help - Say Y here to enable pin controller support for Aspeed's 4th - generation SoCs. GPIO is provided by a separate GPIO driver. - -config PINCTRL_ASPEED_G5 - bool "Aspeed G5 SoC pin control" - depends on (MACH_ASPEED_G5 || COMPILE_TEST) && OF - select PINCTRL_ASPEED - help - Say Y here to enable pin controller support for Aspeed's 5th - generation SoCs. GPIO is provided by a separate GPIO driver. diff --git a/src/linux/drivers/pinctrl/bcm/Kconfig b/src/linux/drivers/pinctrl/bcm/Kconfig deleted file mode 100644 index 6324677..0000000 --- a/src/linux/drivers/pinctrl/bcm/Kconfig +++ /dev/null @@ -1,116 +0,0 @@ -# -# Broadcom pinctrl drivers -# - -config PINCTRL_BCM281XX - bool "Broadcom BCM281xx pinctrl driver" - depends on OF && (ARCH_BCM_MOBILE || COMPILE_TEST) - select PINMUX - select PINCONF - select GENERIC_PINCONF - select REGMAP_MMIO - default ARCH_BCM_MOBILE - help - Say Y here to support Broadcom BCM281xx pinctrl driver, which is used - for the BCM281xx SoC family, including BCM11130, BCM11140, BCM11351, - BCM28145, and BCM28155 SoCs. This driver requires the pinctrl - framework. GPIO is provided by a separate GPIO driver. - -config PINCTRL_BCM2835 - bool - select PINMUX - select PINCONF - -config PINCTRL_IPROC_GPIO - bool "Broadcom iProc GPIO (with PINCONF) driver" - depends on OF_GPIO && (ARCH_BCM_IPROC || COMPILE_TEST) - select GPIOLIB_IRQCHIP - select PINCONF - select GENERIC_PINCONF - default ARCH_BCM_IPROC - help - Say yes here to enable the Broadcom iProc GPIO driver. - - The Broadcom iProc based SoCs- Cygnus, NS2, NSP and Stingray, use - same GPIO Controller IP hence this driver could be used for all. - - The Broadcom Cygnus SoC has 3 GPIO controllers including the ASIU - GPIO controller (ASIU), the chipCommonG GPIO controller (CCM), and - the always-ON GPIO controller (CRMU/AON). All 3 GPIO controllers are - supported by this driver. - - The Broadcom NSP has two GPIO controllers including the ChipcommonA - GPIO, the ChipcommonB GPIO. Later controller is supported by this - driver. - - The Broadcom NS2 has two GPIO controller including the CRMU GPIO, - the ChipcommonG GPIO. Both controllers are supported by this driver. - - The Broadcom Stingray GPIO controllers are supported by this driver. - - All above SoCs GPIO controllers support basic PINCONF functions such - as bias pull up, pull down, and drive strength configurations, when - these pins are muxed to GPIO. - - It provides the framework where pins from the individual GPIO can be - individually muxed to GPIO function, through interaction with the - SoCs IOMUX controller. This features could be used only on SoCs which - support individual pin muxing. - -config PINCTRL_CYGNUS_MUX - bool "Broadcom Cygnus IOMUX driver" - depends on (ARCH_BCM_CYGNUS || COMPILE_TEST) - depends on OF - select PINMUX - select GENERIC_PINCONF - default ARCH_BCM_CYGNUS - help - Say yes here to enable the Broadcom Cygnus IOMUX driver. - - The Broadcom Cygnus IOMUX driver supports group based IOMUX - configuration, with the exception that certain individual pins - can be overrided to GPIO function - -config PINCTRL_NSP_GPIO - bool "Broadcom NSP GPIO (with PINCONF) driver" - depends on OF_GPIO && (ARCH_BCM_NSP || COMPILE_TEST) - select GPIOLIB_IRQCHIP - select PINCONF - select GENERIC_PINCONF - default ARCH_BCM_NSP - help - Say yes here to enable the Broadcom NSP GPIO driver. - - The Broadcom Northstar Plus SoC ChipcommonA GPIO controller is - supported by this driver. - - The ChipcommonA GPIO controller support basic PINCONF functions such - as bias pull up, pull down, and drive strength configurations, when - these pins are muxed to GPIO. - -config PINCTRL_NS2_MUX - bool "Broadcom Northstar2 pinmux driver" - depends on OF - depends on ARCH_BCM_IPROC || COMPILE_TEST - select PINMUX - select GENERIC_PINCONF - default ARM64 && ARCH_BCM_IPROC - help - Say yes here to enable the Broadcom NS2 MUX driver. - - The Broadcom Northstar2 IOMUX driver supports group based IOMUX - configuration. - -config PINCTRL_NSP_MUX - bool "Broadcom NSP IOMUX driver" - depends on (ARCH_BCM_NSP || COMPILE_TEST) - depends on OF - select PINMUX - select GENERIC_PINCONF - default ARCH_BCM_NSP - help - Say yes here to enable the Broadcom NSP SOC IOMUX driver. - - The Broadcom Northstar Plus IOMUX driver supports pin based IOMUX - configuration, with certain individual pins can be overridden - to GPIO function. diff --git a/src/linux/drivers/pinctrl/berlin/Kconfig b/src/linux/drivers/pinctrl/berlin/Kconfig deleted file mode 100644 index 8fe6ad7..0000000 --- a/src/linux/drivers/pinctrl/berlin/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -if (ARCH_BERLIN || COMPILE_TEST) - -config PINCTRL_BERLIN - bool - select PINMUX - select REGMAP_MMIO - -config PINCTRL_BERLIN_BG2 - def_bool MACH_BERLIN_BG2 - depends on OF - select PINCTRL_BERLIN - -config PINCTRL_BERLIN_BG2CD - def_bool MACH_BERLIN_BG2CD - depends on OF - select PINCTRL_BERLIN - -config PINCTRL_BERLIN_BG2Q - def_bool MACH_BERLIN_BG2Q - depends on OF - select PINCTRL_BERLIN - -config PINCTRL_BERLIN_BG4CT - bool "Marvell berlin4ct pin controller driver" - depends on OF - select PINCTRL_BERLIN - -endif diff --git a/src/linux/drivers/pinctrl/freescale/Kconfig b/src/linux/drivers/pinctrl/freescale/Kconfig deleted file mode 100644 index fc8cbf6..0000000 --- a/src/linux/drivers/pinctrl/freescale/Kconfig +++ /dev/null @@ -1,123 +0,0 @@ -config PINCTRL_IMX - bool - select PINMUX - select PINCONF - select REGMAP - -config PINCTRL_IMX1_CORE - bool - select PINMUX - select PINCONF - -config PINCTRL_IMX1 - bool "IMX1 pinctrl driver" - depends on SOC_IMX1 - select PINCTRL_IMX1_CORE - help - Say Y here to enable the imx1 pinctrl driver - -config PINCTRL_IMX21 - bool "i.MX21 pinctrl driver" - depends on SOC_IMX21 - select PINCTRL_IMX1_CORE - help - Say Y here to enable the i.MX21 pinctrl driver - -config PINCTRL_IMX27 - bool "IMX27 pinctrl driver" - depends on SOC_IMX27 - select PINCTRL_IMX1_CORE - help - Say Y here to enable the imx27 pinctrl driver - - -config PINCTRL_IMX25 - bool "IMX25 pinctrl driver" - depends on OF - depends on SOC_IMX25 - select PINCTRL_IMX - help - Say Y here to enable the imx25 pinctrl driver - -config PINCTRL_IMX35 - bool "IMX35 pinctrl driver" - depends on SOC_IMX35 - select PINCTRL_IMX - help - Say Y here to enable the imx35 pinctrl driver - -config PINCTRL_IMX50 - bool "IMX50 pinctrl driver" - depends on SOC_IMX50 - select PINCTRL_IMX - help - Say Y here to enable the imx50 pinctrl driver - -config PINCTRL_IMX51 - bool "IMX51 pinctrl driver" - depends on SOC_IMX51 - select PINCTRL_IMX - help - Say Y here to enable the imx51 pinctrl driver - -config PINCTRL_IMX53 - bool "IMX53 pinctrl driver" - depends on SOC_IMX53 - select PINCTRL_IMX - help - Say Y here to enable the imx53 pinctrl driver - -config PINCTRL_IMX6Q - bool "IMX6Q/DL pinctrl driver" - depends on SOC_IMX6Q - select PINCTRL_IMX - help - Say Y here to enable the imx6q/dl pinctrl driver - -config PINCTRL_IMX6SL - bool "IMX6SL pinctrl driver" - depends on SOC_IMX6SL - select PINCTRL_IMX - help - Say Y here to enable the imx6sl pinctrl driver - -config PINCTRL_IMX6SX - bool "IMX6SX pinctrl driver" - depends on SOC_IMX6SX - select PINCTRL_IMX - help - Say Y here to enable the imx6sx pinctrl driver - -config PINCTRL_IMX6UL - bool "IMX6UL pinctrl driver" - depends on SOC_IMX6UL - select PINCTRL_IMX - help - Say Y here to enable the imx6ul pinctrl driver - -config PINCTRL_IMX7D - bool "IMX7D pinctrl driver" - depends on SOC_IMX7D - select PINCTRL_IMX - help - Say Y here to enable the imx7d pinctrl driver - -config PINCTRL_VF610 - bool "Freescale Vybrid VF610 pinctrl driver" - depends on SOC_VF610 - select PINCTRL_IMX - help - Say Y here to enable the Freescale Vybrid VF610 pinctrl driver - -config PINCTRL_MXS - bool - select PINMUX - select PINCONF - -config PINCTRL_IMX23 - bool - select PINCTRL_MXS - -config PINCTRL_IMX28 - bool - select PINCTRL_MXS diff --git a/src/linux/drivers/pinctrl/intel/Kconfig b/src/linux/drivers/pinctrl/intel/Kconfig deleted file mode 100644 index 00fb055..0000000 --- a/src/linux/drivers/pinctrl/intel/Kconfig +++ /dev/null @@ -1,66 +0,0 @@ -# -# Intel pin control drivers -# - -config PINCTRL_BAYTRAIL - bool "Intel Baytrail GPIO pin control" - depends on GPIOLIB && ACPI - select GPIOLIB_IRQCHIP - select PINMUX - select PINCONF - select GENERIC_PINCONF - help - driver for memory mapped GPIO functionality on Intel Baytrail - platforms. Supports 3 banks with 102, 28 and 44 gpios. - Most pins are usually muxed to some other functionality by firmware, - so only a small amount is available for gpio use. - - Requires ACPI device enumeration code to set up a platform device. - -config PINCTRL_CHERRYVIEW - tristate "Intel Cherryview/Braswell pinctrl and GPIO driver" - depends on ACPI - select PINMUX - select PINCONF - select GENERIC_PINCONF - select GPIOLIB - select GPIOLIB_IRQCHIP - help - Cherryview/Braswell pinctrl driver provides an interface that - allows configuring of SoC pins and using them as GPIOs. - -config PINCTRL_MERRIFIELD - tristate "Intel Merrifield pinctrl driver" - depends on X86_INTEL_MID - select PINMUX - select PINCONF - select GENERIC_PINCONF - help - Merrifield Family-Level Interface Shim (FLIS) driver provides an - interface that allows configuring of SoC pins and using them as - GPIOs. - -config PINCTRL_INTEL - tristate - select PINMUX - select PINCONF - select GENERIC_PINCONF - select GPIOLIB - select GPIOLIB_IRQCHIP - -config PINCTRL_BROXTON - tristate "Intel Broxton pinctrl and GPIO driver" - depends on ACPI - select PINCTRL_INTEL - help - Broxton pinctrl driver provides an interface that allows - configuring of SoC pins and using them as GPIOs. - -config PINCTRL_SUNRISEPOINT - tristate "Intel Sunrisepoint pinctrl and GPIO driver" - depends on ACPI - select PINCTRL_INTEL - help - Sunrisepoint is the PCH of Intel Skylake. This pinctrl driver - provides an interface that allows configuring of PCH pins and - using them as GPIOs. diff --git a/src/linux/drivers/pinctrl/mediatek/Kconfig b/src/linux/drivers/pinctrl/mediatek/Kconfig deleted file mode 100644 index 4f0bc8a..0000000 --- a/src/linux/drivers/pinctrl/mediatek/Kconfig +++ /dev/null @@ -1,51 +0,0 @@ -if ARCH_MEDIATEK || COMPILE_TEST - -config PINCTRL_MTK - bool - depends on OF - select PINMUX - select GENERIC_PINCONF - select GPIOLIB - select OF_GPIO - -# For ARMv7 SoCs -config PINCTRL_MT2701 - bool "Mediatek MT2701 pin control" if COMPILE_TEST && !MACH_MT2701 - depends on OF - default MACH_MT2701 - select PINCTRL_MTK - -config PINCTRL_MT7623 - bool "Mediatek MT7623 pin control" if COMPILE_TEST && !MACH_MT7623 - depends on OF - default MACH_MT7623 - select PINCTRL_MTK_COMMON - -config PINCTRL_MT8135 - bool "Mediatek MT8135 pin control" if COMPILE_TEST && !MACH_MT8135 - depends on OF - default MACH_MT8135 - select PINCTRL_MTK - -config PINCTRL_MT8127 - bool "Mediatek MT8127 pin control" if COMPILE_TEST && !MACH_MT8127 - depends on OF - default MACH_MT8127 - select PINCTRL_MTK - -# For ARMv8 SoCs -config PINCTRL_MT8173 - bool "Mediatek MT8173 pin control" - depends on OF - depends on ARM64 || COMPILE_TEST - default ARM64 && ARCH_MEDIATEK - select PINCTRL_MTK - -# For PMIC -config PINCTRL_MT6397 - bool "Mediatek MT6397 pin control" if COMPILE_TEST && !MFD_MT6397 - depends on OF - default MFD_MT6397 - select PINCTRL_MTK - -endif diff --git a/src/linux/drivers/pinctrl/mvebu/Kconfig b/src/linux/drivers/pinctrl/mvebu/Kconfig deleted file mode 100644 index 1706024..0000000 --- a/src/linux/drivers/pinctrl/mvebu/Kconfig +++ /dev/null @@ -1,41 +0,0 @@ -if PLAT_ORION - -config PINCTRL_MVEBU - bool - select PINMUX - select PINCONF - -config PINCTRL_DOVE - bool - select PINCTRL_MVEBU - select MFD_SYSCON - -config PINCTRL_KIRKWOOD - bool - select PINCTRL_MVEBU - -config PINCTRL_ARMADA_370 - bool - select PINCTRL_MVEBU - -config PINCTRL_ARMADA_375 - bool - select PINCTRL_MVEBU - -config PINCTRL_ARMADA_38X - bool - select PINCTRL_MVEBU - -config PINCTRL_ARMADA_39X - bool - select PINCTRL_MVEBU - -config PINCTRL_ARMADA_XP - bool - select PINCTRL_MVEBU - -config PINCTRL_ORION - bool - select PINCTRL_MVEBU - -endif diff --git a/src/linux/drivers/pinctrl/nomadik/Kconfig b/src/linux/drivers/pinctrl/nomadik/Kconfig deleted file mode 100644 index f4fcebf..0000000 --- a/src/linux/drivers/pinctrl/nomadik/Kconfig +++ /dev/null @@ -1,51 +0,0 @@ -if ARCH_U8500 - -config PINCTRL_ABX500 - bool "ST-Ericsson ABx500 family Mixed Signal Circuit gpio functions" - depends on AB8500_CORE - select GENERIC_PINCONF - help - Select this to enable the ABx500 family IC GPIO driver - -config PINCTRL_AB8500 - bool "AB8500 pin controller driver" - depends on PINCTRL_ABX500 && ARCH_U8500 - -config PINCTRL_AB8540 - bool "AB8540 pin controller driver" - depends on PINCTRL_ABX500 && ARCH_U8500 - -config PINCTRL_AB9540 - bool "AB9540 pin controller driver" - depends on PINCTRL_ABX500 && ARCH_U8500 - -config PINCTRL_AB8505 - bool "AB8505 pin controller driver" - depends on PINCTRL_ABX500 && ARCH_U8500 - -endif - -if (ARCH_U8500 || ARCH_NOMADIK) - -config PINCTRL_NOMADIK - bool "Nomadik pin controller driver" - depends on ARCH_U8500 || ARCH_NOMADIK - depends on OF && GPIOLIB - select PINMUX - select PINCONF - select OF_GPIO - select GPIOLIB_IRQCHIP - -config PINCTRL_STN8815 - bool "STN8815 pin controller driver" - depends on PINCTRL_NOMADIK && ARCH_NOMADIK - -config PINCTRL_DB8500 - bool "DB8500 pin controller driver" - depends on PINCTRL_NOMADIK && ARCH_U8500 - -config PINCTRL_DB8540 - bool "DB8540 pin controller driver" - depends on PINCTRL_NOMADIK && ARCH_U8500 - -endif diff --git a/src/linux/drivers/pinctrl/pxa/Kconfig b/src/linux/drivers/pinctrl/pxa/Kconfig deleted file mode 100644 index c29bdcf..0000000 --- a/src/linux/drivers/pinctrl/pxa/Kconfig +++ /dev/null @@ -1,25 +0,0 @@ -if (ARCH_PXA || COMPILE_TEST) - -config PINCTRL_PXA - bool - select PINMUX - select PINCONF - select GENERIC_PINCONF - -config PINCTRL_PXA25X - tristate "Marvell PXA25x pin controller driver" - select PINCTRL_PXA - default y if PXA25x - help - This is the pinctrl, pinmux, pinconf driver for the Marvell - PXA2xx block found in the pxa25x platforms. - -config PINCTRL_PXA27X - tristate "Marvell PXA27x pin controller driver" - select PINCTRL_PXA - default y if PXA27x - help - This is the pinctrl, pinmux, pinconf driver for the Marvell - PXA2xx block found in the pxa27x platforms. - -endif diff --git a/src/linux/drivers/pinctrl/qcom/Kconfig b/src/linux/drivers/pinctrl/qcom/Kconfig deleted file mode 100644 index 93ef268..0000000 --- a/src/linux/drivers/pinctrl/qcom/Kconfig +++ /dev/null @@ -1,123 +0,0 @@ -if (ARCH_QCOM || COMPILE_TEST) - -config PINCTRL_MSM - bool - select PINMUX - select PINCONF - select GENERIC_PINCONF - select GPIOLIB_IRQCHIP - -config PINCTRL_APQ8064 - tristate "Qualcomm APQ8064 pin controller driver" - depends on GPIOLIB && OF - select PINCTRL_MSM - help - This is the pinctrl, pinmux, pinconf and gpiolib driver for the - Qualcomm TLMM block found in the Qualcomm APQ8064 platform. - -config PINCTRL_APQ8084 - tristate "Qualcomm APQ8084 pin controller driver" - depends on GPIOLIB && OF - select PINCTRL_MSM - help - This is the pinctrl, pinmux, pinconf and gpiolib driver for the - Qualcomm TLMM block found in the Qualcomm APQ8084 platform. - -config PINCTRL_IPQ4019 - tristate "Qualcomm IPQ4019 pin controller driver" - depends on GPIOLIB && OF - select PINCTRL_MSM - help - This is the pinctrl, pinmux, pinconf and gpiolib driver for the - Qualcomm TLMM block found in the Qualcomm IPQ4019 platform. - -config PINCTRL_IPQ8064 - tristate "Qualcomm IPQ8064 pin controller driver" - depends on GPIOLIB && OF - select PINCTRL_MSM - help - This is the pinctrl, pinmux, pinconf and gpiolib driver for the - Qualcomm TLMM block found in the Qualcomm IPQ8064 platform. - -config PINCTRL_MSM8660 - tristate "Qualcomm 8660 pin controller driver" - depends on GPIOLIB && OF - select PINCTRL_MSM - help - This is the pinctrl, pinmux, pinconf and gpiolib driver for the - Qualcomm TLMM block found in the Qualcomm 8660 platform. - -config PINCTRL_MSM8960 - tristate "Qualcomm 8960 pin controller driver" - depends on GPIOLIB && OF - select PINCTRL_MSM - help - This is the pinctrl, pinmux, pinconf and gpiolib driver for the - Qualcomm TLMM block found in the Qualcomm 8960 platform. - -config PINCTRL_MDM9615 - tristate "Qualcomm 9615 pin controller driver" - depends on GPIOLIB && OF - select PINCTRL_MSM - help - This is the pinctrl, pinmux, pinconf and gpiolib driver for the - Qualcomm TLMM block found in the Qualcomm 9615 platform. - -config PINCTRL_MSM8X74 - tristate "Qualcomm 8x74 pin controller driver" - depends on GPIOLIB && OF - select PINCTRL_MSM - help - This is the pinctrl, pinmux, pinconf and gpiolib driver for the - Qualcomm TLMM block found in the Qualcomm 8974 platform. - -config PINCTRL_MSM8916 - tristate "Qualcomm 8916 pin controller driver" - depends on GPIOLIB && OF - select PINCTRL_MSM - help - This is the pinctrl, pinmux, pinconf and gpiolib driver for the - Qualcomm TLMM block found on the Qualcomm 8916 platform. - -config PINCTRL_MSM8996 - tristate "Qualcomm MSM8996 pin controller driver" - depends on GPIOLIB && OF - select PINCTRL_MSM - help - This is the pinctrl, pinmux, pinconf and gpiolib driver for the - Qualcomm TLMM block found in the Qualcomm MSM8996 platform. - -config PINCTRL_QDF2XXX - tristate "Qualcomm Technologies QDF2xxx pin controller driver" - depends on GPIOLIB && ACPI - select PINCTRL_MSM - help - This is the GPIO driver for the TLMM block found on the - Qualcomm Technologies QDF2xxx SOCs. - -config PINCTRL_QCOM_SPMI_PMIC - tristate "Qualcomm SPMI PMIC pin controller driver" - depends on GPIOLIB && OF && SPMI - select REGMAP_SPMI - select PINMUX - select PINCONF - select GENERIC_PINCONF - help - This is the pinctrl, pinmux, pinconf and gpiolib driver for the - Qualcomm GPIO and MPP blocks found in the Qualcomm PMIC's chips, - which are using SPMI for communication with SoC. Example PMIC's - devices are pm8841, pm8941 and pma8084. - -config PINCTRL_QCOM_SSBI_PMIC - tristate "Qualcomm SSBI PMIC pin controller driver" - depends on GPIOLIB && OF - select PINMUX - select PINCONF - select GENERIC_PINCONF - help - This is the pinctrl, pinmux, pinconf and gpiolib driver for the - Qualcomm GPIO and MPP blocks found in the Qualcomm PMIC's chips, - which are using SSBI for communication with SoC. Example PMIC's - devices are pm8058 and pm8921. - -endif diff --git a/src/linux/drivers/pinctrl/samsung/Kconfig b/src/linux/drivers/pinctrl/samsung/Kconfig deleted file mode 100644 index d0461cd..0000000 --- a/src/linux/drivers/pinctrl/samsung/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -# -# Samsung Pin control drivers -# -config PINCTRL_SAMSUNG - bool - select PINMUX - select PINCONF - -config PINCTRL_EXYNOS - bool "Pinctrl driver data for Samsung EXYNOS SoCs other than 5440" - depends on OF && GPIOLIB && (ARCH_EXYNOS || ARCH_S5PV210) - select PINCTRL_SAMSUNG - -config PINCTRL_EXYNOS5440 - bool "Samsung EXYNOS5440 SoC pinctrl driver" - depends on SOC_EXYNOS5440 - select PINMUX - select PINCONF - -config PINCTRL_S3C24XX - bool "Samsung S3C24XX SoC pinctrl driver" - depends on ARCH_S3C24XX - select PINCTRL_SAMSUNG - -config PINCTRL_S3C64XX - bool "Samsung S3C64XX SoC pinctrl driver" - depends on ARCH_S3C64XX - select PINCTRL_SAMSUNG diff --git a/src/linux/drivers/pinctrl/sh-pfc/Kconfig b/src/linux/drivers/pinctrl/sh-pfc/Kconfig deleted file mode 100644 index 07eca54..0000000 --- a/src/linux/drivers/pinctrl/sh-pfc/Kconfig +++ /dev/null @@ -1,147 +0,0 @@ -# -# Renesas SH and SH Mobile PINCTRL drivers -# - -if ARCH_RENESAS || SUPERH - -config PINCTRL_SH_PFC - select PINMUX - select PINCONF - select GENERIC_PINCONF - def_bool y - help - This enables pin control drivers for SH and SH Mobile platforms - -config PINCTRL_SH_PFC_GPIO - select GPIOLIB - select PINCTRL_SH_PFC - bool - help - This enables pin control and GPIO drivers for SH/SH Mobile platforms - -config PINCTRL_PFC_EMEV2 - def_bool y - depends on ARCH_EMEV2 - select PINCTRL_SH_PFC - -config PINCTRL_PFC_R8A73A4 - def_bool y - depends on ARCH_R8A73A4 - select PINCTRL_SH_PFC_GPIO - -config PINCTRL_PFC_R8A7740 - def_bool y - depends on ARCH_R8A7740 - select PINCTRL_SH_PFC_GPIO - -config PINCTRL_PFC_R8A7778 - def_bool y - depends on ARCH_R8A7778 - select PINCTRL_SH_PFC - -config PINCTRL_PFC_R8A7779 - def_bool y - depends on ARCH_R8A7779 - select PINCTRL_SH_PFC - -config PINCTRL_PFC_R8A7790 - def_bool y - depends on ARCH_R8A7790 - select PINCTRL_SH_PFC - -config PINCTRL_PFC_R8A7791 - def_bool y - depends on ARCH_R8A7791 - select PINCTRL_SH_PFC - -config PINCTRL_PFC_R8A7792 - def_bool y - depends on ARCH_R8A7792 - select PINCTRL_SH_PFC - -config PINCTRL_PFC_R8A7793 - def_bool y - depends on ARCH_R8A7793 - select PINCTRL_SH_PFC - -config PINCTRL_PFC_R8A7794 - def_bool y - depends on ARCH_R8A7794 - select PINCTRL_SH_PFC - -config PINCTRL_PFC_R8A7795 - def_bool y - depends on ARCH_R8A7795 - select PINCTRL_SH_PFC - -config PINCTRL_PFC_R8A7796 - def_bool y - depends on ARCH_R8A7796 - select PINCTRL_SH_PFC - -config PINCTRL_PFC_SH7203 - def_bool y - depends on CPU_SUBTYPE_SH7203 - select PINCTRL_SH_PFC_GPIO - -config PINCTRL_PFC_SH7264 - def_bool y - depends on CPU_SUBTYPE_SH7264 - select PINCTRL_SH_PFC_GPIO - -config PINCTRL_PFC_SH7269 - def_bool y - depends on CPU_SUBTYPE_SH7269 - select PINCTRL_SH_PFC_GPIO - -config PINCTRL_PFC_SH73A0 - def_bool y - depends on ARCH_SH73A0 - select PINCTRL_SH_PFC_GPIO - select REGULATOR - -config PINCTRL_PFC_SH7720 - def_bool y - depends on CPU_SUBTYPE_SH7720 - select PINCTRL_SH_PFC_GPIO - -config PINCTRL_PFC_SH7722 - def_bool y - depends on CPU_SUBTYPE_SH7722 - select PINCTRL_SH_PFC_GPIO - -config PINCTRL_PFC_SH7723 - def_bool y - depends on CPU_SUBTYPE_SH7723 - select PINCTRL_SH_PFC_GPIO - -config PINCTRL_PFC_SH7724 - def_bool y - depends on CPU_SUBTYPE_SH7724 - select PINCTRL_SH_PFC_GPIO - -config PINCTRL_PFC_SH7734 - def_bool y - depends on CPU_SUBTYPE_SH7734 - select PINCTRL_SH_PFC_GPIO - -config PINCTRL_PFC_SH7757 - def_bool y - depends on CPU_SUBTYPE_SH7757 - select PINCTRL_SH_PFC_GPIO - -config PINCTRL_PFC_SH7785 - def_bool y - depends on CPU_SUBTYPE_SH7785 - select PINCTRL_SH_PFC_GPIO - -config PINCTRL_PFC_SH7786 - def_bool y - depends on CPU_SUBTYPE_SH7786 - select PINCTRL_SH_PFC_GPIO - -config PINCTRL_PFC_SHX3 - def_bool y - depends on CPU_SUBTYPE_SHX3 - select PINCTRL_SH_PFC_GPIO -endif diff --git a/src/linux/drivers/pinctrl/spear/Kconfig b/src/linux/drivers/pinctrl/spear/Kconfig deleted file mode 100644 index 9ef18eb..0000000 --- a/src/linux/drivers/pinctrl/spear/Kconfig +++ /dev/null @@ -1,56 +0,0 @@ -# -# ST Microelectronics SPEAr PINCTRL drivers -# - -if PLAT_SPEAR - -config PINCTRL_SPEAR - bool - depends on OF - select PINMUX - help - This enables pin control drivers for SPEAr Platform - -config PINCTRL_SPEAR3XX - bool - depends on ARCH_SPEAR3XX - select PINCTRL_SPEAR - -config PINCTRL_SPEAR300 - bool "ST Microelectronics SPEAr300 SoC pin controller driver" - depends on MACH_SPEAR300 - select PINCTRL_SPEAR3XX - -config PINCTRL_SPEAR310 - bool "ST Microelectronics SPEAr310 SoC pin controller driver" - depends on MACH_SPEAR310 - select PINCTRL_SPEAR3XX - select PINCTRL_SPEAR_PLGPIO - -config PINCTRL_SPEAR320 - bool "ST Microelectronics SPEAr320 SoC pin controller driver" - depends on MACH_SPEAR320 - select PINCTRL_SPEAR3XX - select PINCTRL_SPEAR_PLGPIO - -config PINCTRL_SPEAR1310 - bool "ST Microelectronics SPEAr1310 SoC pin controller driver" - depends on MACH_SPEAR1310 - select PINCTRL_SPEAR - select PINCTRL_SPEAR_PLGPIO - -config PINCTRL_SPEAR1340 - bool "ST Microelectronics SPEAr1340 SoC pin controller driver" - depends on MACH_SPEAR1340 - select PINCTRL_SPEAR - select PINCTRL_SPEAR_PLGPIO - -config PINCTRL_SPEAR_PLGPIO - bool "SPEAr SoC PLGPIO Controller" - depends on GPIOLIB && PINCTRL_SPEAR - select GPIOLIB_IRQCHIP - help - Say yes here to support PLGPIO controller on ST Microelectronics SPEAr - SoCs. - -endif diff --git a/src/linux/drivers/pinctrl/stm32/Kconfig b/src/linux/drivers/pinctrl/stm32/Kconfig deleted file mode 100644 index c03dce7..0000000 --- a/src/linux/drivers/pinctrl/stm32/Kconfig +++ /dev/null @@ -1,23 +0,0 @@ -if ARCH_STM32 || COMPILE_TEST - -config PINCTRL_STM32 - bool - depends on OF - select PINMUX - select GENERIC_PINCONF - select GPIOLIB - select MFD_SYSCON - -config PINCTRL_STM32F429 - bool "STMicroelectronics STM32F429 pin control" if COMPILE_TEST && !MACH_STM32F429 - depends on OF && IRQ_DOMAIN_HIERARCHY - default MACH_STM32F429 - select PINCTRL_STM32 - -config PINCTRL_STM32F746 - bool "STMicroelectronics STM32F746 pin control" if COMPILE_TEST && !MACH_STM32F746 - depends on OF && IRQ_DOMAIN_HIERARCHY - default MACH_STM32F746 - select PINCTRL_STM32 - -endif diff --git a/src/linux/drivers/pinctrl/sunxi/Kconfig b/src/linux/drivers/pinctrl/sunxi/Kconfig deleted file mode 100644 index bff1ffc..0000000 --- a/src/linux/drivers/pinctrl/sunxi/Kconfig +++ /dev/null @@ -1,79 +0,0 @@ -if ARCH_SUNXI - -config PINCTRL_SUNXI - bool - select PINMUX - select GENERIC_PINCONF - -config PINCTRL_SUN4I_A10 - def_bool MACH_SUN4I - select PINCTRL_SUNXI - -config PINCTRL_SUN5I_A10S - def_bool MACH_SUN5I - select PINCTRL_SUNXI - -config PINCTRL_SUN5I_A13 - def_bool MACH_SUN5I - select PINCTRL_SUNXI - -config PINCTRL_GR8 - def_bool MACH_SUN5I - select PINCTRL_SUNXI_COMMON - -config PINCTRL_SUN6I_A31 - def_bool MACH_SUN6I - select PINCTRL_SUNXI - -config PINCTRL_SUN6I_A31S - def_bool MACH_SUN6I - select PINCTRL_SUNXI - -config PINCTRL_SUN6I_A31_R - def_bool MACH_SUN6I - depends on RESET_CONTROLLER - select PINCTRL_SUNXI - -config PINCTRL_SUN7I_A20 - def_bool MACH_SUN7I - select PINCTRL_SUNXI - -config PINCTRL_SUN8I_A23 - def_bool MACH_SUN8I - select PINCTRL_SUNXI - -config PINCTRL_SUN8I_A33 - def_bool MACH_SUN8I - select PINCTRL_SUNXI - -config PINCTRL_SUN8I_A83T - def_bool MACH_SUN8I - select PINCTRL_SUNXI - -config PINCTRL_SUN8I_A23_R - def_bool MACH_SUN8I - depends on RESET_CONTROLLER - select PINCTRL_SUNXI - -config PINCTRL_SUN8I_H3 - def_bool MACH_SUN8I - select PINCTRL_SUNXI - -config PINCTRL_SUN8I_H3_R - def_bool MACH_SUN8I - select PINCTRL_SUNXI_COMMON - -config PINCTRL_SUN9I_A80 - def_bool MACH_SUN9I - select PINCTRL_SUNXI - -config PINCTRL_SUN9I_A80_R - def_bool MACH_SUN9I - depends on RESET_CONTROLLER - select PINCTRL_SUNXI - -config PINCTRL_SUN50I_A64 - bool - select PINCTRL_SUNXI - -endif diff --git a/src/linux/drivers/pinctrl/tegra/Kconfig b/src/linux/drivers/pinctrl/tegra/Kconfig deleted file mode 100644 index 24e20cc..0000000 --- a/src/linux/drivers/pinctrl/tegra/Kconfig +++ /dev/null @@ -1,30 +0,0 @@ -config PINCTRL_TEGRA - bool - select PINMUX - select PINCONF - -config PINCTRL_TEGRA20 - bool - select PINCTRL_TEGRA - -config PINCTRL_TEGRA30 - bool - select PINCTRL_TEGRA - -config PINCTRL_TEGRA114 - bool - select PINCTRL_TEGRA - -config PINCTRL_TEGRA124 - bool - select PINCTRL_TEGRA - -config PINCTRL_TEGRA210 - bool - select PINCTRL_TEGRA - -config PINCTRL_TEGRA_XUSB - def_bool y if ARCH_TEGRA - select GENERIC_PHY - select PINCONF - select PINMUX diff --git a/src/linux/drivers/pinctrl/uniphier/Kconfig b/src/linux/drivers/pinctrl/uniphier/Kconfig deleted file mode 100644 index e077a9e..0000000 --- a/src/linux/drivers/pinctrl/uniphier/Kconfig +++ /dev/null @@ -1,43 +0,0 @@ -menuconfig PINCTRL_UNIPHIER - bool "UniPhier SoC pinctrl drivers" - depends on ARCH_UNIPHIER || COMPILE_TEST - depends on OF && MFD_SYSCON - default y - select PINMUX - select GENERIC_PINCONF - -if PINCTRL_UNIPHIER - -config PINCTRL_UNIPHIER_LD4 - tristate "UniPhier PH1-LD4 SoC pinctrl driver" - default ARM - -config PINCTRL_UNIPHIER_PRO4 - tristate "UniPhier PH1-Pro4 SoC pinctrl driver" - default ARM - -config PINCTRL_UNIPHIER_SLD8 - tristate "UniPhier PH1-sLD8 SoC pinctrl driver" - default ARM - -config PINCTRL_UNIPHIER_PRO5 - tristate "UniPhier PH1-Pro5 SoC pinctrl driver" - default ARM - -config PINCTRL_UNIPHIER_PXS2 - tristate "UniPhier ProXstream2 SoC pinctrl driver" - default ARM - -config PINCTRL_UNIPHIER_LD6B - tristate "UniPhier PH1-LD6b SoC pinctrl driver" - default ARM - -config PINCTRL_UNIPHIER_LD11 - tristate "UniPhier PH1-LD11 SoC pinctrl driver" - default ARM64 - -config PINCTRL_UNIPHIER_LD20 - tristate "UniPhier PH1-LD20 SoC pinctrl driver" - default ARM64 - -endif diff --git a/src/linux/drivers/pinctrl/vt8500/Kconfig b/src/linux/drivers/pinctrl/vt8500/Kconfig deleted file mode 100644 index 55724a7..0000000 --- a/src/linux/drivers/pinctrl/vt8500/Kconfig +++ /dev/null @@ -1,52 +0,0 @@ -# -# VIA/Wondermedia PINCTRL drivers -# - -if ARCH_VT8500 - -config PINCTRL_WMT - bool - select PINMUX - select GENERIC_PINCONF - -config PINCTRL_VT8500 - bool "VIA VT8500 pin controller driver" - depends on ARCH_WM8505 - select PINCTRL_WMT - help - Say yes here to support the gpio/pin control module on - VIA VT8500 SoCs. - -config PINCTRL_WM8505 - bool "Wondermedia WM8505 pin controller driver" - depends on ARCH_WM8505 - select PINCTRL_WMT - help - Say yes here to support the gpio/pin control module on - Wondermedia WM8505 SoCs. - -config PINCTRL_WM8650 - bool "Wondermedia WM8650 pin controller driver" - depends on ARCH_WM8505 - select PINCTRL_WMT - help - Say yes here to support the gpio/pin control module on - Wondermedia WM8650 SoCs. - -config PINCTRL_WM8750 - bool "Wondermedia WM8750 pin controller driver" - depends on ARCH_WM8750 - select PINCTRL_WMT - help - Say yes here to support the gpio/pin control module on - Wondermedia WM8750 SoCs. - -config PINCTRL_WM8850 - bool "Wondermedia WM8850 pin controller driver" - depends on ARCH_WM8850 - select PINCTRL_WMT - help - Say yes here to support the gpio/pin control module on - Wondermedia WM8850 SoCs. - -endif diff --git a/src/linux/drivers/platform/Kconfig b/src/linux/drivers/platform/Kconfig deleted file mode 100644 index c11db8b..0000000 --- a/src/linux/drivers/platform/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -if X86 -source "drivers/platform/x86/Kconfig" -endif -if MIPS -source "drivers/platform/mips/Kconfig" -endif - -source "drivers/platform/goldfish/Kconfig" - -source "drivers/platform/chrome/Kconfig" diff --git a/src/linux/drivers/platform/Makefile b/src/linux/drivers/platform/Makefile deleted file mode 100644 index ca26925..0000000 --- a/src/linux/drivers/platform/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for linux/drivers/platform -# - -obj-$(CONFIG_X86) += x86/ -obj-$(CONFIG_MIPS) += mips/ -obj-$(CONFIG_OLPC) += olpc/ -obj-$(CONFIG_GOLDFISH) += goldfish/ -obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ diff --git a/src/linux/drivers/platform/chrome/Kconfig b/src/linux/drivers/platform/chrome/Kconfig deleted file mode 100644 index 76bdae1..0000000 --- a/src/linux/drivers/platform/chrome/Kconfig +++ /dev/null @@ -1,77 +0,0 @@ -# -# Platform support for Chrome OS hardware (Chromebooks and Chromeboxes) -# - -menuconfig CHROME_PLATFORMS - bool "Platform support for Chrome hardware" - depends on X86 || ARM || ARM64 || COMPILE_TEST - ---help--- - Say Y here to get to see options for platform support for - various Chromebooks and Chromeboxes. This option alone does - not add any kernel code. - - If you say N, all options in this submenu will be skipped and disabled. - -if CHROME_PLATFORMS - -config CHROMEOS_LAPTOP - tristate "Chrome OS Laptop" - depends on I2C && DMI && X86 - ---help--- - This driver instantiates i2c and smbus devices such as - light sensors and touchpads. - - If you have a supported Chromebook, choose Y or M here. - The module will be called chromeos_laptop. - -config CHROMEOS_PSTORE - tristate "Chrome OS pstore support" - depends on X86 - ---help--- - This module instantiates the persistent storage on x86 ChromeOS - devices. It can be used to store away console logs and crash - information across reboots. - - The range of memory used is 0xf00000-0x1000000, traditionally - the memory used to back VGA controller memory. - - If you have a supported Chromebook, choose Y or M here. - The module will be called chromeos_pstore. - -config CROS_EC_CHARDEV - tristate "Chrome OS Embedded Controller userspace device interface" - depends on MFD_CROS_EC - ---help--- - This driver adds support to talk with the ChromeOS EC from userspace. - - If you have a supported Chromebook, choose Y or M here. - The module will be called cros_ec_dev. - -config CROS_EC_LPC - tristate "ChromeOS Embedded Controller (LPC)" - depends on MFD_CROS_EC && (X86 || COMPILE_TEST) - help - If you say Y here, you get support for talking to the ChromeOS EC - over an LPC bus. This uses a simple byte-level protocol with a - checksum. This is used for userspace access only. The kernel - typically has its own communication methods. - - To compile this driver as a module, choose M here: the - module will be called cros_ec_lpc. - -config CROS_EC_PROTO - bool - help - ChromeOS EC communication protocol helpers. - -config CROS_KBD_LED_BACKLIGHT - tristate "Backlight LED support for Chrome OS keyboards" - depends on LEDS_CLASS && ACPI - help - This option enables support for the keyboard backlight LEDs on - select Chrome OS systems. - - To compile this driver as a module, choose M here: the - module will be called cros_kbd_led_backlight. - -endif # CHROMEOS_PLATFORMS diff --git a/src/linux/drivers/platform/goldfish/Kconfig b/src/linux/drivers/platform/goldfish/Kconfig deleted file mode 100644 index fefbb83..0000000 --- a/src/linux/drivers/platform/goldfish/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -menuconfig GOLDFISH - bool "Platform support for Goldfish virtual devices" - depends on X86_32 || X86_64 || ARM || ARM64 || MIPS - depends on HAS_IOMEM - ---help--- - Say Y here to get to see options for the Goldfish virtual platform. - This option alone does not add any kernel code. - - Unless you are building for the Android Goldfish emulator say N here. - -if GOLDFISH - -config GOLDFISH_BUS - bool "Goldfish platform bus" - ---help--- - This is a virtual bus to host Goldfish Android Virtual Devices. - -config GOLDFISH_PIPE - tristate "Goldfish virtual device for QEMU pipes" - ---help--- - This is a virtual device to drive the QEMU pipe interface used by - the Goldfish Android Virtual Device. - -endif # GOLDFISH diff --git a/src/linux/drivers/platform/mips/Kconfig b/src/linux/drivers/platform/mips/Kconfig deleted file mode 100644 index b3ae30a..0000000 --- a/src/linux/drivers/platform/mips/Kconfig +++ /dev/null @@ -1,26 +0,0 @@ -# -# MIPS Platform Specific Drivers -# - -menuconfig MIPS_PLATFORM_DEVICES - bool "MIPS Platform Specific Device Drivers" - default y - help - Say Y here to get to see options for device drivers of various - MIPS platforms, including vendor-specific netbook/laptop/desktop - extension and hardware monitor drivers. This option itself does - not add any kernel code. - - If you say N, all options in this submenu will be skipped and disabled. - -if MIPS_PLATFORM_DEVICES - -config CPU_HWMON - tristate "Loongson CPU HWMon Driver" - depends on LOONGSON_MACH3X - select HWMON - default y - help - Loongson-3A/3B CPU Hwmon (temperature sensor) driver. - -endif # MIPS_PLATFORM_DEVICES diff --git a/src/linux/drivers/platform/x86/Kconfig b/src/linux/drivers/platform/x86/Kconfig deleted file mode 100644 index b8a21d7..0000000 --- a/src/linux/drivers/platform/x86/Kconfig +++ /dev/null @@ -1,1030 +0,0 @@ -# -# X86 Platform Specific Drivers -# - -menuconfig X86_PLATFORM_DEVICES - bool "X86 Platform Specific Device Drivers" - default y - depends on X86 - ---help--- - Say Y here to get to see options for device drivers for various - x86 platforms, including vendor-specific laptop extension drivers. - This option alone does not add any kernel code. - - If you say N, all options in this submenu will be skipped and disabled. - -if X86_PLATFORM_DEVICES - -config ACER_WMI - tristate "Acer WMI Laptop Extras" - depends on ACPI - select LEDS_CLASS - select NEW_LEDS - depends on BACKLIGHT_CLASS_DEVICE - depends on SERIO_I8042 - depends on INPUT - depends on RFKILL || RFKILL = n - depends on ACPI_WMI - select INPUT_SPARSEKMAP - # Acer WMI depends on ACPI_VIDEO when ACPI is enabled - select ACPI_VIDEO if ACPI - ---help--- - This is a driver for newer Acer (and Wistron) laptops. It adds - wireless radio and bluetooth control, and on some laptops, - exposes the mail LED and LCD backlight. - - If you have an ACPI-WMI compatible Acer/ Wistron laptop, say Y or M - here. - -config ACERHDF - tristate "Acer Aspire One temperature and fan driver" - depends on ACPI && THERMAL - select THERMAL_GOV_BANG_BANG - ---help--- - This is a driver for Acer Aspire One netbooks. It allows to access - the temperature sensor and to control the fan. - - After loading this driver the BIOS is still in control of the fan. - To let the kernel handle the fan, do: - echo -n enabled > /sys/class/thermal/thermal_zone0/mode - - For more information about this driver see - - - If you have an Acer Aspire One netbook, say Y or M - here. - -config ALIENWARE_WMI - tristate "Alienware Special feature control" - depends on ACPI - depends on LEDS_CLASS - depends on NEW_LEDS - depends on ACPI_WMI - ---help--- - This is a driver for controlling Alienware BIOS driven - features. It exposes an interface for controlling the AlienFX - zones on Alienware machines that don't contain a dedicated AlienFX - USB MCU such as the X51 and X51-R2. - -config ASUS_LAPTOP - tristate "Asus Laptop Extras" - depends on ACPI - select LEDS_CLASS - select NEW_LEDS - depends on BACKLIGHT_CLASS_DEVICE - depends on INPUT - depends on RFKILL || RFKILL = n - depends on ACPI_VIDEO || ACPI_VIDEO = n - select INPUT_SPARSEKMAP - select INPUT_POLLDEV - ---help--- - This is a driver for Asus laptops, Lenovo SL and the Pegatron - Lucid tablet. It may also support some MEDION, JVC or VICTOR - laptops. It makes all the extra buttons generate standard - ACPI events and input events, and on the Lucid the built-in - accelerometer appears as an input device. It also adds - support for video output switching, LCD backlight control, - Bluetooth and Wlan control, and most importantly, allows you - to blink those fancy LEDs. - - For more information see . - - If you have an ACPI-compatible ASUS laptop, say Y or M here. - -config DELL_SMBIOS - tristate "Dell SMBIOS Support" - depends on DCDBAS - default n - ---help--- - This module provides common functions for kernel modules using - Dell SMBIOS. - - If you have a Dell laptop, say Y or M here. - -config DELL_LAPTOP - tristate "Dell Laptop Extras" - depends on DELL_SMBIOS - depends on DMI - depends on BACKLIGHT_CLASS_DEVICE - depends on ACPI_VIDEO || ACPI_VIDEO = n - depends on RFKILL || RFKILL = n - depends on SERIO_I8042 - select POWER_SUPPLY - select LEDS_CLASS - select NEW_LEDS - default n - ---help--- - This driver adds support for rfkill and backlight control to Dell - laptops (except for some models covered by the Compal driver). - -config DELL_WMI - tristate "Dell WMI extras" - depends on ACPI_WMI - depends on DMI - depends on INPUT - depends on ACPI_VIDEO || ACPI_VIDEO = n - depends on DELL_SMBIOS - select INPUT_SPARSEKMAP - ---help--- - Say Y here if you want to support WMI-based hotkeys on Dell laptops. - - To compile this driver as a module, choose M here: the module will - be called dell-wmi. - -config DELL_WMI_AIO - tristate "WMI Hotkeys for Dell All-In-One series" - depends on ACPI_WMI - depends on INPUT - select INPUT_SPARSEKMAP - ---help--- - Say Y here if you want to support WMI-based hotkeys on Dell - All-In-One machines. - - To compile this driver as a module, choose M here: the module will - be called dell-wmi-aio. - -config DELL_SMO8800 - tristate "Dell Latitude freefall driver (ACPI SMO88XX)" - depends on ACPI - ---help--- - Say Y here if you want to support SMO88XX freefall devices - on Dell Latitude laptops. - - To compile this driver as a module, choose M here: the module will - be called dell-smo8800. - -config DELL_RBTN - tristate "Dell Airplane Mode Switch driver" - depends on ACPI - depends on INPUT - depends on RFKILL - ---help--- - Say Y here if you want to support Dell Airplane Mode Switch ACPI - device on Dell laptops. Sometimes it has names: DELLABCE or DELRBTN. - This driver register rfkill device or input hotkey device depending - on hardware type (hw switch slider or keyboard toggle button). For - rfkill devices it receive HW switch events and set correct hard - rfkill state. - - To compile this driver as a module, choose M here: the module will - be called dell-rbtn. - - -config FUJITSU_LAPTOP - tristate "Fujitsu Laptop Extras" - depends on ACPI - depends on INPUT - depends on BACKLIGHT_CLASS_DEVICE - depends on ACPI_VIDEO || ACPI_VIDEO = n - depends on LEDS_CLASS || LEDS_CLASS=n - ---help--- - This is a driver for laptops built by Fujitsu: - - * P2xxx/P5xxx/S6xxx/S7xxx series Lifebooks - * Possibly other Fujitsu laptop models - * Tested with S6410 and S7020 - - It adds support for LCD brightness control and some hotkeys. - - If you have a Fujitsu laptop, say Y or M here. - -config FUJITSU_LAPTOP_DEBUG - bool "Verbose debug mode for Fujitsu Laptop Extras" - depends on FUJITSU_LAPTOP - default n - ---help--- - Enables extra debug output from the fujitsu extras driver, at the - expense of a slight increase in driver size. - - If you are not sure, say N here. - -config FUJITSU_TABLET - tristate "Fujitsu Tablet Extras" - depends on ACPI - depends on INPUT - ---help--- - This is a driver for tablets built by Fujitsu: - - * Lifebook P1510/P1610/P1620/Txxxx - * Stylistic ST5xxx - * Possibly other Fujitsu tablet models - - It adds support for the panel buttons, docking station detection, - tablet/notebook mode detection for convertible and - orientation detection for docked slates. - - If you have a Fujitsu convertible or slate, say Y or M here. - -config AMILO_RFKILL - tristate "Fujitsu-Siemens Amilo rfkill support" - depends on RFKILL - depends on SERIO_I8042 - ---help--- - This is a driver for enabling wifi on some Fujitsu-Siemens Amilo - laptops. - -config TC1100_WMI - tristate "HP Compaq TC1100 Tablet WMI Extras" - depends on !X86_64 - depends on ACPI - depends on ACPI_WMI - ---help--- - This is a driver for the WMI extensions (wireless and bluetooth power - control) of the HP Compaq TC1100 tablet. - -config HP_ACCEL - tristate "HP laptop accelerometer" - depends on INPUT && ACPI - depends on SERIO_I8042 - select SENSORS_LIS3LV02D - select NEW_LEDS - select LEDS_CLASS - help - This driver provides support for the "Mobile Data Protection System 3D" - or "3D DriveGuard" feature of HP laptops. On such systems the driver - should load automatically (via ACPI alias). - - Support for a led indicating disk protection will be provided as - hp::hddprotect. For more information on the feature, refer to - Documentation/misc-devices/lis3lv02d. - - To compile this driver as a module, choose M here: the module will - be called hp_accel. - -config HP_WIRELESS - tristate "HP wireless button" - depends on ACPI - depends on INPUT - help - This driver provides supports for new HP wireless button for Windows 8. - On such systems the driver should load automatically (via ACPI alias). - - To compile this driver as a module, choose M here: the module will - be called hp-wireless. - -config HP_WMI - tristate "HP WMI extras" - depends on ACPI_WMI - depends on INPUT - depends on RFKILL || RFKILL = n - select INPUT_SPARSEKMAP - help - Say Y here if you want to support WMI-based hotkeys on HP laptops and - to read data from WMI such as docking or ambient light sensor state. - - To compile this driver as a module, choose M here: the module will - be called hp-wmi. - -config MSI_LAPTOP - tristate "MSI Laptop Extras" - depends on ACPI - depends on BACKLIGHT_CLASS_DEVICE - depends on ACPI_VIDEO || ACPI_VIDEO = n - depends on RFKILL - depends on INPUT && SERIO_I8042 - select INPUT_SPARSEKMAP - ---help--- - This is a driver for laptops built by MSI (MICRO-STAR - INTERNATIONAL): - - MSI MegaBook S270 (MS-1013) - Cytron/TCM/Medion/Tchibo MD96100/SAM2000 - - It adds support for Bluetooth, WLAN and LCD brightness control. - - More information about this driver is available at - . - - If you have an MSI S270 laptop, say Y or M here. - -config PANASONIC_LAPTOP - tristate "Panasonic Laptop Extras" - depends on INPUT && ACPI - depends on BACKLIGHT_CLASS_DEVICE - select INPUT_SPARSEKMAP - ---help--- - This driver adds support for access to backlight control and hotkeys - on Panasonic Let's Note laptops. - - If you have a Panasonic Let's note laptop (such as the R1(N variant), - R2, R3, R5, T2, W2 and Y2 series), say Y. - -config COMPAL_LAPTOP - tristate "Compal (and others) Laptop Extras" - depends on ACPI - depends on BACKLIGHT_CLASS_DEVICE - depends on ACPI_VIDEO || ACPI_VIDEO = n - depends on RFKILL - depends on HWMON - depends on POWER_SUPPLY - ---help--- - This is a driver for laptops built by Compal, and some models by - other brands (e.g. Dell, Toshiba). - - It adds support for rfkill, Bluetooth, WLAN, LCD brightness, hwmon - and battery charging level control. - - For a (possibly incomplete) list of supported laptops, please refer - to: Documentation/platform/x86-laptop-drivers.txt - -config SONY_LAPTOP - tristate "Sony Laptop Extras" - depends on ACPI - depends on ACPI_VIDEO || ACPI_VIDEO = n - depends on BACKLIGHT_CLASS_DEVICE - depends on INPUT - depends on RFKILL - ---help--- - This mini-driver drives the SNC and SPIC devices present in the ACPI - BIOS of the Sony Vaio laptops. - - It gives access to some extra laptop functionalities like Bluetooth, - screen brightness control, Fn keys and allows powering on/off some - devices. - - Read for more information. - -config SONYPI_COMPAT - bool "Sonypi compatibility" - depends on SONY_LAPTOP - ---help--- - Build the sonypi driver compatibility code into the sony-laptop driver. - -config IDEAPAD_LAPTOP - tristate "Lenovo IdeaPad Laptop Extras" - depends on ACPI - depends on RFKILL && INPUT - depends on SERIO_I8042 - depends on BACKLIGHT_CLASS_DEVICE - depends on ACPI_VIDEO || ACPI_VIDEO = n - depends on ACPI_WMI || ACPI_WMI = n - select INPUT_SPARSEKMAP - help - This is a driver for Lenovo IdeaPad netbooks contains drivers for - rfkill switch, hotkey, fan control and backlight control. - -config THINKPAD_ACPI - tristate "ThinkPad ACPI Laptop Extras" - depends on ACPI - depends on INPUT - depends on RFKILL || RFKILL = n - depends on ACPI_VIDEO || ACPI_VIDEO = n - depends on BACKLIGHT_CLASS_DEVICE - select HWMON - select NVRAM - select NEW_LEDS - select LEDS_CLASS - ---help--- - This is a driver for the IBM and Lenovo ThinkPad laptops. It adds - support for Fn-Fx key combinations, Bluetooth control, video - output switching, ThinkLight control, UltraBay eject and more. - For more information about this driver see - and - . - - This driver was formerly known as ibm-acpi. - - Extra functionality will be available if the rfkill (CONFIG_RFKILL) - and/or ALSA (CONFIG_SND) subsystems are available in the kernel. - Note that if you want ThinkPad-ACPI to be built-in instead of - modular, ALSA and rfkill will also have to be built-in. - - If you have an IBM or Lenovo ThinkPad laptop, say Y or M here. - -config THINKPAD_ACPI_ALSA_SUPPORT - bool "Console audio control ALSA interface" - depends on THINKPAD_ACPI - depends on SND - depends on SND = y || THINKPAD_ACPI = SND - default y - ---help--- - Enables monitoring of the built-in console audio output control - (headphone and speakers), which is operated by the mute and (in - some ThinkPad models) volume hotkeys. - - If this option is enabled, ThinkPad-ACPI will export an ALSA card - with a single read-only mixer control, which should be used for - on-screen-display feedback purposes by the Desktop Environment. - - Optionally, the driver will also allow software control (the - ALSA mixer will be made read-write). Please refer to the driver - documentation for details. - - All IBM models have both volume and mute control. Newer Lenovo - models only have mute control (the volume hotkeys are just normal - keys and volume control is done through the main HDA mixer). - -config THINKPAD_ACPI_DEBUGFACILITIES - bool "Maintainer debug facilities" - depends on THINKPAD_ACPI - default n - ---help--- - Enables extra stuff in the thinkpad-acpi which is completely useless - for normal use. Read the driver source to find out what it does. - - Say N here, unless you were told by a kernel maintainer to do - otherwise. - -config THINKPAD_ACPI_DEBUG - bool "Verbose debug mode" - depends on THINKPAD_ACPI - default n - ---help--- - Enables extra debugging information, at the expense of a slightly - increase in driver size. - - If you are not sure, say N here. - -config THINKPAD_ACPI_UNSAFE_LEDS - bool "Allow control of important LEDs (unsafe)" - depends on THINKPAD_ACPI - default n - ---help--- - Overriding LED state on ThinkPads can mask important - firmware alerts (like critical battery condition), or misled - the user into damaging the hardware (undocking or ejecting - the bay while buses are still active), etc. - - LED control on the ThinkPad is write-only (with very few - exceptions on very ancient models), which makes it - impossible to know beforehand if important information will - be lost when one changes LED state. - - Users that know what they are doing can enable this option - and the driver will allow control of every LED, including - the ones on the dock stations. - - Never enable this option on a distribution kernel. - - Say N here, unless you are building a kernel for your own - use, and need to control the important firmware LEDs. - -config THINKPAD_ACPI_VIDEO - bool "Video output control support" - depends on THINKPAD_ACPI - default y - ---help--- - Allows the thinkpad_acpi driver to provide an interface to control - the various video output ports. - - This feature often won't work well, depending on ThinkPad model, - display state, video output devices in use, whether there is a X - server running, phase of the moon, and the current mood of - Schroedinger's cat. If you can use X.org's RandR to control - your ThinkPad's video output ports instead of this feature, - don't think twice: do it and say N here to save memory and avoid - bad interactions with X.org. - - NOTE: access to this feature is limited to processes with the - CAP_SYS_ADMIN capability, to avoid local DoS issues in platforms - where it interacts badly with X.org. - - If you are not sure, say Y here but do try to check if you could - be using X.org RandR instead. - -config THINKPAD_ACPI_HOTKEY_POLL - bool "Support NVRAM polling for hot keys" - depends on THINKPAD_ACPI - default y - ---help--- - Some thinkpad models benefit from NVRAM polling to detect a few of - the hot key press events. If you know your ThinkPad model does not - need to do NVRAM polling to support any of the hot keys you use, - unselecting this option will save about 1kB of memory. - - ThinkPads T40 and newer, R52 and newer, and X31 and newer are - unlikely to need NVRAM polling in their latest BIOS versions. - - NVRAM polling can detect at most the following keys: ThinkPad/Access - IBM, Zoom, Switch Display (fn+F7), ThinkLight, Volume up/down/mute, - Brightness up/down, Display Expand (fn+F8), Hibernate (fn+F12). - - If you are not sure, say Y here. The driver enables polling only if - it is strictly necessary to do so. - -config SENSORS_HDAPS - tristate "Thinkpad Hard Drive Active Protection System (hdaps)" - depends on INPUT - select INPUT_POLLDEV - default n - help - This driver provides support for the IBM Hard Drive Active Protection - System (hdaps), which provides an accelerometer and other misc. data. - ThinkPads starting with the R50, T41, and X40 are supported. The - accelerometer data is readable via sysfs. - - This driver also provides an absolute input class device, allowing - the laptop to act as a pinball machine-esque joystick. - - If your ThinkPad is not recognized by the driver, please update to latest - BIOS. This is especially the case for some R52 ThinkPads. - - Say Y here if you have an applicable laptop and want to experience - the awesome power of hdaps. - -config INTEL_MENLOW - tristate "Thermal Management driver for Intel menlow platform" - depends on ACPI_THERMAL - select THERMAL - ---help--- - ACPI thermal management enhancement driver on - Intel Menlow platform. - - If unsure, say N. - -config EEEPC_LAPTOP - tristate "Eee PC Hotkey Driver" - depends on ACPI - depends on INPUT - depends on RFKILL || RFKILL = n - depends on ACPI_VIDEO || ACPI_VIDEO = n - depends on HOTPLUG_PCI - depends on BACKLIGHT_CLASS_DEVICE - select HWMON - select LEDS_CLASS - select NEW_LEDS - select INPUT_SPARSEKMAP - ---help--- - This driver supports the Fn-Fx keys on Eee PC laptops. - - It also gives access to some extra laptop functionalities like - Bluetooth, backlight and allows powering on/off some other - devices. - - If you have an Eee PC laptop, say Y or M here. If this driver - doesn't work on your Eee PC, try eeepc-wmi instead. - -config ASUS_WMI - tristate "ASUS WMI Driver" - depends on ACPI_WMI - depends on INPUT - depends on HWMON - depends on BACKLIGHT_CLASS_DEVICE - depends on RFKILL || RFKILL = n - depends on HOTPLUG_PCI - depends on ACPI_VIDEO || ACPI_VIDEO = n - select INPUT_SPARSEKMAP - select LEDS_CLASS - select NEW_LEDS - ---help--- - Say Y here if you have a WMI aware Asus laptop (like Eee PCs or new - Asus Notebooks). - - To compile this driver as a module, choose M here: the module will - be called asus-wmi. - -config ASUS_NB_WMI - tristate "Asus Notebook WMI Driver" - depends on ASUS_WMI - depends on SERIO_I8042 || SERIO_I8042 = n - ---help--- - This is a driver for newer Asus notebooks. It adds extra features - like wireless radio and bluetooth control, leds, hotkeys, backlight... - - For more information, see - - - If you have an ACPI-WMI compatible Asus Notebook, say Y or M - here. - -config EEEPC_WMI - tristate "Eee PC WMI Driver" - depends on ASUS_WMI - ---help--- - This is a driver for newer Eee PC laptops. It adds extra features - like wireless radio and bluetooth control, leds, hotkeys, backlight... - - For more information, see - - - If you have an ACPI-WMI compatible Eee PC laptop (>= 1000), say Y or M - here. - -config ASUS_WIRELESS - tristate "Asus Wireless Radio Control Driver" - depends on ACPI - depends on INPUT - select NEW_LEDS - select LEDS_CLASS - ---help--- - The Asus Wireless Radio Control handles the airplane mode hotkey - present on some Asus laptops. - - Say Y or M here if you have an ASUS notebook with an airplane mode - hotkey. - - If you choose to compile this driver as a module the module will be - called asus-wireless. - -config ACPI_WMI - tristate "WMI" - depends on ACPI - help - This driver adds support for the ACPI-WMI (Windows Management - Instrumentation) mapper device (PNP0C14) found on some systems. - - ACPI-WMI is a proprietary extension to ACPI to expose parts of the - ACPI firmware to userspace - this is done through various vendor - defined methods and data blocks in a PNP0C14 device, which are then - made available for userspace to call. - - The implementation of this in Linux currently only exposes this to - other kernel space drivers. - - This driver is a required dependency to build the firmware specific - drivers needed on many machines, including Acer and HP laptops. - - It is safe to enable this driver even if your DSDT doesn't define - any ACPI-WMI devices. - -config MSI_WMI - tristate "MSI WMI extras" - depends on ACPI_WMI - depends on INPUT - depends on BACKLIGHT_CLASS_DEVICE - depends on ACPI_VIDEO || ACPI_VIDEO = n - select INPUT_SPARSEKMAP - help - Say Y here if you want to support WMI-based hotkeys on MSI laptops. - - To compile this driver as a module, choose M here: the module will - be called msi-wmi. - -config TOPSTAR_LAPTOP - tristate "Topstar Laptop Extras" - depends on ACPI - depends on INPUT - select INPUT_SPARSEKMAP - ---help--- - This driver adds support for hotkeys found on Topstar laptops. - - If you have a Topstar laptop, say Y or M here. - -config ACPI_TOSHIBA - tristate "Toshiba Laptop Extras" - depends on ACPI - depends on ACPI_WMI - select LEDS_CLASS - select NEW_LEDS - depends on BACKLIGHT_CLASS_DEVICE - depends on INPUT - depends on SERIO_I8042 || SERIO_I8042 = n - depends on ACPI_VIDEO || ACPI_VIDEO = n - depends on RFKILL || RFKILL = n - depends on IIO - select INPUT_POLLDEV - select INPUT_SPARSEKMAP - ---help--- - This driver adds support for access to certain system settings - on "legacy free" Toshiba laptops. These laptops can be recognized by - their lack of a BIOS setup menu and APM support. - - On these machines, all system configuration is handled through the - ACPI. This driver is required for access to controls not covered - by the general ACPI drivers, such as LCD brightness, video output, - etc. - - This driver differs from the non-ACPI Toshiba laptop driver (located - under "Processor type and features") in several aspects. - Configuration is accessed by reading and writing text files in the - /proc tree instead of by program interface to /dev. Furthermore, no - power management functions are exposed, as those are handled by the - general ACPI drivers. - - More information about this driver is available at - . - - If you have a legacy free Toshiba laptop (such as the Libretto L1 - series), say Y. - -config TOSHIBA_BT_RFKILL - tristate "Toshiba Bluetooth RFKill switch support" - depends on ACPI - depends on RFKILL || RFKILL = n - ---help--- - This driver adds support for Bluetooth events for the RFKill - switch on modern Toshiba laptops with full ACPI support and - an RFKill switch. - - This driver handles RFKill events for the TOS6205 Bluetooth, - and re-enables it when the switch is set back to the 'on' - position. - - If you have a modern Toshiba laptop with a Bluetooth and an - RFKill switch (such as the Portege R500), say Y. - -config TOSHIBA_HAPS - tristate "Toshiba HDD Active Protection Sensor" - depends on ACPI - ---help--- - This driver adds support for the built-in accelerometer - found on recent Toshiba laptops equipped with HID TOS620A - device. - - This driver receives ACPI notify events 0x80 when the sensor - detects a sudden move or a harsh vibration, as well as an - ACPI notify event 0x81 whenever the movement or vibration has - been stabilized. - - Also provides sysfs entries to get/set the desired protection - level and resetting the HDD protection interface. - - If you have a recent Toshiba laptop with a built-in accelerometer - device, say Y. - -config TOSHIBA_WMI - tristate "Toshiba WMI Hotkeys Driver (EXPERIMENTAL)" - default n - depends on ACPI_WMI - depends on INPUT - select INPUT_SPARSEKMAP - ---help--- - This driver adds hotkey monitoring support to some Toshiba models - that manage the hotkeys via WMI events. - - WARNING: This driver is incomplete as it lacks a proper keymap and the - *notify function only prints the ACPI event type value. Be warned that - you will need to provide some information if you have a Toshiba model - with WMI event hotkeys and want to help with the develpment of this - driver. - - If you have a WMI-based hotkeys Toshiba laptop, say Y or M here. - -config ACPI_CMPC - tristate "CMPC Laptop Extras" - depends on ACPI - depends on RFKILL || RFKILL=n - select INPUT - select BACKLIGHT_CLASS_DEVICE - default n - help - Support for Intel Classmate PC ACPI devices, including some - keys as input device, backlight device, tablet and accelerometer - devices. - -config INTEL_HID_EVENT - tristate "INTEL HID Event" - depends on ACPI - depends on INPUT - select INPUT_SPARSEKMAP - help - This driver provides support for the Intel HID Event hotkey interface. - Some laptops require this driver for hotkey support. - - To compile this driver as a module, choose M here: the module will - be called intel_hid. - -config INTEL_VBTN - tristate "INTEL VIRTUAL BUTTON" - depends on ACPI - depends on INPUT - select INPUT_SPARSEKMAP - help - This driver provides support for the Intel Virtual Button interface. - Some laptops require this driver for power button support. - - To compile this driver as a module, choose M here: the module will - be called intel_vbtn. - -config INTEL_SCU_IPC - bool "Intel SCU IPC Support" - depends on X86_INTEL_MID - default y - ---help--- - IPC is used to bridge the communications between kernel and SCU on - some embedded Intel x86 platforms. This is not needed for PC-type - machines. - -config INTEL_SCU_IPC_UTIL - tristate "Intel SCU IPC utility driver" - depends on INTEL_SCU_IPC - default y - ---help--- - The IPC Util driver provides an interface with the SCU enabling - low level access for debug work and updating the firmware. Say - N unless you will be doing this on an Intel MID platform. - -config GPIO_INTEL_PMIC - bool "Intel PMIC GPIO support" - depends on INTEL_SCU_IPC && GPIOLIB - ---help--- - Say Y here to support GPIO via the SCU IPC interface - on Intel MID platforms. - -config INTEL_MID_POWER_BUTTON - tristate "power button driver for Intel MID platforms" - depends on INTEL_SCU_IPC && INPUT - help - This driver handles the power button on the Intel MID platforms. - - If unsure, say N. - -config INTEL_MFLD_THERMAL - tristate "Thermal driver for Intel Medfield platform" - depends on MFD_INTEL_MSIC && THERMAL - help - Say Y here to enable thermal driver support for the Intel Medfield - platform. - -config INTEL_IPS - tristate "Intel Intelligent Power Sharing" - depends on ACPI - ---help--- - Intel Calpella platforms support dynamic power sharing between the - CPU and GPU, maximizing performance in a given TDP. This driver, - along with the CPU frequency and i915 drivers, provides that - functionality. If in doubt, say Y here; it will only load on - supported platforms. - -config INTEL_IMR - bool "Intel Isolated Memory Region support" - default n - depends on X86_INTEL_QUARK && IOSF_MBI - ---help--- - This option provides a means to manipulate Isolated Memory Regions. - IMRs are a set of registers that define read and write access masks - to prohibit certain system agents from accessing memory with 1 KiB - granularity. - - IMRs make it possible to control read/write access to an address - by hardware agents inside the SoC. Read and write masks can be - defined for: - - eSRAM flush - - Dirty CPU snoop (write only) - - RMU access - - PCI Virtual Channel 0/Virtual Channel 1 - - SMM mode - - Non SMM mode - - Quark contains a set of eight IMR registers and makes use of those - registers during its bootup process. - - If you are running on a Galileo/Quark say Y here. - -config INTEL_PMC_CORE - bool "Intel PMC Core driver" - depends on PCI - ---help--- - The Intel Platform Controller Hub for Intel Core SoCs provides access - to Power Management Controller registers via a PCI interface. This - driver can utilize debugging capabilities and supported features as - exposed by the Power Management Controller. - - Supported features: - - SLP_S0_RESIDENCY counter. - -config IBM_RTL - tristate "Device driver to enable PRTL support" - depends on PCI - ---help--- - Enable support for IBM Premium Real Time Mode (PRTM). - This module will allow you the enter and exit PRTM in the BIOS via - sysfs on platforms that support this feature. System in PRTM will - not receive CPU-generated SMIs for recoverable errors. Use of this - feature without proper support may void your hardware warranty. - - If the proper BIOS support is found the driver will load and create - /sys/devices/system/ibm_rtl/. The "state" variable will indicate - whether or not the BIOS is in PRTM. - state = 0 (BIOS SMIs on) - state = 1 (BIOS SMIs off) - -config XO1_RFKILL - tristate "OLPC XO-1 software RF kill switch" - depends on OLPC || COMPILE_TEST - depends on RFKILL - ---help--- - Support for enabling/disabling the WLAN interface on the OLPC XO-1 - laptop. - -config XO15_EBOOK - tristate "OLPC XO-1.5 ebook switch" - depends on OLPC || COMPILE_TEST - depends on ACPI && INPUT - ---help--- - Support for the ebook switch on the OLPC XO-1.5 laptop. - - This switch is triggered as the screen is rotated and folded down to - convert the device into ebook form. - -config SAMSUNG_LAPTOP - tristate "Samsung Laptop driver" - depends on RFKILL || RFKILL = n - depends on ACPI_VIDEO || ACPI_VIDEO = n - depends on BACKLIGHT_CLASS_DEVICE - select LEDS_CLASS - select NEW_LEDS - ---help--- - This module implements a driver for a wide range of different - Samsung laptops. It offers control over the different - function keys, wireless LED, LCD backlight level. - - It may also provide some sysfs files described in - - - To compile this driver as a module, choose M here: the module - will be called samsung-laptop. - -config MXM_WMI - tristate "WMI support for MXM Laptop Graphics" - depends on ACPI_WMI - ---help--- - MXM is a standard for laptop graphics cards, the WMI interface - is required for switchable nvidia graphics machines - -config INTEL_OAKTRAIL - tristate "Intel Oaktrail Platform Extras" - depends on ACPI - depends on ACPI_VIDEO || ACPI_VIDEO = n - depends on RFKILL && BACKLIGHT_CLASS_DEVICE && ACPI - ---help--- - Intel Oaktrail platform need this driver to provide interfaces to - enable/disable the Camera, WiFi, BT etc. devices. If in doubt, say Y - here; it will only load on supported platforms. - -config SAMSUNG_Q10 - tristate "Samsung Q10 Extras" - depends on ACPI - select BACKLIGHT_CLASS_DEVICE - ---help--- - This driver provides support for backlight control on Samsung Q10 - and related laptops, including Dell Latitude X200. - -config APPLE_GMUX - tristate "Apple Gmux Driver" - depends on ACPI - depends on PNP - depends on BACKLIGHT_CLASS_DEVICE - depends on BACKLIGHT_APPLE=n || BACKLIGHT_APPLE - depends on ACPI_VIDEO=n || ACPI_VIDEO - ---help--- - This driver provides support for the gmux device found on many - Apple laptops, which controls the display mux for the hybrid - graphics as well as the backlight. Currently only backlight - control is supported by the driver. - -config INTEL_RST - tristate "Intel Rapid Start Technology Driver" - depends on ACPI - ---help--- - This driver provides support for modifying paramaters on systems - equipped with Intel's Rapid Start Technology. When put in an ACPI - sleep state, these devices will wake after either a configured - timeout or when the system battery reaches a critical state, - automatically copying memory contents to disk. On resume, the - firmware will copy the memory contents back to RAM and resume the OS - as usual. - -config INTEL_SMARTCONNECT - tristate "Intel Smart Connect disabling driver" - depends on ACPI - ---help--- - Intel Smart Connect is a technology intended to permit devices to - update state by resuming for a short period of time at regular - intervals. If a user enables this functionality under Windows and - then reboots into Linux, the system may remain configured to resume - on suspend. In the absence of any userspace to support it, the system - will then remain awake until something triggers another suspend. - - This driver checks to determine whether the device has Intel Smart - Connect enabled, and if so disables it. - -config PVPANIC - tristate "pvpanic device support" - depends on ACPI - ---help--- - This driver provides support for the pvpanic device. pvpanic is - a paravirtualized device provided by QEMU; it lets a virtual machine - (guest) communicate panic events to the host. - -config INTEL_PMC_IPC - tristate "Intel PMC IPC Driver" - depends on ACPI - ---help--- - This driver provides support for PMC control on some Intel platforms. - The PMC is an ARC processor which defines IPC commands for communication - with other entities in the CPU. - -config SURFACE_PRO3_BUTTON - tristate "Power/home/volume buttons driver for Microsoft Surface Pro 3/4 tablet" - depends on ACPI && INPUT - ---help--- - This driver handles the power/home/volume buttons on the Microsoft Surface Pro 3/4 tablet. - -config INTEL_PUNIT_IPC - tristate "Intel P-Unit IPC Driver" - ---help--- - This driver provides support for Intel P-Unit Mailbox IPC mechanism, - which is used to bridge the communications between kernel and P-Unit. - -config INTEL_TELEMETRY - tristate "Intel SoC Telemetry Driver" - default n - depends on INTEL_PMC_IPC && INTEL_PUNIT_IPC && X86_64 - ---help--- - This driver provides interfaces to configure and use - telemetry for INTEL SoC from APL onwards. It is also - used to get various SoC events and parameters - directly via debugfs files. Various tools may use - this interface for SoC state monitoring. -endif # X86_PLATFORM_DEVICES diff --git a/src/linux/drivers/pnp/Kconfig b/src/linux/drivers/pnp/Kconfig deleted file mode 100644 index 2a37b3f..0000000 --- a/src/linux/drivers/pnp/Kconfig +++ /dev/null @@ -1,47 +0,0 @@ -# -# Plug and Play configuration -# - -menuconfig PNP - bool "Plug and Play support" - depends on HAS_IOMEM - depends on ISA || ACPI - ---help--- - Plug and Play (PnP) is a standard for peripherals which allows those - peripherals to be configured by software, e.g. assign IRQ's or other - parameters. No jumpers on the cards are needed, instead the values - are provided to the cards from the BIOS, from the operating system, - or using a user-space utility. - - Say Y here if you would like Linux to configure your Plug and Play - devices. You should then also say Y to all of the protocols below. - Alternatively, you can say N here and configure your PnP devices - using user space utilities such as the isapnptools package. - - If unsure, say Y. - -config PNP_DEBUG_MESSAGES - default y - bool "PNP debugging messages" - depends on PNP - help - Say Y here if you want the PNP layer to be able to produce debugging - messages if needed. The messages can be enabled at boot-time with - the pnp.debug kernel parameter. - - This option allows you to save a bit of space if you do not want - the messages to even be built into the kernel. - - If you have any doubts about this, say Y here. - -if PNP - -comment "Protocols" - -source "drivers/pnp/isapnp/Kconfig" - -source "drivers/pnp/pnpbios/Kconfig" - -source "drivers/pnp/pnpacpi/Kconfig" - -endif # PNP diff --git a/src/linux/drivers/pnp/isapnp/Kconfig b/src/linux/drivers/pnp/isapnp/Kconfig deleted file mode 100644 index f1ef366..0000000 --- a/src/linux/drivers/pnp/isapnp/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -# -# ISA Plug and Play configuration -# -config ISAPNP - bool "ISA Plug and Play support" - depends on ISA - help - Say Y here if you would like support for ISA Plug and Play devices. - Some information is in . - - If unsure, say Y. diff --git a/src/linux/drivers/pnp/pnpacpi/Kconfig b/src/linux/drivers/pnp/pnpacpi/Kconfig deleted file mode 100644 index b04767c..0000000 --- a/src/linux/drivers/pnp/pnpacpi/Kconfig +++ /dev/null @@ -1,6 +0,0 @@ -# -# Plug and Play ACPI configuration -# -config PNPACPI - bool - default (PNP && ACPI) diff --git a/src/linux/drivers/pnp/pnpbios/Kconfig b/src/linux/drivers/pnp/pnpbios/Kconfig deleted file mode 100644 index a786086..0000000 --- a/src/linux/drivers/pnp/pnpbios/Kconfig +++ /dev/null @@ -1,42 +0,0 @@ -# -# Plug and Play BIOS configuration -# -config PNPBIOS - bool "Plug and Play BIOS support" - depends on ISA && X86_32 - default n - ---help--- - Linux uses the PNPBIOS as defined in "Plug and Play BIOS - Specification Version 1.0A May 5, 1994" to autodetect built-in - mainboard resources (e.g. parallel port resources). - - Some features (e.g. event notification, docking station information, - ISAPNP services) are not currently implemented. - - If you would like the kernel to detect and allocate resources to - your mainboard devices (on some systems they are disabled by the - BIOS) say Y here. Also the PNPBIOS can help prevent resource - conflicts between mainboard devices and other bus devices. - - Note: ACPI is expected to supersede PNPBIOS some day, currently it - co-exists nicely. If you have a non-ISA system that supports ACPI, - you probably don't need PNPBIOS support. - -config PNPBIOS_PROC_FS - bool "Plug and Play BIOS /proc interface" - depends on PNPBIOS && PROC_FS - ---help--- - If you say Y here and to "/proc file system support", you will be - able to directly access the PNPBIOS. This includes resource - allocation, ESCD, and other PNPBIOS services. Using this - interface is potentially dangerous because the PNPBIOS driver will - not be notified of any resource changes made by writing directly. - Also some buggy systems will fault when accessing certain features - in the PNPBIOS /proc interface (e.g. "boot" configs). - - See the latest pcmcia-cs (stand-alone package) for a nice set of - PNPBIOS /proc interface tools (lspnp and setpnp). - - Unless you are debugging or have other specific reasons, it is - recommended that you say N here. - diff --git a/src/linux/drivers/power/Kconfig b/src/linux/drivers/power/Kconfig deleted file mode 100644 index 63454b5..0000000 --- a/src/linux/drivers/power/Kconfig +++ /dev/null @@ -1,3 +0,0 @@ -source "drivers/power/avs/Kconfig" -source "drivers/power/reset/Kconfig" -source "drivers/power/supply/Kconfig" diff --git a/src/linux/drivers/power/Makefile b/src/linux/drivers/power/Makefile deleted file mode 100644 index ff35c71..0000000 --- a/src/linux/drivers/power/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_POWER_AVS) += avs/ -obj-$(CONFIG_POWER_RESET) += reset/ -obj-$(CONFIG_POWER_SUPPLY) += supply/ diff --git a/src/linux/drivers/power/avs/Kconfig b/src/linux/drivers/power/avs/Kconfig deleted file mode 100644 index a67eeac..0000000 --- a/src/linux/drivers/power/avs/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -menuconfig POWER_AVS - bool "Adaptive Voltage Scaling class support" - help - AVS is a power management technique which finely controls the - operating voltage of a device in order to optimize (i.e. reduce) - its power consumption. - At a given operating point the voltage is adapted depending on - static factors (chip manufacturing process) and dynamic factors - (temperature depending performance). - AVS is also called SmartReflex on OMAP devices. - - Say Y here to enable Adaptive Voltage Scaling class support. - -config ROCKCHIP_IODOMAIN - tristate "Rockchip IO domain support" - depends on POWER_AVS && ARCH_ROCKCHIP && OF - help - Say y here to enable support io domains on Rockchip SoCs. It is - necessary for the io domain setting of the SoC to match the - voltage supplied by the regulators. diff --git a/src/linux/drivers/power/reset/Kconfig b/src/linux/drivers/power/reset/Kconfig deleted file mode 100644 index c74c3f6..0000000 --- a/src/linux/drivers/power/reset/Kconfig +++ /dev/null @@ -1,212 +0,0 @@ -menuconfig POWER_RESET - bool "Board level reset or power off" - help - Provides a number of drivers which either reset a complete board - or shut it down, by manipulating the main power supply on the board. - - Say Y here to enable board reset and power off - -if POWER_RESET - -config POWER_RESET_AS3722 - bool "ams AS3722 power-off driver" - depends on MFD_AS3722 - help - This driver supports turning off board via a ams AS3722 power-off. - -config POWER_RESET_AT91_POWEROFF - tristate "Atmel AT91 poweroff driver" - depends on ARCH_AT91 - default SOC_AT91SAM9 || SOC_SAMA5 - help - This driver supports poweroff for Atmel AT91SAM9 and SAMA5 - SoCs - -config POWER_RESET_AT91_RESET - tristate "Atmel AT91 reset driver" - depends on ARCH_AT91 - default SOC_AT91SAM9 || SOC_SAMA5 - help - This driver supports restart for Atmel AT91SAM9 and SAMA5 - SoCs - -config POWER_RESET_AT91_SAMA5D2_SHDWC - tristate "Atmel AT91 SAMA5D2-Compatible shutdown controller driver" - depends on ARCH_AT91 || COMPILE_TEST - default SOC_SAMA5 - help - This driver supports the alternate shutdown controller for some Atmel - SAMA5 SoCs. It is present for example on SAMA5D2 SoC. - -config POWER_RESET_AXXIA - bool "LSI Axxia reset driver" - depends on ARCH_AXXIA - help - This driver supports restart for Axxia SoC. - - Say Y if you have an Axxia family SoC. - -config POWER_RESET_BRCMKONA - bool "Broadcom Kona reset driver" - depends on ARM || COMPILE_TEST - default ARCH_BCM_MOBILE - help - This driver provides restart support for Broadcom Kona chips. - - Say Y here if you have a Broadcom Kona-based board and you wish - to have restart support. - -config POWER_RESET_BRCMSTB - bool "Broadcom STB reset driver" - depends on ARM || MIPS || COMPILE_TEST - depends on MFD_SYSCON - default ARCH_BRCMSTB - help - This driver provides restart support for Broadcom STB boards. - - Say Y here if you have a Broadcom STB board and you wish - to have restart support. - -config POWER_RESET_GPIO - bool "GPIO power-off driver" - depends on OF_GPIO - help - This driver supports turning off your board via a GPIO line. - If your board needs a GPIO high/low to power down, say Y and - create a binding in your devicetree. - -config POWER_RESET_GPIO_RESTART - bool "GPIO restart driver" - depends on OF_GPIO - help - This driver supports restarting your board via a GPIO line. - If your board needs a GPIO high/low to restart, say Y and - create a binding in your devicetree. - -config POWER_RESET_HISI - bool "Hisilicon power-off driver" - depends on ARCH_HISI - help - Reboot support for Hisilicon boards. - -config POWER_RESET_IMX - bool "IMX6 power-off driver" - depends on POWER_RESET && SOC_IMX6 - help - This driver support power off external PMIC by PMIC_ON_REQ on i.mx6 - boards.If you want to use other pin to control external power,please - say N here or disable in dts to make sure pm_power_off never be - overwrote wrongly by this driver. - -config POWER_RESET_MSM - bool "Qualcomm MSM power-off driver" - depends on ARCH_QCOM - help - Power off and restart support for Qualcomm boards. - -config POWER_RESET_LTC2952 - bool "LTC2952 PowerPath power-off driver" - depends on OF_GPIO - help - This driver supports an external powerdown trigger and board power - down via the LTC2952. Bindings are made in the device tree. - -config POWER_RESET_QNAP - bool "QNAP power-off driver" - depends on OF_GPIO && PLAT_ORION - help - This driver supports turning off QNAP NAS devices by sending - commands to the microcontroller which controls the main power. - - Say Y if you have a QNAP NAS. - -config POWER_RESET_RESTART - bool "Restart power-off driver" - help - Some boards don't actually have the ability to power off. - Instead they restart, and u-boot holds the SoC until the - user presses a key. u-boot then boots into Linux. - -config POWER_RESET_ST - bool "ST restart driver" - depends on ARCH_STI - help - Reset support for STMicroelectronics boards. - -config POWER_RESET_VERSATILE - bool "ARM Versatile family reboot driver" - depends on ARM - depends on MFD_SYSCON - depends on OF - help - Power off and restart support for ARM Versatile family of - reference boards. - -config POWER_RESET_VEXPRESS - bool "ARM Versatile Express power-off and reset driver" - depends on ARM || ARM64 - depends on VEXPRESS_CONFIG - help - Power off and reset support for the ARM Ltd. Versatile - Express boards. - -config POWER_RESET_XGENE - bool "APM SoC X-Gene reset driver" - depends on ARM64 - help - Reboot support for the APM SoC X-Gene Eval boards. - -config POWER_RESET_KEYSTONE - bool "Keystone reset driver" - depends on ARCH_KEYSTONE || COMPILE_TEST - depends on HAS_IOMEM - select MFD_SYSCON - help - Reboot support for the KEYSTONE SoCs. - -config POWER_RESET_SYSCON - bool "Generic SYSCON regmap reset driver" - depends on OF - depends on HAS_IOMEM - select MFD_SYSCON - help - Reboot support for generic SYSCON mapped register reset. - -config POWER_RESET_SYSCON_POWEROFF - bool "Generic SYSCON regmap poweroff driver" - depends on OF - depends on HAS_IOMEM - select MFD_SYSCON - help - Poweroff support for generic SYSCON mapped register poweroff. - -config POWER_RESET_RMOBILE - tristate "Renesas R-Mobile reset driver" - depends on ARCH_RMOBILE || COMPILE_TEST - depends on HAS_IOMEM - help - Reboot support for Renesas R-Mobile and SH-Mobile SoCs. - -config POWER_RESET_ZX - tristate "ZTE SoCs reset driver" - depends on ARCH_ZX || COMPILE_TEST - depends on HAS_IOMEM - help - Reboot support for ZTE SoCs. - -config REBOOT_MODE - tristate - -config SYSCON_REBOOT_MODE - tristate "Generic SYSCON regmap reboot mode driver" - depends on OF - depends on MFD_SYSCON - select REBOOT_MODE - help - Say y here will enable reboot mode driver. This will - get reboot mode arguments and store it in SYSCON mapped - register, then the bootloader can read it to take different - action according to the mode. - -endif - diff --git a/src/linux/drivers/power/supply/Kconfig b/src/linux/drivers/power/supply/Kconfig deleted file mode 100644 index 76806a0..0000000 --- a/src/linux/drivers/power/supply/Kconfig +++ /dev/null @@ -1,514 +0,0 @@ -menuconfig POWER_SUPPLY - bool "Power supply class support" - help - Say Y here to enable power supply class support. This allows - power supply (batteries, AC, USB) monitoring by userspace - via sysfs and uevent (if available) and/or APM kernel interface - (if selected below). - -if POWER_SUPPLY - -config POWER_SUPPLY_DEBUG - bool "Power supply debug" - help - Say Y here to enable debugging messages for power supply class - and drivers. - -config PDA_POWER - tristate "Generic PDA/phone power driver" - depends on !S390 - help - Say Y here to enable generic power driver for PDAs and phones with - one or two external power supplies (AC/USB) connected to main and - backup batteries, and optional builtin charger. - -config APM_POWER - tristate "APM emulation for class batteries" - depends on APM_EMULATION - help - Say Y here to enable support APM status emulation using - battery class devices. - -config GENERIC_ADC_BATTERY - tristate "Generic battery support using IIO" - depends on IIO - help - Say Y here to enable support for the generic battery driver - which uses IIO framework to read adc. - -config MAX8925_POWER - tristate "MAX8925 battery charger support" - depends on MFD_MAX8925 - help - Say Y here to enable support for the battery charger in the Maxim - MAX8925 PMIC. - -config WM831X_BACKUP - tristate "WM831X backup battery charger support" - depends on MFD_WM831X - help - Say Y here to enable support for the backup battery charger - in the Wolfson Microelectronics WM831x PMICs. - -config WM831X_POWER - tristate "WM831X PMU support" - depends on MFD_WM831X - help - Say Y here to enable support for the power management unit - provided by Wolfson Microelectronics WM831x PMICs. - -config WM8350_POWER - tristate "WM8350 PMU support" - depends on MFD_WM8350 - help - Say Y here to enable support for the power management unit - provided by the Wolfson Microelectronics WM8350 PMIC. - -config TEST_POWER - tristate "Test power driver" - help - This driver is used for testing. It's safe to say M here. - -config BATTERY_88PM860X - tristate "Marvell 88PM860x battery driver" - depends on MFD_88PM860X - help - Say Y here to enable battery monitor for Marvell 88PM860x chip. - -config BATTERY_ACT8945A - tristate "Active-semi ACT8945A charger driver" - depends on MFD_ACT8945A || COMPILE_TEST - help - Say Y here to enable support for power supply provided by - Active-semi ActivePath ACT8945A charger. - -config BATTERY_DS2760 - tristate "DS2760 battery driver (HP iPAQ & others)" - depends on W1 && W1_SLAVE_DS2760 - help - Say Y here to enable support for batteries with ds2760 chip. - -config BATTERY_DS2780 - tristate "DS2780 battery driver" - depends on HAS_IOMEM - select W1 - select W1_SLAVE_DS2780 - help - Say Y here to enable support for batteries with ds2780 chip. - -config BATTERY_DS2781 - tristate "DS2781 battery driver" - depends on HAS_IOMEM - select W1 - select W1_SLAVE_DS2781 - help - If you enable this you will have the DS2781 battery driver support. - - The battery monitor chip is used in many batteries/devices - as the one who is responsible for charging/discharging/monitoring - Li+ batteries. - - If you are unsure, say N. - -config BATTERY_DS2782 - tristate "DS2782/DS2786 standalone gas-gauge" - depends on I2C - help - Say Y here to enable support for the DS2782/DS2786 standalone battery - gas-gauge. - -config BATTERY_PMU - tristate "Apple PMU battery" - depends on PPC32 && ADB_PMU - help - Say Y here to expose battery information on Apple machines - through the generic battery class. - -config BATTERY_OLPC - tristate "One Laptop Per Child battery" - depends on X86_32 && OLPC - help - Say Y to enable support for the battery on the OLPC laptop. - -config BATTERY_TOSA - tristate "Sharp SL-6000 (tosa) battery" - depends on MACH_TOSA && MFD_TC6393XB && TOUCHSCREEN_WM97XX - help - Say Y to enable support for the battery on the Sharp Zaurus - SL-6000 (tosa) models. - -config BATTERY_COLLIE - tristate "Sharp SL-5500 (collie) battery" - depends on SA1100_COLLIE && MCP_UCB1200 - help - Say Y to enable support for the battery on the Sharp Zaurus - SL-5500 (collie) models. - -config BATTERY_IPAQ_MICRO - tristate "iPAQ Atmel Micro ASIC battery driver" - depends on MFD_IPAQ_MICRO - help - Choose this option if you want to monitor battery status on - Compaq/HP iPAQ h3100 and h3600. - -config BATTERY_WM97XX - bool "WM97xx generic battery driver" - depends on TOUCHSCREEN_WM97XX=y - help - Say Y to enable support for battery measured by WM97xx aux port. - -config BATTERY_SBS - tristate "SBS Compliant gas gauge" - depends on I2C - help - Say Y to include support for SBS battery driver for SBS-compliant - gas gauges. - -config BATTERY_BQ27XXX - tristate "BQ27xxx battery driver" - help - Say Y here to enable support for batteries with BQ27xxx chips. - -config BATTERY_BQ27XXX_I2C - tristate "BQ27xxx I2C support" - depends on BATTERY_BQ27XXX - depends on I2C - default y - help - Say Y here to enable support for batteries with BQ27xxx chips - connected over an I2C bus. - -config BATTERY_DA9030 - tristate "DA9030 battery driver" - depends on PMIC_DA903X - help - Say Y here to enable support for batteries charger integrated into - DA9030 PMIC. - -config BATTERY_DA9052 - tristate "Dialog DA9052 Battery" - depends on PMIC_DA9052 - help - Say Y here to enable support for batteries charger integrated into - DA9052 PMIC. - -config CHARGER_DA9150 - tristate "Dialog Semiconductor DA9150 Charger support" - depends on MFD_DA9150 - depends on DA9150_GPADC - depends on IIO - help - Say Y here to enable support for charger unit of the DA9150 - Integrated Charger & Fuel-Gauge IC. - - This driver can also be built as a module. If so, the module will be - called da9150-charger. - -config BATTERY_DA9150 - tristate "Dialog Semiconductor DA9150 Fuel Gauge support" - depends on MFD_DA9150 - help - Say Y here to enable support for the Fuel-Gauge unit of the DA9150 - Integrated Charger & Fuel-Gauge IC - - This driver can also be built as a module. If so, the module will be - called da9150-fg. - -config AXP288_CHARGER - tristate "X-Powers AXP288 Charger" - depends on MFD_AXP20X && EXTCON_AXP288 - help - Say yes here to have support X-Power AXP288 power management IC (PMIC) - integrated charger. - -config AXP288_FUEL_GAUGE - tristate "X-Powers AXP288 Fuel Gauge" - depends on MFD_AXP20X && IIO - help - Say yes here to have support for X-Power power management IC (PMIC) - Fuel Gauge. The device provides battery statistics and status - monitoring as well as alerts for battery over/under voltage and - over/under temperature. - -config BATTERY_MAX17040 - tristate "Maxim MAX17040 Fuel Gauge" - depends on I2C - help - MAX17040 is fuel-gauge systems for lithium-ion (Li+) batteries - in handheld and portable equipment. The MAX17040 is configured - to operate with a single lithium cell - -config BATTERY_MAX17042 - tristate "Maxim MAX17042/17047/17050/8997/8966 Fuel Gauge" - depends on I2C - select REGMAP_I2C - help - MAX17042 is fuel-gauge systems for lithium-ion (Li+) batteries - in handheld and portable equipment. The MAX17042 is configured - to operate with a single lithium cell. MAX8997 and MAX8966 are - multi-function devices that include fuel gauages that are compatible - with MAX17042. This driver also supports max17047/50 chips which are - improved version of max17042. - -config BATTERY_Z2 - tristate "Z2 battery driver" - depends on I2C && MACH_ZIPIT2 - help - Say Y to include support for the battery on the Zipit Z2. - -config BATTERY_S3C_ADC - tristate "Battery driver for Samsung ADC based monitoring" - depends on S3C_ADC - help - Say Y here to enable support for iPAQ h1930/h1940/rx1950 battery - -config BATTERY_TWL4030_MADC - tristate "TWL4030 MADC battery driver" - depends on TWL4030_MADC - help - Say Y here to enable this dumb driver for batteries managed - through the TWL4030 MADC. - -config CHARGER_88PM860X - tristate "Marvell 88PM860x Charger driver" - depends on MFD_88PM860X && BATTERY_88PM860X - help - Say Y here to enable charger for Marvell 88PM860x chip. - -config CHARGER_PCF50633 - tristate "NXP PCF50633 MBC" - depends on MFD_PCF50633 - help - Say Y to include support for NXP PCF50633 Main Battery Charger. - -config BATTERY_JZ4740 - tristate "Ingenic JZ4740 battery" - depends on MACH_JZ4740 - depends on MFD_JZ4740_ADC - help - Say Y to enable support for the battery on Ingenic JZ4740 based - boards. - - This driver can be build as a module. If so, the module will be - called jz4740-battery. - -config BATTERY_INTEL_MID - tristate "Battery driver for Intel MID platforms" - depends on INTEL_SCU_IPC && SPI - help - Say Y here to enable the battery driver on Intel MID - platforms. - -config BATTERY_RX51 - tristate "Nokia RX-51 (N900) battery driver" - depends on TWL4030_MADC - help - Say Y here to enable support for battery information on Nokia - RX-51, also known as N900 tablet. - -config CHARGER_ISP1704 - tristate "ISP1704 USB Charger Detection" - depends on USB_PHY - depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' - help - Say Y to enable support for USB Charger Detection with - ISP1707/ISP1704 USB transceivers. - -config CHARGER_MAX8903 - tristate "MAX8903 Battery DC-DC Charger for USB and Adapter Power" - help - Say Y to enable support for the MAX8903 DC-DC charger and sysfs. - The driver supports controlling charger-enable and current-limit - pins based on the status of charger connections with interrupt - handlers. - -config CHARGER_TWL4030 - tristate "OMAP TWL4030 BCI charger driver" - depends on IIO && TWL4030_CORE - help - Say Y here to enable support for TWL4030 Battery Charge Interface. - -config CHARGER_LP8727 - tristate "TI/National Semiconductor LP8727 charger driver" - depends on I2C - help - Say Y here to enable support for LP8727 Charger Driver. - -config CHARGER_LP8788 - tristate "TI LP8788 charger driver" - depends on MFD_LP8788 - depends on LP8788_ADC - depends on IIO - help - Say Y to enable support for the LP8788 linear charger. - -config CHARGER_GPIO - tristate "GPIO charger" - depends on GPIOLIB || COMPILE_TEST - help - Say Y to include support for chargers which report their online status - through a GPIO pin. - - This driver can be build as a module. If so, the module will be - called gpio-charger. - -config CHARGER_MANAGER - bool "Battery charger manager for multiple chargers" - depends on REGULATOR - select EXTCON - help - Say Y to enable charger-manager support, which allows multiple - chargers attached to a battery and multiple batteries attached to a - system. The charger-manager also can monitor charging status in - runtime and in suspend-to-RAM by waking up the system periodically - with help of suspend_again support. - -config CHARGER_MAX14577 - tristate "Maxim MAX14577/77836 battery charger driver" - depends on MFD_MAX14577 - help - Say Y to enable support for the battery charger control sysfs and - platform data of MAX14577/77836 MUICs. - -config CHARGER_MAX77693 - tristate "Maxim MAX77693 battery charger driver" - depends on MFD_MAX77693 - help - Say Y to enable support for the Maxim MAX77693 battery charger. - -config CHARGER_MAX8997 - tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver" - depends on MFD_MAX8997 && REGULATOR_MAX8997 - help - Say Y to enable support for the battery charger control sysfs and - platform data of MAX8997/LP3974 PMICs. - -config CHARGER_MAX8998 - tristate "Maxim MAX8998/LP3974 PMIC battery charger driver" - depends on MFD_MAX8998 && REGULATOR_MAX8998 - help - Say Y to enable support for the battery charger control sysfs and - platform data of MAX8998/LP3974 PMICs. - -config CHARGER_QCOM_SMBB - tristate "Qualcomm Switch-Mode Battery Charger and Boost" - depends on MFD_SPMI_PMIC || COMPILE_TEST - depends on OF - depends on EXTCON - help - Say Y to include support for the Switch-Mode Battery Charger and - Boost (SMBB) hardware found in Qualcomm PM8941 PMICs. The charger - is an integrated, single-cell lithium-ion battery charger. DT - configuration is required for loading, see the devicetree - documentation for more detail. The base name for this driver is - 'pm8941_charger'. - -config CHARGER_BQ2415X - tristate "TI BQ2415x battery charger driver" - depends on I2C - help - Say Y to enable support for the TI BQ2415x battery charger - PMICs. - - You'll need this driver to charge batteries on e.g. Nokia - RX-51/N900. - -config CHARGER_BQ24190 - tristate "TI BQ24190 battery charger driver" - depends on I2C - depends on GPIOLIB || COMPILE_TEST - help - Say Y to enable support for the TI BQ24190 battery charger. - -config CHARGER_BQ24257 - tristate "TI BQ24250/24251/24257 battery charger driver" - depends on I2C - depends on GPIOLIB || COMPILE_TEST - depends on REGMAP_I2C - help - Say Y to enable support for the TI BQ24250, BQ24251, and BQ24257 battery - chargers. - -config CHARGER_BQ24735 - tristate "TI BQ24735 battery charger support" - depends on I2C - depends on GPIOLIB || COMPILE_TEST - help - Say Y to enable support for the TI BQ24735 battery charger. - -config CHARGER_BQ25890 - tristate "TI BQ25890 battery charger driver" - depends on I2C - depends on GPIOLIB || COMPILE_TEST - select REGMAP_I2C - help - Say Y to enable support for the TI BQ25890 battery charger. - -config CHARGER_SMB347 - tristate "Summit Microelectronics SMB347 Battery Charger" - depends on I2C - select REGMAP_I2C - help - Say Y to include support for Summit Microelectronics SMB347 - Battery Charger. - -config CHARGER_TPS65090 - tristate "TPS65090 battery charger driver" - depends on MFD_TPS65090 - help - Say Y here to enable support for battery charging with TPS65090 - PMIC chips. - -config CHARGER_TPS65217 - tristate "TPS65217 battery charger driver" - depends on MFD_TPS65217 - help - Say Y here to enable support for battery charging with TPS65217 - PMIC chips. - -config BATTERY_GAUGE_LTC2941 - tristate "LTC2941/LTC2943 Battery Gauge Driver" - depends on I2C - help - Say Y here to include support for LTC2941 and LTC2943 Battery - Gauge IC. The driver reports the charge count continuously, and - measures the voltage and temperature every 10 seconds. - -config AB8500_BM - bool "AB8500 Battery Management Driver" - depends on AB8500_CORE && AB8500_GPADC - help - Say Y to include support for AB8500 battery management. - -config BATTERY_GOLDFISH - tristate "Goldfish battery driver" - depends on GOLDFISH || COMPILE_TEST - depends on HAS_IOMEM - help - Say Y to enable support for the battery and AC power in the - Goldfish emulator. - -config BATTERY_RT5033 - tristate "RT5033 fuel gauge support" - depends on MFD_RT5033 - help - This adds support for battery fuel gauge in Richtek RT5033 PMIC. - The fuelgauge calculates and determines the battery state of charge - according to battery open circuit voltage. - -config CHARGER_RT9455 - tristate "Richtek RT9455 battery charger driver" - depends on I2C - depends on GPIOLIB || COMPILE_TEST - select REGMAP_I2C - help - Say Y to enable support for Richtek RT9455 battery charger. - -config AXP20X_POWER - tristate "AXP20x power supply driver" - depends on MFD_AXP20X - help - This driver provides support for the power supply features of - AXP20x PMIC. - -endif # POWER_SUPPLY diff --git a/src/linux/drivers/powercap/Kconfig b/src/linux/drivers/powercap/Kconfig deleted file mode 100644 index 85727ef..0000000 --- a/src/linux/drivers/powercap/Kconfig +++ /dev/null @@ -1,32 +0,0 @@ -# -# Generic power capping sysfs interface configuration -# - -menuconfig POWERCAP - bool "Generic powercap sysfs driver" - help - The power capping sysfs interface allows kernel subsystems to expose power - capping settings to user space in a consistent way. Usually, it consists - of multiple control types that determine which settings may be exposed and - power zones representing parts of the system that can be subject to power - capping. - - If you want this code to be compiled in, say Y here. - -if POWERCAP -# Client driver configurations go here. -config INTEL_RAPL - tristate "Intel RAPL Support" - depends on X86 && IOSF_MBI - default n - ---help--- - This enables support for the Intel Running Average Power Limit (RAPL) - technology which allows power limits to be enforced and monitored on - modern Intel processors (Sandy Bridge and later). - - In RAPL, the platform level settings are divided into domains for - fine grained control. These domains include processor package, DRAM - controller, CPU core (Power Plance 0), graphics uncore (Power Plane - 1), etc. - -endif diff --git a/src/linux/drivers/pps/Kconfig b/src/linux/drivers/pps/Kconfig deleted file mode 100644 index 564a51a..0000000 --- a/src/linux/drivers/pps/Kconfig +++ /dev/null @@ -1,47 +0,0 @@ -# -# PPS support configuration -# - -menu "PPS support" - -config PPS - tristate "PPS support" - ---help--- - PPS (Pulse Per Second) is a special pulse provided by some GPS - antennae. Userland can use it to get a high-precision time - reference. - - Some antennae's PPS signals are connected with the CD (Carrier - Detect) pin of the serial line they use to communicate with the - host. In this case use the SERIAL_LINE client support. - - Some antennae's PPS signals are connected with some special host - inputs so you have to enable the corresponding client support. - - To compile this driver as a module, choose M here: the module - will be called pps_core.ko. -if PPS - -config PPS_DEBUG - bool "PPS debugging messages" - help - Say Y here if you want the PPS support to produce a bunch of debug - messages to the system log. Select this if you are having a - problem with PPS support and want to see more of what is going on. - -config NTP_PPS - bool "PPS kernel consumer support" - depends on !NO_HZ_COMMON - help - This option adds support for direct in-kernel time - synchronization using an external PPS signal. - - It doesn't work on tickless systems at the moment. - -endif - -source drivers/pps/clients/Kconfig - -source drivers/pps/generators/Kconfig - -endmenu diff --git a/src/linux/drivers/pps/clients/Kconfig b/src/linux/drivers/pps/clients/Kconfig deleted file mode 100644 index 0c9f280..0000000 --- a/src/linux/drivers/pps/clients/Kconfig +++ /dev/null @@ -1,41 +0,0 @@ -# -# PPS clients configuration -# - -if PPS - -comment "PPS clients support" - -config PPS_CLIENT_KTIMER - tristate "Kernel timer client (Testing client, use for debug)" - help - If you say yes here you get support for a PPS debugging client - which uses a kernel timer to generate the PPS signal. - - This driver can also be built as a module. If so, the module - will be called pps-ktimer. - -config PPS_CLIENT_LDISC - tristate "PPS line discipline" - depends on PPS && TTY - help - If you say yes here you get support for a PPS source connected - with the CD (Carrier Detect) pin of your serial port. - -config PPS_CLIENT_PARPORT - tristate "Parallel port PPS client" - depends on PPS && PARPORT - help - If you say yes here you get support for a PPS source connected - with the interrupt pin of your parallel port. - -config PPS_CLIENT_GPIO - tristate "PPS client using GPIO" - depends on PPS - help - If you say yes here you get support for a PPS source using - GPIO. To be useful you must also register a platform device - specifying the GPIO pin and other options, usually in your board - setup. - -endif diff --git a/src/linux/drivers/pps/generators/Kconfig b/src/linux/drivers/pps/generators/Kconfig deleted file mode 100644 index e4c4f3d..0000000 --- a/src/linux/drivers/pps/generators/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# -# PPS generators configuration -# - -comment "PPS generators support" - -config PPS_GENERATOR_PARPORT - tristate "Parallel port PPS signal generator" - depends on PARPORT && BROKEN - help - If you say yes here you get support for a PPS signal generator which - utilizes STROBE pin of a parallel port to send PPS signals. It uses - parport abstraction layer and hrtimers to precisely control the signal. diff --git a/src/linux/drivers/ptp/Kconfig b/src/linux/drivers/ptp/Kconfig deleted file mode 100644 index ee3de34..0000000 --- a/src/linux/drivers/ptp/Kconfig +++ /dev/null @@ -1,93 +0,0 @@ -# -# PTP clock support configuration -# - -menu "PTP clock support" - -config PTP_1588_CLOCK - tristate "PTP clock support" - depends on NET - select PPS - select NET_PTP_CLASSIFY - help - The IEEE 1588 standard defines a method to precisely - synchronize distributed clocks over Ethernet networks. The - standard defines a Precision Time Protocol (PTP), which can - be used to achieve synchronization within a few dozen - microseconds. In addition, with the help of special hardware - time stamping units, it can be possible to achieve - synchronization to within a few hundred nanoseconds. - - This driver adds support for PTP clocks as character - devices. If you want to use a PTP clock, then you should - also enable at least one clock driver as well. - - To compile this driver as a module, choose M here: the module - will be called ptp. - -config PTP_1588_CLOCK_GIANFAR - tristate "Freescale eTSEC as PTP clock" - depends on GIANFAR - select PTP_1588_CLOCK - default y - help - This driver adds support for using the eTSEC as a PTP - clock. This clock is only useful if your PTP programs are - getting hardware time stamps on the PTP Ethernet packets - using the SO_TIMESTAMPING API. - - To compile this driver as a module, choose M here: the module - will be called gianfar_ptp. - -config PTP_1588_CLOCK_IXP46X - tristate "Intel IXP46x as PTP clock" - depends on IXP4XX_ETH - select PTP_1588_CLOCK - default y - help - This driver adds support for using the IXP46X as a PTP - clock. This clock is only useful if your PTP programs are - getting hardware time stamps on the PTP Ethernet packets - using the SO_TIMESTAMPING API. - - To compile this driver as a module, choose M here: the module - will be called ptp_ixp46x. - -comment "Enable PHYLIB and NETWORK_PHY_TIMESTAMPING to see the additional clocks." - depends on PHYLIB=n || NETWORK_PHY_TIMESTAMPING=n - -config DP83640_PHY - tristate "Driver for the National Semiconductor DP83640 PHYTER" - depends on NETWORK_PHY_TIMESTAMPING - depends on PHYLIB - select PTP_1588_CLOCK - ---help--- - Supports the DP83640 PHYTER with IEEE 1588 features. - - This driver adds support for using the DP83640 as a PTP - clock. This clock is only useful if your PTP programs are - getting hardware time stamps on the PTP Ethernet packets - using the SO_TIMESTAMPING API. - - In order for this to work, your MAC driver must also - implement the skb_tx_timestamp() function. - -config PTP_1588_CLOCK_PCH - tristate "Intel PCH EG20T as PTP clock" - depends on X86_32 || COMPILE_TEST - depends on HAS_IOMEM && NET - select PTP_1588_CLOCK - help - This driver adds support for using the PCH EG20T as a PTP - clock. The hardware supports time stamping of PTP packets - when using the end-to-end delay (E2E) mechansim. The peer - delay mechansim (P2P) is not supported. - - This clock is only useful if your PTP programs are getting - hardware time stamps on the PTP Ethernet packets using the - SO_TIMESTAMPING API. - - To compile this driver as a module, choose M here: the module - will be called ptp_pch. - -endmenu diff --git a/src/linux/drivers/pwm/Kconfig b/src/linux/drivers/pwm/Kconfig deleted file mode 100644 index bf01288..0000000 --- a/src/linux/drivers/pwm/Kconfig +++ /dev/null @@ -1,474 +0,0 @@ -menuconfig PWM - bool "Pulse-Width Modulation (PWM) Support" - help - Generic Pulse-Width Modulation (PWM) support. - - In Pulse-Width Modulation, a variation of the width of pulses - in a rectangular pulse signal is used as a means to alter the - average power of the signal. Applications include efficient - power delivery and voltage regulation. In computer systems, - PWMs are commonly used to control fans or the brightness of - display backlights. - - This framework provides a generic interface to PWM devices - within the Linux kernel. On the driver side it provides an API - to register and unregister a PWM chip, an abstraction of a PWM - controller, that supports one or more PWM devices. Client - drivers can request PWM devices and use the generic framework - to configure as well as enable and disable them. - - This generic framework replaces the legacy PWM framework which - allows only a single driver implementing the required API. Not - all legacy implementations have been ported to the framework - yet. The framework provides an API that is backward compatible - with the legacy framework so that existing client drivers - continue to work as expected. - - If unsure, say no. - -if PWM - -config PWM_SYSFS - bool - default y if SYSFS - -config PWM_AB8500 - tristate "AB8500 PWM support" - depends on AB8500_CORE && ARCH_U8500 - help - Generic PWM framework driver for Analog Baseband AB8500. - - To compile this driver as a module, choose M here: the module - will be called pwm-ab8500. - -config PWM_ATMEL - tristate "Atmel PWM support" - depends on ARCH_AT91 || AVR32 - help - Generic PWM framework driver for Atmel SoC. - - To compile this driver as a module, choose M here: the module - will be called pwm-atmel. - -config PWM_ATMEL_HLCDC_PWM - tristate "Atmel HLCDC PWM support" - depends on MFD_ATMEL_HLCDC - depends on HAVE_CLK - help - Generic PWM framework driver for the PWM output of the HLCDC - (Atmel High-end LCD Controller). This PWM output is mainly used - to control the LCD backlight. - - To compile this driver as a module, choose M here: the module - will be called pwm-atmel-hlcdc. - -config PWM_ATMEL_TCB - tristate "Atmel TC Block PWM support" - depends on ATMEL_TCLIB && OF - help - Generic PWM framework driver for Atmel Timer Counter Block. - - A Timer Counter Block provides 6 PWM devices grouped by 2. - Devices in a given group must have the same period. - - To compile this driver as a module, choose M here: the module - will be called pwm-atmel-tcb. - -config PWM_BCM_IPROC - tristate "iProc PWM support" - depends on ARCH_BCM_IPROC - help - Generic PWM framework driver for Broadcom iProc PWM block. This - block is used in Broadcom iProc SoC's. - - To compile this driver as a module, choose M here: the module - will be called pwm-bcm-iproc. - -config PWM_BCM_KONA - tristate "Kona PWM support" - depends on ARCH_BCM_MOBILE - help - Generic PWM framework driver for Broadcom Kona PWM block. - - To compile this driver as a module, choose M here: the module - will be called pwm-bcm-kona. - -config PWM_BCM2835 - tristate "BCM2835 PWM support" - depends on ARCH_BCM2835 - help - PWM framework driver for BCM2835 controller (Raspberry Pi) - - To compile this driver as a module, choose M here: the module - will be called pwm-bcm2835. - -config PWM_BERLIN - tristate "Marvell Berlin PWM support" - depends on ARCH_BERLIN - help - PWM framework driver for Marvell Berlin SoCs. - - To compile this driver as a module, choose M here: the module - will be called pwm-berlin. - -config PWM_BFIN - tristate "Blackfin PWM support" - depends on BFIN_GPTIMERS - help - Generic PWM framework driver for Blackfin. - - To compile this driver as a module, choose M here: the module - will be called pwm-bfin. - -config PWM_BRCMSTB - tristate "Broadcom STB PWM support" - depends on ARCH_BRCMSTB || BMIPS_GENERIC - help - Generic PWM framework driver for the Broadcom Set-top-Box - SoCs (BCM7xxx). - - To compile this driver as a module, choose M Here: the module - will be called pwm-brcmstb.c. - -config PWM_CLPS711X - tristate "CLPS711X PWM support" - depends on ARCH_CLPS711X || COMPILE_TEST - depends on HAS_IOMEM - help - Generic PWM framework driver for Cirrus Logic CLPS711X. - - To compile this driver as a module, choose M here: the module - will be called pwm-clps711x. - -config PWM_CRC - bool "Intel Crystalcove (CRC) PWM support" - depends on X86 && INTEL_SOC_PMIC - help - Generic PWM framework driver for Crystalcove (CRC) PMIC based PWM - control. - -config PWM_CROS_EC - tristate "ChromeOS EC PWM driver" - depends on MFD_CROS_EC - help - PWM driver for exposing a PWM attached to the ChromeOS Embedded - Controller. - -config PWM_EP93XX - tristate "Cirrus Logic EP93xx PWM support" - depends on ARCH_EP93XX - help - Generic PWM framework driver for Cirrus Logic EP93xx. - - To compile this driver as a module, choose M here: the module - will be called pwm-ep93xx. - -config PWM_FSL_FTM - tristate "Freescale FlexTimer Module (FTM) PWM support" - depends on HAS_IOMEM - depends on OF - select REGMAP_MMIO - help - Generic FTM PWM framework driver for Freescale VF610 and - Layerscape LS-1 SoCs. - - To compile this driver as a module, choose M here: the module - will be called pwm-fsl-ftm. - -config PWM_IMG - tristate "Imagination Technologies PWM driver" - depends on HAS_IOMEM - depends on MFD_SYSCON - depends on COMMON_CLK - depends on MIPS || COMPILE_TEST - help - Generic PWM framework driver for Imagination Technologies - PWM block which supports 4 channels. - - To compile this driver as a module, choose M here: the module - will be called pwm-img - -config PWM_IMX - tristate "i.MX PWM support" - depends on ARCH_MXC - help - Generic PWM framework driver for i.MX. - - To compile this driver as a module, choose M here: the module - will be called pwm-imx. - -config PWM_JZ4740 - tristate "Ingenic JZ4740 PWM support" - depends on MACH_JZ4740 - help - Generic PWM framework driver for Ingenic JZ4740 based - machines. - - To compile this driver as a module, choose M here: the module - will be called pwm-jz4740. - -config PWM_LP3943 - tristate "TI/National Semiconductor LP3943 PWM support" - depends on MFD_LP3943 - help - Generic PWM framework driver for LP3943 which supports two PWM - channels. - - To compile this driver as a module, choose M here: the module - will be called pwm-lp3943. - -config PWM_LPC18XX_SCT - tristate "LPC18xx/43xx PWM/SCT support" - depends on ARCH_LPC18XX - help - Generic PWM framework driver for NXP LPC18xx PWM/SCT which - supports 16 channels. - A maximum of 15 channels can be requested simultaneously and - must have the same period. - - To compile this driver as a module, choose M here: the module - will be called pwm-lpc18xx-sct. - -config PWM_LPC32XX - tristate "LPC32XX PWM support" - depends on ARCH_LPC32XX - help - Generic PWM framework driver for LPC32XX. The LPC32XX SOC has two - PWM controllers. - - To compile this driver as a module, choose M here: the module - will be called pwm-lpc32xx. - -config PWM_LPSS - tristate - -config PWM_LPSS_PCI - tristate "Intel LPSS PWM PCI driver" - depends on X86 && PCI - select PWM_LPSS - help - The PCI driver for Intel Low Power Subsystem PWM controller. - - To compile this driver as a module, choose M here: the module - will be called pwm-lpss-pci. - -config PWM_LPSS_PLATFORM - tristate "Intel LPSS PWM platform driver" - depends on X86 && ACPI - select PWM_LPSS - help - The platform driver for Intel Low Power Subsystem PWM controller. - - To compile this driver as a module, choose M here: the module - will be called pwm-lpss-platform. - -config PWM_MESON - tristate "Amlogic Meson PWM driver" - depends on ARCH_MESON - help - The platform driver for Amlogic Meson PWM controller. - - To compile this driver as a module, choose M here: the module - will be called pwm-meson. - -config PWM_MTK_DISP - tristate "MediaTek display PWM driver" - depends on ARCH_MEDIATEK || COMPILE_TEST - depends on HAS_IOMEM - help - Generic PWM framework driver for MediaTek disp-pwm device. - The PWM is used to control the backlight brightness for display. - - To compile this driver as a module, choose M here: the module - will be called pwm-mtk-disp. - -config PWM_MXS - tristate "Freescale MXS PWM support" - depends on ARCH_MXS && OF - select STMP_DEVICE - help - Generic PWM framework driver for Freescale MXS. - - To compile this driver as a module, choose M here: the module - will be called pwm-mxs. - -config PWM_OMAP_DMTIMER - tristate "OMAP Dual-Mode Timer PWM support" - depends on OF && ARCH_OMAP && OMAP_DM_TIMER - help - Generic PWM framework driver for OMAP Dual-Mode Timer PWM output - - To compile this driver as a module, choose M here: the module - will be called pwm-omap-dmtimer - -config PWM_PCA9685 - tristate "NXP PCA9685 PWM driver" - depends on I2C - select REGMAP_I2C - help - Generic PWM framework driver for NXP PCA9685 LED controller. - - To compile this driver as a module, choose M here: the module - will be called pwm-pca9685. - -config PWM_PUV3 - tristate "PKUnity NetBook-0916 PWM support" - depends on ARCH_PUV3 - help - Generic PWM framework driver for PKUnity NetBook-0916. - - To compile this driver as a module, choose M here: the module - will be called pwm-puv3. - -config PWM_PXA - tristate "PXA PWM support" - depends on ARCH_PXA - help - Generic PWM framework driver for PXA. - - To compile this driver as a module, choose M here: the module - will be called pwm-pxa. - -config PWM_RCAR - tristate "Renesas R-Car PWM support" - depends on ARCH_RENESAS || COMPILE_TEST - depends on HAS_IOMEM - help - This driver exposes the PWM Timer controller found in Renesas - R-Car chips through the PWM API. - - To compile this driver as a module, choose M here: the module - will be called pwm-rcar. - -config PWM_RENESAS_TPU - tristate "Renesas TPU PWM support" - depends on ARCH_RENESAS || COMPILE_TEST - depends on HAS_IOMEM - help - This driver exposes the Timer Pulse Unit (TPU) PWM controller found - in Renesas chips through the PWM API. - - To compile this driver as a module, choose M here: the module - will be called pwm-renesas-tpu. - -config PWM_ROCKCHIP - tristate "Rockchip PWM support" - depends on ARCH_ROCKCHIP - help - Generic PWM framework driver for the PWM controller found on - Rockchip SoCs. - -config PWM_SAMSUNG - tristate "Samsung PWM support" - depends on PLAT_SAMSUNG || ARCH_EXYNOS - help - Generic PWM framework driver for Samsung. - - To compile this driver as a module, choose M here: the module - will be called pwm-samsung. - -config PWM_SPEAR - tristate "STMicroelectronics SPEAr PWM support" - depends on PLAT_SPEAR - depends on OF - help - Generic PWM framework driver for the PWM controller on ST - SPEAr SoCs. - - To compile this driver as a module, choose M here: the module - will be called pwm-spear. - -config PWM_STI - tristate "STiH4xx PWM support" - depends on ARCH_STI - depends on OF - help - Generic PWM framework driver for STiH4xx SoCs. - - To compile this driver as a module, choose M here: the module - will be called pwm-sti. - -config PWM_STMPE - bool "STMPE expander PWM export" - depends on MFD_STMPE - help - This enables support for the PWMs found in the STMPE I/O - expanders. - -config PWM_SUN4I - tristate "Allwinner PWM support" - depends on ARCH_SUNXI || COMPILE_TEST - depends on HAS_IOMEM && COMMON_CLK - help - Generic PWM framework driver for Allwinner SoCs. - - To compile this driver as a module, choose M here: the module - will be called pwm-sun4i. - -config PWM_TEGRA - tristate "NVIDIA Tegra PWM support" - depends on ARCH_TEGRA - help - Generic PWM framework driver for the PWFM controller found on NVIDIA - Tegra SoCs. - - To compile this driver as a module, choose M here: the module - will be called pwm-tegra. - -config PWM_TIECAP - tristate "ECAP PWM support" - depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX - help - PWM driver support for the ECAP APWM controller found on AM33XX - TI SOC - - To compile this driver as a module, choose M here: the module - will be called pwm-tiecap. - -config PWM_TIEHRPWM - tristate "EHRPWM PWM support" - depends on ARCH_OMAP2PLUS || ARCH_DAVINCI_DA8XX - help - PWM driver support for the EHRPWM controller found on AM33XX - TI SOC - - To compile this driver as a module, choose M here: the module - will be called pwm-tiehrpwm. - -config PWM_TIPWMSS - bool - default y if (ARCH_OMAP2PLUS) && (PWM_TIECAP || PWM_TIEHRPWM) - help - PWM Subsystem driver support for AM33xx SOC. - - PWM submodules require PWM config space access from submodule - drivers and require common parent driver support. - -config PWM_TWL - tristate "TWL4030/6030 PWM support" - depends on TWL4030_CORE - help - Generic PWM framework driver for TWL4030/6030. - - To compile this driver as a module, choose M here: the module - will be called pwm-twl. - -config PWM_TWL_LED - tristate "TWL4030/6030 PWM support for LED drivers" - depends on TWL4030_CORE - help - Generic PWM framework driver for TWL4030/6030 LED terminals. - - To compile this driver as a module, choose M here: the module - will be called pwm-twl-led. - -config PWM_VT8500 - tristate "vt8500 PWM support" - depends on ARCH_VT8500 - help - Generic PWM framework driver for vt8500. - - To compile this driver as a module, choose M here: the module - will be called pwm-vt8500. - -endif diff --git a/src/linux/drivers/pwm/Makefile b/src/linux/drivers/pwm/Makefile deleted file mode 100644 index 1194c54..0000000 --- a/src/linux/drivers/pwm/Makefile +++ /dev/null @@ -1,48 +0,0 @@ -obj-$(CONFIG_PWM) += core.o -obj-$(CONFIG_PWM_SYSFS) += sysfs.o -obj-$(CONFIG_PWM_AB8500) += pwm-ab8500.o -obj-$(CONFIG_PWM_ATMEL) += pwm-atmel.o -obj-$(CONFIG_PWM_ATMEL_HLCDC_PWM) += pwm-atmel-hlcdc.o -obj-$(CONFIG_PWM_ATMEL_TCB) += pwm-atmel-tcb.o -obj-$(CONFIG_PWM_BCM_IPROC) += pwm-bcm-iproc.o -obj-$(CONFIG_PWM_BCM_KONA) += pwm-bcm-kona.o -obj-$(CONFIG_PWM_BCM2835) += pwm-bcm2835.o -obj-$(CONFIG_PWM_BERLIN) += pwm-berlin.o -obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o -obj-$(CONFIG_PWM_BRCMSTB) += pwm-brcmstb.o -obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o -obj-$(CONFIG_PWM_CRC) += pwm-crc.o -obj-$(CONFIG_PWM_CROS_EC) += pwm-cros-ec.o -obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o -obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o -obj-$(CONFIG_PWM_IMG) += pwm-img.o -obj-$(CONFIG_PWM_IMX) += pwm-imx.o -obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o -obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o -obj-$(CONFIG_PWM_LPC18XX_SCT) += pwm-lpc18xx-sct.o -obj-$(CONFIG_PWM_LPC32XX) += pwm-lpc32xx.o -obj-$(CONFIG_PWM_LPSS) += pwm-lpss.o -obj-$(CONFIG_PWM_LPSS_PCI) += pwm-lpss-pci.o -obj-$(CONFIG_PWM_LPSS_PLATFORM) += pwm-lpss-platform.o -obj-$(CONFIG_PWM_MESON) += pwm-meson.o -obj-$(CONFIG_PWM_MTK_DISP) += pwm-mtk-disp.o -obj-$(CONFIG_PWM_MXS) += pwm-mxs.o -obj-$(CONFIG_PWM_OMAP_DMTIMER) += pwm-omap-dmtimer.o -obj-$(CONFIG_PWM_PCA9685) += pwm-pca9685.o -obj-$(CONFIG_PWM_PUV3) += pwm-puv3.o -obj-$(CONFIG_PWM_PXA) += pwm-pxa.o -obj-$(CONFIG_PWM_RCAR) += pwm-rcar.o -obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o -obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o -obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o -obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o -obj-$(CONFIG_PWM_STI) += pwm-sti.o -obj-$(CONFIG_PWM_STMPE) += pwm-stmpe.o -obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o -obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o -obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o -obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o -obj-$(CONFIG_PWM_TIPWMSS) += pwm-tipwmss.o -obj-$(CONFIG_PWM_TWL) += pwm-twl.o -obj-$(CONFIG_PWM_TWL_LED) += pwm-twl-led.o -obj-$(CONFIG_PWM_VT8500) += pwm-vt8500.o diff --git a/src/linux/drivers/ras/Kconfig b/src/linux/drivers/ras/Kconfig deleted file mode 100644 index 4c3c67d..0000000 --- a/src/linux/drivers/ras/Kconfig +++ /dev/null @@ -1,35 +0,0 @@ -menuconfig RAS - bool "Reliability, Availability and Serviceability (RAS) features" - help - Reliability, availability and serviceability (RAS) is a computer - hardware engineering term. Computers designed with higher levels - of RAS have a multitude of features that protect data integrity - and help them stay available for long periods of time without - failure. - - Reliability can be defined as the probability that the system will - produce correct outputs up to some given time. Reliability is - enhanced by features that help to avoid, detect and repair hardware - faults. - - Availability is the probability a system is operational at a given - time, i.e. the amount of time a device is actually operating as the - percentage of total time it should be operating. - - Serviceability or maintainability is the simplicity and speed with - which a system can be repaired or maintained; if the time to repair - a failed system increases, then availability will decrease. - - Note that Reliability and Availability are distinct concepts: - Reliability is a measure of the ability of a system to function - correctly, including avoiding data corruption, whereas Availability - measures how often it is available for use, even though it may not - be functioning correctly. For example, a server may run forever and - so have ideal availability, but may be unreliable, with frequent - data corruption. - -if RAS - -source arch/x86/ras/Kconfig - -endif diff --git a/src/linux/drivers/regulator/Kconfig b/src/linux/drivers/regulator/Kconfig deleted file mode 100644 index 936f7cc..0000000 --- a/src/linux/drivers/regulator/Kconfig +++ /dev/null @@ -1,882 +0,0 @@ -menuconfig REGULATOR - bool "Voltage and Current Regulator Support" - help - Generic Voltage and Current Regulator support. - - This framework is designed to provide a generic interface to voltage - and current regulators within the Linux kernel. It's intended to - provide voltage and current control to client or consumer drivers and - also provide status information to user space applications through a - sysfs interface. - - The intention is to allow systems to dynamically control regulator - output in order to save power and prolong battery life. This applies - to both voltage regulators (where voltage output is controllable) and - current sinks (where current output is controllable). - - This framework safely compiles out if not selected so that client - drivers can still be used in systems with no software controllable - regulators. - - If unsure, say no. - - -if REGULATOR - -config REGULATOR_DEBUG - bool "Regulator debug support" - help - Say yes here to enable debugging support. - -config REGULATOR_FIXED_VOLTAGE - tristate "Fixed voltage regulator support" - help - This driver provides support for fixed voltage regulators, - useful for systems which use a combination of software - managed regulators and simple non-configurable regulators. - -config REGULATOR_VIRTUAL_CONSUMER - tristate "Virtual regulator consumer support" - help - This driver provides a virtual consumer for the voltage and - current regulator API which provides sysfs controls for - configuring the supplies requested. This is mainly useful - for test purposes. - - If unsure, say no. - -config REGULATOR_USERSPACE_CONSUMER - tristate "Userspace regulator consumer support" - help - There are some classes of devices that are controlled entirely - from user space. Userspace consumer driver provides ability to - control power supplies for such devices. - - If unsure, say no. - -config REGULATOR_88PM800 - tristate "Marvell 88PM800 Power regulators" - depends on MFD_88PM800 - help - This driver supports Marvell 88PM800 voltage regulator chips. - It delivers digitally programmable output, - the voltage is programmed via I2C interface. - It's suitable to support PXA988 chips to control VCC_MAIN and - various voltages. - -config REGULATOR_88PM8607 - tristate "Marvell 88PM8607 Power regulators" - depends on MFD_88PM860X=y - help - This driver supports 88PM8607 voltage regulator chips. - -config REGULATOR_ACT8865 - tristate "Active-semi act8865 voltage regulator" - depends on I2C - select REGMAP_I2C - help - This driver controls a active-semi act8865 voltage output - regulator via I2C bus. - -config REGULATOR_ACT8945A - tristate "Active-semi ACT8945A voltage regulator" - depends on MFD_ACT8945A - help - This driver controls a active-semi ACT8945A voltage regulator - via I2C bus. The ACT8945A features three step-down DC/DC converters - and four low-dropout linear regulators, along with a ActivePath - battery charger. - -config REGULATOR_AD5398 - tristate "Analog Devices AD5398/AD5821 regulators" - depends on I2C - help - This driver supports AD5398 and AD5821 current regulator chips. - If building into module, its name is ad5398.ko. - -config REGULATOR_ANATOP - tristate "Freescale i.MX on-chip ANATOP LDO regulators" - depends on MFD_SYSCON - help - Say y here to support Freescale i.MX on-chip ANATOP LDOs - regulators. It is recommended that this option be - enabled on i.MX6 platform. - -config REGULATOR_AAT2870 - tristate "AnalogicTech AAT2870 Regulators" - depends on MFD_AAT2870_CORE - help - If you have a AnalogicTech AAT2870 say Y to enable the - regulator driver. - -config REGULATOR_AB3100 - tristate "ST-Ericsson AB3100 Regulator functions" - depends on AB3100_CORE - default y if AB3100_CORE - help - These regulators correspond to functionality in the - AB3100 analog baseband dealing with power regulators - for the system. - -config REGULATOR_AB8500 - bool "ST-Ericsson AB8500 Power Regulators" - depends on AB8500_CORE - help - This driver supports the regulators found on the ST-Ericsson mixed - signal AB8500 PMIC - -config REGULATOR_ARIZONA - tristate "Wolfson Arizona class devices" - depends on MFD_ARIZONA - depends on SND_SOC - help - Support for the regulators found on Wolfson Arizona class - devices. - -config REGULATOR_AS3711 - tristate "AS3711 PMIC" - depends on MFD_AS3711 - help - This driver provides support for the voltage regulators on the - AS3711 PMIC - -config REGULATOR_AS3722 - tristate "AMS AS3722 PMIC Regulators" - depends on MFD_AS3722 - help - This driver provides support for the voltage regulators on the - AS3722 PMIC. This will enable support for all the software - controllable DCDC/LDO regulators. - -config REGULATOR_AXP20X - tristate "X-POWERS AXP20X PMIC Regulators" - depends on MFD_AXP20X - help - This driver provides support for the voltage regulators on the - AXP20X PMIC. - -config REGULATOR_BCM590XX - tristate "Broadcom BCM590xx PMU Regulators" - depends on MFD_BCM590XX - help - This driver provides support for the voltage regulators on the - BCM590xx PMUs. This will enable support for the software - controllable LDO/Switching regulators. - -config REGULATOR_DA903X - tristate "Dialog Semiconductor DA9030/DA9034 regulators" - depends on PMIC_DA903X - help - Say y here to support the BUCKs and LDOs regulators found on - Dialog Semiconductor DA9030/DA9034 PMIC. - -config REGULATOR_DA9052 - tristate "Dialog Semiconductor DA9052/DA9053 regulators" - depends on PMIC_DA9052 - help - This driver supports the voltage regulators of DA9052-BC and - DA9053-AA/Bx PMIC. - -config REGULATOR_DA9055 - tristate "Dialog Semiconductor DA9055 regulators" - depends on MFD_DA9055 - help - Say y here to support the BUCKs and LDOs regulators found on - Dialog Semiconductor DA9055 PMIC. - - This driver can also be built as a module. If so, the module - will be called da9055-regulator. - -config REGULATOR_DA9062 - tristate "Dialog Semiconductor DA9062 regulators" - depends on MFD_DA9062 - help - Say y here to support the BUCKs and LDOs regulators found on - DA9062 PMICs. - - This driver can also be built as a module. If so, the module - will be called da9062-regulator. - -config REGULATOR_DA9063 - tristate "Dialog Semiconductor DA9063 regulators" - depends on MFD_DA9063 - help - Say y here to support the BUCKs and LDOs regulators found on - DA9063 PMICs. - - This driver can also be built as a module. If so, the module - will be called da9063-regulator. - -config REGULATOR_DA9210 - tristate "Dialog Semiconductor DA9210 regulator" - depends on I2C - select REGMAP_I2C - help - Say y here to support for the Dialog Semiconductor DA9210. - The DA9210 is a multi-phase synchronous step down - converter 12A DC-DC Buck controlled through an I2C - interface. - -config REGULATOR_DA9211 - tristate "Dialog Semiconductor DA9211/DA9212/DA9213/DA9214/DA9215 regulator" - depends on I2C - select REGMAP_I2C - help - Say y here to support for the Dialog Semiconductor DA9211/DA9212 - /DA9213/DA9214/DA9215. - The DA9211/DA9212/DA9213/DA9214/DA9215 is a multi-phase synchronous - step down converter 12A or 16A DC-DC Buck controlled through an I2C - interface. - -config REGULATOR_DBX500_PRCMU - bool - -config REGULATOR_DB8500_PRCMU - bool "ST-Ericsson DB8500 Voltage Domain Regulators" - depends on MFD_DB8500_PRCMU - select REGULATOR_DBX500_PRCMU - help - This driver supports the voltage domain regulators controlled by the - DB8500 PRCMU - -config REGULATOR_FAN53555 - tristate "Fairchild FAN53555 Regulator" - depends on I2C - select REGMAP_I2C - help - This driver supports Fairchild FAN53555 Digitally Programmable - TinyBuck Regulator. The FAN53555 is a step-down switching voltage - regulator that delivers a digitally programmable output from an - input voltage supply of 2.5V to 5.5V. The output voltage is - programmed through an I2C interface. - -config REGULATOR_GPIO - tristate "GPIO regulator support" - depends on GPIOLIB || COMPILE_TEST - help - This driver provides support for regulators that can be - controlled via gpios. - It is capable of supporting current and voltage regulators - and the platform has to provide a mapping of GPIO-states - to target volts/amps. - -config REGULATOR_HI6421 - tristate "HiSilicon Hi6421 PMIC voltage regulator support" - depends on MFD_HI6421_PMIC && OF - help - This driver provides support for the voltage regulators on the - HiSilicon Hi6421 PMU / Codec IC. - Hi6421 is a multi-function device which, on regulator part, provides - 21 general purpose LDOs, 3 dedicated LDOs, and 5 BUCKs. All - of them come with support to either ECO (idle) or sleep mode. - -config REGULATOR_HI655X - tristate "Hisilicon HI655X PMIC regulators support" - depends on ARCH_HISI || COMPILE_TEST - depends on MFD_HI655X_PMIC && OF - help - This driver provides support for the voltage regulators of the - Hisilicon Hi655x PMIC device. - -config REGULATOR_ISL9305 - tristate "Intersil ISL9305 regulator" - depends on I2C - select REGMAP_I2C - help - This driver supports ISL9305 voltage regulator chip. - -config REGULATOR_ISL6271A - tristate "Intersil ISL6271A Power regulator" - depends on I2C - help - This driver supports ISL6271A voltage regulator chip. - -config REGULATOR_LM363X - tristate "TI LM363X voltage regulators" - depends on MFD_TI_LMU - help - This driver supports LM3631 and LM3632 voltage regulators for - the LCD bias. - One boost output voltage is configurable and always on. - Other LDOs are used for the display module. - -config REGULATOR_LP3971 - tristate "National Semiconductors LP3971 PMIC regulator driver" - depends on I2C - help - Say Y here to support the voltage regulators and convertors - on National Semiconductors LP3971 PMIC - -config REGULATOR_LP3972 - tristate "National Semiconductors LP3972 PMIC regulator driver" - depends on I2C - help - Say Y here to support the voltage regulators and convertors - on National Semiconductors LP3972 PMIC - -config REGULATOR_LP872X - tristate "TI/National Semiconductor LP8720/LP8725 voltage regulators" - depends on I2C - select REGMAP_I2C - help - This driver supports LP8720/LP8725 PMIC - -config REGULATOR_LP873X - tristate "TI LP873X Power regulators" - depends on MFD_TI_LP873X && OF - help - This driver supports LP873X voltage regulator chips. LP873X - provides two step-down converters and two general-purpose LDO - voltage regulators. It supports software based voltage control - for different voltage domains - -config REGULATOR_LP8755 - tristate "TI LP8755 High Performance PMU driver" - depends on I2C - select REGMAP_I2C - help - This driver supports LP8755 High Performance PMU driver. This - chip contains six step-down DC/DC converters which can support - 9 mode multiphase configuration. - -config REGULATOR_LP8788 - tristate "TI LP8788 Power Regulators" - depends on MFD_LP8788 - help - This driver supports LP8788 voltage regulator chip. - -config REGULATOR_LTC3589 - tristate "LTC3589 8-output voltage regulator" - depends on I2C - select REGMAP_I2C - help - This enables support for the LTC3589, LTC3589-1, and LTC3589-2 - 8-output regulators controlled via I2C. - -config REGULATOR_LTC3676 - tristate "LTC3676 8-output voltage regulator" - depends on I2C - select REGMAP_I2C - help - This enables support for the LTC3676 - 8-output regulators controlled via I2C. - -config REGULATOR_MAX14577 - tristate "Maxim 14577/77836 regulator" - depends on MFD_MAX14577 - help - This driver controls a Maxim MAX14577/77836 regulator via I2C bus. - The MAX14577 regulators include safeout LDO and charger current - regulator. The MAX77836 has two additional LDOs. - -config REGULATOR_MAX1586 - tristate "Maxim 1586/1587 voltage regulator" - depends on I2C - help - This driver controls a Maxim 1586 or 1587 voltage output - regulator via I2C bus. The provided regulator is suitable - for PXA27x chips to control VCC_CORE and VCC_USIM voltages. - -config REGULATOR_MAX77620 - tristate "Maxim 77620/MAX20024 voltage regulator" - depends on MFD_MAX77620 - help - This driver controls Maxim MAX77620 voltage output regulator - via I2C bus. The provided regulator is suitable for Tegra - chip to control Step-Down DC-DC and LDOs. Say Y here to - enable the regulator driver. - -config REGULATOR_MAX8649 - tristate "Maxim 8649 voltage regulator" - depends on I2C - select REGMAP_I2C - help - This driver controls a Maxim 8649 voltage output regulator via - I2C bus. - -config REGULATOR_MAX8660 - tristate "Maxim 8660/8661 voltage regulator" - depends on I2C - help - This driver controls a Maxim 8660/8661 voltage output - regulator via I2C bus. - -config REGULATOR_MAX8907 - tristate "Maxim 8907 voltage regulator" - depends on MFD_MAX8907 - help - This driver controls a Maxim 8907 voltage output regulator - via I2C bus. The provided regulator is suitable for Tegra - chip to control Step-Down DC-DC and LDOs. - -config REGULATOR_MAX8925 - tristate "Maxim MAX8925 Power Management IC" - depends on MFD_MAX8925 - help - Say y here to support the voltage regulaltor of Maxim MAX8925 PMIC. - -config REGULATOR_MAX8952 - tristate "Maxim MAX8952 Power Management IC" - depends on I2C - help - This driver controls a Maxim 8952 voltage output regulator - via I2C bus. Maxim 8952 has one voltage output and supports 4 DVS - modes ranging from 0.77V to 1.40V by 0.01V steps. - -config REGULATOR_MAX8973 - tristate "Maxim MAX8973 voltage regulator " - depends on I2C - depends on THERMAL && THERMAL_OF - select REGMAP_I2C - help - The MAXIM MAX8973 high-efficiency. three phase, DC-DC step-down - switching regulator delievers up to 9A of output current. Each - phase operates at a 2MHz fixed frequency with a 120 deg shift - from the adjacent phase, allowing the use of small magnetic component. - -config REGULATOR_MAX8997 - tristate "Maxim 8997/8966 regulator" - depends on MFD_MAX8997 - help - This driver controls a Maxim 8997/8966 regulator - via I2C bus. The provided regulator is suitable for S5PC110, - S5PV210, and Exynos-4 chips to control VCC_CORE and - VCC_USIM voltages. - -config REGULATOR_MAX8998 - tristate "Maxim 8998 voltage regulator" - depends on MFD_MAX8998 - help - This driver controls a Maxim 8998 voltage output regulator - via I2C bus. The provided regulator is suitable for S3C6410 - and S5PC1XX chips to control VCC_CORE and VCC_USIM voltages. - -config REGULATOR_MAX77686 - tristate "Maxim 77686 regulator" - depends on MFD_MAX77686 - help - This driver controls a Maxim 77686 regulator - via I2C bus. The provided regulator is suitable for - Exynos-4 chips to control VARM and VINT voltages. - -config REGULATOR_MAX77693 - tristate "Maxim 77693/77843 regulator" - depends on (MFD_MAX77693 || MFD_MAX77843) - help - This driver controls a Maxim 77693/77843 regulators via I2C bus. - The regulators include two LDOs, 'SAFEOUT1', 'SAFEOUT2' - and one current regulator 'CHARGER'. This is suitable for - Exynos-4x12 (MAX77693) or Exynos5433 (MAX77843) SoC chips. - -config REGULATOR_MAX77802 - tristate "Maxim 77802 regulator" - depends on MFD_MAX77686 - help - This driver controls a Maxim 77802 regulator - via I2C bus. The provided regulator is suitable for - Exynos5420/Exynos5800 SoCs to control various voltages. - It includes support for control of voltage and ramp speed. - -config REGULATOR_MC13XXX_CORE - tristate - -config REGULATOR_MC13783 - tristate "Freescale MC13783 regulator driver" - depends on MFD_MC13XXX - select REGULATOR_MC13XXX_CORE - help - Say y here to support the regulators found on the Freescale MC13783 - PMIC. - -config REGULATOR_MC13892 - tristate "Freescale MC13892 regulator driver" - depends on MFD_MC13XXX - select REGULATOR_MC13XXX_CORE - help - Say y here to support the regulators found on the Freescale MC13892 - PMIC. - -config REGULATOR_MT6311 - tristate "MediaTek MT6311 PMIC" - depends on I2C - select REGMAP_I2C - help - Say y here to select this option to enable the power regulator of - MediaTek MT6311 PMIC. - This driver supports the control of different power rails of device - through regulator interface. - -config REGULATOR_MT6323 - tristate "MediaTek MT6323 PMIC" - depends on MFD_MT6397 - help - Say y here to select this option to enable the power regulator of - MediaTek MT6323 PMIC. - This driver supports the control of different power rails of device - through regulator interface. - -config REGULATOR_MT6397 - tristate "MediaTek MT6397 PMIC" - depends on MFD_MT6397 - help - Say y here to select this option to enable the power regulator of - MediaTek MT6397 PMIC. - This driver supports the control of different power rails of device - through regulator interface. - -config REGULATOR_PALMAS - tristate "TI Palmas PMIC Regulators" - depends on MFD_PALMAS - help - If you wish to control the regulators on the Palmas series of - chips say Y here. This will enable support for all the software - controllable SMPS/LDO regulators. - - The regulators available on Palmas series chips vary depending - on the muxing. This is handled automatically in the driver by - reading the mux info from OTP. - -config REGULATOR_PBIAS - tristate "PBIAS OMAP regulator driver" - depends on (ARCH_OMAP || COMPILE_TEST) && MFD_SYSCON - help - Say y here to support pbias regulator for mmc1:SD card i/o - on OMAP SoCs. - This driver provides support for OMAP pbias modelled - regulators. - -config REGULATOR_PCAP - tristate "Motorola PCAP2 regulator driver" - depends on EZX_PCAP - help - This driver provides support for the voltage regulators of the - PCAP2 PMIC. - -config REGULATOR_PCF50633 - tristate "NXP PCF50633 regulator driver" - depends on MFD_PCF50633 - help - Say Y here to support the voltage regulators and convertors - on PCF50633 - -config REGULATOR_PFUZE100 - tristate "Freescale PFUZE100/200/3000 regulator driver" - depends on I2C - select REGMAP_I2C - help - Say y here to support the regulators found on the Freescale - PFUZE100/200/3000 PMIC. - -config REGULATOR_PV88060 - tristate "Powerventure Semiconductor PV88060 regulator" - depends on I2C - select REGMAP_I2C - help - Say y here to support the voltage regulators and convertors - PV88060 - -config REGULATOR_PV88080 - tristate "Powerventure Semiconductor PV88080 regulator" - depends on I2C - select REGMAP_I2C - help - Say y here to support the buck convertors on PV88080 - -config REGULATOR_PV88090 - tristate "Powerventure Semiconductor PV88090 regulator" - depends on I2C - select REGMAP_I2C - help - Say y here to support the voltage regulators and convertors - on PV88090 - -config REGULATOR_PWM - tristate "PWM voltage regulator" - depends on PWM - help - This driver supports PWM controlled voltage regulators. PWM - duty cycle can increase or decrease the voltage. - -config REGULATOR_QCOM_RPM - tristate "Qualcomm RPM regulator driver" - depends on MFD_QCOM_RPM - help - If you say yes to this option, support will be included for the - regulators exposed by the Resource Power Manager found in Qualcomm - 8660, 8960 and 8064 based devices. - - Say M here if you want to include support for the regulators on the - Qualcomm RPM as a module. The module will be named - "qcom_rpm-regulator". - -config REGULATOR_QCOM_SMD_RPM - tristate "Qualcomm SMD based RPM regulator driver" - depends on QCOM_SMD_RPM - help - If you say yes to this option, support will be included for the - regulators exposed by the Resource Power Manager found in Qualcomm - 8974 based devices. - - Say M here if you want to include support for the regulators on the - Qualcomm RPM as a module. The module will be named - "qcom_smd-regulator". - -config REGULATOR_QCOM_SPMI - tristate "Qualcomm SPMI regulator driver" - depends on SPMI || COMPILE_TEST - help - If you say yes to this option, support will be included for the - regulators found in Qualcomm SPMI PMICs. - - Say M here if you want to include support for the regulators on the - Qualcomm SPMI PMICs as a module. The module will be named - "qcom_spmi-regulator". - -config REGULATOR_RC5T583 - tristate "RICOH RC5T583 Power regulators" - depends on MFD_RC5T583 - help - Select this option to enable the power regulator of RICOH - PMIC RC5T583. - This driver supports the control of different power rails of device - through regulator interface. The device supports multiple DCDC/LDO - outputs which can be controlled by i2c communication. - -config REGULATOR_RK808 - tristate "Rockchip RK808/RK818 Power regulators" - depends on MFD_RK808 - help - Select this option to enable the power regulator of ROCKCHIP - PMIC RK808 and RK818. - This driver supports the control of different power rails of device - through regulator interface. The device supports multiple DCDC/LDO - outputs which can be controlled by i2c communication. - -config REGULATOR_RN5T618 - tristate "Ricoh RN5T567/618 voltage regulators" - depends on MFD_RN5T618 - help - Say y here to support the regulators found on Ricoh RN5T567 or - RN5T618 PMIC. - -config REGULATOR_RT5033 - tristate "Richtek RT5033 Regulators" - depends on MFD_RT5033 - help - This adds support for voltage and current regulators in Richtek - RT5033 PMIC. The device supports multiple regulators like - current source, LDO and Buck. - -config REGULATOR_S2MPA01 - tristate "Samsung S2MPA01 voltage regulator" - depends on MFD_SEC_CORE - help - This driver controls Samsung S2MPA01 voltage output regulator - via I2C bus. S2MPA01 has 10 Bucks and 26 LDO outputs. - -config REGULATOR_S2MPS11 - tristate "Samsung S2MPS11/13/14/15/S2MPU02 voltage regulator" - depends on MFD_SEC_CORE - help - This driver supports a Samsung S2MPS11/13/14/15/S2MPU02 voltage - output regulator via I2C bus. The chip is comprised of high efficient - Buck converters including Dual-Phase Buck converter, Buck-Boost - converter, various LDOs. - -config REGULATOR_S5M8767 - tristate "Samsung S5M8767A voltage regulator" - depends on MFD_SEC_CORE - help - This driver supports a Samsung S5M8767A voltage output regulator - via I2C bus. S5M8767A have 9 Bucks and 28 LDOs output and - supports DVS mode with 8bits of output voltage control. - -config REGULATOR_SKY81452 - tristate "Skyworks Solutions SKY81452 voltage regulator" - depends on MFD_SKY81452 - help - This driver supports Skyworks SKY81452 voltage output regulator - via I2C bus. SKY81452 has one voltage linear regulator can be - programmed from 4.5V to 20V. - - This driver can also be built as a module. If so, the module - will be called sky81452-regulator. - -config REGULATOR_TI_ABB - tristate "TI Adaptive Body Bias on-chip LDO" - depends on ARCH_OMAP - help - Select this option to support Texas Instruments' on-chip Adaptive Body - Bias (ABB) LDO regulators. It is recommended that this option be - enabled on required TI SoC. Certain Operating Performance Points - on TI SoCs may be unstable without enabling this as it provides - device specific optimized bias to allow/optimize functionality. - -config REGULATOR_STW481X_VMMC - bool "ST Microelectronics STW481X VMMC regulator" - depends on MFD_STW481X || COMPILE_TEST - default y if MFD_STW481X - help - This driver supports the internal VMMC regulator in the STw481x - PMIC chips. - -config REGULATOR_TPS51632 - tristate "TI TPS51632 Power Regulator" - depends on I2C - select REGMAP_I2C - help - This driver supports TPS51632 voltage regulator chip. - The TPS51632 is 3-2-1 Phase D-Cap+ Step Down Driverless Controller - with Serial VID control and DVFS. - The voltage output can be configure through I2C interface or PWM - interface. - -config REGULATOR_TPS6105X - tristate "TI TPS6105X Power regulators" - depends on TPS6105X - default y if TPS6105X - help - This driver supports TPS61050/TPS61052 voltage regulator chips. - It is a single boost converter primarily for white LEDs and - audio amplifiers. - -config REGULATOR_TPS62360 - tristate "TI TPS6236x Power Regulator" - depends on I2C - select REGMAP_I2C - help - This driver supports TPS6236x voltage regulator chip. This - regulator is meant for processor core supply. This chip is - high-frequency synchronous step down dc-dc converter optimized - for battery-powered portable applications. - -config REGULATOR_TPS65023 - tristate "TI TPS65023 Power regulators" - depends on I2C - select REGMAP_I2C - help - This driver supports TPS65023 voltage regulator chips. TPS65023 provides - three step-down converters and two general-purpose LDO voltage regulators. - It supports TI's software based Class-2 SmartReflex implementation. - -config REGULATOR_TPS6507X - tristate "TI TPS6507X Power regulators" - depends on I2C - help - This driver supports TPS6507X voltage regulator chips. TPS6507X provides - three step-down converters and two general-purpose LDO voltage regulators. - It supports TI's software based Class-2 SmartReflex implementation. - -config REGULATOR_TPS65086 - tristate "TI TPS65086 Power regulators" - depends on MFD_TPS65086 - help - This driver provides support for the voltage regulators on - TI TPS65086 PMICs. - -config REGULATOR_TPS65090 - tristate "TI TPS65090 Power regulator" - depends on MFD_TPS65090 - help - This driver provides support for the voltage regulators on the - TI TPS65090 PMIC. - -config REGULATOR_TPS65217 - tristate "TI TPS65217 Power regulators" - depends on MFD_TPS65217 - help - This driver supports TPS65217 voltage regulator chips. TPS65217 - provides three step-down converters and four general-purpose LDO - voltage regulators. It supports software based voltage control - for different voltage domains - -config REGULATOR_TPS65218 - tristate "TI TPS65218 Power regulators" - depends on MFD_TPS65218 && OF - help - This driver supports TPS65218 voltage regulator chips. TPS65218 - provides six step-down converters and one general-purpose LDO - voltage regulators. It supports software based voltage control - for different voltage domains - -config REGULATOR_TPS6524X - tristate "TI TPS6524X Power regulators" - depends on SPI - help - This driver supports TPS6524X voltage regulator chips. TPS6524X - provides three step-down converters and two general-purpose LDO - voltage regulators. This device is interfaced using a customized - serial interface currently supported on the sequencer serial - port controller. - -config REGULATOR_TPS6586X - tristate "TI TPS6586X Power regulators" - depends on MFD_TPS6586X - help - This driver supports TPS6586X voltage regulator chips. - -config REGULATOR_TPS65910 - tristate "TI TPS65910/TPS65911 Power Regulators" - depends on MFD_TPS65910 - help - This driver supports TPS65910/TPS65911 voltage regulator chips. - -config REGULATOR_TPS65912 - tristate "TI TPS65912 Power regulator" - depends on MFD_TPS65912 - help - This driver supports TPS65912 voltage regulator chip. - -config REGULATOR_TPS80031 - tristate "TI TPS80031/TPS80032 power regulator driver" - depends on MFD_TPS80031 - help - TPS80031/ TPS80032 Fully Integrated Power Management with Power - Path and Battery Charger. It has 5 configurable step-down - converters, 11 general purpose LDOs, VBUS generator and digital - output to control regulators. - -config REGULATOR_TWL4030 - tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0 PMIC" - depends on TWL4030_CORE - help - This driver supports the voltage regulators provided by - this family of companion chips. - -config REGULATOR_VEXPRESS - tristate "Versatile Express regulators" - depends on VEXPRESS_CONFIG - help - This driver provides support for voltage regulators available - on the ARM Ltd's Versatile Express platform. - -config REGULATOR_WM831X - tristate "Wolfson Microelectronics WM831x PMIC regulators" - depends on MFD_WM831X - help - Support the voltage and current regulators of the WM831x series - of PMIC devices. - -config REGULATOR_WM8350 - tristate "Wolfson Microelectronics WM8350 AudioPlus PMIC" - depends on MFD_WM8350 - help - This driver provides support for the voltage and current regulators - of the WM8350 AudioPlus PMIC. - -config REGULATOR_WM8400 - tristate "Wolfson Microelectronics WM8400 AudioPlus PMIC" - depends on MFD_WM8400 - help - This driver provides support for the voltage regulators of the - WM8400 AudioPlus PMIC. - -config REGULATOR_WM8994 - tristate "Wolfson Microelectronics WM8994 CODEC" - depends on MFD_WM8994 - help - This driver provides support for the voltage regulators on the - WM8994 CODEC. - -endif - diff --git a/src/linux/drivers/remoteproc/Kconfig b/src/linux/drivers/remoteproc/Kconfig deleted file mode 100644 index f396bfe..0000000 --- a/src/linux/drivers/remoteproc/Kconfig +++ /dev/null @@ -1,119 +0,0 @@ -menu "Remoteproc drivers" - -# REMOTEPROC gets selected by whoever wants it -config REMOTEPROC - tristate - depends on HAS_DMA - select CRC32 - select FW_LOADER - select VIRTIO - select VIRTUALIZATION - -config OMAP_REMOTEPROC - tristate "OMAP remoteproc support" - depends on HAS_DMA - depends on ARCH_OMAP4 || SOC_OMAP5 - depends on OMAP_IOMMU - select REMOTEPROC - select MAILBOX - select OMAP2PLUS_MBOX - select RPMSG_VIRTIO - help - Say y here to support OMAP's remote processors (dual M3 - and DSP on OMAP4) via the remote processor framework. - - Currently only supported on OMAP4. - - Usually you want to say y here, in order to enable multimedia - use-cases to run on your platform (multimedia codecs are - offloaded to remote DSP processors using this framework). - - It's safe to say n here if you're not interested in multimedia - offloading or just want a bare minimum kernel. - -config STE_MODEM_RPROC - tristate "STE-Modem remoteproc support" - depends on HAS_DMA - select REMOTEPROC - default n - help - Say y or m here to support STE-Modem shared memory driver. - This can be either built-in or a loadable module. - If unsure say N. - -config WKUP_M3_RPROC - tristate "AMx3xx Wakeup M3 remoteproc support" - depends on SOC_AM33XX || SOC_AM43XX - select REMOTEPROC - help - Say y here to support Wakeup M3 remote processor on TI AM33xx - and AM43xx family of SoCs. - - Required for Suspend-to-RAM on AM33xx and AM43xx SoCs. Also needed - for deep CPUIdle states on AM33xx SoCs. Allows for loading of the - firmware onto these remote processors. - If unsure say N. - -config DA8XX_REMOTEPROC - tristate "DA8xx/OMAP-L13x remoteproc support" - depends on ARCH_DAVINCI_DA8XX - select CMA if MMU - select REMOTEPROC - select RPMSG_VIRTIO - help - Say y here to support DA8xx/OMAP-L13x remote processors via the - remote processor framework. - - You want to say y here in order to enable AMP - use-cases to run on your platform (multimedia codecs are - offloaded to remote DSP processors using this framework). - - This module controls the name of the firmware file that gets - loaded on the DSP. This file must reside in the /lib/firmware - directory. It can be specified via the module parameter - da8xx_fw_name=, and if not specified will default to - "rproc-dsp-fw". - - It's safe to say n here if you're not interested in multimedia - offloading. - -config QCOM_MDT_LOADER - tristate - -config QCOM_Q6V5_PIL - tristate "Qualcomm Hexagon V5 Peripherial Image Loader" - depends on OF && ARCH_QCOM - depends on QCOM_SMEM - select MFD_SYSCON - select QCOM_MDT_LOADER - select REMOTEPROC - help - Say y here to support the Qualcomm Peripherial Image Loader for the - Hexagon V5 based remote processors. - -config QCOM_WCNSS_IRIS - tristate - depends on OF && ARCH_QCOM - -config QCOM_WCNSS_PIL - tristate "Qualcomm WCNSS Peripheral Image Loader" - depends on OF && ARCH_QCOM - depends on QCOM_SMEM - select QCOM_MDT_LOADER - select QCOM_SCM - select QCOM_WCNSS_IRIS - select REMOTEPROC - help - Say y here to support the Peripheral Image Loader for the Qualcomm - Wireless Connectivity Subsystem. - -config ST_REMOTEPROC - tristate "ST remoteproc support" - depends on ARCH_STI - select REMOTEPROC - help - Say y here to support ST's adjunct processors via the remote - processor framework. - This can be either built-in or a loadable module. - -endmenu diff --git a/src/linux/drivers/reset/Kconfig b/src/linux/drivers/reset/Kconfig deleted file mode 100644 index 06d9fa2..0000000 --- a/src/linux/drivers/reset/Kconfig +++ /dev/null @@ -1,98 +0,0 @@ -config ARCH_HAS_RESET_CONTROLLER - bool - -menuconfig RESET_CONTROLLER - bool "Reset Controller Support" - default y if ARCH_HAS_RESET_CONTROLLER - help - Generic Reset Controller support. - - This framework is designed to abstract reset handling of devices - via GPIOs or SoC-internal reset controller modules. - - If unsure, say no. - -if RESET_CONTROLLER - -config RESET_ATH79 - bool "AR71xx Reset Driver" if COMPILE_TEST - default ATH79 - help - This enables the ATH79 reset controller driver that supports the - AR71xx SoC reset controller. - -config RESET_BERLIN - bool "Berlin Reset Driver" if COMPILE_TEST - default ARCH_BERLIN - help - This enables the reset controller driver for Marvell Berlin SoCs. - -config RESET_LPC18XX - bool "LPC18xx/43xx Reset Driver" if COMPILE_TEST - default ARCH_LPC18XX - help - This enables the reset controller driver for NXP LPC18xx/43xx SoCs. - -config RESET_MESON - bool "Meson Reset Driver" if COMPILE_TEST - default ARCH_MESON - help - This enables the reset driver for Amlogic Meson SoCs. - -config RESET_OXNAS - bool - -config RESET_PISTACHIO - bool "Pistachio Reset Driver" if COMPILE_TEST - default MACH_PISTACHIO - help - This enables the reset driver for ImgTec Pistachio SoCs. - -config RESET_SOCFPGA - bool "SoCFPGA Reset Driver" if COMPILE_TEST - default ARCH_SOCFPGA - help - This enables the reset controller driver for Altera SoCFPGAs. - -config RESET_STM32 - bool "STM32 Reset Driver" if COMPILE_TEST - default ARCH_STM32 - help - This enables the RCC reset controller driver for STM32 MCUs. - -config RESET_SUNXI - bool "Allwinner SoCs Reset Driver" if COMPILE_TEST && !ARCH_SUNXI - default ARCH_SUNXI - help - This enables the reset driver for Allwinner SoCs. - -config TI_SYSCON_RESET - tristate "TI SYSCON Reset Driver" - depends on HAS_IOMEM - select MFD_SYSCON - help - This enables the reset driver support for TI devices with - memory-mapped reset registers as part of a syscon device node. If - you wish to use the reset framework for such memory-mapped devices, - say Y here. Otherwise, say N. - -config RESET_UNIPHIER - tristate "Reset controller driver for UniPhier SoCs" - depends on ARCH_UNIPHIER || COMPILE_TEST - depends on OF && MFD_SYSCON - default ARCH_UNIPHIER - help - Support for reset controllers on UniPhier SoCs. - Say Y if you want to control reset signals provided by System Control - block, Media I/O block, Peripheral Block. - -config RESET_ZYNQ - bool "ZYNQ Reset Driver" if COMPILE_TEST - default ARCH_ZYNQ - help - This enables the reset controller driver for Xilinx Zynq SoCs. - -source "drivers/reset/sti/Kconfig" -source "drivers/reset/hisilicon/Kconfig" - -endif diff --git a/src/linux/drivers/reset/hisilicon/Kconfig b/src/linux/drivers/reset/hisilicon/Kconfig deleted file mode 100644 index 1ff8b0c..0000000 --- a/src/linux/drivers/reset/hisilicon/Kconfig +++ /dev/null @@ -1,6 +0,0 @@ -config COMMON_RESET_HI6220 - tristate "Hi6220 Reset Driver" - depends on ARCH_HISI || COMPILE_TEST - default ARCH_HISI - help - Build the Hisilicon Hi6220 reset driver. diff --git a/src/linux/drivers/reset/sti/Kconfig b/src/linux/drivers/reset/sti/Kconfig deleted file mode 100644 index 6131785..0000000 --- a/src/linux/drivers/reset/sti/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -if ARCH_STI - -config STI_RESET_SYSCFG - bool - -config STIH415_RESET - bool - select STI_RESET_SYSCFG - -config STIH416_RESET - bool - select STI_RESET_SYSCFG - -config STIH407_RESET - bool - select STI_RESET_SYSCFG - -endif diff --git a/src/linux/drivers/rpmsg/Kconfig b/src/linux/drivers/rpmsg/Kconfig deleted file mode 100644 index de31c5f..0000000 --- a/src/linux/drivers/rpmsg/Kconfig +++ /dev/null @@ -1,23 +0,0 @@ -menu "Rpmsg drivers" - -# RPMSG always gets selected by whoever wants it -config RPMSG - tristate - -config RPMSG_QCOM_SMD - tristate "Qualcomm Shared Memory Driver (SMD)" - depends on QCOM_SMEM - depends on QCOM_SMD=n - select RPMSG - help - Say y here to enable support for the Qualcomm Shared Memory Driver - providing communication channels to remote processors in Qualcomm - platforms. - -config RPMSG_VIRTIO - tristate - select RPMSG - select VIRTIO - select VIRTUALIZATION - -endmenu diff --git a/src/linux/drivers/rtc/Kconfig b/src/linux/drivers/rtc/Kconfig deleted file mode 100644 index e859d14..0000000 --- a/src/linux/drivers/rtc/Kconfig +++ /dev/null @@ -1,1725 +0,0 @@ -# -# RTC class/drivers configuration -# - -config RTC_LIB - bool - -config RTC_MC146818_LIB - bool - select RTC_LIB - -menuconfig RTC_CLASS - bool "Real Time Clock" - default n - depends on !S390 && !UML - select RTC_LIB - help - Generic RTC class support. If you say yes here, you will - be allowed to plug one or more RTCs to your system. You will - probably want to enable one or more of the interfaces below. - -if RTC_CLASS - -config RTC_HCTOSYS - bool "Set system time from RTC on startup and resume" - default y - help - If you say yes here, the system time (wall clock) will be set using - the value read from a specified RTC device. This is useful to avoid - unnecessary fsck runs at boot time, and to network better. - -config RTC_HCTOSYS_DEVICE - string "RTC used to set the system time" - depends on RTC_HCTOSYS - default "rtc0" - help - The RTC device that will be used to (re)initialize the system - clock, usually rtc0. Initialization is done when the system - starts up, and when it resumes from a low power state. This - device should record time in UTC, since the kernel won't do - timezone correction. - - The driver for this RTC device must be loaded before late_initcall - functions run, so it must usually be statically linked. - - This clock should be battery-backed, so that it reads the correct - time when the system boots from a power-off state. Otherwise, your - system will need an external clock source (like an NTP server). - - If the clock you specify here is not battery backed, it may still - be useful to reinitialize system time when resuming from system - sleep states. Do not specify an RTC here unless it stays powered - during all this system's supported sleep states. - -config RTC_SYSTOHC - bool "Set the RTC time based on NTP synchronization" - default y - help - If you say yes here, the system time (wall clock) will be stored - in the RTC specified by RTC_HCTOSYS_DEVICE approximately every 11 - minutes if userspace reports synchronized NTP status. - -config RTC_SYSTOHC_DEVICE - string "RTC used to synchronize NTP adjustment" - depends on RTC_SYSTOHC - default RTC_HCTOSYS_DEVICE if RTC_HCTOSYS - default "rtc0" - help - The RTC device used for NTP synchronization. The main difference - between RTC_HCTOSYS_DEVICE and RTC_SYSTOHC_DEVICE is that this - one can sleep when setting time, because it runs in the workqueue - context. - -config RTC_DEBUG - bool "RTC debug support" - help - Say yes here to enable debugging support in the RTC framework - and individual RTC drivers. - -comment "RTC interfaces" - -config RTC_INTF_SYSFS - bool "/sys/class/rtc/rtcN (sysfs)" - depends on SYSFS - default RTC_CLASS - help - Say yes here if you want to use your RTCs using sysfs interfaces, - /sys/class/rtc/rtc0 through /sys/.../rtcN. - - If unsure, say Y. - -config RTC_INTF_PROC - bool "/proc/driver/rtc (procfs for rtcN)" - depends on PROC_FS - default RTC_CLASS - help - Say yes here if you want to use your system clock RTC through - the proc interface, /proc/driver/rtc. - Other RTCs will not be available through that API. - If there is no RTC for the system clock, then the first RTC(rtc0) - is used by default. - - If unsure, say Y. - -config RTC_INTF_DEV - bool "/dev/rtcN (character devices)" - default RTC_CLASS - help - Say yes here if you want to use your RTCs using the /dev - interfaces, which "udev" sets up as /dev/rtc0 through - /dev/rtcN. - - You may want to set up a symbolic link so one of these - can be accessed as /dev/rtc, which is a name - expected by "hwclock" and some other programs. Recent - versions of "udev" are known to set up the symlink for you. - - If unsure, say Y. - -config RTC_INTF_DEV_UIE_EMUL - bool "RTC UIE emulation on dev interface" - depends on RTC_INTF_DEV - help - Provides an emulation for RTC_UIE if the underlying rtc chip - driver does not expose RTC_UIE ioctls. Those requests generate - once-per-second update interrupts, used for synchronization. - - The emulation code will read the time from the hardware - clock several times per second, please enable this option - only if you know that you really need it. - -config RTC_DRV_TEST - tristate "Test driver/device" - help - If you say yes here you get support for the - RTC test driver. It's a software RTC which can be - used to test the RTC subsystem APIs. It gets - the time from the system clock. - You want this driver only if you are doing development - on the RTC subsystem. Please read the source code - for further details. - - This driver can also be built as a module. If so, the module - will be called rtc-test. - -comment "I2C RTC drivers" - -if I2C - -config RTC_DRV_88PM860X - tristate "Marvell 88PM860x" - depends on MFD_88PM860X - help - If you say yes here you get support for RTC function in Marvell - 88PM860x chips. - - This driver can also be built as a module. If so, the module - will be called rtc-88pm860x. - -config RTC_DRV_88PM80X - tristate "Marvell 88PM80x" - depends on MFD_88PM800 - help - If you say yes here you get support for RTC function in Marvell - 88PM80x chips. - - This driver can also be built as a module. If so, the module - will be called rtc-88pm80x. - -config RTC_DRV_ABB5ZES3 - select REGMAP_I2C - tristate "Abracon AB-RTCMC-32.768kHz-B5ZE-S3" - help - If you say yes here you get support for the Abracon - AB-RTCMC-32.768kHz-B5ZE-S3 I2C RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-ab-b5ze-s3. - -config RTC_DRV_ABX80X - tristate "Abracon ABx80x" - help - If you say yes here you get support for Abracon AB080X and AB180X - families of ultra-low-power battery- and capacitor-backed real-time - clock chips. - - This driver can also be built as a module. If so, the module - will be called rtc-abx80x. - -config RTC_DRV_AC100 - tristate "X-Powers AC100" - depends on MFD_AC100 - help - If you say yes here you get support for the real-time clock found - in X-Powers AC100 family peripheral ICs. - - This driver can also be built as a module. If so, the module - will be called rtc-ac100. - -config RTC_DRV_AS3722 - tristate "ams AS3722 RTC driver" - depends on MFD_AS3722 - help - If you say yes here you get support for the RTC of ams AS3722 PMIC - chips. - - This driver can also be built as a module. If so, the module - will be called rtc-as3722. - -config RTC_DRV_DS1307 - tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025, ISL12057" - help - If you say yes here you get support for various compatible RTC - chips (often with battery backup) connected with I2C. This driver - should handle DS1307, DS1337, DS1338, DS1339, DS1340, ST M41T00, - EPSON RX-8025, Intersil ISL12057 and probably other chips. In some - cases the RTC must already have been initialized (by manufacturing or - a bootloader). - - The first seven registers on these chips hold an RTC, and other - registers may add features such as NVRAM, a trickle charger for - the RTC/NVRAM backup power, and alarms. NVRAM is visible in - sysfs, but other chip features may not be available. - - This driver can also be built as a module. If so, the module - will be called rtc-ds1307. - -config RTC_DRV_DS1307_HWMON - bool "HWMON support for rtc-ds1307" - depends on RTC_DRV_DS1307 && HWMON - depends on !(RTC_DRV_DS1307=y && HWMON=m) - default y - help - Say Y here if you want to expose temperature sensor data on - rtc-ds1307 (only DS3231) - -config RTC_DRV_DS1307_CENTURY - bool "Century bit support for rtc-ds1307" - depends on RTC_DRV_DS1307 - default n - help - The DS1307 driver suffered from a bug where it was enabling the - century bit inconditionnally but never used it when reading the time. - It made the driver unable to support dates beyond 2099. - Setting this option will add proper support for the century bit but if - the time was previously set using a kernel predating this option, - reading the date will return a date in the next century. - To solve that, you could boot a kernel without this option set, set - the RTC date and then boot a kernel with this option set. - -config RTC_DRV_DS1374 - tristate "Dallas/Maxim DS1374" - help - If you say yes here you get support for Dallas Semiconductor - DS1374 real-time clock chips. If an interrupt is associated - with the device, the alarm functionality is supported. - - This driver can also be built as a module. If so, the module - will be called rtc-ds1374. - -config RTC_DRV_DS1374_WDT - bool "Dallas/Maxim DS1374 watchdog timer" - depends on RTC_DRV_DS1374 - help - If you say Y here you will get support for the - watchdog timer in the Dallas Semiconductor DS1374 - real-time clock chips. - -config RTC_DRV_DS1672 - tristate "Dallas/Maxim DS1672" - help - If you say yes here you get support for the - Dallas/Maxim DS1672 timekeeping chip. - - This driver can also be built as a module. If so, the module - will be called rtc-ds1672. - -config RTC_DRV_HYM8563 - tristate "Haoyu Microelectronics HYM8563" - depends on OF - help - Say Y to enable support for the HYM8563 I2C RTC chip. Apart - from the usual rtc functions it provides a clock output of - up to 32kHz. - - This driver can also be built as a module. If so, the module - will be called rtc-hym8563. - -config RTC_DRV_LP8788 - tristate "TI LP8788 RTC driver" - depends on MFD_LP8788 - help - Say Y to enable support for the LP8788 RTC/ALARM driver. - -config RTC_DRV_MAX6900 - tristate "Maxim MAX6900" - help - If you say yes here you will get support for the - Maxim MAX6900 I2C RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-max6900. - -config RTC_DRV_MAX8907 - tristate "Maxim MAX8907" - depends on MFD_MAX8907 - help - If you say yes here you will get support for the - RTC of Maxim MAX8907 PMIC. - - This driver can also be built as a module. If so, the module - will be called rtc-max8907. - -config RTC_DRV_MAX8925 - tristate "Maxim MAX8925" - depends on MFD_MAX8925 - help - If you say yes here you will get support for the - RTC of Maxim MAX8925 PMIC. - - This driver can also be built as a module. If so, the module - will be called rtc-max8925. - -config RTC_DRV_MAX8998 - tristate "Maxim MAX8998" - depends on MFD_MAX8998 - help - If you say yes here you will get support for the - RTC of Maxim MAX8998 PMIC. - - This driver can also be built as a module. If so, the module - will be called rtc-max8998. - -config RTC_DRV_MAX8997 - tristate "Maxim MAX8997" - depends on MFD_MAX8997 - help - If you say yes here you will get support for the - RTC of Maxim MAX8997 PMIC. - - This driver can also be built as a module. If so, the module - will be called rtc-max8997. - -config RTC_DRV_MAX77686 - tristate "Maxim MAX77686" - depends on MFD_MAX77686 || MFD_MAX77620 - help - If you say yes here you will get support for the - RTC of Maxim MAX77686/MAX77620/MAX77802 PMIC. - - This driver can also be built as a module. If so, the module - will be called rtc-max77686. - -config RTC_DRV_RK808 - tristate "Rockchip RK808/RK818 RTC" - depends on MFD_RK808 - help - If you say yes here you will get support for the - RTC of RK808 and RK818 PMIC. - - This driver can also be built as a module. If so, the module - will be called rk808-rtc. - -config RTC_DRV_RS5C372 - tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A" - help - If you say yes here you get support for the - Ricoh R2025S/D, RS5C372A, RS5C372B, RV5C386, and RV5C387A RTC chips. - - This driver can also be built as a module. If so, the module - will be called rtc-rs5c372. - -config RTC_DRV_ISL1208 - tristate "Intersil ISL1208" - help - If you say yes here you get support for the - Intersil ISL1208 RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-isl1208. - -config RTC_DRV_ISL12022 - tristate "Intersil ISL12022" - help - If you say yes here you get support for the - Intersil ISL12022 RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-isl12022. - -config RTC_DRV_X1205 - tristate "Xicor/Intersil X1205" - help - If you say yes here you get support for the - Xicor/Intersil X1205 RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-x1205. - -config RTC_DRV_PCF8523 - tristate "NXP PCF8523" - help - If you say yes here you get support for the NXP PCF8523 RTC - chips. - - This driver can also be built as a module. If so, the module - will be called rtc-pcf8523. - -config RTC_DRV_PCF85063 - tristate "NXP PCF85063" - help - If you say yes here you get support for the PCF85063 RTC chip - - This driver can also be built as a module. If so, the module - will be called rtc-pcf85063. - -config RTC_DRV_PCF8563 - tristate "Philips PCF8563/Epson RTC8564" - help - If you say yes here you get support for the - Philips PCF8563 RTC chip. The Epson RTC8564 - should work as well. - - This driver can also be built as a module. If so, the module - will be called rtc-pcf8563. - -config RTC_DRV_PCF8583 - tristate "Philips PCF8583" - help - If you say yes here you get support for the Philips PCF8583 - RTC chip found on Acorn RiscPCs. This driver supports the - platform specific method of retrieving the current year from - the RTC's SRAM. It will work on other platforms with the same - chip, but the year will probably have to be tweaked. - - This driver can also be built as a module. If so, the module - will be called rtc-pcf8583. - -config RTC_DRV_M41T80 - tristate "ST M41T62/65/M41T80/81/82/83/84/85/87 and compatible" - help - If you say Y here you will get support for the ST M41T60 - and M41T80 RTC chips series. Currently, the following chips are - supported: M41T62, M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84, - M41ST85, M41ST87, and MicroCrystal RV4162. - - This driver can also be built as a module. If so, the module - will be called rtc-m41t80. - -config RTC_DRV_M41T80_WDT - bool "ST M41T65/M41T80 series RTC watchdog timer" - depends on RTC_DRV_M41T80 - help - If you say Y here you will get support for the - watchdog timer in the ST M41T60 and M41T80 RTC chips series. - -config RTC_DRV_BQ32K - tristate "TI BQ32000" - help - If you say Y here you will get support for the TI - BQ32000 I2C RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-bq32k. - -config RTC_DRV_DM355EVM - tristate "TI DaVinci DM355 EVM RTC" - depends on MFD_DM355EVM_MSP - help - Supports the RTC firmware in the MSP430 on the DM355 EVM. - -config RTC_DRV_TWL92330 - bool "TI TWL92330/Menelaus" - depends on MENELAUS - help - If you say yes here you get support for the RTC on the - TWL92330 "Menelaus" power management chip, used with OMAP2 - platforms. The support is integrated with the rest of - the Menelaus driver; it's not separate module. - -config RTC_DRV_TWL4030 - tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0" - depends on TWL4030_CORE - help - If you say yes here you get support for the RTC on the - TWL4030/TWL5030/TWL6030 family chips, used mostly with OMAP3 platforms. - - This driver can also be built as a module. If so, the module - will be called rtc-twl. - -config RTC_DRV_PALMAS - tristate "TI Palmas RTC driver" - depends on MFD_PALMAS - help - If you say yes here you get support for the RTC of TI PALMA series PMIC - chips. - - This driver can also be built as a module. If so, the module - will be called rtc-palma. - -config RTC_DRV_TPS6586X - tristate "TI TPS6586X RTC driver" - depends on MFD_TPS6586X - help - TI Power Management IC TPS6586X supports RTC functionality - along with alarm. This driver supports the RTC driver for - the TPS6586X RTC module. - -config RTC_DRV_TPS65910 - tristate "TI TPS65910 RTC driver" - depends on RTC_CLASS && MFD_TPS65910 - help - If you say yes here you get support for the RTC on the - TPS65910 chips. - - This driver can also be built as a module. If so, the module - will be called rtc-tps65910. - -config RTC_DRV_TPS80031 - tristate "TI TPS80031/TPS80032 RTC driver" - depends on MFD_TPS80031 - help - TI Power Management IC TPS80031 supports RTC functionality - along with alarm. This driver supports the RTC driver for - the TPS80031 RTC module. - -config RTC_DRV_RC5T583 - tristate "RICOH 5T583 RTC driver" - depends on MFD_RC5T583 - help - If you say yes here you get support for the RTC on the - RICOH 5T583 chips. - - This driver can also be built as a module. If so, the module - will be called rtc-rc5t583. - -config RTC_DRV_S35390A - tristate "Seiko Instruments S-35390A" - select BITREVERSE - help - If you say yes here you will get support for the Seiko - Instruments S-35390A. - - This driver can also be built as a module. If so the module - will be called rtc-s35390a. - -config RTC_DRV_FM3130 - tristate "Ramtron FM3130" - help - If you say Y here you will get support for the - Ramtron FM3130 RTC chips. - Ramtron FM3130 is a chip with two separate devices inside, - RTC clock and FRAM. This driver provides only RTC functionality. - - This driver can also be built as a module. If so the module - will be called rtc-fm3130. - -config RTC_DRV_RX8010 - tristate "Epson RX8010SJ" - depends on I2C - help - If you say yes here you get support for the Epson RX8010SJ RTC - chip. - - This driver can also be built as a module. If so, the module - will be called rtc-rx8010. - -config RTC_DRV_RX8581 - tristate "Epson RX-8581" - help - If you say yes here you will get support for the Epson RX-8581. - - This driver can also be built as a module. If so the module - will be called rtc-rx8581. - -config RTC_DRV_RX8025 - tristate "Epson RX-8025SA/NB" - help - If you say yes here you get support for the Epson - RX-8025SA/NB RTC chips. - - This driver can also be built as a module. If so, the module - will be called rtc-rx8025. - -config RTC_DRV_EM3027 - tristate "EM Microelectronic EM3027" - help - If you say yes here you get support for the EM - Microelectronic EM3027 RTC chips. - - This driver can also be built as a module. If so, the module - will be called rtc-em3027. - -config RTC_DRV_RV8803 - tristate "Micro Crystal RV8803, Epson RX8900" - help - If you say yes here you get support for the Micro Crystal RV8803 and - Epson RX8900 RTC chips. - - This driver can also be built as a module. If so, the module - will be called rtc-rv8803. - -config RTC_DRV_S5M - tristate "Samsung S2M/S5M series" - depends on MFD_SEC_CORE - help - If you say yes here you will get support for the - RTC of Samsung S2MPS14 and S5M PMIC series. - - This driver can also be built as a module. If so, the module - will be called rtc-s5m. - -endif # I2C - -comment "SPI RTC drivers" - -if SPI_MASTER - -config RTC_DRV_M41T93 - tristate "ST M41T93" - help - If you say yes here you will get support for the - ST M41T93 SPI RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-m41t93. - -config RTC_DRV_M41T94 - tristate "ST M41T94" - help - If you say yes here you will get support for the - ST M41T94 SPI RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-m41t94. - -config RTC_DRV_DS1302 - tristate "Dallas/Maxim DS1302" - depends on SPI - help - If you say yes here you get support for the Dallas DS1302 RTC chips. - - This driver can also be built as a module. If so, the module - will be called rtc-ds1302. - -config RTC_DRV_DS1305 - tristate "Dallas/Maxim DS1305/DS1306" - help - Select this driver to get support for the Dallas/Maxim DS1305 - and DS1306 real time clock chips. These support a trickle - charger, alarms, and NVRAM in addition to the clock. - - This driver can also be built as a module. If so, the module - will be called rtc-ds1305. - -config RTC_DRV_DS1343 - select REGMAP_SPI - tristate "Dallas/Maxim DS1343/DS1344" - help - If you say yes here you get support for the - Dallas/Maxim DS1343 and DS1344 real time clock chips. - Support for trickle charger, alarm is provided. - - This driver can also be built as a module. If so, the module - will be called rtc-ds1343. - -config RTC_DRV_DS1347 - select REGMAP_SPI - tristate "Dallas/Maxim DS1347" - help - If you say yes here you get support for the - Dallas/Maxim DS1347 chips. - - This driver only supports the RTC feature, and not other chip - features such as alarms. - - This driver can also be built as a module. If so, the module - will be called rtc-ds1347. - -config RTC_DRV_DS1390 - tristate "Dallas/Maxim DS1390/93/94" - help - If you say yes here you get support for the - Dallas/Maxim DS1390/93/94 chips. - - This driver supports the RTC feature and trickle charging but not - other chip features such as alarms. - - This driver can also be built as a module. If so, the module - will be called rtc-ds1390. - -config RTC_DRV_MAX6916 - tristate "Maxim MAX6916" - help - If you say yes here you will get support for the - Maxim MAX6916 SPI RTC chip. - - This driver only supports the RTC feature, and not other chip - features such as alarms. - - This driver can also be built as a module. If so, the module - will be called rtc-max6916. - -config RTC_DRV_R9701 - tristate "Epson RTC-9701JE" - help - If you say yes here you will get support for the - Epson RTC-9701JE SPI RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-r9701. - -config RTC_DRV_RX4581 - tristate "Epson RX-4581" - help - If you say yes here you will get support for the Epson RX-4581. - - This driver can also be built as a module. If so the module - will be called rtc-rx4581. - -config RTC_DRV_RX6110 - tristate "Epson RX-6110" - select REGMAP_SPI - help - If you say yes here you will get support for the Epson RX-6610. - - This driver can also be built as a module. If so the module - will be called rtc-rx6110. - -config RTC_DRV_RS5C348 - tristate "Ricoh RS5C348A/B" - help - If you say yes here you get support for the - Ricoh RS5C348A and RS5C348B RTC chips. - - This driver can also be built as a module. If so, the module - will be called rtc-rs5c348. - -config RTC_DRV_MAX6902 - tristate "Maxim MAX6902" - help - If you say yes here you will get support for the - Maxim MAX6902 SPI RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-max6902. - -config RTC_DRV_PCF2123 - tristate "NXP PCF2123" - help - If you say yes here you get support for the NXP PCF2123 - RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-pcf2123. - -config RTC_DRV_MCP795 - tristate "Microchip MCP795" - help - If you say yes here you will get support for the Microchip MCP795. - - This driver can also be built as a module. If so the module - will be called rtc-mcp795. - -endif # SPI_MASTER - -# -# Helper to resolve issues with configs that have SPI enabled but I2C -# modular. See SND_SOC_I2C_AND_SPI for more information -# -config RTC_I2C_AND_SPI - tristate - default m if I2C=m - default y if I2C=y - default y if SPI_MASTER=y - select REGMAP_I2C if I2C - select REGMAP_SPI if SPI_MASTER - -comment "SPI and I2C RTC drivers" - -config RTC_DRV_DS3232 - tristate "Dallas/Maxim DS3232/DS3234" - depends on RTC_I2C_AND_SPI - help - If you say yes here you get support for Dallas Semiconductor - DS3232 and DS3234 real-time clock chips. If an interrupt is associated - with the device, the alarm functionality is supported. - - This driver can also be built as a module. If so, the module - will be called rtc-ds3232. - -config RTC_DRV_PCF2127 - tristate "NXP PCF2127" - depends on RTC_I2C_AND_SPI - help - If you say yes here you get support for the NXP PCF2127/29 RTC - chips. - - This driver can also be built as a module. If so, the module - will be called rtc-pcf2127. - -config RTC_DRV_RV3029C2 - tristate "Micro Crystal RV3029/3049" - depends on RTC_I2C_AND_SPI - help - If you say yes here you get support for the Micro Crystal - RV3029 and RV3049 RTC chips. - - This driver can also be built as a module. If so, the module - will be called rtc-rv3029c2. - -config RTC_DRV_RV3029_HWMON - bool "HWMON support for RV3029/3049" - depends on RTC_DRV_RV3029C2 && HWMON - depends on !(RTC_DRV_RV3029C2=y && HWMON=m) - default y - help - Say Y here if you want to expose temperature sensor data on - rtc-rv3029. - -comment "Platform RTC drivers" - -# this 'CMOS' RTC driver is arch dependent because -# requires defining CMOS_READ/CMOS_WRITE, and a -# global rtc_lock ... it's not yet just another platform_device. - -config RTC_DRV_CMOS - tristate "PC-style 'CMOS'" - depends on X86 || ARM || M32R || PPC || MIPS || SPARC64 || MN10300 - default y if X86 - select RTC_MC146818_LIB - help - Say "yes" here to get direct support for the real time clock - found in every PC or ACPI-based system, and some other boards. - Specifically the original MC146818, compatibles like those in - PC south bridges, the DS12887 or M48T86, some multifunction - or LPC bus chips, and so on. - - Your system will need to define the platform device used by - this driver, otherwise it won't be accessible. This means - you can safely enable this driver if you don't know whether - or not your board has this kind of hardware. - - This driver can also be built as a module. If so, the module - will be called rtc-cmos. - -config RTC_DRV_ALPHA - bool "Alpha PC-style CMOS" - depends on ALPHA - select RTC_MC146818_LIB - default y - help - Direct support for the real-time clock found on every Alpha - system, specifically MC146818 compatibles. If in doubt, say Y. - -config RTC_DRV_VRTC - tristate "Virtual RTC for Intel MID platforms" - depends on X86_INTEL_MID - default y if X86_INTEL_MID - - help - Say "yes" here to get direct support for the real time clock - found on Moorestown platforms. The VRTC is a emulated RTC that - derives its clock source from a real RTC in the PMIC. The MC146818 - style programming interface is mostly conserved, but any - updates are done via IPC calls to the system controller FW. - -config RTC_DRV_DS1216 - tristate "Dallas DS1216" - depends on SNI_RM - help - If you say yes here you get support for the Dallas DS1216 RTC chips. - -config RTC_DRV_DS1286 - tristate "Dallas DS1286" - depends on HAS_IOMEM - help - If you say yes here you get support for the Dallas DS1286 RTC chips. - -config RTC_DRV_DS1511 - tristate "Dallas DS1511" - depends on HAS_IOMEM - help - If you say yes here you get support for the - Dallas DS1511 timekeeping/watchdog chip. - - This driver can also be built as a module. If so, the module - will be called rtc-ds1511. - -config RTC_DRV_DS1553 - tristate "Maxim/Dallas DS1553" - depends on HAS_IOMEM - help - If you say yes here you get support for the - Maxim/Dallas DS1553 timekeeping chip. - - This driver can also be built as a module. If so, the module - will be called rtc-ds1553. - -config RTC_DRV_DS1685_FAMILY - tristate "Dallas/Maxim DS1685 Family" - help - If you say yes here you get support for the Dallas/Maxim DS1685 - family of real time chips. This family includes the DS1685/DS1687, - DS1689/DS1693, DS17285/DS17287, DS17485/DS17487, and - DS17885/DS17887 chips. - - This driver can also be built as a module. If so, the module - will be called rtc-ds1685. - -choice - prompt "Subtype" - depends on RTC_DRV_DS1685_FAMILY - default RTC_DRV_DS1685 - -config RTC_DRV_DS1685 - bool "DS1685/DS1687" - help - This enables support for the Dallas/Maxim DS1685/DS1687 real time - clock chip. - - This chip is commonly found in SGI O2 (IP32) and SGI Octane (IP30) - systems, as well as EPPC-405-UC modules by electronic system design - GmbH. - -config RTC_DRV_DS1689 - bool "DS1689/DS1693" - help - This enables support for the Dallas/Maxim DS1689/DS1693 real time - clock chip. - - This is an older RTC chip, supplanted by the DS1685/DS1687 above, - which supports a few minor features such as Vcc, Vbat, and Power - Cycle counters, plus a customer-specific, 8-byte ROM/Serial number. - - It also works for the even older DS1688/DS1691 RTC chips, which are - virtually the same and carry the same model number. Both chips - have 114 bytes of user NVRAM. - -config RTC_DRV_DS17285 - bool "DS17285/DS17287" - help - This enables support for the Dallas/Maxim DS17285/DS17287 real time - clock chip. - - This chip features 2kb of extended NV-SRAM. It may possibly be - found in some SGI O2 systems (rare). - -config RTC_DRV_DS17485 - bool "DS17485/DS17487" - help - This enables support for the Dallas/Maxim DS17485/DS17487 real time - clock chip. - - This chip features 4kb of extended NV-SRAM. - -config RTC_DRV_DS17885 - bool "DS17885/DS17887" - help - This enables support for the Dallas/Maxim DS17885/DS17887 real time - clock chip. - - This chip features 8kb of extended NV-SRAM. - -endchoice - -config RTC_DS1685_PROC_REGS - bool "Display register values in /proc" - depends on RTC_DRV_DS1685_FAMILY && PROC_FS - help - Enable this to display a readout of all of the RTC registers in - /proc/drivers/rtc. Keep in mind that this can potentially lead - to lost interrupts, as reading Control Register C will clear - all pending IRQ flags. - - Unless you are debugging this driver, choose N. - -config RTC_DS1685_SYSFS_REGS - bool "SysFS access to RTC register bits" - depends on RTC_DRV_DS1685_FAMILY && SYSFS - help - Enable this to provide access to the RTC control register bits - in /sys. Some of the bits are read-write, others are read-only. - - Keep in mind that reading Control C's bits automatically clears - all pending IRQ flags - this can cause lost interrupts. - - If you know that you need access to these bits, choose Y, Else N. - -config RTC_DRV_DS1742 - tristate "Maxim/Dallas DS1742/1743" - depends on HAS_IOMEM - help - If you say yes here you get support for the - Maxim/Dallas DS1742/1743 timekeeping chip. - - This driver can also be built as a module. If so, the module - will be called rtc-ds1742. - -config RTC_DRV_DS2404 - tristate "Maxim/Dallas DS2404" - help - If you say yes here you get support for the - Dallas DS2404 RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-ds2404. - -config RTC_DRV_DA9052 - tristate "Dialog DA9052/DA9053 RTC" - depends on PMIC_DA9052 - help - Say y here to support the RTC driver for Dialog Semiconductor - DA9052-BC and DA9053-AA/Bx PMICs. - -config RTC_DRV_DA9055 - tristate "Dialog Semiconductor DA9055 RTC" - depends on MFD_DA9055 - help - If you say yes here you will get support for the - RTC of the Dialog DA9055 PMIC. - - This driver can also be built as a module. If so, the module - will be called rtc-da9055 - -config RTC_DRV_DA9063 - tristate "Dialog Semiconductor DA9063/DA9062 RTC" - depends on MFD_DA9063 || MFD_DA9062 - help - If you say yes here you will get support for the RTC subsystem - for the Dialog Semiconductor PMIC chips DA9063 and DA9062. - - This driver can also be built as a module. If so, the module - will be called "rtc-da9063". - -config RTC_DRV_EFI - tristate "EFI RTC" - depends on EFI && !X86 - help - If you say yes here you will get support for the EFI - Real Time Clock. - - This driver can also be built as a module. If so, the module - will be called rtc-efi. - -config RTC_DRV_STK17TA8 - tristate "Simtek STK17TA8" - depends on HAS_IOMEM - help - If you say yes here you get support for the - Simtek STK17TA8 timekeeping chip. - - This driver can also be built as a module. If so, the module - will be called rtc-stk17ta8. - -config RTC_DRV_M48T86 - tristate "ST M48T86/Dallas DS12887" - help - If you say Y here you will get support for the - ST M48T86 and Dallas DS12887 RTC chips. - - This driver can also be built as a module. If so, the module - will be called rtc-m48t86. - -config RTC_DRV_M48T35 - tristate "ST M48T35" - depends on HAS_IOMEM - help - If you say Y here you will get support for the - ST M48T35 RTC chip. - - This driver can also be built as a module, if so, the module - will be called "rtc-m48t35". - -config RTC_DRV_M48T59 - tristate "ST M48T59/M48T08/M48T02" - depends on HAS_IOMEM - help - If you say Y here you will get support for the - ST M48T59 RTC chip and compatible ST M48T08 and M48T02. - - These chips are usually found in Sun SPARC and UltraSPARC - workstations. - - This driver can also be built as a module, if so, the module - will be called "rtc-m48t59". - -config RTC_DRV_MSM6242 - tristate "Oki MSM6242" - depends on HAS_IOMEM - help - If you say yes here you get support for the Oki MSM6242 - timekeeping chip. It is used in some Amiga models (e.g. A2000). - - This driver can also be built as a module. If so, the module - will be called rtc-msm6242. - -config RTC_DRV_BQ4802 - tristate "TI BQ4802" - depends on HAS_IOMEM - help - If you say Y here you will get support for the TI - BQ4802 RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-bq4802. - -config RTC_DRV_RP5C01 - tristate "Ricoh RP5C01" - depends on HAS_IOMEM - help - If you say yes here you get support for the Ricoh RP5C01 - timekeeping chip. It is used in some Amiga models (e.g. A3000 - and A4000). - - This driver can also be built as a module. If so, the module - will be called rtc-rp5c01. - -config RTC_DRV_V3020 - tristate "EM Microelectronic V3020" - help - If you say yes here you will get support for the - EM Microelectronic v3020 RTC chip. - - This driver can also be built as a module. If so, the module - will be called rtc-v3020. - -config RTC_DRV_WM831X - tristate "Wolfson Microelectronics WM831x RTC" - depends on MFD_WM831X - help - If you say yes here you will get support for the RTC subsystem - of the Wolfson Microelectronics WM831X series PMICs. - - This driver can also be built as a module. If so, the module - will be called "rtc-wm831x". - -config RTC_DRV_WM8350 - tristate "Wolfson Microelectronics WM8350 RTC" - depends on MFD_WM8350 - help - If you say yes here you will get support for the RTC subsystem - of the Wolfson Microelectronics WM8350. - - This driver can also be built as a module. If so, the module - will be called "rtc-wm8350". - -config RTC_DRV_SPEAR - tristate "SPEAR ST RTC" - depends on PLAT_SPEAR || COMPILE_TEST - default y - help - If you say Y here you will get support for the RTC found on - spear - -config RTC_DRV_PCF50633 - depends on MFD_PCF50633 - tristate "NXP PCF50633 RTC" - help - If you say yes here you get support for the RTC subsystem of the - NXP PCF50633 used in embedded systems. - -config RTC_DRV_AB3100 - tristate "ST-Ericsson AB3100 RTC" - depends on AB3100_CORE - default y if AB3100_CORE - help - Select this to enable the ST-Ericsson AB3100 Mixed Signal IC RTC - support. This chip contains a battery- and capacitor-backed RTC. - -config RTC_DRV_AB8500 - tristate "ST-Ericsson AB8500 RTC" - depends on AB8500_CORE - select RTC_INTF_DEV - select RTC_INTF_DEV_UIE_EMUL - help - Select this to enable the ST-Ericsson AB8500 power management IC RTC - support. This chip contains a battery- and capacitor-backed RTC. - -config RTC_DRV_NUC900 - tristate "NUC910/NUC920 RTC driver" - depends on ARCH_W90X900 || COMPILE_TEST - help - If you say yes here you get support for the RTC subsystem of the - NUC910/NUC920 used in embedded systems. - -config RTC_DRV_OPAL - tristate "IBM OPAL RTC driver" - depends on PPC_POWERNV - default y - help - If you say yes here you get support for the PowerNV platform RTC - driver based on OPAL interfaces. - - This driver can also be built as a module. If so, the module - will be called rtc-opal. - -config RTC_DRV_ZYNQMP - tristate "Xilinx Zynq Ultrascale+ MPSoC RTC" - depends on OF - help - If you say yes here you get support for the RTC controller found on - Xilinx Zynq Ultrascale+ MPSoC. - -comment "on-CPU RTC drivers" - -config RTC_DRV_ASM9260 - tristate "Alphascale asm9260 RTC" - depends on MACH_ASM9260 || COMPILE_TEST - help - If you say yes here you get support for the RTC on the - Alphascale asm9260 SoC. - - This driver can also be built as a module. If so, the module - will be called rtc-asm9260. - -config RTC_DRV_DAVINCI - tristate "TI DaVinci RTC" - depends on ARCH_DAVINCI_DM365 || COMPILE_TEST - help - If you say yes here you get support for the RTC on the - DaVinci platforms (DM365). - - This driver can also be built as a module. If so, the module - will be called rtc-davinci. - -config RTC_DRV_DIGICOLOR - tristate "Conexant Digicolor RTC" - depends on ARCH_DIGICOLOR || COMPILE_TEST - help - If you say yes here you get support for the RTC on Conexant - Digicolor platforms. This currently includes the CX92755 SoC. - - This driver can also be built as a module. If so, the module - will be called rtc-digicolor. - -config RTC_DRV_IMXDI - tristate "Freescale IMX DryIce Real Time Clock" - depends on ARCH_MXC - help - Support for Freescale IMX DryIce RTC - - This driver can also be built as a module, if so, the module - will be called "rtc-imxdi". - -config RTC_DRV_OMAP - tristate "TI OMAP Real Time Clock" - depends on ARCH_OMAP || ARCH_DAVINCI || COMPILE_TEST - depends on OF - depends on PINCTRL - select GENERIC_PINCONF - help - Say "yes" here to support the on chip real time clock - present on TI OMAP1, AM33xx, DA8xx/OMAP-L13x, AM43xx and DRA7xx. - - This driver can also be built as a module, if so, module - will be called rtc-omap. - -config HAVE_S3C_RTC - bool - help - This will include RTC support for Samsung SoCs. If - you want to include RTC support for any machine, kindly - select this in the respective mach-XXXX/Kconfig file. - -config RTC_DRV_S3C - tristate "Samsung S3C series SoC RTC" - depends on ARCH_S3C64XX || HAVE_S3C_RTC || COMPILE_TEST - help - RTC (Realtime Clock) driver for the clock inbuilt into the - Samsung S3C24XX series of SoCs. This can provide periodic - interrupt rates from 1Hz to 64Hz for user programs, and - wakeup from Alarm. - - The driver currently supports the common features on all the - S3C24XX range, such as the S3C2410, S3C2412, S3C2413, S3C2440 - and S3C2442. - - This driver can also be build as a module. If so, the module - will be called rtc-s3c. - -config RTC_DRV_EP93XX - tristate "Cirrus Logic EP93XX" - depends on ARCH_EP93XX || COMPILE_TEST - help - If you say yes here you get support for the - RTC embedded in the Cirrus Logic EP93XX processors. - - This driver can also be built as a module. If so, the module - will be called rtc-ep93xx. - -config RTC_DRV_SA1100 - tristate "SA11x0/PXA2xx/PXA910" - depends on ARCH_SA1100 || ARCH_PXA || ARCH_MMP - help - If you say Y here you will get access to the real time clock - built into your SA11x0 or PXA2xx CPU. - - To compile this driver as a module, choose M here: the - module will be called rtc-sa1100. - -config RTC_DRV_SH - tristate "SuperH On-Chip RTC" - depends on SUPERH && HAVE_CLK - help - Say Y here to enable support for the on-chip RTC found in - most SuperH processors. - - To compile this driver as a module, choose M here: the - module will be called rtc-sh. - -config RTC_DRV_VR41XX - tristate "NEC VR41XX" - depends on CPU_VR41XX || COMPILE_TEST - help - If you say Y here you will get access to the real time clock - built into your NEC VR41XX CPU. - - To compile this driver as a module, choose M here: the - module will be called rtc-vr41xx. - -config RTC_DRV_PL030 - tristate "ARM AMBA PL030 RTC" - depends on ARM_AMBA - help - If you say Y here you will get access to ARM AMBA - PrimeCell PL030 RTC found on certain ARM SOCs. - - To compile this driver as a module, choose M here: the - module will be called rtc-pl030. - -config RTC_DRV_PL031 - tristate "ARM AMBA PL031 RTC" - depends on ARM_AMBA - help - If you say Y here you will get access to ARM AMBA - PrimeCell PL031 RTC found on certain ARM SOCs. - - To compile this driver as a module, choose M here: the - module will be called rtc-pl031. - -config RTC_DRV_AT32AP700X - tristate "AT32AP700X series RTC" - depends on PLATFORM_AT32AP || COMPILE_TEST - help - Driver for the internal RTC (Realtime Clock) on Atmel AVR32 - AT32AP700x family processors. - -config RTC_DRV_AT91RM9200 - tristate "AT91RM9200 or some AT91SAM9 RTC" - depends on ARCH_AT91 || COMPILE_TEST - help - Driver for the internal RTC (Realtime Clock) module found on - Atmel AT91RM9200's and some AT91SAM9 chips. On AT91SAM9 chips - this is powered by the backup power supply. - -config RTC_DRV_AT91SAM9 - tristate "AT91SAM9 RTT as RTC" - depends on ARCH_AT91 || COMPILE_TEST - select MFD_SYSCON - help - Some AT91SAM9 SoCs provide an RTT (Real Time Timer) block which - can be used as an RTC thanks to the backup power supply (e.g. a - small coin cell battery) which keeps this block and the GPBR - (General Purpose Backup Registers) block powered when the device - is shutdown. - Some AT91SAM9 SoCs provide a real RTC block, on those ones you'd - probably want to use the real RTC block instead of the "RTT as an - RTC" driver. - -config RTC_DRV_AU1XXX - tristate "Au1xxx Counter0 RTC support" - depends on MIPS_ALCHEMY - help - This is a driver for the Au1xxx on-chip Counter0 (Time-Of-Year - counter) to be used as a RTC. - - This driver can also be built as a module. If so, the module - will be called rtc-au1xxx. - -config RTC_DRV_BFIN - tristate "Blackfin On-Chip RTC" - depends on BLACKFIN && !BF561 - help - If you say yes here you will get support for the - Blackfin On-Chip Real Time Clock. - - This driver can also be built as a module. If so, the module - will be called rtc-bfin. - -config RTC_DRV_RS5C313 - tristate "Ricoh RS5C313" - depends on SH_LANDISK - help - If you say yes here you get support for the Ricoh RS5C313 RTC chips. - -config RTC_DRV_GENERIC - tristate "Generic RTC support" - # Please consider writing a new RTC driver instead of using the generic - # RTC abstraction - depends on PARISC || M68K || PPC || SUPERH32 || COMPILE_TEST - help - Say Y or M here to enable RTC support on systems using the generic - RTC abstraction. If you do not know what you are doing, you should - just say Y. - -config RTC_DRV_PXA - tristate "PXA27x/PXA3xx" - depends on ARCH_PXA - select RTC_DRV_SA1100 - help - If you say Y here you will get access to the real time clock - built into your PXA27x or PXA3xx CPU. This RTC is actually 2 RTCs - consisting of an SA1100 compatible RTC and the extended PXA RTC. - - This RTC driver uses PXA RTC registers available since pxa27x - series (RDxR, RYxR) instead of legacy RCNR, RTAR. - -config RTC_DRV_VT8500 - tristate "VIA/WonderMedia 85xx SoC RTC" - depends on ARCH_VT8500 || COMPILE_TEST - help - If you say Y here you will get access to the real time clock - built into your VIA VT8500 SoC or its relatives. - - -config RTC_DRV_SUN4V - bool "SUN4V Hypervisor RTC" - depends on SPARC64 - help - If you say Y here you will get support for the Hypervisor - based RTC on SUN4V systems. - -config RTC_DRV_SUN6I - tristate "Allwinner A31 RTC" - default MACH_SUN6I || MACH_SUN8I || COMPILE_TEST - depends on ARCH_SUNXI - help - If you say Y here you will get support for the RTC found in - some Allwinner SoCs like the A31 or the A64. - -config RTC_DRV_SUNXI - tristate "Allwinner sun4i/sun7i RTC" - depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST - help - If you say Y here you will get support for the RTC found on - Allwinner A10/A20. - -config RTC_DRV_STARFIRE - bool "Starfire RTC" - depends on SPARC64 - help - If you say Y here you will get support for the RTC found on - Starfire systems. - -config RTC_DRV_TX4939 - tristate "TX4939 SoC" - depends on SOC_TX4939 - help - Driver for the internal RTC (Realtime Clock) module found on - Toshiba TX4939 SoC. - -config RTC_DRV_MV - tristate "Marvell SoC RTC" - depends on ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST - help - If you say yes here you will get support for the in-chip RTC - that can be found in some of Marvell's SoC devices, such as - the Kirkwood 88F6281 and 88F6192. - - This driver can also be built as a module. If so, the module - will be called rtc-mv. - -config RTC_DRV_ARMADA38X - tristate "Armada 38x Marvell SoC RTC" - depends on ARCH_MVEBU || COMPILE_TEST - help - If you say yes here you will get support for the in-chip RTC - that can be found in the Armada 38x Marvell's SoC device - - This driver can also be built as a module. If so, the module - will be called armada38x-rtc. - -config RTC_DRV_GEMINI - tristate "Gemini SoC RTC" - depends on ARCH_GEMINI || COMPILE_TEST - depends on HAS_IOMEM - help - If you say Y here you will get support for the - RTC found on Gemini SoC's. - - This driver can also be built as a module. If so, the module - will be called rtc-gemini. - -config RTC_DRV_PS3 - tristate "PS3 RTC" - depends on PPC_PS3 - help - If you say yes here you will get support for the RTC on PS3. - - This driver can also be built as a module. If so, the module - will be called rtc-ps3. - -config RTC_DRV_COH901331 - tristate "ST-Ericsson COH 901 331 RTC" - depends on ARCH_U300 || COMPILE_TEST - help - If you say Y here you will get access to ST-Ericsson - COH 901 331 RTC clock found in some ST-Ericsson Mobile - Platforms. - - This driver can also be built as a module. If so, the module - will be called "rtc-coh901331". - - -config RTC_DRV_STMP - tristate "Freescale STMP3xxx/i.MX23/i.MX28 RTC" - depends on ARCH_MXS || COMPILE_TEST - select STMP_DEVICE - help - If you say yes here you will get support for the onboard - STMP3xxx/i.MX23/i.MX28 RTC. - - This driver can also be built as a module. If so, the module - will be called rtc-stmp3xxx. - -config RTC_DRV_PCAP - tristate "PCAP RTC" - depends on EZX_PCAP - help - If you say Y here you will get support for the RTC found on - the PCAP2 ASIC used on some Motorola phones. - -config RTC_DRV_MC13XXX - depends on MFD_MC13XXX - tristate "Freescale MC13xxx RTC" - help - This enables support for the RTCs found on Freescale's PMICs - MC13783 and MC13892. - -config RTC_DRV_MPC5121 - tristate "Freescale MPC5121 built-in RTC" - depends on PPC_MPC512x || PPC_MPC52xx - help - If you say yes here you will get support for the - built-in RTC on MPC5121 or on MPC5200. - - This driver can also be built as a module. If so, the module - will be called rtc-mpc5121. - -config RTC_DRV_JZ4740 - tristate "Ingenic JZ4740 SoC" - depends on MACH_JZ4740 || COMPILE_TEST - help - If you say yes here you get support for the Ingenic JZ4740 SoC RTC - controller. - - This driver can also be buillt as a module. If so, the module - will be called rtc-jz4740. - -config RTC_DRV_LPC24XX - tristate "NXP RTC for LPC178x/18xx/408x/43xx" - depends on ARCH_LPC18XX || COMPILE_TEST - depends on OF && HAS_IOMEM - help - This enables support for the NXP RTC found which can be found on - NXP LPC178x/18xx/408x/43xx devices. - - If you have one of the devices above enable this driver to use - the hardware RTC. This driver can also be buillt as a module. If - so, the module will be called rtc-lpc24xx. - -config RTC_DRV_LPC32XX - depends on ARCH_LPC32XX || COMPILE_TEST - tristate "NXP LPC32XX RTC" - help - This enables support for the NXP RTC in the LPC32XX - - This driver can also be buillt as a module. If so, the module - will be called rtc-lpc32xx. - -config RTC_DRV_PM8XXX - tristate "Qualcomm PMIC8XXX RTC" - depends on MFD_PM8XXX || MFD_SPMI_PMIC || COMPILE_TEST - help - If you say yes here you get support for the - Qualcomm PMIC8XXX RTC. - - To compile this driver as a module, choose M here: the - module will be called rtc-pm8xxx. - -config RTC_DRV_TEGRA - tristate "NVIDIA Tegra Internal RTC driver" - depends on ARCH_TEGRA || COMPILE_TEST - help - If you say yes here you get support for the - Tegra 200 series internal RTC module. - - This drive can also be built as a module. If so, the module - will be called rtc-tegra. - -config RTC_DRV_TILE - tristate "Tilera hypervisor RTC support" - depends on TILE - help - Enable support for the Linux driver side of the Tilera - hypervisor's real-time clock interface. - -config RTC_DRV_PUV3 - tristate "PKUnity v3 RTC support" - depends on ARCH_PUV3 - help - This enables support for the RTC in the PKUnity-v3 SoCs. - - This drive can also be built as a module. If so, the module - will be called rtc-puv3. - -config RTC_DRV_LOONGSON1 - tristate "loongson1 RTC support" - depends on MACH_LOONGSON32 - help - This is a driver for the loongson1 on-chip Counter0 (Time-Of-Year - counter) to be used as a RTC. - - This driver can also be built as a module. If so, the module - will be called rtc-ls1x. - -config RTC_DRV_MXC - tristate "Freescale MXC Real Time Clock" - depends on ARCH_MXC - help - If you say yes here you get support for the Freescale MXC - RTC module. - - This driver can also be built as a module, if so, the module - will be called "rtc-mxc". - -config RTC_DRV_SNVS - tristate "Freescale SNVS RTC support" - select REGMAP_MMIO - depends on HAS_IOMEM - depends on OF - help - If you say yes here you get support for the Freescale SNVS - Low Power (LP) RTC module. - - This driver can also be built as a module, if so, the module - will be called "rtc-snvs". - -config RTC_DRV_SIRFSOC - tristate "SiRFSOC RTC" - depends on ARCH_SIRF - help - Say "yes" here to support the real time clock on SiRF SOC chips. - This driver can also be built as a module called rtc-sirfsoc. - -config RTC_DRV_ST_LPC - tristate "STMicroelectronics LPC RTC" - depends on ARCH_STI - depends on OF - help - Say Y here to include STMicroelectronics Low Power Controller - (LPC) based RTC support. - - To compile this driver as a module, choose M here: the - module will be called rtc-st-lpc. - -config RTC_DRV_MOXART - tristate "MOXA ART RTC" - depends on ARCH_MOXART || COMPILE_TEST - help - If you say yes here you get support for the MOXA ART - RTC module. - - This driver can also be built as a module. If so, the module - will be called rtc-moxart - -config RTC_DRV_MT6397 - tristate "Mediatek Real Time Clock driver" - depends on MFD_MT6397 || (COMPILE_TEST && IRQ_DOMAIN) - help - This selects the Mediatek(R) RTC driver. RTC is part of Mediatek - MT6397 PMIC. You should enable MT6397 PMIC MFD before select - Mediatek(R) RTC driver. - - If you want to use Mediatek(R) RTC interface, select Y or M here. - -config RTC_DRV_XGENE - tristate "APM X-Gene RTC" - depends on HAS_IOMEM - depends on ARCH_XGENE || COMPILE_TEST - help - If you say yes here you get support for the APM X-Gene SoC real time - clock. - - This driver can also be built as a module, if so, the module - will be called "rtc-xgene". - -config RTC_DRV_PIC32 - tristate "Microchip PIC32 RTC" - depends on MACH_PIC32 - default y - help - If you say yes here you get support for the PIC32 RTC module. - - This driver can also be built as a module. If so, the module - will be called rtc-pic32 - -comment "HID Sensor RTC drivers" - -config RTC_DRV_HID_SENSOR_TIME - tristate "HID Sensor Time" - depends on USB_HID - select IIO - select HID_SENSOR_HUB - select HID_SENSOR_IIO_COMMON - help - Say yes here to build support for the HID Sensors of type Time. - This drivers makes such sensors available as RTCs. - - If this driver is compiled as a module, it will be named - rtc-hid-sensor-time. - - -endif # RTC_CLASS diff --git a/src/linux/drivers/s390/block/Kconfig b/src/linux/drivers/s390/block/Kconfig deleted file mode 100644 index 4a3b623..0000000 --- a/src/linux/drivers/s390/block/Kconfig +++ /dev/null @@ -1,90 +0,0 @@ -comment "S/390 block device drivers" - depends on S390 && BLOCK - -config BLK_DEV_XPRAM - def_tristate m - prompt "XPRAM disk support" - depends on S390 && BLOCK - help - Select this option if you want to use your expanded storage on S/390 - or zSeries as a disk. This is useful as a _fast_ swap device if you - want to access more than 2G of memory when running in 31 bit mode. - This option is also available as a module which will be called - xpram. If unsure, say "N". - -config DCSSBLK - def_tristate m - prompt "DCSSBLK support" - depends on S390 && BLOCK - help - Support for dcss block device - -config DASD - def_tristate y - prompt "Support for DASD devices" - depends on CCW && BLOCK - select IOSCHED_DEADLINE - help - Enable this option if you want to access DASDs directly utilizing - S/390s channel subsystem commands. This is necessary for running - natively on a single image or an LPAR. - -config DASD_PROFILE - def_bool y - prompt "Profiling support for dasd devices" - depends on DASD - help - Enable this option if you want to see profiling information - in /proc/dasd/statistics. - -config DASD_ECKD - def_tristate y - prompt "Support for ECKD Disks" - depends on DASD - help - ECKD devices are the most commonly used devices. You should enable - this option unless you are very sure to have no ECKD device. - -config DASD_FBA - def_tristate y - prompt "Support for FBA Disks" - depends on DASD - help - Select this option to be able to access FBA devices. It is safe to - say "Y". - -config DASD_DIAG - def_tristate y - prompt "Support for DIAG access to Disks" - depends on DASD - help - Select this option if you want to use Diagnose250 command to access - Disks under VM. If you are not running under VM or unsure what it is, - say "N". - -config DASD_EER - def_bool y - prompt "Extended error reporting (EER)" - depends on DASD - help - This driver provides a character device interface to the - DASD extended error reporting. This is only needed if you want to - use applications written for the EER facility. - -config SCM_BLOCK - def_tristate m - prompt "Support for Storage Class Memory" - depends on S390 && BLOCK && EADM_SCH && SCM_BUS - help - Block device driver for Storage Class Memory (SCM). This driver - provides a block device interface for each available SCM increment. - - To compile this driver as a module, choose M here: the - module will be called scm_block. - -config SCM_BLOCK_CLUSTER_WRITE - def_bool y - prompt "SCM force cluster writes" - depends on SCM_BLOCK - help - Force writes to Storage Class Memory (SCM) to be in done in clusters. diff --git a/src/linux/drivers/s390/char/Kconfig b/src/linux/drivers/s390/char/Kconfig deleted file mode 100644 index b3f1c45..0000000 --- a/src/linux/drivers/s390/char/Kconfig +++ /dev/null @@ -1,196 +0,0 @@ -comment "S/390 character device drivers" - depends on S390 - -config TN3270 - def_tristate y - prompt "Support for locally attached 3270 terminals" - depends on CCW - help - Include support for IBM 3270 terminals. - -config TN3270_TTY - def_tristate y - prompt "Support for tty input/output on 3270 terminals" - depends on TN3270 && TTY - help - Include support for using an IBM 3270 terminal as a Linux tty. - -config TN3270_FS - def_tristate m - prompt "Support for fullscreen applications on 3270 terminals" - depends on TN3270 - help - Include support for fullscreen applications on an IBM 3270 terminal. - -config TN3270_CONSOLE - def_bool y - prompt "Support for console on 3270 terminal" - depends on TN3270=y && TN3270_TTY=y - help - Include support for using an IBM 3270 terminal as a Linux system - console. Available only if 3270 support is compiled in statically. - -config TN3215 - def_bool y - prompt "Support for 3215 line mode terminal" - depends on CCW && TTY - help - Include support for IBM 3215 line-mode terminals. - -config TN3215_CONSOLE - def_bool y - prompt "Support for console on 3215 line mode terminal" - depends on TN3215 - help - Include support for using an IBM 3215 line-mode terminal as a - Linux system console. - -config CCW_CONSOLE - def_bool y if TN3215_CONSOLE || TN3270_CONSOLE - -config SCLP_TTY - def_bool y - prompt "Support for SCLP line mode terminal" - depends on S390 && TTY - help - Include support for IBM SCLP line-mode terminals. - -config SCLP_CONSOLE - def_bool y - prompt "Support for console on SCLP line mode terminal" - depends on SCLP_TTY - help - Include support for using an IBM HWC line-mode terminal as the Linux - system console. - -config SCLP_VT220_TTY - def_bool y - prompt "Support for SCLP VT220-compatible terminal" - depends on S390 && TTY - help - Include support for an IBM SCLP VT220-compatible terminal. - -config SCLP_VT220_CONSOLE - def_bool y - prompt "Support for console on SCLP VT220-compatible terminal" - depends on SCLP_VT220_TTY - help - Include support for using an IBM SCLP VT220-compatible terminal as a - Linux system console. - -config SCLP_ASYNC - def_tristate m - prompt "Support for Call Home via Asynchronous SCLP Records" - depends on S390 - help - This option enables the call home function, which is able to inform - the service element and connected organisations about a kernel panic. - You should only select this option if you know what you are doing, - want for inform other people about your kernel panics, - need this feature and intend to run your kernel in LPAR. - -config SCLP_ASYNC_ID - string "Component ID for Call Home" - depends on SCLP_ASYNC - default "000000000" - help - The Component ID for Call Home is used to identify the correct - problem reporting queue the call home records should be sent to. - - If your are unsure, please use the default value "000000000". - -config HMC_DRV - def_tristate m - prompt "Support for file transfers from HMC drive CD/DVD-ROM" - depends on S390 - select CRC16 - help - This option enables support for file transfers from a Hardware - Management Console (HMC) drive CD/DVD-ROM. It is available as a - module, called 'hmcdrv', and also as kernel built-in. There is one - optional parameter for this module: cachesize=N, which modifies the - transfer cache size from it's default value 0.5MB to N bytes. If N - is zero, then no caching is performed. - -config SCLP_OFB - def_bool n - prompt "Support for Open-for-Business SCLP Event" - depends on S390 - help - This option enables the Open-for-Business interface to the s390 - Service Element. - -config S390_TAPE - def_tristate m - prompt "S/390 tape device support" - depends on CCW - help - Select this option if you want to access channel-attached tape - devices on IBM S/390 or zSeries. - If you select this option you will also want to select at - least one of the tape interface options and one of the tape - hardware options in order to access a tape device. - This option is also available as a module. The module will be - called tape390 and include all selected interfaces and - hardware drivers. - -comment "S/390 tape hardware support" - depends on S390_TAPE - -config S390_TAPE_34XX - def_tristate m - prompt "Support for 3480/3490 tape hardware" - depends on S390_TAPE - help - Select this option if you want to access IBM 3480/3490 magnetic - tape subsystems and 100% compatibles. - It is safe to say "Y" here. - -config S390_TAPE_3590 - def_tristate m - prompt "Support for 3590 tape hardware" - depends on S390_TAPE - help - Select this option if you want to access IBM 3590 magnetic - tape subsystems and 100% compatibles. - It is safe to say "Y" here. - -config VMLOGRDR - def_tristate m - prompt "Support for the z/VM recording system services (VM only)" - depends on IUCV - help - Select this option if you want to be able to receive records collected - by the z/VM recording system services, eg. from *LOGREC, *ACCOUNT or - *SYMPTOM. - This driver depends on the IUCV support driver. - -config VMCP - def_bool y - prompt "Support for the z/VM CP interface" - depends on S390 - help - Select this option if you want to be able to interact with the control - program on z/VM - -config MONREADER - def_tristate m - prompt "API for reading z/VM monitor service records" - depends on IUCV - help - Character device driver for reading z/VM monitor service records - -config MONWRITER - def_tristate m - prompt "API for writing z/VM monitor service records" - depends on S390 - help - Character device driver for writing z/VM monitor service records - -config S390_VMUR - def_tristate m - prompt "z/VM unit record device driver" - depends on S390 - help - Character device driver for z/VM reader, puncher and printer. - diff --git a/src/linux/drivers/s390/net/Kconfig b/src/linux/drivers/s390/net/Kconfig deleted file mode 100644 index b2837b1..0000000 --- a/src/linux/drivers/s390/net/Kconfig +++ /dev/null @@ -1,100 +0,0 @@ -menu "S/390 network device drivers" - depends on NETDEVICES && S390 - -config LCS - def_tristate m - prompt "Lan Channel Station Interface" - depends on CCW && NETDEVICES && (ETHERNET || FDDI) - help - Select this option if you want to use LCS networking on IBM System z. - This device driver supports FDDI (IEEE 802.7) and Ethernet. - To compile as a module, choose M. The module name is lcs. - If you do not know what it is, it's safe to choose Y. - -config CTCM - def_tristate m - prompt "CTC and MPC SNA device support" - depends on CCW && NETDEVICES - help - Select this option if you want to use channel-to-channel - point-to-point networking on IBM System z. - This device driver supports real CTC coupling using ESCON. - It also supports virtual CTCs when running under VM. - This driver also supports channel-to-channel MPC SNA devices. - MPC is an SNA protocol device used by Communication Server for Linux. - To compile as a module, choose M. The module name is ctcm. - To compile into the kernel, choose Y. - If you do not need any channel-to-channel connection, choose N. - -config NETIUCV - def_tristate m - prompt "IUCV network device support (VM only)" - depends on IUCV && NETDEVICES - help - Select this option if you want to use inter-user communication - vehicle networking under VM or VIF. It enables a fast communication - link between VM guests. Using ifconfig a point-to-point connection - can be established to the Linux on IBM System z - running on the other VM guest. To compile as a module, choose M. - The module name is netiucv. If unsure, choose Y. - -config SMSGIUCV - def_tristate m - prompt "IUCV special message support (VM only)" - depends on IUCV - help - Select this option if you want to be able to receive SMSG messages - from other VM guest systems. - -config SMSGIUCV_EVENT - def_tristate m - prompt "Deliver IUCV special messages as uevents (VM only)" - depends on SMSGIUCV - help - Select this option to deliver CP special messages (SMSGs) as - uevents. The driver handles only those special messages that - start with "APP". - - To compile as a module, choose M. The module name is "smsgiucv_app". - -config QETH - def_tristate y - prompt "Gigabit Ethernet device support" - depends on CCW && NETDEVICES && IP_MULTICAST && QDIO && ETHERNET - help - This driver supports the IBM System z OSA Express adapters - in QDIO mode (all media types), HiperSockets interfaces and z/VM - virtual NICs for Guest LAN and VSWITCH. - - For details please refer to the documentation provided by IBM at - - - To compile this driver as a module, choose M. - The module name is qeth. - -config QETH_L2 - def_tristate y - prompt "qeth layer 2 device support" - depends on QETH - help - Select this option to be able to run qeth devices in layer 2 mode. - To compile as a module, choose M. The module name is qeth_l2. - If unsure, choose y. - -config QETH_L3 - def_tristate y - prompt "qeth layer 3 device support" - depends on QETH - help - Select this option to be able to run qeth devices in layer 3 mode. - To compile as a module choose M. The module name is qeth_l3. - If unsure, choose Y. - -config QETH_IPV6 - def_bool y if (QETH_L3 = IPV6) || (QETH_L3 && IPV6 = 'y') - -config CCWGROUP - tristate - default (LCS || CTCM || QETH) - -endmenu diff --git a/src/linux/drivers/scsi/.gitignore b/src/linux/drivers/scsi/.gitignore deleted file mode 100644 index c89ae9a..0000000 --- a/src/linux/drivers/scsi/.gitignore +++ /dev/null @@ -1 +0,0 @@ -53c700_d.h diff --git a/src/linux/drivers/scsi/Kconfig b/src/linux/drivers/scsi/Kconfig deleted file mode 100644 index 3e2bdb9..0000000 --- a/src/linux/drivers/scsi/Kconfig +++ /dev/null @@ -1,1632 +0,0 @@ -menu "SCSI device support" - -config SCSI_MOD - tristate - default y if SCSI=n || SCSI=y - default m if SCSI=m - -config RAID_ATTRS - tristate "RAID Transport Class" - default n - depends on BLOCK - depends on SCSI_MOD - ---help--- - Provides RAID - -config SCSI - tristate "SCSI device support" - depends on BLOCK - select SCSI_DMA if HAS_DMA - select SG_POOL - ---help--- - If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or - any other SCSI device under Linux, say Y and make sure that you know - the name of your SCSI host adapter (the card inside your computer - that "speaks" the SCSI protocol, also called SCSI controller), - because you will be asked for it. - - You also need to say Y here if you have a device which speaks - the SCSI protocol. Examples of this include the parallel port - version of the IOMEGA ZIP drive, USB storage devices, Fibre - Channel, and FireWire storage. - - To compile this driver as a module, choose M here and read - . - The module will be called scsi_mod. - - However, do not compile this as a module if your root file system - (the one containing the directory /) is located on a SCSI device. - -config SCSI_DMA - bool - default n - -config SCSI_NETLINK - bool - default n - depends on NET - -config SCSI_MQ_DEFAULT - bool "SCSI: use blk-mq I/O path by default" - depends on SCSI - ---help--- - This option enables the new blk-mq based I/O path for SCSI - devices by default. With the option the scsi_mod.use_blk_mq - module/boot option defaults to Y, without it to N, but it can - still be overridden either way. - - If unsure say N. - -config SCSI_PROC_FS - bool "legacy /proc/scsi/ support" - depends on SCSI && PROC_FS - default y - ---help--- - This option enables support for the various files in - /proc/scsi. In Linux 2.6 this has been superseded by - files in sysfs but many legacy applications rely on this. - - If unsure say Y. - -comment "SCSI support type (disk, tape, CD-ROM)" - depends on SCSI - -config BLK_DEV_SD - tristate "SCSI disk support" - depends on SCSI - ---help--- - If you want to use SCSI hard disks, Fibre Channel disks, - Serial ATA (SATA) or Parallel ATA (PATA) hard disks, - USB storage or the SCSI or parallel port version of - the IOMEGA ZIP drive, say Y and read the SCSI-HOWTO, - the Disk-HOWTO and the Multi-Disk-HOWTO, available from - . This is NOT for SCSI - CD-ROMs. - - To compile this driver as a module, choose M here and read - . - The module will be called sd_mod. - - Do not compile this driver as a module if your root file system - (the one containing the directory /) is located on a SCSI disk. - In this case, do not compile the driver for your SCSI host adapter - (below) as a module either. - -config CHR_DEV_ST - tristate "SCSI tape support" - depends on SCSI - ---help--- - If you want to use a SCSI tape drive under Linux, say Y and read the - SCSI-HOWTO, available from - , and - in the kernel source. This is NOT - for SCSI CD-ROMs. - - To compile this driver as a module, choose M here and read - . The module will be called st. - -config CHR_DEV_OSST - tristate "SCSI OnStream SC-x0 tape support" - depends on SCSI - ---help--- - The OnStream SC-x0 SCSI tape drives cannot be driven by the - standard st driver, but instead need this special osst driver and - use the /dev/osstX char device nodes (major 206). Via usb-storage, - you may be able to drive the USB-x0 and DI-x0 drives as well. - Note that there is also a second generation of OnStream - tape drives (ADR-x0) that supports the standard SCSI-2 commands for - tapes (QIC-157) and can be driven by the standard driver st. - For more information, you may have a look at the SCSI-HOWTO - and - in the kernel source. - More info on the OnStream driver may be found on - - Please also have a look at the standard st docu, as most of it - applies to osst as well. - - To compile this driver as a module, choose M here and read - . The module will be called osst. - -config BLK_DEV_SR - tristate "SCSI CDROM support" - depends on SCSI - ---help--- - If you want to use a CD or DVD drive attached to your computer - by SCSI, FireWire, USB or ATAPI, say Y and read the SCSI-HOWTO - and the CDROM-HOWTO at . - - Make sure to say Y or M to "ISO 9660 CD-ROM file system support". - - To compile this driver as a module, choose M here and read - . - The module will be called sr_mod. - -config BLK_DEV_SR_VENDOR - bool "Enable vendor-specific extensions (for SCSI CDROM)" - depends on BLK_DEV_SR - help - This enables the usage of vendor specific SCSI commands. This is - required to support multisession CDs with old NEC/TOSHIBA cdrom - drives (and HP Writers). If you have such a drive and get the first - session only, try saying Y here; everybody else says N. - -config CHR_DEV_SG - tristate "SCSI generic support" - depends on SCSI - ---help--- - If you want to use SCSI scanners, synthesizers or CD-writers or just - about anything having "SCSI" in its name other than hard disks, - CD-ROMs or tapes, say Y here. These won't be supported by the kernel - directly, so you need some additional software which knows how to - talk to these devices using the SCSI protocol: - - For scanners, look at SANE (). For CD - writer software look at Cdrtools - () - and for burning a "disk at once": CDRDAO - (). Cdparanoia is a high - quality digital reader of audio CDs (). - For other devices, it's possible that you'll have to write the - driver software yourself. Please read the file - for more information. - - To compile this driver as a module, choose M here and read - . The module will be called sg. - - If unsure, say N. - -config CHR_DEV_SCH - tristate "SCSI media changer support" - depends on SCSI - ---help--- - This is a driver for SCSI media changers. Most common devices are - tape libraries and MOD/CDROM jukeboxes. *Real* jukeboxes, you - don't need this for those tiny 6-slot cdrom changers. Media - changers are listed as "Type: Medium Changer" in /proc/scsi/scsi. - If you have such hardware and want to use it with linux, say Y - here. Check for details. - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here and read and - . The module will be called ch.o. - If unsure, say N. - -config SCSI_ENCLOSURE - tristate "SCSI Enclosure Support" - depends on SCSI && ENCLOSURE_SERVICES - depends on m || SCSI_SAS_ATTRS != m - help - Enclosures are devices sitting on or in SCSI backplanes that - manage devices. If you have a disk cage, the chances are that - it has an enclosure device. Selecting this option will just allow - certain enclosure conditions to be reported and is not required. - -config SCSI_CONSTANTS - bool "Verbose SCSI error reporting (kernel size += 36K)" - depends on SCSI - help - The error messages regarding your SCSI hardware will be easier to - understand if you say Y here; it will enlarge your kernel by about - 36 KB. If in doubt, say Y. - -config SCSI_LOGGING - bool "SCSI logging facility" - depends on SCSI - ---help--- - This turns on a logging facility that can be used to debug a number - of SCSI related problems. - - If you say Y here, no logging output will appear by default, but you - can enable logging by saying Y to "/proc file system support" and - "Sysctl support" below and executing the command - - echo > /proc/sys/dev/scsi/logging_level - - where is a four byte value representing the logging type - and logging level for each type of logging selected. - - There are a number of logging types and you can find them in the - source at . The logging levels - are also described in that file and they determine the verbosity of - the logging for each logging type. - - If you say N here, it may be harder to track down some types of SCSI - problems. If you say Y here your kernel will be somewhat larger, but - there should be no noticeable performance impact as long as you have - logging turned off. - -config SCSI_SCAN_ASYNC - bool "Asynchronous SCSI scanning" - depends on SCSI - help - The SCSI subsystem can probe for devices while the rest of the - system continues booting, and even probe devices on different - busses in parallel, leading to a significant speed-up. - - You can override this choice by specifying "scsi_mod.scan=sync" - or async on the kernel's command line. - - Note that this setting also affects whether resuming from - system suspend will be performed asynchronously. - -menu "SCSI Transports" - depends on SCSI - -config SCSI_SPI_ATTRS - tristate "Parallel SCSI (SPI) Transport Attributes" - depends on SCSI - help - If you wish to export transport-specific information about - each attached SCSI device to sysfs, say Y. Otherwise, say N. - -config SCSI_FC_ATTRS - tristate "FiberChannel Transport Attributes" - depends on SCSI && NET - select SCSI_NETLINK - help - If you wish to export transport-specific information about - each attached FiberChannel device to sysfs, say Y. - Otherwise, say N. - -config SCSI_ISCSI_ATTRS - tristate "iSCSI Transport Attributes" - depends on SCSI && NET - select BLK_DEV_BSGLIB - help - If you wish to export transport-specific information about - each attached iSCSI device to sysfs, say Y. - Otherwise, say N. - -config SCSI_SAS_ATTRS - tristate "SAS Transport Attributes" - depends on SCSI - select BLK_DEV_BSG - help - If you wish to export transport-specific information about - each attached SAS device to sysfs, say Y. - -source "drivers/scsi/libsas/Kconfig" - -config SCSI_SRP_ATTRS - tristate "SRP Transport Attributes" - depends on SCSI - help - If you wish to export transport-specific information about - each attached SRP device to sysfs, say Y. - -endmenu - -menuconfig SCSI_LOWLEVEL - bool "SCSI low-level drivers" - depends on SCSI!=n - default y - -if SCSI_LOWLEVEL && SCSI - -config ISCSI_TCP - tristate "iSCSI Initiator over TCP/IP" - depends on SCSI && INET - select CRYPTO - select CRYPTO_MD5 - select CRYPTO_CRC32C - select SCSI_ISCSI_ATTRS - help - The iSCSI Driver provides a host with the ability to access storage - through an IP network. The driver uses the iSCSI protocol to transport - SCSI requests and responses over a TCP/IP network between the host - (the "initiator") and "targets". Architecturally, the iSCSI driver - combines with the host's TCP/IP stack, network drivers, and Network - Interface Card (NIC) to provide the same functions as a SCSI or a - Fibre Channel (FC) adapter driver with a Host Bus Adapter (HBA). - - To compile this driver as a module, choose M here: the - module will be called iscsi_tcp. - - The userspace component needed to initialize the driver, documentation, - and sample configuration files can be found here: - - http://open-iscsi.org - -config ISCSI_BOOT_SYSFS - tristate "iSCSI Boot Sysfs Interface" - default n - help - This option enables support for exposing iSCSI boot information - via sysfs to userspace. If you wish to export this information, - say Y. Otherwise, say N. - -source "drivers/scsi/cxgbi/Kconfig" -source "drivers/scsi/bnx2i/Kconfig" -source "drivers/scsi/bnx2fc/Kconfig" -source "drivers/scsi/be2iscsi/Kconfig" -source "drivers/scsi/cxlflash/Kconfig" - -config SGIWD93_SCSI - tristate "SGI WD93C93 SCSI Driver" - depends on SGI_HAS_WD93 && SCSI - help - If you have a Western Digital WD93 SCSI controller on - an SGI MIPS system, say Y. Otherwise, say N. - -config BLK_DEV_3W_XXXX_RAID - tristate "3ware 5/6/7/8xxx ATA-RAID support" - depends on PCI && SCSI - help - 3ware is the only hardware ATA-Raid product in Linux to date. - This card is 2,4, or 8 channel master mode support only. - SCSI support required!!! - - - - Please read the comments at the top of - . - -config SCSI_HPSA - tristate "HP Smart Array SCSI driver" - depends on PCI && SCSI - select CHECK_SIGNATURE - select SCSI_SAS_ATTRS - help - This driver supports HP Smart Array Controllers (circa 2009). - It is a SCSI alternative to the cciss driver, which is a block - driver. Anyone wishing to use HP Smart Array controllers who - would prefer the devices be presented to linux as SCSI devices, - rather than as generic block devices should say Y here. - -config SCSI_3W_9XXX - tristate "3ware 9xxx SATA-RAID support" - depends on PCI && SCSI - help - This driver supports the 9000 series 3ware SATA-RAID cards. - - - - Please read the comments at the top of - . - -config SCSI_3W_SAS - tristate "3ware 97xx SAS/SATA-RAID support" - depends on PCI && SCSI - help - This driver supports the LSI 3ware 9750 6Gb/s SAS/SATA-RAID cards. - - - - Please read the comments at the top of - . - -config SCSI_ACARD - tristate "ACARD SCSI support" - depends on PCI && SCSI - help - This driver supports the ACARD SCSI host adapter. - Support Chip - To compile this driver as a module, choose M here: the - module will be called atp870u. - -config SCSI_AHA152X - tristate "Adaptec AHA152X/2825 support" - depends on ISA && SCSI - select SCSI_SPI_ATTRS - select CHECK_SIGNATURE - ---help--- - This is a driver for the AHA-1510, AHA-1520, AHA-1522, and AHA-2825 - SCSI host adapters. It also works for the AVA-1505, but the IRQ etc. - must be manually specified in this case. - - It is explained in section 3.3 of the SCSI-HOWTO, available from - . You might also want to - read the file . - - To compile this driver as a module, choose M here: the - module will be called aha152x. - -config SCSI_AHA1542 - tristate "Adaptec AHA1542 support" - depends on ISA && SCSI && ISA_DMA_API - ---help--- - This is support for a SCSI host adapter. It is explained in section - 3.4 of the SCSI-HOWTO, available from - . Note that Trantor was - purchased by Adaptec, and some former Trantor products are being - sold under the Adaptec name. If it doesn't work out of the box, you - may have to change some settings in . - - To compile this driver as a module, choose M here: the - module will be called aha1542. - -config SCSI_AHA1740 - tristate "Adaptec AHA1740 support" - depends on EISA && SCSI - ---help--- - This is support for a SCSI host adapter. It is explained in section - 3.5 of the SCSI-HOWTO, available from - . If it doesn't work out - of the box, you may have to change some settings in - . - - To compile this driver as a module, choose M here: the - module will be called aha1740. - -config SCSI_AACRAID - tristate "Adaptec AACRAID support" - depends on SCSI && PCI - help - This driver supports a variety of Dell, HP, Adaptec, IBM and - ICP storage products. For a list of supported products, refer - to . - - To compile this driver as a module, choose M here: the module - will be called aacraid. - - -source "drivers/scsi/aic7xxx/Kconfig.aic7xxx" -source "drivers/scsi/aic7xxx/Kconfig.aic79xx" -source "drivers/scsi/aic94xx/Kconfig" -source "drivers/scsi/hisi_sas/Kconfig" -source "drivers/scsi/mvsas/Kconfig" - -config SCSI_MVUMI - tristate "Marvell UMI driver" - depends on SCSI && PCI - help - Module for Marvell Universal Message Interface(UMI) driver - - To compile this driver as a module, choose M here: the - module will be called mvumi. - -config SCSI_DPT_I2O - tristate "Adaptec I2O RAID support " - depends on SCSI && PCI && VIRT_TO_BUS - help - This driver supports all of Adaptec's I2O based RAID controllers as - well as the DPT SmartRaid V cards. This is an Adaptec maintained - driver by Deanna Bonds. See . - - To compile this driver as a module, choose M here: the - module will be called dpt_i2o. - -config SCSI_ADVANSYS - tristate "AdvanSys SCSI support" - depends on SCSI - depends on ISA || EISA || PCI - depends on ISA_DMA_API || !ISA - help - This is a driver for all SCSI host adapters manufactured by - AdvanSys. It is documented in the kernel source in - . - - To compile this driver as a module, choose M here: the - module will be called advansys. - -config SCSI_ARCMSR - tristate "ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID Host Adapter" - depends on PCI && SCSI - help - This driver supports all of ARECA's SATA/SAS RAID controller cards. - This is an ARECA-maintained driver by Erich Chen. - If you have any problems, please mail to: . - Areca supports Linux RAID config tools. - Please link - - To compile this driver as a module, choose M here: the - module will be called arcmsr (modprobe arcmsr). - -source "drivers/scsi/esas2r/Kconfig" -source "drivers/scsi/megaraid/Kconfig.megaraid" -source "drivers/scsi/mpt3sas/Kconfig" -source "drivers/scsi/smartpqi/Kconfig" -source "drivers/scsi/ufs/Kconfig" - -config SCSI_HPTIOP - tristate "HighPoint RocketRAID 3xxx/4xxx Controller support" - depends on SCSI && PCI - help - This option enables support for HighPoint RocketRAID 3xxx/4xxx - controllers. - - To compile this driver as a module, choose M here; the module - will be called hptiop. If unsure, say N. - -config SCSI_BUSLOGIC - tristate "BusLogic SCSI support" - depends on (PCI || ISA || MCA) && SCSI && ISA_DMA_API && VIRT_TO_BUS - ---help--- - This is support for BusLogic MultiMaster and FlashPoint SCSI Host - Adapters. Consult the SCSI-HOWTO, available from - , and the files - and - for more information. - Note that support for FlashPoint is only available for 32-bit - x86 configurations. - - To compile this driver as a module, choose M here: the - module will be called BusLogic. - -config SCSI_FLASHPOINT - bool "FlashPoint support" - depends on SCSI_BUSLOGIC && PCI - help - This option allows you to add FlashPoint support to the - BusLogic SCSI driver. The FlashPoint SCCB Manager code is - substantial, so users of MultiMaster Host Adapters may not - wish to include it. - -config VMWARE_PVSCSI - tristate "VMware PVSCSI driver support" - depends on PCI && SCSI && X86 - help - This driver supports VMware's para virtualized SCSI HBA. - To compile this driver as a module, choose M here: the - module will be called vmw_pvscsi. - -config XEN_SCSI_FRONTEND - tristate "XEN SCSI frontend driver" - depends on SCSI && XEN - select XEN_XENBUS_FRONTEND - help - The XEN SCSI frontend driver allows the kernel to access SCSI Devices - within another guest OS (usually Dom0). - Only needed if the kernel is running in a XEN guest and generic - SCSI access to a device is needed. - -config HYPERV_STORAGE - tristate "Microsoft Hyper-V virtual storage driver" - depends on SCSI && HYPERV - depends on m || SCSI_FC_ATTRS != m - default HYPERV - help - Select this option to enable the Hyper-V virtual storage driver. - -config LIBFC - tristate "LibFC module" - depends on SCSI_FC_ATTRS - select CRC32 - ---help--- - Fibre Channel library module - -config LIBFCOE - tristate "LibFCoE module" - depends on LIBFC - ---help--- - Library for Fibre Channel over Ethernet module - -config FCOE - tristate "FCoE module" - depends on PCI - depends on LIBFCOE - ---help--- - Fibre Channel over Ethernet module - -config FCOE_FNIC - tristate "Cisco FNIC Driver" - depends on PCI && X86 - depends on LIBFCOE - help - This is support for the Cisco PCI-Express FCoE HBA. - - To compile this driver as a module, choose M here and read - . - The module will be called fnic. - -config SCSI_SNIC - tristate "Cisco SNIC Driver" - depends on PCI && SCSI - help - This is support for the Cisco PCI-Express SCSI HBA. - - To compile this driver as a module, choose M here and read - . - The module will be called snic. - -config SCSI_SNIC_DEBUG_FS - bool "Cisco SNIC Driver Debugfs Support" - depends on SCSI_SNIC && DEBUG_FS - help - This enables to list debugging information from SNIC Driver - available via debugfs file system - -config SCSI_DMX3191D - tristate "DMX3191D SCSI support" - depends on PCI && SCSI - select SCSI_SPI_ATTRS - help - This is support for Domex DMX3191D SCSI Host Adapters. - - To compile this driver as a module, choose M here: the - module will be called dmx3191d. - -config SCSI_EATA - tristate "EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support" - depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API - ---help--- - This driver supports all EATA/DMA-compliant SCSI host adapters. DPT - ISA and all EISA I/O addresses are probed looking for the "EATA" - signature. The addresses of all the PCI SCSI controllers reported - by the PCI subsystem are probed as well. - - You want to read the start of and the - SCSI-HOWTO, available from - . - - To compile this driver as a module, choose M here: the - module will be called eata. - -config SCSI_EATA_TAGGED_QUEUE - bool "enable tagged command queueing" - depends on SCSI_EATA - help - This is a feature of SCSI-2 which improves performance: the host - adapter can send several SCSI commands to a device's queue even if - previous commands haven't finished yet. - This is equivalent to the "eata=tc:y" boot option. - -config SCSI_EATA_LINKED_COMMANDS - bool "enable elevator sorting" - depends on SCSI_EATA - help - This option enables elevator sorting for all probed SCSI disks and - CD-ROMs. It definitely reduces the average seek distance when doing - random seeks, but this does not necessarily result in a noticeable - performance improvement: your mileage may vary... - This is equivalent to the "eata=lc:y" boot option. - -config SCSI_EATA_MAX_TAGS - int "maximum number of queued commands" - depends on SCSI_EATA - default "16" - help - This specifies how many SCSI commands can be maximally queued for - each probed SCSI device. You should reduce the default value of 16 - only if you have disks with buggy or limited tagged command support. - Minimum is 2 and maximum is 62. This value is also the window size - used by the elevator sorting option above. The effective value used - by the driver for each probed SCSI device is reported at boot time. - This is equivalent to the "eata=mq:8" boot option. - -config SCSI_EATA_PIO - tristate "EATA-PIO (old DPT PM2001, PM2012A) support" - depends on (ISA || EISA || PCI) && SCSI && BROKEN - ---help--- - This driver supports all EATA-PIO protocol compliant SCSI Host - Adapters like the DPT PM2001 and the PM2012A. EATA-DMA compliant - host adapters could also use this driver but are discouraged from - doing so, since this driver only supports hard disks and lacks - numerous features. You might want to have a look at the SCSI-HOWTO, - available from . - - To compile this driver as a module, choose M here: the - module will be called eata_pio. - -config SCSI_FUTURE_DOMAIN - tristate "Future Domain 16xx SCSI/AHA-2920A support" - depends on (ISA || PCI) && SCSI - select CHECK_SIGNATURE - ---help--- - This is support for Future Domain's 16-bit SCSI host adapters - (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and - other adapters based on the Future Domain chipsets (Quantum - ISA-200S, ISA-250MG; Adaptec AHA-2920A; and at least one IBM board). - It is explained in section 3.7 of the SCSI-HOWTO, available from - . - - NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip - and should use the aic7xxx driver ("Adaptec AIC7xxx chipset SCSI - controller support"). This Future Domain driver works with the older - Adaptec AHA-2920A boards with a Future Domain chip on them. - - To compile this driver as a module, choose M here: the - module will be called fdomain. - -config SCSI_GDTH - tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support" - depends on (ISA || EISA || PCI) && SCSI && ISA_DMA_API - ---help--- - Formerly called GDT SCSI Disk Array Controller Support. - - This is a driver for RAID/SCSI Disk Array Controllers (EISA/ISA/PCI) - manufactured by Intel Corporation/ICP vortex GmbH. It is documented - in the kernel source in and - . - - To compile this driver as a module, choose M here: the - module will be called gdth. - -config SCSI_ISCI - tristate "Intel(R) C600 Series Chipset SAS Controller" - depends on PCI && SCSI - depends on X86 - select SCSI_SAS_LIBSAS - ---help--- - This driver supports the 6Gb/s SAS capabilities of the storage - control unit found in the Intel(R) C600 series chipset. - -config SCSI_GENERIC_NCR5380 - tristate "Generic NCR5380/53c400 SCSI PIO support" - depends on ISA && SCSI - select SCSI_SPI_ATTRS - ---help--- - This is a driver for the old NCR 53c80 series of SCSI controllers - on boards using PIO. Most boards such as the Trantor T130 fit this - category, along with a large number of ISA 8bit controllers shipped - for free with SCSI scanners. If you have a PAS16, T128 or DMX3191 - you should select the specific driver for that card rather than - generic 5380 support. - - It is explained in section 3.8 of the SCSI-HOWTO, available from - . If it doesn't work out - of the box, you may have to change some settings in - . - - To compile this driver as a module, choose M here: the - module will be called g_NCR5380. - -config SCSI_GENERIC_NCR5380_MMIO - tristate "Generic NCR5380/53c400 SCSI MMIO support" - depends on ISA && SCSI - select SCSI_SPI_ATTRS - ---help--- - This is a driver for the old NCR 53c80 series of SCSI controllers - on boards using memory mapped I/O. - It is explained in section 3.8 of the SCSI-HOWTO, available from - . If it doesn't work out - of the box, you may have to change some settings in - . - - To compile this driver as a module, choose M here: the - module will be called g_NCR5380_mmio. - -config SCSI_IPS - tristate "IBM ServeRAID support" - depends on PCI && SCSI - ---help--- - This is support for the IBM ServeRAID hardware RAID controllers. - See - and - for more information. If this driver does not work correctly - without modification please contact the author by email at - . - - To compile this driver as a module, choose M here: the - module will be called ips. - -config SCSI_IBMVSCSI - tristate "IBM Virtual SCSI support" - depends on PPC_PSERIES - select SCSI_SRP_ATTRS - help - This is the IBM POWER Virtual SCSI Client - - To compile this driver as a module, choose M here: the - module will be called ibmvscsi. - -config SCSI_IBMVSCSIS - tristate "IBM Virtual SCSI Server support" - depends on PPC_PSERIES && TARGET_CORE && SCSI && PCI - help - This is the IBM POWER Virtual SCSI Target Server - This driver uses the SRP protocol for communication betwen servers - guest and/or the host that run on the same server. - More information on VSCSI protocol can be found at www.power.org - - The userspace configuration needed to initialize the driver can be - be found here: - - https://github.com/powervm/ibmvscsis/wiki/Configuration - - To compile this driver as a module, choose M here: the - module will be called ibmvscsis. - -config SCSI_IBMVFC - tristate "IBM Virtual FC support" - depends on PPC_PSERIES && SCSI - depends on SCSI_FC_ATTRS - help - This is the IBM POWER Virtual FC Client - - To compile this driver as a module, choose M here: the - module will be called ibmvfc. - -config SCSI_IBMVFC_TRACE - bool "enable driver internal trace" - depends on SCSI_IBMVFC - default y - help - If you say Y here, the driver will trace all commands issued - to the adapter. Performance impact is minimal. Trace can be - dumped using /sys/class/scsi_host/hostXX/trace. - -config SCSI_INITIO - tristate "Initio 9100U(W) support" - depends on PCI && SCSI - help - This is support for the Initio 91XXU(W) SCSI host adapter. Please - read the SCSI-HOWTO, available from - . - - To compile this driver as a module, choose M here: the - module will be called initio. - -config SCSI_INIA100 - tristate "Initio INI-A100U2W support" - depends on PCI && SCSI - help - This is support for the Initio INI-A100U2W SCSI host adapter. - Please read the SCSI-HOWTO, available from - . - - To compile this driver as a module, choose M here: the - module will be called a100u2w. - -config SCSI_PPA - tristate "IOMEGA parallel port (ppa - older drives)" - depends on SCSI && PARPORT_PC - ---help--- - This driver supports older versions of IOMEGA's parallel port ZIP - drive (a 100 MB removable media device). - - Note that you can say N here if you have the SCSI version of the ZIP - drive: it will be supported automatically if you said Y to the - generic "SCSI disk support", above. - - If you have the ZIP Plus drive or a more recent parallel port ZIP - drive (if the supplied cable with the drive is labeled "AutoDetect") - then you should say N here and Y to "IOMEGA parallel port (imm - - newer drives)", below. - - For more information about this driver and how to use it you should - read the file . You should also read - the SCSI-HOWTO, which is available from - . If you use this driver, - you will still be able to use the parallel port for other tasks, - such as a printer; it is safe to compile both drivers into the - kernel. - - To compile this driver as a module, choose M here: the - module will be called ppa. - -config SCSI_IMM - tristate "IOMEGA parallel port (imm - newer drives)" - depends on SCSI && PARPORT_PC - ---help--- - This driver supports newer versions of IOMEGA's parallel port ZIP - drive (a 100 MB removable media device). - - Note that you can say N here if you have the SCSI version of the ZIP - drive: it will be supported automatically if you said Y to the - generic "SCSI disk support", above. - - If you have the ZIP Plus drive or a more recent parallel port ZIP - drive (if the supplied cable with the drive is labeled "AutoDetect") - then you should say Y here; if you have an older ZIP drive, say N - here and Y to "IOMEGA Parallel Port (ppa - older drives)", above. - - For more information about this driver and how to use it you should - read the file . You should also read - the SCSI-HOWTO, which is available from - . If you use this driver, - you will still be able to use the parallel port for other tasks, - such as a printer; it is safe to compile both drivers into the - kernel. - - To compile this driver as a module, choose M here: the - module will be called imm. - -config SCSI_IZIP_EPP16 - bool "ppa/imm option - Use slow (but safe) EPP-16" - depends on SCSI_PPA || SCSI_IMM - ---help--- - EPP (Enhanced Parallel Port) is a standard for parallel ports which - allows them to act as expansion buses that can handle up to 64 - peripheral devices. - - Some parallel port chipsets are slower than their motherboard, and - so we have to control the state of the chipset's FIFO queue every - now and then to avoid data loss. This will be done if you say Y - here. - - Generally, saying Y is the safe option and slows things down a bit. - -config SCSI_IZIP_SLOW_CTR - bool "ppa/imm option - Assume slow parport control register" - depends on SCSI_PPA || SCSI_IMM - help - Some parallel ports are known to have excessive delays between - changing the parallel port control register and good data being - available on the parallel port data/status register. This option - forces a small delay (1.0 usec to be exact) after changing the - control register to let things settle out. Enabling this option may - result in a big drop in performance but some very old parallel ports - (found in 386 vintage machines) will not work properly. - - Generally, saying N is fine. - -config SCSI_NCR53C406A - tristate "NCR53c406a SCSI support" - depends on ISA && SCSI - help - This is support for the NCR53c406a SCSI host adapter. For user - configurable parameters, check out - in the kernel source. Also read the SCSI-HOWTO, available from - . - - To compile this driver as a module, choose M here: the - module will be called NCR53c406. - -config SCSI_NCR_D700 - tristate "NCR Dual 700 MCA SCSI support" - depends on MCA && SCSI - select SCSI_SPI_ATTRS - help - This is a driver for the MicroChannel Dual 700 card produced by - NCR and commonly used in 345x/35xx/4100 class machines. It always - tries to negotiate sync and uses tag command queueing. - - Unless you have an NCR manufactured machine, the chances are that - you do not have this SCSI card, so say N. - -config SCSI_LASI700 - tristate "HP Lasi SCSI support for 53c700/710" - depends on GSC && SCSI - select SCSI_SPI_ATTRS - help - This is a driver for the SCSI controller in the Lasi chip found in - many PA-RISC workstations & servers. If you do not know whether you - have a Lasi chip, it is safe to say "Y" here. - -config SCSI_SNI_53C710 - tristate "SNI RM SCSI support for 53c710" - depends on SNI_RM && SCSI - select SCSI_SPI_ATTRS - select 53C700_LE_ON_BE - help - This is a driver for the onboard SCSI controller found in older - SNI RM workstations & servers. - -config 53C700_LE_ON_BE - bool - depends on SCSI_LASI700 - default y - -config SCSI_STEX - tristate "Promise SuperTrak EX Series support" - depends on PCI && SCSI - ---help--- - This driver supports Promise SuperTrak EX series storage controllers. - - Promise provides Linux RAID configuration utility for these - controllers. Please visit to download. - - To compile this driver as a module, choose M here: the - module will be called stex. - -config 53C700_BE_BUS - bool - depends on SCSI_A4000T || SCSI_ZORRO7XX || MVME16x_SCSI || BVME6000_SCSI - default y - -config SCSI_SYM53C8XX_2 - tristate "SYM53C8XX Version 2 SCSI support" - depends on PCI && SCSI - select SCSI_SPI_ATTRS - ---help--- - This driver supports the whole NCR53C8XX/SYM53C8XX family of - PCI-SCSI controllers. It also supports the subset of LSI53C10XX - Ultra-160 controllers that are based on the SYM53C8XX SCRIPTS - language. It does not support LSI53C10XX Ultra-320 PCI-X SCSI - controllers; you need to use the Fusion MPT driver for that. - - Please read for more - information. - -config SCSI_SYM53C8XX_DMA_ADDRESSING_MODE - int "DMA addressing mode" - depends on SCSI_SYM53C8XX_2 - default "1" - ---help--- - This option only applies to PCI-SCSI chips that are PCI DAC - capable (875A, 895A, 896, 1010-33, 1010-66, 1000). - - When set to 0, the driver will program the chip to only perform - 32-bit DMA. When set to 1, the chip will be able to perform DMA - to addresses up to 1TB. When set to 2, the driver supports the - full 64-bit DMA address range, but can only address 16 segments - of 4 GB each. This limits the total addressable range to 64 GB. - - Most machines with less than 4GB of memory should use a setting - of 0 for best performance. If your machine has 4GB of memory - or more, you should set this option to 1 (the default). - - The still experimental value 2 (64 bit DMA addressing with 16 - x 4GB segments limitation) can be used on systems that require - PCI address bits past bit 39 to be set for the addressing of - memory using PCI DAC cycles. - -config SCSI_SYM53C8XX_DEFAULT_TAGS - int "Default tagged command queue depth" - depends on SCSI_SYM53C8XX_2 - default "16" - help - This is the default value of the command queue depth the - driver will announce to the generic SCSI layer for devices - that support tagged command queueing. This value can be changed - from the boot command line. This is a soft limit that cannot - exceed CONFIG_SCSI_SYM53C8XX_MAX_TAGS. - -config SCSI_SYM53C8XX_MAX_TAGS - int "Maximum number of queued commands" - depends on SCSI_SYM53C8XX_2 - default "64" - help - This option allows you to specify the maximum number of commands - that can be queued to any device, when tagged command queuing is - possible. The driver supports up to 256 queued commands per device. - This value is used as a compiled-in hard limit. - -config SCSI_SYM53C8XX_MMIO - bool "Use memory mapped IO" - depends on SCSI_SYM53C8XX_2 - default y - help - Memory mapped IO is faster than Port IO. Most people should - answer Y here, but some machines may have problems. If you have - to answer N here, please report the problem to the maintainer. - -config SCSI_IPR - tristate "IBM Power Linux RAID adapter support" - depends on PCI && SCSI && ATA - select FW_LOADER - select IRQ_POLL - ---help--- - This driver supports the IBM Power Linux family RAID adapters. - This includes IBM pSeries 5712, 5703, 5709, and 570A, as well - as IBM iSeries 5702, 5703, 5709, and 570A. - -config SCSI_IPR_TRACE - bool "enable driver internal trace" - depends on SCSI_IPR - default y - help - If you say Y here, the driver will trace all commands issued - to the adapter. Performance impact is minimal. Trace can be - dumped using /sys/bus/class/scsi_host/hostXX/trace. - -config SCSI_IPR_DUMP - bool "enable adapter dump support" - depends on SCSI_IPR - default y - help - If you say Y here, the driver will support adapter crash dump. - If you enable this support, the iprdump daemon can be used - to capture adapter failure analysis information. - -config SCSI_ZALON - tristate "Zalon SCSI support" - depends on GSC && SCSI - select SCSI_SPI_ATTRS - help - The Zalon is a GSC/HSC bus interface chip that sits between the - PA-RISC processor and the NCR 53c720 SCSI controller on C100, - C110, J200, J210 and some D, K & R-class machines. It's also - used on the add-in Bluefish, Barracuda & Shrike SCSI cards. - Say Y here if you have one of these machines or cards. - -config SCSI_NCR_Q720 - tristate "NCR Quad 720 MCA SCSI support" - depends on MCA && SCSI - select SCSI_SPI_ATTRS - help - This is a driver for the MicroChannel Quad 720 card produced by - NCR and commonly used in 345x/35xx/4100 class machines. It always - tries to negotiate sync and uses tag command queueing. - - Unless you have an NCR manufactured machine, the chances are that - you do not have this SCSI card, so say N. - -config SCSI_NCR53C8XX_DEFAULT_TAGS - int "default tagged command queue depth" - depends on SCSI_ZALON || SCSI_NCR_Q720 - default "8" - ---help--- - "Tagged command queuing" is a feature of SCSI-2 which improves - performance: the host adapter can send several SCSI commands to a - device's queue even if previous commands haven't finished yet. - Because the device is intelligent, it can optimize its operations - (like head positioning) based on its own request queue. Some SCSI - devices don't implement this properly; if you want to disable this - feature, enter 0 or 1 here (it doesn't matter which). - - The default value is 8 and should be supported by most hard disks. - This value can be overridden from the boot command line using the - 'tags' option as follows (example): - 'ncr53c8xx=tags:4/t2t3q16/t0u2q10' will set default queue depth to - 4, set queue depth to 16 for target 2 and target 3 on controller 0 - and set queue depth to 10 for target 0 / lun 2 on controller 1. - - The normal answer therefore is to go with the default 8 and to use - a boot command line option for devices that need to use a different - command queue depth. - - There is no safe option other than using good SCSI devices. - -config SCSI_NCR53C8XX_MAX_TAGS - int "maximum number of queued commands" - depends on SCSI_ZALON || SCSI_NCR_Q720 - default "32" - ---help--- - This option allows you to specify the maximum number of commands - that can be queued to any device, when tagged command queuing is - possible. The default value is 32. Minimum is 2, maximum is 64. - Modern hard disks are able to support 64 tags and even more, but - do not seem to be faster when more than 32 tags are being used. - - So, the normal answer here is to go with the default value 32 unless - you are using very large hard disks with large cache (>= 1 MB) that - are able to take advantage of more than 32 tagged commands. - - There is no safe option and the default answer is recommended. - -config SCSI_NCR53C8XX_SYNC - int "synchronous transfers frequency in MHz" - depends on SCSI_ZALON || SCSI_NCR_Q720 - default "20" - ---help--- - The SCSI Parallel Interface-2 Standard defines 5 classes of transfer - rates: FAST-5, FAST-10, FAST-20, FAST-40 and FAST-80. The numbers - are respectively the maximum data transfer rates in mega-transfers - per second for each class. For example, a FAST-20 Wide 16 device is - able to transfer data at 20 million 16 bit packets per second for a - total rate of 40 MB/s. - - You may specify 0 if you want to only use asynchronous data - transfers. This is the safest and slowest option. Otherwise, specify - a value between 5 and 80, depending on the capability of your SCSI - controller. The higher the number, the faster the data transfer. - Note that 80 should normally be ok since the driver decreases the - value automatically according to the controller's capabilities. - - Your answer to this question is ignored for controllers with NVRAM, - since the driver will get this information from the user set-up. It - also can be overridden using a boot setup option, as follows - (example): 'ncr53c8xx=sync:12' will allow the driver to negotiate - for FAST-20 synchronous data transfer (20 mega-transfers per - second). - - The normal answer therefore is not to go with the default but to - select the maximum value 80 allowing the driver to use the maximum - value supported by each controller. If this causes problems with - your SCSI devices, you should come back and decrease the value. - - There is no safe option other than using good cabling, right - terminations and SCSI conformant devices. - -config SCSI_NCR53C8XX_NO_DISCONNECT - bool "not allow targets to disconnect" - depends on (SCSI_ZALON || SCSI_NCR_Q720) && SCSI_NCR53C8XX_DEFAULT_TAGS=0 - help - This option is only provided for safety if you suspect some SCSI - device of yours to not support properly the target-disconnect - feature. In that case, you would say Y here. In general however, to - not allow targets to disconnect is not reasonable if there is more - than 1 device on a SCSI bus. The normal answer therefore is N. - -config SCSI_QLOGIC_FAS - tristate "Qlogic FAS SCSI support" - depends on ISA && SCSI - ---help--- - This is a driver for the ISA, VLB, and PCMCIA versions of the Qlogic - FastSCSI! cards as well as any other card based on the FASXX chip - (including the Control Concepts SCSI/IDE/SIO/PIO/FDC cards). - - This driver does NOT support the PCI versions of these cards. The - PCI versions are supported by the Qlogic ISP driver ("Qlogic ISP - SCSI support"), below. - - Information about this driver is contained in - . You should also read the - SCSI-HOWTO, available from - . - - To compile this driver as a module, choose M here: the - module will be called qlogicfas. - -config SCSI_QLOGIC_1280 - tristate "Qlogic QLA 1240/1x80/1x160 SCSI support" - depends on PCI && SCSI - help - Say Y if you have a QLogic ISP1240/1x80/1x160 SCSI host adapter. - - To compile this driver as a module, choose M here: the - module will be called qla1280. - -config SCSI_QLOGICPTI - tristate "PTI Qlogic, ISP Driver" - depends on SBUS && SCSI - help - This driver supports SBUS SCSI controllers from PTI or QLogic. These - controllers are known under Solaris as qpti and in the openprom as - PTI,ptisp or QLGC,isp. Note that PCI QLogic SCSI controllers are - driven by a different driver. - - To compile this driver as a module, choose M here: the - module will be called qlogicpti. - -source "drivers/scsi/qla2xxx/Kconfig" -source "drivers/scsi/qla4xxx/Kconfig" - -config SCSI_LPFC - tristate "Emulex LightPulse Fibre Channel Support" - depends on PCI && SCSI - depends on SCSI_FC_ATTRS - select CRC_T10DIF - help - This lpfc driver supports the Emulex LightPulse - Family of Fibre Channel PCI host adapters. - -config SCSI_LPFC_DEBUG_FS - bool "Emulex LightPulse Fibre Channel debugfs Support" - depends on SCSI_LPFC && DEBUG_FS - help - This makes debugging information from the lpfc driver - available via the debugfs filesystem. - -config SCSI_SIM710 - tristate "Simple 53c710 SCSI support (Compaq, NCR machines)" - depends on (EISA || MCA) && SCSI - select SCSI_SPI_ATTRS - ---help--- - This driver is for NCR53c710 based SCSI host adapters. - - It currently supports Compaq EISA cards and NCR MCA cards - -config SCSI_SYM53C416 - tristate "Symbios 53c416 SCSI support" - depends on ISA && SCSI - ---help--- - This is support for the sym53c416 SCSI host adapter, the SCSI - adapter that comes with some HP scanners. This driver requires that - the sym53c416 is configured first using some sort of PnP - configuration program (e.g. isapnp) or by a PnP aware BIOS. If you - are using isapnp then you need to compile this driver as a module - and then load it using insmod after isapnp has run. The parameters - of the configured card(s) should be passed to the driver. The format - is: - - insmod sym53c416 sym53c416=, [sym53c416_1=,] - - To compile this driver as a module, choose M here: the - module will be called sym53c416. - -config SCSI_DC395x - tristate "Tekram DC395(U/UW/F) and DC315(U) SCSI support" - depends on PCI && SCSI - ---help--- - This driver supports PCI SCSI host adapters based on the ASIC - TRM-S1040 chip, e.g Tekram DC395(U/UW/F) and DC315(U) variants. - - This driver works, but is still in experimental status. So better - have a bootable disk and a backup in case of emergency. - - Documentation can be found in . - - To compile this driver as a module, choose M here: the - module will be called dc395x. - -config SCSI_AM53C974 - tristate "Tekram DC390(T) and Am53/79C974 SCSI support (new driver)" - depends on PCI && SCSI - select SCSI_SPI_ATTRS - ---help--- - This driver supports PCI SCSI host adapters based on the Am53C974A - chip, e.g. Tekram DC390(T), DawiControl 2974 and some onboard - PCscsi/PCnet (Am53/79C974) solutions. - This is a new implementation base on the generic esp_scsi driver. - - Documentation can be found in . - - Note that this driver does NOT support Tekram DC390W/U/F, which are - based on NCR/Symbios chips. Use "NCR53C8XX SCSI support" for those. - - To compile this driver as a module, choose M here: the - module will be called am53c974. - -config SCSI_NSP32 - tristate "Workbit NinjaSCSI-32Bi/UDE support" - depends on PCI && SCSI && !64BIT - help - This is support for the Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus - SCSI host adapter. Please read the SCSI-HOWTO, available from - . - - To compile this driver as a module, choose M here: the - module will be called nsp32. - -config SCSI_WD719X - tristate "Western Digital WD7193/7197/7296 support" - depends on PCI && SCSI - select EEPROM_93CX6 - ---help--- - This is a driver for Western Digital WD7193, WD7197 and WD7296 PCI - SCSI controllers (based on WD33C296A chip). - -config SCSI_DEBUG - tristate "SCSI debugging host and device simulator" - depends on SCSI - select CRC_T10DIF - help - This pseudo driver simulates one or more hosts (SCSI initiators), - each with one or more targets, each with one or more logical units. - Defaults to one of each, creating a small RAM disk device. Many - parameters found in the /sys/bus/pseudo/drivers/scsi_debug - directory can be tweaked at run time. - See for more information. - Mainly used for testing and best as a module. If unsure, say N. - -config SCSI_MESH - tristate "MESH (Power Mac internal SCSI) support" - depends on PPC32 && PPC_PMAC && SCSI - help - Many Power Macintoshes and clones have a MESH (Macintosh Enhanced - SCSI Hardware) SCSI bus adaptor (the 7200 doesn't, but all of the - other Power Macintoshes do). Say Y to include support for this SCSI - adaptor. - - To compile this driver as a module, choose M here: the - module will be called mesh. - -config SCSI_MESH_SYNC_RATE - int "maximum synchronous transfer rate (MB/s) (0 = async)" - depends on SCSI_MESH - default "5" - help - On Power Macintoshes (and clones) where the MESH SCSI bus adaptor - drives a bus which is entirely internal to the machine (such as the - 7500, 7600, 8500, etc.), the MESH is capable of synchronous - operation at up to 10 MB/s. On machines where the SCSI bus - controlled by the MESH can have external devices connected, it is - usually rated at 5 MB/s. 5 is a safe value here unless you know the - MESH SCSI bus is internal only; in that case you can say 10. Say 0 - to disable synchronous operation. - -config SCSI_MESH_RESET_DELAY_MS - int "initial bus reset delay (ms) (0 = no reset)" - depends on SCSI_MESH - default "4000" - -config SCSI_MAC53C94 - tristate "53C94 (Power Mac external SCSI) support" - depends on PPC32 && PPC_PMAC && SCSI - help - On Power Macintoshes (and clones) with two SCSI buses, the external - SCSI bus is usually controlled by a 53C94 SCSI bus adaptor. Older - machines which only have one SCSI bus, such as the 7200, also use - the 53C94. Say Y to include support for the 53C94. - - To compile this driver as a module, choose M here: the - module will be called mac53c94. - -source "drivers/scsi/arm/Kconfig" - -config JAZZ_ESP - bool "MIPS JAZZ FAS216 SCSI support" - depends on MACH_JAZZ && SCSI - select SCSI_SPI_ATTRS - help - This is the driver for the onboard SCSI host adapter of MIPS Magnum - 4000, Acer PICA, Olivetti M700-10 and a few other identical OEM - systems. - -config A3000_SCSI - tristate "A3000 WD33C93A support" - depends on AMIGA && SCSI - help - If you have an Amiga 3000 and have SCSI devices connected to the - built-in SCSI controller, say Y. Otherwise, say N. - - To compile this driver as a module, choose M here: the - module will be called a3000. - -config A2091_SCSI - tristate "A2091/A590 WD33C93A support" - depends on ZORRO && SCSI - help - If you have a Commodore A2091 SCSI controller, say Y. Otherwise, - say N. - - To compile this driver as a module, choose M here: the - module will be called a2091. - -config GVP11_SCSI - tristate "GVP Series II WD33C93A support" - depends on ZORRO && SCSI - ---help--- - If you have a Great Valley Products Series II SCSI controller, - answer Y. Also say Y if you have a later model of GVP SCSI - controller (such as the GVP A4008 or a Combo board). Otherwise, - answer N. This driver does NOT work for the T-Rex series of - accelerators from TekMagic and GVP-M. - - To compile this driver as a module, choose M here: the - module will be called gvp11. - -config SCSI_A4000T - tristate "A4000T NCR53c710 SCSI support" - depends on AMIGA && SCSI - select SCSI_SPI_ATTRS - help - If you have an Amiga 4000T and have SCSI devices connected to the - built-in SCSI controller, say Y. Otherwise, say N. - - To compile this driver as a module, choose M here: the - module will be called a4000t. - -config SCSI_ZORRO7XX - tristate "Zorro NCR53c710 SCSI support" - depends on ZORRO && SCSI - select SCSI_SPI_ATTRS - help - Support for various NCR53c710-based SCSI controllers on Zorro - expansion boards for the Amiga. - This includes: - - the Amiga 4091 Zorro III SCSI-2 controller, - - the MacroSystem Development's WarpEngine Amiga SCSI-2 controller - (info at - ), - - the SCSI controller on the Phase5 Blizzard PowerUP 603e+ - accelerator card for the Amiga 1200, - - the SCSI controller on the GVP Turbo 040/060 accelerator. - -config ATARI_SCSI - tristate "Atari native SCSI support" - depends on ATARI && SCSI - select SCSI_SPI_ATTRS - select NVRAM - ---help--- - If you have an Atari with built-in NCR5380 SCSI controller (TT, - Falcon, ...) say Y to get it supported. Of course also, if you have - a compatible SCSI controller (e.g. for Medusa). - - To compile this driver as a module, choose M here: the - module will be called atari_scsi. - - This driver supports both styles of NCR integration into the - system: the TT style (separate DMA), and the Falcon style (via - ST-DMA, replacing ACSI). It does NOT support other schemes, like - in the Hades (without DMA). - -config MAC_SCSI - tristate "Macintosh NCR5380 SCSI" - depends on MAC && SCSI=y - select SCSI_SPI_ATTRS - help - This is the NCR 5380 SCSI controller included on most of the 68030 - based Macintoshes. If you have one of these say Y and read the - SCSI-HOWTO, available from - . - -config SCSI_MAC_ESP - tristate "Macintosh NCR53c9[46] SCSI" - depends on MAC && SCSI - select SCSI_SPI_ATTRS - help - This is the NCR 53c9x SCSI controller found on most of the 68040 - based Macintoshes. - - To compile this driver as a module, choose M here: the module - will be called mac_esp. - -config MVME147_SCSI - bool "WD33C93 SCSI driver for MVME147" - depends on MVME147 && SCSI=y - select SCSI_SPI_ATTRS - help - Support for the on-board SCSI controller on the Motorola MVME147 - single-board computer. - -config MVME16x_SCSI - tristate "NCR53C710 SCSI driver for MVME16x" - depends on MVME16x && SCSI - select SCSI_SPI_ATTRS - help - The Motorola MVME162, 166, 167, 172 and 177 boards use the NCR53C710 - SCSI controller chip. Almost everyone using one of these boards - will want to say Y to this question. - -config BVME6000_SCSI - tristate "NCR53C710 SCSI driver for BVME6000" - depends on BVME6000 && SCSI - select SCSI_SPI_ATTRS - help - The BVME4000 and BVME6000 boards from BVM Ltd use the NCR53C710 - SCSI controller chip. Almost everyone using one of these boards - will want to say Y to this question. - -config SUN3_SCSI - tristate "Sun3 NCR5380 SCSI" - depends on SUN3 && SCSI - select SCSI_SPI_ATTRS - help - This option will enable support for the OBIO (onboard io) NCR5380 - SCSI controller found in the Sun 3/50 and 3/60, as well as for - "Sun3" type VME scsi controllers also based on the NCR5380. - General Linux information on the Sun 3 series (now discontinued) - is at . - -config SUN3X_ESP - bool "Sun3x ESP SCSI" - depends on SUN3X && SCSI=y - select SCSI_SPI_ATTRS - help - The ESP was an on-board SCSI controller used on Sun 3/80 - machines. Say Y here to compile in support for it. - -config SCSI_SUNESP - tristate "Sparc ESP Scsi Driver" - depends on SBUS && SCSI - select SCSI_SPI_ATTRS - help - This is the driver for the Sun ESP SCSI host adapter. The ESP - chipset is present in most SPARC SBUS-based computers and - supports the Emulex family of ESP SCSI chips (esp100, esp100A, - esp236, fas101, fas236) as well as the Qlogic fas366 SCSI chip. - - To compile this driver as a module, choose M here: the - module will be called sun_esp. - -config ZFCP - tristate "FCP host bus adapter driver for IBM eServer zSeries" - depends on S390 && QDIO && SCSI - depends on SCSI_FC_ATTRS - help - If you want to access SCSI devices attached to your IBM eServer - zSeries by means of Fibre Channel interfaces say Y. - For details please refer to the documentation provided by IBM at - - - This driver is also available as a module. This module will be - called zfcp. If you want to compile it as a module, say M here - and read . - -config SCSI_PMCRAID - tristate "PMC SIERRA Linux MaxRAID adapter support" - depends on PCI && SCSI && NET - ---help--- - This driver supports the PMC SIERRA MaxRAID adapters. - -config SCSI_PM8001 - tristate "PMC-Sierra SPC 8001 SAS/SATA Based Host Adapter driver" - depends on PCI && SCSI - select SCSI_SAS_LIBSAS - help - This driver supports PMC-Sierra PCIE SAS/SATA 8x6G SPC 8001 chip - based host adapters. - -config SCSI_BFA_FC - tristate "Brocade BFA Fibre Channel Support" - depends on PCI && SCSI - depends on SCSI_FC_ATTRS - help - This bfa driver supports all Brocade PCIe FC/FCOE host adapters. - - To compile this driver as a module, choose M here. The module will - be called bfa. - -config SCSI_VIRTIO - tristate "virtio-scsi support" - depends on VIRTIO - help - This is the virtual HBA driver for virtio. If the kernel will - be used in a virtual machine, say Y or M. - -source "drivers/scsi/csiostor/Kconfig" - -endif # SCSI_LOWLEVEL - -source "drivers/scsi/pcmcia/Kconfig" - -source "drivers/scsi/device_handler/Kconfig" - -source "drivers/scsi/osd/Kconfig" - -endmenu diff --git a/src/linux/drivers/scsi/aic7xxx/.gitignore b/src/linux/drivers/scsi/aic7xxx/.gitignore deleted file mode 100644 index b8ee24d..0000000 --- a/src/linux/drivers/scsi/aic7xxx/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -aic79xx_reg.h -aic79xx_reg_print.c -aic79xx_seq.h -aic7xxx_reg.h -aic7xxx_reg_print.c -aic7xxx_seq.h diff --git a/src/linux/drivers/scsi/aic7xxx/Kconfig.aic79xx b/src/linux/drivers/scsi/aic7xxx/Kconfig.aic79xx deleted file mode 100644 index 3b3d599..0000000 --- a/src/linux/drivers/scsi/aic7xxx/Kconfig.aic79xx +++ /dev/null @@ -1,85 +0,0 @@ -# -# AIC79XX 2.5.X Kernel configuration File. -# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic79xx#4 $ -# -config SCSI_AIC79XX - tristate "Adaptec AIC79xx U320 support" - depends on PCI && SCSI - select SCSI_SPI_ATTRS - help - This driver supports all of Adaptec's Ultra 320 PCI-X - based SCSI controllers. - -config AIC79XX_CMDS_PER_DEVICE - int "Maximum number of TCQ commands per device" - depends on SCSI_AIC79XX - default "32" - ---help--- - Specify the number of commands you would like to allocate per SCSI - device when Tagged Command Queueing (TCQ) is enabled on that device. - - This is an upper bound value for the number of tagged transactions - to be used for any device. The aic7xxx driver will automatically - vary this number based on device behavior. For devices with a - fixed maximum, the driver will eventually lock to this maximum - and display a console message indicating this value. - - Due to resource allocation issues in the Linux SCSI mid-layer, using - a high number of commands per device may result in memory allocation - failures when many devices are attached to the system. For this reason, - the default is set to 32. Higher values may result in higher performance - on some devices. The upper bound is 253. 0 disables tagged queueing. - - Per device tag depth can be controlled via the kernel command line - "tag_info" option. See Documentation/scsi/aic79xx.txt for details. - -config AIC79XX_RESET_DELAY_MS - int "Initial bus reset delay in milli-seconds" - depends on SCSI_AIC79XX - default "5000" - ---help--- - The number of milliseconds to delay after an initial bus reset. - The bus settle delay following all error recovery actions is - dictated by the SCSI layer and is not affected by this value. - - Default: 5000 (5 seconds) - -config AIC79XX_BUILD_FIRMWARE - bool "Build Adapter Firmware with Kernel Build" - depends on SCSI_AIC79XX && !PREVENT_FIRMWARE_BUILD - help - This option should only be enabled if you are modifying the firmware - source to the aic79xx driver and wish to have the generated firmware - include files updated during a normal kernel build. The assembler - for the firmware requires lex and yacc or their equivalents, as well - as the db v1 library. You may have to install additional packages - or modify the assembler Makefile or the files it includes if your - build environment is different than that of the author. - -config AIC79XX_DEBUG_ENABLE - bool "Compile in Debugging Code" - depends on SCSI_AIC79XX - default y - help - Compile in aic79xx debugging code that can be useful in diagnosing - driver errors. - -config AIC79XX_DEBUG_MASK - int "Debug code enable mask (16383 for all debugging)" - depends on SCSI_AIC79XX - default "0" - help - Bit mask of debug options that is only valid if the - CONFIG_AIC79XX_DEBUG_ENABLE option is enabled. The bits in this mask - are defined in the drivers/scsi/aic7xxx/aic79xx.h - search for the - variable ahd_debug in that file to find them. - -config AIC79XX_REG_PRETTY_PRINT - bool "Decode registers during diagnostics" - depends on SCSI_AIC79XX - default y - help - Compile in register value tables for the output of expanded register - contents in diagnostics. This make it much easier to understand debug - output without having to refer to a data book and/or the aic7xxx.reg - file. diff --git a/src/linux/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/src/linux/drivers/scsi/aic7xxx/Kconfig.aic7xxx deleted file mode 100644 index 55ac55e..0000000 --- a/src/linux/drivers/scsi/aic7xxx/Kconfig.aic7xxx +++ /dev/null @@ -1,90 +0,0 @@ -# -# AIC7XXX and AIC79XX 2.5.X Kernel configuration File. -# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic7xxx#7 $ -# -config SCSI_AIC7XXX - tristate "Adaptec AIC7xxx Fast -> U160 support (New Driver)" - depends on (PCI || EISA) && SCSI - select SCSI_SPI_ATTRS - ---help--- - This driver supports all of Adaptec's Fast through Ultra 160 PCI - based SCSI controllers as well as the aic7770 based EISA and VLB - SCSI controllers (the 274x and 284x series). For AAA and ARO based - configurations, only SCSI functionality is provided. - - To compile this driver as a module, choose M here: the - module will be called aic7xxx. - -config AIC7XXX_CMDS_PER_DEVICE - int "Maximum number of TCQ commands per device" - depends on SCSI_AIC7XXX - default "32" - ---help--- - Specify the number of commands you would like to allocate per SCSI - device when Tagged Command Queueing (TCQ) is enabled on that device. - - This is an upper bound value for the number of tagged transactions - to be used for any device. The aic7xxx driver will automatically - vary this number based on device behavior. For devices with a - fixed maximum, the driver will eventually lock to this maximum - and display a console message indicating this value. - - Due to resource allocation issues in the Linux SCSI mid-layer, using - a high number of commands per device may result in memory allocation - failures when many devices are attached to the system. For this reason, - the default is set to 32. Higher values may result in higher performance - on some devices. The upper bound is 253. 0 disables tagged queueing. - - Per device tag depth can be controlled via the kernel command line - "tag_info" option. See Documentation/scsi/aic7xxx.txt for details. - -config AIC7XXX_RESET_DELAY_MS - int "Initial bus reset delay in milli-seconds" - depends on SCSI_AIC7XXX - default "5000" - ---help--- - The number of milliseconds to delay after an initial bus reset. - The bus settle delay following all error recovery actions is - dictated by the SCSI layer and is not affected by this value. - - Default: 5000 (5 seconds) - -config AIC7XXX_BUILD_FIRMWARE - bool "Build Adapter Firmware with Kernel Build" - depends on SCSI_AIC7XXX && !PREVENT_FIRMWARE_BUILD - help - This option should only be enabled if you are modifying the firmware - source to the aic7xxx driver and wish to have the generated firmware - include files updated during a normal kernel build. The assembler - for the firmware requires lex and yacc or their equivalents, as well - as the db v1 library. You may have to install additional packages - or modify the assembler Makefile or the files it includes if your - build environment is different than that of the author. - -config AIC7XXX_DEBUG_ENABLE - bool "Compile in Debugging Code" - depends on SCSI_AIC7XXX - default y - help - Compile in aic7xxx debugging code that can be useful in diagnosing - driver errors. - -config AIC7XXX_DEBUG_MASK - int "Debug code enable mask (2047 for all debugging)" - depends on SCSI_AIC7XXX - default "0" - help - Bit mask of debug options that is only valid if the - CONFIG_AIC7XXX_DEBUG_ENABLE option is enabled. The bits in this mask - are defined in the drivers/scsi/aic7xxx/aic7xxx.h - search for the - variable ahc_debug in that file to find them. - -config AIC7XXX_REG_PRETTY_PRINT - bool "Decode registers during diagnostics" - depends on SCSI_AIC7XXX - default y - help - Compile in register value tables for the output of expanded register - contents in diagnostics. This make it much easier to understand debug - output without having to refer to a data book and/or the aic7xxx.reg - file. diff --git a/src/linux/drivers/scsi/aic94xx/Kconfig b/src/linux/drivers/scsi/aic94xx/Kconfig deleted file mode 100644 index c83fe75..0000000 --- a/src/linux/drivers/scsi/aic94xx/Kconfig +++ /dev/null @@ -1,42 +0,0 @@ -# -# Kernel configuration file for aic94xx SAS/SATA driver. -# -# Copyright (c) 2005 Adaptec, Inc. All rights reserved. -# Copyright (c) 2005 Luben Tuikov -# -# This file is licensed under GPLv2. -# -# This file is part of the aic94xx driver. -# -# The aic94xx driver is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 of the -# License. -# -# The aic94xx driver is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Aic94xx Driver; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# -# - -config SCSI_AIC94XX - tristate "Adaptec AIC94xx SAS/SATA support" - depends on PCI - select SCSI_SAS_LIBSAS - select FW_LOADER - help - This driver supports Adaptec's SAS/SATA 3Gb/s 64 bit PCI-X - AIC94xx chip based host adapters. - -config AIC94XX_DEBUG - bool "Compile in debug mode" - default y - depends on SCSI_AIC94XX - help - Compiles the aic94xx driver in debug mode. In debug mode, - the driver prints some messages to the console. diff --git a/src/linux/drivers/scsi/arm/Kconfig b/src/linux/drivers/scsi/arm/Kconfig deleted file mode 100644 index cfd172a..0000000 --- a/src/linux/drivers/scsi/arm/Kconfig +++ /dev/null @@ -1,84 +0,0 @@ -# -# SCSI driver configuration for Acorn -# -config SCSI_ACORNSCSI_3 - tristate "Acorn SCSI card (aka30) support" - depends on ARCH_ACORN && SCSI - select SCSI_SPI_ATTRS - help - This enables support for the Acorn SCSI card (aka30). If you have an - Acorn system with one of these, say Y. If unsure, say N. - -config SCSI_ACORNSCSI_TAGGED_QUEUE - bool "Support SCSI 2 Tagged queueing" - depends on SCSI_ACORNSCSI_3 - help - Say Y here to enable tagged queuing support on the Acorn SCSI card. - - This is a feature of SCSI-2 which improves performance: the host - adapter can send several SCSI commands to a device's queue even if - previous commands haven't finished yet. Some SCSI devices don't - implement this properly, so the safe answer is N. - -config SCSI_ACORNSCSI_SYNC - bool "Support SCSI 2 Synchronous Transfers" - depends on SCSI_ACORNSCSI_3 - help - Say Y here to enable synchronous transfer negotiation with all - targets on the Acorn SCSI card. - - In general, this improves performance; however some SCSI devices - don't implement it properly, so the safe answer is N. - -config SCSI_ARXESCSI - tristate "ARXE SCSI support" - depends on ARCH_ACORN && SCSI - help - Around 1991, Arxe Systems Limited released a high density floppy - disc interface for the Acorn Archimedes range, to allow the use of - HD discs from the then new A5000 on earlier models. This interface - was either sold on its own or with an integral SCSI controller. - Technical details on this NCR53c94-based device are available at - - Say Y here to compile in support for the SCSI controller. - -config SCSI_CUMANA_2 - tristate "CumanaSCSI II support" - depends on ARCH_ACORN && SCSI - help - This enables support for the Cumana SCSI II card. If you have an - Acorn system with one of these, say Y. If unsure, say N. - -config SCSI_EESOXSCSI - tristate "EESOX support" - depends on ARCH_ACORN && SCSI - help - This enables support for the EESOX SCSI card. If you have an Acorn - system with one of these, say Y, otherwise say N. - -config SCSI_POWERTECSCSI - tristate "PowerTec support" - depends on ARCH_ACORN && SCSI - help - This enables support for the Powertec SCSI card on Acorn systems. If - you have one of these, say Y. If unsure, say N. - -comment "The following drivers are not fully supported" - depends on ARCH_ACORN - -config SCSI_CUMANA_1 - tristate "CumanaSCSI I support" - depends on ARCH_ACORN && SCSI - select SCSI_SPI_ATTRS - help - This enables support for the Cumana SCSI I card. If you have an - Acorn system with one of these, say Y. If unsure, say N. - -config SCSI_OAK1 - tristate "Oak SCSI support" - depends on ARCH_ACORN && SCSI - select SCSI_SPI_ATTRS - help - This enables support for the Oak SCSI card. If you have an Acorn - system with one of these, say Y. If unsure, say N. - diff --git a/src/linux/drivers/scsi/be2iscsi/Kconfig b/src/linux/drivers/scsi/be2iscsi/Kconfig deleted file mode 100644 index bad5f32..0000000 --- a/src/linux/drivers/scsi/be2iscsi/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config BE2ISCSI - tristate "Emulex 10Gbps iSCSI - BladeEngine 2" - depends on PCI && SCSI && NET - select SCSI_ISCSI_ATTRS - select ISCSI_BOOT_SYSFS - select IRQ_POLL - - help - This driver implements the iSCSI functionality for Emulex - 10Gbps Storage adapter - BladeEngine 2. diff --git a/src/linux/drivers/scsi/bnx2fc/Kconfig b/src/linux/drivers/scsi/bnx2fc/Kconfig deleted file mode 100644 index d401a09..0000000 --- a/src/linux/drivers/scsi/bnx2fc/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config SCSI_BNX2X_FCOE - tristate "QLogic FCoE offload support" - depends on PCI - depends on (IPV6 || IPV6=n) - depends on LIBFC - depends on LIBFCOE - select NETDEVICES - select ETHERNET - select NET_VENDOR_BROADCOM - select CNIC - ---help--- - This driver supports FCoE offload for the QLogic devices. diff --git a/src/linux/drivers/scsi/bnx2i/Kconfig b/src/linux/drivers/scsi/bnx2i/Kconfig deleted file mode 100644 index ba30ff8..0000000 --- a/src/linux/drivers/scsi/bnx2i/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config SCSI_BNX2_ISCSI - tristate "QLogic NetXtreme II iSCSI support" - depends on NET - depends on PCI - depends on (IPV6 || IPV6=n) - select SCSI_ISCSI_ATTRS - select NETDEVICES - select ETHERNET - select NET_VENDOR_BROADCOM - select CNIC - ---help--- - This driver supports iSCSI offload for the QLogic NetXtreme II - devices. diff --git a/src/linux/drivers/scsi/csiostor/Kconfig b/src/linux/drivers/scsi/csiostor/Kconfig deleted file mode 100644 index 7c7e508..0000000 --- a/src/linux/drivers/scsi/csiostor/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -config SCSI_CHELSIO_FCOE - tristate "Chelsio Communications FCoE support" - depends on PCI && SCSI - depends on SCSI_FC_ATTRS - select FW_LOADER - help - This driver supports FCoE Offload functionality over - Chelsio T4-based 10Gb Converged Network Adapters. - - For general information about Chelsio and our products, visit - our website at . - - For customer support, please visit our customer support page at - . - - Please send feedback to . - - To compile this driver as a module choose M here; the module - will be called csiostor. diff --git a/src/linux/drivers/scsi/cxgbi/Kconfig b/src/linux/drivers/scsi/cxgbi/Kconfig deleted file mode 100644 index 17eb5d5..0000000 --- a/src/linux/drivers/scsi/cxgbi/Kconfig +++ /dev/null @@ -1,2 +0,0 @@ -source "drivers/scsi/cxgbi/cxgb3i/Kconfig" -source "drivers/scsi/cxgbi/cxgb4i/Kconfig" diff --git a/src/linux/drivers/scsi/cxgbi/cxgb3i/Kconfig b/src/linux/drivers/scsi/cxgbi/cxgb3i/Kconfig deleted file mode 100644 index f68c871..0000000 --- a/src/linux/drivers/scsi/cxgbi/cxgb3i/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config SCSI_CXGB3_ISCSI - tristate "Chelsio T3 iSCSI support" - depends on PCI && INET && (IPV6 || IPV6=n) - select NETDEVICES - select ETHERNET - select NET_VENDOR_CHELSIO - select CHELSIO_T3 - select CHELSIO_LIB - select SCSI_ISCSI_ATTRS - ---help--- - This driver supports iSCSI offload for the Chelsio T3 devices. diff --git a/src/linux/drivers/scsi/cxgbi/cxgb4i/Kconfig b/src/linux/drivers/scsi/cxgbi/cxgb4i/Kconfig deleted file mode 100644 index 594f593..0000000 --- a/src/linux/drivers/scsi/cxgbi/cxgb4i/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config SCSI_CXGB4_ISCSI - tristate "Chelsio T4 iSCSI support" - depends on PCI && INET && (IPV6 || IPV6=n) - select NETDEVICES - select ETHERNET - select NET_VENDOR_CHELSIO - select CHELSIO_T4 - select CHELSIO_LIB - select SCSI_ISCSI_ATTRS - ---help--- - This driver supports iSCSI offload for the Chelsio T4 devices. diff --git a/src/linux/drivers/scsi/cxlflash/Kconfig b/src/linux/drivers/scsi/cxlflash/Kconfig deleted file mode 100644 index c052104..0000000 --- a/src/linux/drivers/scsi/cxlflash/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -# -# IBM CXL-attached Flash Accelerator SCSI Driver -# - -config CXLFLASH - tristate "Support for IBM CAPI Flash" - depends on PCI && SCSI && CXL && EEH - default m - help - Allows CAPI Accelerated IO to Flash - If unsure, say N. diff --git a/src/linux/drivers/scsi/device_handler/Kconfig b/src/linux/drivers/scsi/device_handler/Kconfig deleted file mode 100644 index 0b331c9..0000000 --- a/src/linux/drivers/scsi/device_handler/Kconfig +++ /dev/null @@ -1,40 +0,0 @@ -# -# SCSI Device Handler configuration -# - -menuconfig SCSI_DH - bool "SCSI Device Handlers" - depends on SCSI - default n - help - SCSI Device Handlers provide device specific support for - devices utilized in multipath configurations. Say Y here to - select support for specific hardware. - -config SCSI_DH_RDAC - tristate "LSI RDAC Device Handler" - depends on SCSI_DH && SCSI - help - If you have a LSI RDAC select y. Otherwise, say N. - -config SCSI_DH_HP_SW - tristate "HP/COMPAQ MSA Device Handler" - depends on SCSI_DH && SCSI - help - If you have a HP/COMPAQ MSA device that requires START_STOP to - be sent to start it and cannot upgrade the firmware then select y. - Otherwise, say N. - -config SCSI_DH_EMC - tristate "EMC CLARiiON Device Handler" - depends on SCSI_DH && SCSI - help - If you have a EMC CLARiiON select y. Otherwise, say N. - -config SCSI_DH_ALUA - tristate "SPC-3 ALUA Device Handler" - depends on SCSI_DH && SCSI - help - SCSI Device handler for generic SPC-3 Asymmetric Logical Unit - Access (ALUA). - diff --git a/src/linux/drivers/scsi/esas2r/Kconfig b/src/linux/drivers/scsi/esas2r/Kconfig deleted file mode 100644 index 78fdbfd..0000000 --- a/src/linux/drivers/scsi/esas2r/Kconfig +++ /dev/null @@ -1,5 +0,0 @@ -config SCSI_ESAS2R - tristate "ATTO Technology's ExpressSAS RAID adapter driver" - depends on PCI && SCSI - ---help--- - This driver supports the ATTO ExpressSAS R6xx SAS/SATA RAID controllers. diff --git a/src/linux/drivers/scsi/hisi_sas/Kconfig b/src/linux/drivers/scsi/hisi_sas/Kconfig deleted file mode 100644 index d1dd161..0000000 --- a/src/linux/drivers/scsi/hisi_sas/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config SCSI_HISI_SAS - tristate "HiSilicon SAS" - depends on HAS_DMA && HAS_IOMEM - depends on ARM64 || COMPILE_TEST - select SCSI_SAS_LIBSAS - select BLK_DEV_INTEGRITY - help - This driver supports HiSilicon's SAS HBA diff --git a/src/linux/drivers/scsi/libsas/Kconfig b/src/linux/drivers/scsi/libsas/Kconfig deleted file mode 100644 index 9dafe64..0000000 --- a/src/linux/drivers/scsi/libsas/Kconfig +++ /dev/null @@ -1,48 +0,0 @@ -# -# Kernel configuration file for the SAS Class -# -# Copyright (C) 2005 Adaptec, Inc. All rights reserved. -# Copyright (C) 2005 Luben Tuikov -# -# This file is licensed under GPLv2. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation; version 2 of the -# License. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 -# USA -# - -config SCSI_SAS_LIBSAS - tristate "SAS Domain Transport Attributes" - depends on SCSI - select SCSI_SAS_ATTRS - help - This provides transport specific helpers for SAS drivers which - use the domain device construct (like the aic94xxx). - -config SCSI_SAS_ATA - bool "ATA support for libsas (requires libata)" - depends on SCSI_SAS_LIBSAS - depends on ATA = y || ATA = SCSI_SAS_LIBSAS - help - Builds in ATA support into libsas. Will necessitate - the loading of libata along with libsas. - -config SCSI_SAS_HOST_SMP - bool "Support for SMP interpretation for SAS hosts" - default y - depends on SCSI_SAS_LIBSAS - help - Allows sas hosts to receive SMP frames. Selecting this - option builds an SMP interpreter into libsas. Say - N here if you want to save the few kb this consumes. diff --git a/src/linux/drivers/scsi/megaraid/Kconfig.megaraid b/src/linux/drivers/scsi/megaraid/Kconfig.megaraid deleted file mode 100644 index 17419e3..0000000 --- a/src/linux/drivers/scsi/megaraid/Kconfig.megaraid +++ /dev/null @@ -1,85 +0,0 @@ -config MEGARAID_NEWGEN - bool "LSI Logic New Generation RAID Device Drivers" - depends on PCI && SCSI - help - LSI Logic RAID Device Drivers - -config MEGARAID_MM - tristate "LSI Logic Management Module (New Driver)" - depends on PCI && SCSI && MEGARAID_NEWGEN - help - Management Module provides ioctl, sysfs support for LSI Logic - RAID controllers. - To compile this driver as a module, choose M here: the - module will be called megaraid_mm - - -config MEGARAID_MAILBOX - tristate "LSI Logic MegaRAID Driver (New Driver)" - depends on PCI && SCSI && MEGARAID_MM - help - List of supported controllers - - OEM Product Name VID :DID :SVID:SSID - --- ------------ ---- ---- ---- ---- - Dell PERC3/QC 101E:1960:1028:0471 - Dell PERC3/DC 101E:1960:1028:0493 - Dell PERC3/SC 101E:1960:1028:0475 - Dell PERC3/Di 1028:000E:1028:0123 - Dell PERC4/SC 1000:1960:1028:0520 - Dell PERC4/DC 1000:1960:1028:0518 - Dell PERC4/QC 1000:0407:1028:0531 - Dell PERC4/Di 1028:000F:1028:014A - Dell PERC 4e/Si 1028:0013:1028:016c - Dell PERC 4e/Di 1028:0013:1028:016d - Dell PERC 4e/Di 1028:0013:1028:016e - Dell PERC 4e/Di 1028:0013:1028:016f - Dell PERC 4e/Di 1028:0013:1028:0170 - Dell PERC 4e/DC 1000:0408:1028:0002 - Dell PERC 4e/SC 1000:0408:1028:0001 - LSI MegaRAID SCSI 320-0 1000:1960:1000:A520 - LSI MegaRAID SCSI 320-1 1000:1960:1000:0520 - LSI MegaRAID SCSI 320-2 1000:1960:1000:0518 - LSI MegaRAID SCSI 320-0X 1000:0407:1000:0530 - LSI MegaRAID SCSI 320-2X 1000:0407:1000:0532 - LSI MegaRAID SCSI 320-4X 1000:0407:1000:0531 - LSI MegaRAID SCSI 320-1E 1000:0408:1000:0001 - LSI MegaRAID SCSI 320-2E 1000:0408:1000:0002 - LSI MegaRAID SATA 150-4 1000:1960:1000:4523 - LSI MegaRAID SATA 150-6 1000:1960:1000:0523 - LSI MegaRAID SATA 300-4X 1000:0409:1000:3004 - LSI MegaRAID SATA 300-8X 1000:0409:1000:3008 - INTEL RAID Controller SRCU42X 1000:0407:8086:0532 - INTEL RAID Controller SRCS16 1000:1960:8086:0523 - INTEL RAID Controller SRCU42E 1000:0408:8086:0002 - INTEL RAID Controller SRCZCRX 1000:0407:8086:0530 - INTEL RAID Controller SRCS28X 1000:0409:8086:3008 - INTEL RAID Controller SROMBU42E 1000:0408:8086:3431 - INTEL RAID Controller SROMBU42E 1000:0408:8086:3499 - INTEL RAID Controller SRCU51L 1000:1960:8086:0520 - FSC MegaRAID PCI Express ROMB 1000:0408:1734:1065 - ACER MegaRAID ROMB-2E 1000:0408:1025:004D - NEC MegaRAID PCI Express ROMB 1000:0408:1033:8287 - - To compile this driver as a module, choose M here: the - module will be called megaraid_mbox - -config MEGARAID_LEGACY - tristate "LSI Logic Legacy MegaRAID Driver" - depends on PCI && SCSI - help - This driver supports the LSI MegaRAID 418, 428, 438, 466, 762, 490 - and 467 SCSI host adapters. This driver also support the all U320 - RAID controllers - - To compile this driver as a module, choose M here: the - module will be called megaraid - -config MEGARAID_SAS - tristate "LSI Logic MegaRAID SAS RAID Module" - depends on PCI && SCSI - help - Module for LSI Logic's SAS based RAID controllers. - To compile this driver as a module, choose 'm' here. - Module will be called megaraid_sas - diff --git a/src/linux/drivers/scsi/mpt3sas/Kconfig b/src/linux/drivers/scsi/mpt3sas/Kconfig deleted file mode 100644 index b736dbc..0000000 --- a/src/linux/drivers/scsi/mpt3sas/Kconfig +++ /dev/null @@ -1,82 +0,0 @@ -# -# Kernel configuration file for the MPT3SAS -# -# This code is based on drivers/scsi/mpt3sas/Kconfig -# Copyright (C) 2012-2014 LSI Corporation -# (mailto:DL-MPTFusionLinux@lsi.com) - -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# NO WARRANTY -# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -# solely responsible for determining the appropriateness of using and -# distributing the Program and assumes all risks associated with its -# exercise of rights under this Agreement, including but not limited to -# the risks and costs of program errors, damage to or loss of data, -# programs or equipment, and unavailability or interruption of operations. - -# DISCLAIMER OF LIABILITY -# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -# USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -# USA. - -config SCSI_MPT3SAS - tristate "LSI MPT Fusion SAS 3.0 & SAS 2.0 Device Driver" - depends on PCI && SCSI - select SCSI_SAS_ATTRS - select RAID_ATTRS - ---help--- - This driver supports PCI-Express SAS 12Gb/s Host Adapters. - -config SCSI_MPT2SAS_MAX_SGE - int "LSI MPT Fusion SAS 2.0 Max number of SG Entries (16 - 256)" - depends on PCI && SCSI && SCSI_MPT3SAS - default "128" - range 16 256 - ---help--- - This option allows you to specify the maximum number of scatter- - gather entries per I/O. The driver default is 128, which matches - MAX_PHYS_SEGMENTS in most kernels. However in SuSE kernels this - can be 256. However, it may decreased down to 16. Decreasing this - parameter will reduce memory requirements on a per controller instance. - -config SCSI_MPT3SAS_MAX_SGE - int "LSI MPT Fusion SAS 3.0 Max number of SG Entries (16 - 256)" - depends on PCI && SCSI && SCSI_MPT3SAS - default "128" - range 16 256 - ---help--- - This option allows you to specify the maximum number of scatter- - gather entries per I/O. The driver default is 128, which matches - MAX_PHYS_SEGMENTS in most kernels. However in SuSE kernels this - can be 256. However, it may decreased down to 16. Decreasing this - parameter will reduce memory requirements on a per controller instance. - -config SCSI_MPT2SAS - tristate "Legacy MPT2SAS config option" - default n - select SCSI_MPT3SAS - depends on PCI && SCSI - ---help--- - Dummy config option for backwards compatiblity: configure the MPT3SAS - driver instead. diff --git a/src/linux/drivers/scsi/mvsas/Kconfig b/src/linux/drivers/scsi/mvsas/Kconfig deleted file mode 100644 index 78f7e20..0000000 --- a/src/linux/drivers/scsi/mvsas/Kconfig +++ /dev/null @@ -1,50 +0,0 @@ -# -# Kernel configuration file for 88SE64XX/88SE94XX SAS/SATA driver. -# -# Copyright 2007 Red Hat, Inc. -# Copyright 2008 Marvell. -# Copyright 2009-2011 Marvell. -# -# This file is licensed under GPLv2. -# -# This file is part of the 88SE64XX/88SE94XX driver. -# -# The 88SE64XX/88SE94XX driver is free software; you can redistribute -# it and/or modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; version 2 of the -# License. -# -# The 88SE64XX/88SE94XX driver is distributed in the hope that it will be -# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with 88SE64XX/88SE94XX Driver; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# -# - -config SCSI_MVSAS - tristate "Marvell 88SE64XX/88SE94XX SAS/SATA support" - depends on PCI - select SCSI_SAS_LIBSAS - select FW_LOADER - help - This driver supports Marvell's SAS/SATA 3Gb/s PCI-E 88SE64XX and 6Gb/s - PCI-E 88SE94XX chip based host adapters. - -config SCSI_MVSAS_DEBUG - bool "Compile in debug mode" - default y - depends on SCSI_MVSAS - help - Compiles the 88SE64XX/88SE94XX driver in debug mode. In debug mode, - the driver prints some messages to the console. -config SCSI_MVSAS_TASKLET - bool "Support for interrupt tasklet" - default n - depends on SCSI_MVSAS - help - Compiles the 88SE64xx/88SE94xx driver in interrupt tasklet mode.In this mode, - the interrupt will schedule a tasklet. diff --git a/src/linux/drivers/scsi/osd/Kconfig b/src/linux/drivers/scsi/osd/Kconfig deleted file mode 100644 index 347cc5e..0000000 --- a/src/linux/drivers/scsi/osd/Kconfig +++ /dev/null @@ -1,49 +0,0 @@ -# -# Kernel configuration file for the OSD scsi protocol -# -# Copyright (C) 2008 Panasas Inc. All rights reserved. -# -# Authors: -# Boaz Harrosh -# Benny Halevy -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public version 2 License as -# published by the Free Software Foundation -# -config SCSI_OSD_INITIATOR - tristate "OSD-Initiator library" - depends on SCSI - help - Enable the OSD-Initiator library (libosd.ko). - NOTE: You must also select CRYPTO_SHA1 + CRYPTO_HMAC and their - dependencies - -config SCSI_OSD_ULD - tristate "OSD Upper Level driver" - depends on SCSI_OSD_INITIATOR - help - Build a SCSI upper layer driver that exports /dev/osdX devices - to user-mode for testing and controlling OSD devices. It is also - needed by exofs, for mounting an OSD based file system. - -config SCSI_OSD_DPRINT_SENSE - int "(0-2) When sense is returned, DEBUG print all sense descriptors" - default 1 - depends on SCSI_OSD_INITIATOR - help - When a CHECK_CONDITION status is returned from a target, and a - sense-buffer is retrieved, turning this on will dump a full - sense-decoding message. Setting to 2 will also print recoverable - errors that might be regularly returned for some filesystem - operations. - -config SCSI_OSD_DEBUG - bool "Compile All OSD modules with lots of DEBUG prints" - default n - depends on SCSI_OSD_INITIATOR - help - OSD Code is populated with lots of OSD_DEBUG(..) printouts to - dmesg. Enable this if you found a bug and you want to help us - track the problem (see also MAINTAINERS). Setting this will also - force SCSI_OSD_DPRINT_SENSE=2. diff --git a/src/linux/drivers/scsi/pcmcia/Kconfig b/src/linux/drivers/scsi/pcmcia/Kconfig deleted file mode 100644 index ecc855c..0000000 --- a/src/linux/drivers/scsi/pcmcia/Kconfig +++ /dev/null @@ -1,83 +0,0 @@ -# -# PCMCIA SCSI adapter configuration -# - -menuconfig SCSI_LOWLEVEL_PCMCIA - bool "PCMCIA SCSI adapter support" - depends on SCSI!=n && PCMCIA!=n - -# drivers have problems when build in, so require modules -if SCSI_LOWLEVEL_PCMCIA && SCSI && PCMCIA && m - -config PCMCIA_AHA152X - tristate "Adaptec AHA152X PCMCIA support" - select SCSI_SPI_ATTRS - help - Say Y here if you intend to attach this type of PCMCIA SCSI host - adapter to your computer. - - To compile this driver as a module, choose M here: the - module will be called aha152x_cs. - -config PCMCIA_FDOMAIN - tristate "Future Domain PCMCIA support" - help - Say Y here if you intend to attach this type of PCMCIA SCSI host - adapter to your computer. - - To compile this driver as a module, choose M here: the - module will be called fdomain_cs. - -config PCMCIA_NINJA_SCSI - tristate "NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support" - depends on !64BIT - help - If you intend to attach this type of PCMCIA SCSI host adapter to - your computer, say Y here and read - . - - Supported cards: - - NinjaSCSI-3: (version string: "WBT","NinjaSCSI-3","R1.0") - IO-DATA PCSC-FP - ALPHA DATA AD-PCS201 - CyQ've SFC-201 - LOGITECH LPM-SCSI2E - Pioneer PCR-PR24's card - I-O DATA CDPS-PX24's card (PCSC-F) - Panasonic KXL-RW10AN CD-RW's card - etc. - - NinjaSCSI-32Bit (in 16bit mode): - [Workbit (version string: "WORKBIT","UltraNinja-16","1")] - Jazz SCP050 - [I-O DATA (OEM) (version string: "IO DATA","CBSC16 ","1")] - I-O DATA CBSC-II - [Kyusyu Matsushita Kotobuki (OEM) - (version string: "KME ","SCSI-CARD-001","1")] - KME KXL-820AN's card - HP M820e CDRW's card - etc. - - To compile this driver as a module, choose M here: the - module will be called nsp_cs. - -config PCMCIA_QLOGIC - tristate "Qlogic PCMCIA support" - help - Say Y here if you intend to attach this type of PCMCIA SCSI host - adapter to your computer. - - To compile this driver as a module, choose M here: the - module will be called qlogic_cs. - -config PCMCIA_SYM53C500 - tristate "Symbios 53c500 PCMCIA support" - help - Say Y here if you have a New Media Bus Toaster or other PCMCIA - SCSI adapter based on the Symbios 53c500 controller. - - To compile this driver as a module, choose M here: the - module will be called sym53c500_cs. - -endif # SCSI_LOWLEVEL_PCMCIA diff --git a/src/linux/drivers/scsi/qla2xxx/Kconfig b/src/linux/drivers/scsi/qla2xxx/Kconfig deleted file mode 100644 index 67c0d5a..0000000 --- a/src/linux/drivers/scsi/qla2xxx/Kconfig +++ /dev/null @@ -1,47 +0,0 @@ -config SCSI_QLA_FC - tristate "QLogic QLA2XXX Fibre Channel Support" - depends on PCI && SCSI - depends on SCSI_FC_ATTRS - select FW_LOADER - ---help--- - This qla2xxx driver supports all QLogic Fibre Channel - PCI and PCIe host adapters. - - By default, firmware for the ISP parts will be loaded - via the Firmware Loader interface. - - ISP Firmware Filename - ---------- ----------------- - 21xx ql2100_fw.bin - 22xx ql2200_fw.bin - 2300, 2312, 6312 ql2300_fw.bin - 2322, 6322 ql2322_fw.bin - 24xx, 54xx ql2400_fw.bin - 25xx ql2500_fw.bin - - Upon request, the driver caches the firmware image until - the driver is unloaded. - - Firmware images can be retrieved from: - - http://ldriver.qlogic.com/firmware/ - - They are also included in the linux-firmware tree as well. - -config TCM_QLA2XXX - tristate "TCM_QLA2XXX fabric module for QLogic 24xx+ series target mode HBAs" - depends on SCSI_QLA_FC && TARGET_CORE - depends on LIBFC - select BTREE - default n - ---help--- - Say Y here to enable the TCM_QLA2XXX fabric module for QLogic 24xx+ series target mode HBAs - -if TCM_QLA2XXX -config TCM_QLA2XXX_DEBUG - bool "TCM_QLA2XXX fabric module DEBUG mode for QLogic 24xx+ series target mode HBAs" - default n - ---help--- - Say Y here to enable the TCM_QLA2XXX fabric module DEBUG for QLogic 24xx+ series target mode HBAs - This will include code to enable the SCSI command jammer -endif diff --git a/src/linux/drivers/scsi/qla4xxx/Kconfig b/src/linux/drivers/scsi/qla4xxx/Kconfig deleted file mode 100644 index e4dc7c7..0000000 --- a/src/linux/drivers/scsi/qla4xxx/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config SCSI_QLA_ISCSI - tristate "QLogic ISP4XXX and ISP82XX host adapter family support" - depends on PCI && SCSI && NET - select SCSI_ISCSI_ATTRS - select ISCSI_BOOT_SYSFS - ---help--- - This driver supports the QLogic 40xx (ISP4XXX), 8022 (ISP82XX) - and 8032 (ISP83XX) iSCSI host adapter family. diff --git a/src/linux/drivers/scsi/smartpqi/Kconfig b/src/linux/drivers/scsi/smartpqi/Kconfig deleted file mode 100644 index 97e159c..0000000 --- a/src/linux/drivers/scsi/smartpqi/Kconfig +++ /dev/null @@ -1,54 +0,0 @@ -# -# Kernel configuration file for the SMARTPQI -# -# Copyright (c) 2016 Microsemi Corporation -# Copyright (c) 2016 PMC-Sierra, Inc. -# (mailto:esc.storagedev@microsemi.com) - -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; version 2 -# of the License. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. - -# NO WARRANTY -# THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR -# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT -# LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, -# MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is -# solely responsible for determining the appropriateness of using and -# distributing the Program and assumes all risks associated with its -# exercise of rights under this Agreement, including but not limited to -# the risks and costs of program errors, damage to or loss of data, -# programs or equipment, and unavailability or interruption of operations. - -# DISCLAIMER OF LIABILITY -# NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY -# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -# DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND -# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR -# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -# USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED -# HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES - -config SCSI_SMARTPQI - tristate "Microsemi PQI Driver" - depends on PCI && SCSI && !S390 - select SCSI_SAS_ATTRS - select RAID_ATTRS - ---help--- - This driver supports Microsemi PQI controllers. - - - - To compile this driver as a module, choose M here: the - module will be called smartpqi. - - Note: the aacraid driver will not manage a smartpqi - controller. You need to enable smartpqi for smartpqi - controllers. For more information, please see - Documentation/scsi/smartpqi.txt diff --git a/src/linux/drivers/scsi/ufs/Kconfig b/src/linux/drivers/scsi/ufs/Kconfig deleted file mode 100644 index e27b4d4..0000000 --- a/src/linux/drivers/scsi/ufs/Kconfig +++ /dev/null @@ -1,102 +0,0 @@ -# -# Kernel configuration file for the UFS Host Controller -# -# This code is based on drivers/scsi/ufs/Kconfig -# Copyright (C) 2011-2013 Samsung India Software Operations -# -# Authors: -# Santosh Yaraganavi -# Vinayak Holikatti -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# See the COPYING file in the top-level directory or visit -# -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# This program is provided "AS IS" and "WITH ALL FAULTS" and -# without warranty of any kind. You are solely responsible for -# determining the appropriateness of using and distributing -# the program and assume all risks associated with your exercise -# of rights with respect to the program, including but not limited -# to infringement of third party rights, the risks and costs of -# program errors, damage to or loss of data, programs or equipment, -# and unavailability or interruption of operations. Under no -# circumstances will the contributor of this Program be liable for -# any damages of any kind arising from your use or distribution of -# this program. - -config SCSI_UFSHCD - tristate "Universal Flash Storage Controller Driver Core" - depends on SCSI && SCSI_DMA - select PM_DEVFREQ - select DEVFREQ_GOV_SIMPLE_ONDEMAND - select NLS - ---help--- - This selects the support for UFS devices in Linux, say Y and make - sure that you know the name of your UFS host adapter (the card - inside your computer that "speaks" the UFS protocol, also - called UFS Host Controller), because you will be asked for it. - The module will be called ufshcd. - - To compile this driver as a module, choose M here and read - . - However, do not compile this as a module if your root file system - (the one containing the directory /) is located on a UFS device. - -config SCSI_UFSHCD_PCI - tristate "PCI bus based UFS Controller support" - depends on SCSI_UFSHCD && PCI - ---help--- - This selects the PCI UFS Host Controller Interface. Select this if - you have UFS Host Controller with PCI Interface. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config SCSI_UFS_DWC_TC_PCI - tristate "DesignWare pci support using a G210 Test Chip" - depends on SCSI_UFSHCD_PCI - ---help--- - Synopsys Test Chip is a PHY for prototyping purposes. - - If unsure, say N. - -config SCSI_UFSHCD_PLATFORM - tristate "Platform bus based UFS Controller support" - depends on SCSI_UFSHCD - ---help--- - This selects the UFS host controller support. Select this if - you have an UFS controller on Platform bus. - - If you have a controller with this interface, say Y or M here. - - If unsure, say N. - -config SCSI_UFS_DWC_TC_PLATFORM - tristate "DesignWare platform support using a G210 Test Chip" - depends on SCSI_UFSHCD_PLATFORM - ---help--- - Synopsys Test Chip is a PHY for prototyping purposes. - - If unsure, say N. - -config SCSI_UFS_QCOM - tristate "QCOM specific hooks to UFS controller platform driver" - depends on SCSI_UFSHCD_PLATFORM && ARCH_QCOM - select PHY_QCOM_UFS - help - This selects the QCOM specific additions to UFSHCD platform driver. - UFS host on QCOM needs some vendor specific configuration before - accessing the hardware which includes PHY configuration and vendor - specific registers. - - Select this if you have UFS controller on QCOM chipset. - If unsure, say N. diff --git a/src/linux/drivers/soc/Kconfig b/src/linux/drivers/soc/Kconfig deleted file mode 100644 index e6e90e8..0000000 --- a/src/linux/drivers/soc/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -menu "SOC (System On Chip) specific Drivers" - -source "drivers/soc/bcm/Kconfig" -source "drivers/soc/fsl/qbman/Kconfig" -source "drivers/soc/fsl/qe/Kconfig" -source "drivers/soc/mediatek/Kconfig" -source "drivers/soc/qcom/Kconfig" -source "drivers/soc/rockchip/Kconfig" -source "drivers/soc/samsung/Kconfig" -source "drivers/soc/sunxi/Kconfig" -source "drivers/soc/tegra/Kconfig" -source "drivers/soc/ti/Kconfig" -source "drivers/soc/ux500/Kconfig" -source "drivers/soc/versatile/Kconfig" - -endmenu diff --git a/src/linux/drivers/soc/Makefile b/src/linux/drivers/soc/Makefile deleted file mode 100644 index 50c23d0..0000000 --- a/src/linux/drivers/soc/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# -# Makefile for the Linux Kernel SOC specific device drivers. -# - -obj-y += bcm/ -obj-$(CONFIG_ARCH_DOVE) += dove/ -obj-$(CONFIG_MACH_DOVE) += dove/ -obj-y += fsl/ -obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/ -obj-$(CONFIG_ARCH_QCOM) += qcom/ -obj-$(CONFIG_ARCH_RENESAS) += renesas/ -obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/ -obj-$(CONFIG_SOC_SAMSUNG) += samsung/ -obj-$(CONFIG_ARCH_SUNXI) += sunxi/ -obj-$(CONFIG_ARCH_TEGRA) += tegra/ -obj-$(CONFIG_SOC_TI) += ti/ -obj-$(CONFIG_ARCH_U8500) += ux500/ -obj-$(CONFIG_PLAT_VERSATILE) += versatile/ diff --git a/src/linux/drivers/soc/bcm/Kconfig b/src/linux/drivers/soc/bcm/Kconfig deleted file mode 100644 index a39b0d5..0000000 --- a/src/linux/drivers/soc/bcm/Kconfig +++ /dev/null @@ -1,23 +0,0 @@ -menu "Broadcom SoC drivers" - -config RASPBERRYPI_POWER - bool "Raspberry Pi power domain driver" - depends on ARCH_BCM2835 || (COMPILE_TEST && OF) - depends on RASPBERRYPI_FIRMWARE=y - select PM_GENERIC_DOMAINS if PM - help - This enables support for the RPi power domains which can be enabled - or disabled via the RPi firmware. - -config SOC_BRCMSTB - bool "Broadcom STB SoC drivers" - depends on ARM - select SOC_BUS - help - Enables drivers for the Broadcom Set-Top Box (STB) series of chips. - This option alone enables only some support code, while the drivers - can be enabled individually within this menu. - - If unsure, say N. - -endmenu diff --git a/src/linux/drivers/soc/bcm/Makefile b/src/linux/drivers/soc/bcm/Makefile deleted file mode 100644 index dc4fced..0000000 --- a/src/linux/drivers/soc/bcm/Makefile +++ /dev/null @@ -1,2 +0,0 @@ -obj-$(CONFIG_RASPBERRYPI_POWER) += raspberrypi-power.o -obj-$(CONFIG_SOC_BRCMSTB) += brcmstb/ diff --git a/src/linux/drivers/soc/fsl/Makefile b/src/linux/drivers/soc/fsl/Makefile deleted file mode 100644 index 75e1f53..0000000 --- a/src/linux/drivers/soc/fsl/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for the Linux Kernel SOC fsl specific device drivers -# - -obj-$(CONFIG_FSL_DPAA) += qbman/ -obj-$(CONFIG_QUICC_ENGINE) += qe/ -obj-$(CONFIG_CPM) += qe/ diff --git a/src/linux/drivers/soc/fsl/qbman/Kconfig b/src/linux/drivers/soc/fsl/qbman/Kconfig deleted file mode 100644 index 757033c..0000000 --- a/src/linux/drivers/soc/fsl/qbman/Kconfig +++ /dev/null @@ -1,67 +0,0 @@ -menuconfig FSL_DPAA - bool "Freescale DPAA 1.x support" - depends on FSL_SOC_BOOKE - select GENERIC_ALLOCATOR - help - The Freescale Data Path Acceleration Architecture (DPAA) is a set of - hardware components on specific QorIQ multicore processors. - This architecture provides the infrastructure to support simplified - sharing of networking interfaces and accelerators by multiple CPUs. - The major h/w blocks composing DPAA are BMan and QMan. - - The Buffer Manager (BMan) is a hardware buffer pool management block - that allows software and accelerators on the datapath to acquire and - release buffers in order to build frames. - - The Queue Manager (QMan) is a hardware queue management block - that allows software and accelerators on the datapath to enqueue and - dequeue frames in order to communicate. - -if FSL_DPAA - -config FSL_DPAA_CHECKING - bool "Additional driver checking" - help - Compiles in additional checks, to sanity-check the drivers and - any use of the exported API. Not recommended for performance. - -config FSL_BMAN_TEST - tristate "BMan self-tests" - help - Compile the BMan self-test code. These tests will - exercise the BMan APIs to confirm functionality - of both the software drivers and hardware device. - -config FSL_BMAN_TEST_API - bool "High-level API self-test" - depends on FSL_BMAN_TEST - default y - help - This requires the presence of cpu-affine portals, and performs - high-level API testing with them (whichever portal(s) are affine - to the cpu(s) the test executes on). - -config FSL_QMAN_TEST - tristate "QMan self-tests" - help - Compile self-test code for QMan. - -config FSL_QMAN_TEST_API - bool "QMan high-level self-test" - depends on FSL_QMAN_TEST - default y - help - This requires the presence of cpu-affine portals, and performs - high-level API testing with them (whichever portal(s) are affine to - the cpu(s) the test executes on). - -config FSL_QMAN_TEST_STASH - bool "QMan 'hot potato' data-stashing self-test" - depends on FSL_QMAN_TEST - default y - help - This performs a "hot potato" style test enqueuing/dequeuing a frame - across a series of FQs scheduled to different portals (and cpus), with - DQRR, data and context stashing always on. - -endif # FSL_DPAA diff --git a/src/linux/drivers/soc/fsl/qe/Kconfig b/src/linux/drivers/soc/fsl/qe/Kconfig deleted file mode 100644 index 73a2e08..0000000 --- a/src/linux/drivers/soc/fsl/qe/Kconfig +++ /dev/null @@ -1,42 +0,0 @@ -# -# QE Communication options -# - -config QUICC_ENGINE - bool "Freescale QUICC Engine (QE) Support" - depends on FSL_SOC && PPC32 - select GENERIC_ALLOCATOR - select CRC32 - help - The QUICC Engine (QE) is a new generation of communications - coprocessors on Freescale embedded CPUs (akin to CPM in older chips). - Selecting this option means that you wish to build a kernel - for a machine with a QE coprocessor. - -config UCC_SLOW - bool - default y if SERIAL_QE - help - This option provides qe_lib support to UCC slow - protocols: UART, BISYNC, QMC - -config UCC_FAST - bool - default y if UCC_GETH || QE_TDM - help - This option provides qe_lib support to UCC fast - protocols: HDLC, Ethernet, ATM, transparent - -config UCC - bool - default y if UCC_FAST || UCC_SLOW - -config QE_TDM - bool - default y if FSL_UCC_HDLC - -config QE_USB - bool - default y if USB_FSL_QE - help - QE USB Controller support diff --git a/src/linux/drivers/soc/mediatek/Kconfig b/src/linux/drivers/soc/mediatek/Kconfig deleted file mode 100644 index 0a4ea80..0000000 --- a/src/linux/drivers/soc/mediatek/Kconfig +++ /dev/null @@ -1,32 +0,0 @@ -# -# MediaTek SoC drivers -# -config MTK_INFRACFG - bool "MediaTek INFRACFG Support" - depends on ARCH_MEDIATEK || COMPILE_TEST - select REGMAP - help - Say yes here to add support for the MediaTek INFRACFG controller. The - INFRACFG controller contains various infrastructure registers not - directly associated to any device. - -config MTK_PMIC_WRAP - tristate "MediaTek PMIC Wrapper Support" - depends on ARCH_MEDIATEK - depends on RESET_CONTROLLER - select REGMAP - help - Say yes here to add support for MediaTek PMIC Wrapper found - on different MediaTek SoCs. The PMIC wrapper is a proprietary - hardware to connect the PMIC. - -config MTK_SCPSYS - bool "MediaTek SCPSYS Support" - depends on ARCH_MEDIATEK || COMPILE_TEST - default ARM64 && ARCH_MEDIATEK - select REGMAP - select MTK_INFRACFG - select PM_GENERIC_DOMAINS if PM - help - Say yes here to add support for the MediaTek SCPSYS power domain - driver. diff --git a/src/linux/drivers/soc/qcom/Kconfig b/src/linux/drivers/soc/qcom/Kconfig deleted file mode 100644 index 461b387..0000000 --- a/src/linux/drivers/soc/qcom/Kconfig +++ /dev/null @@ -1,78 +0,0 @@ -# -# QCOM Soc drivers -# -config QCOM_GSBI - tristate "QCOM General Serial Bus Interface" - depends on ARCH_QCOM - select MFD_SYSCON - help - Say y here to enable GSBI support. The GSBI provides control - functions for connecting the underlying serial UART, SPI, and I2C - devices to the output pins. - -config QCOM_PM - bool "Qualcomm Power Management" - depends on ARCH_QCOM && !ARM64 - select ARM_CPU_SUSPEND - select QCOM_SCM - help - QCOM Platform specific power driver to manage cores and L2 low power - modes. It interface with various system drivers to put the cores in - low power modes. - -config QCOM_SMEM - tristate "Qualcomm Shared Memory Manager (SMEM)" - depends on ARCH_QCOM - depends on HWSPINLOCK - help - Say y here to enable support for the Qualcomm Shared Memory Manager. - The driver provides an interface to items in a heap shared among all - processors in a Qualcomm platform. - -config QCOM_SMD - tristate "Qualcomm Shared Memory Driver (SMD)" - depends on QCOM_SMEM - help - Say y here to enable support for the Qualcomm Shared Memory Driver - providing communication channels to remote processors in Qualcomm - platforms. - -config QCOM_SMD_RPM - tristate "Qualcomm Resource Power Manager (RPM) over SMD" - depends on QCOM_SMD && OF - help - If you say yes to this option, support will be included for the - Resource Power Manager system found in the Qualcomm 8974 based - devices. - - This is required to access many regulators, clocks and bus - frequencies controlled by the RPM on these devices. - - Say M here if you want to include support for the Qualcomm RPM as a - module. This will build a module called "qcom-smd-rpm". - -config QCOM_SMEM_STATE - bool - -config QCOM_SMP2P - tristate "Qualcomm Shared Memory Point to Point support" - depends on QCOM_SMEM - select QCOM_SMEM_STATE - help - Say yes here to support the Qualcomm Shared Memory Point to Point - protocol. - -config QCOM_SMSM - tristate "Qualcomm Shared Memory State Machine" - depends on QCOM_SMEM - select QCOM_SMEM_STATE - help - Say yes here to support the Qualcomm Shared Memory State Machine. - The state machine is represented by bits in shared memory. - -config QCOM_WCNSS_CTRL - tristate "Qualcomm WCNSS control driver" - depends on QCOM_SMD - help - Client driver for the WCNSS_CTRL SMD channel, used to download nv - firmware to a newly booted WCNSS chip. diff --git a/src/linux/drivers/soc/rockchip/Kconfig b/src/linux/drivers/soc/rockchip/Kconfig deleted file mode 100644 index 7140ff8..0000000 --- a/src/linux/drivers/soc/rockchip/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -if ARCH_ROCKCHIP || COMPILE_TEST - -# -# Rockchip Soc drivers -# -config ROCKCHIP_PM_DOMAINS - bool "Rockchip generic power domain" - depends on PM - select PM_GENERIC_DOMAINS - help - Say y here to enable power domain support. - In order to meet high performance and low power requirements, a power - management unit is designed or saving power when RK3288 in low power - mode. The RK3288 PMU is dedicated for managing the power of the whole chip. - - If unsure, say N. - -endif diff --git a/src/linux/drivers/soc/samsung/Kconfig b/src/linux/drivers/soc/samsung/Kconfig deleted file mode 100644 index 2455339..0000000 --- a/src/linux/drivers/soc/samsung/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -# -# SAMSUNG SoC drivers -# -menuconfig SOC_SAMSUNG - bool "Samsung SoC driver support" if COMPILE_TEST - -if SOC_SAMSUNG - -config EXYNOS_PMU - bool "Exynos PMU controller driver" if COMPILE_TEST - depends on (ARM && ARCH_EXYNOS) || ((ARM || ARM64) && COMPILE_TEST) - -config EXYNOS_PM_DOMAINS - bool "Exynos PM domains" if COMPILE_TEST - depends on PM_GENERIC_DOMAINS || COMPILE_TEST - -endif diff --git a/src/linux/drivers/soc/sunxi/Kconfig b/src/linux/drivers/soc/sunxi/Kconfig deleted file mode 100644 index 353b07e..0000000 --- a/src/linux/drivers/soc/sunxi/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -# -# Allwinner sunXi SoC drivers -# -config SUNXI_SRAM - bool - default ARCH_SUNXI - help - Say y here to enable the SRAM controller support. This - device is responsible on mapping the SRAM in the sunXi SoCs - whether to the CPU/DMA, or to the devices. diff --git a/src/linux/drivers/soc/tegra/Kconfig b/src/linux/drivers/soc/tegra/Kconfig deleted file mode 100644 index 03089ad..0000000 --- a/src/linux/drivers/soc/tegra/Kconfig +++ /dev/null @@ -1,81 +0,0 @@ -if ARCH_TEGRA - -# 32-bit ARM SoCs -if ARM - -config ARCH_TEGRA_2x_SOC - bool "Enable support for Tegra20 family" - select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP - select ARM_ERRATA_720789 - select ARM_ERRATA_754327 if SMP - select ARM_ERRATA_764369 if SMP - select PINCTRL_TEGRA20 - select PL310_ERRATA_727915 if CACHE_L2X0 - select PL310_ERRATA_769419 if CACHE_L2X0 - select TEGRA_TIMER - help - Support for NVIDIA Tegra AP20 and T20 processors, based on the - ARM CortexA9MP CPU and the ARM PL310 L2 cache controller - -config ARCH_TEGRA_3x_SOC - bool "Enable support for Tegra30 family" - select ARM_ERRATA_754322 - select ARM_ERRATA_764369 if SMP - select PINCTRL_TEGRA30 - select PL310_ERRATA_769419 if CACHE_L2X0 - select TEGRA_TIMER - help - Support for NVIDIA Tegra T30 processor family, based on the - ARM CortexA9MP CPU and the ARM PL310 L2 cache controller - -config ARCH_TEGRA_114_SOC - bool "Enable support for Tegra114 family" - select ARM_ERRATA_798181 if SMP - select HAVE_ARM_ARCH_TIMER - select PINCTRL_TEGRA114 - select TEGRA_TIMER - help - Support for NVIDIA Tegra T114 processor family, based on the - ARM CortexA15MP CPU - -config ARCH_TEGRA_124_SOC - bool "Enable support for Tegra124 family" - select HAVE_ARM_ARCH_TIMER - select PINCTRL_TEGRA124 - select TEGRA_TIMER - help - Support for NVIDIA Tegra T124 processor family, based on the - ARM CortexA15MP CPU - -endif - -# 64-bit ARM SoCs -if ARM64 - -config ARCH_TEGRA_132_SOC - bool "NVIDIA Tegra132 SoC" - select PINCTRL_TEGRA124 - help - Enable support for NVIDIA Tegra132 SoC, based on the Denver - ARMv8 CPU. The Tegra132 SoC is similar to the Tegra124 SoC, - but contains an NVIDIA Denver CPU complex in place of - Tegra124's "4+1" Cortex-A15 CPU complex. - -config ARCH_TEGRA_210_SOC - bool "NVIDIA Tegra210 SoC" - select PINCTRL_TEGRA210 - help - Enable support for the NVIDIA Tegra210 SoC. Also known as Tegra X1, - the Tegra210 has four Cortex-A57 cores paired with four Cortex-A53 - cores in a switched configuration. It features a GPU of the Maxwell - architecture with support for DX11, SM4, OpenGL 4.5, OpenGL ES 3.1 - and providing 256 CUDA cores. It supports hardware-accelerated en- - and decoding of various video standards including H.265, H.264 and - VP8 at 4K resolution and up to 60 fps. - - Besides the multimedia features it also comes with a variety of I/O - controllers, such as GPIO, I2C, SPI, SDHCI, PCIe, SATA and XHCI, to - name only a few. - -endif -endif diff --git a/src/linux/drivers/soc/ti/Kconfig b/src/linux/drivers/soc/ti/Kconfig deleted file mode 100644 index 3557c5e..0000000 --- a/src/linux/drivers/soc/ti/Kconfig +++ /dev/null @@ -1,41 +0,0 @@ -# -# TI SOC drivers -# -menuconfig SOC_TI - bool "TI SOC drivers support" - -if SOC_TI - -config KEYSTONE_NAVIGATOR_QMSS - tristate "Keystone Queue Manager Sub System" - depends on ARCH_KEYSTONE - help - Say y here to support the Keystone multicore Navigator Queue - Manager support. The Queue Manager is a hardware module that - is responsible for accelerating management of the packet queues. - Packets are queued/de-queued by writing/reading descriptor address - to a particular memory mapped location in the Queue Manager module. - - If unsure, say N. - -config KEYSTONE_NAVIGATOR_DMA - tristate "TI Keystone Navigator Packet DMA support" - depends on ARCH_KEYSTONE - help - Say y tp enable support for the Keystone Navigator Packet DMA on - on Keystone family of devices. It sets up the dma channels for the - Queue Manager Sub System. - - If unsure, say N. - -config WKUP_M3_IPC - tristate "TI AMx3 Wkup-M3 IPC Driver" - depends on WKUP_M3_RPROC - depends on OMAP2PLUS_MBOX - help - TI AM33XX and AM43XX have a Cortex M3, the Wakeup M3, to handle - low power transitions. This IPC driver provides the necessary API - to communicate and use the Wakeup M3 for PM features like suspend - resume and boots it using wkup_m3_rproc driver. - -endif # SOC_TI diff --git a/src/linux/drivers/soc/ux500/Kconfig b/src/linux/drivers/soc/ux500/Kconfig deleted file mode 100644 index 025a44a..0000000 --- a/src/linux/drivers/soc/ux500/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -config UX500_SOC_ID - bool "SoC bus for ST-Ericsson ux500" - depends on ARCH_U8500 || COMPILE_TEST - default ARCH_U8500 - help - Include support for the SoC bus on the ARM RealView platforms - providing some sysfs information about the ASIC variant. diff --git a/src/linux/drivers/soc/versatile/Kconfig b/src/linux/drivers/soc/versatile/Kconfig deleted file mode 100644 index a928a7f..0000000 --- a/src/linux/drivers/soc/versatile/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -# -# ARM Versatile SoC drivers -# -config SOC_INTEGRATOR_CM - bool "SoC bus device for the ARM Integrator platform core modules" - depends on ARCH_INTEGRATOR - select SOC_BUS - help - Include support for the SoC bus on the ARM Integrator platform - core modules providing some sysfs information about the ASIC - variant. - -config SOC_REALVIEW - bool "SoC bus device for the ARM RealView platforms" - depends on ARCH_REALVIEW - select SOC_BUS - help - Include support for the SoC bus on the ARM RealView platforms - providing some sysfs information about the ASIC variant. diff --git a/src/linux/drivers/spi/Kconfig b/src/linux/drivers/spi/Kconfig deleted file mode 100644 index b799547..0000000 --- a/src/linux/drivers/spi/Kconfig +++ /dev/null @@ -1,766 +0,0 @@ -# -# SPI driver configuration -# -# NOTE: the reason this doesn't show SPI slave support is mostly that -# nobody's needed a slave side API yet. The master-role API is not -# fully appropriate there, so it'd need some thought to do well. -# -menuconfig SPI - bool "SPI support" - depends on HAS_IOMEM - help - The "Serial Peripheral Interface" is a low level synchronous - protocol. Chips that support SPI can have data transfer rates - up to several tens of Mbit/sec. Chips are addressed with a - controller and a chipselect. Most SPI slaves don't support - dynamic device discovery; some are even write-only or read-only. - - SPI is widely used by microcontrollers to talk with sensors, - eeprom and flash memory, codecs and various other controller - chips, analog to digital (and d-to-a) converters, and more. - MMC and SD cards can be accessed using SPI protocol; and for - DataFlash cards used in MMC sockets, SPI must always be used. - - SPI is one of a family of similar protocols using a four wire - interface (select, clock, data in, data out) including Microwire - (half duplex), SSP, SSI, and PSP. This driver framework should - work with most such devices and controllers. - -if SPI - -config SPI_DEBUG - bool "Debug support for SPI drivers" - depends on DEBUG_KERNEL - help - Say "yes" to enable debug messaging (like dev_dbg and pr_debug), - sysfs, and debugfs support in SPI controller and protocol drivers. - -# -# MASTER side ... talking to discrete SPI slave chips including microcontrollers -# - -config SPI_MASTER -# bool "SPI Master Support" - bool - default SPI - help - If your system has an master-capable SPI controller (which - provides the clock and chipselect), you can enable that - controller and the protocol drivers for the SPI slave chips - that are connected. - -if SPI_MASTER - -comment "SPI Master Controller Drivers" - -config SPI_ALTERA - tristate "Altera SPI Controller" - select SPI_BITBANG - help - This is the driver for the Altera SPI Controller. - -config SPI_ATH79 - tristate "Atheros AR71XX/AR724X/AR913X SPI controller driver" - depends on ATH79 && GPIOLIB - select SPI_BITBANG - help - This enables support for the SPI controller present on the - Atheros AR71XX/AR724X/AR913X SoCs. - -config SPI_ATMEL - tristate "Atmel SPI Controller" - depends on HAS_DMA - depends on (ARCH_AT91 || AVR32 || COMPILE_TEST) - help - This selects a driver for the Atmel SPI Controller, present on - many AT32 (AVR32) and AT91 (ARM) chips. - -config SPI_AU1550 - tristate "Au1550/Au1200/Au1300 SPI Controller" - depends on MIPS_ALCHEMY - select SPI_BITBANG - help - If you say yes to this option, support will be included for the - PSC SPI controller found on Au1550, Au1200 and Au1300 series. - -config SPI_AXI_SPI_ENGINE - tristate "Analog Devices AXI SPI Engine controller" - depends on HAS_IOMEM - help - This enables support for the Analog Devices AXI SPI Engine SPI controller. - It is part of the SPI Engine framework that is used in some Analog Devices - reference designs for FPGAs. - -config SPI_BCM2835 - tristate "BCM2835 SPI controller" - depends on GPIOLIB - depends on ARCH_BCM2835 || COMPILE_TEST - help - This selects a driver for the Broadcom BCM2835 SPI master. - - The BCM2835 contains two types of SPI master controller; the - "universal SPI master", and the regular SPI controller. This driver - is for the regular SPI controller. Slave mode operation is not also - not supported. - -config SPI_BCM2835AUX - tristate "BCM2835 SPI auxiliary controller" - depends on (ARCH_BCM2835 && GPIOLIB) || COMPILE_TEST - help - This selects a driver for the Broadcom BCM2835 SPI aux master. - - The BCM2835 contains two types of SPI master controller; the - "universal SPI master", and the regular SPI controller. - This driver is for the universal/auxiliary SPI controller. - -config SPI_BFIN5XX - tristate "SPI controller driver for ADI Blackfin5xx" - depends on BLACKFIN && !BF60x - help - This is the SPI controller master driver for Blackfin 5xx processor. - -config SPI_ADI_V3 - tristate "SPI controller v3 for ADI" - depends on BF60x - help - This is the SPI controller v3 master driver - found on Blackfin 60x processor. - -config SPI_BFIN_SPORT - tristate "SPI bus via Blackfin SPORT" - depends on BLACKFIN - help - Enable support for a SPI bus via the Blackfin SPORT peripheral. - -config SPI_BCM53XX - tristate "Broadcom BCM53xx SPI controller" - depends on ARCH_BCM_5301X - depends on BCMA_POSSIBLE - select BCMA - help - Enable support for the SPI controller on Broadcom BCM53xx ARM SoCs. - -config SPI_BCM63XX - tristate "Broadcom BCM63xx SPI controller" - depends on BCM63XX || COMPILE_TEST - help - Enable support for the SPI controller on the Broadcom BCM63xx SoCs. - -config SPI_BCM63XX_HSSPI - tristate "Broadcom BCM63XX HS SPI controller driver" - depends on BCM63XX || COMPILE_TEST - help - This enables support for the High Speed SPI controller present on - newer Broadcom BCM63XX SoCs. - -config SPI_BCM_QSPI - tristate "Broadcom BSPI and MSPI controller support" - depends on ARCH_BRCMSTB || ARCH_BCM || ARCH_BCM_IPROC || COMPILE_TEST - default ARCH_BCM_IPROC - help - Enables support for the Broadcom SPI flash and MSPI controller. - Select this option for any one of BRCMSTB, iProc NSP and NS2 SoCs - based platforms. This driver works for both SPI master for spi-nor - flash device as well as MSPI device. - -config SPI_BITBANG - tristate "Utilities for Bitbanging SPI masters" - help - With a few GPIO pins, your system can bitbang the SPI protocol. - Select this to get SPI support through I/O pins (GPIO, parallel - port, etc). Or, some systems' SPI master controller drivers use - this code to manage the per-word or per-transfer accesses to the - hardware shift registers. - - This is library code, and is automatically selected by drivers that - need it. You only need to select this explicitly to support driver - modules that aren't part of this kernel tree. - -config SPI_BUTTERFLY - tristate "Parallel port adapter for AVR Butterfly (DEVELOPMENT)" - depends on PARPORT - select SPI_BITBANG - help - This uses a custom parallel port cable to connect to an AVR - Butterfly , an - inexpensive battery powered microcontroller evaluation board. - This same cable can be used to flash new firmware. - -config SPI_CADENCE - tristate "Cadence SPI controller" - help - This selects the Cadence SPI controller master driver - used by Xilinx Zynq and ZynqMP. - -config SPI_CLPS711X - tristate "CLPS711X host SPI controller" - depends on ARCH_CLPS711X || COMPILE_TEST - help - This enables dedicated general purpose SPI/Microwire1-compatible - master mode interface (SSI1) for CLPS711X-based CPUs. - -config SPI_COLDFIRE_QSPI - tristate "Freescale Coldfire QSPI controller" - depends on (M520x || M523x || M5249 || M525x || M527x || M528x || M532x) - help - This enables support for the Coldfire QSPI controller in master - mode. - -config SPI_DAVINCI - tristate "Texas Instruments DaVinci/DA8x/OMAP-L/AM1x SoC SPI controller" - depends on ARCH_DAVINCI || ARCH_KEYSTONE - select SPI_BITBANG - help - SPI master controller for DaVinci/DA8x/OMAP-L/AM1x SPI modules. - -config SPI_DESIGNWARE - tristate "DesignWare SPI controller core support" - help - general driver for SPI controller core from DesignWare - -config SPI_DW_PCI - tristate "PCI interface driver for DW SPI core" - depends on SPI_DESIGNWARE && PCI - -config SPI_DW_MID_DMA - bool "DMA support for DW SPI controller on Intel MID platform" - depends on SPI_DW_PCI && DW_DMAC_PCI - -config SPI_DW_MMIO - tristate "Memory-mapped io interface driver for DW SPI core" - depends on SPI_DESIGNWARE - -config SPI_DLN2 - tristate "Diolan DLN-2 USB SPI adapter" - depends on MFD_DLN2 - help - If you say yes to this option, support will be included for Diolan - DLN2, a USB to SPI interface. - - This driver can also be built as a module. If so, the module - will be called spi-dln2. - -config SPI_EFM32 - tristate "EFM32 SPI controller" - depends on OF && ARM && (ARCH_EFM32 || COMPILE_TEST) - select SPI_BITBANG - help - Driver for the spi controller found on Energy Micro's EFM32 SoCs. - -config SPI_EP93XX - tristate "Cirrus Logic EP93xx SPI controller" - depends on HAS_DMA - depends on ARCH_EP93XX || COMPILE_TEST - help - This enables using the Cirrus EP93xx SPI controller in master - mode. - -config SPI_FALCON - tristate "Falcon SPI controller support" - depends on SOC_FALCON - help - The external bus unit (EBU) found on the FALC-ON SoC has SPI - emulation that is designed for serial flash access. This driver - has only been tested with m25p80 type chips. The hardware has no - support for other types of SPI peripherals. - -config SPI_GPIO - tristate "GPIO-based bitbanging SPI Master" - depends on GPIOLIB || COMPILE_TEST - select SPI_BITBANG - help - This simple GPIO bitbanging SPI master uses the arch-neutral GPIO - interface to manage MOSI, MISO, SCK, and chipselect signals. SPI - slaves connected to a bus using this driver are configured as usual, - except that the spi_board_info.controller_data holds the GPIO number - for the chipselect used by this controller driver. - - Note that this driver often won't achieve even 1 Mbit/sec speeds, - making it unusually slow for SPI. If your platform can inline - GPIO operations, you should be able to leverage that for better - speed with a custom version of this driver; see the source code. - -config SPI_IMG_SPFI - tristate "IMG SPFI controller" - depends on MIPS || COMPILE_TEST - help - This enables support for the SPFI master controller found on - IMG SoCs. - -config SPI_IMX - tristate "Freescale i.MX SPI controllers" - depends on ARCH_MXC || COMPILE_TEST - select SPI_BITBANG - help - This enables using the Freescale i.MX SPI controllers in master - mode. - -config SPI_JCORE - tristate "J-Core SPI Master" - depends on OF && (SUPERH || COMPILE_TEST) - help - This enables support for the SPI master controller in the J-Core - synthesizable, open source SoC. - -config SPI_LM70_LLP - tristate "Parallel port adapter for LM70 eval board (DEVELOPMENT)" - depends on PARPORT - select SPI_BITBANG - help - This driver supports the NS LM70 LLP Evaluation Board, - which interfaces to an LM70 temperature sensor using - a parallel port. - -config SPI_LP8841_RTC - tristate "ICP DAS LP-8841 SPI Controller for RTC" - depends on MACH_PXA27X_DT || COMPILE_TEST - help - This driver provides an SPI master device to drive Maxim - DS-1302 real time clock. - - Say N here unless you plan to run the kernel on an ICP DAS - LP-8x4x industrial computer. - -config SPI_MPC52xx - tristate "Freescale MPC52xx SPI (non-PSC) controller support" - depends on PPC_MPC52xx - help - This drivers supports the MPC52xx SPI controller in master SPI - mode. - -config SPI_MPC52xx_PSC - tristate "Freescale MPC52xx PSC SPI controller" - depends on PPC_MPC52xx - help - This enables using the Freescale MPC52xx Programmable Serial - Controller in master SPI mode. - -config SPI_MPC512x_PSC - tristate "Freescale MPC512x PSC SPI controller" - depends on PPC_MPC512x - help - This enables using the Freescale MPC5121 Programmable Serial - Controller in SPI master mode. - -config SPI_FSL_LIB - tristate - depends on OF - -config SPI_FSL_CPM - tristate - depends on FSL_SOC - -config SPI_FSL_SPI - tristate "Freescale SPI controller and Aeroflex Gaisler GRLIB SPI controller" - depends on OF - select SPI_FSL_LIB - select SPI_FSL_CPM if FSL_SOC - help - This enables using the Freescale SPI controllers in master mode. - MPC83xx platform uses the controller in cpu mode or CPM/QE mode. - MPC8569 uses the controller in QE mode, MPC8610 in cpu mode. - This also enables using the Aeroflex Gaisler GRLIB SPI controller in - master mode. - -config SPI_FSL_DSPI - tristate "Freescale DSPI controller" - select REGMAP_MMIO - depends on SOC_VF610 || SOC_LS1021A || ARCH_LAYERSCAPE || COMPILE_TEST - help - This enables support for the Freescale DSPI controller in master - mode. VF610 platform uses the controller. - -config SPI_FSL_ESPI - tristate "Freescale eSPI controller" - depends on FSL_SOC - select SPI_FSL_LIB - help - This enables using the Freescale eSPI controllers in master mode. - From MPC8536, 85xx platform uses the controller, and all P10xx, - P20xx, P30xx,P40xx, P50xx uses this controller. - -config SPI_MESON_SPIFC - tristate "Amlogic Meson SPIFC controller" - depends on ARCH_MESON || COMPILE_TEST - select REGMAP_MMIO - help - This enables master mode support for the SPIFC (SPI flash - controller) available in Amlogic Meson SoCs. - -config SPI_MT65XX - tristate "MediaTek SPI controller" - depends on ARCH_MEDIATEK || COMPILE_TEST - help - This selects the MediaTek(R) SPI bus driver. - If you want to use MediaTek(R) SPI interface, - say Y or M here.If you are not sure, say N. - SPI drivers for Mediatek MT65XX and MT81XX series ARM SoCs. - -config SPI_NUC900 - tristate "Nuvoton NUC900 series SPI" - depends on ARCH_W90X900 - select SPI_BITBANG - help - SPI driver for Nuvoton NUC900 series ARM SoCs - -config SPI_OC_TINY - tristate "OpenCores tiny SPI" - depends on GPIOLIB || COMPILE_TEST - select SPI_BITBANG - help - This is the driver for OpenCores tiny SPI master controller. - -config SPI_OCTEON - tristate "Cavium OCTEON SPI controller" - depends on CAVIUM_OCTEON_SOC - help - SPI host driver for the hardware found on some Cavium OCTEON - SOCs. - -config SPI_OMAP_UWIRE - tristate "OMAP1 MicroWire" - depends on ARCH_OMAP1 - select SPI_BITBANG - help - This hooks up to the MicroWire controller on OMAP1 chips. - -config SPI_OMAP24XX - tristate "McSPI driver for OMAP" - depends on HAS_DMA - depends on ARCH_OMAP2PLUS || COMPILE_TEST - select SG_SPLIT - help - SPI master controller for OMAP24XX and later Multichannel SPI - (McSPI) modules. - -config SPI_TI_QSPI - tristate "DRA7xxx QSPI controller support" - depends on ARCH_OMAP2PLUS || COMPILE_TEST - help - QSPI master controller for DRA7xxx used for flash devices. - This device supports single, dual and quad read support, while - it only supports single write mode. - -config SPI_OMAP_100K - tristate "OMAP SPI 100K" - depends on ARCH_OMAP850 || ARCH_OMAP730 || COMPILE_TEST - help - OMAP SPI 100K master controller for omap7xx boards. - -config SPI_ORION - tristate "Orion SPI master" - depends on PLAT_ORION || ARCH_MVEBU || COMPILE_TEST - help - This enables using the SPI master controller on the Orion chips. - -config SPI_PIC32 - tristate "Microchip PIC32 series SPI" - depends on MACH_PIC32 || COMPILE_TEST - help - SPI driver for Microchip PIC32 SPI master controller. - -config SPI_PIC32_SQI - tristate "Microchip PIC32 Quad SPI driver" - depends on MACH_PIC32 || COMPILE_TEST - depends on HAS_DMA - help - SPI driver for PIC32 Quad SPI controller. - -config SPI_PL022 - tristate "ARM AMBA PL022 SSP controller" - depends on ARM_AMBA - default y if MACH_U300 - default y if ARCH_REALVIEW - default y if INTEGRATOR_IMPD1 - default y if ARCH_VERSATILE - help - This selects the ARM(R) AMBA(R) PrimeCell PL022 SSP - controller. If you have an embedded system with an AMBA(R) - bus and a PL022 controller, say Y or M here. - -config SPI_PPC4xx - tristate "PPC4xx SPI Controller" - depends on PPC32 && 4xx - select SPI_BITBANG - help - This selects a driver for the PPC4xx SPI Controller. - -config SPI_PXA2XX - tristate "PXA2xx SSP SPI master" - depends on (ARCH_PXA || PCI || ACPI) - select PXA_SSP if ARCH_PXA - help - This enables using a PXA2xx or Sodaville SSP port as a SPI master - controller. The driver can be configured to use any SSP port and - additional documentation can be found a Documentation/spi/pxa2xx. - -config SPI_PXA2XX_PCI - def_tristate SPI_PXA2XX && PCI && COMMON_CLK - -config SPI_ROCKCHIP - tristate "Rockchip SPI controller driver" - help - This selects a driver for Rockchip SPI controller. - - If you say yes to this option, support will be included for - RK3066, RK3188 and RK3288 families of SPI controller. - Rockchip SPI controller support DMA transport and PIO mode. - The main usecase of this controller is to use spi flash as boot - device. - -config SPI_RB4XX - tristate "Mikrotik RB4XX SPI master" - depends on SPI_MASTER && ATH79 - help - SPI controller driver for the Mikrotik RB4xx series boards. - -config SPI_RSPI - tristate "Renesas RSPI/QSPI controller" - depends on SUPERH || ARCH_RENESAS || COMPILE_TEST - help - SPI driver for Renesas RSPI and QSPI blocks. - -config SPI_QUP - tristate "Qualcomm SPI controller with QUP interface" - depends on ARCH_QCOM || (ARM && COMPILE_TEST) - help - Qualcomm Universal Peripheral (QUP) core is an AHB slave that - provides a common data path (an output FIFO and an input FIFO) - for serial peripheral interface (SPI) mini-core. SPI in master - mode supports up to 50MHz, up to four chip selects, programmable - data path from 4 bits to 32 bits and numerous protocol variants. - - This driver can also be built as a module. If so, the module - will be called spi_qup. - -config SPI_S3C24XX - tristate "Samsung S3C24XX series SPI" - depends on ARCH_S3C24XX - select SPI_BITBANG - help - SPI driver for Samsung S3C24XX series ARM SoCs - -config SPI_S3C24XX_FIQ - bool "S3C24XX driver with FIQ pseudo-DMA" - depends on SPI_S3C24XX - select FIQ - help - Enable FIQ support for the S3C24XX SPI driver to provide pseudo - DMA by using the fast-interrupt request framework, This allows - the driver to get DMA-like performance when there are either - no free DMA channels, or when doing transfers that required both - TX and RX data paths. - -config SPI_S3C64XX - tristate "Samsung S3C64XX series type SPI" - depends on (PLAT_SAMSUNG || ARCH_EXYNOS) - help - SPI driver for Samsung S3C64XX and newer SoCs. - -config SPI_SC18IS602 - tristate "NXP SC18IS602/602B/603 I2C to SPI bridge" - depends on I2C - help - SPI driver for NXP SC18IS602/602B/603 I2C to SPI bridge. - -config SPI_SH_MSIOF - tristate "SuperH MSIOF SPI controller" - depends on HAVE_CLK && HAS_DMA - depends on ARCH_SHMOBILE || ARCH_RENESAS || COMPILE_TEST - help - SPI driver for SuperH and SH Mobile MSIOF blocks. - -config SPI_SH - tristate "SuperH SPI controller" - depends on SUPERH || COMPILE_TEST - help - SPI driver for SuperH SPI blocks. - -config SPI_SH_SCI - tristate "SuperH SCI SPI controller" - depends on SUPERH - select SPI_BITBANG - help - SPI driver for SuperH SCI blocks. - -config SPI_SH_HSPI - tristate "SuperH HSPI controller" - depends on ARCH_RENESAS || COMPILE_TEST - help - SPI driver for SuperH HSPI blocks. - -config SPI_SIRF - tristate "CSR SiRFprimaII SPI controller" - depends on SIRF_DMA - select SPI_BITBANG - help - SPI driver for CSR SiRFprimaII SoCs - -config SPI_ST_SSC4 - tristate "STMicroelectronics SPI SSC-based driver" - depends on ARCH_STI || COMPILE_TEST - help - STMicroelectronics SoCs support for SPI. If you say yes to - this option, support will be included for the SSC driven SPI. - -config SPI_SUN4I - tristate "Allwinner A10 SoCs SPI controller" - depends on ARCH_SUNXI || COMPILE_TEST - help - SPI driver for Allwinner sun4i, sun5i and sun7i SoCs - -config SPI_SUN6I - tristate "Allwinner A31 SPI controller" - depends on ARCH_SUNXI || COMPILE_TEST - depends on RESET_CONTROLLER - help - This enables using the SPI controller on the Allwinner A31 SoCs. - -config SPI_MXS - tristate "Freescale MXS SPI controller" - depends on ARCH_MXS - select STMP_DEVICE - help - SPI driver for Freescale MXS devices. - -config SPI_TEGRA114 - tristate "NVIDIA Tegra114 SPI Controller" - depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST - depends on RESET_CONTROLLER && HAS_DMA - help - SPI driver for NVIDIA Tegra114 SPI Controller interface. This controller - is different than the older SoCs SPI controller and also register interface - get changed with this controller. - -config SPI_TEGRA20_SFLASH - tristate "Nvidia Tegra20 Serial flash Controller" - depends on ARCH_TEGRA || COMPILE_TEST - depends on RESET_CONTROLLER - help - SPI driver for Nvidia Tegra20 Serial flash Controller interface. - The main usecase of this controller is to use spi flash as boot - device. - -config SPI_TEGRA20_SLINK - tristate "Nvidia Tegra20/Tegra30 SLINK Controller" - depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST - depends on RESET_CONTROLLER && HAS_DMA - help - SPI driver for Nvidia Tegra20/Tegra30 SLINK Controller interface. - -config SPI_THUNDERX - tristate "Cavium ThunderX SPI controller" - depends on PCI && 64BIT && (ARM64 || COMPILE_TEST) - help - SPI host driver for the hardware found on Cavium ThunderX - SOCs. - -config SPI_TOPCLIFF_PCH - tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) SPI" - depends on PCI && (X86_32 || MIPS || COMPILE_TEST) - help - SPI driver for the Topcliff PCH (Platform Controller Hub) SPI bus - used in some x86 embedded processors. - - This driver also supports the ML7213/ML7223/ML7831, a companion chip - for the Atom E6xx series and compatible with the Intel EG20T PCH. - -config SPI_TXX9 - tristate "Toshiba TXx9 SPI controller" - depends on GPIOLIB && (CPU_TX49XX || COMPILE_TEST) - help - SPI driver for Toshiba TXx9 MIPS SoCs - -config SPI_XCOMM - tristate "Analog Devices AD-FMCOMMS1-EBZ SPI-I2C-bridge driver" - depends on I2C - help - Support for the SPI-I2C bridge found on the Analog Devices - AD-FMCOMMS1-EBZ board. - -config SPI_XILINX - tristate "Xilinx SPI controller common module" - depends on HAS_IOMEM - select SPI_BITBANG - help - This exposes the SPI controller IP from the Xilinx EDK. - - See the "OPB Serial Peripheral Interface (SPI) (v1.00e)" - Product Specification document (DS464) for hardware details. - - Or for the DS570, see "XPS Serial Peripheral Interface (SPI) (v2.00b)" - -config SPI_XLP - tristate "Netlogic XLP SPI controller driver" - depends on CPU_XLP || ARCH_VULCAN || COMPILE_TEST - help - Enable support for the SPI controller on the Netlogic XLP SoCs. - Currently supported XLP variants are XLP8XX, XLP3XX, XLP2XX, XLP9XX - and XLP5XX. - - If you have a Netlogic XLP platform say Y here. - If unsure, say N. - -config SPI_XTENSA_XTFPGA - tristate "Xtensa SPI controller for xtfpga" - depends on (XTENSA && XTENSA_PLATFORM_XTFPGA) || COMPILE_TEST - select SPI_BITBANG - help - SPI driver for xtfpga SPI master controller. - - This simple SPI master controller is built into xtfpga bitstreams - and is used to control daughterboard audio codec. It always transfers - 16 bit words in SPI mode 0, automatically asserting CS on transfer - start and deasserting on end. - -config SPI_ZYNQMP_GQSPI - tristate "Xilinx ZynqMP GQSPI controller" - depends on SPI_MASTER && HAS_DMA - help - Enables Xilinx GQSPI controller driver for Zynq UltraScale+ MPSoC. - -# -# Add new SPI master controllers in alphabetical order above this line -# - -# -# There are lots of SPI device types, with sensors and memory -# being probably the most widely used ones. -# -comment "SPI Protocol Masters" - -config SPI_SPIDEV - tristate "User mode SPI device driver support" - help - This supports user mode SPI protocol drivers. - - Note that this application programming interface is EXPERIMENTAL - and hence SUBJECT TO CHANGE WITHOUT NOTICE while it stabilizes. - -config SPI_LOOPBACK_TEST - tristate "spi loopback test framework support" - depends on m - help - This enables the SPI loopback testing framework driver - - primarily used for development of spi_master drivers - and to detect regressions - -config SPI_TLE62X0 - tristate "Infineon TLE62X0 (for power switching)" - depends on SYSFS - help - SPI driver for Infineon TLE62X0 series line driver chips, - such as the TLE6220, TLE6230 and TLE6240. This provides a - sysfs interface, with each line presented as a kind of GPIO - exposing both switch control and diagnostic feedback. - -# -# Add new SPI protocol masters in alphabetical order above this line -# - -endif # SPI_MASTER - -# (slave support would go here) - -endif # SPI diff --git a/src/linux/drivers/spmi/Kconfig b/src/linux/drivers/spmi/Kconfig deleted file mode 100644 index 0d3b70b..0000000 --- a/src/linux/drivers/spmi/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -# -# SPMI driver configuration -# -menuconfig SPMI - tristate "SPMI support" - help - SPMI (System Power Management Interface) is a two-wire - serial interface between baseband and application processors - and Power Management Integrated Circuits (PMIC). - -if SPMI - -config SPMI_MSM_PMIC_ARB - tristate "Qualcomm MSM SPMI Controller (PMIC Arbiter)" - select IRQ_DOMAIN - depends on ARCH_QCOM || COMPILE_TEST - depends on HAS_IOMEM - default ARCH_QCOM - help - If you say yes to this option, support will be included for the - built-in SPMI PMIC Arbiter interface on Qualcomm MSM family - processors. - - This is required for communicating with Qualcomm PMICs and - other devices that have the SPMI interface. - -endif diff --git a/src/linux/drivers/ssb/Kconfig b/src/linux/drivers/ssb/Kconfig deleted file mode 100644 index d8e4219..0000000 --- a/src/linux/drivers/ssb/Kconfig +++ /dev/null @@ -1,188 +0,0 @@ -config SSB_POSSIBLE - bool - depends on HAS_IOMEM && HAS_DMA - default y - -menu "Sonics Silicon Backplane" - depends on SSB_POSSIBLE - -config SSB - tristate "Sonics Silicon Backplane support" - depends on SSB_POSSIBLE - help - Support for the Sonics Silicon Backplane bus. - You only need to enable this option, if you are - configuring a kernel for an embedded system with - this bus. - It will be auto-selected if needed in other - environments. - - The module will be called ssb. - - If unsure, say N. - -# Common SPROM support routines -config SSB_SPROM - bool - -# Support for Block-I/O. SELECT this from the driver that needs it. -config SSB_BLOCKIO - bool - depends on SSB - -config SSB_PCIHOST_POSSIBLE - bool - depends on SSB && (PCI = y || PCI = SSB) - default y - -config SSB_PCIHOST - bool "Support for SSB on PCI-bus host" - depends on SSB_PCIHOST_POSSIBLE - select SSB_SPROM - default y - help - Support for a Sonics Silicon Backplane on top - of a PCI device. - - If unsure, say Y - -config SSB_B43_PCI_BRIDGE - bool - depends on SSB_PCIHOST - default n - -config SSB_PCMCIAHOST_POSSIBLE - bool - depends on SSB && (PCMCIA = y || PCMCIA = SSB) - default y - -config SSB_PCMCIAHOST - bool "Support for SSB on PCMCIA-bus host" - depends on SSB_PCMCIAHOST_POSSIBLE - select SSB_SPROM - help - Support for a Sonics Silicon Backplane on top - of a PCMCIA device. - - If unsure, say N - -config SSB_SDIOHOST_POSSIBLE - bool - depends on SSB && (MMC = y || MMC = SSB) - default y - -config SSB_SDIOHOST - bool "Support for SSB on SDIO-bus host" - depends on SSB_SDIOHOST_POSSIBLE - help - Support for a Sonics Silicon Backplane on top - of a SDIO device. - - If unsure, say N - -config SSB_HOST_SOC - bool "Support for SSB bus on SoC" - depends on SSB && BCM47XX_NVRAM - select SSB_SPROM - help - Host interface for a SSB directly mapped into memory. This is - for some Broadcom SoCs from the BCM47xx and BCM53xx lines. - - If unsure, say N - -config SSB_SILENT - bool "No SSB kernel messages" - depends on SSB && EXPERT - help - This option turns off all Sonics Silicon Backplane printks. - Note that you won't be able to identify problems, once - messages are turned off. - This might only be desired for production kernels on - embedded devices to reduce the kernel size. - - Say N - -config SSB_DEBUG - bool "SSB debugging" - depends on SSB && !SSB_SILENT - help - This turns on additional runtime checks and debugging - messages. Turn this on for SSB troubleshooting. - - If unsure, say N - -config SSB_SERIAL - bool - depends on SSB - # ChipCommon and ExtIf serial support routines. - -config SSB_DRIVER_PCICORE_POSSIBLE - bool - depends on SSB_PCIHOST - default y - -config SSB_DRIVER_PCICORE - bool "SSB PCI core driver" - depends on SSB_DRIVER_PCICORE_POSSIBLE - help - Driver for the Sonics Silicon Backplane attached - Broadcom PCI core. - - If unsure, say Y - -config SSB_PCICORE_HOSTMODE - bool "Hostmode support for SSB PCI core" - depends on SSB_DRIVER_PCICORE && SSB_DRIVER_MIPS - help - PCIcore hostmode operation (external PCI bus). - -config SSB_DRIVER_MIPS - bool "SSB Broadcom MIPS core driver" - depends on SSB && MIPS - select SSB_SERIAL - select SSB_SFLASH - help - Driver for the Sonics Silicon Backplane attached - Broadcom MIPS core. - - If unsure, say N - -config SSB_SFLASH - bool "SSB serial flash support" - depends on SSB_DRIVER_MIPS - default y - -# Assumption: We are on embedded, if we compile the MIPS core. -config SSB_EMBEDDED - bool - depends on SSB_DRIVER_MIPS && SSB_PCICORE_HOSTMODE - default y - -config SSB_DRIVER_EXTIF - bool "SSB Broadcom EXTIF core driver" - depends on SSB_DRIVER_MIPS - help - Driver for the Sonics Silicon Backplane attached - Broadcom EXTIF core. - - If unsure, say N - -config SSB_DRIVER_GIGE - bool "SSB Broadcom Gigabit Ethernet driver" - depends on SSB_PCIHOST_POSSIBLE && SSB_EMBEDDED && MIPS - help - Driver for the Sonics Silicon Backplane attached - Broadcom Gigabit Ethernet. - - If unsure, say N - -config SSB_DRIVER_GPIO - bool "SSB GPIO driver" - depends on SSB && GPIOLIB - select IRQ_DOMAIN if SSB_EMBEDDED - help - Driver to provide access to the GPIO pins on the bus. - - If unsure, say N - -endmenu diff --git a/src/linux/drivers/staging/Kconfig b/src/linux/drivers/staging/Kconfig deleted file mode 100644 index 58a7b35..0000000 --- a/src/linux/drivers/staging/Kconfig +++ /dev/null @@ -1,109 +0,0 @@ -menuconfig STAGING - bool "Staging drivers" - default n - ---help--- - This option allows you to select a number of drivers that are - not of the "normal" Linux kernel quality level. These drivers - are placed here in order to get a wider audience to make use of - them. Please note that these drivers are under heavy - development, may or may not work, and may contain userspace - interfaces that most likely will be changed in the near - future. - - Using any of these drivers will taint your kernel which might - affect support options from both the community, and various - commercial support organizations. - - If you wish to work on these drivers, to help improve them, or - to report problems you have with them, please see the - driver_name.README file in the drivers/staging/ directory to - see what needs to be worked on, and who to contact. - - If in doubt, say N here. - - -if STAGING - -source "drivers/staging/slicoss/Kconfig" - -source "drivers/staging/wlan-ng/Kconfig" - -source "drivers/staging/comedi/Kconfig" - -source "drivers/staging/olpc_dcon/Kconfig" - -source "drivers/staging/rtl8192u/Kconfig" - -source "drivers/staging/rtl8192e/Kconfig" - -source "drivers/staging/rtl8712/Kconfig" - -source "drivers/staging/rtl8188eu/Kconfig" - -source "drivers/staging/rts5208/Kconfig" - -source "drivers/staging/octeon/Kconfig" - -source "drivers/staging/octeon-usb/Kconfig" - -source "drivers/staging/vt6655/Kconfig" - -source "drivers/staging/vt6656/Kconfig" - -source "drivers/staging/iio/Kconfig" - -source "drivers/staging/sm750fb/Kconfig" - -source "drivers/staging/xgifb/Kconfig" - -source "drivers/staging/emxx_udc/Kconfig" - -source "drivers/staging/speakup/Kconfig" - -source "drivers/staging/nvec/Kconfig" - -source "drivers/staging/media/Kconfig" - -source "drivers/staging/android/Kconfig" - -source "drivers/staging/board/Kconfig" - -source "drivers/staging/gdm724x/Kconfig" - -source "drivers/staging/fwserial/Kconfig" - -source "drivers/staging/goldfish/Kconfig" - -source "drivers/staging/netlogic/Kconfig" - -source "drivers/staging/mt29f_spinand/Kconfig" - -source "drivers/staging/lustre/Kconfig" - -source "drivers/staging/dgnc/Kconfig" - -source "drivers/staging/gs_fpgaboot/Kconfig" - -source "drivers/staging/skein/Kconfig" - -source "drivers/staging/unisys/Kconfig" - -source "drivers/staging/clocking-wizard/Kconfig" - -source "drivers/staging/fbtft/Kconfig" - -source "drivers/staging/fsl-mc/Kconfig" - -source "drivers/staging/wilc1000/Kconfig" - -source "drivers/staging/most/Kconfig" - -source "drivers/staging/i4l/Kconfig" - -source "drivers/staging/ks7010/Kconfig" - -source "drivers/staging/greybus/Kconfig" - -source "drivers/staging/vc04_services/Kconfig" - -endif # STAGING diff --git a/src/linux/drivers/staging/android/Kconfig b/src/linux/drivers/staging/android/Kconfig deleted file mode 100644 index 6c00d6f..0000000 --- a/src/linux/drivers/staging/android/Kconfig +++ /dev/null @@ -1,31 +0,0 @@ -menu "Android" - -if ANDROID - -config ASHMEM - bool "Enable the Anonymous Shared Memory Subsystem" - default n - depends on SHMEM - ---help--- - The ashmem subsystem is a new shared memory allocator, similar to - POSIX SHM but with different behavior and sporting a simpler - file-based API. - - It is, in theory, a good memory allocator for low-memory devices, - because it can discard shared memory units when under memory pressure. - -config ANDROID_LOW_MEMORY_KILLER - bool "Android Low Memory Killer" - ---help--- - Registers processes to be killed when low memory conditions, this is useful - as there is no particular swap space on android. - - The registered process will kill according to the priorities in android init - scripts (/init.rc), and it defines priority values with minimum free memory size - for each priority. - -source "drivers/staging/android/ion/Kconfig" - -endif # if ANDROID - -endmenu diff --git a/src/linux/drivers/staging/android/ion/Kconfig b/src/linux/drivers/staging/android/ion/Kconfig deleted file mode 100644 index c8fb413..0000000 --- a/src/linux/drivers/staging/android/ion/Kconfig +++ /dev/null @@ -1,54 +0,0 @@ -menuconfig ION - bool "Ion Memory Manager" - depends on HAVE_MEMBLOCK && HAS_DMA && MMU - select GENERIC_ALLOCATOR - select DMA_SHARED_BUFFER - ---help--- - Chose this option to enable the ION Memory Manager, - used by Android to efficiently allocate buffers - from userspace that can be shared between drivers. - If you're not using Android its probably safe to - say N here. - -config ION_TEST - tristate "Ion Test Device" - depends on ION - help - Choose this option to create a device that can be used to test the - kernel and device side ION functions. - -config ION_DUMMY - bool "Dummy Ion driver" - depends on ION - help - Provides a dummy ION driver that registers the - /dev/ion device and some basic heaps. This can - be used for testing the ION infrastructure if - one doesn't have access to hardware drivers that - use ION. - -config ION_TEGRA - tristate "Ion for Tegra" - depends on ARCH_TEGRA && ION - help - Choose this option if you wish to use ion on an nVidia Tegra. - -config ION_HISI - tristate "Ion for Hisilicon" - depends on ARCH_HISI && ION - select ION_OF - help - Choose this option if you wish to use ion on Hisilicon Platform. - -source "drivers/staging/android/ion/hisilicon/Kconfig" - -config ION_OF - bool "Devicetree support for Ion" - depends on ION && OF_ADDRESS - help - Provides base support for defining Ion heaps in devicetree - and setting them up. Also includes functions for platforms - to parse the devicetree and expand for their own custom - extensions - - If using Ion and devicetree, you should say Y here diff --git a/src/linux/drivers/staging/android/ion/hisilicon/Kconfig b/src/linux/drivers/staging/android/ion/hisilicon/Kconfig deleted file mode 100644 index 2b4bd07..0000000 --- a/src/linux/drivers/staging/android/ion/hisilicon/Kconfig +++ /dev/null @@ -1,5 +0,0 @@ -config HI6220_ION - bool "Hi6220 ION Driver" - depends on ARCH_HISI && ION - help - Build the Hisilicon Hi6220 ion driver. diff --git a/src/linux/drivers/staging/board/Kconfig b/src/linux/drivers/staging/board/Kconfig deleted file mode 100644 index 3f287c4..0000000 --- a/src/linux/drivers/staging/board/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config STAGING_BOARD - bool "Staging Board Support" - depends on OF_ADDRESS && OF_IRQ && CLKDEV_LOOKUP - help - Select to enable per-board staging support code. - - If in doubt, say N here. - diff --git a/src/linux/drivers/staging/clocking-wizard/Kconfig b/src/linux/drivers/staging/clocking-wizard/Kconfig deleted file mode 100644 index 357af02..0000000 --- a/src/linux/drivers/staging/clocking-wizard/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -# -# Xilinx Clocking Wizard Driver -# - -config COMMON_CLK_XLNX_CLKWZRD - tristate "Xilinx Clocking Wizard" - depends on COMMON_CLK && OF - ---help--- - Support for the Xilinx Clocking Wizard IP core clock generator. diff --git a/src/linux/drivers/staging/comedi/Kconfig b/src/linux/drivers/staging/comedi/Kconfig deleted file mode 100644 index e7255f8..0000000 --- a/src/linux/drivers/staging/comedi/Kconfig +++ /dev/null @@ -1,1322 +0,0 @@ -config COMEDI - tristate "Data acquisition support (comedi)" - depends on m - ---help--- - Enable support for a wide range of data acquisition devices - for Linux. - -if COMEDI - -config COMEDI_DEBUG - bool "Comedi debugging" - ---help--- - This is an option for use by developers; most people should - say N here. This enables comedi core and driver debugging. - -config COMEDI_DEFAULT_BUF_SIZE_KB - int "Comedi default initial asynchronous buffer size in KiB" - default "2048" - ---help--- - This is the default asynchronous buffer size which is used for - commands running in the background in kernel space. This - defaults to 2048 KiB of memory so that a 16 channel card - running at 10 kHz has of 2-4 seconds of buffer. - -config COMEDI_DEFAULT_BUF_MAXSIZE_KB - int "Comedi default maximum asynchronous buffer size in KiB" - default "20480" - ---help--- - This is the default maximum asynchronous buffer size which can - be requested by a userspace program without root privileges. - This is set to 20480 KiB so that a fast I/O card with 16 - channels running at 100 kHz has 2-4 seconds of buffer. - -menuconfig COMEDI_MISC_DRIVERS - bool "Comedi misc drivers" - ---help--- - Enable comedi misc drivers to be built - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about misc non-hardware comedi drivers. - -if COMEDI_MISC_DRIVERS - -config COMEDI_BOND - tristate "Comedi device bonding support" - select COMEDI_KCOMEDILIB - ---help--- - Enable support for a driver to 'bond' (merge) multiple subdevices - from multiple devices together as one. - - Currently, it only handles digital I/O subdevices. - - To compile this driver as a module, choose M here: the module will be - called comedi_bond. - -config COMEDI_TEST - tristate "Fake waveform generator support" - ---help--- - Enable support for the fake waveform generator. - This driver is mainly for testing purposes, but can also be used to - generate sample waveforms on systems that don't have data acquisition - hardware. - - To compile this driver as a module, choose M here: the module will be - called comedi_test. - -config COMEDI_PARPORT - tristate "Parallel port support" - ---help--- - Enable support for the standard parallel port. - A cheap and easy way to get a few more digital I/O lines. Steal - additional parallel ports from old computers or your neighbors' - computers. - - To compile this driver as a module, choose M here: the module will be - called comedi_parport. - -config COMEDI_SERIAL2002 - tristate "Driver for serial connected hardware" - ---help--- - Enable support for serial connected hardware - - To compile this driver as a module, choose M here: the module will be - called serial2002. - -config COMEDI_SSV_DNP - tristate "SSV Embedded Systems DIL/Net-PC support" - depends on X86_32 || COMPILE_TEST - ---help--- - Enable support for SSV Embedded Systems DIL/Net-PC - - To compile this driver as a module, choose M here: the module will be - called ssv_dnp. - -endif # COMEDI_MISC_DRIVERS - -menuconfig COMEDI_ISA_DRIVERS - bool "Comedi ISA and PC/104 drivers" - ---help--- - Enable comedi ISA and PC/104 drivers to be built - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about ISA and PC/104 comedi drivers. - -if COMEDI_ISA_DRIVERS - -config COMEDI_PCL711 - tristate "Advantech PCL-711/711b and ADlink ACL-8112 ISA card support" - select COMEDI_8254 - ---help--- - Enable support for Advantech PCL-711 and 711b, ADlink ACL-8112 - - To compile this driver as a module, choose M here: the module will be - called pcl711. - -config COMEDI_PCL724 - tristate "Advantech PCL-722/724/731 and ADlink ACL-7122/7124/PET-48DIO" - select COMEDI_8255 - ---help--- - Enable support for ISA and PC/104 based 8255 digital i/o boards. This - driver provides a legacy comedi driver wrapper for the generic 8255 - support driver. - - Supported boards include: - Advantech PCL-724 24 channels - Advantech PCL-722 144 (or 96) channels - Advantech PCL-731 48 channels - ADlink ACL-7122 144 (or 96) channels - ADlink ACL-7124 24 channels - ADlink PET-48DIO 48 channels - WinSystems PCM-IO48 48 channels (PC/104) - Diamond Systems ONYX-MM-DIO 48 channels (PC/104) - - To compile this driver as a module, choose M here: the module will be - called pcl724. - -config COMEDI_PCL726 - tristate "Advantech PCL-726 and compatible ISA card support" - ---help--- - Enable support for Advantech PCL-726 and compatible ISA cards. - - To compile this driver as a module, choose M here: the module will be - called pcl726. - -config COMEDI_PCL730 - tristate "Simple Digital I/O board support (8-bit ports)" - ---help--- - Enable support for various simple ISA or PC/104 Digital I/O boards. - These boards all use 8-bit I/O ports. - - Advantech PCL-730 iso - 16 in/16 out ttl - 16 in/16 out - ICP ISO-730 iso - 16 in/16 out ttl - 16 in/16 out - ADlink ACL-7130 iso - 16 in/16 out ttl - 16 in/16 out - Advantech PCM-3730 iso - 8 in/8 out ttl - 16 in/16 out - Advantech PCL-725 iso - 8 in/8 out - ICP P8R8-DIO iso - 8 in/8 out - ADlink ACL-7225b iso - 16 in/16 out - ICP P16R16-DIO iso - 16 in/16 out - Advantech PCL-733 iso - 32 in - Advantech PCL-734 iso - 32 out - Diamond Systems OPMM-1616-XT iso - 16 in/16 out - Diamond Systems PEARL-MM-P iso - 16 out - Diamond Systems IR104-PBF iso - 20 in/20 out - - To compile this driver as a module, choose M here: the module will be - called pcl730. - -config COMEDI_PCL812 - tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216" - select COMEDI_ISADMA if ISA_DMA_API - select COMEDI_8254 - ---help--- - Enable support for Advantech PCL-812/PG, PCL-813/B, ADLink - ACL-8112DG/HG/PG, ACL-8113, ACL-8216, ICP DAS A-821PGH/PGL/PGL-NDA, - A-822PGH/PGL, A-823PGH/PGL, A-826PG and ICP DAS ISO-813 ISA cards - - To compile this driver as a module, choose M here: the module will be - called pcl812. - -config COMEDI_PCL816 - tristate "Advantech PCL-814 and PCL-816 ISA card support" - select COMEDI_ISADMA if ISA_DMA_API - select COMEDI_8254 - ---help--- - Enable support for Advantech PCL-814 and PCL-816 ISA cards - - To compile this driver as a module, choose M here: the module will be - called pcl816. - -config COMEDI_PCL818 - tristate "Advantech PCL-718 and PCL-818 ISA card support" - select COMEDI_ISADMA if ISA_DMA_API - select COMEDI_8254 - ---help--- - Enable support for Advantech PCL-818 ISA cards - PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818 and PCL-718 - - To compile this driver as a module, choose M here: the module will be - called pcl818. - -config COMEDI_PCM3724 - tristate "Advantech PCM-3724 PC/104 card support" - select COMEDI_8255 - ---help--- - Enable support for Advantech PCM-3724 PC/104 cards. - - To compile this driver as a module, choose M here: the module will be - called pcm3724. - -config COMEDI_AMPLC_DIO200_ISA - tristate "Amplicon PC212E/PC214E/PC215E/PC218E/PC272E" - select COMEDI_AMPLC_DIO200 - ---help--- - Enable support for Amplicon PC212E, PC214E, PC215E, PC218E and - PC272E ISA DIO boards - - To compile this driver as a module, choose M here: the module will be - called amplc_dio200. - -config COMEDI_AMPLC_PC236_ISA - tristate "Amplicon PC36AT DIO board support" - select COMEDI_AMPLC_PC236 - ---help--- - Enable support for Amplicon PC36AT ISA DIO board. - - To compile this driver as a module, choose M here: the module will be - called amplc_pc236. - -config COMEDI_AMPLC_PC263_ISA - tristate "Amplicon PC263 relay board support" - ---help--- - Enable support for Amplicon PC263 ISA relay board. This board has - 16 reed relay output channels. - - To compile this driver as a module, choose M here: the module will be - called amplc_pc263. - -config COMEDI_RTI800 - tristate "Analog Devices RTI-800/815 ISA card support" - ---help--- - Enable support for Analog Devices RTI-800/815 ISA cards - - To compile this driver as a module, choose M here: the module will be - called rti800. - -config COMEDI_RTI802 - tristate "Analog Devices RTI-802 ISA card support" - ---help--- - Enable support for Analog Devices RTI-802 ISA cards - - To compile this driver as a module, choose M here: the module will be - called rti802. - -config COMEDI_DAC02 - tristate "Keithley Metrabyte DAC02 compatible ISA card support" - ---help--- - Enable support for Keithley Metrabyte DAC02 compatible ISA cards. - - To compile this driver as a module, choose M here: the module will be - called dac02. - -config COMEDI_DAS16M1 - tristate "MeasurementComputing CIO-DAS16/M1DAS-16 ISA card support" - select COMEDI_8254 - select COMEDI_8255 - ---help--- - Enable support for Measurement Computing CIO-DAS16/M1 ISA cards. - - To compile this driver as a module, choose M here: the module will be - called das16m1. - -config COMEDI_DAS08_ISA - tristate "DAS-08 compatible ISA and PC/104 card support" - select COMEDI_DAS08 - ---help--- - Enable support for Keithley Metrabyte/ComputerBoards DAS08 - and compatible ISA and PC/104 cards: - Keithley Metrabyte/ComputerBoards DAS08, DAS08-PGM, DAS08-PGH, - DAS08-PGL, DAS08-AOH, DAS08-AOL, DAS08-AOM, DAS08/JR-AO, - DAS08/JR-16-AO, PC104-DAS08, DAS08/JR/16. - - To compile this driver as a module, choose M here: the module will be - called das08_isa. - -config COMEDI_DAS16 - tristate "DAS-16 compatible ISA and PC/104 card support" - select COMEDI_ISADMA if ISA_DMA_API - select COMEDI_8254 - select COMEDI_8255 - ---help--- - Enable support for Keithley Metrabyte/ComputerBoards DAS16 - and compatible ISA and PC/104 cards: - Keithley Metrabyte DAS-16, DAS-16G, DAS-16F, DAS-1201, DAS-1202, - DAS-1401, DAS-1402, DAS-1601, DAS-1602 and - ComputerBoards/MeasurementComputing PC104-DAS16/JR/, - PC104-DAS16JR/16, CIO-DAS16JR/16, CIO-DAS16/JR, CIO-DAS1401/12, - CIO-DAS1402/12, CIO-DAS1402/16, CIO-DAS1601/12, CIO-DAS1602/12, - CIO-DAS1602/16, CIO-DAS16/330 - - To compile this driver as a module, choose M here: the module will be - called das16. - -config COMEDI_DAS800 - tristate "DAS800 and compatible ISA card support" - select COMEDI_8254 - ---help--- - Enable support for Keithley Metrabyte DAS800 and compatible ISA cards - Keithley Metrabyte DAS-800, DAS-801, DAS-802 - Measurement Computing CIO-DAS800, CIO-DAS801, CIO-DAS802 and - CIO-DAS802/16 - - To compile this driver as a module, choose M here: the module will be - called das800. - -config COMEDI_DAS1800 - tristate "DAS1800 and compatible ISA card support" - select COMEDI_ISADMA if ISA_DMA_API - select COMEDI_8254 - ---help--- - Enable support for DAS1800 and compatible ISA cards - Keithley Metrabyte DAS-1701ST, DAS-1701ST-DA, DAS-1701/AO, - DAS-1702ST, DAS-1702ST-DA, DAS-1702HR, DAS-1702HR-DA, DAS-1702/AO, - DAS-1801ST, DAS-1801ST-DA, DAS-1801HC, DAS-1801AO, DAS-1802ST, - DAS-1802ST-DA, DAS-1802HR, DAS-1802HR-DA, DAS-1802HC and - DAS-1802AO - - To compile this driver as a module, choose M here: the module will be - called das1800. - -config COMEDI_DAS6402 - tristate "DAS6402 and compatible ISA card support" - select COMEDI_8254 - ---help--- - Enable support for DAS6402 and compatible ISA cards - Computerboards, Keithley Metrabyte DAS6402 and compatibles - - To compile this driver as a module, choose M here: the module will be - called das6402. - -config COMEDI_DT2801 - tristate "Data Translation DT2801 ISA card support" - ---help--- - Enable support for Data Translation DT2801 ISA cards - - To compile this driver as a module, choose M here: the module will be - called dt2801. - -config COMEDI_DT2811 - tristate "Data Translation DT2811 ISA card support" - ---help--- - Enable support for Data Translation DT2811 ISA cards - - To compile this driver as a module, choose M here: the module will be - called dt2811. - -config COMEDI_DT2814 - tristate "Data Translation DT2814 ISA card support" - ---help--- - Enable support for Data Translation DT2814 ISA cards - - To compile this driver as a module, choose M here: the module will be - called dt2814. - -config COMEDI_DT2815 - tristate "Data Translation DT2815 ISA card support" - ---help--- - Enable support for Data Translation DT2815 ISA cards - - To compile this driver as a module, choose M here: the module will be - called dt2815. - -config COMEDI_DT2817 - tristate "Data Translation DT2817 ISA card support" - ---help--- - Enable support for Data Translation DT2817 ISA cards - - To compile this driver as a module, choose M here: the module will be - called dt2817. - -config COMEDI_DT282X - tristate "Data Translation DT2821 series and DT-EZ ISA card support" - select COMEDI_ISADMA if ISA_DMA_API - ---help--- - Enable support for Data Translation DT2821 series including DT-EZ - DT2821, DT2821-F-16SE, DT2821-F-8DI, DT2821-G-16SE, DT2821-G-8DI, - DT2823 (dt2823), DT2824-PGH, DT2824-PGL, DT2825, DT2827, DT2828, - DT21-EZ, DT23-EZ, DT24-EZ and DT24-EZ-PGL - - To compile this driver as a module, choose M here: the module will be - called dt282x. - -config COMEDI_DMM32AT - tristate "Diamond Systems MM-32-AT PC/104 board support" - select COMEDI_8255 - ---help--- - Enable support for Diamond Systems MM-32-AT PC/104 boards - - To compile this driver as a module, choose M here: the module will be - called dmm32at. - -config COMEDI_FL512 - tristate "FL512 ISA card support" - ---help--- - Enable support for FL512 ISA card - - To compile this driver as a module, choose M here: the module will be - called fl512. - -config COMEDI_AIO_AIO12_8 - tristate "I/O Products PC/104 AIO12-8 Analog I/O Board support" - select COMEDI_8254 - select COMEDI_8255 - ---help--- - Enable support for I/O Products PC/104 AIO12-8 Analog I/O Board - - To compile this driver as a module, choose M here: the module will be - called aio_aio12_8. - -config COMEDI_AIO_IIRO_16 - tristate "I/O Products PC/104 IIRO16 Board support" - ---help--- - Enable support for I/O Products PC/104 IIRO16 Relay And Isolated - Input Board - - To compile this driver as a module, choose M here: the module will be - called aio_iiro_16. - -config COMEDI_II_PCI20KC - tristate "Intelligent Instruments PCI-20001C carrier support" - depends on HAS_IOMEM - ---help--- - Enable support for Intelligent Instruments PCI-20001C carrier - PCI-20001, PCI-20006 and PCI-20341 - - To compile this driver as a module, choose M here: the module will be - called ii_pci20kc. - -config COMEDI_C6XDIGIO - tristate "Mechatronic Systems Inc. C6x_DIGIO DSP daughter card support" - ---help--- - Enable support for Mechatronic Systems Inc. C6x_DIGIO DSP daughter - card - - To compile this driver as a module, choose M here: the module will be - called c6xdigio. - -config COMEDI_MPC624 - tristate "Micro/sys MPC-624 PC/104 board support" - ---help--- - Enable support for Micro/sys MPC-624 PC/104 board - - To compile this driver as a module, choose M here: the module will be - called mpc624. - -config COMEDI_ADQ12B - tristate "MicroAxial ADQ12-B data acquisition and control card support" - ---help--- - Enable MicroAxial ADQ12-B daq and control card support. - - To compile this driver as a module, choose M here: the module will be - called adq12b. - -config COMEDI_NI_AT_A2150 - tristate "NI AT-A2150 ISA card support" - select COMEDI_ISADMA if ISA_DMA_API - select COMEDI_8254 - ---help--- - Enable support for National Instruments AT-A2150 cards - - To compile this driver as a module, choose M here: the module will be - called ni_at_a2150. - -config COMEDI_NI_AT_AO - tristate "NI AT-AO-6/10 EISA card support" - select COMEDI_8254 - ---help--- - Enable support for National Instruments AT-AO-6/10 cards - - To compile this driver as a module, choose M here: the module will be - called ni_at_ao. - -config COMEDI_NI_ATMIO - tristate "NI AT-MIO E series ISA-PNP card support" - select COMEDI_8255 - select COMEDI_NI_TIO - ---help--- - Enable support for National Instruments AT-MIO E series cards - National Instruments AT-MIO-16E-1 (ni_atmio), - AT-MIO-16E-2, AT-MIO-16E-10, AT-MIO-16DE-10, AT-MIO-64E-3, - AT-MIO-16XE-50, AT-MIO-16XE-10, AT-AI-16XE-10 - - To compile this driver as a module, choose M here: the module will be - called ni_atmio. - -config COMEDI_NI_ATMIO16D - tristate "NI AT-MIO-16/AT-MIO-16D series ISA card support" - select COMEDI_8255 - ---help--- - Enable support for National Instruments AT-MIO-16/AT-MIO-16D cards. - - To compile this driver as a module, choose M here: the module will be - called ni_atmio16d. - -config COMEDI_NI_LABPC_ISA - tristate "NI Lab-PC and compatibles ISA support" - select COMEDI_NI_LABPC - select COMEDI_NI_LABPC_ISADMA if ISA_DMA_API - ---help--- - Enable support for National Instruments Lab-PC and compatibles - Lab-PC-1200, Lab-PC-1200AI, Lab-PC+. - Kernel-level ISA plug-and-play support for the lab-pc-1200 boards has - not yet been added to the driver. - - To compile this driver as a module, choose M here: the module will be - called ni_labpc. - -config COMEDI_PCMAD - tristate "Winsystems PCM-A/D12 and PCM-A/D16 PC/104 board support" - ---help--- - Enable support for Winsystems PCM-A/D12 and PCM-A/D16 PC/104 boards. - - To compile this driver as a module, choose M here: the module will be - called pcmad. - -config COMEDI_PCMDA12 - tristate "Winsystems PCM-D/A-12 8-channel AO PC/104 board support" - ---help--- - Enable support for Winsystems PCM-D/A-12 8-channel AO PC/104 boards. - Note that the board is not ISA-PNP capable and thus needs the I/O - port comedi_config parameter. - - To compile this driver as a module, choose M here: the module will be - called pcmda12. - -config COMEDI_PCMMIO - tristate "Winsystems PCM-MIO PC/104 board support" - ---help--- - Enable support for Winsystems PCM-MIO multifunction PC/104 boards. - - To compile this driver as a module, choose M here: the module will be - called pcmmio. - -config COMEDI_PCMUIO - tristate "Winsystems PCM-UIO48A and PCM-UIO96A PC/104 board support" - ---help--- - Enable support for PCM-UIO48A and PCM-UIO96A PC/104 boards. - - To compile this driver as a module, choose M here: the module will be - called pcmuio. - -config COMEDI_MULTIQ3 - tristate "Quanser Consulting MultiQ-3 ISA card support" - ---help--- - Enable support for Quanser Consulting MultiQ-3 ISA cards - - To compile this driver as a module, choose M here: the module will be - called multiq3. - -config COMEDI_S526 - tristate "Sensoray s526 support" - ---help--- - Enable support for Sensoray s526 - - To compile this driver as a module, choose M here: the module will be - called s526. - -endif # COMEDI_ISA_DRIVERS - -menuconfig COMEDI_PCI_DRIVERS - tristate "Comedi PCI drivers" - depends on PCI - ---help--- - Enable support for comedi PCI drivers. - - To compile this support as a module, choose M here: the module will - be called comedi_pci. - -if COMEDI_PCI_DRIVERS - -config COMEDI_8255_PCI - tristate "Generic PCI based 8255 digital i/o board support" - select COMEDI_8255 - ---help--- - Enable support for PCI based 8255 digital i/o boards. This driver - provides a PCI wrapper around the generic 8255 driver. - - Supported boards: - ADlink - PCI-7224, PCI-7248, and PCI-7296 - Measurement Computing - PCI-DIO24, PCI-DIO24H, PCI-DIO48H and - PCI-DIO96H - National Instruments - PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503, - PCI-6503B, PCI-6503X, and PXI-6503 - - To compile this driver as a module, choose M here: the module will - be called 8255_pci. - -config COMEDI_ADDI_WATCHDOG - tristate - ---help--- - Provides support for the watchdog subdevice found on many ADDI-DATA - boards. This module will be automatically selected when needed. The - module will be called addi_watchdog. - -config COMEDI_ADDI_APCI_1032 - tristate "ADDI-DATA APCI_1032 support" - ---help--- - Enable support for ADDI-DATA APCI_1032 cards - - To compile this driver as a module, choose M here: the module will be - called addi_apci_1032. - -config COMEDI_ADDI_APCI_1500 - tristate "ADDI-DATA APCI_1500 support" - ---help--- - Enable support for ADDI-DATA APCI_1500 cards - - To compile this driver as a module, choose M here: the module will be - called addi_apci_1500. - -config COMEDI_ADDI_APCI_1516 - tristate "ADDI-DATA APCI-1016/1516/2016 support" - select COMEDI_ADDI_WATCHDOG - ---help--- - Enable support for ADDI-DATA APCI-1016, APCI-1516 and APCI-2016 boards. - These are 16 channel, optically isolated, digital I/O boards. The 1516 - and 2016 boards also have a watchdog for resetting the outputs to "0". - - To compile this driver as a module, choose M here: the module will be - called addi_apci_1516. - -config COMEDI_ADDI_APCI_1564 - tristate "ADDI-DATA APCI_1564 support" - select COMEDI_ADDI_WATCHDOG - ---help--- - Enable support for ADDI-DATA APCI_1564 cards - - To compile this driver as a module, choose M here: the module will be - called addi_apci_1564. - -config COMEDI_ADDI_APCI_16XX - tristate "ADDI-DATA APCI_16xx support" - ---help--- - Enable support for ADDI-DATA APCI_16xx cards - - To compile this driver as a module, choose M here: the module will be - called addi_apci_16xx. - -config COMEDI_ADDI_APCI_2032 - tristate "ADDI-DATA APCI_2032 support" - select COMEDI_ADDI_WATCHDOG - ---help--- - Enable support for ADDI-DATA APCI_2032 cards - - To compile this driver as a module, choose M here: the module will be - called addi_apci_2032. - -config COMEDI_ADDI_APCI_2200 - tristate "ADDI-DATA APCI_2200 support" - select COMEDI_ADDI_WATCHDOG - ---help--- - Enable support for ADDI-DATA APCI_2200 cards - - To compile this driver as a module, choose M here: the module will be - called addi_apci_2200. - -config COMEDI_ADDI_APCI_3120 - tristate "ADDI-DATA APCI_3120/3001 support" - depends on HAS_DMA - ---help--- - Enable support for ADDI-DATA APCI_3120/3001 cards - - To compile this driver as a module, choose M here: the module will be - called addi_apci_3120. - -config COMEDI_ADDI_APCI_3501 - tristate "ADDI-DATA APCI_3501 support" - ---help--- - Enable support for ADDI-DATA APCI_3501 cards - - To compile this driver as a module, choose M here: the module will be - called addi_apci_3501. - -config COMEDI_ADDI_APCI_3XXX - tristate "ADDI-DATA APCI_3xxx support" - ---help--- - Enable support for ADDI-DATA APCI_3xxx cards - - To compile this driver as a module, choose M here: the module will be - called addi_apci_3xxx. - -config COMEDI_ADL_PCI6208 - tristate "ADLink PCI-6208A support" - ---help--- - Enable support for ADLink PCI-6208A cards - - To compile this driver as a module, choose M here: the module will be - called adl_pci6208. - -config COMEDI_ADL_PCI7X3X - tristate "ADLink PCI-723X/743X isolated digital i/o board support" - ---help--- - Enable support for ADlink PCI-723X/743X isolated digital i/o boards. - Supported boards include the 32-channel PCI-7230 (16 in/16 out), - PCI-7233 (32 in), and PCI-7234 (32 out) as well as the 64-channel - PCI-7432 (32 in/32 out), PCI-7433 (64 in), and PCI-7434 (64 out). - - To compile this driver as a module, choose M here: the module will be - called adl_pci7x3x. - -config COMEDI_ADL_PCI8164 - tristate "ADLink PCI-8164 4 Axes Motion Control board support" - ---help--- - Enable support for ADlink PCI-8164 4 Axes Motion Control board - - To compile this driver as a module, choose M here: the module will be - called adl_pci8164. - -config COMEDI_ADL_PCI9111 - tristate "ADLink PCI-9111HR support" - select COMEDI_8254 - ---help--- - Enable support for ADlink PCI9111 cards - - To compile this driver as a module, choose M here: the module will be - called adl_pci9111. - -config COMEDI_ADL_PCI9118 - tristate "ADLink PCI-9118DG, PCI-9118HG, PCI-9118HR support" - depends on HAS_DMA - select COMEDI_8254 - ---help--- - Enable support for ADlink PCI-9118DG, PCI-9118HG, PCI-9118HR cards - - To compile this driver as a module, choose M here: the module will be - called adl_pci9118. - -config COMEDI_ADV_PCI1710 - tristate "Advantech PCI-171x and PCI-1731 support" - select COMEDI_8254 - ---help--- - Enable support for Advantech PCI-1710, PCI-1710HG, PCI-1711, - PCI-1713 and PCI-1731 - - To compile this driver as a module, choose M here: the module will be - called adv_pci1710. - -config COMEDI_ADV_PCI1720 - tristate "Advantech PCI-1720 support" - ---help--- - Enable support for Advantech PCI-1720 Analog Output board. - - To compile this driver as a module, choose M here: the module will be - called adv_pci1720. - -config COMEDI_ADV_PCI1723 - tristate "Advantech PCI-1723 support" - ---help--- - Enable support for Advantech PCI-1723 cards - - To compile this driver as a module, choose M here: the module will be - called adv_pci1723. - -config COMEDI_ADV_PCI1724 - tristate "Advantech PCI-1724U support" - ---help--- - Enable support for Advantech PCI-1724U cards. These are 32-channel - analog output cards with voltage and current loop output ranges and - 14-bit resolution. - - To compile this driver as a module, choose M here: the module will be - called adv_pci1724. - -config COMEDI_ADV_PCI1760 - tristate "Advantech PCI-1760 support" - ---help--- - Enable support for Advantech PCI-1760 board. - - To compile this driver as a module, choose M here: the module will be - called adv_pci1760. - -config COMEDI_ADV_PCI_DIO - tristate "Advantech PCI DIO card support" - select COMEDI_8254 - select COMEDI_8255 - ---help--- - Enable support for Advantech PCI DIO cards - PCI-1730, PCI-1733, PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U, - PCI-1750, PCI-1751, PCI-1752, PCI-1753/E, PCI-1754, PCI-1756 and - PCI-1762 - - To compile this driver as a module, choose M here: the module will be - called adv_pci_dio. - -config COMEDI_AMPLC_DIO200_PCI - tristate "Amplicon PCI215/PCI272/PCIe215/PCIe236/PCIe296 DIO support" - select COMEDI_AMPLC_DIO200 - ---help--- - Enable support for Amplicon PCI215, PCI272, PCIe215, PCIe236 - and PCIe296 DIO boards. - - To compile this driver as a module, choose M here: the module will be - called amplc_dio200_pci. - -config COMEDI_AMPLC_PC236_PCI - tristate "Amplicon PCI236 DIO board support" - select COMEDI_AMPLC_PC236 - ---help--- - Enable support for Amplicon PCI236 DIO board. - - To compile this driver as a module, choose M here: the module will be - called amplc_pci236. - -config COMEDI_AMPLC_PC263_PCI - tristate "Amplicon PCI263 relay board support" - ---help--- - Enable support for Amplicon PCI263 relay board. This is a PCI board - with 16 reed relay output channels. - - To compile this driver as a module, choose M here: the module will be - called amplc_pci263. - -config COMEDI_AMPLC_PCI224 - tristate "Amplicon PCI224 and PCI234 support" - select COMEDI_8254 - ---help--- - Enable support for Amplicon PCI224 and PCI234 AO boards - - To compile this driver as a module, choose M here: the module will be - called amplc_pci224. - -config COMEDI_AMPLC_PCI230 - tristate "Amplicon PCI230 and PCI260 support" - select COMEDI_8254 - select COMEDI_8255 - ---help--- - Enable support for Amplicon PCI230 and PCI260 Multifunction I/O - boards - - To compile this driver as a module, choose M here: the module will be - called amplc_pci230. - -config COMEDI_CONTEC_PCI_DIO - tristate "Contec PIO1616L digital I/O board support" - ---help--- - Enable support for the Contec PIO1616L digital I/O board - - To compile this driver as a module, choose M here: the module will be - called contec_pci_dio. - -config COMEDI_DAS08_PCI - tristate "DAS-08 PCI support" - select COMEDI_DAS08 - ---help--- - Enable support for PCI DAS-08 cards. - - To compile this driver as a module, choose M here: the module will be - called das08_pci. - -config COMEDI_DT3000 - tristate "Data Translation DT3000 series support" - ---help--- - Enable support for Data Translation DT3000 series - DT3001, DT3001-PGL, DT3002, DT3003, DT3003-PGL, DT3004, DT3005 and - DT3004-200 - - To compile this driver as a module, choose M here: the module will be - called dt3000. - -config COMEDI_DYNA_PCI10XX - tristate "Dynalog PCI DAQ series support" - ---help--- - Enable support for Dynalog PCI DAQ series - PCI-1050 - - To compile this driver as a module, choose M here: the module will be - called dyna_pci10xx. - -config COMEDI_GSC_HPDI - tristate "General Standards PCI-HPDI32 / PMC-HPDI32 support" - ---help--- - Enable support for General Standards Corporation high speed parallel - digital interface rs485 boards PCI-HPDI32 and PMC-HPDI32. - Only receive mode works, transmit not supported. - - To compile this driver as a module, choose M here: the module will be - called gsc_hpdi. - -config COMEDI_MF6X4 - tristate "Humusoft MF634 and MF624 DAQ Card support" - ---help--- - This driver supports both Humusoft MF634 and MF624 Data acquisition - cards. The legacy Humusoft MF614 card is not supported. - -config COMEDI_ICP_MULTI - tristate "Inova ICP_MULTI support" - ---help--- - Enable support for Inova ICP_MULTI card - - To compile this driver as a module, choose M here: the module will be - called icp_multi. - -config COMEDI_DAQBOARD2000 - tristate "IOtech DAQboard/2000 support" - select COMEDI_8255 - ---help--- - Enable support for the IOtech DAQboard/2000 - - To compile this driver as a module, choose M here: the module will be - called daqboard2000. - -config COMEDI_JR3_PCI - tristate "JR3/PCI force sensor board support" - ---help--- - Enable support for JR3/PCI force sensor boards - - To compile this driver as a module, choose M here: the module will be - called jr3_pci. - -config COMEDI_KE_COUNTER - tristate "Kolter-Electronic PCI Counter 1 card support" - ---help--- - Enable support for Kolter-Electronic PCI Counter 1 cards - - To compile this driver as a module, choose M here: the module will be - called ke_counter. - -config COMEDI_CB_PCIDAS64 - tristate "MeasurementComputing PCI-DAS 64xx, 60xx, and 4020 support" - select COMEDI_8255 - ---help--- - Enable support for ComputerBoards/MeasurementComputing PCI-DAS 64xx, - 60xx, and 4020 series with the PLX 9080 PCI controller - - To compile this driver as a module, choose M here: the module will be - called cb_pcidas64. - -config COMEDI_CB_PCIDAS - tristate "MeasurementComputing PCI-DAS support" - select COMEDI_8254 - select COMEDI_8255 - ---help--- - Enable support for ComputerBoards/MeasurementComputing PCI-DAS with - AMCC S5933 PCIcontroller: PCI-DAS1602/16, PCI-DAS1602/16jr, - PCI-DAS1602/12, PCI-DAS1200, PCI-DAS1200jr, PCI-DAS1000, PCI-DAS1001 - and PCI_DAS1002. - - To compile this driver as a module, choose M here: the module will be - called cb_pcidas. - -config COMEDI_CB_PCIDDA - tristate "MeasurementComputing PCI-DDA series support" - select COMEDI_8255 - ---help--- - Enable support for ComputerBoards/MeasurementComputing PCI-DDA - series: PCI-DDA08/12, PCI-DDA04/12, PCI-DDA02/12, PCI-DDA08/16, - PCI-DDA04/16 and PCI-DDA02/16 - - To compile this driver as a module, choose M here: the module will be - called cb_pcidda. - -config COMEDI_CB_PCIMDAS - tristate "MeasurementComputing PCIM-DAS1602/16, PCIe-DAS1602/16 support" - select COMEDI_8254 - select COMEDI_8255 - ---help--- - Enable support for ComputerBoards/MeasurementComputing PCI Migration - series PCIM-DAS1602/16 and PCIe-DAS1602/16. - - To compile this driver as a module, choose M here: the module will be - called cb_pcimdas. - -config COMEDI_CB_PCIMDDA - tristate "MeasurementComputing PCIM-DDA06-16 support" - select COMEDI_8255 - ---help--- - Enable support for ComputerBoards/MeasurementComputing PCIM-DDA06-16 - - To compile this driver as a module, choose M here: the module will be - called cb_pcimdda. - -config COMEDI_ME4000 - tristate "Meilhaus ME-4000 support" - select COMEDI_8254 - ---help--- - Enable support for Meilhaus PCI data acquisition cards - ME-4650, ME-4670i, ME-4680, ME-4680i and ME-4680is - - To compile this driver as a module, choose M here: the module will be - called me4000. - -config COMEDI_ME_DAQ - tristate "Meilhaus ME-2000i, ME-2600i, ME-3000vm1 support" - ---help--- - Enable support for Meilhaus PCI data acquisition cards - ME-2000i, ME-2600i and ME-3000vm1 - - To compile this driver as a module, choose M here: the module will be - called me_daq. - -config COMEDI_NI_6527 - tristate "NI 6527 support" - ---help--- - Enable support for the National Instruments 6527 PCI card - - To compile this driver as a module, choose M here: the module will be - called ni_6527. - -config COMEDI_NI_65XX - tristate "NI 65xx static dio PCI card support" - ---help--- - Enable support for National Instruments 65xx static dio boards. - Supported devices: National Instruments PCI-6509 (ni_65xx), - PXI-6509, PCI-6510, PCI-6511, PXI-6511, PCI-6512, PXI-6512, PCI-6513, - PXI-6513, PCI-6514, PXI-6514, PCI-6515, PXI-6515, PCI-6516, PCI-6517, - PCI-6518, PCI-6519, PCI-6520, PCI-6521, PXI-6521, PCI-6528, PXI-6528 - - To compile this driver as a module, choose M here: the module will be - called ni_65xx. - -config COMEDI_NI_660X - tristate "NI 660x counter/timer PCI card support" - depends on HAS_DMA - select COMEDI_NI_TIOCMD - ---help--- - Enable support for National Instruments PCI-6601 (ni_660x), PCI-6602, - PXI-6602, PXI-6608 and PXI-6624. - - To compile this driver as a module, choose M here: the module will be - called ni_660x. - -config COMEDI_NI_670X - tristate "NI 670x PCI card support" - ---help--- - Enable support for National Instruments PCI-6703 and PCI-6704 - - To compile this driver as a module, choose M here: the module will be - called ni_670x. - -config COMEDI_NI_LABPC_PCI - tristate "NI Lab-PC PCI-1200 support" - select COMEDI_NI_LABPC - ---help--- - Enable support for National Instruments Lab-PC PCI-1200. - - To compile this driver as a module, choose M here: the module will be - called ni_labpc_pci. - -config COMEDI_NI_PCIDIO - tristate "NI PCI-DIO32HS, PCI-6533, PCI-6534 support" - depends on HAS_DMA - select COMEDI_MITE - select COMEDI_8255 - ---help--- - Enable support for National Instruments PCI-DIO-32HS, PXI-6533, - PCI-6533 and PCI-6534 - - To compile this driver as a module, choose M here: the module will be - called ni_pcidio. - -config COMEDI_NI_PCIMIO - tristate "NI PCI-MIO-E series and M series support" - depends on HAS_DMA - select COMEDI_NI_TIOCMD - select COMEDI_8255 - ---help--- - Enable support for National Instruments PCI-MIO-E series and M series - (all boards): PCI-MIO-16XE-10, PXI-6030E, PCI-MIO-16E-1, - PCI-MIO-16E-4, PCI-6014, PCI-6040E, PXI-6040E, PCI-6030E, PCI-6031E, - PCI-6032E, PCI-6033E, PCI-6071E, PCI-6023E, PCI-6024E, PCI-6025E, - PXI-6025E, PCI-6034E, PCI-6035E, PCI-6052E, PCI-6110, PCI-6111, - PCI-6220, PCI-6221, PCI-6224, PXI-6224, PCI-6225, PXI-6225, PCI-6229, - PCI-6250, PCI-6251, PCIe-6251, PCI-6254, PCI-6259, PCIe-6259, - PCI-6280, PCI-6281, PXI-6281, PCI-6284, PCI-6289, PCI-6711, PXI-6711, - PCI-6713, PXI-6713, PXI-6071E, PCI-6070E, PXI-6070E, PXI-6052E, - PCI-6036E, PCI-6731, PCI-6733, PXI-6733, PCI-6143, PXI-6143 - - To compile this driver as a module, choose M here: the module will be - called ni_pcimio. - -config COMEDI_RTD520 - tristate "Real Time Devices PCI4520/DM7520 support" - select COMEDI_8254 - ---help--- - Enable support for Real Time Devices PCI4520/DM7520 - - To compile this driver as a module, choose M here: the module will be - called rtd520. - -config COMEDI_S626 - tristate "Sensoray 626 support" - ---help--- - Enable support for Sensoray 626 - - To compile this driver as a module, choose M here: the module will be - called s626. - -config COMEDI_MITE - depends on HAS_DMA - tristate - -config COMEDI_NI_TIOCMD - tristate - depends on HAS_DMA - select COMEDI_NI_TIO - select COMEDI_MITE - -endif # COMEDI_PCI_DRIVERS - -menuconfig COMEDI_PCMCIA_DRIVERS - tristate "Comedi PCMCIA drivers" - depends on PCMCIA - ---help--- - Enable support for comedi PCMCIA drivers. - - To compile this support as a module, choose M here: the module will - be called comedi_pcmcia. - -if COMEDI_PCMCIA_DRIVERS - -config COMEDI_CB_DAS16_CS - tristate "CB DAS16 series PCMCIA support" - select COMEDI_8254 - ---help--- - Enable support for the ComputerBoards/MeasurementComputing PCMCIA - cards DAS16/16, PCM-DAS16D/12 and PCM-DAS16s/16 - - To compile this driver as a module, choose M here: the module will be - called cb_das16_cs. - -config COMEDI_DAS08_CS - tristate "CB DAS08 PCMCIA support" - select COMEDI_DAS08 - ---help--- - Enable support for the ComputerBoards/MeasurementComputing DAS-08 - PCMCIA card - - To compile this driver as a module, choose M here: the module will be - called das08_cs. - -config COMEDI_NI_DAQ_700_CS - tristate "NI DAQCard-700 PCMCIA support" - ---help--- - Enable support for the National Instruments PCMCIA DAQCard-700 DIO - - To compile this driver as a module, choose M here: the module will be - called ni_daq_700. - -config COMEDI_NI_DAQ_DIO24_CS - tristate "NI DAQ-Card DIO-24 PCMCIA support" - select COMEDI_8255 - ---help--- - Enable support for the National Instruments PCMCIA DAQ-Card DIO-24 - - To compile this driver as a module, choose M here: the module will be - called ni_daq_dio24. - -config COMEDI_NI_LABPC_CS - tristate "NI DAQCard-1200 PCMCIA support" - select COMEDI_NI_LABPC - ---help--- - Enable support for the National Instruments PCMCIA DAQCard-1200 - - To compile this driver as a module, choose M here: the module will be - called ni_labpc_cs. - -config COMEDI_NI_MIO_CS - tristate "NI DAQCard E series PCMCIA support" - select COMEDI_NI_TIO - select COMEDI_8255 - ---help--- - Enable support for the National Instruments PCMCIA DAQCard E series - DAQCard-ai-16xe-50, DAQCard-ai-16e-4, DAQCard-6062E, DAQCard-6024E - and DAQCard-6036E - - To compile this driver as a module, choose M here: the module will be - called ni_mio_cs. - -config COMEDI_QUATECH_DAQP_CS - tristate "Quatech DAQP PCMCIA data capture card support" - ---help--- - Enable support for the Quatech DAQP PCMCIA data capture cards - DAQP-208 and DAQP-308 - - To compile this driver as a module, choose M here: the module will be - called quatech_daqp_cs. - -endif # COMEDI_PCMCIA_DRIVERS - -menuconfig COMEDI_USB_DRIVERS - tristate "Comedi USB drivers" - depends on USB - ---help--- - Enable support for comedi USB drivers. - - To compile this support as a module, choose M here: the module will - be called comedi_usb. - -if COMEDI_USB_DRIVERS - -config COMEDI_DT9812 - tristate "DataTranslation DT9812 USB module support" - ---help--- - Enable support for the Data Translation DT9812 USB module - - To compile this driver as a module, choose M here: the module will be - called dt9812. - -config COMEDI_NI_USB6501 - tristate "NI USB-6501 support" - ---help--- - Enable support for the National Instruments USB-6501 module. - - The NI USB-6501 is a Full-Speed USB 2.0 (12 Mbit/s) device that - provides 24 digital I/O lines channels and one 32-bit counter. - - To compile this driver as a module, choose M here: the module will be - called ni_usb6501. - -config COMEDI_USBDUX - tristate "ITL USB-DUX-D support" - ---help--- - Enable support for the Incite Technology Ltd USB-DUX-D Board - - To compile this driver as a module, choose M here: the module will be - called usbdux. - -config COMEDI_USBDUXFAST - tristate "ITL USB-DUXfast support" - ---help--- - Enable support for the Incite Technology Ltd USB-DUXfast Board - - To compile this driver as a module, choose M here: the module will be - called usbduxfast. - -config COMEDI_USBDUXSIGMA - tristate "ITL USB-DUXsigma support" - ---help--- - Enable support for the Incite Technology Ltd USB-DUXsigma Board - - To compile this driver as a module, choose M here: the module will be - called usbduxsigma. - -config COMEDI_VMK80XX - tristate "Velleman VM110/VM140 USB Board support" - ---help--- - Build the Velleman USB Board Low-Level Driver supporting the - K8055/K8061 aka VM110/VM140 devices - - To compile this driver as a module, choose M here: the module will be - called vmk80xx. - -endif # COMEDI_USB_DRIVERS - -config COMEDI_8254 - tristate - -config COMEDI_8255 - tristate - -config COMEDI_8255_SA - tristate "Standalone 8255 support" - select COMEDI_8255 - ---help--- - Enable support for 8255 digital I/O as a standalone driver. - - You should enable compilation this driver if you plan to use a board - that has an 8255 chip at a known I/O base address and there are no - other Comedi drivers for the board. - - Note that Comedi drivers for most multi-function boards incorporating - an 8255 chip use the 'comedi_8255' module. Most PCI-based 8255 - boards use the 8255_pci driver as a wrapper around the 'comedi_8255' - module. - - To compile this driver as a module, choose M here: the module will be - called 8255. - -config COMEDI_KCOMEDILIB - tristate "Comedi kcomedilib" - ---help--- - Build the kcomedilib. - - This is a kernel module used to open and manipulate Comedi devices - from within kernel code. It is currently only used by the - comedi_bond driver, and its functionality has been stripped down to - the needs of that driver, so is currently not very useful for - anything else. - - To compile kcomedilib as a module, choose M here: the module will be - called kcomedilib. - -config COMEDI_AMPLC_DIO200 - select COMEDI_8254 - tristate - -config COMEDI_AMPLC_PC236 - tristate - select COMEDI_8255 - -config COMEDI_DAS08 - tristate - select COMEDI_8254 - select COMEDI_8255 - -config COMEDI_ISADMA - tristate - -config COMEDI_NI_LABPC - tristate - select COMEDI_8254 - select COMEDI_8255 - -config COMEDI_NI_LABPC_ISADMA - tristate - select COMEDI_ISADMA - -config COMEDI_NI_TIO - tristate - -endif # COMEDI diff --git a/src/linux/drivers/staging/dgnc/Kconfig b/src/linux/drivers/staging/dgnc/Kconfig deleted file mode 100644 index 032c2a7..0000000 --- a/src/linux/drivers/staging/dgnc/Kconfig +++ /dev/null @@ -1,6 +0,0 @@ -config DGNC - tristate "Digi Neo and Classic PCI Products" - default n - depends on TTY && PCI - ---help--- - Driver for the Digi International Neo and Classic PCI based product line. diff --git a/src/linux/drivers/staging/emxx_udc/Kconfig b/src/linux/drivers/staging/emxx_udc/Kconfig deleted file mode 100644 index d757709..0000000 --- a/src/linux/drivers/staging/emxx_udc/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config USB_EMXX - tristate "EMXX USB Function Device Controller" - depends on USB_GADGET && (ARCH_SHMOBILE || (ARM && COMPILE_TEST)) - help - The Emma Mobile series of SoCs from Renesas Electronics and - former NEC Electronics include USB Function hardware. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "emxx_udc" and force all - gadget drivers to also be dynamically linked. diff --git a/src/linux/drivers/staging/fbtft/Kconfig b/src/linux/drivers/staging/fbtft/Kconfig deleted file mode 100644 index 6f5e824..0000000 --- a/src/linux/drivers/staging/fbtft/Kconfig +++ /dev/null @@ -1,210 +0,0 @@ -menuconfig FB_TFT - tristate "Support for small TFT LCD display modules" - depends on FB && SPI - depends on GPIOLIB || COMPILE_TEST - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - select FB_BACKLIGHT - -config FB_TFT_AGM1264K_FL - tristate "FB driver for the AGM1264K-FL LCD display" - depends on FB_TFT - help - Framebuffer support for the AGM1264K-FL LCD display (two Samsung KS0108 compatible chips) - -config FB_TFT_BD663474 - tristate "FB driver for the BD663474 LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for BD663474 - -config FB_TFT_HX8340BN - tristate "FB driver for the HX8340BN LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for HX8340BN - -config FB_TFT_HX8347D - tristate "FB driver for the HX8347D LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for HX8347D - -config FB_TFT_HX8353D - tristate "FB driver for the HX8353D LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for HX8353D - -config FB_TFT_HX8357D - tristate "FB driver for the HX8357D LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for HX8357D - -config FB_TFT_ILI9163 - tristate "FB driver for the ILI9163 LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for ILI9163 - -config FB_TFT_ILI9320 - tristate "FB driver for the ILI9320 LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for ILI9320 - -config FB_TFT_ILI9325 - tristate "FB driver for the ILI9325 LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for ILI9325 - -config FB_TFT_ILI9340 - tristate "FB driver for the ILI9340 LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for ILI9340 - -config FB_TFT_ILI9341 - tristate "FB driver for the ILI9341 LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for ILI9341 - -config FB_TFT_ILI9481 - tristate "FB driver for the ILI9481 LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for ILI9481 - -config FB_TFT_ILI9486 - tristate "FB driver for the ILI9486 LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for ILI9486 - -config FB_TFT_PCD8544 - tristate "FB driver for the PCD8544 LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for PCD8544 - -config FB_TFT_RA8875 - tristate "FB driver for the RA8875 LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for RA8875 - -config FB_TFT_S6D02A1 - tristate "FB driver for the S6D02A1 LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for S6D02A1 - -config FB_TFT_S6D1121 - tristate "FB driver for the S6D1211 LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for S6D1121 - -config FB_TFT_SSD1289 - tristate "FB driver for the SSD1289 LCD Controller" - depends on FB_TFT - help - Framebuffer support for SSD1289 - -config FB_TFT_SSD1305 - tristate "FB driver for the SSD1305 OLED Controller" - depends on FB_TFT - help - Framebuffer support for SSD1305 - -config FB_TFT_SSD1306 - tristate "FB driver for the SSD1306 OLED Controller" - depends on FB_TFT - help - Framebuffer support for SSD1306 - -config FB_TFT_SSD1325 - tristate "FB driver for the SSD1325 OLED Controller" - depends on FB_TFT - help - Framebuffer support for SSD1305 - -config FB_TFT_SSD1331 - tristate "FB driver for the SSD1331 LCD Controller" - depends on FB_TFT - help - Framebuffer support for SSD1331 - -config FB_TFT_SSD1351 - tristate "FB driver for the SSD1351 LCD Controller" - depends on FB_TFT - help - Framebuffer support for SSD1351 - -config FB_TFT_ST7735R - tristate "FB driver for the ST7735R LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for ST7735R - -config FB_TFT_ST7789V - tristate "FB driver for the ST7789V LCD Controller" - depends on FB_TFT - help - This enables generic framebuffer support for the Sitronix ST7789V - display controller. The controller is intended for small color - displays with a resolution of up to 320x240 pixels. - - Say Y if you have such a display that utilizes this controller. - -config FB_TFT_TINYLCD - tristate "FB driver for tinylcd.com display" - depends on FB_TFT - help - Custom Framebuffer support for tinylcd.com display - -config FB_TFT_TLS8204 - tristate "FB driver for the TLS8204 LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for TLS8204 - -config FB_TFT_UC1611 - tristate "FB driver for the UC1611 LCD controller" - depends on FB_TFT - help - Generic Framebuffer support for UC1611 - -config FB_TFT_UC1701 - tristate "FB driver for the UC1701 LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for UC1701 - -config FB_TFT_UPD161704 - tristate "FB driver for the uPD161704 LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for uPD161704 - -config FB_TFT_WATTEROTT - tristate "FB driver for the WATTEROTT LCD Controller" - depends on FB_TFT - help - Generic Framebuffer support for WATTEROTT - -config FB_FLEX - tristate "Generic FB driver for TFT LCD displays" - depends on FB_TFT - help - Generic Framebuffer support for TFT LCD displays. - -config FB_TFT_FBTFT_DEVICE - tristate "Module to for adding FBTFT devices" - depends on FB_TFT diff --git a/src/linux/drivers/staging/fsl-mc/Kconfig b/src/linux/drivers/staging/fsl-mc/Kconfig deleted file mode 100644 index 32df07b..0000000 --- a/src/linux/drivers/staging/fsl-mc/Kconfig +++ /dev/null @@ -1 +0,0 @@ -source "drivers/staging/fsl-mc/bus/Kconfig" diff --git a/src/linux/drivers/staging/fsl-mc/bus/Kconfig b/src/linux/drivers/staging/fsl-mc/bus/Kconfig deleted file mode 100644 index 1f95933..0000000 --- a/src/linux/drivers/staging/fsl-mc/bus/Kconfig +++ /dev/null @@ -1,25 +0,0 @@ -# -# Freescale Management Complex (MC) bus drivers -# -# Copyright (C) 2014 Freescale Semiconductor, Inc. -# -# This file is released under the GPLv2 -# - -config FSL_MC_BUS - bool "Freescale Management Complex (MC) bus driver" - depends on OF && ARM64 - select GENERIC_MSI_IRQ_DOMAIN - help - Driver to enable the bus infrastructure for the Freescale - QorIQ Management Complex (fsl-mc). The fsl-mc is a hardware - module of the QorIQ LS2 SoCs, that does resource management - for hardware building-blocks in the SoC that can be used - to dynamically create networking hardware objects such as - network interfaces (NICs), crypto accelerator instances, - or L2 switches. - - Only enable this option when building the kernel for - Freescale QorQIQ LS2xxxx SoCs. - - diff --git a/src/linux/drivers/staging/fwserial/Kconfig b/src/linux/drivers/staging/fwserial/Kconfig deleted file mode 100644 index 9c7c926..0000000 --- a/src/linux/drivers/staging/fwserial/Kconfig +++ /dev/null @@ -1,31 +0,0 @@ -config FIREWIRE_SERIAL - tristate "TTY over Firewire" - depends on FIREWIRE && TTY - help - This enables TTY over IEEE 1394, providing high-speed serial - connectivity to cabled peers. This driver implements a - ad-hoc transport protocol and is currently limited to - Linux-to-Linux communication. - - To compile this driver as a module, say M here: the module will - be called firewire-serial. - -if FIREWIRE_SERIAL - -config FWTTY_MAX_TOTAL_PORTS - int "Maximum number of serial ports supported" - default "64" - help - Set this to the maximum number of serial ports you want the - firewire-serial driver to support. - -config FWTTY_MAX_CARD_PORTS - int "Maximum number of serial ports supported per adapter" - range 0 FWTTY_MAX_TOTAL_PORTS - default "32" - help - Set this to the maximum number of serial ports each firewire - adapter supports. The actual number of serial ports registered - is set with the module parameter "ttys". - -endif diff --git a/src/linux/drivers/staging/gdm724x/Kconfig b/src/linux/drivers/staging/gdm724x/Kconfig deleted file mode 100644 index 0a1f090..0000000 --- a/src/linux/drivers/staging/gdm724x/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -# -# GCT GDM724x LTE driver configuration -# - -config LTE_GDM724X - tristate "GCT GDM724x LTE support" - depends on NET && USB && TTY && m - help - This driver supports GCT GDM724x LTE chip based USB modem devices. - It exposes 4 network devices to be used per PDN and 2 tty devices to be - used for AT commands and DM monitoring applications. - The modules will be called gdmulte.ko and gdmtty.ko - - GCT-ATCx can be used for AT Commands - GCT-DMx can be used for LTE protocol monitoring diff --git a/src/linux/drivers/staging/goldfish/Kconfig b/src/linux/drivers/staging/goldfish/Kconfig deleted file mode 100644 index 4e09460..0000000 --- a/src/linux/drivers/staging/goldfish/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config GOLDFISH_AUDIO - tristate "Goldfish AVD Audio Device" - depends on GOLDFISH - ---help--- - Emulated audio channel for the Goldfish Android Virtual Device - -config MTD_GOLDFISH_NAND - tristate "Goldfish NAND device" - depends on GOLDFISH - depends on MTD - help - Drives the emulated NAND flash device on the Google Goldfish - Android virtual device. diff --git a/src/linux/drivers/staging/greybus/Kconfig b/src/linux/drivers/staging/greybus/Kconfig deleted file mode 100644 index 50de2d7..0000000 --- a/src/linux/drivers/staging/greybus/Kconfig +++ /dev/null @@ -1,219 +0,0 @@ -menuconfig GREYBUS - tristate "Greybus support" - depends on SYSFS - ---help--- - This option enables the Greybus driver core. Greybus is an - hardware protocol that was designed to provide Unipro with a - sane application layer. It was originally designed for the - ARA project, a module phone system, but has shown up in other - phones, and can be tunneled over other busses in order to - control hardware devices. - - Say Y here to enable support for these types of drivers. - - To compile this code as a module, chose M here: the module - will be called greybus.ko - -if GREYBUS - -config GREYBUS_ES2 - tristate "Greybus ES3 USB host controller" - depends on USB - ---help--- - Select this option if you have a Toshiba ES3 USB device that - acts as a Greybus "host controller". This device is a bridge - from a USB device to a Unipro network. - - To compile this code as a module, chose M here: the module - will be called gb-es2.ko - -config GREYBUS_AUDIO - tristate "Greybus Audio Class driver" - depends on SOUND - ---help--- - Select this option if you have a device that follows the - Greybus Audio Class specification. - - To compile this code as a module, chose M here: the module - will be called gb-audio.ko - -config GREYBUS_BOOTROM - tristate "Greybus Bootrom Class driver" - ---help--- - Select this option if you have a device that follows the - Greybus Bootrom Class specification. - - To compile this code as a module, chose M here: the module - will be called gb-bootrom.ko - -config GREYBUS_CAMERA - tristate "Greybus Camera Class driver" - depends on MEDIA_SUPPORT && LEDS_CLASS_FLASH && BROKEN - ---help--- - Select this option if you have a device that follows the - Greybus Camera Class specification. - - To compile this code as a module, chose M here: the module - will be called gb-camera.ko - -config GREYBUS_FIRMWARE - tristate "Greybus Firmware Download Class driver" - depends on SPI - ---help--- - Select this option if you have a device that follows the - Greybus Firmware Download Class specification. - - To compile this code as a module, chose M here: the module - will be called gb-firmware.ko - -config GREYBUS_HID - tristate "Greybus HID Class driver" - depends on HID && INPUT - ---help--- - Select this option if you have a device that follows the - Greybus HID Class specification. - - To compile this code as a module, chose M here: the module - will be called gb-hid.ko - -config GREYBUS_LIGHT - tristate "Greybus LED Class driver" - depends on LEDS_CLASS - ---help--- - Select this option if you have a device that follows the - Greybus LED Class specification. - - To compile this code as a module, chose M here: the module - will be called gb-light.ko - -config GREYBUS_LOG - tristate "Greybus Debug Log Class driver" - ---help--- - Select this option if you have a device that follows the - Greybus Debug Log Class specification. - - To compile this code as a module, chose M here: the module - will be called gb-log.ko - -config GREYBUS_LOOPBACK - tristate "Greybus Loopback Class driver" - ---help--- - Select this option if you have a device that follows the - Greybus Debug Log Class specification. - - To compile this code as a module, chose M here: the module - will be called gb-log.ko - -config GREYBUS_POWER - tristate "Greybus Powersupply Class driver" - depends on POWER_SUPPLY - ---help--- - Select this option if you have a device that follows the - Greybus Powersupply Class specification. - - To compile this code as a module, chose M here: the module - will be called gb-power-supply.ko - -config GREYBUS_RAW - tristate "Greybus Raw Class driver" - ---help--- - Select this option if you have a device that follows the - Greybus Raw Class specification. - - To compile this code as a module, chose M here: the module - will be called gb-raw.ko - -config GREYBUS_VIBRATOR - tristate "Greybus Vibrator Motor Class driver" - ---help--- - Select this option if you have a device that follows the - Greybus Vibrator Motor Class specification. - - To compile this code as a module, chose M here: the module - will be called gb-vibrator.ko - -menuconfig GREYBUS_BRIDGED_PHY - tristate "Greybus Bridged PHY Class drivers" - ---help--- - Select this option to pick from a variety of Greybus Bridged - PHY class drivers. These drivers emulate a number of - different "traditional" busses by tunneling them over Greybus. - Examples of this include serial, SPI, USB, and others. - - To compile this code as a module, chose M here: the module - will be called gb-phy.ko - -if GREYBUS_BRIDGED_PHY - -config GREYBUS_GPIO - tristate "Greybus GPIO Bridged PHY driver" - depends on GPIOLIB - ---help--- - Select this option if you have a device that follows the - Greybus GPIO Bridged PHY Class specification. - - To compile this code as a module, chose M here: the module - will be called gb-gpio.ko - -config GREYBUS_I2C - tristate "Greybus I2C Bridged PHY driver" - depends on I2C - ---help--- - Select this option if you have a device that follows the - Greybus I2C Bridged PHY Class specification. - - To compile this code as a module, chose M here: the module - will be called gb-i2c.ko - -config GREYBUS_PWM - tristate "Greybus PWM Bridged PHY driver" - depends on PWM - ---help--- - Select this option if you have a device that follows the - Greybus PWM Bridged PHY Class specification. - - To compile this code as a module, chose M here: the module - will be called gb-pwm.ko - -config GREYBUS_SDIO - tristate "Greybus SDIO Bridged PHY driver" - depends on MMC - ---help--- - Select this option if you have a device that follows the - Greybus SDIO Bridged PHY Class specification. - - To compile this code as a module, chose M here: the module - will be called gb-sdio.ko - -config GREYBUS_SPI - tristate "Greybus SPI Bridged PHY driver" - depends on SPI - ---help--- - Select this option if you have a device that follows the - Greybus SPI Bridged PHY Class specification. - - To compile this code as a module, chose M here: the module - will be called gb-spi.ko - -config GREYBUS_UART - tristate "Greybus UART Bridged PHY driver" - depends on TTY - ---help--- - Select this option if you have a device that follows the - Greybus UART Bridged PHY Class specification. - - To compile this code as a module, chose M here: the module - will be called gb-uart.ko - -config GREYBUS_USB - tristate "Greybus USB Host Bridged PHY driver" - depends on USB - ---help--- - Select this option if you have a device that follows the - Greybus USB Host Bridged PHY Class specification. - - To compile this code as a module, chose M here: the module - will be called gb-usb.ko - -endif # GREYBUS_BRIDGED_PHY -endif # GREYBUS diff --git a/src/linux/drivers/staging/greybus/tools/.gitignore b/src/linux/drivers/staging/greybus/tools/.gitignore deleted file mode 100644 index 023654c..0000000 --- a/src/linux/drivers/staging/greybus/tools/.gitignore +++ /dev/null @@ -1 +0,0 @@ -loopback_test diff --git a/src/linux/drivers/staging/gs_fpgaboot/Kconfig b/src/linux/drivers/staging/gs_fpgaboot/Kconfig deleted file mode 100644 index 5506452..0000000 --- a/src/linux/drivers/staging/gs_fpgaboot/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -# -# "xilinx FPGA firmware download, fpgaboot" -# -config GS_FPGABOOT - tristate "Xilinx FPGA firmware download module" - default n - help - Xilinx FPGA firmware download module diff --git a/src/linux/drivers/staging/i4l/Kconfig b/src/linux/drivers/staging/i4l/Kconfig deleted file mode 100644 index 920216e..0000000 --- a/src/linux/drivers/staging/i4l/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# -# Old ISDN4Linux config -# -menu "Old ISDN4Linux (deprecated)" - depends on ISDN_I4L - -source "drivers/staging/i4l/icn/Kconfig" - -source "drivers/staging/i4l/pcbit/Kconfig" - -source "drivers/staging/i4l/act2000/Kconfig" - -endmenu diff --git a/src/linux/drivers/staging/i4l/act2000/Kconfig b/src/linux/drivers/staging/i4l/act2000/Kconfig deleted file mode 100644 index fa2673f..0000000 --- a/src/linux/drivers/staging/i4l/act2000/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config ISDN_DRV_ACT2000 - tristate "IBM Active 2000 support" - depends on ISA - help - Say Y here if you have an IBM Active 2000 ISDN card. In order to use - this card, additional firmware is necessary, which has to be loaded - into the card using a utility which is part of the latest - isdn4k-utils package. Please read the file - for more information. diff --git a/src/linux/drivers/staging/i4l/icn/Kconfig b/src/linux/drivers/staging/i4l/icn/Kconfig deleted file mode 100644 index 4534f21..0000000 --- a/src/linux/drivers/staging/i4l/icn/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config ISDN_DRV_ICN - tristate "ICN 2B and 4B support" - depends on ISA - help - This enables support for two kinds of ISDN-cards made by a German - company called ICN. 2B is the standard version for a single ISDN - line with two B-channels, 4B supports two ISDN lines. For running - this card, additional firmware is necessary, which has to be - downloaded into the card using a utility which is distributed - separately. See and - for more - information. diff --git a/src/linux/drivers/staging/i4l/pcbit/Kconfig b/src/linux/drivers/staging/i4l/pcbit/Kconfig deleted file mode 100644 index e9b2dd8..0000000 --- a/src/linux/drivers/staging/i4l/pcbit/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config ISDN_DRV_PCBIT - tristate "PCBIT-D support" - depends on ISA && (BROKEN || X86) - help - This enables support for the PCBIT ISDN-card. This card is - manufactured in Portugal by Octal. For running this card, - additional firmware is necessary, which has to be downloaded into - the card using a utility which is distributed separately. See - and - for more information. diff --git a/src/linux/drivers/staging/iio/Kconfig b/src/linux/drivers/staging/iio/Kconfig deleted file mode 100644 index 8abc1ab..0000000 --- a/src/linux/drivers/staging/iio/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -# -# Industrial I/O subsystem configuration -# -menu "IIO staging drivers" - depends on IIO - -source "drivers/staging/iio/accel/Kconfig" -source "drivers/staging/iio/adc/Kconfig" -source "drivers/staging/iio/addac/Kconfig" -source "drivers/staging/iio/cdc/Kconfig" -source "drivers/staging/iio/frequency/Kconfig" -source "drivers/staging/iio/gyro/Kconfig" -source "drivers/staging/iio/impedance-analyzer/Kconfig" -source "drivers/staging/iio/light/Kconfig" -source "drivers/staging/iio/meter/Kconfig" -source "drivers/staging/iio/resolver/Kconfig" -source "drivers/staging/iio/trigger/Kconfig" - -endmenu diff --git a/src/linux/drivers/staging/iio/accel/Kconfig b/src/linux/drivers/staging/iio/accel/Kconfig deleted file mode 100644 index 1c994b5..0000000 --- a/src/linux/drivers/staging/iio/accel/Kconfig +++ /dev/null @@ -1,64 +0,0 @@ -# -# Accelerometer drivers -# -menu "Accelerometers" - -config ADIS16201 - tristate "Analog Devices ADIS16201 Dual-Axis Digital Inclinometer and Accelerometer" - depends on SPI - select IIO_ADIS_LIB - select IIO_ADIS_LIB_BUFFER if IIO_BUFFER - help - Say Y here to build support for Analog Devices adis16201 dual-axis - digital inclinometer and accelerometer. - - To compile this driver as a module, say M here: the module will - be called adis16201. - -config ADIS16203 - tristate "Analog Devices ADIS16203 Programmable 360 Degrees Inclinometer" - depends on SPI - select IIO_ADIS_LIB - select IIO_ADIS_LIB_BUFFER if IIO_BUFFER - help - Say Y here to build support for Analog Devices adis16203 Programmable - 360 Degrees Inclinometer. - - To compile this driver as a module, say M here: the module will be - called adis16203. - -config ADIS16209 - tristate "Analog Devices ADIS16209 Dual-Axis Digital Inclinometer and Accelerometer" - depends on SPI - select IIO_ADIS_LIB - select IIO_ADIS_LIB_BUFFER if IIO_BUFFER - help - Say Y here to build support for Analog Devices adis16209 dual-axis digital inclinometer - and accelerometer. - - To compile this driver as a module, say M here: the module will be - called adis16209. - -config ADIS16240 - tristate "Analog Devices ADIS16240 Programmable Impact Sensor and Recorder" - depends on SPI - select IIO_ADIS_LIB - select IIO_ADIS_LIB_BUFFER if IIO_BUFFER - help - Say Y here to build support for Analog Devices adis16240 programmable - impact Sensor and recorder. - - To compile this driver as a module, say M here: the module will be - called adis16240. - -config SCA3000 - depends on IIO_BUFFER - depends on SPI - tristate "VTI SCA3000 series accelerometers" - help - Say Y here to build support for the VTI SCA3000 series of SPI - accelerometers. These devices use a hardware ring buffer. - - To compile this driver as a module, say M here: the module will be - called sca3000. -endmenu diff --git a/src/linux/drivers/staging/iio/adc/Kconfig b/src/linux/drivers/staging/iio/adc/Kconfig deleted file mode 100644 index deff899..0000000 --- a/src/linux/drivers/staging/iio/adc/Kconfig +++ /dev/null @@ -1,105 +0,0 @@ -# -# ADC drivers -# -menu "Analog to digital converters" - -config AD7606 - tristate "Analog Devices AD7606 ADC driver" - depends on GPIOLIB || COMPILE_TEST - depends on HAS_IOMEM - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for Analog Devices: - ad7606, ad7606-6, ad7606-4 analog to digital converters (ADC). - - To compile this driver as a module, choose M here: the - module will be called ad7606. - -config AD7606_IFACE_PARALLEL - tristate "parallel interface support" - depends on AD7606 - help - Say yes here to include parallel interface support on the AD7606 - ADC driver. - - To compile this driver as a module, choose M here: the - module will be called ad7606_parallel. - -config AD7606_IFACE_SPI - tristate "spi interface support" - depends on AD7606 - depends on SPI - help - Say yes here to include parallel interface support on the AD7606 - ADC driver. - - To compile this driver as a module, choose M here: the - module will be called ad7606_spi. - -config AD7780 - tristate "Analog Devices AD7780 and similar ADCs driver" - depends on SPI - depends on GPIOLIB || COMPILE_TEST - select AD_SIGMA_DELTA - help - Say yes here to build support for Analog Devices AD7170, AD7171, - AD7780 and AD7781 SPI analog to digital converters (ADC). - If unsure, say N (but it's safe to say "Y"). - - To compile this driver as a module, choose M here: the - module will be called ad7780. - -config AD7816 - tristate "Analog Devices AD7816/7/8 temperature sensor and ADC driver" - depends on SPI - depends on GPIOLIB || COMPILE_TEST - help - Say yes here to build support for Analog Devices AD7816/7/8 - temperature sensors and ADC. - -config AD7192 - tristate "Analog Devices AD7190 AD7192 AD7193 AD7195 ADC driver" - depends on SPI - select AD_SIGMA_DELTA - help - Say yes here to build support for Analog Devices AD7190, - AD7192, AD7193 or AD7195 SPI analog to digital converters (ADC). - If unsure, say N (but it's safe to say "Y"). - - To compile this driver as a module, choose M here: the - module will be called ad7192. - -config AD7280 - tristate "Analog Devices AD7280A Lithium Ion Battery Monitoring System" - depends on SPI - help - Say yes here to build support for Analog Devices AD7280A - Lithium Ion Battery Monitoring System. - - To compile this driver as a module, choose M here: the - module will be called ad7280a - -config LPC32XX_ADC - tristate "NXP LPC32XX ADC" - depends on ARCH_LPC32XX || COMPILE_TEST - depends on HAS_IOMEM - help - Say yes here to build support for the integrated ADC inside the - LPC32XX SoC. Note that this feature uses the same hardware as the - touchscreen driver, so you should either select only one of the two - drivers (lpc32xx_adc or lpc32xx_ts) or, in the OpenFirmware case, - activate only one via device tree selection. Provides direct access - via sysfs. - -config SPEAR_ADC - tristate "ST SPEAr ADC" - depends on PLAT_SPEAR || COMPILE_TEST - depends on HAS_IOMEM - help - Say yes here to build support for the integrated ADC inside the - ST SPEAr SoC. Provides direct access via sysfs. - - To compile this driver as a module, choose M here: the - module will be called spear_adc. -endmenu diff --git a/src/linux/drivers/staging/iio/addac/Kconfig b/src/linux/drivers/staging/iio/addac/Kconfig deleted file mode 100644 index ba18b84..0000000 --- a/src/linux/drivers/staging/iio/addac/Kconfig +++ /dev/null @@ -1,37 +0,0 @@ -# -# ADDAC drivers -# -menu "Analog digital bi-direction converters" - -config ADT7316 - tristate "Analog Devices ADT7316/7/8 ADT7516/7/9 temperature sensor, ADC and DAC driver" - depends on GPIOLIB || COMPILE_TEST - help - Say yes here to build support for Analog Devices ADT7316, ADT7317, ADT7318 - and ADT7516, ADT7517, ADT7519 temperature sensors, ADC and DAC. - - To compile this driver as a module, choose M here: the module will - be called adt7316. - -config ADT7316_SPI - tristate "support SPI bus connection" - depends on SPI && ADT7316 - default y - help - Say yes here to build SPI bus support for Analog Devices ADT7316/7/8 - and ADT7516/7/9. - - To compile this driver as a module, choose M here: the module will - be called adt7316_spi. - -config ADT7316_I2C - tristate "support I2C bus connection" - depends on I2C && ADT7316 - help - Say yes here to build I2C bus support for Analog Devices ADT7316/7/8 - and ADT7516/7/9. - - To compile this driver as a module, choose M here: the module will - be called adt7316_i2c. - -endmenu diff --git a/src/linux/drivers/staging/iio/cdc/Kconfig b/src/linux/drivers/staging/iio/cdc/Kconfig deleted file mode 100644 index 80211df..0000000 --- a/src/linux/drivers/staging/iio/cdc/Kconfig +++ /dev/null @@ -1,36 +0,0 @@ -# -# CDC drivers -# -menu "Capacitance to digital converters" - -config AD7150 - tristate "Analog Devices ad7150/1/6 capacitive sensor driver" - depends on I2C - help - Say yes here to build support for Analog Devices capacitive sensors. - (ad7150, ad7151, ad7156) Provides direct access via sysfs. - - To compile this driver as a module, choose M here: the - module will be called ad7150. - -config AD7152 - tristate "Analog Devices ad7152/3 capacitive sensor driver" - depends on I2C - help - Say yes here to build support for Analog Devices capacitive sensors. - (ad7152, ad7153) Provides direct access via sysfs. - - To compile this driver as a module, choose M here: the - module will be called ad7152. - -config AD7746 - tristate "Analog Devices AD7745, AD7746 AD7747 capacitive sensor driver" - depends on I2C - help - Say yes here to build support for Analog Devices capacitive sensors. - (AD7745, AD7746, AD7747) Provides direct access via sysfs. - - To compile this driver as a module, choose M here: the - module will be called ad7746. - -endmenu diff --git a/src/linux/drivers/staging/iio/frequency/Kconfig b/src/linux/drivers/staging/iio/frequency/Kconfig deleted file mode 100644 index fc726d3..0000000 --- a/src/linux/drivers/staging/iio/frequency/Kconfig +++ /dev/null @@ -1,26 +0,0 @@ -# -# Direct Digital Synthesis drivers -# -menu "Direct Digital Synthesis" - -config AD9832 - tristate "Analog Devices ad9832/5 driver" - depends on SPI - help - Say yes here to build support for Analog Devices DDS chip - AD9832 and AD9835, provides direct access via sysfs. - - To compile this driver as a module, choose M here: the - module will be called ad9832. - -config AD9834 - tristate "Analog Devices AD9833/4/7/8 driver" - depends on SPI - help - Say yes here to build support for Analog Devices DDS chip - AD9833, AD9834, AD9837 and AD9838, provides direct access via sysfs. - - To compile this driver as a module, choose M here: the - module will be called ad9834. - -endmenu diff --git a/src/linux/drivers/staging/iio/gyro/Kconfig b/src/linux/drivers/staging/iio/gyro/Kconfig deleted file mode 100644 index f62f68f..0000000 --- a/src/linux/drivers/staging/iio/gyro/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# -# IIO Digital Gyroscope Sensor drivers configuration -# -menu "Digital gyroscope sensors" - -config ADIS16060 - tristate "Analog Devices ADIS16060 Yaw Rate Gyroscope with SPI driver" - depends on SPI - help - Say Y (yes) here to build support for Analog Devices adis16060 wide bandwidth - yaw rate gyroscope with SPI. - - To compile this driver as a module, say M here: the module will be - called adis16060. If unsure, say N. - -endmenu diff --git a/src/linux/drivers/staging/iio/impedance-analyzer/Kconfig b/src/linux/drivers/staging/iio/impedance-analyzer/Kconfig deleted file mode 100644 index dd97b6b..0000000 --- a/src/linux/drivers/staging/iio/impedance-analyzer/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -# -# Impedance Converter, Network Analyzer drivers -# -menu "Network Analyzer, Impedance Converters" - -config AD5933 - tristate "Analog Devices AD5933, AD5934 driver" - depends on I2C - select IIO_BUFFER - select IIO_KFIFO_BUF - help - Say yes here to build support for Analog Devices Impedance Converter, - Network Analyzer, AD5933/4, provides direct access via sysfs. - - To compile this driver as a module, choose M here: the - module will be called ad5933. - -endmenu diff --git a/src/linux/drivers/staging/iio/light/Kconfig b/src/linux/drivers/staging/iio/light/Kconfig deleted file mode 100644 index ca8d6e6..0000000 --- a/src/linux/drivers/staging/iio/light/Kconfig +++ /dev/null @@ -1,43 +0,0 @@ -# -# Light sensors -# -menu "Light sensors" - -config SENSORS_ISL29018 - tristate "ISL 29018 light and proximity sensor" - depends on I2C - select REGMAP_I2C - default n - help - If you say yes here you get support for ambient light sensing and - proximity infrared sensing from Intersil ISL29018. - This driver will provide the measurements of ambient light intensity - in lux, proximity infrared sensing and normal infrared sensing. - Data from sensor is accessible via sysfs. - -config SENSORS_ISL29028 - tristate "Intersil ISL29028 Concurrent Light and Proximity Sensor" - depends on I2C - select REGMAP_I2C - help - Provides driver for the Intersil's ISL29028 device. - This driver supports the sysfs interface to get the ALS, IR intensity, - Proximity value via iio. The ISL29028 provides the concurrent sensing - of ambient light and proximity. - -config TSL2583 - tristate "TAOS TSL2580, TSL2581 and TSL2583 light-to-digital converters" - depends on I2C - help - Provides support for the TAOS tsl2580, tsl2581 and tsl2583 devices. - Access ALS data via iio, sysfs. - -config TSL2x7x - tristate "TAOS TSL/TMD2x71 and TSL/TMD2x72 Family of light and proximity sensors" - depends on I2C - help - Support for: tsl2571, tsl2671, tmd2671, tsl2771, tmd2771, tsl2572, tsl2672, - tmd2672, tsl2772, tmd2772 devices. - Provides iio_events and direct access via sysfs. - -endmenu diff --git a/src/linux/drivers/staging/iio/meter/Kconfig b/src/linux/drivers/staging/iio/meter/Kconfig deleted file mode 100644 index 64cd370..0000000 --- a/src/linux/drivers/staging/iio/meter/Kconfig +++ /dev/null @@ -1,78 +0,0 @@ -# -# IIO meter drivers configuration -# -menu "Active energy metering IC" - -config ADE7753 - tristate "Analog Devices ADE7753/6 Single-Phase Multifunction Metering IC Driver" - depends on SPI - help - Say yes here to build support for Analog Devices ADE7753 Single-Phase Multifunction - Metering IC with di/dt Sensor Interface. - - To compile this driver as a module, choose M here: the - module will be called ade7753. - -config ADE7754 - tristate "Analog Devices ADE7754 Polyphase Multifunction Energy Metering IC Driver" - depends on SPI - help - Say yes here to build support for Analog Devices ADE7754 Polyphase - Multifunction Energy Metering IC Driver. - - To compile this driver as a module, choose M here: the - module will be called ade7754. - -config ADE7758 - tristate "Analog Devices ADE7758 Poly Phase Multifunction Energy Metering IC Driver" - depends on SPI - select IIO_TRIGGER if IIO_BUFFER - select IIO_KFIFO_BUF if IIO_BUFFER - help - Say yes here to build support for Analog Devices ADE7758 Polyphase - Multifunction Energy Metering IC with Per Phase Information Driver. - - To compile this driver as a module, choose M here: the - module will be called ade7758. - -config ADE7759 - tristate "Analog Devices ADE7759 Active Energy Metering IC Driver" - depends on SPI - help - Say yes here to build support for Analog Devices ADE7758 Active Energy - Metering IC with di/dt Sensor Interface. - - To compile this driver as a module, choose M here: the - module will be called ade7759. - -config ADE7854 - tristate "Analog Devices ADE7854/58/68/78 Polyphase Multifunction Energy Metering IC Driver" - depends on SPI || I2C - help - Say yes here to build support for Analog Devices ADE7854/58/68/78 Polyphase - Multifunction Energy Metering IC Driver. - - To compile this driver as a module, choose M here: the - module will be called ade7854. - -config ADE7854_I2C - tristate "support I2C bus connection" - depends on ADE7854 && I2C - default y - help - Say Y here if you have ADE7854/58/68/78 hooked to an I2C bus. - - To compile this driver as a module, choose M here: the - module will be called ade7854-i2c. - -config ADE7854_SPI - tristate "support SPI bus connection" - depends on ADE7854 && SPI - default y - help - Say Y here if you have ADE7854/58/68/78 hooked to a SPI bus. - - To compile this driver as a module, choose M here: the - module will be called ade7854-spi. - -endmenu diff --git a/src/linux/drivers/staging/iio/resolver/Kconfig b/src/linux/drivers/staging/iio/resolver/Kconfig deleted file mode 100644 index 1c7e286..0000000 --- a/src/linux/drivers/staging/iio/resolver/Kconfig +++ /dev/null @@ -1,39 +0,0 @@ -# -# Resolver/Synchro drivers -# -menu "Resolver to digital converters" - -config AD2S90 - tristate "Analog Devices ad2s90 driver" - depends on SPI - help - Say yes here to build support for Analog Devices spi resolver - to digital converters, ad2s90, provides direct access via sysfs. - - To compile this driver as a module, choose M here: the - module will be called ad2s90. - -config AD2S1200 - tristate "Analog Devices ad2s1200/ad2s1205 driver" - depends on SPI - depends on GPIOLIB || COMPILE_TEST - help - Say yes here to build support for Analog Devices spi resolver - to digital converters, ad2s1200 and ad2s1205, provides direct access - via sysfs. - - To compile this driver as a module, choose M here: the - module will be called ad2s1200. - -config AD2S1210 - tristate "Analog Devices ad2s1210 driver" - depends on SPI - depends on GPIOLIB || COMPILE_TEST - help - Say yes here to build support for Analog Devices spi resolver - to digital converters, ad2s1210, provides direct access via sysfs. - - To compile this driver as a module, choose M here: the - module will be called ad2s1210. - -endmenu diff --git a/src/linux/drivers/staging/iio/trigger/Kconfig b/src/linux/drivers/staging/iio/trigger/Kconfig deleted file mode 100644 index 0b01d24..0000000 --- a/src/linux/drivers/staging/iio/trigger/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ - # -# Industrial I/O standalone triggers -# -comment "Triggers - standalone" - -if IIO_TRIGGER - -config IIO_BFIN_TMR_TRIGGER - tristate "Blackfin TIMER trigger" - depends on BLACKFIN - select BFIN_GPTIMERS - help - Provides support for using a Blackfin timer as IIO triggers. - If unsure, say N (but it's safe to say "Y"). - - To compile this driver as a module, choose M here: the - module will be called iio-trig-bfin-timer. - -endif # IIO_TRIGGER diff --git a/src/linux/drivers/staging/ks7010/Kconfig b/src/linux/drivers/staging/ks7010/Kconfig deleted file mode 100644 index 0b92176..0000000 --- a/src/linux/drivers/staging/ks7010/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config KS7010 - tristate "KeyStream KS7010 SDIO support" - depends on MMC && WIRELESS - select WIRELESS_EXT - select WEXT_PRIV - select FW_LOADER - help - This is a driver for KeyStream KS7010 based SDIO WIFI cards. It is - found on at least later Spectec SDW-821 (FCC-ID "S2Y-WLAN-11G-K" only, - sadly not FCC-ID "S2Y-WLAN-11B-G") and Spectec SDW-823 microSD cards. diff --git a/src/linux/drivers/staging/lustre/Kconfig b/src/linux/drivers/staging/lustre/Kconfig deleted file mode 100644 index b7d8109..0000000 --- a/src/linux/drivers/staging/lustre/Kconfig +++ /dev/null @@ -1,3 +0,0 @@ -source "drivers/staging/lustre/lnet/Kconfig" - -source "drivers/staging/lustre/lustre/Kconfig" diff --git a/src/linux/drivers/staging/lustre/lnet/Kconfig b/src/linux/drivers/staging/lustre/lnet/Kconfig deleted file mode 100644 index 13b4327..0000000 --- a/src/linux/drivers/staging/lustre/lnet/Kconfig +++ /dev/null @@ -1,47 +0,0 @@ -config LNET - tristate "Lustre networking subsystem (LNet)" - depends on INET && m - help - The Lustre network layer, also known as LNet, is a networking abstaction - level API that was initially created to allow Lustre Filesystem to utilize - very different networks like tcp and ib verbs in a uniform way. In the - case of Lustre routers only the LNet layer is required. Lately other - projects are also looking into using LNet as their networking API as well. - -config LNET_MAX_PAYLOAD - int "Lustre lnet max transfer payload (default 1MB)" - depends on LNET - default "1048576" - help - This option defines the maximum size of payload in bytes that lnet - can put into its transport. - - If unsure, use default. - -config LNET_SELFTEST - tristate "Lustre networking self testing" - depends on LNET - help - Choose Y here if you want to do lnet self testing. To compile this - as a module, choose M here: the module will be called lnet_selftest. - - To compile this as a kernel modules, choose M here and it will be - called lnet_selftest. - - If unsure, say N. - - See also http://wiki.lustre.org/ - -config LNET_XPRT_IB - tristate "LNET infiniband support" - depends on LNET && INFINIBAND && INFINIBAND_ADDR_TRANS - depends on BROKEN - default LNET && INFINIBAND - help - This option allows the LNET users to use infiniband as an - RDMA-enabled transport. - - To compile this as a kernel module, choose M here and it will be - called ko2iblnd. - - If unsure, say N. diff --git a/src/linux/drivers/staging/lustre/lustre/Kconfig b/src/linux/drivers/staging/lustre/lustre/Kconfig deleted file mode 100644 index 9f5d75f..0000000 --- a/src/linux/drivers/staging/lustre/lustre/Kconfig +++ /dev/null @@ -1,56 +0,0 @@ -config LUSTRE_FS - tristate "Lustre file system client support" - depends on m && !MIPS && !XTENSA && !SUPERH - depends on LNET - select CRYPTO - select CRYPTO_CRC32 - select CRYPTO_CRC32_PCLMUL if X86 - select CRYPTO_CRC32C - select CRYPTO_MD5 - select CRYPTO_SHA1 - select CRYPTO_SHA256 - select CRYPTO_SHA512 - depends on MULTIUSER - help - This option enables Lustre file system client support. Choose Y - here if you want to access a Lustre file system cluster. To compile - this file system support as a module, choose M here: the module will - be called lustre. - - To mount Lustre file systems, you also need to install the user space - mount.lustre and other user space commands which can be found in the - lustre-client package, available from - http://downloads.whamcloud.com/public/lustre/ - - Lustre file system is the most popular cluster file system in high - performance computing. Source code of both kernel space and user space - Lustre components can also be found at - http://git.whamcloud.com/?p=fs/lustre-release.git;a=summary - - If unsure, say N. - - See also http://wiki.lustre.org/ - -config LUSTRE_OBD_MAX_IOCTL_BUFFER - int "Lustre obd max ioctl buffer bytes (default 8KB)" - depends on LUSTRE_FS - default 8192 - help - This option defines the maximum size of buffer in bytes that user space - applications can pass to Lustre kernel module through ioctl interface. - - If unsure, use default. - -config LUSTRE_DEBUG_EXPENSIVE_CHECK - bool "Enable Lustre DEBUG checks" - depends on LUSTRE_FS - help - This option is mainly for debug purpose. It enables Lustre code to do - expensive checks that may have a performance impact. - - Use with caution. If unsure, say N. - -config LUSTRE_TRANSLATE_ERRNOS - bool - depends on LUSTRE_FS && !X86 - default y diff --git a/src/linux/drivers/staging/media/Kconfig b/src/linux/drivers/staging/media/Kconfig deleted file mode 100644 index 6620d96..0000000 --- a/src/linux/drivers/staging/media/Kconfig +++ /dev/null @@ -1,41 +0,0 @@ -menuconfig STAGING_MEDIA - bool "Media staging drivers" - default n - ---help--- - This option allows you to select a number of media drivers that - don't have the "normal" Linux kernel quality level. - Most of them don't follow properly the V4L, DVB and/or RC API's, - so, they won't likely work fine with the existing applications. - That also means that, once fixed, their API's will change to match - the existing ones. - - If you wish to work on these drivers, to help improve them, or - to report problems you have with them, please use the - linux-media@vger.kernel.org mailing list. - - If in doubt, say N here. - - -if STAGING_MEDIA && MEDIA_SUPPORT - -# Please keep them in alphabetic order -source "drivers/staging/media/bcm2048/Kconfig" - -source "drivers/staging/media/cec/Kconfig" - -source "drivers/staging/media/cxd2099/Kconfig" - -source "drivers/staging/media/davinci_vpfe/Kconfig" - -source "drivers/staging/media/omap4iss/Kconfig" - -source "drivers/staging/media/pulse8-cec/Kconfig" - -source "drivers/staging/media/s5p-cec/Kconfig" - -# Keep LIRC at the end, as it has sub-menus -source "drivers/staging/media/lirc/Kconfig" - -source "drivers/staging/media/st-cec/Kconfig" - -endif diff --git a/src/linux/drivers/staging/media/bcm2048/Kconfig b/src/linux/drivers/staging/media/bcm2048/Kconfig deleted file mode 100644 index a9fc6e1..0000000 --- a/src/linux/drivers/staging/media/bcm2048/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# -# Multimedia Video device configuration -# - -config I2C_BCM2048 - tristate "Broadcom BCM2048 FM Radio Receiver support" - depends on I2C && VIDEO_V4L2 && RADIO_ADAPTERS - ---help--- - Say Y here if you want support to BCM2048 FM Radio Receiver. - This device driver supports only i2c bus. - - To compile this driver as a module, choose M here: the - module will be called radio-bcm2048. diff --git a/src/linux/drivers/staging/media/cec/Kconfig b/src/linux/drivers/staging/media/cec/Kconfig deleted file mode 100644 index 6e12d41..0000000 --- a/src/linux/drivers/staging/media/cec/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config MEDIA_CEC - bool "CEC API (EXPERIMENTAL)" - depends on MEDIA_SUPPORT - select MEDIA_CEC_EDID - ---help--- - Enable the CEC API. - -config MEDIA_CEC_DEBUG - bool "CEC debugfs interface (EXPERIMENTAL)" - depends on MEDIA_CEC && DEBUG_FS - ---help--- - Turns on the DebugFS interface for CEC devices. diff --git a/src/linux/drivers/staging/media/cxd2099/Kconfig b/src/linux/drivers/staging/media/cxd2099/Kconfig deleted file mode 100644 index b48aefd..0000000 --- a/src/linux/drivers/staging/media/cxd2099/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config DVB_CXD2099 - tristate "CXD2099AR Common Interface driver" - depends on DVB_CORE && PCI && I2C - ---help--- - Support for the CI module found on cards based on - - Micronas ngene PCIe bridge: cineS2 etc. - - Digital Devices PCIe bridge: Octopus series - - For now, data is passed through '/dev/dvb/adapterX/sec0': - - Encrypted data must be written to 'sec0'. - - Decrypted data can be read from 'sec0'. - - Setup the CAM using device 'ca0'. diff --git a/src/linux/drivers/staging/media/davinci_vpfe/Kconfig b/src/linux/drivers/staging/media/davinci_vpfe/Kconfig deleted file mode 100644 index f40a069..0000000 --- a/src/linux/drivers/staging/media/davinci_vpfe/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config VIDEO_DM365_VPFE - tristate "DM365 VPFE Media Controller Capture Driver" - depends on VIDEO_V4L2 && ARCH_DAVINCI_DM365 && !VIDEO_DM365_ISIF - depends on HAS_DMA - depends on VIDEO_V4L2_SUBDEV_API - depends on VIDEO_DAVINCI_VPBE_DISPLAY - select VIDEOBUF2_DMA_CONTIG - help - Support for DM365 VPFE based Media Controller Capture driver. - - To compile this driver as a module, choose M here: the - module will be called vpfe-mc-capture. diff --git a/src/linux/drivers/staging/media/lirc/Kconfig b/src/linux/drivers/staging/media/lirc/Kconfig deleted file mode 100644 index 6879c46..0000000 --- a/src/linux/drivers/staging/media/lirc/Kconfig +++ /dev/null @@ -1,66 +0,0 @@ -# -# LIRC driver(s) configuration -# -menuconfig LIRC_STAGING - bool "Linux Infrared Remote Control IR receiver/transmitter drivers" - depends on LIRC - help - Say Y here, and all supported Linux Infrared Remote Control IR and - RF receiver and transmitter drivers will be displayed. When paired - with a remote control and the lirc daemon, the receiver drivers - allow control of your Linux system via remote control. - -if LIRC_STAGING - -config LIRC_BT829 - tristate "BT829 based hardware" - depends on LIRC && PCI - help - Driver for the IR interface on BT829-based hardware - -config LIRC_IMON - tristate "Legacy SoundGraph iMON Receiver and Display" - depends on LIRC && USB - help - Driver for the original SoundGraph iMON IR Receiver and Display - - Current generation iMON devices use the input layer imon driver. - -config LIRC_PARALLEL - tristate "Homebrew Parallel Port Receiver" - depends on LIRC && PARPORT - help - Driver for Homebrew Parallel Port Receivers - -config LIRC_SASEM - tristate "Sasem USB IR Remote" - depends on LIRC && USB - help - Driver for the Sasem OnAir Remocon-V or Dign HV5 HTPC IR/VFD Module - -config LIRC_SERIAL - tristate "Homebrew Serial Port Receiver" - depends on LIRC - help - Driver for Homebrew Serial Port Receivers - -config LIRC_SERIAL_TRANSMITTER - bool "Serial Port Transmitter" - default y - depends on LIRC_SERIAL - help - Serial Port Transmitter support - -config LIRC_SIR - tristate "Built-in SIR IrDA port" - depends on LIRC - help - Driver for the SIR IrDA port - -config LIRC_ZILOG - tristate "Zilog/Hauppauge IR Transmitter" - depends on LIRC && I2C - help - Driver for the Zilog/Hauppauge IR Transmitter, found on - PVR-150/500, HVR-1200/1250/1700/1800, HD-PVR and other cards -endif diff --git a/src/linux/drivers/staging/media/omap4iss/Kconfig b/src/linux/drivers/staging/media/omap4iss/Kconfig deleted file mode 100644 index 4618346..0000000 --- a/src/linux/drivers/staging/media/omap4iss/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config VIDEO_OMAP4 - tristate "OMAP 4 Camera support" - depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && I2C && ARCH_OMAP4 - depends on HAS_DMA - select MFD_SYSCON - select VIDEOBUF2_DMA_CONTIG - ---help--- - Driver for an OMAP 4 ISS controller. diff --git a/src/linux/drivers/staging/media/pulse8-cec/Kconfig b/src/linux/drivers/staging/media/pulse8-cec/Kconfig deleted file mode 100644 index c6aa2d1..0000000 --- a/src/linux/drivers/staging/media/pulse8-cec/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config USB_PULSE8_CEC - tristate "Pulse Eight HDMI CEC" - depends on USB_ACM && MEDIA_CEC - select SERIO - select SERIO_SERPORT - ---help--- - This is a cec driver for the Pulse Eight HDMI CEC device. - - To compile this driver as a module, choose M here: the - module will be called pulse8-cec. diff --git a/src/linux/drivers/staging/media/s5p-cec/Kconfig b/src/linux/drivers/staging/media/s5p-cec/Kconfig deleted file mode 100644 index 0315fd7..0000000 --- a/src/linux/drivers/staging/media/s5p-cec/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config VIDEO_SAMSUNG_S5P_CEC - tristate "Samsung S5P CEC driver" - depends on VIDEO_DEV && MEDIA_CEC && (PLAT_S5P || ARCH_EXYNOS || COMPILE_TEST) - ---help--- - This is a driver for Samsung S5P HDMI CEC interface. It uses the - generic CEC framework interface. - CEC bus is present in the HDMI connector and enables communication - between compatible devices. - diff --git a/src/linux/drivers/staging/media/st-cec/Kconfig b/src/linux/drivers/staging/media/st-cec/Kconfig deleted file mode 100644 index 784d2c6..0000000 --- a/src/linux/drivers/staging/media/st-cec/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config VIDEO_STI_HDMI_CEC - tristate "STMicroelectronics STiH4xx HDMI CEC driver" - depends on VIDEO_DEV && MEDIA_CEC && (ARCH_STI || COMPILE_TEST) - ---help--- - This is a driver for STIH4xx HDMI CEC interface. It uses the - generic CEC framework interface. - CEC bus is present in the HDMI connector and enables communication - between compatible devices. diff --git a/src/linux/drivers/staging/most/Kconfig b/src/linux/drivers/staging/most/Kconfig deleted file mode 100644 index 0b9b9b5..0000000 --- a/src/linux/drivers/staging/most/Kconfig +++ /dev/null @@ -1,31 +0,0 @@ -menuconfig MOST - tristate "MOST driver" - depends on HAS_DMA - select MOSTCORE - default n - ---help--- - This option allows you to enable support for MOST Network transceivers. - - If in doubt, say N here. - - - -if MOST - -source "drivers/staging/most/mostcore/Kconfig" - -source "drivers/staging/most/aim-cdev/Kconfig" - -source "drivers/staging/most/aim-network/Kconfig" - -source "drivers/staging/most/aim-sound/Kconfig" - -source "drivers/staging/most/aim-v4l2/Kconfig" - -source "drivers/staging/most/hdm-dim2/Kconfig" - -source "drivers/staging/most/hdm-i2c/Kconfig" - -source "drivers/staging/most/hdm-usb/Kconfig" - -endif diff --git a/src/linux/drivers/staging/most/aim-cdev/Kconfig b/src/linux/drivers/staging/most/aim-cdev/Kconfig deleted file mode 100644 index 3c59f1b..0000000 --- a/src/linux/drivers/staging/most/aim-cdev/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -# -# MOST Cdev configuration -# - -config AIM_CDEV - tristate "Cdev AIM" - - ---help--- - Say Y here if you want to commumicate via character devices. - - To compile this driver as a module, choose M here: the - module will be called aim_cdev. \ No newline at end of file diff --git a/src/linux/drivers/staging/most/aim-network/Kconfig b/src/linux/drivers/staging/most/aim-network/Kconfig deleted file mode 100644 index 4c66b24..0000000 --- a/src/linux/drivers/staging/most/aim-network/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# -# MOST Networking configuration -# - -config AIM_NETWORK - tristate "Networking AIM" - depends on NET - - ---help--- - Say Y here if you want to commumicate via a networking device. - - To compile this driver as a module, choose M here: the - module will be called aim_network. diff --git a/src/linux/drivers/staging/most/aim-sound/Kconfig b/src/linux/drivers/staging/most/aim-sound/Kconfig deleted file mode 100644 index 3194c21..0000000 --- a/src/linux/drivers/staging/most/aim-sound/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# -# MOST ALSA configuration -# - -config AIM_SOUND - tristate "ALSA AIM" - depends on SND - select SND_PCM - ---help--- - Say Y here if you want to commumicate via ALSA/sound devices. - - To compile this driver as a module, choose M here: the - module will be called aim_sound. diff --git a/src/linux/drivers/staging/most/aim-v4l2/Kconfig b/src/linux/drivers/staging/most/aim-v4l2/Kconfig deleted file mode 100644 index d70eaaf..0000000 --- a/src/linux/drivers/staging/most/aim-v4l2/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -# -# MOST V4L2 configuration -# - -config AIM_V4L2 - tristate "V4L2 AIM" - depends on VIDEO_V4L2 - ---help--- - Say Y here if you want to commumicate via Video 4 Linux. - - To compile this driver as a module, choose M here: the - module will be called aim_v4l2. \ No newline at end of file diff --git a/src/linux/drivers/staging/most/hdm-dim2/Kconfig b/src/linux/drivers/staging/most/hdm-dim2/Kconfig deleted file mode 100644 index 28a0e17..0000000 --- a/src/linux/drivers/staging/most/hdm-dim2/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -# -# MediaLB configuration -# - -config HDM_DIM2 - tristate "DIM2 HDM" - depends on AIM_NETWORK - depends on HAS_IOMEM - - ---help--- - Say Y here if you want to connect via MediaLB to network transceiver. - This device driver is platform dependent and needs an additional - platform driver to be installed. For more information contact - maintainer of this driver. - - To compile this driver as a module, choose M here: the - module will be called hdm_dim2. diff --git a/src/linux/drivers/staging/most/hdm-i2c/Kconfig b/src/linux/drivers/staging/most/hdm-i2c/Kconfig deleted file mode 100644 index 6fd7983..0000000 --- a/src/linux/drivers/staging/most/hdm-i2c/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -# -# MOST I2C configuration -# - -config HDM_I2C - tristate "I2C HDM" - depends on I2C - ---help--- - Say Y here if you want to connect via I2C to network tranceiver. - - To compile this driver as a module, choose M here: the - module will be called hdm_i2c. diff --git a/src/linux/drivers/staging/most/hdm-usb/Kconfig b/src/linux/drivers/staging/most/hdm-usb/Kconfig deleted file mode 100644 index ec15463..0000000 --- a/src/linux/drivers/staging/most/hdm-usb/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -# -# MOST USB configuration -# - -config HDM_USB - tristate "USB HDM" - depends on USB && NET - select AIM_NETWORK - ---help--- - Say Y here if you want to connect via USB to network tranceiver. - This device driver depends on the networking AIM. - - To compile this driver as a module, choose M here: the - module will be called hdm_usb. diff --git a/src/linux/drivers/staging/most/mostcore/Kconfig b/src/linux/drivers/staging/most/mostcore/Kconfig deleted file mode 100644 index 4717254..0000000 --- a/src/linux/drivers/staging/most/mostcore/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -# -# MOSTCore configuration -# - -config MOSTCORE - tristate "MOST Core" - depends on HAS_DMA - - ---help--- - Say Y here if you want to enable MOST support. - This device driver needs at least an additional AIM and HDM to work. - - To compile this driver as a module, choose M here: the - module will be called mostcore. diff --git a/src/linux/drivers/staging/mt29f_spinand/Kconfig b/src/linux/drivers/staging/mt29f_spinand/Kconfig deleted file mode 100644 index f3f9cb3..0000000 --- a/src/linux/drivers/staging/mt29f_spinand/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -config MTD_SPINAND_MT29F - tristate "SPINAND Device Support for Micron" - depends on MTD_NAND && SPI - help - This enables support for accessing Micron SPI NAND flash - devices. - If you have Micron SPI NAND chip say yes. - - If unsure, say no here. - -config MTD_SPINAND_ONDIEECC - bool "Use SPINAND internal ECC" - depends on MTD_SPINAND_MT29F - help - Internal ECC. - Enables Hardware ECC support for Micron SPI NAND. diff --git a/src/linux/drivers/staging/netlogic/Kconfig b/src/linux/drivers/staging/netlogic/Kconfig deleted file mode 100644 index d660de5..0000000 --- a/src/linux/drivers/staging/netlogic/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -config NETLOGIC_XLR_NET - tristate "Netlogic XLR/XLS network device" - depends on CPU_XLR - select PHYLIB - ---help--- - This driver support Netlogic XLR/XLS on chip gigabit - Ethernet. diff --git a/src/linux/drivers/staging/nvec/Kconfig b/src/linux/drivers/staging/nvec/Kconfig deleted file mode 100644 index e3a89fb..0000000 --- a/src/linux/drivers/staging/nvec/Kconfig +++ /dev/null @@ -1,53 +0,0 @@ -config MFD_NVEC - tristate "NV Tegra Embedded Controller SMBus Interface" - depends on I2C && GPIOLIB && ARCH_TEGRA - select MFD_CORE - help - Say Y here to enable support for a nVidia compliant embedded - controller. - - To compile this driver as a module, say M here: the module will be - called mfd-nvec - -config KEYBOARD_NVEC - tristate "Keyboard on nVidia compliant EC" - depends on MFD_NVEC && INPUT - help - Say Y here to enable support for a keyboard connected to - a nVidia compliant embedded controller. - - To compile this driver as a module, say M here: the module will be - called keyboard-nvec - -config SERIO_NVEC_PS2 - tristate "PS2 on nVidia EC" - depends on MFD_NVEC && SERIO - help - Say Y here to enable support for a Touchpad / Mouse connected - to a nVidia compliant embedded controller. - - To compile this driver as a module, say M here: the module will be - called serio-nvec-ps2 - - -config NVEC_POWER - tristate "NVEC charger and battery" - depends on MFD_NVEC && POWER_SUPPLY - help - Say Y to enable support for battery and charger interface for - nVidia compliant embedded controllers. - - To compile this driver as a module, say M here: the module will be - called nvec-power - - -config NVEC_PAZ00 - tristate "Support for OEM specific functions on Compal PAZ00 based devices" - depends on MFD_NVEC && LEDS_CLASS - help - Say Y to enable control of the yellow side leds on Compal PAZ00 based - devices, e.g. Toshbia AC100 and Dynabooks AZ netbooks. - - To compile this driver as a module, say M here: the module will be - called nvec-paz00 - diff --git a/src/linux/drivers/staging/octeon-usb/Kconfig b/src/linux/drivers/staging/octeon-usb/Kconfig deleted file mode 100644 index 0b8f1d9..0000000 --- a/src/linux/drivers/staging/octeon-usb/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config OCTEON_USB - tristate "Cavium Networks Octeon USB support" - depends on CAVIUM_OCTEON_SOC && USB - help - This driver supports USB host controller on some Cavium - Networks' products in the Octeon family. - - To compile this driver as a module, choose M here. The module - will be called octeon-hcd. - diff --git a/src/linux/drivers/staging/octeon/Kconfig b/src/linux/drivers/staging/octeon/Kconfig deleted file mode 100644 index 6e1d5f8..0000000 --- a/src/linux/drivers/staging/octeon/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config OCTEON_ETHERNET - tristate "Cavium Networks Octeon Ethernet support" - depends on CAVIUM_OCTEON_SOC && NETDEVICES - select PHYLIB - select MDIO_OCTEON - help - This driver supports the builtin ethernet ports on Cavium - Networks' products in the Octeon family. This driver supports the - CN3XXX and CN5XXX Octeon processors. - - To compile this driver as a module, choose M here. The module - will be called octeon-ethernet. - diff --git a/src/linux/drivers/staging/olpc_dcon/Kconfig b/src/linux/drivers/staging/olpc_dcon/Kconfig deleted file mode 100644 index d277f04..0000000 --- a/src/linux/drivers/staging/olpc_dcon/Kconfig +++ /dev/null @@ -1,35 +0,0 @@ -config FB_OLPC_DCON - tristate "One Laptop Per Child Display CONtroller support" - depends on OLPC && FB - depends on I2C - depends on (GPIO_CS5535 || GPIO_CS5535=n) - select BACKLIGHT_CLASS_DEVICE - ---help--- - In order to support very low power operation, the XO laptop uses a - secondary Display CONtroller, or DCON. This secondary controller - is present in the video pipeline between the primary display - controller (integrate into the processor or chipset) and the LCD - panel. It allows the main processor/display controller to be - completely powered off while still retaining an image on the display. - This controller is only available on OLPC platforms. Unless you have - one of these platforms, you will want to say 'N'. - -config FB_OLPC_DCON_1 - bool "OLPC XO-1 DCON support" - depends on FB_OLPC_DCON && GPIO_CS5535 - default y - ---help--- - Enable support for the DCON in XO-1 model laptops. The kernel - communicates with the DCON using model-specific code. If you - have an XO-1 (or if you're unsure what model you have), you should - say 'Y'. - -config FB_OLPC_DCON_1_5 - bool "OLPC XO-1.5 DCON support" - depends on FB_OLPC_DCON && ACPI - default y - ---help--- - Enable support for the DCON in XO-1.5 model laptops. The kernel - communicates with the DCON using model-specific code. If you - have an XO-1.5 (or if you're unsure what model you have), you - should say 'Y'. diff --git a/src/linux/drivers/staging/rtl8188eu/Kconfig b/src/linux/drivers/staging/rtl8188eu/Kconfig deleted file mode 100644 index 94f3879..0000000 --- a/src/linux/drivers/staging/rtl8188eu/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -config R8188EU - tristate "Realtek RTL8188EU Wireless LAN NIC driver" - depends on WLAN && USB && CFG80211 - select WIRELESS_EXT - select WEXT_PRIV - ---help--- - This option adds the Realtek RTL8188EU USB device such as TP-Link TL-WN725N. - If built as a module, it will be called r8188eu. - -if R8188EU - -config 88EU_AP_MODE - bool "Realtek RTL8188EU AP mode" - default y - ---help--- - This option enables Access Point mode. Unless you know that your system - will never be used as an AP, or the target system has limited memory, - "Y" should be selected. - -endif diff --git a/src/linux/drivers/staging/rtl8192e/Kconfig b/src/linux/drivers/staging/rtl8192e/Kconfig deleted file mode 100644 index 4602a47..0000000 --- a/src/linux/drivers/staging/rtl8192e/Kconfig +++ /dev/null @@ -1,47 +0,0 @@ -config RTLLIB - tristate "Support for rtllib wireless devices" - depends on WLAN && m - default n - select LIB80211 - ---help--- - If you have a wireless card that uses rtllib, say - Y. Currently the only card is the rtl8192e. - - If unsure, say N. - -if RTLLIB - -config RTLLIB_CRYPTO_CCMP - tristate "Support for rtllib CCMP crypto" - depends on RTLLIB - select CRYPTO_AES - default y - ---help--- - CCMP crypto driver for rtllib. - - If you enabled RTLLIB, you want this. - -config RTLLIB_CRYPTO_TKIP - tristate "Support for rtllib TKIP crypto" - depends on RTLLIB - select CRYPTO_ARC4 - select CRYPTO_MICHAEL_MIC - default y - ---help--- - TKIP crypto driver for rtllib. - - If you enabled RTLLIB, you want this. - -config RTLLIB_CRYPTO_WEP - tristate "Support for rtllib WEP crypto" - select CRYPTO_ARC4 - depends on RTLLIB - default y - ---help--- - TKIP crypto driver for rtllib. - - If you enabled RTLLIB, you want this. - -source "drivers/staging/rtl8192e/rtl8192e/Kconfig" - -endif diff --git a/src/linux/drivers/staging/rtl8192e/rtl8192e/Kconfig b/src/linux/drivers/staging/rtl8192e/rtl8192e/Kconfig deleted file mode 100644 index 282e293..0000000 --- a/src/linux/drivers/staging/rtl8192e/rtl8192e/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config RTL8192E - tristate "RealTek RTL8192E Wireless LAN NIC driver" - depends on PCI && WLAN && RTLLIB - depends on m - select WIRELESS_EXT - select WEXT_PRIV - select CRYPTO - select FW_LOADER - ---help--- diff --git a/src/linux/drivers/staging/rtl8192u/Kconfig b/src/linux/drivers/staging/rtl8192u/Kconfig deleted file mode 100644 index 3ee9d0d..0000000 --- a/src/linux/drivers/staging/rtl8192u/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config RTL8192U - tristate "RealTek RTL8192U Wireless LAN NIC driver" - depends on PCI && WLAN && USB - depends on m - select WIRELESS_EXT - select WEXT_PRIV - select CRYPTO - ---help--- diff --git a/src/linux/drivers/staging/rtl8712/Kconfig b/src/linux/drivers/staging/rtl8712/Kconfig deleted file mode 100644 index f160eee..0000000 --- a/src/linux/drivers/staging/rtl8712/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -config R8712U - tristate "RealTek RTL8712U (RTL8192SU) Wireless LAN NIC driver" - depends on WLAN && USB - select WIRELESS_EXT - select WEXT_PRIV - select FW_LOADER - ---help--- - This option adds the Realtek RTL8712 USB device such as the D-Link DWA-130. - If built as a module, it will be called r8712u. - -config R8712_TX_AGGR - bool "Realtek RTL8712U Transmit Aggregation code" - depends on R8712U && BROKEN - ---help--- - This option provides transmit aggregation for the Realtek RTL8712 USB device. - - diff --git a/src/linux/drivers/staging/rts5208/Kconfig b/src/linux/drivers/staging/rts5208/Kconfig deleted file mode 100644 index 05c990f..0000000 --- a/src/linux/drivers/staging/rts5208/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config RTS5208 - tristate "Realtek PCI-E Card Reader RTS5208/5288 support" - depends on PCI && SCSI - help - Say Y here to include driver code to support the Realtek - PCI-E card reader rts5208/rts5288. - - If this driver is compiled as a module, it will be named rts5208. diff --git a/src/linux/drivers/staging/skein/Kconfig b/src/linux/drivers/staging/skein/Kconfig deleted file mode 100644 index 012a823..0000000 --- a/src/linux/drivers/staging/skein/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -config CRYPTO_SKEIN - tristate "Skein digest algorithm" - depends on (X86 || UML_X86) && 64BIT && CRYPTO - select CRYPTO_HASH - select CRYPTO_ALGAPI - help - Skein secure hash algorithm is one of 5 finalists from the NIST SHA3 - competition. - - Skein is optimized for modern, 64bit processors and is highly - customizable. See: - - http://www.skein-hash.info/sites/default/files/skein1.3.pdf - - for more information. This module also contains the threefish block - cipher algorithm. diff --git a/src/linux/drivers/staging/slicoss/Kconfig b/src/linux/drivers/staging/slicoss/Kconfig deleted file mode 100644 index 5c2a15b..0000000 --- a/src/linux/drivers/staging/slicoss/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config SLICOSS - tristate "Alacritech Gigabit IS-NIC support" - depends on PCI && X86 && NET - default n - help - This driver supports Alacritech's IS-NIC gigabit ethernet cards. - - This includes the following devices: - Mojave cards (single port PCI Gigabit) both copper and fiber - Oasis cards (single and dual port PCI-x Gigabit) copper and fiber - Kalahari cards (dual and quad port PCI-e Gigabit) copper and fiber - - To compile this driver as a module, choose M here: the module - will be called slicoss. diff --git a/src/linux/drivers/staging/sm750fb/Kconfig b/src/linux/drivers/staging/sm750fb/Kconfig deleted file mode 100644 index ccebc25..0000000 --- a/src/linux/drivers/staging/sm750fb/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config FB_SM750 - tristate "Silicon Motion SM750 framebuffer support" - depends on FB && PCI - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Frame buffer driver for the Silicon Motion SM750 chip - with 2D accelearion and dual head support. - - This driver is also available as a module. The module will be - called sm750fb. If you want to compile it as a module, say M - here and read . diff --git a/src/linux/drivers/staging/speakup/Kconfig b/src/linux/drivers/staging/speakup/Kconfig deleted file mode 100644 index 7e8037e..0000000 --- a/src/linux/drivers/staging/speakup/Kconfig +++ /dev/null @@ -1,199 +0,0 @@ -menu "Speakup console speech" - -config SPEAKUP - depends on VT && !MN10300 - tristate "Speakup core" - ---help--- - This is the Speakup screen reader. Think of it as a - video console for blind people. If built in to the - kernel, it can speak everything on the text console from - boot up to shutdown. For more information on Speakup, - point your browser at . - There is also a mailing list at the above url that you - can subscribe to. - - Supported synthesizers are accent sa, accent pc, - appollo II., Auddapter, Braille 'n Speak, Dectalk - external (old), Dectalk PC (full length isa board), - Dectalk express, Doubletalk, Doubletalk LT or - Litetalk, Keynote Gold internal PC, software - synthesizers, Speakout, transport, and a dummy module - that can be used with a plain text terminal. - - Speakup can either be built in or compiled as a module - by answering y or m. If you answer y here, then you - must answer either y or m to at least one of the - synthesizer drivers below. If you answer m here, then - the synthesizer drivers below can only be built as - modules. - - These drivers are not standalone drivers, but must be - used in conjunction with Speakup. Think of them as - video cards for blind people. - - - The Dectalk pc driver can only be built as a module, and - requires software to be pre-loaded on to the card before - the module can be loaded. See the decpc choice below - for more details. - - If you are not a blind person, or don't have access to - one of the listed synthesizers, you should say n. - -if SPEAKUP -config SPEAKUP_SYNTH_ACNTSA - tristate "Accent SA synthesizer support" - ---help--- - This is the Speakup driver for the Accent SA - synthesizer. You can say y to build it into the kernel, - or m to build it as a module. See the configuration - help on the Speakup choice above for more info. - -config SPEAKUP_SYNTH_ACNTPC - tristate "Accent PC synthesizer support" - depends on ISA || COMPILE_TEST - ---help--- - This is the Speakup driver for the accent pc - synthesizer. You can say y to build it into the kernel, - or m to build it as a module. See the configuration - help on the Speakup choice above for more info. - -config SPEAKUP_SYNTH_APOLLO - tristate "Apollo II synthesizer support" - ---help--- - This is the Speakup driver for the Apollo II - synthesizer. You can say y to build it into the kernel, - or m to build it as a module. See the configuration - help on the Speakup choice above for more info. - -config SPEAKUP_SYNTH_AUDPTR - tristate "Audapter synthesizer support" - ---help--- - This is the Speakup driver for the Audapter synthesizer. - You can say y to build it into the kernel, or m to - build it as a module. See the configuration help on the - Speakup choice above for more info. - -config SPEAKUP_SYNTH_BNS - tristate "Braille 'n' Speak synthesizer support" - ---help--- - This is the Speakup driver for the Braille 'n' Speak - synthesizer. You can say y to build it into the kernel, - or m to build it as a module. See the configuration - help on the Speakup choice above for more info. - -config SPEAKUP_SYNTH_DECTLK - tristate "DECtalk Express synthesizer support" - ---help--- - - This is the Speakup driver for the DecTalk Express - synthesizer. You can say y to build it into the kernel, - or m to build it as a module. See the configuration - help on the Speakup choice above for more info. - -config SPEAKUP_SYNTH_DECEXT - tristate "DECtalk External (old) synthesizer support" - ---help--- - - This is the Speakup driver for the DecTalk External - (old) synthesizer. You can say y to build it into the - kernel, or m to build it as a module. See the - configuration help on the Speakup choice above for more - info. - -config SPEAKUP_SYNTH_DECPC - depends on m - depends on ISA || COMPILE_TEST - tristate "DECtalk PC (big ISA card) synthesizer support" - ---help--- - - This is the Speakup driver for the DecTalk PC (full - length ISA) synthesizer. You can say m to build it as - a module. See the configuration help on the Speakup - choice above for more info. - - In order to use the DecTalk PC driver, you must download - the dec_pc.tgz file from linux-speakup.org. It is in - the pub/linux/goodies directory. The dec_pc.tgz file - contains the software which must be pre-loaded on to the - DecTalk PC board in order to use it with this driver. - This driver must be built as a module, and can not be - loaded until the file system is mounted and the DecTalk - PC software has been pre-loaded on to the board. - - See the README file in the dec_pc.tgz file for more - details. - -config SPEAKUP_SYNTH_DTLK - tristate "DoubleTalk PC synthesizer support" - depends on ISA || COMPILE_TEST - ---help--- - - This is the Speakup driver for the internal DoubleTalk - PC synthesizer. You can say y to build it into the - kernel, or m to build it as a module. See the - configuration help on the Speakup choice above for more - info. - -config SPEAKUP_SYNTH_KEYPC - tristate "Keynote Gold PC synthesizer support" - depends on ISA || COMPILE_TEST - ---help--- - - This is the Speakup driver for the Keynote Gold - PC synthesizer. You can say y to build it into the - kernel, or m to build it as a module. See the - configuration help on the Speakup choice above for more - info. - -config SPEAKUP_SYNTH_LTLK - tristate "DoubleTalk LT/LiteTalk synthesizer support" ----help--- - - This is the Speakup driver for the LiteTalk/DoubleTalk - LT synthesizer. You can say y to build it into the - kernel, or m to build it as a module. See the - configuration help on the Speakup choice above for more - info. - -config SPEAKUP_SYNTH_SOFT - tristate "Userspace software synthesizer support" - ---help--- - - This is the software synthesizer device node. It will - register a device /dev/softsynth which midware programs - and speech daemons may open and read to provide kernel - output to software synths such as espeak, festival, - flite and so forth. You can select 'y' or 'm' to have - it built-in to the kernel or loaded as a module. - -config SPEAKUP_SYNTH_SPKOUT - tristate "Speak Out synthesizer support" - ---help--- - - This is the Speakup driver for the Speakout synthesizer. - You can say y to build it into the kernel, or m to - build it as a module. See the configuration help on the - Speakup choice above for more info. - -config SPEAKUP_SYNTH_TXPRT - tristate "Transport synthesizer support" - ---help--- - - This is the Speakup driver for the Transport - synthesizer. You can say y to build it into the kernel, - or m to build it as a module. See the configuration - help on the Speakup choice above for more info. - -config SPEAKUP_SYNTH_DUMMY - tristate "Dummy synthesizer driver (for testing)" - ---help--- - - This is a dummy Speakup driver for plugging a mere serial - terminal. This is handy if you want to test speakup but - don't have the hardware. You can say y to build it into - the kernel, or m to build it as a module. See the - configuration help on the Speakup choice above for more info. - -endif # SPEAKUP -endmenu diff --git a/src/linux/drivers/staging/unisys/Kconfig b/src/linux/drivers/staging/unisys/Kconfig deleted file mode 100644 index 4f1f5e6..0000000 --- a/src/linux/drivers/staging/unisys/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -# -# Unisys SPAR driver configuration -# -menuconfig UNISYSSPAR - bool "Unisys SPAR driver support" - depends on X86_64 && !UML - select PCI - select ACPI - ---help--- - Support for the Unisys SPAR drivers - -if UNISYSSPAR - -source "drivers/staging/unisys/visorbus/Kconfig" -source "drivers/staging/unisys/visornic/Kconfig" -source "drivers/staging/unisys/visorinput/Kconfig" -source "drivers/staging/unisys/visorhba/Kconfig" - -endif # UNISYSSPAR diff --git a/src/linux/drivers/staging/unisys/visorbus/Kconfig b/src/linux/drivers/staging/unisys/visorbus/Kconfig deleted file mode 100644 index 5113880..0000000 --- a/src/linux/drivers/staging/unisys/visorbus/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -# -# Unisys visorbus configuration -# - -config UNISYS_VISORBUS - tristate "Unisys visorbus driver" - depends on UNISYSSPAR - ---help--- - The visorbus driver is a virtualized bus for the Unisys s-Par firmware. - Virtualized devices allow Linux guests on a system to share disks and - network cards that do not have SR-IOV support, and to be accessed using - the partition desktop application. The visorbus driver is required to - discover devices on an s-Par guest, and must be present for any other - s-Par guest driver to function correctly. diff --git a/src/linux/drivers/staging/unisys/visorhba/Kconfig b/src/linux/drivers/staging/unisys/visorhba/Kconfig deleted file mode 100644 index 241d803..0000000 --- a/src/linux/drivers/staging/unisys/visorhba/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -# -# Unisys visorhba configuration -# - -config UNISYS_VISORHBA - tristate "Unisys visorhba driver" - depends on UNISYSSPAR && UNISYS_VISORBUS && SCSI - ---help--- - The Unisys visorhba driver provides support for s-Par HBA - devices exposed on the s-Par visorbus. When a message is sent - to visorbus to create a HBA device, the probe function of - visorhba is called to create the scsi device. - If you say Y here, you will enable the Unisys visorhba driver. - diff --git a/src/linux/drivers/staging/unisys/visorinput/Kconfig b/src/linux/drivers/staging/unisys/visorinput/Kconfig deleted file mode 100644 index 655cd62..0000000 --- a/src/linux/drivers/staging/unisys/visorinput/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -# -# Unisys visorinput configuration -# - -config UNISYS_VISORINPUT - tristate "Unisys visorinput driver" - depends on UNISYSSPAR && UNISYS_VISORBUS && FB && INPUT - ---help--- - The Unisys s-Par visorinput driver provides a virtualized system - console (keyboard and mouse) that is accessible through the - s-Par firmware's user interface. s-Par provides video using the EFI - GOP protocol, so If this driver is not present, the Linux guest should - still boot with visible output in the partition desktop, but keyboard - and mouse interaction will not be available. - diff --git a/src/linux/drivers/staging/unisys/visornic/Kconfig b/src/linux/drivers/staging/unisys/visornic/Kconfig deleted file mode 100644 index 1676dc7..0000000 --- a/src/linux/drivers/staging/unisys/visornic/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -# -# Unisys visornic configuration -# - -config UNISYS_VISORNIC - tristate "Unisys visornic driver" - depends on UNISYSSPAR && UNISYS_VISORBUS && NET - ---help--- - The Unisys Visornic driver provides support for s-Par network - devices exposed on the s-Par visorbus. When a message is sent - to visorbus to create a network device, the probe function of - visornic is called to create the netdev device. Networking on - s-Par switches will not work if this driver is not selected. - If you say Y here, you will enable the Unisys visornic driver. - diff --git a/src/linux/drivers/staging/vc04_services/Kconfig b/src/linux/drivers/staging/vc04_services/Kconfig deleted file mode 100644 index 9676fb2..0000000 --- a/src/linux/drivers/staging/vc04_services/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config BCM2708_VCHIQ - tristate "Videocore VCHIQ" - depends on RASPBERRYPI_FIRMWARE && BROKEN - default y - help - Kernel to VideoCore communication interface for the - BCM2708 family of products. - Defaults to Y when the Broadcom Videocore services - are included in the build, N otherwise. diff --git a/src/linux/drivers/staging/vme/devices/Kconfig b/src/linux/drivers/staging/vme/devices/Kconfig deleted file mode 100644 index 1d2ff0c..0000000 --- a/src/linux/drivers/staging/vme/devices/Kconfig +++ /dev/null @@ -1,25 +0,0 @@ -comment "VME Device Drivers" - -config VME_USER - tristate "VME user space access driver" - depends on STAGING - help - If you say Y here you want to be able to access a limited number of - VME windows in a manner at least semi-compatible with the interface - provided with the original driver at . - - To compile this driver as a module, choose M here. The module will - be called vme_user. If unsure, say N. - -config VME_PIO2 - tristate "GE PIO2 VME" - depends on STAGING && GPIOLIB - help - Say Y here to include support for the GE PIO2. The PIO2 is a 6U VME - slave card, implementing 32 solid-state relay switched IO lines, in - 4 groups of 8. Each bank of IO lines is built to function as input, - output or both depending on the variant of the card. - - To compile this driver as a module, choose M here. The module will - be called vme_pio2. If unsure, say N. - diff --git a/src/linux/drivers/staging/vt6655/Kconfig b/src/linux/drivers/staging/vt6655/Kconfig deleted file mode 100644 index 77cfc70..0000000 --- a/src/linux/drivers/staging/vt6655/Kconfig +++ /dev/null @@ -1,6 +0,0 @@ -config VT6655 - tristate "VIA Technologies VT6655 support" - depends on PCI && MAC80211 && m - ---help--- - This is a vendor-written driver for VIA VT6655. - diff --git a/src/linux/drivers/staging/vt6656/Kconfig b/src/linux/drivers/staging/vt6656/Kconfig deleted file mode 100644 index b602ef1..0000000 --- a/src/linux/drivers/staging/vt6656/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -config VT6656 - tristate "VIA Technologies VT6656 support" - depends on MAC80211 && USB && WLAN && m - select FW_LOADER - ---help--- - This is a vendor-written driver for VIA VT6656. - diff --git a/src/linux/drivers/staging/wilc1000/Kconfig b/src/linux/drivers/staging/wilc1000/Kconfig deleted file mode 100644 index 73f7fef..0000000 --- a/src/linux/drivers/staging/wilc1000/Kconfig +++ /dev/null @@ -1,42 +0,0 @@ -config WILC1000 - tristate - ---help--- - This module only support IEEE 802.11n WiFi. - -config WILC1000_SDIO - tristate "Atmel WILC1000 SDIO (WiFi only)" - depends on CFG80211 && INET && MMC - select WILC1000 - ---help--- - This module adds support for the SDIO interface of adapters using - WILC1000 chipset. The Atmel WILC1000 SDIO is a full speed interface. - It meets SDIO card specification version 2.0. The interface supports - the 1-bit/4-bit SD transfer mode at the clock range of 0-50 MHz. - The host can use this interface to read and write from any register - within the chip as well as configure the WILC1000 for data DMA. - To use this interface, pin9 (SDIO_SPI_CFG) must be grounded. Select - this if your platform is using the SDIO bus. - -config WILC1000_SPI - tristate "Atmel WILC1000 SPI (WiFi only)" - depends on CFG80211 && INET && SPI - select WILC1000 - ---help--- - This module adds support for the SPI interface of adapters using - WILC1000 chipset. The Atmel WILC1000 has a Serial Peripheral - Interface (SPI) that operates as a SPI slave. This SPI interface can - be used for control and for serial I/O of 802.11 data. The SPI is a - full-duplex slave synchronous serial interface that is available - immediately following reset when pin 9 (SDIO_SPI_CFG) is tied to - VDDIO. Select this if your platform is using the SPI bus. - -config WILC1000_HW_OOB_INTR - bool "WILC1000 out of band interrupt" - depends on WILC1000_SDIO - default n - ---help--- - This option enables out-of-band interrupt support for the WILC1000 - chipset. This OOB interrupt is intended to provide a faster interrupt - mechanism for SDIO host controllers that don't support SDIO interrupt. - Select this option If the SDIO host controller in your platform - doesn't support SDIO time devision interrupt. diff --git a/src/linux/drivers/staging/wlan-ng/Kconfig b/src/linux/drivers/staging/wlan-ng/Kconfig deleted file mode 100644 index 426d4ef..0000000 --- a/src/linux/drivers/staging/wlan-ng/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config PRISM2_USB - tristate "Prism2.5/3 USB driver" - depends on WLAN && USB && CFG80211 - select WIRELESS_EXT - select WEXT_PRIV - default n - ---help--- - This is the wlan-ng prism 2.5/3 USB driver for a wide range of - old USB wireless devices. - - To compile this driver as a module, choose M here: the module - will be called prism2_usb. diff --git a/src/linux/drivers/staging/xgifb/Kconfig b/src/linux/drivers/staging/xgifb/Kconfig deleted file mode 100644 index bb0ca59..0000000 --- a/src/linux/drivers/staging/xgifb/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config FB_XGI - tristate "XGI display support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This driver supports notebooks with XGI Z7,Z9,Z11 PCI chips. - Say Y if you have such a graphics card. - To compile this driver as a module, choose M here: the - module will be called xgifb.ko diff --git a/src/linux/drivers/target/Kconfig b/src/linux/drivers/target/Kconfig deleted file mode 100644 index 2573612..0000000 --- a/src/linux/drivers/target/Kconfig +++ /dev/null @@ -1,47 +0,0 @@ - -menuconfig TARGET_CORE - tristate "Generic Target Core Mod (TCM) and ConfigFS Infrastructure" - depends on SCSI && BLOCK - select CONFIGFS_FS - select CRC_T10DIF - default n - help - Say Y or M here to enable the TCM Storage Engine and ConfigFS enabled - control path for target_core_mod. This includes built-in TCM RAMDISK - subsystem logic for virtual LUN 0 access - -if TARGET_CORE - -config TCM_IBLOCK - tristate "TCM/IBLOCK Subsystem Plugin for Linux/BLOCK" - select BLK_DEV_INTEGRITY - help - Say Y here to enable the TCM/IBLOCK subsystem plugin for non-buffered - access to Linux/Block devices using BIO - -config TCM_FILEIO - tristate "TCM/FILEIO Subsystem Plugin for Linux/VFS" - help - Say Y here to enable the TCM/FILEIO subsystem plugin for buffered - access to Linux/VFS struct file or struct block_device - -config TCM_PSCSI - tristate "TCM/pSCSI Subsystem Plugin for Linux/SCSI" - help - Say Y here to enable the TCM/pSCSI subsystem plugin for non-buffered - passthrough access to Linux/SCSI device - -config TCM_USER2 - tristate "TCM/USER Subsystem Plugin for Linux" - depends on UIO && NET - help - Say Y here to enable the TCM/USER subsystem plugin for a userspace - process to handle requests. This is version 2 of the ABI; version 1 - is obsolete. - -source "drivers/target/loopback/Kconfig" -source "drivers/target/tcm_fc/Kconfig" -source "drivers/target/iscsi/Kconfig" -source "drivers/target/sbp/Kconfig" - -endif diff --git a/src/linux/drivers/target/iscsi/Kconfig b/src/linux/drivers/target/iscsi/Kconfig deleted file mode 100644 index bbdbf9c..0000000 --- a/src/linux/drivers/target/iscsi/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config ISCSI_TARGET - tristate "Linux-iSCSI.org iSCSI Target Mode Stack" - depends on NET - select CRYPTO - select CRYPTO_CRC32C - select CRYPTO_CRC32C_INTEL if X86 - help - Say M here to enable the ConfigFS enabled Linux-iSCSI.org iSCSI - Target Mode Stack. - -source "drivers/target/iscsi/cxgbit/Kconfig" diff --git a/src/linux/drivers/target/iscsi/cxgbit/Kconfig b/src/linux/drivers/target/iscsi/cxgbit/Kconfig deleted file mode 100644 index bc6c1d5..0000000 --- a/src/linux/drivers/target/iscsi/cxgbit/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -config ISCSI_TARGET_CXGB4 - tristate "Chelsio iSCSI target offload driver" - depends on ISCSI_TARGET && CHELSIO_T4 && INET - select CHELSIO_LIB - ---help--- - To compile this driver as module, choose M here: the module - will be called cxgbit. diff --git a/src/linux/drivers/target/loopback/Kconfig b/src/linux/drivers/target/loopback/Kconfig deleted file mode 100644 index abe8ecb..0000000 --- a/src/linux/drivers/target/loopback/Kconfig +++ /dev/null @@ -1,5 +0,0 @@ -config LOOPBACK_TARGET - tristate "TCM Virtual SAS target and Linux/SCSI LDD fabric loopback module" - help - Say Y here to enable the TCM Virtual SAS target and Linux/SCSI LLD - fabric loopback module. diff --git a/src/linux/drivers/target/sbp/Kconfig b/src/linux/drivers/target/sbp/Kconfig deleted file mode 100644 index 1614bc7..0000000 --- a/src/linux/drivers/target/sbp/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config SBP_TARGET - tristate "FireWire SBP-2 fabric module" - depends on FIREWIRE - help - Say Y or M here to enable SCSI target functionality over FireWire. - This enables you to expose SCSI devices to other nodes on the FireWire - bus, for example hard disks. Similar to FireWire Target Disk mode on - many Apple computers. - - To compile this driver as a module, say M here: The module will be - called sbp-target. diff --git a/src/linux/drivers/target/tcm_fc/Kconfig b/src/linux/drivers/target/tcm_fc/Kconfig deleted file mode 100644 index 40caf45..0000000 --- a/src/linux/drivers/target/tcm_fc/Kconfig +++ /dev/null @@ -1,5 +0,0 @@ -config TCM_FC - tristate "TCM_FC fabric Plugin" - depends on LIBFC - help - Say Y here to enable the TCM FC plugin for accessing FC fabrics in TCM diff --git a/src/linux/drivers/thermal/Kconfig b/src/linux/drivers/thermal/Kconfig deleted file mode 100644 index a13541b..0000000 --- a/src/linux/drivers/thermal/Kconfig +++ /dev/null @@ -1,437 +0,0 @@ -# -# Generic thermal sysfs drivers configuration -# - -menuconfig THERMAL - tristate "Generic Thermal sysfs driver" - help - Generic Thermal Sysfs driver offers a generic mechanism for - thermal management. Usually it's made up of one or more thermal - zone and cooling device. - Each thermal zone contains its own temperature, trip points, - cooling devices. - All platforms with ACPI thermal support can use this driver. - If you want this support, you should say Y or M here. - -if THERMAL - -config THERMAL_HWMON - bool - prompt "Expose thermal sensors as hwmon device" - depends on HWMON=y || HWMON=THERMAL - default y - help - In case a sensor is registered with the thermal - framework, this option will also register it - as a hwmon. The sensor will then have the common - hwmon sysfs interface. - - Say 'Y' here if you want all thermal sensors to - have hwmon sysfs interface too. - -config THERMAL_OF - bool - prompt "APIs to parse thermal data out of device tree" - depends on OF - default y - help - This options provides helpers to add the support to - read and parse thermal data definitions out of the - device tree blob. - - Say 'Y' here if you need to build thermal infrastructure - based on device tree. - -config THERMAL_WRITABLE_TRIPS - bool "Enable writable trip points" - help - This option allows the system integrator to choose whether - trip temperatures can be changed from userspace. The - writable trips need to be specified when setting up the - thermal zone but the choice here takes precedence. - - Say 'Y' here if you would like to allow userspace tools to - change trip temperatures. - -choice - prompt "Default Thermal governor" - default THERMAL_DEFAULT_GOV_STEP_WISE - help - This option sets which thermal governor shall be loaded at - startup. If in doubt, select 'step_wise'. - -config THERMAL_DEFAULT_GOV_STEP_WISE - bool "step_wise" - select THERMAL_GOV_STEP_WISE - help - Use the step_wise governor as default. This throttles the - devices one step at a time. - -config THERMAL_DEFAULT_GOV_FAIR_SHARE - bool "fair_share" - select THERMAL_GOV_FAIR_SHARE - help - Use the fair_share governor as default. This throttles the - devices based on their 'contribution' to a zone. The - contribution should be provided through platform data. - -config THERMAL_DEFAULT_GOV_USER_SPACE - bool "user_space" - select THERMAL_GOV_USER_SPACE - help - Select this if you want to let the user space manage the - platform thermals. - -config THERMAL_DEFAULT_GOV_POWER_ALLOCATOR - bool "power_allocator" - select THERMAL_GOV_POWER_ALLOCATOR - help - Select this if you want to control temperature based on - system and device power allocation. This governor can only - operate on cooling devices that implement the power API. - -endchoice - -config THERMAL_GOV_FAIR_SHARE - bool "Fair-share thermal governor" - help - Enable this to manage platform thermals using fair-share governor. - -config THERMAL_GOV_STEP_WISE - bool "Step_wise thermal governor" - help - Enable this to manage platform thermals using a simple linear - governor. - -config THERMAL_GOV_BANG_BANG - bool "Bang Bang thermal governor" - default n - help - Enable this to manage platform thermals using bang bang governor. - - Say 'Y' here if you want to use two point temperature regulation - used for fans without throttling. Some fan drivers depend on this - governor to be enabled (e.g. acerhdf). - -config THERMAL_GOV_USER_SPACE - bool "User_space thermal governor" - help - Enable this to let the user space manage the platform thermals. - -config THERMAL_GOV_POWER_ALLOCATOR - bool "Power allocator thermal governor" - help - Enable this to manage platform thermals by dynamically - allocating and limiting power to devices. - -config CPU_THERMAL - bool "generic cpu cooling support" - depends on CPU_FREQ - depends on THERMAL_OF - help - This implements the generic cpu cooling mechanism through frequency - reduction. An ACPI version of this already exists - (drivers/acpi/processor_thermal.c). - This will be useful for platforms using the generic thermal interface - and not the ACPI interface. - - If you want this support, you should say Y here. - -config CLOCK_THERMAL - bool "Generic clock cooling support" - depends on COMMON_CLK - depends on PM_OPP - help - This entry implements the generic clock cooling mechanism through - frequency clipping. Typically used to cool off co-processors. The - device that is configured to use this cooling mechanism will be - controlled to reduce clock frequency whenever temperature is high. - -config DEVFREQ_THERMAL - bool "Generic device cooling support" - depends on PM_DEVFREQ - depends on PM_OPP - help - This implements the generic devfreq cooling mechanism through - frequency reduction for devices using devfreq. - - This will throttle the device by limiting the maximum allowed DVFS - frequency corresponding to the cooling level. - - In order to use the power extensions of the cooling device, - devfreq should use the simple_ondemand governor. - - If you want this support, you should say Y here. - -config THERMAL_EMULATION - bool "Thermal emulation mode support" - help - Enable this option to make a emul_temp sysfs node in thermal zone - directory to support temperature emulation. With emulation sysfs node, - user can manually input temperature and test the different trip - threshold behaviour for simulation purpose. - - WARNING: Be careful while enabling this option on production systems, - because userland can easily disable the thermal policy by simply - flooding this sysfs node with low temperature values. - -config HISI_THERMAL - tristate "Hisilicon thermal driver" - depends on (ARCH_HISI && CPU_THERMAL && OF) || COMPILE_TEST - depends on HAS_IOMEM - help - Enable this to plug hisilicon's thermal sensor driver into the Linux - thermal framework. cpufreq is used as the cooling device to throttle - CPUs when the passive trip is crossed. - -config IMX_THERMAL - tristate "Temperature sensor driver for Freescale i.MX SoCs" - depends on (ARCH_MXC && CPU_THERMAL) || COMPILE_TEST - depends on MFD_SYSCON - depends on OF - help - Support for Temperature Monitor (TEMPMON) found on Freescale i.MX SoCs. - It supports one critical trip point and one passive trip point. The - cpufreq is used as the cooling device to throttle CPUs when the - passive trip is crossed. - -config MAX77620_THERMAL - tristate "Temperature sensor driver for Maxim MAX77620 PMIC" - depends on MFD_MAX77620 - depends on OF - help - Support for die junction temperature warning alarm for Maxim - Semiconductor PMIC MAX77620 device. Device generates two alarm - interrupts when PMIC die temperature cross the threshold of - 120 degC and 140 degC. - -config QORIQ_THERMAL - tristate "QorIQ Thermal Monitoring Unit" - depends on THERMAL_OF - depends on HAS_IOMEM - help - Support for Thermal Monitoring Unit (TMU) found on QorIQ platforms. - It supports one critical trip point and one passive trip point. The - cpufreq is used as the cooling device to throttle CPUs when the - passive trip is crossed. - -config SPEAR_THERMAL - tristate "SPEAr thermal sensor driver" - depends on PLAT_SPEAR || COMPILE_TEST - depends on HAS_IOMEM - depends on OF - help - Enable this to plug the SPEAr thermal sensor driver into the Linux - thermal framework. - -config ROCKCHIP_THERMAL - tristate "Rockchip thermal driver" - depends on ARCH_ROCKCHIP || COMPILE_TEST - depends on RESET_CONTROLLER - depends on HAS_IOMEM - help - Rockchip thermal driver provides support for Temperature sensor - ADC (TS-ADC) found on Rockchip SoCs. It supports one critical - trip point. Cpufreq is used as the cooling device and will throttle - CPUs when the Temperature crosses the passive trip point. - -config RCAR_THERMAL - tristate "Renesas R-Car thermal driver" - depends on ARCH_RENESAS || COMPILE_TEST - depends on HAS_IOMEM - help - Enable this to plug the R-Car thermal sensor driver into the Linux - thermal framework. - -config KIRKWOOD_THERMAL - tristate "Temperature sensor on Marvell Kirkwood SoCs" - depends on MACH_KIRKWOOD || COMPILE_TEST - depends on HAS_IOMEM - depends on OF - help - Support for the Kirkwood thermal sensor driver into the Linux thermal - framework. Only kirkwood 88F6282 and 88F6283 have this sensor. - -config DOVE_THERMAL - tristate "Temperature sensor on Marvell Dove SoCs" - depends on ARCH_DOVE || MACH_DOVE || COMPILE_TEST - depends on HAS_IOMEM - depends on OF - help - Support for the Dove thermal sensor driver in the Linux thermal - framework. - -config DB8500_THERMAL - tristate "DB8500 thermal management" - depends on MFD_DB8500_PRCMU - default y - help - Adds DB8500 thermal management implementation according to the thermal - management framework. A thermal zone with several trip points will be - created. Cooling devices can be bound to the trip points to cool this - thermal zone if trip points reached. - -config ARMADA_THERMAL - tristate "Armada 370/XP thermal management" - depends on ARCH_MVEBU || COMPILE_TEST - depends on HAS_IOMEM - depends on OF - help - Enable this option if you want to have support for thermal management - controller present in Armada 370 and Armada XP SoC. - -config DB8500_CPUFREQ_COOLING - tristate "DB8500 cpufreq cooling" - depends on ARCH_U8500 || COMPILE_TEST - depends on HAS_IOMEM - depends on CPU_THERMAL - default y - help - Adds DB8500 cpufreq cooling devices, and these cooling devices can be - bound to thermal zone trip points. When a trip point reached, the - bound cpufreq cooling device turns active to set CPU frequency low to - cool down the CPU. - -config INTEL_POWERCLAMP - tristate "Intel PowerClamp idle injection driver" - depends on THERMAL - depends on X86 - depends on CPU_SUP_INTEL - help - Enable this to enable Intel PowerClamp idle injection driver. This - enforce idle time which results in more package C-state residency. The - user interface is exposed via generic thermal framework. - -config X86_PKG_TEMP_THERMAL - tristate "X86 package temperature thermal driver" - depends on X86_THERMAL_VECTOR - select THERMAL_GOV_USER_SPACE - select THERMAL_WRITABLE_TRIPS - default m - help - Enable this to register CPU digital sensor for package temperature as - thermal zone. Each package will have its own thermal zone. There are - two trip points which can be set by user to get notifications via thermal - notification methods. - -config INTEL_SOC_DTS_IOSF_CORE - tristate - depends on X86 - select IOSF_MBI - help - This is becoming a common feature for Intel SoCs to expose the additional - digital temperature sensors (DTSs) using side band interface (IOSF). This - implements the common set of helper functions to register, get temperature - and get/set thresholds on DTSs. - -config INTEL_SOC_DTS_THERMAL - tristate "Intel SoCs DTS thermal driver" - depends on X86 - select INTEL_SOC_DTS_IOSF_CORE - select THERMAL_WRITABLE_TRIPS - help - Enable this to register Intel SoCs (e.g. Bay Trail) platform digital - temperature sensor (DTS). These SoCs have two additional DTSs in - addition to DTSs on CPU cores. Each DTS will be registered as a - thermal zone. There are two trip points. One of the trip point can - be set by user mode programs to get notifications via Linux thermal - notification methods.The other trip is a critical trip point, which - was set by the driver based on the TJ MAX temperature. - -config INTEL_QUARK_DTS_THERMAL - tristate "Intel Quark DTS thermal driver" - depends on X86_INTEL_QUARK - help - Enable this to register Intel Quark SoC (e.g. X1000) platform digital - temperature sensor (DTS). For X1000 SoC, it has one on-die DTS. - The DTS will be registered as a thermal zone. There are two trip points: - hot & critical. The critical trip point default value is set by - underlying BIOS/Firmware. - -menu "ACPI INT340X thermal drivers" -source drivers/thermal/int340x_thermal/Kconfig -endmenu - -config INTEL_BXT_PMIC_THERMAL - tristate "Intel Broxton PMIC thermal driver" - depends on X86 && INTEL_SOC_PMIC && REGMAP - help - Select this driver for Intel Broxton PMIC with ADC channels monitoring - system temperature measurements and alerts. - This driver is used for monitoring the ADC channels of PMIC and handles - the alert trip point interrupts and notifies the thermal framework with - the trip point and temperature details of the zone. - -config INTEL_PCH_THERMAL - tristate "Intel PCH Thermal Reporting Driver" - depends on X86 && PCI - help - Enable this to support thermal reporting on certain intel PCHs. - Thermal reporting device will provide temperature reading, - programmable trip points and other information. - -config MTK_THERMAL - tristate "Temperature sensor driver for mediatek SoCs" - depends on ARCH_MEDIATEK || COMPILE_TEST - depends on HAS_IOMEM - depends on NVMEM || NVMEM=n - depends on RESET_CONTROLLER - default y - help - Enable this option if you want to have support for thermal management - controller present in Mediatek SoCs - -menu "Texas Instruments thermal drivers" -depends on ARCH_HAS_BANDGAP || COMPILE_TEST -depends on HAS_IOMEM -source "drivers/thermal/ti-soc-thermal/Kconfig" -endmenu - -menu "Samsung thermal drivers" -depends on ARCH_EXYNOS || COMPILE_TEST -source "drivers/thermal/samsung/Kconfig" -endmenu - -menu "STMicroelectronics thermal drivers" -depends on ARCH_STI && OF -source "drivers/thermal/st/Kconfig" -endmenu - -config TANGO_THERMAL - tristate "Tango thermal management" - depends on ARCH_TANGO || COMPILE_TEST - help - Enable the Tango thermal driver, which supports the primitive - temperature sensor embedded in Tango chips since the SMP8758. - This sensor only generates a 1-bit signal to indicate whether - the die temperature exceeds a programmable threshold. - -source "drivers/thermal/tegra/Kconfig" - -config QCOM_SPMI_TEMP_ALARM - tristate "Qualcomm SPMI PMIC Temperature Alarm" - depends on OF && SPMI && IIO - select REGMAP_SPMI - help - This enables a thermal sysfs driver for Qualcomm plug-and-play (QPNP) - PMIC devices. It shows up in sysfs as a thermal sensor with multiple - trip points. The temperature reported by the thermal sensor reflects the - real time die temperature if an ADC is present or an estimate of the - temperature based upon the over temperature stage value. - -config GENERIC_ADC_THERMAL - tristate "Generic ADC based thermal sensor" - depends on IIO - help - This enabled a thermal sysfs driver for the temperature sensor - which is connected to the General Purpose ADC. The ADC channel - is read via IIO framework and the channel information is provided - to this driver. This driver reports the temperature by reading ADC - channel and converts it to temperature based on lookup table. - -menu "Qualcomm thermal drivers" -depends on (ARCH_QCOM && OF) || COMPILE_TEST -source "drivers/thermal/qcom/Kconfig" -endmenu - -endif diff --git a/src/linux/drivers/thermal/int340x_thermal/Kconfig b/src/linux/drivers/thermal/int340x_thermal/Kconfig deleted file mode 100644 index 0582bd1..0000000 --- a/src/linux/drivers/thermal/int340x_thermal/Kconfig +++ /dev/null @@ -1,42 +0,0 @@ -# -# ACPI INT340x thermal drivers configuration -# - -config INT340X_THERMAL - tristate "ACPI INT340X thermal drivers" - depends on X86 && ACPI - select THERMAL_GOV_USER_SPACE - select ACPI_THERMAL_REL - select ACPI_FAN - select INTEL_SOC_DTS_IOSF_CORE - help - Newer laptops and tablets that use ACPI may have thermal sensors and - other devices with thermal control capabilities outside the core - CPU/SOC, for thermal safety reasons. - They are exposed for the OS to use via the INT3400 ACPI device object - as the master, and INT3401~INT340B ACPI device objects as the slaves. - Enable this to expose the temperature information and cooling ability - from these objects to userspace via the normal thermal framework. - This means that a wide range of applications and GUI widgets can show - the information to the user or use this information for making - decisions. For example, the Intel Thermal Daemon can use this - information to allow the user to select his laptop to run without - turning on the fans. - -config ACPI_THERMAL_REL - tristate - depends on ACPI - -if INT340X_THERMAL - -config INT3406_THERMAL - tristate "ACPI INT3406 display thermal driver" - depends on ACPI_VIDEO - help - The display thermal device represents the LED/LCD display panel - that may or may not include touch support. The main function of - the display thermal device is to allow control of the display - brightness in order to address a thermal condition or to reduce - power consumed by display device. - -endif diff --git a/src/linux/drivers/thermal/qcom/Kconfig b/src/linux/drivers/thermal/qcom/Kconfig deleted file mode 100644 index be32e5a..0000000 --- a/src/linux/drivers/thermal/qcom/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config QCOM_TSENS - tristate "Qualcomm TSENS Temperature Alarm" - depends on THERMAL - depends on QCOM_QFPROM - depends on ARCH_QCOM || COMPILE_TEST - help - This enables the thermal sysfs driver for the TSENS device. It shows - up in Sysfs as a thermal zone with multiple trip points. Disabling the - thermal zone device via the mode file results in disabling the sensor. - Also able to set threshold temperature for both hot and cold and update - when a threshold is reached. diff --git a/src/linux/drivers/thermal/samsung/Kconfig b/src/linux/drivers/thermal/samsung/Kconfig deleted file mode 100644 index 222e644..0000000 --- a/src/linux/drivers/thermal/samsung/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config EXYNOS_THERMAL - tristate "Exynos thermal management unit driver" - depends on THERMAL_OF - depends on HAS_IOMEM - help - If you say yes here you get support for the TMU (Thermal Management - Unit) driver for SAMSUNG EXYNOS series of SoCs. This driver initialises - the TMU, reports temperature and handles cooling action if defined. - This driver uses the Exynos core thermal APIs and TMU configuration - data from the supported SoCs. diff --git a/src/linux/drivers/thermal/st/Kconfig b/src/linux/drivers/thermal/st/Kconfig deleted file mode 100644 index 490fdbe..0000000 --- a/src/linux/drivers/thermal/st/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config ST_THERMAL - tristate "Thermal sensors on STMicroelectronics STi series of SoCs" - help - Support for thermal sensors on STMicroelectronics STi series of SoCs. - -config ST_THERMAL_SYSCFG - select ST_THERMAL - tristate "STi series syscfg register access based thermal sensors" - -config ST_THERMAL_MEMMAP - select ST_THERMAL - tristate "STi series memory mapped access based thermal sensors" diff --git a/src/linux/drivers/thermal/tegra/Kconfig b/src/linux/drivers/thermal/tegra/Kconfig deleted file mode 100644 index cec586e..0000000 --- a/src/linux/drivers/thermal/tegra/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -menu "NVIDIA Tegra thermal drivers" -depends on ARCH_TEGRA - -config TEGRA_SOCTHERM - tristate "Tegra SOCTHERM thermal management" - help - Enable this option for integrated thermal management support on NVIDIA - Tegra systems-on-chip. The driver supports four thermal zones - (CPU, GPU, MEM, PLLX). Cooling devices can be bound to the thermal - zones to manage temperatures. This option is also required for the - emergency thermal reset (thermtrip) feature to function. - -endmenu diff --git a/src/linux/drivers/thermal/ti-soc-thermal/Kconfig b/src/linux/drivers/thermal/ti-soc-thermal/Kconfig deleted file mode 100644 index ea8283f..0000000 --- a/src/linux/drivers/thermal/ti-soc-thermal/Kconfig +++ /dev/null @@ -1,73 +0,0 @@ -config TI_SOC_THERMAL - tristate "Texas Instruments SoCs temperature sensor driver" - help - If you say yes here you get support for the Texas Instruments - OMAP4460+ on die bandgap temperature sensor support. The register - set is part of system control module. - - This includes alert interrupts generation and also the TSHUT - support. - -config TI_THERMAL - bool "Texas Instruments SoCs thermal framework support" - depends on TI_SOC_THERMAL - depends on CPU_THERMAL - help - If you say yes here you want to get support for generic thermal - framework for the Texas Instruments on die bandgap temperature sensor. - - This includes trip points definitions, extrapolation rules and - CPU cooling device bindings. - -config OMAP3_THERMAL - bool "Texas Instruments OMAP3 thermal support" - depends on TI_SOC_THERMAL - depends on ARCH_OMAP3 || COMPILE_TEST - help - If you say yes here you get thermal support for the Texas Instruments - OMAP3 SoC family. The current chips supported are: - - OMAP3430 - - OMAP3 chips normally don't need thermal management, and sensors in - this generation are not accurate, nor they are very close to - the important hotspots. - - Say 'N' here. - -config OMAP4_THERMAL - bool "Texas Instruments OMAP4 thermal support" - depends on TI_SOC_THERMAL - depends on ARCH_OMAP4 || COMPILE_TEST - help - If you say yes here you get thermal support for the Texas Instruments - OMAP4 SoC family. The current chip supported are: - - OMAP4430 - - OMAP4460 - - OMAP4470 - - This includes alert interrupts generation and also the TSHUT - support. - -config OMAP5_THERMAL - bool "Texas Instruments OMAP5 thermal support" - depends on TI_SOC_THERMAL - depends on SOC_OMAP5 || COMPILE_TEST - help - If you say yes here you get thermal support for the Texas Instruments - OMAP5 SoC family. The current chip supported are: - - OMAP5430 - - This includes alert interrupts generation and also the TSHUT - support. - -config DRA752_THERMAL - bool "Texas Instruments DRA752 thermal support" - depends on TI_SOC_THERMAL - depends on SOC_DRA7XX || COMPILE_TEST - help - If you say yes here you get thermal support for the Texas Instruments - DRA752 SoC family. The current chip supported are: - - DRA752 - - This includes alert interrupts generation and also the TSHUT - support. diff --git a/src/linux/drivers/thunderbolt/Kconfig b/src/linux/drivers/thunderbolt/Kconfig deleted file mode 100644 index c121acc..0000000 --- a/src/linux/drivers/thunderbolt/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -menuconfig THUNDERBOLT - tristate "Thunderbolt support for Apple devices" - depends on PCI - select CRC32 - help - Cactus Ridge Thunderbolt Controller driver - This driver is required if you want to hotplug Thunderbolt devices on - Apple hardware. - - Device chaining is currently not supported. - - To compile this driver a module, choose M here. The module will be - called thunderbolt. diff --git a/src/linux/drivers/tty/Kconfig b/src/linux/drivers/tty/Kconfig deleted file mode 100644 index 9510305..0000000 --- a/src/linux/drivers/tty/Kconfig +++ /dev/null @@ -1,458 +0,0 @@ -config TTY - bool "Enable TTY" if EXPERT - default y - ---help--- - Allows you to remove TTY support which can save space, and - blocks features that require TTY from inclusion in the kernel. - TTY is required for any text terminals or serial port - communication. Most users should leave this enabled. - -if TTY - -config VT - bool "Virtual terminal" if EXPERT - depends on !S390 && !UML - select INPUT - default y - ---help--- - If you say Y here, you will get support for terminal devices with - display and keyboard devices. These are called "virtual" because you - can run several virtual terminals (also called virtual consoles) on - one physical terminal. This is rather useful, for example one - virtual terminal can collect system messages and warnings, another - one can be used for a text-mode user session, and a third could run - an X session, all in parallel. Switching between virtual terminals - is done with certain key combinations, usually Alt-. - - The setterm command ("man setterm") can be used to change the - properties (such as colors or beeping) of a virtual terminal. The - man page console_codes(4) ("man console_codes") contains the special - character sequences that can be used to change those properties - directly. The fonts used on virtual terminals can be changed with - the setfont ("man setfont") command and the key bindings are defined - with the loadkeys ("man loadkeys") command. - - You need at least one virtual terminal device in order to make use - of your keyboard and monitor. Therefore, only people configuring an - embedded system would want to say N here in order to save some - memory; the only way to log into such a system is then via a serial - or network connection. - - If unsure, say Y, or else you won't be able to do much with your new - shiny Linux system :-) - -config CONSOLE_TRANSLATIONS - depends on VT - default y - bool "Enable character translations in console" if EXPERT - ---help--- - This enables support for font mapping and Unicode translation - on virtual consoles. - -config VT_CONSOLE - bool "Support for console on virtual terminal" if EXPERT - depends on VT - default y - ---help--- - The system console is the device which receives all kernel messages - and warnings and which allows logins in single user mode. If you - answer Y here, a virtual terminal (the device used to interact with - a physical terminal) can be used as system console. This is the most - common mode of operations, so you should say Y here unless you want - the kernel messages be output only to a serial port (in which case - you should say Y to "Console on serial port", below). - - If you do say Y here, by default the currently visible virtual - terminal (/dev/tty0) will be used as system console. You can change - that with a kernel command line option such as "console=tty3" which - would use the third virtual terminal as system console. (Try "man - bootparam" or see the documentation of your boot loader (lilo or - loadlin) about how to pass options to the kernel at boot time.) - - If unsure, say Y. - -config VT_CONSOLE_SLEEP - def_bool y - depends on VT_CONSOLE && PM_SLEEP - -config HW_CONSOLE - bool - depends on VT && !UML - default y - -config VT_HW_CONSOLE_BINDING - bool "Support for binding and unbinding console drivers" - depends on HW_CONSOLE - default n - ---help--- - The virtual terminal is the device that interacts with the physical - terminal through console drivers. On these systems, at least one - console driver is loaded. In other configurations, additional console - drivers may be enabled, such as the framebuffer console. If more than - 1 console driver is enabled, setting this to 'y' will allow you to - select the console driver that will serve as the backend for the - virtual terminals. - - See for more - information. For framebuffer console users, please refer to - . - -config UNIX98_PTYS - bool "Unix98 PTY support" if EXPERT - default y - ---help--- - A pseudo terminal (PTY) is a software device consisting of two - halves: a master and a slave. The slave device behaves identical to - a physical terminal; the master device is used by a process to - read data from and write data to the slave, thereby emulating a - terminal. Typical programs for the master side are telnet servers - and xterms. - - Linux has traditionally used the BSD-like names /dev/ptyxx for - masters and /dev/ttyxx for slaves of pseudo terminals. This scheme - has a number of problems. The GNU C library glibc 2.1 and later, - however, supports the Unix98 naming standard: in order to acquire a - pseudo terminal, a process opens /dev/ptmx; the number of the pseudo - terminal is then made available to the process and the pseudo - terminal slave can be accessed as /dev/pts/. What was - traditionally /dev/ttyp2 will then be /dev/pts/2, for example. - - All modern Linux systems use the Unix98 ptys. Say Y unless - you're on an embedded system and want to conserve memory. - -config LEGACY_PTYS - bool "Legacy (BSD) PTY support" - default y - ---help--- - A pseudo terminal (PTY) is a software device consisting of two - halves: a master and a slave. The slave device behaves identical to - a physical terminal; the master device is used by a process to - read data from and write data to the slave, thereby emulating a - terminal. Typical programs for the master side are telnet servers - and xterms. - - Linux has traditionally used the BSD-like names /dev/ptyxx - for masters and /dev/ttyxx for slaves of pseudo - terminals. This scheme has a number of problems, including - security. This option enables these legacy devices; on most - systems, it is safe to say N. - - -config LEGACY_PTY_COUNT - int "Maximum number of legacy PTY in use" - depends on LEGACY_PTYS - range 0 256 - default "256" - ---help--- - The maximum number of legacy PTYs that can be used at any one time. - The default is 256, and should be more than enough. Embedded - systems may want to reduce this to save memory. - - When not in use, each legacy PTY occupies 12 bytes on 32-bit - architectures and 24 bytes on 64-bit architectures. - -config BFIN_JTAG_COMM - tristate "Blackfin JTAG Communication" - depends on BLACKFIN - help - Add support for emulating a TTY device over the Blackfin JTAG. - - To compile this driver as a module, choose M here: the - module will be called bfin_jtag_comm. - -config BFIN_JTAG_COMM_CONSOLE - bool "Console on Blackfin JTAG" - depends on BFIN_JTAG_COMM=y - -config SERIAL_NONSTANDARD - bool "Non-standard serial port support" - depends on HAS_IOMEM - ---help--- - Say Y here if you have any non-standard serial boards -- boards - which aren't supported using the standard "dumb" serial driver. - This includes intelligent serial boards such as Cyclades, - Digiboards, etc. These are usually used for systems that need many - serial ports because they serve many terminals or dial-in - connections. - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about non-standard serial boards. - - Most people can say N here. - -config ROCKETPORT - tristate "Comtrol RocketPort support" - depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) - help - This driver supports Comtrol RocketPort and RocketModem PCI boards. - These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or - modems. For information about the RocketPort/RocketModem boards - and this driver read . - - To compile this driver as a module, choose M here: the - module will be called rocket. - - If you want to compile this driver into the kernel, say Y here. If - you don't have a Comtrol RocketPort/RocketModem card installed, say N. - -config CYCLADES - tristate "Cyclades async mux support" - depends on SERIAL_NONSTANDARD && (PCI || ISA) - select FW_LOADER - ---help--- - This driver supports Cyclades Z and Y multiserial boards. - You would need something like this to connect more than two modems to - your Linux box, for instance in order to become a dial-in server. - - For information about the Cyclades-Z card, read - . - - To compile this driver as a module, choose M here: the - module will be called cyclades. - - If you haven't heard about it, it's safe to say N. - -config CYZ_INTR - bool "Cyclades-Z interrupt mode operation" - depends on CYCLADES && PCI - help - The Cyclades-Z family of multiport cards allows 2 (two) driver op - modes: polling and interrupt. In polling mode, the driver will check - the status of the Cyclades-Z ports every certain amount of time - (which is called polling cycle and is configurable). In interrupt - mode, it will use an interrupt line (IRQ) in order to check the - status of the Cyclades-Z ports. The default op mode is polling. If - unsure, say N. - -config MOXA_INTELLIO - tristate "Moxa Intellio support" - depends on SERIAL_NONSTANDARD && (ISA || EISA || PCI) - select FW_LOADER - help - Say Y here if you have a Moxa Intellio multiport serial card. - - To compile this driver as a module, choose M here: the - module will be called moxa. - -config MOXA_SMARTIO - tristate "Moxa SmartIO support v. 2.0" - depends on SERIAL_NONSTANDARD && (PCI || EISA || ISA) - help - Say Y here if you have a Moxa SmartIO multiport serial card and/or - want to help develop a new version of this driver. - - This is upgraded (1.9.1) driver from original Moxa drivers with - changes finally resulting in PCI probing. - - This driver can also be built as a module. The module will be called - mxser. If you want to do that, say M here. - -config SYNCLINK - tristate "Microgate SyncLink card support" - depends on SERIAL_NONSTANDARD && PCI && ISA_DMA_API - help - Provides support for the SyncLink ISA and PCI multiprotocol serial - adapters. These adapters support asynchronous and HDLC bit - synchronous communication up to 10Mbps (PCI adapter). - - This driver can only be built as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called synclink. If you want to do that, say M - here. - -config SYNCLINKMP - tristate "SyncLink Multiport support" - depends on SERIAL_NONSTANDARD && PCI - help - Enable support for the SyncLink Multiport (2 or 4 ports) - serial adapter, running asynchronous and HDLC communications up - to 2.048Mbps. Each ports is independently selectable for - RS-232, V.35, RS-449, RS-530, and X.21 - - This driver may be built as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called synclinkmp. If you want to do that, say M - here. - -config SYNCLINK_GT - tristate "SyncLink GT/AC support" - depends on SERIAL_NONSTANDARD && PCI - help - Support for SyncLink GT and SyncLink AC families of - synchronous and asynchronous serial adapters - manufactured by Microgate Systems, Ltd. (www.microgate.com) - -config NOZOMI - tristate "HSDPA Broadband Wireless Data Card - Globe Trotter" - depends on PCI - help - If you have a HSDPA driver Broadband Wireless Data Card - - Globe Trotter PCMCIA card, say Y here. - - To compile this driver as a module, choose M here, the module - will be called nozomi. - -config ISI - tristate "Multi-Tech multiport card support" - depends on SERIAL_NONSTANDARD && PCI - select FW_LOADER - help - This is a driver for the Multi-Tech cards which provide several - serial ports. The driver is experimental and can currently only be - built as a module. The module will be called isicom. - If you want to do that, choose M here. - -config N_HDLC - tristate "HDLC line discipline support" - depends on SERIAL_NONSTANDARD - help - Allows synchronous HDLC communications with tty device drivers that - support synchronous HDLC such as the Microgate SyncLink adapter. - - This driver can be built as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called n_hdlc. If you want to do that, say M - here. - -config N_GSM - tristate "GSM MUX line discipline support (EXPERIMENTAL)" - depends on NET - help - This line discipline provides support for the GSM MUX protocol and - presents the mux as a set of 61 individual tty devices. - -config TRACE_ROUTER - tristate "Trace data router for MIPI P1149.7 cJTAG standard" - depends on TRACE_SINK - default n - help - The trace router uses the Linux tty line discipline framework to - route trace data coming from a tty port (say UART for example) to - the trace sink line discipline driver and to another tty port (say - USB). This is part of a solution for the MIPI P1149.7, compact JTAG, - standard, which is for debugging mobile devices. The PTI driver in - drivers/misc/pti.c defines the majority of this MIPI solution. - - You should select this driver if the target kernel is meant for - a mobile device containing a modem. Then you will need to select - "Trace data sink for MIPI P1149.7 cJTAG standard" line discipline - driver. - -config TRACE_SINK - tristate "Trace data sink for MIPI P1149.7 cJTAG standard" - default n - help - The trace sink uses the Linux line discipline framework to receive - trace data coming from the trace router line discipline driver - to a user-defined tty port target, like USB. - This is to provide a way to extract modem trace data on - devices that do not have a PTI HW module, or just need modem - trace data to come out of a different HW output port. - This is part of a solution for the P1149.7, compact JTAG, standard. - - If you select this option, you need to select - "Trace data router for MIPI P1149.7 cJTAG standard". - -config PPC_EPAPR_HV_BYTECHAN - bool "ePAPR hypervisor byte channel driver" - depends on PPC - select EPAPR_PARAVIRT - help - This driver creates /dev entries for each ePAPR hypervisor byte - channel, thereby allowing applications to communicate with byte - channels as if they were serial ports. - -config PPC_EARLY_DEBUG_EHV_BC - bool "Early console (udbg) support for ePAPR hypervisors" - depends on PPC_EPAPR_HV_BYTECHAN=y - help - Select this option to enable early console (a.k.a. "udbg") support - via an ePAPR byte channel. You also need to choose the byte channel - handle below. - -config PPC_EARLY_DEBUG_EHV_BC_HANDLE - int "Byte channel handle for early console (udbg)" - depends on PPC_EARLY_DEBUG_EHV_BC - default 0 - help - If you want early console (udbg) output through a byte channel, - specify the handle of the byte channel to use. - - For this to work, the byte channel driver must be compiled - in-kernel, not as a module. - - Note that only one early console driver can be enabled, so don't - enable any others if you enable this one. - - If the number you specify is not a valid byte channel handle, then - there simply will be no early console output. This is true also - if you don't boot under a hypervisor at all. - -config GOLDFISH_TTY - tristate "Goldfish TTY Driver" - depends on GOLDFISH - help - Console and system TTY driver for the Goldfish virtual platform. - -config DA_TTY - bool "DA TTY" - depends on METAG_DA - select SERIAL_NONSTANDARD - help - This enables a TTY on a Dash channel. - -config DA_CONSOLE - bool "DA Console" - depends on DA_TTY - help - This enables a console on a Dash channel. - -config MIPS_EJTAG_FDC_TTY - bool "MIPS EJTAG Fast Debug Channel TTY" - depends on MIPS_CDMM - help - This enables a TTY and console on the MIPS EJTAG Fast Debug Channels, - if they are present. This can be useful when working with an EJTAG - probe which supports it, to get console output and a login prompt via - EJTAG without needing to connect a serial cable. - - TTY devices are named e.g. ttyFDC3c2 (for FDC channel 2 of the FDC on - CPU3). - - The console can be enabled with console=fdc1 (for FDC channel 1 on all - CPUs). Do not use the console unless there is a debug probe attached - to drain the FDC TX FIFO. - - If unsure, say N. - -config MIPS_EJTAG_FDC_EARLYCON - bool "Early FDC console" - depends on MIPS_EJTAG_FDC_TTY - help - This registers a console on FDC channel 1 very early during boot (from - MIPS arch code). This is useful for bring-up and debugging early boot - issues. - - Do not enable unless there is a debug probe attached to drain the FDC - TX FIFO. - - If unsure, say N. - -config MIPS_EJTAG_FDC_KGDB - bool "Use KGDB over an FDC channel" - depends on MIPS_EJTAG_FDC_TTY && KGDB - default y - help - This enables the use of KGDB over an FDC channel, allowing KGDB to be - used remotely or when a serial port isn't available. - -config MIPS_EJTAG_FDC_KGDB_CHAN - int "KGDB FDC channel" - depends on MIPS_EJTAG_FDC_KGDB - range 2 15 - default 3 - help - FDC channel number to use for KGDB. - -endif # TTY diff --git a/src/linux/drivers/tty/Makefile b/src/linux/drivers/tty/Makefile deleted file mode 100644 index 5817e23..0000000 --- a/src/linux/drivers/tty/Makefile +++ /dev/null @@ -1,34 +0,0 @@ -obj-$(CONFIG_TTY) += tty_io.o n_tty.o tty_ioctl.o tty_ldisc.o \ - tty_buffer.o tty_port.o tty_mutex.o tty_ldsem.o -obj-$(CONFIG_LEGACY_PTYS) += pty.o -obj-$(CONFIG_UNIX98_PTYS) += pty.o -obj-$(CONFIG_AUDIT) += tty_audit.o -obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o -obj-$(CONFIG_N_HDLC) += n_hdlc.o -obj-$(CONFIG_N_GSM) += n_gsm.o -obj-$(CONFIG_TRACE_ROUTER) += n_tracerouter.o -obj-$(CONFIG_TRACE_SINK) += n_tracesink.o -obj-$(CONFIG_R3964) += n_r3964.o - -obj-y += vt/ -obj-$(CONFIG_HVC_DRIVER) += hvc/ -obj-y += serial/ - -# tty drivers -obj-$(CONFIG_AMIGA_BUILTIN_SERIAL) += amiserial.o -obj-$(CONFIG_BFIN_JTAG_COMM) += bfin_jtag_comm.o -obj-$(CONFIG_CYCLADES) += cyclades.o -obj-$(CONFIG_ISI) += isicom.o -obj-$(CONFIG_MOXA_INTELLIO) += moxa.o -obj-$(CONFIG_MOXA_SMARTIO) += mxser.o -obj-$(CONFIG_NOZOMI) += nozomi.o -obj-$(CONFIG_ROCKETPORT) += rocket.o -obj-$(CONFIG_SYNCLINK_GT) += synclink_gt.o -obj-$(CONFIG_SYNCLINKMP) += synclinkmp.o -obj-$(CONFIG_SYNCLINK) += synclink.o -obj-$(CONFIG_PPC_EPAPR_HV_BYTECHAN) += ehv_bytechan.o -obj-$(CONFIG_GOLDFISH_TTY) += goldfish.o -obj-$(CONFIG_DA_TTY) += metag_da.o -obj-$(CONFIG_MIPS_EJTAG_FDC_TTY) += mips_ejtag_fdc.o - -obj-y += ipwireless/ diff --git a/src/linux/drivers/tty/hvc/Kconfig b/src/linux/drivers/tty/hvc/Kconfig deleted file mode 100644 index 574da15..0000000 --- a/src/linux/drivers/tty/hvc/Kconfig +++ /dev/null @@ -1,117 +0,0 @@ -if TTY - -config HVC_DRIVER - bool - help - Generic "hypervisor virtual console" infrastructure for various - hypervisors (pSeries, iSeries, Xen, lguest). - It will automatically be selected if one of the back-end console drivers - is selected. - -config HVC_IRQ - bool - -config HVC_CONSOLE - bool "pSeries Hypervisor Virtual Console support" - depends on PPC_PSERIES - select HVC_DRIVER - select HVC_IRQ - help - pSeries machines when partitioned support a hypervisor virtual - console. This driver allows each pSeries partition to have a console - which is accessed via the HMC. - -config HVC_OLD_HVSI - bool "Old driver for pSeries serial port (/dev/hvsi*)" - depends on HVC_CONSOLE - default n - -config HVC_OPAL - bool "OPAL Console support" - depends on PPC_POWERNV - select HVC_DRIVER - select HVC_IRQ - default y - help - PowerNV machines running under OPAL need that driver to get a console - -config HVC_RTAS - bool "IBM RTAS Console support" - depends on PPC_RTAS - select HVC_DRIVER - help - IBM Console device driver which makes use of RTAS - -config HVC_IUCV - bool "z/VM IUCV Hypervisor console support (VM only)" - depends on S390 - select HVC_DRIVER - select IUCV - default y - help - This driver provides a Hypervisor console (HVC) back-end to access - a Linux (console) terminal via a z/VM IUCV communication path. - -config HVC_XEN - bool "Xen Hypervisor Console support" - depends on XEN - select HVC_DRIVER - select HVC_IRQ - default y - help - Xen virtual console device driver - -config HVC_XEN_FRONTEND - bool "Xen Hypervisor Multiple Consoles support" - depends on HVC_XEN - select XEN_XENBUS_FRONTEND - default y - help - Xen driver for secondary virtual consoles - -config HVC_UDBG - bool "udbg based fake hypervisor console" - depends on PPC - select HVC_DRIVER - default n - help - This is meant to be used during HW bring up or debugging when - no other console mechanism exist but udbg, to get you a quick - console for userspace. Do NOT enable in production kernels. - -config HVC_DCC - bool "ARM JTAG DCC console" - depends on ARM || ARM64 - select HVC_DRIVER - help - This console uses the JTAG DCC on ARM to create a console under the HVC - driver. This console is used through a JTAG only on ARM. If you don't have - a JTAG then you probably don't want this option. - -config HVC_BFIN_JTAG - bool "Blackfin JTAG console" - depends on BLACKFIN - select HVC_DRIVER - help - This console uses the Blackfin JTAG to create a console under the - the HVC driver. If you don't have JTAG, then you probably don't - want this option. - -config HVCS - tristate "IBM Hypervisor Virtual Console Server support" - depends on PPC_PSERIES && HVC_CONSOLE - help - Partitionable IBM Power5 ppc64 machines allow hosting of - firmware virtual consoles from one Linux partition by - another Linux partition. This driver allows console data - from Linux partitions to be accessed through TTY device - interfaces in the device tree of a Linux partition running - this driver. - - To compile this driver as a module, choose M here: the - module will be called hvcs. Additionally, this module - will depend on arch specific APIs exported from hvcserver.ko - which will also be compiled when this driver is built as a - module. - -endif # TTY diff --git a/src/linux/drivers/tty/ipwireless/Makefile b/src/linux/drivers/tty/ipwireless/Makefile deleted file mode 100644 index fe2e173..0000000 --- a/src/linux/drivers/tty/ipwireless/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for the IPWireless driver -# - -obj-$(CONFIG_IPWIRELESS) += ipwireless.o - -ipwireless-y := hardware.o main.o network.o tty.o - diff --git a/src/linux/drivers/tty/n_tty.c b/src/linux/drivers/tty/n_tty.c deleted file mode 100644 index bdf0e6e..0000000 --- a/src/linux/drivers/tty/n_tty.c +++ /dev/null @@ -1,2475 +0,0 @@ -/* - * n_tty.c --- implements the N_TTY line discipline. - * - * This code used to be in tty_io.c, but things are getting hairy - * enough that it made sense to split things off. (The N_TTY - * processing has changed so much that it's hardly recognizable, - * anyway...) - * - * Note that the open routine for N_TTY is guaranteed never to return - * an error. This is because Linux will fall back to setting a line - * to N_TTY if it can not switch to any other line discipline. - * - * Written by Theodore Ts'o, Copyright 1994. - * - * This file also contains code originally written by Linus Torvalds, - * Copyright 1991, 1992, 1993, and by Julian Cowley, Copyright 1994. - * - * This file may be redistributed under the terms of the GNU General Public - * License. - * - * Reduced memory usage for older ARM systems - Russell King. - * - * 2000/01/20 Fixed SMP locking on put_tty_queue using bits of - * the patch by Andrew J. Kroll - * who actually finally proved there really was a race. - * - * 2002/03/18 Implemented n_tty_wakeup to send SIGIO POLL_OUTs to - * waiting writing processes-Sapan Bhatia . - * Also fixed a bug in BLOCKING mode where n_tty_write returns - * EAGAIN - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* number of characters left in xmit buffer before select has we have room */ -#define WAKEUP_CHARS 256 - -/* - * This defines the low- and high-watermarks for throttling and - * unthrottling the TTY driver. These watermarks are used for - * controlling the space in the read buffer. - */ -#define TTY_THRESHOLD_THROTTLE 128 /* now based on remaining room */ -#define TTY_THRESHOLD_UNTHROTTLE 128 - -/* - * Special byte codes used in the echo buffer to represent operations - * or special handling of characters. Bytes in the echo buffer that - * are not part of such special blocks are treated as normal character - * codes. - */ -#define ECHO_OP_START 0xff -#define ECHO_OP_MOVE_BACK_COL 0x80 -#define ECHO_OP_SET_CANON_COL 0x81 -#define ECHO_OP_ERASE_TAB 0x82 - -#define ECHO_COMMIT_WATERMARK 256 -#define ECHO_BLOCK 256 -#define ECHO_DISCARD_WATERMARK N_TTY_BUF_SIZE - (ECHO_BLOCK + 32) - - -#undef N_TTY_TRACE -#ifdef N_TTY_TRACE -# define n_tty_trace(f, args...) trace_printk(f, ##args) -#else -# define n_tty_trace(f, args...) -#endif - -struct n_tty_data { - /* producer-published */ - size_t read_head; - size_t commit_head; - size_t canon_head; - size_t echo_head; - size_t echo_commit; - size_t echo_mark; - DECLARE_BITMAP(char_map, 256); - - /* private to n_tty_receive_overrun (single-threaded) */ - unsigned long overrun_time; - int num_overrun; - - /* non-atomic */ - bool no_room; - - /* must hold exclusive termios_rwsem to reset these */ - unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1; - unsigned char push:1; - - /* shared by producer and consumer */ - char read_buf[N_TTY_BUF_SIZE]; - DECLARE_BITMAP(read_flags, N_TTY_BUF_SIZE); - unsigned char echo_buf[N_TTY_BUF_SIZE]; - - /* consumer-published */ - size_t read_tail; - size_t line_start; - - /* protected by output lock */ - unsigned int column; - unsigned int canon_column; - size_t echo_tail; - - struct mutex atomic_read_lock; - struct mutex output_lock; -}; - -static inline size_t read_cnt(struct n_tty_data *ldata) -{ - return ldata->read_head - ldata->read_tail; -} - -static inline unsigned char read_buf(struct n_tty_data *ldata, size_t i) -{ - return ldata->read_buf[i & (N_TTY_BUF_SIZE - 1)]; -} - -static inline unsigned char *read_buf_addr(struct n_tty_data *ldata, size_t i) -{ - return &ldata->read_buf[i & (N_TTY_BUF_SIZE - 1)]; -} - -static inline unsigned char echo_buf(struct n_tty_data *ldata, size_t i) -{ - return ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)]; -} - -static inline unsigned char *echo_buf_addr(struct n_tty_data *ldata, size_t i) -{ - return &ldata->echo_buf[i & (N_TTY_BUF_SIZE - 1)]; -} - -static int tty_copy_to_user(struct tty_struct *tty, void __user *to, - size_t tail, size_t n) -{ - struct n_tty_data *ldata = tty->disc_data; - size_t size = N_TTY_BUF_SIZE - tail; - const void *from = read_buf_addr(ldata, tail); - int uncopied; - - if (n > size) { - tty_audit_add_data(tty, from, size); - uncopied = copy_to_user(to, from, size); - if (uncopied) - return uncopied; - to += size; - n -= size; - from = ldata->read_buf; - } - - tty_audit_add_data(tty, from, n); - return copy_to_user(to, from, n); -} - -/** - * n_tty_kick_worker - start input worker (if required) - * @tty: terminal - * - * Re-schedules the flip buffer work if it may have stopped - * - * Caller holds exclusive termios_rwsem - * or - * n_tty_read()/consumer path: - * holds non-exclusive termios_rwsem - */ - -static void n_tty_kick_worker(struct tty_struct *tty) -{ - struct n_tty_data *ldata = tty->disc_data; - - /* Did the input worker stop? Restart it */ - if (unlikely(ldata->no_room)) { - ldata->no_room = 0; - - WARN_RATELIMIT(tty->port->itty == NULL, - "scheduling with invalid itty\n"); - /* see if ldisc has been killed - if so, this means that - * even though the ldisc has been halted and ->buf.work - * cancelled, ->buf.work is about to be rescheduled - */ - WARN_RATELIMIT(test_bit(TTY_LDISC_HALTED, &tty->flags), - "scheduling buffer work for halted ldisc\n"); - tty_buffer_restart_work(tty->port); - } -} - -static ssize_t chars_in_buffer(struct tty_struct *tty) -{ - struct n_tty_data *ldata = tty->disc_data; - ssize_t n = 0; - - if (!ldata->icanon) - n = ldata->commit_head - ldata->read_tail; - else - n = ldata->canon_head - ldata->read_tail; - return n; -} - -/** - * n_tty_write_wakeup - asynchronous I/O notifier - * @tty: tty device - * - * Required for the ptys, serial driver etc. since processes - * that attach themselves to the master and rely on ASYNC - * IO must be woken up - */ - -static void n_tty_write_wakeup(struct tty_struct *tty) -{ - clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - kill_fasync(&tty->fasync, SIGIO, POLL_OUT); -} - -static void n_tty_check_throttle(struct tty_struct *tty) -{ - struct n_tty_data *ldata = tty->disc_data; - - /* - * Check the remaining room for the input canonicalization - * mode. We don't want to throttle the driver if we're in - * canonical mode and don't have a newline yet! - */ - if (ldata->icanon && ldata->canon_head == ldata->read_tail) - return; - - while (1) { - int throttled; - tty_set_flow_change(tty, TTY_THROTTLE_SAFE); - if (N_TTY_BUF_SIZE - read_cnt(ldata) >= TTY_THRESHOLD_THROTTLE) - break; - throttled = tty_throttle_safe(tty); - if (!throttled) - break; - } - __tty_set_flow_change(tty, 0); -} - -static void n_tty_check_unthrottle(struct tty_struct *tty) -{ - if (tty->driver->type == TTY_DRIVER_TYPE_PTY) { - if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE) - return; - n_tty_kick_worker(tty); - tty_wakeup(tty->link); - return; - } - - /* If there is enough space in the read buffer now, let the - * low-level driver know. We use chars_in_buffer() to - * check the buffer, as it now knows about canonical mode. - * Otherwise, if the driver is throttled and the line is - * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode, - * we won't get any more characters. - */ - - while (1) { - int unthrottled; - tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE); - if (chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE) - break; - n_tty_kick_worker(tty); - unthrottled = tty_unthrottle_safe(tty); - if (!unthrottled) - break; - } - __tty_set_flow_change(tty, 0); -} - -/** - * put_tty_queue - add character to tty - * @c: character - * @ldata: n_tty data - * - * Add a character to the tty read_buf queue. - * - * n_tty_receive_buf()/producer path: - * caller holds non-exclusive termios_rwsem - */ - -static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata) -{ - *read_buf_addr(ldata, ldata->read_head) = c; - ldata->read_head++; -} - -/** - * reset_buffer_flags - reset buffer state - * @tty: terminal to reset - * - * Reset the read buffer counters and clear the flags. - * Called from n_tty_open() and n_tty_flush_buffer(). - * - * Locking: caller holds exclusive termios_rwsem - * (or locking is not required) - */ - -static void reset_buffer_flags(struct n_tty_data *ldata) -{ - ldata->read_head = ldata->canon_head = ldata->read_tail = 0; - ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0; - ldata->commit_head = 0; - ldata->echo_mark = 0; - ldata->line_start = 0; - - ldata->erasing = 0; - bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); - ldata->push = 0; -} - -static void n_tty_packet_mode_flush(struct tty_struct *tty) -{ - unsigned long flags; - - if (tty->link->packet) { - spin_lock_irqsave(&tty->ctrl_lock, flags); - tty->ctrl_status |= TIOCPKT_FLUSHREAD; - spin_unlock_irqrestore(&tty->ctrl_lock, flags); - wake_up_interruptible(&tty->link->read_wait); - } -} - -/** - * n_tty_flush_buffer - clean input queue - * @tty: terminal device - * - * Flush the input buffer. Called when the tty layer wants the - * buffer flushed (eg at hangup) or when the N_TTY line discipline - * internally has to clean the pending queue (for example some signals). - * - * Holds termios_rwsem to exclude producer/consumer while - * buffer indices are reset. - * - * Locking: ctrl_lock, exclusive termios_rwsem - */ - -static void n_tty_flush_buffer(struct tty_struct *tty) -{ - down_write(&tty->termios_rwsem); - reset_buffer_flags(tty->disc_data); - n_tty_kick_worker(tty); - - if (tty->link) - n_tty_packet_mode_flush(tty); - up_write(&tty->termios_rwsem); -} - -/** - * is_utf8_continuation - utf8 multibyte check - * @c: byte to check - * - * Returns true if the utf8 character 'c' is a multibyte continuation - * character. We use this to correctly compute the on screen size - * of the character when printing - */ - -static inline int is_utf8_continuation(unsigned char c) -{ - return (c & 0xc0) == 0x80; -} - -/** - * is_continuation - multibyte check - * @c: byte to check - * - * Returns true if the utf8 character 'c' is a multibyte continuation - * character and the terminal is in unicode mode. - */ - -static inline int is_continuation(unsigned char c, struct tty_struct *tty) -{ - return I_IUTF8(tty) && is_utf8_continuation(c); -} - -/** - * do_output_char - output one character - * @c: character (or partial unicode symbol) - * @tty: terminal device - * @space: space available in tty driver write buffer - * - * This is a helper function that handles one output character - * (including special characters like TAB, CR, LF, etc.), - * doing OPOST processing and putting the results in the - * tty driver's write buffer. - * - * Note that Linux currently ignores TABDLY, CRDLY, VTDLY, FFDLY - * and NLDLY. They simply aren't relevant in the world today. - * If you ever need them, add them here. - * - * Returns the number of bytes of buffer space used or -1 if - * no space left. - * - * Locking: should be called under the output_lock to protect - * the column state and space left in the buffer - */ - -static int do_output_char(unsigned char c, struct tty_struct *tty, int space) -{ - struct n_tty_data *ldata = tty->disc_data; - int spaces; - - if (!space) - return -1; - - switch (c) { - case '\n': - if (O_ONLRET(tty)) - ldata->column = 0; - if (O_ONLCR(tty)) { - if (space < 2) - return -1; - ldata->canon_column = ldata->column = 0; - tty->ops->write(tty, "\r\n", 2); - return 2; - } - ldata->canon_column = ldata->column; - break; - case '\r': - if (O_ONOCR(tty) && ldata->column == 0) - return 0; - if (O_OCRNL(tty)) { - c = '\n'; - if (O_ONLRET(tty)) - ldata->canon_column = ldata->column = 0; - break; - } - ldata->canon_column = ldata->column = 0; - break; - case '\t': - spaces = 8 - (ldata->column & 7); - if (O_TABDLY(tty) == XTABS) { - if (space < spaces) - return -1; - ldata->column += spaces; - tty->ops->write(tty, " ", spaces); - return spaces; - } - ldata->column += spaces; - break; - case '\b': - if (ldata->column > 0) - ldata->column--; - break; - default: - if (!iscntrl(c)) { - if (O_OLCUC(tty)) - c = toupper(c); - if (!is_continuation(c, tty)) - ldata->column++; - } - break; - } - - tty_put_char(tty, c); - return 1; -} - -/** - * process_output - output post processor - * @c: character (or partial unicode symbol) - * @tty: terminal device - * - * Output one character with OPOST processing. - * Returns -1 when the output device is full and the character - * must be retried. - * - * Locking: output_lock to protect column state and space left - * (also, this is called from n_tty_write under the - * tty layer write lock) - */ - -static int process_output(unsigned char c, struct tty_struct *tty) -{ - struct n_tty_data *ldata = tty->disc_data; - int space, retval; - - mutex_lock(&ldata->output_lock); - - space = tty_write_room(tty); - retval = do_output_char(c, tty, space); - - mutex_unlock(&ldata->output_lock); - if (retval < 0) - return -1; - else - return 0; -} - -/** - * process_output_block - block post processor - * @tty: terminal device - * @buf: character buffer - * @nr: number of bytes to output - * - * Output a block of characters with OPOST processing. - * Returns the number of characters output. - * - * This path is used to speed up block console writes, among other - * things when processing blocks of output data. It handles only - * the simple cases normally found and helps to generate blocks of - * symbols for the console driver and thus improve performance. - * - * Locking: output_lock to protect column state and space left - * (also, this is called from n_tty_write under the - * tty layer write lock) - */ - -static ssize_t process_output_block(struct tty_struct *tty, - const unsigned char *buf, unsigned int nr) -{ - struct n_tty_data *ldata = tty->disc_data; - int space; - int i; - const unsigned char *cp; - - mutex_lock(&ldata->output_lock); - - space = tty_write_room(tty); - if (!space) { - mutex_unlock(&ldata->output_lock); - return 0; - } - if (nr > space) - nr = space; - - for (i = 0, cp = buf; i < nr; i++, cp++) { - unsigned char c = *cp; - - switch (c) { - case '\n': - if (O_ONLRET(tty)) - ldata->column = 0; - if (O_ONLCR(tty)) - goto break_out; - ldata->canon_column = ldata->column; - break; - case '\r': - if (O_ONOCR(tty) && ldata->column == 0) - goto break_out; - if (O_OCRNL(tty)) - goto break_out; - ldata->canon_column = ldata->column = 0; - break; - case '\t': - goto break_out; - case '\b': - if (ldata->column > 0) - ldata->column--; - break; - default: - if (!iscntrl(c)) { - if (O_OLCUC(tty)) - goto break_out; - if (!is_continuation(c, tty)) - ldata->column++; - } - break; - } - } -break_out: - i = tty->ops->write(tty, buf, i); - - mutex_unlock(&ldata->output_lock); - return i; -} - -/** - * process_echoes - write pending echo characters - * @tty: terminal device - * - * Write previously buffered echo (and other ldisc-generated) - * characters to the tty. - * - * Characters generated by the ldisc (including echoes) need to - * be buffered because the driver's write buffer can fill during - * heavy program output. Echoing straight to the driver will - * often fail under these conditions, causing lost characters and - * resulting mismatches of ldisc state information. - * - * Since the ldisc state must represent the characters actually sent - * to the driver at the time of the write, operations like certain - * changes in column state are also saved in the buffer and executed - * here. - * - * A circular fifo buffer is used so that the most recent characters - * are prioritized. Also, when control characters are echoed with a - * prefixed "^", the pair is treated atomically and thus not separated. - * - * Locking: callers must hold output_lock - */ - -static size_t __process_echoes(struct tty_struct *tty) -{ - struct n_tty_data *ldata = tty->disc_data; - int space, old_space; - size_t tail; - unsigned char c; - - old_space = space = tty_write_room(tty); - - tail = ldata->echo_tail; - while (ldata->echo_commit != tail) { - c = echo_buf(ldata, tail); - if (c == ECHO_OP_START) { - unsigned char op; - int no_space_left = 0; - - /* - * If the buffer byte is the start of a multi-byte - * operation, get the next byte, which is either the - * op code or a control character value. - */ - op = echo_buf(ldata, tail + 1); - - switch (op) { - unsigned int num_chars, num_bs; - - case ECHO_OP_ERASE_TAB: - num_chars = echo_buf(ldata, tail + 2); - - /* - * Determine how many columns to go back - * in order to erase the tab. - * This depends on the number of columns - * used by other characters within the tab - * area. If this (modulo 8) count is from - * the start of input rather than from a - * previous tab, we offset by canon column. - * Otherwise, tab spacing is normal. - */ - if (!(num_chars & 0x80)) - num_chars += ldata->canon_column; - num_bs = 8 - (num_chars & 7); - - if (num_bs > space) { - no_space_left = 1; - break; - } - space -= num_bs; - while (num_bs--) { - tty_put_char(tty, '\b'); - if (ldata->column > 0) - ldata->column--; - } - tail += 3; - break; - - case ECHO_OP_SET_CANON_COL: - ldata->canon_column = ldata->column; - tail += 2; - break; - - case ECHO_OP_MOVE_BACK_COL: - if (ldata->column > 0) - ldata->column--; - tail += 2; - break; - - case ECHO_OP_START: - /* This is an escaped echo op start code */ - if (!space) { - no_space_left = 1; - break; - } - tty_put_char(tty, ECHO_OP_START); - ldata->column++; - space--; - tail += 2; - break; - - default: - /* - * If the op is not a special byte code, - * it is a ctrl char tagged to be echoed - * as "^X" (where X is the letter - * representing the control char). - * Note that we must ensure there is - * enough space for the whole ctrl pair. - * - */ - if (space < 2) { - no_space_left = 1; - break; - } - tty_put_char(tty, '^'); - tty_put_char(tty, op ^ 0100); - ldata->column += 2; - space -= 2; - tail += 2; - } - - if (no_space_left) - break; - } else { - if (O_OPOST(tty)) { - int retval = do_output_char(c, tty, space); - if (retval < 0) - break; - space -= retval; - } else { - if (!space) - break; - tty_put_char(tty, c); - space -= 1; - } - tail += 1; - } - } - - /* If the echo buffer is nearly full (so that the possibility exists - * of echo overrun before the next commit), then discard enough - * data at the tail to prevent a subsequent overrun */ - while (ldata->echo_commit - tail >= ECHO_DISCARD_WATERMARK) { - if (echo_buf(ldata, tail) == ECHO_OP_START) { - if (echo_buf(ldata, tail + 1) == ECHO_OP_ERASE_TAB) - tail += 3; - else - tail += 2; - } else - tail++; - } - - ldata->echo_tail = tail; - return old_space - space; -} - -static void commit_echoes(struct tty_struct *tty) -{ - struct n_tty_data *ldata = tty->disc_data; - size_t nr, old, echoed; - size_t head; - - head = ldata->echo_head; - ldata->echo_mark = head; - old = ldata->echo_commit - ldata->echo_tail; - - /* Process committed echoes if the accumulated # of bytes - * is over the threshold (and try again each time another - * block is accumulated) */ - nr = head - ldata->echo_tail; - if (nr < ECHO_COMMIT_WATERMARK || (nr % ECHO_BLOCK > old % ECHO_BLOCK)) - return; - - mutex_lock(&ldata->output_lock); - ldata->echo_commit = head; - echoed = __process_echoes(tty); - mutex_unlock(&ldata->output_lock); - - if (echoed && tty->ops->flush_chars) - tty->ops->flush_chars(tty); -} - -static void process_echoes(struct tty_struct *tty) -{ - struct n_tty_data *ldata = tty->disc_data; - size_t echoed; - - if (ldata->echo_mark == ldata->echo_tail) - return; - - mutex_lock(&ldata->output_lock); - ldata->echo_commit = ldata->echo_mark; - echoed = __process_echoes(tty); - mutex_unlock(&ldata->output_lock); - - if (echoed && tty->ops->flush_chars) - tty->ops->flush_chars(tty); -} - -/* NB: echo_mark and echo_head should be equivalent here */ -static void flush_echoes(struct tty_struct *tty) -{ - struct n_tty_data *ldata = tty->disc_data; - - if ((!L_ECHO(tty) && !L_ECHONL(tty)) || - ldata->echo_commit == ldata->echo_head) - return; - - mutex_lock(&ldata->output_lock); - ldata->echo_commit = ldata->echo_head; - __process_echoes(tty); - mutex_unlock(&ldata->output_lock); -} - -/** - * add_echo_byte - add a byte to the echo buffer - * @c: unicode byte to echo - * @ldata: n_tty data - * - * Add a character or operation byte to the echo buffer. - */ - -static inline void add_echo_byte(unsigned char c, struct n_tty_data *ldata) -{ - *echo_buf_addr(ldata, ldata->echo_head++) = c; -} - -/** - * echo_move_back_col - add operation to move back a column - * @ldata: n_tty data - * - * Add an operation to the echo buffer to move back one column. - */ - -static void echo_move_back_col(struct n_tty_data *ldata) -{ - add_echo_byte(ECHO_OP_START, ldata); - add_echo_byte(ECHO_OP_MOVE_BACK_COL, ldata); -} - -/** - * echo_set_canon_col - add operation to set the canon column - * @ldata: n_tty data - * - * Add an operation to the echo buffer to set the canon column - * to the current column. - */ - -static void echo_set_canon_col(struct n_tty_data *ldata) -{ - add_echo_byte(ECHO_OP_START, ldata); - add_echo_byte(ECHO_OP_SET_CANON_COL, ldata); -} - -/** - * echo_erase_tab - add operation to erase a tab - * @num_chars: number of character columns already used - * @after_tab: true if num_chars starts after a previous tab - * @ldata: n_tty data - * - * Add an operation to the echo buffer to erase a tab. - * - * Called by the eraser function, which knows how many character - * columns have been used since either a previous tab or the start - * of input. This information will be used later, along with - * canon column (if applicable), to go back the correct number - * of columns. - */ - -static void echo_erase_tab(unsigned int num_chars, int after_tab, - struct n_tty_data *ldata) -{ - add_echo_byte(ECHO_OP_START, ldata); - add_echo_byte(ECHO_OP_ERASE_TAB, ldata); - - /* We only need to know this modulo 8 (tab spacing) */ - num_chars &= 7; - - /* Set the high bit as a flag if num_chars is after a previous tab */ - if (after_tab) - num_chars |= 0x80; - - add_echo_byte(num_chars, ldata); -} - -/** - * echo_char_raw - echo a character raw - * @c: unicode byte to echo - * @tty: terminal device - * - * Echo user input back onto the screen. This must be called only when - * L_ECHO(tty) is true. Called from the driver receive_buf path. - * - * This variant does not treat control characters specially. - */ - -static void echo_char_raw(unsigned char c, struct n_tty_data *ldata) -{ - if (c == ECHO_OP_START) { - add_echo_byte(ECHO_OP_START, ldata); - add_echo_byte(ECHO_OP_START, ldata); - } else { - add_echo_byte(c, ldata); - } -} - -/** - * echo_char - echo a character - * @c: unicode byte to echo - * @tty: terminal device - * - * Echo user input back onto the screen. This must be called only when - * L_ECHO(tty) is true. Called from the driver receive_buf path. - * - * This variant tags control characters to be echoed as "^X" - * (where X is the letter representing the control char). - */ - -static void echo_char(unsigned char c, struct tty_struct *tty) -{ - struct n_tty_data *ldata = tty->disc_data; - - if (c == ECHO_OP_START) { - add_echo_byte(ECHO_OP_START, ldata); - add_echo_byte(ECHO_OP_START, ldata); - } else { - if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') - add_echo_byte(ECHO_OP_START, ldata); - add_echo_byte(c, ldata); - } -} - -/** - * finish_erasing - complete erase - * @ldata: n_tty data - */ - -static inline void finish_erasing(struct n_tty_data *ldata) -{ - if (ldata->erasing) { - echo_char_raw('/', ldata); - ldata->erasing = 0; - } -} - -/** - * eraser - handle erase function - * @c: character input - * @tty: terminal device - * - * Perform erase and necessary output when an erase character is - * present in the stream from the driver layer. Handles the complexities - * of UTF-8 multibyte symbols. - * - * n_tty_receive_buf()/producer path: - * caller holds non-exclusive termios_rwsem - */ - -static void eraser(unsigned char c, struct tty_struct *tty) -{ - struct n_tty_data *ldata = tty->disc_data; - enum { ERASE, WERASE, KILL } kill_type; - size_t head; - size_t cnt; - int seen_alnums; - - if (ldata->read_head == ldata->canon_head) { - /* process_output('\a', tty); */ /* what do you think? */ - return; - } - if (c == ERASE_CHAR(tty)) - kill_type = ERASE; - else if (c == WERASE_CHAR(tty)) - kill_type = WERASE; - else { - if (!L_ECHO(tty)) { - ldata->read_head = ldata->canon_head; - return; - } - if (!L_ECHOK(tty) || !L_ECHOKE(tty) || !L_ECHOE(tty)) { - ldata->read_head = ldata->canon_head; - finish_erasing(ldata); - echo_char(KILL_CHAR(tty), tty); - /* Add a newline if ECHOK is on and ECHOKE is off. */ - if (L_ECHOK(tty)) - echo_char_raw('\n', ldata); - return; - } - kill_type = KILL; - } - - seen_alnums = 0; - while (ldata->read_head != ldata->canon_head) { - head = ldata->read_head; - - /* erase a single possibly multibyte character */ - do { - head--; - c = read_buf(ldata, head); - } while (is_continuation(c, tty) && head != ldata->canon_head); - - /* do not partially erase */ - if (is_continuation(c, tty)) - break; - - if (kill_type == WERASE) { - /* Equivalent to BSD's ALTWERASE. */ - if (isalnum(c) || c == '_') - seen_alnums++; - else if (seen_alnums) - break; - } - cnt = ldata->read_head - head; - ldata->read_head = head; - if (L_ECHO(tty)) { - if (L_ECHOPRT(tty)) { - if (!ldata->erasing) { - echo_char_raw('\\', ldata); - ldata->erasing = 1; - } - /* if cnt > 1, output a multi-byte character */ - echo_char(c, tty); - while (--cnt > 0) { - head++; - echo_char_raw(read_buf(ldata, head), ldata); - echo_move_back_col(ldata); - } - } else if (kill_type == ERASE && !L_ECHOE(tty)) { - echo_char(ERASE_CHAR(tty), tty); - } else if (c == '\t') { - unsigned int num_chars = 0; - int after_tab = 0; - size_t tail = ldata->read_head; - - /* - * Count the columns used for characters - * since the start of input or after a - * previous tab. - * This info is used to go back the correct - * number of columns. - */ - while (tail != ldata->canon_head) { - tail--; - c = read_buf(ldata, tail); - if (c == '\t') { - after_tab = 1; - break; - } else if (iscntrl(c)) { - if (L_ECHOCTL(tty)) - num_chars += 2; - } else if (!is_continuation(c, tty)) { - num_chars++; - } - } - echo_erase_tab(num_chars, after_tab, ldata); - } else { - if (iscntrl(c) && L_ECHOCTL(tty)) { - echo_char_raw('\b', ldata); - echo_char_raw(' ', ldata); - echo_char_raw('\b', ldata); - } - if (!iscntrl(c) || L_ECHOCTL(tty)) { - echo_char_raw('\b', ldata); - echo_char_raw(' ', ldata); - echo_char_raw('\b', ldata); - } - } - } - if (kill_type == ERASE) - break; - } - if (ldata->read_head == ldata->canon_head && L_ECHO(tty)) - finish_erasing(ldata); -} - -/** - * isig - handle the ISIG optio - * @sig: signal - * @tty: terminal - * - * Called when a signal is being sent due to terminal input. - * Called from the driver receive_buf path so serialized. - * - * Performs input and output flush if !NOFLSH. In this context, the echo - * buffer is 'output'. The signal is processed first to alert any current - * readers or writers to discontinue and exit their i/o loops. - * - * Locking: ctrl_lock - */ - -static void __isig(int sig, struct tty_struct *tty) -{ - struct pid *tty_pgrp = tty_get_pgrp(tty); - if (tty_pgrp) { - kill_pgrp(tty_pgrp, sig, 1); - put_pid(tty_pgrp); - } -} - -static void isig(int sig, struct tty_struct *tty) -{ - struct n_tty_data *ldata = tty->disc_data; - - if (L_NOFLSH(tty)) { - /* signal only */ - __isig(sig, tty); - - } else { /* signal and flush */ - up_read(&tty->termios_rwsem); - down_write(&tty->termios_rwsem); - - __isig(sig, tty); - - /* clear echo buffer */ - mutex_lock(&ldata->output_lock); - ldata->echo_head = ldata->echo_tail = 0; - ldata->echo_mark = ldata->echo_commit = 0; - mutex_unlock(&ldata->output_lock); - - /* clear output buffer */ - tty_driver_flush_buffer(tty); - - /* clear input buffer */ - reset_buffer_flags(tty->disc_data); - - /* notify pty master of flush */ - if (tty->link) - n_tty_packet_mode_flush(tty); - - up_write(&tty->termios_rwsem); - down_read(&tty->termios_rwsem); - } -} - -/** - * n_tty_receive_break - handle break - * @tty: terminal - * - * An RS232 break event has been hit in the incoming bitstream. This - * can cause a variety of events depending upon the termios settings. - * - * n_tty_receive_buf()/producer path: - * caller holds non-exclusive termios_rwsem - * - * Note: may get exclusive termios_rwsem if flushing input buffer - */ - -static void n_tty_receive_break(struct tty_struct *tty) -{ - struct n_tty_data *ldata = tty->disc_data; - - if (I_IGNBRK(tty)) - return; - if (I_BRKINT(tty)) { - isig(SIGINT, tty); - return; - } - if (I_PARMRK(tty)) { - put_tty_queue('\377', ldata); - put_tty_queue('\0', ldata); - } - put_tty_queue('\0', ldata); -} - -/** - * n_tty_receive_overrun - handle overrun reporting - * @tty: terminal - * - * Data arrived faster than we could process it. While the tty - * driver has flagged this the bits that were missed are gone - * forever. - * - * Called from the receive_buf path so single threaded. Does not - * need locking as num_overrun and overrun_time are function - * private. - */ - -static void n_tty_receive_overrun(struct tty_struct *tty) -{ - struct n_tty_data *ldata = tty->disc_data; - - ldata->num_overrun++; - if (time_after(jiffies, ldata->overrun_time + HZ) || - time_after(ldata->overrun_time, jiffies)) { - tty_warn(tty, "%d input overrun(s)\n", ldata->num_overrun); - ldata->overrun_time = jiffies; - ldata->num_overrun = 0; - } -} - -/** - * n_tty_receive_parity_error - error notifier - * @tty: terminal device - * @c: character - * - * Process a parity error and queue the right data to indicate - * the error case if necessary. - * - * n_tty_receive_buf()/producer path: - * caller holds non-exclusive termios_rwsem - */ -static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c) -{ - struct n_tty_data *ldata = tty->disc_data; - - if (I_INPCK(tty)) { - if (I_IGNPAR(tty)) - return; - if (I_PARMRK(tty)) { - put_tty_queue('\377', ldata); - put_tty_queue('\0', ldata); - put_tty_queue(c, ldata); - } else - put_tty_queue('\0', ldata); - } else - put_tty_queue(c, ldata); -} - -static void -n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c) -{ - isig(signal, tty); - if (I_IXON(tty)) - start_tty(tty); - if (L_ECHO(tty)) { - echo_char(c, tty); - commit_echoes(tty); - } else - process_echoes(tty); - return; -} - -/** - * n_tty_receive_char - perform processing - * @tty: terminal device - * @c: character - * - * Process an individual character of input received from the driver. - * This is serialized with respect to itself by the rules for the - * driver above. - * - * n_tty_receive_buf()/producer path: - * caller holds non-exclusive termios_rwsem - * publishes canon_head if canonical mode is active - * - * Returns 1 if LNEXT was received, else returns 0 - */ - -static int -n_tty_receive_char_special(struct tty_struct *tty, unsigned char c) -{ - struct n_tty_data *ldata = tty->disc_data; - - if (I_IXON(tty)) { - if (c == START_CHAR(tty)) { - start_tty(tty); - process_echoes(tty); - return 0; - } - if (c == STOP_CHAR(tty)) { - stop_tty(tty); - return 0; - } - } - - if (L_ISIG(tty)) { - if (c == INTR_CHAR(tty)) { - n_tty_receive_signal_char(tty, SIGINT, c); - return 0; - } else if (c == QUIT_CHAR(tty)) { - n_tty_receive_signal_char(tty, SIGQUIT, c); - return 0; - } else if (c == SUSP_CHAR(tty)) { - n_tty_receive_signal_char(tty, SIGTSTP, c); - return 0; - } - } - - if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) { - start_tty(tty); - process_echoes(tty); - } - - if (c == '\r') { - if (I_IGNCR(tty)) - return 0; - if (I_ICRNL(tty)) - c = '\n'; - } else if (c == '\n' && I_INLCR(tty)) - c = '\r'; - - if (ldata->icanon) { - if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) || - (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) { - eraser(c, tty); - commit_echoes(tty); - return 0; - } - if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) { - ldata->lnext = 1; - if (L_ECHO(tty)) { - finish_erasing(ldata); - if (L_ECHOCTL(tty)) { - echo_char_raw('^', ldata); - echo_char_raw('\b', ldata); - commit_echoes(tty); - } - } - return 1; - } - if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && L_IEXTEN(tty)) { - size_t tail = ldata->canon_head; - - finish_erasing(ldata); - echo_char(c, tty); - echo_char_raw('\n', ldata); - while (tail != ldata->read_head) { - echo_char(read_buf(ldata, tail), tty); - tail++; - } - commit_echoes(tty); - return 0; - } - if (c == '\n') { - if (L_ECHO(tty) || L_ECHONL(tty)) { - echo_char_raw('\n', ldata); - commit_echoes(tty); - } - goto handle_newline; - } - if (c == EOF_CHAR(tty)) { - c = __DISABLED_CHAR; - goto handle_newline; - } - if ((c == EOL_CHAR(tty)) || - (c == EOL2_CHAR(tty) && L_IEXTEN(tty))) { - /* - * XXX are EOL_CHAR and EOL2_CHAR echoed?!? - */ - if (L_ECHO(tty)) { - /* Record the column of first canon char. */ - if (ldata->canon_head == ldata->read_head) - echo_set_canon_col(ldata); - echo_char(c, tty); - commit_echoes(tty); - } - /* - * XXX does PARMRK doubling happen for - * EOL_CHAR and EOL2_CHAR? - */ - if (c == (unsigned char) '\377' && I_PARMRK(tty)) - put_tty_queue(c, ldata); - -handle_newline: - set_bit(ldata->read_head & (N_TTY_BUF_SIZE - 1), ldata->read_flags); - put_tty_queue(c, ldata); - smp_store_release(&ldata->canon_head, ldata->read_head); - kill_fasync(&tty->fasync, SIGIO, POLL_IN); - wake_up_interruptible_poll(&tty->read_wait, POLLIN); - return 0; - } - } - - if (L_ECHO(tty)) { - finish_erasing(ldata); - if (c == '\n') - echo_char_raw('\n', ldata); - else { - /* Record the column of first canon char. */ - if (ldata->canon_head == ldata->read_head) - echo_set_canon_col(ldata); - echo_char(c, tty); - } - commit_echoes(tty); - } - - /* PARMRK doubling check */ - if (c == (unsigned char) '\377' && I_PARMRK(tty)) - put_tty_queue(c, ldata); - - put_tty_queue(c, ldata); - return 0; -} - -static inline void -n_tty_receive_char_inline(struct tty_struct *tty, unsigned char c) -{ - struct n_tty_data *ldata = tty->disc_data; - - if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) { - start_tty(tty); - process_echoes(tty); - } - if (L_ECHO(tty)) { - finish_erasing(ldata); - /* Record the column of first canon char. */ - if (ldata->canon_head == ldata->read_head) - echo_set_canon_col(ldata); - echo_char(c, tty); - commit_echoes(tty); - } - /* PARMRK doubling check */ - if (c == (unsigned char) '\377' && I_PARMRK(tty)) - put_tty_queue(c, ldata); - put_tty_queue(c, ldata); -} - -static void n_tty_receive_char(struct tty_struct *tty, unsigned char c) -{ - n_tty_receive_char_inline(tty, c); -} - -static inline void -n_tty_receive_char_fast(struct tty_struct *tty, unsigned char c) -{ - struct n_tty_data *ldata = tty->disc_data; - - if (tty->stopped && !tty->flow_stopped && I_IXON(tty) && I_IXANY(tty)) { - start_tty(tty); - process_echoes(tty); - } - if (L_ECHO(tty)) { - finish_erasing(ldata); - /* Record the column of first canon char. */ - if (ldata->canon_head == ldata->read_head) - echo_set_canon_col(ldata); - echo_char(c, tty); - commit_echoes(tty); - } - put_tty_queue(c, ldata); -} - -static void n_tty_receive_char_closing(struct tty_struct *tty, unsigned char c) -{ - if (I_ISTRIP(tty)) - c &= 0x7f; - if (I_IUCLC(tty) && L_IEXTEN(tty)) - c = tolower(c); - - if (I_IXON(tty)) { - if (c == STOP_CHAR(tty)) - stop_tty(tty); - else if (c == START_CHAR(tty) || - (tty->stopped && !tty->flow_stopped && I_IXANY(tty) && - c != INTR_CHAR(tty) && c != QUIT_CHAR(tty) && - c != SUSP_CHAR(tty))) { - start_tty(tty); - process_echoes(tty); - } - } -} - -static void -n_tty_receive_char_flagged(struct tty_struct *tty, unsigned char c, char flag) -{ - switch (flag) { - case TTY_BREAK: - n_tty_receive_break(tty); - break; - case TTY_PARITY: - case TTY_FRAME: - n_tty_receive_parity_error(tty, c); - break; - case TTY_OVERRUN: - n_tty_receive_overrun(tty); - break; - default: - tty_err(tty, "unknown flag %d\n", flag); - break; - } -} - -static void -n_tty_receive_char_lnext(struct tty_struct *tty, unsigned char c, char flag) -{ - struct n_tty_data *ldata = tty->disc_data; - - ldata->lnext = 0; - if (likely(flag == TTY_NORMAL)) { - if (I_ISTRIP(tty)) - c &= 0x7f; - if (I_IUCLC(tty) && L_IEXTEN(tty)) - c = tolower(c); - n_tty_receive_char(tty, c); - } else - n_tty_receive_char_flagged(tty, c, flag); -} - -static void -n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) -{ - struct n_tty_data *ldata = tty->disc_data; - size_t n, head; - - head = ldata->read_head & (N_TTY_BUF_SIZE - 1); - n = min_t(size_t, count, N_TTY_BUF_SIZE - head); - memcpy(read_buf_addr(ldata, head), cp, n); - ldata->read_head += n; - cp += n; - count -= n; - - head = ldata->read_head & (N_TTY_BUF_SIZE - 1); - n = min_t(size_t, count, N_TTY_BUF_SIZE - head); - memcpy(read_buf_addr(ldata, head), cp, n); - ldata->read_head += n; -} - -static void -n_tty_receive_buf_raw(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) -{ - struct n_tty_data *ldata = tty->disc_data; - char flag = TTY_NORMAL; - - while (count--) { - if (fp) - flag = *fp++; - if (likely(flag == TTY_NORMAL)) - put_tty_queue(*cp++, ldata); - else - n_tty_receive_char_flagged(tty, *cp++, flag); - } -} - -static void -n_tty_receive_buf_closing(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) -{ - char flag = TTY_NORMAL; - - while (count--) { - if (fp) - flag = *fp++; - if (likely(flag == TTY_NORMAL)) - n_tty_receive_char_closing(tty, *cp++); - } -} - -static void -n_tty_receive_buf_standard(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) -{ - struct n_tty_data *ldata = tty->disc_data; - char flag = TTY_NORMAL; - - while (count--) { - if (fp) - flag = *fp++; - if (likely(flag == TTY_NORMAL)) { - unsigned char c = *cp++; - - if (I_ISTRIP(tty)) - c &= 0x7f; - if (I_IUCLC(tty) && L_IEXTEN(tty)) - c = tolower(c); - if (L_EXTPROC(tty)) { - put_tty_queue(c, ldata); - continue; - } - if (!test_bit(c, ldata->char_map)) - n_tty_receive_char_inline(tty, c); - else if (n_tty_receive_char_special(tty, c) && count) { - if (fp) - flag = *fp++; - n_tty_receive_char_lnext(tty, *cp++, flag); - count--; - } - } else - n_tty_receive_char_flagged(tty, *cp++, flag); - } -} - -static void -n_tty_receive_buf_fast(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) -{ - struct n_tty_data *ldata = tty->disc_data; - char flag = TTY_NORMAL; - - while (count--) { - if (fp) - flag = *fp++; - if (likely(flag == TTY_NORMAL)) { - unsigned char c = *cp++; - - if (!test_bit(c, ldata->char_map)) - n_tty_receive_char_fast(tty, c); - else if (n_tty_receive_char_special(tty, c) && count) { - if (fp) - flag = *fp++; - n_tty_receive_char_lnext(tty, *cp++, flag); - count--; - } - } else - n_tty_receive_char_flagged(tty, *cp++, flag); - } -} - -static void __receive_buf(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) -{ - struct n_tty_data *ldata = tty->disc_data; - bool preops = I_ISTRIP(tty) || (I_IUCLC(tty) && L_IEXTEN(tty)); - - if (ldata->real_raw) - n_tty_receive_buf_real_raw(tty, cp, fp, count); - else if (ldata->raw || (L_EXTPROC(tty) && !preops)) - n_tty_receive_buf_raw(tty, cp, fp, count); - else if (tty->closing && !L_EXTPROC(tty)) - n_tty_receive_buf_closing(tty, cp, fp, count); - else { - if (ldata->lnext) { - char flag = TTY_NORMAL; - - if (fp) - flag = *fp++; - n_tty_receive_char_lnext(tty, *cp++, flag); - count--; - } - - if (!preops && !I_PARMRK(tty)) - n_tty_receive_buf_fast(tty, cp, fp, count); - else - n_tty_receive_buf_standard(tty, cp, fp, count); - - flush_echoes(tty); - if (tty->ops->flush_chars) - tty->ops->flush_chars(tty); - } - - if (ldata->icanon && !L_EXTPROC(tty)) - return; - - /* publish read_head to consumer */ - smp_store_release(&ldata->commit_head, ldata->read_head); - - if (read_cnt(ldata)) { - kill_fasync(&tty->fasync, SIGIO, POLL_IN); - wake_up_interruptible_poll(&tty->read_wait, POLLIN); - } -} - -/** - * n_tty_receive_buf_common - process input - * @tty: device to receive input - * @cp: input chars - * @fp: flags for each char (if NULL, all chars are TTY_NORMAL) - * @count: number of input chars in @cp - * - * Called by the terminal driver when a block of characters has - * been received. This function must be called from soft contexts - * not from interrupt context. The driver is responsible for making - * calls one at a time and in order (or using flush_to_ldisc) - * - * Returns the # of input chars from @cp which were processed. - * - * In canonical mode, the maximum line length is 4096 chars (including - * the line termination char); lines longer than 4096 chars are - * truncated. After 4095 chars, input data is still processed but - * not stored. Overflow processing ensures the tty can always - * receive more input until at least one line can be read. - * - * In non-canonical mode, the read buffer will only accept 4095 chars; - * this provides the necessary space for a newline char if the input - * mode is switched to canonical. - * - * Note it is possible for the read buffer to _contain_ 4096 chars - * in non-canonical mode: the read buffer could already contain the - * maximum canon line of 4096 chars when the mode is switched to - * non-canonical. - * - * n_tty_receive_buf()/producer path: - * claims non-exclusive termios_rwsem - * publishes commit_head or canon_head - */ -static int -n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count, int flow) -{ - struct n_tty_data *ldata = tty->disc_data; - int room, n, rcvd = 0, overflow; - - down_read(&tty->termios_rwsem); - - while (1) { - /* - * When PARMRK is set, each input char may take up to 3 chars - * in the read buf; reduce the buffer space avail by 3x - * - * If we are doing input canonicalization, and there are no - * pending newlines, let characters through without limit, so - * that erase characters will be handled. Other excess - * characters will be beeped. - * - * paired with store in *_copy_from_read_buf() -- guarantees - * the consumer has loaded the data in read_buf up to the new - * read_tail (so this producer will not overwrite unread data) - */ - size_t tail = smp_load_acquire(&ldata->read_tail); - - room = N_TTY_BUF_SIZE - (ldata->read_head - tail); - if (I_PARMRK(tty)) - room = (room + 2) / 3; - room--; - if (room <= 0) { - overflow = ldata->icanon && ldata->canon_head == tail; - if (overflow && room < 0) - ldata->read_head--; - room = overflow; - ldata->no_room = flow && !room; - } else - overflow = 0; - - n = min(count, room); - if (!n) - break; - - /* ignore parity errors if handling overflow */ - if (!overflow || !fp || *fp != TTY_PARITY) - __receive_buf(tty, cp, fp, n); - - cp += n; - if (fp) - fp += n; - count -= n; - rcvd += n; - } - - tty->receive_room = room; - - /* Unthrottle if handling overflow on pty */ - if (tty->driver->type == TTY_DRIVER_TYPE_PTY) { - if (overflow) { - tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE); - tty_unthrottle_safe(tty); - __tty_set_flow_change(tty, 0); - } - } else - n_tty_check_throttle(tty); - - up_read(&tty->termios_rwsem); - - return rcvd; -} - -static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) -{ - n_tty_receive_buf_common(tty, cp, fp, count, 0); -} - -static int n_tty_receive_buf2(struct tty_struct *tty, const unsigned char *cp, - char *fp, int count) -{ - return n_tty_receive_buf_common(tty, cp, fp, count, 1); -} - -/** - * n_tty_set_termios - termios data changed - * @tty: terminal - * @old: previous data - * - * Called by the tty layer when the user changes termios flags so - * that the line discipline can plan ahead. This function cannot sleep - * and is protected from re-entry by the tty layer. The user is - * guaranteed that this function will not be re-entered or in progress - * when the ldisc is closed. - * - * Locking: Caller holds tty->termios_rwsem - */ - -static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old) -{ - struct n_tty_data *ldata = tty->disc_data; - - if (!old || (old->c_lflag ^ tty->termios.c_lflag) & ICANON) { - bitmap_zero(ldata->read_flags, N_TTY_BUF_SIZE); - ldata->line_start = ldata->read_tail; - if (!L_ICANON(tty) || !read_cnt(ldata)) { - ldata->canon_head = ldata->read_tail; - ldata->push = 0; - } else { - set_bit((ldata->read_head - 1) & (N_TTY_BUF_SIZE - 1), - ldata->read_flags); - ldata->canon_head = ldata->read_head; - ldata->push = 1; - } - ldata->commit_head = ldata->read_head; - ldata->erasing = 0; - ldata->lnext = 0; - } - - ldata->icanon = (L_ICANON(tty) != 0); - - if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) || - I_ICRNL(tty) || I_INLCR(tty) || L_ICANON(tty) || - I_IXON(tty) || L_ISIG(tty) || L_ECHO(tty) || - I_PARMRK(tty)) { - bitmap_zero(ldata->char_map, 256); - - if (I_IGNCR(tty) || I_ICRNL(tty)) - set_bit('\r', ldata->char_map); - if (I_INLCR(tty)) - set_bit('\n', ldata->char_map); - - if (L_ICANON(tty)) { - set_bit(ERASE_CHAR(tty), ldata->char_map); - set_bit(KILL_CHAR(tty), ldata->char_map); - set_bit(EOF_CHAR(tty), ldata->char_map); - set_bit('\n', ldata->char_map); - set_bit(EOL_CHAR(tty), ldata->char_map); - if (L_IEXTEN(tty)) { - set_bit(WERASE_CHAR(tty), ldata->char_map); - set_bit(LNEXT_CHAR(tty), ldata->char_map); - set_bit(EOL2_CHAR(tty), ldata->char_map); - if (L_ECHO(tty)) - set_bit(REPRINT_CHAR(tty), - ldata->char_map); - } - } - if (I_IXON(tty)) { - set_bit(START_CHAR(tty), ldata->char_map); - set_bit(STOP_CHAR(tty), ldata->char_map); - } - if (L_ISIG(tty)) { - set_bit(INTR_CHAR(tty), ldata->char_map); - set_bit(QUIT_CHAR(tty), ldata->char_map); - set_bit(SUSP_CHAR(tty), ldata->char_map); - } - clear_bit(__DISABLED_CHAR, ldata->char_map); - ldata->raw = 0; - ldata->real_raw = 0; - } else { - ldata->raw = 1; - if ((I_IGNBRK(tty) || (!I_BRKINT(tty) && !I_PARMRK(tty))) && - (I_IGNPAR(tty) || !I_INPCK(tty)) && - (tty->driver->flags & TTY_DRIVER_REAL_RAW)) - ldata->real_raw = 1; - else - ldata->real_raw = 0; - } - /* - * Fix tty hang when I_IXON(tty) is cleared, but the tty - * been stopped by STOP_CHAR(tty) before it. - */ - if (!I_IXON(tty) && old && (old->c_iflag & IXON) && !tty->flow_stopped) { - start_tty(tty); - process_echoes(tty); - } - - /* The termios change make the tty ready for I/O */ - wake_up_interruptible(&tty->write_wait); - wake_up_interruptible(&tty->read_wait); -} - -/** - * n_tty_close - close the ldisc for this tty - * @tty: device - * - * Called from the terminal layer when this line discipline is - * being shut down, either because of a close or becsuse of a - * discipline change. The function will not be called while other - * ldisc methods are in progress. - */ - -static void n_tty_close(struct tty_struct *tty) -{ - struct n_tty_data *ldata = tty->disc_data; - - if (tty->link) - n_tty_packet_mode_flush(tty); - - vfree(ldata); - tty->disc_data = NULL; -} - -/** - * n_tty_open - open an ldisc - * @tty: terminal to open - * - * Called when this line discipline is being attached to the - * terminal device. Can sleep. Called serialized so that no - * other events will occur in parallel. No further open will occur - * until a close. - */ - -static int n_tty_open(struct tty_struct *tty) -{ - struct n_tty_data *ldata; - - /* Currently a malloc failure here can panic */ - ldata = vmalloc(sizeof(*ldata)); - if (!ldata) - goto err; - - ldata->overrun_time = jiffies; - mutex_init(&ldata->atomic_read_lock); - mutex_init(&ldata->output_lock); - - tty->disc_data = ldata; - reset_buffer_flags(tty->disc_data); - ldata->column = 0; - ldata->canon_column = 0; - ldata->num_overrun = 0; - ldata->no_room = 0; - ldata->lnext = 0; - tty->closing = 0; - /* indicate buffer work may resume */ - clear_bit(TTY_LDISC_HALTED, &tty->flags); - n_tty_set_termios(tty, NULL); - tty_unthrottle(tty); - - return 0; -err: - return -ENOMEM; -} - -static inline int input_available_p(struct tty_struct *tty, int poll) -{ - struct n_tty_data *ldata = tty->disc_data; - int amt = poll && !TIME_CHAR(tty) && MIN_CHAR(tty) ? MIN_CHAR(tty) : 1; - - if (ldata->icanon && !L_EXTPROC(tty)) - return ldata->canon_head != ldata->read_tail; - else - return ldata->commit_head - ldata->read_tail >= amt; -} - -/** - * copy_from_read_buf - copy read data directly - * @tty: terminal device - * @b: user data - * @nr: size of data - * - * Helper function to speed up n_tty_read. It is only called when - * ICANON is off; it copies characters straight from the tty queue to - * user space directly. It can be profitably called twice; once to - * drain the space from the tail pointer to the (physical) end of the - * buffer, and once to drain the space from the (physical) beginning of - * the buffer to head pointer. - * - * Called under the ldata->atomic_read_lock sem - * - * n_tty_read()/consumer path: - * caller holds non-exclusive termios_rwsem - * read_tail published - */ - -static int copy_from_read_buf(struct tty_struct *tty, - unsigned char __user **b, - size_t *nr) - -{ - struct n_tty_data *ldata = tty->disc_data; - int retval; - size_t n; - bool is_eof; - size_t head = smp_load_acquire(&ldata->commit_head); - size_t tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1); - - retval = 0; - n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail); - n = min(*nr, n); - if (n) { - const unsigned char *from = read_buf_addr(ldata, tail); - retval = copy_to_user(*b, from, n); - n -= retval; - is_eof = n == 1 && *from == EOF_CHAR(tty); - tty_audit_add_data(tty, from, n); - smp_store_release(&ldata->read_tail, ldata->read_tail + n); - /* Turn single EOF into zero-length read */ - if (L_EXTPROC(tty) && ldata->icanon && is_eof && - (head == ldata->read_tail)) - n = 0; - *b += n; - *nr -= n; - } - return retval; -} - -/** - * canon_copy_from_read_buf - copy read data in canonical mode - * @tty: terminal device - * @b: user data - * @nr: size of data - * - * Helper function for n_tty_read. It is only called when ICANON is on; - * it copies one line of input up to and including the line-delimiting - * character into the user-space buffer. - * - * NB: When termios is changed from non-canonical to canonical mode and - * the read buffer contains data, n_tty_set_termios() simulates an EOF - * push (as if C-d were input) _without_ the DISABLED_CHAR in the buffer. - * This causes data already processed as input to be immediately available - * as input although a newline has not been received. - * - * Called under the atomic_read_lock mutex - * - * n_tty_read()/consumer path: - * caller holds non-exclusive termios_rwsem - * read_tail published - */ - -static int canon_copy_from_read_buf(struct tty_struct *tty, - unsigned char __user **b, - size_t *nr) -{ - struct n_tty_data *ldata = tty->disc_data; - size_t n, size, more, c; - size_t eol; - size_t tail; - int ret, found = 0; - - /* N.B. avoid overrun if nr == 0 */ - if (!*nr) - return 0; - - n = min(*nr + 1, smp_load_acquire(&ldata->canon_head) - ldata->read_tail); - - tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1); - size = min_t(size_t, tail + n, N_TTY_BUF_SIZE); - - n_tty_trace("%s: nr:%zu tail:%zu n:%zu size:%zu\n", - __func__, *nr, tail, n, size); - - eol = find_next_bit(ldata->read_flags, size, tail); - more = n - (size - tail); - if (eol == N_TTY_BUF_SIZE && more) { - /* scan wrapped without finding set bit */ - eol = find_next_bit(ldata->read_flags, more, 0); - found = eol != more; - } else - found = eol != size; - - n = eol - tail; - if (n > N_TTY_BUF_SIZE) - n += N_TTY_BUF_SIZE; - c = n + found; - - if (!found || read_buf(ldata, eol) != __DISABLED_CHAR) { - c = min(*nr, c); - n = c; - } - - n_tty_trace("%s: eol:%zu found:%d n:%zu c:%zu tail:%zu more:%zu\n", - __func__, eol, found, n, c, tail, more); - - ret = tty_copy_to_user(tty, *b, tail, n); - if (ret) - return -EFAULT; - *b += n; - *nr -= n; - - if (found) - clear_bit(eol, ldata->read_flags); - smp_store_release(&ldata->read_tail, ldata->read_tail + c); - - if (found) { - if (!ldata->push) - ldata->line_start = ldata->read_tail; - else - ldata->push = 0; - tty_audit_push(); - } - return 0; -} - -extern ssize_t redirected_tty_write(struct file *, const char __user *, - size_t, loff_t *); - -/** - * job_control - check job control - * @tty: tty - * @file: file handle - * - * Perform job control management checks on this file/tty descriptor - * and if appropriate send any needed signals and return a negative - * error code if action should be taken. - * - * Locking: redirected write test is safe - * current->signal->tty check is safe - * ctrl_lock to safely reference tty->pgrp - */ - -static int job_control(struct tty_struct *tty, struct file *file) -{ - /* Job control check -- must be done at start and after - every sleep (POSIX.1 7.1.1.4). */ - /* NOTE: not yet done after every sleep pending a thorough - check of the logic of this change. -- jlc */ - /* don't stop on /dev/console */ - if (file->f_op->write == redirected_tty_write) - return 0; - - return __tty_check_change(tty, SIGTTIN); -} - - -/** - * n_tty_read - read function for tty - * @tty: tty device - * @file: file object - * @buf: userspace buffer pointer - * @nr: size of I/O - * - * Perform reads for the line discipline. We are guaranteed that the - * line discipline will not be closed under us but we may get multiple - * parallel readers and must handle this ourselves. We may also get - * a hangup. Always called in user context, may sleep. - * - * This code must be sure never to sleep through a hangup. - * - * n_tty_read()/consumer path: - * claims non-exclusive termios_rwsem - * publishes read_tail - */ - -static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t nr) -{ - struct n_tty_data *ldata = tty->disc_data; - unsigned char __user *b = buf; - DEFINE_WAIT_FUNC(wait, woken_wake_function); - int c; - int minimum, time; - ssize_t retval = 0; - long timeout; - int packet; - size_t tail; - - c = job_control(tty, file); - if (c < 0) - return c; - - /* - * Internal serialization of reads. - */ - if (file->f_flags & O_NONBLOCK) { - if (!mutex_trylock(&ldata->atomic_read_lock)) - return -EAGAIN; - } else { - if (mutex_lock_interruptible(&ldata->atomic_read_lock)) - return -ERESTARTSYS; - } - - down_read(&tty->termios_rwsem); - - minimum = time = 0; - timeout = MAX_SCHEDULE_TIMEOUT; - if (!ldata->icanon) { - minimum = MIN_CHAR(tty); - if (minimum) { - time = (HZ / 10) * TIME_CHAR(tty); - } else { - timeout = (HZ / 10) * TIME_CHAR(tty); - minimum = 1; - } - } - - packet = tty->packet; - tail = ldata->read_tail; - - add_wait_queue(&tty->read_wait, &wait); - while (nr) { - /* First test for status change. */ - if (packet && tty->link->ctrl_status) { - unsigned char cs; - if (b != buf) - break; - spin_lock_irq(&tty->link->ctrl_lock); - cs = tty->link->ctrl_status; - tty->link->ctrl_status = 0; - spin_unlock_irq(&tty->link->ctrl_lock); - if (put_user(cs, b)) { - retval = -EFAULT; - break; - } - b++; - nr--; - break; - } - - if (!input_available_p(tty, 0)) { - up_read(&tty->termios_rwsem); - tty_buffer_flush_work(tty->port); - down_read(&tty->termios_rwsem); - if (!input_available_p(tty, 0)) { - if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { - retval = -EIO; - break; - } - if (tty_hung_up_p(file)) - break; - if (!timeout) - break; - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - up_read(&tty->termios_rwsem); - - timeout = wait_woken(&wait, TASK_INTERRUPTIBLE, - timeout); - - down_read(&tty->termios_rwsem); - continue; - } - } - - if (ldata->icanon && !L_EXTPROC(tty)) { - retval = canon_copy_from_read_buf(tty, &b, &nr); - if (retval) - break; - } else { - int uncopied; - - /* Deal with packet mode. */ - if (packet && b == buf) { - if (put_user(TIOCPKT_DATA, b)) { - retval = -EFAULT; - break; - } - b++; - nr--; - } - - uncopied = copy_from_read_buf(tty, &b, &nr); - uncopied += copy_from_read_buf(tty, &b, &nr); - if (uncopied) { - retval = -EFAULT; - break; - } - } - - n_tty_check_unthrottle(tty); - - if (b - buf >= minimum) - break; - if (time) - timeout = time; - } - if (tail != ldata->read_tail) - n_tty_kick_worker(tty); - up_read(&tty->termios_rwsem); - - remove_wait_queue(&tty->read_wait, &wait); - mutex_unlock(&ldata->atomic_read_lock); - - if (b - buf) - retval = b - buf; - - return retval; -} - -/** - * n_tty_write - write function for tty - * @tty: tty device - * @file: file object - * @buf: userspace buffer pointer - * @nr: size of I/O - * - * Write function of the terminal device. This is serialized with - * respect to other write callers but not to termios changes, reads - * and other such events. Since the receive code will echo characters, - * thus calling driver write methods, the output_lock is used in - * the output processing functions called here as well as in the - * echo processing function to protect the column state and space - * left in the buffer. - * - * This code must be sure never to sleep through a hangup. - * - * Locking: output_lock to protect column state and space left - * (note that the process_output*() functions take this - * lock themselves) - */ - -static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr) -{ - const unsigned char *b = buf; - DEFINE_WAIT_FUNC(wait, woken_wake_function); - int c; - ssize_t retval = 0; - - /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */ - if (L_TOSTOP(tty) && file->f_op->write != redirected_tty_write) { - retval = tty_check_change(tty); - if (retval) - return retval; - } - - down_read(&tty->termios_rwsem); - - /* Write out any echoed characters that are still pending */ - process_echoes(tty); - - add_wait_queue(&tty->write_wait, &wait); - while (1) { - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) { - retval = -EIO; - break; - } - if (O_OPOST(tty)) { - while (nr > 0) { - ssize_t num = process_output_block(tty, b, nr); - if (num < 0) { - if (num == -EAGAIN) - break; - retval = num; - goto break_out; - } - b += num; - nr -= num; - if (nr == 0) - break; - c = *b; - if (process_output(c, tty) < 0) - break; - b++; nr--; - } - if (tty->ops->flush_chars) - tty->ops->flush_chars(tty); - } else { - struct n_tty_data *ldata = tty->disc_data; - - while (nr > 0) { - mutex_lock(&ldata->output_lock); - c = tty->ops->write(tty, b, nr); - mutex_unlock(&ldata->output_lock); - if (c < 0) { - retval = c; - goto break_out; - } - if (!c) - break; - b += c; - nr -= c; - } - } - if (!nr) - break; - if (file->f_flags & O_NONBLOCK) { - retval = -EAGAIN; - break; - } - up_read(&tty->termios_rwsem); - - wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); - - down_read(&tty->termios_rwsem); - } -break_out: - remove_wait_queue(&tty->write_wait, &wait); - if (nr && tty->fasync) - set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - up_read(&tty->termios_rwsem); - return (b - buf) ? b - buf : retval; -} - -/** - * n_tty_poll - poll method for N_TTY - * @tty: terminal device - * @file: file accessing it - * @wait: poll table - * - * Called when the line discipline is asked to poll() for data or - * for special events. This code is not serialized with respect to - * other events save open/close. - * - * This code must be sure never to sleep through a hangup. - * Called without the kernel lock held - fine - */ - -static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file, - poll_table *wait) -{ - unsigned int mask = 0; - - poll_wait(file, &tty->read_wait, wait); - poll_wait(file, &tty->write_wait, wait); - if (input_available_p(tty, 1)) - mask |= POLLIN | POLLRDNORM; - else { - tty_buffer_flush_work(tty->port); - if (input_available_p(tty, 1)) - mask |= POLLIN | POLLRDNORM; - } - if (tty->packet && tty->link->ctrl_status) - mask |= POLLPRI | POLLIN | POLLRDNORM; - if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) - mask |= POLLHUP; - if (tty_hung_up_p(file)) - mask |= POLLHUP; - if (tty->ops->write && !tty_is_writelocked(tty) && - tty_chars_in_buffer(tty) < WAKEUP_CHARS && - tty_write_room(tty) > 0) - mask |= POLLOUT | POLLWRNORM; - return mask; -} - -static unsigned long inq_canon(struct n_tty_data *ldata) -{ - size_t nr, head, tail; - - if (ldata->canon_head == ldata->read_tail) - return 0; - head = ldata->canon_head; - tail = ldata->read_tail; - nr = head - tail; - /* Skip EOF-chars.. */ - while (head != tail) { - if (test_bit(tail & (N_TTY_BUF_SIZE - 1), ldata->read_flags) && - read_buf(ldata, tail) == __DISABLED_CHAR) - nr--; - tail++; - } - return nr; -} - -static int n_tty_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct n_tty_data *ldata = tty->disc_data; - int retval; - - switch (cmd) { - case TIOCOUTQ: - return put_user(tty_chars_in_buffer(tty), (int __user *) arg); - case TIOCINQ: - down_write(&tty->termios_rwsem); - if (L_ICANON(tty)) - retval = inq_canon(ldata); - else - retval = read_cnt(ldata); - up_write(&tty->termios_rwsem); - return put_user(retval, (unsigned int __user *) arg); - default: - return n_tty_ioctl_helper(tty, file, cmd, arg); - } -} - -static struct tty_ldisc_ops n_tty_ops = { - .magic = TTY_LDISC_MAGIC, - .name = "n_tty", - .open = n_tty_open, - .close = n_tty_close, - .flush_buffer = n_tty_flush_buffer, - .read = n_tty_read, - .write = n_tty_write, - .ioctl = n_tty_ioctl, - .set_termios = n_tty_set_termios, - .poll = n_tty_poll, - .receive_buf = n_tty_receive_buf, - .write_wakeup = n_tty_write_wakeup, - .receive_buf2 = n_tty_receive_buf2, -}; - -/** - * n_tty_inherit_ops - inherit N_TTY methods - * @ops: struct tty_ldisc_ops where to save N_TTY methods - * - * Enables a 'subclass' line discipline to 'inherit' N_TTY methods. - */ - -void n_tty_inherit_ops(struct tty_ldisc_ops *ops) -{ - *ops = n_tty_ops; - ops->owner = NULL; - ops->refcount = ops->flags = 0; -} -EXPORT_SYMBOL_GPL(n_tty_inherit_ops); - -void __init n_tty_init(void) -{ - tty_register_ldisc(N_TTY, &n_tty_ops); -} diff --git a/src/linux/drivers/tty/pty.c b/src/linux/drivers/tty/pty.c deleted file mode 100644 index a23fa5e..0000000 --- a/src/linux/drivers/tty/pty.c +++ /dev/null @@ -1,879 +0,0 @@ -/* - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Added support for a Unix98-style ptmx device. - * -- C. Scott Ananian , 14-Jan-1998 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#undef TTY_DEBUG_HANGUP -#ifdef TTY_DEBUG_HANGUP -# define tty_debug_hangup(tty, f, args...) tty_debug(tty, f, ##args) -#else -# define tty_debug_hangup(tty, f, args...) do {} while (0) -#endif - -#ifdef CONFIG_UNIX98_PTYS -static struct tty_driver *ptm_driver; -static struct tty_driver *pts_driver; -static DEFINE_MUTEX(devpts_mutex); -#endif - -static void pty_close(struct tty_struct *tty, struct file *filp) -{ - BUG_ON(!tty); - if (tty->driver->subtype == PTY_TYPE_MASTER) - WARN_ON(tty->count > 1); - else { - if (tty_io_error(tty)) - return; - if (tty->count > 2) - return; - } - set_bit(TTY_IO_ERROR, &tty->flags); - wake_up_interruptible(&tty->read_wait); - wake_up_interruptible(&tty->write_wait); - spin_lock_irq(&tty->ctrl_lock); - tty->packet = 0; - spin_unlock_irq(&tty->ctrl_lock); - /* Review - krefs on tty_link ?? */ - if (!tty->link) - return; - set_bit(TTY_OTHER_CLOSED, &tty->link->flags); - wake_up_interruptible(&tty->link->read_wait); - wake_up_interruptible(&tty->link->write_wait); - if (tty->driver->subtype == PTY_TYPE_MASTER) { - set_bit(TTY_OTHER_CLOSED, &tty->flags); -#ifdef CONFIG_UNIX98_PTYS - if (tty->driver == ptm_driver) { - mutex_lock(&devpts_mutex); - if (tty->link->driver_data) - devpts_pty_kill(tty->link->driver_data); - mutex_unlock(&devpts_mutex); - } -#endif - tty_vhangup(tty->link); - } -} - -/* - * The unthrottle routine is called by the line discipline to signal - * that it can receive more characters. For PTY's, the TTY_THROTTLED - * flag is always set, to force the line discipline to always call the - * unthrottle routine when there are fewer than TTY_THRESHOLD_UNTHROTTLE - * characters in the queue. This is necessary since each time this - * happens, we need to wake up any sleeping processes that could be - * (1) trying to send data to the pty, or (2) waiting in wait_until_sent() - * for the pty buffer to be drained. - */ -static void pty_unthrottle(struct tty_struct *tty) -{ - tty_wakeup(tty->link); - set_bit(TTY_THROTTLED, &tty->flags); -} - -/** - * pty_write - write to a pty - * @tty: the tty we write from - * @buf: kernel buffer of data - * @count: bytes to write - * - * Our "hardware" write method. Data is coming from the ldisc which - * may be in a non sleeping state. We simply throw this at the other - * end of the link as if we were an IRQ handler receiving stuff for - * the other side of the pty/tty pair. - */ - -static int pty_write(struct tty_struct *tty, const unsigned char *buf, int c) -{ - struct tty_struct *to = tty->link; - - if (tty->stopped) - return 0; - - if (c > 0) { - /* Stuff the data into the input queue of the other end */ - c = tty_insert_flip_string(to->port, buf, c); - /* And shovel */ - if (c) - tty_flip_buffer_push(to->port); - } - return c; -} - -/** - * pty_write_room - write space - * @tty: tty we are writing from - * - * Report how many bytes the ldisc can send into the queue for - * the other device. - */ - -static int pty_write_room(struct tty_struct *tty) -{ - if (tty->stopped) - return 0; - return tty_buffer_space_avail(tty->link->port); -} - -/** - * pty_chars_in_buffer - characters currently in our tx queue - * @tty: our tty - * - * Report how much we have in the transmit queue. As everything is - * instantly at the other end this is easy to implement. - */ - -static int pty_chars_in_buffer(struct tty_struct *tty) -{ - return 0; -} - -/* Set the lock flag on a pty */ -static int pty_set_lock(struct tty_struct *tty, int __user *arg) -{ - int val; - if (get_user(val, arg)) - return -EFAULT; - if (val) - set_bit(TTY_PTY_LOCK, &tty->flags); - else - clear_bit(TTY_PTY_LOCK, &tty->flags); - return 0; -} - -static int pty_get_lock(struct tty_struct *tty, int __user *arg) -{ - int locked = test_bit(TTY_PTY_LOCK, &tty->flags); - return put_user(locked, arg); -} - -/* Set the packet mode on a pty */ -static int pty_set_pktmode(struct tty_struct *tty, int __user *arg) -{ - int pktmode; - - if (get_user(pktmode, arg)) - return -EFAULT; - - spin_lock_irq(&tty->ctrl_lock); - if (pktmode) { - if (!tty->packet) { - tty->link->ctrl_status = 0; - smp_mb(); - tty->packet = 1; - } - } else - tty->packet = 0; - spin_unlock_irq(&tty->ctrl_lock); - - return 0; -} - -/* Get the packet mode of a pty */ -static int pty_get_pktmode(struct tty_struct *tty, int __user *arg) -{ - int pktmode = tty->packet; - return put_user(pktmode, arg); -} - -/* Send a signal to the slave */ -static int pty_signal(struct tty_struct *tty, int sig) -{ - struct pid *pgrp; - - if (sig != SIGINT && sig != SIGQUIT && sig != SIGTSTP) - return -EINVAL; - - if (tty->link) { - pgrp = tty_get_pgrp(tty->link); - if (pgrp) - kill_pgrp(pgrp, sig, 1); - put_pid(pgrp); - } - return 0; -} - -static void pty_flush_buffer(struct tty_struct *tty) -{ - struct tty_struct *to = tty->link; - struct tty_ldisc *ld; - - if (!to) - return; - - ld = tty_ldisc_ref(to); - tty_buffer_flush(to, ld); - if (ld) - tty_ldisc_deref(ld); - - if (to->packet) { - spin_lock_irq(&tty->ctrl_lock); - tty->ctrl_status |= TIOCPKT_FLUSHWRITE; - wake_up_interruptible(&to->read_wait); - spin_unlock_irq(&tty->ctrl_lock); - } -} - -static int pty_open(struct tty_struct *tty, struct file *filp) -{ - if (!tty || !tty->link) - return -ENODEV; - - if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) - goto out; - if (test_bit(TTY_PTY_LOCK, &tty->link->flags)) - goto out; - if (tty->driver->subtype == PTY_TYPE_SLAVE && tty->link->count != 1) - goto out; - - clear_bit(TTY_IO_ERROR, &tty->flags); - clear_bit(TTY_OTHER_CLOSED, &tty->link->flags); - set_bit(TTY_THROTTLED, &tty->flags); - return 0; - -out: - set_bit(TTY_IO_ERROR, &tty->flags); - return -EIO; -} - -static void pty_set_termios(struct tty_struct *tty, - struct ktermios *old_termios) -{ - /* See if packet mode change of state. */ - if (tty->link && tty->link->packet) { - int extproc = (old_termios->c_lflag & EXTPROC) | L_EXTPROC(tty); - int old_flow = ((old_termios->c_iflag & IXON) && - (old_termios->c_cc[VSTOP] == '\023') && - (old_termios->c_cc[VSTART] == '\021')); - int new_flow = (I_IXON(tty) && - STOP_CHAR(tty) == '\023' && - START_CHAR(tty) == '\021'); - if ((old_flow != new_flow) || extproc) { - spin_lock_irq(&tty->ctrl_lock); - if (old_flow != new_flow) { - tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP); - if (new_flow) - tty->ctrl_status |= TIOCPKT_DOSTOP; - else - tty->ctrl_status |= TIOCPKT_NOSTOP; - } - if (extproc) - tty->ctrl_status |= TIOCPKT_IOCTL; - spin_unlock_irq(&tty->ctrl_lock); - wake_up_interruptible(&tty->link->read_wait); - } - } - - tty->termios.c_cflag &= ~(CSIZE | PARENB); - tty->termios.c_cflag |= (CS8 | CREAD); -} - -/** - * pty_do_resize - resize event - * @tty: tty being resized - * @ws: window size being set. - * - * Update the termios variables and send the necessary signals to - * peform a terminal resize correctly - */ - -static int pty_resize(struct tty_struct *tty, struct winsize *ws) -{ - struct pid *pgrp, *rpgrp; - struct tty_struct *pty = tty->link; - - /* For a PTY we need to lock the tty side */ - mutex_lock(&tty->winsize_mutex); - if (!memcmp(ws, &tty->winsize, sizeof(*ws))) - goto done; - - /* Signal the foreground process group of both ptys */ - pgrp = tty_get_pgrp(tty); - rpgrp = tty_get_pgrp(pty); - - if (pgrp) - kill_pgrp(pgrp, SIGWINCH, 1); - if (rpgrp != pgrp && rpgrp) - kill_pgrp(rpgrp, SIGWINCH, 1); - - put_pid(pgrp); - put_pid(rpgrp); - - tty->winsize = *ws; - pty->winsize = *ws; /* Never used so will go away soon */ -done: - mutex_unlock(&tty->winsize_mutex); - return 0; -} - -/** - * pty_start - start() handler - * pty_stop - stop() handler - * @tty: tty being flow-controlled - * - * Propagates the TIOCPKT status to the master pty. - * - * NB: only the master pty can be in packet mode so only the slave - * needs start()/stop() handlers - */ -static void pty_start(struct tty_struct *tty) -{ - unsigned long flags; - - if (tty->link && tty->link->packet) { - spin_lock_irqsave(&tty->ctrl_lock, flags); - tty->ctrl_status &= ~TIOCPKT_STOP; - tty->ctrl_status |= TIOCPKT_START; - spin_unlock_irqrestore(&tty->ctrl_lock, flags); - wake_up_interruptible_poll(&tty->link->read_wait, POLLIN); - } -} - -static void pty_stop(struct tty_struct *tty) -{ - unsigned long flags; - - if (tty->link && tty->link->packet) { - spin_lock_irqsave(&tty->ctrl_lock, flags); - tty->ctrl_status &= ~TIOCPKT_START; - tty->ctrl_status |= TIOCPKT_STOP; - spin_unlock_irqrestore(&tty->ctrl_lock, flags); - wake_up_interruptible_poll(&tty->link->read_wait, POLLIN); - } -} - -/** - * pty_common_install - set up the pty pair - * @driver: the pty driver - * @tty: the tty being instantiated - * @legacy: true if this is BSD style - * - * Perform the initial set up for the tty/pty pair. Called from the - * tty layer when the port is first opened. - * - * Locking: the caller must hold the tty_mutex - */ -static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty, - bool legacy) -{ - struct tty_struct *o_tty; - struct tty_port *ports[2]; - int idx = tty->index; - int retval = -ENOMEM; - - /* Opening the slave first has always returned -EIO */ - if (driver->subtype != PTY_TYPE_MASTER) - return -EIO; - - ports[0] = kmalloc(sizeof **ports, GFP_KERNEL); - ports[1] = kmalloc(sizeof **ports, GFP_KERNEL); - if (!ports[0] || !ports[1]) - goto err; - if (!try_module_get(driver->other->owner)) { - /* This cannot in fact currently happen */ - goto err; - } - o_tty = alloc_tty_struct(driver->other, idx); - if (!o_tty) - goto err_put_module; - - tty_set_lock_subclass(o_tty); - lockdep_set_subclass(&o_tty->termios_rwsem, TTY_LOCK_SLAVE); - - if (legacy) { - /* We always use new tty termios data so we can do this - the easy way .. */ - tty_init_termios(tty); - tty_init_termios(o_tty); - - driver->other->ttys[idx] = o_tty; - driver->ttys[idx] = tty; - } else { - memset(&tty->termios_locked, 0, sizeof(tty->termios_locked)); - tty->termios = driver->init_termios; - memset(&o_tty->termios_locked, 0, sizeof(tty->termios_locked)); - o_tty->termios = driver->other->init_termios; - } - - /* - * Everything allocated ... set up the o_tty structure. - */ - tty_driver_kref_get(driver->other); - /* Establish the links in both directions */ - tty->link = o_tty; - o_tty->link = tty; - tty_port_init(ports[0]); - tty_port_init(ports[1]); - tty_buffer_set_limit(ports[0], 8192); - tty_buffer_set_limit(ports[1], 8192); - o_tty->port = ports[0]; - tty->port = ports[1]; - o_tty->port->itty = o_tty; - - tty_buffer_set_lock_subclass(o_tty->port); - - tty_driver_kref_get(driver); - tty->count++; - o_tty->count++; - return 0; - -err_put_module: - module_put(driver->other->owner); -err: - kfree(ports[0]); - kfree(ports[1]); - return retval; -} - -static void pty_cleanup(struct tty_struct *tty) -{ - tty_port_put(tty->port); -} - -/* Traditional BSD devices */ -#ifdef CONFIG_LEGACY_PTYS - -static int pty_install(struct tty_driver *driver, struct tty_struct *tty) -{ - return pty_common_install(driver, tty, true); -} - -static void pty_remove(struct tty_driver *driver, struct tty_struct *tty) -{ - struct tty_struct *pair = tty->link; - driver->ttys[tty->index] = NULL; - if (pair) - pair->driver->ttys[pair->index] = NULL; -} - -static int pty_bsd_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */ - return pty_set_lock(tty, (int __user *) arg); - case TIOCGPTLCK: /* Get PT Lock status */ - return pty_get_lock(tty, (int __user *)arg); - case TIOCPKT: /* Set PT packet mode */ - return pty_set_pktmode(tty, (int __user *)arg); - case TIOCGPKT: /* Get PT packet mode */ - return pty_get_pktmode(tty, (int __user *)arg); - case TIOCSIG: /* Send signal to other side of pty */ - return pty_signal(tty, (int) arg); - case TIOCGPTN: /* TTY returns ENOTTY, but glibc expects EINVAL here */ - return -EINVAL; - } - return -ENOIOCTLCMD; -} - -static int legacy_count = CONFIG_LEGACY_PTY_COUNT; -/* - * not really modular, but the easiest way to keep compat with existing - * bootargs behaviour is to continue using module_param here. - */ -module_param(legacy_count, int, 0); - -/* - * The master side of a pty can do TIOCSPTLCK and thus - * has pty_bsd_ioctl. - */ -static const struct tty_operations master_pty_ops_bsd = { - .install = pty_install, - .open = pty_open, - .close = pty_close, - .write = pty_write, - .write_room = pty_write_room, - .flush_buffer = pty_flush_buffer, - .chars_in_buffer = pty_chars_in_buffer, - .unthrottle = pty_unthrottle, - .ioctl = pty_bsd_ioctl, - .cleanup = pty_cleanup, - .resize = pty_resize, - .remove = pty_remove -}; - -static const struct tty_operations slave_pty_ops_bsd = { - .install = pty_install, - .open = pty_open, - .close = pty_close, - .write = pty_write, - .write_room = pty_write_room, - .flush_buffer = pty_flush_buffer, - .chars_in_buffer = pty_chars_in_buffer, - .unthrottle = pty_unthrottle, - .set_termios = pty_set_termios, - .cleanup = pty_cleanup, - .resize = pty_resize, - .start = pty_start, - .stop = pty_stop, - .remove = pty_remove -}; - -static void __init legacy_pty_init(void) -{ - struct tty_driver *pty_driver, *pty_slave_driver; - - if (legacy_count <= 0) - return; - - pty_driver = tty_alloc_driver(legacy_count, - TTY_DRIVER_RESET_TERMIOS | - TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_ALLOC); - if (IS_ERR(pty_driver)) - panic("Couldn't allocate pty driver"); - - pty_slave_driver = tty_alloc_driver(legacy_count, - TTY_DRIVER_RESET_TERMIOS | - TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_ALLOC); - if (IS_ERR(pty_slave_driver)) - panic("Couldn't allocate pty slave driver"); - - pty_driver->driver_name = "pty_master"; - pty_driver->name = "pty"; - pty_driver->major = PTY_MASTER_MAJOR; - pty_driver->minor_start = 0; - pty_driver->type = TTY_DRIVER_TYPE_PTY; - pty_driver->subtype = PTY_TYPE_MASTER; - pty_driver->init_termios = tty_std_termios; - pty_driver->init_termios.c_iflag = 0; - pty_driver->init_termios.c_oflag = 0; - pty_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; - pty_driver->init_termios.c_lflag = 0; - pty_driver->init_termios.c_ispeed = 38400; - pty_driver->init_termios.c_ospeed = 38400; - pty_driver->other = pty_slave_driver; - tty_set_operations(pty_driver, &master_pty_ops_bsd); - - pty_slave_driver->driver_name = "pty_slave"; - pty_slave_driver->name = "ttyp"; - pty_slave_driver->major = PTY_SLAVE_MAJOR; - pty_slave_driver->minor_start = 0; - pty_slave_driver->type = TTY_DRIVER_TYPE_PTY; - pty_slave_driver->subtype = PTY_TYPE_SLAVE; - pty_slave_driver->init_termios = tty_std_termios; - pty_slave_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; - pty_slave_driver->init_termios.c_ispeed = 38400; - pty_slave_driver->init_termios.c_ospeed = 38400; - pty_slave_driver->other = pty_driver; - tty_set_operations(pty_slave_driver, &slave_pty_ops_bsd); - - if (tty_register_driver(pty_driver)) - panic("Couldn't register pty driver"); - if (tty_register_driver(pty_slave_driver)) - panic("Couldn't register pty slave driver"); -} -#else -static inline void legacy_pty_init(void) { } -#endif - -/* Unix98 devices */ -#ifdef CONFIG_UNIX98_PTYS - -static struct cdev ptmx_cdev; - -static int pty_unix98_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case TIOCSPTLCK: /* Set PT Lock (disallow slave open) */ - return pty_set_lock(tty, (int __user *)arg); - case TIOCGPTLCK: /* Get PT Lock status */ - return pty_get_lock(tty, (int __user *)arg); - case TIOCPKT: /* Set PT packet mode */ - return pty_set_pktmode(tty, (int __user *)arg); - case TIOCGPKT: /* Get PT packet mode */ - return pty_get_pktmode(tty, (int __user *)arg); - case TIOCGPTN: /* Get PT Number */ - return put_user(tty->index, (unsigned int __user *)arg); - case TIOCSIG: /* Send signal to other side of pty */ - return pty_signal(tty, (int) arg); - } - - return -ENOIOCTLCMD; -} - -/** - * ptm_unix98_lookup - find a pty master - * @driver: ptm driver - * @idx: tty index - * - * Look up a pty master device. Called under the tty_mutex for now. - * This provides our locking. - */ - -static struct tty_struct *ptm_unix98_lookup(struct tty_driver *driver, - struct file *file, int idx) -{ - /* Master must be open via /dev/ptmx */ - return ERR_PTR(-EIO); -} - -/** - * pts_unix98_lookup - find a pty slave - * @driver: pts driver - * @idx: tty index - * - * Look up a pty master device. Called under the tty_mutex for now. - * This provides our locking for the tty pointer. - */ - -static struct tty_struct *pts_unix98_lookup(struct tty_driver *driver, - struct file *file, int idx) -{ - struct tty_struct *tty; - - mutex_lock(&devpts_mutex); - tty = devpts_get_priv(file->f_path.dentry); - mutex_unlock(&devpts_mutex); - /* Master must be open before slave */ - if (!tty) - return ERR_PTR(-EIO); - return tty; -} - -static int pty_unix98_install(struct tty_driver *driver, struct tty_struct *tty) -{ - return pty_common_install(driver, tty, false); -} - -/* this is called once with whichever end is closed last */ -static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) -{ - struct pts_fs_info *fsi; - - if (tty->driver->subtype == PTY_TYPE_MASTER) - fsi = tty->driver_data; - else - fsi = tty->link->driver_data; - - if (fsi) { - devpts_kill_index(fsi, tty->index); - devpts_release(fsi); - } -} - -static const struct tty_operations ptm_unix98_ops = { - .lookup = ptm_unix98_lookup, - .install = pty_unix98_install, - .remove = pty_unix98_remove, - .open = pty_open, - .close = pty_close, - .write = pty_write, - .write_room = pty_write_room, - .flush_buffer = pty_flush_buffer, - .chars_in_buffer = pty_chars_in_buffer, - .unthrottle = pty_unthrottle, - .ioctl = pty_unix98_ioctl, - .resize = pty_resize, - .cleanup = pty_cleanup -}; - -static const struct tty_operations pty_unix98_ops = { - .lookup = pts_unix98_lookup, - .install = pty_unix98_install, - .remove = pty_unix98_remove, - .open = pty_open, - .close = pty_close, - .write = pty_write, - .write_room = pty_write_room, - .flush_buffer = pty_flush_buffer, - .chars_in_buffer = pty_chars_in_buffer, - .unthrottle = pty_unthrottle, - .set_termios = pty_set_termios, - .start = pty_start, - .stop = pty_stop, - .cleanup = pty_cleanup, -}; - -/** - * ptmx_open - open a unix 98 pty master - * @inode: inode of device file - * @filp: file pointer to tty - * - * Allocate a unix98 pty master device from the ptmx driver. - * - * Locking: tty_mutex protects the init_dev work. tty->count should - * protect the rest. - * allocated_ptys_lock handles the list of free pty numbers - */ - -static int ptmx_open(struct inode *inode, struct file *filp) -{ - struct pts_fs_info *fsi; - struct tty_struct *tty; - struct dentry *dentry; - int retval; - int index; - - nonseekable_open(inode, filp); - - /* We refuse fsnotify events on ptmx, since it's a shared resource */ - filp->f_mode |= FMODE_NONOTIFY; - - retval = tty_alloc_file(filp); - if (retval) - return retval; - - fsi = devpts_acquire(filp); - if (IS_ERR(fsi)) { - retval = PTR_ERR(fsi); - goto out_free_file; - } - - /* find a device that is not in use. */ - mutex_lock(&devpts_mutex); - index = devpts_new_index(fsi); - mutex_unlock(&devpts_mutex); - - retval = index; - if (index < 0) - goto out_put_fsi; - - - mutex_lock(&tty_mutex); - tty = tty_init_dev(ptm_driver, index); - /* The tty returned here is locked so we can safely - drop the mutex */ - mutex_unlock(&tty_mutex); - - retval = PTR_ERR(tty); - if (IS_ERR(tty)) - goto out; - - /* - * From here on out, the tty is "live", and the index and - * fsi will be killed/put by the tty_release() - */ - set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ - tty->driver_data = fsi; - - tty_add_file(tty, filp); - - dentry = devpts_pty_new(fsi, index, tty->link); - if (IS_ERR(dentry)) { - retval = PTR_ERR(dentry); - goto err_release; - } - tty->link->driver_data = dentry; - - retval = ptm_driver->ops->open(tty, filp); - if (retval) - goto err_release; - - tty_debug_hangup(tty, "opening (count=%d)\n", tty->count); - - tty_unlock(tty); - return 0; -err_release: - tty_unlock(tty); - // This will also put-ref the fsi - tty_release(inode, filp); - return retval; -out: - devpts_kill_index(fsi, index); -out_put_fsi: - devpts_release(fsi); -out_free_file: - tty_free_file(filp); - return retval; -} - -static struct file_operations ptmx_fops __ro_after_init; - -static void __init unix98_pty_init(void) -{ - ptm_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX, - TTY_DRIVER_RESET_TERMIOS | - TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV | - TTY_DRIVER_DEVPTS_MEM | - TTY_DRIVER_DYNAMIC_ALLOC); - if (IS_ERR(ptm_driver)) - panic("Couldn't allocate Unix98 ptm driver"); - pts_driver = tty_alloc_driver(NR_UNIX98_PTY_MAX, - TTY_DRIVER_RESET_TERMIOS | - TTY_DRIVER_REAL_RAW | - TTY_DRIVER_DYNAMIC_DEV | - TTY_DRIVER_DEVPTS_MEM | - TTY_DRIVER_DYNAMIC_ALLOC); - if (IS_ERR(pts_driver)) - panic("Couldn't allocate Unix98 pts driver"); - - ptm_driver->driver_name = "pty_master"; - ptm_driver->name = "ptm"; - ptm_driver->major = UNIX98_PTY_MASTER_MAJOR; - ptm_driver->minor_start = 0; - ptm_driver->type = TTY_DRIVER_TYPE_PTY; - ptm_driver->subtype = PTY_TYPE_MASTER; - ptm_driver->init_termios = tty_std_termios; - ptm_driver->init_termios.c_iflag = 0; - ptm_driver->init_termios.c_oflag = 0; - ptm_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; - ptm_driver->init_termios.c_lflag = 0; - ptm_driver->init_termios.c_ispeed = 38400; - ptm_driver->init_termios.c_ospeed = 38400; - ptm_driver->other = pts_driver; - tty_set_operations(ptm_driver, &ptm_unix98_ops); - - pts_driver->driver_name = "pty_slave"; - pts_driver->name = "pts"; - pts_driver->major = UNIX98_PTY_SLAVE_MAJOR; - pts_driver->minor_start = 0; - pts_driver->type = TTY_DRIVER_TYPE_PTY; - pts_driver->subtype = PTY_TYPE_SLAVE; - pts_driver->init_termios = tty_std_termios; - pts_driver->init_termios.c_cflag = B38400 | CS8 | CREAD; - pts_driver->init_termios.c_ispeed = 38400; - pts_driver->init_termios.c_ospeed = 38400; - pts_driver->other = ptm_driver; - tty_set_operations(pts_driver, &pty_unix98_ops); - - if (tty_register_driver(ptm_driver)) - panic("Couldn't register Unix98 ptm driver"); - if (tty_register_driver(pts_driver)) - panic("Couldn't register Unix98 pts driver"); - - /* Now create the /dev/ptmx special device */ - tty_default_fops(&ptmx_fops); - ptmx_fops.open = ptmx_open; - - cdev_init(&ptmx_cdev, &ptmx_fops); - if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) || - register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0) - panic("Couldn't register /dev/ptmx driver"); - device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx"); -} - -#else -static inline void unix98_pty_init(void) { } -#endif - -static int __init pty_init(void) -{ - legacy_pty_init(); - unix98_pty_init(); - return 0; -} -device_initcall(pty_init); diff --git a/src/linux/drivers/tty/serial/8250/Kconfig b/src/linux/drivers/tty/serial/8250/Kconfig deleted file mode 100644 index 8998347..0000000 --- a/src/linux/drivers/tty/serial/8250/Kconfig +++ /dev/null @@ -1,449 +0,0 @@ -# -# The 8250/16550 serial drivers. You shouldn't be in this list unless -# you somehow have an implicit or explicit dependency on SERIAL_8250. -# - -config SERIAL_8250 - tristate "8250/16550 and compatible serial support" - select SERIAL_CORE - ---help--- - This selects whether you want to include the driver for the standard - serial ports. The standard answer is Y. People who might say N - here are those that are setting up dedicated Ethernet WWW/FTP - servers, or users that have one of the various bus mice instead of a - serial mouse and don't intend to use their machine's standard serial - port for anything. (Note that the Cyclades multi serial port driver - does not need this driver built in for it to work.) - - To compile this driver as a module, choose M here: the - module will be called 8250. - [WARNING: Do not compile this driver as a module if you are using - non-standard serial ports, since the configuration information will - be lost when the driver is unloaded. This limitation may be lifted - in the future.] - - BTW1: If you have a mouseman serial mouse which is not recognized by - the X window system, try running gpm first. - - BTW2: If you intend to use a software modem (also called Winmodem) - under Linux, forget it. These modems are crippled and require - proprietary drivers which are only available under Windows. - - Most people will say Y or M here, so that they can use serial mice, - modems and similar devices connecting to the standard serial ports. - -config SERIAL_8250_DEPRECATED_OPTIONS - bool "Support 8250_core.* kernel options (DEPRECATED)" - depends on SERIAL_8250 - default y - ---help--- - In 3.7 we renamed 8250 to 8250_core by mistake, so now we have to - accept kernel parameters in both forms like 8250_core.nr_uarts=4 and - 8250.nr_uarts=4. We now renamed the module back to 8250, but if - anybody noticed in 3.7 and changed their userspace we still have to - keep the 8250_core.* options around until they revert the changes - they already did. - - If 8250 is built as a module, this adds 8250_core alias instead. - - If you did not notice yet and/or you have userspace from pre-3.7, it - is safe (and recommended) to say N here. - -config SERIAL_8250_PNP - bool "8250/16550 PNP device support" if EXPERT - depends on SERIAL_8250 && PNP - default y - ---help--- - This builds standard PNP serial support. You may be able to - disable this feature if you only need legacy serial support. - -config SERIAL_8250_FINTEK - bool "Support for Fintek F81216A LPC to 4 UART RS485 API" - depends on SERIAL_8250 - ---help--- - Selecting this option will add support for the RS485 capabilities - of the Fintek F81216A LPC to 4 UART. - - If this option is not selected the device will be configured as a - standard 16550A serial port. - - If unsure, say N. - -config SERIAL_8250_CONSOLE - bool "Console on 8250/16550 and compatible serial port" - depends on SERIAL_8250=y - select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON - ---help--- - If you say Y here, it will be possible to use a serial port as the - system console (the system console is the device which receives all - kernel messages and warnings and which allows logins in single user - mode). This could be useful if some terminal or printer is connected - to that serial port. - - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttyS1". (Try "man bootparam" or see the documentation of - your boot loader (grub or lilo or loadlin) about how to pass options - to the kernel at boot time.) - - If you don't have a VGA card installed and you say Y here, the - kernel will automatically use the first serial line, /dev/ttyS0, as - system console. - - You can set that using a kernel command line option such as - "console=uart8250,io,0x3f8,9600n8" - "console=uart8250,mmio,0xff5e0000,115200n8". - and it will switch to normal serial console when the corresponding - port is ready. - "earlycon=uart8250,io,0x3f8,9600n8" - "earlycon=uart8250,mmio,0xff5e0000,115200n8". - it will not only setup early console. - - If unsure, say N. - -config SERIAL_8250_GSC - tristate - depends on SERIAL_8250 && GSC - default SERIAL_8250 - -config SERIAL_8250_DMA - bool "DMA support for 16550 compatible UART controllers" if EXPERT - depends on SERIAL_8250 && DMADEVICES=y - default SERIAL_8250 - help - This builds DMA support that can be used with 8250/16650 - compatible UART controllers that support DMA signaling. - -config SERIAL_8250_PCI - tristate "8250/16550 PCI device support" if EXPERT - depends on SERIAL_8250 && PCI - default SERIAL_8250 - help - This builds standard PCI serial support. You may be able to - disable this feature if you only need legacy serial support. - Saves about 9K. - Note that serial ports on NetMos 9835 Multi-I/O cards are handled - by the parport_serial driver, enabled with CONFIG_PARPORT_SERIAL. - -config SERIAL_8250_HP300 - tristate - depends on SERIAL_8250 && HP300 - default SERIAL_8250 - -config SERIAL_8250_CS - tristate "8250/16550 PCMCIA device support" - depends on PCMCIA && SERIAL_8250 - ---help--- - Say Y here to enable support for 16-bit PCMCIA serial devices, - including serial port cards, modems, and the modem functions of - multi-function Ethernet/modem cards. (PCMCIA- or PC-cards are - credit-card size devices often used with laptops.) - - To compile this driver as a module, choose M here: the - module will be called serial_cs. - - If unsure, say N. - -config SERIAL_8250_NR_UARTS - int "Maximum number of 8250/16550 serial ports" - depends on SERIAL_8250 - default "4" - help - Set this to the number of serial ports you want the driver - to support. This includes any ports discovered via ACPI or - PCI enumeration and any ports that may be added at run-time - via hot-plug, or any ISA multi-port serial cards. - -config SERIAL_8250_RUNTIME_UARTS - int "Number of 8250/16550 serial ports to register at runtime" - depends on SERIAL_8250 - range 0 SERIAL_8250_NR_UARTS - default "4" - help - Set this to the maximum number of serial ports you want - the kernel to register at boot time. This can be overridden - with the module parameter "nr_uarts", or boot-time parameter - 8250.nr_uarts - -config SERIAL_8250_EXTENDED - bool "Extended 8250/16550 serial driver options" - depends on SERIAL_8250 - help - If you wish to use any non-standard features of the standard "dumb" - driver, say Y here. This includes HUB6 support, shared serial - interrupts, special multiport support, support for more than the - four COM 1/2/3/4 boards, etc. - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about serial driver options. If unsure, say N. - -config SERIAL_8250_MANY_PORTS - bool "Support more than 4 legacy serial ports" - depends on SERIAL_8250_EXTENDED && !IA64 - help - Say Y here if you have dumb serial boards other than the four - standard COM 1/2/3/4 ports. This may happen if you have an AST - FourPort, Accent Async, Boca (read the Boca mini-HOWTO, available - from ), or other custom - serial port hardware which acts similar to standard serial port - hardware. If you only use the standard COM 1/2/3/4 ports, you can - say N here to save some memory. You can also say Y if you have an - "intelligent" multiport card such as Cyclades, Digiboards, etc. - -# -# Multi-port serial cards -# - -config SERIAL_8250_FOURPORT - tristate "Support Fourport cards" - depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS - help - Say Y here if you have an AST FourPort serial board. - - To compile this driver as a module, choose M here: the module - will be called 8250_fourport. - -config SERIAL_8250_ACCENT - tristate "Support Accent cards" - depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS - help - Say Y here if you have an Accent Async serial board. - - To compile this driver as a module, choose M here: the module - will be called 8250_accent. - -config SERIAL_8250_BOCA - tristate "Support Boca cards" - depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS - help - Say Y here if you have a Boca serial board. Please read the Boca - mini-HOWTO, available from - - To compile this driver as a module, choose M here: the module - will be called 8250_boca. - -config SERIAL_8250_EXAR_ST16C554 - tristate "Support Exar ST16C554/554D Quad UART" - depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS - help - The Uplogix Envoy TU301 uses this Exar Quad UART. If you are - tinkering with your Envoy TU301, or have a machine with this UART, - say Y here. - - To compile this driver as a module, choose M here: the module - will be called 8250_exar_st16c554. - -config SERIAL_8250_HUB6 - tristate "Support Hub6 cards" - depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS - help - Say Y here if you have a HUB6 serial board. - - To compile this driver as a module, choose M here: the module - will be called 8250_hub6. - -# -# Misc. options/drivers. -# - -config SERIAL_8250_SHARE_IRQ - bool "Support for sharing serial interrupts" - depends on SERIAL_8250_EXTENDED - help - Some serial boards have hardware support which allows multiple dumb - serial ports on the same board to share a single IRQ. To enable - support for this in the serial driver, say Y here. - -config SERIAL_8250_DETECT_IRQ - bool "Autodetect IRQ on standard ports (unsafe)" - depends on SERIAL_8250_EXTENDED - help - Say Y here if you want the kernel to try to guess which IRQ - to use for your serial port. - - This is considered unsafe; it is far better to configure the IRQ in - a boot script using the setserial command. - - If unsure, say N. - -config SERIAL_8250_RSA - bool "Support RSA serial ports" - depends on SERIAL_8250_EXTENDED - help - Say Y here if you have a IODATA RSA-DV II/S ISA card and - would like to use its >115kbps speeds. - You will need to provide module parameter "probe_rsa", or boot-time - parameter 8250.probe_rsa with I/O addresses of this card then. - - If you don't have such card, or if unsure, say N. - -config SERIAL_8250_ACORN - tristate "Acorn expansion card serial port support" - depends on ARCH_ACORN && SERIAL_8250 - help - If you have an Atomwide Serial card or Serial Port card for an Acorn - system, say Y to this option. The driver can handle 1, 2, or 3 port - cards. If unsure, say N. - -config SERIAL_8250_BCM2835AUX - tristate "BCM2835 auxiliar mini UART support" - depends on ARCH_BCM2835 || COMPILE_TEST - depends on SERIAL_8250 && SERIAL_8250_SHARE_IRQ - help - Support for the BCM2835 auxiliar mini UART. - - Features and limitations of the UART are - Registers are similar to 16650 registers, - set bits in the control registers that are unsupported - are ignored and read back as 0 - 7/8 bit operation with 1 start and 1 stop bit - 8 symbols deep fifo for rx and tx - SW controlled RTS and SW readable CTS - Clock rate derived from system clock - Uses 8 times oversampling (compared to 16 times for 16650) - Missing break detection (but break generation) - Missing framing error detection - Missing parity bit - Missing receive time-out interrupt - Missing DCD, DSR, DTR and RI signals - - If unsure, say N. - -config SERIAL_8250_FSL - bool - depends on SERIAL_8250_CONSOLE - default PPC || ARM || ARM64 - -config SERIAL_8250_DW - tristate "Support for Synopsys DesignWare 8250 quirks" - depends on SERIAL_8250 - help - Selecting this option will enable handling of the extra features - present in the Synopsys DesignWare APB UART. - -config SERIAL_8250_EM - tristate "Support for Emma Mobile integrated serial port" - depends on SERIAL_8250 && ARM && HAVE_CLK - help - Selecting this option will add support for the integrated serial - port hardware found on the Emma Mobile line of processors. - If unsure, say N. - -config SERIAL_8250_RT288X - bool "Ralink RT288x/RT305x/RT3662/RT3883 serial port support" - depends on SERIAL_8250 - default y if MIPS_ALCHEMY || SOC_RT288X || SOC_RT305X || SOC_RT3883 || SOC_MT7620 - help - Selecting this option will add support for the alternate register - layout used by Ralink RT288x/RT305x, Alchemy Au1xxx, and some others. - If unsure, say N. - -config SERIAL_8250_OMAP - tristate "Support for OMAP internal UART (8250 based driver)" - depends on SERIAL_8250 && ARCH_OMAP2PLUS - help - If you have a machine based on an Texas Instruments OMAP CPU you - can enable its onboard serial ports by enabling this option. - - This driver uses ttyS instead of ttyO. - -config SERIAL_8250_OMAP_TTYO_FIXUP - bool "Replace ttyO with ttyS" - depends on SERIAL_8250_OMAP=y && SERIAL_8250_CONSOLE - default y - help - This option replaces the "console=ttyO" argument with the matching - ttyS argument if the user did not specified it on the command line. - This ensures that the user can see the kernel output during boot - which he wouldn't see otherwise. The getty has still to be configured - for ttyS instead of ttyO regardless of this option. - This option is intended for people who "automatically" enable this - driver without knowing that this driver requires a different console= - argument. If you read this, please keep this option disabled and - instead update your kernel command line. If you prepare a kernel for a - distribution or other kind of larger user base then you probably want - to keep this option enabled. Otherwise people might complain about a - not booting kernel because the serial console remains silent in case - they forgot to update the command line. - -config SERIAL_8250_LPC18XX - tristate "NXP LPC18xx/43xx serial port support" - depends on SERIAL_8250 && OF && (ARCH_LPC18XX || COMPILE_TEST) - default ARCH_LPC18XX - help - If you have a LPC18xx/43xx based board and want to use the - serial port, say Y to this option. If unsure, say Y. - -config SERIAL_8250_MT6577 - tristate "Mediatek serial port support" - depends on SERIAL_8250 && ARCH_MEDIATEK - help - If you have a Mediatek based board and want to use the - serial port, say Y to this option. If unsure, say N. - -config SERIAL_8250_UNIPHIER - tristate "Support for UniPhier on-chip UART" - depends on SERIAL_8250 - depends on ARCH_UNIPHIER || COMPILE_TEST - help - If you have a UniPhier based board and want to use the on-chip - serial ports, say Y to this option. If unsure, say N. - -config SERIAL_8250_INGENIC - tristate "Support for Ingenic SoC serial ports" - depends on SERIAL_8250 - depends on OF_FLATTREE - depends on MIPS || COMPILE_TEST - help - If you have a system using an Ingenic SoC and wish to make use of - its UARTs, say Y to this option. If unsure, say N. - -config SERIAL_8250_LPSS - tristate "Support for serial ports on Intel LPSS platforms" if EXPERT - default SERIAL_8250 - depends on SERIAL_8250 && PCI - depends on X86 || COMPILE_TEST - select DW_DMAC_CORE if SERIAL_8250_DMA - select DW_DMAC_PCI if (SERIAL_8250_DMA && X86_INTEL_LPSS) - select RATIONAL - help - Selecting this option will enable handling of the extra features - present on the UART found on various Intel platforms such as: - - Intel Baytrail SoC - - Intel Braswell SoC - - Intel Quark X1000 SoC - -config SERIAL_8250_MID - tristate "Support for serial ports on Intel MID platforms" if EXPERT - default SERIAL_8250 - depends on SERIAL_8250 && PCI - depends on X86 || COMPILE_TEST - select HSU_DMA if SERIAL_8250_DMA - select HSU_DMA_PCI if (HSU_DMA && X86_INTEL_MID) - select RATIONAL - help - Selecting this option will enable handling of the extra features - present on the UART found on Intel Medfield SOC and various other - Intel platforms. - -config SERIAL_8250_MOXA - tristate "MOXA SmartIO MUE support" - depends on SERIAL_8250 && PCI - help - Say Y here if you have a Moxa SmartIO MUE multiport serial card. - If unsure, say N. - - This driver can also be built as a module. The module will be called - 8250_moxa. If you want to do that, say M here. - -config SERIAL_OF_PLATFORM - tristate "Devicetree based probing for 8250 ports" - depends on SERIAL_8250 && OF - help - This option is used for all 8250 compatible serial ports that - are probed through devicetree, including Open Firmware based - PowerPC systems and embedded systems on architectures using the - flattened device tree format. diff --git a/src/linux/drivers/tty/serial/Kconfig b/src/linux/drivers/tty/serial/Kconfig deleted file mode 100644 index 25c1d7b..0000000 --- a/src/linux/drivers/tty/serial/Kconfig +++ /dev/null @@ -1,1671 +0,0 @@ -# -# Serial device configuration -# - -if TTY - -menu "Serial drivers" - depends on HAS_IOMEM - -config SERIAL_EARLYCON - bool - help - Support for early consoles with the earlycon parameter. This enables - the console before standard serial driver is probed. The console is - enabled when early_param is processed. - -source "drivers/tty/serial/8250/Kconfig" - -comment "Non-8250 serial port support" - -config SERIAL_AMBA_PL010 - tristate "ARM AMBA PL010 serial port support" - depends on ARM_AMBA - select SERIAL_CORE - help - This selects the ARM(R) AMBA(R) PrimeCell PL010 UART. If you have - an Integrator/AP or Integrator/PP2 platform, or if you have a - Cirrus Logic EP93xx CPU, say Y or M here. - - If unsure, say N. - -config SERIAL_AMBA_PL010_CONSOLE - bool "Support for console on AMBA serial port" - depends on SERIAL_AMBA_PL010=y - select SERIAL_CORE_CONSOLE - ---help--- - Say Y here if you wish to use an AMBA PrimeCell UART as the system - console (the system console is the device which receives all kernel - messages and warnings and which allows logins in single user mode). - - Even if you say Y here, the currently visible framebuffer console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttyAM0". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) - -config SERIAL_AMBA_PL011 - tristate "ARM AMBA PL011 serial port support" - depends on ARM_AMBA - select SERIAL_CORE - help - This selects the ARM(R) AMBA(R) PrimeCell PL011 UART. If you have - an Integrator/PP2, Integrator/CP or Versatile platform, say Y or M - here. - - If unsure, say N. - -config SERIAL_AMBA_PL011_CONSOLE - bool "Support for console on AMBA serial port" - depends on SERIAL_AMBA_PL011=y - select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON - ---help--- - Say Y here if you wish to use an AMBA PrimeCell UART as the system - console (the system console is the device which receives all kernel - messages and warnings and which allows logins in single user mode). - - Even if you say Y here, the currently visible framebuffer console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttyAMA0". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) - -config SERIAL_EARLYCON_ARM_SEMIHOST - bool "Early console using ARM semihosting" - depends on ARM64 || ARM - select SERIAL_CORE - select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON - help - Support for early debug console using ARM semihosting. This enables - the console before standard serial driver is probed. This is enabled - with "earlycon=smh" on the kernel command line. The console is - enabled when early_param is processed. - -config SERIAL_SB1250_DUART - tristate "BCM1xxx on-chip DUART serial support" - depends on SIBYTE_SB1xxx_SOC=y - select SERIAL_CORE - default y - ---help--- - Support for the asynchronous serial interface (DUART) included in - the BCM1250 and derived System-On-a-Chip (SOC) devices. Note that - the letter D in DUART stands for "dual", which is how the device - is implemented. Depending on the SOC configuration there may be - one or more DUARTs available of which all are handled. - - If unsure, say Y. To compile this driver as a module, choose M here: - the module will be called sb1250-duart. - -config SERIAL_SB1250_DUART_CONSOLE - bool "Support for console on a BCM1xxx DUART serial port" - depends on SERIAL_SB1250_DUART=y - select SERIAL_CORE_CONSOLE - default y - ---help--- - If you say Y here, it will be possible to use a serial port as the - system console (the system console is the device which receives all - kernel messages and warnings and which allows logins in single user - mode). - - If unsure, say Y. - -config SERIAL_ATMEL - bool "AT91 / AT32 on-chip serial port support" - depends on HAS_DMA - depends on ARCH_AT91 || AVR32 || COMPILE_TEST - select SERIAL_CORE - select SERIAL_MCTRL_GPIO if GPIOLIB - help - This enables the driver for the on-chip UARTs of the Atmel - AT91 and AT32 processors. - -config SERIAL_ATMEL_CONSOLE - bool "Support for console on AT91 / AT32 serial port" - depends on SERIAL_ATMEL=y - select SERIAL_CORE_CONSOLE - help - Say Y here if you wish to use an on-chip UART on a Atmel - AT91 or AT32 processor as the system console (the system - console is the device which receives all kernel messages and - warnings and which allows logins in single user mode). - -config SERIAL_ATMEL_PDC - bool "Support DMA transfers on AT91 / AT32 serial port" - depends on SERIAL_ATMEL - default y - help - Say Y here if you wish to use the PDC to do DMA transfers to - and from the Atmel AT91 / AT32 serial port. In order to - actually use DMA transfers, make sure that the use_dma_tx - and use_dma_rx members in the atmel_uart_data struct is set - appropriately for each port. - - Note that break and error handling currently doesn't work - properly when DMA is enabled. Make sure that ports where - this matters don't use DMA. - -config SERIAL_ATMEL_TTYAT - bool "Install as device ttyATn instead of ttySn" - depends on SERIAL_ATMEL=y - help - Say Y here if you wish to have the internal AT91 / AT32 UARTs - appear as /dev/ttyATn (major 204, minor starting at 154) - instead of the normal /dev/ttySn (major 4, minor starting at - 64). This is necessary if you also want other UARTs, such as - external 8250/16C550 compatible UARTs. - The ttySn nodes are legally reserved for the 8250 serial driver - but are often misused by other serial drivers. - - To use this, you should create suitable ttyATn device nodes in - /dev/, and pass "console=ttyATn" to the kernel. - - Say Y if you have an external 8250/16C550 UART. If unsure, say N. - -config SERIAL_KGDB_NMI - bool "Serial console over KGDB NMI debugger port" - depends on KGDB_SERIAL_CONSOLE - help - This special driver allows you to temporary use NMI debugger port - as a normal console (assuming that the port is attached to KGDB). - - Unlike KDB's disable_nmi command, with this driver you are always - able to go back to the debugger using KGDB escape sequence ($3#33). - This is because this console driver processes the input in NMI - context, and thus is able to intercept the magic sequence. - - Note that since the console interprets input and uses polling - communication methods, for things like PPP you still must fully - detach debugger port from the KGDB NMI (i.e. disable_nmi), and - use raw console. - - If unsure, say N. - -config SERIAL_KS8695 - bool "Micrel KS8695 (Centaur) serial port support" - depends on ARCH_KS8695 - select SERIAL_CORE - help - This selects the Micrel Centaur KS8695 UART. Say Y here. - -config SERIAL_KS8695_CONSOLE - bool "Support for console on KS8695 (Centaur) serial port" - depends on SERIAL_KS8695=y - select SERIAL_CORE_CONSOLE - help - Say Y here if you wish to use a KS8695 (Centaur) UART as the - system console (the system console is the device which - receives all kernel messages and warnings and which allows - logins in single user mode). - -config SERIAL_MESON - tristate "Meson serial port support" - depends on ARCH_MESON - select SERIAL_CORE - help - This enables the driver for the on-chip UARTs of the Amlogic - MesonX processors. - -config SERIAL_MESON_CONSOLE - bool "Support for console on meson" - depends on SERIAL_MESON=y - select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON - help - Say Y here if you wish to use a Amlogic MesonX UART as the - system console (the system console is the device which - receives all kernel messages and warnings and which allows - logins in single user mode) as /dev/ttyAMLx. - -config SERIAL_CLPS711X - tristate "CLPS711X serial port support" - depends on ARCH_CLPS711X || COMPILE_TEST - select SERIAL_CORE - select SERIAL_MCTRL_GPIO if GPIOLIB - help - This enables the driver for the on-chip UARTs of the Cirrus - Logic EP711x/EP721x/EP731x processors. - -config SERIAL_CLPS711X_CONSOLE - bool "Support for console on CLPS711X serial port" - depends on SERIAL_CLPS711X=y - select SERIAL_CORE_CONSOLE - help - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttyCL1". - -config SERIAL_SAMSUNG - tristate "Samsung SoC serial support" - depends on PLAT_SAMSUNG || ARCH_EXYNOS - select SERIAL_CORE - help - Support for the on-chip UARTs on the Samsung S3C24XX series CPUs, - providing /dev/ttySAC0, 1 and 2 (note, some machines may not - provide all of these ports, depending on how the serial port - pins are configured. - -config SERIAL_SAMSUNG_UARTS_4 - bool - depends on SERIAL_SAMSUNG - default y if !(CPU_S3C2410 || CPU_S3C2412 || CPU_S3C2440 || CPU_S3C2442) - help - Internal node for the common case of 4 Samsung compatible UARTs - -config SERIAL_SAMSUNG_UARTS - int - depends on SERIAL_SAMSUNG - default 4 if SERIAL_SAMSUNG_UARTS_4 || CPU_S3C2416 - default 3 - help - Select the number of available UART ports for the Samsung S3C - serial driver - -config SERIAL_SAMSUNG_DEBUG - bool "Samsung SoC serial debug" - depends on SERIAL_SAMSUNG && DEBUG_LL - help - Add support for debugging the serial driver. Since this is - generally being used as a console, we use our own output - routines that go via the low-level debug printascii() - function. - -config SERIAL_SAMSUNG_CONSOLE - bool "Support for console on Samsung SoC serial port" - depends on SERIAL_SAMSUNG=y - select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON - help - Allow selection of the S3C24XX on-board serial ports for use as - an virtual console. - - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttySACx". (Try "man bootparam" or see the documentation of - your boot loader about how to pass options to the kernel at - boot time.) - -config SERIAL_SIRFSOC - tristate "SiRF SoC Platform Serial port support" - depends on ARCH_SIRF - select SERIAL_CORE - help - Support for the on-chip UART on the CSR SiRFprimaII series, - providing /dev/ttySiRF0, 1 and 2 (note, some machines may not - provide all of these ports, depending on how the serial port - pins are configured). - -config SERIAL_SIRFSOC_CONSOLE - bool "Support for console on SiRF SoC serial port" - depends on SERIAL_SIRFSOC=y - select SERIAL_CORE_CONSOLE - help - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttySiRFx". (Try "man bootparam" or see the documentation of - your boot loader about how to pass options to the kernel at - boot time.) - -config SERIAL_TEGRA - tristate "NVIDIA Tegra20/30 SoC serial controller" - depends on ARCH_TEGRA && TEGRA20_APB_DMA - select SERIAL_CORE - help - Support for the on-chip UARTs on the NVIDIA Tegra series SOCs - providing /dev/ttyTHS0, 1, 2, 3 and 4 (note, some machines may not - provide all of these ports, depending on how the serial port - are enabled). This driver uses the APB DMA to achieve higher baudrate - and better performance. - -config SERIAL_MAX3100 - tristate "MAX3100 support" - depends on SPI - select SERIAL_CORE - help - MAX3100 chip support - -config SERIAL_MAX310X - tristate "MAX310X support" - depends on SPI_MASTER - select SERIAL_CORE - select REGMAP_SPI if SPI_MASTER - default n - help - This selects support for an advanced UART from Maxim (Dallas). - Supported ICs are MAX3107, MAX3108, MAX3109, MAX14830. - Each IC contains 128 words each of receive and transmit FIFO - that can be controlled through I2C or high-speed SPI. - - Say Y here if you want to support this ICs. - -config SERIAL_DZ - bool "DECstation DZ serial driver" - depends on MACH_DECSTATION && 32BIT - select SERIAL_CORE - default y - ---help--- - DZ11-family serial controllers for DECstations and VAXstations, - including the DC7085, M7814, and M7819. - -config SERIAL_DZ_CONSOLE - bool "Support console on DECstation DZ serial driver" - depends on SERIAL_DZ=y - select SERIAL_CORE_CONSOLE - default y - ---help--- - If you say Y here, it will be possible to use a serial port as the - system console (the system console is the device which receives all - kernel messages and warnings and which allows logins in single user - mode). - - Note that the firmware uses ttyS3 as the serial console on - DECstations that use this driver. - - If unsure, say Y. - -config SERIAL_ZS - tristate "DECstation Z85C30 serial support" - depends on MACH_DECSTATION - select SERIAL_CORE - default y - ---help--- - Support for the Zilog 85C350 serial communications controller used - for serial ports in newer DECstation systems. These include the - DECsystem 5900 and all models of the DECstation and DECsystem 5000 - systems except from model 200. - - If unsure, say Y. To compile this driver as a module, choose M here: - the module will be called zs. - -config SERIAL_ZS_CONSOLE - bool "Support for console on a DECstation Z85C30 serial port" - depends on SERIAL_ZS=y - select SERIAL_CORE_CONSOLE - default y - ---help--- - If you say Y here, it will be possible to use a serial port as the - system console (the system console is the device which receives all - kernel messages and warnings and which allows logins in single user - mode). - - Note that the firmware uses ttyS1 as the serial console on the - Maxine and ttyS3 on the others using this driver. - - If unsure, say Y. - -config SERIAL_21285 - tristate "DC21285 serial port support" - depends on FOOTBRIDGE - select SERIAL_CORE - help - If you have a machine based on a 21285 (Footbridge) StrongARM(R)/ - PCI bridge you can enable its onboard serial port by enabling this - option. - -config SERIAL_21285_CONSOLE - bool "Console on DC21285 serial port" - depends on SERIAL_21285=y - select SERIAL_CORE_CONSOLE - help - If you have enabled the serial port on the 21285 footbridge you can - make it the console by answering Y to this option. - - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttyFB". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) - -config SERIAL_MPSC - bool "Marvell MPSC serial port support" - depends on MV64X60 - select SERIAL_CORE - help - Say Y here if you want to use the Marvell MPSC serial controller. - -config SERIAL_MPSC_CONSOLE - bool "Support for console on Marvell MPSC serial port" - depends on SERIAL_MPSC - select SERIAL_CORE_CONSOLE - help - Say Y here if you want to support a serial console on a Marvell MPSC. - -config SERIAL_PXA - bool "PXA serial port support" - depends on ARCH_PXA || ARCH_MMP - select SERIAL_CORE - help - If you have a machine based on an Intel XScale PXA2xx CPU you - can enable its onboard serial ports by enabling this option. - -config SERIAL_PXA_CONSOLE - bool "Console on PXA serial port" - depends on SERIAL_PXA - select SERIAL_CORE_CONSOLE - help - If you have enabled the serial port on the Intel XScale PXA - CPU you can make it the console by answering Y to this option. - - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttySA0". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) - -config SERIAL_SA1100 - bool "SA1100 serial port support" - depends on ARCH_SA1100 - select SERIAL_CORE - help - If you have a machine based on a SA1100/SA1110 StrongARM(R) CPU you - can enable its onboard serial port by enabling this option. - Please read for further - info. - -config SERIAL_SA1100_CONSOLE - bool "Console on SA1100 serial port" - depends on SERIAL_SA1100 - select SERIAL_CORE_CONSOLE - help - If you have enabled the serial port on the SA1100/SA1110 StrongARM - CPU you can make it the console by answering Y to this option. - - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttySA0". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) - -config SERIAL_BFIN - tristate "Blackfin serial port support" - depends on BLACKFIN - select SERIAL_CORE - select SERIAL_BFIN_UART0 if (BF531 || BF532 || BF533 || BF561) - help - Add support for the built-in UARTs on the Blackfin. - - To compile this driver as a module, choose M here: the - module is named bfin_uart.ko. - -config SERIAL_BFIN_CONSOLE - bool "Console on Blackfin serial port" - depends on SERIAL_BFIN=y - select SERIAL_CORE_CONSOLE - -choice - prompt "UART Mode" - depends on SERIAL_BFIN - default SERIAL_BFIN_DMA - help - This driver supports the built-in serial ports of the Blackfin family - of CPUs - -config SERIAL_BFIN_DMA - bool "DMA mode" - depends on !DMA_UNCACHED_NONE && KGDB_SERIAL_CONSOLE=n - help - This driver works under DMA mode. If this option is selected, the - blackfin simple dma driver is also enabled. - -config SERIAL_BFIN_PIO - bool "PIO mode" - help - This driver works under PIO mode. - -endchoice - -config SERIAL_BFIN_UART0 - bool "Enable UART0" - depends on SERIAL_BFIN - help - Enable UART0 - -config BFIN_UART0_CTSRTS - bool "Enable UART0 hardware flow control" - depends on SERIAL_BFIN_UART0 - help - Enable hardware flow control in the driver. - -config SERIAL_BFIN_UART1 - bool "Enable UART1" - depends on SERIAL_BFIN && (!BF531 && !BF532 && !BF533 && !BF561) - help - Enable UART1 - -config BFIN_UART1_CTSRTS - bool "Enable UART1 hardware flow control" - depends on SERIAL_BFIN_UART1 - help - Enable hardware flow control in the driver. - -config SERIAL_BFIN_UART2 - bool "Enable UART2" - depends on SERIAL_BFIN && (BF54x || BF538 || BF539) - help - Enable UART2 - -config BFIN_UART2_CTSRTS - bool "Enable UART2 hardware flow control" - depends on SERIAL_BFIN_UART2 - help - Enable hardware flow control in the driver. - -config SERIAL_BFIN_UART3 - bool "Enable UART3" - depends on SERIAL_BFIN && (BF54x) - help - Enable UART3 - -config BFIN_UART3_CTSRTS - bool "Enable UART3 hardware flow control" - depends on SERIAL_BFIN_UART3 - help - Enable hardware flow control in the driver. - -config SERIAL_IMX - tristate "IMX serial port support" - depends on HAS_DMA - depends on ARCH_MXC || COMPILE_TEST - select SERIAL_CORE - select RATIONAL - select SERIAL_MCTRL_GPIO if GPIOLIB - help - If you have a machine based on a Motorola IMX CPU you - can enable its onboard serial port by enabling this option. - -config SERIAL_IMX_CONSOLE - bool "Console on IMX serial port" - depends on SERIAL_IMX=y - select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON if OF - help - If you have enabled the serial port on the Freescale IMX - CPU you can make it the console by answering Y to this option. - - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttymxc0". (Try "man bootparam" or see the documentation of - your bootloader about how to pass options to the kernel at boot time.) - -config SERIAL_UARTLITE - tristate "Xilinx uartlite serial port support" - depends on HAS_IOMEM - select SERIAL_CORE - help - Say Y here if you want to use the Xilinx uartlite serial controller. - - To compile this driver as a module, choose M here: the - module will be called uartlite. - -config SERIAL_UARTLITE_CONSOLE - bool "Support for console on Xilinx uartlite serial port" - depends on SERIAL_UARTLITE=y - select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON - help - Say Y here if you wish to use a Xilinx uartlite as the system - console (the system console is the device which receives all kernel - messages and warnings and which allows logins in single user mode). - -config SERIAL_SUNCORE - bool - depends on SPARC - select SERIAL_CORE - select SERIAL_CORE_CONSOLE - default y - -config SERIAL_SUNZILOG - tristate "Sun Zilog8530 serial support" - depends on SPARC - help - This driver supports the Zilog8530 serial ports found on many Sparc - systems. Say Y or M if you want to be able to these serial ports. - -config SERIAL_SUNZILOG_CONSOLE - bool "Console on Sun Zilog8530 serial port" - depends on SERIAL_SUNZILOG=y - help - If you would like to be able to use the Zilog8530 serial port - on your Sparc system as the console, you can do so by answering - Y to this option. - -config SERIAL_SUNSU - tristate "Sun SU serial support" - depends on SPARC && PCI - help - This driver supports the 8250 serial ports that run the keyboard and - mouse on (PCI) UltraSPARC systems. Say Y or M if you want to be able - to these serial ports. - -config SERIAL_SUNSU_CONSOLE - bool "Console on Sun SU serial port" - depends on SERIAL_SUNSU=y - help - If you would like to be able to use the SU serial port - on your Sparc system as the console, you can do so by answering - Y to this option. - -config SERIAL_MUX - tristate "Serial MUX support" - depends on GSC - select SERIAL_CORE - default y - ---help--- - Saying Y here will enable the hardware MUX serial driver for - the Nova, K class systems and D class with a 'remote control card'. - The hardware MUX is not 8250/16550 compatible therefore the - /dev/ttyB0 device is shared between the Serial MUX and the PDC - software console. The following steps need to be completed to use - the Serial MUX: - - 1. create the device entry (mknod /dev/ttyB0 c 11 0) - 2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0 - 3. Add device ttyB0 to /etc/securetty (if you want to log on as - root on this console.) - 4. Change the kernel command console parameter to: console=ttyB0 - -config SERIAL_MUX_CONSOLE - bool "Support for console on serial MUX" - depends on SERIAL_MUX=y - select SERIAL_CORE_CONSOLE - default y - -config PDC_CONSOLE - bool "PDC software console support" - depends on PARISC && !SERIAL_MUX && VT - default n - help - Saying Y here will enable the software based PDC console to be - used as the system console. This is useful for machines in - which the hardware based console has not been written yet. The - following steps must be completed to use the PDC console: - - 1. create the device entry (mknod /dev/ttyB0 c 11 0) - 2. Edit the /etc/inittab to start a getty listening on /dev/ttyB0 - 3. Add device ttyB0 to /etc/securetty (if you want to log on as - root on this console.) - 4. Change the kernel command console parameter to: console=ttyB0 - -config SERIAL_SUNSAB - tristate "Sun Siemens SAB82532 serial support" - depends on SPARC && PCI - help - This driver supports the Siemens SAB82532 DUSCC serial ports on newer - (PCI) UltraSPARC systems. Say Y or M if you want to be able to these - serial ports. - -config SERIAL_SUNSAB_CONSOLE - bool "Console on Sun Siemens SAB82532 serial port" - depends on SERIAL_SUNSAB=y - help - If you would like to be able to use the SAB82532 serial port - on your Sparc system as the console, you can do so by answering - Y to this option. - -config SERIAL_SUNHV - bool "Sun4v Hypervisor Console support" - depends on SPARC64 - help - This driver supports the console device found on SUN4V Sparc - systems. Say Y if you want to be able to use this device. - -config SERIAL_IP22_ZILOG - tristate "SGI Zilog8530 serial support" - depends on SGI_HAS_ZILOG - select SERIAL_CORE - help - This driver supports the Zilog8530 serial ports found on SGI - systems. Say Y or M if you want to be able to these serial ports. - -config SERIAL_IP22_ZILOG_CONSOLE - bool "Console on SGI Zilog8530 serial port" - depends on SERIAL_IP22_ZILOG=y - select SERIAL_CORE_CONSOLE - -config SERIAL_SH_SCI - tristate "SuperH SCI(F) serial port support" - depends on SUPERH || ARCH_RENESAS || H8300 || COMPILE_TEST - select SERIAL_CORE - select SERIAL_MCTRL_GPIO if GPIOLIB - -config SERIAL_SH_SCI_NR_UARTS - int "Maximum number of SCI(F) serial ports" - depends on SERIAL_SH_SCI - default "2" - -config SERIAL_SH_SCI_CONSOLE - bool "Support for console on SuperH SCI(F)" - depends on SERIAL_SH_SCI=y - select SERIAL_CORE_CONSOLE - -config SERIAL_SH_SCI_EARLYCON - bool "Support for early console on SuperH SCI(F)" - depends on SERIAL_SH_SCI=y - select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON - -config SERIAL_SH_SCI_DMA - bool "DMA support" - depends on SERIAL_SH_SCI && DMA_ENGINE - -config SERIAL_PNX8XXX - bool "Enable PNX8XXX SoCs' UART Support" - depends on SOC_PNX833X - select SERIAL_CORE - help - If you have a MIPS-based Philips SoC such as PNX8330 and you want - to use serial ports, say Y. Otherwise, say N. - -config SERIAL_PNX8XXX_CONSOLE - bool "Enable PNX8XX0 serial console" - depends on SERIAL_PNX8XXX - select SERIAL_CORE_CONSOLE - help - If you have a MIPS-based Philips SoC such as PNX8330 and you want - to use serial console, say Y. Otherwise, say N. - -config SERIAL_HS_LPC32XX - tristate "LPC32XX high speed serial port support" - depends on ARCH_LPC32XX && OF - select SERIAL_CORE - help - Support for the LPC32XX high speed serial ports (up to 900kbps). - Those are UARTs completely different from the Standard UARTs on the - LPC32XX SoC. - Choose M or Y here to build this driver. - -config SERIAL_HS_LPC32XX_CONSOLE - bool "Enable LPC32XX high speed UART serial console" - depends on SERIAL_HS_LPC32XX=y - select SERIAL_CORE_CONSOLE - help - If you would like to be able to use one of the high speed serial - ports on the LPC32XX as the console, you can do so by answering - Y to this option. - -config SERIAL_CORE - tristate - -config SERIAL_CORE_CONSOLE - bool - -config CONSOLE_POLL - bool - -config SERIAL_MCF - bool "Coldfire serial support" - depends on COLDFIRE - select SERIAL_CORE - help - This serial driver supports the Freescale Coldfire serial ports. - -config SERIAL_MCF_BAUDRATE - int "Default baudrate for Coldfire serial ports" - depends on SERIAL_MCF - default 19200 - help - This setting lets you define what the default baudrate is for the - ColdFire serial ports. The usual default varies from board to board, - and this setting is a way of catering for that. - -config SERIAL_MCF_CONSOLE - bool "Coldfire serial console support" - depends on SERIAL_MCF - select SERIAL_CORE_CONSOLE - help - Enable a ColdFire internal serial port to be the system console. - -config SERIAL_PMACZILOG - tristate "Mac or PowerMac z85c30 ESCC support" - depends on (M68K && MAC) || PPC_PMAC - select SERIAL_CORE - help - This driver supports the Zilog z85C30 serial ports found on - (Power)Mac machines. - Say Y or M if you want to be able to these serial ports. - -config SERIAL_PMACZILOG_TTYS - bool "Use ttySn device nodes for Zilog z85c30" - depends on SERIAL_PMACZILOG - help - The pmac_zilog driver for the z85C30 chip on many powermacs - historically used the device numbers for /dev/ttySn. The - 8250 serial port driver also uses these numbers, which means - the two drivers being unable to coexist; you could not use - both z85C30 and 8250 type ports at the same time. - - If this option is not selected, the pmac_zilog driver will - use the device numbers allocated for /dev/ttyPZn. This allows - the pmac_zilog and 8250 drivers to co-exist, but may cause - existing userspace setups to break. Programs that need to - access the built-in serial ports on powermacs will need to - be reconfigured to use /dev/ttyPZn instead of /dev/ttySn. - - If you enable this option, any z85c30 ports in the system will - be registered as ttyS0 onwards as in the past, and you will be - unable to use the 8250 module for PCMCIA or other 16C550-style - UARTs. - - Say N unless you need the z85c30 ports on your (Power)Mac - to appear as /dev/ttySn. - -config SERIAL_PMACZILOG_CONSOLE - bool "Console on Mac or PowerMac z85c30 serial port" - depends on SERIAL_PMACZILOG=y - select SERIAL_CORE_CONSOLE - help - If you would like to be able to use the z85c30 serial port - on your (Power)Mac as the console, you can do so by answering - Y to this option. - -config SERIAL_CPM - tristate "CPM SCC/SMC serial port support" - depends on CPM2 || CPM1 - select SERIAL_CORE - help - This driver supports the SCC and SMC serial ports on Motorola - embedded PowerPC that contain a CPM1 (8xx) or CPM2 (8xxx) - -config SERIAL_CPM_CONSOLE - bool "Support for console on CPM SCC/SMC serial port" - depends on SERIAL_CPM=y - select SERIAL_CORE_CONSOLE - help - Say Y here if you wish to use a SCC or SMC CPM UART as the system - console (the system console is the device which receives all kernel - messages and warnings and which allows logins in single user mode). - - Even if you say Y here, the currently visible framebuffer console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttyCPM0". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) - -config SERIAL_SGI_L1_CONSOLE - bool "SGI Altix L1 serial console support" - depends on IA64_GENERIC || IA64_SGI_SN2 - select SERIAL_CORE - select SERIAL_CORE_CONSOLE - help - If you have an SGI Altix and you would like to use the system - controller serial port as your console (you want this!), - say Y. Otherwise, say N. - -config SERIAL_PIC32 - tristate "Microchip PIC32 serial support" - depends on MACH_PIC32 - select SERIAL_CORE - help - If you have a PIC32, this driver supports the serial ports. - - Say Y or M to use PIC32 serial ports, otherwise say N. Note that - to use a serial port as a console, this must be included in kernel and - not as a module. - -config SERIAL_PIC32_CONSOLE - bool "PIC32 serial console support" - depends on SERIAL_PIC32 - select SERIAL_CORE_CONSOLE - help - If you have a PIC32, this driver supports the putting a console on one - of the serial ports. - - Say Y to use the PIC32 console, otherwise say N. - -config SERIAL_MPC52xx - tristate "Freescale MPC52xx/MPC512x family PSC serial support" - depends on PPC_MPC52xx || PPC_MPC512x - select SERIAL_CORE - help - This driver supports MPC52xx and MPC512x PSC serial ports. If you would - like to use them, you must answer Y or M to this option. Note that - for use as console, it must be included in kernel and not as a - module. - -config SERIAL_MPC52xx_CONSOLE - bool "Console on a Freescale MPC52xx/MPC512x family PSC serial port" - depends on SERIAL_MPC52xx=y - select SERIAL_CORE_CONSOLE - help - Select this options if you'd like to use one of the PSC serial port - of the Freescale MPC52xx family as a console. - -config SERIAL_MPC52xx_CONSOLE_BAUD - int "Freescale MPC52xx/MPC512x family PSC serial port baud" - depends on SERIAL_MPC52xx_CONSOLE=y - default "9600" - help - Select the MPC52xx console baud rate. - This value is only used if the bootloader doesn't pass in the - console baudrate - -config SERIAL_ICOM - tristate "IBM Multiport Serial Adapter" - depends on PCI && PPC_PSERIES - select SERIAL_CORE - select FW_LOADER - help - This driver is for a family of multiport serial adapters - including 2 port RVX, 2 port internal modem, 4 port internal - modem and a split 1 port RVX and 1 port internal modem. - - This driver can also be built as a module. If so, the module - will be called icom. - -config SERIAL_M32R_SIO - bool "M32R SIO I/F" - depends on M32R - default y - select SERIAL_CORE - help - Say Y here if you want to use the M32R serial controller. - -config SERIAL_M32R_SIO_CONSOLE - bool "use SIO console" - depends on SERIAL_M32R_SIO=y - select SERIAL_CORE_CONSOLE - help - Say Y here if you want to support a serial console. - - If you use an M3T-M32700UT or an OPSPUT platform, - please say also y for SERIAL_M32R_PLDSIO. - -config SERIAL_M32R_PLDSIO - bool "M32R SIO I/F on a PLD" - depends on SERIAL_M32R_SIO=y && (PLAT_OPSPUT || PLAT_USRV || PLAT_M32700UT) - default n - help - Say Y here if you want to use the M32R serial controller - on a PLD (Programmable Logic Device). - - If you use an M3T-M32700UT or an OPSPUT platform, - please say Y. - -config SERIAL_TXX9 - bool "TMPTX39XX/49XX SIO support" - depends on HAS_TXX9_SERIAL - select SERIAL_CORE - default y - -config HAS_TXX9_SERIAL - bool - -config SERIAL_TXX9_NR_UARTS - int "Maximum number of TMPTX39XX/49XX SIO ports" - depends on SERIAL_TXX9 - default "6" - -config SERIAL_TXX9_CONSOLE - bool "TMPTX39XX/49XX SIO Console support" - depends on SERIAL_TXX9=y - select SERIAL_CORE_CONSOLE - -config SERIAL_TXX9_STDSERIAL - bool "TX39XX/49XX SIO act as standard serial" - depends on !SERIAL_8250 && SERIAL_TXX9 - -config SERIAL_VR41XX - tristate "NEC VR4100 series Serial Interface Unit support" - depends on CPU_VR41XX - select SERIAL_CORE - help - If you have a NEC VR4100 series processor and you want to use - Serial Interface Unit(SIU) or Debug Serial Interface Unit(DSIU) - (not include VR4111/VR4121 DSIU), say Y. Otherwise, say N. - -config SERIAL_VR41XX_CONSOLE - bool "Enable NEC VR4100 series Serial Interface Unit console" - depends on SERIAL_VR41XX=y - select SERIAL_CORE_CONSOLE - help - If you have a NEC VR4100 series processor and you want to use - a console on a serial port, say Y. Otherwise, say N. - -config SERIAL_JSM - tristate "Digi International NEO and Classic PCI Support" - depends on PCI - select SERIAL_CORE - help - This is a driver for Digi International's Neo and Classic series - of cards which provide multiple serial ports. You would need - something like this to connect more than two modems to your Linux - box, for instance in order to become a dial-in server. This driver - supports PCI boards only. - - If you have a card like this, say Y here, otherwise say N. - - To compile this driver as a module, choose M here: the - module will be called jsm. - -config SERIAL_SGI_IOC4 - tristate "SGI IOC4 controller serial support" - depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC4 - select SERIAL_CORE - help - If you have an SGI Altix with an IOC4 based Base IO card - and wish to use the serial ports on this card, say Y. - Otherwise, say N. - -config SERIAL_SGI_IOC3 - tristate "SGI Altix IOC3 serial support" - depends on (IA64_GENERIC || IA64_SGI_SN2) && SGI_IOC3 - select SERIAL_CORE - help - If you have an SGI Altix with an IOC3 serial card, - say Y or M. Otherwise, say N. - -config SERIAL_MSM - tristate "MSM on-chip serial port support" - depends on ARCH_QCOM - select SERIAL_CORE - -config SERIAL_MSM_CONSOLE - bool "MSM serial console support" - depends on SERIAL_MSM=y - select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON - -config SERIAL_VT8500 - bool "VIA VT8500 on-chip serial port support" - depends on ARCH_VT8500 - select SERIAL_CORE - -config SERIAL_VT8500_CONSOLE - bool "VIA VT8500 serial console support" - depends on SERIAL_VT8500=y - select SERIAL_CORE_CONSOLE - -config SERIAL_ETRAXFS - bool "ETRAX FS serial port support" - depends on ETRAX_ARCH_V32 && OF - select SERIAL_CORE - select SERIAL_MCTRL_GPIO if GPIOLIB - -config SERIAL_ETRAXFS_CONSOLE - bool "ETRAX FS serial console support" - depends on SERIAL_ETRAXFS - select SERIAL_CORE_CONSOLE - -config SERIAL_NETX - tristate "NetX serial port support" - depends on ARCH_NETX - select SERIAL_CORE - help - If you have a machine based on a Hilscher NetX SoC you - can enable its onboard serial port by enabling this option. - - To compile this driver as a module, choose M here: the - module will be called netx-serial. - -config SERIAL_NETX_CONSOLE - bool "Console on NetX serial port" - depends on SERIAL_NETX=y - select SERIAL_CORE_CONSOLE - help - If you have enabled the serial port on the Hilscher NetX SoC - you can make it the console by answering Y to this option. - -config SERIAL_OMAP - tristate "OMAP serial port support" - depends on ARCH_OMAP2PLUS - select SERIAL_CORE - help - If you have a machine based on an Texas Instruments OMAP CPU you - can enable its onboard serial ports by enabling this option. - - By enabling this option you take advantage of dma feature available - with the omap-serial driver. DMA support can be enabled from platform - data. - -config SERIAL_OMAP_CONSOLE - bool "Console on OMAP serial port" - depends on SERIAL_OMAP=y - select SERIAL_CORE_CONSOLE - help - Select this option if you would like to use omap serial port as - console. - - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttyOx". (Try "man bootparam" or see the documentation of - your boot loader about how to pass options to the kernel at - boot time.) - -config SERIAL_LANTIQ - bool "Lantiq serial driver" - depends on LANTIQ - select SERIAL_CORE - select SERIAL_CORE_CONSOLE - help - Support for console and UART on Lantiq SoCs. - -config SERIAL_QE - tristate "Freescale QUICC Engine serial port support" - depends on QUICC_ENGINE - select SERIAL_CORE - select FW_LOADER - default n - help - This driver supports the QE serial ports on Freescale embedded - PowerPC that contain a QUICC Engine. - -config SERIAL_SCCNXP - tristate "SCCNXP serial port support" - select SERIAL_CORE - help - This selects support for an advanced UART from NXP (Philips). - Supported ICs are SCC2681, SCC2691, SCC2692, SC28L91, SC28L92, - SC28L202, SCC68681 and SCC68692. - -config SERIAL_SCCNXP_CONSOLE - bool "Console on SCCNXP serial port" - depends on SERIAL_SCCNXP=y - select SERIAL_CORE_CONSOLE - help - Support for console on SCCNXP serial ports. - -config SERIAL_SC16IS7XX_CORE - tristate - -config SERIAL_SC16IS7XX - tristate "SC16IS7xx serial support" - select SERIAL_CORE - depends on (SPI_MASTER && !I2C) || I2C - help - This selects support for SC16IS7xx serial ports. - Supported ICs are SC16IS740, SC16IS741, SC16IS750, SC16IS752, - SC16IS760 and SC16IS762. Select supported buses using options below. - -config SERIAL_SC16IS7XX_I2C - bool "SC16IS7xx for I2C interface" - depends on SERIAL_SC16IS7XX - depends on I2C - select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX - select REGMAP_I2C if I2C - default y - help - Enable SC16IS7xx driver on I2C bus, - If required say y, and say n to i2c if not required, - Enabled by default to support oldconfig. - You must select at least one bus for the driver to be built. - -config SERIAL_SC16IS7XX_SPI - bool "SC16IS7xx for spi interface" - depends on SERIAL_SC16IS7XX - depends on SPI_MASTER - select SERIAL_SC16IS7XX_CORE if SERIAL_SC16IS7XX - select REGMAP_SPI if SPI_MASTER - help - Enable SC16IS7xx driver on SPI bus, - If required say y, and say n to spi if not required, - This is additional support to exsisting driver. - You must select at least one bus for the driver to be built. - -config SERIAL_BFIN_SPORT - tristate "Blackfin SPORT emulate UART" - depends on BLACKFIN - select SERIAL_CORE - help - Enable SPORT emulate UART on Blackfin series. - - To compile this driver as a module, choose M here: the - module will be called bfin_sport_uart. - -config SERIAL_BFIN_SPORT_CONSOLE - bool "Console on Blackfin sport emulated uart" - depends on SERIAL_BFIN_SPORT=y - select SERIAL_CORE_CONSOLE - -config SERIAL_BFIN_SPORT0_UART - bool "Enable UART over SPORT0" - depends on SERIAL_BFIN_SPORT && !(BF542 || BF544) - help - Enable UART over SPORT0 - -config SERIAL_BFIN_SPORT0_UART_CTSRTS - bool "Enable UART over SPORT0 hardware flow control" - depends on SERIAL_BFIN_SPORT0_UART - help - Enable hardware flow control in the driver. - -config SERIAL_BFIN_SPORT1_UART - bool "Enable UART over SPORT1" - depends on SERIAL_BFIN_SPORT - help - Enable UART over SPORT1 - -config SERIAL_BFIN_SPORT1_UART_CTSRTS - bool "Enable UART over SPORT1 hardware flow control" - depends on SERIAL_BFIN_SPORT1_UART - help - Enable hardware flow control in the driver. - -config SERIAL_BFIN_SPORT2_UART - bool "Enable UART over SPORT2" - depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539) - help - Enable UART over SPORT2 - -config SERIAL_BFIN_SPORT2_UART_CTSRTS - bool "Enable UART over SPORT2 hardware flow control" - depends on SERIAL_BFIN_SPORT2_UART - help - Enable hardware flow control in the driver. - -config SERIAL_BFIN_SPORT3_UART - bool "Enable UART over SPORT3" - depends on SERIAL_BFIN_SPORT && (BF54x || BF538 || BF539) - help - Enable UART over SPORT3 - -config SERIAL_BFIN_SPORT3_UART_CTSRTS - bool "Enable UART over SPORT3 hardware flow control" - depends on SERIAL_BFIN_SPORT3_UART - help - Enable hardware flow control in the driver. - -config SERIAL_TIMBERDALE - tristate "Support for timberdale UART" - select SERIAL_CORE - depends on X86_32 || COMPILE_TEST - ---help--- - Add support for UART controller on timberdale. - -config SERIAL_BCM63XX - tristate "Broadcom BCM63xx/BCM33xx UART support" - select SERIAL_CORE - depends on MIPS || ARM || COMPILE_TEST - help - This enables the driver for the onchip UART core found on - the following chipsets: - - BCM33xx (cable modem) - BCM63xx/BCM63xxx (DSL) - BCM68xx (PON) - BCM7xxx (STB) - DOCSIS console - -config SERIAL_BCM63XX_CONSOLE - bool "Console on BCM63xx serial port" - depends on SERIAL_BCM63XX=y - select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON - help - If you have enabled the serial port on the BCM63xx CPU - you can make it the console by answering Y to this option. - -config SERIAL_GRLIB_GAISLER_APBUART - tristate "GRLIB APBUART serial support" - depends on OF && SPARC - select SERIAL_CORE - ---help--- - Add support for the GRLIB APBUART serial port. - -config SERIAL_GRLIB_GAISLER_APBUART_CONSOLE - bool "Console on GRLIB APBUART serial port" - depends on SERIAL_GRLIB_GAISLER_APBUART=y - select SERIAL_CORE_CONSOLE - help - Support for running a console on the GRLIB APBUART - -config SERIAL_ALTERA_JTAGUART - tristate "Altera JTAG UART support" - select SERIAL_CORE - help - This driver supports the Altera JTAG UART port. - -config SERIAL_ALTERA_JTAGUART_CONSOLE - bool "Altera JTAG UART console support" - depends on SERIAL_ALTERA_JTAGUART=y - select SERIAL_CORE_CONSOLE - help - Enable a Altera JTAG UART port to be the system console. - -config SERIAL_ALTERA_JTAGUART_CONSOLE_BYPASS - bool "Bypass output when no connection" - depends on SERIAL_ALTERA_JTAGUART_CONSOLE - select SERIAL_CORE_CONSOLE - help - Bypass console output and keep going even if there is no - JTAG terminal connection with the host. - -config SERIAL_ALTERA_UART - tristate "Altera UART support" - select SERIAL_CORE - help - This driver supports the Altera softcore UART port. - -config SERIAL_ALTERA_UART_MAXPORTS - int "Maximum number of Altera UART ports" - depends on SERIAL_ALTERA_UART - default 4 - help - This setting lets you define the maximum number of the Altera - UART ports. The usual default varies from board to board, and - this setting is a way of catering for that. - -config SERIAL_ALTERA_UART_BAUDRATE - int "Default baudrate for Altera UART ports" - depends on SERIAL_ALTERA_UART - default 115200 - help - This setting lets you define what the default baudrate is for the - Altera UART ports. The usual default varies from board to board, - and this setting is a way of catering for that. - -config SERIAL_ALTERA_UART_CONSOLE - bool "Altera UART console support" - depends on SERIAL_ALTERA_UART=y - select SERIAL_CORE_CONSOLE - help - Enable a Altera UART port to be the system console. - -config SERIAL_IFX6X60 - tristate "SPI protocol driver for Infineon 6x60 modem (EXPERIMENTAL)" - depends on GPIOLIB || COMPILE_TEST - depends on SPI && HAS_DMA - help - Support for the IFX6x60 modem devices on Intel MID platforms. - -config SERIAL_PCH_UART - tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) UART" - depends on PCI && (X86_32 || MIPS || COMPILE_TEST) - select SERIAL_CORE - help - This driver is for PCH(Platform controller Hub) UART of Intel EG20T - which is an IOH(Input/Output Hub) for x86 embedded processor. - Enabling PCH_DMA, this PCH UART works as DMA mode. - - This driver also can be used for LAPIS Semiconductor IOH(Input/ - Output Hub), ML7213, ML7223 and ML7831. - ML7213 IOH is for IVI(In-Vehicle Infotainment) use, ML7223 IOH is - for MP(Media Phone) use and ML7831 IOH is for general purpose use. - ML7213/ML7223/ML7831 is companion chip for Intel Atom E6xx series. - ML7213/ML7223/ML7831 is completely compatible for Intel EG20T PCH. - -config SERIAL_PCH_UART_CONSOLE - bool "Support for console on Intel EG20T PCH UART/OKI SEMICONDUCTOR ML7213 IOH" - depends on SERIAL_PCH_UART=y - select SERIAL_CORE_CONSOLE - help - Say Y here if you wish to use the PCH UART as the system console - (the system console is the device which receives all kernel messages and - warnings and which allows logins in single user mode). - -config SERIAL_MXS_AUART - tristate "MXS AUART support" - depends on HAS_DMA - depends on ARCH_MXS || MACH_ASM9260 || COMPILE_TEST - select SERIAL_CORE - select SERIAL_MCTRL_GPIO if GPIOLIB - help - This driver supports the MXS and Alphascale ASM9260 Application - UART (AUART) port. - -config SERIAL_MXS_AUART_CONSOLE - bool "MXS AUART console support" - depends on SERIAL_MXS_AUART=y - select SERIAL_CORE_CONSOLE - help - Enable a MXS AUART port to be the system console. - -config SERIAL_XILINX_PS_UART - tristate "Cadence (Xilinx Zynq) UART support" - depends on OF - select SERIAL_CORE - help - This driver supports the Cadence UART. It is found e.g. in Xilinx - Zynq. - -config SERIAL_XILINX_PS_UART_CONSOLE - bool "Cadence UART console support" - depends on SERIAL_XILINX_PS_UART=y - select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON - help - Enable a Cadence UART port to be the system console. - -config SERIAL_AR933X - tristate "AR933X serial port support" - depends on HAVE_CLK && SOC_AR933X - select SERIAL_CORE - help - If you have an Atheros AR933X SOC based board and want to use the - built-in UART of the SoC, say Y to this option. - - To compile this driver as a module, choose M here: the - module will be called ar933x_uart. - -config SERIAL_AR933X_CONSOLE - bool "Console on AR933X serial port" - depends on SERIAL_AR933X=y - select SERIAL_CORE_CONSOLE - help - Enable a built-in UART port of the AR933X to be the system console. - -config SERIAL_AR933X_NR_UARTS - int "Maximum number of AR933X serial ports" - depends on SERIAL_AR933X - default "2" - help - Set this to the number of serial ports you want the driver - to support. - -config SERIAL_EFM32_UART - tristate "EFM32 UART/USART port" - depends on ARM && (ARCH_EFM32 || COMPILE_TEST) - select SERIAL_CORE - help - This driver support the USART and UART ports on - Energy Micro's efm32 SoCs. - -config SERIAL_MPS2_UART_CONSOLE - bool "MPS2 UART console support" - depends on SERIAL_MPS2_UART - select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON - -config SERIAL_MPS2_UART - bool "MPS2 UART port" - depends on ARCH_MPS2 || COMPILE_TEST - select SERIAL_CORE - help - This driver support the UART ports on ARM MPS2. - -config SERIAL_EFM32_UART_CONSOLE - bool "EFM32 UART/USART console support" - depends on SERIAL_EFM32_UART=y - select SERIAL_CORE_CONSOLE - -config SERIAL_TILEGX - tristate "TILE-Gx on-chip serial port support" - depends on TILEGX - select TILE_GXIO_UART - select SERIAL_CORE - ---help--- - This device provides access to the on-chip UARTs on the TILE-Gx - processor. - -config SERIAL_ARC - tristate "ARC UART driver support" - select SERIAL_CORE - help - Driver for on-chip UART for ARC(Synopsys) for the legacy - FPGA Boards (ML50x/ARCAngel4) - -config SERIAL_ARC_CONSOLE - bool "Console on ARC UART" - depends on SERIAL_ARC=y - select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON - help - Enable system Console on ARC UART - -config SERIAL_ARC_NR_PORTS - int "Number of ARC UART ports" - depends on SERIAL_ARC - range 1 3 - default "1" - help - Set this to the number of serial ports you want the driver - to support. - -config SERIAL_RP2 - tristate "Comtrol RocketPort EXPRESS/INFINITY support" - depends on PCI - select SERIAL_CORE - help - This driver supports the Comtrol RocketPort EXPRESS and - RocketPort INFINITY families of PCI/PCIe multiport serial adapters. - These adapters use a "RocketPort 2" ASIC that is not compatible - with the original RocketPort driver (CONFIG_ROCKETPORT). - - To compile this driver as a module, choose M here: the - module will be called rp2. - - If you want to compile this driver into the kernel, say Y here. If - you don't have a suitable RocketPort card installed, say N. - -config SERIAL_RP2_NR_UARTS - int "Maximum number of RocketPort EXPRESS/INFINITY ports" - depends on SERIAL_RP2 - default "32" - help - If multiple cards are present, the default limit of 32 ports may - need to be increased. - -config SERIAL_FSL_LPUART - tristate "Freescale lpuart serial port support" - depends on HAS_DMA - select SERIAL_CORE - help - Support for the on-chip lpuart on some Freescale SOCs. - -config SERIAL_FSL_LPUART_CONSOLE - bool "Console on Freescale lpuart serial port" - depends on SERIAL_FSL_LPUART=y - select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON - help - If you have enabled the lpuart serial port on the Freescale SoCs, - you can make it the console by answering Y to this option. - -config SERIAL_CONEXANT_DIGICOLOR - tristate "Conexant Digicolor CX92xxx USART serial port support" - depends on OF - select SERIAL_CORE - help - Support for the on-chip USART on Conexant Digicolor SoCs. - -config SERIAL_CONEXANT_DIGICOLOR_CONSOLE - bool "Console on Conexant Digicolor serial port" - depends on SERIAL_CONEXANT_DIGICOLOR=y - select SERIAL_CORE_CONSOLE - help - If you have enabled the USART serial port on Conexant Digicolor - SoCs, you can make it the console by answering Y to this option. - -config SERIAL_ST_ASC - tristate "ST ASC serial port support" - select SERIAL_CORE - depends on ARM || COMPILE_TEST - help - This driver is for the on-chip Asychronous Serial Controller on - STMicroelectronics STi SoCs. - ASC is embedded in ST COMMS IP block. It supports Rx & Tx functionality. - It support all industry standard baud rates. - - If unsure, say N. - -config SERIAL_ST_ASC_CONSOLE - bool "Support for console on ST ASC" - depends on SERIAL_ST_ASC=y - select SERIAL_CORE_CONSOLE - -config SERIAL_MEN_Z135 - tristate "MEN 16z135 Support" - select SERIAL_CORE - depends on MCB - help - Say yes here to enable support for the MEN 16z135 High Speed UART IP-Core - on a MCB carrier. - - This driver can also be build as a module. If so, the module will be called - men_z135_uart.ko - -config SERIAL_SPRD - tristate "Support for Spreadtrum serial" - depends on ARCH_SPRD - select SERIAL_CORE - help - This enables the driver for the Spreadtrum's serial. - -config SERIAL_SPRD_CONSOLE - bool "Spreadtrum UART console support" - depends on SERIAL_SPRD=y - select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON - help - Support for early debug console using Spreadtrum's serial. This enables - the console before standard serial driver is probed. This is enabled - with "earlycon" on the kernel command line. The console is - enabled when early_param is processed. - -config SERIAL_STM32 - tristate "STMicroelectronics STM32 serial port support" - select SERIAL_CORE - depends on HAS_DMA - depends on ARM || COMPILE_TEST - help - This driver is for the on-chip Serial Controller on - STMicroelectronics STM32 MCUs. - USART supports Rx & Tx functionality. - It support all industry standard baud rates. - - If unsure, say N. - -config SERIAL_STM32_CONSOLE - bool "Support for console on STM32" - depends on SERIAL_STM32=y - select SERIAL_CORE_CONSOLE - -config SERIAL_MVEBU_UART - bool "Marvell EBU serial port support" - depends on ARCH_MVEBU || COMPILE_TEST - select SERIAL_CORE - help - This driver is for Marvell EBU SoC's UART. If you have a machine - based on the Armada-3700 SoC and wish to use the on-board serial - port, - say 'Y' here. - Otherwise, say 'N'. - -config SERIAL_MVEBU_CONSOLE - bool "Console on Marvell EBU serial port" - depends on SERIAL_MVEBU_UART - select SERIAL_CORE_CONSOLE - select SERIAL_EARLYCON - default y - help - Say 'Y' here if you wish to use Armada-3700 UART as the system console. - (the system console is the device which receives all kernel messages - and warnings and which allows logins in single user mode) - Otherwise, say 'N'. - -endmenu - -config SERIAL_MCTRL_GPIO - tristate - -endif # TTY diff --git a/src/linux/drivers/tty/serial/Makefile b/src/linux/drivers/tty/serial/Makefile deleted file mode 100644 index 1278d37..0000000 --- a/src/linux/drivers/tty/serial/Makefile +++ /dev/null @@ -1,98 +0,0 @@ -# -# Makefile for the kernel serial device drivers. -# - -obj-$(CONFIG_SERIAL_CORE) += serial_core.o -obj-$(CONFIG_SERIAL_21285) += 21285.o - -obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o -obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o - -# These Sparc drivers have to appear before others such as 8250 -# which share ttySx minor node space. Otherwise console device -# names change and other unplesantries. -obj-$(CONFIG_SERIAL_SUNCORE) += suncore.o -obj-$(CONFIG_SERIAL_SUNHV) += sunhv.o -obj-$(CONFIG_SERIAL_SUNZILOG) += sunzilog.o -obj-$(CONFIG_SERIAL_SUNSU) += sunsu.o -obj-$(CONFIG_SERIAL_SUNSAB) += sunsab.o - -# Now bring in any enabled 8250/16450/16550 type drivers. -obj-$(CONFIG_SERIAL_8250) += 8250/ - -obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o -obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o -obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o -obj-$(CONFIG_SERIAL_PXA) += pxa.o -obj-$(CONFIG_SERIAL_PNX8XXX) += pnx8xxx_uart.o -obj-$(CONFIG_SERIAL_SA1100) += sa1100.o -obj-$(CONFIG_SERIAL_BCM63XX) += bcm63xx_uart.o -obj-$(CONFIG_SERIAL_BFIN) += bfin_uart.o -obj-$(CONFIG_SERIAL_BFIN_SPORT) += bfin_sport_uart.o -obj-$(CONFIG_SERIAL_SAMSUNG) += samsung.o -obj-$(CONFIG_SERIAL_MAX3100) += max3100.o -obj-$(CONFIG_SERIAL_MAX310X) += max310x.o -obj-$(CONFIG_SERIAL_IP22_ZILOG) += ip22zilog.o -obj-$(CONFIG_SERIAL_MUX) += mux.o -obj-$(CONFIG_SERIAL_MCF) += mcf.o -obj-$(CONFIG_SERIAL_PMACZILOG) += pmac_zilog.o -obj-$(CONFIG_SERIAL_HS_LPC32XX) += lpc32xx_hs.o -obj-$(CONFIG_SERIAL_DZ) += dz.o -obj-$(CONFIG_SERIAL_ZS) += zs.o -obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o -obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o -obj-$(CONFIG_SERIAL_CPM) += cpm_uart/ -obj-$(CONFIG_SERIAL_IMX) += imx.o -obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o -obj-$(CONFIG_SERIAL_ICOM) += icom.o -obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o -obj-$(CONFIG_SERIAL_MPSC) += mpsc.o -obj-$(CONFIG_SERIAL_MESON) += meson_uart.o -obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o -obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o -obj-$(CONFIG_SERIAL_ETRAXFS) += etraxfs-uart.o -obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o -obj-$(CONFIG_SERIAL_SC16IS7XX_CORE) += sc16is7xx.o -obj-$(CONFIG_SERIAL_JSM) += jsm/ -obj-$(CONFIG_SERIAL_TXX9) += serial_txx9.o -obj-$(CONFIG_SERIAL_VR41XX) += vr41xx_siu.o -obj-$(CONFIG_SERIAL_SGI_IOC4) += ioc4_serial.o -obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o -obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o -obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o -obj-$(CONFIG_SERIAL_MSM) += msm_serial.o -obj-$(CONFIG_SERIAL_NETX) += netx-serial.o -obj-$(CONFIG_SERIAL_KGDB_NMI) += kgdb_nmi.o -obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o -obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o -obj-$(CONFIG_SERIAL_ALTERA_UART) += altera_uart.o -obj-$(CONFIG_SERIAL_ST_ASC) += st-asc.o -obj-$(CONFIG_SERIAL_TILEGX) += tilegx.o -obj-$(CONFIG_KGDB_SERIAL_CONSOLE) += kgdboc.o -obj-$(CONFIG_SERIAL_QE) += ucc_uart.o -obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o -obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o -obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o -obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o -obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o -obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o -obj-$(CONFIG_SERIAL_MXS_AUART) += mxs-auart.o -obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o -obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o -obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o -obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o -obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o -obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o -obj-$(CONFIG_SERIAL_ARC) += arc_uart.o -obj-$(CONFIG_SERIAL_RP2) += rp2.o -obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o -obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR) += digicolor-usart.o -obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o -obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o -obj-$(CONFIG_SERIAL_STM32) += stm32-usart.o -obj-$(CONFIG_SERIAL_MVEBU_UART) += mvebu-uart.o -obj-$(CONFIG_SERIAL_PIC32) += pic32_uart.o -obj-$(CONFIG_SERIAL_MPS2_UART) += mps2-uart.o - -# GPIOLIB helpers for modem control lines -obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o diff --git a/src/linux/drivers/tty/tty_buffer.c b/src/linux/drivers/tty/tty_buffer.c deleted file mode 100644 index aa80dc9..0000000 --- a/src/linux/drivers/tty/tty_buffer.c +++ /dev/null @@ -1,594 +0,0 @@ -/* - * Tty buffer allocation management - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#define MIN_TTYB_SIZE 256 -#define TTYB_ALIGN_MASK 255 - -/* - * Byte threshold to limit memory consumption for flip buffers. - * The actual memory limit is > 2x this amount. - */ -#define TTYB_DEFAULT_MEM_LIMIT 65536 - -/* - * We default to dicing tty buffer allocations to this many characters - * in order to avoid multiple page allocations. We know the size of - * tty_buffer itself but it must also be taken into account that the - * the buffer is 256 byte aligned. See tty_buffer_find for the allocation - * logic this must match - */ - -#define TTY_BUFFER_PAGE (((PAGE_SIZE - sizeof(struct tty_buffer)) / 2) & ~0xFF) - -/** - * tty_buffer_lock_exclusive - gain exclusive access to buffer - * tty_buffer_unlock_exclusive - release exclusive access - * - * @port - tty_port owning the flip buffer - * - * Guarantees safe use of the line discipline's receive_buf() method by - * excluding the buffer work and any pending flush from using the flip - * buffer. Data can continue to be added concurrently to the flip buffer - * from the driver side. - * - * On release, the buffer work is restarted if there is data in the - * flip buffer - */ - -void tty_buffer_lock_exclusive(struct tty_port *port) -{ - struct tty_bufhead *buf = &port->buf; - - atomic_inc(&buf->priority); - mutex_lock(&buf->lock); -} -EXPORT_SYMBOL_GPL(tty_buffer_lock_exclusive); - -void tty_buffer_unlock_exclusive(struct tty_port *port) -{ - struct tty_bufhead *buf = &port->buf; - int restart; - - restart = buf->head->commit != buf->head->read; - - atomic_dec(&buf->priority); - mutex_unlock(&buf->lock); - if (restart) - queue_work(system_unbound_wq, &buf->work); -} -EXPORT_SYMBOL_GPL(tty_buffer_unlock_exclusive); - -/** - * tty_buffer_space_avail - return unused buffer space - * @port - tty_port owning the flip buffer - * - * Returns the # of bytes which can be written by the driver without - * reaching the buffer limit. - * - * Note: this does not guarantee that memory is available to write - * the returned # of bytes (use tty_prepare_flip_string_xxx() to - * pre-allocate if memory guarantee is required). - */ - -int tty_buffer_space_avail(struct tty_port *port) -{ - int space = port->buf.mem_limit - atomic_read(&port->buf.mem_used); - return max(space, 0); -} -EXPORT_SYMBOL_GPL(tty_buffer_space_avail); - -static void tty_buffer_reset(struct tty_buffer *p, size_t size) -{ - p->used = 0; - p->size = size; - p->next = NULL; - p->commit = 0; - p->read = 0; - p->flags = 0; -} - -/** - * tty_buffer_free_all - free buffers used by a tty - * @tty: tty to free from - * - * Remove all the buffers pending on a tty whether queued with data - * or in the free ring. Must be called when the tty is no longer in use - */ - -void tty_buffer_free_all(struct tty_port *port) -{ - struct tty_bufhead *buf = &port->buf; - struct tty_buffer *p, *next; - struct llist_node *llist; - - while ((p = buf->head) != NULL) { - buf->head = p->next; - if (p->size > 0) - kfree(p); - } - llist = llist_del_all(&buf->free); - llist_for_each_entry_safe(p, next, llist, free) - kfree(p); - - tty_buffer_reset(&buf->sentinel, 0); - buf->head = &buf->sentinel; - buf->tail = &buf->sentinel; - - atomic_set(&buf->mem_used, 0); -} - -/** - * tty_buffer_alloc - allocate a tty buffer - * @tty: tty device - * @size: desired size (characters) - * - * Allocate a new tty buffer to hold the desired number of characters. - * We round our buffers off in 256 character chunks to get better - * allocation behaviour. - * Return NULL if out of memory or the allocation would exceed the - * per device queue - */ - -static struct tty_buffer *tty_buffer_alloc(struct tty_port *port, size_t size) -{ - struct llist_node *free; - struct tty_buffer *p; - - /* Round the buffer size out */ - size = __ALIGN_MASK(size, TTYB_ALIGN_MASK); - - if (size <= MIN_TTYB_SIZE) { - free = llist_del_first(&port->buf.free); - if (free) { - p = llist_entry(free, struct tty_buffer, free); - goto found; - } - } - - /* Should possibly check if this fails for the largest buffer we - have queued and recycle that ? */ - if (atomic_read(&port->buf.mem_used) > port->buf.mem_limit) - return NULL; - p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC); - if (p == NULL) - return NULL; - -found: - tty_buffer_reset(p, size); - atomic_add(size, &port->buf.mem_used); - return p; -} - -/** - * tty_buffer_free - free a tty buffer - * @tty: tty owning the buffer - * @b: the buffer to free - * - * Free a tty buffer, or add it to the free list according to our - * internal strategy - */ - -static void tty_buffer_free(struct tty_port *port, struct tty_buffer *b) -{ - struct tty_bufhead *buf = &port->buf; - - /* Dumb strategy for now - should keep some stats */ - WARN_ON(atomic_sub_return(b->size, &buf->mem_used) < 0); - - if (b->size > MIN_TTYB_SIZE) - kfree(b); - else if (b->size > 0) - llist_add(&b->free, &buf->free); -} - -/** - * tty_buffer_flush - flush full tty buffers - * @tty: tty to flush - * @ld: optional ldisc ptr (must be referenced) - * - * flush all the buffers containing receive data. If ld != NULL, - * flush the ldisc input buffer. - * - * Locking: takes buffer lock to ensure single-threaded flip buffer - * 'consumer' - */ - -void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld) -{ - struct tty_port *port = tty->port; - struct tty_bufhead *buf = &port->buf; - struct tty_buffer *next; - - atomic_inc(&buf->priority); - - mutex_lock(&buf->lock); - /* paired w/ release in __tty_buffer_request_room; ensures there are - * no pending memory accesses to the freed buffer - */ - while ((next = smp_load_acquire(&buf->head->next)) != NULL) { - tty_buffer_free(port, buf->head); - buf->head = next; - } - buf->head->read = buf->head->commit; - - if (ld && ld->ops->flush_buffer) - ld->ops->flush_buffer(tty); - - atomic_dec(&buf->priority); - mutex_unlock(&buf->lock); -} - -/** - * tty_buffer_request_room - grow tty buffer if needed - * @tty: tty structure - * @size: size desired - * @flags: buffer flags if new buffer allocated (default = 0) - * - * Make at least size bytes of linear space available for the tty - * buffer. If we fail return the size we managed to find. - * - * Will change over to a new buffer if the current buffer is encoded as - * TTY_NORMAL (so has no flags buffer) and the new buffer requires - * a flags buffer. - */ -static int __tty_buffer_request_room(struct tty_port *port, size_t size, - int flags) -{ - struct tty_bufhead *buf = &port->buf; - struct tty_buffer *b, *n; - int left, change; - - b = buf->tail; - if (b->flags & TTYB_NORMAL) - left = 2 * b->size - b->used; - else - left = b->size - b->used; - - change = (b->flags & TTYB_NORMAL) && (~flags & TTYB_NORMAL); - if (change || left < size) { - /* This is the slow path - looking for new buffers to use */ - n = tty_buffer_alloc(port, size); - if (n != NULL) { - n->flags = flags; - buf->tail = n; - /* paired w/ acquire in flush_to_ldisc(); ensures - * flush_to_ldisc() sees buffer data. - */ - smp_store_release(&b->commit, b->used); - /* paired w/ acquire in flush_to_ldisc(); ensures the - * latest commit value can be read before the head is - * advanced to the next buffer - */ - smp_store_release(&b->next, n); - } else if (change) - size = 0; - else - size = left; - } - return size; -} - -int tty_buffer_request_room(struct tty_port *port, size_t size) -{ - return __tty_buffer_request_room(port, size, 0); -} -EXPORT_SYMBOL_GPL(tty_buffer_request_room); - -/** - * tty_insert_flip_string_fixed_flag - Add characters to the tty buffer - * @port: tty port - * @chars: characters - * @flag: flag value for each character - * @size: size - * - * Queue a series of bytes to the tty buffering. All the characters - * passed are marked with the supplied flag. Returns the number added. - */ - -int tty_insert_flip_string_fixed_flag(struct tty_port *port, - const unsigned char *chars, char flag, size_t size) -{ - int copied = 0; - do { - int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); - int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0; - int space = __tty_buffer_request_room(port, goal, flags); - struct tty_buffer *tb = port->buf.tail; - if (unlikely(space == 0)) - break; - memcpy(char_buf_ptr(tb, tb->used), chars, space); - if (~tb->flags & TTYB_NORMAL) - memset(flag_buf_ptr(tb, tb->used), flag, space); - tb->used += space; - copied += space; - chars += space; - /* There is a small chance that we need to split the data over - several buffers. If this is the case we must loop */ - } while (unlikely(size > copied)); - return copied; -} -EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag); - -/** - * tty_insert_flip_string_flags - Add characters to the tty buffer - * @port: tty port - * @chars: characters - * @flags: flag bytes - * @size: size - * - * Queue a series of bytes to the tty buffering. For each character - * the flags array indicates the status of the character. Returns the - * number added. - */ - -int tty_insert_flip_string_flags(struct tty_port *port, - const unsigned char *chars, const char *flags, size_t size) -{ - int copied = 0; - do { - int goal = min_t(size_t, size - copied, TTY_BUFFER_PAGE); - int space = tty_buffer_request_room(port, goal); - struct tty_buffer *tb = port->buf.tail; - if (unlikely(space == 0)) - break; - memcpy(char_buf_ptr(tb, tb->used), chars, space); - memcpy(flag_buf_ptr(tb, tb->used), flags, space); - tb->used += space; - copied += space; - chars += space; - flags += space; - /* There is a small chance that we need to split the data over - several buffers. If this is the case we must loop */ - } while (unlikely(size > copied)); - return copied; -} -EXPORT_SYMBOL(tty_insert_flip_string_flags); - -/** - * tty_schedule_flip - push characters to ldisc - * @port: tty port to push from - * - * Takes any pending buffers and transfers their ownership to the - * ldisc side of the queue. It then schedules those characters for - * processing by the line discipline. - */ - -void tty_schedule_flip(struct tty_port *port) -{ - struct tty_bufhead *buf = &port->buf; - - /* paired w/ acquire in flush_to_ldisc(); ensures - * flush_to_ldisc() sees buffer data. - */ - smp_store_release(&buf->tail->commit, buf->tail->used); - queue_work(system_unbound_wq, &buf->work); -} -EXPORT_SYMBOL(tty_schedule_flip); - -/** - * tty_prepare_flip_string - make room for characters - * @port: tty port - * @chars: return pointer for character write area - * @size: desired size - * - * Prepare a block of space in the buffer for data. Returns the length - * available and buffer pointer to the space which is now allocated and - * accounted for as ready for normal characters. This is used for drivers - * that need their own block copy routines into the buffer. There is no - * guarantee the buffer is a DMA target! - */ - -int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars, - size_t size) -{ - int space = __tty_buffer_request_room(port, size, TTYB_NORMAL); - if (likely(space)) { - struct tty_buffer *tb = port->buf.tail; - *chars = char_buf_ptr(tb, tb->used); - if (~tb->flags & TTYB_NORMAL) - memset(flag_buf_ptr(tb, tb->used), TTY_NORMAL, space); - tb->used += space; - } - return space; -} -EXPORT_SYMBOL_GPL(tty_prepare_flip_string); - -/** - * tty_ldisc_receive_buf - forward data to line discipline - * @ld: line discipline to process input - * @p: char buffer - * @f: TTY_* flags buffer - * @count: number of bytes to process - * - * Callers other than flush_to_ldisc() need to exclude the kworker - * from concurrent use of the line discipline, see paste_selection(). - * - * Returns the number of bytes not processed - */ -int tty_ldisc_receive_buf(struct tty_ldisc *ld, unsigned char *p, - char *f, int count) -{ - if (ld->ops->receive_buf2) - count = ld->ops->receive_buf2(ld->tty, p, f, count); - else { - count = min_t(int, count, ld->tty->receive_room); - if (count && ld->ops->receive_buf) - ld->ops->receive_buf(ld->tty, p, f, count); - } - return count; -} -EXPORT_SYMBOL_GPL(tty_ldisc_receive_buf); - -static int -receive_buf(struct tty_ldisc *ld, struct tty_buffer *head, int count) -{ - unsigned char *p = char_buf_ptr(head, head->read); - char *f = NULL; - - if (~head->flags & TTYB_NORMAL) - f = flag_buf_ptr(head, head->read); - - return tty_ldisc_receive_buf(ld, p, f, count); -} - -/** - * flush_to_ldisc - * @work: tty structure passed from work queue. - * - * This routine is called out of the software interrupt to flush data - * from the buffer chain to the line discipline. - * - * The receive_buf method is single threaded for each tty instance. - * - * Locking: takes buffer lock to ensure single-threaded flip buffer - * 'consumer' - */ - -static void flush_to_ldisc(struct work_struct *work) -{ - struct tty_port *port = container_of(work, struct tty_port, buf.work); - struct tty_bufhead *buf = &port->buf; - struct tty_struct *tty; - struct tty_ldisc *disc; - - tty = READ_ONCE(port->itty); - if (tty == NULL) - return; - - disc = tty_ldisc_ref(tty); - if (disc == NULL) - return; - - mutex_lock(&buf->lock); - - while (1) { - struct tty_buffer *head = buf->head; - struct tty_buffer *next; - int count; - - /* Ldisc or user is trying to gain exclusive access */ - if (atomic_read(&buf->priority)) - break; - - /* paired w/ release in __tty_buffer_request_room(); - * ensures commit value read is not stale if the head - * is advancing to the next buffer - */ - next = smp_load_acquire(&head->next); - /* paired w/ release in __tty_buffer_request_room() or in - * tty_buffer_flush(); ensures we see the committed buffer data - */ - count = smp_load_acquire(&head->commit) - head->read; - if (!count) { - if (next == NULL) - break; - buf->head = next; - tty_buffer_free(port, head); - continue; - } - - count = receive_buf(disc, head, count); - if (!count) - break; - head->read += count; - } - - mutex_unlock(&buf->lock); - - tty_ldisc_deref(disc); -} - -/** - * tty_flip_buffer_push - terminal - * @port: tty port to push - * - * Queue a push of the terminal flip buffers to the line discipline. - * Can be called from IRQ/atomic context. - * - * In the event of the queue being busy for flipping the work will be - * held off and retried later. - */ - -void tty_flip_buffer_push(struct tty_port *port) -{ - tty_schedule_flip(port); -} -EXPORT_SYMBOL(tty_flip_buffer_push); - -/** - * tty_buffer_init - prepare a tty buffer structure - * @tty: tty to initialise - * - * Set up the initial state of the buffer management for a tty device. - * Must be called before the other tty buffer functions are used. - */ - -void tty_buffer_init(struct tty_port *port) -{ - struct tty_bufhead *buf = &port->buf; - - mutex_init(&buf->lock); - tty_buffer_reset(&buf->sentinel, 0); - buf->head = &buf->sentinel; - buf->tail = &buf->sentinel; - init_llist_head(&buf->free); - atomic_set(&buf->mem_used, 0); - atomic_set(&buf->priority, 0); - INIT_WORK(&buf->work, flush_to_ldisc); - buf->mem_limit = TTYB_DEFAULT_MEM_LIMIT; -} - -/** - * tty_buffer_set_limit - change the tty buffer memory limit - * @port: tty port to change - * - * Change the tty buffer memory limit. - * Must be called before the other tty buffer functions are used. - */ - -int tty_buffer_set_limit(struct tty_port *port, int limit) -{ - if (limit < MIN_TTYB_SIZE) - return -EINVAL; - port->buf.mem_limit = limit; - return 0; -} -EXPORT_SYMBOL_GPL(tty_buffer_set_limit); - -/* slave ptys can claim nested buffer lock when handling BRK and INTR */ -void tty_buffer_set_lock_subclass(struct tty_port *port) -{ - lockdep_set_subclass(&port->buf.lock, TTY_LOCK_SLAVE); -} - -bool tty_buffer_restart_work(struct tty_port *port) -{ - return queue_work(system_unbound_wq, &port->buf.work); -} - -bool tty_buffer_cancel_work(struct tty_port *port) -{ - return cancel_work_sync(&port->buf.work); -} - -void tty_buffer_flush_work(struct tty_port *port) -{ - flush_work(&port->buf.work); -} diff --git a/src/linux/drivers/tty/tty_io.c b/src/linux/drivers/tty/tty_io.c deleted file mode 100644 index 734a635..0000000 --- a/src/linux/drivers/tty/tty_io.c +++ /dev/null @@ -1,3695 +0,0 @@ -/* - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -/* - * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles - * or rs-channels. It also implements echoing, cooked mode etc. - * - * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0. - * - * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the - * tty_struct and tty_queue structures. Previously there was an array - * of 256 tty_struct's which was statically allocated, and the - * tty_queue structures were allocated at boot time. Both are now - * dynamically allocated only when the tty is open. - * - * Also restructured routines so that there is more of a separation - * between the high-level tty routines (tty_io.c and tty_ioctl.c) and - * the low-level tty routines (serial.c, pty.c, console.c). This - * makes for cleaner and more compact code. -TYT, 9/17/92 - * - * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines - * which can be dynamically activated and de-activated by the line - * discipline handling modules (like SLIP). - * - * NOTE: pay no attention to the line discipline code (yet); its - * interface is still subject to change in this version... - * -- TYT, 1/31/92 - * - * Added functionality to the OPOST tty handling. No delays, but all - * other bits should be there. - * -- Nick Holloway , 27th May 1993. - * - * Rewrote canonical mode and added more termios flags. - * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94 - * - * Reorganized FASYNC support so mouse code can share it. - * -- ctm@ardi.com, 9Sep95 - * - * New TIOCLINUX variants added. - * -- mj@k332.feld.cvut.cz, 19-Nov-95 - * - * Restrict vt switching via ioctl() - * -- grif@cs.ucr.edu, 5-Dec-95 - * - * Move console and virtual terminal code to more appropriate files, - * implement CONFIG_VT and generalize console device interface. - * -- Marko Kohtala , March 97 - * - * Rewrote tty_init_dev and tty_release_dev to eliminate races. - * -- Bill Hawes , June 97 - * - * Added devfs support. - * -- C. Scott Ananian , 13-Jan-1998 - * - * Added support for a Unix98-style ptmx device. - * -- C. Scott Ananian , 14-Jan-1998 - * - * Reduced memory usage for older ARM systems - * -- Russell King - * - * Move do_SAK() into process context. Less stack use in devfs functions. - * alloc_tty_struct() always uses kmalloc() - * -- Andrew Morton 17Mar01 - */ - -#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 -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include - -#undef TTY_DEBUG_HANGUP -#ifdef TTY_DEBUG_HANGUP -# define tty_debug_hangup(tty, f, args...) tty_debug(tty, f, ##args) -#else -# define tty_debug_hangup(tty, f, args...) do { } while (0) -#endif - -#define TTY_PARANOIA_CHECK 1 -#define CHECK_TTY_COUNT 1 - -struct ktermios tty_std_termios = { /* for the benefit of tty drivers */ - .c_iflag = ICRNL | IXON, - .c_oflag = OPOST | ONLCR, - .c_cflag = B38400 | CS8 | CREAD | HUPCL, - .c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | - ECHOCTL | ECHOKE | IEXTEN, - .c_cc = INIT_C_CC, - .c_ispeed = 38400, - .c_ospeed = 38400, - /* .c_line = N_TTY, */ -}; - -EXPORT_SYMBOL(tty_std_termios); - -/* This list gets poked at by procfs and various bits of boot up code. This - could do with some rationalisation such as pulling the tty proc function - into this file */ - -LIST_HEAD(tty_drivers); /* linked list of tty drivers */ - -/* Mutex to protect creating and releasing a tty */ -DEFINE_MUTEX(tty_mutex); - -static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *); -static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *); -ssize_t redirected_tty_write(struct file *, const char __user *, - size_t, loff_t *); -static unsigned int tty_poll(struct file *, poll_table *); -static int tty_open(struct inode *, struct file *); -long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -#ifdef CONFIG_COMPAT -static long tty_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg); -#else -#define tty_compat_ioctl NULL -#endif -static int __tty_fasync(int fd, struct file *filp, int on); -static int tty_fasync(int fd, struct file *filp, int on); -static void release_tty(struct tty_struct *tty, int idx); - -/** - * free_tty_struct - free a disused tty - * @tty: tty struct to free - * - * Free the write buffers, tty queue and tty memory itself. - * - * Locking: none. Must be called after tty is definitely unused - */ - -static void free_tty_struct(struct tty_struct *tty) -{ - tty_ldisc_deinit(tty); - put_device(tty->dev); - kfree(tty->write_buf); - tty->magic = 0xDEADDEAD; - kfree(tty); -} - -static inline struct tty_struct *file_tty(struct file *file) -{ - return ((struct tty_file_private *)file->private_data)->tty; -} - -int tty_alloc_file(struct file *file) -{ - struct tty_file_private *priv; - - priv = kmalloc(sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - file->private_data = priv; - - return 0; -} - -/* Associate a new file with the tty structure */ -void tty_add_file(struct tty_struct *tty, struct file *file) -{ - struct tty_file_private *priv = file->private_data; - - priv->tty = tty; - priv->file = file; - - spin_lock(&tty->files_lock); - list_add(&priv->list, &tty->tty_files); - spin_unlock(&tty->files_lock); -} - -/** - * tty_free_file - free file->private_data - * - * This shall be used only for fail path handling when tty_add_file was not - * called yet. - */ -void tty_free_file(struct file *file) -{ - struct tty_file_private *priv = file->private_data; - - file->private_data = NULL; - kfree(priv); -} - -/* Delete file from its tty */ -static void tty_del_file(struct file *file) -{ - struct tty_file_private *priv = file->private_data; - struct tty_struct *tty = priv->tty; - - spin_lock(&tty->files_lock); - list_del(&priv->list); - spin_unlock(&tty->files_lock); - tty_free_file(file); -} - -/** - * tty_name - return tty naming - * @tty: tty structure - * - * Convert a tty structure into a name. The name reflects the kernel - * naming policy and if udev is in use may not reflect user space - * - * Locking: none - */ - -const char *tty_name(const struct tty_struct *tty) -{ - if (!tty) /* Hmm. NULL pointer. That's fun. */ - return "NULL tty"; - return tty->name; -} - -EXPORT_SYMBOL(tty_name); - -const char *tty_driver_name(const struct tty_struct *tty) -{ - if (!tty || !tty->driver) - return ""; - return tty->driver->name; -} - -static int tty_paranoia_check(struct tty_struct *tty, struct inode *inode, - const char *routine) -{ -#ifdef TTY_PARANOIA_CHECK - if (!tty) { - pr_warn("(%d:%d): %s: NULL tty\n", - imajor(inode), iminor(inode), routine); - return 1; - } - if (tty->magic != TTY_MAGIC) { - pr_warn("(%d:%d): %s: bad magic number\n", - imajor(inode), iminor(inode), routine); - return 1; - } -#endif - return 0; -} - -/* Caller must hold tty_lock */ -static int check_tty_count(struct tty_struct *tty, const char *routine) -{ -#ifdef CHECK_TTY_COUNT - struct list_head *p; - int count = 0; - - spin_lock(&tty->files_lock); - list_for_each(p, &tty->tty_files) { - count++; - } - spin_unlock(&tty->files_lock); - if (tty->driver->type == TTY_DRIVER_TYPE_PTY && - tty->driver->subtype == PTY_TYPE_SLAVE && - tty->link && tty->link->count) - count++; - if (tty->count != count) { - tty_warn(tty, "%s: tty->count(%d) != #fd's(%d)\n", - routine, tty->count, count); - return count; - } -#endif - return 0; -} - -/** - * get_tty_driver - find device of a tty - * @dev_t: device identifier - * @index: returns the index of the tty - * - * This routine returns a tty driver structure, given a device number - * and also passes back the index number. - * - * Locking: caller must hold tty_mutex - */ - -static struct tty_driver *get_tty_driver(dev_t device, int *index) -{ - struct tty_driver *p; - - list_for_each_entry(p, &tty_drivers, tty_drivers) { - dev_t base = MKDEV(p->major, p->minor_start); - if (device < base || device >= base + p->num) - continue; - *index = device - base; - return tty_driver_kref_get(p); - } - return NULL; -} - -#ifdef CONFIG_CONSOLE_POLL - -/** - * tty_find_polling_driver - find device of a polled tty - * @name: name string to match - * @line: pointer to resulting tty line nr - * - * This routine returns a tty driver structure, given a name - * and the condition that the tty driver is capable of polled - * operation. - */ -struct tty_driver *tty_find_polling_driver(char *name, int *line) -{ - struct tty_driver *p, *res = NULL; - int tty_line = 0; - int len; - char *str, *stp; - - for (str = name; *str; str++) - if ((*str >= '0' && *str <= '9') || *str == ',') - break; - if (!*str) - return NULL; - - len = str - name; - tty_line = simple_strtoul(str, &str, 10); - - mutex_lock(&tty_mutex); - /* Search through the tty devices to look for a match */ - list_for_each_entry(p, &tty_drivers, tty_drivers) { - if (strncmp(name, p->name, len) != 0) - continue; - stp = str; - if (*stp == ',') - stp++; - if (*stp == '\0') - stp = NULL; - - if (tty_line >= 0 && tty_line < p->num && p->ops && - p->ops->poll_init && !p->ops->poll_init(p, tty_line, stp)) { - res = tty_driver_kref_get(p); - *line = tty_line; - break; - } - } - mutex_unlock(&tty_mutex); - - return res; -} -EXPORT_SYMBOL_GPL(tty_find_polling_driver); -#endif - -static int is_ignored(int sig) -{ - return (sigismember(¤t->blocked, sig) || - current->sighand->action[sig-1].sa.sa_handler == SIG_IGN); -} - -/** - * tty_check_change - check for POSIX terminal changes - * @tty: tty to check - * - * If we try to write to, or set the state of, a terminal and we're - * not in the foreground, send a SIGTTOU. If the signal is blocked or - * ignored, go ahead and perform the operation. (POSIX 7.2) - * - * Locking: ctrl_lock - */ - -int __tty_check_change(struct tty_struct *tty, int sig) -{ - unsigned long flags; - struct pid *pgrp, *tty_pgrp; - int ret = 0; - - if (current->signal->tty != tty) - return 0; - - rcu_read_lock(); - pgrp = task_pgrp(current); - - spin_lock_irqsave(&tty->ctrl_lock, flags); - tty_pgrp = tty->pgrp; - spin_unlock_irqrestore(&tty->ctrl_lock, flags); - - if (tty_pgrp && pgrp != tty->pgrp) { - if (is_ignored(sig)) { - if (sig == SIGTTIN) - ret = -EIO; - } else if (is_current_pgrp_orphaned()) - ret = -EIO; - else { - kill_pgrp(pgrp, sig, 1); - set_thread_flag(TIF_SIGPENDING); - ret = -ERESTARTSYS; - } - } - rcu_read_unlock(); - - if (!tty_pgrp) - tty_warn(tty, "sig=%d, tty->pgrp == NULL!\n", sig); - - return ret; -} - -int tty_check_change(struct tty_struct *tty) -{ - return __tty_check_change(tty, SIGTTOU); -} -EXPORT_SYMBOL(tty_check_change); - -static ssize_t hung_up_tty_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - return 0; -} - -static ssize_t hung_up_tty_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - return -EIO; -} - -/* No kernel lock held - none needed ;) */ -static unsigned int hung_up_tty_poll(struct file *filp, poll_table *wait) -{ - return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM; -} - -static long hung_up_tty_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return cmd == TIOCSPGRP ? -ENOTTY : -EIO; -} - -static long hung_up_tty_compat_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) -{ - return cmd == TIOCSPGRP ? -ENOTTY : -EIO; -} - -static int hung_up_tty_fasync(int fd, struct file *file, int on) -{ - return -ENOTTY; -} - -static const struct file_operations tty_fops = { - .llseek = no_llseek, - .read = tty_read, - .write = tty_write, - .poll = tty_poll, - .unlocked_ioctl = tty_ioctl, - .compat_ioctl = tty_compat_ioctl, - .open = tty_open, - .release = tty_release, - .fasync = tty_fasync, -}; - -static const struct file_operations console_fops = { - .llseek = no_llseek, - .read = tty_read, - .write = redirected_tty_write, - .poll = tty_poll, - .unlocked_ioctl = tty_ioctl, - .compat_ioctl = tty_compat_ioctl, - .open = tty_open, - .release = tty_release, - .fasync = tty_fasync, -}; - -static const struct file_operations hung_up_tty_fops = { - .llseek = no_llseek, - .read = hung_up_tty_read, - .write = hung_up_tty_write, - .poll = hung_up_tty_poll, - .unlocked_ioctl = hung_up_tty_ioctl, - .compat_ioctl = hung_up_tty_compat_ioctl, - .release = tty_release, - .fasync = hung_up_tty_fasync, -}; - -static DEFINE_SPINLOCK(redirect_lock); -static struct file *redirect; - - -void proc_clear_tty(struct task_struct *p) -{ - unsigned long flags; - struct tty_struct *tty; - spin_lock_irqsave(&p->sighand->siglock, flags); - tty = p->signal->tty; - p->signal->tty = NULL; - spin_unlock_irqrestore(&p->sighand->siglock, flags); - tty_kref_put(tty); -} - -/** - * proc_set_tty - set the controlling terminal - * - * Only callable by the session leader and only if it does not already have - * a controlling terminal. - * - * Caller must hold: tty_lock() - * a readlock on tasklist_lock - * sighand lock - */ -static void __proc_set_tty(struct tty_struct *tty) -{ - unsigned long flags; - - spin_lock_irqsave(&tty->ctrl_lock, flags); - /* - * The session and fg pgrp references will be non-NULL if - * tiocsctty() is stealing the controlling tty - */ - put_pid(tty->session); - put_pid(tty->pgrp); - tty->pgrp = get_pid(task_pgrp(current)); - spin_unlock_irqrestore(&tty->ctrl_lock, flags); - tty->session = get_pid(task_session(current)); - if (current->signal->tty) { - tty_debug(tty, "current tty %s not NULL!!\n", - current->signal->tty->name); - tty_kref_put(current->signal->tty); - } - put_pid(current->signal->tty_old_pgrp); - current->signal->tty = tty_kref_get(tty); - current->signal->tty_old_pgrp = NULL; -} - -static void proc_set_tty(struct tty_struct *tty) -{ - spin_lock_irq(¤t->sighand->siglock); - __proc_set_tty(tty); - spin_unlock_irq(¤t->sighand->siglock); -} - -struct tty_struct *get_current_tty(void) -{ - struct tty_struct *tty; - unsigned long flags; - - spin_lock_irqsave(¤t->sighand->siglock, flags); - tty = tty_kref_get(current->signal->tty); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); - return tty; -} -EXPORT_SYMBOL_GPL(get_current_tty); - -static void session_clear_tty(struct pid *session) -{ - struct task_struct *p; - do_each_pid_task(session, PIDTYPE_SID, p) { - proc_clear_tty(p); - } while_each_pid_task(session, PIDTYPE_SID, p); -} - -/** - * tty_wakeup - request more data - * @tty: terminal - * - * Internal and external helper for wakeups of tty. This function - * informs the line discipline if present that the driver is ready - * to receive more output data. - */ - -void tty_wakeup(struct tty_struct *tty) -{ - struct tty_ldisc *ld; - - if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) { - ld = tty_ldisc_ref(tty); - if (ld) { - if (ld->ops->write_wakeup) - ld->ops->write_wakeup(tty); - tty_ldisc_deref(ld); - } - } - wake_up_interruptible_poll(&tty->write_wait, POLLOUT); -} - -EXPORT_SYMBOL_GPL(tty_wakeup); - -/** - * tty_signal_session_leader - sends SIGHUP to session leader - * @tty controlling tty - * @exit_session if non-zero, signal all foreground group processes - * - * Send SIGHUP and SIGCONT to the session leader and its process group. - * Optionally, signal all processes in the foreground process group. - * - * Returns the number of processes in the session with this tty - * as their controlling terminal. This value is used to drop - * tty references for those processes. - */ -static int tty_signal_session_leader(struct tty_struct *tty, int exit_session) -{ - struct task_struct *p; - int refs = 0; - struct pid *tty_pgrp = NULL; - - read_lock(&tasklist_lock); - if (tty->session) { - do_each_pid_task(tty->session, PIDTYPE_SID, p) { - spin_lock_irq(&p->sighand->siglock); - if (p->signal->tty == tty) { - p->signal->tty = NULL; - /* We defer the dereferences outside fo - the tasklist lock */ - refs++; - } - if (!p->signal->leader) { - spin_unlock_irq(&p->sighand->siglock); - continue; - } - __group_send_sig_info(SIGHUP, SEND_SIG_PRIV, p); - __group_send_sig_info(SIGCONT, SEND_SIG_PRIV, p); - put_pid(p->signal->tty_old_pgrp); /* A noop */ - spin_lock(&tty->ctrl_lock); - tty_pgrp = get_pid(tty->pgrp); - if (tty->pgrp) - p->signal->tty_old_pgrp = get_pid(tty->pgrp); - spin_unlock(&tty->ctrl_lock); - spin_unlock_irq(&p->sighand->siglock); - } while_each_pid_task(tty->session, PIDTYPE_SID, p); - } - read_unlock(&tasklist_lock); - - if (tty_pgrp) { - if (exit_session) - kill_pgrp(tty_pgrp, SIGHUP, exit_session); - put_pid(tty_pgrp); - } - - return refs; -} - -/** - * __tty_hangup - actual handler for hangup events - * @work: tty device - * - * This can be called by a "kworker" kernel thread. That is process - * synchronous but doesn't hold any locks, so we need to make sure we - * have the appropriate locks for what we're doing. - * - * The hangup event clears any pending redirections onto the hung up - * device. It ensures future writes will error and it does the needed - * line discipline hangup and signal delivery. The tty object itself - * remains intact. - * - * Locking: - * BTM - * redirect lock for undoing redirection - * file list lock for manipulating list of ttys - * tty_ldiscs_lock from called functions - * termios_rwsem resetting termios data - * tasklist_lock to walk task list for hangup event - * ->siglock to protect ->signal/->sighand - */ -static void __tty_hangup(struct tty_struct *tty, int exit_session) -{ - struct file *cons_filp = NULL; - struct file *filp, *f = NULL; - struct tty_file_private *priv; - int closecount = 0, n; - int refs; - - if (!tty) - return; - - - spin_lock(&redirect_lock); - if (redirect && file_tty(redirect) == tty) { - f = redirect; - redirect = NULL; - } - spin_unlock(&redirect_lock); - - tty_lock(tty); - - if (test_bit(TTY_HUPPED, &tty->flags)) { - tty_unlock(tty); - return; - } - - /* inuse_filps is protected by the single tty lock, - this really needs to change if we want to flush the - workqueue with the lock held */ - check_tty_count(tty, "tty_hangup"); - - spin_lock(&tty->files_lock); - /* This breaks for file handles being sent over AF_UNIX sockets ? */ - list_for_each_entry(priv, &tty->tty_files, list) { - filp = priv->file; - if (filp->f_op->write == redirected_tty_write) - cons_filp = filp; - if (filp->f_op->write != tty_write) - continue; - closecount++; - __tty_fasync(-1, filp, 0); /* can't block */ - filp->f_op = &hung_up_tty_fops; - } - spin_unlock(&tty->files_lock); - - refs = tty_signal_session_leader(tty, exit_session); - /* Account for the p->signal references we killed */ - while (refs--) - tty_kref_put(tty); - - tty_ldisc_hangup(tty, cons_filp != NULL); - - spin_lock_irq(&tty->ctrl_lock); - clear_bit(TTY_THROTTLED, &tty->flags); - clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); - put_pid(tty->session); - put_pid(tty->pgrp); - tty->session = NULL; - tty->pgrp = NULL; - tty->ctrl_status = 0; - spin_unlock_irq(&tty->ctrl_lock); - - /* - * If one of the devices matches a console pointer, we - * cannot just call hangup() because that will cause - * tty->count and state->count to go out of sync. - * So we just call close() the right number of times. - */ - if (cons_filp) { - if (tty->ops->close) - for (n = 0; n < closecount; n++) - tty->ops->close(tty, cons_filp); - } else if (tty->ops->hangup) - tty->ops->hangup(tty); - /* - * We don't want to have driver/ldisc interactions beyond the ones - * we did here. The driver layer expects no calls after ->hangup() - * from the ldisc side, which is now guaranteed. - */ - set_bit(TTY_HUPPED, &tty->flags); - tty_unlock(tty); - - if (f) - fput(f); -} - -static void do_tty_hangup(struct work_struct *work) -{ - struct tty_struct *tty = - container_of(work, struct tty_struct, hangup_work); - - __tty_hangup(tty, 0); -} - -/** - * tty_hangup - trigger a hangup event - * @tty: tty to hangup - * - * A carrier loss (virtual or otherwise) has occurred on this like - * schedule a hangup sequence to run after this event. - */ - -void tty_hangup(struct tty_struct *tty) -{ - tty_debug_hangup(tty, "hangup\n"); - schedule_work(&tty->hangup_work); -} - -EXPORT_SYMBOL(tty_hangup); - -/** - * tty_vhangup - process vhangup - * @tty: tty to hangup - * - * The user has asked via system call for the terminal to be hung up. - * We do this synchronously so that when the syscall returns the process - * is complete. That guarantee is necessary for security reasons. - */ - -void tty_vhangup(struct tty_struct *tty) -{ - tty_debug_hangup(tty, "vhangup\n"); - __tty_hangup(tty, 0); -} - -EXPORT_SYMBOL(tty_vhangup); - - -/** - * tty_vhangup_self - process vhangup for own ctty - * - * Perform a vhangup on the current controlling tty - */ - -void tty_vhangup_self(void) -{ - struct tty_struct *tty; - - tty = get_current_tty(); - if (tty) { - tty_vhangup(tty); - tty_kref_put(tty); - } -} - -/** - * tty_vhangup_session - hangup session leader exit - * @tty: tty to hangup - * - * The session leader is exiting and hanging up its controlling terminal. - * Every process in the foreground process group is signalled SIGHUP. - * - * We do this synchronously so that when the syscall returns the process - * is complete. That guarantee is necessary for security reasons. - */ - -static void tty_vhangup_session(struct tty_struct *tty) -{ - tty_debug_hangup(tty, "session hangup\n"); - __tty_hangup(tty, 1); -} - -/** - * tty_hung_up_p - was tty hung up - * @filp: file pointer of tty - * - * Return true if the tty has been subject to a vhangup or a carrier - * loss - */ - -int tty_hung_up_p(struct file *filp) -{ - return (filp->f_op == &hung_up_tty_fops); -} - -EXPORT_SYMBOL(tty_hung_up_p); - -/** - * disassociate_ctty - disconnect controlling tty - * @on_exit: true if exiting so need to "hang up" the session - * - * This function is typically called only by the session leader, when - * it wants to disassociate itself from its controlling tty. - * - * It performs the following functions: - * (1) Sends a SIGHUP and SIGCONT to the foreground process group - * (2) Clears the tty from being controlling the session - * (3) Clears the controlling tty for all processes in the - * session group. - * - * The argument on_exit is set to 1 if called when a process is - * exiting; it is 0 if called by the ioctl TIOCNOTTY. - * - * Locking: - * BTM is taken for hysterical raisins, and held when - * called from no_tty(). - * tty_mutex is taken to protect tty - * ->siglock is taken to protect ->signal/->sighand - * tasklist_lock is taken to walk process list for sessions - * ->siglock is taken to protect ->signal/->sighand - */ - -void disassociate_ctty(int on_exit) -{ - struct tty_struct *tty; - - if (!current->signal->leader) - return; - - tty = get_current_tty(); - if (tty) { - if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY) { - tty_vhangup_session(tty); - } else { - struct pid *tty_pgrp = tty_get_pgrp(tty); - if (tty_pgrp) { - kill_pgrp(tty_pgrp, SIGHUP, on_exit); - if (!on_exit) - kill_pgrp(tty_pgrp, SIGCONT, on_exit); - put_pid(tty_pgrp); - } - } - tty_kref_put(tty); - - } else if (on_exit) { - struct pid *old_pgrp; - spin_lock_irq(¤t->sighand->siglock); - old_pgrp = current->signal->tty_old_pgrp; - current->signal->tty_old_pgrp = NULL; - spin_unlock_irq(¤t->sighand->siglock); - if (old_pgrp) { - kill_pgrp(old_pgrp, SIGHUP, on_exit); - kill_pgrp(old_pgrp, SIGCONT, on_exit); - put_pid(old_pgrp); - } - return; - } - - spin_lock_irq(¤t->sighand->siglock); - put_pid(current->signal->tty_old_pgrp); - current->signal->tty_old_pgrp = NULL; - - tty = tty_kref_get(current->signal->tty); - if (tty) { - unsigned long flags; - spin_lock_irqsave(&tty->ctrl_lock, flags); - put_pid(tty->session); - put_pid(tty->pgrp); - tty->session = NULL; - tty->pgrp = NULL; - spin_unlock_irqrestore(&tty->ctrl_lock, flags); - tty_kref_put(tty); - } else - tty_debug_hangup(tty, "no current tty\n"); - - spin_unlock_irq(¤t->sighand->siglock); - /* Now clear signal->tty under the lock */ - read_lock(&tasklist_lock); - session_clear_tty(task_session(current)); - read_unlock(&tasklist_lock); -} - -/** - * - * no_tty - Ensure the current process does not have a controlling tty - */ -void no_tty(void) -{ - /* FIXME: Review locking here. The tty_lock never covered any race - between a new association and proc_clear_tty but possible we need - to protect against this anyway */ - struct task_struct *tsk = current; - disassociate_ctty(0); - proc_clear_tty(tsk); -} - - -/** - * stop_tty - propagate flow control - * @tty: tty to stop - * - * Perform flow control to the driver. May be called - * on an already stopped device and will not re-call the driver - * method. - * - * This functionality is used by both the line disciplines for - * halting incoming flow and by the driver. It may therefore be - * called from any context, may be under the tty atomic_write_lock - * but not always. - * - * Locking: - * flow_lock - */ - -void __stop_tty(struct tty_struct *tty) -{ - if (tty->stopped) - return; - tty->stopped = 1; - if (tty->ops->stop) - tty->ops->stop(tty); -} - -void stop_tty(struct tty_struct *tty) -{ - unsigned long flags; - - spin_lock_irqsave(&tty->flow_lock, flags); - __stop_tty(tty); - spin_unlock_irqrestore(&tty->flow_lock, flags); -} -EXPORT_SYMBOL(stop_tty); - -/** - * start_tty - propagate flow control - * @tty: tty to start - * - * Start a tty that has been stopped if at all possible. If this - * tty was previous stopped and is now being started, the driver - * start method is invoked and the line discipline woken. - * - * Locking: - * flow_lock - */ - -void __start_tty(struct tty_struct *tty) -{ - if (!tty->stopped || tty->flow_stopped) - return; - tty->stopped = 0; - if (tty->ops->start) - tty->ops->start(tty); - tty_wakeup(tty); -} - -void start_tty(struct tty_struct *tty) -{ - unsigned long flags; - - spin_lock_irqsave(&tty->flow_lock, flags); - __start_tty(tty); - spin_unlock_irqrestore(&tty->flow_lock, flags); -} -EXPORT_SYMBOL(start_tty); - -static void tty_update_time(struct timespec *time) -{ - unsigned long sec = get_seconds(); - - /* - * We only care if the two values differ in anything other than the - * lower three bits (i.e every 8 seconds). If so, then we can update - * the time of the tty device, otherwise it could be construded as a - * security leak to let userspace know the exact timing of the tty. - */ - if ((sec ^ time->tv_sec) & ~7) - time->tv_sec = sec; -} - -/** - * tty_read - read method for tty device files - * @file: pointer to tty file - * @buf: user buffer - * @count: size of user buffer - * @ppos: unused - * - * Perform the read system call function on this terminal device. Checks - * for hung up devices before calling the line discipline method. - * - * Locking: - * Locks the line discipline internally while needed. Multiple - * read calls may be outstanding in parallel. - */ - -static ssize_t tty_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - int i; - struct inode *inode = file_inode(file); - struct tty_struct *tty = file_tty(file); - struct tty_ldisc *ld; - - if (tty_paranoia_check(tty, inode, "tty_read")) - return -EIO; - if (!tty || tty_io_error(tty)) - return -EIO; - - /* We want to wait for the line discipline to sort out in this - situation */ - ld = tty_ldisc_ref_wait(tty); - if (!ld) - return hung_up_tty_read(file, buf, count, ppos); - if (ld->ops->read) - i = ld->ops->read(tty, file, buf, count); - else - i = -EIO; - tty_ldisc_deref(ld); - - if (i > 0) - tty_update_time(&inode->i_atime); - - return i; -} - -static void tty_write_unlock(struct tty_struct *tty) -{ - mutex_unlock(&tty->atomic_write_lock); - wake_up_interruptible_poll(&tty->write_wait, POLLOUT); -} - -static int tty_write_lock(struct tty_struct *tty, int ndelay) -{ - if (!mutex_trylock(&tty->atomic_write_lock)) { - if (ndelay) - return -EAGAIN; - if (mutex_lock_interruptible(&tty->atomic_write_lock)) - return -ERESTARTSYS; - } - return 0; -} - -/* - * Split writes up in sane blocksizes to avoid - * denial-of-service type attacks - */ -static inline ssize_t do_tty_write( - ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t), - struct tty_struct *tty, - struct file *file, - const char __user *buf, - size_t count) -{ - ssize_t ret, written = 0; - unsigned int chunk; - - ret = tty_write_lock(tty, file->f_flags & O_NDELAY); - if (ret < 0) - return ret; - - /* - * We chunk up writes into a temporary buffer. This - * simplifies low-level drivers immensely, since they - * don't have locking issues and user mode accesses. - * - * But if TTY_NO_WRITE_SPLIT is set, we should use a - * big chunk-size.. - * - * The default chunk-size is 2kB, because the NTTY - * layer has problems with bigger chunks. It will - * claim to be able to handle more characters than - * it actually does. - * - * FIXME: This can probably go away now except that 64K chunks - * are too likely to fail unless switched to vmalloc... - */ - chunk = 2048; - if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags)) - chunk = 65536; - if (count < chunk) - chunk = count; - - /* write_buf/write_cnt is protected by the atomic_write_lock mutex */ - if (tty->write_cnt < chunk) { - unsigned char *buf_chunk; - - if (chunk < 1024) - chunk = 1024; - - buf_chunk = kmalloc(chunk, GFP_KERNEL); - if (!buf_chunk) { - ret = -ENOMEM; - goto out; - } - kfree(tty->write_buf); - tty->write_cnt = chunk; - tty->write_buf = buf_chunk; - } - - /* Do the write .. */ - for (;;) { - size_t size = count; - if (size > chunk) - size = chunk; - ret = -EFAULT; - if (copy_from_user(tty->write_buf, buf, size)) - break; - ret = write(tty, file, tty->write_buf, size); - if (ret <= 0) - break; - written += ret; - buf += ret; - count -= ret; - if (!count) - break; - ret = -ERESTARTSYS; - if (signal_pending(current)) - break; - cond_resched(); - } - if (written) { - tty_update_time(&file_inode(file)->i_mtime); - ret = written; - } -out: - tty_write_unlock(tty); - return ret; -} - -/** - * tty_write_message - write a message to a certain tty, not just the console. - * @tty: the destination tty_struct - * @msg: the message to write - * - * This is used for messages that need to be redirected to a specific tty. - * We don't put it into the syslog queue right now maybe in the future if - * really needed. - * - * We must still hold the BTM and test the CLOSING flag for the moment. - */ - -void tty_write_message(struct tty_struct *tty, char *msg) -{ - if (tty) { - mutex_lock(&tty->atomic_write_lock); - tty_lock(tty); - if (tty->ops->write && tty->count > 0) - tty->ops->write(tty, msg, strlen(msg)); - tty_unlock(tty); - tty_write_unlock(tty); - } - return; -} - - -/** - * tty_write - write method for tty device file - * @file: tty file pointer - * @buf: user data to write - * @count: bytes to write - * @ppos: unused - * - * Write data to a tty device via the line discipline. - * - * Locking: - * Locks the line discipline as required - * Writes to the tty driver are serialized by the atomic_write_lock - * and are then processed in chunks to the device. The line discipline - * write method will not be invoked in parallel for each device. - */ - -static ssize_t tty_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct tty_struct *tty = file_tty(file); - struct tty_ldisc *ld; - ssize_t ret; - - if (tty_paranoia_check(tty, file_inode(file), "tty_write")) - return -EIO; - if (!tty || !tty->ops->write || tty_io_error(tty)) - return -EIO; - /* Short term debug to catch buggy drivers */ - if (tty->ops->write_room == NULL) - tty_err(tty, "missing write_room method\n"); - ld = tty_ldisc_ref_wait(tty); - if (!ld) - return hung_up_tty_write(file, buf, count, ppos); - if (!ld->ops->write) - ret = -EIO; - else - ret = do_tty_write(ld->ops->write, tty, file, buf, count); - tty_ldisc_deref(ld); - return ret; -} - -ssize_t redirected_tty_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - struct file *p = NULL; - - spin_lock(&redirect_lock); - if (redirect) - p = get_file(redirect); - spin_unlock(&redirect_lock); - - if (p) { - ssize_t res; - res = vfs_write(p, buf, count, &p->f_pos); - fput(p); - return res; - } - return tty_write(file, buf, count, ppos); -} - -/** - * tty_send_xchar - send priority character - * - * Send a high priority character to the tty even if stopped - * - * Locking: none for xchar method, write ordering for write method. - */ - -int tty_send_xchar(struct tty_struct *tty, char ch) -{ - int was_stopped = tty->stopped; - - if (tty->ops->send_xchar) { - down_read(&tty->termios_rwsem); - tty->ops->send_xchar(tty, ch); - up_read(&tty->termios_rwsem); - return 0; - } - - if (tty_write_lock(tty, 0) < 0) - return -ERESTARTSYS; - - down_read(&tty->termios_rwsem); - if (was_stopped) - start_tty(tty); - tty->ops->write(tty, &ch, 1); - if (was_stopped) - stop_tty(tty); - up_read(&tty->termios_rwsem); - tty_write_unlock(tty); - return 0; -} - -static char ptychar[] = "pqrstuvwxyzabcde"; - -/** - * pty_line_name - generate name for a pty - * @driver: the tty driver in use - * @index: the minor number - * @p: output buffer of at least 6 bytes - * - * Generate a name from a driver reference and write it to the output - * buffer. - * - * Locking: None - */ -static void pty_line_name(struct tty_driver *driver, int index, char *p) -{ - int i = index + driver->name_base; - /* ->name is initialized to "ttyp", but "tty" is expected */ - sprintf(p, "%s%c%x", - driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name, - ptychar[i >> 4 & 0xf], i & 0xf); -} - -/** - * tty_line_name - generate name for a tty - * @driver: the tty driver in use - * @index: the minor number - * @p: output buffer of at least 7 bytes - * - * Generate a name from a driver reference and write it to the output - * buffer. - * - * Locking: None - */ -static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p) -{ - if (driver->flags & TTY_DRIVER_UNNUMBERED_NODE) - return sprintf(p, "%s", driver->name); - else - return sprintf(p, "%s%d", driver->name, - index + driver->name_base); -} - -/** - * tty_driver_lookup_tty() - find an existing tty, if any - * @driver: the driver for the tty - * @idx: the minor number - * - * Return the tty, if found. If not found, return NULL or ERR_PTR() if the - * driver lookup() method returns an error. - * - * Locking: tty_mutex must be held. If the tty is found, bump the tty kref. - */ -static struct tty_struct *tty_driver_lookup_tty(struct tty_driver *driver, - struct file *file, int idx) -{ - struct tty_struct *tty; - - if (driver->ops->lookup) - tty = driver->ops->lookup(driver, file, idx); - else - tty = driver->ttys[idx]; - - if (!IS_ERR(tty)) - tty_kref_get(tty); - return tty; -} - -/** - * tty_init_termios - helper for termios setup - * @tty: the tty to set up - * - * Initialise the termios structures for this tty. Thus runs under - * the tty_mutex currently so we can be relaxed about ordering. - */ - -void tty_init_termios(struct tty_struct *tty) -{ - struct ktermios *tp; - int idx = tty->index; - - if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) - tty->termios = tty->driver->init_termios; - else { - /* Check for lazy saved data */ - tp = tty->driver->termios[idx]; - if (tp != NULL) { - tty->termios = *tp; - tty->termios.c_line = tty->driver->init_termios.c_line; - } else - tty->termios = tty->driver->init_termios; - } - /* Compatibility until drivers always set this */ - tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios); - tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios); -} -EXPORT_SYMBOL_GPL(tty_init_termios); - -int tty_standard_install(struct tty_driver *driver, struct tty_struct *tty) -{ - tty_init_termios(tty); - tty_driver_kref_get(driver); - tty->count++; - driver->ttys[tty->index] = tty; - return 0; -} -EXPORT_SYMBOL_GPL(tty_standard_install); - -/** - * tty_driver_install_tty() - install a tty entry in the driver - * @driver: the driver for the tty - * @tty: the tty - * - * Install a tty object into the driver tables. The tty->index field - * will be set by the time this is called. This method is responsible - * for ensuring any need additional structures are allocated and - * configured. - * - * Locking: tty_mutex for now - */ -static int tty_driver_install_tty(struct tty_driver *driver, - struct tty_struct *tty) -{ - return driver->ops->install ? driver->ops->install(driver, tty) : - tty_standard_install(driver, tty); -} - -/** - * tty_driver_remove_tty() - remove a tty from the driver tables - * @driver: the driver for the tty - * @idx: the minor number - * - * Remvoe a tty object from the driver tables. The tty->index field - * will be set by the time this is called. - * - * Locking: tty_mutex for now - */ -static void tty_driver_remove_tty(struct tty_driver *driver, struct tty_struct *tty) -{ - if (driver->ops->remove) - driver->ops->remove(driver, tty); - else - driver->ttys[tty->index] = NULL; -} - -/* - * tty_reopen() - fast re-open of an open tty - * @tty - the tty to open - * - * Return 0 on success, -errno on error. - * Re-opens on master ptys are not allowed and return -EIO. - * - * Locking: Caller must hold tty_lock - */ -static int tty_reopen(struct tty_struct *tty) -{ - struct tty_driver *driver = tty->driver; - - if (driver->type == TTY_DRIVER_TYPE_PTY && - driver->subtype == PTY_TYPE_MASTER) - return -EIO; - - if (!tty->count) - return -EAGAIN; - - if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN)) - return -EBUSY; - - tty->count++; - - if (!tty->ldisc) - return tty_ldisc_reinit(tty, tty->termios.c_line); - - return 0; -} - -/** - * tty_init_dev - initialise a tty device - * @driver: tty driver we are opening a device on - * @idx: device index - * @ret_tty: returned tty structure - * - * Prepare a tty device. This may not be a "new" clean device but - * could also be an active device. The pty drivers require special - * handling because of this. - * - * Locking: - * The function is called under the tty_mutex, which - * protects us from the tty struct or driver itself going away. - * - * On exit the tty device has the line discipline attached and - * a reference count of 1. If a pair was created for pty/tty use - * and the other was a pty master then it too has a reference count of 1. - * - * WSH 06/09/97: Rewritten to remove races and properly clean up after a - * failed open. The new code protects the open with a mutex, so it's - * really quite straightforward. The mutex locking can probably be - * relaxed for the (most common) case of reopening a tty. - */ - -struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx) -{ - struct tty_struct *tty; - int retval; - - /* - * First time open is complex, especially for PTY devices. - * This code guarantees that either everything succeeds and the - * TTY is ready for operation, or else the table slots are vacated - * and the allocated memory released. (Except that the termios - * and locked termios may be retained.) - */ - - if (!try_module_get(driver->owner)) - return ERR_PTR(-ENODEV); - - tty = alloc_tty_struct(driver, idx); - if (!tty) { - retval = -ENOMEM; - goto err_module_put; - } - - tty_lock(tty); - retval = tty_driver_install_tty(driver, tty); - if (retval < 0) - goto err_free_tty; - - if (!tty->port) - tty->port = driver->ports[idx]; - - WARN_RATELIMIT(!tty->port, - "%s: %s driver does not set tty->port. This will crash the kernel later. Fix the driver!\n", - __func__, tty->driver->name); - - tty->port->itty = tty; - - /* - * Structures all installed ... call the ldisc open routines. - * If we fail here just call release_tty to clean up. No need - * to decrement the use counts, as release_tty doesn't care. - */ - retval = tty_ldisc_setup(tty, tty->link); - if (retval) - goto err_release_tty; - /* Return the tty locked so that it cannot vanish under the caller */ - return tty; - -err_free_tty: - tty_unlock(tty); - free_tty_struct(tty); -err_module_put: - module_put(driver->owner); - return ERR_PTR(retval); - - /* call the tty release_tty routine to clean out this slot */ -err_release_tty: - tty_unlock(tty); - tty_info_ratelimited(tty, "ldisc open failed (%d), clearing slot %d\n", - retval, idx); - release_tty(tty, idx); - return ERR_PTR(retval); -} - -static void tty_free_termios(struct tty_struct *tty) -{ - struct ktermios *tp; - int idx = tty->index; - - /* If the port is going to reset then it has no termios to save */ - if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) - return; - - /* Stash the termios data */ - tp = tty->driver->termios[idx]; - if (tp == NULL) { - tp = kmalloc(sizeof(struct ktermios), GFP_KERNEL); - if (tp == NULL) - return; - tty->driver->termios[idx] = tp; - } - *tp = tty->termios; -} - -/** - * tty_flush_works - flush all works of a tty/pty pair - * @tty: tty device to flush works for (or either end of a pty pair) - * - * Sync flush all works belonging to @tty (and the 'other' tty). - */ -static void tty_flush_works(struct tty_struct *tty) -{ - flush_work(&tty->SAK_work); - flush_work(&tty->hangup_work); - if (tty->link) { - flush_work(&tty->link->SAK_work); - flush_work(&tty->link->hangup_work); - } -} - -/** - * release_one_tty - release tty structure memory - * @kref: kref of tty we are obliterating - * - * Releases memory associated with a tty structure, and clears out the - * driver table slots. This function is called when a device is no longer - * in use. It also gets called when setup of a device fails. - * - * Locking: - * takes the file list lock internally when working on the list - * of ttys that the driver keeps. - * - * This method gets called from a work queue so that the driver private - * cleanup ops can sleep (needed for USB at least) - */ -static void release_one_tty(struct work_struct *work) -{ - struct tty_struct *tty = - container_of(work, struct tty_struct, hangup_work); - struct tty_driver *driver = tty->driver; - struct module *owner = driver->owner; - - if (tty->ops->cleanup) - tty->ops->cleanup(tty); - - tty->magic = 0; - tty_driver_kref_put(driver); - module_put(owner); - - spin_lock(&tty->files_lock); - list_del_init(&tty->tty_files); - spin_unlock(&tty->files_lock); - - put_pid(tty->pgrp); - put_pid(tty->session); - free_tty_struct(tty); -} - -static void queue_release_one_tty(struct kref *kref) -{ - struct tty_struct *tty = container_of(kref, struct tty_struct, kref); - - /* The hangup queue is now free so we can reuse it rather than - waste a chunk of memory for each port */ - INIT_WORK(&tty->hangup_work, release_one_tty); - schedule_work(&tty->hangup_work); -} - -/** - * tty_kref_put - release a tty kref - * @tty: tty device - * - * Release a reference to a tty device and if need be let the kref - * layer destruct the object for us - */ - -void tty_kref_put(struct tty_struct *tty) -{ - if (tty) - kref_put(&tty->kref, queue_release_one_tty); -} -EXPORT_SYMBOL(tty_kref_put); - -/** - * release_tty - release tty structure memory - * - * Release both @tty and a possible linked partner (think pty pair), - * and decrement the refcount of the backing module. - * - * Locking: - * tty_mutex - * takes the file list lock internally when working on the list - * of ttys that the driver keeps. - * - */ -static void release_tty(struct tty_struct *tty, int idx) -{ - /* This should always be true but check for the moment */ - WARN_ON(tty->index != idx); - WARN_ON(!mutex_is_locked(&tty_mutex)); - if (tty->ops->shutdown) - tty->ops->shutdown(tty); - tty_free_termios(tty); - tty_driver_remove_tty(tty->driver, tty); - tty->port->itty = NULL; - if (tty->link) - tty->link->port->itty = NULL; - tty_buffer_cancel_work(tty->port); - - tty_kref_put(tty->link); - tty_kref_put(tty); -} - -/** - * tty_release_checks - check a tty before real release - * @tty: tty to check - * @o_tty: link of @tty (if any) - * @idx: index of the tty - * - * Performs some paranoid checking before true release of the @tty. - * This is a no-op unless TTY_PARANOIA_CHECK is defined. - */ -static int tty_release_checks(struct tty_struct *tty, int idx) -{ -#ifdef TTY_PARANOIA_CHECK - if (idx < 0 || idx >= tty->driver->num) { - tty_debug(tty, "bad idx %d\n", idx); - return -1; - } - - /* not much to check for devpts */ - if (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) - return 0; - - if (tty != tty->driver->ttys[idx]) { - tty_debug(tty, "bad driver table[%d] = %p\n", - idx, tty->driver->ttys[idx]); - return -1; - } - if (tty->driver->other) { - struct tty_struct *o_tty = tty->link; - - if (o_tty != tty->driver->other->ttys[idx]) { - tty_debug(tty, "bad other table[%d] = %p\n", - idx, tty->driver->other->ttys[idx]); - return -1; - } - if (o_tty->link != tty) { - tty_debug(tty, "bad link = %p\n", o_tty->link); - return -1; - } - } -#endif - return 0; -} - -/** - * tty_release - vfs callback for close - * @inode: inode of tty - * @filp: file pointer for handle to tty - * - * Called the last time each file handle is closed that references - * this tty. There may however be several such references. - * - * Locking: - * Takes bkl. See tty_release_dev - * - * Even releasing the tty structures is a tricky business.. We have - * to be very careful that the structures are all released at the - * same time, as interrupts might otherwise get the wrong pointers. - * - * WSH 09/09/97: rewritten to avoid some nasty race conditions that could - * lead to double frees or releasing memory still in use. - */ - -int tty_release(struct inode *inode, struct file *filp) -{ - struct tty_struct *tty = file_tty(filp); - struct tty_struct *o_tty = NULL; - int do_sleep, final; - int idx; - long timeout = 0; - int once = 1; - - if (tty_paranoia_check(tty, inode, __func__)) - return 0; - - tty_lock(tty); - check_tty_count(tty, __func__); - - __tty_fasync(-1, filp, 0); - - idx = tty->index; - if (tty->driver->type == TTY_DRIVER_TYPE_PTY && - tty->driver->subtype == PTY_TYPE_MASTER) - o_tty = tty->link; - - if (tty_release_checks(tty, idx)) { - tty_unlock(tty); - return 0; - } - - tty_debug_hangup(tty, "releasing (count=%d)\n", tty->count); - - if (tty->ops->close) - tty->ops->close(tty, filp); - - /* If tty is pty master, lock the slave pty (stable lock order) */ - tty_lock_slave(o_tty); - - /* - * Sanity check: if tty->count is going to zero, there shouldn't be - * any waiters on tty->read_wait or tty->write_wait. We test the - * wait queues and kick everyone out _before_ actually starting to - * close. This ensures that we won't block while releasing the tty - * structure. - * - * The test for the o_tty closing is necessary, since the master and - * slave sides may close in any order. If the slave side closes out - * first, its count will be one, since the master side holds an open. - * Thus this test wouldn't be triggered at the time the slave closed, - * so we do it now. - */ - while (1) { - do_sleep = 0; - - if (tty->count <= 1) { - if (waitqueue_active(&tty->read_wait)) { - wake_up_poll(&tty->read_wait, POLLIN); - do_sleep++; - } - if (waitqueue_active(&tty->write_wait)) { - wake_up_poll(&tty->write_wait, POLLOUT); - do_sleep++; - } - } - if (o_tty && o_tty->count <= 1) { - if (waitqueue_active(&o_tty->read_wait)) { - wake_up_poll(&o_tty->read_wait, POLLIN); - do_sleep++; - } - if (waitqueue_active(&o_tty->write_wait)) { - wake_up_poll(&o_tty->write_wait, POLLOUT); - do_sleep++; - } - } - if (!do_sleep) - break; - - if (once) { - once = 0; - tty_warn(tty, "read/write wait queue active!\n"); - } - schedule_timeout_killable(timeout); - if (timeout < 120 * HZ) - timeout = 2 * timeout + 1; - else - timeout = MAX_SCHEDULE_TIMEOUT; - } - - if (o_tty) { - if (--o_tty->count < 0) { - tty_warn(tty, "bad slave count (%d)\n", o_tty->count); - o_tty->count = 0; - } - } - if (--tty->count < 0) { - tty_warn(tty, "bad tty->count (%d)\n", tty->count); - tty->count = 0; - } - - /* - * We've decremented tty->count, so we need to remove this file - * descriptor off the tty->tty_files list; this serves two - * purposes: - * - check_tty_count sees the correct number of file descriptors - * associated with this tty. - * - do_tty_hangup no longer sees this file descriptor as - * something that needs to be handled for hangups. - */ - tty_del_file(filp); - - /* - * Perform some housekeeping before deciding whether to return. - * - * If _either_ side is closing, make sure there aren't any - * processes that still think tty or o_tty is their controlling - * tty. - */ - if (!tty->count) { - read_lock(&tasklist_lock); - session_clear_tty(tty->session); - if (o_tty) - session_clear_tty(o_tty->session); - read_unlock(&tasklist_lock); - } - - /* check whether both sides are closing ... */ - final = !tty->count && !(o_tty && o_tty->count); - - tty_unlock_slave(o_tty); - tty_unlock(tty); - - /* At this point, the tty->count == 0 should ensure a dead tty - cannot be re-opened by a racing opener */ - - if (!final) - return 0; - - tty_debug_hangup(tty, "final close\n"); - /* - * Ask the line discipline code to release its structures - */ - tty_ldisc_release(tty); - - /* Wait for pending work before tty destruction commmences */ - tty_flush_works(tty); - - tty_debug_hangup(tty, "freeing structure\n"); - /* - * The release_tty function takes care of the details of clearing - * the slots and preserving the termios structure. The tty_unlock_pair - * should be safe as we keep a kref while the tty is locked (so the - * unlock never unlocks a freed tty). - */ - mutex_lock(&tty_mutex); - release_tty(tty, idx); - mutex_unlock(&tty_mutex); - - return 0; -} - -/** - * tty_open_current_tty - get locked tty of current task - * @device: device number - * @filp: file pointer to tty - * @return: locked tty of the current task iff @device is /dev/tty - * - * Performs a re-open of the current task's controlling tty. - * - * We cannot return driver and index like for the other nodes because - * devpts will not work then. It expects inodes to be from devpts FS. - */ -static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp) -{ - struct tty_struct *tty; - int retval; - - if (device != MKDEV(TTYAUX_MAJOR, 0)) - return NULL; - - tty = get_current_tty(); - if (!tty) - return ERR_PTR(-ENXIO); - - filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */ - /* noctty = 1; */ - tty_lock(tty); - tty_kref_put(tty); /* safe to drop the kref now */ - - retval = tty_reopen(tty); - if (retval < 0) { - tty_unlock(tty); - tty = ERR_PTR(retval); - } - return tty; -} - -/** - * tty_lookup_driver - lookup a tty driver for a given device file - * @device: device number - * @filp: file pointer to tty - * @index: index for the device in the @return driver - * @return: driver for this inode (with increased refcount) - * - * If @return is not erroneous, the caller is responsible to decrement the - * refcount by tty_driver_kref_put. - * - * Locking: tty_mutex protects get_tty_driver - */ -static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp, - int *index) -{ - struct tty_driver *driver; - - switch (device) { -#ifdef CONFIG_VT - case MKDEV(TTY_MAJOR, 0): { - extern struct tty_driver *console_driver; - driver = tty_driver_kref_get(console_driver); - *index = fg_console; - break; - } -#endif - case MKDEV(TTYAUX_MAJOR, 1): { - struct tty_driver *console_driver = console_device(index); - if (console_driver) { - driver = tty_driver_kref_get(console_driver); - if (driver) { - /* Don't let /dev/console block */ - filp->f_flags |= O_NONBLOCK; - break; - } - } - return ERR_PTR(-ENODEV); - } - default: - driver = get_tty_driver(device, index); - if (!driver) - return ERR_PTR(-ENODEV); - break; - } - return driver; -} - -/** - * tty_open_by_driver - open a tty device - * @device: dev_t of device to open - * @inode: inode of device file - * @filp: file pointer to tty - * - * Performs the driver lookup, checks for a reopen, or otherwise - * performs the first-time tty initialization. - * - * Returns the locked initialized or re-opened &tty_struct - * - * Claims the global tty_mutex to serialize: - * - concurrent first-time tty initialization - * - concurrent tty driver removal w/ lookup - * - concurrent tty removal from driver table - */ -static struct tty_struct *tty_open_by_driver(dev_t device, struct inode *inode, - struct file *filp) -{ - struct tty_struct *tty; - struct tty_driver *driver = NULL; - int index = -1; - int retval; - - mutex_lock(&tty_mutex); - driver = tty_lookup_driver(device, filp, &index); - if (IS_ERR(driver)) { - mutex_unlock(&tty_mutex); - return ERR_CAST(driver); - } - - /* check whether we're reopening an existing tty */ - tty = tty_driver_lookup_tty(driver, filp, index); - if (IS_ERR(tty)) { - mutex_unlock(&tty_mutex); - goto out; - } - - if (tty) { - mutex_unlock(&tty_mutex); - retval = tty_lock_interruptible(tty); - tty_kref_put(tty); /* drop kref from tty_driver_lookup_tty() */ - if (retval) { - if (retval == -EINTR) - retval = -ERESTARTSYS; - tty = ERR_PTR(retval); - goto out; - } - retval = tty_reopen(tty); - if (retval < 0) { - tty_unlock(tty); - tty = ERR_PTR(retval); - } - } else { /* Returns with the tty_lock held for now */ - tty = tty_init_dev(driver, index); - mutex_unlock(&tty_mutex); - } -out: - tty_driver_kref_put(driver); - return tty; -} - -/** - * tty_open - open a tty device - * @inode: inode of device file - * @filp: file pointer to tty - * - * tty_open and tty_release keep up the tty count that contains the - * number of opens done on a tty. We cannot use the inode-count, as - * different inodes might point to the same tty. - * - * Open-counting is needed for pty masters, as well as for keeping - * track of serial lines: DTR is dropped when the last close happens. - * (This is not done solely through tty->count, now. - Ted 1/27/92) - * - * The termios state of a pty is reset on first open so that - * settings don't persist across reuse. - * - * Locking: tty_mutex protects tty, tty_lookup_driver and tty_init_dev. - * tty->count should protect the rest. - * ->siglock protects ->signal/->sighand - * - * Note: the tty_unlock/lock cases without a ref are only safe due to - * tty_mutex - */ - -static int tty_open(struct inode *inode, struct file *filp) -{ - struct tty_struct *tty; - int noctty, retval; - dev_t device = inode->i_rdev; - unsigned saved_flags = filp->f_flags; - - nonseekable_open(inode, filp); - -retry_open: - retval = tty_alloc_file(filp); - if (retval) - return -ENOMEM; - - tty = tty_open_current_tty(device, filp); - if (!tty) - tty = tty_open_by_driver(device, inode, filp); - - if (IS_ERR(tty)) { - tty_free_file(filp); - retval = PTR_ERR(tty); - if (retval != -EAGAIN || signal_pending(current)) - return retval; - schedule(); - goto retry_open; - } - - tty_add_file(tty, filp); - - check_tty_count(tty, __func__); - tty_debug_hangup(tty, "opening (count=%d)\n", tty->count); - - if (tty->ops->open) - retval = tty->ops->open(tty, filp); - else - retval = -ENODEV; - filp->f_flags = saved_flags; - - if (retval) { - tty_debug_hangup(tty, "open error %d, releasing\n", retval); - - tty_unlock(tty); /* need to call tty_release without BTM */ - tty_release(inode, filp); - if (retval != -ERESTARTSYS) - return retval; - - if (signal_pending(current)) - return retval; - - schedule(); - /* - * Need to reset f_op in case a hangup happened. - */ - if (tty_hung_up_p(filp)) - filp->f_op = &tty_fops; - goto retry_open; - } - clear_bit(TTY_HUPPED, &tty->flags); - - - read_lock(&tasklist_lock); - spin_lock_irq(¤t->sighand->siglock); - noctty = (filp->f_flags & O_NOCTTY) || - (IS_ENABLED(CONFIG_VT) && device == MKDEV(TTY_MAJOR, 0)) || - device == MKDEV(TTYAUX_MAJOR, 1) || - (tty->driver->type == TTY_DRIVER_TYPE_PTY && - tty->driver->subtype == PTY_TYPE_MASTER); - - if (!noctty && - current->signal->leader && - !current->signal->tty && - tty->session == NULL) { - /* - * Don't let a process that only has write access to the tty - * obtain the privileges associated with having a tty as - * controlling terminal (being able to reopen it with full - * access through /dev/tty, being able to perform pushback). - * Many distributions set the group of all ttys to "tty" and - * grant write-only access to all terminals for setgid tty - * binaries, which should not imply full privileges on all ttys. - * - * This could theoretically break old code that performs open() - * on a write-only file descriptor. In that case, it might be - * necessary to also permit this if - * inode_permission(inode, MAY_READ) == 0. - */ - if (filp->f_mode & FMODE_READ) - __proc_set_tty(tty); - } - spin_unlock_irq(¤t->sighand->siglock); - read_unlock(&tasklist_lock); - tty_unlock(tty); - return 0; -} - - - -/** - * tty_poll - check tty status - * @filp: file being polled - * @wait: poll wait structures to update - * - * Call the line discipline polling method to obtain the poll - * status of the device. - * - * Locking: locks called line discipline but ldisc poll method - * may be re-entered freely by other callers. - */ - -static unsigned int tty_poll(struct file *filp, poll_table *wait) -{ - struct tty_struct *tty = file_tty(filp); - struct tty_ldisc *ld; - int ret = 0; - - if (tty_paranoia_check(tty, file_inode(filp), "tty_poll")) - return 0; - - ld = tty_ldisc_ref_wait(tty); - if (!ld) - return hung_up_tty_poll(filp, wait); - if (ld->ops->poll) - ret = ld->ops->poll(tty, filp, wait); - tty_ldisc_deref(ld); - return ret; -} - -static int __tty_fasync(int fd, struct file *filp, int on) -{ - struct tty_struct *tty = file_tty(filp); - unsigned long flags; - int retval = 0; - - if (tty_paranoia_check(tty, file_inode(filp), "tty_fasync")) - goto out; - - retval = fasync_helper(fd, filp, on, &tty->fasync); - if (retval <= 0) - goto out; - - if (on) { - enum pid_type type; - struct pid *pid; - - spin_lock_irqsave(&tty->ctrl_lock, flags); - if (tty->pgrp) { - pid = tty->pgrp; - type = PIDTYPE_PGID; - } else { - pid = task_pid(current); - type = PIDTYPE_PID; - } - get_pid(pid); - spin_unlock_irqrestore(&tty->ctrl_lock, flags); - __f_setown(filp, pid, type, 0); - put_pid(pid); - retval = 0; - } -out: - return retval; -} - -static int tty_fasync(int fd, struct file *filp, int on) -{ - struct tty_struct *tty = file_tty(filp); - int retval = -ENOTTY; - - tty_lock(tty); - if (!tty_hung_up_p(filp)) - retval = __tty_fasync(fd, filp, on); - tty_unlock(tty); - - return retval; -} - -/** - * tiocsti - fake input character - * @tty: tty to fake input into - * @p: pointer to character - * - * Fake input to a tty device. Does the necessary locking and - * input management. - * - * FIXME: does not honour flow control ?? - * - * Locking: - * Called functions take tty_ldiscs_lock - * current->signal->tty check is safe without locks - * - * FIXME: may race normal receive processing - */ - -static int tiocsti(struct tty_struct *tty, char __user *p) -{ - char ch, mbz = 0; - struct tty_ldisc *ld; - - if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN)) - return -EPERM; - if (get_user(ch, p)) - return -EFAULT; - tty_audit_tiocsti(tty, ch); - ld = tty_ldisc_ref_wait(tty); - if (!ld) - return -EIO; - ld->ops->receive_buf(tty, &ch, &mbz, 1); - tty_ldisc_deref(ld); - return 0; -} - -/** - * tiocgwinsz - implement window query ioctl - * @tty; tty - * @arg: user buffer for result - * - * Copies the kernel idea of the window size into the user buffer. - * - * Locking: tty->winsize_mutex is taken to ensure the winsize data - * is consistent. - */ - -static int tiocgwinsz(struct tty_struct *tty, struct winsize __user *arg) -{ - int err; - - mutex_lock(&tty->winsize_mutex); - err = copy_to_user(arg, &tty->winsize, sizeof(*arg)); - mutex_unlock(&tty->winsize_mutex); - - return err ? -EFAULT: 0; -} - -/** - * tty_do_resize - resize event - * @tty: tty being resized - * @rows: rows (character) - * @cols: cols (character) - * - * Update the termios variables and send the necessary signals to - * peform a terminal resize correctly - */ - -int tty_do_resize(struct tty_struct *tty, struct winsize *ws) -{ - struct pid *pgrp; - - /* Lock the tty */ - mutex_lock(&tty->winsize_mutex); - if (!memcmp(ws, &tty->winsize, sizeof(*ws))) - goto done; - - /* Signal the foreground process group */ - pgrp = tty_get_pgrp(tty); - if (pgrp) - kill_pgrp(pgrp, SIGWINCH, 1); - put_pid(pgrp); - - tty->winsize = *ws; -done: - mutex_unlock(&tty->winsize_mutex); - return 0; -} -EXPORT_SYMBOL(tty_do_resize); - -/** - * tiocswinsz - implement window size set ioctl - * @tty; tty side of tty - * @arg: user buffer for result - * - * Copies the user idea of the window size to the kernel. Traditionally - * this is just advisory information but for the Linux console it - * actually has driver level meaning and triggers a VC resize. - * - * Locking: - * Driver dependent. The default do_resize method takes the - * tty termios mutex and ctrl_lock. The console takes its own lock - * then calls into the default method. - */ - -static int tiocswinsz(struct tty_struct *tty, struct winsize __user *arg) -{ - struct winsize tmp_ws; - if (copy_from_user(&tmp_ws, arg, sizeof(*arg))) - return -EFAULT; - - if (tty->ops->resize) - return tty->ops->resize(tty, &tmp_ws); - else - return tty_do_resize(tty, &tmp_ws); -} - -/** - * tioccons - allow admin to move logical console - * @file: the file to become console - * - * Allow the administrator to move the redirected console device - * - * Locking: uses redirect_lock to guard the redirect information - */ - -static int tioccons(struct file *file) -{ - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (file->f_op->write == redirected_tty_write) { - struct file *f; - spin_lock(&redirect_lock); - f = redirect; - redirect = NULL; - spin_unlock(&redirect_lock); - if (f) - fput(f); - return 0; - } - spin_lock(&redirect_lock); - if (redirect) { - spin_unlock(&redirect_lock); - return -EBUSY; - } - redirect = get_file(file); - spin_unlock(&redirect_lock); - return 0; -} - -/** - * fionbio - non blocking ioctl - * @file: file to set blocking value - * @p: user parameter - * - * Historical tty interfaces had a blocking control ioctl before - * the generic functionality existed. This piece of history is preserved - * in the expected tty API of posix OS's. - * - * Locking: none, the open file handle ensures it won't go away. - */ - -static int fionbio(struct file *file, int __user *p) -{ - int nonblock; - - if (get_user(nonblock, p)) - return -EFAULT; - - spin_lock(&file->f_lock); - if (nonblock) - file->f_flags |= O_NONBLOCK; - else - file->f_flags &= ~O_NONBLOCK; - spin_unlock(&file->f_lock); - return 0; -} - -/** - * tiocsctty - set controlling tty - * @tty: tty structure - * @arg: user argument - * - * This ioctl is used to manage job control. It permits a session - * leader to set this tty as the controlling tty for the session. - * - * Locking: - * Takes tty_lock() to serialize proc_set_tty() for this tty - * Takes tasklist_lock internally to walk sessions - * Takes ->siglock() when updating signal->tty - */ - -static int tiocsctty(struct tty_struct *tty, struct file *file, int arg) -{ - int ret = 0; - - tty_lock(tty); - read_lock(&tasklist_lock); - - if (current->signal->leader && (task_session(current) == tty->session)) - goto unlock; - - /* - * The process must be a session leader and - * not have a controlling tty already. - */ - if (!current->signal->leader || current->signal->tty) { - ret = -EPERM; - goto unlock; - } - - if (tty->session) { - /* - * This tty is already the controlling - * tty for another session group! - */ - if (arg == 1 && capable(CAP_SYS_ADMIN)) { - /* - * Steal it away - */ - session_clear_tty(tty->session); - } else { - ret = -EPERM; - goto unlock; - } - } - - /* See the comment in tty_open(). */ - if ((file->f_mode & FMODE_READ) == 0 && !capable(CAP_SYS_ADMIN)) { - ret = -EPERM; - goto unlock; - } - - proc_set_tty(tty); -unlock: - read_unlock(&tasklist_lock); - tty_unlock(tty); - return ret; -} - -/** - * tty_get_pgrp - return a ref counted pgrp pid - * @tty: tty to read - * - * Returns a refcounted instance of the pid struct for the process - * group controlling the tty. - */ - -struct pid *tty_get_pgrp(struct tty_struct *tty) -{ - unsigned long flags; - struct pid *pgrp; - - spin_lock_irqsave(&tty->ctrl_lock, flags); - pgrp = get_pid(tty->pgrp); - spin_unlock_irqrestore(&tty->ctrl_lock, flags); - - return pgrp; -} -EXPORT_SYMBOL_GPL(tty_get_pgrp); - -/* - * This checks not only the pgrp, but falls back on the pid if no - * satisfactory pgrp is found. I dunno - gdb doesn't work correctly - * without this... - * - * The caller must hold rcu lock or the tasklist lock. - */ -static struct pid *session_of_pgrp(struct pid *pgrp) -{ - struct task_struct *p; - struct pid *sid = NULL; - - p = pid_task(pgrp, PIDTYPE_PGID); - if (p == NULL) - p = pid_task(pgrp, PIDTYPE_PID); - if (p != NULL) - sid = task_session(p); - - return sid; -} - -/** - * tiocgpgrp - get process group - * @tty: tty passed by user - * @real_tty: tty side of the tty passed by the user if a pty else the tty - * @p: returned pid - * - * Obtain the process group of the tty. If there is no process group - * return an error. - * - * Locking: none. Reference to current->signal->tty is safe. - */ - -static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) -{ - struct pid *pid; - int ret; - /* - * (tty == real_tty) is a cheap way of - * testing if the tty is NOT a master pty. - */ - if (tty == real_tty && current->signal->tty != real_tty) - return -ENOTTY; - pid = tty_get_pgrp(real_tty); - ret = put_user(pid_vnr(pid), p); - put_pid(pid); - return ret; -} - -/** - * tiocspgrp - attempt to set process group - * @tty: tty passed by user - * @real_tty: tty side device matching tty passed by user - * @p: pid pointer - * - * Set the process group of the tty to the session passed. Only - * permitted where the tty session is our session. - * - * Locking: RCU, ctrl lock - */ - -static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) -{ - struct pid *pgrp; - pid_t pgrp_nr; - int retval = tty_check_change(real_tty); - - if (retval == -EIO) - return -ENOTTY; - if (retval) - return retval; - if (!current->signal->tty || - (current->signal->tty != real_tty) || - (real_tty->session != task_session(current))) - return -ENOTTY; - if (get_user(pgrp_nr, p)) - return -EFAULT; - if (pgrp_nr < 0) - return -EINVAL; - rcu_read_lock(); - pgrp = find_vpid(pgrp_nr); - retval = -ESRCH; - if (!pgrp) - goto out_unlock; - retval = -EPERM; - if (session_of_pgrp(pgrp) != task_session(current)) - goto out_unlock; - retval = 0; - spin_lock_irq(&tty->ctrl_lock); - put_pid(real_tty->pgrp); - real_tty->pgrp = get_pid(pgrp); - spin_unlock_irq(&tty->ctrl_lock); -out_unlock: - rcu_read_unlock(); - return retval; -} - -/** - * tiocgsid - get session id - * @tty: tty passed by user - * @real_tty: tty side of the tty passed by the user if a pty else the tty - * @p: pointer to returned session id - * - * Obtain the session id of the tty. If there is no session - * return an error. - * - * Locking: none. Reference to current->signal->tty is safe. - */ - -static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) -{ - /* - * (tty == real_tty) is a cheap way of - * testing if the tty is NOT a master pty. - */ - if (tty == real_tty && current->signal->tty != real_tty) - return -ENOTTY; - if (!real_tty->session) - return -ENOTTY; - return put_user(pid_vnr(real_tty->session), p); -} - -/** - * tiocsetd - set line discipline - * @tty: tty device - * @p: pointer to user data - * - * Set the line discipline according to user request. - * - * Locking: see tty_set_ldisc, this function is just a helper - */ - -static int tiocsetd(struct tty_struct *tty, int __user *p) -{ - int disc; - int ret; - - if (get_user(disc, p)) - return -EFAULT; - - ret = tty_set_ldisc(tty, disc); - - return ret; -} - -/** - * tiocgetd - get line discipline - * @tty: tty device - * @p: pointer to user data - * - * Retrieves the line discipline id directly from the ldisc. - * - * Locking: waits for ldisc reference (in case the line discipline - * is changing or the tty is being hungup) - */ - -static int tiocgetd(struct tty_struct *tty, int __user *p) -{ - struct tty_ldisc *ld; - int ret; - - ld = tty_ldisc_ref_wait(tty); - if (!ld) - return -EIO; - ret = put_user(ld->ops->num, p); - tty_ldisc_deref(ld); - return ret; -} - -/** - * send_break - performed time break - * @tty: device to break on - * @duration: timeout in mS - * - * Perform a timed break on hardware that lacks its own driver level - * timed break functionality. - * - * Locking: - * atomic_write_lock serializes - * - */ - -static int send_break(struct tty_struct *tty, unsigned int duration) -{ - int retval; - - if (tty->ops->break_ctl == NULL) - return 0; - - if (tty->driver->flags & TTY_DRIVER_HARDWARE_BREAK) - retval = tty->ops->break_ctl(tty, duration); - else { - /* Do the work ourselves */ - if (tty_write_lock(tty, 0) < 0) - return -EINTR; - retval = tty->ops->break_ctl(tty, -1); - if (retval) - goto out; - if (!signal_pending(current)) - msleep_interruptible(duration); - retval = tty->ops->break_ctl(tty, 0); -out: - tty_write_unlock(tty); - if (signal_pending(current)) - retval = -EINTR; - } - return retval; -} - -/** - * tty_tiocmget - get modem status - * @tty: tty device - * @file: user file pointer - * @p: pointer to result - * - * Obtain the modem status bits from the tty driver if the feature - * is supported. Return -EINVAL if it is not available. - * - * Locking: none (up to the driver) - */ - -static int tty_tiocmget(struct tty_struct *tty, int __user *p) -{ - int retval = -EINVAL; - - if (tty->ops->tiocmget) { - retval = tty->ops->tiocmget(tty); - - if (retval >= 0) - retval = put_user(retval, p); - } - return retval; -} - -/** - * tty_tiocmset - set modem status - * @tty: tty device - * @cmd: command - clear bits, set bits or set all - * @p: pointer to desired bits - * - * Set the modem status bits from the tty driver if the feature - * is supported. Return -EINVAL if it is not available. - * - * Locking: none (up to the driver) - */ - -static int tty_tiocmset(struct tty_struct *tty, unsigned int cmd, - unsigned __user *p) -{ - int retval; - unsigned int set, clear, val; - - if (tty->ops->tiocmset == NULL) - return -EINVAL; - - retval = get_user(val, p); - if (retval) - return retval; - set = clear = 0; - switch (cmd) { - case TIOCMBIS: - set = val; - break; - case TIOCMBIC: - clear = val; - break; - case TIOCMSET: - set = val; - clear = ~val; - break; - } - set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; - clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP; - return tty->ops->tiocmset(tty, set, clear); -} - -static int tty_tiocgicount(struct tty_struct *tty, void __user *arg) -{ - int retval = -EINVAL; - struct serial_icounter_struct icount; - memset(&icount, 0, sizeof(icount)); - if (tty->ops->get_icount) - retval = tty->ops->get_icount(tty, &icount); - if (retval != 0) - return retval; - if (copy_to_user(arg, &icount, sizeof(icount))) - return -EFAULT; - return 0; -} - -static void tty_warn_deprecated_flags(struct serial_struct __user *ss) -{ - static DEFINE_RATELIMIT_STATE(depr_flags, - DEFAULT_RATELIMIT_INTERVAL, - DEFAULT_RATELIMIT_BURST); - char comm[TASK_COMM_LEN]; - int flags; - - if (get_user(flags, &ss->flags)) - return; - - flags &= ASYNC_DEPRECATED; - - if (flags && __ratelimit(&depr_flags)) - pr_warning("%s: '%s' is using deprecated serial flags (with no effect): %.8x\n", - __func__, get_task_comm(comm, current), flags); -} - -/* - * if pty, return the slave side (real_tty) - * otherwise, return self - */ -static struct tty_struct *tty_pair_get_tty(struct tty_struct *tty) -{ - if (tty->driver->type == TTY_DRIVER_TYPE_PTY && - tty->driver->subtype == PTY_TYPE_MASTER) - tty = tty->link; - return tty; -} - -/* - * Split this up, as gcc can choke on it otherwise.. - */ -long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct tty_struct *tty = file_tty(file); - struct tty_struct *real_tty; - void __user *p = (void __user *)arg; - int retval; - struct tty_ldisc *ld; - - if (tty_paranoia_check(tty, file_inode(file), "tty_ioctl")) - return -EINVAL; - - real_tty = tty_pair_get_tty(tty); - - /* - * Factor out some common prep work - */ - switch (cmd) { - case TIOCSETD: - case TIOCSBRK: - case TIOCCBRK: - case TCSBRK: - case TCSBRKP: - retval = tty_check_change(tty); - if (retval) - return retval; - if (cmd != TIOCCBRK) { - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -EINTR; - } - break; - } - - /* - * Now do the stuff. - */ - switch (cmd) { - case TIOCSTI: - return tiocsti(tty, p); - case TIOCGWINSZ: - return tiocgwinsz(real_tty, p); - case TIOCSWINSZ: - return tiocswinsz(real_tty, p); - case TIOCCONS: - return real_tty != tty ? -EINVAL : tioccons(file); - case FIONBIO: - return fionbio(file, p); - case TIOCEXCL: - set_bit(TTY_EXCLUSIVE, &tty->flags); - return 0; - case TIOCNXCL: - clear_bit(TTY_EXCLUSIVE, &tty->flags); - return 0; - case TIOCGEXCL: - { - int excl = test_bit(TTY_EXCLUSIVE, &tty->flags); - return put_user(excl, (int __user *)p); - } - case TIOCNOTTY: - if (current->signal->tty != tty) - return -ENOTTY; - no_tty(); - return 0; - case TIOCSCTTY: - return tiocsctty(real_tty, file, arg); - case TIOCGPGRP: - return tiocgpgrp(tty, real_tty, p); - case TIOCSPGRP: - return tiocspgrp(tty, real_tty, p); - case TIOCGSID: - return tiocgsid(tty, real_tty, p); - case TIOCGETD: - return tiocgetd(tty, p); - case TIOCSETD: - return tiocsetd(tty, p); - case TIOCVHANGUP: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - tty_vhangup(tty); - return 0; - case TIOCGDEV: - { - unsigned int ret = new_encode_dev(tty_devnum(real_tty)); - return put_user(ret, (unsigned int __user *)p); - } - /* - * Break handling - */ - case TIOCSBRK: /* Turn break on, unconditionally */ - if (tty->ops->break_ctl) - return tty->ops->break_ctl(tty, -1); - return 0; - case TIOCCBRK: /* Turn break off, unconditionally */ - if (tty->ops->break_ctl) - return tty->ops->break_ctl(tty, 0); - return 0; - case TCSBRK: /* SVID version: non-zero arg --> no break */ - /* non-zero arg means wait for all output data - * to be sent (performed above) but don't send break. - * This is used by the tcdrain() termios function. - */ - if (!arg) - return send_break(tty, 250); - return 0; - case TCSBRKP: /* support for POSIX tcsendbreak() */ - return send_break(tty, arg ? arg*100 : 250); - - case TIOCMGET: - return tty_tiocmget(tty, p); - case TIOCMSET: - case TIOCMBIC: - case TIOCMBIS: - return tty_tiocmset(tty, cmd, p); - case TIOCGICOUNT: - retval = tty_tiocgicount(tty, p); - /* For the moment allow fall through to the old method */ - if (retval != -EINVAL) - return retval; - break; - case TCFLSH: - switch (arg) { - case TCIFLUSH: - case TCIOFLUSH: - /* flush tty buffer and allow ldisc to process ioctl */ - tty_buffer_flush(tty, NULL); - break; - } - break; - case TIOCSSERIAL: - tty_warn_deprecated_flags(p); - break; - } - if (tty->ops->ioctl) { - retval = tty->ops->ioctl(tty, cmd, arg); - if (retval != -ENOIOCTLCMD) - return retval; - } - ld = tty_ldisc_ref_wait(tty); - if (!ld) - return hung_up_tty_ioctl(file, cmd, arg); - retval = -EINVAL; - if (ld->ops->ioctl) { - retval = ld->ops->ioctl(tty, file, cmd, arg); - if (retval == -ENOIOCTLCMD) - retval = -ENOTTY; - } - tty_ldisc_deref(ld); - return retval; -} - -#ifdef CONFIG_COMPAT -static long tty_compat_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct tty_struct *tty = file_tty(file); - struct tty_ldisc *ld; - int retval = -ENOIOCTLCMD; - - if (tty_paranoia_check(tty, file_inode(file), "tty_ioctl")) - return -EINVAL; - - if (tty->ops->compat_ioctl) { - retval = tty->ops->compat_ioctl(tty, cmd, arg); - if (retval != -ENOIOCTLCMD) - return retval; - } - - ld = tty_ldisc_ref_wait(tty); - if (!ld) - return hung_up_tty_compat_ioctl(file, cmd, arg); - if (ld->ops->compat_ioctl) - retval = ld->ops->compat_ioctl(tty, file, cmd, arg); - else - retval = n_tty_compat_ioctl_helper(tty, file, cmd, arg); - tty_ldisc_deref(ld); - - return retval; -} -#endif - -static int this_tty(const void *t, struct file *file, unsigned fd) -{ - if (likely(file->f_op->read != tty_read)) - return 0; - return file_tty(file) != t ? 0 : fd + 1; -} - -/* - * This implements the "Secure Attention Key" --- the idea is to - * prevent trojan horses by killing all processes associated with this - * tty when the user hits the "Secure Attention Key". Required for - * super-paranoid applications --- see the Orange Book for more details. - * - * This code could be nicer; ideally it should send a HUP, wait a few - * seconds, then send a INT, and then a KILL signal. But you then - * have to coordinate with the init process, since all processes associated - * with the current tty must be dead before the new getty is allowed - * to spawn. - * - * Now, if it would be correct ;-/ The current code has a nasty hole - - * it doesn't catch files in flight. We may send the descriptor to ourselves - * via AF_UNIX socket, close it and later fetch from socket. FIXME. - * - * Nasty bug: do_SAK is being called in interrupt context. This can - * deadlock. We punt it up to process context. AKPM - 16Mar2001 - */ -void __do_SAK(struct tty_struct *tty) -{ -#ifdef TTY_SOFT_SAK - tty_hangup(tty); -#else - struct task_struct *g, *p; - struct pid *session; - int i; - - if (!tty) - return; - session = tty->session; - - tty_ldisc_flush(tty); - - tty_driver_flush_buffer(tty); - - read_lock(&tasklist_lock); - /* Kill the entire session */ - do_each_pid_task(session, PIDTYPE_SID, p) { - tty_notice(tty, "SAK: killed process %d (%s): by session\n", - task_pid_nr(p), p->comm); - send_sig(SIGKILL, p, 1); - } while_each_pid_task(session, PIDTYPE_SID, p); - - /* Now kill any processes that happen to have the tty open */ - do_each_thread(g, p) { - if (p->signal->tty == tty) { - tty_notice(tty, "SAK: killed process %d (%s): by controlling tty\n", - task_pid_nr(p), p->comm); - send_sig(SIGKILL, p, 1); - continue; - } - task_lock(p); - i = iterate_fd(p->files, 0, this_tty, tty); - if (i != 0) { - tty_notice(tty, "SAK: killed process %d (%s): by fd#%d\n", - task_pid_nr(p), p->comm, i - 1); - force_sig(SIGKILL, p); - } - task_unlock(p); - } while_each_thread(g, p); - read_unlock(&tasklist_lock); -#endif -} - -static void do_SAK_work(struct work_struct *work) -{ - struct tty_struct *tty = - container_of(work, struct tty_struct, SAK_work); - __do_SAK(tty); -} - -/* - * The tq handling here is a little racy - tty->SAK_work may already be queued. - * Fortunately we don't need to worry, because if ->SAK_work is already queued, - * the values which we write to it will be identical to the values which it - * already has. --akpm - */ -void do_SAK(struct tty_struct *tty) -{ - if (!tty) - return; - schedule_work(&tty->SAK_work); -} - -EXPORT_SYMBOL(do_SAK); - -static int dev_match_devt(struct device *dev, const void *data) -{ - const dev_t *devt = data; - return dev->devt == *devt; -} - -/* Must put_device() after it's unused! */ -static struct device *tty_get_device(struct tty_struct *tty) -{ - dev_t devt = tty_devnum(tty); - return class_find_device(tty_class, NULL, &devt, dev_match_devt); -} - - -/** - * alloc_tty_struct - * - * This subroutine allocates and initializes a tty structure. - * - * Locking: none - tty in question is not exposed at this point - */ - -struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx) -{ - struct tty_struct *tty; - - tty = kzalloc(sizeof(*tty), GFP_KERNEL); - if (!tty) - return NULL; - - kref_init(&tty->kref); - tty->magic = TTY_MAGIC; - tty_ldisc_init(tty); - tty->session = NULL; - tty->pgrp = NULL; - mutex_init(&tty->legacy_mutex); - mutex_init(&tty->throttle_mutex); - init_rwsem(&tty->termios_rwsem); - mutex_init(&tty->winsize_mutex); - init_ldsem(&tty->ldisc_sem); - init_waitqueue_head(&tty->write_wait); - init_waitqueue_head(&tty->read_wait); - INIT_WORK(&tty->hangup_work, do_tty_hangup); - mutex_init(&tty->atomic_write_lock); - spin_lock_init(&tty->ctrl_lock); - spin_lock_init(&tty->flow_lock); - spin_lock_init(&tty->files_lock); - INIT_LIST_HEAD(&tty->tty_files); - INIT_WORK(&tty->SAK_work, do_SAK_work); - - tty->driver = driver; - tty->ops = driver->ops; - tty->index = idx; - tty_line_name(driver, idx, tty->name); - tty->dev = tty_get_device(tty); - - return tty; -} - -/** - * tty_put_char - write one character to a tty - * @tty: tty - * @ch: character - * - * Write one byte to the tty using the provided put_char method - * if present. Returns the number of characters successfully output. - * - * Note: the specific put_char operation in the driver layer may go - * away soon. Don't call it directly, use this method - */ - -int tty_put_char(struct tty_struct *tty, unsigned char ch) -{ - if (tty->ops->put_char) - return tty->ops->put_char(tty, ch); - return tty->ops->write(tty, &ch, 1); -} -EXPORT_SYMBOL_GPL(tty_put_char); - -struct class *tty_class; - -static int tty_cdev_add(struct tty_driver *driver, dev_t dev, - unsigned int index, unsigned int count) -{ - int err; - - /* init here, since reused cdevs cause crashes */ - driver->cdevs[index] = cdev_alloc(); - if (!driver->cdevs[index]) - return -ENOMEM; - driver->cdevs[index]->ops = &tty_fops; - driver->cdevs[index]->owner = driver->owner; - err = cdev_add(driver->cdevs[index], dev, count); - if (err) - kobject_put(&driver->cdevs[index]->kobj); - return err; -} - -/** - * tty_register_device - register a tty device - * @driver: the tty driver that describes the tty device - * @index: the index in the tty driver for this tty device - * @device: a struct device that is associated with this tty device. - * This field is optional, if there is no known struct device - * for this tty device it can be set to NULL safely. - * - * Returns a pointer to the struct device for this tty device - * (or ERR_PTR(-EFOO) on error). - * - * This call is required to be made to register an individual tty device - * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If - * that bit is not set, this function should not be called by a tty - * driver. - * - * Locking: ?? - */ - -struct device *tty_register_device(struct tty_driver *driver, unsigned index, - struct device *device) -{ - return tty_register_device_attr(driver, index, device, NULL, NULL); -} -EXPORT_SYMBOL(tty_register_device); - -static void tty_device_create_release(struct device *dev) -{ - dev_dbg(dev, "releasing...\n"); - kfree(dev); -} - -/** - * tty_register_device_attr - register a tty device - * @driver: the tty driver that describes the tty device - * @index: the index in the tty driver for this tty device - * @device: a struct device that is associated with this tty device. - * This field is optional, if there is no known struct device - * for this tty device it can be set to NULL safely. - * @drvdata: Driver data to be set to device. - * @attr_grp: Attribute group to be set on device. - * - * Returns a pointer to the struct device for this tty device - * (or ERR_PTR(-EFOO) on error). - * - * This call is required to be made to register an individual tty device - * if the tty driver's flags have the TTY_DRIVER_DYNAMIC_DEV bit set. If - * that bit is not set, this function should not be called by a tty - * driver. - * - * Locking: ?? - */ -struct device *tty_register_device_attr(struct tty_driver *driver, - unsigned index, struct device *device, - void *drvdata, - const struct attribute_group **attr_grp) -{ - char name[64]; - dev_t devt = MKDEV(driver->major, driver->minor_start) + index; - struct device *dev = NULL; - int retval = -ENODEV; - bool cdev = false; - - if (index >= driver->num) { - pr_err("%s: Attempt to register invalid tty line number (%d)\n", - driver->name, index); - return ERR_PTR(-EINVAL); - } - - if (driver->type == TTY_DRIVER_TYPE_PTY) - pty_line_name(driver, index, name); - else - tty_line_name(driver, index, name); - - if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) { - retval = tty_cdev_add(driver, devt, index, 1); - if (retval) - goto error; - cdev = true; - } - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - retval = -ENOMEM; - goto error; - } - - dev->devt = devt; - dev->class = tty_class; - dev->parent = device; - dev->release = tty_device_create_release; - dev_set_name(dev, "%s", name); - dev->groups = attr_grp; - dev_set_drvdata(dev, drvdata); - - retval = device_register(dev); - if (retval) - goto error; - - return dev; - -error: - put_device(dev); - if (cdev) { - cdev_del(driver->cdevs[index]); - driver->cdevs[index] = NULL; - } - return ERR_PTR(retval); -} -EXPORT_SYMBOL_GPL(tty_register_device_attr); - -/** - * tty_unregister_device - unregister a tty device - * @driver: the tty driver that describes the tty device - * @index: the index in the tty driver for this tty device - * - * If a tty device is registered with a call to tty_register_device() then - * this function must be called when the tty device is gone. - * - * Locking: ?? - */ - -void tty_unregister_device(struct tty_driver *driver, unsigned index) -{ - device_destroy(tty_class, - MKDEV(driver->major, driver->minor_start) + index); - if (!(driver->flags & TTY_DRIVER_DYNAMIC_ALLOC)) { - cdev_del(driver->cdevs[index]); - driver->cdevs[index] = NULL; - } -} -EXPORT_SYMBOL(tty_unregister_device); - -/** - * __tty_alloc_driver -- allocate tty driver - * @lines: count of lines this driver can handle at most - * @owner: module which is repsonsible for this driver - * @flags: some of TTY_DRIVER_* flags, will be set in driver->flags - * - * This should not be called directly, some of the provided macros should be - * used instead. Use IS_ERR and friends on @retval. - */ -struct tty_driver *__tty_alloc_driver(unsigned int lines, struct module *owner, - unsigned long flags) -{ - struct tty_driver *driver; - unsigned int cdevs = 1; - int err; - - if (!lines || (flags & TTY_DRIVER_UNNUMBERED_NODE && lines > 1)) - return ERR_PTR(-EINVAL); - - driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL); - if (!driver) - return ERR_PTR(-ENOMEM); - - kref_init(&driver->kref); - driver->magic = TTY_DRIVER_MAGIC; - driver->num = lines; - driver->owner = owner; - driver->flags = flags; - - if (!(flags & TTY_DRIVER_DEVPTS_MEM)) { - driver->ttys = kcalloc(lines, sizeof(*driver->ttys), - GFP_KERNEL); - driver->termios = kcalloc(lines, sizeof(*driver->termios), - GFP_KERNEL); - if (!driver->ttys || !driver->termios) { - err = -ENOMEM; - goto err_free_all; - } - } - - if (!(flags & TTY_DRIVER_DYNAMIC_ALLOC)) { - driver->ports = kcalloc(lines, sizeof(*driver->ports), - GFP_KERNEL); - if (!driver->ports) { - err = -ENOMEM; - goto err_free_all; - } - cdevs = lines; - } - - driver->cdevs = kcalloc(cdevs, sizeof(*driver->cdevs), GFP_KERNEL); - if (!driver->cdevs) { - err = -ENOMEM; - goto err_free_all; - } - - return driver; -err_free_all: - kfree(driver->ports); - kfree(driver->ttys); - kfree(driver->termios); - kfree(driver->cdevs); - kfree(driver); - return ERR_PTR(err); -} -EXPORT_SYMBOL(__tty_alloc_driver); - -static void destruct_tty_driver(struct kref *kref) -{ - struct tty_driver *driver = container_of(kref, struct tty_driver, kref); - int i; - struct ktermios *tp; - - if (driver->flags & TTY_DRIVER_INSTALLED) { - /* - * Free the termios and termios_locked structures because - * we don't want to get memory leaks when modular tty - * drivers are removed from the kernel. - */ - for (i = 0; i < driver->num; i++) { - tp = driver->termios[i]; - if (tp) { - driver->termios[i] = NULL; - kfree(tp); - } - if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) - tty_unregister_device(driver, i); - } - proc_tty_unregister_driver(driver); - if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) - cdev_del(driver->cdevs[0]); - } - kfree(driver->cdevs); - kfree(driver->ports); - kfree(driver->termios); - kfree(driver->ttys); - kfree(driver); -} - -void tty_driver_kref_put(struct tty_driver *driver) -{ - kref_put(&driver->kref, destruct_tty_driver); -} -EXPORT_SYMBOL(tty_driver_kref_put); - -void tty_set_operations(struct tty_driver *driver, - const struct tty_operations *op) -{ - driver->ops = op; -}; -EXPORT_SYMBOL(tty_set_operations); - -void put_tty_driver(struct tty_driver *d) -{ - tty_driver_kref_put(d); -} -EXPORT_SYMBOL(put_tty_driver); - -/* - * Called by a tty driver to register itself. - */ -int tty_register_driver(struct tty_driver *driver) -{ - int error; - int i; - dev_t dev; - struct device *d; - - if (!driver->major) { - error = alloc_chrdev_region(&dev, driver->minor_start, - driver->num, driver->name); - if (!error) { - driver->major = MAJOR(dev); - driver->minor_start = MINOR(dev); - } - } else { - dev = MKDEV(driver->major, driver->minor_start); - error = register_chrdev_region(dev, driver->num, driver->name); - } - if (error < 0) - goto err; - - if (driver->flags & TTY_DRIVER_DYNAMIC_ALLOC) { - error = tty_cdev_add(driver, dev, 0, driver->num); - if (error) - goto err_unreg_char; - } - - mutex_lock(&tty_mutex); - list_add(&driver->tty_drivers, &tty_drivers); - mutex_unlock(&tty_mutex); - - if (!(driver->flags & TTY_DRIVER_DYNAMIC_DEV)) { - for (i = 0; i < driver->num; i++) { - d = tty_register_device(driver, i, NULL); - if (IS_ERR(d)) { - error = PTR_ERR(d); - goto err_unreg_devs; - } - } - } - proc_tty_register_driver(driver); - driver->flags |= TTY_DRIVER_INSTALLED; - return 0; - -err_unreg_devs: - for (i--; i >= 0; i--) - tty_unregister_device(driver, i); - - mutex_lock(&tty_mutex); - list_del(&driver->tty_drivers); - mutex_unlock(&tty_mutex); - -err_unreg_char: - unregister_chrdev_region(dev, driver->num); -err: - return error; -} -EXPORT_SYMBOL(tty_register_driver); - -/* - * Called by a tty driver to unregister itself. - */ -int tty_unregister_driver(struct tty_driver *driver) -{ -#if 0 - /* FIXME */ - if (driver->refcount) - return -EBUSY; -#endif - unregister_chrdev_region(MKDEV(driver->major, driver->minor_start), - driver->num); - mutex_lock(&tty_mutex); - list_del(&driver->tty_drivers); - mutex_unlock(&tty_mutex); - return 0; -} - -EXPORT_SYMBOL(tty_unregister_driver); - -dev_t tty_devnum(struct tty_struct *tty) -{ - return MKDEV(tty->driver->major, tty->driver->minor_start) + tty->index; -} -EXPORT_SYMBOL(tty_devnum); - -void tty_default_fops(struct file_operations *fops) -{ - *fops = tty_fops; -} - -/* - * Initialize the console device. This is called *early*, so - * we can't necessarily depend on lots of kernel help here. - * Just do some early initializations, and do the complex setup - * later. - */ -void __init console_init(void) -{ - initcall_t *call; - - /* Setup the default TTY line discipline. */ - n_tty_init(); - - /* - * set up the console device so that later boot sequences can - * inform about problems etc.. - */ - call = __con_initcall_start; - while (call < __con_initcall_end) { - (*call)(); - call++; - } -} - -static char *tty_devnode(struct device *dev, umode_t *mode) -{ - if (!mode) - return NULL; - if (dev->devt == MKDEV(TTYAUX_MAJOR, 0) || - dev->devt == MKDEV(TTYAUX_MAJOR, 2)) - *mode = 0666; - return NULL; -} - -static int __init tty_class_init(void) -{ - tty_class = class_create(THIS_MODULE, "tty"); - if (IS_ERR(tty_class)) - return PTR_ERR(tty_class); - tty_class->devnode = tty_devnode; - return 0; -} - -postcore_initcall(tty_class_init); - -/* 3/2004 jmc: why do these devices exist? */ -static struct cdev tty_cdev, console_cdev; - -static ssize_t show_cons_active(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct console *cs[16]; - int i = 0; - struct console *c; - ssize_t count = 0; - - console_lock(); - for_each_console(c) { - if (!c->device) - continue; - if (!c->write) - continue; - if ((c->flags & CON_ENABLED) == 0) - continue; - cs[i++] = c; - if (i >= ARRAY_SIZE(cs)) - break; - } - while (i--) { - int index = cs[i]->index; - struct tty_driver *drv = cs[i]->device(cs[i], &index); - - /* don't resolve tty0 as some programs depend on it */ - if (drv && (cs[i]->index > 0 || drv->major != TTY_MAJOR)) - count += tty_line_name(drv, index, buf + count); - else - count += sprintf(buf + count, "%s%d", - cs[i]->name, cs[i]->index); - - count += sprintf(buf + count, "%c", i ? ' ':'\n'); - } - console_unlock(); - - return count; -} -static DEVICE_ATTR(active, S_IRUGO, show_cons_active, NULL); - -static struct attribute *cons_dev_attrs[] = { - &dev_attr_active.attr, - NULL -}; - -ATTRIBUTE_GROUPS(cons_dev); - -static struct device *consdev; - -void console_sysfs_notify(void) -{ - if (consdev) - sysfs_notify(&consdev->kobj, NULL, "active"); -} - -/* - * Ok, now we can initialize the rest of the tty devices and can count - * on memory allocations, interrupts etc.. - */ -int __init tty_init(void) -{ - cdev_init(&tty_cdev, &tty_fops); - if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) || - register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0) - panic("Couldn't register /dev/tty driver\n"); - device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty"); - - cdev_init(&console_cdev, &console_fops); - if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) || - register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0) - panic("Couldn't register /dev/console driver\n"); - consdev = device_create_with_groups(tty_class, NULL, - MKDEV(TTYAUX_MAJOR, 1), NULL, - cons_dev_groups, "console"); - if (IS_ERR(consdev)) - consdev = NULL; - -#ifdef CONFIG_VT - vty_init(&console_fops); -#endif - return 0; -} - diff --git a/src/linux/drivers/tty/tty_ioctl.c b/src/linux/drivers/tty/tty_ioctl.c deleted file mode 100644 index bf36ac9..0000000 --- a/src/linux/drivers/tty/tty_ioctl.c +++ /dev/null @@ -1,1180 +0,0 @@ -/* - * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds - * - * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines - * which can be dynamically activated and de-activated by the line - * discipline handling modules (like SLIP). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#undef TTY_DEBUG_WAIT_UNTIL_SENT - -#ifdef TTY_DEBUG_WAIT_UNTIL_SENT -# define tty_debug_wait_until_sent(tty, f, args...) tty_debug(tty, f, ##args) -#else -# define tty_debug_wait_until_sent(tty, f, args...) do {} while (0) -#endif - -#undef DEBUG - -/* - * Internal flag options for termios setting behavior - */ -#define TERMIOS_FLUSH 1 -#define TERMIOS_WAIT 2 -#define TERMIOS_TERMIO 4 -#define TERMIOS_OLD 8 - - -/** - * tty_chars_in_buffer - characters pending - * @tty: terminal - * - * Return the number of bytes of data in the device private - * output queue. If no private method is supplied there is assumed - * to be no queue on the device. - */ - -int tty_chars_in_buffer(struct tty_struct *tty) -{ - if (tty->ops->chars_in_buffer) - return tty->ops->chars_in_buffer(tty); - else - return 0; -} -EXPORT_SYMBOL(tty_chars_in_buffer); - -/** - * tty_write_room - write queue space - * @tty: terminal - * - * Return the number of bytes that can be queued to this device - * at the present time. The result should be treated as a guarantee - * and the driver cannot offer a value it later shrinks by more than - * the number of bytes written. If no method is provided 2K is always - * returned and data may be lost as there will be no flow control. - */ - -int tty_write_room(struct tty_struct *tty) -{ - if (tty->ops->write_room) - return tty->ops->write_room(tty); - return 2048; -} -EXPORT_SYMBOL(tty_write_room); - -/** - * tty_driver_flush_buffer - discard internal buffer - * @tty: terminal - * - * Discard the internal output buffer for this device. If no method - * is provided then either the buffer cannot be hardware flushed or - * there is no buffer driver side. - */ -void tty_driver_flush_buffer(struct tty_struct *tty) -{ - if (tty->ops->flush_buffer) - tty->ops->flush_buffer(tty); -} -EXPORT_SYMBOL(tty_driver_flush_buffer); - -/** - * tty_throttle - flow control - * @tty: terminal - * - * Indicate that a tty should stop transmitting data down the stack. - * Takes the termios rwsem to protect against parallel throttle/unthrottle - * and also to ensure the driver can consistently reference its own - * termios data at this point when implementing software flow control. - */ - -void tty_throttle(struct tty_struct *tty) -{ - down_write(&tty->termios_rwsem); - /* check TTY_THROTTLED first so it indicates our state */ - if (!test_and_set_bit(TTY_THROTTLED, &tty->flags) && - tty->ops->throttle) - tty->ops->throttle(tty); - tty->flow_change = 0; - up_write(&tty->termios_rwsem); -} -EXPORT_SYMBOL(tty_throttle); - -/** - * tty_unthrottle - flow control - * @tty: terminal - * - * Indicate that a tty may continue transmitting data down the stack. - * Takes the termios rwsem to protect against parallel throttle/unthrottle - * and also to ensure the driver can consistently reference its own - * termios data at this point when implementing software flow control. - * - * Drivers should however remember that the stack can issue a throttle, - * then change flow control method, then unthrottle. - */ - -void tty_unthrottle(struct tty_struct *tty) -{ - down_write(&tty->termios_rwsem); - if (test_and_clear_bit(TTY_THROTTLED, &tty->flags) && - tty->ops->unthrottle) - tty->ops->unthrottle(tty); - tty->flow_change = 0; - up_write(&tty->termios_rwsem); -} -EXPORT_SYMBOL(tty_unthrottle); - -/** - * tty_throttle_safe - flow control - * @tty: terminal - * - * Similar to tty_throttle() but will only attempt throttle - * if tty->flow_change is TTY_THROTTLE_SAFE. Prevents an accidental - * throttle due to race conditions when throttling is conditional - * on factors evaluated prior to throttling. - * - * Returns 0 if tty is throttled (or was already throttled) - */ - -int tty_throttle_safe(struct tty_struct *tty) -{ - int ret = 0; - - mutex_lock(&tty->throttle_mutex); - if (!tty_throttled(tty)) { - if (tty->flow_change != TTY_THROTTLE_SAFE) - ret = 1; - else { - set_bit(TTY_THROTTLED, &tty->flags); - if (tty->ops->throttle) - tty->ops->throttle(tty); - } - } - mutex_unlock(&tty->throttle_mutex); - - return ret; -} - -/** - * tty_unthrottle_safe - flow control - * @tty: terminal - * - * Similar to tty_unthrottle() but will only attempt unthrottle - * if tty->flow_change is TTY_UNTHROTTLE_SAFE. Prevents an accidental - * unthrottle due to race conditions when unthrottling is conditional - * on factors evaluated prior to unthrottling. - * - * Returns 0 if tty is unthrottled (or was already unthrottled) - */ - -int tty_unthrottle_safe(struct tty_struct *tty) -{ - int ret = 0; - - mutex_lock(&tty->throttle_mutex); - if (tty_throttled(tty)) { - if (tty->flow_change != TTY_UNTHROTTLE_SAFE) - ret = 1; - else { - clear_bit(TTY_THROTTLED, &tty->flags); - if (tty->ops->unthrottle) - tty->ops->unthrottle(tty); - } - } - mutex_unlock(&tty->throttle_mutex); - - return ret; -} - -/** - * tty_wait_until_sent - wait for I/O to finish - * @tty: tty we are waiting for - * @timeout: how long we will wait - * - * Wait for characters pending in a tty driver to hit the wire, or - * for a timeout to occur (eg due to flow control) - * - * Locking: none - */ - -void tty_wait_until_sent(struct tty_struct *tty, long timeout) -{ - tty_debug_wait_until_sent(tty, "wait until sent, timeout=%ld\n", timeout); - - if (!timeout) - timeout = MAX_SCHEDULE_TIMEOUT; - - timeout = wait_event_interruptible_timeout(tty->write_wait, - !tty_chars_in_buffer(tty), timeout); - if (timeout <= 0) - return; - - if (timeout == MAX_SCHEDULE_TIMEOUT) - timeout = 0; - - if (tty->ops->wait_until_sent) - tty->ops->wait_until_sent(tty, timeout); -} -EXPORT_SYMBOL(tty_wait_until_sent); - - -/* - * Termios Helper Methods - */ - -static void unset_locked_termios(struct tty_struct *tty, struct ktermios *old) -{ - struct ktermios *termios = &tty->termios; - struct ktermios *locked = &tty->termios_locked; - int i; - -#define NOSET_MASK(x, y, z) (x = ((x) & ~(z)) | ((y) & (z))) - - NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag); - NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag); - NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag); - NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag); - termios->c_line = locked->c_line ? old->c_line : termios->c_line; - for (i = 0; i < NCCS; i++) - termios->c_cc[i] = locked->c_cc[i] ? - old->c_cc[i] : termios->c_cc[i]; - /* FIXME: What should we do for i/ospeed */ -} - -/* - * Routine which returns the baud rate of the tty - * - * Note that the baud_table needs to be kept in sync with the - * include/asm/termbits.h file. - */ -static const speed_t baud_table[] = { - 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, - 9600, 19200, 38400, 57600, 115200, 230400, 460800, -#ifdef __sparc__ - 76800, 153600, 307200, 614400, 921600 -#else - 500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000, - 2500000, 3000000, 3500000, 4000000 -#endif -}; - -#ifndef __sparc__ -static const tcflag_t baud_bits[] = { - B0, B50, B75, B110, B134, B150, B200, B300, B600, - B1200, B1800, B2400, B4800, B9600, B19200, B38400, - B57600, B115200, B230400, B460800, B500000, B576000, - B921600, B1000000, B1152000, B1500000, B2000000, B2500000, - B3000000, B3500000, B4000000 -}; -#else -static const tcflag_t baud_bits[] = { - B0, B50, B75, B110, B134, B150, B200, B300, B600, - B1200, B1800, B2400, B4800, B9600, B19200, B38400, - B57600, B115200, B230400, B460800, B76800, B153600, - B307200, B614400, B921600 -}; -#endif - -static int n_baud_table = ARRAY_SIZE(baud_table); - -/** - * tty_termios_baud_rate - * @termios: termios structure - * - * Convert termios baud rate data into a speed. This should be called - * with the termios lock held if this termios is a terminal termios - * structure. May change the termios data. Device drivers can call this - * function but should use ->c_[io]speed directly as they are updated. - * - * Locking: none - */ - -speed_t tty_termios_baud_rate(struct ktermios *termios) -{ - unsigned int cbaud; - - cbaud = termios->c_cflag & CBAUD; - -#ifdef BOTHER - /* Magic token for arbitrary speed via c_ispeed/c_ospeed */ - if (cbaud == BOTHER) - return termios->c_ospeed; -#endif - if (cbaud & CBAUDEX) { - cbaud &= ~CBAUDEX; - - if (cbaud < 1 || cbaud + 15 > n_baud_table) - termios->c_cflag &= ~CBAUDEX; - else - cbaud += 15; - } - return baud_table[cbaud]; -} -EXPORT_SYMBOL(tty_termios_baud_rate); - -/** - * tty_termios_input_baud_rate - * @termios: termios structure - * - * Convert termios baud rate data into a speed. This should be called - * with the termios lock held if this termios is a terminal termios - * structure. May change the termios data. Device drivers can call this - * function but should use ->c_[io]speed directly as they are updated. - * - * Locking: none - */ - -speed_t tty_termios_input_baud_rate(struct ktermios *termios) -{ -#ifdef IBSHIFT - unsigned int cbaud = (termios->c_cflag >> IBSHIFT) & CBAUD; - - if (cbaud == B0) - return tty_termios_baud_rate(termios); - - /* Magic token for arbitrary speed via c_ispeed*/ - if (cbaud == BOTHER) - return termios->c_ispeed; - - if (cbaud & CBAUDEX) { - cbaud &= ~CBAUDEX; - - if (cbaud < 1 || cbaud + 15 > n_baud_table) - termios->c_cflag &= ~(CBAUDEX << IBSHIFT); - else - cbaud += 15; - } - return baud_table[cbaud]; -#else - return tty_termios_baud_rate(termios); -#endif -} -EXPORT_SYMBOL(tty_termios_input_baud_rate); - -/** - * tty_termios_encode_baud_rate - * @termios: ktermios structure holding user requested state - * @ispeed: input speed - * @ospeed: output speed - * - * Encode the speeds set into the passed termios structure. This is - * used as a library helper for drivers so that they can report back - * the actual speed selected when it differs from the speed requested - * - * For maximal back compatibility with legacy SYS5/POSIX *nix behaviour - * we need to carefully set the bits when the user does not get the - * desired speed. We allow small margins and preserve as much of possible - * of the input intent to keep compatibility. - * - * Locking: Caller should hold termios lock. This is already held - * when calling this function from the driver termios handler. - * - * The ifdefs deal with platforms whose owners have yet to update them - * and will all go away once this is done. - */ - -void tty_termios_encode_baud_rate(struct ktermios *termios, - speed_t ibaud, speed_t obaud) -{ - int i = 0; - int ifound = -1, ofound = -1; - int iclose = ibaud/50, oclose = obaud/50; - int ibinput = 0; - - if (obaud == 0) /* CD dropped */ - ibaud = 0; /* Clear ibaud to be sure */ - - termios->c_ispeed = ibaud; - termios->c_ospeed = obaud; - -#ifdef BOTHER - /* If the user asked for a precise weird speed give a precise weird - answer. If they asked for a Bfoo speed they may have problems - digesting non-exact replies so fuzz a bit */ - - if ((termios->c_cflag & CBAUD) == BOTHER) - oclose = 0; - if (((termios->c_cflag >> IBSHIFT) & CBAUD) == BOTHER) - iclose = 0; - if ((termios->c_cflag >> IBSHIFT) & CBAUD) - ibinput = 1; /* An input speed was specified */ -#endif - termios->c_cflag &= ~CBAUD; - - /* - * Our goal is to find a close match to the standard baud rate - * returned. Walk the baud rate table and if we get a very close - * match then report back the speed as a POSIX Bxxxx value by - * preference - */ - - do { - if (obaud - oclose <= baud_table[i] && - obaud + oclose >= baud_table[i]) { - termios->c_cflag |= baud_bits[i]; - ofound = i; - } - if (ibaud - iclose <= baud_table[i] && - ibaud + iclose >= baud_table[i]) { - /* For the case input == output don't set IBAUD bits - if the user didn't do so */ - if (ofound == i && !ibinput) - ifound = i; -#ifdef IBSHIFT - else { - ifound = i; - termios->c_cflag |= (baud_bits[i] << IBSHIFT); - } -#endif - } - } while (++i < n_baud_table); - - /* - * If we found no match then use BOTHER if provided or warn - * the user their platform maintainer needs to wake up if not. - */ -#ifdef BOTHER - if (ofound == -1) - termios->c_cflag |= BOTHER; - /* Set exact input bits only if the input and output differ or the - user already did */ - if (ifound == -1 && (ibaud != obaud || ibinput)) - termios->c_cflag |= (BOTHER << IBSHIFT); -#else - if (ifound == -1 || ofound == -1) - pr_warn_once("tty: Unable to return correct speed data as your architecture needs updating.\n"); -#endif -} -EXPORT_SYMBOL_GPL(tty_termios_encode_baud_rate); - -/** - * tty_encode_baud_rate - set baud rate of the tty - * @ibaud: input baud rate - * @obad: output baud rate - * - * Update the current termios data for the tty with the new speed - * settings. The caller must hold the termios_rwsem for the tty in - * question. - */ - -void tty_encode_baud_rate(struct tty_struct *tty, speed_t ibaud, speed_t obaud) -{ - tty_termios_encode_baud_rate(&tty->termios, ibaud, obaud); -} -EXPORT_SYMBOL_GPL(tty_encode_baud_rate); - -/** - * tty_termios_copy_hw - copy hardware settings - * @new: New termios - * @old: Old termios - * - * Propagate the hardware specific terminal setting bits from - * the old termios structure to the new one. This is used in cases - * where the hardware does not support reconfiguration or as a helper - * in some cases where only minimal reconfiguration is supported - */ - -void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old) -{ - /* The bits a dumb device handles in software. Smart devices need - to always provide a set_termios method */ - new->c_cflag &= HUPCL | CREAD | CLOCAL; - new->c_cflag |= old->c_cflag & ~(HUPCL | CREAD | CLOCAL); - new->c_ispeed = old->c_ispeed; - new->c_ospeed = old->c_ospeed; -} -EXPORT_SYMBOL(tty_termios_copy_hw); - -/** - * tty_termios_hw_change - check for setting change - * @a: termios - * @b: termios to compare - * - * Check if any of the bits that affect a dumb device have changed - * between the two termios structures, or a speed change is needed. - */ - -int tty_termios_hw_change(struct ktermios *a, struct ktermios *b) -{ - if (a->c_ispeed != b->c_ispeed || a->c_ospeed != b->c_ospeed) - return 1; - if ((a->c_cflag ^ b->c_cflag) & ~(HUPCL | CREAD | CLOCAL)) - return 1; - return 0; -} -EXPORT_SYMBOL(tty_termios_hw_change); - -/** - * tty_set_termios - update termios values - * @tty: tty to update - * @new_termios: desired new value - * - * Perform updates to the termios values set on this terminal. - * A master pty's termios should never be set. - * - * Locking: termios_rwsem - */ - -int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios) -{ - struct ktermios old_termios; - struct tty_ldisc *ld; - - WARN_ON(tty->driver->type == TTY_DRIVER_TYPE_PTY && - tty->driver->subtype == PTY_TYPE_MASTER); - /* - * Perform the actual termios internal changes under lock. - */ - - - /* FIXME: we need to decide on some locking/ordering semantics - for the set_termios notification eventually */ - down_write(&tty->termios_rwsem); - old_termios = tty->termios; - tty->termios = *new_termios; - unset_locked_termios(tty, &old_termios); - - if (tty->ops->set_termios) - tty->ops->set_termios(tty, &old_termios); - else - tty_termios_copy_hw(&tty->termios, &old_termios); - - ld = tty_ldisc_ref(tty); - if (ld != NULL) { - if (ld->ops->set_termios) - ld->ops->set_termios(tty, &old_termios); - tty_ldisc_deref(ld); - } - up_write(&tty->termios_rwsem); - return 0; -} -EXPORT_SYMBOL_GPL(tty_set_termios); - -/** - * set_termios - set termios values for a tty - * @tty: terminal device - * @arg: user data - * @opt: option information - * - * Helper function to prepare termios data and run necessary other - * functions before using tty_set_termios to do the actual changes. - * - * Locking: - * Called functions take ldisc and termios_rwsem locks - */ - -static int set_termios(struct tty_struct *tty, void __user *arg, int opt) -{ - struct ktermios tmp_termios; - struct tty_ldisc *ld; - int retval = tty_check_change(tty); - - if (retval) - return retval; - - down_read(&tty->termios_rwsem); - tmp_termios = tty->termios; - up_read(&tty->termios_rwsem); - - if (opt & TERMIOS_TERMIO) { - if (user_termio_to_kernel_termios(&tmp_termios, - (struct termio __user *)arg)) - return -EFAULT; -#ifdef TCGETS2 - } else if (opt & TERMIOS_OLD) { - if (user_termios_to_kernel_termios_1(&tmp_termios, - (struct termios __user *)arg)) - return -EFAULT; - } else { - if (user_termios_to_kernel_termios(&tmp_termios, - (struct termios2 __user *)arg)) - return -EFAULT; - } -#else - } else if (user_termios_to_kernel_termios(&tmp_termios, - (struct termios __user *)arg)) - return -EFAULT; -#endif - - /* If old style Bfoo values are used then load c_ispeed/c_ospeed - * with the real speed so its unconditionally usable */ - tmp_termios.c_ispeed = tty_termios_input_baud_rate(&tmp_termios); - tmp_termios.c_ospeed = tty_termios_baud_rate(&tmp_termios); - - ld = tty_ldisc_ref(tty); - - if (ld != NULL) { - if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer) - ld->ops->flush_buffer(tty); - tty_ldisc_deref(ld); - } - - if (opt & TERMIOS_WAIT) { - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -ERESTARTSYS; - } - - tty_set_termios(tty, &tmp_termios); - - /* FIXME: Arguably if tmp_termios == tty->termios AND the - actual requested termios was not tmp_termios then we may - want to return an error as no user requested change has - succeeded */ - return 0; -} - -static void copy_termios(struct tty_struct *tty, struct ktermios *kterm) -{ - down_read(&tty->termios_rwsem); - *kterm = tty->termios; - up_read(&tty->termios_rwsem); -} - -static void copy_termios_locked(struct tty_struct *tty, struct ktermios *kterm) -{ - down_read(&tty->termios_rwsem); - *kterm = tty->termios_locked; - up_read(&tty->termios_rwsem); -} - -static int get_termio(struct tty_struct *tty, struct termio __user *termio) -{ - struct ktermios kterm; - copy_termios(tty, &kterm); - if (kernel_termios_to_user_termio(termio, &kterm)) - return -EFAULT; - return 0; -} - - -#ifdef TCGETX - -/** - * set_termiox - set termiox fields if possible - * @tty: terminal - * @arg: termiox structure from user - * @opt: option flags for ioctl type - * - * Implement the device calling points for the SYS5 termiox ioctl - * interface in Linux - */ - -static int set_termiox(struct tty_struct *tty, void __user *arg, int opt) -{ - struct termiox tnew; - struct tty_ldisc *ld; - - if (tty->termiox == NULL) - return -EINVAL; - if (copy_from_user(&tnew, arg, sizeof(struct termiox))) - return -EFAULT; - - ld = tty_ldisc_ref(tty); - if (ld != NULL) { - if ((opt & TERMIOS_FLUSH) && ld->ops->flush_buffer) - ld->ops->flush_buffer(tty); - tty_ldisc_deref(ld); - } - if (opt & TERMIOS_WAIT) { - tty_wait_until_sent(tty, 0); - if (signal_pending(current)) - return -ERESTARTSYS; - } - - down_write(&tty->termios_rwsem); - if (tty->ops->set_termiox) - tty->ops->set_termiox(tty, &tnew); - up_write(&tty->termios_rwsem); - return 0; -} - -#endif - - -#ifdef TIOCGETP -/* - * These are deprecated, but there is limited support.. - * - * The "sg_flags" translation is a joke.. - */ -static int get_sgflags(struct tty_struct *tty) -{ - int flags = 0; - - if (!L_ICANON(tty)) { - if (L_ISIG(tty)) - flags |= 0x02; /* cbreak */ - else - flags |= 0x20; /* raw */ - } - if (L_ECHO(tty)) - flags |= 0x08; /* echo */ - if (O_OPOST(tty)) - if (O_ONLCR(tty)) - flags |= 0x10; /* crmod */ - return flags; -} - -static int get_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) -{ - struct sgttyb tmp; - - down_read(&tty->termios_rwsem); - tmp.sg_ispeed = tty->termios.c_ispeed; - tmp.sg_ospeed = tty->termios.c_ospeed; - tmp.sg_erase = tty->termios.c_cc[VERASE]; - tmp.sg_kill = tty->termios.c_cc[VKILL]; - tmp.sg_flags = get_sgflags(tty); - up_read(&tty->termios_rwsem); - - return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0; -} - -static void set_sgflags(struct ktermios *termios, int flags) -{ - termios->c_iflag = ICRNL | IXON; - termios->c_oflag = 0; - termios->c_lflag = ISIG | ICANON; - if (flags & 0x02) { /* cbreak */ - termios->c_iflag = 0; - termios->c_lflag &= ~ICANON; - } - if (flags & 0x08) { /* echo */ - termios->c_lflag |= ECHO | ECHOE | ECHOK | - ECHOCTL | ECHOKE | IEXTEN; - } - if (flags & 0x10) { /* crmod */ - termios->c_oflag |= OPOST | ONLCR; - } - if (flags & 0x20) { /* raw */ - termios->c_iflag = 0; - termios->c_lflag &= ~(ISIG | ICANON); - } - if (!(termios->c_lflag & ICANON)) { - termios->c_cc[VMIN] = 1; - termios->c_cc[VTIME] = 0; - } -} - -/** - * set_sgttyb - set legacy terminal values - * @tty: tty structure - * @sgttyb: pointer to old style terminal structure - * - * Updates a terminal from the legacy BSD style terminal information - * structure. - * - * Locking: termios_rwsem - */ - -static int set_sgttyb(struct tty_struct *tty, struct sgttyb __user *sgttyb) -{ - int retval; - struct sgttyb tmp; - struct ktermios termios; - - retval = tty_check_change(tty); - if (retval) - return retval; - - if (copy_from_user(&tmp, sgttyb, sizeof(tmp))) - return -EFAULT; - - down_write(&tty->termios_rwsem); - termios = tty->termios; - termios.c_cc[VERASE] = tmp.sg_erase; - termios.c_cc[VKILL] = tmp.sg_kill; - set_sgflags(&termios, tmp.sg_flags); - /* Try and encode into Bfoo format */ -#ifdef BOTHER - tty_termios_encode_baud_rate(&termios, termios.c_ispeed, - termios.c_ospeed); -#endif - up_write(&tty->termios_rwsem); - tty_set_termios(tty, &termios); - return 0; -} -#endif - -#ifdef TIOCGETC -static int get_tchars(struct tty_struct *tty, struct tchars __user *tchars) -{ - struct tchars tmp; - - down_read(&tty->termios_rwsem); - tmp.t_intrc = tty->termios.c_cc[VINTR]; - tmp.t_quitc = tty->termios.c_cc[VQUIT]; - tmp.t_startc = tty->termios.c_cc[VSTART]; - tmp.t_stopc = tty->termios.c_cc[VSTOP]; - tmp.t_eofc = tty->termios.c_cc[VEOF]; - tmp.t_brkc = tty->termios.c_cc[VEOL2]; /* what is brkc anyway? */ - up_read(&tty->termios_rwsem); - return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0; -} - -static int set_tchars(struct tty_struct *tty, struct tchars __user *tchars) -{ - struct tchars tmp; - - if (copy_from_user(&tmp, tchars, sizeof(tmp))) - return -EFAULT; - down_write(&tty->termios_rwsem); - tty->termios.c_cc[VINTR] = tmp.t_intrc; - tty->termios.c_cc[VQUIT] = tmp.t_quitc; - tty->termios.c_cc[VSTART] = tmp.t_startc; - tty->termios.c_cc[VSTOP] = tmp.t_stopc; - tty->termios.c_cc[VEOF] = tmp.t_eofc; - tty->termios.c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */ - up_write(&tty->termios_rwsem); - return 0; -} -#endif - -#ifdef TIOCGLTC -static int get_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) -{ - struct ltchars tmp; - - down_read(&tty->termios_rwsem); - tmp.t_suspc = tty->termios.c_cc[VSUSP]; - /* what is dsuspc anyway? */ - tmp.t_dsuspc = tty->termios.c_cc[VSUSP]; - tmp.t_rprntc = tty->termios.c_cc[VREPRINT]; - /* what is flushc anyway? */ - tmp.t_flushc = tty->termios.c_cc[VEOL2]; - tmp.t_werasc = tty->termios.c_cc[VWERASE]; - tmp.t_lnextc = tty->termios.c_cc[VLNEXT]; - up_read(&tty->termios_rwsem); - return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0; -} - -static int set_ltchars(struct tty_struct *tty, struct ltchars __user *ltchars) -{ - struct ltchars tmp; - - if (copy_from_user(&tmp, ltchars, sizeof(tmp))) - return -EFAULT; - - down_write(&tty->termios_rwsem); - tty->termios.c_cc[VSUSP] = tmp.t_suspc; - /* what is dsuspc anyway? */ - tty->termios.c_cc[VEOL2] = tmp.t_dsuspc; - tty->termios.c_cc[VREPRINT] = tmp.t_rprntc; - /* what is flushc anyway? */ - tty->termios.c_cc[VEOL2] = tmp.t_flushc; - tty->termios.c_cc[VWERASE] = tmp.t_werasc; - tty->termios.c_cc[VLNEXT] = tmp.t_lnextc; - up_write(&tty->termios_rwsem); - return 0; -} -#endif - -/** - * tty_change_softcar - carrier change ioctl helper - * @tty: tty to update - * @arg: enable/disable CLOCAL - * - * Perform a change to the CLOCAL state and call into the driver - * layer to make it visible. All done with the termios rwsem - */ - -static int tty_change_softcar(struct tty_struct *tty, int arg) -{ - int ret = 0; - int bit = arg ? CLOCAL : 0; - struct ktermios old; - - down_write(&tty->termios_rwsem); - old = tty->termios; - tty->termios.c_cflag &= ~CLOCAL; - tty->termios.c_cflag |= bit; - if (tty->ops->set_termios) - tty->ops->set_termios(tty, &old); - if (C_CLOCAL(tty) != bit) - ret = -EINVAL; - up_write(&tty->termios_rwsem); - return ret; -} - -/** - * tty_mode_ioctl - mode related ioctls - * @tty: tty for the ioctl - * @file: file pointer for the tty - * @cmd: command - * @arg: ioctl argument - * - * Perform non line discipline specific mode control ioctls. This - * is designed to be called by line disciplines to ensure they provide - * consistent mode setting. - */ - -int tty_mode_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct tty_struct *real_tty; - void __user *p = (void __user *)arg; - int ret = 0; - struct ktermios kterm; - - BUG_ON(file == NULL); - - if (tty->driver->type == TTY_DRIVER_TYPE_PTY && - tty->driver->subtype == PTY_TYPE_MASTER) - real_tty = tty->link; - else - real_tty = tty; - - switch (cmd) { -#ifdef TIOCGETP - case TIOCGETP: - return get_sgttyb(real_tty, (struct sgttyb __user *) arg); - case TIOCSETP: - case TIOCSETN: - return set_sgttyb(real_tty, (struct sgttyb __user *) arg); -#endif -#ifdef TIOCGETC - case TIOCGETC: - return get_tchars(real_tty, p); - case TIOCSETC: - return set_tchars(real_tty, p); -#endif -#ifdef TIOCGLTC - case TIOCGLTC: - return get_ltchars(real_tty, p); - case TIOCSLTC: - return set_ltchars(real_tty, p); -#endif - case TCSETSF: - return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_OLD); - case TCSETSW: - return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_OLD); - case TCSETS: - return set_termios(real_tty, p, TERMIOS_OLD); -#ifndef TCGETS2 - case TCGETS: - copy_termios(real_tty, &kterm); - if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm)) - ret = -EFAULT; - return ret; -#else - case TCGETS: - copy_termios(real_tty, &kterm); - if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm)) - ret = -EFAULT; - return ret; - case TCGETS2: - copy_termios(real_tty, &kterm); - if (kernel_termios_to_user_termios((struct termios2 __user *)arg, &kterm)) - ret = -EFAULT; - return ret; - case TCSETSF2: - return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT); - case TCSETSW2: - return set_termios(real_tty, p, TERMIOS_WAIT); - case TCSETS2: - return set_termios(real_tty, p, 0); -#endif - case TCGETA: - return get_termio(real_tty, p); - case TCSETAF: - return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO); - case TCSETAW: - return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO); - case TCSETA: - return set_termios(real_tty, p, TERMIOS_TERMIO); -#ifndef TCGETS2 - case TIOCGLCKTRMIOS: - copy_termios_locked(real_tty, &kterm); - if (kernel_termios_to_user_termios((struct termios __user *)arg, &kterm)) - ret = -EFAULT; - return ret; - case TIOCSLCKTRMIOS: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - copy_termios_locked(real_tty, &kterm); - if (user_termios_to_kernel_termios(&kterm, - (struct termios __user *) arg)) - return -EFAULT; - down_write(&real_tty->termios_rwsem); - real_tty->termios_locked = kterm; - up_write(&real_tty->termios_rwsem); - return 0; -#else - case TIOCGLCKTRMIOS: - copy_termios_locked(real_tty, &kterm); - if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &kterm)) - ret = -EFAULT; - return ret; - case TIOCSLCKTRMIOS: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - copy_termios_locked(real_tty, &kterm); - if (user_termios_to_kernel_termios_1(&kterm, - (struct termios __user *) arg)) - return -EFAULT; - down_write(&real_tty->termios_rwsem); - real_tty->termios_locked = kterm; - up_write(&real_tty->termios_rwsem); - return ret; -#endif -#ifdef TCGETX - case TCGETX: { - struct termiox ktermx; - if (real_tty->termiox == NULL) - return -EINVAL; - down_read(&real_tty->termios_rwsem); - memcpy(&ktermx, real_tty->termiox, sizeof(struct termiox)); - up_read(&real_tty->termios_rwsem); - if (copy_to_user(p, &ktermx, sizeof(struct termiox))) - ret = -EFAULT; - return ret; - } - case TCSETX: - return set_termiox(real_tty, p, 0); - case TCSETXW: - return set_termiox(real_tty, p, TERMIOS_WAIT); - case TCSETXF: - return set_termiox(real_tty, p, TERMIOS_FLUSH); -#endif - case TIOCGSOFTCAR: - copy_termios(real_tty, &kterm); - ret = put_user((kterm.c_cflag & CLOCAL) ? 1 : 0, - (int __user *)arg); - return ret; - case TIOCSSOFTCAR: - if (get_user(arg, (unsigned int __user *) arg)) - return -EFAULT; - return tty_change_softcar(real_tty, arg); - default: - return -ENOIOCTLCMD; - } -} -EXPORT_SYMBOL_GPL(tty_mode_ioctl); - - -/* Caller guarantees ldisc reference is held */ -static int __tty_perform_flush(struct tty_struct *tty, unsigned long arg) -{ - struct tty_ldisc *ld = tty->ldisc; - - switch (arg) { - case TCIFLUSH: - if (ld && ld->ops->flush_buffer) { - ld->ops->flush_buffer(tty); - tty_unthrottle(tty); - } - break; - case TCIOFLUSH: - if (ld && ld->ops->flush_buffer) { - ld->ops->flush_buffer(tty); - tty_unthrottle(tty); - } - /* fall through */ - case TCOFLUSH: - tty_driver_flush_buffer(tty); - break; - default: - return -EINVAL; - } - return 0; -} - -int tty_perform_flush(struct tty_struct *tty, unsigned long arg) -{ - struct tty_ldisc *ld; - int retval = tty_check_change(tty); - if (retval) - return retval; - - ld = tty_ldisc_ref_wait(tty); - retval = __tty_perform_flush(tty, arg); - if (ld) - tty_ldisc_deref(ld); - return retval; -} -EXPORT_SYMBOL_GPL(tty_perform_flush); - -int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - int retval; - - switch (cmd) { - case TCXONC: - retval = tty_check_change(tty); - if (retval) - return retval; - switch (arg) { - case TCOOFF: - spin_lock_irq(&tty->flow_lock); - if (!tty->flow_stopped) { - tty->flow_stopped = 1; - __stop_tty(tty); - } - spin_unlock_irq(&tty->flow_lock); - break; - case TCOON: - spin_lock_irq(&tty->flow_lock); - if (tty->flow_stopped) { - tty->flow_stopped = 0; - __start_tty(tty); - } - spin_unlock_irq(&tty->flow_lock); - break; - case TCIOFF: - if (STOP_CHAR(tty) != __DISABLED_CHAR) - retval = tty_send_xchar(tty, STOP_CHAR(tty)); - break; - case TCION: - if (START_CHAR(tty) != __DISABLED_CHAR) - retval = tty_send_xchar(tty, START_CHAR(tty)); - break; - default: - return -EINVAL; - } - return retval; - case TCFLSH: - retval = tty_check_change(tty); - if (retval) - return retval; - return __tty_perform_flush(tty, arg); - default: - /* Try the mode commands */ - return tty_mode_ioctl(tty, file, cmd, arg); - } -} -EXPORT_SYMBOL(n_tty_ioctl_helper); - -#ifdef CONFIG_COMPAT -long n_tty_compat_ioctl_helper(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case TIOCGLCKTRMIOS: - case TIOCSLCKTRMIOS: - return tty_mode_ioctl(tty, file, cmd, (unsigned long) compat_ptr(arg)); - default: - return -ENOIOCTLCMD; - } -} -EXPORT_SYMBOL(n_tty_compat_ioctl_helper); -#endif - diff --git a/src/linux/drivers/tty/tty_ldisc.c b/src/linux/drivers/tty/tty_ldisc.c deleted file mode 100644 index 68947f6..0000000 --- a/src/linux/drivers/tty/tty_ldisc.c +++ /dev/null @@ -1,826 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#undef LDISC_DEBUG_HANGUP - -#ifdef LDISC_DEBUG_HANGUP -#define tty_ldisc_debug(tty, f, args...) tty_debug(tty, f, ##args) -#else -#define tty_ldisc_debug(tty, f, args...) -#endif - -/* lockdep nested classes for tty->ldisc_sem */ -enum { - LDISC_SEM_NORMAL, - LDISC_SEM_OTHER, -}; - - -/* - * This guards the refcounted line discipline lists. The lock - * must be taken with irqs off because there are hangup path - * callers who will do ldisc lookups and cannot sleep. - */ - -static DEFINE_RAW_SPINLOCK(tty_ldiscs_lock); -/* Line disc dispatch table */ -static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; - -/** - * tty_register_ldisc - install a line discipline - * @disc: ldisc number - * @new_ldisc: pointer to the ldisc object - * - * Installs a new line discipline into the kernel. The discipline - * is set up as unreferenced and then made available to the kernel - * from this point onwards. - * - * Locking: - * takes tty_ldiscs_lock to guard against ldisc races - */ - -int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc) -{ - unsigned long flags; - int ret = 0; - - if (disc < N_TTY || disc >= NR_LDISCS) - return -EINVAL; - - raw_spin_lock_irqsave(&tty_ldiscs_lock, flags); - tty_ldiscs[disc] = new_ldisc; - new_ldisc->num = disc; - new_ldisc->refcount = 0; - raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags); - - return ret; -} -EXPORT_SYMBOL(tty_register_ldisc); - -/** - * tty_unregister_ldisc - unload a line discipline - * @disc: ldisc number - * @new_ldisc: pointer to the ldisc object - * - * Remove a line discipline from the kernel providing it is not - * currently in use. - * - * Locking: - * takes tty_ldiscs_lock to guard against ldisc races - */ - -int tty_unregister_ldisc(int disc) -{ - unsigned long flags; - int ret = 0; - - if (disc < N_TTY || disc >= NR_LDISCS) - return -EINVAL; - - raw_spin_lock_irqsave(&tty_ldiscs_lock, flags); - if (tty_ldiscs[disc]->refcount) - ret = -EBUSY; - else - tty_ldiscs[disc] = NULL; - raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags); - - return ret; -} -EXPORT_SYMBOL(tty_unregister_ldisc); - -static struct tty_ldisc_ops *get_ldops(int disc) -{ - unsigned long flags; - struct tty_ldisc_ops *ldops, *ret; - - raw_spin_lock_irqsave(&tty_ldiscs_lock, flags); - ret = ERR_PTR(-EINVAL); - ldops = tty_ldiscs[disc]; - if (ldops) { - ret = ERR_PTR(-EAGAIN); - if (try_module_get(ldops->owner)) { - ldops->refcount++; - ret = ldops; - } - } - raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags); - return ret; -} - -static void put_ldops(struct tty_ldisc_ops *ldops) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&tty_ldiscs_lock, flags); - ldops->refcount--; - module_put(ldops->owner); - raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags); -} - -/** - * tty_ldisc_get - take a reference to an ldisc - * @disc: ldisc number - * - * Takes a reference to a line discipline. Deals with refcounts and - * module locking counts. - * - * Returns: -EINVAL if the discipline index is not [N_TTY..NR_LDISCS] or - * if the discipline is not registered - * -EAGAIN if request_module() failed to load or register the - * the discipline - * -ENOMEM if allocation failure - * - * Otherwise, returns a pointer to the discipline and bumps the - * ref count - * - * Locking: - * takes tty_ldiscs_lock to guard against ldisc races - */ - -static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc) -{ - struct tty_ldisc *ld; - struct tty_ldisc_ops *ldops; - - if (disc < N_TTY || disc >= NR_LDISCS) - return ERR_PTR(-EINVAL); - - /* - * Get the ldisc ops - we may need to request them to be loaded - * dynamically and try again. - */ - ldops = get_ldops(disc); - if (IS_ERR(ldops)) { - request_module("tty-ldisc-%d", disc); - ldops = get_ldops(disc); - if (IS_ERR(ldops)) - return ERR_CAST(ldops); - } - - ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL); - if (ld == NULL) { - put_ldops(ldops); - return ERR_PTR(-ENOMEM); - } - - ld->ops = ldops; - ld->tty = tty; - - return ld; -} - -/** - * tty_ldisc_put - release the ldisc - * - * Complement of tty_ldisc_get(). - */ -static void tty_ldisc_put(struct tty_ldisc *ld) -{ - if (WARN_ON_ONCE(!ld)) - return; - - put_ldops(ld->ops); - kfree(ld); -} - -static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos) -{ - return (*pos < NR_LDISCS) ? pos : NULL; -} - -static void *tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos) -{ - (*pos)++; - return (*pos < NR_LDISCS) ? pos : NULL; -} - -static void tty_ldiscs_seq_stop(struct seq_file *m, void *v) -{ -} - -static int tty_ldiscs_seq_show(struct seq_file *m, void *v) -{ - int i = *(loff_t *)v; - struct tty_ldisc_ops *ldops; - - ldops = get_ldops(i); - if (IS_ERR(ldops)) - return 0; - seq_printf(m, "%-10s %2d\n", ldops->name ? ldops->name : "???", i); - put_ldops(ldops); - return 0; -} - -static const struct seq_operations tty_ldiscs_seq_ops = { - .start = tty_ldiscs_seq_start, - .next = tty_ldiscs_seq_next, - .stop = tty_ldiscs_seq_stop, - .show = tty_ldiscs_seq_show, -}; - -static int proc_tty_ldiscs_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &tty_ldiscs_seq_ops); -} - -const struct file_operations tty_ldiscs_proc_fops = { - .owner = THIS_MODULE, - .open = proc_tty_ldiscs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/** - * tty_ldisc_ref_wait - wait for the tty ldisc - * @tty: tty device - * - * Dereference the line discipline for the terminal and take a - * reference to it. If the line discipline is in flux then - * wait patiently until it changes. - * - * Returns: NULL if the tty has been hungup and not re-opened with - * a new file descriptor, otherwise valid ldisc reference - * - * Note: Must not be called from an IRQ/timer context. The caller - * must also be careful not to hold other locks that will deadlock - * against a discipline change, such as an existing ldisc reference - * (which we check for) - * - * Note: a file_operations routine (read/poll/write) should use this - * function to wait for any ldisc lifetime events to finish. - */ - -struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) -{ - ldsem_down_read(&tty->ldisc_sem, MAX_SCHEDULE_TIMEOUT); - if (!tty->ldisc) - ldsem_up_read(&tty->ldisc_sem); - return tty->ldisc; -} -EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); - -/** - * tty_ldisc_ref - get the tty ldisc - * @tty: tty device - * - * Dereference the line discipline for the terminal and take a - * reference to it. If the line discipline is in flux then - * return NULL. Can be called from IRQ and timer functions. - */ - -struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) -{ - struct tty_ldisc *ld = NULL; - - if (ldsem_down_read_trylock(&tty->ldisc_sem)) { - ld = tty->ldisc; - if (!ld) - ldsem_up_read(&tty->ldisc_sem); - } - return ld; -} -EXPORT_SYMBOL_GPL(tty_ldisc_ref); - -/** - * tty_ldisc_deref - free a tty ldisc reference - * @ld: reference to free up - * - * Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May - * be called in IRQ context. - */ - -void tty_ldisc_deref(struct tty_ldisc *ld) -{ - ldsem_up_read(&ld->tty->ldisc_sem); -} -EXPORT_SYMBOL_GPL(tty_ldisc_deref); - - -static inline int -__tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout) -{ - return ldsem_down_write(&tty->ldisc_sem, timeout); -} - -static inline int -__tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout) -{ - return ldsem_down_write_nested(&tty->ldisc_sem, - LDISC_SEM_OTHER, timeout); -} - -static inline void __tty_ldisc_unlock(struct tty_struct *tty) -{ - ldsem_up_write(&tty->ldisc_sem); -} - -static int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout) -{ - int ret; - - ret = __tty_ldisc_lock(tty, timeout); - if (!ret) - return -EBUSY; - set_bit(TTY_LDISC_HALTED, &tty->flags); - return 0; -} - -static void tty_ldisc_unlock(struct tty_struct *tty) -{ - clear_bit(TTY_LDISC_HALTED, &tty->flags); - __tty_ldisc_unlock(tty); -} - -static int -tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2, - unsigned long timeout) -{ - int ret; - - if (tty < tty2) { - ret = __tty_ldisc_lock(tty, timeout); - if (ret) { - ret = __tty_ldisc_lock_nested(tty2, timeout); - if (!ret) - __tty_ldisc_unlock(tty); - } - } else { - /* if this is possible, it has lots of implications */ - WARN_ON_ONCE(tty == tty2); - if (tty2 && tty != tty2) { - ret = __tty_ldisc_lock(tty2, timeout); - if (ret) { - ret = __tty_ldisc_lock_nested(tty, timeout); - if (!ret) - __tty_ldisc_unlock(tty2); - } - } else - ret = __tty_ldisc_lock(tty, timeout); - } - - if (!ret) - return -EBUSY; - - set_bit(TTY_LDISC_HALTED, &tty->flags); - if (tty2) - set_bit(TTY_LDISC_HALTED, &tty2->flags); - return 0; -} - -static void tty_ldisc_lock_pair(struct tty_struct *tty, struct tty_struct *tty2) -{ - tty_ldisc_lock_pair_timeout(tty, tty2, MAX_SCHEDULE_TIMEOUT); -} - -static void tty_ldisc_unlock_pair(struct tty_struct *tty, - struct tty_struct *tty2) -{ - __tty_ldisc_unlock(tty); - if (tty2) - __tty_ldisc_unlock(tty2); -} - -/** - * tty_ldisc_flush - flush line discipline queue - * @tty: tty - * - * Flush the line discipline queue (if any) and the tty flip buffers - * for this tty. - */ - -void tty_ldisc_flush(struct tty_struct *tty) -{ - struct tty_ldisc *ld = tty_ldisc_ref(tty); - - tty_buffer_flush(tty, ld); - if (ld) - tty_ldisc_deref(ld); -} -EXPORT_SYMBOL_GPL(tty_ldisc_flush); - -/** - * tty_set_termios_ldisc - set ldisc field - * @tty: tty structure - * @disc: line discipline number - * - * This is probably overkill for real world processors but - * they are not on hot paths so a little discipline won't do - * any harm. - * - * The line discipline-related tty_struct fields are reset to - * prevent the ldisc driver from re-using stale information for - * the new ldisc instance. - * - * Locking: takes termios_rwsem - */ - -static void tty_set_termios_ldisc(struct tty_struct *tty, int disc) -{ - down_write(&tty->termios_rwsem); - tty->termios.c_line = disc; - up_write(&tty->termios_rwsem); - - tty->disc_data = NULL; - tty->receive_room = 0; -} - -/** - * tty_ldisc_open - open a line discipline - * @tty: tty we are opening the ldisc on - * @ld: discipline to open - * - * A helper opening method. Also a convenient debugging and check - * point. - * - * Locking: always called with BTM already held. - */ - -static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) -{ - WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags)); - if (ld->ops->open) { - int ret; - /* BTM here locks versus a hangup event */ - ret = ld->ops->open(tty); - if (ret) - clear_bit(TTY_LDISC_OPEN, &tty->flags); - - tty_ldisc_debug(tty, "%p: opened\n", ld); - return ret; - } - return 0; -} - -/** - * tty_ldisc_close - close a line discipline - * @tty: tty we are opening the ldisc on - * @ld: discipline to close - * - * A helper close method. Also a convenient debugging and check - * point. - */ - -static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld) -{ - WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags)); - clear_bit(TTY_LDISC_OPEN, &tty->flags); - if (ld->ops->close) - ld->ops->close(tty); - tty_ldisc_debug(tty, "%p: closed\n", ld); -} - -/** - * tty_ldisc_restore - helper for tty ldisc change - * @tty: tty to recover - * @old: previous ldisc - * - * Restore the previous line discipline or N_TTY when a line discipline - * change fails due to an open error - */ - -static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) -{ - struct tty_ldisc *new_ldisc; - int r; - - /* There is an outstanding reference here so this is safe */ - old = tty_ldisc_get(tty, old->ops->num); - WARN_ON(IS_ERR(old)); - tty->ldisc = old; - tty_set_termios_ldisc(tty, old->ops->num); - if (tty_ldisc_open(tty, old) < 0) { - tty_ldisc_put(old); - /* This driver is always present */ - new_ldisc = tty_ldisc_get(tty, N_TTY); - if (IS_ERR(new_ldisc)) - panic("n_tty: get"); - tty->ldisc = new_ldisc; - tty_set_termios_ldisc(tty, N_TTY); - r = tty_ldisc_open(tty, new_ldisc); - if (r < 0) - panic("Couldn't open N_TTY ldisc for " - "%s --- error %d.", - tty_name(tty), r); - } -} - -/** - * tty_set_ldisc - set line discipline - * @tty: the terminal to set - * @ldisc: the line discipline - * - * Set the discipline of a tty line. Must be called from a process - * context. The ldisc change logic has to protect itself against any - * overlapping ldisc change (including on the other end of pty pairs), - * the close of one side of a tty/pty pair, and eventually hangup. - */ - -int tty_set_ldisc(struct tty_struct *tty, int disc) -{ - int retval; - struct tty_ldisc *old_ldisc, *new_ldisc; - - new_ldisc = tty_ldisc_get(tty, disc); - if (IS_ERR(new_ldisc)) - return PTR_ERR(new_ldisc); - - tty_lock(tty); - retval = tty_ldisc_lock(tty, 5 * HZ); - if (retval) - goto err; - - if (!tty->ldisc) { - retval = -EIO; - goto out; - } - - /* Check the no-op case */ - if (tty->ldisc->ops->num == disc) - goto out; - - if (test_bit(TTY_HUPPED, &tty->flags)) { - /* We were raced by hangup */ - retval = -EIO; - goto out; - } - - old_ldisc = tty->ldisc; - - /* Shutdown the old discipline. */ - tty_ldisc_close(tty, old_ldisc); - - /* Now set up the new line discipline. */ - tty->ldisc = new_ldisc; - tty_set_termios_ldisc(tty, disc); - - retval = tty_ldisc_open(tty, new_ldisc); - if (retval < 0) { - /* Back to the old one or N_TTY if we can't */ - tty_ldisc_put(new_ldisc); - tty_ldisc_restore(tty, old_ldisc); - } - - if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc) { - down_read(&tty->termios_rwsem); - tty->ops->set_ldisc(tty); - up_read(&tty->termios_rwsem); - } - - /* At this point we hold a reference to the new ldisc and a - reference to the old ldisc, or we hold two references to - the old ldisc (if it was restored as part of error cleanup - above). In either case, releasing a single reference from - the old ldisc is correct. */ - new_ldisc = old_ldisc; -out: - tty_ldisc_unlock(tty); - - /* Restart the work queue in case no characters kick it off. Safe if - already running */ - tty_buffer_restart_work(tty->port); -err: - tty_ldisc_put(new_ldisc); /* drop the extra reference */ - tty_unlock(tty); - return retval; -} - -/** - * tty_ldisc_kill - teardown ldisc - * @tty: tty being released - * - * Perform final close of the ldisc and reset tty->ldisc - */ -static void tty_ldisc_kill(struct tty_struct *tty) -{ - if (!tty->ldisc) - return; - /* - * Now kill off the ldisc - */ - tty_ldisc_close(tty, tty->ldisc); - tty_ldisc_put(tty->ldisc); - /* Force an oops if we mess this up */ - tty->ldisc = NULL; -} - -/** - * tty_reset_termios - reset terminal state - * @tty: tty to reset - * - * Restore a terminal to the driver default state. - */ - -static void tty_reset_termios(struct tty_struct *tty) -{ - down_write(&tty->termios_rwsem); - tty->termios = tty->driver->init_termios; - tty->termios.c_ispeed = tty_termios_input_baud_rate(&tty->termios); - tty->termios.c_ospeed = tty_termios_baud_rate(&tty->termios); - up_write(&tty->termios_rwsem); -} - - -/** - * tty_ldisc_reinit - reinitialise the tty ldisc - * @tty: tty to reinit - * @disc: line discipline to reinitialize - * - * Completely reinitialize the line discipline state, by closing the - * current instance, if there is one, and opening a new instance. If - * an error occurs opening the new non-N_TTY instance, the instance - * is dropped and tty->ldisc reset to NULL. The caller can then retry - * with N_TTY instead. - * - * Returns 0 if successful, otherwise error code < 0 - */ - -int tty_ldisc_reinit(struct tty_struct *tty, int disc) -{ - struct tty_ldisc *ld; - int retval; - - ld = tty_ldisc_get(tty, disc); - if (IS_ERR(ld)) { - BUG_ON(disc == N_TTY); - return PTR_ERR(ld); - } - - if (tty->ldisc) { - tty_ldisc_close(tty, tty->ldisc); - tty_ldisc_put(tty->ldisc); - } - - /* switch the line discipline */ - tty->ldisc = ld; - tty_set_termios_ldisc(tty, disc); - retval = tty_ldisc_open(tty, tty->ldisc); - if (retval) { - if (!WARN_ON(disc == N_TTY)) { - tty_ldisc_put(tty->ldisc); - tty->ldisc = NULL; - } - } - return retval; -} - -/** - * tty_ldisc_hangup - hangup ldisc reset - * @tty: tty being hung up - * - * Some tty devices reset their termios when they receive a hangup - * event. In that situation we must also switch back to N_TTY properly - * before we reset the termios data. - * - * Locking: We can take the ldisc mutex as the rest of the code is - * careful to allow for this. - * - * In the pty pair case this occurs in the close() path of the - * tty itself so we must be careful about locking rules. - */ - -void tty_ldisc_hangup(struct tty_struct *tty, bool reinit) -{ - struct tty_ldisc *ld; - - tty_ldisc_debug(tty, "%p: hangup\n", tty->ldisc); - - ld = tty_ldisc_ref(tty); - if (ld != NULL) { - if (ld->ops->flush_buffer) - ld->ops->flush_buffer(tty); - tty_driver_flush_buffer(tty); - if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && - ld->ops->write_wakeup) - ld->ops->write_wakeup(tty); - if (ld->ops->hangup) - ld->ops->hangup(tty); - tty_ldisc_deref(ld); - } - - wake_up_interruptible_poll(&tty->write_wait, POLLOUT); - wake_up_interruptible_poll(&tty->read_wait, POLLIN); - - /* - * Shutdown the current line discipline, and reset it to - * N_TTY if need be. - * - * Avoid racing set_ldisc or tty_ldisc_release - */ - tty_ldisc_lock(tty, MAX_SCHEDULE_TIMEOUT); - - if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) - tty_reset_termios(tty); - - if (tty->ldisc) { - if (reinit) { - if (tty_ldisc_reinit(tty, tty->termios.c_line) < 0) - tty_ldisc_reinit(tty, N_TTY); - } else - tty_ldisc_kill(tty); - } - tty_ldisc_unlock(tty); -} - -/** - * tty_ldisc_setup - open line discipline - * @tty: tty being shut down - * @o_tty: pair tty for pty/tty pairs - * - * Called during the initial open of a tty/pty pair in order to set up the - * line disciplines and bind them to the tty. This has no locking issues - * as the device isn't yet active. - */ - -int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) -{ - int retval = tty_ldisc_open(tty, tty->ldisc); - if (retval) - return retval; - - if (o_tty) { - retval = tty_ldisc_open(o_tty, o_tty->ldisc); - if (retval) { - tty_ldisc_close(tty, tty->ldisc); - return retval; - } - } - return 0; -} - -/** - * tty_ldisc_release - release line discipline - * @tty: tty being shut down (or one end of pty pair) - * - * Called during the final close of a tty or a pty pair in order to shut - * down the line discpline layer. On exit, each tty's ldisc is NULL. - */ - -void tty_ldisc_release(struct tty_struct *tty) -{ - struct tty_struct *o_tty = tty->link; - - /* - * Shutdown this line discipline. As this is the final close, - * it does not race with the set_ldisc code path. - */ - - tty_ldisc_lock_pair(tty, o_tty); - tty_ldisc_kill(tty); - if (o_tty) - tty_ldisc_kill(o_tty); - tty_ldisc_unlock_pair(tty, o_tty); - - /* And the memory resources remaining (buffers, termios) will be - disposed of when the kref hits zero */ - - tty_ldisc_debug(tty, "released\n"); -} - -/** - * tty_ldisc_init - ldisc setup for new tty - * @tty: tty being allocated - * - * Set up the line discipline objects for a newly allocated tty. Note that - * the tty structure is not completely set up when this call is made. - */ - -void tty_ldisc_init(struct tty_struct *tty) -{ - struct tty_ldisc *ld = tty_ldisc_get(tty, N_TTY); - if (IS_ERR(ld)) - panic("n_tty: init_tty"); - tty->ldisc = ld; -} - -/** - * tty_ldisc_deinit - ldisc cleanup for new tty - * @tty: tty that was allocated recently - * - * The tty structure must not becompletely set up (tty_ldisc_setup) when - * this call is made. - */ -void tty_ldisc_deinit(struct tty_struct *tty) -{ - if (tty->ldisc) - tty_ldisc_put(tty->ldisc); - tty->ldisc = NULL; -} diff --git a/src/linux/drivers/tty/tty_ldsem.c b/src/linux/drivers/tty/tty_ldsem.c deleted file mode 100644 index 1bf8ed1..0000000 --- a/src/linux/drivers/tty/tty_ldsem.c +++ /dev/null @@ -1,457 +0,0 @@ -/* - * Ldisc rw semaphore - * - * The ldisc semaphore is semantically a rw_semaphore but which enforces - * an alternate policy, namely: - * 1) Supports lock wait timeouts - * 2) Write waiter has priority - * 3) Downgrading is not supported - * - * Implementation notes: - * 1) Upper half of semaphore count is a wait count (differs from rwsem - * in that rwsem normalizes the upper half to the wait bias) - * 2) Lacks overflow checking - * - * The generic counting was copied and modified from include/asm-generic/rwsem.h - * by Paul Mackerras . - * - * The scheduling policy was copied and modified from lib/rwsem.c - * Written by David Howells (dhowells@redhat.com). - * - * This implementation incorporates the write lock stealing work of - * Michel Lespinasse . - * - * Copyright (C) 2013 Peter Hurley - * - * This file may be redistributed under the terms of the GNU General Public - * License v2. - */ - -#include -#include -#include -#include -#include - - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# define __acq(l, s, t, r, c, n, i) \ - lock_acquire(&(l)->dep_map, s, t, r, c, n, i) -# define __rel(l, n, i) \ - lock_release(&(l)->dep_map, n, i) -#define lockdep_acquire(l, s, t, i) __acq(l, s, t, 0, 1, NULL, i) -#define lockdep_acquire_nest(l, s, t, n, i) __acq(l, s, t, 0, 1, n, i) -#define lockdep_acquire_read(l, s, t, i) __acq(l, s, t, 1, 1, NULL, i) -#define lockdep_release(l, n, i) __rel(l, n, i) -#else -# define lockdep_acquire(l, s, t, i) do { } while (0) -# define lockdep_acquire_nest(l, s, t, n, i) do { } while (0) -# define lockdep_acquire_read(l, s, t, i) do { } while (0) -# define lockdep_release(l, n, i) do { } while (0) -#endif - -#ifdef CONFIG_LOCK_STAT -# define lock_stat(_lock, stat) lock_##stat(&(_lock)->dep_map, _RET_IP_) -#else -# define lock_stat(_lock, stat) do { } while (0) -#endif - - -#if BITS_PER_LONG == 64 -# define LDSEM_ACTIVE_MASK 0xffffffffL -#else -# define LDSEM_ACTIVE_MASK 0x0000ffffL -#endif - -#define LDSEM_UNLOCKED 0L -#define LDSEM_ACTIVE_BIAS 1L -#define LDSEM_WAIT_BIAS (-LDSEM_ACTIVE_MASK-1) -#define LDSEM_READ_BIAS LDSEM_ACTIVE_BIAS -#define LDSEM_WRITE_BIAS (LDSEM_WAIT_BIAS + LDSEM_ACTIVE_BIAS) - -struct ldsem_waiter { - struct list_head list; - struct task_struct *task; -}; - -static inline long ldsem_atomic_update(long delta, struct ld_semaphore *sem) -{ - return atomic_long_add_return(delta, (atomic_long_t *)&sem->count); -} - -/* - * ldsem_cmpxchg() updates @*old with the last-known sem->count value. - * Returns 1 if count was successfully changed; @*old will have @new value. - * Returns 0 if count was not changed; @*old will have most recent sem->count - */ -static inline int ldsem_cmpxchg(long *old, long new, struct ld_semaphore *sem) -{ - long tmp = atomic_long_cmpxchg(&sem->count, *old, new); - if (tmp == *old) { - *old = new; - return 1; - } else { - *old = tmp; - return 0; - } -} - -/* - * Initialize an ldsem: - */ -void __init_ldsem(struct ld_semaphore *sem, const char *name, - struct lock_class_key *key) -{ -#ifdef CONFIG_DEBUG_LOCK_ALLOC - /* - * Make sure we are not reinitializing a held semaphore: - */ - debug_check_no_locks_freed((void *)sem, sizeof(*sem)); - lockdep_init_map(&sem->dep_map, name, key, 0); -#endif - sem->count = LDSEM_UNLOCKED; - sem->wait_readers = 0; - raw_spin_lock_init(&sem->wait_lock); - INIT_LIST_HEAD(&sem->read_wait); - INIT_LIST_HEAD(&sem->write_wait); -} - -static void __ldsem_wake_readers(struct ld_semaphore *sem) -{ - struct ldsem_waiter *waiter, *next; - struct task_struct *tsk; - long adjust, count; - - /* Try to grant read locks to all readers on the read wait list. - * Note the 'active part' of the count is incremented by - * the number of readers before waking any processes up. - */ - adjust = sem->wait_readers * (LDSEM_ACTIVE_BIAS - LDSEM_WAIT_BIAS); - count = ldsem_atomic_update(adjust, sem); - do { - if (count > 0) - break; - if (ldsem_cmpxchg(&count, count - adjust, sem)) - return; - } while (1); - - list_for_each_entry_safe(waiter, next, &sem->read_wait, list) { - tsk = waiter->task; - smp_mb(); - waiter->task = NULL; - wake_up_process(tsk); - put_task_struct(tsk); - } - INIT_LIST_HEAD(&sem->read_wait); - sem->wait_readers = 0; -} - -static inline int writer_trylock(struct ld_semaphore *sem) -{ - /* only wake this writer if the active part of the count can be - * transitioned from 0 -> 1 - */ - long count = ldsem_atomic_update(LDSEM_ACTIVE_BIAS, sem); - do { - if ((count & LDSEM_ACTIVE_MASK) == LDSEM_ACTIVE_BIAS) - return 1; - if (ldsem_cmpxchg(&count, count - LDSEM_ACTIVE_BIAS, sem)) - return 0; - } while (1); -} - -static void __ldsem_wake_writer(struct ld_semaphore *sem) -{ - struct ldsem_waiter *waiter; - - waiter = list_entry(sem->write_wait.next, struct ldsem_waiter, list); - wake_up_process(waiter->task); -} - -/* - * handle the lock release when processes blocked on it that can now run - * - if we come here from up_xxxx(), then: - * - the 'active part' of count (&0x0000ffff) reached 0 (but may have changed) - * - the 'waiting part' of count (&0xffff0000) is -ve (and will still be so) - * - the spinlock must be held by the caller - * - woken process blocks are discarded from the list after having task zeroed - */ -static void __ldsem_wake(struct ld_semaphore *sem) -{ - if (!list_empty(&sem->write_wait)) - __ldsem_wake_writer(sem); - else if (!list_empty(&sem->read_wait)) - __ldsem_wake_readers(sem); -} - -static void ldsem_wake(struct ld_semaphore *sem) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&sem->wait_lock, flags); - __ldsem_wake(sem); - raw_spin_unlock_irqrestore(&sem->wait_lock, flags); -} - -/* - * wait for the read lock to be granted - */ -static struct ld_semaphore __sched * -down_read_failed(struct ld_semaphore *sem, long count, long timeout) -{ - struct ldsem_waiter waiter; - struct task_struct *tsk = current; - long adjust = -LDSEM_ACTIVE_BIAS + LDSEM_WAIT_BIAS; - - /* set up my own style of waitqueue */ - raw_spin_lock_irq(&sem->wait_lock); - - /* Try to reverse the lock attempt but if the count has changed - * so that reversing fails, check if there are are no waiters, - * and early-out if not */ - do { - if (ldsem_cmpxchg(&count, count + adjust, sem)) - break; - if (count > 0) { - raw_spin_unlock_irq(&sem->wait_lock); - return sem; - } - } while (1); - - list_add_tail(&waiter.list, &sem->read_wait); - sem->wait_readers++; - - waiter.task = tsk; - get_task_struct(tsk); - - /* if there are no active locks, wake the new lock owner(s) */ - if ((count & LDSEM_ACTIVE_MASK) == 0) - __ldsem_wake(sem); - - raw_spin_unlock_irq(&sem->wait_lock); - - /* wait to be given the lock */ - for (;;) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - - if (!waiter.task) - break; - if (!timeout) - break; - timeout = schedule_timeout(timeout); - } - - __set_task_state(tsk, TASK_RUNNING); - - if (!timeout) { - /* lock timed out but check if this task was just - * granted lock ownership - if so, pretend there - * was no timeout; otherwise, cleanup lock wait */ - raw_spin_lock_irq(&sem->wait_lock); - if (waiter.task) { - ldsem_atomic_update(-LDSEM_WAIT_BIAS, sem); - list_del(&waiter.list); - raw_spin_unlock_irq(&sem->wait_lock); - put_task_struct(waiter.task); - return NULL; - } - raw_spin_unlock_irq(&sem->wait_lock); - } - - return sem; -} - -/* - * wait for the write lock to be granted - */ -static struct ld_semaphore __sched * -down_write_failed(struct ld_semaphore *sem, long count, long timeout) -{ - struct ldsem_waiter waiter; - struct task_struct *tsk = current; - long adjust = -LDSEM_ACTIVE_BIAS; - int locked = 0; - - /* set up my own style of waitqueue */ - raw_spin_lock_irq(&sem->wait_lock); - - /* Try to reverse the lock attempt but if the count has changed - * so that reversing fails, check if the lock is now owned, - * and early-out if so */ - do { - if (ldsem_cmpxchg(&count, count + adjust, sem)) - break; - if ((count & LDSEM_ACTIVE_MASK) == LDSEM_ACTIVE_BIAS) { - raw_spin_unlock_irq(&sem->wait_lock); - return sem; - } - } while (1); - - list_add_tail(&waiter.list, &sem->write_wait); - - waiter.task = tsk; - - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - for (;;) { - if (!timeout) - break; - raw_spin_unlock_irq(&sem->wait_lock); - timeout = schedule_timeout(timeout); - raw_spin_lock_irq(&sem->wait_lock); - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - locked = writer_trylock(sem); - if (locked) - break; - } - - if (!locked) - ldsem_atomic_update(-LDSEM_WAIT_BIAS, sem); - list_del(&waiter.list); - raw_spin_unlock_irq(&sem->wait_lock); - - __set_task_state(tsk, TASK_RUNNING); - - /* lock wait may have timed out */ - if (!locked) - return NULL; - return sem; -} - - - -static int __ldsem_down_read_nested(struct ld_semaphore *sem, - int subclass, long timeout) -{ - long count; - - lockdep_acquire_read(sem, subclass, 0, _RET_IP_); - - count = ldsem_atomic_update(LDSEM_READ_BIAS, sem); - if (count <= 0) { - lock_stat(sem, contended); - if (!down_read_failed(sem, count, timeout)) { - lockdep_release(sem, 1, _RET_IP_); - return 0; - } - } - lock_stat(sem, acquired); - return 1; -} - -static int __ldsem_down_write_nested(struct ld_semaphore *sem, - int subclass, long timeout) -{ - long count; - - lockdep_acquire(sem, subclass, 0, _RET_IP_); - - count = ldsem_atomic_update(LDSEM_WRITE_BIAS, sem); - if ((count & LDSEM_ACTIVE_MASK) != LDSEM_ACTIVE_BIAS) { - lock_stat(sem, contended); - if (!down_write_failed(sem, count, timeout)) { - lockdep_release(sem, 1, _RET_IP_); - return 0; - } - } - lock_stat(sem, acquired); - return 1; -} - - -/* - * lock for reading -- returns 1 if successful, 0 if timed out - */ -int __sched ldsem_down_read(struct ld_semaphore *sem, long timeout) -{ - might_sleep(); - return __ldsem_down_read_nested(sem, 0, timeout); -} - -/* - * trylock for reading -- returns 1 if successful, 0 if contention - */ -int ldsem_down_read_trylock(struct ld_semaphore *sem) -{ - long count = sem->count; - - while (count >= 0) { - if (ldsem_cmpxchg(&count, count + LDSEM_READ_BIAS, sem)) { - lockdep_acquire_read(sem, 0, 1, _RET_IP_); - lock_stat(sem, acquired); - return 1; - } - } - return 0; -} - -/* - * lock for writing -- returns 1 if successful, 0 if timed out - */ -int __sched ldsem_down_write(struct ld_semaphore *sem, long timeout) -{ - might_sleep(); - return __ldsem_down_write_nested(sem, 0, timeout); -} - -/* - * trylock for writing -- returns 1 if successful, 0 if contention - */ -int ldsem_down_write_trylock(struct ld_semaphore *sem) -{ - long count = sem->count; - - while ((count & LDSEM_ACTIVE_MASK) == 0) { - if (ldsem_cmpxchg(&count, count + LDSEM_WRITE_BIAS, sem)) { - lockdep_acquire(sem, 0, 1, _RET_IP_); - lock_stat(sem, acquired); - return 1; - } - } - return 0; -} - -/* - * release a read lock - */ -void ldsem_up_read(struct ld_semaphore *sem) -{ - long count; - - lockdep_release(sem, 1, _RET_IP_); - - count = ldsem_atomic_update(-LDSEM_READ_BIAS, sem); - if (count < 0 && (count & LDSEM_ACTIVE_MASK) == 0) - ldsem_wake(sem); -} - -/* - * release a write lock - */ -void ldsem_up_write(struct ld_semaphore *sem) -{ - long count; - - lockdep_release(sem, 1, _RET_IP_); - - count = ldsem_atomic_update(-LDSEM_WRITE_BIAS, sem); - if (count < 0) - ldsem_wake(sem); -} - - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - -int ldsem_down_read_nested(struct ld_semaphore *sem, int subclass, long timeout) -{ - might_sleep(); - return __ldsem_down_read_nested(sem, subclass, timeout); -} - -int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass, - long timeout) -{ - might_sleep(); - return __ldsem_down_write_nested(sem, subclass, timeout); -} - -#endif diff --git a/src/linux/drivers/tty/tty_mutex.c b/src/linux/drivers/tty/tty_mutex.c deleted file mode 100644 index d8bae67..0000000 --- a/src/linux/drivers/tty/tty_mutex.c +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include -#include -#include -#include - -/* Legacy tty mutex glue */ - -/* - * Getting the big tty mutex. - */ - -void tty_lock(struct tty_struct *tty) -{ - if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty)) - return; - tty_kref_get(tty); - mutex_lock(&tty->legacy_mutex); -} -EXPORT_SYMBOL(tty_lock); - -int tty_lock_interruptible(struct tty_struct *tty) -{ - int ret; - - if (WARN(tty->magic != TTY_MAGIC, "L Bad %p\n", tty)) - return -EIO; - tty_kref_get(tty); - ret = mutex_lock_interruptible(&tty->legacy_mutex); - if (ret) - tty_kref_put(tty); - return ret; -} - -void tty_unlock(struct tty_struct *tty) -{ - if (WARN(tty->magic != TTY_MAGIC, "U Bad %p\n", tty)) - return; - mutex_unlock(&tty->legacy_mutex); - tty_kref_put(tty); -} -EXPORT_SYMBOL(tty_unlock); - -void tty_lock_slave(struct tty_struct *tty) -{ - if (tty && tty != tty->link) - tty_lock(tty); -} - -void tty_unlock_slave(struct tty_struct *tty) -{ - if (tty && tty != tty->link) - tty_unlock(tty); -} - -void tty_set_lock_subclass(struct tty_struct *tty) -{ - lockdep_set_subclass(&tty->legacy_mutex, TTY_LOCK_SLAVE); -} diff --git a/src/linux/drivers/tty/tty_port.c b/src/linux/drivers/tty/tty_port.c deleted file mode 100644 index c3f9d93..0000000 --- a/src/linux/drivers/tty/tty_port.c +++ /dev/null @@ -1,597 +0,0 @@ -/* - * Tty port functions - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void tty_port_init(struct tty_port *port) -{ - memset(port, 0, sizeof(*port)); - tty_buffer_init(port); - init_waitqueue_head(&port->open_wait); - init_waitqueue_head(&port->delta_msr_wait); - mutex_init(&port->mutex); - mutex_init(&port->buf_mutex); - spin_lock_init(&port->lock); - port->close_delay = (50 * HZ) / 100; - port->closing_wait = (3000 * HZ) / 100; - kref_init(&port->kref); -} -EXPORT_SYMBOL(tty_port_init); - -/** - * tty_port_link_device - link tty and tty_port - * @port: tty_port of the device - * @driver: tty_driver for this device - * @index: index of the tty - * - * Provide the tty layer wit ha link from a tty (specified by @index) to a - * tty_port (@port). Use this only if neither tty_port_register_device nor - * tty_port_install is used in the driver. If used, this has to be called before - * tty_register_driver. - */ -void tty_port_link_device(struct tty_port *port, - struct tty_driver *driver, unsigned index) -{ - if (WARN_ON(index >= driver->num)) - return; - driver->ports[index] = port; -} -EXPORT_SYMBOL_GPL(tty_port_link_device); - -/** - * tty_port_register_device - register tty device - * @port: tty_port of the device - * @driver: tty_driver for this device - * @index: index of the tty - * @device: parent if exists, otherwise NULL - * - * It is the same as tty_register_device except the provided @port is linked to - * a concrete tty specified by @index. Use this or tty_port_install (or both). - * Call tty_port_link_device as a last resort. - */ -struct device *tty_port_register_device(struct tty_port *port, - struct tty_driver *driver, unsigned index, - struct device *device) -{ - tty_port_link_device(port, driver, index); - return tty_register_device(driver, index, device); -} -EXPORT_SYMBOL_GPL(tty_port_register_device); - -/** - * tty_port_register_device_attr - register tty device - * @port: tty_port of the device - * @driver: tty_driver for this device - * @index: index of the tty - * @device: parent if exists, otherwise NULL - * @drvdata: Driver data to be set to device. - * @attr_grp: Attribute group to be set on device. - * - * It is the same as tty_register_device_attr except the provided @port is - * linked to a concrete tty specified by @index. Use this or tty_port_install - * (or both). Call tty_port_link_device as a last resort. - */ -struct device *tty_port_register_device_attr(struct tty_port *port, - struct tty_driver *driver, unsigned index, - struct device *device, void *drvdata, - const struct attribute_group **attr_grp) -{ - tty_port_link_device(port, driver, index); - return tty_register_device_attr(driver, index, device, drvdata, - attr_grp); -} -EXPORT_SYMBOL_GPL(tty_port_register_device_attr); - -int tty_port_alloc_xmit_buf(struct tty_port *port) -{ - /* We may sleep in get_zeroed_page() */ - mutex_lock(&port->buf_mutex); - if (port->xmit_buf == NULL) - port->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); - mutex_unlock(&port->buf_mutex); - if (port->xmit_buf == NULL) - return -ENOMEM; - return 0; -} -EXPORT_SYMBOL(tty_port_alloc_xmit_buf); - -void tty_port_free_xmit_buf(struct tty_port *port) -{ - mutex_lock(&port->buf_mutex); - if (port->xmit_buf != NULL) { - free_page((unsigned long)port->xmit_buf); - port->xmit_buf = NULL; - } - mutex_unlock(&port->buf_mutex); -} -EXPORT_SYMBOL(tty_port_free_xmit_buf); - -/** - * tty_port_destroy -- destroy inited port - * @port: tty port to be doestroyed - * - * When a port was initialized using tty_port_init, one has to destroy the - * port by this function. Either indirectly by using tty_port refcounting - * (tty_port_put) or directly if refcounting is not used. - */ -void tty_port_destroy(struct tty_port *port) -{ - tty_buffer_cancel_work(port); - tty_buffer_free_all(port); -} -EXPORT_SYMBOL(tty_port_destroy); - -static void tty_port_destructor(struct kref *kref) -{ - struct tty_port *port = container_of(kref, struct tty_port, kref); - - /* check if last port ref was dropped before tty release */ - if (WARN_ON(port->itty)) - return; - if (port->xmit_buf) - free_page((unsigned long)port->xmit_buf); - tty_port_destroy(port); - if (port->ops && port->ops->destruct) - port->ops->destruct(port); - else - kfree(port); -} - -void tty_port_put(struct tty_port *port) -{ - if (port) - kref_put(&port->kref, tty_port_destructor); -} -EXPORT_SYMBOL(tty_port_put); - -/** - * tty_port_tty_get - get a tty reference - * @port: tty port - * - * Return a refcount protected tty instance or NULL if the port is not - * associated with a tty (eg due to close or hangup) - */ - -struct tty_struct *tty_port_tty_get(struct tty_port *port) -{ - unsigned long flags; - struct tty_struct *tty; - - spin_lock_irqsave(&port->lock, flags); - tty = tty_kref_get(port->tty); - spin_unlock_irqrestore(&port->lock, flags); - return tty; -} -EXPORT_SYMBOL(tty_port_tty_get); - -/** - * tty_port_tty_set - set the tty of a port - * @port: tty port - * @tty: the tty - * - * Associate the port and tty pair. Manages any internal refcounts. - * Pass NULL to deassociate a port - */ - -void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty) -{ - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - tty_kref_put(port->tty); - port->tty = tty_kref_get(tty); - spin_unlock_irqrestore(&port->lock, flags); -} -EXPORT_SYMBOL(tty_port_tty_set); - -static void tty_port_shutdown(struct tty_port *port, struct tty_struct *tty) -{ - mutex_lock(&port->mutex); - if (port->console) - goto out; - - if (tty_port_initialized(port)) { - tty_port_set_initialized(port, 0); - /* - * Drop DTR/RTS if HUPCL is set. This causes any attached - * modem to hang up the line. - */ - if (tty && C_HUPCL(tty)) - tty_port_lower_dtr_rts(port); - - if (port->ops->shutdown) - port->ops->shutdown(port); - } -out: - mutex_unlock(&port->mutex); -} - -/** - * tty_port_hangup - hangup helper - * @port: tty port - * - * Perform port level tty hangup flag and count changes. Drop the tty - * reference. - * - * Caller holds tty lock. - */ - -void tty_port_hangup(struct tty_port *port) -{ - struct tty_struct *tty; - unsigned long flags; - - spin_lock_irqsave(&port->lock, flags); - port->count = 0; - tty = port->tty; - if (tty) - set_bit(TTY_IO_ERROR, &tty->flags); - port->tty = NULL; - spin_unlock_irqrestore(&port->lock, flags); - tty_port_set_active(port, 0); - tty_port_shutdown(port, tty); - tty_kref_put(tty); - wake_up_interruptible(&port->open_wait); - wake_up_interruptible(&port->delta_msr_wait); -} -EXPORT_SYMBOL(tty_port_hangup); - -/** - * tty_port_tty_hangup - helper to hang up a tty - * - * @port: tty port - * @check_clocal: hang only ttys with CLOCAL unset? - */ -void tty_port_tty_hangup(struct tty_port *port, bool check_clocal) -{ - struct tty_struct *tty = tty_port_tty_get(port); - - if (tty && (!check_clocal || !C_CLOCAL(tty))) - tty_hangup(tty); - tty_kref_put(tty); -} -EXPORT_SYMBOL_GPL(tty_port_tty_hangup); - -/** - * tty_port_tty_wakeup - helper to wake up a tty - * - * @port: tty port - */ -void tty_port_tty_wakeup(struct tty_port *port) -{ - struct tty_struct *tty = tty_port_tty_get(port); - - if (tty) { - tty_wakeup(tty); - tty_kref_put(tty); - } -} -EXPORT_SYMBOL_GPL(tty_port_tty_wakeup); - -/** - * tty_port_carrier_raised - carrier raised check - * @port: tty port - * - * Wrapper for the carrier detect logic. For the moment this is used - * to hide some internal details. This will eventually become entirely - * internal to the tty port. - */ - -int tty_port_carrier_raised(struct tty_port *port) -{ - if (port->ops->carrier_raised == NULL) - return 1; - return port->ops->carrier_raised(port); -} -EXPORT_SYMBOL(tty_port_carrier_raised); - -/** - * tty_port_raise_dtr_rts - Raise DTR/RTS - * @port: tty port - * - * Wrapper for the DTR/RTS raise logic. For the moment this is used - * to hide some internal details. This will eventually become entirely - * internal to the tty port. - */ - -void tty_port_raise_dtr_rts(struct tty_port *port) -{ - if (port->ops->dtr_rts) - port->ops->dtr_rts(port, 1); -} -EXPORT_SYMBOL(tty_port_raise_dtr_rts); - -/** - * tty_port_lower_dtr_rts - Lower DTR/RTS - * @port: tty port - * - * Wrapper for the DTR/RTS raise logic. For the moment this is used - * to hide some internal details. This will eventually become entirely - * internal to the tty port. - */ - -void tty_port_lower_dtr_rts(struct tty_port *port) -{ - if (port->ops->dtr_rts) - port->ops->dtr_rts(port, 0); -} -EXPORT_SYMBOL(tty_port_lower_dtr_rts); - -/** - * tty_port_block_til_ready - Waiting logic for tty open - * @port: the tty port being opened - * @tty: the tty device being bound - * @filp: the file pointer of the opener - * - * Implement the core POSIX/SuS tty behaviour when opening a tty device. - * Handles: - * - hangup (both before and during) - * - non blocking open - * - rts/dtr/dcd - * - signals - * - port flags and counts - * - * The passed tty_port must implement the carrier_raised method if it can - * do carrier detect and the dtr_rts method if it supports software - * management of these lines. Note that the dtr/rts raise is done each - * iteration as a hangup may have previously dropped them while we wait. - * - * Caller holds tty lock. - * - * NB: May drop and reacquire tty lock when blocking, so tty and tty_port - * may have changed state (eg., may have been hung up). - */ - -int tty_port_block_til_ready(struct tty_port *port, - struct tty_struct *tty, struct file *filp) -{ - int do_clocal = 0, retval; - unsigned long flags; - DEFINE_WAIT(wait); - - /* if non-blocking mode is set we can pass directly to open unless - the port has just hung up or is in another error state */ - if (tty_io_error(tty)) { - tty_port_set_active(port, 1); - return 0; - } - if (filp->f_flags & O_NONBLOCK) { - /* Indicate we are open */ - if (C_BAUD(tty)) - tty_port_raise_dtr_rts(port); - tty_port_set_active(port, 1); - return 0; - } - - if (C_CLOCAL(tty)) - do_clocal = 1; - - /* Block waiting until we can proceed. We may need to wait for the - carrier, but we must also wait for any close that is in progress - before the next open may complete */ - - retval = 0; - - /* The port lock protects the port counts */ - spin_lock_irqsave(&port->lock, flags); - port->count--; - port->blocked_open++; - spin_unlock_irqrestore(&port->lock, flags); - - while (1) { - /* Indicate we are open */ - if (C_BAUD(tty) && tty_port_initialized(port)) - tty_port_raise_dtr_rts(port); - - prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE); - /* Check for a hangup or uninitialised port. - Return accordingly */ - if (tty_hung_up_p(filp) || !tty_port_initialized(port)) { - if (port->flags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; - break; - } - /* - * Probe the carrier. For devices with no carrier detect - * tty_port_carrier_raised will always return true. - * Never ask drivers if CLOCAL is set, this causes troubles - * on some hardware. - */ - if (do_clocal || tty_port_carrier_raised(port)) - break; - if (signal_pending(current)) { - retval = -ERESTARTSYS; - break; - } - tty_unlock(tty); - schedule(); - tty_lock(tty); - } - finish_wait(&port->open_wait, &wait); - - /* Update counts. A parallel hangup will have set count to zero and - we must not mess that up further */ - spin_lock_irqsave(&port->lock, flags); - if (!tty_hung_up_p(filp)) - port->count++; - port->blocked_open--; - spin_unlock_irqrestore(&port->lock, flags); - if (retval == 0) - tty_port_set_active(port, 1); - return retval; -} -EXPORT_SYMBOL(tty_port_block_til_ready); - -static void tty_port_drain_delay(struct tty_port *port, struct tty_struct *tty) -{ - unsigned int bps = tty_get_baud_rate(tty); - long timeout; - - if (bps > 1200) { - timeout = (HZ * 10 * port->drain_delay) / bps; - timeout = max_t(long, timeout, HZ / 10); - } else { - timeout = 2 * HZ; - } - schedule_timeout_interruptible(timeout); -} - -/* Caller holds tty lock. */ -int tty_port_close_start(struct tty_port *port, - struct tty_struct *tty, struct file *filp) -{ - unsigned long flags; - - if (tty_hung_up_p(filp)) - return 0; - - spin_lock_irqsave(&port->lock, flags); - if (tty->count == 1 && port->count != 1) { - tty_warn(tty, "%s: tty->count = 1 port count = %d\n", __func__, - port->count); - port->count = 1; - } - if (--port->count < 0) { - tty_warn(tty, "%s: bad port count (%d)\n", __func__, - port->count); - port->count = 0; - } - - if (port->count) { - spin_unlock_irqrestore(&port->lock, flags); - return 0; - } - spin_unlock_irqrestore(&port->lock, flags); - - tty->closing = 1; - - if (tty_port_initialized(port)) { - /* Don't block on a stalled port, just pull the chain */ - if (tty->flow_stopped) - tty_driver_flush_buffer(tty); - if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) - tty_wait_until_sent(tty, port->closing_wait); - if (port->drain_delay) - tty_port_drain_delay(port, tty); - } - /* Flush the ldisc buffering */ - tty_ldisc_flush(tty); - - /* Report to caller this is the last port reference */ - return 1; -} -EXPORT_SYMBOL(tty_port_close_start); - -/* Caller holds tty lock */ -void tty_port_close_end(struct tty_port *port, struct tty_struct *tty) -{ - unsigned long flags; - - tty_ldisc_flush(tty); - tty->closing = 0; - - spin_lock_irqsave(&port->lock, flags); - - if (port->blocked_open) { - spin_unlock_irqrestore(&port->lock, flags); - if (port->close_delay) - msleep_interruptible(jiffies_to_msecs(port->close_delay)); - spin_lock_irqsave(&port->lock, flags); - wake_up_interruptible(&port->open_wait); - } - spin_unlock_irqrestore(&port->lock, flags); - tty_port_set_active(port, 0); -} -EXPORT_SYMBOL(tty_port_close_end); - -/** - * tty_port_close - * - * Caller holds tty lock - */ -void tty_port_close(struct tty_port *port, struct tty_struct *tty, - struct file *filp) -{ - if (tty_port_close_start(port, tty, filp) == 0) - return; - tty_port_shutdown(port, tty); - set_bit(TTY_IO_ERROR, &tty->flags); - tty_port_close_end(port, tty); - tty_port_tty_set(port, NULL); -} -EXPORT_SYMBOL(tty_port_close); - -/** - * tty_port_install - generic tty->ops->install handler - * @port: tty_port of the device - * @driver: tty_driver for this device - * @tty: tty to be installed - * - * It is the same as tty_standard_install except the provided @port is linked - * to a concrete tty specified by @tty. Use this or tty_port_register_device - * (or both). Call tty_port_link_device as a last resort. - */ -int tty_port_install(struct tty_port *port, struct tty_driver *driver, - struct tty_struct *tty) -{ - tty->port = port; - return tty_standard_install(driver, tty); -} -EXPORT_SYMBOL_GPL(tty_port_install); - -/** - * tty_port_open - * - * Caller holds tty lock. - * - * NB: may drop and reacquire tty lock (in tty_port_block_til_ready()) so - * tty and tty_port may have changed state (eg., may be hung up now) - */ -int tty_port_open(struct tty_port *port, struct tty_struct *tty, - struct file *filp) -{ - spin_lock_irq(&port->lock); - ++port->count; - spin_unlock_irq(&port->lock); - tty_port_tty_set(port, tty); - - /* - * Do the device-specific open only if the hardware isn't - * already initialized. Serialize open and shutdown using the - * port mutex. - */ - - mutex_lock(&port->mutex); - - if (!tty_port_initialized(port)) { - clear_bit(TTY_IO_ERROR, &tty->flags); - if (port->ops->activate) { - int retval = port->ops->activate(port, tty); - if (retval) { - mutex_unlock(&port->mutex); - return retval; - } - } - tty_port_set_initialized(port, 1); - } - mutex_unlock(&port->mutex); - return tty_port_block_til_ready(port, tty, filp); -} - -EXPORT_SYMBOL(tty_port_open); diff --git a/src/linux/drivers/tty/vt/.gitignore b/src/linux/drivers/tty/vt/.gitignore deleted file mode 100644 index 83683a2..0000000 --- a/src/linux/drivers/tty/vt/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -consolemap_deftbl.c -defkeymap.c diff --git a/src/linux/drivers/tty/vt/Makefile b/src/linux/drivers/tty/vt/Makefile deleted file mode 100644 index 17ae94c..0000000 --- a/src/linux/drivers/tty/vt/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# -# This file contains the font map for the default (hardware) font -# -FONTMAPFILE = cp437.uni - -obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o \ - selection.o keyboard.o -obj-$(CONFIG_CONSOLE_TRANSLATIONS) += consolemap.o consolemap_deftbl.o -obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o - -# Files generated that shall be removed upon make clean -clean-files := consolemap_deftbl.c defkeymap.c - -quiet_cmd_conmk = CONMK $@ - cmd_conmk = scripts/conmakehash $< > $@ - -$(obj)/consolemap_deftbl.c: $(src)/$(FONTMAPFILE) - $(call cmd,conmk) - -$(obj)/defkeymap.o: $(obj)/defkeymap.c - -# Uncomment if you're changing the keymap and have an appropriate -# loadkeys version for the map. By default, we'll use the shipped -# versions. -# GENERATE_KEYMAP := 1 - -ifdef GENERATE_KEYMAP - -$(obj)/defkeymap.c: $(obj)/%.c: $(src)/%.map - loadkeys --mktable $< > $@ - -endif diff --git a/src/linux/drivers/uio/Kconfig b/src/linux/drivers/uio/Kconfig deleted file mode 100644 index 52c98ce..0000000 --- a/src/linux/drivers/uio/Kconfig +++ /dev/null @@ -1,158 +0,0 @@ -menuconfig UIO - tristate "Userspace I/O drivers" - depends on MMU - help - Enable this to allow the userspace driver core code to be - built. This code allows userspace programs easy access to - kernel interrupts and memory locations, allowing some drivers - to be written in userspace. Note that a small kernel driver - is also required for interrupt handling to work properly. - - If you don't know what to do here, say N. - -if UIO - -config UIO_CIF - tristate "generic Hilscher CIF Card driver" - depends on PCI - help - Driver for Hilscher CIF DeviceNet and Profibus cards. This - driver requires a userspace component called cif that handles - all of the heavy lifting and can be found at: - - - To compile this driver as a module, choose M here: the module - will be called uio_cif. - -config UIO_PDRV_GENIRQ - tristate "Userspace I/O platform driver with generic IRQ handling" - help - Platform driver for Userspace I/O devices, including generic - interrupt handling code. Shared interrupts are not supported. - - This kernel driver requires that the matching userspace driver - handles interrupts in a special way. Userspace is responsible - for acknowledging the hardware device if needed, and re-enabling - interrupts in the interrupt controller using the write() syscall. - - If you don't know what to do here, say N. - -config UIO_DMEM_GENIRQ - tristate "Userspace platform driver with generic irq and dynamic memory" - depends on HAS_DMA - help - Platform driver for Userspace I/O devices, including generic - interrupt handling code. Shared interrupts are not supported. - - Memory regions can be specified with the same platform device - resources as the UIO_PDRV drivers, but dynamic regions can also - be specified. - The number and size of these regions is static, - but the memory allocation is not performed until - the associated device file is opened. The - memory is freed once the uio device is closed. - - If you don't know what to do here, say N. - -config UIO_AEC - tristate "AEC video timestamp device" - depends on PCI - help - - UIO driver for the Adrienne Electronics Corporation PCI time - code device. - - This device differs from other UIO devices since it uses I/O - ports instead of memory mapped I/O. In order to make it - possible for UIO to work with this device a utility, uioport, - can be used to read and write the ports: - - git clone git://ifup.org/philips/uioport.git - - If you compile this as a module, it will be called uio_aec. - -config UIO_SERCOS3 - tristate "Automata Sercos III PCI card driver" - depends on PCI - help - Userspace I/O interface for the Sercos III PCI card from - Automata GmbH. The userspace part of this driver will be - available for download from the Automata GmbH web site. - - Automata GmbH: http://www.automataweb.com - Sercos III interface: http://www.sercos.com - - If you compile this as a module, it will be called uio_sercos3. - -config UIO_PCI_GENERIC - tristate "Generic driver for PCI 2.3 and PCI Express cards" - depends on PCI - help - Generic driver that you can bind, dynamically, to any - PCI 2.3 compliant and PCI Express card. It is useful, - primarily, for virtualization scenarios. - If you compile this as a module, it will be called uio_pci_generic. - -config UIO_NETX - tristate "Hilscher NetX Card driver" - depends on PCI - help - Driver for Hilscher NetX based fieldbus cards (cifX, comX). - This driver requires a userspace component that comes with the card - or is available from Hilscher (http://www.hilscher.com). - - To compile this driver as a module, choose M here; the module - will be called uio_netx. - -config UIO_FSL_ELBC_GPCM - tristate "eLBC/GPCM driver" - depends on FSL_LBC - help - Generic driver for accessing a peripheral connected to an eLBC port - that is running in GPCM mode. GPCM is an interface for simple lower - performance memories and memory-mapped devices. For devices using - FCM or UPM eLBC modes, other device-specific drivers are available. - -config UIO_FSL_ELBC_GPCM_NETX5152 - bool "eLBC/GPCM netX 51/52 support" - depends on UIO_FSL_ELBC_GPCM - help - This will add support for netX 51/52 devices connected via eLBC/GPCM. - In particular, it implements interrupt handling. This can be used - together with the userspace netX stack from Hilscher. - - Information about this hardware can be found at: - http://www.hilscher.com/netx - -config UIO_PRUSS - tristate "Texas Instruments PRUSS driver" - select GENERIC_ALLOCATOR - depends on HAS_IOMEM && HAS_DMA - help - PRUSS driver for OMAPL138/DA850/AM18XX devices - PRUSS driver requires user space components, examples and user space - driver is available from below SVN repo - you may use anonymous login - - https://gforge.ti.com/gf/project/pru_sw/ - - More info on API is available at below wiki - - http://processors.wiki.ti.com/index.php/PRU_Linux_Application_Loader - - To compile this driver as a module, choose M here: the module - will be called uio_pruss. - -config UIO_MF624 - tristate "Humusoft MF624 DAQ PCI card driver" - depends on PCI - help - Userspace I/O interface for the Humusoft MF624 PCI card. - A sample userspace application using this driver is available - (among other MF624 related information and software components) - for download in a git repository: - - git clone git://rtime.felk.cvut.cz/mf6xx.git - - If you compile this as a module, it will be called uio_mf624. - -endif diff --git a/src/linux/drivers/usb/Kconfig b/src/linux/drivers/usb/Kconfig deleted file mode 100644 index 644e978..0000000 --- a/src/linux/drivers/usb/Kconfig +++ /dev/null @@ -1,185 +0,0 @@ -# -# USB device configuration -# - -config USB_OHCI_BIG_ENDIAN_DESC - bool - -config USB_OHCI_BIG_ENDIAN_MMIO - bool - -config USB_OHCI_LITTLE_ENDIAN - bool - default n if STB03xxx || PPC_MPC52xx - default y - -config USB_EHCI_BIG_ENDIAN_MMIO - bool - -config USB_EHCI_BIG_ENDIAN_DESC - bool - -menuconfig USB_SUPPORT - bool "USB support" - depends on HAS_IOMEM - default y - ---help--- - This option adds core support for Universal Serial Bus (USB). - You will also need drivers from the following menu to make use of it. - -if USB_SUPPORT - -config USB_COMMON - tristate - -config USB_ARCH_HAS_HCD - def_bool y - -# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface. -config USB - tristate "Support for Host-side USB" - depends on USB_ARCH_HAS_HCD - select USB_COMMON - select NLS # for UTF-8 strings - ---help--- - Universal Serial Bus (USB) is a specification for a serial bus - subsystem which offers higher speeds and more features than the - traditional PC serial port. The bus supplies power to peripherals - and allows for hot swapping. Up to 127 USB peripherals can be - connected to a single USB host in a tree structure. - - The USB host is the root of the tree, the peripherals are the - leaves and the inner nodes are special USB devices called hubs. - Most PCs now have USB host ports, used to connect peripherals - such as scanners, keyboards, mice, modems, cameras, disks, - flash memory, network links, and printers to the PC. - - Say Y here if your computer has a host-side USB port and you want - to use USB devices. You then need to say Y to at least one of the - Host Controller Driver (HCD) options below. Choose a USB 1.1 - controller, such as "UHCI HCD support" or "OHCI HCD support", - and "EHCI HCD (USB 2.0) support" except for older systems that - do not have USB 2.0 support. It doesn't normally hurt to select - them all if you are not certain. - - If your system has a device-side USB port, used in the peripheral - side of the USB protocol, see the "USB Gadget" framework instead. - - After choosing your HCD, then select drivers for the USB peripherals - you'll be using. You may want to check out the information provided - in and especially the links given in - . - - To compile this driver as a module, choose M here: the - module will be called usbcore. - -if USB - -source "drivers/usb/core/Kconfig" - -source "drivers/usb/mon/Kconfig" - -source "drivers/usb/wusbcore/Kconfig" - -source "drivers/usb/host/Kconfig" - -source "drivers/usb/renesas_usbhs/Kconfig" - -source "drivers/usb/class/Kconfig" - -source "drivers/usb/storage/Kconfig" - -source "drivers/usb/image/Kconfig" - -source "drivers/usb/usbip/Kconfig" - -endif - -source "drivers/usb/musb/Kconfig" - -source "drivers/usb/dwc3/Kconfig" - -source "drivers/usb/dwc2/Kconfig" - -source "drivers/usb/chipidea/Kconfig" - -source "drivers/usb/isp1760/Kconfig" - -comment "USB port drivers" - -if USB - -config USB_USS720 - tristate "USS720 parport driver" - depends on PARPORT - select PARPORT_NOT_PC - ---help--- - This driver is for USB parallel port adapters that use the Lucent - Technologies USS-720 chip. These cables are plugged into your USB - port and provide USB compatibility to peripherals designed with - parallel port interfaces. - - The chip has two modes: automatic mode and manual mode. In automatic - mode, it looks to the computer like a standard USB printer. Only - printers may be connected to the USS-720 in this mode. The generic - USB printer driver ("USB Printer support", above) may be used in - that mode, and you can say N here if you want to use the chip only - in this mode. - - Manual mode is not limited to printers, any parallel port - device should work. This driver utilizes manual mode. - Note however that some operations are three orders of magnitude - slower than on a PCI/ISA Parallel Port, so timing critical - applications might not work. - - Say Y here if you own an USS-720 USB->Parport cable and intend to - connect anything other than a printer to it. - - To compile this driver as a module, choose M here: the - module will be called uss720. - -source "drivers/usb/serial/Kconfig" - -source "drivers/usb/misc/Kconfig" - -source "drivers/usb/atm/Kconfig" - -endif # USB - -source "drivers/usb/phy/Kconfig" - -source "drivers/usb/gadget/Kconfig" - -config USB_LED_TRIG - bool "USB LED Triggers" - depends on LEDS_CLASS && LEDS_TRIGGERS - select USB_COMMON - help - This option adds LED triggers for USB host and/or gadget activity. - - Say Y here if you are working on a system with led-class supported - LEDs and you want to use them as activity indicators for USB host or - gadget. - -config USB_ULPI_BUS - tristate "USB ULPI PHY interface support" - select USB_COMMON - help - UTMI+ Low Pin Interface (ULPI) is specification for a commonly used - USB 2.0 PHY interface. The ULPI specification defines a standard set - of registers that can be used to detect the vendor and product which - allows ULPI to be handled as a bus. This module is the driver for that - bus. - - The ULPI interfaces (the buses) are registered by the drivers for USB - controllers which support ULPI register access and have ULPI PHY - attached to them. The ULPI PHY drivers themselves are normal PHY - drivers. - - ULPI PHYs provide often functions such as ADP sensing/probing (OTG - protocol) and USB charger detection. - - To compile this driver as a module, choose M here: the module will - be called ulpi. - -endif # USB_SUPPORT diff --git a/src/linux/drivers/usb/atm/Kconfig b/src/linux/drivers/usb/atm/Kconfig deleted file mode 100644 index 0f92294..0000000 --- a/src/linux/drivers/usb/atm/Kconfig +++ /dev/null @@ -1,68 +0,0 @@ -# -# USB/ATM DSL configuration -# - -menuconfig USB_ATM - tristate "USB DSL modem support" - depends on ATM - select CRC32 - default n - help - Say Y here if you want to connect a USB Digital Subscriber Line (DSL) - modem to your computer's USB port. You will then need to choose your - modem from the list below. - - To compile this driver as a module, choose M here: the - module will be called usbatm. - -if USB_ATM - -config USB_SPEEDTOUCH - tristate "Speedtouch USB support" - select FW_LOADER - help - Say Y here if you have an SpeedTouch USB or SpeedTouch 330 - modem. In order to use your modem you will need to install the - two parts of the firmware, extracted by the user space tools; see - for details. - - To compile this driver as a module, choose M here: the - module will be called speedtch. - -config USB_CXACRU - tristate "Conexant AccessRunner USB support" - select FW_LOADER - help - Say Y here if you have an ADSL USB modem based on the Conexant - AccessRunner chipset. In order to use your modem you will need to - install the firmware, extracted by the user space tools; see - for details. - - To compile this driver as a module, choose M here: the - module will be called cxacru. - -config USB_UEAGLEATM - tristate "ADI 930 and eagle USB DSL modem" - select FW_LOADER - help - Say Y here if you have an ADSL USB modem based on the ADI 930 - or eagle chipset. In order to use your modem you will need to - install firmwares and CMV (Command Management Variables); see - for details. - - To compile this driver as a module, choose M here: the - module will be called ueagle-atm. - -config USB_XUSBATM - tristate "Other USB DSL modem support" - help - Say Y here if you have a DSL USB modem not explicitly supported by - another USB DSL drivers. In order to use your modem you will need to - pass the vendor ID, product ID, and endpoint numbers for transmission - and reception as module parameters. You may need to initialize - the modem using a user space utility (a firmware loader for example). - - To compile this driver as a module, choose M here: the - module will be called xusbatm. - -endif # USB_ATM diff --git a/src/linux/drivers/usb/chipidea/Kconfig b/src/linux/drivers/usb/chipidea/Kconfig deleted file mode 100644 index 5e5b9eb..0000000 --- a/src/linux/drivers/usb/chipidea/Kconfig +++ /dev/null @@ -1,41 +0,0 @@ -config USB_CHIPIDEA - tristate "ChipIdea Highspeed Dual Role Controller" - depends on ((USB_EHCI_HCD && USB_GADGET) || (USB_EHCI_HCD && !USB_GADGET) || (!USB_EHCI_HCD && USB_GADGET)) && HAS_DMA - select EXTCON - help - Say Y here if your system has a dual role high speed USB - controller based on ChipIdea silicon IP. It supports: - Dual-role switch (ID, OTG FSM, sysfs), Host-only, and - Peripheral-only. - - When compiled dynamically, the module will be called ci-hdrc.ko. - -if USB_CHIPIDEA - -config USB_CHIPIDEA_OF - tristate - depends on OF - default USB_CHIPIDEA - -config USB_CHIPIDEA_PCI - tristate - depends on PCI - depends on NOP_USB_XCEIV - default USB_CHIPIDEA - -config USB_CHIPIDEA_UDC - bool "ChipIdea device controller" - depends on USB_GADGET - help - Say Y here to enable device controller functionality of the - ChipIdea driver. - -config USB_CHIPIDEA_HOST - bool "ChipIdea host controller" - depends on USB_EHCI_HCD - select USB_EHCI_ROOT_HUB_TT - help - Say Y here to enable host controller functionality of the - ChipIdea driver. - -endif diff --git a/src/linux/drivers/usb/class/Kconfig b/src/linux/drivers/usb/class/Kconfig deleted file mode 100644 index bb8b736..0000000 --- a/src/linux/drivers/usb/class/Kconfig +++ /dev/null @@ -1,48 +0,0 @@ -# -# USB Class driver configuration -# -comment "USB Device Class drivers" - -config USB_ACM - tristate "USB Modem (CDC ACM) support" - depends on TTY - ---help--- - This driver supports USB modems and ISDN adapters which support the - Communication Device Class Abstract Control Model interface. - Please read for details. - - If your modem only reports "Cls=ff(vend.)" in the descriptors in - /proc/bus/usb/devices, then your modem will not work with this - driver. - - To compile this driver as a module, choose M here: the - module will be called cdc-acm. - -config USB_PRINTER - tristate "USB Printer support" - help - Say Y here if you want to connect a USB printer to your computer's - USB port. - - To compile this driver as a module, choose M here: the - module will be called usblp. - -config USB_WDM - tristate "USB Wireless Device Management support" - ---help--- - This driver supports the WMC Device Management functionality - of cell phones compliant to the CDC WMC specification. You can use - AT commands over this device. - - To compile this driver as a module, choose M here: the - module will be called cdc-wdm. - -config USB_TMC - tristate "USB Test and Measurement Class support" - help - Say Y here if you want to connect a USB device that follows - the USB.org specification for USB Test and Measurement devices - to your computer's USB port. - - To compile this driver as a module, choose M here: the - module will be called usbtmc. diff --git a/src/linux/drivers/usb/core/Kconfig b/src/linux/drivers/usb/core/Kconfig deleted file mode 100644 index 0e5a889..0000000 --- a/src/linux/drivers/usb/core/Kconfig +++ /dev/null @@ -1,92 +0,0 @@ -# -# USB Core configuration -# -config USB_ANNOUNCE_NEW_DEVICES - bool "USB announce new devices" - help - Say Y here if you want the USB core to always announce the - idVendor, idProduct, Manufacturer, Product, and SerialNumber - strings for every new USB device to the syslog. This option is - usually used by distro vendors to help with debugging and to - let users know what specific device was added to the machine - in what location. - - If you do not want this kind of information sent to the system - log, or have any doubts about this, say N here. - -comment "Miscellaneous USB options" - -config USB_DEFAULT_PERSIST - bool "Enable USB persist by default" - default y - help - Say N here if you don't want USB power session persistence - enabled by default. If you say N it will make suspended USB - devices that lose power get reenumerated as if they had been - unplugged, causing any mounted filesystems to be lost. The - persist feature can still be enabled for individual devices - through the power/persist sysfs node. See - Documentation/usb/persist.txt for more info. - - If you have any questions about this, say Y here, only say N - if you know exactly what you are doing. - -config USB_DYNAMIC_MINORS - bool "Dynamic USB minor allocation" - help - If you say Y here, the USB subsystem will use dynamic minor - allocation for any device that uses the USB major number. - This means that you can have more than 16 of a single type - of device (like USB printers). - - If you are unsure about this, say N here. - -config USB_OTG - bool "OTG support" - depends on PM - default n - help - The most notable feature of USB OTG is support for a - "Dual-Role" device, which can act as either a device - or a host. The initial role is decided by the type of - plug inserted and can be changed later when two dual - role devices talk to each other. - - Select this only if your board has Mini-AB/Micro-AB - connector. - -config USB_OTG_WHITELIST - bool "Rely on OTG and EH Targeted Peripherals List" - depends on USB - help - If you say Y here, the "otg_whitelist.h" file will be used as a - product whitelist, so USB peripherals not listed there will be - rejected during enumeration. This behavior is required by the - USB OTG and EH specification for all devices not on your product's - "Targeted Peripherals List". "Embedded Hosts" are likewise - allowed to support only a limited number of peripherals. - -config USB_OTG_BLACKLIST_HUB - bool "Disable external hubs" - depends on USB_OTG || EXPERT - help - If you say Y here, then Linux will refuse to enumerate - external hubs. OTG hosts are allowed to reduce hardware - and software costs by not supporting external hubs. So - are "Embedded Hosts" that don't offer OTG support. - -config USB_OTG_FSM - tristate "USB 2.0 OTG FSM implementation" - depends on USB && USB_OTG - select USB_PHY - help - Implements OTG Finite State Machine as specified in On-The-Go - and Embedded Host Supplement to the USB Revision 2.0 Specification. - -config USB_LEDS_TRIGGER_USBPORT - tristate "USB port LED trigger" - depends on USB && LEDS_TRIGGERS - help - This driver allows LEDs to be controlled by USB events. Enabling this - trigger allows specifying list of USB ports that should turn on LED - when some USB device gets connected. diff --git a/src/linux/drivers/usb/dwc2/Kconfig b/src/linux/drivers/usb/dwc2/Kconfig deleted file mode 100644 index e838701..0000000 --- a/src/linux/drivers/usb/dwc2/Kconfig +++ /dev/null @@ -1,95 +0,0 @@ -config USB_DWC2 - tristate "DesignWare USB2 DRD Core Support" - depends on HAS_DMA - depends on USB || USB_GADGET - depends on HAS_IOMEM - help - Say Y here if your system has a Dual Role Hi-Speed USB - controller based on the DesignWare HSOTG IP Core. - - For host mode, if you choose to build the driver as dynamically - linked modules, the core module will be called dwc2.ko, the PCI - bus interface module (if you have a PCI bus system) will be - called dwc2_pci.ko, and the platform interface module (for - controllers directly connected to the CPU) will be called - dwc2_platform.ko. For all modes(host, gadget and dual-role), there - will be an additional module named dwc2.ko. - -if USB_DWC2 - -choice - bool "DWC2 Mode Selection" - default USB_DWC2_DUAL_ROLE if (USB && USB_GADGET) - default USB_DWC2_HOST if (USB && !USB_GADGET) - default USB_DWC2_PERIPHERAL if (!USB && USB_GADGET) - -config USB_DWC2_HOST - bool "Host only mode" - depends on USB=y || (USB_DWC2=m && USB) - help - The Designware USB2.0 high-speed host controller - integrated into many SoCs. Select this option if you want the - driver to operate in Host-only mode. - -comment "Gadget/Dual-role mode requires USB Gadget support to be enabled" - -config USB_DWC2_PERIPHERAL - bool "Gadget only mode" - depends on USB_GADGET=y || USB_GADGET=USB_DWC2 - help - The Designware USB2.0 high-speed gadget controller - integrated into many SoCs. Select this option if you want the - driver to operate in Peripheral-only mode. This option requires - USB_GADGET to be enabled. - -config USB_DWC2_DUAL_ROLE - bool "Dual Role mode" - depends on (USB=y && USB_GADGET=y) || (USB_DWC2=m && USB && USB_GADGET) - help - Select this option if you want the driver to work in a dual-role - mode. In this mode both host and gadget features are enabled, and - the role will be determined by the cable that gets plugged-in. This - option requires USB_GADGET to be enabled. -endchoice - -config USB_DWC2_PCI - tristate "DWC2 PCI" - depends on PCI - depends on USB_GADGET || !USB_GADGET - default n - select NOP_USB_XCEIV - help - The Designware USB2.0 PCI interface module for controllers - connected to a PCI bus. - -config USB_DWC2_DEBUG - bool "Enable Debugging Messages" - help - Say Y here to enable debugging messages in the DWC2 Driver. - -config USB_DWC2_VERBOSE - bool "Enable Verbose Debugging Messages" - depends on USB_DWC2_DEBUG - help - Say Y here to enable verbose debugging messages in the DWC2 Driver. - WARNING: Enabling this will quickly fill your message log. - If in doubt, say N. - -config USB_DWC2_TRACK_MISSED_SOFS - bool "Enable Missed SOF Tracking" - help - Say Y here to enable logging of missed SOF events to the dmesg log. - WARNING: This feature is still experimental. - If in doubt, say N. - -config USB_DWC2_DEBUG_PERIODIC - bool "Enable Debugging Messages For Periodic Transfers" - depends on USB_DWC2_DEBUG || USB_DWC2_VERBOSE - default y - help - Say N here to disable (verbose) debugging messages to be - logged for periodic transfers. This allows better debugging of - non-periodic transfers, but of course the debug logs will be - incomplete. Note that this also disables some debug messages - for which the transfer type cannot be deduced. -endif diff --git a/src/linux/drivers/usb/dwc3/Kconfig b/src/linux/drivers/usb/dwc3/Kconfig deleted file mode 100644 index b97cde7..0000000 --- a/src/linux/drivers/usb/dwc3/Kconfig +++ /dev/null @@ -1,108 +0,0 @@ -config USB_DWC3 - tristate "DesignWare USB3 DRD Core Support" - depends on (USB || USB_GADGET) && HAS_DMA - select USB_XHCI_PLATFORM if USB_XHCI_HCD - help - Say Y or M here if your system has a Dual Role SuperSpeed - USB controller based on the DesignWare USB3 IP Core. - - If you choose to build this driver is a dynamically linked - module, the module will be called dwc3.ko. - -if USB_DWC3 - -config USB_DWC3_ULPI - bool "Register ULPI PHY Interface" - depends on USB_ULPI_BUS=y || USB_ULPI_BUS=USB_DWC3 - help - Select this if you have ULPI type PHY attached to your DWC3 - controller. - -choice - bool "DWC3 Mode Selection" - default USB_DWC3_DUAL_ROLE if (USB && USB_GADGET) - default USB_DWC3_HOST if (USB && !USB_GADGET) - default USB_DWC3_GADGET if (!USB && USB_GADGET) - -config USB_DWC3_HOST - bool "Host only mode" - depends on USB=y || USB=USB_DWC3 - help - Select this when you want to use DWC3 in host mode only, - thereby the gadget feature will be regressed. - -config USB_DWC3_GADGET - bool "Gadget only mode" - depends on USB_GADGET=y || USB_GADGET=USB_DWC3 - help - Select this when you want to use DWC3 in gadget mode only, - thereby the host feature will be regressed. - -config USB_DWC3_DUAL_ROLE - bool "Dual Role mode" - depends on ((USB=y || USB=USB_DWC3) && (USB_GADGET=y || USB_GADGET=USB_DWC3)) - help - This is the default mode of working of DWC3 controller where - both host and gadget features are enabled. - -endchoice - -comment "Platform Glue Driver Support" - -config USB_DWC3_OMAP - tristate "Texas Instruments OMAP5 and similar Platforms" - depends on EXTCON && (ARCH_OMAP2PLUS || COMPILE_TEST) - depends on OF - default USB_DWC3 - help - Some platforms from Texas Instruments like OMAP5, DRA7xxx and - AM437x use this IP for USB2/3 functionality. - - Say 'Y' or 'M' here if you have one such device - -config USB_DWC3_EXYNOS - tristate "Samsung Exynos Platform" - depends on ARCH_EXYNOS && OF || COMPILE_TEST - default USB_DWC3 - help - Recent Exynos5 SoCs ship with one DesignWare Core USB3 IP inside, - say 'Y' or 'M' if you have one such device. - -config USB_DWC3_PCI - tristate "PCIe-based Platforms" - depends on PCI - default USB_DWC3 - help - If you're using the DesignWare Core IP with a PCIe, please say - 'Y' or 'M' here. - - One such PCIe-based platform is Synopsys' PCIe HAPS model of - this IP. - -config USB_DWC3_KEYSTONE - tristate "Texas Instruments Keystone2 Platforms" - depends on ARCH_KEYSTONE || COMPILE_TEST - default USB_DWC3 - help - Support of USB2/3 functionality in TI Keystone2 platforms. - Say 'Y' or 'M' here if you have one such device - -config USB_DWC3_OF_SIMPLE - tristate "Generic OF Simple Glue Layer" - depends on OF && COMMON_CLK - default USB_DWC3 - help - Support USB2/3 functionality in simple SoC integrations. - Currently supports Xilinx and Qualcomm DWC USB3 IP. - Say 'Y' or 'M' if you have one such device. - -config USB_DWC3_ST - tristate "STMicroelectronics Platforms" - depends on ARCH_STI && OF - default USB_DWC3 - help - STMicroelectronics SoCs with one DesignWare Core USB3 IP - inside (i.e. STiH407). - Say 'Y' or 'M' if you have one such device. - -endif diff --git a/src/linux/drivers/usb/gadget/Kconfig b/src/linux/drivers/usb/gadget/Kconfig deleted file mode 100644 index 8ad2032..0000000 --- a/src/linux/drivers/usb/gadget/Kconfig +++ /dev/null @@ -1,483 +0,0 @@ -# -# USB Gadget support on a system involves -# (a) a peripheral controller, and -# (b) the gadget driver using it. -# -# NOTE: Gadget support ** DOES NOT ** depend on host-side CONFIG_USB !! -# -# - Host systems (like PCs) need CONFIG_USB (with "A" jacks). -# - Peripherals (like PDAs) need CONFIG_USB_GADGET (with "B" jacks). -# - Some systems have both kinds of controllers. -# -# With help from a special transceiver and a "Mini-AB" jack, systems with -# both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG). -# - -menuconfig USB_GADGET - tristate "USB Gadget Support" - select USB_COMMON - select NLS - help - USB is a master/slave protocol, organized with one master - host (such as a PC) controlling up to 127 peripheral devices. - The USB hardware is asymmetric, which makes it easier to set up: - you can't connect a "to-the-host" connector to a peripheral. - - Linux can run in the host, or in the peripheral. In both cases - you need a low level bus controller driver, and some software - talking to it. Peripheral controllers are often discrete silicon, - or are integrated with the CPU in a microcontroller. The more - familiar host side controllers have names like "EHCI", "OHCI", - or "UHCI", and are usually integrated into southbridges on PC - motherboards. - - Enable this configuration option if you want to run Linux inside - a USB peripheral device. Configure one hardware driver for your - peripheral/device side bus controller, and a "gadget driver" for - your peripheral protocol. (If you use modular gadget drivers, - you may configure more than one.) - - If in doubt, say "N" and don't enable these drivers; most people - don't have this kind of hardware (except maybe inside Linux PDAs). - - For more information, see and - the kernel DocBook documentation for this API. - -if USB_GADGET - -config USB_GADGET_DEBUG - bool "Debugging messages (DEVELOPMENT)" - depends on DEBUG_KERNEL - help - Many controller and gadget drivers will print some debugging - messages if you use this option to ask for those messages. - - Avoid enabling these messages, even if you're actively - debugging such a driver. Many drivers will emit so many - messages that the driver timings are affected, which will - either create new failure modes or remove the one you're - trying to track down. Never enable these messages for a - production build. - -config USB_GADGET_VERBOSE - bool "Verbose debugging Messages (DEVELOPMENT)" - depends on USB_GADGET_DEBUG - help - Many controller and gadget drivers will print verbose debugging - messages if you use this option to ask for those messages. - - Avoid enabling these messages, even if you're actively - debugging such a driver. Many drivers will emit so many - messages that the driver timings are affected, which will - either create new failure modes or remove the one you're - trying to track down. Never enable these messages for a - production build. - -config USB_GADGET_DEBUG_FILES - bool "Debugging information files (DEVELOPMENT)" - depends on PROC_FS - help - Some of the drivers in the "gadget" framework can expose - debugging information in files such as /proc/driver/udc - (for a peripheral controller). The information in these - files may help when you're troubleshooting or bringing up a - driver on a new board. Enable these files by choosing "Y" - here. If in doubt, or to conserve kernel memory, say "N". - -config USB_GADGET_DEBUG_FS - bool "Debugging information files in debugfs (DEVELOPMENT)" - depends on DEBUG_FS - help - Some of the drivers in the "gadget" framework can expose - debugging information in files under /sys/kernel/debug/. - The information in these files may help when you're - troubleshooting or bringing up a driver on a new board. - Enable these files by choosing "Y" here. If in doubt, or - to conserve kernel memory, say "N". - -config USB_GADGET_VBUS_DRAW - int "Maximum VBUS Power usage (2-500 mA)" - range 2 500 - default 2 - help - Some devices need to draw power from USB when they are - configured, perhaps to operate circuitry or to recharge - batteries. This is in addition to any local power supply, - such as an AC adapter or batteries. - - Enter the maximum power your device draws through USB, in - milliAmperes. The permitted range of values is 2 - 500 mA; - 0 mA would be legal, but can make some hosts misbehave. - - This value will be used except for system-specific gadget - drivers that have more specific information. - -config USB_GADGET_STORAGE_NUM_BUFFERS - int "Number of storage pipeline buffers" - range 2 256 - default 2 - help - Usually 2 buffers are enough to establish a good buffering - pipeline. The number may be increased in order to compensate - for a bursty VFS behaviour. For instance there may be CPU wake up - latencies that makes the VFS to appear bursty in a system with - an CPU on-demand governor. Especially if DMA is doing IO to - offload the CPU. In this case the CPU will go into power - save often and spin up occasionally to move data within VFS. - If selecting USB_GADGET_DEBUG_FILES this value may be set by - a module parameter as well. - If unsure, say 2. - -config U_SERIAL_CONSOLE - bool "Serial gadget console support" - depends on USB_G_SERIAL - help - It supports the serial gadget can be used as a console. - -source "drivers/usb/gadget/udc/Kconfig" - -# -# USB Gadget Drivers -# - -# composite based drivers -config USB_LIBCOMPOSITE - tristate - select CONFIGFS_FS - depends on USB_GADGET - -config USB_F_ACM - tristate - -config USB_F_SS_LB - tristate - -config USB_U_SERIAL - tristate - -config USB_U_ETHER - tristate - -config USB_F_SERIAL - tristate - -config USB_F_OBEX - tristate - -config USB_F_NCM - tristate - -config USB_F_ECM - tristate - -config USB_F_PHONET - tristate - -config USB_F_EEM - tristate - -config USB_F_SUBSET - tristate - -config USB_F_RNDIS - tristate - -config USB_F_MASS_STORAGE - tristate - -config USB_F_FS - tristate - -config USB_F_UAC1 - tristate - -config USB_F_UAC2 - tristate - -config USB_F_UVC - tristate - -config USB_F_MIDI - tristate - -config USB_F_HID - tristate - -config USB_F_PRINTER - tristate - -config USB_F_TCM - tristate - -# this first set of drivers all depend on bulk-capable hardware. - -config USB_CONFIGFS - tristate "USB functions configurable through configfs" - select USB_LIBCOMPOSITE - help - A Linux USB "gadget" can be set up through configfs. - If this is the case, the USB functions (which from the host's - perspective are seen as interfaces) and configurations are - specified simply by creating appropriate directories in configfs. - Associating functions with configurations is done by creating - appropriate symbolic links. - For more information see Documentation/usb/gadget_configfs.txt. - -config USB_CONFIGFS_SERIAL - bool "Generic serial bulk in/out" - depends on USB_CONFIGFS - depends on TTY - select USB_U_SERIAL - select USB_F_SERIAL - help - The function talks to the Linux-USB generic serial driver. - -config USB_CONFIGFS_ACM - bool "Abstract Control Model (CDC ACM)" - depends on USB_CONFIGFS - depends on TTY - select USB_U_SERIAL - select USB_F_ACM - help - ACM serial link. This function can be used to interoperate with - MS-Windows hosts or with the Linux-USB "cdc-acm" driver. - -config USB_CONFIGFS_OBEX - bool "Object Exchange Model (CDC OBEX)" - depends on USB_CONFIGFS - depends on TTY - select USB_U_SERIAL - select USB_F_OBEX - help - You will need a user space OBEX server talking to /dev/ttyGS*, - since the kernel itself doesn't implement the OBEX protocol. - -config USB_CONFIGFS_NCM - bool "Network Control Model (CDC NCM)" - depends on USB_CONFIGFS - depends on NET - select USB_U_ETHER - select USB_F_NCM - help - NCM is an advanced protocol for Ethernet encapsulation, allows - grouping of several ethernet frames into one USB transfer and - different alignment possibilities. - -config USB_CONFIGFS_ECM - bool "Ethernet Control Model (CDC ECM)" - depends on USB_CONFIGFS - depends on NET - select USB_U_ETHER - select USB_F_ECM - help - The "Communication Device Class" (CDC) Ethernet Control Model. - That protocol is often avoided with pure Ethernet adapters, in - favor of simpler vendor-specific hardware, but is widely - supported by firmware for smart network devices. - -config USB_CONFIGFS_ECM_SUBSET - bool "Ethernet Control Model (CDC ECM) subset" - depends on USB_CONFIGFS - depends on NET - select USB_U_ETHER - select USB_F_SUBSET - help - On hardware that can't implement the full protocol, - a simple CDC subset is used, placing fewer demands on USB. - -config USB_CONFIGFS_RNDIS - bool "RNDIS" - depends on USB_CONFIGFS - depends on NET - select USB_U_ETHER - select USB_F_RNDIS - help - Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol, - and Microsoft provides redistributable binary RNDIS drivers for - older versions of Windows. - - To make MS-Windows work with this, use Documentation/usb/linux.inf - as the "driver info file". For versions of MS-Windows older than - XP, you'll need to download drivers from Microsoft's website; a URL - is given in comments found in that info file. - -config USB_CONFIGFS_EEM - bool "Ethernet Emulation Model (EEM)" - depends on USB_CONFIGFS - depends on NET - select USB_U_ETHER - select USB_F_EEM - help - CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM - and therefore can be supported by more hardware. Technically ECM and - EEM are designed for different applications. The ECM model extends - the network interface to the target (e.g. a USB cable modem), and the - EEM model is for mobile devices to communicate with hosts using - ethernet over USB. For Linux gadgets, however, the interface with - the host is the same (a usbX device), so the differences are minimal. - -config USB_CONFIGFS_PHONET - bool "Phonet protocol" - depends on USB_CONFIGFS - depends on NET - depends on PHONET - select USB_U_ETHER - select USB_F_PHONET - help - The Phonet protocol implementation for USB device. - -config USB_CONFIGFS_MASS_STORAGE - bool "Mass storage" - depends on USB_CONFIGFS - depends on BLOCK - select USB_F_MASS_STORAGE - help - The Mass Storage Gadget acts as a USB Mass Storage disk drive. - As its storage repository it can use a regular file or a block - device (in much the same way as the "loop" device driver), - specified as a module parameter or sysfs option. - -config USB_CONFIGFS_F_LB_SS - bool "Loopback and sourcesink function (for testing)" - depends on USB_CONFIGFS - select USB_F_SS_LB - help - Loopback function loops back a configurable number of transfers. - Sourcesink function either sinks and sources bulk data. - It also implements control requests, for "chapter 9" conformance. - Make this be the first driver you try using on top of any new - USB peripheral controller driver. Then you can use host-side - test software, like the "usbtest" driver, to put your hardware - and its driver through a basic set of functional tests. - -config USB_CONFIGFS_F_FS - bool "Function filesystem (FunctionFS)" - depends on USB_CONFIGFS - select USB_F_FS - help - The Function Filesystem (FunctionFS) lets one create USB - composite functions in user space in the same way GadgetFS - lets one create USB gadgets in user space. This allows creation - of composite gadgets such that some of the functions are - implemented in kernel space (for instance Ethernet, serial or - mass storage) and other are implemented in user space. - -config USB_CONFIGFS_F_UAC1 - bool "Audio Class 1.0" - depends on USB_CONFIGFS - depends on SND - select USB_LIBCOMPOSITE - select SND_PCM - select USB_F_UAC1 - help - This Audio function implements 1 AudioControl interface, - 1 AudioStreaming Interface each for USB-OUT and USB-IN. - This driver requires a real Audio codec to be present - on the device. - -config USB_CONFIGFS_F_UAC2 - bool "Audio Class 2.0" - depends on USB_CONFIGFS - depends on SND - select USB_LIBCOMPOSITE - select SND_PCM - select USB_F_UAC2 - help - This Audio function is compatible with USB Audio Class - specification 2.0. It implements 1 AudioControl interface, - 1 AudioStreaming Interface each for USB-OUT and USB-IN. - This driver doesn't expect any real Audio codec to be present - on the device - the audio streams are simply sinked to and - sourced from a virtual ALSA sound card created. The user-space - application may choose to do whatever it wants with the data - received from the USB Host and choose to provide whatever it - wants as audio data to the USB Host. - -config USB_CONFIGFS_F_MIDI - bool "MIDI function" - depends on USB_CONFIGFS - depends on SND - select USB_LIBCOMPOSITE - select SND_RAWMIDI - select USB_F_MIDI - help - The MIDI Function acts as a USB Audio device, with one MIDI - input and one MIDI output. These MIDI jacks appear as - a sound "card" in the ALSA sound system. Other MIDI - connections can then be made on the gadget system, using - ALSA's aconnect utility etc. - -config USB_CONFIGFS_F_HID - bool "HID function" - depends on USB_CONFIGFS - select USB_F_HID - help - The HID function driver provides generic emulation of USB - Human Interface Devices (HID). - - For more information, see Documentation/usb/gadget_hid.txt. - -config USB_CONFIGFS_F_UVC - bool "USB Webcam function" - depends on USB_CONFIGFS - depends on VIDEO_V4L2 - depends on VIDEO_DEV - select VIDEOBUF2_VMALLOC - select USB_F_UVC - help - The Webcam function acts as a composite USB Audio and Video Class - device. It provides a userspace API to process UVC control requests - and stream video data to the host. - -config USB_CONFIGFS_F_PRINTER - bool "Printer function" - select USB_F_PRINTER - depends on USB_CONFIGFS - help - The Printer function channels data between the USB host and a - userspace program driving the print engine. The user space - program reads and writes the device file /dev/g_printer to - receive or send printer data. It can use ioctl calls to - the device file to get or set printer status. - - For more information, see Documentation/usb/gadget_printer.txt - which includes sample code for accessing the device file. - -config USB_CONFIGFS_F_TCM - bool "USB Gadget Target Fabric" - depends on TARGET_CORE - depends on USB_CONFIGFS - select USB_LIBCOMPOSITE - select USB_F_TCM - help - This fabric is a USB gadget component. Two USB protocols are - supported that is BBB or BOT (Bulk Only Transport) and UAS - (USB Attached SCSI). BOT is advertised on alternative - interface 0 (primary) and UAS is on alternative interface 1. - Both protocols can work on USB2.0 and USB3.0. - UAS utilizes the USB 3.0 feature called streams support. - -choice - tristate "USB Gadget Drivers" - default USB_ETH - help - A Linux "Gadget Driver" talks to the USB Peripheral Controller - driver through the abstract "gadget" API. Some other operating - systems call these "client" drivers, of which "class drivers" - are a subset (implementing a USB device class specification). - A gadget driver implements one or more USB functions using - the peripheral hardware. - - Gadget drivers are hardware-neutral, or "platform independent", - except that they sometimes must understand quirks or limitations - of the particular controllers they work with. For example, when - a controller doesn't support alternate configurations or provide - enough of the right types of endpoints, the gadget driver might - not be able work with that controller, or might need to implement - a less common variant of a device class protocol. - -source "drivers/usb/gadget/legacy/Kconfig" - -endchoice - -endif # USB_GADGET diff --git a/src/linux/drivers/usb/gadget/legacy/Kconfig b/src/linux/drivers/usb/gadget/legacy/Kconfig deleted file mode 100644 index 0b36878..0000000 --- a/src/linux/drivers/usb/gadget/legacy/Kconfig +++ /dev/null @@ -1,483 +0,0 @@ -# -# USB Gadget support on a system involves -# (a) a peripheral controller, and -# (b) the gadget driver using it. -# -# NOTE: Gadget support ** DOES NOT ** depend on host-side CONFIG_USB !! -# -# - Host systems (like PCs) need CONFIG_USB (with "A" jacks). -# - Peripherals (like PDAs) need CONFIG_USB_GADGET (with "B" jacks). -# - Some systems have both kinds of controllers. -# -# With help from a special transceiver and a "Mini-AB" jack, systems with -# both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG). -# - -config USB_ZERO - tristate "Gadget Zero (DEVELOPMENT)" - select USB_LIBCOMPOSITE - select USB_F_SS_LB - help - Gadget Zero is a two-configuration device. It either sinks and - sources bulk data; or it loops back a configurable number of - transfers. It also implements control requests, for "chapter 9" - conformance. The driver needs only two bulk-capable endpoints, so - it can work on top of most device-side usb controllers. It's - useful for testing, and is also a working example showing how - USB "gadget drivers" can be written. - - Make this be the first driver you try using on top of any new - USB peripheral controller driver. Then you can use host-side - test software, like the "usbtest" driver, to put your hardware - and its driver through a basic set of functional tests. - - Gadget Zero also works with the host-side "usb-skeleton" driver, - and with many kinds of host-side test software. You may need - to tweak product and vendor IDs before host software knows about - this device, and arrange to select an appropriate configuration. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_zero". - -config USB_ZERO_HNPTEST - bool "HNP Test Device" - depends on USB_ZERO && USB_OTG - help - You can configure this device to enumerate using the device - identifiers of the USB-OTG test device. That means that when - this gadget connects to another OTG device, with this one using - the "B-Peripheral" role, that device will use HNP to let this - one serve as the USB host instead (in the "B-Host" role). - -config USB_AUDIO - tristate "Audio Gadget" - depends on SND - select USB_LIBCOMPOSITE - select SND_PCM - select USB_F_UAC1 if GADGET_UAC1 - select USB_F_UAC2 if !GADGET_UAC1 - help - This Gadget Audio driver is compatible with USB Audio Class - specification 2.0. It implements 1 AudioControl interface, - 1 AudioStreaming Interface each for USB-OUT and USB-IN. - Number of channels, sample rate and sample size can be - specified as module parameters. - This driver doesn't expect any real Audio codec to be present - on the device - the audio streams are simply sinked to and - sourced from a virtual ALSA sound card created. The user-space - application may choose to do whatever it wants with the data - received from the USB Host and choose to provide whatever it - wants as audio data to the USB Host. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_audio". - -config GADGET_UAC1 - bool "UAC 1.0 (Legacy)" - depends on USB_AUDIO - help - If you instead want older UAC Spec-1.0 driver that also has audio - paths hardwired to the Audio codec chip on-board and doesn't work - without one. - -config USB_ETH - tristate "Ethernet Gadget (with CDC Ethernet support)" - depends on NET - select USB_LIBCOMPOSITE - select USB_U_ETHER - select USB_F_ECM - select USB_F_SUBSET - select CRC32 - help - This driver implements Ethernet style communication, in one of - several ways: - - - The "Communication Device Class" (CDC) Ethernet Control Model. - That protocol is often avoided with pure Ethernet adapters, in - favor of simpler vendor-specific hardware, but is widely - supported by firmware for smart network devices. - - - On hardware can't implement that protocol, a simple CDC subset - is used, placing fewer demands on USB. - - - CDC Ethernet Emulation Model (EEM) is a newer standard that has - a simpler interface that can be used by more USB hardware. - - RNDIS support is an additional option, more demanding than subset. - - Within the USB device, this gadget driver exposes a network device - "usbX", where X depends on what other networking devices you have. - Treat it like a two-node Ethernet link: host, and gadget. - - The Linux-USB host-side "usbnet" driver interoperates with this - driver, so that deep I/O queues can be supported. On 2.4 kernels, - use "CDCEther" instead, if you're using the CDC option. That CDC - mode should also interoperate with standard CDC Ethernet class - drivers on other host operating systems. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_ether". - -config USB_ETH_RNDIS - bool "RNDIS support" - depends on USB_ETH - select USB_LIBCOMPOSITE - select USB_F_RNDIS - default y - help - Microsoft Windows XP bundles the "Remote NDIS" (RNDIS) protocol, - and Microsoft provides redistributable binary RNDIS drivers for - older versions of Windows. - - If you say "y" here, the Ethernet gadget driver will try to provide - a second device configuration, supporting RNDIS to talk to such - Microsoft USB hosts. - - To make MS-Windows work with this, use Documentation/usb/linux.inf - as the "driver info file". For versions of MS-Windows older than - XP, you'll need to download drivers from Microsoft's website; a URL - is given in comments found in that info file. - -config USB_ETH_EEM - bool "Ethernet Emulation Model (EEM) support" - depends on USB_ETH - select USB_LIBCOMPOSITE - select USB_F_EEM - default n - help - CDC EEM is a newer USB standard that is somewhat simpler than CDC ECM - and therefore can be supported by more hardware. Technically ECM and - EEM are designed for different applications. The ECM model extends - the network interface to the target (e.g. a USB cable modem), and the - EEM model is for mobile devices to communicate with hosts using - ethernet over USB. For Linux gadgets, however, the interface with - the host is the same (a usbX device), so the differences are minimal. - - If you say "y" here, the Ethernet gadget driver will use the EEM - protocol rather than ECM. If unsure, say "n". - -config USB_G_NCM - tristate "Network Control Model (NCM) support" - depends on NET - select USB_LIBCOMPOSITE - select USB_U_ETHER - select USB_F_NCM - select CRC32 - help - This driver implements USB CDC NCM subclass standard. NCM is - an advanced protocol for Ethernet encapsulation, allows grouping - of several ethernet frames into one USB transfer and different - alignment possibilities. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_ncm". - -config USB_GADGETFS - tristate "Gadget Filesystem" - help - This driver provides a filesystem based API that lets user mode - programs implement a single-configuration USB device, including - endpoint I/O and control requests that don't relate to enumeration. - All endpoints, transfer speeds, and transfer types supported by - the hardware are available, through read() and write() calls. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "gadgetfs". - -config USB_FUNCTIONFS - tristate "Function Filesystem" - select USB_LIBCOMPOSITE - select USB_F_FS - select USB_FUNCTIONFS_GENERIC if !(USB_FUNCTIONFS_ETH || USB_FUNCTIONFS_RNDIS) - help - The Function Filesystem (FunctionFS) lets one create USB - composite functions in user space in the same way GadgetFS - lets one create USB gadgets in user space. This allows creation - of composite gadgets such that some of the functions are - implemented in kernel space (for instance Ethernet, serial or - mass storage) and other are implemented in user space. - - If you say "y" or "m" here you will be able what kind of - configurations the gadget will provide. - - Say "y" to link the driver statically, or "m" to build - a dynamically linked module called "g_ffs". - -config USB_FUNCTIONFS_ETH - bool "Include configuration with CDC ECM (Ethernet)" - depends on USB_FUNCTIONFS && NET - select USB_U_ETHER - select USB_F_ECM - select USB_F_SUBSET - help - Include a configuration with CDC ECM function (Ethernet) and the - Function Filesystem. - -config USB_FUNCTIONFS_RNDIS - bool "Include configuration with RNDIS (Ethernet)" - depends on USB_FUNCTIONFS && NET - select USB_U_ETHER - select USB_F_RNDIS - help - Include a configuration with RNDIS function (Ethernet) and the Filesystem. - -config USB_FUNCTIONFS_GENERIC - bool "Include 'pure' configuration" - depends on USB_FUNCTIONFS - help - Include a configuration with the Function Filesystem alone with - no Ethernet interface. - -config USB_MASS_STORAGE - tristate "Mass Storage Gadget" - depends on BLOCK - select USB_LIBCOMPOSITE - select USB_F_MASS_STORAGE - help - The Mass Storage Gadget acts as a USB Mass Storage disk drive. - As its storage repository it can use a regular file or a block - device (in much the same way as the "loop" device driver), - specified as a module parameter or sysfs option. - - This driver is a replacement for now removed File-backed - Storage Gadget (g_file_storage). - - Say "y" to link the driver statically, or "m" to build - a dynamically linked module called "g_mass_storage". - -config USB_GADGET_TARGET - tristate "USB Gadget Target Fabric Module" - depends on TARGET_CORE - select USB_LIBCOMPOSITE - select USB_F_TCM - help - This fabric is an USB gadget. Two USB protocols are supported that is - BBB or BOT (Bulk Only Transport) and UAS (USB Attached SCSI). BOT is - advertised on alternative interface 0 (primary) and UAS is on - alternative interface 1. Both protocols can work on USB2.0 and USB3.0. - UAS utilizes the USB 3.0 feature called streams support. - -config USB_G_SERIAL - tristate "Serial Gadget (with CDC ACM and CDC OBEX support)" - depends on TTY - select USB_U_SERIAL - select USB_F_ACM - select USB_F_SERIAL - select USB_F_OBEX - select USB_LIBCOMPOSITE - help - The Serial Gadget talks to the Linux-USB generic serial driver. - This driver supports a CDC-ACM module option, which can be used - to interoperate with MS-Windows hosts or with the Linux-USB - "cdc-acm" driver. - - This driver also supports a CDC-OBEX option. You will need a - user space OBEX server talking to /dev/ttyGS*, since the kernel - itself doesn't implement the OBEX protocol. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_serial". - - For more information, see Documentation/usb/gadget_serial.txt - which includes instructions and a "driver info file" needed to - make MS-Windows work with CDC ACM. - -config USB_MIDI_GADGET - tristate "MIDI Gadget" - depends on SND - select USB_LIBCOMPOSITE - select SND_RAWMIDI - select USB_F_MIDI - help - The MIDI Gadget acts as a USB Audio device, with one MIDI - input and one MIDI output. These MIDI jacks appear as - a sound "card" in the ALSA sound system. Other MIDI - connections can then be made on the gadget system, using - ALSA's aconnect utility etc. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_midi". - -config USB_G_PRINTER - tristate "Printer Gadget" - select USB_LIBCOMPOSITE - select USB_F_PRINTER - help - The Printer Gadget channels data between the USB host and a - userspace program driving the print engine. The user space - program reads and writes the device file /dev/g_printer to - receive or send printer data. It can use ioctl calls to - the device file to get or set printer status. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_printer". - - For more information, see Documentation/usb/gadget_printer.txt - which includes sample code for accessing the device file. - -if TTY - -config USB_CDC_COMPOSITE - tristate "CDC Composite Device (Ethernet and ACM)" - depends on NET - select USB_LIBCOMPOSITE - select USB_U_SERIAL - select USB_U_ETHER - select USB_F_ACM - select USB_F_ECM - help - This driver provides two functions in one configuration: - a CDC Ethernet (ECM) link, and a CDC ACM (serial port) link. - - This driver requires four bulk and two interrupt endpoints, - plus the ability to handle altsettings. Not all peripheral - controllers are that capable. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module. - -config USB_G_NOKIA - tristate "Nokia composite gadget" - depends on PHONET - depends on BLOCK - select USB_LIBCOMPOSITE - select USB_U_SERIAL - select USB_U_ETHER - select USB_F_ACM - select USB_F_OBEX - select USB_F_PHONET - select USB_F_ECM - select USB_F_MASS_STORAGE - help - The Nokia composite gadget provides support for acm, obex - and phonet in only one composite gadget driver. - - It's only really useful for N900 hardware. If you're building - a kernel for N900, say Y or M here. If unsure, say N. - -config USB_G_ACM_MS - tristate "CDC Composite Device (ACM and mass storage)" - depends on BLOCK - select USB_LIBCOMPOSITE - select USB_U_SERIAL - select USB_F_ACM - select USB_F_MASS_STORAGE - help - This driver provides two functions in one configuration: - a mass storage, and a CDC ACM (serial port) link. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_acm_ms". - -config USB_G_MULTI - tristate "Multifunction Composite Gadget" - depends on BLOCK && NET - select USB_G_MULTI_CDC if !USB_G_MULTI_RNDIS - select USB_LIBCOMPOSITE - select USB_U_SERIAL - select USB_U_ETHER - select USB_F_ACM - select USB_F_MASS_STORAGE - help - The Multifunction Composite Gadget provides Ethernet (RNDIS - and/or CDC Ethernet), mass storage and ACM serial link - interfaces. - - You will be asked to choose which of the two configurations is - to be available in the gadget. At least one configuration must - be chosen to make the gadget usable. Selecting more than one - configuration will prevent Windows from automatically detecting - the gadget as a composite gadget, so an INF file will be needed to - use the gadget. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_multi". - -config USB_G_MULTI_RNDIS - bool "RNDIS + CDC Serial + Storage configuration" - depends on USB_G_MULTI - select USB_F_RNDIS - default y - help - This option enables a configuration with RNDIS, CDC Serial and - Mass Storage functions available in the Multifunction Composite - Gadget. This is the configuration dedicated for Windows since RNDIS - is Microsoft's protocol. - - If unsure, say "y". - -config USB_G_MULTI_CDC - bool "CDC Ethernet + CDC Serial + Storage configuration" - depends on USB_G_MULTI - default n - select USB_F_ECM - help - This option enables a configuration with CDC Ethernet (ECM), CDC - Serial and Mass Storage functions available in the Multifunction - Composite Gadget. - - If unsure, say "y". - -endif # TTY - -config USB_G_HID - tristate "HID Gadget" - select USB_LIBCOMPOSITE - select USB_F_HID - help - The HID gadget driver provides generic emulation of USB - Human Interface Devices (HID). - - For more information, see Documentation/usb/gadget_hid.txt which - includes sample code for accessing the device files. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_hid". - -# Standalone / single function gadgets -config USB_G_DBGP - tristate "EHCI Debug Device Gadget" - depends on TTY - select USB_LIBCOMPOSITE - help - This gadget emulates an EHCI Debug device. This is useful when you want - to interact with an EHCI Debug Port. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_dbgp". - -if USB_G_DBGP -choice - prompt "EHCI Debug Device mode" - default USB_G_DBGP_SERIAL - -config USB_G_DBGP_PRINTK - depends on USB_G_DBGP - bool "printk" - help - Directly printk() received data. No interaction. - -config USB_G_DBGP_SERIAL - depends on USB_G_DBGP - select USB_U_SERIAL - bool "serial" - help - Userland can interact using /dev/ttyGSxxx. -endchoice -endif - -# put drivers that need isochronous transfer support (for audio -# or video class gadget drivers), or specific hardware, here. -config USB_G_WEBCAM - tristate "USB Webcam Gadget" - depends on VIDEO_DEV - select USB_LIBCOMPOSITE - select VIDEOBUF2_VMALLOC - select USB_F_UVC - help - The Webcam Gadget acts as a composite USB Audio and Video Class - device. It provides a userspace API to process UVC control requests - and stream video data to the host. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "g_webcam". diff --git a/src/linux/drivers/usb/gadget/udc/Kconfig b/src/linux/drivers/usb/gadget/udc/Kconfig deleted file mode 100644 index 658b8da..0000000 --- a/src/linux/drivers/usb/gadget/udc/Kconfig +++ /dev/null @@ -1,421 +0,0 @@ -# -# USB Gadget support on a system involves -# (a) a peripheral controller, and -# (b) the gadget driver using it. -# -# NOTE: Gadget support ** DOES NOT ** depend on host-side CONFIG_USB !! -# -# - Host systems (like PCs) need CONFIG_USB (with "A" jacks). -# - Peripherals (like PDAs) need CONFIG_USB_GADGET (with "B" jacks). -# - Some systems have both kinds of controllers. -# -# With help from a special transceiver and a "Mini-AB" jack, systems with -# both kinds of controller can also support "USB On-the-Go" (CONFIG_USB_OTG). -# - -# -# USB Peripheral Controller Support -# -# The order here is alphabetical, except that integrated controllers go -# before discrete ones so they will be the initial/default value: -# - integrated/SOC controllers first -# - licensed IP used in both SOC and discrete versions -# - discrete ones (including all PCI-only controllers) -# - debug/dummy gadget+hcd is last. -# -menu "USB Peripheral Controller" - -# -# Integrated controllers -# - -config USB_AT91 - tristate "Atmel AT91 USB Device Port" - depends on ARCH_AT91 - depends on OF || COMPILE_TEST - help - Many Atmel AT91 processors (such as the AT91RM2000) have a - full speed USB Device Port with support for five configurable - endpoints (plus endpoint zero). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "at91_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_LPC32XX - tristate "LPC32XX USB Peripheral Controller" - depends on ARCH_LPC32XX && I2C - select USB_ISP1301 - help - This option selects the USB device controller in the LPC32xx SoC. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "lpc32xx_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_ATMEL_USBA - tristate "Atmel USBA" - depends on ((AVR32 && !OF) || ARCH_AT91) - help - USBA is the integrated high-speed USB Device controller on - the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel. - -config USB_BCM63XX_UDC - tristate "Broadcom BCM63xx Peripheral Controller" - depends on BCM63XX - help - Many Broadcom BCM63xx chipsets (such as the BCM6328) have a - high speed USB Device Port with support for four fixed endpoints - (plus endpoint zero). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "bcm63xx_udc". - -config USB_FSL_USB2 - tristate "Freescale Highspeed USB DR Peripheral Controller" - depends on FSL_SOC || ARCH_MXC - help - Some of Freescale PowerPC and i.MX processors have a High Speed - Dual-Role(DR) USB controller, which supports device mode. - - The number of programmable endpoints is different through - SOC revisions. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "fsl_usb2_udc" and force - all gadget drivers to also be dynamically linked. - -config USB_FUSB300 - tristate "Faraday FUSB300 USB Peripheral Controller" - depends on !PHYS_ADDR_T_64BIT && HAS_DMA - help - Faraday usb device controller FUSB300 driver - -config USB_FOTG210_UDC - depends on HAS_DMA - tristate "Faraday FOTG210 USB Peripheral Controller" - help - Faraday USB2.0 OTG controller which can be configured as - high speed or full speed USB device. This driver supppors - Bulk Transfer so far. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "fotg210_udc". - -config USB_GR_UDC - tristate "Aeroflex Gaisler GRUSBDC USB Peripheral Controller Driver" - depends on HAS_DMA - help - Select this to support Aeroflex Gaisler GRUSBDC cores from the GRLIB - VHDL IP core library. - -config USB_OMAP - tristate "OMAP USB Device Controller" - depends on ARCH_OMAP1 - depends on ISP1301_OMAP || !(MACH_OMAP_H2 || MACH_OMAP_H3) - help - Many Texas Instruments OMAP processors have flexible full - speed USB device controllers, with support for up to 30 - endpoints (plus endpoint zero). This driver supports the - controller in the OMAP 1611, and should work with controllers - in other OMAP processors too, given minor tweaks. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "omap_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_PXA25X - tristate "PXA 25x or IXP 4xx" - depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX - depends on HAS_IOMEM - help - Intel's PXA 25x series XScale ARM-5TE processors include - an integrated full speed USB 1.1 device controller. The - controller in the IXP 4xx series is register-compatible. - - It has fifteen fixed-function endpoints, as well as endpoint - zero (for control transfers). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "pxa25x_udc" and force all - gadget drivers to also be dynamically linked. - -# if there's only one gadget driver, using only two bulk endpoints, -# don't waste memory for the other endpoints -config USB_PXA25X_SMALL - depends on USB_PXA25X - bool - default n if USB_ETH_RNDIS - default y if USB_ZERO - default y if USB_ETH - default y if USB_G_SERIAL - -config USB_R8A66597 - tristate "Renesas R8A66597 USB Peripheral Controller" - depends on HAS_DMA - help - R8A66597 is a discrete USB host and peripheral controller chip that - supports both full and high speed USB 2.0 data transfers. - It has nine configurable endpoints, and endpoint zero. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "r8a66597_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_RENESAS_USBHS_UDC - tristate 'Renesas USBHS controller' - depends on USB_RENESAS_USBHS && HAS_DMA - help - Renesas USBHS is a discrete USB host and peripheral controller chip - that supports both full and high speed USB 2.0 data transfers. - It has nine or more configurable endpoints, and endpoint zero. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "renesas_usbhs" and force all - gadget drivers to also be dynamically linked. - -config USB_RENESAS_USB3 - tristate 'Renesas USB3.0 Peripheral controller' - depends on ARCH_RENESAS || COMPILE_TEST - help - Renesas USB3.0 Peripheral controller is a USB peripheral controller - that supports super, high, and full speed USB 3.0 data transfers. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "renesas_usb3" and force all - gadget drivers to also be dynamically linked. - -config USB_PXA27X - tristate "PXA 27x" - depends on HAS_IOMEM - help - Intel's PXA 27x series XScale ARM v5TE processors include - an integrated full speed USB 1.1 device controller. - - It has up to 23 endpoints, as well as endpoint zero (for - control transfers). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "pxa27x_udc" and force all - gadget drivers to also be dynamically linked. - -config USB_S3C2410 - tristate "S3C2410 USB Device Controller" - depends on ARCH_S3C24XX - help - Samsung's S3C2410 is an ARM-4 processor with an integrated - full speed USB 1.1 device controller. It has 4 configurable - endpoints, as well as endpoint zero (for control transfers). - - This driver has been tested on the S3C2410, S3C2412, and - S3C2440 processors. - -config USB_S3C2410_DEBUG - bool "S3C2410 udc debug messages" - depends on USB_S3C2410 - -config USB_S3C_HSUDC - tristate "S3C2416, S3C2443 and S3C2450 USB Device Controller" - depends on ARCH_S3C24XX - help - Samsung's S3C2416, S3C2443 and S3C2450 is an ARM9 based SoC - integrated with dual speed USB 2.0 device controller. It has - 8 endpoints, as well as endpoint zero. - - This driver has been tested on S3C2416 and S3C2450 processors. - -config USB_MV_UDC - tristate "Marvell USB2.0 Device Controller" - depends on HAS_DMA - help - Marvell Socs (including PXA and MMP series) include a high speed - USB2.0 OTG controller, which can be configured as high speed or - full speed USB peripheral. - -config USB_MV_U3D - depends on HAS_DMA - tristate "MARVELL PXA2128 USB 3.0 controller" - help - MARVELL PXA2128 Processor series include a super speed USB3.0 device - controller, which support super speed USB peripheral. - -# -# Controllers available in both integrated and discrete versions -# - -config USB_M66592 - tristate "Renesas M66592 USB Peripheral Controller" - depends on HAS_IOMEM - help - M66592 is a discrete USB peripheral controller chip that - supports both full and high speed USB 2.0 data transfers. - It has seven configurable endpoints, and endpoint zero. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "m66592_udc" and force all - gadget drivers to also be dynamically linked. - -source "drivers/usb/gadget/udc/bdc/Kconfig" - -# -# Controllers available only in discrete form (and all PCI controllers) -# - -config USB_AMD5536UDC - tristate "AMD5536 UDC" - depends on PCI - help - The AMD5536 UDC is part of the AMD Geode CS5536, an x86 southbridge. - It is a USB Highspeed DMA capable USB device controller. Beside ep0 - it provides 4 IN and 4 OUT endpoints (bulk or interrupt type). - The UDC port supports OTG operation, and may be used as a host port - if it's not being used to implement peripheral or OTG roles. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "amd5536udc" and force all - gadget drivers to also be dynamically linked. - -config USB_FSL_QE - tristate "Freescale QE/CPM USB Device Controller" - depends on FSL_SOC && (QUICC_ENGINE || CPM) - help - Some of Freescale PowerPC processors have a Full Speed - QE/CPM2 USB controller, which support device mode with 4 - programmable endpoints. This driver supports the - controller in the MPC8360 and MPC8272, and should work with - controllers having QE or CPM2, given minor tweaks. - - Set CONFIG_USB_GADGET to "m" to build this driver as a - dynamically linked module called "fsl_qe_udc". - -config USB_NET2272 - depends on HAS_IOMEM - tristate "PLX NET2272" - help - PLX NET2272 is a USB peripheral controller which supports - both full and high speed USB 2.0 data transfers. - - It has three configurable endpoints, as well as endpoint zero - (for control transfer). - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "net2272" and force all - gadget drivers to also be dynamically linked. - -config USB_NET2272_DMA - bool "Support external DMA controller" - depends on USB_NET2272 && HAS_DMA - help - The NET2272 part can optionally support an external DMA - controller, but your board has to have support in the - driver itself. - - If unsure, say "N" here. The driver works fine in PIO mode. - -config USB_NET2280 - tristate "NetChip NET228x / PLX USB3x8x" - depends on PCI - help - NetChip 2280 / 2282 is a PCI based USB peripheral controller which - supports both full and high speed USB 2.0 data transfers. - - It has six configurable endpoints, as well as endpoint zero - (for control transfers) and several endpoints with dedicated - functions. - - PLX 2380 is a PCIe version of the PLX 2380. - - PLX 3380 / 3382 is a PCIe based USB peripheral controller which - supports full, high speed USB 2.0 and super speed USB 3.0 - data transfers. - - It has eight configurable endpoints, as well as endpoint zero - (for control transfers) and several endpoints with dedicated - functions. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "net2280" and force all - gadget drivers to also be dynamically linked. - -config USB_GOKU - tristate "Toshiba TC86C001 'Goku-S'" - depends on PCI - help - The Toshiba TC86C001 is a PCI device which includes controllers - for full speed USB devices, IDE, I2C, SIO, plus a USB host (OHCI). - - The device controller has three configurable (bulk or interrupt) - endpoints, plus endpoint zero (for control transfers). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "goku_udc" and to force all - gadget drivers to also be dynamically linked. - -config USB_EG20T - tristate "Intel QUARK X1000/EG20T PCH/LAPIS Semiconductor IOH(ML7213/ML7831) UDC" - depends on PCI - help - This is a USB device driver for EG20T PCH. - EG20T PCH is the platform controller hub that is used in Intel's - general embedded platform. EG20T PCH has USB device interface. - Using this interface, it is able to access system devices connected - to USB device. - This driver enables USB device function. - USB device is a USB peripheral controller which - supports both full and high speed USB 2.0 data transfers. - This driver supports both control transfer and bulk transfer modes. - This driver dose not support interrupt transfer or isochronous - transfer modes. - - This driver also can be used for LAPIS Semiconductor's ML7213 which is - for IVI(In-Vehicle Infotainment) use. - ML7831 is for general purpose use. - ML7213/ML7831 is companion chip for Intel Atom E6xx series. - ML7213/ML7831 is completely compatible for Intel EG20T PCH. - - This driver can be used with Intel's Quark X1000 SOC platform - -config USB_GADGET_XILINX - tristate "Xilinx USB Driver" - depends on HAS_DMA - depends on OF || COMPILE_TEST - help - USB peripheral controller driver for Xilinx USB2 device. - Xilinx USB2 device is a soft IP which supports both full - and high speed USB 2.0 data transfers. It has seven configurable - endpoints(bulk or interrupt or isochronous), as well as - endpoint zero(for control transfers). - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "udc-xilinx" and force all - gadget drivers to also be dynamically linked. - -# -# LAST -- dummy/emulated controller -# - -config USB_DUMMY_HCD - tristate "Dummy HCD (DEVELOPMENT)" - depends on USB=y || (USB=m && USB_GADGET=m) - help - This host controller driver emulates USB, looping all data transfer - requests back to a USB "gadget driver" in the same host. The host - side is the master; the gadget side is the slave. Gadget drivers - can be high, full, or low speed; and they have access to endpoints - like those from NET2280, PXA2xx, or SA1100 hardware. - - This may help in some stages of creating a driver to embed in a - Linux device, since it lets you debug several parts of the gadget - driver without its hardware or drivers being involved. - - Since such a gadget side driver needs to interoperate with a host - side Linux-USB device driver, this may help to debug both sides - of a USB protocol stack. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "dummy_hcd" and force all - gadget drivers to also be dynamically linked. - -# NOTE: Please keep dummy_hcd LAST so that "real hardware" appears -# first and will be selected by default. - -endmenu diff --git a/src/linux/drivers/usb/gadget/udc/bdc/Kconfig b/src/linux/drivers/usb/gadget/udc/bdc/Kconfig deleted file mode 100644 index 0d7b8c9..0000000 --- a/src/linux/drivers/usb/gadget/udc/bdc/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -config USB_BDC_UDC - tristate "Broadcom USB3.0 device controller IP driver(BDC)" - depends on USB_GADGET && HAS_DMA - - help - BDC is Broadcom's USB3.0 device controller IP. If your SOC has a BDC IP - then select this driver. - - Say "y" here to link the driver statically, or "m" to build a dynamically - linked module called "bdc". - -if USB_BDC_UDC - -comment "Platform Support" -config USB_BDC_PCI - tristate "BDC support for PCIe based platforms" - depends on PCI - default USB_BDC_UDC - help - Enable support for platforms which have BDC connected through PCIe, such as Lego3 FPGA platform. -endif diff --git a/src/linux/drivers/usb/host/Kconfig b/src/linux/drivers/usb/host/Kconfig deleted file mode 100644 index 0b80cee..0000000 --- a/src/linux/drivers/usb/host/Kconfig +++ /dev/null @@ -1,814 +0,0 @@ -# -# USB Host Controller Drivers -# -comment "USB Host Controller Drivers" - -config USB_C67X00_HCD - tristate "Cypress C67x00 HCD support" - depends on HAS_IOMEM - help - The Cypress C67x00 (EZ-Host/EZ-OTG) chips are dual-role - host/peripheral/OTG USB controllers. - - Enable this option to support this chip in host controller mode. - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called c67x00. - -config USB_XHCI_HCD - tristate "xHCI HCD (USB 3.0) support" - depends on HAS_DMA && HAS_IOMEM - ---help--- - The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0 - "SuperSpeed" host controller hardware. - - To compile this driver as a module, choose M here: the - module will be called xhci-hcd. - -if USB_XHCI_HCD - -config USB_XHCI_PCI - tristate - depends on PCI - default y - -config USB_XHCI_PLATFORM - tristate "Generic xHCI driver for a platform device" - select USB_XHCI_RCAR if ARCH_RENESAS - ---help--- - Adds an xHCI host driver for a generic platform device, which - provides a memory space and an irq. - It is also a prerequisite for platform specific drivers that - implement some extra quirks. - - If unsure, say N. - -config USB_XHCI_MTK - tristate "xHCI support for Mediatek MT65xx" - select MFD_SYSCON - depends on ARCH_MEDIATEK || COMPILE_TEST - ---help--- - Say 'Y' to enable the support for the xHCI host controller - found in Mediatek MT65xx SoCs. - If unsure, say N. - -config USB_XHCI_MVEBU - tristate "xHCI support for Marvell Armada 375/38x" - select USB_XHCI_PLATFORM - depends on HAS_IOMEM - depends on ARCH_MVEBU || COMPILE_TEST - ---help--- - Say 'Y' to enable the support for the xHCI host controller - found in Marvell Armada 375/38x ARM SOCs. - -config USB_XHCI_RCAR - tristate "xHCI support for Renesas R-Car SoCs" - depends on USB_XHCI_PLATFORM - depends on ARCH_RENESAS || COMPILE_TEST - ---help--- - Say 'Y' to enable the support for the xHCI host controller - found in Renesas R-Car ARM SoCs. - -config USB_XHCI_TEGRA - tristate "xHCI support for NVIDIA Tegra SoCs" - depends on PHY_TEGRA_XUSB - depends on RESET_CONTROLLER - select FW_LOADER - ---help--- - Say 'Y' to enable the support for the xHCI host controller - found in NVIDIA Tegra124 and later SoCs. - -endif # USB_XHCI_HCD - -config USB_EHCI_HCD - tristate "EHCI HCD (USB 2.0) support" - depends on HAS_DMA && HAS_IOMEM - ---help--- - The Enhanced Host Controller Interface (EHCI) is standard for USB 2.0 - "high speed" (480 Mbit/sec, 60 Mbyte/sec) host controller hardware. - If your USB host controller supports USB 2.0, you will likely want to - configure this Host Controller Driver. - - EHCI controllers are packaged with "companion" host controllers (OHCI - or UHCI) to handle USB 1.1 devices connected to root hub ports. Ports - will connect to EHCI if the device is high speed, otherwise they - connect to a companion controller. If you configure EHCI, you should - probably configure the OHCI (for NEC and some other vendors) USB Host - Controller Driver or UHCI (for Via motherboards) Host Controller - Driver too. - - You may want to read . - - To compile this driver as a module, choose M here: the - module will be called ehci-hcd. - -config USB_EHCI_ROOT_HUB_TT - bool "Root Hub Transaction Translators" - depends on USB_EHCI_HCD - ---help--- - Some EHCI chips have vendor-specific extensions to integrate - transaction translators, so that no OHCI or UHCI companion - controller is needed. It's safe to say "y" even if your - controller doesn't support this feature. - - This supports the EHCI implementation that's originally - from ARC, and has since changed hands a few times. - -config USB_EHCI_TT_NEWSCHED - bool "Improved Transaction Translator scheduling" - depends on USB_EHCI_HCD - default y - ---help--- - This changes the periodic scheduling code to fill more of the low - and full speed bandwidth available from the Transaction Translator - (TT) in USB 2.0 hubs. Without this, only one transfer will be - issued in each microframe, significantly reducing the number of - periodic low/fullspeed transfers possible. - - If you have multiple periodic low/fullspeed devices connected to a - highspeed USB hub which is connected to a highspeed USB Host - Controller, and some of those devices will not work correctly - (possibly due to "ENOSPC" or "-28" errors), say Y. Conversely, if - you have only one such device and it doesn't work, you could try - saying N. - - If unsure, say Y. - -if USB_EHCI_HCD - -config USB_EHCI_PCI - tristate - depends on PCI - default y - -config USB_EHCI_HCD_PMC_MSP - tristate "EHCI support for on-chip PMC MSP71xx USB controller" - depends on MSP_HAS_USB - default n - select USB_EHCI_BIG_ENDIAN_DESC - select USB_EHCI_BIG_ENDIAN_MMIO - ---help--- - Enables support for the onchip USB controller on the PMC_MSP7100 Family SoC's. - If unsure, say N. - -config XPS_USB_HCD_XILINX - bool "Use Xilinx usb host EHCI controller core" - depends on (PPC32 || MICROBLAZE) - select USB_EHCI_BIG_ENDIAN_DESC - select USB_EHCI_BIG_ENDIAN_MMIO - ---help--- - Xilinx xps USB host controller core is EHCI compliant and has - transaction translator built-in. It can be configured to either - support both high speed and full speed devices, or high speed - devices only. - -config USB_EHCI_FSL - tristate "Support for Freescale PPC on-chip EHCI USB controller" - depends on FSL_SOC - select USB_EHCI_ROOT_HUB_TT - ---help--- - Variation of ARC USB block used in some Freescale chips. - -config USB_EHCI_MXC - tristate "Support for Freescale i.MX on-chip EHCI USB controller" - depends on ARCH_MXC - select USB_EHCI_ROOT_HUB_TT - ---help--- - Variation of ARC USB block used in some Freescale chips. - -config USB_EHCI_HCD_OMAP - tristate "EHCI support for OMAP3 and later chips" - depends on ARCH_OMAP - depends on NOP_USB_XCEIV - default y - ---help--- - Enables support for the on-chip EHCI controller on - OMAP3 and later chips. - -config USB_EHCI_HCD_ORION - tristate "Support for Marvell EBU on-chip EHCI USB controller" - depends on USB_EHCI_HCD && PLAT_ORION - default y - ---help--- - Enables support for the on-chip EHCI controller on Marvell's - embedded ARM SoCs, including Orion, Kirkwood, Dove, Armada XP, - Armada 370. This is different from the EHCI implementation - on Marvell's mobile PXA and MMP SoC, see "EHCI support for - Marvell PXA/MMP USB controller" for those. - -config USB_EHCI_HCD_SPEAR - tristate "Support for ST SPEAr on-chip EHCI USB controller" - depends on USB_EHCI_HCD && PLAT_SPEAR - default y - ---help--- - Enables support for the on-chip EHCI controller on - ST SPEAr chips. - -config USB_EHCI_HCD_STI - tristate "Support for ST STiHxxx on-chip EHCI USB controller" - depends on ARCH_STI && OF - select GENERIC_PHY - select USB_EHCI_HCD_PLATFORM - help - Enable support for the on-chip EHCI controller found on - STMicroelectronics consumer electronics SoC's. - -config USB_EHCI_HCD_AT91 - tristate "Support for Atmel on-chip EHCI USB controller" - depends on USB_EHCI_HCD && ARCH_AT91 - default y - ---help--- - Enables support for the on-chip EHCI controller on - Atmel chips. - -config USB_EHCI_MSM - tristate "Support for Qualcomm QSD/MSM on-chip EHCI USB controller" - depends on ARCH_QCOM - select USB_EHCI_ROOT_HUB_TT - ---help--- - Enables support for the USB Host controller present on the - Qualcomm chipsets. Root Hub has inbuilt TT. - This driver depends on OTG driver for PHY initialization, - clock management, powering up VBUS, and power management. - This driver is not supported on boards like trout which - has an external PHY. - -config USB_EHCI_TEGRA - tristate "NVIDIA Tegra HCD support" - depends on ARCH_TEGRA - select USB_EHCI_ROOT_HUB_TT - select USB_PHY - select USB_ULPI - select USB_ULPI_VIEWPORT - help - This driver enables support for the internal USB Host Controllers - found in NVIDIA Tegra SoCs. The controllers are EHCI compliant. - -config USB_EHCI_HCD_PPC_OF - bool "EHCI support for PPC USB controller on OF platform bus" - depends on PPC - default y - ---help--- - Enables support for the USB controller present on the PowerPC - OpenFirmware platform bus. - -config USB_EHCI_SH - bool "EHCI support for SuperH USB controller" - depends on SUPERH - ---help--- - Enables support for the on-chip EHCI controller on the SuperH. - If you use the PCI EHCI controller, this option is not necessary. - -config USB_EHCI_EXYNOS - tristate "EHCI support for Samsung S5P/EXYNOS SoC Series" - depends on ARCH_S5PV210 || ARCH_EXYNOS - help - Enable support for the Samsung Exynos SOC's on-chip EHCI controller. - -config USB_EHCI_MV - bool "EHCI support for Marvell PXA/MMP USB controller" - depends on (ARCH_PXA || ARCH_MMP) - select USB_EHCI_ROOT_HUB_TT - ---help--- - Enables support for Marvell (including PXA and MMP series) on-chip - USB SPH and OTG controller. SPH is a single port host, and it can - only be EHCI host. OTG is controller that can switch to host mode. - Note that this driver will not work on Marvell's other EHCI - controller used by the EBU-type SoCs including Orion, Kirkwood, - Dova, Armada 370 and Armada XP. See "Support for Marvell EBU - on-chip EHCI USB controller" for those. - -config USB_W90X900_EHCI - tristate "W90X900(W90P910) EHCI support" - depends on ARCH_W90X900 - ---help--- - Enables support for the W90X900 USB controller - -config USB_CNS3XXX_EHCI - bool "Cavium CNS3XXX EHCI Module (DEPRECATED)" - depends on ARCH_CNS3XXX - select USB_EHCI_HCD_PLATFORM - ---help--- - This option is deprecated now and the driver was removed, use - USB_EHCI_HCD_PLATFORM instead. - - Enable support for the CNS3XXX SOC's on-chip EHCI controller. - It is needed for high-speed (480Mbit/sec) USB 2.0 device - support. - -config USB_EHCI_ATH79 - bool "EHCI support for AR7XXX/AR9XXX SoCs (DEPRECATED)" - depends on (SOC_AR71XX || SOC_AR724X || SOC_AR913X || SOC_AR933X) - select USB_EHCI_ROOT_HUB_TT - select USB_EHCI_HCD_PLATFORM - default y - ---help--- - This option is deprecated now and the driver was removed, use - USB_EHCI_HCD_PLATFORM instead. - - Enables support for the built-in EHCI controller present - on the Atheros AR7XXX/AR9XXX SoCs. - -config USB_EHCI_HCD_PLATFORM - tristate "Generic EHCI driver for a platform device" - default n - ---help--- - Adds an EHCI host driver for a generic platform device, which - provides a memory space and an irq. - - If unsure, say N. - -config USB_OCTEON_EHCI - bool "Octeon on-chip EHCI support (DEPRECATED)" - depends on CAVIUM_OCTEON_SOC - default n - select USB_EHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN - select USB_EHCI_HCD_PLATFORM - help - This option is deprecated now and the driver was removed, use - USB_EHCI_HCD_PLATFORM instead. - - Enable support for the Octeon II SOC's on-chip EHCI - controller. It is needed for high-speed (480Mbit/sec) - USB 2.0 device support. All CN6XXX based chips with USB are - supported. - -endif # USB_EHCI_HCD - -config USB_OXU210HP_HCD - tristate "OXU210HP HCD support" - depends on HAS_IOMEM - ---help--- - The OXU210HP is an USB host/OTG/device controller. Enable this - option if your board has this chip. If unsure, say N. - - This driver does not support isochronous transfers and doesn't - implement OTG nor USB device controllers. - - To compile this driver as a module, choose M here: the - module will be called oxu210hp-hcd. - -config USB_ISP116X_HCD - tristate "ISP116X HCD support" - depends on HAS_IOMEM - ---help--- - The ISP1160 and ISP1161 chips are USB host controllers. Enable this - option if your board has this chip. If unsure, say N. - - This driver does not support isochronous transfers. - - To compile this driver as a module, choose M here: the - module will be called isp116x-hcd. - -config USB_ISP1362_HCD - tristate "ISP1362 HCD support" - depends on HAS_IOMEM - ---help--- - Supports the Philips ISP1362 chip as a host controller - - This driver does not support isochronous transfers. - - To compile this driver as a module, choose M here: the - module will be called isp1362-hcd. - -config USB_FOTG210_HCD - tristate "FOTG210 HCD support" - depends on USB && HAS_DMA && HAS_IOMEM - ---help--- - Faraday FOTG210 is an OTG controller which can be configured as - an USB2.0 host. It is designed to meet USB2.0 EHCI specification - with minor modification. - - To compile this driver as a module, choose M here: the - module will be called fotg210-hcd. - -config USB_MAX3421_HCD - tristate "MAX3421 HCD (USB-over-SPI) support" - depends on USB && SPI - ---help--- - The Maxim MAX3421E chip supports standard USB 2.0-compliant - full-speed devices either in host or peripheral mode. This - driver supports the host-mode of the MAX3421E only. - - To compile this driver as a module, choose M here: the module will - be called max3421-hcd. - -config USB_OHCI_HCD - tristate "OHCI HCD (USB 1.1) support" - depends on HAS_DMA && HAS_IOMEM - ---help--- - The Open Host Controller Interface (OHCI) is a standard for accessing - USB 1.1 host controller hardware. It does more in hardware than Intel's - UHCI specification. If your USB host controller follows the OHCI spec, - say Y. On most non-x86 systems, and on x86 hardware that's not using a - USB controller from Intel or VIA, this is appropriate. If your host - controller doesn't use PCI, this is probably appropriate. For a PCI - based system where you're not sure, the "lspci -v" entry will list the - right "prog-if" for your USB controller(s): EHCI, OHCI, or UHCI. - - To compile this driver as a module, choose M here: the - module will be called ohci-hcd. - -if USB_OHCI_HCD - -config USB_OHCI_HCD_OMAP1 - tristate "OHCI support for OMAP1/2 chips" - depends on ARCH_OMAP1 - depends on ISP1301_OMAP || !(MACH_OMAP_H2 || MACH_OMAP_H3) - default y - ---help--- - Enables support for the OHCI controller on OMAP1/2 chips. - -config USB_OHCI_HCD_SPEAR - tristate "Support for ST SPEAr on-chip OHCI USB controller" - depends on USB_OHCI_HCD && PLAT_SPEAR - default y - ---help--- - Enables support for the on-chip OHCI controller on - ST SPEAr chips. - -config USB_OHCI_HCD_STI - tristate "Support for ST STiHxxx on-chip OHCI USB controller" - depends on ARCH_STI && OF - select GENERIC_PHY - select USB_OHCI_HCD_PLATFORM - help - Enable support for the on-chip OHCI controller found on - STMicroelectronics consumer electronics SoC's. - -config USB_OHCI_HCD_S3C2410 - tristate "OHCI support for Samsung S3C24xx/S3C64xx SoC series" - depends on USB_OHCI_HCD && (ARCH_S3C24XX || ARCH_S3C64XX) - default y - ---help--- - Enables support for the on-chip OHCI controller on - S3C24xx/S3C64xx chips. - -config USB_OHCI_HCD_LPC32XX - tristate "Support for LPC on-chip OHCI USB controller" - depends on USB_OHCI_HCD && ARCH_LPC32XX - depends on USB_ISP1301 - default y - ---help--- - Enables support for the on-chip OHCI controller on - NXP chips. - -config USB_OHCI_HCD_PXA27X - tristate "Support for PXA27X/PXA3XX on-chip OHCI USB controller" - depends on USB_OHCI_HCD && (PXA27x || PXA3xx) - default y - ---help--- - Enables support for the on-chip OHCI controller on - PXA27x/PXA3xx chips. - -config USB_OHCI_HCD_AT91 - tristate "Support for Atmel on-chip OHCI USB controller" - depends on USB_OHCI_HCD && ARCH_AT91 && OF - default y - ---help--- - Enables support for the on-chip OHCI controller on - Atmel chips. - -config USB_OHCI_HCD_OMAP3 - tristate "OHCI support for OMAP3 and later chips" - depends on (ARCH_OMAP3 || ARCH_OMAP4 || SOC_OMAP5) - default y - ---help--- - Enables support for the on-chip OHCI controller on - OMAP3 and later chips. - -config USB_OHCI_HCD_DAVINCI - bool "OHCI support for TI DaVinci DA8xx" - depends on ARCH_DAVINCI_DA8XX - depends on USB_OHCI_HCD=y - default y - help - Enables support for the DaVinci DA8xx integrated OHCI - controller. This driver cannot currently be a loadable - module because it lacks a proper PHY abstraction. - -config USB_OHCI_ATH79 - bool "USB OHCI support for the Atheros AR71XX/AR7240 SoCs (DEPRECATED)" - depends on (SOC_AR71XX || SOC_AR724X) - select USB_OHCI_HCD_PLATFORM - default y - help - This option is deprecated now and the driver was removed, use - USB_OHCI_HCD_PLATFORM instead. - - Enables support for the built-in OHCI controller present on the - Atheros AR71XX/AR7240 SoCs. - -config USB_OHCI_HCD_PPC_OF_BE - bool "OHCI support for OF platform bus (big endian)" - depends on PPC - select USB_OHCI_BIG_ENDIAN_DESC - select USB_OHCI_BIG_ENDIAN_MMIO - ---help--- - Enables support for big-endian USB controllers present on the - OpenFirmware platform bus. - -config USB_OHCI_HCD_PPC_OF_LE - bool "OHCI support for OF platform bus (little endian)" - depends on PPC - select USB_OHCI_LITTLE_ENDIAN - ---help--- - Enables support for little-endian USB controllers present on the - OpenFirmware platform bus. - -config USB_OHCI_HCD_PPC_OF - bool - depends on PPC - default USB_OHCI_HCD_PPC_OF_BE || USB_OHCI_HCD_PPC_OF_LE - -config USB_OHCI_HCD_PCI - tristate "OHCI support for PCI-bus USB controllers" - depends on PCI - default y - select USB_OHCI_LITTLE_ENDIAN - ---help--- - Enables support for PCI-bus plug-in USB controller cards. - If unsure, say Y. - -config USB_OHCI_HCD_SSB - bool "OHCI support for Broadcom SSB OHCI core (DEPRECATED)" - depends on (SSB = y || SSB = USB_OHCI_HCD) - select USB_HCD_SSB - select USB_OHCI_HCD_PLATFORM - default n - ---help--- - This option is deprecated now and the driver was removed, use - USB_HCD_SSB and USB_OHCI_HCD_PLATFORM instead. - - Support for the Sonics Silicon Backplane (SSB) attached - Broadcom USB OHCI core. - - This device is present in some embedded devices with - Broadcom based SSB bus. - - If unsure, say N. - -config USB_OHCI_SH - bool "OHCI support for SuperH USB controller (DEPRECATED)" - depends on SUPERH - select USB_OHCI_HCD_PLATFORM - ---help--- - This option is deprecated now and the driver was removed, use - USB_OHCI_HCD_PLATFORM instead. - - Enables support for the on-chip OHCI controller on the SuperH. - If you use the PCI OHCI controller, this option is not necessary. - -config USB_OHCI_EXYNOS - tristate "OHCI support for Samsung S5P/EXYNOS SoC Series" - depends on ARCH_S5PV210 || ARCH_EXYNOS - help - Enable support for the Samsung Exynos SOC's on-chip OHCI controller. - -config USB_CNS3XXX_OHCI - bool "Cavium CNS3XXX OHCI Module (DEPRECATED)" - depends on ARCH_CNS3XXX - select USB_OHCI_HCD_PLATFORM - ---help--- - This option is deprecated now and the driver was removed, use - USB_OHCI_HCD_PLATFORM instead. - - Enable support for the CNS3XXX SOC's on-chip OHCI controller. - It is needed for low-speed USB 1.0 device support. - -config USB_OHCI_HCD_PLATFORM - tristate "Generic OHCI driver for a platform device" - default n - ---help--- - Adds an OHCI host driver for a generic platform device, which - provides a memory space and an irq. - - If unsure, say N. - -config USB_OCTEON_OHCI - bool "Octeon on-chip OHCI support (DEPRECATED)" - depends on CAVIUM_OCTEON_SOC - default USB_OCTEON_EHCI - select USB_OHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN - select USB_OHCI_LITTLE_ENDIAN - select USB_OHCI_HCD_PLATFORM - help - This option is deprecated now and the driver was removed, use - USB_OHCI_HCD_PLATFORM instead. - - Enable support for the Octeon II SOC's on-chip OHCI - controller. It is needed for low-speed USB 1.0 device - support. All CN6XXX based chips with USB are supported. - -endif # USB_OHCI_HCD - -config USB_UHCI_HCD - tristate "UHCI HCD (most Intel and VIA) support" - depends on PCI || USB_UHCI_SUPPORT_NON_PCI_HC - ---help--- - The Universal Host Controller Interface is a standard by Intel for - accessing the USB hardware in the PC (which is also called the USB - host controller). If your USB host controller conforms to this - standard, you may want to say Y, but see below. All recent boards - with Intel PCI chipsets (like intel 430TX, 440FX, 440LX, 440BX, - i810, i820) conform to this standard. Also all VIA PCI chipsets - (like VIA VP2, VP3, MVP3, Apollo Pro, Apollo Pro II or Apollo Pro - 133) and LEON/GRLIB SoCs with the GRUSBHC controller. - If unsure, say Y. - - To compile this driver as a module, choose M here: the - module will be called uhci-hcd. - -config USB_UHCI_SUPPORT_NON_PCI_HC - bool - default y if (SPARC_LEON || USB_UHCI_PLATFORM) - -config USB_UHCI_PLATFORM - bool - default y if ARCH_VT8500 - -config USB_UHCI_BIG_ENDIAN_MMIO - bool - default y if SPARC_LEON - -config USB_UHCI_BIG_ENDIAN_DESC - bool - default y if SPARC_LEON - -config USB_FHCI_HCD - tristate "Freescale QE USB Host Controller support" - depends on OF_GPIO && QE_GPIO && QUICC_ENGINE - select FSL_GTM - select QE_USB - help - This driver enables support for Freescale QE USB Host Controller - (as found on MPC8360 and MPC8323 processors), the driver supports - Full and Low Speed USB. - -config FHCI_DEBUG - bool "Freescale QE USB Host Controller debug support" - depends on USB_FHCI_HCD && DEBUG_FS - help - Say "y" to see some FHCI debug information and statistics - through debugfs. - -config USB_U132_HCD - tristate "Elan U132 Adapter Host Controller" - depends on USB_FTDI_ELAN - help - The U132 adapter is a USB to CardBus adapter specifically designed - for PC cards that contain an OHCI host controller. Typical PC cards - are the Orange Mobile 3G Option GlobeTrotter Fusion card. The U132 - adapter will *NOT* work with PC cards that do not contain an OHCI - controller. - - For those PC cards that contain multiple OHCI controllers only the - first one is used. - - The driver consists of two modules, the "ftdi-elan" module is a - USB client driver that interfaces to the FTDI chip within ELAN's - USB-to-PCMCIA adapter, and this "u132-hcd" module is a USB host - controller driver that talks to the OHCI controller within the - CardBus cards that are inserted in the U132 adapter. - - This driver has been tested with a CardBus OHCI USB adapter, and - worked with a USB PEN Drive inserted into the first USB port of - the PCCARD. A rather pointless thing to do, but useful for testing. - - It is safe to say M here. - - See also - -config USB_SL811_HCD - tristate "SL811HS HCD support" - depends on HAS_IOMEM - help - The SL811HS is a single-port USB controller that supports either - host side or peripheral side roles. Enable this option if your - board has this chip, and you want to use it as a host controller. - If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called sl811-hcd. - -config USB_SL811_HCD_ISO - bool "partial ISO support" - depends on USB_SL811_HCD - help - The driver doesn't support iso_frame_desc (yet), but for some simple - devices that just queue one ISO frame per URB, then ISO transfers - "should" work using the normal urb status fields. - - If unsure, say N. - -config USB_SL811_CS - tristate "CF/PCMCIA support for SL811HS HCD" - depends on USB_SL811_HCD && PCMCIA - help - Wraps a PCMCIA driver around the SL811HS HCD, supporting the RATOC - REX-CFU1U CF card (often used with PDAs). If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called "sl811_cs". - -config USB_R8A66597_HCD - tristate "R8A66597 HCD support" - depends on HAS_IOMEM - help - The R8A66597 is a USB 2.0 host and peripheral controller. - - Enable this option if your board has this chip, and you want - to use it as a host controller. If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called r8a66597-hcd. - -config USB_RENESAS_USBHS_HCD - tristate "Renesas USBHS HCD support" - depends on USB_RENESAS_USBHS - help - The Renesas USBHS is a USB 2.0 host and peripheral controller. - - Enable this option if your board has this chip, and you want - to use it as a host controller. If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called renesas-usbhs. - -config USB_WHCI_HCD - tristate "Wireless USB Host Controller Interface (WHCI) driver" - depends on PCI && USB && UWB - select USB_WUSB - select UWB_WHCI - help - A driver for PCI-based Wireless USB Host Controllers that are - compliant with the WHCI specification. - - To compile this driver a module, choose M here: the module - will be called "whci-hcd". - -config USB_HWA_HCD - tristate "Host Wire Adapter (HWA) driver" - depends on USB && UWB - select USB_WUSB - select UWB_HWA - help - This driver enables you to connect Wireless USB devices to - your system using a Host Wire Adaptor USB dongle. This is an - UWB Radio Controller and WUSB Host Controller connected to - your machine via USB (specified in WUSB1.0). - - To compile this driver a module, choose M here: the module - will be called "hwa-hc". - -config USB_IMX21_HCD - tristate "i.MX21 HCD support" - depends on ARM && ARCH_MXC - help - This driver enables support for the on-chip USB host in the - i.MX21 processor. - - To compile this driver as a module, choose M here: the - module will be called "imx21-hcd". - -config USB_HCD_BCMA - tristate "BCMA usb host driver" - depends on BCMA - select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD - select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD - help - Enable support for the EHCI and OCHI host controller on an bcma bus. - It converts the bcma driver into two platform device drivers - for ehci and ohci. - - If unsure, say N. - -config USB_HCD_SSB - tristate "SSB usb host driver" - depends on SSB - select USB_OHCI_HCD_PLATFORM if USB_OHCI_HCD - select USB_EHCI_HCD_PLATFORM if USB_EHCI_HCD - help - Enable support for the EHCI and OCHI host controller on an bcma bus. - It converts the bcma driver into two platform device drivers - for ehci and ohci. - - If unsure, say N. - -config USB_HCD_TEST_MODE - bool "HCD test mode support" - ---help--- - Say 'Y' to enable additional software test modes that may be - supported by the host controller drivers. - - One such test mode is the Embedded High-speed Host Electrical Test - (EHSET) for EHCI host controller hardware, specifically the "Single - Step Set Feature" test. Typically this will be enabled for On-the-Go - or embedded hosts that need to undergo USB-IF compliance testing with - the aid of special testing hardware. In the future, this may expand - to include other tests that require support from a HCD driver. - - This option is of interest only to developers who need to validate - their USB hardware designs. It is not needed for normal use. If - unsure, say N. diff --git a/src/linux/drivers/usb/image/Kconfig b/src/linux/drivers/usb/image/Kconfig deleted file mode 100644 index 320d368..0000000 --- a/src/linux/drivers/usb/image/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -# -# USB Imaging devices configuration -# -comment "USB Imaging devices" - -config USB_MDC800 - tristate "USB Mustek MDC800 Digital Camera support" - ---help--- - Say Y here if you want to connect this type of still camera to - your computer's USB port. This driver can be used with gphoto 0.4.3 - and higher (look at ). - To use it create a device node with "mknod /dev/mustek c 180 32" and - configure it in your software. - - To compile this driver as a module, choose M here: the - module will be called mdc800. - -config USB_MICROTEK - tristate "Microtek X6USB scanner support" - depends on SCSI - help - Say Y here if you want support for the Microtek X6USB and - possibly the Phantom 336CX, Phantom C6 and ScanMaker V6U(S)L. - Support for anything but the X6 is experimental. - Please report failures and successes. - The scanner will appear as a scsi generic device to the rest - of the system. Scsi support is required. - This driver can be compiled as a module, called microtek. diff --git a/src/linux/drivers/usb/isp1760/Kconfig b/src/linux/drivers/usb/isp1760/Kconfig deleted file mode 100644 index c94b7d9..0000000 --- a/src/linux/drivers/usb/isp1760/Kconfig +++ /dev/null @@ -1,59 +0,0 @@ -config USB_ISP1760 - tristate "NXP ISP 1760/1761 support" - depends on USB || USB_GADGET - help - Say Y or M here if your system as an ISP1760 USB host controller - or an ISP1761 USB dual-role controller. - - This driver does not support isochronous transfers or OTG. - This USB controller is usually attached to a non-DMA-Master - capable bus. NXP's eval kit brings this chip on PCI card - where the chip itself is behind a PLB to simulate such - a bus. - - To compile this driver as a module, choose M here: the - module will be called isp1760. - -config USB_ISP1760_HCD - bool - -config USB_ISP1761_UDC - bool - -if USB_ISP1760 - -choice - bool "ISP1760 Mode Selection" - default USB_ISP1760_DUAL_ROLE if (USB && USB_GADGET) - default USB_ISP1760_HOST_ROLE if (USB && !USB_GADGET) - default USB_ISP1760_GADGET_ROLE if (!USB && USB_GADGET) - -config USB_ISP1760_HOST_ROLE - bool "Host only mode" - depends on USB=y || USB=USB_ISP1760 - select USB_ISP1760_HCD - help - Select this if you want to use the ISP1760 in host mode only. The - gadget function will be disabled. - -config USB_ISP1760_GADGET_ROLE - bool "Gadget only mode" - depends on USB_GADGET=y || USB_GADGET=USB_ISP1760 - select USB_ISP1761_UDC - help - Select this if you want to use the ISP1760 in peripheral mode only. - The host function will be disabled. - -config USB_ISP1760_DUAL_ROLE - bool "Dual Role mode" - depends on USB=y || USB=USB_ISP1760 - depends on USB_GADGET=y || USB_GADGET=USB_ISP1760 - select USB_ISP1760_HCD - select USB_ISP1761_UDC - help - Select this if you want to use the ISP1760 in both host and - peripheral modes. - -endchoice - -endif diff --git a/src/linux/drivers/usb/misc/Kconfig b/src/linux/drivers/usb/misc/Kconfig deleted file mode 100644 index 47b3577..0000000 --- a/src/linux/drivers/usb/misc/Kconfig +++ /dev/null @@ -1,294 +0,0 @@ -# -# USB Miscellaneous driver configuration -# -comment "USB Miscellaneous drivers" - -config USB_EMI62 - tristate "EMI 6|2m USB Audio interface support" - ---help--- - This driver loads firmware to Emagic EMI 6|2m low latency USB - Audio and Midi interface. - - After firmware load the device is handled with standard linux - USB Audio driver. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called audio. If you want to compile it as a - module, say M here and read . - -config USB_EMI26 - tristate "EMI 2|6 USB Audio interface support" - ---help--- - This driver loads firmware to Emagic EMI 2|6 low latency USB - Audio interface. - - After firmware load the device is handled with standard linux - USB Audio driver. - - To compile this driver as a module, choose M here: the - module will be called emi26. - -config USB_ADUTUX - tristate "ADU devices from Ontrak Control Systems" - help - Say Y if you want to use an ADU device from Ontrak Control - Systems. - - To compile this driver as a module, choose M here. The module - will be called adutux. - -config USB_SEVSEG - tristate "USB 7-Segment LED Display" - help - Say Y here if you have a USB 7-Segment Display by Delcom - - To compile this driver as a module, choose M here: the - module will be called usbsevseg. - -config USB_RIO500 - tristate "USB Diamond Rio500 support" - help - Say Y here if you want to connect a USB Rio500 mp3 player to your - computer's USB port. Please read - for more information. - - To compile this driver as a module, choose M here: the - module will be called rio500. - -config USB_LEGOTOWER - tristate "USB Lego Infrared Tower support" - help - Say Y here if you want to connect a USB Lego Infrared Tower to your - computer's USB port. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called legousbtower. If you want to compile it as - a module, say M here and read - . - -config USB_LCD - tristate "USB LCD driver support" - help - Say Y here if you want to connect an USBLCD to your computer's - USB port. The USBLCD is a small USB interface board for - alphanumeric LCD modules. See for more - information. - - To compile this driver as a module, choose M here: the - module will be called usblcd. - -config USB_CYPRESS_CY7C63 - tristate "Cypress CY7C63xxx USB driver support" - help - Say Y here if you want to connect a Cypress CY7C63xxx - micro controller to your computer's USB port. Currently this - driver supports the pre-programmed devices (incl. firmware) - by AK Modul-Bus Computer GmbH. - - Please see: http://www.ak-modul-bus.de/stat/mikrocontroller.html - - To compile this driver as a module, choose M here: the - module will be called cypress_cy7c63. - -config USB_CYTHERM - tristate "Cypress USB thermometer driver support" - help - Say Y here if you want to connect a Cypress USB thermometer - device to your computer's USB port. This device is also known - as the Cypress USB Starter kit or demo board. The Elektor - magazine published a modified version of this device in issue - #291. - - To compile this driver as a module, choose M here: the - module will be called cytherm. - -config USB_IDMOUSE - tristate "Siemens ID USB Mouse Fingerprint sensor support" - help - Say Y here if you want to use the fingerprint sensor on - the Siemens ID Mouse. There is also a Siemens ID Mouse - _Professional_, which has not been tested with this driver, - but uses the same sensor and may therefore work. - - This driver creates an entry "/dev/idmouseX" or "/dev/usb/idmouseX", - which can be used by, e.g.,"cat /dev/idmouse0 > fingerprint.pnm". - - See also . - -config USB_FTDI_ELAN - tristate "Elan PCMCIA CardBus Adapter USB Client" - help - ELAN's Uxxx series of adapters are USB to PCMCIA CardBus adapters. - Currently only the U132 adapter is available. - - The U132 is specifically designed for CardBus PC cards that contain - an OHCI host controller. Typical PC cards are the Orange Mobile 3G - Option GlobeTrotter Fusion card. The U132 adapter will *NOT* work - with PC cards that do not contain an OHCI controller. To use a U132 - adapter you will need this "ftdi-elan" module as well as the "u132-hcd" - module which is a USB host controller driver that talks to the OHCI - controller within CardBus card that are inserted in the U132 adapter. - - This driver has been tested with a CardBus OHCI USB adapter, and - worked with a USB PEN Drive inserted into the first USB port of - the PCCARD. A rather pointless thing to do, but useful for testing. - - See also the USB_U132_HCD entry "Elan U132 Adapter Host Controller" - - It is safe to say M here. - -config USB_APPLEDISPLAY - tristate "Apple Cinema Display support" - select BACKLIGHT_LCD_SUPPORT - select BACKLIGHT_CLASS_DEVICE - help - Say Y here if you want to control the backlight of Apple Cinema - Displays over USB. This driver provides a sysfs interface. - -source "drivers/usb/misc/sisusbvga/Kconfig" - -config USB_LD - tristate "USB LD driver" - help - This driver is for generic USB devices that use interrupt transfers, - like LD Didactic's USB devices. - - To compile this driver as a module, choose M here: the - module will be called ldusb. - -config USB_TRANCEVIBRATOR - tristate "PlayStation 2 Trance Vibrator driver support" - help - Say Y here if you want to connect a PlayStation 2 Trance Vibrator - device to your computer's USB port. - - To compile this driver as a module, choose M here: the - module will be called trancevibrator. - -config USB_IOWARRIOR - tristate "IO Warrior driver support" - help - Say Y here if you want to support the IO Warrior devices from Code - Mercenaries. This includes support for the following devices: - IO Warrior 40 - IO Warrior 24 - IO Warrior 56 - IO Warrior 24 Power Vampire - - To compile this driver as a module, choose M here: the - module will be called iowarrior. - -config USB_TEST - tristate "USB testing driver" - help - This driver is for testing host controller software. It is used - with specialized device firmware for regression and stress testing, - to help prevent problems from cropping up with "real" drivers. - - See for more information, - including sample test device firmware and "how to use it". - -config USB_EHSET_TEST_FIXTURE - tristate "USB EHSET Test Fixture driver" - help - Say Y here if you want to support the special test fixture device - used for the USB-IF Embedded Host High-Speed Electrical Test procedure. - - When the test fixture is connected, it can enumerate as one of several - VID/PID pairs. This driver then initiates a corresponding test mode on - the downstream port to which the test fixture is attached. - - See for more - information. - -config USB_ISIGHTFW - tristate "iSight firmware loading support" - select FW_LOADER - help - This driver loads firmware for USB Apple iSight cameras, allowing - them to be driven by the USB video class driver available at - http://linux-uvc.berlios.de - - The firmware for this driver must be extracted from the MacOS - driver beforehand. Tools for doing so are available at - http://bersace03.free.fr - -config USB_YUREX - tristate "USB YUREX driver support" - help - Say Y here if you want to connect a YUREX to your computer's - USB port. The YUREX is a leg-shakes sensor. See - for further information. - This driver supports read/write of leg-shakes counter and - fasync for the counter update via a device file /dev/yurex*. - - To compile this driver as a module, choose M here: the - module will be called yurex. - -config USB_EZUSB_FX2 - tristate "Functions for loading firmware on EZUSB chips" - help - Say Y here if you need EZUSB device support. - (Cypress FX/FX2/FX2LP microcontrollers) - -config USB_HSIC_USB3503 - tristate "USB3503 HSIC to USB20 Driver" - depends on I2C - select REGMAP_I2C - help - This option enables support for SMSC USB3503 HSIC to USB 2.0 Driver. - -config USB_HSIC_USB4604 - tristate "USB4604 HSIC to USB20 Driver" - depends on I2C - help - This option enables support for SMSC USB4604 HSIC to USB 2.0 Driver. - -config USB_LINK_LAYER_TEST - tristate "USB Link Layer Test driver" - help - This driver is for generating specific traffic for Super Speed Link - Layer Test Device. Say Y only when you want to conduct USB Super Speed - Link Layer Test for host controllers. - -config USB_CHAOSKEY - tristate "ChaosKey random number generator driver support" - depends on HW_RANDOM - help - Say Y here if you want to connect an AltusMetrum ChaosKey or - Araneus Alea I to your computer's USB port. These devices - are hardware random number generators which hook into the - kernel entropy pool to ensure a large supply of entropy for - /dev/random and /dev/urandom and also provides direct access - via /dev/chaoskeyX - - To compile this driver as a module, choose M here: the - module will be called chaoskey. - -config UCSI - tristate "USB Type-C Connector System Software Interface driver" - depends on ACPI - help - UCSI driver is meant to be used as a convenience tool for desktop and - server systems that are not equipped to handle USB in device mode. It - will always select USB host role for the USB Type-C ports on systems - that provide UCSI interface. - - USB Type-C Connector System Software Interface (UCSI) is a - specification for an interface that allows the Operating System to - control the USB Type-C ports on a system. Things the need controlling - include the USB Data Role (host or device), and when USB Power - Delivery is supported, the Power Role (source or sink). With USB - Type-C connectors, when two dual role capable devices are attached - together, the data role is selected randomly. Therefore it is - important to give the OS a way to select the role. Otherwise the user - would have to unplug and replug in order in order to attempt to swap - the data and power roles. - - The UCSI specification can be downloaded from: - http://www.intel.com/content/www/us/en/io/universal-serial-bus/usb-type-c-ucsi-spec.html - - To compile the driver as a module, choose M here: the module will be - called ucsi. diff --git a/src/linux/drivers/usb/misc/sisusbvga/Kconfig b/src/linux/drivers/usb/misc/sisusbvga/Kconfig deleted file mode 100644 index 36bc28c..0000000 --- a/src/linux/drivers/usb/misc/sisusbvga/Kconfig +++ /dev/null @@ -1,47 +0,0 @@ - -config USB_SISUSBVGA - tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)" - depends on (USB_MUSB_HDRC || USB_EHCI_HCD) - select FONT_SUPPORT if USB_SISUSBVGA_CON - ---help--- - Say Y here if you intend to attach a USB2VGA dongle based on a - Net2280 and a SiS315 chip. - - Note that this device requires a USB 2.0 host controller. It will not - work with USB 1.x controllers. - - To compile this driver as a module, choose M here; the module will be - called sisusbvga. If unsure, say N. - -config USB_SISUSBVGA_CON - bool "Text console and mode switching support" if USB_SISUSBVGA - depends on VT - select FONT_8x16 - ---help--- - Say Y here if you want a VGA text console via the USB dongle or - want to support userland applications that utilize the driver's - display mode switching capabilities. - - Note that this console supports VGA/EGA text mode only. - - By default, the console part of the driver will not kick in when - the driver is initialized. If you want the driver to take over - one or more of the consoles, you need to specify the number of - the first and last consoles (starting at 1) as driver parameters. - - For example, if the driver is compiled as a module: - - modprobe sisusbvga first=1 last=5 - - If you use hotplug, add this to your modutils config files with - the "options" keyword, such as eg. - - options sisusbvga first=1 last=5 - - If the driver is compiled into the kernel image, the parameters - must be given in the kernel command like, such as - - sisusbvga.first=1 sisusbvga.last=5 - - - diff --git a/src/linux/drivers/usb/mon/Kconfig b/src/linux/drivers/usb/mon/Kconfig deleted file mode 100644 index 5c6ffa2..0000000 --- a/src/linux/drivers/usb/mon/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -# -# USB Monitor configuration -# - -config USB_MON - tristate "USB Monitor" - help - If you select this option, a component which captures the USB traffic - between peripheral-specific drivers and HC drivers will be built. - For more information, see . - - If unsure, say Y, if allowed, otherwise M. diff --git a/src/linux/drivers/usb/musb/Kconfig b/src/linux/drivers/usb/musb/Kconfig deleted file mode 100644 index 72a2a50..0000000 --- a/src/linux/drivers/usb/musb/Kconfig +++ /dev/null @@ -1,176 +0,0 @@ -# -# USB Dual Role (OTG-ready) Controller Drivers -# for silicon based on Mentor Graphics INVENTRA designs -# - -# (M)HDRC = (Multipoint) Highspeed Dual-Role Controller -config USB_MUSB_HDRC - tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, AW, ...)' - depends on (USB || USB_GADGET) - depends on HAS_IOMEM - help - Say Y here if your system has a dual role high speed USB - controller based on the Mentor Graphics silicon IP. Then - configure options to match your silicon and the board - it's being used with, including the USB peripheral role, - or the USB host role, or both. - - Texas Instruments families using this IP include DaVinci - (35x, 644x ...), OMAP 243x, OMAP 3, and TUSB 6010. - - Analog Devices parts using this IP include Blackfin BF54x, - BF525 and BF527. - - Allwinner SoCs using this IP include A10, A13, A20, ... - - If you do not know what this is, please say N. - - To compile this driver as a module, choose M here; the - module will be called "musb-hdrc". - -if USB_MUSB_HDRC - -choice - bool "MUSB Mode Selection" - default USB_MUSB_DUAL_ROLE if (USB && USB_GADGET) - default USB_MUSB_HOST if (USB && !USB_GADGET) - default USB_MUSB_GADGET if (!USB && USB_GADGET) - -config USB_MUSB_HOST - bool "Host only mode" - depends on USB=y || USB=USB_MUSB_HDRC - help - Select this when you want to use MUSB in host mode only, - thereby the gadget feature will be regressed. - -config USB_MUSB_GADGET - bool "Gadget only mode" - depends on USB_GADGET=y || USB_GADGET=USB_MUSB_HDRC - depends on HAS_DMA - help - Select this when you want to use MUSB in gadget mode only, - thereby the host feature will be regressed. - -config USB_MUSB_DUAL_ROLE - bool "Dual Role mode" - depends on ((USB=y || USB=USB_MUSB_HDRC) && (USB_GADGET=y || USB_GADGET=USB_MUSB_HDRC)) - depends on HAS_DMA - help - This is the default mode of working of MUSB controller where - both host and gadget features are enabled. - -endchoice - -comment "Platform Glue Layer" - -config USB_MUSB_SUNXI - tristate "Allwinner (sunxi)" - depends on ARCH_SUNXI - depends on NOP_USB_XCEIV - depends on PHY_SUN4I_USB - depends on EXTCON - depends on GENERIC_PHY - select SUNXI_SRAM - -config USB_MUSB_DAVINCI - tristate "DaVinci" - depends on ARCH_DAVINCI_DMx - depends on NOP_USB_XCEIV - depends on BROKEN - -config USB_MUSB_DA8XX - tristate "DA8xx/OMAP-L1x" - depends on ARCH_DAVINCI_DA8XX - depends on NOP_USB_XCEIV - select PHY_DA8XX_USB - -config USB_MUSB_TUSB6010 - tristate "TUSB6010" - depends on HAS_IOMEM - depends on (ARCH_OMAP2PLUS || COMPILE_TEST) && !BLACKFIN - depends on NOP_USB_XCEIV = USB_MUSB_HDRC # both built-in or both modules - -config USB_MUSB_OMAP2PLUS - tristate "OMAP2430 and onwards" - depends on ARCH_OMAP2PLUS && USB - depends on OMAP_CONTROL_PHY || !OMAP_CONTROL_PHY - select GENERIC_PHY - -config USB_MUSB_AM35X - tristate "AM35x" - depends on ARCH_OMAP - depends on NOP_USB_XCEIV - -config USB_MUSB_DSPS - tristate "TI DSPS platforms" - select USB_MUSB_AM335X_CHILD - depends on ARCH_OMAP2PLUS || COMPILE_TEST - depends on OF_IRQ - -config USB_MUSB_BLACKFIN - tristate "Blackfin" - depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523) - depends on NOP_USB_XCEIV - -config USB_MUSB_UX500 - tristate "Ux500 platforms" - depends on ARCH_U8500 || COMPILE_TEST - -config USB_MUSB_JZ4740 - tristate "JZ4740" - depends on NOP_USB_XCEIV - depends on MACH_JZ4740 || COMPILE_TEST - depends on USB_MUSB_GADGET - depends on USB_OTG_BLACKLIST_HUB - -config USB_MUSB_AM335X_CHILD - tristate - -comment "MUSB DMA mode" - -config MUSB_PIO_ONLY - bool 'Disable DMA (always use PIO)' - help - All data is copied between memory and FIFO by the CPU. - DMA controllers are ignored. - - Do not choose this unless DMA support for your SOC or board - is unavailable (or unstable). When DMA is enabled at compile time, - you can still disable it at run time using the "use_dma=n" module - parameter. - -if !MUSB_PIO_ONLY - -config USB_UX500_DMA - bool 'ST Ericsson Ux500' - depends on USB_MUSB_UX500 - help - Enable DMA transfers on UX500 platforms. - -config USB_INVENTRA_DMA - bool 'Inventra' - depends on USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN - help - Enable DMA transfers using Mentor's engine. - -config USB_TI_CPPI_DMA - bool 'TI CPPI (Davinci)' - depends on USB_MUSB_DAVINCI - help - Enable DMA transfers when TI CPPI DMA is available. - -config USB_TI_CPPI41_DMA - bool 'TI CPPI 4.1 (AM335x)' - depends on ARCH_OMAP && DMADEVICES - select TI_CPPI41 - -config USB_TUSB_OMAP_DMA - bool 'TUSB 6010' - depends on USB_MUSB_TUSB6010 = USB_MUSB_HDRC # both built-in or both modules - depends on ARCH_OMAP - help - Enable DMA transfers on TUSB 6010 when OMAP DMA is available. - -endif # !MUSB_PIO_ONLY - -endif # USB_MUSB_HDRC diff --git a/src/linux/drivers/usb/phy/Kconfig b/src/linux/drivers/usb/phy/Kconfig deleted file mode 100644 index b9c409a..0000000 --- a/src/linux/drivers/usb/phy/Kconfig +++ /dev/null @@ -1,211 +0,0 @@ -# -# Physical Layer USB driver configuration -# -menu "USB Physical Layer drivers" - -config USB_PHY - def_bool n - -# -# USB Transceiver Drivers -# -config AB8500_USB - tristate "AB8500 USB Transceiver Driver" - depends on AB8500_CORE - select USB_PHY - help - Enable this to support the USB OTG transceiver in AB8500 chip. - This transceiver supports high and full speed devices plus, - in host mode, low speed. - -config FSL_USB2_OTG - bool "Freescale USB OTG Transceiver Driver" - depends on USB_EHCI_FSL && USB_FSL_USB2 && USB_OTG_FSM && PM - depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' - select USB_PHY - help - Enable this to support Freescale USB OTG transceiver. - -config ISP1301_OMAP - tristate "Philips ISP1301 with OMAP OTG" - depends on I2C && ARCH_OMAP_OTG - depends on USB - depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' - select USB_PHY - help - If you say yes here you get support for the Philips ISP1301 - USB-On-The-Go transceiver working with the OMAP OTG controller. - The ISP1301 is a full speed USB transceiver which is used in - products including H2, H3, and H4 development boards for Texas - Instruments OMAP processors. - - This driver can also be built as a module. If so, the module - will be called phy-isp1301-omap. - -config KEYSTONE_USB_PHY - tristate "Keystone USB PHY Driver" - depends on ARCH_KEYSTONE || COMPILE_TEST - depends on NOP_USB_XCEIV - help - Enable this to support Keystone USB phy. This driver provides - interface to interact with USB 2.0 and USB 3.0 PHY that is part - of the Keystone SOC. - -config NOP_USB_XCEIV - tristate "NOP USB Transceiver Driver" - depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, NOP can't be built-in - select USB_PHY - help - This driver is to be used by all the usb transceiver which are either - built-in with usb ip or which are autonomous and doesn't require any - phy programming such as ISP1x04 etc. - -config AM335X_CONTROL_USB - tristate - -config AM335X_PHY_USB - tristate "AM335x USB PHY Driver" - depends on ARM || COMPILE_TEST - depends on NOP_USB_XCEIV - select USB_PHY - select AM335X_CONTROL_USB - select USB_COMMON - help - This driver provides PHY support for that phy which part for the - AM335x SoC. - -config SAMSUNG_USBPHY - tristate - help - Enable this to support Samsung USB phy helper driver for Samsung SoCs. - This driver provides common interface to interact, for Samsung USB 2.0 PHY - driver and later for Samsung USB 3.0 PHY driver. - -config TWL6030_USB - tristate "TWL6030 USB Transceiver Driver" - depends on TWL4030_CORE && OMAP_USB2 && USB_MUSB_OMAP2PLUS - help - Enable this to support the USB OTG transceiver on TWL6030 - family chips. This TWL6030 transceiver has the VBUS and ID GND - and OTG SRP events capabilities. For all other transceiver functionality - UTMI PHY is embedded in OMAP4430. The internal PHY configurations APIs - are hooked to this driver through platform_data structure. - The definition of internal PHY APIs are in the mach-omap2 layer. - -config USB_GPIO_VBUS - tristate "GPIO based peripheral-only VBUS sensing 'transceiver'" - depends on GPIOLIB || COMPILE_TEST - depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' - select USB_PHY - help - Provides simple GPIO VBUS sensing for controllers with an - internal transceiver via the usb_phy interface, and - optionally control of a D+ pullup GPIO as well as a VBUS - current limit regulator. - -config OMAP_OTG - tristate "OMAP USB OTG controller driver" - depends on ARCH_OMAP_OTG && EXTCON - help - Enable this to support some transceivers on OMAP1 platforms. OTG - controller is needed to switch between host and peripheral modes. - - This driver can also be built as a module. If so, the module - will be called phy-omap-otg. - -config TAHVO_USB - tristate "Tahvo USB transceiver driver" - depends on MFD_RETU && EXTCON - depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' - select USB_PHY - help - Enable this to support USB transceiver on Tahvo. This is used - at least on Nokia 770. - -config TAHVO_USB_HOST_BY_DEFAULT - depends on TAHVO_USB - bool "Device in USB host mode by default" - help - Say Y here, if you want the device to enter USB host mode - by default on bootup. - -config USB_ISP1301 - tristate "NXP ISP1301 USB transceiver support" - depends on USB || USB_GADGET - depends on I2C - select USB_PHY - help - Say Y here to add support for the NXP ISP1301 USB transceiver driver. - This chip is typically used as USB transceiver for USB host, gadget - and OTG drivers (to be selected separately). - - To compile this driver as a module, choose M here: the - module will be called phy-isp1301. - -config USB_MSM_OTG - tristate "Qualcomm on-chip USB OTG controller support" - depends on (USB || USB_GADGET) && (ARCH_QCOM || COMPILE_TEST) - depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' - depends on RESET_CONTROLLER - depends on EXTCON - select USB_PHY - help - Enable this to support the USB OTG transceiver on Qualcomm chips. It - handles PHY initialization, clock management, and workarounds - required after resetting the hardware and power management. - This driver is required even for peripheral only or host only - mode configurations. - This driver is not supported on boards like trout which - has an external PHY. - -config USB_QCOM_8X16_PHY - tristate "Qualcomm APQ8016/MSM8916 on-chip USB PHY controller support" - depends on ARCH_QCOM || COMPILE_TEST - depends on RESET_CONTROLLER && EXTCON - select USB_PHY - select USB_ULPI_VIEWPORT - help - Enable this to support the USB transceiver on Qualcomm 8x16 chipsets. - It handles PHY initialization, clock management, power management, - and workarounds required after resetting the hardware. - - To compile this driver as a module, choose M here: the - module will be called phy-qcom-8x16-usb. - -config USB_MV_OTG - tristate "Marvell USB OTG support" - depends on USB_EHCI_MV && USB_MV_UDC && PM && USB_OTG - depends on USB_GADGET || !USB_GADGET # if USB_GADGET=m, this can't be 'y' - select USB_PHY - help - Say Y here if you want to build Marvell USB OTG transciever - driver in kernel (including PXA and MMP series). This driver - implements role switch between EHCI host driver and gadget driver. - - To compile this driver as a module, choose M here. - -config USB_MXS_PHY - tristate "Freescale MXS USB PHY support" - depends on ARCH_MXC || ARCH_MXS - select STMP_DEVICE - select USB_PHY - help - Enable this to support the Freescale MXS USB PHY. - - MXS Phy is used by some of the i.MX SoCs, for example imx23/28/6x. - -config USB_ULPI - bool "Generic ULPI Transceiver Driver" - depends on ARM || ARM64 - select USB_ULPI_VIEWPORT - help - Enable this to support ULPI connected USB OTG transceivers which - are likely found on embedded boards. - -config USB_ULPI_VIEWPORT - bool - help - Provides read/write operations to the ULPI phy register set for - controllers with a viewport register (e.g. Chipidea/ARC controllers). - -endmenu diff --git a/src/linux/drivers/usb/renesas_usbhs/Kconfig b/src/linux/drivers/usb/renesas_usbhs/Kconfig deleted file mode 100644 index b26d7c3..0000000 --- a/src/linux/drivers/usb/renesas_usbhs/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -# -# Renesas USBHS Controller Drivers -# - -config USB_RENESAS_USBHS - tristate 'Renesas USBHS controller' - depends on USB_GADGET - depends on ARCH_RENESAS || SUPERH || COMPILE_TEST - depends on EXTCON || !EXTCON # if EXTCON=m, USBHS cannot be built-in - default n - help - Renesas USBHS is a discrete USB host and peripheral controller chip - that supports both full and high speed USB 2.0 data transfers. - It has nine or more configurable endpoints, and endpoint zero. - - Say "y" to link the driver statically, or "m" to build a - dynamically linked module called "renesas_usbhs" diff --git a/src/linux/drivers/usb/serial/Kconfig b/src/linux/drivers/usb/serial/Kconfig deleted file mode 100644 index 56ecb8b..0000000 --- a/src/linux/drivers/usb/serial/Kconfig +++ /dev/null @@ -1,716 +0,0 @@ -# -# USB Serial device configuration -# - -menuconfig USB_SERIAL - tristate "USB Serial Converter support" - depends on TTY - ---help--- - Say Y here if you have a USB device that provides normal serial - ports, or acts like a serial device, and you want to connect it to - your USB bus. - - Please read for more - information on the specifics of the different devices that are - supported, and on how to use them. - - To compile this driver as a module, choose M here: the - module will be called usbserial. - -if USB_SERIAL - -config USB_SERIAL_CONSOLE - bool "USB Serial Console device support" - depends on USB_SERIAL=y - ---help--- - If you say Y here, it will be possible to use a USB to serial - converter port as the system console (the system console is the - device which receives all kernel messages and warnings and which - allows logins in single user mode). This could be useful if some - terminal or printer is connected to that serial port. - - Even if you say Y here, the currently visible virtual console - (/dev/tty0) will still be used as the system console by default, but - you can alter that using a kernel command line option such as - "console=ttyUSB0". (Try "man bootparam" or see the documentation of - your boot loader (lilo or loadlin) about how to pass options to the - kernel at boot time.) - - If you don't have a VGA card installed and you say Y here, the - kernel will automatically use the first USB to serial converter - port, /dev/ttyUSB0, as system console. - - If unsure, say N. - -config USB_SERIAL_GENERIC - bool "USB Generic Serial Driver" - help - Say Y here if you want to use the generic USB serial driver. Please - read for more information on - using this driver. It is recommended that the "USB Serial converter - support" be compiled as a module for this driver to be used - properly. - -config USB_SERIAL_SIMPLE - tristate "USB Serial Simple Driver" - help - Say Y here to use the USB serial "simple" driver. This driver - handles a wide range of very simple devices, all in one - driver. Specifically, it supports: - - Suunto ANT+ USB device. - - Medtronic CareLink USB device - - Fundamental Software dongle. - - Google USB serial devices - - HP4x calculators - - a number of Motorola phones - - Novatel Wireless GPS receivers - - Siemens USB/MPI adapter. - - ViVOtech ViVOpay USB device. - - Infineon Modem Flashloader USB interface - - ZIO Motherboard USB serial interface - - To compile this driver as a module, choose M here: the module - will be called usb-serial-simple. - -config USB_SERIAL_AIRCABLE - tristate "USB AIRcable Bluetooth Dongle Driver" - help - Say Y here if you want to use USB AIRcable Bluetooth Dongle. - - To compile this driver as a module, choose M here: the module - will be called aircable. - -config USB_SERIAL_ARK3116 - tristate "USB ARK Micro 3116 USB Serial Driver" - help - Say Y here if you want to use a ARK Micro 3116 USB to Serial - device. - - To compile this driver as a module, choose M here: the - module will be called ark3116 - -config USB_SERIAL_BELKIN - tristate "USB Belkin and Peracom Single Port Serial Driver" - help - Say Y here if you want to use a Belkin USB Serial single port - adaptor (F5U103 is one of the model numbers) or the Peracom single - port USB to serial adapter. - - To compile this driver as a module, choose M here: the - module will be called belkin_sa. - -config USB_SERIAL_CH341 - tristate "USB Winchiphead CH341 Single Port Serial Driver" - help - Say Y here if you want to use a Winchiphead CH341 single port - USB to serial adapter. - - To compile this driver as a module, choose M here: the - module will be called ch341. - -config USB_SERIAL_WHITEHEAT - tristate "USB ConnectTech WhiteHEAT Serial Driver" - select USB_EZUSB_FX2 - help - Say Y here if you want to use a ConnectTech WhiteHEAT 4 port - USB to serial converter device. - - To compile this driver as a module, choose M here: the - module will be called whiteheat. - -config USB_SERIAL_DIGI_ACCELEPORT - tristate "USB Digi International AccelePort USB Serial Driver" - ---help--- - Say Y here if you want to use Digi AccelePort USB 2 or 4 devices, - 2 port (plus parallel port) and 4 port USB serial converters. The - parallel port on the USB 2 appears as a third serial port on Linux. - The Digi Acceleport USB 8 is not yet supported by this driver. - - This driver works under SMP with the usb-uhci driver. It does not - work under SMP with the uhci driver. - - To compile this driver as a module, choose M here: the - module will be called digi_acceleport. - -config USB_SERIAL_CP210X - tristate "USB CP210x family of UART Bridge Controllers" - help - Say Y here if you want to use a CP2101/CP2102/CP2103 based USB - to RS232 converters. - - To compile this driver as a module, choose M here: the - module will be called cp210x. - -config USB_SERIAL_CYPRESS_M8 - tristate "USB Cypress M8 USB Serial Driver" - help - Say Y here if you want to use a device that contains the Cypress - USB to Serial microcontroller, such as the DeLorme Earthmate GPS. - - Attempted SMP support... send bug reports! - - Supported microcontrollers in the CY4601 family are: - CY7C63741 CY7C63742 CY7C63743 CY7C64013 - - To compile this driver as a module, choose M here: the - module will be called cypress_m8. - -config USB_SERIAL_EMPEG - tristate "USB Empeg empeg-car Mark I/II Driver" - help - Say Y here if you want to connect to your Empeg empeg-car Mark I/II - mp3 player via USB. The driver uses a single ttyUSB{0,1,2,...} - device node. See for more - tidbits of information. - - To compile this driver as a module, choose M here: the - module will be called empeg. - -config USB_SERIAL_FTDI_SIO - tristate "USB FTDI Single Port Serial Driver" - ---help--- - Say Y here if you want to use a FTDI SIO single port USB to serial - converter device. The implementation I have is called the USC-1000. - This driver has also been tested with the 245 and 232 devices. - - See for more - information on this driver and the device. - - To compile this driver as a module, choose M here: the - module will be called ftdi_sio. - -config USB_SERIAL_VISOR - tristate "USB Handspring Visor / Palm m50x / Sony Clie Driver" - help - Say Y here if you want to connect to your HandSpring Visor, Palm - m500 or m505 through its USB docking station. See - for more information on using this - driver. - - To compile this driver as a module, choose M here: the - module will be called visor. - -config USB_SERIAL_IPAQ - tristate "USB PocketPC PDA Driver" - help - Say Y here if you want to connect to your Compaq iPAQ, HP Jornada - or any other PDA running Windows CE 3.0 or PocketPC 2002 - using a USB cradle/cable. For information on using the driver, - read . - - To compile this driver as a module, choose M here: the - module will be called ipaq. - -config USB_SERIAL_IR - tristate "USB IR Dongle Serial Driver" - help - Say Y here if you want to enable simple serial support for USB IrDA - devices. This is useful if you do not want to use the full IrDA - stack. - - To compile this driver as a module, choose M here: the - module will be called ir-usb. - -config USB_SERIAL_EDGEPORT - tristate "USB Inside Out Edgeport Serial Driver" - ---help--- - Say Y here if you want to use any of the following devices from - Inside Out Networks (Digi): - Edgeport/4 - Rapidport/4 - Edgeport/4t - Edgeport/2 - Edgeport/4i - Edgeport/2i - Edgeport/421 - Edgeport/21 - Edgeport/8 - Edgeport/8 Dual - Edgeport/2D8 - Edgeport/4D8 - Edgeport/8i - Edgeport/2 DIN - Edgeport/4 DIN - Edgeport/16 Dual - - To compile this driver as a module, choose M here: the - module will be called io_edgeport. - -config USB_SERIAL_EDGEPORT_TI - tristate "USB Inside Out Edgeport Serial Driver (TI devices)" - help - Say Y here if you want to use any of the devices from Inside Out - Networks (Digi) that are not supported by the io_edgeport driver. - This includes the Edgeport/1 device. - - To compile this driver as a module, choose M here: the - module will be called io_ti. - -config USB_SERIAL_F81232 - tristate "USB Fintek F81232 Single Port Serial Driver" - help - Say Y here if you want to use the Fintek F81232 single - port usb to serial adapter. - - To compile this driver as a module, choose M here: the - module will be called f81232. - -config USB_SERIAL_GARMIN - tristate "USB Garmin GPS driver" - help - Say Y here if you want to connect to your Garmin GPS. - Should work with most Garmin GPS devices which have a native USB port. - - See for the latest - version of the driver. - - To compile this driver as a module, choose M here: the - module will be called garmin_gps. - -config USB_SERIAL_IPW - tristate "USB IPWireless (3G UMTS TDD) Driver" - select USB_SERIAL_WWAN - help - Say Y here if you want to use a IPWireless USB modem such as - the ones supplied by Axity3G/Sentech South Africa. - - To compile this driver as a module, choose M here: the - module will be called ipw. - -config USB_SERIAL_IUU - tristate "USB Infinity USB Unlimited Phoenix Driver" - help - Say Y here if you want to use a IUU in phoenix mode and get - an extra ttyUSBx device. More information available on - http://eczema.ecze.com/iuu_phoenix.html - - To compile this driver as a module, choose M here: the - module will be called iuu_phoenix.o - -config USB_SERIAL_KEYSPAN_PDA - tristate "USB Keyspan PDA Single Port Serial Driver" - select USB_EZUSB_FX2 - help - Say Y here if you want to use a Keyspan PDA single port USB to - serial converter device. This driver makes use of firmware - developed from scratch by Brian Warner. - - To compile this driver as a module, choose M here: the - module will be called keyspan_pda. - -config USB_SERIAL_KEYSPAN - tristate "USB Keyspan USA-xxx Serial Driver" - select USB_EZUSB_FX2 - ---help--- - Say Y here if you want to use Keyspan USB to serial converter - devices. This driver makes use of Keyspan's official firmware - and was developed with their support. You must also include - firmware to support your particular device(s). - - See for more information. - - To compile this driver as a module, choose M here: the - module will be called keyspan. - -config USB_SERIAL_KEYSPAN_MPR - bool "USB Keyspan MPR Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the Keyspan MPR converter. - -config USB_SERIAL_KEYSPAN_USA28 - bool "USB Keyspan USA-28 Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-28 converter. - -config USB_SERIAL_KEYSPAN_USA28X - bool "USB Keyspan USA-28X Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-28X converter. - Be sure you have a USA-28X, there are also 28XA and 28XB - models, the label underneath has the actual part number. - -config USB_SERIAL_KEYSPAN_USA28XA - bool "USB Keyspan USA-28XA Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-28XA converter. - Be sure you have a USA-28XA, there are also 28X and 28XB - models, the label underneath has the actual part number. - -config USB_SERIAL_KEYSPAN_USA28XB - bool "USB Keyspan USA-28XB Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-28XB converter. - Be sure you have a USA-28XB, there are also 28X and 28XA - models, the label underneath has the actual part number. - -config USB_SERIAL_KEYSPAN_USA19 - bool "USB Keyspan USA-19 Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-19 converter. - -config USB_SERIAL_KEYSPAN_USA18X - bool "USB Keyspan USA-18X Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-18X converter. - -config USB_SERIAL_KEYSPAN_USA19W - bool "USB Keyspan USA-19W Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-19W converter. - -config USB_SERIAL_KEYSPAN_USA19QW - bool "USB Keyspan USA-19QW Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-19QW converter. - -config USB_SERIAL_KEYSPAN_USA19QI - bool "USB Keyspan USA-19QI Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-19QI converter. - -config USB_SERIAL_KEYSPAN_USA49W - bool "USB Keyspan USA-49W Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-49W converter. - -config USB_SERIAL_KEYSPAN_USA49WLC - bool "USB Keyspan USA-49WLC Firmware" - depends on USB_SERIAL_KEYSPAN && FIRMWARE_IN_KERNEL - help - Say Y here to include firmware for the USA-49WLC converter. - -config USB_SERIAL_KLSI - tristate "USB KL5KUSB105 (Palmconnect) Driver" - ---help--- - Say Y here if you want to use a KL5KUSB105 - based single port - serial adapter. The most widely known -- and currently the only - tested -- device in this category is the PalmConnect USB Serial - adapter sold by Palm Inc. for use with their Palm III and Palm V - series PDAs. - - Please read for more - information. - - To compile this driver as a module, choose M here: the - module will be called kl5kusb105. - -config USB_SERIAL_KOBIL_SCT - tristate "USB KOBIL chipcard reader" - ---help--- - Say Y here if you want to use one of the following KOBIL USB chipcard - readers: - - - USB TWIN - - KAAN Standard Plus - - KAAN SIM - - SecOVID Reader Plus - - B1 Professional - - KAAN Professional - - Note that you need a current CT-API. - To compile this driver as a module, choose M here: the - module will be called kobil_sct. - -config USB_SERIAL_MCT_U232 - tristate "USB MCT Single Port Serial Driver" - ---help--- - Say Y here if you want to use a USB Serial single port adapter from - Magic Control Technology Corp. (U232 is one of the model numbers). - - This driver also works with Sitecom U232-P25 and D-Link DU-H3SP USB - BAY, Belkin F5U109, and Belkin F5U409 devices. - - To compile this driver as a module, choose M here: the - module will be called mct_u232. - -config USB_SERIAL_METRO - tristate "USB Metrologic Instruments USB-POS Barcode Scanner Driver" - ---help--- - Say Y here if you want to use a USB POS Metrologic barcode scanner. - - To compile this driver as a module, choose M here: the - module will be called metro-usb. - -config USB_SERIAL_MOS7720 - tristate "USB Moschip 7720 Serial Driver" - ---help--- - Say Y here if you want to use USB Serial single and double - port adapters from Moschip Semiconductor Tech. - - To compile this driver as a module, choose M here: the - module will be called mos7720. - -config USB_SERIAL_MOS7715_PARPORT - bool "Support for parallel port on the Moschip 7715" - depends on USB_SERIAL_MOS7720 - depends on PARPORT=y || PARPORT=USB_SERIAL_MOS7720 - select PARPORT_NOT_PC - ---help--- - Say Y if you have a Moschip 7715 device and would like to use - the parallel port it provides. The port will register with - the parport subsystem as a low-level driver. - -config USB_SERIAL_MOS7840 - tristate "USB Moschip 7840/7820 USB Serial Driver" - ---help--- - Say Y here if you want to use a MCS7840 Quad-Serial or MCS7820 - Dual-Serial port device from MosChip Semiconductor. - - The MCS7840 and MCS7820 have been developed to connect a wide range - of standard serial devices to a USB host. The MCS7840 has a USB - device controller connected to four (4) individual UARTs while the - MCS7820 controller connects to two (2) individual UARTs. - - To compile this driver as a module, choose M here: the - module will be called mos7840. If unsure, choose N. - -config USB_SERIAL_MXUPORT - tristate "USB Moxa UPORT Serial Driver" - ---help--- - Say Y here if you want to use a MOXA UPort Serial hub. - - This driver supports: - - [2 Port] - - UPort 1250 : 2 Port RS-232/422/485 USB to Serial Hub - - UPort 1250I : 2 Port RS-232/422/485 USB to Serial Hub with - Isolation - - [4 Port] - - UPort 1410 : 4 Port RS-232 USB to Serial Hub - - UPort 1450 : 4 Port RS-232/422/485 USB to Serial Hub - - UPort 1450I : 4 Port RS-232/422/485 USB to Serial Hub with - Isolation - - [8 Port] - - UPort 1610-8 : 8 Port RS-232 USB to Serial Hub - - UPort 1650-8 : 8 Port RS-232/422/485 USB to Serial Hub - - [16 Port] - - UPort 1610-16 : 16 Port RS-232 USB to Serial Hub - - UPort 1650-16 : 16 Port RS-232/422/485 USB to Serial Hub - - To compile this driver as a module, choose M here: the - module will be called mxuport. - -config USB_SERIAL_NAVMAN - tristate "USB Navman GPS device" - help - To compile this driver as a module, choose M here: the - module will be called navman. - -config USB_SERIAL_PL2303 - tristate "USB Prolific 2303 Single Port Serial Driver" - help - Say Y here if you want to use the PL2303 USB Serial single port - adapter from Prolific. - - To compile this driver as a module, choose M here: the - module will be called pl2303. - -config USB_SERIAL_OTI6858 - tristate "USB Ours Technology Inc. OTi-6858 USB To RS232 Bridge Controller" - help - Say Y here if you want to use the OTi-6858 single port USB to serial - converter device. - - To compile this driver as a module, choose M here: the - module will be called oti6858. - -config USB_SERIAL_QCAUX - tristate "USB Qualcomm Auxiliary Serial Port Driver" - help - Say Y here if you want to use the auxiliary serial ports provided - by many modems based on Qualcomm chipsets. These ports often use - a proprietary protocol called DM and cannot be used for AT- or - PPP-based communication. - - To compile this driver as a module, choose M here: the - module will be called qcaux. If unsure, choose N. - -config USB_SERIAL_QUALCOMM - tristate "USB Qualcomm Serial modem" - select USB_SERIAL_WWAN - help - Say Y here if you have a Qualcomm USB modem device. These are - usually wireless cellular modems. - - To compile this driver as a module, choose M here: the - module will be called qcserial. - -config USB_SERIAL_SPCP8X5 - tristate "USB SPCP8x5 USB To Serial Driver" - help - Say Y here if you want to use the spcp8x5 converter chip. This is - commonly found in some Z-Wave USB devices. - - To compile this driver as a module, choose M here: the - module will be called spcp8x5. - -config USB_SERIAL_SAFE - tristate "USB Safe Serial (Encapsulated) Driver" - -config USB_SERIAL_SAFE_PADDED - bool "USB Secure Encapsulated Driver - Padded" - depends on USB_SERIAL_SAFE - -config USB_SERIAL_SIERRAWIRELESS - tristate "USB Sierra Wireless Driver" - help - Say M here if you want to use Sierra Wireless devices. - - Many devices have a feature known as TRU-Install. For those devices - to work properly, the USB Storage Sierra feature must be enabled. - - To compile this driver as a module, choose M here: the - module will be called sierra. - -config USB_SERIAL_SYMBOL - tristate "USB Symbol Barcode driver (serial mode)" - help - Say Y here if you want to use a Symbol USB Barcode device - in serial emulation mode. - - To compile this driver as a module, choose M here: the - module will be called symbolserial. - -config USB_SERIAL_TI - tristate "USB TI 3410/5052 Serial Driver" - help - Say Y here if you want to use the TI USB 3410 or 5052 - serial devices. - - To compile this driver as a module, choose M here: the - module will be called ti_usb_3410_5052. - -config USB_SERIAL_CYBERJACK - tristate "USB REINER SCT cyberJack pinpad/e-com chipcard reader" - ---help--- - Say Y here if you want to use a cyberJack pinpad/e-com USB chipcard - reader. This is an interface to ISO 7816 compatible contact-based - chipcards, e.g. GSM SIMs. - - To compile this driver as a module, choose M here: the - module will be called cyberjack. - - If unsure, say N. - -config USB_SERIAL_XIRCOM - tristate "USB Xircom / Entrega Single Port Serial Driver" - select USB_EZUSB_FX2 - help - Say Y here if you want to use a Xircom or Entrega single port USB to - serial converter device. This driver makes use of firmware - developed from scratch by Brian Warner. - - To compile this driver as a module, choose M here: the - module will be called keyspan_pda. - -config USB_SERIAL_WWAN - tristate - -config USB_SERIAL_OPTION - tristate "USB driver for GSM and CDMA modems" - select USB_SERIAL_WWAN - help - Say Y here if you have a GSM or CDMA modem that's connected to USB. - - This driver also supports several PCMCIA cards which have a - built-in OHCI-USB adapter and an internally-connected GSM modem. - The USB bus on these cards is not accessible externally. - - Supported devices include (some of?) those made by: - Option, Huawei, Audiovox, Novatel Wireless, or Anydata. - - To compile this driver as a module, choose M here: the - module will be called option. - - If this driver doesn't recognize your device, - it might be accessible via the FTDI_SIO driver. - -config USB_SERIAL_OMNINET - tristate "USB ZyXEL omni.net LCD Plus Driver" - help - Say Y here if you want to use a ZyXEL omni.net LCD ISDN TA. - - To compile this driver as a module, choose M here: the - module will be called omninet. - -config USB_SERIAL_OPTICON - tristate "USB Opticon Barcode driver (serial mode)" - help - Say Y here if you want to use a Opticon USB Barcode device - in serial emulation mode. - - To compile this driver as a module, choose M here: the - module will be called opticon. - -config USB_SERIAL_XSENS_MT - tristate "Xsens motion tracker serial interface driver" - help - Say Y here if you want to use Xsens motion trackers. - - This driver supports the new generation of motion trackers - by Xsens. Older devices can be accessed using the FTDI_SIO - driver. - - To compile this driver as a module, choose M here: the - module will be called xsens_mt. - -config USB_SERIAL_WISHBONE - tristate "USB-Wishbone adapter interface driver" - help - Say Y here if you want to use a USB attached Wishbone bus. - - Wishbone is an open hardware SoC bus commonly used in FPGA - designs. Bus access can be serialized using the Etherbone - protocol . - - This driver is intended to be used with devices which attach - their internal Wishbone bus to a USB serial interface using - the Etherbone protocol. A userspace library is required to - speak the protocol made available by this driver as ttyUSBx. - - To compile this driver as a module, choose M here: the - module will be called wishbone-serial. - -config USB_SERIAL_SSU100 - tristate "USB Quatech SSU-100 Single Port Serial Driver" - help - Say Y here if you want to use the Quatech SSU-100 single - port usb to serial adapter. - - To compile this driver as a module, choose M here: the - module will be called ssu100. - -config USB_SERIAL_QT2 - tristate "USB Quatech Serial Driver for USB 2 devices" - help - Say Y here if you want to use the Quatech USB 2 - serial adapters. - - To compile this driver as a module, choose M here: the - module will be called quatech-serial. - -config USB_SERIAL_DEBUG - tristate "USB Debugging Device" - help - Say Y here if you have a USB debugging device used to receive - debugging data from another machine. The most common of these - devices is the NetChip TurboCONNECT device. - - To compile this driver as a module, choose M here: the - module will be called usb-debug. - -endif # USB_SERIAL diff --git a/src/linux/drivers/usb/storage/Kconfig b/src/linux/drivers/usb/storage/Kconfig deleted file mode 100644 index ec84758..0000000 --- a/src/linux/drivers/usb/storage/Kconfig +++ /dev/null @@ -1,214 +0,0 @@ -# -# USB Storage driver configuration -# - -comment "NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may" -comment "also be needed; see USB_STORAGE Help for more info" - -config USB_STORAGE - tristate "USB Mass Storage support" - depends on SCSI - ---help--- - Say Y here if you want to connect USB mass storage devices to your - computer's USB port. This is the driver you need for USB - floppy drives, USB hard disks, USB tape drives, USB CD-ROMs, - USB flash devices, and memory sticks, along with - similar devices. This driver may also be used for some cameras - and card readers. - - This option depends on 'SCSI' support being enabled, but you - probably also need 'SCSI device support: SCSI disk support' - (BLK_DEV_SD) for most USB storage devices. - - To compile this driver as a module, choose M here: the - module will be called usb-storage. - -config USB_STORAGE_DEBUG - bool "USB Mass Storage verbose debug" - depends on USB_STORAGE - help - Say Y here in order to have the USB Mass Storage code generate - verbose debugging messages. - -config USB_STORAGE_REALTEK - tristate "Realtek Card Reader support" - depends on USB_STORAGE - help - Say Y here to include additional code to support the power-saving function - for Realtek RTS51xx USB card readers. - - If this driver is compiled as a module, it will be named ums-realtek. - -config REALTEK_AUTOPM - bool "Realtek Card Reader autosuspend support" - depends on USB_STORAGE_REALTEK && PM - default y - -config USB_STORAGE_DATAFAB - tristate "Datafab Compact Flash Reader support" - depends on USB_STORAGE - help - Support for certain Datafab CompactFlash readers. - Datafab has a web page at . - - If this driver is compiled as a module, it will be named ums-datafab. - -config USB_STORAGE_FREECOM - tristate "Freecom USB/ATAPI Bridge support" - depends on USB_STORAGE - help - Support for the Freecom USB to IDE/ATAPI adaptor. - Freecom has a web page at . - - If this driver is compiled as a module, it will be named ums-freecom. - -config USB_STORAGE_ISD200 - tristate "ISD-200 USB/ATA Bridge support" - depends on USB_STORAGE - ---help--- - Say Y here if you want to use USB Mass Store devices based - on the In-Systems Design ISD-200 USB/ATA bridge. - - Some of the products that use this chip are: - - - Archos Jukebox 6000 - - ISD SmartCable for Storage - - Taiwan Skymaster CD530U/DEL-0241 IDE bridge - - Sony CRX10U CD-R/RW drive - - CyQ've CQ8060A CDRW drive - - Planex eXtreme Drive RX-25HU USB-IDE cable (not model RX-25U) - - If this driver is compiled as a module, it will be named ums-isd200. - -config USB_STORAGE_USBAT - tristate "USBAT/USBAT02-based storage support" - depends on USB_STORAGE - help - Say Y here to include additional code to support storage devices - based on the SCM/Shuttle USBAT/USBAT02 processors. - - Devices reported to work with this driver include: - - CompactFlash reader included with Kodak DC3800 camera - - Dane-Elec Zmate CompactFlash reader - - Delkin Efilm reader2 - - HP 8200e/8210e/8230e CD-Writer Plus drives - - I-JAM JS-50U - - Jessops CompactFlash JESDCFRU BLACK - - Kingston Technology PCREAD-USB/CF - - Maxell UA4 CompactFlash reader - - Memorex UCF-100 - - Microtech ZiO! ICS-45 CF2 - - RCA LYRA MP3 portable - - Sandisk ImageMate SDDR-05b - - If this driver is compiled as a module, it will be named ums-usbat. - -config USB_STORAGE_SDDR09 - tristate "SanDisk SDDR-09 (and other SmartMedia, including DPCM) support" - depends on USB_STORAGE - help - Say Y here to include additional code to support the Sandisk SDDR-09 - SmartMedia reader in the USB Mass Storage driver. - Also works for the Microtech Zio! CompactFlash/SmartMedia reader. - - If this driver is compiled as a module, it will be named ums-sddr09. - -config USB_STORAGE_SDDR55 - tristate "SanDisk SDDR-55 SmartMedia support" - depends on USB_STORAGE - help - Say Y here to include additional code to support the Sandisk SDDR-55 - SmartMedia reader in the USB Mass Storage driver. - - If this driver is compiled as a module, it will be named ums-sddr55. - -config USB_STORAGE_JUMPSHOT - tristate "Lexar Jumpshot Compact Flash Reader" - depends on USB_STORAGE - help - Say Y here to include additional code to support the Lexar Jumpshot - USB CompactFlash reader. - - If this driver is compiled as a module, it will be named ums-jumpshot. - -config USB_STORAGE_ALAUDA - tristate "Olympus MAUSB-10/Fuji DPC-R1 support" - depends on USB_STORAGE - help - Say Y here to include additional code to support the Olympus MAUSB-10 - and Fujifilm DPC-R1 USB Card reader/writer devices. - - These devices are based on the Alauda chip and support both - XD and SmartMedia cards. - - If this driver is compiled as a module, it will be named ums-alauda. - -config USB_STORAGE_ONETOUCH - tristate "Support OneTouch Button on Maxtor Hard Drives" - depends on USB_STORAGE - depends on INPUT=y || INPUT=USB_STORAGE - help - Say Y here to include additional code to support the Maxtor OneTouch - USB hard drive's onetouch button. - - This code registers the button on the front of Maxtor OneTouch USB - hard drive's as an input device. An action can be associated with - this input in any keybinding software. (e.g. gnome's keyboard short- - cuts) - - If this driver is compiled as a module, it will be named ums-onetouch. - -config USB_STORAGE_KARMA - tristate "Support for Rio Karma music player" - depends on USB_STORAGE - help - Say Y here to include additional code to support the Rio Karma - USB interface. - - This code places the Rio Karma into mass storage mode, enabling - it to be mounted as an ordinary filesystem. Performing an eject - on the resulting scsi device node returns the Karma to normal - operation. - - If this driver is compiled as a module, it will be named ums-karma. - -config USB_STORAGE_CYPRESS_ATACB - tristate "SAT emulation on Cypress USB/ATA Bridge with ATACB" - depends on USB_STORAGE - ---help--- - Say Y here if you want to use SAT (ata pass through) on devices based - on the Cypress USB/ATA bridge supporting ATACB. This will allow you - to use tools to tune and monitor your drive (like hdparm or smartctl). - - If you say no here your device will still work with the standard usb - mass storage class. - - If this driver is compiled as a module, it will be named ums-cypress. - -config USB_STORAGE_ENE_UB6250 - tristate "USB ENE card reader support" - depends on SCSI - depends on USB_STORAGE - ---help--- - Say Y here if you wish to control a ENE SD/MS Card reader. - Note that this driver does not support SM cards. - - This option depends on 'SCSI' support being enabled, but you - probably also need 'SCSI device support: SCSI disk support' - (BLK_DEV_SD) for most USB storage devices. - - To compile this driver as a module, choose M here: the - module will be called ums-eneub6250. - -config USB_UAS - tristate "USB Attached SCSI" - depends on SCSI && USB_STORAGE - help - The USB Attached SCSI protocol is supported by some USB - storage devices. It permits higher performance by supporting - multiple outstanding commands. - - If you don't know whether you have a UAS device, it is safe to - say 'Y' or 'M' here and the kernel will use the right driver. - - If you compile this driver as a module, it will be named uas. diff --git a/src/linux/drivers/usb/usbip/Kconfig b/src/linux/drivers/usb/usbip/Kconfig deleted file mode 100644 index eeefa29..0000000 --- a/src/linux/drivers/usb/usbip/Kconfig +++ /dev/null @@ -1,74 +0,0 @@ -config USBIP_CORE - tristate "USB/IP support" - depends on NET - select USB_COMMON - ---help--- - This enables pushing USB packets over IP to allow remote - machines direct access to USB devices. It provides the - USB/IP core that is required by both drivers. - - For more details, and to get the userspace utility - programs, please see . - - To compile this as a module, choose M here: the module will - be called usbip-core. - - If unsure, say N. - -config USBIP_VHCI_HCD - tristate "VHCI hcd" - depends on USBIP_CORE && USB - ---help--- - This enables the USB/IP virtual host controller driver, - which is run on the remote machine. - - To compile this driver as a module, choose M here: the - module will be called vhci-hcd. - -config USBIP_VHCI_HC_PORTS - int "Number of ports per USB/IP virtual host controller" - range 1 31 - default 8 - depends on USBIP_VHCI_HCD - ---help--- - To increase number of ports available for USB/IP virtual - host controller driver, this defines number of ports per - USB/IP virtual host controller. - -config USBIP_VHCI_NR_HCS - int "Number of USB/IP virtual host controllers" - range 1 128 - default 1 - depends on USBIP_VHCI_HCD - ---help--- - To increase number of ports available for USB/IP virtual - host controller driver, this defines number of USB/IP - virtual host controllers as if adding physical host - controllers. - -config USBIP_HOST - tristate "Host driver" - depends on USBIP_CORE && USB - ---help--- - This enables the USB/IP host driver, which is run on the - machine that is sharing the USB devices. - - To compile this driver as a module, choose M here: the - module will be called usbip-host. - -config USBIP_VUDC - tristate "VUDC driver" - depends on USBIP_CORE && USB_GADGET - ---help--- - This enables the USB/IP virtual USB device controller - driver, which is run on the host machine, allowing the - machine itself to act as a device. - - To compile this driver as a module, choose M here: the - module will be called usbip-vudc. - -config USBIP_DEBUG - bool "Debug messages for USB/IP" - depends on USBIP_CORE - ---help--- - This enables the debug messages from the USB/IP drivers. diff --git a/src/linux/drivers/usb/wusbcore/Kconfig b/src/linux/drivers/usb/wusbcore/Kconfig deleted file mode 100644 index 348de1d..0000000 --- a/src/linux/drivers/usb/wusbcore/Kconfig +++ /dev/null @@ -1,39 +0,0 @@ -# -# Wireless USB Core configuration -# -config USB_WUSB - tristate "Enable Wireless USB extensions" - depends on UWB - select CRYPTO - select CRYPTO_BLKCIPHER - select CRYPTO_CBC - select CRYPTO_MANAGER - select CRYPTO_AES - help - Enable the host-side support for Wireless USB. - - To compile this support select Y (built in). It is safe to - select even if you don't have the hardware. - -config USB_WUSB_CBAF - tristate "Support WUSB Cable Based Association (CBA)" - depends on USB - help - Some WUSB devices support Cable Based Association. It's used to - enable the secure communication between the host and the - device. - - Enable this option if your WUSB device must to be connected - via wired USB before establishing a wireless link. - - It is safe to select even if you don't have a compatible - hardware. - -config USB_WUSB_CBAF_DEBUG - bool "Enable CBA debug messages" - depends on USB_WUSB_CBAF - help - Say Y here if you want the CBA to produce a bunch of debug messages - to the system log. Select this if you are having a problem with - CBA support and want to see more of what is going on. - diff --git a/src/linux/drivers/uwb/Kconfig b/src/linux/drivers/uwb/Kconfig deleted file mode 100644 index c204094..0000000 --- a/src/linux/drivers/uwb/Kconfig +++ /dev/null @@ -1,70 +0,0 @@ -# -# UWB device configuration -# - -menuconfig UWB - tristate "Ultra Wideband devices" - default n - help - UWB is a high-bandwidth, low-power, point-to-point radio - technology using a wide spectrum (3.1-10.6GHz). It is - optimized for in-room use (480Mbps at 2 meters, 110Mbps at - 10m). It serves as the transport layer for other protocols, - such as Wireless USB (WUSB). - - The topology is peer to peer; however, higher level - protocols (such as WUSB) might impose a master/slave - relationship. - - Say Y here if your computer has UWB radio controllers (USB or PCI) - based. You will need to enable the radio controllers - below. It is ok to select all of them, no harm done. - - For more help check the UWB and WUSB related files in - . - - To compile the UWB stack as a module, choose M here. - -if UWB - -config UWB_HWA - tristate "UWB Radio Control driver for WUSB-compliant USB dongles (HWA)" - depends on USB - help - This driver enables the radio controller for HWA USB - devices. HWA stands for Host Wire Adapter, and it is a UWB - Radio Controller connected to your system via USB. Most of - them come with a Wireless USB host controller also. - - To compile this driver select Y (built in) or M (module). It - is safe to select any even if you do not have the hardware. - -config UWB_WHCI - tristate "UWB Radio Control driver for WHCI-compliant cards" - depends on PCI - help - This driver enables the radio controller for WHCI cards. - - WHCI is a specification developed by Intel - (http://www.intel.com/technology/comms/wusb/whci.htm) much - in the spirit of USB's EHCI, but for UWB and Wireless USB - radio/host controllers connected via memory mapping (eg: - PCI). Most of these cards come also with a Wireless USB host - controller. - - To compile this driver select Y (built in) or M (module). It - is safe to select any even if you do not have the hardware. - -config UWB_I1480U - tristate "Support for Intel Wireless UWB Link 1480 HWA" - depends on UWB_HWA - select FW_LOADER - help - This driver enables support for the i1480 when connected via - USB. It consists of a firmware uploader that will enable it - to behave as an HWA device. - - To compile this driver select Y (built in) or M (module). It - is safe to select any even if you do not have the hardware. - -endif # UWB diff --git a/src/linux/drivers/vfio/Kconfig b/src/linux/drivers/vfio/Kconfig deleted file mode 100644 index da6e2ce..0000000 --- a/src/linux/drivers/vfio/Kconfig +++ /dev/null @@ -1,51 +0,0 @@ -config VFIO_IOMMU_TYPE1 - tristate - depends on VFIO - default n - -config VFIO_IOMMU_SPAPR_TCE - tristate - depends on VFIO && SPAPR_TCE_IOMMU - default n - -config VFIO_SPAPR_EEH - tristate - depends on EEH && VFIO_IOMMU_SPAPR_TCE - default n - -config VFIO_VIRQFD - tristate - depends on VFIO && EVENTFD - default n - -menuconfig VFIO - tristate "VFIO Non-Privileged userspace driver framework" - depends on IOMMU_API - select VFIO_IOMMU_TYPE1 if (X86 || S390 || ARM_SMMU || ARM_SMMU_V3) - select VFIO_IOMMU_SPAPR_TCE if (PPC_POWERNV || PPC_PSERIES) - select VFIO_SPAPR_EEH if (PPC_POWERNV || PPC_PSERIES) - select ANON_INODES - help - VFIO provides a framework for secure userspace device drivers. - See Documentation/vfio.txt for more details. - - If you don't know what to do here, say N. - -menuconfig VFIO_NOIOMMU - bool "VFIO No-IOMMU support" - depends on VFIO - help - VFIO is built on the ability to isolate devices using the IOMMU. - Only with an IOMMU can userspace access to DMA capable devices be - considered secure. VFIO No-IOMMU mode enables IOMMU groups for - devices without IOMMU backing for the purpose of re-using the VFIO - infrastructure in a non-secure mode. Use of this mode will result - in an unsupportable kernel and will therefore taint the kernel. - Device assignment to virtual machines is also not possible with - this mode since there is no IOMMU to provide DMA translation. - - If you don't know what to do here, say N. - -source "drivers/vfio/pci/Kconfig" -source "drivers/vfio/platform/Kconfig" -source "virt/lib/Kconfig" diff --git a/src/linux/drivers/vfio/pci/Kconfig b/src/linux/drivers/vfio/pci/Kconfig deleted file mode 100644 index 24ee260..0000000 --- a/src/linux/drivers/vfio/pci/Kconfig +++ /dev/null @@ -1,32 +0,0 @@ -config VFIO_PCI - tristate "VFIO support for PCI devices" - depends on VFIO && PCI && EVENTFD - select VFIO_VIRQFD - select IRQ_BYPASS_MANAGER - help - Support for the PCI VFIO bus driver. This is required to make - use of PCI drivers using the VFIO framework. - - If you don't know what to do here, say N. - -config VFIO_PCI_VGA - bool "VFIO PCI support for VGA devices" - depends on VFIO_PCI && X86 && VGA_ARB - help - Support for VGA extension to VFIO PCI. This exposes an additional - region on VGA devices for accessing legacy VGA addresses used by - BIOS and generic video drivers. - - If you don't know what to do here, say N. - -config VFIO_PCI_MMAP - depends on VFIO_PCI - def_bool y if !S390 - -config VFIO_PCI_INTX - depends on VFIO_PCI - def_bool y if !S390 - -config VFIO_PCI_IGD - depends on VFIO_PCI - def_bool y if X86 diff --git a/src/linux/drivers/vfio/platform/Kconfig b/src/linux/drivers/vfio/platform/Kconfig deleted file mode 100644 index bb30128..0000000 --- a/src/linux/drivers/vfio/platform/Kconfig +++ /dev/null @@ -1,22 +0,0 @@ -config VFIO_PLATFORM - tristate "VFIO support for platform devices" - depends on VFIO && EVENTFD && (ARM || ARM64) - select VFIO_VIRQFD - help - Support for platform devices with VFIO. This is required to make - use of platform devices present on the system using the VFIO - framework. - - If you don't know what to do here, say N. - -config VFIO_AMBA - tristate "VFIO support for AMBA devices" - depends on VFIO_PLATFORM && ARM_AMBA - help - Support for ARM AMBA devices with VFIO. This is required to make - use of ARM AMBA devices present on the system using the VFIO - framework. - - If you don't know what to do here, say N. - -source "drivers/vfio/platform/reset/Kconfig" diff --git a/src/linux/drivers/vfio/platform/reset/Kconfig b/src/linux/drivers/vfio/platform/reset/Kconfig deleted file mode 100644 index 70cccc5..0000000 --- a/src/linux/drivers/vfio/platform/reset/Kconfig +++ /dev/null @@ -1,15 +0,0 @@ -config VFIO_PLATFORM_CALXEDAXGMAC_RESET - tristate "VFIO support for calxeda xgmac reset" - depends on VFIO_PLATFORM - help - Enables the VFIO platform driver to handle reset for Calxeda xgmac - - If you don't know what to do here, say N. - -config VFIO_PLATFORM_AMDXGBE_RESET - tristate "VFIO support for AMD XGBE reset" - depends on VFIO_PLATFORM - help - Enables the VFIO platform driver to handle reset for AMD XGBE - - If you don't know what to do here, say N. diff --git a/src/linux/drivers/vhost/Kconfig.vringh b/src/linux/drivers/vhost/Kconfig.vringh deleted file mode 100644 index 6a4490c..0000000 --- a/src/linux/drivers/vhost/Kconfig.vringh +++ /dev/null @@ -1,5 +0,0 @@ -config VHOST_RING - tristate - ---help--- - This option is selected by any driver which needs to access - the host side of a virtio ring. diff --git a/src/linux/drivers/video/Kconfig b/src/linux/drivers/video/Kconfig deleted file mode 100644 index 3c20af9..0000000 --- a/src/linux/drivers/video/Kconfig +++ /dev/null @@ -1,49 +0,0 @@ -# -# Video configuration -# - -menu "Graphics support" - depends on HAS_IOMEM - -config HAVE_FB_ATMEL - bool - -config SH_LCD_MIPI_DSI - bool - -source "drivers/char/agp/Kconfig" - -source "drivers/gpu/vga/Kconfig" - -source "drivers/gpu/host1x/Kconfig" -source "drivers/gpu/ipu-v3/Kconfig" - -source "drivers/gpu/drm/Kconfig" - -menu "Frame buffer Devices" -source "drivers/video/fbdev/Kconfig" -endmenu - -source "drivers/video/backlight/Kconfig" - -config VGASTATE - tristate - default n - -config VIDEOMODE_HELPERS - bool - -config HDMI - bool - -if VT - source "drivers/video/console/Kconfig" -endif - -if FB || SGI_NEWPORT_CONSOLE - source "drivers/video/logo/Kconfig" - -endif - - -endmenu diff --git a/src/linux/drivers/video/Makefile b/src/linux/drivers/video/Makefile deleted file mode 100644 index 9ad3c17..0000000 --- a/src/linux/drivers/video/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -obj-$(CONFIG_VGASTATE) += vgastate.o -obj-$(CONFIG_HDMI) += hdmi.o - -obj-$(CONFIG_VT) += console/ -obj-$(CONFIG_LOGO) += logo/ -obj-y += backlight/ - -obj-y += fbdev/ - -obj-$(CONFIG_VIDEOMODE_HELPERS) += display_timing.o videomode.o -ifeq ($(CONFIG_OF),y) -obj-$(CONFIG_VIDEOMODE_HELPERS) += of_display_timing.o of_videomode.o -endif diff --git a/src/linux/drivers/video/backlight/Kconfig b/src/linux/drivers/video/backlight/Kconfig deleted file mode 100644 index 5ffa4b4..0000000 --- a/src/linux/drivers/video/backlight/Kconfig +++ /dev/null @@ -1,465 +0,0 @@ -# -# Backlight & LCD drivers configuration -# - -menuconfig BACKLIGHT_LCD_SUPPORT - bool "Backlight & LCD device support" - help - Enable this to be able to choose the drivers for controlling the - backlight and the LCD panel on some platforms, for example on PDAs. - -if BACKLIGHT_LCD_SUPPORT - -# -# LCD -# -config LCD_CLASS_DEVICE - tristate "Lowlevel LCD controls" - default m - help - This framework adds support for low-level control of LCD. - Some framebuffer devices connect to platform-specific LCD modules - in order to have a platform-specific way to control the flat panel - (contrast and applying power to the LCD (not to the backlight!)). - - To have support for your specific LCD panel you will have to - select the proper drivers which depend on this option. - -if LCD_CLASS_DEVICE - -config LCD_CORGI - tristate "LCD Panel support for SHARP corgi/spitz model" - depends on SPI_MASTER && PXA_SHARPSL && BACKLIGHT_CLASS_DEVICE - help - Say y here to support the LCD panels usually found on SHARP - corgi (C7x0) and spitz (Cxx00) models. - -config LCD_L4F00242T03 - tristate "Epson L4F00242T03 LCD" - depends on SPI_MASTER - depends on GPIOLIB || COMPILE_TEST - help - SPI driver for Epson L4F00242T03. This provides basic support - for init and powering the LCD up/down through a sysfs interface. - -config LCD_LMS283GF05 - tristate "Samsung LMS283GF05 LCD" - depends on SPI_MASTER - depends on GPIOLIB || COMPILE_TEST - help - SPI driver for Samsung LMS283GF05. This provides basic support - for powering the LCD up/down through a sysfs interface. - -config LCD_LTV350QV - tristate "Samsung LTV350QV LCD Panel" - depends on SPI_MASTER - help - If you have a Samsung LTV350QV LCD panel, say y to include a - power control driver for it. The panel starts up in power - off state, so you need this driver in order to see any - output. - - The LTV350QV panel is present on all ATSTK1000 boards. - -config LCD_ILI922X - tristate "ILI Technology ILI9221/ILI9222 support" - depends on SPI - help - If you have a panel based on the ILI9221/9222 controller - chip then say y to include a driver for it. - -config LCD_ILI9320 - tristate "ILI Technology ILI9320 controller support" - depends on SPI - help - If you have a panel based on the ILI9320 controller chip - then say y to include a power driver for it. - -config LCD_TDO24M - tristate "Toppoly TDO24M and TDO35S LCD Panels support" - depends on SPI_MASTER - help - If you have a Toppoly TDO24M/TDO35S series LCD panel, say y here to - include the support for it. - -config LCD_VGG2432A4 - tristate "VGG2432A4 LCM device support" - depends on SPI_MASTER - select LCD_ILI9320 - help - If you have a VGG2432A4 panel based on the ILI9320 controller chip - then say y to include a power driver for it. - -config LCD_PLATFORM - tristate "Platform LCD controls" - help - This driver provides a platform-device registered LCD power - control interface. - -config LCD_TOSA - tristate "Sharp SL-6000 LCD Driver" - depends on I2C && SPI && MACH_TOSA - help - If you have an Sharp SL-6000 Zaurus say Y to enable a driver - for its LCD. - -config LCD_HP700 - tristate "HP Jornada 700 series LCD Driver" - depends on SA1100_JORNADA720_SSP && !PREEMPT - default y - help - If you have an HP Jornada 700 series handheld (710/720/728) - say Y to enable LCD control driver. - -config LCD_S6E63M0 - tristate "S6E63M0 AMOLED LCD Driver" - depends on SPI && BACKLIGHT_CLASS_DEVICE - default n - help - If you have an S6E63M0 LCD Panel, say Y to enable its - LCD control driver. - -config LCD_LD9040 - tristate "LD9040 AMOLED LCD Driver" - depends on SPI && BACKLIGHT_CLASS_DEVICE - default n - help - If you have an LD9040 Panel, say Y to enable its - control driver. - -config LCD_AMS369FG06 - tristate "AMS369FG06 AMOLED LCD Driver" - depends on SPI && BACKLIGHT_CLASS_DEVICE - default n - help - If you have an AMS369FG06 AMOLED Panel, say Y to enable its - LCD control driver. - -config LCD_LMS501KF03 - tristate "LMS501KF03 LCD Driver" - depends on SPI - default n - help - If you have an LMS501KF03 LCD Panel, say Y to enable its - LCD control driver. - -config LCD_HX8357 - tristate "Himax HX-8357 LCD Driver" - depends on SPI - help - If you have a HX-8357 LCD panel, say Y to enable its LCD control - driver. - -endif # LCD_CLASS_DEVICE - -# -# Backlight -# -config BACKLIGHT_CLASS_DEVICE - tristate "Lowlevel Backlight controls" - default m - help - This framework adds support for low-level control of the LCD - backlight. This includes support for brightness and power. - - To have support for your specific LCD panel you will have to - select the proper drivers which depend on this option. - -if BACKLIGHT_CLASS_DEVICE - -config BACKLIGHT_ATMEL_LCDC - bool "Atmel LCDC Contrast-as-Backlight control" - depends on FB_ATMEL - help - This provides a backlight control internal to the Atmel LCDC - driver. If the LCD "contrast control" on your board is wired - so it controls the backlight brightness, select this option to - export this as a PWM-based backlight control. - - If in doubt, it's safe to enable this option; it doesn't kick - in unless the board's description says it's wired that way. - -config BACKLIGHT_EP93XX - tristate "Cirrus EP93xx Backlight Driver" - depends on FB_EP93XX - help - If you have a LCD backlight connected to the BRIGHT output of - the EP93xx, say Y here to enable this driver. - - To compile this driver as a module, choose M here: the module will - be called ep93xx_bl. - -config BACKLIGHT_GENERIC - tristate "Generic (aka Sharp Corgi) Backlight Driver" - default y - help - Say y to enable the generic platform backlight driver previously - known as the Corgi backlight driver. If you have a Sharp Zaurus - SL-C7xx, SL-Cxx00 or SL-6000x say y. - -config BACKLIGHT_IPAQ_MICRO - tristate "iPAQ microcontroller backlight driver" - depends on MFD_IPAQ_MICRO - default y - help - Say y to enable the backlight driver for Compaq iPAQ handheld - computers. Say yes if you have one of the h3100/h3600/h3700 - machines. - -config BACKLIGHT_LM3533 - tristate "Backlight Driver for LM3533" - depends on BACKLIGHT_CLASS_DEVICE - depends on MFD_LM3533 - help - Say Y to enable the backlight driver for National Semiconductor / TI - LM3533 Lighting Power chips. - - The backlights can be controlled directly, through PWM input, or by - the ambient-light-sensor interface. The chip supports 256 brightness - levels. - -config BACKLIGHT_LOCOMO - tristate "Sharp LOCOMO LCD/Backlight Driver" - depends on SHARP_LOCOMO - default y - help - If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to - enable the LCD/backlight driver. - -config BACKLIGHT_OMAP1 - tristate "OMAP1 PWL-based LCD Backlight" - depends on ARCH_OMAP1 - default y - help - This driver controls the LCD backlight level and power for - the PWL module of OMAP1 processors. Say Y if your board - uses this hardware. - -config BACKLIGHT_HP680 - tristate "HP Jornada 680 Backlight Driver" - depends on SH_HP6XX - default y - help - If you have a HP Jornada 680, say y to enable the - backlight driver. - -config BACKLIGHT_HP700 - tristate "HP Jornada 700 series Backlight Driver" - depends on SA1100_JORNADA720_SSP && !PREEMPT - default y - help - If you have an HP Jornada 700 series, - say Y to include backlight control driver. - -config BACKLIGHT_CARILLO_RANCH - tristate "Intel Carillo Ranch Backlight Driver" - depends on LCD_CLASS_DEVICE && PCI && X86 && FB_LE80578 - help - If you have a Intel LE80578 (Carillo Ranch) say Y to enable the - backlight driver. - -config BACKLIGHT_PWM - tristate "Generic PWM based Backlight Driver" - depends on PWM - help - If you have a LCD backlight adjustable by PWM, say Y to enable - this driver. - -config BACKLIGHT_DA903X - tristate "Backlight Driver for DA9030/DA9034 using WLED" - depends on PMIC_DA903X - help - If you have a LCD backlight connected to the WLED output of DA9030 - or DA9034 WLED output, say Y here to enable this driver. - -config BACKLIGHT_DA9052 - tristate "Dialog DA9052/DA9053 WLED" - depends on PMIC_DA9052 - help - Enable the Backlight Driver for DA9052-BC and DA9053-AA/Bx PMICs. - -config BACKLIGHT_MAX8925 - tristate "Backlight driver for MAX8925" - depends on MFD_MAX8925 - help - If you have a LCD backlight connected to the WLED output of MAX8925 - WLED output, say Y here to enable this driver. - -config BACKLIGHT_APPLE - tristate "Apple Backlight Driver" - depends on X86 && ACPI - help - If you have an Intel-based Apple say Y to enable a driver for its - backlight. - -config BACKLIGHT_TOSA - tristate "Sharp SL-6000 Backlight Driver" - depends on I2C && MACH_TOSA && LCD_TOSA - help - If you have an Sharp SL-6000 Zaurus say Y to enable a driver - for its backlight - -config BACKLIGHT_PM8941_WLED - tristate "Qualcomm PM8941 WLED Driver" - select REGMAP - help - If you have the Qualcomm PM8941, say Y to enable a driver for the - WLED block. - -config BACKLIGHT_SAHARA - tristate "Tabletkiosk Sahara Touch-iT Backlight Driver" - depends on X86 - help - If you have a Tabletkiosk Sahara Touch-iT, say y to enable the - backlight driver. - -config BACKLIGHT_WM831X - tristate "WM831x PMIC Backlight Driver" - depends on MFD_WM831X - help - If you have a backlight driven by the ISINK and DCDC of a - WM831x PMIC say y to enable the backlight driver for it. - -config BACKLIGHT_ADP5520 - tristate "Backlight Driver for ADP5520/ADP5501 using WLED" - depends on PMIC_ADP5520 - help - If you have a LCD backlight connected to the BST/BL_SNK output of - ADP5520 or ADP5501, say Y here to enable this driver. - - To compile this driver as a module, choose M here: the module will - be called adp5520_bl. - -config BACKLIGHT_ADP8860 - tristate "Backlight Driver for ADP8860/ADP8861/ADP8863 using WLED" - depends on BACKLIGHT_CLASS_DEVICE && I2C - select NEW_LEDS - select LEDS_CLASS - help - If you have a LCD backlight connected to the ADP8860, ADP8861 or - ADP8863 say Y here to enable this driver. - - To compile this driver as a module, choose M here: the module will - be called adp8860_bl. - -config BACKLIGHT_ADP8870 - tristate "Backlight Driver for ADP8870 using WLED" - depends on BACKLIGHT_CLASS_DEVICE && I2C - select NEW_LEDS - select LEDS_CLASS - help - If you have a LCD backlight connected to the ADP8870, - say Y here to enable this driver. - - To compile this driver as a module, choose M here: the module will - be called adp8870_bl. - -config BACKLIGHT_88PM860X - tristate "Backlight Driver for 88PM8606 using WLED" - depends on MFD_88PM860X - help - Say Y to enable the backlight driver for Marvell 88PM8606. - -config BACKLIGHT_PCF50633 - tristate "Backlight driver for NXP PCF50633 MFD" - depends on BACKLIGHT_CLASS_DEVICE && MFD_PCF50633 - help - If you have a backlight driven by a NXP PCF50633 MFD, say Y here to - enable its driver. - -config BACKLIGHT_AAT2870 - tristate "AnalogicTech AAT2870 Backlight" - depends on BACKLIGHT_CLASS_DEVICE && MFD_AAT2870_CORE - help - If you have a AnalogicTech AAT2870 say Y to enable the - backlight driver. - -config BACKLIGHT_LM3630A - tristate "Backlight Driver for LM3630A" - depends on BACKLIGHT_CLASS_DEVICE && I2C && PWM - select REGMAP_I2C - help - This supports TI LM3630A Backlight Driver - -config BACKLIGHT_LM3639 - tristate "Backlight Driver for LM3639" - depends on BACKLIGHT_CLASS_DEVICE && I2C - select REGMAP_I2C - select NEW_LEDS - select LEDS_CLASS - help - This supports TI LM3639 Backlight + 1.5A Flash LED Driver - -config BACKLIGHT_LP855X - tristate "Backlight driver for TI LP855X" - depends on BACKLIGHT_CLASS_DEVICE && I2C && PWM - help - This supports TI LP8550, LP8551, LP8552, LP8553, LP8555, LP8556 and - LP8557 backlight driver. - -config BACKLIGHT_LP8788 - tristate "Backlight driver for TI LP8788 MFD" - depends on BACKLIGHT_CLASS_DEVICE && MFD_LP8788 && PWM - help - This supports TI LP8788 backlight driver. - -config BACKLIGHT_OT200 - tristate "Backlight driver for ot200 visualisation device" - depends on BACKLIGHT_CLASS_DEVICE && CS5535_MFGPT && GPIO_CS5535 - help - To compile this driver as a module, choose M here: the module will be - called ot200_bl. - -config BACKLIGHT_PANDORA - tristate "Backlight driver for Pandora console" - depends on TWL4030_CORE - help - If you have a Pandora console, say Y to enable the - backlight driver. - -config BACKLIGHT_SKY81452 - tristate "Backlight driver for SKY81452" - depends on BACKLIGHT_CLASS_DEVICE && MFD_SKY81452 - help - If you have a Skyworks SKY81452, say Y to enable the - backlight driver. - - To compile this driver as a module, choose M here: the module will - be called sky81452-backlight - -config BACKLIGHT_TPS65217 - tristate "TPS65217 Backlight" - depends on BACKLIGHT_CLASS_DEVICE && MFD_TPS65217 - help - If you have a Texas Instruments TPS65217 say Y to enable the - backlight driver. - -config BACKLIGHT_AS3711 - tristate "AS3711 Backlight" - depends on BACKLIGHT_CLASS_DEVICE && MFD_AS3711 - help - If you have an Austrian Microsystems AS3711 say Y to enable the - backlight driver. - -config BACKLIGHT_GPIO - tristate "Generic GPIO based Backlight Driver" - depends on GPIOLIB || COMPILE_TEST - help - If you have a LCD backlight adjustable by GPIO, say Y to enable - this driver. - -config BACKLIGHT_LV5207LP - tristate "Sanyo LV5207LP Backlight" - depends on I2C - help - If you have a Sanyo LV5207LP say Y to enable the backlight driver. - -config BACKLIGHT_BD6107 - tristate "Rohm BD6107 Backlight" - depends on I2C - help - If you have a Rohm BD6107 say Y to enable the backlight driver. - -endif # BACKLIGHT_CLASS_DEVICE - -endif # BACKLIGHT_LCD_SUPPORT diff --git a/src/linux/drivers/video/backlight/Makefile b/src/linux/drivers/video/backlight/Makefile deleted file mode 100644 index 16ec534..0000000 --- a/src/linux/drivers/video/backlight/Makefile +++ /dev/null @@ -1,57 +0,0 @@ -# Backlight & LCD drivers - -obj-$(CONFIG_LCD_AMS369FG06) += ams369fg06.o -obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o -obj-$(CONFIG_LCD_CORGI) += corgi_lcd.o -obj-$(CONFIG_LCD_HP700) += jornada720_lcd.o -obj-$(CONFIG_LCD_HX8357) += hx8357.o -obj-$(CONFIG_LCD_ILI922X) += ili922x.o -obj-$(CONFIG_LCD_ILI9320) += ili9320.o -obj-$(CONFIG_LCD_L4F00242T03) += l4f00242t03.o -obj-$(CONFIG_LCD_LD9040) += ld9040.o -obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o -obj-$(CONFIG_LCD_LMS501KF03) += lms501kf03.o -obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o -obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o -obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o -obj-$(CONFIG_LCD_TDO24M) += tdo24m.o -obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o -obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o - -obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o -obj-$(CONFIG_BACKLIGHT_AAT2870) += aat2870_bl.o -obj-$(CONFIG_BACKLIGHT_ADP5520) += adp5520_bl.o -obj-$(CONFIG_BACKLIGHT_ADP8860) += adp8860_bl.o -obj-$(CONFIG_BACKLIGHT_ADP8870) += adp8870_bl.o -obj-$(CONFIG_BACKLIGHT_APPLE) += apple_bl.o -obj-$(CONFIG_BACKLIGHT_AS3711) += as3711_bl.o -obj-$(CONFIG_BACKLIGHT_BD6107) += bd6107.o -obj-$(CONFIG_BACKLIGHT_CARILLO_RANCH) += cr_bllcd.o -obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o -obj-$(CONFIG_BACKLIGHT_DA903X) += da903x_bl.o -obj-$(CONFIG_BACKLIGHT_DA9052) += da9052_bl.o -obj-$(CONFIG_BACKLIGHT_EP93XX) += ep93xx_bl.o -obj-$(CONFIG_BACKLIGHT_GENERIC) += generic_bl.o -obj-$(CONFIG_BACKLIGHT_GPIO) += gpio_backlight.o -obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o -obj-$(CONFIG_BACKLIGHT_HP700) += jornada720_bl.o -obj-$(CONFIG_BACKLIGHT_IPAQ_MICRO) += ipaq_micro_bl.o -obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o -obj-$(CONFIG_BACKLIGHT_LM3630A) += lm3630a_bl.o -obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o -obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o -obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o -obj-$(CONFIG_BACKLIGHT_LP8788) += lp8788_bl.o -obj-$(CONFIG_BACKLIGHT_LV5207LP) += lv5207lp.o -obj-$(CONFIG_BACKLIGHT_MAX8925) += max8925_bl.o -obj-$(CONFIG_BACKLIGHT_OMAP1) += omap1_bl.o -obj-$(CONFIG_BACKLIGHT_OT200) += ot200_bl.o -obj-$(CONFIG_BACKLIGHT_PANDORA) += pandora_bl.o -obj-$(CONFIG_BACKLIGHT_PCF50633) += pcf50633-backlight.o -obj-$(CONFIG_BACKLIGHT_PM8941_WLED) += pm8941-wled.o -obj-$(CONFIG_BACKLIGHT_PWM) += pwm_bl.o -obj-$(CONFIG_BACKLIGHT_SAHARA) += kb3886_bl.o -obj-$(CONFIG_BACKLIGHT_SKY81452) += sky81452-backlight.o -obj-$(CONFIG_BACKLIGHT_TOSA) += tosa_bl.o -obj-$(CONFIG_BACKLIGHT_TPS65217) += tps65217_bl.o -obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o diff --git a/src/linux/drivers/video/console/Kconfig b/src/linux/drivers/video/console/Kconfig deleted file mode 100644 index 38da6e2..0000000 --- a/src/linux/drivers/video/console/Kconfig +++ /dev/null @@ -1,144 +0,0 @@ -# -# Video configuration -# - -menu "Console display driver support" - -config VGA_CONSOLE - bool "VGA text console" if EXPERT || !X86 - depends on !4xx && !8xx && !SPARC && !M68K && !PARISC && !FRV && \ - !SUPERH && !BLACKFIN && !AVR32 && !MN10300 && !CRIS && \ - (!ARM || ARCH_FOOTBRIDGE || ARCH_INTEGRATOR || ARCH_NETWINDER) && \ - !ARM64 && !ARC && !MICROBLAZE - default y - help - Saying Y here will allow you to use Linux in text mode through a - display that complies with the generic VGA standard. Virtually - everyone wants that. - - The program SVGATextMode can be used to utilize SVGA video cards to - their full potential in text mode. Download it from - . - - Say Y. - -config VGACON_SOFT_SCROLLBACK - bool "Enable Scrollback Buffer in System RAM" - depends on VGA_CONSOLE - default n - help - The scrollback buffer of the standard VGA console is located in - the VGA RAM. The size of this RAM is fixed and is quite small. - If you require a larger scrollback buffer, this can be placed in - System RAM which is dynamically allocated during initialization. - Placing the scrollback buffer in System RAM will slightly slow - down the console. - - If you want this feature, say 'Y' here and enter the amount of - RAM to allocate for this buffer. If unsure, say 'N'. - -config VGACON_SOFT_SCROLLBACK_SIZE - int "Scrollback Buffer Size (in KB)" - depends on VGACON_SOFT_SCROLLBACK - range 1 1024 - default "64" - help - Enter the amount of System RAM to allocate for the scrollback - buffer. Each 64KB will give you approximately 16 80x25 - screenfuls of scrollback buffer - -config MDA_CONSOLE - depends on !M68K && !PARISC && ISA - tristate "MDA text console (dual-headed)" - ---help--- - Say Y here if you have an old MDA or monochrome Hercules graphics - adapter in your system acting as a second head ( = video card). You - will then be able to use two monitors with your Linux system. Do not - say Y here if your MDA card is the primary card in your system; the - normal VGA driver will handle it. - - To compile this driver as a module, choose M here: the - module will be called mdacon. - - If unsure, say N. - -config SGI_NEWPORT_CONSOLE - tristate "SGI Newport Console support" - depends on SGI_IP22 - select FONT_SUPPORT - help - Say Y here if you want the console on the Newport aka XL graphics - card of your Indy. Most people say Y here. - -config DUMMY_CONSOLE - bool - depends on VGA_CONSOLE!=y || SGI_NEWPORT_CONSOLE!=y - default y - -config DUMMY_CONSOLE_COLUMNS - int "Initial number of console screen columns" - depends on DUMMY_CONSOLE && !ARM - default 160 if PARISC - default 80 - help - On PA-RISC, the default value is 160, which should fit a 1280x1024 - monitor. - Select 80 if you use a 640x480 resolution by default. - -config DUMMY_CONSOLE_ROWS - int "Initial number of console screen rows" - depends on DUMMY_CONSOLE && !ARM - default 64 if PARISC - default 25 - help - On PA-RISC, the default value is 64, which should fit a 1280x1024 - monitor. - Select 25 if you use a 640x480 resolution by default. - -config FRAMEBUFFER_CONSOLE - tristate "Framebuffer Console support" - depends on FB && !UML - select VT_HW_CONSOLE_BINDING - select CRC32 - select FONT_SUPPORT - help - Low-level framebuffer-based console driver. - -config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY - bool "Map the console to the primary display device" - depends on FRAMEBUFFER_CONSOLE - default n - ---help--- - If this option is selected, the framebuffer console will - automatically select the primary display device (if the architecture - supports this feature). Otherwise, the framebuffer console will - always select the first framebuffer driver that is loaded. The latter - is the default behavior. - - You can always override the automatic selection of the primary device - by using the fbcon=map: boot option. - - If unsure, select n. - -config FRAMEBUFFER_CONSOLE_ROTATION - bool "Framebuffer Console Rotation" - depends on FRAMEBUFFER_CONSOLE - help - Enable display rotation for the framebuffer console. This is done - in software and may be significantly slower than a normally oriented - display. Note that the rotation is done at the console level only - such that other users of the framebuffer will remain normally - oriented. - -config STI_CONSOLE - bool "STI text console" - depends on PARISC - select FONT_SUPPORT - default y - help - The STI console is the builtin display/keyboard on HP-PARISC - machines. Say Y here to build support for it into your kernel. - The alternative is to use your primary serial port as a console. - -endmenu - diff --git a/src/linux/drivers/video/fbdev/Kconfig b/src/linux/drivers/video/fbdev/Kconfig deleted file mode 100644 index 5d3b0db..0000000 --- a/src/linux/drivers/video/fbdev/Kconfig +++ /dev/null @@ -1,2492 +0,0 @@ -# -# fbdev configuration -# - -menuconfig FB - tristate "Support for frame buffer devices" - select FB_CMDLINE - select FB_NOTIFY - ---help--- - The frame buffer device provides an abstraction for the graphics - hardware. It represents the frame buffer of some video hardware and - allows application software to access the graphics hardware through - a well-defined interface, so the software doesn't need to know - anything about the low-level (hardware register) stuff. - - Frame buffer devices work identically across the different - architectures supported by Linux and make the implementation of - application programs easier and more portable; at this point, an X - server exists which uses the frame buffer device exclusively. - On several non-X86 architectures, the frame buffer device is the - only way to use the graphics hardware. - - The device is accessed through special device nodes, usually located - in the /dev directory, i.e. /dev/fb*. - - You need an utility program called fbset to make full use of frame - buffer devices. Please read - and the Framebuffer-HOWTO at - for more - information. - - Say Y here and to the driver for your graphics board below if you - are compiling a kernel for a non-x86 architecture. - - If you are compiling for the x86 architecture, you can say Y if you - want to play with it, but it is not essential. Please note that - running graphical applications that directly touch the hardware - (e.g. an accelerated X server) and that are not frame buffer - device-aware may cause unexpected results. If unsure, say N. - -config FIRMWARE_EDID - bool "Enable firmware EDID" - depends on FB - default n - ---help--- - This enables access to the EDID transferred from the firmware. - On the i386, this is from the Video BIOS. Enable this if DDC/I2C - transfers do not work for your driver and if you are using - nvidiafb, i810fb or savagefb. - - In general, choosing Y for this option is safe. If you - experience extremely long delays while booting before you get - something on your display, try setting this to N. Matrox cards in - combination with certain motherboards and monitors are known to - suffer from this problem. - -config FB_CMDLINE - bool - -config FB_NOTIFY - bool - -config FB_DDC - tristate - depends on FB - select I2C_ALGOBIT - select I2C - default n - -config FB_BOOT_VESA_SUPPORT - bool - depends on FB - default n - ---help--- - If true, at least one selected framebuffer driver can take advantage - of VESA video modes set at an early boot stage via the vga= parameter. - -config FB_CFB_FILLRECT - tristate - depends on FB - default n - ---help--- - Include the cfb_fillrect function for generic software rectangle - filling. This is used by drivers that don't provide their own - (accelerated) version. - -config FB_CFB_COPYAREA - tristate - depends on FB - default n - ---help--- - Include the cfb_copyarea function for generic software area copying. - This is used by drivers that don't provide their own (accelerated) - version. - -config FB_CFB_IMAGEBLIT - tristate - depends on FB - default n - ---help--- - Include the cfb_imageblit function for generic software image - blitting. This is used by drivers that don't provide their own - (accelerated) version. - -config FB_CFB_REV_PIXELS_IN_BYTE - bool - depends on FB - default n - ---help--- - Allow generic frame-buffer functions to work on displays with 1, 2 - and 4 bits per pixel depths which has opposite order of pixels in - byte order to bytes in long order. - -config FB_SYS_FILLRECT - tristate - depends on FB - default n - ---help--- - Include the sys_fillrect function for generic software rectangle - filling. This is used by drivers that don't provide their own - (accelerated) version and the framebuffer is in system RAM. - -config FB_SYS_COPYAREA - tristate - depends on FB - default n - ---help--- - Include the sys_copyarea function for generic software area copying. - This is used by drivers that don't provide their own (accelerated) - version and the framebuffer is in system RAM. - -config FB_SYS_IMAGEBLIT - tristate - depends on FB - default n - ---help--- - Include the sys_imageblit function for generic software image - blitting. This is used by drivers that don't provide their own - (accelerated) version and the framebuffer is in system RAM. - -menuconfig FB_FOREIGN_ENDIAN - bool "Framebuffer foreign endianness support" - depends on FB - ---help--- - This menu will let you enable support for the framebuffers with - non-native endianness (e.g. Little-Endian framebuffer on a - Big-Endian machine). Most probably you don't have such hardware, - so it's safe to say "n" here. - -choice - prompt "Choice endianness support" - depends on FB_FOREIGN_ENDIAN - -config FB_BOTH_ENDIAN - bool "Support for Big- and Little-Endian framebuffers" - -config FB_BIG_ENDIAN - bool "Support for Big-Endian framebuffers only" - -config FB_LITTLE_ENDIAN - bool "Support for Little-Endian framebuffers only" - -endchoice - -config FB_SYS_FOPS - tristate - depends on FB - default n - -config FB_DEFERRED_IO - bool - depends on FB - -config FB_HECUBA - tristate - depends on FB - depends on FB_DEFERRED_IO - -config FB_SVGALIB - tristate - depends on FB - default n - ---help--- - Common utility functions useful to fbdev drivers of VGA-based - cards. - -config FB_MACMODES - tristate - depends on FB - default n - -config FB_BACKLIGHT - bool - depends on FB - select BACKLIGHT_LCD_SUPPORT - select BACKLIGHT_CLASS_DEVICE - default n - -config FB_MODE_HELPERS - bool "Enable Video Mode Handling Helpers" - depends on FB - default n - ---help--- - This enables functions for handling video modes using the - Generalized Timing Formula and the EDID parser. A few drivers rely - on this feature such as the radeonfb, rivafb, and the i810fb. If - your driver does not take advantage of this feature, choosing Y will - just increase the kernel size by about 5K. - -config FB_TILEBLITTING - bool "Enable Tile Blitting Support" - depends on FB - default n - ---help--- - This enables tile blitting. Tile blitting is a drawing technique - where the screen is divided into rectangular sections (tiles), whereas - the standard blitting divides the screen into pixels. Because the - default drawing element is a tile, drawing functions will be passed - parameters in terms of number of tiles instead of number of pixels. - For example, to draw a single character, instead of using bitmaps, - an index to an array of bitmaps will be used. To clear or move a - rectangular section of a screen, the rectangle will be described in - terms of number of tiles in the x- and y-axis. - - This is particularly important to one driver, matroxfb. If - unsure, say N. - -comment "Frame buffer hardware drivers" - depends on FB - -config FB_GRVGA - tristate "Aeroflex Gaisler framebuffer support" - depends on FB && SPARC - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - This enables support for the SVGACTRL framebuffer in the GRLIB IP library from Aeroflex Gaisler. - -config FB_CIRRUS - tristate "Cirrus Logic support" - depends on FB && (ZORRO || PCI) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - This enables support for Cirrus Logic GD542x/543x based boards on - Amiga: SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum. - - If you have a PCI-based system, this enables support for these - chips: GD-543x, GD-544x, GD-5480. - - Please read the file . - - Say N unless you have such a graphics board or plan to get one - before you next recompile the kernel. - -config FB_PM2 - tristate "Permedia2 support" - depends on FB && ((AMIGA && BROKEN) || PCI) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for cards based on - the 3D Labs Permedia, Permedia 2 and Permedia 2V chips. - The driver was tested on the following cards: - Diamond FireGL 1000 PRO AGP - ELSA Gloria Synergy PCI - Appian Jeronimo PRO (both heads) PCI - 3DLabs Oxygen ACX aka EONtronics Picasso P2 PCI - Techsource Raptor GFX-8P (aka Sun PGX-32) on SPARC - ASK Graphic Blaster Exxtreme AGP - - To compile this driver as a module, choose M here: the - module will be called pm2fb. - -config FB_PM2_FIFO_DISCONNECT - bool "enable FIFO disconnect feature" - depends on FB_PM2 && PCI - help - Support the Permedia2 FIFO disconnect feature. - -config FB_ARMCLCD - tristate "ARM PrimeCell PL110 support" - depends on ARM || ARM64 || COMPILE_TEST - depends on FB && ARM_AMBA && HAS_IOMEM - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MODE_HELPERS if OF - select VIDEOMODE_HELPERS if OF - select BACKLIGHT_LCD_SUPPORT if OF - select BACKLIGHT_CLASS_DEVICE if OF - help - This framebuffer device driver is for the ARM PrimeCell PL110 - Colour LCD controller. ARM PrimeCells provide the building - blocks for System on a Chip devices. - - If you want to compile this as a module (=code which can be - inserted into and removed from the running kernel), say M - here and read . The module - will be called amba-clcd. - -# Helper logic selected only by the ARM Versatile platform family. -config PLAT_VERSATILE_CLCD - def_bool ARCH_VERSATILE || ARCH_REALVIEW || ARCH_VEXPRESS || ARCH_INTEGRATOR - depends on ARM - depends on FB_ARMCLCD && FB=y - select REGMAP - select MFD_SYSCON - -config FB_ACORN - bool "Acorn VIDC support" - depends on (FB = y) && ARM && ARCH_ACORN - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the Acorn VIDC graphics - hardware found in Acorn RISC PCs and other ARM-based machines. If - unsure, say N. - -config FB_CLPS711X_OLD - tristate - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - -config FB_CLPS711X - tristate "CLPS711X LCD support" - depends on FB && (ARCH_CLPS711X || COMPILE_TEST) - select FB_CLPS711X_OLD if ARCH_CLPS711X && !ARCH_MULTIPLATFORM - select BACKLIGHT_LCD_SUPPORT - select FB_MODE_HELPERS - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select LCD_CLASS_DEVICE - select VIDEOMODE_HELPERS - help - Say Y to enable the Framebuffer driver for the Cirrus Logic - CLPS711X CPUs. - -config FB_SA1100 - bool "SA-1100 LCD support" - depends on (FB = y) && ARM && ARCH_SA1100 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is a framebuffer device for the SA-1100 LCD Controller. - See for information on framebuffer - devices. - - If you plan to use the LCD display with your SA-1100 system, say - Y here. - -config FB_IMX - tristate "Freescale i.MX1/21/25/27 LCD support" - depends on FB && ARCH_MXC - select BACKLIGHT_LCD_SUPPORT - select LCD_CLASS_DEVICE - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MODE_HELPERS - select VIDEOMODE_HELPERS - -config FB_CYBER2000 - tristate "CyberPro 2000/2010/5000 support" - depends on FB && PCI && (BROKEN || !SPARC64) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This enables support for the Integraphics CyberPro 20x0 and 5000 - VGA chips used in the Rebel.com Netwinder and other machines. - Say Y if you have a NetWinder or a graphics card containing this - device, otherwise say N. - -config FB_CYBER2000_DDC - bool "DDC for CyberPro support" - depends on FB_CYBER2000 - select FB_DDC - default y - help - Say Y here if you want DDC support for your CyberPro graphics - card. This is only I2C bus support, driver does not use EDID. - -config FB_CYBER2000_I2C - bool "CyberPro 2000/2010/5000 I2C support" - depends on FB_CYBER2000 && I2C && ARCH_NETWINDER - depends on I2C=y || FB_CYBER2000=m - select I2C_ALGOBIT - help - Enable support for the I2C video decoder interface on the - Integraphics CyberPro 20x0 and 5000 VGA chips. This is used - on the Netwinder machines for the SAA7111 video capture. - -config FB_APOLLO - bool - depends on (FB = y) && APOLLO - default y - select FB_CFB_FILLRECT - select FB_CFB_IMAGEBLIT - -config FB_Q40 - bool - depends on (FB = y) && Q40 - default y - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - -config FB_AMIGA - tristate "Amiga native chipset support" - depends on FB && AMIGA - help - This is the frame buffer device driver for the builtin graphics - chipset found in Amigas. - - To compile this driver as a module, choose M here: the - module will be called amifb. - -config FB_AMIGA_OCS - bool "Amiga OCS chipset support" - depends on FB_AMIGA - help - This enables support for the original Agnus and Denise video chips, - found in the Amiga 1000 and most A500's and A2000's. If you intend - to run Linux on any of these systems, say Y; otherwise say N. - -config FB_AMIGA_ECS - bool "Amiga ECS chipset support" - depends on FB_AMIGA - help - This enables support for the Enhanced Chip Set, found in later - A500's, later A2000's, the A600, the A3000, the A3000T and CDTV. If - you intend to run Linux on any of these systems, say Y; otherwise - say N. - -config FB_AMIGA_AGA - bool "Amiga AGA chipset support" - depends on FB_AMIGA - help - This enables support for the Advanced Graphics Architecture (also - known as the AGA or AA) Chip Set, found in the A1200, A4000, A4000T - and CD32. If you intend to run Linux on any of these systems, say Y; - otherwise say N. - -config FB_FM2 - bool "Amiga FrameMaster II/Rainbow II support" - depends on (FB = y) && ZORRO - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the Amiga FrameMaster - card from BSC (exhibited 1992 but not shipped as a CBM product). - -config FB_ARC - tristate "Arc Monochrome LCD board support" - depends on FB && X86 - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - help - This enables support for the Arc Monochrome LCD board. The board - is based on the KS-108 lcd controller and is typically a matrix - of 2*n chips. This driver was tested with a 128x64 panel. This - driver supports it for use with x86 SBCs through a 16 bit GPIO - interface (8 bit data, 8 bit control). If you anticipate using - this driver, say Y or M; otherwise say N. You must specify the - GPIO IO address to be used for setting control and data. - -config FB_ATARI - bool "Atari native chipset support" - depends on (FB = y) && ATARI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the builtin graphics - chipset found in Ataris. - -config FB_OF - bool "Open Firmware frame buffer device support" - depends on (FB = y) && PPC && (!PPC_PSERIES || PCI) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MACMODES - help - Say Y if you want support with Open Firmware for your graphics - board. - -config FB_CONTROL - bool "Apple \"control\" display support" - depends on (FB = y) && PPC_PMAC && PPC32 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MACMODES - help - This driver supports a frame buffer for the graphics adapter in the - Power Macintosh 7300 and others. - -config FB_PLATINUM - bool "Apple \"platinum\" display support" - depends on (FB = y) && PPC_PMAC && PPC32 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MACMODES - help - This driver supports a frame buffer for the "platinum" graphics - adapter in some Power Macintoshes. - -config FB_VALKYRIE - bool "Apple \"valkyrie\" display support" - depends on (FB = y) && (MAC || (PPC_PMAC && PPC32)) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MACMODES - help - This driver supports a frame buffer for the "valkyrie" graphics - adapter in some Power Macintoshes. - -config FB_CT65550 - bool "Chips 65550 display support" - depends on (FB = y) && PPC32 && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the Chips & Technologies - 65550 graphics chip in PowerBooks. - -config FB_ASILIANT - bool "Asiliant (Chips) 69000 display support" - depends on (FB = y) && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the Asiliant 69030 chipset - -config FB_IMSTT - bool "IMS Twin Turbo display support" - depends on (FB = y) && PCI - select FB_CFB_IMAGEBLIT - select FB_MACMODES if PPC - help - The IMS Twin Turbo is a PCI-based frame buffer card bundled with - many Macintosh and compatible computers. - -config FB_VGA16 - tristate "VGA 16-color graphics support" - depends on FB && (X86 || PPC) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select VGASTATE - select FONT_8x16 if FRAMEBUFFER_CONSOLE - help - This is the frame buffer device driver for VGA 16 color graphic - cards. Say Y if you have such a card. - - To compile this driver as a module, choose M here: the - module will be called vga16fb. - -config FB_BF54X_LQ043 - tristate "SHARP LQ043 TFT LCD (BF548 EZKIT)" - depends on FB && (BF54x) && !BF542 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the framebuffer device driver for a SHARP LQ043T1DG01 TFT LCD - -config FB_BFIN_T350MCQB - tristate "Varitronix COG-T350MCQB TFT LCD display (BF527 EZKIT)" - depends on FB && BLACKFIN - select BFIN_GPTIMERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the framebuffer device driver for a Varitronix VL-PS-COG-T350MCQB-01 display TFT LCD - This display is a QVGA 320x240 24-bit RGB display interfaced by an 8-bit wide PPI - It uses PPI[0..7] PPI_FS1, PPI_FS2 and PPI_CLK. - -config FB_BFIN_LQ035Q1 - tristate "SHARP LQ035Q1DH02 TFT LCD" - depends on FB && BLACKFIN && SPI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select BFIN_GPTIMERS - help - This is the framebuffer device driver for a SHARP LQ035Q1DH02 TFT display found on - the Blackfin Landscape LCD EZ-Extender Card. - This display is a QVGA 320x240 18-bit RGB display interfaced by an 16-bit wide PPI - It uses PPI[0..15] PPI_FS1, PPI_FS2 and PPI_CLK. - - To compile this driver as a module, choose M here: the - module will be called bfin-lq035q1-fb. - -config FB_BF537_LQ035 - tristate "SHARP LQ035 TFT LCD (BF537 STAMP)" - depends on FB && (BF534 || BF536 || BF537) && I2C_BLACKFIN_TWI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select BFIN_GPTIMERS - help - This is the framebuffer device for a SHARP LQ035Q7DB03 TFT LCD - attached to a BF537. - - To compile this driver as a module, choose M here: the - module will be called bf537-lq035. - -config FB_BFIN_7393 - tristate "Blackfin ADV7393 Video encoder" - depends on FB && BLACKFIN - select I2C - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the framebuffer device for a ADV7393 video encoder - attached to a Blackfin on the PPI port. - If your Blackfin board has a ADV7393 select Y. - - To compile this driver as a module, choose M here: the - module will be called bfin_adv7393fb. - -choice - prompt "Video mode support" - depends on FB_BFIN_7393 - default NTSC - -config NTSC - bool 'NTSC 720x480' - -config PAL - bool 'PAL 720x576' - -config NTSC_640x480 - bool 'NTSC 640x480 (Experimental)' - -config PAL_640x480 - bool 'PAL 640x480 (Experimental)' - -config NTSC_YCBCR - bool 'NTSC 720x480 YCbCR input' - -config PAL_YCBCR - bool 'PAL 720x576 YCbCR input' - -endchoice - -choice - prompt "Size of ADV7393 frame buffer memory Single/Double Size" - depends on (FB_BFIN_7393) - default ADV7393_1XMEM - -config ADV7393_1XMEM - bool 'Single' - -config ADV7393_2XMEM - bool 'Double' -endchoice - -config FB_STI - tristate "HP STI frame buffer device support" - depends on FB && PARISC - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select STI_CONSOLE - select VT - default y - ---help--- - STI refers to the HP "Standard Text Interface" which is a set of - BIOS routines contained in a ROM chip in HP PA-RISC based machines. - Enabling this option will implement the linux framebuffer device - using calls to the STI BIOS routines for initialisation. - - If you enable this option, you will get a planar framebuffer device - /dev/fb which will work on the most common HP graphic cards of the - NGLE family, including the artist chips (in the 7xx and Bxxx series), - HCRX, HCRX24, CRX, CRX24 and VisEG series. - - It is safe to enable this option, so you should probably say "Y". - -config FB_MAC - bool "Generic Macintosh display support" - depends on (FB = y) && MAC - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MACMODES - -config FB_HP300 - bool - depends on (FB = y) && DIO - select FB_CFB_IMAGEBLIT - default y - -config FB_TGA - tristate "TGA/SFB+ framebuffer support" - depends on FB && (ALPHA || TC) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select BITREVERSE - ---help--- - This is the frame buffer device driver for generic TGA and SFB+ - graphic cards. These include DEC ZLXp-E1, -E2 and -E3 PCI cards, - also known as PBXGA-A, -B and -C, and DEC ZLX-E1, -E2 and -E3 - TURBOchannel cards, also known as PMAGD-A, -B and -C. - - Due to hardware limitations ZLX-E2 and E3 cards are not supported - for DECstation 5000/200 systems. Additionally due to firmware - limitations these cards may cause troubles with booting DECstation - 5000/240 and /260 systems, but are fully supported under Linux if - you manage to get it going. ;-) - - Say Y if you have one of those. - -config FB_UVESA - tristate "Userspace VESA VGA graphics support" - depends on FB && CONNECTOR - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MODE_HELPERS - help - This is the frame buffer driver for generic VBE 2.0 compliant - graphic cards. It can also take advantage of VBE 3.0 features, - such as refresh rate adjustment. - - This driver generally provides more features than vesafb but - requires a userspace helper application called 'v86d'. See - for more information. - - If unsure, say N. - -config FB_VESA - bool "VESA VGA graphics support" - depends on (FB = y) && X86 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_BOOT_VESA_SUPPORT - help - This is the frame buffer device driver for generic VESA 2.0 - compliant graphic cards. The older VESA 1.2 cards are not supported. - You will get a boot time penguin logo at no additional cost. Please - read . If unsure, say Y. - -config FB_EFI - bool "EFI-based Framebuffer Support" - depends on (FB = y) && !IA64 && EFI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the EFI frame buffer device driver. If the firmware on - your platform is EFI 1.10 or UEFI 2.0, select Y to add support for - using the EFI framebuffer as your console. - -config FB_N411 - tristate "N411 Apollo/Hecuba devkit support" - depends on FB && X86 && MMU - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - select FB_HECUBA - help - This enables support for the Apollo display controller in its - Hecuba form using the n411 devkit. - -config FB_HGA - tristate "Hercules mono graphics support" - depends on FB && X86 - help - Say Y here if you have a Hercules mono graphics card. - - To compile this driver as a module, choose M here: the - module will be called hgafb. - - As this card technology is at least 25 years old, - most people will answer N here. - -config FB_GBE - bool "SGI Graphics Backend frame buffer support" - depends on (FB = y) && SGI_IP32 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for SGI Graphics Backend. - This chip is used in SGI O2 and Visual Workstation 320/540. - -config FB_GBE_MEM - int "Video memory size in MB" - depends on FB_GBE - default 4 - help - This is the amount of memory reserved for the framebuffer, - which can be any value between 1MB and 8MB. - -config FB_SBUS - bool "SBUS and UPA framebuffers" - depends on (FB = y) && SPARC - help - Say Y if you want support for SBUS or UPA based frame buffer device. - -config FB_BW2 - bool "BWtwo support" - depends on (FB = y) && (SPARC && FB_SBUS) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the BWtwo frame buffer. - -config FB_CG3 - bool "CGthree support" - depends on (FB = y) && (SPARC && FB_SBUS) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the CGthree frame buffer. - -config FB_CG6 - bool "CGsix (GX,TurboGX) support" - depends on (FB = y) && (SPARC && FB_SBUS) - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the CGsix (GX, TurboGX) - frame buffer. - -config FB_FFB - bool "Creator/Creator3D/Elite3D support" - depends on FB_SBUS && SPARC64 - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the Creator, Creator3D, - and Elite3D graphics boards. - -config FB_TCX - bool "TCX (SS4/SS5 only) support" - depends on FB_SBUS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the TCX 24/8bit frame - buffer. - -config FB_CG14 - bool "CGfourteen (SX) support" - depends on FB_SBUS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the CGfourteen frame - buffer on Desktop SPARCsystems with the SX graphics option. - -config FB_P9100 - bool "P9100 (Sparcbook 3 only) support" - depends on FB_SBUS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the P9100 card - supported on Sparcbook 3 machines. - -config FB_LEO - bool "Leo (ZX) support" - depends on FB_SBUS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the SBUS-based Sun ZX - (leo) frame buffer cards. - -config FB_IGA - bool "IGA 168x display support" - depends on (FB = y) && SPARC32 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the framebuffer device for the INTERGRAPHICS 1680 and - successor frame buffer cards. - -config FB_XVR500 - bool "Sun XVR-500 3DLABS Wildcat support" - depends on (FB = y) && PCI && SPARC64 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the framebuffer device for the Sun XVR-500 and similar - graphics cards based upon the 3DLABS Wildcat chipset. The driver - only works on sparc64 systems where the system firmware has - mostly initialized the card already. It is treated as a - completely dumb framebuffer device. - -config FB_XVR2500 - bool "Sun XVR-2500 3DLABS Wildcat support" - depends on (FB = y) && PCI && SPARC64 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the framebuffer device for the Sun XVR-2500 and similar - graphics cards based upon the 3DLABS Wildcat chipset. The driver - only works on sparc64 systems where the system firmware has - mostly initialized the card already. It is treated as a - completely dumb framebuffer device. - -config FB_XVR1000 - bool "Sun XVR-1000 support" - depends on (FB = y) && SPARC64 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the framebuffer device for the Sun XVR-1000 and similar - graphics cards. The driver only works on sparc64 systems where - the system firmware has mostly initialized the card already. It - is treated as a completely dumb framebuffer device. - -config FB_PVR2 - tristate "NEC PowerVR 2 display support" - depends on FB && SH_DREAMCAST - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Say Y here if you have a PowerVR 2 card in your box. If you plan to - run linux on your Dreamcast, you will have to say Y here. - This driver may or may not work on other PowerVR 2 cards, but is - totally untested. Use at your own risk. If unsure, say N. - - To compile this driver as a module, choose M here: the - module will be called pvr2fb. - - You can pass several parameters to the driver at boot time or at - module load time. The parameters look like "video=pvr2:XXX", where - the meaning of XXX can be found at the end of the main source file - (). Please see the file - . - -config FB_OPENCORES - tristate "OpenCores VGA/LCD core 2.0 framebuffer support" - depends on FB && HAS_DMA - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This enables support for the OpenCores VGA/LCD core. - - The OpenCores VGA/LCD core is typically used together with - softcore CPUs (e.g. OpenRISC or Microblaze) or hard processor - systems (e.g. Altera socfpga or Xilinx Zynq) on FPGAs. - - The source code and specification for the core is available at - - -config FB_S1D13XXX - tristate "Epson S1D13XXX framebuffer support" - depends on FB - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Support for S1D13XXX framebuffer device family (currently only - working with S1D13806). Product specs at - - -config FB_ATMEL - tristate "AT91/AT32 LCD Controller support" - depends on FB && HAVE_FB_ATMEL - select FB_BACKLIGHT - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MODE_HELPERS - select VIDEOMODE_HELPERS - help - This enables support for the AT91/AT32 LCD Controller. - -config FB_NVIDIA - tristate "nVidia Framebuffer Support" - depends on FB && PCI - select FB_BACKLIGHT if FB_NVIDIA_BACKLIGHT - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select BITREVERSE - select VGASTATE - help - This driver supports graphics boards with the nVidia chips, TNT - and newer. For very old chipsets, such as the RIVA128, then use - the rivafb. - Say Y if you have such a graphics board. - - To compile this driver as a module, choose M here: the - module will be called nvidiafb. - -config FB_NVIDIA_I2C - bool "Enable DDC Support" - depends on FB_NVIDIA - select FB_DDC - help - This enables I2C support for nVidia Chipsets. This is used - only for getting EDID information from the attached display - allowing for robust video mode handling and switching. - - Because fbdev-2.6 requires that drivers must be able to - independently validate video mode parameters, you should say Y - here. - -config FB_NVIDIA_DEBUG - bool "Lots of debug output" - depends on FB_NVIDIA - default n - help - Say Y here if you want the nVidia driver to output all sorts - of debugging information to provide to the maintainer when - something goes wrong. - -config FB_NVIDIA_BACKLIGHT - bool "Support for backlight control" - depends on FB_NVIDIA - default y - help - Say Y here if you want to control the backlight of your display. - -config FB_RIVA - tristate "nVidia Riva support" - depends on FB && PCI - select FB_BACKLIGHT if FB_RIVA_BACKLIGHT - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select BITREVERSE - select VGASTATE - help - This driver supports graphics boards with the nVidia Riva/Geforce - chips. - Say Y if you have such a graphics board. - - To compile this driver as a module, choose M here: the - module will be called rivafb. - -config FB_RIVA_I2C - bool "Enable DDC Support" - depends on FB_RIVA - select FB_DDC - help - This enables I2C support for nVidia Chipsets. This is used - only for getting EDID information from the attached display - allowing for robust video mode handling and switching. - - Because fbdev-2.6 requires that drivers must be able to - independently validate video mode parameters, you should say Y - here. - -config FB_RIVA_DEBUG - bool "Lots of debug output" - depends on FB_RIVA - default n - help - Say Y here if you want the Riva driver to output all sorts - of debugging information to provide to the maintainer when - something goes wrong. - -config FB_RIVA_BACKLIGHT - bool "Support for backlight control" - depends on FB_RIVA - default y - help - Say Y here if you want to control the backlight of your display. - -config FB_I740 - tristate "Intel740 support" - depends on FB && PCI - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select VGASTATE - select FB_DDC - help - This driver supports graphics cards based on Intel740 chip. - -config FB_I810 - tristate "Intel 810/815 support" - depends on FB && PCI && X86_32 && AGP_INTEL - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select VGASTATE - help - This driver supports the on-board graphics built in to the Intel 810 - and 815 chipsets. Say Y if you have and plan to use such a board. - - To compile this driver as a module, choose M here: the - module will be called i810fb. - - For more information, please read - - -config FB_I810_GTF - bool "use VESA Generalized Timing Formula" - depends on FB_I810 - help - If you say Y, then the VESA standard, Generalized Timing Formula - or GTF, will be used to calculate the required video timing values - per video mode. Since the GTF allows nondiscrete timings - (nondiscrete being a range of values as opposed to discrete being a - set of values), you'll be able to use any combination of horizontal - and vertical resolutions, and vertical refresh rates without having - to specify your own timing parameters. This is especially useful - to maximize the performance of an aging display, or if you just - have a display with nonstandard dimensions. A VESA compliant - monitor is recommended, but can still work with non-compliant ones. - If you need or want this, then select this option. The timings may - not be compliant with Intel's recommended values. Use at your own - risk. - - If you say N, the driver will revert to discrete video timings - using a set recommended by Intel in their documentation. - - If unsure, say N. - -config FB_I810_I2C - bool "Enable DDC Support" - depends on FB_I810 && FB_I810_GTF - select FB_DDC - help - -config FB_LE80578 - tristate "Intel LE80578 (Vermilion) support" - depends on FB && PCI && X86 - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This driver supports the LE80578 (Vermilion Range) chipset - -config FB_CARILLO_RANCH - tristate "Intel Carillo Ranch support" - depends on FB_LE80578 && FB && PCI && X86 - help - This driver supports the LE80578 (Carillo Ranch) board - -config FB_INTEL - tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G/945GM/965G/965GM support" - depends on FB && PCI && X86 && AGP_INTEL && EXPERT - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_BOOT_VESA_SUPPORT if FB_INTEL = y - depends on !DRM_I915 - help - This driver supports the on-board graphics built in to the Intel - 830M/845G/852GM/855GM/865G/915G/915GM/945G/945GM/965G/965GM chipsets. - Say Y if you have and plan to use such a board. - - To make FB_INTELFB=Y work you need to say AGP_INTEL=y too. - - To compile this driver as a module, choose M here: the - module will be called intelfb. - - For more information, please read - -config FB_INTEL_DEBUG - bool "Intel driver Debug Messages" - depends on FB_INTEL - ---help--- - Say Y here if you want the Intel driver to output all sorts - of debugging information to provide to the maintainer when - something goes wrong. - -config FB_INTEL_I2C - bool "DDC/I2C for Intel framebuffer support" - depends on FB_INTEL - select FB_DDC - default y - help - Say Y here if you want DDC/I2C support for your on-board Intel graphics. - -config FB_MATROX - tristate "Matrox acceleration" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_TILEBLITTING - select FB_MACMODES if PPC_PMAC - ---help--- - Say Y here if you have a Matrox Millennium, Matrox Millennium II, - Matrox Mystique, Matrox Mystique 220, Matrox Productiva G100, Matrox - Mystique G200, Matrox Millennium G200, Matrox Marvel G200 video, - Matrox G400, G450 or G550 card in your box. - - To compile this driver as a module, choose M here: the - module will be called matroxfb. - - You can pass several parameters to the driver at boot time or at - module load time. The parameters look like "video=matroxfb:XXX", and - are described in . - -config FB_MATROX_MILLENIUM - bool "Millennium I/II support" - depends on FB_MATROX - help - Say Y here if you have a Matrox Millennium or Matrox Millennium II - video card. If you select "Advanced lowlevel driver options" below, - you should check 4 bpp packed pixel, 8 bpp packed pixel, 16 bpp - packed pixel, 24 bpp packed pixel and 32 bpp packed pixel. You can - also use font widths different from 8. - -config FB_MATROX_MYSTIQUE - bool "Mystique support" - depends on FB_MATROX - help - Say Y here if you have a Matrox Mystique or Matrox Mystique 220 - video card. If you select "Advanced lowlevel driver options" below, - you should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp - packed pixel and 32 bpp packed pixel. You can also use font widths - different from 8. - -config FB_MATROX_G - bool "G100/G200/G400/G450/G550 support" - depends on FB_MATROX - ---help--- - Say Y here if you have a Matrox G100, G200, G400, G450 or G550 based - video card. If you select "Advanced lowlevel driver options", you - should check 8 bpp packed pixel, 16 bpp packed pixel, 24 bpp packed - pixel and 32 bpp packed pixel. You can also use font widths - different from 8. - - If you need support for G400 secondary head, you must say Y to - "Matrox I2C support" and "G400 second head support" right below. - G450/G550 secondary head and digital output are supported without - additional modules. - - The driver starts in monitor mode. You must use the matroxset tool - (available at ) to - swap primary and secondary head outputs, or to change output mode. - Secondary head driver always start in 640x480 resolution and you - must use fbset to change it. - - Do not forget that second head supports only 16 and 32 bpp - packed pixels, so it is a good idea to compile them into the kernel - too. You can use only some font widths, as the driver uses generic - painting procedures (the secondary head does not use acceleration - engine). - - G450/G550 hardware can display TV picture only from secondary CRTC, - and it performs no scaling, so picture must have 525 or 625 lines. - -config FB_MATROX_I2C - tristate "Matrox I2C support" - depends on FB_MATROX - select FB_DDC - ---help--- - This drivers creates I2C buses which are needed for accessing the - DDC (I2C) bus present on all Matroxes, an I2C bus which - interconnects Matrox optional devices, like MGA-TVO on G200 and - G400, and the secondary head DDC bus, present on G400 only. - - You can say Y or M here if you want to experiment with monitor - detection code. You must say Y or M here if you want to use either - second head of G400 or MGA-TVO on G200 or G400. - - If you compile it as module, it will create a module named - i2c-matroxfb. - -config FB_MATROX_MAVEN - tristate "G400 second head support" - depends on FB_MATROX_G && FB_MATROX_I2C - ---help--- - WARNING !!! This support does not work with G450 !!! - - Say Y or M here if you want to use a secondary head (meaning two - monitors in parallel) on G400 or MGA-TVO add-on on G200. Secondary - head is not compatible with accelerated XFree 3.3.x SVGA servers - - secondary head output is blanked while you are in X. With XFree - 3.9.17 preview you can use both heads if you use SVGA over fbdev or - the fbdev driver on first head and the fbdev driver on second head. - - If you compile it as module, two modules are created, - matroxfb_crtc2 and matroxfb_maven. Matroxfb_maven is needed for - both G200 and G400, matroxfb_crtc2 is needed only by G400. You must - also load i2c-matroxfb to get it to run. - - The driver starts in monitor mode and you must use the matroxset - tool (available at - ) to switch it to - PAL or NTSC or to swap primary and secondary head outputs. - Secondary head driver also always start in 640x480 resolution, you - must use fbset to change it. - - Also do not forget that second head supports only 16 and 32 bpp - packed pixels, so it is a good idea to compile them into the kernel - too. You can use only some font widths, as the driver uses generic - painting procedures (the secondary head does not use acceleration - engine). - -config FB_RADEON - tristate "ATI Radeon display support" - depends on FB && PCI - select FB_BACKLIGHT if FB_RADEON_BACKLIGHT - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MACMODES if PPC - help - Choose this option if you want to use an ATI Radeon graphics card as - a framebuffer device. There are both PCI and AGP versions. You - don't need to choose this to run the Radeon in plain VGA mode. - - There is a product page at - http://products.amd.com/en-us/GraphicCardResult.aspx - -config FB_RADEON_I2C - bool "DDC/I2C for ATI Radeon support" - depends on FB_RADEON - select FB_DDC - default y - help - Say Y here if you want DDC/I2C support for your Radeon board. - -config FB_RADEON_BACKLIGHT - bool "Support for backlight control" - depends on FB_RADEON - default y - help - Say Y here if you want to control the backlight of your display. - -config FB_RADEON_DEBUG - bool "Lots of debug output from Radeon driver" - depends on FB_RADEON - default n - help - Say Y here if you want the Radeon driver to output all sorts - of debugging information to provide to the maintainer when - something goes wrong. - -config FB_ATY128 - tristate "ATI Rage128 display support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_BACKLIGHT if FB_ATY128_BACKLIGHT - select FB_MACMODES if PPC_PMAC - help - This driver supports graphics boards with the ATI Rage128 chips. - Say Y if you have such a graphics board and read - . - - To compile this driver as a module, choose M here: the - module will be called aty128fb. - -config FB_ATY128_BACKLIGHT - bool "Support for backlight control" - depends on FB_ATY128 - default y - help - Say Y here if you want to control the backlight of your display. - -config FB_ATY - tristate "ATI Mach64 display support" if PCI || ATARI - depends on FB && !SPARC32 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_BACKLIGHT if FB_ATY_BACKLIGHT - select FB_MACMODES if PPC - help - This driver supports graphics boards with the ATI Mach64 chips. - Say Y if you have such a graphics board. - - To compile this driver as a module, choose M here: the - module will be called atyfb. - -config FB_ATY_CT - bool "Mach64 CT/VT/GT/LT (incl. 3D RAGE) support" - depends on PCI && FB_ATY - default y if SPARC64 && PCI - help - Say Y here to support use of ATI's 64-bit Rage boards (or other - boards based on the Mach64 CT, VT, GT, and LT chipsets) as a - framebuffer device. The ATI product support page for these boards - is at . - -config FB_ATY_GENERIC_LCD - bool "Mach64 generic LCD support" - depends on FB_ATY_CT - help - Say Y if you have a laptop with an ATI Rage LT PRO, Rage Mobility, - Rage XC, or Rage XL chipset. - -config FB_ATY_GX - bool "Mach64 GX support" if PCI - depends on FB_ATY - default y if ATARI - help - Say Y here to support use of the ATI Mach64 Graphics Expression - board (or other boards based on the Mach64 GX chipset) as a - framebuffer device. The ATI product support page for these boards - is at - . - -config FB_ATY_BACKLIGHT - bool "Support for backlight control" - depends on FB_ATY - default y - help - Say Y here if you want to control the backlight of your display. - -config FB_S3 - tristate "S3 Trio/Virge support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_TILEBLITTING - select FB_SVGALIB - select VGASTATE - select FONT_8x16 if FRAMEBUFFER_CONSOLE - ---help--- - Driver for graphics boards with S3 Trio / S3 Virge chip. - -config FB_S3_DDC - bool "DDC for S3 support" - depends on FB_S3 - select FB_DDC - default y - help - Say Y here if you want DDC support for your S3 graphics card. - -config FB_SAVAGE - tristate "S3 Savage support" - depends on FB && PCI - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select VGASTATE - help - This driver supports notebooks and computers with S3 Savage PCI/AGP - chips. - - Say Y if you have such a graphics card. - - To compile this driver as a module, choose M here; the module - will be called savagefb. - -config FB_SAVAGE_I2C - bool "Enable DDC2 Support" - depends on FB_SAVAGE - select FB_DDC - help - This enables I2C support for S3 Savage Chipsets. This is used - only for getting EDID information from the attached display - allowing for robust video mode handling and switching. - - Because fbdev-2.6 requires that drivers must be able to - independently validate video mode parameters, you should say Y - here. - -config FB_SAVAGE_ACCEL - bool "Enable Console Acceleration" - depends on FB_SAVAGE - default n - help - This option will compile in console acceleration support. If - the resulting framebuffer console has bothersome glitches, then - choose N here. - -config FB_SIS - tristate "SiS/XGI display support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_BOOT_VESA_SUPPORT if FB_SIS = y - select FB_SIS_300 if !FB_SIS_315 - help - This is the frame buffer device driver for the SiS 300, 315, 330 - and 340 series as well as XGI V3XT, V5, V8, Z7 graphics chipsets. - Specs available at and . - - To compile this driver as a module, choose M here; the module - will be called sisfb. - -config FB_SIS_300 - bool "SiS 300 series support" - depends on FB_SIS - help - Say Y here to support use of the SiS 300/305, 540, 630 and 730. - -config FB_SIS_315 - bool "SiS 315/330/340 series and XGI support" - depends on FB_SIS - help - Say Y here to support use of the SiS 315, 330 and 340 series - (315/H/PRO, 55x, 650, 651, 740, 330, 661, 741, 760, 761) as well - as XGI V3XT, V5, V8 and Z7. - -config FB_VIA - tristate "VIA UniChrome (Pro) and Chrome9 display support" - depends on FB && PCI && X86 && GPIOLIB && I2C - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select I2C_ALGOBIT - help - This is the frame buffer device driver for Graphics chips of VIA - UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/ - CN700/VN800,CX700/VX700,P4M890) and Chrome9 Family (K8M890,CN896 - /P4M900,VX800) - Say Y if you have a VIA UniChrome graphics board. - - To compile this driver as a module, choose M here: the - module will be called viafb. - -if FB_VIA - -config FB_VIA_DIRECT_PROCFS - bool "direct hardware access via procfs (DEPRECATED)(DANGEROUS)" - depends on FB_VIA - default n - help - Allow direct hardware access to some output registers via procfs. - This is dangerous but may provide the only chance to get the - correct output device configuration. - Its use is strongly discouraged. - -config FB_VIA_X_COMPATIBILITY - bool "X server compatibility" - depends on FB_VIA - default n - help - This option reduces the functionality (power saving, ...) of the - framebuffer to avoid negative impact on the OpenChrome X server. - If you use any X server other than fbdev you should enable this - otherwise it should be safe to disable it and allow using all - features. - -endif - -config FB_NEOMAGIC - tristate "NeoMagic display support" - depends on FB && PCI - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select VGASTATE - help - This driver supports notebooks with NeoMagic PCI chips. - Say Y if you have such a graphics card. - - To compile this driver as a module, choose M here: the - module will be called neofb. - -config FB_KYRO - tristate "IMG Kyro support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Say Y here if you have a STG4000 / Kyro / PowerVR 3 based - graphics board. - - To compile this driver as a module, choose M here: the - module will be called kyrofb. - -config FB_3DFX - tristate "3Dfx Banshee/Voodoo3/Voodoo5 display support" - depends on FB && PCI - select FB_CFB_IMAGEBLIT - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_MODE_HELPERS - help - This driver supports graphics boards with the 3Dfx Banshee, - Voodoo3 or VSA-100 (aka Voodoo4/5) chips. Say Y if you have - such a graphics board. - - To compile this driver as a module, choose M here: the - module will be called tdfxfb. - -config FB_3DFX_ACCEL - bool "3Dfx Acceleration functions" - depends on FB_3DFX - ---help--- - This will compile the 3Dfx Banshee/Voodoo3/VSA-100 frame buffer - device driver with acceleration functions. - -config FB_3DFX_I2C - bool "Enable DDC/I2C support" - depends on FB_3DFX - select FB_DDC - default y - help - Say Y here if you want DDC/I2C support for your 3dfx Voodoo3. - -config FB_VOODOO1 - tristate "3Dfx Voodoo Graphics (sst1) support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Say Y here if you have a 3Dfx Voodoo Graphics (Voodoo1/sst1) or - Voodoo2 (cvg) based graphics card. - - To compile this driver as a module, choose M here: the - module will be called sstfb. - - WARNING: Do not use any application that uses the 3D engine - (namely glide) while using this driver. - Please read the for supported - options and other important info support. - -config FB_VT8623 - tristate "VIA VT8623 support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_TILEBLITTING - select FB_SVGALIB - select VGASTATE - select FONT_8x16 if FRAMEBUFFER_CONSOLE - ---help--- - Driver for CastleRock integrated graphics core in the - VIA VT8623 [Apollo CLE266] chipset. - -config FB_TRIDENT - tristate "Trident/CyberXXX/CyberBlade support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_DDC - select FB_MODE_HELPERS - ---help--- - This is the frame buffer device driver for Trident PCI/AGP chipsets. - Supported chipset families are TGUI 9440/96XX, 3DImage, Blade3D - and Blade XP. - There are also integrated versions of these chips called CyberXXXX, - CyberImage or CyberBlade. These chips are mostly found in laptops - but also on some motherboards including early VIA EPIA motherboards. - For more information, read - - Say Y if you have such a graphics board. - - To compile this driver as a module, choose M here: the - module will be called tridentfb. - -config FB_ARK - tristate "ARK 2000PV support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_TILEBLITTING - select FB_SVGALIB - select VGASTATE - select FONT_8x16 if FRAMEBUFFER_CONSOLE - ---help--- - Driver for PCI graphics boards with ARK 2000PV chip - and ICS 5342 RAMDAC. - -config FB_PM3 - tristate "Permedia3 support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the 3DLabs Permedia3 - chipset, used in Formac ProFormance III, 3DLabs Oxygen VX1 & - similar boards, 3DLabs Permedia3 Create!, Appian Jeronimo 2000 - and maybe other boards. - -config FB_CARMINE - tristate "Fujitsu carmine frame buffer support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the Fujitsu Carmine chip. - The driver provides two independent frame buffer devices. - -choice - depends on FB_CARMINE - prompt "DRAM timing" - default FB_CARMINE_DRAM_EVAL - -config FB_CARMINE_DRAM_EVAL - bool "Eval board timings" - help - Use timings which work on the eval card. - -config CARMINE_DRAM_CUSTOM - bool "Custom board timings" - help - Use custom board timings. -endchoice - -config FB_AU1100 - bool "Au1100 LCD Driver" - depends on (FB = y) && MIPS_ALCHEMY - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the framebuffer driver for the AMD Au1100 SOC. It can drive - various panels and CRTs by passing in kernel cmd line option - au1100fb:panel=. - -config FB_AU1200 - bool "Au1200/Au1300 LCD Driver" - depends on (FB = y) && MIPS_ALCHEMY - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - help - This is the framebuffer driver for the Au1200/Au1300 SOCs. - It can drive various panels and CRTs by passing in kernel cmd line - option au1200fb:panel=. - -config FB_VT8500 - bool "VIA VT8500 framebuffer support" - depends on (FB = y) && ARM && ARCH_VT8500 - select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS) - select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS) - select FB_SYS_IMAGEBLIT - select FB_MODE_HELPERS - select VIDEOMODE_HELPERS - help - This is the framebuffer driver for VIA VT8500 integrated LCD - controller. - -config FB_WM8505 - bool "Wondermedia WM8xxx-series frame buffer support" - depends on (FB = y) && ARM && ARCH_VT8500 - select FB_SYS_FILLRECT if (!FB_WMT_GE_ROPS) - select FB_SYS_COPYAREA if (!FB_WMT_GE_ROPS) - select FB_SYS_IMAGEBLIT - select FB_MODE_HELPERS - select VIDEOMODE_HELPERS - help - This is the framebuffer driver for WonderMedia WM8xxx-series - integrated LCD controller. This driver covers the WM8505, WM8650 - and WM8850 SoCs. - -config FB_WMT_GE_ROPS - bool "VT8500/WM8xxx accelerated raster ops support" - depends on (FB = y) && (FB_VT8500 || FB_WM8505) - default n - help - This adds support for accelerated raster operations on the - VIA VT8500 and Wondermedia 85xx series SoCs. - -source "drivers/video/fbdev/geode/Kconfig" - -config FB_HIT - tristate "HD64461 Frame Buffer support" - depends on FB && HD64461 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This is the frame buffer device driver for the Hitachi HD64461 LCD - frame buffer card. - -config FB_PMAG_AA - tristate "PMAG-AA TURBOchannel framebuffer support" - depends on FB && TC - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Support for the PMAG-AA TURBOchannel framebuffer card (1280x1024x1) - used mainly in the MIPS-based DECstation series. - -config FB_PMAG_BA - tristate "PMAG-BA TURBOchannel framebuffer support" - depends on FB && TC - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Support for the PMAG-BA TURBOchannel framebuffer card (1024x864x8) - used mainly in the MIPS-based DECstation series. - -config FB_PMAGB_B - tristate "PMAGB-B TURBOchannel framebuffer support" - depends on FB && TC - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Support for the PMAGB-B TURBOchannel framebuffer card used mainly - in the MIPS-based DECstation series. The card is currently only - supported in 1280x1024x8 mode. - -config FB_MAXINE - bool "Maxine (Personal DECstation) onboard framebuffer support" - depends on (FB = y) && MACH_DECSTATION - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Support for the onboard framebuffer (1024x768x8) in the Personal - DECstation series (Personal DECstation 5000/20, /25, /33, /50, - Codename "Maxine"). - -config FB_G364 - bool "G364 frame buffer support" - depends on (FB = y) && (MIPS_MAGNUM_4000 || OLIVETTI_M700) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - The G364 driver is the framebuffer used in MIPS Magnum 4000 and - Olivetti M700-10 systems. - -config FB_68328 - bool "Motorola 68328 native frame buffer support" - depends on (FB = y) && (M68328 || M68EZ328 || M68VZ328) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Say Y here if you want to support the built-in frame buffer of - the Motorola 68328 CPU family. - -config FB_PXA168 - tristate "PXA168/910 LCD framebuffer support" - depends on FB && (CPU_PXA168 || CPU_PXA910) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Frame buffer driver for the built-in LCD controller in the Marvell - MMP processor. - -config FB_PXA - tristate "PXA LCD framebuffer support" - depends on FB && ARCH_PXA - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select VIDEOMODE_HELPERS if OF - select FB_MODE_HELPERS if OF - ---help--- - Frame buffer driver for the built-in LCD controller in the Intel - PXA2x0 processor. - - This driver is also available as a module ( = code which can be - inserted and removed from the running kernel whenever you want). The - module will be called pxafb. If you want to compile it as a module, - say M here and read . - - If unsure, say N. - -config FB_PXA_OVERLAY - bool "Support PXA27x/PXA3xx Overlay(s) as framebuffer" - default n - depends on FB_PXA && (PXA27x || PXA3xx) - -config FB_PXA_SMARTPANEL - bool "PXA Smartpanel LCD support" - default n - depends on FB_PXA - -config FB_PXA_PARAMETERS - bool "PXA LCD command line parameters" - default n - depends on FB_PXA - ---help--- - Enable the use of kernel command line or module parameters - to configure the physical properties of the LCD panel when - using the PXA LCD driver. - - This option allows you to override the panel parameters - supplied by the platform in order to support multiple - different models of flatpanel. If you will only be using a - single model of flatpanel then you can safely leave this - option disabled. - - describes the available parameters. - -config PXA3XX_GCU - tristate "PXA3xx 2D graphics accelerator driver" - depends on FB_PXA - help - Kernelspace driver for the 2D graphics controller unit (GCU) - found on PXA3xx processors. There is a counterpart driver in the - DirectFB suite, see http://www.directfb.org/ - - If you compile this as a module, it will be called pxa3xx_gcu. - -config FB_MBX - tristate "2700G LCD framebuffer support" - depends on FB && ARCH_PXA - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Framebuffer driver for the Intel 2700G (Marathon) Graphics - Accelerator - -config FB_MBX_DEBUG - bool "Enable debugging info via debugfs" - depends on FB_MBX && DEBUG_FS - default n - ---help--- - Enable this if you want debugging information using the debug - filesystem (debugfs) - - If unsure, say N. - -config FB_FSL_DIU - tristate "Freescale DIU framebuffer support" - depends on FB && FSL_SOC - select FB_MODE_HELPERS - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select PPC_LIB_RHEAP - ---help--- - Framebuffer driver for the Freescale SoC DIU - -config FB_W100 - tristate "W100 frame buffer support" - depends on FB && ARCH_PXA - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Frame buffer driver for the w100 as found on the Sharp SL-Cxx series. - It can also drive the w3220 chip found on iPAQ hx4700. - - This driver is also available as a module ( = code which can be - inserted and removed from the running kernel whenever you want). The - module will be called w100fb. If you want to compile it as a module, - say M here and read . - - If unsure, say N. - -config FB_SH_MOBILE_LCDC - tristate "SuperH Mobile LCDC framebuffer support" - depends on FB && (SUPERH || ARCH_RENESAS) && HAVE_CLK - depends on FB_SH_MOBILE_MERAM || !FB_SH_MOBILE_MERAM - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - select FB_BACKLIGHT - ---help--- - Frame buffer driver for the on-chip SH-Mobile LCD controller. - -config FB_TMIO - tristate "Toshiba Mobile IO FrameBuffer support" - depends on FB && (MFD_TMIO || COMPILE_TEST) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Frame buffer driver for the Toshiba Mobile IO integrated as found - on the Sharp SL-6000 series - - This driver is also available as a module ( = code which can be - inserted and removed from the running kernel whenever you want). The - module will be called tmiofb. If you want to compile it as a module, - say M here and read . - - If unsure, say N. - -config FB_TMIO_ACCELL - bool "tmiofb acceleration" - depends on FB_TMIO - default y - -config FB_S3C - tristate "Samsung S3C framebuffer support" - depends on FB && (CPU_S3C2416 || ARCH_S3C64XX || \ - ARCH_S5PV210 || ARCH_EXYNOS) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Frame buffer driver for the built-in FB controller in the Samsung - SoC line from the S3C2443 onwards, including the S3C2416, S3C2450, - and the S3C64XX series such as the S3C6400 and S3C6410. - - These chips all have the same basic framebuffer design with the - actual capabilities depending on the chip. For instance the S3C6400 - and S3C6410 support 4 hardware windows whereas the S3C24XX series - currently only have two. - - Currently the support is only for the S3C6400 and S3C6410 SoCs. - -config FB_S3C_DEBUG_REGWRITE - bool "Debug register writes" - depends on FB_S3C - ---help--- - Show all register writes via pr_debug() - -config FB_S3C2410 - tristate "S3C2410 LCD framebuffer support" - depends on FB && ARCH_S3C24XX - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Frame buffer driver for the built-in LCD controller in the Samsung - S3C2410 processor. - - This driver is also available as a module ( = code which can be - inserted and removed from the running kernel whenever you want). The - module will be called s3c2410fb. If you want to compile it as a module, - say M here and read . - - If unsure, say N. -config FB_S3C2410_DEBUG - bool "S3C2410 lcd debug messages" - depends on FB_S3C2410 - help - Turn on debugging messages. Note that you can set/unset at run time - through sysfs - -config FB_NUC900 - tristate "NUC900 LCD framebuffer support" - depends on FB && ARCH_W90X900 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Frame buffer driver for the built-in LCD controller in the Nuvoton - NUC900 processor - -config GPM1040A0_320X240 - bool "Giantplus Technology GPM1040A0 320x240 Color TFT LCD" - depends on FB_NUC900 - -config FB_SM501 - tristate "Silicon Motion SM501 framebuffer support" - depends on FB && MFD_SM501 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Frame buffer driver for the CRT and LCD controllers in the Silicon - Motion SM501. - - This driver is also available as a module ( = code which can be - inserted and removed from the running kernel whenever you want). The - module will be called sm501fb. If you want to compile it as a module, - say M here and read . - - If unsure, say N. - -config FB_SMSCUFX - tristate "SMSC UFX6000/7000 USB Framebuffer support" - depends on FB && USB - select FB_MODE_HELPERS - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - ---help--- - This is a kernel framebuffer driver for SMSC UFX USB devices. - Supports fbdev clients like xf86-video-fbdev, kdrive, fbi, and - mplayer -vo fbdev. Supports both UFX6000 (USB 2.0) and UFX7000 - (USB 3.0) devices. - To compile as a module, choose M here: the module name is smscufx. - -config FB_UDL - tristate "Displaylink USB Framebuffer support" - depends on FB && USB - select FB_MODE_HELPERS - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - ---help--- - This is a kernel framebuffer driver for DisplayLink USB devices. - Supports fbdev clients like xf86-video-fbdev, kdrive, fbi, and - mplayer -vo fbdev. Supports all USB 2.0 era DisplayLink devices. - To compile as a module, choose M here: the module name is udlfb. - -config FB_IBM_GXT4500 - tristate "Framebuffer support for IBM GXT4000P/4500P/6000P/6500P adaptors" - depends on FB - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Say Y here to enable support for the IBM GXT4000P/6000P and - GXT4500P/6500P display adaptor based on Raster Engine RC1000, - found on some IBM System P (pSeries) machines. This driver - doesn't use Geometry Engine GT1000. This driver also supports - AGP Fire GL2/3/4 cards on x86. - -config FB_PS3 - tristate "PS3 GPU framebuffer driver" - depends on FB && PS3_PS3AV - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - ---help--- - Include support for the virtual frame buffer in the PS3 platform. - -config FB_PS3_DEFAULT_SIZE_M - int "PS3 default frame buffer size (in MiB)" - depends on FB_PS3 - default 9 - ---help--- - This is the default size (in MiB) of the virtual frame buffer in - the PS3. - The default value can be overridden on the kernel command line - using the "ps3fb" option (e.g. "ps3fb=9M"); - -config FB_XILINX - tristate "Xilinx frame buffer support" - depends on FB && (XILINX_VIRTEX || MICROBLAZE || ARCH_ZYNQ) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Include support for the Xilinx ML300/ML403 reference design - framebuffer. ML300 carries a 640*480 LCD display on the board, - ML403 uses a standard DB15 VGA connector. - -config FB_GOLDFISH - tristate "Goldfish Framebuffer" - depends on FB && HAS_DMA && (GOLDFISH || COMPILE_TEST) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Framebuffer driver for Goldfish Virtual Platform - -config FB_COBALT - tristate "Cobalt server LCD frame buffer support" - depends on FB && MIPS_COBALT - -config FB_SH7760 - bool "SH7760/SH7763/SH7720/SH7721 LCDC support" - depends on FB && (CPU_SUBTYPE_SH7760 || CPU_SUBTYPE_SH7763 \ - || CPU_SUBTYPE_SH7720 || CPU_SUBTYPE_SH7721) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Support for the SH7760/SH7763/SH7720/SH7721 integrated - (D)STN/TFT LCD Controller. - Supports display resolutions up to 1024x1024 pixel, grayscale and - color operation, with depths ranging from 1 bpp to 8 bpp monochrome - and 8, 15 or 16 bpp color; 90 degrees clockwise display rotation for - panels <= 320 pixel horizontal resolution. - -config FB_DA8XX - tristate "DA8xx/OMAP-L1xx/AM335x Framebuffer support" - depends on FB && (ARCH_DAVINCI_DA8XX || SOC_AM33XX) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_CFB_REV_PIXELS_IN_BYTE - select FB_MODE_HELPERS - select VIDEOMODE_HELPERS - ---help--- - This is the frame buffer device driver for the TI LCD controller - found on DA8xx/OMAP-L1xx/AM335x SoCs. - If unsure, say N. - -config FB_VIRTUAL - tristate "Virtual Frame Buffer support (ONLY FOR TESTING!)" - depends on FB - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - ---help--- - This is a `virtual' frame buffer device. It operates on a chunk of - unswappable kernel memory instead of on the memory of a graphics - board. This means you cannot see any output sent to this frame - buffer device, while it does consume precious memory. The main use - of this frame buffer device is testing and debugging the frame - buffer subsystem. Do NOT enable it for normal systems! To protect - the innocent, it has to be enabled explicitly at boot time using the - kernel option `video=vfb:'. - - To compile this driver as a module, choose M here: the - module will be called vfb. In order to load it, you must use - the vfb_enable=1 option. - - If unsure, say N. - -config XEN_FBDEV_FRONTEND - tristate "Xen virtual frame buffer support" - depends on FB && XEN - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - select XEN_XENBUS_FRONTEND - default y - help - This driver implements the front-end of the Xen virtual - frame buffer driver. It communicates with a back-end - in another domain. - -config FB_METRONOME - tristate "E-Ink Metronome/8track controller support" - depends on FB - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - help - This driver implements support for the E-Ink Metronome - controller. The pre-release name for this device was 8track - and could also have been called by some vendors as PVI-nnnn. - -config FB_MB862XX - tristate "Fujitsu MB862xx GDC support" - depends on FB - depends on PCI || (OF && PPC) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Frame buffer driver for Fujitsu Carmine/Coral-P(A)/Lime controllers. - -choice - prompt "GDC variant" - depends on FB_MB862XX - -config FB_MB862XX_PCI_GDC - bool "Carmine/Coral-P(A) GDC" - depends on PCI - ---help--- - This enables framebuffer support for Fujitsu Carmine/Coral-P(A) - PCI graphics controller devices. - -config FB_MB862XX_LIME - bool "Lime GDC" - depends on OF && PPC - select FB_FOREIGN_ENDIAN - select FB_LITTLE_ENDIAN - ---help--- - Framebuffer support for Fujitsu Lime GDC on host CPU bus. - -endchoice - -config FB_MB862XX_I2C - bool "Support I2C bus on MB862XX GDC" - depends on FB_MB862XX && I2C - depends on FB_MB862XX=m || I2C=y - default y - help - Selecting this option adds Coral-P(A)/Lime GDC I2C bus adapter - driver to support accessing I2C devices on controller's I2C bus. - These are usually some video decoder chips. - -config FB_EP93XX - tristate "EP93XX frame buffer support" - depends on FB && ARCH_EP93XX - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Framebuffer driver for the Cirrus Logic EP93XX series of processors. - This driver is also available as a module. The module will be called - ep93xx-fb. - -config FB_PRE_INIT_FB - bool "Don't reinitialize, use bootloader's GDC/Display configuration" - depends on FB && FB_MB862XX_LIME - ---help--- - Select this option if display contents should be inherited as set by - the bootloader. - -config FB_MX3 - tristate "MX3 Framebuffer support" - depends on FB && MX3_IPU - select BACKLIGHT_CLASS_DEVICE - select BACKLIGHT_LCD_SUPPORT - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - default y - help - This is a framebuffer device for the i.MX31 LCD Controller. So - far only synchronous displays are supported. If you plan to use - an LCD display with your i.MX31 system, say Y here. - -config FB_BROADSHEET - tristate "E-Ink Broadsheet/Epson S1D13521 controller support" - depends on FB - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - help - This driver implements support for the E-Ink Broadsheet - controller. The release name for this device was Epson S1D13521 - and could also have been called by other names when coupled with - a bridge adapter. - -config FB_AUO_K190X - tristate "AUO-K190X EPD controller support" - depends on FB - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - select FB_DEFERRED_IO - help - Provides support for epaper controllers from the K190X series - of AUO. These controllers can be used to drive epaper displays - from Sipix. - - This option enables the common support, shared by the individual - controller drivers. You will also have to enable the driver - for the controller type used in your device. - -config FB_AUO_K1900 - tristate "AUO-K1900 EPD controller support" - depends on FB && FB_AUO_K190X - help - This driver implements support for the AUO K1900 epd-controller. - This controller can drive Sipix epaper displays but can only do - serial updates, reducing the number of possible frames per second. - -config FB_AUO_K1901 - tristate "AUO-K1901 EPD controller support" - depends on FB && FB_AUO_K190X - help - This driver implements support for the AUO K1901 epd-controller. - This controller can drive Sipix epaper displays and supports - concurrent updates, making higher frames per second possible. - -config FB_JZ4740 - tristate "JZ4740 LCD framebuffer support" - depends on FB && MACH_JZ4740 - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - help - Framebuffer support for the JZ4740 SoC. - -config FB_MXS - tristate "MXS LCD framebuffer support" - depends on FB && (ARCH_MXS || ARCH_MXC) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - select FB_MODE_HELPERS - select VIDEOMODE_HELPERS - help - Framebuffer support for the MXS SoC. - -config FB_PUV3_UNIGFX - tristate "PKUnity v3 Unigfx framebuffer support" - depends on FB && UNICORE32 && ARCH_PUV3 - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_SYS_FOPS - help - Choose this option if you want to use the Unigfx device as a - framebuffer device. Without the support of PCI & AGP. - -config FB_HYPERV - tristate "Microsoft Hyper-V Synthetic Video support" - depends on FB && HYPERV - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - This framebuffer driver supports Microsoft Hyper-V Synthetic Video. - -config FB_SIMPLE - bool "Simple framebuffer support" - depends on (FB = y) - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Say Y if you want support for a simple frame-buffer. - - This driver assumes that the display hardware has been initialized - before the kernel boots, and the kernel will simply render to the - pre-allocated frame buffer surface. - - Configuration re: surface address, size, and format must be provided - through device tree, or plain old platform data. - -source "drivers/video/fbdev/omap/Kconfig" -source "drivers/video/fbdev/omap2/Kconfig" -source "drivers/video/fbdev/mmp/Kconfig" - -config FB_SH_MOBILE_MERAM - tristate "SuperH Mobile MERAM read ahead support" - depends on (SUPERH || ARCH_SHMOBILE) - select GENERIC_ALLOCATOR - ---help--- - Enable MERAM support for the SuperH controller. - - This will allow for caching of the framebuffer to provide more - reliable access under heavy main memory bus traffic situations. - Up to 4 memory channels can be configured, allowing 4 RGB or - 2 YCbCr framebuffers to be configured. - -config FB_SSD1307 - tristate "Solomon SSD1307 framebuffer support" - depends on FB && I2C - depends on OF - depends on GPIOLIB || COMPILE_TEST - select FB_SYS_FOPS - select FB_SYS_FILLRECT - select FB_SYS_COPYAREA - select FB_SYS_IMAGEBLIT - select FB_DEFERRED_IO - select PWM - select FB_BACKLIGHT - help - This driver implements support for the Solomon SSD1307 - OLED controller over I2C. - -config FB_SM712 - tristate "Silicon Motion SM712 framebuffer support" - depends on FB && PCI - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Frame buffer driver for the Silicon Motion SM710, SM712, SM721 - and SM722 chips. - - This driver is also available as a module. The module will be - called sm712fb. If you want to compile it as a module, say M - here and read . diff --git a/src/linux/drivers/video/fbdev/Makefile b/src/linux/drivers/video/fbdev/Makefile deleted file mode 100644 index ee8c814..0000000 --- a/src/linux/drivers/video/fbdev/Makefile +++ /dev/null @@ -1,151 +0,0 @@ -# Makefile for the Linux video drivers. -# 5 Aug 1999, James Simmons, -# Rewritten to use lists instead of if-statements. - -# Each configuration option enables a list of files. - -obj-y += core/ - -obj-$(CONFIG_FB_MACMODES) += macmodes.o -obj-$(CONFIG_FB_WMT_GE_ROPS) += wmt_ge_rops.o - -# Hardware specific drivers go first -obj-$(CONFIG_FB_AMIGA) += amifb.o c2p_planar.o -obj-$(CONFIG_FB_ARC) += arcfb.o -obj-$(CONFIG_FB_CLPS711X) += clps711x-fb.o -obj-$(CONFIG_FB_CLPS711X_OLD) += clps711xfb.o -obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o -obj-$(CONFIG_FB_GRVGA) += grvga.o -obj-$(CONFIG_FB_PM2) += pm2fb.o -obj-$(CONFIG_FB_PM3) += pm3fb.o - -obj-$(CONFIG_FB_I740) += i740fb.o -obj-$(CONFIG_FB_MATROX) += matrox/ -obj-$(CONFIG_FB_RIVA) += riva/ -obj-$(CONFIG_FB_NVIDIA) += nvidia/ -obj-$(CONFIG_FB_ATY) += aty/ macmodes.o -obj-$(CONFIG_FB_ATY128) += aty/ macmodes.o -obj-$(CONFIG_FB_RADEON) += aty/ -obj-$(CONFIG_FB_SIS) += sis/ -obj-$(CONFIG_FB_VIA) += via/ -obj-$(CONFIG_FB_KYRO) += kyro/ -obj-$(CONFIG_FB_SAVAGE) += savage/ -obj-$(CONFIG_FB_GEODE) += geode/ -obj-$(CONFIG_FB_MBX) += mbx/ -obj-$(CONFIG_FB_NEOMAGIC) += neofb.o -obj-$(CONFIG_FB_3DFX) += tdfxfb.o -obj-$(CONFIG_FB_CONTROL) += controlfb.o -obj-$(CONFIG_FB_PLATINUM) += platinumfb.o -obj-$(CONFIG_FB_VALKYRIE) += valkyriefb.o -obj-$(CONFIG_FB_CT65550) += chipsfb.o -obj-$(CONFIG_FB_IMSTT) += imsttfb.o -obj-$(CONFIG_FB_FM2) += fm2fb.o -obj-$(CONFIG_FB_VT8623) += vt8623fb.o -obj-$(CONFIG_FB_TRIDENT) += tridentfb.o -obj-$(CONFIG_FB_LE80578) += vermilion/ -obj-$(CONFIG_FB_S3) += s3fb.o -obj-$(CONFIG_FB_ARK) += arkfb.o -obj-$(CONFIG_FB_STI) += stifb.o -obj-$(CONFIG_FB_FFB) += ffb.o sbuslib.o -obj-$(CONFIG_FB_CG6) += cg6.o sbuslib.o -obj-$(CONFIG_FB_CG3) += cg3.o sbuslib.o -obj-$(CONFIG_FB_BW2) += bw2.o sbuslib.o -obj-$(CONFIG_FB_CG14) += cg14.o sbuslib.o -obj-$(CONFIG_FB_P9100) += p9100.o sbuslib.o -obj-$(CONFIG_FB_TCX) += tcx.o sbuslib.o -obj-$(CONFIG_FB_LEO) += leo.o sbuslib.o -obj-$(CONFIG_FB_ACORN) += acornfb.o -obj-$(CONFIG_FB_ATARI) += atafb.o c2p_iplan2.o atafb_mfb.o \ - atafb_iplan2p2.o atafb_iplan2p4.o atafb_iplan2p8.o -obj-$(CONFIG_FB_MAC) += macfb.o -obj-$(CONFIG_FB_HECUBA) += hecubafb.o -obj-$(CONFIG_FB_N411) += n411.o -obj-$(CONFIG_FB_HGA) += hgafb.o -obj-$(CONFIG_FB_XVR500) += sunxvr500.o -obj-$(CONFIG_FB_XVR2500) += sunxvr2500.o -obj-$(CONFIG_FB_XVR1000) += sunxvr1000.o -obj-$(CONFIG_FB_IGA) += igafb.o -obj-$(CONFIG_FB_APOLLO) += dnfb.o -obj-$(CONFIG_FB_Q40) += q40fb.o -obj-$(CONFIG_FB_TGA) += tgafb.o -obj-$(CONFIG_FB_HP300) += hpfb.o -obj-$(CONFIG_FB_G364) += g364fb.o -obj-$(CONFIG_FB_EP93XX) += ep93xx-fb.o -obj-$(CONFIG_FB_SA1100) += sa1100fb.o -obj-$(CONFIG_FB_HIT) += hitfb.o -obj-$(CONFIG_FB_ATMEL) += atmel_lcdfb.o -obj-$(CONFIG_FB_PVR2) += pvr2fb.o -obj-$(CONFIG_FB_VOODOO1) += sstfb.o -obj-$(CONFIG_FB_ARMCLCD) += amba-clcd.o -obj-$(CONFIG_ARCH_NOMADIK) += amba-clcd-nomadik.o -obj-$(CONFIG_PLAT_VERSATILE_CLCD) += amba-clcd-versatile.o -obj-$(CONFIG_FB_GOLDFISH) += goldfishfb.o -obj-$(CONFIG_FB_68328) += 68328fb.o -obj-$(CONFIG_FB_GBE) += gbefb.o -obj-$(CONFIG_FB_CIRRUS) += cirrusfb.o -obj-$(CONFIG_FB_ASILIANT) += asiliantfb.o -obj-$(CONFIG_FB_PXA) += pxafb.o -obj-$(CONFIG_FB_PXA168) += pxa168fb.o -obj-$(CONFIG_PXA3XX_GCU) += pxa3xx-gcu.o -obj-$(CONFIG_MMP_DISP) += mmp/ -obj-$(CONFIG_FB_W100) += w100fb.o -obj-$(CONFIG_FB_TMIO) += tmiofb.o -obj-$(CONFIG_FB_AU1100) += au1100fb.o -obj-$(CONFIG_FB_AU1200) += au1200fb.o -obj-$(CONFIG_FB_VT8500) += vt8500lcdfb.o -obj-$(CONFIG_FB_WM8505) += wm8505fb.o -obj-$(CONFIG_FB_PMAG_AA) += pmag-aa-fb.o -obj-$(CONFIG_FB_PMAG_BA) += pmag-ba-fb.o -obj-$(CONFIG_FB_PMAGB_B) += pmagb-b-fb.o -obj-$(CONFIG_FB_MAXINE) += maxinefb.o -obj-$(CONFIG_FB_METRONOME) += metronomefb.o -obj-$(CONFIG_FB_BROADSHEET) += broadsheetfb.o -obj-$(CONFIG_FB_AUO_K190X) += auo_k190x.o -obj-$(CONFIG_FB_AUO_K1900) += auo_k1900fb.o -obj-$(CONFIG_FB_AUO_K1901) += auo_k1901fb.o -obj-$(CONFIG_FB_S1D13XXX) += s1d13xxxfb.o -obj-$(CONFIG_FB_SH7760) += sh7760fb.o -obj-$(CONFIG_FB_IMX) += imxfb.o -obj-$(CONFIG_FB_S3C) += s3c-fb.o -obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o -obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o -obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o -obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o -obj-$(CONFIG_FB_PS3) += ps3fb.o -obj-$(CONFIG_FB_SM501) += sm501fb.o -obj-$(CONFIG_FB_UDL) += udlfb.o -obj-$(CONFIG_FB_SMSCUFX) += smscufx.o -obj-$(CONFIG_FB_XILINX) += xilinxfb.o -obj-$(CONFIG_FB_SH_MOBILE_MERAM) += sh_mobile_meram.o -obj-$(CONFIG_FB_SH_MOBILE_LCDC) += sh_mobile_lcdcfb.o -obj-$(CONFIG_FB_OMAP) += omap/ -obj-y += omap2/ -obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o -obj-$(CONFIG_FB_CARMINE) += carminefb.o -obj-$(CONFIG_FB_MB862XX) += mb862xx/ -obj-$(CONFIG_FB_NUC900) += nuc900fb.o -obj-$(CONFIG_FB_JZ4740) += jz4740_fb.o -obj-$(CONFIG_FB_PUV3_UNIGFX) += fb-puv3.o -obj-$(CONFIG_FB_HYPERV) += hyperv_fb.o -obj-$(CONFIG_FB_OPENCORES) += ocfb.o -obj-$(CONFIG_FB_SM712) += sm712fb.o - -# Platform or fallback drivers go here -obj-$(CONFIG_FB_UVESA) += uvesafb.o -obj-$(CONFIG_FB_VESA) += vesafb.o -obj-$(CONFIG_FB_EFI) += efifb.o -obj-$(CONFIG_FB_VGA16) += vga16fb.o -obj-$(CONFIG_FB_OF) += offb.o -obj-$(CONFIG_FB_BF537_LQ035) += bf537-lq035.o -obj-$(CONFIG_FB_BF54X_LQ043) += bf54x-lq043fb.o -obj-$(CONFIG_FB_BFIN_LQ035Q1) += bfin-lq035q1-fb.o -obj-$(CONFIG_FB_BFIN_T350MCQB) += bfin-t350mcqb-fb.o -obj-$(CONFIG_FB_BFIN_7393) += bfin_adv7393fb.o -obj-$(CONFIG_FB_MX3) += mx3fb.o -obj-$(CONFIG_FB_DA8XX) += da8xx-fb.o -obj-$(CONFIG_FB_MXS) += mxsfb.o -obj-$(CONFIG_FB_SSD1307) += ssd1307fb.o -obj-$(CONFIG_FB_SIMPLE) += simplefb.o - -# the test framebuffer is last -obj-$(CONFIG_FB_VIRTUAL) += vfb.o diff --git a/src/linux/drivers/video/fbdev/core/Makefile b/src/linux/drivers/video/fbdev/core/Makefile deleted file mode 100644 index 9e3ddf2..0000000 --- a/src/linux/drivers/video/fbdev/core/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -obj-$(CONFIG_FB_CMDLINE) += fb_cmdline.o -obj-$(CONFIG_FB_NOTIFY) += fb_notify.o -obj-$(CONFIG_FB) += fb.o -fb-y := fbmem.o fbmon.o fbcmap.o fbsysfs.o \ - modedb.o fbcvt.o -fb-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o -fb-objs := $(fb-y) - -obj-$(CONFIG_FB_CFB_FILLRECT) += cfbfillrect.o -obj-$(CONFIG_FB_CFB_COPYAREA) += cfbcopyarea.o -obj-$(CONFIG_FB_CFB_IMAGEBLIT) += cfbimgblt.o -obj-$(CONFIG_FB_SYS_FILLRECT) += sysfillrect.o -obj-$(CONFIG_FB_SYS_COPYAREA) += syscopyarea.o -obj-$(CONFIG_FB_SYS_IMAGEBLIT) += sysimgblt.o -obj-$(CONFIG_FB_SYS_FOPS) += fb_sys_fops.o -obj-$(CONFIG_FB_SVGALIB) += svgalib.o -obj-$(CONFIG_FB_DDC) += fb_ddc.o diff --git a/src/linux/drivers/video/fbdev/geode/Kconfig b/src/linux/drivers/video/fbdev/geode/Kconfig deleted file mode 100644 index 1e85552..0000000 --- a/src/linux/drivers/video/fbdev/geode/Kconfig +++ /dev/null @@ -1,54 +0,0 @@ -# -# Geode family framebuffer configuration -# -config FB_GEODE - bool "AMD Geode family framebuffer support" - depends on FB && PCI && (X86_32 || (X86 && COMPILE_TEST)) - ---help--- - Say 'Y' here to allow you to select framebuffer drivers for - the AMD Geode family of processors. - -config FB_GEODE_LX - tristate "AMD Geode LX framebuffer support" - depends on FB && FB_GEODE - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Framebuffer driver for the display controller integrated into the - AMD Geode LX processors. - - To compile this driver as a module, choose M here: the module will - be called lxfb. - - If unsure, say N. - -config FB_GEODE_GX - tristate "AMD Geode GX framebuffer support" - depends on FB && FB_GEODE - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Framebuffer driver for the display controller integrated into the - AMD Geode GX processors. - - To compile this driver as a module, choose M here: the module will be - called gxfb. - - If unsure, say N. - -config FB_GEODE_GX1 - tristate "AMD Geode GX1 framebuffer support" - depends on FB && FB_GEODE - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - ---help--- - Framebuffer driver for the display controller integrated into the - AMD Geode GX1 processor. - - To compile this driver as a module, choose M here: the module will be - called gx1fb. - - If unsure, say N. diff --git a/src/linux/drivers/video/fbdev/mmp/Kconfig b/src/linux/drivers/video/fbdev/mmp/Kconfig deleted file mode 100644 index f56a7e2..0000000 --- a/src/linux/drivers/video/fbdev/mmp/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -menuconfig MMP_DISP - tristate "Marvell MMP Display Subsystem support" - depends on CPU_PXA910 || CPU_MMP2 - help - Marvell Display Subsystem support. - -if MMP_DISP -source "drivers/video/fbdev/mmp/hw/Kconfig" -source "drivers/video/fbdev/mmp/panel/Kconfig" -source "drivers/video/fbdev/mmp/fb/Kconfig" -endif diff --git a/src/linux/drivers/video/fbdev/mmp/fb/Kconfig b/src/linux/drivers/video/fbdev/mmp/fb/Kconfig deleted file mode 100644 index 985e1a7..0000000 --- a/src/linux/drivers/video/fbdev/mmp/fb/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -if MMP_DISP - -config MMP_FB - tristate "fb driver for Marvell MMP Display Subsystem" - depends on FB - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - default y - help - fb driver for Marvell MMP Display Subsystem - -endif diff --git a/src/linux/drivers/video/fbdev/mmp/hw/Kconfig b/src/linux/drivers/video/fbdev/mmp/hw/Kconfig deleted file mode 100644 index c735d13..0000000 --- a/src/linux/drivers/video/fbdev/mmp/hw/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -if MMP_DISP - -config MMP_DISP_CONTROLLER - bool "mmp display controller hw support" - depends on CPU_PXA910 || CPU_MMP2 - default n - help - Marvell MMP display hw controller support - this controller is used on Marvell PXA910 and - MMP2 chips - -config MMP_DISP_SPI - bool "mmp display controller spi port" - depends on MMP_DISP_CONTROLLER && SPI_MASTER - default y - help - Marvell MMP display hw controller spi port support - will register as a spi master for panel usage - -endif diff --git a/src/linux/drivers/video/fbdev/mmp/panel/Kconfig b/src/linux/drivers/video/fbdev/mmp/panel/Kconfig deleted file mode 100644 index 4b2c4f4..0000000 --- a/src/linux/drivers/video/fbdev/mmp/panel/Kconfig +++ /dev/null @@ -1,6 +0,0 @@ -config MMP_PANEL_TPOHVGA - bool "tpohvga panel TJ032MD01BW support" - depends on SPI_MASTER - default n - help - tpohvga panel support diff --git a/src/linux/drivers/video/fbdev/omap/Kconfig b/src/linux/drivers/video/fbdev/omap/Kconfig deleted file mode 100644 index 29d250d..0000000 --- a/src/linux/drivers/video/fbdev/omap/Kconfig +++ /dev/null @@ -1,61 +0,0 @@ -config FB_OMAP - tristate "OMAP frame buffer support" - depends on FB - depends on ARCH_OMAP1 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Frame buffer driver for OMAP based boards. - -config FB_OMAP_LCDC_EXTERNAL - bool "External LCD controller support" - depends on FB_OMAP - help - Say Y here, if you want to have support for boards with an - external LCD controller connected to the SoSSI/RFBI interface. - -config FB_OMAP_LCDC_HWA742 - bool "Epson HWA742 LCD controller support" - depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL - help - Say Y here if you want to have support for the external - Epson HWA742 LCD controller. - -config FB_OMAP_MANUAL_UPDATE - bool "Default to manual update mode" - depends on FB_OMAP && FB_OMAP_LCDC_EXTERNAL - help - Say Y here, if your user-space applications are capable of - notifying the frame buffer driver when a change has occurred in - the frame buffer content and thus a reload of the image data to - the external frame buffer is required. If unsure, say N. - -config FB_OMAP_LCD_MIPID - bool "MIPI DBI-C/DCS compatible LCD support" - depends on FB_OMAP && SPI_MASTER - help - Say Y here if you want to have support for LCDs compatible with - the Mobile Industry Processor Interface DBI-C/DCS - specification. (Supported LCDs: Philips LPH8923, Sharp LS041Y3) - -config FB_OMAP_LCD_H3 - bool "TPS65010 LCD controller on OMAP-H3" - depends on MACH_OMAP_H3 - depends on TPS65010=y - default y - help - Say Y here if you want to have support for the LCD on the - H3 board. - -config FB_OMAP_DMA_TUNE - bool "Set DMA SDRAM access priority high" - depends on FB_OMAP - help - On systems in which video memory is in system memory - (SDRAM) this will speed up graphics DMA operations. - If you have such a system and want to use rotation - answer yes. Answer no if you have a dedicated video - memory, or don't use any of the accelerated features. - - diff --git a/src/linux/drivers/video/fbdev/omap2/Kconfig b/src/linux/drivers/video/fbdev/omap2/Kconfig deleted file mode 100644 index 0921c4d..0000000 --- a/src/linux/drivers/video/fbdev/omap2/Kconfig +++ /dev/null @@ -1,5 +0,0 @@ -if ARCH_OMAP2PLUS - -source "drivers/video/fbdev/omap2/omapfb/Kconfig" - -endif diff --git a/src/linux/drivers/video/fbdev/omap2/Makefile b/src/linux/drivers/video/fbdev/omap2/Makefile deleted file mode 100644 index 71ab5ac..0000000 --- a/src/linux/drivers/video/fbdev/omap2/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-y += omapfb/ diff --git a/src/linux/drivers/video/fbdev/omap2/omapfb/Kconfig b/src/linux/drivers/video/fbdev/omap2/omapfb/Kconfig deleted file mode 100644 index e6226ae..0000000 --- a/src/linux/drivers/video/fbdev/omap2/omapfb/Kconfig +++ /dev/null @@ -1,39 +0,0 @@ -config OMAP2_VRFB - bool - -menuconfig FB_OMAP2 - tristate "OMAP2+ frame buffer support" - depends on FB - depends on DRM_OMAP = n - - select FB_OMAP2_DSS - select OMAP2_VRFB if ARCH_OMAP2 || ARCH_OMAP3 - select FB_CFB_FILLRECT - select FB_CFB_COPYAREA - select FB_CFB_IMAGEBLIT - help - Frame buffer driver for OMAP2+ based boards. - -if FB_OMAP2 - -config FB_OMAP2_DEBUG_SUPPORT - bool "Debug support for OMAP2+ FB" - default y - depends on FB_OMAP2 - help - Support for debug output. You have to enable the actual printing - with 'debug' module parameter. - -config FB_OMAP2_NUM_FBS - int "Number of framebuffers" - range 1 10 - default 3 - depends on FB_OMAP2 - help - Select the number of framebuffers created. OMAP2/3 has 3 overlays - so normally this would be 3. - -source "drivers/video/fbdev/omap2/omapfb/dss/Kconfig" -source "drivers/video/fbdev/omap2/omapfb/displays/Kconfig" - -endif diff --git a/src/linux/drivers/video/fbdev/omap2/omapfb/Makefile b/src/linux/drivers/video/fbdev/omap2/omapfb/Makefile deleted file mode 100644 index ad68ecf..0000000 --- a/src/linux/drivers/video/fbdev/omap2/omapfb/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -obj-$(CONFIG_OMAP2_VRFB) += vrfb.o -obj-y += dss/ -obj-y += displays/ -obj-$(CONFIG_FB_OMAP2) += omapfb.o -omapfb-y := omapfb-main.o omapfb-sysfs.o omapfb-ioctl.o diff --git a/src/linux/drivers/video/fbdev/omap2/omapfb/displays/Kconfig b/src/linux/drivers/video/fbdev/omap2/omapfb/displays/Kconfig deleted file mode 100644 index 08f1203..0000000 --- a/src/linux/drivers/video/fbdev/omap2/omapfb/displays/Kconfig +++ /dev/null @@ -1,86 +0,0 @@ -menu "OMAPFB Panel and Encoder Drivers" - depends on FB_OMAP2_DSS - -config FB_OMAP2_ENCODER_OPA362 - tristate "OPA362 external analog amplifier" - help - Driver for OPA362 external analog TV amplifier controlled - through a GPIO. - -config FB_OMAP2_ENCODER_TFP410 - tristate "TFP410 DPI to DVI Encoder" - help - Driver for TFP410 DPI to DVI encoder. - -config FB_OMAP2_ENCODER_TPD12S015 - tristate "TPD12S015 HDMI ESD protection and level shifter" - help - Driver for TPD12S015, which offers HDMI ESD protection and level - shifting. - -config FB_OMAP2_CONNECTOR_DVI - tristate "DVI Connector" - depends on I2C - help - Driver for a generic DVI connector. - -config FB_OMAP2_CONNECTOR_HDMI - tristate "HDMI Connector" - help - Driver for a generic HDMI connector. - -config FB_OMAP2_CONNECTOR_ANALOG_TV - tristate "Analog TV Connector" - help - Driver for a generic analog TV connector. - -config FB_OMAP2_PANEL_DPI - tristate "Generic DPI panel" - help - Driver for generic DPI panels. - -config FB_OMAP2_PANEL_DSI_CM - tristate "Generic DSI Command Mode Panel" - depends on BACKLIGHT_CLASS_DEVICE - help - Driver for generic DSI command mode panels. - -config FB_OMAP2_PANEL_SONY_ACX565AKM - tristate "ACX565AKM Panel" - depends on SPI && BACKLIGHT_CLASS_DEVICE - help - This is the LCD panel used on Nokia N900 - -config FB_OMAP2_PANEL_LGPHILIPS_LB035Q02 - tristate "LG.Philips LB035Q02 LCD Panel" - depends on SPI - help - LCD Panel used on the Gumstix Overo Palo35 - -config FB_OMAP2_PANEL_SHARP_LS037V7DW01 - tristate "Sharp LS037V7DW01 LCD Panel" - depends on BACKLIGHT_CLASS_DEVICE - help - LCD Panel used in TI's SDP3430 and EVM boards - -config FB_OMAP2_PANEL_TPO_TD028TTEC1 - tristate "TPO TD028TTEC1 LCD Panel" - depends on SPI - help - LCD panel used in Openmoko. - -config FB_OMAP2_PANEL_TPO_TD043MTEA1 - tristate "TPO TD043MTEA1 LCD Panel" - depends on SPI - help - LCD Panel used in OMAP3 Pandora - -config FB_OMAP2_PANEL_NEC_NL8048HL11 - tristate "NEC NL8048HL11 Panel" - depends on SPI - depends on BACKLIGHT_CLASS_DEVICE - help - This NEC NL8048HL11 panel is TFT LCD used in the - Zoom2/3/3630 sdp boards. - -endmenu diff --git a/src/linux/drivers/video/fbdev/omap2/omapfb/displays/Makefile b/src/linux/drivers/video/fbdev/omap2/omapfb/displays/Makefile deleted file mode 100644 index 4f74592..0000000 --- a/src/linux/drivers/video/fbdev/omap2/omapfb/displays/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -obj-$(CONFIG_FB_OMAP2_ENCODER_OPA362) += encoder-opa362.o -obj-$(CONFIG_FB_OMAP2_ENCODER_TFP410) += encoder-tfp410.o -obj-$(CONFIG_FB_OMAP2_ENCODER_TPD12S015) += encoder-tpd12s015.o -obj-$(CONFIG_FB_OMAP2_CONNECTOR_DVI) += connector-dvi.o -obj-$(CONFIG_FB_OMAP2_CONNECTOR_HDMI) += connector-hdmi.o -obj-$(CONFIG_FB_OMAP2_CONNECTOR_ANALOG_TV) += connector-analog-tv.o -obj-$(CONFIG_FB_OMAP2_PANEL_DPI) += panel-dpi.o -obj-$(CONFIG_FB_OMAP2_PANEL_DSI_CM) += panel-dsi-cm.o -obj-$(CONFIG_FB_OMAP2_PANEL_SONY_ACX565AKM) += panel-sony-acx565akm.o -obj-$(CONFIG_FB_OMAP2_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o -obj-$(CONFIG_FB_OMAP2_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o -obj-$(CONFIG_FB_OMAP2_PANEL_TPO_TD028TTEC1) += panel-tpo-td028ttec1.o -obj-$(CONFIG_FB_OMAP2_PANEL_TPO_TD043MTEA1) += panel-tpo-td043mtea1.o -obj-$(CONFIG_FB_OMAP2_PANEL_NEC_NL8048HL11) += panel-nec-nl8048hl11.o diff --git a/src/linux/drivers/video/fbdev/omap2/omapfb/dss/Kconfig b/src/linux/drivers/video/fbdev/omap2/omapfb/dss/Kconfig deleted file mode 100644 index 27d2202..0000000 --- a/src/linux/drivers/video/fbdev/omap2/omapfb/dss/Kconfig +++ /dev/null @@ -1,129 +0,0 @@ -config FB_OMAP2_DSS_INIT - bool - -config FB_OMAP2_DSS - tristate - select VIDEOMODE_HELPERS - select FB_OMAP2_DSS_INIT - select HDMI - -config FB_OMAP2_DSS_DEBUG - bool "Debug support" - default n - help - This enables printing of debug messages. Alternatively, debug messages - can also be enabled by setting CONFIG_DYNAMIC_DEBUG and then setting - appropriate flags in /dynamic_debug/control. - -config FB_OMAP2_DSS_DEBUGFS - bool "Debugfs filesystem support" - depends on DEBUG_FS - default n - help - This enables debugfs for OMAPDSS at /omapdss. This enables - querying about clock configuration and register configuration of dss, - dispc, dsi, hdmi and rfbi. - -config FB_OMAP2_DSS_COLLECT_IRQ_STATS - bool "Collect DSS IRQ statistics" - depends on FB_OMAP2_DSS_DEBUGFS - default n - help - Collect DSS IRQ statistics, printable via debugfs. - - The statistics can be found from - /omapdss/dispc_irq for DISPC interrupts, and - /omapdss/dsi_irq for DSI interrupts. - -config FB_OMAP2_DSS_DPI - bool "DPI support" - default y - help - DPI Interface. This is the Parallel Display Interface. - -config FB_OMAP2_DSS_RFBI - bool "RFBI support" - depends on BROKEN - default n - help - MIPI DBI support (RFBI, Remote Framebuffer Interface, in Texas - Instrument's terminology). - - DBI is a bus between the host processor and a peripheral, - such as a display or a framebuffer chip. - - See http://www.mipi.org/ for DBI specifications. - -config FB_OMAP2_DSS_VENC - bool "VENC support" - default y - help - OMAP Video Encoder support for S-Video and composite TV-out. - -config FB_OMAP2_DSS_HDMI_COMMON - bool - -config FB_OMAP4_DSS_HDMI - bool "HDMI support for OMAP4" - default y - select FB_OMAP2_DSS_HDMI_COMMON - help - HDMI support for OMAP4 based SoCs. - -config FB_OMAP5_DSS_HDMI - bool "HDMI support for OMAP5" - default n - select FB_OMAP2_DSS_HDMI_COMMON - help - HDMI Interface for OMAP5 and similar cores. This adds the High - Definition Multimedia Interface. See http://www.hdmi.org/ for HDMI - specification. - -config FB_OMAP2_DSS_SDI - bool "SDI support" - default n - help - SDI (Serial Display Interface) support. - - SDI is a high speed one-way display serial bus between the host - processor and a display. - -config FB_OMAP2_DSS_DSI - bool "DSI support" - default n - help - MIPI DSI (Display Serial Interface) support. - - DSI is a high speed half-duplex serial interface between the host - processor and a peripheral, such as a display or a framebuffer chip. - - See http://www.mipi.org/ for DSI specifications. - -config FB_OMAP2_DSS_MIN_FCK_PER_PCK - int "Minimum FCK/PCK ratio (for scaling)" - range 0 32 - default 0 - help - This can be used to adjust the minimum FCK/PCK ratio. - - With this you can make sure that DISPC FCK is at least - n x PCK. Video plane scaling requires higher FCK than - normally. - - If this is set to 0, there's no extra constraint on the - DISPC FCK. However, the FCK will at minimum be - 2xPCK (if active matrix) or 3xPCK (if passive matrix). - - Max FCK is 173MHz, so this doesn't work if your PCK - is very high. - -config FB_OMAP2_DSS_SLEEP_AFTER_VENC_RESET - bool "Sleep 20ms after VENC reset" - default y - help - There is a 20ms sleep after VENC reset which seemed to fix the - reset. The reason for the bug is unclear, and it's also unclear - on what platforms this happens. - - This option enables the sleep, and is enabled by default. You can - disable the sleep if it doesn't cause problems on your platform. diff --git a/src/linux/drivers/video/fbdev/omap2/omapfb/dss/Makefile b/src/linux/drivers/video/fbdev/omap2/omapfb/dss/Makefile deleted file mode 100644 index 02308e2..0000000 --- a/src/linux/drivers/video/fbdev/omap2/omapfb/dss/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -obj-$(CONFIG_FB_OMAP2_DSS_INIT) += omapdss-boot-init.o -obj-$(CONFIG_FB_OMAP2_DSS) += omapdss.o -# Core DSS files -omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \ - output.o dss-of.o pll.o video-pll.o -# DSS compat layer files -omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \ - dispc-compat.o display-sysfs.o -omapdss-$(CONFIG_FB_OMAP2_DSS_DPI) += dpi.o -omapdss-$(CONFIG_FB_OMAP2_DSS_RFBI) += rfbi.o -omapdss-$(CONFIG_FB_OMAP2_DSS_VENC) += venc.o -omapdss-$(CONFIG_FB_OMAP2_DSS_SDI) += sdi.o -omapdss-$(CONFIG_FB_OMAP2_DSS_DSI) += dsi.o -omapdss-$(CONFIG_FB_OMAP2_DSS_HDMI_COMMON) += hdmi_common.o hdmi_wp.o hdmi_pll.o \ - hdmi_phy.o -omapdss-$(CONFIG_FB_OMAP4_DSS_HDMI) += hdmi4.o hdmi4_core.o -omapdss-$(CONFIG_FB_OMAP5_DSS_HDMI) += hdmi5.o hdmi5_core.o -ccflags-$(CONFIG_FB_OMAP2_DSS_DEBUG) += -DDEBUG diff --git a/src/linux/drivers/video/logo/.gitignore b/src/linux/drivers/video/logo/.gitignore deleted file mode 100644 index e48355f..0000000 --- a/src/linux/drivers/video/logo/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# -# Generated files -# -*_mono.c -*_vga16.c -*_clut224.c -*_gray256.c diff --git a/src/linux/drivers/video/logo/Kconfig b/src/linux/drivers/video/logo/Kconfig deleted file mode 100644 index 0037104..0000000 --- a/src/linux/drivers/video/logo/Kconfig +++ /dev/null @@ -1,85 +0,0 @@ -# -# Logo configuration -# - -menuconfig LOGO - bool "Bootup logo" - depends on FB || SGI_NEWPORT_CONSOLE - help - Enable and select frame buffer bootup logos. - -if LOGO - -config FB_LOGO_EXTRA - bool - depends on FB=y - default y if SPU_BASE - -config LOGO_LINUX_MONO - bool "Standard black and white Linux logo" - default y - -config LOGO_LINUX_VGA16 - bool "Standard 16-color Linux logo" - default y - -config LOGO_LINUX_CLUT224 - bool "Standard 224-color Linux logo" - default y - -config LOGO_BLACKFIN_VGA16 - bool "16-colour Blackfin Processor Linux logo" - depends on BLACKFIN - default y - -config LOGO_BLACKFIN_CLUT224 - bool "224-colour Blackfin Processor Linux logo" - depends on BLACKFIN - default y - -config LOGO_DEC_CLUT224 - bool "224-color Digital Equipment Corporation Linux logo" - depends on MACH_DECSTATION || ALPHA - default y - -config LOGO_MAC_CLUT224 - bool "224-color Macintosh Linux logo" - depends on MAC - default y - -config LOGO_PARISC_CLUT224 - bool "224-color PA-RISC Linux logo" - depends on PARISC - default y - -config LOGO_SGI_CLUT224 - bool "224-color SGI Linux logo" - depends on SGI_IP22 || SGI_IP27 || SGI_IP32 - default y - -config LOGO_SUN_CLUT224 - bool "224-color Sun Linux logo" - depends on SPARC - default y - -config LOGO_SUPERH_MONO - bool "Black and white SuperH Linux logo" - depends on SUPERH - default y - -config LOGO_SUPERH_VGA16 - bool "16-color SuperH Linux logo" - depends on SUPERH - default y - -config LOGO_SUPERH_CLUT224 - bool "224-color SuperH Linux logo" - depends on SUPERH - default y - -config LOGO_M32R_CLUT224 - bool "224-color M32R Linux logo" - depends on M32R - default y - -endif # LOGO diff --git a/src/linux/drivers/virt/Kconfig b/src/linux/drivers/virt/Kconfig deleted file mode 100644 index 99ebdde..0000000 --- a/src/linux/drivers/virt/Kconfig +++ /dev/null @@ -1,33 +0,0 @@ -# -# Virtualization support drivers -# - -menuconfig VIRT_DRIVERS - bool "Virtualization drivers" - ---help--- - Say Y here to get to see options for device drivers that support - virtualization environments. - - If you say N, all options in this submenu will be skipped and disabled. - -if VIRT_DRIVERS - -config FSL_HV_MANAGER - tristate "Freescale hypervisor management driver" - depends on FSL_SOC - select EPAPR_PARAVIRT - help - The Freescale hypervisor management driver provides several services - to drivers and applications related to the Freescale hypervisor: - - 1) An ioctl interface for querying and managing partitions. - - 2) A file interface to reading incoming doorbells. - - 3) An interrupt handler for shutting down the partition upon - receiving the shutdown doorbell from a manager partition. - - 4) A kernel interface for receiving callbacks when a managed - partition shuts down. - -endif diff --git a/src/linux/drivers/virtio/Kconfig b/src/linux/drivers/virtio/Kconfig deleted file mode 100644 index 7759032..0000000 --- a/src/linux/drivers/virtio/Kconfig +++ /dev/null @@ -1,82 +0,0 @@ -config VIRTIO - tristate - ---help--- - This option is selected by any driver which implements the virtio - bus, such as CONFIG_VIRTIO_PCI, CONFIG_VIRTIO_MMIO, CONFIG_LGUEST, - CONFIG_RPMSG or CONFIG_S390_GUEST. - -menu "Virtio drivers" - -config VIRTIO_PCI - tristate "PCI driver for virtio devices" - depends on PCI - select VIRTIO - ---help--- - This driver provides support for virtio based paravirtual device - drivers over PCI. This requires that your VMM has appropriate PCI - virtio backends. Most QEMU based VMMs should support these devices - (like KVM or Xen). - - If unsure, say M. - -config VIRTIO_PCI_LEGACY - bool "Support for legacy virtio draft 0.9.X and older devices" - default y - depends on VIRTIO_PCI - ---help--- - Virtio PCI Card 0.9.X Draft (circa 2014) and older device support. - - This option enables building a transitional driver, supporting - both devices conforming to Virtio 1 specification, and legacy devices. - If disabled, you get a slightly smaller, non-transitional driver, - with no legacy compatibility. - - So look out into your driveway. Do you have a flying car? If - so, you can happily disable this option and virtio will not - break. Otherwise, leave it set. Unless you're testing what - life will be like in The Future. - - If unsure, say Y. - -config VIRTIO_BALLOON - tristate "Virtio balloon driver" - depends on VIRTIO - select MEMORY_BALLOON - ---help--- - This driver supports increasing and decreasing the amount - of memory within a KVM guest. - - If unsure, say M. - -config VIRTIO_INPUT - tristate "Virtio input driver" - depends on VIRTIO - depends on INPUT - ---help--- - This driver supports virtio input devices such as - keyboards, mice and tablets. - - If unsure, say M. - - config VIRTIO_MMIO - tristate "Platform bus driver for memory mapped virtio devices" - depends on HAS_IOMEM && HAS_DMA - select VIRTIO - ---help--- - This drivers provides support for memory mapped virtio - platform device driver. - - If unsure, say N. - -config VIRTIO_MMIO_CMDLINE_DEVICES - bool "Memory mapped virtio devices parameter parsing" - depends on VIRTIO_MMIO - ---help--- - Allow virtio-mmio devices instantiation via the kernel command line - or module parameters. Be aware that using incorrect parameters (base - address in particular) can crash your system - you have been warned. - See Documentation/kernel-parameters.txt for details. - - If unsure, say 'N'. - -endmenu diff --git a/src/linux/drivers/virtio/Makefile b/src/linux/drivers/virtio/Makefile deleted file mode 100644 index 41e30e3..0000000 --- a/src/linux/drivers/virtio/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -obj-$(CONFIG_VIRTIO) += virtio.o virtio_ring.o -obj-$(CONFIG_VIRTIO_MMIO) += virtio_mmio.o -obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o -virtio_pci-y := virtio_pci_modern.o virtio_pci_common.o -virtio_pci-$(CONFIG_VIRTIO_PCI_LEGACY) += virtio_pci_legacy.o -obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o -obj-$(CONFIG_VIRTIO_INPUT) += virtio_input.o diff --git a/src/linux/drivers/virtio/virtio.c b/src/linux/drivers/virtio/virtio.c deleted file mode 100644 index 7062bb0..0000000 --- a/src/linux/drivers/virtio/virtio.c +++ /dev/null @@ -1,420 +0,0 @@ -#include -#include -#include -#include -#include -#include - -/* Unique numbering for virtio devices. */ -static DEFINE_IDA(virtio_index_ida); - -static ssize_t device_show(struct device *_d, - struct device_attribute *attr, char *buf) -{ - struct virtio_device *dev = dev_to_virtio(_d); - return sprintf(buf, "0x%04x\n", dev->id.device); -} -static DEVICE_ATTR_RO(device); - -static ssize_t vendor_show(struct device *_d, - struct device_attribute *attr, char *buf) -{ - struct virtio_device *dev = dev_to_virtio(_d); - return sprintf(buf, "0x%04x\n", dev->id.vendor); -} -static DEVICE_ATTR_RO(vendor); - -static ssize_t status_show(struct device *_d, - struct device_attribute *attr, char *buf) -{ - struct virtio_device *dev = dev_to_virtio(_d); - return sprintf(buf, "0x%08x\n", dev->config->get_status(dev)); -} -static DEVICE_ATTR_RO(status); - -static ssize_t modalias_show(struct device *_d, - struct device_attribute *attr, char *buf) -{ - struct virtio_device *dev = dev_to_virtio(_d); - return sprintf(buf, "virtio:d%08Xv%08X\n", - dev->id.device, dev->id.vendor); -} -static DEVICE_ATTR_RO(modalias); - -static ssize_t features_show(struct device *_d, - struct device_attribute *attr, char *buf) -{ - struct virtio_device *dev = dev_to_virtio(_d); - unsigned int i; - ssize_t len = 0; - - /* We actually represent this as a bitstring, as it could be - * arbitrary length in future. */ - for (i = 0; i < sizeof(dev->features)*8; i++) - len += sprintf(buf+len, "%c", - __virtio_test_bit(dev, i) ? '1' : '0'); - len += sprintf(buf+len, "\n"); - return len; -} -static DEVICE_ATTR_RO(features); - -static struct attribute *virtio_dev_attrs[] = { - &dev_attr_device.attr, - &dev_attr_vendor.attr, - &dev_attr_status.attr, - &dev_attr_modalias.attr, - &dev_attr_features.attr, - NULL, -}; -ATTRIBUTE_GROUPS(virtio_dev); - -static inline int virtio_id_match(const struct virtio_device *dev, - const struct virtio_device_id *id) -{ - if (id->device != dev->id.device && id->device != VIRTIO_DEV_ANY_ID) - return 0; - - return id->vendor == VIRTIO_DEV_ANY_ID || id->vendor == dev->id.vendor; -} - -/* This looks through all the IDs a driver claims to support. If any of them - * match, we return 1 and the kernel will call virtio_dev_probe(). */ -static int virtio_dev_match(struct device *_dv, struct device_driver *_dr) -{ - unsigned int i; - struct virtio_device *dev = dev_to_virtio(_dv); - const struct virtio_device_id *ids; - - ids = drv_to_virtio(_dr)->id_table; - for (i = 0; ids[i].device; i++) - if (virtio_id_match(dev, &ids[i])) - return 1; - return 0; -} - -static int virtio_uevent(struct device *_dv, struct kobj_uevent_env *env) -{ - struct virtio_device *dev = dev_to_virtio(_dv); - - return add_uevent_var(env, "MODALIAS=virtio:d%08Xv%08X", - dev->id.device, dev->id.vendor); -} - -static void add_status(struct virtio_device *dev, unsigned status) -{ - dev->config->set_status(dev, dev->config->get_status(dev) | status); -} - -void virtio_check_driver_offered_feature(const struct virtio_device *vdev, - unsigned int fbit) -{ - unsigned int i; - struct virtio_driver *drv = drv_to_virtio(vdev->dev.driver); - - for (i = 0; i < drv->feature_table_size; i++) - if (drv->feature_table[i] == fbit) - return; - - if (drv->feature_table_legacy) { - for (i = 0; i < drv->feature_table_size_legacy; i++) - if (drv->feature_table_legacy[i] == fbit) - return; - } - - BUG(); -} -EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature); - -static void __virtio_config_changed(struct virtio_device *dev) -{ - struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); - - if (!dev->config_enabled) - dev->config_change_pending = true; - else if (drv && drv->config_changed) - drv->config_changed(dev); -} - -void virtio_config_changed(struct virtio_device *dev) -{ - unsigned long flags; - - spin_lock_irqsave(&dev->config_lock, flags); - __virtio_config_changed(dev); - spin_unlock_irqrestore(&dev->config_lock, flags); -} -EXPORT_SYMBOL_GPL(virtio_config_changed); - -static void virtio_config_disable(struct virtio_device *dev) -{ - spin_lock_irq(&dev->config_lock); - dev->config_enabled = false; - spin_unlock_irq(&dev->config_lock); -} - -static void virtio_config_enable(struct virtio_device *dev) -{ - spin_lock_irq(&dev->config_lock); - dev->config_enabled = true; - if (dev->config_change_pending) - __virtio_config_changed(dev); - dev->config_change_pending = false; - spin_unlock_irq(&dev->config_lock); -} - -static int virtio_finalize_features(struct virtio_device *dev) -{ - int ret = dev->config->finalize_features(dev); - unsigned status; - - if (ret) - return ret; - - if (!virtio_has_feature(dev, VIRTIO_F_VERSION_1)) - return 0; - - add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK); - status = dev->config->get_status(dev); - if (!(status & VIRTIO_CONFIG_S_FEATURES_OK)) { - dev_err(&dev->dev, "virtio: device refuses features: %x\n", - status); - return -ENODEV; - } - return 0; -} - -static int virtio_dev_probe(struct device *_d) -{ - int err, i; - struct virtio_device *dev = dev_to_virtio(_d); - struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); - u64 device_features; - u64 driver_features; - u64 driver_features_legacy; - - /* We have a driver! */ - add_status(dev, VIRTIO_CONFIG_S_DRIVER); - - /* Figure out what features the device supports. */ - device_features = dev->config->get_features(dev); - - /* Figure out what features the driver supports. */ - driver_features = 0; - for (i = 0; i < drv->feature_table_size; i++) { - unsigned int f = drv->feature_table[i]; - BUG_ON(f >= 64); - driver_features |= (1ULL << f); - } - - /* Some drivers have a separate feature table for virtio v1.0 */ - if (drv->feature_table_legacy) { - driver_features_legacy = 0; - for (i = 0; i < drv->feature_table_size_legacy; i++) { - unsigned int f = drv->feature_table_legacy[i]; - BUG_ON(f >= 64); - driver_features_legacy |= (1ULL << f); - } - } else { - driver_features_legacy = driver_features; - } - - if (device_features & (1ULL << VIRTIO_F_VERSION_1)) - dev->features = driver_features & device_features; - else - dev->features = driver_features_legacy & device_features; - - /* Transport features always preserved to pass to finalize_features. */ - for (i = VIRTIO_TRANSPORT_F_START; i < VIRTIO_TRANSPORT_F_END; i++) - if (device_features & (1ULL << i)) - __virtio_set_bit(dev, i); - - err = virtio_finalize_features(dev); - if (err) - goto err; - - err = drv->probe(dev); - if (err) - goto err; - - /* If probe didn't do it, mark device DRIVER_OK ourselves. */ - if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK)) - virtio_device_ready(dev); - - if (drv->scan) - drv->scan(dev); - - virtio_config_enable(dev); - - return 0; -err: - add_status(dev, VIRTIO_CONFIG_S_FAILED); - return err; - -} - -static int virtio_dev_remove(struct device *_d) -{ - struct virtio_device *dev = dev_to_virtio(_d); - struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); - - virtio_config_disable(dev); - - drv->remove(dev); - - /* Driver should have reset device. */ - WARN_ON_ONCE(dev->config->get_status(dev)); - - /* Acknowledge the device's existence again. */ - add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE); - return 0; -} - -static struct bus_type virtio_bus = { - .name = "virtio", - .match = virtio_dev_match, - .dev_groups = virtio_dev_groups, - .uevent = virtio_uevent, - .probe = virtio_dev_probe, - .remove = virtio_dev_remove, -}; - -int register_virtio_driver(struct virtio_driver *driver) -{ - /* Catch this early. */ - BUG_ON(driver->feature_table_size && !driver->feature_table); - driver->driver.bus = &virtio_bus; - return driver_register(&driver->driver); -} -EXPORT_SYMBOL_GPL(register_virtio_driver); - -void unregister_virtio_driver(struct virtio_driver *driver) -{ - driver_unregister(&driver->driver); -} -EXPORT_SYMBOL_GPL(unregister_virtio_driver); - -int register_virtio_device(struct virtio_device *dev) -{ - int err; - - dev->dev.bus = &virtio_bus; - - /* Assign a unique device index and hence name. */ - err = ida_simple_get(&virtio_index_ida, 0, 0, GFP_KERNEL); - if (err < 0) - goto out; - - dev->index = err; - dev_set_name(&dev->dev, "virtio%u", dev->index); - - spin_lock_init(&dev->config_lock); - dev->config_enabled = false; - dev->config_change_pending = false; - - /* We always start by resetting the device, in case a previous - * driver messed it up. This also tests that code path a little. */ - dev->config->reset(dev); - - /* Acknowledge that we've seen the device. */ - add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE); - - INIT_LIST_HEAD(&dev->vqs); - - /* device_register() causes the bus infrastructure to look for a - * matching driver. */ - err = device_register(&dev->dev); -out: - if (err) - add_status(dev, VIRTIO_CONFIG_S_FAILED); - return err; -} -EXPORT_SYMBOL_GPL(register_virtio_device); - -void unregister_virtio_device(struct virtio_device *dev) -{ - int index = dev->index; /* save for after device release */ - - device_unregister(&dev->dev); - ida_simple_remove(&virtio_index_ida, index); -} -EXPORT_SYMBOL_GPL(unregister_virtio_device); - -#ifdef CONFIG_PM_SLEEP -int virtio_device_freeze(struct virtio_device *dev) -{ - struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); - - virtio_config_disable(dev); - - dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED; - - if (drv && drv->freeze) - return drv->freeze(dev); - - return 0; -} -EXPORT_SYMBOL_GPL(virtio_device_freeze); - -int virtio_device_restore(struct virtio_device *dev) -{ - struct virtio_driver *drv = drv_to_virtio(dev->dev.driver); - int ret; - - /* We always start by resetting the device, in case a previous - * driver messed it up. */ - dev->config->reset(dev); - - /* Acknowledge that we've seen the device. */ - add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE); - - /* Maybe driver failed before freeze. - * Restore the failed status, for debugging. */ - if (dev->failed) - add_status(dev, VIRTIO_CONFIG_S_FAILED); - - if (!drv) - return 0; - - /* We have a driver! */ - add_status(dev, VIRTIO_CONFIG_S_DRIVER); - - ret = virtio_finalize_features(dev); - if (ret) - goto err; - - if (drv->restore) { - ret = drv->restore(dev); - if (ret) - goto err; - } - - /* Finally, tell the device we're all set */ - add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); - - virtio_config_enable(dev); - - return 0; - -err: - add_status(dev, VIRTIO_CONFIG_S_FAILED); - return ret; -} -EXPORT_SYMBOL_GPL(virtio_device_restore); -#endif - -static int virtio_init(void) -{ - if (bus_register(&virtio_bus) != 0) - panic("virtio bus registration failed"); - return 0; -} - -static void __exit virtio_exit(void) -{ - bus_unregister(&virtio_bus); - ida_destroy(&virtio_index_ida); -} -core_initcall(virtio_init); -module_exit(virtio_exit); - -MODULE_LICENSE("GPL"); diff --git a/src/linux/drivers/virtio/virtio_mmio.c b/src/linux/drivers/virtio/virtio_mmio.c deleted file mode 100644 index 48bfea9..0000000 --- a/src/linux/drivers/virtio/virtio_mmio.c +++ /dev/null @@ -1,733 +0,0 @@ -/* - * Virtio memory mapped device driver - * - * Copyright 2011-2014, ARM Ltd. - * - * This module allows virtio devices to be used over a virtual, memory mapped - * platform device. - * - * The guest device(s) may be instantiated in one of three equivalent ways: - * - * 1. Static platform device in board's code, eg.: - * - * static struct platform_device v2m_virtio_device = { - * .name = "virtio-mmio", - * .id = -1, - * .num_resources = 2, - * .resource = (struct resource []) { - * { - * .start = 0x1001e000, - * .end = 0x1001e0ff, - * .flags = IORESOURCE_MEM, - * }, { - * .start = 42 + 32, - * .end = 42 + 32, - * .flags = IORESOURCE_IRQ, - * }, - * } - * }; - * - * 2. Device Tree node, eg.: - * - * virtio_block@1e000 { - * compatible = "virtio,mmio"; - * reg = <0x1e000 0x100>; - * interrupts = <42>; - * } - * - * 3. Kernel module (or command line) parameter. Can be used more than once - - * one device will be created for each one. Syntax: - * - * [virtio_mmio.]device=@:[:] - * where: - * := size (can use standard suffixes like K, M or G) - * := physical base address - * := interrupt number (as passed to request_irq()) - * := (optional) platform device id - * eg.: - * virtio_mmio.device=0x100@0x100b0000:48 \ - * virtio_mmio.device=1K@0x1001e000:74 - * - * - * - * Based on Virtio PCI driver by Anthony Liguori, copyright IBM Corp. 2007 - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - */ - -#define pr_fmt(fmt) "virtio-mmio: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - - -/* The alignment to use between consumer and producer parts of vring. - * Currently hardcoded to the page size. */ -#define VIRTIO_MMIO_VRING_ALIGN PAGE_SIZE - - - -#define to_virtio_mmio_device(_plat_dev) \ - container_of(_plat_dev, struct virtio_mmio_device, vdev) - -struct virtio_mmio_device { - struct virtio_device vdev; - struct platform_device *pdev; - - void __iomem *base; - unsigned long version; - - /* a list of queues so we can dispatch IRQs */ - spinlock_t lock; - struct list_head virtqueues; -}; - -struct virtio_mmio_vq_info { - /* the actual virtqueue */ - struct virtqueue *vq; - - /* the list node for the virtqueues list */ - struct list_head node; -}; - - - -/* Configuration interface */ - -static u64 vm_get_features(struct virtio_device *vdev) -{ - struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); - u64 features; - - writel(1, vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL); - features = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES); - features <<= 32; - - writel(0, vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL); - features |= readl(vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES); - - return features; -} - -static int vm_finalize_features(struct virtio_device *vdev) -{ - struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); - - /* Give virtio_ring a chance to accept features. */ - vring_transport_features(vdev); - - /* Make sure there is are no mixed devices */ - if (vm_dev->version == 2 && - !__virtio_test_bit(vdev, VIRTIO_F_VERSION_1)) { - dev_err(&vdev->dev, "New virtio-mmio devices (version 2) must provide VIRTIO_F_VERSION_1 feature!\n"); - return -EINVAL; - } - - writel(1, vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL); - writel((u32)(vdev->features >> 32), - vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES); - - writel(0, vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL); - writel((u32)vdev->features, - vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES); - - return 0; -} - -static void vm_get(struct virtio_device *vdev, unsigned offset, - void *buf, unsigned len) -{ - struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); - void __iomem *base = vm_dev->base + VIRTIO_MMIO_CONFIG; - u8 b; - __le16 w; - __le32 l; - - if (vm_dev->version == 1) { - u8 *ptr = buf; - int i; - - for (i = 0; i < len; i++) - ptr[i] = readb(base + offset + i); - return; - } - - switch (len) { - case 1: - b = readb(base + offset); - memcpy(buf, &b, sizeof b); - break; - case 2: - w = cpu_to_le16(readw(base + offset)); - memcpy(buf, &w, sizeof w); - break; - case 4: - l = cpu_to_le32(readl(base + offset)); - memcpy(buf, &l, sizeof l); - break; - case 8: - l = cpu_to_le32(readl(base + offset)); - memcpy(buf, &l, sizeof l); - l = cpu_to_le32(ioread32(base + offset + sizeof l)); - memcpy(buf + sizeof l, &l, sizeof l); - break; - default: - BUG(); - } -} - -static void vm_set(struct virtio_device *vdev, unsigned offset, - const void *buf, unsigned len) -{ - struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); - void __iomem *base = vm_dev->base + VIRTIO_MMIO_CONFIG; - u8 b; - __le16 w; - __le32 l; - - if (vm_dev->version == 1) { - const u8 *ptr = buf; - int i; - - for (i = 0; i < len; i++) - writeb(ptr[i], base + offset + i); - - return; - } - - switch (len) { - case 1: - memcpy(&b, buf, sizeof b); - writeb(b, base + offset); - break; - case 2: - memcpy(&w, buf, sizeof w); - writew(le16_to_cpu(w), base + offset); - break; - case 4: - memcpy(&l, buf, sizeof l); - writel(le32_to_cpu(l), base + offset); - break; - case 8: - memcpy(&l, buf, sizeof l); - writel(le32_to_cpu(l), base + offset); - memcpy(&l, buf + sizeof l, sizeof l); - writel(le32_to_cpu(l), base + offset + sizeof l); - break; - default: - BUG(); - } -} - -static u32 vm_generation(struct virtio_device *vdev) -{ - struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); - - if (vm_dev->version == 1) - return 0; - else - return readl(vm_dev->base + VIRTIO_MMIO_CONFIG_GENERATION); -} - -static u8 vm_get_status(struct virtio_device *vdev) -{ - struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); - - return readl(vm_dev->base + VIRTIO_MMIO_STATUS) & 0xff; -} - -static void vm_set_status(struct virtio_device *vdev, u8 status) -{ - struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); - - /* We should never be setting status to 0. */ - BUG_ON(status == 0); - - writel(status, vm_dev->base + VIRTIO_MMIO_STATUS); -} - -static void vm_reset(struct virtio_device *vdev) -{ - struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); - - /* 0 status means a reset. */ - writel(0, vm_dev->base + VIRTIO_MMIO_STATUS); -} - - - -/* Transport interface */ - -/* the notify function used when creating a virt queue */ -static bool vm_notify(struct virtqueue *vq) -{ - struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vq->vdev); - - /* We write the queue's selector into the notification register to - * signal the other end */ - writel(vq->index, vm_dev->base + VIRTIO_MMIO_QUEUE_NOTIFY); - return true; -} - -/* Notify all virtqueues on an interrupt. */ -static irqreturn_t vm_interrupt(int irq, void *opaque) -{ - struct virtio_mmio_device *vm_dev = opaque; - struct virtio_mmio_vq_info *info; - unsigned long status; - unsigned long flags; - irqreturn_t ret = IRQ_NONE; - - /* Read and acknowledge interrupts */ - status = readl(vm_dev->base + VIRTIO_MMIO_INTERRUPT_STATUS); - writel(status, vm_dev->base + VIRTIO_MMIO_INTERRUPT_ACK); - - if (unlikely(status & VIRTIO_MMIO_INT_CONFIG)) { - virtio_config_changed(&vm_dev->vdev); - ret = IRQ_HANDLED; - } - - if (likely(status & VIRTIO_MMIO_INT_VRING)) { - spin_lock_irqsave(&vm_dev->lock, flags); - list_for_each_entry(info, &vm_dev->virtqueues, node) - ret |= vring_interrupt(irq, info->vq); - spin_unlock_irqrestore(&vm_dev->lock, flags); - } - - return ret; -} - - - -static void vm_del_vq(struct virtqueue *vq) -{ - struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vq->vdev); - struct virtio_mmio_vq_info *info = vq->priv; - unsigned long flags; - unsigned int index = vq->index; - - spin_lock_irqsave(&vm_dev->lock, flags); - list_del(&info->node); - spin_unlock_irqrestore(&vm_dev->lock, flags); - - /* Select and deactivate the queue */ - writel(index, vm_dev->base + VIRTIO_MMIO_QUEUE_SEL); - if (vm_dev->version == 1) { - writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); - } else { - writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_READY); - WARN_ON(readl(vm_dev->base + VIRTIO_MMIO_QUEUE_READY)); - } - - vring_del_virtqueue(vq); - - kfree(info); -} - -static void vm_del_vqs(struct virtio_device *vdev) -{ - struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); - struct virtqueue *vq, *n; - - list_for_each_entry_safe(vq, n, &vdev->vqs, list) - vm_del_vq(vq); - - free_irq(platform_get_irq(vm_dev->pdev, 0), vm_dev); -} - -static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index, - void (*callback)(struct virtqueue *vq), - const char *name) -{ - struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); - struct virtio_mmio_vq_info *info; - struct virtqueue *vq; - unsigned long flags; - unsigned int num; - int err; - - if (!name) - return NULL; - - /* Select the queue we're interested in */ - writel(index, vm_dev->base + VIRTIO_MMIO_QUEUE_SEL); - - /* Queue shouldn't already be set up. */ - if (readl(vm_dev->base + (vm_dev->version == 1 ? - VIRTIO_MMIO_QUEUE_PFN : VIRTIO_MMIO_QUEUE_READY))) { - err = -ENOENT; - goto error_available; - } - - /* Allocate and fill out our active queue description */ - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) { - err = -ENOMEM; - goto error_kmalloc; - } - - num = readl(vm_dev->base + VIRTIO_MMIO_QUEUE_NUM_MAX); - if (num == 0) { - err = -ENOENT; - goto error_new_virtqueue; - } - - /* Create the vring */ - vq = vring_create_virtqueue(index, num, VIRTIO_MMIO_VRING_ALIGN, vdev, - true, true, vm_notify, callback, name); - if (!vq) { - err = -ENOMEM; - goto error_new_virtqueue; - } - - /* Activate the queue */ - writel(virtqueue_get_vring_size(vq), vm_dev->base + VIRTIO_MMIO_QUEUE_NUM); - if (vm_dev->version == 1) { - writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_QUEUE_ALIGN); - writel(virtqueue_get_desc_addr(vq) >> PAGE_SHIFT, - vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); - } else { - u64 addr; - - addr = virtqueue_get_desc_addr(vq); - writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_DESC_LOW); - writel((u32)(addr >> 32), - vm_dev->base + VIRTIO_MMIO_QUEUE_DESC_HIGH); - - addr = virtqueue_get_avail_addr(vq); - writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_AVAIL_LOW); - writel((u32)(addr >> 32), - vm_dev->base + VIRTIO_MMIO_QUEUE_AVAIL_HIGH); - - addr = virtqueue_get_used_addr(vq); - writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_USED_LOW); - writel((u32)(addr >> 32), - vm_dev->base + VIRTIO_MMIO_QUEUE_USED_HIGH); - - writel(1, vm_dev->base + VIRTIO_MMIO_QUEUE_READY); - } - - vq->priv = info; - info->vq = vq; - - spin_lock_irqsave(&vm_dev->lock, flags); - list_add(&info->node, &vm_dev->virtqueues); - spin_unlock_irqrestore(&vm_dev->lock, flags); - - return vq; - -error_new_virtqueue: - if (vm_dev->version == 1) { - writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN); - } else { - writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_READY); - WARN_ON(readl(vm_dev->base + VIRTIO_MMIO_QUEUE_READY)); - } - kfree(info); -error_kmalloc: -error_available: - return ERR_PTR(err); -} - -static int vm_find_vqs(struct virtio_device *vdev, unsigned nvqs, - struct virtqueue *vqs[], - vq_callback_t *callbacks[], - const char * const names[]) -{ - struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); - unsigned int irq = platform_get_irq(vm_dev->pdev, 0); - int i, err; - - err = request_irq(irq, vm_interrupt, IRQF_SHARED, - dev_name(&vdev->dev), vm_dev); - if (err) - return err; - - for (i = 0; i < nvqs; ++i) { - vqs[i] = vm_setup_vq(vdev, i, callbacks[i], names[i]); - if (IS_ERR(vqs[i])) { - vm_del_vqs(vdev); - return PTR_ERR(vqs[i]); - } - } - - return 0; -} - -static const char *vm_bus_name(struct virtio_device *vdev) -{ - struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev); - - return vm_dev->pdev->name; -} - -static const struct virtio_config_ops virtio_mmio_config_ops = { - .get = vm_get, - .set = vm_set, - .generation = vm_generation, - .get_status = vm_get_status, - .set_status = vm_set_status, - .reset = vm_reset, - .find_vqs = vm_find_vqs, - .del_vqs = vm_del_vqs, - .get_features = vm_get_features, - .finalize_features = vm_finalize_features, - .bus_name = vm_bus_name, -}; - - - -/* Platform device */ - -static int virtio_mmio_probe(struct platform_device *pdev) -{ - struct virtio_mmio_device *vm_dev; - struct resource *mem; - unsigned long magic; - - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) - return -EINVAL; - - if (!devm_request_mem_region(&pdev->dev, mem->start, - resource_size(mem), pdev->name)) - return -EBUSY; - - vm_dev = devm_kzalloc(&pdev->dev, sizeof(*vm_dev), GFP_KERNEL); - if (!vm_dev) - return -ENOMEM; - - vm_dev->vdev.dev.parent = &pdev->dev; - vm_dev->vdev.config = &virtio_mmio_config_ops; - vm_dev->pdev = pdev; - INIT_LIST_HEAD(&vm_dev->virtqueues); - spin_lock_init(&vm_dev->lock); - - vm_dev->base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem)); - if (vm_dev->base == NULL) - return -EFAULT; - - /* Check magic value */ - magic = readl(vm_dev->base + VIRTIO_MMIO_MAGIC_VALUE); - if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24)) { - dev_warn(&pdev->dev, "Wrong magic value 0x%08lx!\n", magic); - return -ENODEV; - } - - /* Check device version */ - vm_dev->version = readl(vm_dev->base + VIRTIO_MMIO_VERSION); - if (vm_dev->version < 1 || vm_dev->version > 2) { - dev_err(&pdev->dev, "Version %ld not supported!\n", - vm_dev->version); - return -ENXIO; - } - - vm_dev->vdev.id.device = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_ID); - if (vm_dev->vdev.id.device == 0) { - /* - * virtio-mmio device with an ID 0 is a (dummy) placeholder - * with no function. End probing now with no error reported. - */ - return -ENODEV; - } - vm_dev->vdev.id.vendor = readl(vm_dev->base + VIRTIO_MMIO_VENDOR_ID); - - if (vm_dev->version == 1) - writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_GUEST_PAGE_SIZE); - - platform_set_drvdata(pdev, vm_dev); - - return register_virtio_device(&vm_dev->vdev); -} - -static int virtio_mmio_remove(struct platform_device *pdev) -{ - struct virtio_mmio_device *vm_dev = platform_get_drvdata(pdev); - - unregister_virtio_device(&vm_dev->vdev); - - return 0; -} - - - -/* Devices list parameter */ - -#if defined(CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES) - -static struct device vm_cmdline_parent = { - .init_name = "virtio-mmio-cmdline", -}; - -static int vm_cmdline_parent_registered; -static int vm_cmdline_id; - -static int vm_cmdline_set(const char *device, - const struct kernel_param *kp) -{ - int err; - struct resource resources[2] = {}; - char *str; - long long int base, size; - unsigned int irq; - int processed, consumed = 0; - struct platform_device *pdev; - - /* Consume "size" part of the command line parameter */ - size = memparse(device, &str); - - /* Get "@:[:]" chunks */ - processed = sscanf(str, "@%lli:%u%n:%d%n", - &base, &irq, &consumed, - &vm_cmdline_id, &consumed); - - /* - * sscanf() must processes at least 2 chunks; also there - * must be no extra characters after the last chunk, so - * str[consumed] must be '\0' - */ - if (processed < 2 || str[consumed]) - return -EINVAL; - - resources[0].flags = IORESOURCE_MEM; - resources[0].start = base; - resources[0].end = base + size - 1; - - resources[1].flags = IORESOURCE_IRQ; - resources[1].start = resources[1].end = irq; - - if (!vm_cmdline_parent_registered) { - err = device_register(&vm_cmdline_parent); - if (err) { - pr_err("Failed to register parent device!\n"); - return err; - } - vm_cmdline_parent_registered = 1; - } - - pr_info("Registering device virtio-mmio.%d at 0x%llx-0x%llx, IRQ %d.\n", - vm_cmdline_id, - (unsigned long long)resources[0].start, - (unsigned long long)resources[0].end, - (int)resources[1].start); - - pdev = platform_device_register_resndata(&vm_cmdline_parent, - "virtio-mmio", vm_cmdline_id++, - resources, ARRAY_SIZE(resources), NULL, 0); - if (IS_ERR(pdev)) - return PTR_ERR(pdev); - - return 0; -} - -static int vm_cmdline_get_device(struct device *dev, void *data) -{ - char *buffer = data; - unsigned int len = strlen(buffer); - struct platform_device *pdev = to_platform_device(dev); - - snprintf(buffer + len, PAGE_SIZE - len, "0x%llx@0x%llx:%llu:%d\n", - pdev->resource[0].end - pdev->resource[0].start + 1ULL, - (unsigned long long)pdev->resource[0].start, - (unsigned long long)pdev->resource[1].start, - pdev->id); - return 0; -} - -static int vm_cmdline_get(char *buffer, const struct kernel_param *kp) -{ - buffer[0] = '\0'; - device_for_each_child(&vm_cmdline_parent, buffer, - vm_cmdline_get_device); - return strlen(buffer) + 1; -} - -static const struct kernel_param_ops vm_cmdline_param_ops = { - .set = vm_cmdline_set, - .get = vm_cmdline_get, -}; - -device_param_cb(device, &vm_cmdline_param_ops, NULL, S_IRUSR); - -static int vm_unregister_cmdline_device(struct device *dev, - void *data) -{ - platform_device_unregister(to_platform_device(dev)); - - return 0; -} - -static void vm_unregister_cmdline_devices(void) -{ - if (vm_cmdline_parent_registered) { - device_for_each_child(&vm_cmdline_parent, NULL, - vm_unregister_cmdline_device); - device_unregister(&vm_cmdline_parent); - vm_cmdline_parent_registered = 0; - } -} - -#else - -static void vm_unregister_cmdline_devices(void) -{ -} - -#endif - -/* Platform driver */ - -static struct of_device_id virtio_mmio_match[] = { - { .compatible = "virtio,mmio", }, - {}, -}; -MODULE_DEVICE_TABLE(of, virtio_mmio_match); - -#ifdef CONFIG_ACPI -static const struct acpi_device_id virtio_mmio_acpi_match[] = { - { "LNRO0005", }, - { } -}; -MODULE_DEVICE_TABLE(acpi, virtio_mmio_acpi_match); -#endif - -static struct platform_driver virtio_mmio_driver = { - .probe = virtio_mmio_probe, - .remove = virtio_mmio_remove, - .driver = { - .name = "virtio-mmio", - .of_match_table = virtio_mmio_match, - .acpi_match_table = ACPI_PTR(virtio_mmio_acpi_match), - }, -}; - -static int __init virtio_mmio_init(void) -{ - return platform_driver_register(&virtio_mmio_driver); -} - -static void __exit virtio_mmio_exit(void) -{ - platform_driver_unregister(&virtio_mmio_driver); - vm_unregister_cmdline_devices(); -} - -module_init(virtio_mmio_init); -module_exit(virtio_mmio_exit); - -MODULE_AUTHOR("Pawel Moll "); -MODULE_DESCRIPTION("Platform bus driver for memory mapped virtio devices"); -MODULE_LICENSE("GPL"); diff --git a/src/linux/drivers/virtio/virtio_ring.c b/src/linux/drivers/virtio/virtio_ring.c deleted file mode 100644 index 489bfc6..0000000 --- a/src/linux/drivers/virtio/virtio_ring.c +++ /dev/null @@ -1,1207 +0,0 @@ -/* Virtio ring implementation. - * - * Copyright 2007 Rusty Russell IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef DEBUG -/* For development, we want to crash whenever the ring is screwed. */ -#define BAD_RING(_vq, fmt, args...) \ - do { \ - dev_err(&(_vq)->vq.vdev->dev, \ - "%s:"fmt, (_vq)->vq.name, ##args); \ - BUG(); \ - } while (0) -/* Caller is supposed to guarantee no reentry. */ -#define START_USE(_vq) \ - do { \ - if ((_vq)->in_use) \ - panic("%s:in_use = %i\n", \ - (_vq)->vq.name, (_vq)->in_use); \ - (_vq)->in_use = __LINE__; \ - } while (0) -#define END_USE(_vq) \ - do { BUG_ON(!(_vq)->in_use); (_vq)->in_use = 0; } while(0) -#else -#define BAD_RING(_vq, fmt, args...) \ - do { \ - dev_err(&_vq->vq.vdev->dev, \ - "%s:"fmt, (_vq)->vq.name, ##args); \ - (_vq)->broken = true; \ - } while (0) -#define START_USE(vq) -#define END_USE(vq) -#endif - -struct vring_desc_state { - void *data; /* Data for callback. */ - struct vring_desc *indir_desc; /* Indirect descriptor, if any. */ -}; - -struct vring_virtqueue { - struct virtqueue vq; - - /* Actual memory layout for this queue */ - struct vring vring; - - /* Can we use weak barriers? */ - bool weak_barriers; - - /* Other side has made a mess, don't try any more. */ - bool broken; - - /* Host supports indirect buffers */ - bool indirect; - - /* Host publishes avail event idx */ - bool event; - - /* Head of free buffer list. */ - unsigned int free_head; - /* Number we've added since last sync. */ - unsigned int num_added; - - /* Last used index we've seen. */ - u16 last_used_idx; - - /* Last written value to avail->flags */ - u16 avail_flags_shadow; - - /* Last written value to avail->idx in guest byte order */ - u16 avail_idx_shadow; - - /* How to notify other side. FIXME: commonalize hcalls! */ - bool (*notify)(struct virtqueue *vq); - - /* DMA, allocation, and size information */ - bool we_own_ring; - size_t queue_size_in_bytes; - dma_addr_t queue_dma_addr; - -#ifdef DEBUG - /* They're supposed to lock for us. */ - unsigned int in_use; - - /* Figure out if their kicks are too delayed. */ - bool last_add_time_valid; - ktime_t last_add_time; -#endif - - /* Per-descriptor state. */ - struct vring_desc_state desc_state[]; -}; - -#define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq) - -/* - * Modern virtio devices have feature bits to specify whether they need a - * quirk and bypass the IOMMU. If not there, just use the DMA API. - * - * If there, the interaction between virtio and DMA API is messy. - * - * On most systems with virtio, physical addresses match bus addresses, - * and it doesn't particularly matter whether we use the DMA API. - * - * On some systems, including Xen and any system with a physical device - * that speaks virtio behind a physical IOMMU, we must use the DMA API - * for virtio DMA to work at all. - * - * On other systems, including SPARC and PPC64, virtio-pci devices are - * enumerated as though they are behind an IOMMU, but the virtio host - * ignores the IOMMU, so we must either pretend that the IOMMU isn't - * there or somehow map everything as the identity. - * - * For the time being, we preserve historic behavior and bypass the DMA - * API. - * - * TODO: install a per-device DMA ops structure that does the right thing - * taking into account all the above quirks, and use the DMA API - * unconditionally on data path. - */ - -static bool vring_use_dma_api(struct virtio_device *vdev) -{ - if (!virtio_has_iommu_quirk(vdev)) - return true; - - /* Otherwise, we are left to guess. */ - /* - * In theory, it's possible to have a buggy QEMU-supposed - * emulated Q35 IOMMU and Xen enabled at the same time. On - * such a configuration, virtio has never worked and will - * not work without an even larger kludge. Instead, enable - * the DMA API if we're a Xen guest, which at least allows - * all of the sensible Xen configurations to work correctly. - */ - if (xen_domain()) - return true; - - return false; -} - -/* - * The DMA ops on various arches are rather gnarly right now, and - * making all of the arch DMA ops work on the vring device itself - * is a mess. For now, we use the parent device for DMA ops. - */ -static inline struct device *vring_dma_dev(const struct vring_virtqueue *vq) -{ - return vq->vq.vdev->dev.parent; -} - -/* Map one sg entry. */ -static dma_addr_t vring_map_one_sg(const struct vring_virtqueue *vq, - struct scatterlist *sg, - enum dma_data_direction direction) -{ - if (!vring_use_dma_api(vq->vq.vdev)) - return (dma_addr_t)sg_phys(sg); - - /* - * We can't use dma_map_sg, because we don't use scatterlists in - * the way it expects (we don't guarantee that the scatterlist - * will exist for the lifetime of the mapping). - */ - return dma_map_page(vring_dma_dev(vq), - sg_page(sg), sg->offset, sg->length, - direction); -} - -static dma_addr_t vring_map_single(const struct vring_virtqueue *vq, - void *cpu_addr, size_t size, - enum dma_data_direction direction) -{ - if (!vring_use_dma_api(vq->vq.vdev)) - return (dma_addr_t)virt_to_phys(cpu_addr); - - return dma_map_single(vring_dma_dev(vq), - cpu_addr, size, direction); -} - -static void vring_unmap_one(const struct vring_virtqueue *vq, - struct vring_desc *desc) -{ - u16 flags; - - if (!vring_use_dma_api(vq->vq.vdev)) - return; - - flags = virtio16_to_cpu(vq->vq.vdev, desc->flags); - - if (flags & VRING_DESC_F_INDIRECT) { - dma_unmap_single(vring_dma_dev(vq), - virtio64_to_cpu(vq->vq.vdev, desc->addr), - virtio32_to_cpu(vq->vq.vdev, desc->len), - (flags & VRING_DESC_F_WRITE) ? - DMA_FROM_DEVICE : DMA_TO_DEVICE); - } else { - dma_unmap_page(vring_dma_dev(vq), - virtio64_to_cpu(vq->vq.vdev, desc->addr), - virtio32_to_cpu(vq->vq.vdev, desc->len), - (flags & VRING_DESC_F_WRITE) ? - DMA_FROM_DEVICE : DMA_TO_DEVICE); - } -} - -static int vring_mapping_error(const struct vring_virtqueue *vq, - dma_addr_t addr) -{ - if (!vring_use_dma_api(vq->vq.vdev)) - return 0; - - return dma_mapping_error(vring_dma_dev(vq), addr); -} - -static struct vring_desc *alloc_indirect(struct virtqueue *_vq, - unsigned int total_sg, gfp_t gfp) -{ - struct vring_desc *desc; - unsigned int i; - - /* - * We require lowmem mappings for the descriptors because - * otherwise virt_to_phys will give us bogus addresses in the - * virtqueue. - */ - gfp &= ~__GFP_HIGHMEM; - - desc = kmalloc(total_sg * sizeof(struct vring_desc), gfp); - if (!desc) - return NULL; - - for (i = 0; i < total_sg; i++) - desc[i].next = cpu_to_virtio16(_vq->vdev, i + 1); - return desc; -} - -static inline int virtqueue_add(struct virtqueue *_vq, - struct scatterlist *sgs[], - unsigned int total_sg, - unsigned int out_sgs, - unsigned int in_sgs, - void *data, - gfp_t gfp) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - struct scatterlist *sg; - struct vring_desc *desc; - unsigned int i, n, avail, descs_used, uninitialized_var(prev), err_idx; - int head; - bool indirect; - - START_USE(vq); - - BUG_ON(data == NULL); - - if (unlikely(vq->broken)) { - END_USE(vq); - return -EIO; - } - -#ifdef DEBUG - { - ktime_t now = ktime_get(); - - /* No kick or get, with .1 second between? Warn. */ - if (vq->last_add_time_valid) - WARN_ON(ktime_to_ms(ktime_sub(now, vq->last_add_time)) - > 100); - vq->last_add_time = now; - vq->last_add_time_valid = true; - } -#endif - - BUG_ON(total_sg > vq->vring.num); - BUG_ON(total_sg == 0); - - head = vq->free_head; - - /* If the host supports indirect descriptor tables, and we have multiple - * buffers, then go indirect. FIXME: tune this threshold */ - if (vq->indirect && total_sg > 1 && vq->vq.num_free) - desc = alloc_indirect(_vq, total_sg, gfp); - else - desc = NULL; - - if (desc) { - /* Use a single buffer which doesn't continue */ - indirect = true; - /* Set up rest to use this indirect table. */ - i = 0; - descs_used = 1; - } else { - indirect = false; - desc = vq->vring.desc; - i = head; - descs_used = total_sg; - } - - if (vq->vq.num_free < descs_used) { - pr_debug("Can't add buf len %i - avail = %i\n", - descs_used, vq->vq.num_free); - /* FIXME: for historical reasons, we force a notify here if - * there are outgoing parts to the buffer. Presumably the - * host should service the ring ASAP. */ - if (out_sgs) - vq->notify(&vq->vq); - if (indirect) - kfree(desc); - END_USE(vq); - return -ENOSPC; - } - - for (n = 0; n < out_sgs; n++) { - for (sg = sgs[n]; sg; sg = sg_next(sg)) { - dma_addr_t addr = vring_map_one_sg(vq, sg, DMA_TO_DEVICE); - if (vring_mapping_error(vq, addr)) - goto unmap_release; - - desc[i].flags = cpu_to_virtio16(_vq->vdev, VRING_DESC_F_NEXT); - desc[i].addr = cpu_to_virtio64(_vq->vdev, addr); - desc[i].len = cpu_to_virtio32(_vq->vdev, sg->length); - prev = i; - i = virtio16_to_cpu(_vq->vdev, desc[i].next); - } - } - for (; n < (out_sgs + in_sgs); n++) { - for (sg = sgs[n]; sg; sg = sg_next(sg)) { - dma_addr_t addr = vring_map_one_sg(vq, sg, DMA_FROM_DEVICE); - if (vring_mapping_error(vq, addr)) - goto unmap_release; - - desc[i].flags = cpu_to_virtio16(_vq->vdev, VRING_DESC_F_NEXT | VRING_DESC_F_WRITE); - desc[i].addr = cpu_to_virtio64(_vq->vdev, addr); - desc[i].len = cpu_to_virtio32(_vq->vdev, sg->length); - prev = i; - i = virtio16_to_cpu(_vq->vdev, desc[i].next); - } - } - /* Last one doesn't continue. */ - desc[prev].flags &= cpu_to_virtio16(_vq->vdev, ~VRING_DESC_F_NEXT); - - if (indirect) { - /* Now that the indirect table is filled in, map it. */ - dma_addr_t addr = vring_map_single( - vq, desc, total_sg * sizeof(struct vring_desc), - DMA_TO_DEVICE); - if (vring_mapping_error(vq, addr)) - goto unmap_release; - - vq->vring.desc[head].flags = cpu_to_virtio16(_vq->vdev, VRING_DESC_F_INDIRECT); - vq->vring.desc[head].addr = cpu_to_virtio64(_vq->vdev, addr); - - vq->vring.desc[head].len = cpu_to_virtio32(_vq->vdev, total_sg * sizeof(struct vring_desc)); - } - - /* We're using some buffers from the free list. */ - vq->vq.num_free -= descs_used; - - /* Update free pointer */ - if (indirect) - vq->free_head = virtio16_to_cpu(_vq->vdev, vq->vring.desc[head].next); - else - vq->free_head = i; - - /* Store token and indirect buffer state. */ - vq->desc_state[head].data = data; - if (indirect) - vq->desc_state[head].indir_desc = desc; - - /* Put entry in available array (but don't update avail->idx until they - * do sync). */ - avail = vq->avail_idx_shadow & (vq->vring.num - 1); - vq->vring.avail->ring[avail] = cpu_to_virtio16(_vq->vdev, head); - - /* Descriptors and available array need to be set before we expose the - * new available array entries. */ - virtio_wmb(vq->weak_barriers); - vq->avail_idx_shadow++; - vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, vq->avail_idx_shadow); - vq->num_added++; - - pr_debug("Added buffer head %i to %p\n", head, vq); - END_USE(vq); - - /* This is very unlikely, but theoretically possible. Kick - * just in case. */ - if (unlikely(vq->num_added == (1 << 16) - 1)) - virtqueue_kick(_vq); - - return 0; - -unmap_release: - err_idx = i; - i = head; - - for (n = 0; n < total_sg; n++) { - if (i == err_idx) - break; - vring_unmap_one(vq, &desc[i]); - i = vq->vring.desc[i].next; - } - - vq->vq.num_free += total_sg; - - if (indirect) - kfree(desc); - - END_USE(vq); - return -EIO; -} - -/** - * virtqueue_add_sgs - expose buffers to other end - * @vq: the struct virtqueue we're talking about. - * @sgs: array of terminated scatterlists. - * @out_num: the number of scatterlists readable by other side - * @in_num: the number of scatterlists which are writable (after readable ones) - * @data: the token identifying the buffer. - * @gfp: how to do memory allocations (if necessary). - * - * Caller must ensure we don't call this with other virtqueue operations - * at the same time (except where noted). - * - * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO). - */ -int virtqueue_add_sgs(struct virtqueue *_vq, - struct scatterlist *sgs[], - unsigned int out_sgs, - unsigned int in_sgs, - void *data, - gfp_t gfp) -{ - unsigned int i, total_sg = 0; - - /* Count them first. */ - for (i = 0; i < out_sgs + in_sgs; i++) { - struct scatterlist *sg; - for (sg = sgs[i]; sg; sg = sg_next(sg)) - total_sg++; - } - return virtqueue_add(_vq, sgs, total_sg, out_sgs, in_sgs, data, gfp); -} -EXPORT_SYMBOL_GPL(virtqueue_add_sgs); - -/** - * virtqueue_add_outbuf - expose output buffers to other end - * @vq: the struct virtqueue we're talking about. - * @sg: scatterlist (must be well-formed and terminated!) - * @num: the number of entries in @sg readable by other side - * @data: the token identifying the buffer. - * @gfp: how to do memory allocations (if necessary). - * - * Caller must ensure we don't call this with other virtqueue operations - * at the same time (except where noted). - * - * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO). - */ -int virtqueue_add_outbuf(struct virtqueue *vq, - struct scatterlist *sg, unsigned int num, - void *data, - gfp_t gfp) -{ - return virtqueue_add(vq, &sg, num, 1, 0, data, gfp); -} -EXPORT_SYMBOL_GPL(virtqueue_add_outbuf); - -/** - * virtqueue_add_inbuf - expose input buffers to other end - * @vq: the struct virtqueue we're talking about. - * @sg: scatterlist (must be well-formed and terminated!) - * @num: the number of entries in @sg writable by other side - * @data: the token identifying the buffer. - * @gfp: how to do memory allocations (if necessary). - * - * Caller must ensure we don't call this with other virtqueue operations - * at the same time (except where noted). - * - * Returns zero or a negative error (ie. ENOSPC, ENOMEM, EIO). - */ -int virtqueue_add_inbuf(struct virtqueue *vq, - struct scatterlist *sg, unsigned int num, - void *data, - gfp_t gfp) -{ - return virtqueue_add(vq, &sg, num, 0, 1, data, gfp); -} -EXPORT_SYMBOL_GPL(virtqueue_add_inbuf); - -/** - * virtqueue_kick_prepare - first half of split virtqueue_kick call. - * @vq: the struct virtqueue - * - * Instead of virtqueue_kick(), you can do: - * if (virtqueue_kick_prepare(vq)) - * virtqueue_notify(vq); - * - * This is sometimes useful because the virtqueue_kick_prepare() needs - * to be serialized, but the actual virtqueue_notify() call does not. - */ -bool virtqueue_kick_prepare(struct virtqueue *_vq) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - u16 new, old; - bool needs_kick; - - START_USE(vq); - /* We need to expose available array entries before checking avail - * event. */ - virtio_mb(vq->weak_barriers); - - old = vq->avail_idx_shadow - vq->num_added; - new = vq->avail_idx_shadow; - vq->num_added = 0; - -#ifdef DEBUG - if (vq->last_add_time_valid) { - WARN_ON(ktime_to_ms(ktime_sub(ktime_get(), - vq->last_add_time)) > 100); - } - vq->last_add_time_valid = false; -#endif - - if (vq->event) { - needs_kick = vring_need_event(virtio16_to_cpu(_vq->vdev, vring_avail_event(&vq->vring)), - new, old); - } else { - needs_kick = !(vq->vring.used->flags & cpu_to_virtio16(_vq->vdev, VRING_USED_F_NO_NOTIFY)); - } - END_USE(vq); - return needs_kick; -} -EXPORT_SYMBOL_GPL(virtqueue_kick_prepare); - -/** - * virtqueue_notify - second half of split virtqueue_kick call. - * @vq: the struct virtqueue - * - * This does not need to be serialized. - * - * Returns false if host notify failed or queue is broken, otherwise true. - */ -bool virtqueue_notify(struct virtqueue *_vq) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - - if (unlikely(vq->broken)) - return false; - - /* Prod other side to tell it about changes. */ - if (!vq->notify(_vq)) { - vq->broken = true; - return false; - } - return true; -} -EXPORT_SYMBOL_GPL(virtqueue_notify); - -/** - * virtqueue_kick - update after add_buf - * @vq: the struct virtqueue - * - * After one or more virtqueue_add_* calls, invoke this to kick - * the other side. - * - * Caller must ensure we don't call this with other virtqueue - * operations at the same time (except where noted). - * - * Returns false if kick failed, otherwise true. - */ -bool virtqueue_kick(struct virtqueue *vq) -{ - if (virtqueue_kick_prepare(vq)) - return virtqueue_notify(vq); - return true; -} -EXPORT_SYMBOL_GPL(virtqueue_kick); - -static void detach_buf(struct vring_virtqueue *vq, unsigned int head) -{ - unsigned int i, j; - u16 nextflag = cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_NEXT); - - /* Clear data ptr. */ - vq->desc_state[head].data = NULL; - - /* Put back on free list: unmap first-level descriptors and find end */ - i = head; - - while (vq->vring.desc[i].flags & nextflag) { - vring_unmap_one(vq, &vq->vring.desc[i]); - i = virtio16_to_cpu(vq->vq.vdev, vq->vring.desc[i].next); - vq->vq.num_free++; - } - - vring_unmap_one(vq, &vq->vring.desc[i]); - vq->vring.desc[i].next = cpu_to_virtio16(vq->vq.vdev, vq->free_head); - vq->free_head = head; - - /* Plus final descriptor */ - vq->vq.num_free++; - - /* Free the indirect table, if any, now that it's unmapped. */ - if (vq->desc_state[head].indir_desc) { - struct vring_desc *indir_desc = vq->desc_state[head].indir_desc; - u32 len = virtio32_to_cpu(vq->vq.vdev, vq->vring.desc[head].len); - - BUG_ON(!(vq->vring.desc[head].flags & - cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_INDIRECT))); - BUG_ON(len == 0 || len % sizeof(struct vring_desc)); - - for (j = 0; j < len / sizeof(struct vring_desc); j++) - vring_unmap_one(vq, &indir_desc[j]); - - kfree(vq->desc_state[head].indir_desc); - vq->desc_state[head].indir_desc = NULL; - } -} - -static inline bool more_used(const struct vring_virtqueue *vq) -{ - return vq->last_used_idx != virtio16_to_cpu(vq->vq.vdev, vq->vring.used->idx); -} - -/** - * virtqueue_get_buf - get the next used buffer - * @vq: the struct virtqueue we're talking about. - * @len: the length written into the buffer - * - * If the driver wrote data into the buffer, @len will be set to the - * amount written. This means you don't need to clear the buffer - * beforehand to ensure there's no data leakage in the case of short - * writes. - * - * Caller must ensure we don't call this with other virtqueue - * operations at the same time (except where noted). - * - * Returns NULL if there are no used buffers, or the "data" token - * handed to virtqueue_add_*(). - */ -void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - void *ret; - unsigned int i; - u16 last_used; - - START_USE(vq); - - if (unlikely(vq->broken)) { - END_USE(vq); - return NULL; - } - - if (!more_used(vq)) { - pr_debug("No more buffers in queue\n"); - END_USE(vq); - return NULL; - } - - /* Only get used array entries after they have been exposed by host. */ - virtio_rmb(vq->weak_barriers); - - last_used = (vq->last_used_idx & (vq->vring.num - 1)); - i = virtio32_to_cpu(_vq->vdev, vq->vring.used->ring[last_used].id); - *len = virtio32_to_cpu(_vq->vdev, vq->vring.used->ring[last_used].len); - - if (unlikely(i >= vq->vring.num)) { - BAD_RING(vq, "id %u out of range\n", i); - return NULL; - } - if (unlikely(!vq->desc_state[i].data)) { - BAD_RING(vq, "id %u is not a head!\n", i); - return NULL; - } - - /* detach_buf clears data, so grab it now. */ - ret = vq->desc_state[i].data; - detach_buf(vq, i); - vq->last_used_idx++; - /* If we expect an interrupt for the next entry, tell host - * by writing event index and flush out the write before - * the read in the next get_buf call. */ - if (!(vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT)) - virtio_store_mb(vq->weak_barriers, - &vring_used_event(&vq->vring), - cpu_to_virtio16(_vq->vdev, vq->last_used_idx)); - -#ifdef DEBUG - vq->last_add_time_valid = false; -#endif - - END_USE(vq); - return ret; -} -EXPORT_SYMBOL_GPL(virtqueue_get_buf); - -/** - * virtqueue_disable_cb - disable callbacks - * @vq: the struct virtqueue we're talking about. - * - * Note that this is not necessarily synchronous, hence unreliable and only - * useful as an optimization. - * - * Unlike other operations, this need not be serialized. - */ -void virtqueue_disable_cb(struct virtqueue *_vq) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - - if (!(vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT)) { - vq->avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT; - if (!vq->event) - vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow); - } - -} -EXPORT_SYMBOL_GPL(virtqueue_disable_cb); - -/** - * virtqueue_enable_cb_prepare - restart callbacks after disable_cb - * @vq: the struct virtqueue we're talking about. - * - * This re-enables callbacks; it returns current queue state - * in an opaque unsigned value. This value should be later tested by - * virtqueue_poll, to detect a possible race between the driver checking for - * more work, and enabling callbacks. - * - * Caller must ensure we don't call this with other virtqueue - * operations at the same time (except where noted). - */ -unsigned virtqueue_enable_cb_prepare(struct virtqueue *_vq) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - u16 last_used_idx; - - START_USE(vq); - - /* We optimistically turn back on interrupts, then check if there was - * more to do. */ - /* Depending on the VIRTIO_RING_F_EVENT_IDX feature, we need to - * either clear the flags bit or point the event index at the next - * entry. Always do both to keep code simple. */ - if (vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT) { - vq->avail_flags_shadow &= ~VRING_AVAIL_F_NO_INTERRUPT; - if (!vq->event) - vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow); - } - vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, last_used_idx = vq->last_used_idx); - END_USE(vq); - return last_used_idx; -} -EXPORT_SYMBOL_GPL(virtqueue_enable_cb_prepare); - -/** - * virtqueue_poll - query pending used buffers - * @vq: the struct virtqueue we're talking about. - * @last_used_idx: virtqueue state (from call to virtqueue_enable_cb_prepare). - * - * Returns "true" if there are pending used buffers in the queue. - * - * This does not need to be serialized. - */ -bool virtqueue_poll(struct virtqueue *_vq, unsigned last_used_idx) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - - virtio_mb(vq->weak_barriers); - return (u16)last_used_idx != virtio16_to_cpu(_vq->vdev, vq->vring.used->idx); -} -EXPORT_SYMBOL_GPL(virtqueue_poll); - -/** - * virtqueue_enable_cb - restart callbacks after disable_cb. - * @vq: the struct virtqueue we're talking about. - * - * This re-enables callbacks; it returns "false" if there are pending - * buffers in the queue, to detect a possible race between the driver - * checking for more work, and enabling callbacks. - * - * Caller must ensure we don't call this with other virtqueue - * operations at the same time (except where noted). - */ -bool virtqueue_enable_cb(struct virtqueue *_vq) -{ - unsigned last_used_idx = virtqueue_enable_cb_prepare(_vq); - return !virtqueue_poll(_vq, last_used_idx); -} -EXPORT_SYMBOL_GPL(virtqueue_enable_cb); - -/** - * virtqueue_enable_cb_delayed - restart callbacks after disable_cb. - * @vq: the struct virtqueue we're talking about. - * - * This re-enables callbacks but hints to the other side to delay - * interrupts until most of the available buffers have been processed; - * it returns "false" if there are many pending buffers in the queue, - * to detect a possible race between the driver checking for more work, - * and enabling callbacks. - * - * Caller must ensure we don't call this with other virtqueue - * operations at the same time (except where noted). - */ -bool virtqueue_enable_cb_delayed(struct virtqueue *_vq) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - u16 bufs; - - START_USE(vq); - - /* We optimistically turn back on interrupts, then check if there was - * more to do. */ - /* Depending on the VIRTIO_RING_F_USED_EVENT_IDX feature, we need to - * either clear the flags bit or point the event index at the next - * entry. Always update the event index to keep code simple. */ - if (vq->avail_flags_shadow & VRING_AVAIL_F_NO_INTERRUPT) { - vq->avail_flags_shadow &= ~VRING_AVAIL_F_NO_INTERRUPT; - if (!vq->event) - vq->vring.avail->flags = cpu_to_virtio16(_vq->vdev, vq->avail_flags_shadow); - } - /* TODO: tune this threshold */ - bufs = (u16)(vq->avail_idx_shadow - vq->last_used_idx) * 3 / 4; - - virtio_store_mb(vq->weak_barriers, - &vring_used_event(&vq->vring), - cpu_to_virtio16(_vq->vdev, vq->last_used_idx + bufs)); - - if (unlikely((u16)(virtio16_to_cpu(_vq->vdev, vq->vring.used->idx) - vq->last_used_idx) > bufs)) { - END_USE(vq); - return false; - } - - END_USE(vq); - return true; -} -EXPORT_SYMBOL_GPL(virtqueue_enable_cb_delayed); - -/** - * virtqueue_detach_unused_buf - detach first unused buffer - * @vq: the struct virtqueue we're talking about. - * - * Returns NULL or the "data" token handed to virtqueue_add_*(). - * This is not valid on an active queue; it is useful only for device - * shutdown. - */ -void *virtqueue_detach_unused_buf(struct virtqueue *_vq) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - unsigned int i; - void *buf; - - START_USE(vq); - - for (i = 0; i < vq->vring.num; i++) { - if (!vq->desc_state[i].data) - continue; - /* detach_buf clears data, so grab it now. */ - buf = vq->desc_state[i].data; - detach_buf(vq, i); - vq->avail_idx_shadow--; - vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, vq->avail_idx_shadow); - END_USE(vq); - return buf; - } - /* That should have freed everything. */ - BUG_ON(vq->vq.num_free != vq->vring.num); - - END_USE(vq); - return NULL; -} -EXPORT_SYMBOL_GPL(virtqueue_detach_unused_buf); - -irqreturn_t vring_interrupt(int irq, void *_vq) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - - if (!more_used(vq)) { - pr_debug("virtqueue interrupt with no work for %p\n", vq); - return IRQ_NONE; - } - - if (unlikely(vq->broken)) - return IRQ_HANDLED; - - pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback); - if (vq->vq.callback) - vq->vq.callback(&vq->vq); - - return IRQ_HANDLED; -} -EXPORT_SYMBOL_GPL(vring_interrupt); - -struct virtqueue *__vring_new_virtqueue(unsigned int index, - struct vring vring, - struct virtio_device *vdev, - bool weak_barriers, - bool (*notify)(struct virtqueue *), - void (*callback)(struct virtqueue *), - const char *name) -{ - unsigned int i; - struct vring_virtqueue *vq; - - vq = kmalloc(sizeof(*vq) + vring.num * sizeof(struct vring_desc_state), - GFP_KERNEL); - if (!vq) - return NULL; - - vq->vring = vring; - vq->vq.callback = callback; - vq->vq.vdev = vdev; - vq->vq.name = name; - vq->vq.num_free = vring.num; - vq->vq.index = index; - vq->we_own_ring = false; - vq->queue_dma_addr = 0; - vq->queue_size_in_bytes = 0; - vq->notify = notify; - vq->weak_barriers = weak_barriers; - vq->broken = false; - vq->last_used_idx = 0; - vq->avail_flags_shadow = 0; - vq->avail_idx_shadow = 0; - vq->num_added = 0; - list_add_tail(&vq->vq.list, &vdev->vqs); -#ifdef DEBUG - vq->in_use = false; - vq->last_add_time_valid = false; -#endif - - vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC); - vq->event = virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX); - - /* No callback? Tell other side not to bother us. */ - if (!callback) { - vq->avail_flags_shadow |= VRING_AVAIL_F_NO_INTERRUPT; - if (!vq->event) - vq->vring.avail->flags = cpu_to_virtio16(vdev, vq->avail_flags_shadow); - } - - /* Put everything in free lists. */ - vq->free_head = 0; - for (i = 0; i < vring.num-1; i++) - vq->vring.desc[i].next = cpu_to_virtio16(vdev, i + 1); - memset(vq->desc_state, 0, vring.num * sizeof(struct vring_desc_state)); - - return &vq->vq; -} -EXPORT_SYMBOL_GPL(__vring_new_virtqueue); - -static void *vring_alloc_queue(struct virtio_device *vdev, size_t size, - dma_addr_t *dma_handle, gfp_t flag) -{ - if (vring_use_dma_api(vdev)) { - return dma_alloc_coherent(vdev->dev.parent, size, - dma_handle, flag); - } else { - void *queue = alloc_pages_exact(PAGE_ALIGN(size), flag); - if (queue) { - phys_addr_t phys_addr = virt_to_phys(queue); - *dma_handle = (dma_addr_t)phys_addr; - - /* - * Sanity check: make sure we dind't truncate - * the address. The only arches I can find that - * have 64-bit phys_addr_t but 32-bit dma_addr_t - * are certain non-highmem MIPS and x86 - * configurations, but these configurations - * should never allocate physical pages above 32 - * bits, so this is fine. Just in case, throw a - * warning and abort if we end up with an - * unrepresentable address. - */ - if (WARN_ON_ONCE(*dma_handle != phys_addr)) { - free_pages_exact(queue, PAGE_ALIGN(size)); - return NULL; - } - } - return queue; - } -} - -static void vring_free_queue(struct virtio_device *vdev, size_t size, - void *queue, dma_addr_t dma_handle) -{ - if (vring_use_dma_api(vdev)) { - dma_free_coherent(vdev->dev.parent, size, queue, dma_handle); - } else { - free_pages_exact(queue, PAGE_ALIGN(size)); - } -} - -struct virtqueue *vring_create_virtqueue( - unsigned int index, - unsigned int num, - unsigned int vring_align, - struct virtio_device *vdev, - bool weak_barriers, - bool may_reduce_num, - bool (*notify)(struct virtqueue *), - void (*callback)(struct virtqueue *), - const char *name) -{ - struct virtqueue *vq; - void *queue = NULL; - dma_addr_t dma_addr; - size_t queue_size_in_bytes; - struct vring vring; - - /* We assume num is a power of 2. */ - if (num & (num - 1)) { - dev_warn(&vdev->dev, "Bad virtqueue length %u\n", num); - return NULL; - } - - /* TODO: allocate each queue chunk individually */ - for (; num && vring_size(num, vring_align) > PAGE_SIZE; num /= 2) { - queue = vring_alloc_queue(vdev, vring_size(num, vring_align), - &dma_addr, - GFP_KERNEL|__GFP_NOWARN|__GFP_ZERO); - if (queue) - break; - } - - if (!num) - return NULL; - - if (!queue) { - /* Try to get a single page. You are my only hope! */ - queue = vring_alloc_queue(vdev, vring_size(num, vring_align), - &dma_addr, GFP_KERNEL|__GFP_ZERO); - } - if (!queue) - return NULL; - - queue_size_in_bytes = vring_size(num, vring_align); - vring_init(&vring, num, queue, vring_align); - - vq = __vring_new_virtqueue(index, vring, vdev, weak_barriers, - notify, callback, name); - if (!vq) { - vring_free_queue(vdev, queue_size_in_bytes, queue, - dma_addr); - return NULL; - } - - to_vvq(vq)->queue_dma_addr = dma_addr; - to_vvq(vq)->queue_size_in_bytes = queue_size_in_bytes; - to_vvq(vq)->we_own_ring = true; - - return vq; -} -EXPORT_SYMBOL_GPL(vring_create_virtqueue); - -struct virtqueue *vring_new_virtqueue(unsigned int index, - unsigned int num, - unsigned int vring_align, - struct virtio_device *vdev, - bool weak_barriers, - void *pages, - bool (*notify)(struct virtqueue *vq), - void (*callback)(struct virtqueue *vq), - const char *name) -{ - struct vring vring; - vring_init(&vring, num, pages, vring_align); - return __vring_new_virtqueue(index, vring, vdev, weak_barriers, - notify, callback, name); -} -EXPORT_SYMBOL_GPL(vring_new_virtqueue); - -void vring_del_virtqueue(struct virtqueue *_vq) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - - if (vq->we_own_ring) { - vring_free_queue(vq->vq.vdev, vq->queue_size_in_bytes, - vq->vring.desc, vq->queue_dma_addr); - } - list_del(&_vq->list); - kfree(vq); -} -EXPORT_SYMBOL_GPL(vring_del_virtqueue); - -/* Manipulates transport-specific feature bits. */ -void vring_transport_features(struct virtio_device *vdev) -{ - unsigned int i; - - for (i = VIRTIO_TRANSPORT_F_START; i < VIRTIO_TRANSPORT_F_END; i++) { - switch (i) { - case VIRTIO_RING_F_INDIRECT_DESC: - break; - case VIRTIO_RING_F_EVENT_IDX: - break; - case VIRTIO_F_VERSION_1: - break; - case VIRTIO_F_IOMMU_PLATFORM: - break; - default: - /* We don't understand this bit. */ - __virtio_clear_bit(vdev, i); - } - } -} -EXPORT_SYMBOL_GPL(vring_transport_features); - -/** - * virtqueue_get_vring_size - return the size of the virtqueue's vring - * @vq: the struct virtqueue containing the vring of interest. - * - * Returns the size of the vring. This is mainly used for boasting to - * userspace. Unlike other operations, this need not be serialized. - */ -unsigned int virtqueue_get_vring_size(struct virtqueue *_vq) -{ - - struct vring_virtqueue *vq = to_vvq(_vq); - - return vq->vring.num; -} -EXPORT_SYMBOL_GPL(virtqueue_get_vring_size); - -bool virtqueue_is_broken(struct virtqueue *_vq) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - - return vq->broken; -} -EXPORT_SYMBOL_GPL(virtqueue_is_broken); - -/* - * This should prevent the device from being used, allowing drivers to - * recover. You may need to grab appropriate locks to flush. - */ -void virtio_break_device(struct virtio_device *dev) -{ - struct virtqueue *_vq; - - list_for_each_entry(_vq, &dev->vqs, list) { - struct vring_virtqueue *vq = to_vvq(_vq); - vq->broken = true; - } -} -EXPORT_SYMBOL_GPL(virtio_break_device); - -dma_addr_t virtqueue_get_desc_addr(struct virtqueue *_vq) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - - BUG_ON(!vq->we_own_ring); - - return vq->queue_dma_addr; -} -EXPORT_SYMBOL_GPL(virtqueue_get_desc_addr); - -dma_addr_t virtqueue_get_avail_addr(struct virtqueue *_vq) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - - BUG_ON(!vq->we_own_ring); - - return vq->queue_dma_addr + - ((char *)vq->vring.avail - (char *)vq->vring.desc); -} -EXPORT_SYMBOL_GPL(virtqueue_get_avail_addr); - -dma_addr_t virtqueue_get_used_addr(struct virtqueue *_vq) -{ - struct vring_virtqueue *vq = to_vvq(_vq); - - BUG_ON(!vq->we_own_ring); - - return vq->queue_dma_addr + - ((char *)vq->vring.used - (char *)vq->vring.desc); -} -EXPORT_SYMBOL_GPL(virtqueue_get_used_addr); - -const struct vring *virtqueue_get_vring(struct virtqueue *vq) -{ - return &to_vvq(vq)->vring; -} -EXPORT_SYMBOL_GPL(virtqueue_get_vring); - -MODULE_LICENSE("GPL"); diff --git a/src/linux/drivers/vlynq/Kconfig b/src/linux/drivers/vlynq/Kconfig deleted file mode 100644 index e011620..0000000 --- a/src/linux/drivers/vlynq/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -menu "TI VLYNQ" - depends on AR7 - -config VLYNQ - bool "TI VLYNQ bus support" - help - Support for Texas Instruments(R) VLYNQ bus. - The VLYNQ bus is a high-speed, serial and packetized - data bus which allows external peripherals of a SoC - to appear into the system's main memory. - - If unsure, say N - -config VLYNQ_DEBUG - bool "VLYNQ bus debug" - depends on VLYNQ && DEBUG_KERNEL - help - Turn on VLYNQ bus debugging. - -endmenu diff --git a/src/linux/drivers/vme/Kconfig b/src/linux/drivers/vme/Kconfig deleted file mode 100644 index a6a6f95..0000000 --- a/src/linux/drivers/vme/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -# -# VME configuration. -# - -menuconfig VME_BUS - bool "VME bridge support" - depends on PCI - ---help--- - If you say Y here you get support for the VME bridge Framework. - -if VME_BUS - -source "drivers/vme/bridges/Kconfig" - -source "drivers/vme/boards/Kconfig" - -source "drivers/staging/vme/devices/Kconfig" - -endif # VME diff --git a/src/linux/drivers/vme/boards/Kconfig b/src/linux/drivers/vme/boards/Kconfig deleted file mode 100644 index 7616313..0000000 --- a/src/linux/drivers/vme/boards/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -comment "VME Board Drivers" - -config VMIVME_7805 - tristate "VMIVME-7805" - help - If you say Y here you get support for the VMIVME-7805 board. - This board has an additional control interface to the Universe II - chip. This driver has to be included if you want to access VME bus - with VMIVME-7805 board. diff --git a/src/linux/drivers/vme/bridges/Kconfig b/src/linux/drivers/vme/bridges/Kconfig deleted file mode 100644 index f6ddc37..0000000 --- a/src/linux/drivers/vme/bridges/Kconfig +++ /dev/null @@ -1,23 +0,0 @@ -comment "VME Bridge Drivers" - -config VME_CA91CX42 - tristate "Universe II" - depends on VIRT_TO_BUS - help - If you say Y here you get support for the Tundra CA91C142 - (Universe II) VME bridge chip. - -config VME_TSI148 - tristate "Tempe" - depends on HAS_DMA - help - If you say Y here you get support for the Tundra TSI148 VME bridge - chip. - -config VME_FAKE - tristate "Fake" - help - If you say Y here you get support for the fake VME bridge. This - provides a virtualised VME Bus for devices with no VME bridge. This - is mainly useful for VME development (in the absence of VME - hardware). diff --git a/src/linux/drivers/w1/Kconfig b/src/linux/drivers/w1/Kconfig deleted file mode 100644 index 6743bde..0000000 --- a/src/linux/drivers/w1/Kconfig +++ /dev/null @@ -1,31 +0,0 @@ -menuconfig W1 - tristate "Dallas's 1-wire support" - depends on HAS_IOMEM - ---help--- - Dallas' 1-wire bus is useful to connect slow 1-pin devices - such as iButtons and thermal sensors. - - If you want W1 support, you should say Y here. - - This W1 support can also be built as a module. If so, the module - will be called wire. - -if W1 - -config W1_CON - depends on CONNECTOR - bool "Userspace communication over connector" - default y - ---help--- - This allows to communicate with userspace using connector. For more - information see . - There are three types of messages between w1 core and userspace: - 1. Events. They are generated each time new master or slave device found - either due to automatic or requested search. - 2. Userspace commands. Includes read/write and search/alarm search commands. - 3. Replies to userspace commands. - -source drivers/w1/masters/Kconfig -source drivers/w1/slaves/Kconfig - -endif # W1 diff --git a/src/linux/drivers/w1/masters/Kconfig b/src/linux/drivers/w1/masters/Kconfig deleted file mode 100644 index 1708b23..0000000 --- a/src/linux/drivers/w1/masters/Kconfig +++ /dev/null @@ -1,68 +0,0 @@ -# -# 1-wire bus master configuration -# - -menu "1-wire Bus Masters" - -config W1_MASTER_MATROX - tristate "Matrox G400 transport layer for 1-wire" - depends on PCI - help - Say Y here if you want to communicate with your 1-wire devices - using Matrox's G400 GPIO pins. - - This support is also available as a module. If so, the module - will be called matrox_w1. - -config W1_MASTER_DS2490 - tristate "DS2490 USB <-> W1 transport layer for 1-wire" - depends on USB - help - Say Y here if you want to have a driver for DS2490 based USB <-> W1 bridges, - for example DS9490*. - - This support is also available as a module. If so, the module - will be called ds2490. - -config W1_MASTER_DS2482 - tristate "Maxim DS2482 I2C to 1-Wire bridge" - depends on I2C - help - If you say yes here you get support for the Maxim DS2482 - I2C to 1-Wire bridge. - - This driver can also be built as a module. If so, the module - will be called ds2482. - -config W1_MASTER_MXC - tristate "Freescale MXC 1-wire busmaster" - depends on ARCH_MXC || COMPILE_TEST - help - Say Y here to enable MXC 1-wire host - -config W1_MASTER_DS1WM - tristate "Maxim DS1WM 1-wire busmaster" - help - Say Y here to enable the DS1WM 1-wire driver, such as that - in HP iPAQ devices like h5xxx, h2200, and ASIC3-based like - hx4700. - -config W1_MASTER_GPIO - tristate "GPIO 1-wire busmaster" - depends on GPIOLIB - help - Say Y here if you want to communicate with your 1-wire devices using - GPIO pins. This driver uses the GPIO API to control the wire. - - This support is also available as a module. If so, the module - will be called w1-gpio. - -config HDQ_MASTER_OMAP - tristate "OMAP HDQ driver" - depends on ARCH_OMAP - help - Say Y here if you want support for the 1-wire or HDQ Interface - on an OMAP processor. - -endmenu - diff --git a/src/linux/drivers/w1/slaves/Kconfig b/src/linux/drivers/w1/slaves/Kconfig deleted file mode 100644 index cfe74d0..0000000 --- a/src/linux/drivers/w1/slaves/Kconfig +++ /dev/null @@ -1,135 +0,0 @@ -# -# 1-wire slaves configuration -# - -menu "1-wire Slaves" - -config W1_SLAVE_THERM - tristate "Thermal family implementation" - help - Say Y here if you want to connect 1-wire thermal sensors to your - wire. - -config W1_SLAVE_SMEM - tristate "Simple 64bit memory family implementation" - help - Say Y here if you want to connect 1-wire - simple 64bit memory rom(ds2401/ds2411/ds1990*) to your wire. - -config W1_SLAVE_DS2408 - tristate "8-Channel Addressable Switch (IO Expander) 0x29 family support (DS2408)" - help - Say Y here if you want to use a 1-wire - DS2408 8-Channel Addressable Switch device support - -config W1_SLAVE_DS2408_READBACK - bool "Read-back values written to DS2408's output register" - depends on W1_SLAVE_DS2408 - default y - help - Enabling this will cause the driver to read back the values written - to the chip's output register in order to detect errors. - - This is slower but useful when debugging chips and/or busses. - -config W1_SLAVE_DS2413 - tristate "Dual Channel Addressable Switch 0x3a family support (DS2413)" - help - Say Y here if you want to use a 1-wire - DS2413 Dual Channel Addressable Switch device support - -config W1_SLAVE_DS2406 - tristate "Dual Channel Addressable Switch 0x12 family support (DS2406)" - select CRC16 - help - Say Y or M here if you want to use a 1-wire - DS2406 Dual Channel Addressable Switch. EPROM read/write - support for these devices is not implemented. - -config W1_SLAVE_DS2423 - tristate "Counter 1-wire device (DS2423)" - select CRC16 - help - If you enable this you can read the counter values available - in the DS2423 chipset from the w1_slave file under the - sys file system. - - Say Y here if you want to use a 1-wire - counter family device (DS2423). - -config W1_SLAVE_DS2431 - tristate "1kb EEPROM family support (DS2431)" - help - Say Y here if you want to use a 1-wire - 1kb EEPROM family device (DS2431) - -config W1_SLAVE_DS2433 - tristate "4kb EEPROM family support (DS2433)" - help - Say Y here if you want to use a 1-wire - 4kb EEPROM family device (DS2433). - -config W1_SLAVE_DS2433_CRC - bool "Protect DS2433 data with a CRC16" - depends on W1_SLAVE_DS2433 - select CRC16 - help - Say Y here to protect DS2433 data with a CRC16. - Each block has 30 bytes of data and a two byte CRC16. - Full block writes are only allowed if the CRC is valid. - -config W1_SLAVE_DS2760 - tristate "Dallas 2760 battery monitor chip (HP iPAQ & others)" - help - If you enable this you will have the DS2760 battery monitor - chip support. - - The battery monitor chip is used in many batteries/devices - as the one who is responsible for charging/discharging/monitoring - Li+ batteries. - - If you are unsure, say N. - -config W1_SLAVE_DS2780 - tristate "Dallas 2780 battery monitor chip" - help - If you enable this you will have the DS2780 battery monitor - chip support. - - The battery monitor chip is used in many batteries/devices - as the one who is responsible for charging/discharging/monitoring - Li+ batteries. - - If you are unsure, say N. - -config W1_SLAVE_DS2781 - tristate "Dallas 2781 battery monitor chip" - help - If you enable this you will have the DS2781 battery monitor - chip support. - - The battery monitor chip is used in many batteries/devices - as the one who is responsible for charging/discharging/monitoring - Li+ batteries. - - If you are unsure, say N. - -config W1_SLAVE_DS28E04 - tristate "4096-Bit Addressable 1-Wire EEPROM with PIO (DS28E04-100)" - select CRC16 - help - If you enable this you will have the DS28E04-100 - chip support. - - Say Y here if you want to use a 1-wire - 4kb EEPROM with PIO family device (DS28E04). - - If you are unsure, say N. - -config W1_SLAVE_BQ27000 - tristate "BQ27000 slave support" - help - Say Y here if you want to use a hdq - bq27000 slave support. - -endmenu diff --git a/src/linux/drivers/watchdog/Kconfig b/src/linux/drivers/watchdog/Kconfig deleted file mode 100644 index 3eb58cb..0000000 --- a/src/linux/drivers/watchdog/Kconfig +++ /dev/null @@ -1,1897 +0,0 @@ - -# -# Watchdog device configuration -# - -menuconfig WATCHDOG - bool "Watchdog Timer Support" - ---help--- - If you say Y here (and to one of the following options) and create a - character special file /dev/watchdog with major number 10 and minor - number 130 using mknod ("man mknod"), you will get a watchdog, i.e.: - subsequently opening the file and then failing to write to it for - longer than 1 minute will result in rebooting the machine. This - could be useful for a networked machine that needs to come back - on-line as fast as possible after a lock-up. There's both a watchdog - implementation entirely in software (which can sometimes fail to - reboot the machine) and a driver for hardware watchdog boards, which - are more robust and can also keep track of the temperature inside - your computer. For details, read - in the kernel source. - - The watchdog is usually used together with the watchdog daemon - which is available from - . This daemon can - also monitor NFS connections and can reboot the machine when the process - table is full. - - If unsure, say N. - -if WATCHDOG - -config WATCHDOG_CORE - bool "WatchDog Timer Driver Core" - ---help--- - Say Y here if you want to use the new watchdog timer driver core. - This driver provides a framework for all watchdog timer drivers - and gives them the /dev/watchdog interface (and later also the - sysfs interface). - -config WATCHDOG_NOWAYOUT - bool "Disable watchdog shutdown on close" - help - The default watchdog behaviour (which you get if you say N here) is - to stop the timer if the process managing it closes the file - /dev/watchdog. It's always remotely possible that this process might - get killed. If you say Y here, the watchdog cannot be stopped once - it has been started. - -config WATCHDOG_SYSFS - bool "Read different watchdog information through sysfs" - help - Say Y here if you want to enable watchdog device status read through - sysfs attributes. - -# -# General Watchdog drivers -# - -comment "Watchdog Device Drivers" - -# Architecture Independent - -config SOFT_WATCHDOG - tristate "Software watchdog" - select WATCHDOG_CORE - help - A software monitoring watchdog. This will fail to reboot your system - from some situations that the hardware watchdog will recover - from. Equally it's a lot cheaper to install. - - To compile this driver as a module, choose M here: the - module will be called softdog. - -config DA9052_WATCHDOG - tristate "Dialog DA9052 Watchdog" - depends on PMIC_DA9052 - select WATCHDOG_CORE - help - Support for the watchdog in the DA9052 PMIC. Watchdog trigger - cause system reset. - - Say Y here to include support for the DA9052 watchdog. - Alternatively say M to compile the driver as a module, - which will be called da9052_wdt. - -config DA9055_WATCHDOG - tristate "Dialog Semiconductor DA9055 Watchdog" - depends on MFD_DA9055 - select WATCHDOG_CORE - help - If you say yes here you get support for watchdog on the Dialog - Semiconductor DA9055 PMIC. - - This driver can also be built as a module. If so, the module - will be called da9055_wdt. - -config DA9063_WATCHDOG - tristate "Dialog DA9063 Watchdog" - depends on MFD_DA9063 - select WATCHDOG_CORE - help - Support for the watchdog in the DA9063 PMIC. - - This driver can be built as a module. The module name is da9063_wdt. - -config DA9062_WATCHDOG - tristate "Dialog DA9062 Watchdog" - depends on MFD_DA9062 - select WATCHDOG_CORE - help - Support for the watchdog in the DA9062 PMIC. - - This driver can be built as a module. The module name is da9062_wdt. - -config GPIO_WATCHDOG - tristate "Watchdog device controlled through GPIO-line" - depends on OF_GPIO - select WATCHDOG_CORE - help - If you say yes here you get support for watchdog device - controlled through GPIO-line. - -config GPIO_WATCHDOG_ARCH_INITCALL - bool "Register the watchdog as early as possible" - depends on GPIO_WATCHDOG=y - help - In some situations, the default initcall level (module_init) - in not early enough in the boot process to avoid the watchdog - to be triggered. - If you say yes here, the initcall level would be raised to - arch_initcall. - If in doubt, say N. - -config MENF21BMC_WATCHDOG - tristate "MEN 14F021P00 BMC Watchdog" - depends on MFD_MENF21BMC - select WATCHDOG_CORE - help - Say Y here to include support for the MEN 14F021P00 BMC Watchdog. - - This driver can also be built as a module. If so the module - will be called menf21bmc_wdt. - -config TANGOX_WATCHDOG - tristate "Sigma Designs SMP86xx/SMP87xx watchdog" - select WATCHDOG_CORE - depends on ARCH_TANGO || COMPILE_TEST - depends on HAS_IOMEM - help - Support for the watchdog in Sigma Designs SMP86xx (tango3) - and SMP87xx (tango4) family chips. - - This driver can be built as a module. The module name is tangox_wdt. - -config WDAT_WDT - tristate "ACPI Watchdog Action Table (WDAT)" - depends on ACPI - select WATCHDOG_CORE - select ACPI_WATCHDOG - help - This driver adds support for systems with ACPI Watchdog Action - Table (WDAT) table. Servers typically have this but it can be - found on some desktop machines as well. This driver will take - over the native iTCO watchdog driver found on many Intel CPUs. - - To compile this driver as module, choose M here: the module will - be called wdat_wdt. - -config WM831X_WATCHDOG - tristate "WM831x watchdog" - depends on MFD_WM831X - select WATCHDOG_CORE - help - Support for the watchdog in the WM831x AudioPlus PMICs. When - the watchdog triggers the system will be reset. - -config WM8350_WATCHDOG - tristate "WM8350 watchdog" - depends on MFD_WM8350 - select WATCHDOG_CORE - help - Support for the watchdog in the WM8350 AudioPlus PMIC. When - the watchdog triggers the system will be reset. - -config XILINX_WATCHDOG - tristate "Xilinx Watchdog timer" - depends on HAS_IOMEM - select WATCHDOG_CORE - help - Watchdog driver for the xps_timebase_wdt ip core. - - To compile this driver as a module, choose M here: the - module will be called of_xilinx_wdt. - -config ZIIRAVE_WATCHDOG - tristate "Zodiac RAVE Watchdog Timer" - depends on I2C - select WATCHDOG_CORE - help - Watchdog driver for the Zodiac Aerospace RAVE Switch Watchdog - Processor. - - To compile this driver as a module, choose M here: the - module will be called ziirave_wdt. - -# ALPHA Architecture - -# ARM Architecture - -config ARM_SP805_WATCHDOG - tristate "ARM SP805 Watchdog" - depends on (ARM || ARM64) && ARM_AMBA - select WATCHDOG_CORE - help - ARM Primecell SP805 Watchdog timer. This will reboot your system when - the timeout is reached. - -config ARM_SBSA_WATCHDOG - tristate "ARM SBSA Generic Watchdog" - depends on ARM64 - depends on ARM_ARCH_TIMER - select WATCHDOG_CORE - help - ARM SBSA Generic Watchdog has two stage timeouts: - the first signal (WS0) is for alerting the system by interrupt, - the second one (WS1) is a real hardware reset. - More details: ARM DEN0029B - Server Base System Architecture (SBSA) - - This driver can operate ARM SBSA Generic Watchdog as a single stage - or a two stages watchdog, it depends on the module parameter "action". - - Note: the maximum timeout in the two stages mode is half of that in - the single stage mode. - - To compile this driver as module, choose M here: The module - will be called sbsa_gwdt. - -config ASM9260_WATCHDOG - tristate "Alphascale ASM9260 watchdog" - depends on MACH_ASM9260 - depends on OF - select WATCHDOG_CORE - select RESET_CONTROLLER - help - Watchdog timer embedded into Alphascale asm9260 chips. This will reboot your - system when the timeout is reached. - -config AT91RM9200_WATCHDOG - tristate "AT91RM9200 watchdog" - depends on SOC_AT91RM9200 && MFD_SYSCON - help - Watchdog timer embedded into AT91RM9200 chips. This will reboot your - system when the timeout is reached. - -config AT91SAM9X_WATCHDOG - tristate "AT91SAM9X / AT91CAP9 watchdog" - depends on ARCH_AT91 - select WATCHDOG_CORE - help - Watchdog timer embedded into AT91SAM9X and AT91CAP9 chips. This will - reboot your system when the timeout is reached. - -config SAMA5D4_WATCHDOG - tristate "Atmel SAMA5D4 Watchdog Timer" - depends on ARCH_AT91 - select WATCHDOG_CORE - help - Atmel SAMA5D4 watchdog timer is embedded into SAMA5D4 chips. - Its Watchdog Timer Mode Register can be written more than once. - This will reboot your system when the timeout is reached. - -config CADENCE_WATCHDOG - tristate "Cadence Watchdog Timer" - depends on HAS_IOMEM - select WATCHDOG_CORE - help - Say Y here if you want to include support for the watchdog - timer in the Xilinx Zynq. - -config 21285_WATCHDOG - tristate "DC21285 watchdog" - depends on FOOTBRIDGE - help - The Intel Footbridge chip contains a built-in watchdog circuit. Say Y - here if you wish to use this. Alternatively say M to compile the - driver as a module, which will be called wdt285. - - This driver does not work on all machines. In particular, early CATS - boards have hardware problems that will cause the machine to simply - lock up if the watchdog fires. - - "If in doubt, leave it out" - say N. - -config 977_WATCHDOG - tristate "NetWinder WB83C977 watchdog" - depends on FOOTBRIDGE && ARCH_NETWINDER - help - Say Y here to include support for the WB977 watchdog included in - NetWinder machines. Alternatively say M to compile the driver as - a module, which will be called wdt977. - - Not sure? It's safe to say N. - -config IXP4XX_WATCHDOG - tristate "IXP4xx Watchdog" - depends on ARCH_IXP4XX - help - Say Y here if to include support for the watchdog timer - in the Intel IXP4xx network processors. This driver can - be built as a module by choosing M. The module will - be called ixp4xx_wdt. - - Note: The internal IXP4xx watchdog does a soft CPU reset - which doesn't reset any peripherals. There are circumstances - where the watchdog will fail to reset the board correctly - (e.g., if the boot ROM is in an unreadable state). - - Say N if you are unsure. - -config KS8695_WATCHDOG - tristate "KS8695 watchdog" - depends on ARCH_KS8695 - help - Watchdog timer embedded into KS8695 processor. This will reboot your - system when the timeout is reached. - -config HAVE_S3C2410_WATCHDOG - bool - help - This will include watchdog timer support for Samsung SoCs. If - you want to include watchdog support for any machine, kindly - select this in the respective mach-XXXX/Kconfig file. - -config S3C2410_WATCHDOG - tristate "S3C2410 Watchdog" - depends on HAVE_S3C2410_WATCHDOG - select WATCHDOG_CORE - select MFD_SYSCON if ARCH_EXYNOS5 - help - Watchdog timer block in the Samsung SoCs. This will reboot - the system when the timer expires with the watchdog enabled. - - The driver is limited by the speed of the system's PCLK - signal, so with reasonably fast systems (PCLK around 50-66MHz) - then watchdog intervals of over approximately 20seconds are - unavailable. - - The driver can be built as a module by choosing M, and will - be called s3c2410_wdt - -config SA1100_WATCHDOG - tristate "SA1100/PXA2xx watchdog" - depends on ARCH_SA1100 || ARCH_PXA - help - Watchdog timer embedded into SA11x0 and PXA2xx chips. This will - reboot your system when timeout is reached. - - NOTE: once enabled, this timer cannot be disabled. - - To compile this driver as a module, choose M here: the - module will be called sa1100_wdt. - -config DW_WATCHDOG - tristate "Synopsys DesignWare watchdog" - depends on HAS_IOMEM - select WATCHDOG_CORE - help - Say Y here if to include support for the Synopsys DesignWare - watchdog timer found in many chips. - To compile this driver as a module, choose M here: the - module will be called dw_wdt. - -config EP93XX_WATCHDOG - tristate "EP93xx Watchdog" - depends on ARCH_EP93XX - select WATCHDOG_CORE - help - Say Y here if to include support for the watchdog timer - embedded in the Cirrus Logic EP93xx family of devices. - - To compile this driver as a module, choose M here: the - module will be called ep93xx_wdt. - -config OMAP_WATCHDOG - tristate "OMAP Watchdog" - depends on ARCH_OMAP16XX || ARCH_OMAP2PLUS - select WATCHDOG_CORE - help - Support for TI OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog. Say 'Y' - here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430/OMAP4430 watchdog timer. - -config PNX4008_WATCHDOG - tristate "LPC32XX Watchdog" - depends on ARCH_LPC32XX - select WATCHDOG_CORE - help - Say Y here if to include support for the watchdog timer - in the LPC32XX processor. - This driver can be built as a module by choosing M. The module - will be called pnx4008_wdt. - - Say N if you are unsure. - -config IOP_WATCHDOG - tristate "IOP Watchdog" - depends on ARCH_IOP13XX - select WATCHDOG_NOWAYOUT if (ARCH_IOP32X || ARCH_IOP33X) - help - Say Y here if to include support for the watchdog timer - in the Intel IOP3XX & IOP13XX I/O Processors. This driver can - be built as a module by choosing M. The module will - be called iop_wdt. - - Note: The IOP13XX watchdog does an Internal Bus Reset which will - affect both cores and the peripherals of the IOP. The ATU-X - and/or ATUe configuration registers will remain intact, but if - operating as an Root Complex and/or Central Resource, the PCI-X - and/or PCIe busses will also be reset. THIS IS A VERY BIG HAMMER. - -config DAVINCI_WATCHDOG - tristate "DaVinci watchdog" - depends on ARCH_DAVINCI || ARCH_KEYSTONE - select WATCHDOG_CORE - help - Say Y here if to include support for the watchdog timer - in the DaVinci DM644x/DM646x or Keystone processors. - To compile this driver as a module, choose M here: the - module will be called davinci_wdt. - - NOTE: once enabled, this timer cannot be disabled. - Say N if you are unsure. - -config ORION_WATCHDOG - tristate "Orion watchdog" - depends on ARCH_ORION5X || ARCH_DOVE || MACH_DOVE || ARCH_MVEBU - depends on ARM - select WATCHDOG_CORE - help - Say Y here if to include support for the watchdog timer - in the Marvell Orion5x and Kirkwood ARM SoCs. - To compile this driver as a module, choose M here: the - module will be called orion_wdt. - -config RN5T618_WATCHDOG - tristate "Ricoh RN5T618 watchdog" - depends on MFD_RN5T618 - select WATCHDOG_CORE - help - If you say yes here you get support for watchdog on the Ricoh - RN5T618 PMIC. - - This driver can also be built as a module. If so, the module - will be called rn5t618_wdt. - -config SUNXI_WATCHDOG - tristate "Allwinner SoCs watchdog support" - depends on ARCH_SUNXI - select WATCHDOG_CORE - help - Say Y here to include support for the watchdog timer - in Allwinner SoCs. - To compile this driver as a module, choose M here: the - module will be called sunxi_wdt. - -config COH901327_WATCHDOG - bool "ST-Ericsson COH 901 327 watchdog" - depends on ARCH_U300 - default y if MACH_U300 - select WATCHDOG_CORE - help - Say Y here to include Watchdog timer support for the - watchdog embedded into the ST-Ericsson U300 series platforms. - This watchdog is used to reset the system and thus cannot be - compiled as a module. - -config TWL4030_WATCHDOG - tristate "TWL4030 Watchdog" - depends on TWL4030_CORE - select WATCHDOG_CORE - help - Support for TI TWL4030 watchdog. Say 'Y' here to enable the - watchdog timer support for TWL4030 chips. - -config STMP3XXX_RTC_WATCHDOG - tristate "Freescale STMP3XXX & i.MX23/28 watchdog" - depends on RTC_DRV_STMP - select WATCHDOG_CORE - help - Say Y here to include support for the watchdog timer inside - the RTC for the STMP37XX/378X or i.MX23/28 SoC. - To compile this driver as a module, choose M here: the - module will be called stmp3xxx_rtc_wdt. - -config NUC900_WATCHDOG - tristate "Nuvoton NUC900 watchdog" - depends on ARCH_W90X900 - help - Say Y here if to include support for the watchdog timer - for the Nuvoton NUC900 series SoCs. - To compile this driver as a module, choose M here: the - module will be called nuc900_wdt. - -config TS4800_WATCHDOG - tristate "TS-4800 Watchdog" - depends on HAS_IOMEM && OF - depends on SOC_IMX51 || COMPILE_TEST - select WATCHDOG_CORE - select MFD_SYSCON - help - Technologic Systems TS-4800 has watchdog timer implemented in - an external FPGA. Say Y here if you want to support for the - watchdog timer on TS-4800 board. - -config TS72XX_WATCHDOG - tristate "TS-72XX SBC Watchdog" - depends on MACH_TS72XX - help - Technologic Systems TS-7200, TS-7250 and TS-7260 boards have - watchdog timer implemented in a external CPLD chip. Say Y here - if you want to support for the watchdog timer on TS-72XX boards. - - To compile this driver as a module, choose M here: the - module will be called ts72xx_wdt. - -config MAX63XX_WATCHDOG - tristate "Max63xx watchdog" - depends on HAS_IOMEM - select WATCHDOG_CORE - help - Support for memory mapped max63{69,70,71,72,73,74} watchdog timer. - -config MAX77620_WATCHDOG - tristate "Maxim Max77620 Watchdog Timer" - depends on MFD_MAX77620 - help - This is the driver for the Max77620 watchdog timer. - Say 'Y' here to enable the watchdog timer support for - MAX77620 chips. To compile this driver as a module, - choose M here: the module will be called max77620_wdt. - -config IMX2_WDT - tristate "IMX2+ Watchdog" - depends on ARCH_MXC || ARCH_LAYERSCAPE - select REGMAP_MMIO - select WATCHDOG_CORE - help - This is the driver for the hardware watchdog - on the Freescale IMX2 and later processors. - If you have one of these processors and wish to have - watchdog support enabled, say Y, otherwise say N. - - To compile this driver as a module, choose M here: the - module will be called imx2_wdt. - -config UX500_WATCHDOG - tristate "ST-Ericsson Ux500 watchdog" - depends on MFD_DB8500_PRCMU - select WATCHDOG_CORE - default y - help - Say Y here to include Watchdog timer support for the watchdog - existing in the prcmu of ST-Ericsson Ux500 series platforms. - - To compile this driver as a module, choose M here: the - module will be called ux500_wdt. - -config RETU_WATCHDOG - tristate "Retu watchdog" - depends on MFD_RETU - select WATCHDOG_CORE - help - Retu watchdog driver for Nokia Internet Tablets (770, N800, - N810). At least on N800 the watchdog cannot be disabled, so - this driver is essential and you should enable it. - - To compile this driver as a module, choose M here: the - module will be called retu_wdt. - -config MOXART_WDT - tristate "MOXART watchdog" - depends on ARCH_MOXART - help - Say Y here to include Watchdog timer support for the watchdog - existing on the MOXA ART SoC series platforms. - - To compile this driver as a module, choose M here: the - module will be called moxart_wdt. - -config SIRFSOC_WATCHDOG - tristate "SiRFSOC watchdog" - depends on ARCH_SIRF - select WATCHDOG_CORE - default y - help - Support for CSR SiRFprimaII and SiRFatlasVI watchdog. When - the watchdog triggers the system will be reset. - -config ST_LPC_WATCHDOG - tristate "STMicroelectronics LPC Watchdog" - depends on ARCH_STI - depends on OF - select WATCHDOG_CORE - help - Say Y here to include STMicroelectronics Low Power Controller - (LPC) based Watchdog timer support. - - To compile this driver as a module, choose M here: the - module will be called st_lpc_wdt. - -config TEGRA_WATCHDOG - tristate "Tegra watchdog" - depends on (ARCH_TEGRA || COMPILE_TEST) && HAS_IOMEM - select WATCHDOG_CORE - help - Say Y here to include support for the watchdog timer - embedded in NVIDIA Tegra SoCs. - - To compile this driver as a module, choose M here: the - module will be called tegra_wdt. - -config QCOM_WDT - tristate "QCOM watchdog" - depends on HAS_IOMEM - depends on ARCH_QCOM - select WATCHDOG_CORE - help - Say Y here to include Watchdog timer support for the watchdog found - on QCOM chipsets. Currently supported targets are the MSM8960, - APQ8064, and IPQ8064. - - To compile this driver as a module, choose M here: the - module will be called qcom_wdt. - -config MESON_GXBB_WATCHDOG - tristate "Amlogic Meson GXBB SoCs watchdog support" - depends on ARCH_MESON - select WATCHDOG_CORE - help - Say Y here to include support for the watchdog timer - in Amlogic Meson GXBB SoCs. - To compile this driver as a module, choose M here: the - module will be called meson_gxbb_wdt. - -config MESON_WATCHDOG - tristate "Amlogic Meson SoCs watchdog support" - depends on ARCH_MESON - select WATCHDOG_CORE - help - Say Y here to include support for the watchdog timer - in Amlogic Meson SoCs. - To compile this driver as a module, choose M here: the - module will be called meson_wdt. - -config MEDIATEK_WATCHDOG - tristate "Mediatek SoCs watchdog support" - depends on ARCH_MEDIATEK - select WATCHDOG_CORE - help - Say Y here to include support for the watchdog timer - in Mediatek SoCs. - To compile this driver as a module, choose M here: the - module will be called mtk_wdt. - -config DIGICOLOR_WATCHDOG - tristate "Conexant Digicolor SoCs watchdog support" - depends on ARCH_DIGICOLOR - select WATCHDOG_CORE - help - Say Y here to include support for the watchdog timer - in Conexant Digicolor SoCs. - To compile this driver as a module, choose M here: the - module will be called digicolor_wdt. - -config LPC18XX_WATCHDOG - tristate "LPC18xx/43xx Watchdog" - depends on ARCH_LPC18XX || COMPILE_TEST - depends on HAS_IOMEM - select WATCHDOG_CORE - help - Say Y here if to include support for the watchdog timer - in NXP LPC SoCs family, which includes LPC18xx/LPC43xx - processors. - To compile this driver as a module, choose M here: the - module will be called lpc18xx_wdt. - -config ATLAS7_WATCHDOG - tristate "CSRatlas7 watchdog" - depends on ARCH_ATLAS7 - help - Say Y here to include Watchdog timer support for the watchdog - existing on the CSRatlas7 series platforms. - - To compile this driver as a module, choose M here: the - module will be called atlas7_wdt. - -config RENESAS_WDT - tristate "Renesas WDT Watchdog" - depends on ARCH_RENESAS || COMPILE_TEST - select WATCHDOG_CORE - help - This driver adds watchdog support for the integrated watchdogs in the - Renesas R-Car and other SH-Mobile SoCs (usually named RWDT or SWDT). - -config ASPEED_WATCHDOG - tristate "Aspeed 2400 watchdog support" - depends on ARCH_ASPEED || COMPILE_TEST - select WATCHDOG_CORE - help - Say Y here to include support for the watchdog timer - in Apseed BMC SoCs. - - This driver is required to reboot the SoC. - - To compile this driver as a module, choose M here: the - module will be called aspeed_wdt. - -# AVR32 Architecture - -config AT32AP700X_WDT - tristate "AT32AP700x watchdog" - depends on CPU_AT32AP700X - help - Watchdog timer embedded into AT32AP700x devices. This will reboot - your system when the timeout is reached. - -# BLACKFIN Architecture - -config BFIN_WDT - tristate "Blackfin On-Chip Watchdog Timer" - depends on BLACKFIN - ---help--- - If you say yes here you will get support for the Blackfin On-Chip - Watchdog Timer. If you have one of these processors and wish to - have watchdog support enabled, say Y, otherwise say N. - - To compile this driver as a module, choose M here: the - module will be called bfin_wdt. - -# CRIS Architecture - -# FRV Architecture - -# X86 (i386 + ia64 + x86_64) Architecture - -config ACQUIRE_WDT - tristate "Acquire SBC Watchdog Timer" - depends on X86 - ---help--- - This is the driver for the hardware watchdog on Single Board - Computers produced by Acquire Inc (and others). This watchdog - simply watches your kernel to make sure it doesn't freeze, and if - it does, it reboots your computer after a certain amount of time. - - To compile this driver as a module, choose M here: the - module will be called acquirewdt. - - Most people will say N. - -config ADVANTECH_WDT - tristate "Advantech SBC Watchdog Timer" - depends on X86 - help - If you are configuring a Linux kernel for the Advantech single-board - computer, say `Y' here to support its built-in watchdog timer - feature. More information can be found at - - -config ALIM1535_WDT - tristate "ALi M1535 PMU Watchdog Timer" - depends on X86 && PCI - ---help--- - This is the driver for the hardware watchdog on the ALi M1535 PMU. - - To compile this driver as a module, choose M here: the - module will be called alim1535_wdt. - - Most people will say N. - -config ALIM7101_WDT - tristate "ALi M7101 PMU Computer Watchdog" - depends on PCI - help - This is the driver for the hardware watchdog on the ALi M7101 PMU - as used in the x86 Cobalt servers and also found in some - SPARC Netra servers too. - - To compile this driver as a module, choose M here: the - module will be called alim7101_wdt. - - Most people will say N. - -config EBC_C384_WDT - tristate "WinSystems EBC-C384 Watchdog Timer" - depends on X86 && ISA_BUS_API - select WATCHDOG_CORE - help - Enables watchdog timer support for the watchdog timer on the - WinSystems EBC-C384 motherboard. The timeout may be configured via - the timeout module parameter. - -config F71808E_WDT - tristate "Fintek F71808E, F71862FG, F71869, F71882FG and F71889FG Watchdog" - depends on X86 - help - This is the driver for the hardware watchdog on the Fintek - F71808E, F71862FG, F71869, F71882FG and F71889FG Super I/O controllers. - - You can compile this driver directly into the kernel, or use - it as a module. The module will be called f71808e_wdt. - -config SP5100_TCO - tristate "AMD/ATI SP5100 TCO Timer/Watchdog" - depends on X86 && PCI - ---help--- - Hardware watchdog driver for the AMD/ATI SP5100 chipset. The TCO - (Total Cost of Ownership) timer is a watchdog timer that will reboot - the machine after its expiration. The expiration time can be - configured with the "heartbeat" parameter. - - To compile this driver as a module, choose M here: the - module will be called sp5100_tco. - -config GEODE_WDT - tristate "AMD Geode CS5535/CS5536 Watchdog" - depends on CS5535_MFGPT - help - This driver enables a watchdog capability built into the - CS5535/CS5536 companion chips for the AMD Geode GX and LX - processors. This watchdog watches your kernel to make sure - it doesn't freeze, and if it does, it reboots your computer after - a certain amount of time. - - You can compile this driver directly into the kernel, or use - it as a module. The module will be called geodewdt. - -config SC520_WDT - tristate "AMD Elan SC520 processor Watchdog" - depends on MELAN - help - This is the driver for the hardware watchdog built in to the - AMD "Elan" SC520 microcomputer commonly used in embedded systems. - This watchdog simply watches your kernel to make sure it doesn't - freeze, and if it does, it reboots your computer after a certain - amount of time. - - You can compile this driver directly into the kernel, or use - it as a module. The module will be called sc520_wdt. - -config SBC_FITPC2_WATCHDOG - tristate "Compulab SBC-FITPC2 watchdog" - depends on X86 - ---help--- - This is the driver for the built-in watchdog timer on the fit-PC2, - fit-PC2i, CM-iAM single-board computers made by Compulab. - - It`s possible to enable watchdog timer either from BIOS (F2) or from booted Linux. - When "Watchdog Timer Value" enabled one can set 31-255 s operational range. - - Entering BIOS setup temporary disables watchdog operation regardless to current state, - so system will not be restarted while user in BIOS setup. - - Once watchdog was enabled the system will be restarted every - "Watchdog Timer Value" period, so to prevent it user can restart or - disable the watchdog. - - To compile this driver as a module, choose M here: the - module will be called sbc_fitpc2_wdt. - - Most people will say N. - -config EUROTECH_WDT - tristate "Eurotech CPU-1220/1410 Watchdog Timer" - depends on X86 - help - Enable support for the watchdog timer on the Eurotech CPU-1220 and - CPU-1410 cards. These are PC/104 SBCs. Spec sheets and product - information are at . - -config IB700_WDT - tristate "IB700 SBC Watchdog Timer" - depends on X86 - ---help--- - This is the driver for the hardware watchdog on the IB700 Single - Board Computer produced by TMC Technology (www.tmc-uk.com). This watchdog - simply watches your kernel to make sure it doesn't freeze, and if - it does, it reboots your computer after a certain amount of time. - - This driver is like the WDT501 driver but for slightly different hardware. - - To compile this driver as a module, choose M here: the - module will be called ib700wdt. - - Most people will say N. - -config IBMASR - tristate "IBM Automatic Server Restart" - depends on X86 - help - This is the driver for the IBM Automatic Server Restart watchdog - timer built-in into some eServer xSeries machines. - - To compile this driver as a module, choose M here: the - module will be called ibmasr. - -config WAFER_WDT - tristate "ICP Single Board Computer Watchdog Timer" - depends on X86 - help - This is a driver for the hardware watchdog on the ICP Single - Board Computer. This driver is working on (at least) the following - IPC SBC's: Wafer 5823, Rocky 4783, Rocky 3703 and Rocky 3782. - - To compile this driver as a module, choose M here: the - module will be called wafer5823wdt. - -config I6300ESB_WDT - tristate "Intel 6300ESB Timer/Watchdog" - depends on PCI - ---help--- - Hardware driver for the watchdog timer built into the Intel - 6300ESB controller hub. - - To compile this driver as a module, choose M here: the - module will be called i6300esb. - -config IE6XX_WDT - tristate "Intel Atom E6xx Watchdog" - depends on X86 && PCI - select WATCHDOG_CORE - select MFD_CORE - select LPC_SCH - ---help--- - Hardware driver for the watchdog timer built into the Intel - Atom E6XX (TunnelCreek) processor. - - To compile this driver as a module, choose M here: the - module will be called ie6xx_wdt. - -config INTEL_SCU_WATCHDOG - bool "Intel SCU Watchdog for Mobile Platforms" - depends on X86_INTEL_MID - ---help--- - Hardware driver for the watchdog time built into the Intel SCU - for Intel Mobile Platforms. - - To compile this driver as a module, choose M here. - -config INTEL_MID_WATCHDOG - tristate "Intel MID Watchdog Timer" - depends on X86_INTEL_MID - select WATCHDOG_CORE - ---help--- - Watchdog timer driver built into the Intel SCU for Intel MID - Platforms. - - This driver currently supports only the watchdog evolution - implementation in SCU, available for Merrifield generation. - - To compile this driver as a module, choose M here. - -config ITCO_WDT - tristate "Intel TCO Timer/Watchdog" - depends on (X86 || IA64) && PCI - select WATCHDOG_CORE - depends on I2C || I2C=n - select LPC_ICH if !EXPERT - select I2C_I801 if !EXPERT && I2C - ---help--- - Hardware driver for the intel TCO timer based watchdog devices. - These drivers are included in the Intel 82801 I/O Controller - Hub family (from ICH0 up to ICH10) and in the Intel 63xxESB - controller hub. - - The TCO (Total Cost of Ownership) timer is a watchdog timer - that will reboot the machine after its second expiration. The - expiration time can be configured with the "heartbeat" parameter. - - On some motherboards the driver may fail to reset the chipset's - NO_REBOOT flag which prevents the watchdog from rebooting the - machine. If this is the case you will get a kernel message like - "failed to reset NO_REBOOT flag, reboot disabled by hardware". - - To compile this driver as a module, choose M here: the - module will be called iTCO_wdt. - -config ITCO_VENDOR_SUPPORT - bool "Intel TCO Timer/Watchdog Specific Vendor Support" - depends on ITCO_WDT - ---help--- - Add vendor specific support to the intel TCO timer based watchdog - devices. At this moment we only have additional support for some - SuperMicro Inc. motherboards. - -config IT8712F_WDT - tristate "IT8712F (Smart Guardian) Watchdog Timer" - depends on X86 - ---help--- - This is the driver for the built-in watchdog timer on the IT8712F - Super I/0 chipset used on many motherboards. - - If the driver does not work, then make sure that the game port in - the BIOS is enabled. - - To compile this driver as a module, choose M here: the - module will be called it8712f_wdt. - -config IT87_WDT - tristate "IT87 Watchdog Timer" - depends on X86 - ---help--- - This is the driver for the hardware watchdog on the ITE IT8702, - IT8712, IT8716, IT8718, IT8720, IT8721, IT8726 and IT8728 - Super I/O chips. - - If the driver does not work, then make sure that the game port in - the BIOS is enabled. - - This watchdog simply watches your kernel to make sure it doesn't - freeze, and if it does, it reboots your computer after a certain - amount of time. - - To compile this driver as a module, choose M here: the module will - be called it87_wdt. - -config HP_WATCHDOG - tristate "HP ProLiant iLO2+ Hardware Watchdog Timer" - depends on X86 && PCI - help - A software monitoring watchdog and NMI sourcing driver. This driver - will detect lockups and provide a stack trace. This is a driver that - will only load on an HP ProLiant system with a minimum of iLO2 support. - To compile this driver as a module, choose M here: the module will be - called hpwdt. - -config KEMPLD_WDT - tristate "Kontron COM Watchdog Timer" - depends on MFD_KEMPLD - select WATCHDOG_CORE - help - Support for the PLD watchdog on some Kontron ETX and COMexpress - (ETXexpress) modules - - This driver can also be built as a module. If so, the module will be - called kempld_wdt. - -config HPWDT_NMI_DECODING - bool "NMI decoding support for the HP ProLiant iLO2+ Hardware Watchdog Timer" - depends on HP_WATCHDOG - default y - help - When an NMI occurs this feature will make the necessary BIOS calls to - log the cause of the NMI. - -config SC1200_WDT - tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog" - depends on X86 - help - This is a driver for National Semiconductor PC87307/PC97307 hardware - watchdog cards as found on the SC1200. This watchdog is mainly used - for power management purposes and can be used to power down the device - during inactivity periods (includes interrupt activity monitoring). - - To compile this driver as a module, choose M here: the - module will be called sc1200wdt. - - Most people will say N. - -config SCx200_WDT - tristate "National Semiconductor SCx200 Watchdog" - depends on SCx200 && PCI - help - Enable the built-in watchdog timer support on the National - Semiconductor SCx200 processors. - - If compiled as a module, it will be called scx200_wdt. - -config PC87413_WDT - tristate "NS PC87413 watchdog" - depends on X86 - ---help--- - This is the driver for the hardware watchdog on the PC87413 chipset - This watchdog simply watches your kernel to make sure it doesn't - freeze, and if it does, it reboots your computer after a certain - amount of time. - - To compile this driver as a module, choose M here: the - module will be called pc87413_wdt. - - Most people will say N. - -config NV_TCO - tristate "nVidia TCO Timer/Watchdog" - depends on X86 && PCI - ---help--- - Hardware driver for the TCO timer built into the nVidia Hub family - (such as the MCP51). The TCO (Total Cost of Ownership) timer is a - watchdog timer that will reboot the machine after its second - expiration. The expiration time can be configured with the - "heartbeat" parameter. - - On some motherboards the driver may fail to reset the chipset's - NO_REBOOT flag which prevents the watchdog from rebooting the - machine. If this is the case you will get a kernel message like - "failed to reset NO_REBOOT flag, reboot disabled by hardware". - - To compile this driver as a module, choose M here: the - module will be called nv_tco. - -config RDC321X_WDT - tristate "RDC R-321x SoC watchdog" - depends on X86_RDC321X - help - This is the driver for the built in hardware watchdog - in the RDC R-321x SoC. - - To compile this driver as a module, choose M here: the - module will be called rdc321x_wdt. - -config 60XX_WDT - tristate "SBC-60XX Watchdog Timer" - depends on X86 - help - This driver can be used with the watchdog timer found on some - single board computers, namely the 6010 PII based computer. - It may well work with other cards. It reads port 0x443 to enable - and re-set the watchdog timer, and reads port 0x45 to disable - the watchdog. If you have a card that behave in similar ways, - you can probably make this driver work with your card as well. - - You can compile this driver directly into the kernel, or use - it as a module. The module will be called sbc60xxwdt. - -config SBC8360_WDT - tristate "SBC8360 Watchdog Timer" - depends on X86_32 - ---help--- - - This is the driver for the hardware watchdog on the SBC8360 Single - Board Computer produced by Axiomtek Co., Ltd. (www.axiomtek.com). - - To compile this driver as a module, choose M here: the - module will be called sbc8360. - - Most people will say N. - -config SBC7240_WDT - tristate "SBC Nano 7240 Watchdog Timer" - depends on X86_32 && !UML - ---help--- - This is the driver for the hardware watchdog found on the IEI - single board computers EPIC Nano 7240 (and likely others). This - watchdog simply watches your kernel to make sure it doesn't freeze, - and if it does, it reboots your computer after a certain amount of - time. - - To compile this driver as a module, choose M here: the - module will be called sbc7240_wdt. - -config CPU5_WDT - tristate "SMA CPU5 Watchdog" - depends on X86 - ---help--- - TBD. - To compile this driver as a module, choose M here: the - module will be called cpu5wdt. - -config SMSC_SCH311X_WDT - tristate "SMSC SCH311X Watchdog Timer" - depends on X86 - ---help--- - This is the driver for the hardware watchdog timer on the - SMSC SCH3112, SCH3114 and SCH3116 Super IO chipset - (LPC IO with 8042 KBC, Reset Generation, HWM and multiple - serial ports). - - To compile this driver as a module, choose M here: the - module will be called sch311x_wdt. - -config SMSC37B787_WDT - tristate "Winbond SMsC37B787 Watchdog Timer" - depends on X86 - ---help--- - This is the driver for the hardware watchdog component on the - Winbond SMsC37B787 chipset as used on the NetRunner Mainboard - from Vision Systems and maybe others. - - This watchdog simply watches your kernel to make sure it doesn't - freeze, and if it does, it reboots your computer after a certain - amount of time. - - Usually a userspace daemon will notify the kernel WDT driver that - userspace is still alive, at regular intervals. - - To compile this driver as a module, choose M here: the - module will be called smsc37b787_wdt. - - Most people will say N. - -config VIA_WDT - tristate "VIA Watchdog Timer" - depends on X86 && PCI - select WATCHDOG_CORE - ---help--- - This is the driver for the hardware watchdog timer on VIA - southbridge chipset CX700, VX800/VX820 or VX855/VX875. - - To compile this driver as a module, choose M here; the module - will be called via_wdt. - - Most people will say N. - -config W83627HF_WDT - tristate "Watchdog timer for W83627HF/W83627DHG and compatibles" - depends on X86 - select WATCHDOG_CORE - ---help--- - This is the driver for the hardware watchdog on the following - Super I/O chips. - W83627DHG/DHG-P/EHF/EHG/F/G/HF/S/SF/THF/UHG/UG - W83637HF - W83667HG/HG-B - W83687THF - W83697HF - W83697UG - NCT6775 - NCT6776 - NCT6779 - NCT6791 - NCT6792 - NCT6102D/04D/06D - - This watchdog simply watches your kernel to make sure it doesn't - freeze, and if it does, it reboots your computer after a certain - amount of time. - - To compile this driver as a module, choose M here: the - module will be called w83627hf_wdt. - - Most people will say N. - -config W83877F_WDT - tristate "W83877F (EMACS) Watchdog Timer" - depends on X86 - ---help--- - This is the driver for the hardware watchdog on the W83877F chipset - as used in EMACS PC-104 motherboards (and likely others). This - watchdog simply watches your kernel to make sure it doesn't freeze, - and if it does, it reboots your computer after a certain amount of - time. - - To compile this driver as a module, choose M here: the - module will be called w83877f_wdt. - - Most people will say N. - -config W83977F_WDT - tristate "W83977F (PCM-5335) Watchdog Timer" - depends on X86 - ---help--- - This is the driver for the hardware watchdog on the W83977F I/O chip - as used in AAEON's PCM-5335 SBC (and likely others). This - watchdog simply watches your kernel to make sure it doesn't freeze, - and if it does, it reboots your computer after a certain amount of - time. - - To compile this driver as a module, choose M here: the - module will be called w83977f_wdt. - -config MACHZ_WDT - tristate "ZF MachZ Watchdog" - depends on X86 - ---help--- - If you are using a ZF Micro MachZ processor, say Y here, otherwise - N. This is the driver for the watchdog timer built-in on that - processor using ZF-Logic interface. This watchdog simply watches - your kernel to make sure it doesn't freeze, and if it does, it - reboots your computer after a certain amount of time. - - To compile this driver as a module, choose M here: the - module will be called machzwd. - -config SBC_EPX_C3_WATCHDOG - tristate "Winsystems SBC EPX-C3 watchdog" - depends on X86 - ---help--- - This is the driver for the built-in watchdog timer on the EPX-C3 - Single-board computer made by Winsystems, Inc. - - *Note*: This hardware watchdog is not probeable and thus there - is no way to know if writing to its IO address will corrupt - your system or have any real effect. The only way to be sure - that this driver does what you want is to make sure you - are running it on an EPX-C3 from Winsystems with the watchdog - timer at IO address 0x1ee and 0x1ef. It will write to both those - IO ports. Basically, the assumption is made that if you compile - this driver into your kernel and/or load it as a module, that you - know what you are doing and that you are in fact running on an - EPX-C3 board! - - To compile this driver as a module, choose M here: the - module will be called sbc_epx_c3. - -config INTEL_MEI_WDT - tristate "Intel MEI iAMT Watchdog" - depends on INTEL_MEI && X86 - select WATCHDOG_CORE - ---help--- - A device driver for the Intel MEI iAMT watchdog. - - The Intel AMT Watchdog is an OS Health (Hang/Crash) watchdog. - Whenever the OS hangs or crashes, iAMT will send an event - to any subscriber to this event. The watchdog doesn't reset the - the platform. - - To compile this driver as a module, choose M here: - the module will be called mei_wdt. - -config NI903X_WDT - tristate "NI 903x/913x Watchdog" - depends on X86 && ACPI - select WATCHDOG_CORE - ---help--- - This is the driver for the watchdog timer on the National Instruments - 903x/913x real-time controllers. - - To compile this driver as a module, choose M here: the module will be - called ni903x_wdt. - -# M32R Architecture - -# M68K Architecture - -config M54xx_WATCHDOG - tristate "MCF54xx watchdog support" - depends on M548x - help - To compile this driver as a module, choose M here: the - module will be called m54xx_wdt. - -# MicroBlaze Architecture - -# MIPS Architecture - -config ATH79_WDT - tristate "Atheros AR71XX/AR724X/AR913X hardware watchdog" - depends on ATH79 - help - Hardware driver for the built-in watchdog timer on the Atheros - AR71XX/AR724X/AR913X SoCs. - -config BCM47XX_WDT - tristate "Broadcom BCM47xx Watchdog Timer" - depends on BCM47XX || ARCH_BCM_5301X - select WATCHDOG_CORE - help - Hardware driver for the Broadcom BCM47xx Watchdog Timer. - -config RC32434_WDT - tristate "IDT RC32434 SoC Watchdog Timer" - depends on MIKROTIK_RB532 - help - Hardware driver for the IDT RC32434 SoC built-in - watchdog timer. - - To compile this driver as a module, choose M here: the - module will be called rc32434_wdt. - -config INDYDOG - tristate "Indy/I2 Hardware Watchdog" - depends on SGI_HAS_INDYDOG - help - Hardware driver for the Indy's/I2's watchdog. This is a - watchdog timer that will reboot the machine after a 60 second - timer expired and no process has written to /dev/watchdog during - that time. - -config JZ4740_WDT - tristate "Ingenic jz4740 SoC hardware watchdog" - depends on MACH_JZ4740 - select WATCHDOG_CORE - help - Hardware driver for the built-in watchdog timer on Ingenic jz4740 SoCs. - -config WDT_MTX1 - tristate "MTX-1 Hardware Watchdog" - depends on MIPS_MTX1 - help - Hardware driver for the MTX-1 boards. This is a watchdog timer that - will reboot the machine after a 100 seconds timer expired. - -config PNX833X_WDT - tristate "PNX833x Hardware Watchdog" - depends on SOC_PNX8335 - help - Hardware driver for the PNX833x's watchdog. This is a - watchdog timer that will reboot the machine after a programmable - timer has expired and no process has written to /dev/watchdog during - that time. - -config SIBYTE_WDOG - tristate "Sibyte SoC hardware watchdog" - depends on CPU_SB1 - help - Watchdog driver for the built in watchdog hardware in Sibyte - SoC processors. There are apparently two watchdog timers - on such processors; this driver supports only the first one, - because currently Linux only supports exporting one watchdog - to userspace. - - To compile this driver as a loadable module, choose M here. - The module will be called sb_wdog. - -config AR7_WDT - tristate "TI AR7 Watchdog Timer" - depends on AR7 - help - Hardware driver for the TI AR7 Watchdog Timer. - -config TXX9_WDT - tristate "Toshiba TXx9 Watchdog Timer" - depends on CPU_TX39XX || CPU_TX49XX - select WATCHDOG_CORE - help - Hardware driver for the built-in watchdog timer on TXx9 MIPS SoCs. - -config OCTEON_WDT - tristate "Cavium OCTEON SOC family Watchdog Timer" - depends on CAVIUM_OCTEON_SOC - default y - select WATCHDOG_CORE - select EXPORT_UASM if OCTEON_WDT = m - help - Hardware driver for OCTEON's on chip watchdog timer. - Enables the watchdog for all cores running Linux. It - installs a NMI handler and pokes the watchdog based on an - interrupt. On first expiration of the watchdog, the - interrupt handler pokes it. The second expiration causes an - NMI that prints a message. The third expiration causes a - global soft reset. - - When userspace has /dev/watchdog open, no poking is done - from the first interrupt, it is then only poked when the - device is written. - -config BCM63XX_WDT - tristate "Broadcom BCM63xx hardware watchdog" - depends on BCM63XX - help - Watchdog driver for the built in watchdog hardware in Broadcom - BCM63xx SoC. - - To compile this driver as a loadable module, choose M here. - The module will be called bcm63xx_wdt. - -config BCM2835_WDT - tristate "Broadcom BCM2835 hardware watchdog" - depends on ARCH_BCM2835 - select WATCHDOG_CORE - help - Watchdog driver for the built in watchdog hardware in Broadcom - BCM2835 SoC. - - To compile this driver as a loadable module, choose M here. - The module will be called bcm2835_wdt. - -config BCM_KONA_WDT - tristate "BCM Kona Watchdog" - depends on ARCH_BCM_MOBILE - select WATCHDOG_CORE - help - Support for the watchdog timer on the following Broadcom BCM281xx - family, which includes BCM11130, BCM11140, BCM11351, BCM28145 and - BCM28155 variants. - - Say 'Y' or 'M' here to enable the driver. The module will be called - bcm_kona_wdt. - -config BCM_KONA_WDT_DEBUG - bool "DEBUGFS support for BCM Kona Watchdog" - depends on BCM_KONA_WDT - help - If enabled, adds /sys/kernel/debug/bcm_kona_wdt/info which provides - access to the driver's internal data structures as well as watchdog - timer hardware registres. - - If in doubt, say 'N'. - -config BCM7038_WDT - tristate "BCM7038 Watchdog" - select WATCHDOG_CORE - depends on HAS_IOMEM - depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST - help - Watchdog driver for the built-in hardware in Broadcom 7038 and - later SoCs used in set-top boxes. BCM7038 was made public - during the 2004 CES, and since then, many Broadcom chips use this - watchdog block, including some cable modem chips. - -config IMGPDC_WDT - tristate "Imagination Technologies PDC Watchdog Timer" - depends on HAS_IOMEM - depends on METAG || MIPS || COMPILE_TEST - select WATCHDOG_CORE - help - Driver for Imagination Technologies PowerDown Controller - Watchdog Timer. - - To compile this driver as a loadable module, choose M here. - The module will be called imgpdc_wdt. - -config LANTIQ_WDT - tristate "Lantiq SoC watchdog" - depends on LANTIQ - help - Hardware driver for the Lantiq SoC Watchdog Timer. - -config RALINK_WDT - tristate "Ralink SoC watchdog" - select WATCHDOG_CORE - depends on RALINK - help - Hardware driver for the Ralink SoC Watchdog Timer. - -config MT7621_WDT - tristate "Mediatek SoC watchdog" - select WATCHDOG_CORE - depends on SOC_MT7620 || SOC_MT7621 - help - Hardware driver for the Mediatek/Ralink MT7621/8 SoC Watchdog Timer. - -config PIC32_WDT - tristate "Microchip PIC32 hardware watchdog" - select WATCHDOG_CORE - depends on MACH_PIC32 - help - Watchdog driver for the built in watchdog hardware in a PIC32. - - Configuration bits must be set appropriately for the watchdog to be - controlled by this driver. - - To compile this driver as a loadable module, choose M here. - The module will be called pic32-wdt. - -config PIC32_DMT - tristate "Microchip PIC32 Deadman Timer" - select WATCHDOG_CORE - depends on MACH_PIC32 - help - Watchdog driver for PIC32 instruction fetch counting timer. This specific - timer is typically be used in misson critical and safety critical - applications, where any single failure of the software functionality - and sequencing must be detected. - - To compile this driver as a loadable module, choose M here. - The module will be called pic32-dmt. - -# PARISC Architecture - -# POWERPC Architecture - -config GEF_WDT - tristate "GE Watchdog Timer" - depends on GE_FPGA - ---help--- - Watchdog timer found in a number of GE single board computers. - -config MPC5200_WDT - bool "MPC52xx Watchdog Timer" - depends on PPC_MPC52xx - help - Use General Purpose Timer (GPT) 0 on the MPC5200 as Watchdog. - -config 8xxx_WDT - tristate "MPC8xxx Platform Watchdog Timer" - depends on PPC_8xx || PPC_83xx || PPC_86xx || PPC_MPC512x - select WATCHDOG_CORE - help - This driver is for a SoC level watchdog that exists on some - Freescale PowerPC processors. So far this driver supports: - - MPC8xx watchdogs - - MPC83xx watchdogs - - MPC86xx watchdogs - - For BookE processors (MPC85xx) use the BOOKE_WDT driver instead. - -config MV64X60_WDT - tristate "MV64X60 (Marvell Discovery) Watchdog Timer" - depends on MV64X60 - -config PIKA_WDT - tristate "PIKA FPGA Watchdog" - depends on WARP - default y - help - This enables the watchdog in the PIKA FPGA. Currently used on - the Warp platform. - -config BOOKE_WDT - tristate "PowerPC Book-E Watchdog Timer" - depends on BOOKE || 4xx - select WATCHDOG_CORE - ---help--- - Watchdog driver for PowerPC Book-E chips, such as the Freescale - MPC85xx SOCs and the IBM PowerPC 440. - - Please see Documentation/watchdog/watchdog-api.txt for - more information. - -config BOOKE_WDT_DEFAULT_TIMEOUT - int "PowerPC Book-E Watchdog Timer Default Timeout" - depends on BOOKE_WDT - default 38 if PPC_FSL_BOOK3E - range 0 63 if PPC_FSL_BOOK3E - default 3 if !PPC_FSL_BOOK3E - range 0 3 if !PPC_FSL_BOOK3E - help - Select the default watchdog timer period to be used by the PowerPC - Book-E watchdog driver. A watchdog "event" occurs when the bit - position represented by this number transitions from zero to one. - - For Freescale Book-E processors, this is a number between 0 and 63. - For other Book-E processors, this is a number between 0 and 3. - - The value can be overridden by the wdt_period command-line parameter. - -config MEN_A21_WDT - tristate "MEN A21 VME CPU Carrier Board Watchdog Timer" - select WATCHDOG_CORE - depends on GPIOLIB || COMPILE_TEST - help - Watchdog driver for MEN A21 VMEbus CPU Carrier Boards. - - The driver can also be built as a module. If so, the module will be - called mena21_wdt. - - If unsure select N here. - -# PPC64 Architecture - -config WATCHDOG_RTAS - tristate "RTAS watchdog" - depends on PPC_RTAS - help - This driver adds watchdog support for the RTAS watchdog. - - To compile this driver as a module, choose M here. The module - will be called wdrtas. - -# S390 Architecture - -config DIAG288_WATCHDOG - tristate "System z diag288 Watchdog" - depends on S390 - select WATCHDOG_CORE - help - IBM s/390 and zSeries machines running under z/VM 5.1 or later - provide a virtual watchdog timer to their guest that cause a - user define Control Program command to be executed after a - timeout. - LPAR provides a very similar interface. This driver handles - both. - - To compile this driver as a module, choose M here. The module - will be called diag288_wdt. - -# SUPERH (sh + sh64) Architecture - -config SH_WDT - tristate "SuperH Watchdog" - depends on SUPERH && (CPU_SH3 || CPU_SH4) - select WATCHDOG_CORE - help - This driver adds watchdog support for the integrated watchdog in the - SuperH processors. If you have one of these processors and wish - to have watchdog support enabled, say Y, otherwise say N. - - As a side note, saying Y here will automatically boost HZ to 1000 - so that the timer has a chance to clear the overflow counter. On - slower systems (such as the SH-2 and SH-3) this will likely yield - some performance issues. As such, the WDT should be avoided here - unless it is absolutely necessary. - - To compile this driver as a module, choose M here: the - module will be called shwdt. - -# SPARC Architecture - -# SPARC64 Architecture - -config WATCHDOG_CP1XXX - tristate "CP1XXX Hardware Watchdog support" - depends on SPARC64 && PCI - ---help--- - This is the driver for the hardware watchdog timers present on - Sun Microsystems CompactPCI models CP1400 and CP1500. - - To compile this driver as a module, choose M here: the - module will be called cpwatchdog. - - If you do not have a CompactPCI model CP1400 or CP1500, or - another UltraSPARC-IIi-cEngine boardset with hardware watchdog, - you should say N to this option. - -config WATCHDOG_RIO - tristate "RIO Hardware Watchdog support" - depends on SPARC64 && PCI - help - Say Y here to support the hardware watchdog capability on Sun RIO - machines. The watchdog timeout period is normally one minute but - can be changed with a boot-time parameter. - -config WATCHDOG_SUN4V - tristate "Sun4v Watchdog support" - select WATCHDOG_CORE - depends on SPARC64 - help - Say Y here to support the hypervisor watchdog capability embedded - in the SPARC sun4v architecture. - - To compile this driver as a module, choose M here. The module will - be called sun4v_wdt. - -# XTENSA Architecture - -# Xen Architecture - -config XEN_WDT - tristate "Xen Watchdog support" - depends on XEN - help - Say Y here to support the hypervisor watchdog capability provided - by Xen 4.0 and newer. The watchdog timeout period is normally one - minute but can be changed with a boot-time parameter. - -config UML_WATCHDOG - tristate "UML watchdog" - depends on UML - -# -# ISA-based Watchdog Cards -# - -comment "ISA-based Watchdog Cards" - depends on ISA - -config PCWATCHDOG - tristate "Berkshire Products ISA-PC Watchdog" - depends on ISA - ---help--- - This is the driver for the Berkshire Products ISA-PC Watchdog card. - This card simply watches your kernel to make sure it doesn't freeze, - and if it does, it reboots your computer after a certain amount of - time. This driver is like the WDT501 driver but for different - hardware. Please read . The PC - watchdog cards can be ordered from . - - To compile this driver as a module, choose M here: the - module will be called pcwd. - - Most people will say N. - -config MIXCOMWD - tristate "Mixcom Watchdog" - depends on ISA - ---help--- - This is a driver for the Mixcom hardware watchdog cards. This - watchdog simply watches your kernel to make sure it doesn't freeze, - and if it does, it reboots your computer after a certain amount of - time. - - To compile this driver as a module, choose M here: the - module will be called mixcomwd. - - Most people will say N. - -config WDT - tristate "WDT Watchdog timer" - depends on ISA - ---help--- - If you have a WDT500P or WDT501P watchdog board, say Y here, - otherwise N. It is not possible to probe for this board, which means - that you have to inform the kernel about the IO port and IRQ that - is needed (you can do this via the io and irq parameters) - - To compile this driver as a module, choose M here: the - module will be called wdt. - -# -# PCI-based Watchdog Cards -# - -comment "PCI-based Watchdog Cards" - depends on PCI - -config PCIPCWATCHDOG - tristate "Berkshire Products PCI-PC Watchdog" - depends on PCI - ---help--- - This is the driver for the Berkshire Products PCI-PC Watchdog card. - This card simply watches your kernel to make sure it doesn't freeze, - and if it does, it reboots your computer after a certain amount of - time. The card can also monitor the internal temperature of the PC. - More info is available at . - - To compile this driver as a module, choose M here: the - module will be called pcwd_pci. - - Most people will say N. - -config WDTPCI - tristate "PCI-WDT500/501 Watchdog timer" - depends on PCI - ---help--- - If you have a PCI-WDT500/501 watchdog board, say Y here, otherwise N. - - If you have a PCI-WDT501 watchdog board then you can enable the - temperature sensor by setting the type parameter to 501. - - If you want to enable the Fan Tachometer on the PCI-WDT501, then you - can do this via the tachometer parameter. Only do this if you have a - fan tachometer actually set up. - - To compile this driver as a module, choose M here: the - module will be called wdt_pci. - -# -# USB-based Watchdog Cards -# - -comment "USB-based Watchdog Cards" - depends on USB - -config USBPCWATCHDOG - tristate "Berkshire Products USB-PC Watchdog" - depends on USB - ---help--- - This is the driver for the Berkshire Products USB-PC Watchdog card. - This card simply watches your kernel to make sure it doesn't freeze, - and if it does, it reboots your computer after a certain amount of - time. The card can also monitor the internal temperature of the PC. - More info is available at . - - To compile this driver as a module, choose M here: the - module will be called pcwd_usb. - - Most people will say N. - -comment "Watchdog Pretimeout Governors" - -config WATCHDOG_PRETIMEOUT_GOV - bool "Enable watchdog pretimeout governors" - help - The option allows to select watchdog pretimeout governors. - -if WATCHDOG_PRETIMEOUT_GOV - -choice - prompt "Default Watchdog Pretimeout Governor" - default WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC - help - This option selects a default watchdog pretimeout governor. - The governor takes its action, if a watchdog is capable - to report a pretimeout event. - -config WATCHDOG_PRETIMEOUT_DEFAULT_GOV_NOOP - bool "noop" - select WATCHDOG_PRETIMEOUT_GOV_NOOP - help - Use noop watchdog pretimeout governor by default. If noop - governor is selected by a user, write a short message to - the kernel log buffer and don't do any system changes. - -config WATCHDOG_PRETIMEOUT_DEFAULT_GOV_PANIC - bool "panic" - select WATCHDOG_PRETIMEOUT_GOV_PANIC - help - Use panic watchdog pretimeout governor by default, if - a watchdog pretimeout event happens, consider that - a watchdog feeder is dead and reboot is unavoidable. - -endchoice - -config WATCHDOG_PRETIMEOUT_GOV_NOOP - tristate "Noop watchdog pretimeout governor" - help - Noop watchdog pretimeout governor, only an informational - message is added to kernel log buffer. - -config WATCHDOG_PRETIMEOUT_GOV_PANIC - tristate "Panic watchdog pretimeout governor" - help - Panic watchdog pretimeout governor, on watchdog pretimeout - event put the kernel into panic. - -endif # WATCHDOG_PRETIMEOUT_GOV - -endif # WATCHDOG diff --git a/src/linux/drivers/xen/Kconfig b/src/linux/drivers/xen/Kconfig deleted file mode 100644 index f15bb3b..0000000 --- a/src/linux/drivers/xen/Kconfig +++ /dev/null @@ -1,301 +0,0 @@ -menu "Xen driver support" - depends on XEN - -config XEN_BALLOON - bool "Xen memory balloon driver" - default y - help - The balloon driver allows the Xen domain to request more memory from - the system to expand the domain's memory allocation, or alternatively - return unneeded memory to the system. - -config XEN_SELFBALLOONING - bool "Dynamically self-balloon kernel memory to target" - depends on XEN && XEN_BALLOON && CLEANCACHE && SWAP && XEN_TMEM - default n - help - Self-ballooning dynamically balloons available kernel memory driven - by the current usage of anonymous memory ("committed AS") and - controlled by various sysfs-settable parameters. Configuring - FRONTSWAP is highly recommended; if it is not configured, self- - ballooning is disabled by default. If FRONTSWAP is configured, - frontswap-selfshrinking is enabled by default but can be disabled - with the 'tmem.selfshrink=0' kernel boot parameter; and self-ballooning - is enabled by default but can be disabled with the 'tmem.selfballooning=0' - kernel boot parameter. Note that systems without a sufficiently - large swap device should not enable self-ballooning. - -config XEN_BALLOON_MEMORY_HOTPLUG - bool "Memory hotplug support for Xen balloon driver" - default n - depends on XEN_BALLOON && MEMORY_HOTPLUG - help - Memory hotplug support for Xen balloon driver allows expanding memory - available for the system above limit declared at system startup. - It is very useful on critical systems which require long - run without rebooting. - - Memory could be hotplugged in following steps: - - 1) target domain: ensure that memory auto online policy is in - effect by checking /sys/devices/system/memory/auto_online_blocks - file (should be 'online'). - - 2) control domain: xl mem-max - where is >= requested memory size, - - 3) control domain: xl mem-set - where is requested memory size; alternatively memory - could be added by writing proper value to - /sys/devices/system/xen_memory/xen_memory0/target or - /sys/devices/system/xen_memory/xen_memory0/target_kb on the - target domain. - - Alternatively, if memory auto onlining was not requested at step 1 - the newly added memory can be manually onlined in the target domain - by doing the following: - - for i in /sys/devices/system/memory/memory*/state; do \ - [ "`cat "$i"`" = offline ] && echo online > "$i"; done - - or by adding the following line to udev rules: - - SUBSYSTEM=="memory", ACTION=="add", RUN+="/bin/sh -c '[ -f /sys$devpath/state ] && echo online > /sys$devpath/state'" - -config XEN_BALLOON_MEMORY_HOTPLUG_LIMIT - int "Hotplugged memory limit (in GiB) for a PV guest" - default 512 if X86_64 - default 4 if X86_32 - range 0 64 if X86_32 - depends on XEN_HAVE_PVMMU - depends on XEN_BALLOON_MEMORY_HOTPLUG - help - Maxmium amount of memory (in GiB) that a PV guest can be - expanded to when using memory hotplug. - - A PV guest can have more memory than this limit if is - started with a larger maximum. - - This value is used to allocate enough space in internal - tables needed for physical memory administration. - -config XEN_SCRUB_PAGES - bool "Scrub pages before returning them to system" - depends on XEN_BALLOON - default y - help - Scrub pages before returning them to the system for reuse by - other domains. This makes sure that any confidential data - is not accidentally visible to other domains. Is it more - secure, but slightly less efficient. - If in doubt, say yes. - -config XEN_DEV_EVTCHN - tristate "Xen /dev/xen/evtchn device" - default y - help - The evtchn driver allows a userspace process to trigger event - channels and to receive notification of an event channel - firing. - If in doubt, say yes. - -config XEN_BACKEND - bool "Backend driver support" - depends on XEN_DOM0 - default y - help - Support for backend device drivers that provide I/O services - to other virtual machines. - -config XENFS - tristate "Xen filesystem" - select XEN_PRIVCMD - default y - help - The xen filesystem provides a way for domains to share - information with each other and with the hypervisor. - For example, by reading and writing the "xenbus" file, guests - may pass arbitrary information to the initial domain. - If in doubt, say yes. - -config XEN_COMPAT_XENFS - bool "Create compatibility mount point /proc/xen" - depends on XENFS - default y - help - The old xenstore userspace tools expect to find "xenbus" - under /proc/xen, but "xenbus" is now found at the root of the - xenfs filesystem. Selecting this causes the kernel to create - the compatibility mount point /proc/xen if it is running on - a xen platform. - If in doubt, say yes. - -config XEN_SYS_HYPERVISOR - bool "Create xen entries under /sys/hypervisor" - depends on SYSFS - select SYS_HYPERVISOR - default y - help - Create entries under /sys/hypervisor describing the Xen - hypervisor environment. When running native or in another - virtual environment, /sys/hypervisor will still be present, - but will have no xen contents. - -config XEN_XENBUS_FRONTEND - tristate - -config XEN_GNTDEV - tristate "userspace grant access device driver" - depends on XEN - default m - select MMU_NOTIFIER - help - Allows userspace processes to use grants. - -config XEN_GRANT_DEV_ALLOC - tristate "User-space grant reference allocator driver" - depends on XEN - default m - help - Allows userspace processes to create pages with access granted - to other domains. This can be used to implement frontend drivers - or as part of an inter-domain shared memory channel. - -config SWIOTLB_XEN - def_bool y - select SWIOTLB - -config XEN_TMEM - tristate - depends on !ARM && !ARM64 - default m if (CLEANCACHE || FRONTSWAP) - help - Shim to interface in-kernel Transcendent Memory hooks - (e.g. cleancache and frontswap) to Xen tmem hypercalls. - -config XEN_PCIDEV_BACKEND - tristate "Xen PCI-device backend driver" - depends on PCI && X86 && XEN - depends on XEN_BACKEND - default m - help - The PCI device backend driver allows the kernel to export arbitrary - PCI devices to other guests. If you select this to be a module, you - will need to make sure no other driver has bound to the device(s) - you want to make visible to other guests. - - The parameter "passthrough" allows you specify how you want the PCI - devices to appear in the guest. You can choose the default (0) where - PCI topology starts at 00.00.0, or (1) for passthrough if you want - the PCI devices topology appear the same as in the host. - - The "hide" parameter (only applicable if backend driver is compiled - into the kernel) allows you to bind the PCI devices to this module - from the default device drivers. The argument is the list of PCI BDFs: - xen-pciback.hide=(03:00.0)(04:00.0) - - If in doubt, say m. - -config XEN_SCSI_BACKEND - tristate "XEN SCSI backend driver" - depends on XEN && XEN_BACKEND && TARGET_CORE - help - The SCSI backend driver allows the kernel to export its SCSI Devices - to other guests via a high-performance shared-memory interface. - Only needed for systems running as XEN driver domains (e.g. Dom0) and - if guests need generic access to SCSI devices. - -config XEN_PRIVCMD - tristate - depends on XEN - default m - -config XEN_STUB - bool "Xen stub drivers" - depends on XEN && X86_64 && BROKEN - default n - help - Allow kernel to install stub drivers, to reserve space for Xen drivers, - i.e. memory hotplug and cpu hotplug, and to block native drivers loaded, - so that real Xen drivers can be modular. - - To enable Xen features like cpu and memory hotplug, select Y here. - -config XEN_ACPI_HOTPLUG_MEMORY - tristate "Xen ACPI memory hotplug" - depends on XEN_DOM0 && XEN_STUB && ACPI - default n - help - This is Xen ACPI memory hotplug. - - Currently Xen only support ACPI memory hot-add. If you want - to hot-add memory at runtime (the hot-added memory cannot be - removed until machine stop), select Y/M here, otherwise select N. - -config XEN_ACPI_HOTPLUG_CPU - tristate "Xen ACPI cpu hotplug" - depends on XEN_DOM0 && XEN_STUB && ACPI - select ACPI_CONTAINER - default n - help - Xen ACPI cpu enumerating and hotplugging - - For hotplugging, currently Xen only support ACPI cpu hotadd. - If you want to hotadd cpu at runtime (the hotadded cpu cannot - be removed until machine stop), select Y/M here. - -config XEN_ACPI_PROCESSOR - tristate "Xen ACPI processor" - depends on XEN && X86 && ACPI_PROCESSOR && CPU_FREQ - default m - help - This ACPI processor uploads Power Management information to the Xen - hypervisor. - - To do that the driver parses the Power Management data and uploads - said information to the Xen hypervisor. Then the Xen hypervisor can - select the proper Cx and Pxx states. It also registers itself as the - SMM so that other drivers (such as ACPI cpufreq scaling driver) will - not load. - - To compile this driver as a module, choose M here: the module will be - called xen_acpi_processor If you do not know what to choose, select - M here. If the CPUFREQ drivers are built in, select Y here. - -config XEN_MCE_LOG - bool "Xen platform mcelog" - depends on XEN_DOM0 && X86_64 && X86_MCE - default n - help - Allow kernel fetching MCE error from Xen platform and - converting it into Linux mcelog format for mcelog tools - -config XEN_HAVE_PVMMU - bool - -config XEN_EFI - def_bool y - depends on (ARM || ARM64 || X86_64) && EFI - -config XEN_AUTO_XLATE - def_bool y - depends on ARM || ARM64 || XEN_PVHVM - help - Support for auto-translated physmap guests. - -config XEN_ACPI - def_bool y - depends on X86 && ACPI - -config XEN_SYMS - bool "Xen symbols" - depends on X86 && XEN_DOM0 && XENFS - default y if KALLSYMS - help - Exports hypervisor symbols (along with their types and addresses) via - /proc/xen/xensyms file, similar to /proc/kallsyms - -config XEN_HAVE_VPMU - bool - -endmenu diff --git a/src/linux/drivers/zorro/.gitignore b/src/linux/drivers/zorro/.gitignore deleted file mode 100644 index 34f980b..0000000 --- a/src/linux/drivers/zorro/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -devlist.h -gen-devlist diff --git a/src/linux/firmware/.gitignore b/src/linux/firmware/.gitignore deleted file mode 100644 index d9c6901..0000000 --- a/src/linux/firmware/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -*.gen.S -*.fw -*.bin -*.csp -*.dsp -ihex2fw diff --git a/src/linux/firmware/Makefile b/src/linux/firmware/Makefile deleted file mode 100644 index e297e1b..0000000 --- a/src/linux/firmware/Makefile +++ /dev/null @@ -1,237 +0,0 @@ -# -# kbuild file for firmware/ -# - -# Create $(fwabs) from $(CONFIG_EXTRA_FIRMWARE_DIR) -- if it doesn't have a -# leading /, it's relative to $(srctree). -fwdir := $(subst $(quote),,$(CONFIG_EXTRA_FIRMWARE_DIR)) -fwabs := $(addprefix $(srctree)/,$(filter-out /%,$(fwdir)))$(filter /%,$(fwdir)) - -fw-external-y := $(subst $(quote),,$(CONFIG_EXTRA_FIRMWARE)) - -# There are three cases to care about: -# 1. Building kernel with CONFIG_FIRMWARE_IN_KERNEL=y -- $(fw-shipped-y) should -# include the firmware files to include, according to .config -# 2. 'make modules_install', which will install firmware for modules, and -# _also_ for the in-kernel drivers when CONFIG_FIRMWARE_IN_KERNEL=n -# 3. 'make firmware_install', which installs all firmware, unconditionally. - -# For the former two cases we want $(fw-shipped-y) and $(fw-shipped-m) to be -# accurate. In the latter case it doesn't matter -- it'll use $(fw-shipped-all). -# But be aware that the config file might not be included at all. - -ifdef CONFIG_ACENIC_OMIT_TIGON_I -acenic-objs := acenic/tg2.bin -fw-shipped- += acenic/tg1.bin -else -acenic-objs := acenic/tg1.bin acenic/tg2.bin -endif -fw-shipped-$(CONFIG_ACENIC) += $(acenic-objs) -fw-shipped-$(CONFIG_ADAPTEC_STARFIRE) += adaptec/starfire_rx.bin \ - adaptec/starfire_tx.bin -fw-shipped-$(CONFIG_ATARI_DSP56K) += dsp56k/bootstrap.bin -fw-shipped-$(CONFIG_ATM_AMBASSADOR) += atmsar11.fw -fw-shipped-$(CONFIG_BNX2X) += bnx2x/bnx2x-e1-6.2.9.0.fw \ - bnx2x/bnx2x-e1h-6.2.9.0.fw \ - bnx2x/bnx2x-e2-6.2.9.0.fw -fw-shipped-$(CONFIG_BNX2) += bnx2/bnx2-mips-09-6.2.1a.fw \ - bnx2/bnx2-rv2p-09-6.0.17.fw \ - bnx2/bnx2-rv2p-09ax-6.0.17.fw \ - bnx2/bnx2-mips-06-6.2.1.fw \ - bnx2/bnx2-rv2p-06-6.0.15.fw -fw-shipped-$(CONFIG_CASSINI) += sun/cassini.bin -fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \ - cxgb3/t3c_psram-1.1.0.bin \ - cxgb3/ael2005_opt_edc.bin \ - cxgb3/ael2005_twx_edc.bin \ - cxgb3/ael2020_twx_edc.bin -fw-shipped-$(CONFIG_DRM_MGA) += matrox/g200_warp.fw matrox/g400_warp.fw -fw-shipped-$(CONFIG_DRM_R128) += r128/r128_cce.bin -fw-shipped-$(CONFIG_DRM_RADEON) += radeon/R100_cp.bin radeon/R200_cp.bin \ - radeon/R300_cp.bin radeon/R420_cp.bin \ - radeon/RS690_cp.bin radeon/RS600_cp.bin \ - radeon/R520_cp.bin \ - radeon/R600_pfp.bin radeon/R600_me.bin \ - radeon/RV610_pfp.bin radeon/RV610_me.bin \ - radeon/RV630_pfp.bin radeon/RV630_me.bin \ - radeon/RV620_pfp.bin radeon/RV620_me.bin \ - radeon/RV635_pfp.bin radeon/RV635_me.bin \ - radeon/RV670_pfp.bin radeon/RV670_me.bin \ - radeon/RS780_pfp.bin radeon/RS780_me.bin \ - radeon/RV770_pfp.bin radeon/RV770_me.bin \ - radeon/RV730_pfp.bin radeon/RV730_me.bin \ - radeon/RV710_pfp.bin radeon/RV710_me.bin -fw-shipped-$(CONFIG_DVB_AV7110) += av7110/bootcode.bin -fw-shipped-$(CONFIG_DVB_TTUSB_BUDGET) += ttusb-budget/dspbootcode.bin -fw-shipped-$(CONFIG_E100) += e100/d101m_ucode.bin e100/d101s_ucode.bin \ - e100/d102e_ucode.bin -fw-shipped-$(CONFIG_MYRI_SBUS) += myricom/lanai.bin -fw-shipped-$(CONFIG_PCMCIA_PCNET) += cis/LA-PCM.cis cis/PCMLM28.cis \ - cis/DP83903.cis cis/NE2K.cis \ - cis/tamarack.cis cis/PE-200.cis \ - cis/PE520.cis -fw-shipped-$(CONFIG_PCMCIA_3C589) += cis/3CXEM556.cis -fw-shipped-$(CONFIG_PCMCIA_3C574) += cis/3CCFEM556.cis -fw-shipped-$(CONFIG_SERIAL_8250_CS) += cis/MT5634ZLX.cis cis/RS-COM-2P.cis \ - cis/COMpad2.cis cis/COMpad4.cis \ - cis/SW_555_SER.cis cis/SW_7xx_SER.cis \ - cis/SW_8xx_SER.cis -fw-shipped-$(CONFIG_PCMCIA_SMC91C92) += ositech/Xilinx7OD.bin -fw-shipped-$(CONFIG_SCSI_ADVANSYS) += advansys/mcode.bin advansys/38C1600.bin \ - advansys/3550.bin advansys/38C0800.bin -fw-shipped-$(CONFIG_SCSI_QLOGIC_1280) += qlogic/1040.bin qlogic/1280.bin \ - qlogic/12160.bin -fw-shipped-$(CONFIG_SCSI_QLOGICPTI) += qlogic/isp1000.bin -fw-shipped-$(CONFIG_INFINIBAND_QIB) += qlogic/sd7220.fw -fw-shipped-$(CONFIG_SND_KORG1212) += korg/k1212.dsp -fw-shipped-$(CONFIG_SND_MAESTRO3) += ess/maestro3_assp_kernel.fw \ - ess/maestro3_assp_minisrc.fw -fw-shipped-$(CONFIG_SND_SB16_CSP) += sb16/mulaw_main.csp sb16/alaw_main.csp \ - sb16/ima_adpcm_init.csp \ - sb16/ima_adpcm_playback.csp \ - sb16/ima_adpcm_capture.csp -fw-shipped-$(CONFIG_SND_YMFPCI) += yamaha/ds1_ctrl.fw yamaha/ds1_dsp.fw \ - yamaha/ds1e_ctrl.fw -fw-shipped-$(CONFIG_SND_WAVEFRONT) += yamaha/yss225_registers.bin -fw-shipped-$(CONFIG_TEHUTI) += tehuti/bdx.bin -fw-shipped-$(CONFIG_TIGON3) += tigon/tg3.bin tigon/tg3_tso.bin \ - tigon/tg3_tso5.bin -fw-shipped-$(CONFIG_TYPHOON) += 3com/typhoon.bin -fw-shipped-$(CONFIG_USB_EMI26) += emi26/loader.fw emi26/firmware.fw \ - emi26/bitstream.fw -fw-shipped-$(CONFIG_USB_EMI62) += emi62/loader.fw emi62/bitstream.fw \ - emi62/spdif.fw emi62/midi.fw -fw-shipped-$(CONFIG_USB_KAWETH) += kaweth/new_code.bin kaweth/trigger_code.bin \ - kaweth/new_code_fix.bin \ - kaweth/trigger_code_fix.bin -ifdef CONFIG_FIRMWARE_IN_KERNEL -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_MPR) += keyspan/mpr.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA18X) += keyspan/usa18x.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA19) += keyspan/usa19.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA19QI) += keyspan/usa19qi.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA19QW) += keyspan/usa19qw.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA19W) += keyspan/usa19w.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA28) += keyspan/usa28.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA28XA) += keyspan/usa28xa.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA28XB) += keyspan/usa28xb.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA28X) += keyspan/usa28x.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA49W) += keyspan/usa49w.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_USA49WLC) += keyspan/usa49wlc.fw -else -fw-shipped- += keyspan/mpr.fw keyspan/usa18x.fw keyspan/usa19.fw \ - keyspan/usa19qi.fw keyspan/usa19qw.fw keyspan/usa19w.fw \ - keyspan/usa28.fw keyspan/usa28xa.fw keyspan/usa28xb.fw \ - keyspan/usa28x.fw keyspan/usa49w.fw keyspan/usa49wlc.fw -endif -fw-shipped-$(CONFIG_USB_SERIAL_TI) += ti_3410.fw ti_5052.fw \ - mts_cdma.fw mts_gsm.fw mts_edge.fw -fw-shipped-$(CONFIG_USB_SERIAL_EDGEPORT) += edgeport/boot.fw edgeport/boot2.fw \ - edgeport/down.fw edgeport/down2.fw -fw-shipped-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += edgeport/down3.bin -fw-shipped-$(CONFIG_USB_SERIAL_WHITEHEAT) += whiteheat_loader.fw whiteheat.fw \ - # whiteheat_loader_debug.fw -fw-shipped-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda/keyspan_pda.fw -fw-shipped-$(CONFIG_USB_SERIAL_XIRCOM) += keyspan_pda/xircom_pgs.fw -fw-shipped-$(CONFIG_USB_VICAM) += vicam/firmware.fw -fw-shipped-$(CONFIG_VIDEO_CPIA2) += cpia2/stv0672_vp4.bin -fw-shipped-$(CONFIG_YAM) += yam/1200.bin yam/9600.bin - -fw-shipped-all := $(fw-shipped-y) $(fw-shipped-m) $(fw-shipped-) - -quiet_cmd_ihex = IHEX $@ - cmd_ihex = $(OBJCOPY) -Iihex -Obinary $< $@ - -quiet_cmd_ihex2fw = IHEX2FW $@ - cmd_ihex2fw = $(objtree)/$(obj)/ihex2fw $< $@ - -quiet_cmd_h16tofw = H16TOFW $@ - cmd_h16tofw = $(objtree)/$(obj)/ihex2fw -w $< $@ - -quiet_cmd_fwbin = MK_FW $@ - cmd_fwbin = FWNAME="$(patsubst firmware/%.gen.S,%,$@)"; \ - FWSTR="$(subst /,_,$(subst .,_,$(subst -,_,$(patsubst \ - firmware/%.gen.S,%,$@))))"; \ - ASM_WORD=$(if $(CONFIG_64BIT),.quad,.long); \ - ASM_ALIGN=$(if $(CONFIG_64BIT),3,2); \ - PROGBITS=$(if $(CONFIG_ARM),%,@)progbits; \ - echo "/* Generated by firmware/Makefile */" > $@;\ - echo " .section .rodata" >>$@;\ - echo " .p2align $${ASM_ALIGN}" >>$@;\ - echo "_fw_$${FWSTR}_bin:" >>$@;\ - echo " .incbin \"$(2)\"" >>$@;\ - echo "_fw_end:" >>$@;\ - echo " .section .rodata.str,\"aMS\",$${PROGBITS},1" >>$@;\ - echo " .p2align $${ASM_ALIGN}" >>$@;\ - echo "_fw_$${FWSTR}_name:" >>$@;\ - echo " .string \"$$FWNAME\"" >>$@;\ - echo " .section .builtin_fw,\"a\",$${PROGBITS}" >>$@;\ - echo " .p2align $${ASM_ALIGN}" >>$@;\ - echo " $${ASM_WORD} _fw_$${FWSTR}_name" >>$@;\ - echo " $${ASM_WORD} _fw_$${FWSTR}_bin" >>$@;\ - echo " $${ASM_WORD} _fw_end - _fw_$${FWSTR}_bin" >>$@; - -# One of these files will change, or come into existence, whenever -# the configuration changes between 32-bit and 64-bit. The .S files -# need to change when that happens. -wordsize_deps := $(wildcard include/config/64bit.h include/config/32bit.h \ - include/config/ppc32.h include/config/ppc64.h \ - include/config/superh32.h include/config/superh64.h \ - include/config/x86_32.h include/config/x86_64.h) - -$(patsubst %,$(obj)/%.gen.S, $(fw-shipped-y)): %: $(wordsize_deps) - $(call cmd,fwbin,$(patsubst %.gen.S,%,$@)) -$(patsubst %,$(obj)/%.gen.S, $(fw-external-y)): %: $(wordsize_deps) \ - include/config/extra/firmware/dir.h - $(call cmd,fwbin,$(fwabs)/$(patsubst $(obj)/%.gen.S,%,$@)) - -# The .o files depend on the binaries directly; the .S files don't. -$(patsubst %,$(obj)/%.gen.o, $(fw-shipped-y)): %.gen.o: % -$(patsubst %,$(obj)/%.gen.o, $(fw-external-y)): $(obj)/%.gen.o: $(fwdir)/% - -# .ihex is used just as a simple way to hold binary files in a source tree -# where binaries are frowned upon. They are directly converted with objcopy. -$(obj)/%: $(obj)/%.ihex - $(call cmd,ihex) - -# Don't depend on ihex2fw if we're installing and it already exists. -# Putting it after | in the dependencies doesn't seem sufficient when -# we're installing after a cross-compile, because ihex2fw has dependencies -# on stuff like /usr/lib/gcc/ppc64-redhat-linux/4.3.0/include/stddef.h and -# thus wants to be rebuilt. Which it can't be, if the prebuilt kernel tree -# is exported read-only for someone to run 'make install'. -ifeq ($(INSTALL):$(wildcard $(obj)/ihex2fw),install:$(obj)/ihex2fw) -ihex2fw_dep := -else -ihex2fw_dep := $(obj)/ihex2fw -endif - -# .HEX is also Intel HEX, but where the offset and length in each record -# is actually meaningful, because the firmware has to be loaded in a certain -# order rather than as a single binary blob. Thus, we convert them into our -# more compact binary representation of ihex records () -$(obj)/%.fw: $(obj)/%.HEX $(ihex2fw_dep) - $(call cmd,ihex2fw) - -# .H16 is our own modified form of Intel HEX, with 16-bit length for records. -$(obj)/%.fw: $(obj)/%.H16 $(ihex2fw_dep) - $(call cmd,h16tofw) - -obj-y += $(patsubst %,%.gen.o, $(fw-external-y)) -obj-$(CONFIG_FIRMWARE_IN_KERNEL) += $(patsubst %,%.gen.o, $(fw-shipped-y)) - -ifeq ($(KBUILD_SRC),) -# Makefile.build only creates subdirectories for O= builds, but external -# firmware might live outside the kernel source tree -_dummy := $(foreach d,$(addprefix $(obj)/,$(dir $(fw-external-y))), $(shell [ -d $(d) ] || mkdir -p $(d))) -endif - -# Remove .S files and binaries created from ihex -# (during 'make clean' .config isn't included so they're all in $(fw-shipped-)) -targets := $(fw-shipped-) $(patsubst $(obj)/%,%, \ - $(shell find $(obj) -name \*.gen.S 2>/dev/null)) - -# Without this, built-in.o won't be created when it's empty, and the -# final vmlinux link will fail. -obj- := dummy - -hostprogs-y := ihex2fw diff --git a/src/linux/firmware/cis/.gitignore b/src/linux/firmware/cis/.gitignore deleted file mode 100644 index 1de3984..0000000 --- a/src/linux/firmware/cis/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.cis diff --git a/src/linux/fs/9p/Kconfig b/src/linux/fs/9p/Kconfig deleted file mode 100644 index 6489e1f..0000000 --- a/src/linux/fs/9p/Kconfig +++ /dev/null @@ -1,46 +0,0 @@ -config 9P_FS - tristate "Plan 9 Resource Sharing Support (9P2000)" - depends on INET && NET_9P - help - If you say Y here, you will get experimental support for - Plan 9 resource sharing via the 9P2000 protocol. - - See for more information. - - If unsure, say N. - -if 9P_FS -config 9P_FSCACHE - bool "Enable 9P client caching support" - depends on 9P_FS=m && FSCACHE || 9P_FS=y && FSCACHE=y - help - Choose Y here to enable persistent, read-only local - caching support for 9p clients using FS-Cache - - -config 9P_FS_POSIX_ACL - bool "9P POSIX Access Control Lists" - select FS_POSIX_ACL - help - POSIX Access Control Lists (ACLs) support permissions for users and - groups beyond the owner/group/world scheme. - - To learn more about Access Control Lists, visit the POSIX ACLs for - Linux website . - - If you don't know what Access Control Lists are, say N - -endif - - -config 9P_FS_SECURITY - bool "9P Security Labels" - depends on 9P_FS - help - Security labels support alternative access control models - implemented by security modules like SELinux. This option - enables an extended attribute handler for file security - labels in the 9P filesystem. - - If you are not using a security module that requires using - extended attributes for file security labels, say N. diff --git a/src/linux/fs/Kconfig b/src/linux/fs/Kconfig deleted file mode 100644 index 4bd03a2..0000000 --- a/src/linux/fs/Kconfig +++ /dev/null @@ -1,312 +0,0 @@ -# -# File system configuration -# - -menu "File systems" - -# Use unaligned word dcache accesses -config DCACHE_WORD_ACCESS - bool - -if BLOCK - -config FS_IOMAP - bool - -source "fs/ext2/Kconfig" -source "fs/ext4/Kconfig" -source "fs/jbd2/Kconfig" - -config FS_MBCACHE -# Meta block cache for Extended Attributes (ext2/ext3/ext4) - tristate - default y if EXT2_FS=y && EXT2_FS_XATTR - default y if EXT4_FS=y - default m if EXT2_FS_XATTR || EXT4_FS - -source "fs/reiserfs/Kconfig" -source "fs/jfs/Kconfig" - -source "fs/xfs/Kconfig" -source "fs/gfs2/Kconfig" -source "fs/ocfs2/Kconfig" -source "fs/btrfs/Kconfig" -source "fs/nilfs2/Kconfig" -source "fs/f2fs/Kconfig" - -config FS_DAX - bool "Direct Access (DAX) support" - depends on MMU - depends on !(ARM || MIPS || SPARC) - help - Direct Access (DAX) can be used on memory-backed block devices. - If the block device supports DAX and the filesystem supports DAX, - then you can avoid using the pagecache to buffer I/Os. Turning - on this option will compile in support for DAX; you will need to - mount the filesystem using the -o dax option. - - If you do not have a block device that is capable of using this, - or if unsure, say N. Saying Y will increase the size of the kernel - by about 5kB. - -config FS_DAX_PMD - bool - default FS_DAX - depends on FS_DAX - depends on ZONE_DEVICE - depends on TRANSPARENT_HUGEPAGE - depends on BROKEN - -endif # BLOCK - -# Posix ACL utility routines -# -# Note: Posix ACLs can be implemented without these helpers. Never use -# this symbol for ifdefs in core code. -# -config FS_POSIX_ACL - def_bool n - -config EXPORTFS - tristate - -config EXPORTFS_BLOCK_OPS - bool "Enable filesystem export operations for block IO" - help - This option enables the export operations for a filesystem to support - external block IO. - -config FILE_LOCKING - bool "Enable POSIX file locking API" if EXPERT - default y - select PERCPU_RWSEM - help - This option enables standard file locking support, required - for filesystems like NFS and for the flock() system - call. Disabling this option saves about 11k. - -config MANDATORY_FILE_LOCKING - bool "Enable Mandatory file locking" - depends on FILE_LOCKING - default y - help - This option enables files appropriately marked files on appropriely - mounted filesystems to support mandatory locking. - - To the best of my knowledge this is dead code that no one cares about. - -source "fs/crypto/Kconfig" - -source "fs/notify/Kconfig" - -source "fs/quota/Kconfig" - -source "fs/autofs4/Kconfig" -source "fs/fuse/Kconfig" -source "fs/overlayfs/Kconfig" - -menu "Caches" - -source "fs/fscache/Kconfig" -source "fs/cachefiles/Kconfig" - -endmenu - -if BLOCK -menu "CD-ROM/DVD Filesystems" - -source "fs/isofs/Kconfig" -source "fs/udf/Kconfig" - -endmenu -endif # BLOCK - -if BLOCK -menu "DOS/FAT/NT Filesystems" - -source "fs/fat/Kconfig" -source "fs/ntfs/Kconfig" - -endmenu -endif # BLOCK - -menu "Pseudo filesystems" - -source "fs/proc/Kconfig" -source "fs/kernfs/Kconfig" -source "fs/sysfs/Kconfig" - -config TMPFS - bool "Tmpfs virtual memory file system support (former shm fs)" - depends on SHMEM - help - Tmpfs is a file system which keeps all files in virtual memory. - - Everything in tmpfs is temporary in the sense that no files will be - created on your hard drive. The files live in memory and swap - space. If you unmount a tmpfs instance, everything stored therein is - lost. - - See for details. - -config TMPFS_POSIX_ACL - bool "Tmpfs POSIX Access Control Lists" - depends on TMPFS - select TMPFS_XATTR - select FS_POSIX_ACL - help - POSIX Access Control Lists (ACLs) support additional access rights - for users and groups beyond the standard owner/group/world scheme, - and this option selects support for ACLs specifically for tmpfs - filesystems. - - If you've selected TMPFS, it's possible that you'll also need - this option as there are a number of Linux distros that require - POSIX ACL support under /dev for certain features to work properly. - For example, some distros need this feature for ALSA-related /dev - files for sound to work properly. In short, if you're not sure, - say Y. - - To learn more about Access Control Lists, visit the POSIX ACLs for - Linux website . - -config TMPFS_XATTR - bool "Tmpfs extended attributes" - depends on TMPFS - default n - help - Extended attributes are name:value pairs associated with inodes by - the kernel or by users (see the attr(5) manual page, or visit - for details). - - Currently this enables support for the trusted.* and - security.* namespaces. - - You need this for POSIX ACL support on tmpfs. - - If unsure, say N. - -config HUGETLBFS - bool "HugeTLB file system support" - depends on X86 || IA64 || SPARC64 || (S390 && 64BIT) || \ - SYS_SUPPORTS_HUGETLBFS || BROKEN - help - hugetlbfs is a filesystem backing for HugeTLB pages, based on - ramfs. For architectures that support it, say Y here and read - for details. - - If unsure, say N. - -config HUGETLB_PAGE - def_bool HUGETLBFS - -config ARCH_HAS_GIGANTIC_PAGE - bool - -source "fs/configfs/Kconfig" -source "fs/efivarfs/Kconfig" - -endmenu - -menuconfig MISC_FILESYSTEMS - bool "Miscellaneous filesystems" - default y - ---help--- - Say Y here to get to see options for various miscellaneous - filesystems, such as filesystems that came from other - operating systems. - - This option alone does not add any kernel code. - - If you say N, all options in this submenu will be skipped and - disabled; if unsure, say Y here. - -if MISC_FILESYSTEMS - -source "fs/orangefs/Kconfig" -source "fs/adfs/Kconfig" -source "fs/affs/Kconfig" -source "fs/ecryptfs/Kconfig" -source "fs/hfs/Kconfig" -source "fs/hfsplus/Kconfig" -source "fs/befs/Kconfig" -source "fs/bfs/Kconfig" -source "fs/efs/Kconfig" -source "fs/jffs2/Kconfig" -# UBIFS File system configuration -source "fs/ubifs/Kconfig" -source "fs/logfs/Kconfig" -source "fs/cramfs/Kconfig" -source "fs/squashfs/Kconfig" -source "fs/freevxfs/Kconfig" -source "fs/minix/Kconfig" -source "fs/omfs/Kconfig" -source "fs/hpfs/Kconfig" -source "fs/qnx4/Kconfig" -source "fs/qnx6/Kconfig" -source "fs/romfs/Kconfig" -source "fs/pstore/Kconfig" -source "fs/sysv/Kconfig" -source "fs/ufs/Kconfig" -source "fs/exofs/Kconfig" - -endif # MISC_FILESYSTEMS - -source "fs/exofs/Kconfig.ore" - -menuconfig NETWORK_FILESYSTEMS - bool "Network File Systems" - default y - depends on NET - ---help--- - Say Y here to get to see options for network filesystems and - filesystem-related networking code, such as NFS daemon and - RPCSEC security modules. - - This option alone does not add any kernel code. - - If you say N, all options in this submenu will be skipped and - disabled; if unsure, say Y here. - -if NETWORK_FILESYSTEMS - -source "fs/nfs/Kconfig" -source "fs/nfsd/Kconfig" - -config GRACE_PERIOD - tristate - -config LOCKD - tristate - depends on FILE_LOCKING - select GRACE_PERIOD - -config LOCKD_V4 - bool - depends on NFSD_V3 || NFS_V3 - depends on FILE_LOCKING - default y - -config NFS_ACL_SUPPORT - tristate - select FS_POSIX_ACL - -config NFS_COMMON - bool - depends on NFSD || NFS_FS || LOCKD - default y - -source "net/sunrpc/Kconfig" -source "fs/ceph/Kconfig" -source "fs/cifs/Kconfig" -source "fs/ncpfs/Kconfig" -source "fs/coda/Kconfig" -source "fs/afs/Kconfig" -source "fs/9p/Kconfig" - -endif # NETWORK_FILESYSTEMS - -source "fs/nls/Kconfig" -source "fs/dlm/Kconfig" - -endmenu diff --git a/src/linux/fs/Makefile b/src/linux/fs/Makefile deleted file mode 100644 index ed2b632..0000000 --- a/src/linux/fs/Makefile +++ /dev/null @@ -1,131 +0,0 @@ -# -# Makefile for the Linux filesystems. -# -# 14 Sep 2000, Christoph Hellwig -# Rewritten to use lists instead of if-statements. -# - -obj-y := open.o read_write.o file_table.o super.o \ - char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \ - ioctl.o readdir.o select.o dcache.o inode.o \ - attr.o bad_inode.o file.o filesystems.o namespace.o \ - seq_file.o xattr.o libfs.o fs-writeback.o \ - pnode.o splice.o sync.o utimes.o \ - stack.o fs_struct.o statfs.o fs_pin.o nsfs.o - -ifeq ($(CONFIG_BLOCK),y) -obj-y += buffer.o block_dev.o direct-io.o mpage.o -else -obj-y += no-block.o -endif - -obj-$(CONFIG_PROC_FS) += proc_namespace.o - -obj-y += notify/ -obj-$(CONFIG_EPOLL) += eventpoll.o -obj-$(CONFIG_ANON_INODES) += anon_inodes.o -obj-$(CONFIG_SIGNALFD) += signalfd.o -obj-$(CONFIG_TIMERFD) += timerfd.o -obj-$(CONFIG_EVENTFD) += eventfd.o -obj-$(CONFIG_USERFAULTFD) += userfaultfd.o -obj-$(CONFIG_AIO) += aio.o -obj-$(CONFIG_FS_DAX) += dax.o -obj-$(CONFIG_FS_ENCRYPTION) += crypto/ -obj-$(CONFIG_FILE_LOCKING) += locks.o -obj-$(CONFIG_COMPAT) += compat.o compat_ioctl.o -obj-$(CONFIG_BINFMT_AOUT) += binfmt_aout.o -obj-$(CONFIG_BINFMT_EM86) += binfmt_em86.o -obj-$(CONFIG_BINFMT_MISC) += binfmt_misc.o -obj-$(CONFIG_BINFMT_SCRIPT) += binfmt_script.o -obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o -obj-$(CONFIG_COMPAT_BINFMT_ELF) += compat_binfmt_elf.o -obj-$(CONFIG_BINFMT_ELF_FDPIC) += binfmt_elf_fdpic.o -obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat.o - -obj-$(CONFIG_FS_MBCACHE) += mbcache.o -obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o -obj-$(CONFIG_NFS_COMMON) += nfs_common/ -obj-$(CONFIG_COREDUMP) += coredump.o -obj-$(CONFIG_SYSCTL) += drop_caches.o - -obj-$(CONFIG_FHANDLE) += fhandle.o -obj-$(CONFIG_FS_IOMAP) += iomap.o - -obj-y += quota/ - -obj-$(CONFIG_PROC_FS) += proc/ -obj-$(CONFIG_KERNFS) += kernfs/ -obj-$(CONFIG_SYSFS) += sysfs/ -obj-$(CONFIG_CONFIGFS_FS) += configfs/ -obj-y += devpts/ - -obj-$(CONFIG_PROFILING) += dcookies.o -obj-$(CONFIG_DLM) += dlm/ - -# Do not add any filesystems before this line -obj-$(CONFIG_FSCACHE) += fscache/ -obj-$(CONFIG_REISERFS_FS) += reiserfs/ -obj-$(CONFIG_EXT4_FS) += ext4/ -# We place ext4 before ext2 so that clean ext3 root fs's do NOT mount using the -# ext2 driver, which doesn't know about journalling! Explicitly request ext2 -# by giving the rootfstype= parameter. -obj-$(CONFIG_EXT2_FS) += ext2/ -obj-$(CONFIG_JBD2) += jbd2/ -obj-$(CONFIG_CRAMFS) += cramfs/ -obj-$(CONFIG_SQUASHFS) += squashfs/ -obj-y += ramfs/ -obj-$(CONFIG_HUGETLBFS) += hugetlbfs/ -obj-$(CONFIG_CODA_FS) += coda/ -obj-$(CONFIG_MINIX_FS) += minix/ -obj-$(CONFIG_FAT_FS) += fat/ -obj-$(CONFIG_BFS_FS) += bfs/ -obj-$(CONFIG_ISO9660_FS) += isofs/ -obj-$(CONFIG_HFSPLUS_FS) += hfsplus/ # Before hfs to find wrapped HFS+ -obj-$(CONFIG_HFS_FS) += hfs/ -obj-$(CONFIG_ECRYPT_FS) += ecryptfs/ -obj-$(CONFIG_VXFS_FS) += freevxfs/ -obj-$(CONFIG_NFS_FS) += nfs/ -obj-$(CONFIG_EXPORTFS) += exportfs/ -obj-$(CONFIG_NFSD) += nfsd/ -obj-$(CONFIG_LOCKD) += lockd/ -obj-$(CONFIG_NLS) += nls/ -obj-$(CONFIG_SYSV_FS) += sysv/ -obj-$(CONFIG_CIFS) += cifs/ -obj-$(CONFIG_NCP_FS) += ncpfs/ -obj-$(CONFIG_HPFS_FS) += hpfs/ -obj-$(CONFIG_NTFS_FS) += ntfs/ -obj-$(CONFIG_UFS_FS) += ufs/ -obj-$(CONFIG_EFS_FS) += efs/ -obj-$(CONFIG_JFFS2_FS) += jffs2/ -obj-$(CONFIG_LOGFS) += logfs/ -obj-$(CONFIG_UBIFS_FS) += ubifs/ -obj-$(CONFIG_AFFS_FS) += affs/ -obj-$(CONFIG_ROMFS_FS) += romfs/ -obj-$(CONFIG_QNX4FS_FS) += qnx4/ -obj-$(CONFIG_QNX6FS_FS) += qnx6/ -obj-$(CONFIG_AUTOFS4_FS) += autofs4/ -obj-$(CONFIG_ADFS_FS) += adfs/ -obj-$(CONFIG_FUSE_FS) += fuse/ -obj-$(CONFIG_OVERLAY_FS) += overlayfs/ -obj-$(CONFIG_ORANGEFS_FS) += orangefs/ -obj-$(CONFIG_UDF_FS) += udf/ -obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ -obj-$(CONFIG_OMFS_FS) += omfs/ -obj-$(CONFIG_JFS_FS) += jfs/ -obj-$(CONFIG_XFS_FS) += xfs/ -obj-$(CONFIG_9P_FS) += 9p/ -obj-$(CONFIG_AFS_FS) += afs/ -obj-$(CONFIG_NILFS2_FS) += nilfs2/ -obj-$(CONFIG_BEFS_FS) += befs/ -obj-$(CONFIG_HOSTFS) += hostfs/ -obj-$(CONFIG_CACHEFILES) += cachefiles/ -obj-$(CONFIG_DEBUG_FS) += debugfs/ -obj-$(CONFIG_TRACING) += tracefs/ -obj-$(CONFIG_OCFS2_FS) += ocfs2/ -obj-$(CONFIG_BTRFS_FS) += btrfs/ -obj-$(CONFIG_GFS2_FS) += gfs2/ -obj-$(CONFIG_F2FS_FS) += f2fs/ -obj-y += exofs/ # Multiple modules -obj-$(CONFIG_CEPH_FS) += ceph/ -obj-$(CONFIG_PSTORE) += pstore/ -obj-$(CONFIG_EFIVAR_FS) += efivarfs/ diff --git a/src/linux/fs/adfs/Kconfig b/src/linux/fs/adfs/Kconfig deleted file mode 100644 index c5a7787..0000000 --- a/src/linux/fs/adfs/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -config ADFS_FS - tristate "ADFS file system support" - depends on BLOCK - help - The Acorn Disc Filing System is the standard file system of the - RiscOS operating system which runs on Acorn's ARM-based Risc PC - systems and the Acorn Archimedes range of machines. If you say Y - here, Linux will be able to read from ADFS partitions on hard drives - and from ADFS-formatted floppy discs. If you also want to be able to - write to those devices, say Y to "ADFS write support" below. - - The ADFS partition should be the first partition (i.e., - /dev/[hs]d?1) on each of your drives. Please read the file - for further details. - - To compile this code as a module, choose M here: the module will be - called adfs. - - If unsure, say N. - -config ADFS_FS_RW - bool "ADFS write support (DANGEROUS)" - depends on ADFS_FS - help - If you say Y here, you will be able to write to ADFS partitions on - hard drives and ADFS-formatted floppy disks. This is experimental - codes, so if you're unsure, say N. diff --git a/src/linux/fs/affs/Kconfig b/src/linux/fs/affs/Kconfig deleted file mode 100644 index a04d9e8..0000000 --- a/src/linux/fs/affs/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -config AFFS_FS - tristate "Amiga FFS file system support" - depends on BLOCK - help - The Fast File System (FFS) is the common file system used on hard - disks by Amiga(tm) systems since AmigaOS Version 1.3 (34.20). Say Y - if you want to be able to read and write files from and to an Amiga - FFS partition on your hard drive. Amiga floppies however cannot be - read with this driver due to an incompatibility of the floppy - controller used in an Amiga and the standard floppy controller in - PCs and workstations. Read - and . - - With this driver you can also mount disk files used by Bernd - Schmidt's Un*X Amiga Emulator - (). - If you want to do this, you will also need to say Y or M to "Loop - device support", above. - - To compile this file system support as a module, choose M here: the - module will be called affs. If unsure, say N. diff --git a/src/linux/fs/afs/Kconfig b/src/linux/fs/afs/Kconfig deleted file mode 100644 index ebba3b1..0000000 --- a/src/linux/fs/afs/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -config AFS_FS - tristate "Andrew File System support (AFS)" - depends on INET - select AF_RXRPC - select DNS_RESOLVER - help - If you say Y here, you will get an experimental Andrew File System - driver. It currently only supports unsecured read-only AFS access. - - See for more information. - - If unsure, say N. - -config AFS_DEBUG - bool "AFS dynamic debugging" - depends on AFS_FS - help - Say Y here to make runtime controllable debugging messages appear. - - See for more information. - - If unsure, say N. - -config AFS_FSCACHE - bool "Provide AFS client caching support" - depends on AFS_FS=m && FSCACHE || AFS_FS=y && FSCACHE=y - help - Say Y here if you want AFS data to be cached locally on disk through - the generic filesystem cache manager diff --git a/src/linux/fs/anon_inodes.c b/src/linux/fs/anon_inodes.c deleted file mode 100644 index 80ef38c..0000000 --- a/src/linux/fs/anon_inodes.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * fs/anon_inodes.c - * - * Copyright (C) 2007 Davide Libenzi - * - * Thanks to Arnd Bergmann for code review and suggestions. - * More changes for Thomas Gleixner suggestions. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static struct vfsmount *anon_inode_mnt __read_mostly; -static struct inode *anon_inode_inode; - -/* - * anon_inodefs_dname() is called from d_path(). - */ -static char *anon_inodefs_dname(struct dentry *dentry, char *buffer, int buflen) -{ - return dynamic_dname(dentry, buffer, buflen, "anon_inode:%s", - dentry->d_name.name); -} - -static const struct dentry_operations anon_inodefs_dentry_operations = { - .d_dname = anon_inodefs_dname, -}; - -static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_pseudo(fs_type, "anon_inode:", NULL, - &anon_inodefs_dentry_operations, ANON_INODE_FS_MAGIC); -} - -static struct file_system_type anon_inode_fs_type = { - .name = "anon_inodefs", - .mount = anon_inodefs_mount, - .kill_sb = kill_anon_super, -}; - -/** - * anon_inode_getfile - creates a new file instance by hooking it up to an - * anonymous inode, and a dentry that describe the "class" - * of the file - * - * @name: [in] name of the "class" of the new file - * @fops: [in] file operations for the new file - * @priv: [in] private data for the new file (will be file's private_data) - * @flags: [in] flags - * - * Creates a new file by hooking it on a single inode. This is useful for files - * that do not need to have a full-fledged inode in order to operate correctly. - * All the files created with anon_inode_getfile() will share a single inode, - * hence saving memory and avoiding code duplication for the file/inode/dentry - * setup. Returns the newly created file* or an error pointer. - */ -struct file *anon_inode_getfile(const char *name, - const struct file_operations *fops, - void *priv, int flags) -{ - struct qstr this; - struct path path; - struct file *file; - - if (IS_ERR(anon_inode_inode)) - return ERR_PTR(-ENODEV); - - if (fops->owner && !try_module_get(fops->owner)) - return ERR_PTR(-ENOENT); - - /* - * Link the inode to a directory entry by creating a unique name - * using the inode sequence number. - */ - file = ERR_PTR(-ENOMEM); - this.name = name; - this.len = strlen(name); - this.hash = 0; - path.dentry = d_alloc_pseudo(anon_inode_mnt->mnt_sb, &this); - if (!path.dentry) - goto err_module; - - path.mnt = mntget(anon_inode_mnt); - /* - * We know the anon_inode inode count is always greater than zero, - * so ihold() is safe. - */ - ihold(anon_inode_inode); - - d_instantiate(path.dentry, anon_inode_inode); - - file = alloc_file(&path, OPEN_FMODE(flags), fops); - if (IS_ERR(file)) - goto err_dput; - file->f_mapping = anon_inode_inode->i_mapping; - - file->f_flags = flags & (O_ACCMODE | O_NONBLOCK); - file->private_data = priv; - - return file; - -err_dput: - path_put(&path); -err_module: - module_put(fops->owner); - return file; -} -EXPORT_SYMBOL_GPL(anon_inode_getfile); - -/** - * anon_inode_getfd - creates a new file instance by hooking it up to an - * anonymous inode, and a dentry that describe the "class" - * of the file - * - * @name: [in] name of the "class" of the new file - * @fops: [in] file operations for the new file - * @priv: [in] private data for the new file (will be file's private_data) - * @flags: [in] flags - * - * Creates a new file by hooking it on a single inode. This is useful for files - * that do not need to have a full-fledged inode in order to operate correctly. - * All the files created with anon_inode_getfd() will share a single inode, - * hence saving memory and avoiding code duplication for the file/inode/dentry - * setup. Returns new descriptor or an error code. - */ -int anon_inode_getfd(const char *name, const struct file_operations *fops, - void *priv, int flags) -{ - int error, fd; - struct file *file; - - error = get_unused_fd_flags(flags); - if (error < 0) - return error; - fd = error; - - file = anon_inode_getfile(name, fops, priv, flags); - if (IS_ERR(file)) { - error = PTR_ERR(file); - goto err_put_unused_fd; - } - fd_install(fd, file); - - return fd; - -err_put_unused_fd: - put_unused_fd(fd); - return error; -} -EXPORT_SYMBOL_GPL(anon_inode_getfd); - -static int __init anon_inode_init(void) -{ - anon_inode_mnt = kern_mount(&anon_inode_fs_type); - if (IS_ERR(anon_inode_mnt)) - panic("anon_inode_init() kernel mount failed (%ld)\n", PTR_ERR(anon_inode_mnt)); - - anon_inode_inode = alloc_anon_inode(anon_inode_mnt->mnt_sb); - if (IS_ERR(anon_inode_inode)) - panic("anon_inode_init() inode allocation failed (%ld)\n", PTR_ERR(anon_inode_inode)); - - return 0; -} - -fs_initcall(anon_inode_init); - diff --git a/src/linux/fs/attr.c b/src/linux/fs/attr.c deleted file mode 100644 index c902b3d..0000000 --- a/src/linux/fs/attr.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * linux/fs/attr.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * changes by Thomas Schoebel-Theuer - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * setattr_prepare - check if attribute changes to a dentry are allowed - * @dentry: dentry to check - * @attr: attributes to change - * - * Check if we are allowed to change the attributes contained in @attr - * in the given dentry. This includes the normal unix access permission - * checks, as well as checks for rlimits and others. The function also clears - * SGID bit from mode if user is not allowed to set it. Also file capabilities - * and IMA extended attributes are cleared if ATTR_KILL_PRIV is set. - * - * Should be called as the first thing in ->setattr implementations, - * possibly after taking additional locks. - */ -int setattr_prepare(struct dentry *dentry, struct iattr *attr) -{ - struct inode *inode = d_inode(dentry); - unsigned int ia_valid = attr->ia_valid; - - /* - * First check size constraints. These can't be overriden using - * ATTR_FORCE. - */ - if (ia_valid & ATTR_SIZE) { - int error = inode_newsize_ok(inode, attr->ia_size); - if (error) - return error; - } - - /* If force is set do it anyway. */ - if (ia_valid & ATTR_FORCE) - goto kill_priv; - - /* Make sure a caller can chown. */ - if ((ia_valid & ATTR_UID) && - (!uid_eq(current_fsuid(), inode->i_uid) || - !uid_eq(attr->ia_uid, inode->i_uid)) && - !capable_wrt_inode_uidgid(inode, CAP_CHOWN)) - return -EPERM; - - /* Make sure caller can chgrp. */ - if ((ia_valid & ATTR_GID) && - (!uid_eq(current_fsuid(), inode->i_uid) || - (!in_group_p(attr->ia_gid) && !gid_eq(attr->ia_gid, inode->i_gid))) && - !capable_wrt_inode_uidgid(inode, CAP_CHOWN)) - return -EPERM; - - /* Make sure a caller can chmod. */ - if (ia_valid & ATTR_MODE) { - if (!inode_owner_or_capable(inode)) - return -EPERM; - /* Also check the setgid bit! */ - if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : - inode->i_gid) && - !capable_wrt_inode_uidgid(inode, CAP_FSETID)) - attr->ia_mode &= ~S_ISGID; - } - - /* Check for setting the inode time. */ - if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) { - if (!inode_owner_or_capable(inode)) - return -EPERM; - } - -kill_priv: - /* User has permission for the change */ - if (ia_valid & ATTR_KILL_PRIV) { - int error; - - error = security_inode_killpriv(dentry); - if (error) - return error; - } - - return 0; -} -EXPORT_SYMBOL(setattr_prepare); - -/** - * inode_newsize_ok - may this inode be truncated to a given size - * @inode: the inode to be truncated - * @offset: the new size to assign to the inode - * @Returns: 0 on success, -ve errno on failure - * - * inode_newsize_ok must be called with i_mutex held. - * - * inode_newsize_ok will check filesystem limits and ulimits to check that the - * new inode size is within limits. inode_newsize_ok will also send SIGXFSZ - * when necessary. Caller must not proceed with inode size change if failure is - * returned. @inode must be a file (not directory), with appropriate - * permissions to allow truncate (inode_newsize_ok does NOT check these - * conditions). - */ -int inode_newsize_ok(const struct inode *inode, loff_t offset) -{ - if (inode->i_size < offset) { - unsigned long limit; - - limit = rlimit(RLIMIT_FSIZE); - if (limit != RLIM_INFINITY && offset > limit) - goto out_sig; - if (offset > inode->i_sb->s_maxbytes) - goto out_big; - } else { - /* - * truncation of in-use swapfiles is disallowed - it would - * cause subsequent swapout to scribble on the now-freed - * blocks. - */ - if (IS_SWAPFILE(inode)) - return -ETXTBSY; - } - - return 0; -out_sig: - send_sig(SIGXFSZ, current, 0); -out_big: - return -EFBIG; -} -EXPORT_SYMBOL(inode_newsize_ok); - -/** - * setattr_copy - copy simple metadata updates into the generic inode - * @inode: the inode to be updated - * @attr: the new attributes - * - * setattr_copy must be called with i_mutex held. - * - * setattr_copy updates the inode's metadata with that specified - * in attr. Noticeably missing is inode size update, which is more complex - * as it requires pagecache updates. - * - * The inode is not marked as dirty after this operation. The rationale is - * that for "simple" filesystems, the struct inode is the inode storage. - * The caller is free to mark the inode dirty afterwards if needed. - */ -void setattr_copy(struct inode *inode, const struct iattr *attr) -{ - unsigned int ia_valid = attr->ia_valid; - - if (ia_valid & ATTR_UID) - inode->i_uid = attr->ia_uid; - if (ia_valid & ATTR_GID) - inode->i_gid = attr->ia_gid; - if (ia_valid & ATTR_ATIME) - inode->i_atime = timespec_trunc(attr->ia_atime, - inode->i_sb->s_time_gran); - if (ia_valid & ATTR_MTIME) - inode->i_mtime = timespec_trunc(attr->ia_mtime, - inode->i_sb->s_time_gran); - if (ia_valid & ATTR_CTIME) - inode->i_ctime = timespec_trunc(attr->ia_ctime, - inode->i_sb->s_time_gran); - if (ia_valid & ATTR_MODE) { - umode_t mode = attr->ia_mode; - - if (!in_group_p(inode->i_gid) && - !capable_wrt_inode_uidgid(inode, CAP_FSETID)) - mode &= ~S_ISGID; - inode->i_mode = mode; - } -} -EXPORT_SYMBOL(setattr_copy); - -/** - * notify_change - modify attributes of a filesytem object - * @dentry: object affected - * @iattr: new attributes - * @delegated_inode: returns inode, if the inode is delegated - * - * The caller must hold the i_mutex on the affected object. - * - * If notify_change discovers a delegation in need of breaking, - * it will return -EWOULDBLOCK and return a reference to the inode in - * delegated_inode. The caller should then break the delegation and - * retry. Because breaking a delegation may take a long time, the - * caller should drop the i_mutex before doing so. - * - * Alternatively, a caller may pass NULL for delegated_inode. This may - * be appropriate for callers that expect the underlying filesystem not - * to be NFS exported. Also, passing NULL is fine for callers holding - * the file open for write, as there can be no conflicting delegation in - * that case. - */ -int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode) -{ - struct inode *inode = dentry->d_inode; - umode_t mode = inode->i_mode; - int error; - struct timespec now; - unsigned int ia_valid = attr->ia_valid; - - WARN_ON_ONCE(!inode_is_locked(inode)); - - if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) { - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - return -EPERM; - } - - /* - * If utimes(2) and friends are called with times == NULL (or both - * times are UTIME_NOW), then we need to check for write permission - */ - if (ia_valid & ATTR_TOUCH) { - if (IS_IMMUTABLE(inode)) - return -EPERM; - - if (!inode_owner_or_capable(inode)) { - error = inode_permission(inode, MAY_WRITE); - if (error) - return error; - } - } - - if ((ia_valid & ATTR_MODE)) { - umode_t amode = attr->ia_mode; - /* Flag setting protected by i_mutex */ - if (is_sxid(amode)) - inode->i_flags &= ~S_NOSEC; - } - - now = current_time(inode); - - attr->ia_ctime = now; - if (!(ia_valid & ATTR_ATIME_SET)) - attr->ia_atime = now; - if (!(ia_valid & ATTR_MTIME_SET)) - attr->ia_mtime = now; - if (ia_valid & ATTR_KILL_PRIV) { - error = security_inode_need_killpriv(dentry); - if (error < 0) - return error; - if (error == 0) - ia_valid = attr->ia_valid &= ~ATTR_KILL_PRIV; - } - - /* - * We now pass ATTR_KILL_S*ID to the lower level setattr function so - * that the function has the ability to reinterpret a mode change - * that's due to these bits. This adds an implicit restriction that - * no function will ever call notify_change with both ATTR_MODE and - * ATTR_KILL_S*ID set. - */ - if ((ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID)) && - (ia_valid & ATTR_MODE)) - BUG(); - - if (ia_valid & ATTR_KILL_SUID) { - if (mode & S_ISUID) { - ia_valid = attr->ia_valid |= ATTR_MODE; - attr->ia_mode = (inode->i_mode & ~S_ISUID); - } - } - if (ia_valid & ATTR_KILL_SGID) { - if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { - if (!(ia_valid & ATTR_MODE)) { - ia_valid = attr->ia_valid |= ATTR_MODE; - attr->ia_mode = inode->i_mode; - } - attr->ia_mode &= ~S_ISGID; - } - } - if (!(attr->ia_valid & ~(ATTR_KILL_SUID | ATTR_KILL_SGID))) - return 0; - - /* - * Verify that uid/gid changes are valid in the target - * namespace of the superblock. - */ - if (ia_valid & ATTR_UID && - !kuid_has_mapping(inode->i_sb->s_user_ns, attr->ia_uid)) - return -EOVERFLOW; - if (ia_valid & ATTR_GID && - !kgid_has_mapping(inode->i_sb->s_user_ns, attr->ia_gid)) - return -EOVERFLOW; - - /* Don't allow modifications of files with invalid uids or - * gids unless those uids & gids are being made valid. - */ - if (!(ia_valid & ATTR_UID) && !uid_valid(inode->i_uid)) - return -EOVERFLOW; - if (!(ia_valid & ATTR_GID) && !gid_valid(inode->i_gid)) - return -EOVERFLOW; - - error = security_inode_setattr(dentry, attr); - if (error) - return error; - error = try_break_deleg(inode, delegated_inode); - if (error) - return error; - - if (inode->i_op->setattr) - error = inode->i_op->setattr(dentry, attr); - else - error = simple_setattr(dentry, attr); - - if (!error) { - fsnotify_change(dentry, ia_valid); - ima_inode_post_setattr(dentry); - evm_inode_post_setattr(dentry, ia_valid); - } - - return error; -} -EXPORT_SYMBOL(notify_change); diff --git a/src/linux/fs/autofs4/Kconfig b/src/linux/fs/autofs4/Kconfig deleted file mode 100644 index 1204d63..0000000 --- a/src/linux/fs/autofs4/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -config AUTOFS4_FS - tristate "Kernel automounter version 4 support (also supports v3)" - help - The automounter is a tool to automatically mount remote file systems - on demand. This implementation is partially kernel-based to reduce - overhead in the already-mounted case; this is unlike the BSD - automounter (amd), which is a pure user space daemon. - - To use the automounter you need the user-space tools from - ; you also - want to answer Y to "NFS file system support", below. - - To compile this support as a module, choose M here: the module will be - called autofs4. You will need to add "alias autofs autofs4" to your - modules configuration file. - - If you are not a part of a fairly large, distributed network or - don't have a laptop which needs to dynamically reconfigure to the - local network, you probably do not need an automounter, and can say - N here. diff --git a/src/linux/fs/bad_inode.c b/src/linux/fs/bad_inode.c deleted file mode 100644 index 8712062..0000000 --- a/src/linux/fs/bad_inode.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * linux/fs/bad_inode.c - * - * Copyright (C) 1997, Stephen Tweedie - * - * Provide stub functions for unreadable inodes - * - * Fabian Frederick : August 2003 - All file operations assigned to EIO - */ - -#include -#include -#include -#include -#include -#include - -static int bad_file_open(struct inode *inode, struct file *filp) -{ - return -EIO; -} - -static const struct file_operations bad_file_ops = -{ - .open = bad_file_open, -}; - -static int bad_inode_create (struct inode *dir, struct dentry *dentry, - umode_t mode, bool excl) -{ - return -EIO; -} - -static struct dentry *bad_inode_lookup(struct inode *dir, - struct dentry *dentry, unsigned int flags) -{ - return ERR_PTR(-EIO); -} - -static int bad_inode_link (struct dentry *old_dentry, struct inode *dir, - struct dentry *dentry) -{ - return -EIO; -} - -static int bad_inode_unlink(struct inode *dir, struct dentry *dentry) -{ - return -EIO; -} - -static int bad_inode_symlink (struct inode *dir, struct dentry *dentry, - const char *symname) -{ - return -EIO; -} - -static int bad_inode_mkdir(struct inode *dir, struct dentry *dentry, - umode_t mode) -{ - return -EIO; -} - -static int bad_inode_rmdir (struct inode *dir, struct dentry *dentry) -{ - return -EIO; -} - -static int bad_inode_mknod (struct inode *dir, struct dentry *dentry, - umode_t mode, dev_t rdev) -{ - return -EIO; -} - -static int bad_inode_rename2(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry, - unsigned int flags) -{ - return -EIO; -} - -static int bad_inode_readlink(struct dentry *dentry, char __user *buffer, - int buflen) -{ - return -EIO; -} - -static int bad_inode_permission(struct inode *inode, int mask) -{ - return -EIO; -} - -static int bad_inode_getattr(struct vfsmount *mnt, struct dentry *dentry, - struct kstat *stat) -{ - return -EIO; -} - -static int bad_inode_setattr(struct dentry *direntry, struct iattr *attrs) -{ - return -EIO; -} - -static ssize_t bad_inode_listxattr(struct dentry *dentry, char *buffer, - size_t buffer_size) -{ - return -EIO; -} - -static const struct inode_operations bad_inode_ops = -{ - .create = bad_inode_create, - .lookup = bad_inode_lookup, - .link = bad_inode_link, - .unlink = bad_inode_unlink, - .symlink = bad_inode_symlink, - .mkdir = bad_inode_mkdir, - .rmdir = bad_inode_rmdir, - .mknod = bad_inode_mknod, - .rename = bad_inode_rename2, - .readlink = bad_inode_readlink, - /* follow_link must be no-op, otherwise unmounting this inode - won't work */ - /* put_link returns void */ - /* truncate returns void */ - .permission = bad_inode_permission, - .getattr = bad_inode_getattr, - .setattr = bad_inode_setattr, - .listxattr = bad_inode_listxattr, -}; - - -/* - * When a filesystem is unable to read an inode due to an I/O error in - * its read_inode() function, it can call make_bad_inode() to return a - * set of stubs which will return EIO errors as required. - * - * We only need to do limited initialisation: all other fields are - * preinitialised to zero automatically. - */ - -/** - * make_bad_inode - mark an inode bad due to an I/O error - * @inode: Inode to mark bad - * - * When an inode cannot be read due to a media or remote network - * failure this function makes the inode "bad" and causes I/O operations - * on it to fail from this point on. - */ - -void make_bad_inode(struct inode *inode) -{ - remove_inode_hash(inode); - - inode->i_mode = S_IFREG; - inode->i_atime = inode->i_mtime = inode->i_ctime = - current_time(inode); - inode->i_op = &bad_inode_ops; - inode->i_opflags &= ~IOP_XATTR; - inode->i_fop = &bad_file_ops; -} -EXPORT_SYMBOL(make_bad_inode); - -/* - * This tests whether an inode has been flagged as bad. The test uses - * &bad_inode_ops to cover the case of invalidated inodes as well as - * those created by make_bad_inode() above. - */ - -/** - * is_bad_inode - is an inode errored - * @inode: inode to test - * - * Returns true if the inode in question has been marked as bad. - */ - -bool is_bad_inode(struct inode *inode) -{ - return (inode->i_op == &bad_inode_ops); -} - -EXPORT_SYMBOL(is_bad_inode); - -/** - * iget_failed - Mark an under-construction inode as dead and release it - * @inode: The inode to discard - * - * Mark an under-construction inode as dead and release it. - */ -void iget_failed(struct inode *inode) -{ - make_bad_inode(inode); - unlock_new_inode(inode); - iput(inode); -} -EXPORT_SYMBOL(iget_failed); diff --git a/src/linux/fs/befs/Kconfig b/src/linux/fs/befs/Kconfig deleted file mode 100644 index edc5cc2..0000000 --- a/src/linux/fs/befs/Kconfig +++ /dev/null @@ -1,26 +0,0 @@ -config BEFS_FS - tristate "BeOS file system (BeFS) support (read only)" - depends on BLOCK - select NLS - help - The BeOS File System (BeFS) is the native file system of Be, Inc's - BeOS. Notable features include support for arbitrary attributes - on files and directories, and database-like indices on selected - attributes. (Also note that this driver doesn't make those features - available at this time). It is a 64 bit filesystem, so it supports - extremely large volumes and files. - - If you use this filesystem, you should also say Y to at least one - of the NLS (native language support) options below. - - If you don't know what this is about, say N. - - To compile this as a module, choose M here: the module will be - called befs. - -config BEFS_DEBUG - bool "Debug BeFS" - depends on BEFS_FS - help - If you say Y here, you can use the 'debug' mount option to enable - debugging output from the driver. diff --git a/src/linux/fs/bfs/Kconfig b/src/linux/fs/bfs/Kconfig deleted file mode 100644 index 3728a64..0000000 --- a/src/linux/fs/bfs/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -config BFS_FS - tristate "BFS file system support" - depends on BLOCK - help - Boot File System (BFS) is a file system used under SCO UnixWare to - allow the bootloader access to the kernel image and other important - files during the boot process. It is usually mounted under /stand - and corresponds to the slice marked as "STAND" in the UnixWare - partition. You should say Y if you want to read or write the files - on your /stand slice from within Linux. You then also need to say Y - to "UnixWare slices support", below. More information about the BFS - file system is contained in the file - . - - If you don't know what this is about, say N. - - To compile this as a module, choose M here: the module will be called - bfs. Note that the file system of your root partition (the one - containing the directory /) cannot be compiled as a module. diff --git a/src/linux/fs/block_dev.c b/src/linux/fs/block_dev.c deleted file mode 100644 index 05b5533..0000000 --- a/src/linux/fs/block_dev.c +++ /dev/null @@ -1,1980 +0,0 @@ -/* - * linux/fs/block_dev.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * Copyright (C) 2001 Andrea Arcangeli SuSE - */ - -#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 "internal.h" - -struct bdev_inode { - struct block_device bdev; - struct inode vfs_inode; -}; - -static const struct address_space_operations def_blk_aops; - -static inline struct bdev_inode *BDEV_I(struct inode *inode) -{ - return container_of(inode, struct bdev_inode, vfs_inode); -} - -struct block_device *I_BDEV(struct inode *inode) -{ - return &BDEV_I(inode)->bdev; -} -EXPORT_SYMBOL(I_BDEV); - -void __vfs_msg(struct super_block *sb, const char *prefix, const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; - printk_ratelimited("%sVFS (%s): %pV\n", prefix, sb->s_id, &vaf); - va_end(args); -} - -static void bdev_write_inode(struct block_device *bdev) -{ - struct inode *inode = bdev->bd_inode; - int ret; - - spin_lock(&inode->i_lock); - while (inode->i_state & I_DIRTY) { - spin_unlock(&inode->i_lock); - ret = write_inode_now(inode, true); - if (ret) { - char name[BDEVNAME_SIZE]; - pr_warn_ratelimited("VFS: Dirty inode writeback failed " - "for block device %s (err=%d).\n", - bdevname(bdev, name), ret); - } - spin_lock(&inode->i_lock); - } - spin_unlock(&inode->i_lock); -} - -/* Kill _all_ buffers and pagecache , dirty or not.. */ -void kill_bdev(struct block_device *bdev) -{ - struct address_space *mapping = bdev->bd_inode->i_mapping; - - if (mapping->nrpages == 0 && mapping->nrexceptional == 0) - return; - - invalidate_bh_lrus(); - truncate_inode_pages(mapping, 0); -} -EXPORT_SYMBOL(kill_bdev); - -/* Invalidate clean unused buffers and pagecache. */ -void invalidate_bdev(struct block_device *bdev) -{ - struct address_space *mapping = bdev->bd_inode->i_mapping; - - if (mapping->nrpages == 0) - return; - - invalidate_bh_lrus(); - lru_add_drain_all(); /* make sure all lru add caches are flushed */ - invalidate_mapping_pages(mapping, 0, -1); - /* 99% of the time, we don't need to flush the cleancache on the bdev. - * But, for the strange corners, lets be cautious - */ - cleancache_invalidate_inode(mapping); -} -EXPORT_SYMBOL(invalidate_bdev); - -int set_blocksize(struct block_device *bdev, int size) -{ - /* Size must be a power of two, and between 512 and PAGE_SIZE */ - if (size > PAGE_SIZE || size < 512 || !is_power_of_2(size)) - return -EINVAL; - - /* Size cannot be smaller than the size supported by the device */ - if (size < bdev_logical_block_size(bdev)) - return -EINVAL; - - /* Don't change the size if it is same as current */ - if (bdev->bd_block_size != size) { - sync_blockdev(bdev); - bdev->bd_block_size = size; - bdev->bd_inode->i_blkbits = blksize_bits(size); - kill_bdev(bdev); - } - return 0; -} - -EXPORT_SYMBOL(set_blocksize); - -int sb_set_blocksize(struct super_block *sb, int size) -{ - if (set_blocksize(sb->s_bdev, size)) - return 0; - /* If we get here, we know size is power of two - * and it's value is between 512 and PAGE_SIZE */ - sb->s_blocksize = size; - sb->s_blocksize_bits = blksize_bits(size); - return sb->s_blocksize; -} - -EXPORT_SYMBOL(sb_set_blocksize); - -int sb_min_blocksize(struct super_block *sb, int size) -{ - int minsize = bdev_logical_block_size(sb->s_bdev); - if (size < minsize) - size = minsize; - return sb_set_blocksize(sb, size); -} - -EXPORT_SYMBOL(sb_min_blocksize); - -static int -blkdev_get_block(struct inode *inode, sector_t iblock, - struct buffer_head *bh, int create) -{ - bh->b_bdev = I_BDEV(inode); - bh->b_blocknr = iblock; - set_buffer_mapped(bh); - return 0; -} - -static struct inode *bdev_file_inode(struct file *file) -{ - return file->f_mapping->host; -} - -static ssize_t -blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter) -{ - struct file *file = iocb->ki_filp; - struct inode *inode = bdev_file_inode(file); - - return __blockdev_direct_IO(iocb, inode, I_BDEV(inode), iter, - blkdev_get_block, NULL, NULL, - DIO_SKIP_DIO_COUNT); -} - -int __sync_blockdev(struct block_device *bdev, int wait) -{ - if (!bdev) - return 0; - if (!wait) - return filemap_flush(bdev->bd_inode->i_mapping); - return filemap_write_and_wait(bdev->bd_inode->i_mapping); -} - -/* - * Write out and wait upon all the dirty data associated with a block - * device via its mapping. Does not take the superblock lock. - */ -int sync_blockdev(struct block_device *bdev) -{ - return __sync_blockdev(bdev, 1); -} -EXPORT_SYMBOL(sync_blockdev); - -/* - * Write out and wait upon all dirty data associated with this - * device. Filesystem data as well as the underlying block - * device. Takes the superblock lock. - */ -int fsync_bdev(struct block_device *bdev) -{ - struct super_block *sb = get_super(bdev); - if (sb) { - int res = sync_filesystem(sb); - drop_super(sb); - return res; - } - return sync_blockdev(bdev); -} -EXPORT_SYMBOL(fsync_bdev); - -/** - * freeze_bdev -- lock a filesystem and force it into a consistent state - * @bdev: blockdevice to lock - * - * If a superblock is found on this device, we take the s_umount semaphore - * on it to make sure nobody unmounts until the snapshot creation is done. - * The reference counter (bd_fsfreeze_count) guarantees that only the last - * unfreeze process can unfreeze the frozen filesystem actually when multiple - * freeze requests arrive simultaneously. It counts up in freeze_bdev() and - * count down in thaw_bdev(). When it becomes 0, thaw_bdev() will unfreeze - * actually. - */ -struct super_block *freeze_bdev(struct block_device *bdev) -{ - struct super_block *sb; - int error = 0; - - mutex_lock(&bdev->bd_fsfreeze_mutex); - if (++bdev->bd_fsfreeze_count > 1) { - /* - * We don't even need to grab a reference - the first call - * to freeze_bdev grab an active reference and only the last - * thaw_bdev drops it. - */ - sb = get_super(bdev); - if (sb) - drop_super(sb); - mutex_unlock(&bdev->bd_fsfreeze_mutex); - return sb; - } - - sb = get_active_super(bdev); - if (!sb) - goto out; - if (sb->s_op->freeze_super) - error = sb->s_op->freeze_super(sb); - else - error = freeze_super(sb); - if (error) { - deactivate_super(sb); - bdev->bd_fsfreeze_count--; - mutex_unlock(&bdev->bd_fsfreeze_mutex); - return ERR_PTR(error); - } - deactivate_super(sb); - out: - sync_blockdev(bdev); - mutex_unlock(&bdev->bd_fsfreeze_mutex); - return sb; /* thaw_bdev releases s->s_umount */ -} -EXPORT_SYMBOL(freeze_bdev); - -/** - * thaw_bdev -- unlock filesystem - * @bdev: blockdevice to unlock - * @sb: associated superblock - * - * Unlocks the filesystem and marks it writeable again after freeze_bdev(). - */ -int thaw_bdev(struct block_device *bdev, struct super_block *sb) -{ - int error = -EINVAL; - - mutex_lock(&bdev->bd_fsfreeze_mutex); - if (!bdev->bd_fsfreeze_count) - goto out; - - error = 0; - if (--bdev->bd_fsfreeze_count > 0) - goto out; - - if (!sb) - goto out; - - if (sb->s_op->thaw_super) - error = sb->s_op->thaw_super(sb); - else - error = thaw_super(sb); - if (error) - bdev->bd_fsfreeze_count++; -out: - mutex_unlock(&bdev->bd_fsfreeze_mutex); - return error; -} -EXPORT_SYMBOL(thaw_bdev); - -static int blkdev_writepage(struct page *page, struct writeback_control *wbc) -{ - return block_write_full_page(page, blkdev_get_block, wbc); -} - -static int blkdev_readpage(struct file * file, struct page * page) -{ - return block_read_full_page(page, blkdev_get_block); -} - -static int blkdev_readpages(struct file *file, struct address_space *mapping, - struct list_head *pages, unsigned nr_pages) -{ - return mpage_readpages(mapping, pages, nr_pages, blkdev_get_block); -} - -static int blkdev_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) -{ - return block_write_begin(mapping, pos, len, flags, pagep, - blkdev_get_block); -} - -static int blkdev_write_end(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) -{ - int ret; - ret = block_write_end(file, mapping, pos, len, copied, page, fsdata); - - unlock_page(page); - put_page(page); - - return ret; -} - -/* - * private llseek: - * for a block special file file_inode(file)->i_size is zero - * so we compute the size by hand (just as in block_read/write above) - */ -static loff_t block_llseek(struct file *file, loff_t offset, int whence) -{ - struct inode *bd_inode = bdev_file_inode(file); - loff_t retval; - - inode_lock(bd_inode); - retval = fixed_size_llseek(file, offset, whence, i_size_read(bd_inode)); - inode_unlock(bd_inode); - return retval; -} - -int blkdev_fsync(struct file *filp, loff_t start, loff_t end, int datasync) -{ - struct inode *bd_inode = bdev_file_inode(filp); - struct block_device *bdev = I_BDEV(bd_inode); - int error; - - error = filemap_write_and_wait_range(filp->f_mapping, start, end); - if (error) - return error; - - /* - * There is no need to serialise calls to blkdev_issue_flush with - * i_mutex and doing so causes performance issues with concurrent - * O_SYNC writers to a block device. - */ - error = blkdev_issue_flush(bdev, GFP_KERNEL, NULL); - if (error == -EOPNOTSUPP) - error = 0; - - return error; -} -EXPORT_SYMBOL(blkdev_fsync); - -/** - * bdev_read_page() - Start reading a page from a block device - * @bdev: The device to read the page from - * @sector: The offset on the device to read the page to (need not be aligned) - * @page: The page to read - * - * On entry, the page should be locked. It will be unlocked when the page - * has been read. If the block driver implements rw_page synchronously, - * that will be true on exit from this function, but it need not be. - * - * Errors returned by this function are usually "soft", eg out of memory, or - * queue full; callers should try a different route to read this page rather - * than propagate an error back up the stack. - * - * Return: negative errno if an error occurs, 0 if submission was successful. - */ -int bdev_read_page(struct block_device *bdev, sector_t sector, - struct page *page) -{ - const struct block_device_operations *ops = bdev->bd_disk->fops; - int result = -EOPNOTSUPP; - - if (!ops->rw_page || bdev_get_integrity(bdev)) - return result; - - result = blk_queue_enter(bdev->bd_queue, false); - if (result) - return result; - result = ops->rw_page(bdev, sector + get_start_sect(bdev), page, false); - blk_queue_exit(bdev->bd_queue); - return result; -} -EXPORT_SYMBOL_GPL(bdev_read_page); - -/** - * bdev_write_page() - Start writing a page to a block device - * @bdev: The device to write the page to - * @sector: The offset on the device to write the page to (need not be aligned) - * @page: The page to write - * @wbc: The writeback_control for the write - * - * On entry, the page should be locked and not currently under writeback. - * On exit, if the write started successfully, the page will be unlocked and - * under writeback. If the write failed already (eg the driver failed to - * queue the page to the device), the page will still be locked. If the - * caller is a ->writepage implementation, it will need to unlock the page. - * - * Errors returned by this function are usually "soft", eg out of memory, or - * queue full; callers should try a different route to write this page rather - * than propagate an error back up the stack. - * - * Return: negative errno if an error occurs, 0 if submission was successful. - */ -int bdev_write_page(struct block_device *bdev, sector_t sector, - struct page *page, struct writeback_control *wbc) -{ - int result; - const struct block_device_operations *ops = bdev->bd_disk->fops; - - if (!ops->rw_page || bdev_get_integrity(bdev)) - return -EOPNOTSUPP; - result = blk_queue_enter(bdev->bd_queue, false); - if (result) - return result; - - set_page_writeback(page); - result = ops->rw_page(bdev, sector + get_start_sect(bdev), page, true); - if (result) - end_page_writeback(page); - else - unlock_page(page); - blk_queue_exit(bdev->bd_queue); - return result; -} -EXPORT_SYMBOL_GPL(bdev_write_page); - -/** - * bdev_direct_access() - Get the address for directly-accessibly memory - * @bdev: The device containing the memory - * @dax: control and output parameters for ->direct_access - * - * If a block device is made up of directly addressable memory, this function - * will tell the caller the PFN and the address of the memory. The address - * may be directly dereferenced within the kernel without the need to call - * ioremap(), kmap() or similar. The PFN is suitable for inserting into - * page tables. - * - * Return: negative errno if an error occurs, otherwise the number of bytes - * accessible at this address. - */ -long bdev_direct_access(struct block_device *bdev, struct blk_dax_ctl *dax) -{ - sector_t sector = dax->sector; - long avail, size = dax->size; - const struct block_device_operations *ops = bdev->bd_disk->fops; - - /* - * The device driver is allowed to sleep, in order to make the - * memory directly accessible. - */ - might_sleep(); - - if (size < 0) - return size; - if (!blk_queue_dax(bdev_get_queue(bdev)) || !ops->direct_access) - return -EOPNOTSUPP; - if ((sector + DIV_ROUND_UP(size, 512)) > - part_nr_sects_read(bdev->bd_part)) - return -ERANGE; - sector += get_start_sect(bdev); - if (sector % (PAGE_SIZE / 512)) - return -EINVAL; - avail = ops->direct_access(bdev, sector, &dax->addr, &dax->pfn, size); - if (!avail) - return -ERANGE; - if (avail > 0 && avail & ~PAGE_MASK) - return -ENXIO; - return min(avail, size); -} -EXPORT_SYMBOL_GPL(bdev_direct_access); - -/** - * bdev_dax_supported() - Check if the device supports dax for filesystem - * @sb: The superblock of the device - * @blocksize: The block size of the device - * - * This is a library function for filesystems to check if the block device - * can be mounted with dax option. - * - * Return: negative errno if unsupported, 0 if supported. - */ -int bdev_dax_supported(struct super_block *sb, int blocksize) -{ - struct blk_dax_ctl dax = { - .sector = 0, - .size = PAGE_SIZE, - }; - int err; - - if (blocksize != PAGE_SIZE) { - vfs_msg(sb, KERN_ERR, "error: unsupported blocksize for dax"); - return -EINVAL; - } - - err = bdev_direct_access(sb->s_bdev, &dax); - if (err < 0) { - switch (err) { - case -EOPNOTSUPP: - vfs_msg(sb, KERN_ERR, - "error: device does not support dax"); - break; - case -EINVAL: - vfs_msg(sb, KERN_ERR, - "error: unaligned partition for dax"); - break; - default: - vfs_msg(sb, KERN_ERR, - "error: dax access failed (%d)", err); - } - return err; - } - - return 0; -} -EXPORT_SYMBOL_GPL(bdev_dax_supported); - -/** - * bdev_dax_capable() - Return if the raw device is capable for dax - * @bdev: The device for raw block device access - */ -bool bdev_dax_capable(struct block_device *bdev) -{ - struct blk_dax_ctl dax = { - .size = PAGE_SIZE, - }; - - if (!IS_ENABLED(CONFIG_FS_DAX)) - return false; - - dax.sector = 0; - if (bdev_direct_access(bdev, &dax) < 0) - return false; - - dax.sector = bdev->bd_part->nr_sects - (PAGE_SIZE / 512); - if (bdev_direct_access(bdev, &dax) < 0) - return false; - - return true; -} - -/* - * pseudo-fs - */ - -static __cacheline_aligned_in_smp DEFINE_SPINLOCK(bdev_lock); -static struct kmem_cache * bdev_cachep __read_mostly; - -static struct inode *bdev_alloc_inode(struct super_block *sb) -{ - struct bdev_inode *ei = kmem_cache_alloc(bdev_cachep, GFP_KERNEL); - if (!ei) - return NULL; - return &ei->vfs_inode; -} - -static void bdev_i_callback(struct rcu_head *head) -{ - struct inode *inode = container_of(head, struct inode, i_rcu); - struct bdev_inode *bdi = BDEV_I(inode); - - kmem_cache_free(bdev_cachep, bdi); -} - -static void bdev_destroy_inode(struct inode *inode) -{ - call_rcu(&inode->i_rcu, bdev_i_callback); -} - -static void init_once(void *foo) -{ - struct bdev_inode *ei = (struct bdev_inode *) foo; - struct block_device *bdev = &ei->bdev; - - memset(bdev, 0, sizeof(*bdev)); - mutex_init(&bdev->bd_mutex); - INIT_LIST_HEAD(&bdev->bd_list); -#ifdef CONFIG_SYSFS - INIT_LIST_HEAD(&bdev->bd_holder_disks); -#endif - inode_init_once(&ei->vfs_inode); - /* Initialize mutex for freeze. */ - mutex_init(&bdev->bd_fsfreeze_mutex); -} - -static void bdev_evict_inode(struct inode *inode) -{ - struct block_device *bdev = &BDEV_I(inode)->bdev; - truncate_inode_pages_final(&inode->i_data); - invalidate_inode_buffers(inode); /* is it needed here? */ - clear_inode(inode); - spin_lock(&bdev_lock); - list_del_init(&bdev->bd_list); - spin_unlock(&bdev_lock); -} - -static const struct super_operations bdev_sops = { - .statfs = simple_statfs, - .alloc_inode = bdev_alloc_inode, - .destroy_inode = bdev_destroy_inode, - .drop_inode = generic_delete_inode, - .evict_inode = bdev_evict_inode, -}; - -static struct dentry *bd_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - struct dentry *dent; - dent = mount_pseudo(fs_type, "bdev:", &bdev_sops, NULL, BDEVFS_MAGIC); - if (!IS_ERR(dent)) - dent->d_sb->s_iflags |= SB_I_CGROUPWB; - return dent; -} - -static struct file_system_type bd_type = { - .name = "bdev", - .mount = bd_mount, - .kill_sb = kill_anon_super, -}; - -struct super_block *blockdev_superblock __read_mostly; -EXPORT_SYMBOL_GPL(blockdev_superblock); - -void __init bdev_cache_init(void) -{ - int err; - static struct vfsmount *bd_mnt; - - bdev_cachep = kmem_cache_create("bdev_cache", sizeof(struct bdev_inode), - 0, (SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT| - SLAB_MEM_SPREAD|SLAB_ACCOUNT|SLAB_PANIC), - init_once); - err = register_filesystem(&bd_type); - if (err) - panic("Cannot register bdev pseudo-fs"); - bd_mnt = kern_mount(&bd_type); - if (IS_ERR(bd_mnt)) - panic("Cannot create bdev pseudo-fs"); - blockdev_superblock = bd_mnt->mnt_sb; /* For writeback */ -} - -/* - * Most likely _very_ bad one - but then it's hardly critical for small - * /dev and can be fixed when somebody will need really large one. - * Keep in mind that it will be fed through icache hash function too. - */ -static inline unsigned long hash(dev_t dev) -{ - return MAJOR(dev)+MINOR(dev); -} - -static int bdev_test(struct inode *inode, void *data) -{ - return BDEV_I(inode)->bdev.bd_dev == *(dev_t *)data; -} - -static int bdev_set(struct inode *inode, void *data) -{ - BDEV_I(inode)->bdev.bd_dev = *(dev_t *)data; - return 0; -} - -static LIST_HEAD(all_bdevs); - -struct block_device *bdget(dev_t dev) -{ - struct block_device *bdev; - struct inode *inode; - - inode = iget5_locked(blockdev_superblock, hash(dev), - bdev_test, bdev_set, &dev); - - if (!inode) - return NULL; - - bdev = &BDEV_I(inode)->bdev; - - if (inode->i_state & I_NEW) { - bdev->bd_contains = NULL; - bdev->bd_super = NULL; - bdev->bd_inode = inode; - bdev->bd_block_size = (1 << inode->i_blkbits); - bdev->bd_part_count = 0; - bdev->bd_invalidated = 0; - inode->i_mode = S_IFBLK; - inode->i_rdev = dev; - inode->i_bdev = bdev; - inode->i_data.a_ops = &def_blk_aops; - mapping_set_gfp_mask(&inode->i_data, GFP_USER); - spin_lock(&bdev_lock); - list_add(&bdev->bd_list, &all_bdevs); - spin_unlock(&bdev_lock); - unlock_new_inode(inode); - } - return bdev; -} - -EXPORT_SYMBOL(bdget); - -/** - * bdgrab -- Grab a reference to an already referenced block device - * @bdev: Block device to grab a reference to. - */ -struct block_device *bdgrab(struct block_device *bdev) -{ - ihold(bdev->bd_inode); - return bdev; -} -EXPORT_SYMBOL(bdgrab); - -long nr_blockdev_pages(void) -{ - struct block_device *bdev; - long ret = 0; - spin_lock(&bdev_lock); - list_for_each_entry(bdev, &all_bdevs, bd_list) { - ret += bdev->bd_inode->i_mapping->nrpages; - } - spin_unlock(&bdev_lock); - return ret; -} - -void bdput(struct block_device *bdev) -{ - iput(bdev->bd_inode); -} - -EXPORT_SYMBOL(bdput); - -static struct block_device *bd_acquire(struct inode *inode) -{ - struct block_device *bdev; - - spin_lock(&bdev_lock); - bdev = inode->i_bdev; - if (bdev) { - bdgrab(bdev); - spin_unlock(&bdev_lock); - return bdev; - } - spin_unlock(&bdev_lock); - - bdev = bdget(inode->i_rdev); - if (bdev) { - spin_lock(&bdev_lock); - if (!inode->i_bdev) { - /* - * We take an additional reference to bd_inode, - * and it's released in clear_inode() of inode. - * So, we can access it via ->i_mapping always - * without igrab(). - */ - bdgrab(bdev); - inode->i_bdev = bdev; - inode->i_mapping = bdev->bd_inode->i_mapping; - } - spin_unlock(&bdev_lock); - } - return bdev; -} - -/* Call when you free inode */ - -void bd_forget(struct inode *inode) -{ - struct block_device *bdev = NULL; - - spin_lock(&bdev_lock); - if (!sb_is_blkdev_sb(inode->i_sb)) - bdev = inode->i_bdev; - inode->i_bdev = NULL; - inode->i_mapping = &inode->i_data; - spin_unlock(&bdev_lock); - - if (bdev) - bdput(bdev); -} - -/** - * bd_may_claim - test whether a block device can be claimed - * @bdev: block device of interest - * @whole: whole block device containing @bdev, may equal @bdev - * @holder: holder trying to claim @bdev - * - * Test whether @bdev can be claimed by @holder. - * - * CONTEXT: - * spin_lock(&bdev_lock). - * - * RETURNS: - * %true if @bdev can be claimed, %false otherwise. - */ -static bool bd_may_claim(struct block_device *bdev, struct block_device *whole, - void *holder) -{ - if (bdev->bd_holder == holder) - return true; /* already a holder */ - else if (bdev->bd_holder != NULL) - return false; /* held by someone else */ - else if (bdev->bd_contains == bdev) - return true; /* is a whole device which isn't held */ - - else if (whole->bd_holder == bd_may_claim) - return true; /* is a partition of a device that is being partitioned */ - else if (whole->bd_holder != NULL) - return false; /* is a partition of a held device */ - else - return true; /* is a partition of an un-held device */ -} - -/** - * bd_prepare_to_claim - prepare to claim a block device - * @bdev: block device of interest - * @whole: the whole device containing @bdev, may equal @bdev - * @holder: holder trying to claim @bdev - * - * Prepare to claim @bdev. This function fails if @bdev is already - * claimed by another holder and waits if another claiming is in - * progress. This function doesn't actually claim. On successful - * return, the caller has ownership of bd_claiming and bd_holder[s]. - * - * CONTEXT: - * spin_lock(&bdev_lock). Might release bdev_lock, sleep and regrab - * it multiple times. - * - * RETURNS: - * 0 if @bdev can be claimed, -EBUSY otherwise. - */ -static int bd_prepare_to_claim(struct block_device *bdev, - struct block_device *whole, void *holder) -{ -retry: - /* if someone else claimed, fail */ - if (!bd_may_claim(bdev, whole, holder)) - return -EBUSY; - - /* if claiming is already in progress, wait for it to finish */ - if (whole->bd_claiming) { - wait_queue_head_t *wq = bit_waitqueue(&whole->bd_claiming, 0); - DEFINE_WAIT(wait); - - prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE); - spin_unlock(&bdev_lock); - schedule(); - finish_wait(wq, &wait); - spin_lock(&bdev_lock); - goto retry; - } - - /* yay, all mine */ - return 0; -} - -/** - * bd_start_claiming - start claiming a block device - * @bdev: block device of interest - * @holder: holder trying to claim @bdev - * - * @bdev is about to be opened exclusively. Check @bdev can be opened - * exclusively and mark that an exclusive open is in progress. Each - * successful call to this function must be matched with a call to - * either bd_finish_claiming() or bd_abort_claiming() (which do not - * fail). - * - * This function is used to gain exclusive access to the block device - * without actually causing other exclusive open attempts to fail. It - * should be used when the open sequence itself requires exclusive - * access but may subsequently fail. - * - * CONTEXT: - * Might sleep. - * - * RETURNS: - * Pointer to the block device containing @bdev on success, ERR_PTR() - * value on failure. - */ -static struct block_device *bd_start_claiming(struct block_device *bdev, - void *holder) -{ - struct gendisk *disk; - struct block_device *whole; - int partno, err; - - might_sleep(); - - /* - * @bdev might not have been initialized properly yet, look up - * and grab the outer block device the hard way. - */ - disk = get_gendisk(bdev->bd_dev, &partno); - if (!disk) - return ERR_PTR(-ENXIO); - - /* - * Normally, @bdev should equal what's returned from bdget_disk() - * if partno is 0; however, some drivers (floppy) use multiple - * bdev's for the same physical device and @bdev may be one of the - * aliases. Keep @bdev if partno is 0. This means claimer - * tracking is broken for those devices but it has always been that - * way. - */ - if (partno) - whole = bdget_disk(disk, 0); - else - whole = bdgrab(bdev); - - module_put(disk->fops->owner); - put_disk(disk); - if (!whole) - return ERR_PTR(-ENOMEM); - - /* prepare to claim, if successful, mark claiming in progress */ - spin_lock(&bdev_lock); - - err = bd_prepare_to_claim(bdev, whole, holder); - if (err == 0) { - whole->bd_claiming = holder; - spin_unlock(&bdev_lock); - return whole; - } else { - spin_unlock(&bdev_lock); - bdput(whole); - return ERR_PTR(err); - } -} - -#ifdef CONFIG_SYSFS -struct bd_holder_disk { - struct list_head list; - struct gendisk *disk; - int refcnt; -}; - -static struct bd_holder_disk *bd_find_holder_disk(struct block_device *bdev, - struct gendisk *disk) -{ - struct bd_holder_disk *holder; - - list_for_each_entry(holder, &bdev->bd_holder_disks, list) - if (holder->disk == disk) - return holder; - return NULL; -} - -static int add_symlink(struct kobject *from, struct kobject *to) -{ - return sysfs_create_link(from, to, kobject_name(to)); -} - -static void del_symlink(struct kobject *from, struct kobject *to) -{ - sysfs_remove_link(from, kobject_name(to)); -} - -/** - * bd_link_disk_holder - create symlinks between holding disk and slave bdev - * @bdev: the claimed slave bdev - * @disk: the holding disk - * - * DON'T USE THIS UNLESS YOU'RE ALREADY USING IT. - * - * This functions creates the following sysfs symlinks. - * - * - from "slaves" directory of the holder @disk to the claimed @bdev - * - from "holders" directory of the @bdev to the holder @disk - * - * For example, if /dev/dm-0 maps to /dev/sda and disk for dm-0 is - * passed to bd_link_disk_holder(), then: - * - * /sys/block/dm-0/slaves/sda --> /sys/block/sda - * /sys/block/sda/holders/dm-0 --> /sys/block/dm-0 - * - * The caller must have claimed @bdev before calling this function and - * ensure that both @bdev and @disk are valid during the creation and - * lifetime of these symlinks. - * - * CONTEXT: - * Might sleep. - * - * RETURNS: - * 0 on success, -errno on failure. - */ -int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk) -{ - struct bd_holder_disk *holder; - int ret = 0; - - mutex_lock(&bdev->bd_mutex); - - WARN_ON_ONCE(!bdev->bd_holder); - - /* FIXME: remove the following once add_disk() handles errors */ - if (WARN_ON(!disk->slave_dir || !bdev->bd_part->holder_dir)) - goto out_unlock; - - holder = bd_find_holder_disk(bdev, disk); - if (holder) { - holder->refcnt++; - goto out_unlock; - } - - holder = kzalloc(sizeof(*holder), GFP_KERNEL); - if (!holder) { - ret = -ENOMEM; - goto out_unlock; - } - - INIT_LIST_HEAD(&holder->list); - holder->disk = disk; - holder->refcnt = 1; - - ret = add_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); - if (ret) - goto out_free; - - ret = add_symlink(bdev->bd_part->holder_dir, &disk_to_dev(disk)->kobj); - if (ret) - goto out_del; - /* - * bdev could be deleted beneath us which would implicitly destroy - * the holder directory. Hold on to it. - */ - kobject_get(bdev->bd_part->holder_dir); - - list_add(&holder->list, &bdev->bd_holder_disks); - goto out_unlock; - -out_del: - del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); -out_free: - kfree(holder); -out_unlock: - mutex_unlock(&bdev->bd_mutex); - return ret; -} -EXPORT_SYMBOL_GPL(bd_link_disk_holder); - -/** - * bd_unlink_disk_holder - destroy symlinks created by bd_link_disk_holder() - * @bdev: the calimed slave bdev - * @disk: the holding disk - * - * DON'T USE THIS UNLESS YOU'RE ALREADY USING IT. - * - * CONTEXT: - * Might sleep. - */ -void bd_unlink_disk_holder(struct block_device *bdev, struct gendisk *disk) -{ - struct bd_holder_disk *holder; - - mutex_lock(&bdev->bd_mutex); - - holder = bd_find_holder_disk(bdev, disk); - - if (!WARN_ON_ONCE(holder == NULL) && !--holder->refcnt) { - del_symlink(disk->slave_dir, &part_to_dev(bdev->bd_part)->kobj); - del_symlink(bdev->bd_part->holder_dir, - &disk_to_dev(disk)->kobj); - kobject_put(bdev->bd_part->holder_dir); - list_del_init(&holder->list); - kfree(holder); - } - - mutex_unlock(&bdev->bd_mutex); -} -EXPORT_SYMBOL_GPL(bd_unlink_disk_holder); -#endif - -/** - * flush_disk - invalidates all buffer-cache entries on a disk - * - * @bdev: struct block device to be flushed - * @kill_dirty: flag to guide handling of dirty inodes - * - * Invalidates all buffer-cache entries on a disk. It should be called - * when a disk has been changed -- either by a media change or online - * resize. - */ -static void flush_disk(struct block_device *bdev, bool kill_dirty) -{ - if (__invalidate_device(bdev, kill_dirty)) { - printk(KERN_WARNING "VFS: busy inodes on changed media or " - "resized disk %s\n", - bdev->bd_disk ? bdev->bd_disk->disk_name : ""); - } - - if (!bdev->bd_disk) - return; - if (disk_part_scan_enabled(bdev->bd_disk)) - bdev->bd_invalidated = 1; -} - -/** - * check_disk_size_change - checks for disk size change and adjusts bdev size. - * @disk: struct gendisk to check - * @bdev: struct bdev to adjust. - * - * This routine checks to see if the bdev size does not match the disk size - * and adjusts it if it differs. - */ -void check_disk_size_change(struct gendisk *disk, struct block_device *bdev) -{ - loff_t disk_size, bdev_size; - - disk_size = (loff_t)get_capacity(disk) << 9; - bdev_size = i_size_read(bdev->bd_inode); - if (disk_size != bdev_size) { - printk(KERN_INFO - "%s: detected capacity change from %lld to %lld\n", - disk->disk_name, bdev_size, disk_size); - i_size_write(bdev->bd_inode, disk_size); - flush_disk(bdev, false); - } -} -EXPORT_SYMBOL(check_disk_size_change); - -/** - * revalidate_disk - wrapper for lower-level driver's revalidate_disk call-back - * @disk: struct gendisk to be revalidated - * - * This routine is a wrapper for lower-level driver's revalidate_disk - * call-backs. It is used to do common pre and post operations needed - * for all revalidate_disk operations. - */ -int revalidate_disk(struct gendisk *disk) -{ - struct block_device *bdev; - int ret = 0; - - if (disk->fops->revalidate_disk) - ret = disk->fops->revalidate_disk(disk); - blk_integrity_revalidate(disk); - bdev = bdget_disk(disk, 0); - if (!bdev) - return ret; - - mutex_lock(&bdev->bd_mutex); - check_disk_size_change(disk, bdev); - bdev->bd_invalidated = 0; - mutex_unlock(&bdev->bd_mutex); - bdput(bdev); - return ret; -} -EXPORT_SYMBOL(revalidate_disk); - -/* - * This routine checks whether a removable media has been changed, - * and invalidates all buffer-cache-entries in that case. This - * is a relatively slow routine, so we have to try to minimize using - * it. Thus it is called only upon a 'mount' or 'open'. This - * is the best way of combining speed and utility, I think. - * People changing diskettes in the middle of an operation deserve - * to lose :-) - */ -int check_disk_change(struct block_device *bdev) -{ - struct gendisk *disk = bdev->bd_disk; - const struct block_device_operations *bdops = disk->fops; - unsigned int events; - - events = disk_clear_events(disk, DISK_EVENT_MEDIA_CHANGE | - DISK_EVENT_EJECT_REQUEST); - if (!(events & DISK_EVENT_MEDIA_CHANGE)) - return 0; - - flush_disk(bdev, true); - if (bdops->revalidate_disk) - bdops->revalidate_disk(bdev->bd_disk); - return 1; -} - -EXPORT_SYMBOL(check_disk_change); - -void bd_set_size(struct block_device *bdev, loff_t size) -{ - unsigned bsize = bdev_logical_block_size(bdev); - - inode_lock(bdev->bd_inode); - i_size_write(bdev->bd_inode, size); - inode_unlock(bdev->bd_inode); - while (bsize < PAGE_SIZE) { - if (size & bsize) - break; - bsize <<= 1; - } - bdev->bd_block_size = bsize; - bdev->bd_inode->i_blkbits = blksize_bits(bsize); -} -EXPORT_SYMBOL(bd_set_size); - -static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part); - -/* - * bd_mutex locking: - * - * mutex_lock(part->bd_mutex) - * mutex_lock_nested(whole->bd_mutex, 1) - */ - -static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) -{ - struct gendisk *disk; - struct module *owner; - int ret; - int partno; - int perm = 0; - - if (mode & FMODE_READ) - perm |= MAY_READ; - if (mode & FMODE_WRITE) - perm |= MAY_WRITE; - /* - * hooks: /n/, see "layering violations". - */ - if (!for_part) { - ret = devcgroup_inode_permission(bdev->bd_inode, perm); - if (ret != 0) { - bdput(bdev); - return ret; - } - } - - restart: - - ret = -ENXIO; - disk = get_gendisk(bdev->bd_dev, &partno); - if (!disk) - goto out; - owner = disk->fops->owner; - - disk_block_events(disk); - mutex_lock_nested(&bdev->bd_mutex, for_part); - if (!bdev->bd_openers) { - bdev->bd_disk = disk; - bdev->bd_queue = disk->queue; - bdev->bd_contains = bdev; - - if (!partno) { - ret = -ENXIO; - bdev->bd_part = disk_get_part(disk, partno); - if (!bdev->bd_part) - goto out_clear; - - ret = 0; - if (disk->fops->open) { - ret = disk->fops->open(bdev, mode); - if (ret == -ERESTARTSYS) { - /* Lost a race with 'disk' being - * deleted, try again. - * See md.c - */ - disk_put_part(bdev->bd_part); - bdev->bd_part = NULL; - bdev->bd_disk = NULL; - bdev->bd_queue = NULL; - mutex_unlock(&bdev->bd_mutex); - disk_unblock_events(disk); - put_disk(disk); - module_put(owner); - goto restart; - } - } - - if (!ret) - bd_set_size(bdev,(loff_t)get_capacity(disk)<<9); - - /* - * If the device is invalidated, rescan partition - * if open succeeded or failed with -ENOMEDIUM. - * The latter is necessary to prevent ghost - * partitions on a removed medium. - */ - if (bdev->bd_invalidated) { - if (!ret) - rescan_partitions(disk, bdev); - else if (ret == -ENOMEDIUM) - invalidate_partitions(disk, bdev); - } - - if (ret) - goto out_clear; - } else { - struct block_device *whole; - whole = bdget_disk(disk, 0); - ret = -ENOMEM; - if (!whole) - goto out_clear; - BUG_ON(for_part); - ret = __blkdev_get(whole, mode, 1); - if (ret) - goto out_clear; - bdev->bd_contains = whole; - bdev->bd_part = disk_get_part(disk, partno); - if (!(disk->flags & GENHD_FL_UP) || - !bdev->bd_part || !bdev->bd_part->nr_sects) { - ret = -ENXIO; - goto out_clear; - } - bd_set_size(bdev, (loff_t)bdev->bd_part->nr_sects << 9); - } - } else { - if (bdev->bd_contains == bdev) { - ret = 0; - if (bdev->bd_disk->fops->open) - ret = bdev->bd_disk->fops->open(bdev, mode); - /* the same as first opener case, read comment there */ - if (bdev->bd_invalidated) { - if (!ret) - rescan_partitions(bdev->bd_disk, bdev); - else if (ret == -ENOMEDIUM) - invalidate_partitions(bdev->bd_disk, bdev); - } - if (ret) - goto out_unlock_bdev; - } - /* only one opener holds refs to the module and disk */ - put_disk(disk); - module_put(owner); - } - bdev->bd_openers++; - if (for_part) - bdev->bd_part_count++; - mutex_unlock(&bdev->bd_mutex); - disk_unblock_events(disk); - return 0; - - out_clear: - disk_put_part(bdev->bd_part); - bdev->bd_disk = NULL; - bdev->bd_part = NULL; - bdev->bd_queue = NULL; - if (bdev != bdev->bd_contains) - __blkdev_put(bdev->bd_contains, mode, 1); - bdev->bd_contains = NULL; - out_unlock_bdev: - mutex_unlock(&bdev->bd_mutex); - disk_unblock_events(disk); - put_disk(disk); - module_put(owner); - out: - bdput(bdev); - - return ret; -} - -/** - * blkdev_get - open a block device - * @bdev: block_device to open - * @mode: FMODE_* mask - * @holder: exclusive holder identifier - * - * Open @bdev with @mode. If @mode includes %FMODE_EXCL, @bdev is - * open with exclusive access. Specifying %FMODE_EXCL with %NULL - * @holder is invalid. Exclusive opens may nest for the same @holder. - * - * On success, the reference count of @bdev is unchanged. On failure, - * @bdev is put. - * - * CONTEXT: - * Might sleep. - * - * RETURNS: - * 0 on success, -errno on failure. - */ -int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder) -{ - struct block_device *whole = NULL; - int res; - - WARN_ON_ONCE((mode & FMODE_EXCL) && !holder); - - if ((mode & FMODE_EXCL) && holder) { - whole = bd_start_claiming(bdev, holder); - if (IS_ERR(whole)) { - bdput(bdev); - return PTR_ERR(whole); - } - } - - res = __blkdev_get(bdev, mode, 0); - - if (whole) { - struct gendisk *disk = whole->bd_disk; - - /* finish claiming */ - mutex_lock(&bdev->bd_mutex); - spin_lock(&bdev_lock); - - if (!res) { - BUG_ON(!bd_may_claim(bdev, whole, holder)); - /* - * Note that for a whole device bd_holders - * will be incremented twice, and bd_holder - * will be set to bd_may_claim before being - * set to holder - */ - whole->bd_holders++; - whole->bd_holder = bd_may_claim; - bdev->bd_holders++; - bdev->bd_holder = holder; - } - - /* tell others that we're done */ - BUG_ON(whole->bd_claiming != holder); - whole->bd_claiming = NULL; - wake_up_bit(&whole->bd_claiming, 0); - - spin_unlock(&bdev_lock); - - /* - * Block event polling for write claims if requested. Any - * write holder makes the write_holder state stick until - * all are released. This is good enough and tracking - * individual writeable reference is too fragile given the - * way @mode is used in blkdev_get/put(). - */ - if (!res && (mode & FMODE_WRITE) && !bdev->bd_write_holder && - (disk->flags & GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE)) { - bdev->bd_write_holder = true; - disk_block_events(disk); - } - - mutex_unlock(&bdev->bd_mutex); - bdput(whole); - } - - return res; -} -EXPORT_SYMBOL(blkdev_get); - -/** - * blkdev_get_by_path - open a block device by name - * @path: path to the block device to open - * @mode: FMODE_* mask - * @holder: exclusive holder identifier - * - * Open the blockdevice described by the device file at @path. @mode - * and @holder are identical to blkdev_get(). - * - * On success, the returned block_device has reference count of one. - * - * CONTEXT: - * Might sleep. - * - * RETURNS: - * Pointer to block_device on success, ERR_PTR(-errno) on failure. - */ -struct block_device *blkdev_get_by_path(const char *path, fmode_t mode, - void *holder) -{ - struct block_device *bdev; - int err; - - bdev = lookup_bdev(path); - if (IS_ERR(bdev)) - return bdev; - - err = blkdev_get(bdev, mode, holder); - if (err) - return ERR_PTR(err); - - if ((mode & FMODE_WRITE) && bdev_read_only(bdev)) { - blkdev_put(bdev, mode); - return ERR_PTR(-EACCES); - } - - return bdev; -} -EXPORT_SYMBOL(blkdev_get_by_path); - -/** - * blkdev_get_by_dev - open a block device by device number - * @dev: device number of block device to open - * @mode: FMODE_* mask - * @holder: exclusive holder identifier - * - * Open the blockdevice described by device number @dev. @mode and - * @holder are identical to blkdev_get(). - * - * Use it ONLY if you really do not have anything better - i.e. when - * you are behind a truly sucky interface and all you are given is a - * device number. _Never_ to be used for internal purposes. If you - * ever need it - reconsider your API. - * - * On success, the returned block_device has reference count of one. - * - * CONTEXT: - * Might sleep. - * - * RETURNS: - * Pointer to block_device on success, ERR_PTR(-errno) on failure. - */ -struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, void *holder) -{ - struct block_device *bdev; - int err; - - bdev = bdget(dev); - if (!bdev) - return ERR_PTR(-ENOMEM); - - err = blkdev_get(bdev, mode, holder); - if (err) - return ERR_PTR(err); - - return bdev; -} -EXPORT_SYMBOL(blkdev_get_by_dev); - -static int blkdev_open(struct inode * inode, struct file * filp) -{ - struct block_device *bdev; - - /* - * Preserve backwards compatibility and allow large file access - * even if userspace doesn't ask for it explicitly. Some mkfs - * binary needs it. We might want to drop this workaround - * during an unstable branch. - */ - filp->f_flags |= O_LARGEFILE; - - if (filp->f_flags & O_NDELAY) - filp->f_mode |= FMODE_NDELAY; - if (filp->f_flags & O_EXCL) - filp->f_mode |= FMODE_EXCL; - if ((filp->f_flags & O_ACCMODE) == 3) - filp->f_mode |= FMODE_WRITE_IOCTL; - - bdev = bd_acquire(inode); - if (bdev == NULL) - return -ENOMEM; - - filp->f_mapping = bdev->bd_inode->i_mapping; - - return blkdev_get(bdev, filp->f_mode, filp); -} - -static void __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) -{ - struct gendisk *disk = bdev->bd_disk; - struct block_device *victim = NULL; - - mutex_lock_nested(&bdev->bd_mutex, for_part); - if (for_part) - bdev->bd_part_count--; - - if (!--bdev->bd_openers) { - WARN_ON_ONCE(bdev->bd_holders); - sync_blockdev(bdev); - kill_bdev(bdev); - - bdev_write_inode(bdev); - /* - * Detaching bdev inode from its wb in __destroy_inode() - * is too late: the queue which embeds its bdi (along with - * root wb) can be gone as soon as we put_disk() below. - */ - inode_detach_wb(bdev->bd_inode); - } - if (bdev->bd_contains == bdev) { - if (disk->fops->release) - disk->fops->release(disk, mode); - } - if (!bdev->bd_openers) { - struct module *owner = disk->fops->owner; - - disk_put_part(bdev->bd_part); - bdev->bd_part = NULL; - bdev->bd_disk = NULL; - if (bdev != bdev->bd_contains) - victim = bdev->bd_contains; - bdev->bd_contains = NULL; - - put_disk(disk); - module_put(owner); - } - mutex_unlock(&bdev->bd_mutex); - bdput(bdev); - if (victim) - __blkdev_put(victim, mode, 1); -} - -void blkdev_put(struct block_device *bdev, fmode_t mode) -{ - mutex_lock(&bdev->bd_mutex); - - if (mode & FMODE_EXCL) { - bool bdev_free; - - /* - * Release a claim on the device. The holder fields - * are protected with bdev_lock. bd_mutex is to - * synchronize disk_holder unlinking. - */ - spin_lock(&bdev_lock); - - WARN_ON_ONCE(--bdev->bd_holders < 0); - WARN_ON_ONCE(--bdev->bd_contains->bd_holders < 0); - - /* bd_contains might point to self, check in a separate step */ - if ((bdev_free = !bdev->bd_holders)) - bdev->bd_holder = NULL; - if (!bdev->bd_contains->bd_holders) - bdev->bd_contains->bd_holder = NULL; - - spin_unlock(&bdev_lock); - - /* - * If this was the last claim, remove holder link and - * unblock evpoll if it was a write holder. - */ - if (bdev_free && bdev->bd_write_holder) { - disk_unblock_events(bdev->bd_disk); - bdev->bd_write_holder = false; - } - } - - /* - * Trigger event checking and tell drivers to flush MEDIA_CHANGE - * event. This is to ensure detection of media removal commanded - * from userland - e.g. eject(1). - */ - disk_flush_events(bdev->bd_disk, DISK_EVENT_MEDIA_CHANGE); - - mutex_unlock(&bdev->bd_mutex); - - __blkdev_put(bdev, mode, 0); -} -EXPORT_SYMBOL(blkdev_put); - -static int blkdev_close(struct inode * inode, struct file * filp) -{ - struct block_device *bdev = I_BDEV(bdev_file_inode(filp)); - blkdev_put(bdev, filp->f_mode); - return 0; -} - -static long block_ioctl(struct file *file, unsigned cmd, unsigned long arg) -{ - struct block_device *bdev = I_BDEV(bdev_file_inode(file)); - fmode_t mode = file->f_mode; - - /* - * O_NDELAY can be altered using fcntl(.., F_SETFL, ..), so we have - * to updated it before every ioctl. - */ - if (file->f_flags & O_NDELAY) - mode |= FMODE_NDELAY; - else - mode &= ~FMODE_NDELAY; - - return blkdev_ioctl(bdev, mode, cmd, arg); -} - -/* - * Write data to the block device. Only intended for the block device itself - * and the raw driver which basically is a fake block device. - * - * Does not take i_mutex for the write and thus is not for general purpose - * use. - */ -ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from) -{ - struct file *file = iocb->ki_filp; - struct inode *bd_inode = bdev_file_inode(file); - loff_t size = i_size_read(bd_inode); - struct blk_plug plug; - ssize_t ret; - - if (bdev_read_only(I_BDEV(bd_inode))) - return -EPERM; - - if (!iov_iter_count(from)) - return 0; - - if (iocb->ki_pos >= size) - return -ENOSPC; - - iov_iter_truncate(from, size - iocb->ki_pos); - - blk_start_plug(&plug); - ret = __generic_file_write_iter(iocb, from); - if (ret > 0) - ret = generic_write_sync(iocb, ret); - blk_finish_plug(&plug); - return ret; -} -EXPORT_SYMBOL_GPL(blkdev_write_iter); - -ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to) -{ - struct file *file = iocb->ki_filp; - struct inode *bd_inode = bdev_file_inode(file); - loff_t size = i_size_read(bd_inode); - loff_t pos = iocb->ki_pos; - - if (pos >= size) - return 0; - - size -= pos; - iov_iter_truncate(to, size); - return generic_file_read_iter(iocb, to); -} -EXPORT_SYMBOL_GPL(blkdev_read_iter); - -/* - * Try to release a page associated with block device when the system - * is under memory pressure. - */ -static int blkdev_releasepage(struct page *page, gfp_t wait) -{ - struct super_block *super = BDEV_I(page->mapping->host)->bdev.bd_super; - - if (super && super->s_op->bdev_try_to_free_page) - return super->s_op->bdev_try_to_free_page(super, page, wait); - - return try_to_free_buffers(page); -} - -static int blkdev_writepages(struct address_space *mapping, - struct writeback_control *wbc) -{ - if (dax_mapping(mapping)) { - struct block_device *bdev = I_BDEV(mapping->host); - - return dax_writeback_mapping_range(mapping, bdev, wbc); - } - return generic_writepages(mapping, wbc); -} - -static const struct address_space_operations def_blk_aops = { - .readpage = blkdev_readpage, - .readpages = blkdev_readpages, - .writepage = blkdev_writepage, - .write_begin = blkdev_write_begin, - .write_end = blkdev_write_end, - .writepages = blkdev_writepages, - .releasepage = blkdev_releasepage, - .direct_IO = blkdev_direct_IO, - .is_dirty_writeback = buffer_check_dirty_writeback, -}; - -#define BLKDEV_FALLOC_FL_SUPPORTED \ - (FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | \ - FALLOC_FL_ZERO_RANGE | FALLOC_FL_NO_HIDE_STALE) - -static long blkdev_fallocate(struct file *file, int mode, loff_t start, - loff_t len) -{ - struct block_device *bdev = I_BDEV(bdev_file_inode(file)); - struct request_queue *q = bdev_get_queue(bdev); - struct address_space *mapping; - loff_t end = start + len - 1; - loff_t isize; - int error; - - /* Fail if we don't recognize the flags. */ - if (mode & ~BLKDEV_FALLOC_FL_SUPPORTED) - return -EOPNOTSUPP; - - /* Don't go off the end of the device. */ - isize = i_size_read(bdev->bd_inode); - if (start >= isize) - return -EINVAL; - if (end >= isize) { - if (mode & FALLOC_FL_KEEP_SIZE) { - len = isize - start; - end = start + len - 1; - } else - return -EINVAL; - } - - /* - * Don't allow IO that isn't aligned to logical block size. - */ - if ((start | len) & (bdev_logical_block_size(bdev) - 1)) - return -EINVAL; - - /* Invalidate the page cache, including dirty pages. */ - mapping = bdev->bd_inode->i_mapping; - truncate_inode_pages_range(mapping, start, end); - - switch (mode) { - case FALLOC_FL_ZERO_RANGE: - case FALLOC_FL_ZERO_RANGE | FALLOC_FL_KEEP_SIZE: - error = blkdev_issue_zeroout(bdev, start >> 9, len >> 9, - GFP_KERNEL, false); - break; - case FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE: - /* Only punch if the device can do zeroing discard. */ - if (!blk_queue_discard(q) || !q->limits.discard_zeroes_data) - return -EOPNOTSUPP; - error = blkdev_issue_discard(bdev, start >> 9, len >> 9, - GFP_KERNEL, 0); - break; - case FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE | FALLOC_FL_NO_HIDE_STALE: - if (!blk_queue_discard(q)) - return -EOPNOTSUPP; - error = blkdev_issue_discard(bdev, start >> 9, len >> 9, - GFP_KERNEL, 0); - break; - default: - return -EOPNOTSUPP; - } - if (error) - return error; - - /* - * Invalidate again; if someone wandered in and dirtied a page, - * the caller will be given -EBUSY. The third argument is - * inclusive, so the rounding here is safe. - */ - return invalidate_inode_pages2_range(mapping, - start >> PAGE_SHIFT, - end >> PAGE_SHIFT); -} - -const struct file_operations def_blk_fops = { - .open = blkdev_open, - .release = blkdev_close, - .llseek = block_llseek, - .read_iter = blkdev_read_iter, - .write_iter = blkdev_write_iter, - .mmap = generic_file_mmap, - .fsync = blkdev_fsync, - .unlocked_ioctl = block_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = compat_blkdev_ioctl, -#endif - .splice_read = generic_file_splice_read, - .splice_write = iter_file_splice_write, - .fallocate = blkdev_fallocate, -}; - -int ioctl_by_bdev(struct block_device *bdev, unsigned cmd, unsigned long arg) -{ - int res; - mm_segment_t old_fs = get_fs(); - set_fs(KERNEL_DS); - res = blkdev_ioctl(bdev, 0, cmd, arg); - set_fs(old_fs); - return res; -} - -EXPORT_SYMBOL(ioctl_by_bdev); - -/** - * lookup_bdev - lookup a struct block_device by name - * @pathname: special file representing the block device - * - * Get a reference to the blockdevice at @pathname in the current - * namespace if possible and return it. Return ERR_PTR(error) - * otherwise. - */ -struct block_device *lookup_bdev(const char *pathname) -{ - struct block_device *bdev; - struct inode *inode; - struct path path; - int error; - - if (!pathname || !*pathname) - return ERR_PTR(-EINVAL); - - error = kern_path(pathname, LOOKUP_FOLLOW, &path); - if (error) - return ERR_PTR(error); - - inode = d_backing_inode(path.dentry); - error = -ENOTBLK; - if (!S_ISBLK(inode->i_mode)) - goto fail; - error = -EACCES; - if (!may_open_dev(&path)) - goto fail; - error = -ENOMEM; - bdev = bd_acquire(inode); - if (!bdev) - goto fail; -out: - path_put(&path); - return bdev; -fail: - bdev = ERR_PTR(error); - goto out; -} -EXPORT_SYMBOL(lookup_bdev); - -int __invalidate_device(struct block_device *bdev, bool kill_dirty) -{ - struct super_block *sb = get_super(bdev); - int res = 0; - - if (sb) { - /* - * no need to lock the super, get_super holds the - * read mutex so the filesystem cannot go away - * under us (->put_super runs with the write lock - * hold). - */ - shrink_dcache_sb(sb); - res = invalidate_inodes(sb, kill_dirty); - drop_super(sb); - } - invalidate_bdev(bdev); - return res; -} -EXPORT_SYMBOL(__invalidate_device); - -void iterate_bdevs(void (*func)(struct block_device *, void *), void *arg) -{ - struct inode *inode, *old_inode = NULL; - - spin_lock(&blockdev_superblock->s_inode_list_lock); - list_for_each_entry(inode, &blockdev_superblock->s_inodes, i_sb_list) { - struct address_space *mapping = inode->i_mapping; - - spin_lock(&inode->i_lock); - if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW) || - mapping->nrpages == 0) { - spin_unlock(&inode->i_lock); - continue; - } - __iget(inode); - spin_unlock(&inode->i_lock); - spin_unlock(&blockdev_superblock->s_inode_list_lock); - /* - * We hold a reference to 'inode' so it couldn't have been - * removed from s_inodes list while we dropped the - * s_inode_list_lock We cannot iput the inode now as we can - * be holding the last reference and we cannot iput it under - * s_inode_list_lock. So we keep the reference and iput it - * later. - */ - iput(old_inode); - old_inode = inode; - - func(I_BDEV(inode), arg); - - spin_lock(&blockdev_superblock->s_inode_list_lock); - } - spin_unlock(&blockdev_superblock->s_inode_list_lock); - iput(old_inode); -} diff --git a/src/linux/fs/btrfs/Kconfig b/src/linux/fs/btrfs/Kconfig deleted file mode 100644 index 80e9c18..0000000 --- a/src/linux/fs/btrfs/Kconfig +++ /dev/null @@ -1,91 +0,0 @@ -config BTRFS_FS - tristate "Btrfs filesystem support" - select CRYPTO - select CRYPTO_CRC32C - select ZLIB_INFLATE - select ZLIB_DEFLATE - select LZO_COMPRESS - select LZO_DECOMPRESS - select RAID6_PQ - select XOR_BLOCKS - select SRCU - - help - Btrfs is a general purpose copy-on-write filesystem with extents, - writable snapshotting, support for multiple devices and many more - features focused on fault tolerance, repair and easy administration. - - The filesystem disk format is no longer unstable, and it's not - expected to change unless there are strong reasons to do so. If there - is a format change, file systems with a unchanged format will - continue to be mountable and usable by newer kernels. - - For more information, please see the web pages at - http://btrfs.wiki.kernel.org. - - To compile this file system support as a module, choose M here. The - module will be called btrfs. - - If unsure, say N. - -config BTRFS_FS_POSIX_ACL - bool "Btrfs POSIX Access Control Lists" - depends on BTRFS_FS - select FS_POSIX_ACL - help - POSIX Access Control Lists (ACLs) support permissions for users and - groups beyond the owner/group/world scheme. - - To learn more about Access Control Lists, visit the POSIX ACLs for - Linux website . - - If you don't know what Access Control Lists are, say N - -config BTRFS_FS_CHECK_INTEGRITY - bool "Btrfs with integrity check tool compiled in (DANGEROUS)" - depends on BTRFS_FS - help - Adds code that examines all block write requests (including - writes of the super block). The goal is to verify that the - state of the filesystem on disk is always consistent, i.e., - after a power-loss or kernel panic event the filesystem is - in a consistent state. - - If the integrity check tool is included and activated in - the mount options, plenty of kernel memory is used, and - plenty of additional CPU cycles are spent. Enabling this - functionality is not intended for normal use. - - In most cases, unless you are a btrfs developer who needs - to verify the integrity of (super)-block write requests - during the run of a regression test, say N - -config BTRFS_FS_RUN_SANITY_TESTS - bool "Btrfs will run sanity tests upon loading" - depends on BTRFS_FS - help - This will run some basic sanity tests on the free space cache - code to make sure it is acting as it should. These are mostly - regression tests and are only really interesting to btrfs - developers. - - If unsure, say N. - -config BTRFS_DEBUG - bool "Btrfs debugging support" - depends on BTRFS_FS - help - Enable run-time debugging support for the btrfs filesystem. This may - enable additional and expensive checks with negative impact on - performance, or export extra information via sysfs. - - If unsure, say N. - -config BTRFS_ASSERT - bool "Btrfs assert support" - depends on BTRFS_FS - help - Enable run-time assertion checking. This will result in panics if - any of the assertions trip. This is meant for btrfs developers only. - - If unsure, say N. diff --git a/src/linux/fs/btrfs/Makefile b/src/linux/fs/btrfs/Makefile deleted file mode 100644 index 128ce17..0000000 --- a/src/linux/fs/btrfs/Makefile +++ /dev/null @@ -1,20 +0,0 @@ - -obj-$(CONFIG_BTRFS_FS) := btrfs.o - -btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \ - file-item.o inode-item.o inode-map.o disk-io.o \ - transaction.o inode.o file.o tree-defrag.o \ - extent_map.o sysfs.o struct-funcs.o xattr.o ordered-data.o \ - extent_io.o volumes.o async-thread.o ioctl.o locking.o orphan.o \ - export.o tree-log.o free-space-cache.o zlib.o lzo.o \ - compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \ - reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \ - uuid-tree.o props.o hash.o free-space-tree.o - -btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o -btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o - -btrfs-$(CONFIG_BTRFS_FS_RUN_SANITY_TESTS) += tests/free-space-tests.o \ - tests/extent-buffer-tests.o tests/btrfs-tests.o \ - tests/extent-io-tests.o tests/inode-tests.o tests/qgroup-tests.o \ - tests/free-space-tree-tests.o diff --git a/src/linux/fs/btrfs/acl.c b/src/linux/fs/btrfs/acl.c deleted file mode 100644 index 247b8df..0000000 --- a/src/linux/fs/btrfs/acl.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (C) 2007 Red Hat. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "ctree.h" -#include "btrfs_inode.h" -#include "xattr.h" - -struct posix_acl *btrfs_get_acl(struct inode *inode, int type) -{ - int size; - const char *name; - char *value = NULL; - struct posix_acl *acl; - - switch (type) { - case ACL_TYPE_ACCESS: - name = XATTR_NAME_POSIX_ACL_ACCESS; - break; - case ACL_TYPE_DEFAULT: - name = XATTR_NAME_POSIX_ACL_DEFAULT; - break; - default: - BUG(); - } - - size = __btrfs_getxattr(inode, name, "", 0); - if (size > 0) { - value = kzalloc(size, GFP_KERNEL); - if (!value) - return ERR_PTR(-ENOMEM); - size = __btrfs_getxattr(inode, name, value, size); - } - if (size > 0) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - } else if (size == -ERANGE || size == -ENODATA || size == 0) { - acl = NULL; - } else { - acl = ERR_PTR(-EIO); - } - kfree(value); - - return acl; -} - -/* - * Needs to be called with fs_mutex held - */ -static int __btrfs_set_acl(struct btrfs_trans_handle *trans, - struct inode *inode, struct posix_acl *acl, int type) -{ - int ret, size = 0; - const char *name; - char *value = NULL; - - switch (type) { - case ACL_TYPE_ACCESS: - name = XATTR_NAME_POSIX_ACL_ACCESS; - if (acl) { - ret = posix_acl_update_mode(inode, &inode->i_mode, &acl); - if (ret) - return ret; - } - ret = 0; - break; - case ACL_TYPE_DEFAULT: - if (!S_ISDIR(inode->i_mode)) - return acl ? -EINVAL : 0; - name = XATTR_NAME_POSIX_ACL_DEFAULT; - break; - default: - return -EINVAL; - } - - if (acl) { - size = posix_acl_xattr_size(acl->a_count); - value = kmalloc(size, GFP_KERNEL); - if (!value) { - ret = -ENOMEM; - goto out; - } - - ret = posix_acl_to_xattr(&init_user_ns, acl, value, size); - if (ret < 0) - goto out; - } - - ret = __btrfs_setxattr(trans, inode, name, value, size, 0); -out: - kfree(value); - - if (!ret) - set_cached_acl(inode, type, acl); - - return ret; -} - -int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) -{ - return __btrfs_set_acl(NULL, inode, acl, type); -} - -/* - * btrfs_init_acl is already generally called under fs_mutex, so the locking - * stuff has been fixed to work with that. If the locking stuff changes, we - * need to re-evaluate the acl locking stuff. - */ -int btrfs_init_acl(struct btrfs_trans_handle *trans, - struct inode *inode, struct inode *dir) -{ - struct posix_acl *default_acl, *acl; - int ret = 0; - - /* this happens with subvols */ - if (!dir) - return 0; - - ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); - if (ret) - return ret; - - if (default_acl) { - ret = __btrfs_set_acl(trans, inode, default_acl, - ACL_TYPE_DEFAULT); - posix_acl_release(default_acl); - } - - if (acl) { - if (!ret) - ret = __btrfs_set_acl(trans, inode, acl, - ACL_TYPE_ACCESS); - posix_acl_release(acl); - } - - if (!default_acl && !acl) - cache_no_acl(inode); - return ret; -} diff --git a/src/linux/fs/btrfs/async-thread.c b/src/linux/fs/btrfs/async-thread.c deleted file mode 100644 index e0f071f..0000000 --- a/src/linux/fs/btrfs/async-thread.c +++ /dev/null @@ -1,396 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * Copyright (C) 2014 Fujitsu. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include -#include "async-thread.h" -#include "ctree.h" - -#define WORK_DONE_BIT 0 -#define WORK_ORDER_DONE_BIT 1 -#define WORK_HIGH_PRIO_BIT 2 - -#define NO_THRESHOLD (-1) -#define DFT_THRESHOLD (32) - -struct __btrfs_workqueue { - struct workqueue_struct *normal_wq; - - /* File system this workqueue services */ - struct btrfs_fs_info *fs_info; - - /* List head pointing to ordered work list */ - struct list_head ordered_list; - - /* Spinlock for ordered_list */ - spinlock_t list_lock; - - /* Thresholding related variants */ - atomic_t pending; - - /* Up limit of concurrency workers */ - int limit_active; - - /* Current number of concurrency workers */ - int current_active; - - /* Threshold to change current_active */ - int thresh; - unsigned int count; - spinlock_t thres_lock; -}; - -struct btrfs_workqueue { - struct __btrfs_workqueue *normal; - struct __btrfs_workqueue *high; -}; - -static void normal_work_helper(struct btrfs_work *work); - -#define BTRFS_WORK_HELPER(name) \ -void btrfs_##name(struct work_struct *arg) \ -{ \ - struct btrfs_work *work = container_of(arg, struct btrfs_work, \ - normal_work); \ - normal_work_helper(work); \ -} - -struct btrfs_fs_info * -btrfs_workqueue_owner(struct __btrfs_workqueue *wq) -{ - return wq->fs_info; -} - -struct btrfs_fs_info * -btrfs_work_owner(struct btrfs_work *work) -{ - return work->wq->fs_info; -} - -BTRFS_WORK_HELPER(worker_helper); -BTRFS_WORK_HELPER(delalloc_helper); -BTRFS_WORK_HELPER(flush_delalloc_helper); -BTRFS_WORK_HELPER(cache_helper); -BTRFS_WORK_HELPER(submit_helper); -BTRFS_WORK_HELPER(fixup_helper); -BTRFS_WORK_HELPER(endio_helper); -BTRFS_WORK_HELPER(endio_meta_helper); -BTRFS_WORK_HELPER(endio_meta_write_helper); -BTRFS_WORK_HELPER(endio_raid56_helper); -BTRFS_WORK_HELPER(endio_repair_helper); -BTRFS_WORK_HELPER(rmw_helper); -BTRFS_WORK_HELPER(endio_write_helper); -BTRFS_WORK_HELPER(freespace_write_helper); -BTRFS_WORK_HELPER(delayed_meta_helper); -BTRFS_WORK_HELPER(readahead_helper); -BTRFS_WORK_HELPER(qgroup_rescan_helper); -BTRFS_WORK_HELPER(extent_refs_helper); -BTRFS_WORK_HELPER(scrub_helper); -BTRFS_WORK_HELPER(scrubwrc_helper); -BTRFS_WORK_HELPER(scrubnc_helper); -BTRFS_WORK_HELPER(scrubparity_helper); - -static struct __btrfs_workqueue * -__btrfs_alloc_workqueue(struct btrfs_fs_info *fs_info, const char *name, - unsigned int flags, int limit_active, int thresh) -{ - struct __btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_KERNEL); - - if (!ret) - return NULL; - - ret->fs_info = fs_info; - ret->limit_active = limit_active; - atomic_set(&ret->pending, 0); - if (thresh == 0) - thresh = DFT_THRESHOLD; - /* For low threshold, disabling threshold is a better choice */ - if (thresh < DFT_THRESHOLD) { - ret->current_active = limit_active; - ret->thresh = NO_THRESHOLD; - } else { - /* - * For threshold-able wq, let its concurrency grow on demand. - * Use minimal max_active at alloc time to reduce resource - * usage. - */ - ret->current_active = 1; - ret->thresh = thresh; - } - - if (flags & WQ_HIGHPRI) - ret->normal_wq = alloc_workqueue("%s-%s-high", flags, - ret->current_active, "btrfs", - name); - else - ret->normal_wq = alloc_workqueue("%s-%s", flags, - ret->current_active, "btrfs", - name); - if (!ret->normal_wq) { - kfree(ret); - return NULL; - } - - INIT_LIST_HEAD(&ret->ordered_list); - spin_lock_init(&ret->list_lock); - spin_lock_init(&ret->thres_lock); - trace_btrfs_workqueue_alloc(ret, name, flags & WQ_HIGHPRI); - return ret; -} - -static inline void -__btrfs_destroy_workqueue(struct __btrfs_workqueue *wq); - -struct btrfs_workqueue *btrfs_alloc_workqueue(struct btrfs_fs_info *fs_info, - const char *name, - unsigned int flags, - int limit_active, - int thresh) -{ - struct btrfs_workqueue *ret = kzalloc(sizeof(*ret), GFP_KERNEL); - - if (!ret) - return NULL; - - ret->normal = __btrfs_alloc_workqueue(fs_info, name, - flags & ~WQ_HIGHPRI, - limit_active, thresh); - if (!ret->normal) { - kfree(ret); - return NULL; - } - - if (flags & WQ_HIGHPRI) { - ret->high = __btrfs_alloc_workqueue(fs_info, name, flags, - limit_active, thresh); - if (!ret->high) { - __btrfs_destroy_workqueue(ret->normal); - kfree(ret); - return NULL; - } - } - return ret; -} - -/* - * Hook for threshold which will be called in btrfs_queue_work. - * This hook WILL be called in IRQ handler context, - * so workqueue_set_max_active MUST NOT be called in this hook - */ -static inline void thresh_queue_hook(struct __btrfs_workqueue *wq) -{ - if (wq->thresh == NO_THRESHOLD) - return; - atomic_inc(&wq->pending); -} - -/* - * Hook for threshold which will be called before executing the work, - * This hook is called in kthread content. - * So workqueue_set_max_active is called here. - */ -static inline void thresh_exec_hook(struct __btrfs_workqueue *wq) -{ - int new_current_active; - long pending; - int need_change = 0; - - if (wq->thresh == NO_THRESHOLD) - return; - - atomic_dec(&wq->pending); - spin_lock(&wq->thres_lock); - /* - * Use wq->count to limit the calling frequency of - * workqueue_set_max_active. - */ - wq->count++; - wq->count %= (wq->thresh / 4); - if (!wq->count) - goto out; - new_current_active = wq->current_active; - - /* - * pending may be changed later, but it's OK since we really - * don't need it so accurate to calculate new_max_active. - */ - pending = atomic_read(&wq->pending); - if (pending > wq->thresh) - new_current_active++; - if (pending < wq->thresh / 2) - new_current_active--; - new_current_active = clamp_val(new_current_active, 1, wq->limit_active); - if (new_current_active != wq->current_active) { - need_change = 1; - wq->current_active = new_current_active; - } -out: - spin_unlock(&wq->thres_lock); - - if (need_change) { - workqueue_set_max_active(wq->normal_wq, wq->current_active); - } -} - -static void run_ordered_work(struct __btrfs_workqueue *wq) -{ - struct list_head *list = &wq->ordered_list; - struct btrfs_work *work; - spinlock_t *lock = &wq->list_lock; - unsigned long flags; - - while (1) { - spin_lock_irqsave(lock, flags); - if (list_empty(list)) - break; - work = list_entry(list->next, struct btrfs_work, - ordered_list); - if (!test_bit(WORK_DONE_BIT, &work->flags)) - break; - - /* - * we are going to call the ordered done function, but - * we leave the work item on the list as a barrier so - * that later work items that are done don't have their - * functions called before this one returns - */ - if (test_and_set_bit(WORK_ORDER_DONE_BIT, &work->flags)) - break; - trace_btrfs_ordered_sched(work); - spin_unlock_irqrestore(lock, flags); - work->ordered_func(work); - - /* now take the lock again and drop our item from the list */ - spin_lock_irqsave(lock, flags); - list_del(&work->ordered_list); - spin_unlock_irqrestore(lock, flags); - - /* - * we don't want to call the ordered free functions - * with the lock held though - */ - work->ordered_free(work); - trace_btrfs_all_work_done(work); - } - spin_unlock_irqrestore(lock, flags); -} - -static void normal_work_helper(struct btrfs_work *work) -{ - struct __btrfs_workqueue *wq; - int need_order = 0; - - /* - * We should not touch things inside work in the following cases: - * 1) after work->func() if it has no ordered_free - * Since the struct is freed in work->func(). - * 2) after setting WORK_DONE_BIT - * The work may be freed in other threads almost instantly. - * So we save the needed things here. - */ - if (work->ordered_func) - need_order = 1; - wq = work->wq; - - trace_btrfs_work_sched(work); - thresh_exec_hook(wq); - work->func(work); - if (need_order) { - set_bit(WORK_DONE_BIT, &work->flags); - run_ordered_work(wq); - } - if (!need_order) - trace_btrfs_all_work_done(work); -} - -void btrfs_init_work(struct btrfs_work *work, btrfs_work_func_t uniq_func, - btrfs_func_t func, - btrfs_func_t ordered_func, - btrfs_func_t ordered_free) -{ - work->func = func; - work->ordered_func = ordered_func; - work->ordered_free = ordered_free; - INIT_WORK(&work->normal_work, uniq_func); - INIT_LIST_HEAD(&work->ordered_list); - work->flags = 0; -} - -static inline void __btrfs_queue_work(struct __btrfs_workqueue *wq, - struct btrfs_work *work) -{ - unsigned long flags; - - work->wq = wq; - thresh_queue_hook(wq); - if (work->ordered_func) { - spin_lock_irqsave(&wq->list_lock, flags); - list_add_tail(&work->ordered_list, &wq->ordered_list); - spin_unlock_irqrestore(&wq->list_lock, flags); - } - trace_btrfs_work_queued(work); - queue_work(wq->normal_wq, &work->normal_work); -} - -void btrfs_queue_work(struct btrfs_workqueue *wq, - struct btrfs_work *work) -{ - struct __btrfs_workqueue *dest_wq; - - if (test_bit(WORK_HIGH_PRIO_BIT, &work->flags) && wq->high) - dest_wq = wq->high; - else - dest_wq = wq->normal; - __btrfs_queue_work(dest_wq, work); -} - -static inline void -__btrfs_destroy_workqueue(struct __btrfs_workqueue *wq) -{ - destroy_workqueue(wq->normal_wq); - trace_btrfs_workqueue_destroy(wq); - kfree(wq); -} - -void btrfs_destroy_workqueue(struct btrfs_workqueue *wq) -{ - if (!wq) - return; - if (wq->high) - __btrfs_destroy_workqueue(wq->high); - __btrfs_destroy_workqueue(wq->normal); - kfree(wq); -} - -void btrfs_workqueue_set_max(struct btrfs_workqueue *wq, int limit_active) -{ - if (!wq) - return; - wq->normal->limit_active = limit_active; - if (wq->high) - wq->high->limit_active = limit_active; -} - -void btrfs_set_work_high_priority(struct btrfs_work *work) -{ - set_bit(WORK_HIGH_PRIO_BIT, &work->flags); -} diff --git a/src/linux/fs/btrfs/async-thread.h b/src/linux/fs/btrfs/async-thread.h deleted file mode 100644 index 8e52484..0000000 --- a/src/linux/fs/btrfs/async-thread.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * Copyright (C) 2014 Fujitsu. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __BTRFS_ASYNC_THREAD_ -#define __BTRFS_ASYNC_THREAD_ -#include - -struct btrfs_fs_info; -struct btrfs_workqueue; -/* Internal use only */ -struct __btrfs_workqueue; -struct btrfs_work; -typedef void (*btrfs_func_t)(struct btrfs_work *arg); -typedef void (*btrfs_work_func_t)(struct work_struct *arg); - -struct btrfs_work { - btrfs_func_t func; - btrfs_func_t ordered_func; - btrfs_func_t ordered_free; - - /* Don't touch things below */ - struct work_struct normal_work; - struct list_head ordered_list; - struct __btrfs_workqueue *wq; - unsigned long flags; -}; - -#define BTRFS_WORK_HELPER_PROTO(name) \ -void btrfs_##name(struct work_struct *arg) - -BTRFS_WORK_HELPER_PROTO(worker_helper); -BTRFS_WORK_HELPER_PROTO(delalloc_helper); -BTRFS_WORK_HELPER_PROTO(flush_delalloc_helper); -BTRFS_WORK_HELPER_PROTO(cache_helper); -BTRFS_WORK_HELPER_PROTO(submit_helper); -BTRFS_WORK_HELPER_PROTO(fixup_helper); -BTRFS_WORK_HELPER_PROTO(endio_helper); -BTRFS_WORK_HELPER_PROTO(endio_meta_helper); -BTRFS_WORK_HELPER_PROTO(endio_meta_write_helper); -BTRFS_WORK_HELPER_PROTO(endio_raid56_helper); -BTRFS_WORK_HELPER_PROTO(endio_repair_helper); -BTRFS_WORK_HELPER_PROTO(rmw_helper); -BTRFS_WORK_HELPER_PROTO(endio_write_helper); -BTRFS_WORK_HELPER_PROTO(freespace_write_helper); -BTRFS_WORK_HELPER_PROTO(delayed_meta_helper); -BTRFS_WORK_HELPER_PROTO(readahead_helper); -BTRFS_WORK_HELPER_PROTO(qgroup_rescan_helper); -BTRFS_WORK_HELPER_PROTO(extent_refs_helper); -BTRFS_WORK_HELPER_PROTO(scrub_helper); -BTRFS_WORK_HELPER_PROTO(scrubwrc_helper); -BTRFS_WORK_HELPER_PROTO(scrubnc_helper); -BTRFS_WORK_HELPER_PROTO(scrubparity_helper); - - -struct btrfs_workqueue *btrfs_alloc_workqueue(struct btrfs_fs_info *fs_info, - const char *name, - unsigned int flags, - int limit_active, - int thresh); -void btrfs_init_work(struct btrfs_work *work, btrfs_work_func_t helper, - btrfs_func_t func, - btrfs_func_t ordered_func, - btrfs_func_t ordered_free); -void btrfs_queue_work(struct btrfs_workqueue *wq, - struct btrfs_work *work); -void btrfs_destroy_workqueue(struct btrfs_workqueue *wq); -void btrfs_workqueue_set_max(struct btrfs_workqueue *wq, int max); -void btrfs_set_work_high_priority(struct btrfs_work *work); -struct btrfs_fs_info *btrfs_work_owner(struct btrfs_work *work); -struct btrfs_fs_info *btrfs_workqueue_owner(struct __btrfs_workqueue *wq); -#endif diff --git a/src/linux/fs/btrfs/backref.c b/src/linux/fs/btrfs/backref.c deleted file mode 100644 index 85dc7ab..0000000 --- a/src/linux/fs/btrfs/backref.c +++ /dev/null @@ -1,2361 +0,0 @@ -/* - * Copyright (C) 2011 STRATO. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include "ctree.h" -#include "disk-io.h" -#include "backref.h" -#include "ulist.h" -#include "transaction.h" -#include "delayed-ref.h" -#include "locking.h" - -/* Just an arbitrary number so we can be sure this happened */ -#define BACKREF_FOUND_SHARED 6 - -struct extent_inode_elem { - u64 inum; - u64 offset; - struct extent_inode_elem *next; -}; - -/* - * ref_root is used as the root of the ref tree that hold a collection - * of unique references. - */ -struct ref_root { - struct rb_root rb_root; - - /* - * The unique_refs represents the number of ref_nodes with a positive - * count stored in the tree. Even if a ref_node (the count is greater - * than one) is added, the unique_refs will only increase by one. - */ - unsigned int unique_refs; -}; - -/* ref_node is used to store a unique reference to the ref tree. */ -struct ref_node { - struct rb_node rb_node; - - /* For NORMAL_REF, otherwise all these fields should be set to 0 */ - u64 root_id; - u64 object_id; - u64 offset; - - /* For SHARED_REF, otherwise parent field should be set to 0 */ - u64 parent; - - /* Ref to the ref_mod of btrfs_delayed_ref_node */ - int ref_mod; -}; - -/* Dynamically allocate and initialize a ref_root */ -static struct ref_root *ref_root_alloc(void) -{ - struct ref_root *ref_tree; - - ref_tree = kmalloc(sizeof(*ref_tree), GFP_NOFS); - if (!ref_tree) - return NULL; - - ref_tree->rb_root = RB_ROOT; - ref_tree->unique_refs = 0; - - return ref_tree; -} - -/* Free all nodes in the ref tree, and reinit ref_root */ -static void ref_root_fini(struct ref_root *ref_tree) -{ - struct ref_node *node; - struct rb_node *next; - - while ((next = rb_first(&ref_tree->rb_root)) != NULL) { - node = rb_entry(next, struct ref_node, rb_node); - rb_erase(next, &ref_tree->rb_root); - kfree(node); - } - - ref_tree->rb_root = RB_ROOT; - ref_tree->unique_refs = 0; -} - -static void ref_root_free(struct ref_root *ref_tree) -{ - if (!ref_tree) - return; - - ref_root_fini(ref_tree); - kfree(ref_tree); -} - -/* - * Compare ref_node with (root_id, object_id, offset, parent) - * - * The function compares two ref_node a and b. It returns an integer less - * than, equal to, or greater than zero , respectively, to be less than, to - * equal, or be greater than b. - */ -static int ref_node_cmp(struct ref_node *a, struct ref_node *b) -{ - if (a->root_id < b->root_id) - return -1; - else if (a->root_id > b->root_id) - return 1; - - if (a->object_id < b->object_id) - return -1; - else if (a->object_id > b->object_id) - return 1; - - if (a->offset < b->offset) - return -1; - else if (a->offset > b->offset) - return 1; - - if (a->parent < b->parent) - return -1; - else if (a->parent > b->parent) - return 1; - - return 0; -} - -/* - * Search ref_node with (root_id, object_id, offset, parent) in the tree - * - * if found, the pointer of the ref_node will be returned; - * if not found, NULL will be returned and pos will point to the rb_node for - * insert, pos_parent will point to pos'parent for insert; -*/ -static struct ref_node *__ref_tree_search(struct ref_root *ref_tree, - struct rb_node ***pos, - struct rb_node **pos_parent, - u64 root_id, u64 object_id, - u64 offset, u64 parent) -{ - struct ref_node *cur = NULL; - struct ref_node entry; - int ret; - - entry.root_id = root_id; - entry.object_id = object_id; - entry.offset = offset; - entry.parent = parent; - - *pos = &ref_tree->rb_root.rb_node; - - while (**pos) { - *pos_parent = **pos; - cur = rb_entry(*pos_parent, struct ref_node, rb_node); - - ret = ref_node_cmp(cur, &entry); - if (ret > 0) - *pos = &(**pos)->rb_left; - else if (ret < 0) - *pos = &(**pos)->rb_right; - else - return cur; - } - - return NULL; -} - -/* - * Insert a ref_node to the ref tree - * @pos used for specifiy the position to insert - * @pos_parent for specifiy pos's parent - * - * success, return 0; - * ref_node already exists, return -EEXIST; -*/ -static int ref_tree_insert(struct ref_root *ref_tree, struct rb_node **pos, - struct rb_node *pos_parent, struct ref_node *ins) -{ - struct rb_node **p = NULL; - struct rb_node *parent = NULL; - struct ref_node *cur = NULL; - - if (!pos) { - cur = __ref_tree_search(ref_tree, &p, &parent, ins->root_id, - ins->object_id, ins->offset, - ins->parent); - if (cur) - return -EEXIST; - } else { - p = pos; - parent = pos_parent; - } - - rb_link_node(&ins->rb_node, parent, p); - rb_insert_color(&ins->rb_node, &ref_tree->rb_root); - - return 0; -} - -/* Erase and free ref_node, caller should update ref_root->unique_refs */ -static void ref_tree_remove(struct ref_root *ref_tree, struct ref_node *node) -{ - rb_erase(&node->rb_node, &ref_tree->rb_root); - kfree(node); -} - -/* - * Update ref_root->unique_refs - * - * Call __ref_tree_search - * 1. if ref_node doesn't exist, ref_tree_insert this node, and update - * ref_root->unique_refs: - * if ref_node->ref_mod > 0, ref_root->unique_refs++; - * if ref_node->ref_mod < 0, do noting; - * - * 2. if ref_node is found, then get origin ref_node->ref_mod, and update - * ref_node->ref_mod. - * if ref_node->ref_mod is equal to 0,then call ref_tree_remove - * - * according to origin_mod and new_mod, update ref_root->items - * +----------------+--------------+-------------+ - * | |new_count <= 0|new_count > 0| - * +----------------+--------------+-------------+ - * |origin_count < 0| 0 | 1 | - * +----------------+--------------+-------------+ - * |origin_count > 0| -1 | 0 | - * +----------------+--------------+-------------+ - * - * In case of allocation failure, -ENOMEM is returned and the ref_tree stays - * unaltered. - * Success, return 0 - */ -static int ref_tree_add(struct ref_root *ref_tree, u64 root_id, u64 object_id, - u64 offset, u64 parent, int count) -{ - struct ref_node *node = NULL; - struct rb_node **pos = NULL; - struct rb_node *pos_parent = NULL; - int origin_count; - int ret; - - if (!count) - return 0; - - node = __ref_tree_search(ref_tree, &pos, &pos_parent, root_id, - object_id, offset, parent); - if (node == NULL) { - node = kmalloc(sizeof(*node), GFP_NOFS); - if (!node) - return -ENOMEM; - - node->root_id = root_id; - node->object_id = object_id; - node->offset = offset; - node->parent = parent; - node->ref_mod = count; - - ret = ref_tree_insert(ref_tree, pos, pos_parent, node); - ASSERT(!ret); - if (ret) { - kfree(node); - return ret; - } - - ref_tree->unique_refs += node->ref_mod > 0 ? 1 : 0; - - return 0; - } - - origin_count = node->ref_mod; - node->ref_mod += count; - - if (node->ref_mod > 0) - ref_tree->unique_refs += origin_count > 0 ? 0 : 1; - else if (node->ref_mod <= 0) - ref_tree->unique_refs += origin_count > 0 ? -1 : 0; - - if (!node->ref_mod) - ref_tree_remove(ref_tree, node); - - return 0; -} - -static int check_extent_in_eb(struct btrfs_key *key, struct extent_buffer *eb, - struct btrfs_file_extent_item *fi, - u64 extent_item_pos, - struct extent_inode_elem **eie) -{ - u64 offset = 0; - struct extent_inode_elem *e; - - if (!btrfs_file_extent_compression(eb, fi) && - !btrfs_file_extent_encryption(eb, fi) && - !btrfs_file_extent_other_encoding(eb, fi)) { - u64 data_offset; - u64 data_len; - - data_offset = btrfs_file_extent_offset(eb, fi); - data_len = btrfs_file_extent_num_bytes(eb, fi); - - if (extent_item_pos < data_offset || - extent_item_pos >= data_offset + data_len) - return 1; - offset = extent_item_pos - data_offset; - } - - e = kmalloc(sizeof(*e), GFP_NOFS); - if (!e) - return -ENOMEM; - - e->next = *eie; - e->inum = key->objectid; - e->offset = key->offset + offset; - *eie = e; - - return 0; -} - -static void free_inode_elem_list(struct extent_inode_elem *eie) -{ - struct extent_inode_elem *eie_next; - - for (; eie; eie = eie_next) { - eie_next = eie->next; - kfree(eie); - } -} - -static int find_extent_in_eb(struct extent_buffer *eb, u64 wanted_disk_byte, - u64 extent_item_pos, - struct extent_inode_elem **eie) -{ - u64 disk_byte; - struct btrfs_key key; - struct btrfs_file_extent_item *fi; - int slot; - int nritems; - int extent_type; - int ret; - - /* - * from the shared data ref, we only have the leaf but we need - * the key. thus, we must look into all items and see that we - * find one (some) with a reference to our extent item. - */ - nritems = btrfs_header_nritems(eb); - for (slot = 0; slot < nritems; ++slot) { - btrfs_item_key_to_cpu(eb, &key, slot); - if (key.type != BTRFS_EXTENT_DATA_KEY) - continue; - fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); - extent_type = btrfs_file_extent_type(eb, fi); - if (extent_type == BTRFS_FILE_EXTENT_INLINE) - continue; - /* don't skip BTRFS_FILE_EXTENT_PREALLOC, we can handle that */ - disk_byte = btrfs_file_extent_disk_bytenr(eb, fi); - if (disk_byte != wanted_disk_byte) - continue; - - ret = check_extent_in_eb(&key, eb, fi, extent_item_pos, eie); - if (ret < 0) - return ret; - } - - return 0; -} - -/* - * this structure records all encountered refs on the way up to the root - */ -struct __prelim_ref { - struct list_head list; - u64 root_id; - struct btrfs_key key_for_search; - int level; - int count; - struct extent_inode_elem *inode_list; - u64 parent; - u64 wanted_disk_byte; -}; - -static struct kmem_cache *btrfs_prelim_ref_cache; - -int __init btrfs_prelim_ref_init(void) -{ - btrfs_prelim_ref_cache = kmem_cache_create("btrfs_prelim_ref", - sizeof(struct __prelim_ref), - 0, - SLAB_MEM_SPREAD, - NULL); - if (!btrfs_prelim_ref_cache) - return -ENOMEM; - return 0; -} - -void btrfs_prelim_ref_exit(void) -{ - kmem_cache_destroy(btrfs_prelim_ref_cache); -} - -/* - * the rules for all callers of this function are: - * - obtaining the parent is the goal - * - if you add a key, you must know that it is a correct key - * - if you cannot add the parent or a correct key, then we will look into the - * block later to set a correct key - * - * delayed refs - * ============ - * backref type | shared | indirect | shared | indirect - * information | tree | tree | data | data - * --------------------+--------+----------+--------+---------- - * parent logical | y | - | - | - - * key to resolve | - | y | y | y - * tree block logical | - | - | - | - - * root for resolving | y | y | y | y - * - * - column 1: we've the parent -> done - * - column 2, 3, 4: we use the key to find the parent - * - * on disk refs (inline or keyed) - * ============================== - * backref type | shared | indirect | shared | indirect - * information | tree | tree | data | data - * --------------------+--------+----------+--------+---------- - * parent logical | y | - | y | - - * key to resolve | - | - | - | y - * tree block logical | y | y | y | y - * root for resolving | - | y | y | y - * - * - column 1, 3: we've the parent -> done - * - column 2: we take the first key from the block to find the parent - * (see __add_missing_keys) - * - column 4: we use the key to find the parent - * - * additional information that's available but not required to find the parent - * block might help in merging entries to gain some speed. - */ - -static int __add_prelim_ref(struct list_head *head, u64 root_id, - struct btrfs_key *key, int level, - u64 parent, u64 wanted_disk_byte, int count, - gfp_t gfp_mask) -{ - struct __prelim_ref *ref; - - if (root_id == BTRFS_DATA_RELOC_TREE_OBJECTID) - return 0; - - ref = kmem_cache_alloc(btrfs_prelim_ref_cache, gfp_mask); - if (!ref) - return -ENOMEM; - - ref->root_id = root_id; - if (key) { - ref->key_for_search = *key; - /* - * We can often find data backrefs with an offset that is too - * large (>= LLONG_MAX, maximum allowed file offset) due to - * underflows when subtracting a file's offset with the data - * offset of its corresponding extent data item. This can - * happen for example in the clone ioctl. - * So if we detect such case we set the search key's offset to - * zero to make sure we will find the matching file extent item - * at add_all_parents(), otherwise we will miss it because the - * offset taken form the backref is much larger then the offset - * of the file extent item. This can make us scan a very large - * number of file extent items, but at least it will not make - * us miss any. - * This is an ugly workaround for a behaviour that should have - * never existed, but it does and a fix for the clone ioctl - * would touch a lot of places, cause backwards incompatibility - * and would not fix the problem for extents cloned with older - * kernels. - */ - if (ref->key_for_search.type == BTRFS_EXTENT_DATA_KEY && - ref->key_for_search.offset >= LLONG_MAX) - ref->key_for_search.offset = 0; - } else { - memset(&ref->key_for_search, 0, sizeof(ref->key_for_search)); - } - - ref->inode_list = NULL; - ref->level = level; - ref->count = count; - ref->parent = parent; - ref->wanted_disk_byte = wanted_disk_byte; - list_add_tail(&ref->list, head); - - return 0; -} - -static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, - struct ulist *parents, struct __prelim_ref *ref, - int level, u64 time_seq, const u64 *extent_item_pos, - u64 total_refs) -{ - int ret = 0; - int slot; - struct extent_buffer *eb; - struct btrfs_key key; - struct btrfs_key *key_for_search = &ref->key_for_search; - struct btrfs_file_extent_item *fi; - struct extent_inode_elem *eie = NULL, *old = NULL; - u64 disk_byte; - u64 wanted_disk_byte = ref->wanted_disk_byte; - u64 count = 0; - - if (level != 0) { - eb = path->nodes[level]; - ret = ulist_add(parents, eb->start, 0, GFP_NOFS); - if (ret < 0) - return ret; - return 0; - } - - /* - * We normally enter this function with the path already pointing to - * the first item to check. But sometimes, we may enter it with - * slot==nritems. In that case, go to the next leaf before we continue. - */ - if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { - if (time_seq == (u64)-1) - ret = btrfs_next_leaf(root, path); - else - ret = btrfs_next_old_leaf(root, path, time_seq); - } - - while (!ret && count < total_refs) { - eb = path->nodes[0]; - slot = path->slots[0]; - - btrfs_item_key_to_cpu(eb, &key, slot); - - if (key.objectid != key_for_search->objectid || - key.type != BTRFS_EXTENT_DATA_KEY) - break; - - fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); - disk_byte = btrfs_file_extent_disk_bytenr(eb, fi); - - if (disk_byte == wanted_disk_byte) { - eie = NULL; - old = NULL; - count++; - if (extent_item_pos) { - ret = check_extent_in_eb(&key, eb, fi, - *extent_item_pos, - &eie); - if (ret < 0) - break; - } - if (ret > 0) - goto next; - ret = ulist_add_merge_ptr(parents, eb->start, - eie, (void **)&old, GFP_NOFS); - if (ret < 0) - break; - if (!ret && extent_item_pos) { - while (old->next) - old = old->next; - old->next = eie; - } - eie = NULL; - } -next: - if (time_seq == (u64)-1) - ret = btrfs_next_item(root, path); - else - ret = btrfs_next_old_item(root, path, time_seq); - } - - if (ret > 0) - ret = 0; - else if (ret < 0) - free_inode_elem_list(eie); - return ret; -} - -/* - * resolve an indirect backref in the form (root_id, key, level) - * to a logical address - */ -static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, - struct btrfs_path *path, u64 time_seq, - struct __prelim_ref *ref, - struct ulist *parents, - const u64 *extent_item_pos, u64 total_refs) -{ - struct btrfs_root *root; - struct btrfs_key root_key; - struct extent_buffer *eb; - int ret = 0; - int root_level; - int level = ref->level; - int index; - - root_key.objectid = ref->root_id; - root_key.type = BTRFS_ROOT_ITEM_KEY; - root_key.offset = (u64)-1; - - index = srcu_read_lock(&fs_info->subvol_srcu); - - root = btrfs_get_fs_root(fs_info, &root_key, false); - if (IS_ERR(root)) { - srcu_read_unlock(&fs_info->subvol_srcu, index); - ret = PTR_ERR(root); - goto out; - } - - if (btrfs_is_testing(fs_info)) { - srcu_read_unlock(&fs_info->subvol_srcu, index); - ret = -ENOENT; - goto out; - } - - if (path->search_commit_root) - root_level = btrfs_header_level(root->commit_root); - else if (time_seq == (u64)-1) - root_level = btrfs_header_level(root->node); - else - root_level = btrfs_old_root_level(root, time_seq); - - if (root_level + 1 == level) { - srcu_read_unlock(&fs_info->subvol_srcu, index); - goto out; - } - - path->lowest_level = level; - if (time_seq == (u64)-1) - ret = btrfs_search_slot(NULL, root, &ref->key_for_search, path, - 0, 0); - else - ret = btrfs_search_old_slot(root, &ref->key_for_search, path, - time_seq); - - /* root node has been locked, we can release @subvol_srcu safely here */ - srcu_read_unlock(&fs_info->subvol_srcu, index); - - btrfs_debug(fs_info, - "search slot in root %llu (level %d, ref count %d) returned %d for key (%llu %u %llu)", - ref->root_id, level, ref->count, ret, - ref->key_for_search.objectid, ref->key_for_search.type, - ref->key_for_search.offset); - if (ret < 0) - goto out; - - eb = path->nodes[level]; - while (!eb) { - if (WARN_ON(!level)) { - ret = 1; - goto out; - } - level--; - eb = path->nodes[level]; - } - - ret = add_all_parents(root, path, parents, ref, level, time_seq, - extent_item_pos, total_refs); -out: - path->lowest_level = 0; - btrfs_release_path(path); - return ret; -} - -/* - * resolve all indirect backrefs from the list - */ -static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info, - struct btrfs_path *path, u64 time_seq, - struct list_head *head, - const u64 *extent_item_pos, u64 total_refs, - u64 root_objectid) -{ - int err; - int ret = 0; - struct __prelim_ref *ref; - struct __prelim_ref *ref_safe; - struct __prelim_ref *new_ref; - struct ulist *parents; - struct ulist_node *node; - struct ulist_iterator uiter; - - parents = ulist_alloc(GFP_NOFS); - if (!parents) - return -ENOMEM; - - /* - * _safe allows us to insert directly after the current item without - * iterating over the newly inserted items. - * we're also allowed to re-assign ref during iteration. - */ - list_for_each_entry_safe(ref, ref_safe, head, list) { - if (ref->parent) /* already direct */ - continue; - if (ref->count == 0) - continue; - if (root_objectid && ref->root_id != root_objectid) { - ret = BACKREF_FOUND_SHARED; - goto out; - } - err = __resolve_indirect_ref(fs_info, path, time_seq, ref, - parents, extent_item_pos, - total_refs); - /* - * we can only tolerate ENOENT,otherwise,we should catch error - * and return directly. - */ - if (err == -ENOENT) { - continue; - } else if (err) { - ret = err; - goto out; - } - - /* we put the first parent into the ref at hand */ - ULIST_ITER_INIT(&uiter); - node = ulist_next(parents, &uiter); - ref->parent = node ? node->val : 0; - ref->inode_list = node ? - (struct extent_inode_elem *)(uintptr_t)node->aux : NULL; - - /* additional parents require new refs being added here */ - while ((node = ulist_next(parents, &uiter))) { - new_ref = kmem_cache_alloc(btrfs_prelim_ref_cache, - GFP_NOFS); - if (!new_ref) { - ret = -ENOMEM; - goto out; - } - memcpy(new_ref, ref, sizeof(*ref)); - new_ref->parent = node->val; - new_ref->inode_list = (struct extent_inode_elem *) - (uintptr_t)node->aux; - list_add(&new_ref->list, &ref->list); - } - ulist_reinit(parents); - } -out: - ulist_free(parents); - return ret; -} - -static inline int ref_for_same_block(struct __prelim_ref *ref1, - struct __prelim_ref *ref2) -{ - if (ref1->level != ref2->level) - return 0; - if (ref1->root_id != ref2->root_id) - return 0; - if (ref1->key_for_search.type != ref2->key_for_search.type) - return 0; - if (ref1->key_for_search.objectid != ref2->key_for_search.objectid) - return 0; - if (ref1->key_for_search.offset != ref2->key_for_search.offset) - return 0; - if (ref1->parent != ref2->parent) - return 0; - - return 1; -} - -/* - * read tree blocks and add keys where required. - */ -static int __add_missing_keys(struct btrfs_fs_info *fs_info, - struct list_head *head) -{ - struct __prelim_ref *ref; - struct extent_buffer *eb; - - list_for_each_entry(ref, head, list) { - if (ref->parent) - continue; - if (ref->key_for_search.type) - continue; - BUG_ON(!ref->wanted_disk_byte); - eb = read_tree_block(fs_info->tree_root, ref->wanted_disk_byte, - 0); - if (IS_ERR(eb)) { - return PTR_ERR(eb); - } else if (!extent_buffer_uptodate(eb)) { - free_extent_buffer(eb); - return -EIO; - } - btrfs_tree_read_lock(eb); - if (btrfs_header_level(eb) == 0) - btrfs_item_key_to_cpu(eb, &ref->key_for_search, 0); - else - btrfs_node_key_to_cpu(eb, &ref->key_for_search, 0); - btrfs_tree_read_unlock(eb); - free_extent_buffer(eb); - } - return 0; -} - -/* - * merge backrefs and adjust counts accordingly - * - * mode = 1: merge identical keys, if key is set - * FIXME: if we add more keys in __add_prelim_ref, we can merge more here. - * additionally, we could even add a key range for the blocks we - * looked into to merge even more (-> replace unresolved refs by those - * having a parent). - * mode = 2: merge identical parents - */ -static void __merge_refs(struct list_head *head, int mode) -{ - struct __prelim_ref *pos1; - - list_for_each_entry(pos1, head, list) { - struct __prelim_ref *pos2 = pos1, *tmp; - - list_for_each_entry_safe_continue(pos2, tmp, head, list) { - struct __prelim_ref *ref1 = pos1, *ref2 = pos2; - struct extent_inode_elem *eie; - - if (!ref_for_same_block(ref1, ref2)) - continue; - if (mode == 1) { - if (!ref1->parent && ref2->parent) - swap(ref1, ref2); - } else { - if (ref1->parent != ref2->parent) - continue; - } - - eie = ref1->inode_list; - while (eie && eie->next) - eie = eie->next; - if (eie) - eie->next = ref2->inode_list; - else - ref1->inode_list = ref2->inode_list; - ref1->count += ref2->count; - - list_del(&ref2->list); - kmem_cache_free(btrfs_prelim_ref_cache, ref2); - cond_resched(); - } - - } -} - -/* - * add all currently queued delayed refs from this head whose seq nr is - * smaller or equal that seq to the list - */ -static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq, - struct list_head *prefs, u64 *total_refs, - u64 inum) -{ - struct btrfs_delayed_ref_node *node; - struct btrfs_delayed_extent_op *extent_op = head->extent_op; - struct btrfs_key key; - struct btrfs_key op_key = {0}; - int sgn; - int ret = 0; - - if (extent_op && extent_op->update_key) - btrfs_disk_key_to_cpu(&op_key, &extent_op->key); - - spin_lock(&head->lock); - list_for_each_entry(node, &head->ref_list, list) { - if (node->seq > seq) - continue; - - switch (node->action) { - case BTRFS_ADD_DELAYED_EXTENT: - case BTRFS_UPDATE_DELAYED_HEAD: - WARN_ON(1); - continue; - case BTRFS_ADD_DELAYED_REF: - sgn = 1; - break; - case BTRFS_DROP_DELAYED_REF: - sgn = -1; - break; - default: - BUG_ON(1); - } - *total_refs += (node->ref_mod * sgn); - switch (node->type) { - case BTRFS_TREE_BLOCK_REF_KEY: { - struct btrfs_delayed_tree_ref *ref; - - ref = btrfs_delayed_node_to_tree_ref(node); - ret = __add_prelim_ref(prefs, ref->root, &op_key, - ref->level + 1, 0, node->bytenr, - node->ref_mod * sgn, GFP_ATOMIC); - break; - } - case BTRFS_SHARED_BLOCK_REF_KEY: { - struct btrfs_delayed_tree_ref *ref; - - ref = btrfs_delayed_node_to_tree_ref(node); - ret = __add_prelim_ref(prefs, 0, NULL, - ref->level + 1, ref->parent, - node->bytenr, - node->ref_mod * sgn, GFP_ATOMIC); - break; - } - case BTRFS_EXTENT_DATA_REF_KEY: { - struct btrfs_delayed_data_ref *ref; - ref = btrfs_delayed_node_to_data_ref(node); - - key.objectid = ref->objectid; - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = ref->offset; - - /* - * Found a inum that doesn't match our known inum, we - * know it's shared. - */ - if (inum && ref->objectid != inum) { - ret = BACKREF_FOUND_SHARED; - break; - } - - ret = __add_prelim_ref(prefs, ref->root, &key, 0, 0, - node->bytenr, - node->ref_mod * sgn, GFP_ATOMIC); - break; - } - case BTRFS_SHARED_DATA_REF_KEY: { - struct btrfs_delayed_data_ref *ref; - - ref = btrfs_delayed_node_to_data_ref(node); - ret = __add_prelim_ref(prefs, 0, NULL, 0, - ref->parent, node->bytenr, - node->ref_mod * sgn, GFP_ATOMIC); - break; - } - default: - WARN_ON(1); - } - if (ret) - break; - } - spin_unlock(&head->lock); - return ret; -} - -/* - * add all inline backrefs for bytenr to the list - */ -static int __add_inline_refs(struct btrfs_fs_info *fs_info, - struct btrfs_path *path, u64 bytenr, - int *info_level, struct list_head *prefs, - struct ref_root *ref_tree, - u64 *total_refs, u64 inum) -{ - int ret = 0; - int slot; - struct extent_buffer *leaf; - struct btrfs_key key; - struct btrfs_key found_key; - unsigned long ptr; - unsigned long end; - struct btrfs_extent_item *ei; - u64 flags; - u64 item_size; - - /* - * enumerate all inline refs - */ - leaf = path->nodes[0]; - slot = path->slots[0]; - - item_size = btrfs_item_size_nr(leaf, slot); - BUG_ON(item_size < sizeof(*ei)); - - ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item); - flags = btrfs_extent_flags(leaf, ei); - *total_refs += btrfs_extent_refs(leaf, ei); - btrfs_item_key_to_cpu(leaf, &found_key, slot); - - ptr = (unsigned long)(ei + 1); - end = (unsigned long)ei + item_size; - - if (found_key.type == BTRFS_EXTENT_ITEM_KEY && - flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { - struct btrfs_tree_block_info *info; - - info = (struct btrfs_tree_block_info *)ptr; - *info_level = btrfs_tree_block_level(leaf, info); - ptr += sizeof(struct btrfs_tree_block_info); - BUG_ON(ptr > end); - } else if (found_key.type == BTRFS_METADATA_ITEM_KEY) { - *info_level = found_key.offset; - } else { - BUG_ON(!(flags & BTRFS_EXTENT_FLAG_DATA)); - } - - while (ptr < end) { - struct btrfs_extent_inline_ref *iref; - u64 offset; - int type; - - iref = (struct btrfs_extent_inline_ref *)ptr; - type = btrfs_extent_inline_ref_type(leaf, iref); - offset = btrfs_extent_inline_ref_offset(leaf, iref); - - switch (type) { - case BTRFS_SHARED_BLOCK_REF_KEY: - ret = __add_prelim_ref(prefs, 0, NULL, - *info_level + 1, offset, - bytenr, 1, GFP_NOFS); - break; - case BTRFS_SHARED_DATA_REF_KEY: { - struct btrfs_shared_data_ref *sdref; - int count; - - sdref = (struct btrfs_shared_data_ref *)(iref + 1); - count = btrfs_shared_data_ref_count(leaf, sdref); - ret = __add_prelim_ref(prefs, 0, NULL, 0, offset, - bytenr, count, GFP_NOFS); - if (ref_tree) { - if (!ret) - ret = ref_tree_add(ref_tree, 0, 0, 0, - bytenr, count); - if (!ret && ref_tree->unique_refs > 1) - ret = BACKREF_FOUND_SHARED; - } - break; - } - case BTRFS_TREE_BLOCK_REF_KEY: - ret = __add_prelim_ref(prefs, offset, NULL, - *info_level + 1, 0, - bytenr, 1, GFP_NOFS); - break; - case BTRFS_EXTENT_DATA_REF_KEY: { - struct btrfs_extent_data_ref *dref; - int count; - u64 root; - - dref = (struct btrfs_extent_data_ref *)(&iref->offset); - count = btrfs_extent_data_ref_count(leaf, dref); - key.objectid = btrfs_extent_data_ref_objectid(leaf, - dref); - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = btrfs_extent_data_ref_offset(leaf, dref); - - if (inum && key.objectid != inum) { - ret = BACKREF_FOUND_SHARED; - break; - } - - root = btrfs_extent_data_ref_root(leaf, dref); - ret = __add_prelim_ref(prefs, root, &key, 0, 0, - bytenr, count, GFP_NOFS); - if (ref_tree) { - if (!ret) - ret = ref_tree_add(ref_tree, root, - key.objectid, - key.offset, 0, - count); - if (!ret && ref_tree->unique_refs > 1) - ret = BACKREF_FOUND_SHARED; - } - break; - } - default: - WARN_ON(1); - } - if (ret) - return ret; - ptr += btrfs_extent_inline_ref_size(type); - } - - return 0; -} - -/* - * add all non-inline backrefs for bytenr to the list - */ -static int __add_keyed_refs(struct btrfs_fs_info *fs_info, - struct btrfs_path *path, u64 bytenr, - int info_level, struct list_head *prefs, - struct ref_root *ref_tree, u64 inum) -{ - struct btrfs_root *extent_root = fs_info->extent_root; - int ret; - int slot; - struct extent_buffer *leaf; - struct btrfs_key key; - - while (1) { - ret = btrfs_next_item(extent_root, path); - if (ret < 0) - break; - if (ret) { - ret = 0; - break; - } - - slot = path->slots[0]; - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, slot); - - if (key.objectid != bytenr) - break; - if (key.type < BTRFS_TREE_BLOCK_REF_KEY) - continue; - if (key.type > BTRFS_SHARED_DATA_REF_KEY) - break; - - switch (key.type) { - case BTRFS_SHARED_BLOCK_REF_KEY: - ret = __add_prelim_ref(prefs, 0, NULL, - info_level + 1, key.offset, - bytenr, 1, GFP_NOFS); - break; - case BTRFS_SHARED_DATA_REF_KEY: { - struct btrfs_shared_data_ref *sdref; - int count; - - sdref = btrfs_item_ptr(leaf, slot, - struct btrfs_shared_data_ref); - count = btrfs_shared_data_ref_count(leaf, sdref); - ret = __add_prelim_ref(prefs, 0, NULL, 0, key.offset, - bytenr, count, GFP_NOFS); - if (ref_tree) { - if (!ret) - ret = ref_tree_add(ref_tree, 0, 0, 0, - bytenr, count); - if (!ret && ref_tree->unique_refs > 1) - ret = BACKREF_FOUND_SHARED; - } - break; - } - case BTRFS_TREE_BLOCK_REF_KEY: - ret = __add_prelim_ref(prefs, key.offset, NULL, - info_level + 1, 0, - bytenr, 1, GFP_NOFS); - break; - case BTRFS_EXTENT_DATA_REF_KEY: { - struct btrfs_extent_data_ref *dref; - int count; - u64 root; - - dref = btrfs_item_ptr(leaf, slot, - struct btrfs_extent_data_ref); - count = btrfs_extent_data_ref_count(leaf, dref); - key.objectid = btrfs_extent_data_ref_objectid(leaf, - dref); - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = btrfs_extent_data_ref_offset(leaf, dref); - - if (inum && key.objectid != inum) { - ret = BACKREF_FOUND_SHARED; - break; - } - - root = btrfs_extent_data_ref_root(leaf, dref); - ret = __add_prelim_ref(prefs, root, &key, 0, 0, - bytenr, count, GFP_NOFS); - if (ref_tree) { - if (!ret) - ret = ref_tree_add(ref_tree, root, - key.objectid, - key.offset, 0, - count); - if (!ret && ref_tree->unique_refs > 1) - ret = BACKREF_FOUND_SHARED; - } - break; - } - default: - WARN_ON(1); - } - if (ret) - return ret; - - } - - return ret; -} - -/* - * this adds all existing backrefs (inline backrefs, backrefs and delayed - * refs) for the given bytenr to the refs list, merges duplicates and resolves - * indirect refs to their parent bytenr. - * When roots are found, they're added to the roots list - * - * NOTE: This can return values > 0 - * - * If time_seq is set to (u64)-1, it will not search delayed_refs, and behave - * much like trans == NULL case, the difference only lies in it will not - * commit root. - * The special case is for qgroup to search roots in commit_transaction(). - * - * If check_shared is set to 1, any extent has more than one ref item, will - * be returned BACKREF_FOUND_SHARED immediately. - * - * FIXME some caching might speed things up - */ -static int find_parent_nodes(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 bytenr, - u64 time_seq, struct ulist *refs, - struct ulist *roots, const u64 *extent_item_pos, - u64 root_objectid, u64 inum, int check_shared) -{ - struct btrfs_key key; - struct btrfs_path *path; - struct btrfs_delayed_ref_root *delayed_refs = NULL; - struct btrfs_delayed_ref_head *head; - int info_level = 0; - int ret; - struct list_head prefs_delayed; - struct list_head prefs; - struct __prelim_ref *ref; - struct extent_inode_elem *eie = NULL; - struct ref_root *ref_tree = NULL; - u64 total_refs = 0; - - INIT_LIST_HEAD(&prefs); - INIT_LIST_HEAD(&prefs_delayed); - - key.objectid = bytenr; - key.offset = (u64)-1; - if (btrfs_fs_incompat(fs_info, SKINNY_METADATA)) - key.type = BTRFS_METADATA_ITEM_KEY; - else - key.type = BTRFS_EXTENT_ITEM_KEY; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - if (!trans) { - path->search_commit_root = 1; - path->skip_locking = 1; - } - - if (time_seq == (u64)-1) - path->skip_locking = 1; - - /* - * grab both a lock on the path and a lock on the delayed ref head. - * We need both to get a consistent picture of how the refs look - * at a specified point in time - */ -again: - head = NULL; - - if (check_shared) { - if (!ref_tree) { - ref_tree = ref_root_alloc(); - if (!ref_tree) { - ret = -ENOMEM; - goto out; - } - } else { - ref_root_fini(ref_tree); - } - } - - ret = btrfs_search_slot(trans, fs_info->extent_root, &key, path, 0, 0); - if (ret < 0) - goto out; - BUG_ON(ret == 0); - -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS - if (trans && likely(trans->type != __TRANS_DUMMY) && - time_seq != (u64)-1) { -#else - if (trans && time_seq != (u64)-1) { -#endif - /* - * look if there are updates for this ref queued and lock the - * head - */ - delayed_refs = &trans->transaction->delayed_refs; - spin_lock(&delayed_refs->lock); - head = btrfs_find_delayed_ref_head(trans, bytenr); - if (head) { - if (!mutex_trylock(&head->mutex)) { - atomic_inc(&head->node.refs); - spin_unlock(&delayed_refs->lock); - - btrfs_release_path(path); - - /* - * Mutex was contended, block until it's - * released and try again - */ - mutex_lock(&head->mutex); - mutex_unlock(&head->mutex); - btrfs_put_delayed_ref(&head->node); - goto again; - } - spin_unlock(&delayed_refs->lock); - ret = __add_delayed_refs(head, time_seq, - &prefs_delayed, &total_refs, - inum); - mutex_unlock(&head->mutex); - if (ret) - goto out; - } else { - spin_unlock(&delayed_refs->lock); - } - - if (check_shared && !list_empty(&prefs_delayed)) { - /* - * Add all delay_ref to the ref_tree and check if there - * are multiple ref items added. - */ - list_for_each_entry(ref, &prefs_delayed, list) { - if (ref->key_for_search.type) { - ret = ref_tree_add(ref_tree, - ref->root_id, - ref->key_for_search.objectid, - ref->key_for_search.offset, - 0, ref->count); - if (ret) - goto out; - } else { - ret = ref_tree_add(ref_tree, 0, 0, 0, - ref->parent, ref->count); - if (ret) - goto out; - } - - } - - if (ref_tree->unique_refs > 1) { - ret = BACKREF_FOUND_SHARED; - goto out; - } - - } - } - - if (path->slots[0]) { - struct extent_buffer *leaf; - int slot; - - path->slots[0]--; - leaf = path->nodes[0]; - slot = path->slots[0]; - btrfs_item_key_to_cpu(leaf, &key, slot); - if (key.objectid == bytenr && - (key.type == BTRFS_EXTENT_ITEM_KEY || - key.type == BTRFS_METADATA_ITEM_KEY)) { - ret = __add_inline_refs(fs_info, path, bytenr, - &info_level, &prefs, - ref_tree, &total_refs, - inum); - if (ret) - goto out; - ret = __add_keyed_refs(fs_info, path, bytenr, - info_level, &prefs, - ref_tree, inum); - if (ret) - goto out; - } - } - btrfs_release_path(path); - - list_splice_init(&prefs_delayed, &prefs); - - ret = __add_missing_keys(fs_info, &prefs); - if (ret) - goto out; - - __merge_refs(&prefs, 1); - - ret = __resolve_indirect_refs(fs_info, path, time_seq, &prefs, - extent_item_pos, total_refs, - root_objectid); - if (ret) - goto out; - - __merge_refs(&prefs, 2); - - while (!list_empty(&prefs)) { - ref = list_first_entry(&prefs, struct __prelim_ref, list); - WARN_ON(ref->count < 0); - if (roots && ref->count && ref->root_id && ref->parent == 0) { - if (root_objectid && ref->root_id != root_objectid) { - ret = BACKREF_FOUND_SHARED; - goto out; - } - - /* no parent == root of tree */ - ret = ulist_add(roots, ref->root_id, 0, GFP_NOFS); - if (ret < 0) - goto out; - } - if (ref->count && ref->parent) { - if (extent_item_pos && !ref->inode_list && - ref->level == 0) { - struct extent_buffer *eb; - - eb = read_tree_block(fs_info->extent_root, - ref->parent, 0); - if (IS_ERR(eb)) { - ret = PTR_ERR(eb); - goto out; - } else if (!extent_buffer_uptodate(eb)) { - free_extent_buffer(eb); - ret = -EIO; - goto out; - } - btrfs_tree_read_lock(eb); - btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); - ret = find_extent_in_eb(eb, bytenr, - *extent_item_pos, &eie); - btrfs_tree_read_unlock_blocking(eb); - free_extent_buffer(eb); - if (ret < 0) - goto out; - ref->inode_list = eie; - } - ret = ulist_add_merge_ptr(refs, ref->parent, - ref->inode_list, - (void **)&eie, GFP_NOFS); - if (ret < 0) - goto out; - if (!ret && extent_item_pos) { - /* - * we've recorded that parent, so we must extend - * its inode list here - */ - BUG_ON(!eie); - while (eie->next) - eie = eie->next; - eie->next = ref->inode_list; - } - eie = NULL; - } - list_del(&ref->list); - kmem_cache_free(btrfs_prelim_ref_cache, ref); - } - -out: - btrfs_free_path(path); - ref_root_free(ref_tree); - while (!list_empty(&prefs)) { - ref = list_first_entry(&prefs, struct __prelim_ref, list); - list_del(&ref->list); - kmem_cache_free(btrfs_prelim_ref_cache, ref); - } - while (!list_empty(&prefs_delayed)) { - ref = list_first_entry(&prefs_delayed, struct __prelim_ref, - list); - list_del(&ref->list); - kmem_cache_free(btrfs_prelim_ref_cache, ref); - } - if (ret < 0) - free_inode_elem_list(eie); - return ret; -} - -static void free_leaf_list(struct ulist *blocks) -{ - struct ulist_node *node = NULL; - struct extent_inode_elem *eie; - struct ulist_iterator uiter; - - ULIST_ITER_INIT(&uiter); - while ((node = ulist_next(blocks, &uiter))) { - if (!node->aux) - continue; - eie = (struct extent_inode_elem *)(uintptr_t)node->aux; - free_inode_elem_list(eie); - node->aux = 0; - } - - ulist_free(blocks); -} - -/* - * Finds all leafs with a reference to the specified combination of bytenr and - * offset. key_list_head will point to a list of corresponding keys (caller must - * free each list element). The leafs will be stored in the leafs ulist, which - * must be freed with ulist_free. - * - * returns 0 on success, <0 on error - */ -static int btrfs_find_all_leafs(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 bytenr, - u64 time_seq, struct ulist **leafs, - const u64 *extent_item_pos) -{ - int ret; - - *leafs = ulist_alloc(GFP_NOFS); - if (!*leafs) - return -ENOMEM; - - ret = find_parent_nodes(trans, fs_info, bytenr, time_seq, - *leafs, NULL, extent_item_pos, 0, 0, 0); - if (ret < 0 && ret != -ENOENT) { - free_leaf_list(*leafs); - return ret; - } - - return 0; -} - -/* - * walk all backrefs for a given extent to find all roots that reference this - * extent. Walking a backref means finding all extents that reference this - * extent and in turn walk the backrefs of those, too. Naturally this is a - * recursive process, but here it is implemented in an iterative fashion: We - * find all referencing extents for the extent in question and put them on a - * list. In turn, we find all referencing extents for those, further appending - * to the list. The way we iterate the list allows adding more elements after - * the current while iterating. The process stops when we reach the end of the - * list. Found roots are added to the roots list. - * - * returns 0 on success, < 0 on error. - */ -static int __btrfs_find_all_roots(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 bytenr, - u64 time_seq, struct ulist **roots) -{ - struct ulist *tmp; - struct ulist_node *node = NULL; - struct ulist_iterator uiter; - int ret; - - tmp = ulist_alloc(GFP_NOFS); - if (!tmp) - return -ENOMEM; - *roots = ulist_alloc(GFP_NOFS); - if (!*roots) { - ulist_free(tmp); - return -ENOMEM; - } - - ULIST_ITER_INIT(&uiter); - while (1) { - ret = find_parent_nodes(trans, fs_info, bytenr, time_seq, - tmp, *roots, NULL, 0, 0, 0); - if (ret < 0 && ret != -ENOENT) { - ulist_free(tmp); - ulist_free(*roots); - return ret; - } - node = ulist_next(tmp, &uiter); - if (!node) - break; - bytenr = node->val; - cond_resched(); - } - - ulist_free(tmp); - return 0; -} - -int btrfs_find_all_roots(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 bytenr, - u64 time_seq, struct ulist **roots) -{ - int ret; - - if (!trans) - down_read(&fs_info->commit_root_sem); - ret = __btrfs_find_all_roots(trans, fs_info, bytenr, time_seq, roots); - if (!trans) - up_read(&fs_info->commit_root_sem); - return ret; -} - -/** - * btrfs_check_shared - tell us whether an extent is shared - * - * @trans: optional trans handle - * - * btrfs_check_shared uses the backref walking code but will short - * circuit as soon as it finds a root or inode that doesn't match the - * one passed in. This provides a significant performance benefit for - * callers (such as fiemap) which want to know whether the extent is - * shared but do not need a ref count. - * - * Return: 0 if extent is not shared, 1 if it is shared, < 0 on error. - */ -int btrfs_check_shared(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 root_objectid, - u64 inum, u64 bytenr) -{ - struct ulist *tmp = NULL; - struct ulist *roots = NULL; - struct ulist_iterator uiter; - struct ulist_node *node; - struct seq_list elem = SEQ_LIST_INIT(elem); - int ret = 0; - - tmp = ulist_alloc(GFP_NOFS); - roots = ulist_alloc(GFP_NOFS); - if (!tmp || !roots) { - ulist_free(tmp); - ulist_free(roots); - return -ENOMEM; - } - - if (trans) - btrfs_get_tree_mod_seq(fs_info, &elem); - else - down_read(&fs_info->commit_root_sem); - ULIST_ITER_INIT(&uiter); - while (1) { - ret = find_parent_nodes(trans, fs_info, bytenr, elem.seq, tmp, - roots, NULL, root_objectid, inum, 1); - if (ret == BACKREF_FOUND_SHARED) { - /* this is the only condition under which we return 1 */ - ret = 1; - break; - } - if (ret < 0 && ret != -ENOENT) - break; - ret = 0; - node = ulist_next(tmp, &uiter); - if (!node) - break; - bytenr = node->val; - cond_resched(); - } - if (trans) - btrfs_put_tree_mod_seq(fs_info, &elem); - else - up_read(&fs_info->commit_root_sem); - ulist_free(tmp); - ulist_free(roots); - return ret; -} - -int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid, - u64 start_off, struct btrfs_path *path, - struct btrfs_inode_extref **ret_extref, - u64 *found_off) -{ - int ret, slot; - struct btrfs_key key; - struct btrfs_key found_key; - struct btrfs_inode_extref *extref; - struct extent_buffer *leaf; - unsigned long ptr; - - key.objectid = inode_objectid; - key.type = BTRFS_INODE_EXTREF_KEY; - key.offset = start_off; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - return ret; - - while (1) { - leaf = path->nodes[0]; - slot = path->slots[0]; - if (slot >= btrfs_header_nritems(leaf)) { - /* - * If the item at offset is not found, - * btrfs_search_slot will point us to the slot - * where it should be inserted. In our case - * that will be the slot directly before the - * next INODE_REF_KEY_V2 item. In the case - * that we're pointing to the last slot in a - * leaf, we must move one leaf over. - */ - ret = btrfs_next_leaf(root, path); - if (ret) { - if (ret >= 1) - ret = -ENOENT; - break; - } - continue; - } - - btrfs_item_key_to_cpu(leaf, &found_key, slot); - - /* - * Check that we're still looking at an extended ref key for - * this particular objectid. If we have different - * objectid or type then there are no more to be found - * in the tree and we can exit. - */ - ret = -ENOENT; - if (found_key.objectid != inode_objectid) - break; - if (found_key.type != BTRFS_INODE_EXTREF_KEY) - break; - - ret = 0; - ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); - extref = (struct btrfs_inode_extref *)ptr; - *ret_extref = extref; - if (found_off) - *found_off = found_key.offset; - break; - } - - return ret; -} - -/* - * this iterates to turn a name (from iref/extref) into a full filesystem path. - * Elements of the path are separated by '/' and the path is guaranteed to be - * 0-terminated. the path is only given within the current file system. - * Therefore, it never starts with a '/'. the caller is responsible to provide - * "size" bytes in "dest". the dest buffer will be filled backwards. finally, - * the start point of the resulting string is returned. this pointer is within - * dest, normally. - * in case the path buffer would overflow, the pointer is decremented further - * as if output was written to the buffer, though no more output is actually - * generated. that way, the caller can determine how much space would be - * required for the path to fit into the buffer. in that case, the returned - * value will be smaller than dest. callers must check this! - */ -char *btrfs_ref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path, - u32 name_len, unsigned long name_off, - struct extent_buffer *eb_in, u64 parent, - char *dest, u32 size) -{ - int slot; - u64 next_inum; - int ret; - s64 bytes_left = ((s64)size) - 1; - struct extent_buffer *eb = eb_in; - struct btrfs_key found_key; - int leave_spinning = path->leave_spinning; - struct btrfs_inode_ref *iref; - - if (bytes_left >= 0) - dest[bytes_left] = '\0'; - - path->leave_spinning = 1; - while (1) { - bytes_left -= name_len; - if (bytes_left >= 0) - read_extent_buffer(eb, dest + bytes_left, - name_off, name_len); - if (eb != eb_in) { - if (!path->skip_locking) - btrfs_tree_read_unlock_blocking(eb); - free_extent_buffer(eb); - } - ret = btrfs_find_item(fs_root, path, parent, 0, - BTRFS_INODE_REF_KEY, &found_key); - if (ret > 0) - ret = -ENOENT; - if (ret) - break; - - next_inum = found_key.offset; - - /* regular exit ahead */ - if (parent == next_inum) - break; - - slot = path->slots[0]; - eb = path->nodes[0]; - /* make sure we can use eb after releasing the path */ - if (eb != eb_in) { - if (!path->skip_locking) - btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); - path->nodes[0] = NULL; - path->locks[0] = 0; - } - btrfs_release_path(path); - iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref); - - name_len = btrfs_inode_ref_name_len(eb, iref); - name_off = (unsigned long)(iref + 1); - - parent = next_inum; - --bytes_left; - if (bytes_left >= 0) - dest[bytes_left] = '/'; - } - - btrfs_release_path(path); - path->leave_spinning = leave_spinning; - - if (ret) - return ERR_PTR(ret); - - return dest + bytes_left; -} - -/* - * this makes the path point to (logical EXTENT_ITEM *) - * returns BTRFS_EXTENT_FLAG_DATA for data, BTRFS_EXTENT_FLAG_TREE_BLOCK for - * tree blocks and <0 on error. - */ -int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical, - struct btrfs_path *path, struct btrfs_key *found_key, - u64 *flags_ret) -{ - int ret; - u64 flags; - u64 size = 0; - u32 item_size; - struct extent_buffer *eb; - struct btrfs_extent_item *ei; - struct btrfs_key key; - - if (btrfs_fs_incompat(fs_info, SKINNY_METADATA)) - key.type = BTRFS_METADATA_ITEM_KEY; - else - key.type = BTRFS_EXTENT_ITEM_KEY; - key.objectid = logical; - key.offset = (u64)-1; - - ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0); - if (ret < 0) - return ret; - - ret = btrfs_previous_extent_item(fs_info->extent_root, path, 0); - if (ret) { - if (ret > 0) - ret = -ENOENT; - return ret; - } - btrfs_item_key_to_cpu(path->nodes[0], found_key, path->slots[0]); - if (found_key->type == BTRFS_METADATA_ITEM_KEY) - size = fs_info->extent_root->nodesize; - else if (found_key->type == BTRFS_EXTENT_ITEM_KEY) - size = found_key->offset; - - if (found_key->objectid > logical || - found_key->objectid + size <= logical) { - btrfs_debug(fs_info, - "logical %llu is not within any extent", logical); - return -ENOENT; - } - - eb = path->nodes[0]; - item_size = btrfs_item_size_nr(eb, path->slots[0]); - BUG_ON(item_size < sizeof(*ei)); - - ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item); - flags = btrfs_extent_flags(eb, ei); - - btrfs_debug(fs_info, - "logical %llu is at position %llu within the extent (%llu EXTENT_ITEM %llu) flags %#llx size %u", - logical, logical - found_key->objectid, found_key->objectid, - found_key->offset, flags, item_size); - - WARN_ON(!flags_ret); - if (flags_ret) { - if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) - *flags_ret = BTRFS_EXTENT_FLAG_TREE_BLOCK; - else if (flags & BTRFS_EXTENT_FLAG_DATA) - *flags_ret = BTRFS_EXTENT_FLAG_DATA; - else - BUG_ON(1); - return 0; - } - - return -EIO; -} - -/* - * helper function to iterate extent inline refs. ptr must point to a 0 value - * for the first call and may be modified. it is used to track state. - * if more refs exist, 0 is returned and the next call to - * __get_extent_inline_ref must pass the modified ptr parameter to get the - * next ref. after the last ref was processed, 1 is returned. - * returns <0 on error - */ -static int __get_extent_inline_ref(unsigned long *ptr, struct extent_buffer *eb, - struct btrfs_key *key, - struct btrfs_extent_item *ei, u32 item_size, - struct btrfs_extent_inline_ref **out_eiref, - int *out_type) -{ - unsigned long end; - u64 flags; - struct btrfs_tree_block_info *info; - - if (!*ptr) { - /* first call */ - flags = btrfs_extent_flags(eb, ei); - if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { - if (key->type == BTRFS_METADATA_ITEM_KEY) { - /* a skinny metadata extent */ - *out_eiref = - (struct btrfs_extent_inline_ref *)(ei + 1); - } else { - WARN_ON(key->type != BTRFS_EXTENT_ITEM_KEY); - info = (struct btrfs_tree_block_info *)(ei + 1); - *out_eiref = - (struct btrfs_extent_inline_ref *)(info + 1); - } - } else { - *out_eiref = (struct btrfs_extent_inline_ref *)(ei + 1); - } - *ptr = (unsigned long)*out_eiref; - if ((unsigned long)(*ptr) >= (unsigned long)ei + item_size) - return -ENOENT; - } - - end = (unsigned long)ei + item_size; - *out_eiref = (struct btrfs_extent_inline_ref *)(*ptr); - *out_type = btrfs_extent_inline_ref_type(eb, *out_eiref); - - *ptr += btrfs_extent_inline_ref_size(*out_type); - WARN_ON(*ptr > end); - if (*ptr == end) - return 1; /* last */ - - return 0; -} - -/* - * reads the tree block backref for an extent. tree level and root are returned - * through out_level and out_root. ptr must point to a 0 value for the first - * call and may be modified (see __get_extent_inline_ref comment). - * returns 0 if data was provided, 1 if there was no more data to provide or - * <0 on error. - */ -int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb, - struct btrfs_key *key, struct btrfs_extent_item *ei, - u32 item_size, u64 *out_root, u8 *out_level) -{ - int ret; - int type; - struct btrfs_extent_inline_ref *eiref; - - if (*ptr == (unsigned long)-1) - return 1; - - while (1) { - ret = __get_extent_inline_ref(ptr, eb, key, ei, item_size, - &eiref, &type); - if (ret < 0) - return ret; - - if (type == BTRFS_TREE_BLOCK_REF_KEY || - type == BTRFS_SHARED_BLOCK_REF_KEY) - break; - - if (ret == 1) - return 1; - } - - /* we can treat both ref types equally here */ - *out_root = btrfs_extent_inline_ref_offset(eb, eiref); - - if (key->type == BTRFS_EXTENT_ITEM_KEY) { - struct btrfs_tree_block_info *info; - - info = (struct btrfs_tree_block_info *)(ei + 1); - *out_level = btrfs_tree_block_level(eb, info); - } else { - ASSERT(key->type == BTRFS_METADATA_ITEM_KEY); - *out_level = (u8)key->offset; - } - - if (ret == 1) - *ptr = (unsigned long)-1; - - return 0; -} - -static int iterate_leaf_refs(struct btrfs_fs_info *fs_info, - struct extent_inode_elem *inode_list, - u64 root, u64 extent_item_objectid, - iterate_extent_inodes_t *iterate, void *ctx) -{ - struct extent_inode_elem *eie; - int ret = 0; - - for (eie = inode_list; eie; eie = eie->next) { - btrfs_debug(fs_info, - "ref for %llu resolved, key (%llu EXTEND_DATA %llu), root %llu", - extent_item_objectid, eie->inum, - eie->offset, root); - ret = iterate(eie->inum, eie->offset, root, ctx); - if (ret) { - btrfs_debug(fs_info, - "stopping iteration for %llu due to ret=%d", - extent_item_objectid, ret); - break; - } - } - - return ret; -} - -/* - * calls iterate() for every inode that references the extent identified by - * the given parameters. - * when the iterator function returns a non-zero value, iteration stops. - */ -int iterate_extent_inodes(struct btrfs_fs_info *fs_info, - u64 extent_item_objectid, u64 extent_item_pos, - int search_commit_root, - iterate_extent_inodes_t *iterate, void *ctx) -{ - int ret; - struct btrfs_trans_handle *trans = NULL; - struct ulist *refs = NULL; - struct ulist *roots = NULL; - struct ulist_node *ref_node = NULL; - struct ulist_node *root_node = NULL; - struct seq_list tree_mod_seq_elem = SEQ_LIST_INIT(tree_mod_seq_elem); - struct ulist_iterator ref_uiter; - struct ulist_iterator root_uiter; - - btrfs_debug(fs_info, "resolving all inodes for extent %llu", - extent_item_objectid); - - if (!search_commit_root) { - trans = btrfs_join_transaction(fs_info->extent_root); - if (IS_ERR(trans)) - return PTR_ERR(trans); - btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem); - } else { - down_read(&fs_info->commit_root_sem); - } - - ret = btrfs_find_all_leafs(trans, fs_info, extent_item_objectid, - tree_mod_seq_elem.seq, &refs, - &extent_item_pos); - if (ret) - goto out; - - ULIST_ITER_INIT(&ref_uiter); - while (!ret && (ref_node = ulist_next(refs, &ref_uiter))) { - ret = __btrfs_find_all_roots(trans, fs_info, ref_node->val, - tree_mod_seq_elem.seq, &roots); - if (ret) - break; - ULIST_ITER_INIT(&root_uiter); - while (!ret && (root_node = ulist_next(roots, &root_uiter))) { - btrfs_debug(fs_info, - "root %llu references leaf %llu, data list %#llx", - root_node->val, ref_node->val, - ref_node->aux); - ret = iterate_leaf_refs(fs_info, - (struct extent_inode_elem *) - (uintptr_t)ref_node->aux, - root_node->val, - extent_item_objectid, - iterate, ctx); - } - ulist_free(roots); - } - - free_leaf_list(refs); -out: - if (!search_commit_root) { - btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem); - btrfs_end_transaction(trans, fs_info->extent_root); - } else { - up_read(&fs_info->commit_root_sem); - } - - return ret; -} - -int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info, - struct btrfs_path *path, - iterate_extent_inodes_t *iterate, void *ctx) -{ - int ret; - u64 extent_item_pos; - u64 flags = 0; - struct btrfs_key found_key; - int search_commit_root = path->search_commit_root; - - ret = extent_from_logical(fs_info, logical, path, &found_key, &flags); - btrfs_release_path(path); - if (ret < 0) - return ret; - if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) - return -EINVAL; - - extent_item_pos = logical - found_key.objectid; - ret = iterate_extent_inodes(fs_info, found_key.objectid, - extent_item_pos, search_commit_root, - iterate, ctx); - - return ret; -} - -typedef int (iterate_irefs_t)(u64 parent, u32 name_len, unsigned long name_off, - struct extent_buffer *eb, void *ctx); - -static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root, - struct btrfs_path *path, - iterate_irefs_t *iterate, void *ctx) -{ - int ret = 0; - int slot; - u32 cur; - u32 len; - u32 name_len; - u64 parent = 0; - int found = 0; - struct extent_buffer *eb; - struct btrfs_item *item; - struct btrfs_inode_ref *iref; - struct btrfs_key found_key; - - while (!ret) { - ret = btrfs_find_item(fs_root, path, inum, - parent ? parent + 1 : 0, BTRFS_INODE_REF_KEY, - &found_key); - - if (ret < 0) - break; - if (ret) { - ret = found ? 0 : -ENOENT; - break; - } - ++found; - - parent = found_key.offset; - slot = path->slots[0]; - eb = btrfs_clone_extent_buffer(path->nodes[0]); - if (!eb) { - ret = -ENOMEM; - break; - } - extent_buffer_get(eb); - btrfs_tree_read_lock(eb); - btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); - btrfs_release_path(path); - - item = btrfs_item_nr(slot); - iref = btrfs_item_ptr(eb, slot, struct btrfs_inode_ref); - - for (cur = 0; cur < btrfs_item_size(eb, item); cur += len) { - name_len = btrfs_inode_ref_name_len(eb, iref); - /* path must be released before calling iterate()! */ - btrfs_debug(fs_root->fs_info, - "following ref at offset %u for inode %llu in tree %llu", - cur, found_key.objectid, fs_root->objectid); - ret = iterate(parent, name_len, - (unsigned long)(iref + 1), eb, ctx); - if (ret) - break; - len = sizeof(*iref) + name_len; - iref = (struct btrfs_inode_ref *)((char *)iref + len); - } - btrfs_tree_read_unlock_blocking(eb); - free_extent_buffer(eb); - } - - btrfs_release_path(path); - - return ret; -} - -static int iterate_inode_extrefs(u64 inum, struct btrfs_root *fs_root, - struct btrfs_path *path, - iterate_irefs_t *iterate, void *ctx) -{ - int ret; - int slot; - u64 offset = 0; - u64 parent; - int found = 0; - struct extent_buffer *eb; - struct btrfs_inode_extref *extref; - u32 item_size; - u32 cur_offset; - unsigned long ptr; - - while (1) { - ret = btrfs_find_one_extref(fs_root, inum, offset, path, &extref, - &offset); - if (ret < 0) - break; - if (ret) { - ret = found ? 0 : -ENOENT; - break; - } - ++found; - - slot = path->slots[0]; - eb = btrfs_clone_extent_buffer(path->nodes[0]); - if (!eb) { - ret = -ENOMEM; - break; - } - extent_buffer_get(eb); - - btrfs_tree_read_lock(eb); - btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); - btrfs_release_path(path); - - item_size = btrfs_item_size_nr(eb, slot); - ptr = btrfs_item_ptr_offset(eb, slot); - cur_offset = 0; - - while (cur_offset < item_size) { - u32 name_len; - - extref = (struct btrfs_inode_extref *)(ptr + cur_offset); - parent = btrfs_inode_extref_parent(eb, extref); - name_len = btrfs_inode_extref_name_len(eb, extref); - ret = iterate(parent, name_len, - (unsigned long)&extref->name, eb, ctx); - if (ret) - break; - - cur_offset += btrfs_inode_extref_name_len(eb, extref); - cur_offset += sizeof(*extref); - } - btrfs_tree_read_unlock_blocking(eb); - free_extent_buffer(eb); - - offset++; - } - - btrfs_release_path(path); - - return ret; -} - -static int iterate_irefs(u64 inum, struct btrfs_root *fs_root, - struct btrfs_path *path, iterate_irefs_t *iterate, - void *ctx) -{ - int ret; - int found_refs = 0; - - ret = iterate_inode_refs(inum, fs_root, path, iterate, ctx); - if (!ret) - ++found_refs; - else if (ret != -ENOENT) - return ret; - - ret = iterate_inode_extrefs(inum, fs_root, path, iterate, ctx); - if (ret == -ENOENT && found_refs) - return 0; - - return ret; -} - -/* - * returns 0 if the path could be dumped (probably truncated) - * returns <0 in case of an error - */ -static int inode_to_path(u64 inum, u32 name_len, unsigned long name_off, - struct extent_buffer *eb, void *ctx) -{ - struct inode_fs_paths *ipath = ctx; - char *fspath; - char *fspath_min; - int i = ipath->fspath->elem_cnt; - const int s_ptr = sizeof(char *); - u32 bytes_left; - - bytes_left = ipath->fspath->bytes_left > s_ptr ? - ipath->fspath->bytes_left - s_ptr : 0; - - fspath_min = (char *)ipath->fspath->val + (i + 1) * s_ptr; - fspath = btrfs_ref_to_path(ipath->fs_root, ipath->btrfs_path, name_len, - name_off, eb, inum, fspath_min, bytes_left); - if (IS_ERR(fspath)) - return PTR_ERR(fspath); - - if (fspath > fspath_min) { - ipath->fspath->val[i] = (u64)(unsigned long)fspath; - ++ipath->fspath->elem_cnt; - ipath->fspath->bytes_left = fspath - fspath_min; - } else { - ++ipath->fspath->elem_missed; - ipath->fspath->bytes_missing += fspath_min - fspath; - ipath->fspath->bytes_left = 0; - } - - return 0; -} - -/* - * this dumps all file system paths to the inode into the ipath struct, provided - * is has been created large enough. each path is zero-terminated and accessed - * from ipath->fspath->val[i]. - * when it returns, there are ipath->fspath->elem_cnt number of paths available - * in ipath->fspath->val[]. when the allocated space wasn't sufficient, the - * number of missed paths is recorded in ipath->fspath->elem_missed, otherwise, - * it's zero. ipath->fspath->bytes_missing holds the number of bytes that would - * have been needed to return all paths. - */ -int paths_from_inode(u64 inum, struct inode_fs_paths *ipath) -{ - return iterate_irefs(inum, ipath->fs_root, ipath->btrfs_path, - inode_to_path, ipath); -} - -struct btrfs_data_container *init_data_container(u32 total_bytes) -{ - struct btrfs_data_container *data; - size_t alloc_bytes; - - alloc_bytes = max_t(size_t, total_bytes, sizeof(*data)); - data = vmalloc(alloc_bytes); - if (!data) - return ERR_PTR(-ENOMEM); - - if (total_bytes >= sizeof(*data)) { - data->bytes_left = total_bytes - sizeof(*data); - data->bytes_missing = 0; - } else { - data->bytes_missing = sizeof(*data) - total_bytes; - data->bytes_left = 0; - } - - data->elem_cnt = 0; - data->elem_missed = 0; - - return data; -} - -/* - * allocates space to return multiple file system paths for an inode. - * total_bytes to allocate are passed, note that space usable for actual path - * information will be total_bytes - sizeof(struct inode_fs_paths). - * the returned pointer must be freed with free_ipath() in the end. - */ -struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root, - struct btrfs_path *path) -{ - struct inode_fs_paths *ifp; - struct btrfs_data_container *fspath; - - fspath = init_data_container(total_bytes); - if (IS_ERR(fspath)) - return (void *)fspath; - - ifp = kmalloc(sizeof(*ifp), GFP_NOFS); - if (!ifp) { - vfree(fspath); - return ERR_PTR(-ENOMEM); - } - - ifp->btrfs_path = path; - ifp->fspath = fspath; - ifp->fs_root = fs_root; - - return ifp; -} - -void free_ipath(struct inode_fs_paths *ipath) -{ - if (!ipath) - return; - vfree(ipath->fspath); - kfree(ipath); -} diff --git a/src/linux/fs/btrfs/backref.h b/src/linux/fs/btrfs/backref.h deleted file mode 100644 index 9c41fba..0000000 --- a/src/linux/fs/btrfs/backref.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2011 STRATO. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __BTRFS_BACKREF__ -#define __BTRFS_BACKREF__ - -#include -#include "ulist.h" -#include "extent_io.h" - -struct inode_fs_paths { - struct btrfs_path *btrfs_path; - struct btrfs_root *fs_root; - struct btrfs_data_container *fspath; -}; - -typedef int (iterate_extent_inodes_t)(u64 inum, u64 offset, u64 root, - void *ctx); - -int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical, - struct btrfs_path *path, struct btrfs_key *found_key, - u64 *flags); - -int tree_backref_for_extent(unsigned long *ptr, struct extent_buffer *eb, - struct btrfs_key *key, struct btrfs_extent_item *ei, - u32 item_size, u64 *out_root, u8 *out_level); - -int iterate_extent_inodes(struct btrfs_fs_info *fs_info, - u64 extent_item_objectid, - u64 extent_offset, int search_commit_root, - iterate_extent_inodes_t *iterate, void *ctx); - -int iterate_inodes_from_logical(u64 logical, struct btrfs_fs_info *fs_info, - struct btrfs_path *path, - iterate_extent_inodes_t *iterate, void *ctx); - -int paths_from_inode(u64 inum, struct inode_fs_paths *ipath); - -int btrfs_find_all_roots(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 bytenr, - u64 time_seq, struct ulist **roots); -char *btrfs_ref_to_path(struct btrfs_root *fs_root, struct btrfs_path *path, - u32 name_len, unsigned long name_off, - struct extent_buffer *eb_in, u64 parent, - char *dest, u32 size); - -struct btrfs_data_container *init_data_container(u32 total_bytes); -struct inode_fs_paths *init_ipath(s32 total_bytes, struct btrfs_root *fs_root, - struct btrfs_path *path); -void free_ipath(struct inode_fs_paths *ipath); - -int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid, - u64 start_off, struct btrfs_path *path, - struct btrfs_inode_extref **ret_extref, - u64 *found_off); -int btrfs_check_shared(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 root_objectid, - u64 inum, u64 bytenr); - -int __init btrfs_prelim_ref_init(void); -void btrfs_prelim_ref_exit(void); -#endif diff --git a/src/linux/fs/btrfs/btrfs_inode.h b/src/linux/fs/btrfs/btrfs_inode.h deleted file mode 100644 index 1a8fa46..0000000 --- a/src/linux/fs/btrfs/btrfs_inode.h +++ /dev/null @@ -1,331 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __BTRFS_I__ -#define __BTRFS_I__ - -#include -#include "extent_map.h" -#include "extent_io.h" -#include "ordered-data.h" -#include "delayed-inode.h" - -/* - * ordered_data_close is set by truncate when a file that used - * to have good data has been truncated to zero. When it is set - * the btrfs file release call will add this inode to the - * ordered operations list so that we make sure to flush out any - * new data the application may have written before commit. - */ -#define BTRFS_INODE_ORDERED_DATA_CLOSE 0 -#define BTRFS_INODE_ORPHAN_META_RESERVED 1 -#define BTRFS_INODE_DUMMY 2 -#define BTRFS_INODE_IN_DEFRAG 3 -#define BTRFS_INODE_DELALLOC_META_RESERVED 4 -#define BTRFS_INODE_HAS_ORPHAN_ITEM 5 -#define BTRFS_INODE_HAS_ASYNC_EXTENT 6 -#define BTRFS_INODE_NEEDS_FULL_SYNC 7 -#define BTRFS_INODE_COPY_EVERYTHING 8 -#define BTRFS_INODE_IN_DELALLOC_LIST 9 -#define BTRFS_INODE_READDIO_NEED_LOCK 10 -#define BTRFS_INODE_HAS_PROPS 11 - -/* in memory btrfs inode */ -struct btrfs_inode { - /* which subvolume this inode belongs to */ - struct btrfs_root *root; - - /* key used to find this inode on disk. This is used by the code - * to read in roots of subvolumes - */ - struct btrfs_key location; - - /* - * Lock for counters and all fields used to determine if the inode is in - * the log or not (last_trans, last_sub_trans, last_log_commit, - * logged_trans). - */ - spinlock_t lock; - - /* the extent_tree has caches of all the extent mappings to disk */ - struct extent_map_tree extent_tree; - - /* the io_tree does range state (DIRTY, LOCKED etc) */ - struct extent_io_tree io_tree; - - /* special utility tree used to record which mirrors have already been - * tried when checksums fail for a given block - */ - struct extent_io_tree io_failure_tree; - - /* held while logging the inode in tree-log.c */ - struct mutex log_mutex; - - /* held while doing delalloc reservations */ - struct mutex delalloc_mutex; - - /* used to order data wrt metadata */ - struct btrfs_ordered_inode_tree ordered_tree; - - /* list of all the delalloc inodes in the FS. There are times we need - * to write all the delalloc pages to disk, and this list is used - * to walk them all. - */ - struct list_head delalloc_inodes; - - /* node for the red-black tree that links inodes in subvolume root */ - struct rb_node rb_node; - - unsigned long runtime_flags; - - /* Keep track of who's O_SYNC/fsyncing currently */ - atomic_t sync_writers; - - /* full 64 bit generation number, struct vfs_inode doesn't have a big - * enough field for this. - */ - u64 generation; - - /* - * transid of the trans_handle that last modified this inode - */ - u64 last_trans; - - /* - * transid that last logged this inode - */ - u64 logged_trans; - - /* - * log transid when this inode was last modified - */ - int last_sub_trans; - - /* a local copy of root's last_log_commit */ - int last_log_commit; - - /* total number of bytes pending delalloc, used by stat to calc the - * real block usage of the file - */ - u64 delalloc_bytes; - - /* - * total number of bytes pending defrag, used by stat to check whether - * it needs COW. - */ - u64 defrag_bytes; - - /* - * the size of the file stored in the metadata on disk. data=ordered - * means the in-memory i_size might be larger than the size on disk - * because not all the blocks are written yet. - */ - u64 disk_i_size; - - /* - * if this is a directory then index_cnt is the counter for the index - * number for new files that are created - */ - u64 index_cnt; - - /* Cache the directory index number to speed the dir/file remove */ - u64 dir_index; - - /* the fsync log has some corner cases that mean we have to check - * directories to see if any unlinks have been done before - * the directory was logged. See tree-log.c for all the - * details - */ - u64 last_unlink_trans; - - /* - * Number of bytes outstanding that are going to need csums. This is - * used in ENOSPC accounting. - */ - u64 csum_bytes; - - /* flags field from the on disk inode */ - u32 flags; - - /* - * Counters to keep track of the number of extent item's we may use due - * to delalloc and such. outstanding_extents is the number of extent - * items we think we'll end up using, and reserved_extents is the number - * of extent items we've reserved metadata for. - */ - unsigned outstanding_extents; - unsigned reserved_extents; - - /* - * always compress this one file - */ - unsigned force_compress; - - struct btrfs_delayed_node *delayed_node; - - /* File creation time. */ - struct timespec i_otime; - - /* Hook into fs_info->delayed_iputs */ - struct list_head delayed_iput; - long delayed_iput_count; - - /* - * To avoid races between lockless (i_mutex not held) direct IO writes - * and concurrent fsync requests. Direct IO writes must acquire read - * access on this semaphore for creating an extent map and its - * corresponding ordered extent. The fast fsync path must acquire write - * access on this semaphore before it collects ordered extents and - * extent maps. - */ - struct rw_semaphore dio_sem; - - struct inode vfs_inode; -}; - -extern unsigned char btrfs_filetype_table[]; - -static inline struct btrfs_inode *BTRFS_I(struct inode *inode) -{ - return container_of(inode, struct btrfs_inode, vfs_inode); -} - -static inline unsigned long btrfs_inode_hash(u64 objectid, - const struct btrfs_root *root) -{ - u64 h = objectid ^ (root->objectid * GOLDEN_RATIO_PRIME); - -#if BITS_PER_LONG == 32 - h = (h >> 32) ^ (h & 0xffffffff); -#endif - - return (unsigned long)h; -} - -static inline void btrfs_insert_inode_hash(struct inode *inode) -{ - unsigned long h = btrfs_inode_hash(inode->i_ino, BTRFS_I(inode)->root); - - __insert_inode_hash(inode, h); -} - -static inline u64 btrfs_ino(struct inode *inode) -{ - u64 ino = BTRFS_I(inode)->location.objectid; - - /* - * !ino: btree_inode - * type == BTRFS_ROOT_ITEM_KEY: subvol dir - */ - if (!ino || BTRFS_I(inode)->location.type == BTRFS_ROOT_ITEM_KEY) - ino = inode->i_ino; - return ino; -} - -static inline void btrfs_i_size_write(struct inode *inode, u64 size) -{ - i_size_write(inode, size); - BTRFS_I(inode)->disk_i_size = size; -} - -static inline bool btrfs_is_free_space_inode(struct inode *inode) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - - if (root == root->fs_info->tree_root && - btrfs_ino(inode) != BTRFS_BTREE_INODE_OBJECTID) - return true; - if (BTRFS_I(inode)->location.objectid == BTRFS_FREE_INO_OBJECTID) - return true; - return false; -} - -static inline int btrfs_inode_in_log(struct inode *inode, u64 generation) -{ - int ret = 0; - - spin_lock(&BTRFS_I(inode)->lock); - if (BTRFS_I(inode)->logged_trans == generation && - BTRFS_I(inode)->last_sub_trans <= - BTRFS_I(inode)->last_log_commit && - BTRFS_I(inode)->last_sub_trans <= - BTRFS_I(inode)->root->last_log_commit) { - /* - * After a ranged fsync we might have left some extent maps - * (that fall outside the fsync's range). So return false - * here if the list isn't empty, to make sure btrfs_log_inode() - * will be called and process those extent maps. - */ - smp_mb(); - if (list_empty(&BTRFS_I(inode)->extent_tree.modified_extents)) - ret = 1; - } - spin_unlock(&BTRFS_I(inode)->lock); - return ret; -} - -#define BTRFS_DIO_ORIG_BIO_SUBMITTED 0x1 - -struct btrfs_dio_private { - struct inode *inode; - unsigned long flags; - u64 logical_offset; - u64 disk_bytenr; - u64 bytes; - void *private; - - /* number of bios pending for this dio */ - atomic_t pending_bios; - - /* IO errors */ - int errors; - - /* orig_bio is our btrfs_io_bio */ - struct bio *orig_bio; - - /* dio_bio came from fs/direct-io.c */ - struct bio *dio_bio; - - /* - * The original bio may be split to several sub-bios, this is - * done during endio of sub-bios - */ - int (*subio_endio)(struct inode *, struct btrfs_io_bio *, int); -}; - -/* - * Disable DIO read nolock optimization, so new dio readers will be forced - * to grab i_mutex. It is used to avoid the endless truncate due to - * nonlocked dio read. - */ -static inline void btrfs_inode_block_unlocked_dio(struct inode *inode) -{ - set_bit(BTRFS_INODE_READDIO_NEED_LOCK, &BTRFS_I(inode)->runtime_flags); - smp_mb(); -} - -static inline void btrfs_inode_resume_unlocked_dio(struct inode *inode) -{ - smp_mb__before_atomic(); - clear_bit(BTRFS_INODE_READDIO_NEED_LOCK, - &BTRFS_I(inode)->runtime_flags); -} - -bool btrfs_page_exists_in_range(struct inode *inode, loff_t start, loff_t end); - -#endif diff --git a/src/linux/fs/btrfs/check-integrity.h b/src/linux/fs/btrfs/check-integrity.h deleted file mode 100644 index f78dff1..0000000 --- a/src/linux/fs/btrfs/check-integrity.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) STRATO AG 2011. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#if !defined(__BTRFS_CHECK_INTEGRITY__) -#define __BTRFS_CHECK_INTEGRITY__ - -#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY -int btrfsic_submit_bh(int op, int op_flags, struct buffer_head *bh); -void btrfsic_submit_bio(struct bio *bio); -int btrfsic_submit_bio_wait(struct bio *bio); -#else -#define btrfsic_submit_bh submit_bh -#define btrfsic_submit_bio submit_bio -#define btrfsic_submit_bio_wait submit_bio_wait -#endif - -int btrfsic_mount(struct btrfs_root *root, - struct btrfs_fs_devices *fs_devices, - int including_extent_data, u32 print_mask); -void btrfsic_unmount(struct btrfs_root *root, - struct btrfs_fs_devices *fs_devices); - -#endif diff --git a/src/linux/fs/btrfs/compression.c b/src/linux/fs/btrfs/compression.c deleted file mode 100644 index d4d8b7e..0000000 --- a/src/linux/fs/btrfs/compression.c +++ /dev/null @@ -1,1136 +0,0 @@ -/* - * Copyright (C) 2008 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ctree.h" -#include "disk-io.h" -#include "transaction.h" -#include "btrfs_inode.h" -#include "volumes.h" -#include "ordered-data.h" -#include "compression.h" -#include "extent_io.h" -#include "extent_map.h" - -struct compressed_bio { - /* number of bios pending for this compressed extent */ - atomic_t pending_bios; - - /* the pages with the compressed data on them */ - struct page **compressed_pages; - - /* inode that owns this data */ - struct inode *inode; - - /* starting offset in the inode for our pages */ - u64 start; - - /* number of bytes in the inode we're working on */ - unsigned long len; - - /* number of bytes on disk */ - unsigned long compressed_len; - - /* the compression algorithm for this bio */ - int compress_type; - - /* number of compressed pages in the array */ - unsigned long nr_pages; - - /* IO errors */ - int errors; - int mirror_num; - - /* for reads, this is the bio we are copying the data into */ - struct bio *orig_bio; - - /* - * the start of a variable length array of checksums only - * used by reads - */ - u32 sums; -}; - -static int btrfs_decompress_biovec(int type, struct page **pages_in, - u64 disk_start, struct bio_vec *bvec, - int vcnt, size_t srclen); - -static inline int compressed_bio_size(struct btrfs_root *root, - unsigned long disk_size) -{ - u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); - - return sizeof(struct compressed_bio) + - (DIV_ROUND_UP(disk_size, root->sectorsize)) * csum_size; -} - -static struct bio *compressed_bio_alloc(struct block_device *bdev, - u64 first_byte, gfp_t gfp_flags) -{ - return btrfs_bio_alloc(bdev, first_byte >> 9, BIO_MAX_PAGES, gfp_flags); -} - -static int check_compressed_csum(struct inode *inode, - struct compressed_bio *cb, - u64 disk_start) -{ - int ret; - struct page *page; - unsigned long i; - char *kaddr; - u32 csum; - u32 *cb_sum = &cb->sums; - - if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM) - return 0; - - for (i = 0; i < cb->nr_pages; i++) { - page = cb->compressed_pages[i]; - csum = ~(u32)0; - - kaddr = kmap_atomic(page); - csum = btrfs_csum_data(kaddr, csum, PAGE_SIZE); - btrfs_csum_final(csum, (char *)&csum); - kunmap_atomic(kaddr); - - if (csum != *cb_sum) { - btrfs_info(BTRFS_I(inode)->root->fs_info, - "csum failed ino %llu extent %llu csum %u wanted %u mirror %d", - btrfs_ino(inode), disk_start, csum, *cb_sum, - cb->mirror_num); - ret = -EIO; - goto fail; - } - cb_sum++; - - } - ret = 0; -fail: - return ret; -} - -/* when we finish reading compressed pages from the disk, we - * decompress them and then run the bio end_io routines on the - * decompressed pages (in the inode address space). - * - * This allows the checksumming and other IO error handling routines - * to work normally - * - * The compressed pages are freed here, and it must be run - * in process context - */ -static void end_compressed_bio_read(struct bio *bio) -{ - struct compressed_bio *cb = bio->bi_private; - struct inode *inode; - struct page *page; - unsigned long index; - int ret; - - if (bio->bi_error) - cb->errors = 1; - - /* if there are more bios still pending for this compressed - * extent, just exit - */ - if (!atomic_dec_and_test(&cb->pending_bios)) - goto out; - - inode = cb->inode; - ret = check_compressed_csum(inode, cb, - (u64)bio->bi_iter.bi_sector << 9); - if (ret) - goto csum_failed; - - /* ok, we're the last bio for this extent, lets start - * the decompression. - */ - ret = btrfs_decompress_biovec(cb->compress_type, - cb->compressed_pages, - cb->start, - cb->orig_bio->bi_io_vec, - cb->orig_bio->bi_vcnt, - cb->compressed_len); -csum_failed: - if (ret) - cb->errors = 1; - - /* release the compressed pages */ - index = 0; - for (index = 0; index < cb->nr_pages; index++) { - page = cb->compressed_pages[index]; - page->mapping = NULL; - put_page(page); - } - - /* do io completion on the original bio */ - if (cb->errors) { - bio_io_error(cb->orig_bio); - } else { - int i; - struct bio_vec *bvec; - - /* - * we have verified the checksum already, set page - * checked so the end_io handlers know about it - */ - bio_for_each_segment_all(bvec, cb->orig_bio, i) - SetPageChecked(bvec->bv_page); - - bio_endio(cb->orig_bio); - } - - /* finally free the cb struct */ - kfree(cb->compressed_pages); - kfree(cb); -out: - bio_put(bio); -} - -/* - * Clear the writeback bits on all of the file - * pages for a compressed write - */ -static noinline void end_compressed_writeback(struct inode *inode, - const struct compressed_bio *cb) -{ - unsigned long index = cb->start >> PAGE_SHIFT; - unsigned long end_index = (cb->start + cb->len - 1) >> PAGE_SHIFT; - struct page *pages[16]; - unsigned long nr_pages = end_index - index + 1; - int i; - int ret; - - if (cb->errors) - mapping_set_error(inode->i_mapping, -EIO); - - while (nr_pages > 0) { - ret = find_get_pages_contig(inode->i_mapping, index, - min_t(unsigned long, - nr_pages, ARRAY_SIZE(pages)), pages); - if (ret == 0) { - nr_pages -= 1; - index += 1; - continue; - } - for (i = 0; i < ret; i++) { - if (cb->errors) - SetPageError(pages[i]); - end_page_writeback(pages[i]); - put_page(pages[i]); - } - nr_pages -= ret; - index += ret; - } - /* the inode may be gone now */ -} - -/* - * do the cleanup once all the compressed pages hit the disk. - * This will clear writeback on the file pages and free the compressed - * pages. - * - * This also calls the writeback end hooks for the file pages so that - * metadata and checksums can be updated in the file. - */ -static void end_compressed_bio_write(struct bio *bio) -{ - struct extent_io_tree *tree; - struct compressed_bio *cb = bio->bi_private; - struct inode *inode; - struct page *page; - unsigned long index; - - if (bio->bi_error) - cb->errors = 1; - - /* if there are more bios still pending for this compressed - * extent, just exit - */ - if (!atomic_dec_and_test(&cb->pending_bios)) - goto out; - - /* ok, we're the last bio for this extent, step one is to - * call back into the FS and do all the end_io operations - */ - inode = cb->inode; - tree = &BTRFS_I(inode)->io_tree; - cb->compressed_pages[0]->mapping = cb->inode->i_mapping; - tree->ops->writepage_end_io_hook(cb->compressed_pages[0], - cb->start, - cb->start + cb->len - 1, - NULL, - bio->bi_error ? 0 : 1); - cb->compressed_pages[0]->mapping = NULL; - - end_compressed_writeback(inode, cb); - /* note, our inode could be gone now */ - - /* - * release the compressed pages, these came from alloc_page and - * are not attached to the inode at all - */ - index = 0; - for (index = 0; index < cb->nr_pages; index++) { - page = cb->compressed_pages[index]; - page->mapping = NULL; - put_page(page); - } - - /* finally free the cb struct */ - kfree(cb->compressed_pages); - kfree(cb); -out: - bio_put(bio); -} - -/* - * worker function to build and submit bios for previously compressed pages. - * The corresponding pages in the inode should be marked for writeback - * and the compressed pages should have a reference on them for dropping - * when the IO is complete. - * - * This also checksums the file bytes and gets things ready for - * the end io hooks. - */ -int btrfs_submit_compressed_write(struct inode *inode, u64 start, - unsigned long len, u64 disk_start, - unsigned long compressed_len, - struct page **compressed_pages, - unsigned long nr_pages) -{ - struct bio *bio = NULL; - struct btrfs_root *root = BTRFS_I(inode)->root; - struct compressed_bio *cb; - unsigned long bytes_left; - struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; - int pg_index = 0; - struct page *page; - u64 first_byte = disk_start; - struct block_device *bdev; - int ret; - int skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; - - WARN_ON(start & ((u64)PAGE_SIZE - 1)); - cb = kmalloc(compressed_bio_size(root, compressed_len), GFP_NOFS); - if (!cb) - return -ENOMEM; - atomic_set(&cb->pending_bios, 0); - cb->errors = 0; - cb->inode = inode; - cb->start = start; - cb->len = len; - cb->mirror_num = 0; - cb->compressed_pages = compressed_pages; - cb->compressed_len = compressed_len; - cb->orig_bio = NULL; - cb->nr_pages = nr_pages; - - bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev; - - bio = compressed_bio_alloc(bdev, first_byte, GFP_NOFS); - if (!bio) { - kfree(cb); - return -ENOMEM; - } - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); - bio->bi_private = cb; - bio->bi_end_io = end_compressed_bio_write; - atomic_inc(&cb->pending_bios); - - /* create and submit bios for the compressed pages */ - bytes_left = compressed_len; - for (pg_index = 0; pg_index < cb->nr_pages; pg_index++) { - page = compressed_pages[pg_index]; - page->mapping = inode->i_mapping; - if (bio->bi_iter.bi_size) - ret = io_tree->ops->merge_bio_hook(page, 0, - PAGE_SIZE, - bio, 0); - else - ret = 0; - - page->mapping = NULL; - if (ret || bio_add_page(bio, page, PAGE_SIZE, 0) < - PAGE_SIZE) { - bio_get(bio); - - /* - * inc the count before we submit the bio so - * we know the end IO handler won't happen before - * we inc the count. Otherwise, the cb might get - * freed before we're done setting it up - */ - atomic_inc(&cb->pending_bios); - ret = btrfs_bio_wq_end_io(root->fs_info, bio, - BTRFS_WQ_ENDIO_DATA); - BUG_ON(ret); /* -ENOMEM */ - - if (!skip_sum) { - ret = btrfs_csum_one_bio(root, inode, bio, - start, 1); - BUG_ON(ret); /* -ENOMEM */ - } - - ret = btrfs_map_bio(root, bio, 0, 1); - if (ret) { - bio->bi_error = ret; - bio_endio(bio); - } - - bio_put(bio); - - bio = compressed_bio_alloc(bdev, first_byte, GFP_NOFS); - BUG_ON(!bio); - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); - bio->bi_private = cb; - bio->bi_end_io = end_compressed_bio_write; - bio_add_page(bio, page, PAGE_SIZE, 0); - } - if (bytes_left < PAGE_SIZE) { - btrfs_info(BTRFS_I(inode)->root->fs_info, - "bytes left %lu compress len %lu nr %lu", - bytes_left, cb->compressed_len, cb->nr_pages); - } - bytes_left -= PAGE_SIZE; - first_byte += PAGE_SIZE; - cond_resched(); - } - bio_get(bio); - - ret = btrfs_bio_wq_end_io(root->fs_info, bio, BTRFS_WQ_ENDIO_DATA); - BUG_ON(ret); /* -ENOMEM */ - - if (!skip_sum) { - ret = btrfs_csum_one_bio(root, inode, bio, start, 1); - BUG_ON(ret); /* -ENOMEM */ - } - - ret = btrfs_map_bio(root, bio, 0, 1); - if (ret) { - bio->bi_error = ret; - bio_endio(bio); - } - - bio_put(bio); - return 0; -} - -static noinline int add_ra_bio_pages(struct inode *inode, - u64 compressed_end, - struct compressed_bio *cb) -{ - unsigned long end_index; - unsigned long pg_index; - u64 last_offset; - u64 isize = i_size_read(inode); - int ret; - struct page *page; - unsigned long nr_pages = 0; - struct extent_map *em; - struct address_space *mapping = inode->i_mapping; - struct extent_map_tree *em_tree; - struct extent_io_tree *tree; - u64 end; - int misses = 0; - - page = cb->orig_bio->bi_io_vec[cb->orig_bio->bi_vcnt - 1].bv_page; - last_offset = (page_offset(page) + PAGE_SIZE); - em_tree = &BTRFS_I(inode)->extent_tree; - tree = &BTRFS_I(inode)->io_tree; - - if (isize == 0) - return 0; - - end_index = (i_size_read(inode) - 1) >> PAGE_SHIFT; - - while (last_offset < compressed_end) { - pg_index = last_offset >> PAGE_SHIFT; - - if (pg_index > end_index) - break; - - rcu_read_lock(); - page = radix_tree_lookup(&mapping->page_tree, pg_index); - rcu_read_unlock(); - if (page && !radix_tree_exceptional_entry(page)) { - misses++; - if (misses > 4) - break; - goto next; - } - - page = __page_cache_alloc(mapping_gfp_constraint(mapping, - ~__GFP_FS)); - if (!page) - break; - - if (add_to_page_cache_lru(page, mapping, pg_index, GFP_NOFS)) { - put_page(page); - goto next; - } - - end = last_offset + PAGE_SIZE - 1; - /* - * at this point, we have a locked page in the page cache - * for these bytes in the file. But, we have to make - * sure they map to this compressed extent on disk. - */ - set_page_extent_mapped(page); - lock_extent(tree, last_offset, end); - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, last_offset, - PAGE_SIZE); - read_unlock(&em_tree->lock); - - if (!em || last_offset < em->start || - (last_offset + PAGE_SIZE > extent_map_end(em)) || - (em->block_start >> 9) != cb->orig_bio->bi_iter.bi_sector) { - free_extent_map(em); - unlock_extent(tree, last_offset, end); - unlock_page(page); - put_page(page); - break; - } - free_extent_map(em); - - if (page->index == end_index) { - char *userpage; - size_t zero_offset = isize & (PAGE_SIZE - 1); - - if (zero_offset) { - int zeros; - zeros = PAGE_SIZE - zero_offset; - userpage = kmap_atomic(page); - memset(userpage + zero_offset, 0, zeros); - flush_dcache_page(page); - kunmap_atomic(userpage); - } - } - - ret = bio_add_page(cb->orig_bio, page, - PAGE_SIZE, 0); - - if (ret == PAGE_SIZE) { - nr_pages++; - put_page(page); - } else { - unlock_extent(tree, last_offset, end); - unlock_page(page); - put_page(page); - break; - } -next: - last_offset += PAGE_SIZE; - } - return 0; -} - -/* - * for a compressed read, the bio we get passed has all the inode pages - * in it. We don't actually do IO on those pages but allocate new ones - * to hold the compressed pages on disk. - * - * bio->bi_iter.bi_sector points to the compressed extent on disk - * bio->bi_io_vec points to all of the inode pages - * bio->bi_vcnt is a count of pages - * - * After the compressed pages are read, we copy the bytes into the - * bio we were passed and then call the bio end_io calls - */ -int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, - int mirror_num, unsigned long bio_flags) -{ - struct extent_io_tree *tree; - struct extent_map_tree *em_tree; - struct compressed_bio *cb; - struct btrfs_root *root = BTRFS_I(inode)->root; - unsigned long uncompressed_len = bio->bi_vcnt * PAGE_SIZE; - unsigned long compressed_len; - unsigned long nr_pages; - unsigned long pg_index; - struct page *page; - struct block_device *bdev; - struct bio *comp_bio; - u64 cur_disk_byte = (u64)bio->bi_iter.bi_sector << 9; - u64 em_len; - u64 em_start; - struct extent_map *em; - int ret = -ENOMEM; - int faili = 0; - u32 *sums; - - tree = &BTRFS_I(inode)->io_tree; - em_tree = &BTRFS_I(inode)->extent_tree; - - /* we need the actual starting offset of this extent in the file */ - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, - page_offset(bio->bi_io_vec->bv_page), - PAGE_SIZE); - read_unlock(&em_tree->lock); - if (!em) - return -EIO; - - compressed_len = em->block_len; - cb = kmalloc(compressed_bio_size(root, compressed_len), GFP_NOFS); - if (!cb) - goto out; - - atomic_set(&cb->pending_bios, 0); - cb->errors = 0; - cb->inode = inode; - cb->mirror_num = mirror_num; - sums = &cb->sums; - - cb->start = em->orig_start; - em_len = em->len; - em_start = em->start; - - free_extent_map(em); - em = NULL; - - cb->len = uncompressed_len; - cb->compressed_len = compressed_len; - cb->compress_type = extent_compress_type(bio_flags); - cb->orig_bio = bio; - - nr_pages = DIV_ROUND_UP(compressed_len, PAGE_SIZE); - cb->compressed_pages = kcalloc(nr_pages, sizeof(struct page *), - GFP_NOFS); - if (!cb->compressed_pages) - goto fail1; - - bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev; - - for (pg_index = 0; pg_index < nr_pages; pg_index++) { - cb->compressed_pages[pg_index] = alloc_page(GFP_NOFS | - __GFP_HIGHMEM); - if (!cb->compressed_pages[pg_index]) { - faili = pg_index - 1; - ret = -ENOMEM; - goto fail2; - } - } - faili = nr_pages - 1; - cb->nr_pages = nr_pages; - - add_ra_bio_pages(inode, em_start + em_len, cb); - - /* include any pages we added in add_ra-bio_pages */ - uncompressed_len = bio->bi_vcnt * PAGE_SIZE; - cb->len = uncompressed_len; - - comp_bio = compressed_bio_alloc(bdev, cur_disk_byte, GFP_NOFS); - if (!comp_bio) - goto fail2; - bio_set_op_attrs (comp_bio, REQ_OP_READ, 0); - comp_bio->bi_private = cb; - comp_bio->bi_end_io = end_compressed_bio_read; - atomic_inc(&cb->pending_bios); - - for (pg_index = 0; pg_index < nr_pages; pg_index++) { - page = cb->compressed_pages[pg_index]; - page->mapping = inode->i_mapping; - page->index = em_start >> PAGE_SHIFT; - - if (comp_bio->bi_iter.bi_size) - ret = tree->ops->merge_bio_hook(page, 0, - PAGE_SIZE, - comp_bio, 0); - else - ret = 0; - - page->mapping = NULL; - if (ret || bio_add_page(comp_bio, page, PAGE_SIZE, 0) < - PAGE_SIZE) { - bio_get(comp_bio); - - ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, - BTRFS_WQ_ENDIO_DATA); - BUG_ON(ret); /* -ENOMEM */ - - /* - * inc the count before we submit the bio so - * we know the end IO handler won't happen before - * we inc the count. Otherwise, the cb might get - * freed before we're done setting it up - */ - atomic_inc(&cb->pending_bios); - - if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) { - ret = btrfs_lookup_bio_sums(root, inode, - comp_bio, sums); - BUG_ON(ret); /* -ENOMEM */ - } - sums += DIV_ROUND_UP(comp_bio->bi_iter.bi_size, - root->sectorsize); - - ret = btrfs_map_bio(root, comp_bio, mirror_num, 0); - if (ret) { - comp_bio->bi_error = ret; - bio_endio(comp_bio); - } - - bio_put(comp_bio); - - comp_bio = compressed_bio_alloc(bdev, cur_disk_byte, - GFP_NOFS); - BUG_ON(!comp_bio); - bio_set_op_attrs(comp_bio, REQ_OP_READ, 0); - comp_bio->bi_private = cb; - comp_bio->bi_end_io = end_compressed_bio_read; - - bio_add_page(comp_bio, page, PAGE_SIZE, 0); - } - cur_disk_byte += PAGE_SIZE; - } - bio_get(comp_bio); - - ret = btrfs_bio_wq_end_io(root->fs_info, comp_bio, - BTRFS_WQ_ENDIO_DATA); - BUG_ON(ret); /* -ENOMEM */ - - if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) { - ret = btrfs_lookup_bio_sums(root, inode, comp_bio, sums); - BUG_ON(ret); /* -ENOMEM */ - } - - ret = btrfs_map_bio(root, comp_bio, mirror_num, 0); - if (ret) { - comp_bio->bi_error = ret; - bio_endio(comp_bio); - } - - bio_put(comp_bio); - return 0; - -fail2: - while (faili >= 0) { - __free_page(cb->compressed_pages[faili]); - faili--; - } - - kfree(cb->compressed_pages); -fail1: - kfree(cb); -out: - free_extent_map(em); - return ret; -} - -static struct { - struct list_head idle_ws; - spinlock_t ws_lock; - /* Number of free workspaces */ - int free_ws; - /* Total number of allocated workspaces */ - atomic_t total_ws; - /* Waiters for a free workspace */ - wait_queue_head_t ws_wait; -} btrfs_comp_ws[BTRFS_COMPRESS_TYPES]; - -static const struct btrfs_compress_op * const btrfs_compress_op[] = { - &btrfs_zlib_compress, - &btrfs_lzo_compress, -}; - -void __init btrfs_init_compress(void) -{ - int i; - - for (i = 0; i < BTRFS_COMPRESS_TYPES; i++) { - struct list_head *workspace; - - INIT_LIST_HEAD(&btrfs_comp_ws[i].idle_ws); - spin_lock_init(&btrfs_comp_ws[i].ws_lock); - atomic_set(&btrfs_comp_ws[i].total_ws, 0); - init_waitqueue_head(&btrfs_comp_ws[i].ws_wait); - - /* - * Preallocate one workspace for each compression type so - * we can guarantee forward progress in the worst case - */ - workspace = btrfs_compress_op[i]->alloc_workspace(); - if (IS_ERR(workspace)) { - pr_warn("BTRFS: cannot preallocate compression workspace, will try later\n"); - } else { - atomic_set(&btrfs_comp_ws[i].total_ws, 1); - btrfs_comp_ws[i].free_ws = 1; - list_add(workspace, &btrfs_comp_ws[i].idle_ws); - } - } -} - -/* - * This finds an available workspace or allocates a new one. - * If it's not possible to allocate a new one, waits until there's one. - * Preallocation makes a forward progress guarantees and we do not return - * errors. - */ -static struct list_head *find_workspace(int type) -{ - struct list_head *workspace; - int cpus = num_online_cpus(); - int idx = type - 1; - - struct list_head *idle_ws = &btrfs_comp_ws[idx].idle_ws; - spinlock_t *ws_lock = &btrfs_comp_ws[idx].ws_lock; - atomic_t *total_ws = &btrfs_comp_ws[idx].total_ws; - wait_queue_head_t *ws_wait = &btrfs_comp_ws[idx].ws_wait; - int *free_ws = &btrfs_comp_ws[idx].free_ws; -again: - spin_lock(ws_lock); - if (!list_empty(idle_ws)) { - workspace = idle_ws->next; - list_del(workspace); - (*free_ws)--; - spin_unlock(ws_lock); - return workspace; - - } - if (atomic_read(total_ws) > cpus) { - DEFINE_WAIT(wait); - - spin_unlock(ws_lock); - prepare_to_wait(ws_wait, &wait, TASK_UNINTERRUPTIBLE); - if (atomic_read(total_ws) > cpus && !*free_ws) - schedule(); - finish_wait(ws_wait, &wait); - goto again; - } - atomic_inc(total_ws); - spin_unlock(ws_lock); - - workspace = btrfs_compress_op[idx]->alloc_workspace(); - if (IS_ERR(workspace)) { - atomic_dec(total_ws); - wake_up(ws_wait); - - /* - * Do not return the error but go back to waiting. There's a - * workspace preallocated for each type and the compression - * time is bounded so we get to a workspace eventually. This - * makes our caller's life easier. - * - * To prevent silent and low-probability deadlocks (when the - * initial preallocation fails), check if there are any - * workspaces at all. - */ - if (atomic_read(total_ws) == 0) { - static DEFINE_RATELIMIT_STATE(_rs, - /* once per minute */ 60 * HZ, - /* no burst */ 1); - - if (__ratelimit(&_rs)) { - pr_warn("BTRFS: no compression workspaces, low memory, retrying\n"); - } - } - goto again; - } - return workspace; -} - -/* - * put a workspace struct back on the list or free it if we have enough - * idle ones sitting around - */ -static void free_workspace(int type, struct list_head *workspace) -{ - int idx = type - 1; - struct list_head *idle_ws = &btrfs_comp_ws[idx].idle_ws; - spinlock_t *ws_lock = &btrfs_comp_ws[idx].ws_lock; - atomic_t *total_ws = &btrfs_comp_ws[idx].total_ws; - wait_queue_head_t *ws_wait = &btrfs_comp_ws[idx].ws_wait; - int *free_ws = &btrfs_comp_ws[idx].free_ws; - - spin_lock(ws_lock); - if (*free_ws < num_online_cpus()) { - list_add(workspace, idle_ws); - (*free_ws)++; - spin_unlock(ws_lock); - goto wake; - } - spin_unlock(ws_lock); - - btrfs_compress_op[idx]->free_workspace(workspace); - atomic_dec(total_ws); -wake: - /* - * Make sure counter is updated before we wake up waiters. - */ - smp_mb(); - if (waitqueue_active(ws_wait)) - wake_up(ws_wait); -} - -/* - * cleanup function for module exit - */ -static void free_workspaces(void) -{ - struct list_head *workspace; - int i; - - for (i = 0; i < BTRFS_COMPRESS_TYPES; i++) { - while (!list_empty(&btrfs_comp_ws[i].idle_ws)) { - workspace = btrfs_comp_ws[i].idle_ws.next; - list_del(workspace); - btrfs_compress_op[i]->free_workspace(workspace); - atomic_dec(&btrfs_comp_ws[i].total_ws); - } - } -} - -/* - * given an address space and start/len, compress the bytes. - * - * pages are allocated to hold the compressed result and stored - * in 'pages' - * - * out_pages is used to return the number of pages allocated. There - * may be pages allocated even if we return an error - * - * total_in is used to return the number of bytes actually read. It - * may be smaller then len if we had to exit early because we - * ran out of room in the pages array or because we cross the - * max_out threshold. - * - * total_out is used to return the total number of compressed bytes - * - * max_out tells us the max number of bytes that we're allowed to - * stuff into pages - */ -int btrfs_compress_pages(int type, struct address_space *mapping, - u64 start, unsigned long len, - struct page **pages, - unsigned long nr_dest_pages, - unsigned long *out_pages, - unsigned long *total_in, - unsigned long *total_out, - unsigned long max_out) -{ - struct list_head *workspace; - int ret; - - workspace = find_workspace(type); - - ret = btrfs_compress_op[type-1]->compress_pages(workspace, mapping, - start, len, pages, - nr_dest_pages, out_pages, - total_in, total_out, - max_out); - free_workspace(type, workspace); - return ret; -} - -/* - * pages_in is an array of pages with compressed data. - * - * disk_start is the starting logical offset of this array in the file - * - * bvec is a bio_vec of pages from the file that we want to decompress into - * - * vcnt is the count of pages in the biovec - * - * srclen is the number of bytes in pages_in - * - * The basic idea is that we have a bio that was created by readpages. - * The pages in the bio are for the uncompressed data, and they may not - * be contiguous. They all correspond to the range of bytes covered by - * the compressed extent. - */ -static int btrfs_decompress_biovec(int type, struct page **pages_in, - u64 disk_start, struct bio_vec *bvec, - int vcnt, size_t srclen) -{ - struct list_head *workspace; - int ret; - - workspace = find_workspace(type); - - ret = btrfs_compress_op[type-1]->decompress_biovec(workspace, pages_in, - disk_start, - bvec, vcnt, srclen); - free_workspace(type, workspace); - return ret; -} - -/* - * a less complex decompression routine. Our compressed data fits in a - * single page, and we want to read a single page out of it. - * start_byte tells us the offset into the compressed data we're interested in - */ -int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page, - unsigned long start_byte, size_t srclen, size_t destlen) -{ - struct list_head *workspace; - int ret; - - workspace = find_workspace(type); - - ret = btrfs_compress_op[type-1]->decompress(workspace, data_in, - dest_page, start_byte, - srclen, destlen); - - free_workspace(type, workspace); - return ret; -} - -void btrfs_exit_compress(void) -{ - free_workspaces(); -} - -/* - * Copy uncompressed data from working buffer to pages. - * - * buf_start is the byte offset we're of the start of our workspace buffer. - * - * total_out is the last byte of the buffer - */ -int btrfs_decompress_buf2page(char *buf, unsigned long buf_start, - unsigned long total_out, u64 disk_start, - struct bio_vec *bvec, int vcnt, - unsigned long *pg_index, - unsigned long *pg_offset) -{ - unsigned long buf_offset; - unsigned long current_buf_start; - unsigned long start_byte; - unsigned long working_bytes = total_out - buf_start; - unsigned long bytes; - char *kaddr; - struct page *page_out = bvec[*pg_index].bv_page; - - /* - * start byte is the first byte of the page we're currently - * copying into relative to the start of the compressed data. - */ - start_byte = page_offset(page_out) - disk_start; - - /* we haven't yet hit data corresponding to this page */ - if (total_out <= start_byte) - return 1; - - /* - * the start of the data we care about is offset into - * the middle of our working buffer - */ - if (total_out > start_byte && buf_start < start_byte) { - buf_offset = start_byte - buf_start; - working_bytes -= buf_offset; - } else { - buf_offset = 0; - } - current_buf_start = buf_start; - - /* copy bytes from the working buffer into the pages */ - while (working_bytes > 0) { - bytes = min(PAGE_SIZE - *pg_offset, - PAGE_SIZE - buf_offset); - bytes = min(bytes, working_bytes); - kaddr = kmap_atomic(page_out); - memcpy(kaddr + *pg_offset, buf + buf_offset, bytes); - kunmap_atomic(kaddr); - flush_dcache_page(page_out); - - *pg_offset += bytes; - buf_offset += bytes; - working_bytes -= bytes; - current_buf_start += bytes; - - /* check if we need to pick another page */ - if (*pg_offset == PAGE_SIZE) { - (*pg_index)++; - if (*pg_index >= vcnt) - return 0; - - page_out = bvec[*pg_index].bv_page; - *pg_offset = 0; - start_byte = page_offset(page_out) - disk_start; - - /* - * make sure our new page is covered by this - * working buffer - */ - if (total_out <= start_byte) - return 1; - - /* - * the next page in the biovec might not be adjacent - * to the last page, but it might still be found - * inside this working buffer. bump our offset pointer - */ - if (total_out > start_byte && - current_buf_start < start_byte) { - buf_offset = start_byte - buf_start; - working_bytes = total_out - start_byte; - current_buf_start = buf_start + buf_offset; - } - } - } - - return 1; -} - -/* - * When uncompressing data, we need to make sure and zero any parts of - * the biovec that were not filled in by the decompression code. pg_index - * and pg_offset indicate the last page and the last offset of that page - * that have been filled in. This will zero everything remaining in the - * biovec. - */ -void btrfs_clear_biovec_end(struct bio_vec *bvec, int vcnt, - unsigned long pg_index, - unsigned long pg_offset) -{ - while (pg_index < vcnt) { - struct page *page = bvec[pg_index].bv_page; - unsigned long off = bvec[pg_index].bv_offset; - unsigned long len = bvec[pg_index].bv_len; - - if (pg_offset < off) - pg_offset = off; - if (pg_offset < off + len) { - unsigned long bytes = off + len - pg_offset; - char *kaddr; - - kaddr = kmap_atomic(page); - memset(kaddr + pg_offset, 0, bytes); - kunmap_atomic(kaddr); - } - pg_index++; - pg_offset = 0; - } -} diff --git a/src/linux/fs/btrfs/compression.h b/src/linux/fs/btrfs/compression.h deleted file mode 100644 index f49d8b8..0000000 --- a/src/linux/fs/btrfs/compression.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2008 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __BTRFS_COMPRESSION_ -#define __BTRFS_COMPRESSION_ - -void btrfs_init_compress(void); -void btrfs_exit_compress(void); - -int btrfs_compress_pages(int type, struct address_space *mapping, - u64 start, unsigned long len, - struct page **pages, - unsigned long nr_dest_pages, - unsigned long *out_pages, - unsigned long *total_in, - unsigned long *total_out, - unsigned long max_out); -int btrfs_decompress(int type, unsigned char *data_in, struct page *dest_page, - unsigned long start_byte, size_t srclen, size_t destlen); -int btrfs_decompress_buf2page(char *buf, unsigned long buf_start, - unsigned long total_out, u64 disk_start, - struct bio_vec *bvec, int vcnt, - unsigned long *pg_index, - unsigned long *pg_offset); - -int btrfs_submit_compressed_write(struct inode *inode, u64 start, - unsigned long len, u64 disk_start, - unsigned long compressed_len, - struct page **compressed_pages, - unsigned long nr_pages); -int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio, - int mirror_num, unsigned long bio_flags); -void btrfs_clear_biovec_end(struct bio_vec *bvec, int vcnt, - unsigned long pg_index, - unsigned long pg_offset); - -enum btrfs_compression_type { - BTRFS_COMPRESS_NONE = 0, - BTRFS_COMPRESS_ZLIB = 1, - BTRFS_COMPRESS_LZO = 2, - BTRFS_COMPRESS_TYPES = 2, - BTRFS_COMPRESS_LAST = 3, -}; - -struct btrfs_compress_op { - struct list_head *(*alloc_workspace)(void); - - void (*free_workspace)(struct list_head *workspace); - - int (*compress_pages)(struct list_head *workspace, - struct address_space *mapping, - u64 start, unsigned long len, - struct page **pages, - unsigned long nr_dest_pages, - unsigned long *out_pages, - unsigned long *total_in, - unsigned long *total_out, - unsigned long max_out); - - int (*decompress_biovec)(struct list_head *workspace, - struct page **pages_in, - u64 disk_start, - struct bio_vec *bvec, - int vcnt, - size_t srclen); - - int (*decompress)(struct list_head *workspace, - unsigned char *data_in, - struct page *dest_page, - unsigned long start_byte, - size_t srclen, size_t destlen); -}; - -extern const struct btrfs_compress_op btrfs_zlib_compress; -extern const struct btrfs_compress_op btrfs_lzo_compress; - -#endif diff --git a/src/linux/fs/btrfs/ctree.c b/src/linux/fs/btrfs/ctree.c deleted file mode 100644 index f6ba165..0000000 --- a/src/linux/fs/btrfs/ctree.c +++ /dev/null @@ -1,5941 +0,0 @@ -/* - * Copyright (C) 2007,2008 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include "ctree.h" -#include "disk-io.h" -#include "transaction.h" -#include "print-tree.h" -#include "locking.h" - -static int split_node(struct btrfs_trans_handle *trans, struct btrfs_root - *root, struct btrfs_path *path, int level); -static int split_leaf(struct btrfs_trans_handle *trans, struct btrfs_root - *root, struct btrfs_key *ins_key, - struct btrfs_path *path, int data_size, int extend); -static int push_node_left(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct extent_buffer *dst, - struct extent_buffer *src, int empty); -static int balance_node_right(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct extent_buffer *dst_buf, - struct extent_buffer *src_buf); -static void del_ptr(struct btrfs_root *root, struct btrfs_path *path, - int level, int slot); -static int tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, - struct extent_buffer *eb); - -struct btrfs_path *btrfs_alloc_path(void) -{ - return kmem_cache_zalloc(btrfs_path_cachep, GFP_NOFS); -} - -/* - * set all locked nodes in the path to blocking locks. This should - * be done before scheduling - */ -noinline void btrfs_set_path_blocking(struct btrfs_path *p) -{ - int i; - for (i = 0; i < BTRFS_MAX_LEVEL; i++) { - if (!p->nodes[i] || !p->locks[i]) - continue; - btrfs_set_lock_blocking_rw(p->nodes[i], p->locks[i]); - if (p->locks[i] == BTRFS_READ_LOCK) - p->locks[i] = BTRFS_READ_LOCK_BLOCKING; - else if (p->locks[i] == BTRFS_WRITE_LOCK) - p->locks[i] = BTRFS_WRITE_LOCK_BLOCKING; - } -} - -/* - * reset all the locked nodes in the patch to spinning locks. - * - * held is used to keep lockdep happy, when lockdep is enabled - * we set held to a blocking lock before we go around and - * retake all the spinlocks in the path. You can safely use NULL - * for held - */ -noinline void btrfs_clear_path_blocking(struct btrfs_path *p, - struct extent_buffer *held, int held_rw) -{ - int i; - - if (held) { - btrfs_set_lock_blocking_rw(held, held_rw); - if (held_rw == BTRFS_WRITE_LOCK) - held_rw = BTRFS_WRITE_LOCK_BLOCKING; - else if (held_rw == BTRFS_READ_LOCK) - held_rw = BTRFS_READ_LOCK_BLOCKING; - } - btrfs_set_path_blocking(p); - - for (i = BTRFS_MAX_LEVEL - 1; i >= 0; i--) { - if (p->nodes[i] && p->locks[i]) { - btrfs_clear_lock_blocking_rw(p->nodes[i], p->locks[i]); - if (p->locks[i] == BTRFS_WRITE_LOCK_BLOCKING) - p->locks[i] = BTRFS_WRITE_LOCK; - else if (p->locks[i] == BTRFS_READ_LOCK_BLOCKING) - p->locks[i] = BTRFS_READ_LOCK; - } - } - - if (held) - btrfs_clear_lock_blocking_rw(held, held_rw); -} - -/* this also releases the path */ -void btrfs_free_path(struct btrfs_path *p) -{ - if (!p) - return; - btrfs_release_path(p); - kmem_cache_free(btrfs_path_cachep, p); -} - -/* - * path release drops references on the extent buffers in the path - * and it drops any locks held by this path - * - * It is safe to call this on paths that no locks or extent buffers held. - */ -noinline void btrfs_release_path(struct btrfs_path *p) -{ - int i; - - for (i = 0; i < BTRFS_MAX_LEVEL; i++) { - p->slots[i] = 0; - if (!p->nodes[i]) - continue; - if (p->locks[i]) { - btrfs_tree_unlock_rw(p->nodes[i], p->locks[i]); - p->locks[i] = 0; - } - free_extent_buffer(p->nodes[i]); - p->nodes[i] = NULL; - } -} - -/* - * safely gets a reference on the root node of a tree. A lock - * is not taken, so a concurrent writer may put a different node - * at the root of the tree. See btrfs_lock_root_node for the - * looping required. - * - * The extent buffer returned by this has a reference taken, so - * it won't disappear. It may stop being the root of the tree - * at any time because there are no locks held. - */ -struct extent_buffer *btrfs_root_node(struct btrfs_root *root) -{ - struct extent_buffer *eb; - - while (1) { - rcu_read_lock(); - eb = rcu_dereference(root->node); - - /* - * RCU really hurts here, we could free up the root node because - * it was COWed but we may not get the new root node yet so do - * the inc_not_zero dance and if it doesn't work then - * synchronize_rcu and try again. - */ - if (atomic_inc_not_zero(&eb->refs)) { - rcu_read_unlock(); - break; - } - rcu_read_unlock(); - synchronize_rcu(); - } - return eb; -} - -/* loop around taking references on and locking the root node of the - * tree until you end up with a lock on the root. A locked buffer - * is returned, with a reference held. - */ -struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root) -{ - struct extent_buffer *eb; - - while (1) { - eb = btrfs_root_node(root); - btrfs_tree_lock(eb); - if (eb == root->node) - break; - btrfs_tree_unlock(eb); - free_extent_buffer(eb); - } - return eb; -} - -/* loop around taking references on and locking the root node of the - * tree until you end up with a lock on the root. A locked buffer - * is returned, with a reference held. - */ -static struct extent_buffer *btrfs_read_lock_root_node(struct btrfs_root *root) -{ - struct extent_buffer *eb; - - while (1) { - eb = btrfs_root_node(root); - btrfs_tree_read_lock(eb); - if (eb == root->node) - break; - btrfs_tree_read_unlock(eb); - free_extent_buffer(eb); - } - return eb; -} - -/* cowonly root (everything not a reference counted cow subvolume), just get - * put onto a simple dirty list. transaction.c walks this to make sure they - * get properly updated on disk. - */ -static void add_root_to_dirty_list(struct btrfs_root *root) -{ - if (test_bit(BTRFS_ROOT_DIRTY, &root->state) || - !test_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state)) - return; - - spin_lock(&root->fs_info->trans_lock); - if (!test_and_set_bit(BTRFS_ROOT_DIRTY, &root->state)) { - /* Want the extent tree to be the last on the list */ - if (root->objectid == BTRFS_EXTENT_TREE_OBJECTID) - list_move_tail(&root->dirty_list, - &root->fs_info->dirty_cowonly_roots); - else - list_move(&root->dirty_list, - &root->fs_info->dirty_cowonly_roots); - } - spin_unlock(&root->fs_info->trans_lock); -} - -/* - * used by snapshot creation to make a copy of a root for a tree with - * a given objectid. The buffer with the new root node is returned in - * cow_ret, and this func returns zero on success or a negative error code. - */ -int btrfs_copy_root(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct extent_buffer *buf, - struct extent_buffer **cow_ret, u64 new_root_objectid) -{ - struct extent_buffer *cow; - int ret = 0; - int level; - struct btrfs_disk_key disk_key; - - WARN_ON(test_bit(BTRFS_ROOT_REF_COWS, &root->state) && - trans->transid != root->fs_info->running_transaction->transid); - WARN_ON(test_bit(BTRFS_ROOT_REF_COWS, &root->state) && - trans->transid != root->last_trans); - - level = btrfs_header_level(buf); - if (level == 0) - btrfs_item_key(buf, &disk_key, 0); - else - btrfs_node_key(buf, &disk_key, 0); - - cow = btrfs_alloc_tree_block(trans, root, 0, new_root_objectid, - &disk_key, level, buf->start, 0); - if (IS_ERR(cow)) - return PTR_ERR(cow); - - copy_extent_buffer(cow, buf, 0, 0, cow->len); - btrfs_set_header_bytenr(cow, cow->start); - btrfs_set_header_generation(cow, trans->transid); - btrfs_set_header_backref_rev(cow, BTRFS_MIXED_BACKREF_REV); - btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN | - BTRFS_HEADER_FLAG_RELOC); - if (new_root_objectid == BTRFS_TREE_RELOC_OBJECTID) - btrfs_set_header_flag(cow, BTRFS_HEADER_FLAG_RELOC); - else - btrfs_set_header_owner(cow, new_root_objectid); - - write_extent_buffer(cow, root->fs_info->fsid, btrfs_header_fsid(), - BTRFS_FSID_SIZE); - - WARN_ON(btrfs_header_generation(buf) > trans->transid); - if (new_root_objectid == BTRFS_TREE_RELOC_OBJECTID) - ret = btrfs_inc_ref(trans, root, cow, 1); - else - ret = btrfs_inc_ref(trans, root, cow, 0); - - if (ret) - return ret; - - btrfs_mark_buffer_dirty(cow); - *cow_ret = cow; - return 0; -} - -enum mod_log_op { - MOD_LOG_KEY_REPLACE, - MOD_LOG_KEY_ADD, - MOD_LOG_KEY_REMOVE, - MOD_LOG_KEY_REMOVE_WHILE_FREEING, - MOD_LOG_KEY_REMOVE_WHILE_MOVING, - MOD_LOG_MOVE_KEYS, - MOD_LOG_ROOT_REPLACE, -}; - -struct tree_mod_move { - int dst_slot; - int nr_items; -}; - -struct tree_mod_root { - u64 logical; - u8 level; -}; - -struct tree_mod_elem { - struct rb_node node; - u64 logical; - u64 seq; - enum mod_log_op op; - - /* this is used for MOD_LOG_KEY_* and MOD_LOG_MOVE_KEYS operations */ - int slot; - - /* this is used for MOD_LOG_KEY* and MOD_LOG_ROOT_REPLACE */ - u64 generation; - - /* those are used for op == MOD_LOG_KEY_{REPLACE,REMOVE} */ - struct btrfs_disk_key key; - u64 blockptr; - - /* this is used for op == MOD_LOG_MOVE_KEYS */ - struct tree_mod_move move; - - /* this is used for op == MOD_LOG_ROOT_REPLACE */ - struct tree_mod_root old_root; -}; - -static inline void tree_mod_log_read_lock(struct btrfs_fs_info *fs_info) -{ - read_lock(&fs_info->tree_mod_log_lock); -} - -static inline void tree_mod_log_read_unlock(struct btrfs_fs_info *fs_info) -{ - read_unlock(&fs_info->tree_mod_log_lock); -} - -static inline void tree_mod_log_write_lock(struct btrfs_fs_info *fs_info) -{ - write_lock(&fs_info->tree_mod_log_lock); -} - -static inline void tree_mod_log_write_unlock(struct btrfs_fs_info *fs_info) -{ - write_unlock(&fs_info->tree_mod_log_lock); -} - -/* - * Pull a new tree mod seq number for our operation. - */ -static inline u64 btrfs_inc_tree_mod_seq(struct btrfs_fs_info *fs_info) -{ - return atomic64_inc_return(&fs_info->tree_mod_seq); -} - -/* - * This adds a new blocker to the tree mod log's blocker list if the @elem - * passed does not already have a sequence number set. So when a caller expects - * to record tree modifications, it should ensure to set elem->seq to zero - * before calling btrfs_get_tree_mod_seq. - * Returns a fresh, unused tree log modification sequence number, even if no new - * blocker was added. - */ -u64 btrfs_get_tree_mod_seq(struct btrfs_fs_info *fs_info, - struct seq_list *elem) -{ - tree_mod_log_write_lock(fs_info); - spin_lock(&fs_info->tree_mod_seq_lock); - if (!elem->seq) { - elem->seq = btrfs_inc_tree_mod_seq(fs_info); - list_add_tail(&elem->list, &fs_info->tree_mod_seq_list); - } - spin_unlock(&fs_info->tree_mod_seq_lock); - tree_mod_log_write_unlock(fs_info); - - return elem->seq; -} - -void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info, - struct seq_list *elem) -{ - struct rb_root *tm_root; - struct rb_node *node; - struct rb_node *next; - struct seq_list *cur_elem; - struct tree_mod_elem *tm; - u64 min_seq = (u64)-1; - u64 seq_putting = elem->seq; - - if (!seq_putting) - return; - - spin_lock(&fs_info->tree_mod_seq_lock); - list_del(&elem->list); - elem->seq = 0; - - list_for_each_entry(cur_elem, &fs_info->tree_mod_seq_list, list) { - if (cur_elem->seq < min_seq) { - if (seq_putting > cur_elem->seq) { - /* - * blocker with lower sequence number exists, we - * cannot remove anything from the log - */ - spin_unlock(&fs_info->tree_mod_seq_lock); - return; - } - min_seq = cur_elem->seq; - } - } - spin_unlock(&fs_info->tree_mod_seq_lock); - - /* - * anything that's lower than the lowest existing (read: blocked) - * sequence number can be removed from the tree. - */ - tree_mod_log_write_lock(fs_info); - tm_root = &fs_info->tree_mod_log; - for (node = rb_first(tm_root); node; node = next) { - next = rb_next(node); - tm = container_of(node, struct tree_mod_elem, node); - if (tm->seq > min_seq) - continue; - rb_erase(node, tm_root); - kfree(tm); - } - tree_mod_log_write_unlock(fs_info); -} - -/* - * key order of the log: - * node/leaf start address -> sequence - * - * The 'start address' is the logical address of the *new* root node - * for root replace operations, or the logical address of the affected - * block for all other operations. - * - * Note: must be called with write lock (tree_mod_log_write_lock). - */ -static noinline int -__tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm) -{ - struct rb_root *tm_root; - struct rb_node **new; - struct rb_node *parent = NULL; - struct tree_mod_elem *cur; - - BUG_ON(!tm); - - tm->seq = btrfs_inc_tree_mod_seq(fs_info); - - tm_root = &fs_info->tree_mod_log; - new = &tm_root->rb_node; - while (*new) { - cur = container_of(*new, struct tree_mod_elem, node); - parent = *new; - if (cur->logical < tm->logical) - new = &((*new)->rb_left); - else if (cur->logical > tm->logical) - new = &((*new)->rb_right); - else if (cur->seq < tm->seq) - new = &((*new)->rb_left); - else if (cur->seq > tm->seq) - new = &((*new)->rb_right); - else - return -EEXIST; - } - - rb_link_node(&tm->node, parent, new); - rb_insert_color(&tm->node, tm_root); - return 0; -} - -/* - * Determines if logging can be omitted. Returns 1 if it can. Otherwise, it - * returns zero with the tree_mod_log_lock acquired. The caller must hold - * this until all tree mod log insertions are recorded in the rb tree and then - * call tree_mod_log_write_unlock() to release. - */ -static inline int tree_mod_dont_log(struct btrfs_fs_info *fs_info, - struct extent_buffer *eb) { - smp_mb(); - if (list_empty(&(fs_info)->tree_mod_seq_list)) - return 1; - if (eb && btrfs_header_level(eb) == 0) - return 1; - - tree_mod_log_write_lock(fs_info); - if (list_empty(&(fs_info)->tree_mod_seq_list)) { - tree_mod_log_write_unlock(fs_info); - return 1; - } - - return 0; -} - -/* Similar to tree_mod_dont_log, but doesn't acquire any locks. */ -static inline int tree_mod_need_log(const struct btrfs_fs_info *fs_info, - struct extent_buffer *eb) -{ - smp_mb(); - if (list_empty(&(fs_info)->tree_mod_seq_list)) - return 0; - if (eb && btrfs_header_level(eb) == 0) - return 0; - - return 1; -} - -static struct tree_mod_elem * -alloc_tree_mod_elem(struct extent_buffer *eb, int slot, - enum mod_log_op op, gfp_t flags) -{ - struct tree_mod_elem *tm; - - tm = kzalloc(sizeof(*tm), flags); - if (!tm) - return NULL; - - tm->logical = eb->start; - if (op != MOD_LOG_KEY_ADD) { - btrfs_node_key(eb, &tm->key, slot); - tm->blockptr = btrfs_node_blockptr(eb, slot); - } - tm->op = op; - tm->slot = slot; - tm->generation = btrfs_node_ptr_generation(eb, slot); - RB_CLEAR_NODE(&tm->node); - - return tm; -} - -static noinline int -tree_mod_log_insert_key(struct btrfs_fs_info *fs_info, - struct extent_buffer *eb, int slot, - enum mod_log_op op, gfp_t flags) -{ - struct tree_mod_elem *tm; - int ret; - - if (!tree_mod_need_log(fs_info, eb)) - return 0; - - tm = alloc_tree_mod_elem(eb, slot, op, flags); - if (!tm) - return -ENOMEM; - - if (tree_mod_dont_log(fs_info, eb)) { - kfree(tm); - return 0; - } - - ret = __tree_mod_log_insert(fs_info, tm); - tree_mod_log_write_unlock(fs_info); - if (ret) - kfree(tm); - - return ret; -} - -static noinline int -tree_mod_log_insert_move(struct btrfs_fs_info *fs_info, - struct extent_buffer *eb, int dst_slot, int src_slot, - int nr_items, gfp_t flags) -{ - struct tree_mod_elem *tm = NULL; - struct tree_mod_elem **tm_list = NULL; - int ret = 0; - int i; - int locked = 0; - - if (!tree_mod_need_log(fs_info, eb)) - return 0; - - tm_list = kcalloc(nr_items, sizeof(struct tree_mod_elem *), flags); - if (!tm_list) - return -ENOMEM; - - tm = kzalloc(sizeof(*tm), flags); - if (!tm) { - ret = -ENOMEM; - goto free_tms; - } - - tm->logical = eb->start; - tm->slot = src_slot; - tm->move.dst_slot = dst_slot; - tm->move.nr_items = nr_items; - tm->op = MOD_LOG_MOVE_KEYS; - - for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) { - tm_list[i] = alloc_tree_mod_elem(eb, i + dst_slot, - MOD_LOG_KEY_REMOVE_WHILE_MOVING, flags); - if (!tm_list[i]) { - ret = -ENOMEM; - goto free_tms; - } - } - - if (tree_mod_dont_log(fs_info, eb)) - goto free_tms; - locked = 1; - - /* - * When we override something during the move, we log these removals. - * This can only happen when we move towards the beginning of the - * buffer, i.e. dst_slot < src_slot. - */ - for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) { - ret = __tree_mod_log_insert(fs_info, tm_list[i]); - if (ret) - goto free_tms; - } - - ret = __tree_mod_log_insert(fs_info, tm); - if (ret) - goto free_tms; - tree_mod_log_write_unlock(fs_info); - kfree(tm_list); - - return 0; -free_tms: - for (i = 0; i < nr_items; i++) { - if (tm_list[i] && !RB_EMPTY_NODE(&tm_list[i]->node)) - rb_erase(&tm_list[i]->node, &fs_info->tree_mod_log); - kfree(tm_list[i]); - } - if (locked) - tree_mod_log_write_unlock(fs_info); - kfree(tm_list); - kfree(tm); - - return ret; -} - -static inline int -__tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, - struct tree_mod_elem **tm_list, - int nritems) -{ - int i, j; - int ret; - - for (i = nritems - 1; i >= 0; i--) { - ret = __tree_mod_log_insert(fs_info, tm_list[i]); - if (ret) { - for (j = nritems - 1; j > i; j--) - rb_erase(&tm_list[j]->node, - &fs_info->tree_mod_log); - return ret; - } - } - - return 0; -} - -static noinline int -tree_mod_log_insert_root(struct btrfs_fs_info *fs_info, - struct extent_buffer *old_root, - struct extent_buffer *new_root, gfp_t flags, - int log_removal) -{ - struct tree_mod_elem *tm = NULL; - struct tree_mod_elem **tm_list = NULL; - int nritems = 0; - int ret = 0; - int i; - - if (!tree_mod_need_log(fs_info, NULL)) - return 0; - - if (log_removal && btrfs_header_level(old_root) > 0) { - nritems = btrfs_header_nritems(old_root); - tm_list = kcalloc(nritems, sizeof(struct tree_mod_elem *), - flags); - if (!tm_list) { - ret = -ENOMEM; - goto free_tms; - } - for (i = 0; i < nritems; i++) { - tm_list[i] = alloc_tree_mod_elem(old_root, i, - MOD_LOG_KEY_REMOVE_WHILE_FREEING, flags); - if (!tm_list[i]) { - ret = -ENOMEM; - goto free_tms; - } - } - } - - tm = kzalloc(sizeof(*tm), flags); - if (!tm) { - ret = -ENOMEM; - goto free_tms; - } - - tm->logical = new_root->start; - tm->old_root.logical = old_root->start; - tm->old_root.level = btrfs_header_level(old_root); - tm->generation = btrfs_header_generation(old_root); - tm->op = MOD_LOG_ROOT_REPLACE; - - if (tree_mod_dont_log(fs_info, NULL)) - goto free_tms; - - if (tm_list) - ret = __tree_mod_log_free_eb(fs_info, tm_list, nritems); - if (!ret) - ret = __tree_mod_log_insert(fs_info, tm); - - tree_mod_log_write_unlock(fs_info); - if (ret) - goto free_tms; - kfree(tm_list); - - return ret; - -free_tms: - if (tm_list) { - for (i = 0; i < nritems; i++) - kfree(tm_list[i]); - kfree(tm_list); - } - kfree(tm); - - return ret; -} - -static struct tree_mod_elem * -__tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq, - int smallest) -{ - struct rb_root *tm_root; - struct rb_node *node; - struct tree_mod_elem *cur = NULL; - struct tree_mod_elem *found = NULL; - - tree_mod_log_read_lock(fs_info); - tm_root = &fs_info->tree_mod_log; - node = tm_root->rb_node; - while (node) { - cur = container_of(node, struct tree_mod_elem, node); - if (cur->logical < start) { - node = node->rb_left; - } else if (cur->logical > start) { - node = node->rb_right; - } else if (cur->seq < min_seq) { - node = node->rb_left; - } else if (!smallest) { - /* we want the node with the highest seq */ - if (found) - BUG_ON(found->seq > cur->seq); - found = cur; - node = node->rb_left; - } else if (cur->seq > min_seq) { - /* we want the node with the smallest seq */ - if (found) - BUG_ON(found->seq < cur->seq); - found = cur; - node = node->rb_right; - } else { - found = cur; - break; - } - } - tree_mod_log_read_unlock(fs_info); - - return found; -} - -/* - * this returns the element from the log with the smallest time sequence - * value that's in the log (the oldest log item). any element with a time - * sequence lower than min_seq will be ignored. - */ -static struct tree_mod_elem * -tree_mod_log_search_oldest(struct btrfs_fs_info *fs_info, u64 start, - u64 min_seq) -{ - return __tree_mod_log_search(fs_info, start, min_seq, 1); -} - -/* - * this returns the element from the log with the largest time sequence - * value that's in the log (the most recent log item). any element with - * a time sequence lower than min_seq will be ignored. - */ -static struct tree_mod_elem * -tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq) -{ - return __tree_mod_log_search(fs_info, start, min_seq, 0); -} - -static noinline int -tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst, - struct extent_buffer *src, unsigned long dst_offset, - unsigned long src_offset, int nr_items) -{ - int ret = 0; - struct tree_mod_elem **tm_list = NULL; - struct tree_mod_elem **tm_list_add, **tm_list_rem; - int i; - int locked = 0; - - if (!tree_mod_need_log(fs_info, NULL)) - return 0; - - if (btrfs_header_level(dst) == 0 && btrfs_header_level(src) == 0) - return 0; - - tm_list = kcalloc(nr_items * 2, sizeof(struct tree_mod_elem *), - GFP_NOFS); - if (!tm_list) - return -ENOMEM; - - tm_list_add = tm_list; - tm_list_rem = tm_list + nr_items; - for (i = 0; i < nr_items; i++) { - tm_list_rem[i] = alloc_tree_mod_elem(src, i + src_offset, - MOD_LOG_KEY_REMOVE, GFP_NOFS); - if (!tm_list_rem[i]) { - ret = -ENOMEM; - goto free_tms; - } - - tm_list_add[i] = alloc_tree_mod_elem(dst, i + dst_offset, - MOD_LOG_KEY_ADD, GFP_NOFS); - if (!tm_list_add[i]) { - ret = -ENOMEM; - goto free_tms; - } - } - - if (tree_mod_dont_log(fs_info, NULL)) - goto free_tms; - locked = 1; - - for (i = 0; i < nr_items; i++) { - ret = __tree_mod_log_insert(fs_info, tm_list_rem[i]); - if (ret) - goto free_tms; - ret = __tree_mod_log_insert(fs_info, tm_list_add[i]); - if (ret) - goto free_tms; - } - - tree_mod_log_write_unlock(fs_info); - kfree(tm_list); - - return 0; - -free_tms: - for (i = 0; i < nr_items * 2; i++) { - if (tm_list[i] && !RB_EMPTY_NODE(&tm_list[i]->node)) - rb_erase(&tm_list[i]->node, &fs_info->tree_mod_log); - kfree(tm_list[i]); - } - if (locked) - tree_mod_log_write_unlock(fs_info); - kfree(tm_list); - - return ret; -} - -static inline void -tree_mod_log_eb_move(struct btrfs_fs_info *fs_info, struct extent_buffer *dst, - int dst_offset, int src_offset, int nr_items) -{ - int ret; - ret = tree_mod_log_insert_move(fs_info, dst, dst_offset, src_offset, - nr_items, GFP_NOFS); - BUG_ON(ret < 0); -} - -static noinline void -tree_mod_log_set_node_key(struct btrfs_fs_info *fs_info, - struct extent_buffer *eb, int slot, int atomic) -{ - int ret; - - ret = tree_mod_log_insert_key(fs_info, eb, slot, - MOD_LOG_KEY_REPLACE, - atomic ? GFP_ATOMIC : GFP_NOFS); - BUG_ON(ret < 0); -} - -static noinline int -tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb) -{ - struct tree_mod_elem **tm_list = NULL; - int nritems = 0; - int i; - int ret = 0; - - if (btrfs_header_level(eb) == 0) - return 0; - - if (!tree_mod_need_log(fs_info, NULL)) - return 0; - - nritems = btrfs_header_nritems(eb); - tm_list = kcalloc(nritems, sizeof(struct tree_mod_elem *), GFP_NOFS); - if (!tm_list) - return -ENOMEM; - - for (i = 0; i < nritems; i++) { - tm_list[i] = alloc_tree_mod_elem(eb, i, - MOD_LOG_KEY_REMOVE_WHILE_FREEING, GFP_NOFS); - if (!tm_list[i]) { - ret = -ENOMEM; - goto free_tms; - } - } - - if (tree_mod_dont_log(fs_info, eb)) - goto free_tms; - - ret = __tree_mod_log_free_eb(fs_info, tm_list, nritems); - tree_mod_log_write_unlock(fs_info); - if (ret) - goto free_tms; - kfree(tm_list); - - return 0; - -free_tms: - for (i = 0; i < nritems; i++) - kfree(tm_list[i]); - kfree(tm_list); - - return ret; -} - -static noinline void -tree_mod_log_set_root_pointer(struct btrfs_root *root, - struct extent_buffer *new_root_node, - int log_removal) -{ - int ret; - ret = tree_mod_log_insert_root(root->fs_info, root->node, - new_root_node, GFP_NOFS, log_removal); - BUG_ON(ret < 0); -} - -/* - * check if the tree block can be shared by multiple trees - */ -int btrfs_block_can_be_shared(struct btrfs_root *root, - struct extent_buffer *buf) -{ - /* - * Tree blocks not in reference counted trees and tree roots - * are never shared. If a block was allocated after the last - * snapshot and the block was not allocated by tree relocation, - * we know the block is not shared. - */ - if (test_bit(BTRFS_ROOT_REF_COWS, &root->state) && - buf != root->node && buf != root->commit_root && - (btrfs_header_generation(buf) <= - btrfs_root_last_snapshot(&root->root_item) || - btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC))) - return 1; -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (test_bit(BTRFS_ROOT_REF_COWS, &root->state) && - btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV) - return 1; -#endif - return 0; -} - -static noinline int update_ref_for_cow(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct extent_buffer *buf, - struct extent_buffer *cow, - int *last_ref) -{ - u64 refs; - u64 owner; - u64 flags; - u64 new_flags = 0; - int ret; - - /* - * Backrefs update rules: - * - * Always use full backrefs for extent pointers in tree block - * allocated by tree relocation. - * - * If a shared tree block is no longer referenced by its owner - * tree (btrfs_header_owner(buf) == root->root_key.objectid), - * use full backrefs for extent pointers in tree block. - * - * If a tree block is been relocating - * (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID), - * use full backrefs for extent pointers in tree block. - * The reason for this is some operations (such as drop tree) - * are only allowed for blocks use full backrefs. - */ - - if (btrfs_block_can_be_shared(root, buf)) { - ret = btrfs_lookup_extent_info(trans, root, buf->start, - btrfs_header_level(buf), 1, - &refs, &flags); - if (ret) - return ret; - if (refs == 0) { - ret = -EROFS; - btrfs_handle_fs_error(root->fs_info, ret, NULL); - return ret; - } - } else { - refs = 1; - if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID || - btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV) - flags = BTRFS_BLOCK_FLAG_FULL_BACKREF; - else - flags = 0; - } - - owner = btrfs_header_owner(buf); - BUG_ON(owner == BTRFS_TREE_RELOC_OBJECTID && - !(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)); - - if (refs > 1) { - if ((owner == root->root_key.objectid || - root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) && - !(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) { - ret = btrfs_inc_ref(trans, root, buf, 1); - BUG_ON(ret); /* -ENOMEM */ - - if (root->root_key.objectid == - BTRFS_TREE_RELOC_OBJECTID) { - ret = btrfs_dec_ref(trans, root, buf, 0); - BUG_ON(ret); /* -ENOMEM */ - ret = btrfs_inc_ref(trans, root, cow, 1); - BUG_ON(ret); /* -ENOMEM */ - } - new_flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF; - } else { - - if (root->root_key.objectid == - BTRFS_TREE_RELOC_OBJECTID) - ret = btrfs_inc_ref(trans, root, cow, 1); - else - ret = btrfs_inc_ref(trans, root, cow, 0); - BUG_ON(ret); /* -ENOMEM */ - } - if (new_flags != 0) { - int level = btrfs_header_level(buf); - - ret = btrfs_set_disk_extent_flags(trans, root, - buf->start, - buf->len, - new_flags, level, 0); - if (ret) - return ret; - } - } else { - if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) { - if (root->root_key.objectid == - BTRFS_TREE_RELOC_OBJECTID) - ret = btrfs_inc_ref(trans, root, cow, 1); - else - ret = btrfs_inc_ref(trans, root, cow, 0); - BUG_ON(ret); /* -ENOMEM */ - ret = btrfs_dec_ref(trans, root, buf, 1); - BUG_ON(ret); /* -ENOMEM */ - } - clean_tree_block(trans, root->fs_info, buf); - *last_ref = 1; - } - return 0; -} - -/* - * does the dirty work in cow of a single block. The parent block (if - * supplied) is updated to point to the new cow copy. The new buffer is marked - * dirty and returned locked. If you modify the block it needs to be marked - * dirty again. - * - * search_start -- an allocation hint for the new block - * - * empty_size -- a hint that you plan on doing more cow. This is the size in - * bytes the allocator should try to find free next to the block it returns. - * This is just a hint and may be ignored by the allocator. - */ -static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct extent_buffer *buf, - struct extent_buffer *parent, int parent_slot, - struct extent_buffer **cow_ret, - u64 search_start, u64 empty_size) -{ - struct btrfs_disk_key disk_key; - struct extent_buffer *cow; - int level, ret; - int last_ref = 0; - int unlock_orig = 0; - u64 parent_start = 0; - - if (*cow_ret == buf) - unlock_orig = 1; - - btrfs_assert_tree_locked(buf); - - WARN_ON(test_bit(BTRFS_ROOT_REF_COWS, &root->state) && - trans->transid != root->fs_info->running_transaction->transid); - WARN_ON(test_bit(BTRFS_ROOT_REF_COWS, &root->state) && - trans->transid != root->last_trans); - - level = btrfs_header_level(buf); - - if (level == 0) - btrfs_item_key(buf, &disk_key, 0); - else - btrfs_node_key(buf, &disk_key, 0); - - if ((root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) && parent) - parent_start = parent->start; - - cow = btrfs_alloc_tree_block(trans, root, parent_start, - root->root_key.objectid, &disk_key, level, - search_start, empty_size); - if (IS_ERR(cow)) - return PTR_ERR(cow); - - /* cow is set to blocking by btrfs_init_new_buffer */ - - copy_extent_buffer(cow, buf, 0, 0, cow->len); - btrfs_set_header_bytenr(cow, cow->start); - btrfs_set_header_generation(cow, trans->transid); - btrfs_set_header_backref_rev(cow, BTRFS_MIXED_BACKREF_REV); - btrfs_clear_header_flag(cow, BTRFS_HEADER_FLAG_WRITTEN | - BTRFS_HEADER_FLAG_RELOC); - if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) - btrfs_set_header_flag(cow, BTRFS_HEADER_FLAG_RELOC); - else - btrfs_set_header_owner(cow, root->root_key.objectid); - - write_extent_buffer(cow, root->fs_info->fsid, btrfs_header_fsid(), - BTRFS_FSID_SIZE); - - ret = update_ref_for_cow(trans, root, buf, cow, &last_ref); - if (ret) { - btrfs_abort_transaction(trans, ret); - return ret; - } - - if (test_bit(BTRFS_ROOT_REF_COWS, &root->state)) { - ret = btrfs_reloc_cow_block(trans, root, buf, cow); - if (ret) { - btrfs_abort_transaction(trans, ret); - return ret; - } - } - - if (buf == root->node) { - WARN_ON(parent && parent != buf); - if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID || - btrfs_header_backref_rev(buf) < BTRFS_MIXED_BACKREF_REV) - parent_start = buf->start; - - extent_buffer_get(cow); - tree_mod_log_set_root_pointer(root, cow, 1); - rcu_assign_pointer(root->node, cow); - - btrfs_free_tree_block(trans, root, buf, parent_start, - last_ref); - free_extent_buffer(buf); - add_root_to_dirty_list(root); - } else { - WARN_ON(trans->transid != btrfs_header_generation(parent)); - tree_mod_log_insert_key(root->fs_info, parent, parent_slot, - MOD_LOG_KEY_REPLACE, GFP_NOFS); - btrfs_set_node_blockptr(parent, parent_slot, - cow->start); - btrfs_set_node_ptr_generation(parent, parent_slot, - trans->transid); - btrfs_mark_buffer_dirty(parent); - if (last_ref) { - ret = tree_mod_log_free_eb(root->fs_info, buf); - if (ret) { - btrfs_abort_transaction(trans, ret); - return ret; - } - } - btrfs_free_tree_block(trans, root, buf, parent_start, - last_ref); - } - if (unlock_orig) - btrfs_tree_unlock(buf); - free_extent_buffer_stale(buf); - btrfs_mark_buffer_dirty(cow); - *cow_ret = cow; - return 0; -} - -/* - * returns the logical address of the oldest predecessor of the given root. - * entries older than time_seq are ignored. - */ -static struct tree_mod_elem * -__tree_mod_log_oldest_root(struct btrfs_fs_info *fs_info, - struct extent_buffer *eb_root, u64 time_seq) -{ - struct tree_mod_elem *tm; - struct tree_mod_elem *found = NULL; - u64 root_logical = eb_root->start; - int looped = 0; - - if (!time_seq) - return NULL; - - /* - * the very last operation that's logged for a root is the - * replacement operation (if it is replaced at all). this has - * the logical address of the *new* root, making it the very - * first operation that's logged for this root. - */ - while (1) { - tm = tree_mod_log_search_oldest(fs_info, root_logical, - time_seq); - if (!looped && !tm) - return NULL; - /* - * if there are no tree operation for the oldest root, we simply - * return it. this should only happen if that (old) root is at - * level 0. - */ - if (!tm) - break; - - /* - * if there's an operation that's not a root replacement, we - * found the oldest version of our root. normally, we'll find a - * MOD_LOG_KEY_REMOVE_WHILE_FREEING operation here. - */ - if (tm->op != MOD_LOG_ROOT_REPLACE) - break; - - found = tm; - root_logical = tm->old_root.logical; - looped = 1; - } - - /* if there's no old root to return, return what we found instead */ - if (!found) - found = tm; - - return found; -} - -/* - * tm is a pointer to the first operation to rewind within eb. then, all - * previous operations will be rewound (until we reach something older than - * time_seq). - */ -static void -__tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct extent_buffer *eb, - u64 time_seq, struct tree_mod_elem *first_tm) -{ - u32 n; - struct rb_node *next; - struct tree_mod_elem *tm = first_tm; - unsigned long o_dst; - unsigned long o_src; - unsigned long p_size = sizeof(struct btrfs_key_ptr); - - n = btrfs_header_nritems(eb); - tree_mod_log_read_lock(fs_info); - while (tm && tm->seq >= time_seq) { - /* - * all the operations are recorded with the operator used for - * the modification. as we're going backwards, we do the - * opposite of each operation here. - */ - switch (tm->op) { - case MOD_LOG_KEY_REMOVE_WHILE_FREEING: - BUG_ON(tm->slot < n); - /* Fallthrough */ - case MOD_LOG_KEY_REMOVE_WHILE_MOVING: - case MOD_LOG_KEY_REMOVE: - btrfs_set_node_key(eb, &tm->key, tm->slot); - btrfs_set_node_blockptr(eb, tm->slot, tm->blockptr); - btrfs_set_node_ptr_generation(eb, tm->slot, - tm->generation); - n++; - break; - case MOD_LOG_KEY_REPLACE: - BUG_ON(tm->slot >= n); - btrfs_set_node_key(eb, &tm->key, tm->slot); - btrfs_set_node_blockptr(eb, tm->slot, tm->blockptr); - btrfs_set_node_ptr_generation(eb, tm->slot, - tm->generation); - break; - case MOD_LOG_KEY_ADD: - /* if a move operation is needed it's in the log */ - n--; - break; - case MOD_LOG_MOVE_KEYS: - o_dst = btrfs_node_key_ptr_offset(tm->slot); - o_src = btrfs_node_key_ptr_offset(tm->move.dst_slot); - memmove_extent_buffer(eb, o_dst, o_src, - tm->move.nr_items * p_size); - break; - case MOD_LOG_ROOT_REPLACE: - /* - * this operation is special. for roots, this must be - * handled explicitly before rewinding. - * for non-roots, this operation may exist if the node - * was a root: root A -> child B; then A gets empty and - * B is promoted to the new root. in the mod log, we'll - * have a root-replace operation for B, a tree block - * that is no root. we simply ignore that operation. - */ - break; - } - next = rb_next(&tm->node); - if (!next) - break; - tm = container_of(next, struct tree_mod_elem, node); - if (tm->logical != first_tm->logical) - break; - } - tree_mod_log_read_unlock(fs_info); - btrfs_set_header_nritems(eb, n); -} - -/* - * Called with eb read locked. If the buffer cannot be rewound, the same buffer - * is returned. If rewind operations happen, a fresh buffer is returned. The - * returned buffer is always read-locked. If the returned buffer is not the - * input buffer, the lock on the input buffer is released and the input buffer - * is freed (its refcount is decremented). - */ -static struct extent_buffer * -tree_mod_log_rewind(struct btrfs_fs_info *fs_info, struct btrfs_path *path, - struct extent_buffer *eb, u64 time_seq) -{ - struct extent_buffer *eb_rewin; - struct tree_mod_elem *tm; - - if (!time_seq) - return eb; - - if (btrfs_header_level(eb) == 0) - return eb; - - tm = tree_mod_log_search(fs_info, eb->start, time_seq); - if (!tm) - return eb; - - btrfs_set_path_blocking(path); - btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); - - if (tm->op == MOD_LOG_KEY_REMOVE_WHILE_FREEING) { - BUG_ON(tm->slot != 0); - eb_rewin = alloc_dummy_extent_buffer(fs_info, eb->start, - eb->len); - if (!eb_rewin) { - btrfs_tree_read_unlock_blocking(eb); - free_extent_buffer(eb); - return NULL; - } - btrfs_set_header_bytenr(eb_rewin, eb->start); - btrfs_set_header_backref_rev(eb_rewin, - btrfs_header_backref_rev(eb)); - btrfs_set_header_owner(eb_rewin, btrfs_header_owner(eb)); - btrfs_set_header_level(eb_rewin, btrfs_header_level(eb)); - } else { - eb_rewin = btrfs_clone_extent_buffer(eb); - if (!eb_rewin) { - btrfs_tree_read_unlock_blocking(eb); - free_extent_buffer(eb); - return NULL; - } - } - - btrfs_clear_path_blocking(path, NULL, BTRFS_READ_LOCK); - btrfs_tree_read_unlock_blocking(eb); - free_extent_buffer(eb); - - extent_buffer_get(eb_rewin); - btrfs_tree_read_lock(eb_rewin); - __tree_mod_log_rewind(fs_info, eb_rewin, time_seq, tm); - WARN_ON(btrfs_header_nritems(eb_rewin) > - BTRFS_NODEPTRS_PER_BLOCK(fs_info->tree_root)); - - return eb_rewin; -} - -/* - * get_old_root() rewinds the state of @root's root node to the given @time_seq - * value. If there are no changes, the current root->root_node is returned. If - * anything changed in between, there's a fresh buffer allocated on which the - * rewind operations are done. In any case, the returned buffer is read locked. - * Returns NULL on error (with no locks held). - */ -static inline struct extent_buffer * -get_old_root(struct btrfs_root *root, u64 time_seq) -{ - struct tree_mod_elem *tm; - struct extent_buffer *eb = NULL; - struct extent_buffer *eb_root; - struct extent_buffer *old; - struct tree_mod_root *old_root = NULL; - u64 old_generation = 0; - u64 logical; - - eb_root = btrfs_read_lock_root_node(root); - tm = __tree_mod_log_oldest_root(root->fs_info, eb_root, time_seq); - if (!tm) - return eb_root; - - if (tm->op == MOD_LOG_ROOT_REPLACE) { - old_root = &tm->old_root; - old_generation = tm->generation; - logical = old_root->logical; - } else { - logical = eb_root->start; - } - - tm = tree_mod_log_search(root->fs_info, logical, time_seq); - if (old_root && tm && tm->op != MOD_LOG_KEY_REMOVE_WHILE_FREEING) { - btrfs_tree_read_unlock(eb_root); - free_extent_buffer(eb_root); - old = read_tree_block(root, logical, 0); - if (WARN_ON(IS_ERR(old) || !extent_buffer_uptodate(old))) { - if (!IS_ERR(old)) - free_extent_buffer(old); - btrfs_warn(root->fs_info, - "failed to read tree block %llu from get_old_root", logical); - } else { - eb = btrfs_clone_extent_buffer(old); - free_extent_buffer(old); - } - } else if (old_root) { - btrfs_tree_read_unlock(eb_root); - free_extent_buffer(eb_root); - eb = alloc_dummy_extent_buffer(root->fs_info, logical, - root->nodesize); - } else { - btrfs_set_lock_blocking_rw(eb_root, BTRFS_READ_LOCK); - eb = btrfs_clone_extent_buffer(eb_root); - btrfs_tree_read_unlock_blocking(eb_root); - free_extent_buffer(eb_root); - } - - if (!eb) - return NULL; - extent_buffer_get(eb); - btrfs_tree_read_lock(eb); - if (old_root) { - btrfs_set_header_bytenr(eb, eb->start); - btrfs_set_header_backref_rev(eb, BTRFS_MIXED_BACKREF_REV); - btrfs_set_header_owner(eb, btrfs_header_owner(eb_root)); - btrfs_set_header_level(eb, old_root->level); - btrfs_set_header_generation(eb, old_generation); - } - if (tm) - __tree_mod_log_rewind(root->fs_info, eb, time_seq, tm); - else - WARN_ON(btrfs_header_level(eb) != 0); - WARN_ON(btrfs_header_nritems(eb) > BTRFS_NODEPTRS_PER_BLOCK(root)); - - return eb; -} - -int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq) -{ - struct tree_mod_elem *tm; - int level; - struct extent_buffer *eb_root = btrfs_root_node(root); - - tm = __tree_mod_log_oldest_root(root->fs_info, eb_root, time_seq); - if (tm && tm->op == MOD_LOG_ROOT_REPLACE) { - level = tm->old_root.level; - } else { - level = btrfs_header_level(eb_root); - } - free_extent_buffer(eb_root); - - return level; -} - -static inline int should_cow_block(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct extent_buffer *buf) -{ - if (btrfs_is_testing(root->fs_info)) - return 0; - - /* ensure we can see the force_cow */ - smp_rmb(); - - /* - * We do not need to cow a block if - * 1) this block is not created or changed in this transaction; - * 2) this block does not belong to TREE_RELOC tree; - * 3) the root is not forced COW. - * - * What is forced COW: - * when we create snapshot during committing the transaction, - * after we've finished coping src root, we must COW the shared - * block to ensure the metadata consistency. - */ - if (btrfs_header_generation(buf) == trans->transid && - !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN) && - !(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID && - btrfs_header_flag(buf, BTRFS_HEADER_FLAG_RELOC)) && - !test_bit(BTRFS_ROOT_FORCE_COW, &root->state)) - return 0; - return 1; -} - -/* - * cows a single block, see __btrfs_cow_block for the real work. - * This version of it has extra checks so that a block isn't COWed more than - * once per transaction, as long as it hasn't been written yet - */ -noinline int btrfs_cow_block(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct extent_buffer *buf, - struct extent_buffer *parent, int parent_slot, - struct extent_buffer **cow_ret) -{ - u64 search_start; - int ret; - - if (trans->transaction != root->fs_info->running_transaction) - WARN(1, KERN_CRIT "trans %llu running %llu\n", - trans->transid, - root->fs_info->running_transaction->transid); - - if (trans->transid != root->fs_info->generation) - WARN(1, KERN_CRIT "trans %llu running %llu\n", - trans->transid, root->fs_info->generation); - - if (!should_cow_block(trans, root, buf)) { - trans->dirty = true; - *cow_ret = buf; - return 0; - } - - search_start = buf->start & ~((u64)SZ_1G - 1); - - if (parent) - btrfs_set_lock_blocking(parent); - btrfs_set_lock_blocking(buf); - - ret = __btrfs_cow_block(trans, root, buf, parent, - parent_slot, cow_ret, search_start, 0); - - trace_btrfs_cow_block(root, buf, *cow_ret); - - return ret; -} - -/* - * helper function for defrag to decide if two blocks pointed to by a - * node are actually close by - */ -static int close_blocks(u64 blocknr, u64 other, u32 blocksize) -{ - if (blocknr < other && other - (blocknr + blocksize) < 32768) - return 1; - if (blocknr > other && blocknr - (other + blocksize) < 32768) - return 1; - return 0; -} - -/* - * compare two keys in a memcmp fashion - */ -static int comp_keys(struct btrfs_disk_key *disk, struct btrfs_key *k2) -{ - struct btrfs_key k1; - - btrfs_disk_key_to_cpu(&k1, disk); - - return btrfs_comp_cpu_keys(&k1, k2); -} - -/* - * same as comp_keys only with two btrfs_key's - */ -int btrfs_comp_cpu_keys(struct btrfs_key *k1, struct btrfs_key *k2) -{ - if (k1->objectid > k2->objectid) - return 1; - if (k1->objectid < k2->objectid) - return -1; - if (k1->type > k2->type) - return 1; - if (k1->type < k2->type) - return -1; - if (k1->offset > k2->offset) - return 1; - if (k1->offset < k2->offset) - return -1; - return 0; -} - -/* - * this is used by the defrag code to go through all the - * leaves pointed to by a node and reallocate them so that - * disk order is close to key order - */ -int btrfs_realloc_node(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct extent_buffer *parent, - int start_slot, u64 *last_ret, - struct btrfs_key *progress) -{ - struct extent_buffer *cur; - u64 blocknr; - u64 gen; - u64 search_start = *last_ret; - u64 last_block = 0; - u64 other; - u32 parent_nritems; - int end_slot; - int i; - int err = 0; - int parent_level; - int uptodate; - u32 blocksize; - int progress_passed = 0; - struct btrfs_disk_key disk_key; - - parent_level = btrfs_header_level(parent); - - WARN_ON(trans->transaction != root->fs_info->running_transaction); - WARN_ON(trans->transid != root->fs_info->generation); - - parent_nritems = btrfs_header_nritems(parent); - blocksize = root->nodesize; - end_slot = parent_nritems - 1; - - if (parent_nritems <= 1) - return 0; - - btrfs_set_lock_blocking(parent); - - for (i = start_slot; i <= end_slot; i++) { - int close = 1; - - btrfs_node_key(parent, &disk_key, i); - if (!progress_passed && comp_keys(&disk_key, progress) < 0) - continue; - - progress_passed = 1; - blocknr = btrfs_node_blockptr(parent, i); - gen = btrfs_node_ptr_generation(parent, i); - if (last_block == 0) - last_block = blocknr; - - if (i > 0) { - other = btrfs_node_blockptr(parent, i - 1); - close = close_blocks(blocknr, other, blocksize); - } - if (!close && i < end_slot) { - other = btrfs_node_blockptr(parent, i + 1); - close = close_blocks(blocknr, other, blocksize); - } - if (close) { - last_block = blocknr; - continue; - } - - cur = btrfs_find_tree_block(root->fs_info, blocknr); - if (cur) - uptodate = btrfs_buffer_uptodate(cur, gen, 0); - else - uptodate = 0; - if (!cur || !uptodate) { - if (!cur) { - cur = read_tree_block(root, blocknr, gen); - if (IS_ERR(cur)) { - return PTR_ERR(cur); - } else if (!extent_buffer_uptodate(cur)) { - free_extent_buffer(cur); - return -EIO; - } - } else if (!uptodate) { - err = btrfs_read_buffer(cur, gen); - if (err) { - free_extent_buffer(cur); - return err; - } - } - } - if (search_start == 0) - search_start = last_block; - - btrfs_tree_lock(cur); - btrfs_set_lock_blocking(cur); - err = __btrfs_cow_block(trans, root, cur, parent, i, - &cur, search_start, - min(16 * blocksize, - (end_slot - i) * blocksize)); - if (err) { - btrfs_tree_unlock(cur); - free_extent_buffer(cur); - break; - } - search_start = cur->start; - last_block = cur->start; - *last_ret = search_start; - btrfs_tree_unlock(cur); - free_extent_buffer(cur); - } - return err; -} - - -/* - * search for key in the extent_buffer. The items start at offset p, - * and they are item_size apart. There are 'max' items in p. - * - * the slot in the array is returned via slot, and it points to - * the place where you would insert key if it is not found in - * the array. - * - * slot may point to max if the key is bigger than all of the keys - */ -static noinline int generic_bin_search(struct extent_buffer *eb, - unsigned long p, - int item_size, struct btrfs_key *key, - int max, int *slot) -{ - int low = 0; - int high = max; - int mid; - int ret; - struct btrfs_disk_key *tmp = NULL; - struct btrfs_disk_key unaligned; - unsigned long offset; - char *kaddr = NULL; - unsigned long map_start = 0; - unsigned long map_len = 0; - int err; - - if (low > high) { - btrfs_err(eb->fs_info, - "%s: low (%d) > high (%d) eb %llu owner %llu level %d", - __func__, low, high, eb->start, - btrfs_header_owner(eb), btrfs_header_level(eb)); - return -EINVAL; - } - - while (low < high) { - mid = (low + high) / 2; - offset = p + mid * item_size; - - if (!kaddr || offset < map_start || - (offset + sizeof(struct btrfs_disk_key)) > - map_start + map_len) { - - err = map_private_extent_buffer(eb, offset, - sizeof(struct btrfs_disk_key), - &kaddr, &map_start, &map_len); - - if (!err) { - tmp = (struct btrfs_disk_key *)(kaddr + offset - - map_start); - } else if (err == 1) { - read_extent_buffer(eb, &unaligned, - offset, sizeof(unaligned)); - tmp = &unaligned; - } else { - return err; - } - - } else { - tmp = (struct btrfs_disk_key *)(kaddr + offset - - map_start); - } - ret = comp_keys(tmp, key); - - if (ret < 0) - low = mid + 1; - else if (ret > 0) - high = mid; - else { - *slot = mid; - return 0; - } - } - *slot = low; - return 1; -} - -/* - * simple bin_search frontend that does the right thing for - * leaves vs nodes - */ -static int bin_search(struct extent_buffer *eb, struct btrfs_key *key, - int level, int *slot) -{ - if (level == 0) - return generic_bin_search(eb, - offsetof(struct btrfs_leaf, items), - sizeof(struct btrfs_item), - key, btrfs_header_nritems(eb), - slot); - else - return generic_bin_search(eb, - offsetof(struct btrfs_node, ptrs), - sizeof(struct btrfs_key_ptr), - key, btrfs_header_nritems(eb), - slot); -} - -int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, - int level, int *slot) -{ - return bin_search(eb, key, level, slot); -} - -static void root_add_used(struct btrfs_root *root, u32 size) -{ - spin_lock(&root->accounting_lock); - btrfs_set_root_used(&root->root_item, - btrfs_root_used(&root->root_item) + size); - spin_unlock(&root->accounting_lock); -} - -static void root_sub_used(struct btrfs_root *root, u32 size) -{ - spin_lock(&root->accounting_lock); - btrfs_set_root_used(&root->root_item, - btrfs_root_used(&root->root_item) - size); - spin_unlock(&root->accounting_lock); -} - -/* given a node and slot number, this reads the blocks it points to. The - * extent buffer is returned with a reference taken (but unlocked). - */ -static noinline struct extent_buffer *read_node_slot(struct btrfs_root *root, - struct extent_buffer *parent, int slot) -{ - int level = btrfs_header_level(parent); - struct extent_buffer *eb; - - if (slot < 0 || slot >= btrfs_header_nritems(parent)) - return ERR_PTR(-ENOENT); - - BUG_ON(level == 0); - - eb = read_tree_block(root, btrfs_node_blockptr(parent, slot), - btrfs_node_ptr_generation(parent, slot)); - if (!IS_ERR(eb) && !extent_buffer_uptodate(eb)) { - free_extent_buffer(eb); - eb = ERR_PTR(-EIO); - } - - return eb; -} - -/* - * node level balancing, used to make sure nodes are in proper order for - * item deletion. We balance from the top down, so we have to make sure - * that a deletion won't leave an node completely empty later on. - */ -static noinline int balance_level(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, int level) -{ - struct extent_buffer *right = NULL; - struct extent_buffer *mid; - struct extent_buffer *left = NULL; - struct extent_buffer *parent = NULL; - int ret = 0; - int wret; - int pslot; - int orig_slot = path->slots[level]; - u64 orig_ptr; - - if (level == 0) - return 0; - - mid = path->nodes[level]; - - WARN_ON(path->locks[level] != BTRFS_WRITE_LOCK && - path->locks[level] != BTRFS_WRITE_LOCK_BLOCKING); - WARN_ON(btrfs_header_generation(mid) != trans->transid); - - orig_ptr = btrfs_node_blockptr(mid, orig_slot); - - if (level < BTRFS_MAX_LEVEL - 1) { - parent = path->nodes[level + 1]; - pslot = path->slots[level + 1]; - } - - /* - * deal with the case where there is only one pointer in the root - * by promoting the node below to a root - */ - if (!parent) { - struct extent_buffer *child; - - if (btrfs_header_nritems(mid) != 1) - return 0; - - /* promote the child to a root */ - child = read_node_slot(root, mid, 0); - if (IS_ERR(child)) { - ret = PTR_ERR(child); - btrfs_handle_fs_error(root->fs_info, ret, NULL); - goto enospc; - } - - btrfs_tree_lock(child); - btrfs_set_lock_blocking(child); - ret = btrfs_cow_block(trans, root, child, mid, 0, &child); - if (ret) { - btrfs_tree_unlock(child); - free_extent_buffer(child); - goto enospc; - } - - tree_mod_log_set_root_pointer(root, child, 1); - rcu_assign_pointer(root->node, child); - - add_root_to_dirty_list(root); - btrfs_tree_unlock(child); - - path->locks[level] = 0; - path->nodes[level] = NULL; - clean_tree_block(trans, root->fs_info, mid); - btrfs_tree_unlock(mid); - /* once for the path */ - free_extent_buffer(mid); - - root_sub_used(root, mid->len); - btrfs_free_tree_block(trans, root, mid, 0, 1); - /* once for the root ptr */ - free_extent_buffer_stale(mid); - return 0; - } - if (btrfs_header_nritems(mid) > - BTRFS_NODEPTRS_PER_BLOCK(root) / 4) - return 0; - - left = read_node_slot(root, parent, pslot - 1); - if (IS_ERR(left)) - left = NULL; - - if (left) { - btrfs_tree_lock(left); - btrfs_set_lock_blocking(left); - wret = btrfs_cow_block(trans, root, left, - parent, pslot - 1, &left); - if (wret) { - ret = wret; - goto enospc; - } - } - - right = read_node_slot(root, parent, pslot + 1); - if (IS_ERR(right)) - right = NULL; - - if (right) { - btrfs_tree_lock(right); - btrfs_set_lock_blocking(right); - wret = btrfs_cow_block(trans, root, right, - parent, pslot + 1, &right); - if (wret) { - ret = wret; - goto enospc; - } - } - - /* first, try to make some room in the middle buffer */ - if (left) { - orig_slot += btrfs_header_nritems(left); - wret = push_node_left(trans, root, left, mid, 1); - if (wret < 0) - ret = wret; - } - - /* - * then try to empty the right most buffer into the middle - */ - if (right) { - wret = push_node_left(trans, root, mid, right, 1); - if (wret < 0 && wret != -ENOSPC) - ret = wret; - if (btrfs_header_nritems(right) == 0) { - clean_tree_block(trans, root->fs_info, right); - btrfs_tree_unlock(right); - del_ptr(root, path, level + 1, pslot + 1); - root_sub_used(root, right->len); - btrfs_free_tree_block(trans, root, right, 0, 1); - free_extent_buffer_stale(right); - right = NULL; - } else { - struct btrfs_disk_key right_key; - btrfs_node_key(right, &right_key, 0); - tree_mod_log_set_node_key(root->fs_info, parent, - pslot + 1, 0); - btrfs_set_node_key(parent, &right_key, pslot + 1); - btrfs_mark_buffer_dirty(parent); - } - } - if (btrfs_header_nritems(mid) == 1) { - /* - * we're not allowed to leave a node with one item in the - * tree during a delete. A deletion from lower in the tree - * could try to delete the only pointer in this node. - * So, pull some keys from the left. - * There has to be a left pointer at this point because - * otherwise we would have pulled some pointers from the - * right - */ - if (!left) { - ret = -EROFS; - btrfs_handle_fs_error(root->fs_info, ret, NULL); - goto enospc; - } - wret = balance_node_right(trans, root, mid, left); - if (wret < 0) { - ret = wret; - goto enospc; - } - if (wret == 1) { - wret = push_node_left(trans, root, left, mid, 1); - if (wret < 0) - ret = wret; - } - BUG_ON(wret == 1); - } - if (btrfs_header_nritems(mid) == 0) { - clean_tree_block(trans, root->fs_info, mid); - btrfs_tree_unlock(mid); - del_ptr(root, path, level + 1, pslot); - root_sub_used(root, mid->len); - btrfs_free_tree_block(trans, root, mid, 0, 1); - free_extent_buffer_stale(mid); - mid = NULL; - } else { - /* update the parent key to reflect our changes */ - struct btrfs_disk_key mid_key; - btrfs_node_key(mid, &mid_key, 0); - tree_mod_log_set_node_key(root->fs_info, parent, - pslot, 0); - btrfs_set_node_key(parent, &mid_key, pslot); - btrfs_mark_buffer_dirty(parent); - } - - /* update the path */ - if (left) { - if (btrfs_header_nritems(left) > orig_slot) { - extent_buffer_get(left); - /* left was locked after cow */ - path->nodes[level] = left; - path->slots[level + 1] -= 1; - path->slots[level] = orig_slot; - if (mid) { - btrfs_tree_unlock(mid); - free_extent_buffer(mid); - } - } else { - orig_slot -= btrfs_header_nritems(left); - path->slots[level] = orig_slot; - } - } - /* double check we haven't messed things up */ - if (orig_ptr != - btrfs_node_blockptr(path->nodes[level], path->slots[level])) - BUG(); -enospc: - if (right) { - btrfs_tree_unlock(right); - free_extent_buffer(right); - } - if (left) { - if (path->nodes[level] != left) - btrfs_tree_unlock(left); - free_extent_buffer(left); - } - return ret; -} - -/* Node balancing for insertion. Here we only split or push nodes around - * when they are completely full. This is also done top down, so we - * have to be pessimistic. - */ -static noinline int push_nodes_for_insert(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, int level) -{ - struct extent_buffer *right = NULL; - struct extent_buffer *mid; - struct extent_buffer *left = NULL; - struct extent_buffer *parent = NULL; - int ret = 0; - int wret; - int pslot; - int orig_slot = path->slots[level]; - - if (level == 0) - return 1; - - mid = path->nodes[level]; - WARN_ON(btrfs_header_generation(mid) != trans->transid); - - if (level < BTRFS_MAX_LEVEL - 1) { - parent = path->nodes[level + 1]; - pslot = path->slots[level + 1]; - } - - if (!parent) - return 1; - - left = read_node_slot(root, parent, pslot - 1); - if (IS_ERR(left)) - left = NULL; - - /* first, try to make some room in the middle buffer */ - if (left) { - u32 left_nr; - - btrfs_tree_lock(left); - btrfs_set_lock_blocking(left); - - left_nr = btrfs_header_nritems(left); - if (left_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) { - wret = 1; - } else { - ret = btrfs_cow_block(trans, root, left, parent, - pslot - 1, &left); - if (ret) - wret = 1; - else { - wret = push_node_left(trans, root, - left, mid, 0); - } - } - if (wret < 0) - ret = wret; - if (wret == 0) { - struct btrfs_disk_key disk_key; - orig_slot += left_nr; - btrfs_node_key(mid, &disk_key, 0); - tree_mod_log_set_node_key(root->fs_info, parent, - pslot, 0); - btrfs_set_node_key(parent, &disk_key, pslot); - btrfs_mark_buffer_dirty(parent); - if (btrfs_header_nritems(left) > orig_slot) { - path->nodes[level] = left; - path->slots[level + 1] -= 1; - path->slots[level] = orig_slot; - btrfs_tree_unlock(mid); - free_extent_buffer(mid); - } else { - orig_slot -= - btrfs_header_nritems(left); - path->slots[level] = orig_slot; - btrfs_tree_unlock(left); - free_extent_buffer(left); - } - return 0; - } - btrfs_tree_unlock(left); - free_extent_buffer(left); - } - right = read_node_slot(root, parent, pslot + 1); - if (IS_ERR(right)) - right = NULL; - - /* - * then try to empty the right most buffer into the middle - */ - if (right) { - u32 right_nr; - - btrfs_tree_lock(right); - btrfs_set_lock_blocking(right); - - right_nr = btrfs_header_nritems(right); - if (right_nr >= BTRFS_NODEPTRS_PER_BLOCK(root) - 1) { - wret = 1; - } else { - ret = btrfs_cow_block(trans, root, right, - parent, pslot + 1, - &right); - if (ret) - wret = 1; - else { - wret = balance_node_right(trans, root, - right, mid); - } - } - if (wret < 0) - ret = wret; - if (wret == 0) { - struct btrfs_disk_key disk_key; - - btrfs_node_key(right, &disk_key, 0); - tree_mod_log_set_node_key(root->fs_info, parent, - pslot + 1, 0); - btrfs_set_node_key(parent, &disk_key, pslot + 1); - btrfs_mark_buffer_dirty(parent); - - if (btrfs_header_nritems(mid) <= orig_slot) { - path->nodes[level] = right; - path->slots[level + 1] += 1; - path->slots[level] = orig_slot - - btrfs_header_nritems(mid); - btrfs_tree_unlock(mid); - free_extent_buffer(mid); - } else { - btrfs_tree_unlock(right); - free_extent_buffer(right); - } - return 0; - } - btrfs_tree_unlock(right); - free_extent_buffer(right); - } - return 1; -} - -/* - * readahead one full node of leaves, finding things that are close - * to the block in 'slot', and triggering ra on them. - */ -static void reada_for_search(struct btrfs_root *root, - struct btrfs_path *path, - int level, int slot, u64 objectid) -{ - struct extent_buffer *node; - struct btrfs_disk_key disk_key; - u32 nritems; - u64 search; - u64 target; - u64 nread = 0; - struct extent_buffer *eb; - u32 nr; - u32 blocksize; - u32 nscan = 0; - - if (level != 1) - return; - - if (!path->nodes[level]) - return; - - node = path->nodes[level]; - - search = btrfs_node_blockptr(node, slot); - blocksize = root->nodesize; - eb = btrfs_find_tree_block(root->fs_info, search); - if (eb) { - free_extent_buffer(eb); - return; - } - - target = search; - - nritems = btrfs_header_nritems(node); - nr = slot; - - while (1) { - if (path->reada == READA_BACK) { - if (nr == 0) - break; - nr--; - } else if (path->reada == READA_FORWARD) { - nr++; - if (nr >= nritems) - break; - } - if (path->reada == READA_BACK && objectid) { - btrfs_node_key(node, &disk_key, nr); - if (btrfs_disk_key_objectid(&disk_key) != objectid) - break; - } - search = btrfs_node_blockptr(node, nr); - if ((search <= target && target - search <= 65536) || - (search > target && search - target <= 65536)) { - readahead_tree_block(root, search); - nread += blocksize; - } - nscan++; - if ((nread > 65536 || nscan > 32)) - break; - } -} - -static noinline void reada_for_balance(struct btrfs_root *root, - struct btrfs_path *path, int level) -{ - int slot; - int nritems; - struct extent_buffer *parent; - struct extent_buffer *eb; - u64 gen; - u64 block1 = 0; - u64 block2 = 0; - - parent = path->nodes[level + 1]; - if (!parent) - return; - - nritems = btrfs_header_nritems(parent); - slot = path->slots[level + 1]; - - if (slot > 0) { - block1 = btrfs_node_blockptr(parent, slot - 1); - gen = btrfs_node_ptr_generation(parent, slot - 1); - eb = btrfs_find_tree_block(root->fs_info, block1); - /* - * if we get -eagain from btrfs_buffer_uptodate, we - * don't want to return eagain here. That will loop - * forever - */ - if (eb && btrfs_buffer_uptodate(eb, gen, 1) != 0) - block1 = 0; - free_extent_buffer(eb); - } - if (slot + 1 < nritems) { - block2 = btrfs_node_blockptr(parent, slot + 1); - gen = btrfs_node_ptr_generation(parent, slot + 1); - eb = btrfs_find_tree_block(root->fs_info, block2); - if (eb && btrfs_buffer_uptodate(eb, gen, 1) != 0) - block2 = 0; - free_extent_buffer(eb); - } - - if (block1) - readahead_tree_block(root, block1); - if (block2) - readahead_tree_block(root, block2); -} - - -/* - * when we walk down the tree, it is usually safe to unlock the higher layers - * in the tree. The exceptions are when our path goes through slot 0, because - * operations on the tree might require changing key pointers higher up in the - * tree. - * - * callers might also have set path->keep_locks, which tells this code to keep - * the lock if the path points to the last slot in the block. This is part of - * walking through the tree, and selecting the next slot in the higher block. - * - * lowest_unlock sets the lowest level in the tree we're allowed to unlock. so - * if lowest_unlock is 1, level 0 won't be unlocked - */ -static noinline void unlock_up(struct btrfs_path *path, int level, - int lowest_unlock, int min_write_lock_level, - int *write_lock_level) -{ - int i; - int skip_level = level; - int no_skips = 0; - struct extent_buffer *t; - - for (i = level; i < BTRFS_MAX_LEVEL; i++) { - if (!path->nodes[i]) - break; - if (!path->locks[i]) - break; - if (!no_skips && path->slots[i] == 0) { - skip_level = i + 1; - continue; - } - if (!no_skips && path->keep_locks) { - u32 nritems; - t = path->nodes[i]; - nritems = btrfs_header_nritems(t); - if (nritems < 1 || path->slots[i] >= nritems - 1) { - skip_level = i + 1; - continue; - } - } - if (skip_level < i && i >= lowest_unlock) - no_skips = 1; - - t = path->nodes[i]; - if (i >= lowest_unlock && i > skip_level && path->locks[i]) { - btrfs_tree_unlock_rw(t, path->locks[i]); - path->locks[i] = 0; - if (write_lock_level && - i > min_write_lock_level && - i <= *write_lock_level) { - *write_lock_level = i - 1; - } - } - } -} - -/* - * This releases any locks held in the path starting at level and - * going all the way up to the root. - * - * btrfs_search_slot will keep the lock held on higher nodes in a few - * corner cases, such as COW of the block at slot zero in the node. This - * ignores those rules, and it should only be called when there are no - * more updates to be done higher up in the tree. - */ -noinline void btrfs_unlock_up_safe(struct btrfs_path *path, int level) -{ - int i; - - if (path->keep_locks) - return; - - for (i = level; i < BTRFS_MAX_LEVEL; i++) { - if (!path->nodes[i]) - continue; - if (!path->locks[i]) - continue; - btrfs_tree_unlock_rw(path->nodes[i], path->locks[i]); - path->locks[i] = 0; - } -} - -/* - * helper function for btrfs_search_slot. The goal is to find a block - * in cache without setting the path to blocking. If we find the block - * we return zero and the path is unchanged. - * - * If we can't find the block, we set the path blocking and do some - * reada. -EAGAIN is returned and the search must be repeated. - */ -static int -read_block_for_search(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct btrfs_path *p, - struct extent_buffer **eb_ret, int level, int slot, - struct btrfs_key *key, u64 time_seq) -{ - u64 blocknr; - u64 gen; - struct extent_buffer *b = *eb_ret; - struct extent_buffer *tmp; - int ret; - - blocknr = btrfs_node_blockptr(b, slot); - gen = btrfs_node_ptr_generation(b, slot); - - tmp = btrfs_find_tree_block(root->fs_info, blocknr); - if (tmp) { - /* first we do an atomic uptodate check */ - if (btrfs_buffer_uptodate(tmp, gen, 1) > 0) { - *eb_ret = tmp; - return 0; - } - - /* the pages were up to date, but we failed - * the generation number check. Do a full - * read for the generation number that is correct. - * We must do this without dropping locks so - * we can trust our generation number - */ - btrfs_set_path_blocking(p); - - /* now we're allowed to do a blocking uptodate check */ - ret = btrfs_read_buffer(tmp, gen); - if (!ret) { - *eb_ret = tmp; - return 0; - } - free_extent_buffer(tmp); - btrfs_release_path(p); - return -EIO; - } - - /* - * reduce lock contention at high levels - * of the btree by dropping locks before - * we read. Don't release the lock on the current - * level because we need to walk this node to figure - * out which blocks to read. - */ - btrfs_unlock_up_safe(p, level + 1); - btrfs_set_path_blocking(p); - - free_extent_buffer(tmp); - if (p->reada != READA_NONE) - reada_for_search(root, p, level, slot, key->objectid); - - btrfs_release_path(p); - - ret = -EAGAIN; - tmp = read_tree_block(root, blocknr, 0); - if (!IS_ERR(tmp)) { - /* - * If the read above didn't mark this buffer up to date, - * it will never end up being up to date. Set ret to EIO now - * and give up so that our caller doesn't loop forever - * on our EAGAINs. - */ - if (!btrfs_buffer_uptodate(tmp, 0, 0)) - ret = -EIO; - free_extent_buffer(tmp); - } else { - ret = PTR_ERR(tmp); - } - return ret; -} - -/* - * helper function for btrfs_search_slot. This does all of the checks - * for node-level blocks and does any balancing required based on - * the ins_len. - * - * If no extra work was required, zero is returned. If we had to - * drop the path, -EAGAIN is returned and btrfs_search_slot must - * start over - */ -static int -setup_nodes_for_search(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct btrfs_path *p, - struct extent_buffer *b, int level, int ins_len, - int *write_lock_level) -{ - int ret; - if ((p->search_for_split || ins_len > 0) && btrfs_header_nritems(b) >= - BTRFS_NODEPTRS_PER_BLOCK(root) - 3) { - int sret; - - if (*write_lock_level < level + 1) { - *write_lock_level = level + 1; - btrfs_release_path(p); - goto again; - } - - btrfs_set_path_blocking(p); - reada_for_balance(root, p, level); - sret = split_node(trans, root, p, level); - btrfs_clear_path_blocking(p, NULL, 0); - - BUG_ON(sret > 0); - if (sret) { - ret = sret; - goto done; - } - b = p->nodes[level]; - } else if (ins_len < 0 && btrfs_header_nritems(b) < - BTRFS_NODEPTRS_PER_BLOCK(root) / 2) { - int sret; - - if (*write_lock_level < level + 1) { - *write_lock_level = level + 1; - btrfs_release_path(p); - goto again; - } - - btrfs_set_path_blocking(p); - reada_for_balance(root, p, level); - sret = balance_level(trans, root, p, level); - btrfs_clear_path_blocking(p, NULL, 0); - - if (sret) { - ret = sret; - goto done; - } - b = p->nodes[level]; - if (!b) { - btrfs_release_path(p); - goto again; - } - BUG_ON(btrfs_header_nritems(b) == 1); - } - return 0; - -again: - ret = -EAGAIN; -done: - return ret; -} - -static void key_search_validate(struct extent_buffer *b, - struct btrfs_key *key, - int level) -{ -#ifdef CONFIG_BTRFS_ASSERT - struct btrfs_disk_key disk_key; - - btrfs_cpu_key_to_disk(&disk_key, key); - - if (level == 0) - ASSERT(!memcmp_extent_buffer(b, &disk_key, - offsetof(struct btrfs_leaf, items[0].key), - sizeof(disk_key))); - else - ASSERT(!memcmp_extent_buffer(b, &disk_key, - offsetof(struct btrfs_node, ptrs[0].key), - sizeof(disk_key))); -#endif -} - -static int key_search(struct extent_buffer *b, struct btrfs_key *key, - int level, int *prev_cmp, int *slot) -{ - if (*prev_cmp != 0) { - *prev_cmp = bin_search(b, key, level, slot); - return *prev_cmp; - } - - key_search_validate(b, key, level); - *slot = 0; - - return 0; -} - -int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *path, - u64 iobjectid, u64 ioff, u8 key_type, - struct btrfs_key *found_key) -{ - int ret; - struct btrfs_key key; - struct extent_buffer *eb; - - ASSERT(path); - ASSERT(found_key); - - key.type = key_type; - key.objectid = iobjectid; - key.offset = ioff; - - ret = btrfs_search_slot(NULL, fs_root, &key, path, 0, 0); - if (ret < 0) - return ret; - - eb = path->nodes[0]; - if (ret && path->slots[0] >= btrfs_header_nritems(eb)) { - ret = btrfs_next_leaf(fs_root, path); - if (ret) - return ret; - eb = path->nodes[0]; - } - - btrfs_item_key_to_cpu(eb, found_key, path->slots[0]); - if (found_key->type != key.type || - found_key->objectid != key.objectid) - return 1; - - return 0; -} - -/* - * look for key in the tree. path is filled in with nodes along the way - * if key is found, we return zero and you can find the item in the leaf - * level of the path (level 0) - * - * If the key isn't found, the path points to the slot where it should - * be inserted, and 1 is returned. If there are other errors during the - * search a negative error number is returned. - * - * if ins_len > 0, nodes and leaves will be split as we walk down the - * tree. if ins_len < 0, nodes will be merged as we walk down the tree (if - * possible) - */ -int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root - *root, struct btrfs_key *key, struct btrfs_path *p, int - ins_len, int cow) -{ - struct extent_buffer *b; - int slot; - int ret; - int err; - int level; - int lowest_unlock = 1; - int root_lock; - /* everything at write_lock_level or lower must be write locked */ - int write_lock_level = 0; - u8 lowest_level = 0; - int min_write_lock_level; - int prev_cmp; - - lowest_level = p->lowest_level; - WARN_ON(lowest_level && ins_len > 0); - WARN_ON(p->nodes[0] != NULL); - BUG_ON(!cow && ins_len); - - if (ins_len < 0) { - lowest_unlock = 2; - - /* when we are removing items, we might have to go up to level - * two as we update tree pointers Make sure we keep write - * for those levels as well - */ - write_lock_level = 2; - } else if (ins_len > 0) { - /* - * for inserting items, make sure we have a write lock on - * level 1 so we can update keys - */ - write_lock_level = 1; - } - - if (!cow) - write_lock_level = -1; - - if (cow && (p->keep_locks || p->lowest_level)) - write_lock_level = BTRFS_MAX_LEVEL; - - min_write_lock_level = write_lock_level; - -again: - prev_cmp = -1; - /* - * we try very hard to do read locks on the root - */ - root_lock = BTRFS_READ_LOCK; - level = 0; - if (p->search_commit_root) { - /* - * the commit roots are read only - * so we always do read locks - */ - if (p->need_commit_sem) - down_read(&root->fs_info->commit_root_sem); - b = root->commit_root; - extent_buffer_get(b); - level = btrfs_header_level(b); - if (p->need_commit_sem) - up_read(&root->fs_info->commit_root_sem); - if (!p->skip_locking) - btrfs_tree_read_lock(b); - } else { - if (p->skip_locking) { - b = btrfs_root_node(root); - level = btrfs_header_level(b); - } else { - /* we don't know the level of the root node - * until we actually have it read locked - */ - b = btrfs_read_lock_root_node(root); - level = btrfs_header_level(b); - if (level <= write_lock_level) { - /* whoops, must trade for write lock */ - btrfs_tree_read_unlock(b); - free_extent_buffer(b); - b = btrfs_lock_root_node(root); - root_lock = BTRFS_WRITE_LOCK; - - /* the level might have changed, check again */ - level = btrfs_header_level(b); - } - } - } - p->nodes[level] = b; - if (!p->skip_locking) - p->locks[level] = root_lock; - - while (b) { - level = btrfs_header_level(b); - - /* - * setup the path here so we can release it under lock - * contention with the cow code - */ - if (cow) { - /* - * if we don't really need to cow this block - * then we don't want to set the path blocking, - * so we test it here - */ - if (!should_cow_block(trans, root, b)) { - trans->dirty = true; - goto cow_done; - } - - /* - * must have write locks on this node and the - * parent - */ - if (level > write_lock_level || - (level + 1 > write_lock_level && - level + 1 < BTRFS_MAX_LEVEL && - p->nodes[level + 1])) { - write_lock_level = level + 1; - btrfs_release_path(p); - goto again; - } - - btrfs_set_path_blocking(p); - err = btrfs_cow_block(trans, root, b, - p->nodes[level + 1], - p->slots[level + 1], &b); - if (err) { - ret = err; - goto done; - } - } -cow_done: - p->nodes[level] = b; - btrfs_clear_path_blocking(p, NULL, 0); - - /* - * we have a lock on b and as long as we aren't changing - * the tree, there is no way to for the items in b to change. - * It is safe to drop the lock on our parent before we - * go through the expensive btree search on b. - * - * If we're inserting or deleting (ins_len != 0), then we might - * be changing slot zero, which may require changing the parent. - * So, we can't drop the lock until after we know which slot - * we're operating on. - */ - if (!ins_len && !p->keep_locks) { - int u = level + 1; - - if (u < BTRFS_MAX_LEVEL && p->locks[u]) { - btrfs_tree_unlock_rw(p->nodes[u], p->locks[u]); - p->locks[u] = 0; - } - } - - ret = key_search(b, key, level, &prev_cmp, &slot); - if (ret < 0) - goto done; - - if (level != 0) { - int dec = 0; - if (ret && slot > 0) { - dec = 1; - slot -= 1; - } - p->slots[level] = slot; - err = setup_nodes_for_search(trans, root, p, b, level, - ins_len, &write_lock_level); - if (err == -EAGAIN) - goto again; - if (err) { - ret = err; - goto done; - } - b = p->nodes[level]; - slot = p->slots[level]; - - /* - * slot 0 is special, if we change the key - * we have to update the parent pointer - * which means we must have a write lock - * on the parent - */ - if (slot == 0 && ins_len && - write_lock_level < level + 1) { - write_lock_level = level + 1; - btrfs_release_path(p); - goto again; - } - - unlock_up(p, level, lowest_unlock, - min_write_lock_level, &write_lock_level); - - if (level == lowest_level) { - if (dec) - p->slots[level]++; - goto done; - } - - err = read_block_for_search(trans, root, p, - &b, level, slot, key, 0); - if (err == -EAGAIN) - goto again; - if (err) { - ret = err; - goto done; - } - - if (!p->skip_locking) { - level = btrfs_header_level(b); - if (level <= write_lock_level) { - err = btrfs_try_tree_write_lock(b); - if (!err) { - btrfs_set_path_blocking(p); - btrfs_tree_lock(b); - btrfs_clear_path_blocking(p, b, - BTRFS_WRITE_LOCK); - } - p->locks[level] = BTRFS_WRITE_LOCK; - } else { - err = btrfs_tree_read_lock_atomic(b); - if (!err) { - btrfs_set_path_blocking(p); - btrfs_tree_read_lock(b); - btrfs_clear_path_blocking(p, b, - BTRFS_READ_LOCK); - } - p->locks[level] = BTRFS_READ_LOCK; - } - p->nodes[level] = b; - } - } else { - p->slots[level] = slot; - if (ins_len > 0 && - btrfs_leaf_free_space(root, b) < ins_len) { - if (write_lock_level < 1) { - write_lock_level = 1; - btrfs_release_path(p); - goto again; - } - - btrfs_set_path_blocking(p); - err = split_leaf(trans, root, key, - p, ins_len, ret == 0); - btrfs_clear_path_blocking(p, NULL, 0); - - BUG_ON(err > 0); - if (err) { - ret = err; - goto done; - } - } - if (!p->search_for_split) - unlock_up(p, level, lowest_unlock, - min_write_lock_level, &write_lock_level); - goto done; - } - } - ret = 1; -done: - /* - * we don't really know what they plan on doing with the path - * from here on, so for now just mark it as blocking - */ - if (!p->leave_spinning) - btrfs_set_path_blocking(p); - if (ret < 0 && !p->skip_release_on_error) - btrfs_release_path(p); - return ret; -} - -/* - * Like btrfs_search_slot, this looks for a key in the given tree. It uses the - * current state of the tree together with the operations recorded in the tree - * modification log to search for the key in a previous version of this tree, as - * denoted by the time_seq parameter. - * - * Naturally, there is no support for insert, delete or cow operations. - * - * The resulting path and return value will be set up as if we called - * btrfs_search_slot at that point in time with ins_len and cow both set to 0. - */ -int btrfs_search_old_slot(struct btrfs_root *root, struct btrfs_key *key, - struct btrfs_path *p, u64 time_seq) -{ - struct extent_buffer *b; - int slot; - int ret; - int err; - int level; - int lowest_unlock = 1; - u8 lowest_level = 0; - int prev_cmp = -1; - - lowest_level = p->lowest_level; - WARN_ON(p->nodes[0] != NULL); - - if (p->search_commit_root) { - BUG_ON(time_seq); - return btrfs_search_slot(NULL, root, key, p, 0, 0); - } - -again: - b = get_old_root(root, time_seq); - level = btrfs_header_level(b); - p->locks[level] = BTRFS_READ_LOCK; - - while (b) { - level = btrfs_header_level(b); - p->nodes[level] = b; - btrfs_clear_path_blocking(p, NULL, 0); - - /* - * we have a lock on b and as long as we aren't changing - * the tree, there is no way to for the items in b to change. - * It is safe to drop the lock on our parent before we - * go through the expensive btree search on b. - */ - btrfs_unlock_up_safe(p, level + 1); - - /* - * Since we can unwind ebs we want to do a real search every - * time. - */ - prev_cmp = -1; - ret = key_search(b, key, level, &prev_cmp, &slot); - - if (level != 0) { - int dec = 0; - if (ret && slot > 0) { - dec = 1; - slot -= 1; - } - p->slots[level] = slot; - unlock_up(p, level, lowest_unlock, 0, NULL); - - if (level == lowest_level) { - if (dec) - p->slots[level]++; - goto done; - } - - err = read_block_for_search(NULL, root, p, &b, level, - slot, key, time_seq); - if (err == -EAGAIN) - goto again; - if (err) { - ret = err; - goto done; - } - - level = btrfs_header_level(b); - err = btrfs_tree_read_lock_atomic(b); - if (!err) { - btrfs_set_path_blocking(p); - btrfs_tree_read_lock(b); - btrfs_clear_path_blocking(p, b, - BTRFS_READ_LOCK); - } - b = tree_mod_log_rewind(root->fs_info, p, b, time_seq); - if (!b) { - ret = -ENOMEM; - goto done; - } - p->locks[level] = BTRFS_READ_LOCK; - p->nodes[level] = b; - } else { - p->slots[level] = slot; - unlock_up(p, level, lowest_unlock, 0, NULL); - goto done; - } - } - ret = 1; -done: - if (!p->leave_spinning) - btrfs_set_path_blocking(p); - if (ret < 0) - btrfs_release_path(p); - - return ret; -} - -/* - * helper to use instead of search slot if no exact match is needed but - * instead the next or previous item should be returned. - * When find_higher is true, the next higher item is returned, the next lower - * otherwise. - * When return_any and find_higher are both true, and no higher item is found, - * return the next lower instead. - * When return_any is true and find_higher is false, and no lower item is found, - * return the next higher instead. - * It returns 0 if any item is found, 1 if none is found (tree empty), and - * < 0 on error - */ -int btrfs_search_slot_for_read(struct btrfs_root *root, - struct btrfs_key *key, struct btrfs_path *p, - int find_higher, int return_any) -{ - int ret; - struct extent_buffer *leaf; - -again: - ret = btrfs_search_slot(NULL, root, key, p, 0, 0); - if (ret <= 0) - return ret; - /* - * a return value of 1 means the path is at the position where the - * item should be inserted. Normally this is the next bigger item, - * but in case the previous item is the last in a leaf, path points - * to the first free slot in the previous leaf, i.e. at an invalid - * item. - */ - leaf = p->nodes[0]; - - if (find_higher) { - if (p->slots[0] >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(root, p); - if (ret <= 0) - return ret; - if (!return_any) - return 1; - /* - * no higher item found, return the next - * lower instead - */ - return_any = 0; - find_higher = 0; - btrfs_release_path(p); - goto again; - } - } else { - if (p->slots[0] == 0) { - ret = btrfs_prev_leaf(root, p); - if (ret < 0) - return ret; - if (!ret) { - leaf = p->nodes[0]; - if (p->slots[0] == btrfs_header_nritems(leaf)) - p->slots[0]--; - return 0; - } - if (!return_any) - return 1; - /* - * no lower item found, return the next - * higher instead - */ - return_any = 0; - find_higher = 1; - btrfs_release_path(p); - goto again; - } else { - --p->slots[0]; - } - } - return 0; -} - -/* - * adjust the pointers going up the tree, starting at level - * making sure the right key of each node is points to 'key'. - * This is used after shifting pointers to the left, so it stops - * fixing up pointers when a given leaf/node is not in slot 0 of the - * higher levels - * - */ -static void fixup_low_keys(struct btrfs_fs_info *fs_info, - struct btrfs_path *path, - struct btrfs_disk_key *key, int level) -{ - int i; - struct extent_buffer *t; - - for (i = level; i < BTRFS_MAX_LEVEL; i++) { - int tslot = path->slots[i]; - if (!path->nodes[i]) - break; - t = path->nodes[i]; - tree_mod_log_set_node_key(fs_info, t, tslot, 1); - btrfs_set_node_key(t, key, tslot); - btrfs_mark_buffer_dirty(path->nodes[i]); - if (tslot != 0) - break; - } -} - -/* - * update item key. - * - * This function isn't completely safe. It's the caller's responsibility - * that the new key won't break the order - */ -void btrfs_set_item_key_safe(struct btrfs_fs_info *fs_info, - struct btrfs_path *path, - struct btrfs_key *new_key) -{ - struct btrfs_disk_key disk_key; - struct extent_buffer *eb; - int slot; - - eb = path->nodes[0]; - slot = path->slots[0]; - if (slot > 0) { - btrfs_item_key(eb, &disk_key, slot - 1); - BUG_ON(comp_keys(&disk_key, new_key) >= 0); - } - if (slot < btrfs_header_nritems(eb) - 1) { - btrfs_item_key(eb, &disk_key, slot + 1); - BUG_ON(comp_keys(&disk_key, new_key) <= 0); - } - - btrfs_cpu_key_to_disk(&disk_key, new_key); - btrfs_set_item_key(eb, &disk_key, slot); - btrfs_mark_buffer_dirty(eb); - if (slot == 0) - fixup_low_keys(fs_info, path, &disk_key, 1); -} - -/* - * try to push data from one node into the next node left in the - * tree. - * - * returns 0 if some ptrs were pushed left, < 0 if there was some horrible - * error, and > 0 if there was no room in the left hand block. - */ -static int push_node_left(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct extent_buffer *dst, - struct extent_buffer *src, int empty) -{ - int push_items = 0; - int src_nritems; - int dst_nritems; - int ret = 0; - - src_nritems = btrfs_header_nritems(src); - dst_nritems = btrfs_header_nritems(dst); - push_items = BTRFS_NODEPTRS_PER_BLOCK(root) - dst_nritems; - WARN_ON(btrfs_header_generation(src) != trans->transid); - WARN_ON(btrfs_header_generation(dst) != trans->transid); - - if (!empty && src_nritems <= 8) - return 1; - - if (push_items <= 0) - return 1; - - if (empty) { - push_items = min(src_nritems, push_items); - if (push_items < src_nritems) { - /* leave at least 8 pointers in the node if - * we aren't going to empty it - */ - if (src_nritems - push_items < 8) { - if (push_items <= 8) - return 1; - push_items -= 8; - } - } - } else - push_items = min(src_nritems - 8, push_items); - - ret = tree_mod_log_eb_copy(root->fs_info, dst, src, dst_nritems, 0, - push_items); - if (ret) { - btrfs_abort_transaction(trans, ret); - return ret; - } - copy_extent_buffer(dst, src, - btrfs_node_key_ptr_offset(dst_nritems), - btrfs_node_key_ptr_offset(0), - push_items * sizeof(struct btrfs_key_ptr)); - - if (push_items < src_nritems) { - /* - * don't call tree_mod_log_eb_move here, key removal was already - * fully logged by tree_mod_log_eb_copy above. - */ - memmove_extent_buffer(src, btrfs_node_key_ptr_offset(0), - btrfs_node_key_ptr_offset(push_items), - (src_nritems - push_items) * - sizeof(struct btrfs_key_ptr)); - } - btrfs_set_header_nritems(src, src_nritems - push_items); - btrfs_set_header_nritems(dst, dst_nritems + push_items); - btrfs_mark_buffer_dirty(src); - btrfs_mark_buffer_dirty(dst); - - return ret; -} - -/* - * try to push data from one node into the next node right in the - * tree. - * - * returns 0 if some ptrs were pushed, < 0 if there was some horrible - * error, and > 0 if there was no room in the right hand block. - * - * this will only push up to 1/2 the contents of the left node over - */ -static int balance_node_right(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct extent_buffer *dst, - struct extent_buffer *src) -{ - int push_items = 0; - int max_push; - int src_nritems; - int dst_nritems; - int ret = 0; - - WARN_ON(btrfs_header_generation(src) != trans->transid); - WARN_ON(btrfs_header_generation(dst) != trans->transid); - - src_nritems = btrfs_header_nritems(src); - dst_nritems = btrfs_header_nritems(dst); - push_items = BTRFS_NODEPTRS_PER_BLOCK(root) - dst_nritems; - if (push_items <= 0) - return 1; - - if (src_nritems < 4) - return 1; - - max_push = src_nritems / 2 + 1; - /* don't try to empty the node */ - if (max_push >= src_nritems) - return 1; - - if (max_push < push_items) - push_items = max_push; - - tree_mod_log_eb_move(root->fs_info, dst, push_items, 0, dst_nritems); - memmove_extent_buffer(dst, btrfs_node_key_ptr_offset(push_items), - btrfs_node_key_ptr_offset(0), - (dst_nritems) * - sizeof(struct btrfs_key_ptr)); - - ret = tree_mod_log_eb_copy(root->fs_info, dst, src, 0, - src_nritems - push_items, push_items); - if (ret) { - btrfs_abort_transaction(trans, ret); - return ret; - } - copy_extent_buffer(dst, src, - btrfs_node_key_ptr_offset(0), - btrfs_node_key_ptr_offset(src_nritems - push_items), - push_items * sizeof(struct btrfs_key_ptr)); - - btrfs_set_header_nritems(src, src_nritems - push_items); - btrfs_set_header_nritems(dst, dst_nritems + push_items); - - btrfs_mark_buffer_dirty(src); - btrfs_mark_buffer_dirty(dst); - - return ret; -} - -/* - * helper function to insert a new root level in the tree. - * A new node is allocated, and a single item is inserted to - * point to the existing root - * - * returns zero on success or < 0 on failure. - */ -static noinline int insert_new_root(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, int level) -{ - u64 lower_gen; - struct extent_buffer *lower; - struct extent_buffer *c; - struct extent_buffer *old; - struct btrfs_disk_key lower_key; - - BUG_ON(path->nodes[level]); - BUG_ON(path->nodes[level-1] != root->node); - - lower = path->nodes[level-1]; - if (level == 1) - btrfs_item_key(lower, &lower_key, 0); - else - btrfs_node_key(lower, &lower_key, 0); - - c = btrfs_alloc_tree_block(trans, root, 0, root->root_key.objectid, - &lower_key, level, root->node->start, 0); - if (IS_ERR(c)) - return PTR_ERR(c); - - root_add_used(root, root->nodesize); - - memset_extent_buffer(c, 0, 0, sizeof(struct btrfs_header)); - btrfs_set_header_nritems(c, 1); - btrfs_set_header_level(c, level); - btrfs_set_header_bytenr(c, c->start); - btrfs_set_header_generation(c, trans->transid); - btrfs_set_header_backref_rev(c, BTRFS_MIXED_BACKREF_REV); - btrfs_set_header_owner(c, root->root_key.objectid); - - write_extent_buffer(c, root->fs_info->fsid, btrfs_header_fsid(), - BTRFS_FSID_SIZE); - - write_extent_buffer(c, root->fs_info->chunk_tree_uuid, - btrfs_header_chunk_tree_uuid(c), BTRFS_UUID_SIZE); - - btrfs_set_node_key(c, &lower_key, 0); - btrfs_set_node_blockptr(c, 0, lower->start); - lower_gen = btrfs_header_generation(lower); - WARN_ON(lower_gen != trans->transid); - - btrfs_set_node_ptr_generation(c, 0, lower_gen); - - btrfs_mark_buffer_dirty(c); - - old = root->node; - tree_mod_log_set_root_pointer(root, c, 0); - rcu_assign_pointer(root->node, c); - - /* the super has an extra ref to root->node */ - free_extent_buffer(old); - - add_root_to_dirty_list(root); - extent_buffer_get(c); - path->nodes[level] = c; - path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING; - path->slots[level] = 0; - return 0; -} - -/* - * worker function to insert a single pointer in a node. - * the node should have enough room for the pointer already - * - * slot and level indicate where you want the key to go, and - * blocknr is the block the key points to. - */ -static void insert_ptr(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct btrfs_path *path, - struct btrfs_disk_key *key, u64 bytenr, - int slot, int level) -{ - struct extent_buffer *lower; - int nritems; - int ret; - - BUG_ON(!path->nodes[level]); - btrfs_assert_tree_locked(path->nodes[level]); - lower = path->nodes[level]; - nritems = btrfs_header_nritems(lower); - BUG_ON(slot > nritems); - BUG_ON(nritems == BTRFS_NODEPTRS_PER_BLOCK(root)); - if (slot != nritems) { - if (level) - tree_mod_log_eb_move(root->fs_info, lower, slot + 1, - slot, nritems - slot); - memmove_extent_buffer(lower, - btrfs_node_key_ptr_offset(slot + 1), - btrfs_node_key_ptr_offset(slot), - (nritems - slot) * sizeof(struct btrfs_key_ptr)); - } - if (level) { - ret = tree_mod_log_insert_key(root->fs_info, lower, slot, - MOD_LOG_KEY_ADD, GFP_NOFS); - BUG_ON(ret < 0); - } - btrfs_set_node_key(lower, key, slot); - btrfs_set_node_blockptr(lower, slot, bytenr); - WARN_ON(trans->transid == 0); - btrfs_set_node_ptr_generation(lower, slot, trans->transid); - btrfs_set_header_nritems(lower, nritems + 1); - btrfs_mark_buffer_dirty(lower); -} - -/* - * split the node at the specified level in path in two. - * The path is corrected to point to the appropriate node after the split - * - * Before splitting this tries to make some room in the node by pushing - * left and right, if either one works, it returns right away. - * - * returns 0 on success and < 0 on failure - */ -static noinline int split_node(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, int level) -{ - struct extent_buffer *c; - struct extent_buffer *split; - struct btrfs_disk_key disk_key; - int mid; - int ret; - u32 c_nritems; - - c = path->nodes[level]; - WARN_ON(btrfs_header_generation(c) != trans->transid); - if (c == root->node) { - /* - * trying to split the root, lets make a new one - * - * tree mod log: We don't log_removal old root in - * insert_new_root, because that root buffer will be kept as a - * normal node. We are going to log removal of half of the - * elements below with tree_mod_log_eb_copy. We're holding a - * tree lock on the buffer, which is why we cannot race with - * other tree_mod_log users. - */ - ret = insert_new_root(trans, root, path, level + 1); - if (ret) - return ret; - } else { - ret = push_nodes_for_insert(trans, root, path, level); - c = path->nodes[level]; - if (!ret && btrfs_header_nritems(c) < - BTRFS_NODEPTRS_PER_BLOCK(root) - 3) - return 0; - if (ret < 0) - return ret; - } - - c_nritems = btrfs_header_nritems(c); - mid = (c_nritems + 1) / 2; - btrfs_node_key(c, &disk_key, mid); - - split = btrfs_alloc_tree_block(trans, root, 0, root->root_key.objectid, - &disk_key, level, c->start, 0); - if (IS_ERR(split)) - return PTR_ERR(split); - - root_add_used(root, root->nodesize); - - memset_extent_buffer(split, 0, 0, sizeof(struct btrfs_header)); - btrfs_set_header_level(split, btrfs_header_level(c)); - btrfs_set_header_bytenr(split, split->start); - btrfs_set_header_generation(split, trans->transid); - btrfs_set_header_backref_rev(split, BTRFS_MIXED_BACKREF_REV); - btrfs_set_header_owner(split, root->root_key.objectid); - write_extent_buffer(split, root->fs_info->fsid, - btrfs_header_fsid(), BTRFS_FSID_SIZE); - write_extent_buffer(split, root->fs_info->chunk_tree_uuid, - btrfs_header_chunk_tree_uuid(split), - BTRFS_UUID_SIZE); - - ret = tree_mod_log_eb_copy(root->fs_info, split, c, 0, - mid, c_nritems - mid); - if (ret) { - btrfs_abort_transaction(trans, ret); - return ret; - } - copy_extent_buffer(split, c, - btrfs_node_key_ptr_offset(0), - btrfs_node_key_ptr_offset(mid), - (c_nritems - mid) * sizeof(struct btrfs_key_ptr)); - btrfs_set_header_nritems(split, c_nritems - mid); - btrfs_set_header_nritems(c, mid); - ret = 0; - - btrfs_mark_buffer_dirty(c); - btrfs_mark_buffer_dirty(split); - - insert_ptr(trans, root, path, &disk_key, split->start, - path->slots[level + 1] + 1, level + 1); - - if (path->slots[level] >= mid) { - path->slots[level] -= mid; - btrfs_tree_unlock(c); - free_extent_buffer(c); - path->nodes[level] = split; - path->slots[level + 1] += 1; - } else { - btrfs_tree_unlock(split); - free_extent_buffer(split); - } - return ret; -} - -/* - * how many bytes are required to store the items in a leaf. start - * and nr indicate which items in the leaf to check. This totals up the - * space used both by the item structs and the item data - */ -static int leaf_space_used(struct extent_buffer *l, int start, int nr) -{ - struct btrfs_item *start_item; - struct btrfs_item *end_item; - struct btrfs_map_token token; - int data_len; - int nritems = btrfs_header_nritems(l); - int end = min(nritems, start + nr) - 1; - - if (!nr) - return 0; - btrfs_init_map_token(&token); - start_item = btrfs_item_nr(start); - end_item = btrfs_item_nr(end); - data_len = btrfs_token_item_offset(l, start_item, &token) + - btrfs_token_item_size(l, start_item, &token); - data_len = data_len - btrfs_token_item_offset(l, end_item, &token); - data_len += sizeof(struct btrfs_item) * nr; - WARN_ON(data_len < 0); - return data_len; -} - -/* - * The space between the end of the leaf items and - * the start of the leaf data. IOW, how much room - * the leaf has left for both items and data - */ -noinline int btrfs_leaf_free_space(struct btrfs_root *root, - struct extent_buffer *leaf) -{ - int nritems = btrfs_header_nritems(leaf); - int ret; - ret = BTRFS_LEAF_DATA_SIZE(root) - leaf_space_used(leaf, 0, nritems); - if (ret < 0) { - btrfs_crit(root->fs_info, - "leaf free space ret %d, leaf data size %lu, used %d nritems %d", - ret, (unsigned long) BTRFS_LEAF_DATA_SIZE(root), - leaf_space_used(leaf, 0, nritems), nritems); - } - return ret; -} - -/* - * min slot controls the lowest index we're willing to push to the - * right. We'll push up to and including min_slot, but no lower - */ -static noinline int __push_leaf_right(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - int data_size, int empty, - struct extent_buffer *right, - int free_space, u32 left_nritems, - u32 min_slot) -{ - struct extent_buffer *left = path->nodes[0]; - struct extent_buffer *upper = path->nodes[1]; - struct btrfs_map_token token; - struct btrfs_disk_key disk_key; - int slot; - u32 i; - int push_space = 0; - int push_items = 0; - struct btrfs_item *item; - u32 nr; - u32 right_nritems; - u32 data_end; - u32 this_item_size; - - btrfs_init_map_token(&token); - - if (empty) - nr = 0; - else - nr = max_t(u32, 1, min_slot); - - if (path->slots[0] >= left_nritems) - push_space += data_size; - - slot = path->slots[1]; - i = left_nritems - 1; - while (i >= nr) { - item = btrfs_item_nr(i); - - if (!empty && push_items > 0) { - if (path->slots[0] > i) - break; - if (path->slots[0] == i) { - int space = btrfs_leaf_free_space(root, left); - if (space + push_space * 2 > free_space) - break; - } - } - - if (path->slots[0] == i) - push_space += data_size; - - this_item_size = btrfs_item_size(left, item); - if (this_item_size + sizeof(*item) + push_space > free_space) - break; - - push_items++; - push_space += this_item_size + sizeof(*item); - if (i == 0) - break; - i--; - } - - if (push_items == 0) - goto out_unlock; - - WARN_ON(!empty && push_items == left_nritems); - - /* push left to right */ - right_nritems = btrfs_header_nritems(right); - - push_space = btrfs_item_end_nr(left, left_nritems - push_items); - push_space -= leaf_data_end(root, left); - - /* make room in the right data area */ - data_end = leaf_data_end(root, right); - memmove_extent_buffer(right, - btrfs_leaf_data(right) + data_end - push_space, - btrfs_leaf_data(right) + data_end, - BTRFS_LEAF_DATA_SIZE(root) - data_end); - - /* copy from the left data area */ - copy_extent_buffer(right, left, btrfs_leaf_data(right) + - BTRFS_LEAF_DATA_SIZE(root) - push_space, - btrfs_leaf_data(left) + leaf_data_end(root, left), - push_space); - - memmove_extent_buffer(right, btrfs_item_nr_offset(push_items), - btrfs_item_nr_offset(0), - right_nritems * sizeof(struct btrfs_item)); - - /* copy the items from left to right */ - copy_extent_buffer(right, left, btrfs_item_nr_offset(0), - btrfs_item_nr_offset(left_nritems - push_items), - push_items * sizeof(struct btrfs_item)); - - /* update the item pointers */ - right_nritems += push_items; - btrfs_set_header_nritems(right, right_nritems); - push_space = BTRFS_LEAF_DATA_SIZE(root); - for (i = 0; i < right_nritems; i++) { - item = btrfs_item_nr(i); - push_space -= btrfs_token_item_size(right, item, &token); - btrfs_set_token_item_offset(right, item, push_space, &token); - } - - left_nritems -= push_items; - btrfs_set_header_nritems(left, left_nritems); - - if (left_nritems) - btrfs_mark_buffer_dirty(left); - else - clean_tree_block(trans, root->fs_info, left); - - btrfs_mark_buffer_dirty(right); - - btrfs_item_key(right, &disk_key, 0); - btrfs_set_node_key(upper, &disk_key, slot + 1); - btrfs_mark_buffer_dirty(upper); - - /* then fixup the leaf pointer in the path */ - if (path->slots[0] >= left_nritems) { - path->slots[0] -= left_nritems; - if (btrfs_header_nritems(path->nodes[0]) == 0) - clean_tree_block(trans, root->fs_info, path->nodes[0]); - btrfs_tree_unlock(path->nodes[0]); - free_extent_buffer(path->nodes[0]); - path->nodes[0] = right; - path->slots[1] += 1; - } else { - btrfs_tree_unlock(right); - free_extent_buffer(right); - } - return 0; - -out_unlock: - btrfs_tree_unlock(right); - free_extent_buffer(right); - return 1; -} - -/* - * push some data in the path leaf to the right, trying to free up at - * least data_size bytes. returns zero if the push worked, nonzero otherwise - * - * returns 1 if the push failed because the other node didn't have enough - * room, 0 if everything worked out and < 0 if there were major errors. - * - * this will push starting from min_slot to the end of the leaf. It won't - * push any slot lower than min_slot - */ -static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root - *root, struct btrfs_path *path, - int min_data_size, int data_size, - int empty, u32 min_slot) -{ - struct extent_buffer *left = path->nodes[0]; - struct extent_buffer *right; - struct extent_buffer *upper; - int slot; - int free_space; - u32 left_nritems; - int ret; - - if (!path->nodes[1]) - return 1; - - slot = path->slots[1]; - upper = path->nodes[1]; - if (slot >= btrfs_header_nritems(upper) - 1) - return 1; - - btrfs_assert_tree_locked(path->nodes[1]); - - right = read_node_slot(root, upper, slot + 1); - /* - * slot + 1 is not valid or we fail to read the right node, - * no big deal, just return. - */ - if (IS_ERR(right)) - return 1; - - btrfs_tree_lock(right); - btrfs_set_lock_blocking(right); - - free_space = btrfs_leaf_free_space(root, right); - if (free_space < data_size) - goto out_unlock; - - /* cow and double check */ - ret = btrfs_cow_block(trans, root, right, upper, - slot + 1, &right); - if (ret) - goto out_unlock; - - free_space = btrfs_leaf_free_space(root, right); - if (free_space < data_size) - goto out_unlock; - - left_nritems = btrfs_header_nritems(left); - if (left_nritems == 0) - goto out_unlock; - - if (path->slots[0] == left_nritems && !empty) { - /* Key greater than all keys in the leaf, right neighbor has - * enough room for it and we're not emptying our leaf to delete - * it, therefore use right neighbor to insert the new item and - * no need to touch/dirty our left leaft. */ - btrfs_tree_unlock(left); - free_extent_buffer(left); - path->nodes[0] = right; - path->slots[0] = 0; - path->slots[1]++; - return 0; - } - - return __push_leaf_right(trans, root, path, min_data_size, empty, - right, free_space, left_nritems, min_slot); -out_unlock: - btrfs_tree_unlock(right); - free_extent_buffer(right); - return 1; -} - -/* - * push some data in the path leaf to the left, trying to free up at - * least data_size bytes. returns zero if the push worked, nonzero otherwise - * - * max_slot can put a limit on how far into the leaf we'll push items. The - * item at 'max_slot' won't be touched. Use (u32)-1 to make us do all the - * items - */ -static noinline int __push_leaf_left(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, int data_size, - int empty, struct extent_buffer *left, - int free_space, u32 right_nritems, - u32 max_slot) -{ - struct btrfs_disk_key disk_key; - struct extent_buffer *right = path->nodes[0]; - int i; - int push_space = 0; - int push_items = 0; - struct btrfs_item *item; - u32 old_left_nritems; - u32 nr; - int ret = 0; - u32 this_item_size; - u32 old_left_item_size; - struct btrfs_map_token token; - - btrfs_init_map_token(&token); - - if (empty) - nr = min(right_nritems, max_slot); - else - nr = min(right_nritems - 1, max_slot); - - for (i = 0; i < nr; i++) { - item = btrfs_item_nr(i); - - if (!empty && push_items > 0) { - if (path->slots[0] < i) - break; - if (path->slots[0] == i) { - int space = btrfs_leaf_free_space(root, right); - if (space + push_space * 2 > free_space) - break; - } - } - - if (path->slots[0] == i) - push_space += data_size; - - this_item_size = btrfs_item_size(right, item); - if (this_item_size + sizeof(*item) + push_space > free_space) - break; - - push_items++; - push_space += this_item_size + sizeof(*item); - } - - if (push_items == 0) { - ret = 1; - goto out; - } - WARN_ON(!empty && push_items == btrfs_header_nritems(right)); - - /* push data from right to left */ - copy_extent_buffer(left, right, - btrfs_item_nr_offset(btrfs_header_nritems(left)), - btrfs_item_nr_offset(0), - push_items * sizeof(struct btrfs_item)); - - push_space = BTRFS_LEAF_DATA_SIZE(root) - - btrfs_item_offset_nr(right, push_items - 1); - - copy_extent_buffer(left, right, btrfs_leaf_data(left) + - leaf_data_end(root, left) - push_space, - btrfs_leaf_data(right) + - btrfs_item_offset_nr(right, push_items - 1), - push_space); - old_left_nritems = btrfs_header_nritems(left); - BUG_ON(old_left_nritems <= 0); - - old_left_item_size = btrfs_item_offset_nr(left, old_left_nritems - 1); - for (i = old_left_nritems; i < old_left_nritems + push_items; i++) { - u32 ioff; - - item = btrfs_item_nr(i); - - ioff = btrfs_token_item_offset(left, item, &token); - btrfs_set_token_item_offset(left, item, - ioff - (BTRFS_LEAF_DATA_SIZE(root) - old_left_item_size), - &token); - } - btrfs_set_header_nritems(left, old_left_nritems + push_items); - - /* fixup right node */ - if (push_items > right_nritems) - WARN(1, KERN_CRIT "push items %d nr %u\n", push_items, - right_nritems); - - if (push_items < right_nritems) { - push_space = btrfs_item_offset_nr(right, push_items - 1) - - leaf_data_end(root, right); - memmove_extent_buffer(right, btrfs_leaf_data(right) + - BTRFS_LEAF_DATA_SIZE(root) - push_space, - btrfs_leaf_data(right) + - leaf_data_end(root, right), push_space); - - memmove_extent_buffer(right, btrfs_item_nr_offset(0), - btrfs_item_nr_offset(push_items), - (btrfs_header_nritems(right) - push_items) * - sizeof(struct btrfs_item)); - } - right_nritems -= push_items; - btrfs_set_header_nritems(right, right_nritems); - push_space = BTRFS_LEAF_DATA_SIZE(root); - for (i = 0; i < right_nritems; i++) { - item = btrfs_item_nr(i); - - push_space = push_space - btrfs_token_item_size(right, - item, &token); - btrfs_set_token_item_offset(right, item, push_space, &token); - } - - btrfs_mark_buffer_dirty(left); - if (right_nritems) - btrfs_mark_buffer_dirty(right); - else - clean_tree_block(trans, root->fs_info, right); - - btrfs_item_key(right, &disk_key, 0); - fixup_low_keys(root->fs_info, path, &disk_key, 1); - - /* then fixup the leaf pointer in the path */ - if (path->slots[0] < push_items) { - path->slots[0] += old_left_nritems; - btrfs_tree_unlock(path->nodes[0]); - free_extent_buffer(path->nodes[0]); - path->nodes[0] = left; - path->slots[1] -= 1; - } else { - btrfs_tree_unlock(left); - free_extent_buffer(left); - path->slots[0] -= push_items; - } - BUG_ON(path->slots[0] < 0); - return ret; -out: - btrfs_tree_unlock(left); - free_extent_buffer(left); - return ret; -} - -/* - * push some data in the path leaf to the left, trying to free up at - * least data_size bytes. returns zero if the push worked, nonzero otherwise - * - * max_slot can put a limit on how far into the leaf we'll push items. The - * item at 'max_slot' won't be touched. Use (u32)-1 to make us push all the - * items - */ -static int push_leaf_left(struct btrfs_trans_handle *trans, struct btrfs_root - *root, struct btrfs_path *path, int min_data_size, - int data_size, int empty, u32 max_slot) -{ - struct extent_buffer *right = path->nodes[0]; - struct extent_buffer *left; - int slot; - int free_space; - u32 right_nritems; - int ret = 0; - - slot = path->slots[1]; - if (slot == 0) - return 1; - if (!path->nodes[1]) - return 1; - - right_nritems = btrfs_header_nritems(right); - if (right_nritems == 0) - return 1; - - btrfs_assert_tree_locked(path->nodes[1]); - - left = read_node_slot(root, path->nodes[1], slot - 1); - /* - * slot - 1 is not valid or we fail to read the left node, - * no big deal, just return. - */ - if (IS_ERR(left)) - return 1; - - btrfs_tree_lock(left); - btrfs_set_lock_blocking(left); - - free_space = btrfs_leaf_free_space(root, left); - if (free_space < data_size) { - ret = 1; - goto out; - } - - /* cow and double check */ - ret = btrfs_cow_block(trans, root, left, - path->nodes[1], slot - 1, &left); - if (ret) { - /* we hit -ENOSPC, but it isn't fatal here */ - if (ret == -ENOSPC) - ret = 1; - goto out; - } - - free_space = btrfs_leaf_free_space(root, left); - if (free_space < data_size) { - ret = 1; - goto out; - } - - return __push_leaf_left(trans, root, path, min_data_size, - empty, left, free_space, right_nritems, - max_slot); -out: - btrfs_tree_unlock(left); - free_extent_buffer(left); - return ret; -} - -/* - * split the path's leaf in two, making sure there is at least data_size - * available for the resulting leaf level of the path. - */ -static noinline void copy_for_split(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct extent_buffer *l, - struct extent_buffer *right, - int slot, int mid, int nritems) -{ - int data_copy_size; - int rt_data_off; - int i; - struct btrfs_disk_key disk_key; - struct btrfs_map_token token; - - btrfs_init_map_token(&token); - - nritems = nritems - mid; - btrfs_set_header_nritems(right, nritems); - data_copy_size = btrfs_item_end_nr(l, mid) - leaf_data_end(root, l); - - copy_extent_buffer(right, l, btrfs_item_nr_offset(0), - btrfs_item_nr_offset(mid), - nritems * sizeof(struct btrfs_item)); - - copy_extent_buffer(right, l, - btrfs_leaf_data(right) + BTRFS_LEAF_DATA_SIZE(root) - - data_copy_size, btrfs_leaf_data(l) + - leaf_data_end(root, l), data_copy_size); - - rt_data_off = BTRFS_LEAF_DATA_SIZE(root) - - btrfs_item_end_nr(l, mid); - - for (i = 0; i < nritems; i++) { - struct btrfs_item *item = btrfs_item_nr(i); - u32 ioff; - - ioff = btrfs_token_item_offset(right, item, &token); - btrfs_set_token_item_offset(right, item, - ioff + rt_data_off, &token); - } - - btrfs_set_header_nritems(l, mid); - btrfs_item_key(right, &disk_key, 0); - insert_ptr(trans, root, path, &disk_key, right->start, - path->slots[1] + 1, 1); - - btrfs_mark_buffer_dirty(right); - btrfs_mark_buffer_dirty(l); - BUG_ON(path->slots[0] != slot); - - if (mid <= slot) { - btrfs_tree_unlock(path->nodes[0]); - free_extent_buffer(path->nodes[0]); - path->nodes[0] = right; - path->slots[0] -= mid; - path->slots[1] += 1; - } else { - btrfs_tree_unlock(right); - free_extent_buffer(right); - } - - BUG_ON(path->slots[0] < 0); -} - -/* - * double splits happen when we need to insert a big item in the middle - * of a leaf. A double split can leave us with 3 mostly empty leaves: - * leaf: [ slots 0 - N] [ our target ] [ N + 1 - total in leaf ] - * A B C - * - * We avoid this by trying to push the items on either side of our target - * into the adjacent leaves. If all goes well we can avoid the double split - * completely. - */ -static noinline int push_for_double_split(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - int data_size) -{ - int ret; - int progress = 0; - int slot; - u32 nritems; - int space_needed = data_size; - - slot = path->slots[0]; - if (slot < btrfs_header_nritems(path->nodes[0])) - space_needed -= btrfs_leaf_free_space(root, path->nodes[0]); - - /* - * try to push all the items after our slot into the - * right leaf - */ - ret = push_leaf_right(trans, root, path, 1, space_needed, 0, slot); - if (ret < 0) - return ret; - - if (ret == 0) - progress++; - - nritems = btrfs_header_nritems(path->nodes[0]); - /* - * our goal is to get our slot at the start or end of a leaf. If - * we've done so we're done - */ - if (path->slots[0] == 0 || path->slots[0] == nritems) - return 0; - - if (btrfs_leaf_free_space(root, path->nodes[0]) >= data_size) - return 0; - - /* try to push all the items before our slot into the next leaf */ - slot = path->slots[0]; - ret = push_leaf_left(trans, root, path, 1, space_needed, 0, slot); - if (ret < 0) - return ret; - - if (ret == 0) - progress++; - - if (progress) - return 0; - return 1; -} - -/* - * split the path's leaf in two, making sure there is at least data_size - * available for the resulting leaf level of the path. - * - * returns 0 if all went well and < 0 on failure. - */ -static noinline int split_leaf(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_key *ins_key, - struct btrfs_path *path, int data_size, - int extend) -{ - struct btrfs_disk_key disk_key; - struct extent_buffer *l; - u32 nritems; - int mid; - int slot; - struct extent_buffer *right; - struct btrfs_fs_info *fs_info = root->fs_info; - int ret = 0; - int wret; - int split; - int num_doubles = 0; - int tried_avoid_double = 0; - - l = path->nodes[0]; - slot = path->slots[0]; - if (extend && data_size + btrfs_item_size_nr(l, slot) + - sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root)) - return -EOVERFLOW; - - /* first try to make some room by pushing left and right */ - if (data_size && path->nodes[1]) { - int space_needed = data_size; - - if (slot < btrfs_header_nritems(l)) - space_needed -= btrfs_leaf_free_space(root, l); - - wret = push_leaf_right(trans, root, path, space_needed, - space_needed, 0, 0); - if (wret < 0) - return wret; - if (wret) { - wret = push_leaf_left(trans, root, path, space_needed, - space_needed, 0, (u32)-1); - if (wret < 0) - return wret; - } - l = path->nodes[0]; - - /* did the pushes work? */ - if (btrfs_leaf_free_space(root, l) >= data_size) - return 0; - } - - if (!path->nodes[1]) { - ret = insert_new_root(trans, root, path, 1); - if (ret) - return ret; - } -again: - split = 1; - l = path->nodes[0]; - slot = path->slots[0]; - nritems = btrfs_header_nritems(l); - mid = (nritems + 1) / 2; - - if (mid <= slot) { - if (nritems == 1 || - leaf_space_used(l, mid, nritems - mid) + data_size > - BTRFS_LEAF_DATA_SIZE(root)) { - if (slot >= nritems) { - split = 0; - } else { - mid = slot; - if (mid != nritems && - leaf_space_used(l, mid, nritems - mid) + - data_size > BTRFS_LEAF_DATA_SIZE(root)) { - if (data_size && !tried_avoid_double) - goto push_for_double; - split = 2; - } - } - } - } else { - if (leaf_space_used(l, 0, mid) + data_size > - BTRFS_LEAF_DATA_SIZE(root)) { - if (!extend && data_size && slot == 0) { - split = 0; - } else if ((extend || !data_size) && slot == 0) { - mid = 1; - } else { - mid = slot; - if (mid != nritems && - leaf_space_used(l, mid, nritems - mid) + - data_size > BTRFS_LEAF_DATA_SIZE(root)) { - if (data_size && !tried_avoid_double) - goto push_for_double; - split = 2; - } - } - } - } - - if (split == 0) - btrfs_cpu_key_to_disk(&disk_key, ins_key); - else - btrfs_item_key(l, &disk_key, mid); - - right = btrfs_alloc_tree_block(trans, root, 0, root->root_key.objectid, - &disk_key, 0, l->start, 0); - if (IS_ERR(right)) - return PTR_ERR(right); - - root_add_used(root, root->nodesize); - - memset_extent_buffer(right, 0, 0, sizeof(struct btrfs_header)); - btrfs_set_header_bytenr(right, right->start); - btrfs_set_header_generation(right, trans->transid); - btrfs_set_header_backref_rev(right, BTRFS_MIXED_BACKREF_REV); - btrfs_set_header_owner(right, root->root_key.objectid); - btrfs_set_header_level(right, 0); - write_extent_buffer(right, fs_info->fsid, - btrfs_header_fsid(), BTRFS_FSID_SIZE); - - write_extent_buffer(right, fs_info->chunk_tree_uuid, - btrfs_header_chunk_tree_uuid(right), - BTRFS_UUID_SIZE); - - if (split == 0) { - if (mid <= slot) { - btrfs_set_header_nritems(right, 0); - insert_ptr(trans, root, path, &disk_key, right->start, - path->slots[1] + 1, 1); - btrfs_tree_unlock(path->nodes[0]); - free_extent_buffer(path->nodes[0]); - path->nodes[0] = right; - path->slots[0] = 0; - path->slots[1] += 1; - } else { - btrfs_set_header_nritems(right, 0); - insert_ptr(trans, root, path, &disk_key, right->start, - path->slots[1], 1); - btrfs_tree_unlock(path->nodes[0]); - free_extent_buffer(path->nodes[0]); - path->nodes[0] = right; - path->slots[0] = 0; - if (path->slots[1] == 0) - fixup_low_keys(fs_info, path, &disk_key, 1); - } - /* - * We create a new leaf 'right' for the required ins_len and - * we'll do btrfs_mark_buffer_dirty() on this leaf after copying - * the content of ins_len to 'right'. - */ - return ret; - } - - copy_for_split(trans, root, path, l, right, slot, mid, nritems); - - if (split == 2) { - BUG_ON(num_doubles != 0); - num_doubles++; - goto again; - } - - return 0; - -push_for_double: - push_for_double_split(trans, root, path, data_size); - tried_avoid_double = 1; - if (btrfs_leaf_free_space(root, path->nodes[0]) >= data_size) - return 0; - goto again; -} - -static noinline int setup_leaf_for_split(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, int ins_len) -{ - struct btrfs_key key; - struct extent_buffer *leaf; - struct btrfs_file_extent_item *fi; - u64 extent_len = 0; - u32 item_size; - int ret; - - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - - BUG_ON(key.type != BTRFS_EXTENT_DATA_KEY && - key.type != BTRFS_EXTENT_CSUM_KEY); - - if (btrfs_leaf_free_space(root, leaf) >= ins_len) - return 0; - - item_size = btrfs_item_size_nr(leaf, path->slots[0]); - if (key.type == BTRFS_EXTENT_DATA_KEY) { - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - extent_len = btrfs_file_extent_num_bytes(leaf, fi); - } - btrfs_release_path(path); - - path->keep_locks = 1; - path->search_for_split = 1; - ret = btrfs_search_slot(trans, root, &key, path, 0, 1); - path->search_for_split = 0; - if (ret > 0) - ret = -EAGAIN; - if (ret < 0) - goto err; - - ret = -EAGAIN; - leaf = path->nodes[0]; - /* if our item isn't there, return now */ - if (item_size != btrfs_item_size_nr(leaf, path->slots[0])) - goto err; - - /* the leaf has changed, it now has room. return now */ - if (btrfs_leaf_free_space(root, path->nodes[0]) >= ins_len) - goto err; - - if (key.type == BTRFS_EXTENT_DATA_KEY) { - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - if (extent_len != btrfs_file_extent_num_bytes(leaf, fi)) - goto err; - } - - btrfs_set_path_blocking(path); - ret = split_leaf(trans, root, &key, path, ins_len, 1); - if (ret) - goto err; - - path->keep_locks = 0; - btrfs_unlock_up_safe(path, 1); - return 0; -err: - path->keep_locks = 0; - return ret; -} - -static noinline int split_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_key *new_key, - unsigned long split_offset) -{ - struct extent_buffer *leaf; - struct btrfs_item *item; - struct btrfs_item *new_item; - int slot; - char *buf; - u32 nritems; - u32 item_size; - u32 orig_offset; - struct btrfs_disk_key disk_key; - - leaf = path->nodes[0]; - BUG_ON(btrfs_leaf_free_space(root, leaf) < sizeof(struct btrfs_item)); - - btrfs_set_path_blocking(path); - - item = btrfs_item_nr(path->slots[0]); - orig_offset = btrfs_item_offset(leaf, item); - item_size = btrfs_item_size(leaf, item); - - buf = kmalloc(item_size, GFP_NOFS); - if (!buf) - return -ENOMEM; - - read_extent_buffer(leaf, buf, btrfs_item_ptr_offset(leaf, - path->slots[0]), item_size); - - slot = path->slots[0] + 1; - nritems = btrfs_header_nritems(leaf); - if (slot != nritems) { - /* shift the items */ - memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + 1), - btrfs_item_nr_offset(slot), - (nritems - slot) * sizeof(struct btrfs_item)); - } - - btrfs_cpu_key_to_disk(&disk_key, new_key); - btrfs_set_item_key(leaf, &disk_key, slot); - - new_item = btrfs_item_nr(slot); - - btrfs_set_item_offset(leaf, new_item, orig_offset); - btrfs_set_item_size(leaf, new_item, item_size - split_offset); - - btrfs_set_item_offset(leaf, item, - orig_offset + item_size - split_offset); - btrfs_set_item_size(leaf, item, split_offset); - - btrfs_set_header_nritems(leaf, nritems + 1); - - /* write the data for the start of the original item */ - write_extent_buffer(leaf, buf, - btrfs_item_ptr_offset(leaf, path->slots[0]), - split_offset); - - /* write the data for the new item */ - write_extent_buffer(leaf, buf + split_offset, - btrfs_item_ptr_offset(leaf, slot), - item_size - split_offset); - btrfs_mark_buffer_dirty(leaf); - - BUG_ON(btrfs_leaf_free_space(root, leaf) < 0); - kfree(buf); - return 0; -} - -/* - * This function splits a single item into two items, - * giving 'new_key' to the new item and splitting the - * old one at split_offset (from the start of the item). - * - * The path may be released by this operation. After - * the split, the path is pointing to the old item. The - * new item is going to be in the same node as the old one. - * - * Note, the item being split must be smaller enough to live alone on - * a tree block with room for one extra struct btrfs_item - * - * This allows us to split the item in place, keeping a lock on the - * leaf the entire time. - */ -int btrfs_split_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_key *new_key, - unsigned long split_offset) -{ - int ret; - ret = setup_leaf_for_split(trans, root, path, - sizeof(struct btrfs_item)); - if (ret) - return ret; - - ret = split_item(trans, root, path, new_key, split_offset); - return ret; -} - -/* - * This function duplicate a item, giving 'new_key' to the new item. - * It guarantees both items live in the same tree leaf and the new item - * is contiguous with the original item. - * - * This allows us to split file extent in place, keeping a lock on the - * leaf the entire time. - */ -int btrfs_duplicate_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_key *new_key) -{ - struct extent_buffer *leaf; - int ret; - u32 item_size; - - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, path->slots[0]); - ret = setup_leaf_for_split(trans, root, path, - item_size + sizeof(struct btrfs_item)); - if (ret) - return ret; - - path->slots[0]++; - setup_items_for_insert(root, path, new_key, &item_size, - item_size, item_size + - sizeof(struct btrfs_item), 1); - leaf = path->nodes[0]; - memcpy_extent_buffer(leaf, - btrfs_item_ptr_offset(leaf, path->slots[0]), - btrfs_item_ptr_offset(leaf, path->slots[0] - 1), - item_size); - return 0; -} - -/* - * make the item pointed to by the path smaller. new_size indicates - * how small to make it, and from_end tells us if we just chop bytes - * off the end of the item or if we shift the item to chop bytes off - * the front. - */ -void btrfs_truncate_item(struct btrfs_root *root, struct btrfs_path *path, - u32 new_size, int from_end) -{ - int slot; - struct extent_buffer *leaf; - struct btrfs_item *item; - u32 nritems; - unsigned int data_end; - unsigned int old_data_start; - unsigned int old_size; - unsigned int size_diff; - int i; - struct btrfs_map_token token; - - btrfs_init_map_token(&token); - - leaf = path->nodes[0]; - slot = path->slots[0]; - - old_size = btrfs_item_size_nr(leaf, slot); - if (old_size == new_size) - return; - - nritems = btrfs_header_nritems(leaf); - data_end = leaf_data_end(root, leaf); - - old_data_start = btrfs_item_offset_nr(leaf, slot); - - size_diff = old_size - new_size; - - BUG_ON(slot < 0); - BUG_ON(slot >= nritems); - - /* - * item0..itemN ... dataN.offset..dataN.size .. data0.size - */ - /* first correct the data pointers */ - for (i = slot; i < nritems; i++) { - u32 ioff; - item = btrfs_item_nr(i); - - ioff = btrfs_token_item_offset(leaf, item, &token); - btrfs_set_token_item_offset(leaf, item, - ioff + size_diff, &token); - } - - /* shift the data */ - if (from_end) { - memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + - data_end + size_diff, btrfs_leaf_data(leaf) + - data_end, old_data_start + new_size - data_end); - } else { - struct btrfs_disk_key disk_key; - u64 offset; - - btrfs_item_key(leaf, &disk_key, slot); - - if (btrfs_disk_key_type(&disk_key) == BTRFS_EXTENT_DATA_KEY) { - unsigned long ptr; - struct btrfs_file_extent_item *fi; - - fi = btrfs_item_ptr(leaf, slot, - struct btrfs_file_extent_item); - fi = (struct btrfs_file_extent_item *)( - (unsigned long)fi - size_diff); - - if (btrfs_file_extent_type(leaf, fi) == - BTRFS_FILE_EXTENT_INLINE) { - ptr = btrfs_item_ptr_offset(leaf, slot); - memmove_extent_buffer(leaf, ptr, - (unsigned long)fi, - BTRFS_FILE_EXTENT_INLINE_DATA_START); - } - } - - memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + - data_end + size_diff, btrfs_leaf_data(leaf) + - data_end, old_data_start - data_end); - - offset = btrfs_disk_key_offset(&disk_key); - btrfs_set_disk_key_offset(&disk_key, offset + size_diff); - btrfs_set_item_key(leaf, &disk_key, slot); - if (slot == 0) - fixup_low_keys(root->fs_info, path, &disk_key, 1); - } - - item = btrfs_item_nr(slot); - btrfs_set_item_size(leaf, item, new_size); - btrfs_mark_buffer_dirty(leaf); - - if (btrfs_leaf_free_space(root, leaf) < 0) { - btrfs_print_leaf(root, leaf); - BUG(); - } -} - -/* - * make the item pointed to by the path bigger, data_size is the added size. - */ -void btrfs_extend_item(struct btrfs_root *root, struct btrfs_path *path, - u32 data_size) -{ - int slot; - struct extent_buffer *leaf; - struct btrfs_item *item; - u32 nritems; - unsigned int data_end; - unsigned int old_data; - unsigned int old_size; - int i; - struct btrfs_map_token token; - - btrfs_init_map_token(&token); - - leaf = path->nodes[0]; - - nritems = btrfs_header_nritems(leaf); - data_end = leaf_data_end(root, leaf); - - if (btrfs_leaf_free_space(root, leaf) < data_size) { - btrfs_print_leaf(root, leaf); - BUG(); - } - slot = path->slots[0]; - old_data = btrfs_item_end_nr(leaf, slot); - - BUG_ON(slot < 0); - if (slot >= nritems) { - btrfs_print_leaf(root, leaf); - btrfs_crit(root->fs_info, "slot %d too large, nritems %d", - slot, nritems); - BUG_ON(1); - } - - /* - * item0..itemN ... dataN.offset..dataN.size .. data0.size - */ - /* first correct the data pointers */ - for (i = slot; i < nritems; i++) { - u32 ioff; - item = btrfs_item_nr(i); - - ioff = btrfs_token_item_offset(leaf, item, &token); - btrfs_set_token_item_offset(leaf, item, - ioff - data_size, &token); - } - - /* shift the data */ - memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + - data_end - data_size, btrfs_leaf_data(leaf) + - data_end, old_data - data_end); - - data_end = old_data; - old_size = btrfs_item_size_nr(leaf, slot); - item = btrfs_item_nr(slot); - btrfs_set_item_size(leaf, item, old_size + data_size); - btrfs_mark_buffer_dirty(leaf); - - if (btrfs_leaf_free_space(root, leaf) < 0) { - btrfs_print_leaf(root, leaf); - BUG(); - } -} - -/* - * this is a helper for btrfs_insert_empty_items, the main goal here is - * to save stack depth by doing the bulk of the work in a function - * that doesn't call btrfs_search_slot - */ -void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path, - struct btrfs_key *cpu_key, u32 *data_size, - u32 total_data, u32 total_size, int nr) -{ - struct btrfs_item *item; - int i; - u32 nritems; - unsigned int data_end; - struct btrfs_disk_key disk_key; - struct extent_buffer *leaf; - int slot; - struct btrfs_map_token token; - - if (path->slots[0] == 0) { - btrfs_cpu_key_to_disk(&disk_key, cpu_key); - fixup_low_keys(root->fs_info, path, &disk_key, 1); - } - btrfs_unlock_up_safe(path, 1); - - btrfs_init_map_token(&token); - - leaf = path->nodes[0]; - slot = path->slots[0]; - - nritems = btrfs_header_nritems(leaf); - data_end = leaf_data_end(root, leaf); - - if (btrfs_leaf_free_space(root, leaf) < total_size) { - btrfs_print_leaf(root, leaf); - btrfs_crit(root->fs_info, - "not enough freespace need %u have %d", - total_size, btrfs_leaf_free_space(root, leaf)); - BUG(); - } - - if (slot != nritems) { - unsigned int old_data = btrfs_item_end_nr(leaf, slot); - - if (old_data < data_end) { - btrfs_print_leaf(root, leaf); - btrfs_crit(root->fs_info, - "slot %d old_data %d data_end %d", - slot, old_data, data_end); - BUG_ON(1); - } - /* - * item0..itemN ... dataN.offset..dataN.size .. data0.size - */ - /* first correct the data pointers */ - for (i = slot; i < nritems; i++) { - u32 ioff; - - item = btrfs_item_nr(i); - ioff = btrfs_token_item_offset(leaf, item, &token); - btrfs_set_token_item_offset(leaf, item, - ioff - total_data, &token); - } - /* shift the items */ - memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot + nr), - btrfs_item_nr_offset(slot), - (nritems - slot) * sizeof(struct btrfs_item)); - - /* shift the data */ - memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + - data_end - total_data, btrfs_leaf_data(leaf) + - data_end, old_data - data_end); - data_end = old_data; - } - - /* setup the item for the new data */ - for (i = 0; i < nr; i++) { - btrfs_cpu_key_to_disk(&disk_key, cpu_key + i); - btrfs_set_item_key(leaf, &disk_key, slot + i); - item = btrfs_item_nr(slot + i); - btrfs_set_token_item_offset(leaf, item, - data_end - data_size[i], &token); - data_end -= data_size[i]; - btrfs_set_token_item_size(leaf, item, data_size[i], &token); - } - - btrfs_set_header_nritems(leaf, nritems + nr); - btrfs_mark_buffer_dirty(leaf); - - if (btrfs_leaf_free_space(root, leaf) < 0) { - btrfs_print_leaf(root, leaf); - BUG(); - } -} - -/* - * Given a key and some data, insert items into the tree. - * This does all the path init required, making room in the tree if needed. - */ -int btrfs_insert_empty_items(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_key *cpu_key, u32 *data_size, - int nr) -{ - int ret = 0; - int slot; - int i; - u32 total_size = 0; - u32 total_data = 0; - - for (i = 0; i < nr; i++) - total_data += data_size[i]; - - total_size = total_data + (nr * sizeof(struct btrfs_item)); - ret = btrfs_search_slot(trans, root, cpu_key, path, total_size, 1); - if (ret == 0) - return -EEXIST; - if (ret < 0) - return ret; - - slot = path->slots[0]; - BUG_ON(slot < 0); - - setup_items_for_insert(root, path, cpu_key, data_size, - total_data, total_size, nr); - return 0; -} - -/* - * Given a key and some data, insert an item into the tree. - * This does all the path init required, making room in the tree if needed. - */ -int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root - *root, struct btrfs_key *cpu_key, void *data, u32 - data_size) -{ - int ret = 0; - struct btrfs_path *path; - struct extent_buffer *leaf; - unsigned long ptr; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size); - if (!ret) { - leaf = path->nodes[0]; - ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); - write_extent_buffer(leaf, data, ptr, data_size); - btrfs_mark_buffer_dirty(leaf); - } - btrfs_free_path(path); - return ret; -} - -/* - * delete the pointer from a given node. - * - * the tree should have been previously balanced so the deletion does not - * empty a node. - */ -static void del_ptr(struct btrfs_root *root, struct btrfs_path *path, - int level, int slot) -{ - struct extent_buffer *parent = path->nodes[level]; - u32 nritems; - int ret; - - nritems = btrfs_header_nritems(parent); - if (slot != nritems - 1) { - if (level) - tree_mod_log_eb_move(root->fs_info, parent, slot, - slot + 1, nritems - slot - 1); - memmove_extent_buffer(parent, - btrfs_node_key_ptr_offset(slot), - btrfs_node_key_ptr_offset(slot + 1), - sizeof(struct btrfs_key_ptr) * - (nritems - slot - 1)); - } else if (level) { - ret = tree_mod_log_insert_key(root->fs_info, parent, slot, - MOD_LOG_KEY_REMOVE, GFP_NOFS); - BUG_ON(ret < 0); - } - - nritems--; - btrfs_set_header_nritems(parent, nritems); - if (nritems == 0 && parent == root->node) { - BUG_ON(btrfs_header_level(root->node) != 1); - /* just turn the root into a leaf and break */ - btrfs_set_header_level(root->node, 0); - } else if (slot == 0) { - struct btrfs_disk_key disk_key; - - btrfs_node_key(parent, &disk_key, 0); - fixup_low_keys(root->fs_info, path, &disk_key, level + 1); - } - btrfs_mark_buffer_dirty(parent); -} - -/* - * a helper function to delete the leaf pointed to by path->slots[1] and - * path->nodes[1]. - * - * This deletes the pointer in path->nodes[1] and frees the leaf - * block extent. zero is returned if it all worked out, < 0 otherwise. - * - * The path must have already been setup for deleting the leaf, including - * all the proper balancing. path->nodes[1] must be locked. - */ -static noinline void btrfs_del_leaf(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct extent_buffer *leaf) -{ - WARN_ON(btrfs_header_generation(leaf) != trans->transid); - del_ptr(root, path, 1, path->slots[1]); - - /* - * btrfs_free_extent is expensive, we want to make sure we - * aren't holding any locks when we call it - */ - btrfs_unlock_up_safe(path, 0); - - root_sub_used(root, leaf->len); - - extent_buffer_get(leaf); - btrfs_free_tree_block(trans, root, leaf, 0, 1); - free_extent_buffer_stale(leaf); -} -/* - * delete the item at the leaf level in path. If that empties - * the leaf, remove it from the tree - */ -int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, - struct btrfs_path *path, int slot, int nr) -{ - struct extent_buffer *leaf; - struct btrfs_item *item; - u32 last_off; - u32 dsize = 0; - int ret = 0; - int wret; - int i; - u32 nritems; - struct btrfs_map_token token; - - btrfs_init_map_token(&token); - - leaf = path->nodes[0]; - last_off = btrfs_item_offset_nr(leaf, slot + nr - 1); - - for (i = 0; i < nr; i++) - dsize += btrfs_item_size_nr(leaf, slot + i); - - nritems = btrfs_header_nritems(leaf); - - if (slot + nr != nritems) { - int data_end = leaf_data_end(root, leaf); - - memmove_extent_buffer(leaf, btrfs_leaf_data(leaf) + - data_end + dsize, - btrfs_leaf_data(leaf) + data_end, - last_off - data_end); - - for (i = slot + nr; i < nritems; i++) { - u32 ioff; - - item = btrfs_item_nr(i); - ioff = btrfs_token_item_offset(leaf, item, &token); - btrfs_set_token_item_offset(leaf, item, - ioff + dsize, &token); - } - - memmove_extent_buffer(leaf, btrfs_item_nr_offset(slot), - btrfs_item_nr_offset(slot + nr), - sizeof(struct btrfs_item) * - (nritems - slot - nr)); - } - btrfs_set_header_nritems(leaf, nritems - nr); - nritems -= nr; - - /* delete the leaf if we've emptied it */ - if (nritems == 0) { - if (leaf == root->node) { - btrfs_set_header_level(leaf, 0); - } else { - btrfs_set_path_blocking(path); - clean_tree_block(trans, root->fs_info, leaf); - btrfs_del_leaf(trans, root, path, leaf); - } - } else { - int used = leaf_space_used(leaf, 0, nritems); - if (slot == 0) { - struct btrfs_disk_key disk_key; - - btrfs_item_key(leaf, &disk_key, 0); - fixup_low_keys(root->fs_info, path, &disk_key, 1); - } - - /* delete the leaf if it is mostly empty */ - if (used < BTRFS_LEAF_DATA_SIZE(root) / 3) { - /* push_leaf_left fixes the path. - * make sure the path still points to our leaf - * for possible call to del_ptr below - */ - slot = path->slots[1]; - extent_buffer_get(leaf); - - btrfs_set_path_blocking(path); - wret = push_leaf_left(trans, root, path, 1, 1, - 1, (u32)-1); - if (wret < 0 && wret != -ENOSPC) - ret = wret; - - if (path->nodes[0] == leaf && - btrfs_header_nritems(leaf)) { - wret = push_leaf_right(trans, root, path, 1, - 1, 1, 0); - if (wret < 0 && wret != -ENOSPC) - ret = wret; - } - - if (btrfs_header_nritems(leaf) == 0) { - path->slots[1] = slot; - btrfs_del_leaf(trans, root, path, leaf); - free_extent_buffer(leaf); - ret = 0; - } else { - /* if we're still in the path, make sure - * we're dirty. Otherwise, one of the - * push_leaf functions must have already - * dirtied this buffer - */ - if (path->nodes[0] == leaf) - btrfs_mark_buffer_dirty(leaf); - free_extent_buffer(leaf); - } - } else { - btrfs_mark_buffer_dirty(leaf); - } - } - return ret; -} - -/* - * search the tree again to find a leaf with lesser keys - * returns 0 if it found something or 1 if there are no lesser leaves. - * returns < 0 on io errors. - * - * This may release the path, and so you may lose any locks held at the - * time you call it. - */ -int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path) -{ - struct btrfs_key key; - struct btrfs_disk_key found_key; - int ret; - - btrfs_item_key_to_cpu(path->nodes[0], &key, 0); - - if (key.offset > 0) { - key.offset--; - } else if (key.type > 0) { - key.type--; - key.offset = (u64)-1; - } else if (key.objectid > 0) { - key.objectid--; - key.type = (u8)-1; - key.offset = (u64)-1; - } else { - return 1; - } - - btrfs_release_path(path); - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - return ret; - btrfs_item_key(path->nodes[0], &found_key, 0); - ret = comp_keys(&found_key, &key); - /* - * We might have had an item with the previous key in the tree right - * before we released our path. And after we released our path, that - * item might have been pushed to the first slot (0) of the leaf we - * were holding due to a tree balance. Alternatively, an item with the - * previous key can exist as the only element of a leaf (big fat item). - * Therefore account for these 2 cases, so that our callers (like - * btrfs_previous_item) don't miss an existing item with a key matching - * the previous key we computed above. - */ - if (ret <= 0) - return 0; - return 1; -} - -/* - * A helper function to walk down the tree starting at min_key, and looking - * for nodes or leaves that are have a minimum transaction id. - * This is used by the btree defrag code, and tree logging - * - * This does not cow, but it does stuff the starting key it finds back - * into min_key, so you can call btrfs_search_slot with cow=1 on the - * key and get a writable path. - * - * This does lock as it descends, and path->keep_locks should be set - * to 1 by the caller. - * - * This honors path->lowest_level to prevent descent past a given level - * of the tree. - * - * min_trans indicates the oldest transaction that you are interested - * in walking through. Any nodes or leaves older than min_trans are - * skipped over (without reading them). - * - * returns zero if something useful was found, < 0 on error and 1 if there - * was nothing in the tree that matched the search criteria. - */ -int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, - struct btrfs_path *path, - u64 min_trans) -{ - struct extent_buffer *cur; - struct btrfs_key found_key; - int slot; - int sret; - u32 nritems; - int level; - int ret = 1; - int keep_locks = path->keep_locks; - - path->keep_locks = 1; -again: - cur = btrfs_read_lock_root_node(root); - level = btrfs_header_level(cur); - WARN_ON(path->nodes[level]); - path->nodes[level] = cur; - path->locks[level] = BTRFS_READ_LOCK; - - if (btrfs_header_generation(cur) < min_trans) { - ret = 1; - goto out; - } - while (1) { - nritems = btrfs_header_nritems(cur); - level = btrfs_header_level(cur); - sret = bin_search(cur, min_key, level, &slot); - - /* at the lowest level, we're done, setup the path and exit */ - if (level == path->lowest_level) { - if (slot >= nritems) - goto find_next_key; - ret = 0; - path->slots[level] = slot; - btrfs_item_key_to_cpu(cur, &found_key, slot); - goto out; - } - if (sret && slot > 0) - slot--; - /* - * check this node pointer against the min_trans parameters. - * If it is too old, old, skip to the next one. - */ - while (slot < nritems) { - u64 gen; - - gen = btrfs_node_ptr_generation(cur, slot); - if (gen < min_trans) { - slot++; - continue; - } - break; - } -find_next_key: - /* - * we didn't find a candidate key in this node, walk forward - * and find another one - */ - if (slot >= nritems) { - path->slots[level] = slot; - btrfs_set_path_blocking(path); - sret = btrfs_find_next_key(root, path, min_key, level, - min_trans); - if (sret == 0) { - btrfs_release_path(path); - goto again; - } else { - goto out; - } - } - /* save our key for returning back */ - btrfs_node_key_to_cpu(cur, &found_key, slot); - path->slots[level] = slot; - if (level == path->lowest_level) { - ret = 0; - goto out; - } - btrfs_set_path_blocking(path); - cur = read_node_slot(root, cur, slot); - if (IS_ERR(cur)) { - ret = PTR_ERR(cur); - goto out; - } - - btrfs_tree_read_lock(cur); - - path->locks[level - 1] = BTRFS_READ_LOCK; - path->nodes[level - 1] = cur; - unlock_up(path, level, 1, 0, NULL); - btrfs_clear_path_blocking(path, NULL, 0); - } -out: - path->keep_locks = keep_locks; - if (ret == 0) { - btrfs_unlock_up_safe(path, path->lowest_level + 1); - btrfs_set_path_blocking(path); - memcpy(min_key, &found_key, sizeof(found_key)); - } - return ret; -} - -static int tree_move_down(struct btrfs_root *root, - struct btrfs_path *path, - int *level, int root_level) -{ - struct extent_buffer *eb; - - BUG_ON(*level == 0); - eb = read_node_slot(root, path->nodes[*level], path->slots[*level]); - if (IS_ERR(eb)) - return PTR_ERR(eb); - - path->nodes[*level - 1] = eb; - path->slots[*level - 1] = 0; - (*level)--; - return 0; -} - -static int tree_move_next_or_upnext(struct btrfs_root *root, - struct btrfs_path *path, - int *level, int root_level) -{ - int ret = 0; - int nritems; - nritems = btrfs_header_nritems(path->nodes[*level]); - - path->slots[*level]++; - - while (path->slots[*level] >= nritems) { - if (*level == root_level) - return -1; - - /* move upnext */ - path->slots[*level] = 0; - free_extent_buffer(path->nodes[*level]); - path->nodes[*level] = NULL; - (*level)++; - path->slots[*level]++; - - nritems = btrfs_header_nritems(path->nodes[*level]); - ret = 1; - } - return ret; -} - -/* - * Returns 1 if it had to move up and next. 0 is returned if it moved only next - * or down. - */ -static int tree_advance(struct btrfs_root *root, - struct btrfs_path *path, - int *level, int root_level, - int allow_down, - struct btrfs_key *key) -{ - int ret; - - if (*level == 0 || !allow_down) { - ret = tree_move_next_or_upnext(root, path, level, root_level); - } else { - ret = tree_move_down(root, path, level, root_level); - } - if (ret >= 0) { - if (*level == 0) - btrfs_item_key_to_cpu(path->nodes[*level], key, - path->slots[*level]); - else - btrfs_node_key_to_cpu(path->nodes[*level], key, - path->slots[*level]); - } - return ret; -} - -static int tree_compare_item(struct btrfs_root *left_root, - struct btrfs_path *left_path, - struct btrfs_path *right_path, - char *tmp_buf) -{ - int cmp; - int len1, len2; - unsigned long off1, off2; - - len1 = btrfs_item_size_nr(left_path->nodes[0], left_path->slots[0]); - len2 = btrfs_item_size_nr(right_path->nodes[0], right_path->slots[0]); - if (len1 != len2) - return 1; - - off1 = btrfs_item_ptr_offset(left_path->nodes[0], left_path->slots[0]); - off2 = btrfs_item_ptr_offset(right_path->nodes[0], - right_path->slots[0]); - - read_extent_buffer(left_path->nodes[0], tmp_buf, off1, len1); - - cmp = memcmp_extent_buffer(right_path->nodes[0], tmp_buf, off2, len1); - if (cmp) - return 1; - return 0; -} - -#define ADVANCE 1 -#define ADVANCE_ONLY_NEXT -1 - -/* - * This function compares two trees and calls the provided callback for - * every changed/new/deleted item it finds. - * If shared tree blocks are encountered, whole subtrees are skipped, making - * the compare pretty fast on snapshotted subvolumes. - * - * This currently works on commit roots only. As commit roots are read only, - * we don't do any locking. The commit roots are protected with transactions. - * Transactions are ended and rejoined when a commit is tried in between. - * - * This function checks for modifications done to the trees while comparing. - * If it detects a change, it aborts immediately. - */ -int btrfs_compare_trees(struct btrfs_root *left_root, - struct btrfs_root *right_root, - btrfs_changed_cb_t changed_cb, void *ctx) -{ - int ret; - int cmp; - struct btrfs_path *left_path = NULL; - struct btrfs_path *right_path = NULL; - struct btrfs_key left_key; - struct btrfs_key right_key; - char *tmp_buf = NULL; - int left_root_level; - int right_root_level; - int left_level; - int right_level; - int left_end_reached; - int right_end_reached; - int advance_left; - int advance_right; - u64 left_blockptr; - u64 right_blockptr; - u64 left_gen; - u64 right_gen; - - left_path = btrfs_alloc_path(); - if (!left_path) { - ret = -ENOMEM; - goto out; - } - right_path = btrfs_alloc_path(); - if (!right_path) { - ret = -ENOMEM; - goto out; - } - - tmp_buf = kmalloc(left_root->nodesize, GFP_KERNEL | __GFP_NOWARN); - if (!tmp_buf) { - tmp_buf = vmalloc(left_root->nodesize); - if (!tmp_buf) { - ret = -ENOMEM; - goto out; - } - } - - left_path->search_commit_root = 1; - left_path->skip_locking = 1; - right_path->search_commit_root = 1; - right_path->skip_locking = 1; - - /* - * Strategy: Go to the first items of both trees. Then do - * - * If both trees are at level 0 - * Compare keys of current items - * If left < right treat left item as new, advance left tree - * and repeat - * If left > right treat right item as deleted, advance right tree - * and repeat - * If left == right do deep compare of items, treat as changed if - * needed, advance both trees and repeat - * If both trees are at the same level but not at level 0 - * Compare keys of current nodes/leafs - * If left < right advance left tree and repeat - * If left > right advance right tree and repeat - * If left == right compare blockptrs of the next nodes/leafs - * If they match advance both trees but stay at the same level - * and repeat - * If they don't match advance both trees while allowing to go - * deeper and repeat - * If tree levels are different - * Advance the tree that needs it and repeat - * - * Advancing a tree means: - * If we are at level 0, try to go to the next slot. If that's not - * possible, go one level up and repeat. Stop when we found a level - * where we could go to the next slot. We may at this point be on a - * node or a leaf. - * - * If we are not at level 0 and not on shared tree blocks, go one - * level deeper. - * - * If we are not at level 0 and on shared tree blocks, go one slot to - * the right if possible or go up and right. - */ - - down_read(&left_root->fs_info->commit_root_sem); - left_level = btrfs_header_level(left_root->commit_root); - left_root_level = left_level; - left_path->nodes[left_level] = left_root->commit_root; - extent_buffer_get(left_path->nodes[left_level]); - - right_level = btrfs_header_level(right_root->commit_root); - right_root_level = right_level; - right_path->nodes[right_level] = right_root->commit_root; - extent_buffer_get(right_path->nodes[right_level]); - up_read(&left_root->fs_info->commit_root_sem); - - if (left_level == 0) - btrfs_item_key_to_cpu(left_path->nodes[left_level], - &left_key, left_path->slots[left_level]); - else - btrfs_node_key_to_cpu(left_path->nodes[left_level], - &left_key, left_path->slots[left_level]); - if (right_level == 0) - btrfs_item_key_to_cpu(right_path->nodes[right_level], - &right_key, right_path->slots[right_level]); - else - btrfs_node_key_to_cpu(right_path->nodes[right_level], - &right_key, right_path->slots[right_level]); - - left_end_reached = right_end_reached = 0; - advance_left = advance_right = 0; - - while (1) { - if (advance_left && !left_end_reached) { - ret = tree_advance(left_root, left_path, &left_level, - left_root_level, - advance_left != ADVANCE_ONLY_NEXT, - &left_key); - if (ret == -1) - left_end_reached = ADVANCE; - else if (ret < 0) - goto out; - advance_left = 0; - } - if (advance_right && !right_end_reached) { - ret = tree_advance(right_root, right_path, &right_level, - right_root_level, - advance_right != ADVANCE_ONLY_NEXT, - &right_key); - if (ret == -1) - right_end_reached = ADVANCE; - else if (ret < 0) - goto out; - advance_right = 0; - } - - if (left_end_reached && right_end_reached) { - ret = 0; - goto out; - } else if (left_end_reached) { - if (right_level == 0) { - ret = changed_cb(left_root, right_root, - left_path, right_path, - &right_key, - BTRFS_COMPARE_TREE_DELETED, - ctx); - if (ret < 0) - goto out; - } - advance_right = ADVANCE; - continue; - } else if (right_end_reached) { - if (left_level == 0) { - ret = changed_cb(left_root, right_root, - left_path, right_path, - &left_key, - BTRFS_COMPARE_TREE_NEW, - ctx); - if (ret < 0) - goto out; - } - advance_left = ADVANCE; - continue; - } - - if (left_level == 0 && right_level == 0) { - cmp = btrfs_comp_cpu_keys(&left_key, &right_key); - if (cmp < 0) { - ret = changed_cb(left_root, right_root, - left_path, right_path, - &left_key, - BTRFS_COMPARE_TREE_NEW, - ctx); - if (ret < 0) - goto out; - advance_left = ADVANCE; - } else if (cmp > 0) { - ret = changed_cb(left_root, right_root, - left_path, right_path, - &right_key, - BTRFS_COMPARE_TREE_DELETED, - ctx); - if (ret < 0) - goto out; - advance_right = ADVANCE; - } else { - enum btrfs_compare_tree_result result; - - WARN_ON(!extent_buffer_uptodate(left_path->nodes[0])); - ret = tree_compare_item(left_root, left_path, - right_path, tmp_buf); - if (ret) - result = BTRFS_COMPARE_TREE_CHANGED; - else - result = BTRFS_COMPARE_TREE_SAME; - ret = changed_cb(left_root, right_root, - left_path, right_path, - &left_key, result, ctx); - if (ret < 0) - goto out; - advance_left = ADVANCE; - advance_right = ADVANCE; - } - } else if (left_level == right_level) { - cmp = btrfs_comp_cpu_keys(&left_key, &right_key); - if (cmp < 0) { - advance_left = ADVANCE; - } else if (cmp > 0) { - advance_right = ADVANCE; - } else { - left_blockptr = btrfs_node_blockptr( - left_path->nodes[left_level], - left_path->slots[left_level]); - right_blockptr = btrfs_node_blockptr( - right_path->nodes[right_level], - right_path->slots[right_level]); - left_gen = btrfs_node_ptr_generation( - left_path->nodes[left_level], - left_path->slots[left_level]); - right_gen = btrfs_node_ptr_generation( - right_path->nodes[right_level], - right_path->slots[right_level]); - if (left_blockptr == right_blockptr && - left_gen == right_gen) { - /* - * As we're on a shared block, don't - * allow to go deeper. - */ - advance_left = ADVANCE_ONLY_NEXT; - advance_right = ADVANCE_ONLY_NEXT; - } else { - advance_left = ADVANCE; - advance_right = ADVANCE; - } - } - } else if (left_level < right_level) { - advance_right = ADVANCE; - } else { - advance_left = ADVANCE; - } - } - -out: - btrfs_free_path(left_path); - btrfs_free_path(right_path); - kvfree(tmp_buf); - return ret; -} - -/* - * this is similar to btrfs_next_leaf, but does not try to preserve - * and fixup the path. It looks for and returns the next key in the - * tree based on the current path and the min_trans parameters. - * - * 0 is returned if another key is found, < 0 if there are any errors - * and 1 is returned if there are no higher keys in the tree - * - * path->keep_locks should be set to 1 on the search made before - * calling this function. - */ -int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, - struct btrfs_key *key, int level, u64 min_trans) -{ - int slot; - struct extent_buffer *c; - - WARN_ON(!path->keep_locks); - while (level < BTRFS_MAX_LEVEL) { - if (!path->nodes[level]) - return 1; - - slot = path->slots[level] + 1; - c = path->nodes[level]; -next: - if (slot >= btrfs_header_nritems(c)) { - int ret; - int orig_lowest; - struct btrfs_key cur_key; - if (level + 1 >= BTRFS_MAX_LEVEL || - !path->nodes[level + 1]) - return 1; - - if (path->locks[level + 1]) { - level++; - continue; - } - - slot = btrfs_header_nritems(c) - 1; - if (level == 0) - btrfs_item_key_to_cpu(c, &cur_key, slot); - else - btrfs_node_key_to_cpu(c, &cur_key, slot); - - orig_lowest = path->lowest_level; - btrfs_release_path(path); - path->lowest_level = level; - ret = btrfs_search_slot(NULL, root, &cur_key, path, - 0, 0); - path->lowest_level = orig_lowest; - if (ret < 0) - return ret; - - c = path->nodes[level]; - slot = path->slots[level]; - if (ret == 0) - slot++; - goto next; - } - - if (level == 0) - btrfs_item_key_to_cpu(c, key, slot); - else { - u64 gen = btrfs_node_ptr_generation(c, slot); - - if (gen < min_trans) { - slot++; - goto next; - } - btrfs_node_key_to_cpu(c, key, slot); - } - return 0; - } - return 1; -} - -/* - * search the tree again to find a leaf with greater keys - * returns 0 if it found something or 1 if there are no greater leaves. - * returns < 0 on io errors. - */ -int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path) -{ - return btrfs_next_old_leaf(root, path, 0); -} - -int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, - u64 time_seq) -{ - int slot; - int level; - struct extent_buffer *c; - struct extent_buffer *next; - struct btrfs_key key; - u32 nritems; - int ret; - int old_spinning = path->leave_spinning; - int next_rw_lock = 0; - - nritems = btrfs_header_nritems(path->nodes[0]); - if (nritems == 0) - return 1; - - btrfs_item_key_to_cpu(path->nodes[0], &key, nritems - 1); -again: - level = 1; - next = NULL; - next_rw_lock = 0; - btrfs_release_path(path); - - path->keep_locks = 1; - path->leave_spinning = 1; - - if (time_seq) - ret = btrfs_search_old_slot(root, &key, path, time_seq); - else - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - path->keep_locks = 0; - - if (ret < 0) - return ret; - - nritems = btrfs_header_nritems(path->nodes[0]); - /* - * by releasing the path above we dropped all our locks. A balance - * could have added more items next to the key that used to be - * at the very end of the block. So, check again here and - * advance the path if there are now more items available. - */ - if (nritems > 0 && path->slots[0] < nritems - 1) { - if (ret == 0) - path->slots[0]++; - ret = 0; - goto done; - } - /* - * So the above check misses one case: - * - after releasing the path above, someone has removed the item that - * used to be at the very end of the block, and balance between leafs - * gets another one with bigger key.offset to replace it. - * - * This one should be returned as well, or we can get leaf corruption - * later(esp. in __btrfs_drop_extents()). - * - * And a bit more explanation about this check, - * with ret > 0, the key isn't found, the path points to the slot - * where it should be inserted, so the path->slots[0] item must be the - * bigger one. - */ - if (nritems > 0 && ret > 0 && path->slots[0] == nritems - 1) { - ret = 0; - goto done; - } - - while (level < BTRFS_MAX_LEVEL) { - if (!path->nodes[level]) { - ret = 1; - goto done; - } - - slot = path->slots[level] + 1; - c = path->nodes[level]; - if (slot >= btrfs_header_nritems(c)) { - level++; - if (level == BTRFS_MAX_LEVEL) { - ret = 1; - goto done; - } - continue; - } - - if (next) { - btrfs_tree_unlock_rw(next, next_rw_lock); - free_extent_buffer(next); - } - - next = c; - next_rw_lock = path->locks[level]; - ret = read_block_for_search(NULL, root, path, &next, level, - slot, &key, 0); - if (ret == -EAGAIN) - goto again; - - if (ret < 0) { - btrfs_release_path(path); - goto done; - } - - if (!path->skip_locking) { - ret = btrfs_try_tree_read_lock(next); - if (!ret && time_seq) { - /* - * If we don't get the lock, we may be racing - * with push_leaf_left, holding that lock while - * itself waiting for the leaf we've currently - * locked. To solve this situation, we give up - * on our lock and cycle. - */ - free_extent_buffer(next); - btrfs_release_path(path); - cond_resched(); - goto again; - } - if (!ret) { - btrfs_set_path_blocking(path); - btrfs_tree_read_lock(next); - btrfs_clear_path_blocking(path, next, - BTRFS_READ_LOCK); - } - next_rw_lock = BTRFS_READ_LOCK; - } - break; - } - path->slots[level] = slot; - while (1) { - level--; - c = path->nodes[level]; - if (path->locks[level]) - btrfs_tree_unlock_rw(c, path->locks[level]); - - free_extent_buffer(c); - path->nodes[level] = next; - path->slots[level] = 0; - if (!path->skip_locking) - path->locks[level] = next_rw_lock; - if (!level) - break; - - ret = read_block_for_search(NULL, root, path, &next, level, - 0, &key, 0); - if (ret == -EAGAIN) - goto again; - - if (ret < 0) { - btrfs_release_path(path); - goto done; - } - - if (!path->skip_locking) { - ret = btrfs_try_tree_read_lock(next); - if (!ret) { - btrfs_set_path_blocking(path); - btrfs_tree_read_lock(next); - btrfs_clear_path_blocking(path, next, - BTRFS_READ_LOCK); - } - next_rw_lock = BTRFS_READ_LOCK; - } - } - ret = 0; -done: - unlock_up(path, 0, 1, 0, NULL); - path->leave_spinning = old_spinning; - if (!old_spinning) - btrfs_set_path_blocking(path); - - return ret; -} - -/* - * this uses btrfs_prev_leaf to walk backwards in the tree, and keeps - * searching until it gets past min_objectid or finds an item of 'type' - * - * returns 0 if something is found, 1 if nothing was found and < 0 on error - */ -int btrfs_previous_item(struct btrfs_root *root, - struct btrfs_path *path, u64 min_objectid, - int type) -{ - struct btrfs_key found_key; - struct extent_buffer *leaf; - u32 nritems; - int ret; - - while (1) { - if (path->slots[0] == 0) { - btrfs_set_path_blocking(path); - ret = btrfs_prev_leaf(root, path); - if (ret != 0) - return ret; - } else { - path->slots[0]--; - } - leaf = path->nodes[0]; - nritems = btrfs_header_nritems(leaf); - if (nritems == 0) - return 1; - if (path->slots[0] == nritems) - path->slots[0]--; - - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - if (found_key.objectid < min_objectid) - break; - if (found_key.type == type) - return 0; - if (found_key.objectid == min_objectid && - found_key.type < type) - break; - } - return 1; -} - -/* - * search in extent tree to find a previous Metadata/Data extent item with - * min objecitd. - * - * returns 0 if something is found, 1 if nothing was found and < 0 on error - */ -int btrfs_previous_extent_item(struct btrfs_root *root, - struct btrfs_path *path, u64 min_objectid) -{ - struct btrfs_key found_key; - struct extent_buffer *leaf; - u32 nritems; - int ret; - - while (1) { - if (path->slots[0] == 0) { - btrfs_set_path_blocking(path); - ret = btrfs_prev_leaf(root, path); - if (ret != 0) - return ret; - } else { - path->slots[0]--; - } - leaf = path->nodes[0]; - nritems = btrfs_header_nritems(leaf); - if (nritems == 0) - return 1; - if (path->slots[0] == nritems) - path->slots[0]--; - - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - if (found_key.objectid < min_objectid) - break; - if (found_key.type == BTRFS_EXTENT_ITEM_KEY || - found_key.type == BTRFS_METADATA_ITEM_KEY) - return 0; - if (found_key.objectid == min_objectid && - found_key.type < BTRFS_EXTENT_ITEM_KEY) - break; - } - return 1; -} diff --git a/src/linux/fs/btrfs/ctree.h b/src/linux/fs/btrfs/ctree.h deleted file mode 100644 index 0b8ce2b..0000000 --- a/src/linux/fs/btrfs/ctree.h +++ /dev/null @@ -1,3693 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __BTRFS_CTREE__ -#define __BTRFS_CTREE__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "extent_io.h" -#include "extent_map.h" -#include "async-thread.h" - -struct btrfs_trans_handle; -struct btrfs_transaction; -struct btrfs_pending_snapshot; -extern struct kmem_cache *btrfs_trans_handle_cachep; -extern struct kmem_cache *btrfs_transaction_cachep; -extern struct kmem_cache *btrfs_bit_radix_cachep; -extern struct kmem_cache *btrfs_path_cachep; -extern struct kmem_cache *btrfs_free_space_cachep; -struct btrfs_ordered_sum; - -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS -#define STATIC noinline -#else -#define STATIC static noinline -#endif - -#define BTRFS_MAGIC 0x4D5F53665248425FULL /* ascii _BHRfS_M, no null */ - -#define BTRFS_MAX_MIRRORS 3 - -#define BTRFS_MAX_LEVEL 8 - -#define BTRFS_COMPAT_EXTENT_TREE_V0 - -/* - * the max metadata block size. This limit is somewhat artificial, - * but the memmove costs go through the roof for larger blocks. - */ -#define BTRFS_MAX_METADATA_BLOCKSIZE 65536 - -/* - * we can actually store much bigger names, but lets not confuse the rest - * of linux - */ -#define BTRFS_NAME_LEN 255 - -/* - * Theoretical limit is larger, but we keep this down to a sane - * value. That should limit greatly the possibility of collisions on - * inode ref items. - */ -#define BTRFS_LINK_MAX 65535U - -static const int btrfs_csum_sizes[] = { 4 }; - -/* four bytes for CRC32 */ -#define BTRFS_EMPTY_DIR_SIZE 0 - -/* specific to btrfs_map_block(), therefore not in include/linux/blk_types.h */ -#define REQ_GET_READ_MIRRORS (1 << 30) - -/* ioprio of readahead is set to idle */ -#define BTRFS_IOPRIO_READA (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0)) - -#define BTRFS_DIRTY_METADATA_THRESH SZ_32M - -#define BTRFS_MAX_EXTENT_SIZE SZ_128M - -struct btrfs_mapping_tree { - struct extent_map_tree map_tree; -}; - -static inline unsigned long btrfs_chunk_item_size(int num_stripes) -{ - BUG_ON(num_stripes == 0); - return sizeof(struct btrfs_chunk) + - sizeof(struct btrfs_stripe) * (num_stripes - 1); -} - -/* - * File system states - */ -#define BTRFS_FS_STATE_ERROR 0 -#define BTRFS_FS_STATE_REMOUNTING 1 -#define BTRFS_FS_STATE_TRANS_ABORTED 2 -#define BTRFS_FS_STATE_DEV_REPLACING 3 -#define BTRFS_FS_STATE_DUMMY_FS_INFO 4 - -#define BTRFS_BACKREF_REV_MAX 256 -#define BTRFS_BACKREF_REV_SHIFT 56 -#define BTRFS_BACKREF_REV_MASK (((u64)BTRFS_BACKREF_REV_MAX - 1) << \ - BTRFS_BACKREF_REV_SHIFT) - -#define BTRFS_OLD_BACKREF_REV 0 -#define BTRFS_MIXED_BACKREF_REV 1 - -/* - * every tree block (leaf or node) starts with this header. - */ -struct btrfs_header { - /* these first four must match the super block */ - u8 csum[BTRFS_CSUM_SIZE]; - u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ - __le64 bytenr; /* which block this node is supposed to live in */ - __le64 flags; - - /* allowed to be different from the super from here on down */ - u8 chunk_tree_uuid[BTRFS_UUID_SIZE]; - __le64 generation; - __le64 owner; - __le32 nritems; - u8 level; -} __attribute__ ((__packed__)); - -/* - * this is a very generous portion of the super block, giving us - * room to translate 14 chunks with 3 stripes each. - */ -#define BTRFS_SYSTEM_CHUNK_ARRAY_SIZE 2048 - -/* - * just in case we somehow lose the roots and are not able to mount, - * we store an array of the roots from previous transactions - * in the super. - */ -#define BTRFS_NUM_BACKUP_ROOTS 4 -struct btrfs_root_backup { - __le64 tree_root; - __le64 tree_root_gen; - - __le64 chunk_root; - __le64 chunk_root_gen; - - __le64 extent_root; - __le64 extent_root_gen; - - __le64 fs_root; - __le64 fs_root_gen; - - __le64 dev_root; - __le64 dev_root_gen; - - __le64 csum_root; - __le64 csum_root_gen; - - __le64 total_bytes; - __le64 bytes_used; - __le64 num_devices; - /* future */ - __le64 unused_64[4]; - - u8 tree_root_level; - u8 chunk_root_level; - u8 extent_root_level; - u8 fs_root_level; - u8 dev_root_level; - u8 csum_root_level; - /* future and to align */ - u8 unused_8[10]; -} __attribute__ ((__packed__)); - -/* - * the super block basically lists the main trees of the FS - * it currently lacks any block count etc etc - */ -struct btrfs_super_block { - u8 csum[BTRFS_CSUM_SIZE]; - /* the first 4 fields must match struct btrfs_header */ - u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ - __le64 bytenr; /* this block number */ - __le64 flags; - - /* allowed to be different from the btrfs_header from here own down */ - __le64 magic; - __le64 generation; - __le64 root; - __le64 chunk_root; - __le64 log_root; - - /* this will help find the new super based on the log root */ - __le64 log_root_transid; - __le64 total_bytes; - __le64 bytes_used; - __le64 root_dir_objectid; - __le64 num_devices; - __le32 sectorsize; - __le32 nodesize; - __le32 __unused_leafsize; - __le32 stripesize; - __le32 sys_chunk_array_size; - __le64 chunk_root_generation; - __le64 compat_flags; - __le64 compat_ro_flags; - __le64 incompat_flags; - __le16 csum_type; - u8 root_level; - u8 chunk_root_level; - u8 log_root_level; - struct btrfs_dev_item dev_item; - - char label[BTRFS_LABEL_SIZE]; - - __le64 cache_generation; - __le64 uuid_tree_generation; - - /* future expansion */ - __le64 reserved[30]; - u8 sys_chunk_array[BTRFS_SYSTEM_CHUNK_ARRAY_SIZE]; - struct btrfs_root_backup super_roots[BTRFS_NUM_BACKUP_ROOTS]; -} __attribute__ ((__packed__)); - -/* - * Compat flags that we support. If any incompat flags are set other than the - * ones specified below then we will fail to mount - */ -#define BTRFS_FEATURE_COMPAT_SUPP 0ULL -#define BTRFS_FEATURE_COMPAT_SAFE_SET 0ULL -#define BTRFS_FEATURE_COMPAT_SAFE_CLEAR 0ULL - -#define BTRFS_FEATURE_COMPAT_RO_SUPP \ - (BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE | \ - BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID) - -#define BTRFS_FEATURE_COMPAT_RO_SAFE_SET 0ULL -#define BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR 0ULL - -#define BTRFS_FEATURE_INCOMPAT_SUPP \ - (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF | \ - BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL | \ - BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS | \ - BTRFS_FEATURE_INCOMPAT_BIG_METADATA | \ - BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO | \ - BTRFS_FEATURE_INCOMPAT_RAID56 | \ - BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF | \ - BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA | \ - BTRFS_FEATURE_INCOMPAT_NO_HOLES) - -#define BTRFS_FEATURE_INCOMPAT_SAFE_SET \ - (BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF) -#define BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR 0ULL - -/* - * A leaf is full of items. offset and size tell us where to find - * the item in the leaf (relative to the start of the data area) - */ -struct btrfs_item { - struct btrfs_disk_key key; - __le32 offset; - __le32 size; -} __attribute__ ((__packed__)); - -/* - * leaves have an item area and a data area: - * [item0, item1....itemN] [free space] [dataN...data1, data0] - * - * The data is separate from the items to get the keys closer together - * during searches. - */ -struct btrfs_leaf { - struct btrfs_header header; - struct btrfs_item items[]; -} __attribute__ ((__packed__)); - -/* - * all non-leaf blocks are nodes, they hold only keys and pointers to - * other blocks - */ -struct btrfs_key_ptr { - struct btrfs_disk_key key; - __le64 blockptr; - __le64 generation; -} __attribute__ ((__packed__)); - -struct btrfs_node { - struct btrfs_header header; - struct btrfs_key_ptr ptrs[]; -} __attribute__ ((__packed__)); - -/* - * btrfs_paths remember the path taken from the root down to the leaf. - * level 0 is always the leaf, and nodes[1...BTRFS_MAX_LEVEL] will point - * to any other levels that are present. - * - * The slots array records the index of the item or block pointer - * used while walking the tree. - */ -enum { READA_NONE = 0, READA_BACK, READA_FORWARD }; -struct btrfs_path { - struct extent_buffer *nodes[BTRFS_MAX_LEVEL]; - int slots[BTRFS_MAX_LEVEL]; - /* if there is real range locking, this locks field will change */ - u8 locks[BTRFS_MAX_LEVEL]; - u8 reada; - /* keep some upper locks as we walk down */ - u8 lowest_level; - - /* - * set by btrfs_split_item, tells search_slot to keep all locks - * and to force calls to keep space in the nodes - */ - unsigned int search_for_split:1; - unsigned int keep_locks:1; - unsigned int skip_locking:1; - unsigned int leave_spinning:1; - unsigned int search_commit_root:1; - unsigned int need_commit_sem:1; - unsigned int skip_release_on_error:1; -}; -#define BTRFS_MAX_EXTENT_ITEM_SIZE(r) ((BTRFS_LEAF_DATA_SIZE(r) >> 4) - \ - sizeof(struct btrfs_item)) -struct btrfs_dev_replace { - u64 replace_state; /* see #define above */ - u64 time_started; /* seconds since 1-Jan-1970 */ - u64 time_stopped; /* seconds since 1-Jan-1970 */ - atomic64_t num_write_errors; - atomic64_t num_uncorrectable_read_errors; - - u64 cursor_left; - u64 committed_cursor_left; - u64 cursor_left_last_write_of_item; - u64 cursor_right; - - u64 cont_reading_from_srcdev_mode; /* see #define above */ - - int is_valid; - int item_needs_writeback; - struct btrfs_device *srcdev; - struct btrfs_device *tgtdev; - - pid_t lock_owner; - atomic_t nesting_level; - struct mutex lock_finishing_cancel_unmount; - rwlock_t lock; - atomic_t read_locks; - atomic_t blocking_readers; - wait_queue_head_t read_lock_wq; - - struct btrfs_scrub_progress scrub_progress; -}; - -/* For raid type sysfs entries */ -struct raid_kobject { - int raid_type; - struct kobject kobj; -}; - -struct btrfs_space_info { - spinlock_t lock; - - u64 total_bytes; /* total bytes in the space, - this doesn't take mirrors into account */ - u64 bytes_used; /* total bytes used, - this doesn't take mirrors into account */ - u64 bytes_pinned; /* total bytes pinned, will be freed when the - transaction finishes */ - u64 bytes_reserved; /* total bytes the allocator has reserved for - current allocations */ - u64 bytes_may_use; /* number of bytes that may be used for - delalloc/allocations */ - u64 bytes_readonly; /* total bytes that are read only */ - - u64 max_extent_size; /* This will hold the maximum extent size of - the space info if we had an ENOSPC in the - allocator. */ - - unsigned int full:1; /* indicates that we cannot allocate any more - chunks for this space */ - unsigned int chunk_alloc:1; /* set if we are allocating a chunk */ - - unsigned int flush:1; /* set if we are trying to make space */ - - unsigned int force_alloc; /* set if we need to force a chunk - alloc for this space */ - - u64 disk_used; /* total bytes used on disk */ - u64 disk_total; /* total bytes on disk, takes mirrors into - account */ - - u64 flags; - - /* - * bytes_pinned is kept in line with what is actually pinned, as in - * we've called update_block_group and dropped the bytes_used counter - * and increased the bytes_pinned counter. However this means that - * bytes_pinned does not reflect the bytes that will be pinned once the - * delayed refs are flushed, so this counter is inc'ed every time we - * call btrfs_free_extent so it is a realtime count of what will be - * freed once the transaction is committed. It will be zeroed every - * time the transaction commits. - */ - struct percpu_counter total_bytes_pinned; - - struct list_head list; - /* Protected by the spinlock 'lock'. */ - struct list_head ro_bgs; - struct list_head priority_tickets; - struct list_head tickets; - u64 tickets_id; - - struct rw_semaphore groups_sem; - /* for block groups in our same type */ - struct list_head block_groups[BTRFS_NR_RAID_TYPES]; - wait_queue_head_t wait; - - struct kobject kobj; - struct kobject *block_group_kobjs[BTRFS_NR_RAID_TYPES]; -}; - -#define BTRFS_BLOCK_RSV_GLOBAL 1 -#define BTRFS_BLOCK_RSV_DELALLOC 2 -#define BTRFS_BLOCK_RSV_TRANS 3 -#define BTRFS_BLOCK_RSV_CHUNK 4 -#define BTRFS_BLOCK_RSV_DELOPS 5 -#define BTRFS_BLOCK_RSV_EMPTY 6 -#define BTRFS_BLOCK_RSV_TEMP 7 - -struct btrfs_block_rsv { - u64 size; - u64 reserved; - struct btrfs_space_info *space_info; - spinlock_t lock; - unsigned short full; - unsigned short type; - unsigned short failfast; -}; - -/* - * free clusters are used to claim free space in relatively large chunks, - * allowing us to do less seeky writes. They are used for all metadata - * allocations and data allocations in ssd mode. - */ -struct btrfs_free_cluster { - spinlock_t lock; - spinlock_t refill_lock; - struct rb_root root; - - /* largest extent in this cluster */ - u64 max_size; - - /* first extent starting offset */ - u64 window_start; - - /* We did a full search and couldn't create a cluster */ - bool fragmented; - - struct btrfs_block_group_cache *block_group; - /* - * when a cluster is allocated from a block group, we put the - * cluster onto a list in the block group so that it can - * be freed before the block group is freed. - */ - struct list_head block_group_list; -}; - -enum btrfs_caching_type { - BTRFS_CACHE_NO = 0, - BTRFS_CACHE_STARTED = 1, - BTRFS_CACHE_FAST = 2, - BTRFS_CACHE_FINISHED = 3, - BTRFS_CACHE_ERROR = 4, -}; - -enum btrfs_disk_cache_state { - BTRFS_DC_WRITTEN = 0, - BTRFS_DC_ERROR = 1, - BTRFS_DC_CLEAR = 2, - BTRFS_DC_SETUP = 3, -}; - -struct btrfs_caching_control { - struct list_head list; - struct mutex mutex; - wait_queue_head_t wait; - struct btrfs_work work; - struct btrfs_block_group_cache *block_group; - u64 progress; - atomic_t count; -}; - -/* Once caching_thread() finds this much free space, it will wake up waiters. */ -#define CACHING_CTL_WAKE_UP (1024 * 1024 * 2) - -struct btrfs_io_ctl { - void *cur, *orig; - struct page *page; - struct page **pages; - struct btrfs_root *root; - struct inode *inode; - unsigned long size; - int index; - int num_pages; - int entries; - int bitmaps; - unsigned check_crcs:1; -}; - -struct btrfs_block_group_cache { - struct btrfs_key key; - struct btrfs_block_group_item item; - struct btrfs_fs_info *fs_info; - struct inode *inode; - spinlock_t lock; - u64 pinned; - u64 reserved; - u64 delalloc_bytes; - u64 bytes_super; - u64 flags; - u64 cache_generation; - u32 sectorsize; - - /* - * If the free space extent count exceeds this number, convert the block - * group to bitmaps. - */ - u32 bitmap_high_thresh; - - /* - * If the free space extent count drops below this number, convert the - * block group back to extents. - */ - u32 bitmap_low_thresh; - - /* - * It is just used for the delayed data space allocation because - * only the data space allocation and the relative metadata update - * can be done cross the transaction. - */ - struct rw_semaphore data_rwsem; - - /* for raid56, this is a full stripe, without parity */ - unsigned long full_stripe_len; - - unsigned int ro; - unsigned int iref:1; - unsigned int has_caching_ctl:1; - unsigned int removed:1; - - int disk_cache_state; - - /* cache tracking stuff */ - int cached; - struct btrfs_caching_control *caching_ctl; - u64 last_byte_to_unpin; - - struct btrfs_space_info *space_info; - - /* free space cache stuff */ - struct btrfs_free_space_ctl *free_space_ctl; - - /* block group cache stuff */ - struct rb_node cache_node; - - /* for block groups in the same raid type */ - struct list_head list; - - /* usage count */ - atomic_t count; - - /* List of struct btrfs_free_clusters for this block group. - * Today it will only have one thing on it, but that may change - */ - struct list_head cluster_list; - - /* For delayed block group creation or deletion of empty block groups */ - struct list_head bg_list; - - /* For read-only block groups */ - struct list_head ro_list; - - atomic_t trimming; - - /* For dirty block groups */ - struct list_head dirty_list; - struct list_head io_list; - - struct btrfs_io_ctl io_ctl; - - /* - * Incremented when doing extent allocations and holding a read lock - * on the space_info's groups_sem semaphore. - * Decremented when an ordered extent that represents an IO against this - * block group's range is created (after it's added to its inode's - * root's list of ordered extents) or immediately after the allocation - * if it's a metadata extent or fallocate extent (for these cases we - * don't create ordered extents). - */ - atomic_t reservations; - - /* - * Incremented while holding the spinlock *lock* by a task checking if - * it can perform a nocow write (incremented if the value for the *ro* - * field is 0). Decremented by such tasks once they create an ordered - * extent or before that if some error happens before reaching that step. - * This is to prevent races between block group relocation and nocow - * writes through direct IO. - */ - atomic_t nocow_writers; - - /* Lock for free space tree operations. */ - struct mutex free_space_lock; - - /* - * Does the block group need to be added to the free space tree? - * Protected by free_space_lock. - */ - int needs_free_space; -}; - -/* delayed seq elem */ -struct seq_list { - struct list_head list; - u64 seq; -}; - -#define SEQ_LIST_INIT(name) { .list = LIST_HEAD_INIT((name).list), .seq = 0 } - -enum btrfs_orphan_cleanup_state { - ORPHAN_CLEANUP_STARTED = 1, - ORPHAN_CLEANUP_DONE = 2, -}; - -/* used by the raid56 code to lock stripes for read/modify/write */ -struct btrfs_stripe_hash { - struct list_head hash_list; - wait_queue_head_t wait; - spinlock_t lock; -}; - -/* used by the raid56 code to lock stripes for read/modify/write */ -struct btrfs_stripe_hash_table { - struct list_head stripe_cache; - spinlock_t cache_lock; - int cache_size; - struct btrfs_stripe_hash table[]; -}; - -#define BTRFS_STRIPE_HASH_TABLE_BITS 11 - -void btrfs_init_async_reclaim_work(struct work_struct *work); - -/* fs_info */ -struct reloc_control; -struct btrfs_device; -struct btrfs_fs_devices; -struct btrfs_balance_control; -struct btrfs_delayed_root; - -#define BTRFS_FS_BARRIER 1 -#define BTRFS_FS_CLOSING_START 2 -#define BTRFS_FS_CLOSING_DONE 3 -#define BTRFS_FS_LOG_RECOVERING 4 -#define BTRFS_FS_OPEN 5 -#define BTRFS_FS_QUOTA_ENABLED 6 -#define BTRFS_FS_QUOTA_ENABLING 7 -#define BTRFS_FS_QUOTA_DISABLING 8 -#define BTRFS_FS_UPDATE_UUID_TREE_GEN 9 -#define BTRFS_FS_CREATING_FREE_SPACE_TREE 10 -#define BTRFS_FS_BTREE_ERR 11 -#define BTRFS_FS_LOG1_ERR 12 -#define BTRFS_FS_LOG2_ERR 13 - -struct btrfs_fs_info { - u8 fsid[BTRFS_FSID_SIZE]; - u8 chunk_tree_uuid[BTRFS_UUID_SIZE]; - unsigned long flags; - struct btrfs_root *extent_root; - struct btrfs_root *tree_root; - struct btrfs_root *chunk_root; - struct btrfs_root *dev_root; - struct btrfs_root *fs_root; - struct btrfs_root *csum_root; - struct btrfs_root *quota_root; - struct btrfs_root *uuid_root; - struct btrfs_root *free_space_root; - - /* the log root tree is a directory of all the other log roots */ - struct btrfs_root *log_root_tree; - - spinlock_t fs_roots_radix_lock; - struct radix_tree_root fs_roots_radix; - - /* block group cache stuff */ - spinlock_t block_group_cache_lock; - u64 first_logical_byte; - struct rb_root block_group_cache_tree; - - /* keep track of unallocated space */ - spinlock_t free_chunk_lock; - u64 free_chunk_space; - - struct extent_io_tree freed_extents[2]; - struct extent_io_tree *pinned_extents; - - /* logical->physical extent mapping */ - struct btrfs_mapping_tree mapping_tree; - - /* - * block reservation for extent, checksum, root tree and - * delayed dir index item - */ - struct btrfs_block_rsv global_block_rsv; - /* block reservation for delay allocation */ - struct btrfs_block_rsv delalloc_block_rsv; - /* block reservation for metadata operations */ - struct btrfs_block_rsv trans_block_rsv; - /* block reservation for chunk tree */ - struct btrfs_block_rsv chunk_block_rsv; - /* block reservation for delayed operations */ - struct btrfs_block_rsv delayed_block_rsv; - - struct btrfs_block_rsv empty_block_rsv; - - u64 generation; - u64 last_trans_committed; - u64 avg_delayed_ref_runtime; - - /* - * this is updated to the current trans every time a full commit - * is required instead of the faster short fsync log commits - */ - u64 last_trans_log_full_commit; - unsigned long mount_opt; - /* - * Track requests for actions that need to be done during transaction - * commit (like for some mount options). - */ - unsigned long pending_changes; - unsigned long compress_type:4; - int commit_interval; - /* - * It is a suggestive number, the read side is safe even it gets a - * wrong number because we will write out the data into a regular - * extent. The write side(mount/remount) is under ->s_umount lock, - * so it is also safe. - */ - u64 max_inline; - /* - * Protected by ->chunk_mutex and sb->s_umount. - * - * The reason that we use two lock to protect it is because only - * remount and mount operations can change it and these two operations - * are under sb->s_umount, but the read side (chunk allocation) can not - * acquire sb->s_umount or the deadlock would happen. So we use two - * locks to protect it. On the write side, we must acquire two locks, - * and on the read side, we just need acquire one of them. - */ - u64 alloc_start; - struct btrfs_transaction *running_transaction; - wait_queue_head_t transaction_throttle; - wait_queue_head_t transaction_wait; - wait_queue_head_t transaction_blocked_wait; - wait_queue_head_t async_submit_wait; - - /* - * Used to protect the incompat_flags, compat_flags, compat_ro_flags - * when they are updated. - * - * Because we do not clear the flags for ever, so we needn't use - * the lock on the read side. - * - * We also needn't use the lock when we mount the fs, because - * there is no other task which will update the flag. - */ - spinlock_t super_lock; - struct btrfs_super_block *super_copy; - struct btrfs_super_block *super_for_commit; - struct block_device *__bdev; - struct super_block *sb; - struct inode *btree_inode; - struct backing_dev_info bdi; - struct mutex tree_log_mutex; - struct mutex transaction_kthread_mutex; - struct mutex cleaner_mutex; - struct mutex chunk_mutex; - struct mutex volume_mutex; - - /* - * this is taken to make sure we don't set block groups ro after - * the free space cache has been allocated on them - */ - struct mutex ro_block_group_mutex; - - /* this is used during read/modify/write to make sure - * no two ios are trying to mod the same stripe at the same - * time - */ - struct btrfs_stripe_hash_table *stripe_hash_table; - - /* - * this protects the ordered operations list only while we are - * processing all of the entries on it. This way we make - * sure the commit code doesn't find the list temporarily empty - * because another function happens to be doing non-waiting preflush - * before jumping into the main commit. - */ - struct mutex ordered_operations_mutex; - - struct rw_semaphore commit_root_sem; - - struct rw_semaphore cleanup_work_sem; - - struct rw_semaphore subvol_sem; - struct srcu_struct subvol_srcu; - - spinlock_t trans_lock; - /* - * the reloc mutex goes with the trans lock, it is taken - * during commit to protect us from the relocation code - */ - struct mutex reloc_mutex; - - struct list_head trans_list; - struct list_head dead_roots; - struct list_head caching_block_groups; - - spinlock_t delayed_iput_lock; - struct list_head delayed_iputs; - struct mutex cleaner_delayed_iput_mutex; - - /* this protects tree_mod_seq_list */ - spinlock_t tree_mod_seq_lock; - atomic64_t tree_mod_seq; - struct list_head tree_mod_seq_list; - - /* this protects tree_mod_log */ - rwlock_t tree_mod_log_lock; - struct rb_root tree_mod_log; - - atomic_t nr_async_submits; - atomic_t async_submit_draining; - atomic_t nr_async_bios; - atomic_t async_delalloc_pages; - atomic_t open_ioctl_trans; - - /* - * this is used to protect the following list -- ordered_roots. - */ - spinlock_t ordered_root_lock; - - /* - * all fs/file tree roots in which there are data=ordered extents - * pending writeback are added into this list. - * - * these can span multiple transactions and basically include - * every dirty data page that isn't from nodatacow - */ - struct list_head ordered_roots; - - struct mutex delalloc_root_mutex; - spinlock_t delalloc_root_lock; - /* all fs/file tree roots that have delalloc inodes. */ - struct list_head delalloc_roots; - - /* - * there is a pool of worker threads for checksumming during writes - * and a pool for checksumming after reads. This is because readers - * can run with FS locks held, and the writers may be waiting for - * those locks. We don't want ordering in the pending list to cause - * deadlocks, and so the two are serviced separately. - * - * A third pool does submit_bio to avoid deadlocking with the other - * two - */ - struct btrfs_workqueue *workers; - struct btrfs_workqueue *delalloc_workers; - struct btrfs_workqueue *flush_workers; - struct btrfs_workqueue *endio_workers; - struct btrfs_workqueue *endio_meta_workers; - struct btrfs_workqueue *endio_raid56_workers; - struct btrfs_workqueue *endio_repair_workers; - struct btrfs_workqueue *rmw_workers; - struct btrfs_workqueue *endio_meta_write_workers; - struct btrfs_workqueue *endio_write_workers; - struct btrfs_workqueue *endio_freespace_worker; - struct btrfs_workqueue *submit_workers; - struct btrfs_workqueue *caching_workers; - struct btrfs_workqueue *readahead_workers; - - /* - * fixup workers take dirty pages that didn't properly go through - * the cow mechanism and make them safe to write. It happens - * for the sys_munmap function call path - */ - struct btrfs_workqueue *fixup_workers; - struct btrfs_workqueue *delayed_workers; - - /* the extent workers do delayed refs on the extent allocation tree */ - struct btrfs_workqueue *extent_workers; - struct task_struct *transaction_kthread; - struct task_struct *cleaner_kthread; - int thread_pool_size; - - struct kobject *space_info_kobj; - - u64 total_pinned; - - /* used to keep from writing metadata until there is a nice batch */ - struct percpu_counter dirty_metadata_bytes; - struct percpu_counter delalloc_bytes; - s32 dirty_metadata_batch; - s32 delalloc_batch; - - struct list_head dirty_cowonly_roots; - - struct btrfs_fs_devices *fs_devices; - - /* - * the space_info list is almost entirely read only. It only changes - * when we add a new raid type to the FS, and that happens - * very rarely. RCU is used to protect it. - */ - struct list_head space_info; - - struct btrfs_space_info *data_sinfo; - - struct reloc_control *reloc_ctl; - - /* data_alloc_cluster is only used in ssd mode */ - struct btrfs_free_cluster data_alloc_cluster; - - /* all metadata allocations go through this cluster */ - struct btrfs_free_cluster meta_alloc_cluster; - - /* auto defrag inodes go here */ - spinlock_t defrag_inodes_lock; - struct rb_root defrag_inodes; - atomic_t defrag_running; - - /* Used to protect avail_{data, metadata, system}_alloc_bits */ - seqlock_t profiles_lock; - /* - * these three are in extended format (availability of single - * chunks is denoted by BTRFS_AVAIL_ALLOC_BIT_SINGLE bit, other - * types are denoted by corresponding BTRFS_BLOCK_GROUP_* bits) - */ - u64 avail_data_alloc_bits; - u64 avail_metadata_alloc_bits; - u64 avail_system_alloc_bits; - - /* restriper state */ - spinlock_t balance_lock; - struct mutex balance_mutex; - atomic_t balance_running; - atomic_t balance_pause_req; - atomic_t balance_cancel_req; - struct btrfs_balance_control *balance_ctl; - wait_queue_head_t balance_wait_q; - - unsigned data_chunk_allocations; - unsigned metadata_ratio; - - void *bdev_holder; - - /* private scrub information */ - struct mutex scrub_lock; - atomic_t scrubs_running; - atomic_t scrub_pause_req; - atomic_t scrubs_paused; - atomic_t scrub_cancel_req; - wait_queue_head_t scrub_pause_wait; - int scrub_workers_refcnt; - struct btrfs_workqueue *scrub_workers; - struct btrfs_workqueue *scrub_wr_completion_workers; - struct btrfs_workqueue *scrub_nocow_workers; - struct btrfs_workqueue *scrub_parity_workers; - -#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY - u32 check_integrity_print_mask; -#endif - /* is qgroup tracking in a consistent state? */ - u64 qgroup_flags; - - /* holds configuration and tracking. Protected by qgroup_lock */ - struct rb_root qgroup_tree; - struct rb_root qgroup_op_tree; - spinlock_t qgroup_lock; - spinlock_t qgroup_op_lock; - atomic_t qgroup_op_seq; - - /* - * used to avoid frequently calling ulist_alloc()/ulist_free() - * when doing qgroup accounting, it must be protected by qgroup_lock. - */ - struct ulist *qgroup_ulist; - - /* protect user change for quota operations */ - struct mutex qgroup_ioctl_lock; - - /* list of dirty qgroups to be written at next commit */ - struct list_head dirty_qgroups; - - /* used by qgroup for an efficient tree traversal */ - u64 qgroup_seq; - - /* qgroup rescan items */ - struct mutex qgroup_rescan_lock; /* protects the progress item */ - struct btrfs_key qgroup_rescan_progress; - struct btrfs_workqueue *qgroup_rescan_workers; - struct completion qgroup_rescan_completion; - struct btrfs_work qgroup_rescan_work; - bool qgroup_rescan_running; /* protected by qgroup_rescan_lock */ - - /* filesystem state */ - unsigned long fs_state; - - struct btrfs_delayed_root *delayed_root; - - /* readahead tree */ - spinlock_t reada_lock; - struct radix_tree_root reada_tree; - - /* readahead works cnt */ - atomic_t reada_works_cnt; - - /* Extent buffer radix tree */ - spinlock_t buffer_lock; - struct radix_tree_root buffer_radix; - - /* next backup root to be overwritten */ - int backup_root_index; - - int num_tolerated_disk_barrier_failures; - - /* device replace state */ - struct btrfs_dev_replace dev_replace; - - atomic_t mutually_exclusive_operation_running; - - struct percpu_counter bio_counter; - wait_queue_head_t replace_wait; - - struct semaphore uuid_tree_rescan_sem; - - /* Used to reclaim the metadata space in the background. */ - struct work_struct async_reclaim_work; - - spinlock_t unused_bgs_lock; - struct list_head unused_bgs; - struct mutex unused_bg_unpin_mutex; - struct mutex delete_unused_bgs_mutex; - - /* For btrfs to record security options */ - struct security_mnt_opts security_opts; - - /* - * Chunks that can't be freed yet (under a trim/discard operation) - * and will be latter freed. Protected by fs_info->chunk_mutex. - */ - struct list_head pinned_chunks; - - /* Used to record internally whether fs has been frozen */ - int fs_frozen; -}; - -struct btrfs_subvolume_writers { - struct percpu_counter counter; - wait_queue_head_t wait; -}; - -/* - * The state of btrfs root - */ -/* - * btrfs_record_root_in_trans is a multi-step process, - * and it can race with the balancing code. But the - * race is very small, and only the first time the root - * is added to each transaction. So IN_TRANS_SETUP - * is used to tell us when more checks are required - */ -#define BTRFS_ROOT_IN_TRANS_SETUP 0 -#define BTRFS_ROOT_REF_COWS 1 -#define BTRFS_ROOT_TRACK_DIRTY 2 -#define BTRFS_ROOT_IN_RADIX 3 -#define BTRFS_ROOT_ORPHAN_ITEM_INSERTED 4 -#define BTRFS_ROOT_DEFRAG_RUNNING 5 -#define BTRFS_ROOT_FORCE_COW 6 -#define BTRFS_ROOT_MULTI_LOG_TASKS 7 -#define BTRFS_ROOT_DIRTY 8 - -/* - * in ram representation of the tree. extent_root is used for all allocations - * and for the extent tree extent_root root. - */ -struct btrfs_root { - struct extent_buffer *node; - - struct extent_buffer *commit_root; - struct btrfs_root *log_root; - struct btrfs_root *reloc_root; - - unsigned long state; - struct btrfs_root_item root_item; - struct btrfs_key root_key; - struct btrfs_fs_info *fs_info; - struct extent_io_tree dirty_log_pages; - - struct mutex objectid_mutex; - - spinlock_t accounting_lock; - struct btrfs_block_rsv *block_rsv; - - /* free ino cache stuff */ - struct btrfs_free_space_ctl *free_ino_ctl; - enum btrfs_caching_type ino_cache_state; - spinlock_t ino_cache_lock; - wait_queue_head_t ino_cache_wait; - struct btrfs_free_space_ctl *free_ino_pinned; - u64 ino_cache_progress; - struct inode *ino_cache_inode; - - struct mutex log_mutex; - wait_queue_head_t log_writer_wait; - wait_queue_head_t log_commit_wait[2]; - struct list_head log_ctxs[2]; - atomic_t log_writers; - atomic_t log_commit[2]; - atomic_t log_batch; - int log_transid; - /* No matter the commit succeeds or not*/ - int log_transid_committed; - /* Just be updated when the commit succeeds. */ - int last_log_commit; - pid_t log_start_pid; - - u64 objectid; - u64 last_trans; - - /* data allocations are done in sectorsize units */ - u32 sectorsize; - - /* node allocations are done in nodesize units */ - u32 nodesize; - - u32 stripesize; - - u32 type; - - u64 highest_objectid; - -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS - /* only used with CONFIG_BTRFS_FS_RUN_SANITY_TESTS is enabled */ - u64 alloc_bytenr; -#endif - - u64 defrag_trans_start; - struct btrfs_key defrag_progress; - struct btrfs_key defrag_max; - char *name; - - /* the dirty list is only used by non-reference counted roots */ - struct list_head dirty_list; - - struct list_head root_list; - - spinlock_t log_extents_lock[2]; - struct list_head logged_list[2]; - - spinlock_t orphan_lock; - atomic_t orphan_inodes; - struct btrfs_block_rsv *orphan_block_rsv; - int orphan_cleanup_state; - - spinlock_t inode_lock; - /* red-black tree that keeps track of in-memory inodes */ - struct rb_root inode_tree; - - /* - * radix tree that keeps track of delayed nodes of every inode, - * protected by inode_lock - */ - struct radix_tree_root delayed_nodes_tree; - /* - * right now this just gets used so that a root has its own devid - * for stat. It may be used for more later - */ - dev_t anon_dev; - - spinlock_t root_item_lock; - atomic_t refs; - - struct mutex delalloc_mutex; - spinlock_t delalloc_lock; - /* - * all of the inodes that have delalloc bytes. It is possible for - * this list to be empty even when there is still dirty data=ordered - * extents waiting to finish IO. - */ - struct list_head delalloc_inodes; - struct list_head delalloc_root; - u64 nr_delalloc_inodes; - - struct mutex ordered_extent_mutex; - /* - * this is used by the balancing code to wait for all the pending - * ordered extents - */ - spinlock_t ordered_extent_lock; - - /* - * all of the data=ordered extents pending writeback - * these can span multiple transactions and basically include - * every dirty data page that isn't from nodatacow - */ - struct list_head ordered_extents; - struct list_head ordered_root; - u64 nr_ordered_extents; - - /* - * Number of currently running SEND ioctls to prevent - * manipulation with the read-only status via SUBVOL_SETFLAGS - */ - int send_in_progress; - struct btrfs_subvolume_writers *subv_writers; - atomic_t will_be_snapshoted; - - /* For qgroup metadata space reserve */ - atomic_t qgroup_meta_rsv; -}; - -static inline u32 __BTRFS_LEAF_DATA_SIZE(u32 blocksize) -{ - return blocksize - sizeof(struct btrfs_header); -} - -static inline u32 BTRFS_LEAF_DATA_SIZE(const struct btrfs_root *root) -{ - return __BTRFS_LEAF_DATA_SIZE(root->nodesize); -} - -static inline u32 BTRFS_MAX_ITEM_SIZE(const struct btrfs_root *root) -{ - return BTRFS_LEAF_DATA_SIZE(root) - sizeof(struct btrfs_item); -} - -static inline u32 BTRFS_NODEPTRS_PER_BLOCK(const struct btrfs_root *root) -{ - return BTRFS_LEAF_DATA_SIZE(root) / sizeof(struct btrfs_key_ptr); -} - -#define BTRFS_FILE_EXTENT_INLINE_DATA_START \ - (offsetof(struct btrfs_file_extent_item, disk_bytenr)) -static inline u32 BTRFS_MAX_INLINE_DATA_SIZE(const struct btrfs_root *root) -{ - return BTRFS_MAX_ITEM_SIZE(root) - - BTRFS_FILE_EXTENT_INLINE_DATA_START; -} - -static inline u32 BTRFS_MAX_XATTR_SIZE(const struct btrfs_root *root) -{ - return BTRFS_MAX_ITEM_SIZE(root) - sizeof(struct btrfs_dir_item); -} - -/* - * Flags for mount options. - * - * Note: don't forget to add new options to btrfs_show_options() - */ -#define BTRFS_MOUNT_NODATASUM (1 << 0) -#define BTRFS_MOUNT_NODATACOW (1 << 1) -#define BTRFS_MOUNT_NOBARRIER (1 << 2) -#define BTRFS_MOUNT_SSD (1 << 3) -#define BTRFS_MOUNT_DEGRADED (1 << 4) -#define BTRFS_MOUNT_COMPRESS (1 << 5) -#define BTRFS_MOUNT_NOTREELOG (1 << 6) -#define BTRFS_MOUNT_FLUSHONCOMMIT (1 << 7) -#define BTRFS_MOUNT_SSD_SPREAD (1 << 8) -#define BTRFS_MOUNT_NOSSD (1 << 9) -#define BTRFS_MOUNT_DISCARD (1 << 10) -#define BTRFS_MOUNT_FORCE_COMPRESS (1 << 11) -#define BTRFS_MOUNT_SPACE_CACHE (1 << 12) -#define BTRFS_MOUNT_CLEAR_CACHE (1 << 13) -#define BTRFS_MOUNT_USER_SUBVOL_RM_ALLOWED (1 << 14) -#define BTRFS_MOUNT_ENOSPC_DEBUG (1 << 15) -#define BTRFS_MOUNT_AUTO_DEFRAG (1 << 16) -#define BTRFS_MOUNT_INODE_MAP_CACHE (1 << 17) -#define BTRFS_MOUNT_USEBACKUPROOT (1 << 18) -#define BTRFS_MOUNT_SKIP_BALANCE (1 << 19) -#define BTRFS_MOUNT_CHECK_INTEGRITY (1 << 20) -#define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1 << 21) -#define BTRFS_MOUNT_PANIC_ON_FATAL_ERROR (1 << 22) -#define BTRFS_MOUNT_RESCAN_UUID_TREE (1 << 23) -#define BTRFS_MOUNT_FRAGMENT_DATA (1 << 24) -#define BTRFS_MOUNT_FRAGMENT_METADATA (1 << 25) -#define BTRFS_MOUNT_FREE_SPACE_TREE (1 << 26) -#define BTRFS_MOUNT_NOLOGREPLAY (1 << 27) - -#define BTRFS_DEFAULT_COMMIT_INTERVAL (30) -#define BTRFS_DEFAULT_MAX_INLINE (2048) - -#define btrfs_clear_opt(o, opt) ((o) &= ~BTRFS_MOUNT_##opt) -#define btrfs_set_opt(o, opt) ((o) |= BTRFS_MOUNT_##opt) -#define btrfs_raw_test_opt(o, opt) ((o) & BTRFS_MOUNT_##opt) -#define btrfs_test_opt(fs_info, opt) ((fs_info)->mount_opt & \ - BTRFS_MOUNT_##opt) - -#define btrfs_set_and_info(fs_info, opt, fmt, args...) \ -{ \ - if (!btrfs_test_opt(fs_info, opt)) \ - btrfs_info(fs_info, fmt, ##args); \ - btrfs_set_opt(fs_info->mount_opt, opt); \ -} - -#define btrfs_clear_and_info(fs_info, opt, fmt, args...) \ -{ \ - if (btrfs_test_opt(fs_info, opt)) \ - btrfs_info(fs_info, fmt, ##args); \ - btrfs_clear_opt(fs_info->mount_opt, opt); \ -} - -#ifdef CONFIG_BTRFS_DEBUG -static inline int -btrfs_should_fragment_free_space(struct btrfs_root *root, - struct btrfs_block_group_cache *block_group) -{ - return (btrfs_test_opt(root->fs_info, FRAGMENT_METADATA) && - block_group->flags & BTRFS_BLOCK_GROUP_METADATA) || - (btrfs_test_opt(root->fs_info, FRAGMENT_DATA) && - block_group->flags & BTRFS_BLOCK_GROUP_DATA); -} -#endif - -/* - * Requests for changes that need to be done during transaction commit. - * - * Internal mount options that are used for special handling of the real - * mount options (eg. cannot be set during remount and have to be set during - * transaction commit) - */ - -#define BTRFS_PENDING_SET_INODE_MAP_CACHE (0) -#define BTRFS_PENDING_CLEAR_INODE_MAP_CACHE (1) -#define BTRFS_PENDING_COMMIT (2) - -#define btrfs_test_pending(info, opt) \ - test_bit(BTRFS_PENDING_##opt, &(info)->pending_changes) -#define btrfs_set_pending(info, opt) \ - set_bit(BTRFS_PENDING_##opt, &(info)->pending_changes) -#define btrfs_clear_pending(info, opt) \ - clear_bit(BTRFS_PENDING_##opt, &(info)->pending_changes) - -/* - * Helpers for setting pending mount option changes. - * - * Expects corresponding macros - * BTRFS_PENDING_SET_ and CLEAR_ + short mount option name - */ -#define btrfs_set_pending_and_info(info, opt, fmt, args...) \ -do { \ - if (!btrfs_raw_test_opt((info)->mount_opt, opt)) { \ - btrfs_info((info), fmt, ##args); \ - btrfs_set_pending((info), SET_##opt); \ - btrfs_clear_pending((info), CLEAR_##opt); \ - } \ -} while(0) - -#define btrfs_clear_pending_and_info(info, opt, fmt, args...) \ -do { \ - if (btrfs_raw_test_opt((info)->mount_opt, opt)) { \ - btrfs_info((info), fmt, ##args); \ - btrfs_set_pending((info), CLEAR_##opt); \ - btrfs_clear_pending((info), SET_##opt); \ - } \ -} while(0) - -/* - * Inode flags - */ -#define BTRFS_INODE_NODATASUM (1 << 0) -#define BTRFS_INODE_NODATACOW (1 << 1) -#define BTRFS_INODE_READONLY (1 << 2) -#define BTRFS_INODE_NOCOMPRESS (1 << 3) -#define BTRFS_INODE_PREALLOC (1 << 4) -#define BTRFS_INODE_SYNC (1 << 5) -#define BTRFS_INODE_IMMUTABLE (1 << 6) -#define BTRFS_INODE_APPEND (1 << 7) -#define BTRFS_INODE_NODUMP (1 << 8) -#define BTRFS_INODE_NOATIME (1 << 9) -#define BTRFS_INODE_DIRSYNC (1 << 10) -#define BTRFS_INODE_COMPRESS (1 << 11) - -#define BTRFS_INODE_ROOT_ITEM_INIT (1 << 31) - -struct btrfs_map_token { - struct extent_buffer *eb; - char *kaddr; - unsigned long offset; -}; - -#define BTRFS_BYTES_TO_BLKS(fs_info, bytes) \ - ((bytes) >> (fs_info)->sb->s_blocksize_bits) - -static inline void btrfs_init_map_token (struct btrfs_map_token *token) -{ - token->kaddr = NULL; -} - -/* some macros to generate set/get functions for the struct fields. This - * assumes there is a lefoo_to_cpu for every type, so lets make a simple - * one for u8: - */ -#define le8_to_cpu(v) (v) -#define cpu_to_le8(v) (v) -#define __le8 u8 - -#define read_eb_member(eb, ptr, type, member, result) (\ - read_extent_buffer(eb, (char *)(result), \ - ((unsigned long)(ptr)) + \ - offsetof(type, member), \ - sizeof(((type *)0)->member))) - -#define write_eb_member(eb, ptr, type, member, result) (\ - write_extent_buffer(eb, (char *)(result), \ - ((unsigned long)(ptr)) + \ - offsetof(type, member), \ - sizeof(((type *)0)->member))) - -#define DECLARE_BTRFS_SETGET_BITS(bits) \ -u##bits btrfs_get_token_##bits(struct extent_buffer *eb, void *ptr, \ - unsigned long off, \ - struct btrfs_map_token *token); \ -void btrfs_set_token_##bits(struct extent_buffer *eb, void *ptr, \ - unsigned long off, u##bits val, \ - struct btrfs_map_token *token); \ -static inline u##bits btrfs_get_##bits(struct extent_buffer *eb, void *ptr, \ - unsigned long off) \ -{ \ - return btrfs_get_token_##bits(eb, ptr, off, NULL); \ -} \ -static inline void btrfs_set_##bits(struct extent_buffer *eb, void *ptr, \ - unsigned long off, u##bits val) \ -{ \ - btrfs_set_token_##bits(eb, ptr, off, val, NULL); \ -} - -DECLARE_BTRFS_SETGET_BITS(8) -DECLARE_BTRFS_SETGET_BITS(16) -DECLARE_BTRFS_SETGET_BITS(32) -DECLARE_BTRFS_SETGET_BITS(64) - -#define BTRFS_SETGET_FUNCS(name, type, member, bits) \ -static inline u##bits btrfs_##name(struct extent_buffer *eb, type *s) \ -{ \ - BUILD_BUG_ON(sizeof(u##bits) != sizeof(((type *)0))->member); \ - return btrfs_get_##bits(eb, s, offsetof(type, member)); \ -} \ -static inline void btrfs_set_##name(struct extent_buffer *eb, type *s, \ - u##bits val) \ -{ \ - BUILD_BUG_ON(sizeof(u##bits) != sizeof(((type *)0))->member); \ - btrfs_set_##bits(eb, s, offsetof(type, member), val); \ -} \ -static inline u##bits btrfs_token_##name(struct extent_buffer *eb, type *s, \ - struct btrfs_map_token *token) \ -{ \ - BUILD_BUG_ON(sizeof(u##bits) != sizeof(((type *)0))->member); \ - return btrfs_get_token_##bits(eb, s, offsetof(type, member), token); \ -} \ -static inline void btrfs_set_token_##name(struct extent_buffer *eb, \ - type *s, u##bits val, \ - struct btrfs_map_token *token) \ -{ \ - BUILD_BUG_ON(sizeof(u##bits) != sizeof(((type *)0))->member); \ - btrfs_set_token_##bits(eb, s, offsetof(type, member), val, token); \ -} - -#define BTRFS_SETGET_HEADER_FUNCS(name, type, member, bits) \ -static inline u##bits btrfs_##name(struct extent_buffer *eb) \ -{ \ - type *p = page_address(eb->pages[0]); \ - u##bits res = le##bits##_to_cpu(p->member); \ - return res; \ -} \ -static inline void btrfs_set_##name(struct extent_buffer *eb, \ - u##bits val) \ -{ \ - type *p = page_address(eb->pages[0]); \ - p->member = cpu_to_le##bits(val); \ -} - -#define BTRFS_SETGET_STACK_FUNCS(name, type, member, bits) \ -static inline u##bits btrfs_##name(type *s) \ -{ \ - return le##bits##_to_cpu(s->member); \ -} \ -static inline void btrfs_set_##name(type *s, u##bits val) \ -{ \ - s->member = cpu_to_le##bits(val); \ -} - -BTRFS_SETGET_FUNCS(device_type, struct btrfs_dev_item, type, 64); -BTRFS_SETGET_FUNCS(device_total_bytes, struct btrfs_dev_item, total_bytes, 64); -BTRFS_SETGET_FUNCS(device_bytes_used, struct btrfs_dev_item, bytes_used, 64); -BTRFS_SETGET_FUNCS(device_io_align, struct btrfs_dev_item, io_align, 32); -BTRFS_SETGET_FUNCS(device_io_width, struct btrfs_dev_item, io_width, 32); -BTRFS_SETGET_FUNCS(device_start_offset, struct btrfs_dev_item, - start_offset, 64); -BTRFS_SETGET_FUNCS(device_sector_size, struct btrfs_dev_item, sector_size, 32); -BTRFS_SETGET_FUNCS(device_id, struct btrfs_dev_item, devid, 64); -BTRFS_SETGET_FUNCS(device_group, struct btrfs_dev_item, dev_group, 32); -BTRFS_SETGET_FUNCS(device_seek_speed, struct btrfs_dev_item, seek_speed, 8); -BTRFS_SETGET_FUNCS(device_bandwidth, struct btrfs_dev_item, bandwidth, 8); -BTRFS_SETGET_FUNCS(device_generation, struct btrfs_dev_item, generation, 64); - -BTRFS_SETGET_STACK_FUNCS(stack_device_type, struct btrfs_dev_item, type, 64); -BTRFS_SETGET_STACK_FUNCS(stack_device_total_bytes, struct btrfs_dev_item, - total_bytes, 64); -BTRFS_SETGET_STACK_FUNCS(stack_device_bytes_used, struct btrfs_dev_item, - bytes_used, 64); -BTRFS_SETGET_STACK_FUNCS(stack_device_io_align, struct btrfs_dev_item, - io_align, 32); -BTRFS_SETGET_STACK_FUNCS(stack_device_io_width, struct btrfs_dev_item, - io_width, 32); -BTRFS_SETGET_STACK_FUNCS(stack_device_sector_size, struct btrfs_dev_item, - sector_size, 32); -BTRFS_SETGET_STACK_FUNCS(stack_device_id, struct btrfs_dev_item, devid, 64); -BTRFS_SETGET_STACK_FUNCS(stack_device_group, struct btrfs_dev_item, - dev_group, 32); -BTRFS_SETGET_STACK_FUNCS(stack_device_seek_speed, struct btrfs_dev_item, - seek_speed, 8); -BTRFS_SETGET_STACK_FUNCS(stack_device_bandwidth, struct btrfs_dev_item, - bandwidth, 8); -BTRFS_SETGET_STACK_FUNCS(stack_device_generation, struct btrfs_dev_item, - generation, 64); - -static inline unsigned long btrfs_device_uuid(struct btrfs_dev_item *d) -{ - return (unsigned long)d + offsetof(struct btrfs_dev_item, uuid); -} - -static inline unsigned long btrfs_device_fsid(struct btrfs_dev_item *d) -{ - return (unsigned long)d + offsetof(struct btrfs_dev_item, fsid); -} - -BTRFS_SETGET_FUNCS(chunk_length, struct btrfs_chunk, length, 64); -BTRFS_SETGET_FUNCS(chunk_owner, struct btrfs_chunk, owner, 64); -BTRFS_SETGET_FUNCS(chunk_stripe_len, struct btrfs_chunk, stripe_len, 64); -BTRFS_SETGET_FUNCS(chunk_io_align, struct btrfs_chunk, io_align, 32); -BTRFS_SETGET_FUNCS(chunk_io_width, struct btrfs_chunk, io_width, 32); -BTRFS_SETGET_FUNCS(chunk_sector_size, struct btrfs_chunk, sector_size, 32); -BTRFS_SETGET_FUNCS(chunk_type, struct btrfs_chunk, type, 64); -BTRFS_SETGET_FUNCS(chunk_num_stripes, struct btrfs_chunk, num_stripes, 16); -BTRFS_SETGET_FUNCS(chunk_sub_stripes, struct btrfs_chunk, sub_stripes, 16); -BTRFS_SETGET_FUNCS(stripe_devid, struct btrfs_stripe, devid, 64); -BTRFS_SETGET_FUNCS(stripe_offset, struct btrfs_stripe, offset, 64); - -static inline char *btrfs_stripe_dev_uuid(struct btrfs_stripe *s) -{ - return (char *)s + offsetof(struct btrfs_stripe, dev_uuid); -} - -BTRFS_SETGET_STACK_FUNCS(stack_chunk_length, struct btrfs_chunk, length, 64); -BTRFS_SETGET_STACK_FUNCS(stack_chunk_owner, struct btrfs_chunk, owner, 64); -BTRFS_SETGET_STACK_FUNCS(stack_chunk_stripe_len, struct btrfs_chunk, - stripe_len, 64); -BTRFS_SETGET_STACK_FUNCS(stack_chunk_io_align, struct btrfs_chunk, - io_align, 32); -BTRFS_SETGET_STACK_FUNCS(stack_chunk_io_width, struct btrfs_chunk, - io_width, 32); -BTRFS_SETGET_STACK_FUNCS(stack_chunk_sector_size, struct btrfs_chunk, - sector_size, 32); -BTRFS_SETGET_STACK_FUNCS(stack_chunk_type, struct btrfs_chunk, type, 64); -BTRFS_SETGET_STACK_FUNCS(stack_chunk_num_stripes, struct btrfs_chunk, - num_stripes, 16); -BTRFS_SETGET_STACK_FUNCS(stack_chunk_sub_stripes, struct btrfs_chunk, - sub_stripes, 16); -BTRFS_SETGET_STACK_FUNCS(stack_stripe_devid, struct btrfs_stripe, devid, 64); -BTRFS_SETGET_STACK_FUNCS(stack_stripe_offset, struct btrfs_stripe, offset, 64); - -static inline struct btrfs_stripe *btrfs_stripe_nr(struct btrfs_chunk *c, - int nr) -{ - unsigned long offset = (unsigned long)c; - offset += offsetof(struct btrfs_chunk, stripe); - offset += nr * sizeof(struct btrfs_stripe); - return (struct btrfs_stripe *)offset; -} - -static inline char *btrfs_stripe_dev_uuid_nr(struct btrfs_chunk *c, int nr) -{ - return btrfs_stripe_dev_uuid(btrfs_stripe_nr(c, nr)); -} - -static inline u64 btrfs_stripe_offset_nr(struct extent_buffer *eb, - struct btrfs_chunk *c, int nr) -{ - return btrfs_stripe_offset(eb, btrfs_stripe_nr(c, nr)); -} - -static inline u64 btrfs_stripe_devid_nr(struct extent_buffer *eb, - struct btrfs_chunk *c, int nr) -{ - return btrfs_stripe_devid(eb, btrfs_stripe_nr(c, nr)); -} - -/* struct btrfs_block_group_item */ -BTRFS_SETGET_STACK_FUNCS(block_group_used, struct btrfs_block_group_item, - used, 64); -BTRFS_SETGET_FUNCS(disk_block_group_used, struct btrfs_block_group_item, - used, 64); -BTRFS_SETGET_STACK_FUNCS(block_group_chunk_objectid, - struct btrfs_block_group_item, chunk_objectid, 64); - -BTRFS_SETGET_FUNCS(disk_block_group_chunk_objectid, - struct btrfs_block_group_item, chunk_objectid, 64); -BTRFS_SETGET_FUNCS(disk_block_group_flags, - struct btrfs_block_group_item, flags, 64); -BTRFS_SETGET_STACK_FUNCS(block_group_flags, - struct btrfs_block_group_item, flags, 64); - -/* struct btrfs_free_space_info */ -BTRFS_SETGET_FUNCS(free_space_extent_count, struct btrfs_free_space_info, - extent_count, 32); -BTRFS_SETGET_FUNCS(free_space_flags, struct btrfs_free_space_info, flags, 32); - -/* struct btrfs_inode_ref */ -BTRFS_SETGET_FUNCS(inode_ref_name_len, struct btrfs_inode_ref, name_len, 16); -BTRFS_SETGET_FUNCS(inode_ref_index, struct btrfs_inode_ref, index, 64); - -/* struct btrfs_inode_extref */ -BTRFS_SETGET_FUNCS(inode_extref_parent, struct btrfs_inode_extref, - parent_objectid, 64); -BTRFS_SETGET_FUNCS(inode_extref_name_len, struct btrfs_inode_extref, - name_len, 16); -BTRFS_SETGET_FUNCS(inode_extref_index, struct btrfs_inode_extref, index, 64); - -/* struct btrfs_inode_item */ -BTRFS_SETGET_FUNCS(inode_generation, struct btrfs_inode_item, generation, 64); -BTRFS_SETGET_FUNCS(inode_sequence, struct btrfs_inode_item, sequence, 64); -BTRFS_SETGET_FUNCS(inode_transid, struct btrfs_inode_item, transid, 64); -BTRFS_SETGET_FUNCS(inode_size, struct btrfs_inode_item, size, 64); -BTRFS_SETGET_FUNCS(inode_nbytes, struct btrfs_inode_item, nbytes, 64); -BTRFS_SETGET_FUNCS(inode_block_group, struct btrfs_inode_item, block_group, 64); -BTRFS_SETGET_FUNCS(inode_nlink, struct btrfs_inode_item, nlink, 32); -BTRFS_SETGET_FUNCS(inode_uid, struct btrfs_inode_item, uid, 32); -BTRFS_SETGET_FUNCS(inode_gid, struct btrfs_inode_item, gid, 32); -BTRFS_SETGET_FUNCS(inode_mode, struct btrfs_inode_item, mode, 32); -BTRFS_SETGET_FUNCS(inode_rdev, struct btrfs_inode_item, rdev, 64); -BTRFS_SETGET_FUNCS(inode_flags, struct btrfs_inode_item, flags, 64); -BTRFS_SETGET_STACK_FUNCS(stack_inode_generation, struct btrfs_inode_item, - generation, 64); -BTRFS_SETGET_STACK_FUNCS(stack_inode_sequence, struct btrfs_inode_item, - sequence, 64); -BTRFS_SETGET_STACK_FUNCS(stack_inode_transid, struct btrfs_inode_item, - transid, 64); -BTRFS_SETGET_STACK_FUNCS(stack_inode_size, struct btrfs_inode_item, size, 64); -BTRFS_SETGET_STACK_FUNCS(stack_inode_nbytes, struct btrfs_inode_item, - nbytes, 64); -BTRFS_SETGET_STACK_FUNCS(stack_inode_block_group, struct btrfs_inode_item, - block_group, 64); -BTRFS_SETGET_STACK_FUNCS(stack_inode_nlink, struct btrfs_inode_item, nlink, 32); -BTRFS_SETGET_STACK_FUNCS(stack_inode_uid, struct btrfs_inode_item, uid, 32); -BTRFS_SETGET_STACK_FUNCS(stack_inode_gid, struct btrfs_inode_item, gid, 32); -BTRFS_SETGET_STACK_FUNCS(stack_inode_mode, struct btrfs_inode_item, mode, 32); -BTRFS_SETGET_STACK_FUNCS(stack_inode_rdev, struct btrfs_inode_item, rdev, 64); -BTRFS_SETGET_STACK_FUNCS(stack_inode_flags, struct btrfs_inode_item, flags, 64); -BTRFS_SETGET_FUNCS(timespec_sec, struct btrfs_timespec, sec, 64); -BTRFS_SETGET_FUNCS(timespec_nsec, struct btrfs_timespec, nsec, 32); -BTRFS_SETGET_STACK_FUNCS(stack_timespec_sec, struct btrfs_timespec, sec, 64); -BTRFS_SETGET_STACK_FUNCS(stack_timespec_nsec, struct btrfs_timespec, nsec, 32); - -/* struct btrfs_dev_extent */ -BTRFS_SETGET_FUNCS(dev_extent_chunk_tree, struct btrfs_dev_extent, - chunk_tree, 64); -BTRFS_SETGET_FUNCS(dev_extent_chunk_objectid, struct btrfs_dev_extent, - chunk_objectid, 64); -BTRFS_SETGET_FUNCS(dev_extent_chunk_offset, struct btrfs_dev_extent, - chunk_offset, 64); -BTRFS_SETGET_FUNCS(dev_extent_length, struct btrfs_dev_extent, length, 64); - -static inline unsigned long btrfs_dev_extent_chunk_tree_uuid(struct btrfs_dev_extent *dev) -{ - unsigned long ptr = offsetof(struct btrfs_dev_extent, chunk_tree_uuid); - return (unsigned long)dev + ptr; -} - -BTRFS_SETGET_FUNCS(extent_refs, struct btrfs_extent_item, refs, 64); -BTRFS_SETGET_FUNCS(extent_generation, struct btrfs_extent_item, - generation, 64); -BTRFS_SETGET_FUNCS(extent_flags, struct btrfs_extent_item, flags, 64); - -BTRFS_SETGET_FUNCS(extent_refs_v0, struct btrfs_extent_item_v0, refs, 32); - - -BTRFS_SETGET_FUNCS(tree_block_level, struct btrfs_tree_block_info, level, 8); - -static inline void btrfs_tree_block_key(struct extent_buffer *eb, - struct btrfs_tree_block_info *item, - struct btrfs_disk_key *key) -{ - read_eb_member(eb, item, struct btrfs_tree_block_info, key, key); -} - -static inline void btrfs_set_tree_block_key(struct extent_buffer *eb, - struct btrfs_tree_block_info *item, - struct btrfs_disk_key *key) -{ - write_eb_member(eb, item, struct btrfs_tree_block_info, key, key); -} - -BTRFS_SETGET_FUNCS(extent_data_ref_root, struct btrfs_extent_data_ref, - root, 64); -BTRFS_SETGET_FUNCS(extent_data_ref_objectid, struct btrfs_extent_data_ref, - objectid, 64); -BTRFS_SETGET_FUNCS(extent_data_ref_offset, struct btrfs_extent_data_ref, - offset, 64); -BTRFS_SETGET_FUNCS(extent_data_ref_count, struct btrfs_extent_data_ref, - count, 32); - -BTRFS_SETGET_FUNCS(shared_data_ref_count, struct btrfs_shared_data_ref, - count, 32); - -BTRFS_SETGET_FUNCS(extent_inline_ref_type, struct btrfs_extent_inline_ref, - type, 8); -BTRFS_SETGET_FUNCS(extent_inline_ref_offset, struct btrfs_extent_inline_ref, - offset, 64); - -static inline u32 btrfs_extent_inline_ref_size(int type) -{ - if (type == BTRFS_TREE_BLOCK_REF_KEY || - type == BTRFS_SHARED_BLOCK_REF_KEY) - return sizeof(struct btrfs_extent_inline_ref); - if (type == BTRFS_SHARED_DATA_REF_KEY) - return sizeof(struct btrfs_shared_data_ref) + - sizeof(struct btrfs_extent_inline_ref); - if (type == BTRFS_EXTENT_DATA_REF_KEY) - return sizeof(struct btrfs_extent_data_ref) + - offsetof(struct btrfs_extent_inline_ref, offset); - BUG(); - return 0; -} - -BTRFS_SETGET_FUNCS(ref_root_v0, struct btrfs_extent_ref_v0, root, 64); -BTRFS_SETGET_FUNCS(ref_generation_v0, struct btrfs_extent_ref_v0, - generation, 64); -BTRFS_SETGET_FUNCS(ref_objectid_v0, struct btrfs_extent_ref_v0, objectid, 64); -BTRFS_SETGET_FUNCS(ref_count_v0, struct btrfs_extent_ref_v0, count, 32); - -/* struct btrfs_node */ -BTRFS_SETGET_FUNCS(key_blockptr, struct btrfs_key_ptr, blockptr, 64); -BTRFS_SETGET_FUNCS(key_generation, struct btrfs_key_ptr, generation, 64); -BTRFS_SETGET_STACK_FUNCS(stack_key_blockptr, struct btrfs_key_ptr, - blockptr, 64); -BTRFS_SETGET_STACK_FUNCS(stack_key_generation, struct btrfs_key_ptr, - generation, 64); - -static inline u64 btrfs_node_blockptr(struct extent_buffer *eb, int nr) -{ - unsigned long ptr; - ptr = offsetof(struct btrfs_node, ptrs) + - sizeof(struct btrfs_key_ptr) * nr; - return btrfs_key_blockptr(eb, (struct btrfs_key_ptr *)ptr); -} - -static inline void btrfs_set_node_blockptr(struct extent_buffer *eb, - int nr, u64 val) -{ - unsigned long ptr; - ptr = offsetof(struct btrfs_node, ptrs) + - sizeof(struct btrfs_key_ptr) * nr; - btrfs_set_key_blockptr(eb, (struct btrfs_key_ptr *)ptr, val); -} - -static inline u64 btrfs_node_ptr_generation(struct extent_buffer *eb, int nr) -{ - unsigned long ptr; - ptr = offsetof(struct btrfs_node, ptrs) + - sizeof(struct btrfs_key_ptr) * nr; - return btrfs_key_generation(eb, (struct btrfs_key_ptr *)ptr); -} - -static inline void btrfs_set_node_ptr_generation(struct extent_buffer *eb, - int nr, u64 val) -{ - unsigned long ptr; - ptr = offsetof(struct btrfs_node, ptrs) + - sizeof(struct btrfs_key_ptr) * nr; - btrfs_set_key_generation(eb, (struct btrfs_key_ptr *)ptr, val); -} - -static inline unsigned long btrfs_node_key_ptr_offset(int nr) -{ - return offsetof(struct btrfs_node, ptrs) + - sizeof(struct btrfs_key_ptr) * nr; -} - -void btrfs_node_key(struct extent_buffer *eb, - struct btrfs_disk_key *disk_key, int nr); - -static inline void btrfs_set_node_key(struct extent_buffer *eb, - struct btrfs_disk_key *disk_key, int nr) -{ - unsigned long ptr; - ptr = btrfs_node_key_ptr_offset(nr); - write_eb_member(eb, (struct btrfs_key_ptr *)ptr, - struct btrfs_key_ptr, key, disk_key); -} - -/* struct btrfs_item */ -BTRFS_SETGET_FUNCS(item_offset, struct btrfs_item, offset, 32); -BTRFS_SETGET_FUNCS(item_size, struct btrfs_item, size, 32); -BTRFS_SETGET_STACK_FUNCS(stack_item_offset, struct btrfs_item, offset, 32); -BTRFS_SETGET_STACK_FUNCS(stack_item_size, struct btrfs_item, size, 32); - -static inline unsigned long btrfs_item_nr_offset(int nr) -{ - return offsetof(struct btrfs_leaf, items) + - sizeof(struct btrfs_item) * nr; -} - -static inline struct btrfs_item *btrfs_item_nr(int nr) -{ - return (struct btrfs_item *)btrfs_item_nr_offset(nr); -} - -static inline u32 btrfs_item_end(struct extent_buffer *eb, - struct btrfs_item *item) -{ - return btrfs_item_offset(eb, item) + btrfs_item_size(eb, item); -} - -static inline u32 btrfs_item_end_nr(struct extent_buffer *eb, int nr) -{ - return btrfs_item_end(eb, btrfs_item_nr(nr)); -} - -static inline u32 btrfs_item_offset_nr(struct extent_buffer *eb, int nr) -{ - return btrfs_item_offset(eb, btrfs_item_nr(nr)); -} - -static inline u32 btrfs_item_size_nr(struct extent_buffer *eb, int nr) -{ - return btrfs_item_size(eb, btrfs_item_nr(nr)); -} - -static inline void btrfs_item_key(struct extent_buffer *eb, - struct btrfs_disk_key *disk_key, int nr) -{ - struct btrfs_item *item = btrfs_item_nr(nr); - read_eb_member(eb, item, struct btrfs_item, key, disk_key); -} - -static inline void btrfs_set_item_key(struct extent_buffer *eb, - struct btrfs_disk_key *disk_key, int nr) -{ - struct btrfs_item *item = btrfs_item_nr(nr); - write_eb_member(eb, item, struct btrfs_item, key, disk_key); -} - -BTRFS_SETGET_FUNCS(dir_log_end, struct btrfs_dir_log_item, end, 64); - -/* - * struct btrfs_root_ref - */ -BTRFS_SETGET_FUNCS(root_ref_dirid, struct btrfs_root_ref, dirid, 64); -BTRFS_SETGET_FUNCS(root_ref_sequence, struct btrfs_root_ref, sequence, 64); -BTRFS_SETGET_FUNCS(root_ref_name_len, struct btrfs_root_ref, name_len, 16); - -/* struct btrfs_dir_item */ -BTRFS_SETGET_FUNCS(dir_data_len, struct btrfs_dir_item, data_len, 16); -BTRFS_SETGET_FUNCS(dir_type, struct btrfs_dir_item, type, 8); -BTRFS_SETGET_FUNCS(dir_name_len, struct btrfs_dir_item, name_len, 16); -BTRFS_SETGET_FUNCS(dir_transid, struct btrfs_dir_item, transid, 64); -BTRFS_SETGET_STACK_FUNCS(stack_dir_type, struct btrfs_dir_item, type, 8); -BTRFS_SETGET_STACK_FUNCS(stack_dir_data_len, struct btrfs_dir_item, - data_len, 16); -BTRFS_SETGET_STACK_FUNCS(stack_dir_name_len, struct btrfs_dir_item, - name_len, 16); -BTRFS_SETGET_STACK_FUNCS(stack_dir_transid, struct btrfs_dir_item, - transid, 64); - -static inline void btrfs_dir_item_key(struct extent_buffer *eb, - struct btrfs_dir_item *item, - struct btrfs_disk_key *key) -{ - read_eb_member(eb, item, struct btrfs_dir_item, location, key); -} - -static inline void btrfs_set_dir_item_key(struct extent_buffer *eb, - struct btrfs_dir_item *item, - struct btrfs_disk_key *key) -{ - write_eb_member(eb, item, struct btrfs_dir_item, location, key); -} - -BTRFS_SETGET_FUNCS(free_space_entries, struct btrfs_free_space_header, - num_entries, 64); -BTRFS_SETGET_FUNCS(free_space_bitmaps, struct btrfs_free_space_header, - num_bitmaps, 64); -BTRFS_SETGET_FUNCS(free_space_generation, struct btrfs_free_space_header, - generation, 64); - -static inline void btrfs_free_space_key(struct extent_buffer *eb, - struct btrfs_free_space_header *h, - struct btrfs_disk_key *key) -{ - read_eb_member(eb, h, struct btrfs_free_space_header, location, key); -} - -static inline void btrfs_set_free_space_key(struct extent_buffer *eb, - struct btrfs_free_space_header *h, - struct btrfs_disk_key *key) -{ - write_eb_member(eb, h, struct btrfs_free_space_header, location, key); -} - -/* struct btrfs_disk_key */ -BTRFS_SETGET_STACK_FUNCS(disk_key_objectid, struct btrfs_disk_key, - objectid, 64); -BTRFS_SETGET_STACK_FUNCS(disk_key_offset, struct btrfs_disk_key, offset, 64); -BTRFS_SETGET_STACK_FUNCS(disk_key_type, struct btrfs_disk_key, type, 8); - -static inline void btrfs_disk_key_to_cpu(struct btrfs_key *cpu, - struct btrfs_disk_key *disk) -{ - cpu->offset = le64_to_cpu(disk->offset); - cpu->type = disk->type; - cpu->objectid = le64_to_cpu(disk->objectid); -} - -static inline void btrfs_cpu_key_to_disk(struct btrfs_disk_key *disk, - struct btrfs_key *cpu) -{ - disk->offset = cpu_to_le64(cpu->offset); - disk->type = cpu->type; - disk->objectid = cpu_to_le64(cpu->objectid); -} - -static inline void btrfs_node_key_to_cpu(struct extent_buffer *eb, - struct btrfs_key *key, int nr) -{ - struct btrfs_disk_key disk_key; - btrfs_node_key(eb, &disk_key, nr); - btrfs_disk_key_to_cpu(key, &disk_key); -} - -static inline void btrfs_item_key_to_cpu(struct extent_buffer *eb, - struct btrfs_key *key, int nr) -{ - struct btrfs_disk_key disk_key; - btrfs_item_key(eb, &disk_key, nr); - btrfs_disk_key_to_cpu(key, &disk_key); -} - -static inline void btrfs_dir_item_key_to_cpu(struct extent_buffer *eb, - struct btrfs_dir_item *item, - struct btrfs_key *key) -{ - struct btrfs_disk_key disk_key; - btrfs_dir_item_key(eb, item, &disk_key); - btrfs_disk_key_to_cpu(key, &disk_key); -} - - -static inline u8 btrfs_key_type(struct btrfs_key *key) -{ - return key->type; -} - -static inline void btrfs_set_key_type(struct btrfs_key *key, u8 val) -{ - key->type = val; -} - -/* struct btrfs_header */ -BTRFS_SETGET_HEADER_FUNCS(header_bytenr, struct btrfs_header, bytenr, 64); -BTRFS_SETGET_HEADER_FUNCS(header_generation, struct btrfs_header, - generation, 64); -BTRFS_SETGET_HEADER_FUNCS(header_owner, struct btrfs_header, owner, 64); -BTRFS_SETGET_HEADER_FUNCS(header_nritems, struct btrfs_header, nritems, 32); -BTRFS_SETGET_HEADER_FUNCS(header_flags, struct btrfs_header, flags, 64); -BTRFS_SETGET_HEADER_FUNCS(header_level, struct btrfs_header, level, 8); -BTRFS_SETGET_STACK_FUNCS(stack_header_generation, struct btrfs_header, - generation, 64); -BTRFS_SETGET_STACK_FUNCS(stack_header_owner, struct btrfs_header, owner, 64); -BTRFS_SETGET_STACK_FUNCS(stack_header_nritems, struct btrfs_header, - nritems, 32); -BTRFS_SETGET_STACK_FUNCS(stack_header_bytenr, struct btrfs_header, bytenr, 64); - -static inline int btrfs_header_flag(struct extent_buffer *eb, u64 flag) -{ - return (btrfs_header_flags(eb) & flag) == flag; -} - -static inline int btrfs_set_header_flag(struct extent_buffer *eb, u64 flag) -{ - u64 flags = btrfs_header_flags(eb); - btrfs_set_header_flags(eb, flags | flag); - return (flags & flag) == flag; -} - -static inline int btrfs_clear_header_flag(struct extent_buffer *eb, u64 flag) -{ - u64 flags = btrfs_header_flags(eb); - btrfs_set_header_flags(eb, flags & ~flag); - return (flags & flag) == flag; -} - -static inline int btrfs_header_backref_rev(struct extent_buffer *eb) -{ - u64 flags = btrfs_header_flags(eb); - return flags >> BTRFS_BACKREF_REV_SHIFT; -} - -static inline void btrfs_set_header_backref_rev(struct extent_buffer *eb, - int rev) -{ - u64 flags = btrfs_header_flags(eb); - flags &= ~BTRFS_BACKREF_REV_MASK; - flags |= (u64)rev << BTRFS_BACKREF_REV_SHIFT; - btrfs_set_header_flags(eb, flags); -} - -static inline unsigned long btrfs_header_fsid(void) -{ - return offsetof(struct btrfs_header, fsid); -} - -static inline unsigned long btrfs_header_chunk_tree_uuid(struct extent_buffer *eb) -{ - return offsetof(struct btrfs_header, chunk_tree_uuid); -} - -static inline int btrfs_is_leaf(struct extent_buffer *eb) -{ - return btrfs_header_level(eb) == 0; -} - -/* struct btrfs_root_item */ -BTRFS_SETGET_FUNCS(disk_root_generation, struct btrfs_root_item, - generation, 64); -BTRFS_SETGET_FUNCS(disk_root_refs, struct btrfs_root_item, refs, 32); -BTRFS_SETGET_FUNCS(disk_root_bytenr, struct btrfs_root_item, bytenr, 64); -BTRFS_SETGET_FUNCS(disk_root_level, struct btrfs_root_item, level, 8); - -BTRFS_SETGET_STACK_FUNCS(root_generation, struct btrfs_root_item, - generation, 64); -BTRFS_SETGET_STACK_FUNCS(root_bytenr, struct btrfs_root_item, bytenr, 64); -BTRFS_SETGET_STACK_FUNCS(root_level, struct btrfs_root_item, level, 8); -BTRFS_SETGET_STACK_FUNCS(root_dirid, struct btrfs_root_item, root_dirid, 64); -BTRFS_SETGET_STACK_FUNCS(root_refs, struct btrfs_root_item, refs, 32); -BTRFS_SETGET_STACK_FUNCS(root_flags, struct btrfs_root_item, flags, 64); -BTRFS_SETGET_STACK_FUNCS(root_used, struct btrfs_root_item, bytes_used, 64); -BTRFS_SETGET_STACK_FUNCS(root_limit, struct btrfs_root_item, byte_limit, 64); -BTRFS_SETGET_STACK_FUNCS(root_last_snapshot, struct btrfs_root_item, - last_snapshot, 64); -BTRFS_SETGET_STACK_FUNCS(root_generation_v2, struct btrfs_root_item, - generation_v2, 64); -BTRFS_SETGET_STACK_FUNCS(root_ctransid, struct btrfs_root_item, - ctransid, 64); -BTRFS_SETGET_STACK_FUNCS(root_otransid, struct btrfs_root_item, - otransid, 64); -BTRFS_SETGET_STACK_FUNCS(root_stransid, struct btrfs_root_item, - stransid, 64); -BTRFS_SETGET_STACK_FUNCS(root_rtransid, struct btrfs_root_item, - rtransid, 64); - -static inline bool btrfs_root_readonly(struct btrfs_root *root) -{ - return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_RDONLY)) != 0; -} - -static inline bool btrfs_root_dead(struct btrfs_root *root) -{ - return (root->root_item.flags & cpu_to_le64(BTRFS_ROOT_SUBVOL_DEAD)) != 0; -} - -/* struct btrfs_root_backup */ -BTRFS_SETGET_STACK_FUNCS(backup_tree_root, struct btrfs_root_backup, - tree_root, 64); -BTRFS_SETGET_STACK_FUNCS(backup_tree_root_gen, struct btrfs_root_backup, - tree_root_gen, 64); -BTRFS_SETGET_STACK_FUNCS(backup_tree_root_level, struct btrfs_root_backup, - tree_root_level, 8); - -BTRFS_SETGET_STACK_FUNCS(backup_chunk_root, struct btrfs_root_backup, - chunk_root, 64); -BTRFS_SETGET_STACK_FUNCS(backup_chunk_root_gen, struct btrfs_root_backup, - chunk_root_gen, 64); -BTRFS_SETGET_STACK_FUNCS(backup_chunk_root_level, struct btrfs_root_backup, - chunk_root_level, 8); - -BTRFS_SETGET_STACK_FUNCS(backup_extent_root, struct btrfs_root_backup, - extent_root, 64); -BTRFS_SETGET_STACK_FUNCS(backup_extent_root_gen, struct btrfs_root_backup, - extent_root_gen, 64); -BTRFS_SETGET_STACK_FUNCS(backup_extent_root_level, struct btrfs_root_backup, - extent_root_level, 8); - -BTRFS_SETGET_STACK_FUNCS(backup_fs_root, struct btrfs_root_backup, - fs_root, 64); -BTRFS_SETGET_STACK_FUNCS(backup_fs_root_gen, struct btrfs_root_backup, - fs_root_gen, 64); -BTRFS_SETGET_STACK_FUNCS(backup_fs_root_level, struct btrfs_root_backup, - fs_root_level, 8); - -BTRFS_SETGET_STACK_FUNCS(backup_dev_root, struct btrfs_root_backup, - dev_root, 64); -BTRFS_SETGET_STACK_FUNCS(backup_dev_root_gen, struct btrfs_root_backup, - dev_root_gen, 64); -BTRFS_SETGET_STACK_FUNCS(backup_dev_root_level, struct btrfs_root_backup, - dev_root_level, 8); - -BTRFS_SETGET_STACK_FUNCS(backup_csum_root, struct btrfs_root_backup, - csum_root, 64); -BTRFS_SETGET_STACK_FUNCS(backup_csum_root_gen, struct btrfs_root_backup, - csum_root_gen, 64); -BTRFS_SETGET_STACK_FUNCS(backup_csum_root_level, struct btrfs_root_backup, - csum_root_level, 8); -BTRFS_SETGET_STACK_FUNCS(backup_total_bytes, struct btrfs_root_backup, - total_bytes, 64); -BTRFS_SETGET_STACK_FUNCS(backup_bytes_used, struct btrfs_root_backup, - bytes_used, 64); -BTRFS_SETGET_STACK_FUNCS(backup_num_devices, struct btrfs_root_backup, - num_devices, 64); - -/* struct btrfs_balance_item */ -BTRFS_SETGET_FUNCS(balance_flags, struct btrfs_balance_item, flags, 64); - -static inline void btrfs_balance_data(struct extent_buffer *eb, - struct btrfs_balance_item *bi, - struct btrfs_disk_balance_args *ba) -{ - read_eb_member(eb, bi, struct btrfs_balance_item, data, ba); -} - -static inline void btrfs_set_balance_data(struct extent_buffer *eb, - struct btrfs_balance_item *bi, - struct btrfs_disk_balance_args *ba) -{ - write_eb_member(eb, bi, struct btrfs_balance_item, data, ba); -} - -static inline void btrfs_balance_meta(struct extent_buffer *eb, - struct btrfs_balance_item *bi, - struct btrfs_disk_balance_args *ba) -{ - read_eb_member(eb, bi, struct btrfs_balance_item, meta, ba); -} - -static inline void btrfs_set_balance_meta(struct extent_buffer *eb, - struct btrfs_balance_item *bi, - struct btrfs_disk_balance_args *ba) -{ - write_eb_member(eb, bi, struct btrfs_balance_item, meta, ba); -} - -static inline void btrfs_balance_sys(struct extent_buffer *eb, - struct btrfs_balance_item *bi, - struct btrfs_disk_balance_args *ba) -{ - read_eb_member(eb, bi, struct btrfs_balance_item, sys, ba); -} - -static inline void btrfs_set_balance_sys(struct extent_buffer *eb, - struct btrfs_balance_item *bi, - struct btrfs_disk_balance_args *ba) -{ - write_eb_member(eb, bi, struct btrfs_balance_item, sys, ba); -} - -static inline void -btrfs_disk_balance_args_to_cpu(struct btrfs_balance_args *cpu, - struct btrfs_disk_balance_args *disk) -{ - memset(cpu, 0, sizeof(*cpu)); - - cpu->profiles = le64_to_cpu(disk->profiles); - cpu->usage = le64_to_cpu(disk->usage); - cpu->devid = le64_to_cpu(disk->devid); - cpu->pstart = le64_to_cpu(disk->pstart); - cpu->pend = le64_to_cpu(disk->pend); - cpu->vstart = le64_to_cpu(disk->vstart); - cpu->vend = le64_to_cpu(disk->vend); - cpu->target = le64_to_cpu(disk->target); - cpu->flags = le64_to_cpu(disk->flags); - cpu->limit = le64_to_cpu(disk->limit); -} - -static inline void -btrfs_cpu_balance_args_to_disk(struct btrfs_disk_balance_args *disk, - struct btrfs_balance_args *cpu) -{ - memset(disk, 0, sizeof(*disk)); - - disk->profiles = cpu_to_le64(cpu->profiles); - disk->usage = cpu_to_le64(cpu->usage); - disk->devid = cpu_to_le64(cpu->devid); - disk->pstart = cpu_to_le64(cpu->pstart); - disk->pend = cpu_to_le64(cpu->pend); - disk->vstart = cpu_to_le64(cpu->vstart); - disk->vend = cpu_to_le64(cpu->vend); - disk->target = cpu_to_le64(cpu->target); - disk->flags = cpu_to_le64(cpu->flags); - disk->limit = cpu_to_le64(cpu->limit); -} - -/* struct btrfs_super_block */ -BTRFS_SETGET_STACK_FUNCS(super_bytenr, struct btrfs_super_block, bytenr, 64); -BTRFS_SETGET_STACK_FUNCS(super_flags, struct btrfs_super_block, flags, 64); -BTRFS_SETGET_STACK_FUNCS(super_generation, struct btrfs_super_block, - generation, 64); -BTRFS_SETGET_STACK_FUNCS(super_root, struct btrfs_super_block, root, 64); -BTRFS_SETGET_STACK_FUNCS(super_sys_array_size, - struct btrfs_super_block, sys_chunk_array_size, 32); -BTRFS_SETGET_STACK_FUNCS(super_chunk_root_generation, - struct btrfs_super_block, chunk_root_generation, 64); -BTRFS_SETGET_STACK_FUNCS(super_root_level, struct btrfs_super_block, - root_level, 8); -BTRFS_SETGET_STACK_FUNCS(super_chunk_root, struct btrfs_super_block, - chunk_root, 64); -BTRFS_SETGET_STACK_FUNCS(super_chunk_root_level, struct btrfs_super_block, - chunk_root_level, 8); -BTRFS_SETGET_STACK_FUNCS(super_log_root, struct btrfs_super_block, - log_root, 64); -BTRFS_SETGET_STACK_FUNCS(super_log_root_transid, struct btrfs_super_block, - log_root_transid, 64); -BTRFS_SETGET_STACK_FUNCS(super_log_root_level, struct btrfs_super_block, - log_root_level, 8); -BTRFS_SETGET_STACK_FUNCS(super_total_bytes, struct btrfs_super_block, - total_bytes, 64); -BTRFS_SETGET_STACK_FUNCS(super_bytes_used, struct btrfs_super_block, - bytes_used, 64); -BTRFS_SETGET_STACK_FUNCS(super_sectorsize, struct btrfs_super_block, - sectorsize, 32); -BTRFS_SETGET_STACK_FUNCS(super_nodesize, struct btrfs_super_block, - nodesize, 32); -BTRFS_SETGET_STACK_FUNCS(super_stripesize, struct btrfs_super_block, - stripesize, 32); -BTRFS_SETGET_STACK_FUNCS(super_root_dir, struct btrfs_super_block, - root_dir_objectid, 64); -BTRFS_SETGET_STACK_FUNCS(super_num_devices, struct btrfs_super_block, - num_devices, 64); -BTRFS_SETGET_STACK_FUNCS(super_compat_flags, struct btrfs_super_block, - compat_flags, 64); -BTRFS_SETGET_STACK_FUNCS(super_compat_ro_flags, struct btrfs_super_block, - compat_ro_flags, 64); -BTRFS_SETGET_STACK_FUNCS(super_incompat_flags, struct btrfs_super_block, - incompat_flags, 64); -BTRFS_SETGET_STACK_FUNCS(super_csum_type, struct btrfs_super_block, - csum_type, 16); -BTRFS_SETGET_STACK_FUNCS(super_cache_generation, struct btrfs_super_block, - cache_generation, 64); -BTRFS_SETGET_STACK_FUNCS(super_magic, struct btrfs_super_block, magic, 64); -BTRFS_SETGET_STACK_FUNCS(super_uuid_tree_generation, struct btrfs_super_block, - uuid_tree_generation, 64); - -static inline int btrfs_super_csum_size(struct btrfs_super_block *s) -{ - u16 t = btrfs_super_csum_type(s); - /* - * csum type is validated at mount time - */ - return btrfs_csum_sizes[t]; -} - -static inline unsigned long btrfs_leaf_data(struct extent_buffer *l) -{ - return offsetof(struct btrfs_leaf, items); -} - -/* - * The leaf data grows from end-to-front in the node. - * this returns the address of the start of the last item, - * which is the stop of the leaf data stack - */ -static inline unsigned int leaf_data_end(struct btrfs_root *root, - struct extent_buffer *leaf) -{ - u32 nr = btrfs_header_nritems(leaf); - - if (nr == 0) - return BTRFS_LEAF_DATA_SIZE(root); - return btrfs_item_offset_nr(leaf, nr - 1); -} - -/* struct btrfs_file_extent_item */ -BTRFS_SETGET_FUNCS(file_extent_type, struct btrfs_file_extent_item, type, 8); -BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_bytenr, - struct btrfs_file_extent_item, disk_bytenr, 64); -BTRFS_SETGET_STACK_FUNCS(stack_file_extent_offset, - struct btrfs_file_extent_item, offset, 64); -BTRFS_SETGET_STACK_FUNCS(stack_file_extent_generation, - struct btrfs_file_extent_item, generation, 64); -BTRFS_SETGET_STACK_FUNCS(stack_file_extent_num_bytes, - struct btrfs_file_extent_item, num_bytes, 64); -BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_num_bytes, - struct btrfs_file_extent_item, disk_num_bytes, 64); -BTRFS_SETGET_STACK_FUNCS(stack_file_extent_compression, - struct btrfs_file_extent_item, compression, 8); - -static inline unsigned long -btrfs_file_extent_inline_start(struct btrfs_file_extent_item *e) -{ - return (unsigned long)e + BTRFS_FILE_EXTENT_INLINE_DATA_START; -} - -static inline u32 btrfs_file_extent_calc_inline_size(u32 datasize) -{ - return BTRFS_FILE_EXTENT_INLINE_DATA_START + datasize; -} - -BTRFS_SETGET_FUNCS(file_extent_disk_bytenr, struct btrfs_file_extent_item, - disk_bytenr, 64); -BTRFS_SETGET_FUNCS(file_extent_generation, struct btrfs_file_extent_item, - generation, 64); -BTRFS_SETGET_FUNCS(file_extent_disk_num_bytes, struct btrfs_file_extent_item, - disk_num_bytes, 64); -BTRFS_SETGET_FUNCS(file_extent_offset, struct btrfs_file_extent_item, - offset, 64); -BTRFS_SETGET_FUNCS(file_extent_num_bytes, struct btrfs_file_extent_item, - num_bytes, 64); -BTRFS_SETGET_FUNCS(file_extent_ram_bytes, struct btrfs_file_extent_item, - ram_bytes, 64); -BTRFS_SETGET_FUNCS(file_extent_compression, struct btrfs_file_extent_item, - compression, 8); -BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item, - encryption, 8); -BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item, - other_encoding, 16); - -/* - * this returns the number of bytes used by the item on disk, minus the - * size of any extent headers. If a file is compressed on disk, this is - * the compressed size - */ -static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb, - struct btrfs_item *e) -{ - return btrfs_item_size(eb, e) - BTRFS_FILE_EXTENT_INLINE_DATA_START; -} - -/* this returns the number of file bytes represented by the inline item. - * If an item is compressed, this is the uncompressed size - */ -static inline u32 btrfs_file_extent_inline_len(struct extent_buffer *eb, - int slot, - struct btrfs_file_extent_item *fi) -{ - struct btrfs_map_token token; - - btrfs_init_map_token(&token); - /* - * return the space used on disk if this item isn't - * compressed or encoded - */ - if (btrfs_token_file_extent_compression(eb, fi, &token) == 0 && - btrfs_token_file_extent_encryption(eb, fi, &token) == 0 && - btrfs_token_file_extent_other_encoding(eb, fi, &token) == 0) { - return btrfs_file_extent_inline_item_len(eb, - btrfs_item_nr(slot)); - } - - /* otherwise use the ram bytes field */ - return btrfs_token_file_extent_ram_bytes(eb, fi, &token); -} - - -/* btrfs_dev_stats_item */ -static inline u64 btrfs_dev_stats_value(struct extent_buffer *eb, - struct btrfs_dev_stats_item *ptr, - int index) -{ - u64 val; - - read_extent_buffer(eb, &val, - offsetof(struct btrfs_dev_stats_item, values) + - ((unsigned long)ptr) + (index * sizeof(u64)), - sizeof(val)); - return val; -} - -static inline void btrfs_set_dev_stats_value(struct extent_buffer *eb, - struct btrfs_dev_stats_item *ptr, - int index, u64 val) -{ - write_extent_buffer(eb, &val, - offsetof(struct btrfs_dev_stats_item, values) + - ((unsigned long)ptr) + (index * sizeof(u64)), - sizeof(val)); -} - -/* btrfs_qgroup_status_item */ -BTRFS_SETGET_FUNCS(qgroup_status_generation, struct btrfs_qgroup_status_item, - generation, 64); -BTRFS_SETGET_FUNCS(qgroup_status_version, struct btrfs_qgroup_status_item, - version, 64); -BTRFS_SETGET_FUNCS(qgroup_status_flags, struct btrfs_qgroup_status_item, - flags, 64); -BTRFS_SETGET_FUNCS(qgroup_status_rescan, struct btrfs_qgroup_status_item, - rescan, 64); - -/* btrfs_qgroup_info_item */ -BTRFS_SETGET_FUNCS(qgroup_info_generation, struct btrfs_qgroup_info_item, - generation, 64); -BTRFS_SETGET_FUNCS(qgroup_info_rfer, struct btrfs_qgroup_info_item, rfer, 64); -BTRFS_SETGET_FUNCS(qgroup_info_rfer_cmpr, struct btrfs_qgroup_info_item, - rfer_cmpr, 64); -BTRFS_SETGET_FUNCS(qgroup_info_excl, struct btrfs_qgroup_info_item, excl, 64); -BTRFS_SETGET_FUNCS(qgroup_info_excl_cmpr, struct btrfs_qgroup_info_item, - excl_cmpr, 64); - -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_generation, - struct btrfs_qgroup_info_item, generation, 64); -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_rfer, struct btrfs_qgroup_info_item, - rfer, 64); -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_rfer_cmpr, - struct btrfs_qgroup_info_item, rfer_cmpr, 64); -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_excl, struct btrfs_qgroup_info_item, - excl, 64); -BTRFS_SETGET_STACK_FUNCS(stack_qgroup_info_excl_cmpr, - struct btrfs_qgroup_info_item, excl_cmpr, 64); - -/* btrfs_qgroup_limit_item */ -BTRFS_SETGET_FUNCS(qgroup_limit_flags, struct btrfs_qgroup_limit_item, - flags, 64); -BTRFS_SETGET_FUNCS(qgroup_limit_max_rfer, struct btrfs_qgroup_limit_item, - max_rfer, 64); -BTRFS_SETGET_FUNCS(qgroup_limit_max_excl, struct btrfs_qgroup_limit_item, - max_excl, 64); -BTRFS_SETGET_FUNCS(qgroup_limit_rsv_rfer, struct btrfs_qgroup_limit_item, - rsv_rfer, 64); -BTRFS_SETGET_FUNCS(qgroup_limit_rsv_excl, struct btrfs_qgroup_limit_item, - rsv_excl, 64); - -/* btrfs_dev_replace_item */ -BTRFS_SETGET_FUNCS(dev_replace_src_devid, - struct btrfs_dev_replace_item, src_devid, 64); -BTRFS_SETGET_FUNCS(dev_replace_cont_reading_from_srcdev_mode, - struct btrfs_dev_replace_item, cont_reading_from_srcdev_mode, - 64); -BTRFS_SETGET_FUNCS(dev_replace_replace_state, struct btrfs_dev_replace_item, - replace_state, 64); -BTRFS_SETGET_FUNCS(dev_replace_time_started, struct btrfs_dev_replace_item, - time_started, 64); -BTRFS_SETGET_FUNCS(dev_replace_time_stopped, struct btrfs_dev_replace_item, - time_stopped, 64); -BTRFS_SETGET_FUNCS(dev_replace_num_write_errors, struct btrfs_dev_replace_item, - num_write_errors, 64); -BTRFS_SETGET_FUNCS(dev_replace_num_uncorrectable_read_errors, - struct btrfs_dev_replace_item, num_uncorrectable_read_errors, - 64); -BTRFS_SETGET_FUNCS(dev_replace_cursor_left, struct btrfs_dev_replace_item, - cursor_left, 64); -BTRFS_SETGET_FUNCS(dev_replace_cursor_right, struct btrfs_dev_replace_item, - cursor_right, 64); - -BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_src_devid, - struct btrfs_dev_replace_item, src_devid, 64); -BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cont_reading_from_srcdev_mode, - struct btrfs_dev_replace_item, - cont_reading_from_srcdev_mode, 64); -BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_replace_state, - struct btrfs_dev_replace_item, replace_state, 64); -BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_time_started, - struct btrfs_dev_replace_item, time_started, 64); -BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_time_stopped, - struct btrfs_dev_replace_item, time_stopped, 64); -BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_num_write_errors, - struct btrfs_dev_replace_item, num_write_errors, 64); -BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_num_uncorrectable_read_errors, - struct btrfs_dev_replace_item, - num_uncorrectable_read_errors, 64); -BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_left, - struct btrfs_dev_replace_item, cursor_left, 64); -BTRFS_SETGET_STACK_FUNCS(stack_dev_replace_cursor_right, - struct btrfs_dev_replace_item, cursor_right, 64); - -static inline struct btrfs_fs_info *btrfs_sb(struct super_block *sb) -{ - return sb->s_fs_info; -} - -/* helper function to cast into the data area of the leaf. */ -#define btrfs_item_ptr(leaf, slot, type) \ - ((type *)(btrfs_leaf_data(leaf) + \ - btrfs_item_offset_nr(leaf, slot))) - -#define btrfs_item_ptr_offset(leaf, slot) \ - ((unsigned long)(btrfs_leaf_data(leaf) + \ - btrfs_item_offset_nr(leaf, slot))) - -static inline bool btrfs_mixed_space_info(struct btrfs_space_info *space_info) -{ - return ((space_info->flags & BTRFS_BLOCK_GROUP_METADATA) && - (space_info->flags & BTRFS_BLOCK_GROUP_DATA)); -} - -static inline gfp_t btrfs_alloc_write_mask(struct address_space *mapping) -{ - return mapping_gfp_constraint(mapping, ~__GFP_FS); -} - -/* extent-tree.c */ - -u64 btrfs_csum_bytes_to_leaves(struct btrfs_root *root, u64 csum_bytes); - -static inline u64 btrfs_calc_trans_metadata_size(struct btrfs_root *root, - unsigned num_items) -{ - return root->nodesize * BTRFS_MAX_LEVEL * 2 * num_items; -} - -/* - * Doing a truncate won't result in new nodes or leaves, just what we need for - * COW. - */ -static inline u64 btrfs_calc_trunc_metadata_size(struct btrfs_root *root, - unsigned num_items) -{ - return root->nodesize * BTRFS_MAX_LEVEL * num_items; -} - -int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -int btrfs_check_space_for_delayed_refs(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -void btrfs_dec_block_group_reservations(struct btrfs_fs_info *fs_info, - const u64 start); -void btrfs_wait_block_group_reservations(struct btrfs_block_group_cache *bg); -bool btrfs_inc_nocow_writers(struct btrfs_fs_info *fs_info, u64 bytenr); -void btrfs_dec_nocow_writers(struct btrfs_fs_info *fs_info, u64 bytenr); -void btrfs_wait_nocow_writers(struct btrfs_block_group_cache *bg); -void btrfs_put_block_group(struct btrfs_block_group_cache *cache); -int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, - struct btrfs_root *root, unsigned long count); -int btrfs_async_run_delayed_refs(struct btrfs_root *root, - unsigned long count, u64 transid, int wait); -int btrfs_lookup_data_extent(struct btrfs_root *root, u64 start, u64 len); -int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 bytenr, - u64 offset, int metadata, u64 *refs, u64 *flags); -int btrfs_pin_extent(struct btrfs_root *root, - u64 bytenr, u64 num, int reserved); -int btrfs_pin_extent_for_log_replay(struct btrfs_root *root, - u64 bytenr, u64 num_bytes); -int btrfs_exclude_logged_extents(struct btrfs_root *root, - struct extent_buffer *eb); -int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 objectid, u64 offset, u64 bytenr); -struct btrfs_block_group_cache *btrfs_lookup_block_group( - struct btrfs_fs_info *info, - u64 bytenr); -void btrfs_get_block_group(struct btrfs_block_group_cache *cache); -void btrfs_put_block_group(struct btrfs_block_group_cache *cache); -int get_block_group_index(struct btrfs_block_group_cache *cache); -struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 parent, - u64 root_objectid, - struct btrfs_disk_key *key, int level, - u64 hint, u64 empty_size); -void btrfs_free_tree_block(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct extent_buffer *buf, - u64 parent, int last_ref); -int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 root_objectid, u64 owner, - u64 offset, u64 ram_bytes, - struct btrfs_key *ins); -int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 root_objectid, u64 owner, u64 offset, - struct btrfs_key *ins); -int btrfs_reserve_extent(struct btrfs_root *root, u64 ram_bytes, u64 num_bytes, - u64 min_alloc_size, u64 empty_size, u64 hint_byte, - struct btrfs_key *ins, int is_data, int delalloc); -int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, - struct extent_buffer *buf, int full_backref); -int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, - struct extent_buffer *buf, int full_backref); -int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 bytenr, u64 num_bytes, u64 flags, - int level, int is_data); -int btrfs_free_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, - u64 owner, u64 offset); - -int btrfs_free_reserved_extent(struct btrfs_root *root, u64 start, u64 len, - int delalloc); -int btrfs_free_and_pin_reserved_extent(struct btrfs_root *root, - u64 start, u64 len); -void btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 bytenr, u64 num_bytes, u64 parent, - u64 root_objectid, u64 owner, u64 offset); - -int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -int btrfs_setup_space_cache(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr); -int btrfs_free_block_groups(struct btrfs_fs_info *info); -int btrfs_read_block_groups(struct btrfs_root *root); -int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr); -int btrfs_make_block_group(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 bytes_used, - u64 type, u64 chunk_objectid, u64 chunk_offset, - u64 size); -struct btrfs_trans_handle *btrfs_start_trans_remove_block_group( - struct btrfs_fs_info *fs_info, - const u64 chunk_offset); -int btrfs_remove_block_group(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 group_start, - struct extent_map *em); -void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info); -void btrfs_get_block_group_trimming(struct btrfs_block_group_cache *cache); -void btrfs_put_block_group_trimming(struct btrfs_block_group_cache *cache); -void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data); -void btrfs_clear_space_info_full(struct btrfs_fs_info *info); - -enum btrfs_reserve_flush_enum { - /* If we are in the transaction, we can't flush anything.*/ - BTRFS_RESERVE_NO_FLUSH, - /* - * Flushing delalloc may cause deadlock somewhere, in this - * case, use FLUSH LIMIT - */ - BTRFS_RESERVE_FLUSH_LIMIT, - BTRFS_RESERVE_FLUSH_ALL, -}; - -enum btrfs_flush_state { - FLUSH_DELAYED_ITEMS_NR = 1, - FLUSH_DELAYED_ITEMS = 2, - FLUSH_DELALLOC = 3, - FLUSH_DELALLOC_WAIT = 4, - ALLOC_CHUNK = 5, - COMMIT_TRANS = 6, -}; - -int btrfs_check_data_free_space(struct inode *inode, u64 start, u64 len); -int btrfs_alloc_data_chunk_ondemand(struct inode *inode, u64 bytes); -void btrfs_free_reserved_data_space(struct inode *inode, u64 start, u64 len); -void btrfs_free_reserved_data_space_noquota(struct inode *inode, u64 start, - u64 len); -void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -void btrfs_trans_release_chunk_metadata(struct btrfs_trans_handle *trans); -int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans, - struct inode *inode); -void btrfs_orphan_release_metadata(struct inode *inode); -int btrfs_subvolume_reserve_metadata(struct btrfs_root *root, - struct btrfs_block_rsv *rsv, - int nitems, - u64 *qgroup_reserved, bool use_global_rsv); -void btrfs_subvolume_release_metadata(struct btrfs_root *root, - struct btrfs_block_rsv *rsv, - u64 qgroup_reserved); -int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes); -void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes); -int btrfs_delalloc_reserve_space(struct inode *inode, u64 start, u64 len); -void btrfs_delalloc_release_space(struct inode *inode, u64 start, u64 len); -void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv, unsigned short type); -struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_root *root, - unsigned short type); -void btrfs_free_block_rsv(struct btrfs_root *root, - struct btrfs_block_rsv *rsv); -void __btrfs_free_block_rsv(struct btrfs_block_rsv *rsv); -int btrfs_block_rsv_add(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, u64 num_bytes, - enum btrfs_reserve_flush_enum flush); -int btrfs_block_rsv_check(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, int min_factor); -int btrfs_block_rsv_refill(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, u64 min_reserved, - enum btrfs_reserve_flush_enum flush); -int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv, - struct btrfs_block_rsv *dst_rsv, u64 num_bytes, - int update_size); -int btrfs_cond_migrate_bytes(struct btrfs_fs_info *fs_info, - struct btrfs_block_rsv *dest, u64 num_bytes, - int min_factor); -void btrfs_block_rsv_release(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, - u64 num_bytes); -int btrfs_inc_block_group_ro(struct btrfs_root *root, - struct btrfs_block_group_cache *cache); -void btrfs_dec_block_group_ro(struct btrfs_root *root, - struct btrfs_block_group_cache *cache); -void btrfs_put_block_group_cache(struct btrfs_fs_info *info); -u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo); -int btrfs_error_unpin_extent_range(struct btrfs_root *root, - u64 start, u64 end); -int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr, - u64 num_bytes, u64 *actual_bytes); -int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 type); -int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range); - -int btrfs_init_space_info(struct btrfs_fs_info *fs_info); -int btrfs_delayed_refs_qgroup_accounting(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info); -int __get_raid_index(u64 flags); -int btrfs_start_write_no_snapshoting(struct btrfs_root *root); -void btrfs_end_write_no_snapshoting(struct btrfs_root *root); -void btrfs_wait_for_snapshot_creation(struct btrfs_root *root); -void check_system_chunk(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - const u64 type); -u64 add_new_free_space(struct btrfs_block_group_cache *block_group, - struct btrfs_fs_info *info, u64 start, u64 end); - -/* ctree.c */ -int btrfs_bin_search(struct extent_buffer *eb, struct btrfs_key *key, - int level, int *slot); -int btrfs_comp_cpu_keys(struct btrfs_key *k1, struct btrfs_key *k2); -int btrfs_previous_item(struct btrfs_root *root, - struct btrfs_path *path, u64 min_objectid, - int type); -int btrfs_previous_extent_item(struct btrfs_root *root, - struct btrfs_path *path, u64 min_objectid); -void btrfs_set_item_key_safe(struct btrfs_fs_info *fs_info, - struct btrfs_path *path, - struct btrfs_key *new_key); -struct extent_buffer *btrfs_root_node(struct btrfs_root *root); -struct extent_buffer *btrfs_lock_root_node(struct btrfs_root *root); -int btrfs_find_next_key(struct btrfs_root *root, struct btrfs_path *path, - struct btrfs_key *key, int lowest_level, - u64 min_trans); -int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key *min_key, - struct btrfs_path *path, - u64 min_trans); -enum btrfs_compare_tree_result { - BTRFS_COMPARE_TREE_NEW, - BTRFS_COMPARE_TREE_DELETED, - BTRFS_COMPARE_TREE_CHANGED, - BTRFS_COMPARE_TREE_SAME, -}; -typedef int (*btrfs_changed_cb_t)(struct btrfs_root *left_root, - struct btrfs_root *right_root, - struct btrfs_path *left_path, - struct btrfs_path *right_path, - struct btrfs_key *key, - enum btrfs_compare_tree_result result, - void *ctx); -int btrfs_compare_trees(struct btrfs_root *left_root, - struct btrfs_root *right_root, - btrfs_changed_cb_t cb, void *ctx); -int btrfs_cow_block(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct extent_buffer *buf, - struct extent_buffer *parent, int parent_slot, - struct extent_buffer **cow_ret); -int btrfs_copy_root(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct extent_buffer *buf, - struct extent_buffer **cow_ret, u64 new_root_objectid); -int btrfs_block_can_be_shared(struct btrfs_root *root, - struct extent_buffer *buf); -void btrfs_extend_item(struct btrfs_root *root, struct btrfs_path *path, - u32 data_size); -void btrfs_truncate_item(struct btrfs_root *root, struct btrfs_path *path, - u32 new_size, int from_end); -int btrfs_split_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_key *new_key, - unsigned long split_offset); -int btrfs_duplicate_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_key *new_key); -int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *path, - u64 inum, u64 ioff, u8 key_type, struct btrfs_key *found_key); -int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root - *root, struct btrfs_key *key, struct btrfs_path *p, int - ins_len, int cow); -int btrfs_search_old_slot(struct btrfs_root *root, struct btrfs_key *key, - struct btrfs_path *p, u64 time_seq); -int btrfs_search_slot_for_read(struct btrfs_root *root, - struct btrfs_key *key, struct btrfs_path *p, - int find_higher, int return_any); -int btrfs_realloc_node(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct extent_buffer *parent, - int start_slot, u64 *last_ret, - struct btrfs_key *progress); -void btrfs_release_path(struct btrfs_path *p); -struct btrfs_path *btrfs_alloc_path(void); -void btrfs_free_path(struct btrfs_path *p); -void btrfs_set_path_blocking(struct btrfs_path *p); -void btrfs_clear_path_blocking(struct btrfs_path *p, - struct extent_buffer *held, int held_rw); -void btrfs_unlock_up_safe(struct btrfs_path *p, int level); - -int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root, - struct btrfs_path *path, int slot, int nr); -static inline int btrfs_del_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path) -{ - return btrfs_del_items(trans, root, path, path->slots[0], 1); -} - -void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path, - struct btrfs_key *cpu_key, u32 *data_size, - u32 total_data, u32 total_size, int nr); -int btrfs_insert_item(struct btrfs_trans_handle *trans, struct btrfs_root - *root, struct btrfs_key *key, void *data, u32 data_size); -int btrfs_insert_empty_items(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_key *cpu_key, u32 *data_size, int nr); - -static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_key *key, - u32 data_size) -{ - return btrfs_insert_empty_items(trans, root, path, key, &data_size, 1); -} - -int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); -int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path); -int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, - u64 time_seq); -static inline int btrfs_next_old_item(struct btrfs_root *root, - struct btrfs_path *p, u64 time_seq) -{ - ++p->slots[0]; - if (p->slots[0] >= btrfs_header_nritems(p->nodes[0])) - return btrfs_next_old_leaf(root, p, time_seq); - return 0; -} -static inline int btrfs_next_item(struct btrfs_root *root, struct btrfs_path *p) -{ - return btrfs_next_old_item(root, p, 0); -} -int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf); -int __must_check btrfs_drop_snapshot(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, - int update_ref, int for_reloc); -int btrfs_drop_subtree(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct extent_buffer *node, - struct extent_buffer *parent); -static inline int btrfs_fs_closing(struct btrfs_fs_info *fs_info) -{ - /* - * Do it this way so we only ever do one test_bit in the normal case. - */ - if (test_bit(BTRFS_FS_CLOSING_START, &fs_info->flags)) { - if (test_bit(BTRFS_FS_CLOSING_DONE, &fs_info->flags)) - return 2; - return 1; - } - return 0; -} - -/* - * If we remount the fs to be R/O or umount the fs, the cleaner needn't do - * anything except sleeping. This function is used to check the status of - * the fs. - */ -static inline int btrfs_need_cleaner_sleep(struct btrfs_root *root) -{ - return (root->fs_info->sb->s_flags & MS_RDONLY || - btrfs_fs_closing(root->fs_info)); -} - -static inline void free_fs_info(struct btrfs_fs_info *fs_info) -{ - kfree(fs_info->balance_ctl); - kfree(fs_info->delayed_root); - kfree(fs_info->extent_root); - kfree(fs_info->tree_root); - kfree(fs_info->chunk_root); - kfree(fs_info->dev_root); - kfree(fs_info->csum_root); - kfree(fs_info->quota_root); - kfree(fs_info->uuid_root); - kfree(fs_info->free_space_root); - kfree(fs_info->super_copy); - kfree(fs_info->super_for_commit); - security_free_mnt_opts(&fs_info->security_opts); - kfree(fs_info); -} - -/* tree mod log functions from ctree.c */ -u64 btrfs_get_tree_mod_seq(struct btrfs_fs_info *fs_info, - struct seq_list *elem); -void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info, - struct seq_list *elem); -int btrfs_old_root_level(struct btrfs_root *root, u64 time_seq); - -/* root-item.c */ -int btrfs_add_root_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *tree_root, - u64 root_id, u64 ref_id, u64 dirid, u64 sequence, - const char *name, int name_len); -int btrfs_del_root_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *tree_root, - u64 root_id, u64 ref_id, u64 dirid, u64 *sequence, - const char *name, int name_len); -int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, - struct btrfs_key *key); -int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root - *root, struct btrfs_key *key, struct btrfs_root_item - *item); -int __must_check btrfs_update_root(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_key *key, - struct btrfs_root_item *item); -int btrfs_find_root(struct btrfs_root *root, struct btrfs_key *search_key, - struct btrfs_path *path, struct btrfs_root_item *root_item, - struct btrfs_key *root_key); -int btrfs_find_orphan_roots(struct btrfs_root *tree_root); -void btrfs_set_root_node(struct btrfs_root_item *item, - struct extent_buffer *node); -void btrfs_check_and_init_root_item(struct btrfs_root_item *item); -void btrfs_update_root_times(struct btrfs_trans_handle *trans, - struct btrfs_root *root); - -/* uuid-tree.c */ -int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, - struct btrfs_root *uuid_root, u8 *uuid, u8 type, - u64 subid); -int btrfs_uuid_tree_rem(struct btrfs_trans_handle *trans, - struct btrfs_root *uuid_root, u8 *uuid, u8 type, - u64 subid); -int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info, - int (*check_func)(struct btrfs_fs_info *, u8 *, u8, - u64)); - -/* dir-item.c */ -int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir, - const char *name, int name_len); -int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, const char *name, - int name_len, struct inode *dir, - struct btrfs_key *location, u8 type, u64 index); -struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, u64 dir, - const char *name, int name_len, - int mod); -struct btrfs_dir_item * -btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, u64 dir, - u64 objectid, const char *name, int name_len, - int mod); -struct btrfs_dir_item * -btrfs_search_dir_index_item(struct btrfs_root *root, - struct btrfs_path *path, u64 dirid, - const char *name, int name_len); -int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_dir_item *di); -int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, u64 objectid, - const char *name, u16 name_len, - const void *data, u16 data_len); -struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, u64 dir, - const char *name, u16 name_len, - int mod); -int verify_dir_item(struct btrfs_root *root, - struct extent_buffer *leaf, - struct btrfs_dir_item *dir_item); -struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, - struct btrfs_path *path, - const char *name, - int name_len); - -/* orphan.c */ -int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 offset); -int btrfs_del_orphan_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 offset); -int btrfs_find_orphan_item(struct btrfs_root *root, u64 offset); - -/* inode-item.c */ -int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - const char *name, int name_len, - u64 inode_objectid, u64 ref_objectid, u64 index); -int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - const char *name, int name_len, - u64 inode_objectid, u64 ref_objectid, u64 *index); -int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, u64 objectid); -int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root - *root, struct btrfs_path *path, - struct btrfs_key *location, int mod); - -struct btrfs_inode_extref * -btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - const char *name, int name_len, - u64 inode_objectid, u64 ref_objectid, int ins_len, - int cow); - -int btrfs_find_name_in_ext_backref(struct btrfs_path *path, - u64 ref_objectid, const char *name, - int name_len, - struct btrfs_inode_extref **extref_ret); - -/* file-item.c */ -struct btrfs_dio_private; -int btrfs_del_csums(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 bytenr, u64 len); -int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, - struct bio *bio, u32 *dst); -int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, - struct bio *bio, u64 logical_offset); -int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 objectid, u64 pos, - u64 disk_offset, u64 disk_num_bytes, - u64 num_bytes, u64 offset, u64 ram_bytes, - u8 compression, u8 encryption, u16 other_encoding); -int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, u64 objectid, - u64 bytenr, int mod); -int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_ordered_sum *sums); -int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, - struct bio *bio, u64 file_start, int contig); -int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, - struct list_head *list, int search_commit); -void btrfs_extent_item_to_extent_map(struct inode *inode, - const struct btrfs_path *path, - struct btrfs_file_extent_item *fi, - const bool new_inline, - struct extent_map *em); - -/* inode.c */ -struct btrfs_delalloc_work { - struct inode *inode; - int delay_iput; - struct completion completion; - struct list_head list; - struct btrfs_work work; -}; - -struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode, - int delay_iput); -void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work); - -struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page, - size_t pg_offset, u64 start, u64 len, - int create); -noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len, - u64 *orig_start, u64 *orig_block_len, - u64 *ram_bytes); - -/* RHEL and EL kernels have a patch that renames PG_checked to FsMisc */ -#if defined(ClearPageFsMisc) && !defined(ClearPageChecked) -#define ClearPageChecked ClearPageFsMisc -#define SetPageChecked SetPageFsMisc -#define PageChecked PageFsMisc -#endif - -/* This forces readahead on a given range of bytes in an inode */ -static inline void btrfs_force_ra(struct address_space *mapping, - struct file_ra_state *ra, struct file *file, - pgoff_t offset, unsigned long req_size) -{ - page_cache_sync_readahead(mapping, ra, file, offset, req_size); -} - -struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry); -int btrfs_set_inode_index(struct inode *dir, u64 *index); -int btrfs_unlink_inode(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *dir, struct inode *inode, - const char *name, int name_len); -int btrfs_add_link(struct btrfs_trans_handle *trans, - struct inode *parent_inode, struct inode *inode, - const char *name, int name_len, int add_backref, u64 index); -int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *dir, u64 objectid, - const char *name, int name_len); -int btrfs_truncate_block(struct inode *inode, loff_t from, loff_t len, - int front); -int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *inode, u64 new_size, - u32 min_type); - -int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput); -int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput, - int nr); -int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end, - struct extent_state **cached_state, int dedupe); -int btrfs_create_subvol_root(struct btrfs_trans_handle *trans, - struct btrfs_root *new_root, - struct btrfs_root *parent_root, - u64 new_dirid); -int btrfs_merge_bio_hook(struct page *page, unsigned long offset, - size_t size, struct bio *bio, - unsigned long bio_flags); -int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); -int btrfs_readpage(struct file *file, struct page *page); -void btrfs_evict_inode(struct inode *inode); -int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc); -struct inode *btrfs_alloc_inode(struct super_block *sb); -void btrfs_destroy_inode(struct inode *inode); -int btrfs_drop_inode(struct inode *inode); -int btrfs_init_cachep(void); -void btrfs_destroy_cachep(void); -long btrfs_ioctl_trans_end(struct file *file); -struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, - struct btrfs_root *root, int *was_new); -struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, - size_t pg_offset, u64 start, u64 end, - int create); -int btrfs_update_inode(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *inode); -int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct inode *inode); -int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode); -int btrfs_orphan_cleanup(struct btrfs_root *root); -void btrfs_orphan_commit_root(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size); -void btrfs_invalidate_inodes(struct btrfs_root *root); -void btrfs_add_delayed_iput(struct inode *inode); -void btrfs_run_delayed_iputs(struct btrfs_root *root); -int btrfs_prealloc_file_range(struct inode *inode, int mode, - u64 start, u64 num_bytes, u64 min_size, - loff_t actual_len, u64 *alloc_hint); -int btrfs_prealloc_file_range_trans(struct inode *inode, - struct btrfs_trans_handle *trans, int mode, - u64 start, u64 num_bytes, u64 min_size, - loff_t actual_len, u64 *alloc_hint); -extern const struct dentry_operations btrfs_dentry_operations; -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS -void btrfs_test_inode_set_ops(struct inode *inode); -#endif - -/* ioctl.c */ -long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -long btrfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -int btrfs_ioctl_get_supported_features(void __user *arg); -void btrfs_update_iflags(struct inode *inode); -void btrfs_inherit_iflags(struct inode *inode, struct inode *dir); -int btrfs_is_empty_uuid(u8 *uuid); -int btrfs_defrag_file(struct inode *inode, struct file *file, - struct btrfs_ioctl_defrag_range_args *range, - u64 newer_than, unsigned long max_pages); -void btrfs_get_block_group_info(struct list_head *groups_list, - struct btrfs_ioctl_space_info *space); -void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock, - struct btrfs_ioctl_balance_args *bargs); -ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen, - struct file *dst_file, u64 dst_loff); - -/* file.c */ -int btrfs_auto_defrag_init(void); -void btrfs_auto_defrag_exit(void); -int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, - struct inode *inode); -int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info); -void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info); -int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync); -void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, - int skip_pinned); -extern const struct file_operations btrfs_file_operations; -int __btrfs_drop_extents(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct inode *inode, - struct btrfs_path *path, u64 start, u64 end, - u64 *drop_end, int drop_cache, - int replace_extent, - u32 extent_item_size, - int *key_inserted); -int btrfs_drop_extents(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct inode *inode, u64 start, - u64 end, int drop_cache); -int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, - struct inode *inode, u64 start, u64 end); -int btrfs_release_file(struct inode *inode, struct file *file); -int btrfs_dirty_pages(struct btrfs_root *root, struct inode *inode, - struct page **pages, size_t num_pages, - loff_t pos, size_t write_bytes, - struct extent_state **cached); -int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end); -ssize_t btrfs_copy_file_range(struct file *file_in, loff_t pos_in, - struct file *file_out, loff_t pos_out, - size_t len, unsigned int flags); -int btrfs_clone_file_range(struct file *file_in, loff_t pos_in, - struct file *file_out, loff_t pos_out, u64 len); - -/* tree-defrag.c */ -int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, - struct btrfs_root *root); - -/* sysfs.c */ -int btrfs_init_sysfs(void); -void btrfs_exit_sysfs(void); -int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info); -void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info); - -/* xattr.c */ -ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size); - -/* super.c */ -int btrfs_parse_options(struct btrfs_root *root, char *options, - unsigned long new_flags); -int btrfs_sync_fs(struct super_block *sb, int wait); - -static inline __printf(2, 3) -void btrfs_no_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...) -{ -} - -#ifdef CONFIG_PRINTK -__printf(2, 3) -void btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...); -#else -#define btrfs_printk(fs_info, fmt, args...) \ - btrfs_no_printk(fs_info, fmt, ##args) -#endif - -#define btrfs_emerg(fs_info, fmt, args...) \ - btrfs_printk(fs_info, KERN_EMERG fmt, ##args) -#define btrfs_alert(fs_info, fmt, args...) \ - btrfs_printk(fs_info, KERN_ALERT fmt, ##args) -#define btrfs_crit(fs_info, fmt, args...) \ - btrfs_printk(fs_info, KERN_CRIT fmt, ##args) -#define btrfs_err(fs_info, fmt, args...) \ - btrfs_printk(fs_info, KERN_ERR fmt, ##args) -#define btrfs_warn(fs_info, fmt, args...) \ - btrfs_printk(fs_info, KERN_WARNING fmt, ##args) -#define btrfs_notice(fs_info, fmt, args...) \ - btrfs_printk(fs_info, KERN_NOTICE fmt, ##args) -#define btrfs_info(fs_info, fmt, args...) \ - btrfs_printk(fs_info, KERN_INFO fmt, ##args) - -/* - * Wrappers that use printk_in_rcu - */ -#define btrfs_emerg_in_rcu(fs_info, fmt, args...) \ - btrfs_printk_in_rcu(fs_info, KERN_EMERG fmt, ##args) -#define btrfs_alert_in_rcu(fs_info, fmt, args...) \ - btrfs_printk_in_rcu(fs_info, KERN_ALERT fmt, ##args) -#define btrfs_crit_in_rcu(fs_info, fmt, args...) \ - btrfs_printk_in_rcu(fs_info, KERN_CRIT fmt, ##args) -#define btrfs_err_in_rcu(fs_info, fmt, args...) \ - btrfs_printk_in_rcu(fs_info, KERN_ERR fmt, ##args) -#define btrfs_warn_in_rcu(fs_info, fmt, args...) \ - btrfs_printk_in_rcu(fs_info, KERN_WARNING fmt, ##args) -#define btrfs_notice_in_rcu(fs_info, fmt, args...) \ - btrfs_printk_in_rcu(fs_info, KERN_NOTICE fmt, ##args) -#define btrfs_info_in_rcu(fs_info, fmt, args...) \ - btrfs_printk_in_rcu(fs_info, KERN_INFO fmt, ##args) - -/* - * Wrappers that use a ratelimited printk_in_rcu - */ -#define btrfs_emerg_rl_in_rcu(fs_info, fmt, args...) \ - btrfs_printk_rl_in_rcu(fs_info, KERN_EMERG fmt, ##args) -#define btrfs_alert_rl_in_rcu(fs_info, fmt, args...) \ - btrfs_printk_rl_in_rcu(fs_info, KERN_ALERT fmt, ##args) -#define btrfs_crit_rl_in_rcu(fs_info, fmt, args...) \ - btrfs_printk_rl_in_rcu(fs_info, KERN_CRIT fmt, ##args) -#define btrfs_err_rl_in_rcu(fs_info, fmt, args...) \ - btrfs_printk_rl_in_rcu(fs_info, KERN_ERR fmt, ##args) -#define btrfs_warn_rl_in_rcu(fs_info, fmt, args...) \ - btrfs_printk_rl_in_rcu(fs_info, KERN_WARNING fmt, ##args) -#define btrfs_notice_rl_in_rcu(fs_info, fmt, args...) \ - btrfs_printk_rl_in_rcu(fs_info, KERN_NOTICE fmt, ##args) -#define btrfs_info_rl_in_rcu(fs_info, fmt, args...) \ - btrfs_printk_rl_in_rcu(fs_info, KERN_INFO fmt, ##args) - -/* - * Wrappers that use a ratelimited printk - */ -#define btrfs_emerg_rl(fs_info, fmt, args...) \ - btrfs_printk_ratelimited(fs_info, KERN_EMERG fmt, ##args) -#define btrfs_alert_rl(fs_info, fmt, args...) \ - btrfs_printk_ratelimited(fs_info, KERN_ALERT fmt, ##args) -#define btrfs_crit_rl(fs_info, fmt, args...) \ - btrfs_printk_ratelimited(fs_info, KERN_CRIT fmt, ##args) -#define btrfs_err_rl(fs_info, fmt, args...) \ - btrfs_printk_ratelimited(fs_info, KERN_ERR fmt, ##args) -#define btrfs_warn_rl(fs_info, fmt, args...) \ - btrfs_printk_ratelimited(fs_info, KERN_WARNING fmt, ##args) -#define btrfs_notice_rl(fs_info, fmt, args...) \ - btrfs_printk_ratelimited(fs_info, KERN_NOTICE fmt, ##args) -#define btrfs_info_rl(fs_info, fmt, args...) \ - btrfs_printk_ratelimited(fs_info, KERN_INFO fmt, ##args) - -#if defined(CONFIG_DYNAMIC_DEBUG) -#define btrfs_debug(fs_info, fmt, args...) \ -do { \ - DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ - if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)) \ - btrfs_printk(fs_info, KERN_DEBUG fmt, ##args); \ -} while (0) -#define btrfs_debug_in_rcu(fs_info, fmt, args...) \ -do { \ - DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ - if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)) \ - btrfs_printk_in_rcu(fs_info, KERN_DEBUG fmt, ##args); \ -} while (0) -#define btrfs_debug_rl_in_rcu(fs_info, fmt, args...) \ -do { \ - DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ - if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)) \ - btrfs_printk_rl_in_rcu(fs_info, KERN_DEBUG fmt, \ - ##args);\ -} while (0) -#define btrfs_debug_rl(fs_info, fmt, args...) \ -do { \ - DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ - if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)) \ - btrfs_printk_ratelimited(fs_info, KERN_DEBUG fmt, \ - ##args); \ -} while (0) -#elif defined(DEBUG) -#define btrfs_debug(fs_info, fmt, args...) \ - btrfs_printk(fs_info, KERN_DEBUG fmt, ##args) -#define btrfs_debug_in_rcu(fs_info, fmt, args...) \ - btrfs_printk_in_rcu(fs_info, KERN_DEBUG fmt, ##args) -#define btrfs_debug_rl_in_rcu(fs_info, fmt, args...) \ - btrfs_printk_rl_in_rcu(fs_info, KERN_DEBUG fmt, ##args) -#define btrfs_debug_rl(fs_info, fmt, args...) \ - btrfs_printk_ratelimited(fs_info, KERN_DEBUG fmt, ##args) -#else -#define btrfs_debug(fs_info, fmt, args...) \ - btrfs_no_printk(fs_info, KERN_DEBUG fmt, ##args) -#define btrfs_debug_in_rcu(fs_info, fmt, args...) \ - btrfs_no_printk(fs_info, KERN_DEBUG fmt, ##args) -#define btrfs_debug_rl_in_rcu(fs_info, fmt, args...) \ - btrfs_no_printk(fs_info, KERN_DEBUG fmt, ##args) -#define btrfs_debug_rl(fs_info, fmt, args...) \ - btrfs_no_printk(fs_info, KERN_DEBUG fmt, ##args) -#endif - -#define btrfs_printk_in_rcu(fs_info, fmt, args...) \ -do { \ - rcu_read_lock(); \ - btrfs_printk(fs_info, fmt, ##args); \ - rcu_read_unlock(); \ -} while (0) - -#define btrfs_printk_ratelimited(fs_info, fmt, args...) \ -do { \ - static DEFINE_RATELIMIT_STATE(_rs, \ - DEFAULT_RATELIMIT_INTERVAL, \ - DEFAULT_RATELIMIT_BURST); \ - if (__ratelimit(&_rs)) \ - btrfs_printk(fs_info, fmt, ##args); \ -} while (0) - -#define btrfs_printk_rl_in_rcu(fs_info, fmt, args...) \ -do { \ - rcu_read_lock(); \ - btrfs_printk_ratelimited(fs_info, fmt, ##args); \ - rcu_read_unlock(); \ -} while (0) - -#ifdef CONFIG_BTRFS_ASSERT - -__cold -static inline void assfail(char *expr, char *file, int line) -{ - pr_err("assertion failed: %s, file: %s, line: %d\n", - expr, file, line); - BUG(); -} - -#define ASSERT(expr) \ - (likely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__)) -#else -#define ASSERT(expr) ((void)0) -#endif - -__printf(5, 6) -__cold -void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function, - unsigned int line, int errno, const char *fmt, ...); - -const char *btrfs_decode_error(int errno); - -__cold -void __btrfs_abort_transaction(struct btrfs_trans_handle *trans, - const char *function, - unsigned int line, int errno); - -/* - * Call btrfs_abort_transaction as early as possible when an error condition is - * detected, that way the exact line number is reported. - */ -#define btrfs_abort_transaction(trans, errno) \ -do { \ - /* Report first abort since mount */ \ - if (!test_and_set_bit(BTRFS_FS_STATE_TRANS_ABORTED, \ - &((trans)->fs_info->fs_state))) { \ - WARN(1, KERN_DEBUG \ - "BTRFS: Transaction aborted (error %d)\n", \ - (errno)); \ - } \ - __btrfs_abort_transaction((trans), __func__, \ - __LINE__, (errno)); \ -} while (0) - -#define btrfs_handle_fs_error(fs_info, errno, fmt, args...) \ -do { \ - __btrfs_handle_fs_error((fs_info), __func__, __LINE__, \ - (errno), fmt, ##args); \ -} while (0) - -__printf(5, 6) -__cold -void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function, - unsigned int line, int errno, const char *fmt, ...); -/* - * If BTRFS_MOUNT_PANIC_ON_FATAL_ERROR is in mount_opt, __btrfs_panic - * will panic(). Otherwise we BUG() here. - */ -#define btrfs_panic(fs_info, errno, fmt, args...) \ -do { \ - __btrfs_panic(fs_info, __func__, __LINE__, errno, fmt, ##args); \ - BUG(); \ -} while (0) - - -/* compatibility and incompatibility defines */ - -#define btrfs_set_fs_incompat(__fs_info, opt) \ - __btrfs_set_fs_incompat((__fs_info), BTRFS_FEATURE_INCOMPAT_##opt) - -static inline void __btrfs_set_fs_incompat(struct btrfs_fs_info *fs_info, - u64 flag) -{ - struct btrfs_super_block *disk_super; - u64 features; - - disk_super = fs_info->super_copy; - features = btrfs_super_incompat_flags(disk_super); - if (!(features & flag)) { - spin_lock(&fs_info->super_lock); - features = btrfs_super_incompat_flags(disk_super); - if (!(features & flag)) { - features |= flag; - btrfs_set_super_incompat_flags(disk_super, features); - btrfs_info(fs_info, "setting %llu feature flag", - flag); - } - spin_unlock(&fs_info->super_lock); - } -} - -#define btrfs_clear_fs_incompat(__fs_info, opt) \ - __btrfs_clear_fs_incompat((__fs_info), BTRFS_FEATURE_INCOMPAT_##opt) - -static inline void __btrfs_clear_fs_incompat(struct btrfs_fs_info *fs_info, - u64 flag) -{ - struct btrfs_super_block *disk_super; - u64 features; - - disk_super = fs_info->super_copy; - features = btrfs_super_incompat_flags(disk_super); - if (features & flag) { - spin_lock(&fs_info->super_lock); - features = btrfs_super_incompat_flags(disk_super); - if (features & flag) { - features &= ~flag; - btrfs_set_super_incompat_flags(disk_super, features); - btrfs_info(fs_info, "clearing %llu feature flag", - flag); - } - spin_unlock(&fs_info->super_lock); - } -} - -#define btrfs_fs_incompat(fs_info, opt) \ - __btrfs_fs_incompat((fs_info), BTRFS_FEATURE_INCOMPAT_##opt) - -static inline bool __btrfs_fs_incompat(struct btrfs_fs_info *fs_info, u64 flag) -{ - struct btrfs_super_block *disk_super; - disk_super = fs_info->super_copy; - return !!(btrfs_super_incompat_flags(disk_super) & flag); -} - -#define btrfs_set_fs_compat_ro(__fs_info, opt) \ - __btrfs_set_fs_compat_ro((__fs_info), BTRFS_FEATURE_COMPAT_RO_##opt) - -static inline void __btrfs_set_fs_compat_ro(struct btrfs_fs_info *fs_info, - u64 flag) -{ - struct btrfs_super_block *disk_super; - u64 features; - - disk_super = fs_info->super_copy; - features = btrfs_super_compat_ro_flags(disk_super); - if (!(features & flag)) { - spin_lock(&fs_info->super_lock); - features = btrfs_super_compat_ro_flags(disk_super); - if (!(features & flag)) { - features |= flag; - btrfs_set_super_compat_ro_flags(disk_super, features); - btrfs_info(fs_info, "setting %llu ro feature flag", - flag); - } - spin_unlock(&fs_info->super_lock); - } -} - -#define btrfs_clear_fs_compat_ro(__fs_info, opt) \ - __btrfs_clear_fs_compat_ro((__fs_info), BTRFS_FEATURE_COMPAT_RO_##opt) - -static inline void __btrfs_clear_fs_compat_ro(struct btrfs_fs_info *fs_info, - u64 flag) -{ - struct btrfs_super_block *disk_super; - u64 features; - - disk_super = fs_info->super_copy; - features = btrfs_super_compat_ro_flags(disk_super); - if (features & flag) { - spin_lock(&fs_info->super_lock); - features = btrfs_super_compat_ro_flags(disk_super); - if (features & flag) { - features &= ~flag; - btrfs_set_super_compat_ro_flags(disk_super, features); - btrfs_info(fs_info, "clearing %llu ro feature flag", - flag); - } - spin_unlock(&fs_info->super_lock); - } -} - -#define btrfs_fs_compat_ro(fs_info, opt) \ - __btrfs_fs_compat_ro((fs_info), BTRFS_FEATURE_COMPAT_RO_##opt) - -static inline int __btrfs_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag) -{ - struct btrfs_super_block *disk_super; - disk_super = fs_info->super_copy; - return !!(btrfs_super_compat_ro_flags(disk_super) & flag); -} - -/* acl.c */ -#ifdef CONFIG_BTRFS_FS_POSIX_ACL -struct posix_acl *btrfs_get_acl(struct inode *inode, int type); -int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type); -int btrfs_init_acl(struct btrfs_trans_handle *trans, - struct inode *inode, struct inode *dir); -#else -#define btrfs_get_acl NULL -#define btrfs_set_acl NULL -static inline int btrfs_init_acl(struct btrfs_trans_handle *trans, - struct inode *inode, struct inode *dir) -{ - return 0; -} -#endif - -/* relocation.c */ -int btrfs_relocate_block_group(struct btrfs_root *root, u64 group_start); -int btrfs_init_reloc_root(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -int btrfs_update_reloc_root(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -int btrfs_recover_relocation(struct btrfs_root *root); -int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len); -int btrfs_reloc_cow_block(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct extent_buffer *buf, - struct extent_buffer *cow); -void btrfs_reloc_pre_snapshot(struct btrfs_pending_snapshot *pending, - u64 *bytes_to_reserve); -int btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans, - struct btrfs_pending_snapshot *pending); - -/* scrub.c */ -int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, - u64 end, struct btrfs_scrub_progress *progress, - int readonly, int is_dev_replace); -void btrfs_scrub_pause(struct btrfs_root *root); -void btrfs_scrub_continue(struct btrfs_root *root); -int btrfs_scrub_cancel(struct btrfs_fs_info *info); -int btrfs_scrub_cancel_dev(struct btrfs_fs_info *info, - struct btrfs_device *dev); -int btrfs_scrub_progress(struct btrfs_root *root, u64 devid, - struct btrfs_scrub_progress *progress); - -/* dev-replace.c */ -void btrfs_bio_counter_inc_blocked(struct btrfs_fs_info *fs_info); -void btrfs_bio_counter_inc_noblocked(struct btrfs_fs_info *fs_info); -void btrfs_bio_counter_sub(struct btrfs_fs_info *fs_info, s64 amount); - -static inline void btrfs_bio_counter_dec(struct btrfs_fs_info *fs_info) -{ - btrfs_bio_counter_sub(fs_info, 1); -} - -/* reada.c */ -struct reada_control { - struct btrfs_root *root; /* tree to prefetch */ - struct btrfs_key key_start; - struct btrfs_key key_end; /* exclusive */ - atomic_t elems; - struct kref refcnt; - wait_queue_head_t wait; -}; -struct reada_control *btrfs_reada_add(struct btrfs_root *root, - struct btrfs_key *start, struct btrfs_key *end); -int btrfs_reada_wait(void *handle); -void btrfs_reada_detach(void *handle); -int btree_readahead_hook(struct btrfs_fs_info *fs_info, - struct extent_buffer *eb, u64 start, int err); - -static inline int is_fstree(u64 rootid) -{ - if (rootid == BTRFS_FS_TREE_OBJECTID || - ((s64)rootid >= (s64)BTRFS_FIRST_FREE_OBJECTID && - !btrfs_qgroup_level(rootid))) - return 1; - return 0; -} - -static inline int btrfs_defrag_cancelled(struct btrfs_fs_info *fs_info) -{ - return signal_pending(current); -} - -/* Sanity test specific functions */ -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS -void btrfs_test_destroy_inode(struct inode *inode); -#endif - -static inline int btrfs_is_testing(struct btrfs_fs_info *fs_info) -{ -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS - if (unlikely(test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, - &fs_info->fs_state))) - return 1; -#endif - return 0; -} -#endif diff --git a/src/linux/fs/btrfs/dedupe.h b/src/linux/fs/btrfs/dedupe.h deleted file mode 100644 index 83ebfe2..0000000 --- a/src/linux/fs/btrfs/dedupe.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2016 Fujitsu. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __BTRFS_DEDUPE__ -#define __BTRFS_DEDUPE__ - -/* later in-band dedupe will expand this struct */ -struct btrfs_dedupe_hash; -#endif diff --git a/src/linux/fs/btrfs/delayed-inode.c b/src/linux/fs/btrfs/delayed-inode.c deleted file mode 100644 index 0fcf5f2..0000000 --- a/src/linux/fs/btrfs/delayed-inode.c +++ /dev/null @@ -1,1995 +0,0 @@ -/* - * Copyright (C) 2011 Fujitsu. All rights reserved. - * Written by Miao Xie - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include "delayed-inode.h" -#include "disk-io.h" -#include "transaction.h" -#include "ctree.h" - -#define BTRFS_DELAYED_WRITEBACK 512 -#define BTRFS_DELAYED_BACKGROUND 128 -#define BTRFS_DELAYED_BATCH 16 - -static struct kmem_cache *delayed_node_cache; - -int __init btrfs_delayed_inode_init(void) -{ - delayed_node_cache = kmem_cache_create("btrfs_delayed_node", - sizeof(struct btrfs_delayed_node), - 0, - SLAB_MEM_SPREAD, - NULL); - if (!delayed_node_cache) - return -ENOMEM; - return 0; -} - -void btrfs_delayed_inode_exit(void) -{ - kmem_cache_destroy(delayed_node_cache); -} - -static inline void btrfs_init_delayed_node( - struct btrfs_delayed_node *delayed_node, - struct btrfs_root *root, u64 inode_id) -{ - delayed_node->root = root; - delayed_node->inode_id = inode_id; - atomic_set(&delayed_node->refs, 0); - delayed_node->ins_root = RB_ROOT; - delayed_node->del_root = RB_ROOT; - mutex_init(&delayed_node->mutex); - INIT_LIST_HEAD(&delayed_node->n_list); - INIT_LIST_HEAD(&delayed_node->p_list); -} - -static inline int btrfs_is_continuous_delayed_item( - struct btrfs_delayed_item *item1, - struct btrfs_delayed_item *item2) -{ - if (item1->key.type == BTRFS_DIR_INDEX_KEY && - item1->key.objectid == item2->key.objectid && - item1->key.type == item2->key.type && - item1->key.offset + 1 == item2->key.offset) - return 1; - return 0; -} - -static inline struct btrfs_delayed_root *btrfs_get_delayed_root( - struct btrfs_root *root) -{ - return root->fs_info->delayed_root; -} - -static struct btrfs_delayed_node *btrfs_get_delayed_node(struct inode *inode) -{ - struct btrfs_inode *btrfs_inode = BTRFS_I(inode); - struct btrfs_root *root = btrfs_inode->root; - u64 ino = btrfs_ino(inode); - struct btrfs_delayed_node *node; - - node = ACCESS_ONCE(btrfs_inode->delayed_node); - if (node) { - atomic_inc(&node->refs); - return node; - } - - spin_lock(&root->inode_lock); - node = radix_tree_lookup(&root->delayed_nodes_tree, ino); - if (node) { - if (btrfs_inode->delayed_node) { - atomic_inc(&node->refs); /* can be accessed */ - BUG_ON(btrfs_inode->delayed_node != node); - spin_unlock(&root->inode_lock); - return node; - } - btrfs_inode->delayed_node = node; - /* can be accessed and cached in the inode */ - atomic_add(2, &node->refs); - spin_unlock(&root->inode_lock); - return node; - } - spin_unlock(&root->inode_lock); - - return NULL; -} - -/* Will return either the node or PTR_ERR(-ENOMEM) */ -static struct btrfs_delayed_node *btrfs_get_or_create_delayed_node( - struct inode *inode) -{ - struct btrfs_delayed_node *node; - struct btrfs_inode *btrfs_inode = BTRFS_I(inode); - struct btrfs_root *root = btrfs_inode->root; - u64 ino = btrfs_ino(inode); - int ret; - -again: - node = btrfs_get_delayed_node(inode); - if (node) - return node; - - node = kmem_cache_zalloc(delayed_node_cache, GFP_NOFS); - if (!node) - return ERR_PTR(-ENOMEM); - btrfs_init_delayed_node(node, root, ino); - - /* cached in the btrfs inode and can be accessed */ - atomic_add(2, &node->refs); - - ret = radix_tree_preload(GFP_NOFS); - if (ret) { - kmem_cache_free(delayed_node_cache, node); - return ERR_PTR(ret); - } - - spin_lock(&root->inode_lock); - ret = radix_tree_insert(&root->delayed_nodes_tree, ino, node); - if (ret == -EEXIST) { - spin_unlock(&root->inode_lock); - kmem_cache_free(delayed_node_cache, node); - radix_tree_preload_end(); - goto again; - } - btrfs_inode->delayed_node = node; - spin_unlock(&root->inode_lock); - radix_tree_preload_end(); - - return node; -} - -/* - * Call it when holding delayed_node->mutex - * - * If mod = 1, add this node into the prepared list. - */ -static void btrfs_queue_delayed_node(struct btrfs_delayed_root *root, - struct btrfs_delayed_node *node, - int mod) -{ - spin_lock(&root->lock); - if (test_bit(BTRFS_DELAYED_NODE_IN_LIST, &node->flags)) { - if (!list_empty(&node->p_list)) - list_move_tail(&node->p_list, &root->prepare_list); - else if (mod) - list_add_tail(&node->p_list, &root->prepare_list); - } else { - list_add_tail(&node->n_list, &root->node_list); - list_add_tail(&node->p_list, &root->prepare_list); - atomic_inc(&node->refs); /* inserted into list */ - root->nodes++; - set_bit(BTRFS_DELAYED_NODE_IN_LIST, &node->flags); - } - spin_unlock(&root->lock); -} - -/* Call it when holding delayed_node->mutex */ -static void btrfs_dequeue_delayed_node(struct btrfs_delayed_root *root, - struct btrfs_delayed_node *node) -{ - spin_lock(&root->lock); - if (test_bit(BTRFS_DELAYED_NODE_IN_LIST, &node->flags)) { - root->nodes--; - atomic_dec(&node->refs); /* not in the list */ - list_del_init(&node->n_list); - if (!list_empty(&node->p_list)) - list_del_init(&node->p_list); - clear_bit(BTRFS_DELAYED_NODE_IN_LIST, &node->flags); - } - spin_unlock(&root->lock); -} - -static struct btrfs_delayed_node *btrfs_first_delayed_node( - struct btrfs_delayed_root *delayed_root) -{ - struct list_head *p; - struct btrfs_delayed_node *node = NULL; - - spin_lock(&delayed_root->lock); - if (list_empty(&delayed_root->node_list)) - goto out; - - p = delayed_root->node_list.next; - node = list_entry(p, struct btrfs_delayed_node, n_list); - atomic_inc(&node->refs); -out: - spin_unlock(&delayed_root->lock); - - return node; -} - -static struct btrfs_delayed_node *btrfs_next_delayed_node( - struct btrfs_delayed_node *node) -{ - struct btrfs_delayed_root *delayed_root; - struct list_head *p; - struct btrfs_delayed_node *next = NULL; - - delayed_root = node->root->fs_info->delayed_root; - spin_lock(&delayed_root->lock); - if (!test_bit(BTRFS_DELAYED_NODE_IN_LIST, &node->flags)) { - /* not in the list */ - if (list_empty(&delayed_root->node_list)) - goto out; - p = delayed_root->node_list.next; - } else if (list_is_last(&node->n_list, &delayed_root->node_list)) - goto out; - else - p = node->n_list.next; - - next = list_entry(p, struct btrfs_delayed_node, n_list); - atomic_inc(&next->refs); -out: - spin_unlock(&delayed_root->lock); - - return next; -} - -static void __btrfs_release_delayed_node( - struct btrfs_delayed_node *delayed_node, - int mod) -{ - struct btrfs_delayed_root *delayed_root; - - if (!delayed_node) - return; - - delayed_root = delayed_node->root->fs_info->delayed_root; - - mutex_lock(&delayed_node->mutex); - if (delayed_node->count) - btrfs_queue_delayed_node(delayed_root, delayed_node, mod); - else - btrfs_dequeue_delayed_node(delayed_root, delayed_node); - mutex_unlock(&delayed_node->mutex); - - if (atomic_dec_and_test(&delayed_node->refs)) { - bool free = false; - struct btrfs_root *root = delayed_node->root; - spin_lock(&root->inode_lock); - if (atomic_read(&delayed_node->refs) == 0) { - radix_tree_delete(&root->delayed_nodes_tree, - delayed_node->inode_id); - free = true; - } - spin_unlock(&root->inode_lock); - if (free) - kmem_cache_free(delayed_node_cache, delayed_node); - } -} - -static inline void btrfs_release_delayed_node(struct btrfs_delayed_node *node) -{ - __btrfs_release_delayed_node(node, 0); -} - -static struct btrfs_delayed_node *btrfs_first_prepared_delayed_node( - struct btrfs_delayed_root *delayed_root) -{ - struct list_head *p; - struct btrfs_delayed_node *node = NULL; - - spin_lock(&delayed_root->lock); - if (list_empty(&delayed_root->prepare_list)) - goto out; - - p = delayed_root->prepare_list.next; - list_del_init(p); - node = list_entry(p, struct btrfs_delayed_node, p_list); - atomic_inc(&node->refs); -out: - spin_unlock(&delayed_root->lock); - - return node; -} - -static inline void btrfs_release_prepared_delayed_node( - struct btrfs_delayed_node *node) -{ - __btrfs_release_delayed_node(node, 1); -} - -static struct btrfs_delayed_item *btrfs_alloc_delayed_item(u32 data_len) -{ - struct btrfs_delayed_item *item; - item = kmalloc(sizeof(*item) + data_len, GFP_NOFS); - if (item) { - item->data_len = data_len; - item->ins_or_del = 0; - item->bytes_reserved = 0; - item->delayed_node = NULL; - atomic_set(&item->refs, 1); - } - return item; -} - -/* - * __btrfs_lookup_delayed_item - look up the delayed item by key - * @delayed_node: pointer to the delayed node - * @key: the key to look up - * @prev: used to store the prev item if the right item isn't found - * @next: used to store the next item if the right item isn't found - * - * Note: if we don't find the right item, we will return the prev item and - * the next item. - */ -static struct btrfs_delayed_item *__btrfs_lookup_delayed_item( - struct rb_root *root, - struct btrfs_key *key, - struct btrfs_delayed_item **prev, - struct btrfs_delayed_item **next) -{ - struct rb_node *node, *prev_node = NULL; - struct btrfs_delayed_item *delayed_item = NULL; - int ret = 0; - - node = root->rb_node; - - while (node) { - delayed_item = rb_entry(node, struct btrfs_delayed_item, - rb_node); - prev_node = node; - ret = btrfs_comp_cpu_keys(&delayed_item->key, key); - if (ret < 0) - node = node->rb_right; - else if (ret > 0) - node = node->rb_left; - else - return delayed_item; - } - - if (prev) { - if (!prev_node) - *prev = NULL; - else if (ret < 0) - *prev = delayed_item; - else if ((node = rb_prev(prev_node)) != NULL) { - *prev = rb_entry(node, struct btrfs_delayed_item, - rb_node); - } else - *prev = NULL; - } - - if (next) { - if (!prev_node) - *next = NULL; - else if (ret > 0) - *next = delayed_item; - else if ((node = rb_next(prev_node)) != NULL) { - *next = rb_entry(node, struct btrfs_delayed_item, - rb_node); - } else - *next = NULL; - } - return NULL; -} - -static struct btrfs_delayed_item *__btrfs_lookup_delayed_insertion_item( - struct btrfs_delayed_node *delayed_node, - struct btrfs_key *key) -{ - return __btrfs_lookup_delayed_item(&delayed_node->ins_root, key, - NULL, NULL); -} - -static int __btrfs_add_delayed_item(struct btrfs_delayed_node *delayed_node, - struct btrfs_delayed_item *ins, - int action) -{ - struct rb_node **p, *node; - struct rb_node *parent_node = NULL; - struct rb_root *root; - struct btrfs_delayed_item *item; - int cmp; - - if (action == BTRFS_DELAYED_INSERTION_ITEM) - root = &delayed_node->ins_root; - else if (action == BTRFS_DELAYED_DELETION_ITEM) - root = &delayed_node->del_root; - else - BUG(); - p = &root->rb_node; - node = &ins->rb_node; - - while (*p) { - parent_node = *p; - item = rb_entry(parent_node, struct btrfs_delayed_item, - rb_node); - - cmp = btrfs_comp_cpu_keys(&item->key, &ins->key); - if (cmp < 0) - p = &(*p)->rb_right; - else if (cmp > 0) - p = &(*p)->rb_left; - else - return -EEXIST; - } - - rb_link_node(node, parent_node, p); - rb_insert_color(node, root); - ins->delayed_node = delayed_node; - ins->ins_or_del = action; - - if (ins->key.type == BTRFS_DIR_INDEX_KEY && - action == BTRFS_DELAYED_INSERTION_ITEM && - ins->key.offset >= delayed_node->index_cnt) - delayed_node->index_cnt = ins->key.offset + 1; - - delayed_node->count++; - atomic_inc(&delayed_node->root->fs_info->delayed_root->items); - return 0; -} - -static int __btrfs_add_delayed_insertion_item(struct btrfs_delayed_node *node, - struct btrfs_delayed_item *item) -{ - return __btrfs_add_delayed_item(node, item, - BTRFS_DELAYED_INSERTION_ITEM); -} - -static int __btrfs_add_delayed_deletion_item(struct btrfs_delayed_node *node, - struct btrfs_delayed_item *item) -{ - return __btrfs_add_delayed_item(node, item, - BTRFS_DELAYED_DELETION_ITEM); -} - -static void finish_one_item(struct btrfs_delayed_root *delayed_root) -{ - int seq = atomic_inc_return(&delayed_root->items_seq); - - /* - * atomic_dec_return implies a barrier for waitqueue_active - */ - if ((atomic_dec_return(&delayed_root->items) < - BTRFS_DELAYED_BACKGROUND || seq % BTRFS_DELAYED_BATCH == 0) && - waitqueue_active(&delayed_root->wait)) - wake_up(&delayed_root->wait); -} - -static void __btrfs_remove_delayed_item(struct btrfs_delayed_item *delayed_item) -{ - struct rb_root *root; - struct btrfs_delayed_root *delayed_root; - - delayed_root = delayed_item->delayed_node->root->fs_info->delayed_root; - - BUG_ON(!delayed_root); - BUG_ON(delayed_item->ins_or_del != BTRFS_DELAYED_DELETION_ITEM && - delayed_item->ins_or_del != BTRFS_DELAYED_INSERTION_ITEM); - - if (delayed_item->ins_or_del == BTRFS_DELAYED_INSERTION_ITEM) - root = &delayed_item->delayed_node->ins_root; - else - root = &delayed_item->delayed_node->del_root; - - rb_erase(&delayed_item->rb_node, root); - delayed_item->delayed_node->count--; - - finish_one_item(delayed_root); -} - -static void btrfs_release_delayed_item(struct btrfs_delayed_item *item) -{ - if (item) { - __btrfs_remove_delayed_item(item); - if (atomic_dec_and_test(&item->refs)) - kfree(item); - } -} - -static struct btrfs_delayed_item *__btrfs_first_delayed_insertion_item( - struct btrfs_delayed_node *delayed_node) -{ - struct rb_node *p; - struct btrfs_delayed_item *item = NULL; - - p = rb_first(&delayed_node->ins_root); - if (p) - item = rb_entry(p, struct btrfs_delayed_item, rb_node); - - return item; -} - -static struct btrfs_delayed_item *__btrfs_first_delayed_deletion_item( - struct btrfs_delayed_node *delayed_node) -{ - struct rb_node *p; - struct btrfs_delayed_item *item = NULL; - - p = rb_first(&delayed_node->del_root); - if (p) - item = rb_entry(p, struct btrfs_delayed_item, rb_node); - - return item; -} - -static struct btrfs_delayed_item *__btrfs_next_delayed_item( - struct btrfs_delayed_item *item) -{ - struct rb_node *p; - struct btrfs_delayed_item *next = NULL; - - p = rb_next(&item->rb_node); - if (p) - next = rb_entry(p, struct btrfs_delayed_item, rb_node); - - return next; -} - -static int btrfs_delayed_item_reserve_metadata(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_delayed_item *item) -{ - struct btrfs_block_rsv *src_rsv; - struct btrfs_block_rsv *dst_rsv; - u64 num_bytes; - int ret; - - if (!trans->bytes_reserved) - return 0; - - src_rsv = trans->block_rsv; - dst_rsv = &root->fs_info->delayed_block_rsv; - - num_bytes = btrfs_calc_trans_metadata_size(root, 1); - ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes, 1); - if (!ret) { - trace_btrfs_space_reservation(root->fs_info, "delayed_item", - item->key.objectid, - num_bytes, 1); - item->bytes_reserved = num_bytes; - } - - return ret; -} - -static void btrfs_delayed_item_release_metadata(struct btrfs_root *root, - struct btrfs_delayed_item *item) -{ - struct btrfs_block_rsv *rsv; - - if (!item->bytes_reserved) - return; - - rsv = &root->fs_info->delayed_block_rsv; - trace_btrfs_space_reservation(root->fs_info, "delayed_item", - item->key.objectid, item->bytes_reserved, - 0); - btrfs_block_rsv_release(root, rsv, - item->bytes_reserved); -} - -static int btrfs_delayed_inode_reserve_metadata( - struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *inode, - struct btrfs_delayed_node *node) -{ - struct btrfs_block_rsv *src_rsv; - struct btrfs_block_rsv *dst_rsv; - u64 num_bytes; - int ret; - bool release = false; - - src_rsv = trans->block_rsv; - dst_rsv = &root->fs_info->delayed_block_rsv; - - num_bytes = btrfs_calc_trans_metadata_size(root, 1); - - /* - * If our block_rsv is the delalloc block reserve then check and see if - * we have our extra reservation for updating the inode. If not fall - * through and try to reserve space quickly. - * - * We used to try and steal from the delalloc block rsv or the global - * reserve, but we'd steal a full reservation, which isn't kind. We are - * here through delalloc which means we've likely just cowed down close - * to the leaf that contains the inode, so we would steal less just - * doing the fallback inode update, so if we do end up having to steal - * from the global block rsv we hopefully only steal one or two blocks - * worth which is less likely to hurt us. - */ - if (src_rsv && src_rsv->type == BTRFS_BLOCK_RSV_DELALLOC) { - spin_lock(&BTRFS_I(inode)->lock); - if (test_and_clear_bit(BTRFS_INODE_DELALLOC_META_RESERVED, - &BTRFS_I(inode)->runtime_flags)) - release = true; - else - src_rsv = NULL; - spin_unlock(&BTRFS_I(inode)->lock); - } - - /* - * btrfs_dirty_inode will update the inode under btrfs_join_transaction - * which doesn't reserve space for speed. This is a problem since we - * still need to reserve space for this update, so try to reserve the - * space. - * - * Now if src_rsv == delalloc_block_rsv we'll let it just steal since - * we're accounted for. - */ - if (!src_rsv || (!trans->bytes_reserved && - src_rsv->type != BTRFS_BLOCK_RSV_DELALLOC)) { - ret = btrfs_block_rsv_add(root, dst_rsv, num_bytes, - BTRFS_RESERVE_NO_FLUSH); - /* - * Since we're under a transaction reserve_metadata_bytes could - * try to commit the transaction which will make it return - * EAGAIN to make us stop the transaction we have, so return - * ENOSPC instead so that btrfs_dirty_inode knows what to do. - */ - if (ret == -EAGAIN) - ret = -ENOSPC; - if (!ret) { - node->bytes_reserved = num_bytes; - trace_btrfs_space_reservation(root->fs_info, - "delayed_inode", - btrfs_ino(inode), - num_bytes, 1); - } - return ret; - } - - ret = btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes, 1); - - /* - * Migrate only takes a reservation, it doesn't touch the size of the - * block_rsv. This is to simplify people who don't normally have things - * migrated from their block rsv. If they go to release their - * reservation, that will decrease the size as well, so if migrate - * reduced size we'd end up with a negative size. But for the - * delalloc_meta_reserved stuff we will only know to drop 1 reservation, - * but we could in fact do this reserve/migrate dance several times - * between the time we did the original reservation and we'd clean it - * up. So to take care of this, release the space for the meta - * reservation here. I think it may be time for a documentation page on - * how block rsvs. work. - */ - if (!ret) { - trace_btrfs_space_reservation(root->fs_info, "delayed_inode", - btrfs_ino(inode), num_bytes, 1); - node->bytes_reserved = num_bytes; - } - - if (release) { - trace_btrfs_space_reservation(root->fs_info, "delalloc", - btrfs_ino(inode), num_bytes, 0); - btrfs_block_rsv_release(root, src_rsv, num_bytes); - } - - return ret; -} - -static void btrfs_delayed_inode_release_metadata(struct btrfs_root *root, - struct btrfs_delayed_node *node) -{ - struct btrfs_block_rsv *rsv; - - if (!node->bytes_reserved) - return; - - rsv = &root->fs_info->delayed_block_rsv; - trace_btrfs_space_reservation(root->fs_info, "delayed_inode", - node->inode_id, node->bytes_reserved, 0); - btrfs_block_rsv_release(root, rsv, - node->bytes_reserved); - node->bytes_reserved = 0; -} - -/* - * This helper will insert some continuous items into the same leaf according - * to the free space of the leaf. - */ -static int btrfs_batch_insert_items(struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_delayed_item *item) -{ - struct btrfs_delayed_item *curr, *next; - int free_space; - int total_data_size = 0, total_size = 0; - struct extent_buffer *leaf; - char *data_ptr; - struct btrfs_key *keys; - u32 *data_size; - struct list_head head; - int slot; - int nitems; - int i; - int ret = 0; - - BUG_ON(!path->nodes[0]); - - leaf = path->nodes[0]; - free_space = btrfs_leaf_free_space(root, leaf); - INIT_LIST_HEAD(&head); - - next = item; - nitems = 0; - - /* - * count the number of the continuous items that we can insert in batch - */ - while (total_size + next->data_len + sizeof(struct btrfs_item) <= - free_space) { - total_data_size += next->data_len; - total_size += next->data_len + sizeof(struct btrfs_item); - list_add_tail(&next->tree_list, &head); - nitems++; - - curr = next; - next = __btrfs_next_delayed_item(curr); - if (!next) - break; - - if (!btrfs_is_continuous_delayed_item(curr, next)) - break; - } - - if (!nitems) { - ret = 0; - goto out; - } - - /* - * we need allocate some memory space, but it might cause the task - * to sleep, so we set all locked nodes in the path to blocking locks - * first. - */ - btrfs_set_path_blocking(path); - - keys = kmalloc_array(nitems, sizeof(struct btrfs_key), GFP_NOFS); - if (!keys) { - ret = -ENOMEM; - goto out; - } - - data_size = kmalloc_array(nitems, sizeof(u32), GFP_NOFS); - if (!data_size) { - ret = -ENOMEM; - goto error; - } - - /* get keys of all the delayed items */ - i = 0; - list_for_each_entry(next, &head, tree_list) { - keys[i] = next->key; - data_size[i] = next->data_len; - i++; - } - - /* reset all the locked nodes in the patch to spinning locks. */ - btrfs_clear_path_blocking(path, NULL, 0); - - /* insert the keys of the items */ - setup_items_for_insert(root, path, keys, data_size, - total_data_size, total_size, nitems); - - /* insert the dir index items */ - slot = path->slots[0]; - list_for_each_entry_safe(curr, next, &head, tree_list) { - data_ptr = btrfs_item_ptr(leaf, slot, char); - write_extent_buffer(leaf, &curr->data, - (unsigned long)data_ptr, - curr->data_len); - slot++; - - btrfs_delayed_item_release_metadata(root, curr); - - list_del(&curr->tree_list); - btrfs_release_delayed_item(curr); - } - -error: - kfree(data_size); - kfree(keys); -out: - return ret; -} - -/* - * This helper can just do simple insertion that needn't extend item for new - * data, such as directory name index insertion, inode insertion. - */ -static int btrfs_insert_delayed_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_delayed_item *delayed_item) -{ - struct extent_buffer *leaf; - char *ptr; - int ret; - - ret = btrfs_insert_empty_item(trans, root, path, &delayed_item->key, - delayed_item->data_len); - if (ret < 0 && ret != -EEXIST) - return ret; - - leaf = path->nodes[0]; - - ptr = btrfs_item_ptr(leaf, path->slots[0], char); - - write_extent_buffer(leaf, delayed_item->data, (unsigned long)ptr, - delayed_item->data_len); - btrfs_mark_buffer_dirty(leaf); - - btrfs_delayed_item_release_metadata(root, delayed_item); - return 0; -} - -/* - * we insert an item first, then if there are some continuous items, we try - * to insert those items into the same leaf. - */ -static int btrfs_insert_delayed_items(struct btrfs_trans_handle *trans, - struct btrfs_path *path, - struct btrfs_root *root, - struct btrfs_delayed_node *node) -{ - struct btrfs_delayed_item *curr, *prev; - int ret = 0; - -do_again: - mutex_lock(&node->mutex); - curr = __btrfs_first_delayed_insertion_item(node); - if (!curr) - goto insert_end; - - ret = btrfs_insert_delayed_item(trans, root, path, curr); - if (ret < 0) { - btrfs_release_path(path); - goto insert_end; - } - - prev = curr; - curr = __btrfs_next_delayed_item(prev); - if (curr && btrfs_is_continuous_delayed_item(prev, curr)) { - /* insert the continuous items into the same leaf */ - path->slots[0]++; - btrfs_batch_insert_items(root, path, curr); - } - btrfs_release_delayed_item(prev); - btrfs_mark_buffer_dirty(path->nodes[0]); - - btrfs_release_path(path); - mutex_unlock(&node->mutex); - goto do_again; - -insert_end: - mutex_unlock(&node->mutex); - return ret; -} - -static int btrfs_batch_delete_items(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_delayed_item *item) -{ - struct btrfs_delayed_item *curr, *next; - struct extent_buffer *leaf; - struct btrfs_key key; - struct list_head head; - int nitems, i, last_item; - int ret = 0; - - BUG_ON(!path->nodes[0]); - - leaf = path->nodes[0]; - - i = path->slots[0]; - last_item = btrfs_header_nritems(leaf) - 1; - if (i > last_item) - return -ENOENT; /* FIXME: Is errno suitable? */ - - next = item; - INIT_LIST_HEAD(&head); - btrfs_item_key_to_cpu(leaf, &key, i); - nitems = 0; - /* - * count the number of the dir index items that we can delete in batch - */ - while (btrfs_comp_cpu_keys(&next->key, &key) == 0) { - list_add_tail(&next->tree_list, &head); - nitems++; - - curr = next; - next = __btrfs_next_delayed_item(curr); - if (!next) - break; - - if (!btrfs_is_continuous_delayed_item(curr, next)) - break; - - i++; - if (i > last_item) - break; - btrfs_item_key_to_cpu(leaf, &key, i); - } - - if (!nitems) - return 0; - - ret = btrfs_del_items(trans, root, path, path->slots[0], nitems); - if (ret) - goto out; - - list_for_each_entry_safe(curr, next, &head, tree_list) { - btrfs_delayed_item_release_metadata(root, curr); - list_del(&curr->tree_list); - btrfs_release_delayed_item(curr); - } - -out: - return ret; -} - -static int btrfs_delete_delayed_items(struct btrfs_trans_handle *trans, - struct btrfs_path *path, - struct btrfs_root *root, - struct btrfs_delayed_node *node) -{ - struct btrfs_delayed_item *curr, *prev; - int ret = 0; - -do_again: - mutex_lock(&node->mutex); - curr = __btrfs_first_delayed_deletion_item(node); - if (!curr) - goto delete_fail; - - ret = btrfs_search_slot(trans, root, &curr->key, path, -1, 1); - if (ret < 0) - goto delete_fail; - else if (ret > 0) { - /* - * can't find the item which the node points to, so this node - * is invalid, just drop it. - */ - prev = curr; - curr = __btrfs_next_delayed_item(prev); - btrfs_release_delayed_item(prev); - ret = 0; - btrfs_release_path(path); - if (curr) { - mutex_unlock(&node->mutex); - goto do_again; - } else - goto delete_fail; - } - - btrfs_batch_delete_items(trans, root, path, curr); - btrfs_release_path(path); - mutex_unlock(&node->mutex); - goto do_again; - -delete_fail: - btrfs_release_path(path); - mutex_unlock(&node->mutex); - return ret; -} - -static void btrfs_release_delayed_inode(struct btrfs_delayed_node *delayed_node) -{ - struct btrfs_delayed_root *delayed_root; - - if (delayed_node && - test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) { - BUG_ON(!delayed_node->root); - clear_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags); - delayed_node->count--; - - delayed_root = delayed_node->root->fs_info->delayed_root; - finish_one_item(delayed_root); - } -} - -static void btrfs_release_delayed_iref(struct btrfs_delayed_node *delayed_node) -{ - struct btrfs_delayed_root *delayed_root; - - ASSERT(delayed_node->root); - clear_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags); - delayed_node->count--; - - delayed_root = delayed_node->root->fs_info->delayed_root; - finish_one_item(delayed_root); -} - -static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_delayed_node *node) -{ - struct btrfs_key key; - struct btrfs_inode_item *inode_item; - struct extent_buffer *leaf; - int mod; - int ret; - - key.objectid = node->inode_id; - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - - if (test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &node->flags)) - mod = -1; - else - mod = 1; - - ret = btrfs_lookup_inode(trans, root, path, &key, mod); - if (ret > 0) { - btrfs_release_path(path); - return -ENOENT; - } else if (ret < 0) { - return ret; - } - - leaf = path->nodes[0]; - inode_item = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_inode_item); - write_extent_buffer(leaf, &node->inode_item, (unsigned long)inode_item, - sizeof(struct btrfs_inode_item)); - btrfs_mark_buffer_dirty(leaf); - - if (!test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &node->flags)) - goto no_iref; - - path->slots[0]++; - if (path->slots[0] >= btrfs_header_nritems(leaf)) - goto search; -again: - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - if (key.objectid != node->inode_id) - goto out; - - if (key.type != BTRFS_INODE_REF_KEY && - key.type != BTRFS_INODE_EXTREF_KEY) - goto out; - - /* - * Delayed iref deletion is for the inode who has only one link, - * so there is only one iref. The case that several irefs are - * in the same item doesn't exist. - */ - btrfs_del_item(trans, root, path); -out: - btrfs_release_delayed_iref(node); -no_iref: - btrfs_release_path(path); -err_out: - btrfs_delayed_inode_release_metadata(root, node); - btrfs_release_delayed_inode(node); - - return ret; - -search: - btrfs_release_path(path); - - key.type = BTRFS_INODE_EXTREF_KEY; - key.offset = -1; - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret < 0) - goto err_out; - ASSERT(ret); - - ret = 0; - leaf = path->nodes[0]; - path->slots[0]--; - goto again; -} - -static inline int btrfs_update_delayed_inode(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_delayed_node *node) -{ - int ret; - - mutex_lock(&node->mutex); - if (!test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &node->flags)) { - mutex_unlock(&node->mutex); - return 0; - } - - ret = __btrfs_update_delayed_inode(trans, root, path, node); - mutex_unlock(&node->mutex); - return ret; -} - -static inline int -__btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans, - struct btrfs_path *path, - struct btrfs_delayed_node *node) -{ - int ret; - - ret = btrfs_insert_delayed_items(trans, path, node->root, node); - if (ret) - return ret; - - ret = btrfs_delete_delayed_items(trans, path, node->root, node); - if (ret) - return ret; - - ret = btrfs_update_delayed_inode(trans, node->root, path, node); - return ret; -} - -/* - * Called when committing the transaction. - * Returns 0 on success. - * Returns < 0 on error and returns with an aborted transaction with any - * outstanding delayed items cleaned up. - */ -static int __btrfs_run_delayed_items(struct btrfs_trans_handle *trans, - struct btrfs_root *root, int nr) -{ - struct btrfs_delayed_root *delayed_root; - struct btrfs_delayed_node *curr_node, *prev_node; - struct btrfs_path *path; - struct btrfs_block_rsv *block_rsv; - int ret = 0; - bool count = (nr > 0); - - if (trans->aborted) - return -EIO; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->leave_spinning = 1; - - block_rsv = trans->block_rsv; - trans->block_rsv = &root->fs_info->delayed_block_rsv; - - delayed_root = btrfs_get_delayed_root(root); - - curr_node = btrfs_first_delayed_node(delayed_root); - while (curr_node && (!count || (count && nr--))) { - ret = __btrfs_commit_inode_delayed_items(trans, path, - curr_node); - if (ret) { - btrfs_release_delayed_node(curr_node); - curr_node = NULL; - btrfs_abort_transaction(trans, ret); - break; - } - - prev_node = curr_node; - curr_node = btrfs_next_delayed_node(curr_node); - btrfs_release_delayed_node(prev_node); - } - - if (curr_node) - btrfs_release_delayed_node(curr_node); - btrfs_free_path(path); - trans->block_rsv = block_rsv; - - return ret; -} - -int btrfs_run_delayed_items(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - return __btrfs_run_delayed_items(trans, root, -1); -} - -int btrfs_run_delayed_items_nr(struct btrfs_trans_handle *trans, - struct btrfs_root *root, int nr) -{ - return __btrfs_run_delayed_items(trans, root, nr); -} - -int btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans, - struct inode *inode) -{ - struct btrfs_delayed_node *delayed_node = btrfs_get_delayed_node(inode); - struct btrfs_path *path; - struct btrfs_block_rsv *block_rsv; - int ret; - - if (!delayed_node) - return 0; - - mutex_lock(&delayed_node->mutex); - if (!delayed_node->count) { - mutex_unlock(&delayed_node->mutex); - btrfs_release_delayed_node(delayed_node); - return 0; - } - mutex_unlock(&delayed_node->mutex); - - path = btrfs_alloc_path(); - if (!path) { - btrfs_release_delayed_node(delayed_node); - return -ENOMEM; - } - path->leave_spinning = 1; - - block_rsv = trans->block_rsv; - trans->block_rsv = &delayed_node->root->fs_info->delayed_block_rsv; - - ret = __btrfs_commit_inode_delayed_items(trans, path, delayed_node); - - btrfs_release_delayed_node(delayed_node); - btrfs_free_path(path); - trans->block_rsv = block_rsv; - - return ret; -} - -int btrfs_commit_inode_delayed_inode(struct inode *inode) -{ - struct btrfs_trans_handle *trans; - struct btrfs_delayed_node *delayed_node = btrfs_get_delayed_node(inode); - struct btrfs_path *path; - struct btrfs_block_rsv *block_rsv; - int ret; - - if (!delayed_node) - return 0; - - mutex_lock(&delayed_node->mutex); - if (!test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) { - mutex_unlock(&delayed_node->mutex); - btrfs_release_delayed_node(delayed_node); - return 0; - } - mutex_unlock(&delayed_node->mutex); - - trans = btrfs_join_transaction(delayed_node->root); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out; - } - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto trans_out; - } - path->leave_spinning = 1; - - block_rsv = trans->block_rsv; - trans->block_rsv = &delayed_node->root->fs_info->delayed_block_rsv; - - mutex_lock(&delayed_node->mutex); - if (test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) - ret = __btrfs_update_delayed_inode(trans, delayed_node->root, - path, delayed_node); - else - ret = 0; - mutex_unlock(&delayed_node->mutex); - - btrfs_free_path(path); - trans->block_rsv = block_rsv; -trans_out: - btrfs_end_transaction(trans, delayed_node->root); - btrfs_btree_balance_dirty(delayed_node->root); -out: - btrfs_release_delayed_node(delayed_node); - - return ret; -} - -void btrfs_remove_delayed_node(struct inode *inode) -{ - struct btrfs_delayed_node *delayed_node; - - delayed_node = ACCESS_ONCE(BTRFS_I(inode)->delayed_node); - if (!delayed_node) - return; - - BTRFS_I(inode)->delayed_node = NULL; - btrfs_release_delayed_node(delayed_node); -} - -struct btrfs_async_delayed_work { - struct btrfs_delayed_root *delayed_root; - int nr; - struct btrfs_work work; -}; - -static void btrfs_async_run_delayed_root(struct btrfs_work *work) -{ - struct btrfs_async_delayed_work *async_work; - struct btrfs_delayed_root *delayed_root; - struct btrfs_trans_handle *trans; - struct btrfs_path *path; - struct btrfs_delayed_node *delayed_node = NULL; - struct btrfs_root *root; - struct btrfs_block_rsv *block_rsv; - int total_done = 0; - - async_work = container_of(work, struct btrfs_async_delayed_work, work); - delayed_root = async_work->delayed_root; - - path = btrfs_alloc_path(); - if (!path) - goto out; - -again: - if (atomic_read(&delayed_root->items) < BTRFS_DELAYED_BACKGROUND / 2) - goto free_path; - - delayed_node = btrfs_first_prepared_delayed_node(delayed_root); - if (!delayed_node) - goto free_path; - - path->leave_spinning = 1; - root = delayed_node->root; - - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) - goto release_path; - - block_rsv = trans->block_rsv; - trans->block_rsv = &root->fs_info->delayed_block_rsv; - - __btrfs_commit_inode_delayed_items(trans, path, delayed_node); - - trans->block_rsv = block_rsv; - btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty_nodelay(root); - -release_path: - btrfs_release_path(path); - total_done++; - - btrfs_release_prepared_delayed_node(delayed_node); - if (async_work->nr == 0 || total_done < async_work->nr) - goto again; - -free_path: - btrfs_free_path(path); -out: - wake_up(&delayed_root->wait); - kfree(async_work); -} - - -static int btrfs_wq_run_delayed_node(struct btrfs_delayed_root *delayed_root, - struct btrfs_fs_info *fs_info, int nr) -{ - struct btrfs_async_delayed_work *async_work; - - if (atomic_read(&delayed_root->items) < BTRFS_DELAYED_BACKGROUND) - return 0; - - async_work = kmalloc(sizeof(*async_work), GFP_NOFS); - if (!async_work) - return -ENOMEM; - - async_work->delayed_root = delayed_root; - btrfs_init_work(&async_work->work, btrfs_delayed_meta_helper, - btrfs_async_run_delayed_root, NULL, NULL); - async_work->nr = nr; - - btrfs_queue_work(fs_info->delayed_workers, &async_work->work); - return 0; -} - -void btrfs_assert_delayed_root_empty(struct btrfs_root *root) -{ - struct btrfs_delayed_root *delayed_root; - delayed_root = btrfs_get_delayed_root(root); - WARN_ON(btrfs_first_delayed_node(delayed_root)); -} - -static int could_end_wait(struct btrfs_delayed_root *delayed_root, int seq) -{ - int val = atomic_read(&delayed_root->items_seq); - - if (val < seq || val >= seq + BTRFS_DELAYED_BATCH) - return 1; - - if (atomic_read(&delayed_root->items) < BTRFS_DELAYED_BACKGROUND) - return 1; - - return 0; -} - -void btrfs_balance_delayed_items(struct btrfs_root *root) -{ - struct btrfs_delayed_root *delayed_root; - struct btrfs_fs_info *fs_info = root->fs_info; - - delayed_root = btrfs_get_delayed_root(root); - - if (atomic_read(&delayed_root->items) < BTRFS_DELAYED_BACKGROUND) - return; - - if (atomic_read(&delayed_root->items) >= BTRFS_DELAYED_WRITEBACK) { - int seq; - int ret; - - seq = atomic_read(&delayed_root->items_seq); - - ret = btrfs_wq_run_delayed_node(delayed_root, fs_info, 0); - if (ret) - return; - - wait_event_interruptible(delayed_root->wait, - could_end_wait(delayed_root, seq)); - return; - } - - btrfs_wq_run_delayed_node(delayed_root, fs_info, BTRFS_DELAYED_BATCH); -} - -/* Will return 0 or -ENOMEM */ -int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans, - struct btrfs_root *root, const char *name, - int name_len, struct inode *dir, - struct btrfs_disk_key *disk_key, u8 type, - u64 index) -{ - struct btrfs_delayed_node *delayed_node; - struct btrfs_delayed_item *delayed_item; - struct btrfs_dir_item *dir_item; - int ret; - - delayed_node = btrfs_get_or_create_delayed_node(dir); - if (IS_ERR(delayed_node)) - return PTR_ERR(delayed_node); - - delayed_item = btrfs_alloc_delayed_item(sizeof(*dir_item) + name_len); - if (!delayed_item) { - ret = -ENOMEM; - goto release_node; - } - - delayed_item->key.objectid = btrfs_ino(dir); - delayed_item->key.type = BTRFS_DIR_INDEX_KEY; - delayed_item->key.offset = index; - - dir_item = (struct btrfs_dir_item *)delayed_item->data; - dir_item->location = *disk_key; - btrfs_set_stack_dir_transid(dir_item, trans->transid); - btrfs_set_stack_dir_data_len(dir_item, 0); - btrfs_set_stack_dir_name_len(dir_item, name_len); - btrfs_set_stack_dir_type(dir_item, type); - memcpy((char *)(dir_item + 1), name, name_len); - - ret = btrfs_delayed_item_reserve_metadata(trans, root, delayed_item); - /* - * we have reserved enough space when we start a new transaction, - * so reserving metadata failure is impossible - */ - BUG_ON(ret); - - - mutex_lock(&delayed_node->mutex); - ret = __btrfs_add_delayed_insertion_item(delayed_node, delayed_item); - if (unlikely(ret)) { - btrfs_err(root->fs_info, - "err add delayed dir index item(name: %.*s) into the insertion tree of the delayed node(root id: %llu, inode id: %llu, errno: %d)", - name_len, name, delayed_node->root->objectid, - delayed_node->inode_id, ret); - BUG(); - } - mutex_unlock(&delayed_node->mutex); - -release_node: - btrfs_release_delayed_node(delayed_node); - return ret; -} - -static int btrfs_delete_delayed_insertion_item(struct btrfs_root *root, - struct btrfs_delayed_node *node, - struct btrfs_key *key) -{ - struct btrfs_delayed_item *item; - - mutex_lock(&node->mutex); - item = __btrfs_lookup_delayed_insertion_item(node, key); - if (!item) { - mutex_unlock(&node->mutex); - return 1; - } - - btrfs_delayed_item_release_metadata(root, item); - btrfs_release_delayed_item(item); - mutex_unlock(&node->mutex); - return 0; -} - -int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct inode *dir, - u64 index) -{ - struct btrfs_delayed_node *node; - struct btrfs_delayed_item *item; - struct btrfs_key item_key; - int ret; - - node = btrfs_get_or_create_delayed_node(dir); - if (IS_ERR(node)) - return PTR_ERR(node); - - item_key.objectid = btrfs_ino(dir); - item_key.type = BTRFS_DIR_INDEX_KEY; - item_key.offset = index; - - ret = btrfs_delete_delayed_insertion_item(root, node, &item_key); - if (!ret) - goto end; - - item = btrfs_alloc_delayed_item(0); - if (!item) { - ret = -ENOMEM; - goto end; - } - - item->key = item_key; - - ret = btrfs_delayed_item_reserve_metadata(trans, root, item); - /* - * we have reserved enough space when we start a new transaction, - * so reserving metadata failure is impossible. - */ - BUG_ON(ret); - - mutex_lock(&node->mutex); - ret = __btrfs_add_delayed_deletion_item(node, item); - if (unlikely(ret)) { - btrfs_err(root->fs_info, - "err add delayed dir index item(index: %llu) into the deletion tree of the delayed node(root id: %llu, inode id: %llu, errno: %d)", - index, node->root->objectid, node->inode_id, ret); - BUG(); - } - mutex_unlock(&node->mutex); -end: - btrfs_release_delayed_node(node); - return ret; -} - -int btrfs_inode_delayed_dir_index_count(struct inode *inode) -{ - struct btrfs_delayed_node *delayed_node = btrfs_get_delayed_node(inode); - - if (!delayed_node) - return -ENOENT; - - /* - * Since we have held i_mutex of this directory, it is impossible that - * a new directory index is added into the delayed node and index_cnt - * is updated now. So we needn't lock the delayed node. - */ - if (!delayed_node->index_cnt) { - btrfs_release_delayed_node(delayed_node); - return -EINVAL; - } - - BTRFS_I(inode)->index_cnt = delayed_node->index_cnt; - btrfs_release_delayed_node(delayed_node); - return 0; -} - -bool btrfs_readdir_get_delayed_items(struct inode *inode, - struct list_head *ins_list, - struct list_head *del_list) -{ - struct btrfs_delayed_node *delayed_node; - struct btrfs_delayed_item *item; - - delayed_node = btrfs_get_delayed_node(inode); - if (!delayed_node) - return false; - - /* - * We can only do one readdir with delayed items at a time because of - * item->readdir_list. - */ - inode_unlock_shared(inode); - inode_lock(inode); - - mutex_lock(&delayed_node->mutex); - item = __btrfs_first_delayed_insertion_item(delayed_node); - while (item) { - atomic_inc(&item->refs); - list_add_tail(&item->readdir_list, ins_list); - item = __btrfs_next_delayed_item(item); - } - - item = __btrfs_first_delayed_deletion_item(delayed_node); - while (item) { - atomic_inc(&item->refs); - list_add_tail(&item->readdir_list, del_list); - item = __btrfs_next_delayed_item(item); - } - mutex_unlock(&delayed_node->mutex); - /* - * This delayed node is still cached in the btrfs inode, so refs - * must be > 1 now, and we needn't check it is going to be freed - * or not. - * - * Besides that, this function is used to read dir, we do not - * insert/delete delayed items in this period. So we also needn't - * requeue or dequeue this delayed node. - */ - atomic_dec(&delayed_node->refs); - - return true; -} - -void btrfs_readdir_put_delayed_items(struct inode *inode, - struct list_head *ins_list, - struct list_head *del_list) -{ - struct btrfs_delayed_item *curr, *next; - - list_for_each_entry_safe(curr, next, ins_list, readdir_list) { - list_del(&curr->readdir_list); - if (atomic_dec_and_test(&curr->refs)) - kfree(curr); - } - - list_for_each_entry_safe(curr, next, del_list, readdir_list) { - list_del(&curr->readdir_list); - if (atomic_dec_and_test(&curr->refs)) - kfree(curr); - } - - /* - * The VFS is going to do up_read(), so we need to downgrade back to a - * read lock. - */ - downgrade_write(&inode->i_rwsem); -} - -int btrfs_should_delete_dir_index(struct list_head *del_list, - u64 index) -{ - struct btrfs_delayed_item *curr, *next; - int ret; - - if (list_empty(del_list)) - return 0; - - list_for_each_entry_safe(curr, next, del_list, readdir_list) { - if (curr->key.offset > index) - break; - - list_del(&curr->readdir_list); - ret = (curr->key.offset == index); - - if (atomic_dec_and_test(&curr->refs)) - kfree(curr); - - if (ret) - return 1; - else - continue; - } - return 0; -} - -/* - * btrfs_readdir_delayed_dir_index - read dir info stored in the delayed tree - * - */ -int btrfs_readdir_delayed_dir_index(struct dir_context *ctx, - struct list_head *ins_list, bool *emitted) -{ - struct btrfs_dir_item *di; - struct btrfs_delayed_item *curr, *next; - struct btrfs_key location; - char *name; - int name_len; - int over = 0; - unsigned char d_type; - - if (list_empty(ins_list)) - return 0; - - /* - * Changing the data of the delayed item is impossible. So - * we needn't lock them. And we have held i_mutex of the - * directory, nobody can delete any directory indexes now. - */ - list_for_each_entry_safe(curr, next, ins_list, readdir_list) { - list_del(&curr->readdir_list); - - if (curr->key.offset < ctx->pos) { - if (atomic_dec_and_test(&curr->refs)) - kfree(curr); - continue; - } - - ctx->pos = curr->key.offset; - - di = (struct btrfs_dir_item *)curr->data; - name = (char *)(di + 1); - name_len = btrfs_stack_dir_name_len(di); - - d_type = btrfs_filetype_table[di->type]; - btrfs_disk_key_to_cpu(&location, &di->location); - - over = !dir_emit(ctx, name, name_len, - location.objectid, d_type); - - if (atomic_dec_and_test(&curr->refs)) - kfree(curr); - - if (over) - return 1; - *emitted = true; - } - return 0; -} - -static void fill_stack_inode_item(struct btrfs_trans_handle *trans, - struct btrfs_inode_item *inode_item, - struct inode *inode) -{ - btrfs_set_stack_inode_uid(inode_item, i_uid_read(inode)); - btrfs_set_stack_inode_gid(inode_item, i_gid_read(inode)); - btrfs_set_stack_inode_size(inode_item, BTRFS_I(inode)->disk_i_size); - btrfs_set_stack_inode_mode(inode_item, inode->i_mode); - btrfs_set_stack_inode_nlink(inode_item, inode->i_nlink); - btrfs_set_stack_inode_nbytes(inode_item, inode_get_bytes(inode)); - btrfs_set_stack_inode_generation(inode_item, - BTRFS_I(inode)->generation); - btrfs_set_stack_inode_sequence(inode_item, inode->i_version); - btrfs_set_stack_inode_transid(inode_item, trans->transid); - btrfs_set_stack_inode_rdev(inode_item, inode->i_rdev); - btrfs_set_stack_inode_flags(inode_item, BTRFS_I(inode)->flags); - btrfs_set_stack_inode_block_group(inode_item, 0); - - btrfs_set_stack_timespec_sec(&inode_item->atime, - inode->i_atime.tv_sec); - btrfs_set_stack_timespec_nsec(&inode_item->atime, - inode->i_atime.tv_nsec); - - btrfs_set_stack_timespec_sec(&inode_item->mtime, - inode->i_mtime.tv_sec); - btrfs_set_stack_timespec_nsec(&inode_item->mtime, - inode->i_mtime.tv_nsec); - - btrfs_set_stack_timespec_sec(&inode_item->ctime, - inode->i_ctime.tv_sec); - btrfs_set_stack_timespec_nsec(&inode_item->ctime, - inode->i_ctime.tv_nsec); - - btrfs_set_stack_timespec_sec(&inode_item->otime, - BTRFS_I(inode)->i_otime.tv_sec); - btrfs_set_stack_timespec_nsec(&inode_item->otime, - BTRFS_I(inode)->i_otime.tv_nsec); -} - -int btrfs_fill_inode(struct inode *inode, u32 *rdev) -{ - struct btrfs_delayed_node *delayed_node; - struct btrfs_inode_item *inode_item; - - delayed_node = btrfs_get_delayed_node(inode); - if (!delayed_node) - return -ENOENT; - - mutex_lock(&delayed_node->mutex); - if (!test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) { - mutex_unlock(&delayed_node->mutex); - btrfs_release_delayed_node(delayed_node); - return -ENOENT; - } - - inode_item = &delayed_node->inode_item; - - i_uid_write(inode, btrfs_stack_inode_uid(inode_item)); - i_gid_write(inode, btrfs_stack_inode_gid(inode_item)); - btrfs_i_size_write(inode, btrfs_stack_inode_size(inode_item)); - inode->i_mode = btrfs_stack_inode_mode(inode_item); - set_nlink(inode, btrfs_stack_inode_nlink(inode_item)); - inode_set_bytes(inode, btrfs_stack_inode_nbytes(inode_item)); - BTRFS_I(inode)->generation = btrfs_stack_inode_generation(inode_item); - BTRFS_I(inode)->last_trans = btrfs_stack_inode_transid(inode_item); - - inode->i_version = btrfs_stack_inode_sequence(inode_item); - inode->i_rdev = 0; - *rdev = btrfs_stack_inode_rdev(inode_item); - BTRFS_I(inode)->flags = btrfs_stack_inode_flags(inode_item); - - inode->i_atime.tv_sec = btrfs_stack_timespec_sec(&inode_item->atime); - inode->i_atime.tv_nsec = btrfs_stack_timespec_nsec(&inode_item->atime); - - inode->i_mtime.tv_sec = btrfs_stack_timespec_sec(&inode_item->mtime); - inode->i_mtime.tv_nsec = btrfs_stack_timespec_nsec(&inode_item->mtime); - - inode->i_ctime.tv_sec = btrfs_stack_timespec_sec(&inode_item->ctime); - inode->i_ctime.tv_nsec = btrfs_stack_timespec_nsec(&inode_item->ctime); - - BTRFS_I(inode)->i_otime.tv_sec = - btrfs_stack_timespec_sec(&inode_item->otime); - BTRFS_I(inode)->i_otime.tv_nsec = - btrfs_stack_timespec_nsec(&inode_item->otime); - - inode->i_generation = BTRFS_I(inode)->generation; - BTRFS_I(inode)->index_cnt = (u64)-1; - - mutex_unlock(&delayed_node->mutex); - btrfs_release_delayed_node(delayed_node); - return 0; -} - -int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct inode *inode) -{ - struct btrfs_delayed_node *delayed_node; - int ret = 0; - - delayed_node = btrfs_get_or_create_delayed_node(inode); - if (IS_ERR(delayed_node)) - return PTR_ERR(delayed_node); - - mutex_lock(&delayed_node->mutex); - if (test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) { - fill_stack_inode_item(trans, &delayed_node->inode_item, inode); - goto release_node; - } - - ret = btrfs_delayed_inode_reserve_metadata(trans, root, inode, - delayed_node); - if (ret) - goto release_node; - - fill_stack_inode_item(trans, &delayed_node->inode_item, inode); - set_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags); - delayed_node->count++; - atomic_inc(&root->fs_info->delayed_root->items); -release_node: - mutex_unlock(&delayed_node->mutex); - btrfs_release_delayed_node(delayed_node); - return ret; -} - -int btrfs_delayed_delete_inode_ref(struct inode *inode) -{ - struct btrfs_delayed_node *delayed_node; - - /* - * we don't do delayed inode updates during log recovery because it - * leads to enospc problems. This means we also can't do - * delayed inode refs - */ - if (test_bit(BTRFS_FS_LOG_RECOVERING, - &BTRFS_I(inode)->root->fs_info->flags)) - return -EAGAIN; - - delayed_node = btrfs_get_or_create_delayed_node(inode); - if (IS_ERR(delayed_node)) - return PTR_ERR(delayed_node); - - /* - * We don't reserve space for inode ref deletion is because: - * - We ONLY do async inode ref deletion for the inode who has only - * one link(i_nlink == 1), it means there is only one inode ref. - * And in most case, the inode ref and the inode item are in the - * same leaf, and we will deal with them at the same time. - * Since we are sure we will reserve the space for the inode item, - * it is unnecessary to reserve space for inode ref deletion. - * - If the inode ref and the inode item are not in the same leaf, - * We also needn't worry about enospc problem, because we reserve - * much more space for the inode update than it needs. - * - At the worst, we can steal some space from the global reservation. - * It is very rare. - */ - mutex_lock(&delayed_node->mutex); - if (test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags)) - goto release_node; - - set_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags); - delayed_node->count++; - atomic_inc(&BTRFS_I(inode)->root->fs_info->delayed_root->items); -release_node: - mutex_unlock(&delayed_node->mutex); - btrfs_release_delayed_node(delayed_node); - return 0; -} - -static void __btrfs_kill_delayed_node(struct btrfs_delayed_node *delayed_node) -{ - struct btrfs_root *root = delayed_node->root; - struct btrfs_delayed_item *curr_item, *prev_item; - - mutex_lock(&delayed_node->mutex); - curr_item = __btrfs_first_delayed_insertion_item(delayed_node); - while (curr_item) { - btrfs_delayed_item_release_metadata(root, curr_item); - prev_item = curr_item; - curr_item = __btrfs_next_delayed_item(prev_item); - btrfs_release_delayed_item(prev_item); - } - - curr_item = __btrfs_first_delayed_deletion_item(delayed_node); - while (curr_item) { - btrfs_delayed_item_release_metadata(root, curr_item); - prev_item = curr_item; - curr_item = __btrfs_next_delayed_item(prev_item); - btrfs_release_delayed_item(prev_item); - } - - if (test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags)) - btrfs_release_delayed_iref(delayed_node); - - if (test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) { - btrfs_delayed_inode_release_metadata(root, delayed_node); - btrfs_release_delayed_inode(delayed_node); - } - mutex_unlock(&delayed_node->mutex); -} - -void btrfs_kill_delayed_inode_items(struct inode *inode) -{ - struct btrfs_delayed_node *delayed_node; - - delayed_node = btrfs_get_delayed_node(inode); - if (!delayed_node) - return; - - __btrfs_kill_delayed_node(delayed_node); - btrfs_release_delayed_node(delayed_node); -} - -void btrfs_kill_all_delayed_nodes(struct btrfs_root *root) -{ - u64 inode_id = 0; - struct btrfs_delayed_node *delayed_nodes[8]; - int i, n; - - while (1) { - spin_lock(&root->inode_lock); - n = radix_tree_gang_lookup(&root->delayed_nodes_tree, - (void **)delayed_nodes, inode_id, - ARRAY_SIZE(delayed_nodes)); - if (!n) { - spin_unlock(&root->inode_lock); - break; - } - - inode_id = delayed_nodes[n - 1]->inode_id + 1; - - for (i = 0; i < n; i++) - atomic_inc(&delayed_nodes[i]->refs); - spin_unlock(&root->inode_lock); - - for (i = 0; i < n; i++) { - __btrfs_kill_delayed_node(delayed_nodes[i]); - btrfs_release_delayed_node(delayed_nodes[i]); - } - } -} - -void btrfs_destroy_delayed_inodes(struct btrfs_root *root) -{ - struct btrfs_delayed_root *delayed_root; - struct btrfs_delayed_node *curr_node, *prev_node; - - delayed_root = btrfs_get_delayed_root(root); - - curr_node = btrfs_first_delayed_node(delayed_root); - while (curr_node) { - __btrfs_kill_delayed_node(curr_node); - - prev_node = curr_node; - curr_node = btrfs_next_delayed_node(curr_node); - btrfs_release_delayed_node(prev_node); - } -} - diff --git a/src/linux/fs/btrfs/delayed-inode.h b/src/linux/fs/btrfs/delayed-inode.h deleted file mode 100644 index 2495b3d..0000000 --- a/src/linux/fs/btrfs/delayed-inode.h +++ /dev/null @@ -1,158 +0,0 @@ -/* - * Copyright (C) 2011 Fujitsu. All rights reserved. - * Written by Miao Xie - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __DELAYED_TREE_OPERATION_H -#define __DELAYED_TREE_OPERATION_H - -#include -#include -#include -#include -#include -#include - -#include "ctree.h" - -/* types of the delayed item */ -#define BTRFS_DELAYED_INSERTION_ITEM 1 -#define BTRFS_DELAYED_DELETION_ITEM 2 - -struct btrfs_delayed_root { - spinlock_t lock; - struct list_head node_list; - /* - * Used for delayed nodes which is waiting to be dealt with by the - * worker. If the delayed node is inserted into the work queue, we - * drop it from this list. - */ - struct list_head prepare_list; - atomic_t items; /* for delayed items */ - atomic_t items_seq; /* for delayed items */ - int nodes; /* for delayed nodes */ - wait_queue_head_t wait; -}; - -#define BTRFS_DELAYED_NODE_IN_LIST 0 -#define BTRFS_DELAYED_NODE_INODE_DIRTY 1 -#define BTRFS_DELAYED_NODE_DEL_IREF 2 - -struct btrfs_delayed_node { - u64 inode_id; - u64 bytes_reserved; - struct btrfs_root *root; - /* Used to add the node into the delayed root's node list. */ - struct list_head n_list; - /* - * Used to add the node into the prepare list, the nodes in this list - * is waiting to be dealt with by the async worker. - */ - struct list_head p_list; - struct rb_root ins_root; - struct rb_root del_root; - struct mutex mutex; - struct btrfs_inode_item inode_item; - atomic_t refs; - u64 index_cnt; - unsigned long flags; - int count; -}; - -struct btrfs_delayed_item { - struct rb_node rb_node; - struct btrfs_key key; - struct list_head tree_list; /* used for batch insert/delete items */ - struct list_head readdir_list; /* used for readdir items */ - u64 bytes_reserved; - struct btrfs_delayed_node *delayed_node; - atomic_t refs; - int ins_or_del; - u32 data_len; - char data[0]; -}; - -static inline void btrfs_init_delayed_root( - struct btrfs_delayed_root *delayed_root) -{ - atomic_set(&delayed_root->items, 0); - atomic_set(&delayed_root->items_seq, 0); - delayed_root->nodes = 0; - spin_lock_init(&delayed_root->lock); - init_waitqueue_head(&delayed_root->wait); - INIT_LIST_HEAD(&delayed_root->node_list); - INIT_LIST_HEAD(&delayed_root->prepare_list); -} - -int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans, - struct btrfs_root *root, const char *name, - int name_len, struct inode *dir, - struct btrfs_disk_key *disk_key, u8 type, - u64 index); - -int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct inode *dir, - u64 index); - -int btrfs_inode_delayed_dir_index_count(struct inode *inode); - -int btrfs_run_delayed_items(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -int btrfs_run_delayed_items_nr(struct btrfs_trans_handle *trans, - struct btrfs_root *root, int nr); - -void btrfs_balance_delayed_items(struct btrfs_root *root); - -int btrfs_commit_inode_delayed_items(struct btrfs_trans_handle *trans, - struct inode *inode); -/* Used for evicting the inode. */ -void btrfs_remove_delayed_node(struct inode *inode); -void btrfs_kill_delayed_inode_items(struct inode *inode); -int btrfs_commit_inode_delayed_inode(struct inode *inode); - - -int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct inode *inode); -int btrfs_fill_inode(struct inode *inode, u32 *rdev); -int btrfs_delayed_delete_inode_ref(struct inode *inode); - -/* Used for drop dead root */ -void btrfs_kill_all_delayed_nodes(struct btrfs_root *root); - -/* Used for clean the transaction */ -void btrfs_destroy_delayed_inodes(struct btrfs_root *root); - -/* Used for readdir() */ -bool btrfs_readdir_get_delayed_items(struct inode *inode, - struct list_head *ins_list, - struct list_head *del_list); -void btrfs_readdir_put_delayed_items(struct inode *inode, - struct list_head *ins_list, - struct list_head *del_list); -int btrfs_should_delete_dir_index(struct list_head *del_list, - u64 index); -int btrfs_readdir_delayed_dir_index(struct dir_context *ctx, - struct list_head *ins_list, bool *emitted); - -/* for init */ -int __init btrfs_delayed_inode_init(void); -void btrfs_delayed_inode_exit(void); - -/* for debugging */ -void btrfs_assert_delayed_root_empty(struct btrfs_root *root); - -#endif diff --git a/src/linux/fs/btrfs/delayed-ref.c b/src/linux/fs/btrfs/delayed-ref.c deleted file mode 100644 index 8d93854..0000000 --- a/src/linux/fs/btrfs/delayed-ref.c +++ /dev/null @@ -1,946 +0,0 @@ -/* - * Copyright (C) 2009 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include "ctree.h" -#include "delayed-ref.h" -#include "transaction.h" -#include "qgroup.h" - -struct kmem_cache *btrfs_delayed_ref_head_cachep; -struct kmem_cache *btrfs_delayed_tree_ref_cachep; -struct kmem_cache *btrfs_delayed_data_ref_cachep; -struct kmem_cache *btrfs_delayed_extent_op_cachep; -/* - * delayed back reference update tracking. For subvolume trees - * we queue up extent allocations and backref maintenance for - * delayed processing. This avoids deep call chains where we - * add extents in the middle of btrfs_search_slot, and it allows - * us to buffer up frequently modified backrefs in an rb tree instead - * of hammering updates on the extent allocation tree. - */ - -/* - * compare two delayed tree backrefs with same bytenr and type - */ -static int comp_tree_refs(struct btrfs_delayed_tree_ref *ref2, - struct btrfs_delayed_tree_ref *ref1, int type) -{ - if (type == BTRFS_TREE_BLOCK_REF_KEY) { - if (ref1->root < ref2->root) - return -1; - if (ref1->root > ref2->root) - return 1; - } else { - if (ref1->parent < ref2->parent) - return -1; - if (ref1->parent > ref2->parent) - return 1; - } - return 0; -} - -/* - * compare two delayed data backrefs with same bytenr and type - */ -static int comp_data_refs(struct btrfs_delayed_data_ref *ref2, - struct btrfs_delayed_data_ref *ref1) -{ - if (ref1->node.type == BTRFS_EXTENT_DATA_REF_KEY) { - if (ref1->root < ref2->root) - return -1; - if (ref1->root > ref2->root) - return 1; - if (ref1->objectid < ref2->objectid) - return -1; - if (ref1->objectid > ref2->objectid) - return 1; - if (ref1->offset < ref2->offset) - return -1; - if (ref1->offset > ref2->offset) - return 1; - } else { - if (ref1->parent < ref2->parent) - return -1; - if (ref1->parent > ref2->parent) - return 1; - } - return 0; -} - -/* insert a new ref to head ref rbtree */ -static struct btrfs_delayed_ref_head *htree_insert(struct rb_root *root, - struct rb_node *node) -{ - struct rb_node **p = &root->rb_node; - struct rb_node *parent_node = NULL; - struct btrfs_delayed_ref_head *entry; - struct btrfs_delayed_ref_head *ins; - u64 bytenr; - - ins = rb_entry(node, struct btrfs_delayed_ref_head, href_node); - bytenr = ins->node.bytenr; - while (*p) { - parent_node = *p; - entry = rb_entry(parent_node, struct btrfs_delayed_ref_head, - href_node); - - if (bytenr < entry->node.bytenr) - p = &(*p)->rb_left; - else if (bytenr > entry->node.bytenr) - p = &(*p)->rb_right; - else - return entry; - } - - rb_link_node(node, parent_node, p); - rb_insert_color(node, root); - return NULL; -} - -/* - * find an head entry based on bytenr. This returns the delayed ref - * head if it was able to find one, or NULL if nothing was in that spot. - * If return_bigger is given, the next bigger entry is returned if no exact - * match is found. - */ -static struct btrfs_delayed_ref_head * -find_ref_head(struct rb_root *root, u64 bytenr, - int return_bigger) -{ - struct rb_node *n; - struct btrfs_delayed_ref_head *entry; - - n = root->rb_node; - entry = NULL; - while (n) { - entry = rb_entry(n, struct btrfs_delayed_ref_head, href_node); - - if (bytenr < entry->node.bytenr) - n = n->rb_left; - else if (bytenr > entry->node.bytenr) - n = n->rb_right; - else - return entry; - } - if (entry && return_bigger) { - if (bytenr > entry->node.bytenr) { - n = rb_next(&entry->href_node); - if (!n) - n = rb_first(root); - entry = rb_entry(n, struct btrfs_delayed_ref_head, - href_node); - return entry; - } - return entry; - } - return NULL; -} - -int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans, - struct btrfs_delayed_ref_head *head) -{ - struct btrfs_delayed_ref_root *delayed_refs; - - delayed_refs = &trans->transaction->delayed_refs; - assert_spin_locked(&delayed_refs->lock); - if (mutex_trylock(&head->mutex)) - return 0; - - atomic_inc(&head->node.refs); - spin_unlock(&delayed_refs->lock); - - mutex_lock(&head->mutex); - spin_lock(&delayed_refs->lock); - if (!head->node.in_tree) { - mutex_unlock(&head->mutex); - btrfs_put_delayed_ref(&head->node); - return -EAGAIN; - } - btrfs_put_delayed_ref(&head->node); - return 0; -} - -static inline void drop_delayed_ref(struct btrfs_trans_handle *trans, - struct btrfs_delayed_ref_root *delayed_refs, - struct btrfs_delayed_ref_head *head, - struct btrfs_delayed_ref_node *ref) -{ - if (btrfs_delayed_ref_is_head(ref)) { - head = btrfs_delayed_node_to_head(ref); - rb_erase(&head->href_node, &delayed_refs->href_root); - } else { - assert_spin_locked(&head->lock); - list_del(&ref->list); - } - ref->in_tree = 0; - btrfs_put_delayed_ref(ref); - atomic_dec(&delayed_refs->num_entries); - if (trans->delayed_ref_updates) - trans->delayed_ref_updates--; -} - -static bool merge_ref(struct btrfs_trans_handle *trans, - struct btrfs_delayed_ref_root *delayed_refs, - struct btrfs_delayed_ref_head *head, - struct btrfs_delayed_ref_node *ref, - u64 seq) -{ - struct btrfs_delayed_ref_node *next; - bool done = false; - - next = list_first_entry(&head->ref_list, struct btrfs_delayed_ref_node, - list); - while (!done && &next->list != &head->ref_list) { - int mod; - struct btrfs_delayed_ref_node *next2; - - next2 = list_next_entry(next, list); - - if (next == ref) - goto next; - - if (seq && next->seq >= seq) - goto next; - - if (next->type != ref->type) - goto next; - - if ((ref->type == BTRFS_TREE_BLOCK_REF_KEY || - ref->type == BTRFS_SHARED_BLOCK_REF_KEY) && - comp_tree_refs(btrfs_delayed_node_to_tree_ref(ref), - btrfs_delayed_node_to_tree_ref(next), - ref->type)) - goto next; - if ((ref->type == BTRFS_EXTENT_DATA_REF_KEY || - ref->type == BTRFS_SHARED_DATA_REF_KEY) && - comp_data_refs(btrfs_delayed_node_to_data_ref(ref), - btrfs_delayed_node_to_data_ref(next))) - goto next; - - if (ref->action == next->action) { - mod = next->ref_mod; - } else { - if (ref->ref_mod < next->ref_mod) { - swap(ref, next); - done = true; - } - mod = -next->ref_mod; - } - - drop_delayed_ref(trans, delayed_refs, head, next); - ref->ref_mod += mod; - if (ref->ref_mod == 0) { - drop_delayed_ref(trans, delayed_refs, head, ref); - done = true; - } else { - /* - * Can't have multiples of the same ref on a tree block. - */ - WARN_ON(ref->type == BTRFS_TREE_BLOCK_REF_KEY || - ref->type == BTRFS_SHARED_BLOCK_REF_KEY); - } -next: - next = next2; - } - - return done; -} - -void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_delayed_ref_root *delayed_refs, - struct btrfs_delayed_ref_head *head) -{ - struct btrfs_delayed_ref_node *ref; - u64 seq = 0; - - assert_spin_locked(&head->lock); - - if (list_empty(&head->ref_list)) - return; - - /* We don't have too many refs to merge for data. */ - if (head->is_data) - return; - - spin_lock(&fs_info->tree_mod_seq_lock); - if (!list_empty(&fs_info->tree_mod_seq_list)) { - struct seq_list *elem; - - elem = list_first_entry(&fs_info->tree_mod_seq_list, - struct seq_list, list); - seq = elem->seq; - } - spin_unlock(&fs_info->tree_mod_seq_lock); - - ref = list_first_entry(&head->ref_list, struct btrfs_delayed_ref_node, - list); - while (&ref->list != &head->ref_list) { - if (seq && ref->seq >= seq) - goto next; - - if (merge_ref(trans, delayed_refs, head, ref, seq)) { - if (list_empty(&head->ref_list)) - break; - ref = list_first_entry(&head->ref_list, - struct btrfs_delayed_ref_node, - list); - continue; - } -next: - ref = list_next_entry(ref, list); - } -} - -int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info, - struct btrfs_delayed_ref_root *delayed_refs, - u64 seq) -{ - struct seq_list *elem; - int ret = 0; - - spin_lock(&fs_info->tree_mod_seq_lock); - if (!list_empty(&fs_info->tree_mod_seq_list)) { - elem = list_first_entry(&fs_info->tree_mod_seq_list, - struct seq_list, list); - if (seq >= elem->seq) { - btrfs_debug(fs_info, - "holding back delayed_ref %#x.%x, lowest is %#x.%x (%p)", - (u32)(seq >> 32), (u32)seq, - (u32)(elem->seq >> 32), (u32)elem->seq, - delayed_refs); - ret = 1; - } - } - - spin_unlock(&fs_info->tree_mod_seq_lock); - return ret; -} - -struct btrfs_delayed_ref_head * -btrfs_select_ref_head(struct btrfs_trans_handle *trans) -{ - struct btrfs_delayed_ref_root *delayed_refs; - struct btrfs_delayed_ref_head *head; - u64 start; - bool loop = false; - - delayed_refs = &trans->transaction->delayed_refs; - -again: - start = delayed_refs->run_delayed_start; - head = find_ref_head(&delayed_refs->href_root, start, 1); - if (!head && !loop) { - delayed_refs->run_delayed_start = 0; - start = 0; - loop = true; - head = find_ref_head(&delayed_refs->href_root, start, 1); - if (!head) - return NULL; - } else if (!head && loop) { - return NULL; - } - - while (head->processing) { - struct rb_node *node; - - node = rb_next(&head->href_node); - if (!node) { - if (loop) - return NULL; - delayed_refs->run_delayed_start = 0; - start = 0; - loop = true; - goto again; - } - head = rb_entry(node, struct btrfs_delayed_ref_head, - href_node); - } - - head->processing = 1; - WARN_ON(delayed_refs->num_heads_ready == 0); - delayed_refs->num_heads_ready--; - delayed_refs->run_delayed_start = head->node.bytenr + - head->node.num_bytes; - return head; -} - -/* - * Helper to insert the ref_node to the tail or merge with tail. - * - * Return 0 for insert. - * Return >0 for merge. - */ -static int -add_delayed_ref_tail_merge(struct btrfs_trans_handle *trans, - struct btrfs_delayed_ref_root *root, - struct btrfs_delayed_ref_head *href, - struct btrfs_delayed_ref_node *ref) -{ - struct btrfs_delayed_ref_node *exist; - int mod; - int ret = 0; - - spin_lock(&href->lock); - /* Check whether we can merge the tail node with ref */ - if (list_empty(&href->ref_list)) - goto add_tail; - exist = list_entry(href->ref_list.prev, struct btrfs_delayed_ref_node, - list); - /* No need to compare bytenr nor is_head */ - if (exist->type != ref->type || exist->seq != ref->seq) - goto add_tail; - - if ((exist->type == BTRFS_TREE_BLOCK_REF_KEY || - exist->type == BTRFS_SHARED_BLOCK_REF_KEY) && - comp_tree_refs(btrfs_delayed_node_to_tree_ref(exist), - btrfs_delayed_node_to_tree_ref(ref), - ref->type)) - goto add_tail; - if ((exist->type == BTRFS_EXTENT_DATA_REF_KEY || - exist->type == BTRFS_SHARED_DATA_REF_KEY) && - comp_data_refs(btrfs_delayed_node_to_data_ref(exist), - btrfs_delayed_node_to_data_ref(ref))) - goto add_tail; - - /* Now we are sure we can merge */ - ret = 1; - if (exist->action == ref->action) { - mod = ref->ref_mod; - } else { - /* Need to change action */ - if (exist->ref_mod < ref->ref_mod) { - exist->action = ref->action; - mod = -exist->ref_mod; - exist->ref_mod = ref->ref_mod; - } else - mod = -ref->ref_mod; - } - exist->ref_mod += mod; - - /* remove existing tail if its ref_mod is zero */ - if (exist->ref_mod == 0) - drop_delayed_ref(trans, root, href, exist); - spin_unlock(&href->lock); - return ret; - -add_tail: - list_add_tail(&ref->list, &href->ref_list); - atomic_inc(&root->num_entries); - trans->delayed_ref_updates++; - spin_unlock(&href->lock); - return ret; -} - -/* - * helper function to update the accounting in the head ref - * existing and update must have the same bytenr - */ -static noinline void -update_existing_head_ref(struct btrfs_delayed_ref_root *delayed_refs, - struct btrfs_delayed_ref_node *existing, - struct btrfs_delayed_ref_node *update) -{ - struct btrfs_delayed_ref_head *existing_ref; - struct btrfs_delayed_ref_head *ref; - int old_ref_mod; - - existing_ref = btrfs_delayed_node_to_head(existing); - ref = btrfs_delayed_node_to_head(update); - BUG_ON(existing_ref->is_data != ref->is_data); - - spin_lock(&existing_ref->lock); - if (ref->must_insert_reserved) { - /* if the extent was freed and then - * reallocated before the delayed ref - * entries were processed, we can end up - * with an existing head ref without - * the must_insert_reserved flag set. - * Set it again here - */ - existing_ref->must_insert_reserved = ref->must_insert_reserved; - - /* - * update the num_bytes so we make sure the accounting - * is done correctly - */ - existing->num_bytes = update->num_bytes; - - } - - if (ref->extent_op) { - if (!existing_ref->extent_op) { - existing_ref->extent_op = ref->extent_op; - } else { - if (ref->extent_op->update_key) { - memcpy(&existing_ref->extent_op->key, - &ref->extent_op->key, - sizeof(ref->extent_op->key)); - existing_ref->extent_op->update_key = true; - } - if (ref->extent_op->update_flags) { - existing_ref->extent_op->flags_to_set |= - ref->extent_op->flags_to_set; - existing_ref->extent_op->update_flags = true; - } - btrfs_free_delayed_extent_op(ref->extent_op); - } - } - /* - * update the reference mod on the head to reflect this new operation, - * only need the lock for this case cause we could be processing it - * currently, for refs we just added we know we're a-ok. - */ - old_ref_mod = existing_ref->total_ref_mod; - existing->ref_mod += update->ref_mod; - existing_ref->total_ref_mod += update->ref_mod; - - /* - * If we are going to from a positive ref mod to a negative or vice - * versa we need to make sure to adjust pending_csums accordingly. - */ - if (existing_ref->is_data) { - if (existing_ref->total_ref_mod >= 0 && old_ref_mod < 0) - delayed_refs->pending_csums -= existing->num_bytes; - if (existing_ref->total_ref_mod < 0 && old_ref_mod >= 0) - delayed_refs->pending_csums += existing->num_bytes; - } - spin_unlock(&existing_ref->lock); -} - -/* - * helper function to actually insert a head node into the rbtree. - * this does all the dirty work in terms of maintaining the correct - * overall modification count. - */ -static noinline struct btrfs_delayed_ref_head * -add_delayed_ref_head(struct btrfs_fs_info *fs_info, - struct btrfs_trans_handle *trans, - struct btrfs_delayed_ref_node *ref, - struct btrfs_qgroup_extent_record *qrecord, - u64 bytenr, u64 num_bytes, u64 ref_root, u64 reserved, - int action, int is_data) -{ - struct btrfs_delayed_ref_head *existing; - struct btrfs_delayed_ref_head *head_ref = NULL; - struct btrfs_delayed_ref_root *delayed_refs; - int count_mod = 1; - int must_insert_reserved = 0; - - /* If reserved is provided, it must be a data extent. */ - BUG_ON(!is_data && reserved); - - /* - * the head node stores the sum of all the mods, so dropping a ref - * should drop the sum in the head node by one. - */ - if (action == BTRFS_UPDATE_DELAYED_HEAD) - count_mod = 0; - else if (action == BTRFS_DROP_DELAYED_REF) - count_mod = -1; - - /* - * BTRFS_ADD_DELAYED_EXTENT means that we need to update - * the reserved accounting when the extent is finally added, or - * if a later modification deletes the delayed ref without ever - * inserting the extent into the extent allocation tree. - * ref->must_insert_reserved is the flag used to record - * that accounting mods are required. - * - * Once we record must_insert_reserved, switch the action to - * BTRFS_ADD_DELAYED_REF because other special casing is not required. - */ - if (action == BTRFS_ADD_DELAYED_EXTENT) - must_insert_reserved = 1; - else - must_insert_reserved = 0; - - delayed_refs = &trans->transaction->delayed_refs; - - /* first set the basic ref node struct up */ - atomic_set(&ref->refs, 1); - ref->bytenr = bytenr; - ref->num_bytes = num_bytes; - ref->ref_mod = count_mod; - ref->type = 0; - ref->action = 0; - ref->is_head = 1; - ref->in_tree = 1; - ref->seq = 0; - - head_ref = btrfs_delayed_node_to_head(ref); - head_ref->must_insert_reserved = must_insert_reserved; - head_ref->is_data = is_data; - INIT_LIST_HEAD(&head_ref->ref_list); - head_ref->processing = 0; - head_ref->total_ref_mod = count_mod; - head_ref->qgroup_reserved = 0; - head_ref->qgroup_ref_root = 0; - - /* Record qgroup extent info if provided */ - if (qrecord) { - if (ref_root && reserved) { - head_ref->qgroup_ref_root = ref_root; - head_ref->qgroup_reserved = reserved; - } - - qrecord->bytenr = bytenr; - qrecord->num_bytes = num_bytes; - qrecord->old_roots = NULL; - - if(btrfs_qgroup_insert_dirty_extent_nolock(fs_info, - delayed_refs, qrecord)) - kfree(qrecord); - } - - spin_lock_init(&head_ref->lock); - mutex_init(&head_ref->mutex); - - trace_add_delayed_ref_head(fs_info, ref, head_ref, action); - - existing = htree_insert(&delayed_refs->href_root, - &head_ref->href_node); - if (existing) { - WARN_ON(ref_root && reserved && existing->qgroup_ref_root - && existing->qgroup_reserved); - update_existing_head_ref(delayed_refs, &existing->node, ref); - /* - * we've updated the existing ref, free the newly - * allocated ref - */ - kmem_cache_free(btrfs_delayed_ref_head_cachep, head_ref); - head_ref = existing; - } else { - if (is_data && count_mod < 0) - delayed_refs->pending_csums += num_bytes; - delayed_refs->num_heads++; - delayed_refs->num_heads_ready++; - atomic_inc(&delayed_refs->num_entries); - trans->delayed_ref_updates++; - } - return head_ref; -} - -/* - * helper to insert a delayed tree ref into the rbtree. - */ -static noinline void -add_delayed_tree_ref(struct btrfs_fs_info *fs_info, - struct btrfs_trans_handle *trans, - struct btrfs_delayed_ref_head *head_ref, - struct btrfs_delayed_ref_node *ref, u64 bytenr, - u64 num_bytes, u64 parent, u64 ref_root, int level, - int action) -{ - struct btrfs_delayed_tree_ref *full_ref; - struct btrfs_delayed_ref_root *delayed_refs; - u64 seq = 0; - int ret; - - if (action == BTRFS_ADD_DELAYED_EXTENT) - action = BTRFS_ADD_DELAYED_REF; - - if (is_fstree(ref_root)) - seq = atomic64_read(&fs_info->tree_mod_seq); - delayed_refs = &trans->transaction->delayed_refs; - - /* first set the basic ref node struct up */ - atomic_set(&ref->refs, 1); - ref->bytenr = bytenr; - ref->num_bytes = num_bytes; - ref->ref_mod = 1; - ref->action = action; - ref->is_head = 0; - ref->in_tree = 1; - ref->seq = seq; - - full_ref = btrfs_delayed_node_to_tree_ref(ref); - full_ref->parent = parent; - full_ref->root = ref_root; - if (parent) - ref->type = BTRFS_SHARED_BLOCK_REF_KEY; - else - ref->type = BTRFS_TREE_BLOCK_REF_KEY; - full_ref->level = level; - - trace_add_delayed_tree_ref(fs_info, ref, full_ref, action); - - ret = add_delayed_ref_tail_merge(trans, delayed_refs, head_ref, ref); - - /* - * XXX: memory should be freed at the same level allocated. - * But bad practice is anywhere... Follow it now. Need cleanup. - */ - if (ret > 0) - kmem_cache_free(btrfs_delayed_tree_ref_cachep, full_ref); -} - -/* - * helper to insert a delayed data ref into the rbtree. - */ -static noinline void -add_delayed_data_ref(struct btrfs_fs_info *fs_info, - struct btrfs_trans_handle *trans, - struct btrfs_delayed_ref_head *head_ref, - struct btrfs_delayed_ref_node *ref, u64 bytenr, - u64 num_bytes, u64 parent, u64 ref_root, u64 owner, - u64 offset, int action) -{ - struct btrfs_delayed_data_ref *full_ref; - struct btrfs_delayed_ref_root *delayed_refs; - u64 seq = 0; - int ret; - - if (action == BTRFS_ADD_DELAYED_EXTENT) - action = BTRFS_ADD_DELAYED_REF; - - delayed_refs = &trans->transaction->delayed_refs; - - if (is_fstree(ref_root)) - seq = atomic64_read(&fs_info->tree_mod_seq); - - /* first set the basic ref node struct up */ - atomic_set(&ref->refs, 1); - ref->bytenr = bytenr; - ref->num_bytes = num_bytes; - ref->ref_mod = 1; - ref->action = action; - ref->is_head = 0; - ref->in_tree = 1; - ref->seq = seq; - - full_ref = btrfs_delayed_node_to_data_ref(ref); - full_ref->parent = parent; - full_ref->root = ref_root; - if (parent) - ref->type = BTRFS_SHARED_DATA_REF_KEY; - else - ref->type = BTRFS_EXTENT_DATA_REF_KEY; - - full_ref->objectid = owner; - full_ref->offset = offset; - - trace_add_delayed_data_ref(fs_info, ref, full_ref, action); - - ret = add_delayed_ref_tail_merge(trans, delayed_refs, head_ref, ref); - - if (ret > 0) - kmem_cache_free(btrfs_delayed_data_ref_cachep, full_ref); -} - -/* - * add a delayed tree ref. This does all of the accounting required - * to make sure the delayed ref is eventually processed before this - * transaction commits. - */ -int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info, - struct btrfs_trans_handle *trans, - u64 bytenr, u64 num_bytes, u64 parent, - u64 ref_root, int level, int action, - struct btrfs_delayed_extent_op *extent_op) -{ - struct btrfs_delayed_tree_ref *ref; - struct btrfs_delayed_ref_head *head_ref; - struct btrfs_delayed_ref_root *delayed_refs; - struct btrfs_qgroup_extent_record *record = NULL; - - BUG_ON(extent_op && extent_op->is_data); - ref = kmem_cache_alloc(btrfs_delayed_tree_ref_cachep, GFP_NOFS); - if (!ref) - return -ENOMEM; - - head_ref = kmem_cache_alloc(btrfs_delayed_ref_head_cachep, GFP_NOFS); - if (!head_ref) - goto free_ref; - - if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) && - is_fstree(ref_root)) { - record = kmalloc(sizeof(*record), GFP_NOFS); - if (!record) - goto free_head_ref; - } - - head_ref->extent_op = extent_op; - - delayed_refs = &trans->transaction->delayed_refs; - spin_lock(&delayed_refs->lock); - - /* - * insert both the head node and the new ref without dropping - * the spin lock - */ - head_ref = add_delayed_ref_head(fs_info, trans, &head_ref->node, record, - bytenr, num_bytes, 0, 0, action, 0); - - add_delayed_tree_ref(fs_info, trans, head_ref, &ref->node, bytenr, - num_bytes, parent, ref_root, level, action); - spin_unlock(&delayed_refs->lock); - - return 0; - -free_head_ref: - kmem_cache_free(btrfs_delayed_ref_head_cachep, head_ref); -free_ref: - kmem_cache_free(btrfs_delayed_tree_ref_cachep, ref); - - return -ENOMEM; -} - -/* - * add a delayed data ref. it's similar to btrfs_add_delayed_tree_ref. - */ -int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info, - struct btrfs_trans_handle *trans, - u64 bytenr, u64 num_bytes, - u64 parent, u64 ref_root, - u64 owner, u64 offset, u64 reserved, int action, - struct btrfs_delayed_extent_op *extent_op) -{ - struct btrfs_delayed_data_ref *ref; - struct btrfs_delayed_ref_head *head_ref; - struct btrfs_delayed_ref_root *delayed_refs; - struct btrfs_qgroup_extent_record *record = NULL; - - BUG_ON(extent_op && !extent_op->is_data); - ref = kmem_cache_alloc(btrfs_delayed_data_ref_cachep, GFP_NOFS); - if (!ref) - return -ENOMEM; - - head_ref = kmem_cache_alloc(btrfs_delayed_ref_head_cachep, GFP_NOFS); - if (!head_ref) { - kmem_cache_free(btrfs_delayed_data_ref_cachep, ref); - return -ENOMEM; - } - - if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) && - is_fstree(ref_root)) { - record = kmalloc(sizeof(*record), GFP_NOFS); - if (!record) { - kmem_cache_free(btrfs_delayed_data_ref_cachep, ref); - kmem_cache_free(btrfs_delayed_ref_head_cachep, - head_ref); - return -ENOMEM; - } - } - - head_ref->extent_op = extent_op; - - delayed_refs = &trans->transaction->delayed_refs; - spin_lock(&delayed_refs->lock); - - /* - * insert both the head node and the new ref without dropping - * the spin lock - */ - head_ref = add_delayed_ref_head(fs_info, trans, &head_ref->node, record, - bytenr, num_bytes, ref_root, reserved, - action, 1); - - add_delayed_data_ref(fs_info, trans, head_ref, &ref->node, bytenr, - num_bytes, parent, ref_root, owner, offset, - action); - spin_unlock(&delayed_refs->lock); - - return 0; -} - -int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info, - struct btrfs_trans_handle *trans, - u64 bytenr, u64 num_bytes, - struct btrfs_delayed_extent_op *extent_op) -{ - struct btrfs_delayed_ref_head *head_ref; - struct btrfs_delayed_ref_root *delayed_refs; - - head_ref = kmem_cache_alloc(btrfs_delayed_ref_head_cachep, GFP_NOFS); - if (!head_ref) - return -ENOMEM; - - head_ref->extent_op = extent_op; - - delayed_refs = &trans->transaction->delayed_refs; - spin_lock(&delayed_refs->lock); - - add_delayed_ref_head(fs_info, trans, &head_ref->node, NULL, bytenr, - num_bytes, 0, 0, BTRFS_UPDATE_DELAYED_HEAD, - extent_op->is_data); - - spin_unlock(&delayed_refs->lock); - return 0; -} - -/* - * this does a simple search for the head node for a given extent. - * It must be called with the delayed ref spinlock held, and it returns - * the head node if any where found, or NULL if not. - */ -struct btrfs_delayed_ref_head * -btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr) -{ - struct btrfs_delayed_ref_root *delayed_refs; - - delayed_refs = &trans->transaction->delayed_refs; - return find_ref_head(&delayed_refs->href_root, bytenr, 0); -} - -void btrfs_delayed_ref_exit(void) -{ - kmem_cache_destroy(btrfs_delayed_ref_head_cachep); - kmem_cache_destroy(btrfs_delayed_tree_ref_cachep); - kmem_cache_destroy(btrfs_delayed_data_ref_cachep); - kmem_cache_destroy(btrfs_delayed_extent_op_cachep); -} - -int btrfs_delayed_ref_init(void) -{ - btrfs_delayed_ref_head_cachep = kmem_cache_create( - "btrfs_delayed_ref_head", - sizeof(struct btrfs_delayed_ref_head), 0, - SLAB_MEM_SPREAD, NULL); - if (!btrfs_delayed_ref_head_cachep) - goto fail; - - btrfs_delayed_tree_ref_cachep = kmem_cache_create( - "btrfs_delayed_tree_ref", - sizeof(struct btrfs_delayed_tree_ref), 0, - SLAB_MEM_SPREAD, NULL); - if (!btrfs_delayed_tree_ref_cachep) - goto fail; - - btrfs_delayed_data_ref_cachep = kmem_cache_create( - "btrfs_delayed_data_ref", - sizeof(struct btrfs_delayed_data_ref), 0, - SLAB_MEM_SPREAD, NULL); - if (!btrfs_delayed_data_ref_cachep) - goto fail; - - btrfs_delayed_extent_op_cachep = kmem_cache_create( - "btrfs_delayed_extent_op", - sizeof(struct btrfs_delayed_extent_op), 0, - SLAB_MEM_SPREAD, NULL); - if (!btrfs_delayed_extent_op_cachep) - goto fail; - - return 0; -fail: - btrfs_delayed_ref_exit(); - return -ENOMEM; -} diff --git a/src/linux/fs/btrfs/delayed-ref.h b/src/linux/fs/btrfs/delayed-ref.h deleted file mode 100644 index 43f3629..0000000 --- a/src/linux/fs/btrfs/delayed-ref.h +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright (C) 2008 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ -#ifndef __DELAYED_REF__ -#define __DELAYED_REF__ - -/* these are the possible values of struct btrfs_delayed_ref_node->action */ -#define BTRFS_ADD_DELAYED_REF 1 /* add one backref to the tree */ -#define BTRFS_DROP_DELAYED_REF 2 /* delete one backref from the tree */ -#define BTRFS_ADD_DELAYED_EXTENT 3 /* record a full extent allocation */ -#define BTRFS_UPDATE_DELAYED_HEAD 4 /* not changing ref count on head ref */ - -/* - * XXX: Qu: I really hate the design that ref_head and tree/data ref shares the - * same ref_node structure. - * Ref_head is in a higher logic level than tree/data ref, and duplicated - * bytenr/num_bytes in ref_node is really a waste or memory, they should be - * referred from ref_head. - * This gets more disgusting after we use list to store tree/data ref in - * ref_head. Must clean this mess up later. - */ -struct btrfs_delayed_ref_node { - /* - * ref_head use rb tree, stored in ref_root->href. - * indexed by bytenr - */ - struct rb_node rb_node; - - /*data/tree ref use list, stored in ref_head->ref_list. */ - struct list_head list; - - /* the starting bytenr of the extent */ - u64 bytenr; - - /* the size of the extent */ - u64 num_bytes; - - /* seq number to keep track of insertion order */ - u64 seq; - - /* ref count on this data structure */ - atomic_t refs; - - /* - * how many refs is this entry adding or deleting. For - * head refs, this may be a negative number because it is keeping - * track of the total mods done to the reference count. - * For individual refs, this will always be a positive number - * - * It may be more than one, since it is possible for a single - * parent to have more than one ref on an extent - */ - int ref_mod; - - unsigned int action:8; - unsigned int type:8; - /* is this node still in the rbtree? */ - unsigned int is_head:1; - unsigned int in_tree:1; -}; - -struct btrfs_delayed_extent_op { - struct btrfs_disk_key key; - u8 level; - bool update_key; - bool update_flags; - bool is_data; - u64 flags_to_set; -}; - -/* - * the head refs are used to hold a lock on a given extent, which allows us - * to make sure that only one process is running the delayed refs - * at a time for a single extent. They also store the sum of all the - * reference count modifications we've queued up. - */ -struct btrfs_delayed_ref_head { - struct btrfs_delayed_ref_node node; - - /* - * the mutex is held while running the refs, and it is also - * held when checking the sum of reference modifications. - */ - struct mutex mutex; - - spinlock_t lock; - struct list_head ref_list; - - struct rb_node href_node; - - struct btrfs_delayed_extent_op *extent_op; - - /* - * This is used to track the final ref_mod from all the refs associated - * with this head ref, this is not adjusted as delayed refs are run, - * this is meant to track if we need to do the csum accounting or not. - */ - int total_ref_mod; - - /* - * For qgroup reserved space freeing. - * - * ref_root and reserved will be recorded after - * BTRFS_ADD_DELAYED_EXTENT is called. - * And will be used to free reserved qgroup space at - * run_delayed_refs() time. - */ - u64 qgroup_ref_root; - u64 qgroup_reserved; - - /* - * when a new extent is allocated, it is just reserved in memory - * The actual extent isn't inserted into the extent allocation tree - * until the delayed ref is processed. must_insert_reserved is - * used to flag a delayed ref so the accounting can be updated - * when a full insert is done. - * - * It is possible the extent will be freed before it is ever - * inserted into the extent allocation tree. In this case - * we need to update the in ram accounting to properly reflect - * the free has happened. - */ - unsigned int must_insert_reserved:1; - unsigned int is_data:1; - unsigned int processing:1; -}; - -struct btrfs_delayed_tree_ref { - struct btrfs_delayed_ref_node node; - u64 root; - u64 parent; - int level; -}; - -struct btrfs_delayed_data_ref { - struct btrfs_delayed_ref_node node; - u64 root; - u64 parent; - u64 objectid; - u64 offset; -}; - -struct btrfs_delayed_ref_root { - /* head ref rbtree */ - struct rb_root href_root; - - /* dirty extent records */ - struct rb_root dirty_extent_root; - - /* this spin lock protects the rbtree and the entries inside */ - spinlock_t lock; - - /* how many delayed ref updates we've queued, used by the - * throttling code - */ - atomic_t num_entries; - - /* total number of head nodes in tree */ - unsigned long num_heads; - - /* total number of head nodes ready for processing */ - unsigned long num_heads_ready; - - u64 pending_csums; - - /* - * set when the tree is flushing before a transaction commit, - * used by the throttling code to decide if new updates need - * to be run right away - */ - int flushing; - - u64 run_delayed_start; - - /* - * To make qgroup to skip given root. - * This is for snapshot, as btrfs_qgroup_inherit() will manually - * modify counters for snapshot and its source, so we should skip - * the snapshot in new_root/old_roots or it will get calculated twice - */ - u64 qgroup_to_skip; -}; - -extern struct kmem_cache *btrfs_delayed_ref_head_cachep; -extern struct kmem_cache *btrfs_delayed_tree_ref_cachep; -extern struct kmem_cache *btrfs_delayed_data_ref_cachep; -extern struct kmem_cache *btrfs_delayed_extent_op_cachep; - -int btrfs_delayed_ref_init(void); -void btrfs_delayed_ref_exit(void); - -static inline struct btrfs_delayed_extent_op * -btrfs_alloc_delayed_extent_op(void) -{ - return kmem_cache_alloc(btrfs_delayed_extent_op_cachep, GFP_NOFS); -} - -static inline void -btrfs_free_delayed_extent_op(struct btrfs_delayed_extent_op *op) -{ - if (op) - kmem_cache_free(btrfs_delayed_extent_op_cachep, op); -} - -static inline void btrfs_put_delayed_ref(struct btrfs_delayed_ref_node *ref) -{ - WARN_ON(atomic_read(&ref->refs) == 0); - if (atomic_dec_and_test(&ref->refs)) { - WARN_ON(ref->in_tree); - switch (ref->type) { - case BTRFS_TREE_BLOCK_REF_KEY: - case BTRFS_SHARED_BLOCK_REF_KEY: - kmem_cache_free(btrfs_delayed_tree_ref_cachep, ref); - break; - case BTRFS_EXTENT_DATA_REF_KEY: - case BTRFS_SHARED_DATA_REF_KEY: - kmem_cache_free(btrfs_delayed_data_ref_cachep, ref); - break; - case 0: - kmem_cache_free(btrfs_delayed_ref_head_cachep, ref); - break; - default: - BUG(); - } - } -} - -int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info, - struct btrfs_trans_handle *trans, - u64 bytenr, u64 num_bytes, u64 parent, - u64 ref_root, int level, int action, - struct btrfs_delayed_extent_op *extent_op); -int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info, - struct btrfs_trans_handle *trans, - u64 bytenr, u64 num_bytes, - u64 parent, u64 ref_root, - u64 owner, u64 offset, u64 reserved, int action, - struct btrfs_delayed_extent_op *extent_op); -int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info, - struct btrfs_trans_handle *trans, - u64 bytenr, u64 num_bytes, - struct btrfs_delayed_extent_op *extent_op); -void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_delayed_ref_root *delayed_refs, - struct btrfs_delayed_ref_head *head); - -struct btrfs_delayed_ref_head * -btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr); -int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans, - struct btrfs_delayed_ref_head *head); -static inline void btrfs_delayed_ref_unlock(struct btrfs_delayed_ref_head *head) -{ - mutex_unlock(&head->mutex); -} - - -struct btrfs_delayed_ref_head * -btrfs_select_ref_head(struct btrfs_trans_handle *trans); - -int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info, - struct btrfs_delayed_ref_root *delayed_refs, - u64 seq); - -/* - * a node might live in a head or a regular ref, this lets you - * test for the proper type to use. - */ -static int btrfs_delayed_ref_is_head(struct btrfs_delayed_ref_node *node) -{ - return node->is_head; -} - -/* - * helper functions to cast a node into its container - */ -static inline struct btrfs_delayed_tree_ref * -btrfs_delayed_node_to_tree_ref(struct btrfs_delayed_ref_node *node) -{ - WARN_ON(btrfs_delayed_ref_is_head(node)); - return container_of(node, struct btrfs_delayed_tree_ref, node); -} - -static inline struct btrfs_delayed_data_ref * -btrfs_delayed_node_to_data_ref(struct btrfs_delayed_ref_node *node) -{ - WARN_ON(btrfs_delayed_ref_is_head(node)); - return container_of(node, struct btrfs_delayed_data_ref, node); -} - -static inline struct btrfs_delayed_ref_head * -btrfs_delayed_node_to_head(struct btrfs_delayed_ref_node *node) -{ - WARN_ON(!btrfs_delayed_ref_is_head(node)); - return container_of(node, struct btrfs_delayed_ref_head, node); -} -#endif diff --git a/src/linux/fs/btrfs/dev-replace.c b/src/linux/fs/btrfs/dev-replace.c deleted file mode 100644 index 05169ef..0000000 --- a/src/linux/fs/btrfs/dev-replace.c +++ /dev/null @@ -1,942 +0,0 @@ -/* - * Copyright (C) STRATO AG 2012. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ctree.h" -#include "extent_map.h" -#include "disk-io.h" -#include "transaction.h" -#include "print-tree.h" -#include "volumes.h" -#include "async-thread.h" -#include "check-integrity.h" -#include "rcu-string.h" -#include "dev-replace.h" -#include "sysfs.h" - -static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, - int scrub_ret); -static void btrfs_dev_replace_update_device_in_mapping_tree( - struct btrfs_fs_info *fs_info, - struct btrfs_device *srcdev, - struct btrfs_device *tgtdev); -static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info); -static int btrfs_dev_replace_kthread(void *data); -static int btrfs_dev_replace_continue_on_mount(struct btrfs_fs_info *fs_info); - - -int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info) -{ - struct btrfs_key key; - struct btrfs_root *dev_root = fs_info->dev_root; - struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; - struct extent_buffer *eb; - int slot; - int ret = 0; - struct btrfs_path *path = NULL; - int item_size; - struct btrfs_dev_replace_item *ptr; - u64 src_devid; - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - key.objectid = 0; - key.type = BTRFS_DEV_REPLACE_KEY; - key.offset = 0; - ret = btrfs_search_slot(NULL, dev_root, &key, path, 0, 0); - if (ret) { -no_valid_dev_replace_entry_found: - ret = 0; - dev_replace->replace_state = - BTRFS_DEV_REPLACE_ITEM_STATE_NEVER_STARTED; - dev_replace->cont_reading_from_srcdev_mode = - BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_ALWAYS; - dev_replace->replace_state = 0; - dev_replace->time_started = 0; - dev_replace->time_stopped = 0; - atomic64_set(&dev_replace->num_write_errors, 0); - atomic64_set(&dev_replace->num_uncorrectable_read_errors, 0); - dev_replace->cursor_left = 0; - dev_replace->committed_cursor_left = 0; - dev_replace->cursor_left_last_write_of_item = 0; - dev_replace->cursor_right = 0; - dev_replace->srcdev = NULL; - dev_replace->tgtdev = NULL; - dev_replace->is_valid = 0; - dev_replace->item_needs_writeback = 0; - goto out; - } - slot = path->slots[0]; - eb = path->nodes[0]; - item_size = btrfs_item_size_nr(eb, slot); - ptr = btrfs_item_ptr(eb, slot, struct btrfs_dev_replace_item); - - if (item_size != sizeof(struct btrfs_dev_replace_item)) { - btrfs_warn(fs_info, - "dev_replace entry found has unexpected size, ignore entry"); - goto no_valid_dev_replace_entry_found; - } - - src_devid = btrfs_dev_replace_src_devid(eb, ptr); - dev_replace->cont_reading_from_srcdev_mode = - btrfs_dev_replace_cont_reading_from_srcdev_mode(eb, ptr); - dev_replace->replace_state = btrfs_dev_replace_replace_state(eb, ptr); - dev_replace->time_started = btrfs_dev_replace_time_started(eb, ptr); - dev_replace->time_stopped = - btrfs_dev_replace_time_stopped(eb, ptr); - atomic64_set(&dev_replace->num_write_errors, - btrfs_dev_replace_num_write_errors(eb, ptr)); - atomic64_set(&dev_replace->num_uncorrectable_read_errors, - btrfs_dev_replace_num_uncorrectable_read_errors(eb, ptr)); - dev_replace->cursor_left = btrfs_dev_replace_cursor_left(eb, ptr); - dev_replace->committed_cursor_left = dev_replace->cursor_left; - dev_replace->cursor_left_last_write_of_item = dev_replace->cursor_left; - dev_replace->cursor_right = btrfs_dev_replace_cursor_right(eb, ptr); - dev_replace->is_valid = 1; - - dev_replace->item_needs_writeback = 0; - switch (dev_replace->replace_state) { - case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: - dev_replace->srcdev = NULL; - dev_replace->tgtdev = NULL; - break; - case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: - dev_replace->srcdev = btrfs_find_device(fs_info, src_devid, - NULL, NULL); - dev_replace->tgtdev = btrfs_find_device(fs_info, - BTRFS_DEV_REPLACE_DEVID, - NULL, NULL); - /* - * allow 'btrfs dev replace_cancel' if src/tgt device is - * missing - */ - if (!dev_replace->srcdev && - !btrfs_test_opt(dev_root->fs_info, DEGRADED)) { - ret = -EIO; - btrfs_warn(fs_info, - "cannot mount because device replace operation is ongoing and"); - btrfs_warn(fs_info, - "srcdev (devid %llu) is missing, need to run 'btrfs dev scan'?", - src_devid); - } - if (!dev_replace->tgtdev && - !btrfs_test_opt(dev_root->fs_info, DEGRADED)) { - ret = -EIO; - btrfs_warn(fs_info, - "cannot mount because device replace operation is ongoing and"); - btrfs_warn(fs_info, - "tgtdev (devid %llu) is missing, need to run 'btrfs dev scan'?", - BTRFS_DEV_REPLACE_DEVID); - } - if (dev_replace->tgtdev) { - if (dev_replace->srcdev) { - dev_replace->tgtdev->total_bytes = - dev_replace->srcdev->total_bytes; - dev_replace->tgtdev->disk_total_bytes = - dev_replace->srcdev->disk_total_bytes; - dev_replace->tgtdev->commit_total_bytes = - dev_replace->srcdev->commit_total_bytes; - dev_replace->tgtdev->bytes_used = - dev_replace->srcdev->bytes_used; - dev_replace->tgtdev->commit_bytes_used = - dev_replace->srcdev->commit_bytes_used; - } - dev_replace->tgtdev->is_tgtdev_for_dev_replace = 1; - btrfs_init_dev_replace_tgtdev_for_resume(fs_info, - dev_replace->tgtdev); - } - break; - } - -out: - btrfs_free_path(path); - return ret; -} - -/* - * called from commit_transaction. Writes changed device replace state to - * disk. - */ -int btrfs_run_dev_replace(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info) -{ - int ret; - struct btrfs_root *dev_root = fs_info->dev_root; - struct btrfs_path *path; - struct btrfs_key key; - struct extent_buffer *eb; - struct btrfs_dev_replace_item *ptr; - struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; - - btrfs_dev_replace_lock(dev_replace, 0); - if (!dev_replace->is_valid || - !dev_replace->item_needs_writeback) { - btrfs_dev_replace_unlock(dev_replace, 0); - return 0; - } - btrfs_dev_replace_unlock(dev_replace, 0); - - key.objectid = 0; - key.type = BTRFS_DEV_REPLACE_KEY; - key.offset = 0; - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - ret = btrfs_search_slot(trans, dev_root, &key, path, -1, 1); - if (ret < 0) { - btrfs_warn(fs_info, - "error %d while searching for dev_replace item!", - ret); - goto out; - } - - if (ret == 0 && - btrfs_item_size_nr(path->nodes[0], path->slots[0]) < sizeof(*ptr)) { - /* - * need to delete old one and insert a new one. - * Since no attempt is made to recover any old state, if the - * dev_replace state is 'running', the data on the target - * drive is lost. - * It would be possible to recover the state: just make sure - * that the beginning of the item is never changed and always - * contains all the essential information. Then read this - * minimal set of information and use it as a base for the - * new state. - */ - ret = btrfs_del_item(trans, dev_root, path); - if (ret != 0) { - btrfs_warn(fs_info, - "delete too small dev_replace item failed %d!", - ret); - goto out; - } - ret = 1; - } - - if (ret == 1) { - /* need to insert a new item */ - btrfs_release_path(path); - ret = btrfs_insert_empty_item(trans, dev_root, path, - &key, sizeof(*ptr)); - if (ret < 0) { - btrfs_warn(fs_info, - "insert dev_replace item failed %d!", ret); - goto out; - } - } - - eb = path->nodes[0]; - ptr = btrfs_item_ptr(eb, path->slots[0], - struct btrfs_dev_replace_item); - - btrfs_dev_replace_lock(dev_replace, 1); - if (dev_replace->srcdev) - btrfs_set_dev_replace_src_devid(eb, ptr, - dev_replace->srcdev->devid); - else - btrfs_set_dev_replace_src_devid(eb, ptr, (u64)-1); - btrfs_set_dev_replace_cont_reading_from_srcdev_mode(eb, ptr, - dev_replace->cont_reading_from_srcdev_mode); - btrfs_set_dev_replace_replace_state(eb, ptr, - dev_replace->replace_state); - btrfs_set_dev_replace_time_started(eb, ptr, dev_replace->time_started); - btrfs_set_dev_replace_time_stopped(eb, ptr, dev_replace->time_stopped); - btrfs_set_dev_replace_num_write_errors(eb, ptr, - atomic64_read(&dev_replace->num_write_errors)); - btrfs_set_dev_replace_num_uncorrectable_read_errors(eb, ptr, - atomic64_read(&dev_replace->num_uncorrectable_read_errors)); - dev_replace->cursor_left_last_write_of_item = - dev_replace->cursor_left; - btrfs_set_dev_replace_cursor_left(eb, ptr, - dev_replace->cursor_left_last_write_of_item); - btrfs_set_dev_replace_cursor_right(eb, ptr, - dev_replace->cursor_right); - dev_replace->item_needs_writeback = 0; - btrfs_dev_replace_unlock(dev_replace, 1); - - btrfs_mark_buffer_dirty(eb); - -out: - btrfs_free_path(path); - - return ret; -} - -void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info) -{ - struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; - - dev_replace->committed_cursor_left = - dev_replace->cursor_left_last_write_of_item; -} - -int btrfs_dev_replace_start(struct btrfs_root *root, char *tgtdev_name, - u64 srcdevid, char *srcdev_name, int read_src) -{ - struct btrfs_trans_handle *trans; - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; - int ret; - struct btrfs_device *tgt_device = NULL; - struct btrfs_device *src_device = NULL; - - /* the disk copy procedure reuses the scrub code */ - mutex_lock(&fs_info->volume_mutex); - ret = btrfs_find_device_by_devspec(root, srcdevid, - srcdev_name, &src_device); - if (ret) { - mutex_unlock(&fs_info->volume_mutex); - return ret; - } - - ret = btrfs_init_dev_replace_tgtdev(root, tgtdev_name, - src_device, &tgt_device); - mutex_unlock(&fs_info->volume_mutex); - if (ret) - return ret; - - /* - * Here we commit the transaction to make sure commit_total_bytes - * of all the devices are updated. - */ - trans = btrfs_attach_transaction(root); - if (!IS_ERR(trans)) { - ret = btrfs_commit_transaction(trans, root); - if (ret) - return ret; - } else if (PTR_ERR(trans) != -ENOENT) { - return PTR_ERR(trans); - } - - btrfs_dev_replace_lock(dev_replace, 1); - switch (dev_replace->replace_state) { - case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: - break; - case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: - ret = BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED; - goto leave; - } - - dev_replace->cont_reading_from_srcdev_mode = read_src; - WARN_ON(!src_device); - dev_replace->srcdev = src_device; - WARN_ON(!tgt_device); - dev_replace->tgtdev = tgt_device; - - btrfs_info_in_rcu(fs_info, - "dev_replace from %s (devid %llu) to %s started", - src_device->missing ? "" : - rcu_str_deref(src_device->name), - src_device->devid, - rcu_str_deref(tgt_device->name)); - - /* - * from now on, the writes to the srcdev are all duplicated to - * go to the tgtdev as well (refer to btrfs_map_block()). - */ - dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED; - dev_replace->time_started = get_seconds(); - dev_replace->cursor_left = 0; - dev_replace->committed_cursor_left = 0; - dev_replace->cursor_left_last_write_of_item = 0; - dev_replace->cursor_right = 0; - dev_replace->is_valid = 1; - dev_replace->item_needs_writeback = 1; - atomic64_set(&dev_replace->num_write_errors, 0); - atomic64_set(&dev_replace->num_uncorrectable_read_errors, 0); - btrfs_dev_replace_unlock(dev_replace, 1); - - ret = btrfs_sysfs_add_device_link(tgt_device->fs_devices, tgt_device); - if (ret) - btrfs_err(fs_info, "kobj add dev failed %d", ret); - - btrfs_wait_ordered_roots(root->fs_info, -1, 0, (u64)-1); - - /* force writing the updated state information to disk */ - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - btrfs_dev_replace_lock(dev_replace, 1); - goto leave; - } - - ret = btrfs_commit_transaction(trans, root); - WARN_ON(ret); - - /* the disk copy procedure reuses the scrub code */ - ret = btrfs_scrub_dev(fs_info, src_device->devid, 0, - btrfs_device_get_total_bytes(src_device), - &dev_replace->scrub_progress, 0, 1); - - ret = btrfs_dev_replace_finishing(fs_info, ret); - if (ret == -EINPROGRESS) { - ret = BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS; - } else { - WARN_ON(ret); - } - - return ret; - -leave: - dev_replace->srcdev = NULL; - dev_replace->tgtdev = NULL; - btrfs_dev_replace_unlock(dev_replace, 1); - btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device); - return ret; -} - -int btrfs_dev_replace_by_ioctl(struct btrfs_root *root, - struct btrfs_ioctl_dev_replace_args *args) -{ - int ret; - - switch (args->start.cont_reading_from_srcdev_mode) { - case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS: - case BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID: - break; - default: - return -EINVAL; - } - - if ((args->start.srcdevid == 0 && args->start.srcdev_name[0] == '\0') || - args->start.tgtdev_name[0] == '\0') - return -EINVAL; - - ret = btrfs_dev_replace_start(root, args->start.tgtdev_name, - args->start.srcdevid, - args->start.srcdev_name, - args->start.cont_reading_from_srcdev_mode); - args->result = ret; - /* don't warn if EINPROGRESS, someone else might be running scrub */ - if (ret == BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS) - ret = 0; - - return ret; -} - -/* - * blocked until all in-flight bios operations are finished. - */ -static void btrfs_rm_dev_replace_blocked(struct btrfs_fs_info *fs_info) -{ - set_bit(BTRFS_FS_STATE_DEV_REPLACING, &fs_info->fs_state); - wait_event(fs_info->replace_wait, !percpu_counter_sum( - &fs_info->bio_counter)); -} - -/* - * we have removed target device, it is safe to allow new bios request. - */ -static void btrfs_rm_dev_replace_unblocked(struct btrfs_fs_info *fs_info) -{ - clear_bit(BTRFS_FS_STATE_DEV_REPLACING, &fs_info->fs_state); - wake_up(&fs_info->replace_wait); -} - -static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info, - int scrub_ret) -{ - struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; - struct btrfs_device *tgt_device; - struct btrfs_device *src_device; - struct btrfs_root *root = fs_info->tree_root; - u8 uuid_tmp[BTRFS_UUID_SIZE]; - struct btrfs_trans_handle *trans; - int ret = 0; - - /* don't allow cancel or unmount to disturb the finishing procedure */ - mutex_lock(&dev_replace->lock_finishing_cancel_unmount); - - btrfs_dev_replace_lock(dev_replace, 0); - /* was the operation canceled, or is it finished? */ - if (dev_replace->replace_state != - BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED) { - btrfs_dev_replace_unlock(dev_replace, 0); - mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); - return 0; - } - - tgt_device = dev_replace->tgtdev; - src_device = dev_replace->srcdev; - btrfs_dev_replace_unlock(dev_replace, 0); - - /* - * flush all outstanding I/O and inode extent mappings before the - * copy operation is declared as being finished - */ - ret = btrfs_start_delalloc_roots(root->fs_info, 0, -1); - if (ret) { - mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); - return ret; - } - btrfs_wait_ordered_roots(root->fs_info, -1, 0, (u64)-1); - - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) { - mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); - return PTR_ERR(trans); - } - ret = btrfs_commit_transaction(trans, root); - WARN_ON(ret); - - mutex_lock(&uuid_mutex); - /* keep away write_all_supers() during the finishing procedure */ - mutex_lock(&root->fs_info->fs_devices->device_list_mutex); - mutex_lock(&root->fs_info->chunk_mutex); - btrfs_dev_replace_lock(dev_replace, 1); - dev_replace->replace_state = - scrub_ret ? BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED - : BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED; - dev_replace->tgtdev = NULL; - dev_replace->srcdev = NULL; - dev_replace->time_stopped = get_seconds(); - dev_replace->item_needs_writeback = 1; - - /* replace old device with new one in mapping tree */ - if (!scrub_ret) { - btrfs_dev_replace_update_device_in_mapping_tree(fs_info, - src_device, - tgt_device); - } else { - btrfs_err_in_rcu(root->fs_info, - "btrfs_scrub_dev(%s, %llu, %s) failed %d", - src_device->missing ? "" : - rcu_str_deref(src_device->name), - src_device->devid, - rcu_str_deref(tgt_device->name), scrub_ret); - btrfs_dev_replace_unlock(dev_replace, 1); - mutex_unlock(&root->fs_info->chunk_mutex); - mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); - mutex_unlock(&uuid_mutex); - if (tgt_device) - btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device); - mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); - - return scrub_ret; - } - - btrfs_info_in_rcu(root->fs_info, - "dev_replace from %s (devid %llu) to %s finished", - src_device->missing ? "" : - rcu_str_deref(src_device->name), - src_device->devid, - rcu_str_deref(tgt_device->name)); - tgt_device->is_tgtdev_for_dev_replace = 0; - tgt_device->devid = src_device->devid; - src_device->devid = BTRFS_DEV_REPLACE_DEVID; - memcpy(uuid_tmp, tgt_device->uuid, sizeof(uuid_tmp)); - memcpy(tgt_device->uuid, src_device->uuid, sizeof(tgt_device->uuid)); - memcpy(src_device->uuid, uuid_tmp, sizeof(src_device->uuid)); - btrfs_device_set_total_bytes(tgt_device, src_device->total_bytes); - btrfs_device_set_disk_total_bytes(tgt_device, - src_device->disk_total_bytes); - btrfs_device_set_bytes_used(tgt_device, src_device->bytes_used); - ASSERT(list_empty(&src_device->resized_list)); - tgt_device->commit_total_bytes = src_device->commit_total_bytes; - tgt_device->commit_bytes_used = src_device->bytes_used; - - btrfs_assign_next_active_device(fs_info, src_device, tgt_device); - - list_add(&tgt_device->dev_alloc_list, &fs_info->fs_devices->alloc_list); - fs_info->fs_devices->rw_devices++; - - btrfs_dev_replace_unlock(dev_replace, 1); - - btrfs_rm_dev_replace_blocked(fs_info); - - btrfs_rm_dev_replace_remove_srcdev(fs_info, src_device); - - btrfs_rm_dev_replace_unblocked(fs_info); - - /* - * this is again a consistent state where no dev_replace procedure - * is running, the target device is part of the filesystem, the - * source device is not part of the filesystem anymore and its 1st - * superblock is scratched out so that it is no longer marked to - * belong to this filesystem. - */ - mutex_unlock(&root->fs_info->chunk_mutex); - mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); - mutex_unlock(&uuid_mutex); - - /* replace the sysfs entry */ - btrfs_sysfs_rm_device_link(fs_info->fs_devices, src_device); - btrfs_rm_dev_replace_free_srcdev(fs_info, src_device); - - /* write back the superblocks */ - trans = btrfs_start_transaction(root, 0); - if (!IS_ERR(trans)) - btrfs_commit_transaction(trans, root); - - mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); - - return 0; -} - -static void btrfs_dev_replace_update_device_in_mapping_tree( - struct btrfs_fs_info *fs_info, - struct btrfs_device *srcdev, - struct btrfs_device *tgtdev) -{ - struct extent_map_tree *em_tree = &fs_info->mapping_tree.map_tree; - struct extent_map *em; - struct map_lookup *map; - u64 start = 0; - int i; - - write_lock(&em_tree->lock); - do { - em = lookup_extent_mapping(em_tree, start, (u64)-1); - if (!em) - break; - map = em->map_lookup; - for (i = 0; i < map->num_stripes; i++) - if (srcdev == map->stripes[i].dev) - map->stripes[i].dev = tgtdev; - start = em->start + em->len; - free_extent_map(em); - } while (start); - write_unlock(&em_tree->lock); -} - -void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info, - struct btrfs_ioctl_dev_replace_args *args) -{ - struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; - struct btrfs_device *srcdev; - - btrfs_dev_replace_lock(dev_replace, 0); - /* even if !dev_replace_is_valid, the values are good enough for - * the replace_status ioctl */ - args->result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR; - args->status.replace_state = dev_replace->replace_state; - args->status.time_started = dev_replace->time_started; - args->status.time_stopped = dev_replace->time_stopped; - args->status.num_write_errors = - atomic64_read(&dev_replace->num_write_errors); - args->status.num_uncorrectable_read_errors = - atomic64_read(&dev_replace->num_uncorrectable_read_errors); - switch (dev_replace->replace_state) { - case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: - args->status.progress_1000 = 0; - break; - case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: - args->status.progress_1000 = 1000; - break; - case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: - srcdev = dev_replace->srcdev; - args->status.progress_1000 = div_u64(dev_replace->cursor_left, - div_u64(btrfs_device_get_total_bytes(srcdev), 1000)); - break; - } - btrfs_dev_replace_unlock(dev_replace, 0); -} - -int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info, - struct btrfs_ioctl_dev_replace_args *args) -{ - args->result = __btrfs_dev_replace_cancel(fs_info); - return 0; -} - -static u64 __btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info) -{ - struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; - struct btrfs_device *tgt_device = NULL; - struct btrfs_trans_handle *trans; - struct btrfs_root *root = fs_info->tree_root; - u64 result; - int ret; - - if (fs_info->sb->s_flags & MS_RDONLY) - return -EROFS; - - mutex_lock(&dev_replace->lock_finishing_cancel_unmount); - btrfs_dev_replace_lock(dev_replace, 1); - switch (dev_replace->replace_state) { - case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: - result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NOT_STARTED; - btrfs_dev_replace_unlock(dev_replace, 1); - goto leave; - case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: - result = BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR; - tgt_device = dev_replace->tgtdev; - dev_replace->tgtdev = NULL; - dev_replace->srcdev = NULL; - break; - } - dev_replace->replace_state = BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED; - dev_replace->time_stopped = get_seconds(); - dev_replace->item_needs_writeback = 1; - btrfs_dev_replace_unlock(dev_replace, 1); - btrfs_scrub_cancel(fs_info); - - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) { - mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); - return PTR_ERR(trans); - } - ret = btrfs_commit_transaction(trans, root); - WARN_ON(ret); - if (tgt_device) - btrfs_destroy_dev_replace_tgtdev(fs_info, tgt_device); - -leave: - mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); - return result; -} - -void btrfs_dev_replace_suspend_for_unmount(struct btrfs_fs_info *fs_info) -{ - struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; - - mutex_lock(&dev_replace->lock_finishing_cancel_unmount); - btrfs_dev_replace_lock(dev_replace, 1); - switch (dev_replace->replace_state) { - case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: - break; - case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: - dev_replace->replace_state = - BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED; - dev_replace->time_stopped = get_seconds(); - dev_replace->item_needs_writeback = 1; - btrfs_info(fs_info, "suspending dev_replace for unmount"); - break; - } - - btrfs_dev_replace_unlock(dev_replace, 1); - mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); -} - -/* resume dev_replace procedure that was interrupted by unmount */ -int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info) -{ - struct task_struct *task; - struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; - - btrfs_dev_replace_lock(dev_replace, 1); - switch (dev_replace->replace_state) { - case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: - btrfs_dev_replace_unlock(dev_replace, 1); - return 0; - case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: - break; - case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: - dev_replace->replace_state = - BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED; - break; - } - if (!dev_replace->tgtdev || !dev_replace->tgtdev->bdev) { - btrfs_info(fs_info, - "cannot continue dev_replace, tgtdev is missing"); - btrfs_info(fs_info, - "you may cancel the operation after 'mount -o degraded'"); - btrfs_dev_replace_unlock(dev_replace, 1); - return 0; - } - btrfs_dev_replace_unlock(dev_replace, 1); - - WARN_ON(atomic_xchg( - &fs_info->mutually_exclusive_operation_running, 1)); - task = kthread_run(btrfs_dev_replace_kthread, fs_info, "btrfs-devrepl"); - return PTR_ERR_OR_ZERO(task); -} - -static int btrfs_dev_replace_kthread(void *data) -{ - struct btrfs_fs_info *fs_info = data; - struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; - struct btrfs_ioctl_dev_replace_args *status_args; - u64 progress; - - status_args = kzalloc(sizeof(*status_args), GFP_KERNEL); - if (status_args) { - btrfs_dev_replace_status(fs_info, status_args); - progress = status_args->status.progress_1000; - kfree(status_args); - progress = div_u64(progress, 10); - btrfs_info_in_rcu(fs_info, - "continuing dev_replace from %s (devid %llu) to %s @%u%%", - dev_replace->srcdev->missing ? "" : - rcu_str_deref(dev_replace->srcdev->name), - dev_replace->srcdev->devid, - dev_replace->tgtdev ? - rcu_str_deref(dev_replace->tgtdev->name) : - "", - (unsigned int)progress); - } - btrfs_dev_replace_continue_on_mount(fs_info); - atomic_set(&fs_info->mutually_exclusive_operation_running, 0); - - return 0; -} - -static int btrfs_dev_replace_continue_on_mount(struct btrfs_fs_info *fs_info) -{ - struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; - int ret; - - ret = btrfs_scrub_dev(fs_info, dev_replace->srcdev->devid, - dev_replace->committed_cursor_left, - btrfs_device_get_total_bytes(dev_replace->srcdev), - &dev_replace->scrub_progress, 0, 1); - ret = btrfs_dev_replace_finishing(fs_info, ret); - WARN_ON(ret); - return 0; -} - -int btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace) -{ - if (!dev_replace->is_valid) - return 0; - - switch (dev_replace->replace_state) { - case BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED: - return 0; - case BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED: - case BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED: - /* - * return true even if tgtdev is missing (this is - * something that can happen if the dev_replace - * procedure is suspended by an umount and then - * the tgtdev is missing (or "btrfs dev scan") was - * not called and the the filesystem is remounted - * in degraded state. This does not stop the - * dev_replace procedure. It needs to be canceled - * manually if the cancellation is wanted. - */ - break; - } - return 1; -} - -void btrfs_dev_replace_lock(struct btrfs_dev_replace *dev_replace, int rw) -{ - if (rw == 1) { - /* write */ -again: - wait_event(dev_replace->read_lock_wq, - atomic_read(&dev_replace->blocking_readers) == 0); - write_lock(&dev_replace->lock); - if (atomic_read(&dev_replace->blocking_readers)) { - write_unlock(&dev_replace->lock); - goto again; - } - } else { - read_lock(&dev_replace->lock); - atomic_inc(&dev_replace->read_locks); - } -} - -void btrfs_dev_replace_unlock(struct btrfs_dev_replace *dev_replace, int rw) -{ - if (rw == 1) { - /* write */ - ASSERT(atomic_read(&dev_replace->blocking_readers) == 0); - write_unlock(&dev_replace->lock); - } else { - ASSERT(atomic_read(&dev_replace->read_locks) > 0); - atomic_dec(&dev_replace->read_locks); - read_unlock(&dev_replace->lock); - } -} - -/* inc blocking cnt and release read lock */ -void btrfs_dev_replace_set_lock_blocking( - struct btrfs_dev_replace *dev_replace) -{ - /* only set blocking for read lock */ - ASSERT(atomic_read(&dev_replace->read_locks) > 0); - atomic_inc(&dev_replace->blocking_readers); - read_unlock(&dev_replace->lock); -} - -/* acquire read lock and dec blocking cnt */ -void btrfs_dev_replace_clear_lock_blocking( - struct btrfs_dev_replace *dev_replace) -{ - /* only set blocking for read lock */ - ASSERT(atomic_read(&dev_replace->read_locks) > 0); - ASSERT(atomic_read(&dev_replace->blocking_readers) > 0); - read_lock(&dev_replace->lock); - if (atomic_dec_and_test(&dev_replace->blocking_readers) && - waitqueue_active(&dev_replace->read_lock_wq)) - wake_up(&dev_replace->read_lock_wq); -} - -void btrfs_bio_counter_inc_noblocked(struct btrfs_fs_info *fs_info) -{ - percpu_counter_inc(&fs_info->bio_counter); -} - -void btrfs_bio_counter_sub(struct btrfs_fs_info *fs_info, s64 amount) -{ - percpu_counter_sub(&fs_info->bio_counter, amount); - - if (waitqueue_active(&fs_info->replace_wait)) - wake_up(&fs_info->replace_wait); -} - -void btrfs_bio_counter_inc_blocked(struct btrfs_fs_info *fs_info) -{ - while (1) { - percpu_counter_inc(&fs_info->bio_counter); - if (likely(!test_bit(BTRFS_FS_STATE_DEV_REPLACING, - &fs_info->fs_state))) - break; - - btrfs_bio_counter_dec(fs_info); - wait_event(fs_info->replace_wait, - !test_bit(BTRFS_FS_STATE_DEV_REPLACING, - &fs_info->fs_state)); - } -} diff --git a/src/linux/fs/btrfs/dev-replace.h b/src/linux/fs/btrfs/dev-replace.h deleted file mode 100644 index e922b42..0000000 --- a/src/linux/fs/btrfs/dev-replace.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) STRATO AG 2012. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#if !defined(__BTRFS_DEV_REPLACE__) -#define __BTRFS_DEV_REPLACE__ - -struct btrfs_ioctl_dev_replace_args; - -int btrfs_init_dev_replace(struct btrfs_fs_info *fs_info); -int btrfs_run_dev_replace(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info); -void btrfs_after_dev_replace_commit(struct btrfs_fs_info *fs_info); -int btrfs_dev_replace_by_ioctl(struct btrfs_root *root, - struct btrfs_ioctl_dev_replace_args *args); -int btrfs_dev_replace_start(struct btrfs_root *root, char *tgtdev_name, - u64 srcdevid, char *srcdev_name, int read_src); -void btrfs_dev_replace_status(struct btrfs_fs_info *fs_info, - struct btrfs_ioctl_dev_replace_args *args); -int btrfs_dev_replace_cancel(struct btrfs_fs_info *fs_info, - struct btrfs_ioctl_dev_replace_args *args); -void btrfs_dev_replace_suspend_for_unmount(struct btrfs_fs_info *fs_info); -int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info); -int btrfs_dev_replace_is_ongoing(struct btrfs_dev_replace *dev_replace); -void btrfs_dev_replace_lock(struct btrfs_dev_replace *dev_replace, int rw); -void btrfs_dev_replace_unlock(struct btrfs_dev_replace *dev_replace, int rw); -void btrfs_dev_replace_set_lock_blocking(struct btrfs_dev_replace *dev_replace); -void btrfs_dev_replace_clear_lock_blocking( - struct btrfs_dev_replace *dev_replace); - -static inline void btrfs_dev_replace_stats_inc(atomic64_t *stat_value) -{ - atomic64_inc(stat_value); -} -#endif diff --git a/src/linux/fs/btrfs/dir-item.c b/src/linux/fs/btrfs/dir-item.c deleted file mode 100644 index 0dc1a03..0000000 --- a/src/linux/fs/btrfs/dir-item.c +++ /dev/null @@ -1,483 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include "ctree.h" -#include "disk-io.h" -#include "hash.h" -#include "transaction.h" - -/* - * insert a name into a directory, doing overflow properly if there is a hash - * collision. data_size indicates how big the item inserted should be. On - * success a struct btrfs_dir_item pointer is returned, otherwise it is - * an ERR_PTR. - * - * The name is not copied into the dir item, you have to do that yourself. - */ -static struct btrfs_dir_item *insert_with_overflow(struct btrfs_trans_handle - *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_key *cpu_key, - u32 data_size, - const char *name, - int name_len) -{ - int ret; - char *ptr; - struct btrfs_item *item; - struct extent_buffer *leaf; - - ret = btrfs_insert_empty_item(trans, root, path, cpu_key, data_size); - if (ret == -EEXIST) { - struct btrfs_dir_item *di; - di = btrfs_match_dir_item_name(root, path, name, name_len); - if (di) - return ERR_PTR(-EEXIST); - btrfs_extend_item(root, path, data_size); - } else if (ret < 0) - return ERR_PTR(ret); - WARN_ON(ret > 0); - leaf = path->nodes[0]; - item = btrfs_item_nr(path->slots[0]); - ptr = btrfs_item_ptr(leaf, path->slots[0], char); - BUG_ON(data_size > btrfs_item_size(leaf, item)); - ptr += btrfs_item_size(leaf, item) - data_size; - return (struct btrfs_dir_item *)ptr; -} - -/* - * xattrs work a lot like directories, this inserts an xattr item - * into the tree - */ -int btrfs_insert_xattr_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, u64 objectid, - const char *name, u16 name_len, - const void *data, u16 data_len) -{ - int ret = 0; - struct btrfs_dir_item *dir_item; - unsigned long name_ptr, data_ptr; - struct btrfs_key key, location; - struct btrfs_disk_key disk_key; - struct extent_buffer *leaf; - u32 data_size; - - BUG_ON(name_len + data_len > BTRFS_MAX_XATTR_SIZE(root)); - - key.objectid = objectid; - key.type = BTRFS_XATTR_ITEM_KEY; - key.offset = btrfs_name_hash(name, name_len); - - data_size = sizeof(*dir_item) + name_len + data_len; - dir_item = insert_with_overflow(trans, root, path, &key, data_size, - name, name_len); - if (IS_ERR(dir_item)) - return PTR_ERR(dir_item); - memset(&location, 0, sizeof(location)); - - leaf = path->nodes[0]; - btrfs_cpu_key_to_disk(&disk_key, &location); - btrfs_set_dir_item_key(leaf, dir_item, &disk_key); - btrfs_set_dir_type(leaf, dir_item, BTRFS_FT_XATTR); - btrfs_set_dir_name_len(leaf, dir_item, name_len); - btrfs_set_dir_transid(leaf, dir_item, trans->transid); - btrfs_set_dir_data_len(leaf, dir_item, data_len); - name_ptr = (unsigned long)(dir_item + 1); - data_ptr = (unsigned long)((char *)name_ptr + name_len); - - write_extent_buffer(leaf, name, name_ptr, name_len); - write_extent_buffer(leaf, data, data_ptr, data_len); - btrfs_mark_buffer_dirty(path->nodes[0]); - - return ret; -} - -/* - * insert a directory item in the tree, doing all the magic for - * both indexes. 'dir' indicates which objectid to insert it into, - * 'location' is the key to stuff into the directory item, 'type' is the - * type of the inode we're pointing to, and 'index' is the sequence number - * to use for the second index (if one is created). - * Will return 0 or -ENOMEM - */ -int btrfs_insert_dir_item(struct btrfs_trans_handle *trans, struct btrfs_root - *root, const char *name, int name_len, - struct inode *dir, struct btrfs_key *location, - u8 type, u64 index) -{ - int ret = 0; - int ret2 = 0; - struct btrfs_path *path; - struct btrfs_dir_item *dir_item; - struct extent_buffer *leaf; - unsigned long name_ptr; - struct btrfs_key key; - struct btrfs_disk_key disk_key; - u32 data_size; - - key.objectid = btrfs_ino(dir); - key.type = BTRFS_DIR_ITEM_KEY; - key.offset = btrfs_name_hash(name, name_len); - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->leave_spinning = 1; - - btrfs_cpu_key_to_disk(&disk_key, location); - - data_size = sizeof(*dir_item) + name_len; - dir_item = insert_with_overflow(trans, root, path, &key, data_size, - name, name_len); - if (IS_ERR(dir_item)) { - ret = PTR_ERR(dir_item); - if (ret == -EEXIST) - goto second_insert; - goto out_free; - } - - leaf = path->nodes[0]; - btrfs_set_dir_item_key(leaf, dir_item, &disk_key); - btrfs_set_dir_type(leaf, dir_item, type); - btrfs_set_dir_data_len(leaf, dir_item, 0); - btrfs_set_dir_name_len(leaf, dir_item, name_len); - btrfs_set_dir_transid(leaf, dir_item, trans->transid); - name_ptr = (unsigned long)(dir_item + 1); - - write_extent_buffer(leaf, name, name_ptr, name_len); - btrfs_mark_buffer_dirty(leaf); - -second_insert: - /* FIXME, use some real flag for selecting the extra index */ - if (root == root->fs_info->tree_root) { - ret = 0; - goto out_free; - } - btrfs_release_path(path); - - ret2 = btrfs_insert_delayed_dir_index(trans, root, name, name_len, dir, - &disk_key, type, index); -out_free: - btrfs_free_path(path); - if (ret) - return ret; - if (ret2) - return ret2; - return 0; -} - -/* - * lookup a directory item based on name. 'dir' is the objectid - * we're searching in, and 'mod' tells us if you plan on deleting the - * item (use mod < 0) or changing the options (use mod > 0) - */ -struct btrfs_dir_item *btrfs_lookup_dir_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, u64 dir, - const char *name, int name_len, - int mod) -{ - int ret; - struct btrfs_key key; - int ins_len = mod < 0 ? -1 : 0; - int cow = mod != 0; - - key.objectid = dir; - key.type = BTRFS_DIR_ITEM_KEY; - - key.offset = btrfs_name_hash(name, name_len); - - ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); - if (ret < 0) - return ERR_PTR(ret); - if (ret > 0) - return NULL; - - return btrfs_match_dir_item_name(root, path, name, name_len); -} - -int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir, - const char *name, int name_len) -{ - int ret; - struct btrfs_key key; - struct btrfs_dir_item *di; - int data_size; - struct extent_buffer *leaf; - int slot; - struct btrfs_path *path; - - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - key.objectid = dir; - key.type = BTRFS_DIR_ITEM_KEY; - key.offset = btrfs_name_hash(name, name_len); - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - - /* return back any errors */ - if (ret < 0) - goto out; - - /* nothing found, we're safe */ - if (ret > 0) { - ret = 0; - goto out; - } - - /* we found an item, look for our name in the item */ - di = btrfs_match_dir_item_name(root, path, name, name_len); - if (di) { - /* our exact name was found */ - ret = -EEXIST; - goto out; - } - - /* - * see if there is room in the item to insert this - * name - */ - data_size = sizeof(*di) + name_len; - leaf = path->nodes[0]; - slot = path->slots[0]; - if (data_size + btrfs_item_size_nr(leaf, slot) + - sizeof(struct btrfs_item) > BTRFS_LEAF_DATA_SIZE(root)) { - ret = -EOVERFLOW; - } else { - /* plenty of insertion room */ - ret = 0; - } -out: - btrfs_free_path(path); - return ret; -} - -/* - * lookup a directory item based on index. 'dir' is the objectid - * we're searching in, and 'mod' tells us if you plan on deleting the - * item (use mod < 0) or changing the options (use mod > 0) - * - * The name is used to make sure the index really points to the name you were - * looking for. - */ -struct btrfs_dir_item * -btrfs_lookup_dir_index_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, u64 dir, - u64 objectid, const char *name, int name_len, - int mod) -{ - int ret; - struct btrfs_key key; - int ins_len = mod < 0 ? -1 : 0; - int cow = mod != 0; - - key.objectid = dir; - key.type = BTRFS_DIR_INDEX_KEY; - key.offset = objectid; - - ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); - if (ret < 0) - return ERR_PTR(ret); - if (ret > 0) - return ERR_PTR(-ENOENT); - return btrfs_match_dir_item_name(root, path, name, name_len); -} - -struct btrfs_dir_item * -btrfs_search_dir_index_item(struct btrfs_root *root, - struct btrfs_path *path, u64 dirid, - const char *name, int name_len) -{ - struct extent_buffer *leaf; - struct btrfs_dir_item *di; - struct btrfs_key key; - u32 nritems; - int ret; - - key.objectid = dirid; - key.type = BTRFS_DIR_INDEX_KEY; - key.offset = 0; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - return ERR_PTR(ret); - - leaf = path->nodes[0]; - nritems = btrfs_header_nritems(leaf); - - while (1) { - if (path->slots[0] >= nritems) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) - return ERR_PTR(ret); - if (ret > 0) - break; - leaf = path->nodes[0]; - nritems = btrfs_header_nritems(leaf); - continue; - } - - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - if (key.objectid != dirid || key.type != BTRFS_DIR_INDEX_KEY) - break; - - di = btrfs_match_dir_item_name(root, path, name, name_len); - if (di) - return di; - - path->slots[0]++; - } - return NULL; -} - -struct btrfs_dir_item *btrfs_lookup_xattr(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, u64 dir, - const char *name, u16 name_len, - int mod) -{ - int ret; - struct btrfs_key key; - int ins_len = mod < 0 ? -1 : 0; - int cow = mod != 0; - - key.objectid = dir; - key.type = BTRFS_XATTR_ITEM_KEY; - key.offset = btrfs_name_hash(name, name_len); - ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); - if (ret < 0) - return ERR_PTR(ret); - if (ret > 0) - return NULL; - - return btrfs_match_dir_item_name(root, path, name, name_len); -} - -/* - * helper function to look at the directory item pointed to by 'path' - * this walks through all the entries in a dir item and finds one - * for a specific name. - */ -struct btrfs_dir_item *btrfs_match_dir_item_name(struct btrfs_root *root, - struct btrfs_path *path, - const char *name, int name_len) -{ - struct btrfs_dir_item *dir_item; - unsigned long name_ptr; - u32 total_len; - u32 cur = 0; - u32 this_len; - struct extent_buffer *leaf; - - leaf = path->nodes[0]; - dir_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dir_item); - if (verify_dir_item(root, leaf, dir_item)) - return NULL; - - total_len = btrfs_item_size_nr(leaf, path->slots[0]); - while (cur < total_len) { - this_len = sizeof(*dir_item) + - btrfs_dir_name_len(leaf, dir_item) + - btrfs_dir_data_len(leaf, dir_item); - name_ptr = (unsigned long)(dir_item + 1); - - if (btrfs_dir_name_len(leaf, dir_item) == name_len && - memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) - return dir_item; - - cur += this_len; - dir_item = (struct btrfs_dir_item *)((char *)dir_item + - this_len); - } - return NULL; -} - -/* - * given a pointer into a directory item, delete it. This - * handles items that have more than one entry in them. - */ -int btrfs_delete_one_dir_name(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_dir_item *di) -{ - - struct extent_buffer *leaf; - u32 sub_item_len; - u32 item_len; - int ret = 0; - - leaf = path->nodes[0]; - sub_item_len = sizeof(*di) + btrfs_dir_name_len(leaf, di) + - btrfs_dir_data_len(leaf, di); - item_len = btrfs_item_size_nr(leaf, path->slots[0]); - if (sub_item_len == item_len) { - ret = btrfs_del_item(trans, root, path); - } else { - /* MARKER */ - unsigned long ptr = (unsigned long)di; - unsigned long start; - - start = btrfs_item_ptr_offset(leaf, path->slots[0]); - memmove_extent_buffer(leaf, ptr, ptr + sub_item_len, - item_len - (ptr + sub_item_len - start)); - btrfs_truncate_item(root, path, item_len - sub_item_len, 1); - } - return ret; -} - -int verify_dir_item(struct btrfs_root *root, - struct extent_buffer *leaf, - struct btrfs_dir_item *dir_item) -{ - u16 namelen = BTRFS_NAME_LEN; - u8 type = btrfs_dir_type(leaf, dir_item); - - if (type >= BTRFS_FT_MAX) { - btrfs_crit(root->fs_info, "invalid dir item type: %d", - (int)type); - return 1; - } - - if (type == BTRFS_FT_XATTR) - namelen = XATTR_NAME_MAX; - - if (btrfs_dir_name_len(leaf, dir_item) > namelen) { - btrfs_crit(root->fs_info, "invalid dir item name len: %u", - (unsigned)btrfs_dir_data_len(leaf, dir_item)); - return 1; - } - - /* BTRFS_MAX_XATTR_SIZE is the same for all dir items */ - if ((btrfs_dir_data_len(leaf, dir_item) + - btrfs_dir_name_len(leaf, dir_item)) > BTRFS_MAX_XATTR_SIZE(root)) { - btrfs_crit(root->fs_info, - "invalid dir item name + data len: %u + %u", - (unsigned)btrfs_dir_name_len(leaf, dir_item), - (unsigned)btrfs_dir_data_len(leaf, dir_item)); - return 1; - } - - return 0; -} diff --git a/src/linux/fs/btrfs/disk-io.c b/src/linux/fs/btrfs/disk-io.c deleted file mode 100644 index 3a57f99..0000000 --- a/src/linux/fs/btrfs/disk-io.c +++ /dev/null @@ -1,4663 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ctree.h" -#include "disk-io.h" -#include "hash.h" -#include "transaction.h" -#include "btrfs_inode.h" -#include "volumes.h" -#include "print-tree.h" -#include "locking.h" -#include "tree-log.h" -#include "free-space-cache.h" -#include "free-space-tree.h" -#include "inode-map.h" -#include "check-integrity.h" -#include "rcu-string.h" -#include "dev-replace.h" -#include "raid56.h" -#include "sysfs.h" -#include "qgroup.h" -#include "compression.h" - -#ifdef CONFIG_X86 -#include -#endif - -#define BTRFS_SUPER_FLAG_SUPP (BTRFS_HEADER_FLAG_WRITTEN |\ - BTRFS_HEADER_FLAG_RELOC |\ - BTRFS_SUPER_FLAG_ERROR |\ - BTRFS_SUPER_FLAG_SEEDING |\ - BTRFS_SUPER_FLAG_METADUMP) - -static const struct extent_io_ops btree_extent_io_ops; -static void end_workqueue_fn(struct btrfs_work *work); -static void free_fs_root(struct btrfs_root *root); -static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info, - int read_only); -static void btrfs_destroy_ordered_extents(struct btrfs_root *root); -static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, - struct btrfs_root *root); -static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root); -static int btrfs_destroy_marked_extents(struct btrfs_root *root, - struct extent_io_tree *dirty_pages, - int mark); -static int btrfs_destroy_pinned_extent(struct btrfs_root *root, - struct extent_io_tree *pinned_extents); -static int btrfs_cleanup_transaction(struct btrfs_root *root); -static void btrfs_error_commit_super(struct btrfs_root *root); - -/* - * btrfs_end_io_wq structs are used to do processing in task context when an IO - * is complete. This is used during reads to verify checksums, and it is used - * by writes to insert metadata for new file extents after IO is complete. - */ -struct btrfs_end_io_wq { - struct bio *bio; - bio_end_io_t *end_io; - void *private; - struct btrfs_fs_info *info; - int error; - enum btrfs_wq_endio_type metadata; - struct list_head list; - struct btrfs_work work; -}; - -static struct kmem_cache *btrfs_end_io_wq_cache; - -int __init btrfs_end_io_wq_init(void) -{ - btrfs_end_io_wq_cache = kmem_cache_create("btrfs_end_io_wq", - sizeof(struct btrfs_end_io_wq), - 0, - SLAB_MEM_SPREAD, - NULL); - if (!btrfs_end_io_wq_cache) - return -ENOMEM; - return 0; -} - -void btrfs_end_io_wq_exit(void) -{ - kmem_cache_destroy(btrfs_end_io_wq_cache); -} - -/* - * async submit bios are used to offload expensive checksumming - * onto the worker threads. They checksum file and metadata bios - * just before they are sent down the IO stack. - */ -struct async_submit_bio { - struct inode *inode; - struct bio *bio; - struct list_head list; - extent_submit_bio_hook_t *submit_bio_start; - extent_submit_bio_hook_t *submit_bio_done; - int mirror_num; - unsigned long bio_flags; - /* - * bio_offset is optional, can be used if the pages in the bio - * can't tell us where in the file the bio should go - */ - u64 bio_offset; - struct btrfs_work work; - int error; -}; - -/* - * Lockdep class keys for extent_buffer->lock's in this root. For a given - * eb, the lockdep key is determined by the btrfs_root it belongs to and - * the level the eb occupies in the tree. - * - * Different roots are used for different purposes and may nest inside each - * other and they require separate keysets. As lockdep keys should be - * static, assign keysets according to the purpose of the root as indicated - * by btrfs_root->objectid. This ensures that all special purpose roots - * have separate keysets. - * - * Lock-nesting across peer nodes is always done with the immediate parent - * node locked thus preventing deadlock. As lockdep doesn't know this, use - * subclass to avoid triggering lockdep warning in such cases. - * - * The key is set by the readpage_end_io_hook after the buffer has passed - * csum validation but before the pages are unlocked. It is also set by - * btrfs_init_new_buffer on freshly allocated blocks. - * - * We also add a check to make sure the highest level of the tree is the - * same as our lockdep setup here. If BTRFS_MAX_LEVEL changes, this code - * needs update as well. - */ -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# if BTRFS_MAX_LEVEL != 8 -# error -# endif - -static struct btrfs_lockdep_keyset { - u64 id; /* root objectid */ - const char *name_stem; /* lock name stem */ - char names[BTRFS_MAX_LEVEL + 1][20]; - struct lock_class_key keys[BTRFS_MAX_LEVEL + 1]; -} btrfs_lockdep_keysets[] = { - { .id = BTRFS_ROOT_TREE_OBJECTID, .name_stem = "root" }, - { .id = BTRFS_EXTENT_TREE_OBJECTID, .name_stem = "extent" }, - { .id = BTRFS_CHUNK_TREE_OBJECTID, .name_stem = "chunk" }, - { .id = BTRFS_DEV_TREE_OBJECTID, .name_stem = "dev" }, - { .id = BTRFS_FS_TREE_OBJECTID, .name_stem = "fs" }, - { .id = BTRFS_CSUM_TREE_OBJECTID, .name_stem = "csum" }, - { .id = BTRFS_QUOTA_TREE_OBJECTID, .name_stem = "quota" }, - { .id = BTRFS_TREE_LOG_OBJECTID, .name_stem = "log" }, - { .id = BTRFS_TREE_RELOC_OBJECTID, .name_stem = "treloc" }, - { .id = BTRFS_DATA_RELOC_TREE_OBJECTID, .name_stem = "dreloc" }, - { .id = BTRFS_UUID_TREE_OBJECTID, .name_stem = "uuid" }, - { .id = BTRFS_FREE_SPACE_TREE_OBJECTID, .name_stem = "free-space" }, - { .id = 0, .name_stem = "tree" }, -}; - -void __init btrfs_init_lockdep(void) -{ - int i, j; - - /* initialize lockdep class names */ - for (i = 0; i < ARRAY_SIZE(btrfs_lockdep_keysets); i++) { - struct btrfs_lockdep_keyset *ks = &btrfs_lockdep_keysets[i]; - - for (j = 0; j < ARRAY_SIZE(ks->names); j++) - snprintf(ks->names[j], sizeof(ks->names[j]), - "btrfs-%s-%02d", ks->name_stem, j); - } -} - -void btrfs_set_buffer_lockdep_class(u64 objectid, struct extent_buffer *eb, - int level) -{ - struct btrfs_lockdep_keyset *ks; - - BUG_ON(level >= ARRAY_SIZE(ks->keys)); - - /* find the matching keyset, id 0 is the default entry */ - for (ks = btrfs_lockdep_keysets; ks->id; ks++) - if (ks->id == objectid) - break; - - lockdep_set_class_and_name(&eb->lock, - &ks->keys[level], ks->names[level]); -} - -#endif - -/* - * extents on the btree inode are pretty simple, there's one extent - * that covers the entire device - */ -static struct extent_map *btree_get_extent(struct inode *inode, - struct page *page, size_t pg_offset, u64 start, u64 len, - int create) -{ - struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; - struct extent_map *em; - int ret; - - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, start, len); - if (em) { - em->bdev = - BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev; - read_unlock(&em_tree->lock); - goto out; - } - read_unlock(&em_tree->lock); - - em = alloc_extent_map(); - if (!em) { - em = ERR_PTR(-ENOMEM); - goto out; - } - em->start = 0; - em->len = (u64)-1; - em->block_len = (u64)-1; - em->block_start = 0; - em->bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev; - - write_lock(&em_tree->lock); - ret = add_extent_mapping(em_tree, em, 0); - if (ret == -EEXIST) { - free_extent_map(em); - em = lookup_extent_mapping(em_tree, start, len); - if (!em) - em = ERR_PTR(-EIO); - } else if (ret) { - free_extent_map(em); - em = ERR_PTR(ret); - } - write_unlock(&em_tree->lock); - -out: - return em; -} - -u32 btrfs_csum_data(char *data, u32 seed, size_t len) -{ - return btrfs_crc32c(seed, data, len); -} - -void btrfs_csum_final(u32 crc, char *result) -{ - put_unaligned_le32(~crc, result); -} - -/* - * compute the csum for a btree block, and either verify it or write it - * into the csum field of the block. - */ -static int csum_tree_block(struct btrfs_fs_info *fs_info, - struct extent_buffer *buf, - int verify) -{ - u16 csum_size = btrfs_super_csum_size(fs_info->super_copy); - char *result = NULL; - unsigned long len; - unsigned long cur_len; - unsigned long offset = BTRFS_CSUM_SIZE; - char *kaddr; - unsigned long map_start; - unsigned long map_len; - int err; - u32 crc = ~(u32)0; - unsigned long inline_result; - - len = buf->len - offset; - while (len > 0) { - err = map_private_extent_buffer(buf, offset, 32, - &kaddr, &map_start, &map_len); - if (err) - return err; - cur_len = min(len, map_len - (offset - map_start)); - crc = btrfs_csum_data(kaddr + offset - map_start, - crc, cur_len); - len -= cur_len; - offset += cur_len; - } - if (csum_size > sizeof(inline_result)) { - result = kzalloc(csum_size, GFP_NOFS); - if (!result) - return -ENOMEM; - } else { - result = (char *)&inline_result; - } - - btrfs_csum_final(crc, result); - - if (verify) { - if (memcmp_extent_buffer(buf, result, 0, csum_size)) { - u32 val; - u32 found = 0; - memcpy(&found, result, csum_size); - - read_extent_buffer(buf, &val, 0, csum_size); - btrfs_warn_rl(fs_info, - "%s checksum verify failed on %llu wanted %X found %X level %d", - fs_info->sb->s_id, buf->start, - val, found, btrfs_header_level(buf)); - if (result != (char *)&inline_result) - kfree(result); - return -EUCLEAN; - } - } else { - write_extent_buffer(buf, result, 0, csum_size); - } - if (result != (char *)&inline_result) - kfree(result); - return 0; -} - -/* - * we can't consider a given block up to date unless the transid of the - * block matches the transid in the parent node's pointer. This is how we - * detect blocks that either didn't get written at all or got written - * in the wrong place. - */ -static int verify_parent_transid(struct extent_io_tree *io_tree, - struct extent_buffer *eb, u64 parent_transid, - int atomic) -{ - struct extent_state *cached_state = NULL; - int ret; - bool need_lock = (current->journal_info == BTRFS_SEND_TRANS_STUB); - - if (!parent_transid || btrfs_header_generation(eb) == parent_transid) - return 0; - - if (atomic) - return -EAGAIN; - - if (need_lock) { - btrfs_tree_read_lock(eb); - btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); - } - - lock_extent_bits(io_tree, eb->start, eb->start + eb->len - 1, - &cached_state); - if (extent_buffer_uptodate(eb) && - btrfs_header_generation(eb) == parent_transid) { - ret = 0; - goto out; - } - btrfs_err_rl(eb->fs_info, - "parent transid verify failed on %llu wanted %llu found %llu", - eb->start, - parent_transid, btrfs_header_generation(eb)); - ret = 1; - - /* - * Things reading via commit roots that don't have normal protection, - * like send, can have a really old block in cache that may point at a - * block that has been freed and re-allocated. So don't clear uptodate - * if we find an eb that is under IO (dirty/writeback) because we could - * end up reading in the stale data and then writing it back out and - * making everybody very sad. - */ - if (!extent_buffer_under_io(eb)) - clear_extent_buffer_uptodate(eb); -out: - unlock_extent_cached(io_tree, eb->start, eb->start + eb->len - 1, - &cached_state, GFP_NOFS); - if (need_lock) - btrfs_tree_read_unlock_blocking(eb); - return ret; -} - -/* - * Return 0 if the superblock checksum type matches the checksum value of that - * algorithm. Pass the raw disk superblock data. - */ -static int btrfs_check_super_csum(struct btrfs_fs_info *fs_info, - char *raw_disk_sb) -{ - struct btrfs_super_block *disk_sb = - (struct btrfs_super_block *)raw_disk_sb; - u16 csum_type = btrfs_super_csum_type(disk_sb); - int ret = 0; - - if (csum_type == BTRFS_CSUM_TYPE_CRC32) { - u32 crc = ~(u32)0; - const int csum_size = sizeof(crc); - char result[csum_size]; - - /* - * The super_block structure does not span the whole - * BTRFS_SUPER_INFO_SIZE range, we expect that the unused space - * is filled with zeros and is included in the checksum. - */ - crc = btrfs_csum_data(raw_disk_sb + BTRFS_CSUM_SIZE, - crc, BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE); - btrfs_csum_final(crc, result); - - if (memcmp(raw_disk_sb, result, csum_size)) - ret = 1; - } - - if (csum_type >= ARRAY_SIZE(btrfs_csum_sizes)) { - btrfs_err(fs_info, "unsupported checksum algorithm %u", - csum_type); - ret = 1; - } - - return ret; -} - -/* - * helper to read a given tree block, doing retries as required when - * the checksums don't match and we have alternate mirrors to try. - */ -static int btree_read_extent_buffer_pages(struct btrfs_root *root, - struct extent_buffer *eb, - u64 parent_transid) -{ - struct extent_io_tree *io_tree; - int failed = 0; - int ret; - int num_copies = 0; - int mirror_num = 0; - int failed_mirror = 0; - - clear_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags); - io_tree = &BTRFS_I(root->fs_info->btree_inode)->io_tree; - while (1) { - ret = read_extent_buffer_pages(io_tree, eb, WAIT_COMPLETE, - btree_get_extent, mirror_num); - if (!ret) { - if (!verify_parent_transid(io_tree, eb, - parent_transid, 0)) - break; - else - ret = -EIO; - } - - /* - * This buffer's crc is fine, but its contents are corrupted, so - * there is no reason to read the other copies, they won't be - * any less wrong. - */ - if (test_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags)) - break; - - num_copies = btrfs_num_copies(root->fs_info, - eb->start, eb->len); - if (num_copies == 1) - break; - - if (!failed_mirror) { - failed = 1; - failed_mirror = eb->read_mirror; - } - - mirror_num++; - if (mirror_num == failed_mirror) - mirror_num++; - - if (mirror_num > num_copies) - break; - } - - if (failed && !ret && failed_mirror) - repair_eb_io_failure(root, eb, failed_mirror); - - return ret; -} - -/* - * checksum a dirty tree block before IO. This has extra checks to make sure - * we only fill in the checksum field in the first page of a multi-page block - */ - -static int csum_dirty_buffer(struct btrfs_fs_info *fs_info, struct page *page) -{ - u64 start = page_offset(page); - u64 found_start; - struct extent_buffer *eb; - - eb = (struct extent_buffer *)page->private; - if (page != eb->pages[0]) - return 0; - - found_start = btrfs_header_bytenr(eb); - /* - * Please do not consolidate these warnings into a single if. - * It is useful to know what went wrong. - */ - if (WARN_ON(found_start != start)) - return -EUCLEAN; - if (WARN_ON(!PageUptodate(page))) - return -EUCLEAN; - - ASSERT(memcmp_extent_buffer(eb, fs_info->fsid, - btrfs_header_fsid(), BTRFS_FSID_SIZE) == 0); - - return csum_tree_block(fs_info, eb, 0); -} - -static int check_tree_block_fsid(struct btrfs_fs_info *fs_info, - struct extent_buffer *eb) -{ - struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; - u8 fsid[BTRFS_UUID_SIZE]; - int ret = 1; - - read_extent_buffer(eb, fsid, btrfs_header_fsid(), BTRFS_FSID_SIZE); - while (fs_devices) { - if (!memcmp(fsid, fs_devices->fsid, BTRFS_FSID_SIZE)) { - ret = 0; - break; - } - fs_devices = fs_devices->seed; - } - return ret; -} - -#define CORRUPT(reason, eb, root, slot) \ - btrfs_crit(root->fs_info, "corrupt %s, %s: block=%llu," \ - " root=%llu, slot=%d", \ - btrfs_header_level(eb) == 0 ? "leaf" : "node",\ - reason, btrfs_header_bytenr(eb), root->objectid, slot) - -static noinline int check_leaf(struct btrfs_root *root, - struct extent_buffer *leaf) -{ - struct btrfs_key key; - struct btrfs_key leaf_key; - u32 nritems = btrfs_header_nritems(leaf); - int slot; - - if (nritems == 0) { - struct btrfs_root *check_root; - - key.objectid = btrfs_header_owner(leaf); - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = (u64)-1; - - check_root = btrfs_get_fs_root(root->fs_info, &key, false); - /* - * The only reason we also check NULL here is that during - * open_ctree() some roots has not yet been set up. - */ - if (!IS_ERR_OR_NULL(check_root)) { - /* if leaf is the root, then it's fine */ - if (leaf->start != - btrfs_root_bytenr(&check_root->root_item)) { - CORRUPT("non-root leaf's nritems is 0", - leaf, root, 0); - return -EIO; - } - } - return 0; - } - - /* Check the 0 item */ - if (btrfs_item_offset_nr(leaf, 0) + btrfs_item_size_nr(leaf, 0) != - BTRFS_LEAF_DATA_SIZE(root)) { - CORRUPT("invalid item offset size pair", leaf, root, 0); - return -EIO; - } - - /* - * Check to make sure each items keys are in the correct order and their - * offsets make sense. We only have to loop through nritems-1 because - * we check the current slot against the next slot, which verifies the - * next slot's offset+size makes sense and that the current's slot - * offset is correct. - */ - for (slot = 0; slot < nritems - 1; slot++) { - btrfs_item_key_to_cpu(leaf, &leaf_key, slot); - btrfs_item_key_to_cpu(leaf, &key, slot + 1); - - /* Make sure the keys are in the right order */ - if (btrfs_comp_cpu_keys(&leaf_key, &key) >= 0) { - CORRUPT("bad key order", leaf, root, slot); - return -EIO; - } - - /* - * Make sure the offset and ends are right, remember that the - * item data starts at the end of the leaf and grows towards the - * front. - */ - if (btrfs_item_offset_nr(leaf, slot) != - btrfs_item_end_nr(leaf, slot + 1)) { - CORRUPT("slot offset bad", leaf, root, slot); - return -EIO; - } - - /* - * Check to make sure that we don't point outside of the leaf, - * just in case all the items are consistent to each other, but - * all point outside of the leaf. - */ - if (btrfs_item_end_nr(leaf, slot) > - BTRFS_LEAF_DATA_SIZE(root)) { - CORRUPT("slot end outside of leaf", leaf, root, slot); - return -EIO; - } - } - - return 0; -} - -static int check_node(struct btrfs_root *root, struct extent_buffer *node) -{ - unsigned long nr = btrfs_header_nritems(node); - struct btrfs_key key, next_key; - int slot; - u64 bytenr; - int ret = 0; - - if (nr == 0 || nr > BTRFS_NODEPTRS_PER_BLOCK(root)) { - btrfs_crit(root->fs_info, - "corrupt node: block %llu root %llu nritems %lu", - node->start, root->objectid, nr); - return -EIO; - } - - for (slot = 0; slot < nr - 1; slot++) { - bytenr = btrfs_node_blockptr(node, slot); - btrfs_node_key_to_cpu(node, &key, slot); - btrfs_node_key_to_cpu(node, &next_key, slot + 1); - - if (!bytenr) { - CORRUPT("invalid item slot", node, root, slot); - ret = -EIO; - goto out; - } - - if (btrfs_comp_cpu_keys(&key, &next_key) >= 0) { - CORRUPT("bad key order", node, root, slot); - ret = -EIO; - goto out; - } - } -out: - return ret; -} - -static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio, - u64 phy_offset, struct page *page, - u64 start, u64 end, int mirror) -{ - u64 found_start; - int found_level; - struct extent_buffer *eb; - struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; - struct btrfs_fs_info *fs_info = root->fs_info; - int ret = 0; - int reads_done; - - if (!page->private) - goto out; - - eb = (struct extent_buffer *)page->private; - - /* the pending IO might have been the only thing that kept this buffer - * in memory. Make sure we have a ref for all this other checks - */ - extent_buffer_get(eb); - - reads_done = atomic_dec_and_test(&eb->io_pages); - if (!reads_done) - goto err; - - eb->read_mirror = mirror; - if (test_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags)) { - ret = -EIO; - goto err; - } - - found_start = btrfs_header_bytenr(eb); - if (found_start != eb->start) { - btrfs_err_rl(fs_info, "bad tree block start %llu %llu", - found_start, eb->start); - ret = -EIO; - goto err; - } - if (check_tree_block_fsid(fs_info, eb)) { - btrfs_err_rl(fs_info, "bad fsid on block %llu", - eb->start); - ret = -EIO; - goto err; - } - found_level = btrfs_header_level(eb); - if (found_level >= BTRFS_MAX_LEVEL) { - btrfs_err(fs_info, "bad tree block level %d", - (int)btrfs_header_level(eb)); - ret = -EIO; - goto err; - } - - btrfs_set_buffer_lockdep_class(btrfs_header_owner(eb), - eb, found_level); - - ret = csum_tree_block(fs_info, eb, 1); - if (ret) - goto err; - - /* - * If this is a leaf block and it is corrupt, set the corrupt bit so - * that we don't try and read the other copies of this block, just - * return -EIO. - */ - if (found_level == 0 && check_leaf(root, eb)) { - set_bit(EXTENT_BUFFER_CORRUPT, &eb->bflags); - ret = -EIO; - } - - if (found_level > 0 && check_node(root, eb)) - ret = -EIO; - - if (!ret) - set_extent_buffer_uptodate(eb); -err: - if (reads_done && - test_and_clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) - btree_readahead_hook(fs_info, eb, eb->start, ret); - - if (ret) { - /* - * our io error hook is going to dec the io pages - * again, we have to make sure it has something - * to decrement - */ - atomic_inc(&eb->io_pages); - clear_extent_buffer_uptodate(eb); - } - free_extent_buffer(eb); -out: - return ret; -} - -static int btree_io_failed_hook(struct page *page, int failed_mirror) -{ - struct extent_buffer *eb; - - eb = (struct extent_buffer *)page->private; - set_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags); - eb->read_mirror = failed_mirror; - atomic_dec(&eb->io_pages); - if (test_and_clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags)) - btree_readahead_hook(eb->fs_info, eb, eb->start, -EIO); - return -EIO; /* we fixed nothing */ -} - -static void end_workqueue_bio(struct bio *bio) -{ - struct btrfs_end_io_wq *end_io_wq = bio->bi_private; - struct btrfs_fs_info *fs_info; - struct btrfs_workqueue *wq; - btrfs_work_func_t func; - - fs_info = end_io_wq->info; - end_io_wq->error = bio->bi_error; - - if (bio_op(bio) == REQ_OP_WRITE) { - if (end_io_wq->metadata == BTRFS_WQ_ENDIO_METADATA) { - wq = fs_info->endio_meta_write_workers; - func = btrfs_endio_meta_write_helper; - } else if (end_io_wq->metadata == BTRFS_WQ_ENDIO_FREE_SPACE) { - wq = fs_info->endio_freespace_worker; - func = btrfs_freespace_write_helper; - } else if (end_io_wq->metadata == BTRFS_WQ_ENDIO_RAID56) { - wq = fs_info->endio_raid56_workers; - func = btrfs_endio_raid56_helper; - } else { - wq = fs_info->endio_write_workers; - func = btrfs_endio_write_helper; - } - } else { - if (unlikely(end_io_wq->metadata == - BTRFS_WQ_ENDIO_DIO_REPAIR)) { - wq = fs_info->endio_repair_workers; - func = btrfs_endio_repair_helper; - } else if (end_io_wq->metadata == BTRFS_WQ_ENDIO_RAID56) { - wq = fs_info->endio_raid56_workers; - func = btrfs_endio_raid56_helper; - } else if (end_io_wq->metadata) { - wq = fs_info->endio_meta_workers; - func = btrfs_endio_meta_helper; - } else { - wq = fs_info->endio_workers; - func = btrfs_endio_helper; - } - } - - btrfs_init_work(&end_io_wq->work, func, end_workqueue_fn, NULL, NULL); - btrfs_queue_work(wq, &end_io_wq->work); -} - -int btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio, - enum btrfs_wq_endio_type metadata) -{ - struct btrfs_end_io_wq *end_io_wq; - - end_io_wq = kmem_cache_alloc(btrfs_end_io_wq_cache, GFP_NOFS); - if (!end_io_wq) - return -ENOMEM; - - end_io_wq->private = bio->bi_private; - end_io_wq->end_io = bio->bi_end_io; - end_io_wq->info = info; - end_io_wq->error = 0; - end_io_wq->bio = bio; - end_io_wq->metadata = metadata; - - bio->bi_private = end_io_wq; - bio->bi_end_io = end_workqueue_bio; - return 0; -} - -unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info) -{ - unsigned long limit = min_t(unsigned long, - info->thread_pool_size, - info->fs_devices->open_devices); - return 256 * limit; -} - -static void run_one_async_start(struct btrfs_work *work) -{ - struct async_submit_bio *async; - int ret; - - async = container_of(work, struct async_submit_bio, work); - ret = async->submit_bio_start(async->inode, async->bio, - async->mirror_num, async->bio_flags, - async->bio_offset); - if (ret) - async->error = ret; -} - -static void run_one_async_done(struct btrfs_work *work) -{ - struct btrfs_fs_info *fs_info; - struct async_submit_bio *async; - int limit; - - async = container_of(work, struct async_submit_bio, work); - fs_info = BTRFS_I(async->inode)->root->fs_info; - - limit = btrfs_async_submit_limit(fs_info); - limit = limit * 2 / 3; - - /* - * atomic_dec_return implies a barrier for waitqueue_active - */ - if (atomic_dec_return(&fs_info->nr_async_submits) < limit && - waitqueue_active(&fs_info->async_submit_wait)) - wake_up(&fs_info->async_submit_wait); - - /* If an error occurred we just want to clean up the bio and move on */ - if (async->error) { - async->bio->bi_error = async->error; - bio_endio(async->bio); - return; - } - - async->submit_bio_done(async->inode, async->bio, async->mirror_num, - async->bio_flags, async->bio_offset); -} - -static void run_one_async_free(struct btrfs_work *work) -{ - struct async_submit_bio *async; - - async = container_of(work, struct async_submit_bio, work); - kfree(async); -} - -int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, - struct bio *bio, int mirror_num, - unsigned long bio_flags, - u64 bio_offset, - extent_submit_bio_hook_t *submit_bio_start, - extent_submit_bio_hook_t *submit_bio_done) -{ - struct async_submit_bio *async; - - async = kmalloc(sizeof(*async), GFP_NOFS); - if (!async) - return -ENOMEM; - - async->inode = inode; - async->bio = bio; - async->mirror_num = mirror_num; - async->submit_bio_start = submit_bio_start; - async->submit_bio_done = submit_bio_done; - - btrfs_init_work(&async->work, btrfs_worker_helper, run_one_async_start, - run_one_async_done, run_one_async_free); - - async->bio_flags = bio_flags; - async->bio_offset = bio_offset; - - async->error = 0; - - atomic_inc(&fs_info->nr_async_submits); - - if (bio->bi_opf & REQ_SYNC) - btrfs_set_work_high_priority(&async->work); - - btrfs_queue_work(fs_info->workers, &async->work); - - while (atomic_read(&fs_info->async_submit_draining) && - atomic_read(&fs_info->nr_async_submits)) { - wait_event(fs_info->async_submit_wait, - (atomic_read(&fs_info->nr_async_submits) == 0)); - } - - return 0; -} - -static int btree_csum_one_bio(struct bio *bio) -{ - struct bio_vec *bvec; - struct btrfs_root *root; - int i, ret = 0; - - bio_for_each_segment_all(bvec, bio, i) { - root = BTRFS_I(bvec->bv_page->mapping->host)->root; - ret = csum_dirty_buffer(root->fs_info, bvec->bv_page); - if (ret) - break; - } - - return ret; -} - -static int __btree_submit_bio_start(struct inode *inode, struct bio *bio, - int mirror_num, unsigned long bio_flags, - u64 bio_offset) -{ - /* - * when we're called for a write, we're already in the async - * submission context. Just jump into btrfs_map_bio - */ - return btree_csum_one_bio(bio); -} - -static int __btree_submit_bio_done(struct inode *inode, struct bio *bio, - int mirror_num, unsigned long bio_flags, - u64 bio_offset) -{ - int ret; - - /* - * when we're called for a write, we're already in the async - * submission context. Just jump into btrfs_map_bio - */ - ret = btrfs_map_bio(BTRFS_I(inode)->root, bio, mirror_num, 1); - if (ret) { - bio->bi_error = ret; - bio_endio(bio); - } - return ret; -} - -static int check_async_write(struct inode *inode, unsigned long bio_flags) -{ - if (bio_flags & EXTENT_BIO_TREE_LOG) - return 0; -#ifdef CONFIG_X86 - if (static_cpu_has(X86_FEATURE_XMM4_2)) - return 0; -#endif - return 1; -} - -static int btree_submit_bio_hook(struct inode *inode, struct bio *bio, - int mirror_num, unsigned long bio_flags, - u64 bio_offset) -{ - int async = check_async_write(inode, bio_flags); - int ret; - - if (bio_op(bio) != REQ_OP_WRITE) { - /* - * called for a read, do the setup so that checksum validation - * can happen in the async kernel threads - */ - ret = btrfs_bio_wq_end_io(BTRFS_I(inode)->root->fs_info, - bio, BTRFS_WQ_ENDIO_METADATA); - if (ret) - goto out_w_error; - ret = btrfs_map_bio(BTRFS_I(inode)->root, bio, mirror_num, 0); - } else if (!async) { - ret = btree_csum_one_bio(bio); - if (ret) - goto out_w_error; - ret = btrfs_map_bio(BTRFS_I(inode)->root, bio, mirror_num, 0); - } else { - /* - * kthread helpers are used to submit writes so that - * checksumming can happen in parallel across all CPUs - */ - ret = btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, - inode, bio, mirror_num, 0, - bio_offset, - __btree_submit_bio_start, - __btree_submit_bio_done); - } - - if (ret) - goto out_w_error; - return 0; - -out_w_error: - bio->bi_error = ret; - bio_endio(bio); - return ret; -} - -#ifdef CONFIG_MIGRATION -static int btree_migratepage(struct address_space *mapping, - struct page *newpage, struct page *page, - enum migrate_mode mode) -{ - /* - * we can't safely write a btree page from here, - * we haven't done the locking hook - */ - if (PageDirty(page)) - return -EAGAIN; - /* - * Buffers may be managed in a filesystem specific way. - * We must have no buffers or drop them. - */ - if (page_has_private(page) && - !try_to_release_page(page, GFP_KERNEL)) - return -EAGAIN; - return migrate_page(mapping, newpage, page, mode); -} -#endif - - -static int btree_writepages(struct address_space *mapping, - struct writeback_control *wbc) -{ - struct btrfs_fs_info *fs_info; - int ret; - - if (wbc->sync_mode == WB_SYNC_NONE) { - - if (wbc->for_kupdate) - return 0; - - fs_info = BTRFS_I(mapping->host)->root->fs_info; - /* this is a bit racy, but that's ok */ - ret = percpu_counter_compare(&fs_info->dirty_metadata_bytes, - BTRFS_DIRTY_METADATA_THRESH); - if (ret < 0) - return 0; - } - return btree_write_cache_pages(mapping, wbc); -} - -static int btree_readpage(struct file *file, struct page *page) -{ - struct extent_io_tree *tree; - tree = &BTRFS_I(page->mapping->host)->io_tree; - return extent_read_full_page(tree, page, btree_get_extent, 0); -} - -static int btree_releasepage(struct page *page, gfp_t gfp_flags) -{ - if (PageWriteback(page) || PageDirty(page)) - return 0; - - return try_release_extent_buffer(page); -} - -static void btree_invalidatepage(struct page *page, unsigned int offset, - unsigned int length) -{ - struct extent_io_tree *tree; - tree = &BTRFS_I(page->mapping->host)->io_tree; - extent_invalidatepage(tree, page, offset); - btree_releasepage(page, GFP_NOFS); - if (PagePrivate(page)) { - btrfs_warn(BTRFS_I(page->mapping->host)->root->fs_info, - "page private not zero on page %llu", - (unsigned long long)page_offset(page)); - ClearPagePrivate(page); - set_page_private(page, 0); - put_page(page); - } -} - -static int btree_set_page_dirty(struct page *page) -{ -#ifdef DEBUG - struct extent_buffer *eb; - - BUG_ON(!PagePrivate(page)); - eb = (struct extent_buffer *)page->private; - BUG_ON(!eb); - BUG_ON(!test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)); - BUG_ON(!atomic_read(&eb->refs)); - btrfs_assert_tree_locked(eb); -#endif - return __set_page_dirty_nobuffers(page); -} - -static const struct address_space_operations btree_aops = { - .readpage = btree_readpage, - .writepages = btree_writepages, - .releasepage = btree_releasepage, - .invalidatepage = btree_invalidatepage, -#ifdef CONFIG_MIGRATION - .migratepage = btree_migratepage, -#endif - .set_page_dirty = btree_set_page_dirty, -}; - -void readahead_tree_block(struct btrfs_root *root, u64 bytenr) -{ - struct extent_buffer *buf = NULL; - struct inode *btree_inode = root->fs_info->btree_inode; - - buf = btrfs_find_create_tree_block(root, bytenr); - if (IS_ERR(buf)) - return; - read_extent_buffer_pages(&BTRFS_I(btree_inode)->io_tree, - buf, WAIT_NONE, btree_get_extent, 0); - free_extent_buffer(buf); -} - -int reada_tree_block_flagged(struct btrfs_root *root, u64 bytenr, - int mirror_num, struct extent_buffer **eb) -{ - struct extent_buffer *buf = NULL; - struct inode *btree_inode = root->fs_info->btree_inode; - struct extent_io_tree *io_tree = &BTRFS_I(btree_inode)->io_tree; - int ret; - - buf = btrfs_find_create_tree_block(root, bytenr); - if (IS_ERR(buf)) - return 0; - - set_bit(EXTENT_BUFFER_READAHEAD, &buf->bflags); - - ret = read_extent_buffer_pages(io_tree, buf, WAIT_PAGE_LOCK, - btree_get_extent, mirror_num); - if (ret) { - free_extent_buffer(buf); - return ret; - } - - if (test_bit(EXTENT_BUFFER_CORRUPT, &buf->bflags)) { - free_extent_buffer(buf); - return -EIO; - } else if (extent_buffer_uptodate(buf)) { - *eb = buf; - } else { - free_extent_buffer(buf); - } - return 0; -} - -struct extent_buffer *btrfs_find_tree_block(struct btrfs_fs_info *fs_info, - u64 bytenr) -{ - return find_extent_buffer(fs_info, bytenr); -} - -struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, - u64 bytenr) -{ - if (btrfs_is_testing(root->fs_info)) - return alloc_test_extent_buffer(root->fs_info, bytenr, - root->nodesize); - return alloc_extent_buffer(root->fs_info, bytenr); -} - - -int btrfs_write_tree_block(struct extent_buffer *buf) -{ - return filemap_fdatawrite_range(buf->pages[0]->mapping, buf->start, - buf->start + buf->len - 1); -} - -int btrfs_wait_tree_block_writeback(struct extent_buffer *buf) -{ - return filemap_fdatawait_range(buf->pages[0]->mapping, - buf->start, buf->start + buf->len - 1); -} - -struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, - u64 parent_transid) -{ - struct extent_buffer *buf = NULL; - int ret; - - buf = btrfs_find_create_tree_block(root, bytenr); - if (IS_ERR(buf)) - return buf; - - ret = btree_read_extent_buffer_pages(root, buf, parent_transid); - if (ret) { - free_extent_buffer(buf); - return ERR_PTR(ret); - } - return buf; - -} - -void clean_tree_block(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct extent_buffer *buf) -{ - if (btrfs_header_generation(buf) == - fs_info->running_transaction->transid) { - btrfs_assert_tree_locked(buf); - - if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &buf->bflags)) { - __percpu_counter_add(&fs_info->dirty_metadata_bytes, - -buf->len, - fs_info->dirty_metadata_batch); - /* ugh, clear_extent_buffer_dirty needs to lock the page */ - btrfs_set_lock_blocking(buf); - clear_extent_buffer_dirty(buf); - } - } -} - -static struct btrfs_subvolume_writers *btrfs_alloc_subvolume_writers(void) -{ - struct btrfs_subvolume_writers *writers; - int ret; - - writers = kmalloc(sizeof(*writers), GFP_NOFS); - if (!writers) - return ERR_PTR(-ENOMEM); - - ret = percpu_counter_init(&writers->counter, 0, GFP_KERNEL); - if (ret < 0) { - kfree(writers); - return ERR_PTR(ret); - } - - init_waitqueue_head(&writers->wait); - return writers; -} - -static void -btrfs_free_subvolume_writers(struct btrfs_subvolume_writers *writers) -{ - percpu_counter_destroy(&writers->counter); - kfree(writers); -} - -static void __setup_root(u32 nodesize, u32 sectorsize, u32 stripesize, - struct btrfs_root *root, struct btrfs_fs_info *fs_info, - u64 objectid) -{ - bool dummy = test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state); - root->node = NULL; - root->commit_root = NULL; - root->sectorsize = sectorsize; - root->nodesize = nodesize; - root->stripesize = stripesize; - root->state = 0; - root->orphan_cleanup_state = 0; - - root->objectid = objectid; - root->last_trans = 0; - root->highest_objectid = 0; - root->nr_delalloc_inodes = 0; - root->nr_ordered_extents = 0; - root->name = NULL; - root->inode_tree = RB_ROOT; - INIT_RADIX_TREE(&root->delayed_nodes_tree, GFP_ATOMIC); - root->block_rsv = NULL; - root->orphan_block_rsv = NULL; - - INIT_LIST_HEAD(&root->dirty_list); - INIT_LIST_HEAD(&root->root_list); - INIT_LIST_HEAD(&root->delalloc_inodes); - INIT_LIST_HEAD(&root->delalloc_root); - INIT_LIST_HEAD(&root->ordered_extents); - INIT_LIST_HEAD(&root->ordered_root); - INIT_LIST_HEAD(&root->logged_list[0]); - INIT_LIST_HEAD(&root->logged_list[1]); - spin_lock_init(&root->orphan_lock); - spin_lock_init(&root->inode_lock); - spin_lock_init(&root->delalloc_lock); - spin_lock_init(&root->ordered_extent_lock); - spin_lock_init(&root->accounting_lock); - spin_lock_init(&root->log_extents_lock[0]); - spin_lock_init(&root->log_extents_lock[1]); - mutex_init(&root->objectid_mutex); - mutex_init(&root->log_mutex); - mutex_init(&root->ordered_extent_mutex); - mutex_init(&root->delalloc_mutex); - init_waitqueue_head(&root->log_writer_wait); - init_waitqueue_head(&root->log_commit_wait[0]); - init_waitqueue_head(&root->log_commit_wait[1]); - INIT_LIST_HEAD(&root->log_ctxs[0]); - INIT_LIST_HEAD(&root->log_ctxs[1]); - atomic_set(&root->log_commit[0], 0); - atomic_set(&root->log_commit[1], 0); - atomic_set(&root->log_writers, 0); - atomic_set(&root->log_batch, 0); - atomic_set(&root->orphan_inodes, 0); - atomic_set(&root->refs, 1); - atomic_set(&root->will_be_snapshoted, 0); - atomic_set(&root->qgroup_meta_rsv, 0); - root->log_transid = 0; - root->log_transid_committed = -1; - root->last_log_commit = 0; - if (!dummy) - extent_io_tree_init(&root->dirty_log_pages, - fs_info->btree_inode->i_mapping); - - memset(&root->root_key, 0, sizeof(root->root_key)); - memset(&root->root_item, 0, sizeof(root->root_item)); - memset(&root->defrag_progress, 0, sizeof(root->defrag_progress)); - if (!dummy) - root->defrag_trans_start = fs_info->generation; - else - root->defrag_trans_start = 0; - root->root_key.objectid = objectid; - root->anon_dev = 0; - - spin_lock_init(&root->root_item_lock); -} - -static struct btrfs_root *btrfs_alloc_root(struct btrfs_fs_info *fs_info, - gfp_t flags) -{ - struct btrfs_root *root = kzalloc(sizeof(*root), flags); - if (root) - root->fs_info = fs_info; - return root; -} - -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS -/* Should only be used by the testing infrastructure */ -struct btrfs_root *btrfs_alloc_dummy_root(struct btrfs_fs_info *fs_info, - u32 sectorsize, u32 nodesize) -{ - struct btrfs_root *root; - - if (!fs_info) - return ERR_PTR(-EINVAL); - - root = btrfs_alloc_root(fs_info, GFP_KERNEL); - if (!root) - return ERR_PTR(-ENOMEM); - /* We don't use the stripesize in selftest, set it as sectorsize */ - __setup_root(nodesize, sectorsize, sectorsize, root, fs_info, - BTRFS_ROOT_TREE_OBJECTID); - root->alloc_bytenr = 0; - - return root; -} -#endif - -struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - u64 objectid) -{ - struct extent_buffer *leaf; - struct btrfs_root *tree_root = fs_info->tree_root; - struct btrfs_root *root; - struct btrfs_key key; - int ret = 0; - uuid_le uuid; - - root = btrfs_alloc_root(fs_info, GFP_KERNEL); - if (!root) - return ERR_PTR(-ENOMEM); - - __setup_root(tree_root->nodesize, tree_root->sectorsize, - tree_root->stripesize, root, fs_info, objectid); - root->root_key.objectid = objectid; - root->root_key.type = BTRFS_ROOT_ITEM_KEY; - root->root_key.offset = 0; - - leaf = btrfs_alloc_tree_block(trans, root, 0, objectid, NULL, 0, 0, 0); - if (IS_ERR(leaf)) { - ret = PTR_ERR(leaf); - leaf = NULL; - goto fail; - } - - memset_extent_buffer(leaf, 0, 0, sizeof(struct btrfs_header)); - btrfs_set_header_bytenr(leaf, leaf->start); - btrfs_set_header_generation(leaf, trans->transid); - btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV); - btrfs_set_header_owner(leaf, objectid); - root->node = leaf; - - write_extent_buffer(leaf, fs_info->fsid, btrfs_header_fsid(), - BTRFS_FSID_SIZE); - write_extent_buffer(leaf, fs_info->chunk_tree_uuid, - btrfs_header_chunk_tree_uuid(leaf), - BTRFS_UUID_SIZE); - btrfs_mark_buffer_dirty(leaf); - - root->commit_root = btrfs_root_node(root); - set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); - - root->root_item.flags = 0; - root->root_item.byte_limit = 0; - btrfs_set_root_bytenr(&root->root_item, leaf->start); - btrfs_set_root_generation(&root->root_item, trans->transid); - btrfs_set_root_level(&root->root_item, 0); - btrfs_set_root_refs(&root->root_item, 1); - btrfs_set_root_used(&root->root_item, leaf->len); - btrfs_set_root_last_snapshot(&root->root_item, 0); - btrfs_set_root_dirid(&root->root_item, 0); - uuid_le_gen(&uuid); - memcpy(root->root_item.uuid, uuid.b, BTRFS_UUID_SIZE); - root->root_item.drop_level = 0; - - key.objectid = objectid; - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = 0; - ret = btrfs_insert_root(trans, tree_root, &key, &root->root_item); - if (ret) - goto fail; - - btrfs_tree_unlock(leaf); - - return root; - -fail: - if (leaf) { - btrfs_tree_unlock(leaf); - free_extent_buffer(root->commit_root); - free_extent_buffer(leaf); - } - kfree(root); - - return ERR_PTR(ret); -} - -static struct btrfs_root *alloc_log_tree(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info) -{ - struct btrfs_root *root; - struct btrfs_root *tree_root = fs_info->tree_root; - struct extent_buffer *leaf; - - root = btrfs_alloc_root(fs_info, GFP_NOFS); - if (!root) - return ERR_PTR(-ENOMEM); - - __setup_root(tree_root->nodesize, tree_root->sectorsize, - tree_root->stripesize, root, fs_info, - BTRFS_TREE_LOG_OBJECTID); - - root->root_key.objectid = BTRFS_TREE_LOG_OBJECTID; - root->root_key.type = BTRFS_ROOT_ITEM_KEY; - root->root_key.offset = BTRFS_TREE_LOG_OBJECTID; - - /* - * DON'T set REF_COWS for log trees - * - * log trees do not get reference counted because they go away - * before a real commit is actually done. They do store pointers - * to file data extents, and those reference counts still get - * updated (along with back refs to the log tree). - */ - - leaf = btrfs_alloc_tree_block(trans, root, 0, BTRFS_TREE_LOG_OBJECTID, - NULL, 0, 0, 0); - if (IS_ERR(leaf)) { - kfree(root); - return ERR_CAST(leaf); - } - - memset_extent_buffer(leaf, 0, 0, sizeof(struct btrfs_header)); - btrfs_set_header_bytenr(leaf, leaf->start); - btrfs_set_header_generation(leaf, trans->transid); - btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV); - btrfs_set_header_owner(leaf, BTRFS_TREE_LOG_OBJECTID); - root->node = leaf; - - write_extent_buffer(root->node, root->fs_info->fsid, - btrfs_header_fsid(), BTRFS_FSID_SIZE); - btrfs_mark_buffer_dirty(root->node); - btrfs_tree_unlock(root->node); - return root; -} - -int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info) -{ - struct btrfs_root *log_root; - - log_root = alloc_log_tree(trans, fs_info); - if (IS_ERR(log_root)) - return PTR_ERR(log_root); - WARN_ON(fs_info->log_root_tree); - fs_info->log_root_tree = log_root; - return 0; -} - -int btrfs_add_log_tree(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_root *log_root; - struct btrfs_inode_item *inode_item; - - log_root = alloc_log_tree(trans, root->fs_info); - if (IS_ERR(log_root)) - return PTR_ERR(log_root); - - log_root->last_trans = trans->transid; - log_root->root_key.offset = root->root_key.objectid; - - inode_item = &log_root->root_item.inode; - btrfs_set_stack_inode_generation(inode_item, 1); - btrfs_set_stack_inode_size(inode_item, 3); - btrfs_set_stack_inode_nlink(inode_item, 1); - btrfs_set_stack_inode_nbytes(inode_item, root->nodesize); - btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755); - - btrfs_set_root_node(&log_root->root_item, log_root->node); - - WARN_ON(root->log_root); - root->log_root = log_root; - root->log_transid = 0; - root->log_transid_committed = -1; - root->last_log_commit = 0; - return 0; -} - -static struct btrfs_root *btrfs_read_tree_root(struct btrfs_root *tree_root, - struct btrfs_key *key) -{ - struct btrfs_root *root; - struct btrfs_fs_info *fs_info = tree_root->fs_info; - struct btrfs_path *path; - u64 generation; - int ret; - - path = btrfs_alloc_path(); - if (!path) - return ERR_PTR(-ENOMEM); - - root = btrfs_alloc_root(fs_info, GFP_NOFS); - if (!root) { - ret = -ENOMEM; - goto alloc_fail; - } - - __setup_root(tree_root->nodesize, tree_root->sectorsize, - tree_root->stripesize, root, fs_info, key->objectid); - - ret = btrfs_find_root(tree_root, key, path, - &root->root_item, &root->root_key); - if (ret) { - if (ret > 0) - ret = -ENOENT; - goto find_fail; - } - - generation = btrfs_root_generation(&root->root_item); - root->node = read_tree_block(root, btrfs_root_bytenr(&root->root_item), - generation); - if (IS_ERR(root->node)) { - ret = PTR_ERR(root->node); - goto find_fail; - } else if (!btrfs_buffer_uptodate(root->node, generation, 0)) { - ret = -EIO; - free_extent_buffer(root->node); - goto find_fail; - } - root->commit_root = btrfs_root_node(root); -out: - btrfs_free_path(path); - return root; - -find_fail: - kfree(root); -alloc_fail: - root = ERR_PTR(ret); - goto out; -} - -struct btrfs_root *btrfs_read_fs_root(struct btrfs_root *tree_root, - struct btrfs_key *location) -{ - struct btrfs_root *root; - - root = btrfs_read_tree_root(tree_root, location); - if (IS_ERR(root)) - return root; - - if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) { - set_bit(BTRFS_ROOT_REF_COWS, &root->state); - btrfs_check_and_init_root_item(&root->root_item); - } - - return root; -} - -int btrfs_init_fs_root(struct btrfs_root *root) -{ - int ret; - struct btrfs_subvolume_writers *writers; - - root->free_ino_ctl = kzalloc(sizeof(*root->free_ino_ctl), GFP_NOFS); - root->free_ino_pinned = kzalloc(sizeof(*root->free_ino_pinned), - GFP_NOFS); - if (!root->free_ino_pinned || !root->free_ino_ctl) { - ret = -ENOMEM; - goto fail; - } - - writers = btrfs_alloc_subvolume_writers(); - if (IS_ERR(writers)) { - ret = PTR_ERR(writers); - goto fail; - } - root->subv_writers = writers; - - btrfs_init_free_ino_ctl(root); - spin_lock_init(&root->ino_cache_lock); - init_waitqueue_head(&root->ino_cache_wait); - - ret = get_anon_bdev(&root->anon_dev); - if (ret) - goto fail; - - mutex_lock(&root->objectid_mutex); - ret = btrfs_find_highest_objectid(root, - &root->highest_objectid); - if (ret) { - mutex_unlock(&root->objectid_mutex); - goto fail; - } - - ASSERT(root->highest_objectid <= BTRFS_LAST_FREE_OBJECTID); - - mutex_unlock(&root->objectid_mutex); - - return 0; -fail: - /* the caller is responsible to call free_fs_root */ - return ret; -} - -struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info, - u64 root_id) -{ - struct btrfs_root *root; - - spin_lock(&fs_info->fs_roots_radix_lock); - root = radix_tree_lookup(&fs_info->fs_roots_radix, - (unsigned long)root_id); - spin_unlock(&fs_info->fs_roots_radix_lock); - return root; -} - -int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info, - struct btrfs_root *root) -{ - int ret; - - ret = radix_tree_preload(GFP_NOFS); - if (ret) - return ret; - - spin_lock(&fs_info->fs_roots_radix_lock); - ret = radix_tree_insert(&fs_info->fs_roots_radix, - (unsigned long)root->root_key.objectid, - root); - if (ret == 0) - set_bit(BTRFS_ROOT_IN_RADIX, &root->state); - spin_unlock(&fs_info->fs_roots_radix_lock); - radix_tree_preload_end(); - - return ret; -} - -struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info, - struct btrfs_key *location, - bool check_ref) -{ - struct btrfs_root *root; - struct btrfs_path *path; - struct btrfs_key key; - int ret; - - if (location->objectid == BTRFS_ROOT_TREE_OBJECTID) - return fs_info->tree_root; - if (location->objectid == BTRFS_EXTENT_TREE_OBJECTID) - return fs_info->extent_root; - if (location->objectid == BTRFS_CHUNK_TREE_OBJECTID) - return fs_info->chunk_root; - if (location->objectid == BTRFS_DEV_TREE_OBJECTID) - return fs_info->dev_root; - if (location->objectid == BTRFS_CSUM_TREE_OBJECTID) - return fs_info->csum_root; - if (location->objectid == BTRFS_QUOTA_TREE_OBJECTID) - return fs_info->quota_root ? fs_info->quota_root : - ERR_PTR(-ENOENT); - if (location->objectid == BTRFS_UUID_TREE_OBJECTID) - return fs_info->uuid_root ? fs_info->uuid_root : - ERR_PTR(-ENOENT); - if (location->objectid == BTRFS_FREE_SPACE_TREE_OBJECTID) - return fs_info->free_space_root ? fs_info->free_space_root : - ERR_PTR(-ENOENT); -again: - root = btrfs_lookup_fs_root(fs_info, location->objectid); - if (root) { - if (check_ref && btrfs_root_refs(&root->root_item) == 0) - return ERR_PTR(-ENOENT); - return root; - } - - root = btrfs_read_fs_root(fs_info->tree_root, location); - if (IS_ERR(root)) - return root; - - if (check_ref && btrfs_root_refs(&root->root_item) == 0) { - ret = -ENOENT; - goto fail; - } - - ret = btrfs_init_fs_root(root); - if (ret) - goto fail; - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto fail; - } - key.objectid = BTRFS_ORPHAN_OBJECTID; - key.type = BTRFS_ORPHAN_ITEM_KEY; - key.offset = location->objectid; - - ret = btrfs_search_slot(NULL, fs_info->tree_root, &key, path, 0, 0); - btrfs_free_path(path); - if (ret < 0) - goto fail; - if (ret == 0) - set_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, &root->state); - - ret = btrfs_insert_fs_root(fs_info, root); - if (ret) { - if (ret == -EEXIST) { - free_fs_root(root); - goto again; - } - goto fail; - } - return root; -fail: - free_fs_root(root); - return ERR_PTR(ret); -} - -static int btrfs_congested_fn(void *congested_data, int bdi_bits) -{ - struct btrfs_fs_info *info = (struct btrfs_fs_info *)congested_data; - int ret = 0; - struct btrfs_device *device; - struct backing_dev_info *bdi; - - rcu_read_lock(); - list_for_each_entry_rcu(device, &info->fs_devices->devices, dev_list) { - if (!device->bdev) - continue; - bdi = blk_get_backing_dev_info(device->bdev); - if (bdi_congested(bdi, bdi_bits)) { - ret = 1; - break; - } - } - rcu_read_unlock(); - return ret; -} - -static int setup_bdi(struct btrfs_fs_info *info, struct backing_dev_info *bdi) -{ - int err; - - err = bdi_setup_and_register(bdi, "btrfs"); - if (err) - return err; - - bdi->ra_pages = VM_MAX_READAHEAD * 1024 / PAGE_SIZE; - bdi->congested_fn = btrfs_congested_fn; - bdi->congested_data = info; - bdi->capabilities |= BDI_CAP_CGROUP_WRITEBACK; - return 0; -} - -/* - * called by the kthread helper functions to finally call the bio end_io - * functions. This is where read checksum verification actually happens - */ -static void end_workqueue_fn(struct btrfs_work *work) -{ - struct bio *bio; - struct btrfs_end_io_wq *end_io_wq; - - end_io_wq = container_of(work, struct btrfs_end_io_wq, work); - bio = end_io_wq->bio; - - bio->bi_error = end_io_wq->error; - bio->bi_private = end_io_wq->private; - bio->bi_end_io = end_io_wq->end_io; - kmem_cache_free(btrfs_end_io_wq_cache, end_io_wq); - bio_endio(bio); -} - -static int cleaner_kthread(void *arg) -{ - struct btrfs_root *root = arg; - int again; - struct btrfs_trans_handle *trans; - - do { - again = 0; - - /* Make the cleaner go to sleep early. */ - if (btrfs_need_cleaner_sleep(root)) - goto sleep; - - /* - * Do not do anything if we might cause open_ctree() to block - * before we have finished mounting the filesystem. - */ - if (!test_bit(BTRFS_FS_OPEN, &root->fs_info->flags)) - goto sleep; - - if (!mutex_trylock(&root->fs_info->cleaner_mutex)) - goto sleep; - - /* - * Avoid the problem that we change the status of the fs - * during the above check and trylock. - */ - if (btrfs_need_cleaner_sleep(root)) { - mutex_unlock(&root->fs_info->cleaner_mutex); - goto sleep; - } - - mutex_lock(&root->fs_info->cleaner_delayed_iput_mutex); - btrfs_run_delayed_iputs(root); - mutex_unlock(&root->fs_info->cleaner_delayed_iput_mutex); - - again = btrfs_clean_one_deleted_snapshot(root); - mutex_unlock(&root->fs_info->cleaner_mutex); - - /* - * The defragger has dealt with the R/O remount and umount, - * needn't do anything special here. - */ - btrfs_run_defrag_inodes(root->fs_info); - - /* - * Acquires fs_info->delete_unused_bgs_mutex to avoid racing - * with relocation (btrfs_relocate_chunk) and relocation - * acquires fs_info->cleaner_mutex (btrfs_relocate_block_group) - * after acquiring fs_info->delete_unused_bgs_mutex. So we - * can't hold, nor need to, fs_info->cleaner_mutex when deleting - * unused block groups. - */ - btrfs_delete_unused_bgs(root->fs_info); -sleep: - if (!again) { - set_current_state(TASK_INTERRUPTIBLE); - if (!kthread_should_stop()) - schedule(); - __set_current_state(TASK_RUNNING); - } - } while (!kthread_should_stop()); - - /* - * Transaction kthread is stopped before us and wakes us up. - * However we might have started a new transaction and COWed some - * tree blocks when deleting unused block groups for example. So - * make sure we commit the transaction we started to have a clean - * shutdown when evicting the btree inode - if it has dirty pages - * when we do the final iput() on it, eviction will trigger a - * writeback for it which will fail with null pointer dereferences - * since work queues and other resources were already released and - * destroyed by the time the iput/eviction/writeback is made. - */ - trans = btrfs_attach_transaction(root); - if (IS_ERR(trans)) { - if (PTR_ERR(trans) != -ENOENT) - btrfs_err(root->fs_info, - "cleaner transaction attach returned %ld", - PTR_ERR(trans)); - } else { - int ret; - - ret = btrfs_commit_transaction(trans, root); - if (ret) - btrfs_err(root->fs_info, - "cleaner open transaction commit returned %d", - ret); - } - - return 0; -} - -static int transaction_kthread(void *arg) -{ - struct btrfs_root *root = arg; - struct btrfs_trans_handle *trans; - struct btrfs_transaction *cur; - u64 transid; - unsigned long now; - unsigned long delay; - bool cannot_commit; - - do { - cannot_commit = false; - delay = HZ * root->fs_info->commit_interval; - mutex_lock(&root->fs_info->transaction_kthread_mutex); - - spin_lock(&root->fs_info->trans_lock); - cur = root->fs_info->running_transaction; - if (!cur) { - spin_unlock(&root->fs_info->trans_lock); - goto sleep; - } - - now = get_seconds(); - if (cur->state < TRANS_STATE_BLOCKED && - (now < cur->start_time || - now - cur->start_time < root->fs_info->commit_interval)) { - spin_unlock(&root->fs_info->trans_lock); - delay = HZ * 5; - goto sleep; - } - transid = cur->transid; - spin_unlock(&root->fs_info->trans_lock); - - /* If the file system is aborted, this will always fail. */ - trans = btrfs_attach_transaction(root); - if (IS_ERR(trans)) { - if (PTR_ERR(trans) != -ENOENT) - cannot_commit = true; - goto sleep; - } - if (transid == trans->transid) { - btrfs_commit_transaction(trans, root); - } else { - btrfs_end_transaction(trans, root); - } -sleep: - wake_up_process(root->fs_info->cleaner_kthread); - mutex_unlock(&root->fs_info->transaction_kthread_mutex); - - if (unlikely(test_bit(BTRFS_FS_STATE_ERROR, - &root->fs_info->fs_state))) - btrfs_cleanup_transaction(root); - set_current_state(TASK_INTERRUPTIBLE); - if (!kthread_should_stop() && - (!btrfs_transaction_blocked(root->fs_info) || - cannot_commit)) - schedule_timeout(delay); - __set_current_state(TASK_RUNNING); - } while (!kthread_should_stop()); - return 0; -} - -/* - * this will find the highest generation in the array of - * root backups. The index of the highest array is returned, - * or -1 if we can't find anything. - * - * We check to make sure the array is valid by comparing the - * generation of the latest root in the array with the generation - * in the super block. If they don't match we pitch it. - */ -static int find_newest_super_backup(struct btrfs_fs_info *info, u64 newest_gen) -{ - u64 cur; - int newest_index = -1; - struct btrfs_root_backup *root_backup; - int i; - - for (i = 0; i < BTRFS_NUM_BACKUP_ROOTS; i++) { - root_backup = info->super_copy->super_roots + i; - cur = btrfs_backup_tree_root_gen(root_backup); - if (cur == newest_gen) - newest_index = i; - } - - /* check to see if we actually wrapped around */ - if (newest_index == BTRFS_NUM_BACKUP_ROOTS - 1) { - root_backup = info->super_copy->super_roots; - cur = btrfs_backup_tree_root_gen(root_backup); - if (cur == newest_gen) - newest_index = 0; - } - return newest_index; -} - - -/* - * find the oldest backup so we know where to store new entries - * in the backup array. This will set the backup_root_index - * field in the fs_info struct - */ -static void find_oldest_super_backup(struct btrfs_fs_info *info, - u64 newest_gen) -{ - int newest_index = -1; - - newest_index = find_newest_super_backup(info, newest_gen); - /* if there was garbage in there, just move along */ - if (newest_index == -1) { - info->backup_root_index = 0; - } else { - info->backup_root_index = (newest_index + 1) % BTRFS_NUM_BACKUP_ROOTS; - } -} - -/* - * copy all the root pointers into the super backup array. - * this will bump the backup pointer by one when it is - * done - */ -static void backup_super_roots(struct btrfs_fs_info *info) -{ - int next_backup; - struct btrfs_root_backup *root_backup; - int last_backup; - - next_backup = info->backup_root_index; - last_backup = (next_backup + BTRFS_NUM_BACKUP_ROOTS - 1) % - BTRFS_NUM_BACKUP_ROOTS; - - /* - * just overwrite the last backup if we're at the same generation - * this happens only at umount - */ - root_backup = info->super_for_commit->super_roots + last_backup; - if (btrfs_backup_tree_root_gen(root_backup) == - btrfs_header_generation(info->tree_root->node)) - next_backup = last_backup; - - root_backup = info->super_for_commit->super_roots + next_backup; - - /* - * make sure all of our padding and empty slots get zero filled - * regardless of which ones we use today - */ - memset(root_backup, 0, sizeof(*root_backup)); - - info->backup_root_index = (next_backup + 1) % BTRFS_NUM_BACKUP_ROOTS; - - btrfs_set_backup_tree_root(root_backup, info->tree_root->node->start); - btrfs_set_backup_tree_root_gen(root_backup, - btrfs_header_generation(info->tree_root->node)); - - btrfs_set_backup_tree_root_level(root_backup, - btrfs_header_level(info->tree_root->node)); - - btrfs_set_backup_chunk_root(root_backup, info->chunk_root->node->start); - btrfs_set_backup_chunk_root_gen(root_backup, - btrfs_header_generation(info->chunk_root->node)); - btrfs_set_backup_chunk_root_level(root_backup, - btrfs_header_level(info->chunk_root->node)); - - btrfs_set_backup_extent_root(root_backup, info->extent_root->node->start); - btrfs_set_backup_extent_root_gen(root_backup, - btrfs_header_generation(info->extent_root->node)); - btrfs_set_backup_extent_root_level(root_backup, - btrfs_header_level(info->extent_root->node)); - - /* - * we might commit during log recovery, which happens before we set - * the fs_root. Make sure it is valid before we fill it in. - */ - if (info->fs_root && info->fs_root->node) { - btrfs_set_backup_fs_root(root_backup, - info->fs_root->node->start); - btrfs_set_backup_fs_root_gen(root_backup, - btrfs_header_generation(info->fs_root->node)); - btrfs_set_backup_fs_root_level(root_backup, - btrfs_header_level(info->fs_root->node)); - } - - btrfs_set_backup_dev_root(root_backup, info->dev_root->node->start); - btrfs_set_backup_dev_root_gen(root_backup, - btrfs_header_generation(info->dev_root->node)); - btrfs_set_backup_dev_root_level(root_backup, - btrfs_header_level(info->dev_root->node)); - - btrfs_set_backup_csum_root(root_backup, info->csum_root->node->start); - btrfs_set_backup_csum_root_gen(root_backup, - btrfs_header_generation(info->csum_root->node)); - btrfs_set_backup_csum_root_level(root_backup, - btrfs_header_level(info->csum_root->node)); - - btrfs_set_backup_total_bytes(root_backup, - btrfs_super_total_bytes(info->super_copy)); - btrfs_set_backup_bytes_used(root_backup, - btrfs_super_bytes_used(info->super_copy)); - btrfs_set_backup_num_devices(root_backup, - btrfs_super_num_devices(info->super_copy)); - - /* - * if we don't copy this out to the super_copy, it won't get remembered - * for the next commit - */ - memcpy(&info->super_copy->super_roots, - &info->super_for_commit->super_roots, - sizeof(*root_backup) * BTRFS_NUM_BACKUP_ROOTS); -} - -/* - * this copies info out of the root backup array and back into - * the in-memory super block. It is meant to help iterate through - * the array, so you send it the number of backups you've already - * tried and the last backup index you used. - * - * this returns -1 when it has tried all the backups - */ -static noinline int next_root_backup(struct btrfs_fs_info *info, - struct btrfs_super_block *super, - int *num_backups_tried, int *backup_index) -{ - struct btrfs_root_backup *root_backup; - int newest = *backup_index; - - if (*num_backups_tried == 0) { - u64 gen = btrfs_super_generation(super); - - newest = find_newest_super_backup(info, gen); - if (newest == -1) - return -1; - - *backup_index = newest; - *num_backups_tried = 1; - } else if (*num_backups_tried == BTRFS_NUM_BACKUP_ROOTS) { - /* we've tried all the backups, all done */ - return -1; - } else { - /* jump to the next oldest backup */ - newest = (*backup_index + BTRFS_NUM_BACKUP_ROOTS - 1) % - BTRFS_NUM_BACKUP_ROOTS; - *backup_index = newest; - *num_backups_tried += 1; - } - root_backup = super->super_roots + newest; - - btrfs_set_super_generation(super, - btrfs_backup_tree_root_gen(root_backup)); - btrfs_set_super_root(super, btrfs_backup_tree_root(root_backup)); - btrfs_set_super_root_level(super, - btrfs_backup_tree_root_level(root_backup)); - btrfs_set_super_bytes_used(super, btrfs_backup_bytes_used(root_backup)); - - /* - * fixme: the total bytes and num_devices need to match or we should - * need a fsck - */ - btrfs_set_super_total_bytes(super, btrfs_backup_total_bytes(root_backup)); - btrfs_set_super_num_devices(super, btrfs_backup_num_devices(root_backup)); - return 0; -} - -/* helper to cleanup workers */ -static void btrfs_stop_all_workers(struct btrfs_fs_info *fs_info) -{ - btrfs_destroy_workqueue(fs_info->fixup_workers); - btrfs_destroy_workqueue(fs_info->delalloc_workers); - btrfs_destroy_workqueue(fs_info->workers); - btrfs_destroy_workqueue(fs_info->endio_workers); - btrfs_destroy_workqueue(fs_info->endio_meta_workers); - btrfs_destroy_workqueue(fs_info->endio_raid56_workers); - btrfs_destroy_workqueue(fs_info->endio_repair_workers); - btrfs_destroy_workqueue(fs_info->rmw_workers); - btrfs_destroy_workqueue(fs_info->endio_meta_write_workers); - btrfs_destroy_workqueue(fs_info->endio_write_workers); - btrfs_destroy_workqueue(fs_info->endio_freespace_worker); - btrfs_destroy_workqueue(fs_info->submit_workers); - btrfs_destroy_workqueue(fs_info->delayed_workers); - btrfs_destroy_workqueue(fs_info->caching_workers); - btrfs_destroy_workqueue(fs_info->readahead_workers); - btrfs_destroy_workqueue(fs_info->flush_workers); - btrfs_destroy_workqueue(fs_info->qgroup_rescan_workers); - btrfs_destroy_workqueue(fs_info->extent_workers); -} - -static void free_root_extent_buffers(struct btrfs_root *root) -{ - if (root) { - free_extent_buffer(root->node); - free_extent_buffer(root->commit_root); - root->node = NULL; - root->commit_root = NULL; - } -} - -/* helper to cleanup tree roots */ -static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root) -{ - free_root_extent_buffers(info->tree_root); - - free_root_extent_buffers(info->dev_root); - free_root_extent_buffers(info->extent_root); - free_root_extent_buffers(info->csum_root); - free_root_extent_buffers(info->quota_root); - free_root_extent_buffers(info->uuid_root); - if (chunk_root) - free_root_extent_buffers(info->chunk_root); - free_root_extent_buffers(info->free_space_root); -} - -void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info) -{ - int ret; - struct btrfs_root *gang[8]; - int i; - - while (!list_empty(&fs_info->dead_roots)) { - gang[0] = list_entry(fs_info->dead_roots.next, - struct btrfs_root, root_list); - list_del(&gang[0]->root_list); - - if (test_bit(BTRFS_ROOT_IN_RADIX, &gang[0]->state)) { - btrfs_drop_and_free_fs_root(fs_info, gang[0]); - } else { - free_extent_buffer(gang[0]->node); - free_extent_buffer(gang[0]->commit_root); - btrfs_put_fs_root(gang[0]); - } - } - - while (1) { - ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix, - (void **)gang, 0, - ARRAY_SIZE(gang)); - if (!ret) - break; - for (i = 0; i < ret; i++) - btrfs_drop_and_free_fs_root(fs_info, gang[i]); - } - - if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) { - btrfs_free_log_root_tree(NULL, fs_info); - btrfs_destroy_pinned_extent(fs_info->tree_root, - fs_info->pinned_extents); - } -} - -static void btrfs_init_scrub(struct btrfs_fs_info *fs_info) -{ - mutex_init(&fs_info->scrub_lock); - atomic_set(&fs_info->scrubs_running, 0); - atomic_set(&fs_info->scrub_pause_req, 0); - atomic_set(&fs_info->scrubs_paused, 0); - atomic_set(&fs_info->scrub_cancel_req, 0); - init_waitqueue_head(&fs_info->scrub_pause_wait); - fs_info->scrub_workers_refcnt = 0; -} - -static void btrfs_init_balance(struct btrfs_fs_info *fs_info) -{ - spin_lock_init(&fs_info->balance_lock); - mutex_init(&fs_info->balance_mutex); - atomic_set(&fs_info->balance_running, 0); - atomic_set(&fs_info->balance_pause_req, 0); - atomic_set(&fs_info->balance_cancel_req, 0); - fs_info->balance_ctl = NULL; - init_waitqueue_head(&fs_info->balance_wait_q); -} - -static void btrfs_init_btree_inode(struct btrfs_fs_info *fs_info, - struct btrfs_root *tree_root) -{ - fs_info->btree_inode->i_ino = BTRFS_BTREE_INODE_OBJECTID; - set_nlink(fs_info->btree_inode, 1); - /* - * we set the i_size on the btree inode to the max possible int. - * the real end of the address space is determined by all of - * the devices in the system - */ - fs_info->btree_inode->i_size = OFFSET_MAX; - fs_info->btree_inode->i_mapping->a_ops = &btree_aops; - - RB_CLEAR_NODE(&BTRFS_I(fs_info->btree_inode)->rb_node); - extent_io_tree_init(&BTRFS_I(fs_info->btree_inode)->io_tree, - fs_info->btree_inode->i_mapping); - BTRFS_I(fs_info->btree_inode)->io_tree.track_uptodate = 0; - extent_map_tree_init(&BTRFS_I(fs_info->btree_inode)->extent_tree); - - BTRFS_I(fs_info->btree_inode)->io_tree.ops = &btree_extent_io_ops; - - BTRFS_I(fs_info->btree_inode)->root = tree_root; - memset(&BTRFS_I(fs_info->btree_inode)->location, 0, - sizeof(struct btrfs_key)); - set_bit(BTRFS_INODE_DUMMY, - &BTRFS_I(fs_info->btree_inode)->runtime_flags); - btrfs_insert_inode_hash(fs_info->btree_inode); -} - -static void btrfs_init_dev_replace_locks(struct btrfs_fs_info *fs_info) -{ - fs_info->dev_replace.lock_owner = 0; - atomic_set(&fs_info->dev_replace.nesting_level, 0); - mutex_init(&fs_info->dev_replace.lock_finishing_cancel_unmount); - rwlock_init(&fs_info->dev_replace.lock); - atomic_set(&fs_info->dev_replace.read_locks, 0); - atomic_set(&fs_info->dev_replace.blocking_readers, 0); - init_waitqueue_head(&fs_info->replace_wait); - init_waitqueue_head(&fs_info->dev_replace.read_lock_wq); -} - -static void btrfs_init_qgroup(struct btrfs_fs_info *fs_info) -{ - spin_lock_init(&fs_info->qgroup_lock); - mutex_init(&fs_info->qgroup_ioctl_lock); - fs_info->qgroup_tree = RB_ROOT; - fs_info->qgroup_op_tree = RB_ROOT; - INIT_LIST_HEAD(&fs_info->dirty_qgroups); - fs_info->qgroup_seq = 1; - fs_info->qgroup_ulist = NULL; - fs_info->qgroup_rescan_running = false; - mutex_init(&fs_info->qgroup_rescan_lock); -} - -static int btrfs_init_workqueues(struct btrfs_fs_info *fs_info, - struct btrfs_fs_devices *fs_devices) -{ - int max_active = fs_info->thread_pool_size; - unsigned int flags = WQ_MEM_RECLAIM | WQ_FREEZABLE | WQ_UNBOUND; - - fs_info->workers = - btrfs_alloc_workqueue(fs_info, "worker", - flags | WQ_HIGHPRI, max_active, 16); - - fs_info->delalloc_workers = - btrfs_alloc_workqueue(fs_info, "delalloc", - flags, max_active, 2); - - fs_info->flush_workers = - btrfs_alloc_workqueue(fs_info, "flush_delalloc", - flags, max_active, 0); - - fs_info->caching_workers = - btrfs_alloc_workqueue(fs_info, "cache", flags, max_active, 0); - - /* - * a higher idle thresh on the submit workers makes it much more - * likely that bios will be send down in a sane order to the - * devices - */ - fs_info->submit_workers = - btrfs_alloc_workqueue(fs_info, "submit", flags, - min_t(u64, fs_devices->num_devices, - max_active), 64); - - fs_info->fixup_workers = - btrfs_alloc_workqueue(fs_info, "fixup", flags, 1, 0); - - /* - * endios are largely parallel and should have a very - * low idle thresh - */ - fs_info->endio_workers = - btrfs_alloc_workqueue(fs_info, "endio", flags, max_active, 4); - fs_info->endio_meta_workers = - btrfs_alloc_workqueue(fs_info, "endio-meta", flags, - max_active, 4); - fs_info->endio_meta_write_workers = - btrfs_alloc_workqueue(fs_info, "endio-meta-write", flags, - max_active, 2); - fs_info->endio_raid56_workers = - btrfs_alloc_workqueue(fs_info, "endio-raid56", flags, - max_active, 4); - fs_info->endio_repair_workers = - btrfs_alloc_workqueue(fs_info, "endio-repair", flags, 1, 0); - fs_info->rmw_workers = - btrfs_alloc_workqueue(fs_info, "rmw", flags, max_active, 2); - fs_info->endio_write_workers = - btrfs_alloc_workqueue(fs_info, "endio-write", flags, - max_active, 2); - fs_info->endio_freespace_worker = - btrfs_alloc_workqueue(fs_info, "freespace-write", flags, - max_active, 0); - fs_info->delayed_workers = - btrfs_alloc_workqueue(fs_info, "delayed-meta", flags, - max_active, 0); - fs_info->readahead_workers = - btrfs_alloc_workqueue(fs_info, "readahead", flags, - max_active, 2); - fs_info->qgroup_rescan_workers = - btrfs_alloc_workqueue(fs_info, "qgroup-rescan", flags, 1, 0); - fs_info->extent_workers = - btrfs_alloc_workqueue(fs_info, "extent-refs", flags, - min_t(u64, fs_devices->num_devices, - max_active), 8); - - if (!(fs_info->workers && fs_info->delalloc_workers && - fs_info->submit_workers && fs_info->flush_workers && - fs_info->endio_workers && fs_info->endio_meta_workers && - fs_info->endio_meta_write_workers && - fs_info->endio_repair_workers && - fs_info->endio_write_workers && fs_info->endio_raid56_workers && - fs_info->endio_freespace_worker && fs_info->rmw_workers && - fs_info->caching_workers && fs_info->readahead_workers && - fs_info->fixup_workers && fs_info->delayed_workers && - fs_info->extent_workers && - fs_info->qgroup_rescan_workers)) { - return -ENOMEM; - } - - return 0; -} - -static int btrfs_replay_log(struct btrfs_fs_info *fs_info, - struct btrfs_fs_devices *fs_devices) -{ - int ret; - struct btrfs_root *tree_root = fs_info->tree_root; - struct btrfs_root *log_tree_root; - struct btrfs_super_block *disk_super = fs_info->super_copy; - u64 bytenr = btrfs_super_log_root(disk_super); - - if (fs_devices->rw_devices == 0) { - btrfs_warn(fs_info, "log replay required on RO media"); - return -EIO; - } - - log_tree_root = btrfs_alloc_root(fs_info, GFP_KERNEL); - if (!log_tree_root) - return -ENOMEM; - - __setup_root(tree_root->nodesize, tree_root->sectorsize, - tree_root->stripesize, log_tree_root, fs_info, - BTRFS_TREE_LOG_OBJECTID); - - log_tree_root->node = read_tree_block(tree_root, bytenr, - fs_info->generation + 1); - if (IS_ERR(log_tree_root->node)) { - btrfs_warn(fs_info, "failed to read log tree"); - ret = PTR_ERR(log_tree_root->node); - kfree(log_tree_root); - return ret; - } else if (!extent_buffer_uptodate(log_tree_root->node)) { - btrfs_err(fs_info, "failed to read log tree"); - free_extent_buffer(log_tree_root->node); - kfree(log_tree_root); - return -EIO; - } - /* returns with log_tree_root freed on success */ - ret = btrfs_recover_log_trees(log_tree_root); - if (ret) { - btrfs_handle_fs_error(tree_root->fs_info, ret, - "Failed to recover log tree"); - free_extent_buffer(log_tree_root->node); - kfree(log_tree_root); - return ret; - } - - if (fs_info->sb->s_flags & MS_RDONLY) { - ret = btrfs_commit_super(tree_root); - if (ret) - return ret; - } - - return 0; -} - -static int btrfs_read_roots(struct btrfs_fs_info *fs_info, - struct btrfs_root *tree_root) -{ - struct btrfs_root *root; - struct btrfs_key location; - int ret; - - location.objectid = BTRFS_EXTENT_TREE_OBJECTID; - location.type = BTRFS_ROOT_ITEM_KEY; - location.offset = 0; - - root = btrfs_read_tree_root(tree_root, &location); - if (IS_ERR(root)) - return PTR_ERR(root); - set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); - fs_info->extent_root = root; - - location.objectid = BTRFS_DEV_TREE_OBJECTID; - root = btrfs_read_tree_root(tree_root, &location); - if (IS_ERR(root)) - return PTR_ERR(root); - set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); - fs_info->dev_root = root; - btrfs_init_devices_late(fs_info); - - location.objectid = BTRFS_CSUM_TREE_OBJECTID; - root = btrfs_read_tree_root(tree_root, &location); - if (IS_ERR(root)) - return PTR_ERR(root); - set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); - fs_info->csum_root = root; - - location.objectid = BTRFS_QUOTA_TREE_OBJECTID; - root = btrfs_read_tree_root(tree_root, &location); - if (!IS_ERR(root)) { - set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); - set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); - fs_info->quota_root = root; - } - - location.objectid = BTRFS_UUID_TREE_OBJECTID; - root = btrfs_read_tree_root(tree_root, &location); - if (IS_ERR(root)) { - ret = PTR_ERR(root); - if (ret != -ENOENT) - return ret; - } else { - set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); - fs_info->uuid_root = root; - } - - if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { - location.objectid = BTRFS_FREE_SPACE_TREE_OBJECTID; - root = btrfs_read_tree_root(tree_root, &location); - if (IS_ERR(root)) - return PTR_ERR(root); - set_bit(BTRFS_ROOT_TRACK_DIRTY, &root->state); - fs_info->free_space_root = root; - } - - return 0; -} - -int open_ctree(struct super_block *sb, - struct btrfs_fs_devices *fs_devices, - char *options) -{ - u32 sectorsize; - u32 nodesize; - u32 stripesize; - u64 generation; - u64 features; - struct btrfs_key location; - struct buffer_head *bh; - struct btrfs_super_block *disk_super; - struct btrfs_fs_info *fs_info = btrfs_sb(sb); - struct btrfs_root *tree_root; - struct btrfs_root *chunk_root; - int ret; - int err = -EINVAL; - int num_backups_tried = 0; - int backup_index = 0; - int max_active; - int clear_free_space_tree = 0; - - tree_root = fs_info->tree_root = btrfs_alloc_root(fs_info, GFP_KERNEL); - chunk_root = fs_info->chunk_root = btrfs_alloc_root(fs_info, GFP_KERNEL); - if (!tree_root || !chunk_root) { - err = -ENOMEM; - goto fail; - } - - ret = init_srcu_struct(&fs_info->subvol_srcu); - if (ret) { - err = ret; - goto fail; - } - - ret = setup_bdi(fs_info, &fs_info->bdi); - if (ret) { - err = ret; - goto fail_srcu; - } - - ret = percpu_counter_init(&fs_info->dirty_metadata_bytes, 0, GFP_KERNEL); - if (ret) { - err = ret; - goto fail_bdi; - } - fs_info->dirty_metadata_batch = PAGE_SIZE * - (1 + ilog2(nr_cpu_ids)); - - ret = percpu_counter_init(&fs_info->delalloc_bytes, 0, GFP_KERNEL); - if (ret) { - err = ret; - goto fail_dirty_metadata_bytes; - } - - ret = percpu_counter_init(&fs_info->bio_counter, 0, GFP_KERNEL); - if (ret) { - err = ret; - goto fail_delalloc_bytes; - } - - fs_info->btree_inode = new_inode(sb); - if (!fs_info->btree_inode) { - err = -ENOMEM; - goto fail_bio_counter; - } - - mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS); - - INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC); - INIT_RADIX_TREE(&fs_info->buffer_radix, GFP_ATOMIC); - INIT_LIST_HEAD(&fs_info->trans_list); - INIT_LIST_HEAD(&fs_info->dead_roots); - INIT_LIST_HEAD(&fs_info->delayed_iputs); - INIT_LIST_HEAD(&fs_info->delalloc_roots); - INIT_LIST_HEAD(&fs_info->caching_block_groups); - spin_lock_init(&fs_info->delalloc_root_lock); - spin_lock_init(&fs_info->trans_lock); - spin_lock_init(&fs_info->fs_roots_radix_lock); - spin_lock_init(&fs_info->delayed_iput_lock); - spin_lock_init(&fs_info->defrag_inodes_lock); - spin_lock_init(&fs_info->free_chunk_lock); - spin_lock_init(&fs_info->tree_mod_seq_lock); - spin_lock_init(&fs_info->super_lock); - spin_lock_init(&fs_info->qgroup_op_lock); - spin_lock_init(&fs_info->buffer_lock); - spin_lock_init(&fs_info->unused_bgs_lock); - rwlock_init(&fs_info->tree_mod_log_lock); - mutex_init(&fs_info->unused_bg_unpin_mutex); - mutex_init(&fs_info->delete_unused_bgs_mutex); - mutex_init(&fs_info->reloc_mutex); - mutex_init(&fs_info->delalloc_root_mutex); - mutex_init(&fs_info->cleaner_delayed_iput_mutex); - seqlock_init(&fs_info->profiles_lock); - - INIT_LIST_HEAD(&fs_info->dirty_cowonly_roots); - INIT_LIST_HEAD(&fs_info->space_info); - INIT_LIST_HEAD(&fs_info->tree_mod_seq_list); - INIT_LIST_HEAD(&fs_info->unused_bgs); - btrfs_mapping_init(&fs_info->mapping_tree); - btrfs_init_block_rsv(&fs_info->global_block_rsv, - BTRFS_BLOCK_RSV_GLOBAL); - btrfs_init_block_rsv(&fs_info->delalloc_block_rsv, - BTRFS_BLOCK_RSV_DELALLOC); - btrfs_init_block_rsv(&fs_info->trans_block_rsv, BTRFS_BLOCK_RSV_TRANS); - btrfs_init_block_rsv(&fs_info->chunk_block_rsv, BTRFS_BLOCK_RSV_CHUNK); - btrfs_init_block_rsv(&fs_info->empty_block_rsv, BTRFS_BLOCK_RSV_EMPTY); - btrfs_init_block_rsv(&fs_info->delayed_block_rsv, - BTRFS_BLOCK_RSV_DELOPS); - atomic_set(&fs_info->nr_async_submits, 0); - atomic_set(&fs_info->async_delalloc_pages, 0); - atomic_set(&fs_info->async_submit_draining, 0); - atomic_set(&fs_info->nr_async_bios, 0); - atomic_set(&fs_info->defrag_running, 0); - atomic_set(&fs_info->qgroup_op_seq, 0); - atomic_set(&fs_info->reada_works_cnt, 0); - atomic64_set(&fs_info->tree_mod_seq, 0); - fs_info->fs_frozen = 0; - fs_info->sb = sb; - fs_info->max_inline = BTRFS_DEFAULT_MAX_INLINE; - fs_info->metadata_ratio = 0; - fs_info->defrag_inodes = RB_ROOT; - fs_info->free_chunk_space = 0; - fs_info->tree_mod_log = RB_ROOT; - fs_info->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL; - fs_info->avg_delayed_ref_runtime = NSEC_PER_SEC >> 6; /* div by 64 */ - /* readahead state */ - INIT_RADIX_TREE(&fs_info->reada_tree, GFP_NOFS & ~__GFP_DIRECT_RECLAIM); - spin_lock_init(&fs_info->reada_lock); - - fs_info->thread_pool_size = min_t(unsigned long, - num_online_cpus() + 2, 8); - - INIT_LIST_HEAD(&fs_info->ordered_roots); - spin_lock_init(&fs_info->ordered_root_lock); - fs_info->delayed_root = kmalloc(sizeof(struct btrfs_delayed_root), - GFP_KERNEL); - if (!fs_info->delayed_root) { - err = -ENOMEM; - goto fail_iput; - } - btrfs_init_delayed_root(fs_info->delayed_root); - - btrfs_init_scrub(fs_info); -#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY - fs_info->check_integrity_print_mask = 0; -#endif - btrfs_init_balance(fs_info); - btrfs_init_async_reclaim_work(&fs_info->async_reclaim_work); - - sb->s_blocksize = 4096; - sb->s_blocksize_bits = blksize_bits(4096); - sb->s_bdi = &fs_info->bdi; - - btrfs_init_btree_inode(fs_info, tree_root); - - spin_lock_init(&fs_info->block_group_cache_lock); - fs_info->block_group_cache_tree = RB_ROOT; - fs_info->first_logical_byte = (u64)-1; - - extent_io_tree_init(&fs_info->freed_extents[0], - fs_info->btree_inode->i_mapping); - extent_io_tree_init(&fs_info->freed_extents[1], - fs_info->btree_inode->i_mapping); - fs_info->pinned_extents = &fs_info->freed_extents[0]; - set_bit(BTRFS_FS_BARRIER, &fs_info->flags); - - mutex_init(&fs_info->ordered_operations_mutex); - mutex_init(&fs_info->tree_log_mutex); - mutex_init(&fs_info->chunk_mutex); - mutex_init(&fs_info->transaction_kthread_mutex); - mutex_init(&fs_info->cleaner_mutex); - mutex_init(&fs_info->volume_mutex); - mutex_init(&fs_info->ro_block_group_mutex); - init_rwsem(&fs_info->commit_root_sem); - init_rwsem(&fs_info->cleanup_work_sem); - init_rwsem(&fs_info->subvol_sem); - sema_init(&fs_info->uuid_tree_rescan_sem, 1); - - btrfs_init_dev_replace_locks(fs_info); - btrfs_init_qgroup(fs_info); - - btrfs_init_free_cluster(&fs_info->meta_alloc_cluster); - btrfs_init_free_cluster(&fs_info->data_alloc_cluster); - - init_waitqueue_head(&fs_info->transaction_throttle); - init_waitqueue_head(&fs_info->transaction_wait); - init_waitqueue_head(&fs_info->transaction_blocked_wait); - init_waitqueue_head(&fs_info->async_submit_wait); - - INIT_LIST_HEAD(&fs_info->pinned_chunks); - - ret = btrfs_alloc_stripe_hash_table(fs_info); - if (ret) { - err = ret; - goto fail_alloc; - } - - __setup_root(4096, 4096, 4096, tree_root, - fs_info, BTRFS_ROOT_TREE_OBJECTID); - - invalidate_bdev(fs_devices->latest_bdev); - - /* - * Read super block and check the signature bytes only - */ - bh = btrfs_read_dev_super(fs_devices->latest_bdev); - if (IS_ERR(bh)) { - err = PTR_ERR(bh); - goto fail_alloc; - } - - /* - * We want to check superblock checksum, the type is stored inside. - * Pass the whole disk block of size BTRFS_SUPER_INFO_SIZE (4k). - */ - if (btrfs_check_super_csum(fs_info, bh->b_data)) { - btrfs_err(fs_info, "superblock checksum mismatch"); - err = -EINVAL; - brelse(bh); - goto fail_alloc; - } - - /* - * super_copy is zeroed at allocation time and we never touch the - * following bytes up to INFO_SIZE, the checksum is calculated from - * the whole block of INFO_SIZE - */ - memcpy(fs_info->super_copy, bh->b_data, sizeof(*fs_info->super_copy)); - memcpy(fs_info->super_for_commit, fs_info->super_copy, - sizeof(*fs_info->super_for_commit)); - brelse(bh); - - memcpy(fs_info->fsid, fs_info->super_copy->fsid, BTRFS_FSID_SIZE); - - ret = btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY); - if (ret) { - btrfs_err(fs_info, "superblock contains fatal errors"); - err = -EINVAL; - goto fail_alloc; - } - - disk_super = fs_info->super_copy; - if (!btrfs_super_root(disk_super)) - goto fail_alloc; - - /* check FS state, whether FS is broken. */ - if (btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_ERROR) - set_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state); - - /* - * run through our array of backup supers and setup - * our ring pointer to the oldest one - */ - generation = btrfs_super_generation(disk_super); - find_oldest_super_backup(fs_info, generation); - - /* - * In the long term, we'll store the compression type in the super - * block, and it'll be used for per file compression control. - */ - fs_info->compress_type = BTRFS_COMPRESS_ZLIB; - - ret = btrfs_parse_options(tree_root, options, sb->s_flags); - if (ret) { - err = ret; - goto fail_alloc; - } - - features = btrfs_super_incompat_flags(disk_super) & - ~BTRFS_FEATURE_INCOMPAT_SUPP; - if (features) { - btrfs_err(fs_info, - "cannot mount because of unsupported optional features (%llx)", - features); - err = -EINVAL; - goto fail_alloc; - } - - features = btrfs_super_incompat_flags(disk_super); - features |= BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF; - if (tree_root->fs_info->compress_type == BTRFS_COMPRESS_LZO) - features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO; - - if (features & BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA) - btrfs_info(fs_info, "has skinny extents"); - - /* - * flag our filesystem as having big metadata blocks if - * they are bigger than the page size - */ - if (btrfs_super_nodesize(disk_super) > PAGE_SIZE) { - if (!(features & BTRFS_FEATURE_INCOMPAT_BIG_METADATA)) - btrfs_info(fs_info, - "flagging fs with big metadata feature"); - features |= BTRFS_FEATURE_INCOMPAT_BIG_METADATA; - } - - nodesize = btrfs_super_nodesize(disk_super); - sectorsize = btrfs_super_sectorsize(disk_super); - stripesize = sectorsize; - fs_info->dirty_metadata_batch = nodesize * (1 + ilog2(nr_cpu_ids)); - fs_info->delalloc_batch = sectorsize * 512 * (1 + ilog2(nr_cpu_ids)); - - /* - * mixed block groups end up with duplicate but slightly offset - * extent buffers for the same range. It leads to corruptions - */ - if ((features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) && - (sectorsize != nodesize)) { - btrfs_err(fs_info, -"unequal nodesize/sectorsize (%u != %u) are not allowed for mixed block groups", - nodesize, sectorsize); - goto fail_alloc; - } - - /* - * Needn't use the lock because there is no other task which will - * update the flag. - */ - btrfs_set_super_incompat_flags(disk_super, features); - - features = btrfs_super_compat_ro_flags(disk_super) & - ~BTRFS_FEATURE_COMPAT_RO_SUPP; - if (!(sb->s_flags & MS_RDONLY) && features) { - btrfs_err(fs_info, - "cannot mount read-write because of unsupported optional features (%llx)", - features); - err = -EINVAL; - goto fail_alloc; - } - - max_active = fs_info->thread_pool_size; - - ret = btrfs_init_workqueues(fs_info, fs_devices); - if (ret) { - err = ret; - goto fail_sb_buffer; - } - - fs_info->bdi.ra_pages *= btrfs_super_num_devices(disk_super); - fs_info->bdi.ra_pages = max(fs_info->bdi.ra_pages, - SZ_4M / PAGE_SIZE); - - tree_root->nodesize = nodesize; - tree_root->sectorsize = sectorsize; - tree_root->stripesize = stripesize; - - sb->s_blocksize = sectorsize; - sb->s_blocksize_bits = blksize_bits(sectorsize); - - mutex_lock(&fs_info->chunk_mutex); - ret = btrfs_read_sys_array(tree_root); - mutex_unlock(&fs_info->chunk_mutex); - if (ret) { - btrfs_err(fs_info, "failed to read the system array: %d", ret); - goto fail_sb_buffer; - } - - generation = btrfs_super_chunk_root_generation(disk_super); - - __setup_root(nodesize, sectorsize, stripesize, chunk_root, - fs_info, BTRFS_CHUNK_TREE_OBJECTID); - - chunk_root->node = read_tree_block(chunk_root, - btrfs_super_chunk_root(disk_super), - generation); - if (IS_ERR(chunk_root->node) || - !extent_buffer_uptodate(chunk_root->node)) { - btrfs_err(fs_info, "failed to read chunk root"); - if (!IS_ERR(chunk_root->node)) - free_extent_buffer(chunk_root->node); - chunk_root->node = NULL; - goto fail_tree_roots; - } - btrfs_set_root_node(&chunk_root->root_item, chunk_root->node); - chunk_root->commit_root = btrfs_root_node(chunk_root); - - read_extent_buffer(chunk_root->node, fs_info->chunk_tree_uuid, - btrfs_header_chunk_tree_uuid(chunk_root->node), BTRFS_UUID_SIZE); - - ret = btrfs_read_chunk_tree(chunk_root); - if (ret) { - btrfs_err(fs_info, "failed to read chunk tree: %d", ret); - goto fail_tree_roots; - } - - /* - * keep the device that is marked to be the target device for the - * dev_replace procedure - */ - btrfs_close_extra_devices(fs_devices, 0); - - if (!fs_devices->latest_bdev) { - btrfs_err(fs_info, "failed to read devices"); - goto fail_tree_roots; - } - -retry_root_backup: - generation = btrfs_super_generation(disk_super); - - tree_root->node = read_tree_block(tree_root, - btrfs_super_root(disk_super), - generation); - if (IS_ERR(tree_root->node) || - !extent_buffer_uptodate(tree_root->node)) { - btrfs_warn(fs_info, "failed to read tree root"); - if (!IS_ERR(tree_root->node)) - free_extent_buffer(tree_root->node); - tree_root->node = NULL; - goto recovery_tree_root; - } - - btrfs_set_root_node(&tree_root->root_item, tree_root->node); - tree_root->commit_root = btrfs_root_node(tree_root); - btrfs_set_root_refs(&tree_root->root_item, 1); - - mutex_lock(&tree_root->objectid_mutex); - ret = btrfs_find_highest_objectid(tree_root, - &tree_root->highest_objectid); - if (ret) { - mutex_unlock(&tree_root->objectid_mutex); - goto recovery_tree_root; - } - - ASSERT(tree_root->highest_objectid <= BTRFS_LAST_FREE_OBJECTID); - - mutex_unlock(&tree_root->objectid_mutex); - - ret = btrfs_read_roots(fs_info, tree_root); - if (ret) - goto recovery_tree_root; - - fs_info->generation = generation; - fs_info->last_trans_committed = generation; - - ret = btrfs_recover_balance(fs_info); - if (ret) { - btrfs_err(fs_info, "failed to recover balance: %d", ret); - goto fail_block_groups; - } - - ret = btrfs_init_dev_stats(fs_info); - if (ret) { - btrfs_err(fs_info, "failed to init dev_stats: %d", ret); - goto fail_block_groups; - } - - ret = btrfs_init_dev_replace(fs_info); - if (ret) { - btrfs_err(fs_info, "failed to init dev_replace: %d", ret); - goto fail_block_groups; - } - - btrfs_close_extra_devices(fs_devices, 1); - - ret = btrfs_sysfs_add_fsid(fs_devices, NULL); - if (ret) { - btrfs_err(fs_info, "failed to init sysfs fsid interface: %d", - ret); - goto fail_block_groups; - } - - ret = btrfs_sysfs_add_device(fs_devices); - if (ret) { - btrfs_err(fs_info, "failed to init sysfs device interface: %d", - ret); - goto fail_fsdev_sysfs; - } - - ret = btrfs_sysfs_add_mounted(fs_info); - if (ret) { - btrfs_err(fs_info, "failed to init sysfs interface: %d", ret); - goto fail_fsdev_sysfs; - } - - ret = btrfs_init_space_info(fs_info); - if (ret) { - btrfs_err(fs_info, "failed to initialize space info: %d", ret); - goto fail_sysfs; - } - - ret = btrfs_read_block_groups(fs_info->extent_root); - if (ret) { - btrfs_err(fs_info, "failed to read block groups: %d", ret); - goto fail_sysfs; - } - fs_info->num_tolerated_disk_barrier_failures = - btrfs_calc_num_tolerated_disk_barrier_failures(fs_info); - if (fs_info->fs_devices->missing_devices > - fs_info->num_tolerated_disk_barrier_failures && - !(sb->s_flags & MS_RDONLY)) { - btrfs_warn(fs_info, -"missing devices (%llu) exceeds the limit (%d), writeable mount is not allowed", - fs_info->fs_devices->missing_devices, - fs_info->num_tolerated_disk_barrier_failures); - goto fail_sysfs; - } - - fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root, - "btrfs-cleaner"); - if (IS_ERR(fs_info->cleaner_kthread)) - goto fail_sysfs; - - fs_info->transaction_kthread = kthread_run(transaction_kthread, - tree_root, - "btrfs-transaction"); - if (IS_ERR(fs_info->transaction_kthread)) - goto fail_cleaner; - - if (!btrfs_test_opt(tree_root->fs_info, SSD) && - !btrfs_test_opt(tree_root->fs_info, NOSSD) && - !fs_info->fs_devices->rotating) { - btrfs_info(fs_info, "detected SSD devices, enabling SSD mode"); - btrfs_set_opt(fs_info->mount_opt, SSD); - } - - /* - * Mount does not set all options immediately, we can do it now and do - * not have to wait for transaction commit - */ - btrfs_apply_pending_changes(fs_info); - -#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY - if (btrfs_test_opt(tree_root->fs_info, CHECK_INTEGRITY)) { - ret = btrfsic_mount(tree_root, fs_devices, - btrfs_test_opt(tree_root->fs_info, - CHECK_INTEGRITY_INCLUDING_EXTENT_DATA) ? - 1 : 0, - fs_info->check_integrity_print_mask); - if (ret) - btrfs_warn(fs_info, - "failed to initialize integrity check module: %d", - ret); - } -#endif - ret = btrfs_read_qgroup_config(fs_info); - if (ret) - goto fail_trans_kthread; - - /* do not make disk changes in broken FS or nologreplay is given */ - if (btrfs_super_log_root(disk_super) != 0 && - !btrfs_test_opt(tree_root->fs_info, NOLOGREPLAY)) { - ret = btrfs_replay_log(fs_info, fs_devices); - if (ret) { - err = ret; - goto fail_qgroup; - } - } - - ret = btrfs_find_orphan_roots(tree_root); - if (ret) - goto fail_qgroup; - - if (!(sb->s_flags & MS_RDONLY)) { - ret = btrfs_cleanup_fs_roots(fs_info); - if (ret) - goto fail_qgroup; - - mutex_lock(&fs_info->cleaner_mutex); - ret = btrfs_recover_relocation(tree_root); - mutex_unlock(&fs_info->cleaner_mutex); - if (ret < 0) { - btrfs_warn(fs_info, "failed to recover relocation: %d", - ret); - err = -EINVAL; - goto fail_qgroup; - } - } - - location.objectid = BTRFS_FS_TREE_OBJECTID; - location.type = BTRFS_ROOT_ITEM_KEY; - location.offset = 0; - - fs_info->fs_root = btrfs_read_fs_root_no_name(fs_info, &location); - if (IS_ERR(fs_info->fs_root)) { - err = PTR_ERR(fs_info->fs_root); - goto fail_qgroup; - } - - if (sb->s_flags & MS_RDONLY) - return 0; - - if (btrfs_test_opt(fs_info, CLEAR_CACHE) && - btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { - clear_free_space_tree = 1; - } else if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE) && - !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID)) { - btrfs_warn(fs_info, "free space tree is invalid"); - clear_free_space_tree = 1; - } - - if (clear_free_space_tree) { - btrfs_info(fs_info, "clearing free space tree"); - ret = btrfs_clear_free_space_tree(fs_info); - if (ret) { - btrfs_warn(fs_info, - "failed to clear free space tree: %d", ret); - close_ctree(tree_root); - return ret; - } - } - - if (btrfs_test_opt(tree_root->fs_info, FREE_SPACE_TREE) && - !btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) { - btrfs_info(fs_info, "creating free space tree"); - ret = btrfs_create_free_space_tree(fs_info); - if (ret) { - btrfs_warn(fs_info, - "failed to create free space tree: %d", ret); - close_ctree(tree_root); - return ret; - } - } - - down_read(&fs_info->cleanup_work_sem); - if ((ret = btrfs_orphan_cleanup(fs_info->fs_root)) || - (ret = btrfs_orphan_cleanup(fs_info->tree_root))) { - up_read(&fs_info->cleanup_work_sem); - close_ctree(tree_root); - return ret; - } - up_read(&fs_info->cleanup_work_sem); - - ret = btrfs_resume_balance_async(fs_info); - if (ret) { - btrfs_warn(fs_info, "failed to resume balance: %d", ret); - close_ctree(tree_root); - return ret; - } - - ret = btrfs_resume_dev_replace_async(fs_info); - if (ret) { - btrfs_warn(fs_info, "failed to resume device replace: %d", ret); - close_ctree(tree_root); - return ret; - } - - btrfs_qgroup_rescan_resume(fs_info); - - if (!fs_info->uuid_root) { - btrfs_info(fs_info, "creating UUID tree"); - ret = btrfs_create_uuid_tree(fs_info); - if (ret) { - btrfs_warn(fs_info, - "failed to create the UUID tree: %d", ret); - close_ctree(tree_root); - return ret; - } - } else if (btrfs_test_opt(tree_root->fs_info, RESCAN_UUID_TREE) || - fs_info->generation != - btrfs_super_uuid_tree_generation(disk_super)) { - btrfs_info(fs_info, "checking UUID tree"); - ret = btrfs_check_uuid_tree(fs_info); - if (ret) { - btrfs_warn(fs_info, - "failed to check the UUID tree: %d", ret); - close_ctree(tree_root); - return ret; - } - } else { - set_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags); - } - set_bit(BTRFS_FS_OPEN, &fs_info->flags); - - /* - * backuproot only affect mount behavior, and if open_ctree succeeded, - * no need to keep the flag - */ - btrfs_clear_opt(fs_info->mount_opt, USEBACKUPROOT); - - return 0; - -fail_qgroup: - btrfs_free_qgroup_config(fs_info); -fail_trans_kthread: - kthread_stop(fs_info->transaction_kthread); - btrfs_cleanup_transaction(fs_info->tree_root); - btrfs_free_fs_roots(fs_info); -fail_cleaner: - kthread_stop(fs_info->cleaner_kthread); - - /* - * make sure we're done with the btree inode before we stop our - * kthreads - */ - filemap_write_and_wait(fs_info->btree_inode->i_mapping); - -fail_sysfs: - btrfs_sysfs_remove_mounted(fs_info); - -fail_fsdev_sysfs: - btrfs_sysfs_remove_fsid(fs_info->fs_devices); - -fail_block_groups: - btrfs_put_block_group_cache(fs_info); - btrfs_free_block_groups(fs_info); - -fail_tree_roots: - free_root_pointers(fs_info, 1); - invalidate_inode_pages2(fs_info->btree_inode->i_mapping); - -fail_sb_buffer: - btrfs_stop_all_workers(fs_info); -fail_alloc: -fail_iput: - btrfs_mapping_tree_free(&fs_info->mapping_tree); - - iput(fs_info->btree_inode); -fail_bio_counter: - percpu_counter_destroy(&fs_info->bio_counter); -fail_delalloc_bytes: - percpu_counter_destroy(&fs_info->delalloc_bytes); -fail_dirty_metadata_bytes: - percpu_counter_destroy(&fs_info->dirty_metadata_bytes); -fail_bdi: - bdi_destroy(&fs_info->bdi); -fail_srcu: - cleanup_srcu_struct(&fs_info->subvol_srcu); -fail: - btrfs_free_stripe_hash_table(fs_info); - btrfs_close_devices(fs_info->fs_devices); - return err; - -recovery_tree_root: - if (!btrfs_test_opt(tree_root->fs_info, USEBACKUPROOT)) - goto fail_tree_roots; - - free_root_pointers(fs_info, 0); - - /* don't use the log in recovery mode, it won't be valid */ - btrfs_set_super_log_root(disk_super, 0); - - /* we can't trust the free space cache either */ - btrfs_set_opt(fs_info->mount_opt, CLEAR_CACHE); - - ret = next_root_backup(fs_info, fs_info->super_copy, - &num_backups_tried, &backup_index); - if (ret == -1) - goto fail_block_groups; - goto retry_root_backup; -} - -static void btrfs_end_buffer_write_sync(struct buffer_head *bh, int uptodate) -{ - if (uptodate) { - set_buffer_uptodate(bh); - } else { - struct btrfs_device *device = (struct btrfs_device *) - bh->b_private; - - btrfs_warn_rl_in_rcu(device->dev_root->fs_info, - "lost page write due to IO error on %s", - rcu_str_deref(device->name)); - /* note, we don't set_buffer_write_io_error because we have - * our own ways of dealing with the IO errors - */ - clear_buffer_uptodate(bh); - btrfs_dev_stat_inc_and_print(device, BTRFS_DEV_STAT_WRITE_ERRS); - } - unlock_buffer(bh); - put_bh(bh); -} - -int btrfs_read_dev_one_super(struct block_device *bdev, int copy_num, - struct buffer_head **bh_ret) -{ - struct buffer_head *bh; - struct btrfs_super_block *super; - u64 bytenr; - - bytenr = btrfs_sb_offset(copy_num); - if (bytenr + BTRFS_SUPER_INFO_SIZE >= i_size_read(bdev->bd_inode)) - return -EINVAL; - - bh = __bread(bdev, bytenr / 4096, BTRFS_SUPER_INFO_SIZE); - /* - * If we fail to read from the underlying devices, as of now - * the best option we have is to mark it EIO. - */ - if (!bh) - return -EIO; - - super = (struct btrfs_super_block *)bh->b_data; - if (btrfs_super_bytenr(super) != bytenr || - btrfs_super_magic(super) != BTRFS_MAGIC) { - brelse(bh); - return -EINVAL; - } - - *bh_ret = bh; - return 0; -} - - -struct buffer_head *btrfs_read_dev_super(struct block_device *bdev) -{ - struct buffer_head *bh; - struct buffer_head *latest = NULL; - struct btrfs_super_block *super; - int i; - u64 transid = 0; - int ret = -EINVAL; - - /* we would like to check all the supers, but that would make - * a btrfs mount succeed after a mkfs from a different FS. - * So, we need to add a special mount option to scan for - * later supers, using BTRFS_SUPER_MIRROR_MAX instead - */ - for (i = 0; i < 1; i++) { - ret = btrfs_read_dev_one_super(bdev, i, &bh); - if (ret) - continue; - - super = (struct btrfs_super_block *)bh->b_data; - - if (!latest || btrfs_super_generation(super) > transid) { - brelse(latest); - latest = bh; - transid = btrfs_super_generation(super); - } else { - brelse(bh); - } - } - - if (!latest) - return ERR_PTR(ret); - - return latest; -} - -/* - * this should be called twice, once with wait == 0 and - * once with wait == 1. When wait == 0 is done, all the buffer heads - * we write are pinned. - * - * They are released when wait == 1 is done. - * max_mirrors must be the same for both runs, and it indicates how - * many supers on this one device should be written. - * - * max_mirrors == 0 means to write them all. - */ -static int write_dev_supers(struct btrfs_device *device, - struct btrfs_super_block *sb, - int do_barriers, int wait, int max_mirrors) -{ - struct buffer_head *bh; - int i; - int ret; - int errors = 0; - u32 crc; - u64 bytenr; - - if (max_mirrors == 0) - max_mirrors = BTRFS_SUPER_MIRROR_MAX; - - for (i = 0; i < max_mirrors; i++) { - bytenr = btrfs_sb_offset(i); - if (bytenr + BTRFS_SUPER_INFO_SIZE >= - device->commit_total_bytes) - break; - - if (wait) { - bh = __find_get_block(device->bdev, bytenr / 4096, - BTRFS_SUPER_INFO_SIZE); - if (!bh) { - errors++; - continue; - } - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) - errors++; - - /* drop our reference */ - brelse(bh); - - /* drop the reference from the wait == 0 run */ - brelse(bh); - continue; - } else { - btrfs_set_super_bytenr(sb, bytenr); - - crc = ~(u32)0; - crc = btrfs_csum_data((char *)sb + - BTRFS_CSUM_SIZE, crc, - BTRFS_SUPER_INFO_SIZE - - BTRFS_CSUM_SIZE); - btrfs_csum_final(crc, sb->csum); - - /* - * one reference for us, and we leave it for the - * caller - */ - bh = __getblk(device->bdev, bytenr / 4096, - BTRFS_SUPER_INFO_SIZE); - if (!bh) { - btrfs_err(device->dev_root->fs_info, - "couldn't get super buffer head for bytenr %llu", - bytenr); - errors++; - continue; - } - - memcpy(bh->b_data, sb, BTRFS_SUPER_INFO_SIZE); - - /* one reference for submit_bh */ - get_bh(bh); - - set_buffer_uptodate(bh); - lock_buffer(bh); - bh->b_end_io = btrfs_end_buffer_write_sync; - bh->b_private = device; - } - - /* - * we fua the first super. The others we allow - * to go down lazy. - */ - if (i == 0) - ret = btrfsic_submit_bh(REQ_OP_WRITE, WRITE_FUA, bh); - else - ret = btrfsic_submit_bh(REQ_OP_WRITE, WRITE_SYNC, bh); - if (ret) - errors++; - } - return errors < i ? 0 : -1; -} - -/* - * endio for the write_dev_flush, this will wake anyone waiting - * for the barrier when it is done - */ -static void btrfs_end_empty_barrier(struct bio *bio) -{ - if (bio->bi_private) - complete(bio->bi_private); - bio_put(bio); -} - -/* - * trigger flushes for one the devices. If you pass wait == 0, the flushes are - * sent down. With wait == 1, it waits for the previous flush. - * - * any device where the flush fails with eopnotsupp are flagged as not-barrier - * capable - */ -static int write_dev_flush(struct btrfs_device *device, int wait) -{ - struct bio *bio; - int ret = 0; - - if (device->nobarriers) - return 0; - - if (wait) { - bio = device->flush_bio; - if (!bio) - return 0; - - wait_for_completion(&device->flush_wait); - - if (bio->bi_error) { - ret = bio->bi_error; - btrfs_dev_stat_inc_and_print(device, - BTRFS_DEV_STAT_FLUSH_ERRS); - } - - /* drop the reference from the wait == 0 run */ - bio_put(bio); - device->flush_bio = NULL; - - return ret; - } - - /* - * one reference for us, and we leave it for the - * caller - */ - device->flush_bio = NULL; - bio = btrfs_io_bio_alloc(GFP_NOFS, 0); - if (!bio) - return -ENOMEM; - - bio->bi_end_io = btrfs_end_empty_barrier; - bio->bi_bdev = device->bdev; - bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_FLUSH); - init_completion(&device->flush_wait); - bio->bi_private = &device->flush_wait; - device->flush_bio = bio; - - bio_get(bio); - btrfsic_submit_bio(bio); - - return 0; -} - -/* - * send an empty flush down to each device in parallel, - * then wait for them - */ -static int barrier_all_devices(struct btrfs_fs_info *info) -{ - struct list_head *head; - struct btrfs_device *dev; - int errors_send = 0; - int errors_wait = 0; - int ret; - - /* send down all the barriers */ - head = &info->fs_devices->devices; - list_for_each_entry_rcu(dev, head, dev_list) { - if (dev->missing) - continue; - if (!dev->bdev) { - errors_send++; - continue; - } - if (!dev->in_fs_metadata || !dev->writeable) - continue; - - ret = write_dev_flush(dev, 0); - if (ret) - errors_send++; - } - - /* wait for all the barriers */ - list_for_each_entry_rcu(dev, head, dev_list) { - if (dev->missing) - continue; - if (!dev->bdev) { - errors_wait++; - continue; - } - if (!dev->in_fs_metadata || !dev->writeable) - continue; - - ret = write_dev_flush(dev, 1); - if (ret) - errors_wait++; - } - if (errors_send > info->num_tolerated_disk_barrier_failures || - errors_wait > info->num_tolerated_disk_barrier_failures) - return -EIO; - return 0; -} - -int btrfs_get_num_tolerated_disk_barrier_failures(u64 flags) -{ - int raid_type; - int min_tolerated = INT_MAX; - - if ((flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0 || - (flags & BTRFS_AVAIL_ALLOC_BIT_SINGLE)) - min_tolerated = min(min_tolerated, - btrfs_raid_array[BTRFS_RAID_SINGLE]. - tolerated_failures); - - for (raid_type = 0; raid_type < BTRFS_NR_RAID_TYPES; raid_type++) { - if (raid_type == BTRFS_RAID_SINGLE) - continue; - if (!(flags & btrfs_raid_group[raid_type])) - continue; - min_tolerated = min(min_tolerated, - btrfs_raid_array[raid_type]. - tolerated_failures); - } - - if (min_tolerated == INT_MAX) { - pr_warn("BTRFS: unknown raid flag: %llu", flags); - min_tolerated = 0; - } - - return min_tolerated; -} - -int btrfs_calc_num_tolerated_disk_barrier_failures( - struct btrfs_fs_info *fs_info) -{ - struct btrfs_ioctl_space_info space; - struct btrfs_space_info *sinfo; - u64 types[] = {BTRFS_BLOCK_GROUP_DATA, - BTRFS_BLOCK_GROUP_SYSTEM, - BTRFS_BLOCK_GROUP_METADATA, - BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA}; - int i; - int c; - int num_tolerated_disk_barrier_failures = - (int)fs_info->fs_devices->num_devices; - - for (i = 0; i < ARRAY_SIZE(types); i++) { - struct btrfs_space_info *tmp; - - sinfo = NULL; - rcu_read_lock(); - list_for_each_entry_rcu(tmp, &fs_info->space_info, list) { - if (tmp->flags == types[i]) { - sinfo = tmp; - break; - } - } - rcu_read_unlock(); - - if (!sinfo) - continue; - - down_read(&sinfo->groups_sem); - for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) { - u64 flags; - - if (list_empty(&sinfo->block_groups[c])) - continue; - - btrfs_get_block_group_info(&sinfo->block_groups[c], - &space); - if (space.total_bytes == 0 || space.used_bytes == 0) - continue; - flags = space.flags; - - num_tolerated_disk_barrier_failures = min( - num_tolerated_disk_barrier_failures, - btrfs_get_num_tolerated_disk_barrier_failures( - flags)); - } - up_read(&sinfo->groups_sem); - } - - return num_tolerated_disk_barrier_failures; -} - -static int write_all_supers(struct btrfs_root *root, int max_mirrors) -{ - struct list_head *head; - struct btrfs_device *dev; - struct btrfs_super_block *sb; - struct btrfs_dev_item *dev_item; - int ret; - int do_barriers; - int max_errors; - int total_errors = 0; - u64 flags; - - do_barriers = !btrfs_test_opt(root->fs_info, NOBARRIER); - backup_super_roots(root->fs_info); - - sb = root->fs_info->super_for_commit; - dev_item = &sb->dev_item; - - mutex_lock(&root->fs_info->fs_devices->device_list_mutex); - head = &root->fs_info->fs_devices->devices; - max_errors = btrfs_super_num_devices(root->fs_info->super_copy) - 1; - - if (do_barriers) { - ret = barrier_all_devices(root->fs_info); - if (ret) { - mutex_unlock( - &root->fs_info->fs_devices->device_list_mutex); - btrfs_handle_fs_error(root->fs_info, ret, - "errors while submitting device barriers."); - return ret; - } - } - - list_for_each_entry_rcu(dev, head, dev_list) { - if (!dev->bdev) { - total_errors++; - continue; - } - if (!dev->in_fs_metadata || !dev->writeable) - continue; - - btrfs_set_stack_device_generation(dev_item, 0); - btrfs_set_stack_device_type(dev_item, dev->type); - btrfs_set_stack_device_id(dev_item, dev->devid); - btrfs_set_stack_device_total_bytes(dev_item, - dev->commit_total_bytes); - btrfs_set_stack_device_bytes_used(dev_item, - dev->commit_bytes_used); - btrfs_set_stack_device_io_align(dev_item, dev->io_align); - btrfs_set_stack_device_io_width(dev_item, dev->io_width); - btrfs_set_stack_device_sector_size(dev_item, dev->sector_size); - memcpy(dev_item->uuid, dev->uuid, BTRFS_UUID_SIZE); - memcpy(dev_item->fsid, dev->fs_devices->fsid, BTRFS_UUID_SIZE); - - flags = btrfs_super_flags(sb); - btrfs_set_super_flags(sb, flags | BTRFS_HEADER_FLAG_WRITTEN); - - ret = write_dev_supers(dev, sb, do_barriers, 0, max_mirrors); - if (ret) - total_errors++; - } - if (total_errors > max_errors) { - btrfs_err(root->fs_info, "%d errors while writing supers", - total_errors); - mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); - - /* FUA is masked off if unsupported and can't be the reason */ - btrfs_handle_fs_error(root->fs_info, -EIO, - "%d errors while writing supers", total_errors); - return -EIO; - } - - total_errors = 0; - list_for_each_entry_rcu(dev, head, dev_list) { - if (!dev->bdev) - continue; - if (!dev->in_fs_metadata || !dev->writeable) - continue; - - ret = write_dev_supers(dev, sb, do_barriers, 1, max_mirrors); - if (ret) - total_errors++; - } - mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); - if (total_errors > max_errors) { - btrfs_handle_fs_error(root->fs_info, -EIO, - "%d errors while writing supers", total_errors); - return -EIO; - } - return 0; -} - -int write_ctree_super(struct btrfs_trans_handle *trans, - struct btrfs_root *root, int max_mirrors) -{ - return write_all_supers(root, max_mirrors); -} - -/* Drop a fs root from the radix tree and free it. */ -void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info, - struct btrfs_root *root) -{ - spin_lock(&fs_info->fs_roots_radix_lock); - radix_tree_delete(&fs_info->fs_roots_radix, - (unsigned long)root->root_key.objectid); - spin_unlock(&fs_info->fs_roots_radix_lock); - - if (btrfs_root_refs(&root->root_item) == 0) - synchronize_srcu(&fs_info->subvol_srcu); - - if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) { - btrfs_free_log(NULL, root); - if (root->reloc_root) { - free_extent_buffer(root->reloc_root->node); - free_extent_buffer(root->reloc_root->commit_root); - btrfs_put_fs_root(root->reloc_root); - root->reloc_root = NULL; - } - } - - if (root->free_ino_pinned) - __btrfs_remove_free_space_cache(root->free_ino_pinned); - if (root->free_ino_ctl) - __btrfs_remove_free_space_cache(root->free_ino_ctl); - free_fs_root(root); -} - -static void free_fs_root(struct btrfs_root *root) -{ - iput(root->ino_cache_inode); - WARN_ON(!RB_EMPTY_ROOT(&root->inode_tree)); - btrfs_free_block_rsv(root, root->orphan_block_rsv); - root->orphan_block_rsv = NULL; - if (root->anon_dev) - free_anon_bdev(root->anon_dev); - if (root->subv_writers) - btrfs_free_subvolume_writers(root->subv_writers); - free_extent_buffer(root->node); - free_extent_buffer(root->commit_root); - kfree(root->free_ino_ctl); - kfree(root->free_ino_pinned); - kfree(root->name); - btrfs_put_fs_root(root); -} - -void btrfs_free_fs_root(struct btrfs_root *root) -{ - free_fs_root(root); -} - -int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info) -{ - u64 root_objectid = 0; - struct btrfs_root *gang[8]; - int i = 0; - int err = 0; - unsigned int ret = 0; - int index; - - while (1) { - index = srcu_read_lock(&fs_info->subvol_srcu); - ret = radix_tree_gang_lookup(&fs_info->fs_roots_radix, - (void **)gang, root_objectid, - ARRAY_SIZE(gang)); - if (!ret) { - srcu_read_unlock(&fs_info->subvol_srcu, index); - break; - } - root_objectid = gang[ret - 1]->root_key.objectid + 1; - - for (i = 0; i < ret; i++) { - /* Avoid to grab roots in dead_roots */ - if (btrfs_root_refs(&gang[i]->root_item) == 0) { - gang[i] = NULL; - continue; - } - /* grab all the search result for later use */ - gang[i] = btrfs_grab_fs_root(gang[i]); - } - srcu_read_unlock(&fs_info->subvol_srcu, index); - - for (i = 0; i < ret; i++) { - if (!gang[i]) - continue; - root_objectid = gang[i]->root_key.objectid; - err = btrfs_orphan_cleanup(gang[i]); - if (err) - break; - btrfs_put_fs_root(gang[i]); - } - root_objectid++; - } - - /* release the uncleaned roots due to error */ - for (; i < ret; i++) { - if (gang[i]) - btrfs_put_fs_root(gang[i]); - } - return err; -} - -int btrfs_commit_super(struct btrfs_root *root) -{ - struct btrfs_trans_handle *trans; - - mutex_lock(&root->fs_info->cleaner_mutex); - btrfs_run_delayed_iputs(root); - mutex_unlock(&root->fs_info->cleaner_mutex); - wake_up_process(root->fs_info->cleaner_kthread); - - /* wait until ongoing cleanup work done */ - down_write(&root->fs_info->cleanup_work_sem); - up_write(&root->fs_info->cleanup_work_sem); - - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) - return PTR_ERR(trans); - return btrfs_commit_transaction(trans, root); -} - -void close_ctree(struct btrfs_root *root) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - int ret; - - set_bit(BTRFS_FS_CLOSING_START, &fs_info->flags); - - /* wait for the qgroup rescan worker to stop */ - btrfs_qgroup_wait_for_completion(fs_info, false); - - /* wait for the uuid_scan task to finish */ - down(&fs_info->uuid_tree_rescan_sem); - /* avoid complains from lockdep et al., set sem back to initial state */ - up(&fs_info->uuid_tree_rescan_sem); - - /* pause restriper - we want to resume on mount */ - btrfs_pause_balance(fs_info); - - btrfs_dev_replace_suspend_for_unmount(fs_info); - - btrfs_scrub_cancel(fs_info); - - /* wait for any defraggers to finish */ - wait_event(fs_info->transaction_wait, - (atomic_read(&fs_info->defrag_running) == 0)); - - /* clear out the rbtree of defraggable inodes */ - btrfs_cleanup_defrag_inodes(fs_info); - - cancel_work_sync(&fs_info->async_reclaim_work); - - if (!(fs_info->sb->s_flags & MS_RDONLY)) { - /* - * If the cleaner thread is stopped and there are - * block groups queued for removal, the deletion will be - * skipped when we quit the cleaner thread. - */ - btrfs_delete_unused_bgs(root->fs_info); - - ret = btrfs_commit_super(root); - if (ret) - btrfs_err(fs_info, "commit super ret %d", ret); - } - - if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) - btrfs_error_commit_super(root); - - kthread_stop(fs_info->transaction_kthread); - kthread_stop(fs_info->cleaner_kthread); - - set_bit(BTRFS_FS_CLOSING_DONE, &fs_info->flags); - - btrfs_free_qgroup_config(fs_info); - - if (percpu_counter_sum(&fs_info->delalloc_bytes)) { - btrfs_info(fs_info, "at unmount delalloc count %lld", - percpu_counter_sum(&fs_info->delalloc_bytes)); - } - - btrfs_sysfs_remove_mounted(fs_info); - btrfs_sysfs_remove_fsid(fs_info->fs_devices); - - btrfs_free_fs_roots(fs_info); - - btrfs_put_block_group_cache(fs_info); - - btrfs_free_block_groups(fs_info); - - /* - * we must make sure there is not any read request to - * submit after we stopping all workers. - */ - invalidate_inode_pages2(fs_info->btree_inode->i_mapping); - btrfs_stop_all_workers(fs_info); - - clear_bit(BTRFS_FS_OPEN, &fs_info->flags); - free_root_pointers(fs_info, 1); - - iput(fs_info->btree_inode); - -#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY - if (btrfs_test_opt(root->fs_info, CHECK_INTEGRITY)) - btrfsic_unmount(root, fs_info->fs_devices); -#endif - - btrfs_close_devices(fs_info->fs_devices); - btrfs_mapping_tree_free(&fs_info->mapping_tree); - - percpu_counter_destroy(&fs_info->dirty_metadata_bytes); - percpu_counter_destroy(&fs_info->delalloc_bytes); - percpu_counter_destroy(&fs_info->bio_counter); - bdi_destroy(&fs_info->bdi); - cleanup_srcu_struct(&fs_info->subvol_srcu); - - btrfs_free_stripe_hash_table(fs_info); - - __btrfs_free_block_rsv(root->orphan_block_rsv); - root->orphan_block_rsv = NULL; - - lock_chunks(root); - while (!list_empty(&fs_info->pinned_chunks)) { - struct extent_map *em; - - em = list_first_entry(&fs_info->pinned_chunks, - struct extent_map, list); - list_del_init(&em->list); - free_extent_map(em); - } - unlock_chunks(root); -} - -int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid, - int atomic) -{ - int ret; - struct inode *btree_inode = buf->pages[0]->mapping->host; - - ret = extent_buffer_uptodate(buf); - if (!ret) - return ret; - - ret = verify_parent_transid(&BTRFS_I(btree_inode)->io_tree, buf, - parent_transid, atomic); - if (ret == -EAGAIN) - return ret; - return !ret; -} - -void btrfs_mark_buffer_dirty(struct extent_buffer *buf) -{ - struct btrfs_root *root; - u64 transid = btrfs_header_generation(buf); - int was_dirty; - -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS - /* - * This is a fast path so only do this check if we have sanity tests - * enabled. Normal people shouldn't be marking dummy buffers as dirty - * outside of the sanity tests. - */ - if (unlikely(test_bit(EXTENT_BUFFER_DUMMY, &buf->bflags))) - return; -#endif - root = BTRFS_I(buf->pages[0]->mapping->host)->root; - btrfs_assert_tree_locked(buf); - if (transid != root->fs_info->generation) - WARN(1, KERN_CRIT "btrfs transid mismatch buffer %llu, found %llu running %llu\n", - buf->start, transid, root->fs_info->generation); - was_dirty = set_extent_buffer_dirty(buf); - if (!was_dirty) - __percpu_counter_add(&root->fs_info->dirty_metadata_bytes, - buf->len, - root->fs_info->dirty_metadata_batch); -#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY - if (btrfs_header_level(buf) == 0 && check_leaf(root, buf)) { - btrfs_print_leaf(root, buf); - ASSERT(0); - } -#endif -} - -static void __btrfs_btree_balance_dirty(struct btrfs_root *root, - int flush_delayed) -{ - /* - * looks as though older kernels can get into trouble with - * this code, they end up stuck in balance_dirty_pages forever - */ - int ret; - - if (current->flags & PF_MEMALLOC) - return; - - if (flush_delayed) - btrfs_balance_delayed_items(root); - - ret = percpu_counter_compare(&root->fs_info->dirty_metadata_bytes, - BTRFS_DIRTY_METADATA_THRESH); - if (ret > 0) { - balance_dirty_pages_ratelimited( - root->fs_info->btree_inode->i_mapping); - } -} - -void btrfs_btree_balance_dirty(struct btrfs_root *root) -{ - __btrfs_btree_balance_dirty(root, 1); -} - -void btrfs_btree_balance_dirty_nodelay(struct btrfs_root *root) -{ - __btrfs_btree_balance_dirty(root, 0); -} - -int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid) -{ - struct btrfs_root *root = BTRFS_I(buf->pages[0]->mapping->host)->root; - return btree_read_extent_buffer_pages(root, buf, parent_transid); -} - -static int btrfs_check_super_valid(struct btrfs_fs_info *fs_info, - int read_only) -{ - struct btrfs_super_block *sb = fs_info->super_copy; - u64 nodesize = btrfs_super_nodesize(sb); - u64 sectorsize = btrfs_super_sectorsize(sb); - int ret = 0; - - if (btrfs_super_magic(sb) != BTRFS_MAGIC) { - btrfs_err(fs_info, "no valid FS found"); - ret = -EINVAL; - } - if (btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP) - btrfs_warn(fs_info, "unrecognized super flag: %llu", - btrfs_super_flags(sb) & ~BTRFS_SUPER_FLAG_SUPP); - if (btrfs_super_root_level(sb) >= BTRFS_MAX_LEVEL) { - btrfs_err(fs_info, "tree_root level too big: %d >= %d", - btrfs_super_root_level(sb), BTRFS_MAX_LEVEL); - ret = -EINVAL; - } - if (btrfs_super_chunk_root_level(sb) >= BTRFS_MAX_LEVEL) { - btrfs_err(fs_info, "chunk_root level too big: %d >= %d", - btrfs_super_chunk_root_level(sb), BTRFS_MAX_LEVEL); - ret = -EINVAL; - } - if (btrfs_super_log_root_level(sb) >= BTRFS_MAX_LEVEL) { - btrfs_err(fs_info, "log_root level too big: %d >= %d", - btrfs_super_log_root_level(sb), BTRFS_MAX_LEVEL); - ret = -EINVAL; - } - - /* - * Check sectorsize and nodesize first, other check will need it. - * Check all possible sectorsize(4K, 8K, 16K, 32K, 64K) here. - */ - if (!is_power_of_2(sectorsize) || sectorsize < 4096 || - sectorsize > BTRFS_MAX_METADATA_BLOCKSIZE) { - btrfs_err(fs_info, "invalid sectorsize %llu", sectorsize); - ret = -EINVAL; - } - /* Only PAGE SIZE is supported yet */ - if (sectorsize != PAGE_SIZE) { - btrfs_err(fs_info, - "sectorsize %llu not supported yet, only support %lu", - sectorsize, PAGE_SIZE); - ret = -EINVAL; - } - if (!is_power_of_2(nodesize) || nodesize < sectorsize || - nodesize > BTRFS_MAX_METADATA_BLOCKSIZE) { - btrfs_err(fs_info, "invalid nodesize %llu", nodesize); - ret = -EINVAL; - } - if (nodesize != le32_to_cpu(sb->__unused_leafsize)) { - btrfs_err(fs_info, "invalid leafsize %u, should be %llu", - le32_to_cpu(sb->__unused_leafsize), nodesize); - ret = -EINVAL; - } - - /* Root alignment check */ - if (!IS_ALIGNED(btrfs_super_root(sb), sectorsize)) { - btrfs_warn(fs_info, "tree_root block unaligned: %llu", - btrfs_super_root(sb)); - ret = -EINVAL; - } - if (!IS_ALIGNED(btrfs_super_chunk_root(sb), sectorsize)) { - btrfs_warn(fs_info, "chunk_root block unaligned: %llu", - btrfs_super_chunk_root(sb)); - ret = -EINVAL; - } - if (!IS_ALIGNED(btrfs_super_log_root(sb), sectorsize)) { - btrfs_warn(fs_info, "log_root block unaligned: %llu", - btrfs_super_log_root(sb)); - ret = -EINVAL; - } - - if (memcmp(fs_info->fsid, sb->dev_item.fsid, BTRFS_UUID_SIZE) != 0) { - btrfs_err(fs_info, - "dev_item UUID does not match fsid: %pU != %pU", - fs_info->fsid, sb->dev_item.fsid); - ret = -EINVAL; - } - - /* - * Hint to catch really bogus numbers, bitflips or so, more exact checks are - * done later - */ - if (btrfs_super_bytes_used(sb) < 6 * btrfs_super_nodesize(sb)) { - btrfs_err(fs_info, "bytes_used is too small %llu", - btrfs_super_bytes_used(sb)); - ret = -EINVAL; - } - if (!is_power_of_2(btrfs_super_stripesize(sb))) { - btrfs_err(fs_info, "invalid stripesize %u", - btrfs_super_stripesize(sb)); - ret = -EINVAL; - } - if (btrfs_super_num_devices(sb) > (1UL << 31)) - btrfs_warn(fs_info, "suspicious number of devices: %llu", - btrfs_super_num_devices(sb)); - if (btrfs_super_num_devices(sb) == 0) { - btrfs_err(fs_info, "number of devices is 0"); - ret = -EINVAL; - } - - if (btrfs_super_bytenr(sb) != BTRFS_SUPER_INFO_OFFSET) { - btrfs_err(fs_info, "super offset mismatch %llu != %u", - btrfs_super_bytenr(sb), BTRFS_SUPER_INFO_OFFSET); - ret = -EINVAL; - } - - /* - * Obvious sys_chunk_array corruptions, it must hold at least one key - * and one chunk - */ - if (btrfs_super_sys_array_size(sb) > BTRFS_SYSTEM_CHUNK_ARRAY_SIZE) { - btrfs_err(fs_info, "system chunk array too big %u > %u", - btrfs_super_sys_array_size(sb), - BTRFS_SYSTEM_CHUNK_ARRAY_SIZE); - ret = -EINVAL; - } - if (btrfs_super_sys_array_size(sb) < sizeof(struct btrfs_disk_key) - + sizeof(struct btrfs_chunk)) { - btrfs_err(fs_info, "system chunk array too small %u < %zu", - btrfs_super_sys_array_size(sb), - sizeof(struct btrfs_disk_key) - + sizeof(struct btrfs_chunk)); - ret = -EINVAL; - } - - /* - * The generation is a global counter, we'll trust it more than the others - * but it's still possible that it's the one that's wrong. - */ - if (btrfs_super_generation(sb) < btrfs_super_chunk_root_generation(sb)) - btrfs_warn(fs_info, - "suspicious: generation < chunk_root_generation: %llu < %llu", - btrfs_super_generation(sb), - btrfs_super_chunk_root_generation(sb)); - if (btrfs_super_generation(sb) < btrfs_super_cache_generation(sb) - && btrfs_super_cache_generation(sb) != (u64)-1) - btrfs_warn(fs_info, - "suspicious: generation < cache_generation: %llu < %llu", - btrfs_super_generation(sb), - btrfs_super_cache_generation(sb)); - - return ret; -} - -static void btrfs_error_commit_super(struct btrfs_root *root) -{ - mutex_lock(&root->fs_info->cleaner_mutex); - btrfs_run_delayed_iputs(root); - mutex_unlock(&root->fs_info->cleaner_mutex); - - down_write(&root->fs_info->cleanup_work_sem); - up_write(&root->fs_info->cleanup_work_sem); - - /* cleanup FS via transaction */ - btrfs_cleanup_transaction(root); -} - -static void btrfs_destroy_ordered_extents(struct btrfs_root *root) -{ - struct btrfs_ordered_extent *ordered; - - spin_lock(&root->ordered_extent_lock); - /* - * This will just short circuit the ordered completion stuff which will - * make sure the ordered extent gets properly cleaned up. - */ - list_for_each_entry(ordered, &root->ordered_extents, - root_extent_list) - set_bit(BTRFS_ORDERED_IOERR, &ordered->flags); - spin_unlock(&root->ordered_extent_lock); -} - -static void btrfs_destroy_all_ordered_extents(struct btrfs_fs_info *fs_info) -{ - struct btrfs_root *root; - struct list_head splice; - - INIT_LIST_HEAD(&splice); - - spin_lock(&fs_info->ordered_root_lock); - list_splice_init(&fs_info->ordered_roots, &splice); - while (!list_empty(&splice)) { - root = list_first_entry(&splice, struct btrfs_root, - ordered_root); - list_move_tail(&root->ordered_root, - &fs_info->ordered_roots); - - spin_unlock(&fs_info->ordered_root_lock); - btrfs_destroy_ordered_extents(root); - - cond_resched(); - spin_lock(&fs_info->ordered_root_lock); - } - spin_unlock(&fs_info->ordered_root_lock); -} - -static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, - struct btrfs_root *root) -{ - struct rb_node *node; - struct btrfs_delayed_ref_root *delayed_refs; - struct btrfs_delayed_ref_node *ref; - int ret = 0; - - delayed_refs = &trans->delayed_refs; - - spin_lock(&delayed_refs->lock); - if (atomic_read(&delayed_refs->num_entries) == 0) { - spin_unlock(&delayed_refs->lock); - btrfs_info(root->fs_info, "delayed_refs has NO entry"); - return ret; - } - - while ((node = rb_first(&delayed_refs->href_root)) != NULL) { - struct btrfs_delayed_ref_head *head; - struct btrfs_delayed_ref_node *tmp; - bool pin_bytes = false; - - head = rb_entry(node, struct btrfs_delayed_ref_head, - href_node); - if (!mutex_trylock(&head->mutex)) { - atomic_inc(&head->node.refs); - spin_unlock(&delayed_refs->lock); - - mutex_lock(&head->mutex); - mutex_unlock(&head->mutex); - btrfs_put_delayed_ref(&head->node); - spin_lock(&delayed_refs->lock); - continue; - } - spin_lock(&head->lock); - list_for_each_entry_safe_reverse(ref, tmp, &head->ref_list, - list) { - ref->in_tree = 0; - list_del(&ref->list); - atomic_dec(&delayed_refs->num_entries); - btrfs_put_delayed_ref(ref); - } - if (head->must_insert_reserved) - pin_bytes = true; - btrfs_free_delayed_extent_op(head->extent_op); - delayed_refs->num_heads--; - if (head->processing == 0) - delayed_refs->num_heads_ready--; - atomic_dec(&delayed_refs->num_entries); - head->node.in_tree = 0; - rb_erase(&head->href_node, &delayed_refs->href_root); - spin_unlock(&head->lock); - spin_unlock(&delayed_refs->lock); - mutex_unlock(&head->mutex); - - if (pin_bytes) - btrfs_pin_extent(root, head->node.bytenr, - head->node.num_bytes, 1); - btrfs_put_delayed_ref(&head->node); - cond_resched(); - spin_lock(&delayed_refs->lock); - } - - spin_unlock(&delayed_refs->lock); - - return ret; -} - -static void btrfs_destroy_delalloc_inodes(struct btrfs_root *root) -{ - struct btrfs_inode *btrfs_inode; - struct list_head splice; - - INIT_LIST_HEAD(&splice); - - spin_lock(&root->delalloc_lock); - list_splice_init(&root->delalloc_inodes, &splice); - - while (!list_empty(&splice)) { - btrfs_inode = list_first_entry(&splice, struct btrfs_inode, - delalloc_inodes); - - list_del_init(&btrfs_inode->delalloc_inodes); - clear_bit(BTRFS_INODE_IN_DELALLOC_LIST, - &btrfs_inode->runtime_flags); - spin_unlock(&root->delalloc_lock); - - btrfs_invalidate_inodes(btrfs_inode->root); - - spin_lock(&root->delalloc_lock); - } - - spin_unlock(&root->delalloc_lock); -} - -static void btrfs_destroy_all_delalloc_inodes(struct btrfs_fs_info *fs_info) -{ - struct btrfs_root *root; - struct list_head splice; - - INIT_LIST_HEAD(&splice); - - spin_lock(&fs_info->delalloc_root_lock); - list_splice_init(&fs_info->delalloc_roots, &splice); - while (!list_empty(&splice)) { - root = list_first_entry(&splice, struct btrfs_root, - delalloc_root); - list_del_init(&root->delalloc_root); - root = btrfs_grab_fs_root(root); - BUG_ON(!root); - spin_unlock(&fs_info->delalloc_root_lock); - - btrfs_destroy_delalloc_inodes(root); - btrfs_put_fs_root(root); - - spin_lock(&fs_info->delalloc_root_lock); - } - spin_unlock(&fs_info->delalloc_root_lock); -} - -static int btrfs_destroy_marked_extents(struct btrfs_root *root, - struct extent_io_tree *dirty_pages, - int mark) -{ - int ret; - struct extent_buffer *eb; - u64 start = 0; - u64 end; - - while (1) { - ret = find_first_extent_bit(dirty_pages, start, &start, &end, - mark, NULL); - if (ret) - break; - - clear_extent_bits(dirty_pages, start, end, mark); - while (start <= end) { - eb = btrfs_find_tree_block(root->fs_info, start); - start += root->nodesize; - if (!eb) - continue; - wait_on_extent_buffer_writeback(eb); - - if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, - &eb->bflags)) - clear_extent_buffer_dirty(eb); - free_extent_buffer_stale(eb); - } - } - - return ret; -} - -static int btrfs_destroy_pinned_extent(struct btrfs_root *root, - struct extent_io_tree *pinned_extents) -{ - struct extent_io_tree *unpin; - u64 start; - u64 end; - int ret; - bool loop = true; - - unpin = pinned_extents; -again: - while (1) { - ret = find_first_extent_bit(unpin, 0, &start, &end, - EXTENT_DIRTY, NULL); - if (ret) - break; - - clear_extent_dirty(unpin, start, end); - btrfs_error_unpin_extent_range(root, start, end); - cond_resched(); - } - - if (loop) { - if (unpin == &root->fs_info->freed_extents[0]) - unpin = &root->fs_info->freed_extents[1]; - else - unpin = &root->fs_info->freed_extents[0]; - loop = false; - goto again; - } - - return 0; -} - -static void btrfs_cleanup_bg_io(struct btrfs_block_group_cache *cache) -{ - struct inode *inode; - - inode = cache->io_ctl.inode; - if (inode) { - invalidate_inode_pages2(inode->i_mapping); - BTRFS_I(inode)->generation = 0; - cache->io_ctl.inode = NULL; - iput(inode); - } - btrfs_put_block_group(cache); -} - -void btrfs_cleanup_dirty_bgs(struct btrfs_transaction *cur_trans, - struct btrfs_root *root) -{ - struct btrfs_block_group_cache *cache; - - spin_lock(&cur_trans->dirty_bgs_lock); - while (!list_empty(&cur_trans->dirty_bgs)) { - cache = list_first_entry(&cur_trans->dirty_bgs, - struct btrfs_block_group_cache, - dirty_list); - if (!cache) { - btrfs_err(root->fs_info, - "orphan block group dirty_bgs list"); - spin_unlock(&cur_trans->dirty_bgs_lock); - return; - } - - if (!list_empty(&cache->io_list)) { - spin_unlock(&cur_trans->dirty_bgs_lock); - list_del_init(&cache->io_list); - btrfs_cleanup_bg_io(cache); - spin_lock(&cur_trans->dirty_bgs_lock); - } - - list_del_init(&cache->dirty_list); - spin_lock(&cache->lock); - cache->disk_cache_state = BTRFS_DC_ERROR; - spin_unlock(&cache->lock); - - spin_unlock(&cur_trans->dirty_bgs_lock); - btrfs_put_block_group(cache); - spin_lock(&cur_trans->dirty_bgs_lock); - } - spin_unlock(&cur_trans->dirty_bgs_lock); - - while (!list_empty(&cur_trans->io_bgs)) { - cache = list_first_entry(&cur_trans->io_bgs, - struct btrfs_block_group_cache, - io_list); - if (!cache) { - btrfs_err(root->fs_info, - "orphan block group on io_bgs list"); - return; - } - - list_del_init(&cache->io_list); - spin_lock(&cache->lock); - cache->disk_cache_state = BTRFS_DC_ERROR; - spin_unlock(&cache->lock); - btrfs_cleanup_bg_io(cache); - } -} - -void btrfs_cleanup_one_transaction(struct btrfs_transaction *cur_trans, - struct btrfs_root *root) -{ - btrfs_cleanup_dirty_bgs(cur_trans, root); - ASSERT(list_empty(&cur_trans->dirty_bgs)); - ASSERT(list_empty(&cur_trans->io_bgs)); - - btrfs_destroy_delayed_refs(cur_trans, root); - - cur_trans->state = TRANS_STATE_COMMIT_START; - wake_up(&root->fs_info->transaction_blocked_wait); - - cur_trans->state = TRANS_STATE_UNBLOCKED; - wake_up(&root->fs_info->transaction_wait); - - btrfs_destroy_delayed_inodes(root); - btrfs_assert_delayed_root_empty(root); - - btrfs_destroy_marked_extents(root, &cur_trans->dirty_pages, - EXTENT_DIRTY); - btrfs_destroy_pinned_extent(root, - root->fs_info->pinned_extents); - - cur_trans->state =TRANS_STATE_COMPLETED; - wake_up(&cur_trans->commit_wait); - - /* - memset(cur_trans, 0, sizeof(*cur_trans)); - kmem_cache_free(btrfs_transaction_cachep, cur_trans); - */ -} - -static int btrfs_cleanup_transaction(struct btrfs_root *root) -{ - struct btrfs_transaction *t; - - mutex_lock(&root->fs_info->transaction_kthread_mutex); - - spin_lock(&root->fs_info->trans_lock); - while (!list_empty(&root->fs_info->trans_list)) { - t = list_first_entry(&root->fs_info->trans_list, - struct btrfs_transaction, list); - if (t->state >= TRANS_STATE_COMMIT_START) { - atomic_inc(&t->use_count); - spin_unlock(&root->fs_info->trans_lock); - btrfs_wait_for_commit(root, t->transid); - btrfs_put_transaction(t); - spin_lock(&root->fs_info->trans_lock); - continue; - } - if (t == root->fs_info->running_transaction) { - t->state = TRANS_STATE_COMMIT_DOING; - spin_unlock(&root->fs_info->trans_lock); - /* - * We wait for 0 num_writers since we don't hold a trans - * handle open currently for this transaction. - */ - wait_event(t->writer_wait, - atomic_read(&t->num_writers) == 0); - } else { - spin_unlock(&root->fs_info->trans_lock); - } - btrfs_cleanup_one_transaction(t, root); - - spin_lock(&root->fs_info->trans_lock); - if (t == root->fs_info->running_transaction) - root->fs_info->running_transaction = NULL; - list_del_init(&t->list); - spin_unlock(&root->fs_info->trans_lock); - - btrfs_put_transaction(t); - trace_btrfs_transaction_commit(root); - spin_lock(&root->fs_info->trans_lock); - } - spin_unlock(&root->fs_info->trans_lock); - btrfs_destroy_all_ordered_extents(root->fs_info); - btrfs_destroy_delayed_inodes(root); - btrfs_assert_delayed_root_empty(root); - btrfs_destroy_pinned_extent(root, root->fs_info->pinned_extents); - btrfs_destroy_all_delalloc_inodes(root->fs_info); - mutex_unlock(&root->fs_info->transaction_kthread_mutex); - - return 0; -} - -static const struct extent_io_ops btree_extent_io_ops = { - .readpage_end_io_hook = btree_readpage_end_io_hook, - .readpage_io_failed_hook = btree_io_failed_hook, - .submit_bio_hook = btree_submit_bio_hook, - /* note we're sharing with inode.c for the merge bio hook */ - .merge_bio_hook = btrfs_merge_bio_hook, -}; diff --git a/src/linux/fs/btrfs/disk-io.h b/src/linux/fs/btrfs/disk-io.h deleted file mode 100644 index 1a3237e..0000000 --- a/src/linux/fs/btrfs/disk-io.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __DISKIO__ -#define __DISKIO__ - -#define BTRFS_SUPER_INFO_OFFSET SZ_64K -#define BTRFS_SUPER_INFO_SIZE 4096 - -#define BTRFS_SUPER_MIRROR_MAX 3 -#define BTRFS_SUPER_MIRROR_SHIFT 12 - -enum btrfs_wq_endio_type { - BTRFS_WQ_ENDIO_DATA = 0, - BTRFS_WQ_ENDIO_METADATA = 1, - BTRFS_WQ_ENDIO_FREE_SPACE = 2, - BTRFS_WQ_ENDIO_RAID56 = 3, - BTRFS_WQ_ENDIO_DIO_REPAIR = 4, -}; - -static inline u64 btrfs_sb_offset(int mirror) -{ - u64 start = SZ_16K; - if (mirror) - return start << (BTRFS_SUPER_MIRROR_SHIFT * mirror); - return BTRFS_SUPER_INFO_OFFSET; -} - -struct btrfs_device; -struct btrfs_fs_devices; - -struct extent_buffer *read_tree_block(struct btrfs_root *root, u64 bytenr, - u64 parent_transid); -void readahead_tree_block(struct btrfs_root *root, u64 bytenr); -int reada_tree_block_flagged(struct btrfs_root *root, u64 bytenr, - int mirror_num, struct extent_buffer **eb); -struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, - u64 bytenr); -void clean_tree_block(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, struct extent_buffer *buf); -int open_ctree(struct super_block *sb, - struct btrfs_fs_devices *fs_devices, - char *options); -void close_ctree(struct btrfs_root *root); -int write_ctree_super(struct btrfs_trans_handle *trans, - struct btrfs_root *root, int max_mirrors); -struct buffer_head *btrfs_read_dev_super(struct block_device *bdev); -int btrfs_read_dev_one_super(struct block_device *bdev, int copy_num, - struct buffer_head **bh_ret); -int btrfs_commit_super(struct btrfs_root *root); -struct extent_buffer *btrfs_find_tree_block(struct btrfs_fs_info *fs_info, - u64 bytenr); -struct btrfs_root *btrfs_read_fs_root(struct btrfs_root *tree_root, - struct btrfs_key *location); -int btrfs_init_fs_root(struct btrfs_root *root); -struct btrfs_root *btrfs_lookup_fs_root(struct btrfs_fs_info *fs_info, - u64 root_id); -int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info, - struct btrfs_root *root); -void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info); - -struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info, - struct btrfs_key *key, - bool check_ref); -static inline struct btrfs_root * -btrfs_read_fs_root_no_name(struct btrfs_fs_info *fs_info, - struct btrfs_key *location) -{ - return btrfs_get_fs_root(fs_info, location, true); -} - -int btrfs_cleanup_fs_roots(struct btrfs_fs_info *fs_info); -void btrfs_btree_balance_dirty(struct btrfs_root *root); -void btrfs_btree_balance_dirty_nodelay(struct btrfs_root *root); -void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info, - struct btrfs_root *root); -void btrfs_free_fs_root(struct btrfs_root *root); - -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS -struct btrfs_root *btrfs_alloc_dummy_root(struct btrfs_fs_info *fs_info, - u32 sectorsize, u32 nodesize); -#endif - -/* - * This function is used to grab the root, and avoid it is freed when we - * access it. But it doesn't ensure that the tree is not dropped. - * - * If you want to ensure the whole tree is safe, you should use - * fs_info->subvol_srcu - */ -static inline struct btrfs_root *btrfs_grab_fs_root(struct btrfs_root *root) -{ - if (atomic_inc_not_zero(&root->refs)) - return root; - return NULL; -} - -static inline void btrfs_put_fs_root(struct btrfs_root *root) -{ - if (atomic_dec_and_test(&root->refs)) - kfree(root); -} - -void btrfs_mark_buffer_dirty(struct extent_buffer *buf); -int btrfs_buffer_uptodate(struct extent_buffer *buf, u64 parent_transid, - int atomic); -int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid); -u32 btrfs_csum_data(char *data, u32 seed, size_t len); -void btrfs_csum_final(u32 crc, char *result); -int btrfs_bio_wq_end_io(struct btrfs_fs_info *info, struct bio *bio, - enum btrfs_wq_endio_type metadata); -int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, - struct bio *bio, int mirror_num, - unsigned long bio_flags, u64 bio_offset, - extent_submit_bio_hook_t *submit_bio_start, - extent_submit_bio_hook_t *submit_bio_done); -unsigned long btrfs_async_submit_limit(struct btrfs_fs_info *info); -int btrfs_write_tree_block(struct extent_buffer *buf); -int btrfs_wait_tree_block_writeback(struct extent_buffer *buf); -int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info); -int btrfs_add_log_tree(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -void btrfs_cleanup_dirty_bgs(struct btrfs_transaction *trans, - struct btrfs_root *root); -void btrfs_cleanup_one_transaction(struct btrfs_transaction *trans, - struct btrfs_root *root); -struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - u64 objectid); -int btree_lock_page_hook(struct page *page, void *data, - void (*flush_fn)(void *)); -int btrfs_get_num_tolerated_disk_barrier_failures(u64 flags); -int btrfs_calc_num_tolerated_disk_barrier_failures( - struct btrfs_fs_info *fs_info); -int __init btrfs_end_io_wq_init(void); -void btrfs_end_io_wq_exit(void); - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -void btrfs_init_lockdep(void); -void btrfs_set_buffer_lockdep_class(u64 objectid, - struct extent_buffer *eb, int level); -#else -static inline void btrfs_init_lockdep(void) -{ } -static inline void btrfs_set_buffer_lockdep_class(u64 objectid, - struct extent_buffer *eb, int level) -{ -} -#endif -#endif diff --git a/src/linux/fs/btrfs/export.c b/src/linux/fs/btrfs/export.c deleted file mode 100644 index 2513a7f..0000000 --- a/src/linux/fs/btrfs/export.c +++ /dev/null @@ -1,304 +0,0 @@ -#include -#include -#include "ctree.h" -#include "disk-io.h" -#include "btrfs_inode.h" -#include "print-tree.h" -#include "export.h" - -#define BTRFS_FID_SIZE_NON_CONNECTABLE (offsetof(struct btrfs_fid, \ - parent_objectid) / 4) -#define BTRFS_FID_SIZE_CONNECTABLE (offsetof(struct btrfs_fid, \ - parent_root_objectid) / 4) -#define BTRFS_FID_SIZE_CONNECTABLE_ROOT (sizeof(struct btrfs_fid) / 4) - -static int btrfs_encode_fh(struct inode *inode, u32 *fh, int *max_len, - struct inode *parent) -{ - struct btrfs_fid *fid = (struct btrfs_fid *)fh; - int len = *max_len; - int type; - - if (parent && (len < BTRFS_FID_SIZE_CONNECTABLE)) { - *max_len = BTRFS_FID_SIZE_CONNECTABLE; - return FILEID_INVALID; - } else if (len < BTRFS_FID_SIZE_NON_CONNECTABLE) { - *max_len = BTRFS_FID_SIZE_NON_CONNECTABLE; - return FILEID_INVALID; - } - - len = BTRFS_FID_SIZE_NON_CONNECTABLE; - type = FILEID_BTRFS_WITHOUT_PARENT; - - fid->objectid = btrfs_ino(inode); - fid->root_objectid = BTRFS_I(inode)->root->objectid; - fid->gen = inode->i_generation; - - if (parent) { - u64 parent_root_id; - - fid->parent_objectid = BTRFS_I(parent)->location.objectid; - fid->parent_gen = parent->i_generation; - parent_root_id = BTRFS_I(parent)->root->objectid; - - if (parent_root_id != fid->root_objectid) { - fid->parent_root_objectid = parent_root_id; - len = BTRFS_FID_SIZE_CONNECTABLE_ROOT; - type = FILEID_BTRFS_WITH_PARENT_ROOT; - } else { - len = BTRFS_FID_SIZE_CONNECTABLE; - type = FILEID_BTRFS_WITH_PARENT; - } - } - - *max_len = len; - return type; -} - -static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid, - u64 root_objectid, u32 generation, - int check_generation) -{ - struct btrfs_fs_info *fs_info = btrfs_sb(sb); - struct btrfs_root *root; - struct inode *inode; - struct btrfs_key key; - int index; - int err = 0; - - if (objectid < BTRFS_FIRST_FREE_OBJECTID) - return ERR_PTR(-ESTALE); - - key.objectid = root_objectid; - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = (u64)-1; - - index = srcu_read_lock(&fs_info->subvol_srcu); - - root = btrfs_read_fs_root_no_name(fs_info, &key); - if (IS_ERR(root)) { - err = PTR_ERR(root); - goto fail; - } - - key.objectid = objectid; - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - - inode = btrfs_iget(sb, &key, root, NULL); - if (IS_ERR(inode)) { - err = PTR_ERR(inode); - goto fail; - } - - srcu_read_unlock(&fs_info->subvol_srcu, index); - - if (check_generation && generation != inode->i_generation) { - iput(inode); - return ERR_PTR(-ESTALE); - } - - return d_obtain_alias(inode); -fail: - srcu_read_unlock(&fs_info->subvol_srcu, index); - return ERR_PTR(err); -} - -static struct dentry *btrfs_fh_to_parent(struct super_block *sb, struct fid *fh, - int fh_len, int fh_type) -{ - struct btrfs_fid *fid = (struct btrfs_fid *) fh; - u64 objectid, root_objectid; - u32 generation; - - if (fh_type == FILEID_BTRFS_WITH_PARENT) { - if (fh_len < BTRFS_FID_SIZE_CONNECTABLE) - return NULL; - root_objectid = fid->root_objectid; - } else if (fh_type == FILEID_BTRFS_WITH_PARENT_ROOT) { - if (fh_len < BTRFS_FID_SIZE_CONNECTABLE_ROOT) - return NULL; - root_objectid = fid->parent_root_objectid; - } else - return NULL; - - objectid = fid->parent_objectid; - generation = fid->parent_gen; - - return btrfs_get_dentry(sb, objectid, root_objectid, generation, 1); -} - -static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh, - int fh_len, int fh_type) -{ - struct btrfs_fid *fid = (struct btrfs_fid *) fh; - u64 objectid, root_objectid; - u32 generation; - - if ((fh_type != FILEID_BTRFS_WITH_PARENT || - fh_len < BTRFS_FID_SIZE_CONNECTABLE) && - (fh_type != FILEID_BTRFS_WITH_PARENT_ROOT || - fh_len < BTRFS_FID_SIZE_CONNECTABLE_ROOT) && - (fh_type != FILEID_BTRFS_WITHOUT_PARENT || - fh_len < BTRFS_FID_SIZE_NON_CONNECTABLE)) - return NULL; - - objectid = fid->objectid; - root_objectid = fid->root_objectid; - generation = fid->gen; - - return btrfs_get_dentry(sb, objectid, root_objectid, generation, 1); -} - -static struct dentry *btrfs_get_parent(struct dentry *child) -{ - struct inode *dir = d_inode(child); - struct btrfs_root *root = BTRFS_I(dir)->root; - struct btrfs_path *path; - struct extent_buffer *leaf; - struct btrfs_root_ref *ref; - struct btrfs_key key; - struct btrfs_key found_key; - int ret; - - path = btrfs_alloc_path(); - if (!path) - return ERR_PTR(-ENOMEM); - - if (btrfs_ino(dir) == BTRFS_FIRST_FREE_OBJECTID) { - key.objectid = root->root_key.objectid; - key.type = BTRFS_ROOT_BACKREF_KEY; - key.offset = (u64)-1; - root = root->fs_info->tree_root; - } else { - key.objectid = btrfs_ino(dir); - key.type = BTRFS_INODE_REF_KEY; - key.offset = (u64)-1; - } - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto fail; - - BUG_ON(ret == 0); /* Key with offset of -1 found */ - if (path->slots[0] == 0) { - ret = -ENOENT; - goto fail; - } - - path->slots[0]--; - leaf = path->nodes[0]; - - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - if (found_key.objectid != key.objectid || found_key.type != key.type) { - ret = -ENOENT; - goto fail; - } - - if (found_key.type == BTRFS_ROOT_BACKREF_KEY) { - ref = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_root_ref); - key.objectid = btrfs_root_ref_dirid(leaf, ref); - } else { - key.objectid = found_key.offset; - } - btrfs_free_path(path); - - if (found_key.type == BTRFS_ROOT_BACKREF_KEY) { - return btrfs_get_dentry(root->fs_info->sb, key.objectid, - found_key.offset, 0, 0); - } - - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - return d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root, NULL)); -fail: - btrfs_free_path(path); - return ERR_PTR(ret); -} - -static int btrfs_get_name(struct dentry *parent, char *name, - struct dentry *child) -{ - struct inode *inode = d_inode(child); - struct inode *dir = d_inode(parent); - struct btrfs_path *path; - struct btrfs_root *root = BTRFS_I(dir)->root; - struct btrfs_inode_ref *iref; - struct btrfs_root_ref *rref; - struct extent_buffer *leaf; - unsigned long name_ptr; - struct btrfs_key key; - int name_len; - int ret; - u64 ino; - - if (!dir || !inode) - return -EINVAL; - - if (!S_ISDIR(dir->i_mode)) - return -EINVAL; - - ino = btrfs_ino(inode); - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->leave_spinning = 1; - - if (ino == BTRFS_FIRST_FREE_OBJECTID) { - key.objectid = BTRFS_I(inode)->root->root_key.objectid; - key.type = BTRFS_ROOT_BACKREF_KEY; - key.offset = (u64)-1; - root = root->fs_info->tree_root; - } else { - key.objectid = ino; - key.offset = btrfs_ino(dir); - key.type = BTRFS_INODE_REF_KEY; - } - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) { - btrfs_free_path(path); - return ret; - } else if (ret > 0) { - if (ino == BTRFS_FIRST_FREE_OBJECTID) { - path->slots[0]--; - } else { - btrfs_free_path(path); - return -ENOENT; - } - } - leaf = path->nodes[0]; - - if (ino == BTRFS_FIRST_FREE_OBJECTID) { - rref = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_root_ref); - name_ptr = (unsigned long)(rref + 1); - name_len = btrfs_root_ref_name_len(leaf, rref); - } else { - iref = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_inode_ref); - name_ptr = (unsigned long)(iref + 1); - name_len = btrfs_inode_ref_name_len(leaf, iref); - } - - read_extent_buffer(leaf, name, name_ptr, name_len); - btrfs_free_path(path); - - /* - * have to add the null termination to make sure that reconnect_path - * gets the right len for strlen - */ - name[name_len] = '\0'; - - return 0; -} - -const struct export_operations btrfs_export_ops = { - .encode_fh = btrfs_encode_fh, - .fh_to_dentry = btrfs_fh_to_dentry, - .fh_to_parent = btrfs_fh_to_parent, - .get_parent = btrfs_get_parent, - .get_name = btrfs_get_name, -}; diff --git a/src/linux/fs/btrfs/export.h b/src/linux/fs/btrfs/export.h deleted file mode 100644 index 074348a..0000000 --- a/src/linux/fs/btrfs/export.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef BTRFS_EXPORT_H -#define BTRFS_EXPORT_H - -#include - -extern const struct export_operations btrfs_export_ops; - -struct btrfs_fid { - u64 objectid; - u64 root_objectid; - u32 gen; - - u64 parent_objectid; - u32 parent_gen; - - u64 parent_root_objectid; -} __attribute__ ((packed)); - -#endif diff --git a/src/linux/fs/btrfs/extent-tree.c b/src/linux/fs/btrfs/extent-tree.c deleted file mode 100644 index 4607af3..0000000 --- a/src/linux/fs/btrfs/extent-tree.c +++ /dev/null @@ -1,11243 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "hash.h" -#include "tree-log.h" -#include "disk-io.h" -#include "print-tree.h" -#include "volumes.h" -#include "raid56.h" -#include "locking.h" -#include "free-space-cache.h" -#include "free-space-tree.h" -#include "math.h" -#include "sysfs.h" -#include "qgroup.h" - -#undef SCRAMBLE_DELAYED_REFS - -/* - * control flags for do_chunk_alloc's force field - * CHUNK_ALLOC_NO_FORCE means to only allocate a chunk - * if we really need one. - * - * CHUNK_ALLOC_LIMITED means to only try and allocate one - * if we have very few chunks already allocated. This is - * used as part of the clustering code to help make sure - * we have a good pool of storage to cluster in, without - * filling the FS with empty chunks - * - * CHUNK_ALLOC_FORCE means it must try to allocate one - * - */ -enum { - CHUNK_ALLOC_NO_FORCE = 0, - CHUNK_ALLOC_LIMITED = 1, - CHUNK_ALLOC_FORCE = 2, -}; - -static int update_block_group(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 bytenr, - u64 num_bytes, int alloc); -static int __btrfs_free_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_delayed_ref_node *node, u64 parent, - u64 root_objectid, u64 owner_objectid, - u64 owner_offset, int refs_to_drop, - struct btrfs_delayed_extent_op *extra_op); -static void __run_delayed_extent_op(struct btrfs_delayed_extent_op *extent_op, - struct extent_buffer *leaf, - struct btrfs_extent_item *ei); -static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 parent, u64 root_objectid, - u64 flags, u64 owner, u64 offset, - struct btrfs_key *ins, int ref_mod); -static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 parent, u64 root_objectid, - u64 flags, struct btrfs_disk_key *key, - int level, struct btrfs_key *ins); -static int do_chunk_alloc(struct btrfs_trans_handle *trans, - struct btrfs_root *extent_root, u64 flags, - int force); -static int find_next_key(struct btrfs_path *path, int level, - struct btrfs_key *key); -static void dump_space_info(struct btrfs_fs_info *fs_info, - struct btrfs_space_info *info, u64 bytes, - int dump_block_groups); -static int btrfs_add_reserved_bytes(struct btrfs_block_group_cache *cache, - u64 ram_bytes, u64 num_bytes, int delalloc); -static int btrfs_free_reserved_bytes(struct btrfs_block_group_cache *cache, - u64 num_bytes, int delalloc); -static int block_rsv_use_bytes(struct btrfs_block_rsv *block_rsv, - u64 num_bytes); -int btrfs_pin_extent(struct btrfs_root *root, - u64 bytenr, u64 num_bytes, int reserved); -static int __reserve_metadata_bytes(struct btrfs_root *root, - struct btrfs_space_info *space_info, - u64 orig_bytes, - enum btrfs_reserve_flush_enum flush); -static void space_info_add_new_bytes(struct btrfs_fs_info *fs_info, - struct btrfs_space_info *space_info, - u64 num_bytes); -static void space_info_add_old_bytes(struct btrfs_fs_info *fs_info, - struct btrfs_space_info *space_info, - u64 num_bytes); - -static noinline int -block_group_cache_done(struct btrfs_block_group_cache *cache) -{ - smp_mb(); - return cache->cached == BTRFS_CACHE_FINISHED || - cache->cached == BTRFS_CACHE_ERROR; -} - -static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits) -{ - return (cache->flags & bits) == bits; -} - -void btrfs_get_block_group(struct btrfs_block_group_cache *cache) -{ - atomic_inc(&cache->count); -} - -void btrfs_put_block_group(struct btrfs_block_group_cache *cache) -{ - if (atomic_dec_and_test(&cache->count)) { - WARN_ON(cache->pinned > 0); - WARN_ON(cache->reserved > 0); - kfree(cache->free_space_ctl); - kfree(cache); - } -} - -/* - * this adds the block group to the fs_info rb tree for the block group - * cache - */ -static int btrfs_add_block_group_cache(struct btrfs_fs_info *info, - struct btrfs_block_group_cache *block_group) -{ - struct rb_node **p; - struct rb_node *parent = NULL; - struct btrfs_block_group_cache *cache; - - spin_lock(&info->block_group_cache_lock); - p = &info->block_group_cache_tree.rb_node; - - while (*p) { - parent = *p; - cache = rb_entry(parent, struct btrfs_block_group_cache, - cache_node); - if (block_group->key.objectid < cache->key.objectid) { - p = &(*p)->rb_left; - } else if (block_group->key.objectid > cache->key.objectid) { - p = &(*p)->rb_right; - } else { - spin_unlock(&info->block_group_cache_lock); - return -EEXIST; - } - } - - rb_link_node(&block_group->cache_node, parent, p); - rb_insert_color(&block_group->cache_node, - &info->block_group_cache_tree); - - if (info->first_logical_byte > block_group->key.objectid) - info->first_logical_byte = block_group->key.objectid; - - spin_unlock(&info->block_group_cache_lock); - - return 0; -} - -/* - * This will return the block group at or after bytenr if contains is 0, else - * it will return the block group that contains the bytenr - */ -static struct btrfs_block_group_cache * -block_group_cache_tree_search(struct btrfs_fs_info *info, u64 bytenr, - int contains) -{ - struct btrfs_block_group_cache *cache, *ret = NULL; - struct rb_node *n; - u64 end, start; - - spin_lock(&info->block_group_cache_lock); - n = info->block_group_cache_tree.rb_node; - - while (n) { - cache = rb_entry(n, struct btrfs_block_group_cache, - cache_node); - end = cache->key.objectid + cache->key.offset - 1; - start = cache->key.objectid; - - if (bytenr < start) { - if (!contains && (!ret || start < ret->key.objectid)) - ret = cache; - n = n->rb_left; - } else if (bytenr > start) { - if (contains && bytenr <= end) { - ret = cache; - break; - } - n = n->rb_right; - } else { - ret = cache; - break; - } - } - if (ret) { - btrfs_get_block_group(ret); - if (bytenr == 0 && info->first_logical_byte > ret->key.objectid) - info->first_logical_byte = ret->key.objectid; - } - spin_unlock(&info->block_group_cache_lock); - - return ret; -} - -static int add_excluded_extent(struct btrfs_root *root, - u64 start, u64 num_bytes) -{ - u64 end = start + num_bytes - 1; - set_extent_bits(&root->fs_info->freed_extents[0], - start, end, EXTENT_UPTODATE); - set_extent_bits(&root->fs_info->freed_extents[1], - start, end, EXTENT_UPTODATE); - return 0; -} - -static void free_excluded_extents(struct btrfs_root *root, - struct btrfs_block_group_cache *cache) -{ - u64 start, end; - - start = cache->key.objectid; - end = start + cache->key.offset - 1; - - clear_extent_bits(&root->fs_info->freed_extents[0], - start, end, EXTENT_UPTODATE); - clear_extent_bits(&root->fs_info->freed_extents[1], - start, end, EXTENT_UPTODATE); -} - -static int exclude_super_stripes(struct btrfs_root *root, - struct btrfs_block_group_cache *cache) -{ - u64 bytenr; - u64 *logical; - int stripe_len; - int i, nr, ret; - - if (cache->key.objectid < BTRFS_SUPER_INFO_OFFSET) { - stripe_len = BTRFS_SUPER_INFO_OFFSET - cache->key.objectid; - cache->bytes_super += stripe_len; - ret = add_excluded_extent(root, cache->key.objectid, - stripe_len); - if (ret) - return ret; - } - - for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { - bytenr = btrfs_sb_offset(i); - ret = btrfs_rmap_block(root->fs_info, cache->key.objectid, - bytenr, 0, &logical, &nr, &stripe_len); - if (ret) - return ret; - - while (nr--) { - u64 start, len; - - if (logical[nr] > cache->key.objectid + - cache->key.offset) - continue; - - if (logical[nr] + stripe_len <= cache->key.objectid) - continue; - - start = logical[nr]; - if (start < cache->key.objectid) { - start = cache->key.objectid; - len = (logical[nr] + stripe_len) - start; - } else { - len = min_t(u64, stripe_len, - cache->key.objectid + - cache->key.offset - start); - } - - cache->bytes_super += len; - ret = add_excluded_extent(root, start, len); - if (ret) { - kfree(logical); - return ret; - } - } - - kfree(logical); - } - return 0; -} - -static struct btrfs_caching_control * -get_caching_control(struct btrfs_block_group_cache *cache) -{ - struct btrfs_caching_control *ctl; - - spin_lock(&cache->lock); - if (!cache->caching_ctl) { - spin_unlock(&cache->lock); - return NULL; - } - - ctl = cache->caching_ctl; - atomic_inc(&ctl->count); - spin_unlock(&cache->lock); - return ctl; -} - -static void put_caching_control(struct btrfs_caching_control *ctl) -{ - if (atomic_dec_and_test(&ctl->count)) - kfree(ctl); -} - -#ifdef CONFIG_BTRFS_DEBUG -static void fragment_free_space(struct btrfs_root *root, - struct btrfs_block_group_cache *block_group) -{ - u64 start = block_group->key.objectid; - u64 len = block_group->key.offset; - u64 chunk = block_group->flags & BTRFS_BLOCK_GROUP_METADATA ? - root->nodesize : root->sectorsize; - u64 step = chunk << 1; - - while (len > chunk) { - btrfs_remove_free_space(block_group, start, chunk); - start += step; - if (len < step) - len = 0; - else - len -= step; - } -} -#endif - -/* - * this is only called by cache_block_group, since we could have freed extents - * we need to check the pinned_extents for any extents that can't be used yet - * since their free space will be released as soon as the transaction commits. - */ -u64 add_new_free_space(struct btrfs_block_group_cache *block_group, - struct btrfs_fs_info *info, u64 start, u64 end) -{ - u64 extent_start, extent_end, size, total_added = 0; - int ret; - - while (start < end) { - ret = find_first_extent_bit(info->pinned_extents, start, - &extent_start, &extent_end, - EXTENT_DIRTY | EXTENT_UPTODATE, - NULL); - if (ret) - break; - - if (extent_start <= start) { - start = extent_end + 1; - } else if (extent_start > start && extent_start < end) { - size = extent_start - start; - total_added += size; - ret = btrfs_add_free_space(block_group, start, - size); - BUG_ON(ret); /* -ENOMEM or logic error */ - start = extent_end + 1; - } else { - break; - } - } - - if (start < end) { - size = end - start; - total_added += size; - ret = btrfs_add_free_space(block_group, start, size); - BUG_ON(ret); /* -ENOMEM or logic error */ - } - - return total_added; -} - -static int load_extent_tree_free(struct btrfs_caching_control *caching_ctl) -{ - struct btrfs_block_group_cache *block_group; - struct btrfs_fs_info *fs_info; - struct btrfs_root *extent_root; - struct btrfs_path *path; - struct extent_buffer *leaf; - struct btrfs_key key; - u64 total_found = 0; - u64 last = 0; - u32 nritems; - int ret; - bool wakeup = true; - - block_group = caching_ctl->block_group; - fs_info = block_group->fs_info; - extent_root = fs_info->extent_root; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - last = max_t(u64, block_group->key.objectid, BTRFS_SUPER_INFO_OFFSET); - -#ifdef CONFIG_BTRFS_DEBUG - /* - * If we're fragmenting we don't want to make anybody think we can - * allocate from this block group until we've had a chance to fragment - * the free space. - */ - if (btrfs_should_fragment_free_space(extent_root, block_group)) - wakeup = false; -#endif - /* - * We don't want to deadlock with somebody trying to allocate a new - * extent for the extent root while also trying to search the extent - * root to add free space. So we skip locking and search the commit - * root, since its read-only - */ - path->skip_locking = 1; - path->search_commit_root = 1; - path->reada = READA_FORWARD; - - key.objectid = last; - key.offset = 0; - key.type = BTRFS_EXTENT_ITEM_KEY; - -next: - ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0); - if (ret < 0) - goto out; - - leaf = path->nodes[0]; - nritems = btrfs_header_nritems(leaf); - - while (1) { - if (btrfs_fs_closing(fs_info) > 1) { - last = (u64)-1; - break; - } - - if (path->slots[0] < nritems) { - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - } else { - ret = find_next_key(path, 0, &key); - if (ret) - break; - - if (need_resched() || - rwsem_is_contended(&fs_info->commit_root_sem)) { - if (wakeup) - caching_ctl->progress = last; - btrfs_release_path(path); - up_read(&fs_info->commit_root_sem); - mutex_unlock(&caching_ctl->mutex); - cond_resched(); - mutex_lock(&caching_ctl->mutex); - down_read(&fs_info->commit_root_sem); - goto next; - } - - ret = btrfs_next_leaf(extent_root, path); - if (ret < 0) - goto out; - if (ret) - break; - leaf = path->nodes[0]; - nritems = btrfs_header_nritems(leaf); - continue; - } - - if (key.objectid < last) { - key.objectid = last; - key.offset = 0; - key.type = BTRFS_EXTENT_ITEM_KEY; - - if (wakeup) - caching_ctl->progress = last; - btrfs_release_path(path); - goto next; - } - - if (key.objectid < block_group->key.objectid) { - path->slots[0]++; - continue; - } - - if (key.objectid >= block_group->key.objectid + - block_group->key.offset) - break; - - if (key.type == BTRFS_EXTENT_ITEM_KEY || - key.type == BTRFS_METADATA_ITEM_KEY) { - total_found += add_new_free_space(block_group, - fs_info, last, - key.objectid); - if (key.type == BTRFS_METADATA_ITEM_KEY) - last = key.objectid + - fs_info->tree_root->nodesize; - else - last = key.objectid + key.offset; - - if (total_found > CACHING_CTL_WAKE_UP) { - total_found = 0; - if (wakeup) - wake_up(&caching_ctl->wait); - } - } - path->slots[0]++; - } - ret = 0; - - total_found += add_new_free_space(block_group, fs_info, last, - block_group->key.objectid + - block_group->key.offset); - caching_ctl->progress = (u64)-1; - -out: - btrfs_free_path(path); - return ret; -} - -static noinline void caching_thread(struct btrfs_work *work) -{ - struct btrfs_block_group_cache *block_group; - struct btrfs_fs_info *fs_info; - struct btrfs_caching_control *caching_ctl; - struct btrfs_root *extent_root; - int ret; - - caching_ctl = container_of(work, struct btrfs_caching_control, work); - block_group = caching_ctl->block_group; - fs_info = block_group->fs_info; - extent_root = fs_info->extent_root; - - mutex_lock(&caching_ctl->mutex); - down_read(&fs_info->commit_root_sem); - - if (btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) - ret = load_free_space_tree(caching_ctl); - else - ret = load_extent_tree_free(caching_ctl); - - spin_lock(&block_group->lock); - block_group->caching_ctl = NULL; - block_group->cached = ret ? BTRFS_CACHE_ERROR : BTRFS_CACHE_FINISHED; - spin_unlock(&block_group->lock); - -#ifdef CONFIG_BTRFS_DEBUG - if (btrfs_should_fragment_free_space(extent_root, block_group)) { - u64 bytes_used; - - spin_lock(&block_group->space_info->lock); - spin_lock(&block_group->lock); - bytes_used = block_group->key.offset - - btrfs_block_group_used(&block_group->item); - block_group->space_info->bytes_used += bytes_used >> 1; - spin_unlock(&block_group->lock); - spin_unlock(&block_group->space_info->lock); - fragment_free_space(extent_root, block_group); - } -#endif - - caching_ctl->progress = (u64)-1; - - up_read(&fs_info->commit_root_sem); - free_excluded_extents(fs_info->extent_root, block_group); - mutex_unlock(&caching_ctl->mutex); - - wake_up(&caching_ctl->wait); - - put_caching_control(caching_ctl); - btrfs_put_block_group(block_group); -} - -static int cache_block_group(struct btrfs_block_group_cache *cache, - int load_cache_only) -{ - DEFINE_WAIT(wait); - struct btrfs_fs_info *fs_info = cache->fs_info; - struct btrfs_caching_control *caching_ctl; - int ret = 0; - - caching_ctl = kzalloc(sizeof(*caching_ctl), GFP_NOFS); - if (!caching_ctl) - return -ENOMEM; - - INIT_LIST_HEAD(&caching_ctl->list); - mutex_init(&caching_ctl->mutex); - init_waitqueue_head(&caching_ctl->wait); - caching_ctl->block_group = cache; - caching_ctl->progress = cache->key.objectid; - atomic_set(&caching_ctl->count, 1); - btrfs_init_work(&caching_ctl->work, btrfs_cache_helper, - caching_thread, NULL, NULL); - - spin_lock(&cache->lock); - /* - * This should be a rare occasion, but this could happen I think in the - * case where one thread starts to load the space cache info, and then - * some other thread starts a transaction commit which tries to do an - * allocation while the other thread is still loading the space cache - * info. The previous loop should have kept us from choosing this block - * group, but if we've moved to the state where we will wait on caching - * block groups we need to first check if we're doing a fast load here, - * so we can wait for it to finish, otherwise we could end up allocating - * from a block group who's cache gets evicted for one reason or - * another. - */ - while (cache->cached == BTRFS_CACHE_FAST) { - struct btrfs_caching_control *ctl; - - ctl = cache->caching_ctl; - atomic_inc(&ctl->count); - prepare_to_wait(&ctl->wait, &wait, TASK_UNINTERRUPTIBLE); - spin_unlock(&cache->lock); - - schedule(); - - finish_wait(&ctl->wait, &wait); - put_caching_control(ctl); - spin_lock(&cache->lock); - } - - if (cache->cached != BTRFS_CACHE_NO) { - spin_unlock(&cache->lock); - kfree(caching_ctl); - return 0; - } - WARN_ON(cache->caching_ctl); - cache->caching_ctl = caching_ctl; - cache->cached = BTRFS_CACHE_FAST; - spin_unlock(&cache->lock); - - if (fs_info->mount_opt & BTRFS_MOUNT_SPACE_CACHE) { - mutex_lock(&caching_ctl->mutex); - ret = load_free_space_cache(fs_info, cache); - - spin_lock(&cache->lock); - if (ret == 1) { - cache->caching_ctl = NULL; - cache->cached = BTRFS_CACHE_FINISHED; - cache->last_byte_to_unpin = (u64)-1; - caching_ctl->progress = (u64)-1; - } else { - if (load_cache_only) { - cache->caching_ctl = NULL; - cache->cached = BTRFS_CACHE_NO; - } else { - cache->cached = BTRFS_CACHE_STARTED; - cache->has_caching_ctl = 1; - } - } - spin_unlock(&cache->lock); -#ifdef CONFIG_BTRFS_DEBUG - if (ret == 1 && - btrfs_should_fragment_free_space(fs_info->extent_root, - cache)) { - u64 bytes_used; - - spin_lock(&cache->space_info->lock); - spin_lock(&cache->lock); - bytes_used = cache->key.offset - - btrfs_block_group_used(&cache->item); - cache->space_info->bytes_used += bytes_used >> 1; - spin_unlock(&cache->lock); - spin_unlock(&cache->space_info->lock); - fragment_free_space(fs_info->extent_root, cache); - } -#endif - mutex_unlock(&caching_ctl->mutex); - - wake_up(&caching_ctl->wait); - if (ret == 1) { - put_caching_control(caching_ctl); - free_excluded_extents(fs_info->extent_root, cache); - return 0; - } - } else { - /* - * We're either using the free space tree or no caching at all. - * Set cached to the appropriate value and wakeup any waiters. - */ - spin_lock(&cache->lock); - if (load_cache_only) { - cache->caching_ctl = NULL; - cache->cached = BTRFS_CACHE_NO; - } else { - cache->cached = BTRFS_CACHE_STARTED; - cache->has_caching_ctl = 1; - } - spin_unlock(&cache->lock); - wake_up(&caching_ctl->wait); - } - - if (load_cache_only) { - put_caching_control(caching_ctl); - return 0; - } - - down_write(&fs_info->commit_root_sem); - atomic_inc(&caching_ctl->count); - list_add_tail(&caching_ctl->list, &fs_info->caching_block_groups); - up_write(&fs_info->commit_root_sem); - - btrfs_get_block_group(cache); - - btrfs_queue_work(fs_info->caching_workers, &caching_ctl->work); - - return ret; -} - -/* - * return the block group that starts at or after bytenr - */ -static struct btrfs_block_group_cache * -btrfs_lookup_first_block_group(struct btrfs_fs_info *info, u64 bytenr) -{ - return block_group_cache_tree_search(info, bytenr, 0); -} - -/* - * return the block group that contains the given bytenr - */ -struct btrfs_block_group_cache *btrfs_lookup_block_group( - struct btrfs_fs_info *info, - u64 bytenr) -{ - return block_group_cache_tree_search(info, bytenr, 1); -} - -static struct btrfs_space_info *__find_space_info(struct btrfs_fs_info *info, - u64 flags) -{ - struct list_head *head = &info->space_info; - struct btrfs_space_info *found; - - flags &= BTRFS_BLOCK_GROUP_TYPE_MASK; - - rcu_read_lock(); - list_for_each_entry_rcu(found, head, list) { - if (found->flags & flags) { - rcu_read_unlock(); - return found; - } - } - rcu_read_unlock(); - return NULL; -} - -/* - * after adding space to the filesystem, we need to clear the full flags - * on all the space infos. - */ -void btrfs_clear_space_info_full(struct btrfs_fs_info *info) -{ - struct list_head *head = &info->space_info; - struct btrfs_space_info *found; - - rcu_read_lock(); - list_for_each_entry_rcu(found, head, list) - found->full = 0; - rcu_read_unlock(); -} - -/* simple helper to search for an existing data extent at a given offset */ -int btrfs_lookup_data_extent(struct btrfs_root *root, u64 start, u64 len) -{ - int ret; - struct btrfs_key key; - struct btrfs_path *path; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - key.objectid = start; - key.offset = len; - key.type = BTRFS_EXTENT_ITEM_KEY; - ret = btrfs_search_slot(NULL, root->fs_info->extent_root, &key, path, - 0, 0); - btrfs_free_path(path); - return ret; -} - -/* - * helper function to lookup reference count and flags of a tree block. - * - * the head node for delayed ref is used to store the sum of all the - * reference count modifications queued up in the rbtree. the head - * node may also store the extent flags to set. This way you can check - * to see what the reference count and extent flags would be if all of - * the delayed refs are not processed. - */ -int btrfs_lookup_extent_info(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 bytenr, - u64 offset, int metadata, u64 *refs, u64 *flags) -{ - struct btrfs_delayed_ref_head *head; - struct btrfs_delayed_ref_root *delayed_refs; - struct btrfs_path *path; - struct btrfs_extent_item *ei; - struct extent_buffer *leaf; - struct btrfs_key key; - u32 item_size; - u64 num_refs; - u64 extent_flags; - int ret; - - /* - * If we don't have skinny metadata, don't bother doing anything - * different - */ - if (metadata && !btrfs_fs_incompat(root->fs_info, SKINNY_METADATA)) { - offset = root->nodesize; - metadata = 0; - } - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - if (!trans) { - path->skip_locking = 1; - path->search_commit_root = 1; - } - -search_again: - key.objectid = bytenr; - key.offset = offset; - if (metadata) - key.type = BTRFS_METADATA_ITEM_KEY; - else - key.type = BTRFS_EXTENT_ITEM_KEY; - - ret = btrfs_search_slot(trans, root->fs_info->extent_root, - &key, path, 0, 0); - if (ret < 0) - goto out_free; - - if (ret > 0 && metadata && key.type == BTRFS_METADATA_ITEM_KEY) { - if (path->slots[0]) { - path->slots[0]--; - btrfs_item_key_to_cpu(path->nodes[0], &key, - path->slots[0]); - if (key.objectid == bytenr && - key.type == BTRFS_EXTENT_ITEM_KEY && - key.offset == root->nodesize) - ret = 0; - } - } - - if (ret == 0) { - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, path->slots[0]); - if (item_size >= sizeof(*ei)) { - ei = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_item); - num_refs = btrfs_extent_refs(leaf, ei); - extent_flags = btrfs_extent_flags(leaf, ei); - } else { -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - struct btrfs_extent_item_v0 *ei0; - BUG_ON(item_size != sizeof(*ei0)); - ei0 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_item_v0); - num_refs = btrfs_extent_refs_v0(leaf, ei0); - /* FIXME: this isn't correct for data */ - extent_flags = BTRFS_BLOCK_FLAG_FULL_BACKREF; -#else - BUG(); -#endif - } - BUG_ON(num_refs == 0); - } else { - num_refs = 0; - extent_flags = 0; - ret = 0; - } - - if (!trans) - goto out; - - delayed_refs = &trans->transaction->delayed_refs; - spin_lock(&delayed_refs->lock); - head = btrfs_find_delayed_ref_head(trans, bytenr); - if (head) { - if (!mutex_trylock(&head->mutex)) { - atomic_inc(&head->node.refs); - spin_unlock(&delayed_refs->lock); - - btrfs_release_path(path); - - /* - * Mutex was contended, block until it's released and try - * again - */ - mutex_lock(&head->mutex); - mutex_unlock(&head->mutex); - btrfs_put_delayed_ref(&head->node); - goto search_again; - } - spin_lock(&head->lock); - if (head->extent_op && head->extent_op->update_flags) - extent_flags |= head->extent_op->flags_to_set; - else - BUG_ON(num_refs == 0); - - num_refs += head->node.ref_mod; - spin_unlock(&head->lock); - mutex_unlock(&head->mutex); - } - spin_unlock(&delayed_refs->lock); -out: - WARN_ON(num_refs == 0); - if (refs) - *refs = num_refs; - if (flags) - *flags = extent_flags; -out_free: - btrfs_free_path(path); - return ret; -} - -/* - * Back reference rules. Back refs have three main goals: - * - * 1) differentiate between all holders of references to an extent so that - * when a reference is dropped we can make sure it was a valid reference - * before freeing the extent. - * - * 2) Provide enough information to quickly find the holders of an extent - * if we notice a given block is corrupted or bad. - * - * 3) Make it easy to migrate blocks for FS shrinking or storage pool - * maintenance. This is actually the same as #2, but with a slightly - * different use case. - * - * There are two kinds of back refs. The implicit back refs is optimized - * for pointers in non-shared tree blocks. For a given pointer in a block, - * back refs of this kind provide information about the block's owner tree - * and the pointer's key. These information allow us to find the block by - * b-tree searching. The full back refs is for pointers in tree blocks not - * referenced by their owner trees. The location of tree block is recorded - * in the back refs. Actually the full back refs is generic, and can be - * used in all cases the implicit back refs is used. The major shortcoming - * of the full back refs is its overhead. Every time a tree block gets - * COWed, we have to update back refs entry for all pointers in it. - * - * For a newly allocated tree block, we use implicit back refs for - * pointers in it. This means most tree related operations only involve - * implicit back refs. For a tree block created in old transaction, the - * only way to drop a reference to it is COW it. So we can detect the - * event that tree block loses its owner tree's reference and do the - * back refs conversion. - * - * When a tree block is COWed through a tree, there are four cases: - * - * The reference count of the block is one and the tree is the block's - * owner tree. Nothing to do in this case. - * - * The reference count of the block is one and the tree is not the - * block's owner tree. In this case, full back refs is used for pointers - * in the block. Remove these full back refs, add implicit back refs for - * every pointers in the new block. - * - * The reference count of the block is greater than one and the tree is - * the block's owner tree. In this case, implicit back refs is used for - * pointers in the block. Add full back refs for every pointers in the - * block, increase lower level extents' reference counts. The original - * implicit back refs are entailed to the new block. - * - * The reference count of the block is greater than one and the tree is - * not the block's owner tree. Add implicit back refs for every pointer in - * the new block, increase lower level extents' reference count. - * - * Back Reference Key composing: - * - * The key objectid corresponds to the first byte in the extent, - * The key type is used to differentiate between types of back refs. - * There are different meanings of the key offset for different types - * of back refs. - * - * File extents can be referenced by: - * - * - multiple snapshots, subvolumes, or different generations in one subvol - * - different files inside a single subvolume - * - different offsets inside a file (bookend extents in file.c) - * - * The extent ref structure for the implicit back refs has fields for: - * - * - Objectid of the subvolume root - * - objectid of the file holding the reference - * - original offset in the file - * - how many bookend extents - * - * The key offset for the implicit back refs is hash of the first - * three fields. - * - * The extent ref structure for the full back refs has field for: - * - * - number of pointers in the tree leaf - * - * The key offset for the implicit back refs is the first byte of - * the tree leaf - * - * When a file extent is allocated, The implicit back refs is used. - * the fields are filled in: - * - * (root_key.objectid, inode objectid, offset in file, 1) - * - * When a file extent is removed file truncation, we find the - * corresponding implicit back refs and check the following fields: - * - * (btrfs_header_owner(leaf), inode objectid, offset in file) - * - * Btree extents can be referenced by: - * - * - Different subvolumes - * - * Both the implicit back refs and the full back refs for tree blocks - * only consist of key. The key offset for the implicit back refs is - * objectid of block's owner tree. The key offset for the full back refs - * is the first byte of parent block. - * - * When implicit back refs is used, information about the lowest key and - * level of the tree block are required. These information are stored in - * tree block info structure. - */ - -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 -static int convert_extent_item_v0(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - u64 owner, u32 extra_size) -{ - struct btrfs_extent_item *item; - struct btrfs_extent_item_v0 *ei0; - struct btrfs_extent_ref_v0 *ref0; - struct btrfs_tree_block_info *bi; - struct extent_buffer *leaf; - struct btrfs_key key; - struct btrfs_key found_key; - u32 new_size = sizeof(*item); - u64 refs; - int ret; - - leaf = path->nodes[0]; - BUG_ON(btrfs_item_size_nr(leaf, path->slots[0]) != sizeof(*ei0)); - - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - ei0 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_item_v0); - refs = btrfs_extent_refs_v0(leaf, ei0); - - if (owner == (u64)-1) { - while (1) { - if (path->slots[0] >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) - return ret; - BUG_ON(ret > 0); /* Corruption */ - leaf = path->nodes[0]; - } - btrfs_item_key_to_cpu(leaf, &found_key, - path->slots[0]); - BUG_ON(key.objectid != found_key.objectid); - if (found_key.type != BTRFS_EXTENT_REF_V0_KEY) { - path->slots[0]++; - continue; - } - ref0 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_ref_v0); - owner = btrfs_ref_objectid_v0(leaf, ref0); - break; - } - } - btrfs_release_path(path); - - if (owner < BTRFS_FIRST_FREE_OBJECTID) - new_size += sizeof(*bi); - - new_size -= sizeof(*ei0); - ret = btrfs_search_slot(trans, root, &key, path, - new_size + extra_size, 1); - if (ret < 0) - return ret; - BUG_ON(ret); /* Corruption */ - - btrfs_extend_item(root, path, new_size); - - leaf = path->nodes[0]; - item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); - btrfs_set_extent_refs(leaf, item, refs); - /* FIXME: get real generation */ - btrfs_set_extent_generation(leaf, item, 0); - if (owner < BTRFS_FIRST_FREE_OBJECTID) { - btrfs_set_extent_flags(leaf, item, - BTRFS_EXTENT_FLAG_TREE_BLOCK | - BTRFS_BLOCK_FLAG_FULL_BACKREF); - bi = (struct btrfs_tree_block_info *)(item + 1); - /* FIXME: get first key of the block */ - memset_extent_buffer(leaf, 0, (unsigned long)bi, sizeof(*bi)); - btrfs_set_tree_block_level(leaf, bi, (int)owner); - } else { - btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_DATA); - } - btrfs_mark_buffer_dirty(leaf); - return 0; -} -#endif - -static u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset) -{ - u32 high_crc = ~(u32)0; - u32 low_crc = ~(u32)0; - __le64 lenum; - - lenum = cpu_to_le64(root_objectid); - high_crc = btrfs_crc32c(high_crc, &lenum, sizeof(lenum)); - lenum = cpu_to_le64(owner); - low_crc = btrfs_crc32c(low_crc, &lenum, sizeof(lenum)); - lenum = cpu_to_le64(offset); - low_crc = btrfs_crc32c(low_crc, &lenum, sizeof(lenum)); - - return ((u64)high_crc << 31) ^ (u64)low_crc; -} - -static u64 hash_extent_data_ref_item(struct extent_buffer *leaf, - struct btrfs_extent_data_ref *ref) -{ - return hash_extent_data_ref(btrfs_extent_data_ref_root(leaf, ref), - btrfs_extent_data_ref_objectid(leaf, ref), - btrfs_extent_data_ref_offset(leaf, ref)); -} - -static int match_extent_data_ref(struct extent_buffer *leaf, - struct btrfs_extent_data_ref *ref, - u64 root_objectid, u64 owner, u64 offset) -{ - if (btrfs_extent_data_ref_root(leaf, ref) != root_objectid || - btrfs_extent_data_ref_objectid(leaf, ref) != owner || - btrfs_extent_data_ref_offset(leaf, ref) != offset) - return 0; - return 1; -} - -static noinline int lookup_extent_data_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - u64 bytenr, u64 parent, - u64 root_objectid, - u64 owner, u64 offset) -{ - struct btrfs_key key; - struct btrfs_extent_data_ref *ref; - struct extent_buffer *leaf; - u32 nritems; - int ret; - int recow; - int err = -ENOENT; - - key.objectid = bytenr; - if (parent) { - key.type = BTRFS_SHARED_DATA_REF_KEY; - key.offset = parent; - } else { - key.type = BTRFS_EXTENT_DATA_REF_KEY; - key.offset = hash_extent_data_ref(root_objectid, - owner, offset); - } -again: - recow = 0; - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret < 0) { - err = ret; - goto fail; - } - - if (parent) { - if (!ret) - return 0; -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - key.type = BTRFS_EXTENT_REF_V0_KEY; - btrfs_release_path(path); - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret < 0) { - err = ret; - goto fail; - } - if (!ret) - return 0; -#endif - goto fail; - } - - leaf = path->nodes[0]; - nritems = btrfs_header_nritems(leaf); - while (1) { - if (path->slots[0] >= nritems) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) - err = ret; - if (ret) - goto fail; - - leaf = path->nodes[0]; - nritems = btrfs_header_nritems(leaf); - recow = 1; - } - - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - if (key.objectid != bytenr || - key.type != BTRFS_EXTENT_DATA_REF_KEY) - goto fail; - - ref = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_data_ref); - - if (match_extent_data_ref(leaf, ref, root_objectid, - owner, offset)) { - if (recow) { - btrfs_release_path(path); - goto again; - } - err = 0; - break; - } - path->slots[0]++; - } -fail: - return err; -} - -static noinline int insert_extent_data_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - u64 bytenr, u64 parent, - u64 root_objectid, u64 owner, - u64 offset, int refs_to_add) -{ - struct btrfs_key key; - struct extent_buffer *leaf; - u32 size; - u32 num_refs; - int ret; - - key.objectid = bytenr; - if (parent) { - key.type = BTRFS_SHARED_DATA_REF_KEY; - key.offset = parent; - size = sizeof(struct btrfs_shared_data_ref); - } else { - key.type = BTRFS_EXTENT_DATA_REF_KEY; - key.offset = hash_extent_data_ref(root_objectid, - owner, offset); - size = sizeof(struct btrfs_extent_data_ref); - } - - ret = btrfs_insert_empty_item(trans, root, path, &key, size); - if (ret && ret != -EEXIST) - goto fail; - - leaf = path->nodes[0]; - if (parent) { - struct btrfs_shared_data_ref *ref; - ref = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_shared_data_ref); - if (ret == 0) { - btrfs_set_shared_data_ref_count(leaf, ref, refs_to_add); - } else { - num_refs = btrfs_shared_data_ref_count(leaf, ref); - num_refs += refs_to_add; - btrfs_set_shared_data_ref_count(leaf, ref, num_refs); - } - } else { - struct btrfs_extent_data_ref *ref; - while (ret == -EEXIST) { - ref = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_data_ref); - if (match_extent_data_ref(leaf, ref, root_objectid, - owner, offset)) - break; - btrfs_release_path(path); - key.offset++; - ret = btrfs_insert_empty_item(trans, root, path, &key, - size); - if (ret && ret != -EEXIST) - goto fail; - - leaf = path->nodes[0]; - } - ref = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_data_ref); - if (ret == 0) { - btrfs_set_extent_data_ref_root(leaf, ref, - root_objectid); - btrfs_set_extent_data_ref_objectid(leaf, ref, owner); - btrfs_set_extent_data_ref_offset(leaf, ref, offset); - btrfs_set_extent_data_ref_count(leaf, ref, refs_to_add); - } else { - num_refs = btrfs_extent_data_ref_count(leaf, ref); - num_refs += refs_to_add; - btrfs_set_extent_data_ref_count(leaf, ref, num_refs); - } - } - btrfs_mark_buffer_dirty(leaf); - ret = 0; -fail: - btrfs_release_path(path); - return ret; -} - -static noinline int remove_extent_data_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - int refs_to_drop, int *last_ref) -{ - struct btrfs_key key; - struct btrfs_extent_data_ref *ref1 = NULL; - struct btrfs_shared_data_ref *ref2 = NULL; - struct extent_buffer *leaf; - u32 num_refs = 0; - int ret = 0; - - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - - if (key.type == BTRFS_EXTENT_DATA_REF_KEY) { - ref1 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_data_ref); - num_refs = btrfs_extent_data_ref_count(leaf, ref1); - } else if (key.type == BTRFS_SHARED_DATA_REF_KEY) { - ref2 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_shared_data_ref); - num_refs = btrfs_shared_data_ref_count(leaf, ref2); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { - struct btrfs_extent_ref_v0 *ref0; - ref0 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_ref_v0); - num_refs = btrfs_ref_count_v0(leaf, ref0); -#endif - } else { - BUG(); - } - - BUG_ON(num_refs < refs_to_drop); - num_refs -= refs_to_drop; - - if (num_refs == 0) { - ret = btrfs_del_item(trans, root, path); - *last_ref = 1; - } else { - if (key.type == BTRFS_EXTENT_DATA_REF_KEY) - btrfs_set_extent_data_ref_count(leaf, ref1, num_refs); - else if (key.type == BTRFS_SHARED_DATA_REF_KEY) - btrfs_set_shared_data_ref_count(leaf, ref2, num_refs); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - else { - struct btrfs_extent_ref_v0 *ref0; - ref0 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_ref_v0); - btrfs_set_ref_count_v0(leaf, ref0, num_refs); - } -#endif - btrfs_mark_buffer_dirty(leaf); - } - return ret; -} - -static noinline u32 extent_data_ref_count(struct btrfs_path *path, - struct btrfs_extent_inline_ref *iref) -{ - struct btrfs_key key; - struct extent_buffer *leaf; - struct btrfs_extent_data_ref *ref1; - struct btrfs_shared_data_ref *ref2; - u32 num_refs = 0; - - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - if (iref) { - if (btrfs_extent_inline_ref_type(leaf, iref) == - BTRFS_EXTENT_DATA_REF_KEY) { - ref1 = (struct btrfs_extent_data_ref *)(&iref->offset); - num_refs = btrfs_extent_data_ref_count(leaf, ref1); - } else { - ref2 = (struct btrfs_shared_data_ref *)(iref + 1); - num_refs = btrfs_shared_data_ref_count(leaf, ref2); - } - } else if (key.type == BTRFS_EXTENT_DATA_REF_KEY) { - ref1 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_data_ref); - num_refs = btrfs_extent_data_ref_count(leaf, ref1); - } else if (key.type == BTRFS_SHARED_DATA_REF_KEY) { - ref2 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_shared_data_ref); - num_refs = btrfs_shared_data_ref_count(leaf, ref2); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - } else if (key.type == BTRFS_EXTENT_REF_V0_KEY) { - struct btrfs_extent_ref_v0 *ref0; - ref0 = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_ref_v0); - num_refs = btrfs_ref_count_v0(leaf, ref0); -#endif - } else { - WARN_ON(1); - } - return num_refs; -} - -static noinline int lookup_tree_block_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - u64 bytenr, u64 parent, - u64 root_objectid) -{ - struct btrfs_key key; - int ret; - - key.objectid = bytenr; - if (parent) { - key.type = BTRFS_SHARED_BLOCK_REF_KEY; - key.offset = parent; - } else { - key.type = BTRFS_TREE_BLOCK_REF_KEY; - key.offset = root_objectid; - } - - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret > 0) - ret = -ENOENT; -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (ret == -ENOENT && parent) { - btrfs_release_path(path); - key.type = BTRFS_EXTENT_REF_V0_KEY; - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret > 0) - ret = -ENOENT; - } -#endif - return ret; -} - -static noinline int insert_tree_block_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - u64 bytenr, u64 parent, - u64 root_objectid) -{ - struct btrfs_key key; - int ret; - - key.objectid = bytenr; - if (parent) { - key.type = BTRFS_SHARED_BLOCK_REF_KEY; - key.offset = parent; - } else { - key.type = BTRFS_TREE_BLOCK_REF_KEY; - key.offset = root_objectid; - } - - ret = btrfs_insert_empty_item(trans, root, path, &key, 0); - btrfs_release_path(path); - return ret; -} - -static inline int extent_ref_type(u64 parent, u64 owner) -{ - int type; - if (owner < BTRFS_FIRST_FREE_OBJECTID) { - if (parent > 0) - type = BTRFS_SHARED_BLOCK_REF_KEY; - else - type = BTRFS_TREE_BLOCK_REF_KEY; - } else { - if (parent > 0) - type = BTRFS_SHARED_DATA_REF_KEY; - else - type = BTRFS_EXTENT_DATA_REF_KEY; - } - return type; -} - -static int find_next_key(struct btrfs_path *path, int level, - struct btrfs_key *key) - -{ - for (; level < BTRFS_MAX_LEVEL; level++) { - if (!path->nodes[level]) - break; - if (path->slots[level] + 1 >= - btrfs_header_nritems(path->nodes[level])) - continue; - if (level == 0) - btrfs_item_key_to_cpu(path->nodes[level], key, - path->slots[level] + 1); - else - btrfs_node_key_to_cpu(path->nodes[level], key, - path->slots[level] + 1); - return 0; - } - return 1; -} - -/* - * look for inline back ref. if back ref is found, *ref_ret is set - * to the address of inline back ref, and 0 is returned. - * - * if back ref isn't found, *ref_ret is set to the address where it - * should be inserted, and -ENOENT is returned. - * - * if insert is true and there are too many inline back refs, the path - * points to the extent item, and -EAGAIN is returned. - * - * NOTE: inline back refs are ordered in the same way that back ref - * items in the tree are ordered. - */ -static noinline_for_stack -int lookup_inline_extent_backref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_extent_inline_ref **ref_ret, - u64 bytenr, u64 num_bytes, - u64 parent, u64 root_objectid, - u64 owner, u64 offset, int insert) -{ - struct btrfs_key key; - struct extent_buffer *leaf; - struct btrfs_extent_item *ei; - struct btrfs_extent_inline_ref *iref; - u64 flags; - u64 item_size; - unsigned long ptr; - unsigned long end; - int extra_size; - int type; - int want; - int ret; - int err = 0; - bool skinny_metadata = btrfs_fs_incompat(root->fs_info, - SKINNY_METADATA); - - key.objectid = bytenr; - key.type = BTRFS_EXTENT_ITEM_KEY; - key.offset = num_bytes; - - want = extent_ref_type(parent, owner); - if (insert) { - extra_size = btrfs_extent_inline_ref_size(want); - path->keep_locks = 1; - } else - extra_size = -1; - - /* - * Owner is our parent level, so we can just add one to get the level - * for the block we are interested in. - */ - if (skinny_metadata && owner < BTRFS_FIRST_FREE_OBJECTID) { - key.type = BTRFS_METADATA_ITEM_KEY; - key.offset = owner; - } - -again: - ret = btrfs_search_slot(trans, root, &key, path, extra_size, 1); - if (ret < 0) { - err = ret; - goto out; - } - - /* - * We may be a newly converted file system which still has the old fat - * extent entries for metadata, so try and see if we have one of those. - */ - if (ret > 0 && skinny_metadata) { - skinny_metadata = false; - if (path->slots[0]) { - path->slots[0]--; - btrfs_item_key_to_cpu(path->nodes[0], &key, - path->slots[0]); - if (key.objectid == bytenr && - key.type == BTRFS_EXTENT_ITEM_KEY && - key.offset == num_bytes) - ret = 0; - } - if (ret) { - key.objectid = bytenr; - key.type = BTRFS_EXTENT_ITEM_KEY; - key.offset = num_bytes; - btrfs_release_path(path); - goto again; - } - } - - if (ret && !insert) { - err = -ENOENT; - goto out; - } else if (WARN_ON(ret)) { - err = -EIO; - goto out; - } - - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, path->slots[0]); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (item_size < sizeof(*ei)) { - if (!insert) { - err = -ENOENT; - goto out; - } - ret = convert_extent_item_v0(trans, root, path, owner, - extra_size); - if (ret < 0) { - err = ret; - goto out; - } - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, path->slots[0]); - } -#endif - BUG_ON(item_size < sizeof(*ei)); - - ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); - flags = btrfs_extent_flags(leaf, ei); - - ptr = (unsigned long)(ei + 1); - end = (unsigned long)ei + item_size; - - if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK && !skinny_metadata) { - ptr += sizeof(struct btrfs_tree_block_info); - BUG_ON(ptr > end); - } - - err = -ENOENT; - while (1) { - if (ptr >= end) { - WARN_ON(ptr > end); - break; - } - iref = (struct btrfs_extent_inline_ref *)ptr; - type = btrfs_extent_inline_ref_type(leaf, iref); - if (want < type) - break; - if (want > type) { - ptr += btrfs_extent_inline_ref_size(type); - continue; - } - - if (type == BTRFS_EXTENT_DATA_REF_KEY) { - struct btrfs_extent_data_ref *dref; - dref = (struct btrfs_extent_data_ref *)(&iref->offset); - if (match_extent_data_ref(leaf, dref, root_objectid, - owner, offset)) { - err = 0; - break; - } - if (hash_extent_data_ref_item(leaf, dref) < - hash_extent_data_ref(root_objectid, owner, offset)) - break; - } else { - u64 ref_offset; - ref_offset = btrfs_extent_inline_ref_offset(leaf, iref); - if (parent > 0) { - if (parent == ref_offset) { - err = 0; - break; - } - if (ref_offset < parent) - break; - } else { - if (root_objectid == ref_offset) { - err = 0; - break; - } - if (ref_offset < root_objectid) - break; - } - } - ptr += btrfs_extent_inline_ref_size(type); - } - if (err == -ENOENT && insert) { - if (item_size + extra_size >= - BTRFS_MAX_EXTENT_ITEM_SIZE(root)) { - err = -EAGAIN; - goto out; - } - /* - * To add new inline back ref, we have to make sure - * there is no corresponding back ref item. - * For simplicity, we just do not add new inline back - * ref if there is any kind of item for this block - */ - if (find_next_key(path, 0, &key) == 0 && - key.objectid == bytenr && - key.type < BTRFS_BLOCK_GROUP_ITEM_KEY) { - err = -EAGAIN; - goto out; - } - } - *ref_ret = (struct btrfs_extent_inline_ref *)ptr; -out: - if (insert) { - path->keep_locks = 0; - btrfs_unlock_up_safe(path, 1); - } - return err; -} - -/* - * helper to add new inline back ref - */ -static noinline_for_stack -void setup_inline_extent_backref(struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_extent_inline_ref *iref, - u64 parent, u64 root_objectid, - u64 owner, u64 offset, int refs_to_add, - struct btrfs_delayed_extent_op *extent_op) -{ - struct extent_buffer *leaf; - struct btrfs_extent_item *ei; - unsigned long ptr; - unsigned long end; - unsigned long item_offset; - u64 refs; - int size; - int type; - - leaf = path->nodes[0]; - ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); - item_offset = (unsigned long)iref - (unsigned long)ei; - - type = extent_ref_type(parent, owner); - size = btrfs_extent_inline_ref_size(type); - - btrfs_extend_item(root, path, size); - - ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); - refs = btrfs_extent_refs(leaf, ei); - refs += refs_to_add; - btrfs_set_extent_refs(leaf, ei, refs); - if (extent_op) - __run_delayed_extent_op(extent_op, leaf, ei); - - ptr = (unsigned long)ei + item_offset; - end = (unsigned long)ei + btrfs_item_size_nr(leaf, path->slots[0]); - if (ptr < end - size) - memmove_extent_buffer(leaf, ptr + size, ptr, - end - size - ptr); - - iref = (struct btrfs_extent_inline_ref *)ptr; - btrfs_set_extent_inline_ref_type(leaf, iref, type); - if (type == BTRFS_EXTENT_DATA_REF_KEY) { - struct btrfs_extent_data_ref *dref; - dref = (struct btrfs_extent_data_ref *)(&iref->offset); - btrfs_set_extent_data_ref_root(leaf, dref, root_objectid); - btrfs_set_extent_data_ref_objectid(leaf, dref, owner); - btrfs_set_extent_data_ref_offset(leaf, dref, offset); - btrfs_set_extent_data_ref_count(leaf, dref, refs_to_add); - } else if (type == BTRFS_SHARED_DATA_REF_KEY) { - struct btrfs_shared_data_ref *sref; - sref = (struct btrfs_shared_data_ref *)(iref + 1); - btrfs_set_shared_data_ref_count(leaf, sref, refs_to_add); - btrfs_set_extent_inline_ref_offset(leaf, iref, parent); - } else if (type == BTRFS_SHARED_BLOCK_REF_KEY) { - btrfs_set_extent_inline_ref_offset(leaf, iref, parent); - } else { - btrfs_set_extent_inline_ref_offset(leaf, iref, root_objectid); - } - btrfs_mark_buffer_dirty(leaf); -} - -static int lookup_extent_backref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_extent_inline_ref **ref_ret, - u64 bytenr, u64 num_bytes, u64 parent, - u64 root_objectid, u64 owner, u64 offset) -{ - int ret; - - ret = lookup_inline_extent_backref(trans, root, path, ref_ret, - bytenr, num_bytes, parent, - root_objectid, owner, offset, 0); - if (ret != -ENOENT) - return ret; - - btrfs_release_path(path); - *ref_ret = NULL; - - if (owner < BTRFS_FIRST_FREE_OBJECTID) { - ret = lookup_tree_block_ref(trans, root, path, bytenr, parent, - root_objectid); - } else { - ret = lookup_extent_data_ref(trans, root, path, bytenr, parent, - root_objectid, owner, offset); - } - return ret; -} - -/* - * helper to update/remove inline back ref - */ -static noinline_for_stack -void update_inline_extent_backref(struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_extent_inline_ref *iref, - int refs_to_mod, - struct btrfs_delayed_extent_op *extent_op, - int *last_ref) -{ - struct extent_buffer *leaf; - struct btrfs_extent_item *ei; - struct btrfs_extent_data_ref *dref = NULL; - struct btrfs_shared_data_ref *sref = NULL; - unsigned long ptr; - unsigned long end; - u32 item_size; - int size; - int type; - u64 refs; - - leaf = path->nodes[0]; - ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); - refs = btrfs_extent_refs(leaf, ei); - WARN_ON(refs_to_mod < 0 && refs + refs_to_mod <= 0); - refs += refs_to_mod; - btrfs_set_extent_refs(leaf, ei, refs); - if (extent_op) - __run_delayed_extent_op(extent_op, leaf, ei); - - type = btrfs_extent_inline_ref_type(leaf, iref); - - if (type == BTRFS_EXTENT_DATA_REF_KEY) { - dref = (struct btrfs_extent_data_ref *)(&iref->offset); - refs = btrfs_extent_data_ref_count(leaf, dref); - } else if (type == BTRFS_SHARED_DATA_REF_KEY) { - sref = (struct btrfs_shared_data_ref *)(iref + 1); - refs = btrfs_shared_data_ref_count(leaf, sref); - } else { - refs = 1; - BUG_ON(refs_to_mod != -1); - } - - BUG_ON(refs_to_mod < 0 && refs < -refs_to_mod); - refs += refs_to_mod; - - if (refs > 0) { - if (type == BTRFS_EXTENT_DATA_REF_KEY) - btrfs_set_extent_data_ref_count(leaf, dref, refs); - else - btrfs_set_shared_data_ref_count(leaf, sref, refs); - } else { - *last_ref = 1; - size = btrfs_extent_inline_ref_size(type); - item_size = btrfs_item_size_nr(leaf, path->slots[0]); - ptr = (unsigned long)iref; - end = (unsigned long)ei + item_size; - if (ptr + size < end) - memmove_extent_buffer(leaf, ptr, ptr + size, - end - ptr - size); - item_size -= size; - btrfs_truncate_item(root, path, item_size, 1); - } - btrfs_mark_buffer_dirty(leaf); -} - -static noinline_for_stack -int insert_inline_extent_backref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - u64 bytenr, u64 num_bytes, u64 parent, - u64 root_objectid, u64 owner, - u64 offset, int refs_to_add, - struct btrfs_delayed_extent_op *extent_op) -{ - struct btrfs_extent_inline_ref *iref; - int ret; - - ret = lookup_inline_extent_backref(trans, root, path, &iref, - bytenr, num_bytes, parent, - root_objectid, owner, offset, 1); - if (ret == 0) { - BUG_ON(owner < BTRFS_FIRST_FREE_OBJECTID); - update_inline_extent_backref(root, path, iref, - refs_to_add, extent_op, NULL); - } else if (ret == -ENOENT) { - setup_inline_extent_backref(root, path, iref, parent, - root_objectid, owner, offset, - refs_to_add, extent_op); - ret = 0; - } - return ret; -} - -static int insert_extent_backref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - u64 bytenr, u64 parent, u64 root_objectid, - u64 owner, u64 offset, int refs_to_add) -{ - int ret; - if (owner < BTRFS_FIRST_FREE_OBJECTID) { - BUG_ON(refs_to_add != 1); - ret = insert_tree_block_ref(trans, root, path, bytenr, - parent, root_objectid); - } else { - ret = insert_extent_data_ref(trans, root, path, bytenr, - parent, root_objectid, - owner, offset, refs_to_add); - } - return ret; -} - -static int remove_extent_backref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_extent_inline_ref *iref, - int refs_to_drop, int is_data, int *last_ref) -{ - int ret = 0; - - BUG_ON(!is_data && refs_to_drop != 1); - if (iref) { - update_inline_extent_backref(root, path, iref, - -refs_to_drop, NULL, last_ref); - } else if (is_data) { - ret = remove_extent_data_ref(trans, root, path, refs_to_drop, - last_ref); - } else { - *last_ref = 1; - ret = btrfs_del_item(trans, root, path); - } - return ret; -} - -#define in_range(b, first, len) ((b) >= (first) && (b) < (first) + (len)) -static int btrfs_issue_discard(struct block_device *bdev, u64 start, u64 len, - u64 *discarded_bytes) -{ - int j, ret = 0; - u64 bytes_left, end; - u64 aligned_start = ALIGN(start, 1 << 9); - - if (WARN_ON(start != aligned_start)) { - len -= aligned_start - start; - len = round_down(len, 1 << 9); - start = aligned_start; - } - - *discarded_bytes = 0; - - if (!len) - return 0; - - end = start + len; - bytes_left = len; - - /* Skip any superblocks on this device. */ - for (j = 0; j < BTRFS_SUPER_MIRROR_MAX; j++) { - u64 sb_start = btrfs_sb_offset(j); - u64 sb_end = sb_start + BTRFS_SUPER_INFO_SIZE; - u64 size = sb_start - start; - - if (!in_range(sb_start, start, bytes_left) && - !in_range(sb_end, start, bytes_left) && - !in_range(start, sb_start, BTRFS_SUPER_INFO_SIZE)) - continue; - - /* - * Superblock spans beginning of range. Adjust start and - * try again. - */ - if (sb_start <= start) { - start += sb_end - start; - if (start > end) { - bytes_left = 0; - break; - } - bytes_left = end - start; - continue; - } - - if (size) { - ret = blkdev_issue_discard(bdev, start >> 9, size >> 9, - GFP_NOFS, 0); - if (!ret) - *discarded_bytes += size; - else if (ret != -EOPNOTSUPP) - return ret; - } - - start = sb_end; - if (start > end) { - bytes_left = 0; - break; - } - bytes_left = end - start; - } - - if (bytes_left) { - ret = blkdev_issue_discard(bdev, start >> 9, bytes_left >> 9, - GFP_NOFS, 0); - if (!ret) - *discarded_bytes += bytes_left; - } - return ret; -} - -int btrfs_discard_extent(struct btrfs_root *root, u64 bytenr, - u64 num_bytes, u64 *actual_bytes) -{ - int ret; - u64 discarded_bytes = 0; - struct btrfs_bio *bbio = NULL; - - - /* - * Avoid races with device replace and make sure our bbio has devices - * associated to its stripes that don't go away while we are discarding. - */ - btrfs_bio_counter_inc_blocked(root->fs_info); - /* Tell the block device(s) that the sectors can be discarded */ - ret = btrfs_map_block(root->fs_info, REQ_OP_DISCARD, - bytenr, &num_bytes, &bbio, 0); - /* Error condition is -ENOMEM */ - if (!ret) { - struct btrfs_bio_stripe *stripe = bbio->stripes; - int i; - - - for (i = 0; i < bbio->num_stripes; i++, stripe++) { - u64 bytes; - if (!stripe->dev->can_discard) - continue; - - ret = btrfs_issue_discard(stripe->dev->bdev, - stripe->physical, - stripe->length, - &bytes); - if (!ret) - discarded_bytes += bytes; - else if (ret != -EOPNOTSUPP) - break; /* Logic errors or -ENOMEM, or -EIO but I don't know how that could happen JDM */ - - /* - * Just in case we get back EOPNOTSUPP for some reason, - * just ignore the return value so we don't screw up - * people calling discard_extent. - */ - ret = 0; - } - btrfs_put_bbio(bbio); - } - btrfs_bio_counter_dec(root->fs_info); - - if (actual_bytes) - *actual_bytes = discarded_bytes; - - - if (ret == -EOPNOTSUPP) - ret = 0; - return ret; -} - -/* Can return -ENOMEM */ -int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 bytenr, u64 num_bytes, u64 parent, - u64 root_objectid, u64 owner, u64 offset) -{ - int ret; - struct btrfs_fs_info *fs_info = root->fs_info; - - BUG_ON(owner < BTRFS_FIRST_FREE_OBJECTID && - root_objectid == BTRFS_TREE_LOG_OBJECTID); - - if (owner < BTRFS_FIRST_FREE_OBJECTID) { - ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr, - num_bytes, - parent, root_objectid, (int)owner, - BTRFS_ADD_DELAYED_REF, NULL); - } else { - ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr, - num_bytes, parent, root_objectid, - owner, offset, 0, - BTRFS_ADD_DELAYED_REF, NULL); - } - return ret; -} - -static int __btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_delayed_ref_node *node, - u64 parent, u64 root_objectid, - u64 owner, u64 offset, int refs_to_add, - struct btrfs_delayed_extent_op *extent_op) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_path *path; - struct extent_buffer *leaf; - struct btrfs_extent_item *item; - struct btrfs_key key; - u64 bytenr = node->bytenr; - u64 num_bytes = node->num_bytes; - u64 refs; - int ret; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - path->reada = READA_FORWARD; - path->leave_spinning = 1; - /* this will setup the path even if it fails to insert the back ref */ - ret = insert_inline_extent_backref(trans, fs_info->extent_root, path, - bytenr, num_bytes, parent, - root_objectid, owner, offset, - refs_to_add, extent_op); - if ((ret < 0 && ret != -EAGAIN) || !ret) - goto out; - - /* - * Ok we had -EAGAIN which means we didn't have space to insert and - * inline extent ref, so just update the reference count and add a - * normal backref. - */ - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); - refs = btrfs_extent_refs(leaf, item); - btrfs_set_extent_refs(leaf, item, refs + refs_to_add); - if (extent_op) - __run_delayed_extent_op(extent_op, leaf, item); - - btrfs_mark_buffer_dirty(leaf); - btrfs_release_path(path); - - path->reada = READA_FORWARD; - path->leave_spinning = 1; - /* now insert the actual backref */ - ret = insert_extent_backref(trans, root->fs_info->extent_root, - path, bytenr, parent, root_objectid, - owner, offset, refs_to_add); - if (ret) - btrfs_abort_transaction(trans, ret); -out: - btrfs_free_path(path); - return ret; -} - -static int run_delayed_data_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_delayed_ref_node *node, - struct btrfs_delayed_extent_op *extent_op, - int insert_reserved) -{ - int ret = 0; - struct btrfs_delayed_data_ref *ref; - struct btrfs_key ins; - u64 parent = 0; - u64 ref_root = 0; - u64 flags = 0; - - ins.objectid = node->bytenr; - ins.offset = node->num_bytes; - ins.type = BTRFS_EXTENT_ITEM_KEY; - - ref = btrfs_delayed_node_to_data_ref(node); - trace_run_delayed_data_ref(root->fs_info, node, ref, node->action); - - if (node->type == BTRFS_SHARED_DATA_REF_KEY) - parent = ref->parent; - ref_root = ref->root; - - if (node->action == BTRFS_ADD_DELAYED_REF && insert_reserved) { - if (extent_op) - flags |= extent_op->flags_to_set; - ret = alloc_reserved_file_extent(trans, root, - parent, ref_root, flags, - ref->objectid, ref->offset, - &ins, node->ref_mod); - } else if (node->action == BTRFS_ADD_DELAYED_REF) { - ret = __btrfs_inc_extent_ref(trans, root, node, parent, - ref_root, ref->objectid, - ref->offset, node->ref_mod, - extent_op); - } else if (node->action == BTRFS_DROP_DELAYED_REF) { - ret = __btrfs_free_extent(trans, root, node, parent, - ref_root, ref->objectid, - ref->offset, node->ref_mod, - extent_op); - } else { - BUG(); - } - return ret; -} - -static void __run_delayed_extent_op(struct btrfs_delayed_extent_op *extent_op, - struct extent_buffer *leaf, - struct btrfs_extent_item *ei) -{ - u64 flags = btrfs_extent_flags(leaf, ei); - if (extent_op->update_flags) { - flags |= extent_op->flags_to_set; - btrfs_set_extent_flags(leaf, ei, flags); - } - - if (extent_op->update_key) { - struct btrfs_tree_block_info *bi; - BUG_ON(!(flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)); - bi = (struct btrfs_tree_block_info *)(ei + 1); - btrfs_set_tree_block_key(leaf, bi, &extent_op->key); - } -} - -static int run_delayed_extent_op(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_delayed_ref_node *node, - struct btrfs_delayed_extent_op *extent_op) -{ - struct btrfs_key key; - struct btrfs_path *path; - struct btrfs_extent_item *ei; - struct extent_buffer *leaf; - u32 item_size; - int ret; - int err = 0; - int metadata = !extent_op->is_data; - - if (trans->aborted) - return 0; - - if (metadata && !btrfs_fs_incompat(root->fs_info, SKINNY_METADATA)) - metadata = 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - key.objectid = node->bytenr; - - if (metadata) { - key.type = BTRFS_METADATA_ITEM_KEY; - key.offset = extent_op->level; - } else { - key.type = BTRFS_EXTENT_ITEM_KEY; - key.offset = node->num_bytes; - } - -again: - path->reada = READA_FORWARD; - path->leave_spinning = 1; - ret = btrfs_search_slot(trans, root->fs_info->extent_root, &key, - path, 0, 1); - if (ret < 0) { - err = ret; - goto out; - } - if (ret > 0) { - if (metadata) { - if (path->slots[0] > 0) { - path->slots[0]--; - btrfs_item_key_to_cpu(path->nodes[0], &key, - path->slots[0]); - if (key.objectid == node->bytenr && - key.type == BTRFS_EXTENT_ITEM_KEY && - key.offset == node->num_bytes) - ret = 0; - } - if (ret > 0) { - btrfs_release_path(path); - metadata = 0; - - key.objectid = node->bytenr; - key.offset = node->num_bytes; - key.type = BTRFS_EXTENT_ITEM_KEY; - goto again; - } - } else { - err = -EIO; - goto out; - } - } - - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, path->slots[0]); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (item_size < sizeof(*ei)) { - ret = convert_extent_item_v0(trans, root->fs_info->extent_root, - path, (u64)-1, 0); - if (ret < 0) { - err = ret; - goto out; - } - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, path->slots[0]); - } -#endif - BUG_ON(item_size < sizeof(*ei)); - ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); - __run_delayed_extent_op(extent_op, leaf, ei); - - btrfs_mark_buffer_dirty(leaf); -out: - btrfs_free_path(path); - return err; -} - -static int run_delayed_tree_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_delayed_ref_node *node, - struct btrfs_delayed_extent_op *extent_op, - int insert_reserved) -{ - int ret = 0; - struct btrfs_delayed_tree_ref *ref; - struct btrfs_key ins; - u64 parent = 0; - u64 ref_root = 0; - bool skinny_metadata = btrfs_fs_incompat(root->fs_info, - SKINNY_METADATA); - - ref = btrfs_delayed_node_to_tree_ref(node); - trace_run_delayed_tree_ref(root->fs_info, node, ref, node->action); - - if (node->type == BTRFS_SHARED_BLOCK_REF_KEY) - parent = ref->parent; - ref_root = ref->root; - - ins.objectid = node->bytenr; - if (skinny_metadata) { - ins.offset = ref->level; - ins.type = BTRFS_METADATA_ITEM_KEY; - } else { - ins.offset = node->num_bytes; - ins.type = BTRFS_EXTENT_ITEM_KEY; - } - - if (node->ref_mod != 1) { - btrfs_err(root->fs_info, - "btree block(%llu) has %d references rather than 1: action %d ref_root %llu parent %llu", - node->bytenr, node->ref_mod, node->action, ref_root, - parent); - return -EIO; - } - if (node->action == BTRFS_ADD_DELAYED_REF && insert_reserved) { - BUG_ON(!extent_op || !extent_op->update_flags); - ret = alloc_reserved_tree_block(trans, root, - parent, ref_root, - extent_op->flags_to_set, - &extent_op->key, - ref->level, &ins); - } else if (node->action == BTRFS_ADD_DELAYED_REF) { - ret = __btrfs_inc_extent_ref(trans, root, node, - parent, ref_root, - ref->level, 0, 1, - extent_op); - } else if (node->action == BTRFS_DROP_DELAYED_REF) { - ret = __btrfs_free_extent(trans, root, node, - parent, ref_root, - ref->level, 0, 1, extent_op); - } else { - BUG(); - } - return ret; -} - -/* helper function to actually process a single delayed ref entry */ -static int run_one_delayed_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_delayed_ref_node *node, - struct btrfs_delayed_extent_op *extent_op, - int insert_reserved) -{ - int ret = 0; - - if (trans->aborted) { - if (insert_reserved) - btrfs_pin_extent(root, node->bytenr, - node->num_bytes, 1); - return 0; - } - - if (btrfs_delayed_ref_is_head(node)) { - struct btrfs_delayed_ref_head *head; - /* - * we've hit the end of the chain and we were supposed - * to insert this extent into the tree. But, it got - * deleted before we ever needed to insert it, so all - * we have to do is clean up the accounting - */ - BUG_ON(extent_op); - head = btrfs_delayed_node_to_head(node); - trace_run_delayed_ref_head(root->fs_info, node, head, - node->action); - - if (insert_reserved) { - btrfs_pin_extent(root, node->bytenr, - node->num_bytes, 1); - if (head->is_data) { - ret = btrfs_del_csums(trans, root, - node->bytenr, - node->num_bytes); - } - } - - /* Also free its reserved qgroup space */ - btrfs_qgroup_free_delayed_ref(root->fs_info, - head->qgroup_ref_root, - head->qgroup_reserved); - return ret; - } - - if (node->type == BTRFS_TREE_BLOCK_REF_KEY || - node->type == BTRFS_SHARED_BLOCK_REF_KEY) - ret = run_delayed_tree_ref(trans, root, node, extent_op, - insert_reserved); - else if (node->type == BTRFS_EXTENT_DATA_REF_KEY || - node->type == BTRFS_SHARED_DATA_REF_KEY) - ret = run_delayed_data_ref(trans, root, node, extent_op, - insert_reserved); - else - BUG(); - return ret; -} - -static inline struct btrfs_delayed_ref_node * -select_delayed_ref(struct btrfs_delayed_ref_head *head) -{ - struct btrfs_delayed_ref_node *ref; - - if (list_empty(&head->ref_list)) - return NULL; - - /* - * Select a delayed ref of type BTRFS_ADD_DELAYED_REF first. - * This is to prevent a ref count from going down to zero, which deletes - * the extent item from the extent tree, when there still are references - * to add, which would fail because they would not find the extent item. - */ - list_for_each_entry(ref, &head->ref_list, list) { - if (ref->action == BTRFS_ADD_DELAYED_REF) - return ref; - } - - return list_entry(head->ref_list.next, struct btrfs_delayed_ref_node, - list); -} - -/* - * Returns 0 on success or if called with an already aborted transaction. - * Returns -ENOMEM or -EIO on failure and will abort the transaction. - */ -static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - unsigned long nr) -{ - struct btrfs_delayed_ref_root *delayed_refs; - struct btrfs_delayed_ref_node *ref; - struct btrfs_delayed_ref_head *locked_ref = NULL; - struct btrfs_delayed_extent_op *extent_op; - struct btrfs_fs_info *fs_info = root->fs_info; - ktime_t start = ktime_get(); - int ret; - unsigned long count = 0; - unsigned long actual_count = 0; - int must_insert_reserved = 0; - - delayed_refs = &trans->transaction->delayed_refs; - while (1) { - if (!locked_ref) { - if (count >= nr) - break; - - spin_lock(&delayed_refs->lock); - locked_ref = btrfs_select_ref_head(trans); - if (!locked_ref) { - spin_unlock(&delayed_refs->lock); - break; - } - - /* grab the lock that says we are going to process - * all the refs for this head */ - ret = btrfs_delayed_ref_lock(trans, locked_ref); - spin_unlock(&delayed_refs->lock); - /* - * we may have dropped the spin lock to get the head - * mutex lock, and that might have given someone else - * time to free the head. If that's true, it has been - * removed from our list and we can move on. - */ - if (ret == -EAGAIN) { - locked_ref = NULL; - count++; - continue; - } - } - - /* - * We need to try and merge add/drops of the same ref since we - * can run into issues with relocate dropping the implicit ref - * and then it being added back again before the drop can - * finish. If we merged anything we need to re-loop so we can - * get a good ref. - * Or we can get node references of the same type that weren't - * merged when created due to bumps in the tree mod seq, and - * we need to merge them to prevent adding an inline extent - * backref before dropping it (triggering a BUG_ON at - * insert_inline_extent_backref()). - */ - spin_lock(&locked_ref->lock); - btrfs_merge_delayed_refs(trans, fs_info, delayed_refs, - locked_ref); - - /* - * locked_ref is the head node, so we have to go one - * node back for any delayed ref updates - */ - ref = select_delayed_ref(locked_ref); - - if (ref && ref->seq && - btrfs_check_delayed_seq(fs_info, delayed_refs, ref->seq)) { - spin_unlock(&locked_ref->lock); - btrfs_delayed_ref_unlock(locked_ref); - spin_lock(&delayed_refs->lock); - locked_ref->processing = 0; - delayed_refs->num_heads_ready++; - spin_unlock(&delayed_refs->lock); - locked_ref = NULL; - cond_resched(); - count++; - continue; - } - - /* - * record the must insert reserved flag before we - * drop the spin lock. - */ - must_insert_reserved = locked_ref->must_insert_reserved; - locked_ref->must_insert_reserved = 0; - - extent_op = locked_ref->extent_op; - locked_ref->extent_op = NULL; - - if (!ref) { - - - /* All delayed refs have been processed, Go ahead - * and send the head node to run_one_delayed_ref, - * so that any accounting fixes can happen - */ - ref = &locked_ref->node; - - if (extent_op && must_insert_reserved) { - btrfs_free_delayed_extent_op(extent_op); - extent_op = NULL; - } - - if (extent_op) { - spin_unlock(&locked_ref->lock); - ret = run_delayed_extent_op(trans, root, - ref, extent_op); - btrfs_free_delayed_extent_op(extent_op); - - if (ret) { - /* - * Need to reset must_insert_reserved if - * there was an error so the abort stuff - * can cleanup the reserved space - * properly. - */ - if (must_insert_reserved) - locked_ref->must_insert_reserved = 1; - locked_ref->processing = 0; - btrfs_debug(fs_info, - "run_delayed_extent_op returned %d", - ret); - btrfs_delayed_ref_unlock(locked_ref); - return ret; - } - continue; - } - - /* - * Need to drop our head ref lock and re-acquire the - * delayed ref lock and then re-check to make sure - * nobody got added. - */ - spin_unlock(&locked_ref->lock); - spin_lock(&delayed_refs->lock); - spin_lock(&locked_ref->lock); - if (!list_empty(&locked_ref->ref_list) || - locked_ref->extent_op) { - spin_unlock(&locked_ref->lock); - spin_unlock(&delayed_refs->lock); - continue; - } - ref->in_tree = 0; - delayed_refs->num_heads--; - rb_erase(&locked_ref->href_node, - &delayed_refs->href_root); - spin_unlock(&delayed_refs->lock); - } else { - actual_count++; - ref->in_tree = 0; - list_del(&ref->list); - } - atomic_dec(&delayed_refs->num_entries); - - if (!btrfs_delayed_ref_is_head(ref)) { - /* - * when we play the delayed ref, also correct the - * ref_mod on head - */ - switch (ref->action) { - case BTRFS_ADD_DELAYED_REF: - case BTRFS_ADD_DELAYED_EXTENT: - locked_ref->node.ref_mod -= ref->ref_mod; - break; - case BTRFS_DROP_DELAYED_REF: - locked_ref->node.ref_mod += ref->ref_mod; - break; - default: - WARN_ON(1); - } - } - spin_unlock(&locked_ref->lock); - - ret = run_one_delayed_ref(trans, root, ref, extent_op, - must_insert_reserved); - - btrfs_free_delayed_extent_op(extent_op); - if (ret) { - spin_lock(&delayed_refs->lock); - locked_ref->processing = 0; - delayed_refs->num_heads_ready++; - spin_unlock(&delayed_refs->lock); - btrfs_delayed_ref_unlock(locked_ref); - btrfs_put_delayed_ref(ref); - btrfs_debug(fs_info, "run_one_delayed_ref returned %d", - ret); - return ret; - } - - /* - * If this node is a head, that means all the refs in this head - * have been dealt with, and we will pick the next head to deal - * with, so we must unlock the head and drop it from the cluster - * list before we release it. - */ - if (btrfs_delayed_ref_is_head(ref)) { - if (locked_ref->is_data && - locked_ref->total_ref_mod < 0) { - spin_lock(&delayed_refs->lock); - delayed_refs->pending_csums -= ref->num_bytes; - spin_unlock(&delayed_refs->lock); - } - btrfs_delayed_ref_unlock(locked_ref); - locked_ref = NULL; - } - btrfs_put_delayed_ref(ref); - count++; - cond_resched(); - } - - /* - * We don't want to include ref heads since we can have empty ref heads - * and those will drastically skew our runtime down since we just do - * accounting, no actual extent tree updates. - */ - if (actual_count > 0) { - u64 runtime = ktime_to_ns(ktime_sub(ktime_get(), start)); - u64 avg; - - /* - * We weigh the current average higher than our current runtime - * to avoid large swings in the average. - */ - spin_lock(&delayed_refs->lock); - avg = fs_info->avg_delayed_ref_runtime * 3 + runtime; - fs_info->avg_delayed_ref_runtime = avg >> 2; /* div by 4 */ - spin_unlock(&delayed_refs->lock); - } - return 0; -} - -#ifdef SCRAMBLE_DELAYED_REFS -/* - * Normally delayed refs get processed in ascending bytenr order. This - * correlates in most cases to the order added. To expose dependencies on this - * order, we start to process the tree in the middle instead of the beginning - */ -static u64 find_middle(struct rb_root *root) -{ - struct rb_node *n = root->rb_node; - struct btrfs_delayed_ref_node *entry; - int alt = 1; - u64 middle; - u64 first = 0, last = 0; - - n = rb_first(root); - if (n) { - entry = rb_entry(n, struct btrfs_delayed_ref_node, rb_node); - first = entry->bytenr; - } - n = rb_last(root); - if (n) { - entry = rb_entry(n, struct btrfs_delayed_ref_node, rb_node); - last = entry->bytenr; - } - n = root->rb_node; - - while (n) { - entry = rb_entry(n, struct btrfs_delayed_ref_node, rb_node); - WARN_ON(!entry->in_tree); - - middle = entry->bytenr; - - if (alt) - n = n->rb_left; - else - n = n->rb_right; - - alt = 1 - alt; - } - return middle; -} -#endif - -static inline u64 heads_to_leaves(struct btrfs_root *root, u64 heads) -{ - u64 num_bytes; - - num_bytes = heads * (sizeof(struct btrfs_extent_item) + - sizeof(struct btrfs_extent_inline_ref)); - if (!btrfs_fs_incompat(root->fs_info, SKINNY_METADATA)) - num_bytes += heads * sizeof(struct btrfs_tree_block_info); - - /* - * We don't ever fill up leaves all the way so multiply by 2 just to be - * closer to what we're really going to want to use. - */ - return div_u64(num_bytes, BTRFS_LEAF_DATA_SIZE(root)); -} - -/* - * Takes the number of bytes to be csumm'ed and figures out how many leaves it - * would require to store the csums for that many bytes. - */ -u64 btrfs_csum_bytes_to_leaves(struct btrfs_root *root, u64 csum_bytes) -{ - u64 csum_size; - u64 num_csums_per_leaf; - u64 num_csums; - - csum_size = BTRFS_MAX_ITEM_SIZE(root); - num_csums_per_leaf = div64_u64(csum_size, - (u64)btrfs_super_csum_size(root->fs_info->super_copy)); - num_csums = div64_u64(csum_bytes, root->sectorsize); - num_csums += num_csums_per_leaf - 1; - num_csums = div64_u64(num_csums, num_csums_per_leaf); - return num_csums; -} - -int btrfs_check_space_for_delayed_refs(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_block_rsv *global_rsv; - u64 num_heads = trans->transaction->delayed_refs.num_heads_ready; - u64 csum_bytes = trans->transaction->delayed_refs.pending_csums; - u64 num_dirty_bgs = trans->transaction->num_dirty_bgs; - u64 num_bytes, num_dirty_bgs_bytes; - int ret = 0; - - num_bytes = btrfs_calc_trans_metadata_size(root, 1); - num_heads = heads_to_leaves(root, num_heads); - if (num_heads > 1) - num_bytes += (num_heads - 1) * root->nodesize; - num_bytes <<= 1; - num_bytes += btrfs_csum_bytes_to_leaves(root, csum_bytes) * root->nodesize; - num_dirty_bgs_bytes = btrfs_calc_trans_metadata_size(root, - num_dirty_bgs); - global_rsv = &root->fs_info->global_block_rsv; - - /* - * If we can't allocate any more chunks lets make sure we have _lots_ of - * wiggle room since running delayed refs can create more delayed refs. - */ - if (global_rsv->space_info->full) { - num_dirty_bgs_bytes <<= 1; - num_bytes <<= 1; - } - - spin_lock(&global_rsv->lock); - if (global_rsv->reserved <= num_bytes + num_dirty_bgs_bytes) - ret = 1; - spin_unlock(&global_rsv->lock); - return ret; -} - -int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - u64 num_entries = - atomic_read(&trans->transaction->delayed_refs.num_entries); - u64 avg_runtime; - u64 val; - - smp_mb(); - avg_runtime = fs_info->avg_delayed_ref_runtime; - val = num_entries * avg_runtime; - if (num_entries * avg_runtime >= NSEC_PER_SEC) - return 1; - if (val >= NSEC_PER_SEC / 2) - return 2; - - return btrfs_check_space_for_delayed_refs(trans, root); -} - -struct async_delayed_refs { - struct btrfs_root *root; - u64 transid; - int count; - int error; - int sync; - struct completion wait; - struct btrfs_work work; -}; - -static void delayed_ref_async_start(struct btrfs_work *work) -{ - struct async_delayed_refs *async; - struct btrfs_trans_handle *trans; - int ret; - - async = container_of(work, struct async_delayed_refs, work); - - /* if the commit is already started, we don't need to wait here */ - if (btrfs_transaction_blocked(async->root->fs_info)) - goto done; - - trans = btrfs_join_transaction(async->root); - if (IS_ERR(trans)) { - async->error = PTR_ERR(trans); - goto done; - } - - /* - * trans->sync means that when we call end_transaction, we won't - * wait on delayed refs - */ - trans->sync = true; - - /* Don't bother flushing if we got into a different transaction */ - if (trans->transid > async->transid) - goto end; - - ret = btrfs_run_delayed_refs(trans, async->root, async->count); - if (ret) - async->error = ret; -end: - ret = btrfs_end_transaction(trans, async->root); - if (ret && !async->error) - async->error = ret; -done: - if (async->sync) - complete(&async->wait); - else - kfree(async); -} - -int btrfs_async_run_delayed_refs(struct btrfs_root *root, - unsigned long count, u64 transid, int wait) -{ - struct async_delayed_refs *async; - int ret; - - async = kmalloc(sizeof(*async), GFP_NOFS); - if (!async) - return -ENOMEM; - - async->root = root->fs_info->tree_root; - async->count = count; - async->error = 0; - async->transid = transid; - if (wait) - async->sync = 1; - else - async->sync = 0; - init_completion(&async->wait); - - btrfs_init_work(&async->work, btrfs_extent_refs_helper, - delayed_ref_async_start, NULL, NULL); - - btrfs_queue_work(root->fs_info->extent_workers, &async->work); - - if (wait) { - wait_for_completion(&async->wait); - ret = async->error; - kfree(async); - return ret; - } - return 0; -} - -/* - * this starts processing the delayed reference count updates and - * extent insertions we have queued up so far. count can be - * 0, which means to process everything in the tree at the start - * of the run (but not newly added entries), or it can be some target - * number you'd like to process. - * - * Returns 0 on success or if called with an aborted transaction - * Returns <0 on error and aborts the transaction - */ -int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans, - struct btrfs_root *root, unsigned long count) -{ - struct rb_node *node; - struct btrfs_delayed_ref_root *delayed_refs; - struct btrfs_delayed_ref_head *head; - int ret; - int run_all = count == (unsigned long)-1; - bool can_flush_pending_bgs = trans->can_flush_pending_bgs; - - /* We'll clean this up in btrfs_cleanup_transaction */ - if (trans->aborted) - return 0; - - if (test_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &root->fs_info->flags)) - return 0; - - if (root == root->fs_info->extent_root) - root = root->fs_info->tree_root; - - delayed_refs = &trans->transaction->delayed_refs; - if (count == 0) - count = atomic_read(&delayed_refs->num_entries) * 2; - -again: -#ifdef SCRAMBLE_DELAYED_REFS - delayed_refs->run_delayed_start = find_middle(&delayed_refs->root); -#endif - trans->can_flush_pending_bgs = false; - ret = __btrfs_run_delayed_refs(trans, root, count); - if (ret < 0) { - btrfs_abort_transaction(trans, ret); - return ret; - } - - if (run_all) { - if (!list_empty(&trans->new_bgs)) - btrfs_create_pending_block_groups(trans, root); - - spin_lock(&delayed_refs->lock); - node = rb_first(&delayed_refs->href_root); - if (!node) { - spin_unlock(&delayed_refs->lock); - goto out; - } - - while (node) { - head = rb_entry(node, struct btrfs_delayed_ref_head, - href_node); - if (btrfs_delayed_ref_is_head(&head->node)) { - struct btrfs_delayed_ref_node *ref; - - ref = &head->node; - atomic_inc(&ref->refs); - - spin_unlock(&delayed_refs->lock); - /* - * Mutex was contended, block until it's - * released and try again - */ - mutex_lock(&head->mutex); - mutex_unlock(&head->mutex); - - btrfs_put_delayed_ref(ref); - cond_resched(); - goto again; - } else { - WARN_ON(1); - } - node = rb_next(node); - } - spin_unlock(&delayed_refs->lock); - cond_resched(); - goto again; - } -out: - assert_qgroups_uptodate(trans); - trans->can_flush_pending_bgs = can_flush_pending_bgs; - return 0; -} - -int btrfs_set_disk_extent_flags(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 bytenr, u64 num_bytes, u64 flags, - int level, int is_data) -{ - struct btrfs_delayed_extent_op *extent_op; - int ret; - - extent_op = btrfs_alloc_delayed_extent_op(); - if (!extent_op) - return -ENOMEM; - - extent_op->flags_to_set = flags; - extent_op->update_flags = true; - extent_op->update_key = false; - extent_op->is_data = is_data ? true : false; - extent_op->level = level; - - ret = btrfs_add_delayed_extent_op(root->fs_info, trans, bytenr, - num_bytes, extent_op); - if (ret) - btrfs_free_delayed_extent_op(extent_op); - return ret; -} - -static noinline int check_delayed_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - u64 objectid, u64 offset, u64 bytenr) -{ - struct btrfs_delayed_ref_head *head; - struct btrfs_delayed_ref_node *ref; - struct btrfs_delayed_data_ref *data_ref; - struct btrfs_delayed_ref_root *delayed_refs; - int ret = 0; - - delayed_refs = &trans->transaction->delayed_refs; - spin_lock(&delayed_refs->lock); - head = btrfs_find_delayed_ref_head(trans, bytenr); - if (!head) { - spin_unlock(&delayed_refs->lock); - return 0; - } - - if (!mutex_trylock(&head->mutex)) { - atomic_inc(&head->node.refs); - spin_unlock(&delayed_refs->lock); - - btrfs_release_path(path); - - /* - * Mutex was contended, block until it's released and let - * caller try again - */ - mutex_lock(&head->mutex); - mutex_unlock(&head->mutex); - btrfs_put_delayed_ref(&head->node); - return -EAGAIN; - } - spin_unlock(&delayed_refs->lock); - - spin_lock(&head->lock); - list_for_each_entry(ref, &head->ref_list, list) { - /* If it's a shared ref we know a cross reference exists */ - if (ref->type != BTRFS_EXTENT_DATA_REF_KEY) { - ret = 1; - break; - } - - data_ref = btrfs_delayed_node_to_data_ref(ref); - - /* - * If our ref doesn't match the one we're currently looking at - * then we have a cross reference. - */ - if (data_ref->root != root->root_key.objectid || - data_ref->objectid != objectid || - data_ref->offset != offset) { - ret = 1; - break; - } - } - spin_unlock(&head->lock); - mutex_unlock(&head->mutex); - return ret; -} - -static noinline int check_committed_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - u64 objectid, u64 offset, u64 bytenr) -{ - struct btrfs_root *extent_root = root->fs_info->extent_root; - struct extent_buffer *leaf; - struct btrfs_extent_data_ref *ref; - struct btrfs_extent_inline_ref *iref; - struct btrfs_extent_item *ei; - struct btrfs_key key; - u32 item_size; - int ret; - - key.objectid = bytenr; - key.offset = (u64)-1; - key.type = BTRFS_EXTENT_ITEM_KEY; - - ret = btrfs_search_slot(NULL, extent_root, &key, path, 0, 0); - if (ret < 0) - goto out; - BUG_ON(ret == 0); /* Corruption */ - - ret = -ENOENT; - if (path->slots[0] == 0) - goto out; - - path->slots[0]--; - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - - if (key.objectid != bytenr || key.type != BTRFS_EXTENT_ITEM_KEY) - goto out; - - ret = 1; - item_size = btrfs_item_size_nr(leaf, path->slots[0]); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (item_size < sizeof(*ei)) { - WARN_ON(item_size != sizeof(struct btrfs_extent_item_v0)); - goto out; - } -#endif - ei = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); - - if (item_size != sizeof(*ei) + - btrfs_extent_inline_ref_size(BTRFS_EXTENT_DATA_REF_KEY)) - goto out; - - if (btrfs_extent_generation(leaf, ei) <= - btrfs_root_last_snapshot(&root->root_item)) - goto out; - - iref = (struct btrfs_extent_inline_ref *)(ei + 1); - if (btrfs_extent_inline_ref_type(leaf, iref) != - BTRFS_EXTENT_DATA_REF_KEY) - goto out; - - ref = (struct btrfs_extent_data_ref *)(&iref->offset); - if (btrfs_extent_refs(leaf, ei) != - btrfs_extent_data_ref_count(leaf, ref) || - btrfs_extent_data_ref_root(leaf, ref) != - root->root_key.objectid || - btrfs_extent_data_ref_objectid(leaf, ref) != objectid || - btrfs_extent_data_ref_offset(leaf, ref) != offset) - goto out; - - ret = 0; -out: - return ret; -} - -int btrfs_cross_ref_exist(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 objectid, u64 offset, u64 bytenr) -{ - struct btrfs_path *path; - int ret; - int ret2; - - path = btrfs_alloc_path(); - if (!path) - return -ENOENT; - - do { - ret = check_committed_ref(trans, root, path, objectid, - offset, bytenr); - if (ret && ret != -ENOENT) - goto out; - - ret2 = check_delayed_ref(trans, root, path, objectid, - offset, bytenr); - } while (ret2 == -EAGAIN); - - if (ret2 && ret2 != -ENOENT) { - ret = ret2; - goto out; - } - - if (ret != -ENOENT || ret2 != -ENOENT) - ret = 0; -out: - btrfs_free_path(path); - if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID) - WARN_ON(ret > 0); - return ret; -} - -static int __btrfs_mod_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct extent_buffer *buf, - int full_backref, int inc) -{ - u64 bytenr; - u64 num_bytes; - u64 parent; - u64 ref_root; - u32 nritems; - struct btrfs_key key; - struct btrfs_file_extent_item *fi; - int i; - int level; - int ret = 0; - int (*process_func)(struct btrfs_trans_handle *, struct btrfs_root *, - u64, u64, u64, u64, u64, u64); - - - if (btrfs_is_testing(root->fs_info)) - return 0; - - ref_root = btrfs_header_owner(buf); - nritems = btrfs_header_nritems(buf); - level = btrfs_header_level(buf); - - if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state) && level == 0) - return 0; - - if (inc) - process_func = btrfs_inc_extent_ref; - else - process_func = btrfs_free_extent; - - if (full_backref) - parent = buf->start; - else - parent = 0; - - for (i = 0; i < nritems; i++) { - if (level == 0) { - btrfs_item_key_to_cpu(buf, &key, i); - if (key.type != BTRFS_EXTENT_DATA_KEY) - continue; - fi = btrfs_item_ptr(buf, i, - struct btrfs_file_extent_item); - if (btrfs_file_extent_type(buf, fi) == - BTRFS_FILE_EXTENT_INLINE) - continue; - bytenr = btrfs_file_extent_disk_bytenr(buf, fi); - if (bytenr == 0) - continue; - - num_bytes = btrfs_file_extent_disk_num_bytes(buf, fi); - key.offset -= btrfs_file_extent_offset(buf, fi); - ret = process_func(trans, root, bytenr, num_bytes, - parent, ref_root, key.objectid, - key.offset); - if (ret) - goto fail; - } else { - bytenr = btrfs_node_blockptr(buf, i); - num_bytes = root->nodesize; - ret = process_func(trans, root, bytenr, num_bytes, - parent, ref_root, level - 1, 0); - if (ret) - goto fail; - } - } - return 0; -fail: - return ret; -} - -int btrfs_inc_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, - struct extent_buffer *buf, int full_backref) -{ - return __btrfs_mod_ref(trans, root, buf, full_backref, 1); -} - -int btrfs_dec_ref(struct btrfs_trans_handle *trans, struct btrfs_root *root, - struct extent_buffer *buf, int full_backref) -{ - return __btrfs_mod_ref(trans, root, buf, full_backref, 0); -} - -static int write_one_cache_group(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_block_group_cache *cache) -{ - int ret; - struct btrfs_root *extent_root = root->fs_info->extent_root; - unsigned long bi; - struct extent_buffer *leaf; - - ret = btrfs_search_slot(trans, extent_root, &cache->key, path, 0, 1); - if (ret) { - if (ret > 0) - ret = -ENOENT; - goto fail; - } - - leaf = path->nodes[0]; - bi = btrfs_item_ptr_offset(leaf, path->slots[0]); - write_extent_buffer(leaf, &cache->item, bi, sizeof(cache->item)); - btrfs_mark_buffer_dirty(leaf); -fail: - btrfs_release_path(path); - return ret; - -} - -static struct btrfs_block_group_cache * -next_block_group(struct btrfs_root *root, - struct btrfs_block_group_cache *cache) -{ - struct rb_node *node; - - spin_lock(&root->fs_info->block_group_cache_lock); - - /* If our block group was removed, we need a full search. */ - if (RB_EMPTY_NODE(&cache->cache_node)) { - const u64 next_bytenr = cache->key.objectid + cache->key.offset; - - spin_unlock(&root->fs_info->block_group_cache_lock); - btrfs_put_block_group(cache); - cache = btrfs_lookup_first_block_group(root->fs_info, - next_bytenr); - return cache; - } - node = rb_next(&cache->cache_node); - btrfs_put_block_group(cache); - if (node) { - cache = rb_entry(node, struct btrfs_block_group_cache, - cache_node); - btrfs_get_block_group(cache); - } else - cache = NULL; - spin_unlock(&root->fs_info->block_group_cache_lock); - return cache; -} - -static int cache_save_setup(struct btrfs_block_group_cache *block_group, - struct btrfs_trans_handle *trans, - struct btrfs_path *path) -{ - struct btrfs_root *root = block_group->fs_info->tree_root; - struct inode *inode = NULL; - u64 alloc_hint = 0; - int dcs = BTRFS_DC_ERROR; - u64 num_pages = 0; - int retries = 0; - int ret = 0; - - /* - * If this block group is smaller than 100 megs don't bother caching the - * block group. - */ - if (block_group->key.offset < (100 * SZ_1M)) { - spin_lock(&block_group->lock); - block_group->disk_cache_state = BTRFS_DC_WRITTEN; - spin_unlock(&block_group->lock); - return 0; - } - - if (trans->aborted) - return 0; -again: - inode = lookup_free_space_inode(root, block_group, path); - if (IS_ERR(inode) && PTR_ERR(inode) != -ENOENT) { - ret = PTR_ERR(inode); - btrfs_release_path(path); - goto out; - } - - if (IS_ERR(inode)) { - BUG_ON(retries); - retries++; - - if (block_group->ro) - goto out_free; - - ret = create_free_space_inode(root, trans, block_group, path); - if (ret) - goto out_free; - goto again; - } - - /* We've already setup this transaction, go ahead and exit */ - if (block_group->cache_generation == trans->transid && - i_size_read(inode)) { - dcs = BTRFS_DC_SETUP; - goto out_put; - } - - /* - * We want to set the generation to 0, that way if anything goes wrong - * from here on out we know not to trust this cache when we load up next - * time. - */ - BTRFS_I(inode)->generation = 0; - ret = btrfs_update_inode(trans, root, inode); - if (ret) { - /* - * So theoretically we could recover from this, simply set the - * super cache generation to 0 so we know to invalidate the - * cache, but then we'd have to keep track of the block groups - * that fail this way so we know we _have_ to reset this cache - * before the next commit or risk reading stale cache. So to - * limit our exposure to horrible edge cases lets just abort the - * transaction, this only happens in really bad situations - * anyway. - */ - btrfs_abort_transaction(trans, ret); - goto out_put; - } - WARN_ON(ret); - - if (i_size_read(inode) > 0) { - ret = btrfs_check_trunc_cache_free_space(root, - &root->fs_info->global_block_rsv); - if (ret) - goto out_put; - - ret = btrfs_truncate_free_space_cache(root, trans, NULL, inode); - if (ret) - goto out_put; - } - - spin_lock(&block_group->lock); - if (block_group->cached != BTRFS_CACHE_FINISHED || - !btrfs_test_opt(root->fs_info, SPACE_CACHE)) { - /* - * don't bother trying to write stuff out _if_ - * a) we're not cached, - * b) we're with nospace_cache mount option. - */ - dcs = BTRFS_DC_WRITTEN; - spin_unlock(&block_group->lock); - goto out_put; - } - spin_unlock(&block_group->lock); - - /* - * We hit an ENOSPC when setting up the cache in this transaction, just - * skip doing the setup, we've already cleared the cache so we're safe. - */ - if (test_bit(BTRFS_TRANS_CACHE_ENOSPC, &trans->transaction->flags)) { - ret = -ENOSPC; - goto out_put; - } - - /* - * Try to preallocate enough space based on how big the block group is. - * Keep in mind this has to include any pinned space which could end up - * taking up quite a bit since it's not folded into the other space - * cache. - */ - num_pages = div_u64(block_group->key.offset, SZ_256M); - if (!num_pages) - num_pages = 1; - - num_pages *= 16; - num_pages *= PAGE_SIZE; - - ret = btrfs_check_data_free_space(inode, 0, num_pages); - if (ret) - goto out_put; - - ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, num_pages, - num_pages, num_pages, - &alloc_hint); - /* - * Our cache requires contiguous chunks so that we don't modify a bunch - * of metadata or split extents when writing the cache out, which means - * we can enospc if we are heavily fragmented in addition to just normal - * out of space conditions. So if we hit this just skip setting up any - * other block groups for this transaction, maybe we'll unpin enough - * space the next time around. - */ - if (!ret) - dcs = BTRFS_DC_SETUP; - else if (ret == -ENOSPC) - set_bit(BTRFS_TRANS_CACHE_ENOSPC, &trans->transaction->flags); - -out_put: - iput(inode); -out_free: - btrfs_release_path(path); -out: - spin_lock(&block_group->lock); - if (!ret && dcs == BTRFS_DC_SETUP) - block_group->cache_generation = trans->transid; - block_group->disk_cache_state = dcs; - spin_unlock(&block_group->lock); - - return ret; -} - -int btrfs_setup_space_cache(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_block_group_cache *cache, *tmp; - struct btrfs_transaction *cur_trans = trans->transaction; - struct btrfs_path *path; - - if (list_empty(&cur_trans->dirty_bgs) || - !btrfs_test_opt(root->fs_info, SPACE_CACHE)) - return 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - /* Could add new block groups, use _safe just in case */ - list_for_each_entry_safe(cache, tmp, &cur_trans->dirty_bgs, - dirty_list) { - if (cache->disk_cache_state == BTRFS_DC_CLEAR) - cache_save_setup(cache, trans, path); - } - - btrfs_free_path(path); - return 0; -} - -/* - * transaction commit does final block group cache writeback during a - * critical section where nothing is allowed to change the FS. This is - * required in order for the cache to actually match the block group, - * but can introduce a lot of latency into the commit. - * - * So, btrfs_start_dirty_block_groups is here to kick off block group - * cache IO. There's a chance we'll have to redo some of it if the - * block group changes again during the commit, but it greatly reduces - * the commit latency by getting rid of the easy block groups while - * we're still allowing others to join the commit. - */ -int btrfs_start_dirty_block_groups(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_block_group_cache *cache; - struct btrfs_transaction *cur_trans = trans->transaction; - int ret = 0; - int should_put; - struct btrfs_path *path = NULL; - LIST_HEAD(dirty); - struct list_head *io = &cur_trans->io_bgs; - int num_started = 0; - int loops = 0; - - spin_lock(&cur_trans->dirty_bgs_lock); - if (list_empty(&cur_trans->dirty_bgs)) { - spin_unlock(&cur_trans->dirty_bgs_lock); - return 0; - } - list_splice_init(&cur_trans->dirty_bgs, &dirty); - spin_unlock(&cur_trans->dirty_bgs_lock); - -again: - /* - * make sure all the block groups on our dirty list actually - * exist - */ - btrfs_create_pending_block_groups(trans, root); - - if (!path) { - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - } - - /* - * cache_write_mutex is here only to save us from balance or automatic - * removal of empty block groups deleting this block group while we are - * writing out the cache - */ - mutex_lock(&trans->transaction->cache_write_mutex); - while (!list_empty(&dirty)) { - cache = list_first_entry(&dirty, - struct btrfs_block_group_cache, - dirty_list); - /* - * this can happen if something re-dirties a block - * group that is already under IO. Just wait for it to - * finish and then do it all again - */ - if (!list_empty(&cache->io_list)) { - list_del_init(&cache->io_list); - btrfs_wait_cache_io(root, trans, cache, - &cache->io_ctl, path, - cache->key.objectid); - btrfs_put_block_group(cache); - } - - - /* - * btrfs_wait_cache_io uses the cache->dirty_list to decide - * if it should update the cache_state. Don't delete - * until after we wait. - * - * Since we're not running in the commit critical section - * we need the dirty_bgs_lock to protect from update_block_group - */ - spin_lock(&cur_trans->dirty_bgs_lock); - list_del_init(&cache->dirty_list); - spin_unlock(&cur_trans->dirty_bgs_lock); - - should_put = 1; - - cache_save_setup(cache, trans, path); - - if (cache->disk_cache_state == BTRFS_DC_SETUP) { - cache->io_ctl.inode = NULL; - ret = btrfs_write_out_cache(root, trans, cache, path); - if (ret == 0 && cache->io_ctl.inode) { - num_started++; - should_put = 0; - - /* - * the cache_write_mutex is protecting - * the io_list - */ - list_add_tail(&cache->io_list, io); - } else { - /* - * if we failed to write the cache, the - * generation will be bad and life goes on - */ - ret = 0; - } - } - if (!ret) { - ret = write_one_cache_group(trans, root, path, cache); - /* - * Our block group might still be attached to the list - * of new block groups in the transaction handle of some - * other task (struct btrfs_trans_handle->new_bgs). This - * means its block group item isn't yet in the extent - * tree. If this happens ignore the error, as we will - * try again later in the critical section of the - * transaction commit. - */ - if (ret == -ENOENT) { - ret = 0; - spin_lock(&cur_trans->dirty_bgs_lock); - if (list_empty(&cache->dirty_list)) { - list_add_tail(&cache->dirty_list, - &cur_trans->dirty_bgs); - btrfs_get_block_group(cache); - } - spin_unlock(&cur_trans->dirty_bgs_lock); - } else if (ret) { - btrfs_abort_transaction(trans, ret); - } - } - - /* if its not on the io list, we need to put the block group */ - if (should_put) - btrfs_put_block_group(cache); - - if (ret) - break; - - /* - * Avoid blocking other tasks for too long. It might even save - * us from writing caches for block groups that are going to be - * removed. - */ - mutex_unlock(&trans->transaction->cache_write_mutex); - mutex_lock(&trans->transaction->cache_write_mutex); - } - mutex_unlock(&trans->transaction->cache_write_mutex); - - /* - * go through delayed refs for all the stuff we've just kicked off - * and then loop back (just once) - */ - ret = btrfs_run_delayed_refs(trans, root, 0); - if (!ret && loops == 0) { - loops++; - spin_lock(&cur_trans->dirty_bgs_lock); - list_splice_init(&cur_trans->dirty_bgs, &dirty); - /* - * dirty_bgs_lock protects us from concurrent block group - * deletes too (not just cache_write_mutex). - */ - if (!list_empty(&dirty)) { - spin_unlock(&cur_trans->dirty_bgs_lock); - goto again; - } - spin_unlock(&cur_trans->dirty_bgs_lock); - } else if (ret < 0) { - btrfs_cleanup_dirty_bgs(cur_trans, root); - } - - btrfs_free_path(path); - return ret; -} - -int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_block_group_cache *cache; - struct btrfs_transaction *cur_trans = trans->transaction; - int ret = 0; - int should_put; - struct btrfs_path *path; - struct list_head *io = &cur_trans->io_bgs; - int num_started = 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - /* - * Even though we are in the critical section of the transaction commit, - * we can still have concurrent tasks adding elements to this - * transaction's list of dirty block groups. These tasks correspond to - * endio free space workers started when writeback finishes for a - * space cache, which run inode.c:btrfs_finish_ordered_io(), and can - * allocate new block groups as a result of COWing nodes of the root - * tree when updating the free space inode. The writeback for the space - * caches is triggered by an earlier call to - * btrfs_start_dirty_block_groups() and iterations of the following - * loop. - * Also we want to do the cache_save_setup first and then run the - * delayed refs to make sure we have the best chance at doing this all - * in one shot. - */ - spin_lock(&cur_trans->dirty_bgs_lock); - while (!list_empty(&cur_trans->dirty_bgs)) { - cache = list_first_entry(&cur_trans->dirty_bgs, - struct btrfs_block_group_cache, - dirty_list); - - /* - * this can happen if cache_save_setup re-dirties a block - * group that is already under IO. Just wait for it to - * finish and then do it all again - */ - if (!list_empty(&cache->io_list)) { - spin_unlock(&cur_trans->dirty_bgs_lock); - list_del_init(&cache->io_list); - btrfs_wait_cache_io(root, trans, cache, - &cache->io_ctl, path, - cache->key.objectid); - btrfs_put_block_group(cache); - spin_lock(&cur_trans->dirty_bgs_lock); - } - - /* - * don't remove from the dirty list until after we've waited - * on any pending IO - */ - list_del_init(&cache->dirty_list); - spin_unlock(&cur_trans->dirty_bgs_lock); - should_put = 1; - - cache_save_setup(cache, trans, path); - - if (!ret) - ret = btrfs_run_delayed_refs(trans, root, (unsigned long) -1); - - if (!ret && cache->disk_cache_state == BTRFS_DC_SETUP) { - cache->io_ctl.inode = NULL; - ret = btrfs_write_out_cache(root, trans, cache, path); - if (ret == 0 && cache->io_ctl.inode) { - num_started++; - should_put = 0; - list_add_tail(&cache->io_list, io); - } else { - /* - * if we failed to write the cache, the - * generation will be bad and life goes on - */ - ret = 0; - } - } - if (!ret) { - ret = write_one_cache_group(trans, root, path, cache); - /* - * One of the free space endio workers might have - * created a new block group while updating a free space - * cache's inode (at inode.c:btrfs_finish_ordered_io()) - * and hasn't released its transaction handle yet, in - * which case the new block group is still attached to - * its transaction handle and its creation has not - * finished yet (no block group item in the extent tree - * yet, etc). If this is the case, wait for all free - * space endio workers to finish and retry. This is a - * a very rare case so no need for a more efficient and - * complex approach. - */ - if (ret == -ENOENT) { - wait_event(cur_trans->writer_wait, - atomic_read(&cur_trans->num_writers) == 1); - ret = write_one_cache_group(trans, root, path, - cache); - } - if (ret) - btrfs_abort_transaction(trans, ret); - } - - /* if its not on the io list, we need to put the block group */ - if (should_put) - btrfs_put_block_group(cache); - spin_lock(&cur_trans->dirty_bgs_lock); - } - spin_unlock(&cur_trans->dirty_bgs_lock); - - while (!list_empty(io)) { - cache = list_first_entry(io, struct btrfs_block_group_cache, - io_list); - list_del_init(&cache->io_list); - btrfs_wait_cache_io(root, trans, cache, - &cache->io_ctl, path, cache->key.objectid); - btrfs_put_block_group(cache); - } - - btrfs_free_path(path); - return ret; -} - -int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr) -{ - struct btrfs_block_group_cache *block_group; - int readonly = 0; - - block_group = btrfs_lookup_block_group(root->fs_info, bytenr); - if (!block_group || block_group->ro) - readonly = 1; - if (block_group) - btrfs_put_block_group(block_group); - return readonly; -} - -bool btrfs_inc_nocow_writers(struct btrfs_fs_info *fs_info, u64 bytenr) -{ - struct btrfs_block_group_cache *bg; - bool ret = true; - - bg = btrfs_lookup_block_group(fs_info, bytenr); - if (!bg) - return false; - - spin_lock(&bg->lock); - if (bg->ro) - ret = false; - else - atomic_inc(&bg->nocow_writers); - spin_unlock(&bg->lock); - - /* no put on block group, done by btrfs_dec_nocow_writers */ - if (!ret) - btrfs_put_block_group(bg); - - return ret; - -} - -void btrfs_dec_nocow_writers(struct btrfs_fs_info *fs_info, u64 bytenr) -{ - struct btrfs_block_group_cache *bg; - - bg = btrfs_lookup_block_group(fs_info, bytenr); - ASSERT(bg); - if (atomic_dec_and_test(&bg->nocow_writers)) - wake_up_atomic_t(&bg->nocow_writers); - /* - * Once for our lookup and once for the lookup done by a previous call - * to btrfs_inc_nocow_writers() - */ - btrfs_put_block_group(bg); - btrfs_put_block_group(bg); -} - -static int btrfs_wait_nocow_writers_atomic_t(atomic_t *a) -{ - schedule(); - return 0; -} - -void btrfs_wait_nocow_writers(struct btrfs_block_group_cache *bg) -{ - wait_on_atomic_t(&bg->nocow_writers, - btrfs_wait_nocow_writers_atomic_t, - TASK_UNINTERRUPTIBLE); -} - -static const char *alloc_name(u64 flags) -{ - switch (flags) { - case BTRFS_BLOCK_GROUP_METADATA|BTRFS_BLOCK_GROUP_DATA: - return "mixed"; - case BTRFS_BLOCK_GROUP_METADATA: - return "metadata"; - case BTRFS_BLOCK_GROUP_DATA: - return "data"; - case BTRFS_BLOCK_GROUP_SYSTEM: - return "system"; - default: - WARN_ON(1); - return "invalid-combination"; - }; -} - -static int update_space_info(struct btrfs_fs_info *info, u64 flags, - u64 total_bytes, u64 bytes_used, - u64 bytes_readonly, - struct btrfs_space_info **space_info) -{ - struct btrfs_space_info *found; - int i; - int factor; - int ret; - - if (flags & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID10)) - factor = 2; - else - factor = 1; - - found = __find_space_info(info, flags); - if (found) { - spin_lock(&found->lock); - found->total_bytes += total_bytes; - found->disk_total += total_bytes * factor; - found->bytes_used += bytes_used; - found->disk_used += bytes_used * factor; - found->bytes_readonly += bytes_readonly; - if (total_bytes > 0) - found->full = 0; - space_info_add_new_bytes(info, found, total_bytes - - bytes_used - bytes_readonly); - spin_unlock(&found->lock); - *space_info = found; - return 0; - } - found = kzalloc(sizeof(*found), GFP_NOFS); - if (!found) - return -ENOMEM; - - ret = percpu_counter_init(&found->total_bytes_pinned, 0, GFP_KERNEL); - if (ret) { - kfree(found); - return ret; - } - - for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) - INIT_LIST_HEAD(&found->block_groups[i]); - init_rwsem(&found->groups_sem); - spin_lock_init(&found->lock); - found->flags = flags & BTRFS_BLOCK_GROUP_TYPE_MASK; - found->total_bytes = total_bytes; - found->disk_total = total_bytes * factor; - found->bytes_used = bytes_used; - found->disk_used = bytes_used * factor; - found->bytes_pinned = 0; - found->bytes_reserved = 0; - found->bytes_readonly = bytes_readonly; - found->bytes_may_use = 0; - found->full = 0; - found->max_extent_size = 0; - found->force_alloc = CHUNK_ALLOC_NO_FORCE; - found->chunk_alloc = 0; - found->flush = 0; - init_waitqueue_head(&found->wait); - INIT_LIST_HEAD(&found->ro_bgs); - INIT_LIST_HEAD(&found->tickets); - INIT_LIST_HEAD(&found->priority_tickets); - - ret = kobject_init_and_add(&found->kobj, &space_info_ktype, - info->space_info_kobj, "%s", - alloc_name(found->flags)); - if (ret) { - kfree(found); - return ret; - } - - *space_info = found; - list_add_rcu(&found->list, &info->space_info); - if (flags & BTRFS_BLOCK_GROUP_DATA) - info->data_sinfo = found; - - return ret; -} - -static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags) -{ - u64 extra_flags = chunk_to_extended(flags) & - BTRFS_EXTENDED_PROFILE_MASK; - - write_seqlock(&fs_info->profiles_lock); - if (flags & BTRFS_BLOCK_GROUP_DATA) - fs_info->avail_data_alloc_bits |= extra_flags; - if (flags & BTRFS_BLOCK_GROUP_METADATA) - fs_info->avail_metadata_alloc_bits |= extra_flags; - if (flags & BTRFS_BLOCK_GROUP_SYSTEM) - fs_info->avail_system_alloc_bits |= extra_flags; - write_sequnlock(&fs_info->profiles_lock); -} - -/* - * returns target flags in extended format or 0 if restripe for this - * chunk_type is not in progress - * - * should be called with either volume_mutex or balance_lock held - */ -static u64 get_restripe_target(struct btrfs_fs_info *fs_info, u64 flags) -{ - struct btrfs_balance_control *bctl = fs_info->balance_ctl; - u64 target = 0; - - if (!bctl) - return 0; - - if (flags & BTRFS_BLOCK_GROUP_DATA && - bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) { - target = BTRFS_BLOCK_GROUP_DATA | bctl->data.target; - } else if (flags & BTRFS_BLOCK_GROUP_SYSTEM && - bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) { - target = BTRFS_BLOCK_GROUP_SYSTEM | bctl->sys.target; - } else if (flags & BTRFS_BLOCK_GROUP_METADATA && - bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) { - target = BTRFS_BLOCK_GROUP_METADATA | bctl->meta.target; - } - - return target; -} - -/* - * @flags: available profiles in extended format (see ctree.h) - * - * Returns reduced profile in chunk format. If profile changing is in - * progress (either running or paused) picks the target profile (if it's - * already available), otherwise falls back to plain reducing. - */ -static u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags) -{ - u64 num_devices = root->fs_info->fs_devices->rw_devices; - u64 target; - u64 raid_type; - u64 allowed = 0; - - /* - * see if restripe for this chunk_type is in progress, if so - * try to reduce to the target profile - */ - spin_lock(&root->fs_info->balance_lock); - target = get_restripe_target(root->fs_info, flags); - if (target) { - /* pick target profile only if it's already available */ - if ((flags & target) & BTRFS_EXTENDED_PROFILE_MASK) { - spin_unlock(&root->fs_info->balance_lock); - return extended_to_chunk(target); - } - } - spin_unlock(&root->fs_info->balance_lock); - - /* First, mask out the RAID levels which aren't possible */ - for (raid_type = 0; raid_type < BTRFS_NR_RAID_TYPES; raid_type++) { - if (num_devices >= btrfs_raid_array[raid_type].devs_min) - allowed |= btrfs_raid_group[raid_type]; - } - allowed &= flags; - - if (allowed & BTRFS_BLOCK_GROUP_RAID6) - allowed = BTRFS_BLOCK_GROUP_RAID6; - else if (allowed & BTRFS_BLOCK_GROUP_RAID5) - allowed = BTRFS_BLOCK_GROUP_RAID5; - else if (allowed & BTRFS_BLOCK_GROUP_RAID10) - allowed = BTRFS_BLOCK_GROUP_RAID10; - else if (allowed & BTRFS_BLOCK_GROUP_RAID1) - allowed = BTRFS_BLOCK_GROUP_RAID1; - else if (allowed & BTRFS_BLOCK_GROUP_RAID0) - allowed = BTRFS_BLOCK_GROUP_RAID0; - - flags &= ~BTRFS_BLOCK_GROUP_PROFILE_MASK; - - return extended_to_chunk(flags | allowed); -} - -static u64 get_alloc_profile(struct btrfs_root *root, u64 orig_flags) -{ - unsigned seq; - u64 flags; - - do { - flags = orig_flags; - seq = read_seqbegin(&root->fs_info->profiles_lock); - - if (flags & BTRFS_BLOCK_GROUP_DATA) - flags |= root->fs_info->avail_data_alloc_bits; - else if (flags & BTRFS_BLOCK_GROUP_SYSTEM) - flags |= root->fs_info->avail_system_alloc_bits; - else if (flags & BTRFS_BLOCK_GROUP_METADATA) - flags |= root->fs_info->avail_metadata_alloc_bits; - } while (read_seqretry(&root->fs_info->profiles_lock, seq)); - - return btrfs_reduce_alloc_profile(root, flags); -} - -u64 btrfs_get_alloc_profile(struct btrfs_root *root, int data) -{ - u64 flags; - u64 ret; - - if (data) - flags = BTRFS_BLOCK_GROUP_DATA; - else if (root == root->fs_info->chunk_root) - flags = BTRFS_BLOCK_GROUP_SYSTEM; - else - flags = BTRFS_BLOCK_GROUP_METADATA; - - ret = get_alloc_profile(root, flags); - return ret; -} - -int btrfs_alloc_data_chunk_ondemand(struct inode *inode, u64 bytes) -{ - struct btrfs_space_info *data_sinfo; - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_fs_info *fs_info = root->fs_info; - u64 used; - int ret = 0; - int need_commit = 2; - int have_pinned_space; - - /* make sure bytes are sectorsize aligned */ - bytes = ALIGN(bytes, root->sectorsize); - - if (btrfs_is_free_space_inode(inode)) { - need_commit = 0; - ASSERT(current->journal_info); - } - - data_sinfo = fs_info->data_sinfo; - if (!data_sinfo) - goto alloc; - -again: - /* make sure we have enough space to handle the data first */ - spin_lock(&data_sinfo->lock); - used = data_sinfo->bytes_used + data_sinfo->bytes_reserved + - data_sinfo->bytes_pinned + data_sinfo->bytes_readonly + - data_sinfo->bytes_may_use; - - if (used + bytes > data_sinfo->total_bytes) { - struct btrfs_trans_handle *trans; - - /* - * if we don't have enough free bytes in this space then we need - * to alloc a new chunk. - */ - if (!data_sinfo->full) { - u64 alloc_target; - - data_sinfo->force_alloc = CHUNK_ALLOC_FORCE; - spin_unlock(&data_sinfo->lock); -alloc: - alloc_target = btrfs_get_alloc_profile(root, 1); - /* - * It is ugly that we don't call nolock join - * transaction for the free space inode case here. - * But it is safe because we only do the data space - * reservation for the free space cache in the - * transaction context, the common join transaction - * just increase the counter of the current transaction - * handler, doesn't try to acquire the trans_lock of - * the fs. - */ - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - ret = do_chunk_alloc(trans, root->fs_info->extent_root, - alloc_target, - CHUNK_ALLOC_NO_FORCE); - btrfs_end_transaction(trans, root); - if (ret < 0) { - if (ret != -ENOSPC) - return ret; - else { - have_pinned_space = 1; - goto commit_trans; - } - } - - if (!data_sinfo) - data_sinfo = fs_info->data_sinfo; - - goto again; - } - - /* - * If we don't have enough pinned space to deal with this - * allocation, and no removed chunk in current transaction, - * don't bother committing the transaction. - */ - have_pinned_space = percpu_counter_compare( - &data_sinfo->total_bytes_pinned, - used + bytes - data_sinfo->total_bytes); - spin_unlock(&data_sinfo->lock); - - /* commit the current transaction and try again */ -commit_trans: - if (need_commit && - !atomic_read(&root->fs_info->open_ioctl_trans)) { - need_commit--; - - if (need_commit > 0) { - btrfs_start_delalloc_roots(fs_info, 0, -1); - btrfs_wait_ordered_roots(fs_info, -1, 0, (u64)-1); - } - - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) - return PTR_ERR(trans); - if (have_pinned_space >= 0 || - test_bit(BTRFS_TRANS_HAVE_FREE_BGS, - &trans->transaction->flags) || - need_commit > 0) { - ret = btrfs_commit_transaction(trans, root); - if (ret) - return ret; - /* - * The cleaner kthread might still be doing iput - * operations. Wait for it to finish so that - * more space is released. - */ - mutex_lock(&root->fs_info->cleaner_delayed_iput_mutex); - mutex_unlock(&root->fs_info->cleaner_delayed_iput_mutex); - goto again; - } else { - btrfs_end_transaction(trans, root); - } - } - - trace_btrfs_space_reservation(root->fs_info, - "space_info:enospc", - data_sinfo->flags, bytes, 1); - return -ENOSPC; - } - data_sinfo->bytes_may_use += bytes; - trace_btrfs_space_reservation(root->fs_info, "space_info", - data_sinfo->flags, bytes, 1); - spin_unlock(&data_sinfo->lock); - - return ret; -} - -/* - * New check_data_free_space() with ability for precious data reservation - * Will replace old btrfs_check_data_free_space(), but for patch split, - * add a new function first and then replace it. - */ -int btrfs_check_data_free_space(struct inode *inode, u64 start, u64 len) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - int ret; - - /* align the range */ - len = round_up(start + len, root->sectorsize) - - round_down(start, root->sectorsize); - start = round_down(start, root->sectorsize); - - ret = btrfs_alloc_data_chunk_ondemand(inode, len); - if (ret < 0) - return ret; - - /* Use new btrfs_qgroup_reserve_data to reserve precious data space. */ - ret = btrfs_qgroup_reserve_data(inode, start, len); - if (ret) - btrfs_free_reserved_data_space_noquota(inode, start, len); - return ret; -} - -/* - * Called if we need to clear a data reservation for this inode - * Normally in a error case. - * - * This one will *NOT* use accurate qgroup reserved space API, just for case - * which we can't sleep and is sure it won't affect qgroup reserved space. - * Like clear_bit_hook(). - */ -void btrfs_free_reserved_data_space_noquota(struct inode *inode, u64 start, - u64 len) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_space_info *data_sinfo; - - /* Make sure the range is aligned to sectorsize */ - len = round_up(start + len, root->sectorsize) - - round_down(start, root->sectorsize); - start = round_down(start, root->sectorsize); - - data_sinfo = root->fs_info->data_sinfo; - spin_lock(&data_sinfo->lock); - if (WARN_ON(data_sinfo->bytes_may_use < len)) - data_sinfo->bytes_may_use = 0; - else - data_sinfo->bytes_may_use -= len; - trace_btrfs_space_reservation(root->fs_info, "space_info", - data_sinfo->flags, len, 0); - spin_unlock(&data_sinfo->lock); -} - -/* - * Called if we need to clear a data reservation for this inode - * Normally in a error case. - * - * This one will handle the per-inode data rsv map for accurate reserved - * space framework. - */ -void btrfs_free_reserved_data_space(struct inode *inode, u64 start, u64 len) -{ - btrfs_free_reserved_data_space_noquota(inode, start, len); - btrfs_qgroup_free_data(inode, start, len); -} - -static void force_metadata_allocation(struct btrfs_fs_info *info) -{ - struct list_head *head = &info->space_info; - struct btrfs_space_info *found; - - rcu_read_lock(); - list_for_each_entry_rcu(found, head, list) { - if (found->flags & BTRFS_BLOCK_GROUP_METADATA) - found->force_alloc = CHUNK_ALLOC_FORCE; - } - rcu_read_unlock(); -} - -static inline u64 calc_global_rsv_need_space(struct btrfs_block_rsv *global) -{ - return (global->size << 1); -} - -static int should_alloc_chunk(struct btrfs_root *root, - struct btrfs_space_info *sinfo, int force) -{ - struct btrfs_block_rsv *global_rsv = &root->fs_info->global_block_rsv; - u64 num_bytes = sinfo->total_bytes - sinfo->bytes_readonly; - u64 num_allocated = sinfo->bytes_used + sinfo->bytes_reserved; - u64 thresh; - - if (force == CHUNK_ALLOC_FORCE) - return 1; - - /* - * We need to take into account the global rsv because for all intents - * and purposes it's used space. Don't worry about locking the - * global_rsv, it doesn't change except when the transaction commits. - */ - if (sinfo->flags & BTRFS_BLOCK_GROUP_METADATA) - num_allocated += calc_global_rsv_need_space(global_rsv); - - /* - * in limited mode, we want to have some free space up to - * about 1% of the FS size. - */ - if (force == CHUNK_ALLOC_LIMITED) { - thresh = btrfs_super_total_bytes(root->fs_info->super_copy); - thresh = max_t(u64, SZ_64M, div_factor_fine(thresh, 1)); - - if (num_bytes - num_allocated < thresh) - return 1; - } - - if (num_allocated + SZ_2M < div_factor(num_bytes, 8)) - return 0; - return 1; -} - -static u64 get_profile_num_devs(struct btrfs_root *root, u64 type) -{ - u64 num_dev; - - if (type & (BTRFS_BLOCK_GROUP_RAID10 | - BTRFS_BLOCK_GROUP_RAID0 | - BTRFS_BLOCK_GROUP_RAID5 | - BTRFS_BLOCK_GROUP_RAID6)) - num_dev = root->fs_info->fs_devices->rw_devices; - else if (type & BTRFS_BLOCK_GROUP_RAID1) - num_dev = 2; - else - num_dev = 1; /* DUP or single */ - - return num_dev; -} - -/* - * If @is_allocation is true, reserve space in the system space info necessary - * for allocating a chunk, otherwise if it's false, reserve space necessary for - * removing a chunk. - */ -void check_system_chunk(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 type) -{ - struct btrfs_space_info *info; - u64 left; - u64 thresh; - int ret = 0; - u64 num_devs; - - /* - * Needed because we can end up allocating a system chunk and for an - * atomic and race free space reservation in the chunk block reserve. - */ - ASSERT(mutex_is_locked(&root->fs_info->chunk_mutex)); - - info = __find_space_info(root->fs_info, BTRFS_BLOCK_GROUP_SYSTEM); - spin_lock(&info->lock); - left = info->total_bytes - info->bytes_used - info->bytes_pinned - - info->bytes_reserved - info->bytes_readonly - - info->bytes_may_use; - spin_unlock(&info->lock); - - num_devs = get_profile_num_devs(root, type); - - /* num_devs device items to update and 1 chunk item to add or remove */ - thresh = btrfs_calc_trunc_metadata_size(root, num_devs) + - btrfs_calc_trans_metadata_size(root, 1); - - if (left < thresh && btrfs_test_opt(root->fs_info, ENOSPC_DEBUG)) { - btrfs_info(root->fs_info, "left=%llu, need=%llu, flags=%llu", - left, thresh, type); - dump_space_info(root->fs_info, info, 0, 0); - } - - if (left < thresh) { - u64 flags; - - flags = btrfs_get_alloc_profile(root->fs_info->chunk_root, 0); - /* - * Ignore failure to create system chunk. We might end up not - * needing it, as we might not need to COW all nodes/leafs from - * the paths we visit in the chunk tree (they were already COWed - * or created in the current transaction for example). - */ - ret = btrfs_alloc_chunk(trans, root, flags); - } - - if (!ret) { - ret = btrfs_block_rsv_add(root->fs_info->chunk_root, - &root->fs_info->chunk_block_rsv, - thresh, BTRFS_RESERVE_NO_FLUSH); - if (!ret) - trans->chunk_bytes_reserved += thresh; - } -} - -/* - * If force is CHUNK_ALLOC_FORCE: - * - return 1 if it successfully allocates a chunk, - * - return errors including -ENOSPC otherwise. - * If force is NOT CHUNK_ALLOC_FORCE: - * - return 0 if it doesn't need to allocate a new chunk, - * - return 1 if it successfully allocates a chunk, - * - return errors including -ENOSPC otherwise. - */ -static int do_chunk_alloc(struct btrfs_trans_handle *trans, - struct btrfs_root *extent_root, u64 flags, int force) -{ - struct btrfs_space_info *space_info; - struct btrfs_fs_info *fs_info = extent_root->fs_info; - int wait_for_alloc = 0; - int ret = 0; - - /* Don't re-enter if we're already allocating a chunk */ - if (trans->allocating_chunk) - return -ENOSPC; - - space_info = __find_space_info(extent_root->fs_info, flags); - if (!space_info) { - ret = update_space_info(extent_root->fs_info, flags, - 0, 0, 0, &space_info); - BUG_ON(ret); /* -ENOMEM */ - } - BUG_ON(!space_info); /* Logic error */ - -again: - spin_lock(&space_info->lock); - if (force < space_info->force_alloc) - force = space_info->force_alloc; - if (space_info->full) { - if (should_alloc_chunk(extent_root, space_info, force)) - ret = -ENOSPC; - else - ret = 0; - spin_unlock(&space_info->lock); - return ret; - } - - if (!should_alloc_chunk(extent_root, space_info, force)) { - spin_unlock(&space_info->lock); - return 0; - } else if (space_info->chunk_alloc) { - wait_for_alloc = 1; - } else { - space_info->chunk_alloc = 1; - } - - spin_unlock(&space_info->lock); - - mutex_lock(&fs_info->chunk_mutex); - - /* - * The chunk_mutex is held throughout the entirety of a chunk - * allocation, so once we've acquired the chunk_mutex we know that the - * other guy is done and we need to recheck and see if we should - * allocate. - */ - if (wait_for_alloc) { - mutex_unlock(&fs_info->chunk_mutex); - wait_for_alloc = 0; - goto again; - } - - trans->allocating_chunk = true; - - /* - * If we have mixed data/metadata chunks we want to make sure we keep - * allocating mixed chunks instead of individual chunks. - */ - if (btrfs_mixed_space_info(space_info)) - flags |= (BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA); - - /* - * if we're doing a data chunk, go ahead and make sure that - * we keep a reasonable number of metadata chunks allocated in the - * FS as well. - */ - if (flags & BTRFS_BLOCK_GROUP_DATA && fs_info->metadata_ratio) { - fs_info->data_chunk_allocations++; - if (!(fs_info->data_chunk_allocations % - fs_info->metadata_ratio)) - force_metadata_allocation(fs_info); - } - - /* - * Check if we have enough space in SYSTEM chunk because we may need - * to update devices. - */ - check_system_chunk(trans, extent_root, flags); - - ret = btrfs_alloc_chunk(trans, extent_root, flags); - trans->allocating_chunk = false; - - spin_lock(&space_info->lock); - if (ret < 0 && ret != -ENOSPC) - goto out; - if (ret) - space_info->full = 1; - else - ret = 1; - - space_info->force_alloc = CHUNK_ALLOC_NO_FORCE; -out: - space_info->chunk_alloc = 0; - spin_unlock(&space_info->lock); - mutex_unlock(&fs_info->chunk_mutex); - /* - * When we allocate a new chunk we reserve space in the chunk block - * reserve to make sure we can COW nodes/leafs in the chunk tree or - * add new nodes/leafs to it if we end up needing to do it when - * inserting the chunk item and updating device items as part of the - * second phase of chunk allocation, performed by - * btrfs_finish_chunk_alloc(). So make sure we don't accumulate a - * large number of new block groups to create in our transaction - * handle's new_bgs list to avoid exhausting the chunk block reserve - * in extreme cases - like having a single transaction create many new - * block groups when starting to write out the free space caches of all - * the block groups that were made dirty during the lifetime of the - * transaction. - */ - if (trans->can_flush_pending_bgs && - trans->chunk_bytes_reserved >= (u64)SZ_2M) { - btrfs_create_pending_block_groups(trans, extent_root); - btrfs_trans_release_chunk_metadata(trans); - } - return ret; -} - -static int can_overcommit(struct btrfs_root *root, - struct btrfs_space_info *space_info, u64 bytes, - enum btrfs_reserve_flush_enum flush) -{ - struct btrfs_block_rsv *global_rsv; - u64 profile; - u64 space_size; - u64 avail; - u64 used; - - /* Don't overcommit when in mixed mode. */ - if (space_info->flags & BTRFS_BLOCK_GROUP_DATA) - return 0; - - BUG_ON(root->fs_info == NULL); - global_rsv = &root->fs_info->global_block_rsv; - profile = btrfs_get_alloc_profile(root, 0); - used = space_info->bytes_used + space_info->bytes_reserved + - space_info->bytes_pinned + space_info->bytes_readonly; - - /* - * We only want to allow over committing if we have lots of actual space - * free, but if we don't have enough space to handle the global reserve - * space then we could end up having a real enospc problem when trying - * to allocate a chunk or some other such important allocation. - */ - spin_lock(&global_rsv->lock); - space_size = calc_global_rsv_need_space(global_rsv); - spin_unlock(&global_rsv->lock); - if (used + space_size >= space_info->total_bytes) - return 0; - - used += space_info->bytes_may_use; - - spin_lock(&root->fs_info->free_chunk_lock); - avail = root->fs_info->free_chunk_space; - spin_unlock(&root->fs_info->free_chunk_lock); - - /* - * If we have dup, raid1 or raid10 then only half of the free - * space is actually useable. For raid56, the space info used - * doesn't include the parity drive, so we don't have to - * change the math - */ - if (profile & (BTRFS_BLOCK_GROUP_DUP | - BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID10)) - avail >>= 1; - - /* - * If we aren't flushing all things, let us overcommit up to - * 1/2th of the space. If we can flush, don't let us overcommit - * too much, let it overcommit up to 1/8 of the space. - */ - if (flush == BTRFS_RESERVE_FLUSH_ALL) - avail >>= 3; - else - avail >>= 1; - - if (used + bytes < space_info->total_bytes + avail) - return 1; - return 0; -} - -static void btrfs_writeback_inodes_sb_nr(struct btrfs_root *root, - unsigned long nr_pages, int nr_items) -{ - struct super_block *sb = root->fs_info->sb; - - if (down_read_trylock(&sb->s_umount)) { - writeback_inodes_sb_nr(sb, nr_pages, WB_REASON_FS_FREE_SPACE); - up_read(&sb->s_umount); - } else { - /* - * We needn't worry the filesystem going from r/w to r/o though - * we don't acquire ->s_umount mutex, because the filesystem - * should guarantee the delalloc inodes list be empty after - * the filesystem is readonly(all dirty pages are written to - * the disk). - */ - btrfs_start_delalloc_roots(root->fs_info, 0, nr_items); - if (!current->journal_info) - btrfs_wait_ordered_roots(root->fs_info, nr_items, - 0, (u64)-1); - } -} - -static inline int calc_reclaim_items_nr(struct btrfs_root *root, u64 to_reclaim) -{ - u64 bytes; - int nr; - - bytes = btrfs_calc_trans_metadata_size(root, 1); - nr = (int)div64_u64(to_reclaim, bytes); - if (!nr) - nr = 1; - return nr; -} - -#define EXTENT_SIZE_PER_ITEM SZ_256K - -/* - * shrink metadata reservation for delalloc - */ -static void shrink_delalloc(struct btrfs_root *root, u64 to_reclaim, u64 orig, - bool wait_ordered) -{ - struct btrfs_block_rsv *block_rsv; - struct btrfs_space_info *space_info; - struct btrfs_trans_handle *trans; - u64 delalloc_bytes; - u64 max_reclaim; - long time_left; - unsigned long nr_pages; - int loops; - int items; - enum btrfs_reserve_flush_enum flush; - - /* Calc the number of the pages we need flush for space reservation */ - items = calc_reclaim_items_nr(root, to_reclaim); - to_reclaim = (u64)items * EXTENT_SIZE_PER_ITEM; - - trans = (struct btrfs_trans_handle *)current->journal_info; - block_rsv = &root->fs_info->delalloc_block_rsv; - space_info = block_rsv->space_info; - - delalloc_bytes = percpu_counter_sum_positive( - &root->fs_info->delalloc_bytes); - if (delalloc_bytes == 0) { - if (trans) - return; - if (wait_ordered) - btrfs_wait_ordered_roots(root->fs_info, items, - 0, (u64)-1); - return; - } - - loops = 0; - while (delalloc_bytes && loops < 3) { - max_reclaim = min(delalloc_bytes, to_reclaim); - nr_pages = max_reclaim >> PAGE_SHIFT; - btrfs_writeback_inodes_sb_nr(root, nr_pages, items); - /* - * We need to wait for the async pages to actually start before - * we do anything. - */ - max_reclaim = atomic_read(&root->fs_info->async_delalloc_pages); - if (!max_reclaim) - goto skip_async; - - if (max_reclaim <= nr_pages) - max_reclaim = 0; - else - max_reclaim -= nr_pages; - - wait_event(root->fs_info->async_submit_wait, - atomic_read(&root->fs_info->async_delalloc_pages) <= - (int)max_reclaim); -skip_async: - if (!trans) - flush = BTRFS_RESERVE_FLUSH_ALL; - else - flush = BTRFS_RESERVE_NO_FLUSH; - spin_lock(&space_info->lock); - if (can_overcommit(root, space_info, orig, flush)) { - spin_unlock(&space_info->lock); - break; - } - if (list_empty(&space_info->tickets) && - list_empty(&space_info->priority_tickets)) { - spin_unlock(&space_info->lock); - break; - } - spin_unlock(&space_info->lock); - - loops++; - if (wait_ordered && !trans) { - btrfs_wait_ordered_roots(root->fs_info, items, - 0, (u64)-1); - } else { - time_left = schedule_timeout_killable(1); - if (time_left) - break; - } - delalloc_bytes = percpu_counter_sum_positive( - &root->fs_info->delalloc_bytes); - } -} - -/** - * maybe_commit_transaction - possibly commit the transaction if its ok to - * @root - the root we're allocating for - * @bytes - the number of bytes we want to reserve - * @force - force the commit - * - * This will check to make sure that committing the transaction will actually - * get us somewhere and then commit the transaction if it does. Otherwise it - * will return -ENOSPC. - */ -static int may_commit_transaction(struct btrfs_root *root, - struct btrfs_space_info *space_info, - u64 bytes, int force) -{ - struct btrfs_block_rsv *delayed_rsv = &root->fs_info->delayed_block_rsv; - struct btrfs_trans_handle *trans; - - trans = (struct btrfs_trans_handle *)current->journal_info; - if (trans) - return -EAGAIN; - - if (force) - goto commit; - - /* See if there is enough pinned space to make this reservation */ - if (percpu_counter_compare(&space_info->total_bytes_pinned, - bytes) >= 0) - goto commit; - - /* - * See if there is some space in the delayed insertion reservation for - * this reservation. - */ - if (space_info != delayed_rsv->space_info) - return -ENOSPC; - - spin_lock(&delayed_rsv->lock); - if (percpu_counter_compare(&space_info->total_bytes_pinned, - bytes - delayed_rsv->size) >= 0) { - spin_unlock(&delayed_rsv->lock); - return -ENOSPC; - } - spin_unlock(&delayed_rsv->lock); - -commit: - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) - return -ENOSPC; - - return btrfs_commit_transaction(trans, root); -} - -struct reserve_ticket { - u64 bytes; - int error; - struct list_head list; - wait_queue_head_t wait; -}; - -static int flush_space(struct btrfs_root *root, - struct btrfs_space_info *space_info, u64 num_bytes, - u64 orig_bytes, int state) -{ - struct btrfs_trans_handle *trans; - int nr; - int ret = 0; - - switch (state) { - case FLUSH_DELAYED_ITEMS_NR: - case FLUSH_DELAYED_ITEMS: - if (state == FLUSH_DELAYED_ITEMS_NR) - nr = calc_reclaim_items_nr(root, num_bytes) * 2; - else - nr = -1; - - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - break; - } - ret = btrfs_run_delayed_items_nr(trans, root, nr); - btrfs_end_transaction(trans, root); - break; - case FLUSH_DELALLOC: - case FLUSH_DELALLOC_WAIT: - shrink_delalloc(root, num_bytes * 2, orig_bytes, - state == FLUSH_DELALLOC_WAIT); - break; - case ALLOC_CHUNK: - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - break; - } - ret = do_chunk_alloc(trans, root->fs_info->extent_root, - btrfs_get_alloc_profile(root, 0), - CHUNK_ALLOC_NO_FORCE); - btrfs_end_transaction(trans, root); - if (ret > 0 || ret == -ENOSPC) - ret = 0; - break; - case COMMIT_TRANS: - ret = may_commit_transaction(root, space_info, orig_bytes, 0); - break; - default: - ret = -ENOSPC; - break; - } - - trace_btrfs_flush_space(root->fs_info, space_info->flags, num_bytes, - orig_bytes, state, ret); - return ret; -} - -static inline u64 -btrfs_calc_reclaim_metadata_size(struct btrfs_root *root, - struct btrfs_space_info *space_info) -{ - struct reserve_ticket *ticket; - u64 used; - u64 expected; - u64 to_reclaim = 0; - - list_for_each_entry(ticket, &space_info->tickets, list) - to_reclaim += ticket->bytes; - list_for_each_entry(ticket, &space_info->priority_tickets, list) - to_reclaim += ticket->bytes; - if (to_reclaim) - return to_reclaim; - - to_reclaim = min_t(u64, num_online_cpus() * SZ_1M, SZ_16M); - if (can_overcommit(root, space_info, to_reclaim, - BTRFS_RESERVE_FLUSH_ALL)) - return 0; - - used = space_info->bytes_used + space_info->bytes_reserved + - space_info->bytes_pinned + space_info->bytes_readonly + - space_info->bytes_may_use; - if (can_overcommit(root, space_info, SZ_1M, BTRFS_RESERVE_FLUSH_ALL)) - expected = div_factor_fine(space_info->total_bytes, 95); - else - expected = div_factor_fine(space_info->total_bytes, 90); - - if (used > expected) - to_reclaim = used - expected; - else - to_reclaim = 0; - to_reclaim = min(to_reclaim, space_info->bytes_may_use + - space_info->bytes_reserved); - return to_reclaim; -} - -static inline int need_do_async_reclaim(struct btrfs_space_info *space_info, - struct btrfs_root *root, u64 used) -{ - u64 thresh = div_factor_fine(space_info->total_bytes, 98); - - /* If we're just plain full then async reclaim just slows us down. */ - if ((space_info->bytes_used + space_info->bytes_reserved) >= thresh) - return 0; - - if (!btrfs_calc_reclaim_metadata_size(root, space_info)) - return 0; - - return (used >= thresh && !btrfs_fs_closing(root->fs_info) && - !test_bit(BTRFS_FS_STATE_REMOUNTING, - &root->fs_info->fs_state)); -} - -static void wake_all_tickets(struct list_head *head) -{ - struct reserve_ticket *ticket; - - while (!list_empty(head)) { - ticket = list_first_entry(head, struct reserve_ticket, list); - list_del_init(&ticket->list); - ticket->error = -ENOSPC; - wake_up(&ticket->wait); - } -} - -/* - * This is for normal flushers, we can wait all goddamned day if we want to. We - * will loop and continuously try to flush as long as we are making progress. - * We count progress as clearing off tickets each time we have to loop. - */ -static void btrfs_async_reclaim_metadata_space(struct work_struct *work) -{ - struct btrfs_fs_info *fs_info; - struct btrfs_space_info *space_info; - u64 to_reclaim; - int flush_state; - int commit_cycles = 0; - u64 last_tickets_id; - - fs_info = container_of(work, struct btrfs_fs_info, async_reclaim_work); - space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA); - - spin_lock(&space_info->lock); - to_reclaim = btrfs_calc_reclaim_metadata_size(fs_info->fs_root, - space_info); - if (!to_reclaim) { - space_info->flush = 0; - spin_unlock(&space_info->lock); - return; - } - last_tickets_id = space_info->tickets_id; - spin_unlock(&space_info->lock); - - flush_state = FLUSH_DELAYED_ITEMS_NR; - do { - struct reserve_ticket *ticket; - int ret; - - ret = flush_space(fs_info->fs_root, space_info, to_reclaim, - to_reclaim, flush_state); - spin_lock(&space_info->lock); - if (list_empty(&space_info->tickets)) { - space_info->flush = 0; - spin_unlock(&space_info->lock); - return; - } - to_reclaim = btrfs_calc_reclaim_metadata_size(fs_info->fs_root, - space_info); - ticket = list_first_entry(&space_info->tickets, - struct reserve_ticket, list); - if (last_tickets_id == space_info->tickets_id) { - flush_state++; - } else { - last_tickets_id = space_info->tickets_id; - flush_state = FLUSH_DELAYED_ITEMS_NR; - if (commit_cycles) - commit_cycles--; - } - - if (flush_state > COMMIT_TRANS) { - commit_cycles++; - if (commit_cycles > 2) { - wake_all_tickets(&space_info->tickets); - space_info->flush = 0; - } else { - flush_state = FLUSH_DELAYED_ITEMS_NR; - } - } - spin_unlock(&space_info->lock); - } while (flush_state <= COMMIT_TRANS); -} - -void btrfs_init_async_reclaim_work(struct work_struct *work) -{ - INIT_WORK(work, btrfs_async_reclaim_metadata_space); -} - -static void priority_reclaim_metadata_space(struct btrfs_fs_info *fs_info, - struct btrfs_space_info *space_info, - struct reserve_ticket *ticket) -{ - u64 to_reclaim; - int flush_state = FLUSH_DELAYED_ITEMS_NR; - - spin_lock(&space_info->lock); - to_reclaim = btrfs_calc_reclaim_metadata_size(fs_info->fs_root, - space_info); - if (!to_reclaim) { - spin_unlock(&space_info->lock); - return; - } - spin_unlock(&space_info->lock); - - do { - flush_space(fs_info->fs_root, space_info, to_reclaim, - to_reclaim, flush_state); - flush_state++; - spin_lock(&space_info->lock); - if (ticket->bytes == 0) { - spin_unlock(&space_info->lock); - return; - } - spin_unlock(&space_info->lock); - - /* - * Priority flushers can't wait on delalloc without - * deadlocking. - */ - if (flush_state == FLUSH_DELALLOC || - flush_state == FLUSH_DELALLOC_WAIT) - flush_state = ALLOC_CHUNK; - } while (flush_state < COMMIT_TRANS); -} - -static int wait_reserve_ticket(struct btrfs_fs_info *fs_info, - struct btrfs_space_info *space_info, - struct reserve_ticket *ticket, u64 orig_bytes) - -{ - DEFINE_WAIT(wait); - int ret = 0; - - spin_lock(&space_info->lock); - while (ticket->bytes > 0 && ticket->error == 0) { - ret = prepare_to_wait_event(&ticket->wait, &wait, TASK_KILLABLE); - if (ret) { - ret = -EINTR; - break; - } - spin_unlock(&space_info->lock); - - schedule(); - - finish_wait(&ticket->wait, &wait); - spin_lock(&space_info->lock); - } - if (!ret) - ret = ticket->error; - if (!list_empty(&ticket->list)) - list_del_init(&ticket->list); - if (ticket->bytes && ticket->bytes < orig_bytes) { - u64 num_bytes = orig_bytes - ticket->bytes; - space_info->bytes_may_use -= num_bytes; - trace_btrfs_space_reservation(fs_info, "space_info", - space_info->flags, num_bytes, 0); - } - spin_unlock(&space_info->lock); - - return ret; -} - -/** - * reserve_metadata_bytes - try to reserve bytes from the block_rsv's space - * @root - the root we're allocating for - * @space_info - the space info we want to allocate from - * @orig_bytes - the number of bytes we want - * @flush - whether or not we can flush to make our reservation - * - * This will reserve orig_bytes number of bytes from the space info associated - * with the block_rsv. If there is not enough space it will make an attempt to - * flush out space to make room. It will do this by flushing delalloc if - * possible or committing the transaction. If flush is 0 then no attempts to - * regain reservations will be made and this will fail if there is not enough - * space already. - */ -static int __reserve_metadata_bytes(struct btrfs_root *root, - struct btrfs_space_info *space_info, - u64 orig_bytes, - enum btrfs_reserve_flush_enum flush) -{ - struct reserve_ticket ticket; - u64 used; - int ret = 0; - - ASSERT(orig_bytes); - ASSERT(!current->journal_info || flush != BTRFS_RESERVE_FLUSH_ALL); - - spin_lock(&space_info->lock); - ret = -ENOSPC; - used = space_info->bytes_used + space_info->bytes_reserved + - space_info->bytes_pinned + space_info->bytes_readonly + - space_info->bytes_may_use; - - /* - * If we have enough space then hooray, make our reservation and carry - * on. If not see if we can overcommit, and if we can, hooray carry on. - * If not things get more complicated. - */ - if (used + orig_bytes <= space_info->total_bytes) { - space_info->bytes_may_use += orig_bytes; - trace_btrfs_space_reservation(root->fs_info, "space_info", - space_info->flags, orig_bytes, - 1); - ret = 0; - } else if (can_overcommit(root, space_info, orig_bytes, flush)) { - space_info->bytes_may_use += orig_bytes; - trace_btrfs_space_reservation(root->fs_info, "space_info", - space_info->flags, orig_bytes, - 1); - ret = 0; - } - - /* - * If we couldn't make a reservation then setup our reservation ticket - * and kick the async worker if it's not already running. - * - * If we are a priority flusher then we just need to add our ticket to - * the list and we will do our own flushing further down. - */ - if (ret && flush != BTRFS_RESERVE_NO_FLUSH) { - ticket.bytes = orig_bytes; - ticket.error = 0; - init_waitqueue_head(&ticket.wait); - if (flush == BTRFS_RESERVE_FLUSH_ALL) { - list_add_tail(&ticket.list, &space_info->tickets); - if (!space_info->flush) { - space_info->flush = 1; - trace_btrfs_trigger_flush(root->fs_info, - space_info->flags, - orig_bytes, flush, - "enospc"); - queue_work(system_unbound_wq, - &root->fs_info->async_reclaim_work); - } - } else { - list_add_tail(&ticket.list, - &space_info->priority_tickets); - } - } else if (!ret && space_info->flags & BTRFS_BLOCK_GROUP_METADATA) { - used += orig_bytes; - /* - * We will do the space reservation dance during log replay, - * which means we won't have fs_info->fs_root set, so don't do - * the async reclaim as we will panic. - */ - if (!test_bit(BTRFS_FS_LOG_RECOVERING, &root->fs_info->flags) && - need_do_async_reclaim(space_info, root, used) && - !work_busy(&root->fs_info->async_reclaim_work)) { - trace_btrfs_trigger_flush(root->fs_info, - space_info->flags, - orig_bytes, flush, - "preempt"); - queue_work(system_unbound_wq, - &root->fs_info->async_reclaim_work); - } - } - spin_unlock(&space_info->lock); - if (!ret || flush == BTRFS_RESERVE_NO_FLUSH) - return ret; - - if (flush == BTRFS_RESERVE_FLUSH_ALL) - return wait_reserve_ticket(root->fs_info, space_info, &ticket, - orig_bytes); - - ret = 0; - priority_reclaim_metadata_space(root->fs_info, space_info, &ticket); - spin_lock(&space_info->lock); - if (ticket.bytes) { - if (ticket.bytes < orig_bytes) { - u64 num_bytes = orig_bytes - ticket.bytes; - space_info->bytes_may_use -= num_bytes; - trace_btrfs_space_reservation(root->fs_info, - "space_info", space_info->flags, - num_bytes, 0); - - } - list_del_init(&ticket.list); - ret = -ENOSPC; - } - spin_unlock(&space_info->lock); - ASSERT(list_empty(&ticket.list)); - return ret; -} - -/** - * reserve_metadata_bytes - try to reserve bytes from the block_rsv's space - * @root - the root we're allocating for - * @block_rsv - the block_rsv we're allocating for - * @orig_bytes - the number of bytes we want - * @flush - whether or not we can flush to make our reservation - * - * This will reserve orgi_bytes number of bytes from the space info associated - * with the block_rsv. If there is not enough space it will make an attempt to - * flush out space to make room. It will do this by flushing delalloc if - * possible or committing the transaction. If flush is 0 then no attempts to - * regain reservations will be made and this will fail if there is not enough - * space already. - */ -static int reserve_metadata_bytes(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, - u64 orig_bytes, - enum btrfs_reserve_flush_enum flush) -{ - int ret; - - ret = __reserve_metadata_bytes(root, block_rsv->space_info, orig_bytes, - flush); - if (ret == -ENOSPC && - unlikely(root->orphan_cleanup_state == ORPHAN_CLEANUP_STARTED)) { - struct btrfs_block_rsv *global_rsv = - &root->fs_info->global_block_rsv; - - if (block_rsv != global_rsv && - !block_rsv_use_bytes(global_rsv, orig_bytes)) - ret = 0; - } - if (ret == -ENOSPC) - trace_btrfs_space_reservation(root->fs_info, - "space_info:enospc", - block_rsv->space_info->flags, - orig_bytes, 1); - return ret; -} - -static struct btrfs_block_rsv *get_block_rsv( - const struct btrfs_trans_handle *trans, - const struct btrfs_root *root) -{ - struct btrfs_block_rsv *block_rsv = NULL; - - if (test_bit(BTRFS_ROOT_REF_COWS, &root->state) || - (root == root->fs_info->csum_root && trans->adding_csums) || - (root == root->fs_info->uuid_root)) - block_rsv = trans->block_rsv; - - if (!block_rsv) - block_rsv = root->block_rsv; - - if (!block_rsv) - block_rsv = &root->fs_info->empty_block_rsv; - - return block_rsv; -} - -static int block_rsv_use_bytes(struct btrfs_block_rsv *block_rsv, - u64 num_bytes) -{ - int ret = -ENOSPC; - spin_lock(&block_rsv->lock); - if (block_rsv->reserved >= num_bytes) { - block_rsv->reserved -= num_bytes; - if (block_rsv->reserved < block_rsv->size) - block_rsv->full = 0; - ret = 0; - } - spin_unlock(&block_rsv->lock); - return ret; -} - -static void block_rsv_add_bytes(struct btrfs_block_rsv *block_rsv, - u64 num_bytes, int update_size) -{ - spin_lock(&block_rsv->lock); - block_rsv->reserved += num_bytes; - if (update_size) - block_rsv->size += num_bytes; - else if (block_rsv->reserved >= block_rsv->size) - block_rsv->full = 1; - spin_unlock(&block_rsv->lock); -} - -int btrfs_cond_migrate_bytes(struct btrfs_fs_info *fs_info, - struct btrfs_block_rsv *dest, u64 num_bytes, - int min_factor) -{ - struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv; - u64 min_bytes; - - if (global_rsv->space_info != dest->space_info) - return -ENOSPC; - - spin_lock(&global_rsv->lock); - min_bytes = div_factor(global_rsv->size, min_factor); - if (global_rsv->reserved < min_bytes + num_bytes) { - spin_unlock(&global_rsv->lock); - return -ENOSPC; - } - global_rsv->reserved -= num_bytes; - if (global_rsv->reserved < global_rsv->size) - global_rsv->full = 0; - spin_unlock(&global_rsv->lock); - - block_rsv_add_bytes(dest, num_bytes, 1); - return 0; -} - -/* - * This is for space we already have accounted in space_info->bytes_may_use, so - * basically when we're returning space from block_rsv's. - */ -static void space_info_add_old_bytes(struct btrfs_fs_info *fs_info, - struct btrfs_space_info *space_info, - u64 num_bytes) -{ - struct reserve_ticket *ticket; - struct list_head *head; - u64 used; - enum btrfs_reserve_flush_enum flush = BTRFS_RESERVE_NO_FLUSH; - bool check_overcommit = false; - - spin_lock(&space_info->lock); - head = &space_info->priority_tickets; - - /* - * If we are over our limit then we need to check and see if we can - * overcommit, and if we can't then we just need to free up our space - * and not satisfy any requests. - */ - used = space_info->bytes_used + space_info->bytes_reserved + - space_info->bytes_pinned + space_info->bytes_readonly + - space_info->bytes_may_use; - if (used - num_bytes >= space_info->total_bytes) - check_overcommit = true; -again: - while (!list_empty(head) && num_bytes) { - ticket = list_first_entry(head, struct reserve_ticket, - list); - /* - * We use 0 bytes because this space is already reserved, so - * adding the ticket space would be a double count. - */ - if (check_overcommit && - !can_overcommit(fs_info->extent_root, space_info, 0, - flush)) - break; - if (num_bytes >= ticket->bytes) { - list_del_init(&ticket->list); - num_bytes -= ticket->bytes; - ticket->bytes = 0; - space_info->tickets_id++; - wake_up(&ticket->wait); - } else { - ticket->bytes -= num_bytes; - num_bytes = 0; - } - } - - if (num_bytes && head == &space_info->priority_tickets) { - head = &space_info->tickets; - flush = BTRFS_RESERVE_FLUSH_ALL; - goto again; - } - space_info->bytes_may_use -= num_bytes; - trace_btrfs_space_reservation(fs_info, "space_info", - space_info->flags, num_bytes, 0); - spin_unlock(&space_info->lock); -} - -/* - * This is for newly allocated space that isn't accounted in - * space_info->bytes_may_use yet. So if we allocate a chunk or unpin an extent - * we use this helper. - */ -static void space_info_add_new_bytes(struct btrfs_fs_info *fs_info, - struct btrfs_space_info *space_info, - u64 num_bytes) -{ - struct reserve_ticket *ticket; - struct list_head *head = &space_info->priority_tickets; - -again: - while (!list_empty(head) && num_bytes) { - ticket = list_first_entry(head, struct reserve_ticket, - list); - if (num_bytes >= ticket->bytes) { - trace_btrfs_space_reservation(fs_info, "space_info", - space_info->flags, - ticket->bytes, 1); - list_del_init(&ticket->list); - num_bytes -= ticket->bytes; - space_info->bytes_may_use += ticket->bytes; - ticket->bytes = 0; - space_info->tickets_id++; - wake_up(&ticket->wait); - } else { - trace_btrfs_space_reservation(fs_info, "space_info", - space_info->flags, - num_bytes, 1); - space_info->bytes_may_use += num_bytes; - ticket->bytes -= num_bytes; - num_bytes = 0; - } - } - - if (num_bytes && head == &space_info->priority_tickets) { - head = &space_info->tickets; - goto again; - } -} - -static void block_rsv_release_bytes(struct btrfs_fs_info *fs_info, - struct btrfs_block_rsv *block_rsv, - struct btrfs_block_rsv *dest, u64 num_bytes) -{ - struct btrfs_space_info *space_info = block_rsv->space_info; - - spin_lock(&block_rsv->lock); - if (num_bytes == (u64)-1) - num_bytes = block_rsv->size; - block_rsv->size -= num_bytes; - if (block_rsv->reserved >= block_rsv->size) { - num_bytes = block_rsv->reserved - block_rsv->size; - block_rsv->reserved = block_rsv->size; - block_rsv->full = 1; - } else { - num_bytes = 0; - } - spin_unlock(&block_rsv->lock); - - if (num_bytes > 0) { - if (dest) { - spin_lock(&dest->lock); - if (!dest->full) { - u64 bytes_to_add; - - bytes_to_add = dest->size - dest->reserved; - bytes_to_add = min(num_bytes, bytes_to_add); - dest->reserved += bytes_to_add; - if (dest->reserved >= dest->size) - dest->full = 1; - num_bytes -= bytes_to_add; - } - spin_unlock(&dest->lock); - } - if (num_bytes) - space_info_add_old_bytes(fs_info, space_info, - num_bytes); - } -} - -int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src, - struct btrfs_block_rsv *dst, u64 num_bytes, - int update_size) -{ - int ret; - - ret = block_rsv_use_bytes(src, num_bytes); - if (ret) - return ret; - - block_rsv_add_bytes(dst, num_bytes, update_size); - return 0; -} - -void btrfs_init_block_rsv(struct btrfs_block_rsv *rsv, unsigned short type) -{ - memset(rsv, 0, sizeof(*rsv)); - spin_lock_init(&rsv->lock); - rsv->type = type; -} - -struct btrfs_block_rsv *btrfs_alloc_block_rsv(struct btrfs_root *root, - unsigned short type) -{ - struct btrfs_block_rsv *block_rsv; - struct btrfs_fs_info *fs_info = root->fs_info; - - block_rsv = kmalloc(sizeof(*block_rsv), GFP_NOFS); - if (!block_rsv) - return NULL; - - btrfs_init_block_rsv(block_rsv, type); - block_rsv->space_info = __find_space_info(fs_info, - BTRFS_BLOCK_GROUP_METADATA); - return block_rsv; -} - -void btrfs_free_block_rsv(struct btrfs_root *root, - struct btrfs_block_rsv *rsv) -{ - if (!rsv) - return; - btrfs_block_rsv_release(root, rsv, (u64)-1); - kfree(rsv); -} - -void __btrfs_free_block_rsv(struct btrfs_block_rsv *rsv) -{ - kfree(rsv); -} - -int btrfs_block_rsv_add(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, u64 num_bytes, - enum btrfs_reserve_flush_enum flush) -{ - int ret; - - if (num_bytes == 0) - return 0; - - ret = reserve_metadata_bytes(root, block_rsv, num_bytes, flush); - if (!ret) { - block_rsv_add_bytes(block_rsv, num_bytes, 1); - return 0; - } - - return ret; -} - -int btrfs_block_rsv_check(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, int min_factor) -{ - u64 num_bytes = 0; - int ret = -ENOSPC; - - if (!block_rsv) - return 0; - - spin_lock(&block_rsv->lock); - num_bytes = div_factor(block_rsv->size, min_factor); - if (block_rsv->reserved >= num_bytes) - ret = 0; - spin_unlock(&block_rsv->lock); - - return ret; -} - -int btrfs_block_rsv_refill(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, u64 min_reserved, - enum btrfs_reserve_flush_enum flush) -{ - u64 num_bytes = 0; - int ret = -ENOSPC; - - if (!block_rsv) - return 0; - - spin_lock(&block_rsv->lock); - num_bytes = min_reserved; - if (block_rsv->reserved >= num_bytes) - ret = 0; - else - num_bytes -= block_rsv->reserved; - spin_unlock(&block_rsv->lock); - - if (!ret) - return 0; - - ret = reserve_metadata_bytes(root, block_rsv, num_bytes, flush); - if (!ret) { - block_rsv_add_bytes(block_rsv, num_bytes, 0); - return 0; - } - - return ret; -} - -void btrfs_block_rsv_release(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, - u64 num_bytes) -{ - struct btrfs_block_rsv *global_rsv = &root->fs_info->global_block_rsv; - if (global_rsv == block_rsv || - block_rsv->space_info != global_rsv->space_info) - global_rsv = NULL; - block_rsv_release_bytes(root->fs_info, block_rsv, global_rsv, - num_bytes); -} - -static void update_global_block_rsv(struct btrfs_fs_info *fs_info) -{ - struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; - struct btrfs_space_info *sinfo = block_rsv->space_info; - u64 num_bytes; - - /* - * The global block rsv is based on the size of the extent tree, the - * checksum tree and the root tree. If the fs is empty we want to set - * it to a minimal amount for safety. - */ - num_bytes = btrfs_root_used(&fs_info->extent_root->root_item) + - btrfs_root_used(&fs_info->csum_root->root_item) + - btrfs_root_used(&fs_info->tree_root->root_item); - num_bytes = max_t(u64, num_bytes, SZ_16M); - - spin_lock(&sinfo->lock); - spin_lock(&block_rsv->lock); - - block_rsv->size = min_t(u64, num_bytes, SZ_512M); - - if (block_rsv->reserved < block_rsv->size) { - num_bytes = sinfo->bytes_used + sinfo->bytes_pinned + - sinfo->bytes_reserved + sinfo->bytes_readonly + - sinfo->bytes_may_use; - if (sinfo->total_bytes > num_bytes) { - num_bytes = sinfo->total_bytes - num_bytes; - num_bytes = min(num_bytes, - block_rsv->size - block_rsv->reserved); - block_rsv->reserved += num_bytes; - sinfo->bytes_may_use += num_bytes; - trace_btrfs_space_reservation(fs_info, "space_info", - sinfo->flags, num_bytes, - 1); - } - } else if (block_rsv->reserved > block_rsv->size) { - num_bytes = block_rsv->reserved - block_rsv->size; - sinfo->bytes_may_use -= num_bytes; - trace_btrfs_space_reservation(fs_info, "space_info", - sinfo->flags, num_bytes, 0); - block_rsv->reserved = block_rsv->size; - } - - if (block_rsv->reserved == block_rsv->size) - block_rsv->full = 1; - else - block_rsv->full = 0; - - spin_unlock(&block_rsv->lock); - spin_unlock(&sinfo->lock); -} - -static void init_global_block_rsv(struct btrfs_fs_info *fs_info) -{ - struct btrfs_space_info *space_info; - - space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_SYSTEM); - fs_info->chunk_block_rsv.space_info = space_info; - - space_info = __find_space_info(fs_info, BTRFS_BLOCK_GROUP_METADATA); - fs_info->global_block_rsv.space_info = space_info; - fs_info->delalloc_block_rsv.space_info = space_info; - fs_info->trans_block_rsv.space_info = space_info; - fs_info->empty_block_rsv.space_info = space_info; - fs_info->delayed_block_rsv.space_info = space_info; - - fs_info->extent_root->block_rsv = &fs_info->global_block_rsv; - fs_info->csum_root->block_rsv = &fs_info->global_block_rsv; - fs_info->dev_root->block_rsv = &fs_info->global_block_rsv; - fs_info->tree_root->block_rsv = &fs_info->global_block_rsv; - if (fs_info->quota_root) - fs_info->quota_root->block_rsv = &fs_info->global_block_rsv; - fs_info->chunk_root->block_rsv = &fs_info->chunk_block_rsv; - - update_global_block_rsv(fs_info); -} - -static void release_global_block_rsv(struct btrfs_fs_info *fs_info) -{ - block_rsv_release_bytes(fs_info, &fs_info->global_block_rsv, NULL, - (u64)-1); - WARN_ON(fs_info->delalloc_block_rsv.size > 0); - WARN_ON(fs_info->delalloc_block_rsv.reserved > 0); - WARN_ON(fs_info->trans_block_rsv.size > 0); - WARN_ON(fs_info->trans_block_rsv.reserved > 0); - WARN_ON(fs_info->chunk_block_rsv.size > 0); - WARN_ON(fs_info->chunk_block_rsv.reserved > 0); - WARN_ON(fs_info->delayed_block_rsv.size > 0); - WARN_ON(fs_info->delayed_block_rsv.reserved > 0); -} - -void btrfs_trans_release_metadata(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - if (!trans->block_rsv) - return; - - if (!trans->bytes_reserved) - return; - - trace_btrfs_space_reservation(root->fs_info, "transaction", - trans->transid, trans->bytes_reserved, 0); - btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved); - trans->bytes_reserved = 0; -} - -/* - * To be called after all the new block groups attached to the transaction - * handle have been created (btrfs_create_pending_block_groups()). - */ -void btrfs_trans_release_chunk_metadata(struct btrfs_trans_handle *trans) -{ - struct btrfs_fs_info *fs_info = trans->fs_info; - - if (!trans->chunk_bytes_reserved) - return; - - WARN_ON_ONCE(!list_empty(&trans->new_bgs)); - - block_rsv_release_bytes(fs_info, &fs_info->chunk_block_rsv, NULL, - trans->chunk_bytes_reserved); - trans->chunk_bytes_reserved = 0; -} - -/* Can only return 0 or -ENOSPC */ -int btrfs_orphan_reserve_metadata(struct btrfs_trans_handle *trans, - struct inode *inode) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - /* - * We always use trans->block_rsv here as we will have reserved space - * for our orphan when starting the transaction, using get_block_rsv() - * here will sometimes make us choose the wrong block rsv as we could be - * doing a reloc inode for a non refcounted root. - */ - struct btrfs_block_rsv *src_rsv = trans->block_rsv; - struct btrfs_block_rsv *dst_rsv = root->orphan_block_rsv; - - /* - * We need to hold space in order to delete our orphan item once we've - * added it, so this takes the reservation so we can release it later - * when we are truly done with the orphan item. - */ - u64 num_bytes = btrfs_calc_trans_metadata_size(root, 1); - trace_btrfs_space_reservation(root->fs_info, "orphan", - btrfs_ino(inode), num_bytes, 1); - return btrfs_block_rsv_migrate(src_rsv, dst_rsv, num_bytes, 1); -} - -void btrfs_orphan_release_metadata(struct inode *inode) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - u64 num_bytes = btrfs_calc_trans_metadata_size(root, 1); - trace_btrfs_space_reservation(root->fs_info, "orphan", - btrfs_ino(inode), num_bytes, 0); - btrfs_block_rsv_release(root, root->orphan_block_rsv, num_bytes); -} - -/* - * btrfs_subvolume_reserve_metadata() - reserve space for subvolume operation - * root: the root of the parent directory - * rsv: block reservation - * items: the number of items that we need do reservation - * qgroup_reserved: used to return the reserved size in qgroup - * - * This function is used to reserve the space for snapshot/subvolume - * creation and deletion. Those operations are different with the - * common file/directory operations, they change two fs/file trees - * and root tree, the number of items that the qgroup reserves is - * different with the free space reservation. So we can not use - * the space reservation mechanism in start_transaction(). - */ -int btrfs_subvolume_reserve_metadata(struct btrfs_root *root, - struct btrfs_block_rsv *rsv, - int items, - u64 *qgroup_reserved, - bool use_global_rsv) -{ - u64 num_bytes; - int ret; - struct btrfs_block_rsv *global_rsv = &root->fs_info->global_block_rsv; - - if (test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags)) { - /* One for parent inode, two for dir entries */ - num_bytes = 3 * root->nodesize; - ret = btrfs_qgroup_reserve_meta(root, num_bytes); - if (ret) - return ret; - } else { - num_bytes = 0; - } - - *qgroup_reserved = num_bytes; - - num_bytes = btrfs_calc_trans_metadata_size(root, items); - rsv->space_info = __find_space_info(root->fs_info, - BTRFS_BLOCK_GROUP_METADATA); - ret = btrfs_block_rsv_add(root, rsv, num_bytes, - BTRFS_RESERVE_FLUSH_ALL); - - if (ret == -ENOSPC && use_global_rsv) - ret = btrfs_block_rsv_migrate(global_rsv, rsv, num_bytes, 1); - - if (ret && *qgroup_reserved) - btrfs_qgroup_free_meta(root, *qgroup_reserved); - - return ret; -} - -void btrfs_subvolume_release_metadata(struct btrfs_root *root, - struct btrfs_block_rsv *rsv, - u64 qgroup_reserved) -{ - btrfs_block_rsv_release(root, rsv, (u64)-1); -} - -/** - * drop_outstanding_extent - drop an outstanding extent - * @inode: the inode we're dropping the extent for - * @num_bytes: the number of bytes we're releasing. - * - * This is called when we are freeing up an outstanding extent, either called - * after an error or after an extent is written. This will return the number of - * reserved extents that need to be freed. This must be called with - * BTRFS_I(inode)->lock held. - */ -static unsigned drop_outstanding_extent(struct inode *inode, u64 num_bytes) -{ - unsigned drop_inode_space = 0; - unsigned dropped_extents = 0; - unsigned num_extents = 0; - - num_extents = (unsigned)div64_u64(num_bytes + - BTRFS_MAX_EXTENT_SIZE - 1, - BTRFS_MAX_EXTENT_SIZE); - ASSERT(num_extents); - ASSERT(BTRFS_I(inode)->outstanding_extents >= num_extents); - BTRFS_I(inode)->outstanding_extents -= num_extents; - - if (BTRFS_I(inode)->outstanding_extents == 0 && - test_and_clear_bit(BTRFS_INODE_DELALLOC_META_RESERVED, - &BTRFS_I(inode)->runtime_flags)) - drop_inode_space = 1; - - /* - * If we have more or the same amount of outstanding extents than we have - * reserved then we need to leave the reserved extents count alone. - */ - if (BTRFS_I(inode)->outstanding_extents >= - BTRFS_I(inode)->reserved_extents) - return drop_inode_space; - - dropped_extents = BTRFS_I(inode)->reserved_extents - - BTRFS_I(inode)->outstanding_extents; - BTRFS_I(inode)->reserved_extents -= dropped_extents; - return dropped_extents + drop_inode_space; -} - -/** - * calc_csum_metadata_size - return the amount of metadata space that must be - * reserved/freed for the given bytes. - * @inode: the inode we're manipulating - * @num_bytes: the number of bytes in question - * @reserve: 1 if we are reserving space, 0 if we are freeing space - * - * This adjusts the number of csum_bytes in the inode and then returns the - * correct amount of metadata that must either be reserved or freed. We - * calculate how many checksums we can fit into one leaf and then divide the - * number of bytes that will need to be checksumed by this value to figure out - * how many checksums will be required. If we are adding bytes then the number - * may go up and we will return the number of additional bytes that must be - * reserved. If it is going down we will return the number of bytes that must - * be freed. - * - * This must be called with BTRFS_I(inode)->lock held. - */ -static u64 calc_csum_metadata_size(struct inode *inode, u64 num_bytes, - int reserve) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - u64 old_csums, num_csums; - - if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM && - BTRFS_I(inode)->csum_bytes == 0) - return 0; - - old_csums = btrfs_csum_bytes_to_leaves(root, BTRFS_I(inode)->csum_bytes); - if (reserve) - BTRFS_I(inode)->csum_bytes += num_bytes; - else - BTRFS_I(inode)->csum_bytes -= num_bytes; - num_csums = btrfs_csum_bytes_to_leaves(root, BTRFS_I(inode)->csum_bytes); - - /* No change, no need to reserve more */ - if (old_csums == num_csums) - return 0; - - if (reserve) - return btrfs_calc_trans_metadata_size(root, - num_csums - old_csums); - - return btrfs_calc_trans_metadata_size(root, old_csums - num_csums); -} - -int btrfs_delalloc_reserve_metadata(struct inode *inode, u64 num_bytes) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_block_rsv *block_rsv = &root->fs_info->delalloc_block_rsv; - u64 to_reserve = 0; - u64 csum_bytes; - unsigned nr_extents = 0; - enum btrfs_reserve_flush_enum flush = BTRFS_RESERVE_FLUSH_ALL; - int ret = 0; - bool delalloc_lock = true; - u64 to_free = 0; - unsigned dropped; - bool release_extra = false; - - /* If we are a free space inode we need to not flush since we will be in - * the middle of a transaction commit. We also don't need the delalloc - * mutex since we won't race with anybody. We need this mostly to make - * lockdep shut its filthy mouth. - * - * If we have a transaction open (can happen if we call truncate_block - * from truncate), then we need FLUSH_LIMIT so we don't deadlock. - */ - if (btrfs_is_free_space_inode(inode)) { - flush = BTRFS_RESERVE_NO_FLUSH; - delalloc_lock = false; - } else if (current->journal_info) { - flush = BTRFS_RESERVE_FLUSH_LIMIT; - } - - if (flush != BTRFS_RESERVE_NO_FLUSH && - btrfs_transaction_in_commit(root->fs_info)) - schedule_timeout(1); - - if (delalloc_lock) - mutex_lock(&BTRFS_I(inode)->delalloc_mutex); - - num_bytes = ALIGN(num_bytes, root->sectorsize); - - spin_lock(&BTRFS_I(inode)->lock); - nr_extents = (unsigned)div64_u64(num_bytes + - BTRFS_MAX_EXTENT_SIZE - 1, - BTRFS_MAX_EXTENT_SIZE); - BTRFS_I(inode)->outstanding_extents += nr_extents; - - nr_extents = 0; - if (BTRFS_I(inode)->outstanding_extents > - BTRFS_I(inode)->reserved_extents) - nr_extents += BTRFS_I(inode)->outstanding_extents - - BTRFS_I(inode)->reserved_extents; - - /* We always want to reserve a slot for updating the inode. */ - to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents + 1); - to_reserve += calc_csum_metadata_size(inode, num_bytes, 1); - csum_bytes = BTRFS_I(inode)->csum_bytes; - spin_unlock(&BTRFS_I(inode)->lock); - - if (test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags)) { - ret = btrfs_qgroup_reserve_meta(root, - nr_extents * root->nodesize); - if (ret) - goto out_fail; - } - - ret = btrfs_block_rsv_add(root, block_rsv, to_reserve, flush); - if (unlikely(ret)) { - btrfs_qgroup_free_meta(root, nr_extents * root->nodesize); - goto out_fail; - } - - spin_lock(&BTRFS_I(inode)->lock); - if (test_and_set_bit(BTRFS_INODE_DELALLOC_META_RESERVED, - &BTRFS_I(inode)->runtime_flags)) { - to_reserve -= btrfs_calc_trans_metadata_size(root, 1); - release_extra = true; - } - BTRFS_I(inode)->reserved_extents += nr_extents; - spin_unlock(&BTRFS_I(inode)->lock); - - if (delalloc_lock) - mutex_unlock(&BTRFS_I(inode)->delalloc_mutex); - - if (to_reserve) - trace_btrfs_space_reservation(root->fs_info, "delalloc", - btrfs_ino(inode), to_reserve, 1); - if (release_extra) - btrfs_block_rsv_release(root, block_rsv, - btrfs_calc_trans_metadata_size(root, - 1)); - return 0; - -out_fail: - spin_lock(&BTRFS_I(inode)->lock); - dropped = drop_outstanding_extent(inode, num_bytes); - /* - * If the inodes csum_bytes is the same as the original - * csum_bytes then we know we haven't raced with any free()ers - * so we can just reduce our inodes csum bytes and carry on. - */ - if (BTRFS_I(inode)->csum_bytes == csum_bytes) { - calc_csum_metadata_size(inode, num_bytes, 0); - } else { - u64 orig_csum_bytes = BTRFS_I(inode)->csum_bytes; - u64 bytes; - - /* - * This is tricky, but first we need to figure out how much we - * freed from any free-ers that occurred during this - * reservation, so we reset ->csum_bytes to the csum_bytes - * before we dropped our lock, and then call the free for the - * number of bytes that were freed while we were trying our - * reservation. - */ - bytes = csum_bytes - BTRFS_I(inode)->csum_bytes; - BTRFS_I(inode)->csum_bytes = csum_bytes; - to_free = calc_csum_metadata_size(inode, bytes, 0); - - - /* - * Now we need to see how much we would have freed had we not - * been making this reservation and our ->csum_bytes were not - * artificially inflated. - */ - BTRFS_I(inode)->csum_bytes = csum_bytes - num_bytes; - bytes = csum_bytes - orig_csum_bytes; - bytes = calc_csum_metadata_size(inode, bytes, 0); - - /* - * Now reset ->csum_bytes to what it should be. If bytes is - * more than to_free then we would have freed more space had we - * not had an artificially high ->csum_bytes, so we need to free - * the remainder. If bytes is the same or less then we don't - * need to do anything, the other free-ers did the correct - * thing. - */ - BTRFS_I(inode)->csum_bytes = orig_csum_bytes - num_bytes; - if (bytes > to_free) - to_free = bytes - to_free; - else - to_free = 0; - } - spin_unlock(&BTRFS_I(inode)->lock); - if (dropped) - to_free += btrfs_calc_trans_metadata_size(root, dropped); - - if (to_free) { - btrfs_block_rsv_release(root, block_rsv, to_free); - trace_btrfs_space_reservation(root->fs_info, "delalloc", - btrfs_ino(inode), to_free, 0); - } - if (delalloc_lock) - mutex_unlock(&BTRFS_I(inode)->delalloc_mutex); - return ret; -} - -/** - * btrfs_delalloc_release_metadata - release a metadata reservation for an inode - * @inode: the inode to release the reservation for - * @num_bytes: the number of bytes we're releasing - * - * This will release the metadata reservation for an inode. This can be called - * once we complete IO for a given set of bytes to release their metadata - * reservations. - */ -void btrfs_delalloc_release_metadata(struct inode *inode, u64 num_bytes) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - u64 to_free = 0; - unsigned dropped; - - num_bytes = ALIGN(num_bytes, root->sectorsize); - spin_lock(&BTRFS_I(inode)->lock); - dropped = drop_outstanding_extent(inode, num_bytes); - - if (num_bytes) - to_free = calc_csum_metadata_size(inode, num_bytes, 0); - spin_unlock(&BTRFS_I(inode)->lock); - if (dropped > 0) - to_free += btrfs_calc_trans_metadata_size(root, dropped); - - if (btrfs_is_testing(root->fs_info)) - return; - - trace_btrfs_space_reservation(root->fs_info, "delalloc", - btrfs_ino(inode), to_free, 0); - - btrfs_block_rsv_release(root, &root->fs_info->delalloc_block_rsv, - to_free); -} - -/** - * btrfs_delalloc_reserve_space - reserve data and metadata space for - * delalloc - * @inode: inode we're writing to - * @start: start range we are writing to - * @len: how long the range we are writing to - * - * This will do the following things - * - * o reserve space in data space info for num bytes - * and reserve precious corresponding qgroup space - * (Done in check_data_free_space) - * - * o reserve space for metadata space, based on the number of outstanding - * extents and how much csums will be needed - * also reserve metadata space in a per root over-reserve method. - * o add to the inodes->delalloc_bytes - * o add it to the fs_info's delalloc inodes list. - * (Above 3 all done in delalloc_reserve_metadata) - * - * Return 0 for success - * Return <0 for error(-ENOSPC or -EQUOT) - */ -int btrfs_delalloc_reserve_space(struct inode *inode, u64 start, u64 len) -{ - int ret; - - ret = btrfs_check_data_free_space(inode, start, len); - if (ret < 0) - return ret; - ret = btrfs_delalloc_reserve_metadata(inode, len); - if (ret < 0) - btrfs_free_reserved_data_space(inode, start, len); - return ret; -} - -/** - * btrfs_delalloc_release_space - release data and metadata space for delalloc - * @inode: inode we're releasing space for - * @start: start position of the space already reserved - * @len: the len of the space already reserved - * - * This must be matched with a call to btrfs_delalloc_reserve_space. This is - * called in the case that we don't need the metadata AND data reservations - * anymore. So if there is an error or we insert an inline extent. - * - * This function will release the metadata space that was not used and will - * decrement ->delalloc_bytes and remove it from the fs_info delalloc_inodes - * list if there are no delalloc bytes left. - * Also it will handle the qgroup reserved space. - */ -void btrfs_delalloc_release_space(struct inode *inode, u64 start, u64 len) -{ - btrfs_delalloc_release_metadata(inode, len); - btrfs_free_reserved_data_space(inode, start, len); -} - -static int update_block_group(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 bytenr, - u64 num_bytes, int alloc) -{ - struct btrfs_block_group_cache *cache = NULL; - struct btrfs_fs_info *info = root->fs_info; - u64 total = num_bytes; - u64 old_val; - u64 byte_in_group; - int factor; - - /* block accounting for super block */ - spin_lock(&info->delalloc_root_lock); - old_val = btrfs_super_bytes_used(info->super_copy); - if (alloc) - old_val += num_bytes; - else - old_val -= num_bytes; - btrfs_set_super_bytes_used(info->super_copy, old_val); - spin_unlock(&info->delalloc_root_lock); - - while (total) { - cache = btrfs_lookup_block_group(info, bytenr); - if (!cache) - return -ENOENT; - if (cache->flags & (BTRFS_BLOCK_GROUP_DUP | - BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID10)) - factor = 2; - else - factor = 1; - /* - * If this block group has free space cache written out, we - * need to make sure to load it if we are removing space. This - * is because we need the unpinning stage to actually add the - * space back to the block group, otherwise we will leak space. - */ - if (!alloc && cache->cached == BTRFS_CACHE_NO) - cache_block_group(cache, 1); - - byte_in_group = bytenr - cache->key.objectid; - WARN_ON(byte_in_group > cache->key.offset); - - spin_lock(&cache->space_info->lock); - spin_lock(&cache->lock); - - if (btrfs_test_opt(root->fs_info, SPACE_CACHE) && - cache->disk_cache_state < BTRFS_DC_CLEAR) - cache->disk_cache_state = BTRFS_DC_CLEAR; - - old_val = btrfs_block_group_used(&cache->item); - num_bytes = min(total, cache->key.offset - byte_in_group); - if (alloc) { - old_val += num_bytes; - btrfs_set_block_group_used(&cache->item, old_val); - cache->reserved -= num_bytes; - cache->space_info->bytes_reserved -= num_bytes; - cache->space_info->bytes_used += num_bytes; - cache->space_info->disk_used += num_bytes * factor; - spin_unlock(&cache->lock); - spin_unlock(&cache->space_info->lock); - } else { - old_val -= num_bytes; - btrfs_set_block_group_used(&cache->item, old_val); - cache->pinned += num_bytes; - cache->space_info->bytes_pinned += num_bytes; - cache->space_info->bytes_used -= num_bytes; - cache->space_info->disk_used -= num_bytes * factor; - spin_unlock(&cache->lock); - spin_unlock(&cache->space_info->lock); - - trace_btrfs_space_reservation(root->fs_info, "pinned", - cache->space_info->flags, - num_bytes, 1); - set_extent_dirty(info->pinned_extents, - bytenr, bytenr + num_bytes - 1, - GFP_NOFS | __GFP_NOFAIL); - } - - spin_lock(&trans->transaction->dirty_bgs_lock); - if (list_empty(&cache->dirty_list)) { - list_add_tail(&cache->dirty_list, - &trans->transaction->dirty_bgs); - trans->transaction->num_dirty_bgs++; - btrfs_get_block_group(cache); - } - spin_unlock(&trans->transaction->dirty_bgs_lock); - - /* - * No longer have used bytes in this block group, queue it for - * deletion. We do this after adding the block group to the - * dirty list to avoid races between cleaner kthread and space - * cache writeout. - */ - if (!alloc && old_val == 0) { - spin_lock(&info->unused_bgs_lock); - if (list_empty(&cache->bg_list)) { - btrfs_get_block_group(cache); - list_add_tail(&cache->bg_list, - &info->unused_bgs); - } - spin_unlock(&info->unused_bgs_lock); - } - - btrfs_put_block_group(cache); - total -= num_bytes; - bytenr += num_bytes; - } - return 0; -} - -static u64 first_logical_byte(struct btrfs_root *root, u64 search_start) -{ - struct btrfs_block_group_cache *cache; - u64 bytenr; - - spin_lock(&root->fs_info->block_group_cache_lock); - bytenr = root->fs_info->first_logical_byte; - spin_unlock(&root->fs_info->block_group_cache_lock); - - if (bytenr < (u64)-1) - return bytenr; - - cache = btrfs_lookup_first_block_group(root->fs_info, search_start); - if (!cache) - return 0; - - bytenr = cache->key.objectid; - btrfs_put_block_group(cache); - - return bytenr; -} - -static int pin_down_extent(struct btrfs_root *root, - struct btrfs_block_group_cache *cache, - u64 bytenr, u64 num_bytes, int reserved) -{ - spin_lock(&cache->space_info->lock); - spin_lock(&cache->lock); - cache->pinned += num_bytes; - cache->space_info->bytes_pinned += num_bytes; - if (reserved) { - cache->reserved -= num_bytes; - cache->space_info->bytes_reserved -= num_bytes; - } - spin_unlock(&cache->lock); - spin_unlock(&cache->space_info->lock); - - trace_btrfs_space_reservation(root->fs_info, "pinned", - cache->space_info->flags, num_bytes, 1); - set_extent_dirty(root->fs_info->pinned_extents, bytenr, - bytenr + num_bytes - 1, GFP_NOFS | __GFP_NOFAIL); - return 0; -} - -/* - * this function must be called within transaction - */ -int btrfs_pin_extent(struct btrfs_root *root, - u64 bytenr, u64 num_bytes, int reserved) -{ - struct btrfs_block_group_cache *cache; - - cache = btrfs_lookup_block_group(root->fs_info, bytenr); - BUG_ON(!cache); /* Logic error */ - - pin_down_extent(root, cache, bytenr, num_bytes, reserved); - - btrfs_put_block_group(cache); - return 0; -} - -/* - * this function must be called within transaction - */ -int btrfs_pin_extent_for_log_replay(struct btrfs_root *root, - u64 bytenr, u64 num_bytes) -{ - struct btrfs_block_group_cache *cache; - int ret; - - cache = btrfs_lookup_block_group(root->fs_info, bytenr); - if (!cache) - return -EINVAL; - - /* - * pull in the free space cache (if any) so that our pin - * removes the free space from the cache. We have load_only set - * to one because the slow code to read in the free extents does check - * the pinned extents. - */ - cache_block_group(cache, 1); - - pin_down_extent(root, cache, bytenr, num_bytes, 0); - - /* remove us from the free space cache (if we're there at all) */ - ret = btrfs_remove_free_space(cache, bytenr, num_bytes); - btrfs_put_block_group(cache); - return ret; -} - -static int __exclude_logged_extent(struct btrfs_root *root, u64 start, u64 num_bytes) -{ - int ret; - struct btrfs_block_group_cache *block_group; - struct btrfs_caching_control *caching_ctl; - - block_group = btrfs_lookup_block_group(root->fs_info, start); - if (!block_group) - return -EINVAL; - - cache_block_group(block_group, 0); - caching_ctl = get_caching_control(block_group); - - if (!caching_ctl) { - /* Logic error */ - BUG_ON(!block_group_cache_done(block_group)); - ret = btrfs_remove_free_space(block_group, start, num_bytes); - } else { - mutex_lock(&caching_ctl->mutex); - - if (start >= caching_ctl->progress) { - ret = add_excluded_extent(root, start, num_bytes); - } else if (start + num_bytes <= caching_ctl->progress) { - ret = btrfs_remove_free_space(block_group, - start, num_bytes); - } else { - num_bytes = caching_ctl->progress - start; - ret = btrfs_remove_free_space(block_group, - start, num_bytes); - if (ret) - goto out_lock; - - num_bytes = (start + num_bytes) - - caching_ctl->progress; - start = caching_ctl->progress; - ret = add_excluded_extent(root, start, num_bytes); - } -out_lock: - mutex_unlock(&caching_ctl->mutex); - put_caching_control(caching_ctl); - } - btrfs_put_block_group(block_group); - return ret; -} - -int btrfs_exclude_logged_extents(struct btrfs_root *log, - struct extent_buffer *eb) -{ - struct btrfs_file_extent_item *item; - struct btrfs_key key; - int found_type; - int i; - - if (!btrfs_fs_incompat(log->fs_info, MIXED_GROUPS)) - return 0; - - for (i = 0; i < btrfs_header_nritems(eb); i++) { - btrfs_item_key_to_cpu(eb, &key, i); - if (key.type != BTRFS_EXTENT_DATA_KEY) - continue; - item = btrfs_item_ptr(eb, i, struct btrfs_file_extent_item); - found_type = btrfs_file_extent_type(eb, item); - if (found_type == BTRFS_FILE_EXTENT_INLINE) - continue; - if (btrfs_file_extent_disk_bytenr(eb, item) == 0) - continue; - key.objectid = btrfs_file_extent_disk_bytenr(eb, item); - key.offset = btrfs_file_extent_disk_num_bytes(eb, item); - __exclude_logged_extent(log, key.objectid, key.offset); - } - - return 0; -} - -static void -btrfs_inc_block_group_reservations(struct btrfs_block_group_cache *bg) -{ - atomic_inc(&bg->reservations); -} - -void btrfs_dec_block_group_reservations(struct btrfs_fs_info *fs_info, - const u64 start) -{ - struct btrfs_block_group_cache *bg; - - bg = btrfs_lookup_block_group(fs_info, start); - ASSERT(bg); - if (atomic_dec_and_test(&bg->reservations)) - wake_up_atomic_t(&bg->reservations); - btrfs_put_block_group(bg); -} - -static int btrfs_wait_bg_reservations_atomic_t(atomic_t *a) -{ - schedule(); - return 0; -} - -void btrfs_wait_block_group_reservations(struct btrfs_block_group_cache *bg) -{ - struct btrfs_space_info *space_info = bg->space_info; - - ASSERT(bg->ro); - - if (!(bg->flags & BTRFS_BLOCK_GROUP_DATA)) - return; - - /* - * Our block group is read only but before we set it to read only, - * some task might have had allocated an extent from it already, but it - * has not yet created a respective ordered extent (and added it to a - * root's list of ordered extents). - * Therefore wait for any task currently allocating extents, since the - * block group's reservations counter is incremented while a read lock - * on the groups' semaphore is held and decremented after releasing - * the read access on that semaphore and creating the ordered extent. - */ - down_write(&space_info->groups_sem); - up_write(&space_info->groups_sem); - - wait_on_atomic_t(&bg->reservations, - btrfs_wait_bg_reservations_atomic_t, - TASK_UNINTERRUPTIBLE); -} - -/** - * btrfs_add_reserved_bytes - update the block_group and space info counters - * @cache: The cache we are manipulating - * @ram_bytes: The number of bytes of file content, and will be same to - * @num_bytes except for the compress path. - * @num_bytes: The number of bytes in question - * @delalloc: The blocks are allocated for the delalloc write - * - * This is called by the allocator when it reserves space. Metadata - * reservations should be called with RESERVE_ALLOC so we do the proper - * ENOSPC accounting. For data we handle the reservation through clearing the - * delalloc bits in the io_tree. We have to do this since we could end up - * allocating less disk space for the amount of data we have reserved in the - * case of compression. - * - * If this is a reservation and the block group has become read only we cannot - * make the reservation and return -EAGAIN, otherwise this function always - * succeeds. - */ -static int btrfs_add_reserved_bytes(struct btrfs_block_group_cache *cache, - u64 ram_bytes, u64 num_bytes, int delalloc) -{ - struct btrfs_space_info *space_info = cache->space_info; - int ret = 0; - - spin_lock(&space_info->lock); - spin_lock(&cache->lock); - if (cache->ro) { - ret = -EAGAIN; - } else { - cache->reserved += num_bytes; - space_info->bytes_reserved += num_bytes; - - trace_btrfs_space_reservation(cache->fs_info, - "space_info", space_info->flags, - ram_bytes, 0); - space_info->bytes_may_use -= ram_bytes; - if (delalloc) - cache->delalloc_bytes += num_bytes; - } - spin_unlock(&cache->lock); - spin_unlock(&space_info->lock); - return ret; -} - -/** - * btrfs_free_reserved_bytes - update the block_group and space info counters - * @cache: The cache we are manipulating - * @num_bytes: The number of bytes in question - * @delalloc: The blocks are allocated for the delalloc write - * - * This is called by somebody who is freeing space that was never actually used - * on disk. For example if you reserve some space for a new leaf in transaction - * A and before transaction A commits you free that leaf, you call this with - * reserve set to 0 in order to clear the reservation. - */ - -static int btrfs_free_reserved_bytes(struct btrfs_block_group_cache *cache, - u64 num_bytes, int delalloc) -{ - struct btrfs_space_info *space_info = cache->space_info; - int ret = 0; - - spin_lock(&space_info->lock); - spin_lock(&cache->lock); - if (cache->ro) - space_info->bytes_readonly += num_bytes; - cache->reserved -= num_bytes; - space_info->bytes_reserved -= num_bytes; - - if (delalloc) - cache->delalloc_bytes -= num_bytes; - spin_unlock(&cache->lock); - spin_unlock(&space_info->lock); - return ret; -} -void btrfs_prepare_extent_commit(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_caching_control *next; - struct btrfs_caching_control *caching_ctl; - struct btrfs_block_group_cache *cache; - - down_write(&fs_info->commit_root_sem); - - list_for_each_entry_safe(caching_ctl, next, - &fs_info->caching_block_groups, list) { - cache = caching_ctl->block_group; - if (block_group_cache_done(cache)) { - cache->last_byte_to_unpin = (u64)-1; - list_del_init(&caching_ctl->list); - put_caching_control(caching_ctl); - } else { - cache->last_byte_to_unpin = caching_ctl->progress; - } - } - - if (fs_info->pinned_extents == &fs_info->freed_extents[0]) - fs_info->pinned_extents = &fs_info->freed_extents[1]; - else - fs_info->pinned_extents = &fs_info->freed_extents[0]; - - up_write(&fs_info->commit_root_sem); - - update_global_block_rsv(fs_info); -} - -/* - * Returns the free cluster for the given space info and sets empty_cluster to - * what it should be based on the mount options. - */ -static struct btrfs_free_cluster * -fetch_cluster_info(struct btrfs_root *root, struct btrfs_space_info *space_info, - u64 *empty_cluster) -{ - struct btrfs_free_cluster *ret = NULL; - bool ssd = btrfs_test_opt(root->fs_info, SSD); - - *empty_cluster = 0; - if (btrfs_mixed_space_info(space_info)) - return ret; - - if (ssd) - *empty_cluster = SZ_2M; - if (space_info->flags & BTRFS_BLOCK_GROUP_METADATA) { - ret = &root->fs_info->meta_alloc_cluster; - if (!ssd) - *empty_cluster = SZ_64K; - } else if ((space_info->flags & BTRFS_BLOCK_GROUP_DATA) && ssd) { - ret = &root->fs_info->data_alloc_cluster; - } - - return ret; -} - -static int unpin_extent_range(struct btrfs_root *root, u64 start, u64 end, - const bool return_free_space) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_block_group_cache *cache = NULL; - struct btrfs_space_info *space_info; - struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv; - struct btrfs_free_cluster *cluster = NULL; - u64 len; - u64 total_unpinned = 0; - u64 empty_cluster = 0; - bool readonly; - - while (start <= end) { - readonly = false; - if (!cache || - start >= cache->key.objectid + cache->key.offset) { - if (cache) - btrfs_put_block_group(cache); - total_unpinned = 0; - cache = btrfs_lookup_block_group(fs_info, start); - BUG_ON(!cache); /* Logic error */ - - cluster = fetch_cluster_info(root, - cache->space_info, - &empty_cluster); - empty_cluster <<= 1; - } - - len = cache->key.objectid + cache->key.offset - start; - len = min(len, end + 1 - start); - - if (start < cache->last_byte_to_unpin) { - len = min(len, cache->last_byte_to_unpin - start); - if (return_free_space) - btrfs_add_free_space(cache, start, len); - } - - start += len; - total_unpinned += len; - space_info = cache->space_info; - - /* - * If this space cluster has been marked as fragmented and we've - * unpinned enough in this block group to potentially allow a - * cluster to be created inside of it go ahead and clear the - * fragmented check. - */ - if (cluster && cluster->fragmented && - total_unpinned > empty_cluster) { - spin_lock(&cluster->lock); - cluster->fragmented = 0; - spin_unlock(&cluster->lock); - } - - spin_lock(&space_info->lock); - spin_lock(&cache->lock); - cache->pinned -= len; - space_info->bytes_pinned -= len; - - trace_btrfs_space_reservation(fs_info, "pinned", - space_info->flags, len, 0); - space_info->max_extent_size = 0; - percpu_counter_add(&space_info->total_bytes_pinned, -len); - if (cache->ro) { - space_info->bytes_readonly += len; - readonly = true; - } - spin_unlock(&cache->lock); - if (!readonly && return_free_space && - global_rsv->space_info == space_info) { - u64 to_add = len; - WARN_ON(!return_free_space); - spin_lock(&global_rsv->lock); - if (!global_rsv->full) { - to_add = min(len, global_rsv->size - - global_rsv->reserved); - global_rsv->reserved += to_add; - space_info->bytes_may_use += to_add; - if (global_rsv->reserved >= global_rsv->size) - global_rsv->full = 1; - trace_btrfs_space_reservation(fs_info, - "space_info", - space_info->flags, - to_add, 1); - len -= to_add; - } - spin_unlock(&global_rsv->lock); - /* Add to any tickets we may have */ - if (len) - space_info_add_new_bytes(fs_info, space_info, - len); - } - spin_unlock(&space_info->lock); - } - - if (cache) - btrfs_put_block_group(cache); - return 0; -} - -int btrfs_finish_extent_commit(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_block_group_cache *block_group, *tmp; - struct list_head *deleted_bgs; - struct extent_io_tree *unpin; - u64 start; - u64 end; - int ret; - - if (fs_info->pinned_extents == &fs_info->freed_extents[0]) - unpin = &fs_info->freed_extents[1]; - else - unpin = &fs_info->freed_extents[0]; - - while (!trans->aborted) { - mutex_lock(&fs_info->unused_bg_unpin_mutex); - ret = find_first_extent_bit(unpin, 0, &start, &end, - EXTENT_DIRTY, NULL); - if (ret) { - mutex_unlock(&fs_info->unused_bg_unpin_mutex); - break; - } - - if (btrfs_test_opt(root->fs_info, DISCARD)) - ret = btrfs_discard_extent(root, start, - end + 1 - start, NULL); - - clear_extent_dirty(unpin, start, end); - unpin_extent_range(root, start, end, true); - mutex_unlock(&fs_info->unused_bg_unpin_mutex); - cond_resched(); - } - - /* - * Transaction is finished. We don't need the lock anymore. We - * do need to clean up the block groups in case of a transaction - * abort. - */ - deleted_bgs = &trans->transaction->deleted_bgs; - list_for_each_entry_safe(block_group, tmp, deleted_bgs, bg_list) { - u64 trimmed = 0; - - ret = -EROFS; - if (!trans->aborted) - ret = btrfs_discard_extent(root, - block_group->key.objectid, - block_group->key.offset, - &trimmed); - - list_del_init(&block_group->bg_list); - btrfs_put_block_group_trimming(block_group); - btrfs_put_block_group(block_group); - - if (ret) { - const char *errstr = btrfs_decode_error(ret); - btrfs_warn(fs_info, - "Discard failed while removing blockgroup: errno=%d %s\n", - ret, errstr); - } - } - - return 0; -} - -static void add_pinned_bytes(struct btrfs_fs_info *fs_info, u64 num_bytes, - u64 owner, u64 root_objectid) -{ - struct btrfs_space_info *space_info; - u64 flags; - - if (owner < BTRFS_FIRST_FREE_OBJECTID) { - if (root_objectid == BTRFS_CHUNK_TREE_OBJECTID) - flags = BTRFS_BLOCK_GROUP_SYSTEM; - else - flags = BTRFS_BLOCK_GROUP_METADATA; - } else { - flags = BTRFS_BLOCK_GROUP_DATA; - } - - space_info = __find_space_info(fs_info, flags); - BUG_ON(!space_info); /* Logic bug */ - percpu_counter_add(&space_info->total_bytes_pinned, num_bytes); -} - - -static int __btrfs_free_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_delayed_ref_node *node, u64 parent, - u64 root_objectid, u64 owner_objectid, - u64 owner_offset, int refs_to_drop, - struct btrfs_delayed_extent_op *extent_op) -{ - struct btrfs_key key; - struct btrfs_path *path; - struct btrfs_fs_info *info = root->fs_info; - struct btrfs_root *extent_root = info->extent_root; - struct extent_buffer *leaf; - struct btrfs_extent_item *ei; - struct btrfs_extent_inline_ref *iref; - int ret; - int is_data; - int extent_slot = 0; - int found_extent = 0; - int num_to_del = 1; - u32 item_size; - u64 refs; - u64 bytenr = node->bytenr; - u64 num_bytes = node->num_bytes; - int last_ref = 0; - bool skinny_metadata = btrfs_fs_incompat(root->fs_info, - SKINNY_METADATA); - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - path->reada = READA_FORWARD; - path->leave_spinning = 1; - - is_data = owner_objectid >= BTRFS_FIRST_FREE_OBJECTID; - BUG_ON(!is_data && refs_to_drop != 1); - - if (is_data) - skinny_metadata = 0; - - ret = lookup_extent_backref(trans, extent_root, path, &iref, - bytenr, num_bytes, parent, - root_objectid, owner_objectid, - owner_offset); - if (ret == 0) { - extent_slot = path->slots[0]; - while (extent_slot >= 0) { - btrfs_item_key_to_cpu(path->nodes[0], &key, - extent_slot); - if (key.objectid != bytenr) - break; - if (key.type == BTRFS_EXTENT_ITEM_KEY && - key.offset == num_bytes) { - found_extent = 1; - break; - } - if (key.type == BTRFS_METADATA_ITEM_KEY && - key.offset == owner_objectid) { - found_extent = 1; - break; - } - if (path->slots[0] - extent_slot > 5) - break; - extent_slot--; - } -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - item_size = btrfs_item_size_nr(path->nodes[0], extent_slot); - if (found_extent && item_size < sizeof(*ei)) - found_extent = 0; -#endif - if (!found_extent) { - BUG_ON(iref); - ret = remove_extent_backref(trans, extent_root, path, - NULL, refs_to_drop, - is_data, &last_ref); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out; - } - btrfs_release_path(path); - path->leave_spinning = 1; - - key.objectid = bytenr; - key.type = BTRFS_EXTENT_ITEM_KEY; - key.offset = num_bytes; - - if (!is_data && skinny_metadata) { - key.type = BTRFS_METADATA_ITEM_KEY; - key.offset = owner_objectid; - } - - ret = btrfs_search_slot(trans, extent_root, - &key, path, -1, 1); - if (ret > 0 && skinny_metadata && path->slots[0]) { - /* - * Couldn't find our skinny metadata item, - * see if we have ye olde extent item. - */ - path->slots[0]--; - btrfs_item_key_to_cpu(path->nodes[0], &key, - path->slots[0]); - if (key.objectid == bytenr && - key.type == BTRFS_EXTENT_ITEM_KEY && - key.offset == num_bytes) - ret = 0; - } - - if (ret > 0 && skinny_metadata) { - skinny_metadata = false; - key.objectid = bytenr; - key.type = BTRFS_EXTENT_ITEM_KEY; - key.offset = num_bytes; - btrfs_release_path(path); - ret = btrfs_search_slot(trans, extent_root, - &key, path, -1, 1); - } - - if (ret) { - btrfs_err(info, - "umm, got %d back from search, was looking for %llu", - ret, bytenr); - if (ret > 0) - btrfs_print_leaf(extent_root, - path->nodes[0]); - } - if (ret < 0) { - btrfs_abort_transaction(trans, ret); - goto out; - } - extent_slot = path->slots[0]; - } - } else if (WARN_ON(ret == -ENOENT)) { - btrfs_print_leaf(extent_root, path->nodes[0]); - btrfs_err(info, - "unable to find ref byte nr %llu parent %llu root %llu owner %llu offset %llu", - bytenr, parent, root_objectid, owner_objectid, - owner_offset); - btrfs_abort_transaction(trans, ret); - goto out; - } else { - btrfs_abort_transaction(trans, ret); - goto out; - } - - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, extent_slot); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (item_size < sizeof(*ei)) { - BUG_ON(found_extent || extent_slot != path->slots[0]); - ret = convert_extent_item_v0(trans, extent_root, path, - owner_objectid, 0); - if (ret < 0) { - btrfs_abort_transaction(trans, ret); - goto out; - } - - btrfs_release_path(path); - path->leave_spinning = 1; - - key.objectid = bytenr; - key.type = BTRFS_EXTENT_ITEM_KEY; - key.offset = num_bytes; - - ret = btrfs_search_slot(trans, extent_root, &key, path, - -1, 1); - if (ret) { - btrfs_err(info, - "umm, got %d back from search, was looking for %llu", - ret, bytenr); - btrfs_print_leaf(extent_root, path->nodes[0]); - } - if (ret < 0) { - btrfs_abort_transaction(trans, ret); - goto out; - } - - extent_slot = path->slots[0]; - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, extent_slot); - } -#endif - BUG_ON(item_size < sizeof(*ei)); - ei = btrfs_item_ptr(leaf, extent_slot, - struct btrfs_extent_item); - if (owner_objectid < BTRFS_FIRST_FREE_OBJECTID && - key.type == BTRFS_EXTENT_ITEM_KEY) { - struct btrfs_tree_block_info *bi; - BUG_ON(item_size < sizeof(*ei) + sizeof(*bi)); - bi = (struct btrfs_tree_block_info *)(ei + 1); - WARN_ON(owner_objectid != btrfs_tree_block_level(leaf, bi)); - } - - refs = btrfs_extent_refs(leaf, ei); - if (refs < refs_to_drop) { - btrfs_err(info, - "trying to drop %d refs but we only have %Lu for bytenr %Lu", - refs_to_drop, refs, bytenr); - ret = -EINVAL; - btrfs_abort_transaction(trans, ret); - goto out; - } - refs -= refs_to_drop; - - if (refs > 0) { - if (extent_op) - __run_delayed_extent_op(extent_op, leaf, ei); - /* - * In the case of inline back ref, reference count will - * be updated by remove_extent_backref - */ - if (iref) { - BUG_ON(!found_extent); - } else { - btrfs_set_extent_refs(leaf, ei, refs); - btrfs_mark_buffer_dirty(leaf); - } - if (found_extent) { - ret = remove_extent_backref(trans, extent_root, path, - iref, refs_to_drop, - is_data, &last_ref); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out; - } - } - add_pinned_bytes(root->fs_info, -num_bytes, owner_objectid, - root_objectid); - } else { - if (found_extent) { - BUG_ON(is_data && refs_to_drop != - extent_data_ref_count(path, iref)); - if (iref) { - BUG_ON(path->slots[0] != extent_slot); - } else { - BUG_ON(path->slots[0] != extent_slot + 1); - path->slots[0] = extent_slot; - num_to_del = 2; - } - } - - last_ref = 1; - ret = btrfs_del_items(trans, extent_root, path, path->slots[0], - num_to_del); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out; - } - btrfs_release_path(path); - - if (is_data) { - ret = btrfs_del_csums(trans, root, bytenr, num_bytes); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out; - } - } - - ret = add_to_free_space_tree(trans, root->fs_info, bytenr, - num_bytes); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out; - } - - ret = update_block_group(trans, root, bytenr, num_bytes, 0); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out; - } - } - btrfs_release_path(path); - -out: - btrfs_free_path(path); - return ret; -} - -/* - * when we free an block, it is possible (and likely) that we free the last - * delayed ref for that extent as well. This searches the delayed ref tree for - * a given extent, and if there are no other delayed refs to be processed, it - * removes it from the tree. - */ -static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 bytenr) -{ - struct btrfs_delayed_ref_head *head; - struct btrfs_delayed_ref_root *delayed_refs; - int ret = 0; - - delayed_refs = &trans->transaction->delayed_refs; - spin_lock(&delayed_refs->lock); - head = btrfs_find_delayed_ref_head(trans, bytenr); - if (!head) - goto out_delayed_unlock; - - spin_lock(&head->lock); - if (!list_empty(&head->ref_list)) - goto out; - - if (head->extent_op) { - if (!head->must_insert_reserved) - goto out; - btrfs_free_delayed_extent_op(head->extent_op); - head->extent_op = NULL; - } - - /* - * waiting for the lock here would deadlock. If someone else has it - * locked they are already in the process of dropping it anyway - */ - if (!mutex_trylock(&head->mutex)) - goto out; - - /* - * at this point we have a head with no other entries. Go - * ahead and process it. - */ - head->node.in_tree = 0; - rb_erase(&head->href_node, &delayed_refs->href_root); - - atomic_dec(&delayed_refs->num_entries); - - /* - * we don't take a ref on the node because we're removing it from the - * tree, so we just steal the ref the tree was holding. - */ - delayed_refs->num_heads--; - if (head->processing == 0) - delayed_refs->num_heads_ready--; - head->processing = 0; - spin_unlock(&head->lock); - spin_unlock(&delayed_refs->lock); - - BUG_ON(head->extent_op); - if (head->must_insert_reserved) - ret = 1; - - mutex_unlock(&head->mutex); - btrfs_put_delayed_ref(&head->node); - return ret; -out: - spin_unlock(&head->lock); - -out_delayed_unlock: - spin_unlock(&delayed_refs->lock); - return 0; -} - -void btrfs_free_tree_block(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct extent_buffer *buf, - u64 parent, int last_ref) -{ - int pin = 1; - int ret; - - if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) { - ret = btrfs_add_delayed_tree_ref(root->fs_info, trans, - buf->start, buf->len, - parent, root->root_key.objectid, - btrfs_header_level(buf), - BTRFS_DROP_DELAYED_REF, NULL); - BUG_ON(ret); /* -ENOMEM */ - } - - if (!last_ref) - return; - - if (btrfs_header_generation(buf) == trans->transid) { - struct btrfs_block_group_cache *cache; - - if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) { - ret = check_ref_cleanup(trans, root, buf->start); - if (!ret) - goto out; - } - - cache = btrfs_lookup_block_group(root->fs_info, buf->start); - - if (btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) { - pin_down_extent(root, cache, buf->start, buf->len, 1); - btrfs_put_block_group(cache); - goto out; - } - - WARN_ON(test_bit(EXTENT_BUFFER_DIRTY, &buf->bflags)); - - btrfs_add_free_space(cache, buf->start, buf->len); - btrfs_free_reserved_bytes(cache, buf->len, 0); - btrfs_put_block_group(cache); - trace_btrfs_reserved_extent_free(root, buf->start, buf->len); - pin = 0; - } -out: - if (pin) - add_pinned_bytes(root->fs_info, buf->len, - btrfs_header_level(buf), - root->root_key.objectid); - - /* - * Deleting the buffer, clear the corrupt flag since it doesn't matter - * anymore. - */ - clear_bit(EXTENT_BUFFER_CORRUPT, &buf->bflags); -} - -/* Can return -ENOMEM */ -int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root, - u64 bytenr, u64 num_bytes, u64 parent, u64 root_objectid, - u64 owner, u64 offset) -{ - int ret; - struct btrfs_fs_info *fs_info = root->fs_info; - - if (btrfs_is_testing(fs_info)) - return 0; - - add_pinned_bytes(root->fs_info, num_bytes, owner, root_objectid); - - /* - * tree log blocks never actually go into the extent allocation - * tree, just update pinning info and exit early. - */ - if (root_objectid == BTRFS_TREE_LOG_OBJECTID) { - WARN_ON(owner >= BTRFS_FIRST_FREE_OBJECTID); - /* unlocks the pinned mutex */ - btrfs_pin_extent(root, bytenr, num_bytes, 1); - ret = 0; - } else if (owner < BTRFS_FIRST_FREE_OBJECTID) { - ret = btrfs_add_delayed_tree_ref(fs_info, trans, bytenr, - num_bytes, - parent, root_objectid, (int)owner, - BTRFS_DROP_DELAYED_REF, NULL); - } else { - ret = btrfs_add_delayed_data_ref(fs_info, trans, bytenr, - num_bytes, - parent, root_objectid, owner, - offset, 0, - BTRFS_DROP_DELAYED_REF, NULL); - } - return ret; -} - -/* - * when we wait for progress in the block group caching, its because - * our allocation attempt failed at least once. So, we must sleep - * and let some progress happen before we try again. - * - * This function will sleep at least once waiting for new free space to - * show up, and then it will check the block group free space numbers - * for our min num_bytes. Another option is to have it go ahead - * and look in the rbtree for a free extent of a given size, but this - * is a good start. - * - * Callers of this must check if cache->cached == BTRFS_CACHE_ERROR before using - * any of the information in this block group. - */ -static noinline void -wait_block_group_cache_progress(struct btrfs_block_group_cache *cache, - u64 num_bytes) -{ - struct btrfs_caching_control *caching_ctl; - - caching_ctl = get_caching_control(cache); - if (!caching_ctl) - return; - - wait_event(caching_ctl->wait, block_group_cache_done(cache) || - (cache->free_space_ctl->free_space >= num_bytes)); - - put_caching_control(caching_ctl); -} - -static noinline int -wait_block_group_cache_done(struct btrfs_block_group_cache *cache) -{ - struct btrfs_caching_control *caching_ctl; - int ret = 0; - - caching_ctl = get_caching_control(cache); - if (!caching_ctl) - return (cache->cached == BTRFS_CACHE_ERROR) ? -EIO : 0; - - wait_event(caching_ctl->wait, block_group_cache_done(cache)); - if (cache->cached == BTRFS_CACHE_ERROR) - ret = -EIO; - put_caching_control(caching_ctl); - return ret; -} - -int __get_raid_index(u64 flags) -{ - if (flags & BTRFS_BLOCK_GROUP_RAID10) - return BTRFS_RAID_RAID10; - else if (flags & BTRFS_BLOCK_GROUP_RAID1) - return BTRFS_RAID_RAID1; - else if (flags & BTRFS_BLOCK_GROUP_DUP) - return BTRFS_RAID_DUP; - else if (flags & BTRFS_BLOCK_GROUP_RAID0) - return BTRFS_RAID_RAID0; - else if (flags & BTRFS_BLOCK_GROUP_RAID5) - return BTRFS_RAID_RAID5; - else if (flags & BTRFS_BLOCK_GROUP_RAID6) - return BTRFS_RAID_RAID6; - - return BTRFS_RAID_SINGLE; /* BTRFS_BLOCK_GROUP_SINGLE */ -} - -int get_block_group_index(struct btrfs_block_group_cache *cache) -{ - return __get_raid_index(cache->flags); -} - -static const char *btrfs_raid_type_names[BTRFS_NR_RAID_TYPES] = { - [BTRFS_RAID_RAID10] = "raid10", - [BTRFS_RAID_RAID1] = "raid1", - [BTRFS_RAID_DUP] = "dup", - [BTRFS_RAID_RAID0] = "raid0", - [BTRFS_RAID_SINGLE] = "single", - [BTRFS_RAID_RAID5] = "raid5", - [BTRFS_RAID_RAID6] = "raid6", -}; - -static const char *get_raid_name(enum btrfs_raid_types type) -{ - if (type >= BTRFS_NR_RAID_TYPES) - return NULL; - - return btrfs_raid_type_names[type]; -} - -enum btrfs_loop_type { - LOOP_CACHING_NOWAIT = 0, - LOOP_CACHING_WAIT = 1, - LOOP_ALLOC_CHUNK = 2, - LOOP_NO_EMPTY_SIZE = 3, -}; - -static inline void -btrfs_lock_block_group(struct btrfs_block_group_cache *cache, - int delalloc) -{ - if (delalloc) - down_read(&cache->data_rwsem); -} - -static inline void -btrfs_grab_block_group(struct btrfs_block_group_cache *cache, - int delalloc) -{ - btrfs_get_block_group(cache); - if (delalloc) - down_read(&cache->data_rwsem); -} - -static struct btrfs_block_group_cache * -btrfs_lock_cluster(struct btrfs_block_group_cache *block_group, - struct btrfs_free_cluster *cluster, - int delalloc) -{ - struct btrfs_block_group_cache *used_bg = NULL; - - spin_lock(&cluster->refill_lock); - while (1) { - used_bg = cluster->block_group; - if (!used_bg) - return NULL; - - if (used_bg == block_group) - return used_bg; - - btrfs_get_block_group(used_bg); - - if (!delalloc) - return used_bg; - - if (down_read_trylock(&used_bg->data_rwsem)) - return used_bg; - - spin_unlock(&cluster->refill_lock); - - down_read(&used_bg->data_rwsem); - - spin_lock(&cluster->refill_lock); - if (used_bg == cluster->block_group) - return used_bg; - - up_read(&used_bg->data_rwsem); - btrfs_put_block_group(used_bg); - } -} - -static inline void -btrfs_release_block_group(struct btrfs_block_group_cache *cache, - int delalloc) -{ - if (delalloc) - up_read(&cache->data_rwsem); - btrfs_put_block_group(cache); -} - -/* - * walks the btree of allocated extents and find a hole of a given size. - * The key ins is changed to record the hole: - * ins->objectid == start position - * ins->flags = BTRFS_EXTENT_ITEM_KEY - * ins->offset == the size of the hole. - * Any available blocks before search_start are skipped. - * - * If there is no suitable free space, we will record the max size of - * the free space extent currently. - */ -static noinline int find_free_extent(struct btrfs_root *orig_root, - u64 ram_bytes, u64 num_bytes, u64 empty_size, - u64 hint_byte, struct btrfs_key *ins, - u64 flags, int delalloc) -{ - int ret = 0; - struct btrfs_root *root = orig_root->fs_info->extent_root; - struct btrfs_free_cluster *last_ptr = NULL; - struct btrfs_block_group_cache *block_group = NULL; - u64 search_start = 0; - u64 max_extent_size = 0; - u64 empty_cluster = 0; - struct btrfs_space_info *space_info; - int loop = 0; - int index = __get_raid_index(flags); - bool failed_cluster_refill = false; - bool failed_alloc = false; - bool use_cluster = true; - bool have_caching_bg = false; - bool orig_have_caching_bg = false; - bool full_search = false; - - WARN_ON(num_bytes < root->sectorsize); - ins->type = BTRFS_EXTENT_ITEM_KEY; - ins->objectid = 0; - ins->offset = 0; - - trace_find_free_extent(orig_root, num_bytes, empty_size, flags); - - space_info = __find_space_info(root->fs_info, flags); - if (!space_info) { - btrfs_err(root->fs_info, "No space info for %llu", flags); - return -ENOSPC; - } - - /* - * If our free space is heavily fragmented we may not be able to make - * big contiguous allocations, so instead of doing the expensive search - * for free space, simply return ENOSPC with our max_extent_size so we - * can go ahead and search for a more manageable chunk. - * - * If our max_extent_size is large enough for our allocation simply - * disable clustering since we will likely not be able to find enough - * space to create a cluster and induce latency trying. - */ - if (unlikely(space_info->max_extent_size)) { - spin_lock(&space_info->lock); - if (space_info->max_extent_size && - num_bytes > space_info->max_extent_size) { - ins->offset = space_info->max_extent_size; - spin_unlock(&space_info->lock); - return -ENOSPC; - } else if (space_info->max_extent_size) { - use_cluster = false; - } - spin_unlock(&space_info->lock); - } - - last_ptr = fetch_cluster_info(orig_root, space_info, &empty_cluster); - if (last_ptr) { - spin_lock(&last_ptr->lock); - if (last_ptr->block_group) - hint_byte = last_ptr->window_start; - if (last_ptr->fragmented) { - /* - * We still set window_start so we can keep track of the - * last place we found an allocation to try and save - * some time. - */ - hint_byte = last_ptr->window_start; - use_cluster = false; - } - spin_unlock(&last_ptr->lock); - } - - search_start = max(search_start, first_logical_byte(root, 0)); - search_start = max(search_start, hint_byte); - if (search_start == hint_byte) { - block_group = btrfs_lookup_block_group(root->fs_info, - search_start); - /* - * we don't want to use the block group if it doesn't match our - * allocation bits, or if its not cached. - * - * However if we are re-searching with an ideal block group - * picked out then we don't care that the block group is cached. - */ - if (block_group && block_group_bits(block_group, flags) && - block_group->cached != BTRFS_CACHE_NO) { - down_read(&space_info->groups_sem); - if (list_empty(&block_group->list) || - block_group->ro) { - /* - * someone is removing this block group, - * we can't jump into the have_block_group - * target because our list pointers are not - * valid - */ - btrfs_put_block_group(block_group); - up_read(&space_info->groups_sem); - } else { - index = get_block_group_index(block_group); - btrfs_lock_block_group(block_group, delalloc); - goto have_block_group; - } - } else if (block_group) { - btrfs_put_block_group(block_group); - } - } -search: - have_caching_bg = false; - if (index == 0 || index == __get_raid_index(flags)) - full_search = true; - down_read(&space_info->groups_sem); - list_for_each_entry(block_group, &space_info->block_groups[index], - list) { - u64 offset; - int cached; - - btrfs_grab_block_group(block_group, delalloc); - search_start = block_group->key.objectid; - - /* - * this can happen if we end up cycling through all the - * raid types, but we want to make sure we only allocate - * for the proper type. - */ - if (!block_group_bits(block_group, flags)) { - u64 extra = BTRFS_BLOCK_GROUP_DUP | - BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID5 | - BTRFS_BLOCK_GROUP_RAID6 | - BTRFS_BLOCK_GROUP_RAID10; - - /* - * if they asked for extra copies and this block group - * doesn't provide them, bail. This does allow us to - * fill raid0 from raid1. - */ - if ((flags & extra) && !(block_group->flags & extra)) - goto loop; - } - -have_block_group: - cached = block_group_cache_done(block_group); - if (unlikely(!cached)) { - have_caching_bg = true; - ret = cache_block_group(block_group, 0); - BUG_ON(ret < 0); - ret = 0; - } - - if (unlikely(block_group->cached == BTRFS_CACHE_ERROR)) - goto loop; - if (unlikely(block_group->ro)) - goto loop; - - /* - * Ok we want to try and use the cluster allocator, so - * lets look there - */ - if (last_ptr && use_cluster) { - struct btrfs_block_group_cache *used_block_group; - unsigned long aligned_cluster; - /* - * the refill lock keeps out other - * people trying to start a new cluster - */ - used_block_group = btrfs_lock_cluster(block_group, - last_ptr, - delalloc); - if (!used_block_group) - goto refill_cluster; - - if (used_block_group != block_group && - (used_block_group->ro || - !block_group_bits(used_block_group, flags))) - goto release_cluster; - - offset = btrfs_alloc_from_cluster(used_block_group, - last_ptr, - num_bytes, - used_block_group->key.objectid, - &max_extent_size); - if (offset) { - /* we have a block, we're done */ - spin_unlock(&last_ptr->refill_lock); - trace_btrfs_reserve_extent_cluster(root, - used_block_group, - search_start, num_bytes); - if (used_block_group != block_group) { - btrfs_release_block_group(block_group, - delalloc); - block_group = used_block_group; - } - goto checks; - } - - WARN_ON(last_ptr->block_group != used_block_group); -release_cluster: - /* If we are on LOOP_NO_EMPTY_SIZE, we can't - * set up a new clusters, so lets just skip it - * and let the allocator find whatever block - * it can find. If we reach this point, we - * will have tried the cluster allocator - * plenty of times and not have found - * anything, so we are likely way too - * fragmented for the clustering stuff to find - * anything. - * - * However, if the cluster is taken from the - * current block group, release the cluster - * first, so that we stand a better chance of - * succeeding in the unclustered - * allocation. */ - if (loop >= LOOP_NO_EMPTY_SIZE && - used_block_group != block_group) { - spin_unlock(&last_ptr->refill_lock); - btrfs_release_block_group(used_block_group, - delalloc); - goto unclustered_alloc; - } - - /* - * this cluster didn't work out, free it and - * start over - */ - btrfs_return_cluster_to_free_space(NULL, last_ptr); - - if (used_block_group != block_group) - btrfs_release_block_group(used_block_group, - delalloc); -refill_cluster: - if (loop >= LOOP_NO_EMPTY_SIZE) { - spin_unlock(&last_ptr->refill_lock); - goto unclustered_alloc; - } - - aligned_cluster = max_t(unsigned long, - empty_cluster + empty_size, - block_group->full_stripe_len); - - /* allocate a cluster in this block group */ - ret = btrfs_find_space_cluster(root, block_group, - last_ptr, search_start, - num_bytes, - aligned_cluster); - if (ret == 0) { - /* - * now pull our allocation out of this - * cluster - */ - offset = btrfs_alloc_from_cluster(block_group, - last_ptr, - num_bytes, - search_start, - &max_extent_size); - if (offset) { - /* we found one, proceed */ - spin_unlock(&last_ptr->refill_lock); - trace_btrfs_reserve_extent_cluster(root, - block_group, search_start, - num_bytes); - goto checks; - } - } else if (!cached && loop > LOOP_CACHING_NOWAIT - && !failed_cluster_refill) { - spin_unlock(&last_ptr->refill_lock); - - failed_cluster_refill = true; - wait_block_group_cache_progress(block_group, - num_bytes + empty_cluster + empty_size); - goto have_block_group; - } - - /* - * at this point we either didn't find a cluster - * or we weren't able to allocate a block from our - * cluster. Free the cluster we've been trying - * to use, and go to the next block group - */ - btrfs_return_cluster_to_free_space(NULL, last_ptr); - spin_unlock(&last_ptr->refill_lock); - goto loop; - } - -unclustered_alloc: - /* - * We are doing an unclustered alloc, set the fragmented flag so - * we don't bother trying to setup a cluster again until we get - * more space. - */ - if (unlikely(last_ptr)) { - spin_lock(&last_ptr->lock); - last_ptr->fragmented = 1; - spin_unlock(&last_ptr->lock); - } - spin_lock(&block_group->free_space_ctl->tree_lock); - if (cached && - block_group->free_space_ctl->free_space < - num_bytes + empty_cluster + empty_size) { - if (block_group->free_space_ctl->free_space > - max_extent_size) - max_extent_size = - block_group->free_space_ctl->free_space; - spin_unlock(&block_group->free_space_ctl->tree_lock); - goto loop; - } - spin_unlock(&block_group->free_space_ctl->tree_lock); - - offset = btrfs_find_space_for_alloc(block_group, search_start, - num_bytes, empty_size, - &max_extent_size); - /* - * If we didn't find a chunk, and we haven't failed on this - * block group before, and this block group is in the middle of - * caching and we are ok with waiting, then go ahead and wait - * for progress to be made, and set failed_alloc to true. - * - * If failed_alloc is true then we've already waited on this - * block group once and should move on to the next block group. - */ - if (!offset && !failed_alloc && !cached && - loop > LOOP_CACHING_NOWAIT) { - wait_block_group_cache_progress(block_group, - num_bytes + empty_size); - failed_alloc = true; - goto have_block_group; - } else if (!offset) { - goto loop; - } -checks: - search_start = ALIGN(offset, root->stripesize); - - /* move on to the next group */ - if (search_start + num_bytes > - block_group->key.objectid + block_group->key.offset) { - btrfs_add_free_space(block_group, offset, num_bytes); - goto loop; - } - - if (offset < search_start) - btrfs_add_free_space(block_group, offset, - search_start - offset); - BUG_ON(offset > search_start); - - ret = btrfs_add_reserved_bytes(block_group, ram_bytes, - num_bytes, delalloc); - if (ret == -EAGAIN) { - btrfs_add_free_space(block_group, offset, num_bytes); - goto loop; - } - btrfs_inc_block_group_reservations(block_group); - - /* we are all good, lets return */ - ins->objectid = search_start; - ins->offset = num_bytes; - - trace_btrfs_reserve_extent(orig_root, block_group, - search_start, num_bytes); - btrfs_release_block_group(block_group, delalloc); - break; -loop: - failed_cluster_refill = false; - failed_alloc = false; - BUG_ON(index != get_block_group_index(block_group)); - btrfs_release_block_group(block_group, delalloc); - } - up_read(&space_info->groups_sem); - - if ((loop == LOOP_CACHING_NOWAIT) && have_caching_bg - && !orig_have_caching_bg) - orig_have_caching_bg = true; - - if (!ins->objectid && loop >= LOOP_CACHING_WAIT && have_caching_bg) - goto search; - - if (!ins->objectid && ++index < BTRFS_NR_RAID_TYPES) - goto search; - - /* - * LOOP_CACHING_NOWAIT, search partially cached block groups, kicking - * caching kthreads as we move along - * LOOP_CACHING_WAIT, search everything, and wait if our bg is caching - * LOOP_ALLOC_CHUNK, force a chunk allocation and try again - * LOOP_NO_EMPTY_SIZE, set empty_size and empty_cluster to 0 and try - * again - */ - if (!ins->objectid && loop < LOOP_NO_EMPTY_SIZE) { - index = 0; - if (loop == LOOP_CACHING_NOWAIT) { - /* - * We want to skip the LOOP_CACHING_WAIT step if we - * don't have any uncached bgs and we've already done a - * full search through. - */ - if (orig_have_caching_bg || !full_search) - loop = LOOP_CACHING_WAIT; - else - loop = LOOP_ALLOC_CHUNK; - } else { - loop++; - } - - if (loop == LOOP_ALLOC_CHUNK) { - struct btrfs_trans_handle *trans; - int exist = 0; - - trans = current->journal_info; - if (trans) - exist = 1; - else - trans = btrfs_join_transaction(root); - - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out; - } - - ret = do_chunk_alloc(trans, root, flags, - CHUNK_ALLOC_FORCE); - - /* - * If we can't allocate a new chunk we've already looped - * through at least once, move on to the NO_EMPTY_SIZE - * case. - */ - if (ret == -ENOSPC) - loop = LOOP_NO_EMPTY_SIZE; - - /* - * Do not bail out on ENOSPC since we - * can do more things. - */ - if (ret < 0 && ret != -ENOSPC) - btrfs_abort_transaction(trans, ret); - else - ret = 0; - if (!exist) - btrfs_end_transaction(trans, root); - if (ret) - goto out; - } - - if (loop == LOOP_NO_EMPTY_SIZE) { - /* - * Don't loop again if we already have no empty_size and - * no empty_cluster. - */ - if (empty_size == 0 && - empty_cluster == 0) { - ret = -ENOSPC; - goto out; - } - empty_size = 0; - empty_cluster = 0; - } - - goto search; - } else if (!ins->objectid) { - ret = -ENOSPC; - } else if (ins->objectid) { - if (!use_cluster && last_ptr) { - spin_lock(&last_ptr->lock); - last_ptr->window_start = ins->objectid; - spin_unlock(&last_ptr->lock); - } - ret = 0; - } -out: - if (ret == -ENOSPC) { - spin_lock(&space_info->lock); - space_info->max_extent_size = max_extent_size; - spin_unlock(&space_info->lock); - ins->offset = max_extent_size; - } - return ret; -} - -static void dump_space_info(struct btrfs_fs_info *fs_info, - struct btrfs_space_info *info, u64 bytes, - int dump_block_groups) -{ - struct btrfs_block_group_cache *cache; - int index = 0; - - spin_lock(&info->lock); - btrfs_info(fs_info, "space_info %llu has %llu free, is %sfull", - info->flags, - info->total_bytes - info->bytes_used - info->bytes_pinned - - info->bytes_reserved - info->bytes_readonly - - info->bytes_may_use, (info->full) ? "" : "not "); - btrfs_info(fs_info, - "space_info total=%llu, used=%llu, pinned=%llu, reserved=%llu, may_use=%llu, readonly=%llu", - info->total_bytes, info->bytes_used, info->bytes_pinned, - info->bytes_reserved, info->bytes_may_use, - info->bytes_readonly); - spin_unlock(&info->lock); - - if (!dump_block_groups) - return; - - down_read(&info->groups_sem); -again: - list_for_each_entry(cache, &info->block_groups[index], list) { - spin_lock(&cache->lock); - btrfs_info(fs_info, - "block group %llu has %llu bytes, %llu used %llu pinned %llu reserved %s", - cache->key.objectid, cache->key.offset, - btrfs_block_group_used(&cache->item), cache->pinned, - cache->reserved, cache->ro ? "[readonly]" : ""); - btrfs_dump_free_space(cache, bytes); - spin_unlock(&cache->lock); - } - if (++index < BTRFS_NR_RAID_TYPES) - goto again; - up_read(&info->groups_sem); -} - -int btrfs_reserve_extent(struct btrfs_root *root, u64 ram_bytes, - u64 num_bytes, u64 min_alloc_size, - u64 empty_size, u64 hint_byte, - struct btrfs_key *ins, int is_data, int delalloc) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - bool final_tried = num_bytes == min_alloc_size; - u64 flags; - int ret; - - flags = btrfs_get_alloc_profile(root, is_data); -again: - WARN_ON(num_bytes < root->sectorsize); - ret = find_free_extent(root, ram_bytes, num_bytes, empty_size, - hint_byte, ins, flags, delalloc); - if (!ret && !is_data) { - btrfs_dec_block_group_reservations(fs_info, ins->objectid); - } else if (ret == -ENOSPC) { - if (!final_tried && ins->offset) { - num_bytes = min(num_bytes >> 1, ins->offset); - num_bytes = round_down(num_bytes, root->sectorsize); - num_bytes = max(num_bytes, min_alloc_size); - ram_bytes = num_bytes; - if (num_bytes == min_alloc_size) - final_tried = true; - goto again; - } else if (btrfs_test_opt(fs_info, ENOSPC_DEBUG)) { - struct btrfs_space_info *sinfo; - - sinfo = __find_space_info(fs_info, flags); - btrfs_err(root->fs_info, - "allocation failed flags %llu, wanted %llu", - flags, num_bytes); - if (sinfo) - dump_space_info(fs_info, sinfo, num_bytes, 1); - } - } - - return ret; -} - -static int __btrfs_free_reserved_extent(struct btrfs_root *root, - u64 start, u64 len, - int pin, int delalloc) -{ - struct btrfs_block_group_cache *cache; - int ret = 0; - - cache = btrfs_lookup_block_group(root->fs_info, start); - if (!cache) { - btrfs_err(root->fs_info, "Unable to find block group for %llu", - start); - return -ENOSPC; - } - - if (pin) - pin_down_extent(root, cache, start, len, 1); - else { - if (btrfs_test_opt(root->fs_info, DISCARD)) - ret = btrfs_discard_extent(root, start, len, NULL); - btrfs_add_free_space(cache, start, len); - btrfs_free_reserved_bytes(cache, len, delalloc); - trace_btrfs_reserved_extent_free(root, start, len); - } - - btrfs_put_block_group(cache); - return ret; -} - -int btrfs_free_reserved_extent(struct btrfs_root *root, - u64 start, u64 len, int delalloc) -{ - return __btrfs_free_reserved_extent(root, start, len, 0, delalloc); -} - -int btrfs_free_and_pin_reserved_extent(struct btrfs_root *root, - u64 start, u64 len) -{ - return __btrfs_free_reserved_extent(root, start, len, 1, 0); -} - -static int alloc_reserved_file_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 parent, u64 root_objectid, - u64 flags, u64 owner, u64 offset, - struct btrfs_key *ins, int ref_mod) -{ - int ret; - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_extent_item *extent_item; - struct btrfs_extent_inline_ref *iref; - struct btrfs_path *path; - struct extent_buffer *leaf; - int type; - u32 size; - - if (parent > 0) - type = BTRFS_SHARED_DATA_REF_KEY; - else - type = BTRFS_EXTENT_DATA_REF_KEY; - - size = sizeof(*extent_item) + btrfs_extent_inline_ref_size(type); - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - path->leave_spinning = 1; - ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path, - ins, size); - if (ret) { - btrfs_free_path(path); - return ret; - } - - leaf = path->nodes[0]; - extent_item = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_item); - btrfs_set_extent_refs(leaf, extent_item, ref_mod); - btrfs_set_extent_generation(leaf, extent_item, trans->transid); - btrfs_set_extent_flags(leaf, extent_item, - flags | BTRFS_EXTENT_FLAG_DATA); - - iref = (struct btrfs_extent_inline_ref *)(extent_item + 1); - btrfs_set_extent_inline_ref_type(leaf, iref, type); - if (parent > 0) { - struct btrfs_shared_data_ref *ref; - ref = (struct btrfs_shared_data_ref *)(iref + 1); - btrfs_set_extent_inline_ref_offset(leaf, iref, parent); - btrfs_set_shared_data_ref_count(leaf, ref, ref_mod); - } else { - struct btrfs_extent_data_ref *ref; - ref = (struct btrfs_extent_data_ref *)(&iref->offset); - btrfs_set_extent_data_ref_root(leaf, ref, root_objectid); - btrfs_set_extent_data_ref_objectid(leaf, ref, owner); - btrfs_set_extent_data_ref_offset(leaf, ref, offset); - btrfs_set_extent_data_ref_count(leaf, ref, ref_mod); - } - - btrfs_mark_buffer_dirty(path->nodes[0]); - btrfs_free_path(path); - - ret = remove_from_free_space_tree(trans, fs_info, ins->objectid, - ins->offset); - if (ret) - return ret; - - ret = update_block_group(trans, root, ins->objectid, ins->offset, 1); - if (ret) { /* -ENOENT, logic error */ - btrfs_err(fs_info, "update block group failed for %llu %llu", - ins->objectid, ins->offset); - BUG(); - } - trace_btrfs_reserved_extent_alloc(root, ins->objectid, ins->offset); - return ret; -} - -static int alloc_reserved_tree_block(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 parent, u64 root_objectid, - u64 flags, struct btrfs_disk_key *key, - int level, struct btrfs_key *ins) -{ - int ret; - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_extent_item *extent_item; - struct btrfs_tree_block_info *block_info; - struct btrfs_extent_inline_ref *iref; - struct btrfs_path *path; - struct extent_buffer *leaf; - u32 size = sizeof(*extent_item) + sizeof(*iref); - u64 num_bytes = ins->offset; - bool skinny_metadata = btrfs_fs_incompat(root->fs_info, - SKINNY_METADATA); - - if (!skinny_metadata) - size += sizeof(*block_info); - - path = btrfs_alloc_path(); - if (!path) { - btrfs_free_and_pin_reserved_extent(root, ins->objectid, - root->nodesize); - return -ENOMEM; - } - - path->leave_spinning = 1; - ret = btrfs_insert_empty_item(trans, fs_info->extent_root, path, - ins, size); - if (ret) { - btrfs_free_path(path); - btrfs_free_and_pin_reserved_extent(root, ins->objectid, - root->nodesize); - return ret; - } - - leaf = path->nodes[0]; - extent_item = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_extent_item); - btrfs_set_extent_refs(leaf, extent_item, 1); - btrfs_set_extent_generation(leaf, extent_item, trans->transid); - btrfs_set_extent_flags(leaf, extent_item, - flags | BTRFS_EXTENT_FLAG_TREE_BLOCK); - - if (skinny_metadata) { - iref = (struct btrfs_extent_inline_ref *)(extent_item + 1); - num_bytes = root->nodesize; - } else { - block_info = (struct btrfs_tree_block_info *)(extent_item + 1); - btrfs_set_tree_block_key(leaf, block_info, key); - btrfs_set_tree_block_level(leaf, block_info, level); - iref = (struct btrfs_extent_inline_ref *)(block_info + 1); - } - - if (parent > 0) { - BUG_ON(!(flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)); - btrfs_set_extent_inline_ref_type(leaf, iref, - BTRFS_SHARED_BLOCK_REF_KEY); - btrfs_set_extent_inline_ref_offset(leaf, iref, parent); - } else { - btrfs_set_extent_inline_ref_type(leaf, iref, - BTRFS_TREE_BLOCK_REF_KEY); - btrfs_set_extent_inline_ref_offset(leaf, iref, root_objectid); - } - - btrfs_mark_buffer_dirty(leaf); - btrfs_free_path(path); - - ret = remove_from_free_space_tree(trans, fs_info, ins->objectid, - num_bytes); - if (ret) - return ret; - - ret = update_block_group(trans, root, ins->objectid, root->nodesize, - 1); - if (ret) { /* -ENOENT, logic error */ - btrfs_err(fs_info, "update block group failed for %llu %llu", - ins->objectid, ins->offset); - BUG(); - } - - trace_btrfs_reserved_extent_alloc(root, ins->objectid, root->nodesize); - return ret; -} - -int btrfs_alloc_reserved_file_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 root_objectid, u64 owner, - u64 offset, u64 ram_bytes, - struct btrfs_key *ins) -{ - int ret; - - BUG_ON(root_objectid == BTRFS_TREE_LOG_OBJECTID); - - ret = btrfs_add_delayed_data_ref(root->fs_info, trans, ins->objectid, - ins->offset, 0, - root_objectid, owner, offset, - ram_bytes, BTRFS_ADD_DELAYED_EXTENT, - NULL); - return ret; -} - -/* - * this is used by the tree logging recovery code. It records that - * an extent has been allocated and makes sure to clear the free - * space cache bits as well - */ -int btrfs_alloc_logged_file_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 root_objectid, u64 owner, u64 offset, - struct btrfs_key *ins) -{ - int ret; - struct btrfs_block_group_cache *block_group; - struct btrfs_space_info *space_info; - - /* - * Mixed block groups will exclude before processing the log so we only - * need to do the exclude dance if this fs isn't mixed. - */ - if (!btrfs_fs_incompat(root->fs_info, MIXED_GROUPS)) { - ret = __exclude_logged_extent(root, ins->objectid, ins->offset); - if (ret) - return ret; - } - - block_group = btrfs_lookup_block_group(root->fs_info, ins->objectid); - if (!block_group) - return -EINVAL; - - space_info = block_group->space_info; - spin_lock(&space_info->lock); - spin_lock(&block_group->lock); - space_info->bytes_reserved += ins->offset; - block_group->reserved += ins->offset; - spin_unlock(&block_group->lock); - spin_unlock(&space_info->lock); - - ret = alloc_reserved_file_extent(trans, root, 0, root_objectid, - 0, owner, offset, ins, 1); - btrfs_put_block_group(block_group); - return ret; -} - -static struct extent_buffer * -btrfs_init_new_buffer(struct btrfs_trans_handle *trans, struct btrfs_root *root, - u64 bytenr, int level) -{ - struct extent_buffer *buf; - - buf = btrfs_find_create_tree_block(root, bytenr); - if (IS_ERR(buf)) - return buf; - - btrfs_set_header_generation(buf, trans->transid); - btrfs_set_buffer_lockdep_class(root->root_key.objectid, buf, level); - btrfs_tree_lock(buf); - clean_tree_block(trans, root->fs_info, buf); - clear_bit(EXTENT_BUFFER_STALE, &buf->bflags); - - btrfs_set_lock_blocking(buf); - set_extent_buffer_uptodate(buf); - - if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) { - buf->log_index = root->log_transid % 2; - /* - * we allow two log transactions at a time, use different - * EXENT bit to differentiate dirty pages. - */ - if (buf->log_index == 0) - set_extent_dirty(&root->dirty_log_pages, buf->start, - buf->start + buf->len - 1, GFP_NOFS); - else - set_extent_new(&root->dirty_log_pages, buf->start, - buf->start + buf->len - 1); - } else { - buf->log_index = -1; - set_extent_dirty(&trans->transaction->dirty_pages, buf->start, - buf->start + buf->len - 1, GFP_NOFS); - } - trans->dirty = true; - /* this returns a buffer locked for blocking */ - return buf; -} - -static struct btrfs_block_rsv * -use_block_rsv(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u32 blocksize) -{ - struct btrfs_block_rsv *block_rsv; - struct btrfs_block_rsv *global_rsv = &root->fs_info->global_block_rsv; - int ret; - bool global_updated = false; - - block_rsv = get_block_rsv(trans, root); - - if (unlikely(block_rsv->size == 0)) - goto try_reserve; -again: - ret = block_rsv_use_bytes(block_rsv, blocksize); - if (!ret) - return block_rsv; - - if (block_rsv->failfast) - return ERR_PTR(ret); - - if (block_rsv->type == BTRFS_BLOCK_RSV_GLOBAL && !global_updated) { - global_updated = true; - update_global_block_rsv(root->fs_info); - goto again; - } - - if (btrfs_test_opt(root->fs_info, ENOSPC_DEBUG)) { - static DEFINE_RATELIMIT_STATE(_rs, - DEFAULT_RATELIMIT_INTERVAL * 10, - /*DEFAULT_RATELIMIT_BURST*/ 1); - if (__ratelimit(&_rs)) - WARN(1, KERN_DEBUG - "BTRFS: block rsv returned %d\n", ret); - } -try_reserve: - ret = reserve_metadata_bytes(root, block_rsv, blocksize, - BTRFS_RESERVE_NO_FLUSH); - if (!ret) - return block_rsv; - /* - * If we couldn't reserve metadata bytes try and use some from - * the global reserve if its space type is the same as the global - * reservation. - */ - if (block_rsv->type != BTRFS_BLOCK_RSV_GLOBAL && - block_rsv->space_info == global_rsv->space_info) { - ret = block_rsv_use_bytes(global_rsv, blocksize); - if (!ret) - return global_rsv; - } - return ERR_PTR(ret); -} - -static void unuse_block_rsv(struct btrfs_fs_info *fs_info, - struct btrfs_block_rsv *block_rsv, u32 blocksize) -{ - block_rsv_add_bytes(block_rsv, blocksize, 0); - block_rsv_release_bytes(fs_info, block_rsv, NULL, 0); -} - -/* - * finds a free extent and does all the dirty work required for allocation - * returns the tree buffer or an ERR_PTR on error. - */ -struct extent_buffer *btrfs_alloc_tree_block(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 parent, u64 root_objectid, - struct btrfs_disk_key *key, int level, - u64 hint, u64 empty_size) -{ - struct btrfs_key ins; - struct btrfs_block_rsv *block_rsv; - struct extent_buffer *buf; - struct btrfs_delayed_extent_op *extent_op; - u64 flags = 0; - int ret; - u32 blocksize = root->nodesize; - bool skinny_metadata = btrfs_fs_incompat(root->fs_info, - SKINNY_METADATA); - -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS - if (btrfs_is_testing(root->fs_info)) { - buf = btrfs_init_new_buffer(trans, root, root->alloc_bytenr, - level); - if (!IS_ERR(buf)) - root->alloc_bytenr += blocksize; - return buf; - } -#endif - - block_rsv = use_block_rsv(trans, root, blocksize); - if (IS_ERR(block_rsv)) - return ERR_CAST(block_rsv); - - ret = btrfs_reserve_extent(root, blocksize, blocksize, blocksize, - empty_size, hint, &ins, 0, 0); - if (ret) - goto out_unuse; - - buf = btrfs_init_new_buffer(trans, root, ins.objectid, level); - if (IS_ERR(buf)) { - ret = PTR_ERR(buf); - goto out_free_reserved; - } - - if (root_objectid == BTRFS_TREE_RELOC_OBJECTID) { - if (parent == 0) - parent = ins.objectid; - flags |= BTRFS_BLOCK_FLAG_FULL_BACKREF; - } else - BUG_ON(parent > 0); - - if (root_objectid != BTRFS_TREE_LOG_OBJECTID) { - extent_op = btrfs_alloc_delayed_extent_op(); - if (!extent_op) { - ret = -ENOMEM; - goto out_free_buf; - } - if (key) - memcpy(&extent_op->key, key, sizeof(extent_op->key)); - else - memset(&extent_op->key, 0, sizeof(extent_op->key)); - extent_op->flags_to_set = flags; - extent_op->update_key = skinny_metadata ? false : true; - extent_op->update_flags = true; - extent_op->is_data = false; - extent_op->level = level; - - ret = btrfs_add_delayed_tree_ref(root->fs_info, trans, - ins.objectid, ins.offset, - parent, root_objectid, level, - BTRFS_ADD_DELAYED_EXTENT, - extent_op); - if (ret) - goto out_free_delayed; - } - return buf; - -out_free_delayed: - btrfs_free_delayed_extent_op(extent_op); -out_free_buf: - free_extent_buffer(buf); -out_free_reserved: - btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 0); -out_unuse: - unuse_block_rsv(root->fs_info, block_rsv, blocksize); - return ERR_PTR(ret); -} - -struct walk_control { - u64 refs[BTRFS_MAX_LEVEL]; - u64 flags[BTRFS_MAX_LEVEL]; - struct btrfs_key update_progress; - int stage; - int level; - int shared_level; - int update_ref; - int keep_locks; - int reada_slot; - int reada_count; - int for_reloc; -}; - -#define DROP_REFERENCE 1 -#define UPDATE_BACKREF 2 - -static noinline void reada_walk_down(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct walk_control *wc, - struct btrfs_path *path) -{ - u64 bytenr; - u64 generation; - u64 refs; - u64 flags; - u32 nritems; - struct btrfs_key key; - struct extent_buffer *eb; - int ret; - int slot; - int nread = 0; - - if (path->slots[wc->level] < wc->reada_slot) { - wc->reada_count = wc->reada_count * 2 / 3; - wc->reada_count = max(wc->reada_count, 2); - } else { - wc->reada_count = wc->reada_count * 3 / 2; - wc->reada_count = min_t(int, wc->reada_count, - BTRFS_NODEPTRS_PER_BLOCK(root)); - } - - eb = path->nodes[wc->level]; - nritems = btrfs_header_nritems(eb); - - for (slot = path->slots[wc->level]; slot < nritems; slot++) { - if (nread >= wc->reada_count) - break; - - cond_resched(); - bytenr = btrfs_node_blockptr(eb, slot); - generation = btrfs_node_ptr_generation(eb, slot); - - if (slot == path->slots[wc->level]) - goto reada; - - if (wc->stage == UPDATE_BACKREF && - generation <= root->root_key.offset) - continue; - - /* We don't lock the tree block, it's OK to be racy here */ - ret = btrfs_lookup_extent_info(trans, root, bytenr, - wc->level - 1, 1, &refs, - &flags); - /* We don't care about errors in readahead. */ - if (ret < 0) - continue; - BUG_ON(refs == 0); - - if (wc->stage == DROP_REFERENCE) { - if (refs == 1) - goto reada; - - if (wc->level == 1 && - (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) - continue; - if (!wc->update_ref || - generation <= root->root_key.offset) - continue; - btrfs_node_key_to_cpu(eb, &key, slot); - ret = btrfs_comp_cpu_keys(&key, - &wc->update_progress); - if (ret < 0) - continue; - } else { - if (wc->level == 1 && - (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) - continue; - } -reada: - readahead_tree_block(root, bytenr); - nread++; - } - wc->reada_slot = slot; -} - -static int account_leaf_items(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct extent_buffer *eb) -{ - int nr = btrfs_header_nritems(eb); - int i, extent_type, ret; - struct btrfs_key key; - struct btrfs_file_extent_item *fi; - u64 bytenr, num_bytes; - - /* We can be called directly from walk_up_proc() */ - if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags)) - return 0; - - for (i = 0; i < nr; i++) { - btrfs_item_key_to_cpu(eb, &key, i); - - if (key.type != BTRFS_EXTENT_DATA_KEY) - continue; - - fi = btrfs_item_ptr(eb, i, struct btrfs_file_extent_item); - /* filter out non qgroup-accountable extents */ - extent_type = btrfs_file_extent_type(eb, fi); - - if (extent_type == BTRFS_FILE_EXTENT_INLINE) - continue; - - bytenr = btrfs_file_extent_disk_bytenr(eb, fi); - if (!bytenr) - continue; - - num_bytes = btrfs_file_extent_disk_num_bytes(eb, fi); - - ret = btrfs_qgroup_insert_dirty_extent(trans, root->fs_info, - bytenr, num_bytes, GFP_NOFS); - if (ret) - return ret; - } - return 0; -} - -/* - * Walk up the tree from the bottom, freeing leaves and any interior - * nodes which have had all slots visited. If a node (leaf or - * interior) is freed, the node above it will have it's slot - * incremented. The root node will never be freed. - * - * At the end of this function, we should have a path which has all - * slots incremented to the next position for a search. If we need to - * read a new node it will be NULL and the node above it will have the - * correct slot selected for a later read. - * - * If we increment the root nodes slot counter past the number of - * elements, 1 is returned to signal completion of the search. - */ -static int adjust_slots_upwards(struct btrfs_root *root, - struct btrfs_path *path, int root_level) -{ - int level = 0; - int nr, slot; - struct extent_buffer *eb; - - if (root_level == 0) - return 1; - - while (level <= root_level) { - eb = path->nodes[level]; - nr = btrfs_header_nritems(eb); - path->slots[level]++; - slot = path->slots[level]; - if (slot >= nr || level == 0) { - /* - * Don't free the root - we will detect this - * condition after our loop and return a - * positive value for caller to stop walking the tree. - */ - if (level != root_level) { - btrfs_tree_unlock_rw(eb, path->locks[level]); - path->locks[level] = 0; - - free_extent_buffer(eb); - path->nodes[level] = NULL; - path->slots[level] = 0; - } - } else { - /* - * We have a valid slot to walk back down - * from. Stop here so caller can process these - * new nodes. - */ - break; - } - - level++; - } - - eb = path->nodes[root_level]; - if (path->slots[root_level] >= btrfs_header_nritems(eb)) - return 1; - - return 0; -} - -/* - * root_eb is the subtree root and is locked before this function is called. - */ -static int account_shared_subtree(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct extent_buffer *root_eb, - u64 root_gen, - int root_level) -{ - int ret = 0; - int level; - struct extent_buffer *eb = root_eb; - struct btrfs_path *path = NULL; - - BUG_ON(root_level < 0 || root_level > BTRFS_MAX_LEVEL); - BUG_ON(root_eb == NULL); - - if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags)) - return 0; - - if (!extent_buffer_uptodate(root_eb)) { - ret = btrfs_read_buffer(root_eb, root_gen); - if (ret) - goto out; - } - - if (root_level == 0) { - ret = account_leaf_items(trans, root, root_eb); - goto out; - } - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - /* - * Walk down the tree. Missing extent blocks are filled in as - * we go. Metadata is accounted every time we read a new - * extent block. - * - * When we reach a leaf, we account for file extent items in it, - * walk back up the tree (adjusting slot pointers as we go) - * and restart the search process. - */ - extent_buffer_get(root_eb); /* For path */ - path->nodes[root_level] = root_eb; - path->slots[root_level] = 0; - path->locks[root_level] = 0; /* so release_path doesn't try to unlock */ -walk_down: - level = root_level; - while (level >= 0) { - if (path->nodes[level] == NULL) { - int parent_slot; - u64 child_gen; - u64 child_bytenr; - - /* We need to get child blockptr/gen from - * parent before we can read it. */ - eb = path->nodes[level + 1]; - parent_slot = path->slots[level + 1]; - child_bytenr = btrfs_node_blockptr(eb, parent_slot); - child_gen = btrfs_node_ptr_generation(eb, parent_slot); - - eb = read_tree_block(root, child_bytenr, child_gen); - if (IS_ERR(eb)) { - ret = PTR_ERR(eb); - goto out; - } else if (!extent_buffer_uptodate(eb)) { - free_extent_buffer(eb); - ret = -EIO; - goto out; - } - - path->nodes[level] = eb; - path->slots[level] = 0; - - btrfs_tree_read_lock(eb); - btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK); - path->locks[level] = BTRFS_READ_LOCK_BLOCKING; - - ret = btrfs_qgroup_insert_dirty_extent(trans, - root->fs_info, child_bytenr, - root->nodesize, GFP_NOFS); - if (ret) - goto out; - } - - if (level == 0) { - ret = account_leaf_items(trans, root, path->nodes[level]); - if (ret) - goto out; - - /* Nonzero return here means we completed our search */ - ret = adjust_slots_upwards(root, path, root_level); - if (ret) - break; - - /* Restart search with new slots */ - goto walk_down; - } - - level--; - } - - ret = 0; -out: - btrfs_free_path(path); - - return ret; -} - -/* - * helper to process tree block while walking down the tree. - * - * when wc->stage == UPDATE_BACKREF, this function updates - * back refs for pointers in the block. - * - * NOTE: return value 1 means we should stop walking down. - */ -static noinline int walk_down_proc(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct walk_control *wc, int lookup_info) -{ - int level = wc->level; - struct extent_buffer *eb = path->nodes[level]; - u64 flag = BTRFS_BLOCK_FLAG_FULL_BACKREF; - int ret; - - if (wc->stage == UPDATE_BACKREF && - btrfs_header_owner(eb) != root->root_key.objectid) - return 1; - - /* - * when reference count of tree block is 1, it won't increase - * again. once full backref flag is set, we never clear it. - */ - if (lookup_info && - ((wc->stage == DROP_REFERENCE && wc->refs[level] != 1) || - (wc->stage == UPDATE_BACKREF && !(wc->flags[level] & flag)))) { - BUG_ON(!path->locks[level]); - ret = btrfs_lookup_extent_info(trans, root, - eb->start, level, 1, - &wc->refs[level], - &wc->flags[level]); - BUG_ON(ret == -ENOMEM); - if (ret) - return ret; - BUG_ON(wc->refs[level] == 0); - } - - if (wc->stage == DROP_REFERENCE) { - if (wc->refs[level] > 1) - return 1; - - if (path->locks[level] && !wc->keep_locks) { - btrfs_tree_unlock_rw(eb, path->locks[level]); - path->locks[level] = 0; - } - return 0; - } - - /* wc->stage == UPDATE_BACKREF */ - if (!(wc->flags[level] & flag)) { - BUG_ON(!path->locks[level]); - ret = btrfs_inc_ref(trans, root, eb, 1); - BUG_ON(ret); /* -ENOMEM */ - ret = btrfs_dec_ref(trans, root, eb, 0); - BUG_ON(ret); /* -ENOMEM */ - ret = btrfs_set_disk_extent_flags(trans, root, eb->start, - eb->len, flag, - btrfs_header_level(eb), 0); - BUG_ON(ret); /* -ENOMEM */ - wc->flags[level] |= flag; - } - - /* - * the block is shared by multiple trees, so it's not good to - * keep the tree lock - */ - if (path->locks[level] && level > 0) { - btrfs_tree_unlock_rw(eb, path->locks[level]); - path->locks[level] = 0; - } - return 0; -} - -/* - * helper to process tree block pointer. - * - * when wc->stage == DROP_REFERENCE, this function checks - * reference count of the block pointed to. if the block - * is shared and we need update back refs for the subtree - * rooted at the block, this function changes wc->stage to - * UPDATE_BACKREF. if the block is shared and there is no - * need to update back, this function drops the reference - * to the block. - * - * NOTE: return value 1 means we should stop walking down. - */ -static noinline int do_walk_down(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct walk_control *wc, int *lookup_info) -{ - u64 bytenr; - u64 generation; - u64 parent; - u32 blocksize; - struct btrfs_key key; - struct extent_buffer *next; - int level = wc->level; - int reada = 0; - int ret = 0; - bool need_account = false; - - generation = btrfs_node_ptr_generation(path->nodes[level], - path->slots[level]); - /* - * if the lower level block was created before the snapshot - * was created, we know there is no need to update back refs - * for the subtree - */ - if (wc->stage == UPDATE_BACKREF && - generation <= root->root_key.offset) { - *lookup_info = 1; - return 1; - } - - bytenr = btrfs_node_blockptr(path->nodes[level], path->slots[level]); - blocksize = root->nodesize; - - next = btrfs_find_tree_block(root->fs_info, bytenr); - if (!next) { - next = btrfs_find_create_tree_block(root, bytenr); - if (IS_ERR(next)) - return PTR_ERR(next); - - btrfs_set_buffer_lockdep_class(root->root_key.objectid, next, - level - 1); - reada = 1; - } - btrfs_tree_lock(next); - btrfs_set_lock_blocking(next); - - ret = btrfs_lookup_extent_info(trans, root, bytenr, level - 1, 1, - &wc->refs[level - 1], - &wc->flags[level - 1]); - if (ret < 0) - goto out_unlock; - - if (unlikely(wc->refs[level - 1] == 0)) { - btrfs_err(root->fs_info, "Missing references."); - ret = -EIO; - goto out_unlock; - } - *lookup_info = 0; - - if (wc->stage == DROP_REFERENCE) { - if (wc->refs[level - 1] > 1) { - need_account = true; - if (level == 1 && - (wc->flags[0] & BTRFS_BLOCK_FLAG_FULL_BACKREF)) - goto skip; - - if (!wc->update_ref || - generation <= root->root_key.offset) - goto skip; - - btrfs_node_key_to_cpu(path->nodes[level], &key, - path->slots[level]); - ret = btrfs_comp_cpu_keys(&key, &wc->update_progress); - if (ret < 0) - goto skip; - - wc->stage = UPDATE_BACKREF; - wc->shared_level = level - 1; - } - } else { - if (level == 1 && - (wc->flags[0] & BTRFS_BLOCK_FLAG_FULL_BACKREF)) - goto skip; - } - - if (!btrfs_buffer_uptodate(next, generation, 0)) { - btrfs_tree_unlock(next); - free_extent_buffer(next); - next = NULL; - *lookup_info = 1; - } - - if (!next) { - if (reada && level == 1) - reada_walk_down(trans, root, wc, path); - next = read_tree_block(root, bytenr, generation); - if (IS_ERR(next)) { - return PTR_ERR(next); - } else if (!extent_buffer_uptodate(next)) { - free_extent_buffer(next); - return -EIO; - } - btrfs_tree_lock(next); - btrfs_set_lock_blocking(next); - } - - level--; - ASSERT(level == btrfs_header_level(next)); - if (level != btrfs_header_level(next)) { - btrfs_err(root->fs_info, "mismatched level"); - ret = -EIO; - goto out_unlock; - } - path->nodes[level] = next; - path->slots[level] = 0; - path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING; - wc->level = level; - if (wc->level == 1) - wc->reada_slot = 0; - return 0; -skip: - wc->refs[level - 1] = 0; - wc->flags[level - 1] = 0; - if (wc->stage == DROP_REFERENCE) { - if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) { - parent = path->nodes[level]->start; - } else { - ASSERT(root->root_key.objectid == - btrfs_header_owner(path->nodes[level])); - if (root->root_key.objectid != - btrfs_header_owner(path->nodes[level])) { - btrfs_err(root->fs_info, - "mismatched block owner"); - ret = -EIO; - goto out_unlock; - } - parent = 0; - } - - if (need_account) { - ret = account_shared_subtree(trans, root, next, - generation, level - 1); - if (ret) { - btrfs_err_rl(root->fs_info, - "Error %d accounting shared subtree. Quota is out of sync, rescan required.", - ret); - } - } - ret = btrfs_free_extent(trans, root, bytenr, blocksize, parent, - root->root_key.objectid, level - 1, 0); - if (ret) - goto out_unlock; - } - - *lookup_info = 1; - ret = 1; - -out_unlock: - btrfs_tree_unlock(next); - free_extent_buffer(next); - - return ret; -} - -/* - * helper to process tree block while walking up the tree. - * - * when wc->stage == DROP_REFERENCE, this function drops - * reference count on the block. - * - * when wc->stage == UPDATE_BACKREF, this function changes - * wc->stage back to DROP_REFERENCE if we changed wc->stage - * to UPDATE_BACKREF previously while processing the block. - * - * NOTE: return value 1 means we should stop walking up. - */ -static noinline int walk_up_proc(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct walk_control *wc) -{ - int ret; - int level = wc->level; - struct extent_buffer *eb = path->nodes[level]; - u64 parent = 0; - - if (wc->stage == UPDATE_BACKREF) { - BUG_ON(wc->shared_level < level); - if (level < wc->shared_level) - goto out; - - ret = find_next_key(path, level + 1, &wc->update_progress); - if (ret > 0) - wc->update_ref = 0; - - wc->stage = DROP_REFERENCE; - wc->shared_level = -1; - path->slots[level] = 0; - - /* - * check reference count again if the block isn't locked. - * we should start walking down the tree again if reference - * count is one. - */ - if (!path->locks[level]) { - BUG_ON(level == 0); - btrfs_tree_lock(eb); - btrfs_set_lock_blocking(eb); - path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING; - - ret = btrfs_lookup_extent_info(trans, root, - eb->start, level, 1, - &wc->refs[level], - &wc->flags[level]); - if (ret < 0) { - btrfs_tree_unlock_rw(eb, path->locks[level]); - path->locks[level] = 0; - return ret; - } - BUG_ON(wc->refs[level] == 0); - if (wc->refs[level] == 1) { - btrfs_tree_unlock_rw(eb, path->locks[level]); - path->locks[level] = 0; - return 1; - } - } - } - - /* wc->stage == DROP_REFERENCE */ - BUG_ON(wc->refs[level] > 1 && !path->locks[level]); - - if (wc->refs[level] == 1) { - if (level == 0) { - if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) - ret = btrfs_dec_ref(trans, root, eb, 1); - else - ret = btrfs_dec_ref(trans, root, eb, 0); - BUG_ON(ret); /* -ENOMEM */ - ret = account_leaf_items(trans, root, eb); - if (ret) { - btrfs_err_rl(root->fs_info, - "error %d accounting leaf items. Quota is out of sync, rescan required.", - ret); - } - } - /* make block locked assertion in clean_tree_block happy */ - if (!path->locks[level] && - btrfs_header_generation(eb) == trans->transid) { - btrfs_tree_lock(eb); - btrfs_set_lock_blocking(eb); - path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING; - } - clean_tree_block(trans, root->fs_info, eb); - } - - if (eb == root->node) { - if (wc->flags[level] & BTRFS_BLOCK_FLAG_FULL_BACKREF) - parent = eb->start; - else - BUG_ON(root->root_key.objectid != - btrfs_header_owner(eb)); - } else { - if (wc->flags[level + 1] & BTRFS_BLOCK_FLAG_FULL_BACKREF) - parent = path->nodes[level + 1]->start; - else - BUG_ON(root->root_key.objectid != - btrfs_header_owner(path->nodes[level + 1])); - } - - btrfs_free_tree_block(trans, root, eb, parent, wc->refs[level] == 1); -out: - wc->refs[level] = 0; - wc->flags[level] = 0; - return 0; -} - -static noinline int walk_down_tree(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct walk_control *wc) -{ - int level = wc->level; - int lookup_info = 1; - int ret; - - while (level >= 0) { - ret = walk_down_proc(trans, root, path, wc, lookup_info); - if (ret > 0) - break; - - if (level == 0) - break; - - if (path->slots[level] >= - btrfs_header_nritems(path->nodes[level])) - break; - - ret = do_walk_down(trans, root, path, wc, &lookup_info); - if (ret > 0) { - path->slots[level]++; - continue; - } else if (ret < 0) - return ret; - level = wc->level; - } - return 0; -} - -static noinline int walk_up_tree(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct walk_control *wc, int max_level) -{ - int level = wc->level; - int ret; - - path->slots[level] = btrfs_header_nritems(path->nodes[level]); - while (level < max_level && path->nodes[level]) { - wc->level = level; - if (path->slots[level] + 1 < - btrfs_header_nritems(path->nodes[level])) { - path->slots[level]++; - return 0; - } else { - ret = walk_up_proc(trans, root, path, wc); - if (ret > 0) - return 0; - - if (path->locks[level]) { - btrfs_tree_unlock_rw(path->nodes[level], - path->locks[level]); - path->locks[level] = 0; - } - free_extent_buffer(path->nodes[level]); - path->nodes[level] = NULL; - level++; - } - } - return 1; -} - -/* - * drop a subvolume tree. - * - * this function traverses the tree freeing any blocks that only - * referenced by the tree. - * - * when a shared tree block is found. this function decreases its - * reference count by one. if update_ref is true, this function - * also make sure backrefs for the shared block and all lower level - * blocks are properly updated. - * - * If called with for_reloc == 0, may exit early with -EAGAIN - */ -int btrfs_drop_snapshot(struct btrfs_root *root, - struct btrfs_block_rsv *block_rsv, int update_ref, - int for_reloc) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_path *path; - struct btrfs_trans_handle *trans; - struct btrfs_root *tree_root = fs_info->tree_root; - struct btrfs_root_item *root_item = &root->root_item; - struct walk_control *wc; - struct btrfs_key key; - int err = 0; - int ret; - int level; - bool root_dropped = false; - - btrfs_debug(fs_info, "Drop subvolume %llu", root->objectid); - - path = btrfs_alloc_path(); - if (!path) { - err = -ENOMEM; - goto out; - } - - wc = kzalloc(sizeof(*wc), GFP_NOFS); - if (!wc) { - btrfs_free_path(path); - err = -ENOMEM; - goto out; - } - - trans = btrfs_start_transaction(tree_root, 0); - if (IS_ERR(trans)) { - err = PTR_ERR(trans); - goto out_free; - } - - if (block_rsv) - trans->block_rsv = block_rsv; - - if (btrfs_disk_key_objectid(&root_item->drop_progress) == 0) { - level = btrfs_header_level(root->node); - path->nodes[level] = btrfs_lock_root_node(root); - btrfs_set_lock_blocking(path->nodes[level]); - path->slots[level] = 0; - path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING; - memset(&wc->update_progress, 0, - sizeof(wc->update_progress)); - } else { - btrfs_disk_key_to_cpu(&key, &root_item->drop_progress); - memcpy(&wc->update_progress, &key, - sizeof(wc->update_progress)); - - level = root_item->drop_level; - BUG_ON(level == 0); - path->lowest_level = level; - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - path->lowest_level = 0; - if (ret < 0) { - err = ret; - goto out_end_trans; - } - WARN_ON(ret > 0); - - /* - * unlock our path, this is safe because only this - * function is allowed to delete this snapshot - */ - btrfs_unlock_up_safe(path, 0); - - level = btrfs_header_level(root->node); - while (1) { - btrfs_tree_lock(path->nodes[level]); - btrfs_set_lock_blocking(path->nodes[level]); - path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING; - - ret = btrfs_lookup_extent_info(trans, root, - path->nodes[level]->start, - level, 1, &wc->refs[level], - &wc->flags[level]); - if (ret < 0) { - err = ret; - goto out_end_trans; - } - BUG_ON(wc->refs[level] == 0); - - if (level == root_item->drop_level) - break; - - btrfs_tree_unlock(path->nodes[level]); - path->locks[level] = 0; - WARN_ON(wc->refs[level] != 1); - level--; - } - } - - wc->level = level; - wc->shared_level = -1; - wc->stage = DROP_REFERENCE; - wc->update_ref = update_ref; - wc->keep_locks = 0; - wc->for_reloc = for_reloc; - wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(root); - - while (1) { - - ret = walk_down_tree(trans, root, path, wc); - if (ret < 0) { - err = ret; - break; - } - - ret = walk_up_tree(trans, root, path, wc, BTRFS_MAX_LEVEL); - if (ret < 0) { - err = ret; - break; - } - - if (ret > 0) { - BUG_ON(wc->stage != DROP_REFERENCE); - break; - } - - if (wc->stage == DROP_REFERENCE) { - level = wc->level; - btrfs_node_key(path->nodes[level], - &root_item->drop_progress, - path->slots[level]); - root_item->drop_level = level; - } - - BUG_ON(wc->level == 0); - if (btrfs_should_end_transaction(trans, tree_root) || - (!for_reloc && btrfs_need_cleaner_sleep(root))) { - ret = btrfs_update_root(trans, tree_root, - &root->root_key, - root_item); - if (ret) { - btrfs_abort_transaction(trans, ret); - err = ret; - goto out_end_trans; - } - - btrfs_end_transaction_throttle(trans, tree_root); - if (!for_reloc && btrfs_need_cleaner_sleep(root)) { - btrfs_debug(fs_info, - "drop snapshot early exit"); - err = -EAGAIN; - goto out_free; - } - - trans = btrfs_start_transaction(tree_root, 0); - if (IS_ERR(trans)) { - err = PTR_ERR(trans); - goto out_free; - } - if (block_rsv) - trans->block_rsv = block_rsv; - } - } - btrfs_release_path(path); - if (err) - goto out_end_trans; - - ret = btrfs_del_root(trans, tree_root, &root->root_key); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out_end_trans; - } - - if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) { - ret = btrfs_find_root(tree_root, &root->root_key, path, - NULL, NULL); - if (ret < 0) { - btrfs_abort_transaction(trans, ret); - err = ret; - goto out_end_trans; - } else if (ret > 0) { - /* if we fail to delete the orphan item this time - * around, it'll get picked up the next time. - * - * The most common failure here is just -ENOENT. - */ - btrfs_del_orphan_item(trans, tree_root, - root->root_key.objectid); - } - } - - if (test_bit(BTRFS_ROOT_IN_RADIX, &root->state)) { - btrfs_add_dropped_root(trans, root); - } else { - free_extent_buffer(root->node); - free_extent_buffer(root->commit_root); - btrfs_put_fs_root(root); - } - root_dropped = true; -out_end_trans: - btrfs_end_transaction_throttle(trans, tree_root); -out_free: - kfree(wc); - btrfs_free_path(path); -out: - /* - * So if we need to stop dropping the snapshot for whatever reason we - * need to make sure to add it back to the dead root list so that we - * keep trying to do the work later. This also cleans up roots if we - * don't have it in the radix (like when we recover after a power fail - * or unmount) so we don't leak memory. - */ - if (!for_reloc && root_dropped == false) - btrfs_add_dead_root(root); - if (err && err != -EAGAIN) - btrfs_handle_fs_error(fs_info, err, NULL); - return err; -} - -/* - * drop subtree rooted at tree block 'node'. - * - * NOTE: this function will unlock and release tree block 'node' - * only used by relocation code - */ -int btrfs_drop_subtree(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct extent_buffer *node, - struct extent_buffer *parent) -{ - struct btrfs_path *path; - struct walk_control *wc; - int level; - int parent_level; - int ret = 0; - int wret; - - BUG_ON(root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID); - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - wc = kzalloc(sizeof(*wc), GFP_NOFS); - if (!wc) { - btrfs_free_path(path); - return -ENOMEM; - } - - btrfs_assert_tree_locked(parent); - parent_level = btrfs_header_level(parent); - extent_buffer_get(parent); - path->nodes[parent_level] = parent; - path->slots[parent_level] = btrfs_header_nritems(parent); - - btrfs_assert_tree_locked(node); - level = btrfs_header_level(node); - path->nodes[level] = node; - path->slots[level] = 0; - path->locks[level] = BTRFS_WRITE_LOCK_BLOCKING; - - wc->refs[parent_level] = 1; - wc->flags[parent_level] = BTRFS_BLOCK_FLAG_FULL_BACKREF; - wc->level = level; - wc->shared_level = -1; - wc->stage = DROP_REFERENCE; - wc->update_ref = 0; - wc->keep_locks = 1; - wc->for_reloc = 1; - wc->reada_count = BTRFS_NODEPTRS_PER_BLOCK(root); - - while (1) { - wret = walk_down_tree(trans, root, path, wc); - if (wret < 0) { - ret = wret; - break; - } - - wret = walk_up_tree(trans, root, path, wc, parent_level); - if (wret < 0) - ret = wret; - if (wret != 0) - break; - } - - kfree(wc); - btrfs_free_path(path); - return ret; -} - -static u64 update_block_group_flags(struct btrfs_root *root, u64 flags) -{ - u64 num_devices; - u64 stripped; - - /* - * if restripe for this chunk_type is on pick target profile and - * return, otherwise do the usual balance - */ - stripped = get_restripe_target(root->fs_info, flags); - if (stripped) - return extended_to_chunk(stripped); - - num_devices = root->fs_info->fs_devices->rw_devices; - - stripped = BTRFS_BLOCK_GROUP_RAID0 | - BTRFS_BLOCK_GROUP_RAID5 | BTRFS_BLOCK_GROUP_RAID6 | - BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10; - - if (num_devices == 1) { - stripped |= BTRFS_BLOCK_GROUP_DUP; - stripped = flags & ~stripped; - - /* turn raid0 into single device chunks */ - if (flags & BTRFS_BLOCK_GROUP_RAID0) - return stripped; - - /* turn mirroring into duplication */ - if (flags & (BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID10)) - return stripped | BTRFS_BLOCK_GROUP_DUP; - } else { - /* they already had raid on here, just return */ - if (flags & stripped) - return flags; - - stripped |= BTRFS_BLOCK_GROUP_DUP; - stripped = flags & ~stripped; - - /* switch duplicated blocks with raid1 */ - if (flags & BTRFS_BLOCK_GROUP_DUP) - return stripped | BTRFS_BLOCK_GROUP_RAID1; - - /* this is drive concat, leave it alone */ - } - - return flags; -} - -static int inc_block_group_ro(struct btrfs_block_group_cache *cache, int force) -{ - struct btrfs_space_info *sinfo = cache->space_info; - u64 num_bytes; - u64 min_allocable_bytes; - int ret = -ENOSPC; - - /* - * We need some metadata space and system metadata space for - * allocating chunks in some corner cases until we force to set - * it to be readonly. - */ - if ((sinfo->flags & - (BTRFS_BLOCK_GROUP_SYSTEM | BTRFS_BLOCK_GROUP_METADATA)) && - !force) - min_allocable_bytes = SZ_1M; - else - min_allocable_bytes = 0; - - spin_lock(&sinfo->lock); - spin_lock(&cache->lock); - - if (cache->ro) { - cache->ro++; - ret = 0; - goto out; - } - - num_bytes = cache->key.offset - cache->reserved - cache->pinned - - cache->bytes_super - btrfs_block_group_used(&cache->item); - - if (sinfo->bytes_used + sinfo->bytes_reserved + sinfo->bytes_pinned + - sinfo->bytes_may_use + sinfo->bytes_readonly + num_bytes + - min_allocable_bytes <= sinfo->total_bytes) { - sinfo->bytes_readonly += num_bytes; - cache->ro++; - list_add_tail(&cache->ro_list, &sinfo->ro_bgs); - ret = 0; - } -out: - spin_unlock(&cache->lock); - spin_unlock(&sinfo->lock); - return ret; -} - -int btrfs_inc_block_group_ro(struct btrfs_root *root, - struct btrfs_block_group_cache *cache) - -{ - struct btrfs_trans_handle *trans; - u64 alloc_flags; - int ret; - -again: - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - /* - * we're not allowed to set block groups readonly after the dirty - * block groups cache has started writing. If it already started, - * back off and let this transaction commit - */ - mutex_lock(&root->fs_info->ro_block_group_mutex); - if (test_bit(BTRFS_TRANS_DIRTY_BG_RUN, &trans->transaction->flags)) { - u64 transid = trans->transid; - - mutex_unlock(&root->fs_info->ro_block_group_mutex); - btrfs_end_transaction(trans, root); - - ret = btrfs_wait_for_commit(root, transid); - if (ret) - return ret; - goto again; - } - - /* - * if we are changing raid levels, try to allocate a corresponding - * block group with the new raid level. - */ - alloc_flags = update_block_group_flags(root, cache->flags); - if (alloc_flags != cache->flags) { - ret = do_chunk_alloc(trans, root, alloc_flags, - CHUNK_ALLOC_FORCE); - /* - * ENOSPC is allowed here, we may have enough space - * already allocated at the new raid level to - * carry on - */ - if (ret == -ENOSPC) - ret = 0; - if (ret < 0) - goto out; - } - - ret = inc_block_group_ro(cache, 0); - if (!ret) - goto out; - alloc_flags = get_alloc_profile(root, cache->space_info->flags); - ret = do_chunk_alloc(trans, root, alloc_flags, - CHUNK_ALLOC_FORCE); - if (ret < 0) - goto out; - ret = inc_block_group_ro(cache, 0); -out: - if (cache->flags & BTRFS_BLOCK_GROUP_SYSTEM) { - alloc_flags = update_block_group_flags(root, cache->flags); - lock_chunks(root->fs_info->chunk_root); - check_system_chunk(trans, root, alloc_flags); - unlock_chunks(root->fs_info->chunk_root); - } - mutex_unlock(&root->fs_info->ro_block_group_mutex); - - btrfs_end_transaction(trans, root); - return ret; -} - -int btrfs_force_chunk_alloc(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 type) -{ - u64 alloc_flags = get_alloc_profile(root, type); - return do_chunk_alloc(trans, root, alloc_flags, - CHUNK_ALLOC_FORCE); -} - -/* - * helper to account the unused space of all the readonly block group in the - * space_info. takes mirrors into account. - */ -u64 btrfs_account_ro_block_groups_free_space(struct btrfs_space_info *sinfo) -{ - struct btrfs_block_group_cache *block_group; - u64 free_bytes = 0; - int factor; - - /* It's df, we don't care if it's racy */ - if (list_empty(&sinfo->ro_bgs)) - return 0; - - spin_lock(&sinfo->lock); - list_for_each_entry(block_group, &sinfo->ro_bgs, ro_list) { - spin_lock(&block_group->lock); - - if (!block_group->ro) { - spin_unlock(&block_group->lock); - continue; - } - - if (block_group->flags & (BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID10 | - BTRFS_BLOCK_GROUP_DUP)) - factor = 2; - else - factor = 1; - - free_bytes += (block_group->key.offset - - btrfs_block_group_used(&block_group->item)) * - factor; - - spin_unlock(&block_group->lock); - } - spin_unlock(&sinfo->lock); - - return free_bytes; -} - -void btrfs_dec_block_group_ro(struct btrfs_root *root, - struct btrfs_block_group_cache *cache) -{ - struct btrfs_space_info *sinfo = cache->space_info; - u64 num_bytes; - - BUG_ON(!cache->ro); - - spin_lock(&sinfo->lock); - spin_lock(&cache->lock); - if (!--cache->ro) { - num_bytes = cache->key.offset - cache->reserved - - cache->pinned - cache->bytes_super - - btrfs_block_group_used(&cache->item); - sinfo->bytes_readonly -= num_bytes; - list_del_init(&cache->ro_list); - } - spin_unlock(&cache->lock); - spin_unlock(&sinfo->lock); -} - -/* - * checks to see if its even possible to relocate this block group. - * - * @return - -1 if it's not a good idea to relocate this block group, 0 if its - * ok to go ahead and try. - */ -int btrfs_can_relocate(struct btrfs_root *root, u64 bytenr) -{ - struct btrfs_block_group_cache *block_group; - struct btrfs_space_info *space_info; - struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; - struct btrfs_device *device; - struct btrfs_trans_handle *trans; - u64 min_free; - u64 dev_min = 1; - u64 dev_nr = 0; - u64 target; - int debug; - int index; - int full = 0; - int ret = 0; - - debug = btrfs_test_opt(root->fs_info, ENOSPC_DEBUG); - - block_group = btrfs_lookup_block_group(root->fs_info, bytenr); - - /* odd, couldn't find the block group, leave it alone */ - if (!block_group) { - if (debug) - btrfs_warn(root->fs_info, - "can't find block group for bytenr %llu", - bytenr); - return -1; - } - - min_free = btrfs_block_group_used(&block_group->item); - - /* no bytes used, we're good */ - if (!min_free) - goto out; - - space_info = block_group->space_info; - spin_lock(&space_info->lock); - - full = space_info->full; - - /* - * if this is the last block group we have in this space, we can't - * relocate it unless we're able to allocate a new chunk below. - * - * Otherwise, we need to make sure we have room in the space to handle - * all of the extents from this block group. If we can, we're good - */ - if ((space_info->total_bytes != block_group->key.offset) && - (space_info->bytes_used + space_info->bytes_reserved + - space_info->bytes_pinned + space_info->bytes_readonly + - min_free < space_info->total_bytes)) { - spin_unlock(&space_info->lock); - goto out; - } - spin_unlock(&space_info->lock); - - /* - * ok we don't have enough space, but maybe we have free space on our - * devices to allocate new chunks for relocation, so loop through our - * alloc devices and guess if we have enough space. if this block - * group is going to be restriped, run checks against the target - * profile instead of the current one. - */ - ret = -1; - - /* - * index: - * 0: raid10 - * 1: raid1 - * 2: dup - * 3: raid0 - * 4: single - */ - target = get_restripe_target(root->fs_info, block_group->flags); - if (target) { - index = __get_raid_index(extended_to_chunk(target)); - } else { - /* - * this is just a balance, so if we were marked as full - * we know there is no space for a new chunk - */ - if (full) { - if (debug) - btrfs_warn(root->fs_info, - "no space to alloc new chunk for block group %llu", - block_group->key.objectid); - goto out; - } - - index = get_block_group_index(block_group); - } - - if (index == BTRFS_RAID_RAID10) { - dev_min = 4; - /* Divide by 2 */ - min_free >>= 1; - } else if (index == BTRFS_RAID_RAID1) { - dev_min = 2; - } else if (index == BTRFS_RAID_DUP) { - /* Multiply by 2 */ - min_free <<= 1; - } else if (index == BTRFS_RAID_RAID0) { - dev_min = fs_devices->rw_devices; - min_free = div64_u64(min_free, dev_min); - } - - /* We need to do this so that we can look at pending chunks */ - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out; - } - - mutex_lock(&root->fs_info->chunk_mutex); - list_for_each_entry(device, &fs_devices->alloc_list, dev_alloc_list) { - u64 dev_offset; - - /* - * check to make sure we can actually find a chunk with enough - * space to fit our block group in. - */ - if (device->total_bytes > device->bytes_used + min_free && - !device->is_tgtdev_for_dev_replace) { - ret = find_free_dev_extent(trans, device, min_free, - &dev_offset, NULL); - if (!ret) - dev_nr++; - - if (dev_nr >= dev_min) - break; - - ret = -1; - } - } - if (debug && ret == -1) - btrfs_warn(root->fs_info, - "no space to allocate a new chunk for block group %llu", - block_group->key.objectid); - mutex_unlock(&root->fs_info->chunk_mutex); - btrfs_end_transaction(trans, root); -out: - btrfs_put_block_group(block_group); - return ret; -} - -static int find_first_block_group(struct btrfs_root *root, - struct btrfs_path *path, struct btrfs_key *key) -{ - int ret = 0; - struct btrfs_key found_key; - struct extent_buffer *leaf; - int slot; - - ret = btrfs_search_slot(NULL, root, key, path, 0, 0); - if (ret < 0) - goto out; - - while (1) { - slot = path->slots[0]; - leaf = path->nodes[0]; - if (slot >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(root, path); - if (ret == 0) - continue; - if (ret < 0) - goto out; - break; - } - btrfs_item_key_to_cpu(leaf, &found_key, slot); - - if (found_key.objectid >= key->objectid && - found_key.type == BTRFS_BLOCK_GROUP_ITEM_KEY) { - struct extent_map_tree *em_tree; - struct extent_map *em; - - em_tree = &root->fs_info->mapping_tree.map_tree; - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, found_key.objectid, - found_key.offset); - read_unlock(&em_tree->lock); - if (!em) { - btrfs_err(root->fs_info, - "logical %llu len %llu found bg but no related chunk", - found_key.objectid, found_key.offset); - ret = -ENOENT; - } else { - ret = 0; - } - free_extent_map(em); - goto out; - } - path->slots[0]++; - } -out: - return ret; -} - -void btrfs_put_block_group_cache(struct btrfs_fs_info *info) -{ - struct btrfs_block_group_cache *block_group; - u64 last = 0; - - while (1) { - struct inode *inode; - - block_group = btrfs_lookup_first_block_group(info, last); - while (block_group) { - spin_lock(&block_group->lock); - if (block_group->iref) - break; - spin_unlock(&block_group->lock); - block_group = next_block_group(info->tree_root, - block_group); - } - if (!block_group) { - if (last == 0) - break; - last = 0; - continue; - } - - inode = block_group->inode; - block_group->iref = 0; - block_group->inode = NULL; - spin_unlock(&block_group->lock); - ASSERT(block_group->io_ctl.inode == NULL); - iput(inode); - last = block_group->key.objectid + block_group->key.offset; - btrfs_put_block_group(block_group); - } -} - -int btrfs_free_block_groups(struct btrfs_fs_info *info) -{ - struct btrfs_block_group_cache *block_group; - struct btrfs_space_info *space_info; - struct btrfs_caching_control *caching_ctl; - struct rb_node *n; - - down_write(&info->commit_root_sem); - while (!list_empty(&info->caching_block_groups)) { - caching_ctl = list_entry(info->caching_block_groups.next, - struct btrfs_caching_control, list); - list_del(&caching_ctl->list); - put_caching_control(caching_ctl); - } - up_write(&info->commit_root_sem); - - spin_lock(&info->unused_bgs_lock); - while (!list_empty(&info->unused_bgs)) { - block_group = list_first_entry(&info->unused_bgs, - struct btrfs_block_group_cache, - bg_list); - list_del_init(&block_group->bg_list); - btrfs_put_block_group(block_group); - } - spin_unlock(&info->unused_bgs_lock); - - spin_lock(&info->block_group_cache_lock); - while ((n = rb_last(&info->block_group_cache_tree)) != NULL) { - block_group = rb_entry(n, struct btrfs_block_group_cache, - cache_node); - rb_erase(&block_group->cache_node, - &info->block_group_cache_tree); - RB_CLEAR_NODE(&block_group->cache_node); - spin_unlock(&info->block_group_cache_lock); - - down_write(&block_group->space_info->groups_sem); - list_del(&block_group->list); - up_write(&block_group->space_info->groups_sem); - - if (block_group->cached == BTRFS_CACHE_STARTED) - wait_block_group_cache_done(block_group); - - /* - * We haven't cached this block group, which means we could - * possibly have excluded extents on this block group. - */ - if (block_group->cached == BTRFS_CACHE_NO || - block_group->cached == BTRFS_CACHE_ERROR) - free_excluded_extents(info->extent_root, block_group); - - btrfs_remove_free_space_cache(block_group); - ASSERT(list_empty(&block_group->dirty_list)); - ASSERT(list_empty(&block_group->io_list)); - ASSERT(list_empty(&block_group->bg_list)); - ASSERT(atomic_read(&block_group->count) == 1); - btrfs_put_block_group(block_group); - - spin_lock(&info->block_group_cache_lock); - } - spin_unlock(&info->block_group_cache_lock); - - /* now that all the block groups are freed, go through and - * free all the space_info structs. This is only called during - * the final stages of unmount, and so we know nobody is - * using them. We call synchronize_rcu() once before we start, - * just to be on the safe side. - */ - synchronize_rcu(); - - release_global_block_rsv(info); - - while (!list_empty(&info->space_info)) { - int i; - - space_info = list_entry(info->space_info.next, - struct btrfs_space_info, - list); - - /* - * Do not hide this behind enospc_debug, this is actually - * important and indicates a real bug if this happens. - */ - if (WARN_ON(space_info->bytes_pinned > 0 || - space_info->bytes_reserved > 0 || - space_info->bytes_may_use > 0)) - dump_space_info(info, space_info, 0, 0); - list_del(&space_info->list); - for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) { - struct kobject *kobj; - kobj = space_info->block_group_kobjs[i]; - space_info->block_group_kobjs[i] = NULL; - if (kobj) { - kobject_del(kobj); - kobject_put(kobj); - } - } - kobject_del(&space_info->kobj); - kobject_put(&space_info->kobj); - } - return 0; -} - -static void __link_block_group(struct btrfs_space_info *space_info, - struct btrfs_block_group_cache *cache) -{ - int index = get_block_group_index(cache); - bool first = false; - - down_write(&space_info->groups_sem); - if (list_empty(&space_info->block_groups[index])) - first = true; - list_add_tail(&cache->list, &space_info->block_groups[index]); - up_write(&space_info->groups_sem); - - if (first) { - struct raid_kobject *rkobj; - int ret; - - rkobj = kzalloc(sizeof(*rkobj), GFP_NOFS); - if (!rkobj) - goto out_err; - rkobj->raid_type = index; - kobject_init(&rkobj->kobj, &btrfs_raid_ktype); - ret = kobject_add(&rkobj->kobj, &space_info->kobj, - "%s", get_raid_name(index)); - if (ret) { - kobject_put(&rkobj->kobj); - goto out_err; - } - space_info->block_group_kobjs[index] = &rkobj->kobj; - } - - return; -out_err: - btrfs_warn(cache->fs_info, - "failed to add kobject for block cache, ignoring"); -} - -static struct btrfs_block_group_cache * -btrfs_create_block_group_cache(struct btrfs_root *root, u64 start, u64 size) -{ - struct btrfs_block_group_cache *cache; - - cache = kzalloc(sizeof(*cache), GFP_NOFS); - if (!cache) - return NULL; - - cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl), - GFP_NOFS); - if (!cache->free_space_ctl) { - kfree(cache); - return NULL; - } - - cache->key.objectid = start; - cache->key.offset = size; - cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY; - - cache->sectorsize = root->sectorsize; - cache->fs_info = root->fs_info; - cache->full_stripe_len = btrfs_full_stripe_len(root, - &root->fs_info->mapping_tree, - start); - set_free_space_tree_thresholds(cache); - - atomic_set(&cache->count, 1); - spin_lock_init(&cache->lock); - init_rwsem(&cache->data_rwsem); - INIT_LIST_HEAD(&cache->list); - INIT_LIST_HEAD(&cache->cluster_list); - INIT_LIST_HEAD(&cache->bg_list); - INIT_LIST_HEAD(&cache->ro_list); - INIT_LIST_HEAD(&cache->dirty_list); - INIT_LIST_HEAD(&cache->io_list); - btrfs_init_free_space_ctl(cache); - atomic_set(&cache->trimming, 0); - mutex_init(&cache->free_space_lock); - - return cache; -} - -int btrfs_read_block_groups(struct btrfs_root *root) -{ - struct btrfs_path *path; - int ret; - struct btrfs_block_group_cache *cache; - struct btrfs_fs_info *info = root->fs_info; - struct btrfs_space_info *space_info; - struct btrfs_key key; - struct btrfs_key found_key; - struct extent_buffer *leaf; - int need_clear = 0; - u64 cache_gen; - u64 feature; - int mixed; - - feature = btrfs_super_incompat_flags(info->super_copy); - mixed = !!(feature & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS); - - root = info->extent_root; - key.objectid = 0; - key.offset = 0; - key.type = BTRFS_BLOCK_GROUP_ITEM_KEY; - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->reada = READA_FORWARD; - - cache_gen = btrfs_super_cache_generation(root->fs_info->super_copy); - if (btrfs_test_opt(root->fs_info, SPACE_CACHE) && - btrfs_super_generation(root->fs_info->super_copy) != cache_gen) - need_clear = 1; - if (btrfs_test_opt(root->fs_info, CLEAR_CACHE)) - need_clear = 1; - - while (1) { - ret = find_first_block_group(root, path, &key); - if (ret > 0) - break; - if (ret != 0) - goto error; - - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - - cache = btrfs_create_block_group_cache(root, found_key.objectid, - found_key.offset); - if (!cache) { - ret = -ENOMEM; - goto error; - } - - if (need_clear) { - /* - * When we mount with old space cache, we need to - * set BTRFS_DC_CLEAR and set dirty flag. - * - * a) Setting 'BTRFS_DC_CLEAR' makes sure that we - * truncate the old free space cache inode and - * setup a new one. - * b) Setting 'dirty flag' makes sure that we flush - * the new space cache info onto disk. - */ - if (btrfs_test_opt(root->fs_info, SPACE_CACHE)) - cache->disk_cache_state = BTRFS_DC_CLEAR; - } - - read_extent_buffer(leaf, &cache->item, - btrfs_item_ptr_offset(leaf, path->slots[0]), - sizeof(cache->item)); - cache->flags = btrfs_block_group_flags(&cache->item); - if (!mixed && - ((cache->flags & BTRFS_BLOCK_GROUP_METADATA) && - (cache->flags & BTRFS_BLOCK_GROUP_DATA))) { - btrfs_err(info, -"bg %llu is a mixed block group but filesystem hasn't enabled mixed block groups", - cache->key.objectid); - ret = -EINVAL; - goto error; - } - - key.objectid = found_key.objectid + found_key.offset; - btrfs_release_path(path); - - /* - * We need to exclude the super stripes now so that the space - * info has super bytes accounted for, otherwise we'll think - * we have more space than we actually do. - */ - ret = exclude_super_stripes(root, cache); - if (ret) { - /* - * We may have excluded something, so call this just in - * case. - */ - free_excluded_extents(root, cache); - btrfs_put_block_group(cache); - goto error; - } - - /* - * check for two cases, either we are full, and therefore - * don't need to bother with the caching work since we won't - * find any space, or we are empty, and we can just add all - * the space in and be done with it. This saves us _alot_ of - * time, particularly in the full case. - */ - if (found_key.offset == btrfs_block_group_used(&cache->item)) { - cache->last_byte_to_unpin = (u64)-1; - cache->cached = BTRFS_CACHE_FINISHED; - free_excluded_extents(root, cache); - } else if (btrfs_block_group_used(&cache->item) == 0) { - cache->last_byte_to_unpin = (u64)-1; - cache->cached = BTRFS_CACHE_FINISHED; - add_new_free_space(cache, root->fs_info, - found_key.objectid, - found_key.objectid + - found_key.offset); - free_excluded_extents(root, cache); - } - - ret = btrfs_add_block_group_cache(root->fs_info, cache); - if (ret) { - btrfs_remove_free_space_cache(cache); - btrfs_put_block_group(cache); - goto error; - } - - trace_btrfs_add_block_group(root->fs_info, cache, 0); - ret = update_space_info(info, cache->flags, found_key.offset, - btrfs_block_group_used(&cache->item), - cache->bytes_super, &space_info); - if (ret) { - btrfs_remove_free_space_cache(cache); - spin_lock(&info->block_group_cache_lock); - rb_erase(&cache->cache_node, - &info->block_group_cache_tree); - RB_CLEAR_NODE(&cache->cache_node); - spin_unlock(&info->block_group_cache_lock); - btrfs_put_block_group(cache); - goto error; - } - - cache->space_info = space_info; - - __link_block_group(space_info, cache); - - set_avail_alloc_bits(root->fs_info, cache->flags); - if (btrfs_chunk_readonly(root, cache->key.objectid)) { - inc_block_group_ro(cache, 1); - } else if (btrfs_block_group_used(&cache->item) == 0) { - spin_lock(&info->unused_bgs_lock); - /* Should always be true but just in case. */ - if (list_empty(&cache->bg_list)) { - btrfs_get_block_group(cache); - list_add_tail(&cache->bg_list, - &info->unused_bgs); - } - spin_unlock(&info->unused_bgs_lock); - } - } - - list_for_each_entry_rcu(space_info, &root->fs_info->space_info, list) { - if (!(get_alloc_profile(root, space_info->flags) & - (BTRFS_BLOCK_GROUP_RAID10 | - BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID5 | - BTRFS_BLOCK_GROUP_RAID6 | - BTRFS_BLOCK_GROUP_DUP))) - continue; - /* - * avoid allocating from un-mirrored block group if there are - * mirrored block groups. - */ - list_for_each_entry(cache, - &space_info->block_groups[BTRFS_RAID_RAID0], - list) - inc_block_group_ro(cache, 1); - list_for_each_entry(cache, - &space_info->block_groups[BTRFS_RAID_SINGLE], - list) - inc_block_group_ro(cache, 1); - } - - init_global_block_rsv(info); - ret = 0; -error: - btrfs_free_path(path); - return ret; -} - -void btrfs_create_pending_block_groups(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_block_group_cache *block_group, *tmp; - struct btrfs_root *extent_root = root->fs_info->extent_root; - struct btrfs_block_group_item item; - struct btrfs_key key; - int ret = 0; - bool can_flush_pending_bgs = trans->can_flush_pending_bgs; - - trans->can_flush_pending_bgs = false; - list_for_each_entry_safe(block_group, tmp, &trans->new_bgs, bg_list) { - if (ret) - goto next; - - spin_lock(&block_group->lock); - memcpy(&item, &block_group->item, sizeof(item)); - memcpy(&key, &block_group->key, sizeof(key)); - spin_unlock(&block_group->lock); - - ret = btrfs_insert_item(trans, extent_root, &key, &item, - sizeof(item)); - if (ret) - btrfs_abort_transaction(trans, ret); - ret = btrfs_finish_chunk_alloc(trans, extent_root, - key.objectid, key.offset); - if (ret) - btrfs_abort_transaction(trans, ret); - add_block_group_free_space(trans, root->fs_info, block_group); - /* already aborted the transaction if it failed. */ -next: - list_del_init(&block_group->bg_list); - } - trans->can_flush_pending_bgs = can_flush_pending_bgs; -} - -int btrfs_make_block_group(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 bytes_used, - u64 type, u64 chunk_objectid, u64 chunk_offset, - u64 size) -{ - int ret; - struct btrfs_root *extent_root; - struct btrfs_block_group_cache *cache; - extent_root = root->fs_info->extent_root; - - btrfs_set_log_full_commit(root->fs_info, trans); - - cache = btrfs_create_block_group_cache(root, chunk_offset, size); - if (!cache) - return -ENOMEM; - - btrfs_set_block_group_used(&cache->item, bytes_used); - btrfs_set_block_group_chunk_objectid(&cache->item, chunk_objectid); - btrfs_set_block_group_flags(&cache->item, type); - - cache->flags = type; - cache->last_byte_to_unpin = (u64)-1; - cache->cached = BTRFS_CACHE_FINISHED; - cache->needs_free_space = 1; - ret = exclude_super_stripes(root, cache); - if (ret) { - /* - * We may have excluded something, so call this just in - * case. - */ - free_excluded_extents(root, cache); - btrfs_put_block_group(cache); - return ret; - } - - add_new_free_space(cache, root->fs_info, chunk_offset, - chunk_offset + size); - - free_excluded_extents(root, cache); - -#ifdef CONFIG_BTRFS_DEBUG - if (btrfs_should_fragment_free_space(root, cache)) { - u64 new_bytes_used = size - bytes_used; - - bytes_used += new_bytes_used >> 1; - fragment_free_space(root, cache); - } -#endif - /* - * Call to ensure the corresponding space_info object is created and - * assigned to our block group, but don't update its counters just yet. - * We want our bg to be added to the rbtree with its ->space_info set. - */ - ret = update_space_info(root->fs_info, cache->flags, 0, 0, 0, - &cache->space_info); - if (ret) { - btrfs_remove_free_space_cache(cache); - btrfs_put_block_group(cache); - return ret; - } - - ret = btrfs_add_block_group_cache(root->fs_info, cache); - if (ret) { - btrfs_remove_free_space_cache(cache); - btrfs_put_block_group(cache); - return ret; - } - - /* - * Now that our block group has its ->space_info set and is inserted in - * the rbtree, update the space info's counters. - */ - trace_btrfs_add_block_group(root->fs_info, cache, 1); - ret = update_space_info(root->fs_info, cache->flags, size, bytes_used, - cache->bytes_super, &cache->space_info); - if (ret) { - btrfs_remove_free_space_cache(cache); - spin_lock(&root->fs_info->block_group_cache_lock); - rb_erase(&cache->cache_node, - &root->fs_info->block_group_cache_tree); - RB_CLEAR_NODE(&cache->cache_node); - spin_unlock(&root->fs_info->block_group_cache_lock); - btrfs_put_block_group(cache); - return ret; - } - update_global_block_rsv(root->fs_info); - - __link_block_group(cache->space_info, cache); - - list_add_tail(&cache->bg_list, &trans->new_bgs); - - set_avail_alloc_bits(extent_root->fs_info, type); - return 0; -} - -static void clear_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags) -{ - u64 extra_flags = chunk_to_extended(flags) & - BTRFS_EXTENDED_PROFILE_MASK; - - write_seqlock(&fs_info->profiles_lock); - if (flags & BTRFS_BLOCK_GROUP_DATA) - fs_info->avail_data_alloc_bits &= ~extra_flags; - if (flags & BTRFS_BLOCK_GROUP_METADATA) - fs_info->avail_metadata_alloc_bits &= ~extra_flags; - if (flags & BTRFS_BLOCK_GROUP_SYSTEM) - fs_info->avail_system_alloc_bits &= ~extra_flags; - write_sequnlock(&fs_info->profiles_lock); -} - -int btrfs_remove_block_group(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 group_start, - struct extent_map *em) -{ - struct btrfs_path *path; - struct btrfs_block_group_cache *block_group; - struct btrfs_free_cluster *cluster; - struct btrfs_root *tree_root = root->fs_info->tree_root; - struct btrfs_key key; - struct inode *inode; - struct kobject *kobj = NULL; - int ret; - int index; - int factor; - struct btrfs_caching_control *caching_ctl = NULL; - bool remove_em; - - root = root->fs_info->extent_root; - - block_group = btrfs_lookup_block_group(root->fs_info, group_start); - BUG_ON(!block_group); - BUG_ON(!block_group->ro); - - /* - * Free the reserved super bytes from this block group before - * remove it. - */ - free_excluded_extents(root, block_group); - - memcpy(&key, &block_group->key, sizeof(key)); - index = get_block_group_index(block_group); - if (block_group->flags & (BTRFS_BLOCK_GROUP_DUP | - BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID10)) - factor = 2; - else - factor = 1; - - /* make sure this block group isn't part of an allocation cluster */ - cluster = &root->fs_info->data_alloc_cluster; - spin_lock(&cluster->refill_lock); - btrfs_return_cluster_to_free_space(block_group, cluster); - spin_unlock(&cluster->refill_lock); - - /* - * make sure this block group isn't part of a metadata - * allocation cluster - */ - cluster = &root->fs_info->meta_alloc_cluster; - spin_lock(&cluster->refill_lock); - btrfs_return_cluster_to_free_space(block_group, cluster); - spin_unlock(&cluster->refill_lock); - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - /* - * get the inode first so any iput calls done for the io_list - * aren't the final iput (no unlinks allowed now) - */ - inode = lookup_free_space_inode(tree_root, block_group, path); - - mutex_lock(&trans->transaction->cache_write_mutex); - /* - * make sure our free spache cache IO is done before remove the - * free space inode - */ - spin_lock(&trans->transaction->dirty_bgs_lock); - if (!list_empty(&block_group->io_list)) { - list_del_init(&block_group->io_list); - - WARN_ON(!IS_ERR(inode) && inode != block_group->io_ctl.inode); - - spin_unlock(&trans->transaction->dirty_bgs_lock); - btrfs_wait_cache_io(root, trans, block_group, - &block_group->io_ctl, path, - block_group->key.objectid); - btrfs_put_block_group(block_group); - spin_lock(&trans->transaction->dirty_bgs_lock); - } - - if (!list_empty(&block_group->dirty_list)) { - list_del_init(&block_group->dirty_list); - btrfs_put_block_group(block_group); - } - spin_unlock(&trans->transaction->dirty_bgs_lock); - mutex_unlock(&trans->transaction->cache_write_mutex); - - if (!IS_ERR(inode)) { - ret = btrfs_orphan_add(trans, inode); - if (ret) { - btrfs_add_delayed_iput(inode); - goto out; - } - clear_nlink(inode); - /* One for the block groups ref */ - spin_lock(&block_group->lock); - if (block_group->iref) { - block_group->iref = 0; - block_group->inode = NULL; - spin_unlock(&block_group->lock); - iput(inode); - } else { - spin_unlock(&block_group->lock); - } - /* One for our lookup ref */ - btrfs_add_delayed_iput(inode); - } - - key.objectid = BTRFS_FREE_SPACE_OBJECTID; - key.offset = block_group->key.objectid; - key.type = 0; - - ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1); - if (ret < 0) - goto out; - if (ret > 0) - btrfs_release_path(path); - if (ret == 0) { - ret = btrfs_del_item(trans, tree_root, path); - if (ret) - goto out; - btrfs_release_path(path); - } - - spin_lock(&root->fs_info->block_group_cache_lock); - rb_erase(&block_group->cache_node, - &root->fs_info->block_group_cache_tree); - RB_CLEAR_NODE(&block_group->cache_node); - - if (root->fs_info->first_logical_byte == block_group->key.objectid) - root->fs_info->first_logical_byte = (u64)-1; - spin_unlock(&root->fs_info->block_group_cache_lock); - - down_write(&block_group->space_info->groups_sem); - /* - * we must use list_del_init so people can check to see if they - * are still on the list after taking the semaphore - */ - list_del_init(&block_group->list); - if (list_empty(&block_group->space_info->block_groups[index])) { - kobj = block_group->space_info->block_group_kobjs[index]; - block_group->space_info->block_group_kobjs[index] = NULL; - clear_avail_alloc_bits(root->fs_info, block_group->flags); - } - up_write(&block_group->space_info->groups_sem); - if (kobj) { - kobject_del(kobj); - kobject_put(kobj); - } - - if (block_group->has_caching_ctl) - caching_ctl = get_caching_control(block_group); - if (block_group->cached == BTRFS_CACHE_STARTED) - wait_block_group_cache_done(block_group); - if (block_group->has_caching_ctl) { - down_write(&root->fs_info->commit_root_sem); - if (!caching_ctl) { - struct btrfs_caching_control *ctl; - - list_for_each_entry(ctl, - &root->fs_info->caching_block_groups, list) - if (ctl->block_group == block_group) { - caching_ctl = ctl; - atomic_inc(&caching_ctl->count); - break; - } - } - if (caching_ctl) - list_del_init(&caching_ctl->list); - up_write(&root->fs_info->commit_root_sem); - if (caching_ctl) { - /* Once for the caching bgs list and once for us. */ - put_caching_control(caching_ctl); - put_caching_control(caching_ctl); - } - } - - spin_lock(&trans->transaction->dirty_bgs_lock); - if (!list_empty(&block_group->dirty_list)) { - WARN_ON(1); - } - if (!list_empty(&block_group->io_list)) { - WARN_ON(1); - } - spin_unlock(&trans->transaction->dirty_bgs_lock); - btrfs_remove_free_space_cache(block_group); - - spin_lock(&block_group->space_info->lock); - list_del_init(&block_group->ro_list); - - if (btrfs_test_opt(root->fs_info, ENOSPC_DEBUG)) { - WARN_ON(block_group->space_info->total_bytes - < block_group->key.offset); - WARN_ON(block_group->space_info->bytes_readonly - < block_group->key.offset); - WARN_ON(block_group->space_info->disk_total - < block_group->key.offset * factor); - } - block_group->space_info->total_bytes -= block_group->key.offset; - block_group->space_info->bytes_readonly -= block_group->key.offset; - block_group->space_info->disk_total -= block_group->key.offset * factor; - - spin_unlock(&block_group->space_info->lock); - - memcpy(&key, &block_group->key, sizeof(key)); - - lock_chunks(root); - if (!list_empty(&em->list)) { - /* We're in the transaction->pending_chunks list. */ - free_extent_map(em); - } - spin_lock(&block_group->lock); - block_group->removed = 1; - /* - * At this point trimming can't start on this block group, because we - * removed the block group from the tree fs_info->block_group_cache_tree - * so no one can't find it anymore and even if someone already got this - * block group before we removed it from the rbtree, they have already - * incremented block_group->trimming - if they didn't, they won't find - * any free space entries because we already removed them all when we - * called btrfs_remove_free_space_cache(). - * - * And we must not remove the extent map from the fs_info->mapping_tree - * to prevent the same logical address range and physical device space - * ranges from being reused for a new block group. This is because our - * fs trim operation (btrfs_trim_fs() / btrfs_ioctl_fitrim()) is - * completely transactionless, so while it is trimming a range the - * currently running transaction might finish and a new one start, - * allowing for new block groups to be created that can reuse the same - * physical device locations unless we take this special care. - * - * There may also be an implicit trim operation if the file system - * is mounted with -odiscard. The same protections must remain - * in place until the extents have been discarded completely when - * the transaction commit has completed. - */ - remove_em = (atomic_read(&block_group->trimming) == 0); - /* - * Make sure a trimmer task always sees the em in the pinned_chunks list - * if it sees block_group->removed == 1 (needs to lock block_group->lock - * before checking block_group->removed). - */ - if (!remove_em) { - /* - * Our em might be in trans->transaction->pending_chunks which - * is protected by fs_info->chunk_mutex ([lock|unlock]_chunks), - * and so is the fs_info->pinned_chunks list. - * - * So at this point we must be holding the chunk_mutex to avoid - * any races with chunk allocation (more specifically at - * volumes.c:contains_pending_extent()), to ensure it always - * sees the em, either in the pending_chunks list or in the - * pinned_chunks list. - */ - list_move_tail(&em->list, &root->fs_info->pinned_chunks); - } - spin_unlock(&block_group->lock); - - if (remove_em) { - struct extent_map_tree *em_tree; - - em_tree = &root->fs_info->mapping_tree.map_tree; - write_lock(&em_tree->lock); - /* - * The em might be in the pending_chunks list, so make sure the - * chunk mutex is locked, since remove_extent_mapping() will - * delete us from that list. - */ - remove_extent_mapping(em_tree, em); - write_unlock(&em_tree->lock); - /* once for the tree */ - free_extent_map(em); - } - - unlock_chunks(root); - - ret = remove_block_group_free_space(trans, root->fs_info, block_group); - if (ret) - goto out; - - btrfs_put_block_group(block_group); - btrfs_put_block_group(block_group); - - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret > 0) - ret = -EIO; - if (ret < 0) - goto out; - - ret = btrfs_del_item(trans, root, path); -out: - btrfs_free_path(path); - return ret; -} - -struct btrfs_trans_handle * -btrfs_start_trans_remove_block_group(struct btrfs_fs_info *fs_info, - const u64 chunk_offset) -{ - struct extent_map_tree *em_tree = &fs_info->mapping_tree.map_tree; - struct extent_map *em; - struct map_lookup *map; - unsigned int num_items; - - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, chunk_offset, 1); - read_unlock(&em_tree->lock); - ASSERT(em && em->start == chunk_offset); - - /* - * We need to reserve 3 + N units from the metadata space info in order - * to remove a block group (done at btrfs_remove_chunk() and at - * btrfs_remove_block_group()), which are used for: - * - * 1 unit for adding the free space inode's orphan (located in the tree - * of tree roots). - * 1 unit for deleting the block group item (located in the extent - * tree). - * 1 unit for deleting the free space item (located in tree of tree - * roots). - * N units for deleting N device extent items corresponding to each - * stripe (located in the device tree). - * - * In order to remove a block group we also need to reserve units in the - * system space info in order to update the chunk tree (update one or - * more device items and remove one chunk item), but this is done at - * btrfs_remove_chunk() through a call to check_system_chunk(). - */ - map = em->map_lookup; - num_items = 3 + map->num_stripes; - free_extent_map(em); - - return btrfs_start_transaction_fallback_global_rsv(fs_info->extent_root, - num_items, 1); -} - -/* - * Process the unused_bgs list and remove any that don't have any allocated - * space inside of them. - */ -void btrfs_delete_unused_bgs(struct btrfs_fs_info *fs_info) -{ - struct btrfs_block_group_cache *block_group; - struct btrfs_space_info *space_info; - struct btrfs_root *root = fs_info->extent_root; - struct btrfs_trans_handle *trans; - int ret = 0; - - if (!test_bit(BTRFS_FS_OPEN, &fs_info->flags)) - return; - - spin_lock(&fs_info->unused_bgs_lock); - while (!list_empty(&fs_info->unused_bgs)) { - u64 start, end; - int trimming; - - block_group = list_first_entry(&fs_info->unused_bgs, - struct btrfs_block_group_cache, - bg_list); - list_del_init(&block_group->bg_list); - - space_info = block_group->space_info; - - if (ret || btrfs_mixed_space_info(space_info)) { - btrfs_put_block_group(block_group); - continue; - } - spin_unlock(&fs_info->unused_bgs_lock); - - mutex_lock(&fs_info->delete_unused_bgs_mutex); - - /* Don't want to race with allocators so take the groups_sem */ - down_write(&space_info->groups_sem); - spin_lock(&block_group->lock); - if (block_group->reserved || - btrfs_block_group_used(&block_group->item) || - block_group->ro || - list_is_singular(&block_group->list)) { - /* - * We want to bail if we made new allocations or have - * outstanding allocations in this block group. We do - * the ro check in case balance is currently acting on - * this block group. - */ - spin_unlock(&block_group->lock); - up_write(&space_info->groups_sem); - goto next; - } - spin_unlock(&block_group->lock); - - /* We don't want to force the issue, only flip if it's ok. */ - ret = inc_block_group_ro(block_group, 0); - up_write(&space_info->groups_sem); - if (ret < 0) { - ret = 0; - goto next; - } - - /* - * Want to do this before we do anything else so we can recover - * properly if we fail to join the transaction. - */ - trans = btrfs_start_trans_remove_block_group(fs_info, - block_group->key.objectid); - if (IS_ERR(trans)) { - btrfs_dec_block_group_ro(root, block_group); - ret = PTR_ERR(trans); - goto next; - } - - /* - * We could have pending pinned extents for this block group, - * just delete them, we don't care about them anymore. - */ - start = block_group->key.objectid; - end = start + block_group->key.offset - 1; - /* - * Hold the unused_bg_unpin_mutex lock to avoid racing with - * btrfs_finish_extent_commit(). If we are at transaction N, - * another task might be running finish_extent_commit() for the - * previous transaction N - 1, and have seen a range belonging - * to the block group in freed_extents[] before we were able to - * clear the whole block group range from freed_extents[]. This - * means that task can lookup for the block group after we - * unpinned it from freed_extents[] and removed it, leading to - * a BUG_ON() at btrfs_unpin_extent_range(). - */ - mutex_lock(&fs_info->unused_bg_unpin_mutex); - ret = clear_extent_bits(&fs_info->freed_extents[0], start, end, - EXTENT_DIRTY); - if (ret) { - mutex_unlock(&fs_info->unused_bg_unpin_mutex); - btrfs_dec_block_group_ro(root, block_group); - goto end_trans; - } - ret = clear_extent_bits(&fs_info->freed_extents[1], start, end, - EXTENT_DIRTY); - if (ret) { - mutex_unlock(&fs_info->unused_bg_unpin_mutex); - btrfs_dec_block_group_ro(root, block_group); - goto end_trans; - } - mutex_unlock(&fs_info->unused_bg_unpin_mutex); - - /* Reset pinned so btrfs_put_block_group doesn't complain */ - spin_lock(&space_info->lock); - spin_lock(&block_group->lock); - - space_info->bytes_pinned -= block_group->pinned; - space_info->bytes_readonly += block_group->pinned; - percpu_counter_add(&space_info->total_bytes_pinned, - -block_group->pinned); - block_group->pinned = 0; - - spin_unlock(&block_group->lock); - spin_unlock(&space_info->lock); - - /* DISCARD can flip during remount */ - trimming = btrfs_test_opt(root->fs_info, DISCARD); - - /* Implicit trim during transaction commit. */ - if (trimming) - btrfs_get_block_group_trimming(block_group); - - /* - * Btrfs_remove_chunk will abort the transaction if things go - * horribly wrong. - */ - ret = btrfs_remove_chunk(trans, root, - block_group->key.objectid); - - if (ret) { - if (trimming) - btrfs_put_block_group_trimming(block_group); - goto end_trans; - } - - /* - * If we're not mounted with -odiscard, we can just forget - * about this block group. Otherwise we'll need to wait - * until transaction commit to do the actual discard. - */ - if (trimming) { - spin_lock(&fs_info->unused_bgs_lock); - /* - * A concurrent scrub might have added us to the list - * fs_info->unused_bgs, so use a list_move operation - * to add the block group to the deleted_bgs list. - */ - list_move(&block_group->bg_list, - &trans->transaction->deleted_bgs); - spin_unlock(&fs_info->unused_bgs_lock); - btrfs_get_block_group(block_group); - } -end_trans: - btrfs_end_transaction(trans, root); -next: - mutex_unlock(&fs_info->delete_unused_bgs_mutex); - btrfs_put_block_group(block_group); - spin_lock(&fs_info->unused_bgs_lock); - } - spin_unlock(&fs_info->unused_bgs_lock); -} - -int btrfs_init_space_info(struct btrfs_fs_info *fs_info) -{ - struct btrfs_space_info *space_info; - struct btrfs_super_block *disk_super; - u64 features; - u64 flags; - int mixed = 0; - int ret; - - disk_super = fs_info->super_copy; - if (!btrfs_super_root(disk_super)) - return -EINVAL; - - features = btrfs_super_incompat_flags(disk_super); - if (features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) - mixed = 1; - - flags = BTRFS_BLOCK_GROUP_SYSTEM; - ret = update_space_info(fs_info, flags, 0, 0, 0, &space_info); - if (ret) - goto out; - - if (mixed) { - flags = BTRFS_BLOCK_GROUP_METADATA | BTRFS_BLOCK_GROUP_DATA; - ret = update_space_info(fs_info, flags, 0, 0, 0, &space_info); - } else { - flags = BTRFS_BLOCK_GROUP_METADATA; - ret = update_space_info(fs_info, flags, 0, 0, 0, &space_info); - if (ret) - goto out; - - flags = BTRFS_BLOCK_GROUP_DATA; - ret = update_space_info(fs_info, flags, 0, 0, 0, &space_info); - } -out: - return ret; -} - -int btrfs_error_unpin_extent_range(struct btrfs_root *root, u64 start, u64 end) -{ - return unpin_extent_range(root, start, end, false); -} - -/* - * It used to be that old block groups would be left around forever. - * Iterating over them would be enough to trim unused space. Since we - * now automatically remove them, we also need to iterate over unallocated - * space. - * - * We don't want a transaction for this since the discard may take a - * substantial amount of time. We don't require that a transaction be - * running, but we do need to take a running transaction into account - * to ensure that we're not discarding chunks that were released in - * the current transaction. - * - * Holding the chunks lock will prevent other threads from allocating - * or releasing chunks, but it won't prevent a running transaction - * from committing and releasing the memory that the pending chunks - * list head uses. For that, we need to take a reference to the - * transaction. - */ -static int btrfs_trim_free_extents(struct btrfs_device *device, - u64 minlen, u64 *trimmed) -{ - u64 start = 0, len = 0; - int ret; - - *trimmed = 0; - - /* Not writeable = nothing to do. */ - if (!device->writeable) - return 0; - - /* No free space = nothing to do. */ - if (device->total_bytes <= device->bytes_used) - return 0; - - ret = 0; - - while (1) { - struct btrfs_fs_info *fs_info = device->dev_root->fs_info; - struct btrfs_transaction *trans; - u64 bytes; - - ret = mutex_lock_interruptible(&fs_info->chunk_mutex); - if (ret) - return ret; - - down_read(&fs_info->commit_root_sem); - - spin_lock(&fs_info->trans_lock); - trans = fs_info->running_transaction; - if (trans) - atomic_inc(&trans->use_count); - spin_unlock(&fs_info->trans_lock); - - ret = find_free_dev_extent_start(trans, device, minlen, start, - &start, &len); - if (trans) - btrfs_put_transaction(trans); - - if (ret) { - up_read(&fs_info->commit_root_sem); - mutex_unlock(&fs_info->chunk_mutex); - if (ret == -ENOSPC) - ret = 0; - break; - } - - ret = btrfs_issue_discard(device->bdev, start, len, &bytes); - up_read(&fs_info->commit_root_sem); - mutex_unlock(&fs_info->chunk_mutex); - - if (ret) - break; - - start += len; - *trimmed += bytes; - - if (fatal_signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - - cond_resched(); - } - - return ret; -} - -int btrfs_trim_fs(struct btrfs_root *root, struct fstrim_range *range) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_block_group_cache *cache = NULL; - struct btrfs_device *device; - struct list_head *devices; - u64 group_trimmed; - u64 start; - u64 end; - u64 trimmed = 0; - u64 total_bytes = btrfs_super_total_bytes(fs_info->super_copy); - int ret = 0; - - /* - * try to trim all FS space, our block group may start from non-zero. - */ - if (range->len == total_bytes) - cache = btrfs_lookup_first_block_group(fs_info, range->start); - else - cache = btrfs_lookup_block_group(fs_info, range->start); - - while (cache) { - if (cache->key.objectid >= (range->start + range->len)) { - btrfs_put_block_group(cache); - break; - } - - start = max(range->start, cache->key.objectid); - end = min(range->start + range->len, - cache->key.objectid + cache->key.offset); - - if (end - start >= range->minlen) { - if (!block_group_cache_done(cache)) { - ret = cache_block_group(cache, 0); - if (ret) { - btrfs_put_block_group(cache); - break; - } - ret = wait_block_group_cache_done(cache); - if (ret) { - btrfs_put_block_group(cache); - break; - } - } - ret = btrfs_trim_block_group(cache, - &group_trimmed, - start, - end, - range->minlen); - - trimmed += group_trimmed; - if (ret) { - btrfs_put_block_group(cache); - break; - } - } - - cache = next_block_group(fs_info->tree_root, cache); - } - - mutex_lock(&root->fs_info->fs_devices->device_list_mutex); - devices = &root->fs_info->fs_devices->alloc_list; - list_for_each_entry(device, devices, dev_alloc_list) { - ret = btrfs_trim_free_extents(device, range->minlen, - &group_trimmed); - if (ret) - break; - - trimmed += group_trimmed; - } - mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); - - range->len = trimmed; - return ret; -} - -/* - * btrfs_{start,end}_write_no_snapshoting() are similar to - * mnt_{want,drop}_write(), they are used to prevent some tasks from writing - * data into the page cache through nocow before the subvolume is snapshoted, - * but flush the data into disk after the snapshot creation, or to prevent - * operations while snapshoting is ongoing and that cause the snapshot to be - * inconsistent (writes followed by expanding truncates for example). - */ -void btrfs_end_write_no_snapshoting(struct btrfs_root *root) -{ - percpu_counter_dec(&root->subv_writers->counter); - /* - * Make sure counter is updated before we wake up waiters. - */ - smp_mb(); - if (waitqueue_active(&root->subv_writers->wait)) - wake_up(&root->subv_writers->wait); -} - -int btrfs_start_write_no_snapshoting(struct btrfs_root *root) -{ - if (atomic_read(&root->will_be_snapshoted)) - return 0; - - percpu_counter_inc(&root->subv_writers->counter); - /* - * Make sure counter is updated before we check for snapshot creation. - */ - smp_mb(); - if (atomic_read(&root->will_be_snapshoted)) { - btrfs_end_write_no_snapshoting(root); - return 0; - } - return 1; -} - -static int wait_snapshoting_atomic_t(atomic_t *a) -{ - schedule(); - return 0; -} - -void btrfs_wait_for_snapshot_creation(struct btrfs_root *root) -{ - while (true) { - int ret; - - ret = btrfs_start_write_no_snapshoting(root); - if (ret) - break; - wait_on_atomic_t(&root->will_be_snapshoted, - wait_snapshoting_atomic_t, - TASK_UNINTERRUPTIBLE); - } -} diff --git a/src/linux/fs/btrfs/extent_io.c b/src/linux/fs/btrfs/extent_io.c deleted file mode 100644 index 8ed05d9..0000000 --- a/src/linux/fs/btrfs/extent_io.c +++ /dev/null @@ -1,5901 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "extent_io.h" -#include "extent_map.h" -#include "ctree.h" -#include "btrfs_inode.h" -#include "volumes.h" -#include "check-integrity.h" -#include "locking.h" -#include "rcu-string.h" -#include "backref.h" -#include "transaction.h" - -static struct kmem_cache *extent_state_cache; -static struct kmem_cache *extent_buffer_cache; -static struct bio_set *btrfs_bioset; - -static inline bool extent_state_in_tree(const struct extent_state *state) -{ - return !RB_EMPTY_NODE(&state->rb_node); -} - -#ifdef CONFIG_BTRFS_DEBUG -static LIST_HEAD(buffers); -static LIST_HEAD(states); - -static DEFINE_SPINLOCK(leak_lock); - -static inline -void btrfs_leak_debug_add(struct list_head *new, struct list_head *head) -{ - unsigned long flags; - - spin_lock_irqsave(&leak_lock, flags); - list_add(new, head); - spin_unlock_irqrestore(&leak_lock, flags); -} - -static inline -void btrfs_leak_debug_del(struct list_head *entry) -{ - unsigned long flags; - - spin_lock_irqsave(&leak_lock, flags); - list_del(entry); - spin_unlock_irqrestore(&leak_lock, flags); -} - -static inline -void btrfs_leak_debug_check(void) -{ - struct extent_state *state; - struct extent_buffer *eb; - - while (!list_empty(&states)) { - state = list_entry(states.next, struct extent_state, leak_list); - pr_err("BTRFS: state leak: start %llu end %llu state %u in tree %d refs %d\n", - state->start, state->end, state->state, - extent_state_in_tree(state), - atomic_read(&state->refs)); - list_del(&state->leak_list); - kmem_cache_free(extent_state_cache, state); - } - - while (!list_empty(&buffers)) { - eb = list_entry(buffers.next, struct extent_buffer, leak_list); - pr_err("BTRFS: buffer leak start %llu len %lu refs %d\n", - eb->start, eb->len, atomic_read(&eb->refs)); - list_del(&eb->leak_list); - kmem_cache_free(extent_buffer_cache, eb); - } -} - -#define btrfs_debug_check_extent_io_range(tree, start, end) \ - __btrfs_debug_check_extent_io_range(__func__, (tree), (start), (end)) -static inline void __btrfs_debug_check_extent_io_range(const char *caller, - struct extent_io_tree *tree, u64 start, u64 end) -{ - struct inode *inode; - u64 isize; - - if (!tree->mapping) - return; - - inode = tree->mapping->host; - isize = i_size_read(inode); - if (end >= PAGE_SIZE && (end % 2) == 0 && end != isize - 1) { - btrfs_debug_rl(BTRFS_I(inode)->root->fs_info, - "%s: ino %llu isize %llu odd range [%llu,%llu]", - caller, btrfs_ino(inode), isize, start, end); - } -} -#else -#define btrfs_leak_debug_add(new, head) do {} while (0) -#define btrfs_leak_debug_del(entry) do {} while (0) -#define btrfs_leak_debug_check() do {} while (0) -#define btrfs_debug_check_extent_io_range(c, s, e) do {} while (0) -#endif - -#define BUFFER_LRU_MAX 64 - -struct tree_entry { - u64 start; - u64 end; - struct rb_node rb_node; -}; - -struct extent_page_data { - struct bio *bio; - struct extent_io_tree *tree; - get_extent_t *get_extent; - unsigned long bio_flags; - - /* tells writepage not to lock the state bits for this range - * it still does the unlocking - */ - unsigned int extent_locked:1; - - /* tells the submit_bio code to use a WRITE_SYNC */ - unsigned int sync_io:1; -}; - -static void add_extent_changeset(struct extent_state *state, unsigned bits, - struct extent_changeset *changeset, - int set) -{ - int ret; - - if (!changeset) - return; - if (set && (state->state & bits) == bits) - return; - if (!set && (state->state & bits) == 0) - return; - changeset->bytes_changed += state->end - state->start + 1; - ret = ulist_add(changeset->range_changed, state->start, state->end, - GFP_ATOMIC); - /* ENOMEM */ - BUG_ON(ret < 0); -} - -static noinline void flush_write_bio(void *data); -static inline struct btrfs_fs_info * -tree_fs_info(struct extent_io_tree *tree) -{ - if (!tree->mapping) - return NULL; - return btrfs_sb(tree->mapping->host->i_sb); -} - -int __init extent_io_init(void) -{ - extent_state_cache = kmem_cache_create("btrfs_extent_state", - sizeof(struct extent_state), 0, - SLAB_MEM_SPREAD, NULL); - if (!extent_state_cache) - return -ENOMEM; - - extent_buffer_cache = kmem_cache_create("btrfs_extent_buffer", - sizeof(struct extent_buffer), 0, - SLAB_MEM_SPREAD, NULL); - if (!extent_buffer_cache) - goto free_state_cache; - - btrfs_bioset = bioset_create(BIO_POOL_SIZE, - offsetof(struct btrfs_io_bio, bio)); - if (!btrfs_bioset) - goto free_buffer_cache; - - if (bioset_integrity_create(btrfs_bioset, BIO_POOL_SIZE)) - goto free_bioset; - - return 0; - -free_bioset: - bioset_free(btrfs_bioset); - btrfs_bioset = NULL; - -free_buffer_cache: - kmem_cache_destroy(extent_buffer_cache); - extent_buffer_cache = NULL; - -free_state_cache: - kmem_cache_destroy(extent_state_cache); - extent_state_cache = NULL; - return -ENOMEM; -} - -void extent_io_exit(void) -{ - btrfs_leak_debug_check(); - - /* - * Make sure all delayed rcu free are flushed before we - * destroy caches. - */ - rcu_barrier(); - kmem_cache_destroy(extent_state_cache); - kmem_cache_destroy(extent_buffer_cache); - if (btrfs_bioset) - bioset_free(btrfs_bioset); -} - -void extent_io_tree_init(struct extent_io_tree *tree, - struct address_space *mapping) -{ - tree->state = RB_ROOT; - tree->ops = NULL; - tree->dirty_bytes = 0; - spin_lock_init(&tree->lock); - tree->mapping = mapping; -} - -static struct extent_state *alloc_extent_state(gfp_t mask) -{ - struct extent_state *state; - - state = kmem_cache_alloc(extent_state_cache, mask); - if (!state) - return state; - state->state = 0; - state->failrec = NULL; - RB_CLEAR_NODE(&state->rb_node); - btrfs_leak_debug_add(&state->leak_list, &states); - atomic_set(&state->refs, 1); - init_waitqueue_head(&state->wq); - trace_alloc_extent_state(state, mask, _RET_IP_); - return state; -} - -void free_extent_state(struct extent_state *state) -{ - if (!state) - return; - if (atomic_dec_and_test(&state->refs)) { - WARN_ON(extent_state_in_tree(state)); - btrfs_leak_debug_del(&state->leak_list); - trace_free_extent_state(state, _RET_IP_); - kmem_cache_free(extent_state_cache, state); - } -} - -static struct rb_node *tree_insert(struct rb_root *root, - struct rb_node *search_start, - u64 offset, - struct rb_node *node, - struct rb_node ***p_in, - struct rb_node **parent_in) -{ - struct rb_node **p; - struct rb_node *parent = NULL; - struct tree_entry *entry; - - if (p_in && parent_in) { - p = *p_in; - parent = *parent_in; - goto do_insert; - } - - p = search_start ? &search_start : &root->rb_node; - while (*p) { - parent = *p; - entry = rb_entry(parent, struct tree_entry, rb_node); - - if (offset < entry->start) - p = &(*p)->rb_left; - else if (offset > entry->end) - p = &(*p)->rb_right; - else - return parent; - } - -do_insert: - rb_link_node(node, parent, p); - rb_insert_color(node, root); - return NULL; -} - -static struct rb_node *__etree_search(struct extent_io_tree *tree, u64 offset, - struct rb_node **prev_ret, - struct rb_node **next_ret, - struct rb_node ***p_ret, - struct rb_node **parent_ret) -{ - struct rb_root *root = &tree->state; - struct rb_node **n = &root->rb_node; - struct rb_node *prev = NULL; - struct rb_node *orig_prev = NULL; - struct tree_entry *entry; - struct tree_entry *prev_entry = NULL; - - while (*n) { - prev = *n; - entry = rb_entry(prev, struct tree_entry, rb_node); - prev_entry = entry; - - if (offset < entry->start) - n = &(*n)->rb_left; - else if (offset > entry->end) - n = &(*n)->rb_right; - else - return *n; - } - - if (p_ret) - *p_ret = n; - if (parent_ret) - *parent_ret = prev; - - if (prev_ret) { - orig_prev = prev; - while (prev && offset > prev_entry->end) { - prev = rb_next(prev); - prev_entry = rb_entry(prev, struct tree_entry, rb_node); - } - *prev_ret = prev; - prev = orig_prev; - } - - if (next_ret) { - prev_entry = rb_entry(prev, struct tree_entry, rb_node); - while (prev && offset < prev_entry->start) { - prev = rb_prev(prev); - prev_entry = rb_entry(prev, struct tree_entry, rb_node); - } - *next_ret = prev; - } - return NULL; -} - -static inline struct rb_node * -tree_search_for_insert(struct extent_io_tree *tree, - u64 offset, - struct rb_node ***p_ret, - struct rb_node **parent_ret) -{ - struct rb_node *prev = NULL; - struct rb_node *ret; - - ret = __etree_search(tree, offset, &prev, NULL, p_ret, parent_ret); - if (!ret) - return prev; - return ret; -} - -static inline struct rb_node *tree_search(struct extent_io_tree *tree, - u64 offset) -{ - return tree_search_for_insert(tree, offset, NULL, NULL); -} - -static void merge_cb(struct extent_io_tree *tree, struct extent_state *new, - struct extent_state *other) -{ - if (tree->ops && tree->ops->merge_extent_hook) - tree->ops->merge_extent_hook(tree->mapping->host, new, - other); -} - -/* - * utility function to look for merge candidates inside a given range. - * Any extents with matching state are merged together into a single - * extent in the tree. Extents with EXTENT_IO in their state field - * are not merged because the end_io handlers need to be able to do - * operations on them without sleeping (or doing allocations/splits). - * - * This should be called with the tree lock held. - */ -static void merge_state(struct extent_io_tree *tree, - struct extent_state *state) -{ - struct extent_state *other; - struct rb_node *other_node; - - if (state->state & (EXTENT_IOBITS | EXTENT_BOUNDARY)) - return; - - other_node = rb_prev(&state->rb_node); - if (other_node) { - other = rb_entry(other_node, struct extent_state, rb_node); - if (other->end == state->start - 1 && - other->state == state->state) { - merge_cb(tree, state, other); - state->start = other->start; - rb_erase(&other->rb_node, &tree->state); - RB_CLEAR_NODE(&other->rb_node); - free_extent_state(other); - } - } - other_node = rb_next(&state->rb_node); - if (other_node) { - other = rb_entry(other_node, struct extent_state, rb_node); - if (other->start == state->end + 1 && - other->state == state->state) { - merge_cb(tree, state, other); - state->end = other->end; - rb_erase(&other->rb_node, &tree->state); - RB_CLEAR_NODE(&other->rb_node); - free_extent_state(other); - } - } -} - -static void set_state_cb(struct extent_io_tree *tree, - struct extent_state *state, unsigned *bits) -{ - if (tree->ops && tree->ops->set_bit_hook) - tree->ops->set_bit_hook(tree->mapping->host, state, bits); -} - -static void clear_state_cb(struct extent_io_tree *tree, - struct extent_state *state, unsigned *bits) -{ - if (tree->ops && tree->ops->clear_bit_hook) - tree->ops->clear_bit_hook(tree->mapping->host, state, bits); -} - -static void set_state_bits(struct extent_io_tree *tree, - struct extent_state *state, unsigned *bits, - struct extent_changeset *changeset); - -/* - * insert an extent_state struct into the tree. 'bits' are set on the - * struct before it is inserted. - * - * This may return -EEXIST if the extent is already there, in which case the - * state struct is freed. - * - * The tree lock is not taken internally. This is a utility function and - * probably isn't what you want to call (see set/clear_extent_bit). - */ -static int insert_state(struct extent_io_tree *tree, - struct extent_state *state, u64 start, u64 end, - struct rb_node ***p, - struct rb_node **parent, - unsigned *bits, struct extent_changeset *changeset) -{ - struct rb_node *node; - - if (end < start) - WARN(1, KERN_ERR "BTRFS: end < start %llu %llu\n", - end, start); - state->start = start; - state->end = end; - - set_state_bits(tree, state, bits, changeset); - - node = tree_insert(&tree->state, NULL, end, &state->rb_node, p, parent); - if (node) { - struct extent_state *found; - found = rb_entry(node, struct extent_state, rb_node); - pr_err("BTRFS: found node %llu %llu on insert of %llu %llu\n", - found->start, found->end, start, end); - return -EEXIST; - } - merge_state(tree, state); - return 0; -} - -static void split_cb(struct extent_io_tree *tree, struct extent_state *orig, - u64 split) -{ - if (tree->ops && tree->ops->split_extent_hook) - tree->ops->split_extent_hook(tree->mapping->host, orig, split); -} - -/* - * split a given extent state struct in two, inserting the preallocated - * struct 'prealloc' as the newly created second half. 'split' indicates an - * offset inside 'orig' where it should be split. - * - * Before calling, - * the tree has 'orig' at [orig->start, orig->end]. After calling, there - * are two extent state structs in the tree: - * prealloc: [orig->start, split - 1] - * orig: [ split, orig->end ] - * - * The tree locks are not taken by this function. They need to be held - * by the caller. - */ -static int split_state(struct extent_io_tree *tree, struct extent_state *orig, - struct extent_state *prealloc, u64 split) -{ - struct rb_node *node; - - split_cb(tree, orig, split); - - prealloc->start = orig->start; - prealloc->end = split - 1; - prealloc->state = orig->state; - orig->start = split; - - node = tree_insert(&tree->state, &orig->rb_node, prealloc->end, - &prealloc->rb_node, NULL, NULL); - if (node) { - free_extent_state(prealloc); - return -EEXIST; - } - return 0; -} - -static struct extent_state *next_state(struct extent_state *state) -{ - struct rb_node *next = rb_next(&state->rb_node); - if (next) - return rb_entry(next, struct extent_state, rb_node); - else - return NULL; -} - -/* - * utility function to clear some bits in an extent state struct. - * it will optionally wake up any one waiting on this state (wake == 1). - * - * If no bits are set on the state struct after clearing things, the - * struct is freed and removed from the tree - */ -static struct extent_state *clear_state_bit(struct extent_io_tree *tree, - struct extent_state *state, - unsigned *bits, int wake, - struct extent_changeset *changeset) -{ - struct extent_state *next; - unsigned bits_to_clear = *bits & ~EXTENT_CTLBITS; - - if ((bits_to_clear & EXTENT_DIRTY) && (state->state & EXTENT_DIRTY)) { - u64 range = state->end - state->start + 1; - WARN_ON(range > tree->dirty_bytes); - tree->dirty_bytes -= range; - } - clear_state_cb(tree, state, bits); - add_extent_changeset(state, bits_to_clear, changeset, 0); - state->state &= ~bits_to_clear; - if (wake) - wake_up(&state->wq); - if (state->state == 0) { - next = next_state(state); - if (extent_state_in_tree(state)) { - rb_erase(&state->rb_node, &tree->state); - RB_CLEAR_NODE(&state->rb_node); - free_extent_state(state); - } else { - WARN_ON(1); - } - } else { - merge_state(tree, state); - next = next_state(state); - } - return next; -} - -static struct extent_state * -alloc_extent_state_atomic(struct extent_state *prealloc) -{ - if (!prealloc) - prealloc = alloc_extent_state(GFP_ATOMIC); - - return prealloc; -} - -static void extent_io_tree_panic(struct extent_io_tree *tree, int err) -{ - btrfs_panic(tree_fs_info(tree), err, - "Locking error: Extent tree was modified by another thread while locked."); -} - -/* - * clear some bits on a range in the tree. This may require splitting - * or inserting elements in the tree, so the gfp mask is used to - * indicate which allocations or sleeping are allowed. - * - * pass 'wake' == 1 to kick any sleepers, and 'delete' == 1 to remove - * the given range from the tree regardless of state (ie for truncate). - * - * the range [start, end] is inclusive. - * - * This takes the tree lock, and returns 0 on success and < 0 on error. - */ -static int __clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, - unsigned bits, int wake, int delete, - struct extent_state **cached_state, - gfp_t mask, struct extent_changeset *changeset) -{ - struct extent_state *state; - struct extent_state *cached; - struct extent_state *prealloc = NULL; - struct rb_node *node; - u64 last_end; - int err; - int clear = 0; - - btrfs_debug_check_extent_io_range(tree, start, end); - - if (bits & EXTENT_DELALLOC) - bits |= EXTENT_NORESERVE; - - if (delete) - bits |= ~EXTENT_CTLBITS; - bits |= EXTENT_FIRST_DELALLOC; - - if (bits & (EXTENT_IOBITS | EXTENT_BOUNDARY)) - clear = 1; -again: - if (!prealloc && gfpflags_allow_blocking(mask)) { - /* - * Don't care for allocation failure here because we might end - * up not needing the pre-allocated extent state at all, which - * is the case if we only have in the tree extent states that - * cover our input range and don't cover too any other range. - * If we end up needing a new extent state we allocate it later. - */ - prealloc = alloc_extent_state(mask); - } - - spin_lock(&tree->lock); - if (cached_state) { - cached = *cached_state; - - if (clear) { - *cached_state = NULL; - cached_state = NULL; - } - - if (cached && extent_state_in_tree(cached) && - cached->start <= start && cached->end > start) { - if (clear) - atomic_dec(&cached->refs); - state = cached; - goto hit_next; - } - if (clear) - free_extent_state(cached); - } - /* - * this search will find the extents that end after - * our range starts - */ - node = tree_search(tree, start); - if (!node) - goto out; - state = rb_entry(node, struct extent_state, rb_node); -hit_next: - if (state->start > end) - goto out; - WARN_ON(state->end < start); - last_end = state->end; - - /* the state doesn't have the wanted bits, go ahead */ - if (!(state->state & bits)) { - state = next_state(state); - goto next; - } - - /* - * | ---- desired range ---- | - * | state | or - * | ------------- state -------------- | - * - * We need to split the extent we found, and may flip - * bits on second half. - * - * If the extent we found extends past our range, we - * just split and search again. It'll get split again - * the next time though. - * - * If the extent we found is inside our range, we clear - * the desired bit on it. - */ - - if (state->start < start) { - prealloc = alloc_extent_state_atomic(prealloc); - BUG_ON(!prealloc); - err = split_state(tree, state, prealloc, start); - if (err) - extent_io_tree_panic(tree, err); - - prealloc = NULL; - if (err) - goto out; - if (state->end <= end) { - state = clear_state_bit(tree, state, &bits, wake, - changeset); - goto next; - } - goto search_again; - } - /* - * | ---- desired range ---- | - * | state | - * We need to split the extent, and clear the bit - * on the first half - */ - if (state->start <= end && state->end > end) { - prealloc = alloc_extent_state_atomic(prealloc); - BUG_ON(!prealloc); - err = split_state(tree, state, prealloc, end + 1); - if (err) - extent_io_tree_panic(tree, err); - - if (wake) - wake_up(&state->wq); - - clear_state_bit(tree, prealloc, &bits, wake, changeset); - - prealloc = NULL; - goto out; - } - - state = clear_state_bit(tree, state, &bits, wake, changeset); -next: - if (last_end == (u64)-1) - goto out; - start = last_end + 1; - if (start <= end && state && !need_resched()) - goto hit_next; - -search_again: - if (start > end) - goto out; - spin_unlock(&tree->lock); - if (gfpflags_allow_blocking(mask)) - cond_resched(); - goto again; - -out: - spin_unlock(&tree->lock); - if (prealloc) - free_extent_state(prealloc); - - return 0; - -} - -static void wait_on_state(struct extent_io_tree *tree, - struct extent_state *state) - __releases(tree->lock) - __acquires(tree->lock) -{ - DEFINE_WAIT(wait); - prepare_to_wait(&state->wq, &wait, TASK_UNINTERRUPTIBLE); - spin_unlock(&tree->lock); - schedule(); - spin_lock(&tree->lock); - finish_wait(&state->wq, &wait); -} - -/* - * waits for one or more bits to clear on a range in the state tree. - * The range [start, end] is inclusive. - * The tree lock is taken by this function - */ -static void wait_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, - unsigned long bits) -{ - struct extent_state *state; - struct rb_node *node; - - btrfs_debug_check_extent_io_range(tree, start, end); - - spin_lock(&tree->lock); -again: - while (1) { - /* - * this search will find all the extents that end after - * our range starts - */ - node = tree_search(tree, start); -process_node: - if (!node) - break; - - state = rb_entry(node, struct extent_state, rb_node); - - if (state->start > end) - goto out; - - if (state->state & bits) { - start = state->start; - atomic_inc(&state->refs); - wait_on_state(tree, state); - free_extent_state(state); - goto again; - } - start = state->end + 1; - - if (start > end) - break; - - if (!cond_resched_lock(&tree->lock)) { - node = rb_next(node); - goto process_node; - } - } -out: - spin_unlock(&tree->lock); -} - -static void set_state_bits(struct extent_io_tree *tree, - struct extent_state *state, - unsigned *bits, struct extent_changeset *changeset) -{ - unsigned bits_to_set = *bits & ~EXTENT_CTLBITS; - - set_state_cb(tree, state, bits); - if ((bits_to_set & EXTENT_DIRTY) && !(state->state & EXTENT_DIRTY)) { - u64 range = state->end - state->start + 1; - tree->dirty_bytes += range; - } - add_extent_changeset(state, bits_to_set, changeset, 1); - state->state |= bits_to_set; -} - -static void cache_state_if_flags(struct extent_state *state, - struct extent_state **cached_ptr, - unsigned flags) -{ - if (cached_ptr && !(*cached_ptr)) { - if (!flags || (state->state & flags)) { - *cached_ptr = state; - atomic_inc(&state->refs); - } - } -} - -static void cache_state(struct extent_state *state, - struct extent_state **cached_ptr) -{ - return cache_state_if_flags(state, cached_ptr, - EXTENT_IOBITS | EXTENT_BOUNDARY); -} - -/* - * set some bits on a range in the tree. This may require allocations or - * sleeping, so the gfp mask is used to indicate what is allowed. - * - * If any of the exclusive bits are set, this will fail with -EEXIST if some - * part of the range already has the desired bits set. The start of the - * existing range is returned in failed_start in this case. - * - * [start, end] is inclusive This takes the tree lock. - */ - -static int __must_check -__set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, - unsigned bits, unsigned exclusive_bits, - u64 *failed_start, struct extent_state **cached_state, - gfp_t mask, struct extent_changeset *changeset) -{ - struct extent_state *state; - struct extent_state *prealloc = NULL; - struct rb_node *node; - struct rb_node **p; - struct rb_node *parent; - int err = 0; - u64 last_start; - u64 last_end; - - btrfs_debug_check_extent_io_range(tree, start, end); - - bits |= EXTENT_FIRST_DELALLOC; -again: - if (!prealloc && gfpflags_allow_blocking(mask)) { - /* - * Don't care for allocation failure here because we might end - * up not needing the pre-allocated extent state at all, which - * is the case if we only have in the tree extent states that - * cover our input range and don't cover too any other range. - * If we end up needing a new extent state we allocate it later. - */ - prealloc = alloc_extent_state(mask); - } - - spin_lock(&tree->lock); - if (cached_state && *cached_state) { - state = *cached_state; - if (state->start <= start && state->end > start && - extent_state_in_tree(state)) { - node = &state->rb_node; - goto hit_next; - } - } - /* - * this search will find all the extents that end after - * our range starts. - */ - node = tree_search_for_insert(tree, start, &p, &parent); - if (!node) { - prealloc = alloc_extent_state_atomic(prealloc); - BUG_ON(!prealloc); - err = insert_state(tree, prealloc, start, end, - &p, &parent, &bits, changeset); - if (err) - extent_io_tree_panic(tree, err); - - cache_state(prealloc, cached_state); - prealloc = NULL; - goto out; - } - state = rb_entry(node, struct extent_state, rb_node); -hit_next: - last_start = state->start; - last_end = state->end; - - /* - * | ---- desired range ---- | - * | state | - * - * Just lock what we found and keep going - */ - if (state->start == start && state->end <= end) { - if (state->state & exclusive_bits) { - *failed_start = state->start; - err = -EEXIST; - goto out; - } - - set_state_bits(tree, state, &bits, changeset); - cache_state(state, cached_state); - merge_state(tree, state); - if (last_end == (u64)-1) - goto out; - start = last_end + 1; - state = next_state(state); - if (start < end && state && state->start == start && - !need_resched()) - goto hit_next; - goto search_again; - } - - /* - * | ---- desired range ---- | - * | state | - * or - * | ------------- state -------------- | - * - * We need to split the extent we found, and may flip bits on - * second half. - * - * If the extent we found extends past our - * range, we just split and search again. It'll get split - * again the next time though. - * - * If the extent we found is inside our range, we set the - * desired bit on it. - */ - if (state->start < start) { - if (state->state & exclusive_bits) { - *failed_start = start; - err = -EEXIST; - goto out; - } - - prealloc = alloc_extent_state_atomic(prealloc); - BUG_ON(!prealloc); - err = split_state(tree, state, prealloc, start); - if (err) - extent_io_tree_panic(tree, err); - - prealloc = NULL; - if (err) - goto out; - if (state->end <= end) { - set_state_bits(tree, state, &bits, changeset); - cache_state(state, cached_state); - merge_state(tree, state); - if (last_end == (u64)-1) - goto out; - start = last_end + 1; - state = next_state(state); - if (start < end && state && state->start == start && - !need_resched()) - goto hit_next; - } - goto search_again; - } - /* - * | ---- desired range ---- | - * | state | or | state | - * - * There's a hole, we need to insert something in it and - * ignore the extent we found. - */ - if (state->start > start) { - u64 this_end; - if (end < last_start) - this_end = end; - else - this_end = last_start - 1; - - prealloc = alloc_extent_state_atomic(prealloc); - BUG_ON(!prealloc); - - /* - * Avoid to free 'prealloc' if it can be merged with - * the later extent. - */ - err = insert_state(tree, prealloc, start, this_end, - NULL, NULL, &bits, changeset); - if (err) - extent_io_tree_panic(tree, err); - - cache_state(prealloc, cached_state); - prealloc = NULL; - start = this_end + 1; - goto search_again; - } - /* - * | ---- desired range ---- | - * | state | - * We need to split the extent, and set the bit - * on the first half - */ - if (state->start <= end && state->end > end) { - if (state->state & exclusive_bits) { - *failed_start = start; - err = -EEXIST; - goto out; - } - - prealloc = alloc_extent_state_atomic(prealloc); - BUG_ON(!prealloc); - err = split_state(tree, state, prealloc, end + 1); - if (err) - extent_io_tree_panic(tree, err); - - set_state_bits(tree, prealloc, &bits, changeset); - cache_state(prealloc, cached_state); - merge_state(tree, prealloc); - prealloc = NULL; - goto out; - } - -search_again: - if (start > end) - goto out; - spin_unlock(&tree->lock); - if (gfpflags_allow_blocking(mask)) - cond_resched(); - goto again; - -out: - spin_unlock(&tree->lock); - if (prealloc) - free_extent_state(prealloc); - - return err; - -} - -int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, - unsigned bits, u64 * failed_start, - struct extent_state **cached_state, gfp_t mask) -{ - return __set_extent_bit(tree, start, end, bits, 0, failed_start, - cached_state, mask, NULL); -} - - -/** - * convert_extent_bit - convert all bits in a given range from one bit to - * another - * @tree: the io tree to search - * @start: the start offset in bytes - * @end: the end offset in bytes (inclusive) - * @bits: the bits to set in this range - * @clear_bits: the bits to clear in this range - * @cached_state: state that we're going to cache - * - * This will go through and set bits for the given range. If any states exist - * already in this range they are set with the given bit and cleared of the - * clear_bits. This is only meant to be used by things that are mergeable, ie - * converting from say DELALLOC to DIRTY. This is not meant to be used with - * boundary bits like LOCK. - * - * All allocations are done with GFP_NOFS. - */ -int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, - unsigned bits, unsigned clear_bits, - struct extent_state **cached_state) -{ - struct extent_state *state; - struct extent_state *prealloc = NULL; - struct rb_node *node; - struct rb_node **p; - struct rb_node *parent; - int err = 0; - u64 last_start; - u64 last_end; - bool first_iteration = true; - - btrfs_debug_check_extent_io_range(tree, start, end); - -again: - if (!prealloc) { - /* - * Best effort, don't worry if extent state allocation fails - * here for the first iteration. We might have a cached state - * that matches exactly the target range, in which case no - * extent state allocations are needed. We'll only know this - * after locking the tree. - */ - prealloc = alloc_extent_state(GFP_NOFS); - if (!prealloc && !first_iteration) - return -ENOMEM; - } - - spin_lock(&tree->lock); - if (cached_state && *cached_state) { - state = *cached_state; - if (state->start <= start && state->end > start && - extent_state_in_tree(state)) { - node = &state->rb_node; - goto hit_next; - } - } - - /* - * this search will find all the extents that end after - * our range starts. - */ - node = tree_search_for_insert(tree, start, &p, &parent); - if (!node) { - prealloc = alloc_extent_state_atomic(prealloc); - if (!prealloc) { - err = -ENOMEM; - goto out; - } - err = insert_state(tree, prealloc, start, end, - &p, &parent, &bits, NULL); - if (err) - extent_io_tree_panic(tree, err); - cache_state(prealloc, cached_state); - prealloc = NULL; - goto out; - } - state = rb_entry(node, struct extent_state, rb_node); -hit_next: - last_start = state->start; - last_end = state->end; - - /* - * | ---- desired range ---- | - * | state | - * - * Just lock what we found and keep going - */ - if (state->start == start && state->end <= end) { - set_state_bits(tree, state, &bits, NULL); - cache_state(state, cached_state); - state = clear_state_bit(tree, state, &clear_bits, 0, NULL); - if (last_end == (u64)-1) - goto out; - start = last_end + 1; - if (start < end && state && state->start == start && - !need_resched()) - goto hit_next; - goto search_again; - } - - /* - * | ---- desired range ---- | - * | state | - * or - * | ------------- state -------------- | - * - * We need to split the extent we found, and may flip bits on - * second half. - * - * If the extent we found extends past our - * range, we just split and search again. It'll get split - * again the next time though. - * - * If the extent we found is inside our range, we set the - * desired bit on it. - */ - if (state->start < start) { - prealloc = alloc_extent_state_atomic(prealloc); - if (!prealloc) { - err = -ENOMEM; - goto out; - } - err = split_state(tree, state, prealloc, start); - if (err) - extent_io_tree_panic(tree, err); - prealloc = NULL; - if (err) - goto out; - if (state->end <= end) { - set_state_bits(tree, state, &bits, NULL); - cache_state(state, cached_state); - state = clear_state_bit(tree, state, &clear_bits, 0, - NULL); - if (last_end == (u64)-1) - goto out; - start = last_end + 1; - if (start < end && state && state->start == start && - !need_resched()) - goto hit_next; - } - goto search_again; - } - /* - * | ---- desired range ---- | - * | state | or | state | - * - * There's a hole, we need to insert something in it and - * ignore the extent we found. - */ - if (state->start > start) { - u64 this_end; - if (end < last_start) - this_end = end; - else - this_end = last_start - 1; - - prealloc = alloc_extent_state_atomic(prealloc); - if (!prealloc) { - err = -ENOMEM; - goto out; - } - - /* - * Avoid to free 'prealloc' if it can be merged with - * the later extent. - */ - err = insert_state(tree, prealloc, start, this_end, - NULL, NULL, &bits, NULL); - if (err) - extent_io_tree_panic(tree, err); - cache_state(prealloc, cached_state); - prealloc = NULL; - start = this_end + 1; - goto search_again; - } - /* - * | ---- desired range ---- | - * | state | - * We need to split the extent, and set the bit - * on the first half - */ - if (state->start <= end && state->end > end) { - prealloc = alloc_extent_state_atomic(prealloc); - if (!prealloc) { - err = -ENOMEM; - goto out; - } - - err = split_state(tree, state, prealloc, end + 1); - if (err) - extent_io_tree_panic(tree, err); - - set_state_bits(tree, prealloc, &bits, NULL); - cache_state(prealloc, cached_state); - clear_state_bit(tree, prealloc, &clear_bits, 0, NULL); - prealloc = NULL; - goto out; - } - -search_again: - if (start > end) - goto out; - spin_unlock(&tree->lock); - cond_resched(); - first_iteration = false; - goto again; - -out: - spin_unlock(&tree->lock); - if (prealloc) - free_extent_state(prealloc); - - return err; -} - -/* wrappers around set/clear extent bit */ -int set_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, - unsigned bits, struct extent_changeset *changeset) -{ - /* - * We don't support EXTENT_LOCKED yet, as current changeset will - * record any bits changed, so for EXTENT_LOCKED case, it will - * either fail with -EEXIST or changeset will record the whole - * range. - */ - BUG_ON(bits & EXTENT_LOCKED); - - return __set_extent_bit(tree, start, end, bits, 0, NULL, NULL, GFP_NOFS, - changeset); -} - -int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, - unsigned bits, int wake, int delete, - struct extent_state **cached, gfp_t mask) -{ - return __clear_extent_bit(tree, start, end, bits, wake, delete, - cached, mask, NULL); -} - -int clear_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, - unsigned bits, struct extent_changeset *changeset) -{ - /* - * Don't support EXTENT_LOCKED case, same reason as - * set_record_extent_bits(). - */ - BUG_ON(bits & EXTENT_LOCKED); - - return __clear_extent_bit(tree, start, end, bits, 0, 0, NULL, GFP_NOFS, - changeset); -} - -/* - * either insert or lock state struct between start and end use mask to tell - * us if waiting is desired. - */ -int lock_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, - struct extent_state **cached_state) -{ - int err; - u64 failed_start; - - while (1) { - err = __set_extent_bit(tree, start, end, EXTENT_LOCKED, - EXTENT_LOCKED, &failed_start, - cached_state, GFP_NOFS, NULL); - if (err == -EEXIST) { - wait_extent_bit(tree, failed_start, end, EXTENT_LOCKED); - start = failed_start; - } else - break; - WARN_ON(start > end); - } - return err; -} - -int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end) -{ - int err; - u64 failed_start; - - err = __set_extent_bit(tree, start, end, EXTENT_LOCKED, EXTENT_LOCKED, - &failed_start, NULL, GFP_NOFS, NULL); - if (err == -EEXIST) { - if (failed_start > start) - clear_extent_bit(tree, start, failed_start - 1, - EXTENT_LOCKED, 1, 0, NULL, GFP_NOFS); - return 0; - } - return 1; -} - -void extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end) -{ - unsigned long index = start >> PAGE_SHIFT; - unsigned long end_index = end >> PAGE_SHIFT; - struct page *page; - - while (index <= end_index) { - page = find_get_page(inode->i_mapping, index); - BUG_ON(!page); /* Pages should be in the extent_io_tree */ - clear_page_dirty_for_io(page); - put_page(page); - index++; - } -} - -void extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end) -{ - unsigned long index = start >> PAGE_SHIFT; - unsigned long end_index = end >> PAGE_SHIFT; - struct page *page; - - while (index <= end_index) { - page = find_get_page(inode->i_mapping, index); - BUG_ON(!page); /* Pages should be in the extent_io_tree */ - __set_page_dirty_nobuffers(page); - account_page_redirty(page); - put_page(page); - index++; - } -} - -/* - * helper function to set both pages and extents in the tree writeback - */ -static void set_range_writeback(struct extent_io_tree *tree, u64 start, u64 end) -{ - unsigned long index = start >> PAGE_SHIFT; - unsigned long end_index = end >> PAGE_SHIFT; - struct page *page; - - while (index <= end_index) { - page = find_get_page(tree->mapping, index); - BUG_ON(!page); /* Pages should be in the extent_io_tree */ - set_page_writeback(page); - put_page(page); - index++; - } -} - -/* find the first state struct with 'bits' set after 'start', and - * return it. tree->lock must be held. NULL will returned if - * nothing was found after 'start' - */ -static struct extent_state * -find_first_extent_bit_state(struct extent_io_tree *tree, - u64 start, unsigned bits) -{ - struct rb_node *node; - struct extent_state *state; - - /* - * this search will find all the extents that end after - * our range starts. - */ - node = tree_search(tree, start); - if (!node) - goto out; - - while (1) { - state = rb_entry(node, struct extent_state, rb_node); - if (state->end >= start && (state->state & bits)) - return state; - - node = rb_next(node); - if (!node) - break; - } -out: - return NULL; -} - -/* - * find the first offset in the io tree with 'bits' set. zero is - * returned if we find something, and *start_ret and *end_ret are - * set to reflect the state struct that was found. - * - * If nothing was found, 1 is returned. If found something, return 0. - */ -int find_first_extent_bit(struct extent_io_tree *tree, u64 start, - u64 *start_ret, u64 *end_ret, unsigned bits, - struct extent_state **cached_state) -{ - struct extent_state *state; - struct rb_node *n; - int ret = 1; - - spin_lock(&tree->lock); - if (cached_state && *cached_state) { - state = *cached_state; - if (state->end == start - 1 && extent_state_in_tree(state)) { - n = rb_next(&state->rb_node); - while (n) { - state = rb_entry(n, struct extent_state, - rb_node); - if (state->state & bits) - goto got_it; - n = rb_next(n); - } - free_extent_state(*cached_state); - *cached_state = NULL; - goto out; - } - free_extent_state(*cached_state); - *cached_state = NULL; - } - - state = find_first_extent_bit_state(tree, start, bits); -got_it: - if (state) { - cache_state_if_flags(state, cached_state, 0); - *start_ret = state->start; - *end_ret = state->end; - ret = 0; - } -out: - spin_unlock(&tree->lock); - return ret; -} - -/* - * find a contiguous range of bytes in the file marked as delalloc, not - * more than 'max_bytes'. start and end are used to return the range, - * - * 1 is returned if we find something, 0 if nothing was in the tree - */ -static noinline u64 find_delalloc_range(struct extent_io_tree *tree, - u64 *start, u64 *end, u64 max_bytes, - struct extent_state **cached_state) -{ - struct rb_node *node; - struct extent_state *state; - u64 cur_start = *start; - u64 found = 0; - u64 total_bytes = 0; - - spin_lock(&tree->lock); - - /* - * this search will find all the extents that end after - * our range starts. - */ - node = tree_search(tree, cur_start); - if (!node) { - if (!found) - *end = (u64)-1; - goto out; - } - - while (1) { - state = rb_entry(node, struct extent_state, rb_node); - if (found && (state->start != cur_start || - (state->state & EXTENT_BOUNDARY))) { - goto out; - } - if (!(state->state & EXTENT_DELALLOC)) { - if (!found) - *end = state->end; - goto out; - } - if (!found) { - *start = state->start; - *cached_state = state; - atomic_inc(&state->refs); - } - found++; - *end = state->end; - cur_start = state->end + 1; - node = rb_next(node); - total_bytes += state->end - state->start + 1; - if (total_bytes >= max_bytes) - break; - if (!node) - break; - } -out: - spin_unlock(&tree->lock); - return found; -} - -static noinline void __unlock_for_delalloc(struct inode *inode, - struct page *locked_page, - u64 start, u64 end) -{ - int ret; - struct page *pages[16]; - unsigned long index = start >> PAGE_SHIFT; - unsigned long end_index = end >> PAGE_SHIFT; - unsigned long nr_pages = end_index - index + 1; - int i; - - if (index == locked_page->index && end_index == index) - return; - - while (nr_pages > 0) { - ret = find_get_pages_contig(inode->i_mapping, index, - min_t(unsigned long, nr_pages, - ARRAY_SIZE(pages)), pages); - for (i = 0; i < ret; i++) { - if (pages[i] != locked_page) - unlock_page(pages[i]); - put_page(pages[i]); - } - nr_pages -= ret; - index += ret; - cond_resched(); - } -} - -static noinline int lock_delalloc_pages(struct inode *inode, - struct page *locked_page, - u64 delalloc_start, - u64 delalloc_end) -{ - unsigned long index = delalloc_start >> PAGE_SHIFT; - unsigned long start_index = index; - unsigned long end_index = delalloc_end >> PAGE_SHIFT; - unsigned long pages_locked = 0; - struct page *pages[16]; - unsigned long nrpages; - int ret; - int i; - - /* the caller is responsible for locking the start index */ - if (index == locked_page->index && index == end_index) - return 0; - - /* skip the page at the start index */ - nrpages = end_index - index + 1; - while (nrpages > 0) { - ret = find_get_pages_contig(inode->i_mapping, index, - min_t(unsigned long, - nrpages, ARRAY_SIZE(pages)), pages); - if (ret == 0) { - ret = -EAGAIN; - goto done; - } - /* now we have an array of pages, lock them all */ - for (i = 0; i < ret; i++) { - /* - * the caller is taking responsibility for - * locked_page - */ - if (pages[i] != locked_page) { - lock_page(pages[i]); - if (!PageDirty(pages[i]) || - pages[i]->mapping != inode->i_mapping) { - ret = -EAGAIN; - unlock_page(pages[i]); - put_page(pages[i]); - goto done; - } - } - put_page(pages[i]); - pages_locked++; - } - nrpages -= ret; - index += ret; - cond_resched(); - } - ret = 0; -done: - if (ret && pages_locked) { - __unlock_for_delalloc(inode, locked_page, - delalloc_start, - ((u64)(start_index + pages_locked - 1)) << - PAGE_SHIFT); - } - return ret; -} - -/* - * find a contiguous range of bytes in the file marked as delalloc, not - * more than 'max_bytes'. start and end are used to return the range, - * - * 1 is returned if we find something, 0 if nothing was in the tree - */ -STATIC u64 find_lock_delalloc_range(struct inode *inode, - struct extent_io_tree *tree, - struct page *locked_page, u64 *start, - u64 *end, u64 max_bytes) -{ - u64 delalloc_start; - u64 delalloc_end; - u64 found; - struct extent_state *cached_state = NULL; - int ret; - int loops = 0; - -again: - /* step one, find a bunch of delalloc bytes starting at start */ - delalloc_start = *start; - delalloc_end = 0; - found = find_delalloc_range(tree, &delalloc_start, &delalloc_end, - max_bytes, &cached_state); - if (!found || delalloc_end <= *start) { - *start = delalloc_start; - *end = delalloc_end; - free_extent_state(cached_state); - return 0; - } - - /* - * start comes from the offset of locked_page. We have to lock - * pages in order, so we can't process delalloc bytes before - * locked_page - */ - if (delalloc_start < *start) - delalloc_start = *start; - - /* - * make sure to limit the number of pages we try to lock down - */ - if (delalloc_end + 1 - delalloc_start > max_bytes) - delalloc_end = delalloc_start + max_bytes - 1; - - /* step two, lock all the pages after the page that has start */ - ret = lock_delalloc_pages(inode, locked_page, - delalloc_start, delalloc_end); - if (ret == -EAGAIN) { - /* some of the pages are gone, lets avoid looping by - * shortening the size of the delalloc range we're searching - */ - free_extent_state(cached_state); - cached_state = NULL; - if (!loops) { - max_bytes = PAGE_SIZE; - loops = 1; - goto again; - } else { - found = 0; - goto out_failed; - } - } - BUG_ON(ret); /* Only valid values are 0 and -EAGAIN */ - - /* step three, lock the state bits for the whole range */ - lock_extent_bits(tree, delalloc_start, delalloc_end, &cached_state); - - /* then test to make sure it is all still delalloc */ - ret = test_range_bit(tree, delalloc_start, delalloc_end, - EXTENT_DELALLOC, 1, cached_state); - if (!ret) { - unlock_extent_cached(tree, delalloc_start, delalloc_end, - &cached_state, GFP_NOFS); - __unlock_for_delalloc(inode, locked_page, - delalloc_start, delalloc_end); - cond_resched(); - goto again; - } - free_extent_state(cached_state); - *start = delalloc_start; - *end = delalloc_end; -out_failed: - return found; -} - -void extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end, - u64 delalloc_end, struct page *locked_page, - unsigned clear_bits, - unsigned long page_ops) -{ - struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree; - int ret; - struct page *pages[16]; - unsigned long index = start >> PAGE_SHIFT; - unsigned long end_index = end >> PAGE_SHIFT; - unsigned long nr_pages = end_index - index + 1; - int i; - - clear_extent_bit(tree, start, end, clear_bits, 1, 0, NULL, GFP_NOFS); - if (page_ops == 0) - return; - - if ((page_ops & PAGE_SET_ERROR) && nr_pages > 0) - mapping_set_error(inode->i_mapping, -EIO); - - while (nr_pages > 0) { - ret = find_get_pages_contig(inode->i_mapping, index, - min_t(unsigned long, - nr_pages, ARRAY_SIZE(pages)), pages); - for (i = 0; i < ret; i++) { - - if (page_ops & PAGE_SET_PRIVATE2) - SetPagePrivate2(pages[i]); - - if (pages[i] == locked_page) { - put_page(pages[i]); - continue; - } - if (page_ops & PAGE_CLEAR_DIRTY) - clear_page_dirty_for_io(pages[i]); - if (page_ops & PAGE_SET_WRITEBACK) - set_page_writeback(pages[i]); - if (page_ops & PAGE_SET_ERROR) - SetPageError(pages[i]); - if (page_ops & PAGE_END_WRITEBACK) - end_page_writeback(pages[i]); - if (page_ops & PAGE_UNLOCK) - unlock_page(pages[i]); - put_page(pages[i]); - } - nr_pages -= ret; - index += ret; - cond_resched(); - } -} - -/* - * count the number of bytes in the tree that have a given bit(s) - * set. This can be fairly slow, except for EXTENT_DIRTY which is - * cached. The total number found is returned. - */ -u64 count_range_bits(struct extent_io_tree *tree, - u64 *start, u64 search_end, u64 max_bytes, - unsigned bits, int contig) -{ - struct rb_node *node; - struct extent_state *state; - u64 cur_start = *start; - u64 total_bytes = 0; - u64 last = 0; - int found = 0; - - if (WARN_ON(search_end <= cur_start)) - return 0; - - spin_lock(&tree->lock); - if (cur_start == 0 && bits == EXTENT_DIRTY) { - total_bytes = tree->dirty_bytes; - goto out; - } - /* - * this search will find all the extents that end after - * our range starts. - */ - node = tree_search(tree, cur_start); - if (!node) - goto out; - - while (1) { - state = rb_entry(node, struct extent_state, rb_node); - if (state->start > search_end) - break; - if (contig && found && state->start > last + 1) - break; - if (state->end >= cur_start && (state->state & bits) == bits) { - total_bytes += min(search_end, state->end) + 1 - - max(cur_start, state->start); - if (total_bytes >= max_bytes) - break; - if (!found) { - *start = max(cur_start, state->start); - found = 1; - } - last = state->end; - } else if (contig && found) { - break; - } - node = rb_next(node); - if (!node) - break; - } -out: - spin_unlock(&tree->lock); - return total_bytes; -} - -/* - * set the private field for a given byte offset in the tree. If there isn't - * an extent_state there already, this does nothing. - */ -static noinline int set_state_failrec(struct extent_io_tree *tree, u64 start, - struct io_failure_record *failrec) -{ - struct rb_node *node; - struct extent_state *state; - int ret = 0; - - spin_lock(&tree->lock); - /* - * this search will find all the extents that end after - * our range starts. - */ - node = tree_search(tree, start); - if (!node) { - ret = -ENOENT; - goto out; - } - state = rb_entry(node, struct extent_state, rb_node); - if (state->start != start) { - ret = -ENOENT; - goto out; - } - state->failrec = failrec; -out: - spin_unlock(&tree->lock); - return ret; -} - -static noinline int get_state_failrec(struct extent_io_tree *tree, u64 start, - struct io_failure_record **failrec) -{ - struct rb_node *node; - struct extent_state *state; - int ret = 0; - - spin_lock(&tree->lock); - /* - * this search will find all the extents that end after - * our range starts. - */ - node = tree_search(tree, start); - if (!node) { - ret = -ENOENT; - goto out; - } - state = rb_entry(node, struct extent_state, rb_node); - if (state->start != start) { - ret = -ENOENT; - goto out; - } - *failrec = state->failrec; -out: - spin_unlock(&tree->lock); - return ret; -} - -/* - * searches a range in the state tree for a given mask. - * If 'filled' == 1, this returns 1 only if every extent in the tree - * has the bits set. Otherwise, 1 is returned if any bit in the - * range is found set. - */ -int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end, - unsigned bits, int filled, struct extent_state *cached) -{ - struct extent_state *state = NULL; - struct rb_node *node; - int bitset = 0; - - spin_lock(&tree->lock); - if (cached && extent_state_in_tree(cached) && cached->start <= start && - cached->end > start) - node = &cached->rb_node; - else - node = tree_search(tree, start); - while (node && start <= end) { - state = rb_entry(node, struct extent_state, rb_node); - - if (filled && state->start > start) { - bitset = 0; - break; - } - - if (state->start > end) - break; - - if (state->state & bits) { - bitset = 1; - if (!filled) - break; - } else if (filled) { - bitset = 0; - break; - } - - if (state->end == (u64)-1) - break; - - start = state->end + 1; - if (start > end) - break; - node = rb_next(node); - if (!node) { - if (filled) - bitset = 0; - break; - } - } - spin_unlock(&tree->lock); - return bitset; -} - -/* - * helper function to set a given page up to date if all the - * extents in the tree for that page are up to date - */ -static void check_page_uptodate(struct extent_io_tree *tree, struct page *page) -{ - u64 start = page_offset(page); - u64 end = start + PAGE_SIZE - 1; - if (test_range_bit(tree, start, end, EXTENT_UPTODATE, 1, NULL)) - SetPageUptodate(page); -} - -int free_io_failure(struct inode *inode, struct io_failure_record *rec) -{ - int ret; - int err = 0; - struct extent_io_tree *failure_tree = &BTRFS_I(inode)->io_failure_tree; - - set_state_failrec(failure_tree, rec->start, NULL); - ret = clear_extent_bits(failure_tree, rec->start, - rec->start + rec->len - 1, - EXTENT_LOCKED | EXTENT_DIRTY); - if (ret) - err = ret; - - ret = clear_extent_bits(&BTRFS_I(inode)->io_tree, rec->start, - rec->start + rec->len - 1, - EXTENT_DAMAGED); - if (ret && !err) - err = ret; - - kfree(rec); - return err; -} - -/* - * this bypasses the standard btrfs submit functions deliberately, as - * the standard behavior is to write all copies in a raid setup. here we only - * want to write the one bad copy. so we do the mapping for ourselves and issue - * submit_bio directly. - * to avoid any synchronization issues, wait for the data after writing, which - * actually prevents the read that triggered the error from finishing. - * currently, there can be no more than two copies of every data bit. thus, - * exactly one rewrite is required. - */ -int repair_io_failure(struct inode *inode, u64 start, u64 length, u64 logical, - struct page *page, unsigned int pg_offset, int mirror_num) -{ - struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; - struct bio *bio; - struct btrfs_device *dev; - u64 map_length = 0; - u64 sector; - struct btrfs_bio *bbio = NULL; - struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; - int ret; - - ASSERT(!(fs_info->sb->s_flags & MS_RDONLY)); - BUG_ON(!mirror_num); - - /* we can't repair anything in raid56 yet */ - if (btrfs_is_parity_mirror(map_tree, logical, length, mirror_num)) - return 0; - - bio = btrfs_io_bio_alloc(GFP_NOFS, 1); - if (!bio) - return -EIO; - bio->bi_iter.bi_size = 0; - map_length = length; - - /* - * Avoid races with device replace and make sure our bbio has devices - * associated to its stripes that don't go away while we are doing the - * read repair operation. - */ - btrfs_bio_counter_inc_blocked(fs_info); - ret = btrfs_map_block(fs_info, WRITE, logical, - &map_length, &bbio, mirror_num); - if (ret) { - btrfs_bio_counter_dec(fs_info); - bio_put(bio); - return -EIO; - } - BUG_ON(mirror_num != bbio->mirror_num); - sector = bbio->stripes[mirror_num-1].physical >> 9; - bio->bi_iter.bi_sector = sector; - dev = bbio->stripes[mirror_num-1].dev; - btrfs_put_bbio(bbio); - if (!dev || !dev->bdev || !dev->writeable) { - btrfs_bio_counter_dec(fs_info); - bio_put(bio); - return -EIO; - } - bio->bi_bdev = dev->bdev; - bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_SYNC); - bio_add_page(bio, page, length, pg_offset); - - if (btrfsic_submit_bio_wait(bio)) { - /* try to remap that extent elsewhere? */ - btrfs_bio_counter_dec(fs_info); - bio_put(bio); - btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS); - return -EIO; - } - - btrfs_info_rl_in_rcu(fs_info, - "read error corrected: ino %llu off %llu (dev %s sector %llu)", - btrfs_ino(inode), start, - rcu_str_deref(dev->name), sector); - btrfs_bio_counter_dec(fs_info); - bio_put(bio); - return 0; -} - -int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb, - int mirror_num) -{ - u64 start = eb->start; - unsigned long i, num_pages = num_extent_pages(eb->start, eb->len); - int ret = 0; - - if (root->fs_info->sb->s_flags & MS_RDONLY) - return -EROFS; - - for (i = 0; i < num_pages; i++) { - struct page *p = eb->pages[i]; - - ret = repair_io_failure(root->fs_info->btree_inode, start, - PAGE_SIZE, start, p, - start - page_offset(p), mirror_num); - if (ret) - break; - start += PAGE_SIZE; - } - - return ret; -} - -/* - * each time an IO finishes, we do a fast check in the IO failure tree - * to see if we need to process or clean up an io_failure_record - */ -int clean_io_failure(struct inode *inode, u64 start, struct page *page, - unsigned int pg_offset) -{ - u64 private; - struct io_failure_record *failrec; - struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; - struct extent_state *state; - int num_copies; - int ret; - - private = 0; - ret = count_range_bits(&BTRFS_I(inode)->io_failure_tree, &private, - (u64)-1, 1, EXTENT_DIRTY, 0); - if (!ret) - return 0; - - ret = get_state_failrec(&BTRFS_I(inode)->io_failure_tree, start, - &failrec); - if (ret) - return 0; - - BUG_ON(!failrec->this_mirror); - - if (failrec->in_validation) { - /* there was no real error, just free the record */ - btrfs_debug(fs_info, - "clean_io_failure: freeing dummy error at %llu", - failrec->start); - goto out; - } - if (fs_info->sb->s_flags & MS_RDONLY) - goto out; - - spin_lock(&BTRFS_I(inode)->io_tree.lock); - state = find_first_extent_bit_state(&BTRFS_I(inode)->io_tree, - failrec->start, - EXTENT_LOCKED); - spin_unlock(&BTRFS_I(inode)->io_tree.lock); - - if (state && state->start <= failrec->start && - state->end >= failrec->start + failrec->len - 1) { - num_copies = btrfs_num_copies(fs_info, failrec->logical, - failrec->len); - if (num_copies > 1) { - repair_io_failure(inode, start, failrec->len, - failrec->logical, page, - pg_offset, failrec->failed_mirror); - } - } - -out: - free_io_failure(inode, failrec); - - return 0; -} - -/* - * Can be called when - * - hold extent lock - * - under ordered extent - * - the inode is freeing - */ -void btrfs_free_io_failure_record(struct inode *inode, u64 start, u64 end) -{ - struct extent_io_tree *failure_tree = &BTRFS_I(inode)->io_failure_tree; - struct io_failure_record *failrec; - struct extent_state *state, *next; - - if (RB_EMPTY_ROOT(&failure_tree->state)) - return; - - spin_lock(&failure_tree->lock); - state = find_first_extent_bit_state(failure_tree, start, EXTENT_DIRTY); - while (state) { - if (state->start > end) - break; - - ASSERT(state->end <= end); - - next = next_state(state); - - failrec = state->failrec; - free_extent_state(state); - kfree(failrec); - - state = next; - } - spin_unlock(&failure_tree->lock); -} - -int btrfs_get_io_failure_record(struct inode *inode, u64 start, u64 end, - struct io_failure_record **failrec_ret) -{ - struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); - struct io_failure_record *failrec; - struct extent_map *em; - struct extent_io_tree *failure_tree = &BTRFS_I(inode)->io_failure_tree; - struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree; - struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; - int ret; - u64 logical; - - ret = get_state_failrec(failure_tree, start, &failrec); - if (ret) { - failrec = kzalloc(sizeof(*failrec), GFP_NOFS); - if (!failrec) - return -ENOMEM; - - failrec->start = start; - failrec->len = end - start + 1; - failrec->this_mirror = 0; - failrec->bio_flags = 0; - failrec->in_validation = 0; - - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, start, failrec->len); - if (!em) { - read_unlock(&em_tree->lock); - kfree(failrec); - return -EIO; - } - - if (em->start > start || em->start + em->len <= start) { - free_extent_map(em); - em = NULL; - } - read_unlock(&em_tree->lock); - if (!em) { - kfree(failrec); - return -EIO; - } - - logical = start - em->start; - logical = em->block_start + logical; - if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) { - logical = em->block_start; - failrec->bio_flags = EXTENT_BIO_COMPRESSED; - extent_set_compress_type(&failrec->bio_flags, - em->compress_type); - } - - btrfs_debug(fs_info, - "Get IO Failure Record: (new) logical=%llu, start=%llu, len=%llu", - logical, start, failrec->len); - - failrec->logical = logical; - free_extent_map(em); - - /* set the bits in the private failure tree */ - ret = set_extent_bits(failure_tree, start, end, - EXTENT_LOCKED | EXTENT_DIRTY); - if (ret >= 0) - ret = set_state_failrec(failure_tree, start, failrec); - /* set the bits in the inode's tree */ - if (ret >= 0) - ret = set_extent_bits(tree, start, end, EXTENT_DAMAGED); - if (ret < 0) { - kfree(failrec); - return ret; - } - } else { - btrfs_debug(fs_info, - "Get IO Failure Record: (found) logical=%llu, start=%llu, len=%llu, validation=%d", - failrec->logical, failrec->start, failrec->len, - failrec->in_validation); - /* - * when data can be on disk more than twice, add to failrec here - * (e.g. with a list for failed_mirror) to make - * clean_io_failure() clean all those errors at once. - */ - } - - *failrec_ret = failrec; - - return 0; -} - -int btrfs_check_repairable(struct inode *inode, struct bio *failed_bio, - struct io_failure_record *failrec, int failed_mirror) -{ - struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); - int num_copies; - - num_copies = btrfs_num_copies(fs_info, failrec->logical, failrec->len); - if (num_copies == 1) { - /* - * we only have a single copy of the data, so don't bother with - * all the retry and error correction code that follows. no - * matter what the error is, it is very likely to persist. - */ - btrfs_debug(fs_info, - "Check Repairable: cannot repair, num_copies=%d, next_mirror %d, failed_mirror %d", - num_copies, failrec->this_mirror, failed_mirror); - return 0; - } - - /* - * there are two premises: - * a) deliver good data to the caller - * b) correct the bad sectors on disk - */ - if (failed_bio->bi_vcnt > 1) { - /* - * to fulfill b), we need to know the exact failing sectors, as - * we don't want to rewrite any more than the failed ones. thus, - * we need separate read requests for the failed bio - * - * if the following BUG_ON triggers, our validation request got - * merged. we need separate requests for our algorithm to work. - */ - BUG_ON(failrec->in_validation); - failrec->in_validation = 1; - failrec->this_mirror = failed_mirror; - } else { - /* - * we're ready to fulfill a) and b) alongside. get a good copy - * of the failed sector and if we succeed, we have setup - * everything for repair_io_failure to do the rest for us. - */ - if (failrec->in_validation) { - BUG_ON(failrec->this_mirror != failed_mirror); - failrec->in_validation = 0; - failrec->this_mirror = 0; - } - failrec->failed_mirror = failed_mirror; - failrec->this_mirror++; - if (failrec->this_mirror == failed_mirror) - failrec->this_mirror++; - } - - if (failrec->this_mirror > num_copies) { - btrfs_debug(fs_info, - "Check Repairable: (fail) num_copies=%d, next_mirror %d, failed_mirror %d", - num_copies, failrec->this_mirror, failed_mirror); - return 0; - } - - return 1; -} - - -struct bio *btrfs_create_repair_bio(struct inode *inode, struct bio *failed_bio, - struct io_failure_record *failrec, - struct page *page, int pg_offset, int icsum, - bio_end_io_t *endio_func, void *data) -{ - struct bio *bio; - struct btrfs_io_bio *btrfs_failed_bio; - struct btrfs_io_bio *btrfs_bio; - - bio = btrfs_io_bio_alloc(GFP_NOFS, 1); - if (!bio) - return NULL; - - bio->bi_end_io = endio_func; - bio->bi_iter.bi_sector = failrec->logical >> 9; - bio->bi_bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev; - bio->bi_iter.bi_size = 0; - bio->bi_private = data; - - btrfs_failed_bio = btrfs_io_bio(failed_bio); - if (btrfs_failed_bio->csum) { - struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; - u16 csum_size = btrfs_super_csum_size(fs_info->super_copy); - - btrfs_bio = btrfs_io_bio(bio); - btrfs_bio->csum = btrfs_bio->csum_inline; - icsum *= csum_size; - memcpy(btrfs_bio->csum, btrfs_failed_bio->csum + icsum, - csum_size); - } - - bio_add_page(bio, page, failrec->len, pg_offset); - - return bio; -} - -/* - * this is a generic handler for readpage errors (default - * readpage_io_failed_hook). if other copies exist, read those and write back - * good data to the failed position. does not investigate in remapping the - * failed extent elsewhere, hoping the device will be smart enough to do this as - * needed - */ - -static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset, - struct page *page, u64 start, u64 end, - int failed_mirror) -{ - struct io_failure_record *failrec; - struct inode *inode = page->mapping->host; - struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree; - struct bio *bio; - int read_mode; - int ret; - - BUG_ON(bio_op(failed_bio) == REQ_OP_WRITE); - - ret = btrfs_get_io_failure_record(inode, start, end, &failrec); - if (ret) - return ret; - - ret = btrfs_check_repairable(inode, failed_bio, failrec, failed_mirror); - if (!ret) { - free_io_failure(inode, failrec); - return -EIO; - } - - if (failed_bio->bi_vcnt > 1) - read_mode = READ_SYNC | REQ_FAILFAST_DEV; - else - read_mode = READ_SYNC; - - phy_offset >>= inode->i_sb->s_blocksize_bits; - bio = btrfs_create_repair_bio(inode, failed_bio, failrec, page, - start - page_offset(page), - (int)phy_offset, failed_bio->bi_end_io, - NULL); - if (!bio) { - free_io_failure(inode, failrec); - return -EIO; - } - bio_set_op_attrs(bio, REQ_OP_READ, read_mode); - - btrfs_debug(btrfs_sb(inode->i_sb), - "Repair Read Error: submitting new read[%#x] to this_mirror=%d, in_validation=%d", - read_mode, failrec->this_mirror, failrec->in_validation); - - ret = tree->ops->submit_bio_hook(inode, bio, failrec->this_mirror, - failrec->bio_flags, 0); - if (ret) { - free_io_failure(inode, failrec); - bio_put(bio); - } - - return ret; -} - -/* lots and lots of room for performance fixes in the end_bio funcs */ - -void end_extent_writepage(struct page *page, int err, u64 start, u64 end) -{ - int uptodate = (err == 0); - struct extent_io_tree *tree; - int ret = 0; - - tree = &BTRFS_I(page->mapping->host)->io_tree; - - if (tree->ops && tree->ops->writepage_end_io_hook) { - ret = tree->ops->writepage_end_io_hook(page, start, - end, NULL, uptodate); - if (ret) - uptodate = 0; - } - - if (!uptodate) { - ClearPageUptodate(page); - SetPageError(page); - ret = ret < 0 ? ret : -EIO; - mapping_set_error(page->mapping, ret); - } -} - -/* - * after a writepage IO is done, we need to: - * clear the uptodate bits on error - * clear the writeback bits in the extent tree for this IO - * end_page_writeback if the page has no more pending IO - * - * Scheduling is not allowed, so the extent state tree is expected - * to have one and only one object corresponding to this IO. - */ -static void end_bio_extent_writepage(struct bio *bio) -{ - struct bio_vec *bvec; - u64 start; - u64 end; - int i; - - bio_for_each_segment_all(bvec, bio, i) { - struct page *page = bvec->bv_page; - - /* We always issue full-page reads, but if some block - * in a page fails to read, blk_update_request() will - * advance bv_offset and adjust bv_len to compensate. - * Print a warning for nonzero offsets, and an error - * if they don't add up to a full page. */ - if (bvec->bv_offset || bvec->bv_len != PAGE_SIZE) { - if (bvec->bv_offset + bvec->bv_len != PAGE_SIZE) - btrfs_err(BTRFS_I(page->mapping->host)->root->fs_info, - "partial page write in btrfs with offset %u and length %u", - bvec->bv_offset, bvec->bv_len); - else - btrfs_info(BTRFS_I(page->mapping->host)->root->fs_info, - "incomplete page write in btrfs with offset %u and length %u", - bvec->bv_offset, bvec->bv_len); - } - - start = page_offset(page); - end = start + bvec->bv_offset + bvec->bv_len - 1; - - end_extent_writepage(page, bio->bi_error, start, end); - end_page_writeback(page); - } - - bio_put(bio); -} - -static void -endio_readpage_release_extent(struct extent_io_tree *tree, u64 start, u64 len, - int uptodate) -{ - struct extent_state *cached = NULL; - u64 end = start + len - 1; - - if (uptodate && tree->track_uptodate) - set_extent_uptodate(tree, start, end, &cached, GFP_ATOMIC); - unlock_extent_cached(tree, start, end, &cached, GFP_ATOMIC); -} - -/* - * after a readpage IO is done, we need to: - * clear the uptodate bits on error - * set the uptodate bits if things worked - * set the page up to date if all extents in the tree are uptodate - * clear the lock bit in the extent tree - * unlock the page if there are no other extents locked for it - * - * Scheduling is not allowed, so the extent state tree is expected - * to have one and only one object corresponding to this IO. - */ -static void end_bio_extent_readpage(struct bio *bio) -{ - struct bio_vec *bvec; - int uptodate = !bio->bi_error; - struct btrfs_io_bio *io_bio = btrfs_io_bio(bio); - struct extent_io_tree *tree; - u64 offset = 0; - u64 start; - u64 end; - u64 len; - u64 extent_start = 0; - u64 extent_len = 0; - int mirror; - int ret; - int i; - - bio_for_each_segment_all(bvec, bio, i) { - struct page *page = bvec->bv_page; - struct inode *inode = page->mapping->host; - struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); - - btrfs_debug(fs_info, - "end_bio_extent_readpage: bi_sector=%llu, err=%d, mirror=%u", - (u64)bio->bi_iter.bi_sector, bio->bi_error, - io_bio->mirror_num); - tree = &BTRFS_I(inode)->io_tree; - - /* We always issue full-page reads, but if some block - * in a page fails to read, blk_update_request() will - * advance bv_offset and adjust bv_len to compensate. - * Print a warning for nonzero offsets, and an error - * if they don't add up to a full page. */ - if (bvec->bv_offset || bvec->bv_len != PAGE_SIZE) { - if (bvec->bv_offset + bvec->bv_len != PAGE_SIZE) - btrfs_err(fs_info, - "partial page read in btrfs with offset %u and length %u", - bvec->bv_offset, bvec->bv_len); - else - btrfs_info(fs_info, - "incomplete page read in btrfs with offset %u and length %u", - bvec->bv_offset, bvec->bv_len); - } - - start = page_offset(page); - end = start + bvec->bv_offset + bvec->bv_len - 1; - len = bvec->bv_len; - - mirror = io_bio->mirror_num; - if (likely(uptodate && tree->ops && - tree->ops->readpage_end_io_hook)) { - ret = tree->ops->readpage_end_io_hook(io_bio, offset, - page, start, end, - mirror); - if (ret) - uptodate = 0; - else - clean_io_failure(inode, start, page, 0); - } - - if (likely(uptodate)) - goto readpage_ok; - - if (tree->ops && tree->ops->readpage_io_failed_hook) { - ret = tree->ops->readpage_io_failed_hook(page, mirror); - if (!ret && !bio->bi_error) - uptodate = 1; - } else { - /* - * The generic bio_readpage_error handles errors the - * following way: If possible, new read requests are - * created and submitted and will end up in - * end_bio_extent_readpage as well (if we're lucky, not - * in the !uptodate case). In that case it returns 0 and - * we just go on with the next page in our bio. If it - * can't handle the error it will return -EIO and we - * remain responsible for that page. - */ - ret = bio_readpage_error(bio, offset, page, start, end, - mirror); - if (ret == 0) { - uptodate = !bio->bi_error; - offset += len; - continue; - } - } -readpage_ok: - if (likely(uptodate)) { - loff_t i_size = i_size_read(inode); - pgoff_t end_index = i_size >> PAGE_SHIFT; - unsigned off; - - /* Zero out the end if this page straddles i_size */ - off = i_size & (PAGE_SIZE-1); - if (page->index == end_index && off) - zero_user_segment(page, off, PAGE_SIZE); - SetPageUptodate(page); - } else { - ClearPageUptodate(page); - SetPageError(page); - } - unlock_page(page); - offset += len; - - if (unlikely(!uptodate)) { - if (extent_len) { - endio_readpage_release_extent(tree, - extent_start, - extent_len, 1); - extent_start = 0; - extent_len = 0; - } - endio_readpage_release_extent(tree, start, - end - start + 1, 0); - } else if (!extent_len) { - extent_start = start; - extent_len = end + 1 - start; - } else if (extent_start + extent_len == start) { - extent_len += end + 1 - start; - } else { - endio_readpage_release_extent(tree, extent_start, - extent_len, uptodate); - extent_start = start; - extent_len = end + 1 - start; - } - } - - if (extent_len) - endio_readpage_release_extent(tree, extent_start, extent_len, - uptodate); - if (io_bio->end_io) - io_bio->end_io(io_bio, bio->bi_error); - bio_put(bio); -} - -/* - * this allocates from the btrfs_bioset. We're returning a bio right now - * but you can call btrfs_io_bio for the appropriate container_of magic - */ -struct bio * -btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, - gfp_t gfp_flags) -{ - struct btrfs_io_bio *btrfs_bio; - struct bio *bio; - - bio = bio_alloc_bioset(gfp_flags, nr_vecs, btrfs_bioset); - - if (bio == NULL && (current->flags & PF_MEMALLOC)) { - while (!bio && (nr_vecs /= 2)) { - bio = bio_alloc_bioset(gfp_flags, - nr_vecs, btrfs_bioset); - } - } - - if (bio) { - bio->bi_bdev = bdev; - bio->bi_iter.bi_sector = first_sector; - btrfs_bio = btrfs_io_bio(bio); - btrfs_bio->csum = NULL; - btrfs_bio->csum_allocated = NULL; - btrfs_bio->end_io = NULL; - } - return bio; -} - -struct bio *btrfs_bio_clone(struct bio *bio, gfp_t gfp_mask) -{ - struct btrfs_io_bio *btrfs_bio; - struct bio *new; - - new = bio_clone_bioset(bio, gfp_mask, btrfs_bioset); - if (new) { - btrfs_bio = btrfs_io_bio(new); - btrfs_bio->csum = NULL; - btrfs_bio->csum_allocated = NULL; - btrfs_bio->end_io = NULL; - } - return new; -} - -/* this also allocates from the btrfs_bioset */ -struct bio *btrfs_io_bio_alloc(gfp_t gfp_mask, unsigned int nr_iovecs) -{ - struct btrfs_io_bio *btrfs_bio; - struct bio *bio; - - bio = bio_alloc_bioset(gfp_mask, nr_iovecs, btrfs_bioset); - if (bio) { - btrfs_bio = btrfs_io_bio(bio); - btrfs_bio->csum = NULL; - btrfs_bio->csum_allocated = NULL; - btrfs_bio->end_io = NULL; - } - return bio; -} - - -static int __must_check submit_one_bio(struct bio *bio, int mirror_num, - unsigned long bio_flags) -{ - int ret = 0; - struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1; - struct page *page = bvec->bv_page; - struct extent_io_tree *tree = bio->bi_private; - u64 start; - - start = page_offset(page) + bvec->bv_offset; - - bio->bi_private = NULL; - bio_get(bio); - - if (tree->ops && tree->ops->submit_bio_hook) - ret = tree->ops->submit_bio_hook(page->mapping->host, bio, - mirror_num, bio_flags, start); - else - btrfsic_submit_bio(bio); - - bio_put(bio); - return ret; -} - -static int merge_bio(struct extent_io_tree *tree, struct page *page, - unsigned long offset, size_t size, struct bio *bio, - unsigned long bio_flags) -{ - int ret = 0; - if (tree->ops && tree->ops->merge_bio_hook) - ret = tree->ops->merge_bio_hook(page, offset, size, bio, - bio_flags); - return ret; - -} - -static int submit_extent_page(int op, int op_flags, struct extent_io_tree *tree, - struct writeback_control *wbc, - struct page *page, sector_t sector, - size_t size, unsigned long offset, - struct block_device *bdev, - struct bio **bio_ret, - unsigned long max_pages, - bio_end_io_t end_io_func, - int mirror_num, - unsigned long prev_bio_flags, - unsigned long bio_flags, - bool force_bio_submit) -{ - int ret = 0; - struct bio *bio; - int contig = 0; - int old_compressed = prev_bio_flags & EXTENT_BIO_COMPRESSED; - size_t page_size = min_t(size_t, size, PAGE_SIZE); - - if (bio_ret && *bio_ret) { - bio = *bio_ret; - if (old_compressed) - contig = bio->bi_iter.bi_sector == sector; - else - contig = bio_end_sector(bio) == sector; - - if (prev_bio_flags != bio_flags || !contig || - force_bio_submit || - merge_bio(tree, page, offset, page_size, bio, bio_flags) || - bio_add_page(bio, page, page_size, offset) < page_size) { - ret = submit_one_bio(bio, mirror_num, prev_bio_flags); - if (ret < 0) { - *bio_ret = NULL; - return ret; - } - bio = NULL; - } else { - if (wbc) - wbc_account_io(wbc, page, page_size); - return 0; - } - } - - bio = btrfs_bio_alloc(bdev, sector, BIO_MAX_PAGES, - GFP_NOFS | __GFP_HIGH); - if (!bio) - return -ENOMEM; - - bio_add_page(bio, page, page_size, offset); - bio->bi_end_io = end_io_func; - bio->bi_private = tree; - bio_set_op_attrs(bio, op, op_flags); - if (wbc) { - wbc_init_bio(wbc, bio); - wbc_account_io(wbc, page, page_size); - } - - if (bio_ret) - *bio_ret = bio; - else - ret = submit_one_bio(bio, mirror_num, bio_flags); - - return ret; -} - -static void attach_extent_buffer_page(struct extent_buffer *eb, - struct page *page) -{ - if (!PagePrivate(page)) { - SetPagePrivate(page); - get_page(page); - set_page_private(page, (unsigned long)eb); - } else { - WARN_ON(page->private != (unsigned long)eb); - } -} - -void set_page_extent_mapped(struct page *page) -{ - if (!PagePrivate(page)) { - SetPagePrivate(page); - get_page(page); - set_page_private(page, EXTENT_PAGE_PRIVATE); - } -} - -static struct extent_map * -__get_extent_map(struct inode *inode, struct page *page, size_t pg_offset, - u64 start, u64 len, get_extent_t *get_extent, - struct extent_map **em_cached) -{ - struct extent_map *em; - - if (em_cached && *em_cached) { - em = *em_cached; - if (extent_map_in_tree(em) && start >= em->start && - start < extent_map_end(em)) { - atomic_inc(&em->refs); - return em; - } - - free_extent_map(em); - *em_cached = NULL; - } - - em = get_extent(inode, page, pg_offset, start, len, 0); - if (em_cached && !IS_ERR_OR_NULL(em)) { - BUG_ON(*em_cached); - atomic_inc(&em->refs); - *em_cached = em; - } - return em; -} -/* - * basic readpage implementation. Locked extent state structs are inserted - * into the tree that are removed when the IO is done (by the end_io - * handlers) - * XXX JDM: This needs looking at to ensure proper page locking - * return 0 on success, otherwise return error - */ -static int __do_readpage(struct extent_io_tree *tree, - struct page *page, - get_extent_t *get_extent, - struct extent_map **em_cached, - struct bio **bio, int mirror_num, - unsigned long *bio_flags, int read_flags, - u64 *prev_em_start) -{ - struct inode *inode = page->mapping->host; - u64 start = page_offset(page); - u64 page_end = start + PAGE_SIZE - 1; - u64 end; - u64 cur = start; - u64 extent_offset; - u64 last_byte = i_size_read(inode); - u64 block_start; - u64 cur_end; - sector_t sector; - struct extent_map *em; - struct block_device *bdev; - int ret = 0; - int nr = 0; - size_t pg_offset = 0; - size_t iosize; - size_t disk_io_size; - size_t blocksize = inode->i_sb->s_blocksize; - unsigned long this_bio_flag = 0; - - set_page_extent_mapped(page); - - end = page_end; - if (!PageUptodate(page)) { - if (cleancache_get_page(page) == 0) { - BUG_ON(blocksize != PAGE_SIZE); - unlock_extent(tree, start, end); - goto out; - } - } - - if (page->index == last_byte >> PAGE_SHIFT) { - char *userpage; - size_t zero_offset = last_byte & (PAGE_SIZE - 1); - - if (zero_offset) { - iosize = PAGE_SIZE - zero_offset; - userpage = kmap_atomic(page); - memset(userpage + zero_offset, 0, iosize); - flush_dcache_page(page); - kunmap_atomic(userpage); - } - } - while (cur <= end) { - unsigned long pnr = (last_byte >> PAGE_SHIFT) + 1; - bool force_bio_submit = false; - - if (cur >= last_byte) { - char *userpage; - struct extent_state *cached = NULL; - - iosize = PAGE_SIZE - pg_offset; - userpage = kmap_atomic(page); - memset(userpage + pg_offset, 0, iosize); - flush_dcache_page(page); - kunmap_atomic(userpage); - set_extent_uptodate(tree, cur, cur + iosize - 1, - &cached, GFP_NOFS); - unlock_extent_cached(tree, cur, - cur + iosize - 1, - &cached, GFP_NOFS); - break; - } - em = __get_extent_map(inode, page, pg_offset, cur, - end - cur + 1, get_extent, em_cached); - if (IS_ERR_OR_NULL(em)) { - SetPageError(page); - unlock_extent(tree, cur, end); - break; - } - extent_offset = cur - em->start; - BUG_ON(extent_map_end(em) <= cur); - BUG_ON(end < cur); - - if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) { - this_bio_flag |= EXTENT_BIO_COMPRESSED; - extent_set_compress_type(&this_bio_flag, - em->compress_type); - } - - iosize = min(extent_map_end(em) - cur, end - cur + 1); - cur_end = min(extent_map_end(em) - 1, end); - iosize = ALIGN(iosize, blocksize); - if (this_bio_flag & EXTENT_BIO_COMPRESSED) { - disk_io_size = em->block_len; - sector = em->block_start >> 9; - } else { - sector = (em->block_start + extent_offset) >> 9; - disk_io_size = iosize; - } - bdev = em->bdev; - block_start = em->block_start; - if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) - block_start = EXTENT_MAP_HOLE; - - /* - * If we have a file range that points to a compressed extent - * and it's followed by a consecutive file range that points to - * to the same compressed extent (possibly with a different - * offset and/or length, so it either points to the whole extent - * or only part of it), we must make sure we do not submit a - * single bio to populate the pages for the 2 ranges because - * this makes the compressed extent read zero out the pages - * belonging to the 2nd range. Imagine the following scenario: - * - * File layout - * [0 - 8K] [8K - 24K] - * | | - * | | - * points to extent X, points to extent X, - * offset 4K, length of 8K offset 0, length 16K - * - * [extent X, compressed length = 4K uncompressed length = 16K] - * - * If the bio to read the compressed extent covers both ranges, - * it will decompress extent X into the pages belonging to the - * first range and then it will stop, zeroing out the remaining - * pages that belong to the other range that points to extent X. - * So here we make sure we submit 2 bios, one for the first - * range and another one for the third range. Both will target - * the same physical extent from disk, but we can't currently - * make the compressed bio endio callback populate the pages - * for both ranges because each compressed bio is tightly - * coupled with a single extent map, and each range can have - * an extent map with a different offset value relative to the - * uncompressed data of our extent and different lengths. This - * is a corner case so we prioritize correctness over - * non-optimal behavior (submitting 2 bios for the same extent). - */ - if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags) && - prev_em_start && *prev_em_start != (u64)-1 && - *prev_em_start != em->orig_start) - force_bio_submit = true; - - if (prev_em_start) - *prev_em_start = em->orig_start; - - free_extent_map(em); - em = NULL; - - /* we've found a hole, just zero and go on */ - if (block_start == EXTENT_MAP_HOLE) { - char *userpage; - struct extent_state *cached = NULL; - - userpage = kmap_atomic(page); - memset(userpage + pg_offset, 0, iosize); - flush_dcache_page(page); - kunmap_atomic(userpage); - - set_extent_uptodate(tree, cur, cur + iosize - 1, - &cached, GFP_NOFS); - unlock_extent_cached(tree, cur, - cur + iosize - 1, - &cached, GFP_NOFS); - cur = cur + iosize; - pg_offset += iosize; - continue; - } - /* the get_extent function already copied into the page */ - if (test_range_bit(tree, cur, cur_end, - EXTENT_UPTODATE, 1, NULL)) { - check_page_uptodate(tree, page); - unlock_extent(tree, cur, cur + iosize - 1); - cur = cur + iosize; - pg_offset += iosize; - continue; - } - /* we have an inline extent but it didn't get marked up - * to date. Error out - */ - if (block_start == EXTENT_MAP_INLINE) { - SetPageError(page); - unlock_extent(tree, cur, cur + iosize - 1); - cur = cur + iosize; - pg_offset += iosize; - continue; - } - - pnr -= page->index; - ret = submit_extent_page(REQ_OP_READ, read_flags, tree, NULL, - page, sector, disk_io_size, pg_offset, - bdev, bio, pnr, - end_bio_extent_readpage, mirror_num, - *bio_flags, - this_bio_flag, - force_bio_submit); - if (!ret) { - nr++; - *bio_flags = this_bio_flag; - } else { - SetPageError(page); - unlock_extent(tree, cur, cur + iosize - 1); - goto out; - } - cur = cur + iosize; - pg_offset += iosize; - } -out: - if (!nr) { - if (!PageError(page)) - SetPageUptodate(page); - unlock_page(page); - } - return ret; -} - -static inline void __do_contiguous_readpages(struct extent_io_tree *tree, - struct page *pages[], int nr_pages, - u64 start, u64 end, - get_extent_t *get_extent, - struct extent_map **em_cached, - struct bio **bio, int mirror_num, - unsigned long *bio_flags, - u64 *prev_em_start) -{ - struct inode *inode; - struct btrfs_ordered_extent *ordered; - int index; - - inode = pages[0]->mapping->host; - while (1) { - lock_extent(tree, start, end); - ordered = btrfs_lookup_ordered_range(inode, start, - end - start + 1); - if (!ordered) - break; - unlock_extent(tree, start, end); - btrfs_start_ordered_extent(inode, ordered, 1); - btrfs_put_ordered_extent(ordered); - } - - for (index = 0; index < nr_pages; index++) { - __do_readpage(tree, pages[index], get_extent, em_cached, bio, - mirror_num, bio_flags, 0, prev_em_start); - put_page(pages[index]); - } -} - -static void __extent_readpages(struct extent_io_tree *tree, - struct page *pages[], - int nr_pages, get_extent_t *get_extent, - struct extent_map **em_cached, - struct bio **bio, int mirror_num, - unsigned long *bio_flags, - u64 *prev_em_start) -{ - u64 start = 0; - u64 end = 0; - u64 page_start; - int index; - int first_index = 0; - - for (index = 0; index < nr_pages; index++) { - page_start = page_offset(pages[index]); - if (!end) { - start = page_start; - end = start + PAGE_SIZE - 1; - first_index = index; - } else if (end + 1 == page_start) { - end += PAGE_SIZE; - } else { - __do_contiguous_readpages(tree, &pages[first_index], - index - first_index, start, - end, get_extent, em_cached, - bio, mirror_num, bio_flags, - prev_em_start); - start = page_start; - end = start + PAGE_SIZE - 1; - first_index = index; - } - } - - if (end) - __do_contiguous_readpages(tree, &pages[first_index], - index - first_index, start, - end, get_extent, em_cached, bio, - mirror_num, bio_flags, - prev_em_start); -} - -static int __extent_read_full_page(struct extent_io_tree *tree, - struct page *page, - get_extent_t *get_extent, - struct bio **bio, int mirror_num, - unsigned long *bio_flags, int read_flags) -{ - struct inode *inode = page->mapping->host; - struct btrfs_ordered_extent *ordered; - u64 start = page_offset(page); - u64 end = start + PAGE_SIZE - 1; - int ret; - - while (1) { - lock_extent(tree, start, end); - ordered = btrfs_lookup_ordered_range(inode, start, - PAGE_SIZE); - if (!ordered) - break; - unlock_extent(tree, start, end); - btrfs_start_ordered_extent(inode, ordered, 1); - btrfs_put_ordered_extent(ordered); - } - - ret = __do_readpage(tree, page, get_extent, NULL, bio, mirror_num, - bio_flags, read_flags, NULL); - return ret; -} - -int extent_read_full_page(struct extent_io_tree *tree, struct page *page, - get_extent_t *get_extent, int mirror_num) -{ - struct bio *bio = NULL; - unsigned long bio_flags = 0; - int ret; - - ret = __extent_read_full_page(tree, page, get_extent, &bio, mirror_num, - &bio_flags, 0); - if (bio) - ret = submit_one_bio(bio, mirror_num, bio_flags); - return ret; -} - -static void update_nr_written(struct page *page, struct writeback_control *wbc, - unsigned long nr_written) -{ - wbc->nr_to_write -= nr_written; -} - -/* - * helper for __extent_writepage, doing all of the delayed allocation setup. - * - * This returns 1 if our fill_delalloc function did all the work required - * to write the page (copy into inline extent). In this case the IO has - * been started and the page is already unlocked. - * - * This returns 0 if all went well (page still locked) - * This returns < 0 if there were errors (page still locked) - */ -static noinline_for_stack int writepage_delalloc(struct inode *inode, - struct page *page, struct writeback_control *wbc, - struct extent_page_data *epd, - u64 delalloc_start, - unsigned long *nr_written) -{ - struct extent_io_tree *tree = epd->tree; - u64 page_end = delalloc_start + PAGE_SIZE - 1; - u64 nr_delalloc; - u64 delalloc_to_write = 0; - u64 delalloc_end = 0; - int ret; - int page_started = 0; - - if (epd->extent_locked || !tree->ops || !tree->ops->fill_delalloc) - return 0; - - while (delalloc_end < page_end) { - nr_delalloc = find_lock_delalloc_range(inode, tree, - page, - &delalloc_start, - &delalloc_end, - BTRFS_MAX_EXTENT_SIZE); - if (nr_delalloc == 0) { - delalloc_start = delalloc_end + 1; - continue; - } - ret = tree->ops->fill_delalloc(inode, page, - delalloc_start, - delalloc_end, - &page_started, - nr_written); - /* File system has been set read-only */ - if (ret) { - SetPageError(page); - /* fill_delalloc should be return < 0 for error - * but just in case, we use > 0 here meaning the - * IO is started, so we don't want to return > 0 - * unless things are going well. - */ - ret = ret < 0 ? ret : -EIO; - goto done; - } - /* - * delalloc_end is already one less than the total length, so - * we don't subtract one from PAGE_SIZE - */ - delalloc_to_write += (delalloc_end - delalloc_start + - PAGE_SIZE) >> PAGE_SHIFT; - delalloc_start = delalloc_end + 1; - } - if (wbc->nr_to_write < delalloc_to_write) { - int thresh = 8192; - - if (delalloc_to_write < thresh * 2) - thresh = delalloc_to_write; - wbc->nr_to_write = min_t(u64, delalloc_to_write, - thresh); - } - - /* did the fill delalloc function already unlock and start - * the IO? - */ - if (page_started) { - /* - * we've unlocked the page, so we can't update - * the mapping's writeback index, just update - * nr_to_write. - */ - wbc->nr_to_write -= *nr_written; - return 1; - } - - ret = 0; - -done: - return ret; -} - -/* - * helper for __extent_writepage. This calls the writepage start hooks, - * and does the loop to map the page into extents and bios. - * - * We return 1 if the IO is started and the page is unlocked, - * 0 if all went well (page still locked) - * < 0 if there were errors (page still locked) - */ -static noinline_for_stack int __extent_writepage_io(struct inode *inode, - struct page *page, - struct writeback_control *wbc, - struct extent_page_data *epd, - loff_t i_size, - unsigned long nr_written, - int write_flags, int *nr_ret) -{ - struct extent_io_tree *tree = epd->tree; - u64 start = page_offset(page); - u64 page_end = start + PAGE_SIZE - 1; - u64 end; - u64 cur = start; - u64 extent_offset; - u64 block_start; - u64 iosize; - sector_t sector; - struct extent_state *cached_state = NULL; - struct extent_map *em; - struct block_device *bdev; - size_t pg_offset = 0; - size_t blocksize; - int ret = 0; - int nr = 0; - bool compressed; - - if (tree->ops && tree->ops->writepage_start_hook) { - ret = tree->ops->writepage_start_hook(page, start, - page_end); - if (ret) { - /* Fixup worker will requeue */ - if (ret == -EBUSY) - wbc->pages_skipped++; - else - redirty_page_for_writepage(wbc, page); - - update_nr_written(page, wbc, nr_written); - unlock_page(page); - ret = 1; - goto done_unlocked; - } - } - - /* - * we don't want to touch the inode after unlocking the page, - * so we update the mapping writeback index now - */ - update_nr_written(page, wbc, nr_written + 1); - - end = page_end; - if (i_size <= start) { - if (tree->ops && tree->ops->writepage_end_io_hook) - tree->ops->writepage_end_io_hook(page, start, - page_end, NULL, 1); - goto done; - } - - blocksize = inode->i_sb->s_blocksize; - - while (cur <= end) { - u64 em_end; - unsigned long max_nr; - - if (cur >= i_size) { - if (tree->ops && tree->ops->writepage_end_io_hook) - tree->ops->writepage_end_io_hook(page, cur, - page_end, NULL, 1); - break; - } - em = epd->get_extent(inode, page, pg_offset, cur, - end - cur + 1, 1); - if (IS_ERR_OR_NULL(em)) { - SetPageError(page); - ret = PTR_ERR_OR_ZERO(em); - break; - } - - extent_offset = cur - em->start; - em_end = extent_map_end(em); - BUG_ON(em_end <= cur); - BUG_ON(end < cur); - iosize = min(em_end - cur, end - cur + 1); - iosize = ALIGN(iosize, blocksize); - sector = (em->block_start + extent_offset) >> 9; - bdev = em->bdev; - block_start = em->block_start; - compressed = test_bit(EXTENT_FLAG_COMPRESSED, &em->flags); - free_extent_map(em); - em = NULL; - - /* - * compressed and inline extents are written through other - * paths in the FS - */ - if (compressed || block_start == EXTENT_MAP_HOLE || - block_start == EXTENT_MAP_INLINE) { - /* - * end_io notification does not happen here for - * compressed extents - */ - if (!compressed && tree->ops && - tree->ops->writepage_end_io_hook) - tree->ops->writepage_end_io_hook(page, cur, - cur + iosize - 1, - NULL, 1); - else if (compressed) { - /* we don't want to end_page_writeback on - * a compressed extent. this happens - * elsewhere - */ - nr++; - } - - cur += iosize; - pg_offset += iosize; - continue; - } - - max_nr = (i_size >> PAGE_SHIFT) + 1; - - set_range_writeback(tree, cur, cur + iosize - 1); - if (!PageWriteback(page)) { - btrfs_err(BTRFS_I(inode)->root->fs_info, - "page %lu not writeback, cur %llu end %llu", - page->index, cur, end); - } - - ret = submit_extent_page(REQ_OP_WRITE, write_flags, tree, wbc, - page, sector, iosize, pg_offset, - bdev, &epd->bio, max_nr, - end_bio_extent_writepage, - 0, 0, 0, false); - if (ret) - SetPageError(page); - - cur = cur + iosize; - pg_offset += iosize; - nr++; - } -done: - *nr_ret = nr; - -done_unlocked: - - /* drop our reference on any cached states */ - free_extent_state(cached_state); - return ret; -} - -/* - * the writepage semantics are similar to regular writepage. extent - * records are inserted to lock ranges in the tree, and as dirty areas - * are found, they are marked writeback. Then the lock bits are removed - * and the end_io handler clears the writeback ranges - */ -static int __extent_writepage(struct page *page, struct writeback_control *wbc, - void *data) -{ - struct inode *inode = page->mapping->host; - struct extent_page_data *epd = data; - u64 start = page_offset(page); - u64 page_end = start + PAGE_SIZE - 1; - int ret; - int nr = 0; - size_t pg_offset = 0; - loff_t i_size = i_size_read(inode); - unsigned long end_index = i_size >> PAGE_SHIFT; - int write_flags = 0; - unsigned long nr_written = 0; - - if (wbc->sync_mode == WB_SYNC_ALL) - write_flags = WRITE_SYNC; - - trace___extent_writepage(page, inode, wbc); - - WARN_ON(!PageLocked(page)); - - ClearPageError(page); - - pg_offset = i_size & (PAGE_SIZE - 1); - if (page->index > end_index || - (page->index == end_index && !pg_offset)) { - page->mapping->a_ops->invalidatepage(page, 0, PAGE_SIZE); - unlock_page(page); - return 0; - } - - if (page->index == end_index) { - char *userpage; - - userpage = kmap_atomic(page); - memset(userpage + pg_offset, 0, - PAGE_SIZE - pg_offset); - kunmap_atomic(userpage); - flush_dcache_page(page); - } - - pg_offset = 0; - - set_page_extent_mapped(page); - - ret = writepage_delalloc(inode, page, wbc, epd, start, &nr_written); - if (ret == 1) - goto done_unlocked; - if (ret) - goto done; - - ret = __extent_writepage_io(inode, page, wbc, epd, - i_size, nr_written, write_flags, &nr); - if (ret == 1) - goto done_unlocked; - -done: - if (nr == 0) { - /* make sure the mapping tag for page dirty gets cleared */ - set_page_writeback(page); - end_page_writeback(page); - } - if (PageError(page)) { - ret = ret < 0 ? ret : -EIO; - end_extent_writepage(page, ret, start, page_end); - } - unlock_page(page); - return ret; - -done_unlocked: - return 0; -} - -void wait_on_extent_buffer_writeback(struct extent_buffer *eb) -{ - wait_on_bit_io(&eb->bflags, EXTENT_BUFFER_WRITEBACK, - TASK_UNINTERRUPTIBLE); -} - -static noinline_for_stack int -lock_extent_buffer_for_io(struct extent_buffer *eb, - struct btrfs_fs_info *fs_info, - struct extent_page_data *epd) -{ - unsigned long i, num_pages; - int flush = 0; - int ret = 0; - - if (!btrfs_try_tree_write_lock(eb)) { - flush = 1; - flush_write_bio(epd); - btrfs_tree_lock(eb); - } - - if (test_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags)) { - btrfs_tree_unlock(eb); - if (!epd->sync_io) - return 0; - if (!flush) { - flush_write_bio(epd); - flush = 1; - } - while (1) { - wait_on_extent_buffer_writeback(eb); - btrfs_tree_lock(eb); - if (!test_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags)) - break; - btrfs_tree_unlock(eb); - } - } - - /* - * We need to do this to prevent races in people who check if the eb is - * under IO since we can end up having no IO bits set for a short period - * of time. - */ - spin_lock(&eb->refs_lock); - if (test_and_clear_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)) { - set_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags); - spin_unlock(&eb->refs_lock); - btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN); - __percpu_counter_add(&fs_info->dirty_metadata_bytes, - -eb->len, - fs_info->dirty_metadata_batch); - ret = 1; - } else { - spin_unlock(&eb->refs_lock); - } - - btrfs_tree_unlock(eb); - - if (!ret) - return ret; - - num_pages = num_extent_pages(eb->start, eb->len); - for (i = 0; i < num_pages; i++) { - struct page *p = eb->pages[i]; - - if (!trylock_page(p)) { - if (!flush) { - flush_write_bio(epd); - flush = 1; - } - lock_page(p); - } - } - - return ret; -} - -static void end_extent_buffer_writeback(struct extent_buffer *eb) -{ - clear_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags); - smp_mb__after_atomic(); - wake_up_bit(&eb->bflags, EXTENT_BUFFER_WRITEBACK); -} - -static void set_btree_ioerr(struct page *page) -{ - struct extent_buffer *eb = (struct extent_buffer *)page->private; - - SetPageError(page); - if (test_and_set_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags)) - return; - - /* - * If writeback for a btree extent that doesn't belong to a log tree - * failed, increment the counter transaction->eb_write_errors. - * We do this because while the transaction is running and before it's - * committing (when we call filemap_fdata[write|wait]_range against - * the btree inode), we might have - * btree_inode->i_mapping->a_ops->writepages() called by the VM - if it - * returns an error or an error happens during writeback, when we're - * committing the transaction we wouldn't know about it, since the pages - * can be no longer dirty nor marked anymore for writeback (if a - * subsequent modification to the extent buffer didn't happen before the - * transaction commit), which makes filemap_fdata[write|wait]_range not - * able to find the pages tagged with SetPageError at transaction - * commit time. So if this happens we must abort the transaction, - * otherwise we commit a super block with btree roots that point to - * btree nodes/leafs whose content on disk is invalid - either garbage - * or the content of some node/leaf from a past generation that got - * cowed or deleted and is no longer valid. - * - * Note: setting AS_EIO/AS_ENOSPC in the btree inode's i_mapping would - * not be enough - we need to distinguish between log tree extents vs - * non-log tree extents, and the next filemap_fdatawait_range() call - * will catch and clear such errors in the mapping - and that call might - * be from a log sync and not from a transaction commit. Also, checking - * for the eb flag EXTENT_BUFFER_WRITE_ERR at transaction commit time is - * not done and would not be reliable - the eb might have been released - * from memory and reading it back again means that flag would not be - * set (since it's a runtime flag, not persisted on disk). - * - * Using the flags below in the btree inode also makes us achieve the - * goal of AS_EIO/AS_ENOSPC when writepages() returns success, started - * writeback for all dirty pages and before filemap_fdatawait_range() - * is called, the writeback for all dirty pages had already finished - * with errors - because we were not using AS_EIO/AS_ENOSPC, - * filemap_fdatawait_range() would return success, as it could not know - * that writeback errors happened (the pages were no longer tagged for - * writeback). - */ - switch (eb->log_index) { - case -1: - set_bit(BTRFS_FS_BTREE_ERR, &eb->fs_info->flags); - break; - case 0: - set_bit(BTRFS_FS_LOG1_ERR, &eb->fs_info->flags); - break; - case 1: - set_bit(BTRFS_FS_LOG2_ERR, &eb->fs_info->flags); - break; - default: - BUG(); /* unexpected, logic error */ - } -} - -static void end_bio_extent_buffer_writepage(struct bio *bio) -{ - struct bio_vec *bvec; - struct extent_buffer *eb; - int i, done; - - bio_for_each_segment_all(bvec, bio, i) { - struct page *page = bvec->bv_page; - - eb = (struct extent_buffer *)page->private; - BUG_ON(!eb); - done = atomic_dec_and_test(&eb->io_pages); - - if (bio->bi_error || - test_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags)) { - ClearPageUptodate(page); - set_btree_ioerr(page); - } - - end_page_writeback(page); - - if (!done) - continue; - - end_extent_buffer_writeback(eb); - } - - bio_put(bio); -} - -static noinline_for_stack int write_one_eb(struct extent_buffer *eb, - struct btrfs_fs_info *fs_info, - struct writeback_control *wbc, - struct extent_page_data *epd) -{ - struct block_device *bdev = fs_info->fs_devices->latest_bdev; - struct extent_io_tree *tree = &BTRFS_I(fs_info->btree_inode)->io_tree; - u64 offset = eb->start; - u32 nritems; - unsigned long i, num_pages; - unsigned long bio_flags = 0; - unsigned long start, end; - int write_flags = (epd->sync_io ? WRITE_SYNC : 0) | REQ_META; - int ret = 0; - - clear_bit(EXTENT_BUFFER_WRITE_ERR, &eb->bflags); - num_pages = num_extent_pages(eb->start, eb->len); - atomic_set(&eb->io_pages, num_pages); - if (btrfs_header_owner(eb) == BTRFS_TREE_LOG_OBJECTID) - bio_flags = EXTENT_BIO_TREE_LOG; - - /* set btree blocks beyond nritems with 0 to avoid stale content. */ - nritems = btrfs_header_nritems(eb); - if (btrfs_header_level(eb) > 0) { - end = btrfs_node_key_ptr_offset(nritems); - - memset_extent_buffer(eb, 0, end, eb->len - end); - } else { - /* - * leaf: - * header 0 1 2 .. N ... data_N .. data_2 data_1 data_0 - */ - start = btrfs_item_nr_offset(nritems); - end = btrfs_leaf_data(eb) + - leaf_data_end(fs_info->tree_root, eb); - memset_extent_buffer(eb, 0, start, end - start); - } - - for (i = 0; i < num_pages; i++) { - struct page *p = eb->pages[i]; - - clear_page_dirty_for_io(p); - set_page_writeback(p); - ret = submit_extent_page(REQ_OP_WRITE, write_flags, tree, wbc, - p, offset >> 9, PAGE_SIZE, 0, bdev, - &epd->bio, -1, - end_bio_extent_buffer_writepage, - 0, epd->bio_flags, bio_flags, false); - epd->bio_flags = bio_flags; - if (ret) { - set_btree_ioerr(p); - end_page_writeback(p); - if (atomic_sub_and_test(num_pages - i, &eb->io_pages)) - end_extent_buffer_writeback(eb); - ret = -EIO; - break; - } - offset += PAGE_SIZE; - update_nr_written(p, wbc, 1); - unlock_page(p); - } - - if (unlikely(ret)) { - for (; i < num_pages; i++) { - struct page *p = eb->pages[i]; - clear_page_dirty_for_io(p); - unlock_page(p); - } - } - - return ret; -} - -int btree_write_cache_pages(struct address_space *mapping, - struct writeback_control *wbc) -{ - struct extent_io_tree *tree = &BTRFS_I(mapping->host)->io_tree; - struct btrfs_fs_info *fs_info = BTRFS_I(mapping->host)->root->fs_info; - struct extent_buffer *eb, *prev_eb = NULL; - struct extent_page_data epd = { - .bio = NULL, - .tree = tree, - .extent_locked = 0, - .sync_io = wbc->sync_mode == WB_SYNC_ALL, - .bio_flags = 0, - }; - int ret = 0; - int done = 0; - int nr_to_write_done = 0; - struct pagevec pvec; - int nr_pages; - pgoff_t index; - pgoff_t end; /* Inclusive */ - int scanned = 0; - int tag; - - pagevec_init(&pvec, 0); - if (wbc->range_cyclic) { - index = mapping->writeback_index; /* Start from prev offset */ - end = -1; - } else { - index = wbc->range_start >> PAGE_SHIFT; - end = wbc->range_end >> PAGE_SHIFT; - scanned = 1; - } - if (wbc->sync_mode == WB_SYNC_ALL) - tag = PAGECACHE_TAG_TOWRITE; - else - tag = PAGECACHE_TAG_DIRTY; -retry: - if (wbc->sync_mode == WB_SYNC_ALL) - tag_pages_for_writeback(mapping, index, end); - while (!done && !nr_to_write_done && (index <= end) && - (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag, - min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) { - unsigned i; - - scanned = 1; - for (i = 0; i < nr_pages; i++) { - struct page *page = pvec.pages[i]; - - if (!PagePrivate(page)) - continue; - - if (!wbc->range_cyclic && page->index > end) { - done = 1; - break; - } - - spin_lock(&mapping->private_lock); - if (!PagePrivate(page)) { - spin_unlock(&mapping->private_lock); - continue; - } - - eb = (struct extent_buffer *)page->private; - - /* - * Shouldn't happen and normally this would be a BUG_ON - * but no sense in crashing the users box for something - * we can survive anyway. - */ - if (WARN_ON(!eb)) { - spin_unlock(&mapping->private_lock); - continue; - } - - if (eb == prev_eb) { - spin_unlock(&mapping->private_lock); - continue; - } - - ret = atomic_inc_not_zero(&eb->refs); - spin_unlock(&mapping->private_lock); - if (!ret) - continue; - - prev_eb = eb; - ret = lock_extent_buffer_for_io(eb, fs_info, &epd); - if (!ret) { - free_extent_buffer(eb); - continue; - } - - ret = write_one_eb(eb, fs_info, wbc, &epd); - if (ret) { - done = 1; - free_extent_buffer(eb); - break; - } - free_extent_buffer(eb); - - /* - * the filesystem may choose to bump up nr_to_write. - * We have to make sure to honor the new nr_to_write - * at any time - */ - nr_to_write_done = wbc->nr_to_write <= 0; - } - pagevec_release(&pvec); - cond_resched(); - } - if (!scanned && !done) { - /* - * We hit the last page and there is more work to be done: wrap - * back to the start of the file - */ - scanned = 1; - index = 0; - goto retry; - } - flush_write_bio(&epd); - return ret; -} - -/** - * write_cache_pages - walk the list of dirty pages of the given address space and write all of them. - * @mapping: address space structure to write - * @wbc: subtract the number of written pages from *@wbc->nr_to_write - * @writepage: function called for each page - * @data: data passed to writepage function - * - * If a page is already under I/O, write_cache_pages() skips it, even - * if it's dirty. This is desirable behaviour for memory-cleaning writeback, - * but it is INCORRECT for data-integrity system calls such as fsync(). fsync() - * and msync() need to guarantee that all the data which was dirty at the time - * the call was made get new I/O started against them. If wbc->sync_mode is - * WB_SYNC_ALL then we were called for data integrity and we must wait for - * existing IO to complete. - */ -static int extent_write_cache_pages(struct extent_io_tree *tree, - struct address_space *mapping, - struct writeback_control *wbc, - writepage_t writepage, void *data, - void (*flush_fn)(void *)) -{ - struct inode *inode = mapping->host; - int ret = 0; - int done = 0; - int nr_to_write_done = 0; - struct pagevec pvec; - int nr_pages; - pgoff_t index; - pgoff_t end; /* Inclusive */ - pgoff_t done_index; - int range_whole = 0; - int scanned = 0; - int tag; - - /* - * We have to hold onto the inode so that ordered extents can do their - * work when the IO finishes. The alternative to this is failing to add - * an ordered extent if the igrab() fails there and that is a huge pain - * to deal with, so instead just hold onto the inode throughout the - * writepages operation. If it fails here we are freeing up the inode - * anyway and we'd rather not waste our time writing out stuff that is - * going to be truncated anyway. - */ - if (!igrab(inode)) - return 0; - - pagevec_init(&pvec, 0); - if (wbc->range_cyclic) { - index = mapping->writeback_index; /* Start from prev offset */ - end = -1; - } else { - index = wbc->range_start >> PAGE_SHIFT; - end = wbc->range_end >> PAGE_SHIFT; - if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) - range_whole = 1; - scanned = 1; - } - if (wbc->sync_mode == WB_SYNC_ALL) - tag = PAGECACHE_TAG_TOWRITE; - else - tag = PAGECACHE_TAG_DIRTY; -retry: - if (wbc->sync_mode == WB_SYNC_ALL) - tag_pages_for_writeback(mapping, index, end); - done_index = index; - while (!done && !nr_to_write_done && (index <= end) && - (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag, - min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1))) { - unsigned i; - - scanned = 1; - for (i = 0; i < nr_pages; i++) { - struct page *page = pvec.pages[i]; - - done_index = page->index; - /* - * At this point we hold neither mapping->tree_lock nor - * lock on the page itself: the page may be truncated or - * invalidated (changing page->mapping to NULL), or even - * swizzled back from swapper_space to tmpfs file - * mapping - */ - if (!trylock_page(page)) { - flush_fn(data); - lock_page(page); - } - - if (unlikely(page->mapping != mapping)) { - unlock_page(page); - continue; - } - - if (!wbc->range_cyclic && page->index > end) { - done = 1; - unlock_page(page); - continue; - } - - if (wbc->sync_mode != WB_SYNC_NONE) { - if (PageWriteback(page)) - flush_fn(data); - wait_on_page_writeback(page); - } - - if (PageWriteback(page) || - !clear_page_dirty_for_io(page)) { - unlock_page(page); - continue; - } - - ret = (*writepage)(page, wbc, data); - - if (unlikely(ret == AOP_WRITEPAGE_ACTIVATE)) { - unlock_page(page); - ret = 0; - } - if (ret < 0) { - /* - * done_index is set past this page, - * so media errors will not choke - * background writeout for the entire - * file. This has consequences for - * range_cyclic semantics (ie. it may - * not be suitable for data integrity - * writeout). - */ - done_index = page->index + 1; - done = 1; - break; - } - - /* - * the filesystem may choose to bump up nr_to_write. - * We have to make sure to honor the new nr_to_write - * at any time - */ - nr_to_write_done = wbc->nr_to_write <= 0; - } - pagevec_release(&pvec); - cond_resched(); - } - if (!scanned && !done) { - /* - * We hit the last page and there is more work to be done: wrap - * back to the start of the file - */ - scanned = 1; - index = 0; - goto retry; - } - - if (wbc->range_cyclic || (wbc->nr_to_write > 0 && range_whole)) - mapping->writeback_index = done_index; - - btrfs_add_delayed_iput(inode); - return ret; -} - -static void flush_epd_write_bio(struct extent_page_data *epd) -{ - if (epd->bio) { - int ret; - - bio_set_op_attrs(epd->bio, REQ_OP_WRITE, - epd->sync_io ? WRITE_SYNC : 0); - - ret = submit_one_bio(epd->bio, 0, epd->bio_flags); - BUG_ON(ret < 0); /* -ENOMEM */ - epd->bio = NULL; - } -} - -static noinline void flush_write_bio(void *data) -{ - struct extent_page_data *epd = data; - flush_epd_write_bio(epd); -} - -int extent_write_full_page(struct extent_io_tree *tree, struct page *page, - get_extent_t *get_extent, - struct writeback_control *wbc) -{ - int ret; - struct extent_page_data epd = { - .bio = NULL, - .tree = tree, - .get_extent = get_extent, - .extent_locked = 0, - .sync_io = wbc->sync_mode == WB_SYNC_ALL, - .bio_flags = 0, - }; - - ret = __extent_writepage(page, wbc, &epd); - - flush_epd_write_bio(&epd); - return ret; -} - -int extent_write_locked_range(struct extent_io_tree *tree, struct inode *inode, - u64 start, u64 end, get_extent_t *get_extent, - int mode) -{ - int ret = 0; - struct address_space *mapping = inode->i_mapping; - struct page *page; - unsigned long nr_pages = (end - start + PAGE_SIZE) >> - PAGE_SHIFT; - - struct extent_page_data epd = { - .bio = NULL, - .tree = tree, - .get_extent = get_extent, - .extent_locked = 1, - .sync_io = mode == WB_SYNC_ALL, - .bio_flags = 0, - }; - struct writeback_control wbc_writepages = { - .sync_mode = mode, - .nr_to_write = nr_pages * 2, - .range_start = start, - .range_end = end + 1, - }; - - while (start <= end) { - page = find_get_page(mapping, start >> PAGE_SHIFT); - if (clear_page_dirty_for_io(page)) - ret = __extent_writepage(page, &wbc_writepages, &epd); - else { - if (tree->ops && tree->ops->writepage_end_io_hook) - tree->ops->writepage_end_io_hook(page, start, - start + PAGE_SIZE - 1, - NULL, 1); - unlock_page(page); - } - put_page(page); - start += PAGE_SIZE; - } - - flush_epd_write_bio(&epd); - return ret; -} - -int extent_writepages(struct extent_io_tree *tree, - struct address_space *mapping, - get_extent_t *get_extent, - struct writeback_control *wbc) -{ - int ret = 0; - struct extent_page_data epd = { - .bio = NULL, - .tree = tree, - .get_extent = get_extent, - .extent_locked = 0, - .sync_io = wbc->sync_mode == WB_SYNC_ALL, - .bio_flags = 0, - }; - - ret = extent_write_cache_pages(tree, mapping, wbc, - __extent_writepage, &epd, - flush_write_bio); - flush_epd_write_bio(&epd); - return ret; -} - -int extent_readpages(struct extent_io_tree *tree, - struct address_space *mapping, - struct list_head *pages, unsigned nr_pages, - get_extent_t get_extent) -{ - struct bio *bio = NULL; - unsigned page_idx; - unsigned long bio_flags = 0; - struct page *pagepool[16]; - struct page *page; - struct extent_map *em_cached = NULL; - int nr = 0; - u64 prev_em_start = (u64)-1; - - for (page_idx = 0; page_idx < nr_pages; page_idx++) { - page = list_entry(pages->prev, struct page, lru); - - prefetchw(&page->flags); - list_del(&page->lru); - if (add_to_page_cache_lru(page, mapping, - page->index, - readahead_gfp_mask(mapping))) { - put_page(page); - continue; - } - - pagepool[nr++] = page; - if (nr < ARRAY_SIZE(pagepool)) - continue; - __extent_readpages(tree, pagepool, nr, get_extent, &em_cached, - &bio, 0, &bio_flags, &prev_em_start); - nr = 0; - } - if (nr) - __extent_readpages(tree, pagepool, nr, get_extent, &em_cached, - &bio, 0, &bio_flags, &prev_em_start); - - if (em_cached) - free_extent_map(em_cached); - - BUG_ON(!list_empty(pages)); - if (bio) - return submit_one_bio(bio, 0, bio_flags); - return 0; -} - -/* - * basic invalidatepage code, this waits on any locked or writeback - * ranges corresponding to the page, and then deletes any extent state - * records from the tree - */ -int extent_invalidatepage(struct extent_io_tree *tree, - struct page *page, unsigned long offset) -{ - struct extent_state *cached_state = NULL; - u64 start = page_offset(page); - u64 end = start + PAGE_SIZE - 1; - size_t blocksize = page->mapping->host->i_sb->s_blocksize; - - start += ALIGN(offset, blocksize); - if (start > end) - return 0; - - lock_extent_bits(tree, start, end, &cached_state); - wait_on_page_writeback(page); - clear_extent_bit(tree, start, end, - EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC | - EXTENT_DO_ACCOUNTING, - 1, 1, &cached_state, GFP_NOFS); - return 0; -} - -/* - * a helper for releasepage, this tests for areas of the page that - * are locked or under IO and drops the related state bits if it is safe - * to drop the page. - */ -static int try_release_extent_state(struct extent_map_tree *map, - struct extent_io_tree *tree, - struct page *page, gfp_t mask) -{ - u64 start = page_offset(page); - u64 end = start + PAGE_SIZE - 1; - int ret = 1; - - if (test_range_bit(tree, start, end, - EXTENT_IOBITS, 0, NULL)) - ret = 0; - else { - if ((mask & GFP_NOFS) == GFP_NOFS) - mask = GFP_NOFS; - /* - * at this point we can safely clear everything except the - * locked bit and the nodatasum bit - */ - ret = clear_extent_bit(tree, start, end, - ~(EXTENT_LOCKED | EXTENT_NODATASUM), - 0, 0, NULL, mask); - - /* if clear_extent_bit failed for enomem reasons, - * we can't allow the release to continue. - */ - if (ret < 0) - ret = 0; - else - ret = 1; - } - return ret; -} - -/* - * a helper for releasepage. As long as there are no locked extents - * in the range corresponding to the page, both state records and extent - * map records are removed - */ -int try_release_extent_mapping(struct extent_map_tree *map, - struct extent_io_tree *tree, struct page *page, - gfp_t mask) -{ - struct extent_map *em; - u64 start = page_offset(page); - u64 end = start + PAGE_SIZE - 1; - - if (gfpflags_allow_blocking(mask) && - page->mapping->host->i_size > SZ_16M) { - u64 len; - while (start <= end) { - len = end - start + 1; - write_lock(&map->lock); - em = lookup_extent_mapping(map, start, len); - if (!em) { - write_unlock(&map->lock); - break; - } - if (test_bit(EXTENT_FLAG_PINNED, &em->flags) || - em->start != start) { - write_unlock(&map->lock); - free_extent_map(em); - break; - } - if (!test_range_bit(tree, em->start, - extent_map_end(em) - 1, - EXTENT_LOCKED | EXTENT_WRITEBACK, - 0, NULL)) { - remove_extent_mapping(map, em); - /* once for the rb tree */ - free_extent_map(em); - } - start = extent_map_end(em); - write_unlock(&map->lock); - - /* once for us */ - free_extent_map(em); - } - } - return try_release_extent_state(map, tree, page, mask); -} - -/* - * helper function for fiemap, which doesn't want to see any holes. - * This maps until we find something past 'last' - */ -static struct extent_map *get_extent_skip_holes(struct inode *inode, - u64 offset, - u64 last, - get_extent_t *get_extent) -{ - u64 sectorsize = BTRFS_I(inode)->root->sectorsize; - struct extent_map *em; - u64 len; - - if (offset >= last) - return NULL; - - while (1) { - len = last - offset; - if (len == 0) - break; - len = ALIGN(len, sectorsize); - em = get_extent(inode, NULL, 0, offset, len, 0); - if (IS_ERR_OR_NULL(em)) - return em; - - /* if this isn't a hole return it */ - if (!test_bit(EXTENT_FLAG_VACANCY, &em->flags) && - em->block_start != EXTENT_MAP_HOLE) { - return em; - } - - /* this is a hole, advance to the next extent */ - offset = extent_map_end(em); - free_extent_map(em); - if (offset >= last) - break; - } - return NULL; -} - -int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, - __u64 start, __u64 len, get_extent_t *get_extent) -{ - int ret = 0; - u64 off = start; - u64 max = start + len; - u32 flags = 0; - u32 found_type; - u64 last; - u64 last_for_get_extent = 0; - u64 disko = 0; - u64 isize = i_size_read(inode); - struct btrfs_key found_key; - struct extent_map *em = NULL; - struct extent_state *cached_state = NULL; - struct btrfs_path *path; - struct btrfs_root *root = BTRFS_I(inode)->root; - int end = 0; - u64 em_start = 0; - u64 em_len = 0; - u64 em_end = 0; - - if (len == 0) - return -EINVAL; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->leave_spinning = 1; - - start = round_down(start, BTRFS_I(inode)->root->sectorsize); - len = round_up(max, BTRFS_I(inode)->root->sectorsize) - start; - - /* - * lookup the last file extent. We're not using i_size here - * because there might be preallocation past i_size - */ - ret = btrfs_lookup_file_extent(NULL, root, path, btrfs_ino(inode), -1, - 0); - if (ret < 0) { - btrfs_free_path(path); - return ret; - } else { - WARN_ON(!ret); - if (ret == 1) - ret = 0; - } - - path->slots[0]--; - btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]); - found_type = found_key.type; - - /* No extents, but there might be delalloc bits */ - if (found_key.objectid != btrfs_ino(inode) || - found_type != BTRFS_EXTENT_DATA_KEY) { - /* have to trust i_size as the end */ - last = (u64)-1; - last_for_get_extent = isize; - } else { - /* - * remember the start of the last extent. There are a - * bunch of different factors that go into the length of the - * extent, so its much less complex to remember where it started - */ - last = found_key.offset; - last_for_get_extent = last + 1; - } - btrfs_release_path(path); - - /* - * we might have some extents allocated but more delalloc past those - * extents. so, we trust isize unless the start of the last extent is - * beyond isize - */ - if (last < isize) { - last = (u64)-1; - last_for_get_extent = isize; - } - - lock_extent_bits(&BTRFS_I(inode)->io_tree, start, start + len - 1, - &cached_state); - - em = get_extent_skip_holes(inode, start, last_for_get_extent, - get_extent); - if (!em) - goto out; - if (IS_ERR(em)) { - ret = PTR_ERR(em); - goto out; - } - - while (!end) { - u64 offset_in_extent = 0; - - /* break if the extent we found is outside the range */ - if (em->start >= max || extent_map_end(em) < off) - break; - - /* - * get_extent may return an extent that starts before our - * requested range. We have to make sure the ranges - * we return to fiemap always move forward and don't - * overlap, so adjust the offsets here - */ - em_start = max(em->start, off); - - /* - * record the offset from the start of the extent - * for adjusting the disk offset below. Only do this if the - * extent isn't compressed since our in ram offset may be past - * what we have actually allocated on disk. - */ - if (!test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) - offset_in_extent = em_start - em->start; - em_end = extent_map_end(em); - em_len = em_end - em_start; - disko = 0; - flags = 0; - - /* - * bump off for our next call to get_extent - */ - off = extent_map_end(em); - if (off >= max) - end = 1; - - if (em->block_start == EXTENT_MAP_LAST_BYTE) { - end = 1; - flags |= FIEMAP_EXTENT_LAST; - } else if (em->block_start == EXTENT_MAP_INLINE) { - flags |= (FIEMAP_EXTENT_DATA_INLINE | - FIEMAP_EXTENT_NOT_ALIGNED); - } else if (em->block_start == EXTENT_MAP_DELALLOC) { - flags |= (FIEMAP_EXTENT_DELALLOC | - FIEMAP_EXTENT_UNKNOWN); - } else if (fieinfo->fi_extents_max) { - struct btrfs_trans_handle *trans; - - u64 bytenr = em->block_start - - (em->start - em->orig_start); - - disko = em->block_start + offset_in_extent; - - /* - * We need a trans handle to get delayed refs - */ - trans = btrfs_join_transaction(root); - /* - * It's OK if we can't start a trans we can still check - * from commit_root - */ - if (IS_ERR(trans)) - trans = NULL; - - /* - * As btrfs supports shared space, this information - * can be exported to userspace tools via - * flag FIEMAP_EXTENT_SHARED. If fi_extents_max == 0 - * then we're just getting a count and we can skip the - * lookup stuff. - */ - ret = btrfs_check_shared(trans, root->fs_info, - root->objectid, - btrfs_ino(inode), bytenr); - if (trans) - btrfs_end_transaction(trans, root); - if (ret < 0) - goto out_free; - if (ret) - flags |= FIEMAP_EXTENT_SHARED; - ret = 0; - } - if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) - flags |= FIEMAP_EXTENT_ENCODED; - if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) - flags |= FIEMAP_EXTENT_UNWRITTEN; - - free_extent_map(em); - em = NULL; - if ((em_start >= last) || em_len == (u64)-1 || - (last == (u64)-1 && isize <= em_end)) { - flags |= FIEMAP_EXTENT_LAST; - end = 1; - } - - /* now scan forward to see if this is really the last extent. */ - em = get_extent_skip_holes(inode, off, last_for_get_extent, - get_extent); - if (IS_ERR(em)) { - ret = PTR_ERR(em); - goto out; - } - if (!em) { - flags |= FIEMAP_EXTENT_LAST; - end = 1; - } - ret = fiemap_fill_next_extent(fieinfo, em_start, disko, - em_len, flags); - if (ret) { - if (ret == 1) - ret = 0; - goto out_free; - } - } -out_free: - free_extent_map(em); -out: - btrfs_free_path(path); - unlock_extent_cached(&BTRFS_I(inode)->io_tree, start, start + len - 1, - &cached_state, GFP_NOFS); - return ret; -} - -static void __free_extent_buffer(struct extent_buffer *eb) -{ - btrfs_leak_debug_del(&eb->leak_list); - kmem_cache_free(extent_buffer_cache, eb); -} - -int extent_buffer_under_io(struct extent_buffer *eb) -{ - return (atomic_read(&eb->io_pages) || - test_bit(EXTENT_BUFFER_WRITEBACK, &eb->bflags) || - test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)); -} - -/* - * Helper for releasing extent buffer page. - */ -static void btrfs_release_extent_buffer_page(struct extent_buffer *eb) -{ - unsigned long index; - struct page *page; - int mapped = !test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags); - - BUG_ON(extent_buffer_under_io(eb)); - - index = num_extent_pages(eb->start, eb->len); - if (index == 0) - return; - - do { - index--; - page = eb->pages[index]; - if (!page) - continue; - if (mapped) - spin_lock(&page->mapping->private_lock); - /* - * We do this since we'll remove the pages after we've - * removed the eb from the radix tree, so we could race - * and have this page now attached to the new eb. So - * only clear page_private if it's still connected to - * this eb. - */ - if (PagePrivate(page) && - page->private == (unsigned long)eb) { - BUG_ON(test_bit(EXTENT_BUFFER_DIRTY, &eb->bflags)); - BUG_ON(PageDirty(page)); - BUG_ON(PageWriteback(page)); - /* - * We need to make sure we haven't be attached - * to a new eb. - */ - ClearPagePrivate(page); - set_page_private(page, 0); - /* One for the page private */ - put_page(page); - } - - if (mapped) - spin_unlock(&page->mapping->private_lock); - - /* One for when we allocated the page */ - put_page(page); - } while (index != 0); -} - -/* - * Helper for releasing the extent buffer. - */ -static inline void btrfs_release_extent_buffer(struct extent_buffer *eb) -{ - btrfs_release_extent_buffer_page(eb); - __free_extent_buffer(eb); -} - -static struct extent_buffer * -__alloc_extent_buffer(struct btrfs_fs_info *fs_info, u64 start, - unsigned long len) -{ - struct extent_buffer *eb = NULL; - - eb = kmem_cache_zalloc(extent_buffer_cache, GFP_NOFS|__GFP_NOFAIL); - eb->start = start; - eb->len = len; - eb->fs_info = fs_info; - eb->bflags = 0; - rwlock_init(&eb->lock); - atomic_set(&eb->write_locks, 0); - atomic_set(&eb->read_locks, 0); - atomic_set(&eb->blocking_readers, 0); - atomic_set(&eb->blocking_writers, 0); - atomic_set(&eb->spinning_readers, 0); - atomic_set(&eb->spinning_writers, 0); - eb->lock_nested = 0; - init_waitqueue_head(&eb->write_lock_wq); - init_waitqueue_head(&eb->read_lock_wq); - - btrfs_leak_debug_add(&eb->leak_list, &buffers); - - spin_lock_init(&eb->refs_lock); - atomic_set(&eb->refs, 1); - atomic_set(&eb->io_pages, 0); - - /* - * Sanity checks, currently the maximum is 64k covered by 16x 4k pages - */ - BUILD_BUG_ON(BTRFS_MAX_METADATA_BLOCKSIZE - > MAX_INLINE_EXTENT_BUFFER_SIZE); - BUG_ON(len > MAX_INLINE_EXTENT_BUFFER_SIZE); - - return eb; -} - -struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src) -{ - unsigned long i; - struct page *p; - struct extent_buffer *new; - unsigned long num_pages = num_extent_pages(src->start, src->len); - - new = __alloc_extent_buffer(src->fs_info, src->start, src->len); - if (new == NULL) - return NULL; - - for (i = 0; i < num_pages; i++) { - p = alloc_page(GFP_NOFS); - if (!p) { - btrfs_release_extent_buffer(new); - return NULL; - } - attach_extent_buffer_page(new, p); - WARN_ON(PageDirty(p)); - SetPageUptodate(p); - new->pages[i] = p; - } - - copy_extent_buffer(new, src, 0, 0, src->len); - set_bit(EXTENT_BUFFER_UPTODATE, &new->bflags); - set_bit(EXTENT_BUFFER_DUMMY, &new->bflags); - - return new; -} - -struct extent_buffer *__alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info, - u64 start, unsigned long len) -{ - struct extent_buffer *eb; - unsigned long num_pages; - unsigned long i; - - num_pages = num_extent_pages(start, len); - - eb = __alloc_extent_buffer(fs_info, start, len); - if (!eb) - return NULL; - - for (i = 0; i < num_pages; i++) { - eb->pages[i] = alloc_page(GFP_NOFS); - if (!eb->pages[i]) - goto err; - } - set_extent_buffer_uptodate(eb); - btrfs_set_header_nritems(eb, 0); - set_bit(EXTENT_BUFFER_DUMMY, &eb->bflags); - - return eb; -err: - for (; i > 0; i--) - __free_page(eb->pages[i - 1]); - __free_extent_buffer(eb); - return NULL; -} - -struct extent_buffer *alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info, - u64 start, u32 nodesize) -{ - unsigned long len; - - if (!fs_info) { - /* - * Called only from tests that don't always have a fs_info - * available - */ - len = nodesize; - } else { - len = fs_info->tree_root->nodesize; - } - - return __alloc_dummy_extent_buffer(fs_info, start, len); -} - -static void check_buffer_tree_ref(struct extent_buffer *eb) -{ - int refs; - /* the ref bit is tricky. We have to make sure it is set - * if we have the buffer dirty. Otherwise the - * code to free a buffer can end up dropping a dirty - * page - * - * Once the ref bit is set, it won't go away while the - * buffer is dirty or in writeback, and it also won't - * go away while we have the reference count on the - * eb bumped. - * - * We can't just set the ref bit without bumping the - * ref on the eb because free_extent_buffer might - * see the ref bit and try to clear it. If this happens - * free_extent_buffer might end up dropping our original - * ref by mistake and freeing the page before we are able - * to add one more ref. - * - * So bump the ref count first, then set the bit. If someone - * beat us to it, drop the ref we added. - */ - refs = atomic_read(&eb->refs); - if (refs >= 2 && test_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)) - return; - - spin_lock(&eb->refs_lock); - if (!test_and_set_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)) - atomic_inc(&eb->refs); - spin_unlock(&eb->refs_lock); -} - -static void mark_extent_buffer_accessed(struct extent_buffer *eb, - struct page *accessed) -{ - unsigned long num_pages, i; - - check_buffer_tree_ref(eb); - - num_pages = num_extent_pages(eb->start, eb->len); - for (i = 0; i < num_pages; i++) { - struct page *p = eb->pages[i]; - - if (p != accessed) - mark_page_accessed(p); - } -} - -struct extent_buffer *find_extent_buffer(struct btrfs_fs_info *fs_info, - u64 start) -{ - struct extent_buffer *eb; - - rcu_read_lock(); - eb = radix_tree_lookup(&fs_info->buffer_radix, - start >> PAGE_SHIFT); - if (eb && atomic_inc_not_zero(&eb->refs)) { - rcu_read_unlock(); - /* - * Lock our eb's refs_lock to avoid races with - * free_extent_buffer. When we get our eb it might be flagged - * with EXTENT_BUFFER_STALE and another task running - * free_extent_buffer might have seen that flag set, - * eb->refs == 2, that the buffer isn't under IO (dirty and - * writeback flags not set) and it's still in the tree (flag - * EXTENT_BUFFER_TREE_REF set), therefore being in the process - * of decrementing the extent buffer's reference count twice. - * So here we could race and increment the eb's reference count, - * clear its stale flag, mark it as dirty and drop our reference - * before the other task finishes executing free_extent_buffer, - * which would later result in an attempt to free an extent - * buffer that is dirty. - */ - if (test_bit(EXTENT_BUFFER_STALE, &eb->bflags)) { - spin_lock(&eb->refs_lock); - spin_unlock(&eb->refs_lock); - } - mark_extent_buffer_accessed(eb, NULL); - return eb; - } - rcu_read_unlock(); - - return NULL; -} - -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS -struct extent_buffer *alloc_test_extent_buffer(struct btrfs_fs_info *fs_info, - u64 start, u32 nodesize) -{ - struct extent_buffer *eb, *exists = NULL; - int ret; - - eb = find_extent_buffer(fs_info, start); - if (eb) - return eb; - eb = alloc_dummy_extent_buffer(fs_info, start, nodesize); - if (!eb) - return NULL; - eb->fs_info = fs_info; -again: - ret = radix_tree_preload(GFP_NOFS); - if (ret) - goto free_eb; - spin_lock(&fs_info->buffer_lock); - ret = radix_tree_insert(&fs_info->buffer_radix, - start >> PAGE_SHIFT, eb); - spin_unlock(&fs_info->buffer_lock); - radix_tree_preload_end(); - if (ret == -EEXIST) { - exists = find_extent_buffer(fs_info, start); - if (exists) - goto free_eb; - else - goto again; - } - check_buffer_tree_ref(eb); - set_bit(EXTENT_BUFFER_IN_TREE, &eb->bflags); - - /* - * We will free dummy extent buffer's if they come into - * free_extent_buffer with a ref count of 2, but if we are using this we - * want the buffers to stay in memory until we're done with them, so - * bump the ref count again. - */ - atomic_inc(&eb->refs); - return eb; -free_eb: - btrfs_release_extent_buffer(eb); - return exists; -} -#endif - -struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, - u64 start) -{ - unsigned long len = fs_info->tree_root->nodesize; - unsigned long num_pages = num_extent_pages(start, len); - unsigned long i; - unsigned long index = start >> PAGE_SHIFT; - struct extent_buffer *eb; - struct extent_buffer *exists = NULL; - struct page *p; - struct address_space *mapping = fs_info->btree_inode->i_mapping; - int uptodate = 1; - int ret; - - if (!IS_ALIGNED(start, fs_info->tree_root->sectorsize)) { - btrfs_err(fs_info, "bad tree block start %llu", start); - return ERR_PTR(-EINVAL); - } - - eb = find_extent_buffer(fs_info, start); - if (eb) - return eb; - - eb = __alloc_extent_buffer(fs_info, start, len); - if (!eb) - return ERR_PTR(-ENOMEM); - - for (i = 0; i < num_pages; i++, index++) { - p = find_or_create_page(mapping, index, GFP_NOFS|__GFP_NOFAIL); - if (!p) { - exists = ERR_PTR(-ENOMEM); - goto free_eb; - } - - spin_lock(&mapping->private_lock); - if (PagePrivate(p)) { - /* - * We could have already allocated an eb for this page - * and attached one so lets see if we can get a ref on - * the existing eb, and if we can we know it's good and - * we can just return that one, else we know we can just - * overwrite page->private. - */ - exists = (struct extent_buffer *)p->private; - if (atomic_inc_not_zero(&exists->refs)) { - spin_unlock(&mapping->private_lock); - unlock_page(p); - put_page(p); - mark_extent_buffer_accessed(exists, p); - goto free_eb; - } - exists = NULL; - - /* - * Do this so attach doesn't complain and we need to - * drop the ref the old guy had. - */ - ClearPagePrivate(p); - WARN_ON(PageDirty(p)); - put_page(p); - } - attach_extent_buffer_page(eb, p); - spin_unlock(&mapping->private_lock); - WARN_ON(PageDirty(p)); - eb->pages[i] = p; - if (!PageUptodate(p)) - uptodate = 0; - - /* - * see below about how we avoid a nasty race with release page - * and why we unlock later - */ - } - if (uptodate) - set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); -again: - ret = radix_tree_preload(GFP_NOFS); - if (ret) { - exists = ERR_PTR(ret); - goto free_eb; - } - - spin_lock(&fs_info->buffer_lock); - ret = radix_tree_insert(&fs_info->buffer_radix, - start >> PAGE_SHIFT, eb); - spin_unlock(&fs_info->buffer_lock); - radix_tree_preload_end(); - if (ret == -EEXIST) { - exists = find_extent_buffer(fs_info, start); - if (exists) - goto free_eb; - else - goto again; - } - /* add one reference for the tree */ - check_buffer_tree_ref(eb); - set_bit(EXTENT_BUFFER_IN_TREE, &eb->bflags); - - /* - * there is a race where release page may have - * tried to find this extent buffer in the radix - * but failed. It will tell the VM it is safe to - * reclaim the, and it will clear the page private bit. - * We must make sure to set the page private bit properly - * after the extent buffer is in the radix tree so - * it doesn't get lost - */ - SetPageChecked(eb->pages[0]); - for (i = 1; i < num_pages; i++) { - p = eb->pages[i]; - ClearPageChecked(p); - unlock_page(p); - } - unlock_page(eb->pages[0]); - return eb; - -free_eb: - WARN_ON(!atomic_dec_and_test(&eb->refs)); - for (i = 0; i < num_pages; i++) { - if (eb->pages[i]) - unlock_page(eb->pages[i]); - } - - btrfs_release_extent_buffer(eb); - return exists; -} - -static inline void btrfs_release_extent_buffer_rcu(struct rcu_head *head) -{ - struct extent_buffer *eb = - container_of(head, struct extent_buffer, rcu_head); - - __free_extent_buffer(eb); -} - -/* Expects to have eb->eb_lock already held */ -static int release_extent_buffer(struct extent_buffer *eb) -{ - WARN_ON(atomic_read(&eb->refs) == 0); - if (atomic_dec_and_test(&eb->refs)) { - if (test_and_clear_bit(EXTENT_BUFFER_IN_TREE, &eb->bflags)) { - struct btrfs_fs_info *fs_info = eb->fs_info; - - spin_unlock(&eb->refs_lock); - - spin_lock(&fs_info->buffer_lock); - radix_tree_delete(&fs_info->buffer_radix, - eb->start >> PAGE_SHIFT); - spin_unlock(&fs_info->buffer_lock); - } else { - spin_unlock(&eb->refs_lock); - } - - /* Should be safe to release our pages at this point */ - btrfs_release_extent_buffer_page(eb); -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS - if (unlikely(test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags))) { - __free_extent_buffer(eb); - return 1; - } -#endif - call_rcu(&eb->rcu_head, btrfs_release_extent_buffer_rcu); - return 1; - } - spin_unlock(&eb->refs_lock); - - return 0; -} - -void free_extent_buffer(struct extent_buffer *eb) -{ - int refs; - int old; - if (!eb) - return; - - while (1) { - refs = atomic_read(&eb->refs); - if (refs <= 3) - break; - old = atomic_cmpxchg(&eb->refs, refs, refs - 1); - if (old == refs) - return; - } - - spin_lock(&eb->refs_lock); - if (atomic_read(&eb->refs) == 2 && - test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags)) - atomic_dec(&eb->refs); - - if (atomic_read(&eb->refs) == 2 && - test_bit(EXTENT_BUFFER_STALE, &eb->bflags) && - !extent_buffer_under_io(eb) && - test_and_clear_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)) - atomic_dec(&eb->refs); - - /* - * I know this is terrible, but it's temporary until we stop tracking - * the uptodate bits and such for the extent buffers. - */ - release_extent_buffer(eb); -} - -void free_extent_buffer_stale(struct extent_buffer *eb) -{ - if (!eb) - return; - - spin_lock(&eb->refs_lock); - set_bit(EXTENT_BUFFER_STALE, &eb->bflags); - - if (atomic_read(&eb->refs) == 2 && !extent_buffer_under_io(eb) && - test_and_clear_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)) - atomic_dec(&eb->refs); - release_extent_buffer(eb); -} - -void clear_extent_buffer_dirty(struct extent_buffer *eb) -{ - unsigned long i; - unsigned long num_pages; - struct page *page; - - num_pages = num_extent_pages(eb->start, eb->len); - - for (i = 0; i < num_pages; i++) { - page = eb->pages[i]; - if (!PageDirty(page)) - continue; - - lock_page(page); - WARN_ON(!PagePrivate(page)); - - clear_page_dirty_for_io(page); - spin_lock_irq(&page->mapping->tree_lock); - if (!PageDirty(page)) { - radix_tree_tag_clear(&page->mapping->page_tree, - page_index(page), - PAGECACHE_TAG_DIRTY); - } - spin_unlock_irq(&page->mapping->tree_lock); - ClearPageError(page); - unlock_page(page); - } - WARN_ON(atomic_read(&eb->refs) == 0); -} - -int set_extent_buffer_dirty(struct extent_buffer *eb) -{ - unsigned long i; - unsigned long num_pages; - int was_dirty = 0; - - check_buffer_tree_ref(eb); - - was_dirty = test_and_set_bit(EXTENT_BUFFER_DIRTY, &eb->bflags); - - num_pages = num_extent_pages(eb->start, eb->len); - WARN_ON(atomic_read(&eb->refs) == 0); - WARN_ON(!test_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)); - - for (i = 0; i < num_pages; i++) - set_page_dirty(eb->pages[i]); - return was_dirty; -} - -void clear_extent_buffer_uptodate(struct extent_buffer *eb) -{ - unsigned long i; - struct page *page; - unsigned long num_pages; - - clear_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); - num_pages = num_extent_pages(eb->start, eb->len); - for (i = 0; i < num_pages; i++) { - page = eb->pages[i]; - if (page) - ClearPageUptodate(page); - } -} - -void set_extent_buffer_uptodate(struct extent_buffer *eb) -{ - unsigned long i; - struct page *page; - unsigned long num_pages; - - set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); - num_pages = num_extent_pages(eb->start, eb->len); - for (i = 0; i < num_pages; i++) { - page = eb->pages[i]; - SetPageUptodate(page); - } -} - -int extent_buffer_uptodate(struct extent_buffer *eb) -{ - return test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); -} - -int read_extent_buffer_pages(struct extent_io_tree *tree, - struct extent_buffer *eb, int wait, - get_extent_t *get_extent, int mirror_num) -{ - unsigned long i; - struct page *page; - int err; - int ret = 0; - int locked_pages = 0; - int all_uptodate = 1; - unsigned long num_pages; - unsigned long num_reads = 0; - struct bio *bio = NULL; - unsigned long bio_flags = 0; - - if (test_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags)) - return 0; - - num_pages = num_extent_pages(eb->start, eb->len); - for (i = 0; i < num_pages; i++) { - page = eb->pages[i]; - if (wait == WAIT_NONE) { - if (!trylock_page(page)) - goto unlock_exit; - } else { - lock_page(page); - } - locked_pages++; - } - /* - * We need to firstly lock all pages to make sure that - * the uptodate bit of our pages won't be affected by - * clear_extent_buffer_uptodate(). - */ - for (i = 0; i < num_pages; i++) { - page = eb->pages[i]; - if (!PageUptodate(page)) { - num_reads++; - all_uptodate = 0; - } - } - - if (all_uptodate) { - set_bit(EXTENT_BUFFER_UPTODATE, &eb->bflags); - goto unlock_exit; - } - - clear_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags); - eb->read_mirror = 0; - atomic_set(&eb->io_pages, num_reads); - for (i = 0; i < num_pages; i++) { - page = eb->pages[i]; - - if (!PageUptodate(page)) { - if (ret) { - atomic_dec(&eb->io_pages); - unlock_page(page); - continue; - } - - ClearPageError(page); - err = __extent_read_full_page(tree, page, - get_extent, &bio, - mirror_num, &bio_flags, - REQ_META); - if (err) { - ret = err; - /* - * We use &bio in above __extent_read_full_page, - * so we ensure that if it returns error, the - * current page fails to add itself to bio and - * it's been unlocked. - * - * We must dec io_pages by ourselves. - */ - atomic_dec(&eb->io_pages); - } - } else { - unlock_page(page); - } - } - - if (bio) { - err = submit_one_bio(bio, mirror_num, bio_flags); - if (err) - return err; - } - - if (ret || wait != WAIT_COMPLETE) - return ret; - - for (i = 0; i < num_pages; i++) { - page = eb->pages[i]; - wait_on_page_locked(page); - if (!PageUptodate(page)) - ret = -EIO; - } - - return ret; - -unlock_exit: - while (locked_pages > 0) { - locked_pages--; - page = eb->pages[locked_pages]; - unlock_page(page); - } - return ret; -} - -void read_extent_buffer(struct extent_buffer *eb, void *dstv, - unsigned long start, - unsigned long len) -{ - size_t cur; - size_t offset; - struct page *page; - char *kaddr; - char *dst = (char *)dstv; - size_t start_offset = eb->start & ((u64)PAGE_SIZE - 1); - unsigned long i = (start_offset + start) >> PAGE_SHIFT; - - WARN_ON(start > eb->len); - WARN_ON(start + len > eb->start + eb->len); - - offset = (start_offset + start) & (PAGE_SIZE - 1); - - while (len > 0) { - page = eb->pages[i]; - - cur = min(len, (PAGE_SIZE - offset)); - kaddr = page_address(page); - memcpy(dst, kaddr + offset, cur); - - dst += cur; - len -= cur; - offset = 0; - i++; - } -} - -int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dstv, - unsigned long start, - unsigned long len) -{ - size_t cur; - size_t offset; - struct page *page; - char *kaddr; - char __user *dst = (char __user *)dstv; - size_t start_offset = eb->start & ((u64)PAGE_SIZE - 1); - unsigned long i = (start_offset + start) >> PAGE_SHIFT; - int ret = 0; - - WARN_ON(start > eb->len); - WARN_ON(start + len > eb->start + eb->len); - - offset = (start_offset + start) & (PAGE_SIZE - 1); - - while (len > 0) { - page = eb->pages[i]; - - cur = min(len, (PAGE_SIZE - offset)); - kaddr = page_address(page); - if (copy_to_user(dst, kaddr + offset, cur)) { - ret = -EFAULT; - break; - } - - dst += cur; - len -= cur; - offset = 0; - i++; - } - - return ret; -} - -/* - * return 0 if the item is found within a page. - * return 1 if the item spans two pages. - * return -EINVAL otherwise. - */ -int map_private_extent_buffer(struct extent_buffer *eb, unsigned long start, - unsigned long min_len, char **map, - unsigned long *map_start, - unsigned long *map_len) -{ - size_t offset = start & (PAGE_SIZE - 1); - char *kaddr; - struct page *p; - size_t start_offset = eb->start & ((u64)PAGE_SIZE - 1); - unsigned long i = (start_offset + start) >> PAGE_SHIFT; - unsigned long end_i = (start_offset + start + min_len - 1) >> - PAGE_SHIFT; - - if (i != end_i) - return 1; - - if (i == 0) { - offset = start_offset; - *map_start = 0; - } else { - offset = 0; - *map_start = ((u64)i << PAGE_SHIFT) - start_offset; - } - - if (start + min_len > eb->len) { - WARN(1, KERN_ERR "btrfs bad mapping eb start %llu len %lu, wanted %lu %lu\n", - eb->start, eb->len, start, min_len); - return -EINVAL; - } - - p = eb->pages[i]; - kaddr = page_address(p); - *map = kaddr + offset; - *map_len = PAGE_SIZE - offset; - return 0; -} - -int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv, - unsigned long start, - unsigned long len) -{ - size_t cur; - size_t offset; - struct page *page; - char *kaddr; - char *ptr = (char *)ptrv; - size_t start_offset = eb->start & ((u64)PAGE_SIZE - 1); - unsigned long i = (start_offset + start) >> PAGE_SHIFT; - int ret = 0; - - WARN_ON(start > eb->len); - WARN_ON(start + len > eb->start + eb->len); - - offset = (start_offset + start) & (PAGE_SIZE - 1); - - while (len > 0) { - page = eb->pages[i]; - - cur = min(len, (PAGE_SIZE - offset)); - - kaddr = page_address(page); - ret = memcmp(ptr, kaddr + offset, cur); - if (ret) - break; - - ptr += cur; - len -= cur; - offset = 0; - i++; - } - return ret; -} - -void write_extent_buffer(struct extent_buffer *eb, const void *srcv, - unsigned long start, unsigned long len) -{ - size_t cur; - size_t offset; - struct page *page; - char *kaddr; - char *src = (char *)srcv; - size_t start_offset = eb->start & ((u64)PAGE_SIZE - 1); - unsigned long i = (start_offset + start) >> PAGE_SHIFT; - - WARN_ON(start > eb->len); - WARN_ON(start + len > eb->start + eb->len); - - offset = (start_offset + start) & (PAGE_SIZE - 1); - - while (len > 0) { - page = eb->pages[i]; - WARN_ON(!PageUptodate(page)); - - cur = min(len, PAGE_SIZE - offset); - kaddr = page_address(page); - memcpy(kaddr + offset, src, cur); - - src += cur; - len -= cur; - offset = 0; - i++; - } -} - -void memset_extent_buffer(struct extent_buffer *eb, char c, - unsigned long start, unsigned long len) -{ - size_t cur; - size_t offset; - struct page *page; - char *kaddr; - size_t start_offset = eb->start & ((u64)PAGE_SIZE - 1); - unsigned long i = (start_offset + start) >> PAGE_SHIFT; - - WARN_ON(start > eb->len); - WARN_ON(start + len > eb->start + eb->len); - - offset = (start_offset + start) & (PAGE_SIZE - 1); - - while (len > 0) { - page = eb->pages[i]; - WARN_ON(!PageUptodate(page)); - - cur = min(len, PAGE_SIZE - offset); - kaddr = page_address(page); - memset(kaddr + offset, c, cur); - - len -= cur; - offset = 0; - i++; - } -} - -void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src, - unsigned long dst_offset, unsigned long src_offset, - unsigned long len) -{ - u64 dst_len = dst->len; - size_t cur; - size_t offset; - struct page *page; - char *kaddr; - size_t start_offset = dst->start & ((u64)PAGE_SIZE - 1); - unsigned long i = (start_offset + dst_offset) >> PAGE_SHIFT; - - WARN_ON(src->len != dst_len); - - offset = (start_offset + dst_offset) & - (PAGE_SIZE - 1); - - while (len > 0) { - page = dst->pages[i]; - WARN_ON(!PageUptodate(page)); - - cur = min(len, (unsigned long)(PAGE_SIZE - offset)); - - kaddr = page_address(page); - read_extent_buffer(src, kaddr + offset, src_offset, cur); - - src_offset += cur; - len -= cur; - offset = 0; - i++; - } -} - -void le_bitmap_set(u8 *map, unsigned int start, int len) -{ - u8 *p = map + BIT_BYTE(start); - const unsigned int size = start + len; - int bits_to_set = BITS_PER_BYTE - (start % BITS_PER_BYTE); - u8 mask_to_set = BITMAP_FIRST_BYTE_MASK(start); - - while (len - bits_to_set >= 0) { - *p |= mask_to_set; - len -= bits_to_set; - bits_to_set = BITS_PER_BYTE; - mask_to_set = ~0; - p++; - } - if (len) { - mask_to_set &= BITMAP_LAST_BYTE_MASK(size); - *p |= mask_to_set; - } -} - -void le_bitmap_clear(u8 *map, unsigned int start, int len) -{ - u8 *p = map + BIT_BYTE(start); - const unsigned int size = start + len; - int bits_to_clear = BITS_PER_BYTE - (start % BITS_PER_BYTE); - u8 mask_to_clear = BITMAP_FIRST_BYTE_MASK(start); - - while (len - bits_to_clear >= 0) { - *p &= ~mask_to_clear; - len -= bits_to_clear; - bits_to_clear = BITS_PER_BYTE; - mask_to_clear = ~0; - p++; - } - if (len) { - mask_to_clear &= BITMAP_LAST_BYTE_MASK(size); - *p &= ~mask_to_clear; - } -} - -/* - * eb_bitmap_offset() - calculate the page and offset of the byte containing the - * given bit number - * @eb: the extent buffer - * @start: offset of the bitmap item in the extent buffer - * @nr: bit number - * @page_index: return index of the page in the extent buffer that contains the - * given bit number - * @page_offset: return offset into the page given by page_index - * - * This helper hides the ugliness of finding the byte in an extent buffer which - * contains a given bit. - */ -static inline void eb_bitmap_offset(struct extent_buffer *eb, - unsigned long start, unsigned long nr, - unsigned long *page_index, - size_t *page_offset) -{ - size_t start_offset = eb->start & ((u64)PAGE_SIZE - 1); - size_t byte_offset = BIT_BYTE(nr); - size_t offset; - - /* - * The byte we want is the offset of the extent buffer + the offset of - * the bitmap item in the extent buffer + the offset of the byte in the - * bitmap item. - */ - offset = start_offset + start + byte_offset; - - *page_index = offset >> PAGE_SHIFT; - *page_offset = offset & (PAGE_SIZE - 1); -} - -/** - * extent_buffer_test_bit - determine whether a bit in a bitmap item is set - * @eb: the extent buffer - * @start: offset of the bitmap item in the extent buffer - * @nr: bit number to test - */ -int extent_buffer_test_bit(struct extent_buffer *eb, unsigned long start, - unsigned long nr) -{ - u8 *kaddr; - struct page *page; - unsigned long i; - size_t offset; - - eb_bitmap_offset(eb, start, nr, &i, &offset); - page = eb->pages[i]; - WARN_ON(!PageUptodate(page)); - kaddr = page_address(page); - return 1U & (kaddr[offset] >> (nr & (BITS_PER_BYTE - 1))); -} - -/** - * extent_buffer_bitmap_set - set an area of a bitmap - * @eb: the extent buffer - * @start: offset of the bitmap item in the extent buffer - * @pos: bit number of the first bit - * @len: number of bits to set - */ -void extent_buffer_bitmap_set(struct extent_buffer *eb, unsigned long start, - unsigned long pos, unsigned long len) -{ - u8 *kaddr; - struct page *page; - unsigned long i; - size_t offset; - const unsigned int size = pos + len; - int bits_to_set = BITS_PER_BYTE - (pos % BITS_PER_BYTE); - u8 mask_to_set = BITMAP_FIRST_BYTE_MASK(pos); - - eb_bitmap_offset(eb, start, pos, &i, &offset); - page = eb->pages[i]; - WARN_ON(!PageUptodate(page)); - kaddr = page_address(page); - - while (len >= bits_to_set) { - kaddr[offset] |= mask_to_set; - len -= bits_to_set; - bits_to_set = BITS_PER_BYTE; - mask_to_set = ~0; - if (++offset >= PAGE_SIZE && len > 0) { - offset = 0; - page = eb->pages[++i]; - WARN_ON(!PageUptodate(page)); - kaddr = page_address(page); - } - } - if (len) { - mask_to_set &= BITMAP_LAST_BYTE_MASK(size); - kaddr[offset] |= mask_to_set; - } -} - - -/** - * extent_buffer_bitmap_clear - clear an area of a bitmap - * @eb: the extent buffer - * @start: offset of the bitmap item in the extent buffer - * @pos: bit number of the first bit - * @len: number of bits to clear - */ -void extent_buffer_bitmap_clear(struct extent_buffer *eb, unsigned long start, - unsigned long pos, unsigned long len) -{ - u8 *kaddr; - struct page *page; - unsigned long i; - size_t offset; - const unsigned int size = pos + len; - int bits_to_clear = BITS_PER_BYTE - (pos % BITS_PER_BYTE); - u8 mask_to_clear = BITMAP_FIRST_BYTE_MASK(pos); - - eb_bitmap_offset(eb, start, pos, &i, &offset); - page = eb->pages[i]; - WARN_ON(!PageUptodate(page)); - kaddr = page_address(page); - - while (len >= bits_to_clear) { - kaddr[offset] &= ~mask_to_clear; - len -= bits_to_clear; - bits_to_clear = BITS_PER_BYTE; - mask_to_clear = ~0; - if (++offset >= PAGE_SIZE && len > 0) { - offset = 0; - page = eb->pages[++i]; - WARN_ON(!PageUptodate(page)); - kaddr = page_address(page); - } - } - if (len) { - mask_to_clear &= BITMAP_LAST_BYTE_MASK(size); - kaddr[offset] &= ~mask_to_clear; - } -} - -static inline bool areas_overlap(unsigned long src, unsigned long dst, unsigned long len) -{ - unsigned long distance = (src > dst) ? src - dst : dst - src; - return distance < len; -} - -static void copy_pages(struct page *dst_page, struct page *src_page, - unsigned long dst_off, unsigned long src_off, - unsigned long len) -{ - char *dst_kaddr = page_address(dst_page); - char *src_kaddr; - int must_memmove = 0; - - if (dst_page != src_page) { - src_kaddr = page_address(src_page); - } else { - src_kaddr = dst_kaddr; - if (areas_overlap(src_off, dst_off, len)) - must_memmove = 1; - } - - if (must_memmove) - memmove(dst_kaddr + dst_off, src_kaddr + src_off, len); - else - memcpy(dst_kaddr + dst_off, src_kaddr + src_off, len); -} - -void memcpy_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset, - unsigned long src_offset, unsigned long len) -{ - size_t cur; - size_t dst_off_in_page; - size_t src_off_in_page; - size_t start_offset = dst->start & ((u64)PAGE_SIZE - 1); - unsigned long dst_i; - unsigned long src_i; - - if (src_offset + len > dst->len) { - btrfs_err(dst->fs_info, - "memmove bogus src_offset %lu move len %lu dst len %lu", - src_offset, len, dst->len); - BUG_ON(1); - } - if (dst_offset + len > dst->len) { - btrfs_err(dst->fs_info, - "memmove bogus dst_offset %lu move len %lu dst len %lu", - dst_offset, len, dst->len); - BUG_ON(1); - } - - while (len > 0) { - dst_off_in_page = (start_offset + dst_offset) & - (PAGE_SIZE - 1); - src_off_in_page = (start_offset + src_offset) & - (PAGE_SIZE - 1); - - dst_i = (start_offset + dst_offset) >> PAGE_SHIFT; - src_i = (start_offset + src_offset) >> PAGE_SHIFT; - - cur = min(len, (unsigned long)(PAGE_SIZE - - src_off_in_page)); - cur = min_t(unsigned long, cur, - (unsigned long)(PAGE_SIZE - dst_off_in_page)); - - copy_pages(dst->pages[dst_i], dst->pages[src_i], - dst_off_in_page, src_off_in_page, cur); - - src_offset += cur; - dst_offset += cur; - len -= cur; - } -} - -void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset, - unsigned long src_offset, unsigned long len) -{ - size_t cur; - size_t dst_off_in_page; - size_t src_off_in_page; - unsigned long dst_end = dst_offset + len - 1; - unsigned long src_end = src_offset + len - 1; - size_t start_offset = dst->start & ((u64)PAGE_SIZE - 1); - unsigned long dst_i; - unsigned long src_i; - - if (src_offset + len > dst->len) { - btrfs_err(dst->fs_info, - "memmove bogus src_offset %lu move len %lu len %lu", - src_offset, len, dst->len); - BUG_ON(1); - } - if (dst_offset + len > dst->len) { - btrfs_err(dst->fs_info, - "memmove bogus dst_offset %lu move len %lu len %lu", - dst_offset, len, dst->len); - BUG_ON(1); - } - if (dst_offset < src_offset) { - memcpy_extent_buffer(dst, dst_offset, src_offset, len); - return; - } - while (len > 0) { - dst_i = (start_offset + dst_end) >> PAGE_SHIFT; - src_i = (start_offset + src_end) >> PAGE_SHIFT; - - dst_off_in_page = (start_offset + dst_end) & - (PAGE_SIZE - 1); - src_off_in_page = (start_offset + src_end) & - (PAGE_SIZE - 1); - - cur = min_t(unsigned long, len, src_off_in_page + 1); - cur = min(cur, dst_off_in_page + 1); - copy_pages(dst->pages[dst_i], dst->pages[src_i], - dst_off_in_page - cur + 1, - src_off_in_page - cur + 1, cur); - - dst_end -= cur; - src_end -= cur; - len -= cur; - } -} - -int try_release_extent_buffer(struct page *page) -{ - struct extent_buffer *eb; - - /* - * We need to make sure nobody is attaching this page to an eb right - * now. - */ - spin_lock(&page->mapping->private_lock); - if (!PagePrivate(page)) { - spin_unlock(&page->mapping->private_lock); - return 1; - } - - eb = (struct extent_buffer *)page->private; - BUG_ON(!eb); - - /* - * This is a little awful but should be ok, we need to make sure that - * the eb doesn't disappear out from under us while we're looking at - * this page. - */ - spin_lock(&eb->refs_lock); - if (atomic_read(&eb->refs) != 1 || extent_buffer_under_io(eb)) { - spin_unlock(&eb->refs_lock); - spin_unlock(&page->mapping->private_lock); - return 0; - } - spin_unlock(&page->mapping->private_lock); - - /* - * If tree ref isn't set then we know the ref on this eb is a real ref, - * so just return, this page will likely be freed soon anyway. - */ - if (!test_and_clear_bit(EXTENT_BUFFER_TREE_REF, &eb->bflags)) { - spin_unlock(&eb->refs_lock); - return 0; - } - - return release_extent_buffer(eb); -} diff --git a/src/linux/fs/btrfs/extent_io.h b/src/linux/fs/btrfs/extent_io.h deleted file mode 100644 index ab31d14..0000000 --- a/src/linux/fs/btrfs/extent_io.h +++ /dev/null @@ -1,495 +0,0 @@ -#ifndef __EXTENTIO__ -#define __EXTENTIO__ - -#include -#include "ulist.h" - -/* bits for the extent state */ -#define EXTENT_DIRTY (1U << 0) -#define EXTENT_WRITEBACK (1U << 1) -#define EXTENT_UPTODATE (1U << 2) -#define EXTENT_LOCKED (1U << 3) -#define EXTENT_NEW (1U << 4) -#define EXTENT_DELALLOC (1U << 5) -#define EXTENT_DEFRAG (1U << 6) -#define EXTENT_BOUNDARY (1U << 9) -#define EXTENT_NODATASUM (1U << 10) -#define EXTENT_DO_ACCOUNTING (1U << 11) -#define EXTENT_FIRST_DELALLOC (1U << 12) -#define EXTENT_NEED_WAIT (1U << 13) -#define EXTENT_DAMAGED (1U << 14) -#define EXTENT_NORESERVE (1U << 15) -#define EXTENT_QGROUP_RESERVED (1U << 16) -#define EXTENT_CLEAR_DATA_RESV (1U << 17) -#define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK) -#define EXTENT_CTLBITS (EXTENT_DO_ACCOUNTING | EXTENT_FIRST_DELALLOC) - -/* - * flags for bio submission. The high bits indicate the compression - * type for this bio - */ -#define EXTENT_BIO_COMPRESSED 1 -#define EXTENT_BIO_TREE_LOG 2 -#define EXTENT_BIO_FLAG_SHIFT 16 - -/* these are bit numbers for test/set bit */ -#define EXTENT_BUFFER_UPTODATE 0 -#define EXTENT_BUFFER_DIRTY 2 -#define EXTENT_BUFFER_CORRUPT 3 -#define EXTENT_BUFFER_READAHEAD 4 /* this got triggered by readahead */ -#define EXTENT_BUFFER_TREE_REF 5 -#define EXTENT_BUFFER_STALE 6 -#define EXTENT_BUFFER_WRITEBACK 7 -#define EXTENT_BUFFER_READ_ERR 8 /* read IO error */ -#define EXTENT_BUFFER_DUMMY 9 -#define EXTENT_BUFFER_IN_TREE 10 -#define EXTENT_BUFFER_WRITE_ERR 11 /* write IO error */ - -/* these are flags for extent_clear_unlock_delalloc */ -#define PAGE_UNLOCK (1 << 0) -#define PAGE_CLEAR_DIRTY (1 << 1) -#define PAGE_SET_WRITEBACK (1 << 2) -#define PAGE_END_WRITEBACK (1 << 3) -#define PAGE_SET_PRIVATE2 (1 << 4) -#define PAGE_SET_ERROR (1 << 5) - -/* - * page->private values. Every page that is controlled by the extent - * map has page->private set to one. - */ -#define EXTENT_PAGE_PRIVATE 1 - -/* - * The extent buffer bitmap operations are done with byte granularity instead of - * word granularity for two reasons: - * 1. The bitmaps must be little-endian on disk. - * 2. Bitmap items are not guaranteed to be aligned to a word and therefore a - * single word in a bitmap may straddle two pages in the extent buffer. - */ -#define BIT_BYTE(nr) ((nr) / BITS_PER_BYTE) -#define BYTE_MASK ((1 << BITS_PER_BYTE) - 1) -#define BITMAP_FIRST_BYTE_MASK(start) \ - ((BYTE_MASK << ((start) & (BITS_PER_BYTE - 1))) & BYTE_MASK) -#define BITMAP_LAST_BYTE_MASK(nbits) \ - (BYTE_MASK >> (-(nbits) & (BITS_PER_BYTE - 1))) - -static inline int le_test_bit(int nr, const u8 *addr) -{ - return 1U & (addr[BIT_BYTE(nr)] >> (nr & (BITS_PER_BYTE-1))); -} - -extern void le_bitmap_set(u8 *map, unsigned int start, int len); -extern void le_bitmap_clear(u8 *map, unsigned int start, int len); - -struct extent_state; -struct btrfs_root; -struct btrfs_io_bio; -struct io_failure_record; - -typedef int (extent_submit_bio_hook_t)(struct inode *inode, struct bio *bio, - int mirror_num, unsigned long bio_flags, - u64 bio_offset); -struct extent_io_ops { - int (*fill_delalloc)(struct inode *inode, struct page *locked_page, - u64 start, u64 end, int *page_started, - unsigned long *nr_written); - int (*writepage_start_hook)(struct page *page, u64 start, u64 end); - extent_submit_bio_hook_t *submit_bio_hook; - int (*merge_bio_hook)(struct page *page, unsigned long offset, - size_t size, struct bio *bio, - unsigned long bio_flags); - int (*readpage_io_failed_hook)(struct page *page, int failed_mirror); - int (*readpage_end_io_hook)(struct btrfs_io_bio *io_bio, u64 phy_offset, - struct page *page, u64 start, u64 end, - int mirror); - int (*writepage_end_io_hook)(struct page *page, u64 start, u64 end, - struct extent_state *state, int uptodate); - void (*set_bit_hook)(struct inode *inode, struct extent_state *state, - unsigned *bits); - void (*clear_bit_hook)(struct inode *inode, struct extent_state *state, - unsigned *bits); - void (*merge_extent_hook)(struct inode *inode, - struct extent_state *new, - struct extent_state *other); - void (*split_extent_hook)(struct inode *inode, - struct extent_state *orig, u64 split); -}; - -struct extent_io_tree { - struct rb_root state; - struct address_space *mapping; - u64 dirty_bytes; - int track_uptodate; - spinlock_t lock; - const struct extent_io_ops *ops; -}; - -struct extent_state { - u64 start; - u64 end; /* inclusive */ - struct rb_node rb_node; - - /* ADD NEW ELEMENTS AFTER THIS */ - wait_queue_head_t wq; - atomic_t refs; - unsigned state; - - struct io_failure_record *failrec; - -#ifdef CONFIG_BTRFS_DEBUG - struct list_head leak_list; -#endif -}; - -#define INLINE_EXTENT_BUFFER_PAGES 16 -#define MAX_INLINE_EXTENT_BUFFER_SIZE (INLINE_EXTENT_BUFFER_PAGES * PAGE_SIZE) -struct extent_buffer { - u64 start; - unsigned long len; - unsigned long bflags; - struct btrfs_fs_info *fs_info; - spinlock_t refs_lock; - atomic_t refs; - atomic_t io_pages; - int read_mirror; - struct rcu_head rcu_head; - pid_t lock_owner; - - /* count of read lock holders on the extent buffer */ - atomic_t write_locks; - atomic_t read_locks; - atomic_t blocking_writers; - atomic_t blocking_readers; - atomic_t spinning_readers; - atomic_t spinning_writers; - short lock_nested; - /* >= 0 if eb belongs to a log tree, -1 otherwise */ - short log_index; - - /* protects write locks */ - rwlock_t lock; - - /* readers use lock_wq while they wait for the write - * lock holders to unlock - */ - wait_queue_head_t write_lock_wq; - - /* writers use read_lock_wq while they wait for readers - * to unlock - */ - wait_queue_head_t read_lock_wq; - struct page *pages[INLINE_EXTENT_BUFFER_PAGES]; -#ifdef CONFIG_BTRFS_DEBUG - struct list_head leak_list; -#endif -}; - -/* - * Structure to record how many bytes and which ranges are set/cleared - */ -struct extent_changeset { - /* How many bytes are set/cleared in this operation */ - u64 bytes_changed; - - /* Changed ranges */ - struct ulist *range_changed; -}; - -static inline void extent_set_compress_type(unsigned long *bio_flags, - int compress_type) -{ - *bio_flags |= compress_type << EXTENT_BIO_FLAG_SHIFT; -} - -static inline int extent_compress_type(unsigned long bio_flags) -{ - return bio_flags >> EXTENT_BIO_FLAG_SHIFT; -} - -struct extent_map_tree; - -typedef struct extent_map *(get_extent_t)(struct inode *inode, - struct page *page, - size_t pg_offset, - u64 start, u64 len, - int create); - -void extent_io_tree_init(struct extent_io_tree *tree, - struct address_space *mapping); -int try_release_extent_mapping(struct extent_map_tree *map, - struct extent_io_tree *tree, struct page *page, - gfp_t mask); -int try_release_extent_buffer(struct page *page); -int lock_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, - struct extent_state **cached); - -static inline int lock_extent(struct extent_io_tree *tree, u64 start, u64 end) -{ - return lock_extent_bits(tree, start, end, NULL); -} - -int try_lock_extent(struct extent_io_tree *tree, u64 start, u64 end); -int extent_read_full_page(struct extent_io_tree *tree, struct page *page, - get_extent_t *get_extent, int mirror_num); -int __init extent_io_init(void); -void extent_io_exit(void); - -u64 count_range_bits(struct extent_io_tree *tree, - u64 *start, u64 search_end, - u64 max_bytes, unsigned bits, int contig); - -void free_extent_state(struct extent_state *state); -int test_range_bit(struct extent_io_tree *tree, u64 start, u64 end, - unsigned bits, int filled, - struct extent_state *cached_state); -int clear_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, - unsigned bits, struct extent_changeset *changeset); -int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, - unsigned bits, int wake, int delete, - struct extent_state **cached, gfp_t mask); - -static inline int unlock_extent(struct extent_io_tree *tree, u64 start, u64 end) -{ - return clear_extent_bit(tree, start, end, EXTENT_LOCKED, 1, 0, NULL, - GFP_NOFS); -} - -static inline int unlock_extent_cached(struct extent_io_tree *tree, u64 start, - u64 end, struct extent_state **cached, gfp_t mask) -{ - return clear_extent_bit(tree, start, end, EXTENT_LOCKED, 1, 0, cached, - mask); -} - -static inline int clear_extent_bits(struct extent_io_tree *tree, u64 start, - u64 end, unsigned bits) -{ - int wake = 0; - - if (bits & EXTENT_LOCKED) - wake = 1; - - return clear_extent_bit(tree, start, end, bits, wake, 0, NULL, - GFP_NOFS); -} - -int set_record_extent_bits(struct extent_io_tree *tree, u64 start, u64 end, - unsigned bits, struct extent_changeset *changeset); -int set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, - unsigned bits, u64 *failed_start, - struct extent_state **cached_state, gfp_t mask); - -static inline int set_extent_bits(struct extent_io_tree *tree, u64 start, - u64 end, unsigned bits) -{ - return set_extent_bit(tree, start, end, bits, NULL, NULL, GFP_NOFS); -} - -static inline int clear_extent_uptodate(struct extent_io_tree *tree, u64 start, - u64 end, struct extent_state **cached_state, gfp_t mask) -{ - return clear_extent_bit(tree, start, end, EXTENT_UPTODATE, 0, 0, - cached_state, mask); -} - -static inline int set_extent_dirty(struct extent_io_tree *tree, u64 start, - u64 end, gfp_t mask) -{ - return set_extent_bit(tree, start, end, EXTENT_DIRTY, NULL, - NULL, mask); -} - -static inline int clear_extent_dirty(struct extent_io_tree *tree, u64 start, - u64 end) -{ - return clear_extent_bit(tree, start, end, - EXTENT_DIRTY | EXTENT_DELALLOC | - EXTENT_DO_ACCOUNTING, 0, 0, NULL, GFP_NOFS); -} - -int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end, - unsigned bits, unsigned clear_bits, - struct extent_state **cached_state); - -static inline int set_extent_delalloc(struct extent_io_tree *tree, u64 start, - u64 end, struct extent_state **cached_state) -{ - return set_extent_bit(tree, start, end, - EXTENT_DELALLOC | EXTENT_UPTODATE, - NULL, cached_state, GFP_NOFS); -} - -static inline int set_extent_defrag(struct extent_io_tree *tree, u64 start, - u64 end, struct extent_state **cached_state) -{ - return set_extent_bit(tree, start, end, - EXTENT_DELALLOC | EXTENT_UPTODATE | EXTENT_DEFRAG, - NULL, cached_state, GFP_NOFS); -} - -static inline int set_extent_new(struct extent_io_tree *tree, u64 start, - u64 end) -{ - return set_extent_bit(tree, start, end, EXTENT_NEW, NULL, NULL, - GFP_NOFS); -} - -static inline int set_extent_uptodate(struct extent_io_tree *tree, u64 start, - u64 end, struct extent_state **cached_state, gfp_t mask) -{ - return set_extent_bit(tree, start, end, EXTENT_UPTODATE, NULL, - cached_state, mask); -} - -int find_first_extent_bit(struct extent_io_tree *tree, u64 start, - u64 *start_ret, u64 *end_ret, unsigned bits, - struct extent_state **cached_state); -int extent_invalidatepage(struct extent_io_tree *tree, - struct page *page, unsigned long offset); -int extent_write_full_page(struct extent_io_tree *tree, struct page *page, - get_extent_t *get_extent, - struct writeback_control *wbc); -int extent_write_locked_range(struct extent_io_tree *tree, struct inode *inode, - u64 start, u64 end, get_extent_t *get_extent, - int mode); -int extent_writepages(struct extent_io_tree *tree, - struct address_space *mapping, - get_extent_t *get_extent, - struct writeback_control *wbc); -int btree_write_cache_pages(struct address_space *mapping, - struct writeback_control *wbc); -int extent_readpages(struct extent_io_tree *tree, - struct address_space *mapping, - struct list_head *pages, unsigned nr_pages, - get_extent_t get_extent); -int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, - __u64 start, __u64 len, get_extent_t *get_extent); -void set_page_extent_mapped(struct page *page); - -struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, - u64 start); -struct extent_buffer *__alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info, - u64 start, unsigned long len); -struct extent_buffer *alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info, - u64 start, u32 nodesize); -struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src); -struct extent_buffer *find_extent_buffer(struct btrfs_fs_info *fs_info, - u64 start); -void free_extent_buffer(struct extent_buffer *eb); -void free_extent_buffer_stale(struct extent_buffer *eb); -#define WAIT_NONE 0 -#define WAIT_COMPLETE 1 -#define WAIT_PAGE_LOCK 2 -int read_extent_buffer_pages(struct extent_io_tree *tree, - struct extent_buffer *eb, int wait, - get_extent_t *get_extent, int mirror_num); -void wait_on_extent_buffer_writeback(struct extent_buffer *eb); - -static inline unsigned long num_extent_pages(u64 start, u64 len) -{ - return ((start + len + PAGE_SIZE - 1) >> PAGE_SHIFT) - - (start >> PAGE_SHIFT); -} - -static inline void extent_buffer_get(struct extent_buffer *eb) -{ - atomic_inc(&eb->refs); -} - -int memcmp_extent_buffer(struct extent_buffer *eb, const void *ptrv, - unsigned long start, - unsigned long len); -void read_extent_buffer(struct extent_buffer *eb, void *dst, - unsigned long start, - unsigned long len); -int read_extent_buffer_to_user(struct extent_buffer *eb, void __user *dst, - unsigned long start, - unsigned long len); -void write_extent_buffer(struct extent_buffer *eb, const void *src, - unsigned long start, unsigned long len); -void copy_extent_buffer(struct extent_buffer *dst, struct extent_buffer *src, - unsigned long dst_offset, unsigned long src_offset, - unsigned long len); -void memcpy_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset, - unsigned long src_offset, unsigned long len); -void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset, - unsigned long src_offset, unsigned long len); -void memset_extent_buffer(struct extent_buffer *eb, char c, - unsigned long start, unsigned long len); -int extent_buffer_test_bit(struct extent_buffer *eb, unsigned long start, - unsigned long pos); -void extent_buffer_bitmap_set(struct extent_buffer *eb, unsigned long start, - unsigned long pos, unsigned long len); -void extent_buffer_bitmap_clear(struct extent_buffer *eb, unsigned long start, - unsigned long pos, unsigned long len); -void clear_extent_buffer_dirty(struct extent_buffer *eb); -int set_extent_buffer_dirty(struct extent_buffer *eb); -void set_extent_buffer_uptodate(struct extent_buffer *eb); -void clear_extent_buffer_uptodate(struct extent_buffer *eb); -int extent_buffer_uptodate(struct extent_buffer *eb); -int extent_buffer_under_io(struct extent_buffer *eb); -int map_private_extent_buffer(struct extent_buffer *eb, unsigned long offset, - unsigned long min_len, char **map, - unsigned long *map_start, - unsigned long *map_len); -void extent_range_clear_dirty_for_io(struct inode *inode, u64 start, u64 end); -void extent_range_redirty_for_io(struct inode *inode, u64 start, u64 end); -void extent_clear_unlock_delalloc(struct inode *inode, u64 start, u64 end, - u64 delalloc_end, struct page *locked_page, - unsigned bits_to_clear, - unsigned long page_ops); -struct bio * -btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs, - gfp_t gfp_flags); -struct bio *btrfs_io_bio_alloc(gfp_t gfp_mask, unsigned int nr_iovecs); -struct bio *btrfs_bio_clone(struct bio *bio, gfp_t gfp_mask); - -struct btrfs_fs_info; - -int repair_io_failure(struct inode *inode, u64 start, u64 length, u64 logical, - struct page *page, unsigned int pg_offset, - int mirror_num); -int clean_io_failure(struct inode *inode, u64 start, struct page *page, - unsigned int pg_offset); -void end_extent_writepage(struct page *page, int err, u64 start, u64 end); -int repair_eb_io_failure(struct btrfs_root *root, struct extent_buffer *eb, - int mirror_num); - -/* - * When IO fails, either with EIO or csum verification fails, we - * try other mirrors that might have a good copy of the data. This - * io_failure_record is used to record state as we go through all the - * mirrors. If another mirror has good data, the page is set up to date - * and things continue. If a good mirror can't be found, the original - * bio end_io callback is called to indicate things have failed. - */ -struct io_failure_record { - struct page *page; - u64 start; - u64 len; - u64 logical; - unsigned long bio_flags; - int this_mirror; - int failed_mirror; - int in_validation; -}; - -void btrfs_free_io_failure_record(struct inode *inode, u64 start, u64 end); -int btrfs_get_io_failure_record(struct inode *inode, u64 start, u64 end, - struct io_failure_record **failrec_ret); -int btrfs_check_repairable(struct inode *inode, struct bio *failed_bio, - struct io_failure_record *failrec, int fail_mirror); -struct bio *btrfs_create_repair_bio(struct inode *inode, struct bio *failed_bio, - struct io_failure_record *failrec, - struct page *page, int pg_offset, int icsum, - bio_end_io_t *endio_func, void *data); -int free_io_failure(struct inode *inode, struct io_failure_record *rec); -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS -noinline u64 find_lock_delalloc_range(struct inode *inode, - struct extent_io_tree *tree, - struct page *locked_page, u64 *start, - u64 *end, u64 max_bytes); -#endif -struct extent_buffer *alloc_test_extent_buffer(struct btrfs_fs_info *fs_info, - u64 start, u32 nodesize); -#endif diff --git a/src/linux/fs/btrfs/extent_map.c b/src/linux/fs/btrfs/extent_map.c deleted file mode 100644 index 26f9ac7..0000000 --- a/src/linux/fs/btrfs/extent_map.c +++ /dev/null @@ -1,455 +0,0 @@ -#include -#include -#include -#include -#include "ctree.h" -#include "extent_map.h" -#include "compression.h" - - -static struct kmem_cache *extent_map_cache; - -int __init extent_map_init(void) -{ - extent_map_cache = kmem_cache_create("btrfs_extent_map", - sizeof(struct extent_map), 0, - SLAB_MEM_SPREAD, NULL); - if (!extent_map_cache) - return -ENOMEM; - return 0; -} - -void extent_map_exit(void) -{ - kmem_cache_destroy(extent_map_cache); -} - -/** - * extent_map_tree_init - initialize extent map tree - * @tree: tree to initialize - * - * Initialize the extent tree @tree. Should be called for each new inode - * or other user of the extent_map interface. - */ -void extent_map_tree_init(struct extent_map_tree *tree) -{ - tree->map = RB_ROOT; - INIT_LIST_HEAD(&tree->modified_extents); - rwlock_init(&tree->lock); -} - -/** - * alloc_extent_map - allocate new extent map structure - * - * Allocate a new extent_map structure. The new structure is - * returned with a reference count of one and needs to be - * freed using free_extent_map() - */ -struct extent_map *alloc_extent_map(void) -{ - struct extent_map *em; - em = kmem_cache_zalloc(extent_map_cache, GFP_NOFS); - if (!em) - return NULL; - RB_CLEAR_NODE(&em->rb_node); - em->flags = 0; - em->compress_type = BTRFS_COMPRESS_NONE; - em->generation = 0; - atomic_set(&em->refs, 1); - INIT_LIST_HEAD(&em->list); - return em; -} - -/** - * free_extent_map - drop reference count of an extent_map - * @em: extent map being released - * - * Drops the reference out on @em by one and free the structure - * if the reference count hits zero. - */ -void free_extent_map(struct extent_map *em) -{ - if (!em) - return; - WARN_ON(atomic_read(&em->refs) == 0); - if (atomic_dec_and_test(&em->refs)) { - WARN_ON(extent_map_in_tree(em)); - WARN_ON(!list_empty(&em->list)); - if (test_bit(EXTENT_FLAG_FS_MAPPING, &em->flags)) - kfree(em->map_lookup); - kmem_cache_free(extent_map_cache, em); - } -} - -/* simple helper to do math around the end of an extent, handling wrap */ -static u64 range_end(u64 start, u64 len) -{ - if (start + len < start) - return (u64)-1; - return start + len; -} - -static int tree_insert(struct rb_root *root, struct extent_map *em) -{ - struct rb_node **p = &root->rb_node; - struct rb_node *parent = NULL; - struct extent_map *entry = NULL; - struct rb_node *orig_parent = NULL; - u64 end = range_end(em->start, em->len); - - while (*p) { - parent = *p; - entry = rb_entry(parent, struct extent_map, rb_node); - - if (em->start < entry->start) - p = &(*p)->rb_left; - else if (em->start >= extent_map_end(entry)) - p = &(*p)->rb_right; - else - return -EEXIST; - } - - orig_parent = parent; - while (parent && em->start >= extent_map_end(entry)) { - parent = rb_next(parent); - entry = rb_entry(parent, struct extent_map, rb_node); - } - if (parent) - if (end > entry->start && em->start < extent_map_end(entry)) - return -EEXIST; - - parent = orig_parent; - entry = rb_entry(parent, struct extent_map, rb_node); - while (parent && em->start < entry->start) { - parent = rb_prev(parent); - entry = rb_entry(parent, struct extent_map, rb_node); - } - if (parent) - if (end > entry->start && em->start < extent_map_end(entry)) - return -EEXIST; - - rb_link_node(&em->rb_node, orig_parent, p); - rb_insert_color(&em->rb_node, root); - return 0; -} - -/* - * search through the tree for an extent_map with a given offset. If - * it can't be found, try to find some neighboring extents - */ -static struct rb_node *__tree_search(struct rb_root *root, u64 offset, - struct rb_node **prev_ret, - struct rb_node **next_ret) -{ - struct rb_node *n = root->rb_node; - struct rb_node *prev = NULL; - struct rb_node *orig_prev = NULL; - struct extent_map *entry; - struct extent_map *prev_entry = NULL; - - while (n) { - entry = rb_entry(n, struct extent_map, rb_node); - prev = n; - prev_entry = entry; - - if (offset < entry->start) - n = n->rb_left; - else if (offset >= extent_map_end(entry)) - n = n->rb_right; - else - return n; - } - - if (prev_ret) { - orig_prev = prev; - while (prev && offset >= extent_map_end(prev_entry)) { - prev = rb_next(prev); - prev_entry = rb_entry(prev, struct extent_map, rb_node); - } - *prev_ret = prev; - prev = orig_prev; - } - - if (next_ret) { - prev_entry = rb_entry(prev, struct extent_map, rb_node); - while (prev && offset < prev_entry->start) { - prev = rb_prev(prev); - prev_entry = rb_entry(prev, struct extent_map, rb_node); - } - *next_ret = prev; - } - return NULL; -} - -/* check to see if two extent_map structs are adjacent and safe to merge */ -static int mergable_maps(struct extent_map *prev, struct extent_map *next) -{ - if (test_bit(EXTENT_FLAG_PINNED, &prev->flags)) - return 0; - - /* - * don't merge compressed extents, we need to know their - * actual size - */ - if (test_bit(EXTENT_FLAG_COMPRESSED, &prev->flags)) - return 0; - - if (test_bit(EXTENT_FLAG_LOGGING, &prev->flags) || - test_bit(EXTENT_FLAG_LOGGING, &next->flags)) - return 0; - - /* - * We don't want to merge stuff that hasn't been written to the log yet - * since it may not reflect exactly what is on disk, and that would be - * bad. - */ - if (!list_empty(&prev->list) || !list_empty(&next->list)) - return 0; - - if (extent_map_end(prev) == next->start && - prev->flags == next->flags && - prev->bdev == next->bdev && - ((next->block_start == EXTENT_MAP_HOLE && - prev->block_start == EXTENT_MAP_HOLE) || - (next->block_start == EXTENT_MAP_INLINE && - prev->block_start == EXTENT_MAP_INLINE) || - (next->block_start == EXTENT_MAP_DELALLOC && - prev->block_start == EXTENT_MAP_DELALLOC) || - (next->block_start < EXTENT_MAP_LAST_BYTE - 1 && - next->block_start == extent_map_block_end(prev)))) { - return 1; - } - return 0; -} - -static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em) -{ - struct extent_map *merge = NULL; - struct rb_node *rb; - - if (em->start != 0) { - rb = rb_prev(&em->rb_node); - if (rb) - merge = rb_entry(rb, struct extent_map, rb_node); - if (rb && mergable_maps(merge, em)) { - em->start = merge->start; - em->orig_start = merge->orig_start; - em->len += merge->len; - em->block_len += merge->block_len; - em->block_start = merge->block_start; - em->mod_len = (em->mod_len + em->mod_start) - merge->mod_start; - em->mod_start = merge->mod_start; - em->generation = max(em->generation, merge->generation); - - rb_erase(&merge->rb_node, &tree->map); - RB_CLEAR_NODE(&merge->rb_node); - free_extent_map(merge); - } - } - - rb = rb_next(&em->rb_node); - if (rb) - merge = rb_entry(rb, struct extent_map, rb_node); - if (rb && mergable_maps(em, merge)) { - em->len += merge->len; - em->block_len += merge->block_len; - rb_erase(&merge->rb_node, &tree->map); - RB_CLEAR_NODE(&merge->rb_node); - em->mod_len = (merge->mod_start + merge->mod_len) - em->mod_start; - em->generation = max(em->generation, merge->generation); - free_extent_map(merge); - } -} - -/** - * unpin_extent_cache - unpin an extent from the cache - * @tree: tree to unpin the extent in - * @start: logical offset in the file - * @len: length of the extent - * @gen: generation that this extent has been modified in - * - * Called after an extent has been written to disk properly. Set the generation - * to the generation that actually added the file item to the inode so we know - * we need to sync this extent when we call fsync(). - */ -int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len, - u64 gen) -{ - int ret = 0; - struct extent_map *em; - bool prealloc = false; - - write_lock(&tree->lock); - em = lookup_extent_mapping(tree, start, len); - - WARN_ON(!em || em->start != start); - - if (!em) - goto out; - - em->generation = gen; - clear_bit(EXTENT_FLAG_PINNED, &em->flags); - em->mod_start = em->start; - em->mod_len = em->len; - - if (test_bit(EXTENT_FLAG_FILLING, &em->flags)) { - prealloc = true; - clear_bit(EXTENT_FLAG_FILLING, &em->flags); - } - - try_merge_map(tree, em); - - if (prealloc) { - em->mod_start = em->start; - em->mod_len = em->len; - } - - free_extent_map(em); -out: - write_unlock(&tree->lock); - return ret; - -} - -void clear_em_logging(struct extent_map_tree *tree, struct extent_map *em) -{ - clear_bit(EXTENT_FLAG_LOGGING, &em->flags); - if (extent_map_in_tree(em)) - try_merge_map(tree, em); -} - -static inline void setup_extent_mapping(struct extent_map_tree *tree, - struct extent_map *em, - int modified) -{ - atomic_inc(&em->refs); - em->mod_start = em->start; - em->mod_len = em->len; - - if (modified) - list_move(&em->list, &tree->modified_extents); - else - try_merge_map(tree, em); -} - -/** - * add_extent_mapping - add new extent map to the extent tree - * @tree: tree to insert new map in - * @em: map to insert - * - * Insert @em into @tree or perform a simple forward/backward merge with - * existing mappings. The extent_map struct passed in will be inserted - * into the tree directly, with an additional reference taken, or a - * reference dropped if the merge attempt was successful. - */ -int add_extent_mapping(struct extent_map_tree *tree, - struct extent_map *em, int modified) -{ - int ret = 0; - - ret = tree_insert(&tree->map, em); - if (ret) - goto out; - - setup_extent_mapping(tree, em, modified); -out: - return ret; -} - -static struct extent_map * -__lookup_extent_mapping(struct extent_map_tree *tree, - u64 start, u64 len, int strict) -{ - struct extent_map *em; - struct rb_node *rb_node; - struct rb_node *prev = NULL; - struct rb_node *next = NULL; - u64 end = range_end(start, len); - - rb_node = __tree_search(&tree->map, start, &prev, &next); - if (!rb_node) { - if (prev) - rb_node = prev; - else if (next) - rb_node = next; - else - return NULL; - } - - em = rb_entry(rb_node, struct extent_map, rb_node); - - if (strict && !(end > em->start && start < extent_map_end(em))) - return NULL; - - atomic_inc(&em->refs); - return em; -} - -/** - * lookup_extent_mapping - lookup extent_map - * @tree: tree to lookup in - * @start: byte offset to start the search - * @len: length of the lookup range - * - * Find and return the first extent_map struct in @tree that intersects the - * [start, len] range. There may be additional objects in the tree that - * intersect, so check the object returned carefully to make sure that no - * additional lookups are needed. - */ -struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, - u64 start, u64 len) -{ - return __lookup_extent_mapping(tree, start, len, 1); -} - -/** - * search_extent_mapping - find a nearby extent map - * @tree: tree to lookup in - * @start: byte offset to start the search - * @len: length of the lookup range - * - * Find and return the first extent_map struct in @tree that intersects the - * [start, len] range. - * - * If one can't be found, any nearby extent may be returned - */ -struct extent_map *search_extent_mapping(struct extent_map_tree *tree, - u64 start, u64 len) -{ - return __lookup_extent_mapping(tree, start, len, 0); -} - -/** - * remove_extent_mapping - removes an extent_map from the extent tree - * @tree: extent tree to remove from - * @em: extent map being removed - * - * Removes @em from @tree. No reference counts are dropped, and no checks - * are done to see if the range is in use - */ -int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em) -{ - int ret = 0; - - WARN_ON(test_bit(EXTENT_FLAG_PINNED, &em->flags)); - rb_erase(&em->rb_node, &tree->map); - if (!test_bit(EXTENT_FLAG_LOGGING, &em->flags)) - list_del_init(&em->list); - RB_CLEAR_NODE(&em->rb_node); - return ret; -} - -void replace_extent_mapping(struct extent_map_tree *tree, - struct extent_map *cur, - struct extent_map *new, - int modified) -{ - WARN_ON(test_bit(EXTENT_FLAG_PINNED, &cur->flags)); - ASSERT(extent_map_in_tree(cur)); - if (!test_bit(EXTENT_FLAG_LOGGING, &cur->flags)) - list_del_init(&cur->list); - rb_replace_node(&cur->rb_node, &new->rb_node, &tree->map); - RB_CLEAR_NODE(&cur->rb_node); - - setup_extent_mapping(tree, new, modified); -} diff --git a/src/linux/fs/btrfs/extent_map.h b/src/linux/fs/btrfs/extent_map.h deleted file mode 100644 index eb8b8fa..0000000 --- a/src/linux/fs/btrfs/extent_map.h +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef __EXTENTMAP__ -#define __EXTENTMAP__ - -#include - -#define EXTENT_MAP_LAST_BYTE ((u64)-4) -#define EXTENT_MAP_HOLE ((u64)-3) -#define EXTENT_MAP_INLINE ((u64)-2) -#define EXTENT_MAP_DELALLOC ((u64)-1) - -/* bits for the flags field */ -#define EXTENT_FLAG_PINNED 0 /* this entry not yet on disk, don't free it */ -#define EXTENT_FLAG_COMPRESSED 1 -#define EXTENT_FLAG_VACANCY 2 /* no file extent item found */ -#define EXTENT_FLAG_PREALLOC 3 /* pre-allocated extent */ -#define EXTENT_FLAG_LOGGING 4 /* Logging this extent */ -#define EXTENT_FLAG_FILLING 5 /* Filling in a preallocated extent */ -#define EXTENT_FLAG_FS_MAPPING 6 /* filesystem extent mapping type */ - -struct extent_map { - struct rb_node rb_node; - - /* all of these are in bytes */ - u64 start; - u64 len; - u64 mod_start; - u64 mod_len; - u64 orig_start; - u64 orig_block_len; - u64 ram_bytes; - u64 block_start; - u64 block_len; - u64 generation; - unsigned long flags; - union { - struct block_device *bdev; - - /* - * used for chunk mappings - * flags & EXTENT_FLAG_FS_MAPPING must be set - */ - struct map_lookup *map_lookup; - }; - atomic_t refs; - unsigned int compress_type; - struct list_head list; -}; - -struct extent_map_tree { - struct rb_root map; - struct list_head modified_extents; - rwlock_t lock; -}; - -static inline int extent_map_in_tree(const struct extent_map *em) -{ - return !RB_EMPTY_NODE(&em->rb_node); -} - -static inline u64 extent_map_end(struct extent_map *em) -{ - if (em->start + em->len < em->start) - return (u64)-1; - return em->start + em->len; -} - -static inline u64 extent_map_block_end(struct extent_map *em) -{ - if (em->block_start + em->block_len < em->block_start) - return (u64)-1; - return em->block_start + em->block_len; -} - -void extent_map_tree_init(struct extent_map_tree *tree); -struct extent_map *lookup_extent_mapping(struct extent_map_tree *tree, - u64 start, u64 len); -int add_extent_mapping(struct extent_map_tree *tree, - struct extent_map *em, int modified); -int remove_extent_mapping(struct extent_map_tree *tree, struct extent_map *em); -void replace_extent_mapping(struct extent_map_tree *tree, - struct extent_map *cur, - struct extent_map *new, - int modified); - -struct extent_map *alloc_extent_map(void); -void free_extent_map(struct extent_map *em); -int __init extent_map_init(void); -void extent_map_exit(void); -int unpin_extent_cache(struct extent_map_tree *tree, u64 start, u64 len, u64 gen); -void clear_em_logging(struct extent_map_tree *tree, struct extent_map *em); -struct extent_map *search_extent_mapping(struct extent_map_tree *tree, - u64 start, u64 len); -#endif diff --git a/src/linux/fs/btrfs/file-item.c b/src/linux/fs/btrfs/file-item.c deleted file mode 100644 index d0d571c..0000000 --- a/src/linux/fs/btrfs/file-item.c +++ /dev/null @@ -1,990 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include "ctree.h" -#include "disk-io.h" -#include "transaction.h" -#include "volumes.h" -#include "print-tree.h" -#include "compression.h" - -#define __MAX_CSUM_ITEMS(r, size) ((unsigned long)(((BTRFS_LEAF_DATA_SIZE(r) - \ - sizeof(struct btrfs_item) * 2) / \ - size) - 1)) - -#define MAX_CSUM_ITEMS(r, size) (min_t(u32, __MAX_CSUM_ITEMS(r, size), \ - PAGE_SIZE)) - -#define MAX_ORDERED_SUM_BYTES(r) ((PAGE_SIZE - \ - sizeof(struct btrfs_ordered_sum)) / \ - sizeof(u32) * (r)->sectorsize) - -int btrfs_insert_file_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 objectid, u64 pos, - u64 disk_offset, u64 disk_num_bytes, - u64 num_bytes, u64 offset, u64 ram_bytes, - u8 compression, u8 encryption, u16 other_encoding) -{ - int ret = 0; - struct btrfs_file_extent_item *item; - struct btrfs_key file_key; - struct btrfs_path *path; - struct extent_buffer *leaf; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - file_key.objectid = objectid; - file_key.offset = pos; - file_key.type = BTRFS_EXTENT_DATA_KEY; - - path->leave_spinning = 1; - ret = btrfs_insert_empty_item(trans, root, path, &file_key, - sizeof(*item)); - if (ret < 0) - goto out; - BUG_ON(ret); /* Can't happen */ - leaf = path->nodes[0]; - item = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - btrfs_set_file_extent_disk_bytenr(leaf, item, disk_offset); - btrfs_set_file_extent_disk_num_bytes(leaf, item, disk_num_bytes); - btrfs_set_file_extent_offset(leaf, item, offset); - btrfs_set_file_extent_num_bytes(leaf, item, num_bytes); - btrfs_set_file_extent_ram_bytes(leaf, item, ram_bytes); - btrfs_set_file_extent_generation(leaf, item, trans->transid); - btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG); - btrfs_set_file_extent_compression(leaf, item, compression); - btrfs_set_file_extent_encryption(leaf, item, encryption); - btrfs_set_file_extent_other_encoding(leaf, item, other_encoding); - - btrfs_mark_buffer_dirty(leaf); -out: - btrfs_free_path(path); - return ret; -} - -static struct btrfs_csum_item * -btrfs_lookup_csum(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - u64 bytenr, int cow) -{ - int ret; - struct btrfs_key file_key; - struct btrfs_key found_key; - struct btrfs_csum_item *item; - struct extent_buffer *leaf; - u64 csum_offset = 0; - u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); - int csums_in_item; - - file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; - file_key.offset = bytenr; - file_key.type = BTRFS_EXTENT_CSUM_KEY; - ret = btrfs_search_slot(trans, root, &file_key, path, 0, cow); - if (ret < 0) - goto fail; - leaf = path->nodes[0]; - if (ret > 0) { - ret = 1; - if (path->slots[0] == 0) - goto fail; - path->slots[0]--; - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - if (found_key.type != BTRFS_EXTENT_CSUM_KEY) - goto fail; - - csum_offset = (bytenr - found_key.offset) >> - root->fs_info->sb->s_blocksize_bits; - csums_in_item = btrfs_item_size_nr(leaf, path->slots[0]); - csums_in_item /= csum_size; - - if (csum_offset == csums_in_item) { - ret = -EFBIG; - goto fail; - } else if (csum_offset > csums_in_item) { - goto fail; - } - } - item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); - item = (struct btrfs_csum_item *)((unsigned char *)item + - csum_offset * csum_size); - return item; -fail: - if (ret > 0) - ret = -ENOENT; - return ERR_PTR(ret); -} - -int btrfs_lookup_file_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, u64 objectid, - u64 offset, int mod) -{ - int ret; - struct btrfs_key file_key; - int ins_len = mod < 0 ? -1 : 0; - int cow = mod != 0; - - file_key.objectid = objectid; - file_key.offset = offset; - file_key.type = BTRFS_EXTENT_DATA_KEY; - ret = btrfs_search_slot(trans, root, &file_key, path, ins_len, cow); - return ret; -} - -static void btrfs_io_bio_endio_readpage(struct btrfs_io_bio *bio, int err) -{ - kfree(bio->csum_allocated); -} - -static int __btrfs_lookup_bio_sums(struct btrfs_root *root, - struct inode *inode, struct bio *bio, - u64 logical_offset, u32 *dst, int dio) -{ - struct bio_vec *bvec = bio->bi_io_vec; - struct btrfs_io_bio *btrfs_bio = btrfs_io_bio(bio); - struct btrfs_csum_item *item = NULL; - struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; - struct btrfs_path *path; - u8 *csum; - u64 offset = 0; - u64 item_start_offset = 0; - u64 item_last_offset = 0; - u64 disk_bytenr; - u64 page_bytes_left; - u32 diff; - int nblocks; - int bio_index = 0; - int count; - u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - nblocks = bio->bi_iter.bi_size >> inode->i_sb->s_blocksize_bits; - if (!dst) { - if (nblocks * csum_size > BTRFS_BIO_INLINE_CSUM_SIZE) { - btrfs_bio->csum_allocated = kmalloc_array(nblocks, - csum_size, GFP_NOFS); - if (!btrfs_bio->csum_allocated) { - btrfs_free_path(path); - return -ENOMEM; - } - btrfs_bio->csum = btrfs_bio->csum_allocated; - btrfs_bio->end_io = btrfs_io_bio_endio_readpage; - } else { - btrfs_bio->csum = btrfs_bio->csum_inline; - } - csum = btrfs_bio->csum; - } else { - csum = (u8 *)dst; - } - - if (bio->bi_iter.bi_size > PAGE_SIZE * 8) - path->reada = READA_FORWARD; - - WARN_ON(bio->bi_vcnt <= 0); - - /* - * the free space stuff is only read when it hasn't been - * updated in the current transaction. So, we can safely - * read from the commit root and sidestep a nasty deadlock - * between reading the free space cache and updating the csum tree. - */ - if (btrfs_is_free_space_inode(inode)) { - path->search_commit_root = 1; - path->skip_locking = 1; - } - - disk_bytenr = (u64)bio->bi_iter.bi_sector << 9; - if (dio) - offset = logical_offset; - - page_bytes_left = bvec->bv_len; - while (bio_index < bio->bi_vcnt) { - if (!dio) - offset = page_offset(bvec->bv_page) + bvec->bv_offset; - count = btrfs_find_ordered_sum(inode, offset, disk_bytenr, - (u32 *)csum, nblocks); - if (count) - goto found; - - if (!item || disk_bytenr < item_start_offset || - disk_bytenr >= item_last_offset) { - struct btrfs_key found_key; - u32 item_size; - - if (item) - btrfs_release_path(path); - item = btrfs_lookup_csum(NULL, root->fs_info->csum_root, - path, disk_bytenr, 0); - if (IS_ERR(item)) { - count = 1; - memset(csum, 0, csum_size); - if (BTRFS_I(inode)->root->root_key.objectid == - BTRFS_DATA_RELOC_TREE_OBJECTID) { - set_extent_bits(io_tree, offset, - offset + root->sectorsize - 1, - EXTENT_NODATASUM); - } else { - btrfs_info_rl(BTRFS_I(inode)->root->fs_info, - "no csum found for inode %llu start %llu", - btrfs_ino(inode), offset); - } - item = NULL; - btrfs_release_path(path); - goto found; - } - btrfs_item_key_to_cpu(path->nodes[0], &found_key, - path->slots[0]); - - item_start_offset = found_key.offset; - item_size = btrfs_item_size_nr(path->nodes[0], - path->slots[0]); - item_last_offset = item_start_offset + - (item_size / csum_size) * - root->sectorsize; - item = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_csum_item); - } - /* - * this byte range must be able to fit inside - * a single leaf so it will also fit inside a u32 - */ - diff = disk_bytenr - item_start_offset; - diff = diff / root->sectorsize; - diff = diff * csum_size; - count = min_t(int, nblocks, (item_last_offset - disk_bytenr) >> - inode->i_sb->s_blocksize_bits); - read_extent_buffer(path->nodes[0], csum, - ((unsigned long)item) + diff, - csum_size * count); -found: - csum += count * csum_size; - nblocks -= count; - - while (count--) { - disk_bytenr += root->sectorsize; - offset += root->sectorsize; - page_bytes_left -= root->sectorsize; - if (!page_bytes_left) { - bio_index++; - /* - * make sure we're still inside the - * bio before we update page_bytes_left - */ - if (bio_index >= bio->bi_vcnt) { - WARN_ON_ONCE(count); - goto done; - } - bvec++; - page_bytes_left = bvec->bv_len; - } - - } - } - -done: - btrfs_free_path(path); - return 0; -} - -int btrfs_lookup_bio_sums(struct btrfs_root *root, struct inode *inode, - struct bio *bio, u32 *dst) -{ - return __btrfs_lookup_bio_sums(root, inode, bio, 0, dst, 0); -} - -int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode, - struct bio *bio, u64 offset) -{ - return __btrfs_lookup_bio_sums(root, inode, bio, offset, NULL, 1); -} - -int btrfs_lookup_csums_range(struct btrfs_root *root, u64 start, u64 end, - struct list_head *list, int search_commit) -{ - struct btrfs_key key; - struct btrfs_path *path; - struct extent_buffer *leaf; - struct btrfs_ordered_sum *sums; - struct btrfs_csum_item *item; - LIST_HEAD(tmplist); - unsigned long offset; - int ret; - size_t size; - u64 csum_end; - u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); - - ASSERT(IS_ALIGNED(start, root->sectorsize) && - IS_ALIGNED(end + 1, root->sectorsize)); - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - if (search_commit) { - path->skip_locking = 1; - path->reada = READA_FORWARD; - path->search_commit_root = 1; - } - - key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; - key.offset = start; - key.type = BTRFS_EXTENT_CSUM_KEY; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto fail; - if (ret > 0 && path->slots[0] > 0) { - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1); - if (key.objectid == BTRFS_EXTENT_CSUM_OBJECTID && - key.type == BTRFS_EXTENT_CSUM_KEY) { - offset = (start - key.offset) >> - root->fs_info->sb->s_blocksize_bits; - if (offset * csum_size < - btrfs_item_size_nr(leaf, path->slots[0] - 1)) - path->slots[0]--; - } - } - - while (start <= end) { - leaf = path->nodes[0]; - if (path->slots[0] >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) - goto fail; - if (ret > 0) - break; - leaf = path->nodes[0]; - } - - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || - key.type != BTRFS_EXTENT_CSUM_KEY || - key.offset > end) - break; - - if (key.offset > start) - start = key.offset; - - size = btrfs_item_size_nr(leaf, path->slots[0]); - csum_end = key.offset + (size / csum_size) * root->sectorsize; - if (csum_end <= start) { - path->slots[0]++; - continue; - } - - csum_end = min(csum_end, end + 1); - item = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_csum_item); - while (start < csum_end) { - size = min_t(size_t, csum_end - start, - MAX_ORDERED_SUM_BYTES(root)); - sums = kzalloc(btrfs_ordered_sum_size(root, size), - GFP_NOFS); - if (!sums) { - ret = -ENOMEM; - goto fail; - } - - sums->bytenr = start; - sums->len = (int)size; - - offset = (start - key.offset) >> - root->fs_info->sb->s_blocksize_bits; - offset *= csum_size; - size >>= root->fs_info->sb->s_blocksize_bits; - - read_extent_buffer(path->nodes[0], - sums->sums, - ((unsigned long)item) + offset, - csum_size * size); - - start += root->sectorsize * size; - list_add_tail(&sums->list, &tmplist); - } - path->slots[0]++; - } - ret = 0; -fail: - while (ret < 0 && !list_empty(&tmplist)) { - sums = list_entry(tmplist.next, struct btrfs_ordered_sum, list); - list_del(&sums->list); - kfree(sums); - } - list_splice_tail(&tmplist, list); - - btrfs_free_path(path); - return ret; -} - -int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode, - struct bio *bio, u64 file_start, int contig) -{ - struct btrfs_ordered_sum *sums; - struct btrfs_ordered_extent *ordered; - char *data; - struct bio_vec *bvec = bio->bi_io_vec; - int bio_index = 0; - int index; - int nr_sectors; - int i; - unsigned long total_bytes = 0; - unsigned long this_sum_bytes = 0; - u64 offset; - - WARN_ON(bio->bi_vcnt <= 0); - sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_iter.bi_size), - GFP_NOFS); - if (!sums) - return -ENOMEM; - - sums->len = bio->bi_iter.bi_size; - INIT_LIST_HEAD(&sums->list); - - if (contig) - offset = file_start; - else - offset = page_offset(bvec->bv_page) + bvec->bv_offset; - - ordered = btrfs_lookup_ordered_extent(inode, offset); - BUG_ON(!ordered); /* Logic error */ - sums->bytenr = (u64)bio->bi_iter.bi_sector << 9; - index = 0; - - while (bio_index < bio->bi_vcnt) { - if (!contig) - offset = page_offset(bvec->bv_page) + bvec->bv_offset; - - data = kmap_atomic(bvec->bv_page); - - nr_sectors = BTRFS_BYTES_TO_BLKS(root->fs_info, - bvec->bv_len + root->sectorsize - - 1); - - for (i = 0; i < nr_sectors; i++) { - if (offset >= ordered->file_offset + ordered->len || - offset < ordered->file_offset) { - unsigned long bytes_left; - - kunmap_atomic(data); - sums->len = this_sum_bytes; - this_sum_bytes = 0; - btrfs_add_ordered_sum(inode, ordered, sums); - btrfs_put_ordered_extent(ordered); - - bytes_left = bio->bi_iter.bi_size - total_bytes; - - sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left), - GFP_NOFS); - BUG_ON(!sums); /* -ENOMEM */ - sums->len = bytes_left; - ordered = btrfs_lookup_ordered_extent(inode, - offset); - ASSERT(ordered); /* Logic error */ - sums->bytenr = ((u64)bio->bi_iter.bi_sector << 9) - + total_bytes; - index = 0; - - data = kmap_atomic(bvec->bv_page); - } - - sums->sums[index] = ~(u32)0; - sums->sums[index] - = btrfs_csum_data(data + bvec->bv_offset - + (i * root->sectorsize), - sums->sums[index], - root->sectorsize); - btrfs_csum_final(sums->sums[index], - (char *)(sums->sums + index)); - index++; - offset += root->sectorsize; - this_sum_bytes += root->sectorsize; - total_bytes += root->sectorsize; - } - - kunmap_atomic(data); - - bio_index++; - bvec++; - } - this_sum_bytes = 0; - btrfs_add_ordered_sum(inode, ordered, sums); - btrfs_put_ordered_extent(ordered); - return 0; -} - -/* - * helper function for csum removal, this expects the - * key to describe the csum pointed to by the path, and it expects - * the csum to overlap the range [bytenr, len] - * - * The csum should not be entirely contained in the range and the - * range should not be entirely contained in the csum. - * - * This calls btrfs_truncate_item with the correct args based on the - * overlap, and fixes up the key as required. - */ -static noinline void truncate_one_csum(struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_key *key, - u64 bytenr, u64 len) -{ - struct extent_buffer *leaf; - u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); - u64 csum_end; - u64 end_byte = bytenr + len; - u32 blocksize_bits = root->fs_info->sb->s_blocksize_bits; - - leaf = path->nodes[0]; - csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; - csum_end <<= root->fs_info->sb->s_blocksize_bits; - csum_end += key->offset; - - if (key->offset < bytenr && csum_end <= end_byte) { - /* - * [ bytenr - len ] - * [ ] - * [csum ] - * A simple truncate off the end of the item - */ - u32 new_size = (bytenr - key->offset) >> blocksize_bits; - new_size *= csum_size; - btrfs_truncate_item(root, path, new_size, 1); - } else if (key->offset >= bytenr && csum_end > end_byte && - end_byte > key->offset) { - /* - * [ bytenr - len ] - * [ ] - * [csum ] - * we need to truncate from the beginning of the csum - */ - u32 new_size = (csum_end - end_byte) >> blocksize_bits; - new_size *= csum_size; - - btrfs_truncate_item(root, path, new_size, 0); - - key->offset = end_byte; - btrfs_set_item_key_safe(root->fs_info, path, key); - } else { - BUG(); - } -} - -/* - * deletes the csum items from the csum tree for a given - * range of bytes. - */ -int btrfs_del_csums(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 bytenr, u64 len) -{ - struct btrfs_path *path; - struct btrfs_key key; - u64 end_byte = bytenr + len; - u64 csum_end; - struct extent_buffer *leaf; - int ret; - u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); - int blocksize_bits = root->fs_info->sb->s_blocksize_bits; - - root = root->fs_info->csum_root; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - while (1) { - key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; - key.offset = end_byte - 1; - key.type = BTRFS_EXTENT_CSUM_KEY; - - path->leave_spinning = 1; - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret > 0) { - if (path->slots[0] == 0) - break; - path->slots[0]--; - } else if (ret < 0) { - break; - } - - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - - if (key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || - key.type != BTRFS_EXTENT_CSUM_KEY) { - break; - } - - if (key.offset >= end_byte) - break; - - csum_end = btrfs_item_size_nr(leaf, path->slots[0]) / csum_size; - csum_end <<= blocksize_bits; - csum_end += key.offset; - - /* this csum ends before we start, we're done */ - if (csum_end <= bytenr) - break; - - /* delete the entire item, it is inside our range */ - if (key.offset >= bytenr && csum_end <= end_byte) { - ret = btrfs_del_item(trans, root, path); - if (ret) - goto out; - if (key.offset == bytenr) - break; - } else if (key.offset < bytenr && csum_end > end_byte) { - unsigned long offset; - unsigned long shift_len; - unsigned long item_offset; - /* - * [ bytenr - len ] - * [csum ] - * - * Our bytes are in the middle of the csum, - * we need to split this item and insert a new one. - * - * But we can't drop the path because the - * csum could change, get removed, extended etc. - * - * The trick here is the max size of a csum item leaves - * enough room in the tree block for a single - * item header. So, we split the item in place, - * adding a new header pointing to the existing - * bytes. Then we loop around again and we have - * a nicely formed csum item that we can neatly - * truncate. - */ - offset = (bytenr - key.offset) >> blocksize_bits; - offset *= csum_size; - - shift_len = (len >> blocksize_bits) * csum_size; - - item_offset = btrfs_item_ptr_offset(leaf, - path->slots[0]); - - memset_extent_buffer(leaf, 0, item_offset + offset, - shift_len); - key.offset = bytenr; - - /* - * btrfs_split_item returns -EAGAIN when the - * item changed size or key - */ - ret = btrfs_split_item(trans, root, path, &key, offset); - if (ret && ret != -EAGAIN) { - btrfs_abort_transaction(trans, ret); - goto out; - } - - key.offset = end_byte - 1; - } else { - truncate_one_csum(root, path, &key, bytenr, len); - if (key.offset < bytenr) - break; - } - btrfs_release_path(path); - } - ret = 0; -out: - btrfs_free_path(path); - return ret; -} - -int btrfs_csum_file_blocks(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_ordered_sum *sums) -{ - struct btrfs_key file_key; - struct btrfs_key found_key; - struct btrfs_path *path; - struct btrfs_csum_item *item; - struct btrfs_csum_item *item_end; - struct extent_buffer *leaf = NULL; - u64 next_offset; - u64 total_bytes = 0; - u64 csum_offset; - u64 bytenr; - u32 nritems; - u32 ins_size; - int index = 0; - int found_next; - int ret; - u16 csum_size = btrfs_super_csum_size(root->fs_info->super_copy); - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; -again: - next_offset = (u64)-1; - found_next = 0; - bytenr = sums->bytenr + total_bytes; - file_key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; - file_key.offset = bytenr; - file_key.type = BTRFS_EXTENT_CSUM_KEY; - - item = btrfs_lookup_csum(trans, root, path, bytenr, 1); - if (!IS_ERR(item)) { - ret = 0; - leaf = path->nodes[0]; - item_end = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_csum_item); - item_end = (struct btrfs_csum_item *)((char *)item_end + - btrfs_item_size_nr(leaf, path->slots[0])); - goto found; - } - ret = PTR_ERR(item); - if (ret != -EFBIG && ret != -ENOENT) - goto fail_unlock; - - if (ret == -EFBIG) { - u32 item_size; - /* we found one, but it isn't big enough yet */ - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, path->slots[0]); - if ((item_size / csum_size) >= - MAX_CSUM_ITEMS(root, csum_size)) { - /* already at max size, make a new one */ - goto insert; - } - } else { - int slot = path->slots[0] + 1; - /* we didn't find a csum item, insert one */ - nritems = btrfs_header_nritems(path->nodes[0]); - if (!nritems || (path->slots[0] >= nritems - 1)) { - ret = btrfs_next_leaf(root, path); - if (ret == 1) - found_next = 1; - if (ret != 0) - goto insert; - slot = path->slots[0]; - } - btrfs_item_key_to_cpu(path->nodes[0], &found_key, slot); - if (found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || - found_key.type != BTRFS_EXTENT_CSUM_KEY) { - found_next = 1; - goto insert; - } - next_offset = found_key.offset; - found_next = 1; - goto insert; - } - - /* - * at this point, we know the tree has an item, but it isn't big - * enough yet to put our csum in. Grow it - */ - btrfs_release_path(path); - ret = btrfs_search_slot(trans, root, &file_key, path, - csum_size, 1); - if (ret < 0) - goto fail_unlock; - - if (ret > 0) { - if (path->slots[0] == 0) - goto insert; - path->slots[0]--; - } - - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - csum_offset = (bytenr - found_key.offset) >> - root->fs_info->sb->s_blocksize_bits; - - if (found_key.type != BTRFS_EXTENT_CSUM_KEY || - found_key.objectid != BTRFS_EXTENT_CSUM_OBJECTID || - csum_offset >= MAX_CSUM_ITEMS(root, csum_size)) { - goto insert; - } - - if (csum_offset == btrfs_item_size_nr(leaf, path->slots[0]) / - csum_size) { - int extend_nr; - u64 tmp; - u32 diff; - u32 free_space; - - if (btrfs_leaf_free_space(root, leaf) < - sizeof(struct btrfs_item) + csum_size * 2) - goto insert; - - free_space = btrfs_leaf_free_space(root, leaf) - - sizeof(struct btrfs_item) - csum_size; - tmp = sums->len - total_bytes; - tmp >>= root->fs_info->sb->s_blocksize_bits; - WARN_ON(tmp < 1); - - extend_nr = max_t(int, 1, (int)tmp); - diff = (csum_offset + extend_nr) * csum_size; - diff = min(diff, MAX_CSUM_ITEMS(root, csum_size) * csum_size); - - diff = diff - btrfs_item_size_nr(leaf, path->slots[0]); - diff = min(free_space, diff); - diff /= csum_size; - diff *= csum_size; - - btrfs_extend_item(root, path, diff); - ret = 0; - goto csum; - } - -insert: - btrfs_release_path(path); - csum_offset = 0; - if (found_next) { - u64 tmp; - - tmp = sums->len - total_bytes; - tmp >>= root->fs_info->sb->s_blocksize_bits; - tmp = min(tmp, (next_offset - file_key.offset) >> - root->fs_info->sb->s_blocksize_bits); - - tmp = max((u64)1, tmp); - tmp = min(tmp, (u64)MAX_CSUM_ITEMS(root, csum_size)); - ins_size = csum_size * tmp; - } else { - ins_size = csum_size; - } - path->leave_spinning = 1; - ret = btrfs_insert_empty_item(trans, root, path, &file_key, - ins_size); - path->leave_spinning = 0; - if (ret < 0) - goto fail_unlock; - if (WARN_ON(ret != 0)) - goto fail_unlock; - leaf = path->nodes[0]; -csum: - item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_csum_item); - item_end = (struct btrfs_csum_item *)((unsigned char *)item + - btrfs_item_size_nr(leaf, path->slots[0])); - item = (struct btrfs_csum_item *)((unsigned char *)item + - csum_offset * csum_size); -found: - ins_size = (u32)(sums->len - total_bytes) >> - root->fs_info->sb->s_blocksize_bits; - ins_size *= csum_size; - ins_size = min_t(u32, (unsigned long)item_end - (unsigned long)item, - ins_size); - write_extent_buffer(leaf, sums->sums + index, (unsigned long)item, - ins_size); - - ins_size /= csum_size; - total_bytes += ins_size * root->sectorsize; - index += ins_size; - - btrfs_mark_buffer_dirty(path->nodes[0]); - if (total_bytes < sums->len) { - btrfs_release_path(path); - cond_resched(); - goto again; - } -out: - btrfs_free_path(path); - return ret; - -fail_unlock: - goto out; -} - -void btrfs_extent_item_to_extent_map(struct inode *inode, - const struct btrfs_path *path, - struct btrfs_file_extent_item *fi, - const bool new_inline, - struct extent_map *em) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct extent_buffer *leaf = path->nodes[0]; - const int slot = path->slots[0]; - struct btrfs_key key; - u64 extent_start, extent_end; - u64 bytenr; - u8 type = btrfs_file_extent_type(leaf, fi); - int compress_type = btrfs_file_extent_compression(leaf, fi); - - em->bdev = root->fs_info->fs_devices->latest_bdev; - btrfs_item_key_to_cpu(leaf, &key, slot); - extent_start = key.offset; - - if (type == BTRFS_FILE_EXTENT_REG || - type == BTRFS_FILE_EXTENT_PREALLOC) { - extent_end = extent_start + - btrfs_file_extent_num_bytes(leaf, fi); - } else if (type == BTRFS_FILE_EXTENT_INLINE) { - size_t size; - size = btrfs_file_extent_inline_len(leaf, slot, fi); - extent_end = ALIGN(extent_start + size, root->sectorsize); - } - - em->ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi); - if (type == BTRFS_FILE_EXTENT_REG || - type == BTRFS_FILE_EXTENT_PREALLOC) { - em->start = extent_start; - em->len = extent_end - extent_start; - em->orig_start = extent_start - - btrfs_file_extent_offset(leaf, fi); - em->orig_block_len = btrfs_file_extent_disk_num_bytes(leaf, fi); - bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); - if (bytenr == 0) { - em->block_start = EXTENT_MAP_HOLE; - return; - } - if (compress_type != BTRFS_COMPRESS_NONE) { - set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); - em->compress_type = compress_type; - em->block_start = bytenr; - em->block_len = em->orig_block_len; - } else { - bytenr += btrfs_file_extent_offset(leaf, fi); - em->block_start = bytenr; - em->block_len = em->len; - if (type == BTRFS_FILE_EXTENT_PREALLOC) - set_bit(EXTENT_FLAG_PREALLOC, &em->flags); - } - } else if (type == BTRFS_FILE_EXTENT_INLINE) { - em->block_start = EXTENT_MAP_INLINE; - em->start = extent_start; - em->len = extent_end - extent_start; - /* - * Initialize orig_start and block_len with the same values - * as in inode.c:btrfs_get_extent(). - */ - em->orig_start = EXTENT_MAP_HOLE; - em->block_len = (u64)-1; - if (!new_inline && compress_type != BTRFS_COMPRESS_NONE) { - set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); - em->compress_type = compress_type; - } - } else { - btrfs_err(root->fs_info, - "unknown file extent item type %d, inode %llu, offset %llu, root %llu", - type, btrfs_ino(inode), extent_start, - root->root_key.objectid); - } -} diff --git a/src/linux/fs/btrfs/file.c b/src/linux/fs/btrfs/file.c deleted file mode 100644 index 3a14c87..0000000 --- a/src/linux/fs/btrfs/file.c +++ /dev/null @@ -1,3047 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ctree.h" -#include "disk-io.h" -#include "transaction.h" -#include "btrfs_inode.h" -#include "print-tree.h" -#include "tree-log.h" -#include "locking.h" -#include "volumes.h" -#include "qgroup.h" -#include "compression.h" - -static struct kmem_cache *btrfs_inode_defrag_cachep; -/* - * when auto defrag is enabled we - * queue up these defrag structs to remember which - * inodes need defragging passes - */ -struct inode_defrag { - struct rb_node rb_node; - /* objectid */ - u64 ino; - /* - * transid where the defrag was added, we search for - * extents newer than this - */ - u64 transid; - - /* root objectid */ - u64 root; - - /* last offset we were able to defrag */ - u64 last_offset; - - /* if we've wrapped around back to zero once already */ - int cycled; -}; - -static int __compare_inode_defrag(struct inode_defrag *defrag1, - struct inode_defrag *defrag2) -{ - if (defrag1->root > defrag2->root) - return 1; - else if (defrag1->root < defrag2->root) - return -1; - else if (defrag1->ino > defrag2->ino) - return 1; - else if (defrag1->ino < defrag2->ino) - return -1; - else - return 0; -} - -/* pop a record for an inode into the defrag tree. The lock - * must be held already - * - * If you're inserting a record for an older transid than an - * existing record, the transid already in the tree is lowered - * - * If an existing record is found the defrag item you - * pass in is freed - */ -static int __btrfs_add_inode_defrag(struct inode *inode, - struct inode_defrag *defrag) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct inode_defrag *entry; - struct rb_node **p; - struct rb_node *parent = NULL; - int ret; - - p = &root->fs_info->defrag_inodes.rb_node; - while (*p) { - parent = *p; - entry = rb_entry(parent, struct inode_defrag, rb_node); - - ret = __compare_inode_defrag(defrag, entry); - if (ret < 0) - p = &parent->rb_left; - else if (ret > 0) - p = &parent->rb_right; - else { - /* if we're reinserting an entry for - * an old defrag run, make sure to - * lower the transid of our existing record - */ - if (defrag->transid < entry->transid) - entry->transid = defrag->transid; - if (defrag->last_offset > entry->last_offset) - entry->last_offset = defrag->last_offset; - return -EEXIST; - } - } - set_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags); - rb_link_node(&defrag->rb_node, parent, p); - rb_insert_color(&defrag->rb_node, &root->fs_info->defrag_inodes); - return 0; -} - -static inline int __need_auto_defrag(struct btrfs_root *root) -{ - if (!btrfs_test_opt(root->fs_info, AUTO_DEFRAG)) - return 0; - - if (btrfs_fs_closing(root->fs_info)) - return 0; - - return 1; -} - -/* - * insert a defrag record for this inode if auto defrag is - * enabled - */ -int btrfs_add_inode_defrag(struct btrfs_trans_handle *trans, - struct inode *inode) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct inode_defrag *defrag; - u64 transid; - int ret; - - if (!__need_auto_defrag(root)) - return 0; - - if (test_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags)) - return 0; - - if (trans) - transid = trans->transid; - else - transid = BTRFS_I(inode)->root->last_trans; - - defrag = kmem_cache_zalloc(btrfs_inode_defrag_cachep, GFP_NOFS); - if (!defrag) - return -ENOMEM; - - defrag->ino = btrfs_ino(inode); - defrag->transid = transid; - defrag->root = root->root_key.objectid; - - spin_lock(&root->fs_info->defrag_inodes_lock); - if (!test_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags)) { - /* - * If we set IN_DEFRAG flag and evict the inode from memory, - * and then re-read this inode, this new inode doesn't have - * IN_DEFRAG flag. At the case, we may find the existed defrag. - */ - ret = __btrfs_add_inode_defrag(inode, defrag); - if (ret) - kmem_cache_free(btrfs_inode_defrag_cachep, defrag); - } else { - kmem_cache_free(btrfs_inode_defrag_cachep, defrag); - } - spin_unlock(&root->fs_info->defrag_inodes_lock); - return 0; -} - -/* - * Requeue the defrag object. If there is a defrag object that points to - * the same inode in the tree, we will merge them together (by - * __btrfs_add_inode_defrag()) and free the one that we want to requeue. - */ -static void btrfs_requeue_inode_defrag(struct inode *inode, - struct inode_defrag *defrag) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - int ret; - - if (!__need_auto_defrag(root)) - goto out; - - /* - * Here we don't check the IN_DEFRAG flag, because we need merge - * them together. - */ - spin_lock(&root->fs_info->defrag_inodes_lock); - ret = __btrfs_add_inode_defrag(inode, defrag); - spin_unlock(&root->fs_info->defrag_inodes_lock); - if (ret) - goto out; - return; -out: - kmem_cache_free(btrfs_inode_defrag_cachep, defrag); -} - -/* - * pick the defragable inode that we want, if it doesn't exist, we will get - * the next one. - */ -static struct inode_defrag * -btrfs_pick_defrag_inode(struct btrfs_fs_info *fs_info, u64 root, u64 ino) -{ - struct inode_defrag *entry = NULL; - struct inode_defrag tmp; - struct rb_node *p; - struct rb_node *parent = NULL; - int ret; - - tmp.ino = ino; - tmp.root = root; - - spin_lock(&fs_info->defrag_inodes_lock); - p = fs_info->defrag_inodes.rb_node; - while (p) { - parent = p; - entry = rb_entry(parent, struct inode_defrag, rb_node); - - ret = __compare_inode_defrag(&tmp, entry); - if (ret < 0) - p = parent->rb_left; - else if (ret > 0) - p = parent->rb_right; - else - goto out; - } - - if (parent && __compare_inode_defrag(&tmp, entry) > 0) { - parent = rb_next(parent); - if (parent) - entry = rb_entry(parent, struct inode_defrag, rb_node); - else - entry = NULL; - } -out: - if (entry) - rb_erase(parent, &fs_info->defrag_inodes); - spin_unlock(&fs_info->defrag_inodes_lock); - return entry; -} - -void btrfs_cleanup_defrag_inodes(struct btrfs_fs_info *fs_info) -{ - struct inode_defrag *defrag; - struct rb_node *node; - - spin_lock(&fs_info->defrag_inodes_lock); - node = rb_first(&fs_info->defrag_inodes); - while (node) { - rb_erase(node, &fs_info->defrag_inodes); - defrag = rb_entry(node, struct inode_defrag, rb_node); - kmem_cache_free(btrfs_inode_defrag_cachep, defrag); - - cond_resched_lock(&fs_info->defrag_inodes_lock); - - node = rb_first(&fs_info->defrag_inodes); - } - spin_unlock(&fs_info->defrag_inodes_lock); -} - -#define BTRFS_DEFRAG_BATCH 1024 - -static int __btrfs_run_defrag_inode(struct btrfs_fs_info *fs_info, - struct inode_defrag *defrag) -{ - struct btrfs_root *inode_root; - struct inode *inode; - struct btrfs_key key; - struct btrfs_ioctl_defrag_range_args range; - int num_defrag; - int index; - int ret; - - /* get the inode */ - key.objectid = defrag->root; - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = (u64)-1; - - index = srcu_read_lock(&fs_info->subvol_srcu); - - inode_root = btrfs_read_fs_root_no_name(fs_info, &key); - if (IS_ERR(inode_root)) { - ret = PTR_ERR(inode_root); - goto cleanup; - } - - key.objectid = defrag->ino; - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - inode = btrfs_iget(fs_info->sb, &key, inode_root, NULL); - if (IS_ERR(inode)) { - ret = PTR_ERR(inode); - goto cleanup; - } - srcu_read_unlock(&fs_info->subvol_srcu, index); - - /* do a chunk of defrag */ - clear_bit(BTRFS_INODE_IN_DEFRAG, &BTRFS_I(inode)->runtime_flags); - memset(&range, 0, sizeof(range)); - range.len = (u64)-1; - range.start = defrag->last_offset; - - sb_start_write(fs_info->sb); - num_defrag = btrfs_defrag_file(inode, NULL, &range, defrag->transid, - BTRFS_DEFRAG_BATCH); - sb_end_write(fs_info->sb); - /* - * if we filled the whole defrag batch, there - * must be more work to do. Queue this defrag - * again - */ - if (num_defrag == BTRFS_DEFRAG_BATCH) { - defrag->last_offset = range.start; - btrfs_requeue_inode_defrag(inode, defrag); - } else if (defrag->last_offset && !defrag->cycled) { - /* - * we didn't fill our defrag batch, but - * we didn't start at zero. Make sure we loop - * around to the start of the file. - */ - defrag->last_offset = 0; - defrag->cycled = 1; - btrfs_requeue_inode_defrag(inode, defrag); - } else { - kmem_cache_free(btrfs_inode_defrag_cachep, defrag); - } - - iput(inode); - return 0; -cleanup: - srcu_read_unlock(&fs_info->subvol_srcu, index); - kmem_cache_free(btrfs_inode_defrag_cachep, defrag); - return ret; -} - -/* - * run through the list of inodes in the FS that need - * defragging - */ -int btrfs_run_defrag_inodes(struct btrfs_fs_info *fs_info) -{ - struct inode_defrag *defrag; - u64 first_ino = 0; - u64 root_objectid = 0; - - atomic_inc(&fs_info->defrag_running); - while (1) { - /* Pause the auto defragger. */ - if (test_bit(BTRFS_FS_STATE_REMOUNTING, - &fs_info->fs_state)) - break; - - if (!__need_auto_defrag(fs_info->tree_root)) - break; - - /* find an inode to defrag */ - defrag = btrfs_pick_defrag_inode(fs_info, root_objectid, - first_ino); - if (!defrag) { - if (root_objectid || first_ino) { - root_objectid = 0; - first_ino = 0; - continue; - } else { - break; - } - } - - first_ino = defrag->ino + 1; - root_objectid = defrag->root; - - __btrfs_run_defrag_inode(fs_info, defrag); - } - atomic_dec(&fs_info->defrag_running); - - /* - * during unmount, we use the transaction_wait queue to - * wait for the defragger to stop - */ - wake_up(&fs_info->transaction_wait); - return 0; -} - -/* simple helper to fault in pages and copy. This should go away - * and be replaced with calls into generic code. - */ -static noinline int btrfs_copy_from_user(loff_t pos, size_t write_bytes, - struct page **prepared_pages, - struct iov_iter *i) -{ - size_t copied = 0; - size_t total_copied = 0; - int pg = 0; - int offset = pos & (PAGE_SIZE - 1); - - while (write_bytes > 0) { - size_t count = min_t(size_t, - PAGE_SIZE - offset, write_bytes); - struct page *page = prepared_pages[pg]; - /* - * Copy data from userspace to the current page - */ - copied = iov_iter_copy_from_user_atomic(page, i, offset, count); - - /* Flush processor's dcache for this page */ - flush_dcache_page(page); - - /* - * if we get a partial write, we can end up with - * partially up to date pages. These add - * a lot of complexity, so make sure they don't - * happen by forcing this copy to be retried. - * - * The rest of the btrfs_file_write code will fall - * back to page at a time copies after we return 0. - */ - if (!PageUptodate(page) && copied < count) - copied = 0; - - iov_iter_advance(i, copied); - write_bytes -= copied; - total_copied += copied; - - /* Return to btrfs_file_write_iter to fault page */ - if (unlikely(copied == 0)) - break; - - if (copied < PAGE_SIZE - offset) { - offset += copied; - } else { - pg++; - offset = 0; - } - } - return total_copied; -} - -/* - * unlocks pages after btrfs_file_write is done with them - */ -static void btrfs_drop_pages(struct page **pages, size_t num_pages) -{ - size_t i; - for (i = 0; i < num_pages; i++) { - /* page checked is some magic around finding pages that - * have been modified without going through btrfs_set_page_dirty - * clear it here. There should be no need to mark the pages - * accessed as prepare_pages should have marked them accessed - * in prepare_pages via find_or_create_page() - */ - ClearPageChecked(pages[i]); - unlock_page(pages[i]); - put_page(pages[i]); - } -} - -/* - * after copy_from_user, pages need to be dirtied and we need to make - * sure holes are created between the current EOF and the start of - * any next extents (if required). - * - * this also makes the decision about creating an inline extent vs - * doing real data extents, marking pages dirty and delalloc as required. - */ -int btrfs_dirty_pages(struct btrfs_root *root, struct inode *inode, - struct page **pages, size_t num_pages, - loff_t pos, size_t write_bytes, - struct extent_state **cached) -{ - int err = 0; - int i; - u64 num_bytes; - u64 start_pos; - u64 end_of_last_block; - u64 end_pos = pos + write_bytes; - loff_t isize = i_size_read(inode); - - start_pos = pos & ~((u64)root->sectorsize - 1); - num_bytes = round_up(write_bytes + pos - start_pos, root->sectorsize); - - end_of_last_block = start_pos + num_bytes - 1; - err = btrfs_set_extent_delalloc(inode, start_pos, end_of_last_block, - cached, 0); - if (err) - return err; - - for (i = 0; i < num_pages; i++) { - struct page *p = pages[i]; - SetPageUptodate(p); - ClearPageChecked(p); - set_page_dirty(p); - } - - /* - * we've only changed i_size in ram, and we haven't updated - * the disk i_size. There is no need to log the inode - * at this time. - */ - if (end_pos > isize) - i_size_write(inode, end_pos); - return 0; -} - -/* - * this drops all the extents in the cache that intersect the range - * [start, end]. Existing extents are split as required. - */ -void btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, - int skip_pinned) -{ - struct extent_map *em; - struct extent_map *split = NULL; - struct extent_map *split2 = NULL; - struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; - u64 len = end - start + 1; - u64 gen; - int ret; - int testend = 1; - unsigned long flags; - int compressed = 0; - bool modified; - - WARN_ON(end < start); - if (end == (u64)-1) { - len = (u64)-1; - testend = 0; - } - while (1) { - int no_splits = 0; - - modified = false; - if (!split) - split = alloc_extent_map(); - if (!split2) - split2 = alloc_extent_map(); - if (!split || !split2) - no_splits = 1; - - write_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, start, len); - if (!em) { - write_unlock(&em_tree->lock); - break; - } - flags = em->flags; - gen = em->generation; - if (skip_pinned && test_bit(EXTENT_FLAG_PINNED, &em->flags)) { - if (testend && em->start + em->len >= start + len) { - free_extent_map(em); - write_unlock(&em_tree->lock); - break; - } - start = em->start + em->len; - if (testend) - len = start + len - (em->start + em->len); - free_extent_map(em); - write_unlock(&em_tree->lock); - continue; - } - compressed = test_bit(EXTENT_FLAG_COMPRESSED, &em->flags); - clear_bit(EXTENT_FLAG_PINNED, &em->flags); - clear_bit(EXTENT_FLAG_LOGGING, &flags); - modified = !list_empty(&em->list); - if (no_splits) - goto next; - - if (em->start < start) { - split->start = em->start; - split->len = start - em->start; - - if (em->block_start < EXTENT_MAP_LAST_BYTE) { - split->orig_start = em->orig_start; - split->block_start = em->block_start; - - if (compressed) - split->block_len = em->block_len; - else - split->block_len = split->len; - split->orig_block_len = max(split->block_len, - em->orig_block_len); - split->ram_bytes = em->ram_bytes; - } else { - split->orig_start = split->start; - split->block_len = 0; - split->block_start = em->block_start; - split->orig_block_len = 0; - split->ram_bytes = split->len; - } - - split->generation = gen; - split->bdev = em->bdev; - split->flags = flags; - split->compress_type = em->compress_type; - replace_extent_mapping(em_tree, em, split, modified); - free_extent_map(split); - split = split2; - split2 = NULL; - } - if (testend && em->start + em->len > start + len) { - u64 diff = start + len - em->start; - - split->start = start + len; - split->len = em->start + em->len - (start + len); - split->bdev = em->bdev; - split->flags = flags; - split->compress_type = em->compress_type; - split->generation = gen; - - if (em->block_start < EXTENT_MAP_LAST_BYTE) { - split->orig_block_len = max(em->block_len, - em->orig_block_len); - - split->ram_bytes = em->ram_bytes; - if (compressed) { - split->block_len = em->block_len; - split->block_start = em->block_start; - split->orig_start = em->orig_start; - } else { - split->block_len = split->len; - split->block_start = em->block_start - + diff; - split->orig_start = em->orig_start; - } - } else { - split->ram_bytes = split->len; - split->orig_start = split->start; - split->block_len = 0; - split->block_start = em->block_start; - split->orig_block_len = 0; - } - - if (extent_map_in_tree(em)) { - replace_extent_mapping(em_tree, em, split, - modified); - } else { - ret = add_extent_mapping(em_tree, split, - modified); - ASSERT(ret == 0); /* Logic error */ - } - free_extent_map(split); - split = NULL; - } -next: - if (extent_map_in_tree(em)) - remove_extent_mapping(em_tree, em); - write_unlock(&em_tree->lock); - - /* once for us */ - free_extent_map(em); - /* once for the tree*/ - free_extent_map(em); - } - if (split) - free_extent_map(split); - if (split2) - free_extent_map(split2); -} - -/* - * this is very complex, but the basic idea is to drop all extents - * in the range start - end. hint_block is filled in with a block number - * that would be a good hint to the block allocator for this file. - * - * If an extent intersects the range but is not entirely inside the range - * it is either truncated or split. Anything entirely inside the range - * is deleted from the tree. - */ -int __btrfs_drop_extents(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct inode *inode, - struct btrfs_path *path, u64 start, u64 end, - u64 *drop_end, int drop_cache, - int replace_extent, - u32 extent_item_size, - int *key_inserted) -{ - struct extent_buffer *leaf; - struct btrfs_file_extent_item *fi; - struct btrfs_key key; - struct btrfs_key new_key; - u64 ino = btrfs_ino(inode); - u64 search_start = start; - u64 disk_bytenr = 0; - u64 num_bytes = 0; - u64 extent_offset = 0; - u64 extent_end = 0; - int del_nr = 0; - int del_slot = 0; - int extent_type; - int recow; - int ret; - int modify_tree = -1; - int update_refs; - int found = 0; - int leafs_visited = 0; - - if (drop_cache) - btrfs_drop_extent_cache(inode, start, end - 1, 0); - - if (start >= BTRFS_I(inode)->disk_i_size && !replace_extent) - modify_tree = 0; - - update_refs = (test_bit(BTRFS_ROOT_REF_COWS, &root->state) || - root == root->fs_info->tree_root); - while (1) { - recow = 0; - ret = btrfs_lookup_file_extent(trans, root, path, ino, - search_start, modify_tree); - if (ret < 0) - break; - if (ret > 0 && path->slots[0] > 0 && search_start == start) { - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, path->slots[0] - 1); - if (key.objectid == ino && - key.type == BTRFS_EXTENT_DATA_KEY) - path->slots[0]--; - } - ret = 0; - leafs_visited++; -next_slot: - leaf = path->nodes[0]; - if (path->slots[0] >= btrfs_header_nritems(leaf)) { - BUG_ON(del_nr > 0); - ret = btrfs_next_leaf(root, path); - if (ret < 0) - break; - if (ret > 0) { - ret = 0; - break; - } - leafs_visited++; - leaf = path->nodes[0]; - recow = 1; - } - - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - - if (key.objectid > ino) - break; - if (WARN_ON_ONCE(key.objectid < ino) || - key.type < BTRFS_EXTENT_DATA_KEY) { - ASSERT(del_nr == 0); - path->slots[0]++; - goto next_slot; - } - if (key.type > BTRFS_EXTENT_DATA_KEY || key.offset >= end) - break; - - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - extent_type = btrfs_file_extent_type(leaf, fi); - - if (extent_type == BTRFS_FILE_EXTENT_REG || - extent_type == BTRFS_FILE_EXTENT_PREALLOC) { - disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); - num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); - extent_offset = btrfs_file_extent_offset(leaf, fi); - extent_end = key.offset + - btrfs_file_extent_num_bytes(leaf, fi); - } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { - extent_end = key.offset + - btrfs_file_extent_inline_len(leaf, - path->slots[0], fi); - } else { - /* can't happen */ - BUG(); - } - - /* - * Don't skip extent items representing 0 byte lengths. They - * used to be created (bug) if while punching holes we hit - * -ENOSPC condition. So if we find one here, just ensure we - * delete it, otherwise we would insert a new file extent item - * with the same key (offset) as that 0 bytes length file - * extent item in the call to setup_items_for_insert() later - * in this function. - */ - if (extent_end == key.offset && extent_end >= search_start) - goto delete_extent_item; - - if (extent_end <= search_start) { - path->slots[0]++; - goto next_slot; - } - - found = 1; - search_start = max(key.offset, start); - if (recow || !modify_tree) { - modify_tree = -1; - btrfs_release_path(path); - continue; - } - - /* - * | - range to drop - | - * | -------- extent -------- | - */ - if (start > key.offset && end < extent_end) { - BUG_ON(del_nr > 0); - if (extent_type == BTRFS_FILE_EXTENT_INLINE) { - ret = -EOPNOTSUPP; - break; - } - - memcpy(&new_key, &key, sizeof(new_key)); - new_key.offset = start; - ret = btrfs_duplicate_item(trans, root, path, - &new_key); - if (ret == -EAGAIN) { - btrfs_release_path(path); - continue; - } - if (ret < 0) - break; - - leaf = path->nodes[0]; - fi = btrfs_item_ptr(leaf, path->slots[0] - 1, - struct btrfs_file_extent_item); - btrfs_set_file_extent_num_bytes(leaf, fi, - start - key.offset); - - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - - extent_offset += start - key.offset; - btrfs_set_file_extent_offset(leaf, fi, extent_offset); - btrfs_set_file_extent_num_bytes(leaf, fi, - extent_end - start); - btrfs_mark_buffer_dirty(leaf); - - if (update_refs && disk_bytenr > 0) { - ret = btrfs_inc_extent_ref(trans, root, - disk_bytenr, num_bytes, 0, - root->root_key.objectid, - new_key.objectid, - start - extent_offset); - BUG_ON(ret); /* -ENOMEM */ - } - key.offset = start; - } - /* - * | ---- range to drop ----- | - * | -------- extent -------- | - */ - if (start <= key.offset && end < extent_end) { - if (extent_type == BTRFS_FILE_EXTENT_INLINE) { - ret = -EOPNOTSUPP; - break; - } - - memcpy(&new_key, &key, sizeof(new_key)); - new_key.offset = end; - btrfs_set_item_key_safe(root->fs_info, path, &new_key); - - extent_offset += end - key.offset; - btrfs_set_file_extent_offset(leaf, fi, extent_offset); - btrfs_set_file_extent_num_bytes(leaf, fi, - extent_end - end); - btrfs_mark_buffer_dirty(leaf); - if (update_refs && disk_bytenr > 0) - inode_sub_bytes(inode, end - key.offset); - break; - } - - search_start = extent_end; - /* - * | ---- range to drop ----- | - * | -------- extent -------- | - */ - if (start > key.offset && end >= extent_end) { - BUG_ON(del_nr > 0); - if (extent_type == BTRFS_FILE_EXTENT_INLINE) { - ret = -EOPNOTSUPP; - break; - } - - btrfs_set_file_extent_num_bytes(leaf, fi, - start - key.offset); - btrfs_mark_buffer_dirty(leaf); - if (update_refs && disk_bytenr > 0) - inode_sub_bytes(inode, extent_end - start); - if (end == extent_end) - break; - - path->slots[0]++; - goto next_slot; - } - - /* - * | ---- range to drop ----- | - * | ------ extent ------ | - */ - if (start <= key.offset && end >= extent_end) { -delete_extent_item: - if (del_nr == 0) { - del_slot = path->slots[0]; - del_nr = 1; - } else { - BUG_ON(del_slot + del_nr != path->slots[0]); - del_nr++; - } - - if (update_refs && - extent_type == BTRFS_FILE_EXTENT_INLINE) { - inode_sub_bytes(inode, - extent_end - key.offset); - extent_end = ALIGN(extent_end, - root->sectorsize); - } else if (update_refs && disk_bytenr > 0) { - ret = btrfs_free_extent(trans, root, - disk_bytenr, num_bytes, 0, - root->root_key.objectid, - key.objectid, key.offset - - extent_offset); - BUG_ON(ret); /* -ENOMEM */ - inode_sub_bytes(inode, - extent_end - key.offset); - } - - if (end == extent_end) - break; - - if (path->slots[0] + 1 < btrfs_header_nritems(leaf)) { - path->slots[0]++; - goto next_slot; - } - - ret = btrfs_del_items(trans, root, path, del_slot, - del_nr); - if (ret) { - btrfs_abort_transaction(trans, ret); - break; - } - - del_nr = 0; - del_slot = 0; - - btrfs_release_path(path); - continue; - } - - BUG_ON(1); - } - - if (!ret && del_nr > 0) { - /* - * Set path->slots[0] to first slot, so that after the delete - * if items are move off from our leaf to its immediate left or - * right neighbor leafs, we end up with a correct and adjusted - * path->slots[0] for our insertion (if replace_extent != 0). - */ - path->slots[0] = del_slot; - ret = btrfs_del_items(trans, root, path, del_slot, del_nr); - if (ret) - btrfs_abort_transaction(trans, ret); - } - - leaf = path->nodes[0]; - /* - * If btrfs_del_items() was called, it might have deleted a leaf, in - * which case it unlocked our path, so check path->locks[0] matches a - * write lock. - */ - if (!ret && replace_extent && leafs_visited == 1 && - (path->locks[0] == BTRFS_WRITE_LOCK_BLOCKING || - path->locks[0] == BTRFS_WRITE_LOCK) && - btrfs_leaf_free_space(root, leaf) >= - sizeof(struct btrfs_item) + extent_item_size) { - - key.objectid = ino; - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = start; - if (!del_nr && path->slots[0] < btrfs_header_nritems(leaf)) { - struct btrfs_key slot_key; - - btrfs_item_key_to_cpu(leaf, &slot_key, path->slots[0]); - if (btrfs_comp_cpu_keys(&key, &slot_key) > 0) - path->slots[0]++; - } - setup_items_for_insert(root, path, &key, - &extent_item_size, - extent_item_size, - sizeof(struct btrfs_item) + - extent_item_size, 1); - *key_inserted = 1; - } - - if (!replace_extent || !(*key_inserted)) - btrfs_release_path(path); - if (drop_end) - *drop_end = found ? min(end, extent_end) : end; - return ret; -} - -int btrfs_drop_extents(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct inode *inode, u64 start, - u64 end, int drop_cache) -{ - struct btrfs_path *path; - int ret; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - ret = __btrfs_drop_extents(trans, root, inode, path, start, end, NULL, - drop_cache, 0, 0, NULL); - btrfs_free_path(path); - return ret; -} - -static int extent_mergeable(struct extent_buffer *leaf, int slot, - u64 objectid, u64 bytenr, u64 orig_offset, - u64 *start, u64 *end) -{ - struct btrfs_file_extent_item *fi; - struct btrfs_key key; - u64 extent_end; - - if (slot < 0 || slot >= btrfs_header_nritems(leaf)) - return 0; - - btrfs_item_key_to_cpu(leaf, &key, slot); - if (key.objectid != objectid || key.type != BTRFS_EXTENT_DATA_KEY) - return 0; - - fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); - if (btrfs_file_extent_type(leaf, fi) != BTRFS_FILE_EXTENT_REG || - btrfs_file_extent_disk_bytenr(leaf, fi) != bytenr || - btrfs_file_extent_offset(leaf, fi) != key.offset - orig_offset || - btrfs_file_extent_compression(leaf, fi) || - btrfs_file_extent_encryption(leaf, fi) || - btrfs_file_extent_other_encoding(leaf, fi)) - return 0; - - extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi); - if ((*start && *start != key.offset) || (*end && *end != extent_end)) - return 0; - - *start = key.offset; - *end = extent_end; - return 1; -} - -/* - * Mark extent in the range start - end as written. - * - * This changes extent type from 'pre-allocated' to 'regular'. If only - * part of extent is marked as written, the extent will be split into - * two or three. - */ -int btrfs_mark_extent_written(struct btrfs_trans_handle *trans, - struct inode *inode, u64 start, u64 end) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct extent_buffer *leaf; - struct btrfs_path *path; - struct btrfs_file_extent_item *fi; - struct btrfs_key key; - struct btrfs_key new_key; - u64 bytenr; - u64 num_bytes; - u64 extent_end; - u64 orig_offset; - u64 other_start; - u64 other_end; - u64 split; - int del_nr = 0; - int del_slot = 0; - int recow; - int ret; - u64 ino = btrfs_ino(inode); - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; -again: - recow = 0; - split = start; - key.objectid = ino; - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = split; - - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret < 0) - goto out; - if (ret > 0 && path->slots[0] > 0) - path->slots[0]--; - - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - if (key.objectid != ino || - key.type != BTRFS_EXTENT_DATA_KEY) { - ret = -EINVAL; - btrfs_abort_transaction(trans, ret); - goto out; - } - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - if (btrfs_file_extent_type(leaf, fi) != BTRFS_FILE_EXTENT_PREALLOC) { - ret = -EINVAL; - btrfs_abort_transaction(trans, ret); - goto out; - } - extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi); - if (key.offset > start || extent_end < end) { - ret = -EINVAL; - btrfs_abort_transaction(trans, ret); - goto out; - } - - bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); - num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); - orig_offset = key.offset - btrfs_file_extent_offset(leaf, fi); - memcpy(&new_key, &key, sizeof(new_key)); - - if (start == key.offset && end < extent_end) { - other_start = 0; - other_end = start; - if (extent_mergeable(leaf, path->slots[0] - 1, - ino, bytenr, orig_offset, - &other_start, &other_end)) { - new_key.offset = end; - btrfs_set_item_key_safe(root->fs_info, path, &new_key); - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - btrfs_set_file_extent_generation(leaf, fi, - trans->transid); - btrfs_set_file_extent_num_bytes(leaf, fi, - extent_end - end); - btrfs_set_file_extent_offset(leaf, fi, - end - orig_offset); - fi = btrfs_item_ptr(leaf, path->slots[0] - 1, - struct btrfs_file_extent_item); - btrfs_set_file_extent_generation(leaf, fi, - trans->transid); - btrfs_set_file_extent_num_bytes(leaf, fi, - end - other_start); - btrfs_mark_buffer_dirty(leaf); - goto out; - } - } - - if (start > key.offset && end == extent_end) { - other_start = end; - other_end = 0; - if (extent_mergeable(leaf, path->slots[0] + 1, - ino, bytenr, orig_offset, - &other_start, &other_end)) { - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - btrfs_set_file_extent_num_bytes(leaf, fi, - start - key.offset); - btrfs_set_file_extent_generation(leaf, fi, - trans->transid); - path->slots[0]++; - new_key.offset = start; - btrfs_set_item_key_safe(root->fs_info, path, &new_key); - - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - btrfs_set_file_extent_generation(leaf, fi, - trans->transid); - btrfs_set_file_extent_num_bytes(leaf, fi, - other_end - start); - btrfs_set_file_extent_offset(leaf, fi, - start - orig_offset); - btrfs_mark_buffer_dirty(leaf); - goto out; - } - } - - while (start > key.offset || end < extent_end) { - if (key.offset == start) - split = end; - - new_key.offset = split; - ret = btrfs_duplicate_item(trans, root, path, &new_key); - if (ret == -EAGAIN) { - btrfs_release_path(path); - goto again; - } - if (ret < 0) { - btrfs_abort_transaction(trans, ret); - goto out; - } - - leaf = path->nodes[0]; - fi = btrfs_item_ptr(leaf, path->slots[0] - 1, - struct btrfs_file_extent_item); - btrfs_set_file_extent_generation(leaf, fi, trans->transid); - btrfs_set_file_extent_num_bytes(leaf, fi, - split - key.offset); - - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - - btrfs_set_file_extent_generation(leaf, fi, trans->transid); - btrfs_set_file_extent_offset(leaf, fi, split - orig_offset); - btrfs_set_file_extent_num_bytes(leaf, fi, - extent_end - split); - btrfs_mark_buffer_dirty(leaf); - - ret = btrfs_inc_extent_ref(trans, root, bytenr, num_bytes, 0, - root->root_key.objectid, - ino, orig_offset); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out; - } - - if (split == start) { - key.offset = start; - } else { - if (start != key.offset) { - ret = -EINVAL; - btrfs_abort_transaction(trans, ret); - goto out; - } - path->slots[0]--; - extent_end = end; - } - recow = 1; - } - - other_start = end; - other_end = 0; - if (extent_mergeable(leaf, path->slots[0] + 1, - ino, bytenr, orig_offset, - &other_start, &other_end)) { - if (recow) { - btrfs_release_path(path); - goto again; - } - extent_end = other_end; - del_slot = path->slots[0] + 1; - del_nr++; - ret = btrfs_free_extent(trans, root, bytenr, num_bytes, - 0, root->root_key.objectid, - ino, orig_offset); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out; - } - } - other_start = 0; - other_end = start; - if (extent_mergeable(leaf, path->slots[0] - 1, - ino, bytenr, orig_offset, - &other_start, &other_end)) { - if (recow) { - btrfs_release_path(path); - goto again; - } - key.offset = other_start; - del_slot = path->slots[0]; - del_nr++; - ret = btrfs_free_extent(trans, root, bytenr, num_bytes, - 0, root->root_key.objectid, - ino, orig_offset); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out; - } - } - if (del_nr == 0) { - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - btrfs_set_file_extent_type(leaf, fi, - BTRFS_FILE_EXTENT_REG); - btrfs_set_file_extent_generation(leaf, fi, trans->transid); - btrfs_mark_buffer_dirty(leaf); - } else { - fi = btrfs_item_ptr(leaf, del_slot - 1, - struct btrfs_file_extent_item); - btrfs_set_file_extent_type(leaf, fi, - BTRFS_FILE_EXTENT_REG); - btrfs_set_file_extent_generation(leaf, fi, trans->transid); - btrfs_set_file_extent_num_bytes(leaf, fi, - extent_end - key.offset); - btrfs_mark_buffer_dirty(leaf); - - ret = btrfs_del_items(trans, root, path, del_slot, del_nr); - if (ret < 0) { - btrfs_abort_transaction(trans, ret); - goto out; - } - } -out: - btrfs_free_path(path); - return 0; -} - -/* - * on error we return an unlocked page and the error value - * on success we return a locked page and 0 - */ -static int prepare_uptodate_page(struct inode *inode, - struct page *page, u64 pos, - bool force_uptodate) -{ - int ret = 0; - - if (((pos & (PAGE_SIZE - 1)) || force_uptodate) && - !PageUptodate(page)) { - ret = btrfs_readpage(NULL, page); - if (ret) - return ret; - lock_page(page); - if (!PageUptodate(page)) { - unlock_page(page); - return -EIO; - } - if (page->mapping != inode->i_mapping) { - unlock_page(page); - return -EAGAIN; - } - } - return 0; -} - -/* - * this just gets pages into the page cache and locks them down. - */ -static noinline int prepare_pages(struct inode *inode, struct page **pages, - size_t num_pages, loff_t pos, - size_t write_bytes, bool force_uptodate) -{ - int i; - unsigned long index = pos >> PAGE_SHIFT; - gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping); - int err = 0; - int faili; - - for (i = 0; i < num_pages; i++) { -again: - pages[i] = find_or_create_page(inode->i_mapping, index + i, - mask | __GFP_WRITE); - if (!pages[i]) { - faili = i - 1; - err = -ENOMEM; - goto fail; - } - - if (i == 0) - err = prepare_uptodate_page(inode, pages[i], pos, - force_uptodate); - if (!err && i == num_pages - 1) - err = prepare_uptodate_page(inode, pages[i], - pos + write_bytes, false); - if (err) { - put_page(pages[i]); - if (err == -EAGAIN) { - err = 0; - goto again; - } - faili = i - 1; - goto fail; - } - wait_on_page_writeback(pages[i]); - } - - return 0; -fail: - while (faili >= 0) { - unlock_page(pages[faili]); - put_page(pages[faili]); - faili--; - } - return err; - -} - -/* - * This function locks the extent and properly waits for data=ordered extents - * to finish before allowing the pages to be modified if need. - * - * The return value: - * 1 - the extent is locked - * 0 - the extent is not locked, and everything is OK - * -EAGAIN - need re-prepare the pages - * the other < 0 number - Something wrong happens - */ -static noinline int -lock_and_cleanup_extent_if_need(struct inode *inode, struct page **pages, - size_t num_pages, loff_t pos, - size_t write_bytes, - u64 *lockstart, u64 *lockend, - struct extent_state **cached_state) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - u64 start_pos; - u64 last_pos; - int i; - int ret = 0; - - start_pos = round_down(pos, root->sectorsize); - last_pos = start_pos - + round_up(pos + write_bytes - start_pos, root->sectorsize) - 1; - - if (start_pos < inode->i_size) { - struct btrfs_ordered_extent *ordered; - lock_extent_bits(&BTRFS_I(inode)->io_tree, - start_pos, last_pos, cached_state); - ordered = btrfs_lookup_ordered_range(inode, start_pos, - last_pos - start_pos + 1); - if (ordered && - ordered->file_offset + ordered->len > start_pos && - ordered->file_offset <= last_pos) { - unlock_extent_cached(&BTRFS_I(inode)->io_tree, - start_pos, last_pos, - cached_state, GFP_NOFS); - for (i = 0; i < num_pages; i++) { - unlock_page(pages[i]); - put_page(pages[i]); - } - btrfs_start_ordered_extent(inode, ordered, 1); - btrfs_put_ordered_extent(ordered); - return -EAGAIN; - } - if (ordered) - btrfs_put_ordered_extent(ordered); - - clear_extent_bit(&BTRFS_I(inode)->io_tree, start_pos, - last_pos, EXTENT_DIRTY | EXTENT_DELALLOC | - EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, - 0, 0, cached_state, GFP_NOFS); - *lockstart = start_pos; - *lockend = last_pos; - ret = 1; - } - - for (i = 0; i < num_pages; i++) { - if (clear_page_dirty_for_io(pages[i])) - account_page_redirty(pages[i]); - set_page_extent_mapped(pages[i]); - WARN_ON(!PageLocked(pages[i])); - } - - return ret; -} - -static noinline int check_can_nocow(struct inode *inode, loff_t pos, - size_t *write_bytes) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_ordered_extent *ordered; - u64 lockstart, lockend; - u64 num_bytes; - int ret; - - ret = btrfs_start_write_no_snapshoting(root); - if (!ret) - return -ENOSPC; - - lockstart = round_down(pos, root->sectorsize); - lockend = round_up(pos + *write_bytes, root->sectorsize) - 1; - - while (1) { - lock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend); - ordered = btrfs_lookup_ordered_range(inode, lockstart, - lockend - lockstart + 1); - if (!ordered) { - break; - } - unlock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend); - btrfs_start_ordered_extent(inode, ordered, 1); - btrfs_put_ordered_extent(ordered); - } - - num_bytes = lockend - lockstart + 1; - ret = can_nocow_extent(inode, lockstart, &num_bytes, NULL, NULL, NULL); - if (ret <= 0) { - ret = 0; - btrfs_end_write_no_snapshoting(root); - } else { - *write_bytes = min_t(size_t, *write_bytes , - num_bytes - pos + lockstart); - } - - unlock_extent(&BTRFS_I(inode)->io_tree, lockstart, lockend); - - return ret; -} - -static noinline ssize_t __btrfs_buffered_write(struct file *file, - struct iov_iter *i, - loff_t pos) -{ - struct inode *inode = file_inode(file); - struct btrfs_root *root = BTRFS_I(inode)->root; - struct page **pages = NULL; - struct extent_state *cached_state = NULL; - u64 release_bytes = 0; - u64 lockstart; - u64 lockend; - size_t num_written = 0; - int nrptrs; - int ret = 0; - bool only_release_metadata = false; - bool force_page_uptodate = false; - bool need_unlock; - - nrptrs = min(DIV_ROUND_UP(iov_iter_count(i), PAGE_SIZE), - PAGE_SIZE / (sizeof(struct page *))); - nrptrs = min(nrptrs, current->nr_dirtied_pause - current->nr_dirtied); - nrptrs = max(nrptrs, 8); - pages = kmalloc_array(nrptrs, sizeof(struct page *), GFP_KERNEL); - if (!pages) - return -ENOMEM; - - while (iov_iter_count(i) > 0) { - size_t offset = pos & (PAGE_SIZE - 1); - size_t sector_offset; - size_t write_bytes = min(iov_iter_count(i), - nrptrs * (size_t)PAGE_SIZE - - offset); - size_t num_pages = DIV_ROUND_UP(write_bytes + offset, - PAGE_SIZE); - size_t reserve_bytes; - size_t dirty_pages; - size_t copied; - size_t dirty_sectors; - size_t num_sectors; - - WARN_ON(num_pages > nrptrs); - - /* - * Fault pages before locking them in prepare_pages - * to avoid recursive lock - */ - if (unlikely(iov_iter_fault_in_readable(i, write_bytes))) { - ret = -EFAULT; - break; - } - - sector_offset = pos & (root->sectorsize - 1); - reserve_bytes = round_up(write_bytes + sector_offset, - root->sectorsize); - - ret = btrfs_check_data_free_space(inode, pos, write_bytes); - if (ret < 0) { - if ((BTRFS_I(inode)->flags & (BTRFS_INODE_NODATACOW | - BTRFS_INODE_PREALLOC)) && - check_can_nocow(inode, pos, &write_bytes) > 0) { - /* - * For nodata cow case, no need to reserve - * data space. - */ - only_release_metadata = true; - /* - * our prealloc extent may be smaller than - * write_bytes, so scale down. - */ - num_pages = DIV_ROUND_UP(write_bytes + offset, - PAGE_SIZE); - reserve_bytes = round_up(write_bytes + - sector_offset, - root->sectorsize); - } else { - break; - } - } - - ret = btrfs_delalloc_reserve_metadata(inode, reserve_bytes); - if (ret) { - if (!only_release_metadata) - btrfs_free_reserved_data_space(inode, pos, - write_bytes); - else - btrfs_end_write_no_snapshoting(root); - break; - } - - release_bytes = reserve_bytes; - need_unlock = false; -again: - /* - * This is going to setup the pages array with the number of - * pages we want, so we don't really need to worry about the - * contents of pages from loop to loop - */ - ret = prepare_pages(inode, pages, num_pages, - pos, write_bytes, - force_page_uptodate); - if (ret) - break; - - ret = lock_and_cleanup_extent_if_need(inode, pages, num_pages, - pos, write_bytes, &lockstart, - &lockend, &cached_state); - if (ret < 0) { - if (ret == -EAGAIN) - goto again; - break; - } else if (ret > 0) { - need_unlock = true; - ret = 0; - } - - copied = btrfs_copy_from_user(pos, write_bytes, pages, i); - - num_sectors = BTRFS_BYTES_TO_BLKS(root->fs_info, - reserve_bytes); - dirty_sectors = round_up(copied + sector_offset, - root->sectorsize); - dirty_sectors = BTRFS_BYTES_TO_BLKS(root->fs_info, - dirty_sectors); - - /* - * if we have trouble faulting in the pages, fall - * back to one page at a time - */ - if (copied < write_bytes) - nrptrs = 1; - - if (copied == 0) { - force_page_uptodate = true; - dirty_sectors = 0; - dirty_pages = 0; - } else { - force_page_uptodate = false; - dirty_pages = DIV_ROUND_UP(copied + offset, - PAGE_SIZE); - } - - /* - * If we had a short copy we need to release the excess delaloc - * bytes we reserved. We need to increment outstanding_extents - * because btrfs_delalloc_release_space and - * btrfs_delalloc_release_metadata will decrement it, but - * we still have an outstanding extent for the chunk we actually - * managed to copy. - */ - if (num_sectors > dirty_sectors) { - - /* release everything except the sectors we dirtied */ - release_bytes -= dirty_sectors << - root->fs_info->sb->s_blocksize_bits; - - if (copied > 0) { - spin_lock(&BTRFS_I(inode)->lock); - BTRFS_I(inode)->outstanding_extents++; - spin_unlock(&BTRFS_I(inode)->lock); - } - if (only_release_metadata) { - btrfs_delalloc_release_metadata(inode, - release_bytes); - } else { - u64 __pos; - - __pos = round_down(pos, root->sectorsize) + - (dirty_pages << PAGE_SHIFT); - btrfs_delalloc_release_space(inode, __pos, - release_bytes); - } - } - - release_bytes = round_up(copied + sector_offset, - root->sectorsize); - - if (copied > 0) - ret = btrfs_dirty_pages(root, inode, pages, - dirty_pages, pos, copied, - NULL); - if (need_unlock) - unlock_extent_cached(&BTRFS_I(inode)->io_tree, - lockstart, lockend, &cached_state, - GFP_NOFS); - if (ret) { - btrfs_drop_pages(pages, num_pages); - break; - } - - release_bytes = 0; - if (only_release_metadata) - btrfs_end_write_no_snapshoting(root); - - if (only_release_metadata && copied > 0) { - lockstart = round_down(pos, root->sectorsize); - lockend = round_up(pos + copied, root->sectorsize) - 1; - - set_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, - lockend, EXTENT_NORESERVE, NULL, - NULL, GFP_NOFS); - only_release_metadata = false; - } - - btrfs_drop_pages(pages, num_pages); - - cond_resched(); - - balance_dirty_pages_ratelimited(inode->i_mapping); - if (dirty_pages < (root->nodesize >> PAGE_SHIFT) + 1) - btrfs_btree_balance_dirty(root); - - pos += copied; - num_written += copied; - } - - kfree(pages); - - if (release_bytes) { - if (only_release_metadata) { - btrfs_end_write_no_snapshoting(root); - btrfs_delalloc_release_metadata(inode, release_bytes); - } else { - btrfs_delalloc_release_space(inode, - round_down(pos, root->sectorsize), - release_bytes); - } - } - - return num_written ? num_written : ret; -} - -static ssize_t __btrfs_direct_write(struct kiocb *iocb, struct iov_iter *from) -{ - struct file *file = iocb->ki_filp; - struct inode *inode = file_inode(file); - loff_t pos = iocb->ki_pos; - ssize_t written; - ssize_t written_buffered; - loff_t endbyte; - int err; - - written = generic_file_direct_write(iocb, from); - - if (written < 0 || !iov_iter_count(from)) - return written; - - pos += written; - written_buffered = __btrfs_buffered_write(file, from, pos); - if (written_buffered < 0) { - err = written_buffered; - goto out; - } - /* - * Ensure all data is persisted. We want the next direct IO read to be - * able to read what was just written. - */ - endbyte = pos + written_buffered - 1; - err = btrfs_fdatawrite_range(inode, pos, endbyte); - if (err) - goto out; - err = filemap_fdatawait_range(inode->i_mapping, pos, endbyte); - if (err) - goto out; - written += written_buffered; - iocb->ki_pos = pos + written_buffered; - invalidate_mapping_pages(file->f_mapping, pos >> PAGE_SHIFT, - endbyte >> PAGE_SHIFT); -out: - return written ? written : err; -} - -static void update_time_for_write(struct inode *inode) -{ - struct timespec now; - - if (IS_NOCMTIME(inode)) - return; - - now = current_time(inode); - if (!timespec_equal(&inode->i_mtime, &now)) - inode->i_mtime = now; - - if (!timespec_equal(&inode->i_ctime, &now)) - inode->i_ctime = now; - - if (IS_I_VERSION(inode)) - inode_inc_iversion(inode); -} - -static ssize_t btrfs_file_write_iter(struct kiocb *iocb, - struct iov_iter *from) -{ - struct file *file = iocb->ki_filp; - struct inode *inode = file_inode(file); - struct btrfs_root *root = BTRFS_I(inode)->root; - u64 start_pos; - u64 end_pos; - ssize_t num_written = 0; - bool sync = (file->f_flags & O_DSYNC) || IS_SYNC(file->f_mapping->host); - ssize_t err; - loff_t pos; - size_t count; - loff_t oldsize; - int clean_page = 0; - - inode_lock(inode); - err = generic_write_checks(iocb, from); - if (err <= 0) { - inode_unlock(inode); - return err; - } - - current->backing_dev_info = inode_to_bdi(inode); - err = file_remove_privs(file); - if (err) { - inode_unlock(inode); - goto out; - } - - /* - * If BTRFS flips readonly due to some impossible error - * (fs_info->fs_state now has BTRFS_SUPER_FLAG_ERROR), - * although we have opened a file as writable, we have - * to stop this write operation to ensure FS consistency. - */ - if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state)) { - inode_unlock(inode); - err = -EROFS; - goto out; - } - - /* - * We reserve space for updating the inode when we reserve space for the - * extent we are going to write, so we will enospc out there. We don't - * need to start yet another transaction to update the inode as we will - * update the inode when we finish writing whatever data we write. - */ - update_time_for_write(inode); - - pos = iocb->ki_pos; - count = iov_iter_count(from); - start_pos = round_down(pos, root->sectorsize); - oldsize = i_size_read(inode); - if (start_pos > oldsize) { - /* Expand hole size to cover write data, preventing empty gap */ - end_pos = round_up(pos + count, root->sectorsize); - err = btrfs_cont_expand(inode, oldsize, end_pos); - if (err) { - inode_unlock(inode); - goto out; - } - if (start_pos > round_up(oldsize, root->sectorsize)) - clean_page = 1; - } - - if (sync) - atomic_inc(&BTRFS_I(inode)->sync_writers); - - if (iocb->ki_flags & IOCB_DIRECT) { - num_written = __btrfs_direct_write(iocb, from); - } else { - num_written = __btrfs_buffered_write(file, from, pos); - if (num_written > 0) - iocb->ki_pos = pos + num_written; - if (clean_page) - pagecache_isize_extended(inode, oldsize, - i_size_read(inode)); - } - - inode_unlock(inode); - - /* - * We also have to set last_sub_trans to the current log transid, - * otherwise subsequent syncs to a file that's been synced in this - * transaction will appear to have already occurred. - */ - spin_lock(&BTRFS_I(inode)->lock); - BTRFS_I(inode)->last_sub_trans = root->log_transid; - spin_unlock(&BTRFS_I(inode)->lock); - if (num_written > 0) - num_written = generic_write_sync(iocb, num_written); - - if (sync) - atomic_dec(&BTRFS_I(inode)->sync_writers); -out: - current->backing_dev_info = NULL; - return num_written ? num_written : err; -} - -int btrfs_release_file(struct inode *inode, struct file *filp) -{ - if (filp->private_data) - btrfs_ioctl_trans_end(filp); - /* - * ordered_data_close is set by settattr when we are about to truncate - * a file from a non-zero size to a zero size. This tries to - * flush down new bytes that may have been written if the - * application were using truncate to replace a file in place. - */ - if (test_and_clear_bit(BTRFS_INODE_ORDERED_DATA_CLOSE, - &BTRFS_I(inode)->runtime_flags)) - filemap_flush(inode->i_mapping); - return 0; -} - -static int start_ordered_ops(struct inode *inode, loff_t start, loff_t end) -{ - int ret; - - atomic_inc(&BTRFS_I(inode)->sync_writers); - ret = btrfs_fdatawrite_range(inode, start, end); - atomic_dec(&BTRFS_I(inode)->sync_writers); - - return ret; -} - -/* - * fsync call for both files and directories. This logs the inode into - * the tree log instead of forcing full commits whenever possible. - * - * It needs to call filemap_fdatawait so that all ordered extent updates are - * in the metadata btree are up to date for copying to the log. - * - * It drops the inode mutex before doing the tree log commit. This is an - * important optimization for directories because holding the mutex prevents - * new operations on the dir while we write to disk. - */ -int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync) -{ - struct dentry *dentry = file_dentry(file); - struct inode *inode = d_inode(dentry); - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_trans_handle *trans; - struct btrfs_log_ctx ctx; - int ret = 0; - bool full_sync = 0; - u64 len; - - /* - * The range length can be represented by u64, we have to do the typecasts - * to avoid signed overflow if it's [0, LLONG_MAX] eg. from fsync() - */ - len = (u64)end - (u64)start + 1; - trace_btrfs_sync_file(file, datasync); - - /* - * We write the dirty pages in the range and wait until they complete - * out of the ->i_mutex. If so, we can flush the dirty pages by - * multi-task, and make the performance up. See - * btrfs_wait_ordered_range for an explanation of the ASYNC check. - */ - ret = start_ordered_ops(inode, start, end); - if (ret) - return ret; - - inode_lock(inode); - atomic_inc(&root->log_batch); - full_sync = test_bit(BTRFS_INODE_NEEDS_FULL_SYNC, - &BTRFS_I(inode)->runtime_flags); - /* - * We might have have had more pages made dirty after calling - * start_ordered_ops and before acquiring the inode's i_mutex. - */ - if (full_sync) { - /* - * For a full sync, we need to make sure any ordered operations - * start and finish before we start logging the inode, so that - * all extents are persisted and the respective file extent - * items are in the fs/subvol btree. - */ - ret = btrfs_wait_ordered_range(inode, start, len); - } else { - /* - * Start any new ordered operations before starting to log the - * inode. We will wait for them to finish in btrfs_sync_log(). - * - * Right before acquiring the inode's mutex, we might have new - * writes dirtying pages, which won't immediately start the - * respective ordered operations - that is done through the - * fill_delalloc callbacks invoked from the writepage and - * writepages address space operations. So make sure we start - * all ordered operations before starting to log our inode. Not - * doing this means that while logging the inode, writeback - * could start and invoke writepage/writepages, which would call - * the fill_delalloc callbacks (cow_file_range, - * submit_compressed_extents). These callbacks add first an - * extent map to the modified list of extents and then create - * the respective ordered operation, which means in - * tree-log.c:btrfs_log_inode() we might capture all existing - * ordered operations (with btrfs_get_logged_extents()) before - * the fill_delalloc callback adds its ordered operation, and by - * the time we visit the modified list of extent maps (with - * btrfs_log_changed_extents()), we see and process the extent - * map they created. We then use the extent map to construct a - * file extent item for logging without waiting for the - * respective ordered operation to finish - this file extent - * item points to a disk location that might not have yet been - * written to, containing random data - so after a crash a log - * replay will make our inode have file extent items that point - * to disk locations containing invalid data, as we returned - * success to userspace without waiting for the respective - * ordered operation to finish, because it wasn't captured by - * btrfs_get_logged_extents(). - */ - ret = start_ordered_ops(inode, start, end); - } - if (ret) { - inode_unlock(inode); - goto out; - } - atomic_inc(&root->log_batch); - - /* - * If the last transaction that changed this file was before the current - * transaction and we have the full sync flag set in our inode, we can - * bail out now without any syncing. - * - * Note that we can't bail out if the full sync flag isn't set. This is - * because when the full sync flag is set we start all ordered extents - * and wait for them to fully complete - when they complete they update - * the inode's last_trans field through: - * - * btrfs_finish_ordered_io() -> - * btrfs_update_inode_fallback() -> - * btrfs_update_inode() -> - * btrfs_set_inode_last_trans() - * - * So we are sure that last_trans is up to date and can do this check to - * bail out safely. For the fast path, when the full sync flag is not - * set in our inode, we can not do it because we start only our ordered - * extents and don't wait for them to complete (that is when - * btrfs_finish_ordered_io runs), so here at this point their last_trans - * value might be less than or equals to fs_info->last_trans_committed, - * and setting a speculative last_trans for an inode when a buffered - * write is made (such as fs_info->generation + 1 for example) would not - * be reliable since after setting the value and before fsync is called - * any number of transactions can start and commit (transaction kthread - * commits the current transaction periodically), and a transaction - * commit does not start nor waits for ordered extents to complete. - */ - smp_mb(); - if (btrfs_inode_in_log(inode, root->fs_info->generation) || - (full_sync && BTRFS_I(inode)->last_trans <= - root->fs_info->last_trans_committed) || - (!btrfs_have_ordered_extents_in_range(inode, start, len) && - BTRFS_I(inode)->last_trans - <= root->fs_info->last_trans_committed)) { - /* - * We've had everything committed since the last time we were - * modified so clear this flag in case it was set for whatever - * reason, it's no longer relevant. - */ - clear_bit(BTRFS_INODE_NEEDS_FULL_SYNC, - &BTRFS_I(inode)->runtime_flags); - /* - * An ordered extent might have started before and completed - * already with io errors, in which case the inode was not - * updated and we end up here. So check the inode's mapping - * flags for any errors that might have happened while doing - * writeback of file data. - */ - ret = filemap_check_errors(inode->i_mapping); - inode_unlock(inode); - goto out; - } - - /* - * ok we haven't committed the transaction yet, lets do a commit - */ - if (file->private_data) - btrfs_ioctl_trans_end(file); - - /* - * We use start here because we will need to wait on the IO to complete - * in btrfs_sync_log, which could require joining a transaction (for - * example checking cross references in the nocow path). If we use join - * here we could get into a situation where we're waiting on IO to - * happen that is blocked on a transaction trying to commit. With start - * we inc the extwriter counter, so we wait for all extwriters to exit - * before we start blocking join'ers. This comment is to keep somebody - * from thinking they are super smart and changing this to - * btrfs_join_transaction *cough*Josef*cough*. - */ - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - inode_unlock(inode); - goto out; - } - trans->sync = true; - - btrfs_init_log_ctx(&ctx, inode); - - ret = btrfs_log_dentry_safe(trans, root, dentry, start, end, &ctx); - if (ret < 0) { - /* Fallthrough and commit/free transaction. */ - ret = 1; - } - - /* we've logged all the items and now have a consistent - * version of the file in the log. It is possible that - * someone will come in and modify the file, but that's - * fine because the log is consistent on disk, and we - * have references to all of the file's extents - * - * It is possible that someone will come in and log the - * file again, but that will end up using the synchronization - * inside btrfs_sync_log to keep things safe. - */ - inode_unlock(inode); - - /* - * If any of the ordered extents had an error, just return it to user - * space, so that the application knows some writes didn't succeed and - * can take proper action (retry for e.g.). Blindly committing the - * transaction in this case, would fool userspace that everything was - * successful. And we also want to make sure our log doesn't contain - * file extent items pointing to extents that weren't fully written to - - * just like in the non fast fsync path, where we check for the ordered - * operation's error flag before writing to the log tree and return -EIO - * if any of them had this flag set (btrfs_wait_ordered_range) - - * therefore we need to check for errors in the ordered operations, - * which are indicated by ctx.io_err. - */ - if (ctx.io_err) { - btrfs_end_transaction(trans, root); - ret = ctx.io_err; - goto out; - } - - if (ret != BTRFS_NO_LOG_SYNC) { - if (!ret) { - ret = btrfs_sync_log(trans, root, &ctx); - if (!ret) { - ret = btrfs_end_transaction(trans, root); - goto out; - } - } - if (!full_sync) { - ret = btrfs_wait_ordered_range(inode, start, len); - if (ret) { - btrfs_end_transaction(trans, root); - goto out; - } - } - ret = btrfs_commit_transaction(trans, root); - } else { - ret = btrfs_end_transaction(trans, root); - } -out: - return ret > 0 ? -EIO : ret; -} - -static const struct vm_operations_struct btrfs_file_vm_ops = { - .fault = filemap_fault, - .map_pages = filemap_map_pages, - .page_mkwrite = btrfs_page_mkwrite, -}; - -static int btrfs_file_mmap(struct file *filp, struct vm_area_struct *vma) -{ - struct address_space *mapping = filp->f_mapping; - - if (!mapping->a_ops->readpage) - return -ENOEXEC; - - file_accessed(filp); - vma->vm_ops = &btrfs_file_vm_ops; - - return 0; -} - -static int hole_mergeable(struct inode *inode, struct extent_buffer *leaf, - int slot, u64 start, u64 end) -{ - struct btrfs_file_extent_item *fi; - struct btrfs_key key; - - if (slot < 0 || slot >= btrfs_header_nritems(leaf)) - return 0; - - btrfs_item_key_to_cpu(leaf, &key, slot); - if (key.objectid != btrfs_ino(inode) || - key.type != BTRFS_EXTENT_DATA_KEY) - return 0; - - fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); - - if (btrfs_file_extent_type(leaf, fi) != BTRFS_FILE_EXTENT_REG) - return 0; - - if (btrfs_file_extent_disk_bytenr(leaf, fi)) - return 0; - - if (key.offset == end) - return 1; - if (key.offset + btrfs_file_extent_num_bytes(leaf, fi) == start) - return 1; - return 0; -} - -static int fill_holes(struct btrfs_trans_handle *trans, struct inode *inode, - struct btrfs_path *path, u64 offset, u64 end) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct extent_buffer *leaf; - struct btrfs_file_extent_item *fi; - struct extent_map *hole_em; - struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; - struct btrfs_key key; - int ret; - - if (btrfs_fs_incompat(root->fs_info, NO_HOLES)) - goto out; - - key.objectid = btrfs_ino(inode); - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = offset; - - ret = btrfs_search_slot(trans, root, &key, path, 0, 1); - if (ret < 0) - return ret; - BUG_ON(!ret); - - leaf = path->nodes[0]; - if (hole_mergeable(inode, leaf, path->slots[0]-1, offset, end)) { - u64 num_bytes; - - path->slots[0]--; - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - num_bytes = btrfs_file_extent_num_bytes(leaf, fi) + - end - offset; - btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes); - btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes); - btrfs_set_file_extent_offset(leaf, fi, 0); - btrfs_mark_buffer_dirty(leaf); - goto out; - } - - if (hole_mergeable(inode, leaf, path->slots[0], offset, end)) { - u64 num_bytes; - - key.offset = offset; - btrfs_set_item_key_safe(root->fs_info, path, &key); - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - num_bytes = btrfs_file_extent_num_bytes(leaf, fi) + end - - offset; - btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes); - btrfs_set_file_extent_ram_bytes(leaf, fi, num_bytes); - btrfs_set_file_extent_offset(leaf, fi, 0); - btrfs_mark_buffer_dirty(leaf); - goto out; - } - btrfs_release_path(path); - - ret = btrfs_insert_file_extent(trans, root, btrfs_ino(inode), offset, - 0, 0, end - offset, 0, end - offset, - 0, 0, 0); - if (ret) - return ret; - -out: - btrfs_release_path(path); - - hole_em = alloc_extent_map(); - if (!hole_em) { - btrfs_drop_extent_cache(inode, offset, end - 1, 0); - set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, - &BTRFS_I(inode)->runtime_flags); - } else { - hole_em->start = offset; - hole_em->len = end - offset; - hole_em->ram_bytes = hole_em->len; - hole_em->orig_start = offset; - - hole_em->block_start = EXTENT_MAP_HOLE; - hole_em->block_len = 0; - hole_em->orig_block_len = 0; - hole_em->bdev = root->fs_info->fs_devices->latest_bdev; - hole_em->compress_type = BTRFS_COMPRESS_NONE; - hole_em->generation = trans->transid; - - do { - btrfs_drop_extent_cache(inode, offset, end - 1, 0); - write_lock(&em_tree->lock); - ret = add_extent_mapping(em_tree, hole_em, 1); - write_unlock(&em_tree->lock); - } while (ret == -EEXIST); - free_extent_map(hole_em); - if (ret) - set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, - &BTRFS_I(inode)->runtime_flags); - } - - return 0; -} - -/* - * Find a hole extent on given inode and change start/len to the end of hole - * extent.(hole/vacuum extent whose em->start <= start && - * em->start + em->len > start) - * When a hole extent is found, return 1 and modify start/len. - */ -static int find_first_non_hole(struct inode *inode, u64 *start, u64 *len) -{ - struct extent_map *em; - int ret = 0; - - em = btrfs_get_extent(inode, NULL, 0, *start, *len, 0); - if (IS_ERR_OR_NULL(em)) { - if (!em) - ret = -ENOMEM; - else - ret = PTR_ERR(em); - return ret; - } - - /* Hole or vacuum extent(only exists in no-hole mode) */ - if (em->block_start == EXTENT_MAP_HOLE) { - ret = 1; - *len = em->start + em->len > *start + *len ? - 0 : *start + *len - em->start - em->len; - *start = em->start + em->len; - } - free_extent_map(em); - return ret; -} - -static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct extent_state *cached_state = NULL; - struct btrfs_path *path; - struct btrfs_block_rsv *rsv; - struct btrfs_trans_handle *trans; - u64 lockstart; - u64 lockend; - u64 tail_start; - u64 tail_len; - u64 orig_start = offset; - u64 cur_offset; - u64 min_size = btrfs_calc_trunc_metadata_size(root, 1); - u64 drop_end; - int ret = 0; - int err = 0; - unsigned int rsv_count; - bool same_block; - bool no_holes = btrfs_fs_incompat(root->fs_info, NO_HOLES); - u64 ino_size; - bool truncated_block = false; - bool updated_inode = false; - - ret = btrfs_wait_ordered_range(inode, offset, len); - if (ret) - return ret; - - inode_lock(inode); - ino_size = round_up(inode->i_size, root->sectorsize); - ret = find_first_non_hole(inode, &offset, &len); - if (ret < 0) - goto out_only_mutex; - if (ret && !len) { - /* Already in a large hole */ - ret = 0; - goto out_only_mutex; - } - - lockstart = round_up(offset, BTRFS_I(inode)->root->sectorsize); - lockend = round_down(offset + len, - BTRFS_I(inode)->root->sectorsize) - 1; - same_block = (BTRFS_BYTES_TO_BLKS(root->fs_info, offset)) - == (BTRFS_BYTES_TO_BLKS(root->fs_info, offset + len - 1)); - /* - * We needn't truncate any block which is beyond the end of the file - * because we are sure there is no data there. - */ - /* - * Only do this if we are in the same block and we aren't doing the - * entire block. - */ - if (same_block && len < root->sectorsize) { - if (offset < ino_size) { - truncated_block = true; - ret = btrfs_truncate_block(inode, offset, len, 0); - } else { - ret = 0; - } - goto out_only_mutex; - } - - /* zero back part of the first block */ - if (offset < ino_size) { - truncated_block = true; - ret = btrfs_truncate_block(inode, offset, 0, 0); - if (ret) { - inode_unlock(inode); - return ret; - } - } - - /* Check the aligned pages after the first unaligned page, - * if offset != orig_start, which means the first unaligned page - * including several following pages are already in holes, - * the extra check can be skipped */ - if (offset == orig_start) { - /* after truncate page, check hole again */ - len = offset + len - lockstart; - offset = lockstart; - ret = find_first_non_hole(inode, &offset, &len); - if (ret < 0) - goto out_only_mutex; - if (ret && !len) { - ret = 0; - goto out_only_mutex; - } - lockstart = offset; - } - - /* Check the tail unaligned part is in a hole */ - tail_start = lockend + 1; - tail_len = offset + len - tail_start; - if (tail_len) { - ret = find_first_non_hole(inode, &tail_start, &tail_len); - if (unlikely(ret < 0)) - goto out_only_mutex; - if (!ret) { - /* zero the front end of the last page */ - if (tail_start + tail_len < ino_size) { - truncated_block = true; - ret = btrfs_truncate_block(inode, - tail_start + tail_len, - 0, 1); - if (ret) - goto out_only_mutex; - } - } - } - - if (lockend < lockstart) { - ret = 0; - goto out_only_mutex; - } - - while (1) { - struct btrfs_ordered_extent *ordered; - - truncate_pagecache_range(inode, lockstart, lockend); - - lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, - &cached_state); - ordered = btrfs_lookup_first_ordered_extent(inode, lockend); - - /* - * We need to make sure we have no ordered extents in this range - * and nobody raced in and read a page in this range, if we did - * we need to try again. - */ - if ((!ordered || - (ordered->file_offset + ordered->len <= lockstart || - ordered->file_offset > lockend)) && - !btrfs_page_exists_in_range(inode, lockstart, lockend)) { - if (ordered) - btrfs_put_ordered_extent(ordered); - break; - } - if (ordered) - btrfs_put_ordered_extent(ordered); - unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, - lockend, &cached_state, GFP_NOFS); - ret = btrfs_wait_ordered_range(inode, lockstart, - lockend - lockstart + 1); - if (ret) { - inode_unlock(inode); - return ret; - } - } - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - rsv = btrfs_alloc_block_rsv(root, BTRFS_BLOCK_RSV_TEMP); - if (!rsv) { - ret = -ENOMEM; - goto out_free; - } - rsv->size = btrfs_calc_trunc_metadata_size(root, 1); - rsv->failfast = 1; - - /* - * 1 - update the inode - * 1 - removing the extents in the range - * 1 - adding the hole extent if no_holes isn't set - */ - rsv_count = no_holes ? 2 : 3; - trans = btrfs_start_transaction(root, rsv_count); - if (IS_ERR(trans)) { - err = PTR_ERR(trans); - goto out_free; - } - - ret = btrfs_block_rsv_migrate(&root->fs_info->trans_block_rsv, rsv, - min_size, 0); - BUG_ON(ret); - trans->block_rsv = rsv; - - cur_offset = lockstart; - len = lockend - cur_offset; - while (cur_offset < lockend) { - ret = __btrfs_drop_extents(trans, root, inode, path, - cur_offset, lockend + 1, - &drop_end, 1, 0, 0, NULL); - if (ret != -ENOSPC) - break; - - trans->block_rsv = &root->fs_info->trans_block_rsv; - - if (cur_offset < ino_size) { - ret = fill_holes(trans, inode, path, cur_offset, - drop_end); - if (ret) { - err = ret; - break; - } - } - - cur_offset = drop_end; - - ret = btrfs_update_inode(trans, root, inode); - if (ret) { - err = ret; - break; - } - - btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(root); - - trans = btrfs_start_transaction(root, rsv_count); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - trans = NULL; - break; - } - - ret = btrfs_block_rsv_migrate(&root->fs_info->trans_block_rsv, - rsv, min_size, 0); - BUG_ON(ret); /* shouldn't happen */ - trans->block_rsv = rsv; - - ret = find_first_non_hole(inode, &cur_offset, &len); - if (unlikely(ret < 0)) - break; - if (ret && !len) { - ret = 0; - break; - } - } - - if (ret) { - err = ret; - goto out_trans; - } - - trans->block_rsv = &root->fs_info->trans_block_rsv; - /* - * If we are using the NO_HOLES feature we might have had already an - * hole that overlaps a part of the region [lockstart, lockend] and - * ends at (or beyond) lockend. Since we have no file extent items to - * represent holes, drop_end can be less than lockend and so we must - * make sure we have an extent map representing the existing hole (the - * call to __btrfs_drop_extents() might have dropped the existing extent - * map representing the existing hole), otherwise the fast fsync path - * will not record the existence of the hole region - * [existing_hole_start, lockend]. - */ - if (drop_end <= lockend) - drop_end = lockend + 1; - /* - * Don't insert file hole extent item if it's for a range beyond eof - * (because it's useless) or if it represents a 0 bytes range (when - * cur_offset == drop_end). - */ - if (cur_offset < ino_size && cur_offset < drop_end) { - ret = fill_holes(trans, inode, path, cur_offset, drop_end); - if (ret) { - err = ret; - goto out_trans; - } - } - -out_trans: - if (!trans) - goto out_free; - - inode_inc_iversion(inode); - inode->i_mtime = inode->i_ctime = current_time(inode); - - trans->block_rsv = &root->fs_info->trans_block_rsv; - ret = btrfs_update_inode(trans, root, inode); - updated_inode = true; - btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(root); -out_free: - btrfs_free_path(path); - btrfs_free_block_rsv(root, rsv); -out: - unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend, - &cached_state, GFP_NOFS); -out_only_mutex: - if (!updated_inode && truncated_block && !ret && !err) { - /* - * If we only end up zeroing part of a page, we still need to - * update the inode item, so that all the time fields are - * updated as well as the necessary btrfs inode in memory fields - * for detecting, at fsync time, if the inode isn't yet in the - * log tree or it's there but not up to date. - */ - trans = btrfs_start_transaction(root, 1); - if (IS_ERR(trans)) { - err = PTR_ERR(trans); - } else { - err = btrfs_update_inode(trans, root, inode); - ret = btrfs_end_transaction(trans, root); - } - } - inode_unlock(inode); - if (ret && !err) - err = ret; - return err; -} - -/* Helper structure to record which range is already reserved */ -struct falloc_range { - struct list_head list; - u64 start; - u64 len; -}; - -/* - * Helper function to add falloc range - * - * Caller should have locked the larger range of extent containing - * [start, len) - */ -static int add_falloc_range(struct list_head *head, u64 start, u64 len) -{ - struct falloc_range *prev = NULL; - struct falloc_range *range = NULL; - - if (list_empty(head)) - goto insert; - - /* - * As fallocate iterate by bytenr order, we only need to check - * the last range. - */ - prev = list_entry(head->prev, struct falloc_range, list); - if (prev->start + prev->len == start) { - prev->len += len; - return 0; - } -insert: - range = kmalloc(sizeof(*range), GFP_KERNEL); - if (!range) - return -ENOMEM; - range->start = start; - range->len = len; - list_add_tail(&range->list, head); - return 0; -} - -static long btrfs_fallocate(struct file *file, int mode, - loff_t offset, loff_t len) -{ - struct inode *inode = file_inode(file); - struct extent_state *cached_state = NULL; - struct falloc_range *range; - struct falloc_range *tmp; - struct list_head reserve_list; - u64 cur_offset; - u64 last_byte; - u64 alloc_start; - u64 alloc_end; - u64 alloc_hint = 0; - u64 locked_end; - u64 actual_end = 0; - struct extent_map *em; - int blocksize = BTRFS_I(inode)->root->sectorsize; - int ret; - - alloc_start = round_down(offset, blocksize); - alloc_end = round_up(offset + len, blocksize); - cur_offset = alloc_start; - - /* Make sure we aren't being give some crap mode */ - if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) - return -EOPNOTSUPP; - - if (mode & FALLOC_FL_PUNCH_HOLE) - return btrfs_punch_hole(inode, offset, len); - - /* - * Only trigger disk allocation, don't trigger qgroup reserve - * - * For qgroup space, it will be checked later. - */ - ret = btrfs_alloc_data_chunk_ondemand(inode, alloc_end - alloc_start); - if (ret < 0) - return ret; - - inode_lock(inode); - - if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > inode->i_size) { - ret = inode_newsize_ok(inode, offset + len); - if (ret) - goto out; - } - - /* - * TODO: Move these two operations after we have checked - * accurate reserved space, or fallocate can still fail but - * with page truncated or size expanded. - * - * But that's a minor problem and won't do much harm BTW. - */ - if (alloc_start > inode->i_size) { - ret = btrfs_cont_expand(inode, i_size_read(inode), - alloc_start); - if (ret) - goto out; - } else if (offset + len > inode->i_size) { - /* - * If we are fallocating from the end of the file onward we - * need to zero out the end of the block if i_size lands in the - * middle of a block. - */ - ret = btrfs_truncate_block(inode, inode->i_size, 0, 0); - if (ret) - goto out; - } - - /* - * wait for ordered IO before we have any locks. We'll loop again - * below with the locks held. - */ - ret = btrfs_wait_ordered_range(inode, alloc_start, - alloc_end - alloc_start); - if (ret) - goto out; - - locked_end = alloc_end - 1; - while (1) { - struct btrfs_ordered_extent *ordered; - - /* the extent lock is ordered inside the running - * transaction - */ - lock_extent_bits(&BTRFS_I(inode)->io_tree, alloc_start, - locked_end, &cached_state); - ordered = btrfs_lookup_first_ordered_extent(inode, - alloc_end - 1); - if (ordered && - ordered->file_offset + ordered->len > alloc_start && - ordered->file_offset < alloc_end) { - btrfs_put_ordered_extent(ordered); - unlock_extent_cached(&BTRFS_I(inode)->io_tree, - alloc_start, locked_end, - &cached_state, GFP_KERNEL); - /* - * we can't wait on the range with the transaction - * running or with the extent lock held - */ - ret = btrfs_wait_ordered_range(inode, alloc_start, - alloc_end - alloc_start); - if (ret) - goto out; - } else { - if (ordered) - btrfs_put_ordered_extent(ordered); - break; - } - } - - /* First, check if we exceed the qgroup limit */ - INIT_LIST_HEAD(&reserve_list); - while (1) { - em = btrfs_get_extent(inode, NULL, 0, cur_offset, - alloc_end - cur_offset, 0); - if (IS_ERR_OR_NULL(em)) { - if (!em) - ret = -ENOMEM; - else - ret = PTR_ERR(em); - break; - } - last_byte = min(extent_map_end(em), alloc_end); - actual_end = min_t(u64, extent_map_end(em), offset + len); - last_byte = ALIGN(last_byte, blocksize); - if (em->block_start == EXTENT_MAP_HOLE || - (cur_offset >= inode->i_size && - !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) { - ret = add_falloc_range(&reserve_list, cur_offset, - last_byte - cur_offset); - if (ret < 0) { - free_extent_map(em); - break; - } - ret = btrfs_qgroup_reserve_data(inode, cur_offset, - last_byte - cur_offset); - if (ret < 0) - break; - } else { - /* - * Do not need to reserve unwritten extent for this - * range, free reserved data space first, otherwise - * it'll result in false ENOSPC error. - */ - btrfs_free_reserved_data_space(inode, cur_offset, - last_byte - cur_offset); - } - free_extent_map(em); - cur_offset = last_byte; - if (cur_offset >= alloc_end) - break; - } - - /* - * If ret is still 0, means we're OK to fallocate. - * Or just cleanup the list and exit. - */ - list_for_each_entry_safe(range, tmp, &reserve_list, list) { - if (!ret) - ret = btrfs_prealloc_file_range(inode, mode, - range->start, - range->len, 1 << inode->i_blkbits, - offset + len, &alloc_hint); - else - btrfs_free_reserved_data_space(inode, range->start, - range->len); - list_del(&range->list); - kfree(range); - } - if (ret < 0) - goto out_unlock; - - if (actual_end > inode->i_size && - !(mode & FALLOC_FL_KEEP_SIZE)) { - struct btrfs_trans_handle *trans; - struct btrfs_root *root = BTRFS_I(inode)->root; - - /* - * We didn't need to allocate any more space, but we - * still extended the size of the file so we need to - * update i_size and the inode item. - */ - trans = btrfs_start_transaction(root, 1); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - } else { - inode->i_ctime = current_time(inode); - i_size_write(inode, actual_end); - btrfs_ordered_update_i_size(inode, actual_end, NULL); - ret = btrfs_update_inode(trans, root, inode); - if (ret) - btrfs_end_transaction(trans, root); - else - ret = btrfs_end_transaction(trans, root); - } - } -out_unlock: - unlock_extent_cached(&BTRFS_I(inode)->io_tree, alloc_start, locked_end, - &cached_state, GFP_KERNEL); -out: - inode_unlock(inode); - /* Let go of our reservation. */ - if (ret != 0) - btrfs_free_reserved_data_space(inode, alloc_start, - alloc_end - cur_offset); - return ret; -} - -static int find_desired_extent(struct inode *inode, loff_t *offset, int whence) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct extent_map *em = NULL; - struct extent_state *cached_state = NULL; - u64 lockstart; - u64 lockend; - u64 start; - u64 len; - int ret = 0; - - if (inode->i_size == 0) - return -ENXIO; - - /* - * *offset can be negative, in this case we start finding DATA/HOLE from - * the very start of the file. - */ - start = max_t(loff_t, 0, *offset); - - lockstart = round_down(start, root->sectorsize); - lockend = round_up(i_size_read(inode), root->sectorsize); - if (lockend <= lockstart) - lockend = lockstart + root->sectorsize; - lockend--; - len = lockend - lockstart + 1; - - lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, - &cached_state); - - while (start < inode->i_size) { - em = btrfs_get_extent_fiemap(inode, NULL, 0, start, len, 0); - if (IS_ERR(em)) { - ret = PTR_ERR(em); - em = NULL; - break; - } - - if (whence == SEEK_HOLE && - (em->block_start == EXTENT_MAP_HOLE || - test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) - break; - else if (whence == SEEK_DATA && - (em->block_start != EXTENT_MAP_HOLE && - !test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) - break; - - start = em->start + em->len; - free_extent_map(em); - em = NULL; - cond_resched(); - } - free_extent_map(em); - if (!ret) { - if (whence == SEEK_DATA && start >= inode->i_size) - ret = -ENXIO; - else - *offset = min_t(loff_t, start, inode->i_size); - } - unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend, - &cached_state, GFP_NOFS); - return ret; -} - -static loff_t btrfs_file_llseek(struct file *file, loff_t offset, int whence) -{ - struct inode *inode = file->f_mapping->host; - int ret; - - inode_lock(inode); - switch (whence) { - case SEEK_END: - case SEEK_CUR: - offset = generic_file_llseek(file, offset, whence); - goto out; - case SEEK_DATA: - case SEEK_HOLE: - if (offset >= i_size_read(inode)) { - inode_unlock(inode); - return -ENXIO; - } - - ret = find_desired_extent(inode, &offset, whence); - if (ret) { - inode_unlock(inode); - return ret; - } - } - - offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes); -out: - inode_unlock(inode); - return offset; -} - -const struct file_operations btrfs_file_operations = { - .llseek = btrfs_file_llseek, - .read_iter = generic_file_read_iter, - .splice_read = generic_file_splice_read, - .write_iter = btrfs_file_write_iter, - .mmap = btrfs_file_mmap, - .open = generic_file_open, - .release = btrfs_release_file, - .fsync = btrfs_sync_file, - .fallocate = btrfs_fallocate, - .unlocked_ioctl = btrfs_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = btrfs_compat_ioctl, -#endif - .copy_file_range = btrfs_copy_file_range, - .clone_file_range = btrfs_clone_file_range, - .dedupe_file_range = btrfs_dedupe_file_range, -}; - -void btrfs_auto_defrag_exit(void) -{ - kmem_cache_destroy(btrfs_inode_defrag_cachep); -} - -int btrfs_auto_defrag_init(void) -{ - btrfs_inode_defrag_cachep = kmem_cache_create("btrfs_inode_defrag", - sizeof(struct inode_defrag), 0, - SLAB_MEM_SPREAD, - NULL); - if (!btrfs_inode_defrag_cachep) - return -ENOMEM; - - return 0; -} - -int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end) -{ - int ret; - - /* - * So with compression we will find and lock a dirty page and clear the - * first one as dirty, setup an async extent, and immediately return - * with the entire range locked but with nobody actually marked with - * writeback. So we can't just filemap_write_and_wait_range() and - * expect it to work since it will just kick off a thread to do the - * actual work. So we need to call filemap_fdatawrite_range _again_ - * since it will wait on the page lock, which won't be unlocked until - * after the pages have been marked as writeback and so we're good to go - * from there. We have to do this otherwise we'll miss the ordered - * extents and that results in badness. Please Josef, do not think you - * know better and pull this out at some point in the future, it is - * right and you are wrong. - */ - ret = filemap_fdatawrite_range(inode->i_mapping, start, end); - if (!ret && test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT, - &BTRFS_I(inode)->runtime_flags)) - ret = filemap_fdatawrite_range(inode->i_mapping, start, end); - - return ret; -} diff --git a/src/linux/fs/btrfs/free-space-cache.c b/src/linux/fs/btrfs/free-space-cache.c deleted file mode 100644 index e4b48f3..0000000 --- a/src/linux/fs/btrfs/free-space-cache.c +++ /dev/null @@ -1,3704 +0,0 @@ -/* - * Copyright (C) 2008 Red Hat. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include -#include "ctree.h" -#include "free-space-cache.h" -#include "transaction.h" -#include "disk-io.h" -#include "extent_io.h" -#include "inode-map.h" -#include "volumes.h" - -#define BITS_PER_BITMAP (PAGE_SIZE * 8UL) -#define MAX_CACHE_BYTES_PER_GIG SZ_32K - -struct btrfs_trim_range { - u64 start; - u64 bytes; - struct list_head list; -}; - -static int link_free_space(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info); -static void unlink_free_space(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info); - -static struct inode *__lookup_free_space_inode(struct btrfs_root *root, - struct btrfs_path *path, - u64 offset) -{ - struct btrfs_key key; - struct btrfs_key location; - struct btrfs_disk_key disk_key; - struct btrfs_free_space_header *header; - struct extent_buffer *leaf; - struct inode *inode = NULL; - int ret; - - key.objectid = BTRFS_FREE_SPACE_OBJECTID; - key.offset = offset; - key.type = 0; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - return ERR_PTR(ret); - if (ret > 0) { - btrfs_release_path(path); - return ERR_PTR(-ENOENT); - } - - leaf = path->nodes[0]; - header = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_free_space_header); - btrfs_free_space_key(leaf, header, &disk_key); - btrfs_disk_key_to_cpu(&location, &disk_key); - btrfs_release_path(path); - - inode = btrfs_iget(root->fs_info->sb, &location, root, NULL); - if (!inode) - return ERR_PTR(-ENOENT); - if (IS_ERR(inode)) - return inode; - if (is_bad_inode(inode)) { - iput(inode); - return ERR_PTR(-ENOENT); - } - - mapping_set_gfp_mask(inode->i_mapping, - mapping_gfp_constraint(inode->i_mapping, - ~(__GFP_FS | __GFP_HIGHMEM))); - - return inode; -} - -struct inode *lookup_free_space_inode(struct btrfs_root *root, - struct btrfs_block_group_cache - *block_group, struct btrfs_path *path) -{ - struct inode *inode = NULL; - u32 flags = BTRFS_INODE_NODATASUM | BTRFS_INODE_NODATACOW; - - spin_lock(&block_group->lock); - if (block_group->inode) - inode = igrab(block_group->inode); - spin_unlock(&block_group->lock); - if (inode) - return inode; - - inode = __lookup_free_space_inode(root, path, - block_group->key.objectid); - if (IS_ERR(inode)) - return inode; - - spin_lock(&block_group->lock); - if (!((BTRFS_I(inode)->flags & flags) == flags)) { - btrfs_info(root->fs_info, - "Old style space inode found, converting."); - BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM | - BTRFS_INODE_NODATACOW; - block_group->disk_cache_state = BTRFS_DC_CLEAR; - } - - if (!block_group->iref) { - block_group->inode = igrab(inode); - block_group->iref = 1; - } - spin_unlock(&block_group->lock); - - return inode; -} - -static int __create_free_space_inode(struct btrfs_root *root, - struct btrfs_trans_handle *trans, - struct btrfs_path *path, - u64 ino, u64 offset) -{ - struct btrfs_key key; - struct btrfs_disk_key disk_key; - struct btrfs_free_space_header *header; - struct btrfs_inode_item *inode_item; - struct extent_buffer *leaf; - u64 flags = BTRFS_INODE_NOCOMPRESS | BTRFS_INODE_PREALLOC; - int ret; - - ret = btrfs_insert_empty_inode(trans, root, path, ino); - if (ret) - return ret; - - /* We inline crc's for the free disk space cache */ - if (ino != BTRFS_FREE_INO_OBJECTID) - flags |= BTRFS_INODE_NODATASUM | BTRFS_INODE_NODATACOW; - - leaf = path->nodes[0]; - inode_item = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_inode_item); - btrfs_item_key(leaf, &disk_key, path->slots[0]); - memset_extent_buffer(leaf, 0, (unsigned long)inode_item, - sizeof(*inode_item)); - btrfs_set_inode_generation(leaf, inode_item, trans->transid); - btrfs_set_inode_size(leaf, inode_item, 0); - btrfs_set_inode_nbytes(leaf, inode_item, 0); - btrfs_set_inode_uid(leaf, inode_item, 0); - btrfs_set_inode_gid(leaf, inode_item, 0); - btrfs_set_inode_mode(leaf, inode_item, S_IFREG | 0600); - btrfs_set_inode_flags(leaf, inode_item, flags); - btrfs_set_inode_nlink(leaf, inode_item, 1); - btrfs_set_inode_transid(leaf, inode_item, trans->transid); - btrfs_set_inode_block_group(leaf, inode_item, offset); - btrfs_mark_buffer_dirty(leaf); - btrfs_release_path(path); - - key.objectid = BTRFS_FREE_SPACE_OBJECTID; - key.offset = offset; - key.type = 0; - ret = btrfs_insert_empty_item(trans, root, path, &key, - sizeof(struct btrfs_free_space_header)); - if (ret < 0) { - btrfs_release_path(path); - return ret; - } - - leaf = path->nodes[0]; - header = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_free_space_header); - memset_extent_buffer(leaf, 0, (unsigned long)header, sizeof(*header)); - btrfs_set_free_space_key(leaf, header, &disk_key); - btrfs_mark_buffer_dirty(leaf); - btrfs_release_path(path); - - return 0; -} - -int create_free_space_inode(struct btrfs_root *root, - struct btrfs_trans_handle *trans, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path) -{ - int ret; - u64 ino; - - ret = btrfs_find_free_objectid(root, &ino); - if (ret < 0) - return ret; - - return __create_free_space_inode(root, trans, path, ino, - block_group->key.objectid); -} - -int btrfs_check_trunc_cache_free_space(struct btrfs_root *root, - struct btrfs_block_rsv *rsv) -{ - u64 needed_bytes; - int ret; - - /* 1 for slack space, 1 for updating the inode */ - needed_bytes = btrfs_calc_trunc_metadata_size(root, 1) + - btrfs_calc_trans_metadata_size(root, 1); - - spin_lock(&rsv->lock); - if (rsv->reserved < needed_bytes) - ret = -ENOSPC; - else - ret = 0; - spin_unlock(&rsv->lock); - return ret; -} - -int btrfs_truncate_free_space_cache(struct btrfs_root *root, - struct btrfs_trans_handle *trans, - struct btrfs_block_group_cache *block_group, - struct inode *inode) -{ - int ret = 0; - struct btrfs_path *path = btrfs_alloc_path(); - bool locked = false; - - if (!path) { - ret = -ENOMEM; - goto fail; - } - - if (block_group) { - locked = true; - mutex_lock(&trans->transaction->cache_write_mutex); - if (!list_empty(&block_group->io_list)) { - list_del_init(&block_group->io_list); - - btrfs_wait_cache_io(root, trans, block_group, - &block_group->io_ctl, path, - block_group->key.objectid); - btrfs_put_block_group(block_group); - } - - /* - * now that we've truncated the cache away, its no longer - * setup or written - */ - spin_lock(&block_group->lock); - block_group->disk_cache_state = BTRFS_DC_CLEAR; - spin_unlock(&block_group->lock); - } - btrfs_free_path(path); - - btrfs_i_size_write(inode, 0); - truncate_pagecache(inode, 0); - - /* - * We don't need an orphan item because truncating the free space cache - * will never be split across transactions. - * We don't need to check for -EAGAIN because we're a free space - * cache inode - */ - ret = btrfs_truncate_inode_items(trans, root, inode, - 0, BTRFS_EXTENT_DATA_KEY); - if (ret) - goto fail; - - ret = btrfs_update_inode(trans, root, inode); - -fail: - if (locked) - mutex_unlock(&trans->transaction->cache_write_mutex); - if (ret) - btrfs_abort_transaction(trans, ret); - - return ret; -} - -static int readahead_cache(struct inode *inode) -{ - struct file_ra_state *ra; - unsigned long last_index; - - ra = kzalloc(sizeof(*ra), GFP_NOFS); - if (!ra) - return -ENOMEM; - - file_ra_state_init(ra, inode->i_mapping); - last_index = (i_size_read(inode) - 1) >> PAGE_SHIFT; - - page_cache_sync_readahead(inode->i_mapping, ra, NULL, 0, last_index); - - kfree(ra); - - return 0; -} - -static int io_ctl_init(struct btrfs_io_ctl *io_ctl, struct inode *inode, - struct btrfs_root *root, int write) -{ - int num_pages; - int check_crcs = 0; - - num_pages = DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE); - - if (btrfs_ino(inode) != BTRFS_FREE_INO_OBJECTID) - check_crcs = 1; - - /* Make sure we can fit our crcs into the first page */ - if (write && check_crcs && - (num_pages * sizeof(u32)) >= PAGE_SIZE) - return -ENOSPC; - - memset(io_ctl, 0, sizeof(struct btrfs_io_ctl)); - - io_ctl->pages = kcalloc(num_pages, sizeof(struct page *), GFP_NOFS); - if (!io_ctl->pages) - return -ENOMEM; - - io_ctl->num_pages = num_pages; - io_ctl->root = root; - io_ctl->check_crcs = check_crcs; - io_ctl->inode = inode; - - return 0; -} - -static void io_ctl_free(struct btrfs_io_ctl *io_ctl) -{ - kfree(io_ctl->pages); - io_ctl->pages = NULL; -} - -static void io_ctl_unmap_page(struct btrfs_io_ctl *io_ctl) -{ - if (io_ctl->cur) { - io_ctl->cur = NULL; - io_ctl->orig = NULL; - } -} - -static void io_ctl_map_page(struct btrfs_io_ctl *io_ctl, int clear) -{ - ASSERT(io_ctl->index < io_ctl->num_pages); - io_ctl->page = io_ctl->pages[io_ctl->index++]; - io_ctl->cur = page_address(io_ctl->page); - io_ctl->orig = io_ctl->cur; - io_ctl->size = PAGE_SIZE; - if (clear) - memset(io_ctl->cur, 0, PAGE_SIZE); -} - -static void io_ctl_drop_pages(struct btrfs_io_ctl *io_ctl) -{ - int i; - - io_ctl_unmap_page(io_ctl); - - for (i = 0; i < io_ctl->num_pages; i++) { - if (io_ctl->pages[i]) { - ClearPageChecked(io_ctl->pages[i]); - unlock_page(io_ctl->pages[i]); - put_page(io_ctl->pages[i]); - } - } -} - -static int io_ctl_prepare_pages(struct btrfs_io_ctl *io_ctl, struct inode *inode, - int uptodate) -{ - struct page *page; - gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping); - int i; - - for (i = 0; i < io_ctl->num_pages; i++) { - page = find_or_create_page(inode->i_mapping, i, mask); - if (!page) { - io_ctl_drop_pages(io_ctl); - return -ENOMEM; - } - io_ctl->pages[i] = page; - if (uptodate && !PageUptodate(page)) { - btrfs_readpage(NULL, page); - lock_page(page); - if (!PageUptodate(page)) { - btrfs_err(BTRFS_I(inode)->root->fs_info, - "error reading free space cache"); - io_ctl_drop_pages(io_ctl); - return -EIO; - } - } - } - - for (i = 0; i < io_ctl->num_pages; i++) { - clear_page_dirty_for_io(io_ctl->pages[i]); - set_page_extent_mapped(io_ctl->pages[i]); - } - - return 0; -} - -static void io_ctl_set_generation(struct btrfs_io_ctl *io_ctl, u64 generation) -{ - __le64 *val; - - io_ctl_map_page(io_ctl, 1); - - /* - * Skip the csum areas. If we don't check crcs then we just have a - * 64bit chunk at the front of the first page. - */ - if (io_ctl->check_crcs) { - io_ctl->cur += (sizeof(u32) * io_ctl->num_pages); - io_ctl->size -= sizeof(u64) + (sizeof(u32) * io_ctl->num_pages); - } else { - io_ctl->cur += sizeof(u64); - io_ctl->size -= sizeof(u64) * 2; - } - - val = io_ctl->cur; - *val = cpu_to_le64(generation); - io_ctl->cur += sizeof(u64); -} - -static int io_ctl_check_generation(struct btrfs_io_ctl *io_ctl, u64 generation) -{ - __le64 *gen; - - /* - * Skip the crc area. If we don't check crcs then we just have a 64bit - * chunk at the front of the first page. - */ - if (io_ctl->check_crcs) { - io_ctl->cur += sizeof(u32) * io_ctl->num_pages; - io_ctl->size -= sizeof(u64) + - (sizeof(u32) * io_ctl->num_pages); - } else { - io_ctl->cur += sizeof(u64); - io_ctl->size -= sizeof(u64) * 2; - } - - gen = io_ctl->cur; - if (le64_to_cpu(*gen) != generation) { - btrfs_err_rl(io_ctl->root->fs_info, - "space cache generation (%llu) does not match inode (%llu)", - *gen, generation); - io_ctl_unmap_page(io_ctl); - return -EIO; - } - io_ctl->cur += sizeof(u64); - return 0; -} - -static void io_ctl_set_crc(struct btrfs_io_ctl *io_ctl, int index) -{ - u32 *tmp; - u32 crc = ~(u32)0; - unsigned offset = 0; - - if (!io_ctl->check_crcs) { - io_ctl_unmap_page(io_ctl); - return; - } - - if (index == 0) - offset = sizeof(u32) * io_ctl->num_pages; - - crc = btrfs_csum_data(io_ctl->orig + offset, crc, - PAGE_SIZE - offset); - btrfs_csum_final(crc, (char *)&crc); - io_ctl_unmap_page(io_ctl); - tmp = page_address(io_ctl->pages[0]); - tmp += index; - *tmp = crc; -} - -static int io_ctl_check_crc(struct btrfs_io_ctl *io_ctl, int index) -{ - u32 *tmp, val; - u32 crc = ~(u32)0; - unsigned offset = 0; - - if (!io_ctl->check_crcs) { - io_ctl_map_page(io_ctl, 0); - return 0; - } - - if (index == 0) - offset = sizeof(u32) * io_ctl->num_pages; - - tmp = page_address(io_ctl->pages[0]); - tmp += index; - val = *tmp; - - io_ctl_map_page(io_ctl, 0); - crc = btrfs_csum_data(io_ctl->orig + offset, crc, - PAGE_SIZE - offset); - btrfs_csum_final(crc, (char *)&crc); - if (val != crc) { - btrfs_err_rl(io_ctl->root->fs_info, - "csum mismatch on free space cache"); - io_ctl_unmap_page(io_ctl); - return -EIO; - } - - return 0; -} - -static int io_ctl_add_entry(struct btrfs_io_ctl *io_ctl, u64 offset, u64 bytes, - void *bitmap) -{ - struct btrfs_free_space_entry *entry; - - if (!io_ctl->cur) - return -ENOSPC; - - entry = io_ctl->cur; - entry->offset = cpu_to_le64(offset); - entry->bytes = cpu_to_le64(bytes); - entry->type = (bitmap) ? BTRFS_FREE_SPACE_BITMAP : - BTRFS_FREE_SPACE_EXTENT; - io_ctl->cur += sizeof(struct btrfs_free_space_entry); - io_ctl->size -= sizeof(struct btrfs_free_space_entry); - - if (io_ctl->size >= sizeof(struct btrfs_free_space_entry)) - return 0; - - io_ctl_set_crc(io_ctl, io_ctl->index - 1); - - /* No more pages to map */ - if (io_ctl->index >= io_ctl->num_pages) - return 0; - - /* map the next page */ - io_ctl_map_page(io_ctl, 1); - return 0; -} - -static int io_ctl_add_bitmap(struct btrfs_io_ctl *io_ctl, void *bitmap) -{ - if (!io_ctl->cur) - return -ENOSPC; - - /* - * If we aren't at the start of the current page, unmap this one and - * map the next one if there is any left. - */ - if (io_ctl->cur != io_ctl->orig) { - io_ctl_set_crc(io_ctl, io_ctl->index - 1); - if (io_ctl->index >= io_ctl->num_pages) - return -ENOSPC; - io_ctl_map_page(io_ctl, 0); - } - - memcpy(io_ctl->cur, bitmap, PAGE_SIZE); - io_ctl_set_crc(io_ctl, io_ctl->index - 1); - if (io_ctl->index < io_ctl->num_pages) - io_ctl_map_page(io_ctl, 0); - return 0; -} - -static void io_ctl_zero_remaining_pages(struct btrfs_io_ctl *io_ctl) -{ - /* - * If we're not on the boundary we know we've modified the page and we - * need to crc the page. - */ - if (io_ctl->cur != io_ctl->orig) - io_ctl_set_crc(io_ctl, io_ctl->index - 1); - else - io_ctl_unmap_page(io_ctl); - - while (io_ctl->index < io_ctl->num_pages) { - io_ctl_map_page(io_ctl, 1); - io_ctl_set_crc(io_ctl, io_ctl->index - 1); - } -} - -static int io_ctl_read_entry(struct btrfs_io_ctl *io_ctl, - struct btrfs_free_space *entry, u8 *type) -{ - struct btrfs_free_space_entry *e; - int ret; - - if (!io_ctl->cur) { - ret = io_ctl_check_crc(io_ctl, io_ctl->index); - if (ret) - return ret; - } - - e = io_ctl->cur; - entry->offset = le64_to_cpu(e->offset); - entry->bytes = le64_to_cpu(e->bytes); - *type = e->type; - io_ctl->cur += sizeof(struct btrfs_free_space_entry); - io_ctl->size -= sizeof(struct btrfs_free_space_entry); - - if (io_ctl->size >= sizeof(struct btrfs_free_space_entry)) - return 0; - - io_ctl_unmap_page(io_ctl); - - return 0; -} - -static int io_ctl_read_bitmap(struct btrfs_io_ctl *io_ctl, - struct btrfs_free_space *entry) -{ - int ret; - - ret = io_ctl_check_crc(io_ctl, io_ctl->index); - if (ret) - return ret; - - memcpy(entry->bitmap, io_ctl->cur, PAGE_SIZE); - io_ctl_unmap_page(io_ctl); - - return 0; -} - -/* - * Since we attach pinned extents after the fact we can have contiguous sections - * of free space that are split up in entries. This poses a problem with the - * tree logging stuff since it could have allocated across what appears to be 2 - * entries since we would have merged the entries when adding the pinned extents - * back to the free space cache. So run through the space cache that we just - * loaded and merge contiguous entries. This will make the log replay stuff not - * blow up and it will make for nicer allocator behavior. - */ -static void merge_space_tree(struct btrfs_free_space_ctl *ctl) -{ - struct btrfs_free_space *e, *prev = NULL; - struct rb_node *n; - -again: - spin_lock(&ctl->tree_lock); - for (n = rb_first(&ctl->free_space_offset); n; n = rb_next(n)) { - e = rb_entry(n, struct btrfs_free_space, offset_index); - if (!prev) - goto next; - if (e->bitmap || prev->bitmap) - goto next; - if (prev->offset + prev->bytes == e->offset) { - unlink_free_space(ctl, prev); - unlink_free_space(ctl, e); - prev->bytes += e->bytes; - kmem_cache_free(btrfs_free_space_cachep, e); - link_free_space(ctl, prev); - prev = NULL; - spin_unlock(&ctl->tree_lock); - goto again; - } -next: - prev = e; - } - spin_unlock(&ctl->tree_lock); -} - -static int __load_free_space_cache(struct btrfs_root *root, struct inode *inode, - struct btrfs_free_space_ctl *ctl, - struct btrfs_path *path, u64 offset) -{ - struct btrfs_free_space_header *header; - struct extent_buffer *leaf; - struct btrfs_io_ctl io_ctl; - struct btrfs_key key; - struct btrfs_free_space *e, *n; - LIST_HEAD(bitmaps); - u64 num_entries; - u64 num_bitmaps; - u64 generation; - u8 type; - int ret = 0; - - /* Nothing in the space cache, goodbye */ - if (!i_size_read(inode)) - return 0; - - key.objectid = BTRFS_FREE_SPACE_OBJECTID; - key.offset = offset; - key.type = 0; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - return 0; - else if (ret > 0) { - btrfs_release_path(path); - return 0; - } - - ret = -1; - - leaf = path->nodes[0]; - header = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_free_space_header); - num_entries = btrfs_free_space_entries(leaf, header); - num_bitmaps = btrfs_free_space_bitmaps(leaf, header); - generation = btrfs_free_space_generation(leaf, header); - btrfs_release_path(path); - - if (!BTRFS_I(inode)->generation) { - btrfs_info(root->fs_info, - "The free space cache file (%llu) is invalid. skip it\n", - offset); - return 0; - } - - if (BTRFS_I(inode)->generation != generation) { - btrfs_err(root->fs_info, - "free space inode generation (%llu) did not match free space cache generation (%llu)", - BTRFS_I(inode)->generation, generation); - return 0; - } - - if (!num_entries) - return 0; - - ret = io_ctl_init(&io_ctl, inode, root, 0); - if (ret) - return ret; - - ret = readahead_cache(inode); - if (ret) - goto out; - - ret = io_ctl_prepare_pages(&io_ctl, inode, 1); - if (ret) - goto out; - - ret = io_ctl_check_crc(&io_ctl, 0); - if (ret) - goto free_cache; - - ret = io_ctl_check_generation(&io_ctl, generation); - if (ret) - goto free_cache; - - while (num_entries) { - e = kmem_cache_zalloc(btrfs_free_space_cachep, - GFP_NOFS); - if (!e) - goto free_cache; - - ret = io_ctl_read_entry(&io_ctl, e, &type); - if (ret) { - kmem_cache_free(btrfs_free_space_cachep, e); - goto free_cache; - } - - if (!e->bytes) { - kmem_cache_free(btrfs_free_space_cachep, e); - goto free_cache; - } - - if (type == BTRFS_FREE_SPACE_EXTENT) { - spin_lock(&ctl->tree_lock); - ret = link_free_space(ctl, e); - spin_unlock(&ctl->tree_lock); - if (ret) { - btrfs_err(root->fs_info, - "Duplicate entries in free space cache, dumping"); - kmem_cache_free(btrfs_free_space_cachep, e); - goto free_cache; - } - } else { - ASSERT(num_bitmaps); - num_bitmaps--; - e->bitmap = kzalloc(PAGE_SIZE, GFP_NOFS); - if (!e->bitmap) { - kmem_cache_free( - btrfs_free_space_cachep, e); - goto free_cache; - } - spin_lock(&ctl->tree_lock); - ret = link_free_space(ctl, e); - ctl->total_bitmaps++; - ctl->op->recalc_thresholds(ctl); - spin_unlock(&ctl->tree_lock); - if (ret) { - btrfs_err(root->fs_info, - "Duplicate entries in free space cache, dumping"); - kmem_cache_free(btrfs_free_space_cachep, e); - goto free_cache; - } - list_add_tail(&e->list, &bitmaps); - } - - num_entries--; - } - - io_ctl_unmap_page(&io_ctl); - - /* - * We add the bitmaps at the end of the entries in order that - * the bitmap entries are added to the cache. - */ - list_for_each_entry_safe(e, n, &bitmaps, list) { - list_del_init(&e->list); - ret = io_ctl_read_bitmap(&io_ctl, e); - if (ret) - goto free_cache; - } - - io_ctl_drop_pages(&io_ctl); - merge_space_tree(ctl); - ret = 1; -out: - io_ctl_free(&io_ctl); - return ret; -free_cache: - io_ctl_drop_pages(&io_ctl); - __btrfs_remove_free_space_cache(ctl); - goto out; -} - -int load_free_space_cache(struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group) -{ - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; - struct btrfs_root *root = fs_info->tree_root; - struct inode *inode; - struct btrfs_path *path; - int ret = 0; - bool matched; - u64 used = btrfs_block_group_used(&block_group->item); - - /* - * If this block group has been marked to be cleared for one reason or - * another then we can't trust the on disk cache, so just return. - */ - spin_lock(&block_group->lock); - if (block_group->disk_cache_state != BTRFS_DC_WRITTEN) { - spin_unlock(&block_group->lock); - return 0; - } - spin_unlock(&block_group->lock); - - path = btrfs_alloc_path(); - if (!path) - return 0; - path->search_commit_root = 1; - path->skip_locking = 1; - - inode = lookup_free_space_inode(root, block_group, path); - if (IS_ERR(inode)) { - btrfs_free_path(path); - return 0; - } - - /* We may have converted the inode and made the cache invalid. */ - spin_lock(&block_group->lock); - if (block_group->disk_cache_state != BTRFS_DC_WRITTEN) { - spin_unlock(&block_group->lock); - btrfs_free_path(path); - goto out; - } - spin_unlock(&block_group->lock); - - ret = __load_free_space_cache(fs_info->tree_root, inode, ctl, - path, block_group->key.objectid); - btrfs_free_path(path); - if (ret <= 0) - goto out; - - spin_lock(&ctl->tree_lock); - matched = (ctl->free_space == (block_group->key.offset - used - - block_group->bytes_super)); - spin_unlock(&ctl->tree_lock); - - if (!matched) { - __btrfs_remove_free_space_cache(ctl); - btrfs_warn(fs_info, - "block group %llu has wrong amount of free space", - block_group->key.objectid); - ret = -1; - } -out: - if (ret < 0) { - /* This cache is bogus, make sure it gets cleared */ - spin_lock(&block_group->lock); - block_group->disk_cache_state = BTRFS_DC_CLEAR; - spin_unlock(&block_group->lock); - ret = 0; - - btrfs_warn(fs_info, - "failed to load free space cache for block group %llu, rebuilding it now", - block_group->key.objectid); - } - - iput(inode); - return ret; -} - -static noinline_for_stack -int write_cache_extent_entries(struct btrfs_io_ctl *io_ctl, - struct btrfs_free_space_ctl *ctl, - struct btrfs_block_group_cache *block_group, - int *entries, int *bitmaps, - struct list_head *bitmap_list) -{ - int ret; - struct btrfs_free_cluster *cluster = NULL; - struct btrfs_free_cluster *cluster_locked = NULL; - struct rb_node *node = rb_first(&ctl->free_space_offset); - struct btrfs_trim_range *trim_entry; - - /* Get the cluster for this block_group if it exists */ - if (block_group && !list_empty(&block_group->cluster_list)) { - cluster = list_entry(block_group->cluster_list.next, - struct btrfs_free_cluster, - block_group_list); - } - - if (!node && cluster) { - cluster_locked = cluster; - spin_lock(&cluster_locked->lock); - node = rb_first(&cluster->root); - cluster = NULL; - } - - /* Write out the extent entries */ - while (node) { - struct btrfs_free_space *e; - - e = rb_entry(node, struct btrfs_free_space, offset_index); - *entries += 1; - - ret = io_ctl_add_entry(io_ctl, e->offset, e->bytes, - e->bitmap); - if (ret) - goto fail; - - if (e->bitmap) { - list_add_tail(&e->list, bitmap_list); - *bitmaps += 1; - } - node = rb_next(node); - if (!node && cluster) { - node = rb_first(&cluster->root); - cluster_locked = cluster; - spin_lock(&cluster_locked->lock); - cluster = NULL; - } - } - if (cluster_locked) { - spin_unlock(&cluster_locked->lock); - cluster_locked = NULL; - } - - /* - * Make sure we don't miss any range that was removed from our rbtree - * because trimming is running. Otherwise after a umount+mount (or crash - * after committing the transaction) we would leak free space and get - * an inconsistent free space cache report from fsck. - */ - list_for_each_entry(trim_entry, &ctl->trimming_ranges, list) { - ret = io_ctl_add_entry(io_ctl, trim_entry->start, - trim_entry->bytes, NULL); - if (ret) - goto fail; - *entries += 1; - } - - return 0; -fail: - if (cluster_locked) - spin_unlock(&cluster_locked->lock); - return -ENOSPC; -} - -static noinline_for_stack int -update_cache_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *inode, - struct btrfs_path *path, u64 offset, - int entries, int bitmaps) -{ - struct btrfs_key key; - struct btrfs_free_space_header *header; - struct extent_buffer *leaf; - int ret; - - key.objectid = BTRFS_FREE_SPACE_OBJECTID; - key.offset = offset; - key.type = 0; - - ret = btrfs_search_slot(trans, root, &key, path, 0, 1); - if (ret < 0) { - clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1, - EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, NULL, - GFP_NOFS); - goto fail; - } - leaf = path->nodes[0]; - if (ret > 0) { - struct btrfs_key found_key; - ASSERT(path->slots[0]); - path->slots[0]--; - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - if (found_key.objectid != BTRFS_FREE_SPACE_OBJECTID || - found_key.offset != offset) { - clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, - inode->i_size - 1, - EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, - NULL, GFP_NOFS); - btrfs_release_path(path); - goto fail; - } - } - - BTRFS_I(inode)->generation = trans->transid; - header = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_free_space_header); - btrfs_set_free_space_entries(leaf, header, entries); - btrfs_set_free_space_bitmaps(leaf, header, bitmaps); - btrfs_set_free_space_generation(leaf, header, trans->transid); - btrfs_mark_buffer_dirty(leaf); - btrfs_release_path(path); - - return 0; - -fail: - return -1; -} - -static noinline_for_stack int -write_pinned_extent_entries(struct btrfs_root *root, - struct btrfs_block_group_cache *block_group, - struct btrfs_io_ctl *io_ctl, - int *entries) -{ - u64 start, extent_start, extent_end, len; - struct extent_io_tree *unpin = NULL; - int ret; - - if (!block_group) - return 0; - - /* - * We want to add any pinned extents to our free space cache - * so we don't leak the space - * - * We shouldn't have switched the pinned extents yet so this is the - * right one - */ - unpin = root->fs_info->pinned_extents; - - start = block_group->key.objectid; - - while (start < block_group->key.objectid + block_group->key.offset) { - ret = find_first_extent_bit(unpin, start, - &extent_start, &extent_end, - EXTENT_DIRTY, NULL); - if (ret) - return 0; - - /* This pinned extent is out of our range */ - if (extent_start >= block_group->key.objectid + - block_group->key.offset) - return 0; - - extent_start = max(extent_start, start); - extent_end = min(block_group->key.objectid + - block_group->key.offset, extent_end + 1); - len = extent_end - extent_start; - - *entries += 1; - ret = io_ctl_add_entry(io_ctl, extent_start, len, NULL); - if (ret) - return -ENOSPC; - - start = extent_end; - } - - return 0; -} - -static noinline_for_stack int -write_bitmap_entries(struct btrfs_io_ctl *io_ctl, struct list_head *bitmap_list) -{ - struct btrfs_free_space *entry, *next; - int ret; - - /* Write out the bitmaps */ - list_for_each_entry_safe(entry, next, bitmap_list, list) { - ret = io_ctl_add_bitmap(io_ctl, entry->bitmap); - if (ret) - return -ENOSPC; - list_del_init(&entry->list); - } - - return 0; -} - -static int flush_dirty_cache(struct inode *inode) -{ - int ret; - - ret = btrfs_wait_ordered_range(inode, 0, (u64)-1); - if (ret) - clear_extent_bit(&BTRFS_I(inode)->io_tree, 0, inode->i_size - 1, - EXTENT_DIRTY | EXTENT_DELALLOC, 0, 0, NULL, - GFP_NOFS); - - return ret; -} - -static void noinline_for_stack -cleanup_bitmap_list(struct list_head *bitmap_list) -{ - struct btrfs_free_space *entry, *next; - - list_for_each_entry_safe(entry, next, bitmap_list, list) - list_del_init(&entry->list); -} - -static void noinline_for_stack -cleanup_write_cache_enospc(struct inode *inode, - struct btrfs_io_ctl *io_ctl, - struct extent_state **cached_state, - struct list_head *bitmap_list) -{ - io_ctl_drop_pages(io_ctl); - unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0, - i_size_read(inode) - 1, cached_state, - GFP_NOFS); -} - -int btrfs_wait_cache_io(struct btrfs_root *root, - struct btrfs_trans_handle *trans, - struct btrfs_block_group_cache *block_group, - struct btrfs_io_ctl *io_ctl, - struct btrfs_path *path, u64 offset) -{ - int ret; - struct inode *inode = io_ctl->inode; - - if (!inode) - return 0; - - if (block_group) - root = root->fs_info->tree_root; - - /* Flush the dirty pages in the cache file. */ - ret = flush_dirty_cache(inode); - if (ret) - goto out; - - /* Update the cache item to tell everyone this cache file is valid. */ - ret = update_cache_item(trans, root, inode, path, offset, - io_ctl->entries, io_ctl->bitmaps); -out: - io_ctl_free(io_ctl); - if (ret) { - invalidate_inode_pages2(inode->i_mapping); - BTRFS_I(inode)->generation = 0; - if (block_group) { -#ifdef DEBUG - btrfs_err(root->fs_info, - "failed to write free space cache for block group %llu", - block_group->key.objectid); -#endif - } - } - btrfs_update_inode(trans, root, inode); - - if (block_group) { - /* the dirty list is protected by the dirty_bgs_lock */ - spin_lock(&trans->transaction->dirty_bgs_lock); - - /* the disk_cache_state is protected by the block group lock */ - spin_lock(&block_group->lock); - - /* - * only mark this as written if we didn't get put back on - * the dirty list while waiting for IO. Otherwise our - * cache state won't be right, and we won't get written again - */ - if (!ret && list_empty(&block_group->dirty_list)) - block_group->disk_cache_state = BTRFS_DC_WRITTEN; - else if (ret) - block_group->disk_cache_state = BTRFS_DC_ERROR; - - spin_unlock(&block_group->lock); - spin_unlock(&trans->transaction->dirty_bgs_lock); - io_ctl->inode = NULL; - iput(inode); - } - - return ret; - -} - -/** - * __btrfs_write_out_cache - write out cached info to an inode - * @root - the root the inode belongs to - * @ctl - the free space cache we are going to write out - * @block_group - the block_group for this cache if it belongs to a block_group - * @trans - the trans handle - * @path - the path to use - * @offset - the offset for the key we'll insert - * - * This function writes out a free space cache struct to disk for quick recovery - * on mount. This will return 0 if it was successful in writing the cache out, - * or an errno if it was not. - */ -static int __btrfs_write_out_cache(struct btrfs_root *root, struct inode *inode, - struct btrfs_free_space_ctl *ctl, - struct btrfs_block_group_cache *block_group, - struct btrfs_io_ctl *io_ctl, - struct btrfs_trans_handle *trans, - struct btrfs_path *path, u64 offset) -{ - struct extent_state *cached_state = NULL; - LIST_HEAD(bitmap_list); - int entries = 0; - int bitmaps = 0; - int ret; - int must_iput = 0; - - if (!i_size_read(inode)) - return -EIO; - - WARN_ON(io_ctl->pages); - ret = io_ctl_init(io_ctl, inode, root, 1); - if (ret) - return ret; - - if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA)) { - down_write(&block_group->data_rwsem); - spin_lock(&block_group->lock); - if (block_group->delalloc_bytes) { - block_group->disk_cache_state = BTRFS_DC_WRITTEN; - spin_unlock(&block_group->lock); - up_write(&block_group->data_rwsem); - BTRFS_I(inode)->generation = 0; - ret = 0; - must_iput = 1; - goto out; - } - spin_unlock(&block_group->lock); - } - - /* Lock all pages first so we can lock the extent safely. */ - ret = io_ctl_prepare_pages(io_ctl, inode, 0); - if (ret) - goto out; - - lock_extent_bits(&BTRFS_I(inode)->io_tree, 0, i_size_read(inode) - 1, - &cached_state); - - io_ctl_set_generation(io_ctl, trans->transid); - - mutex_lock(&ctl->cache_writeout_mutex); - /* Write out the extent entries in the free space cache */ - spin_lock(&ctl->tree_lock); - ret = write_cache_extent_entries(io_ctl, ctl, - block_group, &entries, &bitmaps, - &bitmap_list); - if (ret) - goto out_nospc_locked; - - /* - * Some spaces that are freed in the current transaction are pinned, - * they will be added into free space cache after the transaction is - * committed, we shouldn't lose them. - * - * If this changes while we are working we'll get added back to - * the dirty list and redo it. No locking needed - */ - ret = write_pinned_extent_entries(root, block_group, io_ctl, &entries); - if (ret) - goto out_nospc_locked; - - /* - * At last, we write out all the bitmaps and keep cache_writeout_mutex - * locked while doing it because a concurrent trim can be manipulating - * or freeing the bitmap. - */ - ret = write_bitmap_entries(io_ctl, &bitmap_list); - spin_unlock(&ctl->tree_lock); - mutex_unlock(&ctl->cache_writeout_mutex); - if (ret) - goto out_nospc; - - /* Zero out the rest of the pages just to make sure */ - io_ctl_zero_remaining_pages(io_ctl); - - /* Everything is written out, now we dirty the pages in the file. */ - ret = btrfs_dirty_pages(root, inode, io_ctl->pages, io_ctl->num_pages, - 0, i_size_read(inode), &cached_state); - if (ret) - goto out_nospc; - - if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA)) - up_write(&block_group->data_rwsem); - /* - * Release the pages and unlock the extent, we will flush - * them out later - */ - io_ctl_drop_pages(io_ctl); - - unlock_extent_cached(&BTRFS_I(inode)->io_tree, 0, - i_size_read(inode) - 1, &cached_state, GFP_NOFS); - - /* - * at this point the pages are under IO and we're happy, - * The caller is responsible for waiting on them and updating the - * the cache and the inode - */ - io_ctl->entries = entries; - io_ctl->bitmaps = bitmaps; - - ret = btrfs_fdatawrite_range(inode, 0, (u64)-1); - if (ret) - goto out; - - return 0; - -out: - io_ctl->inode = NULL; - io_ctl_free(io_ctl); - if (ret) { - invalidate_inode_pages2(inode->i_mapping); - BTRFS_I(inode)->generation = 0; - } - btrfs_update_inode(trans, root, inode); - if (must_iput) - iput(inode); - return ret; - -out_nospc_locked: - cleanup_bitmap_list(&bitmap_list); - spin_unlock(&ctl->tree_lock); - mutex_unlock(&ctl->cache_writeout_mutex); - -out_nospc: - cleanup_write_cache_enospc(inode, io_ctl, &cached_state, &bitmap_list); - - if (block_group && (block_group->flags & BTRFS_BLOCK_GROUP_DATA)) - up_write(&block_group->data_rwsem); - - goto out; -} - -int btrfs_write_out_cache(struct btrfs_root *root, - struct btrfs_trans_handle *trans, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path) -{ - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; - struct inode *inode; - int ret = 0; - - root = root->fs_info->tree_root; - - spin_lock(&block_group->lock); - if (block_group->disk_cache_state < BTRFS_DC_SETUP) { - spin_unlock(&block_group->lock); - return 0; - } - spin_unlock(&block_group->lock); - - inode = lookup_free_space_inode(root, block_group, path); - if (IS_ERR(inode)) - return 0; - - ret = __btrfs_write_out_cache(root, inode, ctl, block_group, - &block_group->io_ctl, trans, - path, block_group->key.objectid); - if (ret) { -#ifdef DEBUG - btrfs_err(root->fs_info, - "failed to write free space cache for block group %llu", - block_group->key.objectid); -#endif - spin_lock(&block_group->lock); - block_group->disk_cache_state = BTRFS_DC_ERROR; - spin_unlock(&block_group->lock); - - block_group->io_ctl.inode = NULL; - iput(inode); - } - - /* - * if ret == 0 the caller is expected to call btrfs_wait_cache_io - * to wait for IO and put the inode - */ - - return ret; -} - -static inline unsigned long offset_to_bit(u64 bitmap_start, u32 unit, - u64 offset) -{ - ASSERT(offset >= bitmap_start); - offset -= bitmap_start; - return (unsigned long)(div_u64(offset, unit)); -} - -static inline unsigned long bytes_to_bits(u64 bytes, u32 unit) -{ - return (unsigned long)(div_u64(bytes, unit)); -} - -static inline u64 offset_to_bitmap(struct btrfs_free_space_ctl *ctl, - u64 offset) -{ - u64 bitmap_start; - u64 bytes_per_bitmap; - - bytes_per_bitmap = BITS_PER_BITMAP * ctl->unit; - bitmap_start = offset - ctl->start; - bitmap_start = div64_u64(bitmap_start, bytes_per_bitmap); - bitmap_start *= bytes_per_bitmap; - bitmap_start += ctl->start; - - return bitmap_start; -} - -static int tree_insert_offset(struct rb_root *root, u64 offset, - struct rb_node *node, int bitmap) -{ - struct rb_node **p = &root->rb_node; - struct rb_node *parent = NULL; - struct btrfs_free_space *info; - - while (*p) { - parent = *p; - info = rb_entry(parent, struct btrfs_free_space, offset_index); - - if (offset < info->offset) { - p = &(*p)->rb_left; - } else if (offset > info->offset) { - p = &(*p)->rb_right; - } else { - /* - * we could have a bitmap entry and an extent entry - * share the same offset. If this is the case, we want - * the extent entry to always be found first if we do a - * linear search through the tree, since we want to have - * the quickest allocation time, and allocating from an - * extent is faster than allocating from a bitmap. So - * if we're inserting a bitmap and we find an entry at - * this offset, we want to go right, or after this entry - * logically. If we are inserting an extent and we've - * found a bitmap, we want to go left, or before - * logically. - */ - if (bitmap) { - if (info->bitmap) { - WARN_ON_ONCE(1); - return -EEXIST; - } - p = &(*p)->rb_right; - } else { - if (!info->bitmap) { - WARN_ON_ONCE(1); - return -EEXIST; - } - p = &(*p)->rb_left; - } - } - } - - rb_link_node(node, parent, p); - rb_insert_color(node, root); - - return 0; -} - -/* - * searches the tree for the given offset. - * - * fuzzy - If this is set, then we are trying to make an allocation, and we just - * want a section that has at least bytes size and comes at or after the given - * offset. - */ -static struct btrfs_free_space * -tree_search_offset(struct btrfs_free_space_ctl *ctl, - u64 offset, int bitmap_only, int fuzzy) -{ - struct rb_node *n = ctl->free_space_offset.rb_node; - struct btrfs_free_space *entry, *prev = NULL; - - /* find entry that is closest to the 'offset' */ - while (1) { - if (!n) { - entry = NULL; - break; - } - - entry = rb_entry(n, struct btrfs_free_space, offset_index); - prev = entry; - - if (offset < entry->offset) - n = n->rb_left; - else if (offset > entry->offset) - n = n->rb_right; - else - break; - } - - if (bitmap_only) { - if (!entry) - return NULL; - if (entry->bitmap) - return entry; - - /* - * bitmap entry and extent entry may share same offset, - * in that case, bitmap entry comes after extent entry. - */ - n = rb_next(n); - if (!n) - return NULL; - entry = rb_entry(n, struct btrfs_free_space, offset_index); - if (entry->offset != offset) - return NULL; - - WARN_ON(!entry->bitmap); - return entry; - } else if (entry) { - if (entry->bitmap) { - /* - * if previous extent entry covers the offset, - * we should return it instead of the bitmap entry - */ - n = rb_prev(&entry->offset_index); - if (n) { - prev = rb_entry(n, struct btrfs_free_space, - offset_index); - if (!prev->bitmap && - prev->offset + prev->bytes > offset) - entry = prev; - } - } - return entry; - } - - if (!prev) - return NULL; - - /* find last entry before the 'offset' */ - entry = prev; - if (entry->offset > offset) { - n = rb_prev(&entry->offset_index); - if (n) { - entry = rb_entry(n, struct btrfs_free_space, - offset_index); - ASSERT(entry->offset <= offset); - } else { - if (fuzzy) - return entry; - else - return NULL; - } - } - - if (entry->bitmap) { - n = rb_prev(&entry->offset_index); - if (n) { - prev = rb_entry(n, struct btrfs_free_space, - offset_index); - if (!prev->bitmap && - prev->offset + prev->bytes > offset) - return prev; - } - if (entry->offset + BITS_PER_BITMAP * ctl->unit > offset) - return entry; - } else if (entry->offset + entry->bytes > offset) - return entry; - - if (!fuzzy) - return NULL; - - while (1) { - if (entry->bitmap) { - if (entry->offset + BITS_PER_BITMAP * - ctl->unit > offset) - break; - } else { - if (entry->offset + entry->bytes > offset) - break; - } - - n = rb_next(&entry->offset_index); - if (!n) - return NULL; - entry = rb_entry(n, struct btrfs_free_space, offset_index); - } - return entry; -} - -static inline void -__unlink_free_space(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info) -{ - rb_erase(&info->offset_index, &ctl->free_space_offset); - ctl->free_extents--; -} - -static void unlink_free_space(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info) -{ - __unlink_free_space(ctl, info); - ctl->free_space -= info->bytes; -} - -static int link_free_space(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info) -{ - int ret = 0; - - ASSERT(info->bytes || info->bitmap); - ret = tree_insert_offset(&ctl->free_space_offset, info->offset, - &info->offset_index, (info->bitmap != NULL)); - if (ret) - return ret; - - ctl->free_space += info->bytes; - ctl->free_extents++; - return ret; -} - -static void recalculate_thresholds(struct btrfs_free_space_ctl *ctl) -{ - struct btrfs_block_group_cache *block_group = ctl->private; - u64 max_bytes; - u64 bitmap_bytes; - u64 extent_bytes; - u64 size = block_group->key.offset; - u64 bytes_per_bg = BITS_PER_BITMAP * ctl->unit; - u64 max_bitmaps = div64_u64(size + bytes_per_bg - 1, bytes_per_bg); - - max_bitmaps = max_t(u64, max_bitmaps, 1); - - ASSERT(ctl->total_bitmaps <= max_bitmaps); - - /* - * The goal is to keep the total amount of memory used per 1gb of space - * at or below 32k, so we need to adjust how much memory we allow to be - * used by extent based free space tracking - */ - if (size < SZ_1G) - max_bytes = MAX_CACHE_BYTES_PER_GIG; - else - max_bytes = MAX_CACHE_BYTES_PER_GIG * div_u64(size, SZ_1G); - - /* - * we want to account for 1 more bitmap than what we have so we can make - * sure we don't go over our overall goal of MAX_CACHE_BYTES_PER_GIG as - * we add more bitmaps. - */ - bitmap_bytes = (ctl->total_bitmaps + 1) * ctl->unit; - - if (bitmap_bytes >= max_bytes) { - ctl->extents_thresh = 0; - return; - } - - /* - * we want the extent entry threshold to always be at most 1/2 the max - * bytes we can have, or whatever is less than that. - */ - extent_bytes = max_bytes - bitmap_bytes; - extent_bytes = min_t(u64, extent_bytes, max_bytes >> 1); - - ctl->extents_thresh = - div_u64(extent_bytes, sizeof(struct btrfs_free_space)); -} - -static inline void __bitmap_clear_bits(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info, - u64 offset, u64 bytes) -{ - unsigned long start, count; - - start = offset_to_bit(info->offset, ctl->unit, offset); - count = bytes_to_bits(bytes, ctl->unit); - ASSERT(start + count <= BITS_PER_BITMAP); - - bitmap_clear(info->bitmap, start, count); - - info->bytes -= bytes; -} - -static void bitmap_clear_bits(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info, u64 offset, - u64 bytes) -{ - __bitmap_clear_bits(ctl, info, offset, bytes); - ctl->free_space -= bytes; -} - -static void bitmap_set_bits(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info, u64 offset, - u64 bytes) -{ - unsigned long start, count; - - start = offset_to_bit(info->offset, ctl->unit, offset); - count = bytes_to_bits(bytes, ctl->unit); - ASSERT(start + count <= BITS_PER_BITMAP); - - bitmap_set(info->bitmap, start, count); - - info->bytes += bytes; - ctl->free_space += bytes; -} - -/* - * If we can not find suitable extent, we will use bytes to record - * the size of the max extent. - */ -static int search_bitmap(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *bitmap_info, u64 *offset, - u64 *bytes, bool for_alloc) -{ - unsigned long found_bits = 0; - unsigned long max_bits = 0; - unsigned long bits, i; - unsigned long next_zero; - unsigned long extent_bits; - - /* - * Skip searching the bitmap if we don't have a contiguous section that - * is large enough for this allocation. - */ - if (for_alloc && - bitmap_info->max_extent_size && - bitmap_info->max_extent_size < *bytes) { - *bytes = bitmap_info->max_extent_size; - return -1; - } - - i = offset_to_bit(bitmap_info->offset, ctl->unit, - max_t(u64, *offset, bitmap_info->offset)); - bits = bytes_to_bits(*bytes, ctl->unit); - - for_each_set_bit_from(i, bitmap_info->bitmap, BITS_PER_BITMAP) { - if (for_alloc && bits == 1) { - found_bits = 1; - break; - } - next_zero = find_next_zero_bit(bitmap_info->bitmap, - BITS_PER_BITMAP, i); - extent_bits = next_zero - i; - if (extent_bits >= bits) { - found_bits = extent_bits; - break; - } else if (extent_bits > max_bits) { - max_bits = extent_bits; - } - i = next_zero; - } - - if (found_bits) { - *offset = (u64)(i * ctl->unit) + bitmap_info->offset; - *bytes = (u64)(found_bits) * ctl->unit; - return 0; - } - - *bytes = (u64)(max_bits) * ctl->unit; - bitmap_info->max_extent_size = *bytes; - return -1; -} - -/* Cache the size of the max extent in bytes */ -static struct btrfs_free_space * -find_free_space(struct btrfs_free_space_ctl *ctl, u64 *offset, u64 *bytes, - unsigned long align, u64 *max_extent_size) -{ - struct btrfs_free_space *entry; - struct rb_node *node; - u64 tmp; - u64 align_off; - int ret; - - if (!ctl->free_space_offset.rb_node) - goto out; - - entry = tree_search_offset(ctl, offset_to_bitmap(ctl, *offset), 0, 1); - if (!entry) - goto out; - - for (node = &entry->offset_index; node; node = rb_next(node)) { - entry = rb_entry(node, struct btrfs_free_space, offset_index); - if (entry->bytes < *bytes) { - if (entry->bytes > *max_extent_size) - *max_extent_size = entry->bytes; - continue; - } - - /* make sure the space returned is big enough - * to match our requested alignment - */ - if (*bytes >= align) { - tmp = entry->offset - ctl->start + align - 1; - tmp = div64_u64(tmp, align); - tmp = tmp * align + ctl->start; - align_off = tmp - entry->offset; - } else { - align_off = 0; - tmp = entry->offset; - } - - if (entry->bytes < *bytes + align_off) { - if (entry->bytes > *max_extent_size) - *max_extent_size = entry->bytes; - continue; - } - - if (entry->bitmap) { - u64 size = *bytes; - - ret = search_bitmap(ctl, entry, &tmp, &size, true); - if (!ret) { - *offset = tmp; - *bytes = size; - return entry; - } else if (size > *max_extent_size) { - *max_extent_size = size; - } - continue; - } - - *offset = tmp; - *bytes = entry->bytes - align_off; - return entry; - } -out: - return NULL; -} - -static void add_new_bitmap(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info, u64 offset) -{ - info->offset = offset_to_bitmap(ctl, offset); - info->bytes = 0; - INIT_LIST_HEAD(&info->list); - link_free_space(ctl, info); - ctl->total_bitmaps++; - - ctl->op->recalc_thresholds(ctl); -} - -static void free_bitmap(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *bitmap_info) -{ - unlink_free_space(ctl, bitmap_info); - kfree(bitmap_info->bitmap); - kmem_cache_free(btrfs_free_space_cachep, bitmap_info); - ctl->total_bitmaps--; - ctl->op->recalc_thresholds(ctl); -} - -static noinline int remove_from_bitmap(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *bitmap_info, - u64 *offset, u64 *bytes) -{ - u64 end; - u64 search_start, search_bytes; - int ret; - -again: - end = bitmap_info->offset + (u64)(BITS_PER_BITMAP * ctl->unit) - 1; - - /* - * We need to search for bits in this bitmap. We could only cover some - * of the extent in this bitmap thanks to how we add space, so we need - * to search for as much as it as we can and clear that amount, and then - * go searching for the next bit. - */ - search_start = *offset; - search_bytes = ctl->unit; - search_bytes = min(search_bytes, end - search_start + 1); - ret = search_bitmap(ctl, bitmap_info, &search_start, &search_bytes, - false); - if (ret < 0 || search_start != *offset) - return -EINVAL; - - /* We may have found more bits than what we need */ - search_bytes = min(search_bytes, *bytes); - - /* Cannot clear past the end of the bitmap */ - search_bytes = min(search_bytes, end - search_start + 1); - - bitmap_clear_bits(ctl, bitmap_info, search_start, search_bytes); - *offset += search_bytes; - *bytes -= search_bytes; - - if (*bytes) { - struct rb_node *next = rb_next(&bitmap_info->offset_index); - if (!bitmap_info->bytes) - free_bitmap(ctl, bitmap_info); - - /* - * no entry after this bitmap, but we still have bytes to - * remove, so something has gone wrong. - */ - if (!next) - return -EINVAL; - - bitmap_info = rb_entry(next, struct btrfs_free_space, - offset_index); - - /* - * if the next entry isn't a bitmap we need to return to let the - * extent stuff do its work. - */ - if (!bitmap_info->bitmap) - return -EAGAIN; - - /* - * Ok the next item is a bitmap, but it may not actually hold - * the information for the rest of this free space stuff, so - * look for it, and if we don't find it return so we can try - * everything over again. - */ - search_start = *offset; - search_bytes = ctl->unit; - ret = search_bitmap(ctl, bitmap_info, &search_start, - &search_bytes, false); - if (ret < 0 || search_start != *offset) - return -EAGAIN; - - goto again; - } else if (!bitmap_info->bytes) - free_bitmap(ctl, bitmap_info); - - return 0; -} - -static u64 add_bytes_to_bitmap(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info, u64 offset, - u64 bytes) -{ - u64 bytes_to_set = 0; - u64 end; - - end = info->offset + (u64)(BITS_PER_BITMAP * ctl->unit); - - bytes_to_set = min(end - offset, bytes); - - bitmap_set_bits(ctl, info, offset, bytes_to_set); - - /* - * We set some bytes, we have no idea what the max extent size is - * anymore. - */ - info->max_extent_size = 0; - - return bytes_to_set; - -} - -static bool use_bitmap(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info) -{ - struct btrfs_block_group_cache *block_group = ctl->private; - bool forced = false; - -#ifdef CONFIG_BTRFS_DEBUG - if (btrfs_should_fragment_free_space(block_group->fs_info->extent_root, - block_group)) - forced = true; -#endif - - /* - * If we are below the extents threshold then we can add this as an - * extent, and don't have to deal with the bitmap - */ - if (!forced && ctl->free_extents < ctl->extents_thresh) { - /* - * If this block group has some small extents we don't want to - * use up all of our free slots in the cache with them, we want - * to reserve them to larger extents, however if we have plenty - * of cache left then go ahead an dadd them, no sense in adding - * the overhead of a bitmap if we don't have to. - */ - if (info->bytes <= block_group->sectorsize * 4) { - if (ctl->free_extents * 2 <= ctl->extents_thresh) - return false; - } else { - return false; - } - } - - /* - * The original block groups from mkfs can be really small, like 8 - * megabytes, so don't bother with a bitmap for those entries. However - * some block groups can be smaller than what a bitmap would cover but - * are still large enough that they could overflow the 32k memory limit, - * so allow those block groups to still be allowed to have a bitmap - * entry. - */ - if (((BITS_PER_BITMAP * ctl->unit) >> 1) > block_group->key.offset) - return false; - - return true; -} - -static const struct btrfs_free_space_op free_space_op = { - .recalc_thresholds = recalculate_thresholds, - .use_bitmap = use_bitmap, -}; - -static int insert_into_bitmap(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info) -{ - struct btrfs_free_space *bitmap_info; - struct btrfs_block_group_cache *block_group = NULL; - int added = 0; - u64 bytes, offset, bytes_added; - int ret; - - bytes = info->bytes; - offset = info->offset; - - if (!ctl->op->use_bitmap(ctl, info)) - return 0; - - if (ctl->op == &free_space_op) - block_group = ctl->private; -again: - /* - * Since we link bitmaps right into the cluster we need to see if we - * have a cluster here, and if so and it has our bitmap we need to add - * the free space to that bitmap. - */ - if (block_group && !list_empty(&block_group->cluster_list)) { - struct btrfs_free_cluster *cluster; - struct rb_node *node; - struct btrfs_free_space *entry; - - cluster = list_entry(block_group->cluster_list.next, - struct btrfs_free_cluster, - block_group_list); - spin_lock(&cluster->lock); - node = rb_first(&cluster->root); - if (!node) { - spin_unlock(&cluster->lock); - goto no_cluster_bitmap; - } - - entry = rb_entry(node, struct btrfs_free_space, offset_index); - if (!entry->bitmap) { - spin_unlock(&cluster->lock); - goto no_cluster_bitmap; - } - - if (entry->offset == offset_to_bitmap(ctl, offset)) { - bytes_added = add_bytes_to_bitmap(ctl, entry, - offset, bytes); - bytes -= bytes_added; - offset += bytes_added; - } - spin_unlock(&cluster->lock); - if (!bytes) { - ret = 1; - goto out; - } - } - -no_cluster_bitmap: - bitmap_info = tree_search_offset(ctl, offset_to_bitmap(ctl, offset), - 1, 0); - if (!bitmap_info) { - ASSERT(added == 0); - goto new_bitmap; - } - - bytes_added = add_bytes_to_bitmap(ctl, bitmap_info, offset, bytes); - bytes -= bytes_added; - offset += bytes_added; - added = 0; - - if (!bytes) { - ret = 1; - goto out; - } else - goto again; - -new_bitmap: - if (info && info->bitmap) { - add_new_bitmap(ctl, info, offset); - added = 1; - info = NULL; - goto again; - } else { - spin_unlock(&ctl->tree_lock); - - /* no pre-allocated info, allocate a new one */ - if (!info) { - info = kmem_cache_zalloc(btrfs_free_space_cachep, - GFP_NOFS); - if (!info) { - spin_lock(&ctl->tree_lock); - ret = -ENOMEM; - goto out; - } - } - - /* allocate the bitmap */ - info->bitmap = kzalloc(PAGE_SIZE, GFP_NOFS); - spin_lock(&ctl->tree_lock); - if (!info->bitmap) { - ret = -ENOMEM; - goto out; - } - goto again; - } - -out: - if (info) { - if (info->bitmap) - kfree(info->bitmap); - kmem_cache_free(btrfs_free_space_cachep, info); - } - - return ret; -} - -static bool try_merge_free_space(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info, bool update_stat) -{ - struct btrfs_free_space *left_info; - struct btrfs_free_space *right_info; - bool merged = false; - u64 offset = info->offset; - u64 bytes = info->bytes; - - /* - * first we want to see if there is free space adjacent to the range we - * are adding, if there is remove that struct and add a new one to - * cover the entire range - */ - right_info = tree_search_offset(ctl, offset + bytes, 0, 0); - if (right_info && rb_prev(&right_info->offset_index)) - left_info = rb_entry(rb_prev(&right_info->offset_index), - struct btrfs_free_space, offset_index); - else - left_info = tree_search_offset(ctl, offset - 1, 0, 0); - - if (right_info && !right_info->bitmap) { - if (update_stat) - unlink_free_space(ctl, right_info); - else - __unlink_free_space(ctl, right_info); - info->bytes += right_info->bytes; - kmem_cache_free(btrfs_free_space_cachep, right_info); - merged = true; - } - - if (left_info && !left_info->bitmap && - left_info->offset + left_info->bytes == offset) { - if (update_stat) - unlink_free_space(ctl, left_info); - else - __unlink_free_space(ctl, left_info); - info->offset = left_info->offset; - info->bytes += left_info->bytes; - kmem_cache_free(btrfs_free_space_cachep, left_info); - merged = true; - } - - return merged; -} - -static bool steal_from_bitmap_to_end(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info, - bool update_stat) -{ - struct btrfs_free_space *bitmap; - unsigned long i; - unsigned long j; - const u64 end = info->offset + info->bytes; - const u64 bitmap_offset = offset_to_bitmap(ctl, end); - u64 bytes; - - bitmap = tree_search_offset(ctl, bitmap_offset, 1, 0); - if (!bitmap) - return false; - - i = offset_to_bit(bitmap->offset, ctl->unit, end); - j = find_next_zero_bit(bitmap->bitmap, BITS_PER_BITMAP, i); - if (j == i) - return false; - bytes = (j - i) * ctl->unit; - info->bytes += bytes; - - if (update_stat) - bitmap_clear_bits(ctl, bitmap, end, bytes); - else - __bitmap_clear_bits(ctl, bitmap, end, bytes); - - if (!bitmap->bytes) - free_bitmap(ctl, bitmap); - - return true; -} - -static bool steal_from_bitmap_to_front(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info, - bool update_stat) -{ - struct btrfs_free_space *bitmap; - u64 bitmap_offset; - unsigned long i; - unsigned long j; - unsigned long prev_j; - u64 bytes; - - bitmap_offset = offset_to_bitmap(ctl, info->offset); - /* If we're on a boundary, try the previous logical bitmap. */ - if (bitmap_offset == info->offset) { - if (info->offset == 0) - return false; - bitmap_offset = offset_to_bitmap(ctl, info->offset - 1); - } - - bitmap = tree_search_offset(ctl, bitmap_offset, 1, 0); - if (!bitmap) - return false; - - i = offset_to_bit(bitmap->offset, ctl->unit, info->offset) - 1; - j = 0; - prev_j = (unsigned long)-1; - for_each_clear_bit_from(j, bitmap->bitmap, BITS_PER_BITMAP) { - if (j > i) - break; - prev_j = j; - } - if (prev_j == i) - return false; - - if (prev_j == (unsigned long)-1) - bytes = (i + 1) * ctl->unit; - else - bytes = (i - prev_j) * ctl->unit; - - info->offset -= bytes; - info->bytes += bytes; - - if (update_stat) - bitmap_clear_bits(ctl, bitmap, info->offset, bytes); - else - __bitmap_clear_bits(ctl, bitmap, info->offset, bytes); - - if (!bitmap->bytes) - free_bitmap(ctl, bitmap); - - return true; -} - -/* - * We prefer always to allocate from extent entries, both for clustered and - * non-clustered allocation requests. So when attempting to add a new extent - * entry, try to see if there's adjacent free space in bitmap entries, and if - * there is, migrate that space from the bitmaps to the extent. - * Like this we get better chances of satisfying space allocation requests - * because we attempt to satisfy them based on a single cache entry, and never - * on 2 or more entries - even if the entries represent a contiguous free space - * region (e.g. 1 extent entry + 1 bitmap entry starting where the extent entry - * ends). - */ -static void steal_from_bitmap(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info, - bool update_stat) -{ - /* - * Only work with disconnected entries, as we can change their offset, - * and must be extent entries. - */ - ASSERT(!info->bitmap); - ASSERT(RB_EMPTY_NODE(&info->offset_index)); - - if (ctl->total_bitmaps > 0) { - bool stole_end; - bool stole_front = false; - - stole_end = steal_from_bitmap_to_end(ctl, info, update_stat); - if (ctl->total_bitmaps > 0) - stole_front = steal_from_bitmap_to_front(ctl, info, - update_stat); - - if (stole_end || stole_front) - try_merge_free_space(ctl, info, update_stat); - } -} - -int __btrfs_add_free_space(struct btrfs_fs_info *fs_info, - struct btrfs_free_space_ctl *ctl, - u64 offset, u64 bytes) -{ - struct btrfs_free_space *info; - int ret = 0; - - info = kmem_cache_zalloc(btrfs_free_space_cachep, GFP_NOFS); - if (!info) - return -ENOMEM; - - info->offset = offset; - info->bytes = bytes; - RB_CLEAR_NODE(&info->offset_index); - - spin_lock(&ctl->tree_lock); - - if (try_merge_free_space(ctl, info, true)) - goto link; - - /* - * There was no extent directly to the left or right of this new - * extent then we know we're going to have to allocate a new extent, so - * before we do that see if we need to drop this into a bitmap - */ - ret = insert_into_bitmap(ctl, info); - if (ret < 0) { - goto out; - } else if (ret) { - ret = 0; - goto out; - } -link: - /* - * Only steal free space from adjacent bitmaps if we're sure we're not - * going to add the new free space to existing bitmap entries - because - * that would mean unnecessary work that would be reverted. Therefore - * attempt to steal space from bitmaps if we're adding an extent entry. - */ - steal_from_bitmap(ctl, info, true); - - ret = link_free_space(ctl, info); - if (ret) - kmem_cache_free(btrfs_free_space_cachep, info); -out: - spin_unlock(&ctl->tree_lock); - - if (ret) { - btrfs_crit(fs_info, "unable to add free space :%d", ret); - ASSERT(ret != -EEXIST); - } - - return ret; -} - -int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group, - u64 offset, u64 bytes) -{ - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; - struct btrfs_free_space *info; - int ret; - bool re_search = false; - - spin_lock(&ctl->tree_lock); - -again: - ret = 0; - if (!bytes) - goto out_lock; - - info = tree_search_offset(ctl, offset, 0, 0); - if (!info) { - /* - * oops didn't find an extent that matched the space we wanted - * to remove, look for a bitmap instead - */ - info = tree_search_offset(ctl, offset_to_bitmap(ctl, offset), - 1, 0); - if (!info) { - /* - * If we found a partial bit of our free space in a - * bitmap but then couldn't find the other part this may - * be a problem, so WARN about it. - */ - WARN_ON(re_search); - goto out_lock; - } - } - - re_search = false; - if (!info->bitmap) { - unlink_free_space(ctl, info); - if (offset == info->offset) { - u64 to_free = min(bytes, info->bytes); - - info->bytes -= to_free; - info->offset += to_free; - if (info->bytes) { - ret = link_free_space(ctl, info); - WARN_ON(ret); - } else { - kmem_cache_free(btrfs_free_space_cachep, info); - } - - offset += to_free; - bytes -= to_free; - goto again; - } else { - u64 old_end = info->bytes + info->offset; - - info->bytes = offset - info->offset; - ret = link_free_space(ctl, info); - WARN_ON(ret); - if (ret) - goto out_lock; - - /* Not enough bytes in this entry to satisfy us */ - if (old_end < offset + bytes) { - bytes -= old_end - offset; - offset = old_end; - goto again; - } else if (old_end == offset + bytes) { - /* all done */ - goto out_lock; - } - spin_unlock(&ctl->tree_lock); - - ret = btrfs_add_free_space(block_group, offset + bytes, - old_end - (offset + bytes)); - WARN_ON(ret); - goto out; - } - } - - ret = remove_from_bitmap(ctl, info, &offset, &bytes); - if (ret == -EAGAIN) { - re_search = true; - goto again; - } -out_lock: - spin_unlock(&ctl->tree_lock); -out: - return ret; -} - -void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group, - u64 bytes) -{ - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; - struct btrfs_free_space *info; - struct rb_node *n; - int count = 0; - - for (n = rb_first(&ctl->free_space_offset); n; n = rb_next(n)) { - info = rb_entry(n, struct btrfs_free_space, offset_index); - if (info->bytes >= bytes && !block_group->ro) - count++; - btrfs_crit(block_group->fs_info, - "entry offset %llu, bytes %llu, bitmap %s", - info->offset, info->bytes, - (info->bitmap) ? "yes" : "no"); - } - btrfs_info(block_group->fs_info, "block group has cluster?: %s", - list_empty(&block_group->cluster_list) ? "no" : "yes"); - btrfs_info(block_group->fs_info, - "%d blocks of free space at or bigger than bytes is", count); -} - -void btrfs_init_free_space_ctl(struct btrfs_block_group_cache *block_group) -{ - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; - - spin_lock_init(&ctl->tree_lock); - ctl->unit = block_group->sectorsize; - ctl->start = block_group->key.objectid; - ctl->private = block_group; - ctl->op = &free_space_op; - INIT_LIST_HEAD(&ctl->trimming_ranges); - mutex_init(&ctl->cache_writeout_mutex); - - /* - * we only want to have 32k of ram per block group for keeping - * track of free space, and if we pass 1/2 of that we want to - * start converting things over to using bitmaps - */ - ctl->extents_thresh = (SZ_32K / 2) / sizeof(struct btrfs_free_space); -} - -/* - * for a given cluster, put all of its extents back into the free - * space cache. If the block group passed doesn't match the block group - * pointed to by the cluster, someone else raced in and freed the - * cluster already. In that case, we just return without changing anything - */ -static int -__btrfs_return_cluster_to_free_space( - struct btrfs_block_group_cache *block_group, - struct btrfs_free_cluster *cluster) -{ - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; - struct btrfs_free_space *entry; - struct rb_node *node; - - spin_lock(&cluster->lock); - if (cluster->block_group != block_group) - goto out; - - cluster->block_group = NULL; - cluster->window_start = 0; - list_del_init(&cluster->block_group_list); - - node = rb_first(&cluster->root); - while (node) { - bool bitmap; - - entry = rb_entry(node, struct btrfs_free_space, offset_index); - node = rb_next(&entry->offset_index); - rb_erase(&entry->offset_index, &cluster->root); - RB_CLEAR_NODE(&entry->offset_index); - - bitmap = (entry->bitmap != NULL); - if (!bitmap) { - try_merge_free_space(ctl, entry, false); - steal_from_bitmap(ctl, entry, false); - } - tree_insert_offset(&ctl->free_space_offset, - entry->offset, &entry->offset_index, bitmap); - } - cluster->root = RB_ROOT; - -out: - spin_unlock(&cluster->lock); - btrfs_put_block_group(block_group); - return 0; -} - -static void __btrfs_remove_free_space_cache_locked( - struct btrfs_free_space_ctl *ctl) -{ - struct btrfs_free_space *info; - struct rb_node *node; - - while ((node = rb_last(&ctl->free_space_offset)) != NULL) { - info = rb_entry(node, struct btrfs_free_space, offset_index); - if (!info->bitmap) { - unlink_free_space(ctl, info); - kmem_cache_free(btrfs_free_space_cachep, info); - } else { - free_bitmap(ctl, info); - } - - cond_resched_lock(&ctl->tree_lock); - } -} - -void __btrfs_remove_free_space_cache(struct btrfs_free_space_ctl *ctl) -{ - spin_lock(&ctl->tree_lock); - __btrfs_remove_free_space_cache_locked(ctl); - spin_unlock(&ctl->tree_lock); -} - -void btrfs_remove_free_space_cache(struct btrfs_block_group_cache *block_group) -{ - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; - struct btrfs_free_cluster *cluster; - struct list_head *head; - - spin_lock(&ctl->tree_lock); - while ((head = block_group->cluster_list.next) != - &block_group->cluster_list) { - cluster = list_entry(head, struct btrfs_free_cluster, - block_group_list); - - WARN_ON(cluster->block_group != block_group); - __btrfs_return_cluster_to_free_space(block_group, cluster); - - cond_resched_lock(&ctl->tree_lock); - } - __btrfs_remove_free_space_cache_locked(ctl); - spin_unlock(&ctl->tree_lock); - -} - -u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group, - u64 offset, u64 bytes, u64 empty_size, - u64 *max_extent_size) -{ - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; - struct btrfs_free_space *entry = NULL; - u64 bytes_search = bytes + empty_size; - u64 ret = 0; - u64 align_gap = 0; - u64 align_gap_len = 0; - - spin_lock(&ctl->tree_lock); - entry = find_free_space(ctl, &offset, &bytes_search, - block_group->full_stripe_len, max_extent_size); - if (!entry) - goto out; - - ret = offset; - if (entry->bitmap) { - bitmap_clear_bits(ctl, entry, offset, bytes); - if (!entry->bytes) - free_bitmap(ctl, entry); - } else { - unlink_free_space(ctl, entry); - align_gap_len = offset - entry->offset; - align_gap = entry->offset; - - entry->offset = offset + bytes; - WARN_ON(entry->bytes < bytes + align_gap_len); - - entry->bytes -= bytes + align_gap_len; - if (!entry->bytes) - kmem_cache_free(btrfs_free_space_cachep, entry); - else - link_free_space(ctl, entry); - } -out: - spin_unlock(&ctl->tree_lock); - - if (align_gap_len) - __btrfs_add_free_space(block_group->fs_info, ctl, - align_gap, align_gap_len); - return ret; -} - -/* - * given a cluster, put all of its extents back into the free space - * cache. If a block group is passed, this function will only free - * a cluster that belongs to the passed block group. - * - * Otherwise, it'll get a reference on the block group pointed to by the - * cluster and remove the cluster from it. - */ -int btrfs_return_cluster_to_free_space( - struct btrfs_block_group_cache *block_group, - struct btrfs_free_cluster *cluster) -{ - struct btrfs_free_space_ctl *ctl; - int ret; - - /* first, get a safe pointer to the block group */ - spin_lock(&cluster->lock); - if (!block_group) { - block_group = cluster->block_group; - if (!block_group) { - spin_unlock(&cluster->lock); - return 0; - } - } else if (cluster->block_group != block_group) { - /* someone else has already freed it don't redo their work */ - spin_unlock(&cluster->lock); - return 0; - } - atomic_inc(&block_group->count); - spin_unlock(&cluster->lock); - - ctl = block_group->free_space_ctl; - - /* now return any extents the cluster had on it */ - spin_lock(&ctl->tree_lock); - ret = __btrfs_return_cluster_to_free_space(block_group, cluster); - spin_unlock(&ctl->tree_lock); - - /* finally drop our ref */ - btrfs_put_block_group(block_group); - return ret; -} - -static u64 btrfs_alloc_from_bitmap(struct btrfs_block_group_cache *block_group, - struct btrfs_free_cluster *cluster, - struct btrfs_free_space *entry, - u64 bytes, u64 min_start, - u64 *max_extent_size) -{ - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; - int err; - u64 search_start = cluster->window_start; - u64 search_bytes = bytes; - u64 ret = 0; - - search_start = min_start; - search_bytes = bytes; - - err = search_bitmap(ctl, entry, &search_start, &search_bytes, true); - if (err) { - if (search_bytes > *max_extent_size) - *max_extent_size = search_bytes; - return 0; - } - - ret = search_start; - __bitmap_clear_bits(ctl, entry, ret, bytes); - - return ret; -} - -/* - * given a cluster, try to allocate 'bytes' from it, returns 0 - * if it couldn't find anything suitably large, or a logical disk offset - * if things worked out - */ -u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group, - struct btrfs_free_cluster *cluster, u64 bytes, - u64 min_start, u64 *max_extent_size) -{ - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; - struct btrfs_free_space *entry = NULL; - struct rb_node *node; - u64 ret = 0; - - spin_lock(&cluster->lock); - if (bytes > cluster->max_size) - goto out; - - if (cluster->block_group != block_group) - goto out; - - node = rb_first(&cluster->root); - if (!node) - goto out; - - entry = rb_entry(node, struct btrfs_free_space, offset_index); - while (1) { - if (entry->bytes < bytes && entry->bytes > *max_extent_size) - *max_extent_size = entry->bytes; - - if (entry->bytes < bytes || - (!entry->bitmap && entry->offset < min_start)) { - node = rb_next(&entry->offset_index); - if (!node) - break; - entry = rb_entry(node, struct btrfs_free_space, - offset_index); - continue; - } - - if (entry->bitmap) { - ret = btrfs_alloc_from_bitmap(block_group, - cluster, entry, bytes, - cluster->window_start, - max_extent_size); - if (ret == 0) { - node = rb_next(&entry->offset_index); - if (!node) - break; - entry = rb_entry(node, struct btrfs_free_space, - offset_index); - continue; - } - cluster->window_start += bytes; - } else { - ret = entry->offset; - - entry->offset += bytes; - entry->bytes -= bytes; - } - - if (entry->bytes == 0) - rb_erase(&entry->offset_index, &cluster->root); - break; - } -out: - spin_unlock(&cluster->lock); - - if (!ret) - return 0; - - spin_lock(&ctl->tree_lock); - - ctl->free_space -= bytes; - if (entry->bytes == 0) { - ctl->free_extents--; - if (entry->bitmap) { - kfree(entry->bitmap); - ctl->total_bitmaps--; - ctl->op->recalc_thresholds(ctl); - } - kmem_cache_free(btrfs_free_space_cachep, entry); - } - - spin_unlock(&ctl->tree_lock); - - return ret; -} - -static int btrfs_bitmap_cluster(struct btrfs_block_group_cache *block_group, - struct btrfs_free_space *entry, - struct btrfs_free_cluster *cluster, - u64 offset, u64 bytes, - u64 cont1_bytes, u64 min_bytes) -{ - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; - unsigned long next_zero; - unsigned long i; - unsigned long want_bits; - unsigned long min_bits; - unsigned long found_bits; - unsigned long max_bits = 0; - unsigned long start = 0; - unsigned long total_found = 0; - int ret; - - i = offset_to_bit(entry->offset, ctl->unit, - max_t(u64, offset, entry->offset)); - want_bits = bytes_to_bits(bytes, ctl->unit); - min_bits = bytes_to_bits(min_bytes, ctl->unit); - - /* - * Don't bother looking for a cluster in this bitmap if it's heavily - * fragmented. - */ - if (entry->max_extent_size && - entry->max_extent_size < cont1_bytes) - return -ENOSPC; -again: - found_bits = 0; - for_each_set_bit_from(i, entry->bitmap, BITS_PER_BITMAP) { - next_zero = find_next_zero_bit(entry->bitmap, - BITS_PER_BITMAP, i); - if (next_zero - i >= min_bits) { - found_bits = next_zero - i; - if (found_bits > max_bits) - max_bits = found_bits; - break; - } - if (next_zero - i > max_bits) - max_bits = next_zero - i; - i = next_zero; - } - - if (!found_bits) { - entry->max_extent_size = (u64)max_bits * ctl->unit; - return -ENOSPC; - } - - if (!total_found) { - start = i; - cluster->max_size = 0; - } - - total_found += found_bits; - - if (cluster->max_size < found_bits * ctl->unit) - cluster->max_size = found_bits * ctl->unit; - - if (total_found < want_bits || cluster->max_size < cont1_bytes) { - i = next_zero + 1; - goto again; - } - - cluster->window_start = start * ctl->unit + entry->offset; - rb_erase(&entry->offset_index, &ctl->free_space_offset); - ret = tree_insert_offset(&cluster->root, entry->offset, - &entry->offset_index, 1); - ASSERT(!ret); /* -EEXIST; Logic error */ - - trace_btrfs_setup_cluster(block_group, cluster, - total_found * ctl->unit, 1); - return 0; -} - -/* - * This searches the block group for just extents to fill the cluster with. - * Try to find a cluster with at least bytes total bytes, at least one - * extent of cont1_bytes, and other clusters of at least min_bytes. - */ -static noinline int -setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group, - struct btrfs_free_cluster *cluster, - struct list_head *bitmaps, u64 offset, u64 bytes, - u64 cont1_bytes, u64 min_bytes) -{ - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; - struct btrfs_free_space *first = NULL; - struct btrfs_free_space *entry = NULL; - struct btrfs_free_space *last; - struct rb_node *node; - u64 window_free; - u64 max_extent; - u64 total_size = 0; - - entry = tree_search_offset(ctl, offset, 0, 1); - if (!entry) - return -ENOSPC; - - /* - * We don't want bitmaps, so just move along until we find a normal - * extent entry. - */ - while (entry->bitmap || entry->bytes < min_bytes) { - if (entry->bitmap && list_empty(&entry->list)) - list_add_tail(&entry->list, bitmaps); - node = rb_next(&entry->offset_index); - if (!node) - return -ENOSPC; - entry = rb_entry(node, struct btrfs_free_space, offset_index); - } - - window_free = entry->bytes; - max_extent = entry->bytes; - first = entry; - last = entry; - - for (node = rb_next(&entry->offset_index); node; - node = rb_next(&entry->offset_index)) { - entry = rb_entry(node, struct btrfs_free_space, offset_index); - - if (entry->bitmap) { - if (list_empty(&entry->list)) - list_add_tail(&entry->list, bitmaps); - continue; - } - - if (entry->bytes < min_bytes) - continue; - - last = entry; - window_free += entry->bytes; - if (entry->bytes > max_extent) - max_extent = entry->bytes; - } - - if (window_free < bytes || max_extent < cont1_bytes) - return -ENOSPC; - - cluster->window_start = first->offset; - - node = &first->offset_index; - - /* - * now we've found our entries, pull them out of the free space - * cache and put them into the cluster rbtree - */ - do { - int ret; - - entry = rb_entry(node, struct btrfs_free_space, offset_index); - node = rb_next(&entry->offset_index); - if (entry->bitmap || entry->bytes < min_bytes) - continue; - - rb_erase(&entry->offset_index, &ctl->free_space_offset); - ret = tree_insert_offset(&cluster->root, entry->offset, - &entry->offset_index, 0); - total_size += entry->bytes; - ASSERT(!ret); /* -EEXIST; Logic error */ - } while (node && entry != last); - - cluster->max_size = max_extent; - trace_btrfs_setup_cluster(block_group, cluster, total_size, 0); - return 0; -} - -/* - * This specifically looks for bitmaps that may work in the cluster, we assume - * that we have already failed to find extents that will work. - */ -static noinline int -setup_cluster_bitmap(struct btrfs_block_group_cache *block_group, - struct btrfs_free_cluster *cluster, - struct list_head *bitmaps, u64 offset, u64 bytes, - u64 cont1_bytes, u64 min_bytes) -{ - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; - struct btrfs_free_space *entry = NULL; - int ret = -ENOSPC; - u64 bitmap_offset = offset_to_bitmap(ctl, offset); - - if (ctl->total_bitmaps == 0) - return -ENOSPC; - - /* - * The bitmap that covers offset won't be in the list unless offset - * is just its start offset. - */ - if (!list_empty(bitmaps)) - entry = list_first_entry(bitmaps, struct btrfs_free_space, list); - - if (!entry || entry->offset != bitmap_offset) { - entry = tree_search_offset(ctl, bitmap_offset, 1, 0); - if (entry && list_empty(&entry->list)) - list_add(&entry->list, bitmaps); - } - - list_for_each_entry(entry, bitmaps, list) { - if (entry->bytes < bytes) - continue; - ret = btrfs_bitmap_cluster(block_group, entry, cluster, offset, - bytes, cont1_bytes, min_bytes); - if (!ret) - return 0; - } - - /* - * The bitmaps list has all the bitmaps that record free space - * starting after offset, so no more search is required. - */ - return -ENOSPC; -} - -/* - * here we try to find a cluster of blocks in a block group. The goal - * is to find at least bytes+empty_size. - * We might not find them all in one contiguous area. - * - * returns zero and sets up cluster if things worked out, otherwise - * it returns -enospc - */ -int btrfs_find_space_cluster(struct btrfs_root *root, - struct btrfs_block_group_cache *block_group, - struct btrfs_free_cluster *cluster, - u64 offset, u64 bytes, u64 empty_size) -{ - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; - struct btrfs_free_space *entry, *tmp; - LIST_HEAD(bitmaps); - u64 min_bytes; - u64 cont1_bytes; - int ret; - - /* - * Choose the minimum extent size we'll require for this - * cluster. For SSD_SPREAD, don't allow any fragmentation. - * For metadata, allow allocates with smaller extents. For - * data, keep it dense. - */ - if (btrfs_test_opt(root->fs_info, SSD_SPREAD)) { - cont1_bytes = min_bytes = bytes + empty_size; - } else if (block_group->flags & BTRFS_BLOCK_GROUP_METADATA) { - cont1_bytes = bytes; - min_bytes = block_group->sectorsize; - } else { - cont1_bytes = max(bytes, (bytes + empty_size) >> 2); - min_bytes = block_group->sectorsize; - } - - spin_lock(&ctl->tree_lock); - - /* - * If we know we don't have enough space to make a cluster don't even - * bother doing all the work to try and find one. - */ - if (ctl->free_space < bytes) { - spin_unlock(&ctl->tree_lock); - return -ENOSPC; - } - - spin_lock(&cluster->lock); - - /* someone already found a cluster, hooray */ - if (cluster->block_group) { - ret = 0; - goto out; - } - - trace_btrfs_find_cluster(block_group, offset, bytes, empty_size, - min_bytes); - - ret = setup_cluster_no_bitmap(block_group, cluster, &bitmaps, offset, - bytes + empty_size, - cont1_bytes, min_bytes); - if (ret) - ret = setup_cluster_bitmap(block_group, cluster, &bitmaps, - offset, bytes + empty_size, - cont1_bytes, min_bytes); - - /* Clear our temporary list */ - list_for_each_entry_safe(entry, tmp, &bitmaps, list) - list_del_init(&entry->list); - - if (!ret) { - atomic_inc(&block_group->count); - list_add_tail(&cluster->block_group_list, - &block_group->cluster_list); - cluster->block_group = block_group; - } else { - trace_btrfs_failed_cluster_setup(block_group); - } -out: - spin_unlock(&cluster->lock); - spin_unlock(&ctl->tree_lock); - - return ret; -} - -/* - * simple code to zero out a cluster - */ -void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster) -{ - spin_lock_init(&cluster->lock); - spin_lock_init(&cluster->refill_lock); - cluster->root = RB_ROOT; - cluster->max_size = 0; - cluster->fragmented = false; - INIT_LIST_HEAD(&cluster->block_group_list); - cluster->block_group = NULL; -} - -static int do_trimming(struct btrfs_block_group_cache *block_group, - u64 *total_trimmed, u64 start, u64 bytes, - u64 reserved_start, u64 reserved_bytes, - struct btrfs_trim_range *trim_entry) -{ - struct btrfs_space_info *space_info = block_group->space_info; - struct btrfs_fs_info *fs_info = block_group->fs_info; - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; - int ret; - int update = 0; - u64 trimmed = 0; - - spin_lock(&space_info->lock); - spin_lock(&block_group->lock); - if (!block_group->ro) { - block_group->reserved += reserved_bytes; - space_info->bytes_reserved += reserved_bytes; - update = 1; - } - spin_unlock(&block_group->lock); - spin_unlock(&space_info->lock); - - ret = btrfs_discard_extent(fs_info->extent_root, - start, bytes, &trimmed); - if (!ret) - *total_trimmed += trimmed; - - mutex_lock(&ctl->cache_writeout_mutex); - btrfs_add_free_space(block_group, reserved_start, reserved_bytes); - list_del(&trim_entry->list); - mutex_unlock(&ctl->cache_writeout_mutex); - - if (update) { - spin_lock(&space_info->lock); - spin_lock(&block_group->lock); - if (block_group->ro) - space_info->bytes_readonly += reserved_bytes; - block_group->reserved -= reserved_bytes; - space_info->bytes_reserved -= reserved_bytes; - spin_unlock(&space_info->lock); - spin_unlock(&block_group->lock); - } - - return ret; -} - -static int trim_no_bitmap(struct btrfs_block_group_cache *block_group, - u64 *total_trimmed, u64 start, u64 end, u64 minlen) -{ - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; - struct btrfs_free_space *entry; - struct rb_node *node; - int ret = 0; - u64 extent_start; - u64 extent_bytes; - u64 bytes; - - while (start < end) { - struct btrfs_trim_range trim_entry; - - mutex_lock(&ctl->cache_writeout_mutex); - spin_lock(&ctl->tree_lock); - - if (ctl->free_space < minlen) { - spin_unlock(&ctl->tree_lock); - mutex_unlock(&ctl->cache_writeout_mutex); - break; - } - - entry = tree_search_offset(ctl, start, 0, 1); - if (!entry) { - spin_unlock(&ctl->tree_lock); - mutex_unlock(&ctl->cache_writeout_mutex); - break; - } - - /* skip bitmaps */ - while (entry->bitmap) { - node = rb_next(&entry->offset_index); - if (!node) { - spin_unlock(&ctl->tree_lock); - mutex_unlock(&ctl->cache_writeout_mutex); - goto out; - } - entry = rb_entry(node, struct btrfs_free_space, - offset_index); - } - - if (entry->offset >= end) { - spin_unlock(&ctl->tree_lock); - mutex_unlock(&ctl->cache_writeout_mutex); - break; - } - - extent_start = entry->offset; - extent_bytes = entry->bytes; - start = max(start, extent_start); - bytes = min(extent_start + extent_bytes, end) - start; - if (bytes < minlen) { - spin_unlock(&ctl->tree_lock); - mutex_unlock(&ctl->cache_writeout_mutex); - goto next; - } - - unlink_free_space(ctl, entry); - kmem_cache_free(btrfs_free_space_cachep, entry); - - spin_unlock(&ctl->tree_lock); - trim_entry.start = extent_start; - trim_entry.bytes = extent_bytes; - list_add_tail(&trim_entry.list, &ctl->trimming_ranges); - mutex_unlock(&ctl->cache_writeout_mutex); - - ret = do_trimming(block_group, total_trimmed, start, bytes, - extent_start, extent_bytes, &trim_entry); - if (ret) - break; -next: - start += bytes; - - if (fatal_signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - - cond_resched(); - } -out: - return ret; -} - -static int trim_bitmaps(struct btrfs_block_group_cache *block_group, - u64 *total_trimmed, u64 start, u64 end, u64 minlen) -{ - struct btrfs_free_space_ctl *ctl = block_group->free_space_ctl; - struct btrfs_free_space *entry; - int ret = 0; - int ret2; - u64 bytes; - u64 offset = offset_to_bitmap(ctl, start); - - while (offset < end) { - bool next_bitmap = false; - struct btrfs_trim_range trim_entry; - - mutex_lock(&ctl->cache_writeout_mutex); - spin_lock(&ctl->tree_lock); - - if (ctl->free_space < minlen) { - spin_unlock(&ctl->tree_lock); - mutex_unlock(&ctl->cache_writeout_mutex); - break; - } - - entry = tree_search_offset(ctl, offset, 1, 0); - if (!entry) { - spin_unlock(&ctl->tree_lock); - mutex_unlock(&ctl->cache_writeout_mutex); - next_bitmap = true; - goto next; - } - - bytes = minlen; - ret2 = search_bitmap(ctl, entry, &start, &bytes, false); - if (ret2 || start >= end) { - spin_unlock(&ctl->tree_lock); - mutex_unlock(&ctl->cache_writeout_mutex); - next_bitmap = true; - goto next; - } - - bytes = min(bytes, end - start); - if (bytes < minlen) { - spin_unlock(&ctl->tree_lock); - mutex_unlock(&ctl->cache_writeout_mutex); - goto next; - } - - bitmap_clear_bits(ctl, entry, start, bytes); - if (entry->bytes == 0) - free_bitmap(ctl, entry); - - spin_unlock(&ctl->tree_lock); - trim_entry.start = start; - trim_entry.bytes = bytes; - list_add_tail(&trim_entry.list, &ctl->trimming_ranges); - mutex_unlock(&ctl->cache_writeout_mutex); - - ret = do_trimming(block_group, total_trimmed, start, bytes, - start, bytes, &trim_entry); - if (ret) - break; -next: - if (next_bitmap) { - offset += BITS_PER_BITMAP * ctl->unit; - } else { - start += bytes; - if (start >= offset + BITS_PER_BITMAP * ctl->unit) - offset += BITS_PER_BITMAP * ctl->unit; - } - - if (fatal_signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - - cond_resched(); - } - - return ret; -} - -void btrfs_get_block_group_trimming(struct btrfs_block_group_cache *cache) -{ - atomic_inc(&cache->trimming); -} - -void btrfs_put_block_group_trimming(struct btrfs_block_group_cache *block_group) -{ - struct extent_map_tree *em_tree; - struct extent_map *em; - bool cleanup; - - spin_lock(&block_group->lock); - cleanup = (atomic_dec_and_test(&block_group->trimming) && - block_group->removed); - spin_unlock(&block_group->lock); - - if (cleanup) { - lock_chunks(block_group->fs_info->chunk_root); - em_tree = &block_group->fs_info->mapping_tree.map_tree; - write_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, block_group->key.objectid, - 1); - BUG_ON(!em); /* logic error, can't happen */ - /* - * remove_extent_mapping() will delete us from the pinned_chunks - * list, which is protected by the chunk mutex. - */ - remove_extent_mapping(em_tree, em); - write_unlock(&em_tree->lock); - unlock_chunks(block_group->fs_info->chunk_root); - - /* once for us and once for the tree */ - free_extent_map(em); - free_extent_map(em); - - /* - * We've left one free space entry and other tasks trimming - * this block group have left 1 entry each one. Free them. - */ - __btrfs_remove_free_space_cache(block_group->free_space_ctl); - } -} - -int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, - u64 *trimmed, u64 start, u64 end, u64 minlen) -{ - int ret; - - *trimmed = 0; - - spin_lock(&block_group->lock); - if (block_group->removed) { - spin_unlock(&block_group->lock); - return 0; - } - btrfs_get_block_group_trimming(block_group); - spin_unlock(&block_group->lock); - - ret = trim_no_bitmap(block_group, trimmed, start, end, minlen); - if (ret) - goto out; - - ret = trim_bitmaps(block_group, trimmed, start, end, minlen); -out: - btrfs_put_block_group_trimming(block_group); - return ret; -} - -/* - * Find the left-most item in the cache tree, and then return the - * smallest inode number in the item. - * - * Note: the returned inode number may not be the smallest one in - * the tree, if the left-most item is a bitmap. - */ -u64 btrfs_find_ino_for_alloc(struct btrfs_root *fs_root) -{ - struct btrfs_free_space_ctl *ctl = fs_root->free_ino_ctl; - struct btrfs_free_space *entry = NULL; - u64 ino = 0; - - spin_lock(&ctl->tree_lock); - - if (RB_EMPTY_ROOT(&ctl->free_space_offset)) - goto out; - - entry = rb_entry(rb_first(&ctl->free_space_offset), - struct btrfs_free_space, offset_index); - - if (!entry->bitmap) { - ino = entry->offset; - - unlink_free_space(ctl, entry); - entry->offset++; - entry->bytes--; - if (!entry->bytes) - kmem_cache_free(btrfs_free_space_cachep, entry); - else - link_free_space(ctl, entry); - } else { - u64 offset = 0; - u64 count = 1; - int ret; - - ret = search_bitmap(ctl, entry, &offset, &count, true); - /* Logic error; Should be empty if it can't find anything */ - ASSERT(!ret); - - ino = offset; - bitmap_clear_bits(ctl, entry, offset, 1); - if (entry->bytes == 0) - free_bitmap(ctl, entry); - } -out: - spin_unlock(&ctl->tree_lock); - - return ino; -} - -struct inode *lookup_free_ino_inode(struct btrfs_root *root, - struct btrfs_path *path) -{ - struct inode *inode = NULL; - - spin_lock(&root->ino_cache_lock); - if (root->ino_cache_inode) - inode = igrab(root->ino_cache_inode); - spin_unlock(&root->ino_cache_lock); - if (inode) - return inode; - - inode = __lookup_free_space_inode(root, path, 0); - if (IS_ERR(inode)) - return inode; - - spin_lock(&root->ino_cache_lock); - if (!btrfs_fs_closing(root->fs_info)) - root->ino_cache_inode = igrab(inode); - spin_unlock(&root->ino_cache_lock); - - return inode; -} - -int create_free_ino_inode(struct btrfs_root *root, - struct btrfs_trans_handle *trans, - struct btrfs_path *path) -{ - return __create_free_space_inode(root, trans, path, - BTRFS_FREE_INO_OBJECTID, 0); -} - -int load_free_ino_cache(struct btrfs_fs_info *fs_info, struct btrfs_root *root) -{ - struct btrfs_free_space_ctl *ctl = root->free_ino_ctl; - struct btrfs_path *path; - struct inode *inode; - int ret = 0; - u64 root_gen = btrfs_root_generation(&root->root_item); - - if (!btrfs_test_opt(root->fs_info, INODE_MAP_CACHE)) - return 0; - - /* - * If we're unmounting then just return, since this does a search on the - * normal root and not the commit root and we could deadlock. - */ - if (btrfs_fs_closing(fs_info)) - return 0; - - path = btrfs_alloc_path(); - if (!path) - return 0; - - inode = lookup_free_ino_inode(root, path); - if (IS_ERR(inode)) - goto out; - - if (root_gen != BTRFS_I(inode)->generation) - goto out_put; - - ret = __load_free_space_cache(root, inode, ctl, path, 0); - - if (ret < 0) - btrfs_err(fs_info, - "failed to load free ino cache for root %llu", - root->root_key.objectid); -out_put: - iput(inode); -out: - btrfs_free_path(path); - return ret; -} - -int btrfs_write_out_ino_cache(struct btrfs_root *root, - struct btrfs_trans_handle *trans, - struct btrfs_path *path, - struct inode *inode) -{ - struct btrfs_free_space_ctl *ctl = root->free_ino_ctl; - int ret; - struct btrfs_io_ctl io_ctl; - bool release_metadata = true; - - if (!btrfs_test_opt(root->fs_info, INODE_MAP_CACHE)) - return 0; - - memset(&io_ctl, 0, sizeof(io_ctl)); - ret = __btrfs_write_out_cache(root, inode, ctl, NULL, &io_ctl, - trans, path, 0); - if (!ret) { - /* - * At this point writepages() didn't error out, so our metadata - * reservation is released when the writeback finishes, at - * inode.c:btrfs_finish_ordered_io(), regardless of it finishing - * with or without an error. - */ - release_metadata = false; - ret = btrfs_wait_cache_io(root, trans, NULL, &io_ctl, path, 0); - } - - if (ret) { - if (release_metadata) - btrfs_delalloc_release_metadata(inode, inode->i_size); -#ifdef DEBUG - btrfs_err(root->fs_info, - "failed to write free ino cache for root %llu", - root->root_key.objectid); -#endif - } - - return ret; -} - -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS -/* - * Use this if you need to make a bitmap or extent entry specifically, it - * doesn't do any of the merging that add_free_space does, this acts a lot like - * how the free space cache loading stuff works, so you can get really weird - * configurations. - */ -int test_add_free_space_entry(struct btrfs_block_group_cache *cache, - u64 offset, u64 bytes, bool bitmap) -{ - struct btrfs_free_space_ctl *ctl = cache->free_space_ctl; - struct btrfs_free_space *info = NULL, *bitmap_info; - void *map = NULL; - u64 bytes_added; - int ret; - -again: - if (!info) { - info = kmem_cache_zalloc(btrfs_free_space_cachep, GFP_NOFS); - if (!info) - return -ENOMEM; - } - - if (!bitmap) { - spin_lock(&ctl->tree_lock); - info->offset = offset; - info->bytes = bytes; - info->max_extent_size = 0; - ret = link_free_space(ctl, info); - spin_unlock(&ctl->tree_lock); - if (ret) - kmem_cache_free(btrfs_free_space_cachep, info); - return ret; - } - - if (!map) { - map = kzalloc(PAGE_SIZE, GFP_NOFS); - if (!map) { - kmem_cache_free(btrfs_free_space_cachep, info); - return -ENOMEM; - } - } - - spin_lock(&ctl->tree_lock); - bitmap_info = tree_search_offset(ctl, offset_to_bitmap(ctl, offset), - 1, 0); - if (!bitmap_info) { - info->bitmap = map; - map = NULL; - add_new_bitmap(ctl, info, offset); - bitmap_info = info; - info = NULL; - } - - bytes_added = add_bytes_to_bitmap(ctl, bitmap_info, offset, bytes); - - bytes -= bytes_added; - offset += bytes_added; - spin_unlock(&ctl->tree_lock); - - if (bytes) - goto again; - - if (info) - kmem_cache_free(btrfs_free_space_cachep, info); - if (map) - kfree(map); - return 0; -} - -/* - * Checks to see if the given range is in the free space cache. This is really - * just used to check the absence of space, so if there is free space in the - * range at all we will return 1. - */ -int test_check_exists(struct btrfs_block_group_cache *cache, - u64 offset, u64 bytes) -{ - struct btrfs_free_space_ctl *ctl = cache->free_space_ctl; - struct btrfs_free_space *info; - int ret = 0; - - spin_lock(&ctl->tree_lock); - info = tree_search_offset(ctl, offset, 0, 0); - if (!info) { - info = tree_search_offset(ctl, offset_to_bitmap(ctl, offset), - 1, 0); - if (!info) - goto out; - } - -have_info: - if (info->bitmap) { - u64 bit_off, bit_bytes; - struct rb_node *n; - struct btrfs_free_space *tmp; - - bit_off = offset; - bit_bytes = ctl->unit; - ret = search_bitmap(ctl, info, &bit_off, &bit_bytes, false); - if (!ret) { - if (bit_off == offset) { - ret = 1; - goto out; - } else if (bit_off > offset && - offset + bytes > bit_off) { - ret = 1; - goto out; - } - } - - n = rb_prev(&info->offset_index); - while (n) { - tmp = rb_entry(n, struct btrfs_free_space, - offset_index); - if (tmp->offset + tmp->bytes < offset) - break; - if (offset + bytes < tmp->offset) { - n = rb_prev(&tmp->offset_index); - continue; - } - info = tmp; - goto have_info; - } - - n = rb_next(&info->offset_index); - while (n) { - tmp = rb_entry(n, struct btrfs_free_space, - offset_index); - if (offset + bytes < tmp->offset) - break; - if (tmp->offset + tmp->bytes < offset) { - n = rb_next(&tmp->offset_index); - continue; - } - info = tmp; - goto have_info; - } - - ret = 0; - goto out; - } - - if (info->offset == offset) { - ret = 1; - goto out; - } - - if (offset > info->offset && offset < info->offset + info->bytes) - ret = 1; -out: - spin_unlock(&ctl->tree_lock); - return ret; -} -#endif /* CONFIG_BTRFS_FS_RUN_SANITY_TESTS */ diff --git a/src/linux/fs/btrfs/free-space-cache.h b/src/linux/fs/btrfs/free-space-cache.h deleted file mode 100644 index 363fdd9..0000000 --- a/src/linux/fs/btrfs/free-space-cache.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2009 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __BTRFS_FREE_SPACE_CACHE -#define __BTRFS_FREE_SPACE_CACHE - -struct btrfs_free_space { - struct rb_node offset_index; - u64 offset; - u64 bytes; - u64 max_extent_size; - unsigned long *bitmap; - struct list_head list; -}; - -struct btrfs_free_space_ctl { - spinlock_t tree_lock; - struct rb_root free_space_offset; - u64 free_space; - int extents_thresh; - int free_extents; - int total_bitmaps; - int unit; - u64 start; - const struct btrfs_free_space_op *op; - void *private; - struct mutex cache_writeout_mutex; - struct list_head trimming_ranges; -}; - -struct btrfs_free_space_op { - void (*recalc_thresholds)(struct btrfs_free_space_ctl *ctl); - bool (*use_bitmap)(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info); -}; - -struct btrfs_io_ctl; - -struct inode *lookup_free_space_inode(struct btrfs_root *root, - struct btrfs_block_group_cache - *block_group, struct btrfs_path *path); -int create_free_space_inode(struct btrfs_root *root, - struct btrfs_trans_handle *trans, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path); - -int btrfs_check_trunc_cache_free_space(struct btrfs_root *root, - struct btrfs_block_rsv *rsv); -int btrfs_truncate_free_space_cache(struct btrfs_root *root, - struct btrfs_trans_handle *trans, - struct btrfs_block_group_cache *block_group, - struct inode *inode); -int load_free_space_cache(struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group); -int btrfs_wait_cache_io(struct btrfs_root *root, - struct btrfs_trans_handle *trans, - struct btrfs_block_group_cache *block_group, - struct btrfs_io_ctl *io_ctl, - struct btrfs_path *path, u64 offset); -int btrfs_write_out_cache(struct btrfs_root *root, - struct btrfs_trans_handle *trans, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path); -struct inode *lookup_free_ino_inode(struct btrfs_root *root, - struct btrfs_path *path); -int create_free_ino_inode(struct btrfs_root *root, - struct btrfs_trans_handle *trans, - struct btrfs_path *path); -int load_free_ino_cache(struct btrfs_fs_info *fs_info, - struct btrfs_root *root); -int btrfs_write_out_ino_cache(struct btrfs_root *root, - struct btrfs_trans_handle *trans, - struct btrfs_path *path, - struct inode *inode); - -void btrfs_init_free_space_ctl(struct btrfs_block_group_cache *block_group); -int __btrfs_add_free_space(struct btrfs_fs_info *fs_info, - struct btrfs_free_space_ctl *ctl, - u64 bytenr, u64 size); -static inline int -btrfs_add_free_space(struct btrfs_block_group_cache *block_group, - u64 bytenr, u64 size) -{ - return __btrfs_add_free_space(block_group->fs_info, - block_group->free_space_ctl, - bytenr, size); -} -int btrfs_remove_free_space(struct btrfs_block_group_cache *block_group, - u64 bytenr, u64 size); -void __btrfs_remove_free_space_cache(struct btrfs_free_space_ctl *ctl); -void btrfs_remove_free_space_cache(struct btrfs_block_group_cache - *block_group); -u64 btrfs_find_space_for_alloc(struct btrfs_block_group_cache *block_group, - u64 offset, u64 bytes, u64 empty_size, - u64 *max_extent_size); -u64 btrfs_find_ino_for_alloc(struct btrfs_root *fs_root); -void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group, - u64 bytes); -int btrfs_find_space_cluster(struct btrfs_root *root, - struct btrfs_block_group_cache *block_group, - struct btrfs_free_cluster *cluster, - u64 offset, u64 bytes, u64 empty_size); -void btrfs_init_free_cluster(struct btrfs_free_cluster *cluster); -u64 btrfs_alloc_from_cluster(struct btrfs_block_group_cache *block_group, - struct btrfs_free_cluster *cluster, u64 bytes, - u64 min_start, u64 *max_extent_size); -int btrfs_return_cluster_to_free_space( - struct btrfs_block_group_cache *block_group, - struct btrfs_free_cluster *cluster); -int btrfs_trim_block_group(struct btrfs_block_group_cache *block_group, - u64 *trimmed, u64 start, u64 end, u64 minlen); - -/* Support functions for running our sanity tests */ -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS -int test_add_free_space_entry(struct btrfs_block_group_cache *cache, - u64 offset, u64 bytes, bool bitmap); -int test_check_exists(struct btrfs_block_group_cache *cache, - u64 offset, u64 bytes); -#endif - -#endif diff --git a/src/linux/fs/btrfs/free-space-tree.c b/src/linux/fs/btrfs/free-space-tree.c deleted file mode 100644 index 57401b4..0000000 --- a/src/linux/fs/btrfs/free-space-tree.c +++ /dev/null @@ -1,1610 +0,0 @@ -/* - * Copyright (C) 2015 Facebook. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include "ctree.h" -#include "disk-io.h" -#include "locking.h" -#include "free-space-tree.h" -#include "transaction.h" - -static int __add_block_group_free_space(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path); - -void set_free_space_tree_thresholds(struct btrfs_block_group_cache *cache) -{ - u32 bitmap_range; - size_t bitmap_size; - u64 num_bitmaps, total_bitmap_size; - - /* - * We convert to bitmaps when the disk space required for using extents - * exceeds that required for using bitmaps. - */ - bitmap_range = cache->sectorsize * BTRFS_FREE_SPACE_BITMAP_BITS; - num_bitmaps = div_u64(cache->key.offset + bitmap_range - 1, - bitmap_range); - bitmap_size = sizeof(struct btrfs_item) + BTRFS_FREE_SPACE_BITMAP_SIZE; - total_bitmap_size = num_bitmaps * bitmap_size; - cache->bitmap_high_thresh = div_u64(total_bitmap_size, - sizeof(struct btrfs_item)); - - /* - * We allow for a small buffer between the high threshold and low - * threshold to avoid thrashing back and forth between the two formats. - */ - if (cache->bitmap_high_thresh > 100) - cache->bitmap_low_thresh = cache->bitmap_high_thresh - 100; - else - cache->bitmap_low_thresh = 0; -} - -static int add_new_free_space_info(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path) -{ - struct btrfs_root *root = fs_info->free_space_root; - struct btrfs_free_space_info *info; - struct btrfs_key key; - struct extent_buffer *leaf; - int ret; - - key.objectid = block_group->key.objectid; - key.type = BTRFS_FREE_SPACE_INFO_KEY; - key.offset = block_group->key.offset; - - ret = btrfs_insert_empty_item(trans, root, path, &key, sizeof(*info)); - if (ret) - goto out; - - leaf = path->nodes[0]; - info = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_free_space_info); - btrfs_set_free_space_extent_count(leaf, info, 0); - btrfs_set_free_space_flags(leaf, info, 0); - btrfs_mark_buffer_dirty(leaf); - - ret = 0; -out: - btrfs_release_path(path); - return ret; -} - -struct btrfs_free_space_info * -search_free_space_info(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path, int cow) -{ - struct btrfs_root *root = fs_info->free_space_root; - struct btrfs_key key; - int ret; - - key.objectid = block_group->key.objectid; - key.type = BTRFS_FREE_SPACE_INFO_KEY; - key.offset = block_group->key.offset; - - ret = btrfs_search_slot(trans, root, &key, path, 0, cow); - if (ret < 0) - return ERR_PTR(ret); - if (ret != 0) { - btrfs_warn(fs_info, "missing free space info for %llu", - block_group->key.objectid); - ASSERT(0); - return ERR_PTR(-ENOENT); - } - - return btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_free_space_info); -} - -/* - * btrfs_search_slot() but we're looking for the greatest key less than the - * passed key. - */ -static int btrfs_search_prev_slot(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_key *key, struct btrfs_path *p, - int ins_len, int cow) -{ - int ret; - - ret = btrfs_search_slot(trans, root, key, p, ins_len, cow); - if (ret < 0) - return ret; - - if (ret == 0) { - ASSERT(0); - return -EIO; - } - - if (p->slots[0] == 0) { - ASSERT(0); - return -EIO; - } - p->slots[0]--; - - return 0; -} - -static inline u32 free_space_bitmap_size(u64 size, u32 sectorsize) -{ - return DIV_ROUND_UP((u32)div_u64(size, sectorsize), BITS_PER_BYTE); -} - -static u8 *alloc_bitmap(u32 bitmap_size) -{ - void *mem; - - /* - * The allocation size varies, observed numbers were < 4K up to 16K. - * Using vmalloc unconditionally would be too heavy, we'll try - * contiguous allocations first. - */ - if (bitmap_size <= PAGE_SIZE) - return kzalloc(bitmap_size, GFP_NOFS); - - mem = kzalloc(bitmap_size, GFP_NOFS | __GFP_NOWARN); - if (mem) - return mem; - - return __vmalloc(bitmap_size, GFP_NOFS | __GFP_HIGHMEM | __GFP_ZERO, - PAGE_KERNEL); -} - -int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path) -{ - struct btrfs_root *root = fs_info->free_space_root; - struct btrfs_free_space_info *info; - struct btrfs_key key, found_key; - struct extent_buffer *leaf; - u8 *bitmap, *bitmap_cursor; - u64 start, end; - u64 bitmap_range, i; - u32 bitmap_size, flags, expected_extent_count; - u32 extent_count = 0; - int done = 0, nr; - int ret; - - bitmap_size = free_space_bitmap_size(block_group->key.offset, - block_group->sectorsize); - bitmap = alloc_bitmap(bitmap_size); - if (!bitmap) { - ret = -ENOMEM; - goto out; - } - - start = block_group->key.objectid; - end = block_group->key.objectid + block_group->key.offset; - - key.objectid = end - 1; - key.type = (u8)-1; - key.offset = (u64)-1; - - while (!done) { - ret = btrfs_search_prev_slot(trans, root, &key, path, -1, 1); - if (ret) - goto out; - - leaf = path->nodes[0]; - nr = 0; - path->slots[0]++; - while (path->slots[0] > 0) { - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0] - 1); - - if (found_key.type == BTRFS_FREE_SPACE_INFO_KEY) { - ASSERT(found_key.objectid == block_group->key.objectid); - ASSERT(found_key.offset == block_group->key.offset); - done = 1; - break; - } else if (found_key.type == BTRFS_FREE_SPACE_EXTENT_KEY) { - u64 first, last; - - ASSERT(found_key.objectid >= start); - ASSERT(found_key.objectid < end); - ASSERT(found_key.objectid + found_key.offset <= end); - - first = div_u64(found_key.objectid - start, - block_group->sectorsize); - last = div_u64(found_key.objectid + found_key.offset - start, - block_group->sectorsize); - le_bitmap_set(bitmap, first, last - first); - - extent_count++; - nr++; - path->slots[0]--; - } else { - ASSERT(0); - } - } - - ret = btrfs_del_items(trans, root, path, path->slots[0], nr); - if (ret) - goto out; - btrfs_release_path(path); - } - - info = search_free_space_info(trans, fs_info, block_group, path, 1); - if (IS_ERR(info)) { - ret = PTR_ERR(info); - goto out; - } - leaf = path->nodes[0]; - flags = btrfs_free_space_flags(leaf, info); - flags |= BTRFS_FREE_SPACE_USING_BITMAPS; - btrfs_set_free_space_flags(leaf, info, flags); - expected_extent_count = btrfs_free_space_extent_count(leaf, info); - btrfs_mark_buffer_dirty(leaf); - btrfs_release_path(path); - - if (extent_count != expected_extent_count) { - btrfs_err(fs_info, - "incorrect extent count for %llu; counted %u, expected %u", - block_group->key.objectid, extent_count, - expected_extent_count); - ASSERT(0); - ret = -EIO; - goto out; - } - - bitmap_cursor = bitmap; - bitmap_range = block_group->sectorsize * BTRFS_FREE_SPACE_BITMAP_BITS; - i = start; - while (i < end) { - unsigned long ptr; - u64 extent_size; - u32 data_size; - - extent_size = min(end - i, bitmap_range); - data_size = free_space_bitmap_size(extent_size, - block_group->sectorsize); - - key.objectid = i; - key.type = BTRFS_FREE_SPACE_BITMAP_KEY; - key.offset = extent_size; - - ret = btrfs_insert_empty_item(trans, root, path, &key, - data_size); - if (ret) - goto out; - - leaf = path->nodes[0]; - ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); - write_extent_buffer(leaf, bitmap_cursor, ptr, - data_size); - btrfs_mark_buffer_dirty(leaf); - btrfs_release_path(path); - - i += extent_size; - bitmap_cursor += data_size; - } - - ret = 0; -out: - kvfree(bitmap); - if (ret) - btrfs_abort_transaction(trans, ret); - return ret; -} - -int convert_free_space_to_extents(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path) -{ - struct btrfs_root *root = fs_info->free_space_root; - struct btrfs_free_space_info *info; - struct btrfs_key key, found_key; - struct extent_buffer *leaf; - u8 *bitmap; - u64 start, end; - /* Initialize to silence GCC. */ - u64 extent_start = 0; - u64 offset; - u32 bitmap_size, flags, expected_extent_count; - int prev_bit = 0, bit, bitnr; - u32 extent_count = 0; - int done = 0, nr; - int ret; - - bitmap_size = free_space_bitmap_size(block_group->key.offset, - block_group->sectorsize); - bitmap = alloc_bitmap(bitmap_size); - if (!bitmap) { - ret = -ENOMEM; - goto out; - } - - start = block_group->key.objectid; - end = block_group->key.objectid + block_group->key.offset; - - key.objectid = end - 1; - key.type = (u8)-1; - key.offset = (u64)-1; - - while (!done) { - ret = btrfs_search_prev_slot(trans, root, &key, path, -1, 1); - if (ret) - goto out; - - leaf = path->nodes[0]; - nr = 0; - path->slots[0]++; - while (path->slots[0] > 0) { - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0] - 1); - - if (found_key.type == BTRFS_FREE_SPACE_INFO_KEY) { - ASSERT(found_key.objectid == block_group->key.objectid); - ASSERT(found_key.offset == block_group->key.offset); - done = 1; - break; - } else if (found_key.type == BTRFS_FREE_SPACE_BITMAP_KEY) { - unsigned long ptr; - u8 *bitmap_cursor; - u32 bitmap_pos, data_size; - - ASSERT(found_key.objectid >= start); - ASSERT(found_key.objectid < end); - ASSERT(found_key.objectid + found_key.offset <= end); - - bitmap_pos = div_u64(found_key.objectid - start, - block_group->sectorsize * - BITS_PER_BYTE); - bitmap_cursor = bitmap + bitmap_pos; - data_size = free_space_bitmap_size(found_key.offset, - block_group->sectorsize); - - ptr = btrfs_item_ptr_offset(leaf, path->slots[0] - 1); - read_extent_buffer(leaf, bitmap_cursor, ptr, - data_size); - - nr++; - path->slots[0]--; - } else { - ASSERT(0); - } - } - - ret = btrfs_del_items(trans, root, path, path->slots[0], nr); - if (ret) - goto out; - btrfs_release_path(path); - } - - info = search_free_space_info(trans, fs_info, block_group, path, 1); - if (IS_ERR(info)) { - ret = PTR_ERR(info); - goto out; - } - leaf = path->nodes[0]; - flags = btrfs_free_space_flags(leaf, info); - flags &= ~BTRFS_FREE_SPACE_USING_BITMAPS; - btrfs_set_free_space_flags(leaf, info, flags); - expected_extent_count = btrfs_free_space_extent_count(leaf, info); - btrfs_mark_buffer_dirty(leaf); - btrfs_release_path(path); - - offset = start; - bitnr = 0; - while (offset < end) { - bit = !!le_test_bit(bitnr, bitmap); - if (prev_bit == 0 && bit == 1) { - extent_start = offset; - } else if (prev_bit == 1 && bit == 0) { - key.objectid = extent_start; - key.type = BTRFS_FREE_SPACE_EXTENT_KEY; - key.offset = offset - extent_start; - - ret = btrfs_insert_empty_item(trans, root, path, &key, 0); - if (ret) - goto out; - btrfs_release_path(path); - - extent_count++; - } - prev_bit = bit; - offset += block_group->sectorsize; - bitnr++; - } - if (prev_bit == 1) { - key.objectid = extent_start; - key.type = BTRFS_FREE_SPACE_EXTENT_KEY; - key.offset = end - extent_start; - - ret = btrfs_insert_empty_item(trans, root, path, &key, 0); - if (ret) - goto out; - btrfs_release_path(path); - - extent_count++; - } - - if (extent_count != expected_extent_count) { - btrfs_err(fs_info, - "incorrect extent count for %llu; counted %u, expected %u", - block_group->key.objectid, extent_count, - expected_extent_count); - ASSERT(0); - ret = -EIO; - goto out; - } - - ret = 0; -out: - kvfree(bitmap); - if (ret) - btrfs_abort_transaction(trans, ret); - return ret; -} - -static int update_free_space_extent_count(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path, - int new_extents) -{ - struct btrfs_free_space_info *info; - u32 flags; - u32 extent_count; - int ret = 0; - - if (new_extents == 0) - return 0; - - info = search_free_space_info(trans, fs_info, block_group, path, 1); - if (IS_ERR(info)) { - ret = PTR_ERR(info); - goto out; - } - flags = btrfs_free_space_flags(path->nodes[0], info); - extent_count = btrfs_free_space_extent_count(path->nodes[0], info); - - extent_count += new_extents; - btrfs_set_free_space_extent_count(path->nodes[0], info, extent_count); - btrfs_mark_buffer_dirty(path->nodes[0]); - btrfs_release_path(path); - - if (!(flags & BTRFS_FREE_SPACE_USING_BITMAPS) && - extent_count > block_group->bitmap_high_thresh) { - ret = convert_free_space_to_bitmaps(trans, fs_info, block_group, - path); - } else if ((flags & BTRFS_FREE_SPACE_USING_BITMAPS) && - extent_count < block_group->bitmap_low_thresh) { - ret = convert_free_space_to_extents(trans, fs_info, block_group, - path); - } - -out: - return ret; -} - -int free_space_test_bit(struct btrfs_block_group_cache *block_group, - struct btrfs_path *path, u64 offset) -{ - struct extent_buffer *leaf; - struct btrfs_key key; - u64 found_start, found_end; - unsigned long ptr, i; - - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - ASSERT(key.type == BTRFS_FREE_SPACE_BITMAP_KEY); - - found_start = key.objectid; - found_end = key.objectid + key.offset; - ASSERT(offset >= found_start && offset < found_end); - - ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); - i = div_u64(offset - found_start, block_group->sectorsize); - return !!extent_buffer_test_bit(leaf, ptr, i); -} - -static void free_space_set_bits(struct btrfs_block_group_cache *block_group, - struct btrfs_path *path, u64 *start, u64 *size, - int bit) -{ - struct extent_buffer *leaf; - struct btrfs_key key; - u64 end = *start + *size; - u64 found_start, found_end; - unsigned long ptr, first, last; - - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - ASSERT(key.type == BTRFS_FREE_SPACE_BITMAP_KEY); - - found_start = key.objectid; - found_end = key.objectid + key.offset; - ASSERT(*start >= found_start && *start < found_end); - ASSERT(end > found_start); - - if (end > found_end) - end = found_end; - - ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); - first = div_u64(*start - found_start, block_group->sectorsize); - last = div_u64(end - found_start, block_group->sectorsize); - if (bit) - extent_buffer_bitmap_set(leaf, ptr, first, last - first); - else - extent_buffer_bitmap_clear(leaf, ptr, first, last - first); - btrfs_mark_buffer_dirty(leaf); - - *size -= end - *start; - *start = end; -} - -/* - * We can't use btrfs_next_item() in modify_free_space_bitmap() because - * btrfs_next_leaf() doesn't get the path for writing. We can forgo the fancy - * tree walking in btrfs_next_leaf() anyways because we know exactly what we're - * looking for. - */ -static int free_space_next_bitmap(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct btrfs_path *p) -{ - struct btrfs_key key; - - if (p->slots[0] + 1 < btrfs_header_nritems(p->nodes[0])) { - p->slots[0]++; - return 0; - } - - btrfs_item_key_to_cpu(p->nodes[0], &key, p->slots[0]); - btrfs_release_path(p); - - key.objectid += key.offset; - key.type = (u8)-1; - key.offset = (u64)-1; - - return btrfs_search_prev_slot(trans, root, &key, p, 0, 1); -} - -/* - * If remove is 1, then we are removing free space, thus clearing bits in the - * bitmap. If remove is 0, then we are adding free space, thus setting bits in - * the bitmap. - */ -static int modify_free_space_bitmap(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path, - u64 start, u64 size, int remove) -{ - struct btrfs_root *root = fs_info->free_space_root; - struct btrfs_key key; - u64 end = start + size; - u64 cur_start, cur_size; - int prev_bit, next_bit; - int new_extents; - int ret; - - /* - * Read the bit for the block immediately before the extent of space if - * that block is within the block group. - */ - if (start > block_group->key.objectid) { - u64 prev_block = start - block_group->sectorsize; - - key.objectid = prev_block; - key.type = (u8)-1; - key.offset = (u64)-1; - - ret = btrfs_search_prev_slot(trans, root, &key, path, 0, 1); - if (ret) - goto out; - - prev_bit = free_space_test_bit(block_group, path, prev_block); - - /* The previous block may have been in the previous bitmap. */ - btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); - if (start >= key.objectid + key.offset) { - ret = free_space_next_bitmap(trans, root, path); - if (ret) - goto out; - } - } else { - key.objectid = start; - key.type = (u8)-1; - key.offset = (u64)-1; - - ret = btrfs_search_prev_slot(trans, root, &key, path, 0, 1); - if (ret) - goto out; - - prev_bit = -1; - } - - /* - * Iterate over all of the bitmaps overlapped by the extent of space, - * clearing/setting bits as required. - */ - cur_start = start; - cur_size = size; - while (1) { - free_space_set_bits(block_group, path, &cur_start, &cur_size, - !remove); - if (cur_size == 0) - break; - ret = free_space_next_bitmap(trans, root, path); - if (ret) - goto out; - } - - /* - * Read the bit for the block immediately after the extent of space if - * that block is within the block group. - */ - if (end < block_group->key.objectid + block_group->key.offset) { - /* The next block may be in the next bitmap. */ - btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); - if (end >= key.objectid + key.offset) { - ret = free_space_next_bitmap(trans, root, path); - if (ret) - goto out; - } - - next_bit = free_space_test_bit(block_group, path, end); - } else { - next_bit = -1; - } - - if (remove) { - new_extents = -1; - if (prev_bit == 1) { - /* Leftover on the left. */ - new_extents++; - } - if (next_bit == 1) { - /* Leftover on the right. */ - new_extents++; - } - } else { - new_extents = 1; - if (prev_bit == 1) { - /* Merging with neighbor on the left. */ - new_extents--; - } - if (next_bit == 1) { - /* Merging with neighbor on the right. */ - new_extents--; - } - } - - btrfs_release_path(path); - ret = update_free_space_extent_count(trans, fs_info, block_group, path, - new_extents); - -out: - return ret; -} - -static int remove_free_space_extent(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path, - u64 start, u64 size) -{ - struct btrfs_root *root = fs_info->free_space_root; - struct btrfs_key key; - u64 found_start, found_end; - u64 end = start + size; - int new_extents = -1; - int ret; - - key.objectid = start; - key.type = (u8)-1; - key.offset = (u64)-1; - - ret = btrfs_search_prev_slot(trans, root, &key, path, -1, 1); - if (ret) - goto out; - - btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); - - ASSERT(key.type == BTRFS_FREE_SPACE_EXTENT_KEY); - - found_start = key.objectid; - found_end = key.objectid + key.offset; - ASSERT(start >= found_start && end <= found_end); - - /* - * Okay, now that we've found the free space extent which contains the - * free space that we are removing, there are four cases: - * - * 1. We're using the whole extent: delete the key we found and - * decrement the free space extent count. - * 2. We are using part of the extent starting at the beginning: delete - * the key we found and insert a new key representing the leftover at - * the end. There is no net change in the number of extents. - * 3. We are using part of the extent ending at the end: delete the key - * we found and insert a new key representing the leftover at the - * beginning. There is no net change in the number of extents. - * 4. We are using part of the extent in the middle: delete the key we - * found and insert two new keys representing the leftovers on each - * side. Where we used to have one extent, we now have two, so increment - * the extent count. We may need to convert the block group to bitmaps - * as a result. - */ - - /* Delete the existing key (cases 1-4). */ - ret = btrfs_del_item(trans, root, path); - if (ret) - goto out; - - /* Add a key for leftovers at the beginning (cases 3 and 4). */ - if (start > found_start) { - key.objectid = found_start; - key.type = BTRFS_FREE_SPACE_EXTENT_KEY; - key.offset = start - found_start; - - btrfs_release_path(path); - ret = btrfs_insert_empty_item(trans, root, path, &key, 0); - if (ret) - goto out; - new_extents++; - } - - /* Add a key for leftovers at the end (cases 2 and 4). */ - if (end < found_end) { - key.objectid = end; - key.type = BTRFS_FREE_SPACE_EXTENT_KEY; - key.offset = found_end - end; - - btrfs_release_path(path); - ret = btrfs_insert_empty_item(trans, root, path, &key, 0); - if (ret) - goto out; - new_extents++; - } - - btrfs_release_path(path); - ret = update_free_space_extent_count(trans, fs_info, block_group, path, - new_extents); - -out: - return ret; -} - -int __remove_from_free_space_tree(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path, u64 start, u64 size) -{ - struct btrfs_free_space_info *info; - u32 flags; - int ret; - - if (block_group->needs_free_space) { - ret = __add_block_group_free_space(trans, fs_info, block_group, - path); - if (ret) - return ret; - } - - info = search_free_space_info(NULL, fs_info, block_group, path, 0); - if (IS_ERR(info)) - return PTR_ERR(info); - flags = btrfs_free_space_flags(path->nodes[0], info); - btrfs_release_path(path); - - if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) { - return modify_free_space_bitmap(trans, fs_info, block_group, - path, start, size, 1); - } else { - return remove_free_space_extent(trans, fs_info, block_group, - path, start, size); - } -} - -int remove_from_free_space_tree(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - u64 start, u64 size) -{ - struct btrfs_block_group_cache *block_group; - struct btrfs_path *path; - int ret; - - if (!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) - return 0; - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - block_group = btrfs_lookup_block_group(fs_info, start); - if (!block_group) { - ASSERT(0); - ret = -ENOENT; - goto out; - } - - mutex_lock(&block_group->free_space_lock); - ret = __remove_from_free_space_tree(trans, fs_info, block_group, path, - start, size); - mutex_unlock(&block_group->free_space_lock); - - btrfs_put_block_group(block_group); -out: - btrfs_free_path(path); - if (ret) - btrfs_abort_transaction(trans, ret); - return ret; -} - -static int add_free_space_extent(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path, - u64 start, u64 size) -{ - struct btrfs_root *root = fs_info->free_space_root; - struct btrfs_key key, new_key; - u64 found_start, found_end; - u64 end = start + size; - int new_extents = 1; - int ret; - - /* - * We are adding a new extent of free space, but we need to merge - * extents. There are four cases here: - * - * 1. The new extent does not have any immediate neighbors to merge - * with: add the new key and increment the free space extent count. We - * may need to convert the block group to bitmaps as a result. - * 2. The new extent has an immediate neighbor before it: remove the - * previous key and insert a new key combining both of them. There is no - * net change in the number of extents. - * 3. The new extent has an immediate neighbor after it: remove the next - * key and insert a new key combining both of them. There is no net - * change in the number of extents. - * 4. The new extent has immediate neighbors on both sides: remove both - * of the keys and insert a new key combining all of them. Where we used - * to have two extents, we now have one, so decrement the extent count. - */ - - new_key.objectid = start; - new_key.type = BTRFS_FREE_SPACE_EXTENT_KEY; - new_key.offset = size; - - /* Search for a neighbor on the left. */ - if (start == block_group->key.objectid) - goto right; - key.objectid = start - 1; - key.type = (u8)-1; - key.offset = (u64)-1; - - ret = btrfs_search_prev_slot(trans, root, &key, path, -1, 1); - if (ret) - goto out; - - btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); - - if (key.type != BTRFS_FREE_SPACE_EXTENT_KEY) { - ASSERT(key.type == BTRFS_FREE_SPACE_INFO_KEY); - btrfs_release_path(path); - goto right; - } - - found_start = key.objectid; - found_end = key.objectid + key.offset; - ASSERT(found_start >= block_group->key.objectid && - found_end > block_group->key.objectid); - ASSERT(found_start < start && found_end <= start); - - /* - * Delete the neighbor on the left and absorb it into the new key (cases - * 2 and 4). - */ - if (found_end == start) { - ret = btrfs_del_item(trans, root, path); - if (ret) - goto out; - new_key.objectid = found_start; - new_key.offset += key.offset; - new_extents--; - } - btrfs_release_path(path); - -right: - /* Search for a neighbor on the right. */ - if (end == block_group->key.objectid + block_group->key.offset) - goto insert; - key.objectid = end; - key.type = (u8)-1; - key.offset = (u64)-1; - - ret = btrfs_search_prev_slot(trans, root, &key, path, -1, 1); - if (ret) - goto out; - - btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); - - if (key.type != BTRFS_FREE_SPACE_EXTENT_KEY) { - ASSERT(key.type == BTRFS_FREE_SPACE_INFO_KEY); - btrfs_release_path(path); - goto insert; - } - - found_start = key.objectid; - found_end = key.objectid + key.offset; - ASSERT(found_start >= block_group->key.objectid && - found_end > block_group->key.objectid); - ASSERT((found_start < start && found_end <= start) || - (found_start >= end && found_end > end)); - - /* - * Delete the neighbor on the right and absorb it into the new key - * (cases 3 and 4). - */ - if (found_start == end) { - ret = btrfs_del_item(trans, root, path); - if (ret) - goto out; - new_key.offset += key.offset; - new_extents--; - } - btrfs_release_path(path); - -insert: - /* Insert the new key (cases 1-4). */ - ret = btrfs_insert_empty_item(trans, root, path, &new_key, 0); - if (ret) - goto out; - - btrfs_release_path(path); - ret = update_free_space_extent_count(trans, fs_info, block_group, path, - new_extents); - -out: - return ret; -} - -int __add_to_free_space_tree(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path, u64 start, u64 size) -{ - struct btrfs_free_space_info *info; - u32 flags; - int ret; - - if (block_group->needs_free_space) { - ret = __add_block_group_free_space(trans, fs_info, block_group, - path); - if (ret) - return ret; - } - - info = search_free_space_info(NULL, fs_info, block_group, path, 0); - if (IS_ERR(info)) - return PTR_ERR(info); - flags = btrfs_free_space_flags(path->nodes[0], info); - btrfs_release_path(path); - - if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) { - return modify_free_space_bitmap(trans, fs_info, block_group, - path, start, size, 0); - } else { - return add_free_space_extent(trans, fs_info, block_group, path, - start, size); - } -} - -int add_to_free_space_tree(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - u64 start, u64 size) -{ - struct btrfs_block_group_cache *block_group; - struct btrfs_path *path; - int ret; - - if (!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) - return 0; - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - block_group = btrfs_lookup_block_group(fs_info, start); - if (!block_group) { - ASSERT(0); - ret = -ENOENT; - goto out; - } - - mutex_lock(&block_group->free_space_lock); - ret = __add_to_free_space_tree(trans, fs_info, block_group, path, start, - size); - mutex_unlock(&block_group->free_space_lock); - - btrfs_put_block_group(block_group); -out: - btrfs_free_path(path); - if (ret) - btrfs_abort_transaction(trans, ret); - return ret; -} - -/* - * Populate the free space tree by walking the extent tree. Operations on the - * extent tree that happen as a result of writes to the free space tree will go - * through the normal add/remove hooks. - */ -static int populate_free_space_tree(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group) -{ - struct btrfs_root *extent_root = fs_info->extent_root; - struct btrfs_path *path, *path2; - struct btrfs_key key; - u64 start, end; - int ret; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->reada = 1; - - path2 = btrfs_alloc_path(); - if (!path2) { - btrfs_free_path(path); - return -ENOMEM; - } - - ret = add_new_free_space_info(trans, fs_info, block_group, path2); - if (ret) - goto out; - - mutex_lock(&block_group->free_space_lock); - - /* - * Iterate through all of the extent and metadata items in this block - * group, adding the free space between them and the free space at the - * end. Note that EXTENT_ITEM and METADATA_ITEM are less than - * BLOCK_GROUP_ITEM, so an extent may precede the block group that it's - * contained in. - */ - key.objectid = block_group->key.objectid; - key.type = BTRFS_EXTENT_ITEM_KEY; - key.offset = 0; - - ret = btrfs_search_slot_for_read(extent_root, &key, path, 1, 0); - if (ret < 0) - goto out_locked; - ASSERT(ret == 0); - - start = block_group->key.objectid; - end = block_group->key.objectid + block_group->key.offset; - while (1) { - btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); - - if (key.type == BTRFS_EXTENT_ITEM_KEY || - key.type == BTRFS_METADATA_ITEM_KEY) { - if (key.objectid >= end) - break; - - if (start < key.objectid) { - ret = __add_to_free_space_tree(trans, fs_info, - block_group, - path2, start, - key.objectid - - start); - if (ret) - goto out_locked; - } - start = key.objectid; - if (key.type == BTRFS_METADATA_ITEM_KEY) - start += fs_info->tree_root->nodesize; - else - start += key.offset; - } else if (key.type == BTRFS_BLOCK_GROUP_ITEM_KEY) { - if (key.objectid != block_group->key.objectid) - break; - } - - ret = btrfs_next_item(extent_root, path); - if (ret < 0) - goto out_locked; - if (ret) - break; - } - if (start < end) { - ret = __add_to_free_space_tree(trans, fs_info, block_group, - path2, start, end - start); - if (ret) - goto out_locked; - } - - ret = 0; -out_locked: - mutex_unlock(&block_group->free_space_lock); -out: - btrfs_free_path(path2); - btrfs_free_path(path); - return ret; -} - -int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info) -{ - struct btrfs_trans_handle *trans; - struct btrfs_root *tree_root = fs_info->tree_root; - struct btrfs_root *free_space_root; - struct btrfs_block_group_cache *block_group; - struct rb_node *node; - int ret; - - trans = btrfs_start_transaction(tree_root, 0); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - set_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags); - free_space_root = btrfs_create_tree(trans, fs_info, - BTRFS_FREE_SPACE_TREE_OBJECTID); - if (IS_ERR(free_space_root)) { - ret = PTR_ERR(free_space_root); - goto abort; - } - fs_info->free_space_root = free_space_root; - - node = rb_first(&fs_info->block_group_cache_tree); - while (node) { - block_group = rb_entry(node, struct btrfs_block_group_cache, - cache_node); - ret = populate_free_space_tree(trans, fs_info, block_group); - if (ret) - goto abort; - node = rb_next(node); - } - - btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE); - btrfs_set_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID); - clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags); - - ret = btrfs_commit_transaction(trans, tree_root); - if (ret) - return ret; - - return 0; - -abort: - clear_bit(BTRFS_FS_CREATING_FREE_SPACE_TREE, &fs_info->flags); - btrfs_abort_transaction(trans, ret); - btrfs_end_transaction(trans, tree_root); - return ret; -} - -static int clear_free_space_tree(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_path *path; - struct btrfs_key key; - int nr; - int ret; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - path->leave_spinning = 1; - - key.objectid = 0; - key.type = 0; - key.offset = 0; - - while (1) { - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret < 0) - goto out; - - nr = btrfs_header_nritems(path->nodes[0]); - if (!nr) - break; - - path->slots[0] = 0; - ret = btrfs_del_items(trans, root, path, 0, nr); - if (ret) - goto out; - - btrfs_release_path(path); - } - - ret = 0; -out: - btrfs_free_path(path); - return ret; -} - -int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info) -{ - struct btrfs_trans_handle *trans; - struct btrfs_root *tree_root = fs_info->tree_root; - struct btrfs_root *free_space_root = fs_info->free_space_root; - int ret; - - trans = btrfs_start_transaction(tree_root, 0); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE); - btrfs_clear_fs_compat_ro(fs_info, FREE_SPACE_TREE_VALID); - fs_info->free_space_root = NULL; - - ret = clear_free_space_tree(trans, free_space_root); - if (ret) - goto abort; - - ret = btrfs_del_root(trans, tree_root, &free_space_root->root_key); - if (ret) - goto abort; - - list_del(&free_space_root->dirty_list); - - btrfs_tree_lock(free_space_root->node); - clean_tree_block(trans, tree_root->fs_info, free_space_root->node); - btrfs_tree_unlock(free_space_root->node); - btrfs_free_tree_block(trans, free_space_root, free_space_root->node, - 0, 1); - - free_extent_buffer(free_space_root->node); - free_extent_buffer(free_space_root->commit_root); - kfree(free_space_root); - - ret = btrfs_commit_transaction(trans, tree_root); - if (ret) - return ret; - - return 0; - -abort: - btrfs_abort_transaction(trans, ret); - btrfs_end_transaction(trans, tree_root); - return ret; -} - -static int __add_block_group_free_space(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path) -{ - u64 start, end; - int ret; - - start = block_group->key.objectid; - end = block_group->key.objectid + block_group->key.offset; - - block_group->needs_free_space = 0; - - ret = add_new_free_space_info(trans, fs_info, block_group, path); - if (ret) - return ret; - - return __add_to_free_space_tree(trans, fs_info, block_group, path, - block_group->key.objectid, - block_group->key.offset); -} - -int add_block_group_free_space(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group) -{ - struct btrfs_path *path = NULL; - int ret = 0; - - if (!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) - return 0; - - mutex_lock(&block_group->free_space_lock); - if (!block_group->needs_free_space) - goto out; - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - ret = __add_block_group_free_space(trans, fs_info, block_group, path); - -out: - btrfs_free_path(path); - mutex_unlock(&block_group->free_space_lock); - if (ret) - btrfs_abort_transaction(trans, ret); - return ret; -} - -int remove_block_group_free_space(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group) -{ - struct btrfs_root *root = fs_info->free_space_root; - struct btrfs_path *path; - struct btrfs_key key, found_key; - struct extent_buffer *leaf; - u64 start, end; - int done = 0, nr; - int ret; - - if (!btrfs_fs_compat_ro(fs_info, FREE_SPACE_TREE)) - return 0; - - if (block_group->needs_free_space) { - /* We never added this block group to the free space tree. */ - return 0; - } - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - start = block_group->key.objectid; - end = block_group->key.objectid + block_group->key.offset; - - key.objectid = end - 1; - key.type = (u8)-1; - key.offset = (u64)-1; - - while (!done) { - ret = btrfs_search_prev_slot(trans, root, &key, path, -1, 1); - if (ret) - goto out; - - leaf = path->nodes[0]; - nr = 0; - path->slots[0]++; - while (path->slots[0] > 0) { - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0] - 1); - - if (found_key.type == BTRFS_FREE_SPACE_INFO_KEY) { - ASSERT(found_key.objectid == block_group->key.objectid); - ASSERT(found_key.offset == block_group->key.offset); - done = 1; - nr++; - path->slots[0]--; - break; - } else if (found_key.type == BTRFS_FREE_SPACE_EXTENT_KEY || - found_key.type == BTRFS_FREE_SPACE_BITMAP_KEY) { - ASSERT(found_key.objectid >= start); - ASSERT(found_key.objectid < end); - ASSERT(found_key.objectid + found_key.offset <= end); - nr++; - path->slots[0]--; - } else { - ASSERT(0); - } - } - - ret = btrfs_del_items(trans, root, path, path->slots[0], nr); - if (ret) - goto out; - btrfs_release_path(path); - } - - ret = 0; -out: - btrfs_free_path(path); - if (ret) - btrfs_abort_transaction(trans, ret); - return ret; -} - -static int load_free_space_bitmaps(struct btrfs_caching_control *caching_ctl, - struct btrfs_path *path, - u32 expected_extent_count) -{ - struct btrfs_block_group_cache *block_group; - struct btrfs_fs_info *fs_info; - struct btrfs_root *root; - struct btrfs_key key; - int prev_bit = 0, bit; - /* Initialize to silence GCC. */ - u64 extent_start = 0; - u64 end, offset; - u64 total_found = 0; - u32 extent_count = 0; - int ret; - - block_group = caching_ctl->block_group; - fs_info = block_group->fs_info; - root = fs_info->free_space_root; - - end = block_group->key.objectid + block_group->key.offset; - - while (1) { - ret = btrfs_next_item(root, path); - if (ret < 0) - goto out; - if (ret) - break; - - btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); - - if (key.type == BTRFS_FREE_SPACE_INFO_KEY) - break; - - ASSERT(key.type == BTRFS_FREE_SPACE_BITMAP_KEY); - ASSERT(key.objectid < end && key.objectid + key.offset <= end); - - caching_ctl->progress = key.objectid; - - offset = key.objectid; - while (offset < key.objectid + key.offset) { - bit = free_space_test_bit(block_group, path, offset); - if (prev_bit == 0 && bit == 1) { - extent_start = offset; - } else if (prev_bit == 1 && bit == 0) { - total_found += add_new_free_space(block_group, - fs_info, - extent_start, - offset); - if (total_found > CACHING_CTL_WAKE_UP) { - total_found = 0; - wake_up(&caching_ctl->wait); - } - extent_count++; - } - prev_bit = bit; - offset += block_group->sectorsize; - } - } - if (prev_bit == 1) { - total_found += add_new_free_space(block_group, fs_info, - extent_start, end); - extent_count++; - } - - if (extent_count != expected_extent_count) { - btrfs_err(fs_info, - "incorrect extent count for %llu; counted %u, expected %u", - block_group->key.objectid, extent_count, - expected_extent_count); - ASSERT(0); - ret = -EIO; - goto out; - } - - caching_ctl->progress = (u64)-1; - - ret = 0; -out: - return ret; -} - -static int load_free_space_extents(struct btrfs_caching_control *caching_ctl, - struct btrfs_path *path, - u32 expected_extent_count) -{ - struct btrfs_block_group_cache *block_group; - struct btrfs_fs_info *fs_info; - struct btrfs_root *root; - struct btrfs_key key; - u64 end; - u64 total_found = 0; - u32 extent_count = 0; - int ret; - - block_group = caching_ctl->block_group; - fs_info = block_group->fs_info; - root = fs_info->free_space_root; - - end = block_group->key.objectid + block_group->key.offset; - - while (1) { - ret = btrfs_next_item(root, path); - if (ret < 0) - goto out; - if (ret) - break; - - btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); - - if (key.type == BTRFS_FREE_SPACE_INFO_KEY) - break; - - ASSERT(key.type == BTRFS_FREE_SPACE_EXTENT_KEY); - ASSERT(key.objectid < end && key.objectid + key.offset <= end); - - caching_ctl->progress = key.objectid; - - total_found += add_new_free_space(block_group, fs_info, - key.objectid, - key.objectid + key.offset); - if (total_found > CACHING_CTL_WAKE_UP) { - total_found = 0; - wake_up(&caching_ctl->wait); - } - extent_count++; - } - - if (extent_count != expected_extent_count) { - btrfs_err(fs_info, - "incorrect extent count for %llu; counted %u, expected %u", - block_group->key.objectid, extent_count, - expected_extent_count); - ASSERT(0); - ret = -EIO; - goto out; - } - - caching_ctl->progress = (u64)-1; - - ret = 0; -out: - return ret; -} - -int load_free_space_tree(struct btrfs_caching_control *caching_ctl) -{ - struct btrfs_block_group_cache *block_group; - struct btrfs_fs_info *fs_info; - struct btrfs_free_space_info *info; - struct btrfs_path *path; - u32 extent_count, flags; - int ret; - - block_group = caching_ctl->block_group; - fs_info = block_group->fs_info; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - /* - * Just like caching_thread() doesn't want to deadlock on the extent - * tree, we don't want to deadlock on the free space tree. - */ - path->skip_locking = 1; - path->search_commit_root = 1; - path->reada = 1; - - info = search_free_space_info(NULL, fs_info, block_group, path, 0); - if (IS_ERR(info)) { - ret = PTR_ERR(info); - goto out; - } - extent_count = btrfs_free_space_extent_count(path->nodes[0], info); - flags = btrfs_free_space_flags(path->nodes[0], info); - - /* - * We left path pointing to the free space info item, so now - * load_free_space_foo can just iterate through the free space tree from - * there. - */ - if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) - ret = load_free_space_bitmaps(caching_ctl, path, extent_count); - else - ret = load_free_space_extents(caching_ctl, path, extent_count); - -out: - btrfs_free_path(path); - return ret; -} diff --git a/src/linux/fs/btrfs/free-space-tree.h b/src/linux/fs/btrfs/free-space-tree.h deleted file mode 100644 index 54ffced..0000000 --- a/src/linux/fs/btrfs/free-space-tree.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2015 Facebook. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __BTRFS_FREE_SPACE_TREE -#define __BTRFS_FREE_SPACE_TREE - -/* - * The default size for new free space bitmap items. The last bitmap in a block - * group may be truncated, and none of the free space tree code assumes that - * existing bitmaps are this size. - */ -#define BTRFS_FREE_SPACE_BITMAP_SIZE 256 -#define BTRFS_FREE_SPACE_BITMAP_BITS (BTRFS_FREE_SPACE_BITMAP_SIZE * BITS_PER_BYTE) - -void set_free_space_tree_thresholds(struct btrfs_block_group_cache *block_group); -int btrfs_create_free_space_tree(struct btrfs_fs_info *fs_info); -int btrfs_clear_free_space_tree(struct btrfs_fs_info *fs_info); -int load_free_space_tree(struct btrfs_caching_control *caching_ctl); -int add_block_group_free_space(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group); -int remove_block_group_free_space(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group); -int add_to_free_space_tree(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - u64 start, u64 size); -int remove_from_free_space_tree(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - u64 start, u64 size); - -/* Exposed for testing. */ -struct btrfs_free_space_info * -search_free_space_info(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path, int cow); -int __add_to_free_space_tree(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path, u64 start, u64 size); -int __remove_from_free_space_tree(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path, u64 start, u64 size); -int convert_free_space_to_bitmaps(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path); -int convert_free_space_to_extents(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, - struct btrfs_path *path); -int free_space_test_bit(struct btrfs_block_group_cache *block_group, - struct btrfs_path *path, u64 offset); - -#endif diff --git a/src/linux/fs/btrfs/hash.c b/src/linux/fs/btrfs/hash.c deleted file mode 100644 index a97fdc1..0000000 --- a/src/linux/fs/btrfs/hash.c +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2014 Filipe David Borba Manana - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include -#include -#include "hash.h" - -static struct crypto_shash *tfm; - -int __init btrfs_hash_init(void) -{ - tfm = crypto_alloc_shash("crc32c", 0, 0); - - return PTR_ERR_OR_ZERO(tfm); -} - -const char* btrfs_crc32c_impl(void) -{ - return crypto_tfm_alg_driver_name(crypto_shash_tfm(tfm)); -} - -void btrfs_hash_exit(void) -{ - crypto_free_shash(tfm); -} - -u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length) -{ - SHASH_DESC_ON_STACK(shash, tfm); - u32 *ctx = (u32 *)shash_desc_ctx(shash); - int err; - - shash->tfm = tfm; - shash->flags = 0; - *ctx = crc; - - err = crypto_shash_update(shash, address, length); - BUG_ON(err); - - return *ctx; -} diff --git a/src/linux/fs/btrfs/hash.h b/src/linux/fs/btrfs/hash.h deleted file mode 100644 index c3a2ec5..0000000 --- a/src/linux/fs/btrfs/hash.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __HASH__ -#define __HASH__ - -int __init btrfs_hash_init(void); - -void btrfs_hash_exit(void); -const char* btrfs_crc32c_impl(void); - -u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length); - -static inline u64 btrfs_name_hash(const char *name, int len) -{ - return btrfs_crc32c((u32)~1, name, len); -} - -/* - * Figure the key offset of an extended inode ref - */ -static inline u64 btrfs_extref_hash(u64 parent_objectid, const char *name, - int len) -{ - return (u64) btrfs_crc32c(parent_objectid, name, len); -} - -#endif diff --git a/src/linux/fs/btrfs/inode-item.c b/src/linux/fs/btrfs/inode-item.c deleted file mode 100644 index b8acc07..0000000 --- a/src/linux/fs/btrfs/inode-item.c +++ /dev/null @@ -1,440 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include "ctree.h" -#include "disk-io.h" -#include "hash.h" -#include "transaction.h" -#include "print-tree.h" - -static int find_name_in_backref(struct btrfs_path *path, const char *name, - int name_len, struct btrfs_inode_ref **ref_ret) -{ - struct extent_buffer *leaf; - struct btrfs_inode_ref *ref; - unsigned long ptr; - unsigned long name_ptr; - u32 item_size; - u32 cur_offset = 0; - int len; - - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, path->slots[0]); - ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); - while (cur_offset < item_size) { - ref = (struct btrfs_inode_ref *)(ptr + cur_offset); - len = btrfs_inode_ref_name_len(leaf, ref); - name_ptr = (unsigned long)(ref + 1); - cur_offset += len + sizeof(*ref); - if (len != name_len) - continue; - if (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0) { - *ref_ret = ref; - return 1; - } - } - return 0; -} - -int btrfs_find_name_in_ext_backref(struct btrfs_path *path, u64 ref_objectid, - const char *name, int name_len, - struct btrfs_inode_extref **extref_ret) -{ - struct extent_buffer *leaf; - struct btrfs_inode_extref *extref; - unsigned long ptr; - unsigned long name_ptr; - u32 item_size; - u32 cur_offset = 0; - int ref_name_len; - - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, path->slots[0]); - ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); - - /* - * Search all extended backrefs in this item. We're only - * looking through any collisions so most of the time this is - * just going to compare against one buffer. If all is well, - * we'll return success and the inode ref object. - */ - while (cur_offset < item_size) { - extref = (struct btrfs_inode_extref *) (ptr + cur_offset); - name_ptr = (unsigned long)(&extref->name); - ref_name_len = btrfs_inode_extref_name_len(leaf, extref); - - if (ref_name_len == name_len && - btrfs_inode_extref_parent(leaf, extref) == ref_objectid && - (memcmp_extent_buffer(leaf, name, name_ptr, name_len) == 0)) { - if (extref_ret) - *extref_ret = extref; - return 1; - } - - cur_offset += ref_name_len + sizeof(*extref); - } - return 0; -} - -/* Returns NULL if no extref found */ -struct btrfs_inode_extref * -btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - const char *name, int name_len, - u64 inode_objectid, u64 ref_objectid, int ins_len, - int cow) -{ - int ret; - struct btrfs_key key; - struct btrfs_inode_extref *extref; - - key.objectid = inode_objectid; - key.type = BTRFS_INODE_EXTREF_KEY; - key.offset = btrfs_extref_hash(ref_objectid, name, name_len); - - ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow); - if (ret < 0) - return ERR_PTR(ret); - if (ret > 0) - return NULL; - if (!btrfs_find_name_in_ext_backref(path, ref_objectid, name, name_len, &extref)) - return NULL; - return extref; -} - -static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - const char *name, int name_len, - u64 inode_objectid, u64 ref_objectid, - u64 *index) -{ - struct btrfs_path *path; - struct btrfs_key key; - struct btrfs_inode_extref *extref; - struct extent_buffer *leaf; - int ret; - int del_len = name_len + sizeof(*extref); - unsigned long ptr; - unsigned long item_start; - u32 item_size; - - key.objectid = inode_objectid; - key.type = BTRFS_INODE_EXTREF_KEY; - key.offset = btrfs_extref_hash(ref_objectid, name, name_len); - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - path->leave_spinning = 1; - - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret > 0) - ret = -ENOENT; - if (ret < 0) - goto out; - - /* - * Sanity check - did we find the right item for this name? - * This should always succeed so error here will make the FS - * readonly. - */ - if (!btrfs_find_name_in_ext_backref(path, ref_objectid, - name, name_len, &extref)) { - btrfs_handle_fs_error(root->fs_info, -ENOENT, NULL); - ret = -EROFS; - goto out; - } - - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, path->slots[0]); - if (index) - *index = btrfs_inode_extref_index(leaf, extref); - - if (del_len == item_size) { - /* - * Common case only one ref in the item, remove the - * whole item. - */ - ret = btrfs_del_item(trans, root, path); - goto out; - } - - ptr = (unsigned long)extref; - item_start = btrfs_item_ptr_offset(leaf, path->slots[0]); - - memmove_extent_buffer(leaf, ptr, ptr + del_len, - item_size - (ptr + del_len - item_start)); - - btrfs_truncate_item(root, path, item_size - del_len, 1); - -out: - btrfs_free_path(path); - - return ret; -} - -int btrfs_del_inode_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - const char *name, int name_len, - u64 inode_objectid, u64 ref_objectid, u64 *index) -{ - struct btrfs_path *path; - struct btrfs_key key; - struct btrfs_inode_ref *ref; - struct extent_buffer *leaf; - unsigned long ptr; - unsigned long item_start; - u32 item_size; - u32 sub_item_len; - int ret; - int search_ext_refs = 0; - int del_len = name_len + sizeof(*ref); - - key.objectid = inode_objectid; - key.offset = ref_objectid; - key.type = BTRFS_INODE_REF_KEY; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - path->leave_spinning = 1; - - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret > 0) { - ret = -ENOENT; - search_ext_refs = 1; - goto out; - } else if (ret < 0) { - goto out; - } - if (!find_name_in_backref(path, name, name_len, &ref)) { - ret = -ENOENT; - search_ext_refs = 1; - goto out; - } - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, path->slots[0]); - - if (index) - *index = btrfs_inode_ref_index(leaf, ref); - - if (del_len == item_size) { - ret = btrfs_del_item(trans, root, path); - goto out; - } - ptr = (unsigned long)ref; - sub_item_len = name_len + sizeof(*ref); - item_start = btrfs_item_ptr_offset(leaf, path->slots[0]); - memmove_extent_buffer(leaf, ptr, ptr + sub_item_len, - item_size - (ptr + sub_item_len - item_start)); - btrfs_truncate_item(root, path, item_size - sub_item_len, 1); -out: - btrfs_free_path(path); - - if (search_ext_refs) { - /* - * No refs were found, or we could not find the - * name in our ref array. Find and remove the extended - * inode ref then. - */ - return btrfs_del_inode_extref(trans, root, name, name_len, - inode_objectid, ref_objectid, index); - } - - return ret; -} - -/* - * btrfs_insert_inode_extref() - Inserts an extended inode ref into a tree. - * - * The caller must have checked against BTRFS_LINK_MAX already. - */ -static int btrfs_insert_inode_extref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - const char *name, int name_len, - u64 inode_objectid, u64 ref_objectid, u64 index) -{ - struct btrfs_inode_extref *extref; - int ret; - int ins_len = name_len + sizeof(*extref); - unsigned long ptr; - struct btrfs_path *path; - struct btrfs_key key; - struct extent_buffer *leaf; - struct btrfs_item *item; - - key.objectid = inode_objectid; - key.type = BTRFS_INODE_EXTREF_KEY; - key.offset = btrfs_extref_hash(ref_objectid, name, name_len); - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - path->leave_spinning = 1; - ret = btrfs_insert_empty_item(trans, root, path, &key, - ins_len); - if (ret == -EEXIST) { - if (btrfs_find_name_in_ext_backref(path, ref_objectid, - name, name_len, NULL)) - goto out; - - btrfs_extend_item(root, path, ins_len); - ret = 0; - } - if (ret < 0) - goto out; - - leaf = path->nodes[0]; - item = btrfs_item_nr(path->slots[0]); - ptr = (unsigned long)btrfs_item_ptr(leaf, path->slots[0], char); - ptr += btrfs_item_size(leaf, item) - ins_len; - extref = (struct btrfs_inode_extref *)ptr; - - btrfs_set_inode_extref_name_len(path->nodes[0], extref, name_len); - btrfs_set_inode_extref_index(path->nodes[0], extref, index); - btrfs_set_inode_extref_parent(path->nodes[0], extref, ref_objectid); - - ptr = (unsigned long)&extref->name; - write_extent_buffer(path->nodes[0], name, ptr, name_len); - btrfs_mark_buffer_dirty(path->nodes[0]); - -out: - btrfs_free_path(path); - return ret; -} - -/* Will return 0, -ENOMEM, -EMLINK, or -EEXIST or anything from the CoW path */ -int btrfs_insert_inode_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - const char *name, int name_len, - u64 inode_objectid, u64 ref_objectid, u64 index) -{ - struct btrfs_path *path; - struct btrfs_key key; - struct btrfs_inode_ref *ref; - unsigned long ptr; - int ret; - int ins_len = name_len + sizeof(*ref); - - key.objectid = inode_objectid; - key.offset = ref_objectid; - key.type = BTRFS_INODE_REF_KEY; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - path->leave_spinning = 1; - path->skip_release_on_error = 1; - ret = btrfs_insert_empty_item(trans, root, path, &key, - ins_len); - if (ret == -EEXIST) { - u32 old_size; - - if (find_name_in_backref(path, name, name_len, &ref)) - goto out; - - old_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]); - btrfs_extend_item(root, path, ins_len); - ref = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_inode_ref); - ref = (struct btrfs_inode_ref *)((unsigned long)ref + old_size); - btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); - btrfs_set_inode_ref_index(path->nodes[0], ref, index); - ptr = (unsigned long)(ref + 1); - ret = 0; - } else if (ret < 0) { - if (ret == -EOVERFLOW) { - if (find_name_in_backref(path, name, name_len, &ref)) - ret = -EEXIST; - else - ret = -EMLINK; - } - goto out; - } else { - ref = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_inode_ref); - btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); - btrfs_set_inode_ref_index(path->nodes[0], ref, index); - ptr = (unsigned long)(ref + 1); - } - write_extent_buffer(path->nodes[0], name, ptr, name_len); - btrfs_mark_buffer_dirty(path->nodes[0]); - -out: - btrfs_free_path(path); - - if (ret == -EMLINK) { - struct btrfs_super_block *disk_super = root->fs_info->super_copy; - /* We ran out of space in the ref array. Need to - * add an extended ref. */ - if (btrfs_super_incompat_flags(disk_super) - & BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF) - ret = btrfs_insert_inode_extref(trans, root, name, - name_len, - inode_objectid, - ref_objectid, index); - } - - return ret; -} - -int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, u64 objectid) -{ - struct btrfs_key key; - int ret; - key.objectid = objectid; - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - - ret = btrfs_insert_empty_item(trans, root, path, &key, - sizeof(struct btrfs_inode_item)); - return ret; -} - -int btrfs_lookup_inode(struct btrfs_trans_handle *trans, struct btrfs_root - *root, struct btrfs_path *path, - struct btrfs_key *location, int mod) -{ - int ins_len = mod < 0 ? -1 : 0; - int cow = mod != 0; - int ret; - int slot; - struct extent_buffer *leaf; - struct btrfs_key found_key; - - ret = btrfs_search_slot(trans, root, location, path, ins_len, cow); - if (ret > 0 && location->type == BTRFS_ROOT_ITEM_KEY && - location->offset == (u64)-1 && path->slots[0] != 0) { - slot = path->slots[0] - 1; - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &found_key, slot); - if (found_key.objectid == location->objectid && - found_key.type == location->type) { - path->slots[0]--; - return 0; - } - } - return ret; -} diff --git a/src/linux/fs/btrfs/inode-map.c b/src/linux/fs/btrfs/inode-map.c deleted file mode 100644 index d27014b..0000000 --- a/src/linux/fs/btrfs/inode-map.c +++ /dev/null @@ -1,573 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include - -#include "ctree.h" -#include "disk-io.h" -#include "free-space-cache.h" -#include "inode-map.h" -#include "transaction.h" - -static int caching_kthread(void *data) -{ - struct btrfs_root *root = data; - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_free_space_ctl *ctl = root->free_ino_ctl; - struct btrfs_key key; - struct btrfs_path *path; - struct extent_buffer *leaf; - u64 last = (u64)-1; - int slot; - int ret; - - if (!btrfs_test_opt(root->fs_info, INODE_MAP_CACHE)) - return 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - /* Since the commit root is read-only, we can safely skip locking. */ - path->skip_locking = 1; - path->search_commit_root = 1; - path->reada = READA_FORWARD; - - key.objectid = BTRFS_FIRST_FREE_OBJECTID; - key.offset = 0; - key.type = BTRFS_INODE_ITEM_KEY; -again: - /* need to make sure the commit_root doesn't disappear */ - down_read(&fs_info->commit_root_sem); - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out; - - while (1) { - if (btrfs_fs_closing(fs_info)) - goto out; - - leaf = path->nodes[0]; - slot = path->slots[0]; - if (slot >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) - goto out; - else if (ret > 0) - break; - - if (need_resched() || - btrfs_transaction_in_commit(fs_info)) { - leaf = path->nodes[0]; - - if (WARN_ON(btrfs_header_nritems(leaf) == 0)) - break; - - /* - * Save the key so we can advances forward - * in the next search. - */ - btrfs_item_key_to_cpu(leaf, &key, 0); - btrfs_release_path(path); - root->ino_cache_progress = last; - up_read(&fs_info->commit_root_sem); - schedule_timeout(1); - goto again; - } else - continue; - } - - btrfs_item_key_to_cpu(leaf, &key, slot); - - if (key.type != BTRFS_INODE_ITEM_KEY) - goto next; - - if (key.objectid >= root->highest_objectid) - break; - - if (last != (u64)-1 && last + 1 != key.objectid) { - __btrfs_add_free_space(fs_info, ctl, last + 1, - key.objectid - last - 1); - wake_up(&root->ino_cache_wait); - } - - last = key.objectid; -next: - path->slots[0]++; - } - - if (last < root->highest_objectid - 1) { - __btrfs_add_free_space(fs_info, ctl, last + 1, - root->highest_objectid - last - 1); - } - - spin_lock(&root->ino_cache_lock); - root->ino_cache_state = BTRFS_CACHE_FINISHED; - spin_unlock(&root->ino_cache_lock); - - root->ino_cache_progress = (u64)-1; - btrfs_unpin_free_ino(root); -out: - wake_up(&root->ino_cache_wait); - up_read(&fs_info->commit_root_sem); - - btrfs_free_path(path); - - return ret; -} - -static void start_caching(struct btrfs_root *root) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_free_space_ctl *ctl = root->free_ino_ctl; - struct task_struct *tsk; - int ret; - u64 objectid; - - if (!btrfs_test_opt(fs_info, INODE_MAP_CACHE)) - return; - - spin_lock(&root->ino_cache_lock); - if (root->ino_cache_state != BTRFS_CACHE_NO) { - spin_unlock(&root->ino_cache_lock); - return; - } - - root->ino_cache_state = BTRFS_CACHE_STARTED; - spin_unlock(&root->ino_cache_lock); - - ret = load_free_ino_cache(fs_info, root); - if (ret == 1) { - spin_lock(&root->ino_cache_lock); - root->ino_cache_state = BTRFS_CACHE_FINISHED; - spin_unlock(&root->ino_cache_lock); - return; - } - - /* - * It can be quite time-consuming to fill the cache by searching - * through the extent tree, and this can keep ino allocation path - * waiting. Therefore at start we quickly find out the highest - * inode number and we know we can use inode numbers which fall in - * [highest_ino + 1, BTRFS_LAST_FREE_OBJECTID]. - */ - ret = btrfs_find_free_objectid(root, &objectid); - if (!ret && objectid <= BTRFS_LAST_FREE_OBJECTID) { - __btrfs_add_free_space(fs_info, ctl, objectid, - BTRFS_LAST_FREE_OBJECTID - objectid + 1); - } - - tsk = kthread_run(caching_kthread, root, "btrfs-ino-cache-%llu", - root->root_key.objectid); - if (IS_ERR(tsk)) { - btrfs_warn(fs_info, "failed to start inode caching task"); - btrfs_clear_pending_and_info(fs_info, INODE_MAP_CACHE, - "disabling inode map caching"); - } -} - -int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid) -{ - if (!btrfs_test_opt(root->fs_info, INODE_MAP_CACHE)) - return btrfs_find_free_objectid(root, objectid); - -again: - *objectid = btrfs_find_ino_for_alloc(root); - - if (*objectid != 0) - return 0; - - start_caching(root); - - wait_event(root->ino_cache_wait, - root->ino_cache_state == BTRFS_CACHE_FINISHED || - root->free_ino_ctl->free_space > 0); - - if (root->ino_cache_state == BTRFS_CACHE_FINISHED && - root->free_ino_ctl->free_space == 0) - return -ENOSPC; - else - goto again; -} - -void btrfs_return_ino(struct btrfs_root *root, u64 objectid) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_free_space_ctl *pinned = root->free_ino_pinned; - - if (!btrfs_test_opt(fs_info, INODE_MAP_CACHE)) - return; -again: - if (root->ino_cache_state == BTRFS_CACHE_FINISHED) { - __btrfs_add_free_space(fs_info, pinned, objectid, 1); - } else { - down_write(&fs_info->commit_root_sem); - spin_lock(&root->ino_cache_lock); - if (root->ino_cache_state == BTRFS_CACHE_FINISHED) { - spin_unlock(&root->ino_cache_lock); - up_write(&fs_info->commit_root_sem); - goto again; - } - spin_unlock(&root->ino_cache_lock); - - start_caching(root); - - __btrfs_add_free_space(fs_info, pinned, objectid, 1); - - up_write(&fs_info->commit_root_sem); - } -} - -/* - * When a transaction is committed, we'll move those inode numbers which are - * smaller than root->ino_cache_progress from pinned tree to free_ino tree, and - * others will just be dropped, because the commit root we were searching has - * changed. - * - * Must be called with root->fs_info->commit_root_sem held - */ -void btrfs_unpin_free_ino(struct btrfs_root *root) -{ - struct btrfs_free_space_ctl *ctl = root->free_ino_ctl; - struct rb_root *rbroot = &root->free_ino_pinned->free_space_offset; - spinlock_t *rbroot_lock = &root->free_ino_pinned->tree_lock; - struct btrfs_free_space *info; - struct rb_node *n; - u64 count; - - if (!btrfs_test_opt(root->fs_info, INODE_MAP_CACHE)) - return; - - while (1) { - bool add_to_ctl = true; - - spin_lock(rbroot_lock); - n = rb_first(rbroot); - if (!n) { - spin_unlock(rbroot_lock); - break; - } - - info = rb_entry(n, struct btrfs_free_space, offset_index); - BUG_ON(info->bitmap); /* Logic error */ - - if (info->offset > root->ino_cache_progress) - add_to_ctl = false; - else if (info->offset + info->bytes > root->ino_cache_progress) - count = root->ino_cache_progress - info->offset + 1; - else - count = info->bytes; - - rb_erase(&info->offset_index, rbroot); - spin_unlock(rbroot_lock); - if (add_to_ctl) - __btrfs_add_free_space(root->fs_info, ctl, - info->offset, count); - kmem_cache_free(btrfs_free_space_cachep, info); - } -} - -#define INIT_THRESHOLD ((SZ_32K / 2) / sizeof(struct btrfs_free_space)) -#define INODES_PER_BITMAP (PAGE_SIZE * 8) - -/* - * The goal is to keep the memory used by the free_ino tree won't - * exceed the memory if we use bitmaps only. - */ -static void recalculate_thresholds(struct btrfs_free_space_ctl *ctl) -{ - struct btrfs_free_space *info; - struct rb_node *n; - int max_ino; - int max_bitmaps; - - n = rb_last(&ctl->free_space_offset); - if (!n) { - ctl->extents_thresh = INIT_THRESHOLD; - return; - } - info = rb_entry(n, struct btrfs_free_space, offset_index); - - /* - * Find the maximum inode number in the filesystem. Note we - * ignore the fact that this can be a bitmap, because we are - * not doing precise calculation. - */ - max_ino = info->bytes - 1; - - max_bitmaps = ALIGN(max_ino, INODES_PER_BITMAP) / INODES_PER_BITMAP; - if (max_bitmaps <= ctl->total_bitmaps) { - ctl->extents_thresh = 0; - return; - } - - ctl->extents_thresh = (max_bitmaps - ctl->total_bitmaps) * - PAGE_SIZE / sizeof(*info); -} - -/* - * We don't fall back to bitmap, if we are below the extents threshold - * or this chunk of inode numbers is a big one. - */ -static bool use_bitmap(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info) -{ - if (ctl->free_extents < ctl->extents_thresh || - info->bytes > INODES_PER_BITMAP / 10) - return false; - - return true; -} - -static const struct btrfs_free_space_op free_ino_op = { - .recalc_thresholds = recalculate_thresholds, - .use_bitmap = use_bitmap, -}; - -static void pinned_recalc_thresholds(struct btrfs_free_space_ctl *ctl) -{ -} - -static bool pinned_use_bitmap(struct btrfs_free_space_ctl *ctl, - struct btrfs_free_space *info) -{ - /* - * We always use extents for two reasons: - * - * - The pinned tree is only used during the process of caching - * work. - * - Make code simpler. See btrfs_unpin_free_ino(). - */ - return false; -} - -static const struct btrfs_free_space_op pinned_free_ino_op = { - .recalc_thresholds = pinned_recalc_thresholds, - .use_bitmap = pinned_use_bitmap, -}; - -void btrfs_init_free_ino_ctl(struct btrfs_root *root) -{ - struct btrfs_free_space_ctl *ctl = root->free_ino_ctl; - struct btrfs_free_space_ctl *pinned = root->free_ino_pinned; - - spin_lock_init(&ctl->tree_lock); - ctl->unit = 1; - ctl->start = 0; - ctl->private = NULL; - ctl->op = &free_ino_op; - INIT_LIST_HEAD(&ctl->trimming_ranges); - mutex_init(&ctl->cache_writeout_mutex); - - /* - * Initially we allow to use 16K of ram to cache chunks of - * inode numbers before we resort to bitmaps. This is somewhat - * arbitrary, but it will be adjusted in runtime. - */ - ctl->extents_thresh = INIT_THRESHOLD; - - spin_lock_init(&pinned->tree_lock); - pinned->unit = 1; - pinned->start = 0; - pinned->private = NULL; - pinned->extents_thresh = 0; - pinned->op = &pinned_free_ino_op; -} - -int btrfs_save_ino_cache(struct btrfs_root *root, - struct btrfs_trans_handle *trans) -{ - struct btrfs_free_space_ctl *ctl = root->free_ino_ctl; - struct btrfs_path *path; - struct inode *inode; - struct btrfs_block_rsv *rsv; - u64 num_bytes; - u64 alloc_hint = 0; - int ret; - int prealloc; - bool retry = false; - - /* only fs tree and subvol/snap needs ino cache */ - if (root->root_key.objectid != BTRFS_FS_TREE_OBJECTID && - (root->root_key.objectid < BTRFS_FIRST_FREE_OBJECTID || - root->root_key.objectid > BTRFS_LAST_FREE_OBJECTID)) - return 0; - - /* Don't save inode cache if we are deleting this root */ - if (btrfs_root_refs(&root->root_item) == 0) - return 0; - - if (!btrfs_test_opt(root->fs_info, INODE_MAP_CACHE)) - return 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - rsv = trans->block_rsv; - trans->block_rsv = &root->fs_info->trans_block_rsv; - - num_bytes = trans->bytes_reserved; - /* - * 1 item for inode item insertion if need - * 4 items for inode item update (in the worst case) - * 1 items for slack space if we need do truncation - * 1 item for free space object - * 3 items for pre-allocation - */ - trans->bytes_reserved = btrfs_calc_trans_metadata_size(root, 10); - ret = btrfs_block_rsv_add(root, trans->block_rsv, - trans->bytes_reserved, - BTRFS_RESERVE_NO_FLUSH); - if (ret) - goto out; - trace_btrfs_space_reservation(root->fs_info, "ino_cache", - trans->transid, trans->bytes_reserved, 1); -again: - inode = lookup_free_ino_inode(root, path); - if (IS_ERR(inode) && (PTR_ERR(inode) != -ENOENT || retry)) { - ret = PTR_ERR(inode); - goto out_release; - } - - if (IS_ERR(inode)) { - BUG_ON(retry); /* Logic error */ - retry = true; - - ret = create_free_ino_inode(root, trans, path); - if (ret) - goto out_release; - goto again; - } - - BTRFS_I(inode)->generation = 0; - ret = btrfs_update_inode(trans, root, inode); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out_put; - } - - if (i_size_read(inode) > 0) { - ret = btrfs_truncate_free_space_cache(root, trans, NULL, inode); - if (ret) { - if (ret != -ENOSPC) - btrfs_abort_transaction(trans, ret); - goto out_put; - } - } - - spin_lock(&root->ino_cache_lock); - if (root->ino_cache_state != BTRFS_CACHE_FINISHED) { - ret = -1; - spin_unlock(&root->ino_cache_lock); - goto out_put; - } - spin_unlock(&root->ino_cache_lock); - - spin_lock(&ctl->tree_lock); - prealloc = sizeof(struct btrfs_free_space) * ctl->free_extents; - prealloc = ALIGN(prealloc, PAGE_SIZE); - prealloc += ctl->total_bitmaps * PAGE_SIZE; - spin_unlock(&ctl->tree_lock); - - /* Just to make sure we have enough space */ - prealloc += 8 * PAGE_SIZE; - - ret = btrfs_delalloc_reserve_space(inode, 0, prealloc); - if (ret) - goto out_put; - - ret = btrfs_prealloc_file_range_trans(inode, trans, 0, 0, prealloc, - prealloc, prealloc, &alloc_hint); - if (ret) { - btrfs_delalloc_release_metadata(inode, prealloc); - goto out_put; - } - - ret = btrfs_write_out_ino_cache(root, trans, path, inode); -out_put: - iput(inode); -out_release: - trace_btrfs_space_reservation(root->fs_info, "ino_cache", - trans->transid, trans->bytes_reserved, 0); - btrfs_block_rsv_release(root, trans->block_rsv, trans->bytes_reserved); -out: - trans->block_rsv = rsv; - trans->bytes_reserved = num_bytes; - - btrfs_free_path(path); - return ret; -} - -int btrfs_find_highest_objectid(struct btrfs_root *root, u64 *objectid) -{ - struct btrfs_path *path; - int ret; - struct extent_buffer *l; - struct btrfs_key search_key; - struct btrfs_key found_key; - int slot; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - search_key.objectid = BTRFS_LAST_FREE_OBJECTID; - search_key.type = -1; - search_key.offset = (u64)-1; - ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); - if (ret < 0) - goto error; - BUG_ON(ret == 0); /* Corruption */ - if (path->slots[0] > 0) { - slot = path->slots[0] - 1; - l = path->nodes[0]; - btrfs_item_key_to_cpu(l, &found_key, slot); - *objectid = max_t(u64, found_key.objectid, - BTRFS_FIRST_FREE_OBJECTID - 1); - } else { - *objectid = BTRFS_FIRST_FREE_OBJECTID - 1; - } - ret = 0; -error: - btrfs_free_path(path); - return ret; -} - -int btrfs_find_free_objectid(struct btrfs_root *root, u64 *objectid) -{ - int ret; - mutex_lock(&root->objectid_mutex); - - if (unlikely(root->highest_objectid >= BTRFS_LAST_FREE_OBJECTID)) { - btrfs_warn(root->fs_info, - "the objectid of root %llu reaches its highest value", - root->root_key.objectid); - ret = -ENOSPC; - goto out; - } - - *objectid = ++root->highest_objectid; - ret = 0; -out: - mutex_unlock(&root->objectid_mutex); - return ret; -} diff --git a/src/linux/fs/btrfs/inode-map.h b/src/linux/fs/btrfs/inode-map.h deleted file mode 100644 index c8e864b..0000000 --- a/src/linux/fs/btrfs/inode-map.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __BTRFS_INODE_MAP -#define __BTRFS_INODE_MAP - -void btrfs_init_free_ino_ctl(struct btrfs_root *root); -void btrfs_unpin_free_ino(struct btrfs_root *root); -void btrfs_return_ino(struct btrfs_root *root, u64 objectid); -int btrfs_find_free_ino(struct btrfs_root *root, u64 *objectid); -int btrfs_save_ino_cache(struct btrfs_root *root, - struct btrfs_trans_handle *trans); - -int btrfs_find_free_objectid(struct btrfs_root *root, u64 *objectid); -int btrfs_find_highest_objectid(struct btrfs_root *root, u64 *objectid); - -#endif diff --git a/src/linux/fs/btrfs/inode.c b/src/linux/fs/btrfs/inode.c deleted file mode 100644 index 8e3a5a2..0000000 --- a/src/linux/fs/btrfs/inode.c +++ /dev/null @@ -1,10683 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#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 "ctree.h" -#include "disk-io.h" -#include "transaction.h" -#include "btrfs_inode.h" -#include "print-tree.h" -#include "ordered-data.h" -#include "xattr.h" -#include "tree-log.h" -#include "volumes.h" -#include "compression.h" -#include "locking.h" -#include "free-space-cache.h" -#include "inode-map.h" -#include "backref.h" -#include "hash.h" -#include "props.h" -#include "qgroup.h" -#include "dedupe.h" - -struct btrfs_iget_args { - struct btrfs_key *location; - struct btrfs_root *root; -}; - -struct btrfs_dio_data { - u64 outstanding_extents; - u64 reserve; - u64 unsubmitted_oe_range_start; - u64 unsubmitted_oe_range_end; -}; - -static const struct inode_operations btrfs_dir_inode_operations; -static const struct inode_operations btrfs_symlink_inode_operations; -static const struct inode_operations btrfs_dir_ro_inode_operations; -static const struct inode_operations btrfs_special_inode_operations; -static const struct inode_operations btrfs_file_inode_operations; -static const struct address_space_operations btrfs_aops; -static const struct address_space_operations btrfs_symlink_aops; -static const struct file_operations btrfs_dir_file_operations; -static const struct extent_io_ops btrfs_extent_io_ops; - -static struct kmem_cache *btrfs_inode_cachep; -struct kmem_cache *btrfs_trans_handle_cachep; -struct kmem_cache *btrfs_transaction_cachep; -struct kmem_cache *btrfs_path_cachep; -struct kmem_cache *btrfs_free_space_cachep; - -#define S_SHIFT 12 -static const unsigned char btrfs_type_by_mode[S_IFMT >> S_SHIFT] = { - [S_IFREG >> S_SHIFT] = BTRFS_FT_REG_FILE, - [S_IFDIR >> S_SHIFT] = BTRFS_FT_DIR, - [S_IFCHR >> S_SHIFT] = BTRFS_FT_CHRDEV, - [S_IFBLK >> S_SHIFT] = BTRFS_FT_BLKDEV, - [S_IFIFO >> S_SHIFT] = BTRFS_FT_FIFO, - [S_IFSOCK >> S_SHIFT] = BTRFS_FT_SOCK, - [S_IFLNK >> S_SHIFT] = BTRFS_FT_SYMLINK, -}; - -static int btrfs_setsize(struct inode *inode, struct iattr *attr); -static int btrfs_truncate(struct inode *inode); -static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent); -static noinline int cow_file_range(struct inode *inode, - struct page *locked_page, - u64 start, u64 end, u64 delalloc_end, - int *page_started, unsigned long *nr_written, - int unlock, struct btrfs_dedupe_hash *hash); -static struct extent_map *create_pinned_em(struct inode *inode, u64 start, - u64 len, u64 orig_start, - u64 block_start, u64 block_len, - u64 orig_block_len, u64 ram_bytes, - int type); - -static int btrfs_dirty_inode(struct inode *inode); - -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS -void btrfs_test_inode_set_ops(struct inode *inode) -{ - BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; -} -#endif - -static int btrfs_init_inode_security(struct btrfs_trans_handle *trans, - struct inode *inode, struct inode *dir, - const struct qstr *qstr) -{ - int err; - - err = btrfs_init_acl(trans, inode, dir); - if (!err) - err = btrfs_xattr_security_init(trans, inode, dir, qstr); - return err; -} - -/* - * this does all the hard work for inserting an inline extent into - * the btree. The caller should have done a btrfs_drop_extents so that - * no overlapping inline items exist in the btree - */ -static int insert_inline_extent(struct btrfs_trans_handle *trans, - struct btrfs_path *path, int extent_inserted, - struct btrfs_root *root, struct inode *inode, - u64 start, size_t size, size_t compressed_size, - int compress_type, - struct page **compressed_pages) -{ - struct extent_buffer *leaf; - struct page *page = NULL; - char *kaddr; - unsigned long ptr; - struct btrfs_file_extent_item *ei; - int err = 0; - int ret; - size_t cur_size = size; - unsigned long offset; - - if (compressed_size && compressed_pages) - cur_size = compressed_size; - - inode_add_bytes(inode, size); - - if (!extent_inserted) { - struct btrfs_key key; - size_t datasize; - - key.objectid = btrfs_ino(inode); - key.offset = start; - key.type = BTRFS_EXTENT_DATA_KEY; - - datasize = btrfs_file_extent_calc_inline_size(cur_size); - path->leave_spinning = 1; - ret = btrfs_insert_empty_item(trans, root, path, &key, - datasize); - if (ret) { - err = ret; - goto fail; - } - } - leaf = path->nodes[0]; - ei = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - btrfs_set_file_extent_generation(leaf, ei, trans->transid); - btrfs_set_file_extent_type(leaf, ei, BTRFS_FILE_EXTENT_INLINE); - btrfs_set_file_extent_encryption(leaf, ei, 0); - btrfs_set_file_extent_other_encoding(leaf, ei, 0); - btrfs_set_file_extent_ram_bytes(leaf, ei, size); - ptr = btrfs_file_extent_inline_start(ei); - - if (compress_type != BTRFS_COMPRESS_NONE) { - struct page *cpage; - int i = 0; - while (compressed_size > 0) { - cpage = compressed_pages[i]; - cur_size = min_t(unsigned long, compressed_size, - PAGE_SIZE); - - kaddr = kmap_atomic(cpage); - write_extent_buffer(leaf, kaddr, ptr, cur_size); - kunmap_atomic(kaddr); - - i++; - ptr += cur_size; - compressed_size -= cur_size; - } - btrfs_set_file_extent_compression(leaf, ei, - compress_type); - } else { - page = find_get_page(inode->i_mapping, - start >> PAGE_SHIFT); - btrfs_set_file_extent_compression(leaf, ei, 0); - kaddr = kmap_atomic(page); - offset = start & (PAGE_SIZE - 1); - write_extent_buffer(leaf, kaddr + offset, ptr, size); - kunmap_atomic(kaddr); - put_page(page); - } - btrfs_mark_buffer_dirty(leaf); - btrfs_release_path(path); - - /* - * we're an inline extent, so nobody can - * extend the file past i_size without locking - * a page we already have locked. - * - * We must do any isize and inode updates - * before we unlock the pages. Otherwise we - * could end up racing with unlink. - */ - BTRFS_I(inode)->disk_i_size = inode->i_size; - ret = btrfs_update_inode(trans, root, inode); - - return ret; -fail: - return err; -} - - -/* - * conditionally insert an inline extent into the file. This - * does the checks required to make sure the data is small enough - * to fit as an inline extent. - */ -static noinline int cow_file_range_inline(struct btrfs_root *root, - struct inode *inode, u64 start, - u64 end, size_t compressed_size, - int compress_type, - struct page **compressed_pages) -{ - struct btrfs_trans_handle *trans; - u64 isize = i_size_read(inode); - u64 actual_end = min(end + 1, isize); - u64 inline_len = actual_end - start; - u64 aligned_end = ALIGN(end, root->sectorsize); - u64 data_len = inline_len; - int ret; - struct btrfs_path *path; - int extent_inserted = 0; - u32 extent_item_size; - - if (compressed_size) - data_len = compressed_size; - - if (start > 0 || - actual_end > root->sectorsize || - data_len > BTRFS_MAX_INLINE_DATA_SIZE(root) || - (!compressed_size && - (actual_end & (root->sectorsize - 1)) == 0) || - end + 1 < isize || - data_len > root->fs_info->max_inline) { - return 1; - } - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) { - btrfs_free_path(path); - return PTR_ERR(trans); - } - trans->block_rsv = &root->fs_info->delalloc_block_rsv; - - if (compressed_size && compressed_pages) - extent_item_size = btrfs_file_extent_calc_inline_size( - compressed_size); - else - extent_item_size = btrfs_file_extent_calc_inline_size( - inline_len); - - ret = __btrfs_drop_extents(trans, root, inode, path, - start, aligned_end, NULL, - 1, 1, extent_item_size, &extent_inserted); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out; - } - - if (isize > actual_end) - inline_len = min_t(u64, isize, actual_end); - ret = insert_inline_extent(trans, path, extent_inserted, - root, inode, start, - inline_len, compressed_size, - compress_type, compressed_pages); - if (ret && ret != -ENOSPC) { - btrfs_abort_transaction(trans, ret); - goto out; - } else if (ret == -ENOSPC) { - ret = 1; - goto out; - } - - set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(inode)->runtime_flags); - btrfs_delalloc_release_metadata(inode, end + 1 - start); - btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0); -out: - /* - * Don't forget to free the reserved space, as for inlined extent - * it won't count as data extent, free them directly here. - * And at reserve time, it's always aligned to page size, so - * just free one page here. - */ - btrfs_qgroup_free_data(inode, 0, PAGE_SIZE); - btrfs_free_path(path); - btrfs_end_transaction(trans, root); - return ret; -} - -struct async_extent { - u64 start; - u64 ram_size; - u64 compressed_size; - struct page **pages; - unsigned long nr_pages; - int compress_type; - struct list_head list; -}; - -struct async_cow { - struct inode *inode; - struct btrfs_root *root; - struct page *locked_page; - u64 start; - u64 end; - struct list_head extents; - struct btrfs_work work; -}; - -static noinline int add_async_extent(struct async_cow *cow, - u64 start, u64 ram_size, - u64 compressed_size, - struct page **pages, - unsigned long nr_pages, - int compress_type) -{ - struct async_extent *async_extent; - - async_extent = kmalloc(sizeof(*async_extent), GFP_NOFS); - BUG_ON(!async_extent); /* -ENOMEM */ - async_extent->start = start; - async_extent->ram_size = ram_size; - async_extent->compressed_size = compressed_size; - async_extent->pages = pages; - async_extent->nr_pages = nr_pages; - async_extent->compress_type = compress_type; - list_add_tail(&async_extent->list, &cow->extents); - return 0; -} - -static inline int inode_need_compress(struct inode *inode) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - - /* force compress */ - if (btrfs_test_opt(root->fs_info, FORCE_COMPRESS)) - return 1; - /* bad compression ratios */ - if (BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS) - return 0; - if (btrfs_test_opt(root->fs_info, COMPRESS) || - BTRFS_I(inode)->flags & BTRFS_INODE_COMPRESS || - BTRFS_I(inode)->force_compress) - return 1; - return 0; -} - -/* - * we create compressed extents in two phases. The first - * phase compresses a range of pages that have already been - * locked (both pages and state bits are locked). - * - * This is done inside an ordered work queue, and the compression - * is spread across many cpus. The actual IO submission is step - * two, and the ordered work queue takes care of making sure that - * happens in the same order things were put onto the queue by - * writepages and friends. - * - * If this code finds it can't get good compression, it puts an - * entry onto the work queue to write the uncompressed bytes. This - * makes sure that both compressed inodes and uncompressed inodes - * are written in the same order that the flusher thread sent them - * down. - */ -static noinline void compress_file_range(struct inode *inode, - struct page *locked_page, - u64 start, u64 end, - struct async_cow *async_cow, - int *num_added) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - u64 num_bytes; - u64 blocksize = root->sectorsize; - u64 actual_end; - u64 isize = i_size_read(inode); - int ret = 0; - struct page **pages = NULL; - unsigned long nr_pages; - unsigned long nr_pages_ret = 0; - unsigned long total_compressed = 0; - unsigned long total_in = 0; - unsigned long max_compressed = SZ_128K; - unsigned long max_uncompressed = SZ_128K; - int i; - int will_compress; - int compress_type = root->fs_info->compress_type; - int redirty = 0; - - /* if this is a small write inside eof, kick off a defrag */ - if ((end - start + 1) < SZ_16K && - (start > 0 || end + 1 < BTRFS_I(inode)->disk_i_size)) - btrfs_add_inode_defrag(NULL, inode); - - actual_end = min_t(u64, isize, end + 1); -again: - will_compress = 0; - nr_pages = (end >> PAGE_SHIFT) - (start >> PAGE_SHIFT) + 1; - nr_pages = min_t(unsigned long, nr_pages, SZ_128K / PAGE_SIZE); - - /* - * we don't want to send crud past the end of i_size through - * compression, that's just a waste of CPU time. So, if the - * end of the file is before the start of our current - * requested range of bytes, we bail out to the uncompressed - * cleanup code that can deal with all of this. - * - * It isn't really the fastest way to fix things, but this is a - * very uncommon corner. - */ - if (actual_end <= start) - goto cleanup_and_bail_uncompressed; - - total_compressed = actual_end - start; - - /* - * skip compression for a small file range(<=blocksize) that - * isn't an inline extent, since it doesn't save disk space at all. - */ - if (total_compressed <= blocksize && - (start > 0 || end + 1 < BTRFS_I(inode)->disk_i_size)) - goto cleanup_and_bail_uncompressed; - - /* we want to make sure that amount of ram required to uncompress - * an extent is reasonable, so we limit the total size in ram - * of a compressed extent to 128k. This is a crucial number - * because it also controls how easily we can spread reads across - * cpus for decompression. - * - * We also want to make sure the amount of IO required to do - * a random read is reasonably small, so we limit the size of - * a compressed extent to 128k. - */ - total_compressed = min(total_compressed, max_uncompressed); - num_bytes = ALIGN(end - start + 1, blocksize); - num_bytes = max(blocksize, num_bytes); - total_in = 0; - ret = 0; - - /* - * we do compression for mount -o compress and when the - * inode has not been flagged as nocompress. This flag can - * change at any time if we discover bad compression ratios. - */ - if (inode_need_compress(inode)) { - WARN_ON(pages); - pages = kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS); - if (!pages) { - /* just bail out to the uncompressed code */ - goto cont; - } - - if (BTRFS_I(inode)->force_compress) - compress_type = BTRFS_I(inode)->force_compress; - - /* - * we need to call clear_page_dirty_for_io on each - * page in the range. Otherwise applications with the file - * mmap'd can wander in and change the page contents while - * we are compressing them. - * - * If the compression fails for any reason, we set the pages - * dirty again later on. - */ - extent_range_clear_dirty_for_io(inode, start, end); - redirty = 1; - ret = btrfs_compress_pages(compress_type, - inode->i_mapping, start, - total_compressed, pages, - nr_pages, &nr_pages_ret, - &total_in, - &total_compressed, - max_compressed); - - if (!ret) { - unsigned long offset = total_compressed & - (PAGE_SIZE - 1); - struct page *page = pages[nr_pages_ret - 1]; - char *kaddr; - - /* zero the tail end of the last page, we might be - * sending it down to disk - */ - if (offset) { - kaddr = kmap_atomic(page); - memset(kaddr + offset, 0, - PAGE_SIZE - offset); - kunmap_atomic(kaddr); - } - will_compress = 1; - } - } -cont: - if (start == 0) { - /* lets try to make an inline extent */ - if (ret || total_in < (actual_end - start)) { - /* we didn't compress the entire range, try - * to make an uncompressed inline extent. - */ - ret = cow_file_range_inline(root, inode, start, end, - 0, 0, NULL); - } else { - /* try making a compressed inline extent */ - ret = cow_file_range_inline(root, inode, start, end, - total_compressed, - compress_type, pages); - } - if (ret <= 0) { - unsigned long clear_flags = EXTENT_DELALLOC | - EXTENT_DEFRAG; - unsigned long page_error_op; - - clear_flags |= (ret < 0) ? EXTENT_DO_ACCOUNTING : 0; - page_error_op = ret < 0 ? PAGE_SET_ERROR : 0; - - /* - * inline extent creation worked or returned error, - * we don't need to create any more async work items. - * Unlock and free up our temp pages. - */ - extent_clear_unlock_delalloc(inode, start, end, end, - NULL, clear_flags, - PAGE_UNLOCK | - PAGE_CLEAR_DIRTY | - PAGE_SET_WRITEBACK | - page_error_op | - PAGE_END_WRITEBACK); - btrfs_free_reserved_data_space_noquota(inode, start, - end - start + 1); - goto free_pages_out; - } - } - - if (will_compress) { - /* - * we aren't doing an inline extent round the compressed size - * up to a block size boundary so the allocator does sane - * things - */ - total_compressed = ALIGN(total_compressed, blocksize); - - /* - * one last check to make sure the compression is really a - * win, compare the page count read with the blocks on disk - */ - total_in = ALIGN(total_in, PAGE_SIZE); - if (total_compressed >= total_in) { - will_compress = 0; - } else { - num_bytes = total_in; - *num_added += 1; - - /* - * The async work queues will take care of doing actual - * allocation on disk for these compressed pages, and - * will submit them to the elevator. - */ - add_async_extent(async_cow, start, num_bytes, - total_compressed, pages, nr_pages_ret, - compress_type); - - if (start + num_bytes < end) { - start += num_bytes; - pages = NULL; - cond_resched(); - goto again; - } - return; - } - } - if (pages) { - /* - * the compression code ran but failed to make things smaller, - * free any pages it allocated and our page pointer array - */ - for (i = 0; i < nr_pages_ret; i++) { - WARN_ON(pages[i]->mapping); - put_page(pages[i]); - } - kfree(pages); - pages = NULL; - total_compressed = 0; - nr_pages_ret = 0; - - /* flag the file so we don't compress in the future */ - if (!btrfs_test_opt(root->fs_info, FORCE_COMPRESS) && - !(BTRFS_I(inode)->force_compress)) { - BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS; - } - } -cleanup_and_bail_uncompressed: - /* - * No compression, but we still need to write the pages in the file - * we've been given so far. redirty the locked page if it corresponds - * to our extent and set things up for the async work queue to run - * cow_file_range to do the normal delalloc dance. - */ - if (page_offset(locked_page) >= start && - page_offset(locked_page) <= end) - __set_page_dirty_nobuffers(locked_page); - /* unlocked later on in the async handlers */ - - if (redirty) - extent_range_redirty_for_io(inode, start, end); - add_async_extent(async_cow, start, end - start + 1, 0, NULL, 0, - BTRFS_COMPRESS_NONE); - *num_added += 1; - - return; - -free_pages_out: - for (i = 0; i < nr_pages_ret; i++) { - WARN_ON(pages[i]->mapping); - put_page(pages[i]); - } - kfree(pages); -} - -static void free_async_extent_pages(struct async_extent *async_extent) -{ - int i; - - if (!async_extent->pages) - return; - - for (i = 0; i < async_extent->nr_pages; i++) { - WARN_ON(async_extent->pages[i]->mapping); - put_page(async_extent->pages[i]); - } - kfree(async_extent->pages); - async_extent->nr_pages = 0; - async_extent->pages = NULL; -} - -/* - * phase two of compressed writeback. This is the ordered portion - * of the code, which only gets called in the order the work was - * queued. We walk all the async extents created by compress_file_range - * and send them down to the disk. - */ -static noinline void submit_compressed_extents(struct inode *inode, - struct async_cow *async_cow) -{ - struct async_extent *async_extent; - u64 alloc_hint = 0; - struct btrfs_key ins; - struct extent_map *em; - struct btrfs_root *root = BTRFS_I(inode)->root; - struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; - struct extent_io_tree *io_tree; - int ret = 0; - -again: - while (!list_empty(&async_cow->extents)) { - async_extent = list_entry(async_cow->extents.next, - struct async_extent, list); - list_del(&async_extent->list); - - io_tree = &BTRFS_I(inode)->io_tree; - -retry: - /* did the compression code fall back to uncompressed IO? */ - if (!async_extent->pages) { - int page_started = 0; - unsigned long nr_written = 0; - - lock_extent(io_tree, async_extent->start, - async_extent->start + - async_extent->ram_size - 1); - - /* allocate blocks */ - ret = cow_file_range(inode, async_cow->locked_page, - async_extent->start, - async_extent->start + - async_extent->ram_size - 1, - async_extent->start + - async_extent->ram_size - 1, - &page_started, &nr_written, 0, - NULL); - - /* JDM XXX */ - - /* - * if page_started, cow_file_range inserted an - * inline extent and took care of all the unlocking - * and IO for us. Otherwise, we need to submit - * all those pages down to the drive. - */ - if (!page_started && !ret) - extent_write_locked_range(io_tree, - inode, async_extent->start, - async_extent->start + - async_extent->ram_size - 1, - btrfs_get_extent, - WB_SYNC_ALL); - else if (ret) - unlock_page(async_cow->locked_page); - kfree(async_extent); - cond_resched(); - continue; - } - - lock_extent(io_tree, async_extent->start, - async_extent->start + async_extent->ram_size - 1); - - ret = btrfs_reserve_extent(root, async_extent->ram_size, - async_extent->compressed_size, - async_extent->compressed_size, - 0, alloc_hint, &ins, 1, 1); - if (ret) { - free_async_extent_pages(async_extent); - - if (ret == -ENOSPC) { - unlock_extent(io_tree, async_extent->start, - async_extent->start + - async_extent->ram_size - 1); - - /* - * we need to redirty the pages if we decide to - * fallback to uncompressed IO, otherwise we - * will not submit these pages down to lower - * layers. - */ - extent_range_redirty_for_io(inode, - async_extent->start, - async_extent->start + - async_extent->ram_size - 1); - - goto retry; - } - goto out_free; - } - /* - * here we're doing allocation and writeback of the - * compressed pages - */ - btrfs_drop_extent_cache(inode, async_extent->start, - async_extent->start + - async_extent->ram_size - 1, 0); - - em = alloc_extent_map(); - if (!em) { - ret = -ENOMEM; - goto out_free_reserve; - } - em->start = async_extent->start; - em->len = async_extent->ram_size; - em->orig_start = em->start; - em->mod_start = em->start; - em->mod_len = em->len; - - em->block_start = ins.objectid; - em->block_len = ins.offset; - em->orig_block_len = ins.offset; - em->ram_bytes = async_extent->ram_size; - em->bdev = root->fs_info->fs_devices->latest_bdev; - em->compress_type = async_extent->compress_type; - set_bit(EXTENT_FLAG_PINNED, &em->flags); - set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); - em->generation = -1; - - while (1) { - write_lock(&em_tree->lock); - ret = add_extent_mapping(em_tree, em, 1); - write_unlock(&em_tree->lock); - if (ret != -EEXIST) { - free_extent_map(em); - break; - } - btrfs_drop_extent_cache(inode, async_extent->start, - async_extent->start + - async_extent->ram_size - 1, 0); - } - - if (ret) - goto out_free_reserve; - - ret = btrfs_add_ordered_extent_compress(inode, - async_extent->start, - ins.objectid, - async_extent->ram_size, - ins.offset, - BTRFS_ORDERED_COMPRESSED, - async_extent->compress_type); - if (ret) { - btrfs_drop_extent_cache(inode, async_extent->start, - async_extent->start + - async_extent->ram_size - 1, 0); - goto out_free_reserve; - } - btrfs_dec_block_group_reservations(root->fs_info, ins.objectid); - - /* - * clear dirty, set writeback and unlock the pages. - */ - extent_clear_unlock_delalloc(inode, async_extent->start, - async_extent->start + - async_extent->ram_size - 1, - async_extent->start + - async_extent->ram_size - 1, - NULL, EXTENT_LOCKED | EXTENT_DELALLOC, - PAGE_UNLOCK | PAGE_CLEAR_DIRTY | - PAGE_SET_WRITEBACK); - ret = btrfs_submit_compressed_write(inode, - async_extent->start, - async_extent->ram_size, - ins.objectid, - ins.offset, async_extent->pages, - async_extent->nr_pages); - if (ret) { - struct extent_io_tree *tree = &BTRFS_I(inode)->io_tree; - struct page *p = async_extent->pages[0]; - const u64 start = async_extent->start; - const u64 end = start + async_extent->ram_size - 1; - - p->mapping = inode->i_mapping; - tree->ops->writepage_end_io_hook(p, start, end, - NULL, 0); - p->mapping = NULL; - extent_clear_unlock_delalloc(inode, start, end, end, - NULL, 0, - PAGE_END_WRITEBACK | - PAGE_SET_ERROR); - free_async_extent_pages(async_extent); - } - alloc_hint = ins.objectid + ins.offset; - kfree(async_extent); - cond_resched(); - } - return; -out_free_reserve: - btrfs_dec_block_group_reservations(root->fs_info, ins.objectid); - btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1); -out_free: - extent_clear_unlock_delalloc(inode, async_extent->start, - async_extent->start + - async_extent->ram_size - 1, - async_extent->start + - async_extent->ram_size - 1, - NULL, EXTENT_LOCKED | EXTENT_DELALLOC | - EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING, - PAGE_UNLOCK | PAGE_CLEAR_DIRTY | - PAGE_SET_WRITEBACK | PAGE_END_WRITEBACK | - PAGE_SET_ERROR); - free_async_extent_pages(async_extent); - kfree(async_extent); - goto again; -} - -static u64 get_extent_allocation_hint(struct inode *inode, u64 start, - u64 num_bytes) -{ - struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; - struct extent_map *em; - u64 alloc_hint = 0; - - read_lock(&em_tree->lock); - em = search_extent_mapping(em_tree, start, num_bytes); - if (em) { - /* - * if block start isn't an actual block number then find the - * first block in this inode and use that as a hint. If that - * block is also bogus then just don't worry about it. - */ - if (em->block_start >= EXTENT_MAP_LAST_BYTE) { - free_extent_map(em); - em = search_extent_mapping(em_tree, 0, 0); - if (em && em->block_start < EXTENT_MAP_LAST_BYTE) - alloc_hint = em->block_start; - if (em) - free_extent_map(em); - } else { - alloc_hint = em->block_start; - free_extent_map(em); - } - } - read_unlock(&em_tree->lock); - - return alloc_hint; -} - -/* - * when extent_io.c finds a delayed allocation range in the file, - * the call backs end up in this code. The basic idea is to - * allocate extents on disk for the range, and create ordered data structs - * in ram to track those extents. - * - * locked_page is the page that writepage had locked already. We use - * it to make sure we don't do extra locks or unlocks. - * - * *page_started is set to one if we unlock locked_page and do everything - * required to start IO on it. It may be clean and already done with - * IO when we return. - */ -static noinline int cow_file_range(struct inode *inode, - struct page *locked_page, - u64 start, u64 end, u64 delalloc_end, - int *page_started, unsigned long *nr_written, - int unlock, struct btrfs_dedupe_hash *hash) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - u64 alloc_hint = 0; - u64 num_bytes; - unsigned long ram_size; - u64 disk_num_bytes; - u64 cur_alloc_size; - u64 blocksize = root->sectorsize; - struct btrfs_key ins; - struct extent_map *em; - struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; - int ret = 0; - - if (btrfs_is_free_space_inode(inode)) { - WARN_ON_ONCE(1); - ret = -EINVAL; - goto out_unlock; - } - - num_bytes = ALIGN(end - start + 1, blocksize); - num_bytes = max(blocksize, num_bytes); - disk_num_bytes = num_bytes; - - /* if this is a small write inside eof, kick off defrag */ - if (num_bytes < SZ_64K && - (start > 0 || end + 1 < BTRFS_I(inode)->disk_i_size)) - btrfs_add_inode_defrag(NULL, inode); - - if (start == 0) { - /* lets try to make an inline extent */ - ret = cow_file_range_inline(root, inode, start, end, 0, 0, - NULL); - if (ret == 0) { - extent_clear_unlock_delalloc(inode, start, end, - delalloc_end, NULL, - EXTENT_LOCKED | EXTENT_DELALLOC | - EXTENT_DEFRAG, PAGE_UNLOCK | - PAGE_CLEAR_DIRTY | PAGE_SET_WRITEBACK | - PAGE_END_WRITEBACK); - btrfs_free_reserved_data_space_noquota(inode, start, - end - start + 1); - *nr_written = *nr_written + - (end - start + PAGE_SIZE) / PAGE_SIZE; - *page_started = 1; - goto out; - } else if (ret < 0) { - goto out_unlock; - } - } - - BUG_ON(disk_num_bytes > - btrfs_super_total_bytes(root->fs_info->super_copy)); - - alloc_hint = get_extent_allocation_hint(inode, start, num_bytes); - btrfs_drop_extent_cache(inode, start, start + num_bytes - 1, 0); - - while (disk_num_bytes > 0) { - unsigned long op; - - cur_alloc_size = disk_num_bytes; - ret = btrfs_reserve_extent(root, cur_alloc_size, cur_alloc_size, - root->sectorsize, 0, alloc_hint, - &ins, 1, 1); - if (ret < 0) - goto out_unlock; - - em = alloc_extent_map(); - if (!em) { - ret = -ENOMEM; - goto out_reserve; - } - em->start = start; - em->orig_start = em->start; - ram_size = ins.offset; - em->len = ins.offset; - em->mod_start = em->start; - em->mod_len = em->len; - - em->block_start = ins.objectid; - em->block_len = ins.offset; - em->orig_block_len = ins.offset; - em->ram_bytes = ram_size; - em->bdev = root->fs_info->fs_devices->latest_bdev; - set_bit(EXTENT_FLAG_PINNED, &em->flags); - em->generation = -1; - - while (1) { - write_lock(&em_tree->lock); - ret = add_extent_mapping(em_tree, em, 1); - write_unlock(&em_tree->lock); - if (ret != -EEXIST) { - free_extent_map(em); - break; - } - btrfs_drop_extent_cache(inode, start, - start + ram_size - 1, 0); - } - if (ret) - goto out_reserve; - - cur_alloc_size = ins.offset; - ret = btrfs_add_ordered_extent(inode, start, ins.objectid, - ram_size, cur_alloc_size, 0); - if (ret) - goto out_drop_extent_cache; - - if (root->root_key.objectid == - BTRFS_DATA_RELOC_TREE_OBJECTID) { - ret = btrfs_reloc_clone_csums(inode, start, - cur_alloc_size); - if (ret) - goto out_drop_extent_cache; - } - - btrfs_dec_block_group_reservations(root->fs_info, ins.objectid); - - if (disk_num_bytes < cur_alloc_size) - break; - - /* we're not doing compressed IO, don't unlock the first - * page (which the caller expects to stay locked), don't - * clear any dirty bits and don't set any writeback bits - * - * Do set the Private2 bit so we know this page was properly - * setup for writepage - */ - op = unlock ? PAGE_UNLOCK : 0; - op |= PAGE_SET_PRIVATE2; - - extent_clear_unlock_delalloc(inode, start, - start + ram_size - 1, - delalloc_end, locked_page, - EXTENT_LOCKED | EXTENT_DELALLOC, - op); - disk_num_bytes -= cur_alloc_size; - num_bytes -= cur_alloc_size; - alloc_hint = ins.objectid + ins.offset; - start += cur_alloc_size; - } -out: - return ret; - -out_drop_extent_cache: - btrfs_drop_extent_cache(inode, start, start + ram_size - 1, 0); -out_reserve: - btrfs_dec_block_group_reservations(root->fs_info, ins.objectid); - btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1); -out_unlock: - extent_clear_unlock_delalloc(inode, start, end, delalloc_end, - locked_page, - EXTENT_LOCKED | EXTENT_DO_ACCOUNTING | - EXTENT_DELALLOC | EXTENT_DEFRAG, - PAGE_UNLOCK | PAGE_CLEAR_DIRTY | - PAGE_SET_WRITEBACK | PAGE_END_WRITEBACK); - goto out; -} - -/* - * work queue call back to started compression on a file and pages - */ -static noinline void async_cow_start(struct btrfs_work *work) -{ - struct async_cow *async_cow; - int num_added = 0; - async_cow = container_of(work, struct async_cow, work); - - compress_file_range(async_cow->inode, async_cow->locked_page, - async_cow->start, async_cow->end, async_cow, - &num_added); - if (num_added == 0) { - btrfs_add_delayed_iput(async_cow->inode); - async_cow->inode = NULL; - } -} - -/* - * work queue call back to submit previously compressed pages - */ -static noinline void async_cow_submit(struct btrfs_work *work) -{ - struct async_cow *async_cow; - struct btrfs_root *root; - unsigned long nr_pages; - - async_cow = container_of(work, struct async_cow, work); - - root = async_cow->root; - nr_pages = (async_cow->end - async_cow->start + PAGE_SIZE) >> - PAGE_SHIFT; - - /* - * atomic_sub_return implies a barrier for waitqueue_active - */ - if (atomic_sub_return(nr_pages, &root->fs_info->async_delalloc_pages) < - 5 * SZ_1M && - waitqueue_active(&root->fs_info->async_submit_wait)) - wake_up(&root->fs_info->async_submit_wait); - - if (async_cow->inode) - submit_compressed_extents(async_cow->inode, async_cow); -} - -static noinline void async_cow_free(struct btrfs_work *work) -{ - struct async_cow *async_cow; - async_cow = container_of(work, struct async_cow, work); - if (async_cow->inode) - btrfs_add_delayed_iput(async_cow->inode); - kfree(async_cow); -} - -static int cow_file_range_async(struct inode *inode, struct page *locked_page, - u64 start, u64 end, int *page_started, - unsigned long *nr_written) -{ - struct async_cow *async_cow; - struct btrfs_root *root = BTRFS_I(inode)->root; - unsigned long nr_pages; - u64 cur_end; - int limit = 10 * SZ_1M; - - clear_extent_bit(&BTRFS_I(inode)->io_tree, start, end, EXTENT_LOCKED, - 1, 0, NULL, GFP_NOFS); - while (start < end) { - async_cow = kmalloc(sizeof(*async_cow), GFP_NOFS); - BUG_ON(!async_cow); /* -ENOMEM */ - async_cow->inode = igrab(inode); - async_cow->root = root; - async_cow->locked_page = locked_page; - async_cow->start = start; - - if (BTRFS_I(inode)->flags & BTRFS_INODE_NOCOMPRESS && - !btrfs_test_opt(root->fs_info, FORCE_COMPRESS)) - cur_end = end; - else - cur_end = min(end, start + SZ_512K - 1); - - async_cow->end = cur_end; - INIT_LIST_HEAD(&async_cow->extents); - - btrfs_init_work(&async_cow->work, - btrfs_delalloc_helper, - async_cow_start, async_cow_submit, - async_cow_free); - - nr_pages = (cur_end - start + PAGE_SIZE) >> - PAGE_SHIFT; - atomic_add(nr_pages, &root->fs_info->async_delalloc_pages); - - btrfs_queue_work(root->fs_info->delalloc_workers, - &async_cow->work); - - if (atomic_read(&root->fs_info->async_delalloc_pages) > limit) { - wait_event(root->fs_info->async_submit_wait, - (atomic_read(&root->fs_info->async_delalloc_pages) < - limit)); - } - - while (atomic_read(&root->fs_info->async_submit_draining) && - atomic_read(&root->fs_info->async_delalloc_pages)) { - wait_event(root->fs_info->async_submit_wait, - (atomic_read(&root->fs_info->async_delalloc_pages) == - 0)); - } - - *nr_written += nr_pages; - start = cur_end + 1; - } - *page_started = 1; - return 0; -} - -static noinline int csum_exist_in_range(struct btrfs_root *root, - u64 bytenr, u64 num_bytes) -{ - int ret; - struct btrfs_ordered_sum *sums; - LIST_HEAD(list); - - ret = btrfs_lookup_csums_range(root->fs_info->csum_root, bytenr, - bytenr + num_bytes - 1, &list, 0); - if (ret == 0 && list_empty(&list)) - return 0; - - while (!list_empty(&list)) { - sums = list_entry(list.next, struct btrfs_ordered_sum, list); - list_del(&sums->list); - kfree(sums); - } - return 1; -} - -/* - * when nowcow writeback call back. This checks for snapshots or COW copies - * of the extents that exist in the file, and COWs the file as required. - * - * If no cow copies or snapshots exist, we write directly to the existing - * blocks on disk - */ -static noinline int run_delalloc_nocow(struct inode *inode, - struct page *locked_page, - u64 start, u64 end, int *page_started, int force, - unsigned long *nr_written) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_trans_handle *trans; - struct extent_buffer *leaf; - struct btrfs_path *path; - struct btrfs_file_extent_item *fi; - struct btrfs_key found_key; - u64 cow_start; - u64 cur_offset; - u64 extent_end; - u64 extent_offset; - u64 disk_bytenr; - u64 num_bytes; - u64 disk_num_bytes; - u64 ram_bytes; - int extent_type; - int ret, err; - int type; - int nocow; - int check_prev = 1; - bool nolock; - u64 ino = btrfs_ino(inode); - - path = btrfs_alloc_path(); - if (!path) { - extent_clear_unlock_delalloc(inode, start, end, end, - locked_page, - EXTENT_LOCKED | EXTENT_DELALLOC | - EXTENT_DO_ACCOUNTING | - EXTENT_DEFRAG, PAGE_UNLOCK | - PAGE_CLEAR_DIRTY | - PAGE_SET_WRITEBACK | - PAGE_END_WRITEBACK); - return -ENOMEM; - } - - nolock = btrfs_is_free_space_inode(inode); - - if (nolock) - trans = btrfs_join_transaction_nolock(root); - else - trans = btrfs_join_transaction(root); - - if (IS_ERR(trans)) { - extent_clear_unlock_delalloc(inode, start, end, end, - locked_page, - EXTENT_LOCKED | EXTENT_DELALLOC | - EXTENT_DO_ACCOUNTING | - EXTENT_DEFRAG, PAGE_UNLOCK | - PAGE_CLEAR_DIRTY | - PAGE_SET_WRITEBACK | - PAGE_END_WRITEBACK); - btrfs_free_path(path); - return PTR_ERR(trans); - } - - trans->block_rsv = &root->fs_info->delalloc_block_rsv; - - cow_start = (u64)-1; - cur_offset = start; - while (1) { - ret = btrfs_lookup_file_extent(trans, root, path, ino, - cur_offset, 0); - if (ret < 0) - goto error; - if (ret > 0 && path->slots[0] > 0 && check_prev) { - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &found_key, - path->slots[0] - 1); - if (found_key.objectid == ino && - found_key.type == BTRFS_EXTENT_DATA_KEY) - path->slots[0]--; - } - check_prev = 0; -next_slot: - leaf = path->nodes[0]; - if (path->slots[0] >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) - goto error; - if (ret > 0) - break; - leaf = path->nodes[0]; - } - - nocow = 0; - disk_bytenr = 0; - num_bytes = 0; - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - - if (found_key.objectid > ino) - break; - if (WARN_ON_ONCE(found_key.objectid < ino) || - found_key.type < BTRFS_EXTENT_DATA_KEY) { - path->slots[0]++; - goto next_slot; - } - if (found_key.type > BTRFS_EXTENT_DATA_KEY || - found_key.offset > end) - break; - - if (found_key.offset > cur_offset) { - extent_end = found_key.offset; - extent_type = 0; - goto out_check; - } - - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - extent_type = btrfs_file_extent_type(leaf, fi); - - ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi); - if (extent_type == BTRFS_FILE_EXTENT_REG || - extent_type == BTRFS_FILE_EXTENT_PREALLOC) { - disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); - extent_offset = btrfs_file_extent_offset(leaf, fi); - extent_end = found_key.offset + - btrfs_file_extent_num_bytes(leaf, fi); - disk_num_bytes = - btrfs_file_extent_disk_num_bytes(leaf, fi); - if (extent_end <= start) { - path->slots[0]++; - goto next_slot; - } - if (disk_bytenr == 0) - goto out_check; - if (btrfs_file_extent_compression(leaf, fi) || - btrfs_file_extent_encryption(leaf, fi) || - btrfs_file_extent_other_encoding(leaf, fi)) - goto out_check; - if (extent_type == BTRFS_FILE_EXTENT_REG && !force) - goto out_check; - if (btrfs_extent_readonly(root, disk_bytenr)) - goto out_check; - if (btrfs_cross_ref_exist(trans, root, ino, - found_key.offset - - extent_offset, disk_bytenr)) - goto out_check; - disk_bytenr += extent_offset; - disk_bytenr += cur_offset - found_key.offset; - num_bytes = min(end + 1, extent_end) - cur_offset; - /* - * if there are pending snapshots for this root, - * we fall into common COW way. - */ - if (!nolock) { - err = btrfs_start_write_no_snapshoting(root); - if (!err) - goto out_check; - } - /* - * force cow if csum exists in the range. - * this ensure that csum for a given extent are - * either valid or do not exist. - */ - if (csum_exist_in_range(root, disk_bytenr, num_bytes)) - goto out_check; - if (!btrfs_inc_nocow_writers(root->fs_info, - disk_bytenr)) - goto out_check; - nocow = 1; - } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { - extent_end = found_key.offset + - btrfs_file_extent_inline_len(leaf, - path->slots[0], fi); - extent_end = ALIGN(extent_end, root->sectorsize); - } else { - BUG_ON(1); - } -out_check: - if (extent_end <= start) { - path->slots[0]++; - if (!nolock && nocow) - btrfs_end_write_no_snapshoting(root); - if (nocow) - btrfs_dec_nocow_writers(root->fs_info, - disk_bytenr); - goto next_slot; - } - if (!nocow) { - if (cow_start == (u64)-1) - cow_start = cur_offset; - cur_offset = extent_end; - if (cur_offset > end) - break; - path->slots[0]++; - goto next_slot; - } - - btrfs_release_path(path); - if (cow_start != (u64)-1) { - ret = cow_file_range(inode, locked_page, - cow_start, found_key.offset - 1, - end, page_started, nr_written, 1, - NULL); - if (ret) { - if (!nolock && nocow) - btrfs_end_write_no_snapshoting(root); - if (nocow) - btrfs_dec_nocow_writers(root->fs_info, - disk_bytenr); - goto error; - } - cow_start = (u64)-1; - } - - if (extent_type == BTRFS_FILE_EXTENT_PREALLOC) { - struct extent_map *em; - struct extent_map_tree *em_tree; - em_tree = &BTRFS_I(inode)->extent_tree; - em = alloc_extent_map(); - BUG_ON(!em); /* -ENOMEM */ - em->start = cur_offset; - em->orig_start = found_key.offset - extent_offset; - em->len = num_bytes; - em->block_len = num_bytes; - em->block_start = disk_bytenr; - em->orig_block_len = disk_num_bytes; - em->ram_bytes = ram_bytes; - em->bdev = root->fs_info->fs_devices->latest_bdev; - em->mod_start = em->start; - em->mod_len = em->len; - set_bit(EXTENT_FLAG_PINNED, &em->flags); - set_bit(EXTENT_FLAG_FILLING, &em->flags); - em->generation = -1; - while (1) { - write_lock(&em_tree->lock); - ret = add_extent_mapping(em_tree, em, 1); - write_unlock(&em_tree->lock); - if (ret != -EEXIST) { - free_extent_map(em); - break; - } - btrfs_drop_extent_cache(inode, em->start, - em->start + em->len - 1, 0); - } - type = BTRFS_ORDERED_PREALLOC; - } else { - type = BTRFS_ORDERED_NOCOW; - } - - ret = btrfs_add_ordered_extent(inode, cur_offset, disk_bytenr, - num_bytes, num_bytes, type); - if (nocow) - btrfs_dec_nocow_writers(root->fs_info, disk_bytenr); - BUG_ON(ret); /* -ENOMEM */ - - if (root->root_key.objectid == - BTRFS_DATA_RELOC_TREE_OBJECTID) { - ret = btrfs_reloc_clone_csums(inode, cur_offset, - num_bytes); - if (ret) { - if (!nolock && nocow) - btrfs_end_write_no_snapshoting(root); - goto error; - } - } - - extent_clear_unlock_delalloc(inode, cur_offset, - cur_offset + num_bytes - 1, end, - locked_page, EXTENT_LOCKED | - EXTENT_DELALLOC | - EXTENT_CLEAR_DATA_RESV, - PAGE_UNLOCK | PAGE_SET_PRIVATE2); - - if (!nolock && nocow) - btrfs_end_write_no_snapshoting(root); - cur_offset = extent_end; - if (cur_offset > end) - break; - } - btrfs_release_path(path); - - if (cur_offset <= end && cow_start == (u64)-1) { - cow_start = cur_offset; - cur_offset = end; - } - - if (cow_start != (u64)-1) { - ret = cow_file_range(inode, locked_page, cow_start, end, end, - page_started, nr_written, 1, NULL); - if (ret) - goto error; - } - -error: - err = btrfs_end_transaction(trans, root); - if (!ret) - ret = err; - - if (ret && cur_offset < end) - extent_clear_unlock_delalloc(inode, cur_offset, end, end, - locked_page, EXTENT_LOCKED | - EXTENT_DELALLOC | EXTENT_DEFRAG | - EXTENT_DO_ACCOUNTING, PAGE_UNLOCK | - PAGE_CLEAR_DIRTY | - PAGE_SET_WRITEBACK | - PAGE_END_WRITEBACK); - btrfs_free_path(path); - return ret; -} - -static inline int need_force_cow(struct inode *inode, u64 start, u64 end) -{ - - if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW) && - !(BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC)) - return 0; - - /* - * @defrag_bytes is a hint value, no spinlock held here, - * if is not zero, it means the file is defragging. - * Force cow if given extent needs to be defragged. - */ - if (BTRFS_I(inode)->defrag_bytes && - test_range_bit(&BTRFS_I(inode)->io_tree, start, end, - EXTENT_DEFRAG, 0, NULL)) - return 1; - - return 0; -} - -/* - * extent_io.c call back to do delayed allocation processing - */ -static int run_delalloc_range(struct inode *inode, struct page *locked_page, - u64 start, u64 end, int *page_started, - unsigned long *nr_written) -{ - int ret; - int force_cow = need_force_cow(inode, start, end); - - if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW && !force_cow) { - ret = run_delalloc_nocow(inode, locked_page, start, end, - page_started, 1, nr_written); - } else if (BTRFS_I(inode)->flags & BTRFS_INODE_PREALLOC && !force_cow) { - ret = run_delalloc_nocow(inode, locked_page, start, end, - page_started, 0, nr_written); - } else if (!inode_need_compress(inode)) { - ret = cow_file_range(inode, locked_page, start, end, end, - page_started, nr_written, 1, NULL); - } else { - set_bit(BTRFS_INODE_HAS_ASYNC_EXTENT, - &BTRFS_I(inode)->runtime_flags); - ret = cow_file_range_async(inode, locked_page, start, end, - page_started, nr_written); - } - return ret; -} - -static void btrfs_split_extent_hook(struct inode *inode, - struct extent_state *orig, u64 split) -{ - u64 size; - - /* not delalloc, ignore it */ - if (!(orig->state & EXTENT_DELALLOC)) - return; - - size = orig->end - orig->start + 1; - if (size > BTRFS_MAX_EXTENT_SIZE) { - u64 num_extents; - u64 new_size; - - /* - * See the explanation in btrfs_merge_extent_hook, the same - * applies here, just in reverse. - */ - new_size = orig->end - split + 1; - num_extents = div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1, - BTRFS_MAX_EXTENT_SIZE); - new_size = split - orig->start; - num_extents += div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1, - BTRFS_MAX_EXTENT_SIZE); - if (div64_u64(size + BTRFS_MAX_EXTENT_SIZE - 1, - BTRFS_MAX_EXTENT_SIZE) >= num_extents) - return; - } - - spin_lock(&BTRFS_I(inode)->lock); - BTRFS_I(inode)->outstanding_extents++; - spin_unlock(&BTRFS_I(inode)->lock); -} - -/* - * extent_io.c merge_extent_hook, used to track merged delayed allocation - * extents so we can keep track of new extents that are just merged onto old - * extents, such as when we are doing sequential writes, so we can properly - * account for the metadata space we'll need. - */ -static void btrfs_merge_extent_hook(struct inode *inode, - struct extent_state *new, - struct extent_state *other) -{ - u64 new_size, old_size; - u64 num_extents; - - /* not delalloc, ignore it */ - if (!(other->state & EXTENT_DELALLOC)) - return; - - if (new->start > other->start) - new_size = new->end - other->start + 1; - else - new_size = other->end - new->start + 1; - - /* we're not bigger than the max, unreserve the space and go */ - if (new_size <= BTRFS_MAX_EXTENT_SIZE) { - spin_lock(&BTRFS_I(inode)->lock); - BTRFS_I(inode)->outstanding_extents--; - spin_unlock(&BTRFS_I(inode)->lock); - return; - } - - /* - * We have to add up either side to figure out how many extents were - * accounted for before we merged into one big extent. If the number of - * extents we accounted for is <= the amount we need for the new range - * then we can return, otherwise drop. Think of it like this - * - * [ 4k][MAX_SIZE] - * - * So we've grown the extent by a MAX_SIZE extent, this would mean we - * need 2 outstanding extents, on one side we have 1 and the other side - * we have 1 so they are == and we can return. But in this case - * - * [MAX_SIZE+4k][MAX_SIZE+4k] - * - * Each range on their own accounts for 2 extents, but merged together - * they are only 3 extents worth of accounting, so we need to drop in - * this case. - */ - old_size = other->end - other->start + 1; - num_extents = div64_u64(old_size + BTRFS_MAX_EXTENT_SIZE - 1, - BTRFS_MAX_EXTENT_SIZE); - old_size = new->end - new->start + 1; - num_extents += div64_u64(old_size + BTRFS_MAX_EXTENT_SIZE - 1, - BTRFS_MAX_EXTENT_SIZE); - - if (div64_u64(new_size + BTRFS_MAX_EXTENT_SIZE - 1, - BTRFS_MAX_EXTENT_SIZE) >= num_extents) - return; - - spin_lock(&BTRFS_I(inode)->lock); - BTRFS_I(inode)->outstanding_extents--; - spin_unlock(&BTRFS_I(inode)->lock); -} - -static void btrfs_add_delalloc_inodes(struct btrfs_root *root, - struct inode *inode) -{ - spin_lock(&root->delalloc_lock); - if (list_empty(&BTRFS_I(inode)->delalloc_inodes)) { - list_add_tail(&BTRFS_I(inode)->delalloc_inodes, - &root->delalloc_inodes); - set_bit(BTRFS_INODE_IN_DELALLOC_LIST, - &BTRFS_I(inode)->runtime_flags); - root->nr_delalloc_inodes++; - if (root->nr_delalloc_inodes == 1) { - spin_lock(&root->fs_info->delalloc_root_lock); - BUG_ON(!list_empty(&root->delalloc_root)); - list_add_tail(&root->delalloc_root, - &root->fs_info->delalloc_roots); - spin_unlock(&root->fs_info->delalloc_root_lock); - } - } - spin_unlock(&root->delalloc_lock); -} - -static void btrfs_del_delalloc_inode(struct btrfs_root *root, - struct inode *inode) -{ - spin_lock(&root->delalloc_lock); - if (!list_empty(&BTRFS_I(inode)->delalloc_inodes)) { - list_del_init(&BTRFS_I(inode)->delalloc_inodes); - clear_bit(BTRFS_INODE_IN_DELALLOC_LIST, - &BTRFS_I(inode)->runtime_flags); - root->nr_delalloc_inodes--; - if (!root->nr_delalloc_inodes) { - spin_lock(&root->fs_info->delalloc_root_lock); - BUG_ON(list_empty(&root->delalloc_root)); - list_del_init(&root->delalloc_root); - spin_unlock(&root->fs_info->delalloc_root_lock); - } - } - spin_unlock(&root->delalloc_lock); -} - -/* - * extent_io.c set_bit_hook, used to track delayed allocation - * bytes in this file, and to maintain the list of inodes that - * have pending delalloc work to be done. - */ -static void btrfs_set_bit_hook(struct inode *inode, - struct extent_state *state, unsigned *bits) -{ - - if ((*bits & EXTENT_DEFRAG) && !(*bits & EXTENT_DELALLOC)) - WARN_ON(1); - /* - * set_bit and clear bit hooks normally require _irqsave/restore - * but in this case, we are only testing for the DELALLOC - * bit, which is only set or cleared with irqs on - */ - if (!(state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) { - struct btrfs_root *root = BTRFS_I(inode)->root; - u64 len = state->end + 1 - state->start; - bool do_list = !btrfs_is_free_space_inode(inode); - - if (*bits & EXTENT_FIRST_DELALLOC) { - *bits &= ~EXTENT_FIRST_DELALLOC; - } else { - spin_lock(&BTRFS_I(inode)->lock); - BTRFS_I(inode)->outstanding_extents++; - spin_unlock(&BTRFS_I(inode)->lock); - } - - /* For sanity tests */ - if (btrfs_is_testing(root->fs_info)) - return; - - __percpu_counter_add(&root->fs_info->delalloc_bytes, len, - root->fs_info->delalloc_batch); - spin_lock(&BTRFS_I(inode)->lock); - BTRFS_I(inode)->delalloc_bytes += len; - if (*bits & EXTENT_DEFRAG) - BTRFS_I(inode)->defrag_bytes += len; - if (do_list && !test_bit(BTRFS_INODE_IN_DELALLOC_LIST, - &BTRFS_I(inode)->runtime_flags)) - btrfs_add_delalloc_inodes(root, inode); - spin_unlock(&BTRFS_I(inode)->lock); - } -} - -/* - * extent_io.c clear_bit_hook, see set_bit_hook for why - */ -static void btrfs_clear_bit_hook(struct inode *inode, - struct extent_state *state, - unsigned *bits) -{ - u64 len = state->end + 1 - state->start; - u64 num_extents = div64_u64(len + BTRFS_MAX_EXTENT_SIZE -1, - BTRFS_MAX_EXTENT_SIZE); - - spin_lock(&BTRFS_I(inode)->lock); - if ((state->state & EXTENT_DEFRAG) && (*bits & EXTENT_DEFRAG)) - BTRFS_I(inode)->defrag_bytes -= len; - spin_unlock(&BTRFS_I(inode)->lock); - - /* - * set_bit and clear bit hooks normally require _irqsave/restore - * but in this case, we are only testing for the DELALLOC - * bit, which is only set or cleared with irqs on - */ - if ((state->state & EXTENT_DELALLOC) && (*bits & EXTENT_DELALLOC)) { - struct btrfs_root *root = BTRFS_I(inode)->root; - bool do_list = !btrfs_is_free_space_inode(inode); - - if (*bits & EXTENT_FIRST_DELALLOC) { - *bits &= ~EXTENT_FIRST_DELALLOC; - } else if (!(*bits & EXTENT_DO_ACCOUNTING)) { - spin_lock(&BTRFS_I(inode)->lock); - BTRFS_I(inode)->outstanding_extents -= num_extents; - spin_unlock(&BTRFS_I(inode)->lock); - } - - /* - * We don't reserve metadata space for space cache inodes so we - * don't need to call dellalloc_release_metadata if there is an - * error. - */ - if (*bits & EXTENT_DO_ACCOUNTING && - root != root->fs_info->tree_root) - btrfs_delalloc_release_metadata(inode, len); - - /* For sanity tests. */ - if (btrfs_is_testing(root->fs_info)) - return; - - if (root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID - && do_list && !(state->state & EXTENT_NORESERVE) - && (*bits & (EXTENT_DO_ACCOUNTING | - EXTENT_CLEAR_DATA_RESV))) - btrfs_free_reserved_data_space_noquota(inode, - state->start, len); - - __percpu_counter_add(&root->fs_info->delalloc_bytes, -len, - root->fs_info->delalloc_batch); - spin_lock(&BTRFS_I(inode)->lock); - BTRFS_I(inode)->delalloc_bytes -= len; - if (do_list && BTRFS_I(inode)->delalloc_bytes == 0 && - test_bit(BTRFS_INODE_IN_DELALLOC_LIST, - &BTRFS_I(inode)->runtime_flags)) - btrfs_del_delalloc_inode(root, inode); - spin_unlock(&BTRFS_I(inode)->lock); - } -} - -/* - * extent_io.c merge_bio_hook, this must check the chunk tree to make sure - * we don't create bios that span stripes or chunks - * - * return 1 if page cannot be merged to bio - * return 0 if page can be merged to bio - * return error otherwise - */ -int btrfs_merge_bio_hook(struct page *page, unsigned long offset, - size_t size, struct bio *bio, - unsigned long bio_flags) -{ - struct btrfs_root *root = BTRFS_I(page->mapping->host)->root; - u64 logical = (u64)bio->bi_iter.bi_sector << 9; - u64 length = 0; - u64 map_length; - int ret; - - if (bio_flags & EXTENT_BIO_COMPRESSED) - return 0; - - length = bio->bi_iter.bi_size; - map_length = length; - ret = btrfs_map_block(root->fs_info, bio_op(bio), logical, - &map_length, NULL, 0); - if (ret < 0) - return ret; - if (map_length < length + size) - return 1; - return 0; -} - -/* - * in order to insert checksums into the metadata in large chunks, - * we wait until bio submission time. All the pages in the bio are - * checksummed and sums are attached onto the ordered extent record. - * - * At IO completion time the cums attached on the ordered extent record - * are inserted into the btree - */ -static int __btrfs_submit_bio_start(struct inode *inode, struct bio *bio, - int mirror_num, unsigned long bio_flags, - u64 bio_offset) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - int ret = 0; - - ret = btrfs_csum_one_bio(root, inode, bio, 0, 0); - BUG_ON(ret); /* -ENOMEM */ - return 0; -} - -/* - * in order to insert checksums into the metadata in large chunks, - * we wait until bio submission time. All the pages in the bio are - * checksummed and sums are attached onto the ordered extent record. - * - * At IO completion time the cums attached on the ordered extent record - * are inserted into the btree - */ -static int __btrfs_submit_bio_done(struct inode *inode, struct bio *bio, - int mirror_num, unsigned long bio_flags, - u64 bio_offset) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - int ret; - - ret = btrfs_map_bio(root, bio, mirror_num, 1); - if (ret) { - bio->bi_error = ret; - bio_endio(bio); - } - return ret; -} - -/* - * extent_io.c submission hook. This does the right thing for csum calculation - * on write, or reading the csums from the tree before a read - */ -static int btrfs_submit_bio_hook(struct inode *inode, struct bio *bio, - int mirror_num, unsigned long bio_flags, - u64 bio_offset) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - enum btrfs_wq_endio_type metadata = BTRFS_WQ_ENDIO_DATA; - int ret = 0; - int skip_sum; - int async = !atomic_read(&BTRFS_I(inode)->sync_writers); - - skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; - - if (btrfs_is_free_space_inode(inode)) - metadata = BTRFS_WQ_ENDIO_FREE_SPACE; - - if (bio_op(bio) != REQ_OP_WRITE) { - ret = btrfs_bio_wq_end_io(root->fs_info, bio, metadata); - if (ret) - goto out; - - if (bio_flags & EXTENT_BIO_COMPRESSED) { - ret = btrfs_submit_compressed_read(inode, bio, - mirror_num, - bio_flags); - goto out; - } else if (!skip_sum) { - ret = btrfs_lookup_bio_sums(root, inode, bio, NULL); - if (ret) - goto out; - } - goto mapit; - } else if (async && !skip_sum) { - /* csum items have already been cloned */ - if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID) - goto mapit; - /* we're doing a write, do the async checksumming */ - ret = btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, - inode, bio, mirror_num, - bio_flags, bio_offset, - __btrfs_submit_bio_start, - __btrfs_submit_bio_done); - goto out; - } else if (!skip_sum) { - ret = btrfs_csum_one_bio(root, inode, bio, 0, 0); - if (ret) - goto out; - } - -mapit: - ret = btrfs_map_bio(root, bio, mirror_num, 0); - -out: - if (ret < 0) { - bio->bi_error = ret; - bio_endio(bio); - } - return ret; -} - -/* - * given a list of ordered sums record them in the inode. This happens - * at IO completion time based on sums calculated at bio submission time. - */ -static noinline int add_pending_csums(struct btrfs_trans_handle *trans, - struct inode *inode, u64 file_offset, - struct list_head *list) -{ - struct btrfs_ordered_sum *sum; - - list_for_each_entry(sum, list, list) { - trans->adding_csums = 1; - btrfs_csum_file_blocks(trans, - BTRFS_I(inode)->root->fs_info->csum_root, sum); - trans->adding_csums = 0; - } - return 0; -} - -int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end, - struct extent_state **cached_state, int dedupe) -{ - WARN_ON((end & (PAGE_SIZE - 1)) == 0); - return set_extent_delalloc(&BTRFS_I(inode)->io_tree, start, end, - cached_state); -} - -/* see btrfs_writepage_start_hook for details on why this is required */ -struct btrfs_writepage_fixup { - struct page *page; - struct btrfs_work work; -}; - -static void btrfs_writepage_fixup_worker(struct btrfs_work *work) -{ - struct btrfs_writepage_fixup *fixup; - struct btrfs_ordered_extent *ordered; - struct extent_state *cached_state = NULL; - struct page *page; - struct inode *inode; - u64 page_start; - u64 page_end; - int ret; - - fixup = container_of(work, struct btrfs_writepage_fixup, work); - page = fixup->page; -again: - lock_page(page); - if (!page->mapping || !PageDirty(page) || !PageChecked(page)) { - ClearPageChecked(page); - goto out_page; - } - - inode = page->mapping->host; - page_start = page_offset(page); - page_end = page_offset(page) + PAGE_SIZE - 1; - - lock_extent_bits(&BTRFS_I(inode)->io_tree, page_start, page_end, - &cached_state); - - /* already ordered? We're done */ - if (PagePrivate2(page)) - goto out; - - ordered = btrfs_lookup_ordered_range(inode, page_start, - PAGE_SIZE); - if (ordered) { - unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start, - page_end, &cached_state, GFP_NOFS); - unlock_page(page); - btrfs_start_ordered_extent(inode, ordered, 1); - btrfs_put_ordered_extent(ordered); - goto again; - } - - ret = btrfs_delalloc_reserve_space(inode, page_start, - PAGE_SIZE); - if (ret) { - mapping_set_error(page->mapping, ret); - end_extent_writepage(page, ret, page_start, page_end); - ClearPageChecked(page); - goto out; - } - - btrfs_set_extent_delalloc(inode, page_start, page_end, &cached_state, - 0); - ClearPageChecked(page); - set_page_dirty(page); -out: - unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start, page_end, - &cached_state, GFP_NOFS); -out_page: - unlock_page(page); - put_page(page); - kfree(fixup); -} - -/* - * There are a few paths in the higher layers of the kernel that directly - * set the page dirty bit without asking the filesystem if it is a - * good idea. This causes problems because we want to make sure COW - * properly happens and the data=ordered rules are followed. - * - * In our case any range that doesn't have the ORDERED bit set - * hasn't been properly setup for IO. We kick off an async process - * to fix it up. The async helper will wait for ordered extents, set - * the delalloc bit and make it safe to write the page. - */ -static int btrfs_writepage_start_hook(struct page *page, u64 start, u64 end) -{ - struct inode *inode = page->mapping->host; - struct btrfs_writepage_fixup *fixup; - struct btrfs_root *root = BTRFS_I(inode)->root; - - /* this page is properly in the ordered list */ - if (TestClearPagePrivate2(page)) - return 0; - - if (PageChecked(page)) - return -EAGAIN; - - fixup = kzalloc(sizeof(*fixup), GFP_NOFS); - if (!fixup) - return -EAGAIN; - - SetPageChecked(page); - get_page(page); - btrfs_init_work(&fixup->work, btrfs_fixup_helper, - btrfs_writepage_fixup_worker, NULL, NULL); - fixup->page = page; - btrfs_queue_work(root->fs_info->fixup_workers, &fixup->work); - return -EBUSY; -} - -static int insert_reserved_file_extent(struct btrfs_trans_handle *trans, - struct inode *inode, u64 file_pos, - u64 disk_bytenr, u64 disk_num_bytes, - u64 num_bytes, u64 ram_bytes, - u8 compression, u8 encryption, - u16 other_encoding, int extent_type) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_file_extent_item *fi; - struct btrfs_path *path; - struct extent_buffer *leaf; - struct btrfs_key ins; - int extent_inserted = 0; - int ret; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - /* - * we may be replacing one extent in the tree with another. - * The new extent is pinned in the extent map, and we don't want - * to drop it from the cache until it is completely in the btree. - * - * So, tell btrfs_drop_extents to leave this extent in the cache. - * the caller is expected to unpin it and allow it to be merged - * with the others. - */ - ret = __btrfs_drop_extents(trans, root, inode, path, file_pos, - file_pos + num_bytes, NULL, 0, - 1, sizeof(*fi), &extent_inserted); - if (ret) - goto out; - - if (!extent_inserted) { - ins.objectid = btrfs_ino(inode); - ins.offset = file_pos; - ins.type = BTRFS_EXTENT_DATA_KEY; - - path->leave_spinning = 1; - ret = btrfs_insert_empty_item(trans, root, path, &ins, - sizeof(*fi)); - if (ret) - goto out; - } - leaf = path->nodes[0]; - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - btrfs_set_file_extent_generation(leaf, fi, trans->transid); - btrfs_set_file_extent_type(leaf, fi, extent_type); - btrfs_set_file_extent_disk_bytenr(leaf, fi, disk_bytenr); - btrfs_set_file_extent_disk_num_bytes(leaf, fi, disk_num_bytes); - btrfs_set_file_extent_offset(leaf, fi, 0); - btrfs_set_file_extent_num_bytes(leaf, fi, num_bytes); - btrfs_set_file_extent_ram_bytes(leaf, fi, ram_bytes); - btrfs_set_file_extent_compression(leaf, fi, compression); - btrfs_set_file_extent_encryption(leaf, fi, encryption); - btrfs_set_file_extent_other_encoding(leaf, fi, other_encoding); - - btrfs_mark_buffer_dirty(leaf); - btrfs_release_path(path); - - inode_add_bytes(inode, num_bytes); - - ins.objectid = disk_bytenr; - ins.offset = disk_num_bytes; - ins.type = BTRFS_EXTENT_ITEM_KEY; - ret = btrfs_alloc_reserved_file_extent(trans, root, - root->root_key.objectid, - btrfs_ino(inode), file_pos, - ram_bytes, &ins); - /* - * Release the reserved range from inode dirty range map, as it is - * already moved into delayed_ref_head - */ - btrfs_qgroup_release_data(inode, file_pos, ram_bytes); -out: - btrfs_free_path(path); - - return ret; -} - -/* snapshot-aware defrag */ -struct sa_defrag_extent_backref { - struct rb_node node; - struct old_sa_defrag_extent *old; - u64 root_id; - u64 inum; - u64 file_pos; - u64 extent_offset; - u64 num_bytes; - u64 generation; -}; - -struct old_sa_defrag_extent { - struct list_head list; - struct new_sa_defrag_extent *new; - - u64 extent_offset; - u64 bytenr; - u64 offset; - u64 len; - int count; -}; - -struct new_sa_defrag_extent { - struct rb_root root; - struct list_head head; - struct btrfs_path *path; - struct inode *inode; - u64 file_pos; - u64 len; - u64 bytenr; - u64 disk_len; - u8 compress_type; -}; - -static int backref_comp(struct sa_defrag_extent_backref *b1, - struct sa_defrag_extent_backref *b2) -{ - if (b1->root_id < b2->root_id) - return -1; - else if (b1->root_id > b2->root_id) - return 1; - - if (b1->inum < b2->inum) - return -1; - else if (b1->inum > b2->inum) - return 1; - - if (b1->file_pos < b2->file_pos) - return -1; - else if (b1->file_pos > b2->file_pos) - return 1; - - /* - * [------------------------------] ===> (a range of space) - * |<--->| |<---->| =============> (fs/file tree A) - * |<---------------------------->| ===> (fs/file tree B) - * - * A range of space can refer to two file extents in one tree while - * refer to only one file extent in another tree. - * - * So we may process a disk offset more than one time(two extents in A) - * and locate at the same extent(one extent in B), then insert two same - * backrefs(both refer to the extent in B). - */ - return 0; -} - -static void backref_insert(struct rb_root *root, - struct sa_defrag_extent_backref *backref) -{ - struct rb_node **p = &root->rb_node; - struct rb_node *parent = NULL; - struct sa_defrag_extent_backref *entry; - int ret; - - while (*p) { - parent = *p; - entry = rb_entry(parent, struct sa_defrag_extent_backref, node); - - ret = backref_comp(backref, entry); - if (ret < 0) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - - rb_link_node(&backref->node, parent, p); - rb_insert_color(&backref->node, root); -} - -/* - * Note the backref might has changed, and in this case we just return 0. - */ -static noinline int record_one_backref(u64 inum, u64 offset, u64 root_id, - void *ctx) -{ - struct btrfs_file_extent_item *extent; - struct btrfs_fs_info *fs_info; - struct old_sa_defrag_extent *old = ctx; - struct new_sa_defrag_extent *new = old->new; - struct btrfs_path *path = new->path; - struct btrfs_key key; - struct btrfs_root *root; - struct sa_defrag_extent_backref *backref; - struct extent_buffer *leaf; - struct inode *inode = new->inode; - int slot; - int ret; - u64 extent_offset; - u64 num_bytes; - - if (BTRFS_I(inode)->root->root_key.objectid == root_id && - inum == btrfs_ino(inode)) - return 0; - - key.objectid = root_id; - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = (u64)-1; - - fs_info = BTRFS_I(inode)->root->fs_info; - root = btrfs_read_fs_root_no_name(fs_info, &key); - if (IS_ERR(root)) { - if (PTR_ERR(root) == -ENOENT) - return 0; - WARN_ON(1); - btrfs_debug(fs_info, "inum=%llu, offset=%llu, root_id=%llu", - inum, offset, root_id); - return PTR_ERR(root); - } - - key.objectid = inum; - key.type = BTRFS_EXTENT_DATA_KEY; - if (offset > (u64)-1 << 32) - key.offset = 0; - else - key.offset = offset; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (WARN_ON(ret < 0)) - return ret; - ret = 0; - - while (1) { - cond_resched(); - - leaf = path->nodes[0]; - slot = path->slots[0]; - - if (slot >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) { - goto out; - } else if (ret > 0) { - ret = 0; - goto out; - } - continue; - } - - path->slots[0]++; - - btrfs_item_key_to_cpu(leaf, &key, slot); - - if (key.objectid > inum) - goto out; - - if (key.objectid < inum || key.type != BTRFS_EXTENT_DATA_KEY) - continue; - - extent = btrfs_item_ptr(leaf, slot, - struct btrfs_file_extent_item); - - if (btrfs_file_extent_disk_bytenr(leaf, extent) != old->bytenr) - continue; - - /* - * 'offset' refers to the exact key.offset, - * NOT the 'offset' field in btrfs_extent_data_ref, ie. - * (key.offset - extent_offset). - */ - if (key.offset != offset) - continue; - - extent_offset = btrfs_file_extent_offset(leaf, extent); - num_bytes = btrfs_file_extent_num_bytes(leaf, extent); - - if (extent_offset >= old->extent_offset + old->offset + - old->len || extent_offset + num_bytes <= - old->extent_offset + old->offset) - continue; - break; - } - - backref = kmalloc(sizeof(*backref), GFP_NOFS); - if (!backref) { - ret = -ENOENT; - goto out; - } - - backref->root_id = root_id; - backref->inum = inum; - backref->file_pos = offset; - backref->num_bytes = num_bytes; - backref->extent_offset = extent_offset; - backref->generation = btrfs_file_extent_generation(leaf, extent); - backref->old = old; - backref_insert(&new->root, backref); - old->count++; -out: - btrfs_release_path(path); - WARN_ON(ret); - return ret; -} - -static noinline bool record_extent_backrefs(struct btrfs_path *path, - struct new_sa_defrag_extent *new) -{ - struct btrfs_fs_info *fs_info = BTRFS_I(new->inode)->root->fs_info; - struct old_sa_defrag_extent *old, *tmp; - int ret; - - new->path = path; - - list_for_each_entry_safe(old, tmp, &new->head, list) { - ret = iterate_inodes_from_logical(old->bytenr + - old->extent_offset, fs_info, - path, record_one_backref, - old); - if (ret < 0 && ret != -ENOENT) - return false; - - /* no backref to be processed for this extent */ - if (!old->count) { - list_del(&old->list); - kfree(old); - } - } - - if (list_empty(&new->head)) - return false; - - return true; -} - -static int relink_is_mergable(struct extent_buffer *leaf, - struct btrfs_file_extent_item *fi, - struct new_sa_defrag_extent *new) -{ - if (btrfs_file_extent_disk_bytenr(leaf, fi) != new->bytenr) - return 0; - - if (btrfs_file_extent_type(leaf, fi) != BTRFS_FILE_EXTENT_REG) - return 0; - - if (btrfs_file_extent_compression(leaf, fi) != new->compress_type) - return 0; - - if (btrfs_file_extent_encryption(leaf, fi) || - btrfs_file_extent_other_encoding(leaf, fi)) - return 0; - - return 1; -} - -/* - * Note the backref might has changed, and in this case we just return 0. - */ -static noinline int relink_extent_backref(struct btrfs_path *path, - struct sa_defrag_extent_backref *prev, - struct sa_defrag_extent_backref *backref) -{ - struct btrfs_file_extent_item *extent; - struct btrfs_file_extent_item *item; - struct btrfs_ordered_extent *ordered; - struct btrfs_trans_handle *trans; - struct btrfs_fs_info *fs_info; - struct btrfs_root *root; - struct btrfs_key key; - struct extent_buffer *leaf; - struct old_sa_defrag_extent *old = backref->old; - struct new_sa_defrag_extent *new = old->new; - struct inode *src_inode = new->inode; - struct inode *inode; - struct extent_state *cached = NULL; - int ret = 0; - u64 start; - u64 len; - u64 lock_start; - u64 lock_end; - bool merge = false; - int index; - - if (prev && prev->root_id == backref->root_id && - prev->inum == backref->inum && - prev->file_pos + prev->num_bytes == backref->file_pos) - merge = true; - - /* step 1: get root */ - key.objectid = backref->root_id; - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = (u64)-1; - - fs_info = BTRFS_I(src_inode)->root->fs_info; - index = srcu_read_lock(&fs_info->subvol_srcu); - - root = btrfs_read_fs_root_no_name(fs_info, &key); - if (IS_ERR(root)) { - srcu_read_unlock(&fs_info->subvol_srcu, index); - if (PTR_ERR(root) == -ENOENT) - return 0; - return PTR_ERR(root); - } - - if (btrfs_root_readonly(root)) { - srcu_read_unlock(&fs_info->subvol_srcu, index); - return 0; - } - - /* step 2: get inode */ - key.objectid = backref->inum; - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - - inode = btrfs_iget(fs_info->sb, &key, root, NULL); - if (IS_ERR(inode)) { - srcu_read_unlock(&fs_info->subvol_srcu, index); - return 0; - } - - srcu_read_unlock(&fs_info->subvol_srcu, index); - - /* step 3: relink backref */ - lock_start = backref->file_pos; - lock_end = backref->file_pos + backref->num_bytes - 1; - lock_extent_bits(&BTRFS_I(inode)->io_tree, lock_start, lock_end, - &cached); - - ordered = btrfs_lookup_first_ordered_extent(inode, lock_end); - if (ordered) { - btrfs_put_ordered_extent(ordered); - goto out_unlock; - } - - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out_unlock; - } - - key.objectid = backref->inum; - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = backref->file_pos; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) { - goto out_free_path; - } else if (ret > 0) { - ret = 0; - goto out_free_path; - } - - extent = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_file_extent_item); - - if (btrfs_file_extent_generation(path->nodes[0], extent) != - backref->generation) - goto out_free_path; - - btrfs_release_path(path); - - start = backref->file_pos; - if (backref->extent_offset < old->extent_offset + old->offset) - start += old->extent_offset + old->offset - - backref->extent_offset; - - len = min(backref->extent_offset + backref->num_bytes, - old->extent_offset + old->offset + old->len); - len -= max(backref->extent_offset, old->extent_offset + old->offset); - - ret = btrfs_drop_extents(trans, root, inode, start, - start + len, 1); - if (ret) - goto out_free_path; -again: - key.objectid = btrfs_ino(inode); - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = start; - - path->leave_spinning = 1; - if (merge) { - struct btrfs_file_extent_item *fi; - u64 extent_len; - struct btrfs_key found_key; - - ret = btrfs_search_slot(trans, root, &key, path, 0, 1); - if (ret < 0) - goto out_free_path; - - path->slots[0]--; - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - extent_len = btrfs_file_extent_num_bytes(leaf, fi); - - if (extent_len + found_key.offset == start && - relink_is_mergable(leaf, fi, new)) { - btrfs_set_file_extent_num_bytes(leaf, fi, - extent_len + len); - btrfs_mark_buffer_dirty(leaf); - inode_add_bytes(inode, len); - - ret = 1; - goto out_free_path; - } else { - merge = false; - btrfs_release_path(path); - goto again; - } - } - - ret = btrfs_insert_empty_item(trans, root, path, &key, - sizeof(*extent)); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out_free_path; - } - - leaf = path->nodes[0]; - item = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - btrfs_set_file_extent_disk_bytenr(leaf, item, new->bytenr); - btrfs_set_file_extent_disk_num_bytes(leaf, item, new->disk_len); - btrfs_set_file_extent_offset(leaf, item, start - new->file_pos); - btrfs_set_file_extent_num_bytes(leaf, item, len); - btrfs_set_file_extent_ram_bytes(leaf, item, new->len); - btrfs_set_file_extent_generation(leaf, item, trans->transid); - btrfs_set_file_extent_type(leaf, item, BTRFS_FILE_EXTENT_REG); - btrfs_set_file_extent_compression(leaf, item, new->compress_type); - btrfs_set_file_extent_encryption(leaf, item, 0); - btrfs_set_file_extent_other_encoding(leaf, item, 0); - - btrfs_mark_buffer_dirty(leaf); - inode_add_bytes(inode, len); - btrfs_release_path(path); - - ret = btrfs_inc_extent_ref(trans, root, new->bytenr, - new->disk_len, 0, - backref->root_id, backref->inum, - new->file_pos); /* start - extent_offset */ - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out_free_path; - } - - ret = 1; -out_free_path: - btrfs_release_path(path); - path->leave_spinning = 0; - btrfs_end_transaction(trans, root); -out_unlock: - unlock_extent_cached(&BTRFS_I(inode)->io_tree, lock_start, lock_end, - &cached, GFP_NOFS); - iput(inode); - return ret; -} - -static void free_sa_defrag_extent(struct new_sa_defrag_extent *new) -{ - struct old_sa_defrag_extent *old, *tmp; - - if (!new) - return; - - list_for_each_entry_safe(old, tmp, &new->head, list) { - kfree(old); - } - kfree(new); -} - -static void relink_file_extents(struct new_sa_defrag_extent *new) -{ - struct btrfs_path *path; - struct sa_defrag_extent_backref *backref; - struct sa_defrag_extent_backref *prev = NULL; - struct inode *inode; - struct btrfs_root *root; - struct rb_node *node; - int ret; - - inode = new->inode; - root = BTRFS_I(inode)->root; - - path = btrfs_alloc_path(); - if (!path) - return; - - if (!record_extent_backrefs(path, new)) { - btrfs_free_path(path); - goto out; - } - btrfs_release_path(path); - - while (1) { - node = rb_first(&new->root); - if (!node) - break; - rb_erase(node, &new->root); - - backref = rb_entry(node, struct sa_defrag_extent_backref, node); - - ret = relink_extent_backref(path, prev, backref); - WARN_ON(ret < 0); - - kfree(prev); - - if (ret == 1) - prev = backref; - else - prev = NULL; - cond_resched(); - } - kfree(prev); - - btrfs_free_path(path); -out: - free_sa_defrag_extent(new); - - atomic_dec(&root->fs_info->defrag_running); - wake_up(&root->fs_info->transaction_wait); -} - -static struct new_sa_defrag_extent * -record_old_file_extents(struct inode *inode, - struct btrfs_ordered_extent *ordered) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_path *path; - struct btrfs_key key; - struct old_sa_defrag_extent *old; - struct new_sa_defrag_extent *new; - int ret; - - new = kmalloc(sizeof(*new), GFP_NOFS); - if (!new) - return NULL; - - new->inode = inode; - new->file_pos = ordered->file_offset; - new->len = ordered->len; - new->bytenr = ordered->start; - new->disk_len = ordered->disk_len; - new->compress_type = ordered->compress_type; - new->root = RB_ROOT; - INIT_LIST_HEAD(&new->head); - - path = btrfs_alloc_path(); - if (!path) - goto out_kfree; - - key.objectid = btrfs_ino(inode); - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = new->file_pos; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out_free_path; - if (ret > 0 && path->slots[0] > 0) - path->slots[0]--; - - /* find out all the old extents for the file range */ - while (1) { - struct btrfs_file_extent_item *extent; - struct extent_buffer *l; - int slot; - u64 num_bytes; - u64 offset; - u64 end; - u64 disk_bytenr; - u64 extent_offset; - - l = path->nodes[0]; - slot = path->slots[0]; - - if (slot >= btrfs_header_nritems(l)) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) - goto out_free_path; - else if (ret > 0) - break; - continue; - } - - btrfs_item_key_to_cpu(l, &key, slot); - - if (key.objectid != btrfs_ino(inode)) - break; - if (key.type != BTRFS_EXTENT_DATA_KEY) - break; - if (key.offset >= new->file_pos + new->len) - break; - - extent = btrfs_item_ptr(l, slot, struct btrfs_file_extent_item); - - num_bytes = btrfs_file_extent_num_bytes(l, extent); - if (key.offset + num_bytes < new->file_pos) - goto next; - - disk_bytenr = btrfs_file_extent_disk_bytenr(l, extent); - if (!disk_bytenr) - goto next; - - extent_offset = btrfs_file_extent_offset(l, extent); - - old = kmalloc(sizeof(*old), GFP_NOFS); - if (!old) - goto out_free_path; - - offset = max(new->file_pos, key.offset); - end = min(new->file_pos + new->len, key.offset + num_bytes); - - old->bytenr = disk_bytenr; - old->extent_offset = extent_offset; - old->offset = offset - key.offset; - old->len = end - offset; - old->new = new; - old->count = 0; - list_add_tail(&old->list, &new->head); -next: - path->slots[0]++; - cond_resched(); - } - - btrfs_free_path(path); - atomic_inc(&root->fs_info->defrag_running); - - return new; - -out_free_path: - btrfs_free_path(path); -out_kfree: - free_sa_defrag_extent(new); - return NULL; -} - -static void btrfs_release_delalloc_bytes(struct btrfs_root *root, - u64 start, u64 len) -{ - struct btrfs_block_group_cache *cache; - - cache = btrfs_lookup_block_group(root->fs_info, start); - ASSERT(cache); - - spin_lock(&cache->lock); - cache->delalloc_bytes -= len; - spin_unlock(&cache->lock); - - btrfs_put_block_group(cache); -} - -/* as ordered data IO finishes, this gets called so we can finish - * an ordered extent if the range of bytes in the file it covers are - * fully written. - */ -static int btrfs_finish_ordered_io(struct btrfs_ordered_extent *ordered_extent) -{ - struct inode *inode = ordered_extent->inode; - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_trans_handle *trans = NULL; - struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; - struct extent_state *cached_state = NULL; - struct new_sa_defrag_extent *new = NULL; - int compress_type = 0; - int ret = 0; - u64 logical_len = ordered_extent->len; - bool nolock; - bool truncated = false; - - nolock = btrfs_is_free_space_inode(inode); - - if (test_bit(BTRFS_ORDERED_IOERR, &ordered_extent->flags)) { - ret = -EIO; - goto out; - } - - btrfs_free_io_failure_record(inode, ordered_extent->file_offset, - ordered_extent->file_offset + - ordered_extent->len - 1); - - if (test_bit(BTRFS_ORDERED_TRUNCATED, &ordered_extent->flags)) { - truncated = true; - logical_len = ordered_extent->truncated_len; - /* Truncated the entire extent, don't bother adding */ - if (!logical_len) - goto out; - } - - if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) { - BUG_ON(!list_empty(&ordered_extent->list)); /* Logic error */ - - /* - * For mwrite(mmap + memset to write) case, we still reserve - * space for NOCOW range. - * As NOCOW won't cause a new delayed ref, just free the space - */ - btrfs_qgroup_free_data(inode, ordered_extent->file_offset, - ordered_extent->len); - btrfs_ordered_update_i_size(inode, 0, ordered_extent); - if (nolock) - trans = btrfs_join_transaction_nolock(root); - else - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - trans = NULL; - goto out; - } - trans->block_rsv = &root->fs_info->delalloc_block_rsv; - ret = btrfs_update_inode_fallback(trans, root, inode); - if (ret) /* -ENOMEM or corruption */ - btrfs_abort_transaction(trans, ret); - goto out; - } - - lock_extent_bits(io_tree, ordered_extent->file_offset, - ordered_extent->file_offset + ordered_extent->len - 1, - &cached_state); - - ret = test_range_bit(io_tree, ordered_extent->file_offset, - ordered_extent->file_offset + ordered_extent->len - 1, - EXTENT_DEFRAG, 1, cached_state); - if (ret) { - u64 last_snapshot = btrfs_root_last_snapshot(&root->root_item); - if (0 && last_snapshot >= BTRFS_I(inode)->generation) - /* the inode is shared */ - new = record_old_file_extents(inode, ordered_extent); - - clear_extent_bit(io_tree, ordered_extent->file_offset, - ordered_extent->file_offset + ordered_extent->len - 1, - EXTENT_DEFRAG, 0, 0, &cached_state, GFP_NOFS); - } - - if (nolock) - trans = btrfs_join_transaction_nolock(root); - else - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - trans = NULL; - goto out_unlock; - } - - trans->block_rsv = &root->fs_info->delalloc_block_rsv; - - if (test_bit(BTRFS_ORDERED_COMPRESSED, &ordered_extent->flags)) - compress_type = ordered_extent->compress_type; - if (test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) { - BUG_ON(compress_type); - ret = btrfs_mark_extent_written(trans, inode, - ordered_extent->file_offset, - ordered_extent->file_offset + - logical_len); - } else { - BUG_ON(root == root->fs_info->tree_root); - ret = insert_reserved_file_extent(trans, inode, - ordered_extent->file_offset, - ordered_extent->start, - ordered_extent->disk_len, - logical_len, logical_len, - compress_type, 0, 0, - BTRFS_FILE_EXTENT_REG); - if (!ret) - btrfs_release_delalloc_bytes(root, - ordered_extent->start, - ordered_extent->disk_len); - } - unpin_extent_cache(&BTRFS_I(inode)->extent_tree, - ordered_extent->file_offset, ordered_extent->len, - trans->transid); - if (ret < 0) { - btrfs_abort_transaction(trans, ret); - goto out_unlock; - } - - add_pending_csums(trans, inode, ordered_extent->file_offset, - &ordered_extent->list); - - btrfs_ordered_update_i_size(inode, 0, ordered_extent); - ret = btrfs_update_inode_fallback(trans, root, inode); - if (ret) { /* -ENOMEM or corruption */ - btrfs_abort_transaction(trans, ret); - goto out_unlock; - } - ret = 0; -out_unlock: - unlock_extent_cached(io_tree, ordered_extent->file_offset, - ordered_extent->file_offset + - ordered_extent->len - 1, &cached_state, GFP_NOFS); -out: - if (root != root->fs_info->tree_root) - btrfs_delalloc_release_metadata(inode, ordered_extent->len); - if (trans) - btrfs_end_transaction(trans, root); - - if (ret || truncated) { - u64 start, end; - - if (truncated) - start = ordered_extent->file_offset + logical_len; - else - start = ordered_extent->file_offset; - end = ordered_extent->file_offset + ordered_extent->len - 1; - clear_extent_uptodate(io_tree, start, end, NULL, GFP_NOFS); - - /* Drop the cache for the part of the extent we didn't write. */ - btrfs_drop_extent_cache(inode, start, end, 0); - - /* - * If the ordered extent had an IOERR or something else went - * wrong we need to return the space for this ordered extent - * back to the allocator. We only free the extent in the - * truncated case if we didn't write out the extent at all. - */ - if ((ret || !logical_len) && - !test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags) && - !test_bit(BTRFS_ORDERED_PREALLOC, &ordered_extent->flags)) - btrfs_free_reserved_extent(root, ordered_extent->start, - ordered_extent->disk_len, 1); - } - - - /* - * This needs to be done to make sure anybody waiting knows we are done - * updating everything for this ordered extent. - */ - btrfs_remove_ordered_extent(inode, ordered_extent); - - /* for snapshot-aware defrag */ - if (new) { - if (ret) { - free_sa_defrag_extent(new); - atomic_dec(&root->fs_info->defrag_running); - } else { - relink_file_extents(new); - } - } - - /* once for us */ - btrfs_put_ordered_extent(ordered_extent); - /* once for the tree */ - btrfs_put_ordered_extent(ordered_extent); - - return ret; -} - -static void finish_ordered_fn(struct btrfs_work *work) -{ - struct btrfs_ordered_extent *ordered_extent; - ordered_extent = container_of(work, struct btrfs_ordered_extent, work); - btrfs_finish_ordered_io(ordered_extent); -} - -static int btrfs_writepage_end_io_hook(struct page *page, u64 start, u64 end, - struct extent_state *state, int uptodate) -{ - struct inode *inode = page->mapping->host; - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_ordered_extent *ordered_extent = NULL; - struct btrfs_workqueue *wq; - btrfs_work_func_t func; - - trace_btrfs_writepage_end_io_hook(page, start, end, uptodate); - - ClearPagePrivate2(page); - if (!btrfs_dec_test_ordered_pending(inode, &ordered_extent, start, - end - start + 1, uptodate)) - return 0; - - if (btrfs_is_free_space_inode(inode)) { - wq = root->fs_info->endio_freespace_worker; - func = btrfs_freespace_write_helper; - } else { - wq = root->fs_info->endio_write_workers; - func = btrfs_endio_write_helper; - } - - btrfs_init_work(&ordered_extent->work, func, finish_ordered_fn, NULL, - NULL); - btrfs_queue_work(wq, &ordered_extent->work); - - return 0; -} - -static int __readpage_endio_check(struct inode *inode, - struct btrfs_io_bio *io_bio, - int icsum, struct page *page, - int pgoff, u64 start, size_t len) -{ - char *kaddr; - u32 csum_expected; - u32 csum = ~(u32)0; - - csum_expected = *(((u32 *)io_bio->csum) + icsum); - - kaddr = kmap_atomic(page); - csum = btrfs_csum_data(kaddr + pgoff, csum, len); - btrfs_csum_final(csum, (char *)&csum); - if (csum != csum_expected) - goto zeroit; - - kunmap_atomic(kaddr); - return 0; -zeroit: - btrfs_warn_rl(BTRFS_I(inode)->root->fs_info, - "csum failed ino %llu off %llu csum %u expected csum %u", - btrfs_ino(inode), start, csum, csum_expected); - memset(kaddr + pgoff, 1, len); - flush_dcache_page(page); - kunmap_atomic(kaddr); - if (csum_expected == 0) - return 0; - return -EIO; -} - -/* - * when reads are done, we need to check csums to verify the data is correct - * if there's a match, we allow the bio to finish. If not, the code in - * extent_io.c will try to find good copies for us. - */ -static int btrfs_readpage_end_io_hook(struct btrfs_io_bio *io_bio, - u64 phy_offset, struct page *page, - u64 start, u64 end, int mirror) -{ - size_t offset = start - page_offset(page); - struct inode *inode = page->mapping->host; - struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; - struct btrfs_root *root = BTRFS_I(inode)->root; - - if (PageChecked(page)) { - ClearPageChecked(page); - return 0; - } - - if (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM) - return 0; - - if (root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID && - test_range_bit(io_tree, start, end, EXTENT_NODATASUM, 1, NULL)) { - clear_extent_bits(io_tree, start, end, EXTENT_NODATASUM); - return 0; - } - - phy_offset >>= inode->i_sb->s_blocksize_bits; - return __readpage_endio_check(inode, io_bio, phy_offset, page, offset, - start, (size_t)(end - start + 1)); -} - -void btrfs_add_delayed_iput(struct inode *inode) -{ - struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; - struct btrfs_inode *binode = BTRFS_I(inode); - - if (atomic_add_unless(&inode->i_count, -1, 1)) - return; - - spin_lock(&fs_info->delayed_iput_lock); - if (binode->delayed_iput_count == 0) { - ASSERT(list_empty(&binode->delayed_iput)); - list_add_tail(&binode->delayed_iput, &fs_info->delayed_iputs); - } else { - binode->delayed_iput_count++; - } - spin_unlock(&fs_info->delayed_iput_lock); -} - -void btrfs_run_delayed_iputs(struct btrfs_root *root) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - - spin_lock(&fs_info->delayed_iput_lock); - while (!list_empty(&fs_info->delayed_iputs)) { - struct btrfs_inode *inode; - - inode = list_first_entry(&fs_info->delayed_iputs, - struct btrfs_inode, delayed_iput); - if (inode->delayed_iput_count) { - inode->delayed_iput_count--; - list_move_tail(&inode->delayed_iput, - &fs_info->delayed_iputs); - } else { - list_del_init(&inode->delayed_iput); - } - spin_unlock(&fs_info->delayed_iput_lock); - iput(&inode->vfs_inode); - spin_lock(&fs_info->delayed_iput_lock); - } - spin_unlock(&fs_info->delayed_iput_lock); -} - -/* - * This is called in transaction commit time. If there are no orphan - * files in the subvolume, it removes orphan item and frees block_rsv - * structure. - */ -void btrfs_orphan_commit_root(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_block_rsv *block_rsv; - int ret; - - if (atomic_read(&root->orphan_inodes) || - root->orphan_cleanup_state != ORPHAN_CLEANUP_DONE) - return; - - spin_lock(&root->orphan_lock); - if (atomic_read(&root->orphan_inodes)) { - spin_unlock(&root->orphan_lock); - return; - } - - if (root->orphan_cleanup_state != ORPHAN_CLEANUP_DONE) { - spin_unlock(&root->orphan_lock); - return; - } - - block_rsv = root->orphan_block_rsv; - root->orphan_block_rsv = NULL; - spin_unlock(&root->orphan_lock); - - if (test_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, &root->state) && - btrfs_root_refs(&root->root_item) > 0) { - ret = btrfs_del_orphan_item(trans, root->fs_info->tree_root, - root->root_key.objectid); - if (ret) - btrfs_abort_transaction(trans, ret); - else - clear_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, - &root->state); - } - - if (block_rsv) { - WARN_ON(block_rsv->size > 0); - btrfs_free_block_rsv(root, block_rsv); - } -} - -/* - * This creates an orphan entry for the given inode in case something goes - * wrong in the middle of an unlink/truncate. - * - * NOTE: caller of this function should reserve 5 units of metadata for - * this function. - */ -int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_block_rsv *block_rsv = NULL; - int reserve = 0; - int insert = 0; - int ret; - - if (!root->orphan_block_rsv) { - block_rsv = btrfs_alloc_block_rsv(root, BTRFS_BLOCK_RSV_TEMP); - if (!block_rsv) - return -ENOMEM; - } - - spin_lock(&root->orphan_lock); - if (!root->orphan_block_rsv) { - root->orphan_block_rsv = block_rsv; - } else if (block_rsv) { - btrfs_free_block_rsv(root, block_rsv); - block_rsv = NULL; - } - - if (!test_and_set_bit(BTRFS_INODE_HAS_ORPHAN_ITEM, - &BTRFS_I(inode)->runtime_flags)) { -#if 0 - /* - * For proper ENOSPC handling, we should do orphan - * cleanup when mounting. But this introduces backward - * compatibility issue. - */ - if (!xchg(&root->orphan_item_inserted, 1)) - insert = 2; - else - insert = 1; -#endif - insert = 1; - atomic_inc(&root->orphan_inodes); - } - - if (!test_and_set_bit(BTRFS_INODE_ORPHAN_META_RESERVED, - &BTRFS_I(inode)->runtime_flags)) - reserve = 1; - spin_unlock(&root->orphan_lock); - - /* grab metadata reservation from transaction handle */ - if (reserve) { - ret = btrfs_orphan_reserve_metadata(trans, inode); - ASSERT(!ret); - if (ret) { - atomic_dec(&root->orphan_inodes); - clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED, - &BTRFS_I(inode)->runtime_flags); - if (insert) - clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM, - &BTRFS_I(inode)->runtime_flags); - return ret; - } - } - - /* insert an orphan item to track this unlinked/truncated file */ - if (insert >= 1) { - ret = btrfs_insert_orphan_item(trans, root, btrfs_ino(inode)); - if (ret) { - atomic_dec(&root->orphan_inodes); - if (reserve) { - clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED, - &BTRFS_I(inode)->runtime_flags); - btrfs_orphan_release_metadata(inode); - } - if (ret != -EEXIST) { - clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM, - &BTRFS_I(inode)->runtime_flags); - btrfs_abort_transaction(trans, ret); - return ret; - } - } - ret = 0; - } - - /* insert an orphan item to track subvolume contains orphan files */ - if (insert >= 2) { - ret = btrfs_insert_orphan_item(trans, root->fs_info->tree_root, - root->root_key.objectid); - if (ret && ret != -EEXIST) { - btrfs_abort_transaction(trans, ret); - return ret; - } - } - return 0; -} - -/* - * We have done the truncate/delete so we can go ahead and remove the orphan - * item for this particular inode. - */ -static int btrfs_orphan_del(struct btrfs_trans_handle *trans, - struct inode *inode) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - int delete_item = 0; - int release_rsv = 0; - int ret = 0; - - spin_lock(&root->orphan_lock); - if (test_and_clear_bit(BTRFS_INODE_HAS_ORPHAN_ITEM, - &BTRFS_I(inode)->runtime_flags)) - delete_item = 1; - - if (test_and_clear_bit(BTRFS_INODE_ORPHAN_META_RESERVED, - &BTRFS_I(inode)->runtime_flags)) - release_rsv = 1; - spin_unlock(&root->orphan_lock); - - if (delete_item) { - atomic_dec(&root->orphan_inodes); - if (trans) - ret = btrfs_del_orphan_item(trans, root, - btrfs_ino(inode)); - } - - if (release_rsv) - btrfs_orphan_release_metadata(inode); - - return ret; -} - -/* - * this cleans up any orphans that may be left on the list from the last use - * of this root. - */ -int btrfs_orphan_cleanup(struct btrfs_root *root) -{ - struct btrfs_path *path; - struct extent_buffer *leaf; - struct btrfs_key key, found_key; - struct btrfs_trans_handle *trans; - struct inode *inode; - u64 last_objectid = 0; - int ret = 0, nr_unlink = 0, nr_truncate = 0; - - if (cmpxchg(&root->orphan_cleanup_state, 0, ORPHAN_CLEANUP_STARTED)) - return 0; - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - path->reada = READA_BACK; - - key.objectid = BTRFS_ORPHAN_OBJECTID; - key.type = BTRFS_ORPHAN_ITEM_KEY; - key.offset = (u64)-1; - - while (1) { - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out; - - /* - * if ret == 0 means we found what we were searching for, which - * is weird, but possible, so only screw with path if we didn't - * find the key and see if we have stuff that matches - */ - if (ret > 0) { - ret = 0; - if (path->slots[0] == 0) - break; - path->slots[0]--; - } - - /* pull out the item */ - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - - /* make sure the item matches what we want */ - if (found_key.objectid != BTRFS_ORPHAN_OBJECTID) - break; - if (found_key.type != BTRFS_ORPHAN_ITEM_KEY) - break; - - /* release the path since we're done with it */ - btrfs_release_path(path); - - /* - * this is where we are basically btrfs_lookup, without the - * crossing root thing. we store the inode number in the - * offset of the orphan item. - */ - - if (found_key.offset == last_objectid) { - btrfs_err(root->fs_info, - "Error removing orphan entry, stopping orphan cleanup"); - ret = -EINVAL; - goto out; - } - - last_objectid = found_key.offset; - - found_key.objectid = found_key.offset; - found_key.type = BTRFS_INODE_ITEM_KEY; - found_key.offset = 0; - inode = btrfs_iget(root->fs_info->sb, &found_key, root, NULL); - ret = PTR_ERR_OR_ZERO(inode); - if (ret && ret != -ENOENT) - goto out; - - if (ret == -ENOENT && root == root->fs_info->tree_root) { - struct btrfs_root *dead_root; - struct btrfs_fs_info *fs_info = root->fs_info; - int is_dead_root = 0; - - /* - * this is an orphan in the tree root. Currently these - * could come from 2 sources: - * a) a snapshot deletion in progress - * b) a free space cache inode - * We need to distinguish those two, as the snapshot - * orphan must not get deleted. - * find_dead_roots already ran before us, so if this - * is a snapshot deletion, we should find the root - * in the dead_roots list - */ - spin_lock(&fs_info->trans_lock); - list_for_each_entry(dead_root, &fs_info->dead_roots, - root_list) { - if (dead_root->root_key.objectid == - found_key.objectid) { - is_dead_root = 1; - break; - } - } - spin_unlock(&fs_info->trans_lock); - if (is_dead_root) { - /* prevent this orphan from being found again */ - key.offset = found_key.objectid - 1; - continue; - } - } - /* - * Inode is already gone but the orphan item is still there, - * kill the orphan item. - */ - if (ret == -ENOENT) { - trans = btrfs_start_transaction(root, 1); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out; - } - btrfs_debug(root->fs_info, "auto deleting %Lu", - found_key.objectid); - ret = btrfs_del_orphan_item(trans, root, - found_key.objectid); - btrfs_end_transaction(trans, root); - if (ret) - goto out; - continue; - } - - /* - * add this inode to the orphan list so btrfs_orphan_del does - * the proper thing when we hit it - */ - set_bit(BTRFS_INODE_HAS_ORPHAN_ITEM, - &BTRFS_I(inode)->runtime_flags); - atomic_inc(&root->orphan_inodes); - - /* if we have links, this was a truncate, lets do that */ - if (inode->i_nlink) { - if (WARN_ON(!S_ISREG(inode->i_mode))) { - iput(inode); - continue; - } - nr_truncate++; - - /* 1 for the orphan item deletion. */ - trans = btrfs_start_transaction(root, 1); - if (IS_ERR(trans)) { - iput(inode); - ret = PTR_ERR(trans); - goto out; - } - ret = btrfs_orphan_add(trans, inode); - btrfs_end_transaction(trans, root); - if (ret) { - iput(inode); - goto out; - } - - ret = btrfs_truncate(inode); - if (ret) - btrfs_orphan_del(NULL, inode); - } else { - nr_unlink++; - } - - /* this will do delete_inode and everything for us */ - iput(inode); - if (ret) - goto out; - } - /* release the path since we're done with it */ - btrfs_release_path(path); - - root->orphan_cleanup_state = ORPHAN_CLEANUP_DONE; - - if (root->orphan_block_rsv) - btrfs_block_rsv_release(root, root->orphan_block_rsv, - (u64)-1); - - if (root->orphan_block_rsv || - test_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, &root->state)) { - trans = btrfs_join_transaction(root); - if (!IS_ERR(trans)) - btrfs_end_transaction(trans, root); - } - - if (nr_unlink) - btrfs_debug(root->fs_info, "unlinked %d orphans", nr_unlink); - if (nr_truncate) - btrfs_debug(root->fs_info, "truncated %d orphans", nr_truncate); - -out: - if (ret) - btrfs_err(root->fs_info, - "could not do orphan cleanup %d", ret); - btrfs_free_path(path); - return ret; -} - -/* - * very simple check to peek ahead in the leaf looking for xattrs. If we - * don't find any xattrs, we know there can't be any acls. - * - * slot is the slot the inode is in, objectid is the objectid of the inode - */ -static noinline int acls_after_inode_item(struct extent_buffer *leaf, - int slot, u64 objectid, - int *first_xattr_slot) -{ - u32 nritems = btrfs_header_nritems(leaf); - struct btrfs_key found_key; - static u64 xattr_access = 0; - static u64 xattr_default = 0; - int scanned = 0; - - if (!xattr_access) { - xattr_access = btrfs_name_hash(XATTR_NAME_POSIX_ACL_ACCESS, - strlen(XATTR_NAME_POSIX_ACL_ACCESS)); - xattr_default = btrfs_name_hash(XATTR_NAME_POSIX_ACL_DEFAULT, - strlen(XATTR_NAME_POSIX_ACL_DEFAULT)); - } - - slot++; - *first_xattr_slot = -1; - while (slot < nritems) { - btrfs_item_key_to_cpu(leaf, &found_key, slot); - - /* we found a different objectid, there must not be acls */ - if (found_key.objectid != objectid) - return 0; - - /* we found an xattr, assume we've got an acl */ - if (found_key.type == BTRFS_XATTR_ITEM_KEY) { - if (*first_xattr_slot == -1) - *first_xattr_slot = slot; - if (found_key.offset == xattr_access || - found_key.offset == xattr_default) - return 1; - } - - /* - * we found a key greater than an xattr key, there can't - * be any acls later on - */ - if (found_key.type > BTRFS_XATTR_ITEM_KEY) - return 0; - - slot++; - scanned++; - - /* - * it goes inode, inode backrefs, xattrs, extents, - * so if there are a ton of hard links to an inode there can - * be a lot of backrefs. Don't waste time searching too hard, - * this is just an optimization - */ - if (scanned >= 8) - break; - } - /* we hit the end of the leaf before we found an xattr or - * something larger than an xattr. We have to assume the inode - * has acls - */ - if (*first_xattr_slot == -1) - *first_xattr_slot = slot; - return 1; -} - -/* - * read an inode from the btree into the in-memory inode - */ -static int btrfs_read_locked_inode(struct inode *inode) -{ - struct btrfs_path *path; - struct extent_buffer *leaf; - struct btrfs_inode_item *inode_item; - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_key location; - unsigned long ptr; - int maybe_acls; - u32 rdev; - int ret; - bool filled = false; - int first_xattr_slot; - - ret = btrfs_fill_inode(inode, &rdev); - if (!ret) - filled = true; - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto make_bad; - } - - memcpy(&location, &BTRFS_I(inode)->location, sizeof(location)); - - ret = btrfs_lookup_inode(NULL, root, path, &location, 0); - if (ret) { - if (ret > 0) - ret = -ENOENT; - goto make_bad; - } - - leaf = path->nodes[0]; - - if (filled) - goto cache_index; - - inode_item = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_inode_item); - inode->i_mode = btrfs_inode_mode(leaf, inode_item); - set_nlink(inode, btrfs_inode_nlink(leaf, inode_item)); - i_uid_write(inode, btrfs_inode_uid(leaf, inode_item)); - i_gid_write(inode, btrfs_inode_gid(leaf, inode_item)); - btrfs_i_size_write(inode, btrfs_inode_size(leaf, inode_item)); - - inode->i_atime.tv_sec = btrfs_timespec_sec(leaf, &inode_item->atime); - inode->i_atime.tv_nsec = btrfs_timespec_nsec(leaf, &inode_item->atime); - - inode->i_mtime.tv_sec = btrfs_timespec_sec(leaf, &inode_item->mtime); - inode->i_mtime.tv_nsec = btrfs_timespec_nsec(leaf, &inode_item->mtime); - - inode->i_ctime.tv_sec = btrfs_timespec_sec(leaf, &inode_item->ctime); - inode->i_ctime.tv_nsec = btrfs_timespec_nsec(leaf, &inode_item->ctime); - - BTRFS_I(inode)->i_otime.tv_sec = - btrfs_timespec_sec(leaf, &inode_item->otime); - BTRFS_I(inode)->i_otime.tv_nsec = - btrfs_timespec_nsec(leaf, &inode_item->otime); - - inode_set_bytes(inode, btrfs_inode_nbytes(leaf, inode_item)); - BTRFS_I(inode)->generation = btrfs_inode_generation(leaf, inode_item); - BTRFS_I(inode)->last_trans = btrfs_inode_transid(leaf, inode_item); - - inode->i_version = btrfs_inode_sequence(leaf, inode_item); - inode->i_generation = BTRFS_I(inode)->generation; - inode->i_rdev = 0; - rdev = btrfs_inode_rdev(leaf, inode_item); - - BTRFS_I(inode)->index_cnt = (u64)-1; - BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item); - -cache_index: - /* - * If we were modified in the current generation and evicted from memory - * and then re-read we need to do a full sync since we don't have any - * idea about which extents were modified before we were evicted from - * cache. - * - * This is required for both inode re-read from disk and delayed inode - * in delayed_nodes_tree. - */ - if (BTRFS_I(inode)->last_trans == root->fs_info->generation) - set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, - &BTRFS_I(inode)->runtime_flags); - - /* - * We don't persist the id of the transaction where an unlink operation - * against the inode was last made. So here we assume the inode might - * have been evicted, and therefore the exact value of last_unlink_trans - * lost, and set it to last_trans to avoid metadata inconsistencies - * between the inode and its parent if the inode is fsync'ed and the log - * replayed. For example, in the scenario: - * - * touch mydir/foo - * ln mydir/foo mydir/bar - * sync - * unlink mydir/bar - * echo 2 > /proc/sys/vm/drop_caches # evicts inode - * xfs_io -c fsync mydir/foo - * - * mount fs, triggers fsync log replay - * - * We must make sure that when we fsync our inode foo we also log its - * parent inode, otherwise after log replay the parent still has the - * dentry with the "bar" name but our inode foo has a link count of 1 - * and doesn't have an inode ref with the name "bar" anymore. - * - * Setting last_unlink_trans to last_trans is a pessimistic approach, - * but it guarantees correctness at the expense of occasional full - * transaction commits on fsync if our inode is a directory, or if our - * inode is not a directory, logging its parent unnecessarily. - */ - BTRFS_I(inode)->last_unlink_trans = BTRFS_I(inode)->last_trans; - - path->slots[0]++; - if (inode->i_nlink != 1 || - path->slots[0] >= btrfs_header_nritems(leaf)) - goto cache_acl; - - btrfs_item_key_to_cpu(leaf, &location, path->slots[0]); - if (location.objectid != btrfs_ino(inode)) - goto cache_acl; - - ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); - if (location.type == BTRFS_INODE_REF_KEY) { - struct btrfs_inode_ref *ref; - - ref = (struct btrfs_inode_ref *)ptr; - BTRFS_I(inode)->dir_index = btrfs_inode_ref_index(leaf, ref); - } else if (location.type == BTRFS_INODE_EXTREF_KEY) { - struct btrfs_inode_extref *extref; - - extref = (struct btrfs_inode_extref *)ptr; - BTRFS_I(inode)->dir_index = btrfs_inode_extref_index(leaf, - extref); - } -cache_acl: - /* - * try to precache a NULL acl entry for files that don't have - * any xattrs or acls - */ - maybe_acls = acls_after_inode_item(leaf, path->slots[0], - btrfs_ino(inode), &first_xattr_slot); - if (first_xattr_slot != -1) { - path->slots[0] = first_xattr_slot; - ret = btrfs_load_inode_props(inode, path); - if (ret) - btrfs_err(root->fs_info, - "error loading props for ino %llu (root %llu): %d", - btrfs_ino(inode), - root->root_key.objectid, ret); - } - btrfs_free_path(path); - - if (!maybe_acls) - cache_no_acl(inode); - - switch (inode->i_mode & S_IFMT) { - case S_IFREG: - inode->i_mapping->a_ops = &btrfs_aops; - BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; - inode->i_fop = &btrfs_file_operations; - inode->i_op = &btrfs_file_inode_operations; - break; - case S_IFDIR: - inode->i_fop = &btrfs_dir_file_operations; - if (root == root->fs_info->tree_root) - inode->i_op = &btrfs_dir_ro_inode_operations; - else - inode->i_op = &btrfs_dir_inode_operations; - break; - case S_IFLNK: - inode->i_op = &btrfs_symlink_inode_operations; - inode_nohighmem(inode); - inode->i_mapping->a_ops = &btrfs_symlink_aops; - break; - default: - inode->i_op = &btrfs_special_inode_operations; - init_special_inode(inode, inode->i_mode, rdev); - break; - } - - btrfs_update_iflags(inode); - return 0; - -make_bad: - btrfs_free_path(path); - make_bad_inode(inode); - return ret; -} - -/* - * given a leaf and an inode, copy the inode fields into the leaf - */ -static void fill_inode_item(struct btrfs_trans_handle *trans, - struct extent_buffer *leaf, - struct btrfs_inode_item *item, - struct inode *inode) -{ - struct btrfs_map_token token; - - btrfs_init_map_token(&token); - - btrfs_set_token_inode_uid(leaf, item, i_uid_read(inode), &token); - btrfs_set_token_inode_gid(leaf, item, i_gid_read(inode), &token); - btrfs_set_token_inode_size(leaf, item, BTRFS_I(inode)->disk_i_size, - &token); - btrfs_set_token_inode_mode(leaf, item, inode->i_mode, &token); - btrfs_set_token_inode_nlink(leaf, item, inode->i_nlink, &token); - - btrfs_set_token_timespec_sec(leaf, &item->atime, - inode->i_atime.tv_sec, &token); - btrfs_set_token_timespec_nsec(leaf, &item->atime, - inode->i_atime.tv_nsec, &token); - - btrfs_set_token_timespec_sec(leaf, &item->mtime, - inode->i_mtime.tv_sec, &token); - btrfs_set_token_timespec_nsec(leaf, &item->mtime, - inode->i_mtime.tv_nsec, &token); - - btrfs_set_token_timespec_sec(leaf, &item->ctime, - inode->i_ctime.tv_sec, &token); - btrfs_set_token_timespec_nsec(leaf, &item->ctime, - inode->i_ctime.tv_nsec, &token); - - btrfs_set_token_timespec_sec(leaf, &item->otime, - BTRFS_I(inode)->i_otime.tv_sec, &token); - btrfs_set_token_timespec_nsec(leaf, &item->otime, - BTRFS_I(inode)->i_otime.tv_nsec, &token); - - btrfs_set_token_inode_nbytes(leaf, item, inode_get_bytes(inode), - &token); - btrfs_set_token_inode_generation(leaf, item, BTRFS_I(inode)->generation, - &token); - btrfs_set_token_inode_sequence(leaf, item, inode->i_version, &token); - btrfs_set_token_inode_transid(leaf, item, trans->transid, &token); - btrfs_set_token_inode_rdev(leaf, item, inode->i_rdev, &token); - btrfs_set_token_inode_flags(leaf, item, BTRFS_I(inode)->flags, &token); - btrfs_set_token_inode_block_group(leaf, item, 0, &token); -} - -/* - * copy everything in the in-memory inode into the btree. - */ -static noinline int btrfs_update_inode_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct inode *inode) -{ - struct btrfs_inode_item *inode_item; - struct btrfs_path *path; - struct extent_buffer *leaf; - int ret; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - path->leave_spinning = 1; - ret = btrfs_lookup_inode(trans, root, path, &BTRFS_I(inode)->location, - 1); - if (ret) { - if (ret > 0) - ret = -ENOENT; - goto failed; - } - - leaf = path->nodes[0]; - inode_item = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_inode_item); - - fill_inode_item(trans, leaf, inode_item, inode); - btrfs_mark_buffer_dirty(leaf); - btrfs_set_inode_last_trans(trans, inode); - ret = 0; -failed: - btrfs_free_path(path); - return ret; -} - -/* - * copy everything in the in-memory inode into the btree. - */ -noinline int btrfs_update_inode(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct inode *inode) -{ - int ret; - - /* - * If the inode is a free space inode, we can deadlock during commit - * if we put it into the delayed code. - * - * The data relocation inode should also be directly updated - * without delay - */ - if (!btrfs_is_free_space_inode(inode) - && root->root_key.objectid != BTRFS_DATA_RELOC_TREE_OBJECTID - && !test_bit(BTRFS_FS_LOG_RECOVERING, &root->fs_info->flags)) { - btrfs_update_root_times(trans, root); - - ret = btrfs_delayed_update_inode(trans, root, inode); - if (!ret) - btrfs_set_inode_last_trans(trans, inode); - return ret; - } - - return btrfs_update_inode_item(trans, root, inode); -} - -noinline int btrfs_update_inode_fallback(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *inode) -{ - int ret; - - ret = btrfs_update_inode(trans, root, inode); - if (ret == -ENOSPC) - return btrfs_update_inode_item(trans, root, inode); - return ret; -} - -/* - * unlink helper that gets used here in inode.c and in the tree logging - * recovery code. It remove a link in a directory with a given name, and - * also drops the back refs in the inode to the directory - */ -static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *dir, struct inode *inode, - const char *name, int name_len) -{ - struct btrfs_path *path; - int ret = 0; - struct extent_buffer *leaf; - struct btrfs_dir_item *di; - struct btrfs_key key; - u64 index; - u64 ino = btrfs_ino(inode); - u64 dir_ino = btrfs_ino(dir); - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - path->leave_spinning = 1; - di = btrfs_lookup_dir_item(trans, root, path, dir_ino, - name, name_len, -1); - if (IS_ERR(di)) { - ret = PTR_ERR(di); - goto err; - } - if (!di) { - ret = -ENOENT; - goto err; - } - leaf = path->nodes[0]; - btrfs_dir_item_key_to_cpu(leaf, di, &key); - ret = btrfs_delete_one_dir_name(trans, root, path, di); - if (ret) - goto err; - btrfs_release_path(path); - - /* - * If we don't have dir index, we have to get it by looking up - * the inode ref, since we get the inode ref, remove it directly, - * it is unnecessary to do delayed deletion. - * - * But if we have dir index, needn't search inode ref to get it. - * Since the inode ref is close to the inode item, it is better - * that we delay to delete it, and just do this deletion when - * we update the inode item. - */ - if (BTRFS_I(inode)->dir_index) { - ret = btrfs_delayed_delete_inode_ref(inode); - if (!ret) { - index = BTRFS_I(inode)->dir_index; - goto skip_backref; - } - } - - ret = btrfs_del_inode_ref(trans, root, name, name_len, ino, - dir_ino, &index); - if (ret) { - btrfs_info(root->fs_info, - "failed to delete reference to %.*s, inode %llu parent %llu", - name_len, name, ino, dir_ino); - btrfs_abort_transaction(trans, ret); - goto err; - } -skip_backref: - ret = btrfs_delete_delayed_dir_index(trans, root, dir, index); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto err; - } - - ret = btrfs_del_inode_ref_in_log(trans, root, name, name_len, - inode, dir_ino); - if (ret != 0 && ret != -ENOENT) { - btrfs_abort_transaction(trans, ret); - goto err; - } - - ret = btrfs_del_dir_entries_in_log(trans, root, name, name_len, - dir, index); - if (ret == -ENOENT) - ret = 0; - else if (ret) - btrfs_abort_transaction(trans, ret); -err: - btrfs_free_path(path); - if (ret) - goto out; - - btrfs_i_size_write(dir, dir->i_size - name_len * 2); - inode_inc_iversion(inode); - inode_inc_iversion(dir); - inode->i_ctime = dir->i_mtime = - dir->i_ctime = current_time(inode); - ret = btrfs_update_inode(trans, root, dir); -out: - return ret; -} - -int btrfs_unlink_inode(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *dir, struct inode *inode, - const char *name, int name_len) -{ - int ret; - ret = __btrfs_unlink_inode(trans, root, dir, inode, name, name_len); - if (!ret) { - drop_nlink(inode); - ret = btrfs_update_inode(trans, root, inode); - } - return ret; -} - -/* - * helper to start transaction for unlink and rmdir. - * - * unlink and rmdir are special in btrfs, they do not always free space, so - * if we cannot make our reservations the normal way try and see if there is - * plenty of slack room in the global reserve to migrate, otherwise we cannot - * allow the unlink to occur. - */ -static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir) -{ - struct btrfs_root *root = BTRFS_I(dir)->root; - - /* - * 1 for the possible orphan item - * 1 for the dir item - * 1 for the dir index - * 1 for the inode ref - * 1 for the inode - */ - return btrfs_start_transaction_fallback_global_rsv(root, 5, 5); -} - -static int btrfs_unlink(struct inode *dir, struct dentry *dentry) -{ - struct btrfs_root *root = BTRFS_I(dir)->root; - struct btrfs_trans_handle *trans; - struct inode *inode = d_inode(dentry); - int ret; - - trans = __unlink_start_trans(dir); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - btrfs_record_unlink_dir(trans, dir, d_inode(dentry), 0); - - ret = btrfs_unlink_inode(trans, root, dir, d_inode(dentry), - dentry->d_name.name, dentry->d_name.len); - if (ret) - goto out; - - if (inode->i_nlink == 0) { - ret = btrfs_orphan_add(trans, inode); - if (ret) - goto out; - } - -out: - btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(root); - return ret; -} - -int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *dir, u64 objectid, - const char *name, int name_len) -{ - struct btrfs_path *path; - struct extent_buffer *leaf; - struct btrfs_dir_item *di; - struct btrfs_key key; - u64 index; - int ret; - u64 dir_ino = btrfs_ino(dir); - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - di = btrfs_lookup_dir_item(trans, root, path, dir_ino, - name, name_len, -1); - if (IS_ERR_OR_NULL(di)) { - if (!di) - ret = -ENOENT; - else - ret = PTR_ERR(di); - goto out; - } - - leaf = path->nodes[0]; - btrfs_dir_item_key_to_cpu(leaf, di, &key); - WARN_ON(key.type != BTRFS_ROOT_ITEM_KEY || key.objectid != objectid); - ret = btrfs_delete_one_dir_name(trans, root, path, di); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out; - } - btrfs_release_path(path); - - ret = btrfs_del_root_ref(trans, root->fs_info->tree_root, - objectid, root->root_key.objectid, - dir_ino, &index, name, name_len); - if (ret < 0) { - if (ret != -ENOENT) { - btrfs_abort_transaction(trans, ret); - goto out; - } - di = btrfs_search_dir_index_item(root, path, dir_ino, - name, name_len); - if (IS_ERR_OR_NULL(di)) { - if (!di) - ret = -ENOENT; - else - ret = PTR_ERR(di); - btrfs_abort_transaction(trans, ret); - goto out; - } - - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - btrfs_release_path(path); - index = key.offset; - } - btrfs_release_path(path); - - ret = btrfs_delete_delayed_dir_index(trans, root, dir, index); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out; - } - - btrfs_i_size_write(dir, dir->i_size - name_len * 2); - inode_inc_iversion(dir); - dir->i_mtime = dir->i_ctime = current_time(dir); - ret = btrfs_update_inode_fallback(trans, root, dir); - if (ret) - btrfs_abort_transaction(trans, ret); -out: - btrfs_free_path(path); - return ret; -} - -static int btrfs_rmdir(struct inode *dir, struct dentry *dentry) -{ - struct inode *inode = d_inode(dentry); - int err = 0; - struct btrfs_root *root = BTRFS_I(dir)->root; - struct btrfs_trans_handle *trans; - u64 last_unlink_trans; - - if (inode->i_size > BTRFS_EMPTY_DIR_SIZE) - return -ENOTEMPTY; - if (btrfs_ino(inode) == BTRFS_FIRST_FREE_OBJECTID) - return -EPERM; - - trans = __unlink_start_trans(dir); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - if (unlikely(btrfs_ino(inode) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) { - err = btrfs_unlink_subvol(trans, root, dir, - BTRFS_I(inode)->location.objectid, - dentry->d_name.name, - dentry->d_name.len); - goto out; - } - - err = btrfs_orphan_add(trans, inode); - if (err) - goto out; - - last_unlink_trans = BTRFS_I(inode)->last_unlink_trans; - - /* now the directory is empty */ - err = btrfs_unlink_inode(trans, root, dir, d_inode(dentry), - dentry->d_name.name, dentry->d_name.len); - if (!err) { - btrfs_i_size_write(inode, 0); - /* - * Propagate the last_unlink_trans value of the deleted dir to - * its parent directory. This is to prevent an unrecoverable - * log tree in the case we do something like this: - * 1) create dir foo - * 2) create snapshot under dir foo - * 3) delete the snapshot - * 4) rmdir foo - * 5) mkdir foo - * 6) fsync foo or some file inside foo - */ - if (last_unlink_trans >= trans->transid) - BTRFS_I(dir)->last_unlink_trans = last_unlink_trans; - } -out: - btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(root); - - return err; -} - -static int truncate_space_check(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 bytes_deleted) -{ - int ret; - - /* - * This is only used to apply pressure to the enospc system, we don't - * intend to use this reservation at all. - */ - bytes_deleted = btrfs_csum_bytes_to_leaves(root, bytes_deleted); - bytes_deleted *= root->nodesize; - ret = btrfs_block_rsv_add(root, &root->fs_info->trans_block_rsv, - bytes_deleted, BTRFS_RESERVE_NO_FLUSH); - if (!ret) { - trace_btrfs_space_reservation(root->fs_info, "transaction", - trans->transid, - bytes_deleted, 1); - trans->bytes_reserved += bytes_deleted; - } - return ret; - -} - -static int truncate_inline_extent(struct inode *inode, - struct btrfs_path *path, - struct btrfs_key *found_key, - const u64 item_end, - const u64 new_size) -{ - struct extent_buffer *leaf = path->nodes[0]; - int slot = path->slots[0]; - struct btrfs_file_extent_item *fi; - u32 size = (u32)(new_size - found_key->offset); - struct btrfs_root *root = BTRFS_I(inode)->root; - - fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); - - if (btrfs_file_extent_compression(leaf, fi) != BTRFS_COMPRESS_NONE) { - loff_t offset = new_size; - loff_t page_end = ALIGN(offset, PAGE_SIZE); - - /* - * Zero out the remaining of the last page of our inline extent, - * instead of directly truncating our inline extent here - that - * would be much more complex (decompressing all the data, then - * compressing the truncated data, which might be bigger than - * the size of the inline extent, resize the extent, etc). - * We release the path because to get the page we might need to - * read the extent item from disk (data not in the page cache). - */ - btrfs_release_path(path); - return btrfs_truncate_block(inode, offset, page_end - offset, - 0); - } - - btrfs_set_file_extent_ram_bytes(leaf, fi, size); - size = btrfs_file_extent_calc_inline_size(size); - btrfs_truncate_item(root, path, size, 1); - - if (test_bit(BTRFS_ROOT_REF_COWS, &root->state)) - inode_sub_bytes(inode, item_end + 1 - new_size); - - return 0; -} - -/* - * this can truncate away extent items, csum items and directory items. - * It starts at a high offset and removes keys until it can't find - * any higher than new_size - * - * csum items that cross the new i_size are truncated to the new size - * as well. - * - * min_type is the minimum key type to truncate down to. If set to 0, this - * will kill all the items on this inode, including the INODE_ITEM_KEY. - */ -int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *inode, - u64 new_size, u32 min_type) -{ - struct btrfs_path *path; - struct extent_buffer *leaf; - struct btrfs_file_extent_item *fi; - struct btrfs_key key; - struct btrfs_key found_key; - u64 extent_start = 0; - u64 extent_num_bytes = 0; - u64 extent_offset = 0; - u64 item_end = 0; - u64 last_size = new_size; - u32 found_type = (u8)-1; - int found_extent; - int del_item; - int pending_del_nr = 0; - int pending_del_slot = 0; - int extent_type = -1; - int ret; - int err = 0; - u64 ino = btrfs_ino(inode); - u64 bytes_deleted = 0; - bool be_nice = 0; - bool should_throttle = 0; - bool should_end = 0; - - BUG_ON(new_size > 0 && min_type != BTRFS_EXTENT_DATA_KEY); - - /* - * for non-free space inodes and ref cows, we want to back off from - * time to time - */ - if (!btrfs_is_free_space_inode(inode) && - test_bit(BTRFS_ROOT_REF_COWS, &root->state)) - be_nice = 1; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->reada = READA_BACK; - - /* - * We want to drop from the next block forward in case this new size is - * not block aligned since we will be keeping the last block of the - * extent just the way it is. - */ - if (test_bit(BTRFS_ROOT_REF_COWS, &root->state) || - root == root->fs_info->tree_root) - btrfs_drop_extent_cache(inode, ALIGN(new_size, - root->sectorsize), (u64)-1, 0); - - /* - * This function is also used to drop the items in the log tree before - * we relog the inode, so if root != BTRFS_I(inode)->root, it means - * it is used to drop the loged items. So we shouldn't kill the delayed - * items. - */ - if (min_type == 0 && root == BTRFS_I(inode)->root) - btrfs_kill_delayed_inode_items(inode); - - key.objectid = ino; - key.offset = (u64)-1; - key.type = (u8)-1; - -search_again: - /* - * with a 16K leaf size and 128MB extents, you can actually queue - * up a huge file in a single leaf. Most of the time that - * bytes_deleted is > 0, it will be huge by the time we get here - */ - if (be_nice && bytes_deleted > SZ_32M) { - if (btrfs_should_end_transaction(trans, root)) { - err = -EAGAIN; - goto error; - } - } - - - path->leave_spinning = 1; - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret < 0) { - err = ret; - goto out; - } - - if (ret > 0) { - /* there are no items in the tree for us to truncate, we're - * done - */ - if (path->slots[0] == 0) - goto out; - path->slots[0]--; - } - - while (1) { - fi = NULL; - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - found_type = found_key.type; - - if (found_key.objectid != ino) - break; - - if (found_type < min_type) - break; - - item_end = found_key.offset; - if (found_type == BTRFS_EXTENT_DATA_KEY) { - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - extent_type = btrfs_file_extent_type(leaf, fi); - if (extent_type != BTRFS_FILE_EXTENT_INLINE) { - item_end += - btrfs_file_extent_num_bytes(leaf, fi); - } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { - item_end += btrfs_file_extent_inline_len(leaf, - path->slots[0], fi); - } - item_end--; - } - if (found_type > min_type) { - del_item = 1; - } else { - if (item_end < new_size) - break; - if (found_key.offset >= new_size) - del_item = 1; - else - del_item = 0; - } - found_extent = 0; - /* FIXME, shrink the extent if the ref count is only 1 */ - if (found_type != BTRFS_EXTENT_DATA_KEY) - goto delete; - - if (del_item) - last_size = found_key.offset; - else - last_size = new_size; - - if (extent_type != BTRFS_FILE_EXTENT_INLINE) { - u64 num_dec; - extent_start = btrfs_file_extent_disk_bytenr(leaf, fi); - if (!del_item) { - u64 orig_num_bytes = - btrfs_file_extent_num_bytes(leaf, fi); - extent_num_bytes = ALIGN(new_size - - found_key.offset, - root->sectorsize); - btrfs_set_file_extent_num_bytes(leaf, fi, - extent_num_bytes); - num_dec = (orig_num_bytes - - extent_num_bytes); - if (test_bit(BTRFS_ROOT_REF_COWS, - &root->state) && - extent_start != 0) - inode_sub_bytes(inode, num_dec); - btrfs_mark_buffer_dirty(leaf); - } else { - extent_num_bytes = - btrfs_file_extent_disk_num_bytes(leaf, - fi); - extent_offset = found_key.offset - - btrfs_file_extent_offset(leaf, fi); - - /* FIXME blocksize != 4096 */ - num_dec = btrfs_file_extent_num_bytes(leaf, fi); - if (extent_start != 0) { - found_extent = 1; - if (test_bit(BTRFS_ROOT_REF_COWS, - &root->state)) - inode_sub_bytes(inode, num_dec); - } - } - } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) { - /* - * we can't truncate inline items that have had - * special encodings - */ - if (!del_item && - btrfs_file_extent_encryption(leaf, fi) == 0 && - btrfs_file_extent_other_encoding(leaf, fi) == 0) { - - /* - * Need to release path in order to truncate a - * compressed extent. So delete any accumulated - * extent items so far. - */ - if (btrfs_file_extent_compression(leaf, fi) != - BTRFS_COMPRESS_NONE && pending_del_nr) { - err = btrfs_del_items(trans, root, path, - pending_del_slot, - pending_del_nr); - if (err) { - btrfs_abort_transaction(trans, - err); - goto error; - } - pending_del_nr = 0; - } - - err = truncate_inline_extent(inode, path, - &found_key, - item_end, - new_size); - if (err) { - btrfs_abort_transaction(trans, err); - goto error; - } - } else if (test_bit(BTRFS_ROOT_REF_COWS, - &root->state)) { - inode_sub_bytes(inode, item_end + 1 - new_size); - } - } -delete: - if (del_item) { - if (!pending_del_nr) { - /* no pending yet, add ourselves */ - pending_del_slot = path->slots[0]; - pending_del_nr = 1; - } else if (pending_del_nr && - path->slots[0] + 1 == pending_del_slot) { - /* hop on the pending chunk */ - pending_del_nr++; - pending_del_slot = path->slots[0]; - } else { - BUG(); - } - } else { - break; - } - should_throttle = 0; - - if (found_extent && - (test_bit(BTRFS_ROOT_REF_COWS, &root->state) || - root == root->fs_info->tree_root)) { - btrfs_set_path_blocking(path); - bytes_deleted += extent_num_bytes; - ret = btrfs_free_extent(trans, root, extent_start, - extent_num_bytes, 0, - btrfs_header_owner(leaf), - ino, extent_offset); - BUG_ON(ret); - if (btrfs_should_throttle_delayed_refs(trans, root)) - btrfs_async_run_delayed_refs(root, - trans->delayed_ref_updates * 2, - trans->transid, 0); - if (be_nice) { - if (truncate_space_check(trans, root, - extent_num_bytes)) { - should_end = 1; - } - if (btrfs_should_throttle_delayed_refs(trans, - root)) { - should_throttle = 1; - } - } - } - - if (found_type == BTRFS_INODE_ITEM_KEY) - break; - - if (path->slots[0] == 0 || - path->slots[0] != pending_del_slot || - should_throttle || should_end) { - if (pending_del_nr) { - ret = btrfs_del_items(trans, root, path, - pending_del_slot, - pending_del_nr); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto error; - } - pending_del_nr = 0; - } - btrfs_release_path(path); - if (should_throttle) { - unsigned long updates = trans->delayed_ref_updates; - if (updates) { - trans->delayed_ref_updates = 0; - ret = btrfs_run_delayed_refs(trans, root, updates * 2); - if (ret && !err) - err = ret; - } - } - /* - * if we failed to refill our space rsv, bail out - * and let the transaction restart - */ - if (should_end) { - err = -EAGAIN; - goto error; - } - goto search_again; - } else { - path->slots[0]--; - } - } -out: - if (pending_del_nr) { - ret = btrfs_del_items(trans, root, path, pending_del_slot, - pending_del_nr); - if (ret) - btrfs_abort_transaction(trans, ret); - } -error: - if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) - btrfs_ordered_update_i_size(inode, last_size, NULL); - - btrfs_free_path(path); - - if (be_nice && bytes_deleted > SZ_32M) { - unsigned long updates = trans->delayed_ref_updates; - if (updates) { - trans->delayed_ref_updates = 0; - ret = btrfs_run_delayed_refs(trans, root, updates * 2); - if (ret && !err) - err = ret; - } - } - return err; -} - -/* - * btrfs_truncate_block - read, zero a chunk and write a block - * @inode - inode that we're zeroing - * @from - the offset to start zeroing - * @len - the length to zero, 0 to zero the entire range respective to the - * offset - * @front - zero up to the offset instead of from the offset on - * - * This will find the block for the "from" offset and cow the block and zero the - * part we want to zero. This is used with truncate and hole punching. - */ -int btrfs_truncate_block(struct inode *inode, loff_t from, loff_t len, - int front) -{ - struct address_space *mapping = inode->i_mapping; - struct btrfs_root *root = BTRFS_I(inode)->root; - struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; - struct btrfs_ordered_extent *ordered; - struct extent_state *cached_state = NULL; - char *kaddr; - u32 blocksize = root->sectorsize; - pgoff_t index = from >> PAGE_SHIFT; - unsigned offset = from & (blocksize - 1); - struct page *page; - gfp_t mask = btrfs_alloc_write_mask(mapping); - int ret = 0; - u64 block_start; - u64 block_end; - - if ((offset & (blocksize - 1)) == 0 && - (!len || ((len & (blocksize - 1)) == 0))) - goto out; - - ret = btrfs_delalloc_reserve_space(inode, - round_down(from, blocksize), blocksize); - if (ret) - goto out; - -again: - page = find_or_create_page(mapping, index, mask); - if (!page) { - btrfs_delalloc_release_space(inode, - round_down(from, blocksize), - blocksize); - ret = -ENOMEM; - goto out; - } - - block_start = round_down(from, blocksize); - block_end = block_start + blocksize - 1; - - if (!PageUptodate(page)) { - ret = btrfs_readpage(NULL, page); - lock_page(page); - if (page->mapping != mapping) { - unlock_page(page); - put_page(page); - goto again; - } - if (!PageUptodate(page)) { - ret = -EIO; - goto out_unlock; - } - } - wait_on_page_writeback(page); - - lock_extent_bits(io_tree, block_start, block_end, &cached_state); - set_page_extent_mapped(page); - - ordered = btrfs_lookup_ordered_extent(inode, block_start); - if (ordered) { - unlock_extent_cached(io_tree, block_start, block_end, - &cached_state, GFP_NOFS); - unlock_page(page); - put_page(page); - btrfs_start_ordered_extent(inode, ordered, 1); - btrfs_put_ordered_extent(ordered); - goto again; - } - - clear_extent_bit(&BTRFS_I(inode)->io_tree, block_start, block_end, - EXTENT_DIRTY | EXTENT_DELALLOC | - EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, - 0, 0, &cached_state, GFP_NOFS); - - ret = btrfs_set_extent_delalloc(inode, block_start, block_end, - &cached_state, 0); - if (ret) { - unlock_extent_cached(io_tree, block_start, block_end, - &cached_state, GFP_NOFS); - goto out_unlock; - } - - if (offset != blocksize) { - if (!len) - len = blocksize - offset; - kaddr = kmap(page); - if (front) - memset(kaddr + (block_start - page_offset(page)), - 0, offset); - else - memset(kaddr + (block_start - page_offset(page)) + offset, - 0, len); - flush_dcache_page(page); - kunmap(page); - } - ClearPageChecked(page); - set_page_dirty(page); - unlock_extent_cached(io_tree, block_start, block_end, &cached_state, - GFP_NOFS); - -out_unlock: - if (ret) - btrfs_delalloc_release_space(inode, block_start, - blocksize); - unlock_page(page); - put_page(page); -out: - return ret; -} - -static int maybe_insert_hole(struct btrfs_root *root, struct inode *inode, - u64 offset, u64 len) -{ - struct btrfs_trans_handle *trans; - int ret; - - /* - * Still need to make sure the inode looks like it's been updated so - * that any holes get logged if we fsync. - */ - if (btrfs_fs_incompat(root->fs_info, NO_HOLES)) { - BTRFS_I(inode)->last_trans = root->fs_info->generation; - BTRFS_I(inode)->last_sub_trans = root->log_transid; - BTRFS_I(inode)->last_log_commit = root->last_log_commit; - return 0; - } - - /* - * 1 - for the one we're dropping - * 1 - for the one we're adding - * 1 - for updating the inode. - */ - trans = btrfs_start_transaction(root, 3); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - ret = btrfs_drop_extents(trans, root, inode, offset, offset + len, 1); - if (ret) { - btrfs_abort_transaction(trans, ret); - btrfs_end_transaction(trans, root); - return ret; - } - - ret = btrfs_insert_file_extent(trans, root, btrfs_ino(inode), offset, - 0, 0, len, 0, len, 0, 0, 0); - if (ret) - btrfs_abort_transaction(trans, ret); - else - btrfs_update_inode(trans, root, inode); - btrfs_end_transaction(trans, root); - return ret; -} - -/* - * This function puts in dummy file extents for the area we're creating a hole - * for. So if we are truncating this file to a larger size we need to insert - * these file extents so that btrfs_get_extent will return a EXTENT_MAP_HOLE for - * the range between oldsize and size - */ -int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; - struct extent_map *em = NULL; - struct extent_state *cached_state = NULL; - struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; - u64 hole_start = ALIGN(oldsize, root->sectorsize); - u64 block_end = ALIGN(size, root->sectorsize); - u64 last_byte; - u64 cur_offset; - u64 hole_size; - int err = 0; - - /* - * If our size started in the middle of a block we need to zero out the - * rest of the block before we expand the i_size, otherwise we could - * expose stale data. - */ - err = btrfs_truncate_block(inode, oldsize, 0, 0); - if (err) - return err; - - if (size <= hole_start) - return 0; - - while (1) { - struct btrfs_ordered_extent *ordered; - - lock_extent_bits(io_tree, hole_start, block_end - 1, - &cached_state); - ordered = btrfs_lookup_ordered_range(inode, hole_start, - block_end - hole_start); - if (!ordered) - break; - unlock_extent_cached(io_tree, hole_start, block_end - 1, - &cached_state, GFP_NOFS); - btrfs_start_ordered_extent(inode, ordered, 1); - btrfs_put_ordered_extent(ordered); - } - - cur_offset = hole_start; - while (1) { - em = btrfs_get_extent(inode, NULL, 0, cur_offset, - block_end - cur_offset, 0); - if (IS_ERR(em)) { - err = PTR_ERR(em); - em = NULL; - break; - } - last_byte = min(extent_map_end(em), block_end); - last_byte = ALIGN(last_byte , root->sectorsize); - if (!test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) { - struct extent_map *hole_em; - hole_size = last_byte - cur_offset; - - err = maybe_insert_hole(root, inode, cur_offset, - hole_size); - if (err) - break; - btrfs_drop_extent_cache(inode, cur_offset, - cur_offset + hole_size - 1, 0); - hole_em = alloc_extent_map(); - if (!hole_em) { - set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, - &BTRFS_I(inode)->runtime_flags); - goto next; - } - hole_em->start = cur_offset; - hole_em->len = hole_size; - hole_em->orig_start = cur_offset; - - hole_em->block_start = EXTENT_MAP_HOLE; - hole_em->block_len = 0; - hole_em->orig_block_len = 0; - hole_em->ram_bytes = hole_size; - hole_em->bdev = root->fs_info->fs_devices->latest_bdev; - hole_em->compress_type = BTRFS_COMPRESS_NONE; - hole_em->generation = root->fs_info->generation; - - while (1) { - write_lock(&em_tree->lock); - err = add_extent_mapping(em_tree, hole_em, 1); - write_unlock(&em_tree->lock); - if (err != -EEXIST) - break; - btrfs_drop_extent_cache(inode, cur_offset, - cur_offset + - hole_size - 1, 0); - } - free_extent_map(hole_em); - } -next: - free_extent_map(em); - em = NULL; - cur_offset = last_byte; - if (cur_offset >= block_end) - break; - } - free_extent_map(em); - unlock_extent_cached(io_tree, hole_start, block_end - 1, &cached_state, - GFP_NOFS); - return err; -} - -static int btrfs_setsize(struct inode *inode, struct iattr *attr) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_trans_handle *trans; - loff_t oldsize = i_size_read(inode); - loff_t newsize = attr->ia_size; - int mask = attr->ia_valid; - int ret; - - /* - * The regular truncate() case without ATTR_CTIME and ATTR_MTIME is a - * special case where we need to update the times despite not having - * these flags set. For all other operations the VFS set these flags - * explicitly if it wants a timestamp update. - */ - if (newsize != oldsize) { - inode_inc_iversion(inode); - if (!(mask & (ATTR_CTIME | ATTR_MTIME))) - inode->i_ctime = inode->i_mtime = - current_time(inode); - } - - if (newsize > oldsize) { - /* - * Don't do an expanding truncate while snapshoting is ongoing. - * This is to ensure the snapshot captures a fully consistent - * state of this file - if the snapshot captures this expanding - * truncation, it must capture all writes that happened before - * this truncation. - */ - btrfs_wait_for_snapshot_creation(root); - ret = btrfs_cont_expand(inode, oldsize, newsize); - if (ret) { - btrfs_end_write_no_snapshoting(root); - return ret; - } - - trans = btrfs_start_transaction(root, 1); - if (IS_ERR(trans)) { - btrfs_end_write_no_snapshoting(root); - return PTR_ERR(trans); - } - - i_size_write(inode, newsize); - btrfs_ordered_update_i_size(inode, i_size_read(inode), NULL); - pagecache_isize_extended(inode, oldsize, newsize); - ret = btrfs_update_inode(trans, root, inode); - btrfs_end_write_no_snapshoting(root); - btrfs_end_transaction(trans, root); - } else { - - /* - * We're truncating a file that used to have good data down to - * zero. Make sure it gets into the ordered flush list so that - * any new writes get down to disk quickly. - */ - if (newsize == 0) - set_bit(BTRFS_INODE_ORDERED_DATA_CLOSE, - &BTRFS_I(inode)->runtime_flags); - - /* - * 1 for the orphan item we're going to add - * 1 for the orphan item deletion. - */ - trans = btrfs_start_transaction(root, 2); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - /* - * We need to do this in case we fail at _any_ point during the - * actual truncate. Once we do the truncate_setsize we could - * invalidate pages which forces any outstanding ordered io to - * be instantly completed which will give us extents that need - * to be truncated. If we fail to get an orphan inode down we - * could have left over extents that were never meant to live, - * so we need to guarantee from this point on that everything - * will be consistent. - */ - ret = btrfs_orphan_add(trans, inode); - btrfs_end_transaction(trans, root); - if (ret) - return ret; - - /* we don't support swapfiles, so vmtruncate shouldn't fail */ - truncate_setsize(inode, newsize); - - /* Disable nonlocked read DIO to avoid the end less truncate */ - btrfs_inode_block_unlocked_dio(inode); - inode_dio_wait(inode); - btrfs_inode_resume_unlocked_dio(inode); - - ret = btrfs_truncate(inode); - if (ret && inode->i_nlink) { - int err; - - /* - * failed to truncate, disk_i_size is only adjusted down - * as we remove extents, so it should represent the true - * size of the inode, so reset the in memory size and - * delete our orphan entry. - */ - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) { - btrfs_orphan_del(NULL, inode); - return ret; - } - i_size_write(inode, BTRFS_I(inode)->disk_i_size); - err = btrfs_orphan_del(trans, inode); - if (err) - btrfs_abort_transaction(trans, err); - btrfs_end_transaction(trans, root); - } - } - - return ret; -} - -static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) -{ - struct inode *inode = d_inode(dentry); - struct btrfs_root *root = BTRFS_I(inode)->root; - int err; - - if (btrfs_root_readonly(root)) - return -EROFS; - - err = setattr_prepare(dentry, attr); - if (err) - return err; - - if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) { - err = btrfs_setsize(inode, attr); - if (err) - return err; - } - - if (attr->ia_valid) { - setattr_copy(inode, attr); - inode_inc_iversion(inode); - err = btrfs_dirty_inode(inode); - - if (!err && attr->ia_valid & ATTR_MODE) - err = posix_acl_chmod(inode, inode->i_mode); - } - - return err; -} - -/* - * While truncating the inode pages during eviction, we get the VFS calling - * btrfs_invalidatepage() against each page of the inode. This is slow because - * the calls to btrfs_invalidatepage() result in a huge amount of calls to - * lock_extent_bits() and clear_extent_bit(), which keep merging and splitting - * extent_state structures over and over, wasting lots of time. - * - * Therefore if the inode is being evicted, let btrfs_invalidatepage() skip all - * those expensive operations on a per page basis and do only the ordered io - * finishing, while we release here the extent_map and extent_state structures, - * without the excessive merging and splitting. - */ -static void evict_inode_truncate_pages(struct inode *inode) -{ - struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; - struct extent_map_tree *map_tree = &BTRFS_I(inode)->extent_tree; - struct rb_node *node; - - ASSERT(inode->i_state & I_FREEING); - truncate_inode_pages_final(&inode->i_data); - - write_lock(&map_tree->lock); - while (!RB_EMPTY_ROOT(&map_tree->map)) { - struct extent_map *em; - - node = rb_first(&map_tree->map); - em = rb_entry(node, struct extent_map, rb_node); - clear_bit(EXTENT_FLAG_PINNED, &em->flags); - clear_bit(EXTENT_FLAG_LOGGING, &em->flags); - remove_extent_mapping(map_tree, em); - free_extent_map(em); - if (need_resched()) { - write_unlock(&map_tree->lock); - cond_resched(); - write_lock(&map_tree->lock); - } - } - write_unlock(&map_tree->lock); - - /* - * Keep looping until we have no more ranges in the io tree. - * We can have ongoing bios started by readpages (called from readahead) - * that have their endio callback (extent_io.c:end_bio_extent_readpage) - * still in progress (unlocked the pages in the bio but did not yet - * unlocked the ranges in the io tree). Therefore this means some - * ranges can still be locked and eviction started because before - * submitting those bios, which are executed by a separate task (work - * queue kthread), inode references (inode->i_count) were not taken - * (which would be dropped in the end io callback of each bio). - * Therefore here we effectively end up waiting for those bios and - * anyone else holding locked ranges without having bumped the inode's - * reference count - if we don't do it, when they access the inode's - * io_tree to unlock a range it may be too late, leading to an - * use-after-free issue. - */ - spin_lock(&io_tree->lock); - while (!RB_EMPTY_ROOT(&io_tree->state)) { - struct extent_state *state; - struct extent_state *cached_state = NULL; - u64 start; - u64 end; - - node = rb_first(&io_tree->state); - state = rb_entry(node, struct extent_state, rb_node); - start = state->start; - end = state->end; - spin_unlock(&io_tree->lock); - - lock_extent_bits(io_tree, start, end, &cached_state); - - /* - * If still has DELALLOC flag, the extent didn't reach disk, - * and its reserved space won't be freed by delayed_ref. - * So we need to free its reserved space here. - * (Refer to comment in btrfs_invalidatepage, case 2) - * - * Note, end is the bytenr of last byte, so we need + 1 here. - */ - if (state->state & EXTENT_DELALLOC) - btrfs_qgroup_free_data(inode, start, end - start + 1); - - clear_extent_bit(io_tree, start, end, - EXTENT_LOCKED | EXTENT_DIRTY | - EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | - EXTENT_DEFRAG, 1, 1, - &cached_state, GFP_NOFS); - - cond_resched(); - spin_lock(&io_tree->lock); - } - spin_unlock(&io_tree->lock); -} - -void btrfs_evict_inode(struct inode *inode) -{ - struct btrfs_trans_handle *trans; - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_block_rsv *rsv, *global_rsv; - int steal_from_global = 0; - u64 min_size; - int ret; - - trace_btrfs_inode_evict(inode); - - if (!root) { - kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode)); - return; - } - - min_size = btrfs_calc_trunc_metadata_size(root, 1); - - evict_inode_truncate_pages(inode); - - if (inode->i_nlink && - ((btrfs_root_refs(&root->root_item) != 0 && - root->root_key.objectid != BTRFS_ROOT_TREE_OBJECTID) || - btrfs_is_free_space_inode(inode))) - goto no_delete; - - if (is_bad_inode(inode)) { - btrfs_orphan_del(NULL, inode); - goto no_delete; - } - /* do we really want it for ->i_nlink > 0 and zero btrfs_root_refs? */ - if (!special_file(inode->i_mode)) - btrfs_wait_ordered_range(inode, 0, (u64)-1); - - btrfs_free_io_failure_record(inode, 0, (u64)-1); - - if (test_bit(BTRFS_FS_LOG_RECOVERING, &root->fs_info->flags)) { - BUG_ON(test_bit(BTRFS_INODE_HAS_ORPHAN_ITEM, - &BTRFS_I(inode)->runtime_flags)); - goto no_delete; - } - - if (inode->i_nlink > 0) { - BUG_ON(btrfs_root_refs(&root->root_item) != 0 && - root->root_key.objectid != BTRFS_ROOT_TREE_OBJECTID); - goto no_delete; - } - - ret = btrfs_commit_inode_delayed_inode(inode); - if (ret) { - btrfs_orphan_del(NULL, inode); - goto no_delete; - } - - rsv = btrfs_alloc_block_rsv(root, BTRFS_BLOCK_RSV_TEMP); - if (!rsv) { - btrfs_orphan_del(NULL, inode); - goto no_delete; - } - rsv->size = min_size; - rsv->failfast = 1; - global_rsv = &root->fs_info->global_block_rsv; - - btrfs_i_size_write(inode, 0); - - /* - * This is a bit simpler than btrfs_truncate since we've already - * reserved our space for our orphan item in the unlink, so we just - * need to reserve some slack space in case we add bytes and update - * inode item when doing the truncate. - */ - while (1) { - ret = btrfs_block_rsv_refill(root, rsv, min_size, - BTRFS_RESERVE_FLUSH_LIMIT); - - /* - * Try and steal from the global reserve since we will - * likely not use this space anyway, we want to try as - * hard as possible to get this to work. - */ - if (ret) - steal_from_global++; - else - steal_from_global = 0; - ret = 0; - - /* - * steal_from_global == 0: we reserved stuff, hooray! - * steal_from_global == 1: we didn't reserve stuff, boo! - * steal_from_global == 2: we've committed, still not a lot of - * room but maybe we'll have room in the global reserve this - * time. - * steal_from_global == 3: abandon all hope! - */ - if (steal_from_global > 2) { - btrfs_warn(root->fs_info, - "Could not get space for a delete, will truncate on mount %d", - ret); - btrfs_orphan_del(NULL, inode); - btrfs_free_block_rsv(root, rsv); - goto no_delete; - } - - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) { - btrfs_orphan_del(NULL, inode); - btrfs_free_block_rsv(root, rsv); - goto no_delete; - } - - /* - * We can't just steal from the global reserve, we need to make - * sure there is room to do it, if not we need to commit and try - * again. - */ - if (steal_from_global) { - if (!btrfs_check_space_for_delayed_refs(trans, root)) - ret = btrfs_block_rsv_migrate(global_rsv, rsv, - min_size, 0); - else - ret = -ENOSPC; - } - - /* - * Couldn't steal from the global reserve, we have too much - * pending stuff built up, commit the transaction and try it - * again. - */ - if (ret) { - ret = btrfs_commit_transaction(trans, root); - if (ret) { - btrfs_orphan_del(NULL, inode); - btrfs_free_block_rsv(root, rsv); - goto no_delete; - } - continue; - } else { - steal_from_global = 0; - } - - trans->block_rsv = rsv; - - ret = btrfs_truncate_inode_items(trans, root, inode, 0, 0); - if (ret != -ENOSPC && ret != -EAGAIN) - break; - - trans->block_rsv = &root->fs_info->trans_block_rsv; - btrfs_end_transaction(trans, root); - trans = NULL; - btrfs_btree_balance_dirty(root); - } - - btrfs_free_block_rsv(root, rsv); - - /* - * Errors here aren't a big deal, it just means we leave orphan items - * in the tree. They will be cleaned up on the next mount. - */ - if (ret == 0) { - trans->block_rsv = root->orphan_block_rsv; - btrfs_orphan_del(trans, inode); - } else { - btrfs_orphan_del(NULL, inode); - } - - trans->block_rsv = &root->fs_info->trans_block_rsv; - if (!(root == root->fs_info->tree_root || - root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID)) - btrfs_return_ino(root, btrfs_ino(inode)); - - btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(root); -no_delete: - btrfs_remove_delayed_node(inode); - clear_inode(inode); -} - -/* - * this returns the key found in the dir entry in the location pointer. - * If no dir entries were found, location->objectid is 0. - */ -static int btrfs_inode_by_name(struct inode *dir, struct dentry *dentry, - struct btrfs_key *location) -{ - const char *name = dentry->d_name.name; - int namelen = dentry->d_name.len; - struct btrfs_dir_item *di; - struct btrfs_path *path; - struct btrfs_root *root = BTRFS_I(dir)->root; - int ret = 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - di = btrfs_lookup_dir_item(NULL, root, path, btrfs_ino(dir), name, - namelen, 0); - if (IS_ERR(di)) - ret = PTR_ERR(di); - - if (IS_ERR_OR_NULL(di)) - goto out_err; - - btrfs_dir_item_key_to_cpu(path->nodes[0], di, location); -out: - btrfs_free_path(path); - return ret; -out_err: - location->objectid = 0; - goto out; -} - -/* - * when we hit a tree root in a directory, the btrfs part of the inode - * needs to be changed to reflect the root directory of the tree root. This - * is kind of like crossing a mount point. - */ -static int fixup_tree_root_location(struct btrfs_root *root, - struct inode *dir, - struct dentry *dentry, - struct btrfs_key *location, - struct btrfs_root **sub_root) -{ - struct btrfs_path *path; - struct btrfs_root *new_root; - struct btrfs_root_ref *ref; - struct extent_buffer *leaf; - struct btrfs_key key; - int ret; - int err = 0; - - path = btrfs_alloc_path(); - if (!path) { - err = -ENOMEM; - goto out; - } - - err = -ENOENT; - key.objectid = BTRFS_I(dir)->root->root_key.objectid; - key.type = BTRFS_ROOT_REF_KEY; - key.offset = location->objectid; - - ret = btrfs_search_slot(NULL, root->fs_info->tree_root, &key, path, - 0, 0); - if (ret) { - if (ret < 0) - err = ret; - goto out; - } - - leaf = path->nodes[0]; - ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref); - if (btrfs_root_ref_dirid(leaf, ref) != btrfs_ino(dir) || - btrfs_root_ref_name_len(leaf, ref) != dentry->d_name.len) - goto out; - - ret = memcmp_extent_buffer(leaf, dentry->d_name.name, - (unsigned long)(ref + 1), - dentry->d_name.len); - if (ret) - goto out; - - btrfs_release_path(path); - - new_root = btrfs_read_fs_root_no_name(root->fs_info, location); - if (IS_ERR(new_root)) { - err = PTR_ERR(new_root); - goto out; - } - - *sub_root = new_root; - location->objectid = btrfs_root_dirid(&new_root->root_item); - location->type = BTRFS_INODE_ITEM_KEY; - location->offset = 0; - err = 0; -out: - btrfs_free_path(path); - return err; -} - -static void inode_tree_add(struct inode *inode) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_inode *entry; - struct rb_node **p; - struct rb_node *parent; - struct rb_node *new = &BTRFS_I(inode)->rb_node; - u64 ino = btrfs_ino(inode); - - if (inode_unhashed(inode)) - return; - parent = NULL; - spin_lock(&root->inode_lock); - p = &root->inode_tree.rb_node; - while (*p) { - parent = *p; - entry = rb_entry(parent, struct btrfs_inode, rb_node); - - if (ino < btrfs_ino(&entry->vfs_inode)) - p = &parent->rb_left; - else if (ino > btrfs_ino(&entry->vfs_inode)) - p = &parent->rb_right; - else { - WARN_ON(!(entry->vfs_inode.i_state & - (I_WILL_FREE | I_FREEING))); - rb_replace_node(parent, new, &root->inode_tree); - RB_CLEAR_NODE(parent); - spin_unlock(&root->inode_lock); - return; - } - } - rb_link_node(new, parent, p); - rb_insert_color(new, &root->inode_tree); - spin_unlock(&root->inode_lock); -} - -static void inode_tree_del(struct inode *inode) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - int empty = 0; - - spin_lock(&root->inode_lock); - if (!RB_EMPTY_NODE(&BTRFS_I(inode)->rb_node)) { - rb_erase(&BTRFS_I(inode)->rb_node, &root->inode_tree); - RB_CLEAR_NODE(&BTRFS_I(inode)->rb_node); - empty = RB_EMPTY_ROOT(&root->inode_tree); - } - spin_unlock(&root->inode_lock); - - if (empty && btrfs_root_refs(&root->root_item) == 0) { - synchronize_srcu(&root->fs_info->subvol_srcu); - spin_lock(&root->inode_lock); - empty = RB_EMPTY_ROOT(&root->inode_tree); - spin_unlock(&root->inode_lock); - if (empty) - btrfs_add_dead_root(root); - } -} - -void btrfs_invalidate_inodes(struct btrfs_root *root) -{ - struct rb_node *node; - struct rb_node *prev; - struct btrfs_inode *entry; - struct inode *inode; - u64 objectid = 0; - - if (!test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state)) - WARN_ON(btrfs_root_refs(&root->root_item) != 0); - - spin_lock(&root->inode_lock); -again: - node = root->inode_tree.rb_node; - prev = NULL; - while (node) { - prev = node; - entry = rb_entry(node, struct btrfs_inode, rb_node); - - if (objectid < btrfs_ino(&entry->vfs_inode)) - node = node->rb_left; - else if (objectid > btrfs_ino(&entry->vfs_inode)) - node = node->rb_right; - else - break; - } - if (!node) { - while (prev) { - entry = rb_entry(prev, struct btrfs_inode, rb_node); - if (objectid <= btrfs_ino(&entry->vfs_inode)) { - node = prev; - break; - } - prev = rb_next(prev); - } - } - while (node) { - entry = rb_entry(node, struct btrfs_inode, rb_node); - objectid = btrfs_ino(&entry->vfs_inode) + 1; - inode = igrab(&entry->vfs_inode); - if (inode) { - spin_unlock(&root->inode_lock); - if (atomic_read(&inode->i_count) > 1) - d_prune_aliases(inode); - /* - * btrfs_drop_inode will have it removed from - * the inode cache when its usage count - * hits zero. - */ - iput(inode); - cond_resched(); - spin_lock(&root->inode_lock); - goto again; - } - - if (cond_resched_lock(&root->inode_lock)) - goto again; - - node = rb_next(node); - } - spin_unlock(&root->inode_lock); -} - -static int btrfs_init_locked_inode(struct inode *inode, void *p) -{ - struct btrfs_iget_args *args = p; - inode->i_ino = args->location->objectid; - memcpy(&BTRFS_I(inode)->location, args->location, - sizeof(*args->location)); - BTRFS_I(inode)->root = args->root; - return 0; -} - -static int btrfs_find_actor(struct inode *inode, void *opaque) -{ - struct btrfs_iget_args *args = opaque; - return args->location->objectid == BTRFS_I(inode)->location.objectid && - args->root == BTRFS_I(inode)->root; -} - -static struct inode *btrfs_iget_locked(struct super_block *s, - struct btrfs_key *location, - struct btrfs_root *root) -{ - struct inode *inode; - struct btrfs_iget_args args; - unsigned long hashval = btrfs_inode_hash(location->objectid, root); - - args.location = location; - args.root = root; - - inode = iget5_locked(s, hashval, btrfs_find_actor, - btrfs_init_locked_inode, - (void *)&args); - return inode; -} - -/* Get an inode object given its location and corresponding root. - * Returns in *is_new if the inode was read from disk - */ -struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, - struct btrfs_root *root, int *new) -{ - struct inode *inode; - - inode = btrfs_iget_locked(s, location, root); - if (!inode) - return ERR_PTR(-ENOMEM); - - if (inode->i_state & I_NEW) { - int ret; - - ret = btrfs_read_locked_inode(inode); - if (!is_bad_inode(inode)) { - inode_tree_add(inode); - unlock_new_inode(inode); - if (new) - *new = 1; - } else { - unlock_new_inode(inode); - iput(inode); - ASSERT(ret < 0); - inode = ERR_PTR(ret < 0 ? ret : -ESTALE); - } - } - - return inode; -} - -static struct inode *new_simple_dir(struct super_block *s, - struct btrfs_key *key, - struct btrfs_root *root) -{ - struct inode *inode = new_inode(s); - - if (!inode) - return ERR_PTR(-ENOMEM); - - BTRFS_I(inode)->root = root; - memcpy(&BTRFS_I(inode)->location, key, sizeof(*key)); - set_bit(BTRFS_INODE_DUMMY, &BTRFS_I(inode)->runtime_flags); - - inode->i_ino = BTRFS_EMPTY_SUBVOL_DIR_OBJECTID; - inode->i_op = &btrfs_dir_ro_inode_operations; - inode->i_fop = &simple_dir_operations; - inode->i_mode = S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO; - inode->i_mtime = current_time(inode); - inode->i_atime = inode->i_mtime; - inode->i_ctime = inode->i_mtime; - BTRFS_I(inode)->i_otime = inode->i_mtime; - - return inode; -} - -struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) -{ - struct inode *inode; - struct btrfs_root *root = BTRFS_I(dir)->root; - struct btrfs_root *sub_root = root; - struct btrfs_key location; - int index; - int ret = 0; - - if (dentry->d_name.len > BTRFS_NAME_LEN) - return ERR_PTR(-ENAMETOOLONG); - - ret = btrfs_inode_by_name(dir, dentry, &location); - if (ret < 0) - return ERR_PTR(ret); - - if (location.objectid == 0) - return ERR_PTR(-ENOENT); - - if (location.type == BTRFS_INODE_ITEM_KEY) { - inode = btrfs_iget(dir->i_sb, &location, root, NULL); - return inode; - } - - BUG_ON(location.type != BTRFS_ROOT_ITEM_KEY); - - index = srcu_read_lock(&root->fs_info->subvol_srcu); - ret = fixup_tree_root_location(root, dir, dentry, - &location, &sub_root); - if (ret < 0) { - if (ret != -ENOENT) - inode = ERR_PTR(ret); - else - inode = new_simple_dir(dir->i_sb, &location, sub_root); - } else { - inode = btrfs_iget(dir->i_sb, &location, sub_root, NULL); - } - srcu_read_unlock(&root->fs_info->subvol_srcu, index); - - if (!IS_ERR(inode) && root != sub_root) { - down_read(&root->fs_info->cleanup_work_sem); - if (!(inode->i_sb->s_flags & MS_RDONLY)) - ret = btrfs_orphan_cleanup(sub_root); - up_read(&root->fs_info->cleanup_work_sem); - if (ret) { - iput(inode); - inode = ERR_PTR(ret); - } - } - - return inode; -} - -static int btrfs_dentry_delete(const struct dentry *dentry) -{ - struct btrfs_root *root; - struct inode *inode = d_inode(dentry); - - if (!inode && !IS_ROOT(dentry)) - inode = d_inode(dentry->d_parent); - - if (inode) { - root = BTRFS_I(inode)->root; - if (btrfs_root_refs(&root->root_item) == 0) - return 1; - - if (btrfs_ino(inode) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID) - return 1; - } - return 0; -} - -static void btrfs_dentry_release(struct dentry *dentry) -{ - kfree(dentry->d_fsdata); -} - -static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry, - unsigned int flags) -{ - struct inode *inode; - - inode = btrfs_lookup_dentry(dir, dentry); - if (IS_ERR(inode)) { - if (PTR_ERR(inode) == -ENOENT) - inode = NULL; - else - return ERR_CAST(inode); - } - - return d_splice_alias(inode, dentry); -} - -unsigned char btrfs_filetype_table[] = { - DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK -}; - -static int btrfs_real_readdir(struct file *file, struct dir_context *ctx) -{ - struct inode *inode = file_inode(file); - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_item *item; - struct btrfs_dir_item *di; - struct btrfs_key key; - struct btrfs_key found_key; - struct btrfs_path *path; - struct list_head ins_list; - struct list_head del_list; - int ret; - struct extent_buffer *leaf; - int slot; - unsigned char d_type; - int over = 0; - u32 di_cur; - u32 di_total; - u32 di_len; - int key_type = BTRFS_DIR_INDEX_KEY; - char tmp_name[32]; - char *name_ptr; - int name_len; - int is_curr = 0; /* ctx->pos points to the current index? */ - bool emitted; - bool put = false; - - /* FIXME, use a real flag for deciding about the key type */ - if (root->fs_info->tree_root == root) - key_type = BTRFS_DIR_ITEM_KEY; - - if (!dir_emit_dots(file, ctx)) - return 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - path->reada = READA_FORWARD; - - if (key_type == BTRFS_DIR_INDEX_KEY) { - INIT_LIST_HEAD(&ins_list); - INIT_LIST_HEAD(&del_list); - put = btrfs_readdir_get_delayed_items(inode, &ins_list, - &del_list); - } - - key.type = key_type; - key.offset = ctx->pos; - key.objectid = btrfs_ino(inode); - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto err; - - emitted = false; - while (1) { - leaf = path->nodes[0]; - slot = path->slots[0]; - if (slot >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) - goto err; - else if (ret > 0) - break; - continue; - } - - item = btrfs_item_nr(slot); - btrfs_item_key_to_cpu(leaf, &found_key, slot); - - if (found_key.objectid != key.objectid) - break; - if (found_key.type != key_type) - break; - if (found_key.offset < ctx->pos) - goto next; - if (key_type == BTRFS_DIR_INDEX_KEY && - btrfs_should_delete_dir_index(&del_list, - found_key.offset)) - goto next; - - ctx->pos = found_key.offset; - is_curr = 1; - - di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); - di_cur = 0; - di_total = btrfs_item_size(leaf, item); - - while (di_cur < di_total) { - struct btrfs_key location; - - if (verify_dir_item(root, leaf, di)) - break; - - name_len = btrfs_dir_name_len(leaf, di); - if (name_len <= sizeof(tmp_name)) { - name_ptr = tmp_name; - } else { - name_ptr = kmalloc(name_len, GFP_KERNEL); - if (!name_ptr) { - ret = -ENOMEM; - goto err; - } - } - read_extent_buffer(leaf, name_ptr, - (unsigned long)(di + 1), name_len); - - d_type = btrfs_filetype_table[btrfs_dir_type(leaf, di)]; - btrfs_dir_item_key_to_cpu(leaf, di, &location); - - - /* is this a reference to our own snapshot? If so - * skip it. - * - * In contrast to old kernels, we insert the snapshot's - * dir item and dir index after it has been created, so - * we won't find a reference to our own snapshot. We - * still keep the following code for backward - * compatibility. - */ - if (location.type == BTRFS_ROOT_ITEM_KEY && - location.objectid == root->root_key.objectid) { - over = 0; - goto skip; - } - over = !dir_emit(ctx, name_ptr, name_len, - location.objectid, d_type); - -skip: - if (name_ptr != tmp_name) - kfree(name_ptr); - - if (over) - goto nopos; - emitted = true; - di_len = btrfs_dir_name_len(leaf, di) + - btrfs_dir_data_len(leaf, di) + sizeof(*di); - di_cur += di_len; - di = (struct btrfs_dir_item *)((char *)di + di_len); - } -next: - path->slots[0]++; - } - - if (key_type == BTRFS_DIR_INDEX_KEY) { - if (is_curr) - ctx->pos++; - ret = btrfs_readdir_delayed_dir_index(ctx, &ins_list, &emitted); - if (ret) - goto nopos; - } - - /* - * If we haven't emitted any dir entry, we must not touch ctx->pos as - * it was was set to the termination value in previous call. We assume - * that "." and ".." were emitted if we reach this point and set the - * termination value as well for an empty directory. - */ - if (ctx->pos > 2 && !emitted) - goto nopos; - - /* Reached end of directory/root. Bump pos past the last item. */ - ctx->pos++; - - /* - * Stop new entries from being returned after we return the last - * entry. - * - * New directory entries are assigned a strictly increasing - * offset. This means that new entries created during readdir - * are *guaranteed* to be seen in the future by that readdir. - * This has broken buggy programs which operate on names as - * they're returned by readdir. Until we re-use freed offsets - * we have this hack to stop new entries from being returned - * under the assumption that they'll never reach this huge - * offset. - * - * This is being careful not to overflow 32bit loff_t unless the - * last entry requires it because doing so has broken 32bit apps - * in the past. - */ - if (key_type == BTRFS_DIR_INDEX_KEY) { - if (ctx->pos >= INT_MAX) - ctx->pos = LLONG_MAX; - else - ctx->pos = INT_MAX; - } -nopos: - ret = 0; -err: - if (put) - btrfs_readdir_put_delayed_items(inode, &ins_list, &del_list); - btrfs_free_path(path); - return ret; -} - -int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_trans_handle *trans; - int ret = 0; - bool nolock = false; - - if (test_bit(BTRFS_INODE_DUMMY, &BTRFS_I(inode)->runtime_flags)) - return 0; - - if (btrfs_fs_closing(root->fs_info) && btrfs_is_free_space_inode(inode)) - nolock = true; - - if (wbc->sync_mode == WB_SYNC_ALL) { - if (nolock) - trans = btrfs_join_transaction_nolock(root); - else - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) - return PTR_ERR(trans); - ret = btrfs_commit_transaction(trans, root); - } - return ret; -} - -/* - * This is somewhat expensive, updating the tree every time the - * inode changes. But, it is most likely to find the inode in cache. - * FIXME, needs more benchmarking...there are no reasons other than performance - * to keep or drop this code. - */ -static int btrfs_dirty_inode(struct inode *inode) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_trans_handle *trans; - int ret; - - if (test_bit(BTRFS_INODE_DUMMY, &BTRFS_I(inode)->runtime_flags)) - return 0; - - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - ret = btrfs_update_inode(trans, root, inode); - if (ret && ret == -ENOSPC) { - /* whoops, lets try again with the full transaction */ - btrfs_end_transaction(trans, root); - trans = btrfs_start_transaction(root, 1); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - ret = btrfs_update_inode(trans, root, inode); - } - btrfs_end_transaction(trans, root); - if (BTRFS_I(inode)->delayed_node) - btrfs_balance_delayed_items(root); - - return ret; -} - -/* - * This is a copy of file_update_time. We need this so we can return error on - * ENOSPC for updating the inode in the case of file write and mmap writes. - */ -static int btrfs_update_time(struct inode *inode, struct timespec *now, - int flags) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - - if (btrfs_root_readonly(root)) - return -EROFS; - - if (flags & S_VERSION) - inode_inc_iversion(inode); - if (flags & S_CTIME) - inode->i_ctime = *now; - if (flags & S_MTIME) - inode->i_mtime = *now; - if (flags & S_ATIME) - inode->i_atime = *now; - return btrfs_dirty_inode(inode); -} - -/* - * find the highest existing sequence number in a directory - * and then set the in-memory index_cnt variable to reflect - * free sequence numbers - */ -static int btrfs_set_inode_index_count(struct inode *inode) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_key key, found_key; - struct btrfs_path *path; - struct extent_buffer *leaf; - int ret; - - key.objectid = btrfs_ino(inode); - key.type = BTRFS_DIR_INDEX_KEY; - key.offset = (u64)-1; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out; - /* FIXME: we should be able to handle this */ - if (ret == 0) - goto out; - ret = 0; - - /* - * MAGIC NUMBER EXPLANATION: - * since we search a directory based on f_pos we have to start at 2 - * since '.' and '..' have f_pos of 0 and 1 respectively, so everybody - * else has to start at 2 - */ - if (path->slots[0] == 0) { - BTRFS_I(inode)->index_cnt = 2; - goto out; - } - - path->slots[0]--; - - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - - if (found_key.objectid != btrfs_ino(inode) || - found_key.type != BTRFS_DIR_INDEX_KEY) { - BTRFS_I(inode)->index_cnt = 2; - goto out; - } - - BTRFS_I(inode)->index_cnt = found_key.offset + 1; -out: - btrfs_free_path(path); - return ret; -} - -/* - * helper to find a free sequence number in a given directory. This current - * code is very simple, later versions will do smarter things in the btree - */ -int btrfs_set_inode_index(struct inode *dir, u64 *index) -{ - int ret = 0; - - if (BTRFS_I(dir)->index_cnt == (u64)-1) { - ret = btrfs_inode_delayed_dir_index_count(dir); - if (ret) { - ret = btrfs_set_inode_index_count(dir); - if (ret) - return ret; - } - } - - *index = BTRFS_I(dir)->index_cnt; - BTRFS_I(dir)->index_cnt++; - - return ret; -} - -static int btrfs_insert_inode_locked(struct inode *inode) -{ - struct btrfs_iget_args args; - args.location = &BTRFS_I(inode)->location; - args.root = BTRFS_I(inode)->root; - - return insert_inode_locked4(inode, - btrfs_inode_hash(inode->i_ino, BTRFS_I(inode)->root), - btrfs_find_actor, &args); -} - -static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *dir, - const char *name, int name_len, - u64 ref_objectid, u64 objectid, - umode_t mode, u64 *index) -{ - struct inode *inode; - struct btrfs_inode_item *inode_item; - struct btrfs_key *location; - struct btrfs_path *path; - struct btrfs_inode_ref *ref; - struct btrfs_key key[2]; - u32 sizes[2]; - int nitems = name ? 2 : 1; - unsigned long ptr; - int ret; - - path = btrfs_alloc_path(); - if (!path) - return ERR_PTR(-ENOMEM); - - inode = new_inode(root->fs_info->sb); - if (!inode) { - btrfs_free_path(path); - return ERR_PTR(-ENOMEM); - } - - /* - * O_TMPFILE, set link count to 0, so that after this point, - * we fill in an inode item with the correct link count. - */ - if (!name) - set_nlink(inode, 0); - - /* - * we have to initialize this early, so we can reclaim the inode - * number if we fail afterwards in this function. - */ - inode->i_ino = objectid; - - if (dir && name) { - trace_btrfs_inode_request(dir); - - ret = btrfs_set_inode_index(dir, index); - if (ret) { - btrfs_free_path(path); - iput(inode); - return ERR_PTR(ret); - } - } else if (dir) { - *index = 0; - } - /* - * index_cnt is ignored for everything but a dir, - * btrfs_get_inode_index_count has an explanation for the magic - * number - */ - BTRFS_I(inode)->index_cnt = 2; - BTRFS_I(inode)->dir_index = *index; - BTRFS_I(inode)->root = root; - BTRFS_I(inode)->generation = trans->transid; - inode->i_generation = BTRFS_I(inode)->generation; - - /* - * We could have gotten an inode number from somebody who was fsynced - * and then removed in this same transaction, so let's just set full - * sync since it will be a full sync anyway and this will blow away the - * old info in the log. - */ - set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(inode)->runtime_flags); - - key[0].objectid = objectid; - key[0].type = BTRFS_INODE_ITEM_KEY; - key[0].offset = 0; - - sizes[0] = sizeof(struct btrfs_inode_item); - - if (name) { - /* - * Start new inodes with an inode_ref. This is slightly more - * efficient for small numbers of hard links since they will - * be packed into one item. Extended refs will kick in if we - * add more hard links than can fit in the ref item. - */ - key[1].objectid = objectid; - key[1].type = BTRFS_INODE_REF_KEY; - key[1].offset = ref_objectid; - - sizes[1] = name_len + sizeof(*ref); - } - - location = &BTRFS_I(inode)->location; - location->objectid = objectid; - location->offset = 0; - location->type = BTRFS_INODE_ITEM_KEY; - - ret = btrfs_insert_inode_locked(inode); - if (ret < 0) - goto fail; - - path->leave_spinning = 1; - ret = btrfs_insert_empty_items(trans, root, path, key, sizes, nitems); - if (ret != 0) - goto fail_unlock; - - inode_init_owner(inode, dir, mode); - inode_set_bytes(inode, 0); - - inode->i_mtime = current_time(inode); - inode->i_atime = inode->i_mtime; - inode->i_ctime = inode->i_mtime; - BTRFS_I(inode)->i_otime = inode->i_mtime; - - inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_inode_item); - memset_extent_buffer(path->nodes[0], 0, (unsigned long)inode_item, - sizeof(*inode_item)); - fill_inode_item(trans, path->nodes[0], inode_item, inode); - - if (name) { - ref = btrfs_item_ptr(path->nodes[0], path->slots[0] + 1, - struct btrfs_inode_ref); - btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len); - btrfs_set_inode_ref_index(path->nodes[0], ref, *index); - ptr = (unsigned long)(ref + 1); - write_extent_buffer(path->nodes[0], name, ptr, name_len); - } - - btrfs_mark_buffer_dirty(path->nodes[0]); - btrfs_free_path(path); - - btrfs_inherit_iflags(inode, dir); - - if (S_ISREG(mode)) { - if (btrfs_test_opt(root->fs_info, NODATASUM)) - BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM; - if (btrfs_test_opt(root->fs_info, NODATACOW)) - BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW | - BTRFS_INODE_NODATASUM; - } - - inode_tree_add(inode); - - trace_btrfs_inode_new(inode); - btrfs_set_inode_last_trans(trans, inode); - - btrfs_update_root_times(trans, root); - - ret = btrfs_inode_inherit_props(trans, inode, dir); - if (ret) - btrfs_err(root->fs_info, - "error inheriting props for ino %llu (root %llu): %d", - btrfs_ino(inode), root->root_key.objectid, ret); - - return inode; - -fail_unlock: - unlock_new_inode(inode); -fail: - if (dir && name) - BTRFS_I(dir)->index_cnt--; - btrfs_free_path(path); - iput(inode); - return ERR_PTR(ret); -} - -static inline u8 btrfs_inode_type(struct inode *inode) -{ - return btrfs_type_by_mode[(inode->i_mode & S_IFMT) >> S_SHIFT]; -} - -/* - * utility function to add 'inode' into 'parent_inode' with - * a give name and a given sequence number. - * if 'add_backref' is true, also insert a backref from the - * inode to the parent directory. - */ -int btrfs_add_link(struct btrfs_trans_handle *trans, - struct inode *parent_inode, struct inode *inode, - const char *name, int name_len, int add_backref, u64 index) -{ - int ret = 0; - struct btrfs_key key; - struct btrfs_root *root = BTRFS_I(parent_inode)->root; - u64 ino = btrfs_ino(inode); - u64 parent_ino = btrfs_ino(parent_inode); - - if (unlikely(ino == BTRFS_FIRST_FREE_OBJECTID)) { - memcpy(&key, &BTRFS_I(inode)->root->root_key, sizeof(key)); - } else { - key.objectid = ino; - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - } - - if (unlikely(ino == BTRFS_FIRST_FREE_OBJECTID)) { - ret = btrfs_add_root_ref(trans, root->fs_info->tree_root, - key.objectid, root->root_key.objectid, - parent_ino, index, name, name_len); - } else if (add_backref) { - ret = btrfs_insert_inode_ref(trans, root, name, name_len, ino, - parent_ino, index); - } - - /* Nothing to clean up yet */ - if (ret) - return ret; - - ret = btrfs_insert_dir_item(trans, root, name, name_len, - parent_inode, &key, - btrfs_inode_type(inode), index); - if (ret == -EEXIST || ret == -EOVERFLOW) - goto fail_dir_item; - else if (ret) { - btrfs_abort_transaction(trans, ret); - return ret; - } - - btrfs_i_size_write(parent_inode, parent_inode->i_size + - name_len * 2); - inode_inc_iversion(parent_inode); - parent_inode->i_mtime = parent_inode->i_ctime = - current_time(parent_inode); - ret = btrfs_update_inode(trans, root, parent_inode); - if (ret) - btrfs_abort_transaction(trans, ret); - return ret; - -fail_dir_item: - if (unlikely(ino == BTRFS_FIRST_FREE_OBJECTID)) { - u64 local_index; - int err; - err = btrfs_del_root_ref(trans, root->fs_info->tree_root, - key.objectid, root->root_key.objectid, - parent_ino, &local_index, name, name_len); - - } else if (add_backref) { - u64 local_index; - int err; - - err = btrfs_del_inode_ref(trans, root, name, name_len, - ino, parent_ino, &local_index); - } - return ret; -} - -static int btrfs_add_nondir(struct btrfs_trans_handle *trans, - struct inode *dir, struct dentry *dentry, - struct inode *inode, int backref, u64 index) -{ - int err = btrfs_add_link(trans, dir, inode, - dentry->d_name.name, dentry->d_name.len, - backref, index); - if (err > 0) - err = -EEXIST; - return err; -} - -static int btrfs_mknod(struct inode *dir, struct dentry *dentry, - umode_t mode, dev_t rdev) -{ - struct btrfs_trans_handle *trans; - struct btrfs_root *root = BTRFS_I(dir)->root; - struct inode *inode = NULL; - int err; - int drop_inode = 0; - u64 objectid; - u64 index = 0; - - /* - * 2 for inode item and ref - * 2 for dir items - * 1 for xattr if selinux is on - */ - trans = btrfs_start_transaction(root, 5); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - err = btrfs_find_free_ino(root, &objectid); - if (err) - goto out_unlock; - - inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name, - dentry->d_name.len, btrfs_ino(dir), objectid, - mode, &index); - if (IS_ERR(inode)) { - err = PTR_ERR(inode); - goto out_unlock; - } - - /* - * If the active LSM wants to access the inode during - * d_instantiate it needs these. Smack checks to see - * if the filesystem supports xattrs by looking at the - * ops vector. - */ - inode->i_op = &btrfs_special_inode_operations; - init_special_inode(inode, inode->i_mode, rdev); - - err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name); - if (err) - goto out_unlock_inode; - - err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index); - if (err) { - goto out_unlock_inode; - } else { - btrfs_update_inode(trans, root, inode); - unlock_new_inode(inode); - d_instantiate(dentry, inode); - } - -out_unlock: - btrfs_end_transaction(trans, root); - btrfs_balance_delayed_items(root); - btrfs_btree_balance_dirty(root); - if (drop_inode) { - inode_dec_link_count(inode); - iput(inode); - } - return err; - -out_unlock_inode: - drop_inode = 1; - unlock_new_inode(inode); - goto out_unlock; - -} - -static int btrfs_create(struct inode *dir, struct dentry *dentry, - umode_t mode, bool excl) -{ - struct btrfs_trans_handle *trans; - struct btrfs_root *root = BTRFS_I(dir)->root; - struct inode *inode = NULL; - int drop_inode_on_err = 0; - int err; - u64 objectid; - u64 index = 0; - - /* - * 2 for inode item and ref - * 2 for dir items - * 1 for xattr if selinux is on - */ - trans = btrfs_start_transaction(root, 5); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - err = btrfs_find_free_ino(root, &objectid); - if (err) - goto out_unlock; - - inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name, - dentry->d_name.len, btrfs_ino(dir), objectid, - mode, &index); - if (IS_ERR(inode)) { - err = PTR_ERR(inode); - goto out_unlock; - } - drop_inode_on_err = 1; - /* - * If the active LSM wants to access the inode during - * d_instantiate it needs these. Smack checks to see - * if the filesystem supports xattrs by looking at the - * ops vector. - */ - inode->i_fop = &btrfs_file_operations; - inode->i_op = &btrfs_file_inode_operations; - inode->i_mapping->a_ops = &btrfs_aops; - - err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name); - if (err) - goto out_unlock_inode; - - err = btrfs_update_inode(trans, root, inode); - if (err) - goto out_unlock_inode; - - err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index); - if (err) - goto out_unlock_inode; - - BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; - unlock_new_inode(inode); - d_instantiate(dentry, inode); - -out_unlock: - btrfs_end_transaction(trans, root); - if (err && drop_inode_on_err) { - inode_dec_link_count(inode); - iput(inode); - } - btrfs_balance_delayed_items(root); - btrfs_btree_balance_dirty(root); - return err; - -out_unlock_inode: - unlock_new_inode(inode); - goto out_unlock; - -} - -static int btrfs_link(struct dentry *old_dentry, struct inode *dir, - struct dentry *dentry) -{ - struct btrfs_trans_handle *trans = NULL; - struct btrfs_root *root = BTRFS_I(dir)->root; - struct inode *inode = d_inode(old_dentry); - u64 index; - int err; - int drop_inode = 0; - - /* do not allow sys_link's with other subvols of the same device */ - if (root->objectid != BTRFS_I(inode)->root->objectid) - return -EXDEV; - - if (inode->i_nlink >= BTRFS_LINK_MAX) - return -EMLINK; - - err = btrfs_set_inode_index(dir, &index); - if (err) - goto fail; - - /* - * 2 items for inode and inode ref - * 2 items for dir items - * 1 item for parent inode - */ - trans = btrfs_start_transaction(root, 5); - if (IS_ERR(trans)) { - err = PTR_ERR(trans); - trans = NULL; - goto fail; - } - - /* There are several dir indexes for this inode, clear the cache. */ - BTRFS_I(inode)->dir_index = 0ULL; - inc_nlink(inode); - inode_inc_iversion(inode); - inode->i_ctime = current_time(inode); - ihold(inode); - set_bit(BTRFS_INODE_COPY_EVERYTHING, &BTRFS_I(inode)->runtime_flags); - - err = btrfs_add_nondir(trans, dir, dentry, inode, 1, index); - - if (err) { - drop_inode = 1; - } else { - struct dentry *parent = dentry->d_parent; - err = btrfs_update_inode(trans, root, inode); - if (err) - goto fail; - if (inode->i_nlink == 1) { - /* - * If new hard link count is 1, it's a file created - * with open(2) O_TMPFILE flag. - */ - err = btrfs_orphan_del(trans, inode); - if (err) - goto fail; - } - d_instantiate(dentry, inode); - btrfs_log_new_name(trans, inode, NULL, parent); - } - - btrfs_balance_delayed_items(root); -fail: - if (trans) - btrfs_end_transaction(trans, root); - if (drop_inode) { - inode_dec_link_count(inode); - iput(inode); - } - btrfs_btree_balance_dirty(root); - return err; -} - -static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) -{ - struct inode *inode = NULL; - struct btrfs_trans_handle *trans; - struct btrfs_root *root = BTRFS_I(dir)->root; - int err = 0; - int drop_on_err = 0; - u64 objectid = 0; - u64 index = 0; - - /* - * 2 items for inode and ref - * 2 items for dir items - * 1 for xattr if selinux is on - */ - trans = btrfs_start_transaction(root, 5); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - err = btrfs_find_free_ino(root, &objectid); - if (err) - goto out_fail; - - inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name, - dentry->d_name.len, btrfs_ino(dir), objectid, - S_IFDIR | mode, &index); - if (IS_ERR(inode)) { - err = PTR_ERR(inode); - goto out_fail; - } - - drop_on_err = 1; - /* these must be set before we unlock the inode */ - inode->i_op = &btrfs_dir_inode_operations; - inode->i_fop = &btrfs_dir_file_operations; - - err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name); - if (err) - goto out_fail_inode; - - btrfs_i_size_write(inode, 0); - err = btrfs_update_inode(trans, root, inode); - if (err) - goto out_fail_inode; - - err = btrfs_add_link(trans, dir, inode, dentry->d_name.name, - dentry->d_name.len, 0, index); - if (err) - goto out_fail_inode; - - d_instantiate(dentry, inode); - /* - * mkdir is special. We're unlocking after we call d_instantiate - * to avoid a race with nfsd calling d_instantiate. - */ - unlock_new_inode(inode); - drop_on_err = 0; - -out_fail: - btrfs_end_transaction(trans, root); - if (drop_on_err) { - inode_dec_link_count(inode); - iput(inode); - } - btrfs_balance_delayed_items(root); - btrfs_btree_balance_dirty(root); - return err; - -out_fail_inode: - unlock_new_inode(inode); - goto out_fail; -} - -/* Find next extent map of a given extent map, caller needs to ensure locks */ -static struct extent_map *next_extent_map(struct extent_map *em) -{ - struct rb_node *next; - - next = rb_next(&em->rb_node); - if (!next) - return NULL; - return container_of(next, struct extent_map, rb_node); -} - -static struct extent_map *prev_extent_map(struct extent_map *em) -{ - struct rb_node *prev; - - prev = rb_prev(&em->rb_node); - if (!prev) - return NULL; - return container_of(prev, struct extent_map, rb_node); -} - -/* helper for btfs_get_extent. Given an existing extent in the tree, - * the existing extent is the nearest extent to map_start, - * and an extent that you want to insert, deal with overlap and insert - * the best fitted new extent into the tree. - */ -static int merge_extent_mapping(struct extent_map_tree *em_tree, - struct extent_map *existing, - struct extent_map *em, - u64 map_start) -{ - struct extent_map *prev; - struct extent_map *next; - u64 start; - u64 end; - u64 start_diff; - - BUG_ON(map_start < em->start || map_start >= extent_map_end(em)); - - if (existing->start > map_start) { - next = existing; - prev = prev_extent_map(next); - } else { - prev = existing; - next = next_extent_map(prev); - } - - start = prev ? extent_map_end(prev) : em->start; - start = max_t(u64, start, em->start); - end = next ? next->start : extent_map_end(em); - end = min_t(u64, end, extent_map_end(em)); - start_diff = start - em->start; - em->start = start; - em->len = end - start; - if (em->block_start < EXTENT_MAP_LAST_BYTE && - !test_bit(EXTENT_FLAG_COMPRESSED, &em->flags)) { - em->block_start += start_diff; - em->block_len -= start_diff; - } - return add_extent_mapping(em_tree, em, 0); -} - -static noinline int uncompress_inline(struct btrfs_path *path, - struct page *page, - size_t pg_offset, u64 extent_offset, - struct btrfs_file_extent_item *item) -{ - int ret; - struct extent_buffer *leaf = path->nodes[0]; - char *tmp; - size_t max_size; - unsigned long inline_size; - unsigned long ptr; - int compress_type; - - WARN_ON(pg_offset != 0); - compress_type = btrfs_file_extent_compression(leaf, item); - max_size = btrfs_file_extent_ram_bytes(leaf, item); - inline_size = btrfs_file_extent_inline_item_len(leaf, - btrfs_item_nr(path->slots[0])); - tmp = kmalloc(inline_size, GFP_NOFS); - if (!tmp) - return -ENOMEM; - ptr = btrfs_file_extent_inline_start(item); - - read_extent_buffer(leaf, tmp, ptr, inline_size); - - max_size = min_t(unsigned long, PAGE_SIZE, max_size); - ret = btrfs_decompress(compress_type, tmp, page, - extent_offset, inline_size, max_size); - kfree(tmp); - return ret; -} - -/* - * a bit scary, this does extent mapping from logical file offset to the disk. - * the ugly parts come from merging extents from the disk with the in-ram - * representation. This gets more complex because of the data=ordered code, - * where the in-ram extents might be locked pending data=ordered completion. - * - * This also copies inline extents directly into the page. - */ - -struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, - size_t pg_offset, u64 start, u64 len, - int create) -{ - int ret; - int err = 0; - u64 extent_start = 0; - u64 extent_end = 0; - u64 objectid = btrfs_ino(inode); - u32 found_type; - struct btrfs_path *path = NULL; - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_file_extent_item *item; - struct extent_buffer *leaf; - struct btrfs_key found_key; - struct extent_map *em = NULL; - struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; - struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; - struct btrfs_trans_handle *trans = NULL; - const bool new_inline = !page || create; - -again: - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, start, len); - if (em) - em->bdev = root->fs_info->fs_devices->latest_bdev; - read_unlock(&em_tree->lock); - - if (em) { - if (em->start > start || em->start + em->len <= start) - free_extent_map(em); - else if (em->block_start == EXTENT_MAP_INLINE && page) - free_extent_map(em); - else - goto out; - } - em = alloc_extent_map(); - if (!em) { - err = -ENOMEM; - goto out; - } - em->bdev = root->fs_info->fs_devices->latest_bdev; - em->start = EXTENT_MAP_HOLE; - em->orig_start = EXTENT_MAP_HOLE; - em->len = (u64)-1; - em->block_len = (u64)-1; - - if (!path) { - path = btrfs_alloc_path(); - if (!path) { - err = -ENOMEM; - goto out; - } - /* - * Chances are we'll be called again, so go ahead and do - * readahead - */ - path->reada = READA_FORWARD; - } - - ret = btrfs_lookup_file_extent(trans, root, path, - objectid, start, trans != NULL); - if (ret < 0) { - err = ret; - goto out; - } - - if (ret != 0) { - if (path->slots[0] == 0) - goto not_found; - path->slots[0]--; - } - - leaf = path->nodes[0]; - item = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - /* are we inside the extent that was found? */ - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - found_type = found_key.type; - if (found_key.objectid != objectid || - found_type != BTRFS_EXTENT_DATA_KEY) { - /* - * If we backup past the first extent we want to move forward - * and see if there is an extent in front of us, otherwise we'll - * say there is a hole for our whole search range which can - * cause problems. - */ - extent_end = start; - goto next; - } - - found_type = btrfs_file_extent_type(leaf, item); - extent_start = found_key.offset; - if (found_type == BTRFS_FILE_EXTENT_REG || - found_type == BTRFS_FILE_EXTENT_PREALLOC) { - extent_end = extent_start + - btrfs_file_extent_num_bytes(leaf, item); - } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { - size_t size; - size = btrfs_file_extent_inline_len(leaf, path->slots[0], item); - extent_end = ALIGN(extent_start + size, root->sectorsize); - } -next: - if (start >= extent_end) { - path->slots[0]++; - if (path->slots[0] >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) { - err = ret; - goto out; - } - if (ret > 0) - goto not_found; - leaf = path->nodes[0]; - } - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - if (found_key.objectid != objectid || - found_key.type != BTRFS_EXTENT_DATA_KEY) - goto not_found; - if (start + len <= found_key.offset) - goto not_found; - if (start > found_key.offset) - goto next; - em->start = start; - em->orig_start = start; - em->len = found_key.offset - start; - goto not_found_em; - } - - btrfs_extent_item_to_extent_map(inode, path, item, new_inline, em); - - if (found_type == BTRFS_FILE_EXTENT_REG || - found_type == BTRFS_FILE_EXTENT_PREALLOC) { - goto insert; - } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { - unsigned long ptr; - char *map; - size_t size; - size_t extent_offset; - size_t copy_size; - - if (new_inline) - goto out; - - size = btrfs_file_extent_inline_len(leaf, path->slots[0], item); - extent_offset = page_offset(page) + pg_offset - extent_start; - copy_size = min_t(u64, PAGE_SIZE - pg_offset, - size - extent_offset); - em->start = extent_start + extent_offset; - em->len = ALIGN(copy_size, root->sectorsize); - em->orig_block_len = em->len; - em->orig_start = em->start; - ptr = btrfs_file_extent_inline_start(item) + extent_offset; - if (create == 0 && !PageUptodate(page)) { - if (btrfs_file_extent_compression(leaf, item) != - BTRFS_COMPRESS_NONE) { - ret = uncompress_inline(path, page, pg_offset, - extent_offset, item); - if (ret) { - err = ret; - goto out; - } - } else { - map = kmap(page); - read_extent_buffer(leaf, map + pg_offset, ptr, - copy_size); - if (pg_offset + copy_size < PAGE_SIZE) { - memset(map + pg_offset + copy_size, 0, - PAGE_SIZE - pg_offset - - copy_size); - } - kunmap(page); - } - flush_dcache_page(page); - } else if (create && PageUptodate(page)) { - BUG(); - if (!trans) { - kunmap(page); - free_extent_map(em); - em = NULL; - - btrfs_release_path(path); - trans = btrfs_join_transaction(root); - - if (IS_ERR(trans)) - return ERR_CAST(trans); - goto again; - } - map = kmap(page); - write_extent_buffer(leaf, map + pg_offset, ptr, - copy_size); - kunmap(page); - btrfs_mark_buffer_dirty(leaf); - } - set_extent_uptodate(io_tree, em->start, - extent_map_end(em) - 1, NULL, GFP_NOFS); - goto insert; - } -not_found: - em->start = start; - em->orig_start = start; - em->len = len; -not_found_em: - em->block_start = EXTENT_MAP_HOLE; - set_bit(EXTENT_FLAG_VACANCY, &em->flags); -insert: - btrfs_release_path(path); - if (em->start > start || extent_map_end(em) <= start) { - btrfs_err(root->fs_info, - "bad extent! em: [%llu %llu] passed [%llu %llu]", - em->start, em->len, start, len); - err = -EIO; - goto out; - } - - err = 0; - write_lock(&em_tree->lock); - ret = add_extent_mapping(em_tree, em, 0); - /* it is possible that someone inserted the extent into the tree - * while we had the lock dropped. It is also possible that - * an overlapping map exists in the tree - */ - if (ret == -EEXIST) { - struct extent_map *existing; - - ret = 0; - - existing = search_extent_mapping(em_tree, start, len); - /* - * existing will always be non-NULL, since there must be - * extent causing the -EEXIST. - */ - if (existing->start == em->start && - extent_map_end(existing) == extent_map_end(em) && - em->block_start == existing->block_start) { - /* - * these two extents are the same, it happens - * with inlines especially - */ - free_extent_map(em); - em = existing; - err = 0; - - } else if (start >= extent_map_end(existing) || - start <= existing->start) { - /* - * The existing extent map is the one nearest to - * the [start, start + len) range which overlaps - */ - err = merge_extent_mapping(em_tree, existing, - em, start); - free_extent_map(existing); - if (err) { - free_extent_map(em); - em = NULL; - } - } else { - free_extent_map(em); - em = existing; - err = 0; - } - } - write_unlock(&em_tree->lock); -out: - - trace_btrfs_get_extent(root, em); - - btrfs_free_path(path); - if (trans) { - ret = btrfs_end_transaction(trans, root); - if (!err) - err = ret; - } - if (err) { - free_extent_map(em); - return ERR_PTR(err); - } - BUG_ON(!em); /* Error is always set */ - return em; -} - -struct extent_map *btrfs_get_extent_fiemap(struct inode *inode, struct page *page, - size_t pg_offset, u64 start, u64 len, - int create) -{ - struct extent_map *em; - struct extent_map *hole_em = NULL; - u64 range_start = start; - u64 end; - u64 found; - u64 found_end; - int err = 0; - - em = btrfs_get_extent(inode, page, pg_offset, start, len, create); - if (IS_ERR(em)) - return em; - if (em) { - /* - * if our em maps to - * - a hole or - * - a pre-alloc extent, - * there might actually be delalloc bytes behind it. - */ - if (em->block_start != EXTENT_MAP_HOLE && - !test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) - return em; - else - hole_em = em; - } - - /* check to see if we've wrapped (len == -1 or similar) */ - end = start + len; - if (end < start) - end = (u64)-1; - else - end -= 1; - - em = NULL; - - /* ok, we didn't find anything, lets look for delalloc */ - found = count_range_bits(&BTRFS_I(inode)->io_tree, &range_start, - end, len, EXTENT_DELALLOC, 1); - found_end = range_start + found; - if (found_end < range_start) - found_end = (u64)-1; - - /* - * we didn't find anything useful, return - * the original results from get_extent() - */ - if (range_start > end || found_end <= start) { - em = hole_em; - hole_em = NULL; - goto out; - } - - /* adjust the range_start to make sure it doesn't - * go backwards from the start they passed in - */ - range_start = max(start, range_start); - found = found_end - range_start; - - if (found > 0) { - u64 hole_start = start; - u64 hole_len = len; - - em = alloc_extent_map(); - if (!em) { - err = -ENOMEM; - goto out; - } - /* - * when btrfs_get_extent can't find anything it - * returns one huge hole - * - * make sure what it found really fits our range, and - * adjust to make sure it is based on the start from - * the caller - */ - if (hole_em) { - u64 calc_end = extent_map_end(hole_em); - - if (calc_end <= start || (hole_em->start > end)) { - free_extent_map(hole_em); - hole_em = NULL; - } else { - hole_start = max(hole_em->start, start); - hole_len = calc_end - hole_start; - } - } - em->bdev = NULL; - if (hole_em && range_start > hole_start) { - /* our hole starts before our delalloc, so we - * have to return just the parts of the hole - * that go until the delalloc starts - */ - em->len = min(hole_len, - range_start - hole_start); - em->start = hole_start; - em->orig_start = hole_start; - /* - * don't adjust block start at all, - * it is fixed at EXTENT_MAP_HOLE - */ - em->block_start = hole_em->block_start; - em->block_len = hole_len; - if (test_bit(EXTENT_FLAG_PREALLOC, &hole_em->flags)) - set_bit(EXTENT_FLAG_PREALLOC, &em->flags); - } else { - em->start = range_start; - em->len = found; - em->orig_start = range_start; - em->block_start = EXTENT_MAP_DELALLOC; - em->block_len = found; - } - } else if (hole_em) { - return hole_em; - } -out: - - free_extent_map(hole_em); - if (err) { - free_extent_map(em); - return ERR_PTR(err); - } - return em; -} - -static struct extent_map *btrfs_create_dio_extent(struct inode *inode, - const u64 start, - const u64 len, - const u64 orig_start, - const u64 block_start, - const u64 block_len, - const u64 orig_block_len, - const u64 ram_bytes, - const int type) -{ - struct extent_map *em = NULL; - int ret; - - down_read(&BTRFS_I(inode)->dio_sem); - if (type != BTRFS_ORDERED_NOCOW) { - em = create_pinned_em(inode, start, len, orig_start, - block_start, block_len, orig_block_len, - ram_bytes, type); - if (IS_ERR(em)) - goto out; - } - ret = btrfs_add_ordered_extent_dio(inode, start, block_start, - len, block_len, type); - if (ret) { - if (em) { - free_extent_map(em); - btrfs_drop_extent_cache(inode, start, - start + len - 1, 0); - } - em = ERR_PTR(ret); - } - out: - up_read(&BTRFS_I(inode)->dio_sem); - - return em; -} - -static struct extent_map *btrfs_new_extent_direct(struct inode *inode, - u64 start, u64 len) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct extent_map *em; - struct btrfs_key ins; - u64 alloc_hint; - int ret; - - alloc_hint = get_extent_allocation_hint(inode, start, len); - ret = btrfs_reserve_extent(root, len, len, root->sectorsize, 0, - alloc_hint, &ins, 1, 1); - if (ret) - return ERR_PTR(ret); - - em = btrfs_create_dio_extent(inode, start, ins.offset, start, - ins.objectid, ins.offset, ins.offset, - ins.offset, 0); - btrfs_dec_block_group_reservations(root->fs_info, ins.objectid); - if (IS_ERR(em)) - btrfs_free_reserved_extent(root, ins.objectid, ins.offset, 1); - - return em; -} - -/* - * returns 1 when the nocow is safe, < 1 on error, 0 if the - * block must be cow'd - */ -noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len, - u64 *orig_start, u64 *orig_block_len, - u64 *ram_bytes) -{ - struct btrfs_trans_handle *trans; - struct btrfs_path *path; - int ret; - struct extent_buffer *leaf; - struct btrfs_root *root = BTRFS_I(inode)->root; - struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; - struct btrfs_file_extent_item *fi; - struct btrfs_key key; - u64 disk_bytenr; - u64 backref_offset; - u64 extent_end; - u64 num_bytes; - int slot; - int found_type; - bool nocow = (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW); - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - ret = btrfs_lookup_file_extent(NULL, root, path, btrfs_ino(inode), - offset, 0); - if (ret < 0) - goto out; - - slot = path->slots[0]; - if (ret == 1) { - if (slot == 0) { - /* can't find the item, must cow */ - ret = 0; - goto out; - } - slot--; - } - ret = 0; - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, slot); - if (key.objectid != btrfs_ino(inode) || - key.type != BTRFS_EXTENT_DATA_KEY) { - /* not our file or wrong item type, must cow */ - goto out; - } - - if (key.offset > offset) { - /* Wrong offset, must cow */ - goto out; - } - - fi = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); - found_type = btrfs_file_extent_type(leaf, fi); - if (found_type != BTRFS_FILE_EXTENT_REG && - found_type != BTRFS_FILE_EXTENT_PREALLOC) { - /* not a regular extent, must cow */ - goto out; - } - - if (!nocow && found_type == BTRFS_FILE_EXTENT_REG) - goto out; - - extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi); - if (extent_end <= offset) - goto out; - - disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); - if (disk_bytenr == 0) - goto out; - - if (btrfs_file_extent_compression(leaf, fi) || - btrfs_file_extent_encryption(leaf, fi) || - btrfs_file_extent_other_encoding(leaf, fi)) - goto out; - - backref_offset = btrfs_file_extent_offset(leaf, fi); - - if (orig_start) { - *orig_start = key.offset - backref_offset; - *orig_block_len = btrfs_file_extent_disk_num_bytes(leaf, fi); - *ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi); - } - - if (btrfs_extent_readonly(root, disk_bytenr)) - goto out; - - num_bytes = min(offset + *len, extent_end) - offset; - if (!nocow && found_type == BTRFS_FILE_EXTENT_PREALLOC) { - u64 range_end; - - range_end = round_up(offset + num_bytes, root->sectorsize) - 1; - ret = test_range_bit(io_tree, offset, range_end, - EXTENT_DELALLOC, 0, NULL); - if (ret) { - ret = -EAGAIN; - goto out; - } - } - - btrfs_release_path(path); - - /* - * look for other files referencing this extent, if we - * find any we must cow - */ - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) { - ret = 0; - goto out; - } - - ret = btrfs_cross_ref_exist(trans, root, btrfs_ino(inode), - key.offset - backref_offset, disk_bytenr); - btrfs_end_transaction(trans, root); - if (ret) { - ret = 0; - goto out; - } - - /* - * adjust disk_bytenr and num_bytes to cover just the bytes - * in this extent we are about to write. If there - * are any csums in that range we have to cow in order - * to keep the csums correct - */ - disk_bytenr += backref_offset; - disk_bytenr += offset - key.offset; - if (csum_exist_in_range(root, disk_bytenr, num_bytes)) - goto out; - /* - * all of the above have passed, it is safe to overwrite this extent - * without cow - */ - *len = num_bytes; - ret = 1; -out: - btrfs_free_path(path); - return ret; -} - -bool btrfs_page_exists_in_range(struct inode *inode, loff_t start, loff_t end) -{ - struct radix_tree_root *root = &inode->i_mapping->page_tree; - int found = false; - void **pagep = NULL; - struct page *page = NULL; - int start_idx; - int end_idx; - - start_idx = start >> PAGE_SHIFT; - - /* - * end is the last byte in the last page. end == start is legal - */ - end_idx = end >> PAGE_SHIFT; - - rcu_read_lock(); - - /* Most of the code in this while loop is lifted from - * find_get_page. It's been modified to begin searching from a - * page and return just the first page found in that range. If the - * found idx is less than or equal to the end idx then we know that - * a page exists. If no pages are found or if those pages are - * outside of the range then we're fine (yay!) */ - while (page == NULL && - radix_tree_gang_lookup_slot(root, &pagep, NULL, start_idx, 1)) { - page = radix_tree_deref_slot(pagep); - if (unlikely(!page)) - break; - - if (radix_tree_exception(page)) { - if (radix_tree_deref_retry(page)) { - page = NULL; - continue; - } - /* - * Otherwise, shmem/tmpfs must be storing a swap entry - * here as an exceptional entry: so return it without - * attempting to raise page count. - */ - page = NULL; - break; /* TODO: Is this relevant for this use case? */ - } - - if (!page_cache_get_speculative(page)) { - page = NULL; - continue; - } - - /* - * Has the page moved? - * This is part of the lockless pagecache protocol. See - * include/linux/pagemap.h for details. - */ - if (unlikely(page != *pagep)) { - put_page(page); - page = NULL; - } - } - - if (page) { - if (page->index <= end_idx) - found = true; - put_page(page); - } - - rcu_read_unlock(); - return found; -} - -static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend, - struct extent_state **cached_state, int writing) -{ - struct btrfs_ordered_extent *ordered; - int ret = 0; - - while (1) { - lock_extent_bits(&BTRFS_I(inode)->io_tree, lockstart, lockend, - cached_state); - /* - * We're concerned with the entire range that we're going to be - * doing DIO to, so we need to make sure there's no ordered - * extents in this range. - */ - ordered = btrfs_lookup_ordered_range(inode, lockstart, - lockend - lockstart + 1); - - /* - * We need to make sure there are no buffered pages in this - * range either, we could have raced between the invalidate in - * generic_file_direct_write and locking the extent. The - * invalidate needs to happen so that reads after a write do not - * get stale data. - */ - if (!ordered && - (!writing || - !btrfs_page_exists_in_range(inode, lockstart, lockend))) - break; - - unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend, - cached_state, GFP_NOFS); - - if (ordered) { - /* - * If we are doing a DIO read and the ordered extent we - * found is for a buffered write, we can not wait for it - * to complete and retry, because if we do so we can - * deadlock with concurrent buffered writes on page - * locks. This happens only if our DIO read covers more - * than one extent map, if at this point has already - * created an ordered extent for a previous extent map - * and locked its range in the inode's io tree, and a - * concurrent write against that previous extent map's - * range and this range started (we unlock the ranges - * in the io tree only when the bios complete and - * buffered writes always lock pages before attempting - * to lock range in the io tree). - */ - if (writing || - test_bit(BTRFS_ORDERED_DIRECT, &ordered->flags)) - btrfs_start_ordered_extent(inode, ordered, 1); - else - ret = -ENOTBLK; - btrfs_put_ordered_extent(ordered); - } else { - /* - * We could trigger writeback for this range (and wait - * for it to complete) and then invalidate the pages for - * this range (through invalidate_inode_pages2_range()), - * but that can lead us to a deadlock with a concurrent - * call to readpages() (a buffered read or a defrag call - * triggered a readahead) on a page lock due to an - * ordered dio extent we created before but did not have - * yet a corresponding bio submitted (whence it can not - * complete), which makes readpages() wait for that - * ordered extent to complete while holding a lock on - * that page. - */ - ret = -ENOTBLK; - } - - if (ret) - break; - - cond_resched(); - } - - return ret; -} - -static struct extent_map *create_pinned_em(struct inode *inode, u64 start, - u64 len, u64 orig_start, - u64 block_start, u64 block_len, - u64 orig_block_len, u64 ram_bytes, - int type) -{ - struct extent_map_tree *em_tree; - struct extent_map *em; - struct btrfs_root *root = BTRFS_I(inode)->root; - int ret; - - em_tree = &BTRFS_I(inode)->extent_tree; - em = alloc_extent_map(); - if (!em) - return ERR_PTR(-ENOMEM); - - em->start = start; - em->orig_start = orig_start; - em->mod_start = start; - em->mod_len = len; - em->len = len; - em->block_len = block_len; - em->block_start = block_start; - em->bdev = root->fs_info->fs_devices->latest_bdev; - em->orig_block_len = orig_block_len; - em->ram_bytes = ram_bytes; - em->generation = -1; - set_bit(EXTENT_FLAG_PINNED, &em->flags); - if (type == BTRFS_ORDERED_PREALLOC) - set_bit(EXTENT_FLAG_FILLING, &em->flags); - - do { - btrfs_drop_extent_cache(inode, em->start, - em->start + em->len - 1, 0); - write_lock(&em_tree->lock); - ret = add_extent_mapping(em_tree, em, 1); - write_unlock(&em_tree->lock); - } while (ret == -EEXIST); - - if (ret) { - free_extent_map(em); - return ERR_PTR(ret); - } - - return em; -} - -static void adjust_dio_outstanding_extents(struct inode *inode, - struct btrfs_dio_data *dio_data, - const u64 len) -{ - unsigned num_extents; - - num_extents = (unsigned) div64_u64(len + BTRFS_MAX_EXTENT_SIZE - 1, - BTRFS_MAX_EXTENT_SIZE); - /* - * If we have an outstanding_extents count still set then we're - * within our reservation, otherwise we need to adjust our inode - * counter appropriately. - */ - if (dio_data->outstanding_extents) { - dio_data->outstanding_extents -= num_extents; - } else { - spin_lock(&BTRFS_I(inode)->lock); - BTRFS_I(inode)->outstanding_extents += num_extents; - spin_unlock(&BTRFS_I(inode)->lock); - } -} - -static int btrfs_get_blocks_direct(struct inode *inode, sector_t iblock, - struct buffer_head *bh_result, int create) -{ - struct extent_map *em; - struct btrfs_root *root = BTRFS_I(inode)->root; - struct extent_state *cached_state = NULL; - struct btrfs_dio_data *dio_data = NULL; - u64 start = iblock << inode->i_blkbits; - u64 lockstart, lockend; - u64 len = bh_result->b_size; - int unlock_bits = EXTENT_LOCKED; - int ret = 0; - - if (create) - unlock_bits |= EXTENT_DIRTY; - else - len = min_t(u64, len, root->sectorsize); - - lockstart = start; - lockend = start + len - 1; - - if (current->journal_info) { - /* - * Need to pull our outstanding extents and set journal_info to NULL so - * that anything that needs to check if there's a transaction doesn't get - * confused. - */ - dio_data = current->journal_info; - current->journal_info = NULL; - } - - /* - * If this errors out it's because we couldn't invalidate pagecache for - * this range and we need to fallback to buffered. - */ - if (lock_extent_direct(inode, lockstart, lockend, &cached_state, - create)) { - ret = -ENOTBLK; - goto err; - } - - em = btrfs_get_extent(inode, NULL, 0, start, len, 0); - if (IS_ERR(em)) { - ret = PTR_ERR(em); - goto unlock_err; - } - - /* - * Ok for INLINE and COMPRESSED extents we need to fallback on buffered - * io. INLINE is special, and we could probably kludge it in here, but - * it's still buffered so for safety lets just fall back to the generic - * buffered path. - * - * For COMPRESSED we _have_ to read the entire extent in so we can - * decompress it, so there will be buffering required no matter what we - * do, so go ahead and fallback to buffered. - * - * We return -ENOTBLK because that's what makes DIO go ahead and go back - * to buffered IO. Don't blame me, this is the price we pay for using - * the generic code. - */ - if (test_bit(EXTENT_FLAG_COMPRESSED, &em->flags) || - em->block_start == EXTENT_MAP_INLINE) { - free_extent_map(em); - ret = -ENOTBLK; - goto unlock_err; - } - - /* Just a good old fashioned hole, return */ - if (!create && (em->block_start == EXTENT_MAP_HOLE || - test_bit(EXTENT_FLAG_PREALLOC, &em->flags))) { - free_extent_map(em); - goto unlock_err; - } - - /* - * We don't allocate a new extent in the following cases - * - * 1) The inode is marked as NODATACOW. In this case we'll just use the - * existing extent. - * 2) The extent is marked as PREALLOC. We're good to go here and can - * just use the extent. - * - */ - if (!create) { - len = min(len, em->len - (start - em->start)); - lockstart = start + len; - goto unlock; - } - - if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags) || - ((BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW) && - em->block_start != EXTENT_MAP_HOLE)) { - int type; - u64 block_start, orig_start, orig_block_len, ram_bytes; - - if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) - type = BTRFS_ORDERED_PREALLOC; - else - type = BTRFS_ORDERED_NOCOW; - len = min(len, em->len - (start - em->start)); - block_start = em->block_start + (start - em->start); - - if (can_nocow_extent(inode, start, &len, &orig_start, - &orig_block_len, &ram_bytes) == 1 && - btrfs_inc_nocow_writers(root->fs_info, block_start)) { - struct extent_map *em2; - - em2 = btrfs_create_dio_extent(inode, start, len, - orig_start, block_start, - len, orig_block_len, - ram_bytes, type); - btrfs_dec_nocow_writers(root->fs_info, block_start); - if (type == BTRFS_ORDERED_PREALLOC) { - free_extent_map(em); - em = em2; - } - if (em2 && IS_ERR(em2)) { - ret = PTR_ERR(em2); - goto unlock_err; - } - /* - * For inode marked NODATACOW or extent marked PREALLOC, - * use the existing or preallocated extent, so does not - * need to adjust btrfs_space_info's bytes_may_use. - */ - btrfs_free_reserved_data_space_noquota(inode, - start, len); - goto unlock; - } - } - - /* - * this will cow the extent, reset the len in case we changed - * it above - */ - len = bh_result->b_size; - free_extent_map(em); - em = btrfs_new_extent_direct(inode, start, len); - if (IS_ERR(em)) { - ret = PTR_ERR(em); - goto unlock_err; - } - len = min(len, em->len - (start - em->start)); -unlock: - bh_result->b_blocknr = (em->block_start + (start - em->start)) >> - inode->i_blkbits; - bh_result->b_size = len; - bh_result->b_bdev = em->bdev; - set_buffer_mapped(bh_result); - if (create) { - if (!test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) - set_buffer_new(bh_result); - - /* - * Need to update the i_size under the extent lock so buffered - * readers will get the updated i_size when we unlock. - */ - if (start + len > i_size_read(inode)) - i_size_write(inode, start + len); - - adjust_dio_outstanding_extents(inode, dio_data, len); - WARN_ON(dio_data->reserve < len); - dio_data->reserve -= len; - dio_data->unsubmitted_oe_range_end = start + len; - current->journal_info = dio_data; - } - - /* - * In the case of write we need to clear and unlock the entire range, - * in the case of read we need to unlock only the end area that we - * aren't using if there is any left over space. - */ - if (lockstart < lockend) { - clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, - lockend, unlock_bits, 1, 0, - &cached_state, GFP_NOFS); - } else { - free_extent_state(cached_state); - } - - free_extent_map(em); - - return 0; - -unlock_err: - clear_extent_bit(&BTRFS_I(inode)->io_tree, lockstart, lockend, - unlock_bits, 1, 0, &cached_state, GFP_NOFS); -err: - if (dio_data) - current->journal_info = dio_data; - /* - * Compensate the delalloc release we do in btrfs_direct_IO() when we - * write less data then expected, so that we don't underflow our inode's - * outstanding extents counter. - */ - if (create && dio_data) - adjust_dio_outstanding_extents(inode, dio_data, len); - - return ret; -} - -static inline int submit_dio_repair_bio(struct inode *inode, struct bio *bio, - int mirror_num) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - int ret; - - BUG_ON(bio_op(bio) == REQ_OP_WRITE); - - bio_get(bio); - - ret = btrfs_bio_wq_end_io(root->fs_info, bio, - BTRFS_WQ_ENDIO_DIO_REPAIR); - if (ret) - goto err; - - ret = btrfs_map_bio(root, bio, mirror_num, 0); -err: - bio_put(bio); - return ret; -} - -static int btrfs_check_dio_repairable(struct inode *inode, - struct bio *failed_bio, - struct io_failure_record *failrec, - int failed_mirror) -{ - struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); - int num_copies; - - num_copies = btrfs_num_copies(fs_info, failrec->logical, failrec->len); - if (num_copies == 1) { - /* - * we only have a single copy of the data, so don't bother with - * all the retry and error correction code that follows. no - * matter what the error is, it is very likely to persist. - */ - btrfs_debug(fs_info, - "Check DIO Repairable: cannot repair, num_copies=%d, next_mirror %d, failed_mirror %d", - num_copies, failrec->this_mirror, failed_mirror); - return 0; - } - - failrec->failed_mirror = failed_mirror; - failrec->this_mirror++; - if (failrec->this_mirror == failed_mirror) - failrec->this_mirror++; - - if (failrec->this_mirror > num_copies) { - btrfs_debug(fs_info, - "Check DIO Repairable: (fail) num_copies=%d, next_mirror %d, failed_mirror %d", - num_copies, failrec->this_mirror, failed_mirror); - return 0; - } - - return 1; -} - -static int dio_read_error(struct inode *inode, struct bio *failed_bio, - struct page *page, unsigned int pgoff, - u64 start, u64 end, int failed_mirror, - bio_end_io_t *repair_endio, void *repair_arg) -{ - struct io_failure_record *failrec; - struct bio *bio; - int isector; - int read_mode; - int ret; - - BUG_ON(bio_op(failed_bio) == REQ_OP_WRITE); - - ret = btrfs_get_io_failure_record(inode, start, end, &failrec); - if (ret) - return ret; - - ret = btrfs_check_dio_repairable(inode, failed_bio, failrec, - failed_mirror); - if (!ret) { - free_io_failure(inode, failrec); - return -EIO; - } - - if ((failed_bio->bi_vcnt > 1) - || (failed_bio->bi_io_vec->bv_len - > BTRFS_I(inode)->root->sectorsize)) - read_mode = READ_SYNC | REQ_FAILFAST_DEV; - else - read_mode = READ_SYNC; - - isector = start - btrfs_io_bio(failed_bio)->logical; - isector >>= inode->i_sb->s_blocksize_bits; - bio = btrfs_create_repair_bio(inode, failed_bio, failrec, page, - pgoff, isector, repair_endio, repair_arg); - if (!bio) { - free_io_failure(inode, failrec); - return -EIO; - } - bio_set_op_attrs(bio, REQ_OP_READ, read_mode); - - btrfs_debug(BTRFS_I(inode)->root->fs_info, - "Repair DIO Read Error: submitting new dio read[%#x] to this_mirror=%d, in_validation=%d\n", - read_mode, failrec->this_mirror, failrec->in_validation); - - ret = submit_dio_repair_bio(inode, bio, failrec->this_mirror); - if (ret) { - free_io_failure(inode, failrec); - bio_put(bio); - } - - return ret; -} - -struct btrfs_retry_complete { - struct completion done; - struct inode *inode; - u64 start; - int uptodate; -}; - -static void btrfs_retry_endio_nocsum(struct bio *bio) -{ - struct btrfs_retry_complete *done = bio->bi_private; - struct inode *inode; - struct bio_vec *bvec; - int i; - - if (bio->bi_error) - goto end; - - ASSERT(bio->bi_vcnt == 1); - inode = bio->bi_io_vec->bv_page->mapping->host; - ASSERT(bio->bi_io_vec->bv_len == BTRFS_I(inode)->root->sectorsize); - - done->uptodate = 1; - bio_for_each_segment_all(bvec, bio, i) - clean_io_failure(done->inode, done->start, bvec->bv_page, 0); -end: - complete(&done->done); - bio_put(bio); -} - -static int __btrfs_correct_data_nocsum(struct inode *inode, - struct btrfs_io_bio *io_bio) -{ - struct btrfs_fs_info *fs_info; - struct bio_vec *bvec; - struct btrfs_retry_complete done; - u64 start; - unsigned int pgoff; - u32 sectorsize; - int nr_sectors; - int i; - int ret; - - fs_info = BTRFS_I(inode)->root->fs_info; - sectorsize = BTRFS_I(inode)->root->sectorsize; - - start = io_bio->logical; - done.inode = inode; - - bio_for_each_segment_all(bvec, &io_bio->bio, i) { - nr_sectors = BTRFS_BYTES_TO_BLKS(fs_info, bvec->bv_len); - pgoff = bvec->bv_offset; - -next_block_or_try_again: - done.uptodate = 0; - done.start = start; - init_completion(&done.done); - - ret = dio_read_error(inode, &io_bio->bio, bvec->bv_page, - pgoff, start, start + sectorsize - 1, - io_bio->mirror_num, - btrfs_retry_endio_nocsum, &done); - if (ret) - return ret; - - wait_for_completion(&done.done); - - if (!done.uptodate) { - /* We might have another mirror, so try again */ - goto next_block_or_try_again; - } - - start += sectorsize; - - if (nr_sectors--) { - pgoff += sectorsize; - goto next_block_or_try_again; - } - } - - return 0; -} - -static void btrfs_retry_endio(struct bio *bio) -{ - struct btrfs_retry_complete *done = bio->bi_private; - struct btrfs_io_bio *io_bio = btrfs_io_bio(bio); - struct inode *inode; - struct bio_vec *bvec; - u64 start; - int uptodate; - int ret; - int i; - - if (bio->bi_error) - goto end; - - uptodate = 1; - - start = done->start; - - ASSERT(bio->bi_vcnt == 1); - inode = bio->bi_io_vec->bv_page->mapping->host; - ASSERT(bio->bi_io_vec->bv_len == BTRFS_I(inode)->root->sectorsize); - - bio_for_each_segment_all(bvec, bio, i) { - ret = __readpage_endio_check(done->inode, io_bio, i, - bvec->bv_page, bvec->bv_offset, - done->start, bvec->bv_len); - if (!ret) - clean_io_failure(done->inode, done->start, - bvec->bv_page, bvec->bv_offset); - else - uptodate = 0; - } - - done->uptodate = uptodate; -end: - complete(&done->done); - bio_put(bio); -} - -static int __btrfs_subio_endio_read(struct inode *inode, - struct btrfs_io_bio *io_bio, int err) -{ - struct btrfs_fs_info *fs_info; - struct bio_vec *bvec; - struct btrfs_retry_complete done; - u64 start; - u64 offset = 0; - u32 sectorsize; - int nr_sectors; - unsigned int pgoff; - int csum_pos; - int i; - int ret; - - fs_info = BTRFS_I(inode)->root->fs_info; - sectorsize = BTRFS_I(inode)->root->sectorsize; - - err = 0; - start = io_bio->logical; - done.inode = inode; - - bio_for_each_segment_all(bvec, &io_bio->bio, i) { - nr_sectors = BTRFS_BYTES_TO_BLKS(fs_info, bvec->bv_len); - - pgoff = bvec->bv_offset; -next_block: - csum_pos = BTRFS_BYTES_TO_BLKS(fs_info, offset); - ret = __readpage_endio_check(inode, io_bio, csum_pos, - bvec->bv_page, pgoff, start, - sectorsize); - if (likely(!ret)) - goto next; -try_again: - done.uptodate = 0; - done.start = start; - init_completion(&done.done); - - ret = dio_read_error(inode, &io_bio->bio, bvec->bv_page, - pgoff, start, start + sectorsize - 1, - io_bio->mirror_num, - btrfs_retry_endio, &done); - if (ret) { - err = ret; - goto next; - } - - wait_for_completion(&done.done); - - if (!done.uptodate) { - /* We might have another mirror, so try again */ - goto try_again; - } -next: - offset += sectorsize; - start += sectorsize; - - ASSERT(nr_sectors); - - if (--nr_sectors) { - pgoff += sectorsize; - goto next_block; - } - } - - return err; -} - -static int btrfs_subio_endio_read(struct inode *inode, - struct btrfs_io_bio *io_bio, int err) -{ - bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; - - if (skip_csum) { - if (unlikely(err)) - return __btrfs_correct_data_nocsum(inode, io_bio); - else - return 0; - } else { - return __btrfs_subio_endio_read(inode, io_bio, err); - } -} - -static void btrfs_endio_direct_read(struct bio *bio) -{ - struct btrfs_dio_private *dip = bio->bi_private; - struct inode *inode = dip->inode; - struct bio *dio_bio; - struct btrfs_io_bio *io_bio = btrfs_io_bio(bio); - int err = bio->bi_error; - - if (dip->flags & BTRFS_DIO_ORIG_BIO_SUBMITTED) - err = btrfs_subio_endio_read(inode, io_bio, err); - - unlock_extent(&BTRFS_I(inode)->io_tree, dip->logical_offset, - dip->logical_offset + dip->bytes - 1); - dio_bio = dip->dio_bio; - - kfree(dip); - - dio_bio->bi_error = bio->bi_error; - dio_end_io(dio_bio, bio->bi_error); - - if (io_bio->end_io) - io_bio->end_io(io_bio, err); - bio_put(bio); -} - -static void btrfs_endio_direct_write_update_ordered(struct inode *inode, - const u64 offset, - const u64 bytes, - const int uptodate) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_ordered_extent *ordered = NULL; - u64 ordered_offset = offset; - u64 ordered_bytes = bytes; - int ret; - -again: - ret = btrfs_dec_test_first_ordered_pending(inode, &ordered, - &ordered_offset, - ordered_bytes, - uptodate); - if (!ret) - goto out_test; - - btrfs_init_work(&ordered->work, btrfs_endio_write_helper, - finish_ordered_fn, NULL, NULL); - btrfs_queue_work(root->fs_info->endio_write_workers, - &ordered->work); -out_test: - /* - * our bio might span multiple ordered extents. If we haven't - * completed the accounting for the whole dio, go back and try again - */ - if (ordered_offset < offset + bytes) { - ordered_bytes = offset + bytes - ordered_offset; - ordered = NULL; - goto again; - } -} - -static void btrfs_endio_direct_write(struct bio *bio) -{ - struct btrfs_dio_private *dip = bio->bi_private; - struct bio *dio_bio = dip->dio_bio; - - btrfs_endio_direct_write_update_ordered(dip->inode, - dip->logical_offset, - dip->bytes, - !bio->bi_error); - - kfree(dip); - - dio_bio->bi_error = bio->bi_error; - dio_end_io(dio_bio, bio->bi_error); - bio_put(bio); -} - -static int __btrfs_submit_bio_start_direct_io(struct inode *inode, - struct bio *bio, int mirror_num, - unsigned long bio_flags, u64 offset) -{ - int ret; - struct btrfs_root *root = BTRFS_I(inode)->root; - ret = btrfs_csum_one_bio(root, inode, bio, offset, 1); - BUG_ON(ret); /* -ENOMEM */ - return 0; -} - -static void btrfs_end_dio_bio(struct bio *bio) -{ - struct btrfs_dio_private *dip = bio->bi_private; - int err = bio->bi_error; - - if (err) - btrfs_warn(BTRFS_I(dip->inode)->root->fs_info, - "direct IO failed ino %llu rw %d,%u sector %#Lx len %u err no %d", - btrfs_ino(dip->inode), bio_op(bio), bio->bi_opf, - (unsigned long long)bio->bi_iter.bi_sector, - bio->bi_iter.bi_size, err); - - if (dip->subio_endio) - err = dip->subio_endio(dip->inode, btrfs_io_bio(bio), err); - - if (err) { - dip->errors = 1; - - /* - * before atomic variable goto zero, we must make sure - * dip->errors is perceived to be set. - */ - smp_mb__before_atomic(); - } - - /* if there are more bios still pending for this dio, just exit */ - if (!atomic_dec_and_test(&dip->pending_bios)) - goto out; - - if (dip->errors) { - bio_io_error(dip->orig_bio); - } else { - dip->dio_bio->bi_error = 0; - bio_endio(dip->orig_bio); - } -out: - bio_put(bio); -} - -static struct bio *btrfs_dio_bio_alloc(struct block_device *bdev, - u64 first_sector, gfp_t gfp_flags) -{ - struct bio *bio; - bio = btrfs_bio_alloc(bdev, first_sector, BIO_MAX_PAGES, gfp_flags); - if (bio) - bio_associate_current(bio); - return bio; -} - -static inline int btrfs_lookup_and_bind_dio_csum(struct btrfs_root *root, - struct inode *inode, - struct btrfs_dio_private *dip, - struct bio *bio, - u64 file_offset) -{ - struct btrfs_io_bio *io_bio = btrfs_io_bio(bio); - struct btrfs_io_bio *orig_io_bio = btrfs_io_bio(dip->orig_bio); - int ret; - - /* - * We load all the csum data we need when we submit - * the first bio to reduce the csum tree search and - * contention. - */ - if (dip->logical_offset == file_offset) { - ret = btrfs_lookup_bio_sums_dio(root, inode, dip->orig_bio, - file_offset); - if (ret) - return ret; - } - - if (bio == dip->orig_bio) - return 0; - - file_offset -= dip->logical_offset; - file_offset >>= inode->i_sb->s_blocksize_bits; - io_bio->csum = (u8 *)(((u32 *)orig_io_bio->csum) + file_offset); - - return 0; -} - -static inline int __btrfs_submit_dio_bio(struct bio *bio, struct inode *inode, - u64 file_offset, int skip_sum, - int async_submit) -{ - struct btrfs_dio_private *dip = bio->bi_private; - bool write = bio_op(bio) == REQ_OP_WRITE; - struct btrfs_root *root = BTRFS_I(inode)->root; - int ret; - - if (async_submit) - async_submit = !atomic_read(&BTRFS_I(inode)->sync_writers); - - bio_get(bio); - - if (!write) { - ret = btrfs_bio_wq_end_io(root->fs_info, bio, - BTRFS_WQ_ENDIO_DATA); - if (ret) - goto err; - } - - if (skip_sum) - goto map; - - if (write && async_submit) { - ret = btrfs_wq_submit_bio(root->fs_info, - inode, bio, 0, 0, file_offset, - __btrfs_submit_bio_start_direct_io, - __btrfs_submit_bio_done); - goto err; - } else if (write) { - /* - * If we aren't doing async submit, calculate the csum of the - * bio now. - */ - ret = btrfs_csum_one_bio(root, inode, bio, file_offset, 1); - if (ret) - goto err; - } else { - ret = btrfs_lookup_and_bind_dio_csum(root, inode, dip, bio, - file_offset); - if (ret) - goto err; - } -map: - ret = btrfs_map_bio(root, bio, 0, async_submit); -err: - bio_put(bio); - return ret; -} - -static int btrfs_submit_direct_hook(struct btrfs_dio_private *dip, - int skip_sum) -{ - struct inode *inode = dip->inode; - struct btrfs_root *root = BTRFS_I(inode)->root; - struct bio *bio; - struct bio *orig_bio = dip->orig_bio; - struct bio_vec *bvec = orig_bio->bi_io_vec; - u64 start_sector = orig_bio->bi_iter.bi_sector; - u64 file_offset = dip->logical_offset; - u64 submit_len = 0; - u64 map_length; - u32 blocksize = root->sectorsize; - int async_submit = 0; - int nr_sectors; - int ret; - int i; - - map_length = orig_bio->bi_iter.bi_size; - ret = btrfs_map_block(root->fs_info, bio_op(orig_bio), - start_sector << 9, &map_length, NULL, 0); - if (ret) - return -EIO; - - if (map_length >= orig_bio->bi_iter.bi_size) { - bio = orig_bio; - dip->flags |= BTRFS_DIO_ORIG_BIO_SUBMITTED; - goto submit; - } - - /* async crcs make it difficult to collect full stripe writes. */ - if (btrfs_get_alloc_profile(root, 1) & BTRFS_BLOCK_GROUP_RAID56_MASK) - async_submit = 0; - else - async_submit = 1; - - bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, start_sector, GFP_NOFS); - if (!bio) - return -ENOMEM; - - bio_set_op_attrs(bio, bio_op(orig_bio), bio_flags(orig_bio)); - bio->bi_private = dip; - bio->bi_end_io = btrfs_end_dio_bio; - btrfs_io_bio(bio)->logical = file_offset; - atomic_inc(&dip->pending_bios); - - while (bvec <= (orig_bio->bi_io_vec + orig_bio->bi_vcnt - 1)) { - nr_sectors = BTRFS_BYTES_TO_BLKS(root->fs_info, bvec->bv_len); - i = 0; -next_block: - if (unlikely(map_length < submit_len + blocksize || - bio_add_page(bio, bvec->bv_page, blocksize, - bvec->bv_offset + (i * blocksize)) < blocksize)) { - /* - * inc the count before we submit the bio so - * we know the end IO handler won't happen before - * we inc the count. Otherwise, the dip might get freed - * before we're done setting it up - */ - atomic_inc(&dip->pending_bios); - ret = __btrfs_submit_dio_bio(bio, inode, - file_offset, skip_sum, - async_submit); - if (ret) { - bio_put(bio); - atomic_dec(&dip->pending_bios); - goto out_err; - } - - start_sector += submit_len >> 9; - file_offset += submit_len; - - submit_len = 0; - - bio = btrfs_dio_bio_alloc(orig_bio->bi_bdev, - start_sector, GFP_NOFS); - if (!bio) - goto out_err; - bio_set_op_attrs(bio, bio_op(orig_bio), - bio_flags(orig_bio)); - bio->bi_private = dip; - bio->bi_end_io = btrfs_end_dio_bio; - btrfs_io_bio(bio)->logical = file_offset; - - map_length = orig_bio->bi_iter.bi_size; - ret = btrfs_map_block(root->fs_info, bio_op(orig_bio), - start_sector << 9, - &map_length, NULL, 0); - if (ret) { - bio_put(bio); - goto out_err; - } - - goto next_block; - } else { - submit_len += blocksize; - if (--nr_sectors) { - i++; - goto next_block; - } - bvec++; - } - } - -submit: - ret = __btrfs_submit_dio_bio(bio, inode, file_offset, skip_sum, - async_submit); - if (!ret) - return 0; - - bio_put(bio); -out_err: - dip->errors = 1; - /* - * before atomic variable goto zero, we must - * make sure dip->errors is perceived to be set. - */ - smp_mb__before_atomic(); - if (atomic_dec_and_test(&dip->pending_bios)) - bio_io_error(dip->orig_bio); - - /* bio_end_io() will handle error, so we needn't return it */ - return 0; -} - -static void btrfs_submit_direct(struct bio *dio_bio, struct inode *inode, - loff_t file_offset) -{ - struct btrfs_dio_private *dip = NULL; - struct bio *io_bio = NULL; - struct btrfs_io_bio *btrfs_bio; - int skip_sum; - bool write = (bio_op(dio_bio) == REQ_OP_WRITE); - int ret = 0; - - skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; - - io_bio = btrfs_bio_clone(dio_bio, GFP_NOFS); - if (!io_bio) { - ret = -ENOMEM; - goto free_ordered; - } - - dip = kzalloc(sizeof(*dip), GFP_NOFS); - if (!dip) { - ret = -ENOMEM; - goto free_ordered; - } - - dip->private = dio_bio->bi_private; - dip->inode = inode; - dip->logical_offset = file_offset; - dip->bytes = dio_bio->bi_iter.bi_size; - dip->disk_bytenr = (u64)dio_bio->bi_iter.bi_sector << 9; - io_bio->bi_private = dip; - dip->orig_bio = io_bio; - dip->dio_bio = dio_bio; - atomic_set(&dip->pending_bios, 0); - btrfs_bio = btrfs_io_bio(io_bio); - btrfs_bio->logical = file_offset; - - if (write) { - io_bio->bi_end_io = btrfs_endio_direct_write; - } else { - io_bio->bi_end_io = btrfs_endio_direct_read; - dip->subio_endio = btrfs_subio_endio_read; - } - - /* - * Reset the range for unsubmitted ordered extents (to a 0 length range) - * even if we fail to submit a bio, because in such case we do the - * corresponding error handling below and it must not be done a second - * time by btrfs_direct_IO(). - */ - if (write) { - struct btrfs_dio_data *dio_data = current->journal_info; - - dio_data->unsubmitted_oe_range_end = dip->logical_offset + - dip->bytes; - dio_data->unsubmitted_oe_range_start = - dio_data->unsubmitted_oe_range_end; - } - - ret = btrfs_submit_direct_hook(dip, skip_sum); - if (!ret) - return; - - if (btrfs_bio->end_io) - btrfs_bio->end_io(btrfs_bio, ret); - -free_ordered: - /* - * If we arrived here it means either we failed to submit the dip - * or we either failed to clone the dio_bio or failed to allocate the - * dip. If we cloned the dio_bio and allocated the dip, we can just - * call bio_endio against our io_bio so that we get proper resource - * cleanup if we fail to submit the dip, otherwise, we must do the - * same as btrfs_endio_direct_[write|read] because we can't call these - * callbacks - they require an allocated dip and a clone of dio_bio. - */ - if (io_bio && dip) { - io_bio->bi_error = -EIO; - bio_endio(io_bio); - /* - * The end io callbacks free our dip, do the final put on io_bio - * and all the cleanup and final put for dio_bio (through - * dio_end_io()). - */ - dip = NULL; - io_bio = NULL; - } else { - if (write) - btrfs_endio_direct_write_update_ordered(inode, - file_offset, - dio_bio->bi_iter.bi_size, - 0); - else - unlock_extent(&BTRFS_I(inode)->io_tree, file_offset, - file_offset + dio_bio->bi_iter.bi_size - 1); - - dio_bio->bi_error = -EIO; - /* - * Releases and cleans up our dio_bio, no need to bio_put() - * nor bio_endio()/bio_io_error() against dio_bio. - */ - dio_end_io(dio_bio, ret); - } - if (io_bio) - bio_put(io_bio); - kfree(dip); -} - -static ssize_t check_direct_IO(struct btrfs_root *root, struct kiocb *iocb, - const struct iov_iter *iter, loff_t offset) -{ - int seg; - int i; - unsigned blocksize_mask = root->sectorsize - 1; - ssize_t retval = -EINVAL; - - if (offset & blocksize_mask) - goto out; - - if (iov_iter_alignment(iter) & blocksize_mask) - goto out; - - /* If this is a write we don't need to check anymore */ - if (iov_iter_rw(iter) != READ || !iter_is_iovec(iter)) - return 0; - /* - * Check to make sure we don't have duplicate iov_base's in this - * iovec, if so return EINVAL, otherwise we'll get csum errors - * when reading back. - */ - for (seg = 0; seg < iter->nr_segs; seg++) { - for (i = seg + 1; i < iter->nr_segs; i++) { - if (iter->iov[seg].iov_base == iter->iov[i].iov_base) - goto out; - } - } - retval = 0; -out: - return retval; -} - -static ssize_t btrfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) -{ - struct file *file = iocb->ki_filp; - struct inode *inode = file->f_mapping->host; - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_dio_data dio_data = { 0 }; - loff_t offset = iocb->ki_pos; - size_t count = 0; - int flags = 0; - bool wakeup = true; - bool relock = false; - ssize_t ret; - - if (check_direct_IO(BTRFS_I(inode)->root, iocb, iter, offset)) - return 0; - - inode_dio_begin(inode); - smp_mb__after_atomic(); - - /* - * The generic stuff only does filemap_write_and_wait_range, which - * isn't enough if we've written compressed pages to this area, so - * we need to flush the dirty pages again to make absolutely sure - * that any outstanding dirty pages are on disk. - */ - count = iov_iter_count(iter); - if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT, - &BTRFS_I(inode)->runtime_flags)) - filemap_fdatawrite_range(inode->i_mapping, offset, - offset + count - 1); - - if (iov_iter_rw(iter) == WRITE) { - /* - * If the write DIO is beyond the EOF, we need update - * the isize, but it is protected by i_mutex. So we can - * not unlock the i_mutex at this case. - */ - if (offset + count <= inode->i_size) { - inode_unlock(inode); - relock = true; - } - ret = btrfs_delalloc_reserve_space(inode, offset, count); - if (ret) - goto out; - dio_data.outstanding_extents = div64_u64(count + - BTRFS_MAX_EXTENT_SIZE - 1, - BTRFS_MAX_EXTENT_SIZE); - - /* - * We need to know how many extents we reserved so that we can - * do the accounting properly if we go over the number we - * originally calculated. Abuse current->journal_info for this. - */ - dio_data.reserve = round_up(count, root->sectorsize); - dio_data.unsubmitted_oe_range_start = (u64)offset; - dio_data.unsubmitted_oe_range_end = (u64)offset; - current->journal_info = &dio_data; - } else if (test_bit(BTRFS_INODE_READDIO_NEED_LOCK, - &BTRFS_I(inode)->runtime_flags)) { - inode_dio_end(inode); - flags = DIO_LOCKING | DIO_SKIP_HOLES; - wakeup = false; - } - - ret = __blockdev_direct_IO(iocb, inode, - BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev, - iter, btrfs_get_blocks_direct, NULL, - btrfs_submit_direct, flags); - if (iov_iter_rw(iter) == WRITE) { - current->journal_info = NULL; - if (ret < 0 && ret != -EIOCBQUEUED) { - if (dio_data.reserve) - btrfs_delalloc_release_space(inode, offset, - dio_data.reserve); - /* - * On error we might have left some ordered extents - * without submitting corresponding bios for them, so - * cleanup them up to avoid other tasks getting them - * and waiting for them to complete forever. - */ - if (dio_data.unsubmitted_oe_range_start < - dio_data.unsubmitted_oe_range_end) - btrfs_endio_direct_write_update_ordered(inode, - dio_data.unsubmitted_oe_range_start, - dio_data.unsubmitted_oe_range_end - - dio_data.unsubmitted_oe_range_start, - 0); - } else if (ret >= 0 && (size_t)ret < count) - btrfs_delalloc_release_space(inode, offset, - count - (size_t)ret); - } -out: - if (wakeup) - inode_dio_end(inode); - if (relock) - inode_lock(inode); - - return ret; -} - -#define BTRFS_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC) - -static int btrfs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, - __u64 start, __u64 len) -{ - int ret; - - ret = fiemap_check_flags(fieinfo, BTRFS_FIEMAP_FLAGS); - if (ret) - return ret; - - return extent_fiemap(inode, fieinfo, start, len, btrfs_get_extent_fiemap); -} - -int btrfs_readpage(struct file *file, struct page *page) -{ - struct extent_io_tree *tree; - tree = &BTRFS_I(page->mapping->host)->io_tree; - return extent_read_full_page(tree, page, btrfs_get_extent, 0); -} - -static int btrfs_writepage(struct page *page, struct writeback_control *wbc) -{ - struct extent_io_tree *tree; - struct inode *inode = page->mapping->host; - int ret; - - if (current->flags & PF_MEMALLOC) { - redirty_page_for_writepage(wbc, page); - unlock_page(page); - return 0; - } - - /* - * If we are under memory pressure we will call this directly from the - * VM, we need to make sure we have the inode referenced for the ordered - * extent. If not just return like we didn't do anything. - */ - if (!igrab(inode)) { - redirty_page_for_writepage(wbc, page); - return AOP_WRITEPAGE_ACTIVATE; - } - tree = &BTRFS_I(page->mapping->host)->io_tree; - ret = extent_write_full_page(tree, page, btrfs_get_extent, wbc); - btrfs_add_delayed_iput(inode); - return ret; -} - -static int btrfs_writepages(struct address_space *mapping, - struct writeback_control *wbc) -{ - struct extent_io_tree *tree; - - tree = &BTRFS_I(mapping->host)->io_tree; - return extent_writepages(tree, mapping, btrfs_get_extent, wbc); -} - -static int -btrfs_readpages(struct file *file, struct address_space *mapping, - struct list_head *pages, unsigned nr_pages) -{ - struct extent_io_tree *tree; - tree = &BTRFS_I(mapping->host)->io_tree; - return extent_readpages(tree, mapping, pages, nr_pages, - btrfs_get_extent); -} -static int __btrfs_releasepage(struct page *page, gfp_t gfp_flags) -{ - struct extent_io_tree *tree; - struct extent_map_tree *map; - int ret; - - tree = &BTRFS_I(page->mapping->host)->io_tree; - map = &BTRFS_I(page->mapping->host)->extent_tree; - ret = try_release_extent_mapping(map, tree, page, gfp_flags); - if (ret == 1) { - ClearPagePrivate(page); - set_page_private(page, 0); - put_page(page); - } - return ret; -} - -static int btrfs_releasepage(struct page *page, gfp_t gfp_flags) -{ - if (PageWriteback(page) || PageDirty(page)) - return 0; - return __btrfs_releasepage(page, gfp_flags & GFP_NOFS); -} - -static void btrfs_invalidatepage(struct page *page, unsigned int offset, - unsigned int length) -{ - struct inode *inode = page->mapping->host; - struct extent_io_tree *tree; - struct btrfs_ordered_extent *ordered; - struct extent_state *cached_state = NULL; - u64 page_start = page_offset(page); - u64 page_end = page_start + PAGE_SIZE - 1; - u64 start; - u64 end; - int inode_evicting = inode->i_state & I_FREEING; - - /* - * we have the page locked, so new writeback can't start, - * and the dirty bit won't be cleared while we are here. - * - * Wait for IO on this page so that we can safely clear - * the PagePrivate2 bit and do ordered accounting - */ - wait_on_page_writeback(page); - - tree = &BTRFS_I(inode)->io_tree; - if (offset) { - btrfs_releasepage(page, GFP_NOFS); - return; - } - - if (!inode_evicting) - lock_extent_bits(tree, page_start, page_end, &cached_state); -again: - start = page_start; - ordered = btrfs_lookup_ordered_range(inode, start, - page_end - start + 1); - if (ordered) { - end = min(page_end, ordered->file_offset + ordered->len - 1); - /* - * IO on this page will never be started, so we need - * to account for any ordered extents now - */ - if (!inode_evicting) - clear_extent_bit(tree, start, end, - EXTENT_DIRTY | EXTENT_DELALLOC | - EXTENT_LOCKED | EXTENT_DO_ACCOUNTING | - EXTENT_DEFRAG, 1, 0, &cached_state, - GFP_NOFS); - /* - * whoever cleared the private bit is responsible - * for the finish_ordered_io - */ - if (TestClearPagePrivate2(page)) { - struct btrfs_ordered_inode_tree *tree; - u64 new_len; - - tree = &BTRFS_I(inode)->ordered_tree; - - spin_lock_irq(&tree->lock); - set_bit(BTRFS_ORDERED_TRUNCATED, &ordered->flags); - new_len = start - ordered->file_offset; - if (new_len < ordered->truncated_len) - ordered->truncated_len = new_len; - spin_unlock_irq(&tree->lock); - - if (btrfs_dec_test_ordered_pending(inode, &ordered, - start, - end - start + 1, 1)) - btrfs_finish_ordered_io(ordered); - } - btrfs_put_ordered_extent(ordered); - if (!inode_evicting) { - cached_state = NULL; - lock_extent_bits(tree, start, end, - &cached_state); - } - - start = end + 1; - if (start < page_end) - goto again; - } - - /* - * Qgroup reserved space handler - * Page here will be either - * 1) Already written to disk - * In this case, its reserved space is released from data rsv map - * and will be freed by delayed_ref handler finally. - * So even we call qgroup_free_data(), it won't decrease reserved - * space. - * 2) Not written to disk - * This means the reserved space should be freed here. However, - * if a truncate invalidates the page (by clearing PageDirty) - * and the page is accounted for while allocating extent - * in btrfs_check_data_free_space() we let delayed_ref to - * free the entire extent. - */ - if (PageDirty(page)) - btrfs_qgroup_free_data(inode, page_start, PAGE_SIZE); - if (!inode_evicting) { - clear_extent_bit(tree, page_start, page_end, - EXTENT_LOCKED | EXTENT_DIRTY | - EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING | - EXTENT_DEFRAG, 1, 1, - &cached_state, GFP_NOFS); - - __btrfs_releasepage(page, GFP_NOFS); - } - - ClearPageChecked(page); - if (PagePrivate(page)) { - ClearPagePrivate(page); - set_page_private(page, 0); - put_page(page); - } -} - -/* - * btrfs_page_mkwrite() is not allowed to change the file size as it gets - * called from a page fault handler when a page is first dirtied. Hence we must - * be careful to check for EOF conditions here. We set the page up correctly - * for a written page which means we get ENOSPC checking when writing into - * holes and correct delalloc and unwritten extent mapping on filesystems that - * support these features. - * - * We are not allowed to take the i_mutex here so we have to play games to - * protect against truncate races as the page could now be beyond EOF. Because - * vmtruncate() writes the inode size before removing pages, once we have the - * page lock we can determine safely if the page is beyond EOF. If it is not - * beyond EOF, then the page is guaranteed safe against truncation until we - * unlock the page. - */ -int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct page *page = vmf->page; - struct inode *inode = file_inode(vma->vm_file); - struct btrfs_root *root = BTRFS_I(inode)->root; - struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; - struct btrfs_ordered_extent *ordered; - struct extent_state *cached_state = NULL; - char *kaddr; - unsigned long zero_start; - loff_t size; - int ret; - int reserved = 0; - u64 reserved_space; - u64 page_start; - u64 page_end; - u64 end; - - reserved_space = PAGE_SIZE; - - sb_start_pagefault(inode->i_sb); - page_start = page_offset(page); - page_end = page_start + PAGE_SIZE - 1; - end = page_end; - - /* - * Reserving delalloc space after obtaining the page lock can lead to - * deadlock. For example, if a dirty page is locked by this function - * and the call to btrfs_delalloc_reserve_space() ends up triggering - * dirty page write out, then the btrfs_writepage() function could - * end up waiting indefinitely to get a lock on the page currently - * being processed by btrfs_page_mkwrite() function. - */ - ret = btrfs_delalloc_reserve_space(inode, page_start, - reserved_space); - if (!ret) { - ret = file_update_time(vma->vm_file); - reserved = 1; - } - if (ret) { - if (ret == -ENOMEM) - ret = VM_FAULT_OOM; - else /* -ENOSPC, -EIO, etc */ - ret = VM_FAULT_SIGBUS; - if (reserved) - goto out; - goto out_noreserve; - } - - ret = VM_FAULT_NOPAGE; /* make the VM retry the fault */ -again: - lock_page(page); - size = i_size_read(inode); - - if ((page->mapping != inode->i_mapping) || - (page_start >= size)) { - /* page got truncated out from underneath us */ - goto out_unlock; - } - wait_on_page_writeback(page); - - lock_extent_bits(io_tree, page_start, page_end, &cached_state); - set_page_extent_mapped(page); - - /* - * we can't set the delalloc bits if there are pending ordered - * extents. Drop our locks and wait for them to finish - */ - ordered = btrfs_lookup_ordered_range(inode, page_start, page_end); - if (ordered) { - unlock_extent_cached(io_tree, page_start, page_end, - &cached_state, GFP_NOFS); - unlock_page(page); - btrfs_start_ordered_extent(inode, ordered, 1); - btrfs_put_ordered_extent(ordered); - goto again; - } - - if (page->index == ((size - 1) >> PAGE_SHIFT)) { - reserved_space = round_up(size - page_start, root->sectorsize); - if (reserved_space < PAGE_SIZE) { - end = page_start + reserved_space - 1; - spin_lock(&BTRFS_I(inode)->lock); - BTRFS_I(inode)->outstanding_extents++; - spin_unlock(&BTRFS_I(inode)->lock); - btrfs_delalloc_release_space(inode, page_start, - PAGE_SIZE - reserved_space); - } - } - - /* - * XXX - page_mkwrite gets called every time the page is dirtied, even - * if it was already dirty, so for space accounting reasons we need to - * clear any delalloc bits for the range we are fixing to save. There - * is probably a better way to do this, but for now keep consistent with - * prepare_pages in the normal write path. - */ - clear_extent_bit(&BTRFS_I(inode)->io_tree, page_start, end, - EXTENT_DIRTY | EXTENT_DELALLOC | - EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, - 0, 0, &cached_state, GFP_NOFS); - - ret = btrfs_set_extent_delalloc(inode, page_start, end, - &cached_state, 0); - if (ret) { - unlock_extent_cached(io_tree, page_start, page_end, - &cached_state, GFP_NOFS); - ret = VM_FAULT_SIGBUS; - goto out_unlock; - } - ret = 0; - - /* page is wholly or partially inside EOF */ - if (page_start + PAGE_SIZE > size) - zero_start = size & ~PAGE_MASK; - else - zero_start = PAGE_SIZE; - - if (zero_start != PAGE_SIZE) { - kaddr = kmap(page); - memset(kaddr + zero_start, 0, PAGE_SIZE - zero_start); - flush_dcache_page(page); - kunmap(page); - } - ClearPageChecked(page); - set_page_dirty(page); - SetPageUptodate(page); - - BTRFS_I(inode)->last_trans = root->fs_info->generation; - BTRFS_I(inode)->last_sub_trans = BTRFS_I(inode)->root->log_transid; - BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->root->last_log_commit; - - unlock_extent_cached(io_tree, page_start, page_end, &cached_state, GFP_NOFS); - -out_unlock: - if (!ret) { - sb_end_pagefault(inode->i_sb); - return VM_FAULT_LOCKED; - } - unlock_page(page); -out: - btrfs_delalloc_release_space(inode, page_start, reserved_space); -out_noreserve: - sb_end_pagefault(inode->i_sb); - return ret; -} - -static int btrfs_truncate(struct inode *inode) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_block_rsv *rsv; - int ret = 0; - int err = 0; - struct btrfs_trans_handle *trans; - u64 mask = root->sectorsize - 1; - u64 min_size = btrfs_calc_trunc_metadata_size(root, 1); - - ret = btrfs_wait_ordered_range(inode, inode->i_size & (~mask), - (u64)-1); - if (ret) - return ret; - - /* - * Yes ladies and gentlemen, this is indeed ugly. The fact is we have - * 3 things going on here - * - * 1) We need to reserve space for our orphan item and the space to - * delete our orphan item. Lord knows we don't want to have a dangling - * orphan item because we didn't reserve space to remove it. - * - * 2) We need to reserve space to update our inode. - * - * 3) We need to have something to cache all the space that is going to - * be free'd up by the truncate operation, but also have some slack - * space reserved in case it uses space during the truncate (thank you - * very much snapshotting). - * - * And we need these to all be separate. The fact is we can use a lot of - * space doing the truncate, and we have no earthly idea how much space - * we will use, so we need the truncate reservation to be separate so it - * doesn't end up using space reserved for updating the inode or - * removing the orphan item. We also need to be able to stop the - * transaction and start a new one, which means we need to be able to - * update the inode several times, and we have no idea of knowing how - * many times that will be, so we can't just reserve 1 item for the - * entirety of the operation, so that has to be done separately as well. - * Then there is the orphan item, which does indeed need to be held on - * to for the whole operation, and we need nobody to touch this reserved - * space except the orphan code. - * - * So that leaves us with - * - * 1) root->orphan_block_rsv - for the orphan deletion. - * 2) rsv - for the truncate reservation, which we will steal from the - * transaction reservation. - * 3) fs_info->trans_block_rsv - this will have 1 items worth left for - * updating the inode. - */ - rsv = btrfs_alloc_block_rsv(root, BTRFS_BLOCK_RSV_TEMP); - if (!rsv) - return -ENOMEM; - rsv->size = min_size; - rsv->failfast = 1; - - /* - * 1 for the truncate slack space - * 1 for updating the inode. - */ - trans = btrfs_start_transaction(root, 2); - if (IS_ERR(trans)) { - err = PTR_ERR(trans); - goto out; - } - - /* Migrate the slack space for the truncate to our reserve */ - ret = btrfs_block_rsv_migrate(&root->fs_info->trans_block_rsv, rsv, - min_size, 0); - BUG_ON(ret); - - /* - * So if we truncate and then write and fsync we normally would just - * write the extents that changed, which is a problem if we need to - * first truncate that entire inode. So set this flag so we write out - * all of the extents in the inode to the sync log so we're completely - * safe. - */ - set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(inode)->runtime_flags); - trans->block_rsv = rsv; - - while (1) { - ret = btrfs_truncate_inode_items(trans, root, inode, - inode->i_size, - BTRFS_EXTENT_DATA_KEY); - if (ret != -ENOSPC && ret != -EAGAIN) { - err = ret; - break; - } - - trans->block_rsv = &root->fs_info->trans_block_rsv; - ret = btrfs_update_inode(trans, root, inode); - if (ret) { - err = ret; - break; - } - - btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(root); - - trans = btrfs_start_transaction(root, 2); - if (IS_ERR(trans)) { - ret = err = PTR_ERR(trans); - trans = NULL; - break; - } - - ret = btrfs_block_rsv_migrate(&root->fs_info->trans_block_rsv, - rsv, min_size, 0); - BUG_ON(ret); /* shouldn't happen */ - trans->block_rsv = rsv; - } - - if (ret == 0 && inode->i_nlink > 0) { - trans->block_rsv = root->orphan_block_rsv; - ret = btrfs_orphan_del(trans, inode); - if (ret) - err = ret; - } - - if (trans) { - trans->block_rsv = &root->fs_info->trans_block_rsv; - ret = btrfs_update_inode(trans, root, inode); - if (ret && !err) - err = ret; - - ret = btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(root); - } -out: - btrfs_free_block_rsv(root, rsv); - - if (ret && !err) - err = ret; - - return err; -} - -/* - * create a new subvolume directory/inode (helper for the ioctl). - */ -int btrfs_create_subvol_root(struct btrfs_trans_handle *trans, - struct btrfs_root *new_root, - struct btrfs_root *parent_root, - u64 new_dirid) -{ - struct inode *inode; - int err; - u64 index = 0; - - inode = btrfs_new_inode(trans, new_root, NULL, "..", 2, - new_dirid, new_dirid, - S_IFDIR | (~current_umask() & S_IRWXUGO), - &index); - if (IS_ERR(inode)) - return PTR_ERR(inode); - inode->i_op = &btrfs_dir_inode_operations; - inode->i_fop = &btrfs_dir_file_operations; - - set_nlink(inode, 1); - btrfs_i_size_write(inode, 0); - unlock_new_inode(inode); - - err = btrfs_subvol_inherit_props(trans, new_root, parent_root); - if (err) - btrfs_err(new_root->fs_info, - "error inheriting subvolume %llu properties: %d", - new_root->root_key.objectid, err); - - err = btrfs_update_inode(trans, new_root, inode); - - iput(inode); - return err; -} - -struct inode *btrfs_alloc_inode(struct super_block *sb) -{ - struct btrfs_inode *ei; - struct inode *inode; - - ei = kmem_cache_alloc(btrfs_inode_cachep, GFP_NOFS); - if (!ei) - return NULL; - - ei->root = NULL; - ei->generation = 0; - ei->last_trans = 0; - ei->last_sub_trans = 0; - ei->logged_trans = 0; - ei->delalloc_bytes = 0; - ei->defrag_bytes = 0; - ei->disk_i_size = 0; - ei->flags = 0; - ei->csum_bytes = 0; - ei->index_cnt = (u64)-1; - ei->dir_index = 0; - ei->last_unlink_trans = 0; - ei->last_log_commit = 0; - ei->delayed_iput_count = 0; - - spin_lock_init(&ei->lock); - ei->outstanding_extents = 0; - ei->reserved_extents = 0; - - ei->runtime_flags = 0; - ei->force_compress = BTRFS_COMPRESS_NONE; - - ei->delayed_node = NULL; - - ei->i_otime.tv_sec = 0; - ei->i_otime.tv_nsec = 0; - - inode = &ei->vfs_inode; - extent_map_tree_init(&ei->extent_tree); - extent_io_tree_init(&ei->io_tree, &inode->i_data); - extent_io_tree_init(&ei->io_failure_tree, &inode->i_data); - ei->io_tree.track_uptodate = 1; - ei->io_failure_tree.track_uptodate = 1; - atomic_set(&ei->sync_writers, 0); - mutex_init(&ei->log_mutex); - mutex_init(&ei->delalloc_mutex); - btrfs_ordered_inode_tree_init(&ei->ordered_tree); - INIT_LIST_HEAD(&ei->delalloc_inodes); - INIT_LIST_HEAD(&ei->delayed_iput); - RB_CLEAR_NODE(&ei->rb_node); - init_rwsem(&ei->dio_sem); - - return inode; -} - -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS -void btrfs_test_destroy_inode(struct inode *inode) -{ - btrfs_drop_extent_cache(inode, 0, (u64)-1, 0); - kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode)); -} -#endif - -static void btrfs_i_callback(struct rcu_head *head) -{ - struct inode *inode = container_of(head, struct inode, i_rcu); - kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode)); -} - -void btrfs_destroy_inode(struct inode *inode) -{ - struct btrfs_ordered_extent *ordered; - struct btrfs_root *root = BTRFS_I(inode)->root; - - WARN_ON(!hlist_empty(&inode->i_dentry)); - WARN_ON(inode->i_data.nrpages); - WARN_ON(BTRFS_I(inode)->outstanding_extents); - WARN_ON(BTRFS_I(inode)->reserved_extents); - WARN_ON(BTRFS_I(inode)->delalloc_bytes); - WARN_ON(BTRFS_I(inode)->csum_bytes); - WARN_ON(BTRFS_I(inode)->defrag_bytes); - - /* - * This can happen where we create an inode, but somebody else also - * created the same inode and we need to destroy the one we already - * created. - */ - if (!root) - goto free; - - if (test_bit(BTRFS_INODE_HAS_ORPHAN_ITEM, - &BTRFS_I(inode)->runtime_flags)) { - btrfs_info(root->fs_info, "inode %llu still on the orphan list", - btrfs_ino(inode)); - atomic_dec(&root->orphan_inodes); - } - - while (1) { - ordered = btrfs_lookup_first_ordered_extent(inode, (u64)-1); - if (!ordered) - break; - else { - btrfs_err(root->fs_info, - "found ordered extent %llu %llu on inode cleanup", - ordered->file_offset, ordered->len); - btrfs_remove_ordered_extent(inode, ordered); - btrfs_put_ordered_extent(ordered); - btrfs_put_ordered_extent(ordered); - } - } - btrfs_qgroup_check_reserved_leak(inode); - inode_tree_del(inode); - btrfs_drop_extent_cache(inode, 0, (u64)-1, 0); -free: - call_rcu(&inode->i_rcu, btrfs_i_callback); -} - -int btrfs_drop_inode(struct inode *inode) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - - if (root == NULL) - return 1; - - /* the snap/subvol tree is on deleting */ - if (btrfs_root_refs(&root->root_item) == 0) - return 1; - else - return generic_drop_inode(inode); -} - -static void init_once(void *foo) -{ - struct btrfs_inode *ei = (struct btrfs_inode *) foo; - - inode_init_once(&ei->vfs_inode); -} - -void btrfs_destroy_cachep(void) -{ - /* - * Make sure all delayed rcu free inodes are flushed before we - * destroy cache. - */ - rcu_barrier(); - kmem_cache_destroy(btrfs_inode_cachep); - kmem_cache_destroy(btrfs_trans_handle_cachep); - kmem_cache_destroy(btrfs_transaction_cachep); - kmem_cache_destroy(btrfs_path_cachep); - kmem_cache_destroy(btrfs_free_space_cachep); -} - -int btrfs_init_cachep(void) -{ - btrfs_inode_cachep = kmem_cache_create("btrfs_inode", - sizeof(struct btrfs_inode), 0, - SLAB_RECLAIM_ACCOUNT | SLAB_MEM_SPREAD | SLAB_ACCOUNT, - init_once); - if (!btrfs_inode_cachep) - goto fail; - - btrfs_trans_handle_cachep = kmem_cache_create("btrfs_trans_handle", - sizeof(struct btrfs_trans_handle), 0, - SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL); - if (!btrfs_trans_handle_cachep) - goto fail; - - btrfs_transaction_cachep = kmem_cache_create("btrfs_transaction", - sizeof(struct btrfs_transaction), 0, - SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL); - if (!btrfs_transaction_cachep) - goto fail; - - btrfs_path_cachep = kmem_cache_create("btrfs_path", - sizeof(struct btrfs_path), 0, - SLAB_MEM_SPREAD, NULL); - if (!btrfs_path_cachep) - goto fail; - - btrfs_free_space_cachep = kmem_cache_create("btrfs_free_space", - sizeof(struct btrfs_free_space), 0, - SLAB_MEM_SPREAD, NULL); - if (!btrfs_free_space_cachep) - goto fail; - - return 0; -fail: - btrfs_destroy_cachep(); - return -ENOMEM; -} - -static int btrfs_getattr(struct vfsmount *mnt, - struct dentry *dentry, struct kstat *stat) -{ - u64 delalloc_bytes; - struct inode *inode = d_inode(dentry); - u32 blocksize = inode->i_sb->s_blocksize; - - generic_fillattr(inode, stat); - stat->dev = BTRFS_I(inode)->root->anon_dev; - - spin_lock(&BTRFS_I(inode)->lock); - delalloc_bytes = BTRFS_I(inode)->delalloc_bytes; - spin_unlock(&BTRFS_I(inode)->lock); - stat->blocks = (ALIGN(inode_get_bytes(inode), blocksize) + - ALIGN(delalloc_bytes, blocksize)) >> 9; - return 0; -} - -static int btrfs_rename_exchange(struct inode *old_dir, - struct dentry *old_dentry, - struct inode *new_dir, - struct dentry *new_dentry) -{ - struct btrfs_trans_handle *trans; - struct btrfs_root *root = BTRFS_I(old_dir)->root; - struct btrfs_root *dest = BTRFS_I(new_dir)->root; - struct inode *new_inode = new_dentry->d_inode; - struct inode *old_inode = old_dentry->d_inode; - struct timespec ctime = current_time(old_inode); - struct dentry *parent; - u64 old_ino = btrfs_ino(old_inode); - u64 new_ino = btrfs_ino(new_inode); - u64 old_idx = 0; - u64 new_idx = 0; - u64 root_objectid; - int ret; - bool root_log_pinned = false; - bool dest_log_pinned = false; - - /* we only allow rename subvolume link between subvolumes */ - if (old_ino != BTRFS_FIRST_FREE_OBJECTID && root != dest) - return -EXDEV; - - /* close the race window with snapshot create/destroy ioctl */ - if (old_ino == BTRFS_FIRST_FREE_OBJECTID) - down_read(&root->fs_info->subvol_sem); - if (new_ino == BTRFS_FIRST_FREE_OBJECTID) - down_read(&dest->fs_info->subvol_sem); - - /* - * We want to reserve the absolute worst case amount of items. So if - * both inodes are subvols and we need to unlink them then that would - * require 4 item modifications, but if they are both normal inodes it - * would require 5 item modifications, so we'll assume their normal - * inodes. So 5 * 2 is 10, plus 2 for the new links, so 12 total items - * should cover the worst case number of items we'll modify. - */ - trans = btrfs_start_transaction(root, 12); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out_notrans; - } - - /* - * We need to find a free sequence number both in the source and - * in the destination directory for the exchange. - */ - ret = btrfs_set_inode_index(new_dir, &old_idx); - if (ret) - goto out_fail; - ret = btrfs_set_inode_index(old_dir, &new_idx); - if (ret) - goto out_fail; - - BTRFS_I(old_inode)->dir_index = 0ULL; - BTRFS_I(new_inode)->dir_index = 0ULL; - - /* Reference for the source. */ - if (old_ino == BTRFS_FIRST_FREE_OBJECTID) { - /* force full log commit if subvolume involved. */ - btrfs_set_log_full_commit(root->fs_info, trans); - } else { - btrfs_pin_log_trans(root); - root_log_pinned = true; - ret = btrfs_insert_inode_ref(trans, dest, - new_dentry->d_name.name, - new_dentry->d_name.len, - old_ino, - btrfs_ino(new_dir), old_idx); - if (ret) - goto out_fail; - } - - /* And now for the dest. */ - if (new_ino == BTRFS_FIRST_FREE_OBJECTID) { - /* force full log commit if subvolume involved. */ - btrfs_set_log_full_commit(dest->fs_info, trans); - } else { - btrfs_pin_log_trans(dest); - dest_log_pinned = true; - ret = btrfs_insert_inode_ref(trans, root, - old_dentry->d_name.name, - old_dentry->d_name.len, - new_ino, - btrfs_ino(old_dir), new_idx); - if (ret) - goto out_fail; - } - - /* Update inode version and ctime/mtime. */ - inode_inc_iversion(old_dir); - inode_inc_iversion(new_dir); - inode_inc_iversion(old_inode); - inode_inc_iversion(new_inode); - old_dir->i_ctime = old_dir->i_mtime = ctime; - new_dir->i_ctime = new_dir->i_mtime = ctime; - old_inode->i_ctime = ctime; - new_inode->i_ctime = ctime; - - if (old_dentry->d_parent != new_dentry->d_parent) { - btrfs_record_unlink_dir(trans, old_dir, old_inode, 1); - btrfs_record_unlink_dir(trans, new_dir, new_inode, 1); - } - - /* src is a subvolume */ - if (old_ino == BTRFS_FIRST_FREE_OBJECTID) { - root_objectid = BTRFS_I(old_inode)->root->root_key.objectid; - ret = btrfs_unlink_subvol(trans, root, old_dir, - root_objectid, - old_dentry->d_name.name, - old_dentry->d_name.len); - } else { /* src is an inode */ - ret = __btrfs_unlink_inode(trans, root, old_dir, - old_dentry->d_inode, - old_dentry->d_name.name, - old_dentry->d_name.len); - if (!ret) - ret = btrfs_update_inode(trans, root, old_inode); - } - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out_fail; - } - - /* dest is a subvolume */ - if (new_ino == BTRFS_FIRST_FREE_OBJECTID) { - root_objectid = BTRFS_I(new_inode)->root->root_key.objectid; - ret = btrfs_unlink_subvol(trans, dest, new_dir, - root_objectid, - new_dentry->d_name.name, - new_dentry->d_name.len); - } else { /* dest is an inode */ - ret = __btrfs_unlink_inode(trans, dest, new_dir, - new_dentry->d_inode, - new_dentry->d_name.name, - new_dentry->d_name.len); - if (!ret) - ret = btrfs_update_inode(trans, dest, new_inode); - } - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out_fail; - } - - ret = btrfs_add_link(trans, new_dir, old_inode, - new_dentry->d_name.name, - new_dentry->d_name.len, 0, old_idx); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out_fail; - } - - ret = btrfs_add_link(trans, old_dir, new_inode, - old_dentry->d_name.name, - old_dentry->d_name.len, 0, new_idx); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out_fail; - } - - if (old_inode->i_nlink == 1) - BTRFS_I(old_inode)->dir_index = old_idx; - if (new_inode->i_nlink == 1) - BTRFS_I(new_inode)->dir_index = new_idx; - - if (root_log_pinned) { - parent = new_dentry->d_parent; - btrfs_log_new_name(trans, old_inode, old_dir, parent); - btrfs_end_log_trans(root); - root_log_pinned = false; - } - if (dest_log_pinned) { - parent = old_dentry->d_parent; - btrfs_log_new_name(trans, new_inode, new_dir, parent); - btrfs_end_log_trans(dest); - dest_log_pinned = false; - } -out_fail: - /* - * If we have pinned a log and an error happened, we unpin tasks - * trying to sync the log and force them to fallback to a transaction - * commit if the log currently contains any of the inodes involved in - * this rename operation (to ensure we do not persist a log with an - * inconsistent state for any of these inodes or leading to any - * inconsistencies when replayed). If the transaction was aborted, the - * abortion reason is propagated to userspace when attempting to commit - * the transaction. If the log does not contain any of these inodes, we - * allow the tasks to sync it. - */ - if (ret && (root_log_pinned || dest_log_pinned)) { - if (btrfs_inode_in_log(old_dir, root->fs_info->generation) || - btrfs_inode_in_log(new_dir, root->fs_info->generation) || - btrfs_inode_in_log(old_inode, root->fs_info->generation) || - (new_inode && - btrfs_inode_in_log(new_inode, root->fs_info->generation))) - btrfs_set_log_full_commit(root->fs_info, trans); - - if (root_log_pinned) { - btrfs_end_log_trans(root); - root_log_pinned = false; - } - if (dest_log_pinned) { - btrfs_end_log_trans(dest); - dest_log_pinned = false; - } - } - ret = btrfs_end_transaction(trans, root); -out_notrans: - if (new_ino == BTRFS_FIRST_FREE_OBJECTID) - up_read(&dest->fs_info->subvol_sem); - if (old_ino == BTRFS_FIRST_FREE_OBJECTID) - up_read(&root->fs_info->subvol_sem); - - return ret; -} - -static int btrfs_whiteout_for_rename(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *dir, - struct dentry *dentry) -{ - int ret; - struct inode *inode; - u64 objectid; - u64 index; - - ret = btrfs_find_free_ino(root, &objectid); - if (ret) - return ret; - - inode = btrfs_new_inode(trans, root, dir, - dentry->d_name.name, - dentry->d_name.len, - btrfs_ino(dir), - objectid, - S_IFCHR | WHITEOUT_MODE, - &index); - - if (IS_ERR(inode)) { - ret = PTR_ERR(inode); - return ret; - } - - inode->i_op = &btrfs_special_inode_operations; - init_special_inode(inode, inode->i_mode, - WHITEOUT_DEV); - - ret = btrfs_init_inode_security(trans, inode, dir, - &dentry->d_name); - if (ret) - goto out; - - ret = btrfs_add_nondir(trans, dir, dentry, - inode, 0, index); - if (ret) - goto out; - - ret = btrfs_update_inode(trans, root, inode); -out: - unlock_new_inode(inode); - if (ret) - inode_dec_link_count(inode); - iput(inode); - - return ret; -} - -static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry, - unsigned int flags) -{ - struct btrfs_trans_handle *trans; - unsigned int trans_num_items; - struct btrfs_root *root = BTRFS_I(old_dir)->root; - struct btrfs_root *dest = BTRFS_I(new_dir)->root; - struct inode *new_inode = d_inode(new_dentry); - struct inode *old_inode = d_inode(old_dentry); - u64 index = 0; - u64 root_objectid; - int ret; - u64 old_ino = btrfs_ino(old_inode); - bool log_pinned = false; - - if (btrfs_ino(new_dir) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID) - return -EPERM; - - /* we only allow rename subvolume link between subvolumes */ - if (old_ino != BTRFS_FIRST_FREE_OBJECTID && root != dest) - return -EXDEV; - - if (old_ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID || - (new_inode && btrfs_ino(new_inode) == BTRFS_FIRST_FREE_OBJECTID)) - return -ENOTEMPTY; - - if (S_ISDIR(old_inode->i_mode) && new_inode && - new_inode->i_size > BTRFS_EMPTY_DIR_SIZE) - return -ENOTEMPTY; - - - /* check for collisions, even if the name isn't there */ - ret = btrfs_check_dir_item_collision(dest, new_dir->i_ino, - new_dentry->d_name.name, - new_dentry->d_name.len); - - if (ret) { - if (ret == -EEXIST) { - /* we shouldn't get - * eexist without a new_inode */ - if (WARN_ON(!new_inode)) { - return ret; - } - } else { - /* maybe -EOVERFLOW */ - return ret; - } - } - ret = 0; - - /* - * we're using rename to replace one file with another. Start IO on it - * now so we don't add too much work to the end of the transaction - */ - if (new_inode && S_ISREG(old_inode->i_mode) && new_inode->i_size) - filemap_flush(old_inode->i_mapping); - - /* close the racy window with snapshot create/destroy ioctl */ - if (old_ino == BTRFS_FIRST_FREE_OBJECTID) - down_read(&root->fs_info->subvol_sem); - /* - * We want to reserve the absolute worst case amount of items. So if - * both inodes are subvols and we need to unlink them then that would - * require 4 item modifications, but if they are both normal inodes it - * would require 5 item modifications, so we'll assume they are normal - * inodes. So 5 * 2 is 10, plus 1 for the new link, so 11 total items - * should cover the worst case number of items we'll modify. - * If our rename has the whiteout flag, we need more 5 units for the - * new inode (1 inode item, 1 inode ref, 2 dir items and 1 xattr item - * when selinux is enabled). - */ - trans_num_items = 11; - if (flags & RENAME_WHITEOUT) - trans_num_items += 5; - trans = btrfs_start_transaction(root, trans_num_items); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out_notrans; - } - - if (dest != root) - btrfs_record_root_in_trans(trans, dest); - - ret = btrfs_set_inode_index(new_dir, &index); - if (ret) - goto out_fail; - - BTRFS_I(old_inode)->dir_index = 0ULL; - if (unlikely(old_ino == BTRFS_FIRST_FREE_OBJECTID)) { - /* force full log commit if subvolume involved. */ - btrfs_set_log_full_commit(root->fs_info, trans); - } else { - btrfs_pin_log_trans(root); - log_pinned = true; - ret = btrfs_insert_inode_ref(trans, dest, - new_dentry->d_name.name, - new_dentry->d_name.len, - old_ino, - btrfs_ino(new_dir), index); - if (ret) - goto out_fail; - } - - inode_inc_iversion(old_dir); - inode_inc_iversion(new_dir); - inode_inc_iversion(old_inode); - old_dir->i_ctime = old_dir->i_mtime = - new_dir->i_ctime = new_dir->i_mtime = - old_inode->i_ctime = current_time(old_dir); - - if (old_dentry->d_parent != new_dentry->d_parent) - btrfs_record_unlink_dir(trans, old_dir, old_inode, 1); - - if (unlikely(old_ino == BTRFS_FIRST_FREE_OBJECTID)) { - root_objectid = BTRFS_I(old_inode)->root->root_key.objectid; - ret = btrfs_unlink_subvol(trans, root, old_dir, root_objectid, - old_dentry->d_name.name, - old_dentry->d_name.len); - } else { - ret = __btrfs_unlink_inode(trans, root, old_dir, - d_inode(old_dentry), - old_dentry->d_name.name, - old_dentry->d_name.len); - if (!ret) - ret = btrfs_update_inode(trans, root, old_inode); - } - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out_fail; - } - - if (new_inode) { - inode_inc_iversion(new_inode); - new_inode->i_ctime = current_time(new_inode); - if (unlikely(btrfs_ino(new_inode) == - BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) { - root_objectid = BTRFS_I(new_inode)->location.objectid; - ret = btrfs_unlink_subvol(trans, dest, new_dir, - root_objectid, - new_dentry->d_name.name, - new_dentry->d_name.len); - BUG_ON(new_inode->i_nlink == 0); - } else { - ret = btrfs_unlink_inode(trans, dest, new_dir, - d_inode(new_dentry), - new_dentry->d_name.name, - new_dentry->d_name.len); - } - if (!ret && new_inode->i_nlink == 0) - ret = btrfs_orphan_add(trans, d_inode(new_dentry)); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out_fail; - } - } - - ret = btrfs_add_link(trans, new_dir, old_inode, - new_dentry->d_name.name, - new_dentry->d_name.len, 0, index); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out_fail; - } - - if (old_inode->i_nlink == 1) - BTRFS_I(old_inode)->dir_index = index; - - if (log_pinned) { - struct dentry *parent = new_dentry->d_parent; - - btrfs_log_new_name(trans, old_inode, old_dir, parent); - btrfs_end_log_trans(root); - log_pinned = false; - } - - if (flags & RENAME_WHITEOUT) { - ret = btrfs_whiteout_for_rename(trans, root, old_dir, - old_dentry); - - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out_fail; - } - } -out_fail: - /* - * If we have pinned the log and an error happened, we unpin tasks - * trying to sync the log and force them to fallback to a transaction - * commit if the log currently contains any of the inodes involved in - * this rename operation (to ensure we do not persist a log with an - * inconsistent state for any of these inodes or leading to any - * inconsistencies when replayed). If the transaction was aborted, the - * abortion reason is propagated to userspace when attempting to commit - * the transaction. If the log does not contain any of these inodes, we - * allow the tasks to sync it. - */ - if (ret && log_pinned) { - if (btrfs_inode_in_log(old_dir, root->fs_info->generation) || - btrfs_inode_in_log(new_dir, root->fs_info->generation) || - btrfs_inode_in_log(old_inode, root->fs_info->generation) || - (new_inode && - btrfs_inode_in_log(new_inode, root->fs_info->generation))) - btrfs_set_log_full_commit(root->fs_info, trans); - - btrfs_end_log_trans(root); - log_pinned = false; - } - btrfs_end_transaction(trans, root); -out_notrans: - if (old_ino == BTRFS_FIRST_FREE_OBJECTID) - up_read(&root->fs_info->subvol_sem); - - return ret; -} - -static int btrfs_rename2(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry, - unsigned int flags) -{ - if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) - return -EINVAL; - - if (flags & RENAME_EXCHANGE) - return btrfs_rename_exchange(old_dir, old_dentry, new_dir, - new_dentry); - - return btrfs_rename(old_dir, old_dentry, new_dir, new_dentry, flags); -} - -static void btrfs_run_delalloc_work(struct btrfs_work *work) -{ - struct btrfs_delalloc_work *delalloc_work; - struct inode *inode; - - delalloc_work = container_of(work, struct btrfs_delalloc_work, - work); - inode = delalloc_work->inode; - filemap_flush(inode->i_mapping); - if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT, - &BTRFS_I(inode)->runtime_flags)) - filemap_flush(inode->i_mapping); - - if (delalloc_work->delay_iput) - btrfs_add_delayed_iput(inode); - else - iput(inode); - complete(&delalloc_work->completion); -} - -struct btrfs_delalloc_work *btrfs_alloc_delalloc_work(struct inode *inode, - int delay_iput) -{ - struct btrfs_delalloc_work *work; - - work = kmalloc(sizeof(*work), GFP_NOFS); - if (!work) - return NULL; - - init_completion(&work->completion); - INIT_LIST_HEAD(&work->list); - work->inode = inode; - work->delay_iput = delay_iput; - WARN_ON_ONCE(!inode); - btrfs_init_work(&work->work, btrfs_flush_delalloc_helper, - btrfs_run_delalloc_work, NULL, NULL); - - return work; -} - -void btrfs_wait_and_free_delalloc_work(struct btrfs_delalloc_work *work) -{ - wait_for_completion(&work->completion); - kfree(work); -} - -/* - * some fairly slow code that needs optimization. This walks the list - * of all the inodes with pending delalloc and forces them to disk. - */ -static int __start_delalloc_inodes(struct btrfs_root *root, int delay_iput, - int nr) -{ - struct btrfs_inode *binode; - struct inode *inode; - struct btrfs_delalloc_work *work, *next; - struct list_head works; - struct list_head splice; - int ret = 0; - - INIT_LIST_HEAD(&works); - INIT_LIST_HEAD(&splice); - - mutex_lock(&root->delalloc_mutex); - spin_lock(&root->delalloc_lock); - list_splice_init(&root->delalloc_inodes, &splice); - while (!list_empty(&splice)) { - binode = list_entry(splice.next, struct btrfs_inode, - delalloc_inodes); - - list_move_tail(&binode->delalloc_inodes, - &root->delalloc_inodes); - inode = igrab(&binode->vfs_inode); - if (!inode) { - cond_resched_lock(&root->delalloc_lock); - continue; - } - spin_unlock(&root->delalloc_lock); - - work = btrfs_alloc_delalloc_work(inode, delay_iput); - if (!work) { - if (delay_iput) - btrfs_add_delayed_iput(inode); - else - iput(inode); - ret = -ENOMEM; - goto out; - } - list_add_tail(&work->list, &works); - btrfs_queue_work(root->fs_info->flush_workers, - &work->work); - ret++; - if (nr != -1 && ret >= nr) - goto out; - cond_resched(); - spin_lock(&root->delalloc_lock); - } - spin_unlock(&root->delalloc_lock); - -out: - list_for_each_entry_safe(work, next, &works, list) { - list_del_init(&work->list); - btrfs_wait_and_free_delalloc_work(work); - } - - if (!list_empty_careful(&splice)) { - spin_lock(&root->delalloc_lock); - list_splice_tail(&splice, &root->delalloc_inodes); - spin_unlock(&root->delalloc_lock); - } - mutex_unlock(&root->delalloc_mutex); - return ret; -} - -int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput) -{ - int ret; - - if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state)) - return -EROFS; - - ret = __start_delalloc_inodes(root, delay_iput, -1); - if (ret > 0) - ret = 0; - /* - * the filemap_flush will queue IO into the worker threads, but - * we have to make sure the IO is actually started and that - * ordered extents get created before we return - */ - atomic_inc(&root->fs_info->async_submit_draining); - while (atomic_read(&root->fs_info->nr_async_submits) || - atomic_read(&root->fs_info->async_delalloc_pages)) { - wait_event(root->fs_info->async_submit_wait, - (atomic_read(&root->fs_info->nr_async_submits) == 0 && - atomic_read(&root->fs_info->async_delalloc_pages) == 0)); - } - atomic_dec(&root->fs_info->async_submit_draining); - return ret; -} - -int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput, - int nr) -{ - struct btrfs_root *root; - struct list_head splice; - int ret; - - if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) - return -EROFS; - - INIT_LIST_HEAD(&splice); - - mutex_lock(&fs_info->delalloc_root_mutex); - spin_lock(&fs_info->delalloc_root_lock); - list_splice_init(&fs_info->delalloc_roots, &splice); - while (!list_empty(&splice) && nr) { - root = list_first_entry(&splice, struct btrfs_root, - delalloc_root); - root = btrfs_grab_fs_root(root); - BUG_ON(!root); - list_move_tail(&root->delalloc_root, - &fs_info->delalloc_roots); - spin_unlock(&fs_info->delalloc_root_lock); - - ret = __start_delalloc_inodes(root, delay_iput, nr); - btrfs_put_fs_root(root); - if (ret < 0) - goto out; - - if (nr != -1) { - nr -= ret; - WARN_ON(nr < 0); - } - spin_lock(&fs_info->delalloc_root_lock); - } - spin_unlock(&fs_info->delalloc_root_lock); - - ret = 0; - atomic_inc(&fs_info->async_submit_draining); - while (atomic_read(&fs_info->nr_async_submits) || - atomic_read(&fs_info->async_delalloc_pages)) { - wait_event(fs_info->async_submit_wait, - (atomic_read(&fs_info->nr_async_submits) == 0 && - atomic_read(&fs_info->async_delalloc_pages) == 0)); - } - atomic_dec(&fs_info->async_submit_draining); -out: - if (!list_empty_careful(&splice)) { - spin_lock(&fs_info->delalloc_root_lock); - list_splice_tail(&splice, &fs_info->delalloc_roots); - spin_unlock(&fs_info->delalloc_root_lock); - } - mutex_unlock(&fs_info->delalloc_root_mutex); - return ret; -} - -static int btrfs_symlink(struct inode *dir, struct dentry *dentry, - const char *symname) -{ - struct btrfs_trans_handle *trans; - struct btrfs_root *root = BTRFS_I(dir)->root; - struct btrfs_path *path; - struct btrfs_key key; - struct inode *inode = NULL; - int err; - int drop_inode = 0; - u64 objectid; - u64 index = 0; - int name_len; - int datasize; - unsigned long ptr; - struct btrfs_file_extent_item *ei; - struct extent_buffer *leaf; - - name_len = strlen(symname); - if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(root)) - return -ENAMETOOLONG; - - /* - * 2 items for inode item and ref - * 2 items for dir items - * 1 item for updating parent inode item - * 1 item for the inline extent item - * 1 item for xattr if selinux is on - */ - trans = btrfs_start_transaction(root, 7); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - err = btrfs_find_free_ino(root, &objectid); - if (err) - goto out_unlock; - - inode = btrfs_new_inode(trans, root, dir, dentry->d_name.name, - dentry->d_name.len, btrfs_ino(dir), objectid, - S_IFLNK|S_IRWXUGO, &index); - if (IS_ERR(inode)) { - err = PTR_ERR(inode); - goto out_unlock; - } - - /* - * If the active LSM wants to access the inode during - * d_instantiate it needs these. Smack checks to see - * if the filesystem supports xattrs by looking at the - * ops vector. - */ - inode->i_fop = &btrfs_file_operations; - inode->i_op = &btrfs_file_inode_operations; - inode->i_mapping->a_ops = &btrfs_aops; - BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; - - err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name); - if (err) - goto out_unlock_inode; - - path = btrfs_alloc_path(); - if (!path) { - err = -ENOMEM; - goto out_unlock_inode; - } - key.objectid = btrfs_ino(inode); - key.offset = 0; - key.type = BTRFS_EXTENT_DATA_KEY; - datasize = btrfs_file_extent_calc_inline_size(name_len); - err = btrfs_insert_empty_item(trans, root, path, &key, - datasize); - if (err) { - btrfs_free_path(path); - goto out_unlock_inode; - } - leaf = path->nodes[0]; - ei = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - btrfs_set_file_extent_generation(leaf, ei, trans->transid); - btrfs_set_file_extent_type(leaf, ei, - BTRFS_FILE_EXTENT_INLINE); - btrfs_set_file_extent_encryption(leaf, ei, 0); - btrfs_set_file_extent_compression(leaf, ei, 0); - btrfs_set_file_extent_other_encoding(leaf, ei, 0); - btrfs_set_file_extent_ram_bytes(leaf, ei, name_len); - - ptr = btrfs_file_extent_inline_start(ei); - write_extent_buffer(leaf, symname, ptr, name_len); - btrfs_mark_buffer_dirty(leaf); - btrfs_free_path(path); - - inode->i_op = &btrfs_symlink_inode_operations; - inode_nohighmem(inode); - inode->i_mapping->a_ops = &btrfs_symlink_aops; - inode_set_bytes(inode, name_len); - btrfs_i_size_write(inode, name_len); - err = btrfs_update_inode(trans, root, inode); - /* - * Last step, add directory indexes for our symlink inode. This is the - * last step to avoid extra cleanup of these indexes if an error happens - * elsewhere above. - */ - if (!err) - err = btrfs_add_nondir(trans, dir, dentry, inode, 0, index); - if (err) { - drop_inode = 1; - goto out_unlock_inode; - } - - unlock_new_inode(inode); - d_instantiate(dentry, inode); - -out_unlock: - btrfs_end_transaction(trans, root); - if (drop_inode) { - inode_dec_link_count(inode); - iput(inode); - } - btrfs_btree_balance_dirty(root); - return err; - -out_unlock_inode: - drop_inode = 1; - unlock_new_inode(inode); - goto out_unlock; -} - -static int __btrfs_prealloc_file_range(struct inode *inode, int mode, - u64 start, u64 num_bytes, u64 min_size, - loff_t actual_len, u64 *alloc_hint, - struct btrfs_trans_handle *trans) -{ - struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; - struct extent_map *em; - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_key ins; - u64 cur_offset = start; - u64 i_size; - u64 cur_bytes; - u64 last_alloc = (u64)-1; - int ret = 0; - bool own_trans = true; - u64 end = start + num_bytes - 1; - - if (trans) - own_trans = false; - while (num_bytes > 0) { - if (own_trans) { - trans = btrfs_start_transaction(root, 3); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - break; - } - } - - cur_bytes = min_t(u64, num_bytes, SZ_256M); - cur_bytes = max(cur_bytes, min_size); - /* - * If we are severely fragmented we could end up with really - * small allocations, so if the allocator is returning small - * chunks lets make its job easier by only searching for those - * sized chunks. - */ - cur_bytes = min(cur_bytes, last_alloc); - ret = btrfs_reserve_extent(root, cur_bytes, cur_bytes, - min_size, 0, *alloc_hint, &ins, 1, 0); - if (ret) { - if (own_trans) - btrfs_end_transaction(trans, root); - break; - } - btrfs_dec_block_group_reservations(root->fs_info, ins.objectid); - - last_alloc = ins.offset; - ret = insert_reserved_file_extent(trans, inode, - cur_offset, ins.objectid, - ins.offset, ins.offset, - ins.offset, 0, 0, 0, - BTRFS_FILE_EXTENT_PREALLOC); - if (ret) { - btrfs_free_reserved_extent(root, ins.objectid, - ins.offset, 0); - btrfs_abort_transaction(trans, ret); - if (own_trans) - btrfs_end_transaction(trans, root); - break; - } - - btrfs_drop_extent_cache(inode, cur_offset, - cur_offset + ins.offset -1, 0); - - em = alloc_extent_map(); - if (!em) { - set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, - &BTRFS_I(inode)->runtime_flags); - goto next; - } - - em->start = cur_offset; - em->orig_start = cur_offset; - em->len = ins.offset; - em->block_start = ins.objectid; - em->block_len = ins.offset; - em->orig_block_len = ins.offset; - em->ram_bytes = ins.offset; - em->bdev = root->fs_info->fs_devices->latest_bdev; - set_bit(EXTENT_FLAG_PREALLOC, &em->flags); - em->generation = trans->transid; - - while (1) { - write_lock(&em_tree->lock); - ret = add_extent_mapping(em_tree, em, 1); - write_unlock(&em_tree->lock); - if (ret != -EEXIST) - break; - btrfs_drop_extent_cache(inode, cur_offset, - cur_offset + ins.offset - 1, - 0); - } - free_extent_map(em); -next: - num_bytes -= ins.offset; - cur_offset += ins.offset; - *alloc_hint = ins.objectid + ins.offset; - - inode_inc_iversion(inode); - inode->i_ctime = current_time(inode); - BTRFS_I(inode)->flags |= BTRFS_INODE_PREALLOC; - if (!(mode & FALLOC_FL_KEEP_SIZE) && - (actual_len > inode->i_size) && - (cur_offset > inode->i_size)) { - if (cur_offset > actual_len) - i_size = actual_len; - else - i_size = cur_offset; - i_size_write(inode, i_size); - btrfs_ordered_update_i_size(inode, i_size, NULL); - } - - ret = btrfs_update_inode(trans, root, inode); - - if (ret) { - btrfs_abort_transaction(trans, ret); - if (own_trans) - btrfs_end_transaction(trans, root); - break; - } - - if (own_trans) - btrfs_end_transaction(trans, root); - } - if (cur_offset < end) - btrfs_free_reserved_data_space(inode, cur_offset, - end - cur_offset + 1); - return ret; -} - -int btrfs_prealloc_file_range(struct inode *inode, int mode, - u64 start, u64 num_bytes, u64 min_size, - loff_t actual_len, u64 *alloc_hint) -{ - return __btrfs_prealloc_file_range(inode, mode, start, num_bytes, - min_size, actual_len, alloc_hint, - NULL); -} - -int btrfs_prealloc_file_range_trans(struct inode *inode, - struct btrfs_trans_handle *trans, int mode, - u64 start, u64 num_bytes, u64 min_size, - loff_t actual_len, u64 *alloc_hint) -{ - return __btrfs_prealloc_file_range(inode, mode, start, num_bytes, - min_size, actual_len, alloc_hint, trans); -} - -static int btrfs_set_page_dirty(struct page *page) -{ - return __set_page_dirty_nobuffers(page); -} - -static int btrfs_permission(struct inode *inode, int mask) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - umode_t mode = inode->i_mode; - - if (mask & MAY_WRITE && - (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) { - if (btrfs_root_readonly(root)) - return -EROFS; - if (BTRFS_I(inode)->flags & BTRFS_INODE_READONLY) - return -EACCES; - } - return generic_permission(inode, mask); -} - -static int btrfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) -{ - struct btrfs_trans_handle *trans; - struct btrfs_root *root = BTRFS_I(dir)->root; - struct inode *inode = NULL; - u64 objectid; - u64 index; - int ret = 0; - - /* - * 5 units required for adding orphan entry - */ - trans = btrfs_start_transaction(root, 5); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - ret = btrfs_find_free_ino(root, &objectid); - if (ret) - goto out; - - inode = btrfs_new_inode(trans, root, dir, NULL, 0, - btrfs_ino(dir), objectid, mode, &index); - if (IS_ERR(inode)) { - ret = PTR_ERR(inode); - inode = NULL; - goto out; - } - - inode->i_fop = &btrfs_file_operations; - inode->i_op = &btrfs_file_inode_operations; - - inode->i_mapping->a_ops = &btrfs_aops; - BTRFS_I(inode)->io_tree.ops = &btrfs_extent_io_ops; - - ret = btrfs_init_inode_security(trans, inode, dir, NULL); - if (ret) - goto out_inode; - - ret = btrfs_update_inode(trans, root, inode); - if (ret) - goto out_inode; - ret = btrfs_orphan_add(trans, inode); - if (ret) - goto out_inode; - - /* - * We set number of links to 0 in btrfs_new_inode(), and here we set - * it to 1 because d_tmpfile() will issue a warning if the count is 0, - * through: - * - * d_tmpfile() -> inode_dec_link_count() -> drop_nlink() - */ - set_nlink(inode, 1); - unlock_new_inode(inode); - d_tmpfile(dentry, inode); - mark_inode_dirty(inode); - -out: - btrfs_end_transaction(trans, root); - if (ret) - iput(inode); - btrfs_balance_delayed_items(root); - btrfs_btree_balance_dirty(root); - return ret; - -out_inode: - unlock_new_inode(inode); - goto out; - -} - -static const struct inode_operations btrfs_dir_inode_operations = { - .getattr = btrfs_getattr, - .lookup = btrfs_lookup, - .create = btrfs_create, - .unlink = btrfs_unlink, - .link = btrfs_link, - .mkdir = btrfs_mkdir, - .rmdir = btrfs_rmdir, - .rename = btrfs_rename2, - .symlink = btrfs_symlink, - .setattr = btrfs_setattr, - .mknod = btrfs_mknod, - .listxattr = btrfs_listxattr, - .permission = btrfs_permission, - .get_acl = btrfs_get_acl, - .set_acl = btrfs_set_acl, - .update_time = btrfs_update_time, - .tmpfile = btrfs_tmpfile, -}; -static const struct inode_operations btrfs_dir_ro_inode_operations = { - .lookup = btrfs_lookup, - .permission = btrfs_permission, - .get_acl = btrfs_get_acl, - .set_acl = btrfs_set_acl, - .update_time = btrfs_update_time, -}; - -static const struct file_operations btrfs_dir_file_operations = { - .llseek = generic_file_llseek, - .read = generic_read_dir, - .iterate_shared = btrfs_real_readdir, - .unlocked_ioctl = btrfs_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = btrfs_compat_ioctl, -#endif - .release = btrfs_release_file, - .fsync = btrfs_sync_file, -}; - -static const struct extent_io_ops btrfs_extent_io_ops = { - .fill_delalloc = run_delalloc_range, - .submit_bio_hook = btrfs_submit_bio_hook, - .merge_bio_hook = btrfs_merge_bio_hook, - .readpage_end_io_hook = btrfs_readpage_end_io_hook, - .writepage_end_io_hook = btrfs_writepage_end_io_hook, - .writepage_start_hook = btrfs_writepage_start_hook, - .set_bit_hook = btrfs_set_bit_hook, - .clear_bit_hook = btrfs_clear_bit_hook, - .merge_extent_hook = btrfs_merge_extent_hook, - .split_extent_hook = btrfs_split_extent_hook, -}; - -/* - * btrfs doesn't support the bmap operation because swapfiles - * use bmap to make a mapping of extents in the file. They assume - * these extents won't change over the life of the file and they - * use the bmap result to do IO directly to the drive. - * - * the btrfs bmap call would return logical addresses that aren't - * suitable for IO and they also will change frequently as COW - * operations happen. So, swapfile + btrfs == corruption. - * - * For now we're avoiding this by dropping bmap. - */ -static const struct address_space_operations btrfs_aops = { - .readpage = btrfs_readpage, - .writepage = btrfs_writepage, - .writepages = btrfs_writepages, - .readpages = btrfs_readpages, - .direct_IO = btrfs_direct_IO, - .invalidatepage = btrfs_invalidatepage, - .releasepage = btrfs_releasepage, - .set_page_dirty = btrfs_set_page_dirty, - .error_remove_page = generic_error_remove_page, -}; - -static const struct address_space_operations btrfs_symlink_aops = { - .readpage = btrfs_readpage, - .writepage = btrfs_writepage, - .invalidatepage = btrfs_invalidatepage, - .releasepage = btrfs_releasepage, -}; - -static const struct inode_operations btrfs_file_inode_operations = { - .getattr = btrfs_getattr, - .setattr = btrfs_setattr, - .listxattr = btrfs_listxattr, - .permission = btrfs_permission, - .fiemap = btrfs_fiemap, - .get_acl = btrfs_get_acl, - .set_acl = btrfs_set_acl, - .update_time = btrfs_update_time, -}; -static const struct inode_operations btrfs_special_inode_operations = { - .getattr = btrfs_getattr, - .setattr = btrfs_setattr, - .permission = btrfs_permission, - .listxattr = btrfs_listxattr, - .get_acl = btrfs_get_acl, - .set_acl = btrfs_set_acl, - .update_time = btrfs_update_time, -}; -static const struct inode_operations btrfs_symlink_inode_operations = { - .readlink = generic_readlink, - .get_link = page_get_link, - .getattr = btrfs_getattr, - .setattr = btrfs_setattr, - .permission = btrfs_permission, - .listxattr = btrfs_listxattr, - .update_time = btrfs_update_time, -}; - -const struct dentry_operations btrfs_dentry_operations = { - .d_delete = btrfs_dentry_delete, - .d_release = btrfs_dentry_release, -}; diff --git a/src/linux/fs/btrfs/ioctl.c b/src/linux/fs/btrfs/ioctl.c deleted file mode 100644 index 7acbd2c..0000000 --- a/src/linux/fs/btrfs/ioctl.c +++ /dev/null @@ -1,5667 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#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 -#include "ctree.h" -#include "disk-io.h" -#include "transaction.h" -#include "btrfs_inode.h" -#include "print-tree.h" -#include "volumes.h" -#include "locking.h" -#include "inode-map.h" -#include "backref.h" -#include "rcu-string.h" -#include "send.h" -#include "dev-replace.h" -#include "props.h" -#include "sysfs.h" -#include "qgroup.h" -#include "tree-log.h" -#include "compression.h" - -#ifdef CONFIG_64BIT -/* If we have a 32-bit userspace and 64-bit kernel, then the UAPI - * structures are incorrect, as the timespec structure from userspace - * is 4 bytes too small. We define these alternatives here to teach - * the kernel about the 32-bit struct packing. - */ -struct btrfs_ioctl_timespec_32 { - __u64 sec; - __u32 nsec; -} __attribute__ ((__packed__)); - -struct btrfs_ioctl_received_subvol_args_32 { - char uuid[BTRFS_UUID_SIZE]; /* in */ - __u64 stransid; /* in */ - __u64 rtransid; /* out */ - struct btrfs_ioctl_timespec_32 stime; /* in */ - struct btrfs_ioctl_timespec_32 rtime; /* out */ - __u64 flags; /* in */ - __u64 reserved[16]; /* in */ -} __attribute__ ((__packed__)); - -#define BTRFS_IOC_SET_RECEIVED_SUBVOL_32 _IOWR(BTRFS_IOCTL_MAGIC, 37, \ - struct btrfs_ioctl_received_subvol_args_32) -#endif - - -static int btrfs_clone(struct inode *src, struct inode *inode, - u64 off, u64 olen, u64 olen_aligned, u64 destoff, - int no_time_update); - -/* Mask out flags that are inappropriate for the given type of inode. */ -static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags) -{ - if (S_ISDIR(mode)) - return flags; - else if (S_ISREG(mode)) - return flags & ~FS_DIRSYNC_FL; - else - return flags & (FS_NODUMP_FL | FS_NOATIME_FL); -} - -/* - * Export inode flags to the format expected by the FS_IOC_GETFLAGS ioctl. - */ -static unsigned int btrfs_flags_to_ioctl(unsigned int flags) -{ - unsigned int iflags = 0; - - if (flags & BTRFS_INODE_SYNC) - iflags |= FS_SYNC_FL; - if (flags & BTRFS_INODE_IMMUTABLE) - iflags |= FS_IMMUTABLE_FL; - if (flags & BTRFS_INODE_APPEND) - iflags |= FS_APPEND_FL; - if (flags & BTRFS_INODE_NODUMP) - iflags |= FS_NODUMP_FL; - if (flags & BTRFS_INODE_NOATIME) - iflags |= FS_NOATIME_FL; - if (flags & BTRFS_INODE_DIRSYNC) - iflags |= FS_DIRSYNC_FL; - if (flags & BTRFS_INODE_NODATACOW) - iflags |= FS_NOCOW_FL; - - if (flags & BTRFS_INODE_NOCOMPRESS) - iflags |= FS_NOCOMP_FL; - else if (flags & BTRFS_INODE_COMPRESS) - iflags |= FS_COMPR_FL; - - return iflags; -} - -/* - * Update inode->i_flags based on the btrfs internal flags. - */ -void btrfs_update_iflags(struct inode *inode) -{ - struct btrfs_inode *ip = BTRFS_I(inode); - unsigned int new_fl = 0; - - if (ip->flags & BTRFS_INODE_SYNC) - new_fl |= S_SYNC; - if (ip->flags & BTRFS_INODE_IMMUTABLE) - new_fl |= S_IMMUTABLE; - if (ip->flags & BTRFS_INODE_APPEND) - new_fl |= S_APPEND; - if (ip->flags & BTRFS_INODE_NOATIME) - new_fl |= S_NOATIME; - if (ip->flags & BTRFS_INODE_DIRSYNC) - new_fl |= S_DIRSYNC; - - set_mask_bits(&inode->i_flags, - S_SYNC | S_APPEND | S_IMMUTABLE | S_NOATIME | S_DIRSYNC, - new_fl); -} - -/* - * Inherit flags from the parent inode. - * - * Currently only the compression flags and the cow flags are inherited. - */ -void btrfs_inherit_iflags(struct inode *inode, struct inode *dir) -{ - unsigned int flags; - - if (!dir) - return; - - flags = BTRFS_I(dir)->flags; - - if (flags & BTRFS_INODE_NOCOMPRESS) { - BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS; - BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS; - } else if (flags & BTRFS_INODE_COMPRESS) { - BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS; - BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS; - } - - if (flags & BTRFS_INODE_NODATACOW) { - BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW; - if (S_ISREG(inode->i_mode)) - BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM; - } - - btrfs_update_iflags(inode); -} - -static int btrfs_ioctl_getflags(struct file *file, void __user *arg) -{ - struct btrfs_inode *ip = BTRFS_I(file_inode(file)); - unsigned int flags = btrfs_flags_to_ioctl(ip->flags); - - if (copy_to_user(arg, &flags, sizeof(flags))) - return -EFAULT; - return 0; -} - -static int check_flags(unsigned int flags) -{ - if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ - FS_NOATIME_FL | FS_NODUMP_FL | \ - FS_SYNC_FL | FS_DIRSYNC_FL | \ - FS_NOCOMP_FL | FS_COMPR_FL | - FS_NOCOW_FL)) - return -EOPNOTSUPP; - - if ((flags & FS_NOCOMP_FL) && (flags & FS_COMPR_FL)) - return -EINVAL; - - return 0; -} - -static int btrfs_ioctl_setflags(struct file *file, void __user *arg) -{ - struct inode *inode = file_inode(file); - struct btrfs_inode *ip = BTRFS_I(inode); - struct btrfs_root *root = ip->root; - struct btrfs_trans_handle *trans; - unsigned int flags, oldflags; - int ret; - u64 ip_oldflags; - unsigned int i_oldflags; - umode_t mode; - - if (!inode_owner_or_capable(inode)) - return -EPERM; - - if (btrfs_root_readonly(root)) - return -EROFS; - - if (copy_from_user(&flags, arg, sizeof(flags))) - return -EFAULT; - - ret = check_flags(flags); - if (ret) - return ret; - - ret = mnt_want_write_file(file); - if (ret) - return ret; - - inode_lock(inode); - - ip_oldflags = ip->flags; - i_oldflags = inode->i_flags; - mode = inode->i_mode; - - flags = btrfs_mask_flags(inode->i_mode, flags); - oldflags = btrfs_flags_to_ioctl(ip->flags); - if ((flags ^ oldflags) & (FS_APPEND_FL | FS_IMMUTABLE_FL)) { - if (!capable(CAP_LINUX_IMMUTABLE)) { - ret = -EPERM; - goto out_unlock; - } - } - - if (flags & FS_SYNC_FL) - ip->flags |= BTRFS_INODE_SYNC; - else - ip->flags &= ~BTRFS_INODE_SYNC; - if (flags & FS_IMMUTABLE_FL) - ip->flags |= BTRFS_INODE_IMMUTABLE; - else - ip->flags &= ~BTRFS_INODE_IMMUTABLE; - if (flags & FS_APPEND_FL) - ip->flags |= BTRFS_INODE_APPEND; - else - ip->flags &= ~BTRFS_INODE_APPEND; - if (flags & FS_NODUMP_FL) - ip->flags |= BTRFS_INODE_NODUMP; - else - ip->flags &= ~BTRFS_INODE_NODUMP; - if (flags & FS_NOATIME_FL) - ip->flags |= BTRFS_INODE_NOATIME; - else - ip->flags &= ~BTRFS_INODE_NOATIME; - if (flags & FS_DIRSYNC_FL) - ip->flags |= BTRFS_INODE_DIRSYNC; - else - ip->flags &= ~BTRFS_INODE_DIRSYNC; - if (flags & FS_NOCOW_FL) { - if (S_ISREG(mode)) { - /* - * It's safe to turn csums off here, no extents exist. - * Otherwise we want the flag to reflect the real COW - * status of the file and will not set it. - */ - if (inode->i_size == 0) - ip->flags |= BTRFS_INODE_NODATACOW - | BTRFS_INODE_NODATASUM; - } else { - ip->flags |= BTRFS_INODE_NODATACOW; - } - } else { - /* - * Revert back under same assumptions as above - */ - if (S_ISREG(mode)) { - if (inode->i_size == 0) - ip->flags &= ~(BTRFS_INODE_NODATACOW - | BTRFS_INODE_NODATASUM); - } else { - ip->flags &= ~BTRFS_INODE_NODATACOW; - } - } - - /* - * The COMPRESS flag can only be changed by users, while the NOCOMPRESS - * flag may be changed automatically if compression code won't make - * things smaller. - */ - if (flags & FS_NOCOMP_FL) { - ip->flags &= ~BTRFS_INODE_COMPRESS; - ip->flags |= BTRFS_INODE_NOCOMPRESS; - - ret = btrfs_set_prop(inode, "btrfs.compression", NULL, 0, 0); - if (ret && ret != -ENODATA) - goto out_drop; - } else if (flags & FS_COMPR_FL) { - const char *comp; - - ip->flags |= BTRFS_INODE_COMPRESS; - ip->flags &= ~BTRFS_INODE_NOCOMPRESS; - - if (root->fs_info->compress_type == BTRFS_COMPRESS_LZO) - comp = "lzo"; - else - comp = "zlib"; - ret = btrfs_set_prop(inode, "btrfs.compression", - comp, strlen(comp), 0); - if (ret) - goto out_drop; - - } else { - ret = btrfs_set_prop(inode, "btrfs.compression", NULL, 0, 0); - if (ret && ret != -ENODATA) - goto out_drop; - ip->flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS); - } - - trans = btrfs_start_transaction(root, 1); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out_drop; - } - - btrfs_update_iflags(inode); - inode_inc_iversion(inode); - inode->i_ctime = current_time(inode); - ret = btrfs_update_inode(trans, root, inode); - - btrfs_end_transaction(trans, root); - out_drop: - if (ret) { - ip->flags = ip_oldflags; - inode->i_flags = i_oldflags; - } - - out_unlock: - inode_unlock(inode); - mnt_drop_write_file(file); - return ret; -} - -static int btrfs_ioctl_getversion(struct file *file, int __user *arg) -{ - struct inode *inode = file_inode(file); - - return put_user(inode->i_generation, arg); -} - -static noinline int btrfs_ioctl_fitrim(struct file *file, void __user *arg) -{ - struct btrfs_fs_info *fs_info = btrfs_sb(file_inode(file)->i_sb); - struct btrfs_device *device; - struct request_queue *q; - struct fstrim_range range; - u64 minlen = ULLONG_MAX; - u64 num_devices = 0; - u64 total_bytes = btrfs_super_total_bytes(fs_info->super_copy); - int ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - rcu_read_lock(); - list_for_each_entry_rcu(device, &fs_info->fs_devices->devices, - dev_list) { - if (!device->bdev) - continue; - q = bdev_get_queue(device->bdev); - if (blk_queue_discard(q)) { - num_devices++; - minlen = min((u64)q->limits.discard_granularity, - minlen); - } - } - rcu_read_unlock(); - - if (!num_devices) - return -EOPNOTSUPP; - if (copy_from_user(&range, arg, sizeof(range))) - return -EFAULT; - if (range.start > total_bytes || - range.len < fs_info->sb->s_blocksize) - return -EINVAL; - - range.len = min(range.len, total_bytes - range.start); - range.minlen = max(range.minlen, minlen); - ret = btrfs_trim_fs(fs_info->tree_root, &range); - if (ret < 0) - return ret; - - if (copy_to_user(arg, &range, sizeof(range))) - return -EFAULT; - - return 0; -} - -int btrfs_is_empty_uuid(u8 *uuid) -{ - int i; - - for (i = 0; i < BTRFS_UUID_SIZE; i++) { - if (uuid[i]) - return 0; - } - return 1; -} - -static noinline int create_subvol(struct inode *dir, - struct dentry *dentry, - char *name, int namelen, - u64 *async_transid, - struct btrfs_qgroup_inherit *inherit) -{ - struct btrfs_trans_handle *trans; - struct btrfs_key key; - struct btrfs_root_item *root_item; - struct btrfs_inode_item *inode_item; - struct extent_buffer *leaf; - struct btrfs_root *root = BTRFS_I(dir)->root; - struct btrfs_root *new_root; - struct btrfs_block_rsv block_rsv; - struct timespec cur_time = current_time(dir); - struct inode *inode; - int ret; - int err; - u64 objectid; - u64 new_dirid = BTRFS_FIRST_FREE_OBJECTID; - u64 index = 0; - u64 qgroup_reserved; - uuid_le new_uuid; - - root_item = kzalloc(sizeof(*root_item), GFP_KERNEL); - if (!root_item) - return -ENOMEM; - - ret = btrfs_find_free_objectid(root->fs_info->tree_root, &objectid); - if (ret) - goto fail_free; - - /* - * Don't create subvolume whose level is not zero. Or qgroup will be - * screwed up since it assumes subvolume qgroup's level to be 0. - */ - if (btrfs_qgroup_level(objectid)) { - ret = -ENOSPC; - goto fail_free; - } - - btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP); - /* - * The same as the snapshot creation, please see the comment - * of create_snapshot(). - */ - ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, - 8, &qgroup_reserved, false); - if (ret) - goto fail_free; - - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - btrfs_subvolume_release_metadata(root, &block_rsv, - qgroup_reserved); - goto fail_free; - } - trans->block_rsv = &block_rsv; - trans->bytes_reserved = block_rsv.size; - - ret = btrfs_qgroup_inherit(trans, root->fs_info, 0, objectid, inherit); - if (ret) - goto fail; - - leaf = btrfs_alloc_tree_block(trans, root, 0, objectid, NULL, 0, 0, 0); - if (IS_ERR(leaf)) { - ret = PTR_ERR(leaf); - goto fail; - } - - memset_extent_buffer(leaf, 0, 0, sizeof(struct btrfs_header)); - btrfs_set_header_bytenr(leaf, leaf->start); - btrfs_set_header_generation(leaf, trans->transid); - btrfs_set_header_backref_rev(leaf, BTRFS_MIXED_BACKREF_REV); - btrfs_set_header_owner(leaf, objectid); - - write_extent_buffer(leaf, root->fs_info->fsid, btrfs_header_fsid(), - BTRFS_FSID_SIZE); - write_extent_buffer(leaf, root->fs_info->chunk_tree_uuid, - btrfs_header_chunk_tree_uuid(leaf), - BTRFS_UUID_SIZE); - btrfs_mark_buffer_dirty(leaf); - - inode_item = &root_item->inode; - btrfs_set_stack_inode_generation(inode_item, 1); - btrfs_set_stack_inode_size(inode_item, 3); - btrfs_set_stack_inode_nlink(inode_item, 1); - btrfs_set_stack_inode_nbytes(inode_item, root->nodesize); - btrfs_set_stack_inode_mode(inode_item, S_IFDIR | 0755); - - btrfs_set_root_flags(root_item, 0); - btrfs_set_root_limit(root_item, 0); - btrfs_set_stack_inode_flags(inode_item, BTRFS_INODE_ROOT_ITEM_INIT); - - btrfs_set_root_bytenr(root_item, leaf->start); - btrfs_set_root_generation(root_item, trans->transid); - btrfs_set_root_level(root_item, 0); - btrfs_set_root_refs(root_item, 1); - btrfs_set_root_used(root_item, leaf->len); - btrfs_set_root_last_snapshot(root_item, 0); - - btrfs_set_root_generation_v2(root_item, - btrfs_root_generation(root_item)); - uuid_le_gen(&new_uuid); - memcpy(root_item->uuid, new_uuid.b, BTRFS_UUID_SIZE); - btrfs_set_stack_timespec_sec(&root_item->otime, cur_time.tv_sec); - btrfs_set_stack_timespec_nsec(&root_item->otime, cur_time.tv_nsec); - root_item->ctime = root_item->otime; - btrfs_set_root_ctransid(root_item, trans->transid); - btrfs_set_root_otransid(root_item, trans->transid); - - btrfs_tree_unlock(leaf); - free_extent_buffer(leaf); - leaf = NULL; - - btrfs_set_root_dirid(root_item, new_dirid); - - key.objectid = objectid; - key.offset = 0; - key.type = BTRFS_ROOT_ITEM_KEY; - ret = btrfs_insert_root(trans, root->fs_info->tree_root, &key, - root_item); - if (ret) - goto fail; - - key.offset = (u64)-1; - new_root = btrfs_read_fs_root_no_name(root->fs_info, &key); - if (IS_ERR(new_root)) { - ret = PTR_ERR(new_root); - btrfs_abort_transaction(trans, ret); - goto fail; - } - - btrfs_record_root_in_trans(trans, new_root); - - ret = btrfs_create_subvol_root(trans, new_root, root, new_dirid); - if (ret) { - /* We potentially lose an unused inode item here */ - btrfs_abort_transaction(trans, ret); - goto fail; - } - - mutex_lock(&new_root->objectid_mutex); - new_root->highest_objectid = new_dirid; - mutex_unlock(&new_root->objectid_mutex); - - /* - * insert the directory item - */ - ret = btrfs_set_inode_index(dir, &index); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto fail; - } - - ret = btrfs_insert_dir_item(trans, root, - name, namelen, dir, &key, - BTRFS_FT_DIR, index); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto fail; - } - - btrfs_i_size_write(dir, dir->i_size + namelen * 2); - ret = btrfs_update_inode(trans, root, dir); - BUG_ON(ret); - - ret = btrfs_add_root_ref(trans, root->fs_info->tree_root, - objectid, root->root_key.objectid, - btrfs_ino(dir), index, name, namelen); - BUG_ON(ret); - - ret = btrfs_uuid_tree_add(trans, root->fs_info->uuid_root, - root_item->uuid, BTRFS_UUID_KEY_SUBVOL, - objectid); - if (ret) - btrfs_abort_transaction(trans, ret); - -fail: - kfree(root_item); - trans->block_rsv = NULL; - trans->bytes_reserved = 0; - btrfs_subvolume_release_metadata(root, &block_rsv, qgroup_reserved); - - if (async_transid) { - *async_transid = trans->transid; - err = btrfs_commit_transaction_async(trans, root, 1); - if (err) - err = btrfs_commit_transaction(trans, root); - } else { - err = btrfs_commit_transaction(trans, root); - } - if (err && !ret) - ret = err; - - if (!ret) { - inode = btrfs_lookup_dentry(dir, dentry); - if (IS_ERR(inode)) - return PTR_ERR(inode); - d_instantiate(dentry, inode); - } - return ret; - -fail_free: - kfree(root_item); - return ret; -} - -static void btrfs_wait_for_no_snapshoting_writes(struct btrfs_root *root) -{ - s64 writers; - DEFINE_WAIT(wait); - - do { - prepare_to_wait(&root->subv_writers->wait, &wait, - TASK_UNINTERRUPTIBLE); - - writers = percpu_counter_sum(&root->subv_writers->counter); - if (writers) - schedule(); - - finish_wait(&root->subv_writers->wait, &wait); - } while (writers); -} - -static int create_snapshot(struct btrfs_root *root, struct inode *dir, - struct dentry *dentry, char *name, int namelen, - u64 *async_transid, bool readonly, - struct btrfs_qgroup_inherit *inherit) -{ - struct inode *inode; - struct btrfs_pending_snapshot *pending_snapshot; - struct btrfs_trans_handle *trans; - int ret; - - if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state)) - return -EINVAL; - - pending_snapshot = kzalloc(sizeof(*pending_snapshot), GFP_NOFS); - if (!pending_snapshot) - return -ENOMEM; - - pending_snapshot->root_item = kzalloc(sizeof(struct btrfs_root_item), - GFP_NOFS); - pending_snapshot->path = btrfs_alloc_path(); - if (!pending_snapshot->root_item || !pending_snapshot->path) { - ret = -ENOMEM; - goto free_pending; - } - - atomic_inc(&root->will_be_snapshoted); - smp_mb__after_atomic(); - btrfs_wait_for_no_snapshoting_writes(root); - - ret = btrfs_start_delalloc_inodes(root, 0); - if (ret) - goto dec_and_free; - - btrfs_wait_ordered_extents(root, -1, 0, (u64)-1); - - btrfs_init_block_rsv(&pending_snapshot->block_rsv, - BTRFS_BLOCK_RSV_TEMP); - /* - * 1 - parent dir inode - * 2 - dir entries - * 1 - root item - * 2 - root ref/backref - * 1 - root of snapshot - * 1 - UUID item - */ - ret = btrfs_subvolume_reserve_metadata(BTRFS_I(dir)->root, - &pending_snapshot->block_rsv, 8, - &pending_snapshot->qgroup_reserved, - false); - if (ret) - goto dec_and_free; - - pending_snapshot->dentry = dentry; - pending_snapshot->root = root; - pending_snapshot->readonly = readonly; - pending_snapshot->dir = dir; - pending_snapshot->inherit = inherit; - - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto fail; - } - - spin_lock(&root->fs_info->trans_lock); - list_add(&pending_snapshot->list, - &trans->transaction->pending_snapshots); - spin_unlock(&root->fs_info->trans_lock); - if (async_transid) { - *async_transid = trans->transid; - ret = btrfs_commit_transaction_async(trans, - root->fs_info->extent_root, 1); - if (ret) - ret = btrfs_commit_transaction(trans, root); - } else { - ret = btrfs_commit_transaction(trans, - root->fs_info->extent_root); - } - if (ret) - goto fail; - - ret = pending_snapshot->error; - if (ret) - goto fail; - - ret = btrfs_orphan_cleanup(pending_snapshot->snap); - if (ret) - goto fail; - - inode = btrfs_lookup_dentry(d_inode(dentry->d_parent), dentry); - if (IS_ERR(inode)) { - ret = PTR_ERR(inode); - goto fail; - } - - d_instantiate(dentry, inode); - ret = 0; -fail: - btrfs_subvolume_release_metadata(BTRFS_I(dir)->root, - &pending_snapshot->block_rsv, - pending_snapshot->qgroup_reserved); -dec_and_free: - if (atomic_dec_and_test(&root->will_be_snapshoted)) - wake_up_atomic_t(&root->will_be_snapshoted); -free_pending: - kfree(pending_snapshot->root_item); - btrfs_free_path(pending_snapshot->path); - kfree(pending_snapshot); - - return ret; -} - -/* copy of may_delete in fs/namei.c() - * Check whether we can remove a link victim from directory dir, check - * whether the type of victim is right. - * 1. We can't do it if dir is read-only (done in permission()) - * 2. We should have write and exec permissions on dir - * 3. We can't remove anything from append-only dir - * 4. We can't do anything with immutable dir (done in permission()) - * 5. If the sticky bit on dir is set we should either - * a. be owner of dir, or - * b. be owner of victim, or - * c. have CAP_FOWNER capability - * 6. If the victim is append-only or immutable we can't do anything with - * links pointing to it. - * 7. If we were asked to remove a directory and victim isn't one - ENOTDIR. - * 8. If we were asked to remove a non-directory and victim isn't one - EISDIR. - * 9. We can't remove a root or mountpoint. - * 10. We don't allow removal of NFS sillyrenamed files; it's handled by - * nfs_async_unlink(). - */ - -static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir) -{ - int error; - - if (d_really_is_negative(victim)) - return -ENOENT; - - BUG_ON(d_inode(victim->d_parent) != dir); - audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE); - - error = inode_permission(dir, MAY_WRITE | MAY_EXEC); - if (error) - return error; - if (IS_APPEND(dir)) - return -EPERM; - if (check_sticky(dir, d_inode(victim)) || IS_APPEND(d_inode(victim)) || - IS_IMMUTABLE(d_inode(victim)) || IS_SWAPFILE(d_inode(victim))) - return -EPERM; - if (isdir) { - if (!d_is_dir(victim)) - return -ENOTDIR; - if (IS_ROOT(victim)) - return -EBUSY; - } else if (d_is_dir(victim)) - return -EISDIR; - if (IS_DEADDIR(dir)) - return -ENOENT; - if (victim->d_flags & DCACHE_NFSFS_RENAMED) - return -EBUSY; - return 0; -} - -/* copy of may_create in fs/namei.c() */ -static inline int btrfs_may_create(struct inode *dir, struct dentry *child) -{ - if (d_really_is_positive(child)) - return -EEXIST; - if (IS_DEADDIR(dir)) - return -ENOENT; - return inode_permission(dir, MAY_WRITE | MAY_EXEC); -} - -/* - * Create a new subvolume below @parent. This is largely modeled after - * sys_mkdirat and vfs_mkdir, but we only do a single component lookup - * inside this filesystem so it's quite a bit simpler. - */ -static noinline int btrfs_mksubvol(struct path *parent, - char *name, int namelen, - struct btrfs_root *snap_src, - u64 *async_transid, bool readonly, - struct btrfs_qgroup_inherit *inherit) -{ - struct inode *dir = d_inode(parent->dentry); - struct dentry *dentry; - int error; - - error = down_write_killable_nested(&dir->i_rwsem, I_MUTEX_PARENT); - if (error == -EINTR) - return error; - - dentry = lookup_one_len(name, parent->dentry, namelen); - error = PTR_ERR(dentry); - if (IS_ERR(dentry)) - goto out_unlock; - - error = btrfs_may_create(dir, dentry); - if (error) - goto out_dput; - - /* - * even if this name doesn't exist, we may get hash collisions. - * check for them now when we can safely fail - */ - error = btrfs_check_dir_item_collision(BTRFS_I(dir)->root, - dir->i_ino, name, - namelen); - if (error) - goto out_dput; - - down_read(&BTRFS_I(dir)->root->fs_info->subvol_sem); - - if (btrfs_root_refs(&BTRFS_I(dir)->root->root_item) == 0) - goto out_up_read; - - if (snap_src) { - error = create_snapshot(snap_src, dir, dentry, name, namelen, - async_transid, readonly, inherit); - } else { - error = create_subvol(dir, dentry, name, namelen, - async_transid, inherit); - } - if (!error) - fsnotify_mkdir(dir, dentry); -out_up_read: - up_read(&BTRFS_I(dir)->root->fs_info->subvol_sem); -out_dput: - dput(dentry); -out_unlock: - inode_unlock(dir); - return error; -} - -/* - * When we're defragging a range, we don't want to kick it off again - * if it is really just waiting for delalloc to send it down. - * If we find a nice big extent or delalloc range for the bytes in the - * file you want to defrag, we return 0 to let you know to skip this - * part of the file - */ -static int check_defrag_in_cache(struct inode *inode, u64 offset, u32 thresh) -{ - struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; - struct extent_map *em = NULL; - struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; - u64 end; - - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, offset, PAGE_SIZE); - read_unlock(&em_tree->lock); - - if (em) { - end = extent_map_end(em); - free_extent_map(em); - if (end - offset > thresh) - return 0; - } - /* if we already have a nice delalloc here, just stop */ - thresh /= 2; - end = count_range_bits(io_tree, &offset, offset + thresh, - thresh, EXTENT_DELALLOC, 1); - if (end >= thresh) - return 0; - return 1; -} - -/* - * helper function to walk through a file and find extents - * newer than a specific transid, and smaller than thresh. - * - * This is used by the defragging code to find new and small - * extents - */ -static int find_new_extents(struct btrfs_root *root, - struct inode *inode, u64 newer_than, - u64 *off, u32 thresh) -{ - struct btrfs_path *path; - struct btrfs_key min_key; - struct extent_buffer *leaf; - struct btrfs_file_extent_item *extent; - int type; - int ret; - u64 ino = btrfs_ino(inode); - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - min_key.objectid = ino; - min_key.type = BTRFS_EXTENT_DATA_KEY; - min_key.offset = *off; - - while (1) { - ret = btrfs_search_forward(root, &min_key, path, newer_than); - if (ret != 0) - goto none; -process_slot: - if (min_key.objectid != ino) - goto none; - if (min_key.type != BTRFS_EXTENT_DATA_KEY) - goto none; - - leaf = path->nodes[0]; - extent = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - - type = btrfs_file_extent_type(leaf, extent); - if (type == BTRFS_FILE_EXTENT_REG && - btrfs_file_extent_num_bytes(leaf, extent) < thresh && - check_defrag_in_cache(inode, min_key.offset, thresh)) { - *off = min_key.offset; - btrfs_free_path(path); - return 0; - } - - path->slots[0]++; - if (path->slots[0] < btrfs_header_nritems(leaf)) { - btrfs_item_key_to_cpu(leaf, &min_key, path->slots[0]); - goto process_slot; - } - - if (min_key.offset == (u64)-1) - goto none; - - min_key.offset++; - btrfs_release_path(path); - } -none: - btrfs_free_path(path); - return -ENOENT; -} - -static struct extent_map *defrag_lookup_extent(struct inode *inode, u64 start) -{ - struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; - struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree; - struct extent_map *em; - u64 len = PAGE_SIZE; - - /* - * hopefully we have this extent in the tree already, try without - * the full extent lock - */ - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, start, len); - read_unlock(&em_tree->lock); - - if (!em) { - struct extent_state *cached = NULL; - u64 end = start + len - 1; - - /* get the big lock and read metadata off disk */ - lock_extent_bits(io_tree, start, end, &cached); - em = btrfs_get_extent(inode, NULL, 0, start, len, 0); - unlock_extent_cached(io_tree, start, end, &cached, GFP_NOFS); - - if (IS_ERR(em)) - return NULL; - } - - return em; -} - -static bool defrag_check_next_extent(struct inode *inode, struct extent_map *em) -{ - struct extent_map *next; - bool ret = true; - - /* this is the last extent */ - if (em->start + em->len >= i_size_read(inode)) - return false; - - next = defrag_lookup_extent(inode, em->start + em->len); - if (!next || next->block_start >= EXTENT_MAP_LAST_BYTE) - ret = false; - else if ((em->block_start + em->block_len == next->block_start) && - (em->block_len > SZ_128K && next->block_len > SZ_128K)) - ret = false; - - free_extent_map(next); - return ret; -} - -static int should_defrag_range(struct inode *inode, u64 start, u32 thresh, - u64 *last_len, u64 *skip, u64 *defrag_end, - int compress) -{ - struct extent_map *em; - int ret = 1; - bool next_mergeable = true; - bool prev_mergeable = true; - - /* - * make sure that once we start defragging an extent, we keep on - * defragging it - */ - if (start < *defrag_end) - return 1; - - *skip = 0; - - em = defrag_lookup_extent(inode, start); - if (!em) - return 0; - - /* this will cover holes, and inline extents */ - if (em->block_start >= EXTENT_MAP_LAST_BYTE) { - ret = 0; - goto out; - } - - if (!*defrag_end) - prev_mergeable = false; - - next_mergeable = defrag_check_next_extent(inode, em); - /* - * we hit a real extent, if it is big or the next extent is not a - * real extent, don't bother defragging it - */ - if (!compress && (*last_len == 0 || *last_len >= thresh) && - (em->len >= thresh || (!next_mergeable && !prev_mergeable))) - ret = 0; -out: - /* - * last_len ends up being a counter of how many bytes we've defragged. - * every time we choose not to defrag an extent, we reset *last_len - * so that the next tiny extent will force a defrag. - * - * The end result of this is that tiny extents before a single big - * extent will force at least part of that big extent to be defragged. - */ - if (ret) { - *defrag_end = extent_map_end(em); - } else { - *last_len = 0; - *skip = extent_map_end(em); - *defrag_end = 0; - } - - free_extent_map(em); - return ret; -} - -/* - * it doesn't do much good to defrag one or two pages - * at a time. This pulls in a nice chunk of pages - * to COW and defrag. - * - * It also makes sure the delalloc code has enough - * dirty data to avoid making new small extents as part - * of the defrag - * - * It's a good idea to start RA on this range - * before calling this. - */ -static int cluster_pages_for_defrag(struct inode *inode, - struct page **pages, - unsigned long start_index, - unsigned long num_pages) -{ - unsigned long file_end; - u64 isize = i_size_read(inode); - u64 page_start; - u64 page_end; - u64 page_cnt; - int ret; - int i; - int i_done; - struct btrfs_ordered_extent *ordered; - struct extent_state *cached_state = NULL; - struct extent_io_tree *tree; - gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping); - - file_end = (isize - 1) >> PAGE_SHIFT; - if (!isize || start_index > file_end) - return 0; - - page_cnt = min_t(u64, (u64)num_pages, (u64)file_end - start_index + 1); - - ret = btrfs_delalloc_reserve_space(inode, - start_index << PAGE_SHIFT, - page_cnt << PAGE_SHIFT); - if (ret) - return ret; - i_done = 0; - tree = &BTRFS_I(inode)->io_tree; - - /* step one, lock all the pages */ - for (i = 0; i < page_cnt; i++) { - struct page *page; -again: - page = find_or_create_page(inode->i_mapping, - start_index + i, mask); - if (!page) - break; - - page_start = page_offset(page); - page_end = page_start + PAGE_SIZE - 1; - while (1) { - lock_extent_bits(tree, page_start, page_end, - &cached_state); - ordered = btrfs_lookup_ordered_extent(inode, - page_start); - unlock_extent_cached(tree, page_start, page_end, - &cached_state, GFP_NOFS); - if (!ordered) - break; - - unlock_page(page); - btrfs_start_ordered_extent(inode, ordered, 1); - btrfs_put_ordered_extent(ordered); - lock_page(page); - /* - * we unlocked the page above, so we need check if - * it was released or not. - */ - if (page->mapping != inode->i_mapping) { - unlock_page(page); - put_page(page); - goto again; - } - } - - if (!PageUptodate(page)) { - btrfs_readpage(NULL, page); - lock_page(page); - if (!PageUptodate(page)) { - unlock_page(page); - put_page(page); - ret = -EIO; - break; - } - } - - if (page->mapping != inode->i_mapping) { - unlock_page(page); - put_page(page); - goto again; - } - - pages[i] = page; - i_done++; - } - if (!i_done || ret) - goto out; - - if (!(inode->i_sb->s_flags & MS_ACTIVE)) - goto out; - - /* - * so now we have a nice long stream of locked - * and up to date pages, lets wait on them - */ - for (i = 0; i < i_done; i++) - wait_on_page_writeback(pages[i]); - - page_start = page_offset(pages[0]); - page_end = page_offset(pages[i_done - 1]) + PAGE_SIZE; - - lock_extent_bits(&BTRFS_I(inode)->io_tree, - page_start, page_end - 1, &cached_state); - clear_extent_bit(&BTRFS_I(inode)->io_tree, page_start, - page_end - 1, EXTENT_DIRTY | EXTENT_DELALLOC | - EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 0, 0, - &cached_state, GFP_NOFS); - - if (i_done != page_cnt) { - spin_lock(&BTRFS_I(inode)->lock); - BTRFS_I(inode)->outstanding_extents++; - spin_unlock(&BTRFS_I(inode)->lock); - btrfs_delalloc_release_space(inode, - start_index << PAGE_SHIFT, - (page_cnt - i_done) << PAGE_SHIFT); - } - - - set_extent_defrag(&BTRFS_I(inode)->io_tree, page_start, page_end - 1, - &cached_state); - - unlock_extent_cached(&BTRFS_I(inode)->io_tree, - page_start, page_end - 1, &cached_state, - GFP_NOFS); - - for (i = 0; i < i_done; i++) { - clear_page_dirty_for_io(pages[i]); - ClearPageChecked(pages[i]); - set_page_extent_mapped(pages[i]); - set_page_dirty(pages[i]); - unlock_page(pages[i]); - put_page(pages[i]); - } - return i_done; -out: - for (i = 0; i < i_done; i++) { - unlock_page(pages[i]); - put_page(pages[i]); - } - btrfs_delalloc_release_space(inode, - start_index << PAGE_SHIFT, - page_cnt << PAGE_SHIFT); - return ret; - -} - -int btrfs_defrag_file(struct inode *inode, struct file *file, - struct btrfs_ioctl_defrag_range_args *range, - u64 newer_than, unsigned long max_to_defrag) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct file_ra_state *ra = NULL; - unsigned long last_index; - u64 isize = i_size_read(inode); - u64 last_len = 0; - u64 skip = 0; - u64 defrag_end = 0; - u64 newer_off = range->start; - unsigned long i; - unsigned long ra_index = 0; - int ret; - int defrag_count = 0; - int compress_type = BTRFS_COMPRESS_ZLIB; - u32 extent_thresh = range->extent_thresh; - unsigned long max_cluster = SZ_256K >> PAGE_SHIFT; - unsigned long cluster = max_cluster; - u64 new_align = ~((u64)SZ_128K - 1); - struct page **pages = NULL; - - if (isize == 0) - return 0; - - if (range->start >= isize) - return -EINVAL; - - if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) { - if (range->compress_type > BTRFS_COMPRESS_TYPES) - return -EINVAL; - if (range->compress_type) - compress_type = range->compress_type; - } - - if (extent_thresh == 0) - extent_thresh = SZ_256K; - - /* - * if we were not given a file, allocate a readahead - * context - */ - if (!file) { - ra = kzalloc(sizeof(*ra), GFP_NOFS); - if (!ra) - return -ENOMEM; - file_ra_state_init(ra, inode->i_mapping); - } else { - ra = &file->f_ra; - } - - pages = kmalloc_array(max_cluster, sizeof(struct page *), - GFP_NOFS); - if (!pages) { - ret = -ENOMEM; - goto out_ra; - } - - /* find the last page to defrag */ - if (range->start + range->len > range->start) { - last_index = min_t(u64, isize - 1, - range->start + range->len - 1) >> PAGE_SHIFT; - } else { - last_index = (isize - 1) >> PAGE_SHIFT; - } - - if (newer_than) { - ret = find_new_extents(root, inode, newer_than, - &newer_off, SZ_64K); - if (!ret) { - range->start = newer_off; - /* - * we always align our defrag to help keep - * the extents in the file evenly spaced - */ - i = (newer_off & new_align) >> PAGE_SHIFT; - } else - goto out_ra; - } else { - i = range->start >> PAGE_SHIFT; - } - if (!max_to_defrag) - max_to_defrag = last_index - i + 1; - - /* - * make writeback starts from i, so the defrag range can be - * written sequentially. - */ - if (i < inode->i_mapping->writeback_index) - inode->i_mapping->writeback_index = i; - - while (i <= last_index && defrag_count < max_to_defrag && - (i < DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE))) { - /* - * make sure we stop running if someone unmounts - * the FS - */ - if (!(inode->i_sb->s_flags & MS_ACTIVE)) - break; - - if (btrfs_defrag_cancelled(root->fs_info)) { - btrfs_debug(root->fs_info, "defrag_file cancelled"); - ret = -EAGAIN; - break; - } - - if (!should_defrag_range(inode, (u64)i << PAGE_SHIFT, - extent_thresh, &last_len, &skip, - &defrag_end, range->flags & - BTRFS_DEFRAG_RANGE_COMPRESS)) { - unsigned long next; - /* - * the should_defrag function tells us how much to skip - * bump our counter by the suggested amount - */ - next = DIV_ROUND_UP(skip, PAGE_SIZE); - i = max(i + 1, next); - continue; - } - - if (!newer_than) { - cluster = (PAGE_ALIGN(defrag_end) >> - PAGE_SHIFT) - i; - cluster = min(cluster, max_cluster); - } else { - cluster = max_cluster; - } - - if (i + cluster > ra_index) { - ra_index = max(i, ra_index); - btrfs_force_ra(inode->i_mapping, ra, file, ra_index, - cluster); - ra_index += cluster; - } - - inode_lock(inode); - if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) - BTRFS_I(inode)->force_compress = compress_type; - ret = cluster_pages_for_defrag(inode, pages, i, cluster); - if (ret < 0) { - inode_unlock(inode); - goto out_ra; - } - - defrag_count += ret; - balance_dirty_pages_ratelimited(inode->i_mapping); - inode_unlock(inode); - - if (newer_than) { - if (newer_off == (u64)-1) - break; - - if (ret > 0) - i += ret; - - newer_off = max(newer_off + 1, - (u64)i << PAGE_SHIFT); - - ret = find_new_extents(root, inode, newer_than, - &newer_off, SZ_64K); - if (!ret) { - range->start = newer_off; - i = (newer_off & new_align) >> PAGE_SHIFT; - } else { - break; - } - } else { - if (ret > 0) { - i += ret; - last_len += ret << PAGE_SHIFT; - } else { - i++; - last_len = 0; - } - } - } - - if ((range->flags & BTRFS_DEFRAG_RANGE_START_IO)) { - filemap_flush(inode->i_mapping); - if (test_bit(BTRFS_INODE_HAS_ASYNC_EXTENT, - &BTRFS_I(inode)->runtime_flags)) - filemap_flush(inode->i_mapping); - } - - if ((range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)) { - /* the filemap_flush will queue IO into the worker threads, but - * we have to make sure the IO is actually started and that - * ordered extents get created before we return - */ - atomic_inc(&root->fs_info->async_submit_draining); - while (atomic_read(&root->fs_info->nr_async_submits) || - atomic_read(&root->fs_info->async_delalloc_pages)) { - wait_event(root->fs_info->async_submit_wait, - (atomic_read(&root->fs_info->nr_async_submits) == 0 && - atomic_read(&root->fs_info->async_delalloc_pages) == 0)); - } - atomic_dec(&root->fs_info->async_submit_draining); - } - - if (range->compress_type == BTRFS_COMPRESS_LZO) { - btrfs_set_fs_incompat(root->fs_info, COMPRESS_LZO); - } - - ret = defrag_count; - -out_ra: - if (range->flags & BTRFS_DEFRAG_RANGE_COMPRESS) { - inode_lock(inode); - BTRFS_I(inode)->force_compress = BTRFS_COMPRESS_NONE; - inode_unlock(inode); - } - if (!file) - kfree(ra); - kfree(pages); - return ret; -} - -static noinline int btrfs_ioctl_resize(struct file *file, - void __user *arg) -{ - u64 new_size; - u64 old_size; - u64 devid = 1; - struct btrfs_root *root = BTRFS_I(file_inode(file))->root; - struct btrfs_ioctl_vol_args *vol_args; - struct btrfs_trans_handle *trans; - struct btrfs_device *device = NULL; - char *sizestr; - char *retptr; - char *devstr = NULL; - int ret = 0; - int mod = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - ret = mnt_want_write_file(file); - if (ret) - return ret; - - if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, - 1)) { - mnt_drop_write_file(file); - return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; - } - - mutex_lock(&root->fs_info->volume_mutex); - vol_args = memdup_user(arg, sizeof(*vol_args)); - if (IS_ERR(vol_args)) { - ret = PTR_ERR(vol_args); - goto out; - } - - vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; - - sizestr = vol_args->name; - devstr = strchr(sizestr, ':'); - if (devstr) { - sizestr = devstr + 1; - *devstr = '\0'; - devstr = vol_args->name; - ret = kstrtoull(devstr, 10, &devid); - if (ret) - goto out_free; - if (!devid) { - ret = -EINVAL; - goto out_free; - } - btrfs_info(root->fs_info, "resizing devid %llu", devid); - } - - device = btrfs_find_device(root->fs_info, devid, NULL, NULL); - if (!device) { - btrfs_info(root->fs_info, "resizer unable to find device %llu", - devid); - ret = -ENODEV; - goto out_free; - } - - if (!device->writeable) { - btrfs_info(root->fs_info, - "resizer unable to apply on readonly device %llu", - devid); - ret = -EPERM; - goto out_free; - } - - if (!strcmp(sizestr, "max")) - new_size = device->bdev->bd_inode->i_size; - else { - if (sizestr[0] == '-') { - mod = -1; - sizestr++; - } else if (sizestr[0] == '+') { - mod = 1; - sizestr++; - } - new_size = memparse(sizestr, &retptr); - if (*retptr != '\0' || new_size == 0) { - ret = -EINVAL; - goto out_free; - } - } - - if (device->is_tgtdev_for_dev_replace) { - ret = -EPERM; - goto out_free; - } - - old_size = btrfs_device_get_total_bytes(device); - - if (mod < 0) { - if (new_size > old_size) { - ret = -EINVAL; - goto out_free; - } - new_size = old_size - new_size; - } else if (mod > 0) { - if (new_size > ULLONG_MAX - old_size) { - ret = -ERANGE; - goto out_free; - } - new_size = old_size + new_size; - } - - if (new_size < SZ_256M) { - ret = -EINVAL; - goto out_free; - } - if (new_size > device->bdev->bd_inode->i_size) { - ret = -EFBIG; - goto out_free; - } - - new_size = div_u64(new_size, root->sectorsize); - new_size *= root->sectorsize; - - btrfs_info_in_rcu(root->fs_info, "new size for %s is %llu", - rcu_str_deref(device->name), new_size); - - if (new_size > old_size) { - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out_free; - } - ret = btrfs_grow_device(trans, device, new_size); - btrfs_commit_transaction(trans, root); - } else if (new_size < old_size) { - ret = btrfs_shrink_device(device, new_size); - } /* equal, nothing need to do */ - -out_free: - kfree(vol_args); -out: - mutex_unlock(&root->fs_info->volume_mutex); - atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); - mnt_drop_write_file(file); - return ret; -} - -static noinline int btrfs_ioctl_snap_create_transid(struct file *file, - char *name, unsigned long fd, int subvol, - u64 *transid, bool readonly, - struct btrfs_qgroup_inherit *inherit) -{ - int namelen; - int ret = 0; - - if (!S_ISDIR(file_inode(file)->i_mode)) - return -ENOTDIR; - - ret = mnt_want_write_file(file); - if (ret) - goto out; - - namelen = strlen(name); - if (strchr(name, '/')) { - ret = -EINVAL; - goto out_drop_write; - } - - if (name[0] == '.' && - (namelen == 1 || (name[1] == '.' && namelen == 2))) { - ret = -EEXIST; - goto out_drop_write; - } - - if (subvol) { - ret = btrfs_mksubvol(&file->f_path, name, namelen, - NULL, transid, readonly, inherit); - } else { - struct fd src = fdget(fd); - struct inode *src_inode; - if (!src.file) { - ret = -EINVAL; - goto out_drop_write; - } - - src_inode = file_inode(src.file); - if (src_inode->i_sb != file_inode(file)->i_sb) { - btrfs_info(BTRFS_I(file_inode(file))->root->fs_info, - "Snapshot src from another FS"); - ret = -EXDEV; - } else if (!inode_owner_or_capable(src_inode)) { - /* - * Subvolume creation is not restricted, but snapshots - * are limited to own subvolumes only - */ - ret = -EPERM; - } else { - ret = btrfs_mksubvol(&file->f_path, name, namelen, - BTRFS_I(src_inode)->root, - transid, readonly, inherit); - } - fdput(src); - } -out_drop_write: - mnt_drop_write_file(file); -out: - return ret; -} - -static noinline int btrfs_ioctl_snap_create(struct file *file, - void __user *arg, int subvol) -{ - struct btrfs_ioctl_vol_args *vol_args; - int ret; - - if (!S_ISDIR(file_inode(file)->i_mode)) - return -ENOTDIR; - - vol_args = memdup_user(arg, sizeof(*vol_args)); - if (IS_ERR(vol_args)) - return PTR_ERR(vol_args); - vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; - - ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, - vol_args->fd, subvol, - NULL, false, NULL); - - kfree(vol_args); - return ret; -} - -static noinline int btrfs_ioctl_snap_create_v2(struct file *file, - void __user *arg, int subvol) -{ - struct btrfs_ioctl_vol_args_v2 *vol_args; - int ret; - u64 transid = 0; - u64 *ptr = NULL; - bool readonly = false; - struct btrfs_qgroup_inherit *inherit = NULL; - - if (!S_ISDIR(file_inode(file)->i_mode)) - return -ENOTDIR; - - vol_args = memdup_user(arg, sizeof(*vol_args)); - if (IS_ERR(vol_args)) - return PTR_ERR(vol_args); - vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; - - if (vol_args->flags & - ~(BTRFS_SUBVOL_CREATE_ASYNC | BTRFS_SUBVOL_RDONLY | - BTRFS_SUBVOL_QGROUP_INHERIT)) { - ret = -EOPNOTSUPP; - goto free_args; - } - - if (vol_args->flags & BTRFS_SUBVOL_CREATE_ASYNC) - ptr = &transid; - if (vol_args->flags & BTRFS_SUBVOL_RDONLY) - readonly = true; - if (vol_args->flags & BTRFS_SUBVOL_QGROUP_INHERIT) { - if (vol_args->size > PAGE_SIZE) { - ret = -EINVAL; - goto free_args; - } - inherit = memdup_user(vol_args->qgroup_inherit, vol_args->size); - if (IS_ERR(inherit)) { - ret = PTR_ERR(inherit); - goto free_args; - } - } - - ret = btrfs_ioctl_snap_create_transid(file, vol_args->name, - vol_args->fd, subvol, ptr, - readonly, inherit); - if (ret) - goto free_inherit; - - if (ptr && copy_to_user(arg + - offsetof(struct btrfs_ioctl_vol_args_v2, - transid), - ptr, sizeof(*ptr))) - ret = -EFAULT; - -free_inherit: - kfree(inherit); -free_args: - kfree(vol_args); - return ret; -} - -static noinline int btrfs_ioctl_subvol_getflags(struct file *file, - void __user *arg) -{ - struct inode *inode = file_inode(file); - struct btrfs_root *root = BTRFS_I(inode)->root; - int ret = 0; - u64 flags = 0; - - if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) - return -EINVAL; - - down_read(&root->fs_info->subvol_sem); - if (btrfs_root_readonly(root)) - flags |= BTRFS_SUBVOL_RDONLY; - up_read(&root->fs_info->subvol_sem); - - if (copy_to_user(arg, &flags, sizeof(flags))) - ret = -EFAULT; - - return ret; -} - -static noinline int btrfs_ioctl_subvol_setflags(struct file *file, - void __user *arg) -{ - struct inode *inode = file_inode(file); - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_trans_handle *trans; - u64 root_flags; - u64 flags; - int ret = 0; - - if (!inode_owner_or_capable(inode)) - return -EPERM; - - ret = mnt_want_write_file(file); - if (ret) - goto out; - - if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) { - ret = -EINVAL; - goto out_drop_write; - } - - if (copy_from_user(&flags, arg, sizeof(flags))) { - ret = -EFAULT; - goto out_drop_write; - } - - if (flags & BTRFS_SUBVOL_CREATE_ASYNC) { - ret = -EINVAL; - goto out_drop_write; - } - - if (flags & ~BTRFS_SUBVOL_RDONLY) { - ret = -EOPNOTSUPP; - goto out_drop_write; - } - - down_write(&root->fs_info->subvol_sem); - - /* nothing to do */ - if (!!(flags & BTRFS_SUBVOL_RDONLY) == btrfs_root_readonly(root)) - goto out_drop_sem; - - root_flags = btrfs_root_flags(&root->root_item); - if (flags & BTRFS_SUBVOL_RDONLY) { - btrfs_set_root_flags(&root->root_item, - root_flags | BTRFS_ROOT_SUBVOL_RDONLY); - } else { - /* - * Block RO -> RW transition if this subvolume is involved in - * send - */ - spin_lock(&root->root_item_lock); - if (root->send_in_progress == 0) { - btrfs_set_root_flags(&root->root_item, - root_flags & ~BTRFS_ROOT_SUBVOL_RDONLY); - spin_unlock(&root->root_item_lock); - } else { - spin_unlock(&root->root_item_lock); - btrfs_warn(root->fs_info, - "Attempt to set subvolume %llu read-write during send", - root->root_key.objectid); - ret = -EPERM; - goto out_drop_sem; - } - } - - trans = btrfs_start_transaction(root, 1); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out_reset; - } - - ret = btrfs_update_root(trans, root->fs_info->tree_root, - &root->root_key, &root->root_item); - - btrfs_commit_transaction(trans, root); -out_reset: - if (ret) - btrfs_set_root_flags(&root->root_item, root_flags); -out_drop_sem: - up_write(&root->fs_info->subvol_sem); -out_drop_write: - mnt_drop_write_file(file); -out: - return ret; -} - -/* - * helper to check if the subvolume references other subvolumes - */ -static noinline int may_destroy_subvol(struct btrfs_root *root) -{ - struct btrfs_path *path; - struct btrfs_dir_item *di; - struct btrfs_key key; - u64 dir_id; - int ret; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - /* Make sure this root isn't set as the default subvol */ - dir_id = btrfs_super_root_dir(root->fs_info->super_copy); - di = btrfs_lookup_dir_item(NULL, root->fs_info->tree_root, path, - dir_id, "default", 7, 0); - if (di && !IS_ERR(di)) { - btrfs_dir_item_key_to_cpu(path->nodes[0], di, &key); - if (key.objectid == root->root_key.objectid) { - ret = -EPERM; - btrfs_err(root->fs_info, - "deleting default subvolume %llu is not allowed", - key.objectid); - goto out; - } - btrfs_release_path(path); - } - - key.objectid = root->root_key.objectid; - key.type = BTRFS_ROOT_REF_KEY; - key.offset = (u64)-1; - - ret = btrfs_search_slot(NULL, root->fs_info->tree_root, - &key, path, 0, 0); - if (ret < 0) - goto out; - BUG_ON(ret == 0); - - ret = 0; - if (path->slots[0] > 0) { - path->slots[0]--; - btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); - if (key.objectid == root->root_key.objectid && - key.type == BTRFS_ROOT_REF_KEY) - ret = -ENOTEMPTY; - } -out: - btrfs_free_path(path); - return ret; -} - -static noinline int key_in_sk(struct btrfs_key *key, - struct btrfs_ioctl_search_key *sk) -{ - struct btrfs_key test; - int ret; - - test.objectid = sk->min_objectid; - test.type = sk->min_type; - test.offset = sk->min_offset; - - ret = btrfs_comp_cpu_keys(key, &test); - if (ret < 0) - return 0; - - test.objectid = sk->max_objectid; - test.type = sk->max_type; - test.offset = sk->max_offset; - - ret = btrfs_comp_cpu_keys(key, &test); - if (ret > 0) - return 0; - return 1; -} - -static noinline int copy_to_sk(struct btrfs_path *path, - struct btrfs_key *key, - struct btrfs_ioctl_search_key *sk, - size_t *buf_size, - char __user *ubuf, - unsigned long *sk_offset, - int *num_found) -{ - u64 found_transid; - struct extent_buffer *leaf; - struct btrfs_ioctl_search_header sh; - struct btrfs_key test; - unsigned long item_off; - unsigned long item_len; - int nritems; - int i; - int slot; - int ret = 0; - - leaf = path->nodes[0]; - slot = path->slots[0]; - nritems = btrfs_header_nritems(leaf); - - if (btrfs_header_generation(leaf) > sk->max_transid) { - i = nritems; - goto advance_key; - } - found_transid = btrfs_header_generation(leaf); - - for (i = slot; i < nritems; i++) { - item_off = btrfs_item_ptr_offset(leaf, i); - item_len = btrfs_item_size_nr(leaf, i); - - btrfs_item_key_to_cpu(leaf, key, i); - if (!key_in_sk(key, sk)) - continue; - - if (sizeof(sh) + item_len > *buf_size) { - if (*num_found) { - ret = 1; - goto out; - } - - /* - * return one empty item back for v1, which does not - * handle -EOVERFLOW - */ - - *buf_size = sizeof(sh) + item_len; - item_len = 0; - ret = -EOVERFLOW; - } - - if (sizeof(sh) + item_len + *sk_offset > *buf_size) { - ret = 1; - goto out; - } - - sh.objectid = key->objectid; - sh.offset = key->offset; - sh.type = key->type; - sh.len = item_len; - sh.transid = found_transid; - - /* copy search result header */ - if (copy_to_user(ubuf + *sk_offset, &sh, sizeof(sh))) { - ret = -EFAULT; - goto out; - } - - *sk_offset += sizeof(sh); - - if (item_len) { - char __user *up = ubuf + *sk_offset; - /* copy the item */ - if (read_extent_buffer_to_user(leaf, up, - item_off, item_len)) { - ret = -EFAULT; - goto out; - } - - *sk_offset += item_len; - } - (*num_found)++; - - if (ret) /* -EOVERFLOW from above */ - goto out; - - if (*num_found >= sk->nr_items) { - ret = 1; - goto out; - } - } -advance_key: - ret = 0; - test.objectid = sk->max_objectid; - test.type = sk->max_type; - test.offset = sk->max_offset; - if (btrfs_comp_cpu_keys(key, &test) >= 0) - ret = 1; - else if (key->offset < (u64)-1) - key->offset++; - else if (key->type < (u8)-1) { - key->offset = 0; - key->type++; - } else if (key->objectid < (u64)-1) { - key->offset = 0; - key->type = 0; - key->objectid++; - } else - ret = 1; -out: - /* - * 0: all items from this leaf copied, continue with next - * 1: * more items can be copied, but unused buffer is too small - * * all items were found - * Either way, it will stops the loop which iterates to the next - * leaf - * -EOVERFLOW: item was to large for buffer - * -EFAULT: could not copy extent buffer back to userspace - */ - return ret; -} - -static noinline int search_ioctl(struct inode *inode, - struct btrfs_ioctl_search_key *sk, - size_t *buf_size, - char __user *ubuf) -{ - struct btrfs_root *root; - struct btrfs_key key; - struct btrfs_path *path; - struct btrfs_fs_info *info = BTRFS_I(inode)->root->fs_info; - int ret; - int num_found = 0; - unsigned long sk_offset = 0; - - if (*buf_size < sizeof(struct btrfs_ioctl_search_header)) { - *buf_size = sizeof(struct btrfs_ioctl_search_header); - return -EOVERFLOW; - } - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - if (sk->tree_id == 0) { - /* search the root of the inode that was passed */ - root = BTRFS_I(inode)->root; - } else { - key.objectid = sk->tree_id; - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = (u64)-1; - root = btrfs_read_fs_root_no_name(info, &key); - if (IS_ERR(root)) { - btrfs_free_path(path); - return -ENOENT; - } - } - - key.objectid = sk->min_objectid; - key.type = sk->min_type; - key.offset = sk->min_offset; - - while (1) { - ret = btrfs_search_forward(root, &key, path, sk->min_transid); - if (ret != 0) { - if (ret > 0) - ret = 0; - goto err; - } - ret = copy_to_sk(path, &key, sk, buf_size, ubuf, - &sk_offset, &num_found); - btrfs_release_path(path); - if (ret) - break; - - } - if (ret > 0) - ret = 0; -err: - sk->nr_items = num_found; - btrfs_free_path(path); - return ret; -} - -static noinline int btrfs_ioctl_tree_search(struct file *file, - void __user *argp) -{ - struct btrfs_ioctl_search_args __user *uargs; - struct btrfs_ioctl_search_key sk; - struct inode *inode; - int ret; - size_t buf_size; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - uargs = (struct btrfs_ioctl_search_args __user *)argp; - - if (copy_from_user(&sk, &uargs->key, sizeof(sk))) - return -EFAULT; - - buf_size = sizeof(uargs->buf); - - inode = file_inode(file); - ret = search_ioctl(inode, &sk, &buf_size, uargs->buf); - - /* - * In the origin implementation an overflow is handled by returning a - * search header with a len of zero, so reset ret. - */ - if (ret == -EOVERFLOW) - ret = 0; - - if (ret == 0 && copy_to_user(&uargs->key, &sk, sizeof(sk))) - ret = -EFAULT; - return ret; -} - -static noinline int btrfs_ioctl_tree_search_v2(struct file *file, - void __user *argp) -{ - struct btrfs_ioctl_search_args_v2 __user *uarg; - struct btrfs_ioctl_search_args_v2 args; - struct inode *inode; - int ret; - size_t buf_size; - const size_t buf_limit = SZ_16M; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - /* copy search header and buffer size */ - uarg = (struct btrfs_ioctl_search_args_v2 __user *)argp; - if (copy_from_user(&args, uarg, sizeof(args))) - return -EFAULT; - - buf_size = args.buf_size; - - if (buf_size < sizeof(struct btrfs_ioctl_search_header)) - return -EOVERFLOW; - - /* limit result size to 16MB */ - if (buf_size > buf_limit) - buf_size = buf_limit; - - inode = file_inode(file); - ret = search_ioctl(inode, &args.key, &buf_size, - (char *)(&uarg->buf[0])); - if (ret == 0 && copy_to_user(&uarg->key, &args.key, sizeof(args.key))) - ret = -EFAULT; - else if (ret == -EOVERFLOW && - copy_to_user(&uarg->buf_size, &buf_size, sizeof(buf_size))) - ret = -EFAULT; - - return ret; -} - -/* - * Search INODE_REFs to identify path name of 'dirid' directory - * in a 'tree_id' tree. and sets path name to 'name'. - */ -static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info, - u64 tree_id, u64 dirid, char *name) -{ - struct btrfs_root *root; - struct btrfs_key key; - char *ptr; - int ret = -1; - int slot; - int len; - int total_len = 0; - struct btrfs_inode_ref *iref; - struct extent_buffer *l; - struct btrfs_path *path; - - if (dirid == BTRFS_FIRST_FREE_OBJECTID) { - name[0]='\0'; - return 0; - } - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - ptr = &name[BTRFS_INO_LOOKUP_PATH_MAX]; - - key.objectid = tree_id; - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = (u64)-1; - root = btrfs_read_fs_root_no_name(info, &key); - if (IS_ERR(root)) { - btrfs_err(info, "could not find root %llu", tree_id); - ret = -ENOENT; - goto out; - } - - key.objectid = dirid; - key.type = BTRFS_INODE_REF_KEY; - key.offset = (u64)-1; - - while (1) { - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out; - else if (ret > 0) { - ret = btrfs_previous_item(root, path, dirid, - BTRFS_INODE_REF_KEY); - if (ret < 0) - goto out; - else if (ret > 0) { - ret = -ENOENT; - goto out; - } - } - - l = path->nodes[0]; - slot = path->slots[0]; - btrfs_item_key_to_cpu(l, &key, slot); - - iref = btrfs_item_ptr(l, slot, struct btrfs_inode_ref); - len = btrfs_inode_ref_name_len(l, iref); - ptr -= len + 1; - total_len += len + 1; - if (ptr < name) { - ret = -ENAMETOOLONG; - goto out; - } - - *(ptr + len) = '/'; - read_extent_buffer(l, ptr, (unsigned long)(iref + 1), len); - - if (key.offset == BTRFS_FIRST_FREE_OBJECTID) - break; - - btrfs_release_path(path); - key.objectid = key.offset; - key.offset = (u64)-1; - dirid = key.objectid; - } - memmove(name, ptr, total_len); - name[total_len] = '\0'; - ret = 0; -out: - btrfs_free_path(path); - return ret; -} - -static noinline int btrfs_ioctl_ino_lookup(struct file *file, - void __user *argp) -{ - struct btrfs_ioctl_ino_lookup_args *args; - struct inode *inode; - int ret = 0; - - args = memdup_user(argp, sizeof(*args)); - if (IS_ERR(args)) - return PTR_ERR(args); - - inode = file_inode(file); - - /* - * Unprivileged query to obtain the containing subvolume root id. The - * path is reset so it's consistent with btrfs_search_path_in_tree. - */ - if (args->treeid == 0) - args->treeid = BTRFS_I(inode)->root->root_key.objectid; - - if (args->objectid == BTRFS_FIRST_FREE_OBJECTID) { - args->name[0] = 0; - goto out; - } - - if (!capable(CAP_SYS_ADMIN)) { - ret = -EPERM; - goto out; - } - - ret = btrfs_search_path_in_tree(BTRFS_I(inode)->root->fs_info, - args->treeid, args->objectid, - args->name); - -out: - if (ret == 0 && copy_to_user(argp, args, sizeof(*args))) - ret = -EFAULT; - - kfree(args); - return ret; -} - -static noinline int btrfs_ioctl_snap_destroy(struct file *file, - void __user *arg) -{ - struct dentry *parent = file->f_path.dentry; - struct dentry *dentry; - struct inode *dir = d_inode(parent); - struct inode *inode; - struct btrfs_root *root = BTRFS_I(dir)->root; - struct btrfs_root *dest = NULL; - struct btrfs_ioctl_vol_args *vol_args; - struct btrfs_trans_handle *trans; - struct btrfs_block_rsv block_rsv; - u64 root_flags; - u64 qgroup_reserved; - int namelen; - int ret; - int err = 0; - - if (!S_ISDIR(dir->i_mode)) - return -ENOTDIR; - - vol_args = memdup_user(arg, sizeof(*vol_args)); - if (IS_ERR(vol_args)) - return PTR_ERR(vol_args); - - vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; - namelen = strlen(vol_args->name); - if (strchr(vol_args->name, '/') || - strncmp(vol_args->name, "..", namelen) == 0) { - err = -EINVAL; - goto out; - } - - err = mnt_want_write_file(file); - if (err) - goto out; - - - err = down_write_killable_nested(&dir->i_rwsem, I_MUTEX_PARENT); - if (err == -EINTR) - goto out_drop_write; - dentry = lookup_one_len(vol_args->name, parent, namelen); - if (IS_ERR(dentry)) { - err = PTR_ERR(dentry); - goto out_unlock_dir; - } - - if (d_really_is_negative(dentry)) { - err = -ENOENT; - goto out_dput; - } - - inode = d_inode(dentry); - dest = BTRFS_I(inode)->root; - if (!capable(CAP_SYS_ADMIN)) { - /* - * Regular user. Only allow this with a special mount - * option, when the user has write+exec access to the - * subvol root, and when rmdir(2) would have been - * allowed. - * - * Note that this is _not_ check that the subvol is - * empty or doesn't contain data that we wouldn't - * otherwise be able to delete. - * - * Users who want to delete empty subvols should try - * rmdir(2). - */ - err = -EPERM; - if (!btrfs_test_opt(root->fs_info, USER_SUBVOL_RM_ALLOWED)) - goto out_dput; - - /* - * Do not allow deletion if the parent dir is the same - * as the dir to be deleted. That means the ioctl - * must be called on the dentry referencing the root - * of the subvol, not a random directory contained - * within it. - */ - err = -EINVAL; - if (root == dest) - goto out_dput; - - err = inode_permission(inode, MAY_WRITE | MAY_EXEC); - if (err) - goto out_dput; - } - - /* check if subvolume may be deleted by a user */ - err = btrfs_may_delete(dir, dentry, 1); - if (err) - goto out_dput; - - if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) { - err = -EINVAL; - goto out_dput; - } - - inode_lock(inode); - - /* - * Don't allow to delete a subvolume with send in progress. This is - * inside the i_mutex so the error handling that has to drop the bit - * again is not run concurrently. - */ - spin_lock(&dest->root_item_lock); - root_flags = btrfs_root_flags(&dest->root_item); - if (dest->send_in_progress == 0) { - btrfs_set_root_flags(&dest->root_item, - root_flags | BTRFS_ROOT_SUBVOL_DEAD); - spin_unlock(&dest->root_item_lock); - } else { - spin_unlock(&dest->root_item_lock); - btrfs_warn(root->fs_info, - "Attempt to delete subvolume %llu during send", - dest->root_key.objectid); - err = -EPERM; - goto out_unlock_inode; - } - - down_write(&root->fs_info->subvol_sem); - - err = may_destroy_subvol(dest); - if (err) - goto out_up_write; - - btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP); - /* - * One for dir inode, two for dir entries, two for root - * ref/backref. - */ - err = btrfs_subvolume_reserve_metadata(root, &block_rsv, - 5, &qgroup_reserved, true); - if (err) - goto out_up_write; - - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) { - err = PTR_ERR(trans); - goto out_release; - } - trans->block_rsv = &block_rsv; - trans->bytes_reserved = block_rsv.size; - - btrfs_record_snapshot_destroy(trans, dir); - - ret = btrfs_unlink_subvol(trans, root, dir, - dest->root_key.objectid, - dentry->d_name.name, - dentry->d_name.len); - if (ret) { - err = ret; - btrfs_abort_transaction(trans, ret); - goto out_end_trans; - } - - btrfs_record_root_in_trans(trans, dest); - - memset(&dest->root_item.drop_progress, 0, - sizeof(dest->root_item.drop_progress)); - dest->root_item.drop_level = 0; - btrfs_set_root_refs(&dest->root_item, 0); - - if (!test_and_set_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, &dest->state)) { - ret = btrfs_insert_orphan_item(trans, - root->fs_info->tree_root, - dest->root_key.objectid); - if (ret) { - btrfs_abort_transaction(trans, ret); - err = ret; - goto out_end_trans; - } - } - - ret = btrfs_uuid_tree_rem(trans, root->fs_info->uuid_root, - dest->root_item.uuid, BTRFS_UUID_KEY_SUBVOL, - dest->root_key.objectid); - if (ret && ret != -ENOENT) { - btrfs_abort_transaction(trans, ret); - err = ret; - goto out_end_trans; - } - if (!btrfs_is_empty_uuid(dest->root_item.received_uuid)) { - ret = btrfs_uuid_tree_rem(trans, root->fs_info->uuid_root, - dest->root_item.received_uuid, - BTRFS_UUID_KEY_RECEIVED_SUBVOL, - dest->root_key.objectid); - if (ret && ret != -ENOENT) { - btrfs_abort_transaction(trans, ret); - err = ret; - goto out_end_trans; - } - } - -out_end_trans: - trans->block_rsv = NULL; - trans->bytes_reserved = 0; - ret = btrfs_end_transaction(trans, root); - if (ret && !err) - err = ret; - inode->i_flags |= S_DEAD; -out_release: - btrfs_subvolume_release_metadata(root, &block_rsv, qgroup_reserved); -out_up_write: - up_write(&root->fs_info->subvol_sem); - if (err) { - spin_lock(&dest->root_item_lock); - root_flags = btrfs_root_flags(&dest->root_item); - btrfs_set_root_flags(&dest->root_item, - root_flags & ~BTRFS_ROOT_SUBVOL_DEAD); - spin_unlock(&dest->root_item_lock); - } -out_unlock_inode: - inode_unlock(inode); - if (!err) { - d_invalidate(dentry); - btrfs_invalidate_inodes(dest); - d_delete(dentry); - ASSERT(dest->send_in_progress == 0); - - /* the last ref */ - if (dest->ino_cache_inode) { - iput(dest->ino_cache_inode); - dest->ino_cache_inode = NULL; - } - } -out_dput: - dput(dentry); -out_unlock_dir: - inode_unlock(dir); -out_drop_write: - mnt_drop_write_file(file); -out: - kfree(vol_args); - return err; -} - -static int btrfs_ioctl_defrag(struct file *file, void __user *argp) -{ - struct inode *inode = file_inode(file); - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_ioctl_defrag_range_args *range; - int ret; - - ret = mnt_want_write_file(file); - if (ret) - return ret; - - if (btrfs_root_readonly(root)) { - ret = -EROFS; - goto out; - } - - switch (inode->i_mode & S_IFMT) { - case S_IFDIR: - if (!capable(CAP_SYS_ADMIN)) { - ret = -EPERM; - goto out; - } - ret = btrfs_defrag_root(root); - if (ret) - goto out; - ret = btrfs_defrag_root(root->fs_info->extent_root); - break; - case S_IFREG: - if (!(file->f_mode & FMODE_WRITE)) { - ret = -EINVAL; - goto out; - } - - range = kzalloc(sizeof(*range), GFP_KERNEL); - if (!range) { - ret = -ENOMEM; - goto out; - } - - if (argp) { - if (copy_from_user(range, argp, - sizeof(*range))) { - ret = -EFAULT; - kfree(range); - goto out; - } - /* compression requires us to start the IO */ - if ((range->flags & BTRFS_DEFRAG_RANGE_COMPRESS)) { - range->flags |= BTRFS_DEFRAG_RANGE_START_IO; - range->extent_thresh = (u32)-1; - } - } else { - /* the rest are all set to zero by kzalloc */ - range->len = (u64)-1; - } - ret = btrfs_defrag_file(file_inode(file), file, - range, 0, 0); - if (ret > 0) - ret = 0; - kfree(range); - break; - default: - ret = -EINVAL; - } -out: - mnt_drop_write_file(file); - return ret; -} - -static long btrfs_ioctl_add_dev(struct btrfs_root *root, void __user *arg) -{ - struct btrfs_ioctl_vol_args *vol_args; - int ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, - 1)) { - return BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; - } - - mutex_lock(&root->fs_info->volume_mutex); - vol_args = memdup_user(arg, sizeof(*vol_args)); - if (IS_ERR(vol_args)) { - ret = PTR_ERR(vol_args); - goto out; - } - - vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; - ret = btrfs_init_new_device(root, vol_args->name); - - if (!ret) - btrfs_info(root->fs_info, "disk added %s",vol_args->name); - - kfree(vol_args); -out: - mutex_unlock(&root->fs_info->volume_mutex); - atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); - return ret; -} - -static long btrfs_ioctl_rm_dev_v2(struct file *file, void __user *arg) -{ - struct btrfs_root *root = BTRFS_I(file_inode(file))->root; - struct btrfs_ioctl_vol_args_v2 *vol_args; - int ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - ret = mnt_want_write_file(file); - if (ret) - return ret; - - vol_args = memdup_user(arg, sizeof(*vol_args)); - if (IS_ERR(vol_args)) { - ret = PTR_ERR(vol_args); - goto err_drop; - } - - /* Check for compatibility reject unknown flags */ - if (vol_args->flags & ~BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED) - return -EOPNOTSUPP; - - if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, - 1)) { - ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; - goto out; - } - - mutex_lock(&root->fs_info->volume_mutex); - if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) { - ret = btrfs_rm_device(root, NULL, vol_args->devid); - } else { - vol_args->name[BTRFS_SUBVOL_NAME_MAX] = '\0'; - ret = btrfs_rm_device(root, vol_args->name, 0); - } - mutex_unlock(&root->fs_info->volume_mutex); - atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); - - if (!ret) { - if (vol_args->flags & BTRFS_DEVICE_SPEC_BY_ID) - btrfs_info(root->fs_info, "device deleted: id %llu", - vol_args->devid); - else - btrfs_info(root->fs_info, "device deleted: %s", - vol_args->name); - } -out: - kfree(vol_args); -err_drop: - mnt_drop_write_file(file); - return ret; -} - -static long btrfs_ioctl_rm_dev(struct file *file, void __user *arg) -{ - struct btrfs_root *root = BTRFS_I(file_inode(file))->root; - struct btrfs_ioctl_vol_args *vol_args; - int ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - ret = mnt_want_write_file(file); - if (ret) - return ret; - - if (atomic_xchg(&root->fs_info->mutually_exclusive_operation_running, - 1)) { - ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; - goto out_drop_write; - } - - vol_args = memdup_user(arg, sizeof(*vol_args)); - if (IS_ERR(vol_args)) { - ret = PTR_ERR(vol_args); - goto out; - } - - vol_args->name[BTRFS_PATH_NAME_MAX] = '\0'; - mutex_lock(&root->fs_info->volume_mutex); - ret = btrfs_rm_device(root, vol_args->name, 0); - mutex_unlock(&root->fs_info->volume_mutex); - - if (!ret) - btrfs_info(root->fs_info, "disk deleted %s",vol_args->name); - kfree(vol_args); -out: - atomic_set(&root->fs_info->mutually_exclusive_operation_running, 0); -out_drop_write: - mnt_drop_write_file(file); - - return ret; -} - -static long btrfs_ioctl_fs_info(struct btrfs_root *root, void __user *arg) -{ - struct btrfs_ioctl_fs_info_args *fi_args; - struct btrfs_device *device; - struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; - int ret = 0; - - fi_args = kzalloc(sizeof(*fi_args), GFP_KERNEL); - if (!fi_args) - return -ENOMEM; - - mutex_lock(&fs_devices->device_list_mutex); - fi_args->num_devices = fs_devices->num_devices; - memcpy(&fi_args->fsid, root->fs_info->fsid, sizeof(fi_args->fsid)); - - list_for_each_entry(device, &fs_devices->devices, dev_list) { - if (device->devid > fi_args->max_id) - fi_args->max_id = device->devid; - } - mutex_unlock(&fs_devices->device_list_mutex); - - fi_args->nodesize = root->fs_info->super_copy->nodesize; - fi_args->sectorsize = root->fs_info->super_copy->sectorsize; - fi_args->clone_alignment = root->fs_info->super_copy->sectorsize; - - if (copy_to_user(arg, fi_args, sizeof(*fi_args))) - ret = -EFAULT; - - kfree(fi_args); - return ret; -} - -static long btrfs_ioctl_dev_info(struct btrfs_root *root, void __user *arg) -{ - struct btrfs_ioctl_dev_info_args *di_args; - struct btrfs_device *dev; - struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; - int ret = 0; - char *s_uuid = NULL; - - di_args = memdup_user(arg, sizeof(*di_args)); - if (IS_ERR(di_args)) - return PTR_ERR(di_args); - - if (!btrfs_is_empty_uuid(di_args->uuid)) - s_uuid = di_args->uuid; - - mutex_lock(&fs_devices->device_list_mutex); - dev = btrfs_find_device(root->fs_info, di_args->devid, s_uuid, NULL); - - if (!dev) { - ret = -ENODEV; - goto out; - } - - di_args->devid = dev->devid; - di_args->bytes_used = btrfs_device_get_bytes_used(dev); - di_args->total_bytes = btrfs_device_get_total_bytes(dev); - memcpy(di_args->uuid, dev->uuid, sizeof(di_args->uuid)); - if (dev->name) { - struct rcu_string *name; - - rcu_read_lock(); - name = rcu_dereference(dev->name); - strncpy(di_args->path, name->str, sizeof(di_args->path)); - rcu_read_unlock(); - di_args->path[sizeof(di_args->path) - 1] = 0; - } else { - di_args->path[0] = '\0'; - } - -out: - mutex_unlock(&fs_devices->device_list_mutex); - if (ret == 0 && copy_to_user(arg, di_args, sizeof(*di_args))) - ret = -EFAULT; - - kfree(di_args); - return ret; -} - -static struct page *extent_same_get_page(struct inode *inode, pgoff_t index) -{ - struct page *page; - - page = grab_cache_page(inode->i_mapping, index); - if (!page) - return ERR_PTR(-ENOMEM); - - if (!PageUptodate(page)) { - int ret; - - ret = btrfs_readpage(NULL, page); - if (ret) - return ERR_PTR(ret); - lock_page(page); - if (!PageUptodate(page)) { - unlock_page(page); - put_page(page); - return ERR_PTR(-EIO); - } - if (page->mapping != inode->i_mapping) { - unlock_page(page); - put_page(page); - return ERR_PTR(-EAGAIN); - } - } - - return page; -} - -static int gather_extent_pages(struct inode *inode, struct page **pages, - int num_pages, u64 off) -{ - int i; - pgoff_t index = off >> PAGE_SHIFT; - - for (i = 0; i < num_pages; i++) { -again: - pages[i] = extent_same_get_page(inode, index + i); - if (IS_ERR(pages[i])) { - int err = PTR_ERR(pages[i]); - - if (err == -EAGAIN) - goto again; - pages[i] = NULL; - return err; - } - } - return 0; -} - -static int lock_extent_range(struct inode *inode, u64 off, u64 len, - bool retry_range_locking) -{ - /* - * Do any pending delalloc/csum calculations on inode, one way or - * another, and lock file content. - * The locking order is: - * - * 1) pages - * 2) range in the inode's io tree - */ - while (1) { - struct btrfs_ordered_extent *ordered; - lock_extent(&BTRFS_I(inode)->io_tree, off, off + len - 1); - ordered = btrfs_lookup_first_ordered_extent(inode, - off + len - 1); - if ((!ordered || - ordered->file_offset + ordered->len <= off || - ordered->file_offset >= off + len) && - !test_range_bit(&BTRFS_I(inode)->io_tree, off, - off + len - 1, EXTENT_DELALLOC, 0, NULL)) { - if (ordered) - btrfs_put_ordered_extent(ordered); - break; - } - unlock_extent(&BTRFS_I(inode)->io_tree, off, off + len - 1); - if (ordered) - btrfs_put_ordered_extent(ordered); - if (!retry_range_locking) - return -EAGAIN; - btrfs_wait_ordered_range(inode, off, len); - } - return 0; -} - -static void btrfs_double_inode_unlock(struct inode *inode1, struct inode *inode2) -{ - inode_unlock(inode1); - inode_unlock(inode2); -} - -static void btrfs_double_inode_lock(struct inode *inode1, struct inode *inode2) -{ - if (inode1 < inode2) - swap(inode1, inode2); - - inode_lock_nested(inode1, I_MUTEX_PARENT); - inode_lock_nested(inode2, I_MUTEX_CHILD); -} - -static void btrfs_double_extent_unlock(struct inode *inode1, u64 loff1, - struct inode *inode2, u64 loff2, u64 len) -{ - unlock_extent(&BTRFS_I(inode1)->io_tree, loff1, loff1 + len - 1); - unlock_extent(&BTRFS_I(inode2)->io_tree, loff2, loff2 + len - 1); -} - -static int btrfs_double_extent_lock(struct inode *inode1, u64 loff1, - struct inode *inode2, u64 loff2, u64 len, - bool retry_range_locking) -{ - int ret; - - if (inode1 < inode2) { - swap(inode1, inode2); - swap(loff1, loff2); - } - ret = lock_extent_range(inode1, loff1, len, retry_range_locking); - if (ret) - return ret; - ret = lock_extent_range(inode2, loff2, len, retry_range_locking); - if (ret) - unlock_extent(&BTRFS_I(inode1)->io_tree, loff1, - loff1 + len - 1); - return ret; -} - -struct cmp_pages { - int num_pages; - struct page **src_pages; - struct page **dst_pages; -}; - -static void btrfs_cmp_data_free(struct cmp_pages *cmp) -{ - int i; - struct page *pg; - - for (i = 0; i < cmp->num_pages; i++) { - pg = cmp->src_pages[i]; - if (pg) { - unlock_page(pg); - put_page(pg); - } - pg = cmp->dst_pages[i]; - if (pg) { - unlock_page(pg); - put_page(pg); - } - } - kfree(cmp->src_pages); - kfree(cmp->dst_pages); -} - -static int btrfs_cmp_data_prepare(struct inode *src, u64 loff, - struct inode *dst, u64 dst_loff, - u64 len, struct cmp_pages *cmp) -{ - int ret; - int num_pages = PAGE_ALIGN(len) >> PAGE_SHIFT; - struct page **src_pgarr, **dst_pgarr; - - /* - * We must gather up all the pages before we initiate our - * extent locking. We use an array for the page pointers. Size - * of the array is bounded by len, which is in turn bounded by - * BTRFS_MAX_DEDUPE_LEN. - */ - src_pgarr = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL); - dst_pgarr = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL); - if (!src_pgarr || !dst_pgarr) { - kfree(src_pgarr); - kfree(dst_pgarr); - return -ENOMEM; - } - cmp->num_pages = num_pages; - cmp->src_pages = src_pgarr; - cmp->dst_pages = dst_pgarr; - - ret = gather_extent_pages(src, cmp->src_pages, cmp->num_pages, loff); - if (ret) - goto out; - - ret = gather_extent_pages(dst, cmp->dst_pages, cmp->num_pages, dst_loff); - -out: - if (ret) - btrfs_cmp_data_free(cmp); - return 0; -} - -static int btrfs_cmp_data(struct inode *src, u64 loff, struct inode *dst, - u64 dst_loff, u64 len, struct cmp_pages *cmp) -{ - int ret = 0; - int i; - struct page *src_page, *dst_page; - unsigned int cmp_len = PAGE_SIZE; - void *addr, *dst_addr; - - i = 0; - while (len) { - if (len < PAGE_SIZE) - cmp_len = len; - - BUG_ON(i >= cmp->num_pages); - - src_page = cmp->src_pages[i]; - dst_page = cmp->dst_pages[i]; - ASSERT(PageLocked(src_page)); - ASSERT(PageLocked(dst_page)); - - addr = kmap_atomic(src_page); - dst_addr = kmap_atomic(dst_page); - - flush_dcache_page(src_page); - flush_dcache_page(dst_page); - - if (memcmp(addr, dst_addr, cmp_len)) - ret = -EBADE; - - kunmap_atomic(addr); - kunmap_atomic(dst_addr); - - if (ret) - break; - - len -= cmp_len; - i++; - } - - return ret; -} - -static int extent_same_check_offsets(struct inode *inode, u64 off, u64 *plen, - u64 olen) -{ - u64 len = *plen; - u64 bs = BTRFS_I(inode)->root->fs_info->sb->s_blocksize; - - if (off + olen > inode->i_size || off + olen < off) - return -EINVAL; - - /* if we extend to eof, continue to block boundary */ - if (off + len == inode->i_size) - *plen = len = ALIGN(inode->i_size, bs) - off; - - /* Check that we are block aligned - btrfs_clone() requires this */ - if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs)) - return -EINVAL; - - return 0; -} - -static int btrfs_extent_same(struct inode *src, u64 loff, u64 olen, - struct inode *dst, u64 dst_loff) -{ - int ret; - u64 len = olen; - struct cmp_pages cmp; - int same_inode = 0; - u64 same_lock_start = 0; - u64 same_lock_len = 0; - - if (src == dst) - same_inode = 1; - - if (len == 0) - return 0; - - if (same_inode) { - inode_lock(src); - - ret = extent_same_check_offsets(src, loff, &len, olen); - if (ret) - goto out_unlock; - ret = extent_same_check_offsets(src, dst_loff, &len, olen); - if (ret) - goto out_unlock; - - /* - * Single inode case wants the same checks, except we - * don't want our length pushed out past i_size as - * comparing that data range makes no sense. - * - * extent_same_check_offsets() will do this for an - * unaligned length at i_size, so catch it here and - * reject the request. - * - * This effectively means we require aligned extents - * for the single-inode case, whereas the other cases - * allow an unaligned length so long as it ends at - * i_size. - */ - if (len != olen) { - ret = -EINVAL; - goto out_unlock; - } - - /* Check for overlapping ranges */ - if (dst_loff + len > loff && dst_loff < loff + len) { - ret = -EINVAL; - goto out_unlock; - } - - same_lock_start = min_t(u64, loff, dst_loff); - same_lock_len = max_t(u64, loff, dst_loff) + len - same_lock_start; - } else { - btrfs_double_inode_lock(src, dst); - - ret = extent_same_check_offsets(src, loff, &len, olen); - if (ret) - goto out_unlock; - - ret = extent_same_check_offsets(dst, dst_loff, &len, olen); - if (ret) - goto out_unlock; - } - - /* don't make the dst file partly checksummed */ - if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) != - (BTRFS_I(dst)->flags & BTRFS_INODE_NODATASUM)) { - ret = -EINVAL; - goto out_unlock; - } - -again: - ret = btrfs_cmp_data_prepare(src, loff, dst, dst_loff, olen, &cmp); - if (ret) - goto out_unlock; - - if (same_inode) - ret = lock_extent_range(src, same_lock_start, same_lock_len, - false); - else - ret = btrfs_double_extent_lock(src, loff, dst, dst_loff, len, - false); - /* - * If one of the inodes has dirty pages in the respective range or - * ordered extents, we need to flush dellaloc and wait for all ordered - * extents in the range. We must unlock the pages and the ranges in the - * io trees to avoid deadlocks when flushing delalloc (requires locking - * pages) and when waiting for ordered extents to complete (they require - * range locking). - */ - if (ret == -EAGAIN) { - /* - * Ranges in the io trees already unlocked. Now unlock all - * pages before waiting for all IO to complete. - */ - btrfs_cmp_data_free(&cmp); - if (same_inode) { - btrfs_wait_ordered_range(src, same_lock_start, - same_lock_len); - } else { - btrfs_wait_ordered_range(src, loff, len); - btrfs_wait_ordered_range(dst, dst_loff, len); - } - goto again; - } - ASSERT(ret == 0); - if (WARN_ON(ret)) { - /* ranges in the io trees already unlocked */ - btrfs_cmp_data_free(&cmp); - return ret; - } - - /* pass original length for comparison so we stay within i_size */ - ret = btrfs_cmp_data(src, loff, dst, dst_loff, olen, &cmp); - if (ret == 0) - ret = btrfs_clone(src, dst, loff, olen, len, dst_loff, 1); - - if (same_inode) - unlock_extent(&BTRFS_I(src)->io_tree, same_lock_start, - same_lock_start + same_lock_len - 1); - else - btrfs_double_extent_unlock(src, loff, dst, dst_loff, len); - - btrfs_cmp_data_free(&cmp); -out_unlock: - if (same_inode) - inode_unlock(src); - else - btrfs_double_inode_unlock(src, dst); - - return ret; -} - -#define BTRFS_MAX_DEDUPE_LEN SZ_16M - -ssize_t btrfs_dedupe_file_range(struct file *src_file, u64 loff, u64 olen, - struct file *dst_file, u64 dst_loff) -{ - struct inode *src = file_inode(src_file); - struct inode *dst = file_inode(dst_file); - u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize; - ssize_t res; - - if (olen > BTRFS_MAX_DEDUPE_LEN) - olen = BTRFS_MAX_DEDUPE_LEN; - - if (WARN_ON_ONCE(bs < PAGE_SIZE)) { - /* - * Btrfs does not support blocksize < page_size. As a - * result, btrfs_cmp_data() won't correctly handle - * this situation without an update. - */ - return -EINVAL; - } - - res = btrfs_extent_same(src, loff, olen, dst, dst_loff); - if (res) - return res; - return olen; -} - -static int clone_finish_inode_update(struct btrfs_trans_handle *trans, - struct inode *inode, - u64 endoff, - const u64 destoff, - const u64 olen, - int no_time_update) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - int ret; - - inode_inc_iversion(inode); - if (!no_time_update) - inode->i_mtime = inode->i_ctime = current_time(inode); - /* - * We round up to the block size at eof when determining which - * extents to clone above, but shouldn't round up the file size. - */ - if (endoff > destoff + olen) - endoff = destoff + olen; - if (endoff > inode->i_size) - btrfs_i_size_write(inode, endoff); - - ret = btrfs_update_inode(trans, root, inode); - if (ret) { - btrfs_abort_transaction(trans, ret); - btrfs_end_transaction(trans, root); - goto out; - } - ret = btrfs_end_transaction(trans, root); -out: - return ret; -} - -static void clone_update_extent_map(struct inode *inode, - const struct btrfs_trans_handle *trans, - const struct btrfs_path *path, - const u64 hole_offset, - const u64 hole_len) -{ - struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; - struct extent_map *em; - int ret; - - em = alloc_extent_map(); - if (!em) { - set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, - &BTRFS_I(inode)->runtime_flags); - return; - } - - if (path) { - struct btrfs_file_extent_item *fi; - - fi = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_file_extent_item); - btrfs_extent_item_to_extent_map(inode, path, fi, false, em); - em->generation = -1; - if (btrfs_file_extent_type(path->nodes[0], fi) == - BTRFS_FILE_EXTENT_INLINE) - set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, - &BTRFS_I(inode)->runtime_flags); - } else { - em->start = hole_offset; - em->len = hole_len; - em->ram_bytes = em->len; - em->orig_start = hole_offset; - em->block_start = EXTENT_MAP_HOLE; - em->block_len = 0; - em->orig_block_len = 0; - em->compress_type = BTRFS_COMPRESS_NONE; - em->generation = trans->transid; - } - - while (1) { - write_lock(&em_tree->lock); - ret = add_extent_mapping(em_tree, em, 1); - write_unlock(&em_tree->lock); - if (ret != -EEXIST) { - free_extent_map(em); - break; - } - btrfs_drop_extent_cache(inode, em->start, - em->start + em->len - 1, 0); - } - - if (ret) - set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, - &BTRFS_I(inode)->runtime_flags); -} - -/* - * Make sure we do not end up inserting an inline extent into a file that has - * already other (non-inline) extents. If a file has an inline extent it can - * not have any other extents and the (single) inline extent must start at the - * file offset 0. Failing to respect these rules will lead to file corruption, - * resulting in EIO errors on read/write operations, hitting BUG_ON's in mm, etc - * - * We can have extents that have been already written to disk or we can have - * dirty ranges still in delalloc, in which case the extent maps and items are - * created only when we run delalloc, and the delalloc ranges might fall outside - * the range we are currently locking in the inode's io tree. So we check the - * inode's i_size because of that (i_size updates are done while holding the - * i_mutex, which we are holding here). - * We also check to see if the inode has a size not greater than "datal" but has - * extents beyond it, due to an fallocate with FALLOC_FL_KEEP_SIZE (and we are - * protected against such concurrent fallocate calls by the i_mutex). - * - * If the file has no extents but a size greater than datal, do not allow the - * copy because we would need turn the inline extent into a non-inline one (even - * with NO_HOLES enabled). If we find our destination inode only has one inline - * extent, just overwrite it with the source inline extent if its size is less - * than the source extent's size, or we could copy the source inline extent's - * data into the destination inode's inline extent if the later is greater then - * the former. - */ -static int clone_copy_inline_extent(struct inode *src, - struct inode *dst, - struct btrfs_trans_handle *trans, - struct btrfs_path *path, - struct btrfs_key *new_key, - const u64 drop_start, - const u64 datal, - const u64 skip, - const u64 size, - char *inline_data) -{ - struct btrfs_root *root = BTRFS_I(dst)->root; - const u64 aligned_end = ALIGN(new_key->offset + datal, - root->sectorsize); - int ret; - struct btrfs_key key; - - if (new_key->offset > 0) - return -EOPNOTSUPP; - - key.objectid = btrfs_ino(dst); - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = 0; - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) { - return ret; - } else if (ret > 0) { - if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) - return ret; - else if (ret > 0) - goto copy_inline_extent; - } - btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); - if (key.objectid == btrfs_ino(dst) && - key.type == BTRFS_EXTENT_DATA_KEY) { - ASSERT(key.offset > 0); - return -EOPNOTSUPP; - } - } else if (i_size_read(dst) <= datal) { - struct btrfs_file_extent_item *ei; - u64 ext_len; - - /* - * If the file size is <= datal, make sure there are no other - * extents following (can happen do to an fallocate call with - * the flag FALLOC_FL_KEEP_SIZE). - */ - ei = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_file_extent_item); - /* - * If it's an inline extent, it can not have other extents - * following it. - */ - if (btrfs_file_extent_type(path->nodes[0], ei) == - BTRFS_FILE_EXTENT_INLINE) - goto copy_inline_extent; - - ext_len = btrfs_file_extent_num_bytes(path->nodes[0], ei); - if (ext_len > aligned_end) - return -EOPNOTSUPP; - - ret = btrfs_next_item(root, path); - if (ret < 0) { - return ret; - } else if (ret == 0) { - btrfs_item_key_to_cpu(path->nodes[0], &key, - path->slots[0]); - if (key.objectid == btrfs_ino(dst) && - key.type == BTRFS_EXTENT_DATA_KEY) - return -EOPNOTSUPP; - } - } - -copy_inline_extent: - /* - * We have no extent items, or we have an extent at offset 0 which may - * or may not be inlined. All these cases are dealt the same way. - */ - if (i_size_read(dst) > datal) { - /* - * If the destination inode has an inline extent... - * This would require copying the data from the source inline - * extent into the beginning of the destination's inline extent. - * But this is really complex, both extents can be compressed - * or just one of them, which would require decompressing and - * re-compressing data (which could increase the new compressed - * size, not allowing the compressed data to fit anymore in an - * inline extent). - * So just don't support this case for now (it should be rare, - * we are not really saving space when cloning inline extents). - */ - return -EOPNOTSUPP; - } - - btrfs_release_path(path); - ret = btrfs_drop_extents(trans, root, dst, drop_start, aligned_end, 1); - if (ret) - return ret; - ret = btrfs_insert_empty_item(trans, root, path, new_key, size); - if (ret) - return ret; - - if (skip) { - const u32 start = btrfs_file_extent_calc_inline_size(0); - - memmove(inline_data + start, inline_data + start + skip, datal); - } - - write_extent_buffer(path->nodes[0], inline_data, - btrfs_item_ptr_offset(path->nodes[0], - path->slots[0]), - size); - inode_add_bytes(dst, datal); - - return 0; -} - -/** - * btrfs_clone() - clone a range from inode file to another - * - * @src: Inode to clone from - * @inode: Inode to clone to - * @off: Offset within source to start clone from - * @olen: Original length, passed by user, of range to clone - * @olen_aligned: Block-aligned value of olen - * @destoff: Offset within @inode to start clone - * @no_time_update: Whether to update mtime/ctime on the target inode - */ -static int btrfs_clone(struct inode *src, struct inode *inode, - const u64 off, const u64 olen, const u64 olen_aligned, - const u64 destoff, int no_time_update) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_path *path = NULL; - struct extent_buffer *leaf; - struct btrfs_trans_handle *trans; - char *buf = NULL; - struct btrfs_key key; - u32 nritems; - int slot; - int ret; - const u64 len = olen_aligned; - u64 last_dest_end = destoff; - - ret = -ENOMEM; - buf = kmalloc(root->nodesize, GFP_KERNEL | __GFP_NOWARN); - if (!buf) { - buf = vmalloc(root->nodesize); - if (!buf) - return ret; - } - - path = btrfs_alloc_path(); - if (!path) { - kvfree(buf); - return ret; - } - - path->reada = READA_FORWARD; - /* clone data */ - key.objectid = btrfs_ino(src); - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = off; - - while (1) { - u64 next_key_min_offset = key.offset + 1; - - /* - * note the key will change type as we walk through the - * tree. - */ - path->leave_spinning = 1; - ret = btrfs_search_slot(NULL, BTRFS_I(src)->root, &key, path, - 0, 0); - if (ret < 0) - goto out; - /* - * First search, if no extent item that starts at offset off was - * found but the previous item is an extent item, it's possible - * it might overlap our target range, therefore process it. - */ - if (key.offset == off && ret > 0 && path->slots[0] > 0) { - btrfs_item_key_to_cpu(path->nodes[0], &key, - path->slots[0] - 1); - if (key.type == BTRFS_EXTENT_DATA_KEY) - path->slots[0]--; - } - - nritems = btrfs_header_nritems(path->nodes[0]); -process_slot: - if (path->slots[0] >= nritems) { - ret = btrfs_next_leaf(BTRFS_I(src)->root, path); - if (ret < 0) - goto out; - if (ret > 0) - break; - nritems = btrfs_header_nritems(path->nodes[0]); - } - leaf = path->nodes[0]; - slot = path->slots[0]; - - btrfs_item_key_to_cpu(leaf, &key, slot); - if (key.type > BTRFS_EXTENT_DATA_KEY || - key.objectid != btrfs_ino(src)) - break; - - if (key.type == BTRFS_EXTENT_DATA_KEY) { - struct btrfs_file_extent_item *extent; - int type; - u32 size; - struct btrfs_key new_key; - u64 disko = 0, diskl = 0; - u64 datao = 0, datal = 0; - u8 comp; - u64 drop_start; - - extent = btrfs_item_ptr(leaf, slot, - struct btrfs_file_extent_item); - comp = btrfs_file_extent_compression(leaf, extent); - type = btrfs_file_extent_type(leaf, extent); - if (type == BTRFS_FILE_EXTENT_REG || - type == BTRFS_FILE_EXTENT_PREALLOC) { - disko = btrfs_file_extent_disk_bytenr(leaf, - extent); - diskl = btrfs_file_extent_disk_num_bytes(leaf, - extent); - datao = btrfs_file_extent_offset(leaf, extent); - datal = btrfs_file_extent_num_bytes(leaf, - extent); - } else if (type == BTRFS_FILE_EXTENT_INLINE) { - /* take upper bound, may be compressed */ - datal = btrfs_file_extent_ram_bytes(leaf, - extent); - } - - /* - * The first search might have left us at an extent - * item that ends before our target range's start, can - * happen if we have holes and NO_HOLES feature enabled. - */ - if (key.offset + datal <= off) { - path->slots[0]++; - goto process_slot; - } else if (key.offset >= off + len) { - break; - } - next_key_min_offset = key.offset + datal; - size = btrfs_item_size_nr(leaf, slot); - read_extent_buffer(leaf, buf, - btrfs_item_ptr_offset(leaf, slot), - size); - - btrfs_release_path(path); - path->leave_spinning = 0; - - memcpy(&new_key, &key, sizeof(new_key)); - new_key.objectid = btrfs_ino(inode); - if (off <= key.offset) - new_key.offset = key.offset + destoff - off; - else - new_key.offset = destoff; - - /* - * Deal with a hole that doesn't have an extent item - * that represents it (NO_HOLES feature enabled). - * This hole is either in the middle of the cloning - * range or at the beginning (fully overlaps it or - * partially overlaps it). - */ - if (new_key.offset != last_dest_end) - drop_start = last_dest_end; - else - drop_start = new_key.offset; - - /* - * 1 - adjusting old extent (we may have to split it) - * 1 - add new extent - * 1 - inode update - */ - trans = btrfs_start_transaction(root, 3); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out; - } - - if (type == BTRFS_FILE_EXTENT_REG || - type == BTRFS_FILE_EXTENT_PREALLOC) { - /* - * a | --- range to clone ---| b - * | ------------- extent ------------- | - */ - - /* subtract range b */ - if (key.offset + datal > off + len) - datal = off + len - key.offset; - - /* subtract range a */ - if (off > key.offset) { - datao += off - key.offset; - datal -= off - key.offset; - } - - ret = btrfs_drop_extents(trans, root, inode, - drop_start, - new_key.offset + datal, - 1); - if (ret) { - if (ret != -EOPNOTSUPP) - btrfs_abort_transaction(trans, - ret); - btrfs_end_transaction(trans, root); - goto out; - } - - ret = btrfs_insert_empty_item(trans, root, path, - &new_key, size); - if (ret) { - btrfs_abort_transaction(trans, ret); - btrfs_end_transaction(trans, root); - goto out; - } - - leaf = path->nodes[0]; - slot = path->slots[0]; - write_extent_buffer(leaf, buf, - btrfs_item_ptr_offset(leaf, slot), - size); - - extent = btrfs_item_ptr(leaf, slot, - struct btrfs_file_extent_item); - - /* disko == 0 means it's a hole */ - if (!disko) - datao = 0; - - btrfs_set_file_extent_offset(leaf, extent, - datao); - btrfs_set_file_extent_num_bytes(leaf, extent, - datal); - - if (disko) { - inode_add_bytes(inode, datal); - ret = btrfs_inc_extent_ref(trans, root, - disko, diskl, 0, - root->root_key.objectid, - btrfs_ino(inode), - new_key.offset - datao); - if (ret) { - btrfs_abort_transaction(trans, - ret); - btrfs_end_transaction(trans, - root); - goto out; - - } - } - } else if (type == BTRFS_FILE_EXTENT_INLINE) { - u64 skip = 0; - u64 trim = 0; - - if (off > key.offset) { - skip = off - key.offset; - new_key.offset += skip; - } - - if (key.offset + datal > off + len) - trim = key.offset + datal - (off + len); - - if (comp && (skip || trim)) { - ret = -EINVAL; - btrfs_end_transaction(trans, root); - goto out; - } - size -= skip + trim; - datal -= skip + trim; - - ret = clone_copy_inline_extent(src, inode, - trans, path, - &new_key, - drop_start, - datal, - skip, size, buf); - if (ret) { - if (ret != -EOPNOTSUPP) - btrfs_abort_transaction(trans, - ret); - btrfs_end_transaction(trans, root); - goto out; - } - leaf = path->nodes[0]; - slot = path->slots[0]; - } - - /* If we have an implicit hole (NO_HOLES feature). */ - if (drop_start < new_key.offset) - clone_update_extent_map(inode, trans, - NULL, drop_start, - new_key.offset - drop_start); - - clone_update_extent_map(inode, trans, path, 0, 0); - - btrfs_mark_buffer_dirty(leaf); - btrfs_release_path(path); - - last_dest_end = ALIGN(new_key.offset + datal, - root->sectorsize); - ret = clone_finish_inode_update(trans, inode, - last_dest_end, - destoff, olen, - no_time_update); - if (ret) - goto out; - if (new_key.offset + datal >= destoff + len) - break; - } - btrfs_release_path(path); - key.offset = next_key_min_offset; - - if (fatal_signal_pending(current)) { - ret = -EINTR; - goto out; - } - } - ret = 0; - - if (last_dest_end < destoff + len) { - /* - * We have an implicit hole (NO_HOLES feature is enabled) that - * fully or partially overlaps our cloning range at its end. - */ - btrfs_release_path(path); - - /* - * 1 - remove extent(s) - * 1 - inode update - */ - trans = btrfs_start_transaction(root, 2); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out; - } - ret = btrfs_drop_extents(trans, root, inode, - last_dest_end, destoff + len, 1); - if (ret) { - if (ret != -EOPNOTSUPP) - btrfs_abort_transaction(trans, ret); - btrfs_end_transaction(trans, root); - goto out; - } - clone_update_extent_map(inode, trans, NULL, last_dest_end, - destoff + len - last_dest_end); - ret = clone_finish_inode_update(trans, inode, destoff + len, - destoff, olen, no_time_update); - } - -out: - btrfs_free_path(path); - kvfree(buf); - return ret; -} - -static noinline int btrfs_clone_files(struct file *file, struct file *file_src, - u64 off, u64 olen, u64 destoff) -{ - struct inode *inode = file_inode(file); - struct inode *src = file_inode(file_src); - struct btrfs_root *root = BTRFS_I(inode)->root; - int ret; - u64 len = olen; - u64 bs = root->fs_info->sb->s_blocksize; - int same_inode = src == inode; - - /* - * TODO: - * - split compressed inline extents. annoying: we need to - * decompress into destination's address_space (the file offset - * may change, so source mapping won't do), then recompress (or - * otherwise reinsert) a subrange. - * - * - split destination inode's inline extents. The inline extents can - * be either compressed or non-compressed. - */ - - if (btrfs_root_readonly(root)) - return -EROFS; - - if (file_src->f_path.mnt != file->f_path.mnt || - src->i_sb != inode->i_sb) - return -EXDEV; - - /* don't make the dst file partly checksummed */ - if ((BTRFS_I(src)->flags & BTRFS_INODE_NODATASUM) != - (BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) - return -EINVAL; - - if (S_ISDIR(src->i_mode) || S_ISDIR(inode->i_mode)) - return -EISDIR; - - if (!same_inode) { - btrfs_double_inode_lock(src, inode); - } else { - inode_lock(src); - } - - /* determine range to clone */ - ret = -EINVAL; - if (off + len > src->i_size || off + len < off) - goto out_unlock; - if (len == 0) - olen = len = src->i_size - off; - /* if we extend to eof, continue to block boundary */ - if (off + len == src->i_size) - len = ALIGN(src->i_size, bs) - off; - - if (len == 0) { - ret = 0; - goto out_unlock; - } - - /* verify the end result is block aligned */ - if (!IS_ALIGNED(off, bs) || !IS_ALIGNED(off + len, bs) || - !IS_ALIGNED(destoff, bs)) - goto out_unlock; - - /* verify if ranges are overlapped within the same file */ - if (same_inode) { - if (destoff + len > off && destoff < off + len) - goto out_unlock; - } - - if (destoff > inode->i_size) { - ret = btrfs_cont_expand(inode, inode->i_size, destoff); - if (ret) - goto out_unlock; - } - - /* - * Lock the target range too. Right after we replace the file extent - * items in the fs tree (which now point to the cloned data), we might - * have a worker replace them with extent items relative to a write - * operation that was issued before this clone operation (i.e. confront - * with inode.c:btrfs_finish_ordered_io). - */ - if (same_inode) { - u64 lock_start = min_t(u64, off, destoff); - u64 lock_len = max_t(u64, off, destoff) + len - lock_start; - - ret = lock_extent_range(src, lock_start, lock_len, true); - } else { - ret = btrfs_double_extent_lock(src, off, inode, destoff, len, - true); - } - ASSERT(ret == 0); - if (WARN_ON(ret)) { - /* ranges in the io trees already unlocked */ - goto out_unlock; - } - - ret = btrfs_clone(src, inode, off, olen, len, destoff, 0); - - if (same_inode) { - u64 lock_start = min_t(u64, off, destoff); - u64 lock_end = max_t(u64, off, destoff) + len - 1; - - unlock_extent(&BTRFS_I(src)->io_tree, lock_start, lock_end); - } else { - btrfs_double_extent_unlock(src, off, inode, destoff, len); - } - /* - * Truncate page cache pages so that future reads will see the cloned - * data immediately and not the previous data. - */ - truncate_inode_pages_range(&inode->i_data, - round_down(destoff, PAGE_SIZE), - round_up(destoff + len, PAGE_SIZE) - 1); -out_unlock: - if (!same_inode) - btrfs_double_inode_unlock(src, inode); - else - inode_unlock(src); - return ret; -} - -ssize_t btrfs_copy_file_range(struct file *file_in, loff_t pos_in, - struct file *file_out, loff_t pos_out, - size_t len, unsigned int flags) -{ - ssize_t ret; - - ret = btrfs_clone_files(file_out, file_in, pos_in, len, pos_out); - if (ret == 0) - ret = len; - return ret; -} - -int btrfs_clone_file_range(struct file *src_file, loff_t off, - struct file *dst_file, loff_t destoff, u64 len) -{ - return btrfs_clone_files(dst_file, src_file, off, len, destoff); -} - -/* - * there are many ways the trans_start and trans_end ioctls can lead - * to deadlocks. They should only be used by applications that - * basically own the machine, and have a very in depth understanding - * of all the possible deadlocks and enospc problems. - */ -static long btrfs_ioctl_trans_start(struct file *file) -{ - struct inode *inode = file_inode(file); - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_trans_handle *trans; - int ret; - - ret = -EPERM; - if (!capable(CAP_SYS_ADMIN)) - goto out; - - ret = -EINPROGRESS; - if (file->private_data) - goto out; - - ret = -EROFS; - if (btrfs_root_readonly(root)) - goto out; - - ret = mnt_want_write_file(file); - if (ret) - goto out; - - atomic_inc(&root->fs_info->open_ioctl_trans); - - ret = -ENOMEM; - trans = btrfs_start_ioctl_transaction(root); - if (IS_ERR(trans)) - goto out_drop; - - file->private_data = trans; - return 0; - -out_drop: - atomic_dec(&root->fs_info->open_ioctl_trans); - mnt_drop_write_file(file); -out: - return ret; -} - -static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp) -{ - struct inode *inode = file_inode(file); - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_root *new_root; - struct btrfs_dir_item *di; - struct btrfs_trans_handle *trans; - struct btrfs_path *path; - struct btrfs_key location; - struct btrfs_disk_key disk_key; - u64 objectid = 0; - u64 dir_id; - int ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - ret = mnt_want_write_file(file); - if (ret) - return ret; - - if (copy_from_user(&objectid, argp, sizeof(objectid))) { - ret = -EFAULT; - goto out; - } - - if (!objectid) - objectid = BTRFS_FS_TREE_OBJECTID; - - location.objectid = objectid; - location.type = BTRFS_ROOT_ITEM_KEY; - location.offset = (u64)-1; - - new_root = btrfs_read_fs_root_no_name(root->fs_info, &location); - if (IS_ERR(new_root)) { - ret = PTR_ERR(new_root); - goto out; - } - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - path->leave_spinning = 1; - - trans = btrfs_start_transaction(root, 1); - if (IS_ERR(trans)) { - btrfs_free_path(path); - ret = PTR_ERR(trans); - goto out; - } - - dir_id = btrfs_super_root_dir(root->fs_info->super_copy); - di = btrfs_lookup_dir_item(trans, root->fs_info->tree_root, path, - dir_id, "default", 7, 1); - if (IS_ERR_OR_NULL(di)) { - btrfs_free_path(path); - btrfs_end_transaction(trans, root); - btrfs_err(new_root->fs_info, - "Umm, you don't have the default diritem, this isn't going to work"); - ret = -ENOENT; - goto out; - } - - btrfs_cpu_key_to_disk(&disk_key, &new_root->root_key); - btrfs_set_dir_item_key(path->nodes[0], di, &disk_key); - btrfs_mark_buffer_dirty(path->nodes[0]); - btrfs_free_path(path); - - btrfs_set_fs_incompat(root->fs_info, DEFAULT_SUBVOL); - btrfs_end_transaction(trans, root); -out: - mnt_drop_write_file(file); - return ret; -} - -void btrfs_get_block_group_info(struct list_head *groups_list, - struct btrfs_ioctl_space_info *space) -{ - struct btrfs_block_group_cache *block_group; - - space->total_bytes = 0; - space->used_bytes = 0; - space->flags = 0; - list_for_each_entry(block_group, groups_list, list) { - space->flags = block_group->flags; - space->total_bytes += block_group->key.offset; - space->used_bytes += - btrfs_block_group_used(&block_group->item); - } -} - -static long btrfs_ioctl_space_info(struct btrfs_root *root, void __user *arg) -{ - struct btrfs_ioctl_space_args space_args; - struct btrfs_ioctl_space_info space; - struct btrfs_ioctl_space_info *dest; - struct btrfs_ioctl_space_info *dest_orig; - struct btrfs_ioctl_space_info __user *user_dest; - struct btrfs_space_info *info; - u64 types[] = {BTRFS_BLOCK_GROUP_DATA, - BTRFS_BLOCK_GROUP_SYSTEM, - BTRFS_BLOCK_GROUP_METADATA, - BTRFS_BLOCK_GROUP_DATA | BTRFS_BLOCK_GROUP_METADATA}; - int num_types = 4; - int alloc_size; - int ret = 0; - u64 slot_count = 0; - int i, c; - - if (copy_from_user(&space_args, - (struct btrfs_ioctl_space_args __user *)arg, - sizeof(space_args))) - return -EFAULT; - - for (i = 0; i < num_types; i++) { - struct btrfs_space_info *tmp; - - info = NULL; - rcu_read_lock(); - list_for_each_entry_rcu(tmp, &root->fs_info->space_info, - list) { - if (tmp->flags == types[i]) { - info = tmp; - break; - } - } - rcu_read_unlock(); - - if (!info) - continue; - - down_read(&info->groups_sem); - for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) { - if (!list_empty(&info->block_groups[c])) - slot_count++; - } - up_read(&info->groups_sem); - } - - /* - * Global block reserve, exported as a space_info - */ - slot_count++; - - /* space_slots == 0 means they are asking for a count */ - if (space_args.space_slots == 0) { - space_args.total_spaces = slot_count; - goto out; - } - - slot_count = min_t(u64, space_args.space_slots, slot_count); - - alloc_size = sizeof(*dest) * slot_count; - - /* we generally have at most 6 or so space infos, one for each raid - * level. So, a whole page should be more than enough for everyone - */ - if (alloc_size > PAGE_SIZE) - return -ENOMEM; - - space_args.total_spaces = 0; - dest = kmalloc(alloc_size, GFP_KERNEL); - if (!dest) - return -ENOMEM; - dest_orig = dest; - - /* now we have a buffer to copy into */ - for (i = 0; i < num_types; i++) { - struct btrfs_space_info *tmp; - - if (!slot_count) - break; - - info = NULL; - rcu_read_lock(); - list_for_each_entry_rcu(tmp, &root->fs_info->space_info, - list) { - if (tmp->flags == types[i]) { - info = tmp; - break; - } - } - rcu_read_unlock(); - - if (!info) - continue; - down_read(&info->groups_sem); - for (c = 0; c < BTRFS_NR_RAID_TYPES; c++) { - if (!list_empty(&info->block_groups[c])) { - btrfs_get_block_group_info( - &info->block_groups[c], &space); - memcpy(dest, &space, sizeof(space)); - dest++; - space_args.total_spaces++; - slot_count--; - } - if (!slot_count) - break; - } - up_read(&info->groups_sem); - } - - /* - * Add global block reserve - */ - if (slot_count) { - struct btrfs_block_rsv *block_rsv = &root->fs_info->global_block_rsv; - - spin_lock(&block_rsv->lock); - space.total_bytes = block_rsv->size; - space.used_bytes = block_rsv->size - block_rsv->reserved; - spin_unlock(&block_rsv->lock); - space.flags = BTRFS_SPACE_INFO_GLOBAL_RSV; - memcpy(dest, &space, sizeof(space)); - space_args.total_spaces++; - } - - user_dest = (struct btrfs_ioctl_space_info __user *) - (arg + sizeof(struct btrfs_ioctl_space_args)); - - if (copy_to_user(user_dest, dest_orig, alloc_size)) - ret = -EFAULT; - - kfree(dest_orig); -out: - if (ret == 0 && copy_to_user(arg, &space_args, sizeof(space_args))) - ret = -EFAULT; - - return ret; -} - -/* - * there are many ways the trans_start and trans_end ioctls can lead - * to deadlocks. They should only be used by applications that - * basically own the machine, and have a very in depth understanding - * of all the possible deadlocks and enospc problems. - */ -long btrfs_ioctl_trans_end(struct file *file) -{ - struct inode *inode = file_inode(file); - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_trans_handle *trans; - - trans = file->private_data; - if (!trans) - return -EINVAL; - file->private_data = NULL; - - btrfs_end_transaction(trans, root); - - atomic_dec(&root->fs_info->open_ioctl_trans); - - mnt_drop_write_file(file); - return 0; -} - -static noinline long btrfs_ioctl_start_sync(struct btrfs_root *root, - void __user *argp) -{ - struct btrfs_trans_handle *trans; - u64 transid; - int ret; - - trans = btrfs_attach_transaction_barrier(root); - if (IS_ERR(trans)) { - if (PTR_ERR(trans) != -ENOENT) - return PTR_ERR(trans); - - /* No running transaction, don't bother */ - transid = root->fs_info->last_trans_committed; - goto out; - } - transid = trans->transid; - ret = btrfs_commit_transaction_async(trans, root, 0); - if (ret) { - btrfs_end_transaction(trans, root); - return ret; - } -out: - if (argp) - if (copy_to_user(argp, &transid, sizeof(transid))) - return -EFAULT; - return 0; -} - -static noinline long btrfs_ioctl_wait_sync(struct btrfs_root *root, - void __user *argp) -{ - u64 transid; - - if (argp) { - if (copy_from_user(&transid, argp, sizeof(transid))) - return -EFAULT; - } else { - transid = 0; /* current trans */ - } - return btrfs_wait_for_commit(root, transid); -} - -static long btrfs_ioctl_scrub(struct file *file, void __user *arg) -{ - struct btrfs_root *root = BTRFS_I(file_inode(file))->root; - struct btrfs_ioctl_scrub_args *sa; - int ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - sa = memdup_user(arg, sizeof(*sa)); - if (IS_ERR(sa)) - return PTR_ERR(sa); - - if (!(sa->flags & BTRFS_SCRUB_READONLY)) { - ret = mnt_want_write_file(file); - if (ret) - goto out; - } - - ret = btrfs_scrub_dev(root->fs_info, sa->devid, sa->start, sa->end, - &sa->progress, sa->flags & BTRFS_SCRUB_READONLY, - 0); - - if (copy_to_user(arg, sa, sizeof(*sa))) - ret = -EFAULT; - - if (!(sa->flags & BTRFS_SCRUB_READONLY)) - mnt_drop_write_file(file); -out: - kfree(sa); - return ret; -} - -static long btrfs_ioctl_scrub_cancel(struct btrfs_root *root, void __user *arg) -{ - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - return btrfs_scrub_cancel(root->fs_info); -} - -static long btrfs_ioctl_scrub_progress(struct btrfs_root *root, - void __user *arg) -{ - struct btrfs_ioctl_scrub_args *sa; - int ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - sa = memdup_user(arg, sizeof(*sa)); - if (IS_ERR(sa)) - return PTR_ERR(sa); - - ret = btrfs_scrub_progress(root, sa->devid, &sa->progress); - - if (copy_to_user(arg, sa, sizeof(*sa))) - ret = -EFAULT; - - kfree(sa); - return ret; -} - -static long btrfs_ioctl_get_dev_stats(struct btrfs_root *root, - void __user *arg) -{ - struct btrfs_ioctl_get_dev_stats *sa; - int ret; - - sa = memdup_user(arg, sizeof(*sa)); - if (IS_ERR(sa)) - return PTR_ERR(sa); - - if ((sa->flags & BTRFS_DEV_STATS_RESET) && !capable(CAP_SYS_ADMIN)) { - kfree(sa); - return -EPERM; - } - - ret = btrfs_get_dev_stats(root, sa); - - if (copy_to_user(arg, sa, sizeof(*sa))) - ret = -EFAULT; - - kfree(sa); - return ret; -} - -static long btrfs_ioctl_dev_replace(struct btrfs_root *root, void __user *arg) -{ - struct btrfs_ioctl_dev_replace_args *p; - int ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - p = memdup_user(arg, sizeof(*p)); - if (IS_ERR(p)) - return PTR_ERR(p); - - switch (p->cmd) { - case BTRFS_IOCTL_DEV_REPLACE_CMD_START: - if (root->fs_info->sb->s_flags & MS_RDONLY) { - ret = -EROFS; - goto out; - } - if (atomic_xchg( - &root->fs_info->mutually_exclusive_operation_running, - 1)) { - ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; - } else { - ret = btrfs_dev_replace_by_ioctl(root, p); - atomic_set( - &root->fs_info->mutually_exclusive_operation_running, - 0); - } - break; - case BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS: - btrfs_dev_replace_status(root->fs_info, p); - ret = 0; - break; - case BTRFS_IOCTL_DEV_REPLACE_CMD_CANCEL: - ret = btrfs_dev_replace_cancel(root->fs_info, p); - break; - default: - ret = -EINVAL; - break; - } - - if (copy_to_user(arg, p, sizeof(*p))) - ret = -EFAULT; -out: - kfree(p); - return ret; -} - -static long btrfs_ioctl_ino_to_path(struct btrfs_root *root, void __user *arg) -{ - int ret = 0; - int i; - u64 rel_ptr; - int size; - struct btrfs_ioctl_ino_path_args *ipa = NULL; - struct inode_fs_paths *ipath = NULL; - struct btrfs_path *path; - - if (!capable(CAP_DAC_READ_SEARCH)) - return -EPERM; - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - ipa = memdup_user(arg, sizeof(*ipa)); - if (IS_ERR(ipa)) { - ret = PTR_ERR(ipa); - ipa = NULL; - goto out; - } - - size = min_t(u32, ipa->size, 4096); - ipath = init_ipath(size, root, path); - if (IS_ERR(ipath)) { - ret = PTR_ERR(ipath); - ipath = NULL; - goto out; - } - - ret = paths_from_inode(ipa->inum, ipath); - if (ret < 0) - goto out; - - for (i = 0; i < ipath->fspath->elem_cnt; ++i) { - rel_ptr = ipath->fspath->val[i] - - (u64)(unsigned long)ipath->fspath->val; - ipath->fspath->val[i] = rel_ptr; - } - - ret = copy_to_user((void *)(unsigned long)ipa->fspath, - (void *)(unsigned long)ipath->fspath, size); - if (ret) { - ret = -EFAULT; - goto out; - } - -out: - btrfs_free_path(path); - free_ipath(ipath); - kfree(ipa); - - return ret; -} - -static int build_ino_list(u64 inum, u64 offset, u64 root, void *ctx) -{ - struct btrfs_data_container *inodes = ctx; - const size_t c = 3 * sizeof(u64); - - if (inodes->bytes_left >= c) { - inodes->bytes_left -= c; - inodes->val[inodes->elem_cnt] = inum; - inodes->val[inodes->elem_cnt + 1] = offset; - inodes->val[inodes->elem_cnt + 2] = root; - inodes->elem_cnt += 3; - } else { - inodes->bytes_missing += c - inodes->bytes_left; - inodes->bytes_left = 0; - inodes->elem_missed += 3; - } - - return 0; -} - -static long btrfs_ioctl_logical_to_ino(struct btrfs_root *root, - void __user *arg) -{ - int ret = 0; - int size; - struct btrfs_ioctl_logical_ino_args *loi; - struct btrfs_data_container *inodes = NULL; - struct btrfs_path *path = NULL; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - loi = memdup_user(arg, sizeof(*loi)); - if (IS_ERR(loi)) { - ret = PTR_ERR(loi); - loi = NULL; - goto out; - } - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - size = min_t(u32, loi->size, SZ_64K); - inodes = init_data_container(size); - if (IS_ERR(inodes)) { - ret = PTR_ERR(inodes); - inodes = NULL; - goto out; - } - - ret = iterate_inodes_from_logical(loi->logical, root->fs_info, path, - build_ino_list, inodes); - if (ret == -EINVAL) - ret = -ENOENT; - if (ret < 0) - goto out; - - ret = copy_to_user((void *)(unsigned long)loi->inodes, - (void *)(unsigned long)inodes, size); - if (ret) - ret = -EFAULT; - -out: - btrfs_free_path(path); - vfree(inodes); - kfree(loi); - - return ret; -} - -void update_ioctl_balance_args(struct btrfs_fs_info *fs_info, int lock, - struct btrfs_ioctl_balance_args *bargs) -{ - struct btrfs_balance_control *bctl = fs_info->balance_ctl; - - bargs->flags = bctl->flags; - - if (atomic_read(&fs_info->balance_running)) - bargs->state |= BTRFS_BALANCE_STATE_RUNNING; - if (atomic_read(&fs_info->balance_pause_req)) - bargs->state |= BTRFS_BALANCE_STATE_PAUSE_REQ; - if (atomic_read(&fs_info->balance_cancel_req)) - bargs->state |= BTRFS_BALANCE_STATE_CANCEL_REQ; - - memcpy(&bargs->data, &bctl->data, sizeof(bargs->data)); - memcpy(&bargs->meta, &bctl->meta, sizeof(bargs->meta)); - memcpy(&bargs->sys, &bctl->sys, sizeof(bargs->sys)); - - if (lock) { - spin_lock(&fs_info->balance_lock); - memcpy(&bargs->stat, &bctl->stat, sizeof(bargs->stat)); - spin_unlock(&fs_info->balance_lock); - } else { - memcpy(&bargs->stat, &bctl->stat, sizeof(bargs->stat)); - } -} - -static long btrfs_ioctl_balance(struct file *file, void __user *arg) -{ - struct btrfs_root *root = BTRFS_I(file_inode(file))->root; - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_ioctl_balance_args *bargs; - struct btrfs_balance_control *bctl; - bool need_unlock; /* for mut. excl. ops lock */ - int ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - ret = mnt_want_write_file(file); - if (ret) - return ret; - -again: - if (!atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)) { - mutex_lock(&fs_info->volume_mutex); - mutex_lock(&fs_info->balance_mutex); - need_unlock = true; - goto locked; - } - - /* - * mut. excl. ops lock is locked. Three possibilities: - * (1) some other op is running - * (2) balance is running - * (3) balance is paused -- special case (think resume) - */ - mutex_lock(&fs_info->balance_mutex); - if (fs_info->balance_ctl) { - /* this is either (2) or (3) */ - if (!atomic_read(&fs_info->balance_running)) { - mutex_unlock(&fs_info->balance_mutex); - if (!mutex_trylock(&fs_info->volume_mutex)) - goto again; - mutex_lock(&fs_info->balance_mutex); - - if (fs_info->balance_ctl && - !atomic_read(&fs_info->balance_running)) { - /* this is (3) */ - need_unlock = false; - goto locked; - } - - mutex_unlock(&fs_info->balance_mutex); - mutex_unlock(&fs_info->volume_mutex); - goto again; - } else { - /* this is (2) */ - mutex_unlock(&fs_info->balance_mutex); - ret = -EINPROGRESS; - goto out; - } - } else { - /* this is (1) */ - mutex_unlock(&fs_info->balance_mutex); - ret = BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS; - goto out; - } - -locked: - BUG_ON(!atomic_read(&fs_info->mutually_exclusive_operation_running)); - - if (arg) { - bargs = memdup_user(arg, sizeof(*bargs)); - if (IS_ERR(bargs)) { - ret = PTR_ERR(bargs); - goto out_unlock; - } - - if (bargs->flags & BTRFS_BALANCE_RESUME) { - if (!fs_info->balance_ctl) { - ret = -ENOTCONN; - goto out_bargs; - } - - bctl = fs_info->balance_ctl; - spin_lock(&fs_info->balance_lock); - bctl->flags |= BTRFS_BALANCE_RESUME; - spin_unlock(&fs_info->balance_lock); - - goto do_balance; - } - } else { - bargs = NULL; - } - - if (fs_info->balance_ctl) { - ret = -EINPROGRESS; - goto out_bargs; - } - - bctl = kzalloc(sizeof(*bctl), GFP_KERNEL); - if (!bctl) { - ret = -ENOMEM; - goto out_bargs; - } - - bctl->fs_info = fs_info; - if (arg) { - memcpy(&bctl->data, &bargs->data, sizeof(bctl->data)); - memcpy(&bctl->meta, &bargs->meta, sizeof(bctl->meta)); - memcpy(&bctl->sys, &bargs->sys, sizeof(bctl->sys)); - - bctl->flags = bargs->flags; - } else { - /* balance everything - no filters */ - bctl->flags |= BTRFS_BALANCE_TYPE_MASK; - } - - if (bctl->flags & ~(BTRFS_BALANCE_ARGS_MASK | BTRFS_BALANCE_TYPE_MASK)) { - ret = -EINVAL; - goto out_bctl; - } - -do_balance: - /* - * Ownership of bctl and mutually_exclusive_operation_running - * goes to to btrfs_balance. bctl is freed in __cancel_balance, - * or, if restriper was paused all the way until unmount, in - * free_fs_info. mutually_exclusive_operation_running is - * cleared in __cancel_balance. - */ - need_unlock = false; - - ret = btrfs_balance(bctl, bargs); - bctl = NULL; - - if (arg) { - if (copy_to_user(arg, bargs, sizeof(*bargs))) - ret = -EFAULT; - } - -out_bctl: - kfree(bctl); -out_bargs: - kfree(bargs); -out_unlock: - mutex_unlock(&fs_info->balance_mutex); - mutex_unlock(&fs_info->volume_mutex); - if (need_unlock) - atomic_set(&fs_info->mutually_exclusive_operation_running, 0); -out: - mnt_drop_write_file(file); - return ret; -} - -static long btrfs_ioctl_balance_ctl(struct btrfs_root *root, int cmd) -{ - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - switch (cmd) { - case BTRFS_BALANCE_CTL_PAUSE: - return btrfs_pause_balance(root->fs_info); - case BTRFS_BALANCE_CTL_CANCEL: - return btrfs_cancel_balance(root->fs_info); - } - - return -EINVAL; -} - -static long btrfs_ioctl_balance_progress(struct btrfs_root *root, - void __user *arg) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_ioctl_balance_args *bargs; - int ret = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - mutex_lock(&fs_info->balance_mutex); - if (!fs_info->balance_ctl) { - ret = -ENOTCONN; - goto out; - } - - bargs = kzalloc(sizeof(*bargs), GFP_KERNEL); - if (!bargs) { - ret = -ENOMEM; - goto out; - } - - update_ioctl_balance_args(fs_info, 1, bargs); - - if (copy_to_user(arg, bargs, sizeof(*bargs))) - ret = -EFAULT; - - kfree(bargs); -out: - mutex_unlock(&fs_info->balance_mutex); - return ret; -} - -static long btrfs_ioctl_quota_ctl(struct file *file, void __user *arg) -{ - struct btrfs_root *root = BTRFS_I(file_inode(file))->root; - struct btrfs_ioctl_quota_ctl_args *sa; - struct btrfs_trans_handle *trans = NULL; - int ret; - int err; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - ret = mnt_want_write_file(file); - if (ret) - return ret; - - sa = memdup_user(arg, sizeof(*sa)); - if (IS_ERR(sa)) { - ret = PTR_ERR(sa); - goto drop_write; - } - - down_write(&root->fs_info->subvol_sem); - trans = btrfs_start_transaction(root->fs_info->tree_root, 2); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out; - } - - switch (sa->cmd) { - case BTRFS_QUOTA_CTL_ENABLE: - ret = btrfs_quota_enable(trans, root->fs_info); - break; - case BTRFS_QUOTA_CTL_DISABLE: - ret = btrfs_quota_disable(trans, root->fs_info); - break; - default: - ret = -EINVAL; - break; - } - - err = btrfs_commit_transaction(trans, root->fs_info->tree_root); - if (err && !ret) - ret = err; -out: - kfree(sa); - up_write(&root->fs_info->subvol_sem); -drop_write: - mnt_drop_write_file(file); - return ret; -} - -static long btrfs_ioctl_qgroup_assign(struct file *file, void __user *arg) -{ - struct btrfs_root *root = BTRFS_I(file_inode(file))->root; - struct btrfs_ioctl_qgroup_assign_args *sa; - struct btrfs_trans_handle *trans; - int ret; - int err; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - ret = mnt_want_write_file(file); - if (ret) - return ret; - - sa = memdup_user(arg, sizeof(*sa)); - if (IS_ERR(sa)) { - ret = PTR_ERR(sa); - goto drop_write; - } - - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out; - } - - /* FIXME: check if the IDs really exist */ - if (sa->assign) { - ret = btrfs_add_qgroup_relation(trans, root->fs_info, - sa->src, sa->dst); - } else { - ret = btrfs_del_qgroup_relation(trans, root->fs_info, - sa->src, sa->dst); - } - - /* update qgroup status and info */ - err = btrfs_run_qgroups(trans, root->fs_info); - if (err < 0) - btrfs_handle_fs_error(root->fs_info, err, - "failed to update qgroup status and info"); - err = btrfs_end_transaction(trans, root); - if (err && !ret) - ret = err; - -out: - kfree(sa); -drop_write: - mnt_drop_write_file(file); - return ret; -} - -static long btrfs_ioctl_qgroup_create(struct file *file, void __user *arg) -{ - struct btrfs_root *root = BTRFS_I(file_inode(file))->root; - struct btrfs_ioctl_qgroup_create_args *sa; - struct btrfs_trans_handle *trans; - int ret; - int err; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - ret = mnt_want_write_file(file); - if (ret) - return ret; - - sa = memdup_user(arg, sizeof(*sa)); - if (IS_ERR(sa)) { - ret = PTR_ERR(sa); - goto drop_write; - } - - if (!sa->qgroupid) { - ret = -EINVAL; - goto out; - } - - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out; - } - - /* FIXME: check if the IDs really exist */ - if (sa->create) { - ret = btrfs_create_qgroup(trans, root->fs_info, sa->qgroupid); - } else { - ret = btrfs_remove_qgroup(trans, root->fs_info, sa->qgroupid); - } - - err = btrfs_end_transaction(trans, root); - if (err && !ret) - ret = err; - -out: - kfree(sa); -drop_write: - mnt_drop_write_file(file); - return ret; -} - -static long btrfs_ioctl_qgroup_limit(struct file *file, void __user *arg) -{ - struct btrfs_root *root = BTRFS_I(file_inode(file))->root; - struct btrfs_ioctl_qgroup_limit_args *sa; - struct btrfs_trans_handle *trans; - int ret; - int err; - u64 qgroupid; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - ret = mnt_want_write_file(file); - if (ret) - return ret; - - sa = memdup_user(arg, sizeof(*sa)); - if (IS_ERR(sa)) { - ret = PTR_ERR(sa); - goto drop_write; - } - - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out; - } - - qgroupid = sa->qgroupid; - if (!qgroupid) { - /* take the current subvol as qgroup */ - qgroupid = root->root_key.objectid; - } - - /* FIXME: check if the IDs really exist */ - ret = btrfs_limit_qgroup(trans, root->fs_info, qgroupid, &sa->lim); - - err = btrfs_end_transaction(trans, root); - if (err && !ret) - ret = err; - -out: - kfree(sa); -drop_write: - mnt_drop_write_file(file); - return ret; -} - -static long btrfs_ioctl_quota_rescan(struct file *file, void __user *arg) -{ - struct btrfs_root *root = BTRFS_I(file_inode(file))->root; - struct btrfs_ioctl_quota_rescan_args *qsa; - int ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - ret = mnt_want_write_file(file); - if (ret) - return ret; - - qsa = memdup_user(arg, sizeof(*qsa)); - if (IS_ERR(qsa)) { - ret = PTR_ERR(qsa); - goto drop_write; - } - - if (qsa->flags) { - ret = -EINVAL; - goto out; - } - - ret = btrfs_qgroup_rescan(root->fs_info); - -out: - kfree(qsa); -drop_write: - mnt_drop_write_file(file); - return ret; -} - -static long btrfs_ioctl_quota_rescan_status(struct file *file, void __user *arg) -{ - struct btrfs_root *root = BTRFS_I(file_inode(file))->root; - struct btrfs_ioctl_quota_rescan_args *qsa; - int ret = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - qsa = kzalloc(sizeof(*qsa), GFP_KERNEL); - if (!qsa) - return -ENOMEM; - - if (root->fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) { - qsa->flags = 1; - qsa->progress = root->fs_info->qgroup_rescan_progress.objectid; - } - - if (copy_to_user(arg, qsa, sizeof(*qsa))) - ret = -EFAULT; - - kfree(qsa); - return ret; -} - -static long btrfs_ioctl_quota_rescan_wait(struct file *file, void __user *arg) -{ - struct btrfs_root *root = BTRFS_I(file_inode(file))->root; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - return btrfs_qgroup_wait_for_completion(root->fs_info, true); -} - -static long _btrfs_ioctl_set_received_subvol(struct file *file, - struct btrfs_ioctl_received_subvol_args *sa) -{ - struct inode *inode = file_inode(file); - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_root_item *root_item = &root->root_item; - struct btrfs_trans_handle *trans; - struct timespec ct = current_time(inode); - int ret = 0; - int received_uuid_changed; - - if (!inode_owner_or_capable(inode)) - return -EPERM; - - ret = mnt_want_write_file(file); - if (ret < 0) - return ret; - - down_write(&root->fs_info->subvol_sem); - - if (btrfs_ino(inode) != BTRFS_FIRST_FREE_OBJECTID) { - ret = -EINVAL; - goto out; - } - - if (btrfs_root_readonly(root)) { - ret = -EROFS; - goto out; - } - - /* - * 1 - root item - * 2 - uuid items (received uuid + subvol uuid) - */ - trans = btrfs_start_transaction(root, 3); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - trans = NULL; - goto out; - } - - sa->rtransid = trans->transid; - sa->rtime.sec = ct.tv_sec; - sa->rtime.nsec = ct.tv_nsec; - - received_uuid_changed = memcmp(root_item->received_uuid, sa->uuid, - BTRFS_UUID_SIZE); - if (received_uuid_changed && - !btrfs_is_empty_uuid(root_item->received_uuid)) - btrfs_uuid_tree_rem(trans, root->fs_info->uuid_root, - root_item->received_uuid, - BTRFS_UUID_KEY_RECEIVED_SUBVOL, - root->root_key.objectid); - memcpy(root_item->received_uuid, sa->uuid, BTRFS_UUID_SIZE); - btrfs_set_root_stransid(root_item, sa->stransid); - btrfs_set_root_rtransid(root_item, sa->rtransid); - btrfs_set_stack_timespec_sec(&root_item->stime, sa->stime.sec); - btrfs_set_stack_timespec_nsec(&root_item->stime, sa->stime.nsec); - btrfs_set_stack_timespec_sec(&root_item->rtime, sa->rtime.sec); - btrfs_set_stack_timespec_nsec(&root_item->rtime, sa->rtime.nsec); - - ret = btrfs_update_root(trans, root->fs_info->tree_root, - &root->root_key, &root->root_item); - if (ret < 0) { - btrfs_end_transaction(trans, root); - goto out; - } - if (received_uuid_changed && !btrfs_is_empty_uuid(sa->uuid)) { - ret = btrfs_uuid_tree_add(trans, root->fs_info->uuid_root, - sa->uuid, - BTRFS_UUID_KEY_RECEIVED_SUBVOL, - root->root_key.objectid); - if (ret < 0 && ret != -EEXIST) { - btrfs_abort_transaction(trans, ret); - goto out; - } - } - ret = btrfs_commit_transaction(trans, root); - if (ret < 0) { - btrfs_abort_transaction(trans, ret); - goto out; - } - -out: - up_write(&root->fs_info->subvol_sem); - mnt_drop_write_file(file); - return ret; -} - -#ifdef CONFIG_64BIT -static long btrfs_ioctl_set_received_subvol_32(struct file *file, - void __user *arg) -{ - struct btrfs_ioctl_received_subvol_args_32 *args32 = NULL; - struct btrfs_ioctl_received_subvol_args *args64 = NULL; - int ret = 0; - - args32 = memdup_user(arg, sizeof(*args32)); - if (IS_ERR(args32)) { - ret = PTR_ERR(args32); - args32 = NULL; - goto out; - } - - args64 = kmalloc(sizeof(*args64), GFP_KERNEL); - if (!args64) { - ret = -ENOMEM; - goto out; - } - - memcpy(args64->uuid, args32->uuid, BTRFS_UUID_SIZE); - args64->stransid = args32->stransid; - args64->rtransid = args32->rtransid; - args64->stime.sec = args32->stime.sec; - args64->stime.nsec = args32->stime.nsec; - args64->rtime.sec = args32->rtime.sec; - args64->rtime.nsec = args32->rtime.nsec; - args64->flags = args32->flags; - - ret = _btrfs_ioctl_set_received_subvol(file, args64); - if (ret) - goto out; - - memcpy(args32->uuid, args64->uuid, BTRFS_UUID_SIZE); - args32->stransid = args64->stransid; - args32->rtransid = args64->rtransid; - args32->stime.sec = args64->stime.sec; - args32->stime.nsec = args64->stime.nsec; - args32->rtime.sec = args64->rtime.sec; - args32->rtime.nsec = args64->rtime.nsec; - args32->flags = args64->flags; - - ret = copy_to_user(arg, args32, sizeof(*args32)); - if (ret) - ret = -EFAULT; - -out: - kfree(args32); - kfree(args64); - return ret; -} -#endif - -static long btrfs_ioctl_set_received_subvol(struct file *file, - void __user *arg) -{ - struct btrfs_ioctl_received_subvol_args *sa = NULL; - int ret = 0; - - sa = memdup_user(arg, sizeof(*sa)); - if (IS_ERR(sa)) { - ret = PTR_ERR(sa); - sa = NULL; - goto out; - } - - ret = _btrfs_ioctl_set_received_subvol(file, sa); - - if (ret) - goto out; - - ret = copy_to_user(arg, sa, sizeof(*sa)); - if (ret) - ret = -EFAULT; - -out: - kfree(sa); - return ret; -} - -static int btrfs_ioctl_get_fslabel(struct file *file, void __user *arg) -{ - struct btrfs_root *root = BTRFS_I(file_inode(file))->root; - size_t len; - int ret; - char label[BTRFS_LABEL_SIZE]; - - spin_lock(&root->fs_info->super_lock); - memcpy(label, root->fs_info->super_copy->label, BTRFS_LABEL_SIZE); - spin_unlock(&root->fs_info->super_lock); - - len = strnlen(label, BTRFS_LABEL_SIZE); - - if (len == BTRFS_LABEL_SIZE) { - btrfs_warn(root->fs_info, - "label is too long, return the first %zu bytes", --len); - } - - ret = copy_to_user(arg, label, len); - - return ret ? -EFAULT : 0; -} - -static int btrfs_ioctl_set_fslabel(struct file *file, void __user *arg) -{ - struct btrfs_root *root = BTRFS_I(file_inode(file))->root; - struct btrfs_super_block *super_block = root->fs_info->super_copy; - struct btrfs_trans_handle *trans; - char label[BTRFS_LABEL_SIZE]; - int ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (copy_from_user(label, arg, sizeof(label))) - return -EFAULT; - - if (strnlen(label, BTRFS_LABEL_SIZE) == BTRFS_LABEL_SIZE) { - btrfs_err(root->fs_info, - "unable to set label with more than %d bytes", - BTRFS_LABEL_SIZE - 1); - return -EINVAL; - } - - ret = mnt_want_write_file(file); - if (ret) - return ret; - - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out_unlock; - } - - spin_lock(&root->fs_info->super_lock); - strcpy(super_block->label, label); - spin_unlock(&root->fs_info->super_lock); - ret = btrfs_commit_transaction(trans, root); - -out_unlock: - mnt_drop_write_file(file); - return ret; -} - -#define INIT_FEATURE_FLAGS(suffix) \ - { .compat_flags = BTRFS_FEATURE_COMPAT_##suffix, \ - .compat_ro_flags = BTRFS_FEATURE_COMPAT_RO_##suffix, \ - .incompat_flags = BTRFS_FEATURE_INCOMPAT_##suffix } - -int btrfs_ioctl_get_supported_features(void __user *arg) -{ - static const struct btrfs_ioctl_feature_flags features[3] = { - INIT_FEATURE_FLAGS(SUPP), - INIT_FEATURE_FLAGS(SAFE_SET), - INIT_FEATURE_FLAGS(SAFE_CLEAR) - }; - - if (copy_to_user(arg, &features, sizeof(features))) - return -EFAULT; - - return 0; -} - -static int btrfs_ioctl_get_features(struct file *file, void __user *arg) -{ - struct btrfs_root *root = BTRFS_I(file_inode(file))->root; - struct btrfs_super_block *super_block = root->fs_info->super_copy; - struct btrfs_ioctl_feature_flags features; - - features.compat_flags = btrfs_super_compat_flags(super_block); - features.compat_ro_flags = btrfs_super_compat_ro_flags(super_block); - features.incompat_flags = btrfs_super_incompat_flags(super_block); - - if (copy_to_user(arg, &features, sizeof(features))) - return -EFAULT; - - return 0; -} - -static int check_feature_bits(struct btrfs_root *root, - enum btrfs_feature_set set, - u64 change_mask, u64 flags, u64 supported_flags, - u64 safe_set, u64 safe_clear) -{ - const char *type = btrfs_feature_set_names[set]; - char *names; - u64 disallowed, unsupported; - u64 set_mask = flags & change_mask; - u64 clear_mask = ~flags & change_mask; - - unsupported = set_mask & ~supported_flags; - if (unsupported) { - names = btrfs_printable_features(set, unsupported); - if (names) { - btrfs_warn(root->fs_info, - "this kernel does not support the %s feature bit%s", - names, strchr(names, ',') ? "s" : ""); - kfree(names); - } else - btrfs_warn(root->fs_info, - "this kernel does not support %s bits 0x%llx", - type, unsupported); - return -EOPNOTSUPP; - } - - disallowed = set_mask & ~safe_set; - if (disallowed) { - names = btrfs_printable_features(set, disallowed); - if (names) { - btrfs_warn(root->fs_info, - "can't set the %s feature bit%s while mounted", - names, strchr(names, ',') ? "s" : ""); - kfree(names); - } else - btrfs_warn(root->fs_info, - "can't set %s bits 0x%llx while mounted", - type, disallowed); - return -EPERM; - } - - disallowed = clear_mask & ~safe_clear; - if (disallowed) { - names = btrfs_printable_features(set, disallowed); - if (names) { - btrfs_warn(root->fs_info, - "can't clear the %s feature bit%s while mounted", - names, strchr(names, ',') ? "s" : ""); - kfree(names); - } else - btrfs_warn(root->fs_info, - "can't clear %s bits 0x%llx while mounted", - type, disallowed); - return -EPERM; - } - - return 0; -} - -#define check_feature(root, change_mask, flags, mask_base) \ -check_feature_bits(root, FEAT_##mask_base, change_mask, flags, \ - BTRFS_FEATURE_ ## mask_base ## _SUPP, \ - BTRFS_FEATURE_ ## mask_base ## _SAFE_SET, \ - BTRFS_FEATURE_ ## mask_base ## _SAFE_CLEAR) - -static int btrfs_ioctl_set_features(struct file *file, void __user *arg) -{ - struct btrfs_root *root = BTRFS_I(file_inode(file))->root; - struct btrfs_super_block *super_block = root->fs_info->super_copy; - struct btrfs_ioctl_feature_flags flags[2]; - struct btrfs_trans_handle *trans; - u64 newflags; - int ret; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (copy_from_user(flags, arg, sizeof(flags))) - return -EFAULT; - - /* Nothing to do */ - if (!flags[0].compat_flags && !flags[0].compat_ro_flags && - !flags[0].incompat_flags) - return 0; - - ret = check_feature(root, flags[0].compat_flags, - flags[1].compat_flags, COMPAT); - if (ret) - return ret; - - ret = check_feature(root, flags[0].compat_ro_flags, - flags[1].compat_ro_flags, COMPAT_RO); - if (ret) - return ret; - - ret = check_feature(root, flags[0].incompat_flags, - flags[1].incompat_flags, INCOMPAT); - if (ret) - return ret; - - ret = mnt_want_write_file(file); - if (ret) - return ret; - - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out_drop_write; - } - - spin_lock(&root->fs_info->super_lock); - newflags = btrfs_super_compat_flags(super_block); - newflags |= flags[0].compat_flags & flags[1].compat_flags; - newflags &= ~(flags[0].compat_flags & ~flags[1].compat_flags); - btrfs_set_super_compat_flags(super_block, newflags); - - newflags = btrfs_super_compat_ro_flags(super_block); - newflags |= flags[0].compat_ro_flags & flags[1].compat_ro_flags; - newflags &= ~(flags[0].compat_ro_flags & ~flags[1].compat_ro_flags); - btrfs_set_super_compat_ro_flags(super_block, newflags); - - newflags = btrfs_super_incompat_flags(super_block); - newflags |= flags[0].incompat_flags & flags[1].incompat_flags; - newflags &= ~(flags[0].incompat_flags & ~flags[1].incompat_flags); - btrfs_set_super_incompat_flags(super_block, newflags); - spin_unlock(&root->fs_info->super_lock); - - ret = btrfs_commit_transaction(trans, root); -out_drop_write: - mnt_drop_write_file(file); - - return ret; -} - -long btrfs_ioctl(struct file *file, unsigned int - cmd, unsigned long arg) -{ - struct btrfs_root *root = BTRFS_I(file_inode(file))->root; - void __user *argp = (void __user *)arg; - - switch (cmd) { - case FS_IOC_GETFLAGS: - return btrfs_ioctl_getflags(file, argp); - case FS_IOC_SETFLAGS: - return btrfs_ioctl_setflags(file, argp); - case FS_IOC_GETVERSION: - return btrfs_ioctl_getversion(file, argp); - case FITRIM: - return btrfs_ioctl_fitrim(file, argp); - case BTRFS_IOC_SNAP_CREATE: - return btrfs_ioctl_snap_create(file, argp, 0); - case BTRFS_IOC_SNAP_CREATE_V2: - return btrfs_ioctl_snap_create_v2(file, argp, 0); - case BTRFS_IOC_SUBVOL_CREATE: - return btrfs_ioctl_snap_create(file, argp, 1); - case BTRFS_IOC_SUBVOL_CREATE_V2: - return btrfs_ioctl_snap_create_v2(file, argp, 1); - case BTRFS_IOC_SNAP_DESTROY: - return btrfs_ioctl_snap_destroy(file, argp); - case BTRFS_IOC_SUBVOL_GETFLAGS: - return btrfs_ioctl_subvol_getflags(file, argp); - case BTRFS_IOC_SUBVOL_SETFLAGS: - return btrfs_ioctl_subvol_setflags(file, argp); - case BTRFS_IOC_DEFAULT_SUBVOL: - return btrfs_ioctl_default_subvol(file, argp); - case BTRFS_IOC_DEFRAG: - return btrfs_ioctl_defrag(file, NULL); - case BTRFS_IOC_DEFRAG_RANGE: - return btrfs_ioctl_defrag(file, argp); - case BTRFS_IOC_RESIZE: - return btrfs_ioctl_resize(file, argp); - case BTRFS_IOC_ADD_DEV: - return btrfs_ioctl_add_dev(root, argp); - case BTRFS_IOC_RM_DEV: - return btrfs_ioctl_rm_dev(file, argp); - case BTRFS_IOC_RM_DEV_V2: - return btrfs_ioctl_rm_dev_v2(file, argp); - case BTRFS_IOC_FS_INFO: - return btrfs_ioctl_fs_info(root, argp); - case BTRFS_IOC_DEV_INFO: - return btrfs_ioctl_dev_info(root, argp); - case BTRFS_IOC_BALANCE: - return btrfs_ioctl_balance(file, NULL); - case BTRFS_IOC_TRANS_START: - return btrfs_ioctl_trans_start(file); - case BTRFS_IOC_TRANS_END: - return btrfs_ioctl_trans_end(file); - case BTRFS_IOC_TREE_SEARCH: - return btrfs_ioctl_tree_search(file, argp); - case BTRFS_IOC_TREE_SEARCH_V2: - return btrfs_ioctl_tree_search_v2(file, argp); - case BTRFS_IOC_INO_LOOKUP: - return btrfs_ioctl_ino_lookup(file, argp); - case BTRFS_IOC_INO_PATHS: - return btrfs_ioctl_ino_to_path(root, argp); - case BTRFS_IOC_LOGICAL_INO: - return btrfs_ioctl_logical_to_ino(root, argp); - case BTRFS_IOC_SPACE_INFO: - return btrfs_ioctl_space_info(root, argp); - case BTRFS_IOC_SYNC: { - int ret; - - ret = btrfs_start_delalloc_roots(root->fs_info, 0, -1); - if (ret) - return ret; - ret = btrfs_sync_fs(file_inode(file)->i_sb, 1); - /* - * The transaction thread may want to do more work, - * namely it pokes the cleaner kthread that will start - * processing uncleaned subvols. - */ - wake_up_process(root->fs_info->transaction_kthread); - return ret; - } - case BTRFS_IOC_START_SYNC: - return btrfs_ioctl_start_sync(root, argp); - case BTRFS_IOC_WAIT_SYNC: - return btrfs_ioctl_wait_sync(root, argp); - case BTRFS_IOC_SCRUB: - return btrfs_ioctl_scrub(file, argp); - case BTRFS_IOC_SCRUB_CANCEL: - return btrfs_ioctl_scrub_cancel(root, argp); - case BTRFS_IOC_SCRUB_PROGRESS: - return btrfs_ioctl_scrub_progress(root, argp); - case BTRFS_IOC_BALANCE_V2: - return btrfs_ioctl_balance(file, argp); - case BTRFS_IOC_BALANCE_CTL: - return btrfs_ioctl_balance_ctl(root, arg); - case BTRFS_IOC_BALANCE_PROGRESS: - return btrfs_ioctl_balance_progress(root, argp); - case BTRFS_IOC_SET_RECEIVED_SUBVOL: - return btrfs_ioctl_set_received_subvol(file, argp); -#ifdef CONFIG_64BIT - case BTRFS_IOC_SET_RECEIVED_SUBVOL_32: - return btrfs_ioctl_set_received_subvol_32(file, argp); -#endif - case BTRFS_IOC_SEND: - return btrfs_ioctl_send(file, argp); - case BTRFS_IOC_GET_DEV_STATS: - return btrfs_ioctl_get_dev_stats(root, argp); - case BTRFS_IOC_QUOTA_CTL: - return btrfs_ioctl_quota_ctl(file, argp); - case BTRFS_IOC_QGROUP_ASSIGN: - return btrfs_ioctl_qgroup_assign(file, argp); - case BTRFS_IOC_QGROUP_CREATE: - return btrfs_ioctl_qgroup_create(file, argp); - case BTRFS_IOC_QGROUP_LIMIT: - return btrfs_ioctl_qgroup_limit(file, argp); - case BTRFS_IOC_QUOTA_RESCAN: - return btrfs_ioctl_quota_rescan(file, argp); - case BTRFS_IOC_QUOTA_RESCAN_STATUS: - return btrfs_ioctl_quota_rescan_status(file, argp); - case BTRFS_IOC_QUOTA_RESCAN_WAIT: - return btrfs_ioctl_quota_rescan_wait(file, argp); - case BTRFS_IOC_DEV_REPLACE: - return btrfs_ioctl_dev_replace(root, argp); - case BTRFS_IOC_GET_FSLABEL: - return btrfs_ioctl_get_fslabel(file, argp); - case BTRFS_IOC_SET_FSLABEL: - return btrfs_ioctl_set_fslabel(file, argp); - case BTRFS_IOC_GET_SUPPORTED_FEATURES: - return btrfs_ioctl_get_supported_features(argp); - case BTRFS_IOC_GET_FEATURES: - return btrfs_ioctl_get_features(file, argp); - case BTRFS_IOC_SET_FEATURES: - return btrfs_ioctl_set_features(file, argp); - } - - return -ENOTTY; -} - -#ifdef CONFIG_COMPAT -long btrfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case FS_IOC32_GETFLAGS: - cmd = FS_IOC_GETFLAGS; - break; - case FS_IOC32_SETFLAGS: - cmd = FS_IOC_SETFLAGS; - break; - case FS_IOC32_GETVERSION: - cmd = FS_IOC_GETVERSION; - break; - default: - return -ENOIOCTLCMD; - } - - return btrfs_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); -} -#endif diff --git a/src/linux/fs/btrfs/locking.c b/src/linux/fs/btrfs/locking.c deleted file mode 100644 index d13128c..0000000 --- a/src/linux/fs/btrfs/locking.c +++ /dev/null @@ -1,311 +0,0 @@ -/* - * Copyright (C) 2008 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ -#include -#include -#include -#include -#include -#include "ctree.h" -#include "extent_io.h" -#include "locking.h" - -static void btrfs_assert_tree_read_locked(struct extent_buffer *eb); - -/* - * if we currently have a spinning reader or writer lock - * (indicated by the rw flag) this will bump the count - * of blocking holders and drop the spinlock. - */ -void btrfs_set_lock_blocking_rw(struct extent_buffer *eb, int rw) -{ - /* - * no lock is required. The lock owner may change if - * we have a read lock, but it won't change to or away - * from us. If we have the write lock, we are the owner - * and it'll never change. - */ - if (eb->lock_nested && current->pid == eb->lock_owner) - return; - if (rw == BTRFS_WRITE_LOCK) { - if (atomic_read(&eb->blocking_writers) == 0) { - WARN_ON(atomic_read(&eb->spinning_writers) != 1); - atomic_dec(&eb->spinning_writers); - btrfs_assert_tree_locked(eb); - atomic_inc(&eb->blocking_writers); - write_unlock(&eb->lock); - } - } else if (rw == BTRFS_READ_LOCK) { - btrfs_assert_tree_read_locked(eb); - atomic_inc(&eb->blocking_readers); - WARN_ON(atomic_read(&eb->spinning_readers) == 0); - atomic_dec(&eb->spinning_readers); - read_unlock(&eb->lock); - } -} - -/* - * if we currently have a blocking lock, take the spinlock - * and drop our blocking count - */ -void btrfs_clear_lock_blocking_rw(struct extent_buffer *eb, int rw) -{ - /* - * no lock is required. The lock owner may change if - * we have a read lock, but it won't change to or away - * from us. If we have the write lock, we are the owner - * and it'll never change. - */ - if (eb->lock_nested && current->pid == eb->lock_owner) - return; - - if (rw == BTRFS_WRITE_LOCK_BLOCKING) { - BUG_ON(atomic_read(&eb->blocking_writers) != 1); - write_lock(&eb->lock); - WARN_ON(atomic_read(&eb->spinning_writers)); - atomic_inc(&eb->spinning_writers); - /* - * atomic_dec_and_test implies a barrier for waitqueue_active - */ - if (atomic_dec_and_test(&eb->blocking_writers) && - waitqueue_active(&eb->write_lock_wq)) - wake_up(&eb->write_lock_wq); - } else if (rw == BTRFS_READ_LOCK_BLOCKING) { - BUG_ON(atomic_read(&eb->blocking_readers) == 0); - read_lock(&eb->lock); - atomic_inc(&eb->spinning_readers); - /* - * atomic_dec_and_test implies a barrier for waitqueue_active - */ - if (atomic_dec_and_test(&eb->blocking_readers) && - waitqueue_active(&eb->read_lock_wq)) - wake_up(&eb->read_lock_wq); - } -} - -/* - * take a spinning read lock. This will wait for any blocking - * writers - */ -void btrfs_tree_read_lock(struct extent_buffer *eb) -{ -again: - BUG_ON(!atomic_read(&eb->blocking_writers) && - current->pid == eb->lock_owner); - - read_lock(&eb->lock); - if (atomic_read(&eb->blocking_writers) && - current->pid == eb->lock_owner) { - /* - * This extent is already write-locked by our thread. We allow - * an additional read lock to be added because it's for the same - * thread. btrfs_find_all_roots() depends on this as it may be - * called on a partly (write-)locked tree. - */ - BUG_ON(eb->lock_nested); - eb->lock_nested = 1; - read_unlock(&eb->lock); - return; - } - if (atomic_read(&eb->blocking_writers)) { - read_unlock(&eb->lock); - wait_event(eb->write_lock_wq, - atomic_read(&eb->blocking_writers) == 0); - goto again; - } - atomic_inc(&eb->read_locks); - atomic_inc(&eb->spinning_readers); -} - -/* - * take a spinning read lock. - * returns 1 if we get the read lock and 0 if we don't - * this won't wait for blocking writers - */ -int btrfs_tree_read_lock_atomic(struct extent_buffer *eb) -{ - if (atomic_read(&eb->blocking_writers)) - return 0; - - read_lock(&eb->lock); - if (atomic_read(&eb->blocking_writers)) { - read_unlock(&eb->lock); - return 0; - } - atomic_inc(&eb->read_locks); - atomic_inc(&eb->spinning_readers); - return 1; -} - -/* - * returns 1 if we get the read lock and 0 if we don't - * this won't wait for blocking writers - */ -int btrfs_try_tree_read_lock(struct extent_buffer *eb) -{ - if (atomic_read(&eb->blocking_writers)) - return 0; - - if (!read_trylock(&eb->lock)) - return 0; - - if (atomic_read(&eb->blocking_writers)) { - read_unlock(&eb->lock); - return 0; - } - atomic_inc(&eb->read_locks); - atomic_inc(&eb->spinning_readers); - return 1; -} - -/* - * returns 1 if we get the read lock and 0 if we don't - * this won't wait for blocking writers or readers - */ -int btrfs_try_tree_write_lock(struct extent_buffer *eb) -{ - if (atomic_read(&eb->blocking_writers) || - atomic_read(&eb->blocking_readers)) - return 0; - - write_lock(&eb->lock); - if (atomic_read(&eb->blocking_writers) || - atomic_read(&eb->blocking_readers)) { - write_unlock(&eb->lock); - return 0; - } - atomic_inc(&eb->write_locks); - atomic_inc(&eb->spinning_writers); - eb->lock_owner = current->pid; - return 1; -} - -/* - * drop a spinning read lock - */ -void btrfs_tree_read_unlock(struct extent_buffer *eb) -{ - /* - * if we're nested, we have the write lock. No new locking - * is needed as long as we are the lock owner. - * The write unlock will do a barrier for us, and the lock_nested - * field only matters to the lock owner. - */ - if (eb->lock_nested && current->pid == eb->lock_owner) { - eb->lock_nested = 0; - return; - } - btrfs_assert_tree_read_locked(eb); - WARN_ON(atomic_read(&eb->spinning_readers) == 0); - atomic_dec(&eb->spinning_readers); - atomic_dec(&eb->read_locks); - read_unlock(&eb->lock); -} - -/* - * drop a blocking read lock - */ -void btrfs_tree_read_unlock_blocking(struct extent_buffer *eb) -{ - /* - * if we're nested, we have the write lock. No new locking - * is needed as long as we are the lock owner. - * The write unlock will do a barrier for us, and the lock_nested - * field only matters to the lock owner. - */ - if (eb->lock_nested && current->pid == eb->lock_owner) { - eb->lock_nested = 0; - return; - } - btrfs_assert_tree_read_locked(eb); - WARN_ON(atomic_read(&eb->blocking_readers) == 0); - /* - * atomic_dec_and_test implies a barrier for waitqueue_active - */ - if (atomic_dec_and_test(&eb->blocking_readers) && - waitqueue_active(&eb->read_lock_wq)) - wake_up(&eb->read_lock_wq); - atomic_dec(&eb->read_locks); -} - -/* - * take a spinning write lock. This will wait for both - * blocking readers or writers - */ -void btrfs_tree_lock(struct extent_buffer *eb) -{ - WARN_ON(eb->lock_owner == current->pid); -again: - wait_event(eb->read_lock_wq, atomic_read(&eb->blocking_readers) == 0); - wait_event(eb->write_lock_wq, atomic_read(&eb->blocking_writers) == 0); - write_lock(&eb->lock); - if (atomic_read(&eb->blocking_readers)) { - write_unlock(&eb->lock); - wait_event(eb->read_lock_wq, - atomic_read(&eb->blocking_readers) == 0); - goto again; - } - if (atomic_read(&eb->blocking_writers)) { - write_unlock(&eb->lock); - wait_event(eb->write_lock_wq, - atomic_read(&eb->blocking_writers) == 0); - goto again; - } - WARN_ON(atomic_read(&eb->spinning_writers)); - atomic_inc(&eb->spinning_writers); - atomic_inc(&eb->write_locks); - eb->lock_owner = current->pid; -} - -/* - * drop a spinning or a blocking write lock. - */ -void btrfs_tree_unlock(struct extent_buffer *eb) -{ - int blockers = atomic_read(&eb->blocking_writers); - - BUG_ON(blockers > 1); - - btrfs_assert_tree_locked(eb); - eb->lock_owner = 0; - atomic_dec(&eb->write_locks); - - if (blockers) { - WARN_ON(atomic_read(&eb->spinning_writers)); - atomic_dec(&eb->blocking_writers); - /* - * Make sure counter is updated before we wake up waiters. - */ - smp_mb(); - if (waitqueue_active(&eb->write_lock_wq)) - wake_up(&eb->write_lock_wq); - } else { - WARN_ON(atomic_read(&eb->spinning_writers) != 1); - atomic_dec(&eb->spinning_writers); - write_unlock(&eb->lock); - } -} - -void btrfs_assert_tree_locked(struct extent_buffer *eb) -{ - BUG_ON(!atomic_read(&eb->write_locks)); -} - -static void btrfs_assert_tree_read_locked(struct extent_buffer *eb) -{ - BUG_ON(!atomic_read(&eb->read_locks)); -} diff --git a/src/linux/fs/btrfs/locking.h b/src/linux/fs/btrfs/locking.h deleted file mode 100644 index c44a9d5..0000000 --- a/src/linux/fs/btrfs/locking.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2008 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __BTRFS_LOCKING_ -#define __BTRFS_LOCKING_ - -#define BTRFS_WRITE_LOCK 1 -#define BTRFS_READ_LOCK 2 -#define BTRFS_WRITE_LOCK_BLOCKING 3 -#define BTRFS_READ_LOCK_BLOCKING 4 - -void btrfs_tree_lock(struct extent_buffer *eb); -void btrfs_tree_unlock(struct extent_buffer *eb); - -void btrfs_tree_read_lock(struct extent_buffer *eb); -void btrfs_tree_read_unlock(struct extent_buffer *eb); -void btrfs_tree_read_unlock_blocking(struct extent_buffer *eb); -void btrfs_set_lock_blocking_rw(struct extent_buffer *eb, int rw); -void btrfs_clear_lock_blocking_rw(struct extent_buffer *eb, int rw); -void btrfs_assert_tree_locked(struct extent_buffer *eb); -int btrfs_try_tree_read_lock(struct extent_buffer *eb); -int btrfs_try_tree_write_lock(struct extent_buffer *eb); -int btrfs_tree_read_lock_atomic(struct extent_buffer *eb); - - -static inline void btrfs_tree_unlock_rw(struct extent_buffer *eb, int rw) -{ - if (rw == BTRFS_WRITE_LOCK || rw == BTRFS_WRITE_LOCK_BLOCKING) - btrfs_tree_unlock(eb); - else if (rw == BTRFS_READ_LOCK_BLOCKING) - btrfs_tree_read_unlock_blocking(eb); - else if (rw == BTRFS_READ_LOCK) - btrfs_tree_read_unlock(eb); - else - BUG(); -} - -static inline void btrfs_set_lock_blocking(struct extent_buffer *eb) -{ - btrfs_set_lock_blocking_rw(eb, BTRFS_WRITE_LOCK); -} - -static inline void btrfs_clear_lock_blocking(struct extent_buffer *eb) -{ - btrfs_clear_lock_blocking_rw(eb, BTRFS_WRITE_LOCK_BLOCKING); -} -#endif diff --git a/src/linux/fs/btrfs/lzo.c b/src/linux/fs/btrfs/lzo.c deleted file mode 100644 index 48655da..0000000 --- a/src/linux/fs/btrfs/lzo.c +++ /dev/null @@ -1,443 +0,0 @@ -/* - * Copyright (C) 2008 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "compression.h" - -#define LZO_LEN 4 - -struct workspace { - void *mem; - void *buf; /* where decompressed data goes */ - void *cbuf; /* where compressed data goes */ - struct list_head list; -}; - -static void lzo_free_workspace(struct list_head *ws) -{ - struct workspace *workspace = list_entry(ws, struct workspace, list); - - vfree(workspace->buf); - vfree(workspace->cbuf); - vfree(workspace->mem); - kfree(workspace); -} - -static struct list_head *lzo_alloc_workspace(void) -{ - struct workspace *workspace; - - workspace = kzalloc(sizeof(*workspace), GFP_NOFS); - if (!workspace) - return ERR_PTR(-ENOMEM); - - workspace->mem = vmalloc(LZO1X_MEM_COMPRESS); - workspace->buf = vmalloc(lzo1x_worst_compress(PAGE_SIZE)); - workspace->cbuf = vmalloc(lzo1x_worst_compress(PAGE_SIZE)); - if (!workspace->mem || !workspace->buf || !workspace->cbuf) - goto fail; - - INIT_LIST_HEAD(&workspace->list); - - return &workspace->list; -fail: - lzo_free_workspace(&workspace->list); - return ERR_PTR(-ENOMEM); -} - -static inline void write_compress_length(char *buf, size_t len) -{ - __le32 dlen; - - dlen = cpu_to_le32(len); - memcpy(buf, &dlen, LZO_LEN); -} - -static inline size_t read_compress_length(char *buf) -{ - __le32 dlen; - - memcpy(&dlen, buf, LZO_LEN); - return le32_to_cpu(dlen); -} - -static int lzo_compress_pages(struct list_head *ws, - struct address_space *mapping, - u64 start, unsigned long len, - struct page **pages, - unsigned long nr_dest_pages, - unsigned long *out_pages, - unsigned long *total_in, - unsigned long *total_out, - unsigned long max_out) -{ - struct workspace *workspace = list_entry(ws, struct workspace, list); - int ret = 0; - char *data_in; - char *cpage_out; - int nr_pages = 0; - struct page *in_page = NULL; - struct page *out_page = NULL; - unsigned long bytes_left; - - size_t in_len; - size_t out_len; - char *buf; - unsigned long tot_in = 0; - unsigned long tot_out = 0; - unsigned long pg_bytes_left; - unsigned long out_offset; - unsigned long bytes; - - *out_pages = 0; - *total_out = 0; - *total_in = 0; - - in_page = find_get_page(mapping, start >> PAGE_SHIFT); - data_in = kmap(in_page); - - /* - * store the size of all chunks of compressed data in - * the first 4 bytes - */ - out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); - if (out_page == NULL) { - ret = -ENOMEM; - goto out; - } - cpage_out = kmap(out_page); - out_offset = LZO_LEN; - tot_out = LZO_LEN; - pages[0] = out_page; - nr_pages = 1; - pg_bytes_left = PAGE_SIZE - LZO_LEN; - - /* compress at most one page of data each time */ - in_len = min(len, PAGE_SIZE); - while (tot_in < len) { - ret = lzo1x_1_compress(data_in, in_len, workspace->cbuf, - &out_len, workspace->mem); - if (ret != LZO_E_OK) { - pr_debug("BTRFS: deflate in loop returned %d\n", - ret); - ret = -EIO; - goto out; - } - - /* store the size of this chunk of compressed data */ - write_compress_length(cpage_out + out_offset, out_len); - tot_out += LZO_LEN; - out_offset += LZO_LEN; - pg_bytes_left -= LZO_LEN; - - tot_in += in_len; - tot_out += out_len; - - /* copy bytes from the working buffer into the pages */ - buf = workspace->cbuf; - while (out_len) { - bytes = min_t(unsigned long, pg_bytes_left, out_len); - - memcpy(cpage_out + out_offset, buf, bytes); - - out_len -= bytes; - pg_bytes_left -= bytes; - buf += bytes; - out_offset += bytes; - - /* - * we need another page for writing out. - * - * Note if there's less than 4 bytes left, we just - * skip to a new page. - */ - if ((out_len == 0 && pg_bytes_left < LZO_LEN) || - pg_bytes_left == 0) { - if (pg_bytes_left) { - memset(cpage_out + out_offset, 0, - pg_bytes_left); - tot_out += pg_bytes_left; - } - - /* we're done, don't allocate new page */ - if (out_len == 0 && tot_in >= len) - break; - - kunmap(out_page); - if (nr_pages == nr_dest_pages) { - out_page = NULL; - ret = -E2BIG; - goto out; - } - - out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); - if (out_page == NULL) { - ret = -ENOMEM; - goto out; - } - cpage_out = kmap(out_page); - pages[nr_pages++] = out_page; - - pg_bytes_left = PAGE_SIZE; - out_offset = 0; - } - } - - /* we're making it bigger, give up */ - if (tot_in > 8192 && tot_in < tot_out) { - ret = -E2BIG; - goto out; - } - - /* we're all done */ - if (tot_in >= len) - break; - - if (tot_out > max_out) - break; - - bytes_left = len - tot_in; - kunmap(in_page); - put_page(in_page); - - start += PAGE_SIZE; - in_page = find_get_page(mapping, start >> PAGE_SHIFT); - data_in = kmap(in_page); - in_len = min(bytes_left, PAGE_SIZE); - } - - if (tot_out > tot_in) - goto out; - - /* store the size of all chunks of compressed data */ - cpage_out = kmap(pages[0]); - write_compress_length(cpage_out, tot_out); - - kunmap(pages[0]); - - ret = 0; - *total_out = tot_out; - *total_in = tot_in; -out: - *out_pages = nr_pages; - if (out_page) - kunmap(out_page); - - if (in_page) { - kunmap(in_page); - put_page(in_page); - } - - return ret; -} - -static int lzo_decompress_biovec(struct list_head *ws, - struct page **pages_in, - u64 disk_start, - struct bio_vec *bvec, - int vcnt, - size_t srclen) -{ - struct workspace *workspace = list_entry(ws, struct workspace, list); - int ret = 0, ret2; - char *data_in; - unsigned long page_in_index = 0; - unsigned long page_out_index = 0; - unsigned long total_pages_in = DIV_ROUND_UP(srclen, PAGE_SIZE); - unsigned long buf_start; - unsigned long buf_offset = 0; - unsigned long bytes; - unsigned long working_bytes; - unsigned long pg_offset; - - size_t in_len; - size_t out_len; - unsigned long in_offset; - unsigned long in_page_bytes_left; - unsigned long tot_in; - unsigned long tot_out; - unsigned long tot_len; - char *buf; - bool may_late_unmap, need_unmap; - - data_in = kmap(pages_in[0]); - tot_len = read_compress_length(data_in); - - tot_in = LZO_LEN; - in_offset = LZO_LEN; - tot_len = min_t(size_t, srclen, tot_len); - in_page_bytes_left = PAGE_SIZE - LZO_LEN; - - tot_out = 0; - pg_offset = 0; - - while (tot_in < tot_len) { - in_len = read_compress_length(data_in + in_offset); - in_page_bytes_left -= LZO_LEN; - in_offset += LZO_LEN; - tot_in += LZO_LEN; - - tot_in += in_len; - working_bytes = in_len; - may_late_unmap = need_unmap = false; - - /* fast path: avoid using the working buffer */ - if (in_page_bytes_left >= in_len) { - buf = data_in + in_offset; - bytes = in_len; - may_late_unmap = true; - goto cont; - } - - /* copy bytes from the pages into the working buffer */ - buf = workspace->cbuf; - buf_offset = 0; - while (working_bytes) { - bytes = min(working_bytes, in_page_bytes_left); - - memcpy(buf + buf_offset, data_in + in_offset, bytes); - buf_offset += bytes; -cont: - working_bytes -= bytes; - in_page_bytes_left -= bytes; - in_offset += bytes; - - /* check if we need to pick another page */ - if ((working_bytes == 0 && in_page_bytes_left < LZO_LEN) - || in_page_bytes_left == 0) { - tot_in += in_page_bytes_left; - - if (working_bytes == 0 && tot_in >= tot_len) - break; - - if (page_in_index + 1 >= total_pages_in) { - ret = -EIO; - goto done; - } - - if (may_late_unmap) - need_unmap = true; - else - kunmap(pages_in[page_in_index]); - - data_in = kmap(pages_in[++page_in_index]); - - in_page_bytes_left = PAGE_SIZE; - in_offset = 0; - } - } - - out_len = lzo1x_worst_compress(PAGE_SIZE); - ret = lzo1x_decompress_safe(buf, in_len, workspace->buf, - &out_len); - if (need_unmap) - kunmap(pages_in[page_in_index - 1]); - if (ret != LZO_E_OK) { - pr_warn("BTRFS: decompress failed\n"); - ret = -EIO; - break; - } - - buf_start = tot_out; - tot_out += out_len; - - ret2 = btrfs_decompress_buf2page(workspace->buf, buf_start, - tot_out, disk_start, - bvec, vcnt, - &page_out_index, &pg_offset); - if (ret2 == 0) - break; - } -done: - kunmap(pages_in[page_in_index]); - if (!ret) - btrfs_clear_biovec_end(bvec, vcnt, page_out_index, pg_offset); - return ret; -} - -static int lzo_decompress(struct list_head *ws, unsigned char *data_in, - struct page *dest_page, - unsigned long start_byte, - size_t srclen, size_t destlen) -{ - struct workspace *workspace = list_entry(ws, struct workspace, list); - size_t in_len; - size_t out_len; - size_t tot_len; - int ret = 0; - char *kaddr; - unsigned long bytes; - - BUG_ON(srclen < LZO_LEN); - - tot_len = read_compress_length(data_in); - data_in += LZO_LEN; - - in_len = read_compress_length(data_in); - data_in += LZO_LEN; - - out_len = PAGE_SIZE; - ret = lzo1x_decompress_safe(data_in, in_len, workspace->buf, &out_len); - if (ret != LZO_E_OK) { - pr_warn("BTRFS: decompress failed!\n"); - ret = -EIO; - goto out; - } - - if (out_len < start_byte) { - ret = -EIO; - goto out; - } - - /* - * the caller is already checking against PAGE_SIZE, but lets - * move this check closer to the memcpy/memset - */ - destlen = min_t(unsigned long, destlen, PAGE_SIZE); - bytes = min_t(unsigned long, destlen, out_len - start_byte); - - kaddr = kmap_atomic(dest_page); - memcpy(kaddr, workspace->buf + start_byte, bytes); - - /* - * btrfs_getblock is doing a zero on the tail of the page too, - * but this will cover anything missing from the decompressed - * data. - */ - if (bytes < destlen) - memset(kaddr+bytes, 0, destlen-bytes); - kunmap_atomic(kaddr); -out: - return ret; -} - -const struct btrfs_compress_op btrfs_lzo_compress = { - .alloc_workspace = lzo_alloc_workspace, - .free_workspace = lzo_free_workspace, - .compress_pages = lzo_compress_pages, - .decompress_biovec = lzo_decompress_biovec, - .decompress = lzo_decompress, -}; diff --git a/src/linux/fs/btrfs/math.h b/src/linux/fs/btrfs/math.h deleted file mode 100644 index 1b10a3c..0000000 --- a/src/linux/fs/btrfs/math.h +++ /dev/null @@ -1,42 +0,0 @@ - -/* - * Copyright (C) 2012 Fujitsu. All rights reserved. - * Written by Miao Xie - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __BTRFS_MATH_H -#define __BTRFS_MATH_H - -#include - -static inline u64 div_factor(u64 num, int factor) -{ - if (factor == 10) - return num; - num *= factor; - return div_u64(num, 10); -} - -static inline u64 div_factor_fine(u64 num, int factor) -{ - if (factor == 100) - return num; - num *= factor; - return div_u64(num, 100); -} - -#endif diff --git a/src/linux/fs/btrfs/ordered-data.c b/src/linux/fs/btrfs/ordered-data.c deleted file mode 100644 index b2d1e95..0000000 --- a/src/linux/fs/btrfs/ordered-data.c +++ /dev/null @@ -1,1136 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include "ctree.h" -#include "transaction.h" -#include "btrfs_inode.h" -#include "extent_io.h" -#include "disk-io.h" -#include "compression.h" - -static struct kmem_cache *btrfs_ordered_extent_cache; - -static u64 entry_end(struct btrfs_ordered_extent *entry) -{ - if (entry->file_offset + entry->len < entry->file_offset) - return (u64)-1; - return entry->file_offset + entry->len; -} - -/* returns NULL if the insertion worked, or it returns the node it did find - * in the tree - */ -static struct rb_node *tree_insert(struct rb_root *root, u64 file_offset, - struct rb_node *node) -{ - struct rb_node **p = &root->rb_node; - struct rb_node *parent = NULL; - struct btrfs_ordered_extent *entry; - - while (*p) { - parent = *p; - entry = rb_entry(parent, struct btrfs_ordered_extent, rb_node); - - if (file_offset < entry->file_offset) - p = &(*p)->rb_left; - else if (file_offset >= entry_end(entry)) - p = &(*p)->rb_right; - else - return parent; - } - - rb_link_node(node, parent, p); - rb_insert_color(node, root); - return NULL; -} - -static void ordered_data_tree_panic(struct inode *inode, int errno, - u64 offset) -{ - struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); - btrfs_panic(fs_info, errno, - "Inconsistency in ordered tree at offset %llu", offset); -} - -/* - * look for a given offset in the tree, and if it can't be found return the - * first lesser offset - */ -static struct rb_node *__tree_search(struct rb_root *root, u64 file_offset, - struct rb_node **prev_ret) -{ - struct rb_node *n = root->rb_node; - struct rb_node *prev = NULL; - struct rb_node *test; - struct btrfs_ordered_extent *entry; - struct btrfs_ordered_extent *prev_entry = NULL; - - while (n) { - entry = rb_entry(n, struct btrfs_ordered_extent, rb_node); - prev = n; - prev_entry = entry; - - if (file_offset < entry->file_offset) - n = n->rb_left; - else if (file_offset >= entry_end(entry)) - n = n->rb_right; - else - return n; - } - if (!prev_ret) - return NULL; - - while (prev && file_offset >= entry_end(prev_entry)) { - test = rb_next(prev); - if (!test) - break; - prev_entry = rb_entry(test, struct btrfs_ordered_extent, - rb_node); - if (file_offset < entry_end(prev_entry)) - break; - - prev = test; - } - if (prev) - prev_entry = rb_entry(prev, struct btrfs_ordered_extent, - rb_node); - while (prev && file_offset < entry_end(prev_entry)) { - test = rb_prev(prev); - if (!test) - break; - prev_entry = rb_entry(test, struct btrfs_ordered_extent, - rb_node); - prev = test; - } - *prev_ret = prev; - return NULL; -} - -/* - * helper to check if a given offset is inside a given entry - */ -static int offset_in_entry(struct btrfs_ordered_extent *entry, u64 file_offset) -{ - if (file_offset < entry->file_offset || - entry->file_offset + entry->len <= file_offset) - return 0; - return 1; -} - -static int range_overlaps(struct btrfs_ordered_extent *entry, u64 file_offset, - u64 len) -{ - if (file_offset + len <= entry->file_offset || - entry->file_offset + entry->len <= file_offset) - return 0; - return 1; -} - -/* - * look find the first ordered struct that has this offset, otherwise - * the first one less than this offset - */ -static inline struct rb_node *tree_search(struct btrfs_ordered_inode_tree *tree, - u64 file_offset) -{ - struct rb_root *root = &tree->tree; - struct rb_node *prev = NULL; - struct rb_node *ret; - struct btrfs_ordered_extent *entry; - - if (tree->last) { - entry = rb_entry(tree->last, struct btrfs_ordered_extent, - rb_node); - if (offset_in_entry(entry, file_offset)) - return tree->last; - } - ret = __tree_search(root, file_offset, &prev); - if (!ret) - ret = prev; - if (ret) - tree->last = ret; - return ret; -} - -/* allocate and add a new ordered_extent into the per-inode tree. - * file_offset is the logical offset in the file - * - * start is the disk block number of an extent already reserved in the - * extent allocation tree - * - * len is the length of the extent - * - * The tree is given a single reference on the ordered extent that was - * inserted. - */ -static int __btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, - u64 start, u64 len, u64 disk_len, - int type, int dio, int compress_type) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_ordered_inode_tree *tree; - struct rb_node *node; - struct btrfs_ordered_extent *entry; - - tree = &BTRFS_I(inode)->ordered_tree; - entry = kmem_cache_zalloc(btrfs_ordered_extent_cache, GFP_NOFS); - if (!entry) - return -ENOMEM; - - entry->file_offset = file_offset; - entry->start = start; - entry->len = len; - entry->disk_len = disk_len; - entry->bytes_left = len; - entry->inode = igrab(inode); - entry->compress_type = compress_type; - entry->truncated_len = (u64)-1; - if (type != BTRFS_ORDERED_IO_DONE && type != BTRFS_ORDERED_COMPLETE) - set_bit(type, &entry->flags); - - if (dio) - set_bit(BTRFS_ORDERED_DIRECT, &entry->flags); - - /* one ref for the tree */ - atomic_set(&entry->refs, 1); - init_waitqueue_head(&entry->wait); - INIT_LIST_HEAD(&entry->list); - INIT_LIST_HEAD(&entry->root_extent_list); - INIT_LIST_HEAD(&entry->work_list); - init_completion(&entry->completion); - INIT_LIST_HEAD(&entry->log_list); - INIT_LIST_HEAD(&entry->trans_list); - - trace_btrfs_ordered_extent_add(inode, entry); - - spin_lock_irq(&tree->lock); - node = tree_insert(&tree->tree, file_offset, - &entry->rb_node); - if (node) - ordered_data_tree_panic(inode, -EEXIST, file_offset); - spin_unlock_irq(&tree->lock); - - spin_lock(&root->ordered_extent_lock); - list_add_tail(&entry->root_extent_list, - &root->ordered_extents); - root->nr_ordered_extents++; - if (root->nr_ordered_extents == 1) { - spin_lock(&root->fs_info->ordered_root_lock); - BUG_ON(!list_empty(&root->ordered_root)); - list_add_tail(&root->ordered_root, - &root->fs_info->ordered_roots); - spin_unlock(&root->fs_info->ordered_root_lock); - } - spin_unlock(&root->ordered_extent_lock); - - return 0; -} - -int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, - u64 start, u64 len, u64 disk_len, int type) -{ - return __btrfs_add_ordered_extent(inode, file_offset, start, len, - disk_len, type, 0, - BTRFS_COMPRESS_NONE); -} - -int btrfs_add_ordered_extent_dio(struct inode *inode, u64 file_offset, - u64 start, u64 len, u64 disk_len, int type) -{ - return __btrfs_add_ordered_extent(inode, file_offset, start, len, - disk_len, type, 1, - BTRFS_COMPRESS_NONE); -} - -int btrfs_add_ordered_extent_compress(struct inode *inode, u64 file_offset, - u64 start, u64 len, u64 disk_len, - int type, int compress_type) -{ - return __btrfs_add_ordered_extent(inode, file_offset, start, len, - disk_len, type, 0, - compress_type); -} - -/* - * Add a struct btrfs_ordered_sum into the list of checksums to be inserted - * when an ordered extent is finished. If the list covers more than one - * ordered extent, it is split across multiples. - */ -void btrfs_add_ordered_sum(struct inode *inode, - struct btrfs_ordered_extent *entry, - struct btrfs_ordered_sum *sum) -{ - struct btrfs_ordered_inode_tree *tree; - - tree = &BTRFS_I(inode)->ordered_tree; - spin_lock_irq(&tree->lock); - list_add_tail(&sum->list, &entry->list); - spin_unlock_irq(&tree->lock); -} - -/* - * this is used to account for finished IO across a given range - * of the file. The IO may span ordered extents. If - * a given ordered_extent is completely done, 1 is returned, otherwise - * 0. - * - * test_and_set_bit on a flag in the struct btrfs_ordered_extent is used - * to make sure this function only returns 1 once for a given ordered extent. - * - * file_offset is updated to one byte past the range that is recorded as - * complete. This allows you to walk forward in the file. - */ -int btrfs_dec_test_first_ordered_pending(struct inode *inode, - struct btrfs_ordered_extent **cached, - u64 *file_offset, u64 io_size, int uptodate) -{ - struct btrfs_ordered_inode_tree *tree; - struct rb_node *node; - struct btrfs_ordered_extent *entry = NULL; - int ret; - unsigned long flags; - u64 dec_end; - u64 dec_start; - u64 to_dec; - - tree = &BTRFS_I(inode)->ordered_tree; - spin_lock_irqsave(&tree->lock, flags); - node = tree_search(tree, *file_offset); - if (!node) { - ret = 1; - goto out; - } - - entry = rb_entry(node, struct btrfs_ordered_extent, rb_node); - if (!offset_in_entry(entry, *file_offset)) { - ret = 1; - goto out; - } - - dec_start = max(*file_offset, entry->file_offset); - dec_end = min(*file_offset + io_size, entry->file_offset + - entry->len); - *file_offset = dec_end; - if (dec_start > dec_end) { - btrfs_crit(BTRFS_I(inode)->root->fs_info, - "bad ordering dec_start %llu end %llu", dec_start, dec_end); - } - to_dec = dec_end - dec_start; - if (to_dec > entry->bytes_left) { - btrfs_crit(BTRFS_I(inode)->root->fs_info, - "bad ordered accounting left %llu size %llu", - entry->bytes_left, to_dec); - } - entry->bytes_left -= to_dec; - if (!uptodate) - set_bit(BTRFS_ORDERED_IOERR, &entry->flags); - - if (entry->bytes_left == 0) { - ret = test_and_set_bit(BTRFS_ORDERED_IO_DONE, &entry->flags); - /* - * Implicit memory barrier after test_and_set_bit - */ - if (waitqueue_active(&entry->wait)) - wake_up(&entry->wait); - } else { - ret = 1; - } -out: - if (!ret && cached && entry) { - *cached = entry; - atomic_inc(&entry->refs); - } - spin_unlock_irqrestore(&tree->lock, flags); - return ret == 0; -} - -/* - * this is used to account for finished IO across a given range - * of the file. The IO should not span ordered extents. If - * a given ordered_extent is completely done, 1 is returned, otherwise - * 0. - * - * test_and_set_bit on a flag in the struct btrfs_ordered_extent is used - * to make sure this function only returns 1 once for a given ordered extent. - */ -int btrfs_dec_test_ordered_pending(struct inode *inode, - struct btrfs_ordered_extent **cached, - u64 file_offset, u64 io_size, int uptodate) -{ - struct btrfs_ordered_inode_tree *tree; - struct rb_node *node; - struct btrfs_ordered_extent *entry = NULL; - unsigned long flags; - int ret; - - tree = &BTRFS_I(inode)->ordered_tree; - spin_lock_irqsave(&tree->lock, flags); - if (cached && *cached) { - entry = *cached; - goto have_entry; - } - - node = tree_search(tree, file_offset); - if (!node) { - ret = 1; - goto out; - } - - entry = rb_entry(node, struct btrfs_ordered_extent, rb_node); -have_entry: - if (!offset_in_entry(entry, file_offset)) { - ret = 1; - goto out; - } - - if (io_size > entry->bytes_left) { - btrfs_crit(BTRFS_I(inode)->root->fs_info, - "bad ordered accounting left %llu size %llu", - entry->bytes_left, io_size); - } - entry->bytes_left -= io_size; - if (!uptodate) - set_bit(BTRFS_ORDERED_IOERR, &entry->flags); - - if (entry->bytes_left == 0) { - ret = test_and_set_bit(BTRFS_ORDERED_IO_DONE, &entry->flags); - /* - * Implicit memory barrier after test_and_set_bit - */ - if (waitqueue_active(&entry->wait)) - wake_up(&entry->wait); - } else { - ret = 1; - } -out: - if (!ret && cached && entry) { - *cached = entry; - atomic_inc(&entry->refs); - } - spin_unlock_irqrestore(&tree->lock, flags); - return ret == 0; -} - -/* Needs to either be called under a log transaction or the log_mutex */ -void btrfs_get_logged_extents(struct inode *inode, - struct list_head *logged_list, - const loff_t start, - const loff_t end) -{ - struct btrfs_ordered_inode_tree *tree; - struct btrfs_ordered_extent *ordered; - struct rb_node *n; - struct rb_node *prev; - - tree = &BTRFS_I(inode)->ordered_tree; - spin_lock_irq(&tree->lock); - n = __tree_search(&tree->tree, end, &prev); - if (!n) - n = prev; - for (; n; n = rb_prev(n)) { - ordered = rb_entry(n, struct btrfs_ordered_extent, rb_node); - if (ordered->file_offset > end) - continue; - if (entry_end(ordered) <= start) - break; - if (test_and_set_bit(BTRFS_ORDERED_LOGGED, &ordered->flags)) - continue; - list_add(&ordered->log_list, logged_list); - atomic_inc(&ordered->refs); - } - spin_unlock_irq(&tree->lock); -} - -void btrfs_put_logged_extents(struct list_head *logged_list) -{ - struct btrfs_ordered_extent *ordered; - - while (!list_empty(logged_list)) { - ordered = list_first_entry(logged_list, - struct btrfs_ordered_extent, - log_list); - list_del_init(&ordered->log_list); - btrfs_put_ordered_extent(ordered); - } -} - -void btrfs_submit_logged_extents(struct list_head *logged_list, - struct btrfs_root *log) -{ - int index = log->log_transid % 2; - - spin_lock_irq(&log->log_extents_lock[index]); - list_splice_tail(logged_list, &log->logged_list[index]); - spin_unlock_irq(&log->log_extents_lock[index]); -} - -void btrfs_wait_logged_extents(struct btrfs_trans_handle *trans, - struct btrfs_root *log, u64 transid) -{ - struct btrfs_ordered_extent *ordered; - int index = transid % 2; - - spin_lock_irq(&log->log_extents_lock[index]); - while (!list_empty(&log->logged_list[index])) { - struct inode *inode; - ordered = list_first_entry(&log->logged_list[index], - struct btrfs_ordered_extent, - log_list); - list_del_init(&ordered->log_list); - inode = ordered->inode; - spin_unlock_irq(&log->log_extents_lock[index]); - - if (!test_bit(BTRFS_ORDERED_IO_DONE, &ordered->flags) && - !test_bit(BTRFS_ORDERED_DIRECT, &ordered->flags)) { - u64 start = ordered->file_offset; - u64 end = ordered->file_offset + ordered->len - 1; - - WARN_ON(!inode); - filemap_fdatawrite_range(inode->i_mapping, start, end); - } - wait_event(ordered->wait, test_bit(BTRFS_ORDERED_IO_DONE, - &ordered->flags)); - - /* - * In order to keep us from losing our ordered extent - * information when committing the transaction we have to make - * sure that any logged extents are completed when we go to - * commit the transaction. To do this we simply increase the - * current transactions pending_ordered counter and decrement it - * when the ordered extent completes. - */ - if (!test_bit(BTRFS_ORDERED_COMPLETE, &ordered->flags)) { - struct btrfs_ordered_inode_tree *tree; - - tree = &BTRFS_I(inode)->ordered_tree; - spin_lock_irq(&tree->lock); - if (!test_bit(BTRFS_ORDERED_COMPLETE, &ordered->flags)) { - set_bit(BTRFS_ORDERED_PENDING, &ordered->flags); - atomic_inc(&trans->transaction->pending_ordered); - } - spin_unlock_irq(&tree->lock); - } - btrfs_put_ordered_extent(ordered); - spin_lock_irq(&log->log_extents_lock[index]); - } - spin_unlock_irq(&log->log_extents_lock[index]); -} - -void btrfs_free_logged_extents(struct btrfs_root *log, u64 transid) -{ - struct btrfs_ordered_extent *ordered; - int index = transid % 2; - - spin_lock_irq(&log->log_extents_lock[index]); - while (!list_empty(&log->logged_list[index])) { - ordered = list_first_entry(&log->logged_list[index], - struct btrfs_ordered_extent, - log_list); - list_del_init(&ordered->log_list); - spin_unlock_irq(&log->log_extents_lock[index]); - btrfs_put_ordered_extent(ordered); - spin_lock_irq(&log->log_extents_lock[index]); - } - spin_unlock_irq(&log->log_extents_lock[index]); -} - -/* - * used to drop a reference on an ordered extent. This will free - * the extent if the last reference is dropped - */ -void btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry) -{ - struct list_head *cur; - struct btrfs_ordered_sum *sum; - - trace_btrfs_ordered_extent_put(entry->inode, entry); - - if (atomic_dec_and_test(&entry->refs)) { - ASSERT(list_empty(&entry->log_list)); - ASSERT(list_empty(&entry->trans_list)); - ASSERT(list_empty(&entry->root_extent_list)); - ASSERT(RB_EMPTY_NODE(&entry->rb_node)); - if (entry->inode) - btrfs_add_delayed_iput(entry->inode); - while (!list_empty(&entry->list)) { - cur = entry->list.next; - sum = list_entry(cur, struct btrfs_ordered_sum, list); - list_del(&sum->list); - kfree(sum); - } - kmem_cache_free(btrfs_ordered_extent_cache, entry); - } -} - -/* - * remove an ordered extent from the tree. No references are dropped - * and waiters are woken up. - */ -void btrfs_remove_ordered_extent(struct inode *inode, - struct btrfs_ordered_extent *entry) -{ - struct btrfs_ordered_inode_tree *tree; - struct btrfs_root *root = BTRFS_I(inode)->root; - struct rb_node *node; - bool dec_pending_ordered = false; - - tree = &BTRFS_I(inode)->ordered_tree; - spin_lock_irq(&tree->lock); - node = &entry->rb_node; - rb_erase(node, &tree->tree); - RB_CLEAR_NODE(node); - if (tree->last == node) - tree->last = NULL; - set_bit(BTRFS_ORDERED_COMPLETE, &entry->flags); - if (test_and_clear_bit(BTRFS_ORDERED_PENDING, &entry->flags)) - dec_pending_ordered = true; - spin_unlock_irq(&tree->lock); - - /* - * The current running transaction is waiting on us, we need to let it - * know that we're complete and wake it up. - */ - if (dec_pending_ordered) { - struct btrfs_transaction *trans; - - /* - * The checks for trans are just a formality, it should be set, - * but if it isn't we don't want to deref/assert under the spin - * lock, so be nice and check if trans is set, but ASSERT() so - * if it isn't set a developer will notice. - */ - spin_lock(&root->fs_info->trans_lock); - trans = root->fs_info->running_transaction; - if (trans) - atomic_inc(&trans->use_count); - spin_unlock(&root->fs_info->trans_lock); - - ASSERT(trans); - if (trans) { - if (atomic_dec_and_test(&trans->pending_ordered)) - wake_up(&trans->pending_wait); - btrfs_put_transaction(trans); - } - } - - spin_lock(&root->ordered_extent_lock); - list_del_init(&entry->root_extent_list); - root->nr_ordered_extents--; - - trace_btrfs_ordered_extent_remove(inode, entry); - - if (!root->nr_ordered_extents) { - spin_lock(&root->fs_info->ordered_root_lock); - BUG_ON(list_empty(&root->ordered_root)); - list_del_init(&root->ordered_root); - spin_unlock(&root->fs_info->ordered_root_lock); - } - spin_unlock(&root->ordered_extent_lock); - wake_up(&entry->wait); -} - -static void btrfs_run_ordered_extent_work(struct btrfs_work *work) -{ - struct btrfs_ordered_extent *ordered; - - ordered = container_of(work, struct btrfs_ordered_extent, flush_work); - btrfs_start_ordered_extent(ordered->inode, ordered, 1); - complete(&ordered->completion); -} - -/* - * wait for all the ordered extents in a root. This is done when balancing - * space between drives. - */ -int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr, - const u64 range_start, const u64 range_len) -{ - LIST_HEAD(splice); - LIST_HEAD(skipped); - LIST_HEAD(works); - struct btrfs_ordered_extent *ordered, *next; - int count = 0; - const u64 range_end = range_start + range_len; - - mutex_lock(&root->ordered_extent_mutex); - spin_lock(&root->ordered_extent_lock); - list_splice_init(&root->ordered_extents, &splice); - while (!list_empty(&splice) && nr) { - ordered = list_first_entry(&splice, struct btrfs_ordered_extent, - root_extent_list); - - if (range_end <= ordered->start || - ordered->start + ordered->disk_len <= range_start) { - list_move_tail(&ordered->root_extent_list, &skipped); - cond_resched_lock(&root->ordered_extent_lock); - continue; - } - - list_move_tail(&ordered->root_extent_list, - &root->ordered_extents); - atomic_inc(&ordered->refs); - spin_unlock(&root->ordered_extent_lock); - - btrfs_init_work(&ordered->flush_work, - btrfs_flush_delalloc_helper, - btrfs_run_ordered_extent_work, NULL, NULL); - list_add_tail(&ordered->work_list, &works); - btrfs_queue_work(root->fs_info->flush_workers, - &ordered->flush_work); - - cond_resched(); - spin_lock(&root->ordered_extent_lock); - if (nr != -1) - nr--; - count++; - } - list_splice_tail(&skipped, &root->ordered_extents); - list_splice_tail(&splice, &root->ordered_extents); - spin_unlock(&root->ordered_extent_lock); - - list_for_each_entry_safe(ordered, next, &works, work_list) { - list_del_init(&ordered->work_list); - wait_for_completion(&ordered->completion); - btrfs_put_ordered_extent(ordered); - cond_resched(); - } - mutex_unlock(&root->ordered_extent_mutex); - - return count; -} - -int btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr, - const u64 range_start, const u64 range_len) -{ - struct btrfs_root *root; - struct list_head splice; - int done; - int total_done = 0; - - INIT_LIST_HEAD(&splice); - - mutex_lock(&fs_info->ordered_operations_mutex); - spin_lock(&fs_info->ordered_root_lock); - list_splice_init(&fs_info->ordered_roots, &splice); - while (!list_empty(&splice) && nr) { - root = list_first_entry(&splice, struct btrfs_root, - ordered_root); - root = btrfs_grab_fs_root(root); - BUG_ON(!root); - list_move_tail(&root->ordered_root, - &fs_info->ordered_roots); - spin_unlock(&fs_info->ordered_root_lock); - - done = btrfs_wait_ordered_extents(root, nr, - range_start, range_len); - btrfs_put_fs_root(root); - total_done += done; - - spin_lock(&fs_info->ordered_root_lock); - if (nr != -1) { - nr -= done; - WARN_ON(nr < 0); - } - } - list_splice_tail(&splice, &fs_info->ordered_roots); - spin_unlock(&fs_info->ordered_root_lock); - mutex_unlock(&fs_info->ordered_operations_mutex); - - return total_done; -} - -/* - * Used to start IO or wait for a given ordered extent to finish. - * - * If wait is one, this effectively waits on page writeback for all the pages - * in the extent, and it waits on the io completion code to insert - * metadata into the btree corresponding to the extent - */ -void btrfs_start_ordered_extent(struct inode *inode, - struct btrfs_ordered_extent *entry, - int wait) -{ - u64 start = entry->file_offset; - u64 end = start + entry->len - 1; - - trace_btrfs_ordered_extent_start(inode, entry); - - /* - * pages in the range can be dirty, clean or writeback. We - * start IO on any dirty ones so the wait doesn't stall waiting - * for the flusher thread to find them - */ - if (!test_bit(BTRFS_ORDERED_DIRECT, &entry->flags)) - filemap_fdatawrite_range(inode->i_mapping, start, end); - if (wait) { - wait_event(entry->wait, test_bit(BTRFS_ORDERED_COMPLETE, - &entry->flags)); - } -} - -/* - * Used to wait on ordered extents across a large range of bytes. - */ -int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len) -{ - int ret = 0; - int ret_wb = 0; - u64 end; - u64 orig_end; - struct btrfs_ordered_extent *ordered; - - if (start + len < start) { - orig_end = INT_LIMIT(loff_t); - } else { - orig_end = start + len - 1; - if (orig_end > INT_LIMIT(loff_t)) - orig_end = INT_LIMIT(loff_t); - } - - /* start IO across the range first to instantiate any delalloc - * extents - */ - ret = btrfs_fdatawrite_range(inode, start, orig_end); - if (ret) - return ret; - - /* - * If we have a writeback error don't return immediately. Wait first - * for any ordered extents that haven't completed yet. This is to make - * sure no one can dirty the same page ranges and call writepages() - * before the ordered extents complete - to avoid failures (-EEXIST) - * when adding the new ordered extents to the ordered tree. - */ - ret_wb = filemap_fdatawait_range(inode->i_mapping, start, orig_end); - - end = orig_end; - while (1) { - ordered = btrfs_lookup_first_ordered_extent(inode, end); - if (!ordered) - break; - if (ordered->file_offset > orig_end) { - btrfs_put_ordered_extent(ordered); - break; - } - if (ordered->file_offset + ordered->len <= start) { - btrfs_put_ordered_extent(ordered); - break; - } - btrfs_start_ordered_extent(inode, ordered, 1); - end = ordered->file_offset; - if (test_bit(BTRFS_ORDERED_IOERR, &ordered->flags)) - ret = -EIO; - btrfs_put_ordered_extent(ordered); - if (ret || end == 0 || end == start) - break; - end--; - } - return ret_wb ? ret_wb : ret; -} - -/* - * find an ordered extent corresponding to file_offset. return NULL if - * nothing is found, otherwise take a reference on the extent and return it - */ -struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct inode *inode, - u64 file_offset) -{ - struct btrfs_ordered_inode_tree *tree; - struct rb_node *node; - struct btrfs_ordered_extent *entry = NULL; - - tree = &BTRFS_I(inode)->ordered_tree; - spin_lock_irq(&tree->lock); - node = tree_search(tree, file_offset); - if (!node) - goto out; - - entry = rb_entry(node, struct btrfs_ordered_extent, rb_node); - if (!offset_in_entry(entry, file_offset)) - entry = NULL; - if (entry) - atomic_inc(&entry->refs); -out: - spin_unlock_irq(&tree->lock); - return entry; -} - -/* Since the DIO code tries to lock a wide area we need to look for any ordered - * extents that exist in the range, rather than just the start of the range. - */ -struct btrfs_ordered_extent *btrfs_lookup_ordered_range(struct inode *inode, - u64 file_offset, - u64 len) -{ - struct btrfs_ordered_inode_tree *tree; - struct rb_node *node; - struct btrfs_ordered_extent *entry = NULL; - - tree = &BTRFS_I(inode)->ordered_tree; - spin_lock_irq(&tree->lock); - node = tree_search(tree, file_offset); - if (!node) { - node = tree_search(tree, file_offset + len); - if (!node) - goto out; - } - - while (1) { - entry = rb_entry(node, struct btrfs_ordered_extent, rb_node); - if (range_overlaps(entry, file_offset, len)) - break; - - if (entry->file_offset >= file_offset + len) { - entry = NULL; - break; - } - entry = NULL; - node = rb_next(node); - if (!node) - break; - } -out: - if (entry) - atomic_inc(&entry->refs); - spin_unlock_irq(&tree->lock); - return entry; -} - -bool btrfs_have_ordered_extents_in_range(struct inode *inode, - u64 file_offset, - u64 len) -{ - struct btrfs_ordered_extent *oe; - - oe = btrfs_lookup_ordered_range(inode, file_offset, len); - if (oe) { - btrfs_put_ordered_extent(oe); - return true; - } - return false; -} - -/* - * lookup and return any extent before 'file_offset'. NULL is returned - * if none is found - */ -struct btrfs_ordered_extent * -btrfs_lookup_first_ordered_extent(struct inode *inode, u64 file_offset) -{ - struct btrfs_ordered_inode_tree *tree; - struct rb_node *node; - struct btrfs_ordered_extent *entry = NULL; - - tree = &BTRFS_I(inode)->ordered_tree; - spin_lock_irq(&tree->lock); - node = tree_search(tree, file_offset); - if (!node) - goto out; - - entry = rb_entry(node, struct btrfs_ordered_extent, rb_node); - atomic_inc(&entry->refs); -out: - spin_unlock_irq(&tree->lock); - return entry; -} - -/* - * After an extent is done, call this to conditionally update the on disk - * i_size. i_size is updated to cover any fully written part of the file. - */ -int btrfs_ordered_update_i_size(struct inode *inode, u64 offset, - struct btrfs_ordered_extent *ordered) -{ - struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree; - u64 disk_i_size; - u64 new_i_size; - u64 i_size = i_size_read(inode); - struct rb_node *node; - struct rb_node *prev = NULL; - struct btrfs_ordered_extent *test; - int ret = 1; - u64 orig_offset = offset; - - spin_lock_irq(&tree->lock); - if (ordered) { - offset = entry_end(ordered); - if (test_bit(BTRFS_ORDERED_TRUNCATED, &ordered->flags)) - offset = min(offset, - ordered->file_offset + - ordered->truncated_len); - } else { - offset = ALIGN(offset, BTRFS_I(inode)->root->sectorsize); - } - disk_i_size = BTRFS_I(inode)->disk_i_size; - - /* truncate file */ - if (disk_i_size > i_size) { - BTRFS_I(inode)->disk_i_size = orig_offset; - ret = 0; - goto out; - } - - /* - * if the disk i_size is already at the inode->i_size, or - * this ordered extent is inside the disk i_size, we're done - */ - if (disk_i_size == i_size) - goto out; - - /* - * We still need to update disk_i_size if outstanding_isize is greater - * than disk_i_size. - */ - if (offset <= disk_i_size && - (!ordered || ordered->outstanding_isize <= disk_i_size)) - goto out; - - /* - * walk backward from this ordered extent to disk_i_size. - * if we find an ordered extent then we can't update disk i_size - * yet - */ - if (ordered) { - node = rb_prev(&ordered->rb_node); - } else { - prev = tree_search(tree, offset); - /* - * we insert file extents without involving ordered struct, - * so there should be no ordered struct cover this offset - */ - if (prev) { - test = rb_entry(prev, struct btrfs_ordered_extent, - rb_node); - BUG_ON(offset_in_entry(test, offset)); - } - node = prev; - } - for (; node; node = rb_prev(node)) { - test = rb_entry(node, struct btrfs_ordered_extent, rb_node); - - /* We treat this entry as if it doesn't exist */ - if (test_bit(BTRFS_ORDERED_UPDATED_ISIZE, &test->flags)) - continue; - if (test->file_offset + test->len <= disk_i_size) - break; - if (test->file_offset >= i_size) - break; - if (entry_end(test) > disk_i_size) { - /* - * we don't update disk_i_size now, so record this - * undealt i_size. Or we will not know the real - * i_size. - */ - if (test->outstanding_isize < offset) - test->outstanding_isize = offset; - if (ordered && - ordered->outstanding_isize > - test->outstanding_isize) - test->outstanding_isize = - ordered->outstanding_isize; - goto out; - } - } - new_i_size = min_t(u64, offset, i_size); - - /* - * Some ordered extents may completed before the current one, and - * we hold the real i_size in ->outstanding_isize. - */ - if (ordered && ordered->outstanding_isize > new_i_size) - new_i_size = min_t(u64, ordered->outstanding_isize, i_size); - BTRFS_I(inode)->disk_i_size = new_i_size; - ret = 0; -out: - /* - * We need to do this because we can't remove ordered extents until - * after the i_disk_size has been updated and then the inode has been - * updated to reflect the change, so we need to tell anybody who finds - * this ordered extent that we've already done all the real work, we - * just haven't completed all the other work. - */ - if (ordered) - set_bit(BTRFS_ORDERED_UPDATED_ISIZE, &ordered->flags); - spin_unlock_irq(&tree->lock); - return ret; -} - -/* - * search the ordered extents for one corresponding to 'offset' and - * try to find a checksum. This is used because we allow pages to - * be reclaimed before their checksum is actually put into the btree - */ -int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, - u32 *sum, int len) -{ - struct btrfs_ordered_sum *ordered_sum; - struct btrfs_ordered_extent *ordered; - struct btrfs_ordered_inode_tree *tree = &BTRFS_I(inode)->ordered_tree; - unsigned long num_sectors; - unsigned long i; - u32 sectorsize = BTRFS_I(inode)->root->sectorsize; - int index = 0; - - ordered = btrfs_lookup_ordered_extent(inode, offset); - if (!ordered) - return 0; - - spin_lock_irq(&tree->lock); - list_for_each_entry_reverse(ordered_sum, &ordered->list, list) { - if (disk_bytenr >= ordered_sum->bytenr && - disk_bytenr < ordered_sum->bytenr + ordered_sum->len) { - i = (disk_bytenr - ordered_sum->bytenr) >> - inode->i_sb->s_blocksize_bits; - num_sectors = ordered_sum->len >> - inode->i_sb->s_blocksize_bits; - num_sectors = min_t(int, len - index, num_sectors - i); - memcpy(sum + index, ordered_sum->sums + i, - num_sectors); - - index += (int)num_sectors; - if (index == len) - goto out; - disk_bytenr += num_sectors * sectorsize; - } - } -out: - spin_unlock_irq(&tree->lock); - btrfs_put_ordered_extent(ordered); - return index; -} - -int __init ordered_data_init(void) -{ - btrfs_ordered_extent_cache = kmem_cache_create("btrfs_ordered_extent", - sizeof(struct btrfs_ordered_extent), 0, - SLAB_MEM_SPREAD, - NULL); - if (!btrfs_ordered_extent_cache) - return -ENOMEM; - - return 0; -} - -void ordered_data_exit(void) -{ - kmem_cache_destroy(btrfs_ordered_extent_cache); -} diff --git a/src/linux/fs/btrfs/ordered-data.h b/src/linux/fs/btrfs/ordered-data.h deleted file mode 100644 index 4515077..0000000 --- a/src/linux/fs/btrfs/ordered-data.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __BTRFS_ORDERED_DATA__ -#define __BTRFS_ORDERED_DATA__ - -/* one of these per inode */ -struct btrfs_ordered_inode_tree { - spinlock_t lock; - struct rb_root tree; - struct rb_node *last; -}; - -struct btrfs_ordered_sum { - /* bytenr is the start of this extent on disk */ - u64 bytenr; - - /* - * this is the length in bytes covered by the sums array below. - */ - int len; - struct list_head list; - /* last field is a variable length array of csums */ - u32 sums[]; -}; - -/* - * bits for the flags field: - * - * BTRFS_ORDERED_IO_DONE is set when all of the blocks are written. - * It is used to make sure metadata is inserted into the tree only once - * per extent. - * - * BTRFS_ORDERED_COMPLETE is set when the extent is removed from the - * rbtree, just before waking any waiters. It is used to indicate the - * IO is done and any metadata is inserted into the tree. - */ -#define BTRFS_ORDERED_IO_DONE 0 /* set when all the pages are written */ - -#define BTRFS_ORDERED_COMPLETE 1 /* set when removed from the tree */ - -#define BTRFS_ORDERED_NOCOW 2 /* set when we want to write in place */ - -#define BTRFS_ORDERED_COMPRESSED 3 /* writing a zlib compressed extent */ - -#define BTRFS_ORDERED_PREALLOC 4 /* set when writing to preallocated extent */ - -#define BTRFS_ORDERED_DIRECT 5 /* set when we're doing DIO with this extent */ - -#define BTRFS_ORDERED_IOERR 6 /* We had an io error when writing this out */ - -#define BTRFS_ORDERED_UPDATED_ISIZE 7 /* indicates whether this ordered extent - * has done its due diligence in updating - * the isize. */ -#define BTRFS_ORDERED_LOGGED_CSUM 8 /* We've logged the csums on this ordered - ordered extent */ -#define BTRFS_ORDERED_TRUNCATED 9 /* Set when we have to truncate an extent */ - -#define BTRFS_ORDERED_LOGGED 10 /* Set when we've waited on this ordered extent - * in the logging code. */ -#define BTRFS_ORDERED_PENDING 11 /* We are waiting for this ordered extent to - * complete in the current transaction. */ -struct btrfs_ordered_extent { - /* logical offset in the file */ - u64 file_offset; - - /* disk byte number */ - u64 start; - - /* ram length of the extent in bytes */ - u64 len; - - /* extent length on disk */ - u64 disk_len; - - /* number of bytes that still need writing */ - u64 bytes_left; - - /* - * the end of the ordered extent which is behind it but - * didn't update disk_i_size. Please see the comment of - * btrfs_ordered_update_i_size(); - */ - u64 outstanding_isize; - - /* - * If we get truncated we need to adjust the file extent we enter for - * this ordered extent so that we do not expose stale data. - */ - u64 truncated_len; - - /* flags (described above) */ - unsigned long flags; - - /* compression algorithm */ - int compress_type; - - /* reference count */ - atomic_t refs; - - /* the inode we belong to */ - struct inode *inode; - - /* list of checksums for insertion when the extent io is done */ - struct list_head list; - - /* If we need to wait on this to be done */ - struct list_head log_list; - - /* If the transaction needs to wait on this ordered extent */ - struct list_head trans_list; - - /* used to wait for the BTRFS_ORDERED_COMPLETE bit */ - wait_queue_head_t wait; - - /* our friendly rbtree entry */ - struct rb_node rb_node; - - /* a per root list of all the pending ordered extents */ - struct list_head root_extent_list; - - struct btrfs_work work; - - struct completion completion; - struct btrfs_work flush_work; - struct list_head work_list; -}; - -/* - * calculates the total size you need to allocate for an ordered sum - * structure spanning 'bytes' in the file - */ -static inline int btrfs_ordered_sum_size(struct btrfs_root *root, - unsigned long bytes) -{ - int num_sectors = (int)DIV_ROUND_UP(bytes, root->sectorsize); - return sizeof(struct btrfs_ordered_sum) + num_sectors * sizeof(u32); -} - -static inline void -btrfs_ordered_inode_tree_init(struct btrfs_ordered_inode_tree *t) -{ - spin_lock_init(&t->lock); - t->tree = RB_ROOT; - t->last = NULL; -} - -void btrfs_put_ordered_extent(struct btrfs_ordered_extent *entry); -void btrfs_remove_ordered_extent(struct inode *inode, - struct btrfs_ordered_extent *entry); -int btrfs_dec_test_ordered_pending(struct inode *inode, - struct btrfs_ordered_extent **cached, - u64 file_offset, u64 io_size, int uptodate); -int btrfs_dec_test_first_ordered_pending(struct inode *inode, - struct btrfs_ordered_extent **cached, - u64 *file_offset, u64 io_size, - int uptodate); -int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, - u64 start, u64 len, u64 disk_len, int type); -int btrfs_add_ordered_extent_dio(struct inode *inode, u64 file_offset, - u64 start, u64 len, u64 disk_len, int type); -int btrfs_add_ordered_extent_compress(struct inode *inode, u64 file_offset, - u64 start, u64 len, u64 disk_len, - int type, int compress_type); -void btrfs_add_ordered_sum(struct inode *inode, - struct btrfs_ordered_extent *entry, - struct btrfs_ordered_sum *sum); -struct btrfs_ordered_extent *btrfs_lookup_ordered_extent(struct inode *inode, - u64 file_offset); -void btrfs_start_ordered_extent(struct inode *inode, - struct btrfs_ordered_extent *entry, int wait); -int btrfs_wait_ordered_range(struct inode *inode, u64 start, u64 len); -struct btrfs_ordered_extent * -btrfs_lookup_first_ordered_extent(struct inode * inode, u64 file_offset); -struct btrfs_ordered_extent *btrfs_lookup_ordered_range(struct inode *inode, - u64 file_offset, - u64 len); -bool btrfs_have_ordered_extents_in_range(struct inode *inode, - u64 file_offset, - u64 len); -int btrfs_ordered_update_i_size(struct inode *inode, u64 offset, - struct btrfs_ordered_extent *ordered); -int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, - u32 *sum, int len); -int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr, - const u64 range_start, const u64 range_len); -int btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr, - const u64 range_start, const u64 range_len); -void btrfs_get_logged_extents(struct inode *inode, - struct list_head *logged_list, - const loff_t start, - const loff_t end); -void btrfs_put_logged_extents(struct list_head *logged_list); -void btrfs_submit_logged_extents(struct list_head *logged_list, - struct btrfs_root *log); -void btrfs_wait_logged_extents(struct btrfs_trans_handle *trans, - struct btrfs_root *log, u64 transid); -void btrfs_free_logged_extents(struct btrfs_root *log, u64 transid); -int __init ordered_data_init(void); -void ordered_data_exit(void); -#endif diff --git a/src/linux/fs/btrfs/orphan.c b/src/linux/fs/btrfs/orphan.c deleted file mode 100644 index 47767d5..0000000 --- a/src/linux/fs/btrfs/orphan.c +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2008 Red Hat. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include "ctree.h" -#include "disk-io.h" - -int btrfs_insert_orphan_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 offset) -{ - struct btrfs_path *path; - struct btrfs_key key; - int ret = 0; - - key.objectid = BTRFS_ORPHAN_OBJECTID; - key.type = BTRFS_ORPHAN_ITEM_KEY; - key.offset = offset; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - ret = btrfs_insert_empty_item(trans, root, path, &key, 0); - - btrfs_free_path(path); - return ret; -} - -int btrfs_del_orphan_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 offset) -{ - struct btrfs_path *path; - struct btrfs_key key; - int ret = 0; - - key.objectid = BTRFS_ORPHAN_OBJECTID; - key.type = BTRFS_ORPHAN_ITEM_KEY; - key.offset = offset; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret < 0) - goto out; - if (ret) { /* JDM: Really? */ - ret = -ENOENT; - goto out; - } - - ret = btrfs_del_item(trans, root, path); - -out: - btrfs_free_path(path); - return ret; -} diff --git a/src/linux/fs/btrfs/print-tree.c b/src/linux/fs/btrfs/print-tree.c deleted file mode 100644 index 438575e..0000000 --- a/src/linux/fs/btrfs/print-tree.c +++ /dev/null @@ -1,361 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include "ctree.h" -#include "disk-io.h" -#include "print-tree.h" - -static void print_chunk(struct extent_buffer *eb, struct btrfs_chunk *chunk) -{ - int num_stripes = btrfs_chunk_num_stripes(eb, chunk); - int i; - pr_info("\t\tchunk length %llu owner %llu type %llu num_stripes %d\n", - btrfs_chunk_length(eb, chunk), btrfs_chunk_owner(eb, chunk), - btrfs_chunk_type(eb, chunk), num_stripes); - for (i = 0 ; i < num_stripes ; i++) { - pr_info("\t\t\tstripe %d devid %llu offset %llu\n", i, - btrfs_stripe_devid_nr(eb, chunk, i), - btrfs_stripe_offset_nr(eb, chunk, i)); - } -} -static void print_dev_item(struct extent_buffer *eb, - struct btrfs_dev_item *dev_item) -{ - pr_info("\t\tdev item devid %llu total_bytes %llu bytes used %llu\n", - btrfs_device_id(eb, dev_item), - btrfs_device_total_bytes(eb, dev_item), - btrfs_device_bytes_used(eb, dev_item)); -} -static void print_extent_data_ref(struct extent_buffer *eb, - struct btrfs_extent_data_ref *ref) -{ - pr_info("\t\textent data backref root %llu objectid %llu offset %llu count %u\n", - btrfs_extent_data_ref_root(eb, ref), - btrfs_extent_data_ref_objectid(eb, ref), - btrfs_extent_data_ref_offset(eb, ref), - btrfs_extent_data_ref_count(eb, ref)); -} - -static void print_extent_item(struct extent_buffer *eb, int slot, int type) -{ - struct btrfs_extent_item *ei; - struct btrfs_extent_inline_ref *iref; - struct btrfs_extent_data_ref *dref; - struct btrfs_shared_data_ref *sref; - struct btrfs_disk_key key; - unsigned long end; - unsigned long ptr; - u32 item_size = btrfs_item_size_nr(eb, slot); - u64 flags; - u64 offset; - - if (item_size < sizeof(*ei)) { -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - struct btrfs_extent_item_v0 *ei0; - BUG_ON(item_size != sizeof(*ei0)); - ei0 = btrfs_item_ptr(eb, slot, struct btrfs_extent_item_v0); - pr_info("\t\textent refs %u\n", - btrfs_extent_refs_v0(eb, ei0)); - return; -#else - BUG(); -#endif - } - - ei = btrfs_item_ptr(eb, slot, struct btrfs_extent_item); - flags = btrfs_extent_flags(eb, ei); - - pr_info("\t\textent refs %llu gen %llu flags %llu\n", - btrfs_extent_refs(eb, ei), btrfs_extent_generation(eb, ei), - flags); - - if ((type == BTRFS_EXTENT_ITEM_KEY) && - flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { - struct btrfs_tree_block_info *info; - info = (struct btrfs_tree_block_info *)(ei + 1); - btrfs_tree_block_key(eb, info, &key); - pr_info("\t\ttree block key (%llu %u %llu) level %d\n", - btrfs_disk_key_objectid(&key), key.type, - btrfs_disk_key_offset(&key), - btrfs_tree_block_level(eb, info)); - iref = (struct btrfs_extent_inline_ref *)(info + 1); - } else { - iref = (struct btrfs_extent_inline_ref *)(ei + 1); - } - - ptr = (unsigned long)iref; - end = (unsigned long)ei + item_size; - while (ptr < end) { - iref = (struct btrfs_extent_inline_ref *)ptr; - type = btrfs_extent_inline_ref_type(eb, iref); - offset = btrfs_extent_inline_ref_offset(eb, iref); - switch (type) { - case BTRFS_TREE_BLOCK_REF_KEY: - pr_info("\t\ttree block backref root %llu\n", offset); - break; - case BTRFS_SHARED_BLOCK_REF_KEY: - pr_info("\t\tshared block backref parent %llu\n", offset); - break; - case BTRFS_EXTENT_DATA_REF_KEY: - dref = (struct btrfs_extent_data_ref *)(&iref->offset); - print_extent_data_ref(eb, dref); - break; - case BTRFS_SHARED_DATA_REF_KEY: - sref = (struct btrfs_shared_data_ref *)(iref + 1); - pr_info("\t\tshared data backref parent %llu count %u\n", - offset, btrfs_shared_data_ref_count(eb, sref)); - break; - default: - BUG(); - } - ptr += btrfs_extent_inline_ref_size(type); - } - WARN_ON(ptr > end); -} - -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 -static void print_extent_ref_v0(struct extent_buffer *eb, int slot) -{ - struct btrfs_extent_ref_v0 *ref0; - - ref0 = btrfs_item_ptr(eb, slot, struct btrfs_extent_ref_v0); - printk("\t\textent back ref root %llu gen %llu owner %llu num_refs %lu\n", - btrfs_ref_root_v0(eb, ref0), - btrfs_ref_generation_v0(eb, ref0), - btrfs_ref_objectid_v0(eb, ref0), - (unsigned long)btrfs_ref_count_v0(eb, ref0)); -} -#endif - -static void print_uuid_item(struct extent_buffer *l, unsigned long offset, - u32 item_size) -{ - if (!IS_ALIGNED(item_size, sizeof(u64))) { - pr_warn("BTRFS: uuid item with illegal size %lu!\n", - (unsigned long)item_size); - return; - } - while (item_size) { - __le64 subvol_id; - - read_extent_buffer(l, &subvol_id, offset, sizeof(subvol_id)); - pr_info("\t\tsubvol_id %llu\n", - (unsigned long long)le64_to_cpu(subvol_id)); - item_size -= sizeof(u64); - offset += sizeof(u64); - } -} - -void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l) -{ - int i; - u32 type, nr; - struct btrfs_item *item; - struct btrfs_root_item *ri; - struct btrfs_dir_item *di; - struct btrfs_inode_item *ii; - struct btrfs_block_group_item *bi; - struct btrfs_file_extent_item *fi; - struct btrfs_extent_data_ref *dref; - struct btrfs_shared_data_ref *sref; - struct btrfs_dev_extent *dev_extent; - struct btrfs_key key; - struct btrfs_key found_key; - - if (!l) - return; - - nr = btrfs_header_nritems(l); - - btrfs_info(root->fs_info, "leaf %llu total ptrs %d free space %d", - btrfs_header_bytenr(l), nr, btrfs_leaf_free_space(root, l)); - for (i = 0 ; i < nr ; i++) { - item = btrfs_item_nr(i); - btrfs_item_key_to_cpu(l, &key, i); - type = key.type; - pr_info("\titem %d key (%llu %u %llu) itemoff %d itemsize %d\n", - i, key.objectid, type, key.offset, - btrfs_item_offset(l, item), btrfs_item_size(l, item)); - switch (type) { - case BTRFS_INODE_ITEM_KEY: - ii = btrfs_item_ptr(l, i, struct btrfs_inode_item); - pr_info("\t\tinode generation %llu size %llu mode %o\n", - btrfs_inode_generation(l, ii), - btrfs_inode_size(l, ii), - btrfs_inode_mode(l, ii)); - break; - case BTRFS_DIR_ITEM_KEY: - di = btrfs_item_ptr(l, i, struct btrfs_dir_item); - btrfs_dir_item_key_to_cpu(l, di, &found_key); - pr_info("\t\tdir oid %llu type %u\n", - found_key.objectid, - btrfs_dir_type(l, di)); - break; - case BTRFS_ROOT_ITEM_KEY: - ri = btrfs_item_ptr(l, i, struct btrfs_root_item); - pr_info("\t\troot data bytenr %llu refs %u\n", - btrfs_disk_root_bytenr(l, ri), - btrfs_disk_root_refs(l, ri)); - break; - case BTRFS_EXTENT_ITEM_KEY: - case BTRFS_METADATA_ITEM_KEY: - print_extent_item(l, i, type); - break; - case BTRFS_TREE_BLOCK_REF_KEY: - pr_info("\t\ttree block backref\n"); - break; - case BTRFS_SHARED_BLOCK_REF_KEY: - pr_info("\t\tshared block backref\n"); - break; - case BTRFS_EXTENT_DATA_REF_KEY: - dref = btrfs_item_ptr(l, i, - struct btrfs_extent_data_ref); - print_extent_data_ref(l, dref); - break; - case BTRFS_SHARED_DATA_REF_KEY: - sref = btrfs_item_ptr(l, i, - struct btrfs_shared_data_ref); - pr_info("\t\tshared data backref count %u\n", - btrfs_shared_data_ref_count(l, sref)); - break; - case BTRFS_EXTENT_DATA_KEY: - fi = btrfs_item_ptr(l, i, - struct btrfs_file_extent_item); - if (btrfs_file_extent_type(l, fi) == - BTRFS_FILE_EXTENT_INLINE) { - pr_info("\t\tinline extent data size %u\n", - btrfs_file_extent_inline_len(l, i, fi)); - break; - } - pr_info("\t\textent data disk bytenr %llu nr %llu\n", - btrfs_file_extent_disk_bytenr(l, fi), - btrfs_file_extent_disk_num_bytes(l, fi)); - pr_info("\t\textent data offset %llu nr %llu ram %llu\n", - btrfs_file_extent_offset(l, fi), - btrfs_file_extent_num_bytes(l, fi), - btrfs_file_extent_ram_bytes(l, fi)); - break; - case BTRFS_EXTENT_REF_V0_KEY: -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - print_extent_ref_v0(l, i); -#else - BUG(); -#endif - break; - case BTRFS_BLOCK_GROUP_ITEM_KEY: - bi = btrfs_item_ptr(l, i, - struct btrfs_block_group_item); - pr_info("\t\tblock group used %llu\n", - btrfs_disk_block_group_used(l, bi)); - break; - case BTRFS_CHUNK_ITEM_KEY: - print_chunk(l, btrfs_item_ptr(l, i, - struct btrfs_chunk)); - break; - case BTRFS_DEV_ITEM_KEY: - print_dev_item(l, btrfs_item_ptr(l, i, - struct btrfs_dev_item)); - break; - case BTRFS_DEV_EXTENT_KEY: - dev_extent = btrfs_item_ptr(l, i, - struct btrfs_dev_extent); - pr_info("\t\tdev extent chunk_tree %llu\n\t\tchunk objectid %llu chunk offset %llu length %llu\n", - btrfs_dev_extent_chunk_tree(l, dev_extent), - btrfs_dev_extent_chunk_objectid(l, dev_extent), - btrfs_dev_extent_chunk_offset(l, dev_extent), - btrfs_dev_extent_length(l, dev_extent)); - break; - case BTRFS_PERSISTENT_ITEM_KEY: - pr_info("\t\tpersistent item objectid %llu offset %llu\n", - key.objectid, key.offset); - switch (key.objectid) { - case BTRFS_DEV_STATS_OBJECTID: - pr_info("\t\tdevice stats\n"); - break; - default: - pr_info("\t\tunknown persistent item\n"); - } - break; - case BTRFS_TEMPORARY_ITEM_KEY: - pr_info("\t\ttemporary item objectid %llu offset %llu\n", - key.objectid, key.offset); - switch (key.objectid) { - case BTRFS_BALANCE_OBJECTID: - pr_info("\t\tbalance status\n"); - break; - default: - pr_info("\t\tunknown temporary item\n"); - } - break; - case BTRFS_DEV_REPLACE_KEY: - pr_info("\t\tdev replace\n"); - break; - case BTRFS_UUID_KEY_SUBVOL: - case BTRFS_UUID_KEY_RECEIVED_SUBVOL: - print_uuid_item(l, btrfs_item_ptr_offset(l, i), - btrfs_item_size_nr(l, i)); - break; - }; - } -} - -void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *c) -{ - int i; u32 nr; - struct btrfs_key key; - int level; - - if (!c) - return; - nr = btrfs_header_nritems(c); - level = btrfs_header_level(c); - if (level == 0) { - btrfs_print_leaf(root, c); - return; - } - btrfs_info(root->fs_info, - "node %llu level %d total ptrs %d free spc %u", - btrfs_header_bytenr(c), level, nr, - (u32)BTRFS_NODEPTRS_PER_BLOCK(root) - nr); - for (i = 0; i < nr; i++) { - btrfs_node_key_to_cpu(c, &key, i); - pr_info("\tkey %d (%llu %u %llu) block %llu\n", - i, key.objectid, key.type, key.offset, - btrfs_node_blockptr(c, i)); - } - for (i = 0; i < nr; i++) { - struct extent_buffer *next = read_tree_block(root, - btrfs_node_blockptr(c, i), - btrfs_node_ptr_generation(c, i)); - if (IS_ERR(next)) { - continue; - } else if (!extent_buffer_uptodate(next)) { - free_extent_buffer(next); - continue; - } - - if (btrfs_is_leaf(next) && - level != 1) - BUG(); - if (btrfs_header_level(next) != - level - 1) - BUG(); - btrfs_print_tree(root, next); - free_extent_buffer(next); - } -} diff --git a/src/linux/fs/btrfs/print-tree.h b/src/linux/fs/btrfs/print-tree.h deleted file mode 100644 index 7faddfa..0000000 --- a/src/linux/fs/btrfs/print-tree.h +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __PRINT_TREE_ -#define __PRINT_TREE_ -void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l); -void btrfs_print_tree(struct btrfs_root *root, struct extent_buffer *c); -#endif diff --git a/src/linux/fs/btrfs/props.c b/src/linux/fs/btrfs/props.c deleted file mode 100644 index cf0b444..0000000 --- a/src/linux/fs/btrfs/props.c +++ /dev/null @@ -1,429 +0,0 @@ -/* - * Copyright (C) 2014 Filipe David Borba Manana - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include "props.h" -#include "btrfs_inode.h" -#include "hash.h" -#include "transaction.h" -#include "xattr.h" -#include "compression.h" - -#define BTRFS_PROP_HANDLERS_HT_BITS 8 -static DEFINE_HASHTABLE(prop_handlers_ht, BTRFS_PROP_HANDLERS_HT_BITS); - -struct prop_handler { - struct hlist_node node; - const char *xattr_name; - int (*validate)(const char *value, size_t len); - int (*apply)(struct inode *inode, const char *value, size_t len); - const char *(*extract)(struct inode *inode); - int inheritable; -}; - -static int prop_compression_validate(const char *value, size_t len); -static int prop_compression_apply(struct inode *inode, - const char *value, - size_t len); -static const char *prop_compression_extract(struct inode *inode); - -static struct prop_handler prop_handlers[] = { - { - .xattr_name = XATTR_BTRFS_PREFIX "compression", - .validate = prop_compression_validate, - .apply = prop_compression_apply, - .extract = prop_compression_extract, - .inheritable = 1 - }, -}; - -void __init btrfs_props_init(void) -{ - int i; - - hash_init(prop_handlers_ht); - - for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) { - struct prop_handler *p = &prop_handlers[i]; - u64 h = btrfs_name_hash(p->xattr_name, strlen(p->xattr_name)); - - hash_add(prop_handlers_ht, &p->node, h); - } -} - -static const struct hlist_head *find_prop_handlers_by_hash(const u64 hash) -{ - struct hlist_head *h; - - h = &prop_handlers_ht[hash_min(hash, BTRFS_PROP_HANDLERS_HT_BITS)]; - if (hlist_empty(h)) - return NULL; - - return h; -} - -static const struct prop_handler * -find_prop_handler(const char *name, - const struct hlist_head *handlers) -{ - struct prop_handler *h; - - if (!handlers) { - u64 hash = btrfs_name_hash(name, strlen(name)); - - handlers = find_prop_handlers_by_hash(hash); - if (!handlers) - return NULL; - } - - hlist_for_each_entry(h, handlers, node) - if (!strcmp(h->xattr_name, name)) - return h; - - return NULL; -} - -static int __btrfs_set_prop(struct btrfs_trans_handle *trans, - struct inode *inode, - const char *name, - const char *value, - size_t value_len, - int flags) -{ - const struct prop_handler *handler; - int ret; - - if (strlen(name) <= XATTR_BTRFS_PREFIX_LEN) - return -EINVAL; - - handler = find_prop_handler(name, NULL); - if (!handler) - return -EINVAL; - - if (value_len == 0) { - ret = __btrfs_setxattr(trans, inode, handler->xattr_name, - NULL, 0, flags); - if (ret) - return ret; - - ret = handler->apply(inode, NULL, 0); - ASSERT(ret == 0); - - return ret; - } - - ret = handler->validate(value, value_len); - if (ret) - return ret; - ret = __btrfs_setxattr(trans, inode, handler->xattr_name, - value, value_len, flags); - if (ret) - return ret; - ret = handler->apply(inode, value, value_len); - if (ret) { - __btrfs_setxattr(trans, inode, handler->xattr_name, - NULL, 0, flags); - return ret; - } - - set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags); - - return 0; -} - -int btrfs_set_prop(struct inode *inode, - const char *name, - const char *value, - size_t value_len, - int flags) -{ - return __btrfs_set_prop(NULL, inode, name, value, value_len, flags); -} - -static int iterate_object_props(struct btrfs_root *root, - struct btrfs_path *path, - u64 objectid, - void (*iterator)(void *, - const struct prop_handler *, - const char *, - size_t), - void *ctx) -{ - int ret; - char *name_buf = NULL; - char *value_buf = NULL; - int name_buf_len = 0; - int value_buf_len = 0; - - while (1) { - struct btrfs_key key; - struct btrfs_dir_item *di; - struct extent_buffer *leaf; - u32 total_len, cur, this_len; - int slot; - const struct hlist_head *handlers; - - slot = path->slots[0]; - leaf = path->nodes[0]; - - if (slot >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) - goto out; - else if (ret > 0) - break; - continue; - } - - btrfs_item_key_to_cpu(leaf, &key, slot); - if (key.objectid != objectid) - break; - if (key.type != BTRFS_XATTR_ITEM_KEY) - break; - - handlers = find_prop_handlers_by_hash(key.offset); - if (!handlers) - goto next_slot; - - di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); - cur = 0; - total_len = btrfs_item_size_nr(leaf, slot); - - while (cur < total_len) { - u32 name_len = btrfs_dir_name_len(leaf, di); - u32 data_len = btrfs_dir_data_len(leaf, di); - unsigned long name_ptr, data_ptr; - const struct prop_handler *handler; - - this_len = sizeof(*di) + name_len + data_len; - name_ptr = (unsigned long)(di + 1); - data_ptr = name_ptr + name_len; - - if (name_len <= XATTR_BTRFS_PREFIX_LEN || - memcmp_extent_buffer(leaf, XATTR_BTRFS_PREFIX, - name_ptr, - XATTR_BTRFS_PREFIX_LEN)) - goto next_dir_item; - - if (name_len >= name_buf_len) { - kfree(name_buf); - name_buf_len = name_len + 1; - name_buf = kmalloc(name_buf_len, GFP_NOFS); - if (!name_buf) { - ret = -ENOMEM; - goto out; - } - } - read_extent_buffer(leaf, name_buf, name_ptr, name_len); - name_buf[name_len] = '\0'; - - handler = find_prop_handler(name_buf, handlers); - if (!handler) - goto next_dir_item; - - if (data_len > value_buf_len) { - kfree(value_buf); - value_buf_len = data_len; - value_buf = kmalloc(data_len, GFP_NOFS); - if (!value_buf) { - ret = -ENOMEM; - goto out; - } - } - read_extent_buffer(leaf, value_buf, data_ptr, data_len); - - iterator(ctx, handler, value_buf, data_len); -next_dir_item: - cur += this_len; - di = (struct btrfs_dir_item *)((char *) di + this_len); - } - -next_slot: - path->slots[0]++; - } - - ret = 0; -out: - btrfs_release_path(path); - kfree(name_buf); - kfree(value_buf); - - return ret; -} - -static void inode_prop_iterator(void *ctx, - const struct prop_handler *handler, - const char *value, - size_t len) -{ - struct inode *inode = ctx; - struct btrfs_root *root = BTRFS_I(inode)->root; - int ret; - - ret = handler->apply(inode, value, len); - if (unlikely(ret)) - btrfs_warn(root->fs_info, - "error applying prop %s to ino %llu (root %llu): %d", - handler->xattr_name, btrfs_ino(inode), - root->root_key.objectid, ret); - else - set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags); -} - -int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - u64 ino = btrfs_ino(inode); - int ret; - - ret = iterate_object_props(root, path, ino, inode_prop_iterator, inode); - - return ret; -} - -static int inherit_props(struct btrfs_trans_handle *trans, - struct inode *inode, - struct inode *parent) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - int ret; - int i; - - if (!test_bit(BTRFS_INODE_HAS_PROPS, - &BTRFS_I(parent)->runtime_flags)) - return 0; - - for (i = 0; i < ARRAY_SIZE(prop_handlers); i++) { - const struct prop_handler *h = &prop_handlers[i]; - const char *value; - u64 num_bytes; - - if (!h->inheritable) - continue; - - value = h->extract(parent); - if (!value) - continue; - - num_bytes = btrfs_calc_trans_metadata_size(root, 1); - ret = btrfs_block_rsv_add(root, trans->block_rsv, - num_bytes, BTRFS_RESERVE_NO_FLUSH); - if (ret) - goto out; - ret = __btrfs_set_prop(trans, inode, h->xattr_name, - value, strlen(value), 0); - btrfs_block_rsv_release(root, trans->block_rsv, num_bytes); - if (ret) - goto out; - } - ret = 0; -out: - return ret; -} - -int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans, - struct inode *inode, - struct inode *dir) -{ - if (!dir) - return 0; - - return inherit_props(trans, inode, dir); -} - -int btrfs_subvol_inherit_props(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_root *parent_root) -{ - struct super_block *sb = root->fs_info->sb; - struct btrfs_key key; - struct inode *parent_inode, *child_inode; - int ret; - - key.objectid = BTRFS_FIRST_FREE_OBJECTID; - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - - parent_inode = btrfs_iget(sb, &key, parent_root, NULL); - if (IS_ERR(parent_inode)) - return PTR_ERR(parent_inode); - - child_inode = btrfs_iget(sb, &key, root, NULL); - if (IS_ERR(child_inode)) { - iput(parent_inode); - return PTR_ERR(child_inode); - } - - ret = inherit_props(trans, child_inode, parent_inode); - iput(child_inode); - iput(parent_inode); - - return ret; -} - -static int prop_compression_validate(const char *value, size_t len) -{ - if (!strncmp("lzo", value, len)) - return 0; - else if (!strncmp("zlib", value, len)) - return 0; - - return -EINVAL; -} - -static int prop_compression_apply(struct inode *inode, - const char *value, - size_t len) -{ - int type; - - if (len == 0) { - BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS; - BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS; - BTRFS_I(inode)->force_compress = BTRFS_COMPRESS_NONE; - - return 0; - } - - if (!strncmp("lzo", value, len)) - type = BTRFS_COMPRESS_LZO; - else if (!strncmp("zlib", value, len)) - type = BTRFS_COMPRESS_ZLIB; - else - return -EINVAL; - - BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS; - BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS; - BTRFS_I(inode)->force_compress = type; - - return 0; -} - -static const char *prop_compression_extract(struct inode *inode) -{ - switch (BTRFS_I(inode)->force_compress) { - case BTRFS_COMPRESS_ZLIB: - return "zlib"; - case BTRFS_COMPRESS_LZO: - return "lzo"; - } - - return NULL; -} - - diff --git a/src/linux/fs/btrfs/props.h b/src/linux/fs/btrfs/props.h deleted file mode 100644 index 100f188..0000000 --- a/src/linux/fs/btrfs/props.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (C) 2014 Filipe David Borba Manana - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __BTRFS_PROPS_H -#define __BTRFS_PROPS_H - -#include "ctree.h" - -void __init btrfs_props_init(void); - -int btrfs_set_prop(struct inode *inode, - const char *name, - const char *value, - size_t value_len, - int flags); - -int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path); - -int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans, - struct inode *inode, - struct inode *dir); - -int btrfs_subvol_inherit_props(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_root *parent_root); - -#endif diff --git a/src/linux/fs/btrfs/qgroup.c b/src/linux/fs/btrfs/qgroup.c deleted file mode 100644 index 11f4fff..0000000 --- a/src/linux/fs/btrfs/qgroup.c +++ /dev/null @@ -1,2750 +0,0 @@ -/* - * Copyright (C) 2011 STRATO. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ctree.h" -#include "transaction.h" -#include "disk-io.h" -#include "locking.h" -#include "ulist.h" -#include "backref.h" -#include "extent_io.h" -#include "qgroup.h" - - -/* TODO XXX FIXME - * - subvol delete -> delete when ref goes to 0? delete limits also? - * - reorganize keys - * - compressed - * - sync - * - copy also limits on subvol creation - * - limit - * - caches fuer ulists - * - performance benchmarks - * - check all ioctl parameters - */ - -/* - * one struct for each qgroup, organized in fs_info->qgroup_tree. - */ -struct btrfs_qgroup { - u64 qgroupid; - - /* - * state - */ - u64 rfer; /* referenced */ - u64 rfer_cmpr; /* referenced compressed */ - u64 excl; /* exclusive */ - u64 excl_cmpr; /* exclusive compressed */ - - /* - * limits - */ - u64 lim_flags; /* which limits are set */ - u64 max_rfer; - u64 max_excl; - u64 rsv_rfer; - u64 rsv_excl; - - /* - * reservation tracking - */ - u64 reserved; - - /* - * lists - */ - struct list_head groups; /* groups this group is member of */ - struct list_head members; /* groups that are members of this group */ - struct list_head dirty; /* dirty groups */ - struct rb_node node; /* tree of qgroups */ - - /* - * temp variables for accounting operations - * Refer to qgroup_shared_accounting() for details. - */ - u64 old_refcnt; - u64 new_refcnt; -}; - -static void btrfs_qgroup_update_old_refcnt(struct btrfs_qgroup *qg, u64 seq, - int mod) -{ - if (qg->old_refcnt < seq) - qg->old_refcnt = seq; - qg->old_refcnt += mod; -} - -static void btrfs_qgroup_update_new_refcnt(struct btrfs_qgroup *qg, u64 seq, - int mod) -{ - if (qg->new_refcnt < seq) - qg->new_refcnt = seq; - qg->new_refcnt += mod; -} - -static inline u64 btrfs_qgroup_get_old_refcnt(struct btrfs_qgroup *qg, u64 seq) -{ - if (qg->old_refcnt < seq) - return 0; - return qg->old_refcnt - seq; -} - -static inline u64 btrfs_qgroup_get_new_refcnt(struct btrfs_qgroup *qg, u64 seq) -{ - if (qg->new_refcnt < seq) - return 0; - return qg->new_refcnt - seq; -} - -/* - * glue structure to represent the relations between qgroups. - */ -struct btrfs_qgroup_list { - struct list_head next_group; - struct list_head next_member; - struct btrfs_qgroup *group; - struct btrfs_qgroup *member; -}; - -#define ptr_to_u64(x) ((u64)(uintptr_t)x) -#define u64_to_ptr(x) ((struct btrfs_qgroup *)(uintptr_t)x) - -static int -qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid, - int init_flags); -static void qgroup_rescan_zero_tracking(struct btrfs_fs_info *fs_info); - -/* must be called with qgroup_ioctl_lock held */ -static struct btrfs_qgroup *find_qgroup_rb(struct btrfs_fs_info *fs_info, - u64 qgroupid) -{ - struct rb_node *n = fs_info->qgroup_tree.rb_node; - struct btrfs_qgroup *qgroup; - - while (n) { - qgroup = rb_entry(n, struct btrfs_qgroup, node); - if (qgroup->qgroupid < qgroupid) - n = n->rb_left; - else if (qgroup->qgroupid > qgroupid) - n = n->rb_right; - else - return qgroup; - } - return NULL; -} - -/* must be called with qgroup_lock held */ -static struct btrfs_qgroup *add_qgroup_rb(struct btrfs_fs_info *fs_info, - u64 qgroupid) -{ - struct rb_node **p = &fs_info->qgroup_tree.rb_node; - struct rb_node *parent = NULL; - struct btrfs_qgroup *qgroup; - - while (*p) { - parent = *p; - qgroup = rb_entry(parent, struct btrfs_qgroup, node); - - if (qgroup->qgroupid < qgroupid) - p = &(*p)->rb_left; - else if (qgroup->qgroupid > qgroupid) - p = &(*p)->rb_right; - else - return qgroup; - } - - qgroup = kzalloc(sizeof(*qgroup), GFP_ATOMIC); - if (!qgroup) - return ERR_PTR(-ENOMEM); - - qgroup->qgroupid = qgroupid; - INIT_LIST_HEAD(&qgroup->groups); - INIT_LIST_HEAD(&qgroup->members); - INIT_LIST_HEAD(&qgroup->dirty); - - rb_link_node(&qgroup->node, parent, p); - rb_insert_color(&qgroup->node, &fs_info->qgroup_tree); - - return qgroup; -} - -static void __del_qgroup_rb(struct btrfs_qgroup *qgroup) -{ - struct btrfs_qgroup_list *list; - - list_del(&qgroup->dirty); - while (!list_empty(&qgroup->groups)) { - list = list_first_entry(&qgroup->groups, - struct btrfs_qgroup_list, next_group); - list_del(&list->next_group); - list_del(&list->next_member); - kfree(list); - } - - while (!list_empty(&qgroup->members)) { - list = list_first_entry(&qgroup->members, - struct btrfs_qgroup_list, next_member); - list_del(&list->next_group); - list_del(&list->next_member); - kfree(list); - } - kfree(qgroup); -} - -/* must be called with qgroup_lock held */ -static int del_qgroup_rb(struct btrfs_fs_info *fs_info, u64 qgroupid) -{ - struct btrfs_qgroup *qgroup = find_qgroup_rb(fs_info, qgroupid); - - if (!qgroup) - return -ENOENT; - - rb_erase(&qgroup->node, &fs_info->qgroup_tree); - __del_qgroup_rb(qgroup); - return 0; -} - -/* must be called with qgroup_lock held */ -static int add_relation_rb(struct btrfs_fs_info *fs_info, - u64 memberid, u64 parentid) -{ - struct btrfs_qgroup *member; - struct btrfs_qgroup *parent; - struct btrfs_qgroup_list *list; - - member = find_qgroup_rb(fs_info, memberid); - parent = find_qgroup_rb(fs_info, parentid); - if (!member || !parent) - return -ENOENT; - - list = kzalloc(sizeof(*list), GFP_ATOMIC); - if (!list) - return -ENOMEM; - - list->group = parent; - list->member = member; - list_add_tail(&list->next_group, &member->groups); - list_add_tail(&list->next_member, &parent->members); - - return 0; -} - -/* must be called with qgroup_lock held */ -static int del_relation_rb(struct btrfs_fs_info *fs_info, - u64 memberid, u64 parentid) -{ - struct btrfs_qgroup *member; - struct btrfs_qgroup *parent; - struct btrfs_qgroup_list *list; - - member = find_qgroup_rb(fs_info, memberid); - parent = find_qgroup_rb(fs_info, parentid); - if (!member || !parent) - return -ENOENT; - - list_for_each_entry(list, &member->groups, next_group) { - if (list->group == parent) { - list_del(&list->next_group); - list_del(&list->next_member); - kfree(list); - return 0; - } - } - return -ENOENT; -} - -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS -int btrfs_verify_qgroup_counts(struct btrfs_fs_info *fs_info, u64 qgroupid, - u64 rfer, u64 excl) -{ - struct btrfs_qgroup *qgroup; - - qgroup = find_qgroup_rb(fs_info, qgroupid); - if (!qgroup) - return -EINVAL; - if (qgroup->rfer != rfer || qgroup->excl != excl) - return -EINVAL; - return 0; -} -#endif - -/* - * The full config is read in one go, only called from open_ctree() - * It doesn't use any locking, as at this point we're still single-threaded - */ -int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info) -{ - struct btrfs_key key; - struct btrfs_key found_key; - struct btrfs_root *quota_root = fs_info->quota_root; - struct btrfs_path *path = NULL; - struct extent_buffer *l; - int slot; - int ret = 0; - u64 flags = 0; - u64 rescan_progress = 0; - - if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) - return 0; - - fs_info->qgroup_ulist = ulist_alloc(GFP_NOFS); - if (!fs_info->qgroup_ulist) { - ret = -ENOMEM; - goto out; - } - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - /* default this to quota off, in case no status key is found */ - fs_info->qgroup_flags = 0; - - /* - * pass 1: read status, all qgroup infos and limits - */ - key.objectid = 0; - key.type = 0; - key.offset = 0; - ret = btrfs_search_slot_for_read(quota_root, &key, path, 1, 1); - if (ret) - goto out; - - while (1) { - struct btrfs_qgroup *qgroup; - - slot = path->slots[0]; - l = path->nodes[0]; - btrfs_item_key_to_cpu(l, &found_key, slot); - - if (found_key.type == BTRFS_QGROUP_STATUS_KEY) { - struct btrfs_qgroup_status_item *ptr; - - ptr = btrfs_item_ptr(l, slot, - struct btrfs_qgroup_status_item); - - if (btrfs_qgroup_status_version(l, ptr) != - BTRFS_QGROUP_STATUS_VERSION) { - btrfs_err(fs_info, - "old qgroup version, quota disabled"); - goto out; - } - if (btrfs_qgroup_status_generation(l, ptr) != - fs_info->generation) { - flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; - btrfs_err(fs_info, - "qgroup generation mismatch, marked as inconsistent"); - } - fs_info->qgroup_flags = btrfs_qgroup_status_flags(l, - ptr); - rescan_progress = btrfs_qgroup_status_rescan(l, ptr); - goto next1; - } - - if (found_key.type != BTRFS_QGROUP_INFO_KEY && - found_key.type != BTRFS_QGROUP_LIMIT_KEY) - goto next1; - - qgroup = find_qgroup_rb(fs_info, found_key.offset); - if ((qgroup && found_key.type == BTRFS_QGROUP_INFO_KEY) || - (!qgroup && found_key.type == BTRFS_QGROUP_LIMIT_KEY)) { - btrfs_err(fs_info, "inconsistent qgroup config"); - flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; - } - if (!qgroup) { - qgroup = add_qgroup_rb(fs_info, found_key.offset); - if (IS_ERR(qgroup)) { - ret = PTR_ERR(qgroup); - goto out; - } - } - switch (found_key.type) { - case BTRFS_QGROUP_INFO_KEY: { - struct btrfs_qgroup_info_item *ptr; - - ptr = btrfs_item_ptr(l, slot, - struct btrfs_qgroup_info_item); - qgroup->rfer = btrfs_qgroup_info_rfer(l, ptr); - qgroup->rfer_cmpr = btrfs_qgroup_info_rfer_cmpr(l, ptr); - qgroup->excl = btrfs_qgroup_info_excl(l, ptr); - qgroup->excl_cmpr = btrfs_qgroup_info_excl_cmpr(l, ptr); - /* generation currently unused */ - break; - } - case BTRFS_QGROUP_LIMIT_KEY: { - struct btrfs_qgroup_limit_item *ptr; - - ptr = btrfs_item_ptr(l, slot, - struct btrfs_qgroup_limit_item); - qgroup->lim_flags = btrfs_qgroup_limit_flags(l, ptr); - qgroup->max_rfer = btrfs_qgroup_limit_max_rfer(l, ptr); - qgroup->max_excl = btrfs_qgroup_limit_max_excl(l, ptr); - qgroup->rsv_rfer = btrfs_qgroup_limit_rsv_rfer(l, ptr); - qgroup->rsv_excl = btrfs_qgroup_limit_rsv_excl(l, ptr); - break; - } - } -next1: - ret = btrfs_next_item(quota_root, path); - if (ret < 0) - goto out; - if (ret) - break; - } - btrfs_release_path(path); - - /* - * pass 2: read all qgroup relations - */ - key.objectid = 0; - key.type = BTRFS_QGROUP_RELATION_KEY; - key.offset = 0; - ret = btrfs_search_slot_for_read(quota_root, &key, path, 1, 0); - if (ret) - goto out; - while (1) { - slot = path->slots[0]; - l = path->nodes[0]; - btrfs_item_key_to_cpu(l, &found_key, slot); - - if (found_key.type != BTRFS_QGROUP_RELATION_KEY) - goto next2; - - if (found_key.objectid > found_key.offset) { - /* parent <- member, not needed to build config */ - /* FIXME should we omit the key completely? */ - goto next2; - } - - ret = add_relation_rb(fs_info, found_key.objectid, - found_key.offset); - if (ret == -ENOENT) { - btrfs_warn(fs_info, - "orphan qgroup relation 0x%llx->0x%llx", - found_key.objectid, found_key.offset); - ret = 0; /* ignore the error */ - } - if (ret) - goto out; -next2: - ret = btrfs_next_item(quota_root, path); - if (ret < 0) - goto out; - if (ret) - break; - } -out: - fs_info->qgroup_flags |= flags; - if (!(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_ON)) - clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); - else if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN && - ret >= 0) - ret = qgroup_rescan_init(fs_info, rescan_progress, 0); - btrfs_free_path(path); - - if (ret < 0) { - ulist_free(fs_info->qgroup_ulist); - fs_info->qgroup_ulist = NULL; - fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; - } - - return ret < 0 ? ret : 0; -} - -/* - * This is called from close_ctree() or open_ctree() or btrfs_quota_disable(), - * first two are in single-threaded paths.And for the third one, we have set - * quota_root to be null with qgroup_lock held before, so it is safe to clean - * up the in-memory structures without qgroup_lock held. - */ -void btrfs_free_qgroup_config(struct btrfs_fs_info *fs_info) -{ - struct rb_node *n; - struct btrfs_qgroup *qgroup; - - while ((n = rb_first(&fs_info->qgroup_tree))) { - qgroup = rb_entry(n, struct btrfs_qgroup, node); - rb_erase(n, &fs_info->qgroup_tree); - __del_qgroup_rb(qgroup); - } - /* - * we call btrfs_free_qgroup_config() when umounting - * filesystem and disabling quota, so we set qgroup_ulist - * to be null here to avoid double free. - */ - ulist_free(fs_info->qgroup_ulist); - fs_info->qgroup_ulist = NULL; -} - -static int add_qgroup_relation_item(struct btrfs_trans_handle *trans, - struct btrfs_root *quota_root, - u64 src, u64 dst) -{ - int ret; - struct btrfs_path *path; - struct btrfs_key key; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - key.objectid = src; - key.type = BTRFS_QGROUP_RELATION_KEY; - key.offset = dst; - - ret = btrfs_insert_empty_item(trans, quota_root, path, &key, 0); - - btrfs_mark_buffer_dirty(path->nodes[0]); - - btrfs_free_path(path); - return ret; -} - -static int del_qgroup_relation_item(struct btrfs_trans_handle *trans, - struct btrfs_root *quota_root, - u64 src, u64 dst) -{ - int ret; - struct btrfs_path *path; - struct btrfs_key key; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - key.objectid = src; - key.type = BTRFS_QGROUP_RELATION_KEY; - key.offset = dst; - - ret = btrfs_search_slot(trans, quota_root, &key, path, -1, 1); - if (ret < 0) - goto out; - - if (ret > 0) { - ret = -ENOENT; - goto out; - } - - ret = btrfs_del_item(trans, quota_root, path); -out: - btrfs_free_path(path); - return ret; -} - -static int add_qgroup_item(struct btrfs_trans_handle *trans, - struct btrfs_root *quota_root, u64 qgroupid) -{ - int ret; - struct btrfs_path *path; - struct btrfs_qgroup_info_item *qgroup_info; - struct btrfs_qgroup_limit_item *qgroup_limit; - struct extent_buffer *leaf; - struct btrfs_key key; - - if (btrfs_is_testing(quota_root->fs_info)) - return 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - key.objectid = 0; - key.type = BTRFS_QGROUP_INFO_KEY; - key.offset = qgroupid; - - /* - * Avoid a transaction abort by catching -EEXIST here. In that - * case, we proceed by re-initializing the existing structure - * on disk. - */ - - ret = btrfs_insert_empty_item(trans, quota_root, path, &key, - sizeof(*qgroup_info)); - if (ret && ret != -EEXIST) - goto out; - - leaf = path->nodes[0]; - qgroup_info = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_qgroup_info_item); - btrfs_set_qgroup_info_generation(leaf, qgroup_info, trans->transid); - btrfs_set_qgroup_info_rfer(leaf, qgroup_info, 0); - btrfs_set_qgroup_info_rfer_cmpr(leaf, qgroup_info, 0); - btrfs_set_qgroup_info_excl(leaf, qgroup_info, 0); - btrfs_set_qgroup_info_excl_cmpr(leaf, qgroup_info, 0); - - btrfs_mark_buffer_dirty(leaf); - - btrfs_release_path(path); - - key.type = BTRFS_QGROUP_LIMIT_KEY; - ret = btrfs_insert_empty_item(trans, quota_root, path, &key, - sizeof(*qgroup_limit)); - if (ret && ret != -EEXIST) - goto out; - - leaf = path->nodes[0]; - qgroup_limit = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_qgroup_limit_item); - btrfs_set_qgroup_limit_flags(leaf, qgroup_limit, 0); - btrfs_set_qgroup_limit_max_rfer(leaf, qgroup_limit, 0); - btrfs_set_qgroup_limit_max_excl(leaf, qgroup_limit, 0); - btrfs_set_qgroup_limit_rsv_rfer(leaf, qgroup_limit, 0); - btrfs_set_qgroup_limit_rsv_excl(leaf, qgroup_limit, 0); - - btrfs_mark_buffer_dirty(leaf); - - ret = 0; -out: - btrfs_free_path(path); - return ret; -} - -static int del_qgroup_item(struct btrfs_trans_handle *trans, - struct btrfs_root *quota_root, u64 qgroupid) -{ - int ret; - struct btrfs_path *path; - struct btrfs_key key; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - key.objectid = 0; - key.type = BTRFS_QGROUP_INFO_KEY; - key.offset = qgroupid; - ret = btrfs_search_slot(trans, quota_root, &key, path, -1, 1); - if (ret < 0) - goto out; - - if (ret > 0) { - ret = -ENOENT; - goto out; - } - - ret = btrfs_del_item(trans, quota_root, path); - if (ret) - goto out; - - btrfs_release_path(path); - - key.type = BTRFS_QGROUP_LIMIT_KEY; - ret = btrfs_search_slot(trans, quota_root, &key, path, -1, 1); - if (ret < 0) - goto out; - - if (ret > 0) { - ret = -ENOENT; - goto out; - } - - ret = btrfs_del_item(trans, quota_root, path); - -out: - btrfs_free_path(path); - return ret; -} - -static int update_qgroup_limit_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_qgroup *qgroup) -{ - struct btrfs_path *path; - struct btrfs_key key; - struct extent_buffer *l; - struct btrfs_qgroup_limit_item *qgroup_limit; - int ret; - int slot; - - key.objectid = 0; - key.type = BTRFS_QGROUP_LIMIT_KEY; - key.offset = qgroup->qgroupid; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - ret = btrfs_search_slot(trans, root, &key, path, 0, 1); - if (ret > 0) - ret = -ENOENT; - - if (ret) - goto out; - - l = path->nodes[0]; - slot = path->slots[0]; - qgroup_limit = btrfs_item_ptr(l, slot, struct btrfs_qgroup_limit_item); - btrfs_set_qgroup_limit_flags(l, qgroup_limit, qgroup->lim_flags); - btrfs_set_qgroup_limit_max_rfer(l, qgroup_limit, qgroup->max_rfer); - btrfs_set_qgroup_limit_max_excl(l, qgroup_limit, qgroup->max_excl); - btrfs_set_qgroup_limit_rsv_rfer(l, qgroup_limit, qgroup->rsv_rfer); - btrfs_set_qgroup_limit_rsv_excl(l, qgroup_limit, qgroup->rsv_excl); - - btrfs_mark_buffer_dirty(l); - -out: - btrfs_free_path(path); - return ret; -} - -static int update_qgroup_info_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_qgroup *qgroup) -{ - struct btrfs_path *path; - struct btrfs_key key; - struct extent_buffer *l; - struct btrfs_qgroup_info_item *qgroup_info; - int ret; - int slot; - - if (btrfs_is_testing(root->fs_info)) - return 0; - - key.objectid = 0; - key.type = BTRFS_QGROUP_INFO_KEY; - key.offset = qgroup->qgroupid; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - ret = btrfs_search_slot(trans, root, &key, path, 0, 1); - if (ret > 0) - ret = -ENOENT; - - if (ret) - goto out; - - l = path->nodes[0]; - slot = path->slots[0]; - qgroup_info = btrfs_item_ptr(l, slot, struct btrfs_qgroup_info_item); - btrfs_set_qgroup_info_generation(l, qgroup_info, trans->transid); - btrfs_set_qgroup_info_rfer(l, qgroup_info, qgroup->rfer); - btrfs_set_qgroup_info_rfer_cmpr(l, qgroup_info, qgroup->rfer_cmpr); - btrfs_set_qgroup_info_excl(l, qgroup_info, qgroup->excl); - btrfs_set_qgroup_info_excl_cmpr(l, qgroup_info, qgroup->excl_cmpr); - - btrfs_mark_buffer_dirty(l); - -out: - btrfs_free_path(path); - return ret; -} - -static int update_qgroup_status_item(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_root *root) -{ - struct btrfs_path *path; - struct btrfs_key key; - struct extent_buffer *l; - struct btrfs_qgroup_status_item *ptr; - int ret; - int slot; - - key.objectid = 0; - key.type = BTRFS_QGROUP_STATUS_KEY; - key.offset = 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - ret = btrfs_search_slot(trans, root, &key, path, 0, 1); - if (ret > 0) - ret = -ENOENT; - - if (ret) - goto out; - - l = path->nodes[0]; - slot = path->slots[0]; - ptr = btrfs_item_ptr(l, slot, struct btrfs_qgroup_status_item); - btrfs_set_qgroup_status_flags(l, ptr, fs_info->qgroup_flags); - btrfs_set_qgroup_status_generation(l, ptr, trans->transid); - btrfs_set_qgroup_status_rescan(l, ptr, - fs_info->qgroup_rescan_progress.objectid); - - btrfs_mark_buffer_dirty(l); - -out: - btrfs_free_path(path); - return ret; -} - -/* - * called with qgroup_lock held - */ -static int btrfs_clean_quota_tree(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_path *path; - struct btrfs_key key; - struct extent_buffer *leaf = NULL; - int ret; - int nr = 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - path->leave_spinning = 1; - - key.objectid = 0; - key.offset = 0; - key.type = 0; - - while (1) { - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret < 0) - goto out; - leaf = path->nodes[0]; - nr = btrfs_header_nritems(leaf); - if (!nr) - break; - /* - * delete the leaf one by one - * since the whole tree is going - * to be deleted. - */ - path->slots[0] = 0; - ret = btrfs_del_items(trans, root, path, 0, nr); - if (ret) - goto out; - - btrfs_release_path(path); - } - ret = 0; -out: - set_bit(BTRFS_FS_QUOTA_DISABLING, &root->fs_info->flags); - btrfs_free_path(path); - return ret; -} - -int btrfs_quota_enable(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info) -{ - struct btrfs_root *quota_root; - struct btrfs_root *tree_root = fs_info->tree_root; - struct btrfs_path *path = NULL; - struct btrfs_qgroup_status_item *ptr; - struct extent_buffer *leaf; - struct btrfs_key key; - struct btrfs_key found_key; - struct btrfs_qgroup *qgroup = NULL; - int ret = 0; - int slot; - - mutex_lock(&fs_info->qgroup_ioctl_lock); - if (fs_info->quota_root) { - set_bit(BTRFS_FS_QUOTA_ENABLING, &fs_info->flags); - goto out; - } - - fs_info->qgroup_ulist = ulist_alloc(GFP_NOFS); - if (!fs_info->qgroup_ulist) { - ret = -ENOMEM; - goto out; - } - - /* - * initially create the quota tree - */ - quota_root = btrfs_create_tree(trans, fs_info, - BTRFS_QUOTA_TREE_OBJECTID); - if (IS_ERR(quota_root)) { - ret = PTR_ERR(quota_root); - goto out; - } - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out_free_root; - } - - key.objectid = 0; - key.type = BTRFS_QGROUP_STATUS_KEY; - key.offset = 0; - - ret = btrfs_insert_empty_item(trans, quota_root, path, &key, - sizeof(*ptr)); - if (ret) - goto out_free_path; - - leaf = path->nodes[0]; - ptr = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_qgroup_status_item); - btrfs_set_qgroup_status_generation(leaf, ptr, trans->transid); - btrfs_set_qgroup_status_version(leaf, ptr, BTRFS_QGROUP_STATUS_VERSION); - fs_info->qgroup_flags = BTRFS_QGROUP_STATUS_FLAG_ON | - BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; - btrfs_set_qgroup_status_flags(leaf, ptr, fs_info->qgroup_flags); - btrfs_set_qgroup_status_rescan(leaf, ptr, 0); - - btrfs_mark_buffer_dirty(leaf); - - key.objectid = 0; - key.type = BTRFS_ROOT_REF_KEY; - key.offset = 0; - - btrfs_release_path(path); - ret = btrfs_search_slot_for_read(tree_root, &key, path, 1, 0); - if (ret > 0) - goto out_add_root; - if (ret < 0) - goto out_free_path; - - - while (1) { - slot = path->slots[0]; - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &found_key, slot); - - if (found_key.type == BTRFS_ROOT_REF_KEY) { - ret = add_qgroup_item(trans, quota_root, - found_key.offset); - if (ret) - goto out_free_path; - - qgroup = add_qgroup_rb(fs_info, found_key.offset); - if (IS_ERR(qgroup)) { - ret = PTR_ERR(qgroup); - goto out_free_path; - } - } - ret = btrfs_next_item(tree_root, path); - if (ret < 0) - goto out_free_path; - if (ret) - break; - } - -out_add_root: - btrfs_release_path(path); - ret = add_qgroup_item(trans, quota_root, BTRFS_FS_TREE_OBJECTID); - if (ret) - goto out_free_path; - - qgroup = add_qgroup_rb(fs_info, BTRFS_FS_TREE_OBJECTID); - if (IS_ERR(qgroup)) { - ret = PTR_ERR(qgroup); - goto out_free_path; - } - spin_lock(&fs_info->qgroup_lock); - fs_info->quota_root = quota_root; - set_bit(BTRFS_FS_QUOTA_ENABLING, &fs_info->flags); - spin_unlock(&fs_info->qgroup_lock); -out_free_path: - btrfs_free_path(path); -out_free_root: - if (ret) { - free_extent_buffer(quota_root->node); - free_extent_buffer(quota_root->commit_root); - kfree(quota_root); - } -out: - if (ret) { - ulist_free(fs_info->qgroup_ulist); - fs_info->qgroup_ulist = NULL; - } - mutex_unlock(&fs_info->qgroup_ioctl_lock); - return ret; -} - -int btrfs_quota_disable(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info) -{ - struct btrfs_root *tree_root = fs_info->tree_root; - struct btrfs_root *quota_root; - int ret = 0; - - mutex_lock(&fs_info->qgroup_ioctl_lock); - if (!fs_info->quota_root) - goto out; - clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); - set_bit(BTRFS_FS_QUOTA_DISABLING, &fs_info->flags); - btrfs_qgroup_wait_for_completion(fs_info, false); - spin_lock(&fs_info->qgroup_lock); - quota_root = fs_info->quota_root; - fs_info->quota_root = NULL; - fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_ON; - spin_unlock(&fs_info->qgroup_lock); - - btrfs_free_qgroup_config(fs_info); - - ret = btrfs_clean_quota_tree(trans, quota_root); - if (ret) - goto out; - - ret = btrfs_del_root(trans, tree_root, "a_root->root_key); - if (ret) - goto out; - - list_del("a_root->dirty_list); - - btrfs_tree_lock(quota_root->node); - clean_tree_block(trans, tree_root->fs_info, quota_root->node); - btrfs_tree_unlock(quota_root->node); - btrfs_free_tree_block(trans, quota_root, quota_root->node, 0, 1); - - free_extent_buffer(quota_root->node); - free_extent_buffer(quota_root->commit_root); - kfree(quota_root); -out: - mutex_unlock(&fs_info->qgroup_ioctl_lock); - return ret; -} - -static void qgroup_dirty(struct btrfs_fs_info *fs_info, - struct btrfs_qgroup *qgroup) -{ - if (list_empty(&qgroup->dirty)) - list_add(&qgroup->dirty, &fs_info->dirty_qgroups); -} - -/* - * The easy accounting, if we are adding/removing the only ref for an extent - * then this qgroup and all of the parent qgroups get their reference and - * exclusive counts adjusted. - * - * Caller should hold fs_info->qgroup_lock. - */ -static int __qgroup_excl_accounting(struct btrfs_fs_info *fs_info, - struct ulist *tmp, u64 ref_root, - u64 num_bytes, int sign) -{ - struct btrfs_qgroup *qgroup; - struct btrfs_qgroup_list *glist; - struct ulist_node *unode; - struct ulist_iterator uiter; - int ret = 0; - - qgroup = find_qgroup_rb(fs_info, ref_root); - if (!qgroup) - goto out; - - qgroup->rfer += sign * num_bytes; - qgroup->rfer_cmpr += sign * num_bytes; - - WARN_ON(sign < 0 && qgroup->excl < num_bytes); - qgroup->excl += sign * num_bytes; - qgroup->excl_cmpr += sign * num_bytes; - if (sign > 0) - qgroup->reserved -= num_bytes; - - qgroup_dirty(fs_info, qgroup); - - /* Get all of the parent groups that contain this qgroup */ - list_for_each_entry(glist, &qgroup->groups, next_group) { - ret = ulist_add(tmp, glist->group->qgroupid, - ptr_to_u64(glist->group), GFP_ATOMIC); - if (ret < 0) - goto out; - } - - /* Iterate all of the parents and adjust their reference counts */ - ULIST_ITER_INIT(&uiter); - while ((unode = ulist_next(tmp, &uiter))) { - qgroup = u64_to_ptr(unode->aux); - qgroup->rfer += sign * num_bytes; - qgroup->rfer_cmpr += sign * num_bytes; - WARN_ON(sign < 0 && qgroup->excl < num_bytes); - qgroup->excl += sign * num_bytes; - if (sign > 0) - qgroup->reserved -= num_bytes; - qgroup->excl_cmpr += sign * num_bytes; - qgroup_dirty(fs_info, qgroup); - - /* Add any parents of the parents */ - list_for_each_entry(glist, &qgroup->groups, next_group) { - ret = ulist_add(tmp, glist->group->qgroupid, - ptr_to_u64(glist->group), GFP_ATOMIC); - if (ret < 0) - goto out; - } - } - ret = 0; -out: - return ret; -} - - -/* - * Quick path for updating qgroup with only excl refs. - * - * In that case, just update all parent will be enough. - * Or we needs to do a full rescan. - * Caller should also hold fs_info->qgroup_lock. - * - * Return 0 for quick update, return >0 for need to full rescan - * and mark INCONSISTENT flag. - * Return < 0 for other error. - */ -static int quick_update_accounting(struct btrfs_fs_info *fs_info, - struct ulist *tmp, u64 src, u64 dst, - int sign) -{ - struct btrfs_qgroup *qgroup; - int ret = 1; - int err = 0; - - qgroup = find_qgroup_rb(fs_info, src); - if (!qgroup) - goto out; - if (qgroup->excl == qgroup->rfer) { - ret = 0; - err = __qgroup_excl_accounting(fs_info, tmp, dst, - qgroup->excl, sign); - if (err < 0) { - ret = err; - goto out; - } - } -out: - if (ret) - fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; - return ret; -} - -int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 src, u64 dst) -{ - struct btrfs_root *quota_root; - struct btrfs_qgroup *parent; - struct btrfs_qgroup *member; - struct btrfs_qgroup_list *list; - struct ulist *tmp; - int ret = 0; - - /* Check the level of src and dst first */ - if (btrfs_qgroup_level(src) >= btrfs_qgroup_level(dst)) - return -EINVAL; - - tmp = ulist_alloc(GFP_NOFS); - if (!tmp) - return -ENOMEM; - - mutex_lock(&fs_info->qgroup_ioctl_lock); - quota_root = fs_info->quota_root; - if (!quota_root) { - ret = -EINVAL; - goto out; - } - member = find_qgroup_rb(fs_info, src); - parent = find_qgroup_rb(fs_info, dst); - if (!member || !parent) { - ret = -EINVAL; - goto out; - } - - /* check if such qgroup relation exist firstly */ - list_for_each_entry(list, &member->groups, next_group) { - if (list->group == parent) { - ret = -EEXIST; - goto out; - } - } - - ret = add_qgroup_relation_item(trans, quota_root, src, dst); - if (ret) - goto out; - - ret = add_qgroup_relation_item(trans, quota_root, dst, src); - if (ret) { - del_qgroup_relation_item(trans, quota_root, src, dst); - goto out; - } - - spin_lock(&fs_info->qgroup_lock); - ret = add_relation_rb(quota_root->fs_info, src, dst); - if (ret < 0) { - spin_unlock(&fs_info->qgroup_lock); - goto out; - } - ret = quick_update_accounting(fs_info, tmp, src, dst, 1); - spin_unlock(&fs_info->qgroup_lock); -out: - mutex_unlock(&fs_info->qgroup_ioctl_lock); - ulist_free(tmp); - return ret; -} - -int __del_qgroup_relation(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 src, u64 dst) -{ - struct btrfs_root *quota_root; - struct btrfs_qgroup *parent; - struct btrfs_qgroup *member; - struct btrfs_qgroup_list *list; - struct ulist *tmp; - int ret = 0; - int err; - - tmp = ulist_alloc(GFP_NOFS); - if (!tmp) - return -ENOMEM; - - quota_root = fs_info->quota_root; - if (!quota_root) { - ret = -EINVAL; - goto out; - } - - member = find_qgroup_rb(fs_info, src); - parent = find_qgroup_rb(fs_info, dst); - if (!member || !parent) { - ret = -EINVAL; - goto out; - } - - /* check if such qgroup relation exist firstly */ - list_for_each_entry(list, &member->groups, next_group) { - if (list->group == parent) - goto exist; - } - ret = -ENOENT; - goto out; -exist: - ret = del_qgroup_relation_item(trans, quota_root, src, dst); - err = del_qgroup_relation_item(trans, quota_root, dst, src); - if (err && !ret) - ret = err; - - spin_lock(&fs_info->qgroup_lock); - del_relation_rb(fs_info, src, dst); - ret = quick_update_accounting(fs_info, tmp, src, dst, -1); - spin_unlock(&fs_info->qgroup_lock); -out: - ulist_free(tmp); - return ret; -} - -int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 src, u64 dst) -{ - int ret = 0; - - mutex_lock(&fs_info->qgroup_ioctl_lock); - ret = __del_qgroup_relation(trans, fs_info, src, dst); - mutex_unlock(&fs_info->qgroup_ioctl_lock); - - return ret; -} - -int btrfs_create_qgroup(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 qgroupid) -{ - struct btrfs_root *quota_root; - struct btrfs_qgroup *qgroup; - int ret = 0; - - mutex_lock(&fs_info->qgroup_ioctl_lock); - quota_root = fs_info->quota_root; - if (!quota_root) { - ret = -EINVAL; - goto out; - } - qgroup = find_qgroup_rb(fs_info, qgroupid); - if (qgroup) { - ret = -EEXIST; - goto out; - } - - ret = add_qgroup_item(trans, quota_root, qgroupid); - if (ret) - goto out; - - spin_lock(&fs_info->qgroup_lock); - qgroup = add_qgroup_rb(fs_info, qgroupid); - spin_unlock(&fs_info->qgroup_lock); - - if (IS_ERR(qgroup)) - ret = PTR_ERR(qgroup); -out: - mutex_unlock(&fs_info->qgroup_ioctl_lock); - return ret; -} - -int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 qgroupid) -{ - struct btrfs_root *quota_root; - struct btrfs_qgroup *qgroup; - struct btrfs_qgroup_list *list; - int ret = 0; - - mutex_lock(&fs_info->qgroup_ioctl_lock); - quota_root = fs_info->quota_root; - if (!quota_root) { - ret = -EINVAL; - goto out; - } - - qgroup = find_qgroup_rb(fs_info, qgroupid); - if (!qgroup) { - ret = -ENOENT; - goto out; - } else { - /* check if there are no children of this qgroup */ - if (!list_empty(&qgroup->members)) { - ret = -EBUSY; - goto out; - } - } - ret = del_qgroup_item(trans, quota_root, qgroupid); - - while (!list_empty(&qgroup->groups)) { - list = list_first_entry(&qgroup->groups, - struct btrfs_qgroup_list, next_group); - ret = __del_qgroup_relation(trans, fs_info, - qgroupid, - list->group->qgroupid); - if (ret) - goto out; - } - - spin_lock(&fs_info->qgroup_lock); - del_qgroup_rb(quota_root->fs_info, qgroupid); - spin_unlock(&fs_info->qgroup_lock); -out: - mutex_unlock(&fs_info->qgroup_ioctl_lock); - return ret; -} - -int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 qgroupid, - struct btrfs_qgroup_limit *limit) -{ - struct btrfs_root *quota_root; - struct btrfs_qgroup *qgroup; - int ret = 0; - /* Sometimes we would want to clear the limit on this qgroup. - * To meet this requirement, we treat the -1 as a special value - * which tell kernel to clear the limit on this qgroup. - */ - const u64 CLEAR_VALUE = -1; - - mutex_lock(&fs_info->qgroup_ioctl_lock); - quota_root = fs_info->quota_root; - if (!quota_root) { - ret = -EINVAL; - goto out; - } - - qgroup = find_qgroup_rb(fs_info, qgroupid); - if (!qgroup) { - ret = -ENOENT; - goto out; - } - - spin_lock(&fs_info->qgroup_lock); - if (limit->flags & BTRFS_QGROUP_LIMIT_MAX_RFER) { - if (limit->max_rfer == CLEAR_VALUE) { - qgroup->lim_flags &= ~BTRFS_QGROUP_LIMIT_MAX_RFER; - limit->flags &= ~BTRFS_QGROUP_LIMIT_MAX_RFER; - qgroup->max_rfer = 0; - } else { - qgroup->max_rfer = limit->max_rfer; - } - } - if (limit->flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) { - if (limit->max_excl == CLEAR_VALUE) { - qgroup->lim_flags &= ~BTRFS_QGROUP_LIMIT_MAX_EXCL; - limit->flags &= ~BTRFS_QGROUP_LIMIT_MAX_EXCL; - qgroup->max_excl = 0; - } else { - qgroup->max_excl = limit->max_excl; - } - } - if (limit->flags & BTRFS_QGROUP_LIMIT_RSV_RFER) { - if (limit->rsv_rfer == CLEAR_VALUE) { - qgroup->lim_flags &= ~BTRFS_QGROUP_LIMIT_RSV_RFER; - limit->flags &= ~BTRFS_QGROUP_LIMIT_RSV_RFER; - qgroup->rsv_rfer = 0; - } else { - qgroup->rsv_rfer = limit->rsv_rfer; - } - } - if (limit->flags & BTRFS_QGROUP_LIMIT_RSV_EXCL) { - if (limit->rsv_excl == CLEAR_VALUE) { - qgroup->lim_flags &= ~BTRFS_QGROUP_LIMIT_RSV_EXCL; - limit->flags &= ~BTRFS_QGROUP_LIMIT_RSV_EXCL; - qgroup->rsv_excl = 0; - } else { - qgroup->rsv_excl = limit->rsv_excl; - } - } - qgroup->lim_flags |= limit->flags; - - spin_unlock(&fs_info->qgroup_lock); - - ret = update_qgroup_limit_item(trans, quota_root, qgroup); - if (ret) { - fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; - btrfs_info(fs_info, "unable to update quota limit for %llu", - qgroupid); - } - -out: - mutex_unlock(&fs_info->qgroup_ioctl_lock); - return ret; -} - -int btrfs_qgroup_prepare_account_extents(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info) -{ - struct btrfs_qgroup_extent_record *record; - struct btrfs_delayed_ref_root *delayed_refs; - struct rb_node *node; - u64 qgroup_to_skip; - int ret = 0; - - delayed_refs = &trans->transaction->delayed_refs; - qgroup_to_skip = delayed_refs->qgroup_to_skip; - - /* - * No need to do lock, since this function will only be called in - * btrfs_commit_transaction(). - */ - node = rb_first(&delayed_refs->dirty_extent_root); - while (node) { - record = rb_entry(node, struct btrfs_qgroup_extent_record, - node); - ret = btrfs_find_all_roots(NULL, fs_info, record->bytenr, 0, - &record->old_roots); - if (ret < 0) - break; - if (qgroup_to_skip) - ulist_del(record->old_roots, qgroup_to_skip, 0); - node = rb_next(node); - } - return ret; -} - -int btrfs_qgroup_insert_dirty_extent_nolock(struct btrfs_fs_info *fs_info, - struct btrfs_delayed_ref_root *delayed_refs, - struct btrfs_qgroup_extent_record *record) -{ - struct rb_node **p = &delayed_refs->dirty_extent_root.rb_node; - struct rb_node *parent_node = NULL; - struct btrfs_qgroup_extent_record *entry; - u64 bytenr = record->bytenr; - - assert_spin_locked(&delayed_refs->lock); - trace_btrfs_qgroup_insert_dirty_extent(fs_info, record); - - while (*p) { - parent_node = *p; - entry = rb_entry(parent_node, struct btrfs_qgroup_extent_record, - node); - if (bytenr < entry->bytenr) - p = &(*p)->rb_left; - else if (bytenr > entry->bytenr) - p = &(*p)->rb_right; - else - return 1; - } - - rb_link_node(&record->node, parent_node, p); - rb_insert_color(&record->node, &delayed_refs->dirty_extent_root); - return 0; -} - -int btrfs_qgroup_insert_dirty_extent(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes, - gfp_t gfp_flag) -{ - struct btrfs_qgroup_extent_record *record; - struct btrfs_delayed_ref_root *delayed_refs; - int ret; - - if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) - || bytenr == 0 || num_bytes == 0) - return 0; - if (WARN_ON(trans == NULL)) - return -EINVAL; - record = kmalloc(sizeof(*record), gfp_flag); - if (!record) - return -ENOMEM; - - delayed_refs = &trans->transaction->delayed_refs; - record->bytenr = bytenr; - record->num_bytes = num_bytes; - record->old_roots = NULL; - - spin_lock(&delayed_refs->lock); - ret = btrfs_qgroup_insert_dirty_extent_nolock(fs_info, delayed_refs, - record); - spin_unlock(&delayed_refs->lock); - if (ret > 0) - kfree(record); - return 0; -} - -#define UPDATE_NEW 0 -#define UPDATE_OLD 1 -/* - * Walk all of the roots that points to the bytenr and adjust their refcnts. - */ -static int qgroup_update_refcnt(struct btrfs_fs_info *fs_info, - struct ulist *roots, struct ulist *tmp, - struct ulist *qgroups, u64 seq, int update_old) -{ - struct ulist_node *unode; - struct ulist_iterator uiter; - struct ulist_node *tmp_unode; - struct ulist_iterator tmp_uiter; - struct btrfs_qgroup *qg; - int ret = 0; - - if (!roots) - return 0; - ULIST_ITER_INIT(&uiter); - while ((unode = ulist_next(roots, &uiter))) { - qg = find_qgroup_rb(fs_info, unode->val); - if (!qg) - continue; - - ulist_reinit(tmp); - ret = ulist_add(qgroups, qg->qgroupid, ptr_to_u64(qg), - GFP_ATOMIC); - if (ret < 0) - return ret; - ret = ulist_add(tmp, qg->qgroupid, ptr_to_u64(qg), GFP_ATOMIC); - if (ret < 0) - return ret; - ULIST_ITER_INIT(&tmp_uiter); - while ((tmp_unode = ulist_next(tmp, &tmp_uiter))) { - struct btrfs_qgroup_list *glist; - - qg = u64_to_ptr(tmp_unode->aux); - if (update_old) - btrfs_qgroup_update_old_refcnt(qg, seq, 1); - else - btrfs_qgroup_update_new_refcnt(qg, seq, 1); - list_for_each_entry(glist, &qg->groups, next_group) { - ret = ulist_add(qgroups, glist->group->qgroupid, - ptr_to_u64(glist->group), - GFP_ATOMIC); - if (ret < 0) - return ret; - ret = ulist_add(tmp, glist->group->qgroupid, - ptr_to_u64(glist->group), - GFP_ATOMIC); - if (ret < 0) - return ret; - } - } - } - return 0; -} - -/* - * Update qgroup rfer/excl counters. - * Rfer update is easy, codes can explain themselves. - * - * Excl update is tricky, the update is split into 2 part. - * Part 1: Possible exclusive <-> sharing detect: - * | A | !A | - * ------------------------------------- - * B | * | - | - * ------------------------------------- - * !B | + | ** | - * ------------------------------------- - * - * Conditions: - * A: cur_old_roots < nr_old_roots (not exclusive before) - * !A: cur_old_roots == nr_old_roots (possible exclusive before) - * B: cur_new_roots < nr_new_roots (not exclusive now) - * !B: cur_new_roots == nr_new_roots (possible exclusive now) - * - * Results: - * +: Possible sharing -> exclusive -: Possible exclusive -> sharing - * *: Definitely not changed. **: Possible unchanged. - * - * For !A and !B condition, the exception is cur_old/new_roots == 0 case. - * - * To make the logic clear, we first use condition A and B to split - * combination into 4 results. - * - * Then, for result "+" and "-", check old/new_roots == 0 case, as in them - * only on variant maybe 0. - * - * Lastly, check result **, since there are 2 variants maybe 0, split them - * again(2x2). - * But this time we don't need to consider other things, the codes and logic - * is easy to understand now. - */ -static int qgroup_update_counters(struct btrfs_fs_info *fs_info, - struct ulist *qgroups, - u64 nr_old_roots, - u64 nr_new_roots, - u64 num_bytes, u64 seq) -{ - struct ulist_node *unode; - struct ulist_iterator uiter; - struct btrfs_qgroup *qg; - u64 cur_new_count, cur_old_count; - - ULIST_ITER_INIT(&uiter); - while ((unode = ulist_next(qgroups, &uiter))) { - bool dirty = false; - - qg = u64_to_ptr(unode->aux); - cur_old_count = btrfs_qgroup_get_old_refcnt(qg, seq); - cur_new_count = btrfs_qgroup_get_new_refcnt(qg, seq); - - trace_qgroup_update_counters(fs_info, qg->qgroupid, - cur_old_count, cur_new_count); - - /* Rfer update part */ - if (cur_old_count == 0 && cur_new_count > 0) { - qg->rfer += num_bytes; - qg->rfer_cmpr += num_bytes; - dirty = true; - } - if (cur_old_count > 0 && cur_new_count == 0) { - qg->rfer -= num_bytes; - qg->rfer_cmpr -= num_bytes; - dirty = true; - } - - /* Excl update part */ - /* Exclusive/none -> shared case */ - if (cur_old_count == nr_old_roots && - cur_new_count < nr_new_roots) { - /* Exclusive -> shared */ - if (cur_old_count != 0) { - qg->excl -= num_bytes; - qg->excl_cmpr -= num_bytes; - dirty = true; - } - } - - /* Shared -> exclusive/none case */ - if (cur_old_count < nr_old_roots && - cur_new_count == nr_new_roots) { - /* Shared->exclusive */ - if (cur_new_count != 0) { - qg->excl += num_bytes; - qg->excl_cmpr += num_bytes; - dirty = true; - } - } - - /* Exclusive/none -> exclusive/none case */ - if (cur_old_count == nr_old_roots && - cur_new_count == nr_new_roots) { - if (cur_old_count == 0) { - /* None -> exclusive/none */ - - if (cur_new_count != 0) { - /* None -> exclusive */ - qg->excl += num_bytes; - qg->excl_cmpr += num_bytes; - dirty = true; - } - /* None -> none, nothing changed */ - } else { - /* Exclusive -> exclusive/none */ - - if (cur_new_count == 0) { - /* Exclusive -> none */ - qg->excl -= num_bytes; - qg->excl_cmpr -= num_bytes; - dirty = true; - } - /* Exclusive -> exclusive, nothing changed */ - } - } - - if (dirty) - qgroup_dirty(fs_info, qg); - } - return 0; -} - -int -btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - u64 bytenr, u64 num_bytes, - struct ulist *old_roots, struct ulist *new_roots) -{ - struct ulist *qgroups = NULL; - struct ulist *tmp = NULL; - u64 seq; - u64 nr_new_roots = 0; - u64 nr_old_roots = 0; - int ret = 0; - - if (new_roots) - nr_new_roots = new_roots->nnodes; - if (old_roots) - nr_old_roots = old_roots->nnodes; - - if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) - goto out_free; - BUG_ON(!fs_info->quota_root); - - trace_btrfs_qgroup_account_extent(fs_info, bytenr, num_bytes, - nr_old_roots, nr_new_roots); - - qgroups = ulist_alloc(GFP_NOFS); - if (!qgroups) { - ret = -ENOMEM; - goto out_free; - } - tmp = ulist_alloc(GFP_NOFS); - if (!tmp) { - ret = -ENOMEM; - goto out_free; - } - - mutex_lock(&fs_info->qgroup_rescan_lock); - if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) { - if (fs_info->qgroup_rescan_progress.objectid <= bytenr) { - mutex_unlock(&fs_info->qgroup_rescan_lock); - ret = 0; - goto out_free; - } - } - mutex_unlock(&fs_info->qgroup_rescan_lock); - - spin_lock(&fs_info->qgroup_lock); - seq = fs_info->qgroup_seq; - - /* Update old refcnts using old_roots */ - ret = qgroup_update_refcnt(fs_info, old_roots, tmp, qgroups, seq, - UPDATE_OLD); - if (ret < 0) - goto out; - - /* Update new refcnts using new_roots */ - ret = qgroup_update_refcnt(fs_info, new_roots, tmp, qgroups, seq, - UPDATE_NEW); - if (ret < 0) - goto out; - - qgroup_update_counters(fs_info, qgroups, nr_old_roots, nr_new_roots, - num_bytes, seq); - - /* - * Bump qgroup_seq to avoid seq overlap - */ - fs_info->qgroup_seq += max(nr_old_roots, nr_new_roots) + 1; -out: - spin_unlock(&fs_info->qgroup_lock); -out_free: - ulist_free(tmp); - ulist_free(qgroups); - ulist_free(old_roots); - ulist_free(new_roots); - return ret; -} - -int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info) -{ - struct btrfs_qgroup_extent_record *record; - struct btrfs_delayed_ref_root *delayed_refs; - struct ulist *new_roots = NULL; - struct rb_node *node; - u64 qgroup_to_skip; - int ret = 0; - - delayed_refs = &trans->transaction->delayed_refs; - qgroup_to_skip = delayed_refs->qgroup_to_skip; - while ((node = rb_first(&delayed_refs->dirty_extent_root))) { - record = rb_entry(node, struct btrfs_qgroup_extent_record, - node); - - trace_btrfs_qgroup_account_extents(fs_info, record); - - if (!ret) { - /* - * Use (u64)-1 as time_seq to do special search, which - * doesn't lock tree or delayed_refs and search current - * root. It's safe inside commit_transaction(). - */ - ret = btrfs_find_all_roots(trans, fs_info, - record->bytenr, (u64)-1, &new_roots); - if (ret < 0) - goto cleanup; - if (qgroup_to_skip) - ulist_del(new_roots, qgroup_to_skip, 0); - ret = btrfs_qgroup_account_extent(trans, fs_info, - record->bytenr, record->num_bytes, - record->old_roots, new_roots); - record->old_roots = NULL; - new_roots = NULL; - } -cleanup: - ulist_free(record->old_roots); - ulist_free(new_roots); - new_roots = NULL; - rb_erase(node, &delayed_refs->dirty_extent_root); - kfree(record); - - } - return ret; -} - -/* - * called from commit_transaction. Writes all changed qgroups to disk. - */ -int btrfs_run_qgroups(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info) -{ - struct btrfs_root *quota_root = fs_info->quota_root; - int ret = 0; - int start_rescan_worker = 0; - - if (!quota_root) - goto out; - - if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags) && - test_bit(BTRFS_FS_QUOTA_ENABLING, &fs_info->flags)) - start_rescan_worker = 1; - - if (test_and_clear_bit(BTRFS_FS_QUOTA_ENABLING, &fs_info->flags)) - set_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); - if (test_and_clear_bit(BTRFS_FS_QUOTA_DISABLING, &fs_info->flags)) - clear_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags); - - spin_lock(&fs_info->qgroup_lock); - while (!list_empty(&fs_info->dirty_qgroups)) { - struct btrfs_qgroup *qgroup; - qgroup = list_first_entry(&fs_info->dirty_qgroups, - struct btrfs_qgroup, dirty); - list_del_init(&qgroup->dirty); - spin_unlock(&fs_info->qgroup_lock); - ret = update_qgroup_info_item(trans, quota_root, qgroup); - if (ret) - fs_info->qgroup_flags |= - BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; - ret = update_qgroup_limit_item(trans, quota_root, qgroup); - if (ret) - fs_info->qgroup_flags |= - BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; - spin_lock(&fs_info->qgroup_lock); - } - if (test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) - fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_ON; - else - fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_ON; - spin_unlock(&fs_info->qgroup_lock); - - ret = update_qgroup_status_item(trans, fs_info, quota_root); - if (ret) - fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; - - if (!ret && start_rescan_worker) { - ret = qgroup_rescan_init(fs_info, 0, 1); - if (!ret) { - qgroup_rescan_zero_tracking(fs_info); - btrfs_queue_work(fs_info->qgroup_rescan_workers, - &fs_info->qgroup_rescan_work); - } - ret = 0; - } - -out: - - return ret; -} - -/* - * Copy the accounting information between qgroups. This is necessary - * when a snapshot or a subvolume is created. Throwing an error will - * cause a transaction abort so we take extra care here to only error - * when a readonly fs is a reasonable outcome. - */ -int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 srcid, u64 objectid, - struct btrfs_qgroup_inherit *inherit) -{ - int ret = 0; - int i; - u64 *i_qgroups; - struct btrfs_root *quota_root = fs_info->quota_root; - struct btrfs_qgroup *srcgroup; - struct btrfs_qgroup *dstgroup; - u32 level_size = 0; - u64 nums; - - mutex_lock(&fs_info->qgroup_ioctl_lock); - if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) - goto out; - - if (!quota_root) { - ret = -EINVAL; - goto out; - } - - if (inherit) { - i_qgroups = (u64 *)(inherit + 1); - nums = inherit->num_qgroups + 2 * inherit->num_ref_copies + - 2 * inherit->num_excl_copies; - for (i = 0; i < nums; ++i) { - srcgroup = find_qgroup_rb(fs_info, *i_qgroups); - - /* - * Zero out invalid groups so we can ignore - * them later. - */ - if (!srcgroup || - ((srcgroup->qgroupid >> 48) <= (objectid >> 48))) - *i_qgroups = 0ULL; - - ++i_qgroups; - } - } - - /* - * create a tracking group for the subvol itself - */ - ret = add_qgroup_item(trans, quota_root, objectid); - if (ret) - goto out; - - if (srcid) { - struct btrfs_root *srcroot; - struct btrfs_key srckey; - - srckey.objectid = srcid; - srckey.type = BTRFS_ROOT_ITEM_KEY; - srckey.offset = (u64)-1; - srcroot = btrfs_read_fs_root_no_name(fs_info, &srckey); - if (IS_ERR(srcroot)) { - ret = PTR_ERR(srcroot); - goto out; - } - - rcu_read_lock(); - level_size = srcroot->nodesize; - rcu_read_unlock(); - } - - /* - * add qgroup to all inherited groups - */ - if (inherit) { - i_qgroups = (u64 *)(inherit + 1); - for (i = 0; i < inherit->num_qgroups; ++i, ++i_qgroups) { - if (*i_qgroups == 0) - continue; - ret = add_qgroup_relation_item(trans, quota_root, - objectid, *i_qgroups); - if (ret && ret != -EEXIST) - goto out; - ret = add_qgroup_relation_item(trans, quota_root, - *i_qgroups, objectid); - if (ret && ret != -EEXIST) - goto out; - } - ret = 0; - } - - - spin_lock(&fs_info->qgroup_lock); - - dstgroup = add_qgroup_rb(fs_info, objectid); - if (IS_ERR(dstgroup)) { - ret = PTR_ERR(dstgroup); - goto unlock; - } - - if (inherit && inherit->flags & BTRFS_QGROUP_INHERIT_SET_LIMITS) { - dstgroup->lim_flags = inherit->lim.flags; - dstgroup->max_rfer = inherit->lim.max_rfer; - dstgroup->max_excl = inherit->lim.max_excl; - dstgroup->rsv_rfer = inherit->lim.rsv_rfer; - dstgroup->rsv_excl = inherit->lim.rsv_excl; - - ret = update_qgroup_limit_item(trans, quota_root, dstgroup); - if (ret) { - fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; - btrfs_info(fs_info, - "unable to update quota limit for %llu", - dstgroup->qgroupid); - goto unlock; - } - } - - if (srcid) { - srcgroup = find_qgroup_rb(fs_info, srcid); - if (!srcgroup) - goto unlock; - - /* - * We call inherit after we clone the root in order to make sure - * our counts don't go crazy, so at this point the only - * difference between the two roots should be the root node. - */ - dstgroup->rfer = srcgroup->rfer; - dstgroup->rfer_cmpr = srcgroup->rfer_cmpr; - dstgroup->excl = level_size; - dstgroup->excl_cmpr = level_size; - srcgroup->excl = level_size; - srcgroup->excl_cmpr = level_size; - - /* inherit the limit info */ - dstgroup->lim_flags = srcgroup->lim_flags; - dstgroup->max_rfer = srcgroup->max_rfer; - dstgroup->max_excl = srcgroup->max_excl; - dstgroup->rsv_rfer = srcgroup->rsv_rfer; - dstgroup->rsv_excl = srcgroup->rsv_excl; - - qgroup_dirty(fs_info, dstgroup); - qgroup_dirty(fs_info, srcgroup); - } - - if (!inherit) - goto unlock; - - i_qgroups = (u64 *)(inherit + 1); - for (i = 0; i < inherit->num_qgroups; ++i) { - if (*i_qgroups) { - ret = add_relation_rb(quota_root->fs_info, objectid, - *i_qgroups); - if (ret) - goto unlock; - } - ++i_qgroups; - } - - for (i = 0; i < inherit->num_ref_copies; ++i, i_qgroups += 2) { - struct btrfs_qgroup *src; - struct btrfs_qgroup *dst; - - if (!i_qgroups[0] || !i_qgroups[1]) - continue; - - src = find_qgroup_rb(fs_info, i_qgroups[0]); - dst = find_qgroup_rb(fs_info, i_qgroups[1]); - - if (!src || !dst) { - ret = -EINVAL; - goto unlock; - } - - dst->rfer = src->rfer - level_size; - dst->rfer_cmpr = src->rfer_cmpr - level_size; - } - for (i = 0; i < inherit->num_excl_copies; ++i, i_qgroups += 2) { - struct btrfs_qgroup *src; - struct btrfs_qgroup *dst; - - if (!i_qgroups[0] || !i_qgroups[1]) - continue; - - src = find_qgroup_rb(fs_info, i_qgroups[0]); - dst = find_qgroup_rb(fs_info, i_qgroups[1]); - - if (!src || !dst) { - ret = -EINVAL; - goto unlock; - } - - dst->excl = src->excl + level_size; - dst->excl_cmpr = src->excl_cmpr + level_size; - } - -unlock: - spin_unlock(&fs_info->qgroup_lock); -out: - mutex_unlock(&fs_info->qgroup_ioctl_lock); - return ret; -} - -static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes) -{ - struct btrfs_root *quota_root; - struct btrfs_qgroup *qgroup; - struct btrfs_fs_info *fs_info = root->fs_info; - u64 ref_root = root->root_key.objectid; - int ret = 0; - struct ulist_node *unode; - struct ulist_iterator uiter; - - if (!is_fstree(ref_root)) - return 0; - - if (num_bytes == 0) - return 0; - - spin_lock(&fs_info->qgroup_lock); - quota_root = fs_info->quota_root; - if (!quota_root) - goto out; - - qgroup = find_qgroup_rb(fs_info, ref_root); - if (!qgroup) - goto out; - - /* - * in a first step, we check all affected qgroups if any limits would - * be exceeded - */ - ulist_reinit(fs_info->qgroup_ulist); - ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid, - (uintptr_t)qgroup, GFP_ATOMIC); - if (ret < 0) - goto out; - ULIST_ITER_INIT(&uiter); - while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) { - struct btrfs_qgroup *qg; - struct btrfs_qgroup_list *glist; - - qg = u64_to_ptr(unode->aux); - - if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_RFER) && - qg->reserved + (s64)qg->rfer + num_bytes > - qg->max_rfer) { - ret = -EDQUOT; - goto out; - } - - if ((qg->lim_flags & BTRFS_QGROUP_LIMIT_MAX_EXCL) && - qg->reserved + (s64)qg->excl + num_bytes > - qg->max_excl) { - ret = -EDQUOT; - goto out; - } - - list_for_each_entry(glist, &qg->groups, next_group) { - ret = ulist_add(fs_info->qgroup_ulist, - glist->group->qgroupid, - (uintptr_t)glist->group, GFP_ATOMIC); - if (ret < 0) - goto out; - } - } - ret = 0; - /* - * no limits exceeded, now record the reservation into all qgroups - */ - ULIST_ITER_INIT(&uiter); - while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) { - struct btrfs_qgroup *qg; - - qg = u64_to_ptr(unode->aux); - - qg->reserved += num_bytes; - } - -out: - spin_unlock(&fs_info->qgroup_lock); - return ret; -} - -void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info, - u64 ref_root, u64 num_bytes) -{ - struct btrfs_root *quota_root; - struct btrfs_qgroup *qgroup; - struct ulist_node *unode; - struct ulist_iterator uiter; - int ret = 0; - - if (!is_fstree(ref_root)) - return; - - if (num_bytes == 0) - return; - - spin_lock(&fs_info->qgroup_lock); - - quota_root = fs_info->quota_root; - if (!quota_root) - goto out; - - qgroup = find_qgroup_rb(fs_info, ref_root); - if (!qgroup) - goto out; - - ulist_reinit(fs_info->qgroup_ulist); - ret = ulist_add(fs_info->qgroup_ulist, qgroup->qgroupid, - (uintptr_t)qgroup, GFP_ATOMIC); - if (ret < 0) - goto out; - ULIST_ITER_INIT(&uiter); - while ((unode = ulist_next(fs_info->qgroup_ulist, &uiter))) { - struct btrfs_qgroup *qg; - struct btrfs_qgroup_list *glist; - - qg = u64_to_ptr(unode->aux); - - qg->reserved -= num_bytes; - - list_for_each_entry(glist, &qg->groups, next_group) { - ret = ulist_add(fs_info->qgroup_ulist, - glist->group->qgroupid, - (uintptr_t)glist->group, GFP_ATOMIC); - if (ret < 0) - goto out; - } - } - -out: - spin_unlock(&fs_info->qgroup_lock); -} - -static inline void qgroup_free(struct btrfs_root *root, u64 num_bytes) -{ - return btrfs_qgroup_free_refroot(root->fs_info, root->objectid, - num_bytes); -} -void assert_qgroups_uptodate(struct btrfs_trans_handle *trans) -{ - if (list_empty(&trans->qgroup_ref_list) && !trans->delayed_ref_elem.seq) - return; - btrfs_err(trans->fs_info, - "qgroups not uptodate in trans handle %p: list is%s empty, seq is %#x.%x", - trans, list_empty(&trans->qgroup_ref_list) ? "" : " not", - (u32)(trans->delayed_ref_elem.seq >> 32), - (u32)trans->delayed_ref_elem.seq); - BUG(); -} - -/* - * returns < 0 on error, 0 when more leafs are to be scanned. - * returns 1 when done. - */ -static int -qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path, - struct btrfs_trans_handle *trans) -{ - struct btrfs_key found; - struct extent_buffer *scratch_leaf = NULL; - struct ulist *roots = NULL; - struct seq_list tree_mod_seq_elem = SEQ_LIST_INIT(tree_mod_seq_elem); - u64 num_bytes; - int slot; - int ret; - - mutex_lock(&fs_info->qgroup_rescan_lock); - ret = btrfs_search_slot_for_read(fs_info->extent_root, - &fs_info->qgroup_rescan_progress, - path, 1, 0); - - btrfs_debug(fs_info, - "current progress key (%llu %u %llu), search_slot ret %d", - fs_info->qgroup_rescan_progress.objectid, - fs_info->qgroup_rescan_progress.type, - fs_info->qgroup_rescan_progress.offset, ret); - - if (ret) { - /* - * The rescan is about to end, we will not be scanning any - * further blocks. We cannot unset the RESCAN flag here, because - * we want to commit the transaction if everything went well. - * To make the live accounting work in this phase, we set our - * scan progress pointer such that every real extent objectid - * will be smaller. - */ - fs_info->qgroup_rescan_progress.objectid = (u64)-1; - btrfs_release_path(path); - mutex_unlock(&fs_info->qgroup_rescan_lock); - return ret; - } - - btrfs_item_key_to_cpu(path->nodes[0], &found, - btrfs_header_nritems(path->nodes[0]) - 1); - fs_info->qgroup_rescan_progress.objectid = found.objectid + 1; - - btrfs_get_tree_mod_seq(fs_info, &tree_mod_seq_elem); - scratch_leaf = btrfs_clone_extent_buffer(path->nodes[0]); - if (!scratch_leaf) { - ret = -ENOMEM; - mutex_unlock(&fs_info->qgroup_rescan_lock); - goto out; - } - extent_buffer_get(scratch_leaf); - btrfs_tree_read_lock(scratch_leaf); - btrfs_set_lock_blocking_rw(scratch_leaf, BTRFS_READ_LOCK); - slot = path->slots[0]; - btrfs_release_path(path); - mutex_unlock(&fs_info->qgroup_rescan_lock); - - for (; slot < btrfs_header_nritems(scratch_leaf); ++slot) { - btrfs_item_key_to_cpu(scratch_leaf, &found, slot); - if (found.type != BTRFS_EXTENT_ITEM_KEY && - found.type != BTRFS_METADATA_ITEM_KEY) - continue; - if (found.type == BTRFS_METADATA_ITEM_KEY) - num_bytes = fs_info->extent_root->nodesize; - else - num_bytes = found.offset; - - ret = btrfs_find_all_roots(NULL, fs_info, found.objectid, 0, - &roots); - if (ret < 0) - goto out; - /* For rescan, just pass old_roots as NULL */ - ret = btrfs_qgroup_account_extent(trans, fs_info, - found.objectid, num_bytes, NULL, roots); - if (ret < 0) - goto out; - } -out: - if (scratch_leaf) { - btrfs_tree_read_unlock_blocking(scratch_leaf); - free_extent_buffer(scratch_leaf); - } - btrfs_put_tree_mod_seq(fs_info, &tree_mod_seq_elem); - - return ret; -} - -static void btrfs_qgroup_rescan_worker(struct btrfs_work *work) -{ - struct btrfs_fs_info *fs_info = container_of(work, struct btrfs_fs_info, - qgroup_rescan_work); - struct btrfs_path *path; - struct btrfs_trans_handle *trans = NULL; - int err = -ENOMEM; - int ret = 0; - - mutex_lock(&fs_info->qgroup_rescan_lock); - fs_info->qgroup_rescan_running = true; - mutex_unlock(&fs_info->qgroup_rescan_lock); - - path = btrfs_alloc_path(); - if (!path) - goto out; - - err = 0; - while (!err && !btrfs_fs_closing(fs_info)) { - trans = btrfs_start_transaction(fs_info->fs_root, 0); - if (IS_ERR(trans)) { - err = PTR_ERR(trans); - break; - } - if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) { - err = -EINTR; - } else { - err = qgroup_rescan_leaf(fs_info, path, trans); - } - if (err > 0) - btrfs_commit_transaction(trans, fs_info->fs_root); - else - btrfs_end_transaction(trans, fs_info->fs_root); - } - -out: - btrfs_free_path(path); - - mutex_lock(&fs_info->qgroup_rescan_lock); - if (!btrfs_fs_closing(fs_info)) - fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; - - if (err > 0 && - fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT) { - fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; - } else if (err < 0) { - fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT; - } - mutex_unlock(&fs_info->qgroup_rescan_lock); - - /* - * only update status, since the previous part has already updated the - * qgroup info. - */ - trans = btrfs_start_transaction(fs_info->quota_root, 1); - if (IS_ERR(trans)) { - err = PTR_ERR(trans); - btrfs_err(fs_info, - "fail to start transaction for status update: %d\n", - err); - goto done; - } - ret = update_qgroup_status_item(trans, fs_info, fs_info->quota_root); - if (ret < 0) { - err = ret; - btrfs_err(fs_info, "fail to update qgroup status: %d", err); - } - btrfs_end_transaction(trans, fs_info->quota_root); - - if (btrfs_fs_closing(fs_info)) { - btrfs_info(fs_info, "qgroup scan paused"); - } else if (err >= 0) { - btrfs_info(fs_info, "qgroup scan completed%s", - err > 0 ? " (inconsistency flag cleared)" : ""); - } else { - btrfs_err(fs_info, "qgroup scan failed with %d", err); - } - -done: - mutex_lock(&fs_info->qgroup_rescan_lock); - fs_info->qgroup_rescan_running = false; - mutex_unlock(&fs_info->qgroup_rescan_lock); - complete_all(&fs_info->qgroup_rescan_completion); -} - -/* - * Checks that (a) no rescan is running and (b) quota is enabled. Allocates all - * memory required for the rescan context. - */ -static int -qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid, - int init_flags) -{ - int ret = 0; - - if (!init_flags && - (!(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) || - !(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_ON))) { - ret = -EINVAL; - goto err; - } - - mutex_lock(&fs_info->qgroup_rescan_lock); - spin_lock(&fs_info->qgroup_lock); - - if (init_flags) { - if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) - ret = -EINPROGRESS; - else if (!(fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_ON)) - ret = -EINVAL; - - if (ret) { - spin_unlock(&fs_info->qgroup_lock); - mutex_unlock(&fs_info->qgroup_rescan_lock); - goto err; - } - fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_RESCAN; - } - - memset(&fs_info->qgroup_rescan_progress, 0, - sizeof(fs_info->qgroup_rescan_progress)); - fs_info->qgroup_rescan_progress.objectid = progress_objectid; - init_completion(&fs_info->qgroup_rescan_completion); - - spin_unlock(&fs_info->qgroup_lock); - mutex_unlock(&fs_info->qgroup_rescan_lock); - - memset(&fs_info->qgroup_rescan_work, 0, - sizeof(fs_info->qgroup_rescan_work)); - btrfs_init_work(&fs_info->qgroup_rescan_work, - btrfs_qgroup_rescan_helper, - btrfs_qgroup_rescan_worker, NULL, NULL); - - if (ret) { -err: - btrfs_info(fs_info, "qgroup_rescan_init failed with %d", ret); - return ret; - } - - return 0; -} - -static void -qgroup_rescan_zero_tracking(struct btrfs_fs_info *fs_info) -{ - struct rb_node *n; - struct btrfs_qgroup *qgroup; - - spin_lock(&fs_info->qgroup_lock); - /* clear all current qgroup tracking information */ - for (n = rb_first(&fs_info->qgroup_tree); n; n = rb_next(n)) { - qgroup = rb_entry(n, struct btrfs_qgroup, node); - qgroup->rfer = 0; - qgroup->rfer_cmpr = 0; - qgroup->excl = 0; - qgroup->excl_cmpr = 0; - } - spin_unlock(&fs_info->qgroup_lock); -} - -int -btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info) -{ - int ret = 0; - struct btrfs_trans_handle *trans; - - ret = qgroup_rescan_init(fs_info, 0, 1); - if (ret) - return ret; - - /* - * We have set the rescan_progress to 0, which means no more - * delayed refs will be accounted by btrfs_qgroup_account_ref. - * However, btrfs_qgroup_account_ref may be right after its call - * to btrfs_find_all_roots, in which case it would still do the - * accounting. - * To solve this, we're committing the transaction, which will - * ensure we run all delayed refs and only after that, we are - * going to clear all tracking information for a clean start. - */ - - trans = btrfs_join_transaction(fs_info->fs_root); - if (IS_ERR(trans)) { - fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; - return PTR_ERR(trans); - } - ret = btrfs_commit_transaction(trans, fs_info->fs_root); - if (ret) { - fs_info->qgroup_flags &= ~BTRFS_QGROUP_STATUS_FLAG_RESCAN; - return ret; - } - - qgroup_rescan_zero_tracking(fs_info); - - btrfs_queue_work(fs_info->qgroup_rescan_workers, - &fs_info->qgroup_rescan_work); - - return 0; -} - -int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info, - bool interruptible) -{ - int running; - int ret = 0; - - mutex_lock(&fs_info->qgroup_rescan_lock); - spin_lock(&fs_info->qgroup_lock); - running = fs_info->qgroup_rescan_running; - spin_unlock(&fs_info->qgroup_lock); - mutex_unlock(&fs_info->qgroup_rescan_lock); - - if (!running) - return 0; - - if (interruptible) - ret = wait_for_completion_interruptible( - &fs_info->qgroup_rescan_completion); - else - wait_for_completion(&fs_info->qgroup_rescan_completion); - - return ret; -} - -/* - * this is only called from open_ctree where we're still single threaded, thus - * locking is omitted here. - */ -void -btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info) -{ - if (fs_info->qgroup_flags & BTRFS_QGROUP_STATUS_FLAG_RESCAN) - btrfs_queue_work(fs_info->qgroup_rescan_workers, - &fs_info->qgroup_rescan_work); -} - -/* - * Reserve qgroup space for range [start, start + len). - * - * This function will either reserve space from related qgroups or doing - * nothing if the range is already reserved. - * - * Return 0 for successful reserve - * Return <0 for error (including -EQUOT) - * - * NOTE: this function may sleep for memory allocation. - */ -int btrfs_qgroup_reserve_data(struct inode *inode, u64 start, u64 len) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct extent_changeset changeset; - struct ulist_node *unode; - struct ulist_iterator uiter; - int ret; - - if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags) || - !is_fstree(root->objectid) || len == 0) - return 0; - - changeset.bytes_changed = 0; - changeset.range_changed = ulist_alloc(GFP_NOFS); - ret = set_record_extent_bits(&BTRFS_I(inode)->io_tree, start, - start + len -1, EXTENT_QGROUP_RESERVED, &changeset); - trace_btrfs_qgroup_reserve_data(inode, start, len, - changeset.bytes_changed, - QGROUP_RESERVE); - if (ret < 0) - goto cleanup; - ret = qgroup_reserve(root, changeset.bytes_changed); - if (ret < 0) - goto cleanup; - - ulist_free(changeset.range_changed); - return ret; - -cleanup: - /* cleanup already reserved ranges */ - ULIST_ITER_INIT(&uiter); - while ((unode = ulist_next(changeset.range_changed, &uiter))) - clear_extent_bit(&BTRFS_I(inode)->io_tree, unode->val, - unode->aux, EXTENT_QGROUP_RESERVED, 0, 0, NULL, - GFP_NOFS); - ulist_free(changeset.range_changed); - return ret; -} - -static int __btrfs_qgroup_release_data(struct inode *inode, u64 start, u64 len, - int free) -{ - struct extent_changeset changeset; - int trace_op = QGROUP_RELEASE; - int ret; - - changeset.bytes_changed = 0; - changeset.range_changed = ulist_alloc(GFP_NOFS); - if (!changeset.range_changed) - return -ENOMEM; - - ret = clear_record_extent_bits(&BTRFS_I(inode)->io_tree, start, - start + len -1, EXTENT_QGROUP_RESERVED, &changeset); - if (ret < 0) - goto out; - - if (free) { - qgroup_free(BTRFS_I(inode)->root, changeset.bytes_changed); - trace_op = QGROUP_FREE; - } - trace_btrfs_qgroup_release_data(inode, start, len, - changeset.bytes_changed, trace_op); -out: - ulist_free(changeset.range_changed); - return ret; -} - -/* - * Free a reserved space range from io_tree and related qgroups - * - * Should be called when a range of pages get invalidated before reaching disk. - * Or for error cleanup case. - * - * For data written to disk, use btrfs_qgroup_release_data(). - * - * NOTE: This function may sleep for memory allocation. - */ -int btrfs_qgroup_free_data(struct inode *inode, u64 start, u64 len) -{ - return __btrfs_qgroup_release_data(inode, start, len, 1); -} - -/* - * Release a reserved space range from io_tree only. - * - * Should be called when a range of pages get written to disk and corresponding - * FILE_EXTENT is inserted into corresponding root. - * - * Since new qgroup accounting framework will only update qgroup numbers at - * commit_transaction() time, its reserved space shouldn't be freed from - * related qgroups. - * - * But we should release the range from io_tree, to allow further write to be - * COWed. - * - * NOTE: This function may sleep for memory allocation. - */ -int btrfs_qgroup_release_data(struct inode *inode, u64 start, u64 len) -{ - return __btrfs_qgroup_release_data(inode, start, len, 0); -} - -int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes) -{ - int ret; - - if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags) || - !is_fstree(root->objectid) || num_bytes == 0) - return 0; - - BUG_ON(num_bytes != round_down(num_bytes, root->nodesize)); - ret = qgroup_reserve(root, num_bytes); - if (ret < 0) - return ret; - atomic_add(num_bytes, &root->qgroup_meta_rsv); - return ret; -} - -void btrfs_qgroup_free_meta_all(struct btrfs_root *root) -{ - int reserved; - - if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags) || - !is_fstree(root->objectid)) - return; - - reserved = atomic_xchg(&root->qgroup_meta_rsv, 0); - if (reserved == 0) - return; - qgroup_free(root, reserved); -} - -void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes) -{ - if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &root->fs_info->flags) || - !is_fstree(root->objectid)) - return; - - BUG_ON(num_bytes != round_down(num_bytes, root->nodesize)); - WARN_ON(atomic_read(&root->qgroup_meta_rsv) < num_bytes); - atomic_sub(num_bytes, &root->qgroup_meta_rsv); - qgroup_free(root, num_bytes); -} - -/* - * Check qgroup reserved space leaking, normally at destroy inode - * time - */ -void btrfs_qgroup_check_reserved_leak(struct inode *inode) -{ - struct extent_changeset changeset; - struct ulist_node *unode; - struct ulist_iterator iter; - int ret; - - changeset.bytes_changed = 0; - changeset.range_changed = ulist_alloc(GFP_NOFS); - if (WARN_ON(!changeset.range_changed)) - return; - - ret = clear_record_extent_bits(&BTRFS_I(inode)->io_tree, 0, (u64)-1, - EXTENT_QGROUP_RESERVED, &changeset); - - WARN_ON(ret < 0); - if (WARN_ON(changeset.bytes_changed)) { - ULIST_ITER_INIT(&iter); - while ((unode = ulist_next(changeset.range_changed, &iter))) { - btrfs_warn(BTRFS_I(inode)->root->fs_info, - "leaking qgroup reserved space, ino: %lu, start: %llu, end: %llu", - inode->i_ino, unode->val, unode->aux); - } - qgroup_free(BTRFS_I(inode)->root, changeset.bytes_changed); - } - ulist_free(changeset.range_changed); -} diff --git a/src/linux/fs/btrfs/qgroup.h b/src/linux/fs/btrfs/qgroup.h deleted file mode 100644 index 1bc64c8..0000000 --- a/src/linux/fs/btrfs/qgroup.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2014 Facebook. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __BTRFS_QGROUP__ -#define __BTRFS_QGROUP__ - -#include "ulist.h" -#include "delayed-ref.h" - -/* - * Record a dirty extent, and info qgroup to update quota on it - * TODO: Use kmem cache to alloc it. - */ -struct btrfs_qgroup_extent_record { - struct rb_node node; - u64 bytenr; - u64 num_bytes; - struct ulist *old_roots; -}; - -/* - * For qgroup event trace points only - */ -#define QGROUP_RESERVE (1<<0) -#define QGROUP_RELEASE (1<<1) -#define QGROUP_FREE (1<<2) - -int btrfs_quota_enable(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info); -int btrfs_quota_disable(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info); -int btrfs_qgroup_rescan(struct btrfs_fs_info *fs_info); -void btrfs_qgroup_rescan_resume(struct btrfs_fs_info *fs_info); -int btrfs_qgroup_wait_for_completion(struct btrfs_fs_info *fs_info, - bool interruptible); -int btrfs_add_qgroup_relation(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 src, u64 dst); -int btrfs_del_qgroup_relation(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 src, u64 dst); -int btrfs_create_qgroup(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 qgroupid); -int btrfs_remove_qgroup(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 qgroupid); -int btrfs_limit_qgroup(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 qgroupid, - struct btrfs_qgroup_limit *limit); -int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info); -void btrfs_free_qgroup_config(struct btrfs_fs_info *fs_info); -struct btrfs_delayed_extent_op; -int btrfs_qgroup_prepare_account_extents(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info); -/* - * Insert one dirty extent record into @delayed_refs, informing qgroup to - * account that extent at commit trans time. - * - * No lock version, caller must acquire delayed ref lock and allocate memory. - * - * Return 0 for success insert - * Return >0 for existing record, caller can free @record safely. - * Error is not possible - */ -int btrfs_qgroup_insert_dirty_extent_nolock( - struct btrfs_fs_info *fs_info, - struct btrfs_delayed_ref_root *delayed_refs, - struct btrfs_qgroup_extent_record *record); - -/* - * Insert one dirty extent record into @delayed_refs, informing qgroup to - * account that extent at commit trans time. - * - * Better encapsulated version. - * - * Return 0 if the operation is done. - * Return <0 for error, like memory allocation failure or invalid parameter - * (NULL trans) - */ -int btrfs_qgroup_insert_dirty_extent(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 bytenr, u64 num_bytes, - gfp_t gfp_flag); - -int -btrfs_qgroup_account_extent(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - u64 bytenr, u64 num_bytes, - struct ulist *old_roots, struct ulist *new_roots); -int btrfs_qgroup_account_extents(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info); -int btrfs_run_qgroups(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info); -int btrfs_qgroup_inherit(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, u64 srcid, u64 objectid, - struct btrfs_qgroup_inherit *inherit); -void btrfs_qgroup_free_refroot(struct btrfs_fs_info *fs_info, - u64 ref_root, u64 num_bytes); -/* - * TODO: Add proper trace point for it, as btrfs_qgroup_free() is - * called by everywhere, can't provide good trace for delayed ref case. - */ -static inline void btrfs_qgroup_free_delayed_ref(struct btrfs_fs_info *fs_info, - u64 ref_root, u64 num_bytes) -{ - btrfs_qgroup_free_refroot(fs_info, ref_root, num_bytes); - trace_btrfs_qgroup_free_delayed_ref(fs_info, ref_root, num_bytes); -} -void assert_qgroups_uptodate(struct btrfs_trans_handle *trans); - -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS -int btrfs_verify_qgroup_counts(struct btrfs_fs_info *fs_info, u64 qgroupid, - u64 rfer, u64 excl); -#endif - -/* New io_tree based accurate qgroup reserve API */ -int btrfs_qgroup_reserve_data(struct inode *inode, u64 start, u64 len); -int btrfs_qgroup_release_data(struct inode *inode, u64 start, u64 len); -int btrfs_qgroup_free_data(struct inode *inode, u64 start, u64 len); - -int btrfs_qgroup_reserve_meta(struct btrfs_root *root, int num_bytes); -void btrfs_qgroup_free_meta_all(struct btrfs_root *root); -void btrfs_qgroup_free_meta(struct btrfs_root *root, int num_bytes); -void btrfs_qgroup_check_reserved_leak(struct inode *inode); -#endif /* __BTRFS_QGROUP__ */ diff --git a/src/linux/fs/btrfs/raid56.c b/src/linux/fs/btrfs/raid56.c deleted file mode 100644 index d016d4a..0000000 --- a/src/linux/fs/btrfs/raid56.c +++ /dev/null @@ -1,2713 +0,0 @@ -/* - * Copyright (C) 2012 Fusion-io All rights reserved. - * Copyright (C) 2012 Intel Corp. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ctree.h" -#include "extent_map.h" -#include "disk-io.h" -#include "transaction.h" -#include "print-tree.h" -#include "volumes.h" -#include "raid56.h" -#include "async-thread.h" -#include "check-integrity.h" -#include "rcu-string.h" - -/* set when additional merges to this rbio are not allowed */ -#define RBIO_RMW_LOCKED_BIT 1 - -/* - * set when this rbio is sitting in the hash, but it is just a cache - * of past RMW - */ -#define RBIO_CACHE_BIT 2 - -/* - * set when it is safe to trust the stripe_pages for caching - */ -#define RBIO_CACHE_READY_BIT 3 - -#define RBIO_CACHE_SIZE 1024 - -enum btrfs_rbio_ops { - BTRFS_RBIO_WRITE, - BTRFS_RBIO_READ_REBUILD, - BTRFS_RBIO_PARITY_SCRUB, - BTRFS_RBIO_REBUILD_MISSING, -}; - -struct btrfs_raid_bio { - struct btrfs_fs_info *fs_info; - struct btrfs_bio *bbio; - - /* while we're doing rmw on a stripe - * we put it into a hash table so we can - * lock the stripe and merge more rbios - * into it. - */ - struct list_head hash_list; - - /* - * LRU list for the stripe cache - */ - struct list_head stripe_cache; - - /* - * for scheduling work in the helper threads - */ - struct btrfs_work work; - - /* - * bio list and bio_list_lock are used - * to add more bios into the stripe - * in hopes of avoiding the full rmw - */ - struct bio_list bio_list; - spinlock_t bio_list_lock; - - /* also protected by the bio_list_lock, the - * plug list is used by the plugging code - * to collect partial bios while plugged. The - * stripe locking code also uses it to hand off - * the stripe lock to the next pending IO - */ - struct list_head plug_list; - - /* - * flags that tell us if it is safe to - * merge with this bio - */ - unsigned long flags; - - /* size of each individual stripe on disk */ - int stripe_len; - - /* number of data stripes (no p/q) */ - int nr_data; - - int real_stripes; - - int stripe_npages; - /* - * set if we're doing a parity rebuild - * for a read from higher up, which is handled - * differently from a parity rebuild as part of - * rmw - */ - enum btrfs_rbio_ops operation; - - /* first bad stripe */ - int faila; - - /* second bad stripe (for raid6 use) */ - int failb; - - int scrubp; - /* - * number of pages needed to represent the full - * stripe - */ - int nr_pages; - - /* - * size of all the bios in the bio_list. This - * helps us decide if the rbio maps to a full - * stripe or not - */ - int bio_list_bytes; - - int generic_bio_cnt; - - atomic_t refs; - - atomic_t stripes_pending; - - atomic_t error; - /* - * these are two arrays of pointers. We allocate the - * rbio big enough to hold them both and setup their - * locations when the rbio is allocated - */ - - /* pointers to pages that we allocated for - * reading/writing stripes directly from the disk (including P/Q) - */ - struct page **stripe_pages; - - /* - * pointers to the pages in the bio_list. Stored - * here for faster lookup - */ - struct page **bio_pages; - - /* - * bitmap to record which horizontal stripe has data - */ - unsigned long *dbitmap; -}; - -static int __raid56_parity_recover(struct btrfs_raid_bio *rbio); -static noinline void finish_rmw(struct btrfs_raid_bio *rbio); -static void rmw_work(struct btrfs_work *work); -static void read_rebuild_work(struct btrfs_work *work); -static void async_rmw_stripe(struct btrfs_raid_bio *rbio); -static void async_read_rebuild(struct btrfs_raid_bio *rbio); -static int fail_bio_stripe(struct btrfs_raid_bio *rbio, struct bio *bio); -static int fail_rbio_index(struct btrfs_raid_bio *rbio, int failed); -static void __free_raid_bio(struct btrfs_raid_bio *rbio); -static void index_rbio_pages(struct btrfs_raid_bio *rbio); -static int alloc_rbio_pages(struct btrfs_raid_bio *rbio); - -static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio, - int need_check); -static void async_scrub_parity(struct btrfs_raid_bio *rbio); - -/* - * the stripe hash table is used for locking, and to collect - * bios in hopes of making a full stripe - */ -int btrfs_alloc_stripe_hash_table(struct btrfs_fs_info *info) -{ - struct btrfs_stripe_hash_table *table; - struct btrfs_stripe_hash_table *x; - struct btrfs_stripe_hash *cur; - struct btrfs_stripe_hash *h; - int num_entries = 1 << BTRFS_STRIPE_HASH_TABLE_BITS; - int i; - int table_size; - - if (info->stripe_hash_table) - return 0; - - /* - * The table is large, starting with order 4 and can go as high as - * order 7 in case lock debugging is turned on. - * - * Try harder to allocate and fallback to vmalloc to lower the chance - * of a failing mount. - */ - table_size = sizeof(*table) + sizeof(*h) * num_entries; - table = kzalloc(table_size, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT); - if (!table) { - table = vzalloc(table_size); - if (!table) - return -ENOMEM; - } - - spin_lock_init(&table->cache_lock); - INIT_LIST_HEAD(&table->stripe_cache); - - h = table->table; - - for (i = 0; i < num_entries; i++) { - cur = h + i; - INIT_LIST_HEAD(&cur->hash_list); - spin_lock_init(&cur->lock); - init_waitqueue_head(&cur->wait); - } - - x = cmpxchg(&info->stripe_hash_table, NULL, table); - if (x) - kvfree(x); - return 0; -} - -/* - * caching an rbio means to copy anything from the - * bio_pages array into the stripe_pages array. We - * use the page uptodate bit in the stripe cache array - * to indicate if it has valid data - * - * once the caching is done, we set the cache ready - * bit. - */ -static void cache_rbio_pages(struct btrfs_raid_bio *rbio) -{ - int i; - char *s; - char *d; - int ret; - - ret = alloc_rbio_pages(rbio); - if (ret) - return; - - for (i = 0; i < rbio->nr_pages; i++) { - if (!rbio->bio_pages[i]) - continue; - - s = kmap(rbio->bio_pages[i]); - d = kmap(rbio->stripe_pages[i]); - - memcpy(d, s, PAGE_SIZE); - - kunmap(rbio->bio_pages[i]); - kunmap(rbio->stripe_pages[i]); - SetPageUptodate(rbio->stripe_pages[i]); - } - set_bit(RBIO_CACHE_READY_BIT, &rbio->flags); -} - -/* - * we hash on the first logical address of the stripe - */ -static int rbio_bucket(struct btrfs_raid_bio *rbio) -{ - u64 num = rbio->bbio->raid_map[0]; - - /* - * we shift down quite a bit. We're using byte - * addressing, and most of the lower bits are zeros. - * This tends to upset hash_64, and it consistently - * returns just one or two different values. - * - * shifting off the lower bits fixes things. - */ - return hash_64(num >> 16, BTRFS_STRIPE_HASH_TABLE_BITS); -} - -/* - * stealing an rbio means taking all the uptodate pages from the stripe - * array in the source rbio and putting them into the destination rbio - */ -static void steal_rbio(struct btrfs_raid_bio *src, struct btrfs_raid_bio *dest) -{ - int i; - struct page *s; - struct page *d; - - if (!test_bit(RBIO_CACHE_READY_BIT, &src->flags)) - return; - - for (i = 0; i < dest->nr_pages; i++) { - s = src->stripe_pages[i]; - if (!s || !PageUptodate(s)) { - continue; - } - - d = dest->stripe_pages[i]; - if (d) - __free_page(d); - - dest->stripe_pages[i] = s; - src->stripe_pages[i] = NULL; - } -} - -/* - * merging means we take the bio_list from the victim and - * splice it into the destination. The victim should - * be discarded afterwards. - * - * must be called with dest->rbio_list_lock held - */ -static void merge_rbio(struct btrfs_raid_bio *dest, - struct btrfs_raid_bio *victim) -{ - bio_list_merge(&dest->bio_list, &victim->bio_list); - dest->bio_list_bytes += victim->bio_list_bytes; - dest->generic_bio_cnt += victim->generic_bio_cnt; - bio_list_init(&victim->bio_list); -} - -/* - * used to prune items that are in the cache. The caller - * must hold the hash table lock. - */ -static void __remove_rbio_from_cache(struct btrfs_raid_bio *rbio) -{ - int bucket = rbio_bucket(rbio); - struct btrfs_stripe_hash_table *table; - struct btrfs_stripe_hash *h; - int freeit = 0; - - /* - * check the bit again under the hash table lock. - */ - if (!test_bit(RBIO_CACHE_BIT, &rbio->flags)) - return; - - table = rbio->fs_info->stripe_hash_table; - h = table->table + bucket; - - /* hold the lock for the bucket because we may be - * removing it from the hash table - */ - spin_lock(&h->lock); - - /* - * hold the lock for the bio list because we need - * to make sure the bio list is empty - */ - spin_lock(&rbio->bio_list_lock); - - if (test_and_clear_bit(RBIO_CACHE_BIT, &rbio->flags)) { - list_del_init(&rbio->stripe_cache); - table->cache_size -= 1; - freeit = 1; - - /* if the bio list isn't empty, this rbio is - * still involved in an IO. We take it out - * of the cache list, and drop the ref that - * was held for the list. - * - * If the bio_list was empty, we also remove - * the rbio from the hash_table, and drop - * the corresponding ref - */ - if (bio_list_empty(&rbio->bio_list)) { - if (!list_empty(&rbio->hash_list)) { - list_del_init(&rbio->hash_list); - atomic_dec(&rbio->refs); - BUG_ON(!list_empty(&rbio->plug_list)); - } - } - } - - spin_unlock(&rbio->bio_list_lock); - spin_unlock(&h->lock); - - if (freeit) - __free_raid_bio(rbio); -} - -/* - * prune a given rbio from the cache - */ -static void remove_rbio_from_cache(struct btrfs_raid_bio *rbio) -{ - struct btrfs_stripe_hash_table *table; - unsigned long flags; - - if (!test_bit(RBIO_CACHE_BIT, &rbio->flags)) - return; - - table = rbio->fs_info->stripe_hash_table; - - spin_lock_irqsave(&table->cache_lock, flags); - __remove_rbio_from_cache(rbio); - spin_unlock_irqrestore(&table->cache_lock, flags); -} - -/* - * remove everything in the cache - */ -static void btrfs_clear_rbio_cache(struct btrfs_fs_info *info) -{ - struct btrfs_stripe_hash_table *table; - unsigned long flags; - struct btrfs_raid_bio *rbio; - - table = info->stripe_hash_table; - - spin_lock_irqsave(&table->cache_lock, flags); - while (!list_empty(&table->stripe_cache)) { - rbio = list_entry(table->stripe_cache.next, - struct btrfs_raid_bio, - stripe_cache); - __remove_rbio_from_cache(rbio); - } - spin_unlock_irqrestore(&table->cache_lock, flags); -} - -/* - * remove all cached entries and free the hash table - * used by unmount - */ -void btrfs_free_stripe_hash_table(struct btrfs_fs_info *info) -{ - if (!info->stripe_hash_table) - return; - btrfs_clear_rbio_cache(info); - kvfree(info->stripe_hash_table); - info->stripe_hash_table = NULL; -} - -/* - * insert an rbio into the stripe cache. It - * must have already been prepared by calling - * cache_rbio_pages - * - * If this rbio was already cached, it gets - * moved to the front of the lru. - * - * If the size of the rbio cache is too big, we - * prune an item. - */ -static void cache_rbio(struct btrfs_raid_bio *rbio) -{ - struct btrfs_stripe_hash_table *table; - unsigned long flags; - - if (!test_bit(RBIO_CACHE_READY_BIT, &rbio->flags)) - return; - - table = rbio->fs_info->stripe_hash_table; - - spin_lock_irqsave(&table->cache_lock, flags); - spin_lock(&rbio->bio_list_lock); - - /* bump our ref if we were not in the list before */ - if (!test_and_set_bit(RBIO_CACHE_BIT, &rbio->flags)) - atomic_inc(&rbio->refs); - - if (!list_empty(&rbio->stripe_cache)){ - list_move(&rbio->stripe_cache, &table->stripe_cache); - } else { - list_add(&rbio->stripe_cache, &table->stripe_cache); - table->cache_size += 1; - } - - spin_unlock(&rbio->bio_list_lock); - - if (table->cache_size > RBIO_CACHE_SIZE) { - struct btrfs_raid_bio *found; - - found = list_entry(table->stripe_cache.prev, - struct btrfs_raid_bio, - stripe_cache); - - if (found != rbio) - __remove_rbio_from_cache(found); - } - - spin_unlock_irqrestore(&table->cache_lock, flags); -} - -/* - * helper function to run the xor_blocks api. It is only - * able to do MAX_XOR_BLOCKS at a time, so we need to - * loop through. - */ -static void run_xor(void **pages, int src_cnt, ssize_t len) -{ - int src_off = 0; - int xor_src_cnt = 0; - void *dest = pages[src_cnt]; - - while(src_cnt > 0) { - xor_src_cnt = min(src_cnt, MAX_XOR_BLOCKS); - xor_blocks(xor_src_cnt, len, dest, pages + src_off); - - src_cnt -= xor_src_cnt; - src_off += xor_src_cnt; - } -} - -/* - * returns true if the bio list inside this rbio - * covers an entire stripe (no rmw required). - * Must be called with the bio list lock held, or - * at a time when you know it is impossible to add - * new bios into the list - */ -static int __rbio_is_full(struct btrfs_raid_bio *rbio) -{ - unsigned long size = rbio->bio_list_bytes; - int ret = 1; - - if (size != rbio->nr_data * rbio->stripe_len) - ret = 0; - - BUG_ON(size > rbio->nr_data * rbio->stripe_len); - return ret; -} - -static int rbio_is_full(struct btrfs_raid_bio *rbio) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&rbio->bio_list_lock, flags); - ret = __rbio_is_full(rbio); - spin_unlock_irqrestore(&rbio->bio_list_lock, flags); - return ret; -} - -/* - * returns 1 if it is safe to merge two rbios together. - * The merging is safe if the two rbios correspond to - * the same stripe and if they are both going in the same - * direction (read vs write), and if neither one is - * locked for final IO - * - * The caller is responsible for locking such that - * rmw_locked is safe to test - */ -static int rbio_can_merge(struct btrfs_raid_bio *last, - struct btrfs_raid_bio *cur) -{ - if (test_bit(RBIO_RMW_LOCKED_BIT, &last->flags) || - test_bit(RBIO_RMW_LOCKED_BIT, &cur->flags)) - return 0; - - /* - * we can't merge with cached rbios, since the - * idea is that when we merge the destination - * rbio is going to run our IO for us. We can - * steal from cached rbios though, other functions - * handle that. - */ - if (test_bit(RBIO_CACHE_BIT, &last->flags) || - test_bit(RBIO_CACHE_BIT, &cur->flags)) - return 0; - - if (last->bbio->raid_map[0] != - cur->bbio->raid_map[0]) - return 0; - - /* we can't merge with different operations */ - if (last->operation != cur->operation) - return 0; - /* - * We've need read the full stripe from the drive. - * check and repair the parity and write the new results. - * - * We're not allowed to add any new bios to the - * bio list here, anyone else that wants to - * change this stripe needs to do their own rmw. - */ - if (last->operation == BTRFS_RBIO_PARITY_SCRUB || - cur->operation == BTRFS_RBIO_PARITY_SCRUB) - return 0; - - if (last->operation == BTRFS_RBIO_REBUILD_MISSING || - cur->operation == BTRFS_RBIO_REBUILD_MISSING) - return 0; - - return 1; -} - -static int rbio_stripe_page_index(struct btrfs_raid_bio *rbio, int stripe, - int index) -{ - return stripe * rbio->stripe_npages + index; -} - -/* - * these are just the pages from the rbio array, not from anything - * the FS sent down to us - */ -static struct page *rbio_stripe_page(struct btrfs_raid_bio *rbio, int stripe, - int index) -{ - return rbio->stripe_pages[rbio_stripe_page_index(rbio, stripe, index)]; -} - -/* - * helper to index into the pstripe - */ -static struct page *rbio_pstripe_page(struct btrfs_raid_bio *rbio, int index) -{ - return rbio_stripe_page(rbio, rbio->nr_data, index); -} - -/* - * helper to index into the qstripe, returns null - * if there is no qstripe - */ -static struct page *rbio_qstripe_page(struct btrfs_raid_bio *rbio, int index) -{ - if (rbio->nr_data + 1 == rbio->real_stripes) - return NULL; - return rbio_stripe_page(rbio, rbio->nr_data + 1, index); -} - -/* - * The first stripe in the table for a logical address - * has the lock. rbios are added in one of three ways: - * - * 1) Nobody has the stripe locked yet. The rbio is given - * the lock and 0 is returned. The caller must start the IO - * themselves. - * - * 2) Someone has the stripe locked, but we're able to merge - * with the lock owner. The rbio is freed and the IO will - * start automatically along with the existing rbio. 1 is returned. - * - * 3) Someone has the stripe locked, but we're not able to merge. - * The rbio is added to the lock owner's plug list, or merged into - * an rbio already on the plug list. When the lock owner unlocks, - * the next rbio on the list is run and the IO is started automatically. - * 1 is returned - * - * If we return 0, the caller still owns the rbio and must continue with - * IO submission. If we return 1, the caller must assume the rbio has - * already been freed. - */ -static noinline int lock_stripe_add(struct btrfs_raid_bio *rbio) -{ - int bucket = rbio_bucket(rbio); - struct btrfs_stripe_hash *h = rbio->fs_info->stripe_hash_table->table + bucket; - struct btrfs_raid_bio *cur; - struct btrfs_raid_bio *pending; - unsigned long flags; - DEFINE_WAIT(wait); - struct btrfs_raid_bio *freeit = NULL; - struct btrfs_raid_bio *cache_drop = NULL; - int ret = 0; - int walk = 0; - - spin_lock_irqsave(&h->lock, flags); - list_for_each_entry(cur, &h->hash_list, hash_list) { - walk++; - if (cur->bbio->raid_map[0] == rbio->bbio->raid_map[0]) { - spin_lock(&cur->bio_list_lock); - - /* can we steal this cached rbio's pages? */ - if (bio_list_empty(&cur->bio_list) && - list_empty(&cur->plug_list) && - test_bit(RBIO_CACHE_BIT, &cur->flags) && - !test_bit(RBIO_RMW_LOCKED_BIT, &cur->flags)) { - list_del_init(&cur->hash_list); - atomic_dec(&cur->refs); - - steal_rbio(cur, rbio); - cache_drop = cur; - spin_unlock(&cur->bio_list_lock); - - goto lockit; - } - - /* can we merge into the lock owner? */ - if (rbio_can_merge(cur, rbio)) { - merge_rbio(cur, rbio); - spin_unlock(&cur->bio_list_lock); - freeit = rbio; - ret = 1; - goto out; - } - - - /* - * we couldn't merge with the running - * rbio, see if we can merge with the - * pending ones. We don't have to - * check for rmw_locked because there - * is no way they are inside finish_rmw - * right now - */ - list_for_each_entry(pending, &cur->plug_list, - plug_list) { - if (rbio_can_merge(pending, rbio)) { - merge_rbio(pending, rbio); - spin_unlock(&cur->bio_list_lock); - freeit = rbio; - ret = 1; - goto out; - } - } - - /* no merging, put us on the tail of the plug list, - * our rbio will be started with the currently - * running rbio unlocks - */ - list_add_tail(&rbio->plug_list, &cur->plug_list); - spin_unlock(&cur->bio_list_lock); - ret = 1; - goto out; - } - } -lockit: - atomic_inc(&rbio->refs); - list_add(&rbio->hash_list, &h->hash_list); -out: - spin_unlock_irqrestore(&h->lock, flags); - if (cache_drop) - remove_rbio_from_cache(cache_drop); - if (freeit) - __free_raid_bio(freeit); - return ret; -} - -/* - * called as rmw or parity rebuild is completed. If the plug list has more - * rbios waiting for this stripe, the next one on the list will be started - */ -static noinline void unlock_stripe(struct btrfs_raid_bio *rbio) -{ - int bucket; - struct btrfs_stripe_hash *h; - unsigned long flags; - int keep_cache = 0; - - bucket = rbio_bucket(rbio); - h = rbio->fs_info->stripe_hash_table->table + bucket; - - if (list_empty(&rbio->plug_list)) - cache_rbio(rbio); - - spin_lock_irqsave(&h->lock, flags); - spin_lock(&rbio->bio_list_lock); - - if (!list_empty(&rbio->hash_list)) { - /* - * if we're still cached and there is no other IO - * to perform, just leave this rbio here for others - * to steal from later - */ - if (list_empty(&rbio->plug_list) && - test_bit(RBIO_CACHE_BIT, &rbio->flags)) { - keep_cache = 1; - clear_bit(RBIO_RMW_LOCKED_BIT, &rbio->flags); - BUG_ON(!bio_list_empty(&rbio->bio_list)); - goto done; - } - - list_del_init(&rbio->hash_list); - atomic_dec(&rbio->refs); - - /* - * we use the plug list to hold all the rbios - * waiting for the chance to lock this stripe. - * hand the lock over to one of them. - */ - if (!list_empty(&rbio->plug_list)) { - struct btrfs_raid_bio *next; - struct list_head *head = rbio->plug_list.next; - - next = list_entry(head, struct btrfs_raid_bio, - plug_list); - - list_del_init(&rbio->plug_list); - - list_add(&next->hash_list, &h->hash_list); - atomic_inc(&next->refs); - spin_unlock(&rbio->bio_list_lock); - spin_unlock_irqrestore(&h->lock, flags); - - if (next->operation == BTRFS_RBIO_READ_REBUILD) - async_read_rebuild(next); - else if (next->operation == BTRFS_RBIO_REBUILD_MISSING) { - steal_rbio(rbio, next); - async_read_rebuild(next); - } else if (next->operation == BTRFS_RBIO_WRITE) { - steal_rbio(rbio, next); - async_rmw_stripe(next); - } else if (next->operation == BTRFS_RBIO_PARITY_SCRUB) { - steal_rbio(rbio, next); - async_scrub_parity(next); - } - - goto done_nolock; - /* - * The barrier for this waitqueue_active is not needed, - * we're protected by h->lock and can't miss a wakeup. - */ - } else if (waitqueue_active(&h->wait)) { - spin_unlock(&rbio->bio_list_lock); - spin_unlock_irqrestore(&h->lock, flags); - wake_up(&h->wait); - goto done_nolock; - } - } -done: - spin_unlock(&rbio->bio_list_lock); - spin_unlock_irqrestore(&h->lock, flags); - -done_nolock: - if (!keep_cache) - remove_rbio_from_cache(rbio); -} - -static void __free_raid_bio(struct btrfs_raid_bio *rbio) -{ - int i; - - WARN_ON(atomic_read(&rbio->refs) < 0); - if (!atomic_dec_and_test(&rbio->refs)) - return; - - WARN_ON(!list_empty(&rbio->stripe_cache)); - WARN_ON(!list_empty(&rbio->hash_list)); - WARN_ON(!bio_list_empty(&rbio->bio_list)); - - for (i = 0; i < rbio->nr_pages; i++) { - if (rbio->stripe_pages[i]) { - __free_page(rbio->stripe_pages[i]); - rbio->stripe_pages[i] = NULL; - } - } - - btrfs_put_bbio(rbio->bbio); - kfree(rbio); -} - -static void free_raid_bio(struct btrfs_raid_bio *rbio) -{ - unlock_stripe(rbio); - __free_raid_bio(rbio); -} - -/* - * this frees the rbio and runs through all the bios in the - * bio_list and calls end_io on them - */ -static void rbio_orig_end_io(struct btrfs_raid_bio *rbio, int err) -{ - struct bio *cur = bio_list_get(&rbio->bio_list); - struct bio *next; - - if (rbio->generic_bio_cnt) - btrfs_bio_counter_sub(rbio->fs_info, rbio->generic_bio_cnt); - - free_raid_bio(rbio); - - while (cur) { - next = cur->bi_next; - cur->bi_next = NULL; - cur->bi_error = err; - bio_endio(cur); - cur = next; - } -} - -/* - * end io function used by finish_rmw. When we finally - * get here, we've written a full stripe - */ -static void raid_write_end_io(struct bio *bio) -{ - struct btrfs_raid_bio *rbio = bio->bi_private; - int err = bio->bi_error; - int max_errors; - - if (err) - fail_bio_stripe(rbio, bio); - - bio_put(bio); - - if (!atomic_dec_and_test(&rbio->stripes_pending)) - return; - - err = 0; - - /* OK, we have read all the stripes we need to. */ - max_errors = (rbio->operation == BTRFS_RBIO_PARITY_SCRUB) ? - 0 : rbio->bbio->max_errors; - if (atomic_read(&rbio->error) > max_errors) - err = -EIO; - - rbio_orig_end_io(rbio, err); -} - -/* - * the read/modify/write code wants to use the original bio for - * any pages it included, and then use the rbio for everything - * else. This function decides if a given index (stripe number) - * and page number in that stripe fall inside the original bio - * or the rbio. - * - * if you set bio_list_only, you'll get a NULL back for any ranges - * that are outside the bio_list - * - * This doesn't take any refs on anything, you get a bare page pointer - * and the caller must bump refs as required. - * - * You must call index_rbio_pages once before you can trust - * the answers from this function. - */ -static struct page *page_in_rbio(struct btrfs_raid_bio *rbio, - int index, int pagenr, int bio_list_only) -{ - int chunk_page; - struct page *p = NULL; - - chunk_page = index * (rbio->stripe_len >> PAGE_SHIFT) + pagenr; - - spin_lock_irq(&rbio->bio_list_lock); - p = rbio->bio_pages[chunk_page]; - spin_unlock_irq(&rbio->bio_list_lock); - - if (p || bio_list_only) - return p; - - return rbio->stripe_pages[chunk_page]; -} - -/* - * number of pages we need for the entire stripe across all the - * drives - */ -static unsigned long rbio_nr_pages(unsigned long stripe_len, int nr_stripes) -{ - return DIV_ROUND_UP(stripe_len, PAGE_SIZE) * nr_stripes; -} - -/* - * allocation and initial setup for the btrfs_raid_bio. Not - * this does not allocate any pages for rbio->pages. - */ -static struct btrfs_raid_bio *alloc_rbio(struct btrfs_root *root, - struct btrfs_bio *bbio, u64 stripe_len) -{ - struct btrfs_raid_bio *rbio; - int nr_data = 0; - int real_stripes = bbio->num_stripes - bbio->num_tgtdevs; - int num_pages = rbio_nr_pages(stripe_len, real_stripes); - int stripe_npages = DIV_ROUND_UP(stripe_len, PAGE_SIZE); - void *p; - - rbio = kzalloc(sizeof(*rbio) + num_pages * sizeof(struct page *) * 2 + - DIV_ROUND_UP(stripe_npages, BITS_PER_LONG) * - sizeof(long), GFP_NOFS); - if (!rbio) - return ERR_PTR(-ENOMEM); - - bio_list_init(&rbio->bio_list); - INIT_LIST_HEAD(&rbio->plug_list); - spin_lock_init(&rbio->bio_list_lock); - INIT_LIST_HEAD(&rbio->stripe_cache); - INIT_LIST_HEAD(&rbio->hash_list); - rbio->bbio = bbio; - rbio->fs_info = root->fs_info; - rbio->stripe_len = stripe_len; - rbio->nr_pages = num_pages; - rbio->real_stripes = real_stripes; - rbio->stripe_npages = stripe_npages; - rbio->faila = -1; - rbio->failb = -1; - atomic_set(&rbio->refs, 1); - atomic_set(&rbio->error, 0); - atomic_set(&rbio->stripes_pending, 0); - - /* - * the stripe_pages and bio_pages array point to the extra - * memory we allocated past the end of the rbio - */ - p = rbio + 1; - rbio->stripe_pages = p; - rbio->bio_pages = p + sizeof(struct page *) * num_pages; - rbio->dbitmap = p + sizeof(struct page *) * num_pages * 2; - - if (bbio->map_type & BTRFS_BLOCK_GROUP_RAID5) - nr_data = real_stripes - 1; - else if (bbio->map_type & BTRFS_BLOCK_GROUP_RAID6) - nr_data = real_stripes - 2; - else - BUG(); - - rbio->nr_data = nr_data; - return rbio; -} - -/* allocate pages for all the stripes in the bio, including parity */ -static int alloc_rbio_pages(struct btrfs_raid_bio *rbio) -{ - int i; - struct page *page; - - for (i = 0; i < rbio->nr_pages; i++) { - if (rbio->stripe_pages[i]) - continue; - page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); - if (!page) - return -ENOMEM; - rbio->stripe_pages[i] = page; - } - return 0; -} - -/* only allocate pages for p/q stripes */ -static int alloc_rbio_parity_pages(struct btrfs_raid_bio *rbio) -{ - int i; - struct page *page; - - i = rbio_stripe_page_index(rbio, rbio->nr_data, 0); - - for (; i < rbio->nr_pages; i++) { - if (rbio->stripe_pages[i]) - continue; - page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); - if (!page) - return -ENOMEM; - rbio->stripe_pages[i] = page; - } - return 0; -} - -/* - * add a single page from a specific stripe into our list of bios for IO - * this will try to merge into existing bios if possible, and returns - * zero if all went well. - */ -static int rbio_add_io_page(struct btrfs_raid_bio *rbio, - struct bio_list *bio_list, - struct page *page, - int stripe_nr, - unsigned long page_index, - unsigned long bio_max_len) -{ - struct bio *last = bio_list->tail; - u64 last_end = 0; - int ret; - struct bio *bio; - struct btrfs_bio_stripe *stripe; - u64 disk_start; - - stripe = &rbio->bbio->stripes[stripe_nr]; - disk_start = stripe->physical + (page_index << PAGE_SHIFT); - - /* if the device is missing, just fail this stripe */ - if (!stripe->dev->bdev) - return fail_rbio_index(rbio, stripe_nr); - - /* see if we can add this page onto our existing bio */ - if (last) { - last_end = (u64)last->bi_iter.bi_sector << 9; - last_end += last->bi_iter.bi_size; - - /* - * we can't merge these if they are from different - * devices or if they are not contiguous - */ - if (last_end == disk_start && stripe->dev->bdev && - !last->bi_error && - last->bi_bdev == stripe->dev->bdev) { - ret = bio_add_page(last, page, PAGE_SIZE, 0); - if (ret == PAGE_SIZE) - return 0; - } - } - - /* put a new bio on the list */ - bio = btrfs_io_bio_alloc(GFP_NOFS, bio_max_len >> PAGE_SHIFT?:1); - if (!bio) - return -ENOMEM; - - bio->bi_iter.bi_size = 0; - bio->bi_bdev = stripe->dev->bdev; - bio->bi_iter.bi_sector = disk_start >> 9; - - bio_add_page(bio, page, PAGE_SIZE, 0); - bio_list_add(bio_list, bio); - return 0; -} - -/* - * while we're doing the read/modify/write cycle, we could - * have errors in reading pages off the disk. This checks - * for errors and if we're not able to read the page it'll - * trigger parity reconstruction. The rmw will be finished - * after we've reconstructed the failed stripes - */ -static void validate_rbio_for_rmw(struct btrfs_raid_bio *rbio) -{ - if (rbio->faila >= 0 || rbio->failb >= 0) { - BUG_ON(rbio->faila == rbio->real_stripes - 1); - __raid56_parity_recover(rbio); - } else { - finish_rmw(rbio); - } -} - -/* - * helper function to walk our bio list and populate the bio_pages array with - * the result. This seems expensive, but it is faster than constantly - * searching through the bio list as we setup the IO in finish_rmw or stripe - * reconstruction. - * - * This must be called before you trust the answers from page_in_rbio - */ -static void index_rbio_pages(struct btrfs_raid_bio *rbio) -{ - struct bio *bio; - u64 start; - unsigned long stripe_offset; - unsigned long page_index; - struct page *p; - int i; - - spin_lock_irq(&rbio->bio_list_lock); - bio_list_for_each(bio, &rbio->bio_list) { - start = (u64)bio->bi_iter.bi_sector << 9; - stripe_offset = start - rbio->bbio->raid_map[0]; - page_index = stripe_offset >> PAGE_SHIFT; - - for (i = 0; i < bio->bi_vcnt; i++) { - p = bio->bi_io_vec[i].bv_page; - rbio->bio_pages[page_index + i] = p; - } - } - spin_unlock_irq(&rbio->bio_list_lock); -} - -/* - * this is called from one of two situations. We either - * have a full stripe from the higher layers, or we've read all - * the missing bits off disk. - * - * This will calculate the parity and then send down any - * changed blocks. - */ -static noinline void finish_rmw(struct btrfs_raid_bio *rbio) -{ - struct btrfs_bio *bbio = rbio->bbio; - void *pointers[rbio->real_stripes]; - int nr_data = rbio->nr_data; - int stripe; - int pagenr; - int p_stripe = -1; - int q_stripe = -1; - struct bio_list bio_list; - struct bio *bio; - int ret; - - bio_list_init(&bio_list); - - if (rbio->real_stripes - rbio->nr_data == 1) { - p_stripe = rbio->real_stripes - 1; - } else if (rbio->real_stripes - rbio->nr_data == 2) { - p_stripe = rbio->real_stripes - 2; - q_stripe = rbio->real_stripes - 1; - } else { - BUG(); - } - - /* at this point we either have a full stripe, - * or we've read the full stripe from the drive. - * recalculate the parity and write the new results. - * - * We're not allowed to add any new bios to the - * bio list here, anyone else that wants to - * change this stripe needs to do their own rmw. - */ - spin_lock_irq(&rbio->bio_list_lock); - set_bit(RBIO_RMW_LOCKED_BIT, &rbio->flags); - spin_unlock_irq(&rbio->bio_list_lock); - - atomic_set(&rbio->error, 0); - - /* - * now that we've set rmw_locked, run through the - * bio list one last time and map the page pointers - * - * We don't cache full rbios because we're assuming - * the higher layers are unlikely to use this area of - * the disk again soon. If they do use it again, - * hopefully they will send another full bio. - */ - index_rbio_pages(rbio); - if (!rbio_is_full(rbio)) - cache_rbio_pages(rbio); - else - clear_bit(RBIO_CACHE_READY_BIT, &rbio->flags); - - for (pagenr = 0; pagenr < rbio->stripe_npages; pagenr++) { - struct page *p; - /* first collect one page from each data stripe */ - for (stripe = 0; stripe < nr_data; stripe++) { - p = page_in_rbio(rbio, stripe, pagenr, 0); - pointers[stripe] = kmap(p); - } - - /* then add the parity stripe */ - p = rbio_pstripe_page(rbio, pagenr); - SetPageUptodate(p); - pointers[stripe++] = kmap(p); - - if (q_stripe != -1) { - - /* - * raid6, add the qstripe and call the - * library function to fill in our p/q - */ - p = rbio_qstripe_page(rbio, pagenr); - SetPageUptodate(p); - pointers[stripe++] = kmap(p); - - raid6_call.gen_syndrome(rbio->real_stripes, PAGE_SIZE, - pointers); - } else { - /* raid5 */ - memcpy(pointers[nr_data], pointers[0], PAGE_SIZE); - run_xor(pointers + 1, nr_data - 1, PAGE_SIZE); - } - - - for (stripe = 0; stripe < rbio->real_stripes; stripe++) - kunmap(page_in_rbio(rbio, stripe, pagenr, 0)); - } - - /* - * time to start writing. Make bios for everything from the - * higher layers (the bio_list in our rbio) and our p/q. Ignore - * everything else. - */ - for (stripe = 0; stripe < rbio->real_stripes; stripe++) { - for (pagenr = 0; pagenr < rbio->stripe_npages; pagenr++) { - struct page *page; - if (stripe < rbio->nr_data) { - page = page_in_rbio(rbio, stripe, pagenr, 1); - if (!page) - continue; - } else { - page = rbio_stripe_page(rbio, stripe, pagenr); - } - - ret = rbio_add_io_page(rbio, &bio_list, - page, stripe, pagenr, rbio->stripe_len); - if (ret) - goto cleanup; - } - } - - if (likely(!bbio->num_tgtdevs)) - goto write_data; - - for (stripe = 0; stripe < rbio->real_stripes; stripe++) { - if (!bbio->tgtdev_map[stripe]) - continue; - - for (pagenr = 0; pagenr < rbio->stripe_npages; pagenr++) { - struct page *page; - if (stripe < rbio->nr_data) { - page = page_in_rbio(rbio, stripe, pagenr, 1); - if (!page) - continue; - } else { - page = rbio_stripe_page(rbio, stripe, pagenr); - } - - ret = rbio_add_io_page(rbio, &bio_list, page, - rbio->bbio->tgtdev_map[stripe], - pagenr, rbio->stripe_len); - if (ret) - goto cleanup; - } - } - -write_data: - atomic_set(&rbio->stripes_pending, bio_list_size(&bio_list)); - BUG_ON(atomic_read(&rbio->stripes_pending) == 0); - - while (1) { - bio = bio_list_pop(&bio_list); - if (!bio) - break; - - bio->bi_private = rbio; - bio->bi_end_io = raid_write_end_io; - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); - - submit_bio(bio); - } - return; - -cleanup: - rbio_orig_end_io(rbio, -EIO); -} - -/* - * helper to find the stripe number for a given bio. Used to figure out which - * stripe has failed. This expects the bio to correspond to a physical disk, - * so it looks up based on physical sector numbers. - */ -static int find_bio_stripe(struct btrfs_raid_bio *rbio, - struct bio *bio) -{ - u64 physical = bio->bi_iter.bi_sector; - u64 stripe_start; - int i; - struct btrfs_bio_stripe *stripe; - - physical <<= 9; - - for (i = 0; i < rbio->bbio->num_stripes; i++) { - stripe = &rbio->bbio->stripes[i]; - stripe_start = stripe->physical; - if (physical >= stripe_start && - physical < stripe_start + rbio->stripe_len && - bio->bi_bdev == stripe->dev->bdev) { - return i; - } - } - return -1; -} - -/* - * helper to find the stripe number for a given - * bio (before mapping). Used to figure out which stripe has - * failed. This looks up based on logical block numbers. - */ -static int find_logical_bio_stripe(struct btrfs_raid_bio *rbio, - struct bio *bio) -{ - u64 logical = bio->bi_iter.bi_sector; - u64 stripe_start; - int i; - - logical <<= 9; - - for (i = 0; i < rbio->nr_data; i++) { - stripe_start = rbio->bbio->raid_map[i]; - if (logical >= stripe_start && - logical < stripe_start + rbio->stripe_len) { - return i; - } - } - return -1; -} - -/* - * returns -EIO if we had too many failures - */ -static int fail_rbio_index(struct btrfs_raid_bio *rbio, int failed) -{ - unsigned long flags; - int ret = 0; - - spin_lock_irqsave(&rbio->bio_list_lock, flags); - - /* we already know this stripe is bad, move on */ - if (rbio->faila == failed || rbio->failb == failed) - goto out; - - if (rbio->faila == -1) { - /* first failure on this rbio */ - rbio->faila = failed; - atomic_inc(&rbio->error); - } else if (rbio->failb == -1) { - /* second failure on this rbio */ - rbio->failb = failed; - atomic_inc(&rbio->error); - } else { - ret = -EIO; - } -out: - spin_unlock_irqrestore(&rbio->bio_list_lock, flags); - - return ret; -} - -/* - * helper to fail a stripe based on a physical disk - * bio. - */ -static int fail_bio_stripe(struct btrfs_raid_bio *rbio, - struct bio *bio) -{ - int failed = find_bio_stripe(rbio, bio); - - if (failed < 0) - return -EIO; - - return fail_rbio_index(rbio, failed); -} - -/* - * this sets each page in the bio uptodate. It should only be used on private - * rbio pages, nothing that comes in from the higher layers - */ -static void set_bio_pages_uptodate(struct bio *bio) -{ - int i; - struct page *p; - - for (i = 0; i < bio->bi_vcnt; i++) { - p = bio->bi_io_vec[i].bv_page; - SetPageUptodate(p); - } -} - -/* - * end io for the read phase of the rmw cycle. All the bios here are physical - * stripe bios we've read from the disk so we can recalculate the parity of the - * stripe. - * - * This will usually kick off finish_rmw once all the bios are read in, but it - * may trigger parity reconstruction if we had any errors along the way - */ -static void raid_rmw_end_io(struct bio *bio) -{ - struct btrfs_raid_bio *rbio = bio->bi_private; - - if (bio->bi_error) - fail_bio_stripe(rbio, bio); - else - set_bio_pages_uptodate(bio); - - bio_put(bio); - - if (!atomic_dec_and_test(&rbio->stripes_pending)) - return; - - if (atomic_read(&rbio->error) > rbio->bbio->max_errors) - goto cleanup; - - /* - * this will normally call finish_rmw to start our write - * but if there are any failed stripes we'll reconstruct - * from parity first - */ - validate_rbio_for_rmw(rbio); - return; - -cleanup: - - rbio_orig_end_io(rbio, -EIO); -} - -static void async_rmw_stripe(struct btrfs_raid_bio *rbio) -{ - btrfs_init_work(&rbio->work, btrfs_rmw_helper, - rmw_work, NULL, NULL); - - btrfs_queue_work(rbio->fs_info->rmw_workers, - &rbio->work); -} - -static void async_read_rebuild(struct btrfs_raid_bio *rbio) -{ - btrfs_init_work(&rbio->work, btrfs_rmw_helper, - read_rebuild_work, NULL, NULL); - - btrfs_queue_work(rbio->fs_info->rmw_workers, - &rbio->work); -} - -/* - * the stripe must be locked by the caller. It will - * unlock after all the writes are done - */ -static int raid56_rmw_stripe(struct btrfs_raid_bio *rbio) -{ - int bios_to_read = 0; - struct bio_list bio_list; - int ret; - int pagenr; - int stripe; - struct bio *bio; - - bio_list_init(&bio_list); - - ret = alloc_rbio_pages(rbio); - if (ret) - goto cleanup; - - index_rbio_pages(rbio); - - atomic_set(&rbio->error, 0); - /* - * build a list of bios to read all the missing parts of this - * stripe - */ - for (stripe = 0; stripe < rbio->nr_data; stripe++) { - for (pagenr = 0; pagenr < rbio->stripe_npages; pagenr++) { - struct page *page; - /* - * we want to find all the pages missing from - * the rbio and read them from the disk. If - * page_in_rbio finds a page in the bio list - * we don't need to read it off the stripe. - */ - page = page_in_rbio(rbio, stripe, pagenr, 1); - if (page) - continue; - - page = rbio_stripe_page(rbio, stripe, pagenr); - /* - * the bio cache may have handed us an uptodate - * page. If so, be happy and use it - */ - if (PageUptodate(page)) - continue; - - ret = rbio_add_io_page(rbio, &bio_list, page, - stripe, pagenr, rbio->stripe_len); - if (ret) - goto cleanup; - } - } - - bios_to_read = bio_list_size(&bio_list); - if (!bios_to_read) { - /* - * this can happen if others have merged with - * us, it means there is nothing left to read. - * But if there are missing devices it may not be - * safe to do the full stripe write yet. - */ - goto finish; - } - - /* - * the bbio may be freed once we submit the last bio. Make sure - * not to touch it after that - */ - atomic_set(&rbio->stripes_pending, bios_to_read); - while (1) { - bio = bio_list_pop(&bio_list); - if (!bio) - break; - - bio->bi_private = rbio; - bio->bi_end_io = raid_rmw_end_io; - bio_set_op_attrs(bio, REQ_OP_READ, 0); - - btrfs_bio_wq_end_io(rbio->fs_info, bio, - BTRFS_WQ_ENDIO_RAID56); - - submit_bio(bio); - } - /* the actual write will happen once the reads are done */ - return 0; - -cleanup: - rbio_orig_end_io(rbio, -EIO); - return -EIO; - -finish: - validate_rbio_for_rmw(rbio); - return 0; -} - -/* - * if the upper layers pass in a full stripe, we thank them by only allocating - * enough pages to hold the parity, and sending it all down quickly. - */ -static int full_stripe_write(struct btrfs_raid_bio *rbio) -{ - int ret; - - ret = alloc_rbio_parity_pages(rbio); - if (ret) { - __free_raid_bio(rbio); - return ret; - } - - ret = lock_stripe_add(rbio); - if (ret == 0) - finish_rmw(rbio); - return 0; -} - -/* - * partial stripe writes get handed over to async helpers. - * We're really hoping to merge a few more writes into this - * rbio before calculating new parity - */ -static int partial_stripe_write(struct btrfs_raid_bio *rbio) -{ - int ret; - - ret = lock_stripe_add(rbio); - if (ret == 0) - async_rmw_stripe(rbio); - return 0; -} - -/* - * sometimes while we were reading from the drive to - * recalculate parity, enough new bios come into create - * a full stripe. So we do a check here to see if we can - * go directly to finish_rmw - */ -static int __raid56_parity_write(struct btrfs_raid_bio *rbio) -{ - /* head off into rmw land if we don't have a full stripe */ - if (!rbio_is_full(rbio)) - return partial_stripe_write(rbio); - return full_stripe_write(rbio); -} - -/* - * We use plugging call backs to collect full stripes. - * Any time we get a partial stripe write while plugged - * we collect it into a list. When the unplug comes down, - * we sort the list by logical block number and merge - * everything we can into the same rbios - */ -struct btrfs_plug_cb { - struct blk_plug_cb cb; - struct btrfs_fs_info *info; - struct list_head rbio_list; - struct btrfs_work work; -}; - -/* - * rbios on the plug list are sorted for easier merging. - */ -static int plug_cmp(void *priv, struct list_head *a, struct list_head *b) -{ - struct btrfs_raid_bio *ra = container_of(a, struct btrfs_raid_bio, - plug_list); - struct btrfs_raid_bio *rb = container_of(b, struct btrfs_raid_bio, - plug_list); - u64 a_sector = ra->bio_list.head->bi_iter.bi_sector; - u64 b_sector = rb->bio_list.head->bi_iter.bi_sector; - - if (a_sector < b_sector) - return -1; - if (a_sector > b_sector) - return 1; - return 0; -} - -static void run_plug(struct btrfs_plug_cb *plug) -{ - struct btrfs_raid_bio *cur; - struct btrfs_raid_bio *last = NULL; - - /* - * sort our plug list then try to merge - * everything we can in hopes of creating full - * stripes. - */ - list_sort(NULL, &plug->rbio_list, plug_cmp); - while (!list_empty(&plug->rbio_list)) { - cur = list_entry(plug->rbio_list.next, - struct btrfs_raid_bio, plug_list); - list_del_init(&cur->plug_list); - - if (rbio_is_full(cur)) { - /* we have a full stripe, send it down */ - full_stripe_write(cur); - continue; - } - if (last) { - if (rbio_can_merge(last, cur)) { - merge_rbio(last, cur); - __free_raid_bio(cur); - continue; - - } - __raid56_parity_write(last); - } - last = cur; - } - if (last) { - __raid56_parity_write(last); - } - kfree(plug); -} - -/* - * if the unplug comes from schedule, we have to push the - * work off to a helper thread - */ -static void unplug_work(struct btrfs_work *work) -{ - struct btrfs_plug_cb *plug; - plug = container_of(work, struct btrfs_plug_cb, work); - run_plug(plug); -} - -static void btrfs_raid_unplug(struct blk_plug_cb *cb, bool from_schedule) -{ - struct btrfs_plug_cb *plug; - plug = container_of(cb, struct btrfs_plug_cb, cb); - - if (from_schedule) { - btrfs_init_work(&plug->work, btrfs_rmw_helper, - unplug_work, NULL, NULL); - btrfs_queue_work(plug->info->rmw_workers, - &plug->work); - return; - } - run_plug(plug); -} - -/* - * our main entry point for writes from the rest of the FS. - */ -int raid56_parity_write(struct btrfs_root *root, struct bio *bio, - struct btrfs_bio *bbio, u64 stripe_len) -{ - struct btrfs_raid_bio *rbio; - struct btrfs_plug_cb *plug = NULL; - struct blk_plug_cb *cb; - int ret; - - rbio = alloc_rbio(root, bbio, stripe_len); - if (IS_ERR(rbio)) { - btrfs_put_bbio(bbio); - return PTR_ERR(rbio); - } - bio_list_add(&rbio->bio_list, bio); - rbio->bio_list_bytes = bio->bi_iter.bi_size; - rbio->operation = BTRFS_RBIO_WRITE; - - btrfs_bio_counter_inc_noblocked(root->fs_info); - rbio->generic_bio_cnt = 1; - - /* - * don't plug on full rbios, just get them out the door - * as quickly as we can - */ - if (rbio_is_full(rbio)) { - ret = full_stripe_write(rbio); - if (ret) - btrfs_bio_counter_dec(root->fs_info); - return ret; - } - - cb = blk_check_plugged(btrfs_raid_unplug, root->fs_info, - sizeof(*plug)); - if (cb) { - plug = container_of(cb, struct btrfs_plug_cb, cb); - if (!plug->info) { - plug->info = root->fs_info; - INIT_LIST_HEAD(&plug->rbio_list); - } - list_add_tail(&rbio->plug_list, &plug->rbio_list); - ret = 0; - } else { - ret = __raid56_parity_write(rbio); - if (ret) - btrfs_bio_counter_dec(root->fs_info); - } - return ret; -} - -/* - * all parity reconstruction happens here. We've read in everything - * we can find from the drives and this does the heavy lifting of - * sorting the good from the bad. - */ -static void __raid_recover_end_io(struct btrfs_raid_bio *rbio) -{ - int pagenr, stripe; - void **pointers; - int faila = -1, failb = -1; - struct page *page; - int err; - int i; - - pointers = kcalloc(rbio->real_stripes, sizeof(void *), GFP_NOFS); - if (!pointers) { - err = -ENOMEM; - goto cleanup_io; - } - - faila = rbio->faila; - failb = rbio->failb; - - if (rbio->operation == BTRFS_RBIO_READ_REBUILD || - rbio->operation == BTRFS_RBIO_REBUILD_MISSING) { - spin_lock_irq(&rbio->bio_list_lock); - set_bit(RBIO_RMW_LOCKED_BIT, &rbio->flags); - spin_unlock_irq(&rbio->bio_list_lock); - } - - index_rbio_pages(rbio); - - for (pagenr = 0; pagenr < rbio->stripe_npages; pagenr++) { - /* - * Now we just use bitmap to mark the horizontal stripes in - * which we have data when doing parity scrub. - */ - if (rbio->operation == BTRFS_RBIO_PARITY_SCRUB && - !test_bit(pagenr, rbio->dbitmap)) - continue; - - /* setup our array of pointers with pages - * from each stripe - */ - for (stripe = 0; stripe < rbio->real_stripes; stripe++) { - /* - * if we're rebuilding a read, we have to use - * pages from the bio list - */ - if ((rbio->operation == BTRFS_RBIO_READ_REBUILD || - rbio->operation == BTRFS_RBIO_REBUILD_MISSING) && - (stripe == faila || stripe == failb)) { - page = page_in_rbio(rbio, stripe, pagenr, 0); - } else { - page = rbio_stripe_page(rbio, stripe, pagenr); - } - pointers[stripe] = kmap(page); - } - - /* all raid6 handling here */ - if (rbio->bbio->map_type & BTRFS_BLOCK_GROUP_RAID6) { - /* - * single failure, rebuild from parity raid5 - * style - */ - if (failb < 0) { - if (faila == rbio->nr_data) { - /* - * Just the P stripe has failed, without - * a bad data or Q stripe. - * TODO, we should redo the xor here. - */ - err = -EIO; - goto cleanup; - } - /* - * a single failure in raid6 is rebuilt - * in the pstripe code below - */ - goto pstripe; - } - - /* make sure our ps and qs are in order */ - if (faila > failb) { - int tmp = failb; - failb = faila; - faila = tmp; - } - - /* if the q stripe is failed, do a pstripe reconstruction - * from the xors. - * If both the q stripe and the P stripe are failed, we're - * here due to a crc mismatch and we can't give them the - * data they want - */ - if (rbio->bbio->raid_map[failb] == RAID6_Q_STRIPE) { - if (rbio->bbio->raid_map[faila] == - RAID5_P_STRIPE) { - err = -EIO; - goto cleanup; - } - /* - * otherwise we have one bad data stripe and - * a good P stripe. raid5! - */ - goto pstripe; - } - - if (rbio->bbio->raid_map[failb] == RAID5_P_STRIPE) { - raid6_datap_recov(rbio->real_stripes, - PAGE_SIZE, faila, pointers); - } else { - raid6_2data_recov(rbio->real_stripes, - PAGE_SIZE, faila, failb, - pointers); - } - } else { - void *p; - - /* rebuild from P stripe here (raid5 or raid6) */ - BUG_ON(failb != -1); -pstripe: - /* Copy parity block into failed block to start with */ - memcpy(pointers[faila], - pointers[rbio->nr_data], - PAGE_SIZE); - - /* rearrange the pointer array */ - p = pointers[faila]; - for (stripe = faila; stripe < rbio->nr_data - 1; stripe++) - pointers[stripe] = pointers[stripe + 1]; - pointers[rbio->nr_data - 1] = p; - - /* xor in the rest */ - run_xor(pointers, rbio->nr_data - 1, PAGE_SIZE); - } - /* if we're doing this rebuild as part of an rmw, go through - * and set all of our private rbio pages in the - * failed stripes as uptodate. This way finish_rmw will - * know they can be trusted. If this was a read reconstruction, - * other endio functions will fiddle the uptodate bits - */ - if (rbio->operation == BTRFS_RBIO_WRITE) { - for (i = 0; i < rbio->stripe_npages; i++) { - if (faila != -1) { - page = rbio_stripe_page(rbio, faila, i); - SetPageUptodate(page); - } - if (failb != -1) { - page = rbio_stripe_page(rbio, failb, i); - SetPageUptodate(page); - } - } - } - for (stripe = 0; stripe < rbio->real_stripes; stripe++) { - /* - * if we're rebuilding a read, we have to use - * pages from the bio list - */ - if ((rbio->operation == BTRFS_RBIO_READ_REBUILD || - rbio->operation == BTRFS_RBIO_REBUILD_MISSING) && - (stripe == faila || stripe == failb)) { - page = page_in_rbio(rbio, stripe, pagenr, 0); - } else { - page = rbio_stripe_page(rbio, stripe, pagenr); - } - kunmap(page); - } - } - - err = 0; -cleanup: - kfree(pointers); - -cleanup_io: - if (rbio->operation == BTRFS_RBIO_READ_REBUILD) { - if (err == 0) - cache_rbio_pages(rbio); - else - clear_bit(RBIO_CACHE_READY_BIT, &rbio->flags); - - rbio_orig_end_io(rbio, err); - } else if (rbio->operation == BTRFS_RBIO_REBUILD_MISSING) { - rbio_orig_end_io(rbio, err); - } else if (err == 0) { - rbio->faila = -1; - rbio->failb = -1; - - if (rbio->operation == BTRFS_RBIO_WRITE) - finish_rmw(rbio); - else if (rbio->operation == BTRFS_RBIO_PARITY_SCRUB) - finish_parity_scrub(rbio, 0); - else - BUG(); - } else { - rbio_orig_end_io(rbio, err); - } -} - -/* - * This is called only for stripes we've read from disk to - * reconstruct the parity. - */ -static void raid_recover_end_io(struct bio *bio) -{ - struct btrfs_raid_bio *rbio = bio->bi_private; - - /* - * we only read stripe pages off the disk, set them - * up to date if there were no errors - */ - if (bio->bi_error) - fail_bio_stripe(rbio, bio); - else - set_bio_pages_uptodate(bio); - bio_put(bio); - - if (!atomic_dec_and_test(&rbio->stripes_pending)) - return; - - if (atomic_read(&rbio->error) > rbio->bbio->max_errors) - rbio_orig_end_io(rbio, -EIO); - else - __raid_recover_end_io(rbio); -} - -/* - * reads everything we need off the disk to reconstruct - * the parity. endio handlers trigger final reconstruction - * when the IO is done. - * - * This is used both for reads from the higher layers and for - * parity construction required to finish a rmw cycle. - */ -static int __raid56_parity_recover(struct btrfs_raid_bio *rbio) -{ - int bios_to_read = 0; - struct bio_list bio_list; - int ret; - int pagenr; - int stripe; - struct bio *bio; - - bio_list_init(&bio_list); - - ret = alloc_rbio_pages(rbio); - if (ret) - goto cleanup; - - atomic_set(&rbio->error, 0); - - /* - * read everything that hasn't failed. Thanks to the - * stripe cache, it is possible that some or all of these - * pages are going to be uptodate. - */ - for (stripe = 0; stripe < rbio->real_stripes; stripe++) { - if (rbio->faila == stripe || rbio->failb == stripe) { - atomic_inc(&rbio->error); - continue; - } - - for (pagenr = 0; pagenr < rbio->stripe_npages; pagenr++) { - struct page *p; - - /* - * the rmw code may have already read this - * page in - */ - p = rbio_stripe_page(rbio, stripe, pagenr); - if (PageUptodate(p)) - continue; - - ret = rbio_add_io_page(rbio, &bio_list, - rbio_stripe_page(rbio, stripe, pagenr), - stripe, pagenr, rbio->stripe_len); - if (ret < 0) - goto cleanup; - } - } - - bios_to_read = bio_list_size(&bio_list); - if (!bios_to_read) { - /* - * we might have no bios to read just because the pages - * were up to date, or we might have no bios to read because - * the devices were gone. - */ - if (atomic_read(&rbio->error) <= rbio->bbio->max_errors) { - __raid_recover_end_io(rbio); - goto out; - } else { - goto cleanup; - } - } - - /* - * the bbio may be freed once we submit the last bio. Make sure - * not to touch it after that - */ - atomic_set(&rbio->stripes_pending, bios_to_read); - while (1) { - bio = bio_list_pop(&bio_list); - if (!bio) - break; - - bio->bi_private = rbio; - bio->bi_end_io = raid_recover_end_io; - bio_set_op_attrs(bio, REQ_OP_READ, 0); - - btrfs_bio_wq_end_io(rbio->fs_info, bio, - BTRFS_WQ_ENDIO_RAID56); - - submit_bio(bio); - } -out: - return 0; - -cleanup: - if (rbio->operation == BTRFS_RBIO_READ_REBUILD || - rbio->operation == BTRFS_RBIO_REBUILD_MISSING) - rbio_orig_end_io(rbio, -EIO); - return -EIO; -} - -/* - * the main entry point for reads from the higher layers. This - * is really only called when the normal read path had a failure, - * so we assume the bio they send down corresponds to a failed part - * of the drive. - */ -int raid56_parity_recover(struct btrfs_root *root, struct bio *bio, - struct btrfs_bio *bbio, u64 stripe_len, - int mirror_num, int generic_io) -{ - struct btrfs_raid_bio *rbio; - int ret; - - rbio = alloc_rbio(root, bbio, stripe_len); - if (IS_ERR(rbio)) { - if (generic_io) - btrfs_put_bbio(bbio); - return PTR_ERR(rbio); - } - - rbio->operation = BTRFS_RBIO_READ_REBUILD; - bio_list_add(&rbio->bio_list, bio); - rbio->bio_list_bytes = bio->bi_iter.bi_size; - - rbio->faila = find_logical_bio_stripe(rbio, bio); - if (rbio->faila == -1) { - btrfs_warn(root->fs_info, - "%s could not find the bad stripe in raid56 so that we cannot recover any more (bio has logical %llu len %llu, bbio has map_type %llu)", - __func__, (u64)bio->bi_iter.bi_sector << 9, - (u64)bio->bi_iter.bi_size, bbio->map_type); - if (generic_io) - btrfs_put_bbio(bbio); - kfree(rbio); - return -EIO; - } - - if (generic_io) { - btrfs_bio_counter_inc_noblocked(root->fs_info); - rbio->generic_bio_cnt = 1; - } else { - btrfs_get_bbio(bbio); - } - - /* - * reconstruct from the q stripe if they are - * asking for mirror 3 - */ - if (mirror_num == 3) - rbio->failb = rbio->real_stripes - 2; - - ret = lock_stripe_add(rbio); - - /* - * __raid56_parity_recover will end the bio with - * any errors it hits. We don't want to return - * its error value up the stack because our caller - * will end up calling bio_endio with any nonzero - * return - */ - if (ret == 0) - __raid56_parity_recover(rbio); - /* - * our rbio has been added to the list of - * rbios that will be handled after the - * currently lock owner is done - */ - return 0; - -} - -static void rmw_work(struct btrfs_work *work) -{ - struct btrfs_raid_bio *rbio; - - rbio = container_of(work, struct btrfs_raid_bio, work); - raid56_rmw_stripe(rbio); -} - -static void read_rebuild_work(struct btrfs_work *work) -{ - struct btrfs_raid_bio *rbio; - - rbio = container_of(work, struct btrfs_raid_bio, work); - __raid56_parity_recover(rbio); -} - -/* - * The following code is used to scrub/replace the parity stripe - * - * Note: We need make sure all the pages that add into the scrub/replace - * raid bio are correct and not be changed during the scrub/replace. That - * is those pages just hold metadata or file data with checksum. - */ - -struct btrfs_raid_bio * -raid56_parity_alloc_scrub_rbio(struct btrfs_root *root, struct bio *bio, - struct btrfs_bio *bbio, u64 stripe_len, - struct btrfs_device *scrub_dev, - unsigned long *dbitmap, int stripe_nsectors) -{ - struct btrfs_raid_bio *rbio; - int i; - - rbio = alloc_rbio(root, bbio, stripe_len); - if (IS_ERR(rbio)) - return NULL; - bio_list_add(&rbio->bio_list, bio); - /* - * This is a special bio which is used to hold the completion handler - * and make the scrub rbio is similar to the other types - */ - ASSERT(!bio->bi_iter.bi_size); - rbio->operation = BTRFS_RBIO_PARITY_SCRUB; - - for (i = 0; i < rbio->real_stripes; i++) { - if (bbio->stripes[i].dev == scrub_dev) { - rbio->scrubp = i; - break; - } - } - - /* Now we just support the sectorsize equals to page size */ - ASSERT(root->sectorsize == PAGE_SIZE); - ASSERT(rbio->stripe_npages == stripe_nsectors); - bitmap_copy(rbio->dbitmap, dbitmap, stripe_nsectors); - - return rbio; -} - -/* Used for both parity scrub and missing. */ -void raid56_add_scrub_pages(struct btrfs_raid_bio *rbio, struct page *page, - u64 logical) -{ - int stripe_offset; - int index; - - ASSERT(logical >= rbio->bbio->raid_map[0]); - ASSERT(logical + PAGE_SIZE <= rbio->bbio->raid_map[0] + - rbio->stripe_len * rbio->nr_data); - stripe_offset = (int)(logical - rbio->bbio->raid_map[0]); - index = stripe_offset >> PAGE_SHIFT; - rbio->bio_pages[index] = page; -} - -/* - * We just scrub the parity that we have correct data on the same horizontal, - * so we needn't allocate all pages for all the stripes. - */ -static int alloc_rbio_essential_pages(struct btrfs_raid_bio *rbio) -{ - int i; - int bit; - int index; - struct page *page; - - for_each_set_bit(bit, rbio->dbitmap, rbio->stripe_npages) { - for (i = 0; i < rbio->real_stripes; i++) { - index = i * rbio->stripe_npages + bit; - if (rbio->stripe_pages[index]) - continue; - - page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); - if (!page) - return -ENOMEM; - rbio->stripe_pages[index] = page; - } - } - return 0; -} - -static noinline void finish_parity_scrub(struct btrfs_raid_bio *rbio, - int need_check) -{ - struct btrfs_bio *bbio = rbio->bbio; - void *pointers[rbio->real_stripes]; - DECLARE_BITMAP(pbitmap, rbio->stripe_npages); - int nr_data = rbio->nr_data; - int stripe; - int pagenr; - int p_stripe = -1; - int q_stripe = -1; - struct page *p_page = NULL; - struct page *q_page = NULL; - struct bio_list bio_list; - struct bio *bio; - int is_replace = 0; - int ret; - - bio_list_init(&bio_list); - - if (rbio->real_stripes - rbio->nr_data == 1) { - p_stripe = rbio->real_stripes - 1; - } else if (rbio->real_stripes - rbio->nr_data == 2) { - p_stripe = rbio->real_stripes - 2; - q_stripe = rbio->real_stripes - 1; - } else { - BUG(); - } - - if (bbio->num_tgtdevs && bbio->tgtdev_map[rbio->scrubp]) { - is_replace = 1; - bitmap_copy(pbitmap, rbio->dbitmap, rbio->stripe_npages); - } - - /* - * Because the higher layers(scrubber) are unlikely to - * use this area of the disk again soon, so don't cache - * it. - */ - clear_bit(RBIO_CACHE_READY_BIT, &rbio->flags); - - if (!need_check) - goto writeback; - - p_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); - if (!p_page) - goto cleanup; - SetPageUptodate(p_page); - - if (q_stripe != -1) { - q_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); - if (!q_page) { - __free_page(p_page); - goto cleanup; - } - SetPageUptodate(q_page); - } - - atomic_set(&rbio->error, 0); - - for_each_set_bit(pagenr, rbio->dbitmap, rbio->stripe_npages) { - struct page *p; - void *parity; - /* first collect one page from each data stripe */ - for (stripe = 0; stripe < nr_data; stripe++) { - p = page_in_rbio(rbio, stripe, pagenr, 0); - pointers[stripe] = kmap(p); - } - - /* then add the parity stripe */ - pointers[stripe++] = kmap(p_page); - - if (q_stripe != -1) { - - /* - * raid6, add the qstripe and call the - * library function to fill in our p/q - */ - pointers[stripe++] = kmap(q_page); - - raid6_call.gen_syndrome(rbio->real_stripes, PAGE_SIZE, - pointers); - } else { - /* raid5 */ - memcpy(pointers[nr_data], pointers[0], PAGE_SIZE); - run_xor(pointers + 1, nr_data - 1, PAGE_SIZE); - } - - /* Check scrubbing parity and repair it */ - p = rbio_stripe_page(rbio, rbio->scrubp, pagenr); - parity = kmap(p); - if (memcmp(parity, pointers[rbio->scrubp], PAGE_SIZE)) - memcpy(parity, pointers[rbio->scrubp], PAGE_SIZE); - else - /* Parity is right, needn't writeback */ - bitmap_clear(rbio->dbitmap, pagenr, 1); - kunmap(p); - - for (stripe = 0; stripe < rbio->real_stripes; stripe++) - kunmap(page_in_rbio(rbio, stripe, pagenr, 0)); - } - - __free_page(p_page); - if (q_page) - __free_page(q_page); - -writeback: - /* - * time to start writing. Make bios for everything from the - * higher layers (the bio_list in our rbio) and our p/q. Ignore - * everything else. - */ - for_each_set_bit(pagenr, rbio->dbitmap, rbio->stripe_npages) { - struct page *page; - - page = rbio_stripe_page(rbio, rbio->scrubp, pagenr); - ret = rbio_add_io_page(rbio, &bio_list, - page, rbio->scrubp, pagenr, rbio->stripe_len); - if (ret) - goto cleanup; - } - - if (!is_replace) - goto submit_write; - - for_each_set_bit(pagenr, pbitmap, rbio->stripe_npages) { - struct page *page; - - page = rbio_stripe_page(rbio, rbio->scrubp, pagenr); - ret = rbio_add_io_page(rbio, &bio_list, page, - bbio->tgtdev_map[rbio->scrubp], - pagenr, rbio->stripe_len); - if (ret) - goto cleanup; - } - -submit_write: - nr_data = bio_list_size(&bio_list); - if (!nr_data) { - /* Every parity is right */ - rbio_orig_end_io(rbio, 0); - return; - } - - atomic_set(&rbio->stripes_pending, nr_data); - - while (1) { - bio = bio_list_pop(&bio_list); - if (!bio) - break; - - bio->bi_private = rbio; - bio->bi_end_io = raid_write_end_io; - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); - - submit_bio(bio); - } - return; - -cleanup: - rbio_orig_end_io(rbio, -EIO); -} - -static inline int is_data_stripe(struct btrfs_raid_bio *rbio, int stripe) -{ - if (stripe >= 0 && stripe < rbio->nr_data) - return 1; - return 0; -} - -/* - * While we're doing the parity check and repair, we could have errors - * in reading pages off the disk. This checks for errors and if we're - * not able to read the page it'll trigger parity reconstruction. The - * parity scrub will be finished after we've reconstructed the failed - * stripes - */ -static void validate_rbio_for_parity_scrub(struct btrfs_raid_bio *rbio) -{ - if (atomic_read(&rbio->error) > rbio->bbio->max_errors) - goto cleanup; - - if (rbio->faila >= 0 || rbio->failb >= 0) { - int dfail = 0, failp = -1; - - if (is_data_stripe(rbio, rbio->faila)) - dfail++; - else if (is_parity_stripe(rbio->faila)) - failp = rbio->faila; - - if (is_data_stripe(rbio, rbio->failb)) - dfail++; - else if (is_parity_stripe(rbio->failb)) - failp = rbio->failb; - - /* - * Because we can not use a scrubbing parity to repair - * the data, so the capability of the repair is declined. - * (In the case of RAID5, we can not repair anything) - */ - if (dfail > rbio->bbio->max_errors - 1) - goto cleanup; - - /* - * If all data is good, only parity is correctly, just - * repair the parity. - */ - if (dfail == 0) { - finish_parity_scrub(rbio, 0); - return; - } - - /* - * Here means we got one corrupted data stripe and one - * corrupted parity on RAID6, if the corrupted parity - * is scrubbing parity, luckily, use the other one to repair - * the data, or we can not repair the data stripe. - */ - if (failp != rbio->scrubp) - goto cleanup; - - __raid_recover_end_io(rbio); - } else { - finish_parity_scrub(rbio, 1); - } - return; - -cleanup: - rbio_orig_end_io(rbio, -EIO); -} - -/* - * end io for the read phase of the rmw cycle. All the bios here are physical - * stripe bios we've read from the disk so we can recalculate the parity of the - * stripe. - * - * This will usually kick off finish_rmw once all the bios are read in, but it - * may trigger parity reconstruction if we had any errors along the way - */ -static void raid56_parity_scrub_end_io(struct bio *bio) -{ - struct btrfs_raid_bio *rbio = bio->bi_private; - - if (bio->bi_error) - fail_bio_stripe(rbio, bio); - else - set_bio_pages_uptodate(bio); - - bio_put(bio); - - if (!atomic_dec_and_test(&rbio->stripes_pending)) - return; - - /* - * this will normally call finish_rmw to start our write - * but if there are any failed stripes we'll reconstruct - * from parity first - */ - validate_rbio_for_parity_scrub(rbio); -} - -static void raid56_parity_scrub_stripe(struct btrfs_raid_bio *rbio) -{ - int bios_to_read = 0; - struct bio_list bio_list; - int ret; - int pagenr; - int stripe; - struct bio *bio; - - ret = alloc_rbio_essential_pages(rbio); - if (ret) - goto cleanup; - - bio_list_init(&bio_list); - - atomic_set(&rbio->error, 0); - /* - * build a list of bios to read all the missing parts of this - * stripe - */ - for (stripe = 0; stripe < rbio->real_stripes; stripe++) { - for_each_set_bit(pagenr, rbio->dbitmap, rbio->stripe_npages) { - struct page *page; - /* - * we want to find all the pages missing from - * the rbio and read them from the disk. If - * page_in_rbio finds a page in the bio list - * we don't need to read it off the stripe. - */ - page = page_in_rbio(rbio, stripe, pagenr, 1); - if (page) - continue; - - page = rbio_stripe_page(rbio, stripe, pagenr); - /* - * the bio cache may have handed us an uptodate - * page. If so, be happy and use it - */ - if (PageUptodate(page)) - continue; - - ret = rbio_add_io_page(rbio, &bio_list, page, - stripe, pagenr, rbio->stripe_len); - if (ret) - goto cleanup; - } - } - - bios_to_read = bio_list_size(&bio_list); - if (!bios_to_read) { - /* - * this can happen if others have merged with - * us, it means there is nothing left to read. - * But if there are missing devices it may not be - * safe to do the full stripe write yet. - */ - goto finish; - } - - /* - * the bbio may be freed once we submit the last bio. Make sure - * not to touch it after that - */ - atomic_set(&rbio->stripes_pending, bios_to_read); - while (1) { - bio = bio_list_pop(&bio_list); - if (!bio) - break; - - bio->bi_private = rbio; - bio->bi_end_io = raid56_parity_scrub_end_io; - bio_set_op_attrs(bio, REQ_OP_READ, 0); - - btrfs_bio_wq_end_io(rbio->fs_info, bio, - BTRFS_WQ_ENDIO_RAID56); - - submit_bio(bio); - } - /* the actual write will happen once the reads are done */ - return; - -cleanup: - rbio_orig_end_io(rbio, -EIO); - return; - -finish: - validate_rbio_for_parity_scrub(rbio); -} - -static void scrub_parity_work(struct btrfs_work *work) -{ - struct btrfs_raid_bio *rbio; - - rbio = container_of(work, struct btrfs_raid_bio, work); - raid56_parity_scrub_stripe(rbio); -} - -static void async_scrub_parity(struct btrfs_raid_bio *rbio) -{ - btrfs_init_work(&rbio->work, btrfs_rmw_helper, - scrub_parity_work, NULL, NULL); - - btrfs_queue_work(rbio->fs_info->rmw_workers, - &rbio->work); -} - -void raid56_parity_submit_scrub_rbio(struct btrfs_raid_bio *rbio) -{ - if (!lock_stripe_add(rbio)) - async_scrub_parity(rbio); -} - -/* The following code is used for dev replace of a missing RAID 5/6 device. */ - -struct btrfs_raid_bio * -raid56_alloc_missing_rbio(struct btrfs_root *root, struct bio *bio, - struct btrfs_bio *bbio, u64 length) -{ - struct btrfs_raid_bio *rbio; - - rbio = alloc_rbio(root, bbio, length); - if (IS_ERR(rbio)) - return NULL; - - rbio->operation = BTRFS_RBIO_REBUILD_MISSING; - bio_list_add(&rbio->bio_list, bio); - /* - * This is a special bio which is used to hold the completion handler - * and make the scrub rbio is similar to the other types - */ - ASSERT(!bio->bi_iter.bi_size); - - rbio->faila = find_logical_bio_stripe(rbio, bio); - if (rbio->faila == -1) { - BUG(); - kfree(rbio); - return NULL; - } - - return rbio; -} - -static void missing_raid56_work(struct btrfs_work *work) -{ - struct btrfs_raid_bio *rbio; - - rbio = container_of(work, struct btrfs_raid_bio, work); - __raid56_parity_recover(rbio); -} - -static void async_missing_raid56(struct btrfs_raid_bio *rbio) -{ - btrfs_init_work(&rbio->work, btrfs_rmw_helper, - missing_raid56_work, NULL, NULL); - - btrfs_queue_work(rbio->fs_info->rmw_workers, &rbio->work); -} - -void raid56_submit_missing_rbio(struct btrfs_raid_bio *rbio) -{ - if (!lock_stripe_add(rbio)) - async_missing_raid56(rbio); -} diff --git a/src/linux/fs/btrfs/raid56.h b/src/linux/fs/btrfs/raid56.h deleted file mode 100644 index 8b69469..0000000 --- a/src/linux/fs/btrfs/raid56.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2012 Fusion-io All rights reserved. - * Copyright (C) 2012 Intel Corp. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __BTRFS_RAID56__ -#define __BTRFS_RAID56__ -static inline int nr_parity_stripes(struct map_lookup *map) -{ - if (map->type & BTRFS_BLOCK_GROUP_RAID5) - return 1; - else if (map->type & BTRFS_BLOCK_GROUP_RAID6) - return 2; - else - return 0; -} - -static inline int nr_data_stripes(struct map_lookup *map) -{ - return map->num_stripes - nr_parity_stripes(map); -} -#define RAID5_P_STRIPE ((u64)-2) -#define RAID6_Q_STRIPE ((u64)-1) - -#define is_parity_stripe(x) (((x) == RAID5_P_STRIPE) || \ - ((x) == RAID6_Q_STRIPE)) - -struct btrfs_raid_bio; -struct btrfs_device; - -int raid56_parity_recover(struct btrfs_root *root, struct bio *bio, - struct btrfs_bio *bbio, u64 stripe_len, - int mirror_num, int generic_io); -int raid56_parity_write(struct btrfs_root *root, struct bio *bio, - struct btrfs_bio *bbio, u64 stripe_len); - -void raid56_add_scrub_pages(struct btrfs_raid_bio *rbio, struct page *page, - u64 logical); - -struct btrfs_raid_bio * -raid56_parity_alloc_scrub_rbio(struct btrfs_root *root, struct bio *bio, - struct btrfs_bio *bbio, u64 stripe_len, - struct btrfs_device *scrub_dev, - unsigned long *dbitmap, int stripe_nsectors); -void raid56_parity_submit_scrub_rbio(struct btrfs_raid_bio *rbio); - -struct btrfs_raid_bio * -raid56_alloc_missing_rbio(struct btrfs_root *root, struct bio *bio, - struct btrfs_bio *bbio, u64 length); -void raid56_submit_missing_rbio(struct btrfs_raid_bio *rbio); - -int btrfs_alloc_stripe_hash_table(struct btrfs_fs_info *info); -void btrfs_free_stripe_hash_table(struct btrfs_fs_info *info); -#endif diff --git a/src/linux/fs/btrfs/rcu-string.h b/src/linux/fs/btrfs/rcu-string.h deleted file mode 100644 index 9e111e4..0000000 --- a/src/linux/fs/btrfs/rcu-string.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2012 Red Hat. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -struct rcu_string { - struct rcu_head rcu; - char str[0]; -}; - -static inline struct rcu_string *rcu_string_strdup(const char *src, gfp_t mask) -{ - size_t len = strlen(src) + 1; - struct rcu_string *ret = kzalloc(sizeof(struct rcu_string) + - (len * sizeof(char)), mask); - if (!ret) - return ret; - strncpy(ret->str, src, len); - return ret; -} - -static inline void rcu_string_free(struct rcu_string *str) -{ - if (str) - kfree_rcu(str, rcu); -} - -#define printk_in_rcu(fmt, ...) do { \ - rcu_read_lock(); \ - printk(fmt, __VA_ARGS__); \ - rcu_read_unlock(); \ -} while (0) - -#define printk_ratelimited_in_rcu(fmt, ...) do { \ - rcu_read_lock(); \ - printk_ratelimited(fmt, __VA_ARGS__); \ - rcu_read_unlock(); \ -} while (0) - -#define rcu_str_deref(rcu_str) ({ \ - struct rcu_string *__str = rcu_dereference(rcu_str); \ - __str->str; \ -}) diff --git a/src/linux/fs/btrfs/reada.c b/src/linux/fs/btrfs/reada.c deleted file mode 100644 index 75bab76..0000000 --- a/src/linux/fs/btrfs/reada.c +++ /dev/null @@ -1,996 +0,0 @@ -/* - * Copyright (C) 2011 STRATO. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "ctree.h" -#include "volumes.h" -#include "disk-io.h" -#include "transaction.h" -#include "dev-replace.h" - -#undef DEBUG - -/* - * This is the implementation for the generic read ahead framework. - * - * To trigger a readahead, btrfs_reada_add must be called. It will start - * a read ahead for the given range [start, end) on tree root. The returned - * handle can either be used to wait on the readahead to finish - * (btrfs_reada_wait), or to send it to the background (btrfs_reada_detach). - * - * The read ahead works as follows: - * On btrfs_reada_add, the root of the tree is inserted into a radix_tree. - * reada_start_machine will then search for extents to prefetch and trigger - * some reads. When a read finishes for a node, all contained node/leaf - * pointers that lie in the given range will also be enqueued. The reads will - * be triggered in sequential order, thus giving a big win over a naive - * enumeration. It will also make use of multi-device layouts. Each disk - * will have its on read pointer and all disks will by utilized in parallel. - * Also will no two disks read both sides of a mirror simultaneously, as this - * would waste seeking capacity. Instead both disks will read different parts - * of the filesystem. - * Any number of readaheads can be started in parallel. The read order will be - * determined globally, i.e. 2 parallel readaheads will normally finish faster - * than the 2 started one after another. - */ - -#define MAX_IN_FLIGHT 6 - -struct reada_extctl { - struct list_head list; - struct reada_control *rc; - u64 generation; -}; - -struct reada_extent { - u64 logical; - struct btrfs_key top; - int err; - struct list_head extctl; - int refcnt; - spinlock_t lock; - struct reada_zone *zones[BTRFS_MAX_MIRRORS]; - int nzones; - int scheduled; -}; - -struct reada_zone { - u64 start; - u64 end; - u64 elems; - struct list_head list; - spinlock_t lock; - int locked; - struct btrfs_device *device; - struct btrfs_device *devs[BTRFS_MAX_MIRRORS]; /* full list, incl - * self */ - int ndevs; - struct kref refcnt; -}; - -struct reada_machine_work { - struct btrfs_work work; - struct btrfs_fs_info *fs_info; -}; - -static void reada_extent_put(struct btrfs_fs_info *, struct reada_extent *); -static void reada_control_release(struct kref *kref); -static void reada_zone_release(struct kref *kref); -static void reada_start_machine(struct btrfs_fs_info *fs_info); -static void __reada_start_machine(struct btrfs_fs_info *fs_info); - -static int reada_add_block(struct reada_control *rc, u64 logical, - struct btrfs_key *top, u64 generation); - -/* recurses */ -/* in case of err, eb might be NULL */ -static void __readahead_hook(struct btrfs_fs_info *fs_info, - struct reada_extent *re, struct extent_buffer *eb, - u64 start, int err) -{ - int level = 0; - int nritems; - int i; - u64 bytenr; - u64 generation; - struct list_head list; - - if (eb) - level = btrfs_header_level(eb); - - spin_lock(&re->lock); - /* - * just take the full list from the extent. afterwards we - * don't need the lock anymore - */ - list_replace_init(&re->extctl, &list); - re->scheduled = 0; - spin_unlock(&re->lock); - - /* - * this is the error case, the extent buffer has not been - * read correctly. We won't access anything from it and - * just cleanup our data structures. Effectively this will - * cut the branch below this node from read ahead. - */ - if (err) - goto cleanup; - - /* - * FIXME: currently we just set nritems to 0 if this is a leaf, - * effectively ignoring the content. In a next step we could - * trigger more readahead depending from the content, e.g. - * fetch the checksums for the extents in the leaf. - */ - if (!level) - goto cleanup; - - nritems = btrfs_header_nritems(eb); - generation = btrfs_header_generation(eb); - for (i = 0; i < nritems; i++) { - struct reada_extctl *rec; - u64 n_gen; - struct btrfs_key key; - struct btrfs_key next_key; - - btrfs_node_key_to_cpu(eb, &key, i); - if (i + 1 < nritems) - btrfs_node_key_to_cpu(eb, &next_key, i + 1); - else - next_key = re->top; - bytenr = btrfs_node_blockptr(eb, i); - n_gen = btrfs_node_ptr_generation(eb, i); - - list_for_each_entry(rec, &list, list) { - struct reada_control *rc = rec->rc; - - /* - * if the generation doesn't match, just ignore this - * extctl. This will probably cut off a branch from - * prefetch. Alternatively one could start a new (sub-) - * prefetch for this branch, starting again from root. - * FIXME: move the generation check out of this loop - */ -#ifdef DEBUG - if (rec->generation != generation) { - btrfs_debug(fs_info, - "generation mismatch for (%llu,%d,%llu) %llu != %llu", - key.objectid, key.type, key.offset, - rec->generation, generation); - } -#endif - if (rec->generation == generation && - btrfs_comp_cpu_keys(&key, &rc->key_end) < 0 && - btrfs_comp_cpu_keys(&next_key, &rc->key_start) > 0) - reada_add_block(rc, bytenr, &next_key, n_gen); - } - } - -cleanup: - /* - * free extctl records - */ - while (!list_empty(&list)) { - struct reada_control *rc; - struct reada_extctl *rec; - - rec = list_first_entry(&list, struct reada_extctl, list); - list_del(&rec->list); - rc = rec->rc; - kfree(rec); - - kref_get(&rc->refcnt); - if (atomic_dec_and_test(&rc->elems)) { - kref_put(&rc->refcnt, reada_control_release); - wake_up(&rc->wait); - } - kref_put(&rc->refcnt, reada_control_release); - - reada_extent_put(fs_info, re); /* one ref for each entry */ - } - - return; -} - -/* - * start is passed separately in case eb in NULL, which may be the case with - * failed I/O - */ -int btree_readahead_hook(struct btrfs_fs_info *fs_info, - struct extent_buffer *eb, u64 start, int err) -{ - int ret = 0; - struct reada_extent *re; - - /* find extent */ - spin_lock(&fs_info->reada_lock); - re = radix_tree_lookup(&fs_info->reada_tree, - start >> PAGE_SHIFT); - if (re) - re->refcnt++; - spin_unlock(&fs_info->reada_lock); - if (!re) { - ret = -1; - goto start_machine; - } - - __readahead_hook(fs_info, re, eb, start, err); - reada_extent_put(fs_info, re); /* our ref */ - -start_machine: - reada_start_machine(fs_info); - return ret; -} - -static struct reada_zone *reada_find_zone(struct btrfs_fs_info *fs_info, - struct btrfs_device *dev, u64 logical, - struct btrfs_bio *bbio) -{ - int ret; - struct reada_zone *zone; - struct btrfs_block_group_cache *cache = NULL; - u64 start; - u64 end; - int i; - - zone = NULL; - spin_lock(&fs_info->reada_lock); - ret = radix_tree_gang_lookup(&dev->reada_zones, (void **)&zone, - logical >> PAGE_SHIFT, 1); - if (ret == 1 && logical >= zone->start && logical <= zone->end) { - kref_get(&zone->refcnt); - spin_unlock(&fs_info->reada_lock); - return zone; - } - - spin_unlock(&fs_info->reada_lock); - - cache = btrfs_lookup_block_group(fs_info, logical); - if (!cache) - return NULL; - - start = cache->key.objectid; - end = start + cache->key.offset - 1; - btrfs_put_block_group(cache); - - zone = kzalloc(sizeof(*zone), GFP_KERNEL); - if (!zone) - return NULL; - - zone->start = start; - zone->end = end; - INIT_LIST_HEAD(&zone->list); - spin_lock_init(&zone->lock); - zone->locked = 0; - kref_init(&zone->refcnt); - zone->elems = 0; - zone->device = dev; /* our device always sits at index 0 */ - for (i = 0; i < bbio->num_stripes; ++i) { - /* bounds have already been checked */ - zone->devs[i] = bbio->stripes[i].dev; - } - zone->ndevs = bbio->num_stripes; - - spin_lock(&fs_info->reada_lock); - ret = radix_tree_insert(&dev->reada_zones, - (unsigned long)(zone->end >> PAGE_SHIFT), - zone); - - if (ret == -EEXIST) { - kfree(zone); - ret = radix_tree_gang_lookup(&dev->reada_zones, (void **)&zone, - logical >> PAGE_SHIFT, 1); - if (ret == 1 && logical >= zone->start && logical <= zone->end) - kref_get(&zone->refcnt); - else - zone = NULL; - } - spin_unlock(&fs_info->reada_lock); - - return zone; -} - -static struct reada_extent *reada_find_extent(struct btrfs_root *root, - u64 logical, - struct btrfs_key *top) -{ - int ret; - struct reada_extent *re = NULL; - struct reada_extent *re_exist = NULL; - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_bio *bbio = NULL; - struct btrfs_device *dev; - struct btrfs_device *prev_dev; - u32 blocksize; - u64 length; - int real_stripes; - int nzones = 0; - unsigned long index = logical >> PAGE_SHIFT; - int dev_replace_is_ongoing; - int have_zone = 0; - - spin_lock(&fs_info->reada_lock); - re = radix_tree_lookup(&fs_info->reada_tree, index); - if (re) - re->refcnt++; - spin_unlock(&fs_info->reada_lock); - - if (re) - return re; - - re = kzalloc(sizeof(*re), GFP_KERNEL); - if (!re) - return NULL; - - blocksize = root->nodesize; - re->logical = logical; - re->top = *top; - INIT_LIST_HEAD(&re->extctl); - spin_lock_init(&re->lock); - re->refcnt = 1; - - /* - * map block - */ - length = blocksize; - ret = btrfs_map_block(fs_info, REQ_GET_READ_MIRRORS, logical, &length, - &bbio, 0); - if (ret || !bbio || length < blocksize) - goto error; - - if (bbio->num_stripes > BTRFS_MAX_MIRRORS) { - btrfs_err(root->fs_info, - "readahead: more than %d copies not supported", - BTRFS_MAX_MIRRORS); - goto error; - } - - real_stripes = bbio->num_stripes - bbio->num_tgtdevs; - for (nzones = 0; nzones < real_stripes; ++nzones) { - struct reada_zone *zone; - - dev = bbio->stripes[nzones].dev; - - /* cannot read ahead on missing device. */ - if (!dev->bdev) - continue; - - zone = reada_find_zone(fs_info, dev, logical, bbio); - if (!zone) - continue; - - re->zones[re->nzones++] = zone; - spin_lock(&zone->lock); - if (!zone->elems) - kref_get(&zone->refcnt); - ++zone->elems; - spin_unlock(&zone->lock); - spin_lock(&fs_info->reada_lock); - kref_put(&zone->refcnt, reada_zone_release); - spin_unlock(&fs_info->reada_lock); - } - if (re->nzones == 0) { - /* not a single zone found, error and out */ - goto error; - } - - /* insert extent in reada_tree + all per-device trees, all or nothing */ - btrfs_dev_replace_lock(&fs_info->dev_replace, 0); - spin_lock(&fs_info->reada_lock); - ret = radix_tree_insert(&fs_info->reada_tree, index, re); - if (ret == -EEXIST) { - re_exist = radix_tree_lookup(&fs_info->reada_tree, index); - BUG_ON(!re_exist); - re_exist->refcnt++; - spin_unlock(&fs_info->reada_lock); - btrfs_dev_replace_unlock(&fs_info->dev_replace, 0); - goto error; - } - if (ret) { - spin_unlock(&fs_info->reada_lock); - btrfs_dev_replace_unlock(&fs_info->dev_replace, 0); - goto error; - } - prev_dev = NULL; - dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing( - &fs_info->dev_replace); - for (nzones = 0; nzones < re->nzones; ++nzones) { - dev = re->zones[nzones]->device; - - if (dev == prev_dev) { - /* - * in case of DUP, just add the first zone. As both - * are on the same device, there's nothing to gain - * from adding both. - * Also, it wouldn't work, as the tree is per device - * and adding would fail with EEXIST - */ - continue; - } - if (!dev->bdev) - continue; - - if (dev_replace_is_ongoing && - dev == fs_info->dev_replace.tgtdev) { - /* - * as this device is selected for reading only as - * a last resort, skip it for read ahead. - */ - continue; - } - prev_dev = dev; - ret = radix_tree_insert(&dev->reada_extents, index, re); - if (ret) { - while (--nzones >= 0) { - dev = re->zones[nzones]->device; - BUG_ON(dev == NULL); - /* ignore whether the entry was inserted */ - radix_tree_delete(&dev->reada_extents, index); - } - BUG_ON(fs_info == NULL); - radix_tree_delete(&fs_info->reada_tree, index); - spin_unlock(&fs_info->reada_lock); - btrfs_dev_replace_unlock(&fs_info->dev_replace, 0); - goto error; - } - have_zone = 1; - } - spin_unlock(&fs_info->reada_lock); - btrfs_dev_replace_unlock(&fs_info->dev_replace, 0); - - if (!have_zone) - goto error; - - btrfs_put_bbio(bbio); - return re; - -error: - for (nzones = 0; nzones < re->nzones; ++nzones) { - struct reada_zone *zone; - - zone = re->zones[nzones]; - kref_get(&zone->refcnt); - spin_lock(&zone->lock); - --zone->elems; - if (zone->elems == 0) { - /* - * no fs_info->reada_lock needed, as this can't be - * the last ref - */ - kref_put(&zone->refcnt, reada_zone_release); - } - spin_unlock(&zone->lock); - - spin_lock(&fs_info->reada_lock); - kref_put(&zone->refcnt, reada_zone_release); - spin_unlock(&fs_info->reada_lock); - } - btrfs_put_bbio(bbio); - kfree(re); - return re_exist; -} - -static void reada_extent_put(struct btrfs_fs_info *fs_info, - struct reada_extent *re) -{ - int i; - unsigned long index = re->logical >> PAGE_SHIFT; - - spin_lock(&fs_info->reada_lock); - if (--re->refcnt) { - spin_unlock(&fs_info->reada_lock); - return; - } - - radix_tree_delete(&fs_info->reada_tree, index); - for (i = 0; i < re->nzones; ++i) { - struct reada_zone *zone = re->zones[i]; - - radix_tree_delete(&zone->device->reada_extents, index); - } - - spin_unlock(&fs_info->reada_lock); - - for (i = 0; i < re->nzones; ++i) { - struct reada_zone *zone = re->zones[i]; - - kref_get(&zone->refcnt); - spin_lock(&zone->lock); - --zone->elems; - if (zone->elems == 0) { - /* no fs_info->reada_lock needed, as this can't be - * the last ref */ - kref_put(&zone->refcnt, reada_zone_release); - } - spin_unlock(&zone->lock); - - spin_lock(&fs_info->reada_lock); - kref_put(&zone->refcnt, reada_zone_release); - spin_unlock(&fs_info->reada_lock); - } - - kfree(re); -} - -static void reada_zone_release(struct kref *kref) -{ - struct reada_zone *zone = container_of(kref, struct reada_zone, refcnt); - - radix_tree_delete(&zone->device->reada_zones, - zone->end >> PAGE_SHIFT); - - kfree(zone); -} - -static void reada_control_release(struct kref *kref) -{ - struct reada_control *rc = container_of(kref, struct reada_control, - refcnt); - - kfree(rc); -} - -static int reada_add_block(struct reada_control *rc, u64 logical, - struct btrfs_key *top, u64 generation) -{ - struct btrfs_root *root = rc->root; - struct reada_extent *re; - struct reada_extctl *rec; - - re = reada_find_extent(root, logical, top); /* takes one ref */ - if (!re) - return -1; - - rec = kzalloc(sizeof(*rec), GFP_KERNEL); - if (!rec) { - reada_extent_put(root->fs_info, re); - return -ENOMEM; - } - - rec->rc = rc; - rec->generation = generation; - atomic_inc(&rc->elems); - - spin_lock(&re->lock); - list_add_tail(&rec->list, &re->extctl); - spin_unlock(&re->lock); - - /* leave the ref on the extent */ - - return 0; -} - -/* - * called with fs_info->reada_lock held - */ -static void reada_peer_zones_set_lock(struct reada_zone *zone, int lock) -{ - int i; - unsigned long index = zone->end >> PAGE_SHIFT; - - for (i = 0; i < zone->ndevs; ++i) { - struct reada_zone *peer; - peer = radix_tree_lookup(&zone->devs[i]->reada_zones, index); - if (peer && peer->device != zone->device) - peer->locked = lock; - } -} - -/* - * called with fs_info->reada_lock held - */ -static int reada_pick_zone(struct btrfs_device *dev) -{ - struct reada_zone *top_zone = NULL; - struct reada_zone *top_locked_zone = NULL; - u64 top_elems = 0; - u64 top_locked_elems = 0; - unsigned long index = 0; - int ret; - - if (dev->reada_curr_zone) { - reada_peer_zones_set_lock(dev->reada_curr_zone, 0); - kref_put(&dev->reada_curr_zone->refcnt, reada_zone_release); - dev->reada_curr_zone = NULL; - } - /* pick the zone with the most elements */ - while (1) { - struct reada_zone *zone; - - ret = radix_tree_gang_lookup(&dev->reada_zones, - (void **)&zone, index, 1); - if (ret == 0) - break; - index = (zone->end >> PAGE_SHIFT) + 1; - if (zone->locked) { - if (zone->elems > top_locked_elems) { - top_locked_elems = zone->elems; - top_locked_zone = zone; - } - } else { - if (zone->elems > top_elems) { - top_elems = zone->elems; - top_zone = zone; - } - } - } - if (top_zone) - dev->reada_curr_zone = top_zone; - else if (top_locked_zone) - dev->reada_curr_zone = top_locked_zone; - else - return 0; - - dev->reada_next = dev->reada_curr_zone->start; - kref_get(&dev->reada_curr_zone->refcnt); - reada_peer_zones_set_lock(dev->reada_curr_zone, 1); - - return 1; -} - -static int reada_start_machine_dev(struct btrfs_fs_info *fs_info, - struct btrfs_device *dev) -{ - struct reada_extent *re = NULL; - int mirror_num = 0; - struct extent_buffer *eb = NULL; - u64 logical; - int ret; - int i; - - spin_lock(&fs_info->reada_lock); - if (dev->reada_curr_zone == NULL) { - ret = reada_pick_zone(dev); - if (!ret) { - spin_unlock(&fs_info->reada_lock); - return 0; - } - } - /* - * FIXME currently we issue the reads one extent at a time. If we have - * a contiguous block of extents, we could also coagulate them or use - * plugging to speed things up - */ - ret = radix_tree_gang_lookup(&dev->reada_extents, (void **)&re, - dev->reada_next >> PAGE_SHIFT, 1); - if (ret == 0 || re->logical > dev->reada_curr_zone->end) { - ret = reada_pick_zone(dev); - if (!ret) { - spin_unlock(&fs_info->reada_lock); - return 0; - } - re = NULL; - ret = radix_tree_gang_lookup(&dev->reada_extents, (void **)&re, - dev->reada_next >> PAGE_SHIFT, 1); - } - if (ret == 0) { - spin_unlock(&fs_info->reada_lock); - return 0; - } - dev->reada_next = re->logical + fs_info->tree_root->nodesize; - re->refcnt++; - - spin_unlock(&fs_info->reada_lock); - - spin_lock(&re->lock); - if (re->scheduled || list_empty(&re->extctl)) { - spin_unlock(&re->lock); - reada_extent_put(fs_info, re); - return 0; - } - re->scheduled = 1; - spin_unlock(&re->lock); - - /* - * find mirror num - */ - for (i = 0; i < re->nzones; ++i) { - if (re->zones[i]->device == dev) { - mirror_num = i + 1; - break; - } - } - logical = re->logical; - - atomic_inc(&dev->reada_in_flight); - ret = reada_tree_block_flagged(fs_info->extent_root, logical, - mirror_num, &eb); - if (ret) - __readahead_hook(fs_info, re, NULL, logical, ret); - else if (eb) - __readahead_hook(fs_info, re, eb, eb->start, ret); - - if (eb) - free_extent_buffer(eb); - - atomic_dec(&dev->reada_in_flight); - reada_extent_put(fs_info, re); - - return 1; - -} - -static void reada_start_machine_worker(struct btrfs_work *work) -{ - struct reada_machine_work *rmw; - struct btrfs_fs_info *fs_info; - int old_ioprio; - - rmw = container_of(work, struct reada_machine_work, work); - fs_info = rmw->fs_info; - - kfree(rmw); - - old_ioprio = IOPRIO_PRIO_VALUE(task_nice_ioclass(current), - task_nice_ioprio(current)); - set_task_ioprio(current, BTRFS_IOPRIO_READA); - __reada_start_machine(fs_info); - set_task_ioprio(current, old_ioprio); - - atomic_dec(&fs_info->reada_works_cnt); -} - -static void __reada_start_machine(struct btrfs_fs_info *fs_info) -{ - struct btrfs_device *device; - struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; - u64 enqueued; - u64 total = 0; - int i; - - do { - enqueued = 0; - mutex_lock(&fs_devices->device_list_mutex); - list_for_each_entry(device, &fs_devices->devices, dev_list) { - if (atomic_read(&device->reada_in_flight) < - MAX_IN_FLIGHT) - enqueued += reada_start_machine_dev(fs_info, - device); - } - mutex_unlock(&fs_devices->device_list_mutex); - total += enqueued; - } while (enqueued && total < 10000); - - if (enqueued == 0) - return; - - /* - * If everything is already in the cache, this is effectively single - * threaded. To a) not hold the caller for too long and b) to utilize - * more cores, we broke the loop above after 10000 iterations and now - * enqueue to workers to finish it. This will distribute the load to - * the cores. - */ - for (i = 0; i < 2; ++i) { - reada_start_machine(fs_info); - if (atomic_read(&fs_info->reada_works_cnt) > - BTRFS_MAX_MIRRORS * 2) - break; - } -} - -static void reada_start_machine(struct btrfs_fs_info *fs_info) -{ - struct reada_machine_work *rmw; - - rmw = kzalloc(sizeof(*rmw), GFP_KERNEL); - if (!rmw) { - /* FIXME we cannot handle this properly right now */ - BUG(); - } - btrfs_init_work(&rmw->work, btrfs_readahead_helper, - reada_start_machine_worker, NULL, NULL); - rmw->fs_info = fs_info; - - btrfs_queue_work(fs_info->readahead_workers, &rmw->work); - atomic_inc(&fs_info->reada_works_cnt); -} - -#ifdef DEBUG -static void dump_devs(struct btrfs_fs_info *fs_info, int all) -{ - struct btrfs_device *device; - struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; - unsigned long index; - int ret; - int i; - int j; - int cnt; - - spin_lock(&fs_info->reada_lock); - list_for_each_entry(device, &fs_devices->devices, dev_list) { - btrfs_debug(fs_info, "dev %lld has %d in flight", device->devid, - atomic_read(&device->reada_in_flight)); - index = 0; - while (1) { - struct reada_zone *zone; - ret = radix_tree_gang_lookup(&device->reada_zones, - (void **)&zone, index, 1); - if (ret == 0) - break; - pr_debug(" zone %llu-%llu elems %llu locked %d devs", - zone->start, zone->end, zone->elems, - zone->locked); - for (j = 0; j < zone->ndevs; ++j) { - pr_cont(" %lld", - zone->devs[j]->devid); - } - if (device->reada_curr_zone == zone) - pr_cont(" curr off %llu", - device->reada_next - zone->start); - pr_cont("\n"); - index = (zone->end >> PAGE_SHIFT) + 1; - } - cnt = 0; - index = 0; - while (all) { - struct reada_extent *re = NULL; - - ret = radix_tree_gang_lookup(&device->reada_extents, - (void **)&re, index, 1); - if (ret == 0) - break; - pr_debug(" re: logical %llu size %u empty %d scheduled %d", - re->logical, fs_info->tree_root->nodesize, - list_empty(&re->extctl), re->scheduled); - - for (i = 0; i < re->nzones; ++i) { - pr_cont(" zone %llu-%llu devs", - re->zones[i]->start, - re->zones[i]->end); - for (j = 0; j < re->zones[i]->ndevs; ++j) { - pr_cont(" %lld", - re->zones[i]->devs[j]->devid); - } - } - pr_cont("\n"); - index = (re->logical >> PAGE_SHIFT) + 1; - if (++cnt > 15) - break; - } - } - - index = 0; - cnt = 0; - while (all) { - struct reada_extent *re = NULL; - - ret = radix_tree_gang_lookup(&fs_info->reada_tree, (void **)&re, - index, 1); - if (ret == 0) - break; - if (!re->scheduled) { - index = (re->logical >> PAGE_SHIFT) + 1; - continue; - } - pr_debug("re: logical %llu size %u list empty %d scheduled %d", - re->logical, fs_info->tree_root->nodesize, - list_empty(&re->extctl), re->scheduled); - for (i = 0; i < re->nzones; ++i) { - pr_cont(" zone %llu-%llu devs", - re->zones[i]->start, - re->zones[i]->end); - for (j = 0; j < re->zones[i]->ndevs; ++j) { - pr_cont(" %lld", - re->zones[i]->devs[j]->devid); - } - } - pr_cont("\n"); - index = (re->logical >> PAGE_SHIFT) + 1; - } - spin_unlock(&fs_info->reada_lock); -} -#endif - -/* - * interface - */ -struct reada_control *btrfs_reada_add(struct btrfs_root *root, - struct btrfs_key *key_start, struct btrfs_key *key_end) -{ - struct reada_control *rc; - u64 start; - u64 generation; - int ret; - struct extent_buffer *node; - static struct btrfs_key max_key = { - .objectid = (u64)-1, - .type = (u8)-1, - .offset = (u64)-1 - }; - - rc = kzalloc(sizeof(*rc), GFP_KERNEL); - if (!rc) - return ERR_PTR(-ENOMEM); - - rc->root = root; - rc->key_start = *key_start; - rc->key_end = *key_end; - atomic_set(&rc->elems, 0); - init_waitqueue_head(&rc->wait); - kref_init(&rc->refcnt); - kref_get(&rc->refcnt); /* one ref for having elements */ - - node = btrfs_root_node(root); - start = node->start; - generation = btrfs_header_generation(node); - free_extent_buffer(node); - - ret = reada_add_block(rc, start, &max_key, generation); - if (ret) { - kfree(rc); - return ERR_PTR(ret); - } - - reada_start_machine(root->fs_info); - - return rc; -} - -#ifdef DEBUG -int btrfs_reada_wait(void *handle) -{ - struct reada_control *rc = handle; - struct btrfs_fs_info *fs_info = rc->root->fs_info; - - while (atomic_read(&rc->elems)) { - if (!atomic_read(&fs_info->reada_works_cnt)) - reada_start_machine(fs_info); - wait_event_timeout(rc->wait, atomic_read(&rc->elems) == 0, - 5 * HZ); - dump_devs(rc->root->fs_info, - atomic_read(&rc->elems) < 10 ? 1 : 0); - } - - dump_devs(rc->root->fs_info, atomic_read(&rc->elems) < 10 ? 1 : 0); - - kref_put(&rc->refcnt, reada_control_release); - - return 0; -} -#else -int btrfs_reada_wait(void *handle) -{ - struct reada_control *rc = handle; - struct btrfs_fs_info *fs_info = rc->root->fs_info; - - while (atomic_read(&rc->elems)) { - if (!atomic_read(&fs_info->reada_works_cnt)) - reada_start_machine(fs_info); - wait_event_timeout(rc->wait, atomic_read(&rc->elems) == 0, - (HZ + 9) / 10); - } - - kref_put(&rc->refcnt, reada_control_release); - - return 0; -} -#endif - -void btrfs_reada_detach(void *handle) -{ - struct reada_control *rc = handle; - - kref_put(&rc->refcnt, reada_control_release); -} diff --git a/src/linux/fs/btrfs/relocation.c b/src/linux/fs/btrfs/relocation.c deleted file mode 100644 index c4af0cd..0000000 --- a/src/linux/fs/btrfs/relocation.c +++ /dev/null @@ -1,4809 +0,0 @@ -/* - * Copyright (C) 2009 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include -#include -#include "ctree.h" -#include "disk-io.h" -#include "transaction.h" -#include "volumes.h" -#include "locking.h" -#include "btrfs_inode.h" -#include "async-thread.h" -#include "free-space-cache.h" -#include "inode-map.h" -#include "qgroup.h" - -/* - * backref_node, mapping_node and tree_block start with this - */ -struct tree_entry { - struct rb_node rb_node; - u64 bytenr; -}; - -/* - * present a tree block in the backref cache - */ -struct backref_node { - struct rb_node rb_node; - u64 bytenr; - - u64 new_bytenr; - /* objectid of tree block owner, can be not uptodate */ - u64 owner; - /* link to pending, changed or detached list */ - struct list_head list; - /* list of upper level blocks reference this block */ - struct list_head upper; - /* list of child blocks in the cache */ - struct list_head lower; - /* NULL if this node is not tree root */ - struct btrfs_root *root; - /* extent buffer got by COW the block */ - struct extent_buffer *eb; - /* level of tree block */ - unsigned int level:8; - /* is the block in non-reference counted tree */ - unsigned int cowonly:1; - /* 1 if no child node in the cache */ - unsigned int lowest:1; - /* is the extent buffer locked */ - unsigned int locked:1; - /* has the block been processed */ - unsigned int processed:1; - /* have backrefs of this block been checked */ - unsigned int checked:1; - /* - * 1 if corresponding block has been cowed but some upper - * level block pointers may not point to the new location - */ - unsigned int pending:1; - /* - * 1 if the backref node isn't connected to any other - * backref node. - */ - unsigned int detached:1; -}; - -/* - * present a block pointer in the backref cache - */ -struct backref_edge { - struct list_head list[2]; - struct backref_node *node[2]; -}; - -#define LOWER 0 -#define UPPER 1 -#define RELOCATION_RESERVED_NODES 256 - -struct backref_cache { - /* red black tree of all backref nodes in the cache */ - struct rb_root rb_root; - /* for passing backref nodes to btrfs_reloc_cow_block */ - struct backref_node *path[BTRFS_MAX_LEVEL]; - /* - * list of blocks that have been cowed but some block - * pointers in upper level blocks may not reflect the - * new location - */ - struct list_head pending[BTRFS_MAX_LEVEL]; - /* list of backref nodes with no child node */ - struct list_head leaves; - /* list of blocks that have been cowed in current transaction */ - struct list_head changed; - /* list of detached backref node. */ - struct list_head detached; - - u64 last_trans; - - int nr_nodes; - int nr_edges; -}; - -/* - * map address of tree root to tree - */ -struct mapping_node { - struct rb_node rb_node; - u64 bytenr; - void *data; -}; - -struct mapping_tree { - struct rb_root rb_root; - spinlock_t lock; -}; - -/* - * present a tree block to process - */ -struct tree_block { - struct rb_node rb_node; - u64 bytenr; - struct btrfs_key key; - unsigned int level:8; - unsigned int key_ready:1; -}; - -#define MAX_EXTENTS 128 - -struct file_extent_cluster { - u64 start; - u64 end; - u64 boundary[MAX_EXTENTS]; - unsigned int nr; -}; - -struct reloc_control { - /* block group to relocate */ - struct btrfs_block_group_cache *block_group; - /* extent tree */ - struct btrfs_root *extent_root; - /* inode for moving data */ - struct inode *data_inode; - - struct btrfs_block_rsv *block_rsv; - - struct backref_cache backref_cache; - - struct file_extent_cluster cluster; - /* tree blocks have been processed */ - struct extent_io_tree processed_blocks; - /* map start of tree root to corresponding reloc tree */ - struct mapping_tree reloc_root_tree; - /* list of reloc trees */ - struct list_head reloc_roots; - /* size of metadata reservation for merging reloc trees */ - u64 merging_rsv_size; - /* size of relocated tree nodes */ - u64 nodes_relocated; - /* reserved size for block group relocation*/ - u64 reserved_bytes; - - u64 search_start; - u64 extents_found; - - unsigned int stage:8; - unsigned int create_reloc_tree:1; - unsigned int merge_reloc_tree:1; - unsigned int found_file_extent:1; -}; - -/* stages of data relocation */ -#define MOVE_DATA_EXTENTS 0 -#define UPDATE_DATA_PTRS 1 - -static void remove_backref_node(struct backref_cache *cache, - struct backref_node *node); -static void __mark_block_processed(struct reloc_control *rc, - struct backref_node *node); - -static void mapping_tree_init(struct mapping_tree *tree) -{ - tree->rb_root = RB_ROOT; - spin_lock_init(&tree->lock); -} - -static void backref_cache_init(struct backref_cache *cache) -{ - int i; - cache->rb_root = RB_ROOT; - for (i = 0; i < BTRFS_MAX_LEVEL; i++) - INIT_LIST_HEAD(&cache->pending[i]); - INIT_LIST_HEAD(&cache->changed); - INIT_LIST_HEAD(&cache->detached); - INIT_LIST_HEAD(&cache->leaves); -} - -static void backref_cache_cleanup(struct backref_cache *cache) -{ - struct backref_node *node; - int i; - - while (!list_empty(&cache->detached)) { - node = list_entry(cache->detached.next, - struct backref_node, list); - remove_backref_node(cache, node); - } - - while (!list_empty(&cache->leaves)) { - node = list_entry(cache->leaves.next, - struct backref_node, lower); - remove_backref_node(cache, node); - } - - cache->last_trans = 0; - - for (i = 0; i < BTRFS_MAX_LEVEL; i++) - ASSERT(list_empty(&cache->pending[i])); - ASSERT(list_empty(&cache->changed)); - ASSERT(list_empty(&cache->detached)); - ASSERT(RB_EMPTY_ROOT(&cache->rb_root)); - ASSERT(!cache->nr_nodes); - ASSERT(!cache->nr_edges); -} - -static struct backref_node *alloc_backref_node(struct backref_cache *cache) -{ - struct backref_node *node; - - node = kzalloc(sizeof(*node), GFP_NOFS); - if (node) { - INIT_LIST_HEAD(&node->list); - INIT_LIST_HEAD(&node->upper); - INIT_LIST_HEAD(&node->lower); - RB_CLEAR_NODE(&node->rb_node); - cache->nr_nodes++; - } - return node; -} - -static void free_backref_node(struct backref_cache *cache, - struct backref_node *node) -{ - if (node) { - cache->nr_nodes--; - kfree(node); - } -} - -static struct backref_edge *alloc_backref_edge(struct backref_cache *cache) -{ - struct backref_edge *edge; - - edge = kzalloc(sizeof(*edge), GFP_NOFS); - if (edge) - cache->nr_edges++; - return edge; -} - -static void free_backref_edge(struct backref_cache *cache, - struct backref_edge *edge) -{ - if (edge) { - cache->nr_edges--; - kfree(edge); - } -} - -static struct rb_node *tree_insert(struct rb_root *root, u64 bytenr, - struct rb_node *node) -{ - struct rb_node **p = &root->rb_node; - struct rb_node *parent = NULL; - struct tree_entry *entry; - - while (*p) { - parent = *p; - entry = rb_entry(parent, struct tree_entry, rb_node); - - if (bytenr < entry->bytenr) - p = &(*p)->rb_left; - else if (bytenr > entry->bytenr) - p = &(*p)->rb_right; - else - return parent; - } - - rb_link_node(node, parent, p); - rb_insert_color(node, root); - return NULL; -} - -static struct rb_node *tree_search(struct rb_root *root, u64 bytenr) -{ - struct rb_node *n = root->rb_node; - struct tree_entry *entry; - - while (n) { - entry = rb_entry(n, struct tree_entry, rb_node); - - if (bytenr < entry->bytenr) - n = n->rb_left; - else if (bytenr > entry->bytenr) - n = n->rb_right; - else - return n; - } - return NULL; -} - -static void backref_tree_panic(struct rb_node *rb_node, int errno, u64 bytenr) -{ - - struct btrfs_fs_info *fs_info = NULL; - struct backref_node *bnode = rb_entry(rb_node, struct backref_node, - rb_node); - if (bnode->root) - fs_info = bnode->root->fs_info; - btrfs_panic(fs_info, errno, - "Inconsistency in backref cache found at offset %llu", - bytenr); -} - -/* - * walk up backref nodes until reach node presents tree root - */ -static struct backref_node *walk_up_backref(struct backref_node *node, - struct backref_edge *edges[], - int *index) -{ - struct backref_edge *edge; - int idx = *index; - - while (!list_empty(&node->upper)) { - edge = list_entry(node->upper.next, - struct backref_edge, list[LOWER]); - edges[idx++] = edge; - node = edge->node[UPPER]; - } - BUG_ON(node->detached); - *index = idx; - return node; -} - -/* - * walk down backref nodes to find start of next reference path - */ -static struct backref_node *walk_down_backref(struct backref_edge *edges[], - int *index) -{ - struct backref_edge *edge; - struct backref_node *lower; - int idx = *index; - - while (idx > 0) { - edge = edges[idx - 1]; - lower = edge->node[LOWER]; - if (list_is_last(&edge->list[LOWER], &lower->upper)) { - idx--; - continue; - } - edge = list_entry(edge->list[LOWER].next, - struct backref_edge, list[LOWER]); - edges[idx - 1] = edge; - *index = idx; - return edge->node[UPPER]; - } - *index = 0; - return NULL; -} - -static void unlock_node_buffer(struct backref_node *node) -{ - if (node->locked) { - btrfs_tree_unlock(node->eb); - node->locked = 0; - } -} - -static void drop_node_buffer(struct backref_node *node) -{ - if (node->eb) { - unlock_node_buffer(node); - free_extent_buffer(node->eb); - node->eb = NULL; - } -} - -static void drop_backref_node(struct backref_cache *tree, - struct backref_node *node) -{ - BUG_ON(!list_empty(&node->upper)); - - drop_node_buffer(node); - list_del(&node->list); - list_del(&node->lower); - if (!RB_EMPTY_NODE(&node->rb_node)) - rb_erase(&node->rb_node, &tree->rb_root); - free_backref_node(tree, node); -} - -/* - * remove a backref node from the backref cache - */ -static void remove_backref_node(struct backref_cache *cache, - struct backref_node *node) -{ - struct backref_node *upper; - struct backref_edge *edge; - - if (!node) - return; - - BUG_ON(!node->lowest && !node->detached); - while (!list_empty(&node->upper)) { - edge = list_entry(node->upper.next, struct backref_edge, - list[LOWER]); - upper = edge->node[UPPER]; - list_del(&edge->list[LOWER]); - list_del(&edge->list[UPPER]); - free_backref_edge(cache, edge); - - if (RB_EMPTY_NODE(&upper->rb_node)) { - BUG_ON(!list_empty(&node->upper)); - drop_backref_node(cache, node); - node = upper; - node->lowest = 1; - continue; - } - /* - * add the node to leaf node list if no other - * child block cached. - */ - if (list_empty(&upper->lower)) { - list_add_tail(&upper->lower, &cache->leaves); - upper->lowest = 1; - } - } - - drop_backref_node(cache, node); -} - -static void update_backref_node(struct backref_cache *cache, - struct backref_node *node, u64 bytenr) -{ - struct rb_node *rb_node; - rb_erase(&node->rb_node, &cache->rb_root); - node->bytenr = bytenr; - rb_node = tree_insert(&cache->rb_root, node->bytenr, &node->rb_node); - if (rb_node) - backref_tree_panic(rb_node, -EEXIST, bytenr); -} - -/* - * update backref cache after a transaction commit - */ -static int update_backref_cache(struct btrfs_trans_handle *trans, - struct backref_cache *cache) -{ - struct backref_node *node; - int level = 0; - - if (cache->last_trans == 0) { - cache->last_trans = trans->transid; - return 0; - } - - if (cache->last_trans == trans->transid) - return 0; - - /* - * detached nodes are used to avoid unnecessary backref - * lookup. transaction commit changes the extent tree. - * so the detached nodes are no longer useful. - */ - while (!list_empty(&cache->detached)) { - node = list_entry(cache->detached.next, - struct backref_node, list); - remove_backref_node(cache, node); - } - - while (!list_empty(&cache->changed)) { - node = list_entry(cache->changed.next, - struct backref_node, list); - list_del_init(&node->list); - BUG_ON(node->pending); - update_backref_node(cache, node, node->new_bytenr); - } - - /* - * some nodes can be left in the pending list if there were - * errors during processing the pending nodes. - */ - for (level = 0; level < BTRFS_MAX_LEVEL; level++) { - list_for_each_entry(node, &cache->pending[level], list) { - BUG_ON(!node->pending); - if (node->bytenr == node->new_bytenr) - continue; - update_backref_node(cache, node, node->new_bytenr); - } - } - - cache->last_trans = 0; - return 1; -} - - -static int should_ignore_root(struct btrfs_root *root) -{ - struct btrfs_root *reloc_root; - - if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state)) - return 0; - - reloc_root = root->reloc_root; - if (!reloc_root) - return 0; - - if (btrfs_root_last_snapshot(&reloc_root->root_item) == - root->fs_info->running_transaction->transid - 1) - return 0; - /* - * if there is reloc tree and it was created in previous - * transaction backref lookup can find the reloc tree, - * so backref node for the fs tree root is useless for - * relocation. - */ - return 1; -} -/* - * find reloc tree by address of tree root - */ -static struct btrfs_root *find_reloc_root(struct reloc_control *rc, - u64 bytenr) -{ - struct rb_node *rb_node; - struct mapping_node *node; - struct btrfs_root *root = NULL; - - spin_lock(&rc->reloc_root_tree.lock); - rb_node = tree_search(&rc->reloc_root_tree.rb_root, bytenr); - if (rb_node) { - node = rb_entry(rb_node, struct mapping_node, rb_node); - root = (struct btrfs_root *)node->data; - } - spin_unlock(&rc->reloc_root_tree.lock); - return root; -} - -static int is_cowonly_root(u64 root_objectid) -{ - if (root_objectid == BTRFS_ROOT_TREE_OBJECTID || - root_objectid == BTRFS_EXTENT_TREE_OBJECTID || - root_objectid == BTRFS_CHUNK_TREE_OBJECTID || - root_objectid == BTRFS_DEV_TREE_OBJECTID || - root_objectid == BTRFS_TREE_LOG_OBJECTID || - root_objectid == BTRFS_CSUM_TREE_OBJECTID || - root_objectid == BTRFS_UUID_TREE_OBJECTID || - root_objectid == BTRFS_QUOTA_TREE_OBJECTID || - root_objectid == BTRFS_FREE_SPACE_TREE_OBJECTID) - return 1; - return 0; -} - -static struct btrfs_root *read_fs_root(struct btrfs_fs_info *fs_info, - u64 root_objectid) -{ - struct btrfs_key key; - - key.objectid = root_objectid; - key.type = BTRFS_ROOT_ITEM_KEY; - if (is_cowonly_root(root_objectid)) - key.offset = 0; - else - key.offset = (u64)-1; - - return btrfs_get_fs_root(fs_info, &key, false); -} - -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 -static noinline_for_stack -struct btrfs_root *find_tree_root(struct reloc_control *rc, - struct extent_buffer *leaf, - struct btrfs_extent_ref_v0 *ref0) -{ - struct btrfs_root *root; - u64 root_objectid = btrfs_ref_root_v0(leaf, ref0); - u64 generation = btrfs_ref_generation_v0(leaf, ref0); - - BUG_ON(root_objectid == BTRFS_TREE_RELOC_OBJECTID); - - root = read_fs_root(rc->extent_root->fs_info, root_objectid); - BUG_ON(IS_ERR(root)); - - if (test_bit(BTRFS_ROOT_REF_COWS, &root->state) && - generation != btrfs_root_generation(&root->root_item)) - return NULL; - - return root; -} -#endif - -static noinline_for_stack -int find_inline_backref(struct extent_buffer *leaf, int slot, - unsigned long *ptr, unsigned long *end) -{ - struct btrfs_key key; - struct btrfs_extent_item *ei; - struct btrfs_tree_block_info *bi; - u32 item_size; - - btrfs_item_key_to_cpu(leaf, &key, slot); - - item_size = btrfs_item_size_nr(leaf, slot); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (item_size < sizeof(*ei)) { - WARN_ON(item_size != sizeof(struct btrfs_extent_item_v0)); - return 1; - } -#endif - ei = btrfs_item_ptr(leaf, slot, struct btrfs_extent_item); - WARN_ON(!(btrfs_extent_flags(leaf, ei) & - BTRFS_EXTENT_FLAG_TREE_BLOCK)); - - if (key.type == BTRFS_EXTENT_ITEM_KEY && - item_size <= sizeof(*ei) + sizeof(*bi)) { - WARN_ON(item_size < sizeof(*ei) + sizeof(*bi)); - return 1; - } - if (key.type == BTRFS_METADATA_ITEM_KEY && - item_size <= sizeof(*ei)) { - WARN_ON(item_size < sizeof(*ei)); - return 1; - } - - if (key.type == BTRFS_EXTENT_ITEM_KEY) { - bi = (struct btrfs_tree_block_info *)(ei + 1); - *ptr = (unsigned long)(bi + 1); - } else { - *ptr = (unsigned long)(ei + 1); - } - *end = (unsigned long)ei + item_size; - return 0; -} - -/* - * build backref tree for a given tree block. root of the backref tree - * corresponds the tree block, leaves of the backref tree correspond - * roots of b-trees that reference the tree block. - * - * the basic idea of this function is check backrefs of a given block - * to find upper level blocks that reference the block, and then check - * backrefs of these upper level blocks recursively. the recursion stop - * when tree root is reached or backrefs for the block is cached. - * - * NOTE: if we find backrefs for a block are cached, we know backrefs - * for all upper level blocks that directly/indirectly reference the - * block are also cached. - */ -static noinline_for_stack -struct backref_node *build_backref_tree(struct reloc_control *rc, - struct btrfs_key *node_key, - int level, u64 bytenr) -{ - struct backref_cache *cache = &rc->backref_cache; - struct btrfs_path *path1; - struct btrfs_path *path2; - struct extent_buffer *eb; - struct btrfs_root *root; - struct backref_node *cur; - struct backref_node *upper; - struct backref_node *lower; - struct backref_node *node = NULL; - struct backref_node *exist = NULL; - struct backref_edge *edge; - struct rb_node *rb_node; - struct btrfs_key key; - unsigned long end; - unsigned long ptr; - LIST_HEAD(list); - LIST_HEAD(useless); - int cowonly; - int ret; - int err = 0; - bool need_check = true; - - path1 = btrfs_alloc_path(); - path2 = btrfs_alloc_path(); - if (!path1 || !path2) { - err = -ENOMEM; - goto out; - } - path1->reada = READA_FORWARD; - path2->reada = READA_FORWARD; - - node = alloc_backref_node(cache); - if (!node) { - err = -ENOMEM; - goto out; - } - - node->bytenr = bytenr; - node->level = level; - node->lowest = 1; - cur = node; -again: - end = 0; - ptr = 0; - key.objectid = cur->bytenr; - key.type = BTRFS_METADATA_ITEM_KEY; - key.offset = (u64)-1; - - path1->search_commit_root = 1; - path1->skip_locking = 1; - ret = btrfs_search_slot(NULL, rc->extent_root, &key, path1, - 0, 0); - if (ret < 0) { - err = ret; - goto out; - } - ASSERT(ret); - ASSERT(path1->slots[0]); - - path1->slots[0]--; - - WARN_ON(cur->checked); - if (!list_empty(&cur->upper)) { - /* - * the backref was added previously when processing - * backref of type BTRFS_TREE_BLOCK_REF_KEY - */ - ASSERT(list_is_singular(&cur->upper)); - edge = list_entry(cur->upper.next, struct backref_edge, - list[LOWER]); - ASSERT(list_empty(&edge->list[UPPER])); - exist = edge->node[UPPER]; - /* - * add the upper level block to pending list if we need - * check its backrefs - */ - if (!exist->checked) - list_add_tail(&edge->list[UPPER], &list); - } else { - exist = NULL; - } - - while (1) { - cond_resched(); - eb = path1->nodes[0]; - - if (ptr >= end) { - if (path1->slots[0] >= btrfs_header_nritems(eb)) { - ret = btrfs_next_leaf(rc->extent_root, path1); - if (ret < 0) { - err = ret; - goto out; - } - if (ret > 0) - break; - eb = path1->nodes[0]; - } - - btrfs_item_key_to_cpu(eb, &key, path1->slots[0]); - if (key.objectid != cur->bytenr) { - WARN_ON(exist); - break; - } - - if (key.type == BTRFS_EXTENT_ITEM_KEY || - key.type == BTRFS_METADATA_ITEM_KEY) { - ret = find_inline_backref(eb, path1->slots[0], - &ptr, &end); - if (ret) - goto next; - } - } - - if (ptr < end) { - /* update key for inline back ref */ - struct btrfs_extent_inline_ref *iref; - iref = (struct btrfs_extent_inline_ref *)ptr; - key.type = btrfs_extent_inline_ref_type(eb, iref); - key.offset = btrfs_extent_inline_ref_offset(eb, iref); - WARN_ON(key.type != BTRFS_TREE_BLOCK_REF_KEY && - key.type != BTRFS_SHARED_BLOCK_REF_KEY); - } - - if (exist && - ((key.type == BTRFS_TREE_BLOCK_REF_KEY && - exist->owner == key.offset) || - (key.type == BTRFS_SHARED_BLOCK_REF_KEY && - exist->bytenr == key.offset))) { - exist = NULL; - goto next; - } - -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (key.type == BTRFS_SHARED_BLOCK_REF_KEY || - key.type == BTRFS_EXTENT_REF_V0_KEY) { - if (key.type == BTRFS_EXTENT_REF_V0_KEY) { - struct btrfs_extent_ref_v0 *ref0; - ref0 = btrfs_item_ptr(eb, path1->slots[0], - struct btrfs_extent_ref_v0); - if (key.objectid == key.offset) { - root = find_tree_root(rc, eb, ref0); - if (root && !should_ignore_root(root)) - cur->root = root; - else - list_add(&cur->list, &useless); - break; - } - if (is_cowonly_root(btrfs_ref_root_v0(eb, - ref0))) - cur->cowonly = 1; - } -#else - ASSERT(key.type != BTRFS_EXTENT_REF_V0_KEY); - if (key.type == BTRFS_SHARED_BLOCK_REF_KEY) { -#endif - if (key.objectid == key.offset) { - /* - * only root blocks of reloc trees use - * backref of this type. - */ - root = find_reloc_root(rc, cur->bytenr); - ASSERT(root); - cur->root = root; - break; - } - - edge = alloc_backref_edge(cache); - if (!edge) { - err = -ENOMEM; - goto out; - } - rb_node = tree_search(&cache->rb_root, key.offset); - if (!rb_node) { - upper = alloc_backref_node(cache); - if (!upper) { - free_backref_edge(cache, edge); - err = -ENOMEM; - goto out; - } - upper->bytenr = key.offset; - upper->level = cur->level + 1; - /* - * backrefs for the upper level block isn't - * cached, add the block to pending list - */ - list_add_tail(&edge->list[UPPER], &list); - } else { - upper = rb_entry(rb_node, struct backref_node, - rb_node); - ASSERT(upper->checked); - INIT_LIST_HEAD(&edge->list[UPPER]); - } - list_add_tail(&edge->list[LOWER], &cur->upper); - edge->node[LOWER] = cur; - edge->node[UPPER] = upper; - - goto next; - } else if (key.type != BTRFS_TREE_BLOCK_REF_KEY) { - goto next; - } - - /* key.type == BTRFS_TREE_BLOCK_REF_KEY */ - root = read_fs_root(rc->extent_root->fs_info, key.offset); - if (IS_ERR(root)) { - err = PTR_ERR(root); - goto out; - } - - if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state)) - cur->cowonly = 1; - - if (btrfs_root_level(&root->root_item) == cur->level) { - /* tree root */ - ASSERT(btrfs_root_bytenr(&root->root_item) == - cur->bytenr); - if (should_ignore_root(root)) - list_add(&cur->list, &useless); - else - cur->root = root; - break; - } - - level = cur->level + 1; - - /* - * searching the tree to find upper level blocks - * reference the block. - */ - path2->search_commit_root = 1; - path2->skip_locking = 1; - path2->lowest_level = level; - ret = btrfs_search_slot(NULL, root, node_key, path2, 0, 0); - path2->lowest_level = 0; - if (ret < 0) { - err = ret; - goto out; - } - if (ret > 0 && path2->slots[level] > 0) - path2->slots[level]--; - - eb = path2->nodes[level]; - if (btrfs_node_blockptr(eb, path2->slots[level]) != - cur->bytenr) { - btrfs_err(root->fs_info, - "couldn't find block (%llu) (level %d) in tree (%llu) with key (%llu %u %llu)", - cur->bytenr, level - 1, root->objectid, - node_key->objectid, node_key->type, - node_key->offset); - err = -ENOENT; - goto out; - } - lower = cur; - need_check = true; - for (; level < BTRFS_MAX_LEVEL; level++) { - if (!path2->nodes[level]) { - ASSERT(btrfs_root_bytenr(&root->root_item) == - lower->bytenr); - if (should_ignore_root(root)) - list_add(&lower->list, &useless); - else - lower->root = root; - break; - } - - edge = alloc_backref_edge(cache); - if (!edge) { - err = -ENOMEM; - goto out; - } - - eb = path2->nodes[level]; - rb_node = tree_search(&cache->rb_root, eb->start); - if (!rb_node) { - upper = alloc_backref_node(cache); - if (!upper) { - free_backref_edge(cache, edge); - err = -ENOMEM; - goto out; - } - upper->bytenr = eb->start; - upper->owner = btrfs_header_owner(eb); - upper->level = lower->level + 1; - if (!test_bit(BTRFS_ROOT_REF_COWS, - &root->state)) - upper->cowonly = 1; - - /* - * if we know the block isn't shared - * we can void checking its backrefs. - */ - if (btrfs_block_can_be_shared(root, eb)) - upper->checked = 0; - else - upper->checked = 1; - - /* - * add the block to pending list if we - * need check its backrefs, we only do this once - * while walking up a tree as we will catch - * anything else later on. - */ - if (!upper->checked && need_check) { - need_check = false; - list_add_tail(&edge->list[UPPER], - &list); - } else { - if (upper->checked) - need_check = true; - INIT_LIST_HEAD(&edge->list[UPPER]); - } - } else { - upper = rb_entry(rb_node, struct backref_node, - rb_node); - ASSERT(upper->checked); - INIT_LIST_HEAD(&edge->list[UPPER]); - if (!upper->owner) - upper->owner = btrfs_header_owner(eb); - } - list_add_tail(&edge->list[LOWER], &lower->upper); - edge->node[LOWER] = lower; - edge->node[UPPER] = upper; - - if (rb_node) - break; - lower = upper; - upper = NULL; - } - btrfs_release_path(path2); -next: - if (ptr < end) { - ptr += btrfs_extent_inline_ref_size(key.type); - if (ptr >= end) { - WARN_ON(ptr > end); - ptr = 0; - end = 0; - } - } - if (ptr >= end) - path1->slots[0]++; - } - btrfs_release_path(path1); - - cur->checked = 1; - WARN_ON(exist); - - /* the pending list isn't empty, take the first block to process */ - if (!list_empty(&list)) { - edge = list_entry(list.next, struct backref_edge, list[UPPER]); - list_del_init(&edge->list[UPPER]); - cur = edge->node[UPPER]; - goto again; - } - - /* - * everything goes well, connect backref nodes and insert backref nodes - * into the cache. - */ - ASSERT(node->checked); - cowonly = node->cowonly; - if (!cowonly) { - rb_node = tree_insert(&cache->rb_root, node->bytenr, - &node->rb_node); - if (rb_node) - backref_tree_panic(rb_node, -EEXIST, node->bytenr); - list_add_tail(&node->lower, &cache->leaves); - } - - list_for_each_entry(edge, &node->upper, list[LOWER]) - list_add_tail(&edge->list[UPPER], &list); - - while (!list_empty(&list)) { - edge = list_entry(list.next, struct backref_edge, list[UPPER]); - list_del_init(&edge->list[UPPER]); - upper = edge->node[UPPER]; - if (upper->detached) { - list_del(&edge->list[LOWER]); - lower = edge->node[LOWER]; - free_backref_edge(cache, edge); - if (list_empty(&lower->upper)) - list_add(&lower->list, &useless); - continue; - } - - if (!RB_EMPTY_NODE(&upper->rb_node)) { - if (upper->lowest) { - list_del_init(&upper->lower); - upper->lowest = 0; - } - - list_add_tail(&edge->list[UPPER], &upper->lower); - continue; - } - - if (!upper->checked) { - /* - * Still want to blow up for developers since this is a - * logic bug. - */ - ASSERT(0); - err = -EINVAL; - goto out; - } - if (cowonly != upper->cowonly) { - ASSERT(0); - err = -EINVAL; - goto out; - } - - if (!cowonly) { - rb_node = tree_insert(&cache->rb_root, upper->bytenr, - &upper->rb_node); - if (rb_node) - backref_tree_panic(rb_node, -EEXIST, - upper->bytenr); - } - - list_add_tail(&edge->list[UPPER], &upper->lower); - - list_for_each_entry(edge, &upper->upper, list[LOWER]) - list_add_tail(&edge->list[UPPER], &list); - } - /* - * process useless backref nodes. backref nodes for tree leaves - * are deleted from the cache. backref nodes for upper level - * tree blocks are left in the cache to avoid unnecessary backref - * lookup. - */ - while (!list_empty(&useless)) { - upper = list_entry(useless.next, struct backref_node, list); - list_del_init(&upper->list); - ASSERT(list_empty(&upper->upper)); - if (upper == node) - node = NULL; - if (upper->lowest) { - list_del_init(&upper->lower); - upper->lowest = 0; - } - while (!list_empty(&upper->lower)) { - edge = list_entry(upper->lower.next, - struct backref_edge, list[UPPER]); - list_del(&edge->list[UPPER]); - list_del(&edge->list[LOWER]); - lower = edge->node[LOWER]; - free_backref_edge(cache, edge); - - if (list_empty(&lower->upper)) - list_add(&lower->list, &useless); - } - __mark_block_processed(rc, upper); - if (upper->level > 0) { - list_add(&upper->list, &cache->detached); - upper->detached = 1; - } else { - rb_erase(&upper->rb_node, &cache->rb_root); - free_backref_node(cache, upper); - } - } -out: - btrfs_free_path(path1); - btrfs_free_path(path2); - if (err) { - while (!list_empty(&useless)) { - lower = list_entry(useless.next, - struct backref_node, list); - list_del_init(&lower->list); - } - while (!list_empty(&list)) { - edge = list_first_entry(&list, struct backref_edge, - list[UPPER]); - list_del(&edge->list[UPPER]); - list_del(&edge->list[LOWER]); - lower = edge->node[LOWER]; - upper = edge->node[UPPER]; - free_backref_edge(cache, edge); - - /* - * Lower is no longer linked to any upper backref nodes - * and isn't in the cache, we can free it ourselves. - */ - if (list_empty(&lower->upper) && - RB_EMPTY_NODE(&lower->rb_node)) - list_add(&lower->list, &useless); - - if (!RB_EMPTY_NODE(&upper->rb_node)) - continue; - - /* Add this guy's upper edges to the list to process */ - list_for_each_entry(edge, &upper->upper, list[LOWER]) - list_add_tail(&edge->list[UPPER], &list); - if (list_empty(&upper->upper)) - list_add(&upper->list, &useless); - } - - while (!list_empty(&useless)) { - lower = list_entry(useless.next, - struct backref_node, list); - list_del_init(&lower->list); - if (lower == node) - node = NULL; - free_backref_node(cache, lower); - } - - free_backref_node(cache, node); - return ERR_PTR(err); - } - ASSERT(!node || !node->detached); - return node; -} - -/* - * helper to add backref node for the newly created snapshot. - * the backref node is created by cloning backref node that - * corresponds to root of source tree - */ -static int clone_backref_node(struct btrfs_trans_handle *trans, - struct reloc_control *rc, - struct btrfs_root *src, - struct btrfs_root *dest) -{ - struct btrfs_root *reloc_root = src->reloc_root; - struct backref_cache *cache = &rc->backref_cache; - struct backref_node *node = NULL; - struct backref_node *new_node; - struct backref_edge *edge; - struct backref_edge *new_edge; - struct rb_node *rb_node; - - if (cache->last_trans > 0) - update_backref_cache(trans, cache); - - rb_node = tree_search(&cache->rb_root, src->commit_root->start); - if (rb_node) { - node = rb_entry(rb_node, struct backref_node, rb_node); - if (node->detached) - node = NULL; - else - BUG_ON(node->new_bytenr != reloc_root->node->start); - } - - if (!node) { - rb_node = tree_search(&cache->rb_root, - reloc_root->commit_root->start); - if (rb_node) { - node = rb_entry(rb_node, struct backref_node, - rb_node); - BUG_ON(node->detached); - } - } - - if (!node) - return 0; - - new_node = alloc_backref_node(cache); - if (!new_node) - return -ENOMEM; - - new_node->bytenr = dest->node->start; - new_node->level = node->level; - new_node->lowest = node->lowest; - new_node->checked = 1; - new_node->root = dest; - - if (!node->lowest) { - list_for_each_entry(edge, &node->lower, list[UPPER]) { - new_edge = alloc_backref_edge(cache); - if (!new_edge) - goto fail; - - new_edge->node[UPPER] = new_node; - new_edge->node[LOWER] = edge->node[LOWER]; - list_add_tail(&new_edge->list[UPPER], - &new_node->lower); - } - } else { - list_add_tail(&new_node->lower, &cache->leaves); - } - - rb_node = tree_insert(&cache->rb_root, new_node->bytenr, - &new_node->rb_node); - if (rb_node) - backref_tree_panic(rb_node, -EEXIST, new_node->bytenr); - - if (!new_node->lowest) { - list_for_each_entry(new_edge, &new_node->lower, list[UPPER]) { - list_add_tail(&new_edge->list[LOWER], - &new_edge->node[LOWER]->upper); - } - } - return 0; -fail: - while (!list_empty(&new_node->lower)) { - new_edge = list_entry(new_node->lower.next, - struct backref_edge, list[UPPER]); - list_del(&new_edge->list[UPPER]); - free_backref_edge(cache, new_edge); - } - free_backref_node(cache, new_node); - return -ENOMEM; -} - -/* - * helper to add 'address of tree root -> reloc tree' mapping - */ -static int __must_check __add_reloc_root(struct btrfs_root *root) -{ - struct rb_node *rb_node; - struct mapping_node *node; - struct reloc_control *rc = root->fs_info->reloc_ctl; - - node = kmalloc(sizeof(*node), GFP_NOFS); - if (!node) - return -ENOMEM; - - node->bytenr = root->node->start; - node->data = root; - - spin_lock(&rc->reloc_root_tree.lock); - rb_node = tree_insert(&rc->reloc_root_tree.rb_root, - node->bytenr, &node->rb_node); - spin_unlock(&rc->reloc_root_tree.lock); - if (rb_node) { - btrfs_panic(root->fs_info, -EEXIST, - "Duplicate root found for start=%llu while inserting into relocation tree", - node->bytenr); - kfree(node); - return -EEXIST; - } - - list_add_tail(&root->root_list, &rc->reloc_roots); - return 0; -} - -/* - * helper to delete the 'address of tree root -> reloc tree' - * mapping - */ -static void __del_reloc_root(struct btrfs_root *root) -{ - struct rb_node *rb_node; - struct mapping_node *node = NULL; - struct reloc_control *rc = root->fs_info->reloc_ctl; - - spin_lock(&rc->reloc_root_tree.lock); - rb_node = tree_search(&rc->reloc_root_tree.rb_root, - root->node->start); - if (rb_node) { - node = rb_entry(rb_node, struct mapping_node, rb_node); - rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root); - } - spin_unlock(&rc->reloc_root_tree.lock); - - if (!node) - return; - BUG_ON((struct btrfs_root *)node->data != root); - - spin_lock(&root->fs_info->trans_lock); - list_del_init(&root->root_list); - spin_unlock(&root->fs_info->trans_lock); - kfree(node); -} - -/* - * helper to update the 'address of tree root -> reloc tree' - * mapping - */ -static int __update_reloc_root(struct btrfs_root *root, u64 new_bytenr) -{ - struct rb_node *rb_node; - struct mapping_node *node = NULL; - struct reloc_control *rc = root->fs_info->reloc_ctl; - - spin_lock(&rc->reloc_root_tree.lock); - rb_node = tree_search(&rc->reloc_root_tree.rb_root, - root->node->start); - if (rb_node) { - node = rb_entry(rb_node, struct mapping_node, rb_node); - rb_erase(&node->rb_node, &rc->reloc_root_tree.rb_root); - } - spin_unlock(&rc->reloc_root_tree.lock); - - if (!node) - return 0; - BUG_ON((struct btrfs_root *)node->data != root); - - spin_lock(&rc->reloc_root_tree.lock); - node->bytenr = new_bytenr; - rb_node = tree_insert(&rc->reloc_root_tree.rb_root, - node->bytenr, &node->rb_node); - spin_unlock(&rc->reloc_root_tree.lock); - if (rb_node) - backref_tree_panic(rb_node, -EEXIST, node->bytenr); - return 0; -} - -static struct btrfs_root *create_reloc_root(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 objectid) -{ - struct btrfs_root *reloc_root; - struct extent_buffer *eb; - struct btrfs_root_item *root_item; - struct btrfs_key root_key; - u64 last_snap = 0; - int ret; - - root_item = kmalloc(sizeof(*root_item), GFP_NOFS); - BUG_ON(!root_item); - - root_key.objectid = BTRFS_TREE_RELOC_OBJECTID; - root_key.type = BTRFS_ROOT_ITEM_KEY; - root_key.offset = objectid; - - if (root->root_key.objectid == objectid) { - /* called by btrfs_init_reloc_root */ - ret = btrfs_copy_root(trans, root, root->commit_root, &eb, - BTRFS_TREE_RELOC_OBJECTID); - BUG_ON(ret); - - last_snap = btrfs_root_last_snapshot(&root->root_item); - btrfs_set_root_last_snapshot(&root->root_item, - trans->transid - 1); - } else { - /* - * called by btrfs_reloc_post_snapshot_hook. - * the source tree is a reloc tree, all tree blocks - * modified after it was created have RELOC flag - * set in their headers. so it's OK to not update - * the 'last_snapshot'. - */ - ret = btrfs_copy_root(trans, root, root->node, &eb, - BTRFS_TREE_RELOC_OBJECTID); - BUG_ON(ret); - } - - memcpy(root_item, &root->root_item, sizeof(*root_item)); - btrfs_set_root_bytenr(root_item, eb->start); - btrfs_set_root_level(root_item, btrfs_header_level(eb)); - btrfs_set_root_generation(root_item, trans->transid); - - if (root->root_key.objectid == objectid) { - btrfs_set_root_refs(root_item, 0); - memset(&root_item->drop_progress, 0, - sizeof(struct btrfs_disk_key)); - root_item->drop_level = 0; - /* - * abuse rtransid, it is safe because it is impossible to - * receive data into a relocation tree. - */ - btrfs_set_root_rtransid(root_item, last_snap); - btrfs_set_root_otransid(root_item, trans->transid); - } - - btrfs_tree_unlock(eb); - free_extent_buffer(eb); - - ret = btrfs_insert_root(trans, root->fs_info->tree_root, - &root_key, root_item); - BUG_ON(ret); - kfree(root_item); - - reloc_root = btrfs_read_fs_root(root->fs_info->tree_root, &root_key); - BUG_ON(IS_ERR(reloc_root)); - reloc_root->last_trans = trans->transid; - return reloc_root; -} - -/* - * create reloc tree for a given fs tree. reloc tree is just a - * snapshot of the fs tree with special root objectid. - */ -int btrfs_init_reloc_root(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_root *reloc_root; - struct reloc_control *rc = root->fs_info->reloc_ctl; - struct btrfs_block_rsv *rsv; - int clear_rsv = 0; - int ret; - - if (root->reloc_root) { - reloc_root = root->reloc_root; - reloc_root->last_trans = trans->transid; - return 0; - } - - if (!rc || !rc->create_reloc_tree || - root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) - return 0; - - if (!trans->reloc_reserved) { - rsv = trans->block_rsv; - trans->block_rsv = rc->block_rsv; - clear_rsv = 1; - } - reloc_root = create_reloc_root(trans, root, root->root_key.objectid); - if (clear_rsv) - trans->block_rsv = rsv; - - ret = __add_reloc_root(reloc_root); - BUG_ON(ret < 0); - root->reloc_root = reloc_root; - return 0; -} - -/* - * update root item of reloc tree - */ -int btrfs_update_reloc_root(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_root *reloc_root; - struct btrfs_root_item *root_item; - int ret; - - if (!root->reloc_root) - goto out; - - reloc_root = root->reloc_root; - root_item = &reloc_root->root_item; - - if (root->fs_info->reloc_ctl->merge_reloc_tree && - btrfs_root_refs(root_item) == 0) { - root->reloc_root = NULL; - __del_reloc_root(reloc_root); - } - - if (reloc_root->commit_root != reloc_root->node) { - btrfs_set_root_node(root_item, reloc_root->node); - free_extent_buffer(reloc_root->commit_root); - reloc_root->commit_root = btrfs_root_node(reloc_root); - } - - ret = btrfs_update_root(trans, root->fs_info->tree_root, - &reloc_root->root_key, root_item); - BUG_ON(ret); - -out: - return 0; -} - -/* - * helper to find first cached inode with inode number >= objectid - * in a subvolume - */ -static struct inode *find_next_inode(struct btrfs_root *root, u64 objectid) -{ - struct rb_node *node; - struct rb_node *prev; - struct btrfs_inode *entry; - struct inode *inode; - - spin_lock(&root->inode_lock); -again: - node = root->inode_tree.rb_node; - prev = NULL; - while (node) { - prev = node; - entry = rb_entry(node, struct btrfs_inode, rb_node); - - if (objectid < btrfs_ino(&entry->vfs_inode)) - node = node->rb_left; - else if (objectid > btrfs_ino(&entry->vfs_inode)) - node = node->rb_right; - else - break; - } - if (!node) { - while (prev) { - entry = rb_entry(prev, struct btrfs_inode, rb_node); - if (objectid <= btrfs_ino(&entry->vfs_inode)) { - node = prev; - break; - } - prev = rb_next(prev); - } - } - while (node) { - entry = rb_entry(node, struct btrfs_inode, rb_node); - inode = igrab(&entry->vfs_inode); - if (inode) { - spin_unlock(&root->inode_lock); - return inode; - } - - objectid = btrfs_ino(&entry->vfs_inode) + 1; - if (cond_resched_lock(&root->inode_lock)) - goto again; - - node = rb_next(node); - } - spin_unlock(&root->inode_lock); - return NULL; -} - -static int in_block_group(u64 bytenr, - struct btrfs_block_group_cache *block_group) -{ - if (bytenr >= block_group->key.objectid && - bytenr < block_group->key.objectid + block_group->key.offset) - return 1; - return 0; -} - -/* - * get new location of data - */ -static int get_new_location(struct inode *reloc_inode, u64 *new_bytenr, - u64 bytenr, u64 num_bytes) -{ - struct btrfs_root *root = BTRFS_I(reloc_inode)->root; - struct btrfs_path *path; - struct btrfs_file_extent_item *fi; - struct extent_buffer *leaf; - int ret; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - bytenr -= BTRFS_I(reloc_inode)->index_cnt; - ret = btrfs_lookup_file_extent(NULL, root, path, btrfs_ino(reloc_inode), - bytenr, 0); - if (ret < 0) - goto out; - if (ret > 0) { - ret = -ENOENT; - goto out; - } - - leaf = path->nodes[0]; - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - - BUG_ON(btrfs_file_extent_offset(leaf, fi) || - btrfs_file_extent_compression(leaf, fi) || - btrfs_file_extent_encryption(leaf, fi) || - btrfs_file_extent_other_encoding(leaf, fi)); - - if (num_bytes != btrfs_file_extent_disk_num_bytes(leaf, fi)) { - ret = -EINVAL; - goto out; - } - - *new_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); - ret = 0; -out: - btrfs_free_path(path); - return ret; -} - -/* - * update file extent items in the tree leaf to point to - * the new locations. - */ -static noinline_for_stack -int replace_file_extents(struct btrfs_trans_handle *trans, - struct reloc_control *rc, - struct btrfs_root *root, - struct extent_buffer *leaf) -{ - struct btrfs_key key; - struct btrfs_file_extent_item *fi; - struct inode *inode = NULL; - u64 parent; - u64 bytenr; - u64 new_bytenr = 0; - u64 num_bytes; - u64 end; - u32 nritems; - u32 i; - int ret = 0; - int first = 1; - int dirty = 0; - - if (rc->stage != UPDATE_DATA_PTRS) - return 0; - - /* reloc trees always use full backref */ - if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) - parent = leaf->start; - else - parent = 0; - - nritems = btrfs_header_nritems(leaf); - for (i = 0; i < nritems; i++) { - cond_resched(); - btrfs_item_key_to_cpu(leaf, &key, i); - if (key.type != BTRFS_EXTENT_DATA_KEY) - continue; - fi = btrfs_item_ptr(leaf, i, struct btrfs_file_extent_item); - if (btrfs_file_extent_type(leaf, fi) == - BTRFS_FILE_EXTENT_INLINE) - continue; - bytenr = btrfs_file_extent_disk_bytenr(leaf, fi); - num_bytes = btrfs_file_extent_disk_num_bytes(leaf, fi); - if (bytenr == 0) - continue; - if (!in_block_group(bytenr, rc->block_group)) - continue; - - /* - * if we are modifying block in fs tree, wait for readpage - * to complete and drop the extent cache - */ - if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) { - if (first) { - inode = find_next_inode(root, key.objectid); - first = 0; - } else if (inode && btrfs_ino(inode) < key.objectid) { - btrfs_add_delayed_iput(inode); - inode = find_next_inode(root, key.objectid); - } - if (inode && btrfs_ino(inode) == key.objectid) { - end = key.offset + - btrfs_file_extent_num_bytes(leaf, fi); - WARN_ON(!IS_ALIGNED(key.offset, - root->sectorsize)); - WARN_ON(!IS_ALIGNED(end, root->sectorsize)); - end--; - ret = try_lock_extent(&BTRFS_I(inode)->io_tree, - key.offset, end); - if (!ret) - continue; - - btrfs_drop_extent_cache(inode, key.offset, end, - 1); - unlock_extent(&BTRFS_I(inode)->io_tree, - key.offset, end); - } - } - - ret = get_new_location(rc->data_inode, &new_bytenr, - bytenr, num_bytes); - if (ret) { - /* - * Don't have to abort since we've not changed anything - * in the file extent yet. - */ - break; - } - - btrfs_set_file_extent_disk_bytenr(leaf, fi, new_bytenr); - dirty = 1; - - key.offset -= btrfs_file_extent_offset(leaf, fi); - ret = btrfs_inc_extent_ref(trans, root, new_bytenr, - num_bytes, parent, - btrfs_header_owner(leaf), - key.objectid, key.offset); - if (ret) { - btrfs_abort_transaction(trans, ret); - break; - } - - ret = btrfs_free_extent(trans, root, bytenr, num_bytes, - parent, btrfs_header_owner(leaf), - key.objectid, key.offset); - if (ret) { - btrfs_abort_transaction(trans, ret); - break; - } - } - if (dirty) - btrfs_mark_buffer_dirty(leaf); - if (inode) - btrfs_add_delayed_iput(inode); - return ret; -} - -static noinline_for_stack -int memcmp_node_keys(struct extent_buffer *eb, int slot, - struct btrfs_path *path, int level) -{ - struct btrfs_disk_key key1; - struct btrfs_disk_key key2; - btrfs_node_key(eb, &key1, slot); - btrfs_node_key(path->nodes[level], &key2, path->slots[level]); - return memcmp(&key1, &key2, sizeof(key1)); -} - -/* - * try to replace tree blocks in fs tree with the new blocks - * in reloc tree. tree blocks haven't been modified since the - * reloc tree was create can be replaced. - * - * if a block was replaced, level of the block + 1 is returned. - * if no block got replaced, 0 is returned. if there are other - * errors, a negative error number is returned. - */ -static noinline_for_stack -int replace_path(struct btrfs_trans_handle *trans, - struct btrfs_root *dest, struct btrfs_root *src, - struct btrfs_path *path, struct btrfs_key *next_key, - int lowest_level, int max_level) -{ - struct extent_buffer *eb; - struct extent_buffer *parent; - struct btrfs_key key; - u64 old_bytenr; - u64 new_bytenr; - u64 old_ptr_gen; - u64 new_ptr_gen; - u64 last_snapshot; - u32 blocksize; - int cow = 0; - int level; - int ret; - int slot; - - BUG_ON(src->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID); - BUG_ON(dest->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID); - - last_snapshot = btrfs_root_last_snapshot(&src->root_item); -again: - slot = path->slots[lowest_level]; - btrfs_node_key_to_cpu(path->nodes[lowest_level], &key, slot); - - eb = btrfs_lock_root_node(dest); - btrfs_set_lock_blocking(eb); - level = btrfs_header_level(eb); - - if (level < lowest_level) { - btrfs_tree_unlock(eb); - free_extent_buffer(eb); - return 0; - } - - if (cow) { - ret = btrfs_cow_block(trans, dest, eb, NULL, 0, &eb); - BUG_ON(ret); - } - btrfs_set_lock_blocking(eb); - - if (next_key) { - next_key->objectid = (u64)-1; - next_key->type = (u8)-1; - next_key->offset = (u64)-1; - } - - parent = eb; - while (1) { - level = btrfs_header_level(parent); - BUG_ON(level < lowest_level); - - ret = btrfs_bin_search(parent, &key, level, &slot); - if (ret && slot > 0) - slot--; - - if (next_key && slot + 1 < btrfs_header_nritems(parent)) - btrfs_node_key_to_cpu(parent, next_key, slot + 1); - - old_bytenr = btrfs_node_blockptr(parent, slot); - blocksize = dest->nodesize; - old_ptr_gen = btrfs_node_ptr_generation(parent, slot); - - if (level <= max_level) { - eb = path->nodes[level]; - new_bytenr = btrfs_node_blockptr(eb, - path->slots[level]); - new_ptr_gen = btrfs_node_ptr_generation(eb, - path->slots[level]); - } else { - new_bytenr = 0; - new_ptr_gen = 0; - } - - if (WARN_ON(new_bytenr > 0 && new_bytenr == old_bytenr)) { - ret = level; - break; - } - - if (new_bytenr == 0 || old_ptr_gen > last_snapshot || - memcmp_node_keys(parent, slot, path, level)) { - if (level <= lowest_level) { - ret = 0; - break; - } - - eb = read_tree_block(dest, old_bytenr, old_ptr_gen); - if (IS_ERR(eb)) { - ret = PTR_ERR(eb); - break; - } else if (!extent_buffer_uptodate(eb)) { - ret = -EIO; - free_extent_buffer(eb); - break; - } - btrfs_tree_lock(eb); - if (cow) { - ret = btrfs_cow_block(trans, dest, eb, parent, - slot, &eb); - BUG_ON(ret); - } - btrfs_set_lock_blocking(eb); - - btrfs_tree_unlock(parent); - free_extent_buffer(parent); - - parent = eb; - continue; - } - - if (!cow) { - btrfs_tree_unlock(parent); - free_extent_buffer(parent); - cow = 1; - goto again; - } - - btrfs_node_key_to_cpu(path->nodes[level], &key, - path->slots[level]); - btrfs_release_path(path); - - path->lowest_level = level; - ret = btrfs_search_slot(trans, src, &key, path, 0, 1); - path->lowest_level = 0; - BUG_ON(ret); - - /* - * swap blocks in fs tree and reloc tree. - */ - btrfs_set_node_blockptr(parent, slot, new_bytenr); - btrfs_set_node_ptr_generation(parent, slot, new_ptr_gen); - btrfs_mark_buffer_dirty(parent); - - btrfs_set_node_blockptr(path->nodes[level], - path->slots[level], old_bytenr); - btrfs_set_node_ptr_generation(path->nodes[level], - path->slots[level], old_ptr_gen); - btrfs_mark_buffer_dirty(path->nodes[level]); - - ret = btrfs_inc_extent_ref(trans, src, old_bytenr, blocksize, - path->nodes[level]->start, - src->root_key.objectid, level - 1, 0); - BUG_ON(ret); - ret = btrfs_inc_extent_ref(trans, dest, new_bytenr, blocksize, - 0, dest->root_key.objectid, level - 1, - 0); - BUG_ON(ret); - - ret = btrfs_free_extent(trans, src, new_bytenr, blocksize, - path->nodes[level]->start, - src->root_key.objectid, level - 1, 0); - BUG_ON(ret); - - ret = btrfs_free_extent(trans, dest, old_bytenr, blocksize, - 0, dest->root_key.objectid, level - 1, - 0); - BUG_ON(ret); - - btrfs_unlock_up_safe(path, 0); - - ret = level; - break; - } - btrfs_tree_unlock(parent); - free_extent_buffer(parent); - return ret; -} - -/* - * helper to find next relocated block in reloc tree - */ -static noinline_for_stack -int walk_up_reloc_tree(struct btrfs_root *root, struct btrfs_path *path, - int *level) -{ - struct extent_buffer *eb; - int i; - u64 last_snapshot; - u32 nritems; - - last_snapshot = btrfs_root_last_snapshot(&root->root_item); - - for (i = 0; i < *level; i++) { - free_extent_buffer(path->nodes[i]); - path->nodes[i] = NULL; - } - - for (i = *level; i < BTRFS_MAX_LEVEL && path->nodes[i]; i++) { - eb = path->nodes[i]; - nritems = btrfs_header_nritems(eb); - while (path->slots[i] + 1 < nritems) { - path->slots[i]++; - if (btrfs_node_ptr_generation(eb, path->slots[i]) <= - last_snapshot) - continue; - - *level = i; - return 0; - } - free_extent_buffer(path->nodes[i]); - path->nodes[i] = NULL; - } - return 1; -} - -/* - * walk down reloc tree to find relocated block of lowest level - */ -static noinline_for_stack -int walk_down_reloc_tree(struct btrfs_root *root, struct btrfs_path *path, - int *level) -{ - struct extent_buffer *eb = NULL; - int i; - u64 bytenr; - u64 ptr_gen = 0; - u64 last_snapshot; - u32 nritems; - - last_snapshot = btrfs_root_last_snapshot(&root->root_item); - - for (i = *level; i > 0; i--) { - eb = path->nodes[i]; - nritems = btrfs_header_nritems(eb); - while (path->slots[i] < nritems) { - ptr_gen = btrfs_node_ptr_generation(eb, path->slots[i]); - if (ptr_gen > last_snapshot) - break; - path->slots[i]++; - } - if (path->slots[i] >= nritems) { - if (i == *level) - break; - *level = i + 1; - return 0; - } - if (i == 1) { - *level = i; - return 0; - } - - bytenr = btrfs_node_blockptr(eb, path->slots[i]); - eb = read_tree_block(root, bytenr, ptr_gen); - if (IS_ERR(eb)) { - return PTR_ERR(eb); - } else if (!extent_buffer_uptodate(eb)) { - free_extent_buffer(eb); - return -EIO; - } - BUG_ON(btrfs_header_level(eb) != i - 1); - path->nodes[i - 1] = eb; - path->slots[i - 1] = 0; - } - return 1; -} - -/* - * invalidate extent cache for file extents whose key in range of - * [min_key, max_key) - */ -static int invalidate_extent_cache(struct btrfs_root *root, - struct btrfs_key *min_key, - struct btrfs_key *max_key) -{ - struct inode *inode = NULL; - u64 objectid; - u64 start, end; - u64 ino; - - objectid = min_key->objectid; - while (1) { - cond_resched(); - iput(inode); - - if (objectid > max_key->objectid) - break; - - inode = find_next_inode(root, objectid); - if (!inode) - break; - ino = btrfs_ino(inode); - - if (ino > max_key->objectid) { - iput(inode); - break; - } - - objectid = ino + 1; - if (!S_ISREG(inode->i_mode)) - continue; - - if (unlikely(min_key->objectid == ino)) { - if (min_key->type > BTRFS_EXTENT_DATA_KEY) - continue; - if (min_key->type < BTRFS_EXTENT_DATA_KEY) - start = 0; - else { - start = min_key->offset; - WARN_ON(!IS_ALIGNED(start, root->sectorsize)); - } - } else { - start = 0; - } - - if (unlikely(max_key->objectid == ino)) { - if (max_key->type < BTRFS_EXTENT_DATA_KEY) - continue; - if (max_key->type > BTRFS_EXTENT_DATA_KEY) { - end = (u64)-1; - } else { - if (max_key->offset == 0) - continue; - end = max_key->offset; - WARN_ON(!IS_ALIGNED(end, root->sectorsize)); - end--; - } - } else { - end = (u64)-1; - } - - /* the lock_extent waits for readpage to complete */ - lock_extent(&BTRFS_I(inode)->io_tree, start, end); - btrfs_drop_extent_cache(inode, start, end, 1); - unlock_extent(&BTRFS_I(inode)->io_tree, start, end); - } - return 0; -} - -static int find_next_key(struct btrfs_path *path, int level, - struct btrfs_key *key) - -{ - while (level < BTRFS_MAX_LEVEL) { - if (!path->nodes[level]) - break; - if (path->slots[level] + 1 < - btrfs_header_nritems(path->nodes[level])) { - btrfs_node_key_to_cpu(path->nodes[level], key, - path->slots[level] + 1); - return 0; - } - level++; - } - return 1; -} - -/* - * merge the relocated tree blocks in reloc tree with corresponding - * fs tree. - */ -static noinline_for_stack int merge_reloc_root(struct reloc_control *rc, - struct btrfs_root *root) -{ - LIST_HEAD(inode_list); - struct btrfs_key key; - struct btrfs_key next_key; - struct btrfs_trans_handle *trans = NULL; - struct btrfs_root *reloc_root; - struct btrfs_root_item *root_item; - struct btrfs_path *path; - struct extent_buffer *leaf; - int level; - int max_level; - int replaced = 0; - int ret; - int err = 0; - u32 min_reserved; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->reada = READA_FORWARD; - - reloc_root = root->reloc_root; - root_item = &reloc_root->root_item; - - if (btrfs_disk_key_objectid(&root_item->drop_progress) == 0) { - level = btrfs_root_level(root_item); - extent_buffer_get(reloc_root->node); - path->nodes[level] = reloc_root->node; - path->slots[level] = 0; - } else { - btrfs_disk_key_to_cpu(&key, &root_item->drop_progress); - - level = root_item->drop_level; - BUG_ON(level == 0); - path->lowest_level = level; - ret = btrfs_search_slot(NULL, reloc_root, &key, path, 0, 0); - path->lowest_level = 0; - if (ret < 0) { - btrfs_free_path(path); - return ret; - } - - btrfs_node_key_to_cpu(path->nodes[level], &next_key, - path->slots[level]); - WARN_ON(memcmp(&key, &next_key, sizeof(key))); - - btrfs_unlock_up_safe(path, 0); - } - - min_reserved = root->nodesize * (BTRFS_MAX_LEVEL - 1) * 2; - memset(&next_key, 0, sizeof(next_key)); - - while (1) { - ret = btrfs_block_rsv_refill(root, rc->block_rsv, min_reserved, - BTRFS_RESERVE_FLUSH_ALL); - if (ret) { - err = ret; - goto out; - } - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) { - err = PTR_ERR(trans); - trans = NULL; - goto out; - } - trans->block_rsv = rc->block_rsv; - - replaced = 0; - max_level = level; - - ret = walk_down_reloc_tree(reloc_root, path, &level); - if (ret < 0) { - err = ret; - goto out; - } - if (ret > 0) - break; - - if (!find_next_key(path, level, &key) && - btrfs_comp_cpu_keys(&next_key, &key) >= 0) { - ret = 0; - } else { - ret = replace_path(trans, root, reloc_root, path, - &next_key, level, max_level); - } - if (ret < 0) { - err = ret; - goto out; - } - - if (ret > 0) { - level = ret; - btrfs_node_key_to_cpu(path->nodes[level], &key, - path->slots[level]); - replaced = 1; - } - - ret = walk_up_reloc_tree(reloc_root, path, &level); - if (ret > 0) - break; - - BUG_ON(level == 0); - /* - * save the merging progress in the drop_progress. - * this is OK since root refs == 1 in this case. - */ - btrfs_node_key(path->nodes[level], &root_item->drop_progress, - path->slots[level]); - root_item->drop_level = level; - - btrfs_end_transaction_throttle(trans, root); - trans = NULL; - - btrfs_btree_balance_dirty(root); - - if (replaced && rc->stage == UPDATE_DATA_PTRS) - invalidate_extent_cache(root, &key, &next_key); - } - - /* - * handle the case only one block in the fs tree need to be - * relocated and the block is tree root. - */ - leaf = btrfs_lock_root_node(root); - ret = btrfs_cow_block(trans, root, leaf, NULL, 0, &leaf); - btrfs_tree_unlock(leaf); - free_extent_buffer(leaf); - if (ret < 0) - err = ret; -out: - btrfs_free_path(path); - - if (err == 0) { - memset(&root_item->drop_progress, 0, - sizeof(root_item->drop_progress)); - root_item->drop_level = 0; - btrfs_set_root_refs(root_item, 0); - btrfs_update_reloc_root(trans, root); - } - - if (trans) - btrfs_end_transaction_throttle(trans, root); - - btrfs_btree_balance_dirty(root); - - if (replaced && rc->stage == UPDATE_DATA_PTRS) - invalidate_extent_cache(root, &key, &next_key); - - return err; -} - -static noinline_for_stack -int prepare_to_merge(struct reloc_control *rc, int err) -{ - struct btrfs_root *root = rc->extent_root; - struct btrfs_root *reloc_root; - struct btrfs_trans_handle *trans; - LIST_HEAD(reloc_roots); - u64 num_bytes = 0; - int ret; - - mutex_lock(&root->fs_info->reloc_mutex); - rc->merging_rsv_size += root->nodesize * (BTRFS_MAX_LEVEL - 1) * 2; - rc->merging_rsv_size += rc->nodes_relocated * 2; - mutex_unlock(&root->fs_info->reloc_mutex); - -again: - if (!err) { - num_bytes = rc->merging_rsv_size; - ret = btrfs_block_rsv_add(root, rc->block_rsv, num_bytes, - BTRFS_RESERVE_FLUSH_ALL); - if (ret) - err = ret; - } - - trans = btrfs_join_transaction(rc->extent_root); - if (IS_ERR(trans)) { - if (!err) - btrfs_block_rsv_release(rc->extent_root, - rc->block_rsv, num_bytes); - return PTR_ERR(trans); - } - - if (!err) { - if (num_bytes != rc->merging_rsv_size) { - btrfs_end_transaction(trans, rc->extent_root); - btrfs_block_rsv_release(rc->extent_root, - rc->block_rsv, num_bytes); - goto again; - } - } - - rc->merge_reloc_tree = 1; - - while (!list_empty(&rc->reloc_roots)) { - reloc_root = list_entry(rc->reloc_roots.next, - struct btrfs_root, root_list); - list_del_init(&reloc_root->root_list); - - root = read_fs_root(reloc_root->fs_info, - reloc_root->root_key.offset); - BUG_ON(IS_ERR(root)); - BUG_ON(root->reloc_root != reloc_root); - - /* - * set reference count to 1, so btrfs_recover_relocation - * knows it should resumes merging - */ - if (!err) - btrfs_set_root_refs(&reloc_root->root_item, 1); - btrfs_update_reloc_root(trans, root); - - list_add(&reloc_root->root_list, &reloc_roots); - } - - list_splice(&reloc_roots, &rc->reloc_roots); - - if (!err) - btrfs_commit_transaction(trans, rc->extent_root); - else - btrfs_end_transaction(trans, rc->extent_root); - return err; -} - -static noinline_for_stack -void free_reloc_roots(struct list_head *list) -{ - struct btrfs_root *reloc_root; - - while (!list_empty(list)) { - reloc_root = list_entry(list->next, struct btrfs_root, - root_list); - free_extent_buffer(reloc_root->node); - free_extent_buffer(reloc_root->commit_root); - reloc_root->node = NULL; - reloc_root->commit_root = NULL; - __del_reloc_root(reloc_root); - } -} - -static noinline_for_stack -void merge_reloc_roots(struct reloc_control *rc) -{ - struct btrfs_root *root; - struct btrfs_root *reloc_root; - u64 last_snap; - u64 otransid; - u64 objectid; - LIST_HEAD(reloc_roots); - int found = 0; - int ret = 0; -again: - root = rc->extent_root; - - /* - * this serializes us with btrfs_record_root_in_transaction, - * we have to make sure nobody is in the middle of - * adding their roots to the list while we are - * doing this splice - */ - mutex_lock(&root->fs_info->reloc_mutex); - list_splice_init(&rc->reloc_roots, &reloc_roots); - mutex_unlock(&root->fs_info->reloc_mutex); - - while (!list_empty(&reloc_roots)) { - found = 1; - reloc_root = list_entry(reloc_roots.next, - struct btrfs_root, root_list); - - if (btrfs_root_refs(&reloc_root->root_item) > 0) { - root = read_fs_root(reloc_root->fs_info, - reloc_root->root_key.offset); - BUG_ON(IS_ERR(root)); - BUG_ON(root->reloc_root != reloc_root); - - ret = merge_reloc_root(rc, root); - if (ret) { - if (list_empty(&reloc_root->root_list)) - list_add_tail(&reloc_root->root_list, - &reloc_roots); - goto out; - } - } else { - list_del_init(&reloc_root->root_list); - } - - /* - * we keep the old last snapshot transid in rtranid when we - * created the relocation tree. - */ - last_snap = btrfs_root_rtransid(&reloc_root->root_item); - otransid = btrfs_root_otransid(&reloc_root->root_item); - objectid = reloc_root->root_key.offset; - - ret = btrfs_drop_snapshot(reloc_root, rc->block_rsv, 0, 1); - if (ret < 0) { - if (list_empty(&reloc_root->root_list)) - list_add_tail(&reloc_root->root_list, - &reloc_roots); - goto out; - } - } - - if (found) { - found = 0; - goto again; - } -out: - if (ret) { - btrfs_handle_fs_error(root->fs_info, ret, NULL); - if (!list_empty(&reloc_roots)) - free_reloc_roots(&reloc_roots); - - /* new reloc root may be added */ - mutex_lock(&root->fs_info->reloc_mutex); - list_splice_init(&rc->reloc_roots, &reloc_roots); - mutex_unlock(&root->fs_info->reloc_mutex); - if (!list_empty(&reloc_roots)) - free_reloc_roots(&reloc_roots); - } - - BUG_ON(!RB_EMPTY_ROOT(&rc->reloc_root_tree.rb_root)); -} - -static void free_block_list(struct rb_root *blocks) -{ - struct tree_block *block; - struct rb_node *rb_node; - while ((rb_node = rb_first(blocks))) { - block = rb_entry(rb_node, struct tree_block, rb_node); - rb_erase(rb_node, blocks); - kfree(block); - } -} - -static int record_reloc_root_in_trans(struct btrfs_trans_handle *trans, - struct btrfs_root *reloc_root) -{ - struct btrfs_root *root; - - if (reloc_root->last_trans == trans->transid) - return 0; - - root = read_fs_root(reloc_root->fs_info, reloc_root->root_key.offset); - BUG_ON(IS_ERR(root)); - BUG_ON(root->reloc_root != reloc_root); - - return btrfs_record_root_in_trans(trans, root); -} - -static noinline_for_stack -struct btrfs_root *select_reloc_root(struct btrfs_trans_handle *trans, - struct reloc_control *rc, - struct backref_node *node, - struct backref_edge *edges[]) -{ - struct backref_node *next; - struct btrfs_root *root; - int index = 0; - - next = node; - while (1) { - cond_resched(); - next = walk_up_backref(next, edges, &index); - root = next->root; - BUG_ON(!root); - BUG_ON(!test_bit(BTRFS_ROOT_REF_COWS, &root->state)); - - if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) { - record_reloc_root_in_trans(trans, root); - break; - } - - btrfs_record_root_in_trans(trans, root); - root = root->reloc_root; - - if (next->new_bytenr != root->node->start) { - BUG_ON(next->new_bytenr); - BUG_ON(!list_empty(&next->list)); - next->new_bytenr = root->node->start; - next->root = root; - list_add_tail(&next->list, - &rc->backref_cache.changed); - __mark_block_processed(rc, next); - break; - } - - WARN_ON(1); - root = NULL; - next = walk_down_backref(edges, &index); - if (!next || next->level <= node->level) - break; - } - if (!root) - return NULL; - - next = node; - /* setup backref node path for btrfs_reloc_cow_block */ - while (1) { - rc->backref_cache.path[next->level] = next; - if (--index < 0) - break; - next = edges[index]->node[UPPER]; - } - return root; -} - -/* - * select a tree root for relocation. return NULL if the block - * is reference counted. we should use do_relocation() in this - * case. return a tree root pointer if the block isn't reference - * counted. return -ENOENT if the block is root of reloc tree. - */ -static noinline_for_stack -struct btrfs_root *select_one_root(struct backref_node *node) -{ - struct backref_node *next; - struct btrfs_root *root; - struct btrfs_root *fs_root = NULL; - struct backref_edge *edges[BTRFS_MAX_LEVEL - 1]; - int index = 0; - - next = node; - while (1) { - cond_resched(); - next = walk_up_backref(next, edges, &index); - root = next->root; - BUG_ON(!root); - - /* no other choice for non-references counted tree */ - if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state)) - return root; - - if (root->root_key.objectid != BTRFS_TREE_RELOC_OBJECTID) - fs_root = root; - - if (next != node) - return NULL; - - next = walk_down_backref(edges, &index); - if (!next || next->level <= node->level) - break; - } - - if (!fs_root) - return ERR_PTR(-ENOENT); - return fs_root; -} - -static noinline_for_stack -u64 calcu_metadata_size(struct reloc_control *rc, - struct backref_node *node, int reserve) -{ - struct backref_node *next = node; - struct backref_edge *edge; - struct backref_edge *edges[BTRFS_MAX_LEVEL - 1]; - u64 num_bytes = 0; - int index = 0; - - BUG_ON(reserve && node->processed); - - while (next) { - cond_resched(); - while (1) { - if (next->processed && (reserve || next != node)) - break; - - num_bytes += rc->extent_root->nodesize; - - if (list_empty(&next->upper)) - break; - - edge = list_entry(next->upper.next, - struct backref_edge, list[LOWER]); - edges[index++] = edge; - next = edge->node[UPPER]; - } - next = walk_down_backref(edges, &index); - } - return num_bytes; -} - -static int reserve_metadata_space(struct btrfs_trans_handle *trans, - struct reloc_control *rc, - struct backref_node *node) -{ - struct btrfs_root *root = rc->extent_root; - u64 num_bytes; - int ret; - u64 tmp; - - num_bytes = calcu_metadata_size(rc, node, 1) * 2; - - trans->block_rsv = rc->block_rsv; - rc->reserved_bytes += num_bytes; - - /* - * We are under a transaction here so we can only do limited flushing. - * If we get an enospc just kick back -EAGAIN so we know to drop the - * transaction and try to refill when we can flush all the things. - */ - ret = btrfs_block_rsv_refill(root, rc->block_rsv, num_bytes, - BTRFS_RESERVE_FLUSH_LIMIT); - if (ret) { - tmp = rc->extent_root->nodesize * RELOCATION_RESERVED_NODES; - while (tmp <= rc->reserved_bytes) - tmp <<= 1; - /* - * only one thread can access block_rsv at this point, - * so we don't need hold lock to protect block_rsv. - * we expand more reservation size here to allow enough - * space for relocation and we will return eailer in - * enospc case. - */ - rc->block_rsv->size = tmp + rc->extent_root->nodesize * - RELOCATION_RESERVED_NODES; - return -EAGAIN; - } - - return 0; -} - -/* - * relocate a block tree, and then update pointers in upper level - * blocks that reference the block to point to the new location. - * - * if called by link_to_upper, the block has already been relocated. - * in that case this function just updates pointers. - */ -static int do_relocation(struct btrfs_trans_handle *trans, - struct reloc_control *rc, - struct backref_node *node, - struct btrfs_key *key, - struct btrfs_path *path, int lowest) -{ - struct backref_node *upper; - struct backref_edge *edge; - struct backref_edge *edges[BTRFS_MAX_LEVEL - 1]; - struct btrfs_root *root; - struct extent_buffer *eb; - u32 blocksize; - u64 bytenr; - u64 generation; - int slot; - int ret; - int err = 0; - - BUG_ON(lowest && node->eb); - - path->lowest_level = node->level + 1; - rc->backref_cache.path[node->level] = node; - list_for_each_entry(edge, &node->upper, list[LOWER]) { - cond_resched(); - - upper = edge->node[UPPER]; - root = select_reloc_root(trans, rc, upper, edges); - BUG_ON(!root); - - if (upper->eb && !upper->locked) { - if (!lowest) { - ret = btrfs_bin_search(upper->eb, key, - upper->level, &slot); - BUG_ON(ret); - bytenr = btrfs_node_blockptr(upper->eb, slot); - if (node->eb->start == bytenr) - goto next; - } - drop_node_buffer(upper); - } - - if (!upper->eb) { - ret = btrfs_search_slot(trans, root, key, path, 0, 1); - if (ret) { - if (ret < 0) - err = ret; - else - err = -ENOENT; - - btrfs_release_path(path); - break; - } - - if (!upper->eb) { - upper->eb = path->nodes[upper->level]; - path->nodes[upper->level] = NULL; - } else { - BUG_ON(upper->eb != path->nodes[upper->level]); - } - - upper->locked = 1; - path->locks[upper->level] = 0; - - slot = path->slots[upper->level]; - btrfs_release_path(path); - } else { - ret = btrfs_bin_search(upper->eb, key, upper->level, - &slot); - BUG_ON(ret); - } - - bytenr = btrfs_node_blockptr(upper->eb, slot); - if (lowest) { - if (bytenr != node->bytenr) { - btrfs_err(root->fs_info, - "lowest leaf/node mismatch: bytenr %llu node->bytenr %llu slot %d upper %llu", - bytenr, node->bytenr, slot, - upper->eb->start); - err = -EIO; - goto next; - } - } else { - if (node->eb->start == bytenr) - goto next; - } - - blocksize = root->nodesize; - generation = btrfs_node_ptr_generation(upper->eb, slot); - eb = read_tree_block(root, bytenr, generation); - if (IS_ERR(eb)) { - err = PTR_ERR(eb); - goto next; - } else if (!extent_buffer_uptodate(eb)) { - free_extent_buffer(eb); - err = -EIO; - goto next; - } - btrfs_tree_lock(eb); - btrfs_set_lock_blocking(eb); - - if (!node->eb) { - ret = btrfs_cow_block(trans, root, eb, upper->eb, - slot, &eb); - btrfs_tree_unlock(eb); - free_extent_buffer(eb); - if (ret < 0) { - err = ret; - goto next; - } - BUG_ON(node->eb != eb); - } else { - btrfs_set_node_blockptr(upper->eb, slot, - node->eb->start); - btrfs_set_node_ptr_generation(upper->eb, slot, - trans->transid); - btrfs_mark_buffer_dirty(upper->eb); - - ret = btrfs_inc_extent_ref(trans, root, - node->eb->start, blocksize, - upper->eb->start, - btrfs_header_owner(upper->eb), - node->level, 0); - BUG_ON(ret); - - ret = btrfs_drop_subtree(trans, root, eb, upper->eb); - BUG_ON(ret); - } -next: - if (!upper->pending) - drop_node_buffer(upper); - else - unlock_node_buffer(upper); - if (err) - break; - } - - if (!err && node->pending) { - drop_node_buffer(node); - list_move_tail(&node->list, &rc->backref_cache.changed); - node->pending = 0; - } - - path->lowest_level = 0; - BUG_ON(err == -ENOSPC); - return err; -} - -static int link_to_upper(struct btrfs_trans_handle *trans, - struct reloc_control *rc, - struct backref_node *node, - struct btrfs_path *path) -{ - struct btrfs_key key; - - btrfs_node_key_to_cpu(node->eb, &key, 0); - return do_relocation(trans, rc, node, &key, path, 0); -} - -static int finish_pending_nodes(struct btrfs_trans_handle *trans, - struct reloc_control *rc, - struct btrfs_path *path, int err) -{ - LIST_HEAD(list); - struct backref_cache *cache = &rc->backref_cache; - struct backref_node *node; - int level; - int ret; - - for (level = 0; level < BTRFS_MAX_LEVEL; level++) { - while (!list_empty(&cache->pending[level])) { - node = list_entry(cache->pending[level].next, - struct backref_node, list); - list_move_tail(&node->list, &list); - BUG_ON(!node->pending); - - if (!err) { - ret = link_to_upper(trans, rc, node, path); - if (ret < 0) - err = ret; - } - } - list_splice_init(&list, &cache->pending[level]); - } - return err; -} - -static void mark_block_processed(struct reloc_control *rc, - u64 bytenr, u32 blocksize) -{ - set_extent_bits(&rc->processed_blocks, bytenr, bytenr + blocksize - 1, - EXTENT_DIRTY); -} - -static void __mark_block_processed(struct reloc_control *rc, - struct backref_node *node) -{ - u32 blocksize; - if (node->level == 0 || - in_block_group(node->bytenr, rc->block_group)) { - blocksize = rc->extent_root->nodesize; - mark_block_processed(rc, node->bytenr, blocksize); - } - node->processed = 1; -} - -/* - * mark a block and all blocks directly/indirectly reference the block - * as processed. - */ -static void update_processed_blocks(struct reloc_control *rc, - struct backref_node *node) -{ - struct backref_node *next = node; - struct backref_edge *edge; - struct backref_edge *edges[BTRFS_MAX_LEVEL - 1]; - int index = 0; - - while (next) { - cond_resched(); - while (1) { - if (next->processed) - break; - - __mark_block_processed(rc, next); - - if (list_empty(&next->upper)) - break; - - edge = list_entry(next->upper.next, - struct backref_edge, list[LOWER]); - edges[index++] = edge; - next = edge->node[UPPER]; - } - next = walk_down_backref(edges, &index); - } -} - -static int tree_block_processed(u64 bytenr, struct reloc_control *rc) -{ - u32 blocksize = rc->extent_root->nodesize; - - if (test_range_bit(&rc->processed_blocks, bytenr, - bytenr + blocksize - 1, EXTENT_DIRTY, 1, NULL)) - return 1; - return 0; -} - -static int get_tree_block_key(struct reloc_control *rc, - struct tree_block *block) -{ - struct extent_buffer *eb; - - BUG_ON(block->key_ready); - eb = read_tree_block(rc->extent_root, block->bytenr, - block->key.offset); - if (IS_ERR(eb)) { - return PTR_ERR(eb); - } else if (!extent_buffer_uptodate(eb)) { - free_extent_buffer(eb); - return -EIO; - } - WARN_ON(btrfs_header_level(eb) != block->level); - if (block->level == 0) - btrfs_item_key_to_cpu(eb, &block->key, 0); - else - btrfs_node_key_to_cpu(eb, &block->key, 0); - free_extent_buffer(eb); - block->key_ready = 1; - return 0; -} - -/* - * helper function to relocate a tree block - */ -static int relocate_tree_block(struct btrfs_trans_handle *trans, - struct reloc_control *rc, - struct backref_node *node, - struct btrfs_key *key, - struct btrfs_path *path) -{ - struct btrfs_root *root; - int ret = 0; - - if (!node) - return 0; - - BUG_ON(node->processed); - root = select_one_root(node); - if (root == ERR_PTR(-ENOENT)) { - update_processed_blocks(rc, node); - goto out; - } - - if (!root || test_bit(BTRFS_ROOT_REF_COWS, &root->state)) { - ret = reserve_metadata_space(trans, rc, node); - if (ret) - goto out; - } - - if (root) { - if (test_bit(BTRFS_ROOT_REF_COWS, &root->state)) { - BUG_ON(node->new_bytenr); - BUG_ON(!list_empty(&node->list)); - btrfs_record_root_in_trans(trans, root); - root = root->reloc_root; - node->new_bytenr = root->node->start; - node->root = root; - list_add_tail(&node->list, &rc->backref_cache.changed); - } else { - path->lowest_level = node->level; - ret = btrfs_search_slot(trans, root, key, path, 0, 1); - btrfs_release_path(path); - if (ret > 0) - ret = 0; - } - if (!ret) - update_processed_blocks(rc, node); - } else { - ret = do_relocation(trans, rc, node, key, path, 1); - } -out: - if (ret || node->level == 0 || node->cowonly) - remove_backref_node(&rc->backref_cache, node); - return ret; -} - -/* - * relocate a list of blocks - */ -static noinline_for_stack -int relocate_tree_blocks(struct btrfs_trans_handle *trans, - struct reloc_control *rc, struct rb_root *blocks) -{ - struct backref_node *node; - struct btrfs_path *path; - struct tree_block *block; - struct rb_node *rb_node; - int ret; - int err = 0; - - path = btrfs_alloc_path(); - if (!path) { - err = -ENOMEM; - goto out_free_blocks; - } - - rb_node = rb_first(blocks); - while (rb_node) { - block = rb_entry(rb_node, struct tree_block, rb_node); - if (!block->key_ready) - readahead_tree_block(rc->extent_root, block->bytenr); - rb_node = rb_next(rb_node); - } - - rb_node = rb_first(blocks); - while (rb_node) { - block = rb_entry(rb_node, struct tree_block, rb_node); - if (!block->key_ready) { - err = get_tree_block_key(rc, block); - if (err) - goto out_free_path; - } - rb_node = rb_next(rb_node); - } - - rb_node = rb_first(blocks); - while (rb_node) { - block = rb_entry(rb_node, struct tree_block, rb_node); - - node = build_backref_tree(rc, &block->key, - block->level, block->bytenr); - if (IS_ERR(node)) { - err = PTR_ERR(node); - goto out; - } - - ret = relocate_tree_block(trans, rc, node, &block->key, - path); - if (ret < 0) { - if (ret != -EAGAIN || rb_node == rb_first(blocks)) - err = ret; - goto out; - } - rb_node = rb_next(rb_node); - } -out: - err = finish_pending_nodes(trans, rc, path, err); - -out_free_path: - btrfs_free_path(path); -out_free_blocks: - free_block_list(blocks); - return err; -} - -static noinline_for_stack -int prealloc_file_extent_cluster(struct inode *inode, - struct file_extent_cluster *cluster) -{ - u64 alloc_hint = 0; - u64 start; - u64 end; - u64 offset = BTRFS_I(inode)->index_cnt; - u64 num_bytes; - int nr = 0; - int ret = 0; - u64 prealloc_start = cluster->start - offset; - u64 prealloc_end = cluster->end - offset; - u64 cur_offset; - - BUG_ON(cluster->start != cluster->boundary[0]); - inode_lock(inode); - - ret = btrfs_check_data_free_space(inode, prealloc_start, - prealloc_end + 1 - prealloc_start); - if (ret) - goto out; - - cur_offset = prealloc_start; - while (nr < cluster->nr) { - start = cluster->boundary[nr] - offset; - if (nr + 1 < cluster->nr) - end = cluster->boundary[nr + 1] - 1 - offset; - else - end = cluster->end - offset; - - lock_extent(&BTRFS_I(inode)->io_tree, start, end); - num_bytes = end + 1 - start; - if (cur_offset < start) - btrfs_free_reserved_data_space(inode, cur_offset, - start - cur_offset); - ret = btrfs_prealloc_file_range(inode, 0, start, - num_bytes, num_bytes, - end + 1, &alloc_hint); - cur_offset = end + 1; - unlock_extent(&BTRFS_I(inode)->io_tree, start, end); - if (ret) - break; - nr++; - } - if (cur_offset < prealloc_end) - btrfs_free_reserved_data_space(inode, cur_offset, - prealloc_end + 1 - cur_offset); -out: - inode_unlock(inode); - return ret; -} - -static noinline_for_stack -int setup_extent_mapping(struct inode *inode, u64 start, u64 end, - u64 block_start) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; - struct extent_map *em; - int ret = 0; - - em = alloc_extent_map(); - if (!em) - return -ENOMEM; - - em->start = start; - em->len = end + 1 - start; - em->block_len = em->len; - em->block_start = block_start; - em->bdev = root->fs_info->fs_devices->latest_bdev; - set_bit(EXTENT_FLAG_PINNED, &em->flags); - - lock_extent(&BTRFS_I(inode)->io_tree, start, end); - while (1) { - write_lock(&em_tree->lock); - ret = add_extent_mapping(em_tree, em, 0); - write_unlock(&em_tree->lock); - if (ret != -EEXIST) { - free_extent_map(em); - break; - } - btrfs_drop_extent_cache(inode, start, end, 0); - } - unlock_extent(&BTRFS_I(inode)->io_tree, start, end); - return ret; -} - -static int relocate_file_extent_cluster(struct inode *inode, - struct file_extent_cluster *cluster) -{ - u64 page_start; - u64 page_end; - u64 offset = BTRFS_I(inode)->index_cnt; - unsigned long index; - unsigned long last_index; - struct page *page; - struct file_ra_state *ra; - gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping); - int nr = 0; - int ret = 0; - - if (!cluster->nr) - return 0; - - ra = kzalloc(sizeof(*ra), GFP_NOFS); - if (!ra) - return -ENOMEM; - - ret = prealloc_file_extent_cluster(inode, cluster); - if (ret) - goto out; - - file_ra_state_init(ra, inode->i_mapping); - - ret = setup_extent_mapping(inode, cluster->start - offset, - cluster->end - offset, cluster->start); - if (ret) - goto out; - - index = (cluster->start - offset) >> PAGE_SHIFT; - last_index = (cluster->end - offset) >> PAGE_SHIFT; - while (index <= last_index) { - ret = btrfs_delalloc_reserve_metadata(inode, PAGE_SIZE); - if (ret) - goto out; - - page = find_lock_page(inode->i_mapping, index); - if (!page) { - page_cache_sync_readahead(inode->i_mapping, - ra, NULL, index, - last_index + 1 - index); - page = find_or_create_page(inode->i_mapping, index, - mask); - if (!page) { - btrfs_delalloc_release_metadata(inode, - PAGE_SIZE); - ret = -ENOMEM; - goto out; - } - } - - if (PageReadahead(page)) { - page_cache_async_readahead(inode->i_mapping, - ra, NULL, page, index, - last_index + 1 - index); - } - - if (!PageUptodate(page)) { - btrfs_readpage(NULL, page); - lock_page(page); - if (!PageUptodate(page)) { - unlock_page(page); - put_page(page); - btrfs_delalloc_release_metadata(inode, - PAGE_SIZE); - ret = -EIO; - goto out; - } - } - - page_start = page_offset(page); - page_end = page_start + PAGE_SIZE - 1; - - lock_extent(&BTRFS_I(inode)->io_tree, page_start, page_end); - - set_page_extent_mapped(page); - - if (nr < cluster->nr && - page_start + offset == cluster->boundary[nr]) { - set_extent_bits(&BTRFS_I(inode)->io_tree, - page_start, page_end, - EXTENT_BOUNDARY); - nr++; - } - - btrfs_set_extent_delalloc(inode, page_start, page_end, NULL, 0); - set_page_dirty(page); - - unlock_extent(&BTRFS_I(inode)->io_tree, - page_start, page_end); - unlock_page(page); - put_page(page); - - index++; - balance_dirty_pages_ratelimited(inode->i_mapping); - btrfs_throttle(BTRFS_I(inode)->root); - } - WARN_ON(nr != cluster->nr); -out: - kfree(ra); - return ret; -} - -static noinline_for_stack -int relocate_data_extent(struct inode *inode, struct btrfs_key *extent_key, - struct file_extent_cluster *cluster) -{ - int ret; - - if (cluster->nr > 0 && extent_key->objectid != cluster->end + 1) { - ret = relocate_file_extent_cluster(inode, cluster); - if (ret) - return ret; - cluster->nr = 0; - } - - if (!cluster->nr) - cluster->start = extent_key->objectid; - else - BUG_ON(cluster->nr >= MAX_EXTENTS); - cluster->end = extent_key->objectid + extent_key->offset - 1; - cluster->boundary[cluster->nr] = extent_key->objectid; - cluster->nr++; - - if (cluster->nr >= MAX_EXTENTS) { - ret = relocate_file_extent_cluster(inode, cluster); - if (ret) - return ret; - cluster->nr = 0; - } - return 0; -} - -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 -static int get_ref_objectid_v0(struct reloc_control *rc, - struct btrfs_path *path, - struct btrfs_key *extent_key, - u64 *ref_objectid, int *path_change) -{ - struct btrfs_key key; - struct extent_buffer *leaf; - struct btrfs_extent_ref_v0 *ref0; - int ret; - int slot; - - leaf = path->nodes[0]; - slot = path->slots[0]; - while (1) { - if (slot >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(rc->extent_root, path); - if (ret < 0) - return ret; - BUG_ON(ret > 0); - leaf = path->nodes[0]; - slot = path->slots[0]; - if (path_change) - *path_change = 1; - } - btrfs_item_key_to_cpu(leaf, &key, slot); - if (key.objectid != extent_key->objectid) - return -ENOENT; - - if (key.type != BTRFS_EXTENT_REF_V0_KEY) { - slot++; - continue; - } - ref0 = btrfs_item_ptr(leaf, slot, - struct btrfs_extent_ref_v0); - *ref_objectid = btrfs_ref_objectid_v0(leaf, ref0); - break; - } - return 0; -} -#endif - -/* - * helper to add a tree block to the list. - * the major work is getting the generation and level of the block - */ -static int add_tree_block(struct reloc_control *rc, - struct btrfs_key *extent_key, - struct btrfs_path *path, - struct rb_root *blocks) -{ - struct extent_buffer *eb; - struct btrfs_extent_item *ei; - struct btrfs_tree_block_info *bi; - struct tree_block *block; - struct rb_node *rb_node; - u32 item_size; - int level = -1; - u64 generation; - - eb = path->nodes[0]; - item_size = btrfs_item_size_nr(eb, path->slots[0]); - - if (extent_key->type == BTRFS_METADATA_ITEM_KEY || - item_size >= sizeof(*ei) + sizeof(*bi)) { - ei = btrfs_item_ptr(eb, path->slots[0], - struct btrfs_extent_item); - if (extent_key->type == BTRFS_EXTENT_ITEM_KEY) { - bi = (struct btrfs_tree_block_info *)(ei + 1); - level = btrfs_tree_block_level(eb, bi); - } else { - level = (int)extent_key->offset; - } - generation = btrfs_extent_generation(eb, ei); - } else { -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - u64 ref_owner; - int ret; - - BUG_ON(item_size != sizeof(struct btrfs_extent_item_v0)); - ret = get_ref_objectid_v0(rc, path, extent_key, - &ref_owner, NULL); - if (ret < 0) - return ret; - BUG_ON(ref_owner >= BTRFS_MAX_LEVEL); - level = (int)ref_owner; - /* FIXME: get real generation */ - generation = 0; -#else - BUG(); -#endif - } - - btrfs_release_path(path); - - BUG_ON(level == -1); - - block = kmalloc(sizeof(*block), GFP_NOFS); - if (!block) - return -ENOMEM; - - block->bytenr = extent_key->objectid; - block->key.objectid = rc->extent_root->nodesize; - block->key.offset = generation; - block->level = level; - block->key_ready = 0; - - rb_node = tree_insert(blocks, block->bytenr, &block->rb_node); - if (rb_node) - backref_tree_panic(rb_node, -EEXIST, block->bytenr); - - return 0; -} - -/* - * helper to add tree blocks for backref of type BTRFS_SHARED_DATA_REF_KEY - */ -static int __add_tree_block(struct reloc_control *rc, - u64 bytenr, u32 blocksize, - struct rb_root *blocks) -{ - struct btrfs_path *path; - struct btrfs_key key; - int ret; - bool skinny = btrfs_fs_incompat(rc->extent_root->fs_info, - SKINNY_METADATA); - - if (tree_block_processed(bytenr, rc)) - return 0; - - if (tree_search(blocks, bytenr)) - return 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; -again: - key.objectid = bytenr; - if (skinny) { - key.type = BTRFS_METADATA_ITEM_KEY; - key.offset = (u64)-1; - } else { - key.type = BTRFS_EXTENT_ITEM_KEY; - key.offset = blocksize; - } - - path->search_commit_root = 1; - path->skip_locking = 1; - ret = btrfs_search_slot(NULL, rc->extent_root, &key, path, 0, 0); - if (ret < 0) - goto out; - - if (ret > 0 && skinny) { - if (path->slots[0]) { - path->slots[0]--; - btrfs_item_key_to_cpu(path->nodes[0], &key, - path->slots[0]); - if (key.objectid == bytenr && - (key.type == BTRFS_METADATA_ITEM_KEY || - (key.type == BTRFS_EXTENT_ITEM_KEY && - key.offset == blocksize))) - ret = 0; - } - - if (ret) { - skinny = false; - btrfs_release_path(path); - goto again; - } - } - BUG_ON(ret); - - ret = add_tree_block(rc, &key, path, blocks); -out: - btrfs_free_path(path); - return ret; -} - -/* - * helper to check if the block use full backrefs for pointers in it - */ -static int block_use_full_backref(struct reloc_control *rc, - struct extent_buffer *eb) -{ - u64 flags; - int ret; - - if (btrfs_header_flag(eb, BTRFS_HEADER_FLAG_RELOC) || - btrfs_header_backref_rev(eb) < BTRFS_MIXED_BACKREF_REV) - return 1; - - ret = btrfs_lookup_extent_info(NULL, rc->extent_root, - eb->start, btrfs_header_level(eb), 1, - NULL, &flags); - BUG_ON(ret); - - if (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF) - ret = 1; - else - ret = 0; - return ret; -} - -static int delete_block_group_cache(struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, - struct inode *inode, - u64 ino) -{ - struct btrfs_key key; - struct btrfs_root *root = fs_info->tree_root; - struct btrfs_trans_handle *trans; - int ret = 0; - - if (inode) - goto truncate; - - key.objectid = ino; - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - - inode = btrfs_iget(fs_info->sb, &key, root, NULL); - if (IS_ERR(inode) || is_bad_inode(inode)) { - if (!IS_ERR(inode)) - iput(inode); - return -ENOENT; - } - -truncate: - ret = btrfs_check_trunc_cache_free_space(root, - &fs_info->global_block_rsv); - if (ret) - goto out; - - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out; - } - - ret = btrfs_truncate_free_space_cache(root, trans, block_group, inode); - - btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(root); -out: - iput(inode); - return ret; -} - -/* - * helper to add tree blocks for backref of type BTRFS_EXTENT_DATA_REF_KEY - * this function scans fs tree to find blocks reference the data extent - */ -static int find_data_references(struct reloc_control *rc, - struct btrfs_key *extent_key, - struct extent_buffer *leaf, - struct btrfs_extent_data_ref *ref, - struct rb_root *blocks) -{ - struct btrfs_path *path; - struct tree_block *block; - struct btrfs_root *root; - struct btrfs_file_extent_item *fi; - struct rb_node *rb_node; - struct btrfs_key key; - u64 ref_root; - u64 ref_objectid; - u64 ref_offset; - u32 ref_count; - u32 nritems; - int err = 0; - int added = 0; - int counted; - int ret; - - ref_root = btrfs_extent_data_ref_root(leaf, ref); - ref_objectid = btrfs_extent_data_ref_objectid(leaf, ref); - ref_offset = btrfs_extent_data_ref_offset(leaf, ref); - ref_count = btrfs_extent_data_ref_count(leaf, ref); - - /* - * This is an extent belonging to the free space cache, lets just delete - * it and redo the search. - */ - if (ref_root == BTRFS_ROOT_TREE_OBJECTID) { - ret = delete_block_group_cache(rc->extent_root->fs_info, - rc->block_group, - NULL, ref_objectid); - if (ret != -ENOENT) - return ret; - ret = 0; - } - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->reada = READA_FORWARD; - - root = read_fs_root(rc->extent_root->fs_info, ref_root); - if (IS_ERR(root)) { - err = PTR_ERR(root); - goto out; - } - - key.objectid = ref_objectid; - key.type = BTRFS_EXTENT_DATA_KEY; - if (ref_offset > ((u64)-1 << 32)) - key.offset = 0; - else - key.offset = ref_offset; - - path->search_commit_root = 1; - path->skip_locking = 1; - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) { - err = ret; - goto out; - } - - leaf = path->nodes[0]; - nritems = btrfs_header_nritems(leaf); - /* - * the references in tree blocks that use full backrefs - * are not counted in - */ - if (block_use_full_backref(rc, leaf)) - counted = 0; - else - counted = 1; - rb_node = tree_search(blocks, leaf->start); - if (rb_node) { - if (counted) - added = 1; - else - path->slots[0] = nritems; - } - - while (ref_count > 0) { - while (path->slots[0] >= nritems) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) { - err = ret; - goto out; - } - if (WARN_ON(ret > 0)) - goto out; - - leaf = path->nodes[0]; - nritems = btrfs_header_nritems(leaf); - added = 0; - - if (block_use_full_backref(rc, leaf)) - counted = 0; - else - counted = 1; - rb_node = tree_search(blocks, leaf->start); - if (rb_node) { - if (counted) - added = 1; - else - path->slots[0] = nritems; - } - } - - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - if (WARN_ON(key.objectid != ref_objectid || - key.type != BTRFS_EXTENT_DATA_KEY)) - break; - - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - - if (btrfs_file_extent_type(leaf, fi) == - BTRFS_FILE_EXTENT_INLINE) - goto next; - - if (btrfs_file_extent_disk_bytenr(leaf, fi) != - extent_key->objectid) - goto next; - - key.offset -= btrfs_file_extent_offset(leaf, fi); - if (key.offset != ref_offset) - goto next; - - if (counted) - ref_count--; - if (added) - goto next; - - if (!tree_block_processed(leaf->start, rc)) { - block = kmalloc(sizeof(*block), GFP_NOFS); - if (!block) { - err = -ENOMEM; - break; - } - block->bytenr = leaf->start; - btrfs_item_key_to_cpu(leaf, &block->key, 0); - block->level = 0; - block->key_ready = 1; - rb_node = tree_insert(blocks, block->bytenr, - &block->rb_node); - if (rb_node) - backref_tree_panic(rb_node, -EEXIST, - block->bytenr); - } - if (counted) - added = 1; - else - path->slots[0] = nritems; -next: - path->slots[0]++; - - } -out: - btrfs_free_path(path); - return err; -} - -/* - * helper to find all tree blocks that reference a given data extent - */ -static noinline_for_stack -int add_data_references(struct reloc_control *rc, - struct btrfs_key *extent_key, - struct btrfs_path *path, - struct rb_root *blocks) -{ - struct btrfs_key key; - struct extent_buffer *eb; - struct btrfs_extent_data_ref *dref; - struct btrfs_extent_inline_ref *iref; - unsigned long ptr; - unsigned long end; - u32 blocksize = rc->extent_root->nodesize; - int ret = 0; - int err = 0; - - eb = path->nodes[0]; - ptr = btrfs_item_ptr_offset(eb, path->slots[0]); - end = ptr + btrfs_item_size_nr(eb, path->slots[0]); -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (ptr + sizeof(struct btrfs_extent_item_v0) == end) - ptr = end; - else -#endif - ptr += sizeof(struct btrfs_extent_item); - - while (ptr < end) { - iref = (struct btrfs_extent_inline_ref *)ptr; - key.type = btrfs_extent_inline_ref_type(eb, iref); - if (key.type == BTRFS_SHARED_DATA_REF_KEY) { - key.offset = btrfs_extent_inline_ref_offset(eb, iref); - ret = __add_tree_block(rc, key.offset, blocksize, - blocks); - } else if (key.type == BTRFS_EXTENT_DATA_REF_KEY) { - dref = (struct btrfs_extent_data_ref *)(&iref->offset); - ret = find_data_references(rc, extent_key, - eb, dref, blocks); - } else { - BUG(); - } - if (ret) { - err = ret; - goto out; - } - ptr += btrfs_extent_inline_ref_size(key.type); - } - WARN_ON(ptr > end); - - while (1) { - cond_resched(); - eb = path->nodes[0]; - if (path->slots[0] >= btrfs_header_nritems(eb)) { - ret = btrfs_next_leaf(rc->extent_root, path); - if (ret < 0) { - err = ret; - break; - } - if (ret > 0) - break; - eb = path->nodes[0]; - } - - btrfs_item_key_to_cpu(eb, &key, path->slots[0]); - if (key.objectid != extent_key->objectid) - break; - -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - if (key.type == BTRFS_SHARED_DATA_REF_KEY || - key.type == BTRFS_EXTENT_REF_V0_KEY) { -#else - BUG_ON(key.type == BTRFS_EXTENT_REF_V0_KEY); - if (key.type == BTRFS_SHARED_DATA_REF_KEY) { -#endif - ret = __add_tree_block(rc, key.offset, blocksize, - blocks); - } else if (key.type == BTRFS_EXTENT_DATA_REF_KEY) { - dref = btrfs_item_ptr(eb, path->slots[0], - struct btrfs_extent_data_ref); - ret = find_data_references(rc, extent_key, - eb, dref, blocks); - } else { - ret = 0; - } - if (ret) { - err = ret; - break; - } - path->slots[0]++; - } -out: - btrfs_release_path(path); - if (err) - free_block_list(blocks); - return err; -} - -/* - * helper to find next unprocessed extent - */ -static noinline_for_stack -int find_next_extent(struct reloc_control *rc, struct btrfs_path *path, - struct btrfs_key *extent_key) -{ - struct btrfs_key key; - struct extent_buffer *leaf; - u64 start, end, last; - int ret; - - last = rc->block_group->key.objectid + rc->block_group->key.offset; - while (1) { - cond_resched(); - if (rc->search_start >= last) { - ret = 1; - break; - } - - key.objectid = rc->search_start; - key.type = BTRFS_EXTENT_ITEM_KEY; - key.offset = 0; - - path->search_commit_root = 1; - path->skip_locking = 1; - ret = btrfs_search_slot(NULL, rc->extent_root, &key, path, - 0, 0); - if (ret < 0) - break; -next: - leaf = path->nodes[0]; - if (path->slots[0] >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(rc->extent_root, path); - if (ret != 0) - break; - leaf = path->nodes[0]; - } - - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - if (key.objectid >= last) { - ret = 1; - break; - } - - if (key.type != BTRFS_EXTENT_ITEM_KEY && - key.type != BTRFS_METADATA_ITEM_KEY) { - path->slots[0]++; - goto next; - } - - if (key.type == BTRFS_EXTENT_ITEM_KEY && - key.objectid + key.offset <= rc->search_start) { - path->slots[0]++; - goto next; - } - - if (key.type == BTRFS_METADATA_ITEM_KEY && - key.objectid + rc->extent_root->nodesize <= - rc->search_start) { - path->slots[0]++; - goto next; - } - - ret = find_first_extent_bit(&rc->processed_blocks, - key.objectid, &start, &end, - EXTENT_DIRTY, NULL); - - if (ret == 0 && start <= key.objectid) { - btrfs_release_path(path); - rc->search_start = end + 1; - } else { - if (key.type == BTRFS_EXTENT_ITEM_KEY) - rc->search_start = key.objectid + key.offset; - else - rc->search_start = key.objectid + - rc->extent_root->nodesize; - memcpy(extent_key, &key, sizeof(key)); - return 0; - } - } - btrfs_release_path(path); - return ret; -} - -static void set_reloc_control(struct reloc_control *rc) -{ - struct btrfs_fs_info *fs_info = rc->extent_root->fs_info; - - mutex_lock(&fs_info->reloc_mutex); - fs_info->reloc_ctl = rc; - mutex_unlock(&fs_info->reloc_mutex); -} - -static void unset_reloc_control(struct reloc_control *rc) -{ - struct btrfs_fs_info *fs_info = rc->extent_root->fs_info; - - mutex_lock(&fs_info->reloc_mutex); - fs_info->reloc_ctl = NULL; - mutex_unlock(&fs_info->reloc_mutex); -} - -static int check_extent_flags(u64 flags) -{ - if ((flags & BTRFS_EXTENT_FLAG_DATA) && - (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)) - return 1; - if (!(flags & BTRFS_EXTENT_FLAG_DATA) && - !(flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)) - return 1; - if ((flags & BTRFS_EXTENT_FLAG_DATA) && - (flags & BTRFS_BLOCK_FLAG_FULL_BACKREF)) - return 1; - return 0; -} - -static noinline_for_stack -int prepare_to_relocate(struct reloc_control *rc) -{ - struct btrfs_trans_handle *trans; - int ret; - - rc->block_rsv = btrfs_alloc_block_rsv(rc->extent_root, - BTRFS_BLOCK_RSV_TEMP); - if (!rc->block_rsv) - return -ENOMEM; - - memset(&rc->cluster, 0, sizeof(rc->cluster)); - rc->search_start = rc->block_group->key.objectid; - rc->extents_found = 0; - rc->nodes_relocated = 0; - rc->merging_rsv_size = 0; - rc->reserved_bytes = 0; - rc->block_rsv->size = rc->extent_root->nodesize * - RELOCATION_RESERVED_NODES; - ret = btrfs_block_rsv_refill(rc->extent_root, - rc->block_rsv, rc->block_rsv->size, - BTRFS_RESERVE_FLUSH_ALL); - if (ret) - return ret; - - rc->create_reloc_tree = 1; - set_reloc_control(rc); - - trans = btrfs_join_transaction(rc->extent_root); - if (IS_ERR(trans)) { - unset_reloc_control(rc); - /* - * extent tree is not a ref_cow tree and has no reloc_root to - * cleanup. And callers are responsible to free the above - * block rsv. - */ - return PTR_ERR(trans); - } - btrfs_commit_transaction(trans, rc->extent_root); - return 0; -} - -/* - * Qgroup fixer for data chunk relocation. - * The data relocation is done in the following steps - * 1) Copy data extents into data reloc tree - * 2) Create tree reloc tree(special snapshot) for related subvolumes - * 3) Modify file extents in tree reloc tree - * 4) Merge tree reloc tree with original fs tree, by swapping tree blocks - * - * The problem is, data and tree reloc tree are not accounted to qgroup, - * and 4) will only info qgroup to track tree blocks change, not file extents - * in the tree blocks. - * - * The good news is, related data extents are all in data reloc tree, so we - * only need to info qgroup to track all file extents in data reloc tree - * before commit trans. - */ -static int qgroup_fix_relocated_data_extents(struct btrfs_trans_handle *trans, - struct reloc_control *rc) -{ - struct btrfs_fs_info *fs_info = rc->extent_root->fs_info; - struct inode *inode = rc->data_inode; - struct btrfs_root *data_reloc_root = BTRFS_I(inode)->root; - struct btrfs_path *path; - struct btrfs_key key; - int ret = 0; - - if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) - return 0; - - /* - * Only for stage where we update data pointers the qgroup fix is - * valid. - * For MOVING_DATA stage, we will miss the timing of swapping tree - * blocks, and won't fix it. - */ - if (!(rc->stage == UPDATE_DATA_PTRS && rc->extents_found)) - return 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - key.objectid = btrfs_ino(inode); - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = 0; - - ret = btrfs_search_slot(NULL, data_reloc_root, &key, path, 0, 0); - if (ret < 0) - goto out; - - lock_extent(&BTRFS_I(inode)->io_tree, 0, (u64)-1); - while (1) { - struct btrfs_file_extent_item *fi; - - btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); - if (key.objectid > btrfs_ino(inode)) - break; - if (key.type != BTRFS_EXTENT_DATA_KEY) - goto next; - fi = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_file_extent_item); - if (btrfs_file_extent_type(path->nodes[0], fi) != - BTRFS_FILE_EXTENT_REG) - goto next; - ret = btrfs_qgroup_insert_dirty_extent(trans, fs_info, - btrfs_file_extent_disk_bytenr(path->nodes[0], fi), - btrfs_file_extent_disk_num_bytes(path->nodes[0], fi), - GFP_NOFS); - if (ret < 0) - break; -next: - ret = btrfs_next_item(data_reloc_root, path); - if (ret < 0) - break; - if (ret > 0) { - ret = 0; - break; - } - } - unlock_extent(&BTRFS_I(inode)->io_tree, 0 , (u64)-1); -out: - btrfs_free_path(path); - return ret; -} - -static noinline_for_stack int relocate_block_group(struct reloc_control *rc) -{ - struct rb_root blocks = RB_ROOT; - struct btrfs_key key; - struct btrfs_trans_handle *trans = NULL; - struct btrfs_path *path; - struct btrfs_extent_item *ei; - u64 flags; - u32 item_size; - int ret; - int err = 0; - int progress = 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->reada = READA_FORWARD; - - ret = prepare_to_relocate(rc); - if (ret) { - err = ret; - goto out_free; - } - - while (1) { - rc->reserved_bytes = 0; - ret = btrfs_block_rsv_refill(rc->extent_root, - rc->block_rsv, rc->block_rsv->size, - BTRFS_RESERVE_FLUSH_ALL); - if (ret) { - err = ret; - break; - } - progress++; - trans = btrfs_start_transaction(rc->extent_root, 0); - if (IS_ERR(trans)) { - err = PTR_ERR(trans); - trans = NULL; - break; - } -restart: - if (update_backref_cache(trans, &rc->backref_cache)) { - btrfs_end_transaction(trans, rc->extent_root); - continue; - } - - ret = find_next_extent(rc, path, &key); - if (ret < 0) - err = ret; - if (ret != 0) - break; - - rc->extents_found++; - - ei = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_extent_item); - item_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]); - if (item_size >= sizeof(*ei)) { - flags = btrfs_extent_flags(path->nodes[0], ei); - ret = check_extent_flags(flags); - BUG_ON(ret); - - } else { -#ifdef BTRFS_COMPAT_EXTENT_TREE_V0 - u64 ref_owner; - int path_change = 0; - - BUG_ON(item_size != - sizeof(struct btrfs_extent_item_v0)); - ret = get_ref_objectid_v0(rc, path, &key, &ref_owner, - &path_change); - if (ret < 0) { - err = ret; - break; - } - if (ref_owner < BTRFS_FIRST_FREE_OBJECTID) - flags = BTRFS_EXTENT_FLAG_TREE_BLOCK; - else - flags = BTRFS_EXTENT_FLAG_DATA; - - if (path_change) { - btrfs_release_path(path); - - path->search_commit_root = 1; - path->skip_locking = 1; - ret = btrfs_search_slot(NULL, rc->extent_root, - &key, path, 0, 0); - if (ret < 0) { - err = ret; - break; - } - BUG_ON(ret > 0); - } -#else - BUG(); -#endif - } - - if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { - ret = add_tree_block(rc, &key, path, &blocks); - } else if (rc->stage == UPDATE_DATA_PTRS && - (flags & BTRFS_EXTENT_FLAG_DATA)) { - ret = add_data_references(rc, &key, path, &blocks); - } else { - btrfs_release_path(path); - ret = 0; - } - if (ret < 0) { - err = ret; - break; - } - - if (!RB_EMPTY_ROOT(&blocks)) { - ret = relocate_tree_blocks(trans, rc, &blocks); - if (ret < 0) { - /* - * if we fail to relocate tree blocks, force to update - * backref cache when committing transaction. - */ - rc->backref_cache.last_trans = trans->transid - 1; - - if (ret != -EAGAIN) { - err = ret; - break; - } - rc->extents_found--; - rc->search_start = key.objectid; - } - } - - btrfs_end_transaction_throttle(trans, rc->extent_root); - btrfs_btree_balance_dirty(rc->extent_root); - trans = NULL; - - if (rc->stage == MOVE_DATA_EXTENTS && - (flags & BTRFS_EXTENT_FLAG_DATA)) { - rc->found_file_extent = 1; - ret = relocate_data_extent(rc->data_inode, - &key, &rc->cluster); - if (ret < 0) { - err = ret; - break; - } - } - } - if (trans && progress && err == -ENOSPC) { - ret = btrfs_force_chunk_alloc(trans, rc->extent_root, - rc->block_group->flags); - if (ret == 1) { - err = 0; - progress = 0; - goto restart; - } - } - - btrfs_release_path(path); - clear_extent_bits(&rc->processed_blocks, 0, (u64)-1, EXTENT_DIRTY); - - if (trans) { - btrfs_end_transaction_throttle(trans, rc->extent_root); - btrfs_btree_balance_dirty(rc->extent_root); - } - - if (!err) { - ret = relocate_file_extent_cluster(rc->data_inode, - &rc->cluster); - if (ret < 0) - err = ret; - } - - rc->create_reloc_tree = 0; - set_reloc_control(rc); - - backref_cache_cleanup(&rc->backref_cache); - btrfs_block_rsv_release(rc->extent_root, rc->block_rsv, (u64)-1); - - err = prepare_to_merge(rc, err); - - merge_reloc_roots(rc); - - rc->merge_reloc_tree = 0; - unset_reloc_control(rc); - btrfs_block_rsv_release(rc->extent_root, rc->block_rsv, (u64)-1); - - /* get rid of pinned extents */ - trans = btrfs_join_transaction(rc->extent_root); - if (IS_ERR(trans)) { - err = PTR_ERR(trans); - goto out_free; - } - ret = qgroup_fix_relocated_data_extents(trans, rc); - if (ret < 0) { - btrfs_abort_transaction(trans, ret); - if (!err) - err = ret; - goto out_free; - } - btrfs_commit_transaction(trans, rc->extent_root); -out_free: - btrfs_free_block_rsv(rc->extent_root, rc->block_rsv); - btrfs_free_path(path); - return err; -} - -static int __insert_orphan_inode(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 objectid) -{ - struct btrfs_path *path; - struct btrfs_inode_item *item; - struct extent_buffer *leaf; - int ret; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - ret = btrfs_insert_empty_inode(trans, root, path, objectid); - if (ret) - goto out; - - leaf = path->nodes[0]; - item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_inode_item); - memset_extent_buffer(leaf, 0, (unsigned long)item, sizeof(*item)); - btrfs_set_inode_generation(leaf, item, 1); - btrfs_set_inode_size(leaf, item, 0); - btrfs_set_inode_mode(leaf, item, S_IFREG | 0600); - btrfs_set_inode_flags(leaf, item, BTRFS_INODE_NOCOMPRESS | - BTRFS_INODE_PREALLOC); - btrfs_mark_buffer_dirty(leaf); -out: - btrfs_free_path(path); - return ret; -} - -/* - * helper to create inode for data relocation. - * the inode is in data relocation tree and its link count is 0 - */ -static noinline_for_stack -struct inode *create_reloc_inode(struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *group) -{ - struct inode *inode = NULL; - struct btrfs_trans_handle *trans; - struct btrfs_root *root; - struct btrfs_key key; - u64 objectid; - int err = 0; - - root = read_fs_root(fs_info, BTRFS_DATA_RELOC_TREE_OBJECTID); - if (IS_ERR(root)) - return ERR_CAST(root); - - trans = btrfs_start_transaction(root, 6); - if (IS_ERR(trans)) - return ERR_CAST(trans); - - err = btrfs_find_free_objectid(root, &objectid); - if (err) - goto out; - - err = __insert_orphan_inode(trans, root, objectid); - BUG_ON(err); - - key.objectid = objectid; - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - inode = btrfs_iget(root->fs_info->sb, &key, root, NULL); - BUG_ON(IS_ERR(inode) || is_bad_inode(inode)); - BTRFS_I(inode)->index_cnt = group->key.objectid; - - err = btrfs_orphan_add(trans, inode); -out: - btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(root); - if (err) { - if (inode) - iput(inode); - inode = ERR_PTR(err); - } - return inode; -} - -static struct reloc_control *alloc_reloc_control(struct btrfs_fs_info *fs_info) -{ - struct reloc_control *rc; - - rc = kzalloc(sizeof(*rc), GFP_NOFS); - if (!rc) - return NULL; - - INIT_LIST_HEAD(&rc->reloc_roots); - backref_cache_init(&rc->backref_cache); - mapping_tree_init(&rc->reloc_root_tree); - extent_io_tree_init(&rc->processed_blocks, - fs_info->btree_inode->i_mapping); - return rc; -} - -/* - * function to relocate all extents in a block group. - */ -int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start) -{ - struct btrfs_fs_info *fs_info = extent_root->fs_info; - struct reloc_control *rc; - struct inode *inode; - struct btrfs_path *path; - int ret; - int rw = 0; - int err = 0; - - rc = alloc_reloc_control(fs_info); - if (!rc) - return -ENOMEM; - - rc->extent_root = extent_root; - - rc->block_group = btrfs_lookup_block_group(fs_info, group_start); - BUG_ON(!rc->block_group); - - ret = btrfs_inc_block_group_ro(extent_root, rc->block_group); - if (ret) { - err = ret; - goto out; - } - rw = 1; - - path = btrfs_alloc_path(); - if (!path) { - err = -ENOMEM; - goto out; - } - - inode = lookup_free_space_inode(fs_info->tree_root, rc->block_group, - path); - btrfs_free_path(path); - - if (!IS_ERR(inode)) - ret = delete_block_group_cache(fs_info, rc->block_group, inode, 0); - else - ret = PTR_ERR(inode); - - if (ret && ret != -ENOENT) { - err = ret; - goto out; - } - - rc->data_inode = create_reloc_inode(fs_info, rc->block_group); - if (IS_ERR(rc->data_inode)) { - err = PTR_ERR(rc->data_inode); - rc->data_inode = NULL; - goto out; - } - - btrfs_info(extent_root->fs_info, - "relocating block group %llu flags %llu", - rc->block_group->key.objectid, rc->block_group->flags); - - btrfs_wait_block_group_reservations(rc->block_group); - btrfs_wait_nocow_writers(rc->block_group); - btrfs_wait_ordered_roots(fs_info, -1, - rc->block_group->key.objectid, - rc->block_group->key.offset); - - while (1) { - mutex_lock(&fs_info->cleaner_mutex); - ret = relocate_block_group(rc); - mutex_unlock(&fs_info->cleaner_mutex); - if (ret < 0) { - err = ret; - goto out; - } - - if (rc->extents_found == 0) - break; - - btrfs_info(extent_root->fs_info, "found %llu extents", - rc->extents_found); - - if (rc->stage == MOVE_DATA_EXTENTS && rc->found_file_extent) { - ret = btrfs_wait_ordered_range(rc->data_inode, 0, - (u64)-1); - if (ret) { - err = ret; - goto out; - } - invalidate_mapping_pages(rc->data_inode->i_mapping, - 0, -1); - rc->stage = UPDATE_DATA_PTRS; - } - } - - WARN_ON(rc->block_group->pinned > 0); - WARN_ON(rc->block_group->reserved > 0); - WARN_ON(btrfs_block_group_used(&rc->block_group->item) > 0); -out: - if (err && rw) - btrfs_dec_block_group_ro(extent_root, rc->block_group); - iput(rc->data_inode); - btrfs_put_block_group(rc->block_group); - kfree(rc); - return err; -} - -static noinline_for_stack int mark_garbage_root(struct btrfs_root *root) -{ - struct btrfs_trans_handle *trans; - int ret, err; - - trans = btrfs_start_transaction(root->fs_info->tree_root, 0); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - memset(&root->root_item.drop_progress, 0, - sizeof(root->root_item.drop_progress)); - root->root_item.drop_level = 0; - btrfs_set_root_refs(&root->root_item, 0); - ret = btrfs_update_root(trans, root->fs_info->tree_root, - &root->root_key, &root->root_item); - - err = btrfs_end_transaction(trans, root->fs_info->tree_root); - if (err) - return err; - return ret; -} - -/* - * recover relocation interrupted by system crash. - * - * this function resumes merging reloc trees with corresponding fs trees. - * this is important for keeping the sharing of tree blocks - */ -int btrfs_recover_relocation(struct btrfs_root *root) -{ - LIST_HEAD(reloc_roots); - struct btrfs_key key; - struct btrfs_root *fs_root; - struct btrfs_root *reloc_root; - struct btrfs_path *path; - struct extent_buffer *leaf; - struct reloc_control *rc = NULL; - struct btrfs_trans_handle *trans; - int ret; - int err = 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->reada = READA_BACK; - - key.objectid = BTRFS_TREE_RELOC_OBJECTID; - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = (u64)-1; - - while (1) { - ret = btrfs_search_slot(NULL, root->fs_info->tree_root, &key, - path, 0, 0); - if (ret < 0) { - err = ret; - goto out; - } - if (ret > 0) { - if (path->slots[0] == 0) - break; - path->slots[0]--; - } - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - btrfs_release_path(path); - - if (key.objectid != BTRFS_TREE_RELOC_OBJECTID || - key.type != BTRFS_ROOT_ITEM_KEY) - break; - - reloc_root = btrfs_read_fs_root(root, &key); - if (IS_ERR(reloc_root)) { - err = PTR_ERR(reloc_root); - goto out; - } - - list_add(&reloc_root->root_list, &reloc_roots); - - if (btrfs_root_refs(&reloc_root->root_item) > 0) { - fs_root = read_fs_root(root->fs_info, - reloc_root->root_key.offset); - if (IS_ERR(fs_root)) { - ret = PTR_ERR(fs_root); - if (ret != -ENOENT) { - err = ret; - goto out; - } - ret = mark_garbage_root(reloc_root); - if (ret < 0) { - err = ret; - goto out; - } - } - } - - if (key.offset == 0) - break; - - key.offset--; - } - btrfs_release_path(path); - - if (list_empty(&reloc_roots)) - goto out; - - rc = alloc_reloc_control(root->fs_info); - if (!rc) { - err = -ENOMEM; - goto out; - } - - rc->extent_root = root->fs_info->extent_root; - - set_reloc_control(rc); - - trans = btrfs_join_transaction(rc->extent_root); - if (IS_ERR(trans)) { - unset_reloc_control(rc); - err = PTR_ERR(trans); - goto out_free; - } - - rc->merge_reloc_tree = 1; - - while (!list_empty(&reloc_roots)) { - reloc_root = list_entry(reloc_roots.next, - struct btrfs_root, root_list); - list_del(&reloc_root->root_list); - - if (btrfs_root_refs(&reloc_root->root_item) == 0) { - list_add_tail(&reloc_root->root_list, - &rc->reloc_roots); - continue; - } - - fs_root = read_fs_root(root->fs_info, - reloc_root->root_key.offset); - if (IS_ERR(fs_root)) { - err = PTR_ERR(fs_root); - goto out_free; - } - - err = __add_reloc_root(reloc_root); - BUG_ON(err < 0); /* -ENOMEM or logic error */ - fs_root->reloc_root = reloc_root; - } - - err = btrfs_commit_transaction(trans, rc->extent_root); - if (err) - goto out_free; - - merge_reloc_roots(rc); - - unset_reloc_control(rc); - - trans = btrfs_join_transaction(rc->extent_root); - if (IS_ERR(trans)) { - err = PTR_ERR(trans); - goto out_free; - } - err = qgroup_fix_relocated_data_extents(trans, rc); - if (err < 0) { - btrfs_abort_transaction(trans, err); - goto out_free; - } - err = btrfs_commit_transaction(trans, rc->extent_root); -out_free: - kfree(rc); -out: - if (!list_empty(&reloc_roots)) - free_reloc_roots(&reloc_roots); - - btrfs_free_path(path); - - if (err == 0) { - /* cleanup orphan inode in data relocation tree */ - fs_root = read_fs_root(root->fs_info, - BTRFS_DATA_RELOC_TREE_OBJECTID); - if (IS_ERR(fs_root)) - err = PTR_ERR(fs_root); - else - err = btrfs_orphan_cleanup(fs_root); - } - return err; -} - -/* - * helper to add ordered checksum for data relocation. - * - * cloning checksum properly handles the nodatasum extents. - * it also saves CPU time to re-calculate the checksum. - */ -int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len) -{ - struct btrfs_ordered_sum *sums; - struct btrfs_ordered_extent *ordered; - struct btrfs_root *root = BTRFS_I(inode)->root; - int ret; - u64 disk_bytenr; - u64 new_bytenr; - LIST_HEAD(list); - - ordered = btrfs_lookup_ordered_extent(inode, file_pos); - BUG_ON(ordered->file_offset != file_pos || ordered->len != len); - - disk_bytenr = file_pos + BTRFS_I(inode)->index_cnt; - ret = btrfs_lookup_csums_range(root->fs_info->csum_root, disk_bytenr, - disk_bytenr + len - 1, &list, 0); - if (ret) - goto out; - - while (!list_empty(&list)) { - sums = list_entry(list.next, struct btrfs_ordered_sum, list); - list_del_init(&sums->list); - - /* - * We need to offset the new_bytenr based on where the csum is. - * We need to do this because we will read in entire prealloc - * extents but we may have written to say the middle of the - * prealloc extent, so we need to make sure the csum goes with - * the right disk offset. - * - * We can do this because the data reloc inode refers strictly - * to the on disk bytes, so we don't have to worry about - * disk_len vs real len like with real inodes since it's all - * disk length. - */ - new_bytenr = ordered->start + (sums->bytenr - disk_bytenr); - sums->bytenr = new_bytenr; - - btrfs_add_ordered_sum(inode, ordered, sums); - } -out: - btrfs_put_ordered_extent(ordered); - return ret; -} - -int btrfs_reloc_cow_block(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct extent_buffer *buf, - struct extent_buffer *cow) -{ - struct reloc_control *rc; - struct backref_node *node; - int first_cow = 0; - int level; - int ret = 0; - - rc = root->fs_info->reloc_ctl; - if (!rc) - return 0; - - BUG_ON(rc->stage == UPDATE_DATA_PTRS && - root->root_key.objectid == BTRFS_DATA_RELOC_TREE_OBJECTID); - - if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID) { - if (buf == root->node) - __update_reloc_root(root, cow->start); - } - - level = btrfs_header_level(buf); - if (btrfs_header_generation(buf) <= - btrfs_root_last_snapshot(&root->root_item)) - first_cow = 1; - - if (root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID && - rc->create_reloc_tree) { - WARN_ON(!first_cow && level == 0); - - node = rc->backref_cache.path[level]; - BUG_ON(node->bytenr != buf->start && - node->new_bytenr != buf->start); - - drop_node_buffer(node); - extent_buffer_get(cow); - node->eb = cow; - node->new_bytenr = cow->start; - - if (!node->pending) { - list_move_tail(&node->list, - &rc->backref_cache.pending[level]); - node->pending = 1; - } - - if (first_cow) - __mark_block_processed(rc, node); - - if (first_cow && level > 0) - rc->nodes_relocated += buf->len; - } - - if (level == 0 && first_cow && rc->stage == UPDATE_DATA_PTRS) - ret = replace_file_extents(trans, rc, root, cow); - return ret; -} - -/* - * called before creating snapshot. it calculates metadata reservation - * required for relocating tree blocks in the snapshot - */ -void btrfs_reloc_pre_snapshot(struct btrfs_pending_snapshot *pending, - u64 *bytes_to_reserve) -{ - struct btrfs_root *root; - struct reloc_control *rc; - - root = pending->root; - if (!root->reloc_root) - return; - - rc = root->fs_info->reloc_ctl; - if (!rc->merge_reloc_tree) - return; - - root = root->reloc_root; - BUG_ON(btrfs_root_refs(&root->root_item) == 0); - /* - * relocation is in the stage of merging trees. the space - * used by merging a reloc tree is twice the size of - * relocated tree nodes in the worst case. half for cowing - * the reloc tree, half for cowing the fs tree. the space - * used by cowing the reloc tree will be freed after the - * tree is dropped. if we create snapshot, cowing the fs - * tree may use more space than it frees. so we need - * reserve extra space. - */ - *bytes_to_reserve += rc->nodes_relocated; -} - -/* - * called after snapshot is created. migrate block reservation - * and create reloc root for the newly created snapshot - */ -int btrfs_reloc_post_snapshot(struct btrfs_trans_handle *trans, - struct btrfs_pending_snapshot *pending) -{ - struct btrfs_root *root = pending->root; - struct btrfs_root *reloc_root; - struct btrfs_root *new_root; - struct reloc_control *rc; - int ret; - - if (!root->reloc_root) - return 0; - - rc = root->fs_info->reloc_ctl; - rc->merging_rsv_size += rc->nodes_relocated; - - if (rc->merge_reloc_tree) { - ret = btrfs_block_rsv_migrate(&pending->block_rsv, - rc->block_rsv, - rc->nodes_relocated, 1); - if (ret) - return ret; - } - - new_root = pending->snap; - reloc_root = create_reloc_root(trans, root->reloc_root, - new_root->root_key.objectid); - if (IS_ERR(reloc_root)) - return PTR_ERR(reloc_root); - - ret = __add_reloc_root(reloc_root); - BUG_ON(ret < 0); - new_root->reloc_root = reloc_root; - - if (rc->create_reloc_tree) - ret = clone_backref_node(trans, rc, root, reloc_root); - return ret; -} diff --git a/src/linux/fs/btrfs/root-tree.c b/src/linux/fs/btrfs/root-tree.c deleted file mode 100644 index edae751..0000000 --- a/src/linux/fs/btrfs/root-tree.c +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include "ctree.h" -#include "transaction.h" -#include "disk-io.h" -#include "print-tree.h" - -/* - * Read a root item from the tree. In case we detect a root item smaller then - * sizeof(root_item), we know it's an old version of the root structure and - * initialize all new fields to zero. The same happens if we detect mismatching - * generation numbers as then we know the root was once mounted with an older - * kernel that was not aware of the root item structure change. - */ -static void btrfs_read_root_item(struct extent_buffer *eb, int slot, - struct btrfs_root_item *item) -{ - uuid_le uuid; - int len; - int need_reset = 0; - - len = btrfs_item_size_nr(eb, slot); - read_extent_buffer(eb, item, btrfs_item_ptr_offset(eb, slot), - min_t(int, len, (int)sizeof(*item))); - if (len < sizeof(*item)) - need_reset = 1; - if (!need_reset && btrfs_root_generation(item) - != btrfs_root_generation_v2(item)) { - if (btrfs_root_generation_v2(item) != 0) { - btrfs_warn(eb->fs_info, - "mismatching generation and generation_v2 found in root item. This root was probably mounted with an older kernel. Resetting all new fields."); - } - need_reset = 1; - } - if (need_reset) { - memset(&item->generation_v2, 0, - sizeof(*item) - offsetof(struct btrfs_root_item, - generation_v2)); - - uuid_le_gen(&uuid); - memcpy(item->uuid, uuid.b, BTRFS_UUID_SIZE); - } -} - -/* - * btrfs_find_root - lookup the root by the key. - * root: the root of the root tree - * search_key: the key to search - * path: the path we search - * root_item: the root item of the tree we look for - * root_key: the root key of the tree we look for - * - * If ->offset of 'search_key' is -1ULL, it means we are not sure the offset - * of the search key, just lookup the root with the highest offset for a - * given objectid. - * - * If we find something return 0, otherwise > 0, < 0 on error. - */ -int btrfs_find_root(struct btrfs_root *root, struct btrfs_key *search_key, - struct btrfs_path *path, struct btrfs_root_item *root_item, - struct btrfs_key *root_key) -{ - struct btrfs_key found_key; - struct extent_buffer *l; - int ret; - int slot; - - ret = btrfs_search_slot(NULL, root, search_key, path, 0, 0); - if (ret < 0) - return ret; - - if (search_key->offset != -1ULL) { /* the search key is exact */ - if (ret > 0) - goto out; - } else { - BUG_ON(ret == 0); /* Logical error */ - if (path->slots[0] == 0) - goto out; - path->slots[0]--; - ret = 0; - } - - l = path->nodes[0]; - slot = path->slots[0]; - - btrfs_item_key_to_cpu(l, &found_key, slot); - if (found_key.objectid != search_key->objectid || - found_key.type != BTRFS_ROOT_ITEM_KEY) { - ret = 1; - goto out; - } - - if (root_item) - btrfs_read_root_item(l, slot, root_item); - if (root_key) - memcpy(root_key, &found_key, sizeof(found_key)); -out: - btrfs_release_path(path); - return ret; -} - -void btrfs_set_root_node(struct btrfs_root_item *item, - struct extent_buffer *node) -{ - btrfs_set_root_bytenr(item, node->start); - btrfs_set_root_level(item, btrfs_header_level(node)); - btrfs_set_root_generation(item, btrfs_header_generation(node)); -} - -/* - * copy the data in 'item' into the btree - */ -int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root - *root, struct btrfs_key *key, struct btrfs_root_item - *item) -{ - struct btrfs_path *path; - struct extent_buffer *l; - int ret; - int slot; - unsigned long ptr; - u32 old_len; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - ret = btrfs_search_slot(trans, root, key, path, 0, 1); - if (ret < 0) { - btrfs_abort_transaction(trans, ret); - goto out; - } - - if (ret != 0) { - btrfs_print_leaf(root, path->nodes[0]); - btrfs_crit(root->fs_info, - "unable to update root key %llu %u %llu", - key->objectid, key->type, key->offset); - BUG_ON(1); - } - - l = path->nodes[0]; - slot = path->slots[0]; - ptr = btrfs_item_ptr_offset(l, slot); - old_len = btrfs_item_size_nr(l, slot); - - /* - * If this is the first time we update the root item which originated - * from an older kernel, we need to enlarge the item size to make room - * for the added fields. - */ - if (old_len < sizeof(*item)) { - btrfs_release_path(path); - ret = btrfs_search_slot(trans, root, key, path, - -1, 1); - if (ret < 0) { - btrfs_abort_transaction(trans, ret); - goto out; - } - - ret = btrfs_del_item(trans, root, path); - if (ret < 0) { - btrfs_abort_transaction(trans, ret); - goto out; - } - btrfs_release_path(path); - ret = btrfs_insert_empty_item(trans, root, path, - key, sizeof(*item)); - if (ret < 0) { - btrfs_abort_transaction(trans, ret); - goto out; - } - l = path->nodes[0]; - slot = path->slots[0]; - ptr = btrfs_item_ptr_offset(l, slot); - } - - /* - * Update generation_v2 so at the next mount we know the new root - * fields are valid. - */ - btrfs_set_root_generation_v2(item, btrfs_root_generation(item)); - - write_extent_buffer(l, item, ptr, sizeof(*item)); - btrfs_mark_buffer_dirty(path->nodes[0]); -out: - btrfs_free_path(path); - return ret; -} - -int btrfs_insert_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, - struct btrfs_key *key, struct btrfs_root_item *item) -{ - /* - * Make sure generation v1 and v2 match. See update_root for details. - */ - btrfs_set_root_generation_v2(item, btrfs_root_generation(item)); - return btrfs_insert_item(trans, root, key, item, sizeof(*item)); -} - -int btrfs_find_orphan_roots(struct btrfs_root *tree_root) -{ - struct extent_buffer *leaf; - struct btrfs_path *path; - struct btrfs_key key; - struct btrfs_key root_key; - struct btrfs_root *root; - int err = 0; - int ret; - bool can_recover = true; - - if (tree_root->fs_info->sb->s_flags & MS_RDONLY) - can_recover = false; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - key.objectid = BTRFS_ORPHAN_OBJECTID; - key.type = BTRFS_ORPHAN_ITEM_KEY; - key.offset = 0; - - root_key.type = BTRFS_ROOT_ITEM_KEY; - root_key.offset = (u64)-1; - - while (1) { - ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0); - if (ret < 0) { - err = ret; - break; - } - - leaf = path->nodes[0]; - if (path->slots[0] >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(tree_root, path); - if (ret < 0) - err = ret; - if (ret != 0) - break; - leaf = path->nodes[0]; - } - - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - btrfs_release_path(path); - - if (key.objectid != BTRFS_ORPHAN_OBJECTID || - key.type != BTRFS_ORPHAN_ITEM_KEY) - break; - - root_key.objectid = key.offset; - key.offset++; - - /* - * The root might have been inserted already, as before we look - * for orphan roots, log replay might have happened, which - * triggers a transaction commit and qgroup accounting, which - * in turn reads and inserts fs roots while doing backref - * walking. - */ - root = btrfs_lookup_fs_root(tree_root->fs_info, - root_key.objectid); - if (root) { - WARN_ON(!test_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, - &root->state)); - if (btrfs_root_refs(&root->root_item) == 0) - btrfs_add_dead_root(root); - continue; - } - - root = btrfs_read_fs_root(tree_root, &root_key); - err = PTR_ERR_OR_ZERO(root); - if (err && err != -ENOENT) { - break; - } else if (err == -ENOENT) { - struct btrfs_trans_handle *trans; - - btrfs_release_path(path); - - trans = btrfs_join_transaction(tree_root); - if (IS_ERR(trans)) { - err = PTR_ERR(trans); - btrfs_handle_fs_error(tree_root->fs_info, err, - "Failed to start trans to delete orphan item"); - break; - } - err = btrfs_del_orphan_item(trans, tree_root, - root_key.objectid); - btrfs_end_transaction(trans, tree_root); - if (err) { - btrfs_handle_fs_error(tree_root->fs_info, err, - "Failed to delete root orphan item"); - break; - } - continue; - } - - err = btrfs_init_fs_root(root); - if (err) { - btrfs_free_fs_root(root); - break; - } - - set_bit(BTRFS_ROOT_ORPHAN_ITEM_INSERTED, &root->state); - - err = btrfs_insert_fs_root(root->fs_info, root); - if (err) { - BUG_ON(err == -EEXIST); - btrfs_free_fs_root(root); - break; - } - - if (btrfs_root_refs(&root->root_item) == 0) - btrfs_add_dead_root(root); - } - - btrfs_free_path(path); - return err; -} - -/* drop the root item for 'key' from 'root' */ -int btrfs_del_root(struct btrfs_trans_handle *trans, struct btrfs_root *root, - struct btrfs_key *key) -{ - struct btrfs_path *path; - int ret; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - ret = btrfs_search_slot(trans, root, key, path, -1, 1); - if (ret < 0) - goto out; - - BUG_ON(ret != 0); - - ret = btrfs_del_item(trans, root, path); -out: - btrfs_free_path(path); - return ret; -} - -int btrfs_del_root_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *tree_root, - u64 root_id, u64 ref_id, u64 dirid, u64 *sequence, - const char *name, int name_len) - -{ - struct btrfs_path *path; - struct btrfs_root_ref *ref; - struct extent_buffer *leaf; - struct btrfs_key key; - unsigned long ptr; - int err = 0; - int ret; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - key.objectid = root_id; - key.type = BTRFS_ROOT_BACKREF_KEY; - key.offset = ref_id; -again: - ret = btrfs_search_slot(trans, tree_root, &key, path, -1, 1); - BUG_ON(ret < 0); - if (ret == 0) { - leaf = path->nodes[0]; - ref = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_root_ref); - - WARN_ON(btrfs_root_ref_dirid(leaf, ref) != dirid); - WARN_ON(btrfs_root_ref_name_len(leaf, ref) != name_len); - ptr = (unsigned long)(ref + 1); - WARN_ON(memcmp_extent_buffer(leaf, name, ptr, name_len)); - *sequence = btrfs_root_ref_sequence(leaf, ref); - - ret = btrfs_del_item(trans, tree_root, path); - if (ret) { - err = ret; - goto out; - } - } else - err = -ENOENT; - - if (key.type == BTRFS_ROOT_BACKREF_KEY) { - btrfs_release_path(path); - key.objectid = ref_id; - key.type = BTRFS_ROOT_REF_KEY; - key.offset = root_id; - goto again; - } - -out: - btrfs_free_path(path); - return err; -} - -/* - * add a btrfs_root_ref item. type is either BTRFS_ROOT_REF_KEY - * or BTRFS_ROOT_BACKREF_KEY. - * - * The dirid, sequence, name and name_len refer to the directory entry - * that is referencing the root. - * - * For a forward ref, the root_id is the id of the tree referencing - * the root and ref_id is the id of the subvol or snapshot. - * - * For a back ref the root_id is the id of the subvol or snapshot and - * ref_id is the id of the tree referencing it. - * - * Will return 0, -ENOMEM, or anything from the CoW path - */ -int btrfs_add_root_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *tree_root, - u64 root_id, u64 ref_id, u64 dirid, u64 sequence, - const char *name, int name_len) -{ - struct btrfs_key key; - int ret; - struct btrfs_path *path; - struct btrfs_root_ref *ref; - struct extent_buffer *leaf; - unsigned long ptr; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - key.objectid = root_id; - key.type = BTRFS_ROOT_BACKREF_KEY; - key.offset = ref_id; -again: - ret = btrfs_insert_empty_item(trans, tree_root, path, &key, - sizeof(*ref) + name_len); - if (ret) { - btrfs_abort_transaction(trans, ret); - btrfs_free_path(path); - return ret; - } - - leaf = path->nodes[0]; - ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref); - btrfs_set_root_ref_dirid(leaf, ref, dirid); - btrfs_set_root_ref_sequence(leaf, ref, sequence); - btrfs_set_root_ref_name_len(leaf, ref, name_len); - ptr = (unsigned long)(ref + 1); - write_extent_buffer(leaf, name, ptr, name_len); - btrfs_mark_buffer_dirty(leaf); - - if (key.type == BTRFS_ROOT_BACKREF_KEY) { - btrfs_release_path(path); - key.objectid = ref_id; - key.type = BTRFS_ROOT_REF_KEY; - key.offset = root_id; - goto again; - } - - btrfs_free_path(path); - return 0; -} - -/* - * Old btrfs forgets to init root_item->flags and root_item->byte_limit - * for subvolumes. To work around this problem, we steal a bit from - * root_item->inode_item->flags, and use it to indicate if those fields - * have been properly initialized. - */ -void btrfs_check_and_init_root_item(struct btrfs_root_item *root_item) -{ - u64 inode_flags = btrfs_stack_inode_flags(&root_item->inode); - - if (!(inode_flags & BTRFS_INODE_ROOT_ITEM_INIT)) { - inode_flags |= BTRFS_INODE_ROOT_ITEM_INIT; - btrfs_set_stack_inode_flags(&root_item->inode, inode_flags); - btrfs_set_root_flags(root_item, 0); - btrfs_set_root_limit(root_item, 0); - } -} - -void btrfs_update_root_times(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_root_item *item = &root->root_item; - struct timespec ct = current_fs_time(root->fs_info->sb); - - spin_lock(&root->root_item_lock); - btrfs_set_root_ctransid(item, trans->transid); - btrfs_set_stack_timespec_sec(&item->ctime, ct.tv_sec); - btrfs_set_stack_timespec_nsec(&item->ctime, ct.tv_nsec); - spin_unlock(&root->root_item_lock); -} diff --git a/src/linux/fs/btrfs/scrub.c b/src/linux/fs/btrfs/scrub.c deleted file mode 100644 index fffb9ab..0000000 --- a/src/linux/fs/btrfs/scrub.c +++ /dev/null @@ -1,4457 +0,0 @@ -/* - * Copyright (C) 2011, 2012 STRATO. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include "ctree.h" -#include "volumes.h" -#include "disk-io.h" -#include "ordered-data.h" -#include "transaction.h" -#include "backref.h" -#include "extent_io.h" -#include "dev-replace.h" -#include "check-integrity.h" -#include "rcu-string.h" -#include "raid56.h" - -/* - * This is only the first step towards a full-features scrub. It reads all - * extent and super block and verifies the checksums. In case a bad checksum - * is found or the extent cannot be read, good data will be written back if - * any can be found. - * - * Future enhancements: - * - In case an unrepairable extent is encountered, track which files are - * affected and report them - * - track and record media errors, throw out bad devices - * - add a mode to also read unallocated space - */ - -struct scrub_block; -struct scrub_ctx; - -/* - * the following three values only influence the performance. - * The last one configures the number of parallel and outstanding I/O - * operations. The first two values configure an upper limit for the number - * of (dynamically allocated) pages that are added to a bio. - */ -#define SCRUB_PAGES_PER_RD_BIO 32 /* 128k per bio */ -#define SCRUB_PAGES_PER_WR_BIO 32 /* 128k per bio */ -#define SCRUB_BIOS_PER_SCTX 64 /* 8MB per device in flight */ - -/* - * the following value times PAGE_SIZE needs to be large enough to match the - * largest node/leaf/sector size that shall be supported. - * Values larger than BTRFS_STRIPE_LEN are not supported. - */ -#define SCRUB_MAX_PAGES_PER_BLOCK 16 /* 64k per node/leaf/sector */ - -struct scrub_recover { - atomic_t refs; - struct btrfs_bio *bbio; - u64 map_length; -}; - -struct scrub_page { - struct scrub_block *sblock; - struct page *page; - struct btrfs_device *dev; - struct list_head list; - u64 flags; /* extent flags */ - u64 generation; - u64 logical; - u64 physical; - u64 physical_for_dev_replace; - atomic_t refs; - struct { - unsigned int mirror_num:8; - unsigned int have_csum:1; - unsigned int io_error:1; - }; - u8 csum[BTRFS_CSUM_SIZE]; - - struct scrub_recover *recover; -}; - -struct scrub_bio { - int index; - struct scrub_ctx *sctx; - struct btrfs_device *dev; - struct bio *bio; - int err; - u64 logical; - u64 physical; -#if SCRUB_PAGES_PER_WR_BIO >= SCRUB_PAGES_PER_RD_BIO - struct scrub_page *pagev[SCRUB_PAGES_PER_WR_BIO]; -#else - struct scrub_page *pagev[SCRUB_PAGES_PER_RD_BIO]; -#endif - int page_count; - int next_free; - struct btrfs_work work; -}; - -struct scrub_block { - struct scrub_page *pagev[SCRUB_MAX_PAGES_PER_BLOCK]; - int page_count; - atomic_t outstanding_pages; - atomic_t refs; /* free mem on transition to zero */ - struct scrub_ctx *sctx; - struct scrub_parity *sparity; - struct { - unsigned int header_error:1; - unsigned int checksum_error:1; - unsigned int no_io_error_seen:1; - unsigned int generation_error:1; /* also sets header_error */ - - /* The following is for the data used to check parity */ - /* It is for the data with checksum */ - unsigned int data_corrected:1; - }; - struct btrfs_work work; -}; - -/* Used for the chunks with parity stripe such RAID5/6 */ -struct scrub_parity { - struct scrub_ctx *sctx; - - struct btrfs_device *scrub_dev; - - u64 logic_start; - - u64 logic_end; - - int nsectors; - - int stripe_len; - - atomic_t refs; - - struct list_head spages; - - /* Work of parity check and repair */ - struct btrfs_work work; - - /* Mark the parity blocks which have data */ - unsigned long *dbitmap; - - /* - * Mark the parity blocks which have data, but errors happen when - * read data or check data - */ - unsigned long *ebitmap; - - unsigned long bitmap[0]; -}; - -struct scrub_wr_ctx { - struct scrub_bio *wr_curr_bio; - struct btrfs_device *tgtdev; - int pages_per_wr_bio; /* <= SCRUB_PAGES_PER_WR_BIO */ - atomic_t flush_all_writes; - struct mutex wr_lock; -}; - -struct scrub_ctx { - struct scrub_bio *bios[SCRUB_BIOS_PER_SCTX]; - struct btrfs_root *dev_root; - int first_free; - int curr; - atomic_t bios_in_flight; - atomic_t workers_pending; - spinlock_t list_lock; - wait_queue_head_t list_wait; - u16 csum_size; - struct list_head csum_list; - atomic_t cancel_req; - int readonly; - int pages_per_rd_bio; - u32 sectorsize; - u32 nodesize; - - int is_dev_replace; - struct scrub_wr_ctx wr_ctx; - - /* - * statistics - */ - struct btrfs_scrub_progress stat; - spinlock_t stat_lock; - - /* - * Use a ref counter to avoid use-after-free issues. Scrub workers - * decrement bios_in_flight and workers_pending and then do a wakeup - * on the list_wait wait queue. We must ensure the main scrub task - * doesn't free the scrub context before or while the workers are - * doing the wakeup() call. - */ - atomic_t refs; -}; - -struct scrub_fixup_nodatasum { - struct scrub_ctx *sctx; - struct btrfs_device *dev; - u64 logical; - struct btrfs_root *root; - struct btrfs_work work; - int mirror_num; -}; - -struct scrub_nocow_inode { - u64 inum; - u64 offset; - u64 root; - struct list_head list; -}; - -struct scrub_copy_nocow_ctx { - struct scrub_ctx *sctx; - u64 logical; - u64 len; - int mirror_num; - u64 physical_for_dev_replace; - struct list_head inodes; - struct btrfs_work work; -}; - -struct scrub_warning { - struct btrfs_path *path; - u64 extent_item_size; - const char *errstr; - sector_t sector; - u64 logical; - struct btrfs_device *dev; -}; - -static void scrub_pending_bio_inc(struct scrub_ctx *sctx); -static void scrub_pending_bio_dec(struct scrub_ctx *sctx); -static void scrub_pending_trans_workers_inc(struct scrub_ctx *sctx); -static void scrub_pending_trans_workers_dec(struct scrub_ctx *sctx); -static int scrub_handle_errored_block(struct scrub_block *sblock_to_check); -static int scrub_setup_recheck_block(struct scrub_block *original_sblock, - struct scrub_block *sblocks_for_recheck); -static void scrub_recheck_block(struct btrfs_fs_info *fs_info, - struct scrub_block *sblock, - int retry_failed_mirror); -static void scrub_recheck_block_checksum(struct scrub_block *sblock); -static int scrub_repair_block_from_good_copy(struct scrub_block *sblock_bad, - struct scrub_block *sblock_good); -static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad, - struct scrub_block *sblock_good, - int page_num, int force_write); -static void scrub_write_block_to_dev_replace(struct scrub_block *sblock); -static int scrub_write_page_to_dev_replace(struct scrub_block *sblock, - int page_num); -static int scrub_checksum_data(struct scrub_block *sblock); -static int scrub_checksum_tree_block(struct scrub_block *sblock); -static int scrub_checksum_super(struct scrub_block *sblock); -static void scrub_block_get(struct scrub_block *sblock); -static void scrub_block_put(struct scrub_block *sblock); -static void scrub_page_get(struct scrub_page *spage); -static void scrub_page_put(struct scrub_page *spage); -static void scrub_parity_get(struct scrub_parity *sparity); -static void scrub_parity_put(struct scrub_parity *sparity); -static int scrub_add_page_to_rd_bio(struct scrub_ctx *sctx, - struct scrub_page *spage); -static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len, - u64 physical, struct btrfs_device *dev, u64 flags, - u64 gen, int mirror_num, u8 *csum, int force, - u64 physical_for_dev_replace); -static void scrub_bio_end_io(struct bio *bio); -static void scrub_bio_end_io_worker(struct btrfs_work *work); -static void scrub_block_complete(struct scrub_block *sblock); -static void scrub_remap_extent(struct btrfs_fs_info *fs_info, - u64 extent_logical, u64 extent_len, - u64 *extent_physical, - struct btrfs_device **extent_dev, - int *extent_mirror_num); -static int scrub_setup_wr_ctx(struct scrub_ctx *sctx, - struct scrub_wr_ctx *wr_ctx, - struct btrfs_fs_info *fs_info, - struct btrfs_device *dev, - int is_dev_replace); -static void scrub_free_wr_ctx(struct scrub_wr_ctx *wr_ctx); -static int scrub_add_page_to_wr_bio(struct scrub_ctx *sctx, - struct scrub_page *spage); -static void scrub_wr_submit(struct scrub_ctx *sctx); -static void scrub_wr_bio_end_io(struct bio *bio); -static void scrub_wr_bio_end_io_worker(struct btrfs_work *work); -static int write_page_nocow(struct scrub_ctx *sctx, - u64 physical_for_dev_replace, struct page *page); -static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, - struct scrub_copy_nocow_ctx *ctx); -static int copy_nocow_pages(struct scrub_ctx *sctx, u64 logical, u64 len, - int mirror_num, u64 physical_for_dev_replace); -static void copy_nocow_pages_worker(struct btrfs_work *work); -static void __scrub_blocked_if_needed(struct btrfs_fs_info *fs_info); -static void scrub_blocked_if_needed(struct btrfs_fs_info *fs_info); -static void scrub_put_ctx(struct scrub_ctx *sctx); - - -static void scrub_pending_bio_inc(struct scrub_ctx *sctx) -{ - atomic_inc(&sctx->refs); - atomic_inc(&sctx->bios_in_flight); -} - -static void scrub_pending_bio_dec(struct scrub_ctx *sctx) -{ - atomic_dec(&sctx->bios_in_flight); - wake_up(&sctx->list_wait); - scrub_put_ctx(sctx); -} - -static void __scrub_blocked_if_needed(struct btrfs_fs_info *fs_info) -{ - while (atomic_read(&fs_info->scrub_pause_req)) { - mutex_unlock(&fs_info->scrub_lock); - wait_event(fs_info->scrub_pause_wait, - atomic_read(&fs_info->scrub_pause_req) == 0); - mutex_lock(&fs_info->scrub_lock); - } -} - -static void scrub_pause_on(struct btrfs_fs_info *fs_info) -{ - atomic_inc(&fs_info->scrubs_paused); - wake_up(&fs_info->scrub_pause_wait); -} - -static void scrub_pause_off(struct btrfs_fs_info *fs_info) -{ - mutex_lock(&fs_info->scrub_lock); - __scrub_blocked_if_needed(fs_info); - atomic_dec(&fs_info->scrubs_paused); - mutex_unlock(&fs_info->scrub_lock); - - wake_up(&fs_info->scrub_pause_wait); -} - -static void scrub_blocked_if_needed(struct btrfs_fs_info *fs_info) -{ - scrub_pause_on(fs_info); - scrub_pause_off(fs_info); -} - -/* - * used for workers that require transaction commits (i.e., for the - * NOCOW case) - */ -static void scrub_pending_trans_workers_inc(struct scrub_ctx *sctx) -{ - struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info; - - atomic_inc(&sctx->refs); - /* - * increment scrubs_running to prevent cancel requests from - * completing as long as a worker is running. we must also - * increment scrubs_paused to prevent deadlocking on pause - * requests used for transactions commits (as the worker uses a - * transaction context). it is safe to regard the worker - * as paused for all matters practical. effectively, we only - * avoid cancellation requests from completing. - */ - mutex_lock(&fs_info->scrub_lock); - atomic_inc(&fs_info->scrubs_running); - atomic_inc(&fs_info->scrubs_paused); - mutex_unlock(&fs_info->scrub_lock); - - /* - * check if @scrubs_running=@scrubs_paused condition - * inside wait_event() is not an atomic operation. - * which means we may inc/dec @scrub_running/paused - * at any time. Let's wake up @scrub_pause_wait as - * much as we can to let commit transaction blocked less. - */ - wake_up(&fs_info->scrub_pause_wait); - - atomic_inc(&sctx->workers_pending); -} - -/* used for workers that require transaction commits */ -static void scrub_pending_trans_workers_dec(struct scrub_ctx *sctx) -{ - struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info; - - /* - * see scrub_pending_trans_workers_inc() why we're pretending - * to be paused in the scrub counters - */ - mutex_lock(&fs_info->scrub_lock); - atomic_dec(&fs_info->scrubs_running); - atomic_dec(&fs_info->scrubs_paused); - mutex_unlock(&fs_info->scrub_lock); - atomic_dec(&sctx->workers_pending); - wake_up(&fs_info->scrub_pause_wait); - wake_up(&sctx->list_wait); - scrub_put_ctx(sctx); -} - -static void scrub_free_csums(struct scrub_ctx *sctx) -{ - while (!list_empty(&sctx->csum_list)) { - struct btrfs_ordered_sum *sum; - sum = list_first_entry(&sctx->csum_list, - struct btrfs_ordered_sum, list); - list_del(&sum->list); - kfree(sum); - } -} - -static noinline_for_stack void scrub_free_ctx(struct scrub_ctx *sctx) -{ - int i; - - if (!sctx) - return; - - scrub_free_wr_ctx(&sctx->wr_ctx); - - /* this can happen when scrub is cancelled */ - if (sctx->curr != -1) { - struct scrub_bio *sbio = sctx->bios[sctx->curr]; - - for (i = 0; i < sbio->page_count; i++) { - WARN_ON(!sbio->pagev[i]->page); - scrub_block_put(sbio->pagev[i]->sblock); - } - bio_put(sbio->bio); - } - - for (i = 0; i < SCRUB_BIOS_PER_SCTX; ++i) { - struct scrub_bio *sbio = sctx->bios[i]; - - if (!sbio) - break; - kfree(sbio); - } - - scrub_free_csums(sctx); - kfree(sctx); -} - -static void scrub_put_ctx(struct scrub_ctx *sctx) -{ - if (atomic_dec_and_test(&sctx->refs)) - scrub_free_ctx(sctx); -} - -static noinline_for_stack -struct scrub_ctx *scrub_setup_ctx(struct btrfs_device *dev, int is_dev_replace) -{ - struct scrub_ctx *sctx; - int i; - struct btrfs_fs_info *fs_info = dev->dev_root->fs_info; - int ret; - - sctx = kzalloc(sizeof(*sctx), GFP_KERNEL); - if (!sctx) - goto nomem; - atomic_set(&sctx->refs, 1); - sctx->is_dev_replace = is_dev_replace; - sctx->pages_per_rd_bio = SCRUB_PAGES_PER_RD_BIO; - sctx->curr = -1; - sctx->dev_root = dev->dev_root; - for (i = 0; i < SCRUB_BIOS_PER_SCTX; ++i) { - struct scrub_bio *sbio; - - sbio = kzalloc(sizeof(*sbio), GFP_KERNEL); - if (!sbio) - goto nomem; - sctx->bios[i] = sbio; - - sbio->index = i; - sbio->sctx = sctx; - sbio->page_count = 0; - btrfs_init_work(&sbio->work, btrfs_scrub_helper, - scrub_bio_end_io_worker, NULL, NULL); - - if (i != SCRUB_BIOS_PER_SCTX - 1) - sctx->bios[i]->next_free = i + 1; - else - sctx->bios[i]->next_free = -1; - } - sctx->first_free = 0; - sctx->nodesize = dev->dev_root->nodesize; - sctx->sectorsize = dev->dev_root->sectorsize; - atomic_set(&sctx->bios_in_flight, 0); - atomic_set(&sctx->workers_pending, 0); - atomic_set(&sctx->cancel_req, 0); - sctx->csum_size = btrfs_super_csum_size(fs_info->super_copy); - INIT_LIST_HEAD(&sctx->csum_list); - - spin_lock_init(&sctx->list_lock); - spin_lock_init(&sctx->stat_lock); - init_waitqueue_head(&sctx->list_wait); - - ret = scrub_setup_wr_ctx(sctx, &sctx->wr_ctx, fs_info, - fs_info->dev_replace.tgtdev, is_dev_replace); - if (ret) { - scrub_free_ctx(sctx); - return ERR_PTR(ret); - } - return sctx; - -nomem: - scrub_free_ctx(sctx); - return ERR_PTR(-ENOMEM); -} - -static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root, - void *warn_ctx) -{ - u64 isize; - u32 nlink; - int ret; - int i; - struct extent_buffer *eb; - struct btrfs_inode_item *inode_item; - struct scrub_warning *swarn = warn_ctx; - struct btrfs_fs_info *fs_info = swarn->dev->dev_root->fs_info; - struct inode_fs_paths *ipath = NULL; - struct btrfs_root *local_root; - struct btrfs_key root_key; - struct btrfs_key key; - - root_key.objectid = root; - root_key.type = BTRFS_ROOT_ITEM_KEY; - root_key.offset = (u64)-1; - local_root = btrfs_read_fs_root_no_name(fs_info, &root_key); - if (IS_ERR(local_root)) { - ret = PTR_ERR(local_root); - goto err; - } - - /* - * this makes the path point to (inum INODE_ITEM ioff) - */ - key.objectid = inum; - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - - ret = btrfs_search_slot(NULL, local_root, &key, swarn->path, 0, 0); - if (ret) { - btrfs_release_path(swarn->path); - goto err; - } - - eb = swarn->path->nodes[0]; - inode_item = btrfs_item_ptr(eb, swarn->path->slots[0], - struct btrfs_inode_item); - isize = btrfs_inode_size(eb, inode_item); - nlink = btrfs_inode_nlink(eb, inode_item); - btrfs_release_path(swarn->path); - - ipath = init_ipath(4096, local_root, swarn->path); - if (IS_ERR(ipath)) { - ret = PTR_ERR(ipath); - ipath = NULL; - goto err; - } - ret = paths_from_inode(inum, ipath); - - if (ret < 0) - goto err; - - /* - * we deliberately ignore the bit ipath might have been too small to - * hold all of the paths here - */ - for (i = 0; i < ipath->fspath->elem_cnt; ++i) - btrfs_warn_in_rcu(fs_info, - "%s at logical %llu on dev %s, sector %llu, root %llu, inode %llu, offset %llu, length %llu, links %u (path: %s)", - swarn->errstr, swarn->logical, - rcu_str_deref(swarn->dev->name), - (unsigned long long)swarn->sector, - root, inum, offset, - min(isize - offset, (u64)PAGE_SIZE), nlink, - (char *)(unsigned long)ipath->fspath->val[i]); - - free_ipath(ipath); - return 0; - -err: - btrfs_warn_in_rcu(fs_info, - "%s at logical %llu on dev %s, sector %llu, root %llu, inode %llu, offset %llu: path resolving failed with ret=%d", - swarn->errstr, swarn->logical, - rcu_str_deref(swarn->dev->name), - (unsigned long long)swarn->sector, - root, inum, offset, ret); - - free_ipath(ipath); - return 0; -} - -static void scrub_print_warning(const char *errstr, struct scrub_block *sblock) -{ - struct btrfs_device *dev; - struct btrfs_fs_info *fs_info; - struct btrfs_path *path; - struct btrfs_key found_key; - struct extent_buffer *eb; - struct btrfs_extent_item *ei; - struct scrub_warning swarn; - unsigned long ptr = 0; - u64 extent_item_pos; - u64 flags = 0; - u64 ref_root; - u32 item_size; - u8 ref_level = 0; - int ret; - - WARN_ON(sblock->page_count < 1); - dev = sblock->pagev[0]->dev; - fs_info = sblock->sctx->dev_root->fs_info; - - path = btrfs_alloc_path(); - if (!path) - return; - - swarn.sector = (sblock->pagev[0]->physical) >> 9; - swarn.logical = sblock->pagev[0]->logical; - swarn.errstr = errstr; - swarn.dev = NULL; - - ret = extent_from_logical(fs_info, swarn.logical, path, &found_key, - &flags); - if (ret < 0) - goto out; - - extent_item_pos = swarn.logical - found_key.objectid; - swarn.extent_item_size = found_key.offset; - - eb = path->nodes[0]; - ei = btrfs_item_ptr(eb, path->slots[0], struct btrfs_extent_item); - item_size = btrfs_item_size_nr(eb, path->slots[0]); - - if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { - do { - ret = tree_backref_for_extent(&ptr, eb, &found_key, ei, - item_size, &ref_root, - &ref_level); - btrfs_warn_in_rcu(fs_info, - "%s at logical %llu on dev %s, sector %llu: metadata %s (level %d) in tree %llu", - errstr, swarn.logical, - rcu_str_deref(dev->name), - (unsigned long long)swarn.sector, - ref_level ? "node" : "leaf", - ret < 0 ? -1 : ref_level, - ret < 0 ? -1 : ref_root); - } while (ret != 1); - btrfs_release_path(path); - } else { - btrfs_release_path(path); - swarn.path = path; - swarn.dev = dev; - iterate_extent_inodes(fs_info, found_key.objectid, - extent_item_pos, 1, - scrub_print_warning_inode, &swarn); - } - -out: - btrfs_free_path(path); -} - -static int scrub_fixup_readpage(u64 inum, u64 offset, u64 root, void *fixup_ctx) -{ - struct page *page = NULL; - unsigned long index; - struct scrub_fixup_nodatasum *fixup = fixup_ctx; - int ret; - int corrected = 0; - struct btrfs_key key; - struct inode *inode = NULL; - struct btrfs_fs_info *fs_info; - u64 end = offset + PAGE_SIZE - 1; - struct btrfs_root *local_root; - int srcu_index; - - key.objectid = root; - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = (u64)-1; - - fs_info = fixup->root->fs_info; - srcu_index = srcu_read_lock(&fs_info->subvol_srcu); - - local_root = btrfs_read_fs_root_no_name(fs_info, &key); - if (IS_ERR(local_root)) { - srcu_read_unlock(&fs_info->subvol_srcu, srcu_index); - return PTR_ERR(local_root); - } - - key.type = BTRFS_INODE_ITEM_KEY; - key.objectid = inum; - key.offset = 0; - inode = btrfs_iget(fs_info->sb, &key, local_root, NULL); - srcu_read_unlock(&fs_info->subvol_srcu, srcu_index); - if (IS_ERR(inode)) - return PTR_ERR(inode); - - index = offset >> PAGE_SHIFT; - - page = find_or_create_page(inode->i_mapping, index, GFP_NOFS); - if (!page) { - ret = -ENOMEM; - goto out; - } - - if (PageUptodate(page)) { - if (PageDirty(page)) { - /* - * we need to write the data to the defect sector. the - * data that was in that sector is not in memory, - * because the page was modified. we must not write the - * modified page to that sector. - * - * TODO: what could be done here: wait for the delalloc - * runner to write out that page (might involve - * COW) and see whether the sector is still - * referenced afterwards. - * - * For the meantime, we'll treat this error - * incorrectable, although there is a chance that a - * later scrub will find the bad sector again and that - * there's no dirty page in memory, then. - */ - ret = -EIO; - goto out; - } - ret = repair_io_failure(inode, offset, PAGE_SIZE, - fixup->logical, page, - offset - page_offset(page), - fixup->mirror_num); - unlock_page(page); - corrected = !ret; - } else { - /* - * we need to get good data first. the general readpage path - * will call repair_io_failure for us, we just have to make - * sure we read the bad mirror. - */ - ret = set_extent_bits(&BTRFS_I(inode)->io_tree, offset, end, - EXTENT_DAMAGED); - if (ret) { - /* set_extent_bits should give proper error */ - WARN_ON(ret > 0); - if (ret > 0) - ret = -EFAULT; - goto out; - } - - ret = extent_read_full_page(&BTRFS_I(inode)->io_tree, page, - btrfs_get_extent, - fixup->mirror_num); - wait_on_page_locked(page); - - corrected = !test_range_bit(&BTRFS_I(inode)->io_tree, offset, - end, EXTENT_DAMAGED, 0, NULL); - if (!corrected) - clear_extent_bits(&BTRFS_I(inode)->io_tree, offset, end, - EXTENT_DAMAGED); - } - -out: - if (page) - put_page(page); - - iput(inode); - - if (ret < 0) - return ret; - - if (ret == 0 && corrected) { - /* - * we only need to call readpage for one of the inodes belonging - * to this extent. so make iterate_extent_inodes stop - */ - return 1; - } - - return -EIO; -} - -static void scrub_fixup_nodatasum(struct btrfs_work *work) -{ - int ret; - struct scrub_fixup_nodatasum *fixup; - struct scrub_ctx *sctx; - struct btrfs_trans_handle *trans = NULL; - struct btrfs_path *path; - int uncorrectable = 0; - - fixup = container_of(work, struct scrub_fixup_nodatasum, work); - sctx = fixup->sctx; - - path = btrfs_alloc_path(); - if (!path) { - spin_lock(&sctx->stat_lock); - ++sctx->stat.malloc_errors; - spin_unlock(&sctx->stat_lock); - uncorrectable = 1; - goto out; - } - - trans = btrfs_join_transaction(fixup->root); - if (IS_ERR(trans)) { - uncorrectable = 1; - goto out; - } - - /* - * the idea is to trigger a regular read through the standard path. we - * read a page from the (failed) logical address by specifying the - * corresponding copynum of the failed sector. thus, that readpage is - * expected to fail. - * that is the point where on-the-fly error correction will kick in - * (once it's finished) and rewrite the failed sector if a good copy - * can be found. - */ - ret = iterate_inodes_from_logical(fixup->logical, fixup->root->fs_info, - path, scrub_fixup_readpage, - fixup); - if (ret < 0) { - uncorrectable = 1; - goto out; - } - WARN_ON(ret != 1); - - spin_lock(&sctx->stat_lock); - ++sctx->stat.corrected_errors; - spin_unlock(&sctx->stat_lock); - -out: - if (trans && !IS_ERR(trans)) - btrfs_end_transaction(trans, fixup->root); - if (uncorrectable) { - spin_lock(&sctx->stat_lock); - ++sctx->stat.uncorrectable_errors; - spin_unlock(&sctx->stat_lock); - btrfs_dev_replace_stats_inc( - &sctx->dev_root->fs_info->dev_replace. - num_uncorrectable_read_errors); - btrfs_err_rl_in_rcu(sctx->dev_root->fs_info, - "unable to fixup (nodatasum) error at logical %llu on dev %s", - fixup->logical, rcu_str_deref(fixup->dev->name)); - } - - btrfs_free_path(path); - kfree(fixup); - - scrub_pending_trans_workers_dec(sctx); -} - -static inline void scrub_get_recover(struct scrub_recover *recover) -{ - atomic_inc(&recover->refs); -} - -static inline void scrub_put_recover(struct scrub_recover *recover) -{ - if (atomic_dec_and_test(&recover->refs)) { - btrfs_put_bbio(recover->bbio); - kfree(recover); - } -} - -/* - * scrub_handle_errored_block gets called when either verification of the - * pages failed or the bio failed to read, e.g. with EIO. In the latter - * case, this function handles all pages in the bio, even though only one - * may be bad. - * The goal of this function is to repair the errored block by using the - * contents of one of the mirrors. - */ -static int scrub_handle_errored_block(struct scrub_block *sblock_to_check) -{ - struct scrub_ctx *sctx = sblock_to_check->sctx; - struct btrfs_device *dev; - struct btrfs_fs_info *fs_info; - u64 length; - u64 logical; - unsigned int failed_mirror_index; - unsigned int is_metadata; - unsigned int have_csum; - struct scrub_block *sblocks_for_recheck; /* holds one for each mirror */ - struct scrub_block *sblock_bad; - int ret; - int mirror_index; - int page_num; - int success; - static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL, - DEFAULT_RATELIMIT_BURST); - - BUG_ON(sblock_to_check->page_count < 1); - fs_info = sctx->dev_root->fs_info; - if (sblock_to_check->pagev[0]->flags & BTRFS_EXTENT_FLAG_SUPER) { - /* - * if we find an error in a super block, we just report it. - * They will get written with the next transaction commit - * anyway - */ - spin_lock(&sctx->stat_lock); - ++sctx->stat.super_errors; - spin_unlock(&sctx->stat_lock); - return 0; - } - length = sblock_to_check->page_count * PAGE_SIZE; - logical = sblock_to_check->pagev[0]->logical; - BUG_ON(sblock_to_check->pagev[0]->mirror_num < 1); - failed_mirror_index = sblock_to_check->pagev[0]->mirror_num - 1; - is_metadata = !(sblock_to_check->pagev[0]->flags & - BTRFS_EXTENT_FLAG_DATA); - have_csum = sblock_to_check->pagev[0]->have_csum; - dev = sblock_to_check->pagev[0]->dev; - - if (sctx->is_dev_replace && !is_metadata && !have_csum) { - sblocks_for_recheck = NULL; - goto nodatasum_case; - } - - /* - * read all mirrors one after the other. This includes to - * re-read the extent or metadata block that failed (that was - * the cause that this fixup code is called) another time, - * page by page this time in order to know which pages - * caused I/O errors and which ones are good (for all mirrors). - * It is the goal to handle the situation when more than one - * mirror contains I/O errors, but the errors do not - * overlap, i.e. the data can be repaired by selecting the - * pages from those mirrors without I/O error on the - * particular pages. One example (with blocks >= 2 * PAGE_SIZE) - * would be that mirror #1 has an I/O error on the first page, - * the second page is good, and mirror #2 has an I/O error on - * the second page, but the first page is good. - * Then the first page of the first mirror can be repaired by - * taking the first page of the second mirror, and the - * second page of the second mirror can be repaired by - * copying the contents of the 2nd page of the 1st mirror. - * One more note: if the pages of one mirror contain I/O - * errors, the checksum cannot be verified. In order to get - * the best data for repairing, the first attempt is to find - * a mirror without I/O errors and with a validated checksum. - * Only if this is not possible, the pages are picked from - * mirrors with I/O errors without considering the checksum. - * If the latter is the case, at the end, the checksum of the - * repaired area is verified in order to correctly maintain - * the statistics. - */ - - sblocks_for_recheck = kcalloc(BTRFS_MAX_MIRRORS, - sizeof(*sblocks_for_recheck), GFP_NOFS); - if (!sblocks_for_recheck) { - spin_lock(&sctx->stat_lock); - sctx->stat.malloc_errors++; - sctx->stat.read_errors++; - sctx->stat.uncorrectable_errors++; - spin_unlock(&sctx->stat_lock); - btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_READ_ERRS); - goto out; - } - - /* setup the context, map the logical blocks and alloc the pages */ - ret = scrub_setup_recheck_block(sblock_to_check, sblocks_for_recheck); - if (ret) { - spin_lock(&sctx->stat_lock); - sctx->stat.read_errors++; - sctx->stat.uncorrectable_errors++; - spin_unlock(&sctx->stat_lock); - btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_READ_ERRS); - goto out; - } - BUG_ON(failed_mirror_index >= BTRFS_MAX_MIRRORS); - sblock_bad = sblocks_for_recheck + failed_mirror_index; - - /* build and submit the bios for the failed mirror, check checksums */ - scrub_recheck_block(fs_info, sblock_bad, 1); - - if (!sblock_bad->header_error && !sblock_bad->checksum_error && - sblock_bad->no_io_error_seen) { - /* - * the error disappeared after reading page by page, or - * the area was part of a huge bio and other parts of the - * bio caused I/O errors, or the block layer merged several - * read requests into one and the error is caused by a - * different bio (usually one of the two latter cases is - * the cause) - */ - spin_lock(&sctx->stat_lock); - sctx->stat.unverified_errors++; - sblock_to_check->data_corrected = 1; - spin_unlock(&sctx->stat_lock); - - if (sctx->is_dev_replace) - scrub_write_block_to_dev_replace(sblock_bad); - goto out; - } - - if (!sblock_bad->no_io_error_seen) { - spin_lock(&sctx->stat_lock); - sctx->stat.read_errors++; - spin_unlock(&sctx->stat_lock); - if (__ratelimit(&_rs)) - scrub_print_warning("i/o error", sblock_to_check); - btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_READ_ERRS); - } else if (sblock_bad->checksum_error) { - spin_lock(&sctx->stat_lock); - sctx->stat.csum_errors++; - spin_unlock(&sctx->stat_lock); - if (__ratelimit(&_rs)) - scrub_print_warning("checksum error", sblock_to_check); - btrfs_dev_stat_inc_and_print(dev, - BTRFS_DEV_STAT_CORRUPTION_ERRS); - } else if (sblock_bad->header_error) { - spin_lock(&sctx->stat_lock); - sctx->stat.verify_errors++; - spin_unlock(&sctx->stat_lock); - if (__ratelimit(&_rs)) - scrub_print_warning("checksum/header error", - sblock_to_check); - if (sblock_bad->generation_error) - btrfs_dev_stat_inc_and_print(dev, - BTRFS_DEV_STAT_GENERATION_ERRS); - else - btrfs_dev_stat_inc_and_print(dev, - BTRFS_DEV_STAT_CORRUPTION_ERRS); - } - - if (sctx->readonly) { - ASSERT(!sctx->is_dev_replace); - goto out; - } - - if (!is_metadata && !have_csum) { - struct scrub_fixup_nodatasum *fixup_nodatasum; - - WARN_ON(sctx->is_dev_replace); - -nodatasum_case: - - /* - * !is_metadata and !have_csum, this means that the data - * might not be COWed, that it might be modified - * concurrently. The general strategy to work on the - * commit root does not help in the case when COW is not - * used. - */ - fixup_nodatasum = kzalloc(sizeof(*fixup_nodatasum), GFP_NOFS); - if (!fixup_nodatasum) - goto did_not_correct_error; - fixup_nodatasum->sctx = sctx; - fixup_nodatasum->dev = dev; - fixup_nodatasum->logical = logical; - fixup_nodatasum->root = fs_info->extent_root; - fixup_nodatasum->mirror_num = failed_mirror_index + 1; - scrub_pending_trans_workers_inc(sctx); - btrfs_init_work(&fixup_nodatasum->work, btrfs_scrub_helper, - scrub_fixup_nodatasum, NULL, NULL); - btrfs_queue_work(fs_info->scrub_workers, - &fixup_nodatasum->work); - goto out; - } - - /* - * now build and submit the bios for the other mirrors, check - * checksums. - * First try to pick the mirror which is completely without I/O - * errors and also does not have a checksum error. - * If one is found, and if a checksum is present, the full block - * that is known to contain an error is rewritten. Afterwards - * the block is known to be corrected. - * If a mirror is found which is completely correct, and no - * checksum is present, only those pages are rewritten that had - * an I/O error in the block to be repaired, since it cannot be - * determined, which copy of the other pages is better (and it - * could happen otherwise that a correct page would be - * overwritten by a bad one). - */ - for (mirror_index = 0; - mirror_index < BTRFS_MAX_MIRRORS && - sblocks_for_recheck[mirror_index].page_count > 0; - mirror_index++) { - struct scrub_block *sblock_other; - - if (mirror_index == failed_mirror_index) - continue; - sblock_other = sblocks_for_recheck + mirror_index; - - /* build and submit the bios, check checksums */ - scrub_recheck_block(fs_info, sblock_other, 0); - - if (!sblock_other->header_error && - !sblock_other->checksum_error && - sblock_other->no_io_error_seen) { - if (sctx->is_dev_replace) { - scrub_write_block_to_dev_replace(sblock_other); - goto corrected_error; - } else { - ret = scrub_repair_block_from_good_copy( - sblock_bad, sblock_other); - if (!ret) - goto corrected_error; - } - } - } - - if (sblock_bad->no_io_error_seen && !sctx->is_dev_replace) - goto did_not_correct_error; - - /* - * In case of I/O errors in the area that is supposed to be - * repaired, continue by picking good copies of those pages. - * Select the good pages from mirrors to rewrite bad pages from - * the area to fix. Afterwards verify the checksum of the block - * that is supposed to be repaired. This verification step is - * only done for the purpose of statistic counting and for the - * final scrub report, whether errors remain. - * A perfect algorithm could make use of the checksum and try - * all possible combinations of pages from the different mirrors - * until the checksum verification succeeds. For example, when - * the 2nd page of mirror #1 faces I/O errors, and the 2nd page - * of mirror #2 is readable but the final checksum test fails, - * then the 2nd page of mirror #3 could be tried, whether now - * the final checksum succeeds. But this would be a rare - * exception and is therefore not implemented. At least it is - * avoided that the good copy is overwritten. - * A more useful improvement would be to pick the sectors - * without I/O error based on sector sizes (512 bytes on legacy - * disks) instead of on PAGE_SIZE. Then maybe 512 byte of one - * mirror could be repaired by taking 512 byte of a different - * mirror, even if other 512 byte sectors in the same PAGE_SIZE - * area are unreadable. - */ - success = 1; - for (page_num = 0; page_num < sblock_bad->page_count; - page_num++) { - struct scrub_page *page_bad = sblock_bad->pagev[page_num]; - struct scrub_block *sblock_other = NULL; - - /* skip no-io-error page in scrub */ - if (!page_bad->io_error && !sctx->is_dev_replace) - continue; - - /* try to find no-io-error page in mirrors */ - if (page_bad->io_error) { - for (mirror_index = 0; - mirror_index < BTRFS_MAX_MIRRORS && - sblocks_for_recheck[mirror_index].page_count > 0; - mirror_index++) { - if (!sblocks_for_recheck[mirror_index]. - pagev[page_num]->io_error) { - sblock_other = sblocks_for_recheck + - mirror_index; - break; - } - } - if (!sblock_other) - success = 0; - } - - if (sctx->is_dev_replace) { - /* - * did not find a mirror to fetch the page - * from. scrub_write_page_to_dev_replace() - * handles this case (page->io_error), by - * filling the block with zeros before - * submitting the write request - */ - if (!sblock_other) - sblock_other = sblock_bad; - - if (scrub_write_page_to_dev_replace(sblock_other, - page_num) != 0) { - btrfs_dev_replace_stats_inc( - &sctx->dev_root-> - fs_info->dev_replace. - num_write_errors); - success = 0; - } - } else if (sblock_other) { - ret = scrub_repair_page_from_good_copy(sblock_bad, - sblock_other, - page_num, 0); - if (0 == ret) - page_bad->io_error = 0; - else - success = 0; - } - } - - if (success && !sctx->is_dev_replace) { - if (is_metadata || have_csum) { - /* - * need to verify the checksum now that all - * sectors on disk are repaired (the write - * request for data to be repaired is on its way). - * Just be lazy and use scrub_recheck_block() - * which re-reads the data before the checksum - * is verified, but most likely the data comes out - * of the page cache. - */ - scrub_recheck_block(fs_info, sblock_bad, 1); - if (!sblock_bad->header_error && - !sblock_bad->checksum_error && - sblock_bad->no_io_error_seen) - goto corrected_error; - else - goto did_not_correct_error; - } else { -corrected_error: - spin_lock(&sctx->stat_lock); - sctx->stat.corrected_errors++; - sblock_to_check->data_corrected = 1; - spin_unlock(&sctx->stat_lock); - btrfs_err_rl_in_rcu(fs_info, - "fixed up error at logical %llu on dev %s", - logical, rcu_str_deref(dev->name)); - } - } else { -did_not_correct_error: - spin_lock(&sctx->stat_lock); - sctx->stat.uncorrectable_errors++; - spin_unlock(&sctx->stat_lock); - btrfs_err_rl_in_rcu(fs_info, - "unable to fixup (regular) error at logical %llu on dev %s", - logical, rcu_str_deref(dev->name)); - } - -out: - if (sblocks_for_recheck) { - for (mirror_index = 0; mirror_index < BTRFS_MAX_MIRRORS; - mirror_index++) { - struct scrub_block *sblock = sblocks_for_recheck + - mirror_index; - struct scrub_recover *recover; - int page_index; - - for (page_index = 0; page_index < sblock->page_count; - page_index++) { - sblock->pagev[page_index]->sblock = NULL; - recover = sblock->pagev[page_index]->recover; - if (recover) { - scrub_put_recover(recover); - sblock->pagev[page_index]->recover = - NULL; - } - scrub_page_put(sblock->pagev[page_index]); - } - } - kfree(sblocks_for_recheck); - } - - return 0; -} - -static inline int scrub_nr_raid_mirrors(struct btrfs_bio *bbio) -{ - if (bbio->map_type & BTRFS_BLOCK_GROUP_RAID5) - return 2; - else if (bbio->map_type & BTRFS_BLOCK_GROUP_RAID6) - return 3; - else - return (int)bbio->num_stripes; -} - -static inline void scrub_stripe_index_and_offset(u64 logical, u64 map_type, - u64 *raid_map, - u64 mapped_length, - int nstripes, int mirror, - int *stripe_index, - u64 *stripe_offset) -{ - int i; - - if (map_type & BTRFS_BLOCK_GROUP_RAID56_MASK) { - /* RAID5/6 */ - for (i = 0; i < nstripes; i++) { - if (raid_map[i] == RAID6_Q_STRIPE || - raid_map[i] == RAID5_P_STRIPE) - continue; - - if (logical >= raid_map[i] && - logical < raid_map[i] + mapped_length) - break; - } - - *stripe_index = i; - *stripe_offset = logical - raid_map[i]; - } else { - /* The other RAID type */ - *stripe_index = mirror; - *stripe_offset = 0; - } -} - -static int scrub_setup_recheck_block(struct scrub_block *original_sblock, - struct scrub_block *sblocks_for_recheck) -{ - struct scrub_ctx *sctx = original_sblock->sctx; - struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info; - u64 length = original_sblock->page_count * PAGE_SIZE; - u64 logical = original_sblock->pagev[0]->logical; - u64 generation = original_sblock->pagev[0]->generation; - u64 flags = original_sblock->pagev[0]->flags; - u64 have_csum = original_sblock->pagev[0]->have_csum; - struct scrub_recover *recover; - struct btrfs_bio *bbio; - u64 sublen; - u64 mapped_length; - u64 stripe_offset; - int stripe_index; - int page_index = 0; - int mirror_index; - int nmirrors; - int ret; - - /* - * note: the two members refs and outstanding_pages - * are not used (and not set) in the blocks that are used for - * the recheck procedure - */ - - while (length > 0) { - sublen = min_t(u64, length, PAGE_SIZE); - mapped_length = sublen; - bbio = NULL; - - /* - * with a length of PAGE_SIZE, each returned stripe - * represents one mirror - */ - ret = btrfs_map_sblock(fs_info, REQ_GET_READ_MIRRORS, logical, - &mapped_length, &bbio, 0, 1); - if (ret || !bbio || mapped_length < sublen) { - btrfs_put_bbio(bbio); - return -EIO; - } - - recover = kzalloc(sizeof(struct scrub_recover), GFP_NOFS); - if (!recover) { - btrfs_put_bbio(bbio); - return -ENOMEM; - } - - atomic_set(&recover->refs, 1); - recover->bbio = bbio; - recover->map_length = mapped_length; - - BUG_ON(page_index >= SCRUB_MAX_PAGES_PER_BLOCK); - - nmirrors = min(scrub_nr_raid_mirrors(bbio), BTRFS_MAX_MIRRORS); - - for (mirror_index = 0; mirror_index < nmirrors; - mirror_index++) { - struct scrub_block *sblock; - struct scrub_page *page; - - sblock = sblocks_for_recheck + mirror_index; - sblock->sctx = sctx; - - page = kzalloc(sizeof(*page), GFP_NOFS); - if (!page) { -leave_nomem: - spin_lock(&sctx->stat_lock); - sctx->stat.malloc_errors++; - spin_unlock(&sctx->stat_lock); - scrub_put_recover(recover); - return -ENOMEM; - } - scrub_page_get(page); - sblock->pagev[page_index] = page; - page->sblock = sblock; - page->flags = flags; - page->generation = generation; - page->logical = logical; - page->have_csum = have_csum; - if (have_csum) - memcpy(page->csum, - original_sblock->pagev[0]->csum, - sctx->csum_size); - - scrub_stripe_index_and_offset(logical, - bbio->map_type, - bbio->raid_map, - mapped_length, - bbio->num_stripes - - bbio->num_tgtdevs, - mirror_index, - &stripe_index, - &stripe_offset); - page->physical = bbio->stripes[stripe_index].physical + - stripe_offset; - page->dev = bbio->stripes[stripe_index].dev; - - BUG_ON(page_index >= original_sblock->page_count); - page->physical_for_dev_replace = - original_sblock->pagev[page_index]-> - physical_for_dev_replace; - /* for missing devices, dev->bdev is NULL */ - page->mirror_num = mirror_index + 1; - sblock->page_count++; - page->page = alloc_page(GFP_NOFS); - if (!page->page) - goto leave_nomem; - - scrub_get_recover(recover); - page->recover = recover; - } - scrub_put_recover(recover); - length -= sublen; - logical += sublen; - page_index++; - } - - return 0; -} - -struct scrub_bio_ret { - struct completion event; - int error; -}; - -static void scrub_bio_wait_endio(struct bio *bio) -{ - struct scrub_bio_ret *ret = bio->bi_private; - - ret->error = bio->bi_error; - complete(&ret->event); -} - -static inline int scrub_is_page_on_raid56(struct scrub_page *page) -{ - return page->recover && - (page->recover->bbio->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK); -} - -static int scrub_submit_raid56_bio_wait(struct btrfs_fs_info *fs_info, - struct bio *bio, - struct scrub_page *page) -{ - struct scrub_bio_ret done; - int ret; - - init_completion(&done.event); - done.error = 0; - bio->bi_iter.bi_sector = page->logical >> 9; - bio->bi_private = &done; - bio->bi_end_io = scrub_bio_wait_endio; - - ret = raid56_parity_recover(fs_info->fs_root, bio, page->recover->bbio, - page->recover->map_length, - page->mirror_num, 0); - if (ret) - return ret; - - wait_for_completion(&done.event); - if (done.error) - return -EIO; - - return 0; -} - -/* - * this function will check the on disk data for checksum errors, header - * errors and read I/O errors. If any I/O errors happen, the exact pages - * which are errored are marked as being bad. The goal is to enable scrub - * to take those pages that are not errored from all the mirrors so that - * the pages that are errored in the just handled mirror can be repaired. - */ -static void scrub_recheck_block(struct btrfs_fs_info *fs_info, - struct scrub_block *sblock, - int retry_failed_mirror) -{ - int page_num; - - sblock->no_io_error_seen = 1; - - for (page_num = 0; page_num < sblock->page_count; page_num++) { - struct bio *bio; - struct scrub_page *page = sblock->pagev[page_num]; - - if (page->dev->bdev == NULL) { - page->io_error = 1; - sblock->no_io_error_seen = 0; - continue; - } - - WARN_ON(!page->page); - bio = btrfs_io_bio_alloc(GFP_NOFS, 1); - if (!bio) { - page->io_error = 1; - sblock->no_io_error_seen = 0; - continue; - } - bio->bi_bdev = page->dev->bdev; - - bio_add_page(bio, page->page, PAGE_SIZE, 0); - if (!retry_failed_mirror && scrub_is_page_on_raid56(page)) { - if (scrub_submit_raid56_bio_wait(fs_info, bio, page)) - sblock->no_io_error_seen = 0; - } else { - bio->bi_iter.bi_sector = page->physical >> 9; - bio_set_op_attrs(bio, REQ_OP_READ, 0); - - if (btrfsic_submit_bio_wait(bio)) - sblock->no_io_error_seen = 0; - } - - bio_put(bio); - } - - if (sblock->no_io_error_seen) - scrub_recheck_block_checksum(sblock); -} - -static inline int scrub_check_fsid(u8 fsid[], - struct scrub_page *spage) -{ - struct btrfs_fs_devices *fs_devices = spage->dev->fs_devices; - int ret; - - ret = memcmp(fsid, fs_devices->fsid, BTRFS_UUID_SIZE); - return !ret; -} - -static void scrub_recheck_block_checksum(struct scrub_block *sblock) -{ - sblock->header_error = 0; - sblock->checksum_error = 0; - sblock->generation_error = 0; - - if (sblock->pagev[0]->flags & BTRFS_EXTENT_FLAG_DATA) - scrub_checksum_data(sblock); - else - scrub_checksum_tree_block(sblock); -} - -static int scrub_repair_block_from_good_copy(struct scrub_block *sblock_bad, - struct scrub_block *sblock_good) -{ - int page_num; - int ret = 0; - - for (page_num = 0; page_num < sblock_bad->page_count; page_num++) { - int ret_sub; - - ret_sub = scrub_repair_page_from_good_copy(sblock_bad, - sblock_good, - page_num, 1); - if (ret_sub) - ret = ret_sub; - } - - return ret; -} - -static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad, - struct scrub_block *sblock_good, - int page_num, int force_write) -{ - struct scrub_page *page_bad = sblock_bad->pagev[page_num]; - struct scrub_page *page_good = sblock_good->pagev[page_num]; - - BUG_ON(page_bad->page == NULL); - BUG_ON(page_good->page == NULL); - if (force_write || sblock_bad->header_error || - sblock_bad->checksum_error || page_bad->io_error) { - struct bio *bio; - int ret; - - if (!page_bad->dev->bdev) { - btrfs_warn_rl(sblock_bad->sctx->dev_root->fs_info, - "scrub_repair_page_from_good_copy(bdev == NULL) is unexpected"); - return -EIO; - } - - bio = btrfs_io_bio_alloc(GFP_NOFS, 1); - if (!bio) - return -EIO; - bio->bi_bdev = page_bad->dev->bdev; - bio->bi_iter.bi_sector = page_bad->physical >> 9; - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); - - ret = bio_add_page(bio, page_good->page, PAGE_SIZE, 0); - if (PAGE_SIZE != ret) { - bio_put(bio); - return -EIO; - } - - if (btrfsic_submit_bio_wait(bio)) { - btrfs_dev_stat_inc_and_print(page_bad->dev, - BTRFS_DEV_STAT_WRITE_ERRS); - btrfs_dev_replace_stats_inc( - &sblock_bad->sctx->dev_root->fs_info-> - dev_replace.num_write_errors); - bio_put(bio); - return -EIO; - } - bio_put(bio); - } - - return 0; -} - -static void scrub_write_block_to_dev_replace(struct scrub_block *sblock) -{ - int page_num; - - /* - * This block is used for the check of the parity on the source device, - * so the data needn't be written into the destination device. - */ - if (sblock->sparity) - return; - - for (page_num = 0; page_num < sblock->page_count; page_num++) { - int ret; - - ret = scrub_write_page_to_dev_replace(sblock, page_num); - if (ret) - btrfs_dev_replace_stats_inc( - &sblock->sctx->dev_root->fs_info->dev_replace. - num_write_errors); - } -} - -static int scrub_write_page_to_dev_replace(struct scrub_block *sblock, - int page_num) -{ - struct scrub_page *spage = sblock->pagev[page_num]; - - BUG_ON(spage->page == NULL); - if (spage->io_error) { - void *mapped_buffer = kmap_atomic(spage->page); - - memset(mapped_buffer, 0, PAGE_SIZE); - flush_dcache_page(spage->page); - kunmap_atomic(mapped_buffer); - } - return scrub_add_page_to_wr_bio(sblock->sctx, spage); -} - -static int scrub_add_page_to_wr_bio(struct scrub_ctx *sctx, - struct scrub_page *spage) -{ - struct scrub_wr_ctx *wr_ctx = &sctx->wr_ctx; - struct scrub_bio *sbio; - int ret; - - mutex_lock(&wr_ctx->wr_lock); -again: - if (!wr_ctx->wr_curr_bio) { - wr_ctx->wr_curr_bio = kzalloc(sizeof(*wr_ctx->wr_curr_bio), - GFP_KERNEL); - if (!wr_ctx->wr_curr_bio) { - mutex_unlock(&wr_ctx->wr_lock); - return -ENOMEM; - } - wr_ctx->wr_curr_bio->sctx = sctx; - wr_ctx->wr_curr_bio->page_count = 0; - } - sbio = wr_ctx->wr_curr_bio; - if (sbio->page_count == 0) { - struct bio *bio; - - sbio->physical = spage->physical_for_dev_replace; - sbio->logical = spage->logical; - sbio->dev = wr_ctx->tgtdev; - bio = sbio->bio; - if (!bio) { - bio = btrfs_io_bio_alloc(GFP_KERNEL, - wr_ctx->pages_per_wr_bio); - if (!bio) { - mutex_unlock(&wr_ctx->wr_lock); - return -ENOMEM; - } - sbio->bio = bio; - } - - bio->bi_private = sbio; - bio->bi_end_io = scrub_wr_bio_end_io; - bio->bi_bdev = sbio->dev->bdev; - bio->bi_iter.bi_sector = sbio->physical >> 9; - bio_set_op_attrs(bio, REQ_OP_WRITE, 0); - sbio->err = 0; - } else if (sbio->physical + sbio->page_count * PAGE_SIZE != - spage->physical_for_dev_replace || - sbio->logical + sbio->page_count * PAGE_SIZE != - spage->logical) { - scrub_wr_submit(sctx); - goto again; - } - - ret = bio_add_page(sbio->bio, spage->page, PAGE_SIZE, 0); - if (ret != PAGE_SIZE) { - if (sbio->page_count < 1) { - bio_put(sbio->bio); - sbio->bio = NULL; - mutex_unlock(&wr_ctx->wr_lock); - return -EIO; - } - scrub_wr_submit(sctx); - goto again; - } - - sbio->pagev[sbio->page_count] = spage; - scrub_page_get(spage); - sbio->page_count++; - if (sbio->page_count == wr_ctx->pages_per_wr_bio) - scrub_wr_submit(sctx); - mutex_unlock(&wr_ctx->wr_lock); - - return 0; -} - -static void scrub_wr_submit(struct scrub_ctx *sctx) -{ - struct scrub_wr_ctx *wr_ctx = &sctx->wr_ctx; - struct scrub_bio *sbio; - - if (!wr_ctx->wr_curr_bio) - return; - - sbio = wr_ctx->wr_curr_bio; - wr_ctx->wr_curr_bio = NULL; - WARN_ON(!sbio->bio->bi_bdev); - scrub_pending_bio_inc(sctx); - /* process all writes in a single worker thread. Then the block layer - * orders the requests before sending them to the driver which - * doubled the write performance on spinning disks when measured - * with Linux 3.5 */ - btrfsic_submit_bio(sbio->bio); -} - -static void scrub_wr_bio_end_io(struct bio *bio) -{ - struct scrub_bio *sbio = bio->bi_private; - struct btrfs_fs_info *fs_info = sbio->dev->dev_root->fs_info; - - sbio->err = bio->bi_error; - sbio->bio = bio; - - btrfs_init_work(&sbio->work, btrfs_scrubwrc_helper, - scrub_wr_bio_end_io_worker, NULL, NULL); - btrfs_queue_work(fs_info->scrub_wr_completion_workers, &sbio->work); -} - -static void scrub_wr_bio_end_io_worker(struct btrfs_work *work) -{ - struct scrub_bio *sbio = container_of(work, struct scrub_bio, work); - struct scrub_ctx *sctx = sbio->sctx; - int i; - - WARN_ON(sbio->page_count > SCRUB_PAGES_PER_WR_BIO); - if (sbio->err) { - struct btrfs_dev_replace *dev_replace = - &sbio->sctx->dev_root->fs_info->dev_replace; - - for (i = 0; i < sbio->page_count; i++) { - struct scrub_page *spage = sbio->pagev[i]; - - spage->io_error = 1; - btrfs_dev_replace_stats_inc(&dev_replace-> - num_write_errors); - } - } - - for (i = 0; i < sbio->page_count; i++) - scrub_page_put(sbio->pagev[i]); - - bio_put(sbio->bio); - kfree(sbio); - scrub_pending_bio_dec(sctx); -} - -static int scrub_checksum(struct scrub_block *sblock) -{ - u64 flags; - int ret; - - /* - * No need to initialize these stats currently, - * because this function only use return value - * instead of these stats value. - * - * Todo: - * always use stats - */ - sblock->header_error = 0; - sblock->generation_error = 0; - sblock->checksum_error = 0; - - WARN_ON(sblock->page_count < 1); - flags = sblock->pagev[0]->flags; - ret = 0; - if (flags & BTRFS_EXTENT_FLAG_DATA) - ret = scrub_checksum_data(sblock); - else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) - ret = scrub_checksum_tree_block(sblock); - else if (flags & BTRFS_EXTENT_FLAG_SUPER) - (void)scrub_checksum_super(sblock); - else - WARN_ON(1); - if (ret) - scrub_handle_errored_block(sblock); - - return ret; -} - -static int scrub_checksum_data(struct scrub_block *sblock) -{ - struct scrub_ctx *sctx = sblock->sctx; - u8 csum[BTRFS_CSUM_SIZE]; - u8 *on_disk_csum; - struct page *page; - void *buffer; - u32 crc = ~(u32)0; - u64 len; - int index; - - BUG_ON(sblock->page_count < 1); - if (!sblock->pagev[0]->have_csum) - return 0; - - on_disk_csum = sblock->pagev[0]->csum; - page = sblock->pagev[0]->page; - buffer = kmap_atomic(page); - - len = sctx->sectorsize; - index = 0; - for (;;) { - u64 l = min_t(u64, len, PAGE_SIZE); - - crc = btrfs_csum_data(buffer, crc, l); - kunmap_atomic(buffer); - len -= l; - if (len == 0) - break; - index++; - BUG_ON(index >= sblock->page_count); - BUG_ON(!sblock->pagev[index]->page); - page = sblock->pagev[index]->page; - buffer = kmap_atomic(page); - } - - btrfs_csum_final(crc, csum); - if (memcmp(csum, on_disk_csum, sctx->csum_size)) - sblock->checksum_error = 1; - - return sblock->checksum_error; -} - -static int scrub_checksum_tree_block(struct scrub_block *sblock) -{ - struct scrub_ctx *sctx = sblock->sctx; - struct btrfs_header *h; - struct btrfs_root *root = sctx->dev_root; - struct btrfs_fs_info *fs_info = root->fs_info; - u8 calculated_csum[BTRFS_CSUM_SIZE]; - u8 on_disk_csum[BTRFS_CSUM_SIZE]; - struct page *page; - void *mapped_buffer; - u64 mapped_size; - void *p; - u32 crc = ~(u32)0; - u64 len; - int index; - - BUG_ON(sblock->page_count < 1); - page = sblock->pagev[0]->page; - mapped_buffer = kmap_atomic(page); - h = (struct btrfs_header *)mapped_buffer; - memcpy(on_disk_csum, h->csum, sctx->csum_size); - - /* - * we don't use the getter functions here, as we - * a) don't have an extent buffer and - * b) the page is already kmapped - */ - if (sblock->pagev[0]->logical != btrfs_stack_header_bytenr(h)) - sblock->header_error = 1; - - if (sblock->pagev[0]->generation != btrfs_stack_header_generation(h)) { - sblock->header_error = 1; - sblock->generation_error = 1; - } - - if (!scrub_check_fsid(h->fsid, sblock->pagev[0])) - sblock->header_error = 1; - - if (memcmp(h->chunk_tree_uuid, fs_info->chunk_tree_uuid, - BTRFS_UUID_SIZE)) - sblock->header_error = 1; - - len = sctx->nodesize - BTRFS_CSUM_SIZE; - mapped_size = PAGE_SIZE - BTRFS_CSUM_SIZE; - p = ((u8 *)mapped_buffer) + BTRFS_CSUM_SIZE; - index = 0; - for (;;) { - u64 l = min_t(u64, len, mapped_size); - - crc = btrfs_csum_data(p, crc, l); - kunmap_atomic(mapped_buffer); - len -= l; - if (len == 0) - break; - index++; - BUG_ON(index >= sblock->page_count); - BUG_ON(!sblock->pagev[index]->page); - page = sblock->pagev[index]->page; - mapped_buffer = kmap_atomic(page); - mapped_size = PAGE_SIZE; - p = mapped_buffer; - } - - btrfs_csum_final(crc, calculated_csum); - if (memcmp(calculated_csum, on_disk_csum, sctx->csum_size)) - sblock->checksum_error = 1; - - return sblock->header_error || sblock->checksum_error; -} - -static int scrub_checksum_super(struct scrub_block *sblock) -{ - struct btrfs_super_block *s; - struct scrub_ctx *sctx = sblock->sctx; - u8 calculated_csum[BTRFS_CSUM_SIZE]; - u8 on_disk_csum[BTRFS_CSUM_SIZE]; - struct page *page; - void *mapped_buffer; - u64 mapped_size; - void *p; - u32 crc = ~(u32)0; - int fail_gen = 0; - int fail_cor = 0; - u64 len; - int index; - - BUG_ON(sblock->page_count < 1); - page = sblock->pagev[0]->page; - mapped_buffer = kmap_atomic(page); - s = (struct btrfs_super_block *)mapped_buffer; - memcpy(on_disk_csum, s->csum, sctx->csum_size); - - if (sblock->pagev[0]->logical != btrfs_super_bytenr(s)) - ++fail_cor; - - if (sblock->pagev[0]->generation != btrfs_super_generation(s)) - ++fail_gen; - - if (!scrub_check_fsid(s->fsid, sblock->pagev[0])) - ++fail_cor; - - len = BTRFS_SUPER_INFO_SIZE - BTRFS_CSUM_SIZE; - mapped_size = PAGE_SIZE - BTRFS_CSUM_SIZE; - p = ((u8 *)mapped_buffer) + BTRFS_CSUM_SIZE; - index = 0; - for (;;) { - u64 l = min_t(u64, len, mapped_size); - - crc = btrfs_csum_data(p, crc, l); - kunmap_atomic(mapped_buffer); - len -= l; - if (len == 0) - break; - index++; - BUG_ON(index >= sblock->page_count); - BUG_ON(!sblock->pagev[index]->page); - page = sblock->pagev[index]->page; - mapped_buffer = kmap_atomic(page); - mapped_size = PAGE_SIZE; - p = mapped_buffer; - } - - btrfs_csum_final(crc, calculated_csum); - if (memcmp(calculated_csum, on_disk_csum, sctx->csum_size)) - ++fail_cor; - - if (fail_cor + fail_gen) { - /* - * if we find an error in a super block, we just report it. - * They will get written with the next transaction commit - * anyway - */ - spin_lock(&sctx->stat_lock); - ++sctx->stat.super_errors; - spin_unlock(&sctx->stat_lock); - if (fail_cor) - btrfs_dev_stat_inc_and_print(sblock->pagev[0]->dev, - BTRFS_DEV_STAT_CORRUPTION_ERRS); - else - btrfs_dev_stat_inc_and_print(sblock->pagev[0]->dev, - BTRFS_DEV_STAT_GENERATION_ERRS); - } - - return fail_cor + fail_gen; -} - -static void scrub_block_get(struct scrub_block *sblock) -{ - atomic_inc(&sblock->refs); -} - -static void scrub_block_put(struct scrub_block *sblock) -{ - if (atomic_dec_and_test(&sblock->refs)) { - int i; - - if (sblock->sparity) - scrub_parity_put(sblock->sparity); - - for (i = 0; i < sblock->page_count; i++) - scrub_page_put(sblock->pagev[i]); - kfree(sblock); - } -} - -static void scrub_page_get(struct scrub_page *spage) -{ - atomic_inc(&spage->refs); -} - -static void scrub_page_put(struct scrub_page *spage) -{ - if (atomic_dec_and_test(&spage->refs)) { - if (spage->page) - __free_page(spage->page); - kfree(spage); - } -} - -static void scrub_submit(struct scrub_ctx *sctx) -{ - struct scrub_bio *sbio; - - if (sctx->curr == -1) - return; - - sbio = sctx->bios[sctx->curr]; - sctx->curr = -1; - scrub_pending_bio_inc(sctx); - btrfsic_submit_bio(sbio->bio); -} - -static int scrub_add_page_to_rd_bio(struct scrub_ctx *sctx, - struct scrub_page *spage) -{ - struct scrub_block *sblock = spage->sblock; - struct scrub_bio *sbio; - int ret; - -again: - /* - * grab a fresh bio or wait for one to become available - */ - while (sctx->curr == -1) { - spin_lock(&sctx->list_lock); - sctx->curr = sctx->first_free; - if (sctx->curr != -1) { - sctx->first_free = sctx->bios[sctx->curr]->next_free; - sctx->bios[sctx->curr]->next_free = -1; - sctx->bios[sctx->curr]->page_count = 0; - spin_unlock(&sctx->list_lock); - } else { - spin_unlock(&sctx->list_lock); - wait_event(sctx->list_wait, sctx->first_free != -1); - } - } - sbio = sctx->bios[sctx->curr]; - if (sbio->page_count == 0) { - struct bio *bio; - - sbio->physical = spage->physical; - sbio->logical = spage->logical; - sbio->dev = spage->dev; - bio = sbio->bio; - if (!bio) { - bio = btrfs_io_bio_alloc(GFP_KERNEL, - sctx->pages_per_rd_bio); - if (!bio) - return -ENOMEM; - sbio->bio = bio; - } - - bio->bi_private = sbio; - bio->bi_end_io = scrub_bio_end_io; - bio->bi_bdev = sbio->dev->bdev; - bio->bi_iter.bi_sector = sbio->physical >> 9; - bio_set_op_attrs(bio, REQ_OP_READ, 0); - sbio->err = 0; - } else if (sbio->physical + sbio->page_count * PAGE_SIZE != - spage->physical || - sbio->logical + sbio->page_count * PAGE_SIZE != - spage->logical || - sbio->dev != spage->dev) { - scrub_submit(sctx); - goto again; - } - - sbio->pagev[sbio->page_count] = spage; - ret = bio_add_page(sbio->bio, spage->page, PAGE_SIZE, 0); - if (ret != PAGE_SIZE) { - if (sbio->page_count < 1) { - bio_put(sbio->bio); - sbio->bio = NULL; - return -EIO; - } - scrub_submit(sctx); - goto again; - } - - scrub_block_get(sblock); /* one for the page added to the bio */ - atomic_inc(&sblock->outstanding_pages); - sbio->page_count++; - if (sbio->page_count == sctx->pages_per_rd_bio) - scrub_submit(sctx); - - return 0; -} - -static void scrub_missing_raid56_end_io(struct bio *bio) -{ - struct scrub_block *sblock = bio->bi_private; - struct btrfs_fs_info *fs_info = sblock->sctx->dev_root->fs_info; - - if (bio->bi_error) - sblock->no_io_error_seen = 0; - - bio_put(bio); - - btrfs_queue_work(fs_info->scrub_workers, &sblock->work); -} - -static void scrub_missing_raid56_worker(struct btrfs_work *work) -{ - struct scrub_block *sblock = container_of(work, struct scrub_block, work); - struct scrub_ctx *sctx = sblock->sctx; - u64 logical; - struct btrfs_device *dev; - - logical = sblock->pagev[0]->logical; - dev = sblock->pagev[0]->dev; - - if (sblock->no_io_error_seen) - scrub_recheck_block_checksum(sblock); - - if (!sblock->no_io_error_seen) { - spin_lock(&sctx->stat_lock); - sctx->stat.read_errors++; - spin_unlock(&sctx->stat_lock); - btrfs_err_rl_in_rcu(sctx->dev_root->fs_info, - "IO error rebuilding logical %llu for dev %s", - logical, rcu_str_deref(dev->name)); - } else if (sblock->header_error || sblock->checksum_error) { - spin_lock(&sctx->stat_lock); - sctx->stat.uncorrectable_errors++; - spin_unlock(&sctx->stat_lock); - btrfs_err_rl_in_rcu(sctx->dev_root->fs_info, - "failed to rebuild valid logical %llu for dev %s", - logical, rcu_str_deref(dev->name)); - } else { - scrub_write_block_to_dev_replace(sblock); - } - - scrub_block_put(sblock); - - if (sctx->is_dev_replace && - atomic_read(&sctx->wr_ctx.flush_all_writes)) { - mutex_lock(&sctx->wr_ctx.wr_lock); - scrub_wr_submit(sctx); - mutex_unlock(&sctx->wr_ctx.wr_lock); - } - - scrub_pending_bio_dec(sctx); -} - -static void scrub_missing_raid56_pages(struct scrub_block *sblock) -{ - struct scrub_ctx *sctx = sblock->sctx; - struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info; - u64 length = sblock->page_count * PAGE_SIZE; - u64 logical = sblock->pagev[0]->logical; - struct btrfs_bio *bbio = NULL; - struct bio *bio; - struct btrfs_raid_bio *rbio; - int ret; - int i; - - ret = btrfs_map_sblock(fs_info, REQ_GET_READ_MIRRORS, logical, &length, - &bbio, 0, 1); - if (ret || !bbio || !bbio->raid_map) - goto bbio_out; - - if (WARN_ON(!sctx->is_dev_replace || - !(bbio->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK))) { - /* - * We shouldn't be scrubbing a missing device. Even for dev - * replace, we should only get here for RAID 5/6. We either - * managed to mount something with no mirrors remaining or - * there's a bug in scrub_remap_extent()/btrfs_map_block(). - */ - goto bbio_out; - } - - bio = btrfs_io_bio_alloc(GFP_NOFS, 0); - if (!bio) - goto bbio_out; - - bio->bi_iter.bi_sector = logical >> 9; - bio->bi_private = sblock; - bio->bi_end_io = scrub_missing_raid56_end_io; - - rbio = raid56_alloc_missing_rbio(sctx->dev_root, bio, bbio, length); - if (!rbio) - goto rbio_out; - - for (i = 0; i < sblock->page_count; i++) { - struct scrub_page *spage = sblock->pagev[i]; - - raid56_add_scrub_pages(rbio, spage->page, spage->logical); - } - - btrfs_init_work(&sblock->work, btrfs_scrub_helper, - scrub_missing_raid56_worker, NULL, NULL); - scrub_block_get(sblock); - scrub_pending_bio_inc(sctx); - raid56_submit_missing_rbio(rbio); - return; - -rbio_out: - bio_put(bio); -bbio_out: - btrfs_put_bbio(bbio); - spin_lock(&sctx->stat_lock); - sctx->stat.malloc_errors++; - spin_unlock(&sctx->stat_lock); -} - -static int scrub_pages(struct scrub_ctx *sctx, u64 logical, u64 len, - u64 physical, struct btrfs_device *dev, u64 flags, - u64 gen, int mirror_num, u8 *csum, int force, - u64 physical_for_dev_replace) -{ - struct scrub_block *sblock; - int index; - - sblock = kzalloc(sizeof(*sblock), GFP_KERNEL); - if (!sblock) { - spin_lock(&sctx->stat_lock); - sctx->stat.malloc_errors++; - spin_unlock(&sctx->stat_lock); - return -ENOMEM; - } - - /* one ref inside this function, plus one for each page added to - * a bio later on */ - atomic_set(&sblock->refs, 1); - sblock->sctx = sctx; - sblock->no_io_error_seen = 1; - - for (index = 0; len > 0; index++) { - struct scrub_page *spage; - u64 l = min_t(u64, len, PAGE_SIZE); - - spage = kzalloc(sizeof(*spage), GFP_KERNEL); - if (!spage) { -leave_nomem: - spin_lock(&sctx->stat_lock); - sctx->stat.malloc_errors++; - spin_unlock(&sctx->stat_lock); - scrub_block_put(sblock); - return -ENOMEM; - } - BUG_ON(index >= SCRUB_MAX_PAGES_PER_BLOCK); - scrub_page_get(spage); - sblock->pagev[index] = spage; - spage->sblock = sblock; - spage->dev = dev; - spage->flags = flags; - spage->generation = gen; - spage->logical = logical; - spage->physical = physical; - spage->physical_for_dev_replace = physical_for_dev_replace; - spage->mirror_num = mirror_num; - if (csum) { - spage->have_csum = 1; - memcpy(spage->csum, csum, sctx->csum_size); - } else { - spage->have_csum = 0; - } - sblock->page_count++; - spage->page = alloc_page(GFP_KERNEL); - if (!spage->page) - goto leave_nomem; - len -= l; - logical += l; - physical += l; - physical_for_dev_replace += l; - } - - WARN_ON(sblock->page_count == 0); - if (dev->missing) { - /* - * This case should only be hit for RAID 5/6 device replace. See - * the comment in scrub_missing_raid56_pages() for details. - */ - scrub_missing_raid56_pages(sblock); - } else { - for (index = 0; index < sblock->page_count; index++) { - struct scrub_page *spage = sblock->pagev[index]; - int ret; - - ret = scrub_add_page_to_rd_bio(sctx, spage); - if (ret) { - scrub_block_put(sblock); - return ret; - } - } - - if (force) - scrub_submit(sctx); - } - - /* last one frees, either here or in bio completion for last page */ - scrub_block_put(sblock); - return 0; -} - -static void scrub_bio_end_io(struct bio *bio) -{ - struct scrub_bio *sbio = bio->bi_private; - struct btrfs_fs_info *fs_info = sbio->dev->dev_root->fs_info; - - sbio->err = bio->bi_error; - sbio->bio = bio; - - btrfs_queue_work(fs_info->scrub_workers, &sbio->work); -} - -static void scrub_bio_end_io_worker(struct btrfs_work *work) -{ - struct scrub_bio *sbio = container_of(work, struct scrub_bio, work); - struct scrub_ctx *sctx = sbio->sctx; - int i; - - BUG_ON(sbio->page_count > SCRUB_PAGES_PER_RD_BIO); - if (sbio->err) { - for (i = 0; i < sbio->page_count; i++) { - struct scrub_page *spage = sbio->pagev[i]; - - spage->io_error = 1; - spage->sblock->no_io_error_seen = 0; - } - } - - /* now complete the scrub_block items that have all pages completed */ - for (i = 0; i < sbio->page_count; i++) { - struct scrub_page *spage = sbio->pagev[i]; - struct scrub_block *sblock = spage->sblock; - - if (atomic_dec_and_test(&sblock->outstanding_pages)) - scrub_block_complete(sblock); - scrub_block_put(sblock); - } - - bio_put(sbio->bio); - sbio->bio = NULL; - spin_lock(&sctx->list_lock); - sbio->next_free = sctx->first_free; - sctx->first_free = sbio->index; - spin_unlock(&sctx->list_lock); - - if (sctx->is_dev_replace && - atomic_read(&sctx->wr_ctx.flush_all_writes)) { - mutex_lock(&sctx->wr_ctx.wr_lock); - scrub_wr_submit(sctx); - mutex_unlock(&sctx->wr_ctx.wr_lock); - } - - scrub_pending_bio_dec(sctx); -} - -static inline void __scrub_mark_bitmap(struct scrub_parity *sparity, - unsigned long *bitmap, - u64 start, u64 len) -{ - u32 offset; - int nsectors; - int sectorsize = sparity->sctx->dev_root->sectorsize; - - if (len >= sparity->stripe_len) { - bitmap_set(bitmap, 0, sparity->nsectors); - return; - } - - start -= sparity->logic_start; - start = div_u64_rem(start, sparity->stripe_len, &offset); - offset /= sectorsize; - nsectors = (int)len / sectorsize; - - if (offset + nsectors <= sparity->nsectors) { - bitmap_set(bitmap, offset, nsectors); - return; - } - - bitmap_set(bitmap, offset, sparity->nsectors - offset); - bitmap_set(bitmap, 0, nsectors - (sparity->nsectors - offset)); -} - -static inline void scrub_parity_mark_sectors_error(struct scrub_parity *sparity, - u64 start, u64 len) -{ - __scrub_mark_bitmap(sparity, sparity->ebitmap, start, len); -} - -static inline void scrub_parity_mark_sectors_data(struct scrub_parity *sparity, - u64 start, u64 len) -{ - __scrub_mark_bitmap(sparity, sparity->dbitmap, start, len); -} - -static void scrub_block_complete(struct scrub_block *sblock) -{ - int corrupted = 0; - - if (!sblock->no_io_error_seen) { - corrupted = 1; - scrub_handle_errored_block(sblock); - } else { - /* - * if has checksum error, write via repair mechanism in - * dev replace case, otherwise write here in dev replace - * case. - */ - corrupted = scrub_checksum(sblock); - if (!corrupted && sblock->sctx->is_dev_replace) - scrub_write_block_to_dev_replace(sblock); - } - - if (sblock->sparity && corrupted && !sblock->data_corrected) { - u64 start = sblock->pagev[0]->logical; - u64 end = sblock->pagev[sblock->page_count - 1]->logical + - PAGE_SIZE; - - scrub_parity_mark_sectors_error(sblock->sparity, - start, end - start); - } -} - -static int scrub_find_csum(struct scrub_ctx *sctx, u64 logical, u8 *csum) -{ - struct btrfs_ordered_sum *sum = NULL; - unsigned long index; - unsigned long num_sectors; - - while (!list_empty(&sctx->csum_list)) { - sum = list_first_entry(&sctx->csum_list, - struct btrfs_ordered_sum, list); - if (sum->bytenr > logical) - return 0; - if (sum->bytenr + sum->len > logical) - break; - - ++sctx->stat.csum_discards; - list_del(&sum->list); - kfree(sum); - sum = NULL; - } - if (!sum) - return 0; - - index = ((u32)(logical - sum->bytenr)) / sctx->sectorsize; - num_sectors = sum->len / sctx->sectorsize; - memcpy(csum, sum->sums + index, sctx->csum_size); - if (index == num_sectors - 1) { - list_del(&sum->list); - kfree(sum); - } - return 1; -} - -/* scrub extent tries to collect up to 64 kB for each bio */ -static int scrub_extent(struct scrub_ctx *sctx, u64 logical, u64 len, - u64 physical, struct btrfs_device *dev, u64 flags, - u64 gen, int mirror_num, u64 physical_for_dev_replace) -{ - int ret; - u8 csum[BTRFS_CSUM_SIZE]; - u32 blocksize; - - if (flags & BTRFS_EXTENT_FLAG_DATA) { - blocksize = sctx->sectorsize; - spin_lock(&sctx->stat_lock); - sctx->stat.data_extents_scrubbed++; - sctx->stat.data_bytes_scrubbed += len; - spin_unlock(&sctx->stat_lock); - } else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { - blocksize = sctx->nodesize; - spin_lock(&sctx->stat_lock); - sctx->stat.tree_extents_scrubbed++; - sctx->stat.tree_bytes_scrubbed += len; - spin_unlock(&sctx->stat_lock); - } else { - blocksize = sctx->sectorsize; - WARN_ON(1); - } - - while (len) { - u64 l = min_t(u64, len, blocksize); - int have_csum = 0; - - if (flags & BTRFS_EXTENT_FLAG_DATA) { - /* push csums to sbio */ - have_csum = scrub_find_csum(sctx, logical, csum); - if (have_csum == 0) - ++sctx->stat.no_csum; - if (sctx->is_dev_replace && !have_csum) { - ret = copy_nocow_pages(sctx, logical, l, - mirror_num, - physical_for_dev_replace); - goto behind_scrub_pages; - } - } - ret = scrub_pages(sctx, logical, l, physical, dev, flags, gen, - mirror_num, have_csum ? csum : NULL, 0, - physical_for_dev_replace); -behind_scrub_pages: - if (ret) - return ret; - len -= l; - logical += l; - physical += l; - physical_for_dev_replace += l; - } - return 0; -} - -static int scrub_pages_for_parity(struct scrub_parity *sparity, - u64 logical, u64 len, - u64 physical, struct btrfs_device *dev, - u64 flags, u64 gen, int mirror_num, u8 *csum) -{ - struct scrub_ctx *sctx = sparity->sctx; - struct scrub_block *sblock; - int index; - - sblock = kzalloc(sizeof(*sblock), GFP_KERNEL); - if (!sblock) { - spin_lock(&sctx->stat_lock); - sctx->stat.malloc_errors++; - spin_unlock(&sctx->stat_lock); - return -ENOMEM; - } - - /* one ref inside this function, plus one for each page added to - * a bio later on */ - atomic_set(&sblock->refs, 1); - sblock->sctx = sctx; - sblock->no_io_error_seen = 1; - sblock->sparity = sparity; - scrub_parity_get(sparity); - - for (index = 0; len > 0; index++) { - struct scrub_page *spage; - u64 l = min_t(u64, len, PAGE_SIZE); - - spage = kzalloc(sizeof(*spage), GFP_KERNEL); - if (!spage) { -leave_nomem: - spin_lock(&sctx->stat_lock); - sctx->stat.malloc_errors++; - spin_unlock(&sctx->stat_lock); - scrub_block_put(sblock); - return -ENOMEM; - } - BUG_ON(index >= SCRUB_MAX_PAGES_PER_BLOCK); - /* For scrub block */ - scrub_page_get(spage); - sblock->pagev[index] = spage; - /* For scrub parity */ - scrub_page_get(spage); - list_add_tail(&spage->list, &sparity->spages); - spage->sblock = sblock; - spage->dev = dev; - spage->flags = flags; - spage->generation = gen; - spage->logical = logical; - spage->physical = physical; - spage->mirror_num = mirror_num; - if (csum) { - spage->have_csum = 1; - memcpy(spage->csum, csum, sctx->csum_size); - } else { - spage->have_csum = 0; - } - sblock->page_count++; - spage->page = alloc_page(GFP_KERNEL); - if (!spage->page) - goto leave_nomem; - len -= l; - logical += l; - physical += l; - } - - WARN_ON(sblock->page_count == 0); - for (index = 0; index < sblock->page_count; index++) { - struct scrub_page *spage = sblock->pagev[index]; - int ret; - - ret = scrub_add_page_to_rd_bio(sctx, spage); - if (ret) { - scrub_block_put(sblock); - return ret; - } - } - - /* last one frees, either here or in bio completion for last page */ - scrub_block_put(sblock); - return 0; -} - -static int scrub_extent_for_parity(struct scrub_parity *sparity, - u64 logical, u64 len, - u64 physical, struct btrfs_device *dev, - u64 flags, u64 gen, int mirror_num) -{ - struct scrub_ctx *sctx = sparity->sctx; - int ret; - u8 csum[BTRFS_CSUM_SIZE]; - u32 blocksize; - - if (dev->missing) { - scrub_parity_mark_sectors_error(sparity, logical, len); - return 0; - } - - if (flags & BTRFS_EXTENT_FLAG_DATA) { - blocksize = sctx->sectorsize; - } else if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { - blocksize = sctx->nodesize; - } else { - blocksize = sctx->sectorsize; - WARN_ON(1); - } - - while (len) { - u64 l = min_t(u64, len, blocksize); - int have_csum = 0; - - if (flags & BTRFS_EXTENT_FLAG_DATA) { - /* push csums to sbio */ - have_csum = scrub_find_csum(sctx, logical, csum); - if (have_csum == 0) - goto skip; - } - ret = scrub_pages_for_parity(sparity, logical, l, physical, dev, - flags, gen, mirror_num, - have_csum ? csum : NULL); - if (ret) - return ret; -skip: - len -= l; - logical += l; - physical += l; - } - return 0; -} - -/* - * Given a physical address, this will calculate it's - * logical offset. if this is a parity stripe, it will return - * the most left data stripe's logical offset. - * - * return 0 if it is a data stripe, 1 means parity stripe. - */ -static int get_raid56_logic_offset(u64 physical, int num, - struct map_lookup *map, u64 *offset, - u64 *stripe_start) -{ - int i; - int j = 0; - u64 stripe_nr; - u64 last_offset; - u32 stripe_index; - u32 rot; - - last_offset = (physical - map->stripes[num].physical) * - nr_data_stripes(map); - if (stripe_start) - *stripe_start = last_offset; - - *offset = last_offset; - for (i = 0; i < nr_data_stripes(map); i++) { - *offset = last_offset + i * map->stripe_len; - - stripe_nr = div_u64(*offset, map->stripe_len); - stripe_nr = div_u64(stripe_nr, nr_data_stripes(map)); - - /* Work out the disk rotation on this stripe-set */ - stripe_nr = div_u64_rem(stripe_nr, map->num_stripes, &rot); - /* calculate which stripe this data locates */ - rot += i; - stripe_index = rot % map->num_stripes; - if (stripe_index == num) - return 0; - if (stripe_index < num) - j++; - } - *offset = last_offset + j * map->stripe_len; - return 1; -} - -static void scrub_free_parity(struct scrub_parity *sparity) -{ - struct scrub_ctx *sctx = sparity->sctx; - struct scrub_page *curr, *next; - int nbits; - - nbits = bitmap_weight(sparity->ebitmap, sparity->nsectors); - if (nbits) { - spin_lock(&sctx->stat_lock); - sctx->stat.read_errors += nbits; - sctx->stat.uncorrectable_errors += nbits; - spin_unlock(&sctx->stat_lock); - } - - list_for_each_entry_safe(curr, next, &sparity->spages, list) { - list_del_init(&curr->list); - scrub_page_put(curr); - } - - kfree(sparity); -} - -static void scrub_parity_bio_endio_worker(struct btrfs_work *work) -{ - struct scrub_parity *sparity = container_of(work, struct scrub_parity, - work); - struct scrub_ctx *sctx = sparity->sctx; - - scrub_free_parity(sparity); - scrub_pending_bio_dec(sctx); -} - -static void scrub_parity_bio_endio(struct bio *bio) -{ - struct scrub_parity *sparity = (struct scrub_parity *)bio->bi_private; - - if (bio->bi_error) - bitmap_or(sparity->ebitmap, sparity->ebitmap, sparity->dbitmap, - sparity->nsectors); - - bio_put(bio); - - btrfs_init_work(&sparity->work, btrfs_scrubparity_helper, - scrub_parity_bio_endio_worker, NULL, NULL); - btrfs_queue_work(sparity->sctx->dev_root->fs_info->scrub_parity_workers, - &sparity->work); -} - -static void scrub_parity_check_and_repair(struct scrub_parity *sparity) -{ - struct scrub_ctx *sctx = sparity->sctx; - struct bio *bio; - struct btrfs_raid_bio *rbio; - struct scrub_page *spage; - struct btrfs_bio *bbio = NULL; - u64 length; - int ret; - - if (!bitmap_andnot(sparity->dbitmap, sparity->dbitmap, sparity->ebitmap, - sparity->nsectors)) - goto out; - - length = sparity->logic_end - sparity->logic_start; - ret = btrfs_map_sblock(sctx->dev_root->fs_info, WRITE, - sparity->logic_start, - &length, &bbio, 0, 1); - if (ret || !bbio || !bbio->raid_map) - goto bbio_out; - - bio = btrfs_io_bio_alloc(GFP_NOFS, 0); - if (!bio) - goto bbio_out; - - bio->bi_iter.bi_sector = sparity->logic_start >> 9; - bio->bi_private = sparity; - bio->bi_end_io = scrub_parity_bio_endio; - - rbio = raid56_parity_alloc_scrub_rbio(sctx->dev_root, bio, bbio, - length, sparity->scrub_dev, - sparity->dbitmap, - sparity->nsectors); - if (!rbio) - goto rbio_out; - - list_for_each_entry(spage, &sparity->spages, list) - raid56_add_scrub_pages(rbio, spage->page, spage->logical); - - scrub_pending_bio_inc(sctx); - raid56_parity_submit_scrub_rbio(rbio); - return; - -rbio_out: - bio_put(bio); -bbio_out: - btrfs_put_bbio(bbio); - bitmap_or(sparity->ebitmap, sparity->ebitmap, sparity->dbitmap, - sparity->nsectors); - spin_lock(&sctx->stat_lock); - sctx->stat.malloc_errors++; - spin_unlock(&sctx->stat_lock); -out: - scrub_free_parity(sparity); -} - -static inline int scrub_calc_parity_bitmap_len(int nsectors) -{ - return DIV_ROUND_UP(nsectors, BITS_PER_LONG) * sizeof(long); -} - -static void scrub_parity_get(struct scrub_parity *sparity) -{ - atomic_inc(&sparity->refs); -} - -static void scrub_parity_put(struct scrub_parity *sparity) -{ - if (!atomic_dec_and_test(&sparity->refs)) - return; - - scrub_parity_check_and_repair(sparity); -} - -static noinline_for_stack int scrub_raid56_parity(struct scrub_ctx *sctx, - struct map_lookup *map, - struct btrfs_device *sdev, - struct btrfs_path *path, - u64 logic_start, - u64 logic_end) -{ - struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info; - struct btrfs_root *root = fs_info->extent_root; - struct btrfs_root *csum_root = fs_info->csum_root; - struct btrfs_extent_item *extent; - struct btrfs_bio *bbio = NULL; - u64 flags; - int ret; - int slot; - struct extent_buffer *l; - struct btrfs_key key; - u64 generation; - u64 extent_logical; - u64 extent_physical; - u64 extent_len; - u64 mapped_length; - struct btrfs_device *extent_dev; - struct scrub_parity *sparity; - int nsectors; - int bitmap_len; - int extent_mirror_num; - int stop_loop = 0; - - nsectors = div_u64(map->stripe_len, root->sectorsize); - bitmap_len = scrub_calc_parity_bitmap_len(nsectors); - sparity = kzalloc(sizeof(struct scrub_parity) + 2 * bitmap_len, - GFP_NOFS); - if (!sparity) { - spin_lock(&sctx->stat_lock); - sctx->stat.malloc_errors++; - spin_unlock(&sctx->stat_lock); - return -ENOMEM; - } - - sparity->stripe_len = map->stripe_len; - sparity->nsectors = nsectors; - sparity->sctx = sctx; - sparity->scrub_dev = sdev; - sparity->logic_start = logic_start; - sparity->logic_end = logic_end; - atomic_set(&sparity->refs, 1); - INIT_LIST_HEAD(&sparity->spages); - sparity->dbitmap = sparity->bitmap; - sparity->ebitmap = (void *)sparity->bitmap + bitmap_len; - - ret = 0; - while (logic_start < logic_end) { - if (btrfs_fs_incompat(fs_info, SKINNY_METADATA)) - key.type = BTRFS_METADATA_ITEM_KEY; - else - key.type = BTRFS_EXTENT_ITEM_KEY; - key.objectid = logic_start; - key.offset = (u64)-1; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out; - - if (ret > 0) { - ret = btrfs_previous_extent_item(root, path, 0); - if (ret < 0) - goto out; - if (ret > 0) { - btrfs_release_path(path); - ret = btrfs_search_slot(NULL, root, &key, - path, 0, 0); - if (ret < 0) - goto out; - } - } - - stop_loop = 0; - while (1) { - u64 bytes; - - l = path->nodes[0]; - slot = path->slots[0]; - if (slot >= btrfs_header_nritems(l)) { - ret = btrfs_next_leaf(root, path); - if (ret == 0) - continue; - if (ret < 0) - goto out; - - stop_loop = 1; - break; - } - btrfs_item_key_to_cpu(l, &key, slot); - - if (key.type != BTRFS_EXTENT_ITEM_KEY && - key.type != BTRFS_METADATA_ITEM_KEY) - goto next; - - if (key.type == BTRFS_METADATA_ITEM_KEY) - bytes = root->nodesize; - else - bytes = key.offset; - - if (key.objectid + bytes <= logic_start) - goto next; - - if (key.objectid >= logic_end) { - stop_loop = 1; - break; - } - - while (key.objectid >= logic_start + map->stripe_len) - logic_start += map->stripe_len; - - extent = btrfs_item_ptr(l, slot, - struct btrfs_extent_item); - flags = btrfs_extent_flags(l, extent); - generation = btrfs_extent_generation(l, extent); - - if ((flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) && - (key.objectid < logic_start || - key.objectid + bytes > - logic_start + map->stripe_len)) { - btrfs_err(fs_info, - "scrub: tree block %llu spanning stripes, ignored. logical=%llu", - key.objectid, logic_start); - spin_lock(&sctx->stat_lock); - sctx->stat.uncorrectable_errors++; - spin_unlock(&sctx->stat_lock); - goto next; - } -again: - extent_logical = key.objectid; - extent_len = bytes; - - if (extent_logical < logic_start) { - extent_len -= logic_start - extent_logical; - extent_logical = logic_start; - } - - if (extent_logical + extent_len > - logic_start + map->stripe_len) - extent_len = logic_start + map->stripe_len - - extent_logical; - - scrub_parity_mark_sectors_data(sparity, extent_logical, - extent_len); - - mapped_length = extent_len; - bbio = NULL; - ret = btrfs_map_block(fs_info, READ, extent_logical, - &mapped_length, &bbio, 0); - if (!ret) { - if (!bbio || mapped_length < extent_len) - ret = -EIO; - } - if (ret) { - btrfs_put_bbio(bbio); - goto out; - } - extent_physical = bbio->stripes[0].physical; - extent_mirror_num = bbio->mirror_num; - extent_dev = bbio->stripes[0].dev; - btrfs_put_bbio(bbio); - - ret = btrfs_lookup_csums_range(csum_root, - extent_logical, - extent_logical + extent_len - 1, - &sctx->csum_list, 1); - if (ret) - goto out; - - ret = scrub_extent_for_parity(sparity, extent_logical, - extent_len, - extent_physical, - extent_dev, flags, - generation, - extent_mirror_num); - - scrub_free_csums(sctx); - - if (ret) - goto out; - - if (extent_logical + extent_len < - key.objectid + bytes) { - logic_start += map->stripe_len; - - if (logic_start >= logic_end) { - stop_loop = 1; - break; - } - - if (logic_start < key.objectid + bytes) { - cond_resched(); - goto again; - } - } -next: - path->slots[0]++; - } - - btrfs_release_path(path); - - if (stop_loop) - break; - - logic_start += map->stripe_len; - } -out: - if (ret < 0) - scrub_parity_mark_sectors_error(sparity, logic_start, - logic_end - logic_start); - scrub_parity_put(sparity); - scrub_submit(sctx); - mutex_lock(&sctx->wr_ctx.wr_lock); - scrub_wr_submit(sctx); - mutex_unlock(&sctx->wr_ctx.wr_lock); - - btrfs_release_path(path); - return ret < 0 ? ret : 0; -} - -static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx, - struct map_lookup *map, - struct btrfs_device *scrub_dev, - int num, u64 base, u64 length, - int is_dev_replace) -{ - struct btrfs_path *path, *ppath; - struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info; - struct btrfs_root *root = fs_info->extent_root; - struct btrfs_root *csum_root = fs_info->csum_root; - struct btrfs_extent_item *extent; - struct blk_plug plug; - u64 flags; - int ret; - int slot; - u64 nstripes; - struct extent_buffer *l; - u64 physical; - u64 logical; - u64 logic_end; - u64 physical_end; - u64 generation; - int mirror_num; - struct reada_control *reada1; - struct reada_control *reada2; - struct btrfs_key key; - struct btrfs_key key_end; - u64 increment = map->stripe_len; - u64 offset; - u64 extent_logical; - u64 extent_physical; - u64 extent_len; - u64 stripe_logical; - u64 stripe_end; - struct btrfs_device *extent_dev; - int extent_mirror_num; - int stop_loop = 0; - - physical = map->stripes[num].physical; - offset = 0; - nstripes = div_u64(length, map->stripe_len); - if (map->type & BTRFS_BLOCK_GROUP_RAID0) { - offset = map->stripe_len * num; - increment = map->stripe_len * map->num_stripes; - mirror_num = 1; - } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { - int factor = map->num_stripes / map->sub_stripes; - offset = map->stripe_len * (num / map->sub_stripes); - increment = map->stripe_len * factor; - mirror_num = num % map->sub_stripes + 1; - } else if (map->type & BTRFS_BLOCK_GROUP_RAID1) { - increment = map->stripe_len; - mirror_num = num % map->num_stripes + 1; - } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { - increment = map->stripe_len; - mirror_num = num % map->num_stripes + 1; - } else if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) { - get_raid56_logic_offset(physical, num, map, &offset, NULL); - increment = map->stripe_len * nr_data_stripes(map); - mirror_num = 1; - } else { - increment = map->stripe_len; - mirror_num = 1; - } - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - ppath = btrfs_alloc_path(); - if (!ppath) { - btrfs_free_path(path); - return -ENOMEM; - } - - /* - * work on commit root. The related disk blocks are static as - * long as COW is applied. This means, it is save to rewrite - * them to repair disk errors without any race conditions - */ - path->search_commit_root = 1; - path->skip_locking = 1; - - ppath->search_commit_root = 1; - ppath->skip_locking = 1; - /* - * trigger the readahead for extent tree csum tree and wait for - * completion. During readahead, the scrub is officially paused - * to not hold off transaction commits - */ - logical = base + offset; - physical_end = physical + nstripes * map->stripe_len; - if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) { - get_raid56_logic_offset(physical_end, num, - map, &logic_end, NULL); - logic_end += base; - } else { - logic_end = logical + increment * nstripes; - } - wait_event(sctx->list_wait, - atomic_read(&sctx->bios_in_flight) == 0); - scrub_blocked_if_needed(fs_info); - - /* FIXME it might be better to start readahead at commit root */ - key.objectid = logical; - key.type = BTRFS_EXTENT_ITEM_KEY; - key.offset = (u64)0; - key_end.objectid = logic_end; - key_end.type = BTRFS_METADATA_ITEM_KEY; - key_end.offset = (u64)-1; - reada1 = btrfs_reada_add(root, &key, &key_end); - - key.objectid = BTRFS_EXTENT_CSUM_OBJECTID; - key.type = BTRFS_EXTENT_CSUM_KEY; - key.offset = logical; - key_end.objectid = BTRFS_EXTENT_CSUM_OBJECTID; - key_end.type = BTRFS_EXTENT_CSUM_KEY; - key_end.offset = logic_end; - reada2 = btrfs_reada_add(csum_root, &key, &key_end); - - if (!IS_ERR(reada1)) - btrfs_reada_wait(reada1); - if (!IS_ERR(reada2)) - btrfs_reada_wait(reada2); - - - /* - * collect all data csums for the stripe to avoid seeking during - * the scrub. This might currently (crc32) end up to be about 1MB - */ - blk_start_plug(&plug); - - /* - * now find all extents for each stripe and scrub them - */ - ret = 0; - while (physical < physical_end) { - /* - * canceled? - */ - if (atomic_read(&fs_info->scrub_cancel_req) || - atomic_read(&sctx->cancel_req)) { - ret = -ECANCELED; - goto out; - } - /* - * check to see if we have to pause - */ - if (atomic_read(&fs_info->scrub_pause_req)) { - /* push queued extents */ - atomic_set(&sctx->wr_ctx.flush_all_writes, 1); - scrub_submit(sctx); - mutex_lock(&sctx->wr_ctx.wr_lock); - scrub_wr_submit(sctx); - mutex_unlock(&sctx->wr_ctx.wr_lock); - wait_event(sctx->list_wait, - atomic_read(&sctx->bios_in_flight) == 0); - atomic_set(&sctx->wr_ctx.flush_all_writes, 0); - scrub_blocked_if_needed(fs_info); - } - - if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) { - ret = get_raid56_logic_offset(physical, num, map, - &logical, - &stripe_logical); - logical += base; - if (ret) { - /* it is parity strip */ - stripe_logical += base; - stripe_end = stripe_logical + increment; - ret = scrub_raid56_parity(sctx, map, scrub_dev, - ppath, stripe_logical, - stripe_end); - if (ret) - goto out; - goto skip; - } - } - - if (btrfs_fs_incompat(fs_info, SKINNY_METADATA)) - key.type = BTRFS_METADATA_ITEM_KEY; - else - key.type = BTRFS_EXTENT_ITEM_KEY; - key.objectid = logical; - key.offset = (u64)-1; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out; - - if (ret > 0) { - ret = btrfs_previous_extent_item(root, path, 0); - if (ret < 0) - goto out; - if (ret > 0) { - /* there's no smaller item, so stick with the - * larger one */ - btrfs_release_path(path); - ret = btrfs_search_slot(NULL, root, &key, - path, 0, 0); - if (ret < 0) - goto out; - } - } - - stop_loop = 0; - while (1) { - u64 bytes; - - l = path->nodes[0]; - slot = path->slots[0]; - if (slot >= btrfs_header_nritems(l)) { - ret = btrfs_next_leaf(root, path); - if (ret == 0) - continue; - if (ret < 0) - goto out; - - stop_loop = 1; - break; - } - btrfs_item_key_to_cpu(l, &key, slot); - - if (key.type != BTRFS_EXTENT_ITEM_KEY && - key.type != BTRFS_METADATA_ITEM_KEY) - goto next; - - if (key.type == BTRFS_METADATA_ITEM_KEY) - bytes = root->nodesize; - else - bytes = key.offset; - - if (key.objectid + bytes <= logical) - goto next; - - if (key.objectid >= logical + map->stripe_len) { - /* out of this device extent */ - if (key.objectid >= logic_end) - stop_loop = 1; - break; - } - - extent = btrfs_item_ptr(l, slot, - struct btrfs_extent_item); - flags = btrfs_extent_flags(l, extent); - generation = btrfs_extent_generation(l, extent); - - if ((flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) && - (key.objectid < logical || - key.objectid + bytes > - logical + map->stripe_len)) { - btrfs_err(fs_info, - "scrub: tree block %llu spanning stripes, ignored. logical=%llu", - key.objectid, logical); - spin_lock(&sctx->stat_lock); - sctx->stat.uncorrectable_errors++; - spin_unlock(&sctx->stat_lock); - goto next; - } - -again: - extent_logical = key.objectid; - extent_len = bytes; - - /* - * trim extent to this stripe - */ - if (extent_logical < logical) { - extent_len -= logical - extent_logical; - extent_logical = logical; - } - if (extent_logical + extent_len > - logical + map->stripe_len) { - extent_len = logical + map->stripe_len - - extent_logical; - } - - extent_physical = extent_logical - logical + physical; - extent_dev = scrub_dev; - extent_mirror_num = mirror_num; - if (is_dev_replace) - scrub_remap_extent(fs_info, extent_logical, - extent_len, &extent_physical, - &extent_dev, - &extent_mirror_num); - - ret = btrfs_lookup_csums_range(csum_root, - extent_logical, - extent_logical + - extent_len - 1, - &sctx->csum_list, 1); - if (ret) - goto out; - - ret = scrub_extent(sctx, extent_logical, extent_len, - extent_physical, extent_dev, flags, - generation, extent_mirror_num, - extent_logical - logical + physical); - - scrub_free_csums(sctx); - - if (ret) - goto out; - - if (extent_logical + extent_len < - key.objectid + bytes) { - if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) { - /* - * loop until we find next data stripe - * or we have finished all stripes. - */ -loop: - physical += map->stripe_len; - ret = get_raid56_logic_offset(physical, - num, map, &logical, - &stripe_logical); - logical += base; - - if (ret && physical < physical_end) { - stripe_logical += base; - stripe_end = stripe_logical + - increment; - ret = scrub_raid56_parity(sctx, - map, scrub_dev, ppath, - stripe_logical, - stripe_end); - if (ret) - goto out; - goto loop; - } - } else { - physical += map->stripe_len; - logical += increment; - } - if (logical < key.objectid + bytes) { - cond_resched(); - goto again; - } - - if (physical >= physical_end) { - stop_loop = 1; - break; - } - } -next: - path->slots[0]++; - } - btrfs_release_path(path); -skip: - logical += increment; - physical += map->stripe_len; - spin_lock(&sctx->stat_lock); - if (stop_loop) - sctx->stat.last_physical = map->stripes[num].physical + - length; - else - sctx->stat.last_physical = physical; - spin_unlock(&sctx->stat_lock); - if (stop_loop) - break; - } -out: - /* push queued extents */ - scrub_submit(sctx); - mutex_lock(&sctx->wr_ctx.wr_lock); - scrub_wr_submit(sctx); - mutex_unlock(&sctx->wr_ctx.wr_lock); - - blk_finish_plug(&plug); - btrfs_free_path(path); - btrfs_free_path(ppath); - return ret < 0 ? ret : 0; -} - -static noinline_for_stack int scrub_chunk(struct scrub_ctx *sctx, - struct btrfs_device *scrub_dev, - u64 chunk_offset, u64 length, - u64 dev_offset, - struct btrfs_block_group_cache *cache, - int is_dev_replace) -{ - struct btrfs_mapping_tree *map_tree = - &sctx->dev_root->fs_info->mapping_tree; - struct map_lookup *map; - struct extent_map *em; - int i; - int ret = 0; - - read_lock(&map_tree->map_tree.lock); - em = lookup_extent_mapping(&map_tree->map_tree, chunk_offset, 1); - read_unlock(&map_tree->map_tree.lock); - - if (!em) { - /* - * Might have been an unused block group deleted by the cleaner - * kthread or relocation. - */ - spin_lock(&cache->lock); - if (!cache->removed) - ret = -EINVAL; - spin_unlock(&cache->lock); - - return ret; - } - - map = em->map_lookup; - if (em->start != chunk_offset) - goto out; - - if (em->len < length) - goto out; - - for (i = 0; i < map->num_stripes; ++i) { - if (map->stripes[i].dev->bdev == scrub_dev->bdev && - map->stripes[i].physical == dev_offset) { - ret = scrub_stripe(sctx, map, scrub_dev, i, - chunk_offset, length, - is_dev_replace); - if (ret) - goto out; - } - } -out: - free_extent_map(em); - - return ret; -} - -static noinline_for_stack -int scrub_enumerate_chunks(struct scrub_ctx *sctx, - struct btrfs_device *scrub_dev, u64 start, u64 end, - int is_dev_replace) -{ - struct btrfs_dev_extent *dev_extent = NULL; - struct btrfs_path *path; - struct btrfs_root *root = sctx->dev_root; - struct btrfs_fs_info *fs_info = root->fs_info; - u64 length; - u64 chunk_offset; - int ret = 0; - int ro_set; - int slot; - struct extent_buffer *l; - struct btrfs_key key; - struct btrfs_key found_key; - struct btrfs_block_group_cache *cache; - struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - path->reada = READA_FORWARD; - path->search_commit_root = 1; - path->skip_locking = 1; - - key.objectid = scrub_dev->devid; - key.offset = 0ull; - key.type = BTRFS_DEV_EXTENT_KEY; - - while (1) { - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - break; - if (ret > 0) { - if (path->slots[0] >= - btrfs_header_nritems(path->nodes[0])) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) - break; - if (ret > 0) { - ret = 0; - break; - } - } else { - ret = 0; - } - } - - l = path->nodes[0]; - slot = path->slots[0]; - - btrfs_item_key_to_cpu(l, &found_key, slot); - - if (found_key.objectid != scrub_dev->devid) - break; - - if (found_key.type != BTRFS_DEV_EXTENT_KEY) - break; - - if (found_key.offset >= end) - break; - - if (found_key.offset < key.offset) - break; - - dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent); - length = btrfs_dev_extent_length(l, dev_extent); - - if (found_key.offset + length <= start) - goto skip; - - chunk_offset = btrfs_dev_extent_chunk_offset(l, dev_extent); - - /* - * get a reference on the corresponding block group to prevent - * the chunk from going away while we scrub it - */ - cache = btrfs_lookup_block_group(fs_info, chunk_offset); - - /* some chunks are removed but not committed to disk yet, - * continue scrubbing */ - if (!cache) - goto skip; - - /* - * we need call btrfs_inc_block_group_ro() with scrubs_paused, - * to avoid deadlock caused by: - * btrfs_inc_block_group_ro() - * -> btrfs_wait_for_commit() - * -> btrfs_commit_transaction() - * -> btrfs_scrub_pause() - */ - scrub_pause_on(fs_info); - ret = btrfs_inc_block_group_ro(root, cache); - if (!ret && is_dev_replace) { - /* - * If we are doing a device replace wait for any tasks - * that started dellaloc right before we set the block - * group to RO mode, as they might have just allocated - * an extent from it or decided they could do a nocow - * write. And if any such tasks did that, wait for their - * ordered extents to complete and then commit the - * current transaction, so that we can later see the new - * extent items in the extent tree - the ordered extents - * create delayed data references (for cow writes) when - * they complete, which will be run and insert the - * corresponding extent items into the extent tree when - * we commit the transaction they used when running - * inode.c:btrfs_finish_ordered_io(). We later use - * the commit root of the extent tree to find extents - * to copy from the srcdev into the tgtdev, and we don't - * want to miss any new extents. - */ - btrfs_wait_block_group_reservations(cache); - btrfs_wait_nocow_writers(cache); - ret = btrfs_wait_ordered_roots(fs_info, -1, - cache->key.objectid, - cache->key.offset); - if (ret > 0) { - struct btrfs_trans_handle *trans; - - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) - ret = PTR_ERR(trans); - else - ret = btrfs_commit_transaction(trans, - root); - if (ret) { - scrub_pause_off(fs_info); - btrfs_put_block_group(cache); - break; - } - } - } - scrub_pause_off(fs_info); - - if (ret == 0) { - ro_set = 1; - } else if (ret == -ENOSPC) { - /* - * btrfs_inc_block_group_ro return -ENOSPC when it - * failed in creating new chunk for metadata. - * It is not a problem for scrub/replace, because - * metadata are always cowed, and our scrub paused - * commit_transactions. - */ - ro_set = 0; - } else { - btrfs_warn(fs_info, - "failed setting block group ro, ret=%d\n", - ret); - btrfs_put_block_group(cache); - break; - } - - btrfs_dev_replace_lock(&fs_info->dev_replace, 1); - dev_replace->cursor_right = found_key.offset + length; - dev_replace->cursor_left = found_key.offset; - dev_replace->item_needs_writeback = 1; - btrfs_dev_replace_unlock(&fs_info->dev_replace, 1); - ret = scrub_chunk(sctx, scrub_dev, chunk_offset, length, - found_key.offset, cache, is_dev_replace); - - /* - * flush, submit all pending read and write bios, afterwards - * wait for them. - * Note that in the dev replace case, a read request causes - * write requests that are submitted in the read completion - * worker. Therefore in the current situation, it is required - * that all write requests are flushed, so that all read and - * write requests are really completed when bios_in_flight - * changes to 0. - */ - atomic_set(&sctx->wr_ctx.flush_all_writes, 1); - scrub_submit(sctx); - mutex_lock(&sctx->wr_ctx.wr_lock); - scrub_wr_submit(sctx); - mutex_unlock(&sctx->wr_ctx.wr_lock); - - wait_event(sctx->list_wait, - atomic_read(&sctx->bios_in_flight) == 0); - - scrub_pause_on(fs_info); - - /* - * must be called before we decrease @scrub_paused. - * make sure we don't block transaction commit while - * we are waiting pending workers finished. - */ - wait_event(sctx->list_wait, - atomic_read(&sctx->workers_pending) == 0); - atomic_set(&sctx->wr_ctx.flush_all_writes, 0); - - scrub_pause_off(fs_info); - - btrfs_dev_replace_lock(&fs_info->dev_replace, 1); - dev_replace->cursor_left = dev_replace->cursor_right; - dev_replace->item_needs_writeback = 1; - btrfs_dev_replace_unlock(&fs_info->dev_replace, 1); - - if (ro_set) - btrfs_dec_block_group_ro(root, cache); - - /* - * We might have prevented the cleaner kthread from deleting - * this block group if it was already unused because we raced - * and set it to RO mode first. So add it back to the unused - * list, otherwise it might not ever be deleted unless a manual - * balance is triggered or it becomes used and unused again. - */ - spin_lock(&cache->lock); - if (!cache->removed && !cache->ro && cache->reserved == 0 && - btrfs_block_group_used(&cache->item) == 0) { - spin_unlock(&cache->lock); - spin_lock(&fs_info->unused_bgs_lock); - if (list_empty(&cache->bg_list)) { - btrfs_get_block_group(cache); - list_add_tail(&cache->bg_list, - &fs_info->unused_bgs); - } - spin_unlock(&fs_info->unused_bgs_lock); - } else { - spin_unlock(&cache->lock); - } - - btrfs_put_block_group(cache); - if (ret) - break; - if (is_dev_replace && - atomic64_read(&dev_replace->num_write_errors) > 0) { - ret = -EIO; - break; - } - if (sctx->stat.malloc_errors > 0) { - ret = -ENOMEM; - break; - } -skip: - key.offset = found_key.offset + length; - btrfs_release_path(path); - } - - btrfs_free_path(path); - - return ret; -} - -static noinline_for_stack int scrub_supers(struct scrub_ctx *sctx, - struct btrfs_device *scrub_dev) -{ - int i; - u64 bytenr; - u64 gen; - int ret; - struct btrfs_root *root = sctx->dev_root; - - if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state)) - return -EIO; - - /* Seed devices of a new filesystem has their own generation. */ - if (scrub_dev->fs_devices != root->fs_info->fs_devices) - gen = scrub_dev->generation; - else - gen = root->fs_info->last_trans_committed; - - for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { - bytenr = btrfs_sb_offset(i); - if (bytenr + BTRFS_SUPER_INFO_SIZE > - scrub_dev->commit_total_bytes) - break; - - ret = scrub_pages(sctx, bytenr, BTRFS_SUPER_INFO_SIZE, bytenr, - scrub_dev, BTRFS_EXTENT_FLAG_SUPER, gen, i, - NULL, 1, bytenr); - if (ret) - return ret; - } - wait_event(sctx->list_wait, atomic_read(&sctx->bios_in_flight) == 0); - - return 0; -} - -/* - * get a reference count on fs_info->scrub_workers. start worker if necessary - */ -static noinline_for_stack int scrub_workers_get(struct btrfs_fs_info *fs_info, - int is_dev_replace) -{ - unsigned int flags = WQ_FREEZABLE | WQ_UNBOUND; - int max_active = fs_info->thread_pool_size; - - if (fs_info->scrub_workers_refcnt == 0) { - if (is_dev_replace) - fs_info->scrub_workers = - btrfs_alloc_workqueue(fs_info, "scrub", flags, - 1, 4); - else - fs_info->scrub_workers = - btrfs_alloc_workqueue(fs_info, "scrub", flags, - max_active, 4); - if (!fs_info->scrub_workers) - goto fail_scrub_workers; - - fs_info->scrub_wr_completion_workers = - btrfs_alloc_workqueue(fs_info, "scrubwrc", flags, - max_active, 2); - if (!fs_info->scrub_wr_completion_workers) - goto fail_scrub_wr_completion_workers; - - fs_info->scrub_nocow_workers = - btrfs_alloc_workqueue(fs_info, "scrubnc", flags, 1, 0); - if (!fs_info->scrub_nocow_workers) - goto fail_scrub_nocow_workers; - fs_info->scrub_parity_workers = - btrfs_alloc_workqueue(fs_info, "scrubparity", flags, - max_active, 2); - if (!fs_info->scrub_parity_workers) - goto fail_scrub_parity_workers; - } - ++fs_info->scrub_workers_refcnt; - return 0; - -fail_scrub_parity_workers: - btrfs_destroy_workqueue(fs_info->scrub_nocow_workers); -fail_scrub_nocow_workers: - btrfs_destroy_workqueue(fs_info->scrub_wr_completion_workers); -fail_scrub_wr_completion_workers: - btrfs_destroy_workqueue(fs_info->scrub_workers); -fail_scrub_workers: - return -ENOMEM; -} - -static noinline_for_stack void scrub_workers_put(struct btrfs_fs_info *fs_info) -{ - if (--fs_info->scrub_workers_refcnt == 0) { - btrfs_destroy_workqueue(fs_info->scrub_workers); - btrfs_destroy_workqueue(fs_info->scrub_wr_completion_workers); - btrfs_destroy_workqueue(fs_info->scrub_nocow_workers); - btrfs_destroy_workqueue(fs_info->scrub_parity_workers); - } - WARN_ON(fs_info->scrub_workers_refcnt < 0); -} - -int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start, - u64 end, struct btrfs_scrub_progress *progress, - int readonly, int is_dev_replace) -{ - struct scrub_ctx *sctx; - int ret; - struct btrfs_device *dev; - struct rcu_string *name; - - if (btrfs_fs_closing(fs_info)) - return -EINVAL; - - if (fs_info->chunk_root->nodesize > BTRFS_STRIPE_LEN) { - /* - * in this case scrub is unable to calculate the checksum - * the way scrub is implemented. Do not handle this - * situation at all because it won't ever happen. - */ - btrfs_err(fs_info, - "scrub: size assumption nodesize <= BTRFS_STRIPE_LEN (%d <= %d) fails", - fs_info->chunk_root->nodesize, BTRFS_STRIPE_LEN); - return -EINVAL; - } - - if (fs_info->chunk_root->sectorsize != PAGE_SIZE) { - /* not supported for data w/o checksums */ - btrfs_err_rl(fs_info, - "scrub: size assumption sectorsize != PAGE_SIZE (%d != %lu) fails", - fs_info->chunk_root->sectorsize, PAGE_SIZE); - return -EINVAL; - } - - if (fs_info->chunk_root->nodesize > - PAGE_SIZE * SCRUB_MAX_PAGES_PER_BLOCK || - fs_info->chunk_root->sectorsize > - PAGE_SIZE * SCRUB_MAX_PAGES_PER_BLOCK) { - /* - * would exhaust the array bounds of pagev member in - * struct scrub_block - */ - btrfs_err(fs_info, - "scrub: size assumption nodesize and sectorsize <= SCRUB_MAX_PAGES_PER_BLOCK (%d <= %d && %d <= %d) fails", - fs_info->chunk_root->nodesize, - SCRUB_MAX_PAGES_PER_BLOCK, - fs_info->chunk_root->sectorsize, - SCRUB_MAX_PAGES_PER_BLOCK); - return -EINVAL; - } - - - mutex_lock(&fs_info->fs_devices->device_list_mutex); - dev = btrfs_find_device(fs_info, devid, NULL, NULL); - if (!dev || (dev->missing && !is_dev_replace)) { - mutex_unlock(&fs_info->fs_devices->device_list_mutex); - return -ENODEV; - } - - if (!is_dev_replace && !readonly && !dev->writeable) { - mutex_unlock(&fs_info->fs_devices->device_list_mutex); - rcu_read_lock(); - name = rcu_dereference(dev->name); - btrfs_err(fs_info, "scrub: device %s is not writable", - name->str); - rcu_read_unlock(); - return -EROFS; - } - - mutex_lock(&fs_info->scrub_lock); - if (!dev->in_fs_metadata || dev->is_tgtdev_for_dev_replace) { - mutex_unlock(&fs_info->scrub_lock); - mutex_unlock(&fs_info->fs_devices->device_list_mutex); - return -EIO; - } - - btrfs_dev_replace_lock(&fs_info->dev_replace, 0); - if (dev->scrub_device || - (!is_dev_replace && - btrfs_dev_replace_is_ongoing(&fs_info->dev_replace))) { - btrfs_dev_replace_unlock(&fs_info->dev_replace, 0); - mutex_unlock(&fs_info->scrub_lock); - mutex_unlock(&fs_info->fs_devices->device_list_mutex); - return -EINPROGRESS; - } - btrfs_dev_replace_unlock(&fs_info->dev_replace, 0); - - ret = scrub_workers_get(fs_info, is_dev_replace); - if (ret) { - mutex_unlock(&fs_info->scrub_lock); - mutex_unlock(&fs_info->fs_devices->device_list_mutex); - return ret; - } - - sctx = scrub_setup_ctx(dev, is_dev_replace); - if (IS_ERR(sctx)) { - mutex_unlock(&fs_info->scrub_lock); - mutex_unlock(&fs_info->fs_devices->device_list_mutex); - scrub_workers_put(fs_info); - return PTR_ERR(sctx); - } - sctx->readonly = readonly; - dev->scrub_device = sctx; - mutex_unlock(&fs_info->fs_devices->device_list_mutex); - - /* - * checking @scrub_pause_req here, we can avoid - * race between committing transaction and scrubbing. - */ - __scrub_blocked_if_needed(fs_info); - atomic_inc(&fs_info->scrubs_running); - mutex_unlock(&fs_info->scrub_lock); - - if (!is_dev_replace) { - /* - * by holding device list mutex, we can - * kick off writing super in log tree sync. - */ - mutex_lock(&fs_info->fs_devices->device_list_mutex); - ret = scrub_supers(sctx, dev); - mutex_unlock(&fs_info->fs_devices->device_list_mutex); - } - - if (!ret) - ret = scrub_enumerate_chunks(sctx, dev, start, end, - is_dev_replace); - - wait_event(sctx->list_wait, atomic_read(&sctx->bios_in_flight) == 0); - atomic_dec(&fs_info->scrubs_running); - wake_up(&fs_info->scrub_pause_wait); - - wait_event(sctx->list_wait, atomic_read(&sctx->workers_pending) == 0); - - if (progress) - memcpy(progress, &sctx->stat, sizeof(*progress)); - - mutex_lock(&fs_info->scrub_lock); - dev->scrub_device = NULL; - scrub_workers_put(fs_info); - mutex_unlock(&fs_info->scrub_lock); - - scrub_put_ctx(sctx); - - return ret; -} - -void btrfs_scrub_pause(struct btrfs_root *root) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - - mutex_lock(&fs_info->scrub_lock); - atomic_inc(&fs_info->scrub_pause_req); - while (atomic_read(&fs_info->scrubs_paused) != - atomic_read(&fs_info->scrubs_running)) { - mutex_unlock(&fs_info->scrub_lock); - wait_event(fs_info->scrub_pause_wait, - atomic_read(&fs_info->scrubs_paused) == - atomic_read(&fs_info->scrubs_running)); - mutex_lock(&fs_info->scrub_lock); - } - mutex_unlock(&fs_info->scrub_lock); -} - -void btrfs_scrub_continue(struct btrfs_root *root) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - - atomic_dec(&fs_info->scrub_pause_req); - wake_up(&fs_info->scrub_pause_wait); -} - -int btrfs_scrub_cancel(struct btrfs_fs_info *fs_info) -{ - mutex_lock(&fs_info->scrub_lock); - if (!atomic_read(&fs_info->scrubs_running)) { - mutex_unlock(&fs_info->scrub_lock); - return -ENOTCONN; - } - - atomic_inc(&fs_info->scrub_cancel_req); - while (atomic_read(&fs_info->scrubs_running)) { - mutex_unlock(&fs_info->scrub_lock); - wait_event(fs_info->scrub_pause_wait, - atomic_read(&fs_info->scrubs_running) == 0); - mutex_lock(&fs_info->scrub_lock); - } - atomic_dec(&fs_info->scrub_cancel_req); - mutex_unlock(&fs_info->scrub_lock); - - return 0; -} - -int btrfs_scrub_cancel_dev(struct btrfs_fs_info *fs_info, - struct btrfs_device *dev) -{ - struct scrub_ctx *sctx; - - mutex_lock(&fs_info->scrub_lock); - sctx = dev->scrub_device; - if (!sctx) { - mutex_unlock(&fs_info->scrub_lock); - return -ENOTCONN; - } - atomic_inc(&sctx->cancel_req); - while (dev->scrub_device) { - mutex_unlock(&fs_info->scrub_lock); - wait_event(fs_info->scrub_pause_wait, - dev->scrub_device == NULL); - mutex_lock(&fs_info->scrub_lock); - } - mutex_unlock(&fs_info->scrub_lock); - - return 0; -} - -int btrfs_scrub_progress(struct btrfs_root *root, u64 devid, - struct btrfs_scrub_progress *progress) -{ - struct btrfs_device *dev; - struct scrub_ctx *sctx = NULL; - - mutex_lock(&root->fs_info->fs_devices->device_list_mutex); - dev = btrfs_find_device(root->fs_info, devid, NULL, NULL); - if (dev) - sctx = dev->scrub_device; - if (sctx) - memcpy(progress, &sctx->stat, sizeof(*progress)); - mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); - - return dev ? (sctx ? 0 : -ENOTCONN) : -ENODEV; -} - -static void scrub_remap_extent(struct btrfs_fs_info *fs_info, - u64 extent_logical, u64 extent_len, - u64 *extent_physical, - struct btrfs_device **extent_dev, - int *extent_mirror_num) -{ - u64 mapped_length; - struct btrfs_bio *bbio = NULL; - int ret; - - mapped_length = extent_len; - ret = btrfs_map_block(fs_info, READ, extent_logical, - &mapped_length, &bbio, 0); - if (ret || !bbio || mapped_length < extent_len || - !bbio->stripes[0].dev->bdev) { - btrfs_put_bbio(bbio); - return; - } - - *extent_physical = bbio->stripes[0].physical; - *extent_mirror_num = bbio->mirror_num; - *extent_dev = bbio->stripes[0].dev; - btrfs_put_bbio(bbio); -} - -static int scrub_setup_wr_ctx(struct scrub_ctx *sctx, - struct scrub_wr_ctx *wr_ctx, - struct btrfs_fs_info *fs_info, - struct btrfs_device *dev, - int is_dev_replace) -{ - WARN_ON(wr_ctx->wr_curr_bio != NULL); - - mutex_init(&wr_ctx->wr_lock); - wr_ctx->wr_curr_bio = NULL; - if (!is_dev_replace) - return 0; - - WARN_ON(!dev->bdev); - wr_ctx->pages_per_wr_bio = SCRUB_PAGES_PER_WR_BIO; - wr_ctx->tgtdev = dev; - atomic_set(&wr_ctx->flush_all_writes, 0); - return 0; -} - -static void scrub_free_wr_ctx(struct scrub_wr_ctx *wr_ctx) -{ - mutex_lock(&wr_ctx->wr_lock); - kfree(wr_ctx->wr_curr_bio); - wr_ctx->wr_curr_bio = NULL; - mutex_unlock(&wr_ctx->wr_lock); -} - -static int copy_nocow_pages(struct scrub_ctx *sctx, u64 logical, u64 len, - int mirror_num, u64 physical_for_dev_replace) -{ - struct scrub_copy_nocow_ctx *nocow_ctx; - struct btrfs_fs_info *fs_info = sctx->dev_root->fs_info; - - nocow_ctx = kzalloc(sizeof(*nocow_ctx), GFP_NOFS); - if (!nocow_ctx) { - spin_lock(&sctx->stat_lock); - sctx->stat.malloc_errors++; - spin_unlock(&sctx->stat_lock); - return -ENOMEM; - } - - scrub_pending_trans_workers_inc(sctx); - - nocow_ctx->sctx = sctx; - nocow_ctx->logical = logical; - nocow_ctx->len = len; - nocow_ctx->mirror_num = mirror_num; - nocow_ctx->physical_for_dev_replace = physical_for_dev_replace; - btrfs_init_work(&nocow_ctx->work, btrfs_scrubnc_helper, - copy_nocow_pages_worker, NULL, NULL); - INIT_LIST_HEAD(&nocow_ctx->inodes); - btrfs_queue_work(fs_info->scrub_nocow_workers, - &nocow_ctx->work); - - return 0; -} - -static int record_inode_for_nocow(u64 inum, u64 offset, u64 root, void *ctx) -{ - struct scrub_copy_nocow_ctx *nocow_ctx = ctx; - struct scrub_nocow_inode *nocow_inode; - - nocow_inode = kzalloc(sizeof(*nocow_inode), GFP_NOFS); - if (!nocow_inode) - return -ENOMEM; - nocow_inode->inum = inum; - nocow_inode->offset = offset; - nocow_inode->root = root; - list_add_tail(&nocow_inode->list, &nocow_ctx->inodes); - return 0; -} - -#define COPY_COMPLETE 1 - -static void copy_nocow_pages_worker(struct btrfs_work *work) -{ - struct scrub_copy_nocow_ctx *nocow_ctx = - container_of(work, struct scrub_copy_nocow_ctx, work); - struct scrub_ctx *sctx = nocow_ctx->sctx; - u64 logical = nocow_ctx->logical; - u64 len = nocow_ctx->len; - int mirror_num = nocow_ctx->mirror_num; - u64 physical_for_dev_replace = nocow_ctx->physical_for_dev_replace; - int ret; - struct btrfs_trans_handle *trans = NULL; - struct btrfs_fs_info *fs_info; - struct btrfs_path *path; - struct btrfs_root *root; - int not_written = 0; - - fs_info = sctx->dev_root->fs_info; - root = fs_info->extent_root; - - path = btrfs_alloc_path(); - if (!path) { - spin_lock(&sctx->stat_lock); - sctx->stat.malloc_errors++; - spin_unlock(&sctx->stat_lock); - not_written = 1; - goto out; - } - - trans = btrfs_join_transaction(root); - if (IS_ERR(trans)) { - not_written = 1; - goto out; - } - - ret = iterate_inodes_from_logical(logical, fs_info, path, - record_inode_for_nocow, nocow_ctx); - if (ret != 0 && ret != -ENOENT) { - btrfs_warn(fs_info, - "iterate_inodes_from_logical() failed: log %llu, phys %llu, len %llu, mir %u, ret %d", - logical, physical_for_dev_replace, len, mirror_num, - ret); - not_written = 1; - goto out; - } - - btrfs_end_transaction(trans, root); - trans = NULL; - while (!list_empty(&nocow_ctx->inodes)) { - struct scrub_nocow_inode *entry; - entry = list_first_entry(&nocow_ctx->inodes, - struct scrub_nocow_inode, - list); - list_del_init(&entry->list); - ret = copy_nocow_pages_for_inode(entry->inum, entry->offset, - entry->root, nocow_ctx); - kfree(entry); - if (ret == COPY_COMPLETE) { - ret = 0; - break; - } else if (ret) { - break; - } - } -out: - while (!list_empty(&nocow_ctx->inodes)) { - struct scrub_nocow_inode *entry; - entry = list_first_entry(&nocow_ctx->inodes, - struct scrub_nocow_inode, - list); - list_del_init(&entry->list); - kfree(entry); - } - if (trans && !IS_ERR(trans)) - btrfs_end_transaction(trans, root); - if (not_written) - btrfs_dev_replace_stats_inc(&fs_info->dev_replace. - num_uncorrectable_read_errors); - - btrfs_free_path(path); - kfree(nocow_ctx); - - scrub_pending_trans_workers_dec(sctx); -} - -static int check_extent_to_block(struct inode *inode, u64 start, u64 len, - u64 logical) -{ - struct extent_state *cached_state = NULL; - struct btrfs_ordered_extent *ordered; - struct extent_io_tree *io_tree; - struct extent_map *em; - u64 lockstart = start, lockend = start + len - 1; - int ret = 0; - - io_tree = &BTRFS_I(inode)->io_tree; - - lock_extent_bits(io_tree, lockstart, lockend, &cached_state); - ordered = btrfs_lookup_ordered_range(inode, lockstart, len); - if (ordered) { - btrfs_put_ordered_extent(ordered); - ret = 1; - goto out_unlock; - } - - em = btrfs_get_extent(inode, NULL, 0, start, len, 0); - if (IS_ERR(em)) { - ret = PTR_ERR(em); - goto out_unlock; - } - - /* - * This extent does not actually cover the logical extent anymore, - * move on to the next inode. - */ - if (em->block_start > logical || - em->block_start + em->block_len < logical + len) { - free_extent_map(em); - ret = 1; - goto out_unlock; - } - free_extent_map(em); - -out_unlock: - unlock_extent_cached(io_tree, lockstart, lockend, &cached_state, - GFP_NOFS); - return ret; -} - -static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root, - struct scrub_copy_nocow_ctx *nocow_ctx) -{ - struct btrfs_fs_info *fs_info = nocow_ctx->sctx->dev_root->fs_info; - struct btrfs_key key; - struct inode *inode; - struct page *page; - struct btrfs_root *local_root; - struct extent_io_tree *io_tree; - u64 physical_for_dev_replace; - u64 nocow_ctx_logical; - u64 len = nocow_ctx->len; - unsigned long index; - int srcu_index; - int ret = 0; - int err = 0; - - key.objectid = root; - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = (u64)-1; - - srcu_index = srcu_read_lock(&fs_info->subvol_srcu); - - local_root = btrfs_read_fs_root_no_name(fs_info, &key); - if (IS_ERR(local_root)) { - srcu_read_unlock(&fs_info->subvol_srcu, srcu_index); - return PTR_ERR(local_root); - } - - key.type = BTRFS_INODE_ITEM_KEY; - key.objectid = inum; - key.offset = 0; - inode = btrfs_iget(fs_info->sb, &key, local_root, NULL); - srcu_read_unlock(&fs_info->subvol_srcu, srcu_index); - if (IS_ERR(inode)) - return PTR_ERR(inode); - - /* Avoid truncate/dio/punch hole.. */ - inode_lock(inode); - inode_dio_wait(inode); - - physical_for_dev_replace = nocow_ctx->physical_for_dev_replace; - io_tree = &BTRFS_I(inode)->io_tree; - nocow_ctx_logical = nocow_ctx->logical; - - ret = check_extent_to_block(inode, offset, len, nocow_ctx_logical); - if (ret) { - ret = ret > 0 ? 0 : ret; - goto out; - } - - while (len >= PAGE_SIZE) { - index = offset >> PAGE_SHIFT; -again: - page = find_or_create_page(inode->i_mapping, index, GFP_NOFS); - if (!page) { - btrfs_err(fs_info, "find_or_create_page() failed"); - ret = -ENOMEM; - goto out; - } - - if (PageUptodate(page)) { - if (PageDirty(page)) - goto next_page; - } else { - ClearPageError(page); - err = extent_read_full_page(io_tree, page, - btrfs_get_extent, - nocow_ctx->mirror_num); - if (err) { - ret = err; - goto next_page; - } - - lock_page(page); - /* - * If the page has been remove from the page cache, - * the data on it is meaningless, because it may be - * old one, the new data may be written into the new - * page in the page cache. - */ - if (page->mapping != inode->i_mapping) { - unlock_page(page); - put_page(page); - goto again; - } - if (!PageUptodate(page)) { - ret = -EIO; - goto next_page; - } - } - - ret = check_extent_to_block(inode, offset, len, - nocow_ctx_logical); - if (ret) { - ret = ret > 0 ? 0 : ret; - goto next_page; - } - - err = write_page_nocow(nocow_ctx->sctx, - physical_for_dev_replace, page); - if (err) - ret = err; -next_page: - unlock_page(page); - put_page(page); - - if (ret) - break; - - offset += PAGE_SIZE; - physical_for_dev_replace += PAGE_SIZE; - nocow_ctx_logical += PAGE_SIZE; - len -= PAGE_SIZE; - } - ret = COPY_COMPLETE; -out: - inode_unlock(inode); - iput(inode); - return ret; -} - -static int write_page_nocow(struct scrub_ctx *sctx, - u64 physical_for_dev_replace, struct page *page) -{ - struct bio *bio; - struct btrfs_device *dev; - int ret; - - dev = sctx->wr_ctx.tgtdev; - if (!dev) - return -EIO; - if (!dev->bdev) { - btrfs_warn_rl(dev->dev_root->fs_info, - "scrub write_page_nocow(bdev == NULL) is unexpected"); - return -EIO; - } - bio = btrfs_io_bio_alloc(GFP_NOFS, 1); - if (!bio) { - spin_lock(&sctx->stat_lock); - sctx->stat.malloc_errors++; - spin_unlock(&sctx->stat_lock); - return -ENOMEM; - } - bio->bi_iter.bi_size = 0; - bio->bi_iter.bi_sector = physical_for_dev_replace >> 9; - bio->bi_bdev = dev->bdev; - bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_SYNC); - ret = bio_add_page(bio, page, PAGE_SIZE, 0); - if (ret != PAGE_SIZE) { -leave_with_eio: - bio_put(bio); - btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS); - return -EIO; - } - - if (btrfsic_submit_bio_wait(bio)) - goto leave_with_eio; - - bio_put(bio); - return 0; -} diff --git a/src/linux/fs/btrfs/send.c b/src/linux/fs/btrfs/send.c deleted file mode 100644 index 71261b4..0000000 --- a/src/linux/fs/btrfs/send.c +++ /dev/null @@ -1,6460 +0,0 @@ -/* - * Copyright (C) 2012 Alexander Block. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "send.h" -#include "backref.h" -#include "hash.h" -#include "locking.h" -#include "disk-io.h" -#include "btrfs_inode.h" -#include "transaction.h" -#include "compression.h" - -/* - * A fs_path is a helper to dynamically build path names with unknown size. - * It reallocates the internal buffer on demand. - * It allows fast adding of path elements on the right side (normal path) and - * fast adding to the left side (reversed path). A reversed path can also be - * unreversed if needed. - */ -struct fs_path { - union { - struct { - char *start; - char *end; - - char *buf; - unsigned short buf_len:15; - unsigned short reversed:1; - char inline_buf[]; - }; - /* - * Average path length does not exceed 200 bytes, we'll have - * better packing in the slab and higher chance to satisfy - * a allocation later during send. - */ - char pad[256]; - }; -}; -#define FS_PATH_INLINE_SIZE \ - (sizeof(struct fs_path) - offsetof(struct fs_path, inline_buf)) - - -/* reused for each extent */ -struct clone_root { - struct btrfs_root *root; - u64 ino; - u64 offset; - - u64 found_refs; -}; - -#define SEND_CTX_MAX_NAME_CACHE_SIZE 128 -#define SEND_CTX_NAME_CACHE_CLEAN_SIZE (SEND_CTX_MAX_NAME_CACHE_SIZE * 2) - -struct send_ctx { - struct file *send_filp; - loff_t send_off; - char *send_buf; - u32 send_size; - u32 send_max_size; - u64 total_send_size; - u64 cmd_send_size[BTRFS_SEND_C_MAX + 1]; - u64 flags; /* 'flags' member of btrfs_ioctl_send_args is u64 */ - - struct btrfs_root *send_root; - struct btrfs_root *parent_root; - struct clone_root *clone_roots; - int clone_roots_cnt; - - /* current state of the compare_tree call */ - struct btrfs_path *left_path; - struct btrfs_path *right_path; - struct btrfs_key *cmp_key; - - /* - * infos of the currently processed inode. In case of deleted inodes, - * these are the values from the deleted inode. - */ - u64 cur_ino; - u64 cur_inode_gen; - int cur_inode_new; - int cur_inode_new_gen; - int cur_inode_deleted; - u64 cur_inode_size; - u64 cur_inode_mode; - u64 cur_inode_rdev; - u64 cur_inode_last_extent; - - u64 send_progress; - - struct list_head new_refs; - struct list_head deleted_refs; - - struct radix_tree_root name_cache; - struct list_head name_cache_list; - int name_cache_size; - - struct file_ra_state ra; - - char *read_buf; - - /* - * We process inodes by their increasing order, so if before an - * incremental send we reverse the parent/child relationship of - * directories such that a directory with a lower inode number was - * the parent of a directory with a higher inode number, and the one - * becoming the new parent got renamed too, we can't rename/move the - * directory with lower inode number when we finish processing it - we - * must process the directory with higher inode number first, then - * rename/move it and then rename/move the directory with lower inode - * number. Example follows. - * - * Tree state when the first send was performed: - * - * . - * |-- a (ino 257) - * |-- b (ino 258) - * | - * | - * |-- c (ino 259) - * | |-- d (ino 260) - * | - * |-- c2 (ino 261) - * - * Tree state when the second (incremental) send is performed: - * - * . - * |-- a (ino 257) - * |-- b (ino 258) - * |-- c2 (ino 261) - * |-- d2 (ino 260) - * |-- cc (ino 259) - * - * The sequence of steps that lead to the second state was: - * - * mv /a/b/c/d /a/b/c2/d2 - * mv /a/b/c /a/b/c2/d2/cc - * - * "c" has lower inode number, but we can't move it (2nd mv operation) - * before we move "d", which has higher inode number. - * - * So we just memorize which move/rename operations must be performed - * later when their respective parent is processed and moved/renamed. - */ - - /* Indexed by parent directory inode number. */ - struct rb_root pending_dir_moves; - - /* - * Reverse index, indexed by the inode number of a directory that - * is waiting for the move/rename of its immediate parent before its - * own move/rename can be performed. - */ - struct rb_root waiting_dir_moves; - - /* - * A directory that is going to be rm'ed might have a child directory - * which is in the pending directory moves index above. In this case, - * the directory can only be removed after the move/rename of its child - * is performed. Example: - * - * Parent snapshot: - * - * . (ino 256) - * |-- a/ (ino 257) - * |-- b/ (ino 258) - * |-- c/ (ino 259) - * | |-- x/ (ino 260) - * | - * |-- y/ (ino 261) - * - * Send snapshot: - * - * . (ino 256) - * |-- a/ (ino 257) - * |-- b/ (ino 258) - * |-- YY/ (ino 261) - * |-- x/ (ino 260) - * - * Sequence of steps that lead to the send snapshot: - * rm -f /a/b/c/foo.txt - * mv /a/b/y /a/b/YY - * mv /a/b/c/x /a/b/YY - * rmdir /a/b/c - * - * When the child is processed, its move/rename is delayed until its - * parent is processed (as explained above), but all other operations - * like update utimes, chown, chgrp, etc, are performed and the paths - * that it uses for those operations must use the orphanized name of - * its parent (the directory we're going to rm later), so we need to - * memorize that name. - * - * Indexed by the inode number of the directory to be deleted. - */ - struct rb_root orphan_dirs; -}; - -struct pending_dir_move { - struct rb_node node; - struct list_head list; - u64 parent_ino; - u64 ino; - u64 gen; - struct list_head update_refs; -}; - -struct waiting_dir_move { - struct rb_node node; - u64 ino; - /* - * There might be some directory that could not be removed because it - * was waiting for this directory inode to be moved first. Therefore - * after this directory is moved, we can try to rmdir the ino rmdir_ino. - */ - u64 rmdir_ino; - bool orphanized; -}; - -struct orphan_dir_info { - struct rb_node node; - u64 ino; - u64 gen; -}; - -struct name_cache_entry { - struct list_head list; - /* - * radix_tree has only 32bit entries but we need to handle 64bit inums. - * We use the lower 32bit of the 64bit inum to store it in the tree. If - * more then one inum would fall into the same entry, we use radix_list - * to store the additional entries. radix_list is also used to store - * entries where two entries have the same inum but different - * generations. - */ - struct list_head radix_list; - u64 ino; - u64 gen; - u64 parent_ino; - u64 parent_gen; - int ret; - int need_later_update; - int name_len; - char name[]; -}; - -static void inconsistent_snapshot_error(struct send_ctx *sctx, - enum btrfs_compare_tree_result result, - const char *what) -{ - const char *result_string; - - switch (result) { - case BTRFS_COMPARE_TREE_NEW: - result_string = "new"; - break; - case BTRFS_COMPARE_TREE_DELETED: - result_string = "deleted"; - break; - case BTRFS_COMPARE_TREE_CHANGED: - result_string = "updated"; - break; - case BTRFS_COMPARE_TREE_SAME: - ASSERT(0); - result_string = "unchanged"; - break; - default: - ASSERT(0); - result_string = "unexpected"; - } - - btrfs_err(sctx->send_root->fs_info, - "Send: inconsistent snapshot, found %s %s for inode %llu without updated inode item, send root is %llu, parent root is %llu", - result_string, what, sctx->cmp_key->objectid, - sctx->send_root->root_key.objectid, - (sctx->parent_root ? - sctx->parent_root->root_key.objectid : 0)); -} - -static int is_waiting_for_move(struct send_ctx *sctx, u64 ino); - -static struct waiting_dir_move * -get_waiting_dir_move(struct send_ctx *sctx, u64 ino); - -static int is_waiting_for_rm(struct send_ctx *sctx, u64 dir_ino); - -static int need_send_hole(struct send_ctx *sctx) -{ - return (sctx->parent_root && !sctx->cur_inode_new && - !sctx->cur_inode_new_gen && !sctx->cur_inode_deleted && - S_ISREG(sctx->cur_inode_mode)); -} - -static void fs_path_reset(struct fs_path *p) -{ - if (p->reversed) { - p->start = p->buf + p->buf_len - 1; - p->end = p->start; - *p->start = 0; - } else { - p->start = p->buf; - p->end = p->start; - *p->start = 0; - } -} - -static struct fs_path *fs_path_alloc(void) -{ - struct fs_path *p; - - p = kmalloc(sizeof(*p), GFP_KERNEL); - if (!p) - return NULL; - p->reversed = 0; - p->buf = p->inline_buf; - p->buf_len = FS_PATH_INLINE_SIZE; - fs_path_reset(p); - return p; -} - -static struct fs_path *fs_path_alloc_reversed(void) -{ - struct fs_path *p; - - p = fs_path_alloc(); - if (!p) - return NULL; - p->reversed = 1; - fs_path_reset(p); - return p; -} - -static void fs_path_free(struct fs_path *p) -{ - if (!p) - return; - if (p->buf != p->inline_buf) - kfree(p->buf); - kfree(p); -} - -static int fs_path_len(struct fs_path *p) -{ - return p->end - p->start; -} - -static int fs_path_ensure_buf(struct fs_path *p, int len) -{ - char *tmp_buf; - int path_len; - int old_buf_len; - - len++; - - if (p->buf_len >= len) - return 0; - - if (len > PATH_MAX) { - WARN_ON(1); - return -ENOMEM; - } - - path_len = p->end - p->start; - old_buf_len = p->buf_len; - - /* - * First time the inline_buf does not suffice - */ - if (p->buf == p->inline_buf) { - tmp_buf = kmalloc(len, GFP_KERNEL); - if (tmp_buf) - memcpy(tmp_buf, p->buf, old_buf_len); - } else { - tmp_buf = krealloc(p->buf, len, GFP_KERNEL); - } - if (!tmp_buf) - return -ENOMEM; - p->buf = tmp_buf; - /* - * The real size of the buffer is bigger, this will let the fast path - * happen most of the time - */ - p->buf_len = ksize(p->buf); - - if (p->reversed) { - tmp_buf = p->buf + old_buf_len - path_len - 1; - p->end = p->buf + p->buf_len - 1; - p->start = p->end - path_len; - memmove(p->start, tmp_buf, path_len + 1); - } else { - p->start = p->buf; - p->end = p->start + path_len; - } - return 0; -} - -static int fs_path_prepare_for_add(struct fs_path *p, int name_len, - char **prepared) -{ - int ret; - int new_len; - - new_len = p->end - p->start + name_len; - if (p->start != p->end) - new_len++; - ret = fs_path_ensure_buf(p, new_len); - if (ret < 0) - goto out; - - if (p->reversed) { - if (p->start != p->end) - *--p->start = '/'; - p->start -= name_len; - *prepared = p->start; - } else { - if (p->start != p->end) - *p->end++ = '/'; - *prepared = p->end; - p->end += name_len; - *p->end = 0; - } - -out: - return ret; -} - -static int fs_path_add(struct fs_path *p, const char *name, int name_len) -{ - int ret; - char *prepared; - - ret = fs_path_prepare_for_add(p, name_len, &prepared); - if (ret < 0) - goto out; - memcpy(prepared, name, name_len); - -out: - return ret; -} - -static int fs_path_add_path(struct fs_path *p, struct fs_path *p2) -{ - int ret; - char *prepared; - - ret = fs_path_prepare_for_add(p, p2->end - p2->start, &prepared); - if (ret < 0) - goto out; - memcpy(prepared, p2->start, p2->end - p2->start); - -out: - return ret; -} - -static int fs_path_add_from_extent_buffer(struct fs_path *p, - struct extent_buffer *eb, - unsigned long off, int len) -{ - int ret; - char *prepared; - - ret = fs_path_prepare_for_add(p, len, &prepared); - if (ret < 0) - goto out; - - read_extent_buffer(eb, prepared, off, len); - -out: - return ret; -} - -static int fs_path_copy(struct fs_path *p, struct fs_path *from) -{ - int ret; - - p->reversed = from->reversed; - fs_path_reset(p); - - ret = fs_path_add_path(p, from); - - return ret; -} - - -static void fs_path_unreverse(struct fs_path *p) -{ - char *tmp; - int len; - - if (!p->reversed) - return; - - tmp = p->start; - len = p->end - p->start; - p->start = p->buf; - p->end = p->start + len; - memmove(p->start, tmp, len + 1); - p->reversed = 0; -} - -static struct btrfs_path *alloc_path_for_send(void) -{ - struct btrfs_path *path; - - path = btrfs_alloc_path(); - if (!path) - return NULL; - path->search_commit_root = 1; - path->skip_locking = 1; - path->need_commit_sem = 1; - return path; -} - -static int write_buf(struct file *filp, const void *buf, u32 len, loff_t *off) -{ - int ret; - mm_segment_t old_fs; - u32 pos = 0; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - - while (pos < len) { - ret = vfs_write(filp, (__force const char __user *)buf + pos, - len - pos, off); - /* TODO handle that correctly */ - /*if (ret == -ERESTARTSYS) { - continue; - }*/ - if (ret < 0) - goto out; - if (ret == 0) { - ret = -EIO; - goto out; - } - pos += ret; - } - - ret = 0; - -out: - set_fs(old_fs); - return ret; -} - -static int tlv_put(struct send_ctx *sctx, u16 attr, const void *data, int len) -{ - struct btrfs_tlv_header *hdr; - int total_len = sizeof(*hdr) + len; - int left = sctx->send_max_size - sctx->send_size; - - if (unlikely(left < total_len)) - return -EOVERFLOW; - - hdr = (struct btrfs_tlv_header *) (sctx->send_buf + sctx->send_size); - hdr->tlv_type = cpu_to_le16(attr); - hdr->tlv_len = cpu_to_le16(len); - memcpy(hdr + 1, data, len); - sctx->send_size += total_len; - - return 0; -} - -#define TLV_PUT_DEFINE_INT(bits) \ - static int tlv_put_u##bits(struct send_ctx *sctx, \ - u##bits attr, u##bits value) \ - { \ - __le##bits __tmp = cpu_to_le##bits(value); \ - return tlv_put(sctx, attr, &__tmp, sizeof(__tmp)); \ - } - -TLV_PUT_DEFINE_INT(64) - -static int tlv_put_string(struct send_ctx *sctx, u16 attr, - const char *str, int len) -{ - if (len == -1) - len = strlen(str); - return tlv_put(sctx, attr, str, len); -} - -static int tlv_put_uuid(struct send_ctx *sctx, u16 attr, - const u8 *uuid) -{ - return tlv_put(sctx, attr, uuid, BTRFS_UUID_SIZE); -} - -static int tlv_put_btrfs_timespec(struct send_ctx *sctx, u16 attr, - struct extent_buffer *eb, - struct btrfs_timespec *ts) -{ - struct btrfs_timespec bts; - read_extent_buffer(eb, &bts, (unsigned long)ts, sizeof(bts)); - return tlv_put(sctx, attr, &bts, sizeof(bts)); -} - - -#define TLV_PUT(sctx, attrtype, attrlen, data) \ - do { \ - ret = tlv_put(sctx, attrtype, attrlen, data); \ - if (ret < 0) \ - goto tlv_put_failure; \ - } while (0) - -#define TLV_PUT_INT(sctx, attrtype, bits, value) \ - do { \ - ret = tlv_put_u##bits(sctx, attrtype, value); \ - if (ret < 0) \ - goto tlv_put_failure; \ - } while (0) - -#define TLV_PUT_U8(sctx, attrtype, data) TLV_PUT_INT(sctx, attrtype, 8, data) -#define TLV_PUT_U16(sctx, attrtype, data) TLV_PUT_INT(sctx, attrtype, 16, data) -#define TLV_PUT_U32(sctx, attrtype, data) TLV_PUT_INT(sctx, attrtype, 32, data) -#define TLV_PUT_U64(sctx, attrtype, data) TLV_PUT_INT(sctx, attrtype, 64, data) -#define TLV_PUT_STRING(sctx, attrtype, str, len) \ - do { \ - ret = tlv_put_string(sctx, attrtype, str, len); \ - if (ret < 0) \ - goto tlv_put_failure; \ - } while (0) -#define TLV_PUT_PATH(sctx, attrtype, p) \ - do { \ - ret = tlv_put_string(sctx, attrtype, p->start, \ - p->end - p->start); \ - if (ret < 0) \ - goto tlv_put_failure; \ - } while(0) -#define TLV_PUT_UUID(sctx, attrtype, uuid) \ - do { \ - ret = tlv_put_uuid(sctx, attrtype, uuid); \ - if (ret < 0) \ - goto tlv_put_failure; \ - } while (0) -#define TLV_PUT_BTRFS_TIMESPEC(sctx, attrtype, eb, ts) \ - do { \ - ret = tlv_put_btrfs_timespec(sctx, attrtype, eb, ts); \ - if (ret < 0) \ - goto tlv_put_failure; \ - } while (0) - -static int send_header(struct send_ctx *sctx) -{ - struct btrfs_stream_header hdr; - - strcpy(hdr.magic, BTRFS_SEND_STREAM_MAGIC); - hdr.version = cpu_to_le32(BTRFS_SEND_STREAM_VERSION); - - return write_buf(sctx->send_filp, &hdr, sizeof(hdr), - &sctx->send_off); -} - -/* - * For each command/item we want to send to userspace, we call this function. - */ -static int begin_cmd(struct send_ctx *sctx, int cmd) -{ - struct btrfs_cmd_header *hdr; - - if (WARN_ON(!sctx->send_buf)) - return -EINVAL; - - BUG_ON(sctx->send_size); - - sctx->send_size += sizeof(*hdr); - hdr = (struct btrfs_cmd_header *)sctx->send_buf; - hdr->cmd = cpu_to_le16(cmd); - - return 0; -} - -static int send_cmd(struct send_ctx *sctx) -{ - int ret; - struct btrfs_cmd_header *hdr; - u32 crc; - - hdr = (struct btrfs_cmd_header *)sctx->send_buf; - hdr->len = cpu_to_le32(sctx->send_size - sizeof(*hdr)); - hdr->crc = 0; - - crc = btrfs_crc32c(0, (unsigned char *)sctx->send_buf, sctx->send_size); - hdr->crc = cpu_to_le32(crc); - - ret = write_buf(sctx->send_filp, sctx->send_buf, sctx->send_size, - &sctx->send_off); - - sctx->total_send_size += sctx->send_size; - sctx->cmd_send_size[le16_to_cpu(hdr->cmd)] += sctx->send_size; - sctx->send_size = 0; - - return ret; -} - -/* - * Sends a move instruction to user space - */ -static int send_rename(struct send_ctx *sctx, - struct fs_path *from, struct fs_path *to) -{ - struct btrfs_fs_info *fs_info = sctx->send_root->fs_info; - int ret; - - btrfs_debug(fs_info, "send_rename %s -> %s", from->start, to->start); - - ret = begin_cmd(sctx, BTRFS_SEND_C_RENAME); - if (ret < 0) - goto out; - - TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, from); - TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH_TO, to); - - ret = send_cmd(sctx); - -tlv_put_failure: -out: - return ret; -} - -/* - * Sends a link instruction to user space - */ -static int send_link(struct send_ctx *sctx, - struct fs_path *path, struct fs_path *lnk) -{ - struct btrfs_fs_info *fs_info = sctx->send_root->fs_info; - int ret; - - btrfs_debug(fs_info, "send_link %s -> %s", path->start, lnk->start); - - ret = begin_cmd(sctx, BTRFS_SEND_C_LINK); - if (ret < 0) - goto out; - - TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, path); - TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH_LINK, lnk); - - ret = send_cmd(sctx); - -tlv_put_failure: -out: - return ret; -} - -/* - * Sends an unlink instruction to user space - */ -static int send_unlink(struct send_ctx *sctx, struct fs_path *path) -{ - struct btrfs_fs_info *fs_info = sctx->send_root->fs_info; - int ret; - - btrfs_debug(fs_info, "send_unlink %s", path->start); - - ret = begin_cmd(sctx, BTRFS_SEND_C_UNLINK); - if (ret < 0) - goto out; - - TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, path); - - ret = send_cmd(sctx); - -tlv_put_failure: -out: - return ret; -} - -/* - * Sends a rmdir instruction to user space - */ -static int send_rmdir(struct send_ctx *sctx, struct fs_path *path) -{ - struct btrfs_fs_info *fs_info = sctx->send_root->fs_info; - int ret; - - btrfs_debug(fs_info, "send_rmdir %s", path->start); - - ret = begin_cmd(sctx, BTRFS_SEND_C_RMDIR); - if (ret < 0) - goto out; - - TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, path); - - ret = send_cmd(sctx); - -tlv_put_failure: -out: - return ret; -} - -/* - * Helper function to retrieve some fields from an inode item. - */ -static int __get_inode_info(struct btrfs_root *root, struct btrfs_path *path, - u64 ino, u64 *size, u64 *gen, u64 *mode, u64 *uid, - u64 *gid, u64 *rdev) -{ - int ret; - struct btrfs_inode_item *ii; - struct btrfs_key key; - - key.objectid = ino; - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret) { - if (ret > 0) - ret = -ENOENT; - return ret; - } - - ii = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_inode_item); - if (size) - *size = btrfs_inode_size(path->nodes[0], ii); - if (gen) - *gen = btrfs_inode_generation(path->nodes[0], ii); - if (mode) - *mode = btrfs_inode_mode(path->nodes[0], ii); - if (uid) - *uid = btrfs_inode_uid(path->nodes[0], ii); - if (gid) - *gid = btrfs_inode_gid(path->nodes[0], ii); - if (rdev) - *rdev = btrfs_inode_rdev(path->nodes[0], ii); - - return ret; -} - -static int get_inode_info(struct btrfs_root *root, - u64 ino, u64 *size, u64 *gen, - u64 *mode, u64 *uid, u64 *gid, - u64 *rdev) -{ - struct btrfs_path *path; - int ret; - - path = alloc_path_for_send(); - if (!path) - return -ENOMEM; - ret = __get_inode_info(root, path, ino, size, gen, mode, uid, gid, - rdev); - btrfs_free_path(path); - return ret; -} - -typedef int (*iterate_inode_ref_t)(int num, u64 dir, int index, - struct fs_path *p, - void *ctx); - -/* - * Helper function to iterate the entries in ONE btrfs_inode_ref or - * btrfs_inode_extref. - * The iterate callback may return a non zero value to stop iteration. This can - * be a negative value for error codes or 1 to simply stop it. - * - * path must point to the INODE_REF or INODE_EXTREF when called. - */ -static int iterate_inode_ref(struct btrfs_root *root, struct btrfs_path *path, - struct btrfs_key *found_key, int resolve, - iterate_inode_ref_t iterate, void *ctx) -{ - struct extent_buffer *eb = path->nodes[0]; - struct btrfs_item *item; - struct btrfs_inode_ref *iref; - struct btrfs_inode_extref *extref; - struct btrfs_path *tmp_path; - struct fs_path *p; - u32 cur = 0; - u32 total; - int slot = path->slots[0]; - u32 name_len; - char *start; - int ret = 0; - int num = 0; - int index; - u64 dir; - unsigned long name_off; - unsigned long elem_size; - unsigned long ptr; - - p = fs_path_alloc_reversed(); - if (!p) - return -ENOMEM; - - tmp_path = alloc_path_for_send(); - if (!tmp_path) { - fs_path_free(p); - return -ENOMEM; - } - - - if (found_key->type == BTRFS_INODE_REF_KEY) { - ptr = (unsigned long)btrfs_item_ptr(eb, slot, - struct btrfs_inode_ref); - item = btrfs_item_nr(slot); - total = btrfs_item_size(eb, item); - elem_size = sizeof(*iref); - } else { - ptr = btrfs_item_ptr_offset(eb, slot); - total = btrfs_item_size_nr(eb, slot); - elem_size = sizeof(*extref); - } - - while (cur < total) { - fs_path_reset(p); - - if (found_key->type == BTRFS_INODE_REF_KEY) { - iref = (struct btrfs_inode_ref *)(ptr + cur); - name_len = btrfs_inode_ref_name_len(eb, iref); - name_off = (unsigned long)(iref + 1); - index = btrfs_inode_ref_index(eb, iref); - dir = found_key->offset; - } else { - extref = (struct btrfs_inode_extref *)(ptr + cur); - name_len = btrfs_inode_extref_name_len(eb, extref); - name_off = (unsigned long)&extref->name; - index = btrfs_inode_extref_index(eb, extref); - dir = btrfs_inode_extref_parent(eb, extref); - } - - if (resolve) { - start = btrfs_ref_to_path(root, tmp_path, name_len, - name_off, eb, dir, - p->buf, p->buf_len); - if (IS_ERR(start)) { - ret = PTR_ERR(start); - goto out; - } - if (start < p->buf) { - /* overflow , try again with larger buffer */ - ret = fs_path_ensure_buf(p, - p->buf_len + p->buf - start); - if (ret < 0) - goto out; - start = btrfs_ref_to_path(root, tmp_path, - name_len, name_off, - eb, dir, - p->buf, p->buf_len); - if (IS_ERR(start)) { - ret = PTR_ERR(start); - goto out; - } - BUG_ON(start < p->buf); - } - p->start = start; - } else { - ret = fs_path_add_from_extent_buffer(p, eb, name_off, - name_len); - if (ret < 0) - goto out; - } - - cur += elem_size + name_len; - ret = iterate(num, dir, index, p, ctx); - if (ret) - goto out; - num++; - } - -out: - btrfs_free_path(tmp_path); - fs_path_free(p); - return ret; -} - -typedef int (*iterate_dir_item_t)(int num, struct btrfs_key *di_key, - const char *name, int name_len, - const char *data, int data_len, - u8 type, void *ctx); - -/* - * Helper function to iterate the entries in ONE btrfs_dir_item. - * The iterate callback may return a non zero value to stop iteration. This can - * be a negative value for error codes or 1 to simply stop it. - * - * path must point to the dir item when called. - */ -static int iterate_dir_item(struct btrfs_root *root, struct btrfs_path *path, - struct btrfs_key *found_key, - iterate_dir_item_t iterate, void *ctx) -{ - int ret = 0; - struct extent_buffer *eb; - struct btrfs_item *item; - struct btrfs_dir_item *di; - struct btrfs_key di_key; - char *buf = NULL; - int buf_len; - u32 name_len; - u32 data_len; - u32 cur; - u32 len; - u32 total; - int slot; - int num; - u8 type; - - /* - * Start with a small buffer (1 page). If later we end up needing more - * space, which can happen for xattrs on a fs with a leaf size greater - * then the page size, attempt to increase the buffer. Typically xattr - * values are small. - */ - buf_len = PATH_MAX; - buf = kmalloc(buf_len, GFP_KERNEL); - if (!buf) { - ret = -ENOMEM; - goto out; - } - - eb = path->nodes[0]; - slot = path->slots[0]; - item = btrfs_item_nr(slot); - di = btrfs_item_ptr(eb, slot, struct btrfs_dir_item); - cur = 0; - len = 0; - total = btrfs_item_size(eb, item); - - num = 0; - while (cur < total) { - name_len = btrfs_dir_name_len(eb, di); - data_len = btrfs_dir_data_len(eb, di); - type = btrfs_dir_type(eb, di); - btrfs_dir_item_key_to_cpu(eb, di, &di_key); - - if (type == BTRFS_FT_XATTR) { - if (name_len > XATTR_NAME_MAX) { - ret = -ENAMETOOLONG; - goto out; - } - if (name_len + data_len > BTRFS_MAX_XATTR_SIZE(root)) { - ret = -E2BIG; - goto out; - } - } else { - /* - * Path too long - */ - if (name_len + data_len > PATH_MAX) { - ret = -ENAMETOOLONG; - goto out; - } - } - - if (name_len + data_len > buf_len) { - buf_len = name_len + data_len; - if (is_vmalloc_addr(buf)) { - vfree(buf); - buf = NULL; - } else { - char *tmp = krealloc(buf, buf_len, - GFP_KERNEL | __GFP_NOWARN); - - if (!tmp) - kfree(buf); - buf = tmp; - } - if (!buf) { - buf = vmalloc(buf_len); - if (!buf) { - ret = -ENOMEM; - goto out; - } - } - } - - read_extent_buffer(eb, buf, (unsigned long)(di + 1), - name_len + data_len); - - len = sizeof(*di) + name_len + data_len; - di = (struct btrfs_dir_item *)((char *)di + len); - cur += len; - - ret = iterate(num, &di_key, buf, name_len, buf + name_len, - data_len, type, ctx); - if (ret < 0) - goto out; - if (ret) { - ret = 0; - goto out; - } - - num++; - } - -out: - kvfree(buf); - return ret; -} - -static int __copy_first_ref(int num, u64 dir, int index, - struct fs_path *p, void *ctx) -{ - int ret; - struct fs_path *pt = ctx; - - ret = fs_path_copy(pt, p); - if (ret < 0) - return ret; - - /* we want the first only */ - return 1; -} - -/* - * Retrieve the first path of an inode. If an inode has more then one - * ref/hardlink, this is ignored. - */ -static int get_inode_path(struct btrfs_root *root, - u64 ino, struct fs_path *path) -{ - int ret; - struct btrfs_key key, found_key; - struct btrfs_path *p; - - p = alloc_path_for_send(); - if (!p) - return -ENOMEM; - - fs_path_reset(path); - - key.objectid = ino; - key.type = BTRFS_INODE_REF_KEY; - key.offset = 0; - - ret = btrfs_search_slot_for_read(root, &key, p, 1, 0); - if (ret < 0) - goto out; - if (ret) { - ret = 1; - goto out; - } - btrfs_item_key_to_cpu(p->nodes[0], &found_key, p->slots[0]); - if (found_key.objectid != ino || - (found_key.type != BTRFS_INODE_REF_KEY && - found_key.type != BTRFS_INODE_EXTREF_KEY)) { - ret = -ENOENT; - goto out; - } - - ret = iterate_inode_ref(root, p, &found_key, 1, - __copy_first_ref, path); - if (ret < 0) - goto out; - ret = 0; - -out: - btrfs_free_path(p); - return ret; -} - -struct backref_ctx { - struct send_ctx *sctx; - - struct btrfs_path *path; - /* number of total found references */ - u64 found; - - /* - * used for clones found in send_root. clones found behind cur_objectid - * and cur_offset are not considered as allowed clones. - */ - u64 cur_objectid; - u64 cur_offset; - - /* may be truncated in case it's the last extent in a file */ - u64 extent_len; - - /* data offset in the file extent item */ - u64 data_offset; - - /* Just to check for bugs in backref resolving */ - int found_itself; -}; - -static int __clone_root_cmp_bsearch(const void *key, const void *elt) -{ - u64 root = (u64)(uintptr_t)key; - struct clone_root *cr = (struct clone_root *)elt; - - if (root < cr->root->objectid) - return -1; - if (root > cr->root->objectid) - return 1; - return 0; -} - -static int __clone_root_cmp_sort(const void *e1, const void *e2) -{ - struct clone_root *cr1 = (struct clone_root *)e1; - struct clone_root *cr2 = (struct clone_root *)e2; - - if (cr1->root->objectid < cr2->root->objectid) - return -1; - if (cr1->root->objectid > cr2->root->objectid) - return 1; - return 0; -} - -/* - * Called for every backref that is found for the current extent. - * Results are collected in sctx->clone_roots->ino/offset/found_refs - */ -static int __iterate_backrefs(u64 ino, u64 offset, u64 root, void *ctx_) -{ - struct backref_ctx *bctx = ctx_; - struct clone_root *found; - int ret; - u64 i_size; - - /* First check if the root is in the list of accepted clone sources */ - found = bsearch((void *)(uintptr_t)root, bctx->sctx->clone_roots, - bctx->sctx->clone_roots_cnt, - sizeof(struct clone_root), - __clone_root_cmp_bsearch); - if (!found) - return 0; - - if (found->root == bctx->sctx->send_root && - ino == bctx->cur_objectid && - offset == bctx->cur_offset) { - bctx->found_itself = 1; - } - - /* - * There are inodes that have extents that lie behind its i_size. Don't - * accept clones from these extents. - */ - ret = __get_inode_info(found->root, bctx->path, ino, &i_size, NULL, NULL, - NULL, NULL, NULL); - btrfs_release_path(bctx->path); - if (ret < 0) - return ret; - - if (offset + bctx->data_offset + bctx->extent_len > i_size) - return 0; - - /* - * Make sure we don't consider clones from send_root that are - * behind the current inode/offset. - */ - if (found->root == bctx->sctx->send_root) { - /* - * TODO for the moment we don't accept clones from the inode - * that is currently send. We may change this when - * BTRFS_IOC_CLONE_RANGE supports cloning from and to the same - * file. - */ - if (ino >= bctx->cur_objectid) - return 0; -#if 0 - if (ino > bctx->cur_objectid) - return 0; - if (offset + bctx->extent_len > bctx->cur_offset) - return 0; -#endif - } - - bctx->found++; - found->found_refs++; - if (ino < found->ino) { - found->ino = ino; - found->offset = offset; - } else if (found->ino == ino) { - /* - * same extent found more then once in the same file. - */ - if (found->offset > offset + bctx->extent_len) - found->offset = offset; - } - - return 0; -} - -/* - * Given an inode, offset and extent item, it finds a good clone for a clone - * instruction. Returns -ENOENT when none could be found. The function makes - * sure that the returned clone is usable at the point where sending is at the - * moment. This means, that no clones are accepted which lie behind the current - * inode+offset. - * - * path must point to the extent item when called. - */ -static int find_extent_clone(struct send_ctx *sctx, - struct btrfs_path *path, - u64 ino, u64 data_offset, - u64 ino_size, - struct clone_root **found) -{ - struct btrfs_fs_info *fs_info = sctx->send_root->fs_info; - int ret; - int extent_type; - u64 logical; - u64 disk_byte; - u64 num_bytes; - u64 extent_item_pos; - u64 flags = 0; - struct btrfs_file_extent_item *fi; - struct extent_buffer *eb = path->nodes[0]; - struct backref_ctx *backref_ctx = NULL; - struct clone_root *cur_clone_root; - struct btrfs_key found_key; - struct btrfs_path *tmp_path; - int compressed; - u32 i; - - tmp_path = alloc_path_for_send(); - if (!tmp_path) - return -ENOMEM; - - /* We only use this path under the commit sem */ - tmp_path->need_commit_sem = 0; - - backref_ctx = kmalloc(sizeof(*backref_ctx), GFP_KERNEL); - if (!backref_ctx) { - ret = -ENOMEM; - goto out; - } - - backref_ctx->path = tmp_path; - - if (data_offset >= ino_size) { - /* - * There may be extents that lie behind the file's size. - * I at least had this in combination with snapshotting while - * writing large files. - */ - ret = 0; - goto out; - } - - fi = btrfs_item_ptr(eb, path->slots[0], - struct btrfs_file_extent_item); - extent_type = btrfs_file_extent_type(eb, fi); - if (extent_type == BTRFS_FILE_EXTENT_INLINE) { - ret = -ENOENT; - goto out; - } - compressed = btrfs_file_extent_compression(eb, fi); - - num_bytes = btrfs_file_extent_num_bytes(eb, fi); - disk_byte = btrfs_file_extent_disk_bytenr(eb, fi); - if (disk_byte == 0) { - ret = -ENOENT; - goto out; - } - logical = disk_byte + btrfs_file_extent_offset(eb, fi); - - down_read(&fs_info->commit_root_sem); - ret = extent_from_logical(fs_info, disk_byte, tmp_path, - &found_key, &flags); - up_read(&fs_info->commit_root_sem); - btrfs_release_path(tmp_path); - - if (ret < 0) - goto out; - if (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK) { - ret = -EIO; - goto out; - } - - /* - * Setup the clone roots. - */ - for (i = 0; i < sctx->clone_roots_cnt; i++) { - cur_clone_root = sctx->clone_roots + i; - cur_clone_root->ino = (u64)-1; - cur_clone_root->offset = 0; - cur_clone_root->found_refs = 0; - } - - backref_ctx->sctx = sctx; - backref_ctx->found = 0; - backref_ctx->cur_objectid = ino; - backref_ctx->cur_offset = data_offset; - backref_ctx->found_itself = 0; - backref_ctx->extent_len = num_bytes; - /* - * For non-compressed extents iterate_extent_inodes() gives us extent - * offsets that already take into account the data offset, but not for - * compressed extents, since the offset is logical and not relative to - * the physical extent locations. We must take this into account to - * avoid sending clone offsets that go beyond the source file's size, - * which would result in the clone ioctl failing with -EINVAL on the - * receiving end. - */ - if (compressed == BTRFS_COMPRESS_NONE) - backref_ctx->data_offset = 0; - else - backref_ctx->data_offset = btrfs_file_extent_offset(eb, fi); - - /* - * The last extent of a file may be too large due to page alignment. - * We need to adjust extent_len in this case so that the checks in - * __iterate_backrefs work. - */ - if (data_offset + num_bytes >= ino_size) - backref_ctx->extent_len = ino_size - data_offset; - - /* - * Now collect all backrefs. - */ - if (compressed == BTRFS_COMPRESS_NONE) - extent_item_pos = logical - found_key.objectid; - else - extent_item_pos = 0; - ret = iterate_extent_inodes(fs_info, - found_key.objectid, extent_item_pos, 1, - __iterate_backrefs, backref_ctx); - - if (ret < 0) - goto out; - - if (!backref_ctx->found_itself) { - /* found a bug in backref code? */ - ret = -EIO; - btrfs_err(fs_info, - "did not find backref in send_root. inode=%llu, offset=%llu, disk_byte=%llu found extent=%llu", - ino, data_offset, disk_byte, found_key.objectid); - goto out; - } - - btrfs_debug(fs_info, - "find_extent_clone: data_offset=%llu, ino=%llu, num_bytes=%llu, logical=%llu", - data_offset, ino, num_bytes, logical); - - if (!backref_ctx->found) - btrfs_debug(fs_info, "no clones found"); - - cur_clone_root = NULL; - for (i = 0; i < sctx->clone_roots_cnt; i++) { - if (sctx->clone_roots[i].found_refs) { - if (!cur_clone_root) - cur_clone_root = sctx->clone_roots + i; - else if (sctx->clone_roots[i].root == sctx->send_root) - /* prefer clones from send_root over others */ - cur_clone_root = sctx->clone_roots + i; - } - - } - - if (cur_clone_root) { - *found = cur_clone_root; - ret = 0; - } else { - ret = -ENOENT; - } - -out: - btrfs_free_path(tmp_path); - kfree(backref_ctx); - return ret; -} - -static int read_symlink(struct btrfs_root *root, - u64 ino, - struct fs_path *dest) -{ - int ret; - struct btrfs_path *path; - struct btrfs_key key; - struct btrfs_file_extent_item *ei; - u8 type; - u8 compression; - unsigned long off; - int len; - - path = alloc_path_for_send(); - if (!path) - return -ENOMEM; - - key.objectid = ino; - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = 0; - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out; - if (ret) { - /* - * An empty symlink inode. Can happen in rare error paths when - * creating a symlink (transaction committed before the inode - * eviction handler removed the symlink inode items and a crash - * happened in between or the subvol was snapshoted in between). - * Print an informative message to dmesg/syslog so that the user - * can delete the symlink. - */ - btrfs_err(root->fs_info, - "Found empty symlink inode %llu at root %llu", - ino, root->root_key.objectid); - ret = -EIO; - goto out; - } - - ei = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_file_extent_item); - type = btrfs_file_extent_type(path->nodes[0], ei); - compression = btrfs_file_extent_compression(path->nodes[0], ei); - BUG_ON(type != BTRFS_FILE_EXTENT_INLINE); - BUG_ON(compression); - - off = btrfs_file_extent_inline_start(ei); - len = btrfs_file_extent_inline_len(path->nodes[0], path->slots[0], ei); - - ret = fs_path_add_from_extent_buffer(dest, path->nodes[0], off, len); - -out: - btrfs_free_path(path); - return ret; -} - -/* - * Helper function to generate a file name that is unique in the root of - * send_root and parent_root. This is used to generate names for orphan inodes. - */ -static int gen_unique_name(struct send_ctx *sctx, - u64 ino, u64 gen, - struct fs_path *dest) -{ - int ret = 0; - struct btrfs_path *path; - struct btrfs_dir_item *di; - char tmp[64]; - int len; - u64 idx = 0; - - path = alloc_path_for_send(); - if (!path) - return -ENOMEM; - - while (1) { - len = snprintf(tmp, sizeof(tmp), "o%llu-%llu-%llu", - ino, gen, idx); - ASSERT(len < sizeof(tmp)); - - di = btrfs_lookup_dir_item(NULL, sctx->send_root, - path, BTRFS_FIRST_FREE_OBJECTID, - tmp, strlen(tmp), 0); - btrfs_release_path(path); - if (IS_ERR(di)) { - ret = PTR_ERR(di); - goto out; - } - if (di) { - /* not unique, try again */ - idx++; - continue; - } - - if (!sctx->parent_root) { - /* unique */ - ret = 0; - break; - } - - di = btrfs_lookup_dir_item(NULL, sctx->parent_root, - path, BTRFS_FIRST_FREE_OBJECTID, - tmp, strlen(tmp), 0); - btrfs_release_path(path); - if (IS_ERR(di)) { - ret = PTR_ERR(di); - goto out; - } - if (di) { - /* not unique, try again */ - idx++; - continue; - } - /* unique */ - break; - } - - ret = fs_path_add(dest, tmp, strlen(tmp)); - -out: - btrfs_free_path(path); - return ret; -} - -enum inode_state { - inode_state_no_change, - inode_state_will_create, - inode_state_did_create, - inode_state_will_delete, - inode_state_did_delete, -}; - -static int get_cur_inode_state(struct send_ctx *sctx, u64 ino, u64 gen) -{ - int ret; - int left_ret; - int right_ret; - u64 left_gen; - u64 right_gen; - - ret = get_inode_info(sctx->send_root, ino, NULL, &left_gen, NULL, NULL, - NULL, NULL); - if (ret < 0 && ret != -ENOENT) - goto out; - left_ret = ret; - - if (!sctx->parent_root) { - right_ret = -ENOENT; - } else { - ret = get_inode_info(sctx->parent_root, ino, NULL, &right_gen, - NULL, NULL, NULL, NULL); - if (ret < 0 && ret != -ENOENT) - goto out; - right_ret = ret; - } - - if (!left_ret && !right_ret) { - if (left_gen == gen && right_gen == gen) { - ret = inode_state_no_change; - } else if (left_gen == gen) { - if (ino < sctx->send_progress) - ret = inode_state_did_create; - else - ret = inode_state_will_create; - } else if (right_gen == gen) { - if (ino < sctx->send_progress) - ret = inode_state_did_delete; - else - ret = inode_state_will_delete; - } else { - ret = -ENOENT; - } - } else if (!left_ret) { - if (left_gen == gen) { - if (ino < sctx->send_progress) - ret = inode_state_did_create; - else - ret = inode_state_will_create; - } else { - ret = -ENOENT; - } - } else if (!right_ret) { - if (right_gen == gen) { - if (ino < sctx->send_progress) - ret = inode_state_did_delete; - else - ret = inode_state_will_delete; - } else { - ret = -ENOENT; - } - } else { - ret = -ENOENT; - } - -out: - return ret; -} - -static int is_inode_existent(struct send_ctx *sctx, u64 ino, u64 gen) -{ - int ret; - - ret = get_cur_inode_state(sctx, ino, gen); - if (ret < 0) - goto out; - - if (ret == inode_state_no_change || - ret == inode_state_did_create || - ret == inode_state_will_delete) - ret = 1; - else - ret = 0; - -out: - return ret; -} - -/* - * Helper function to lookup a dir item in a dir. - */ -static int lookup_dir_item_inode(struct btrfs_root *root, - u64 dir, const char *name, int name_len, - u64 *found_inode, - u8 *found_type) -{ - int ret = 0; - struct btrfs_dir_item *di; - struct btrfs_key key; - struct btrfs_path *path; - - path = alloc_path_for_send(); - if (!path) - return -ENOMEM; - - di = btrfs_lookup_dir_item(NULL, root, path, - dir, name, name_len, 0); - if (!di) { - ret = -ENOENT; - goto out; - } - if (IS_ERR(di)) { - ret = PTR_ERR(di); - goto out; - } - btrfs_dir_item_key_to_cpu(path->nodes[0], di, &key); - if (key.type == BTRFS_ROOT_ITEM_KEY) { - ret = -ENOENT; - goto out; - } - *found_inode = key.objectid; - *found_type = btrfs_dir_type(path->nodes[0], di); - -out: - btrfs_free_path(path); - return ret; -} - -/* - * Looks up the first btrfs_inode_ref of a given ino. It returns the parent dir, - * generation of the parent dir and the name of the dir entry. - */ -static int get_first_ref(struct btrfs_root *root, u64 ino, - u64 *dir, u64 *dir_gen, struct fs_path *name) -{ - int ret; - struct btrfs_key key; - struct btrfs_key found_key; - struct btrfs_path *path; - int len; - u64 parent_dir; - - path = alloc_path_for_send(); - if (!path) - return -ENOMEM; - - key.objectid = ino; - key.type = BTRFS_INODE_REF_KEY; - key.offset = 0; - - ret = btrfs_search_slot_for_read(root, &key, path, 1, 0); - if (ret < 0) - goto out; - if (!ret) - btrfs_item_key_to_cpu(path->nodes[0], &found_key, - path->slots[0]); - if (ret || found_key.objectid != ino || - (found_key.type != BTRFS_INODE_REF_KEY && - found_key.type != BTRFS_INODE_EXTREF_KEY)) { - ret = -ENOENT; - goto out; - } - - if (found_key.type == BTRFS_INODE_REF_KEY) { - struct btrfs_inode_ref *iref; - iref = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_inode_ref); - len = btrfs_inode_ref_name_len(path->nodes[0], iref); - ret = fs_path_add_from_extent_buffer(name, path->nodes[0], - (unsigned long)(iref + 1), - len); - parent_dir = found_key.offset; - } else { - struct btrfs_inode_extref *extref; - extref = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_inode_extref); - len = btrfs_inode_extref_name_len(path->nodes[0], extref); - ret = fs_path_add_from_extent_buffer(name, path->nodes[0], - (unsigned long)&extref->name, len); - parent_dir = btrfs_inode_extref_parent(path->nodes[0], extref); - } - if (ret < 0) - goto out; - btrfs_release_path(path); - - if (dir_gen) { - ret = get_inode_info(root, parent_dir, NULL, dir_gen, NULL, - NULL, NULL, NULL); - if (ret < 0) - goto out; - } - - *dir = parent_dir; - -out: - btrfs_free_path(path); - return ret; -} - -static int is_first_ref(struct btrfs_root *root, - u64 ino, u64 dir, - const char *name, int name_len) -{ - int ret; - struct fs_path *tmp_name; - u64 tmp_dir; - - tmp_name = fs_path_alloc(); - if (!tmp_name) - return -ENOMEM; - - ret = get_first_ref(root, ino, &tmp_dir, NULL, tmp_name); - if (ret < 0) - goto out; - - if (dir != tmp_dir || name_len != fs_path_len(tmp_name)) { - ret = 0; - goto out; - } - - ret = !memcmp(tmp_name->start, name, name_len); - -out: - fs_path_free(tmp_name); - return ret; -} - -/* - * Used by process_recorded_refs to determine if a new ref would overwrite an - * already existing ref. In case it detects an overwrite, it returns the - * inode/gen in who_ino/who_gen. - * When an overwrite is detected, process_recorded_refs does proper orphanizing - * to make sure later references to the overwritten inode are possible. - * Orphanizing is however only required for the first ref of an inode. - * process_recorded_refs does an additional is_first_ref check to see if - * orphanizing is really required. - */ -static int will_overwrite_ref(struct send_ctx *sctx, u64 dir, u64 dir_gen, - const char *name, int name_len, - u64 *who_ino, u64 *who_gen) -{ - int ret = 0; - u64 gen; - u64 other_inode = 0; - u8 other_type = 0; - - if (!sctx->parent_root) - goto out; - - ret = is_inode_existent(sctx, dir, dir_gen); - if (ret <= 0) - goto out; - - /* - * If we have a parent root we need to verify that the parent dir was - * not deleted and then re-created, if it was then we have no overwrite - * and we can just unlink this entry. - */ - if (sctx->parent_root) { - ret = get_inode_info(sctx->parent_root, dir, NULL, &gen, NULL, - NULL, NULL, NULL); - if (ret < 0 && ret != -ENOENT) - goto out; - if (ret) { - ret = 0; - goto out; - } - if (gen != dir_gen) - goto out; - } - - ret = lookup_dir_item_inode(sctx->parent_root, dir, name, name_len, - &other_inode, &other_type); - if (ret < 0 && ret != -ENOENT) - goto out; - if (ret) { - ret = 0; - goto out; - } - - /* - * Check if the overwritten ref was already processed. If yes, the ref - * was already unlinked/moved, so we can safely assume that we will not - * overwrite anything at this point in time. - */ - if (other_inode > sctx->send_progress || - is_waiting_for_move(sctx, other_inode)) { - ret = get_inode_info(sctx->parent_root, other_inode, NULL, - who_gen, NULL, NULL, NULL, NULL); - if (ret < 0) - goto out; - - ret = 1; - *who_ino = other_inode; - } else { - ret = 0; - } - -out: - return ret; -} - -/* - * Checks if the ref was overwritten by an already processed inode. This is - * used by __get_cur_name_and_parent to find out if the ref was orphanized and - * thus the orphan name needs be used. - * process_recorded_refs also uses it to avoid unlinking of refs that were - * overwritten. - */ -static int did_overwrite_ref(struct send_ctx *sctx, - u64 dir, u64 dir_gen, - u64 ino, u64 ino_gen, - const char *name, int name_len) -{ - int ret = 0; - u64 gen; - u64 ow_inode; - u8 other_type; - - if (!sctx->parent_root) - goto out; - - ret = is_inode_existent(sctx, dir, dir_gen); - if (ret <= 0) - goto out; - - /* check if the ref was overwritten by another ref */ - ret = lookup_dir_item_inode(sctx->send_root, dir, name, name_len, - &ow_inode, &other_type); - if (ret < 0 && ret != -ENOENT) - goto out; - if (ret) { - /* was never and will never be overwritten */ - ret = 0; - goto out; - } - - ret = get_inode_info(sctx->send_root, ow_inode, NULL, &gen, NULL, NULL, - NULL, NULL); - if (ret < 0) - goto out; - - if (ow_inode == ino && gen == ino_gen) { - ret = 0; - goto out; - } - - /* - * We know that it is or will be overwritten. Check this now. - * The current inode being processed might have been the one that caused - * inode 'ino' to be orphanized, therefore check if ow_inode matches - * the current inode being processed. - */ - if ((ow_inode < sctx->send_progress) || - (ino != sctx->cur_ino && ow_inode == sctx->cur_ino && - gen == sctx->cur_inode_gen)) - ret = 1; - else - ret = 0; - -out: - return ret; -} - -/* - * Same as did_overwrite_ref, but also checks if it is the first ref of an inode - * that got overwritten. This is used by process_recorded_refs to determine - * if it has to use the path as returned by get_cur_path or the orphan name. - */ -static int did_overwrite_first_ref(struct send_ctx *sctx, u64 ino, u64 gen) -{ - int ret = 0; - struct fs_path *name = NULL; - u64 dir; - u64 dir_gen; - - if (!sctx->parent_root) - goto out; - - name = fs_path_alloc(); - if (!name) - return -ENOMEM; - - ret = get_first_ref(sctx->parent_root, ino, &dir, &dir_gen, name); - if (ret < 0) - goto out; - - ret = did_overwrite_ref(sctx, dir, dir_gen, ino, gen, - name->start, fs_path_len(name)); - -out: - fs_path_free(name); - return ret; -} - -/* - * Insert a name cache entry. On 32bit kernels the radix tree index is 32bit, - * so we need to do some special handling in case we have clashes. This function - * takes care of this with the help of name_cache_entry::radix_list. - * In case of error, nce is kfreed. - */ -static int name_cache_insert(struct send_ctx *sctx, - struct name_cache_entry *nce) -{ - int ret = 0; - struct list_head *nce_head; - - nce_head = radix_tree_lookup(&sctx->name_cache, - (unsigned long)nce->ino); - if (!nce_head) { - nce_head = kmalloc(sizeof(*nce_head), GFP_KERNEL); - if (!nce_head) { - kfree(nce); - return -ENOMEM; - } - INIT_LIST_HEAD(nce_head); - - ret = radix_tree_insert(&sctx->name_cache, nce->ino, nce_head); - if (ret < 0) { - kfree(nce_head); - kfree(nce); - return ret; - } - } - list_add_tail(&nce->radix_list, nce_head); - list_add_tail(&nce->list, &sctx->name_cache_list); - sctx->name_cache_size++; - - return ret; -} - -static void name_cache_delete(struct send_ctx *sctx, - struct name_cache_entry *nce) -{ - struct list_head *nce_head; - - nce_head = radix_tree_lookup(&sctx->name_cache, - (unsigned long)nce->ino); - if (!nce_head) { - btrfs_err(sctx->send_root->fs_info, - "name_cache_delete lookup failed ino %llu cache size %d, leaking memory", - nce->ino, sctx->name_cache_size); - } - - list_del(&nce->radix_list); - list_del(&nce->list); - sctx->name_cache_size--; - - /* - * We may not get to the final release of nce_head if the lookup fails - */ - if (nce_head && list_empty(nce_head)) { - radix_tree_delete(&sctx->name_cache, (unsigned long)nce->ino); - kfree(nce_head); - } -} - -static struct name_cache_entry *name_cache_search(struct send_ctx *sctx, - u64 ino, u64 gen) -{ - struct list_head *nce_head; - struct name_cache_entry *cur; - - nce_head = radix_tree_lookup(&sctx->name_cache, (unsigned long)ino); - if (!nce_head) - return NULL; - - list_for_each_entry(cur, nce_head, radix_list) { - if (cur->ino == ino && cur->gen == gen) - return cur; - } - return NULL; -} - -/* - * Removes the entry from the list and adds it back to the end. This marks the - * entry as recently used so that name_cache_clean_unused does not remove it. - */ -static void name_cache_used(struct send_ctx *sctx, struct name_cache_entry *nce) -{ - list_del(&nce->list); - list_add_tail(&nce->list, &sctx->name_cache_list); -} - -/* - * Remove some entries from the beginning of name_cache_list. - */ -static void name_cache_clean_unused(struct send_ctx *sctx) -{ - struct name_cache_entry *nce; - - if (sctx->name_cache_size < SEND_CTX_NAME_CACHE_CLEAN_SIZE) - return; - - while (sctx->name_cache_size > SEND_CTX_MAX_NAME_CACHE_SIZE) { - nce = list_entry(sctx->name_cache_list.next, - struct name_cache_entry, list); - name_cache_delete(sctx, nce); - kfree(nce); - } -} - -static void name_cache_free(struct send_ctx *sctx) -{ - struct name_cache_entry *nce; - - while (!list_empty(&sctx->name_cache_list)) { - nce = list_entry(sctx->name_cache_list.next, - struct name_cache_entry, list); - name_cache_delete(sctx, nce); - kfree(nce); - } -} - -/* - * Used by get_cur_path for each ref up to the root. - * Returns 0 if it succeeded. - * Returns 1 if the inode is not existent or got overwritten. In that case, the - * name is an orphan name. This instructs get_cur_path to stop iterating. If 1 - * is returned, parent_ino/parent_gen are not guaranteed to be valid. - * Returns <0 in case of error. - */ -static int __get_cur_name_and_parent(struct send_ctx *sctx, - u64 ino, u64 gen, - u64 *parent_ino, - u64 *parent_gen, - struct fs_path *dest) -{ - int ret; - int nce_ret; - struct name_cache_entry *nce = NULL; - - /* - * First check if we already did a call to this function with the same - * ino/gen. If yes, check if the cache entry is still up-to-date. If yes - * return the cached result. - */ - nce = name_cache_search(sctx, ino, gen); - if (nce) { - if (ino < sctx->send_progress && nce->need_later_update) { - name_cache_delete(sctx, nce); - kfree(nce); - nce = NULL; - } else { - name_cache_used(sctx, nce); - *parent_ino = nce->parent_ino; - *parent_gen = nce->parent_gen; - ret = fs_path_add(dest, nce->name, nce->name_len); - if (ret < 0) - goto out; - ret = nce->ret; - goto out; - } - } - - /* - * If the inode is not existent yet, add the orphan name and return 1. - * This should only happen for the parent dir that we determine in - * __record_new_ref - */ - ret = is_inode_existent(sctx, ino, gen); - if (ret < 0) - goto out; - - if (!ret) { - ret = gen_unique_name(sctx, ino, gen, dest); - if (ret < 0) - goto out; - ret = 1; - goto out_cache; - } - - /* - * Depending on whether the inode was already processed or not, use - * send_root or parent_root for ref lookup. - */ - if (ino < sctx->send_progress) - ret = get_first_ref(sctx->send_root, ino, - parent_ino, parent_gen, dest); - else - ret = get_first_ref(sctx->parent_root, ino, - parent_ino, parent_gen, dest); - if (ret < 0) - goto out; - - /* - * Check if the ref was overwritten by an inode's ref that was processed - * earlier. If yes, treat as orphan and return 1. - */ - ret = did_overwrite_ref(sctx, *parent_ino, *parent_gen, ino, gen, - dest->start, dest->end - dest->start); - if (ret < 0) - goto out; - if (ret) { - fs_path_reset(dest); - ret = gen_unique_name(sctx, ino, gen, dest); - if (ret < 0) - goto out; - ret = 1; - } - -out_cache: - /* - * Store the result of the lookup in the name cache. - */ - nce = kmalloc(sizeof(*nce) + fs_path_len(dest) + 1, GFP_KERNEL); - if (!nce) { - ret = -ENOMEM; - goto out; - } - - nce->ino = ino; - nce->gen = gen; - nce->parent_ino = *parent_ino; - nce->parent_gen = *parent_gen; - nce->name_len = fs_path_len(dest); - nce->ret = ret; - strcpy(nce->name, dest->start); - - if (ino < sctx->send_progress) - nce->need_later_update = 0; - else - nce->need_later_update = 1; - - nce_ret = name_cache_insert(sctx, nce); - if (nce_ret < 0) - ret = nce_ret; - name_cache_clean_unused(sctx); - -out: - return ret; -} - -/* - * Magic happens here. This function returns the first ref to an inode as it - * would look like while receiving the stream at this point in time. - * We walk the path up to the root. For every inode in between, we check if it - * was already processed/sent. If yes, we continue with the parent as found - * in send_root. If not, we continue with the parent as found in parent_root. - * If we encounter an inode that was deleted at this point in time, we use the - * inodes "orphan" name instead of the real name and stop. Same with new inodes - * that were not created yet and overwritten inodes/refs. - * - * When do we have have orphan inodes: - * 1. When an inode is freshly created and thus no valid refs are available yet - * 2. When a directory lost all it's refs (deleted) but still has dir items - * inside which were not processed yet (pending for move/delete). If anyone - * tried to get the path to the dir items, it would get a path inside that - * orphan directory. - * 3. When an inode is moved around or gets new links, it may overwrite the ref - * of an unprocessed inode. If in that case the first ref would be - * overwritten, the overwritten inode gets "orphanized". Later when we - * process this overwritten inode, it is restored at a new place by moving - * the orphan inode. - * - * sctx->send_progress tells this function at which point in time receiving - * would be. - */ -static int get_cur_path(struct send_ctx *sctx, u64 ino, u64 gen, - struct fs_path *dest) -{ - int ret = 0; - struct fs_path *name = NULL; - u64 parent_inode = 0; - u64 parent_gen = 0; - int stop = 0; - - name = fs_path_alloc(); - if (!name) { - ret = -ENOMEM; - goto out; - } - - dest->reversed = 1; - fs_path_reset(dest); - - while (!stop && ino != BTRFS_FIRST_FREE_OBJECTID) { - struct waiting_dir_move *wdm; - - fs_path_reset(name); - - if (is_waiting_for_rm(sctx, ino)) { - ret = gen_unique_name(sctx, ino, gen, name); - if (ret < 0) - goto out; - ret = fs_path_add_path(dest, name); - break; - } - - wdm = get_waiting_dir_move(sctx, ino); - if (wdm && wdm->orphanized) { - ret = gen_unique_name(sctx, ino, gen, name); - stop = 1; - } else if (wdm) { - ret = get_first_ref(sctx->parent_root, ino, - &parent_inode, &parent_gen, name); - } else { - ret = __get_cur_name_and_parent(sctx, ino, gen, - &parent_inode, - &parent_gen, name); - if (ret) - stop = 1; - } - - if (ret < 0) - goto out; - - ret = fs_path_add_path(dest, name); - if (ret < 0) - goto out; - - ino = parent_inode; - gen = parent_gen; - } - -out: - fs_path_free(name); - if (!ret) - fs_path_unreverse(dest); - return ret; -} - -/* - * Sends a BTRFS_SEND_C_SUBVOL command/item to userspace - */ -static int send_subvol_begin(struct send_ctx *sctx) -{ - int ret; - struct btrfs_root *send_root = sctx->send_root; - struct btrfs_root *parent_root = sctx->parent_root; - struct btrfs_path *path; - struct btrfs_key key; - struct btrfs_root_ref *ref; - struct extent_buffer *leaf; - char *name = NULL; - int namelen; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - name = kmalloc(BTRFS_PATH_NAME_MAX, GFP_KERNEL); - if (!name) { - btrfs_free_path(path); - return -ENOMEM; - } - - key.objectid = send_root->objectid; - key.type = BTRFS_ROOT_BACKREF_KEY; - key.offset = 0; - - ret = btrfs_search_slot_for_read(send_root->fs_info->tree_root, - &key, path, 1, 0); - if (ret < 0) - goto out; - if (ret) { - ret = -ENOENT; - goto out; - } - - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - if (key.type != BTRFS_ROOT_BACKREF_KEY || - key.objectid != send_root->objectid) { - ret = -ENOENT; - goto out; - } - ref = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_root_ref); - namelen = btrfs_root_ref_name_len(leaf, ref); - read_extent_buffer(leaf, name, (unsigned long)(ref + 1), namelen); - btrfs_release_path(path); - - if (parent_root) { - ret = begin_cmd(sctx, BTRFS_SEND_C_SNAPSHOT); - if (ret < 0) - goto out; - } else { - ret = begin_cmd(sctx, BTRFS_SEND_C_SUBVOL); - if (ret < 0) - goto out; - } - - TLV_PUT_STRING(sctx, BTRFS_SEND_A_PATH, name, namelen); - - if (!btrfs_is_empty_uuid(sctx->send_root->root_item.received_uuid)) - TLV_PUT_UUID(sctx, BTRFS_SEND_A_UUID, - sctx->send_root->root_item.received_uuid); - else - TLV_PUT_UUID(sctx, BTRFS_SEND_A_UUID, - sctx->send_root->root_item.uuid); - - TLV_PUT_U64(sctx, BTRFS_SEND_A_CTRANSID, - le64_to_cpu(sctx->send_root->root_item.ctransid)); - if (parent_root) { - if (!btrfs_is_empty_uuid(parent_root->root_item.received_uuid)) - TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, - parent_root->root_item.received_uuid); - else - TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, - parent_root->root_item.uuid); - TLV_PUT_U64(sctx, BTRFS_SEND_A_CLONE_CTRANSID, - le64_to_cpu(sctx->parent_root->root_item.ctransid)); - } - - ret = send_cmd(sctx); - -tlv_put_failure: -out: - btrfs_free_path(path); - kfree(name); - return ret; -} - -static int send_truncate(struct send_ctx *sctx, u64 ino, u64 gen, u64 size) -{ - struct btrfs_fs_info *fs_info = sctx->send_root->fs_info; - int ret = 0; - struct fs_path *p; - - btrfs_debug(fs_info, "send_truncate %llu size=%llu", ino, size); - - p = fs_path_alloc(); - if (!p) - return -ENOMEM; - - ret = begin_cmd(sctx, BTRFS_SEND_C_TRUNCATE); - if (ret < 0) - goto out; - - ret = get_cur_path(sctx, ino, gen, p); - if (ret < 0) - goto out; - TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p); - TLV_PUT_U64(sctx, BTRFS_SEND_A_SIZE, size); - - ret = send_cmd(sctx); - -tlv_put_failure: -out: - fs_path_free(p); - return ret; -} - -static int send_chmod(struct send_ctx *sctx, u64 ino, u64 gen, u64 mode) -{ - struct btrfs_fs_info *fs_info = sctx->send_root->fs_info; - int ret = 0; - struct fs_path *p; - - btrfs_debug(fs_info, "send_chmod %llu mode=%llu", ino, mode); - - p = fs_path_alloc(); - if (!p) - return -ENOMEM; - - ret = begin_cmd(sctx, BTRFS_SEND_C_CHMOD); - if (ret < 0) - goto out; - - ret = get_cur_path(sctx, ino, gen, p); - if (ret < 0) - goto out; - TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p); - TLV_PUT_U64(sctx, BTRFS_SEND_A_MODE, mode & 07777); - - ret = send_cmd(sctx); - -tlv_put_failure: -out: - fs_path_free(p); - return ret; -} - -static int send_chown(struct send_ctx *sctx, u64 ino, u64 gen, u64 uid, u64 gid) -{ - struct btrfs_fs_info *fs_info = sctx->send_root->fs_info; - int ret = 0; - struct fs_path *p; - - btrfs_debug(fs_info, "send_chown %llu uid=%llu, gid=%llu", - ino, uid, gid); - - p = fs_path_alloc(); - if (!p) - return -ENOMEM; - - ret = begin_cmd(sctx, BTRFS_SEND_C_CHOWN); - if (ret < 0) - goto out; - - ret = get_cur_path(sctx, ino, gen, p); - if (ret < 0) - goto out; - TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p); - TLV_PUT_U64(sctx, BTRFS_SEND_A_UID, uid); - TLV_PUT_U64(sctx, BTRFS_SEND_A_GID, gid); - - ret = send_cmd(sctx); - -tlv_put_failure: -out: - fs_path_free(p); - return ret; -} - -static int send_utimes(struct send_ctx *sctx, u64 ino, u64 gen) -{ - struct btrfs_fs_info *fs_info = sctx->send_root->fs_info; - int ret = 0; - struct fs_path *p = NULL; - struct btrfs_inode_item *ii; - struct btrfs_path *path = NULL; - struct extent_buffer *eb; - struct btrfs_key key; - int slot; - - btrfs_debug(fs_info, "send_utimes %llu", ino); - - p = fs_path_alloc(); - if (!p) - return -ENOMEM; - - path = alloc_path_for_send(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - key.objectid = ino; - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - ret = btrfs_search_slot(NULL, sctx->send_root, &key, path, 0, 0); - if (ret > 0) - ret = -ENOENT; - if (ret < 0) - goto out; - - eb = path->nodes[0]; - slot = path->slots[0]; - ii = btrfs_item_ptr(eb, slot, struct btrfs_inode_item); - - ret = begin_cmd(sctx, BTRFS_SEND_C_UTIMES); - if (ret < 0) - goto out; - - ret = get_cur_path(sctx, ino, gen, p); - if (ret < 0) - goto out; - TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p); - TLV_PUT_BTRFS_TIMESPEC(sctx, BTRFS_SEND_A_ATIME, eb, &ii->atime); - TLV_PUT_BTRFS_TIMESPEC(sctx, BTRFS_SEND_A_MTIME, eb, &ii->mtime); - TLV_PUT_BTRFS_TIMESPEC(sctx, BTRFS_SEND_A_CTIME, eb, &ii->ctime); - /* TODO Add otime support when the otime patches get into upstream */ - - ret = send_cmd(sctx); - -tlv_put_failure: -out: - fs_path_free(p); - btrfs_free_path(path); - return ret; -} - -/* - * Sends a BTRFS_SEND_C_MKXXX or SYMLINK command to user space. We don't have - * a valid path yet because we did not process the refs yet. So, the inode - * is created as orphan. - */ -static int send_create_inode(struct send_ctx *sctx, u64 ino) -{ - struct btrfs_fs_info *fs_info = sctx->send_root->fs_info; - int ret = 0; - struct fs_path *p; - int cmd; - u64 gen; - u64 mode; - u64 rdev; - - btrfs_debug(fs_info, "send_create_inode %llu", ino); - - p = fs_path_alloc(); - if (!p) - return -ENOMEM; - - if (ino != sctx->cur_ino) { - ret = get_inode_info(sctx->send_root, ino, NULL, &gen, &mode, - NULL, NULL, &rdev); - if (ret < 0) - goto out; - } else { - gen = sctx->cur_inode_gen; - mode = sctx->cur_inode_mode; - rdev = sctx->cur_inode_rdev; - } - - if (S_ISREG(mode)) { - cmd = BTRFS_SEND_C_MKFILE; - } else if (S_ISDIR(mode)) { - cmd = BTRFS_SEND_C_MKDIR; - } else if (S_ISLNK(mode)) { - cmd = BTRFS_SEND_C_SYMLINK; - } else if (S_ISCHR(mode) || S_ISBLK(mode)) { - cmd = BTRFS_SEND_C_MKNOD; - } else if (S_ISFIFO(mode)) { - cmd = BTRFS_SEND_C_MKFIFO; - } else if (S_ISSOCK(mode)) { - cmd = BTRFS_SEND_C_MKSOCK; - } else { - btrfs_warn(sctx->send_root->fs_info, "unexpected inode type %o", - (int)(mode & S_IFMT)); - ret = -ENOTSUPP; - goto out; - } - - ret = begin_cmd(sctx, cmd); - if (ret < 0) - goto out; - - ret = gen_unique_name(sctx, ino, gen, p); - if (ret < 0) - goto out; - - TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p); - TLV_PUT_U64(sctx, BTRFS_SEND_A_INO, ino); - - if (S_ISLNK(mode)) { - fs_path_reset(p); - ret = read_symlink(sctx->send_root, ino, p); - if (ret < 0) - goto out; - TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH_LINK, p); - } else if (S_ISCHR(mode) || S_ISBLK(mode) || - S_ISFIFO(mode) || S_ISSOCK(mode)) { - TLV_PUT_U64(sctx, BTRFS_SEND_A_RDEV, new_encode_dev(rdev)); - TLV_PUT_U64(sctx, BTRFS_SEND_A_MODE, mode); - } - - ret = send_cmd(sctx); - if (ret < 0) - goto out; - - -tlv_put_failure: -out: - fs_path_free(p); - return ret; -} - -/* - * We need some special handling for inodes that get processed before the parent - * directory got created. See process_recorded_refs for details. - * This function does the check if we already created the dir out of order. - */ -static int did_create_dir(struct send_ctx *sctx, u64 dir) -{ - int ret = 0; - struct btrfs_path *path = NULL; - struct btrfs_key key; - struct btrfs_key found_key; - struct btrfs_key di_key; - struct extent_buffer *eb; - struct btrfs_dir_item *di; - int slot; - - path = alloc_path_for_send(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - key.objectid = dir; - key.type = BTRFS_DIR_INDEX_KEY; - key.offset = 0; - ret = btrfs_search_slot(NULL, sctx->send_root, &key, path, 0, 0); - if (ret < 0) - goto out; - - while (1) { - eb = path->nodes[0]; - slot = path->slots[0]; - if (slot >= btrfs_header_nritems(eb)) { - ret = btrfs_next_leaf(sctx->send_root, path); - if (ret < 0) { - goto out; - } else if (ret > 0) { - ret = 0; - break; - } - continue; - } - - btrfs_item_key_to_cpu(eb, &found_key, slot); - if (found_key.objectid != key.objectid || - found_key.type != key.type) { - ret = 0; - goto out; - } - - di = btrfs_item_ptr(eb, slot, struct btrfs_dir_item); - btrfs_dir_item_key_to_cpu(eb, di, &di_key); - - if (di_key.type != BTRFS_ROOT_ITEM_KEY && - di_key.objectid < sctx->send_progress) { - ret = 1; - goto out; - } - - path->slots[0]++; - } - -out: - btrfs_free_path(path); - return ret; -} - -/* - * Only creates the inode if it is: - * 1. Not a directory - * 2. Or a directory which was not created already due to out of order - * directories. See did_create_dir and process_recorded_refs for details. - */ -static int send_create_inode_if_needed(struct send_ctx *sctx) -{ - int ret; - - if (S_ISDIR(sctx->cur_inode_mode)) { - ret = did_create_dir(sctx, sctx->cur_ino); - if (ret < 0) - goto out; - if (ret) { - ret = 0; - goto out; - } - } - - ret = send_create_inode(sctx, sctx->cur_ino); - if (ret < 0) - goto out; - -out: - return ret; -} - -struct recorded_ref { - struct list_head list; - char *dir_path; - char *name; - struct fs_path *full_path; - u64 dir; - u64 dir_gen; - int dir_path_len; - int name_len; -}; - -/* - * We need to process new refs before deleted refs, but compare_tree gives us - * everything mixed. So we first record all refs and later process them. - * This function is a helper to record one ref. - */ -static int __record_ref(struct list_head *head, u64 dir, - u64 dir_gen, struct fs_path *path) -{ - struct recorded_ref *ref; - - ref = kmalloc(sizeof(*ref), GFP_KERNEL); - if (!ref) - return -ENOMEM; - - ref->dir = dir; - ref->dir_gen = dir_gen; - ref->full_path = path; - - ref->name = (char *)kbasename(ref->full_path->start); - ref->name_len = ref->full_path->end - ref->name; - ref->dir_path = ref->full_path->start; - if (ref->name == ref->full_path->start) - ref->dir_path_len = 0; - else - ref->dir_path_len = ref->full_path->end - - ref->full_path->start - 1 - ref->name_len; - - list_add_tail(&ref->list, head); - return 0; -} - -static int dup_ref(struct recorded_ref *ref, struct list_head *list) -{ - struct recorded_ref *new; - - new = kmalloc(sizeof(*ref), GFP_KERNEL); - if (!new) - return -ENOMEM; - - new->dir = ref->dir; - new->dir_gen = ref->dir_gen; - new->full_path = NULL; - INIT_LIST_HEAD(&new->list); - list_add_tail(&new->list, list); - return 0; -} - -static void __free_recorded_refs(struct list_head *head) -{ - struct recorded_ref *cur; - - while (!list_empty(head)) { - cur = list_entry(head->next, struct recorded_ref, list); - fs_path_free(cur->full_path); - list_del(&cur->list); - kfree(cur); - } -} - -static void free_recorded_refs(struct send_ctx *sctx) -{ - __free_recorded_refs(&sctx->new_refs); - __free_recorded_refs(&sctx->deleted_refs); -} - -/* - * Renames/moves a file/dir to its orphan name. Used when the first - * ref of an unprocessed inode gets overwritten and for all non empty - * directories. - */ -static int orphanize_inode(struct send_ctx *sctx, u64 ino, u64 gen, - struct fs_path *path) -{ - int ret; - struct fs_path *orphan; - - orphan = fs_path_alloc(); - if (!orphan) - return -ENOMEM; - - ret = gen_unique_name(sctx, ino, gen, orphan); - if (ret < 0) - goto out; - - ret = send_rename(sctx, path, orphan); - -out: - fs_path_free(orphan); - return ret; -} - -static struct orphan_dir_info * -add_orphan_dir_info(struct send_ctx *sctx, u64 dir_ino) -{ - struct rb_node **p = &sctx->orphan_dirs.rb_node; - struct rb_node *parent = NULL; - struct orphan_dir_info *entry, *odi; - - odi = kmalloc(sizeof(*odi), GFP_KERNEL); - if (!odi) - return ERR_PTR(-ENOMEM); - odi->ino = dir_ino; - odi->gen = 0; - - while (*p) { - parent = *p; - entry = rb_entry(parent, struct orphan_dir_info, node); - if (dir_ino < entry->ino) { - p = &(*p)->rb_left; - } else if (dir_ino > entry->ino) { - p = &(*p)->rb_right; - } else { - kfree(odi); - return entry; - } - } - - rb_link_node(&odi->node, parent, p); - rb_insert_color(&odi->node, &sctx->orphan_dirs); - return odi; -} - -static struct orphan_dir_info * -get_orphan_dir_info(struct send_ctx *sctx, u64 dir_ino) -{ - struct rb_node *n = sctx->orphan_dirs.rb_node; - struct orphan_dir_info *entry; - - while (n) { - entry = rb_entry(n, struct orphan_dir_info, node); - if (dir_ino < entry->ino) - n = n->rb_left; - else if (dir_ino > entry->ino) - n = n->rb_right; - else - return entry; - } - return NULL; -} - -static int is_waiting_for_rm(struct send_ctx *sctx, u64 dir_ino) -{ - struct orphan_dir_info *odi = get_orphan_dir_info(sctx, dir_ino); - - return odi != NULL; -} - -static void free_orphan_dir_info(struct send_ctx *sctx, - struct orphan_dir_info *odi) -{ - if (!odi) - return; - rb_erase(&odi->node, &sctx->orphan_dirs); - kfree(odi); -} - -/* - * Returns 1 if a directory can be removed at this point in time. - * We check this by iterating all dir items and checking if the inode behind - * the dir item was already processed. - */ -static int can_rmdir(struct send_ctx *sctx, u64 dir, u64 dir_gen, - u64 send_progress) -{ - int ret = 0; - struct btrfs_root *root = sctx->parent_root; - struct btrfs_path *path; - struct btrfs_key key; - struct btrfs_key found_key; - struct btrfs_key loc; - struct btrfs_dir_item *di; - - /* - * Don't try to rmdir the top/root subvolume dir. - */ - if (dir == BTRFS_FIRST_FREE_OBJECTID) - return 0; - - path = alloc_path_for_send(); - if (!path) - return -ENOMEM; - - key.objectid = dir; - key.type = BTRFS_DIR_INDEX_KEY; - key.offset = 0; - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out; - - while (1) { - struct waiting_dir_move *dm; - - if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) - goto out; - else if (ret > 0) - break; - continue; - } - btrfs_item_key_to_cpu(path->nodes[0], &found_key, - path->slots[0]); - if (found_key.objectid != key.objectid || - found_key.type != key.type) - break; - - di = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_dir_item); - btrfs_dir_item_key_to_cpu(path->nodes[0], di, &loc); - - dm = get_waiting_dir_move(sctx, loc.objectid); - if (dm) { - struct orphan_dir_info *odi; - - odi = add_orphan_dir_info(sctx, dir); - if (IS_ERR(odi)) { - ret = PTR_ERR(odi); - goto out; - } - odi->gen = dir_gen; - dm->rmdir_ino = dir; - ret = 0; - goto out; - } - - if (loc.objectid > send_progress) { - struct orphan_dir_info *odi; - - odi = get_orphan_dir_info(sctx, dir); - free_orphan_dir_info(sctx, odi); - ret = 0; - goto out; - } - - path->slots[0]++; - } - - ret = 1; - -out: - btrfs_free_path(path); - return ret; -} - -static int is_waiting_for_move(struct send_ctx *sctx, u64 ino) -{ - struct waiting_dir_move *entry = get_waiting_dir_move(sctx, ino); - - return entry != NULL; -} - -static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino, bool orphanized) -{ - struct rb_node **p = &sctx->waiting_dir_moves.rb_node; - struct rb_node *parent = NULL; - struct waiting_dir_move *entry, *dm; - - dm = kmalloc(sizeof(*dm), GFP_KERNEL); - if (!dm) - return -ENOMEM; - dm->ino = ino; - dm->rmdir_ino = 0; - dm->orphanized = orphanized; - - while (*p) { - parent = *p; - entry = rb_entry(parent, struct waiting_dir_move, node); - if (ino < entry->ino) { - p = &(*p)->rb_left; - } else if (ino > entry->ino) { - p = &(*p)->rb_right; - } else { - kfree(dm); - return -EEXIST; - } - } - - rb_link_node(&dm->node, parent, p); - rb_insert_color(&dm->node, &sctx->waiting_dir_moves); - return 0; -} - -static struct waiting_dir_move * -get_waiting_dir_move(struct send_ctx *sctx, u64 ino) -{ - struct rb_node *n = sctx->waiting_dir_moves.rb_node; - struct waiting_dir_move *entry; - - while (n) { - entry = rb_entry(n, struct waiting_dir_move, node); - if (ino < entry->ino) - n = n->rb_left; - else if (ino > entry->ino) - n = n->rb_right; - else - return entry; - } - return NULL; -} - -static void free_waiting_dir_move(struct send_ctx *sctx, - struct waiting_dir_move *dm) -{ - if (!dm) - return; - rb_erase(&dm->node, &sctx->waiting_dir_moves); - kfree(dm); -} - -static int add_pending_dir_move(struct send_ctx *sctx, - u64 ino, - u64 ino_gen, - u64 parent_ino, - struct list_head *new_refs, - struct list_head *deleted_refs, - const bool is_orphan) -{ - struct rb_node **p = &sctx->pending_dir_moves.rb_node; - struct rb_node *parent = NULL; - struct pending_dir_move *entry = NULL, *pm; - struct recorded_ref *cur; - int exists = 0; - int ret; - - pm = kmalloc(sizeof(*pm), GFP_KERNEL); - if (!pm) - return -ENOMEM; - pm->parent_ino = parent_ino; - pm->ino = ino; - pm->gen = ino_gen; - INIT_LIST_HEAD(&pm->list); - INIT_LIST_HEAD(&pm->update_refs); - RB_CLEAR_NODE(&pm->node); - - while (*p) { - parent = *p; - entry = rb_entry(parent, struct pending_dir_move, node); - if (parent_ino < entry->parent_ino) { - p = &(*p)->rb_left; - } else if (parent_ino > entry->parent_ino) { - p = &(*p)->rb_right; - } else { - exists = 1; - break; - } - } - - list_for_each_entry(cur, deleted_refs, list) { - ret = dup_ref(cur, &pm->update_refs); - if (ret < 0) - goto out; - } - list_for_each_entry(cur, new_refs, list) { - ret = dup_ref(cur, &pm->update_refs); - if (ret < 0) - goto out; - } - - ret = add_waiting_dir_move(sctx, pm->ino, is_orphan); - if (ret) - goto out; - - if (exists) { - list_add_tail(&pm->list, &entry->list); - } else { - rb_link_node(&pm->node, parent, p); - rb_insert_color(&pm->node, &sctx->pending_dir_moves); - } - ret = 0; -out: - if (ret) { - __free_recorded_refs(&pm->update_refs); - kfree(pm); - } - return ret; -} - -static struct pending_dir_move *get_pending_dir_moves(struct send_ctx *sctx, - u64 parent_ino) -{ - struct rb_node *n = sctx->pending_dir_moves.rb_node; - struct pending_dir_move *entry; - - while (n) { - entry = rb_entry(n, struct pending_dir_move, node); - if (parent_ino < entry->parent_ino) - n = n->rb_left; - else if (parent_ino > entry->parent_ino) - n = n->rb_right; - else - return entry; - } - return NULL; -} - -static int path_loop(struct send_ctx *sctx, struct fs_path *name, - u64 ino, u64 gen, u64 *ancestor_ino) -{ - int ret = 0; - u64 parent_inode = 0; - u64 parent_gen = 0; - u64 start_ino = ino; - - *ancestor_ino = 0; - while (ino != BTRFS_FIRST_FREE_OBJECTID) { - fs_path_reset(name); - - if (is_waiting_for_rm(sctx, ino)) - break; - if (is_waiting_for_move(sctx, ino)) { - if (*ancestor_ino == 0) - *ancestor_ino = ino; - ret = get_first_ref(sctx->parent_root, ino, - &parent_inode, &parent_gen, name); - } else { - ret = __get_cur_name_and_parent(sctx, ino, gen, - &parent_inode, - &parent_gen, name); - if (ret > 0) { - ret = 0; - break; - } - } - if (ret < 0) - break; - if (parent_inode == start_ino) { - ret = 1; - if (*ancestor_ino == 0) - *ancestor_ino = ino; - break; - } - ino = parent_inode; - gen = parent_gen; - } - return ret; -} - -static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm) -{ - struct fs_path *from_path = NULL; - struct fs_path *to_path = NULL; - struct fs_path *name = NULL; - u64 orig_progress = sctx->send_progress; - struct recorded_ref *cur; - u64 parent_ino, parent_gen; - struct waiting_dir_move *dm = NULL; - u64 rmdir_ino = 0; - u64 ancestor; - bool is_orphan; - int ret; - - name = fs_path_alloc(); - from_path = fs_path_alloc(); - if (!name || !from_path) { - ret = -ENOMEM; - goto out; - } - - dm = get_waiting_dir_move(sctx, pm->ino); - ASSERT(dm); - rmdir_ino = dm->rmdir_ino; - is_orphan = dm->orphanized; - free_waiting_dir_move(sctx, dm); - - if (is_orphan) { - ret = gen_unique_name(sctx, pm->ino, - pm->gen, from_path); - } else { - ret = get_first_ref(sctx->parent_root, pm->ino, - &parent_ino, &parent_gen, name); - if (ret < 0) - goto out; - ret = get_cur_path(sctx, parent_ino, parent_gen, - from_path); - if (ret < 0) - goto out; - ret = fs_path_add_path(from_path, name); - } - if (ret < 0) - goto out; - - sctx->send_progress = sctx->cur_ino + 1; - ret = path_loop(sctx, name, pm->ino, pm->gen, &ancestor); - if (ret < 0) - goto out; - if (ret) { - LIST_HEAD(deleted_refs); - ASSERT(ancestor > BTRFS_FIRST_FREE_OBJECTID); - ret = add_pending_dir_move(sctx, pm->ino, pm->gen, ancestor, - &pm->update_refs, &deleted_refs, - is_orphan); - if (ret < 0) - goto out; - if (rmdir_ino) { - dm = get_waiting_dir_move(sctx, pm->ino); - ASSERT(dm); - dm->rmdir_ino = rmdir_ino; - } - goto out; - } - fs_path_reset(name); - to_path = name; - name = NULL; - ret = get_cur_path(sctx, pm->ino, pm->gen, to_path); - if (ret < 0) - goto out; - - ret = send_rename(sctx, from_path, to_path); - if (ret < 0) - goto out; - - if (rmdir_ino) { - struct orphan_dir_info *odi; - - odi = get_orphan_dir_info(sctx, rmdir_ino); - if (!odi) { - /* already deleted */ - goto finish; - } - ret = can_rmdir(sctx, rmdir_ino, odi->gen, sctx->cur_ino); - if (ret < 0) - goto out; - if (!ret) - goto finish; - - name = fs_path_alloc(); - if (!name) { - ret = -ENOMEM; - goto out; - } - ret = get_cur_path(sctx, rmdir_ino, odi->gen, name); - if (ret < 0) - goto out; - ret = send_rmdir(sctx, name); - if (ret < 0) - goto out; - free_orphan_dir_info(sctx, odi); - } - -finish: - ret = send_utimes(sctx, pm->ino, pm->gen); - if (ret < 0) - goto out; - - /* - * After rename/move, need to update the utimes of both new parent(s) - * and old parent(s). - */ - list_for_each_entry(cur, &pm->update_refs, list) { - /* - * The parent inode might have been deleted in the send snapshot - */ - ret = get_inode_info(sctx->send_root, cur->dir, NULL, - NULL, NULL, NULL, NULL, NULL); - if (ret == -ENOENT) { - ret = 0; - continue; - } - if (ret < 0) - goto out; - - ret = send_utimes(sctx, cur->dir, cur->dir_gen); - if (ret < 0) - goto out; - } - -out: - fs_path_free(name); - fs_path_free(from_path); - fs_path_free(to_path); - sctx->send_progress = orig_progress; - - return ret; -} - -static void free_pending_move(struct send_ctx *sctx, struct pending_dir_move *m) -{ - if (!list_empty(&m->list)) - list_del(&m->list); - if (!RB_EMPTY_NODE(&m->node)) - rb_erase(&m->node, &sctx->pending_dir_moves); - __free_recorded_refs(&m->update_refs); - kfree(m); -} - -static void tail_append_pending_moves(struct pending_dir_move *moves, - struct list_head *stack) -{ - if (list_empty(&moves->list)) { - list_add_tail(&moves->list, stack); - } else { - LIST_HEAD(list); - list_splice_init(&moves->list, &list); - list_add_tail(&moves->list, stack); - list_splice_tail(&list, stack); - } -} - -static int apply_children_dir_moves(struct send_ctx *sctx) -{ - struct pending_dir_move *pm; - struct list_head stack; - u64 parent_ino = sctx->cur_ino; - int ret = 0; - - pm = get_pending_dir_moves(sctx, parent_ino); - if (!pm) - return 0; - - INIT_LIST_HEAD(&stack); - tail_append_pending_moves(pm, &stack); - - while (!list_empty(&stack)) { - pm = list_first_entry(&stack, struct pending_dir_move, list); - parent_ino = pm->ino; - ret = apply_dir_move(sctx, pm); - free_pending_move(sctx, pm); - if (ret) - goto out; - pm = get_pending_dir_moves(sctx, parent_ino); - if (pm) - tail_append_pending_moves(pm, &stack); - } - return 0; - -out: - while (!list_empty(&stack)) { - pm = list_first_entry(&stack, struct pending_dir_move, list); - free_pending_move(sctx, pm); - } - return ret; -} - -/* - * We might need to delay a directory rename even when no ancestor directory - * (in the send root) with a higher inode number than ours (sctx->cur_ino) was - * renamed. This happens when we rename a directory to the old name (the name - * in the parent root) of some other unrelated directory that got its rename - * delayed due to some ancestor with higher number that got renamed. - * - * Example: - * - * Parent snapshot: - * . (ino 256) - * |---- a/ (ino 257) - * | |---- file (ino 260) - * | - * |---- b/ (ino 258) - * |---- c/ (ino 259) - * - * Send snapshot: - * . (ino 256) - * |---- a/ (ino 258) - * |---- x/ (ino 259) - * |---- y/ (ino 257) - * |----- file (ino 260) - * - * Here we can not rename 258 from 'b' to 'a' without the rename of inode 257 - * from 'a' to 'x/y' happening first, which in turn depends on the rename of - * inode 259 from 'c' to 'x'. So the order of rename commands the send stream - * must issue is: - * - * 1 - rename 259 from 'c' to 'x' - * 2 - rename 257 from 'a' to 'x/y' - * 3 - rename 258 from 'b' to 'a' - * - * Returns 1 if the rename of sctx->cur_ino needs to be delayed, 0 if it can - * be done right away and < 0 on error. - */ -static int wait_for_dest_dir_move(struct send_ctx *sctx, - struct recorded_ref *parent_ref, - const bool is_orphan) -{ - struct btrfs_path *path; - struct btrfs_key key; - struct btrfs_key di_key; - struct btrfs_dir_item *di; - u64 left_gen; - u64 right_gen; - int ret = 0; - struct waiting_dir_move *wdm; - - if (RB_EMPTY_ROOT(&sctx->waiting_dir_moves)) - return 0; - - path = alloc_path_for_send(); - if (!path) - return -ENOMEM; - - key.objectid = parent_ref->dir; - key.type = BTRFS_DIR_ITEM_KEY; - key.offset = btrfs_name_hash(parent_ref->name, parent_ref->name_len); - - ret = btrfs_search_slot(NULL, sctx->parent_root, &key, path, 0, 0); - if (ret < 0) { - goto out; - } else if (ret > 0) { - ret = 0; - goto out; - } - - di = btrfs_match_dir_item_name(sctx->parent_root, path, - parent_ref->name, parent_ref->name_len); - if (!di) { - ret = 0; - goto out; - } - /* - * di_key.objectid has the number of the inode that has a dentry in the - * parent directory with the same name that sctx->cur_ino is being - * renamed to. We need to check if that inode is in the send root as - * well and if it is currently marked as an inode with a pending rename, - * if it is, we need to delay the rename of sctx->cur_ino as well, so - * that it happens after that other inode is renamed. - */ - btrfs_dir_item_key_to_cpu(path->nodes[0], di, &di_key); - if (di_key.type != BTRFS_INODE_ITEM_KEY) { - ret = 0; - goto out; - } - - ret = get_inode_info(sctx->parent_root, di_key.objectid, NULL, - &left_gen, NULL, NULL, NULL, NULL); - if (ret < 0) - goto out; - ret = get_inode_info(sctx->send_root, di_key.objectid, NULL, - &right_gen, NULL, NULL, NULL, NULL); - if (ret < 0) { - if (ret == -ENOENT) - ret = 0; - goto out; - } - - /* Different inode, no need to delay the rename of sctx->cur_ino */ - if (right_gen != left_gen) { - ret = 0; - goto out; - } - - wdm = get_waiting_dir_move(sctx, di_key.objectid); - if (wdm && !wdm->orphanized) { - ret = add_pending_dir_move(sctx, - sctx->cur_ino, - sctx->cur_inode_gen, - di_key.objectid, - &sctx->new_refs, - &sctx->deleted_refs, - is_orphan); - if (!ret) - ret = 1; - } -out: - btrfs_free_path(path); - return ret; -} - -/* - * Check if ino ino1 is an ancestor of inode ino2 in the given root. - * Return 1 if true, 0 if false and < 0 on error. - */ -static int is_ancestor(struct btrfs_root *root, - const u64 ino1, - const u64 ino1_gen, - const u64 ino2, - struct fs_path *fs_path) -{ - u64 ino = ino2; - - while (ino > BTRFS_FIRST_FREE_OBJECTID) { - int ret; - u64 parent; - u64 parent_gen; - - fs_path_reset(fs_path); - ret = get_first_ref(root, ino, &parent, &parent_gen, fs_path); - if (ret < 0) { - if (ret == -ENOENT && ino == ino2) - ret = 0; - return ret; - } - if (parent == ino1) - return parent_gen == ino1_gen ? 1 : 0; - ino = parent; - } - return 0; -} - -static int wait_for_parent_move(struct send_ctx *sctx, - struct recorded_ref *parent_ref, - const bool is_orphan) -{ - int ret = 0; - u64 ino = parent_ref->dir; - u64 parent_ino_before, parent_ino_after; - struct fs_path *path_before = NULL; - struct fs_path *path_after = NULL; - int len1, len2; - - path_after = fs_path_alloc(); - path_before = fs_path_alloc(); - if (!path_after || !path_before) { - ret = -ENOMEM; - goto out; - } - - /* - * Our current directory inode may not yet be renamed/moved because some - * ancestor (immediate or not) has to be renamed/moved first. So find if - * such ancestor exists and make sure our own rename/move happens after - * that ancestor is processed to avoid path build infinite loops (done - * at get_cur_path()). - */ - while (ino > BTRFS_FIRST_FREE_OBJECTID) { - if (is_waiting_for_move(sctx, ino)) { - /* - * If the current inode is an ancestor of ino in the - * parent root, we need to delay the rename of the - * current inode, otherwise don't delayed the rename - * because we can end up with a circular dependency - * of renames, resulting in some directories never - * getting the respective rename operations issued in - * the send stream or getting into infinite path build - * loops. - */ - ret = is_ancestor(sctx->parent_root, - sctx->cur_ino, sctx->cur_inode_gen, - ino, path_before); - if (ret) - break; - } - - fs_path_reset(path_before); - fs_path_reset(path_after); - - ret = get_first_ref(sctx->send_root, ino, &parent_ino_after, - NULL, path_after); - if (ret < 0) - goto out; - ret = get_first_ref(sctx->parent_root, ino, &parent_ino_before, - NULL, path_before); - if (ret < 0 && ret != -ENOENT) { - goto out; - } else if (ret == -ENOENT) { - ret = 0; - break; - } - - len1 = fs_path_len(path_before); - len2 = fs_path_len(path_after); - if (ino > sctx->cur_ino && - (parent_ino_before != parent_ino_after || len1 != len2 || - memcmp(path_before->start, path_after->start, len1))) { - ret = 1; - break; - } - ino = parent_ino_after; - } - -out: - fs_path_free(path_before); - fs_path_free(path_after); - - if (ret == 1) { - ret = add_pending_dir_move(sctx, - sctx->cur_ino, - sctx->cur_inode_gen, - ino, - &sctx->new_refs, - &sctx->deleted_refs, - is_orphan); - if (!ret) - ret = 1; - } - - return ret; -} - -/* - * This does all the move/link/unlink/rmdir magic. - */ -static int process_recorded_refs(struct send_ctx *sctx, int *pending_move) -{ - struct btrfs_fs_info *fs_info = sctx->send_root->fs_info; - int ret = 0; - struct recorded_ref *cur; - struct recorded_ref *cur2; - struct list_head check_dirs; - struct fs_path *valid_path = NULL; - u64 ow_inode = 0; - u64 ow_gen; - int did_overwrite = 0; - int is_orphan = 0; - u64 last_dir_ino_rm = 0; - bool can_rename = true; - - btrfs_debug(fs_info, "process_recorded_refs %llu", sctx->cur_ino); - - /* - * This should never happen as the root dir always has the same ref - * which is always '..' - */ - BUG_ON(sctx->cur_ino <= BTRFS_FIRST_FREE_OBJECTID); - INIT_LIST_HEAD(&check_dirs); - - valid_path = fs_path_alloc(); - if (!valid_path) { - ret = -ENOMEM; - goto out; - } - - /* - * First, check if the first ref of the current inode was overwritten - * before. If yes, we know that the current inode was already orphanized - * and thus use the orphan name. If not, we can use get_cur_path to - * get the path of the first ref as it would like while receiving at - * this point in time. - * New inodes are always orphan at the beginning, so force to use the - * orphan name in this case. - * The first ref is stored in valid_path and will be updated if it - * gets moved around. - */ - if (!sctx->cur_inode_new) { - ret = did_overwrite_first_ref(sctx, sctx->cur_ino, - sctx->cur_inode_gen); - if (ret < 0) - goto out; - if (ret) - did_overwrite = 1; - } - if (sctx->cur_inode_new || did_overwrite) { - ret = gen_unique_name(sctx, sctx->cur_ino, - sctx->cur_inode_gen, valid_path); - if (ret < 0) - goto out; - is_orphan = 1; - } else { - ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, - valid_path); - if (ret < 0) - goto out; - } - - list_for_each_entry(cur, &sctx->new_refs, list) { - /* - * We may have refs where the parent directory does not exist - * yet. This happens if the parent directories inum is higher - * the the current inum. To handle this case, we create the - * parent directory out of order. But we need to check if this - * did already happen before due to other refs in the same dir. - */ - ret = get_cur_inode_state(sctx, cur->dir, cur->dir_gen); - if (ret < 0) - goto out; - if (ret == inode_state_will_create) { - ret = 0; - /* - * First check if any of the current inodes refs did - * already create the dir. - */ - list_for_each_entry(cur2, &sctx->new_refs, list) { - if (cur == cur2) - break; - if (cur2->dir == cur->dir) { - ret = 1; - break; - } - } - - /* - * If that did not happen, check if a previous inode - * did already create the dir. - */ - if (!ret) - ret = did_create_dir(sctx, cur->dir); - if (ret < 0) - goto out; - if (!ret) { - ret = send_create_inode(sctx, cur->dir); - if (ret < 0) - goto out; - } - } - - /* - * Check if this new ref would overwrite the first ref of - * another unprocessed inode. If yes, orphanize the - * overwritten inode. If we find an overwritten ref that is - * not the first ref, simply unlink it. - */ - ret = will_overwrite_ref(sctx, cur->dir, cur->dir_gen, - cur->name, cur->name_len, - &ow_inode, &ow_gen); - if (ret < 0) - goto out; - if (ret) { - ret = is_first_ref(sctx->parent_root, - ow_inode, cur->dir, cur->name, - cur->name_len); - if (ret < 0) - goto out; - if (ret) { - struct name_cache_entry *nce; - struct waiting_dir_move *wdm; - - ret = orphanize_inode(sctx, ow_inode, ow_gen, - cur->full_path); - if (ret < 0) - goto out; - - /* - * If ow_inode has its rename operation delayed - * make sure that its orphanized name is used in - * the source path when performing its rename - * operation. - */ - if (is_waiting_for_move(sctx, ow_inode)) { - wdm = get_waiting_dir_move(sctx, - ow_inode); - ASSERT(wdm); - wdm->orphanized = true; - } - - /* - * Make sure we clear our orphanized inode's - * name from the name cache. This is because the - * inode ow_inode might be an ancestor of some - * other inode that will be orphanized as well - * later and has an inode number greater than - * sctx->send_progress. We need to prevent - * future name lookups from using the old name - * and get instead the orphan name. - */ - nce = name_cache_search(sctx, ow_inode, ow_gen); - if (nce) { - name_cache_delete(sctx, nce); - kfree(nce); - } - - /* - * ow_inode might currently be an ancestor of - * cur_ino, therefore compute valid_path (the - * current path of cur_ino) again because it - * might contain the pre-orphanization name of - * ow_inode, which is no longer valid. - */ - fs_path_reset(valid_path); - ret = get_cur_path(sctx, sctx->cur_ino, - sctx->cur_inode_gen, valid_path); - if (ret < 0) - goto out; - } else { - ret = send_unlink(sctx, cur->full_path); - if (ret < 0) - goto out; - } - } - - if (S_ISDIR(sctx->cur_inode_mode) && sctx->parent_root) { - ret = wait_for_dest_dir_move(sctx, cur, is_orphan); - if (ret < 0) - goto out; - if (ret == 1) { - can_rename = false; - *pending_move = 1; - } - } - - if (S_ISDIR(sctx->cur_inode_mode) && sctx->parent_root && - can_rename) { - ret = wait_for_parent_move(sctx, cur, is_orphan); - if (ret < 0) - goto out; - if (ret == 1) { - can_rename = false; - *pending_move = 1; - } - } - - /* - * link/move the ref to the new place. If we have an orphan - * inode, move it and update valid_path. If not, link or move - * it depending on the inode mode. - */ - if (is_orphan && can_rename) { - ret = send_rename(sctx, valid_path, cur->full_path); - if (ret < 0) - goto out; - is_orphan = 0; - ret = fs_path_copy(valid_path, cur->full_path); - if (ret < 0) - goto out; - } else if (can_rename) { - if (S_ISDIR(sctx->cur_inode_mode)) { - /* - * Dirs can't be linked, so move it. For moved - * dirs, we always have one new and one deleted - * ref. The deleted ref is ignored later. - */ - ret = send_rename(sctx, valid_path, - cur->full_path); - if (!ret) - ret = fs_path_copy(valid_path, - cur->full_path); - if (ret < 0) - goto out; - } else { - ret = send_link(sctx, cur->full_path, - valid_path); - if (ret < 0) - goto out; - } - } - ret = dup_ref(cur, &check_dirs); - if (ret < 0) - goto out; - } - - if (S_ISDIR(sctx->cur_inode_mode) && sctx->cur_inode_deleted) { - /* - * Check if we can already rmdir the directory. If not, - * orphanize it. For every dir item inside that gets deleted - * later, we do this check again and rmdir it then if possible. - * See the use of check_dirs for more details. - */ - ret = can_rmdir(sctx, sctx->cur_ino, sctx->cur_inode_gen, - sctx->cur_ino); - if (ret < 0) - goto out; - if (ret) { - ret = send_rmdir(sctx, valid_path); - if (ret < 0) - goto out; - } else if (!is_orphan) { - ret = orphanize_inode(sctx, sctx->cur_ino, - sctx->cur_inode_gen, valid_path); - if (ret < 0) - goto out; - is_orphan = 1; - } - - list_for_each_entry(cur, &sctx->deleted_refs, list) { - ret = dup_ref(cur, &check_dirs); - if (ret < 0) - goto out; - } - } else if (S_ISDIR(sctx->cur_inode_mode) && - !list_empty(&sctx->deleted_refs)) { - /* - * We have a moved dir. Add the old parent to check_dirs - */ - cur = list_entry(sctx->deleted_refs.next, struct recorded_ref, - list); - ret = dup_ref(cur, &check_dirs); - if (ret < 0) - goto out; - } else if (!S_ISDIR(sctx->cur_inode_mode)) { - /* - * We have a non dir inode. Go through all deleted refs and - * unlink them if they were not already overwritten by other - * inodes. - */ - list_for_each_entry(cur, &sctx->deleted_refs, list) { - ret = did_overwrite_ref(sctx, cur->dir, cur->dir_gen, - sctx->cur_ino, sctx->cur_inode_gen, - cur->name, cur->name_len); - if (ret < 0) - goto out; - if (!ret) { - ret = send_unlink(sctx, cur->full_path); - if (ret < 0) - goto out; - } - ret = dup_ref(cur, &check_dirs); - if (ret < 0) - goto out; - } - /* - * If the inode is still orphan, unlink the orphan. This may - * happen when a previous inode did overwrite the first ref - * of this inode and no new refs were added for the current - * inode. Unlinking does not mean that the inode is deleted in - * all cases. There may still be links to this inode in other - * places. - */ - if (is_orphan) { - ret = send_unlink(sctx, valid_path); - if (ret < 0) - goto out; - } - } - - /* - * We did collect all parent dirs where cur_inode was once located. We - * now go through all these dirs and check if they are pending for - * deletion and if it's finally possible to perform the rmdir now. - * We also update the inode stats of the parent dirs here. - */ - list_for_each_entry(cur, &check_dirs, list) { - /* - * In case we had refs into dirs that were not processed yet, - * we don't need to do the utime and rmdir logic for these dirs. - * The dir will be processed later. - */ - if (cur->dir > sctx->cur_ino) - continue; - - ret = get_cur_inode_state(sctx, cur->dir, cur->dir_gen); - if (ret < 0) - goto out; - - if (ret == inode_state_did_create || - ret == inode_state_no_change) { - /* TODO delayed utimes */ - ret = send_utimes(sctx, cur->dir, cur->dir_gen); - if (ret < 0) - goto out; - } else if (ret == inode_state_did_delete && - cur->dir != last_dir_ino_rm) { - ret = can_rmdir(sctx, cur->dir, cur->dir_gen, - sctx->cur_ino); - if (ret < 0) - goto out; - if (ret) { - ret = get_cur_path(sctx, cur->dir, - cur->dir_gen, valid_path); - if (ret < 0) - goto out; - ret = send_rmdir(sctx, valid_path); - if (ret < 0) - goto out; - last_dir_ino_rm = cur->dir; - } - } - } - - ret = 0; - -out: - __free_recorded_refs(&check_dirs); - free_recorded_refs(sctx); - fs_path_free(valid_path); - return ret; -} - -static int record_ref(struct btrfs_root *root, int num, u64 dir, int index, - struct fs_path *name, void *ctx, struct list_head *refs) -{ - int ret = 0; - struct send_ctx *sctx = ctx; - struct fs_path *p; - u64 gen; - - p = fs_path_alloc(); - if (!p) - return -ENOMEM; - - ret = get_inode_info(root, dir, NULL, &gen, NULL, NULL, - NULL, NULL); - if (ret < 0) - goto out; - - ret = get_cur_path(sctx, dir, gen, p); - if (ret < 0) - goto out; - ret = fs_path_add_path(p, name); - if (ret < 0) - goto out; - - ret = __record_ref(refs, dir, gen, p); - -out: - if (ret) - fs_path_free(p); - return ret; -} - -static int __record_new_ref(int num, u64 dir, int index, - struct fs_path *name, - void *ctx) -{ - struct send_ctx *sctx = ctx; - return record_ref(sctx->send_root, num, dir, index, name, - ctx, &sctx->new_refs); -} - - -static int __record_deleted_ref(int num, u64 dir, int index, - struct fs_path *name, - void *ctx) -{ - struct send_ctx *sctx = ctx; - return record_ref(sctx->parent_root, num, dir, index, name, - ctx, &sctx->deleted_refs); -} - -static int record_new_ref(struct send_ctx *sctx) -{ - int ret; - - ret = iterate_inode_ref(sctx->send_root, sctx->left_path, - sctx->cmp_key, 0, __record_new_ref, sctx); - if (ret < 0) - goto out; - ret = 0; - -out: - return ret; -} - -static int record_deleted_ref(struct send_ctx *sctx) -{ - int ret; - - ret = iterate_inode_ref(sctx->parent_root, sctx->right_path, - sctx->cmp_key, 0, __record_deleted_ref, sctx); - if (ret < 0) - goto out; - ret = 0; - -out: - return ret; -} - -struct find_ref_ctx { - u64 dir; - u64 dir_gen; - struct btrfs_root *root; - struct fs_path *name; - int found_idx; -}; - -static int __find_iref(int num, u64 dir, int index, - struct fs_path *name, - void *ctx_) -{ - struct find_ref_ctx *ctx = ctx_; - u64 dir_gen; - int ret; - - if (dir == ctx->dir && fs_path_len(name) == fs_path_len(ctx->name) && - strncmp(name->start, ctx->name->start, fs_path_len(name)) == 0) { - /* - * To avoid doing extra lookups we'll only do this if everything - * else matches. - */ - ret = get_inode_info(ctx->root, dir, NULL, &dir_gen, NULL, - NULL, NULL, NULL); - if (ret) - return ret; - if (dir_gen != ctx->dir_gen) - return 0; - ctx->found_idx = num; - return 1; - } - return 0; -} - -static int find_iref(struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_key *key, - u64 dir, u64 dir_gen, struct fs_path *name) -{ - int ret; - struct find_ref_ctx ctx; - - ctx.dir = dir; - ctx.name = name; - ctx.dir_gen = dir_gen; - ctx.found_idx = -1; - ctx.root = root; - - ret = iterate_inode_ref(root, path, key, 0, __find_iref, &ctx); - if (ret < 0) - return ret; - - if (ctx.found_idx == -1) - return -ENOENT; - - return ctx.found_idx; -} - -static int __record_changed_new_ref(int num, u64 dir, int index, - struct fs_path *name, - void *ctx) -{ - u64 dir_gen; - int ret; - struct send_ctx *sctx = ctx; - - ret = get_inode_info(sctx->send_root, dir, NULL, &dir_gen, NULL, - NULL, NULL, NULL); - if (ret) - return ret; - - ret = find_iref(sctx->parent_root, sctx->right_path, - sctx->cmp_key, dir, dir_gen, name); - if (ret == -ENOENT) - ret = __record_new_ref(num, dir, index, name, sctx); - else if (ret > 0) - ret = 0; - - return ret; -} - -static int __record_changed_deleted_ref(int num, u64 dir, int index, - struct fs_path *name, - void *ctx) -{ - u64 dir_gen; - int ret; - struct send_ctx *sctx = ctx; - - ret = get_inode_info(sctx->parent_root, dir, NULL, &dir_gen, NULL, - NULL, NULL, NULL); - if (ret) - return ret; - - ret = find_iref(sctx->send_root, sctx->left_path, sctx->cmp_key, - dir, dir_gen, name); - if (ret == -ENOENT) - ret = __record_deleted_ref(num, dir, index, name, sctx); - else if (ret > 0) - ret = 0; - - return ret; -} - -static int record_changed_ref(struct send_ctx *sctx) -{ - int ret = 0; - - ret = iterate_inode_ref(sctx->send_root, sctx->left_path, - sctx->cmp_key, 0, __record_changed_new_ref, sctx); - if (ret < 0) - goto out; - ret = iterate_inode_ref(sctx->parent_root, sctx->right_path, - sctx->cmp_key, 0, __record_changed_deleted_ref, sctx); - if (ret < 0) - goto out; - ret = 0; - -out: - return ret; -} - -/* - * Record and process all refs at once. Needed when an inode changes the - * generation number, which means that it was deleted and recreated. - */ -static int process_all_refs(struct send_ctx *sctx, - enum btrfs_compare_tree_result cmd) -{ - int ret; - struct btrfs_root *root; - struct btrfs_path *path; - struct btrfs_key key; - struct btrfs_key found_key; - struct extent_buffer *eb; - int slot; - iterate_inode_ref_t cb; - int pending_move = 0; - - path = alloc_path_for_send(); - if (!path) - return -ENOMEM; - - if (cmd == BTRFS_COMPARE_TREE_NEW) { - root = sctx->send_root; - cb = __record_new_ref; - } else if (cmd == BTRFS_COMPARE_TREE_DELETED) { - root = sctx->parent_root; - cb = __record_deleted_ref; - } else { - btrfs_err(sctx->send_root->fs_info, - "Wrong command %d in process_all_refs", cmd); - ret = -EINVAL; - goto out; - } - - key.objectid = sctx->cmp_key->objectid; - key.type = BTRFS_INODE_REF_KEY; - key.offset = 0; - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out; - - while (1) { - eb = path->nodes[0]; - slot = path->slots[0]; - if (slot >= btrfs_header_nritems(eb)) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) - goto out; - else if (ret > 0) - break; - continue; - } - - btrfs_item_key_to_cpu(eb, &found_key, slot); - - if (found_key.objectid != key.objectid || - (found_key.type != BTRFS_INODE_REF_KEY && - found_key.type != BTRFS_INODE_EXTREF_KEY)) - break; - - ret = iterate_inode_ref(root, path, &found_key, 0, cb, sctx); - if (ret < 0) - goto out; - - path->slots[0]++; - } - btrfs_release_path(path); - - /* - * We don't actually care about pending_move as we are simply - * re-creating this inode and will be rename'ing it into place once we - * rename the parent directory. - */ - ret = process_recorded_refs(sctx, &pending_move); -out: - btrfs_free_path(path); - return ret; -} - -static int send_set_xattr(struct send_ctx *sctx, - struct fs_path *path, - const char *name, int name_len, - const char *data, int data_len) -{ - int ret = 0; - - ret = begin_cmd(sctx, BTRFS_SEND_C_SET_XATTR); - if (ret < 0) - goto out; - - TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, path); - TLV_PUT_STRING(sctx, BTRFS_SEND_A_XATTR_NAME, name, name_len); - TLV_PUT(sctx, BTRFS_SEND_A_XATTR_DATA, data, data_len); - - ret = send_cmd(sctx); - -tlv_put_failure: -out: - return ret; -} - -static int send_remove_xattr(struct send_ctx *sctx, - struct fs_path *path, - const char *name, int name_len) -{ - int ret = 0; - - ret = begin_cmd(sctx, BTRFS_SEND_C_REMOVE_XATTR); - if (ret < 0) - goto out; - - TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, path); - TLV_PUT_STRING(sctx, BTRFS_SEND_A_XATTR_NAME, name, name_len); - - ret = send_cmd(sctx); - -tlv_put_failure: -out: - return ret; -} - -static int __process_new_xattr(int num, struct btrfs_key *di_key, - const char *name, int name_len, - const char *data, int data_len, - u8 type, void *ctx) -{ - int ret; - struct send_ctx *sctx = ctx; - struct fs_path *p; - struct posix_acl_xattr_header dummy_acl; - - p = fs_path_alloc(); - if (!p) - return -ENOMEM; - - /* - * This hack is needed because empty acls are stored as zero byte - * data in xattrs. Problem with that is, that receiving these zero byte - * acls will fail later. To fix this, we send a dummy acl list that - * only contains the version number and no entries. - */ - if (!strncmp(name, XATTR_NAME_POSIX_ACL_ACCESS, name_len) || - !strncmp(name, XATTR_NAME_POSIX_ACL_DEFAULT, name_len)) { - if (data_len == 0) { - dummy_acl.a_version = - cpu_to_le32(POSIX_ACL_XATTR_VERSION); - data = (char *)&dummy_acl; - data_len = sizeof(dummy_acl); - } - } - - ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, p); - if (ret < 0) - goto out; - - ret = send_set_xattr(sctx, p, name, name_len, data, data_len); - -out: - fs_path_free(p); - return ret; -} - -static int __process_deleted_xattr(int num, struct btrfs_key *di_key, - const char *name, int name_len, - const char *data, int data_len, - u8 type, void *ctx) -{ - int ret; - struct send_ctx *sctx = ctx; - struct fs_path *p; - - p = fs_path_alloc(); - if (!p) - return -ENOMEM; - - ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, p); - if (ret < 0) - goto out; - - ret = send_remove_xattr(sctx, p, name, name_len); - -out: - fs_path_free(p); - return ret; -} - -static int process_new_xattr(struct send_ctx *sctx) -{ - int ret = 0; - - ret = iterate_dir_item(sctx->send_root, sctx->left_path, - sctx->cmp_key, __process_new_xattr, sctx); - - return ret; -} - -static int process_deleted_xattr(struct send_ctx *sctx) -{ - return iterate_dir_item(sctx->parent_root, sctx->right_path, - sctx->cmp_key, __process_deleted_xattr, sctx); -} - -struct find_xattr_ctx { - const char *name; - int name_len; - int found_idx; - char *found_data; - int found_data_len; -}; - -static int __find_xattr(int num, struct btrfs_key *di_key, - const char *name, int name_len, - const char *data, int data_len, - u8 type, void *vctx) -{ - struct find_xattr_ctx *ctx = vctx; - - if (name_len == ctx->name_len && - strncmp(name, ctx->name, name_len) == 0) { - ctx->found_idx = num; - ctx->found_data_len = data_len; - ctx->found_data = kmemdup(data, data_len, GFP_KERNEL); - if (!ctx->found_data) - return -ENOMEM; - return 1; - } - return 0; -} - -static int find_xattr(struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_key *key, - const char *name, int name_len, - char **data, int *data_len) -{ - int ret; - struct find_xattr_ctx ctx; - - ctx.name = name; - ctx.name_len = name_len; - ctx.found_idx = -1; - ctx.found_data = NULL; - ctx.found_data_len = 0; - - ret = iterate_dir_item(root, path, key, __find_xattr, &ctx); - if (ret < 0) - return ret; - - if (ctx.found_idx == -1) - return -ENOENT; - if (data) { - *data = ctx.found_data; - *data_len = ctx.found_data_len; - } else { - kfree(ctx.found_data); - } - return ctx.found_idx; -} - - -static int __process_changed_new_xattr(int num, struct btrfs_key *di_key, - const char *name, int name_len, - const char *data, int data_len, - u8 type, void *ctx) -{ - int ret; - struct send_ctx *sctx = ctx; - char *found_data = NULL; - int found_data_len = 0; - - ret = find_xattr(sctx->parent_root, sctx->right_path, - sctx->cmp_key, name, name_len, &found_data, - &found_data_len); - if (ret == -ENOENT) { - ret = __process_new_xattr(num, di_key, name, name_len, data, - data_len, type, ctx); - } else if (ret >= 0) { - if (data_len != found_data_len || - memcmp(data, found_data, data_len)) { - ret = __process_new_xattr(num, di_key, name, name_len, - data, data_len, type, ctx); - } else { - ret = 0; - } - } - - kfree(found_data); - return ret; -} - -static int __process_changed_deleted_xattr(int num, struct btrfs_key *di_key, - const char *name, int name_len, - const char *data, int data_len, - u8 type, void *ctx) -{ - int ret; - struct send_ctx *sctx = ctx; - - ret = find_xattr(sctx->send_root, sctx->left_path, sctx->cmp_key, - name, name_len, NULL, NULL); - if (ret == -ENOENT) - ret = __process_deleted_xattr(num, di_key, name, name_len, data, - data_len, type, ctx); - else if (ret >= 0) - ret = 0; - - return ret; -} - -static int process_changed_xattr(struct send_ctx *sctx) -{ - int ret = 0; - - ret = iterate_dir_item(sctx->send_root, sctx->left_path, - sctx->cmp_key, __process_changed_new_xattr, sctx); - if (ret < 0) - goto out; - ret = iterate_dir_item(sctx->parent_root, sctx->right_path, - sctx->cmp_key, __process_changed_deleted_xattr, sctx); - -out: - return ret; -} - -static int process_all_new_xattrs(struct send_ctx *sctx) -{ - int ret; - struct btrfs_root *root; - struct btrfs_path *path; - struct btrfs_key key; - struct btrfs_key found_key; - struct extent_buffer *eb; - int slot; - - path = alloc_path_for_send(); - if (!path) - return -ENOMEM; - - root = sctx->send_root; - - key.objectid = sctx->cmp_key->objectid; - key.type = BTRFS_XATTR_ITEM_KEY; - key.offset = 0; - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out; - - while (1) { - eb = path->nodes[0]; - slot = path->slots[0]; - if (slot >= btrfs_header_nritems(eb)) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) { - goto out; - } else if (ret > 0) { - ret = 0; - break; - } - continue; - } - - btrfs_item_key_to_cpu(eb, &found_key, slot); - if (found_key.objectid != key.objectid || - found_key.type != key.type) { - ret = 0; - goto out; - } - - ret = iterate_dir_item(root, path, &found_key, - __process_new_xattr, sctx); - if (ret < 0) - goto out; - - path->slots[0]++; - } - -out: - btrfs_free_path(path); - return ret; -} - -static ssize_t fill_read_buf(struct send_ctx *sctx, u64 offset, u32 len) -{ - struct btrfs_root *root = sctx->send_root; - struct btrfs_fs_info *fs_info = root->fs_info; - struct inode *inode; - struct page *page; - char *addr; - struct btrfs_key key; - pgoff_t index = offset >> PAGE_SHIFT; - pgoff_t last_index; - unsigned pg_offset = offset & ~PAGE_MASK; - ssize_t ret = 0; - - key.objectid = sctx->cur_ino; - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - - inode = btrfs_iget(fs_info->sb, &key, root, NULL); - if (IS_ERR(inode)) - return PTR_ERR(inode); - - if (offset + len > i_size_read(inode)) { - if (offset > i_size_read(inode)) - len = 0; - else - len = offset - i_size_read(inode); - } - if (len == 0) - goto out; - - last_index = (offset + len - 1) >> PAGE_SHIFT; - - /* initial readahead */ - memset(&sctx->ra, 0, sizeof(struct file_ra_state)); - file_ra_state_init(&sctx->ra, inode->i_mapping); - btrfs_force_ra(inode->i_mapping, &sctx->ra, NULL, index, - last_index - index + 1); - - while (index <= last_index) { - unsigned cur_len = min_t(unsigned, len, - PAGE_SIZE - pg_offset); - page = find_or_create_page(inode->i_mapping, index, GFP_KERNEL); - if (!page) { - ret = -ENOMEM; - break; - } - - if (!PageUptodate(page)) { - btrfs_readpage(NULL, page); - lock_page(page); - if (!PageUptodate(page)) { - unlock_page(page); - put_page(page); - ret = -EIO; - break; - } - } - - addr = kmap(page); - memcpy(sctx->read_buf + ret, addr + pg_offset, cur_len); - kunmap(page); - unlock_page(page); - put_page(page); - index++; - pg_offset = 0; - len -= cur_len; - ret += cur_len; - } -out: - iput(inode); - return ret; -} - -/* - * Read some bytes from the current inode/file and send a write command to - * user space. - */ -static int send_write(struct send_ctx *sctx, u64 offset, u32 len) -{ - struct btrfs_fs_info *fs_info = sctx->send_root->fs_info; - int ret = 0; - struct fs_path *p; - ssize_t num_read = 0; - - p = fs_path_alloc(); - if (!p) - return -ENOMEM; - - btrfs_debug(fs_info, "send_write offset=%llu, len=%d", offset, len); - - num_read = fill_read_buf(sctx, offset, len); - if (num_read <= 0) { - if (num_read < 0) - ret = num_read; - goto out; - } - - ret = begin_cmd(sctx, BTRFS_SEND_C_WRITE); - if (ret < 0) - goto out; - - ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, p); - if (ret < 0) - goto out; - - TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p); - TLV_PUT_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, offset); - TLV_PUT(sctx, BTRFS_SEND_A_DATA, sctx->read_buf, num_read); - - ret = send_cmd(sctx); - -tlv_put_failure: -out: - fs_path_free(p); - if (ret < 0) - return ret; - return num_read; -} - -/* - * Send a clone command to user space. - */ -static int send_clone(struct send_ctx *sctx, - u64 offset, u32 len, - struct clone_root *clone_root) -{ - int ret = 0; - struct fs_path *p; - u64 gen; - - btrfs_debug(sctx->send_root->fs_info, - "send_clone offset=%llu, len=%d, clone_root=%llu, clone_inode=%llu, clone_offset=%llu", - offset, len, clone_root->root->objectid, clone_root->ino, - clone_root->offset); - - p = fs_path_alloc(); - if (!p) - return -ENOMEM; - - ret = begin_cmd(sctx, BTRFS_SEND_C_CLONE); - if (ret < 0) - goto out; - - ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, p); - if (ret < 0) - goto out; - - TLV_PUT_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, offset); - TLV_PUT_U64(sctx, BTRFS_SEND_A_CLONE_LEN, len); - TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p); - - if (clone_root->root == sctx->send_root) { - ret = get_inode_info(sctx->send_root, clone_root->ino, NULL, - &gen, NULL, NULL, NULL, NULL); - if (ret < 0) - goto out; - ret = get_cur_path(sctx, clone_root->ino, gen, p); - } else { - ret = get_inode_path(clone_root->root, clone_root->ino, p); - } - if (ret < 0) - goto out; - - /* - * If the parent we're using has a received_uuid set then use that as - * our clone source as that is what we will look for when doing a - * receive. - * - * This covers the case that we create a snapshot off of a received - * subvolume and then use that as the parent and try to receive on a - * different host. - */ - if (!btrfs_is_empty_uuid(clone_root->root->root_item.received_uuid)) - TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, - clone_root->root->root_item.received_uuid); - else - TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID, - clone_root->root->root_item.uuid); - TLV_PUT_U64(sctx, BTRFS_SEND_A_CLONE_CTRANSID, - le64_to_cpu(clone_root->root->root_item.ctransid)); - TLV_PUT_PATH(sctx, BTRFS_SEND_A_CLONE_PATH, p); - TLV_PUT_U64(sctx, BTRFS_SEND_A_CLONE_OFFSET, - clone_root->offset); - - ret = send_cmd(sctx); - -tlv_put_failure: -out: - fs_path_free(p); - return ret; -} - -/* - * Send an update extent command to user space. - */ -static int send_update_extent(struct send_ctx *sctx, - u64 offset, u32 len) -{ - int ret = 0; - struct fs_path *p; - - p = fs_path_alloc(); - if (!p) - return -ENOMEM; - - ret = begin_cmd(sctx, BTRFS_SEND_C_UPDATE_EXTENT); - if (ret < 0) - goto out; - - ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, p); - if (ret < 0) - goto out; - - TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p); - TLV_PUT_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, offset); - TLV_PUT_U64(sctx, BTRFS_SEND_A_SIZE, len); - - ret = send_cmd(sctx); - -tlv_put_failure: -out: - fs_path_free(p); - return ret; -} - -static int send_hole(struct send_ctx *sctx, u64 end) -{ - struct fs_path *p = NULL; - u64 offset = sctx->cur_inode_last_extent; - u64 len; - int ret = 0; - - p = fs_path_alloc(); - if (!p) - return -ENOMEM; - ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, p); - if (ret < 0) - goto tlv_put_failure; - memset(sctx->read_buf, 0, BTRFS_SEND_READ_SIZE); - while (offset < end) { - len = min_t(u64, end - offset, BTRFS_SEND_READ_SIZE); - - ret = begin_cmd(sctx, BTRFS_SEND_C_WRITE); - if (ret < 0) - break; - TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p); - TLV_PUT_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, offset); - TLV_PUT(sctx, BTRFS_SEND_A_DATA, sctx->read_buf, len); - ret = send_cmd(sctx); - if (ret < 0) - break; - offset += len; - } -tlv_put_failure: - fs_path_free(p); - return ret; -} - -static int send_extent_data(struct send_ctx *sctx, - const u64 offset, - const u64 len) -{ - u64 sent = 0; - - if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA) - return send_update_extent(sctx, offset, len); - - while (sent < len) { - u64 size = len - sent; - int ret; - - if (size > BTRFS_SEND_READ_SIZE) - size = BTRFS_SEND_READ_SIZE; - ret = send_write(sctx, offset + sent, size); - if (ret < 0) - return ret; - if (!ret) - break; - sent += ret; - } - return 0; -} - -static int clone_range(struct send_ctx *sctx, - struct clone_root *clone_root, - const u64 disk_byte, - u64 data_offset, - u64 offset, - u64 len) -{ - struct btrfs_path *path; - struct btrfs_key key; - int ret; - - path = alloc_path_for_send(); - if (!path) - return -ENOMEM; - - /* - * We can't send a clone operation for the entire range if we find - * extent items in the respective range in the source file that - * refer to different extents or if we find holes. - * So check for that and do a mix of clone and regular write/copy - * operations if needed. - * - * Example: - * - * mkfs.btrfs -f /dev/sda - * mount /dev/sda /mnt - * xfs_io -f -c "pwrite -S 0xaa 0K 100K" /mnt/foo - * cp --reflink=always /mnt/foo /mnt/bar - * xfs_io -c "pwrite -S 0xbb 50K 50K" /mnt/foo - * btrfs subvolume snapshot -r /mnt /mnt/snap - * - * If when we send the snapshot and we are processing file bar (which - * has a higher inode number than foo) we blindly send a clone operation - * for the [0, 100K[ range from foo to bar, the receiver ends up getting - * a file bar that matches the content of file foo - iow, doesn't match - * the content from bar in the original filesystem. - */ - key.objectid = clone_root->ino; - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = clone_root->offset; - ret = btrfs_search_slot(NULL, clone_root->root, &key, path, 0, 0); - if (ret < 0) - goto out; - if (ret > 0 && path->slots[0] > 0) { - btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0] - 1); - if (key.objectid == clone_root->ino && - key.type == BTRFS_EXTENT_DATA_KEY) - path->slots[0]--; - } - - while (true) { - struct extent_buffer *leaf = path->nodes[0]; - int slot = path->slots[0]; - struct btrfs_file_extent_item *ei; - u8 type; - u64 ext_len; - u64 clone_len; - - if (slot >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(clone_root->root, path); - if (ret < 0) - goto out; - else if (ret > 0) - break; - continue; - } - - btrfs_item_key_to_cpu(leaf, &key, slot); - - /* - * We might have an implicit trailing hole (NO_HOLES feature - * enabled). We deal with it after leaving this loop. - */ - if (key.objectid != clone_root->ino || - key.type != BTRFS_EXTENT_DATA_KEY) - break; - - ei = btrfs_item_ptr(leaf, slot, struct btrfs_file_extent_item); - type = btrfs_file_extent_type(leaf, ei); - if (type == BTRFS_FILE_EXTENT_INLINE) { - ext_len = btrfs_file_extent_inline_len(leaf, slot, ei); - ext_len = PAGE_ALIGN(ext_len); - } else { - ext_len = btrfs_file_extent_num_bytes(leaf, ei); - } - - if (key.offset + ext_len <= clone_root->offset) - goto next; - - if (key.offset > clone_root->offset) { - /* Implicit hole, NO_HOLES feature enabled. */ - u64 hole_len = key.offset - clone_root->offset; - - if (hole_len > len) - hole_len = len; - ret = send_extent_data(sctx, offset, hole_len); - if (ret < 0) - goto out; - - len -= hole_len; - if (len == 0) - break; - offset += hole_len; - clone_root->offset += hole_len; - data_offset += hole_len; - } - - if (key.offset >= clone_root->offset + len) - break; - - clone_len = min_t(u64, ext_len, len); - - if (btrfs_file_extent_disk_bytenr(leaf, ei) == disk_byte && - btrfs_file_extent_offset(leaf, ei) == data_offset) - ret = send_clone(sctx, offset, clone_len, clone_root); - else - ret = send_extent_data(sctx, offset, clone_len); - - if (ret < 0) - goto out; - - len -= clone_len; - if (len == 0) - break; - offset += clone_len; - clone_root->offset += clone_len; - data_offset += clone_len; -next: - path->slots[0]++; - } - - if (len > 0) - ret = send_extent_data(sctx, offset, len); - else - ret = 0; -out: - btrfs_free_path(path); - return ret; -} - -static int send_write_or_clone(struct send_ctx *sctx, - struct btrfs_path *path, - struct btrfs_key *key, - struct clone_root *clone_root) -{ - int ret = 0; - struct btrfs_file_extent_item *ei; - u64 offset = key->offset; - u64 len; - u8 type; - u64 bs = sctx->send_root->fs_info->sb->s_blocksize; - - ei = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_file_extent_item); - type = btrfs_file_extent_type(path->nodes[0], ei); - if (type == BTRFS_FILE_EXTENT_INLINE) { - len = btrfs_file_extent_inline_len(path->nodes[0], - path->slots[0], ei); - /* - * it is possible the inline item won't cover the whole page, - * but there may be items after this page. Make - * sure to send the whole thing - */ - len = PAGE_ALIGN(len); - } else { - len = btrfs_file_extent_num_bytes(path->nodes[0], ei); - } - - if (offset + len > sctx->cur_inode_size) - len = sctx->cur_inode_size - offset; - if (len == 0) { - ret = 0; - goto out; - } - - if (clone_root && IS_ALIGNED(offset + len, bs)) { - u64 disk_byte; - u64 data_offset; - - disk_byte = btrfs_file_extent_disk_bytenr(path->nodes[0], ei); - data_offset = btrfs_file_extent_offset(path->nodes[0], ei); - ret = clone_range(sctx, clone_root, disk_byte, data_offset, - offset, len); - } else { - ret = send_extent_data(sctx, offset, len); - } -out: - return ret; -} - -static int is_extent_unchanged(struct send_ctx *sctx, - struct btrfs_path *left_path, - struct btrfs_key *ekey) -{ - int ret = 0; - struct btrfs_key key; - struct btrfs_path *path = NULL; - struct extent_buffer *eb; - int slot; - struct btrfs_key found_key; - struct btrfs_file_extent_item *ei; - u64 left_disknr; - u64 right_disknr; - u64 left_offset; - u64 right_offset; - u64 left_offset_fixed; - u64 left_len; - u64 right_len; - u64 left_gen; - u64 right_gen; - u8 left_type; - u8 right_type; - - path = alloc_path_for_send(); - if (!path) - return -ENOMEM; - - eb = left_path->nodes[0]; - slot = left_path->slots[0]; - ei = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); - left_type = btrfs_file_extent_type(eb, ei); - - if (left_type != BTRFS_FILE_EXTENT_REG) { - ret = 0; - goto out; - } - left_disknr = btrfs_file_extent_disk_bytenr(eb, ei); - left_len = btrfs_file_extent_num_bytes(eb, ei); - left_offset = btrfs_file_extent_offset(eb, ei); - left_gen = btrfs_file_extent_generation(eb, ei); - - /* - * Following comments will refer to these graphics. L is the left - * extents which we are checking at the moment. 1-8 are the right - * extents that we iterate. - * - * |-----L-----| - * |-1-|-2a-|-3-|-4-|-5-|-6-| - * - * |-----L-----| - * |--1--|-2b-|...(same as above) - * - * Alternative situation. Happens on files where extents got split. - * |-----L-----| - * |-----------7-----------|-6-| - * - * Alternative situation. Happens on files which got larger. - * |-----L-----| - * |-8-| - * Nothing follows after 8. - */ - - key.objectid = ekey->objectid; - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = ekey->offset; - ret = btrfs_search_slot_for_read(sctx->parent_root, &key, path, 0, 0); - if (ret < 0) - goto out; - if (ret) { - ret = 0; - goto out; - } - - /* - * Handle special case where the right side has no extents at all. - */ - eb = path->nodes[0]; - slot = path->slots[0]; - btrfs_item_key_to_cpu(eb, &found_key, slot); - if (found_key.objectid != key.objectid || - found_key.type != key.type) { - /* If we're a hole then just pretend nothing changed */ - ret = (left_disknr) ? 0 : 1; - goto out; - } - - /* - * We're now on 2a, 2b or 7. - */ - key = found_key; - while (key.offset < ekey->offset + left_len) { - ei = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); - right_type = btrfs_file_extent_type(eb, ei); - if (right_type != BTRFS_FILE_EXTENT_REG) { - ret = 0; - goto out; - } - - right_disknr = btrfs_file_extent_disk_bytenr(eb, ei); - right_len = btrfs_file_extent_num_bytes(eb, ei); - right_offset = btrfs_file_extent_offset(eb, ei); - right_gen = btrfs_file_extent_generation(eb, ei); - - /* - * Are we at extent 8? If yes, we know the extent is changed. - * This may only happen on the first iteration. - */ - if (found_key.offset + right_len <= ekey->offset) { - /* If we're a hole just pretend nothing changed */ - ret = (left_disknr) ? 0 : 1; - goto out; - } - - left_offset_fixed = left_offset; - if (key.offset < ekey->offset) { - /* Fix the right offset for 2a and 7. */ - right_offset += ekey->offset - key.offset; - } else { - /* Fix the left offset for all behind 2a and 2b */ - left_offset_fixed += key.offset - ekey->offset; - } - - /* - * Check if we have the same extent. - */ - if (left_disknr != right_disknr || - left_offset_fixed != right_offset || - left_gen != right_gen) { - ret = 0; - goto out; - } - - /* - * Go to the next extent. - */ - ret = btrfs_next_item(sctx->parent_root, path); - if (ret < 0) - goto out; - if (!ret) { - eb = path->nodes[0]; - slot = path->slots[0]; - btrfs_item_key_to_cpu(eb, &found_key, slot); - } - if (ret || found_key.objectid != key.objectid || - found_key.type != key.type) { - key.offset += right_len; - break; - } - if (found_key.offset != key.offset + right_len) { - ret = 0; - goto out; - } - key = found_key; - } - - /* - * We're now behind the left extent (treat as unchanged) or at the end - * of the right side (treat as changed). - */ - if (key.offset >= ekey->offset + left_len) - ret = 1; - else - ret = 0; - - -out: - btrfs_free_path(path); - return ret; -} - -static int get_last_extent(struct send_ctx *sctx, u64 offset) -{ - struct btrfs_path *path; - struct btrfs_root *root = sctx->send_root; - struct btrfs_file_extent_item *fi; - struct btrfs_key key; - u64 extent_end; - u8 type; - int ret; - - path = alloc_path_for_send(); - if (!path) - return -ENOMEM; - - sctx->cur_inode_last_extent = 0; - - key.objectid = sctx->cur_ino; - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = offset; - ret = btrfs_search_slot_for_read(root, &key, path, 0, 1); - if (ret < 0) - goto out; - ret = 0; - btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); - if (key.objectid != sctx->cur_ino || key.type != BTRFS_EXTENT_DATA_KEY) - goto out; - - fi = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_file_extent_item); - type = btrfs_file_extent_type(path->nodes[0], fi); - if (type == BTRFS_FILE_EXTENT_INLINE) { - u64 size = btrfs_file_extent_inline_len(path->nodes[0], - path->slots[0], fi); - extent_end = ALIGN(key.offset + size, - sctx->send_root->sectorsize); - } else { - extent_end = key.offset + - btrfs_file_extent_num_bytes(path->nodes[0], fi); - } - sctx->cur_inode_last_extent = extent_end; -out: - btrfs_free_path(path); - return ret; -} - -static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path, - struct btrfs_key *key) -{ - struct btrfs_file_extent_item *fi; - u64 extent_end; - u8 type; - int ret = 0; - - if (sctx->cur_ino != key->objectid || !need_send_hole(sctx)) - return 0; - - if (sctx->cur_inode_last_extent == (u64)-1) { - ret = get_last_extent(sctx, key->offset - 1); - if (ret) - return ret; - } - - fi = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_file_extent_item); - type = btrfs_file_extent_type(path->nodes[0], fi); - if (type == BTRFS_FILE_EXTENT_INLINE) { - u64 size = btrfs_file_extent_inline_len(path->nodes[0], - path->slots[0], fi); - extent_end = ALIGN(key->offset + size, - sctx->send_root->sectorsize); - } else { - extent_end = key->offset + - btrfs_file_extent_num_bytes(path->nodes[0], fi); - } - - if (path->slots[0] == 0 && - sctx->cur_inode_last_extent < key->offset) { - /* - * We might have skipped entire leafs that contained only - * file extent items for our current inode. These leafs have - * a generation number smaller (older) than the one in the - * current leaf and the leaf our last extent came from, and - * are located between these 2 leafs. - */ - ret = get_last_extent(sctx, key->offset - 1); - if (ret) - return ret; - } - - if (sctx->cur_inode_last_extent < key->offset) - ret = send_hole(sctx, key->offset); - sctx->cur_inode_last_extent = extent_end; - return ret; -} - -static int process_extent(struct send_ctx *sctx, - struct btrfs_path *path, - struct btrfs_key *key) -{ - struct clone_root *found_clone = NULL; - int ret = 0; - - if (S_ISLNK(sctx->cur_inode_mode)) - return 0; - - if (sctx->parent_root && !sctx->cur_inode_new) { - ret = is_extent_unchanged(sctx, path, key); - if (ret < 0) - goto out; - if (ret) { - ret = 0; - goto out_hole; - } - } else { - struct btrfs_file_extent_item *ei; - u8 type; - - ei = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_file_extent_item); - type = btrfs_file_extent_type(path->nodes[0], ei); - if (type == BTRFS_FILE_EXTENT_PREALLOC || - type == BTRFS_FILE_EXTENT_REG) { - /* - * The send spec does not have a prealloc command yet, - * so just leave a hole for prealloc'ed extents until - * we have enough commands queued up to justify rev'ing - * the send spec. - */ - if (type == BTRFS_FILE_EXTENT_PREALLOC) { - ret = 0; - goto out; - } - - /* Have a hole, just skip it. */ - if (btrfs_file_extent_disk_bytenr(path->nodes[0], ei) == 0) { - ret = 0; - goto out; - } - } - } - - ret = find_extent_clone(sctx, path, key->objectid, key->offset, - sctx->cur_inode_size, &found_clone); - if (ret != -ENOENT && ret < 0) - goto out; - - ret = send_write_or_clone(sctx, path, key, found_clone); - if (ret) - goto out; -out_hole: - ret = maybe_send_hole(sctx, path, key); -out: - return ret; -} - -static int process_all_extents(struct send_ctx *sctx) -{ - int ret; - struct btrfs_root *root; - struct btrfs_path *path; - struct btrfs_key key; - struct btrfs_key found_key; - struct extent_buffer *eb; - int slot; - - root = sctx->send_root; - path = alloc_path_for_send(); - if (!path) - return -ENOMEM; - - key.objectid = sctx->cmp_key->objectid; - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = 0; - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out; - - while (1) { - eb = path->nodes[0]; - slot = path->slots[0]; - - if (slot >= btrfs_header_nritems(eb)) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) { - goto out; - } else if (ret > 0) { - ret = 0; - break; - } - continue; - } - - btrfs_item_key_to_cpu(eb, &found_key, slot); - - if (found_key.objectid != key.objectid || - found_key.type != key.type) { - ret = 0; - goto out; - } - - ret = process_extent(sctx, path, &found_key); - if (ret < 0) - goto out; - - path->slots[0]++; - } - -out: - btrfs_free_path(path); - return ret; -} - -static int process_recorded_refs_if_needed(struct send_ctx *sctx, int at_end, - int *pending_move, - int *refs_processed) -{ - int ret = 0; - - if (sctx->cur_ino == 0) - goto out; - if (!at_end && sctx->cur_ino == sctx->cmp_key->objectid && - sctx->cmp_key->type <= BTRFS_INODE_EXTREF_KEY) - goto out; - if (list_empty(&sctx->new_refs) && list_empty(&sctx->deleted_refs)) - goto out; - - ret = process_recorded_refs(sctx, pending_move); - if (ret < 0) - goto out; - - *refs_processed = 1; -out: - return ret; -} - -static int finish_inode_if_needed(struct send_ctx *sctx, int at_end) -{ - int ret = 0; - u64 left_mode; - u64 left_uid; - u64 left_gid; - u64 right_mode; - u64 right_uid; - u64 right_gid; - int need_chmod = 0; - int need_chown = 0; - int pending_move = 0; - int refs_processed = 0; - - ret = process_recorded_refs_if_needed(sctx, at_end, &pending_move, - &refs_processed); - if (ret < 0) - goto out; - - /* - * We have processed the refs and thus need to advance send_progress. - * Now, calls to get_cur_xxx will take the updated refs of the current - * inode into account. - * - * On the other hand, if our current inode is a directory and couldn't - * be moved/renamed because its parent was renamed/moved too and it has - * a higher inode number, we can only move/rename our current inode - * after we moved/renamed its parent. Therefore in this case operate on - * the old path (pre move/rename) of our current inode, and the - * move/rename will be performed later. - */ - if (refs_processed && !pending_move) - sctx->send_progress = sctx->cur_ino + 1; - - if (sctx->cur_ino == 0 || sctx->cur_inode_deleted) - goto out; - if (!at_end && sctx->cmp_key->objectid == sctx->cur_ino) - goto out; - - ret = get_inode_info(sctx->send_root, sctx->cur_ino, NULL, NULL, - &left_mode, &left_uid, &left_gid, NULL); - if (ret < 0) - goto out; - - if (!sctx->parent_root || sctx->cur_inode_new) { - need_chown = 1; - if (!S_ISLNK(sctx->cur_inode_mode)) - need_chmod = 1; - } else { - ret = get_inode_info(sctx->parent_root, sctx->cur_ino, - NULL, NULL, &right_mode, &right_uid, - &right_gid, NULL); - if (ret < 0) - goto out; - - if (left_uid != right_uid || left_gid != right_gid) - need_chown = 1; - if (!S_ISLNK(sctx->cur_inode_mode) && left_mode != right_mode) - need_chmod = 1; - } - - if (S_ISREG(sctx->cur_inode_mode)) { - if (need_send_hole(sctx)) { - if (sctx->cur_inode_last_extent == (u64)-1 || - sctx->cur_inode_last_extent < - sctx->cur_inode_size) { - ret = get_last_extent(sctx, (u64)-1); - if (ret) - goto out; - } - if (sctx->cur_inode_last_extent < - sctx->cur_inode_size) { - ret = send_hole(sctx, sctx->cur_inode_size); - if (ret) - goto out; - } - } - ret = send_truncate(sctx, sctx->cur_ino, sctx->cur_inode_gen, - sctx->cur_inode_size); - if (ret < 0) - goto out; - } - - if (need_chown) { - ret = send_chown(sctx, sctx->cur_ino, sctx->cur_inode_gen, - left_uid, left_gid); - if (ret < 0) - goto out; - } - if (need_chmod) { - ret = send_chmod(sctx, sctx->cur_ino, sctx->cur_inode_gen, - left_mode); - if (ret < 0) - goto out; - } - - /* - * If other directory inodes depended on our current directory - * inode's move/rename, now do their move/rename operations. - */ - if (!is_waiting_for_move(sctx, sctx->cur_ino)) { - ret = apply_children_dir_moves(sctx); - if (ret) - goto out; - /* - * Need to send that every time, no matter if it actually - * changed between the two trees as we have done changes to - * the inode before. If our inode is a directory and it's - * waiting to be moved/renamed, we will send its utimes when - * it's moved/renamed, therefore we don't need to do it here. - */ - sctx->send_progress = sctx->cur_ino + 1; - ret = send_utimes(sctx, sctx->cur_ino, sctx->cur_inode_gen); - if (ret < 0) - goto out; - } - -out: - return ret; -} - -static int changed_inode(struct send_ctx *sctx, - enum btrfs_compare_tree_result result) -{ - int ret = 0; - struct btrfs_key *key = sctx->cmp_key; - struct btrfs_inode_item *left_ii = NULL; - struct btrfs_inode_item *right_ii = NULL; - u64 left_gen = 0; - u64 right_gen = 0; - - sctx->cur_ino = key->objectid; - sctx->cur_inode_new_gen = 0; - sctx->cur_inode_last_extent = (u64)-1; - - /* - * Set send_progress to current inode. This will tell all get_cur_xxx - * functions that the current inode's refs are not updated yet. Later, - * when process_recorded_refs is finished, it is set to cur_ino + 1. - */ - sctx->send_progress = sctx->cur_ino; - - if (result == BTRFS_COMPARE_TREE_NEW || - result == BTRFS_COMPARE_TREE_CHANGED) { - left_ii = btrfs_item_ptr(sctx->left_path->nodes[0], - sctx->left_path->slots[0], - struct btrfs_inode_item); - left_gen = btrfs_inode_generation(sctx->left_path->nodes[0], - left_ii); - } else { - right_ii = btrfs_item_ptr(sctx->right_path->nodes[0], - sctx->right_path->slots[0], - struct btrfs_inode_item); - right_gen = btrfs_inode_generation(sctx->right_path->nodes[0], - right_ii); - } - if (result == BTRFS_COMPARE_TREE_CHANGED) { - right_ii = btrfs_item_ptr(sctx->right_path->nodes[0], - sctx->right_path->slots[0], - struct btrfs_inode_item); - - right_gen = btrfs_inode_generation(sctx->right_path->nodes[0], - right_ii); - - /* - * The cur_ino = root dir case is special here. We can't treat - * the inode as deleted+reused because it would generate a - * stream that tries to delete/mkdir the root dir. - */ - if (left_gen != right_gen && - sctx->cur_ino != BTRFS_FIRST_FREE_OBJECTID) - sctx->cur_inode_new_gen = 1; - } - - if (result == BTRFS_COMPARE_TREE_NEW) { - sctx->cur_inode_gen = left_gen; - sctx->cur_inode_new = 1; - sctx->cur_inode_deleted = 0; - sctx->cur_inode_size = btrfs_inode_size( - sctx->left_path->nodes[0], left_ii); - sctx->cur_inode_mode = btrfs_inode_mode( - sctx->left_path->nodes[0], left_ii); - sctx->cur_inode_rdev = btrfs_inode_rdev( - sctx->left_path->nodes[0], left_ii); - if (sctx->cur_ino != BTRFS_FIRST_FREE_OBJECTID) - ret = send_create_inode_if_needed(sctx); - } else if (result == BTRFS_COMPARE_TREE_DELETED) { - sctx->cur_inode_gen = right_gen; - sctx->cur_inode_new = 0; - sctx->cur_inode_deleted = 1; - sctx->cur_inode_size = btrfs_inode_size( - sctx->right_path->nodes[0], right_ii); - sctx->cur_inode_mode = btrfs_inode_mode( - sctx->right_path->nodes[0], right_ii); - } else if (result == BTRFS_COMPARE_TREE_CHANGED) { - /* - * We need to do some special handling in case the inode was - * reported as changed with a changed generation number. This - * means that the original inode was deleted and new inode - * reused the same inum. So we have to treat the old inode as - * deleted and the new one as new. - */ - if (sctx->cur_inode_new_gen) { - /* - * First, process the inode as if it was deleted. - */ - sctx->cur_inode_gen = right_gen; - sctx->cur_inode_new = 0; - sctx->cur_inode_deleted = 1; - sctx->cur_inode_size = btrfs_inode_size( - sctx->right_path->nodes[0], right_ii); - sctx->cur_inode_mode = btrfs_inode_mode( - sctx->right_path->nodes[0], right_ii); - ret = process_all_refs(sctx, - BTRFS_COMPARE_TREE_DELETED); - if (ret < 0) - goto out; - - /* - * Now process the inode as if it was new. - */ - sctx->cur_inode_gen = left_gen; - sctx->cur_inode_new = 1; - sctx->cur_inode_deleted = 0; - sctx->cur_inode_size = btrfs_inode_size( - sctx->left_path->nodes[0], left_ii); - sctx->cur_inode_mode = btrfs_inode_mode( - sctx->left_path->nodes[0], left_ii); - sctx->cur_inode_rdev = btrfs_inode_rdev( - sctx->left_path->nodes[0], left_ii); - ret = send_create_inode_if_needed(sctx); - if (ret < 0) - goto out; - - ret = process_all_refs(sctx, BTRFS_COMPARE_TREE_NEW); - if (ret < 0) - goto out; - /* - * Advance send_progress now as we did not get into - * process_recorded_refs_if_needed in the new_gen case. - */ - sctx->send_progress = sctx->cur_ino + 1; - - /* - * Now process all extents and xattrs of the inode as if - * they were all new. - */ - ret = process_all_extents(sctx); - if (ret < 0) - goto out; - ret = process_all_new_xattrs(sctx); - if (ret < 0) - goto out; - } else { - sctx->cur_inode_gen = left_gen; - sctx->cur_inode_new = 0; - sctx->cur_inode_new_gen = 0; - sctx->cur_inode_deleted = 0; - sctx->cur_inode_size = btrfs_inode_size( - sctx->left_path->nodes[0], left_ii); - sctx->cur_inode_mode = btrfs_inode_mode( - sctx->left_path->nodes[0], left_ii); - } - } - -out: - return ret; -} - -/* - * We have to process new refs before deleted refs, but compare_trees gives us - * the new and deleted refs mixed. To fix this, we record the new/deleted refs - * first and later process them in process_recorded_refs. - * For the cur_inode_new_gen case, we skip recording completely because - * changed_inode did already initiate processing of refs. The reason for this is - * that in this case, compare_tree actually compares the refs of 2 different - * inodes. To fix this, process_all_refs is used in changed_inode to handle all - * refs of the right tree as deleted and all refs of the left tree as new. - */ -static int changed_ref(struct send_ctx *sctx, - enum btrfs_compare_tree_result result) -{ - int ret = 0; - - if (sctx->cur_ino != sctx->cmp_key->objectid) { - inconsistent_snapshot_error(sctx, result, "reference"); - return -EIO; - } - - if (!sctx->cur_inode_new_gen && - sctx->cur_ino != BTRFS_FIRST_FREE_OBJECTID) { - if (result == BTRFS_COMPARE_TREE_NEW) - ret = record_new_ref(sctx); - else if (result == BTRFS_COMPARE_TREE_DELETED) - ret = record_deleted_ref(sctx); - else if (result == BTRFS_COMPARE_TREE_CHANGED) - ret = record_changed_ref(sctx); - } - - return ret; -} - -/* - * Process new/deleted/changed xattrs. We skip processing in the - * cur_inode_new_gen case because changed_inode did already initiate processing - * of xattrs. The reason is the same as in changed_ref - */ -static int changed_xattr(struct send_ctx *sctx, - enum btrfs_compare_tree_result result) -{ - int ret = 0; - - if (sctx->cur_ino != sctx->cmp_key->objectid) { - inconsistent_snapshot_error(sctx, result, "xattr"); - return -EIO; - } - - if (!sctx->cur_inode_new_gen && !sctx->cur_inode_deleted) { - if (result == BTRFS_COMPARE_TREE_NEW) - ret = process_new_xattr(sctx); - else if (result == BTRFS_COMPARE_TREE_DELETED) - ret = process_deleted_xattr(sctx); - else if (result == BTRFS_COMPARE_TREE_CHANGED) - ret = process_changed_xattr(sctx); - } - - return ret; -} - -/* - * Process new/deleted/changed extents. We skip processing in the - * cur_inode_new_gen case because changed_inode did already initiate processing - * of extents. The reason is the same as in changed_ref - */ -static int changed_extent(struct send_ctx *sctx, - enum btrfs_compare_tree_result result) -{ - int ret = 0; - - if (sctx->cur_ino != sctx->cmp_key->objectid) { - - if (result == BTRFS_COMPARE_TREE_CHANGED) { - struct extent_buffer *leaf_l; - struct extent_buffer *leaf_r; - struct btrfs_file_extent_item *ei_l; - struct btrfs_file_extent_item *ei_r; - - leaf_l = sctx->left_path->nodes[0]; - leaf_r = sctx->right_path->nodes[0]; - ei_l = btrfs_item_ptr(leaf_l, - sctx->left_path->slots[0], - struct btrfs_file_extent_item); - ei_r = btrfs_item_ptr(leaf_r, - sctx->right_path->slots[0], - struct btrfs_file_extent_item); - - /* - * We may have found an extent item that has changed - * only its disk_bytenr field and the corresponding - * inode item was not updated. This case happens due to - * very specific timings during relocation when a leaf - * that contains file extent items is COWed while - * relocation is ongoing and its in the stage where it - * updates data pointers. So when this happens we can - * safely ignore it since we know it's the same extent, - * but just at different logical and physical locations - * (when an extent is fully replaced with a new one, we - * know the generation number must have changed too, - * since snapshot creation implies committing the current - * transaction, and the inode item must have been updated - * as well). - * This replacement of the disk_bytenr happens at - * relocation.c:replace_file_extents() through - * relocation.c:btrfs_reloc_cow_block(). - */ - if (btrfs_file_extent_generation(leaf_l, ei_l) == - btrfs_file_extent_generation(leaf_r, ei_r) && - btrfs_file_extent_ram_bytes(leaf_l, ei_l) == - btrfs_file_extent_ram_bytes(leaf_r, ei_r) && - btrfs_file_extent_compression(leaf_l, ei_l) == - btrfs_file_extent_compression(leaf_r, ei_r) && - btrfs_file_extent_encryption(leaf_l, ei_l) == - btrfs_file_extent_encryption(leaf_r, ei_r) && - btrfs_file_extent_other_encoding(leaf_l, ei_l) == - btrfs_file_extent_other_encoding(leaf_r, ei_r) && - btrfs_file_extent_type(leaf_l, ei_l) == - btrfs_file_extent_type(leaf_r, ei_r) && - btrfs_file_extent_disk_bytenr(leaf_l, ei_l) != - btrfs_file_extent_disk_bytenr(leaf_r, ei_r) && - btrfs_file_extent_disk_num_bytes(leaf_l, ei_l) == - btrfs_file_extent_disk_num_bytes(leaf_r, ei_r) && - btrfs_file_extent_offset(leaf_l, ei_l) == - btrfs_file_extent_offset(leaf_r, ei_r) && - btrfs_file_extent_num_bytes(leaf_l, ei_l) == - btrfs_file_extent_num_bytes(leaf_r, ei_r)) - return 0; - } - - inconsistent_snapshot_error(sctx, result, "extent"); - return -EIO; - } - - if (!sctx->cur_inode_new_gen && !sctx->cur_inode_deleted) { - if (result != BTRFS_COMPARE_TREE_DELETED) - ret = process_extent(sctx, sctx->left_path, - sctx->cmp_key); - } - - return ret; -} - -static int dir_changed(struct send_ctx *sctx, u64 dir) -{ - u64 orig_gen, new_gen; - int ret; - - ret = get_inode_info(sctx->send_root, dir, NULL, &new_gen, NULL, NULL, - NULL, NULL); - if (ret) - return ret; - - ret = get_inode_info(sctx->parent_root, dir, NULL, &orig_gen, NULL, - NULL, NULL, NULL); - if (ret) - return ret; - - return (orig_gen != new_gen) ? 1 : 0; -} - -static int compare_refs(struct send_ctx *sctx, struct btrfs_path *path, - struct btrfs_key *key) -{ - struct btrfs_inode_extref *extref; - struct extent_buffer *leaf; - u64 dirid = 0, last_dirid = 0; - unsigned long ptr; - u32 item_size; - u32 cur_offset = 0; - int ref_name_len; - int ret = 0; - - /* Easy case, just check this one dirid */ - if (key->type == BTRFS_INODE_REF_KEY) { - dirid = key->offset; - - ret = dir_changed(sctx, dirid); - goto out; - } - - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, path->slots[0]); - ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); - while (cur_offset < item_size) { - extref = (struct btrfs_inode_extref *)(ptr + - cur_offset); - dirid = btrfs_inode_extref_parent(leaf, extref); - ref_name_len = btrfs_inode_extref_name_len(leaf, extref); - cur_offset += ref_name_len + sizeof(*extref); - if (dirid == last_dirid) - continue; - ret = dir_changed(sctx, dirid); - if (ret) - break; - last_dirid = dirid; - } -out: - return ret; -} - -/* - * Updates compare related fields in sctx and simply forwards to the actual - * changed_xxx functions. - */ -static int changed_cb(struct btrfs_root *left_root, - struct btrfs_root *right_root, - struct btrfs_path *left_path, - struct btrfs_path *right_path, - struct btrfs_key *key, - enum btrfs_compare_tree_result result, - void *ctx) -{ - int ret = 0; - struct send_ctx *sctx = ctx; - - if (result == BTRFS_COMPARE_TREE_SAME) { - if (key->type == BTRFS_INODE_REF_KEY || - key->type == BTRFS_INODE_EXTREF_KEY) { - ret = compare_refs(sctx, left_path, key); - if (!ret) - return 0; - if (ret < 0) - return ret; - } else if (key->type == BTRFS_EXTENT_DATA_KEY) { - return maybe_send_hole(sctx, left_path, key); - } else { - return 0; - } - result = BTRFS_COMPARE_TREE_CHANGED; - ret = 0; - } - - sctx->left_path = left_path; - sctx->right_path = right_path; - sctx->cmp_key = key; - - ret = finish_inode_if_needed(sctx, 0); - if (ret < 0) - goto out; - - /* Ignore non-FS objects */ - if (key->objectid == BTRFS_FREE_INO_OBJECTID || - key->objectid == BTRFS_FREE_SPACE_OBJECTID) - goto out; - - if (key->type == BTRFS_INODE_ITEM_KEY) - ret = changed_inode(sctx, result); - else if (key->type == BTRFS_INODE_REF_KEY || - key->type == BTRFS_INODE_EXTREF_KEY) - ret = changed_ref(sctx, result); - else if (key->type == BTRFS_XATTR_ITEM_KEY) - ret = changed_xattr(sctx, result); - else if (key->type == BTRFS_EXTENT_DATA_KEY) - ret = changed_extent(sctx, result); - -out: - return ret; -} - -static int full_send_tree(struct send_ctx *sctx) -{ - int ret; - struct btrfs_root *send_root = sctx->send_root; - struct btrfs_key key; - struct btrfs_key found_key; - struct btrfs_path *path; - struct extent_buffer *eb; - int slot; - - path = alloc_path_for_send(); - if (!path) - return -ENOMEM; - - key.objectid = BTRFS_FIRST_FREE_OBJECTID; - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - - ret = btrfs_search_slot_for_read(send_root, &key, path, 1, 0); - if (ret < 0) - goto out; - if (ret) - goto out_finish; - - while (1) { - eb = path->nodes[0]; - slot = path->slots[0]; - btrfs_item_key_to_cpu(eb, &found_key, slot); - - ret = changed_cb(send_root, NULL, path, NULL, - &found_key, BTRFS_COMPARE_TREE_NEW, sctx); - if (ret < 0) - goto out; - - key.objectid = found_key.objectid; - key.type = found_key.type; - key.offset = found_key.offset + 1; - - ret = btrfs_next_item(send_root, path); - if (ret < 0) - goto out; - if (ret) { - ret = 0; - break; - } - } - -out_finish: - ret = finish_inode_if_needed(sctx, 1); - -out: - btrfs_free_path(path); - return ret; -} - -static int send_subvol(struct send_ctx *sctx) -{ - int ret; - - if (!(sctx->flags & BTRFS_SEND_FLAG_OMIT_STREAM_HEADER)) { - ret = send_header(sctx); - if (ret < 0) - goto out; - } - - ret = send_subvol_begin(sctx); - if (ret < 0) - goto out; - - if (sctx->parent_root) { - ret = btrfs_compare_trees(sctx->send_root, sctx->parent_root, - changed_cb, sctx); - if (ret < 0) - goto out; - ret = finish_inode_if_needed(sctx, 1); - if (ret < 0) - goto out; - } else { - ret = full_send_tree(sctx); - if (ret < 0) - goto out; - } - -out: - free_recorded_refs(sctx); - return ret; -} - -/* - * If orphan cleanup did remove any orphans from a root, it means the tree - * was modified and therefore the commit root is not the same as the current - * root anymore. This is a problem, because send uses the commit root and - * therefore can see inode items that don't exist in the current root anymore, - * and for example make calls to btrfs_iget, which will do tree lookups based - * on the current root and not on the commit root. Those lookups will fail, - * returning a -ESTALE error, and making send fail with that error. So make - * sure a send does not see any orphans we have just removed, and that it will - * see the same inodes regardless of whether a transaction commit happened - * before it started (meaning that the commit root will be the same as the - * current root) or not. - */ -static int ensure_commit_roots_uptodate(struct send_ctx *sctx) -{ - int i; - struct btrfs_trans_handle *trans = NULL; - -again: - if (sctx->parent_root && - sctx->parent_root->node != sctx->parent_root->commit_root) - goto commit_trans; - - for (i = 0; i < sctx->clone_roots_cnt; i++) - if (sctx->clone_roots[i].root->node != - sctx->clone_roots[i].root->commit_root) - goto commit_trans; - - if (trans) - return btrfs_end_transaction(trans, sctx->send_root); - - return 0; - -commit_trans: - /* Use any root, all fs roots will get their commit roots updated. */ - if (!trans) { - trans = btrfs_join_transaction(sctx->send_root); - if (IS_ERR(trans)) - return PTR_ERR(trans); - goto again; - } - - return btrfs_commit_transaction(trans, sctx->send_root); -} - -static void btrfs_root_dec_send_in_progress(struct btrfs_root* root) -{ - spin_lock(&root->root_item_lock); - root->send_in_progress--; - /* - * Not much left to do, we don't know why it's unbalanced and - * can't blindly reset it to 0. - */ - if (root->send_in_progress < 0) - btrfs_err(root->fs_info, - "send_in_progres unbalanced %d root %llu", - root->send_in_progress, root->root_key.objectid); - spin_unlock(&root->root_item_lock); -} - -long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_) -{ - int ret = 0; - struct btrfs_root *send_root; - struct btrfs_root *clone_root; - struct btrfs_fs_info *fs_info; - struct btrfs_ioctl_send_args *arg = NULL; - struct btrfs_key key; - struct send_ctx *sctx = NULL; - u32 i; - u64 *clone_sources_tmp = NULL; - int clone_sources_to_rollback = 0; - unsigned alloc_size; - int sort_clone_roots = 0; - int index; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - send_root = BTRFS_I(file_inode(mnt_file))->root; - fs_info = send_root->fs_info; - - /* - * The subvolume must remain read-only during send, protect against - * making it RW. This also protects against deletion. - */ - spin_lock(&send_root->root_item_lock); - send_root->send_in_progress++; - spin_unlock(&send_root->root_item_lock); - - /* - * This is done when we lookup the root, it should already be complete - * by the time we get here. - */ - WARN_ON(send_root->orphan_cleanup_state != ORPHAN_CLEANUP_DONE); - - /* - * Userspace tools do the checks and warn the user if it's - * not RO. - */ - if (!btrfs_root_readonly(send_root)) { - ret = -EPERM; - goto out; - } - - arg = memdup_user(arg_, sizeof(*arg)); - if (IS_ERR(arg)) { - ret = PTR_ERR(arg); - arg = NULL; - goto out; - } - - if (arg->clone_sources_count > - ULLONG_MAX / sizeof(*arg->clone_sources)) { - ret = -EINVAL; - goto out; - } - - if (!access_ok(VERIFY_READ, arg->clone_sources, - sizeof(*arg->clone_sources) * - arg->clone_sources_count)) { - ret = -EFAULT; - goto out; - } - - if (arg->flags & ~BTRFS_SEND_FLAG_MASK) { - ret = -EINVAL; - goto out; - } - - sctx = kzalloc(sizeof(struct send_ctx), GFP_KERNEL); - if (!sctx) { - ret = -ENOMEM; - goto out; - } - - INIT_LIST_HEAD(&sctx->new_refs); - INIT_LIST_HEAD(&sctx->deleted_refs); - INIT_RADIX_TREE(&sctx->name_cache, GFP_KERNEL); - INIT_LIST_HEAD(&sctx->name_cache_list); - - sctx->flags = arg->flags; - - sctx->send_filp = fget(arg->send_fd); - if (!sctx->send_filp) { - ret = -EBADF; - goto out; - } - - sctx->send_root = send_root; - /* - * Unlikely but possible, if the subvolume is marked for deletion but - * is slow to remove the directory entry, send can still be started - */ - if (btrfs_root_dead(sctx->send_root)) { - ret = -EPERM; - goto out; - } - - sctx->clone_roots_cnt = arg->clone_sources_count; - - sctx->send_max_size = BTRFS_SEND_BUF_SIZE; - sctx->send_buf = kmalloc(sctx->send_max_size, GFP_KERNEL | __GFP_NOWARN); - if (!sctx->send_buf) { - sctx->send_buf = vmalloc(sctx->send_max_size); - if (!sctx->send_buf) { - ret = -ENOMEM; - goto out; - } - } - - sctx->read_buf = kmalloc(BTRFS_SEND_READ_SIZE, GFP_KERNEL | __GFP_NOWARN); - if (!sctx->read_buf) { - sctx->read_buf = vmalloc(BTRFS_SEND_READ_SIZE); - if (!sctx->read_buf) { - ret = -ENOMEM; - goto out; - } - } - - sctx->pending_dir_moves = RB_ROOT; - sctx->waiting_dir_moves = RB_ROOT; - sctx->orphan_dirs = RB_ROOT; - - alloc_size = sizeof(struct clone_root) * (arg->clone_sources_count + 1); - - sctx->clone_roots = kzalloc(alloc_size, GFP_KERNEL | __GFP_NOWARN); - if (!sctx->clone_roots) { - sctx->clone_roots = vzalloc(alloc_size); - if (!sctx->clone_roots) { - ret = -ENOMEM; - goto out; - } - } - - alloc_size = arg->clone_sources_count * sizeof(*arg->clone_sources); - - if (arg->clone_sources_count) { - clone_sources_tmp = kmalloc(alloc_size, GFP_KERNEL | __GFP_NOWARN); - if (!clone_sources_tmp) { - clone_sources_tmp = vmalloc(alloc_size); - if (!clone_sources_tmp) { - ret = -ENOMEM; - goto out; - } - } - - ret = copy_from_user(clone_sources_tmp, arg->clone_sources, - alloc_size); - if (ret) { - ret = -EFAULT; - goto out; - } - - for (i = 0; i < arg->clone_sources_count; i++) { - key.objectid = clone_sources_tmp[i]; - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = (u64)-1; - - index = srcu_read_lock(&fs_info->subvol_srcu); - - clone_root = btrfs_read_fs_root_no_name(fs_info, &key); - if (IS_ERR(clone_root)) { - srcu_read_unlock(&fs_info->subvol_srcu, index); - ret = PTR_ERR(clone_root); - goto out; - } - spin_lock(&clone_root->root_item_lock); - if (!btrfs_root_readonly(clone_root) || - btrfs_root_dead(clone_root)) { - spin_unlock(&clone_root->root_item_lock); - srcu_read_unlock(&fs_info->subvol_srcu, index); - ret = -EPERM; - goto out; - } - clone_root->send_in_progress++; - spin_unlock(&clone_root->root_item_lock); - srcu_read_unlock(&fs_info->subvol_srcu, index); - - sctx->clone_roots[i].root = clone_root; - clone_sources_to_rollback = i + 1; - } - kvfree(clone_sources_tmp); - clone_sources_tmp = NULL; - } - - if (arg->parent_root) { - key.objectid = arg->parent_root; - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = (u64)-1; - - index = srcu_read_lock(&fs_info->subvol_srcu); - - sctx->parent_root = btrfs_read_fs_root_no_name(fs_info, &key); - if (IS_ERR(sctx->parent_root)) { - srcu_read_unlock(&fs_info->subvol_srcu, index); - ret = PTR_ERR(sctx->parent_root); - goto out; - } - - spin_lock(&sctx->parent_root->root_item_lock); - sctx->parent_root->send_in_progress++; - if (!btrfs_root_readonly(sctx->parent_root) || - btrfs_root_dead(sctx->parent_root)) { - spin_unlock(&sctx->parent_root->root_item_lock); - srcu_read_unlock(&fs_info->subvol_srcu, index); - ret = -EPERM; - goto out; - } - spin_unlock(&sctx->parent_root->root_item_lock); - - srcu_read_unlock(&fs_info->subvol_srcu, index); - } - - /* - * Clones from send_root are allowed, but only if the clone source - * is behind the current send position. This is checked while searching - * for possible clone sources. - */ - sctx->clone_roots[sctx->clone_roots_cnt++].root = sctx->send_root; - - /* We do a bsearch later */ - sort(sctx->clone_roots, sctx->clone_roots_cnt, - sizeof(*sctx->clone_roots), __clone_root_cmp_sort, - NULL); - sort_clone_roots = 1; - - ret = ensure_commit_roots_uptodate(sctx); - if (ret) - goto out; - - current->journal_info = BTRFS_SEND_TRANS_STUB; - ret = send_subvol(sctx); - current->journal_info = NULL; - if (ret < 0) - goto out; - - if (!(sctx->flags & BTRFS_SEND_FLAG_OMIT_END_CMD)) { - ret = begin_cmd(sctx, BTRFS_SEND_C_END); - if (ret < 0) - goto out; - ret = send_cmd(sctx); - if (ret < 0) - goto out; - } - -out: - WARN_ON(sctx && !ret && !RB_EMPTY_ROOT(&sctx->pending_dir_moves)); - while (sctx && !RB_EMPTY_ROOT(&sctx->pending_dir_moves)) { - struct rb_node *n; - struct pending_dir_move *pm; - - n = rb_first(&sctx->pending_dir_moves); - pm = rb_entry(n, struct pending_dir_move, node); - while (!list_empty(&pm->list)) { - struct pending_dir_move *pm2; - - pm2 = list_first_entry(&pm->list, - struct pending_dir_move, list); - free_pending_move(sctx, pm2); - } - free_pending_move(sctx, pm); - } - - WARN_ON(sctx && !ret && !RB_EMPTY_ROOT(&sctx->waiting_dir_moves)); - while (sctx && !RB_EMPTY_ROOT(&sctx->waiting_dir_moves)) { - struct rb_node *n; - struct waiting_dir_move *dm; - - n = rb_first(&sctx->waiting_dir_moves); - dm = rb_entry(n, struct waiting_dir_move, node); - rb_erase(&dm->node, &sctx->waiting_dir_moves); - kfree(dm); - } - - WARN_ON(sctx && !ret && !RB_EMPTY_ROOT(&sctx->orphan_dirs)); - while (sctx && !RB_EMPTY_ROOT(&sctx->orphan_dirs)) { - struct rb_node *n; - struct orphan_dir_info *odi; - - n = rb_first(&sctx->orphan_dirs); - odi = rb_entry(n, struct orphan_dir_info, node); - free_orphan_dir_info(sctx, odi); - } - - if (sort_clone_roots) { - for (i = 0; i < sctx->clone_roots_cnt; i++) - btrfs_root_dec_send_in_progress( - sctx->clone_roots[i].root); - } else { - for (i = 0; sctx && i < clone_sources_to_rollback; i++) - btrfs_root_dec_send_in_progress( - sctx->clone_roots[i].root); - - btrfs_root_dec_send_in_progress(send_root); - } - if (sctx && !IS_ERR_OR_NULL(sctx->parent_root)) - btrfs_root_dec_send_in_progress(sctx->parent_root); - - kfree(arg); - kvfree(clone_sources_tmp); - - if (sctx) { - if (sctx->send_filp) - fput(sctx->send_filp); - - kvfree(sctx->clone_roots); - kvfree(sctx->send_buf); - kvfree(sctx->read_buf); - - name_cache_free(sctx); - - kfree(sctx); - } - - return ret; -} diff --git a/src/linux/fs/btrfs/send.h b/src/linux/fs/btrfs/send.h deleted file mode 100644 index 02e0016..0000000 --- a/src/linux/fs/btrfs/send.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2012 Alexander Block. All rights reserved. - * Copyright (C) 2012 STRATO. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include "ctree.h" - -#define BTRFS_SEND_STREAM_MAGIC "btrfs-stream" -#define BTRFS_SEND_STREAM_VERSION 1 - -#define BTRFS_SEND_BUF_SIZE SZ_64K -#define BTRFS_SEND_READ_SIZE (48 * SZ_1K) - -enum btrfs_tlv_type { - BTRFS_TLV_U8, - BTRFS_TLV_U16, - BTRFS_TLV_U32, - BTRFS_TLV_U64, - BTRFS_TLV_BINARY, - BTRFS_TLV_STRING, - BTRFS_TLV_UUID, - BTRFS_TLV_TIMESPEC, -}; - -struct btrfs_stream_header { - char magic[sizeof(BTRFS_SEND_STREAM_MAGIC)]; - __le32 version; -} __attribute__ ((__packed__)); - -struct btrfs_cmd_header { - /* len excluding the header */ - __le32 len; - __le16 cmd; - /* crc including the header with zero crc field */ - __le32 crc; -} __attribute__ ((__packed__)); - -struct btrfs_tlv_header { - __le16 tlv_type; - /* len excluding the header */ - __le16 tlv_len; -} __attribute__ ((__packed__)); - -/* commands */ -enum btrfs_send_cmd { - BTRFS_SEND_C_UNSPEC, - - BTRFS_SEND_C_SUBVOL, - BTRFS_SEND_C_SNAPSHOT, - - BTRFS_SEND_C_MKFILE, - BTRFS_SEND_C_MKDIR, - BTRFS_SEND_C_MKNOD, - BTRFS_SEND_C_MKFIFO, - BTRFS_SEND_C_MKSOCK, - BTRFS_SEND_C_SYMLINK, - - BTRFS_SEND_C_RENAME, - BTRFS_SEND_C_LINK, - BTRFS_SEND_C_UNLINK, - BTRFS_SEND_C_RMDIR, - - BTRFS_SEND_C_SET_XATTR, - BTRFS_SEND_C_REMOVE_XATTR, - - BTRFS_SEND_C_WRITE, - BTRFS_SEND_C_CLONE, - - BTRFS_SEND_C_TRUNCATE, - BTRFS_SEND_C_CHMOD, - BTRFS_SEND_C_CHOWN, - BTRFS_SEND_C_UTIMES, - - BTRFS_SEND_C_END, - BTRFS_SEND_C_UPDATE_EXTENT, - __BTRFS_SEND_C_MAX, -}; -#define BTRFS_SEND_C_MAX (__BTRFS_SEND_C_MAX - 1) - -/* attributes in send stream */ -enum { - BTRFS_SEND_A_UNSPEC, - - BTRFS_SEND_A_UUID, - BTRFS_SEND_A_CTRANSID, - - BTRFS_SEND_A_INO, - BTRFS_SEND_A_SIZE, - BTRFS_SEND_A_MODE, - BTRFS_SEND_A_UID, - BTRFS_SEND_A_GID, - BTRFS_SEND_A_RDEV, - BTRFS_SEND_A_CTIME, - BTRFS_SEND_A_MTIME, - BTRFS_SEND_A_ATIME, - BTRFS_SEND_A_OTIME, - - BTRFS_SEND_A_XATTR_NAME, - BTRFS_SEND_A_XATTR_DATA, - - BTRFS_SEND_A_PATH, - BTRFS_SEND_A_PATH_TO, - BTRFS_SEND_A_PATH_LINK, - - BTRFS_SEND_A_FILE_OFFSET, - BTRFS_SEND_A_DATA, - - BTRFS_SEND_A_CLONE_UUID, - BTRFS_SEND_A_CLONE_CTRANSID, - BTRFS_SEND_A_CLONE_PATH, - BTRFS_SEND_A_CLONE_OFFSET, - BTRFS_SEND_A_CLONE_LEN, - - __BTRFS_SEND_A_MAX, -}; -#define BTRFS_SEND_A_MAX (__BTRFS_SEND_A_MAX - 1) - -#ifdef __KERNEL__ -long btrfs_ioctl_send(struct file *mnt_file, void __user *arg); -#endif diff --git a/src/linux/fs/btrfs/struct-funcs.c b/src/linux/fs/btrfs/struct-funcs.c deleted file mode 100644 index 875c757..0000000 --- a/src/linux/fs/btrfs/struct-funcs.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include - -#include "ctree.h" - -static inline u8 get_unaligned_le8(const void *p) -{ - return *(u8 *)p; -} - -static inline void put_unaligned_le8(u8 val, void *p) -{ - *(u8 *)p = val; -} - -/* - * this is some deeply nasty code. - * - * The end result is that anyone who #includes ctree.h gets a - * declaration for the btrfs_set_foo functions and btrfs_foo functions, - * which are wrappers of btrfs_set_token_#bits functions and - * btrfs_get_token_#bits functions, which are defined in this file. - * - * These setget functions do all the extent_buffer related mapping - * required to efficiently read and write specific fields in the extent - * buffers. Every pointer to metadata items in btrfs is really just - * an unsigned long offset into the extent buffer which has been - * cast to a specific type. This gives us all the gcc type checking. - * - * The extent buffer api is used to do the page spanning work required to - * have a metadata blocksize different from the page size. - */ - -#define DEFINE_BTRFS_SETGET_BITS(bits) \ -u##bits btrfs_get_token_##bits(struct extent_buffer *eb, void *ptr, \ - unsigned long off, \ - struct btrfs_map_token *token) \ -{ \ - unsigned long part_offset = (unsigned long)ptr; \ - unsigned long offset = part_offset + off; \ - void *p; \ - int err; \ - char *kaddr; \ - unsigned long map_start; \ - unsigned long map_len; \ - int size = sizeof(u##bits); \ - u##bits res; \ - \ - if (token && token->kaddr && token->offset <= offset && \ - token->eb == eb && \ - (token->offset + PAGE_SIZE >= offset + size)) { \ - kaddr = token->kaddr; \ - p = kaddr + part_offset - token->offset; \ - res = get_unaligned_le##bits(p + off); \ - return res; \ - } \ - err = map_private_extent_buffer(eb, offset, size, \ - &kaddr, &map_start, &map_len); \ - if (err) { \ - __le##bits leres; \ - \ - read_extent_buffer(eb, &leres, offset, size); \ - return le##bits##_to_cpu(leres); \ - } \ - p = kaddr + part_offset - map_start; \ - res = get_unaligned_le##bits(p + off); \ - if (token) { \ - token->kaddr = kaddr; \ - token->offset = map_start; \ - token->eb = eb; \ - } \ - return res; \ -} \ -void btrfs_set_token_##bits(struct extent_buffer *eb, \ - void *ptr, unsigned long off, u##bits val, \ - struct btrfs_map_token *token) \ -{ \ - unsigned long part_offset = (unsigned long)ptr; \ - unsigned long offset = part_offset + off; \ - void *p; \ - int err; \ - char *kaddr; \ - unsigned long map_start; \ - unsigned long map_len; \ - int size = sizeof(u##bits); \ - \ - if (token && token->kaddr && token->offset <= offset && \ - token->eb == eb && \ - (token->offset + PAGE_SIZE >= offset + size)) { \ - kaddr = token->kaddr; \ - p = kaddr + part_offset - token->offset; \ - put_unaligned_le##bits(val, p + off); \ - return; \ - } \ - err = map_private_extent_buffer(eb, offset, size, \ - &kaddr, &map_start, &map_len); \ - if (err) { \ - __le##bits val2; \ - \ - val2 = cpu_to_le##bits(val); \ - write_extent_buffer(eb, &val2, offset, size); \ - return; \ - } \ - p = kaddr + part_offset - map_start; \ - put_unaligned_le##bits(val, p + off); \ - if (token) { \ - token->kaddr = kaddr; \ - token->offset = map_start; \ - token->eb = eb; \ - } \ -} - -DEFINE_BTRFS_SETGET_BITS(8) -DEFINE_BTRFS_SETGET_BITS(16) -DEFINE_BTRFS_SETGET_BITS(32) -DEFINE_BTRFS_SETGET_BITS(64) - -void btrfs_node_key(struct extent_buffer *eb, - struct btrfs_disk_key *disk_key, int nr) -{ - unsigned long ptr = btrfs_node_key_ptr_offset(nr); - read_eb_member(eb, (struct btrfs_key_ptr *)ptr, - struct btrfs_key_ptr, key, disk_key); -} diff --git a/src/linux/fs/btrfs/super.c b/src/linux/fs/btrfs/super.c deleted file mode 100644 index 74ed5aa..0000000 --- a/src/linux/fs/btrfs/super.c +++ /dev/null @@ -1,2493 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#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 "delayed-inode.h" -#include "ctree.h" -#include "disk-io.h" -#include "transaction.h" -#include "btrfs_inode.h" -#include "print-tree.h" -#include "hash.h" -#include "props.h" -#include "xattr.h" -#include "volumes.h" -#include "export.h" -#include "compression.h" -#include "rcu-string.h" -#include "dev-replace.h" -#include "free-space-cache.h" -#include "backref.h" -#include "tests/btrfs-tests.h" - -#include "qgroup.h" -#define CREATE_TRACE_POINTS -#include - -static const struct super_operations btrfs_super_ops; -static struct file_system_type btrfs_fs_type; - -static int btrfs_remount(struct super_block *sb, int *flags, char *data); - -const char *btrfs_decode_error(int errno) -{ - char *errstr = "unknown"; - - switch (errno) { - case -EIO: - errstr = "IO failure"; - break; - case -ENOMEM: - errstr = "Out of memory"; - break; - case -EROFS: - errstr = "Readonly filesystem"; - break; - case -EEXIST: - errstr = "Object already exists"; - break; - case -ENOSPC: - errstr = "No space left"; - break; - case -ENOENT: - errstr = "No such entry"; - break; - } - - return errstr; -} - -/* btrfs handle error by forcing the filesystem readonly */ -static void btrfs_handle_error(struct btrfs_fs_info *fs_info) -{ - struct super_block *sb = fs_info->sb; - - if (sb->s_flags & MS_RDONLY) - return; - - if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) { - sb->s_flags |= MS_RDONLY; - btrfs_info(fs_info, "forced readonly"); - /* - * Note that a running device replace operation is not - * canceled here although there is no way to update - * the progress. It would add the risk of a deadlock, - * therefore the canceling is omitted. The only penalty - * is that some I/O remains active until the procedure - * completes. The next time when the filesystem is - * mounted writeable again, the device replace - * operation continues. - */ - } -} - -/* - * __btrfs_handle_fs_error decodes expected errors from the caller and - * invokes the approciate error response. - */ -__cold -void __btrfs_handle_fs_error(struct btrfs_fs_info *fs_info, const char *function, - unsigned int line, int errno, const char *fmt, ...) -{ - struct super_block *sb = fs_info->sb; -#ifdef CONFIG_PRINTK - const char *errstr; -#endif - - /* - * Special case: if the error is EROFS, and we're already - * under MS_RDONLY, then it is safe here. - */ - if (errno == -EROFS && (sb->s_flags & MS_RDONLY)) - return; - -#ifdef CONFIG_PRINTK - errstr = btrfs_decode_error(errno); - if (fmt) { - struct va_format vaf; - va_list args; - - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; - - pr_crit("BTRFS: error (device %s) in %s:%d: errno=%d %s (%pV)\n", - sb->s_id, function, line, errno, errstr, &vaf); - va_end(args); - } else { - pr_crit("BTRFS: error (device %s) in %s:%d: errno=%d %s\n", - sb->s_id, function, line, errno, errstr); - } -#endif - - /* - * Today we only save the error info to memory. Long term we'll - * also send it down to the disk - */ - set_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state); - - /* Don't go through full error handling during mount */ - if (sb->s_flags & MS_BORN) - btrfs_handle_error(fs_info); -} - -#ifdef CONFIG_PRINTK -static const char * const logtypes[] = { - "emergency", - "alert", - "critical", - "error", - "warning", - "notice", - "info", - "debug", -}; - - -/* - * Use one ratelimit state per log level so that a flood of less important - * messages doesn't cause more important ones to be dropped. - */ -static struct ratelimit_state printk_limits[] = { - RATELIMIT_STATE_INIT(printk_limits[0], DEFAULT_RATELIMIT_INTERVAL, 100), - RATELIMIT_STATE_INIT(printk_limits[1], DEFAULT_RATELIMIT_INTERVAL, 100), - RATELIMIT_STATE_INIT(printk_limits[2], DEFAULT_RATELIMIT_INTERVAL, 100), - RATELIMIT_STATE_INIT(printk_limits[3], DEFAULT_RATELIMIT_INTERVAL, 100), - RATELIMIT_STATE_INIT(printk_limits[4], DEFAULT_RATELIMIT_INTERVAL, 100), - RATELIMIT_STATE_INIT(printk_limits[5], DEFAULT_RATELIMIT_INTERVAL, 100), - RATELIMIT_STATE_INIT(printk_limits[6], DEFAULT_RATELIMIT_INTERVAL, 100), - RATELIMIT_STATE_INIT(printk_limits[7], DEFAULT_RATELIMIT_INTERVAL, 100), -}; - -void btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...) -{ - struct super_block *sb = fs_info->sb; - char lvl[4]; - struct va_format vaf; - va_list args; - const char *type = logtypes[4]; - int kern_level; - struct ratelimit_state *ratelimit; - - va_start(args, fmt); - - kern_level = printk_get_level(fmt); - if (kern_level) { - size_t size = printk_skip_level(fmt) - fmt; - memcpy(lvl, fmt, size); - lvl[size] = '\0'; - fmt += size; - type = logtypes[kern_level - '0']; - ratelimit = &printk_limits[kern_level - '0']; - } else { - *lvl = '\0'; - /* Default to debug output */ - ratelimit = &printk_limits[7]; - } - - vaf.fmt = fmt; - vaf.va = &args; - - if (__ratelimit(ratelimit)) - printk("%sBTRFS %s (device %s): %pV\n", lvl, type, sb->s_id, &vaf); - - va_end(args); -} -#endif - -/* - * We only mark the transaction aborted and then set the file system read-only. - * This will prevent new transactions from starting or trying to join this - * one. - * - * This means that error recovery at the call site is limited to freeing - * any local memory allocations and passing the error code up without - * further cleanup. The transaction should complete as it normally would - * in the call path but will return -EIO. - * - * We'll complete the cleanup in btrfs_end_transaction and - * btrfs_commit_transaction. - */ -__cold -void __btrfs_abort_transaction(struct btrfs_trans_handle *trans, - const char *function, - unsigned int line, int errno) -{ - struct btrfs_fs_info *fs_info = trans->fs_info; - - trans->aborted = errno; - /* Nothing used. The other threads that have joined this - * transaction may be able to continue. */ - if (!trans->dirty && list_empty(&trans->new_bgs)) { - const char *errstr; - - errstr = btrfs_decode_error(errno); - btrfs_warn(fs_info, - "%s:%d: Aborting unused transaction(%s).", - function, line, errstr); - return; - } - ACCESS_ONCE(trans->transaction->aborted) = errno; - /* Wake up anybody who may be waiting on this transaction */ - wake_up(&fs_info->transaction_wait); - wake_up(&fs_info->transaction_blocked_wait); - __btrfs_handle_fs_error(fs_info, function, line, errno, NULL); -} -/* - * __btrfs_panic decodes unexpected, fatal errors from the caller, - * issues an alert, and either panics or BUGs, depending on mount options. - */ -__cold -void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function, - unsigned int line, int errno, const char *fmt, ...) -{ - char *s_id = ""; - const char *errstr; - struct va_format vaf = { .fmt = fmt }; - va_list args; - - if (fs_info) - s_id = fs_info->sb->s_id; - - va_start(args, fmt); - vaf.va = &args; - - errstr = btrfs_decode_error(errno); - if (fs_info && (fs_info->mount_opt & BTRFS_MOUNT_PANIC_ON_FATAL_ERROR)) - panic(KERN_CRIT "BTRFS panic (device %s) in %s:%d: %pV (errno=%d %s)\n", - s_id, function, line, &vaf, errno, errstr); - - btrfs_crit(fs_info, "panic in %s:%d: %pV (errno=%d %s)", - function, line, &vaf, errno, errstr); - va_end(args); - /* Caller calls BUG() */ -} - -static void btrfs_put_super(struct super_block *sb) -{ - close_ctree(btrfs_sb(sb)->tree_root); -} - -enum { - Opt_degraded, Opt_subvol, Opt_subvolid, Opt_device, Opt_nodatasum, - Opt_nodatacow, Opt_max_inline, Opt_alloc_start, Opt_nobarrier, Opt_ssd, - Opt_nossd, Opt_ssd_spread, Opt_thread_pool, Opt_noacl, Opt_compress, - Opt_compress_type, Opt_compress_force, Opt_compress_force_type, - Opt_notreelog, Opt_ratio, Opt_flushoncommit, Opt_discard, - Opt_space_cache, Opt_space_cache_version, Opt_clear_cache, - Opt_user_subvol_rm_allowed, Opt_enospc_debug, Opt_subvolrootid, - Opt_defrag, Opt_inode_cache, Opt_no_space_cache, Opt_recovery, - Opt_skip_balance, Opt_check_integrity, - Opt_check_integrity_including_extent_data, - Opt_check_integrity_print_mask, Opt_fatal_errors, Opt_rescan_uuid_tree, - Opt_commit_interval, Opt_barrier, Opt_nodefrag, Opt_nodiscard, - Opt_noenospc_debug, Opt_noflushoncommit, Opt_acl, Opt_datacow, - Opt_datasum, Opt_treelog, Opt_noinode_cache, Opt_usebackuproot, - Opt_nologreplay, Opt_norecovery, -#ifdef CONFIG_BTRFS_DEBUG - Opt_fragment_data, Opt_fragment_metadata, Opt_fragment_all, -#endif - Opt_err, -}; - -static const match_table_t tokens = { - {Opt_degraded, "degraded"}, - {Opt_subvol, "subvol=%s"}, - {Opt_subvolid, "subvolid=%s"}, - {Opt_device, "device=%s"}, - {Opt_nodatasum, "nodatasum"}, - {Opt_datasum, "datasum"}, - {Opt_nodatacow, "nodatacow"}, - {Opt_datacow, "datacow"}, - {Opt_nobarrier, "nobarrier"}, - {Opt_barrier, "barrier"}, - {Opt_max_inline, "max_inline=%s"}, - {Opt_alloc_start, "alloc_start=%s"}, - {Opt_thread_pool, "thread_pool=%d"}, - {Opt_compress, "compress"}, - {Opt_compress_type, "compress=%s"}, - {Opt_compress_force, "compress-force"}, - {Opt_compress_force_type, "compress-force=%s"}, - {Opt_ssd, "ssd"}, - {Opt_ssd_spread, "ssd_spread"}, - {Opt_nossd, "nossd"}, - {Opt_acl, "acl"}, - {Opt_noacl, "noacl"}, - {Opt_notreelog, "notreelog"}, - {Opt_treelog, "treelog"}, - {Opt_nologreplay, "nologreplay"}, - {Opt_norecovery, "norecovery"}, - {Opt_flushoncommit, "flushoncommit"}, - {Opt_noflushoncommit, "noflushoncommit"}, - {Opt_ratio, "metadata_ratio=%d"}, - {Opt_discard, "discard"}, - {Opt_nodiscard, "nodiscard"}, - {Opt_space_cache, "space_cache"}, - {Opt_space_cache_version, "space_cache=%s"}, - {Opt_clear_cache, "clear_cache"}, - {Opt_user_subvol_rm_allowed, "user_subvol_rm_allowed"}, - {Opt_enospc_debug, "enospc_debug"}, - {Opt_noenospc_debug, "noenospc_debug"}, - {Opt_subvolrootid, "subvolrootid=%d"}, - {Opt_defrag, "autodefrag"}, - {Opt_nodefrag, "noautodefrag"}, - {Opt_inode_cache, "inode_cache"}, - {Opt_noinode_cache, "noinode_cache"}, - {Opt_no_space_cache, "nospace_cache"}, - {Opt_recovery, "recovery"}, /* deprecated */ - {Opt_usebackuproot, "usebackuproot"}, - {Opt_skip_balance, "skip_balance"}, - {Opt_check_integrity, "check_int"}, - {Opt_check_integrity_including_extent_data, "check_int_data"}, - {Opt_check_integrity_print_mask, "check_int_print_mask=%d"}, - {Opt_rescan_uuid_tree, "rescan_uuid_tree"}, - {Opt_fatal_errors, "fatal_errors=%s"}, - {Opt_commit_interval, "commit=%d"}, -#ifdef CONFIG_BTRFS_DEBUG - {Opt_fragment_data, "fragment=data"}, - {Opt_fragment_metadata, "fragment=metadata"}, - {Opt_fragment_all, "fragment=all"}, -#endif - {Opt_err, NULL}, -}; - -/* - * Regular mount options parser. Everything that is needed only when - * reading in a new superblock is parsed here. - * XXX JDM: This needs to be cleaned up for remount. - */ -int btrfs_parse_options(struct btrfs_root *root, char *options, - unsigned long new_flags) -{ - struct btrfs_fs_info *info = root->fs_info; - substring_t args[MAX_OPT_ARGS]; - char *p, *num, *orig = NULL; - u64 cache_gen; - int intarg; - int ret = 0; - char *compress_type; - bool compress_force = false; - enum btrfs_compression_type saved_compress_type; - bool saved_compress_force; - int no_compress = 0; - - cache_gen = btrfs_super_cache_generation(root->fs_info->super_copy); - if (btrfs_fs_compat_ro(root->fs_info, FREE_SPACE_TREE)) - btrfs_set_opt(info->mount_opt, FREE_SPACE_TREE); - else if (cache_gen) - btrfs_set_opt(info->mount_opt, SPACE_CACHE); - - /* - * Even the options are empty, we still need to do extra check - * against new flags - */ - if (!options) - goto check; - - /* - * strsep changes the string, duplicate it because parse_options - * gets called twice - */ - options = kstrdup(options, GFP_NOFS); - if (!options) - return -ENOMEM; - - orig = options; - - while ((p = strsep(&options, ",")) != NULL) { - int token; - if (!*p) - continue; - - token = match_token(p, tokens, args); - switch (token) { - case Opt_degraded: - btrfs_info(root->fs_info, "allowing degraded mounts"); - btrfs_set_opt(info->mount_opt, DEGRADED); - break; - case Opt_subvol: - case Opt_subvolid: - case Opt_subvolrootid: - case Opt_device: - /* - * These are parsed by btrfs_parse_early_options - * and can be happily ignored here. - */ - break; - case Opt_nodatasum: - btrfs_set_and_info(info, NODATASUM, - "setting nodatasum"); - break; - case Opt_datasum: - if (btrfs_test_opt(info, NODATASUM)) { - if (btrfs_test_opt(info, NODATACOW)) - btrfs_info(root->fs_info, - "setting datasum, datacow enabled"); - else - btrfs_info(root->fs_info, - "setting datasum"); - } - btrfs_clear_opt(info->mount_opt, NODATACOW); - btrfs_clear_opt(info->mount_opt, NODATASUM); - break; - case Opt_nodatacow: - if (!btrfs_test_opt(info, NODATACOW)) { - if (!btrfs_test_opt(info, COMPRESS) || - !btrfs_test_opt(info, FORCE_COMPRESS)) { - btrfs_info(root->fs_info, - "setting nodatacow, compression disabled"); - } else { - btrfs_info(root->fs_info, - "setting nodatacow"); - } - } - btrfs_clear_opt(info->mount_opt, COMPRESS); - btrfs_clear_opt(info->mount_opt, FORCE_COMPRESS); - btrfs_set_opt(info->mount_opt, NODATACOW); - btrfs_set_opt(info->mount_opt, NODATASUM); - break; - case Opt_datacow: - btrfs_clear_and_info(info, NODATACOW, - "setting datacow"); - break; - case Opt_compress_force: - case Opt_compress_force_type: - compress_force = true; - /* Fallthrough */ - case Opt_compress: - case Opt_compress_type: - saved_compress_type = btrfs_test_opt(info, - COMPRESS) ? - info->compress_type : BTRFS_COMPRESS_NONE; - saved_compress_force = - btrfs_test_opt(info, FORCE_COMPRESS); - if (token == Opt_compress || - token == Opt_compress_force || - strcmp(args[0].from, "zlib") == 0) { - compress_type = "zlib"; - info->compress_type = BTRFS_COMPRESS_ZLIB; - btrfs_set_opt(info->mount_opt, COMPRESS); - btrfs_clear_opt(info->mount_opt, NODATACOW); - btrfs_clear_opt(info->mount_opt, NODATASUM); - no_compress = 0; - } else if (strcmp(args[0].from, "lzo") == 0) { - compress_type = "lzo"; - info->compress_type = BTRFS_COMPRESS_LZO; - btrfs_set_opt(info->mount_opt, COMPRESS); - btrfs_clear_opt(info->mount_opt, NODATACOW); - btrfs_clear_opt(info->mount_opt, NODATASUM); - btrfs_set_fs_incompat(info, COMPRESS_LZO); - no_compress = 0; - } else if (strncmp(args[0].from, "no", 2) == 0) { - compress_type = "no"; - btrfs_clear_opt(info->mount_opt, COMPRESS); - btrfs_clear_opt(info->mount_opt, FORCE_COMPRESS); - compress_force = false; - no_compress++; - } else { - ret = -EINVAL; - goto out; - } - - if (compress_force) { - btrfs_set_opt(info->mount_opt, FORCE_COMPRESS); - } else { - /* - * If we remount from compress-force=xxx to - * compress=xxx, we need clear FORCE_COMPRESS - * flag, otherwise, there is no way for users - * to disable forcible compression separately. - */ - btrfs_clear_opt(info->mount_opt, FORCE_COMPRESS); - } - if ((btrfs_test_opt(info, COMPRESS) && - (info->compress_type != saved_compress_type || - compress_force != saved_compress_force)) || - (!btrfs_test_opt(info, COMPRESS) && - no_compress == 1)) { - btrfs_info(root->fs_info, - "%s %s compression", - (compress_force) ? "force" : "use", - compress_type); - } - compress_force = false; - break; - case Opt_ssd: - btrfs_set_and_info(info, SSD, - "use ssd allocation scheme"); - break; - case Opt_ssd_spread: - btrfs_set_and_info(info, SSD_SPREAD, - "use spread ssd allocation scheme"); - btrfs_set_opt(info->mount_opt, SSD); - break; - case Opt_nossd: - btrfs_set_and_info(info, NOSSD, - "not using ssd allocation scheme"); - btrfs_clear_opt(info->mount_opt, SSD); - break; - case Opt_barrier: - btrfs_clear_and_info(info, NOBARRIER, - "turning on barriers"); - break; - case Opt_nobarrier: - btrfs_set_and_info(info, NOBARRIER, - "turning off barriers"); - break; - case Opt_thread_pool: - ret = match_int(&args[0], &intarg); - if (ret) { - goto out; - } else if (intarg > 0) { - info->thread_pool_size = intarg; - } else { - ret = -EINVAL; - goto out; - } - break; - case Opt_max_inline: - num = match_strdup(&args[0]); - if (num) { - info->max_inline = memparse(num, NULL); - kfree(num); - - if (info->max_inline) { - info->max_inline = min_t(u64, - info->max_inline, - root->sectorsize); - } - btrfs_info(root->fs_info, "max_inline at %llu", - info->max_inline); - } else { - ret = -ENOMEM; - goto out; - } - break; - case Opt_alloc_start: - num = match_strdup(&args[0]); - if (num) { - mutex_lock(&info->chunk_mutex); - info->alloc_start = memparse(num, NULL); - mutex_unlock(&info->chunk_mutex); - kfree(num); - btrfs_info(root->fs_info, - "allocations start at %llu", - info->alloc_start); - } else { - ret = -ENOMEM; - goto out; - } - break; - case Opt_acl: -#ifdef CONFIG_BTRFS_FS_POSIX_ACL - root->fs_info->sb->s_flags |= MS_POSIXACL; - break; -#else - btrfs_err(root->fs_info, - "support for ACL not compiled in!"); - ret = -EINVAL; - goto out; -#endif - case Opt_noacl: - root->fs_info->sb->s_flags &= ~MS_POSIXACL; - break; - case Opt_notreelog: - btrfs_set_and_info(info, NOTREELOG, - "disabling tree log"); - break; - case Opt_treelog: - btrfs_clear_and_info(info, NOTREELOG, - "enabling tree log"); - break; - case Opt_norecovery: - case Opt_nologreplay: - btrfs_set_and_info(info, NOLOGREPLAY, - "disabling log replay at mount time"); - break; - case Opt_flushoncommit: - btrfs_set_and_info(info, FLUSHONCOMMIT, - "turning on flush-on-commit"); - break; - case Opt_noflushoncommit: - btrfs_clear_and_info(info, FLUSHONCOMMIT, - "turning off flush-on-commit"); - break; - case Opt_ratio: - ret = match_int(&args[0], &intarg); - if (ret) { - goto out; - } else if (intarg >= 0) { - info->metadata_ratio = intarg; - btrfs_info(root->fs_info, "metadata ratio %d", - info->metadata_ratio); - } else { - ret = -EINVAL; - goto out; - } - break; - case Opt_discard: - btrfs_set_and_info(info, DISCARD, - "turning on discard"); - break; - case Opt_nodiscard: - btrfs_clear_and_info(info, DISCARD, - "turning off discard"); - break; - case Opt_space_cache: - case Opt_space_cache_version: - if (token == Opt_space_cache || - strcmp(args[0].from, "v1") == 0) { - btrfs_clear_opt(root->fs_info->mount_opt, - FREE_SPACE_TREE); - btrfs_set_and_info(info, SPACE_CACHE, - "enabling disk space caching"); - } else if (strcmp(args[0].from, "v2") == 0) { - btrfs_clear_opt(root->fs_info->mount_opt, - SPACE_CACHE); - btrfs_set_and_info(info, - FREE_SPACE_TREE, - "enabling free space tree"); - } else { - ret = -EINVAL; - goto out; - } - break; - case Opt_rescan_uuid_tree: - btrfs_set_opt(info->mount_opt, RESCAN_UUID_TREE); - break; - case Opt_no_space_cache: - if (btrfs_test_opt(info, SPACE_CACHE)) { - btrfs_clear_and_info(info, - SPACE_CACHE, - "disabling disk space caching"); - } - if (btrfs_test_opt(info, FREE_SPACE_TREE)) { - btrfs_clear_and_info(info, - FREE_SPACE_TREE, - "disabling free space tree"); - } - break; - case Opt_inode_cache: - btrfs_set_pending_and_info(info, INODE_MAP_CACHE, - "enabling inode map caching"); - break; - case Opt_noinode_cache: - btrfs_clear_pending_and_info(info, INODE_MAP_CACHE, - "disabling inode map caching"); - break; - case Opt_clear_cache: - btrfs_set_and_info(info, CLEAR_CACHE, - "force clearing of disk cache"); - break; - case Opt_user_subvol_rm_allowed: - btrfs_set_opt(info->mount_opt, USER_SUBVOL_RM_ALLOWED); - break; - case Opt_enospc_debug: - btrfs_set_opt(info->mount_opt, ENOSPC_DEBUG); - break; - case Opt_noenospc_debug: - btrfs_clear_opt(info->mount_opt, ENOSPC_DEBUG); - break; - case Opt_defrag: - btrfs_set_and_info(info, AUTO_DEFRAG, - "enabling auto defrag"); - break; - case Opt_nodefrag: - btrfs_clear_and_info(info, AUTO_DEFRAG, - "disabling auto defrag"); - break; - case Opt_recovery: - btrfs_warn(root->fs_info, - "'recovery' is deprecated, use 'usebackuproot' instead"); - case Opt_usebackuproot: - btrfs_info(root->fs_info, - "trying to use backup root at mount time"); - btrfs_set_opt(info->mount_opt, USEBACKUPROOT); - break; - case Opt_skip_balance: - btrfs_set_opt(info->mount_opt, SKIP_BALANCE); - break; -#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY - case Opt_check_integrity_including_extent_data: - btrfs_info(root->fs_info, - "enabling check integrity including extent data"); - btrfs_set_opt(info->mount_opt, - CHECK_INTEGRITY_INCLUDING_EXTENT_DATA); - btrfs_set_opt(info->mount_opt, CHECK_INTEGRITY); - break; - case Opt_check_integrity: - btrfs_info(root->fs_info, "enabling check integrity"); - btrfs_set_opt(info->mount_opt, CHECK_INTEGRITY); - break; - case Opt_check_integrity_print_mask: - ret = match_int(&args[0], &intarg); - if (ret) { - goto out; - } else if (intarg >= 0) { - info->check_integrity_print_mask = intarg; - btrfs_info(root->fs_info, - "check_integrity_print_mask 0x%x", - info->check_integrity_print_mask); - } else { - ret = -EINVAL; - goto out; - } - break; -#else - case Opt_check_integrity_including_extent_data: - case Opt_check_integrity: - case Opt_check_integrity_print_mask: - btrfs_err(root->fs_info, - "support for check_integrity* not compiled in!"); - ret = -EINVAL; - goto out; -#endif - case Opt_fatal_errors: - if (strcmp(args[0].from, "panic") == 0) - btrfs_set_opt(info->mount_opt, - PANIC_ON_FATAL_ERROR); - else if (strcmp(args[0].from, "bug") == 0) - btrfs_clear_opt(info->mount_opt, - PANIC_ON_FATAL_ERROR); - else { - ret = -EINVAL; - goto out; - } - break; - case Opt_commit_interval: - intarg = 0; - ret = match_int(&args[0], &intarg); - if (ret < 0) { - btrfs_err(root->fs_info, - "invalid commit interval"); - ret = -EINVAL; - goto out; - } - if (intarg > 0) { - if (intarg > 300) { - btrfs_warn(root->fs_info, - "excessive commit interval %d", - intarg); - } - info->commit_interval = intarg; - } else { - btrfs_info(root->fs_info, - "using default commit interval %ds", - BTRFS_DEFAULT_COMMIT_INTERVAL); - info->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL; - } - break; -#ifdef CONFIG_BTRFS_DEBUG - case Opt_fragment_all: - btrfs_info(root->fs_info, "fragmenting all space"); - btrfs_set_opt(info->mount_opt, FRAGMENT_DATA); - btrfs_set_opt(info->mount_opt, FRAGMENT_METADATA); - break; - case Opt_fragment_metadata: - btrfs_info(root->fs_info, "fragmenting metadata"); - btrfs_set_opt(info->mount_opt, - FRAGMENT_METADATA); - break; - case Opt_fragment_data: - btrfs_info(root->fs_info, "fragmenting data"); - btrfs_set_opt(info->mount_opt, FRAGMENT_DATA); - break; -#endif - case Opt_err: - btrfs_info(root->fs_info, - "unrecognized mount option '%s'", p); - ret = -EINVAL; - goto out; - default: - break; - } - } -check: - /* - * Extra check for current option against current flag - */ - if (btrfs_test_opt(info, NOLOGREPLAY) && !(new_flags & MS_RDONLY)) { - btrfs_err(root->fs_info, - "nologreplay must be used with ro mount option"); - ret = -EINVAL; - } -out: - if (btrfs_fs_compat_ro(root->fs_info, FREE_SPACE_TREE) && - !btrfs_test_opt(info, FREE_SPACE_TREE) && - !btrfs_test_opt(info, CLEAR_CACHE)) { - btrfs_err(root->fs_info, "cannot disable free space tree"); - ret = -EINVAL; - - } - if (!ret && btrfs_test_opt(info, SPACE_CACHE)) - btrfs_info(root->fs_info, "disk space caching is enabled"); - if (!ret && btrfs_test_opt(info, FREE_SPACE_TREE)) - btrfs_info(root->fs_info, "using free space tree"); - kfree(orig); - return ret; -} - -/* - * Parse mount options that are required early in the mount process. - * - * All other options will be parsed on much later in the mount process and - * only when we need to allocate a new super block. - */ -static int btrfs_parse_early_options(const char *options, fmode_t flags, - void *holder, char **subvol_name, u64 *subvol_objectid, - struct btrfs_fs_devices **fs_devices) -{ - substring_t args[MAX_OPT_ARGS]; - char *device_name, *opts, *orig, *p; - char *num = NULL; - int error = 0; - - if (!options) - return 0; - - /* - * strsep changes the string, duplicate it because parse_options - * gets called twice - */ - opts = kstrdup(options, GFP_KERNEL); - if (!opts) - return -ENOMEM; - orig = opts; - - while ((p = strsep(&opts, ",")) != NULL) { - int token; - if (!*p) - continue; - - token = match_token(p, tokens, args); - switch (token) { - case Opt_subvol: - kfree(*subvol_name); - *subvol_name = match_strdup(&args[0]); - if (!*subvol_name) { - error = -ENOMEM; - goto out; - } - break; - case Opt_subvolid: - num = match_strdup(&args[0]); - if (num) { - *subvol_objectid = memparse(num, NULL); - kfree(num); - /* we want the original fs_tree */ - if (!*subvol_objectid) - *subvol_objectid = - BTRFS_FS_TREE_OBJECTID; - } else { - error = -EINVAL; - goto out; - } - break; - case Opt_subvolrootid: - pr_warn("BTRFS: 'subvolrootid' mount option is deprecated and has no effect\n"); - break; - case Opt_device: - device_name = match_strdup(&args[0]); - if (!device_name) { - error = -ENOMEM; - goto out; - } - error = btrfs_scan_one_device(device_name, - flags, holder, fs_devices); - kfree(device_name); - if (error) - goto out; - break; - default: - break; - } - } - -out: - kfree(orig); - return error; -} - -static char *get_subvol_name_from_objectid(struct btrfs_fs_info *fs_info, - u64 subvol_objectid) -{ - struct btrfs_root *root = fs_info->tree_root; - struct btrfs_root *fs_root; - struct btrfs_root_ref *root_ref; - struct btrfs_inode_ref *inode_ref; - struct btrfs_key key; - struct btrfs_path *path = NULL; - char *name = NULL, *ptr; - u64 dirid; - int len; - int ret; - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto err; - } - path->leave_spinning = 1; - - name = kmalloc(PATH_MAX, GFP_NOFS); - if (!name) { - ret = -ENOMEM; - goto err; - } - ptr = name + PATH_MAX - 1; - ptr[0] = '\0'; - - /* - * Walk up the subvolume trees in the tree of tree roots by root - * backrefs until we hit the top-level subvolume. - */ - while (subvol_objectid != BTRFS_FS_TREE_OBJECTID) { - key.objectid = subvol_objectid; - key.type = BTRFS_ROOT_BACKREF_KEY; - key.offset = (u64)-1; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) { - goto err; - } else if (ret > 0) { - ret = btrfs_previous_item(root, path, subvol_objectid, - BTRFS_ROOT_BACKREF_KEY); - if (ret < 0) { - goto err; - } else if (ret > 0) { - ret = -ENOENT; - goto err; - } - } - - btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); - subvol_objectid = key.offset; - - root_ref = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_root_ref); - len = btrfs_root_ref_name_len(path->nodes[0], root_ref); - ptr -= len + 1; - if (ptr < name) { - ret = -ENAMETOOLONG; - goto err; - } - read_extent_buffer(path->nodes[0], ptr + 1, - (unsigned long)(root_ref + 1), len); - ptr[0] = '/'; - dirid = btrfs_root_ref_dirid(path->nodes[0], root_ref); - btrfs_release_path(path); - - key.objectid = subvol_objectid; - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = (u64)-1; - fs_root = btrfs_read_fs_root_no_name(fs_info, &key); - if (IS_ERR(fs_root)) { - ret = PTR_ERR(fs_root); - goto err; - } - - /* - * Walk up the filesystem tree by inode refs until we hit the - * root directory. - */ - while (dirid != BTRFS_FIRST_FREE_OBJECTID) { - key.objectid = dirid; - key.type = BTRFS_INODE_REF_KEY; - key.offset = (u64)-1; - - ret = btrfs_search_slot(NULL, fs_root, &key, path, 0, 0); - if (ret < 0) { - goto err; - } else if (ret > 0) { - ret = btrfs_previous_item(fs_root, path, dirid, - BTRFS_INODE_REF_KEY); - if (ret < 0) { - goto err; - } else if (ret > 0) { - ret = -ENOENT; - goto err; - } - } - - btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); - dirid = key.offset; - - inode_ref = btrfs_item_ptr(path->nodes[0], - path->slots[0], - struct btrfs_inode_ref); - len = btrfs_inode_ref_name_len(path->nodes[0], - inode_ref); - ptr -= len + 1; - if (ptr < name) { - ret = -ENAMETOOLONG; - goto err; - } - read_extent_buffer(path->nodes[0], ptr + 1, - (unsigned long)(inode_ref + 1), len); - ptr[0] = '/'; - btrfs_release_path(path); - } - } - - btrfs_free_path(path); - if (ptr == name + PATH_MAX - 1) { - name[0] = '/'; - name[1] = '\0'; - } else { - memmove(name, ptr, name + PATH_MAX - ptr); - } - return name; - -err: - btrfs_free_path(path); - kfree(name); - return ERR_PTR(ret); -} - -static int get_default_subvol_objectid(struct btrfs_fs_info *fs_info, u64 *objectid) -{ - struct btrfs_root *root = fs_info->tree_root; - struct btrfs_dir_item *di; - struct btrfs_path *path; - struct btrfs_key location; - u64 dir_id; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->leave_spinning = 1; - - /* - * Find the "default" dir item which points to the root item that we - * will mount by default if we haven't been given a specific subvolume - * to mount. - */ - dir_id = btrfs_super_root_dir(fs_info->super_copy); - di = btrfs_lookup_dir_item(NULL, root, path, dir_id, "default", 7, 0); - if (IS_ERR(di)) { - btrfs_free_path(path); - return PTR_ERR(di); - } - if (!di) { - /* - * Ok the default dir item isn't there. This is weird since - * it's always been there, but don't freak out, just try and - * mount the top-level subvolume. - */ - btrfs_free_path(path); - *objectid = BTRFS_FS_TREE_OBJECTID; - return 0; - } - - btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location); - btrfs_free_path(path); - *objectid = location.objectid; - return 0; -} - -static int btrfs_fill_super(struct super_block *sb, - struct btrfs_fs_devices *fs_devices, - void *data, int silent) -{ - struct inode *inode; - struct btrfs_fs_info *fs_info = btrfs_sb(sb); - struct btrfs_key key; - int err; - - sb->s_maxbytes = MAX_LFS_FILESIZE; - sb->s_magic = BTRFS_SUPER_MAGIC; - sb->s_op = &btrfs_super_ops; - sb->s_d_op = &btrfs_dentry_operations; - sb->s_export_op = &btrfs_export_ops; - sb->s_xattr = btrfs_xattr_handlers; - sb->s_time_gran = 1; -#ifdef CONFIG_BTRFS_FS_POSIX_ACL - sb->s_flags |= MS_POSIXACL; -#endif - sb->s_flags |= MS_I_VERSION; - sb->s_iflags |= SB_I_CGROUPWB; - err = open_ctree(sb, fs_devices, (char *)data); - if (err) { - btrfs_err(fs_info, "open_ctree failed"); - return err; - } - - key.objectid = BTRFS_FIRST_FREE_OBJECTID; - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - inode = btrfs_iget(sb, &key, fs_info->fs_root, NULL); - if (IS_ERR(inode)) { - err = PTR_ERR(inode); - goto fail_close; - } - - sb->s_root = d_make_root(inode); - if (!sb->s_root) { - err = -ENOMEM; - goto fail_close; - } - - save_mount_options(sb, data); - cleancache_init_fs(sb); - sb->s_flags |= MS_ACTIVE; - return 0; - -fail_close: - close_ctree(fs_info->tree_root); - return err; -} - -int btrfs_sync_fs(struct super_block *sb, int wait) -{ - struct btrfs_trans_handle *trans; - struct btrfs_fs_info *fs_info = btrfs_sb(sb); - struct btrfs_root *root = fs_info->tree_root; - - trace_btrfs_sync_fs(fs_info, wait); - - if (!wait) { - filemap_flush(fs_info->btree_inode->i_mapping); - return 0; - } - - btrfs_wait_ordered_roots(fs_info, -1, 0, (u64)-1); - - trans = btrfs_attach_transaction_barrier(root); - if (IS_ERR(trans)) { - /* no transaction, don't bother */ - if (PTR_ERR(trans) == -ENOENT) { - /* - * Exit unless we have some pending changes - * that need to go through commit - */ - if (fs_info->pending_changes == 0) - return 0; - /* - * A non-blocking test if the fs is frozen. We must not - * start a new transaction here otherwise a deadlock - * happens. The pending operations are delayed to the - * next commit after thawing. - */ - if (__sb_start_write(sb, SB_FREEZE_WRITE, false)) - __sb_end_write(sb, SB_FREEZE_WRITE); - else - return 0; - trans = btrfs_start_transaction(root, 0); - } - if (IS_ERR(trans)) - return PTR_ERR(trans); - } - return btrfs_commit_transaction(trans, root); -} - -static int btrfs_show_options(struct seq_file *seq, struct dentry *dentry) -{ - struct btrfs_fs_info *info = btrfs_sb(dentry->d_sb); - struct btrfs_root *root = info->tree_root; - char *compress_type; - - if (btrfs_test_opt(info, DEGRADED)) - seq_puts(seq, ",degraded"); - if (btrfs_test_opt(info, NODATASUM)) - seq_puts(seq, ",nodatasum"); - if (btrfs_test_opt(info, NODATACOW)) - seq_puts(seq, ",nodatacow"); - if (btrfs_test_opt(info, NOBARRIER)) - seq_puts(seq, ",nobarrier"); - if (info->max_inline != BTRFS_DEFAULT_MAX_INLINE) - seq_printf(seq, ",max_inline=%llu", info->max_inline); - if (info->alloc_start != 0) - seq_printf(seq, ",alloc_start=%llu", info->alloc_start); - if (info->thread_pool_size != min_t(unsigned long, - num_online_cpus() + 2, 8)) - seq_printf(seq, ",thread_pool=%d", info->thread_pool_size); - if (btrfs_test_opt(info, COMPRESS)) { - if (info->compress_type == BTRFS_COMPRESS_ZLIB) - compress_type = "zlib"; - else - compress_type = "lzo"; - if (btrfs_test_opt(info, FORCE_COMPRESS)) - seq_printf(seq, ",compress-force=%s", compress_type); - else - seq_printf(seq, ",compress=%s", compress_type); - } - if (btrfs_test_opt(info, NOSSD)) - seq_puts(seq, ",nossd"); - if (btrfs_test_opt(info, SSD_SPREAD)) - seq_puts(seq, ",ssd_spread"); - else if (btrfs_test_opt(info, SSD)) - seq_puts(seq, ",ssd"); - if (btrfs_test_opt(info, NOTREELOG)) - seq_puts(seq, ",notreelog"); - if (btrfs_test_opt(info, NOLOGREPLAY)) - seq_puts(seq, ",nologreplay"); - if (btrfs_test_opt(info, FLUSHONCOMMIT)) - seq_puts(seq, ",flushoncommit"); - if (btrfs_test_opt(info, DISCARD)) - seq_puts(seq, ",discard"); - if (!(root->fs_info->sb->s_flags & MS_POSIXACL)) - seq_puts(seq, ",noacl"); - if (btrfs_test_opt(info, SPACE_CACHE)) - seq_puts(seq, ",space_cache"); - else if (btrfs_test_opt(info, FREE_SPACE_TREE)) - seq_puts(seq, ",space_cache=v2"); - else - seq_puts(seq, ",nospace_cache"); - if (btrfs_test_opt(info, RESCAN_UUID_TREE)) - seq_puts(seq, ",rescan_uuid_tree"); - if (btrfs_test_opt(info, CLEAR_CACHE)) - seq_puts(seq, ",clear_cache"); - if (btrfs_test_opt(info, USER_SUBVOL_RM_ALLOWED)) - seq_puts(seq, ",user_subvol_rm_allowed"); - if (btrfs_test_opt(info, ENOSPC_DEBUG)) - seq_puts(seq, ",enospc_debug"); - if (btrfs_test_opt(info, AUTO_DEFRAG)) - seq_puts(seq, ",autodefrag"); - if (btrfs_test_opt(info, INODE_MAP_CACHE)) - seq_puts(seq, ",inode_cache"); - if (btrfs_test_opt(info, SKIP_BALANCE)) - seq_puts(seq, ",skip_balance"); -#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY - if (btrfs_test_opt(info, CHECK_INTEGRITY_INCLUDING_EXTENT_DATA)) - seq_puts(seq, ",check_int_data"); - else if (btrfs_test_opt(info, CHECK_INTEGRITY)) - seq_puts(seq, ",check_int"); - if (info->check_integrity_print_mask) - seq_printf(seq, ",check_int_print_mask=%d", - info->check_integrity_print_mask); -#endif - if (info->metadata_ratio) - seq_printf(seq, ",metadata_ratio=%d", - info->metadata_ratio); - if (btrfs_test_opt(info, PANIC_ON_FATAL_ERROR)) - seq_puts(seq, ",fatal_errors=panic"); - if (info->commit_interval != BTRFS_DEFAULT_COMMIT_INTERVAL) - seq_printf(seq, ",commit=%d", info->commit_interval); -#ifdef CONFIG_BTRFS_DEBUG - if (btrfs_test_opt(info, FRAGMENT_DATA)) - seq_puts(seq, ",fragment=data"); - if (btrfs_test_opt(info, FRAGMENT_METADATA)) - seq_puts(seq, ",fragment=metadata"); -#endif - seq_printf(seq, ",subvolid=%llu", - BTRFS_I(d_inode(dentry))->root->root_key.objectid); - seq_puts(seq, ",subvol="); - seq_dentry(seq, dentry, " \t\n\\"); - return 0; -} - -static int btrfs_test_super(struct super_block *s, void *data) -{ - struct btrfs_fs_info *p = data; - struct btrfs_fs_info *fs_info = btrfs_sb(s); - - return fs_info->fs_devices == p->fs_devices; -} - -static int btrfs_set_super(struct super_block *s, void *data) -{ - int err = set_anon_super(s, data); - if (!err) - s->s_fs_info = data; - return err; -} - -/* - * subvolumes are identified by ino 256 - */ -static inline int is_subvolume_inode(struct inode *inode) -{ - if (inode && inode->i_ino == BTRFS_FIRST_FREE_OBJECTID) - return 1; - return 0; -} - -/* - * This will add subvolid=0 to the argument string while removing any subvol= - * and subvolid= arguments to make sure we get the top-level root for path - * walking to the subvol we want. - */ -static char *setup_root_args(char *args) -{ - char *buf, *dst, *sep; - - if (!args) - return kstrdup("subvolid=0", GFP_NOFS); - - /* The worst case is that we add ",subvolid=0" to the end. */ - buf = dst = kmalloc(strlen(args) + strlen(",subvolid=0") + 1, GFP_NOFS); - if (!buf) - return NULL; - - while (1) { - sep = strchrnul(args, ','); - if (!strstarts(args, "subvol=") && - !strstarts(args, "subvolid=")) { - memcpy(dst, args, sep - args); - dst += sep - args; - *dst++ = ','; - } - if (*sep) - args = sep + 1; - else - break; - } - strcpy(dst, "subvolid=0"); - - return buf; -} - -static struct dentry *mount_subvol(const char *subvol_name, u64 subvol_objectid, - int flags, const char *device_name, - char *data) -{ - struct dentry *root; - struct vfsmount *mnt = NULL; - char *newargs; - int ret; - - newargs = setup_root_args(data); - if (!newargs) { - root = ERR_PTR(-ENOMEM); - goto out; - } - - mnt = vfs_kern_mount(&btrfs_fs_type, flags, device_name, newargs); - if (PTR_ERR_OR_ZERO(mnt) == -EBUSY) { - if (flags & MS_RDONLY) { - mnt = vfs_kern_mount(&btrfs_fs_type, flags & ~MS_RDONLY, - device_name, newargs); - } else { - mnt = vfs_kern_mount(&btrfs_fs_type, flags | MS_RDONLY, - device_name, newargs); - if (IS_ERR(mnt)) { - root = ERR_CAST(mnt); - mnt = NULL; - goto out; - } - - down_write(&mnt->mnt_sb->s_umount); - ret = btrfs_remount(mnt->mnt_sb, &flags, NULL); - up_write(&mnt->mnt_sb->s_umount); - if (ret < 0) { - root = ERR_PTR(ret); - goto out; - } - } - } - if (IS_ERR(mnt)) { - root = ERR_CAST(mnt); - mnt = NULL; - goto out; - } - - if (!subvol_name) { - if (!subvol_objectid) { - ret = get_default_subvol_objectid(btrfs_sb(mnt->mnt_sb), - &subvol_objectid); - if (ret) { - root = ERR_PTR(ret); - goto out; - } - } - subvol_name = get_subvol_name_from_objectid(btrfs_sb(mnt->mnt_sb), - subvol_objectid); - if (IS_ERR(subvol_name)) { - root = ERR_CAST(subvol_name); - subvol_name = NULL; - goto out; - } - - } - - root = mount_subtree(mnt, subvol_name); - /* mount_subtree() drops our reference on the vfsmount. */ - mnt = NULL; - - if (!IS_ERR(root)) { - struct super_block *s = root->d_sb; - struct btrfs_fs_info *fs_info = btrfs_sb(s); - struct inode *root_inode = d_inode(root); - u64 root_objectid = BTRFS_I(root_inode)->root->root_key.objectid; - - ret = 0; - if (!is_subvolume_inode(root_inode)) { - btrfs_err(fs_info, "'%s' is not a valid subvolume", - subvol_name); - ret = -EINVAL; - } - if (subvol_objectid && root_objectid != subvol_objectid) { - /* - * This will also catch a race condition where a - * subvolume which was passed by ID is renamed and - * another subvolume is renamed over the old location. - */ - btrfs_err(fs_info, - "subvol '%s' does not match subvolid %llu", - subvol_name, subvol_objectid); - ret = -EINVAL; - } - if (ret) { - dput(root); - root = ERR_PTR(ret); - deactivate_locked_super(s); - } - } - -out: - mntput(mnt); - kfree(newargs); - kfree(subvol_name); - return root; -} - -static int parse_security_options(char *orig_opts, - struct security_mnt_opts *sec_opts) -{ - char *secdata = NULL; - int ret = 0; - - secdata = alloc_secdata(); - if (!secdata) - return -ENOMEM; - ret = security_sb_copy_data(orig_opts, secdata); - if (ret) { - free_secdata(secdata); - return ret; - } - ret = security_sb_parse_opts_str(secdata, sec_opts); - free_secdata(secdata); - return ret; -} - -static int setup_security_options(struct btrfs_fs_info *fs_info, - struct super_block *sb, - struct security_mnt_opts *sec_opts) -{ - int ret = 0; - - /* - * Call security_sb_set_mnt_opts() to check whether new sec_opts - * is valid. - */ - ret = security_sb_set_mnt_opts(sb, sec_opts, 0, NULL); - if (ret) - return ret; - -#ifdef CONFIG_SECURITY - if (!fs_info->security_opts.num_mnt_opts) { - /* first time security setup, copy sec_opts to fs_info */ - memcpy(&fs_info->security_opts, sec_opts, sizeof(*sec_opts)); - } else { - /* - * Since SELinux (the only one supporting security_mnt_opts) - * does NOT support changing context during remount/mount of - * the same sb, this must be the same or part of the same - * security options, just free it. - */ - security_free_mnt_opts(sec_opts); - } -#endif - return ret; -} - -/* - * Find a superblock for the given device / mount point. - * - * Note: This is based on get_sb_bdev from fs/super.c with a few additions - * for multiple device setup. Make sure to keep it in sync. - */ -static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags, - const char *device_name, void *data) -{ - struct block_device *bdev = NULL; - struct super_block *s; - struct btrfs_fs_devices *fs_devices = NULL; - struct btrfs_fs_info *fs_info = NULL; - struct security_mnt_opts new_sec_opts; - fmode_t mode = FMODE_READ; - char *subvol_name = NULL; - u64 subvol_objectid = 0; - int error = 0; - - if (!(flags & MS_RDONLY)) - mode |= FMODE_WRITE; - - error = btrfs_parse_early_options(data, mode, fs_type, - &subvol_name, &subvol_objectid, - &fs_devices); - if (error) { - kfree(subvol_name); - return ERR_PTR(error); - } - - if (subvol_name || subvol_objectid != BTRFS_FS_TREE_OBJECTID) { - /* mount_subvol() will free subvol_name. */ - return mount_subvol(subvol_name, subvol_objectid, flags, - device_name, data); - } - - security_init_mnt_opts(&new_sec_opts); - if (data) { - error = parse_security_options(data, &new_sec_opts); - if (error) - return ERR_PTR(error); - } - - error = btrfs_scan_one_device(device_name, mode, fs_type, &fs_devices); - if (error) - goto error_sec_opts; - - /* - * Setup a dummy root and fs_info for test/set super. This is because - * we don't actually fill this stuff out until open_ctree, but we need - * it for searching for existing supers, so this lets us do that and - * then open_ctree will properly initialize everything later. - */ - fs_info = kzalloc(sizeof(struct btrfs_fs_info), GFP_NOFS); - if (!fs_info) { - error = -ENOMEM; - goto error_sec_opts; - } - - fs_info->fs_devices = fs_devices; - - fs_info->super_copy = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS); - fs_info->super_for_commit = kzalloc(BTRFS_SUPER_INFO_SIZE, GFP_NOFS); - security_init_mnt_opts(&fs_info->security_opts); - if (!fs_info->super_copy || !fs_info->super_for_commit) { - error = -ENOMEM; - goto error_fs_info; - } - - error = btrfs_open_devices(fs_devices, mode, fs_type); - if (error) - goto error_fs_info; - - if (!(flags & MS_RDONLY) && fs_devices->rw_devices == 0) { - error = -EACCES; - goto error_close_devices; - } - - bdev = fs_devices->latest_bdev; - s = sget(fs_type, btrfs_test_super, btrfs_set_super, flags | MS_NOSEC, - fs_info); - if (IS_ERR(s)) { - error = PTR_ERR(s); - goto error_close_devices; - } - - if (s->s_root) { - btrfs_close_devices(fs_devices); - free_fs_info(fs_info); - if ((flags ^ s->s_flags) & MS_RDONLY) - error = -EBUSY; - } else { - snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev); - btrfs_sb(s)->bdev_holder = fs_type; - error = btrfs_fill_super(s, fs_devices, data, - flags & MS_SILENT ? 1 : 0); - } - if (error) { - deactivate_locked_super(s); - goto error_sec_opts; - } - - fs_info = btrfs_sb(s); - error = setup_security_options(fs_info, s, &new_sec_opts); - if (error) { - deactivate_locked_super(s); - goto error_sec_opts; - } - - return dget(s->s_root); - -error_close_devices: - btrfs_close_devices(fs_devices); -error_fs_info: - free_fs_info(fs_info); -error_sec_opts: - security_free_mnt_opts(&new_sec_opts); - return ERR_PTR(error); -} - -static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info, - int new_pool_size, int old_pool_size) -{ - if (new_pool_size == old_pool_size) - return; - - fs_info->thread_pool_size = new_pool_size; - - btrfs_info(fs_info, "resize thread pool %d -> %d", - old_pool_size, new_pool_size); - - btrfs_workqueue_set_max(fs_info->workers, new_pool_size); - btrfs_workqueue_set_max(fs_info->delalloc_workers, new_pool_size); - btrfs_workqueue_set_max(fs_info->submit_workers, new_pool_size); - btrfs_workqueue_set_max(fs_info->caching_workers, new_pool_size); - btrfs_workqueue_set_max(fs_info->endio_workers, new_pool_size); - btrfs_workqueue_set_max(fs_info->endio_meta_workers, new_pool_size); - btrfs_workqueue_set_max(fs_info->endio_meta_write_workers, - new_pool_size); - btrfs_workqueue_set_max(fs_info->endio_write_workers, new_pool_size); - btrfs_workqueue_set_max(fs_info->endio_freespace_worker, new_pool_size); - btrfs_workqueue_set_max(fs_info->delayed_workers, new_pool_size); - btrfs_workqueue_set_max(fs_info->readahead_workers, new_pool_size); - btrfs_workqueue_set_max(fs_info->scrub_wr_completion_workers, - new_pool_size); -} - -static inline void btrfs_remount_prepare(struct btrfs_fs_info *fs_info) -{ - set_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state); -} - -static inline void btrfs_remount_begin(struct btrfs_fs_info *fs_info, - unsigned long old_opts, int flags) -{ - if (btrfs_raw_test_opt(old_opts, AUTO_DEFRAG) && - (!btrfs_raw_test_opt(fs_info->mount_opt, AUTO_DEFRAG) || - (flags & MS_RDONLY))) { - /* wait for any defraggers to finish */ - wait_event(fs_info->transaction_wait, - (atomic_read(&fs_info->defrag_running) == 0)); - if (flags & MS_RDONLY) - sync_filesystem(fs_info->sb); - } -} - -static inline void btrfs_remount_cleanup(struct btrfs_fs_info *fs_info, - unsigned long old_opts) -{ - /* - * We need to cleanup all defragable inodes if the autodefragment is - * close or the filesystem is read only. - */ - if (btrfs_raw_test_opt(old_opts, AUTO_DEFRAG) && - (!btrfs_raw_test_opt(fs_info->mount_opt, AUTO_DEFRAG) || - (fs_info->sb->s_flags & MS_RDONLY))) { - btrfs_cleanup_defrag_inodes(fs_info); - } - - clear_bit(BTRFS_FS_STATE_REMOUNTING, &fs_info->fs_state); -} - -static int btrfs_remount(struct super_block *sb, int *flags, char *data) -{ - struct btrfs_fs_info *fs_info = btrfs_sb(sb); - struct btrfs_root *root = fs_info->tree_root; - unsigned old_flags = sb->s_flags; - unsigned long old_opts = fs_info->mount_opt; - unsigned long old_compress_type = fs_info->compress_type; - u64 old_max_inline = fs_info->max_inline; - u64 old_alloc_start = fs_info->alloc_start; - int old_thread_pool_size = fs_info->thread_pool_size; - unsigned int old_metadata_ratio = fs_info->metadata_ratio; - int ret; - - sync_filesystem(sb); - btrfs_remount_prepare(fs_info); - - if (data) { - struct security_mnt_opts new_sec_opts; - - security_init_mnt_opts(&new_sec_opts); - ret = parse_security_options(data, &new_sec_opts); - if (ret) - goto restore; - ret = setup_security_options(fs_info, sb, - &new_sec_opts); - if (ret) { - security_free_mnt_opts(&new_sec_opts); - goto restore; - } - } - - ret = btrfs_parse_options(root, data, *flags); - if (ret) { - ret = -EINVAL; - goto restore; - } - - btrfs_remount_begin(fs_info, old_opts, *flags); - btrfs_resize_thread_pool(fs_info, - fs_info->thread_pool_size, old_thread_pool_size); - - if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) - goto out; - - if (*flags & MS_RDONLY) { - /* - * this also happens on 'umount -rf' or on shutdown, when - * the filesystem is busy. - */ - cancel_work_sync(&fs_info->async_reclaim_work); - - /* wait for the uuid_scan task to finish */ - down(&fs_info->uuid_tree_rescan_sem); - /* avoid complains from lockdep et al. */ - up(&fs_info->uuid_tree_rescan_sem); - - sb->s_flags |= MS_RDONLY; - - /* - * Setting MS_RDONLY will put the cleaner thread to - * sleep at the next loop if it's already active. - * If it's already asleep, we'll leave unused block - * groups on disk until we're mounted read-write again - * unless we clean them up here. - */ - btrfs_delete_unused_bgs(fs_info); - - btrfs_dev_replace_suspend_for_unmount(fs_info); - btrfs_scrub_cancel(fs_info); - btrfs_pause_balance(fs_info); - - ret = btrfs_commit_super(root); - if (ret) - goto restore; - } else { - if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state)) { - btrfs_err(fs_info, - "Remounting read-write after error is not allowed"); - ret = -EINVAL; - goto restore; - } - if (fs_info->fs_devices->rw_devices == 0) { - ret = -EACCES; - goto restore; - } - - if (fs_info->fs_devices->missing_devices > - fs_info->num_tolerated_disk_barrier_failures && - !(*flags & MS_RDONLY)) { - btrfs_warn(fs_info, - "too many missing devices, writeable remount is not allowed"); - ret = -EACCES; - goto restore; - } - - if (btrfs_super_log_root(fs_info->super_copy) != 0) { - ret = -EINVAL; - goto restore; - } - - ret = btrfs_cleanup_fs_roots(fs_info); - if (ret) - goto restore; - - /* recover relocation */ - mutex_lock(&fs_info->cleaner_mutex); - ret = btrfs_recover_relocation(root); - mutex_unlock(&fs_info->cleaner_mutex); - if (ret) - goto restore; - - ret = btrfs_resume_balance_async(fs_info); - if (ret) - goto restore; - - ret = btrfs_resume_dev_replace_async(fs_info); - if (ret) { - btrfs_warn(fs_info, "failed to resume dev_replace"); - goto restore; - } - - if (!fs_info->uuid_root) { - btrfs_info(fs_info, "creating UUID tree"); - ret = btrfs_create_uuid_tree(fs_info); - if (ret) { - btrfs_warn(fs_info, - "failed to create the UUID tree %d", - ret); - goto restore; - } - } - sb->s_flags &= ~MS_RDONLY; - - set_bit(BTRFS_FS_OPEN, &fs_info->flags); - } -out: - wake_up_process(fs_info->transaction_kthread); - btrfs_remount_cleanup(fs_info, old_opts); - return 0; - -restore: - /* We've hit an error - don't reset MS_RDONLY */ - if (sb->s_flags & MS_RDONLY) - old_flags |= MS_RDONLY; - sb->s_flags = old_flags; - fs_info->mount_opt = old_opts; - fs_info->compress_type = old_compress_type; - fs_info->max_inline = old_max_inline; - mutex_lock(&fs_info->chunk_mutex); - fs_info->alloc_start = old_alloc_start; - mutex_unlock(&fs_info->chunk_mutex); - btrfs_resize_thread_pool(fs_info, - old_thread_pool_size, fs_info->thread_pool_size); - fs_info->metadata_ratio = old_metadata_ratio; - btrfs_remount_cleanup(fs_info, old_opts); - return ret; -} - -/* Used to sort the devices by max_avail(descending sort) */ -static int btrfs_cmp_device_free_bytes(const void *dev_info1, - const void *dev_info2) -{ - if (((struct btrfs_device_info *)dev_info1)->max_avail > - ((struct btrfs_device_info *)dev_info2)->max_avail) - return -1; - else if (((struct btrfs_device_info *)dev_info1)->max_avail < - ((struct btrfs_device_info *)dev_info2)->max_avail) - return 1; - else - return 0; -} - -/* - * sort the devices by max_avail, in which max free extent size of each device - * is stored.(Descending Sort) - */ -static inline void btrfs_descending_sort_devices( - struct btrfs_device_info *devices, - size_t nr_devices) -{ - sort(devices, nr_devices, sizeof(struct btrfs_device_info), - btrfs_cmp_device_free_bytes, NULL); -} - -/* - * The helper to calc the free space on the devices that can be used to store - * file data. - */ -static int btrfs_calc_avail_data_space(struct btrfs_root *root, u64 *free_bytes) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_device_info *devices_info; - struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; - struct btrfs_device *device; - u64 skip_space; - u64 type; - u64 avail_space; - u64 used_space; - u64 min_stripe_size; - int min_stripes = 1, num_stripes = 1; - int i = 0, nr_devices; - int ret; - - /* - * We aren't under the device list lock, so this is racy-ish, but good - * enough for our purposes. - */ - nr_devices = fs_info->fs_devices->open_devices; - if (!nr_devices) { - smp_mb(); - nr_devices = fs_info->fs_devices->open_devices; - ASSERT(nr_devices); - if (!nr_devices) { - *free_bytes = 0; - return 0; - } - } - - devices_info = kmalloc_array(nr_devices, sizeof(*devices_info), - GFP_NOFS); - if (!devices_info) - return -ENOMEM; - - /* calc min stripe number for data space allocation */ - type = btrfs_get_alloc_profile(root, 1); - if (type & BTRFS_BLOCK_GROUP_RAID0) { - min_stripes = 2; - num_stripes = nr_devices; - } else if (type & BTRFS_BLOCK_GROUP_RAID1) { - min_stripes = 2; - num_stripes = 2; - } else if (type & BTRFS_BLOCK_GROUP_RAID10) { - min_stripes = 4; - num_stripes = 4; - } - - if (type & BTRFS_BLOCK_GROUP_DUP) - min_stripe_size = 2 * BTRFS_STRIPE_LEN; - else - min_stripe_size = BTRFS_STRIPE_LEN; - - if (fs_info->alloc_start) - mutex_lock(&fs_devices->device_list_mutex); - rcu_read_lock(); - list_for_each_entry_rcu(device, &fs_devices->devices, dev_list) { - if (!device->in_fs_metadata || !device->bdev || - device->is_tgtdev_for_dev_replace) - continue; - - if (i >= nr_devices) - break; - - avail_space = device->total_bytes - device->bytes_used; - - /* align with stripe_len */ - avail_space = div_u64(avail_space, BTRFS_STRIPE_LEN); - avail_space *= BTRFS_STRIPE_LEN; - - /* - * In order to avoid overwriting the superblock on the drive, - * btrfs starts at an offset of at least 1MB when doing chunk - * allocation. - */ - skip_space = SZ_1M; - - /* user can set the offset in fs_info->alloc_start. */ - if (fs_info->alloc_start && - fs_info->alloc_start + BTRFS_STRIPE_LEN <= - device->total_bytes) { - rcu_read_unlock(); - skip_space = max(fs_info->alloc_start, skip_space); - - /* - * btrfs can not use the free space in - * [0, skip_space - 1], we must subtract it from the - * total. In order to implement it, we account the used - * space in this range first. - */ - ret = btrfs_account_dev_extents_size(device, 0, - skip_space - 1, - &used_space); - if (ret) { - kfree(devices_info); - mutex_unlock(&fs_devices->device_list_mutex); - return ret; - } - - rcu_read_lock(); - - /* calc the free space in [0, skip_space - 1] */ - skip_space -= used_space; - } - - /* - * we can use the free space in [0, skip_space - 1], subtract - * it from the total. - */ - if (avail_space && avail_space >= skip_space) - avail_space -= skip_space; - else - avail_space = 0; - - if (avail_space < min_stripe_size) - continue; - - devices_info[i].dev = device; - devices_info[i].max_avail = avail_space; - - i++; - } - rcu_read_unlock(); - if (fs_info->alloc_start) - mutex_unlock(&fs_devices->device_list_mutex); - - nr_devices = i; - - btrfs_descending_sort_devices(devices_info, nr_devices); - - i = nr_devices - 1; - avail_space = 0; - while (nr_devices >= min_stripes) { - if (num_stripes > nr_devices) - num_stripes = nr_devices; - - if (devices_info[i].max_avail >= min_stripe_size) { - int j; - u64 alloc_size; - - avail_space += devices_info[i].max_avail * num_stripes; - alloc_size = devices_info[i].max_avail; - for (j = i + 1 - num_stripes; j <= i; j++) - devices_info[j].max_avail -= alloc_size; - } - i--; - nr_devices--; - } - - kfree(devices_info); - *free_bytes = avail_space; - return 0; -} - -/* - * Calculate numbers for 'df', pessimistic in case of mixed raid profiles. - * - * If there's a redundant raid level at DATA block groups, use the respective - * multiplier to scale the sizes. - * - * Unused device space usage is based on simulating the chunk allocator - * algorithm that respects the device sizes, order of allocations and the - * 'alloc_start' value, this is a close approximation of the actual use but - * there are other factors that may change the result (like a new metadata - * chunk). - * - * If metadata is exhausted, f_bavail will be 0. - */ -static int btrfs_statfs(struct dentry *dentry, struct kstatfs *buf) -{ - struct btrfs_fs_info *fs_info = btrfs_sb(dentry->d_sb); - struct btrfs_super_block *disk_super = fs_info->super_copy; - struct list_head *head = &fs_info->space_info; - struct btrfs_space_info *found; - u64 total_used = 0; - u64 total_free_data = 0; - u64 total_free_meta = 0; - int bits = dentry->d_sb->s_blocksize_bits; - __be32 *fsid = (__be32 *)fs_info->fsid; - unsigned factor = 1; - struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; - int ret; - u64 thresh = 0; - int mixed = 0; - - /* - * holding chunk_mutex to avoid allocating new chunks, holding - * device_list_mutex to avoid the device being removed - */ - rcu_read_lock(); - list_for_each_entry_rcu(found, head, list) { - if (found->flags & BTRFS_BLOCK_GROUP_DATA) { - int i; - - total_free_data += found->disk_total - found->disk_used; - total_free_data -= - btrfs_account_ro_block_groups_free_space(found); - - for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) { - if (!list_empty(&found->block_groups[i])) { - switch (i) { - case BTRFS_RAID_DUP: - case BTRFS_RAID_RAID1: - case BTRFS_RAID_RAID10: - factor = 2; - } - } - } - } - - /* - * Metadata in mixed block goup profiles are accounted in data - */ - if (!mixed && found->flags & BTRFS_BLOCK_GROUP_METADATA) { - if (found->flags & BTRFS_BLOCK_GROUP_DATA) - mixed = 1; - else - total_free_meta += found->disk_total - - found->disk_used; - } - - total_used += found->disk_used; - } - - rcu_read_unlock(); - - buf->f_blocks = div_u64(btrfs_super_total_bytes(disk_super), factor); - buf->f_blocks >>= bits; - buf->f_bfree = buf->f_blocks - (div_u64(total_used, factor) >> bits); - - /* Account global block reserve as used, it's in logical size already */ - spin_lock(&block_rsv->lock); - /* Mixed block groups accounting is not byte-accurate, avoid overflow */ - if (buf->f_bfree >= block_rsv->size >> bits) - buf->f_bfree -= block_rsv->size >> bits; - else - buf->f_bfree = 0; - spin_unlock(&block_rsv->lock); - - buf->f_bavail = div_u64(total_free_data, factor); - ret = btrfs_calc_avail_data_space(fs_info->tree_root, &total_free_data); - if (ret) - return ret; - buf->f_bavail += div_u64(total_free_data, factor); - buf->f_bavail = buf->f_bavail >> bits; - - /* - * We calculate the remaining metadata space minus global reserve. If - * this is (supposedly) smaller than zero, there's no space. But this - * does not hold in practice, the exhausted state happens where's still - * some positive delta. So we apply some guesswork and compare the - * delta to a 4M threshold. (Practically observed delta was ~2M.) - * - * We probably cannot calculate the exact threshold value because this - * depends on the internal reservations requested by various - * operations, so some operations that consume a few metadata will - * succeed even if the Avail is zero. But this is better than the other - * way around. - */ - thresh = 4 * 1024 * 1024; - - if (!mixed && total_free_meta - thresh < block_rsv->size) - buf->f_bavail = 0; - - buf->f_type = BTRFS_SUPER_MAGIC; - buf->f_bsize = dentry->d_sb->s_blocksize; - buf->f_namelen = BTRFS_NAME_LEN; - - /* We treat it as constant endianness (it doesn't matter _which_) - because we want the fsid to come out the same whether mounted - on a big-endian or little-endian host */ - buf->f_fsid.val[0] = be32_to_cpu(fsid[0]) ^ be32_to_cpu(fsid[2]); - buf->f_fsid.val[1] = be32_to_cpu(fsid[1]) ^ be32_to_cpu(fsid[3]); - /* Mask in the root object ID too, to disambiguate subvols */ - buf->f_fsid.val[0] ^= BTRFS_I(d_inode(dentry))->root->objectid >> 32; - buf->f_fsid.val[1] ^= BTRFS_I(d_inode(dentry))->root->objectid; - - return 0; -} - -static void btrfs_kill_super(struct super_block *sb) -{ - struct btrfs_fs_info *fs_info = btrfs_sb(sb); - kill_anon_super(sb); - free_fs_info(fs_info); -} - -static struct file_system_type btrfs_fs_type = { - .owner = THIS_MODULE, - .name = "btrfs", - .mount = btrfs_mount, - .kill_sb = btrfs_kill_super, - .fs_flags = FS_REQUIRES_DEV | FS_BINARY_MOUNTDATA, -}; -MODULE_ALIAS_FS("btrfs"); - -static int btrfs_control_open(struct inode *inode, struct file *file) -{ - /* - * The control file's private_data is used to hold the - * transaction when it is started and is used to keep - * track of whether a transaction is already in progress. - */ - file->private_data = NULL; - return 0; -} - -/* - * used by btrfsctl to scan devices when no FS is mounted - */ -static long btrfs_control_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct btrfs_ioctl_vol_args *vol; - struct btrfs_fs_devices *fs_devices; - int ret = -ENOTTY; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - vol = memdup_user((void __user *)arg, sizeof(*vol)); - if (IS_ERR(vol)) - return PTR_ERR(vol); - - switch (cmd) { - case BTRFS_IOC_SCAN_DEV: - ret = btrfs_scan_one_device(vol->name, FMODE_READ, - &btrfs_fs_type, &fs_devices); - break; - case BTRFS_IOC_DEVICES_READY: - ret = btrfs_scan_one_device(vol->name, FMODE_READ, - &btrfs_fs_type, &fs_devices); - if (ret) - break; - ret = !(fs_devices->num_devices == fs_devices->total_devices); - break; - case BTRFS_IOC_GET_SUPPORTED_FEATURES: - ret = btrfs_ioctl_get_supported_features((void __user*)arg); - break; - } - - kfree(vol); - return ret; -} - -static int btrfs_freeze(struct super_block *sb) -{ - struct btrfs_trans_handle *trans; - struct btrfs_root *root = btrfs_sb(sb)->tree_root; - - root->fs_info->fs_frozen = 1; - /* - * We don't need a barrier here, we'll wait for any transaction that - * could be in progress on other threads (and do delayed iputs that - * we want to avoid on a frozen filesystem), or do the commit - * ourselves. - */ - trans = btrfs_attach_transaction_barrier(root); - if (IS_ERR(trans)) { - /* no transaction, don't bother */ - if (PTR_ERR(trans) == -ENOENT) - return 0; - return PTR_ERR(trans); - } - return btrfs_commit_transaction(trans, root); -} - -static int btrfs_unfreeze(struct super_block *sb) -{ - struct btrfs_root *root = btrfs_sb(sb)->tree_root; - - root->fs_info->fs_frozen = 0; - return 0; -} - -static int btrfs_show_devname(struct seq_file *m, struct dentry *root) -{ - struct btrfs_fs_info *fs_info = btrfs_sb(root->d_sb); - struct btrfs_fs_devices *cur_devices; - struct btrfs_device *dev, *first_dev = NULL; - struct list_head *head; - struct rcu_string *name; - - mutex_lock(&fs_info->fs_devices->device_list_mutex); - cur_devices = fs_info->fs_devices; - while (cur_devices) { - head = &cur_devices->devices; - list_for_each_entry(dev, head, dev_list) { - if (dev->missing) - continue; - if (!dev->name) - continue; - if (!first_dev || dev->devid < first_dev->devid) - first_dev = dev; - } - cur_devices = cur_devices->seed; - } - - if (first_dev) { - rcu_read_lock(); - name = rcu_dereference(first_dev->name); - seq_escape(m, name->str, " \t\n\\"); - rcu_read_unlock(); - } else { - WARN_ON(1); - } - mutex_unlock(&fs_info->fs_devices->device_list_mutex); - return 0; -} - -static const struct super_operations btrfs_super_ops = { - .drop_inode = btrfs_drop_inode, - .evict_inode = btrfs_evict_inode, - .put_super = btrfs_put_super, - .sync_fs = btrfs_sync_fs, - .show_options = btrfs_show_options, - .show_devname = btrfs_show_devname, - .write_inode = btrfs_write_inode, - .alloc_inode = btrfs_alloc_inode, - .destroy_inode = btrfs_destroy_inode, - .statfs = btrfs_statfs, - .remount_fs = btrfs_remount, - .freeze_fs = btrfs_freeze, - .unfreeze_fs = btrfs_unfreeze, -}; - -static const struct file_operations btrfs_ctl_fops = { - .open = btrfs_control_open, - .unlocked_ioctl = btrfs_control_ioctl, - .compat_ioctl = btrfs_control_ioctl, - .owner = THIS_MODULE, - .llseek = noop_llseek, -}; - -static struct miscdevice btrfs_misc = { - .minor = BTRFS_MINOR, - .name = "btrfs-control", - .fops = &btrfs_ctl_fops -}; - -MODULE_ALIAS_MISCDEV(BTRFS_MINOR); -MODULE_ALIAS("devname:btrfs-control"); - -static int btrfs_interface_init(void) -{ - return misc_register(&btrfs_misc); -} - -static void btrfs_interface_exit(void) -{ - misc_deregister(&btrfs_misc); -} - -static void btrfs_print_mod_info(void) -{ - pr_info("Btrfs loaded, crc32c=%s" -#ifdef CONFIG_BTRFS_DEBUG - ", debug=on" -#endif -#ifdef CONFIG_BTRFS_ASSERT - ", assert=on" -#endif -#ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY - ", integrity-checker=on" -#endif - "\n", - btrfs_crc32c_impl()); -} - -static int __init init_btrfs_fs(void) -{ - int err; - - err = btrfs_hash_init(); - if (err) - return err; - - btrfs_props_init(); - - err = btrfs_init_sysfs(); - if (err) - goto free_hash; - - btrfs_init_compress(); - - err = btrfs_init_cachep(); - if (err) - goto free_compress; - - err = extent_io_init(); - if (err) - goto free_cachep; - - err = extent_map_init(); - if (err) - goto free_extent_io; - - err = ordered_data_init(); - if (err) - goto free_extent_map; - - err = btrfs_delayed_inode_init(); - if (err) - goto free_ordered_data; - - err = btrfs_auto_defrag_init(); - if (err) - goto free_delayed_inode; - - err = btrfs_delayed_ref_init(); - if (err) - goto free_auto_defrag; - - err = btrfs_prelim_ref_init(); - if (err) - goto free_delayed_ref; - - err = btrfs_end_io_wq_init(); - if (err) - goto free_prelim_ref; - - err = btrfs_interface_init(); - if (err) - goto free_end_io_wq; - - btrfs_init_lockdep(); - - btrfs_print_mod_info(); - - err = btrfs_run_sanity_tests(); - if (err) - goto unregister_ioctl; - - err = register_filesystem(&btrfs_fs_type); - if (err) - goto unregister_ioctl; - - return 0; - -unregister_ioctl: - btrfs_interface_exit(); -free_end_io_wq: - btrfs_end_io_wq_exit(); -free_prelim_ref: - btrfs_prelim_ref_exit(); -free_delayed_ref: - btrfs_delayed_ref_exit(); -free_auto_defrag: - btrfs_auto_defrag_exit(); -free_delayed_inode: - btrfs_delayed_inode_exit(); -free_ordered_data: - ordered_data_exit(); -free_extent_map: - extent_map_exit(); -free_extent_io: - extent_io_exit(); -free_cachep: - btrfs_destroy_cachep(); -free_compress: - btrfs_exit_compress(); - btrfs_exit_sysfs(); -free_hash: - btrfs_hash_exit(); - return err; -} - -static void __exit exit_btrfs_fs(void) -{ - btrfs_destroy_cachep(); - btrfs_delayed_ref_exit(); - btrfs_auto_defrag_exit(); - btrfs_delayed_inode_exit(); - btrfs_prelim_ref_exit(); - ordered_data_exit(); - extent_map_exit(); - extent_io_exit(); - btrfs_interface_exit(); - btrfs_end_io_wq_exit(); - unregister_filesystem(&btrfs_fs_type); - btrfs_exit_sysfs(); - btrfs_cleanup_fs_uuids(); - btrfs_exit_compress(); - btrfs_hash_exit(); -} - -late_initcall(init_btrfs_fs); -module_exit(exit_btrfs_fs) - -MODULE_LICENSE("GPL"); diff --git a/src/linux/fs/btrfs/sysfs.c b/src/linux/fs/btrfs/sysfs.c deleted file mode 100644 index 1f157fb..0000000 --- a/src/linux/fs/btrfs/sysfs.c +++ /dev/null @@ -1,888 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ctree.h" -#include "disk-io.h" -#include "transaction.h" -#include "sysfs.h" -#include "volumes.h" - -static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj); -static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj); - -static u64 get_features(struct btrfs_fs_info *fs_info, - enum btrfs_feature_set set) -{ - struct btrfs_super_block *disk_super = fs_info->super_copy; - if (set == FEAT_COMPAT) - return btrfs_super_compat_flags(disk_super); - else if (set == FEAT_COMPAT_RO) - return btrfs_super_compat_ro_flags(disk_super); - else - return btrfs_super_incompat_flags(disk_super); -} - -static void set_features(struct btrfs_fs_info *fs_info, - enum btrfs_feature_set set, u64 features) -{ - struct btrfs_super_block *disk_super = fs_info->super_copy; - if (set == FEAT_COMPAT) - btrfs_set_super_compat_flags(disk_super, features); - else if (set == FEAT_COMPAT_RO) - btrfs_set_super_compat_ro_flags(disk_super, features); - else - btrfs_set_super_incompat_flags(disk_super, features); -} - -static int can_modify_feature(struct btrfs_feature_attr *fa) -{ - int val = 0; - u64 set, clear; - switch (fa->feature_set) { - case FEAT_COMPAT: - set = BTRFS_FEATURE_COMPAT_SAFE_SET; - clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR; - break; - case FEAT_COMPAT_RO: - set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET; - clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR; - break; - case FEAT_INCOMPAT: - set = BTRFS_FEATURE_INCOMPAT_SAFE_SET; - clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR; - break; - default: - pr_warn("btrfs: sysfs: unknown feature set %d\n", - fa->feature_set); - return 0; - } - - if (set & fa->feature_bit) - val |= 1; - if (clear & fa->feature_bit) - val |= 2; - - return val; -} - -static ssize_t btrfs_feature_attr_show(struct kobject *kobj, - struct kobj_attribute *a, char *buf) -{ - int val = 0; - struct btrfs_fs_info *fs_info = to_fs_info(kobj); - struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a); - if (fs_info) { - u64 features = get_features(fs_info, fa->feature_set); - if (features & fa->feature_bit) - val = 1; - } else - val = can_modify_feature(fa); - - return snprintf(buf, PAGE_SIZE, "%d\n", val); -} - -static ssize_t btrfs_feature_attr_store(struct kobject *kobj, - struct kobj_attribute *a, - const char *buf, size_t count) -{ - struct btrfs_fs_info *fs_info; - struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a); - u64 features, set, clear; - unsigned long val; - int ret; - - fs_info = to_fs_info(kobj); - if (!fs_info) - return -EPERM; - - if (fs_info->sb->s_flags & MS_RDONLY) - return -EROFS; - - ret = kstrtoul(skip_spaces(buf), 0, &val); - if (ret) - return ret; - - if (fa->feature_set == FEAT_COMPAT) { - set = BTRFS_FEATURE_COMPAT_SAFE_SET; - clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR; - } else if (fa->feature_set == FEAT_COMPAT_RO) { - set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET; - clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR; - } else { - set = BTRFS_FEATURE_INCOMPAT_SAFE_SET; - clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR; - } - - features = get_features(fs_info, fa->feature_set); - - /* Nothing to do */ - if ((val && (features & fa->feature_bit)) || - (!val && !(features & fa->feature_bit))) - return count; - - if ((val && !(set & fa->feature_bit)) || - (!val && !(clear & fa->feature_bit))) { - btrfs_info(fs_info, - "%sabling feature %s on mounted fs is not supported.", - val ? "En" : "Dis", fa->kobj_attr.attr.name); - return -EPERM; - } - - btrfs_info(fs_info, "%s %s feature flag", - val ? "Setting" : "Clearing", fa->kobj_attr.attr.name); - - spin_lock(&fs_info->super_lock); - features = get_features(fs_info, fa->feature_set); - if (val) - features |= fa->feature_bit; - else - features &= ~fa->feature_bit; - set_features(fs_info, fa->feature_set, features); - spin_unlock(&fs_info->super_lock); - - /* - * We don't want to do full transaction commit from inside sysfs - */ - btrfs_set_pending(fs_info, COMMIT); - wake_up_process(fs_info->transaction_kthread); - - return count; -} - -static umode_t btrfs_feature_visible(struct kobject *kobj, - struct attribute *attr, int unused) -{ - struct btrfs_fs_info *fs_info = to_fs_info(kobj); - umode_t mode = attr->mode; - - if (fs_info) { - struct btrfs_feature_attr *fa; - u64 features; - - fa = attr_to_btrfs_feature_attr(attr); - features = get_features(fs_info, fa->feature_set); - - if (can_modify_feature(fa)) - mode |= S_IWUSR; - else if (!(features & fa->feature_bit)) - mode = 0; - } - - return mode; -} - -BTRFS_FEAT_ATTR_INCOMPAT(mixed_backref, MIXED_BACKREF); -BTRFS_FEAT_ATTR_INCOMPAT(default_subvol, DEFAULT_SUBVOL); -BTRFS_FEAT_ATTR_INCOMPAT(mixed_groups, MIXED_GROUPS); -BTRFS_FEAT_ATTR_INCOMPAT(compress_lzo, COMPRESS_LZO); -BTRFS_FEAT_ATTR_INCOMPAT(big_metadata, BIG_METADATA); -BTRFS_FEAT_ATTR_INCOMPAT(extended_iref, EXTENDED_IREF); -BTRFS_FEAT_ATTR_INCOMPAT(raid56, RAID56); -BTRFS_FEAT_ATTR_INCOMPAT(skinny_metadata, SKINNY_METADATA); -BTRFS_FEAT_ATTR_INCOMPAT(no_holes, NO_HOLES); -BTRFS_FEAT_ATTR_COMPAT_RO(free_space_tree, FREE_SPACE_TREE); - -static struct attribute *btrfs_supported_feature_attrs[] = { - BTRFS_FEAT_ATTR_PTR(mixed_backref), - BTRFS_FEAT_ATTR_PTR(default_subvol), - BTRFS_FEAT_ATTR_PTR(mixed_groups), - BTRFS_FEAT_ATTR_PTR(compress_lzo), - BTRFS_FEAT_ATTR_PTR(big_metadata), - BTRFS_FEAT_ATTR_PTR(extended_iref), - BTRFS_FEAT_ATTR_PTR(raid56), - BTRFS_FEAT_ATTR_PTR(skinny_metadata), - BTRFS_FEAT_ATTR_PTR(no_holes), - BTRFS_FEAT_ATTR_PTR(free_space_tree), - NULL -}; - -static const struct attribute_group btrfs_feature_attr_group = { - .name = "features", - .is_visible = btrfs_feature_visible, - .attrs = btrfs_supported_feature_attrs, -}; - -static ssize_t btrfs_show_u64(u64 *value_ptr, spinlock_t *lock, char *buf) -{ - u64 val; - if (lock) - spin_lock(lock); - val = *value_ptr; - if (lock) - spin_unlock(lock); - return snprintf(buf, PAGE_SIZE, "%llu\n", val); -} - -static ssize_t global_rsv_size_show(struct kobject *kobj, - struct kobj_attribute *ka, char *buf) -{ - struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); - struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; - return btrfs_show_u64(&block_rsv->size, &block_rsv->lock, buf); -} -BTRFS_ATTR(global_rsv_size, global_rsv_size_show); - -static ssize_t global_rsv_reserved_show(struct kobject *kobj, - struct kobj_attribute *a, char *buf) -{ - struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent); - struct btrfs_block_rsv *block_rsv = &fs_info->global_block_rsv; - return btrfs_show_u64(&block_rsv->reserved, &block_rsv->lock, buf); -} -BTRFS_ATTR(global_rsv_reserved, global_rsv_reserved_show); - -#define to_space_info(_kobj) container_of(_kobj, struct btrfs_space_info, kobj) -#define to_raid_kobj(_kobj) container_of(_kobj, struct raid_kobject, kobj) - -static ssize_t raid_bytes_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf); -BTRFS_RAID_ATTR(total_bytes, raid_bytes_show); -BTRFS_RAID_ATTR(used_bytes, raid_bytes_show); - -static ssize_t raid_bytes_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) - -{ - struct btrfs_space_info *sinfo = to_space_info(kobj->parent); - struct btrfs_block_group_cache *block_group; - int index = to_raid_kobj(kobj)->raid_type; - u64 val = 0; - - down_read(&sinfo->groups_sem); - list_for_each_entry(block_group, &sinfo->block_groups[index], list) { - if (&attr->attr == BTRFS_RAID_ATTR_PTR(total_bytes)) - val += block_group->key.offset; - else - val += btrfs_block_group_used(&block_group->item); - } - up_read(&sinfo->groups_sem); - return snprintf(buf, PAGE_SIZE, "%llu\n", val); -} - -static struct attribute *raid_attributes[] = { - BTRFS_RAID_ATTR_PTR(total_bytes), - BTRFS_RAID_ATTR_PTR(used_bytes), - NULL -}; - -static void release_raid_kobj(struct kobject *kobj) -{ - kfree(to_raid_kobj(kobj)); -} - -struct kobj_type btrfs_raid_ktype = { - .sysfs_ops = &kobj_sysfs_ops, - .release = release_raid_kobj, - .default_attrs = raid_attributes, -}; - -#define SPACE_INFO_ATTR(field) \ -static ssize_t btrfs_space_info_show_##field(struct kobject *kobj, \ - struct kobj_attribute *a, \ - char *buf) \ -{ \ - struct btrfs_space_info *sinfo = to_space_info(kobj); \ - return btrfs_show_u64(&sinfo->field, &sinfo->lock, buf); \ -} \ -BTRFS_ATTR(field, btrfs_space_info_show_##field) - -static ssize_t btrfs_space_info_show_total_bytes_pinned(struct kobject *kobj, - struct kobj_attribute *a, - char *buf) -{ - struct btrfs_space_info *sinfo = to_space_info(kobj); - s64 val = percpu_counter_sum(&sinfo->total_bytes_pinned); - return snprintf(buf, PAGE_SIZE, "%lld\n", val); -} - -SPACE_INFO_ATTR(flags); -SPACE_INFO_ATTR(total_bytes); -SPACE_INFO_ATTR(bytes_used); -SPACE_INFO_ATTR(bytes_pinned); -SPACE_INFO_ATTR(bytes_reserved); -SPACE_INFO_ATTR(bytes_may_use); -SPACE_INFO_ATTR(bytes_readonly); -SPACE_INFO_ATTR(disk_used); -SPACE_INFO_ATTR(disk_total); -BTRFS_ATTR(total_bytes_pinned, btrfs_space_info_show_total_bytes_pinned); - -static struct attribute *space_info_attrs[] = { - BTRFS_ATTR_PTR(flags), - BTRFS_ATTR_PTR(total_bytes), - BTRFS_ATTR_PTR(bytes_used), - BTRFS_ATTR_PTR(bytes_pinned), - BTRFS_ATTR_PTR(bytes_reserved), - BTRFS_ATTR_PTR(bytes_may_use), - BTRFS_ATTR_PTR(bytes_readonly), - BTRFS_ATTR_PTR(disk_used), - BTRFS_ATTR_PTR(disk_total), - BTRFS_ATTR_PTR(total_bytes_pinned), - NULL, -}; - -static void space_info_release(struct kobject *kobj) -{ - struct btrfs_space_info *sinfo = to_space_info(kobj); - percpu_counter_destroy(&sinfo->total_bytes_pinned); - kfree(sinfo); -} - -struct kobj_type space_info_ktype = { - .sysfs_ops = &kobj_sysfs_ops, - .release = space_info_release, - .default_attrs = space_info_attrs, -}; - -static const struct attribute *allocation_attrs[] = { - BTRFS_ATTR_PTR(global_rsv_reserved), - BTRFS_ATTR_PTR(global_rsv_size), - NULL, -}; - -static ssize_t btrfs_label_show(struct kobject *kobj, - struct kobj_attribute *a, char *buf) -{ - struct btrfs_fs_info *fs_info = to_fs_info(kobj); - char *label = fs_info->super_copy->label; - ssize_t ret; - - spin_lock(&fs_info->super_lock); - ret = snprintf(buf, PAGE_SIZE, label[0] ? "%s\n" : "%s", label); - spin_unlock(&fs_info->super_lock); - - return ret; -} - -static ssize_t btrfs_label_store(struct kobject *kobj, - struct kobj_attribute *a, - const char *buf, size_t len) -{ - struct btrfs_fs_info *fs_info = to_fs_info(kobj); - size_t p_len; - - if (!fs_info) - return -EPERM; - - if (fs_info->sb->s_flags & MS_RDONLY) - return -EROFS; - - /* - * p_len is the len until the first occurrence of either - * '\n' or '\0' - */ - p_len = strcspn(buf, "\n"); - - if (p_len >= BTRFS_LABEL_SIZE) - return -EINVAL; - - spin_lock(&fs_info->super_lock); - memset(fs_info->super_copy->label, 0, BTRFS_LABEL_SIZE); - memcpy(fs_info->super_copy->label, buf, p_len); - spin_unlock(&fs_info->super_lock); - - /* - * We don't want to do full transaction commit from inside sysfs - */ - btrfs_set_pending(fs_info, COMMIT); - wake_up_process(fs_info->transaction_kthread); - - return len; -} -BTRFS_ATTR_RW(label, btrfs_label_show, btrfs_label_store); - -static ssize_t btrfs_nodesize_show(struct kobject *kobj, - struct kobj_attribute *a, char *buf) -{ - struct btrfs_fs_info *fs_info = to_fs_info(kobj); - - return snprintf(buf, PAGE_SIZE, "%u\n", fs_info->super_copy->nodesize); -} - -BTRFS_ATTR(nodesize, btrfs_nodesize_show); - -static ssize_t btrfs_sectorsize_show(struct kobject *kobj, - struct kobj_attribute *a, char *buf) -{ - struct btrfs_fs_info *fs_info = to_fs_info(kobj); - - return snprintf(buf, PAGE_SIZE, "%u\n", - fs_info->super_copy->sectorsize); -} - -BTRFS_ATTR(sectorsize, btrfs_sectorsize_show); - -static ssize_t btrfs_clone_alignment_show(struct kobject *kobj, - struct kobj_attribute *a, char *buf) -{ - struct btrfs_fs_info *fs_info = to_fs_info(kobj); - - return snprintf(buf, PAGE_SIZE, "%u\n", - fs_info->super_copy->sectorsize); -} - -BTRFS_ATTR(clone_alignment, btrfs_clone_alignment_show); - -static const struct attribute *btrfs_attrs[] = { - BTRFS_ATTR_PTR(label), - BTRFS_ATTR_PTR(nodesize), - BTRFS_ATTR_PTR(sectorsize), - BTRFS_ATTR_PTR(clone_alignment), - NULL, -}; - -static void btrfs_release_fsid_kobj(struct kobject *kobj) -{ - struct btrfs_fs_devices *fs_devs = to_fs_devs(kobj); - - memset(&fs_devs->fsid_kobj, 0, sizeof(struct kobject)); - complete(&fs_devs->kobj_unregister); -} - -static struct kobj_type btrfs_ktype = { - .sysfs_ops = &kobj_sysfs_ops, - .release = btrfs_release_fsid_kobj, -}; - -static inline struct btrfs_fs_devices *to_fs_devs(struct kobject *kobj) -{ - if (kobj->ktype != &btrfs_ktype) - return NULL; - return container_of(kobj, struct btrfs_fs_devices, fsid_kobj); -} - -static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj) -{ - if (kobj->ktype != &btrfs_ktype) - return NULL; - return to_fs_devs(kobj)->fs_info; -} - -#define NUM_FEATURE_BITS 64 -static char btrfs_unknown_feature_names[3][NUM_FEATURE_BITS][13]; -static struct btrfs_feature_attr btrfs_feature_attrs[3][NUM_FEATURE_BITS]; - -static const u64 supported_feature_masks[3] = { - [FEAT_COMPAT] = BTRFS_FEATURE_COMPAT_SUPP, - [FEAT_COMPAT_RO] = BTRFS_FEATURE_COMPAT_RO_SUPP, - [FEAT_INCOMPAT] = BTRFS_FEATURE_INCOMPAT_SUPP, -}; - -static int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add) -{ - int set; - - for (set = 0; set < FEAT_MAX; set++) { - int i; - struct attribute *attrs[2]; - struct attribute_group agroup = { - .name = "features", - .attrs = attrs, - }; - u64 features = get_features(fs_info, set); - features &= ~supported_feature_masks[set]; - - if (!features) - continue; - - attrs[1] = NULL; - for (i = 0; i < NUM_FEATURE_BITS; i++) { - struct btrfs_feature_attr *fa; - - if (!(features & (1ULL << i))) - continue; - - fa = &btrfs_feature_attrs[set][i]; - attrs[0] = &fa->kobj_attr.attr; - if (add) { - int ret; - ret = sysfs_merge_group(&fs_info->fs_devices->fsid_kobj, - &agroup); - if (ret) - return ret; - } else - sysfs_unmerge_group(&fs_info->fs_devices->fsid_kobj, - &agroup); - } - - } - return 0; -} - -static void __btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) -{ - if (fs_devs->device_dir_kobj) { - kobject_del(fs_devs->device_dir_kobj); - kobject_put(fs_devs->device_dir_kobj); - fs_devs->device_dir_kobj = NULL; - } - - if (fs_devs->fsid_kobj.state_initialized) { - kobject_del(&fs_devs->fsid_kobj); - kobject_put(&fs_devs->fsid_kobj); - wait_for_completion(&fs_devs->kobj_unregister); - } -} - -/* when fs_devs is NULL it will remove all fsid kobject */ -void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs) -{ - struct list_head *fs_uuids = btrfs_get_fs_uuids(); - - if (fs_devs) { - __btrfs_sysfs_remove_fsid(fs_devs); - return; - } - - list_for_each_entry(fs_devs, fs_uuids, list) { - __btrfs_sysfs_remove_fsid(fs_devs); - } -} - -void btrfs_sysfs_remove_mounted(struct btrfs_fs_info *fs_info) -{ - btrfs_reset_fs_info_ptr(fs_info); - - if (fs_info->space_info_kobj) { - sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs); - kobject_del(fs_info->space_info_kobj); - kobject_put(fs_info->space_info_kobj); - } - addrm_unknown_feature_attrs(fs_info, false); - sysfs_remove_group(&fs_info->fs_devices->fsid_kobj, &btrfs_feature_attr_group); - sysfs_remove_files(&fs_info->fs_devices->fsid_kobj, btrfs_attrs); - btrfs_sysfs_rm_device_link(fs_info->fs_devices, NULL); -} - -const char * const btrfs_feature_set_names[3] = { - [FEAT_COMPAT] = "compat", - [FEAT_COMPAT_RO] = "compat_ro", - [FEAT_INCOMPAT] = "incompat", -}; - -char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags) -{ - size_t bufsize = 4096; /* safe max, 64 names * 64 bytes */ - int len = 0; - int i; - char *str; - - str = kmalloc(bufsize, GFP_KERNEL); - if (!str) - return str; - - for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) { - const char *name; - - if (!(flags & (1ULL << i))) - continue; - - name = btrfs_feature_attrs[set][i].kobj_attr.attr.name; - len += snprintf(str + len, bufsize - len, "%s%s", - len ? "," : "", name); - } - - return str; -} - -static void init_feature_attrs(void) -{ - struct btrfs_feature_attr *fa; - int set, i; - - BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names) != - ARRAY_SIZE(btrfs_feature_attrs)); - BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names[0]) != - ARRAY_SIZE(btrfs_feature_attrs[0])); - - memset(btrfs_feature_attrs, 0, sizeof(btrfs_feature_attrs)); - memset(btrfs_unknown_feature_names, 0, - sizeof(btrfs_unknown_feature_names)); - - for (i = 0; btrfs_supported_feature_attrs[i]; i++) { - struct btrfs_feature_attr *sfa; - struct attribute *a = btrfs_supported_feature_attrs[i]; - int bit; - sfa = attr_to_btrfs_feature_attr(a); - bit = ilog2(sfa->feature_bit); - fa = &btrfs_feature_attrs[sfa->feature_set][bit]; - - fa->kobj_attr.attr.name = sfa->kobj_attr.attr.name; - } - - for (set = 0; set < FEAT_MAX; set++) { - for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) { - char *name = btrfs_unknown_feature_names[set][i]; - fa = &btrfs_feature_attrs[set][i]; - - if (fa->kobj_attr.attr.name) - continue; - - snprintf(name, 13, "%s:%u", - btrfs_feature_set_names[set], i); - - fa->kobj_attr.attr.name = name; - fa->kobj_attr.attr.mode = S_IRUGO; - fa->feature_set = set; - fa->feature_bit = 1ULL << i; - } - } -} - -/* when one_device is NULL, it removes all device links */ - -int btrfs_sysfs_rm_device_link(struct btrfs_fs_devices *fs_devices, - struct btrfs_device *one_device) -{ - struct hd_struct *disk; - struct kobject *disk_kobj; - - if (!fs_devices->device_dir_kobj) - return -EINVAL; - - if (one_device && one_device->bdev) { - disk = one_device->bdev->bd_part; - disk_kobj = &part_to_dev(disk)->kobj; - - sysfs_remove_link(fs_devices->device_dir_kobj, - disk_kobj->name); - } - - if (one_device) - return 0; - - list_for_each_entry(one_device, - &fs_devices->devices, dev_list) { - if (!one_device->bdev) - continue; - disk = one_device->bdev->bd_part; - disk_kobj = &part_to_dev(disk)->kobj; - - sysfs_remove_link(fs_devices->device_dir_kobj, - disk_kobj->name); - } - - return 0; -} - -int btrfs_sysfs_add_device(struct btrfs_fs_devices *fs_devs) -{ - if (!fs_devs->device_dir_kobj) - fs_devs->device_dir_kobj = kobject_create_and_add("devices", - &fs_devs->fsid_kobj); - - if (!fs_devs->device_dir_kobj) - return -ENOMEM; - - return 0; -} - -int btrfs_sysfs_add_device_link(struct btrfs_fs_devices *fs_devices, - struct btrfs_device *one_device) -{ - int error = 0; - struct btrfs_device *dev; - - list_for_each_entry(dev, &fs_devices->devices, dev_list) { - struct hd_struct *disk; - struct kobject *disk_kobj; - - if (!dev->bdev) - continue; - - if (one_device && one_device != dev) - continue; - - disk = dev->bdev->bd_part; - disk_kobj = &part_to_dev(disk)->kobj; - - error = sysfs_create_link(fs_devices->device_dir_kobj, - disk_kobj, disk_kobj->name); - if (error) - break; - } - - return error; -} - -/* /sys/fs/btrfs/ entry */ -static struct kset *btrfs_kset; - -/* /sys/kernel/debug/btrfs */ -static struct dentry *btrfs_debugfs_root_dentry; - -/* Debugging tunables and exported data */ -u64 btrfs_debugfs_test; - -/* - * Can be called by the device discovery thread. - * And parent can be specified for seed device - */ -int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs, - struct kobject *parent) -{ - int error; - - init_completion(&fs_devs->kobj_unregister); - fs_devs->fsid_kobj.kset = btrfs_kset; - error = kobject_init_and_add(&fs_devs->fsid_kobj, - &btrfs_ktype, parent, "%pU", fs_devs->fsid); - return error; -} - -int btrfs_sysfs_add_mounted(struct btrfs_fs_info *fs_info) -{ - int error; - struct btrfs_fs_devices *fs_devs = fs_info->fs_devices; - struct kobject *fsid_kobj = &fs_devs->fsid_kobj; - - btrfs_set_fs_info_ptr(fs_info); - - error = btrfs_sysfs_add_device_link(fs_devs, NULL); - if (error) - return error; - - error = sysfs_create_files(fsid_kobj, btrfs_attrs); - if (error) { - btrfs_sysfs_rm_device_link(fs_devs, NULL); - return error; - } - - error = sysfs_create_group(fsid_kobj, - &btrfs_feature_attr_group); - if (error) - goto failure; - - error = addrm_unknown_feature_attrs(fs_info, true); - if (error) - goto failure; - - fs_info->space_info_kobj = kobject_create_and_add("allocation", - fsid_kobj); - if (!fs_info->space_info_kobj) { - error = -ENOMEM; - goto failure; - } - - error = sysfs_create_files(fs_info->space_info_kobj, allocation_attrs); - if (error) - goto failure; - - return 0; -failure: - btrfs_sysfs_remove_mounted(fs_info); - return error; -} - - -/* - * Change per-fs features in /sys/fs/btrfs/UUID/features to match current - * values in superblock. Call after any changes to incompat/compat_ro flags - */ -void btrfs_sysfs_feature_update(struct btrfs_fs_info *fs_info, - u64 bit, enum btrfs_feature_set set) -{ - struct btrfs_fs_devices *fs_devs; - struct kobject *fsid_kobj; - u64 features; - int ret; - - if (!fs_info) - return; - - features = get_features(fs_info, set); - ASSERT(bit & supported_feature_masks[set]); - - fs_devs = fs_info->fs_devices; - fsid_kobj = &fs_devs->fsid_kobj; - - if (!fsid_kobj->state_initialized) - return; - - /* - * FIXME: this is too heavy to update just one value, ideally we'd like - * to use sysfs_update_group but some refactoring is needed first. - */ - sysfs_remove_group(fsid_kobj, &btrfs_feature_attr_group); - ret = sysfs_create_group(fsid_kobj, &btrfs_feature_attr_group); -} - -static int btrfs_init_debugfs(void) -{ -#ifdef CONFIG_DEBUG_FS - btrfs_debugfs_root_dentry = debugfs_create_dir("btrfs", NULL); - if (!btrfs_debugfs_root_dentry) - return -ENOMEM; - - /* - * Example code, how to export data through debugfs. - * - * file: /sys/kernel/debug/btrfs/test - * contents of: btrfs_debugfs_test - */ -#ifdef CONFIG_BTRFS_DEBUG - debugfs_create_u64("test", S_IRUGO | S_IWUSR, btrfs_debugfs_root_dentry, - &btrfs_debugfs_test); -#endif - -#endif - return 0; -} - -int btrfs_init_sysfs(void) -{ - int ret; - - btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj); - if (!btrfs_kset) - return -ENOMEM; - - ret = btrfs_init_debugfs(); - if (ret) - goto out1; - - init_feature_attrs(); - ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); - if (ret) - goto out2; - - return 0; -out2: - debugfs_remove_recursive(btrfs_debugfs_root_dentry); -out1: - kset_unregister(btrfs_kset); - - return ret; -} - -void btrfs_exit_sysfs(void) -{ - sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group); - kset_unregister(btrfs_kset); - debugfs_remove_recursive(btrfs_debugfs_root_dentry); -} - diff --git a/src/linux/fs/btrfs/sysfs.h b/src/linux/fs/btrfs/sysfs.h deleted file mode 100644 index d7da1a4..0000000 --- a/src/linux/fs/btrfs/sysfs.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef _BTRFS_SYSFS_H_ -#define _BTRFS_SYSFS_H_ - -/* - * Data exported through sysfs - */ -extern u64 btrfs_debugfs_test; - -enum btrfs_feature_set { - FEAT_COMPAT, - FEAT_COMPAT_RO, - FEAT_INCOMPAT, - FEAT_MAX -}; - -#define __INIT_KOBJ_ATTR(_name, _mode, _show, _store) \ -{ \ - .attr = { .name = __stringify(_name), .mode = _mode }, \ - .show = _show, \ - .store = _store, \ -} - -#define BTRFS_ATTR_RW(_name, _show, _store) \ - static struct kobj_attribute btrfs_attr_##_name = \ - __INIT_KOBJ_ATTR(_name, 0644, _show, _store) - -#define BTRFS_ATTR(_name, _show) \ - static struct kobj_attribute btrfs_attr_##_name = \ - __INIT_KOBJ_ATTR(_name, 0444, _show, NULL) - -#define BTRFS_ATTR_PTR(_name) (&btrfs_attr_##_name.attr) - -#define BTRFS_RAID_ATTR(_name, _show) \ - static struct kobj_attribute btrfs_raid_attr_##_name = \ - __INIT_KOBJ_ATTR(_name, 0444, _show, NULL) - -#define BTRFS_RAID_ATTR_PTR(_name) (&btrfs_raid_attr_##_name.attr) - - -struct btrfs_feature_attr { - struct kobj_attribute kobj_attr; - enum btrfs_feature_set feature_set; - u64 feature_bit; -}; - -#define BTRFS_FEAT_ATTR(_name, _feature_set, _prefix, _feature_bit) \ -static struct btrfs_feature_attr btrfs_attr_##_name = { \ - .kobj_attr = __INIT_KOBJ_ATTR(_name, S_IRUGO, \ - btrfs_feature_attr_show, \ - btrfs_feature_attr_store), \ - .feature_set = _feature_set, \ - .feature_bit = _prefix ##_## _feature_bit, \ -} -#define BTRFS_FEAT_ATTR_PTR(_name) (&btrfs_attr_##_name.kobj_attr.attr) - -#define BTRFS_FEAT_ATTR_COMPAT(name, feature) \ - BTRFS_FEAT_ATTR(name, FEAT_COMPAT, BTRFS_FEATURE_COMPAT, feature) -#define BTRFS_FEAT_ATTR_COMPAT_RO(name, feature) \ - BTRFS_FEAT_ATTR(name, FEAT_COMPAT_RO, BTRFS_FEATURE_COMPAT_RO, feature) -#define BTRFS_FEAT_ATTR_INCOMPAT(name, feature) \ - BTRFS_FEAT_ATTR(name, FEAT_INCOMPAT, BTRFS_FEATURE_INCOMPAT, feature) - -/* convert from attribute */ -static inline struct btrfs_feature_attr * -to_btrfs_feature_attr(struct kobj_attribute *a) -{ - return container_of(a, struct btrfs_feature_attr, kobj_attr); -} - -static inline struct kobj_attribute *attr_to_btrfs_attr(struct attribute *attr) -{ - return container_of(attr, struct kobj_attribute, attr); -} - -static inline struct btrfs_feature_attr * -attr_to_btrfs_feature_attr(struct attribute *attr) -{ - return to_btrfs_feature_attr(attr_to_btrfs_attr(attr)); -} - -char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags); -extern const char * const btrfs_feature_set_names[3]; -extern struct kobj_type space_info_ktype; -extern struct kobj_type btrfs_raid_ktype; -int btrfs_sysfs_add_device_link(struct btrfs_fs_devices *fs_devices, - struct btrfs_device *one_device); -int btrfs_sysfs_rm_device_link(struct btrfs_fs_devices *fs_devices, - struct btrfs_device *one_device); -int btrfs_sysfs_add_fsid(struct btrfs_fs_devices *fs_devs, - struct kobject *parent); -int btrfs_sysfs_add_device(struct btrfs_fs_devices *fs_devs); -void btrfs_sysfs_remove_fsid(struct btrfs_fs_devices *fs_devs); -void btrfs_sysfs_feature_update(struct btrfs_fs_info *fs_info, - u64 bit, enum btrfs_feature_set set); - -#endif /* _BTRFS_SYSFS_H_ */ diff --git a/src/linux/fs/btrfs/tests/btrfs-tests.h b/src/linux/fs/btrfs/tests/btrfs-tests.h deleted file mode 100644 index b17ffbe..0000000 --- a/src/linux/fs/btrfs/tests/btrfs-tests.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2013 Fusion IO. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __BTRFS_TESTS -#define __BTRFS_TESTS - -#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS -int btrfs_run_sanity_tests(void); - -#define test_msg(fmt, ...) pr_info("BTRFS: selftest: " fmt, ##__VA_ARGS__) - -struct btrfs_root; -struct btrfs_trans_handle; - -int btrfs_test_extent_buffer_operations(u32 sectorsize, u32 nodesize); -int btrfs_test_free_space_cache(u32 sectorsize, u32 nodesize); -int btrfs_test_extent_io(u32 sectorsize, u32 nodesize); -int btrfs_test_inodes(u32 sectorsize, u32 nodesize); -int btrfs_test_qgroups(u32 sectorsize, u32 nodesize); -int btrfs_test_free_space_tree(u32 sectorsize, u32 nodesize); -struct inode *btrfs_new_test_inode(void); -struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(void); -void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info); -void btrfs_free_dummy_root(struct btrfs_root *root); -struct btrfs_block_group_cache * -btrfs_alloc_dummy_block_group(unsigned long length, u32 sectorsize); -void btrfs_free_dummy_block_group(struct btrfs_block_group_cache *cache); -void btrfs_init_dummy_trans(struct btrfs_trans_handle *trans); -#else -static inline int btrfs_run_sanity_tests(void) -{ - return 0; -} -#endif - -#endif diff --git a/src/linux/fs/btrfs/transaction.c b/src/linux/fs/btrfs/transaction.c deleted file mode 100644 index 9517de0..0000000 --- a/src/linux/fs/btrfs/transaction.c +++ /dev/null @@ -1,2366 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "ctree.h" -#include "disk-io.h" -#include "transaction.h" -#include "locking.h" -#include "tree-log.h" -#include "inode-map.h" -#include "volumes.h" -#include "dev-replace.h" -#include "qgroup.h" - -#define BTRFS_ROOT_TRANS_TAG 0 - -static const unsigned int btrfs_blocked_trans_types[TRANS_STATE_MAX] = { - [TRANS_STATE_RUNNING] = 0U, - [TRANS_STATE_BLOCKED] = (__TRANS_USERSPACE | - __TRANS_START), - [TRANS_STATE_COMMIT_START] = (__TRANS_USERSPACE | - __TRANS_START | - __TRANS_ATTACH), - [TRANS_STATE_COMMIT_DOING] = (__TRANS_USERSPACE | - __TRANS_START | - __TRANS_ATTACH | - __TRANS_JOIN), - [TRANS_STATE_UNBLOCKED] = (__TRANS_USERSPACE | - __TRANS_START | - __TRANS_ATTACH | - __TRANS_JOIN | - __TRANS_JOIN_NOLOCK), - [TRANS_STATE_COMPLETED] = (__TRANS_USERSPACE | - __TRANS_START | - __TRANS_ATTACH | - __TRANS_JOIN | - __TRANS_JOIN_NOLOCK), -}; - -void btrfs_put_transaction(struct btrfs_transaction *transaction) -{ - WARN_ON(atomic_read(&transaction->use_count) == 0); - if (atomic_dec_and_test(&transaction->use_count)) { - BUG_ON(!list_empty(&transaction->list)); - WARN_ON(!RB_EMPTY_ROOT(&transaction->delayed_refs.href_root)); - if (transaction->delayed_refs.pending_csums) - btrfs_err(transaction->fs_info, - "pending csums is %llu", - transaction->delayed_refs.pending_csums); - while (!list_empty(&transaction->pending_chunks)) { - struct extent_map *em; - - em = list_first_entry(&transaction->pending_chunks, - struct extent_map, list); - list_del_init(&em->list); - free_extent_map(em); - } - /* - * If any block groups are found in ->deleted_bgs then it's - * because the transaction was aborted and a commit did not - * happen (things failed before writing the new superblock - * and calling btrfs_finish_extent_commit()), so we can not - * discard the physical locations of the block groups. - */ - while (!list_empty(&transaction->deleted_bgs)) { - struct btrfs_block_group_cache *cache; - - cache = list_first_entry(&transaction->deleted_bgs, - struct btrfs_block_group_cache, - bg_list); - list_del_init(&cache->bg_list); - btrfs_put_block_group_trimming(cache); - btrfs_put_block_group(cache); - } - kmem_cache_free(btrfs_transaction_cachep, transaction); - } -} - -static void clear_btree_io_tree(struct extent_io_tree *tree) -{ - spin_lock(&tree->lock); - /* - * Do a single barrier for the waitqueue_active check here, the state - * of the waitqueue should not change once clear_btree_io_tree is - * called. - */ - smp_mb(); - while (!RB_EMPTY_ROOT(&tree->state)) { - struct rb_node *node; - struct extent_state *state; - - node = rb_first(&tree->state); - state = rb_entry(node, struct extent_state, rb_node); - rb_erase(&state->rb_node, &tree->state); - RB_CLEAR_NODE(&state->rb_node); - /* - * btree io trees aren't supposed to have tasks waiting for - * changes in the flags of extent states ever. - */ - ASSERT(!waitqueue_active(&state->wq)); - free_extent_state(state); - - cond_resched_lock(&tree->lock); - } - spin_unlock(&tree->lock); -} - -static noinline void switch_commit_roots(struct btrfs_transaction *trans, - struct btrfs_fs_info *fs_info) -{ - struct btrfs_root *root, *tmp; - - down_write(&fs_info->commit_root_sem); - list_for_each_entry_safe(root, tmp, &trans->switch_commits, - dirty_list) { - list_del_init(&root->dirty_list); - free_extent_buffer(root->commit_root); - root->commit_root = btrfs_root_node(root); - if (is_fstree(root->objectid)) - btrfs_unpin_free_ino(root); - clear_btree_io_tree(&root->dirty_log_pages); - } - - /* We can free old roots now. */ - spin_lock(&trans->dropped_roots_lock); - while (!list_empty(&trans->dropped_roots)) { - root = list_first_entry(&trans->dropped_roots, - struct btrfs_root, root_list); - list_del_init(&root->root_list); - spin_unlock(&trans->dropped_roots_lock); - btrfs_drop_and_free_fs_root(fs_info, root); - spin_lock(&trans->dropped_roots_lock); - } - spin_unlock(&trans->dropped_roots_lock); - up_write(&fs_info->commit_root_sem); -} - -static inline void extwriter_counter_inc(struct btrfs_transaction *trans, - unsigned int type) -{ - if (type & TRANS_EXTWRITERS) - atomic_inc(&trans->num_extwriters); -} - -static inline void extwriter_counter_dec(struct btrfs_transaction *trans, - unsigned int type) -{ - if (type & TRANS_EXTWRITERS) - atomic_dec(&trans->num_extwriters); -} - -static inline void extwriter_counter_init(struct btrfs_transaction *trans, - unsigned int type) -{ - atomic_set(&trans->num_extwriters, ((type & TRANS_EXTWRITERS) ? 1 : 0)); -} - -static inline int extwriter_counter_read(struct btrfs_transaction *trans) -{ - return atomic_read(&trans->num_extwriters); -} - -/* - * either allocate a new transaction or hop into the existing one - */ -static noinline int join_transaction(struct btrfs_root *root, unsigned int type) -{ - struct btrfs_transaction *cur_trans; - struct btrfs_fs_info *fs_info = root->fs_info; - - spin_lock(&fs_info->trans_lock); -loop: - /* The file system has been taken offline. No new transactions. */ - if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) { - spin_unlock(&fs_info->trans_lock); - return -EROFS; - } - - cur_trans = fs_info->running_transaction; - if (cur_trans) { - if (cur_trans->aborted) { - spin_unlock(&fs_info->trans_lock); - return cur_trans->aborted; - } - if (btrfs_blocked_trans_types[cur_trans->state] & type) { - spin_unlock(&fs_info->trans_lock); - return -EBUSY; - } - atomic_inc(&cur_trans->use_count); - atomic_inc(&cur_trans->num_writers); - extwriter_counter_inc(cur_trans, type); - spin_unlock(&fs_info->trans_lock); - return 0; - } - spin_unlock(&fs_info->trans_lock); - - /* - * If we are ATTACH, we just want to catch the current transaction, - * and commit it. If there is no transaction, just return ENOENT. - */ - if (type == TRANS_ATTACH) - return -ENOENT; - - /* - * JOIN_NOLOCK only happens during the transaction commit, so - * it is impossible that ->running_transaction is NULL - */ - BUG_ON(type == TRANS_JOIN_NOLOCK); - - cur_trans = kmem_cache_alloc(btrfs_transaction_cachep, GFP_NOFS); - if (!cur_trans) - return -ENOMEM; - - spin_lock(&fs_info->trans_lock); - if (fs_info->running_transaction) { - /* - * someone started a transaction after we unlocked. Make sure - * to redo the checks above - */ - kmem_cache_free(btrfs_transaction_cachep, cur_trans); - goto loop; - } else if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) { - spin_unlock(&fs_info->trans_lock); - kmem_cache_free(btrfs_transaction_cachep, cur_trans); - return -EROFS; - } - - cur_trans->fs_info = fs_info; - atomic_set(&cur_trans->num_writers, 1); - extwriter_counter_init(cur_trans, type); - init_waitqueue_head(&cur_trans->writer_wait); - init_waitqueue_head(&cur_trans->commit_wait); - init_waitqueue_head(&cur_trans->pending_wait); - cur_trans->state = TRANS_STATE_RUNNING; - /* - * One for this trans handle, one so it will live on until we - * commit the transaction. - */ - atomic_set(&cur_trans->use_count, 2); - atomic_set(&cur_trans->pending_ordered, 0); - cur_trans->flags = 0; - cur_trans->start_time = get_seconds(); - - memset(&cur_trans->delayed_refs, 0, sizeof(cur_trans->delayed_refs)); - - cur_trans->delayed_refs.href_root = RB_ROOT; - cur_trans->delayed_refs.dirty_extent_root = RB_ROOT; - atomic_set(&cur_trans->delayed_refs.num_entries, 0); - - /* - * although the tree mod log is per file system and not per transaction, - * the log must never go across transaction boundaries. - */ - smp_mb(); - if (!list_empty(&fs_info->tree_mod_seq_list)) - WARN(1, KERN_ERR "BTRFS: tree_mod_seq_list not empty when creating a fresh transaction\n"); - if (!RB_EMPTY_ROOT(&fs_info->tree_mod_log)) - WARN(1, KERN_ERR "BTRFS: tree_mod_log rb tree not empty when creating a fresh transaction\n"); - atomic64_set(&fs_info->tree_mod_seq, 0); - - spin_lock_init(&cur_trans->delayed_refs.lock); - - INIT_LIST_HEAD(&cur_trans->pending_snapshots); - INIT_LIST_HEAD(&cur_trans->pending_chunks); - INIT_LIST_HEAD(&cur_trans->switch_commits); - INIT_LIST_HEAD(&cur_trans->dirty_bgs); - INIT_LIST_HEAD(&cur_trans->io_bgs); - INIT_LIST_HEAD(&cur_trans->dropped_roots); - mutex_init(&cur_trans->cache_write_mutex); - cur_trans->num_dirty_bgs = 0; - spin_lock_init(&cur_trans->dirty_bgs_lock); - INIT_LIST_HEAD(&cur_trans->deleted_bgs); - spin_lock_init(&cur_trans->dropped_roots_lock); - list_add_tail(&cur_trans->list, &fs_info->trans_list); - extent_io_tree_init(&cur_trans->dirty_pages, - fs_info->btree_inode->i_mapping); - fs_info->generation++; - cur_trans->transid = fs_info->generation; - fs_info->running_transaction = cur_trans; - cur_trans->aborted = 0; - spin_unlock(&fs_info->trans_lock); - - return 0; -} - -/* - * this does all the record keeping required to make sure that a reference - * counted root is properly recorded in a given transaction. This is required - * to make sure the old root from before we joined the transaction is deleted - * when the transaction commits - */ -static int record_root_in_trans(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - int force) -{ - if ((test_bit(BTRFS_ROOT_REF_COWS, &root->state) && - root->last_trans < trans->transid) || force) { - WARN_ON(root == root->fs_info->extent_root); - WARN_ON(root->commit_root != root->node); - - /* - * see below for IN_TRANS_SETUP usage rules - * we have the reloc mutex held now, so there - * is only one writer in this function - */ - set_bit(BTRFS_ROOT_IN_TRANS_SETUP, &root->state); - - /* make sure readers find IN_TRANS_SETUP before - * they find our root->last_trans update - */ - smp_wmb(); - - spin_lock(&root->fs_info->fs_roots_radix_lock); - if (root->last_trans == trans->transid && !force) { - spin_unlock(&root->fs_info->fs_roots_radix_lock); - return 0; - } - radix_tree_tag_set(&root->fs_info->fs_roots_radix, - (unsigned long)root->root_key.objectid, - BTRFS_ROOT_TRANS_TAG); - spin_unlock(&root->fs_info->fs_roots_radix_lock); - root->last_trans = trans->transid; - - /* this is pretty tricky. We don't want to - * take the relocation lock in btrfs_record_root_in_trans - * unless we're really doing the first setup for this root in - * this transaction. - * - * Normally we'd use root->last_trans as a flag to decide - * if we want to take the expensive mutex. - * - * But, we have to set root->last_trans before we - * init the relocation root, otherwise, we trip over warnings - * in ctree.c. The solution used here is to flag ourselves - * with root IN_TRANS_SETUP. When this is 1, we're still - * fixing up the reloc trees and everyone must wait. - * - * When this is zero, they can trust root->last_trans and fly - * through btrfs_record_root_in_trans without having to take the - * lock. smp_wmb() makes sure that all the writes above are - * done before we pop in the zero below - */ - btrfs_init_reloc_root(trans, root); - smp_mb__before_atomic(); - clear_bit(BTRFS_ROOT_IN_TRANS_SETUP, &root->state); - } - return 0; -} - - -void btrfs_add_dropped_root(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_transaction *cur_trans = trans->transaction; - - /* Add ourselves to the transaction dropped list */ - spin_lock(&cur_trans->dropped_roots_lock); - list_add_tail(&root->root_list, &cur_trans->dropped_roots); - spin_unlock(&cur_trans->dropped_roots_lock); - - /* Make sure we don't try to update the root at commit time */ - spin_lock(&root->fs_info->fs_roots_radix_lock); - radix_tree_tag_clear(&root->fs_info->fs_roots_radix, - (unsigned long)root->root_key.objectid, - BTRFS_ROOT_TRANS_TAG); - spin_unlock(&root->fs_info->fs_roots_radix_lock); -} - -int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state)) - return 0; - - /* - * see record_root_in_trans for comments about IN_TRANS_SETUP usage - * and barriers - */ - smp_rmb(); - if (root->last_trans == trans->transid && - !test_bit(BTRFS_ROOT_IN_TRANS_SETUP, &root->state)) - return 0; - - mutex_lock(&root->fs_info->reloc_mutex); - record_root_in_trans(trans, root, 0); - mutex_unlock(&root->fs_info->reloc_mutex); - - return 0; -} - -static inline int is_transaction_blocked(struct btrfs_transaction *trans) -{ - return (trans->state >= TRANS_STATE_BLOCKED && - trans->state < TRANS_STATE_UNBLOCKED && - !trans->aborted); -} - -/* wait for commit against the current transaction to become unblocked - * when this is done, it is safe to start a new transaction, but the current - * transaction might not be fully on disk. - */ -static void wait_current_trans(struct btrfs_root *root) -{ - struct btrfs_transaction *cur_trans; - - spin_lock(&root->fs_info->trans_lock); - cur_trans = root->fs_info->running_transaction; - if (cur_trans && is_transaction_blocked(cur_trans)) { - atomic_inc(&cur_trans->use_count); - spin_unlock(&root->fs_info->trans_lock); - - wait_event(root->fs_info->transaction_wait, - cur_trans->state >= TRANS_STATE_UNBLOCKED || - cur_trans->aborted); - btrfs_put_transaction(cur_trans); - } else { - spin_unlock(&root->fs_info->trans_lock); - } -} - -static int may_wait_transaction(struct btrfs_root *root, int type) -{ - if (test_bit(BTRFS_FS_LOG_RECOVERING, &root->fs_info->flags)) - return 0; - - if (type == TRANS_USERSPACE) - return 1; - - if (type == TRANS_START && - !atomic_read(&root->fs_info->open_ioctl_trans)) - return 1; - - return 0; -} - -static inline bool need_reserve_reloc_root(struct btrfs_root *root) -{ - if (!root->fs_info->reloc_ctl || - !test_bit(BTRFS_ROOT_REF_COWS, &root->state) || - root->root_key.objectid == BTRFS_TREE_RELOC_OBJECTID || - root->reloc_root) - return false; - - return true; -} - -static struct btrfs_trans_handle * -start_transaction(struct btrfs_root *root, unsigned int num_items, - unsigned int type, enum btrfs_reserve_flush_enum flush) -{ - struct btrfs_trans_handle *h; - struct btrfs_transaction *cur_trans; - u64 num_bytes = 0; - u64 qgroup_reserved = 0; - bool reloc_reserved = false; - int ret; - - /* Send isn't supposed to start transactions. */ - ASSERT(current->journal_info != BTRFS_SEND_TRANS_STUB); - - if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state)) - return ERR_PTR(-EROFS); - - if (current->journal_info) { - WARN_ON(type & TRANS_EXTWRITERS); - h = current->journal_info; - h->use_count++; - WARN_ON(h->use_count > 2); - h->orig_rsv = h->block_rsv; - h->block_rsv = NULL; - goto got_it; - } - - /* - * Do the reservation before we join the transaction so we can do all - * the appropriate flushing if need be. - */ - if (num_items > 0 && root != root->fs_info->chunk_root) { - qgroup_reserved = num_items * root->nodesize; - ret = btrfs_qgroup_reserve_meta(root, qgroup_reserved); - if (ret) - return ERR_PTR(ret); - - num_bytes = btrfs_calc_trans_metadata_size(root, num_items); - /* - * Do the reservation for the relocation root creation - */ - if (need_reserve_reloc_root(root)) { - num_bytes += root->nodesize; - reloc_reserved = true; - } - - ret = btrfs_block_rsv_add(root, - &root->fs_info->trans_block_rsv, - num_bytes, flush); - if (ret) - goto reserve_fail; - } -again: - h = kmem_cache_zalloc(btrfs_trans_handle_cachep, GFP_NOFS); - if (!h) { - ret = -ENOMEM; - goto alloc_fail; - } - - /* - * If we are JOIN_NOLOCK we're already committing a transaction and - * waiting on this guy, so we don't need to do the sb_start_intwrite - * because we're already holding a ref. We need this because we could - * have raced in and did an fsync() on a file which can kick a commit - * and then we deadlock with somebody doing a freeze. - * - * If we are ATTACH, it means we just want to catch the current - * transaction and commit it, so we needn't do sb_start_intwrite(). - */ - if (type & __TRANS_FREEZABLE) - sb_start_intwrite(root->fs_info->sb); - - if (may_wait_transaction(root, type)) - wait_current_trans(root); - - do { - ret = join_transaction(root, type); - if (ret == -EBUSY) { - wait_current_trans(root); - if (unlikely(type == TRANS_ATTACH)) - ret = -ENOENT; - } - } while (ret == -EBUSY); - - if (ret < 0) - goto join_fail; - - cur_trans = root->fs_info->running_transaction; - - h->transid = cur_trans->transid; - h->transaction = cur_trans; - h->root = root; - h->use_count = 1; - h->fs_info = root->fs_info; - - h->type = type; - h->can_flush_pending_bgs = true; - INIT_LIST_HEAD(&h->qgroup_ref_list); - INIT_LIST_HEAD(&h->new_bgs); - - smp_mb(); - if (cur_trans->state >= TRANS_STATE_BLOCKED && - may_wait_transaction(root, type)) { - current->journal_info = h; - btrfs_commit_transaction(h, root); - goto again; - } - - if (num_bytes) { - trace_btrfs_space_reservation(root->fs_info, "transaction", - h->transid, num_bytes, 1); - h->block_rsv = &root->fs_info->trans_block_rsv; - h->bytes_reserved = num_bytes; - h->reloc_reserved = reloc_reserved; - } - -got_it: - btrfs_record_root_in_trans(h, root); - - if (!current->journal_info && type != TRANS_USERSPACE) - current->journal_info = h; - return h; - -join_fail: - if (type & __TRANS_FREEZABLE) - sb_end_intwrite(root->fs_info->sb); - kmem_cache_free(btrfs_trans_handle_cachep, h); -alloc_fail: - if (num_bytes) - btrfs_block_rsv_release(root, &root->fs_info->trans_block_rsv, - num_bytes); -reserve_fail: - btrfs_qgroup_free_meta(root, qgroup_reserved); - return ERR_PTR(ret); -} - -struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, - unsigned int num_items) -{ - return start_transaction(root, num_items, TRANS_START, - BTRFS_RESERVE_FLUSH_ALL); -} -struct btrfs_trans_handle *btrfs_start_transaction_fallback_global_rsv( - struct btrfs_root *root, - unsigned int num_items, - int min_factor) -{ - struct btrfs_trans_handle *trans; - u64 num_bytes; - int ret; - - trans = btrfs_start_transaction(root, num_items); - if (!IS_ERR(trans) || PTR_ERR(trans) != -ENOSPC) - return trans; - - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) - return trans; - - num_bytes = btrfs_calc_trans_metadata_size(root, num_items); - ret = btrfs_cond_migrate_bytes(root->fs_info, - &root->fs_info->trans_block_rsv, - num_bytes, - min_factor); - if (ret) { - btrfs_end_transaction(trans, root); - return ERR_PTR(ret); - } - - trans->block_rsv = &root->fs_info->trans_block_rsv; - trans->bytes_reserved = num_bytes; - trace_btrfs_space_reservation(root->fs_info, "transaction", - trans->transid, num_bytes, 1); - - return trans; -} - -struct btrfs_trans_handle *btrfs_start_transaction_lflush( - struct btrfs_root *root, - unsigned int num_items) -{ - return start_transaction(root, num_items, TRANS_START, - BTRFS_RESERVE_FLUSH_LIMIT); -} - -struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root) -{ - return start_transaction(root, 0, TRANS_JOIN, - BTRFS_RESERVE_NO_FLUSH); -} - -struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root) -{ - return start_transaction(root, 0, TRANS_JOIN_NOLOCK, - BTRFS_RESERVE_NO_FLUSH); -} - -struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root) -{ - return start_transaction(root, 0, TRANS_USERSPACE, - BTRFS_RESERVE_NO_FLUSH); -} - -/* - * btrfs_attach_transaction() - catch the running transaction - * - * It is used when we want to commit the current the transaction, but - * don't want to start a new one. - * - * Note: If this function return -ENOENT, it just means there is no - * running transaction. But it is possible that the inactive transaction - * is still in the memory, not fully on disk. If you hope there is no - * inactive transaction in the fs when -ENOENT is returned, you should - * invoke - * btrfs_attach_transaction_barrier() - */ -struct btrfs_trans_handle *btrfs_attach_transaction(struct btrfs_root *root) -{ - return start_transaction(root, 0, TRANS_ATTACH, - BTRFS_RESERVE_NO_FLUSH); -} - -/* - * btrfs_attach_transaction_barrier() - catch the running transaction - * - * It is similar to the above function, the differentia is this one - * will wait for all the inactive transactions until they fully - * complete. - */ -struct btrfs_trans_handle * -btrfs_attach_transaction_barrier(struct btrfs_root *root) -{ - struct btrfs_trans_handle *trans; - - trans = start_transaction(root, 0, TRANS_ATTACH, - BTRFS_RESERVE_NO_FLUSH); - if (IS_ERR(trans) && PTR_ERR(trans) == -ENOENT) - btrfs_wait_for_commit(root, 0); - - return trans; -} - -/* wait for a transaction commit to be fully complete */ -static noinline void wait_for_commit(struct btrfs_root *root, - struct btrfs_transaction *commit) -{ - wait_event(commit->commit_wait, commit->state == TRANS_STATE_COMPLETED); -} - -int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid) -{ - struct btrfs_transaction *cur_trans = NULL, *t; - int ret = 0; - - if (transid) { - if (transid <= root->fs_info->last_trans_committed) - goto out; - - /* find specified transaction */ - spin_lock(&root->fs_info->trans_lock); - list_for_each_entry(t, &root->fs_info->trans_list, list) { - if (t->transid == transid) { - cur_trans = t; - atomic_inc(&cur_trans->use_count); - ret = 0; - break; - } - if (t->transid > transid) { - ret = 0; - break; - } - } - spin_unlock(&root->fs_info->trans_lock); - - /* - * The specified transaction doesn't exist, or we - * raced with btrfs_commit_transaction - */ - if (!cur_trans) { - if (transid > root->fs_info->last_trans_committed) - ret = -EINVAL; - goto out; - } - } else { - /* find newest transaction that is committing | committed */ - spin_lock(&root->fs_info->trans_lock); - list_for_each_entry_reverse(t, &root->fs_info->trans_list, - list) { - if (t->state >= TRANS_STATE_COMMIT_START) { - if (t->state == TRANS_STATE_COMPLETED) - break; - cur_trans = t; - atomic_inc(&cur_trans->use_count); - break; - } - } - spin_unlock(&root->fs_info->trans_lock); - if (!cur_trans) - goto out; /* nothing committing|committed */ - } - - wait_for_commit(root, cur_trans); - btrfs_put_transaction(cur_trans); -out: - return ret; -} - -void btrfs_throttle(struct btrfs_root *root) -{ - if (!atomic_read(&root->fs_info->open_ioctl_trans)) - wait_current_trans(root); -} - -static int should_end_transaction(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - if (root->fs_info->global_block_rsv.space_info->full && - btrfs_check_space_for_delayed_refs(trans, root)) - return 1; - - return !!btrfs_block_rsv_check(root, &root->fs_info->global_block_rsv, 5); -} - -int btrfs_should_end_transaction(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_transaction *cur_trans = trans->transaction; - int updates; - int err; - - smp_mb(); - if (cur_trans->state >= TRANS_STATE_BLOCKED || - cur_trans->delayed_refs.flushing) - return 1; - - updates = trans->delayed_ref_updates; - trans->delayed_ref_updates = 0; - if (updates) { - err = btrfs_run_delayed_refs(trans, root, updates * 2); - if (err) /* Error code will also eval true */ - return err; - } - - return should_end_transaction(trans, root); -} - -static int __btrfs_end_transaction(struct btrfs_trans_handle *trans, - struct btrfs_root *root, int throttle) -{ - struct btrfs_transaction *cur_trans = trans->transaction; - struct btrfs_fs_info *info = root->fs_info; - u64 transid = trans->transid; - unsigned long cur = trans->delayed_ref_updates; - int lock = (trans->type != TRANS_JOIN_NOLOCK); - int err = 0; - int must_run_delayed_refs = 0; - - if (trans->use_count > 1) { - trans->use_count--; - trans->block_rsv = trans->orig_rsv; - return 0; - } - - btrfs_trans_release_metadata(trans, root); - trans->block_rsv = NULL; - - if (!list_empty(&trans->new_bgs)) - btrfs_create_pending_block_groups(trans, root); - - trans->delayed_ref_updates = 0; - if (!trans->sync) { - must_run_delayed_refs = - btrfs_should_throttle_delayed_refs(trans, root); - cur = max_t(unsigned long, cur, 32); - - /* - * don't make the caller wait if they are from a NOLOCK - * or ATTACH transaction, it will deadlock with commit - */ - if (must_run_delayed_refs == 1 && - (trans->type & (__TRANS_JOIN_NOLOCK | __TRANS_ATTACH))) - must_run_delayed_refs = 2; - } - - btrfs_trans_release_metadata(trans, root); - trans->block_rsv = NULL; - - if (!list_empty(&trans->new_bgs)) - btrfs_create_pending_block_groups(trans, root); - - btrfs_trans_release_chunk_metadata(trans); - - if (lock && !atomic_read(&root->fs_info->open_ioctl_trans) && - should_end_transaction(trans, root) && - ACCESS_ONCE(cur_trans->state) == TRANS_STATE_RUNNING) { - spin_lock(&info->trans_lock); - if (cur_trans->state == TRANS_STATE_RUNNING) - cur_trans->state = TRANS_STATE_BLOCKED; - spin_unlock(&info->trans_lock); - } - - if (lock && ACCESS_ONCE(cur_trans->state) == TRANS_STATE_BLOCKED) { - if (throttle) - return btrfs_commit_transaction(trans, root); - else - wake_up_process(info->transaction_kthread); - } - - if (trans->type & __TRANS_FREEZABLE) - sb_end_intwrite(root->fs_info->sb); - - WARN_ON(cur_trans != info->running_transaction); - WARN_ON(atomic_read(&cur_trans->num_writers) < 1); - atomic_dec(&cur_trans->num_writers); - extwriter_counter_dec(cur_trans, trans->type); - - /* - * Make sure counter is updated before we wake up waiters. - */ - smp_mb(); - if (waitqueue_active(&cur_trans->writer_wait)) - wake_up(&cur_trans->writer_wait); - btrfs_put_transaction(cur_trans); - - if (current->journal_info == trans) - current->journal_info = NULL; - - if (throttle) - btrfs_run_delayed_iputs(root); - - if (trans->aborted || - test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state)) { - wake_up_process(info->transaction_kthread); - err = -EIO; - } - assert_qgroups_uptodate(trans); - - kmem_cache_free(btrfs_trans_handle_cachep, trans); - if (must_run_delayed_refs) { - btrfs_async_run_delayed_refs(root, cur, transid, - must_run_delayed_refs == 1); - } - return err; -} - -int btrfs_end_transaction(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - return __btrfs_end_transaction(trans, root, 0); -} - -int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - return __btrfs_end_transaction(trans, root, 1); -} - -/* - * when btree blocks are allocated, they have some corresponding bits set for - * them in one of two extent_io trees. This is used to make sure all of - * those extents are sent to disk but does not wait on them - */ -int btrfs_write_marked_extents(struct btrfs_root *root, - struct extent_io_tree *dirty_pages, int mark) -{ - int err = 0; - int werr = 0; - struct address_space *mapping = root->fs_info->btree_inode->i_mapping; - struct extent_state *cached_state = NULL; - u64 start = 0; - u64 end; - - while (!find_first_extent_bit(dirty_pages, start, &start, &end, - mark, &cached_state)) { - bool wait_writeback = false; - - err = convert_extent_bit(dirty_pages, start, end, - EXTENT_NEED_WAIT, - mark, &cached_state); - /* - * convert_extent_bit can return -ENOMEM, which is most of the - * time a temporary error. So when it happens, ignore the error - * and wait for writeback of this range to finish - because we - * failed to set the bit EXTENT_NEED_WAIT for the range, a call - * to btrfs_wait_marked_extents() would not know that writeback - * for this range started and therefore wouldn't wait for it to - * finish - we don't want to commit a superblock that points to - * btree nodes/leafs for which writeback hasn't finished yet - * (and without errors). - * We cleanup any entries left in the io tree when committing - * the transaction (through clear_btree_io_tree()). - */ - if (err == -ENOMEM) { - err = 0; - wait_writeback = true; - } - if (!err) - err = filemap_fdatawrite_range(mapping, start, end); - if (err) - werr = err; - else if (wait_writeback) - werr = filemap_fdatawait_range(mapping, start, end); - free_extent_state(cached_state); - cached_state = NULL; - cond_resched(); - start = end + 1; - } - return werr; -} - -/* - * when btree blocks are allocated, they have some corresponding bits set for - * them in one of two extent_io trees. This is used to make sure all of - * those extents are on disk for transaction or log commit. We wait - * on all the pages and clear them from the dirty pages state tree - */ -int btrfs_wait_marked_extents(struct btrfs_root *root, - struct extent_io_tree *dirty_pages, int mark) -{ - int err = 0; - int werr = 0; - struct address_space *mapping = root->fs_info->btree_inode->i_mapping; - struct extent_state *cached_state = NULL; - u64 start = 0; - u64 end; - bool errors = false; - - while (!find_first_extent_bit(dirty_pages, start, &start, &end, - EXTENT_NEED_WAIT, &cached_state)) { - /* - * Ignore -ENOMEM errors returned by clear_extent_bit(). - * When committing the transaction, we'll remove any entries - * left in the io tree. For a log commit, we don't remove them - * after committing the log because the tree can be accessed - * concurrently - we do it only at transaction commit time when - * it's safe to do it (through clear_btree_io_tree()). - */ - err = clear_extent_bit(dirty_pages, start, end, - EXTENT_NEED_WAIT, - 0, 0, &cached_state, GFP_NOFS); - if (err == -ENOMEM) - err = 0; - if (!err) - err = filemap_fdatawait_range(mapping, start, end); - if (err) - werr = err; - free_extent_state(cached_state); - cached_state = NULL; - cond_resched(); - start = end + 1; - } - if (err) - werr = err; - - if (root->root_key.objectid == BTRFS_TREE_LOG_OBJECTID) { - if ((mark & EXTENT_DIRTY) && - test_and_clear_bit(BTRFS_FS_LOG1_ERR, - &root->fs_info->flags)) - errors = true; - - if ((mark & EXTENT_NEW) && - test_and_clear_bit(BTRFS_FS_LOG2_ERR, - &root->fs_info->flags)) - errors = true; - } else { - if (test_and_clear_bit(BTRFS_FS_BTREE_ERR, - &root->fs_info->flags)) - errors = true; - } - - if (errors && !werr) - werr = -EIO; - - return werr; -} - -/* - * when btree blocks are allocated, they have some corresponding bits set for - * them in one of two extent_io trees. This is used to make sure all of - * those extents are on disk for transaction or log commit - */ -static int btrfs_write_and_wait_marked_extents(struct btrfs_root *root, - struct extent_io_tree *dirty_pages, int mark) -{ - int ret; - int ret2; - struct blk_plug plug; - - blk_start_plug(&plug); - ret = btrfs_write_marked_extents(root, dirty_pages, mark); - blk_finish_plug(&plug); - ret2 = btrfs_wait_marked_extents(root, dirty_pages, mark); - - if (ret) - return ret; - if (ret2) - return ret2; - return 0; -} - -static int btrfs_write_and_wait_transaction(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - int ret; - - ret = btrfs_write_and_wait_marked_extents(root, - &trans->transaction->dirty_pages, - EXTENT_DIRTY); - clear_btree_io_tree(&trans->transaction->dirty_pages); - - return ret; -} - -/* - * this is used to update the root pointer in the tree of tree roots. - * - * But, in the case of the extent allocation tree, updating the root - * pointer may allocate blocks which may change the root of the extent - * allocation tree. - * - * So, this loops and repeats and makes sure the cowonly root didn't - * change while the root pointer was being updated in the metadata. - */ -static int update_cowonly_root(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - int ret; - u64 old_root_bytenr; - u64 old_root_used; - struct btrfs_root *tree_root = root->fs_info->tree_root; - - old_root_used = btrfs_root_used(&root->root_item); - - while (1) { - old_root_bytenr = btrfs_root_bytenr(&root->root_item); - if (old_root_bytenr == root->node->start && - old_root_used == btrfs_root_used(&root->root_item)) - break; - - btrfs_set_root_node(&root->root_item, root->node); - ret = btrfs_update_root(trans, tree_root, - &root->root_key, - &root->root_item); - if (ret) - return ret; - - old_root_used = btrfs_root_used(&root->root_item); - } - - return 0; -} - -/* - * update all the cowonly tree roots on disk - * - * The error handling in this function may not be obvious. Any of the - * failures will cause the file system to go offline. We still need - * to clean up the delayed refs. - */ -static noinline int commit_cowonly_roots(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - struct list_head *dirty_bgs = &trans->transaction->dirty_bgs; - struct list_head *io_bgs = &trans->transaction->io_bgs; - struct list_head *next; - struct extent_buffer *eb; - int ret; - - eb = btrfs_lock_root_node(fs_info->tree_root); - ret = btrfs_cow_block(trans, fs_info->tree_root, eb, NULL, - 0, &eb); - btrfs_tree_unlock(eb); - free_extent_buffer(eb); - - if (ret) - return ret; - - ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); - if (ret) - return ret; - - ret = btrfs_run_dev_stats(trans, root->fs_info); - if (ret) - return ret; - ret = btrfs_run_dev_replace(trans, root->fs_info); - if (ret) - return ret; - ret = btrfs_run_qgroups(trans, root->fs_info); - if (ret) - return ret; - - ret = btrfs_setup_space_cache(trans, root); - if (ret) - return ret; - - /* run_qgroups might have added some more refs */ - ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); - if (ret) - return ret; -again: - while (!list_empty(&fs_info->dirty_cowonly_roots)) { - next = fs_info->dirty_cowonly_roots.next; - list_del_init(next); - root = list_entry(next, struct btrfs_root, dirty_list); - clear_bit(BTRFS_ROOT_DIRTY, &root->state); - - if (root != fs_info->extent_root) - list_add_tail(&root->dirty_list, - &trans->transaction->switch_commits); - ret = update_cowonly_root(trans, root); - if (ret) - return ret; - ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); - if (ret) - return ret; - } - - while (!list_empty(dirty_bgs) || !list_empty(io_bgs)) { - ret = btrfs_write_dirty_block_groups(trans, root); - if (ret) - return ret; - ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); - if (ret) - return ret; - } - - if (!list_empty(&fs_info->dirty_cowonly_roots)) - goto again; - - list_add_tail(&fs_info->extent_root->dirty_list, - &trans->transaction->switch_commits); - btrfs_after_dev_replace_commit(fs_info); - - return 0; -} - -/* - * dead roots are old snapshots that need to be deleted. This allocates - * a dirty root struct and adds it into the list of dead roots that need to - * be deleted - */ -void btrfs_add_dead_root(struct btrfs_root *root) -{ - spin_lock(&root->fs_info->trans_lock); - if (list_empty(&root->root_list)) - list_add_tail(&root->root_list, &root->fs_info->dead_roots); - spin_unlock(&root->fs_info->trans_lock); -} - -/* - * update all the cowonly tree roots on disk - */ -static noinline int commit_fs_roots(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_root *gang[8]; - struct btrfs_fs_info *fs_info = root->fs_info; - int i; - int ret; - int err = 0; - - spin_lock(&fs_info->fs_roots_radix_lock); - while (1) { - ret = radix_tree_gang_lookup_tag(&fs_info->fs_roots_radix, - (void **)gang, 0, - ARRAY_SIZE(gang), - BTRFS_ROOT_TRANS_TAG); - if (ret == 0) - break; - for (i = 0; i < ret; i++) { - root = gang[i]; - radix_tree_tag_clear(&fs_info->fs_roots_radix, - (unsigned long)root->root_key.objectid, - BTRFS_ROOT_TRANS_TAG); - spin_unlock(&fs_info->fs_roots_radix_lock); - - btrfs_free_log(trans, root); - btrfs_update_reloc_root(trans, root); - btrfs_orphan_commit_root(trans, root); - - btrfs_save_ino_cache(root, trans); - - /* see comments in should_cow_block() */ - clear_bit(BTRFS_ROOT_FORCE_COW, &root->state); - smp_mb__after_atomic(); - - if (root->commit_root != root->node) { - list_add_tail(&root->dirty_list, - &trans->transaction->switch_commits); - btrfs_set_root_node(&root->root_item, - root->node); - } - - err = btrfs_update_root(trans, fs_info->tree_root, - &root->root_key, - &root->root_item); - spin_lock(&fs_info->fs_roots_radix_lock); - if (err) - break; - btrfs_qgroup_free_meta_all(root); - } - } - spin_unlock(&fs_info->fs_roots_radix_lock); - return err; -} - -/* - * defrag a given btree. - * Every leaf in the btree is read and defragged. - */ -int btrfs_defrag_root(struct btrfs_root *root) -{ - struct btrfs_fs_info *info = root->fs_info; - struct btrfs_trans_handle *trans; - int ret; - - if (test_and_set_bit(BTRFS_ROOT_DEFRAG_RUNNING, &root->state)) - return 0; - - while (1) { - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - ret = btrfs_defrag_leaves(trans, root); - - btrfs_end_transaction(trans, root); - btrfs_btree_balance_dirty(info->tree_root); - cond_resched(); - - if (btrfs_fs_closing(info) || ret != -EAGAIN) - break; - - if (btrfs_defrag_cancelled(info)) { - btrfs_debug(info, "defrag_root cancelled"); - ret = -EAGAIN; - break; - } - } - clear_bit(BTRFS_ROOT_DEFRAG_RUNNING, &root->state); - return ret; -} - -/* - * Do all special snapshot related qgroup dirty hack. - * - * Will do all needed qgroup inherit and dirty hack like switch commit - * roots inside one transaction and write all btree into disk, to make - * qgroup works. - */ -static int qgroup_account_snapshot(struct btrfs_trans_handle *trans, - struct btrfs_root *src, - struct btrfs_root *parent, - struct btrfs_qgroup_inherit *inherit, - u64 dst_objectid) -{ - struct btrfs_fs_info *fs_info = src->fs_info; - int ret; - - /* - * Save some performance in the case that qgroups are not - * enabled. If this check races with the ioctl, rescan will - * kick in anyway. - */ - mutex_lock(&fs_info->qgroup_ioctl_lock); - if (!test_bit(BTRFS_FS_QUOTA_ENABLED, &fs_info->flags)) { - mutex_unlock(&fs_info->qgroup_ioctl_lock); - return 0; - } - mutex_unlock(&fs_info->qgroup_ioctl_lock); - - /* - * We are going to commit transaction, see btrfs_commit_transaction() - * comment for reason locking tree_log_mutex - */ - mutex_lock(&fs_info->tree_log_mutex); - - ret = commit_fs_roots(trans, src); - if (ret) - goto out; - ret = btrfs_qgroup_prepare_account_extents(trans, fs_info); - if (ret < 0) - goto out; - ret = btrfs_qgroup_account_extents(trans, fs_info); - if (ret < 0) - goto out; - - /* Now qgroup are all updated, we can inherit it to new qgroups */ - ret = btrfs_qgroup_inherit(trans, fs_info, - src->root_key.objectid, dst_objectid, - inherit); - if (ret < 0) - goto out; - - /* - * Now we do a simplified commit transaction, which will: - * 1) commit all subvolume and extent tree - * To ensure all subvolume and extent tree have a valid - * commit_root to accounting later insert_dir_item() - * 2) write all btree blocks onto disk - * This is to make sure later btree modification will be cowed - * Or commit_root can be populated and cause wrong qgroup numbers - * In this simplified commit, we don't really care about other trees - * like chunk and root tree, as they won't affect qgroup. - * And we don't write super to avoid half committed status. - */ - ret = commit_cowonly_roots(trans, src); - if (ret) - goto out; - switch_commit_roots(trans->transaction, fs_info); - ret = btrfs_write_and_wait_transaction(trans, src); - if (ret) - btrfs_handle_fs_error(fs_info, ret, - "Error while writing out transaction for qgroup"); - -out: - mutex_unlock(&fs_info->tree_log_mutex); - - /* - * Force parent root to be updated, as we recorded it before so its - * last_trans == cur_transid. - * Or it won't be committed again onto disk after later - * insert_dir_item() - */ - if (!ret) - record_root_in_trans(trans, parent, 1); - return ret; -} - -/* - * new snapshots need to be created at a very specific time in the - * transaction commit. This does the actual creation. - * - * Note: - * If the error which may affect the commitment of the current transaction - * happens, we should return the error number. If the error which just affect - * the creation of the pending snapshots, just return 0. - */ -static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info, - struct btrfs_pending_snapshot *pending) -{ - struct btrfs_key key; - struct btrfs_root_item *new_root_item; - struct btrfs_root *tree_root = fs_info->tree_root; - struct btrfs_root *root = pending->root; - struct btrfs_root *parent_root; - struct btrfs_block_rsv *rsv; - struct inode *parent_inode; - struct btrfs_path *path; - struct btrfs_dir_item *dir_item; - struct dentry *dentry; - struct extent_buffer *tmp; - struct extent_buffer *old; - struct timespec cur_time; - int ret = 0; - u64 to_reserve = 0; - u64 index = 0; - u64 objectid; - u64 root_flags; - uuid_le new_uuid; - - ASSERT(pending->path); - path = pending->path; - - ASSERT(pending->root_item); - new_root_item = pending->root_item; - - pending->error = btrfs_find_free_objectid(tree_root, &objectid); - if (pending->error) - goto no_free_objectid; - - /* - * Make qgroup to skip current new snapshot's qgroupid, as it is - * accounted by later btrfs_qgroup_inherit(). - */ - btrfs_set_skip_qgroup(trans, objectid); - - btrfs_reloc_pre_snapshot(pending, &to_reserve); - - if (to_reserve > 0) { - pending->error = btrfs_block_rsv_add(root, - &pending->block_rsv, - to_reserve, - BTRFS_RESERVE_NO_FLUSH); - if (pending->error) - goto clear_skip_qgroup; - } - - key.objectid = objectid; - key.offset = (u64)-1; - key.type = BTRFS_ROOT_ITEM_KEY; - - rsv = trans->block_rsv; - trans->block_rsv = &pending->block_rsv; - trans->bytes_reserved = trans->block_rsv->reserved; - trace_btrfs_space_reservation(root->fs_info, "transaction", - trans->transid, - trans->bytes_reserved, 1); - dentry = pending->dentry; - parent_inode = pending->dir; - parent_root = BTRFS_I(parent_inode)->root; - record_root_in_trans(trans, parent_root, 0); - - cur_time = current_time(parent_inode); - - /* - * insert the directory item - */ - ret = btrfs_set_inode_index(parent_inode, &index); - BUG_ON(ret); /* -ENOMEM */ - - /* check if there is a file/dir which has the same name. */ - dir_item = btrfs_lookup_dir_item(NULL, parent_root, path, - btrfs_ino(parent_inode), - dentry->d_name.name, - dentry->d_name.len, 0); - if (dir_item != NULL && !IS_ERR(dir_item)) { - pending->error = -EEXIST; - goto dir_item_existed; - } else if (IS_ERR(dir_item)) { - ret = PTR_ERR(dir_item); - btrfs_abort_transaction(trans, ret); - goto fail; - } - btrfs_release_path(path); - - /* - * pull in the delayed directory update - * and the delayed inode item - * otherwise we corrupt the FS during - * snapshot - */ - ret = btrfs_run_delayed_items(trans, root); - if (ret) { /* Transaction aborted */ - btrfs_abort_transaction(trans, ret); - goto fail; - } - - record_root_in_trans(trans, root, 0); - btrfs_set_root_last_snapshot(&root->root_item, trans->transid); - memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); - btrfs_check_and_init_root_item(new_root_item); - - root_flags = btrfs_root_flags(new_root_item); - if (pending->readonly) - root_flags |= BTRFS_ROOT_SUBVOL_RDONLY; - else - root_flags &= ~BTRFS_ROOT_SUBVOL_RDONLY; - btrfs_set_root_flags(new_root_item, root_flags); - - btrfs_set_root_generation_v2(new_root_item, - trans->transid); - uuid_le_gen(&new_uuid); - memcpy(new_root_item->uuid, new_uuid.b, BTRFS_UUID_SIZE); - memcpy(new_root_item->parent_uuid, root->root_item.uuid, - BTRFS_UUID_SIZE); - if (!(root_flags & BTRFS_ROOT_SUBVOL_RDONLY)) { - memset(new_root_item->received_uuid, 0, - sizeof(new_root_item->received_uuid)); - memset(&new_root_item->stime, 0, sizeof(new_root_item->stime)); - memset(&new_root_item->rtime, 0, sizeof(new_root_item->rtime)); - btrfs_set_root_stransid(new_root_item, 0); - btrfs_set_root_rtransid(new_root_item, 0); - } - btrfs_set_stack_timespec_sec(&new_root_item->otime, cur_time.tv_sec); - btrfs_set_stack_timespec_nsec(&new_root_item->otime, cur_time.tv_nsec); - btrfs_set_root_otransid(new_root_item, trans->transid); - - old = btrfs_lock_root_node(root); - ret = btrfs_cow_block(trans, root, old, NULL, 0, &old); - if (ret) { - btrfs_tree_unlock(old); - free_extent_buffer(old); - btrfs_abort_transaction(trans, ret); - goto fail; - } - - btrfs_set_lock_blocking(old); - - ret = btrfs_copy_root(trans, root, old, &tmp, objectid); - /* clean up in any case */ - btrfs_tree_unlock(old); - free_extent_buffer(old); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto fail; - } - /* see comments in should_cow_block() */ - set_bit(BTRFS_ROOT_FORCE_COW, &root->state); - smp_wmb(); - - btrfs_set_root_node(new_root_item, tmp); - /* record when the snapshot was created in key.offset */ - key.offset = trans->transid; - ret = btrfs_insert_root(trans, tree_root, &key, new_root_item); - btrfs_tree_unlock(tmp); - free_extent_buffer(tmp); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto fail; - } - - /* - * insert root back/forward references - */ - ret = btrfs_add_root_ref(trans, tree_root, objectid, - parent_root->root_key.objectid, - btrfs_ino(parent_inode), index, - dentry->d_name.name, dentry->d_name.len); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto fail; - } - - key.offset = (u64)-1; - pending->snap = btrfs_read_fs_root_no_name(root->fs_info, &key); - if (IS_ERR(pending->snap)) { - ret = PTR_ERR(pending->snap); - btrfs_abort_transaction(trans, ret); - goto fail; - } - - ret = btrfs_reloc_post_snapshot(trans, pending); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto fail; - } - - ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto fail; - } - - /* - * Do special qgroup accounting for snapshot, as we do some qgroup - * snapshot hack to do fast snapshot. - * To co-operate with that hack, we do hack again. - * Or snapshot will be greatly slowed down by a subtree qgroup rescan - */ - ret = qgroup_account_snapshot(trans, root, parent_root, - pending->inherit, objectid); - if (ret < 0) - goto fail; - - ret = btrfs_insert_dir_item(trans, parent_root, - dentry->d_name.name, dentry->d_name.len, - parent_inode, &key, - BTRFS_FT_DIR, index); - /* We have check then name at the beginning, so it is impossible. */ - BUG_ON(ret == -EEXIST || ret == -EOVERFLOW); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto fail; - } - - btrfs_i_size_write(parent_inode, parent_inode->i_size + - dentry->d_name.len * 2); - parent_inode->i_mtime = parent_inode->i_ctime = - current_time(parent_inode); - ret = btrfs_update_inode_fallback(trans, parent_root, parent_inode); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto fail; - } - ret = btrfs_uuid_tree_add(trans, fs_info->uuid_root, new_uuid.b, - BTRFS_UUID_KEY_SUBVOL, objectid); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto fail; - } - if (!btrfs_is_empty_uuid(new_root_item->received_uuid)) { - ret = btrfs_uuid_tree_add(trans, fs_info->uuid_root, - new_root_item->received_uuid, - BTRFS_UUID_KEY_RECEIVED_SUBVOL, - objectid); - if (ret && ret != -EEXIST) { - btrfs_abort_transaction(trans, ret); - goto fail; - } - } - - ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto fail; - } - -fail: - pending->error = ret; -dir_item_existed: - trans->block_rsv = rsv; - trans->bytes_reserved = 0; -clear_skip_qgroup: - btrfs_clear_skip_qgroup(trans); -no_free_objectid: - kfree(new_root_item); - pending->root_item = NULL; - btrfs_free_path(path); - pending->path = NULL; - - return ret; -} - -/* - * create all the snapshots we've scheduled for creation - */ -static noinline int create_pending_snapshots(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info) -{ - struct btrfs_pending_snapshot *pending, *next; - struct list_head *head = &trans->transaction->pending_snapshots; - int ret = 0; - - list_for_each_entry_safe(pending, next, head, list) { - list_del(&pending->list); - ret = create_pending_snapshot(trans, fs_info, pending); - if (ret) - break; - } - return ret; -} - -static void update_super_roots(struct btrfs_root *root) -{ - struct btrfs_root_item *root_item; - struct btrfs_super_block *super; - - super = root->fs_info->super_copy; - - root_item = &root->fs_info->chunk_root->root_item; - super->chunk_root = root_item->bytenr; - super->chunk_root_generation = root_item->generation; - super->chunk_root_level = root_item->level; - - root_item = &root->fs_info->tree_root->root_item; - super->root = root_item->bytenr; - super->generation = root_item->generation; - super->root_level = root_item->level; - if (btrfs_test_opt(root->fs_info, SPACE_CACHE)) - super->cache_generation = root_item->generation; - if (test_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &root->fs_info->flags)) - super->uuid_tree_generation = root_item->generation; -} - -int btrfs_transaction_in_commit(struct btrfs_fs_info *info) -{ - struct btrfs_transaction *trans; - int ret = 0; - - spin_lock(&info->trans_lock); - trans = info->running_transaction; - if (trans) - ret = (trans->state >= TRANS_STATE_COMMIT_START); - spin_unlock(&info->trans_lock); - return ret; -} - -int btrfs_transaction_blocked(struct btrfs_fs_info *info) -{ - struct btrfs_transaction *trans; - int ret = 0; - - spin_lock(&info->trans_lock); - trans = info->running_transaction; - if (trans) - ret = is_transaction_blocked(trans); - spin_unlock(&info->trans_lock); - return ret; -} - -/* - * wait for the current transaction commit to start and block subsequent - * transaction joins - */ -static void wait_current_trans_commit_start(struct btrfs_root *root, - struct btrfs_transaction *trans) -{ - wait_event(root->fs_info->transaction_blocked_wait, - trans->state >= TRANS_STATE_COMMIT_START || - trans->aborted); -} - -/* - * wait for the current transaction to start and then become unblocked. - * caller holds ref. - */ -static void wait_current_trans_commit_start_and_unblock(struct btrfs_root *root, - struct btrfs_transaction *trans) -{ - wait_event(root->fs_info->transaction_wait, - trans->state >= TRANS_STATE_UNBLOCKED || - trans->aborted); -} - -/* - * commit transactions asynchronously. once btrfs_commit_transaction_async - * returns, any subsequent transaction will not be allowed to join. - */ -struct btrfs_async_commit { - struct btrfs_trans_handle *newtrans; - struct btrfs_root *root; - struct work_struct work; -}; - -static void do_async_commit(struct work_struct *work) -{ - struct btrfs_async_commit *ac = - container_of(work, struct btrfs_async_commit, work); - - /* - * We've got freeze protection passed with the transaction. - * Tell lockdep about it. - */ - if (ac->newtrans->type & __TRANS_FREEZABLE) - __sb_writers_acquired(ac->root->fs_info->sb, SB_FREEZE_FS); - - current->journal_info = ac->newtrans; - - btrfs_commit_transaction(ac->newtrans, ac->root); - kfree(ac); -} - -int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - int wait_for_unblock) -{ - struct btrfs_async_commit *ac; - struct btrfs_transaction *cur_trans; - - ac = kmalloc(sizeof(*ac), GFP_NOFS); - if (!ac) - return -ENOMEM; - - INIT_WORK(&ac->work, do_async_commit); - ac->root = root; - ac->newtrans = btrfs_join_transaction(root); - if (IS_ERR(ac->newtrans)) { - int err = PTR_ERR(ac->newtrans); - kfree(ac); - return err; - } - - /* take transaction reference */ - cur_trans = trans->transaction; - atomic_inc(&cur_trans->use_count); - - btrfs_end_transaction(trans, root); - - /* - * Tell lockdep we've released the freeze rwsem, since the - * async commit thread will be the one to unlock it. - */ - if (ac->newtrans->type & __TRANS_FREEZABLE) - __sb_writers_release(root->fs_info->sb, SB_FREEZE_FS); - - schedule_work(&ac->work); - - /* wait for transaction to start and unblock */ - if (wait_for_unblock) - wait_current_trans_commit_start_and_unblock(root, cur_trans); - else - wait_current_trans_commit_start(root, cur_trans); - - if (current->journal_info == trans) - current->journal_info = NULL; - - btrfs_put_transaction(cur_trans); - return 0; -} - - -static void cleanup_transaction(struct btrfs_trans_handle *trans, - struct btrfs_root *root, int err) -{ - struct btrfs_transaction *cur_trans = trans->transaction; - DEFINE_WAIT(wait); - - WARN_ON(trans->use_count > 1); - - btrfs_abort_transaction(trans, err); - - spin_lock(&root->fs_info->trans_lock); - - /* - * If the transaction is removed from the list, it means this - * transaction has been committed successfully, so it is impossible - * to call the cleanup function. - */ - BUG_ON(list_empty(&cur_trans->list)); - - list_del_init(&cur_trans->list); - if (cur_trans == root->fs_info->running_transaction) { - cur_trans->state = TRANS_STATE_COMMIT_DOING; - spin_unlock(&root->fs_info->trans_lock); - wait_event(cur_trans->writer_wait, - atomic_read(&cur_trans->num_writers) == 1); - - spin_lock(&root->fs_info->trans_lock); - } - spin_unlock(&root->fs_info->trans_lock); - - btrfs_cleanup_one_transaction(trans->transaction, root); - - spin_lock(&root->fs_info->trans_lock); - if (cur_trans == root->fs_info->running_transaction) - root->fs_info->running_transaction = NULL; - spin_unlock(&root->fs_info->trans_lock); - - if (trans->type & __TRANS_FREEZABLE) - sb_end_intwrite(root->fs_info->sb); - btrfs_put_transaction(cur_trans); - btrfs_put_transaction(cur_trans); - - trace_btrfs_transaction_commit(root); - - if (current->journal_info == trans) - current->journal_info = NULL; - btrfs_scrub_cancel(root->fs_info); - - kmem_cache_free(btrfs_trans_handle_cachep, trans); -} - -static inline int btrfs_start_delalloc_flush(struct btrfs_fs_info *fs_info) -{ - if (btrfs_test_opt(fs_info, FLUSHONCOMMIT)) - return btrfs_start_delalloc_roots(fs_info, 1, -1); - return 0; -} - -static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info) -{ - if (btrfs_test_opt(fs_info, FLUSHONCOMMIT)) - btrfs_wait_ordered_roots(fs_info, -1, 0, (u64)-1); -} - -static inline void -btrfs_wait_pending_ordered(struct btrfs_transaction *cur_trans) -{ - wait_event(cur_trans->pending_wait, - atomic_read(&cur_trans->pending_ordered) == 0); -} - -int btrfs_commit_transaction(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_transaction *cur_trans = trans->transaction; - struct btrfs_transaction *prev_trans = NULL; - int ret; - - /* Stop the commit early if ->aborted is set */ - if (unlikely(ACCESS_ONCE(cur_trans->aborted))) { - ret = cur_trans->aborted; - btrfs_end_transaction(trans, root); - return ret; - } - - /* make a pass through all the delayed refs we have so far - * any runnings procs may add more while we are here - */ - ret = btrfs_run_delayed_refs(trans, root, 0); - if (ret) { - btrfs_end_transaction(trans, root); - return ret; - } - - btrfs_trans_release_metadata(trans, root); - trans->block_rsv = NULL; - - cur_trans = trans->transaction; - - /* - * set the flushing flag so procs in this transaction have to - * start sending their work down. - */ - cur_trans->delayed_refs.flushing = 1; - smp_wmb(); - - if (!list_empty(&trans->new_bgs)) - btrfs_create_pending_block_groups(trans, root); - - ret = btrfs_run_delayed_refs(trans, root, 0); - if (ret) { - btrfs_end_transaction(trans, root); - return ret; - } - - if (!test_bit(BTRFS_TRANS_DIRTY_BG_RUN, &cur_trans->flags)) { - int run_it = 0; - - /* this mutex is also taken before trying to set - * block groups readonly. We need to make sure - * that nobody has set a block group readonly - * after a extents from that block group have been - * allocated for cache files. btrfs_set_block_group_ro - * will wait for the transaction to commit if it - * finds BTRFS_TRANS_DIRTY_BG_RUN set. - * - * The BTRFS_TRANS_DIRTY_BG_RUN flag is also used to make sure - * only one process starts all the block group IO. It wouldn't - * hurt to have more than one go through, but there's no - * real advantage to it either. - */ - mutex_lock(&root->fs_info->ro_block_group_mutex); - if (!test_and_set_bit(BTRFS_TRANS_DIRTY_BG_RUN, - &cur_trans->flags)) - run_it = 1; - mutex_unlock(&root->fs_info->ro_block_group_mutex); - - if (run_it) - ret = btrfs_start_dirty_block_groups(trans, root); - } - if (ret) { - btrfs_end_transaction(trans, root); - return ret; - } - - spin_lock(&root->fs_info->trans_lock); - if (cur_trans->state >= TRANS_STATE_COMMIT_START) { - spin_unlock(&root->fs_info->trans_lock); - atomic_inc(&cur_trans->use_count); - ret = btrfs_end_transaction(trans, root); - - wait_for_commit(root, cur_trans); - - if (unlikely(cur_trans->aborted)) - ret = cur_trans->aborted; - - btrfs_put_transaction(cur_trans); - - return ret; - } - - cur_trans->state = TRANS_STATE_COMMIT_START; - wake_up(&root->fs_info->transaction_blocked_wait); - - if (cur_trans->list.prev != &root->fs_info->trans_list) { - prev_trans = list_entry(cur_trans->list.prev, - struct btrfs_transaction, list); - if (prev_trans->state != TRANS_STATE_COMPLETED) { - atomic_inc(&prev_trans->use_count); - spin_unlock(&root->fs_info->trans_lock); - - wait_for_commit(root, prev_trans); - ret = prev_trans->aborted; - - btrfs_put_transaction(prev_trans); - if (ret) - goto cleanup_transaction; - } else { - spin_unlock(&root->fs_info->trans_lock); - } - } else { - spin_unlock(&root->fs_info->trans_lock); - } - - extwriter_counter_dec(cur_trans, trans->type); - - ret = btrfs_start_delalloc_flush(root->fs_info); - if (ret) - goto cleanup_transaction; - - ret = btrfs_run_delayed_items(trans, root); - if (ret) - goto cleanup_transaction; - - wait_event(cur_trans->writer_wait, - extwriter_counter_read(cur_trans) == 0); - - /* some pending stuffs might be added after the previous flush. */ - ret = btrfs_run_delayed_items(trans, root); - if (ret) - goto cleanup_transaction; - - btrfs_wait_delalloc_flush(root->fs_info); - - btrfs_wait_pending_ordered(cur_trans); - - btrfs_scrub_pause(root); - /* - * Ok now we need to make sure to block out any other joins while we - * commit the transaction. We could have started a join before setting - * COMMIT_DOING so make sure to wait for num_writers to == 1 again. - */ - spin_lock(&root->fs_info->trans_lock); - cur_trans->state = TRANS_STATE_COMMIT_DOING; - spin_unlock(&root->fs_info->trans_lock); - wait_event(cur_trans->writer_wait, - atomic_read(&cur_trans->num_writers) == 1); - - /* ->aborted might be set after the previous check, so check it */ - if (unlikely(ACCESS_ONCE(cur_trans->aborted))) { - ret = cur_trans->aborted; - goto scrub_continue; - } - /* - * the reloc mutex makes sure that we stop - * the balancing code from coming in and moving - * extents around in the middle of the commit - */ - mutex_lock(&root->fs_info->reloc_mutex); - - /* - * We needn't worry about the delayed items because we will - * deal with them in create_pending_snapshot(), which is the - * core function of the snapshot creation. - */ - ret = create_pending_snapshots(trans, root->fs_info); - if (ret) { - mutex_unlock(&root->fs_info->reloc_mutex); - goto scrub_continue; - } - - /* - * We insert the dir indexes of the snapshots and update the inode - * of the snapshots' parents after the snapshot creation, so there - * are some delayed items which are not dealt with. Now deal with - * them. - * - * We needn't worry that this operation will corrupt the snapshots, - * because all the tree which are snapshoted will be forced to COW - * the nodes and leaves. - */ - ret = btrfs_run_delayed_items(trans, root); - if (ret) { - mutex_unlock(&root->fs_info->reloc_mutex); - goto scrub_continue; - } - - ret = btrfs_run_delayed_refs(trans, root, (unsigned long)-1); - if (ret) { - mutex_unlock(&root->fs_info->reloc_mutex); - goto scrub_continue; - } - - /* Reocrd old roots for later qgroup accounting */ - ret = btrfs_qgroup_prepare_account_extents(trans, root->fs_info); - if (ret) { - mutex_unlock(&root->fs_info->reloc_mutex); - goto scrub_continue; - } - - /* - * make sure none of the code above managed to slip in a - * delayed item - */ - btrfs_assert_delayed_root_empty(root); - - WARN_ON(cur_trans != trans->transaction); - - /* btrfs_commit_tree_roots is responsible for getting the - * various roots consistent with each other. Every pointer - * in the tree of tree roots has to point to the most up to date - * root for every subvolume and other tree. So, we have to keep - * the tree logging code from jumping in and changing any - * of the trees. - * - * At this point in the commit, there can't be any tree-log - * writers, but a little lower down we drop the trans mutex - * and let new people in. By holding the tree_log_mutex - * from now until after the super is written, we avoid races - * with the tree-log code. - */ - mutex_lock(&root->fs_info->tree_log_mutex); - - ret = commit_fs_roots(trans, root); - if (ret) { - mutex_unlock(&root->fs_info->tree_log_mutex); - mutex_unlock(&root->fs_info->reloc_mutex); - goto scrub_continue; - } - - /* - * Since the transaction is done, we can apply the pending changes - * before the next transaction. - */ - btrfs_apply_pending_changes(root->fs_info); - - /* commit_fs_roots gets rid of all the tree log roots, it is now - * safe to free the root of tree log roots - */ - btrfs_free_log_root_tree(trans, root->fs_info); - - /* - * Since fs roots are all committed, we can get a quite accurate - * new_roots. So let's do quota accounting. - */ - ret = btrfs_qgroup_account_extents(trans, root->fs_info); - if (ret < 0) { - mutex_unlock(&root->fs_info->tree_log_mutex); - mutex_unlock(&root->fs_info->reloc_mutex); - goto scrub_continue; - } - - ret = commit_cowonly_roots(trans, root); - if (ret) { - mutex_unlock(&root->fs_info->tree_log_mutex); - mutex_unlock(&root->fs_info->reloc_mutex); - goto scrub_continue; - } - - /* - * The tasks which save the space cache and inode cache may also - * update ->aborted, check it. - */ - if (unlikely(ACCESS_ONCE(cur_trans->aborted))) { - ret = cur_trans->aborted; - mutex_unlock(&root->fs_info->tree_log_mutex); - mutex_unlock(&root->fs_info->reloc_mutex); - goto scrub_continue; - } - - btrfs_prepare_extent_commit(trans, root); - - cur_trans = root->fs_info->running_transaction; - - btrfs_set_root_node(&root->fs_info->tree_root->root_item, - root->fs_info->tree_root->node); - list_add_tail(&root->fs_info->tree_root->dirty_list, - &cur_trans->switch_commits); - - btrfs_set_root_node(&root->fs_info->chunk_root->root_item, - root->fs_info->chunk_root->node); - list_add_tail(&root->fs_info->chunk_root->dirty_list, - &cur_trans->switch_commits); - - switch_commit_roots(cur_trans, root->fs_info); - - assert_qgroups_uptodate(trans); - ASSERT(list_empty(&cur_trans->dirty_bgs)); - ASSERT(list_empty(&cur_trans->io_bgs)); - update_super_roots(root); - - btrfs_set_super_log_root(root->fs_info->super_copy, 0); - btrfs_set_super_log_root_level(root->fs_info->super_copy, 0); - memcpy(root->fs_info->super_for_commit, root->fs_info->super_copy, - sizeof(*root->fs_info->super_copy)); - - btrfs_update_commit_device_size(root->fs_info); - btrfs_update_commit_device_bytes_used(root, cur_trans); - - clear_bit(BTRFS_FS_LOG1_ERR, &root->fs_info->flags); - clear_bit(BTRFS_FS_LOG2_ERR, &root->fs_info->flags); - - btrfs_trans_release_chunk_metadata(trans); - - spin_lock(&root->fs_info->trans_lock); - cur_trans->state = TRANS_STATE_UNBLOCKED; - root->fs_info->running_transaction = NULL; - spin_unlock(&root->fs_info->trans_lock); - mutex_unlock(&root->fs_info->reloc_mutex); - - wake_up(&root->fs_info->transaction_wait); - - ret = btrfs_write_and_wait_transaction(trans, root); - if (ret) { - btrfs_handle_fs_error(root->fs_info, ret, - "Error while writing out transaction"); - mutex_unlock(&root->fs_info->tree_log_mutex); - goto scrub_continue; - } - - ret = write_ctree_super(trans, root, 0); - if (ret) { - mutex_unlock(&root->fs_info->tree_log_mutex); - goto scrub_continue; - } - - /* - * the super is written, we can safely allow the tree-loggers - * to go about their business - */ - mutex_unlock(&root->fs_info->tree_log_mutex); - - btrfs_finish_extent_commit(trans, root); - - if (test_bit(BTRFS_TRANS_HAVE_FREE_BGS, &cur_trans->flags)) - btrfs_clear_space_info_full(root->fs_info); - - root->fs_info->last_trans_committed = cur_trans->transid; - /* - * We needn't acquire the lock here because there is no other task - * which can change it. - */ - cur_trans->state = TRANS_STATE_COMPLETED; - wake_up(&cur_trans->commit_wait); - - spin_lock(&root->fs_info->trans_lock); - list_del_init(&cur_trans->list); - spin_unlock(&root->fs_info->trans_lock); - - btrfs_put_transaction(cur_trans); - btrfs_put_transaction(cur_trans); - - if (trans->type & __TRANS_FREEZABLE) - sb_end_intwrite(root->fs_info->sb); - - trace_btrfs_transaction_commit(root); - - btrfs_scrub_continue(root); - - if (current->journal_info == trans) - current->journal_info = NULL; - - kmem_cache_free(btrfs_trans_handle_cachep, trans); - - /* - * If fs has been frozen, we can not handle delayed iputs, otherwise - * it'll result in deadlock about SB_FREEZE_FS. - */ - if (current != root->fs_info->transaction_kthread && - current != root->fs_info->cleaner_kthread && - !root->fs_info->fs_frozen) - btrfs_run_delayed_iputs(root); - - return ret; - -scrub_continue: - btrfs_scrub_continue(root); -cleanup_transaction: - btrfs_trans_release_metadata(trans, root); - btrfs_trans_release_chunk_metadata(trans); - trans->block_rsv = NULL; - btrfs_warn(root->fs_info, "Skipping commit of aborted transaction."); - if (current->journal_info == trans) - current->journal_info = NULL; - cleanup_transaction(trans, root, ret); - - return ret; -} - -/* - * return < 0 if error - * 0 if there are no more dead_roots at the time of call - * 1 there are more to be processed, call me again - * - * The return value indicates there are certainly more snapshots to delete, but - * if there comes a new one during processing, it may return 0. We don't mind, - * because btrfs_commit_super will poke cleaner thread and it will process it a - * few seconds later. - */ -int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root) -{ - int ret; - struct btrfs_fs_info *fs_info = root->fs_info; - - spin_lock(&fs_info->trans_lock); - if (list_empty(&fs_info->dead_roots)) { - spin_unlock(&fs_info->trans_lock); - return 0; - } - root = list_first_entry(&fs_info->dead_roots, - struct btrfs_root, root_list); - list_del_init(&root->root_list); - spin_unlock(&fs_info->trans_lock); - - btrfs_debug(fs_info, "cleaner removing %llu", root->objectid); - - btrfs_kill_all_delayed_nodes(root); - - if (btrfs_header_backref_rev(root->node) < - BTRFS_MIXED_BACKREF_REV) - ret = btrfs_drop_snapshot(root, NULL, 0, 0); - else - ret = btrfs_drop_snapshot(root, NULL, 1, 0); - - return (ret < 0) ? 0 : 1; -} - -void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info) -{ - unsigned long prev; - unsigned long bit; - - prev = xchg(&fs_info->pending_changes, 0); - if (!prev) - return; - - bit = 1 << BTRFS_PENDING_SET_INODE_MAP_CACHE; - if (prev & bit) - btrfs_set_opt(fs_info->mount_opt, INODE_MAP_CACHE); - prev &= ~bit; - - bit = 1 << BTRFS_PENDING_CLEAR_INODE_MAP_CACHE; - if (prev & bit) - btrfs_clear_opt(fs_info->mount_opt, INODE_MAP_CACHE); - prev &= ~bit; - - bit = 1 << BTRFS_PENDING_COMMIT; - if (prev & bit) - btrfs_debug(fs_info, "pending commit done"); - prev &= ~bit; - - if (prev) - btrfs_warn(fs_info, - "unknown pending changes left 0x%lx, ignoring", prev); -} diff --git a/src/linux/fs/btrfs/transaction.h b/src/linux/fs/btrfs/transaction.h deleted file mode 100644 index 6cf0d37..0000000 --- a/src/linux/fs/btrfs/transaction.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __BTRFS_TRANSACTION__ -#define __BTRFS_TRANSACTION__ -#include "btrfs_inode.h" -#include "delayed-ref.h" -#include "ctree.h" - -enum btrfs_trans_state { - TRANS_STATE_RUNNING = 0, - TRANS_STATE_BLOCKED = 1, - TRANS_STATE_COMMIT_START = 2, - TRANS_STATE_COMMIT_DOING = 3, - TRANS_STATE_UNBLOCKED = 4, - TRANS_STATE_COMPLETED = 5, - TRANS_STATE_MAX = 6, -}; - -#define BTRFS_TRANS_HAVE_FREE_BGS 0 -#define BTRFS_TRANS_DIRTY_BG_RUN 1 -#define BTRFS_TRANS_CACHE_ENOSPC 2 - -struct btrfs_transaction { - u64 transid; - /* - * total external writers(USERSPACE/START/ATTACH) in this - * transaction, it must be zero before the transaction is - * being committed - */ - atomic_t num_extwriters; - /* - * total writers in this transaction, it must be zero before the - * transaction can end - */ - atomic_t num_writers; - atomic_t use_count; - atomic_t pending_ordered; - - unsigned long flags; - - /* Be protected by fs_info->trans_lock when we want to change it. */ - enum btrfs_trans_state state; - struct list_head list; - struct extent_io_tree dirty_pages; - unsigned long start_time; - wait_queue_head_t writer_wait; - wait_queue_head_t commit_wait; - wait_queue_head_t pending_wait; - struct list_head pending_snapshots; - struct list_head pending_chunks; - struct list_head switch_commits; - struct list_head dirty_bgs; - struct list_head io_bgs; - struct list_head dropped_roots; - u64 num_dirty_bgs; - - /* - * we need to make sure block group deletion doesn't race with - * free space cache writeout. This mutex keeps them from stomping - * on each other - */ - struct mutex cache_write_mutex; - spinlock_t dirty_bgs_lock; - /* Protected by spin lock fs_info->unused_bgs_lock. */ - struct list_head deleted_bgs; - spinlock_t dropped_roots_lock; - struct btrfs_delayed_ref_root delayed_refs; - int aborted; - struct btrfs_fs_info *fs_info; -}; - -#define __TRANS_FREEZABLE (1U << 0) - -#define __TRANS_USERSPACE (1U << 8) -#define __TRANS_START (1U << 9) -#define __TRANS_ATTACH (1U << 10) -#define __TRANS_JOIN (1U << 11) -#define __TRANS_JOIN_NOLOCK (1U << 12) -#define __TRANS_DUMMY (1U << 13) - -#define TRANS_USERSPACE (__TRANS_USERSPACE | __TRANS_FREEZABLE) -#define TRANS_START (__TRANS_START | __TRANS_FREEZABLE) -#define TRANS_ATTACH (__TRANS_ATTACH) -#define TRANS_JOIN (__TRANS_JOIN | __TRANS_FREEZABLE) -#define TRANS_JOIN_NOLOCK (__TRANS_JOIN_NOLOCK) - -#define TRANS_EXTWRITERS (__TRANS_USERSPACE | __TRANS_START | \ - __TRANS_ATTACH) - -#define BTRFS_SEND_TRANS_STUB ((void *)1) - -struct btrfs_trans_handle { - u64 transid; - u64 bytes_reserved; - u64 chunk_bytes_reserved; - unsigned long use_count; - unsigned long blocks_reserved; - unsigned long delayed_ref_updates; - struct btrfs_transaction *transaction; - struct btrfs_block_rsv *block_rsv; - struct btrfs_block_rsv *orig_rsv; - short aborted; - short adding_csums; - bool allocating_chunk; - bool can_flush_pending_bgs; - bool reloc_reserved; - bool sync; - bool dirty; - unsigned int type; - /* - * this root is only needed to validate that the root passed to - * start_transaction is the same as the one passed to end_transaction. - * Subvolume quota depends on this - */ - struct btrfs_root *root; - struct btrfs_fs_info *fs_info; - struct seq_list delayed_ref_elem; - struct list_head qgroup_ref_list; - struct list_head new_bgs; -}; - -struct btrfs_pending_snapshot { - struct dentry *dentry; - struct inode *dir; - struct btrfs_root *root; - struct btrfs_root_item *root_item; - struct btrfs_root *snap; - struct btrfs_qgroup_inherit *inherit; - struct btrfs_path *path; - /* block reservation for the operation */ - struct btrfs_block_rsv block_rsv; - u64 qgroup_reserved; - /* extra metadata reservation for relocation */ - int error; - bool readonly; - struct list_head list; -}; - -static inline void btrfs_set_inode_last_trans(struct btrfs_trans_handle *trans, - struct inode *inode) -{ - spin_lock(&BTRFS_I(inode)->lock); - BTRFS_I(inode)->last_trans = trans->transaction->transid; - BTRFS_I(inode)->last_sub_trans = BTRFS_I(inode)->root->log_transid; - BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->root->last_log_commit; - spin_unlock(&BTRFS_I(inode)->lock); -} - -/* - * Make qgroup codes to skip given qgroupid, means the old/new_roots for - * qgroup won't contain the qgroupid in it. - */ -static inline void btrfs_set_skip_qgroup(struct btrfs_trans_handle *trans, - u64 qgroupid) -{ - struct btrfs_delayed_ref_root *delayed_refs; - - delayed_refs = &trans->transaction->delayed_refs; - WARN_ON(delayed_refs->qgroup_to_skip); - delayed_refs->qgroup_to_skip = qgroupid; -} - -static inline void btrfs_clear_skip_qgroup(struct btrfs_trans_handle *trans) -{ - struct btrfs_delayed_ref_root *delayed_refs; - - delayed_refs = &trans->transaction->delayed_refs; - WARN_ON(!delayed_refs->qgroup_to_skip); - delayed_refs->qgroup_to_skip = 0; -} - -int btrfs_end_transaction(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -struct btrfs_trans_handle *btrfs_start_transaction(struct btrfs_root *root, - unsigned int num_items); -struct btrfs_trans_handle *btrfs_start_transaction_fallback_global_rsv( - struct btrfs_root *root, - unsigned int num_items, - int min_factor); -struct btrfs_trans_handle *btrfs_start_transaction_lflush( - struct btrfs_root *root, - unsigned int num_items); -struct btrfs_trans_handle *btrfs_join_transaction(struct btrfs_root *root); -struct btrfs_trans_handle *btrfs_join_transaction_nolock(struct btrfs_root *root); -struct btrfs_trans_handle *btrfs_attach_transaction(struct btrfs_root *root); -struct btrfs_trans_handle *btrfs_attach_transaction_barrier( - struct btrfs_root *root); -struct btrfs_trans_handle *btrfs_start_ioctl_transaction(struct btrfs_root *root); -int btrfs_wait_for_commit(struct btrfs_root *root, u64 transid); - -void btrfs_add_dead_root(struct btrfs_root *root); -int btrfs_defrag_root(struct btrfs_root *root); -int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root); -int btrfs_commit_transaction(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - int wait_for_unblock); -int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -int btrfs_should_end_transaction(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -void btrfs_throttle(struct btrfs_root *root); -int btrfs_record_root_in_trans(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -int btrfs_write_marked_extents(struct btrfs_root *root, - struct extent_io_tree *dirty_pages, int mark); -int btrfs_wait_marked_extents(struct btrfs_root *root, - struct extent_io_tree *dirty_pages, int mark); -int btrfs_transaction_blocked(struct btrfs_fs_info *info); -int btrfs_transaction_in_commit(struct btrfs_fs_info *info); -void btrfs_put_transaction(struct btrfs_transaction *transaction); -void btrfs_apply_pending_changes(struct btrfs_fs_info *fs_info); -void btrfs_add_dropped_root(struct btrfs_trans_handle *trans, - struct btrfs_root *root); -#endif diff --git a/src/linux/fs/btrfs/tree-defrag.c b/src/linux/fs/btrfs/tree-defrag.c deleted file mode 100644 index cb65089..0000000 --- a/src/linux/fs/btrfs/tree-defrag.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include "ctree.h" -#include "disk-io.h" -#include "print-tree.h" -#include "transaction.h" -#include "locking.h" - -/* - * Defrag all the leaves in a given btree. - * Read all the leaves and try to get key order to - * better reflect disk order - */ - -int btrfs_defrag_leaves(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_path *path = NULL; - struct btrfs_key key; - int ret = 0; - int wret; - int level; - int next_key_ret = 0; - u64 last_ret = 0; - u64 min_trans = 0; - - if (root->fs_info->extent_root == root) { - /* - * there's recursion here right now in the tree locking, - * we can't defrag the extent root without deadlock - */ - goto out; - } - - if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state)) - goto out; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - level = btrfs_header_level(root->node); - - if (level == 0) - goto out; - - if (root->defrag_progress.objectid == 0) { - struct extent_buffer *root_node; - u32 nritems; - - root_node = btrfs_lock_root_node(root); - btrfs_set_lock_blocking(root_node); - nritems = btrfs_header_nritems(root_node); - root->defrag_max.objectid = 0; - /* from above we know this is not a leaf */ - btrfs_node_key_to_cpu(root_node, &root->defrag_max, - nritems - 1); - btrfs_tree_unlock(root_node); - free_extent_buffer(root_node); - memset(&key, 0, sizeof(key)); - } else { - memcpy(&key, &root->defrag_progress, sizeof(key)); - } - - path->keep_locks = 1; - - ret = btrfs_search_forward(root, &key, path, min_trans); - if (ret < 0) - goto out; - if (ret > 0) { - ret = 0; - goto out; - } - btrfs_release_path(path); - /* - * We don't need a lock on a leaf. btrfs_realloc_node() will lock all - * leafs from path->nodes[1], so set lowest_level to 1 to avoid later - * a deadlock (attempting to write lock an already write locked leaf). - */ - path->lowest_level = 1; - wret = btrfs_search_slot(trans, root, &key, path, 0, 1); - - if (wret < 0) { - ret = wret; - goto out; - } - if (!path->nodes[1]) { - ret = 0; - goto out; - } - /* - * The node at level 1 must always be locked when our path has - * keep_locks set and lowest_level is 1, regardless of the value of - * path->slots[1]. - */ - BUG_ON(path->locks[1] == 0); - ret = btrfs_realloc_node(trans, root, - path->nodes[1], 0, - &last_ret, - &root->defrag_progress); - if (ret) { - WARN_ON(ret == -EAGAIN); - goto out; - } - /* - * Now that we reallocated the node we can find the next key. Note that - * btrfs_find_next_key() can release our path and do another search - * without COWing, this is because even with path->keep_locks = 1, - * btrfs_search_slot() / ctree.c:unlock_up() does not keeps a lock on a - * node when path->slots[node_level - 1] does not point to the last - * item or a slot beyond the last item (ctree.c:unlock_up()). Therefore - * we search for the next key after reallocating our node. - */ - path->slots[1] = btrfs_header_nritems(path->nodes[1]); - next_key_ret = btrfs_find_next_key(root, path, &key, 1, - min_trans); - if (next_key_ret == 0) { - memcpy(&root->defrag_progress, &key, sizeof(key)); - ret = -EAGAIN; - } -out: - btrfs_free_path(path); - if (ret == -EAGAIN) { - if (root->defrag_max.objectid > root->defrag_progress.objectid) - goto done; - if (root->defrag_max.type > root->defrag_progress.type) - goto done; - if (root->defrag_max.offset > root->defrag_progress.offset) - goto done; - ret = 0; - } -done: - if (ret != -EAGAIN) { - memset(&root->defrag_progress, 0, - sizeof(root->defrag_progress)); - root->defrag_trans_start = trans->transid; - } - return ret; -} diff --git a/src/linux/fs/btrfs/tree-log.c b/src/linux/fs/btrfs/tree-log.c deleted file mode 100644 index 3d33c4e..0000000 --- a/src/linux/fs/btrfs/tree-log.c +++ /dev/null @@ -1,5811 +0,0 @@ -/* - * Copyright (C) 2008 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include "tree-log.h" -#include "disk-io.h" -#include "locking.h" -#include "print-tree.h" -#include "backref.h" -#include "hash.h" -#include "compression.h" -#include "qgroup.h" - -/* magic values for the inode_only field in btrfs_log_inode: - * - * LOG_INODE_ALL means to log everything - * LOG_INODE_EXISTS means to log just enough to recreate the inode - * during log replay - */ -#define LOG_INODE_ALL 0 -#define LOG_INODE_EXISTS 1 - -/* - * directory trouble cases - * - * 1) on rename or unlink, if the inode being unlinked isn't in the fsync - * log, we must force a full commit before doing an fsync of the directory - * where the unlink was done. - * ---> record transid of last unlink/rename per directory - * - * mkdir foo/some_dir - * normal commit - * rename foo/some_dir foo2/some_dir - * mkdir foo/some_dir - * fsync foo/some_dir/some_file - * - * The fsync above will unlink the original some_dir without recording - * it in its new location (foo2). After a crash, some_dir will be gone - * unless the fsync of some_file forces a full commit - * - * 2) we must log any new names for any file or dir that is in the fsync - * log. ---> check inode while renaming/linking. - * - * 2a) we must log any new names for any file or dir during rename - * when the directory they are being removed from was logged. - * ---> check inode and old parent dir during rename - * - * 2a is actually the more important variant. With the extra logging - * a crash might unlink the old name without recreating the new one - * - * 3) after a crash, we must go through any directories with a link count - * of zero and redo the rm -rf - * - * mkdir f1/foo - * normal commit - * rm -rf f1/foo - * fsync(f1) - * - * The directory f1 was fully removed from the FS, but fsync was never - * called on f1, only its parent dir. After a crash the rm -rf must - * be replayed. This must be able to recurse down the entire - * directory tree. The inode link count fixup code takes care of the - * ugly details. - */ - -/* - * stages for the tree walking. The first - * stage (0) is to only pin down the blocks we find - * the second stage (1) is to make sure that all the inodes - * we find in the log are created in the subvolume. - * - * The last stage is to deal with directories and links and extents - * and all the other fun semantics - */ -#define LOG_WALK_PIN_ONLY 0 -#define LOG_WALK_REPLAY_INODES 1 -#define LOG_WALK_REPLAY_DIR_INDEX 2 -#define LOG_WALK_REPLAY_ALL 3 - -static int btrfs_log_inode(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct inode *inode, - int inode_only, - const loff_t start, - const loff_t end, - struct btrfs_log_ctx *ctx); -static int link_to_fixup_dir(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, u64 objectid); -static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_root *log, - struct btrfs_path *path, - u64 dirid, int del_all); - -/* - * tree logging is a special write ahead log used to make sure that - * fsyncs and O_SYNCs can happen without doing full tree commits. - * - * Full tree commits are expensive because they require commonly - * modified blocks to be recowed, creating many dirty pages in the - * extent tree an 4x-6x higher write load than ext3. - * - * Instead of doing a tree commit on every fsync, we use the - * key ranges and transaction ids to find items for a given file or directory - * that have changed in this transaction. Those items are copied into - * a special tree (one per subvolume root), that tree is written to disk - * and then the fsync is considered complete. - * - * After a crash, items are copied out of the log-tree back into the - * subvolume tree. Any file data extents found are recorded in the extent - * allocation tree, and the log-tree freed. - * - * The log tree is read three times, once to pin down all the extents it is - * using in ram and once, once to create all the inodes logged in the tree - * and once to do all the other items. - */ - -/* - * start a sub transaction and setup the log tree - * this increments the log tree writer count to make the people - * syncing the tree wait for us to finish - */ -static int start_log_trans(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_log_ctx *ctx) -{ - int ret = 0; - - mutex_lock(&root->log_mutex); - - if (root->log_root) { - if (btrfs_need_log_full_commit(root->fs_info, trans)) { - ret = -EAGAIN; - goto out; - } - - if (!root->log_start_pid) { - clear_bit(BTRFS_ROOT_MULTI_LOG_TASKS, &root->state); - root->log_start_pid = current->pid; - } else if (root->log_start_pid != current->pid) { - set_bit(BTRFS_ROOT_MULTI_LOG_TASKS, &root->state); - } - } else { - mutex_lock(&root->fs_info->tree_log_mutex); - if (!root->fs_info->log_root_tree) - ret = btrfs_init_log_root_tree(trans, root->fs_info); - mutex_unlock(&root->fs_info->tree_log_mutex); - if (ret) - goto out; - - ret = btrfs_add_log_tree(trans, root); - if (ret) - goto out; - - clear_bit(BTRFS_ROOT_MULTI_LOG_TASKS, &root->state); - root->log_start_pid = current->pid; - } - - atomic_inc(&root->log_batch); - atomic_inc(&root->log_writers); - if (ctx) { - int index = root->log_transid % 2; - list_add_tail(&ctx->list, &root->log_ctxs[index]); - ctx->log_transid = root->log_transid; - } - -out: - mutex_unlock(&root->log_mutex); - return ret; -} - -/* - * returns 0 if there was a log transaction running and we were able - * to join, or returns -ENOENT if there were not transactions - * in progress - */ -static int join_running_log_trans(struct btrfs_root *root) -{ - int ret = -ENOENT; - - smp_mb(); - if (!root->log_root) - return -ENOENT; - - mutex_lock(&root->log_mutex); - if (root->log_root) { - ret = 0; - atomic_inc(&root->log_writers); - } - mutex_unlock(&root->log_mutex); - return ret; -} - -/* - * This either makes the current running log transaction wait - * until you call btrfs_end_log_trans() or it makes any future - * log transactions wait until you call btrfs_end_log_trans() - */ -int btrfs_pin_log_trans(struct btrfs_root *root) -{ - int ret = -ENOENT; - - mutex_lock(&root->log_mutex); - atomic_inc(&root->log_writers); - mutex_unlock(&root->log_mutex); - return ret; -} - -/* - * indicate we're done making changes to the log tree - * and wake up anyone waiting to do a sync - */ -void btrfs_end_log_trans(struct btrfs_root *root) -{ - if (atomic_dec_and_test(&root->log_writers)) { - /* - * Implicit memory barrier after atomic_dec_and_test - */ - if (waitqueue_active(&root->log_writer_wait)) - wake_up(&root->log_writer_wait); - } -} - - -/* - * the walk control struct is used to pass state down the chain when - * processing the log tree. The stage field tells us which part - * of the log tree processing we are currently doing. The others - * are state fields used for that specific part - */ -struct walk_control { - /* should we free the extent on disk when done? This is used - * at transaction commit time while freeing a log tree - */ - int free; - - /* should we write out the extent buffer? This is used - * while flushing the log tree to disk during a sync - */ - int write; - - /* should we wait for the extent buffer io to finish? Also used - * while flushing the log tree to disk for a sync - */ - int wait; - - /* pin only walk, we record which extents on disk belong to the - * log trees - */ - int pin; - - /* what stage of the replay code we're currently in */ - int stage; - - /* the root we are currently replaying */ - struct btrfs_root *replay_dest; - - /* the trans handle for the current replay */ - struct btrfs_trans_handle *trans; - - /* the function that gets used to process blocks we find in the - * tree. Note the extent_buffer might not be up to date when it is - * passed in, and it must be checked or read if you need the data - * inside it - */ - int (*process_func)(struct btrfs_root *log, struct extent_buffer *eb, - struct walk_control *wc, u64 gen); -}; - -/* - * process_func used to pin down extents, write them or wait on them - */ -static int process_one_buffer(struct btrfs_root *log, - struct extent_buffer *eb, - struct walk_control *wc, u64 gen) -{ - int ret = 0; - - /* - * If this fs is mixed then we need to be able to process the leaves to - * pin down any logged extents, so we have to read the block. - */ - if (btrfs_fs_incompat(log->fs_info, MIXED_GROUPS)) { - ret = btrfs_read_buffer(eb, gen); - if (ret) - return ret; - } - - if (wc->pin) - ret = btrfs_pin_extent_for_log_replay(log->fs_info->extent_root, - eb->start, eb->len); - - if (!ret && btrfs_buffer_uptodate(eb, gen, 0)) { - if (wc->pin && btrfs_header_level(eb) == 0) - ret = btrfs_exclude_logged_extents(log, eb); - if (wc->write) - btrfs_write_tree_block(eb); - if (wc->wait) - btrfs_wait_tree_block_writeback(eb); - } - return ret; -} - -/* - * Item overwrite used by replay and tree logging. eb, slot and key all refer - * to the src data we are copying out. - * - * root is the tree we are copying into, and path is a scratch - * path for use in this function (it should be released on entry and - * will be released on exit). - * - * If the key is already in the destination tree the existing item is - * overwritten. If the existing item isn't big enough, it is extended. - * If it is too large, it is truncated. - * - * If the key isn't in the destination yet, a new item is inserted. - */ -static noinline int overwrite_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct extent_buffer *eb, int slot, - struct btrfs_key *key) -{ - int ret; - u32 item_size; - u64 saved_i_size = 0; - int save_old_i_size = 0; - unsigned long src_ptr; - unsigned long dst_ptr; - int overwrite_root = 0; - bool inode_item = key->type == BTRFS_INODE_ITEM_KEY; - - if (root->root_key.objectid != BTRFS_TREE_LOG_OBJECTID) - overwrite_root = 1; - - item_size = btrfs_item_size_nr(eb, slot); - src_ptr = btrfs_item_ptr_offset(eb, slot); - - /* look for the key in the destination tree */ - ret = btrfs_search_slot(NULL, root, key, path, 0, 0); - if (ret < 0) - return ret; - - if (ret == 0) { - char *src_copy; - char *dst_copy; - u32 dst_size = btrfs_item_size_nr(path->nodes[0], - path->slots[0]); - if (dst_size != item_size) - goto insert; - - if (item_size == 0) { - btrfs_release_path(path); - return 0; - } - dst_copy = kmalloc(item_size, GFP_NOFS); - src_copy = kmalloc(item_size, GFP_NOFS); - if (!dst_copy || !src_copy) { - btrfs_release_path(path); - kfree(dst_copy); - kfree(src_copy); - return -ENOMEM; - } - - read_extent_buffer(eb, src_copy, src_ptr, item_size); - - dst_ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]); - read_extent_buffer(path->nodes[0], dst_copy, dst_ptr, - item_size); - ret = memcmp(dst_copy, src_copy, item_size); - - kfree(dst_copy); - kfree(src_copy); - /* - * they have the same contents, just return, this saves - * us from cowing blocks in the destination tree and doing - * extra writes that may not have been done by a previous - * sync - */ - if (ret == 0) { - btrfs_release_path(path); - return 0; - } - - /* - * We need to load the old nbytes into the inode so when we - * replay the extents we've logged we get the right nbytes. - */ - if (inode_item) { - struct btrfs_inode_item *item; - u64 nbytes; - u32 mode; - - item = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_inode_item); - nbytes = btrfs_inode_nbytes(path->nodes[0], item); - item = btrfs_item_ptr(eb, slot, - struct btrfs_inode_item); - btrfs_set_inode_nbytes(eb, item, nbytes); - - /* - * If this is a directory we need to reset the i_size to - * 0 so that we can set it up properly when replaying - * the rest of the items in this log. - */ - mode = btrfs_inode_mode(eb, item); - if (S_ISDIR(mode)) - btrfs_set_inode_size(eb, item, 0); - } - } else if (inode_item) { - struct btrfs_inode_item *item; - u32 mode; - - /* - * New inode, set nbytes to 0 so that the nbytes comes out - * properly when we replay the extents. - */ - item = btrfs_item_ptr(eb, slot, struct btrfs_inode_item); - btrfs_set_inode_nbytes(eb, item, 0); - - /* - * If this is a directory we need to reset the i_size to 0 so - * that we can set it up properly when replaying the rest of - * the items in this log. - */ - mode = btrfs_inode_mode(eb, item); - if (S_ISDIR(mode)) - btrfs_set_inode_size(eb, item, 0); - } -insert: - btrfs_release_path(path); - /* try to insert the key into the destination tree */ - path->skip_release_on_error = 1; - ret = btrfs_insert_empty_item(trans, root, path, - key, item_size); - path->skip_release_on_error = 0; - - /* make sure any existing item is the correct size */ - if (ret == -EEXIST || ret == -EOVERFLOW) { - u32 found_size; - found_size = btrfs_item_size_nr(path->nodes[0], - path->slots[0]); - if (found_size > item_size) - btrfs_truncate_item(root, path, item_size, 1); - else if (found_size < item_size) - btrfs_extend_item(root, path, - item_size - found_size); - } else if (ret) { - return ret; - } - dst_ptr = btrfs_item_ptr_offset(path->nodes[0], - path->slots[0]); - - /* don't overwrite an existing inode if the generation number - * was logged as zero. This is done when the tree logging code - * is just logging an inode to make sure it exists after recovery. - * - * Also, don't overwrite i_size on directories during replay. - * log replay inserts and removes directory items based on the - * state of the tree found in the subvolume, and i_size is modified - * as it goes - */ - if (key->type == BTRFS_INODE_ITEM_KEY && ret == -EEXIST) { - struct btrfs_inode_item *src_item; - struct btrfs_inode_item *dst_item; - - src_item = (struct btrfs_inode_item *)src_ptr; - dst_item = (struct btrfs_inode_item *)dst_ptr; - - if (btrfs_inode_generation(eb, src_item) == 0) { - struct extent_buffer *dst_eb = path->nodes[0]; - const u64 ino_size = btrfs_inode_size(eb, src_item); - - /* - * For regular files an ino_size == 0 is used only when - * logging that an inode exists, as part of a directory - * fsync, and the inode wasn't fsynced before. In this - * case don't set the size of the inode in the fs/subvol - * tree, otherwise we would be throwing valid data away. - */ - if (S_ISREG(btrfs_inode_mode(eb, src_item)) && - S_ISREG(btrfs_inode_mode(dst_eb, dst_item)) && - ino_size != 0) { - struct btrfs_map_token token; - - btrfs_init_map_token(&token); - btrfs_set_token_inode_size(dst_eb, dst_item, - ino_size, &token); - } - goto no_copy; - } - - if (overwrite_root && - S_ISDIR(btrfs_inode_mode(eb, src_item)) && - S_ISDIR(btrfs_inode_mode(path->nodes[0], dst_item))) { - save_old_i_size = 1; - saved_i_size = btrfs_inode_size(path->nodes[0], - dst_item); - } - } - - copy_extent_buffer(path->nodes[0], eb, dst_ptr, - src_ptr, item_size); - - if (save_old_i_size) { - struct btrfs_inode_item *dst_item; - dst_item = (struct btrfs_inode_item *)dst_ptr; - btrfs_set_inode_size(path->nodes[0], dst_item, saved_i_size); - } - - /* make sure the generation is filled in */ - if (key->type == BTRFS_INODE_ITEM_KEY) { - struct btrfs_inode_item *dst_item; - dst_item = (struct btrfs_inode_item *)dst_ptr; - if (btrfs_inode_generation(path->nodes[0], dst_item) == 0) { - btrfs_set_inode_generation(path->nodes[0], dst_item, - trans->transid); - } - } -no_copy: - btrfs_mark_buffer_dirty(path->nodes[0]); - btrfs_release_path(path); - return 0; -} - -/* - * simple helper to read an inode off the disk from a given root - * This can only be called for subvolume roots and not for the log - */ -static noinline struct inode *read_one_inode(struct btrfs_root *root, - u64 objectid) -{ - struct btrfs_key key; - struct inode *inode; - - key.objectid = objectid; - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - inode = btrfs_iget(root->fs_info->sb, &key, root, NULL); - if (IS_ERR(inode)) { - inode = NULL; - } else if (is_bad_inode(inode)) { - iput(inode); - inode = NULL; - } - return inode; -} - -/* replays a single extent in 'eb' at 'slot' with 'key' into the - * subvolume 'root'. path is released on entry and should be released - * on exit. - * - * extents in the log tree have not been allocated out of the extent - * tree yet. So, this completes the allocation, taking a reference - * as required if the extent already exists or creating a new extent - * if it isn't in the extent allocation tree yet. - * - * The extent is inserted into the file, dropping any existing extents - * from the file that overlap the new one. - */ -static noinline int replay_one_extent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct extent_buffer *eb, int slot, - struct btrfs_key *key) -{ - int found_type; - u64 extent_end; - u64 start = key->offset; - u64 nbytes = 0; - struct btrfs_file_extent_item *item; - struct inode *inode = NULL; - unsigned long size; - int ret = 0; - - item = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); - found_type = btrfs_file_extent_type(eb, item); - - if (found_type == BTRFS_FILE_EXTENT_REG || - found_type == BTRFS_FILE_EXTENT_PREALLOC) { - nbytes = btrfs_file_extent_num_bytes(eb, item); - extent_end = start + nbytes; - - /* - * We don't add to the inodes nbytes if we are prealloc or a - * hole. - */ - if (btrfs_file_extent_disk_bytenr(eb, item) == 0) - nbytes = 0; - } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { - size = btrfs_file_extent_inline_len(eb, slot, item); - nbytes = btrfs_file_extent_ram_bytes(eb, item); - extent_end = ALIGN(start + size, root->sectorsize); - } else { - ret = 0; - goto out; - } - - inode = read_one_inode(root, key->objectid); - if (!inode) { - ret = -EIO; - goto out; - } - - /* - * first check to see if we already have this extent in the - * file. This must be done before the btrfs_drop_extents run - * so we don't try to drop this extent. - */ - ret = btrfs_lookup_file_extent(trans, root, path, btrfs_ino(inode), - start, 0); - - if (ret == 0 && - (found_type == BTRFS_FILE_EXTENT_REG || - found_type == BTRFS_FILE_EXTENT_PREALLOC)) { - struct btrfs_file_extent_item cmp1; - struct btrfs_file_extent_item cmp2; - struct btrfs_file_extent_item *existing; - struct extent_buffer *leaf; - - leaf = path->nodes[0]; - existing = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - - read_extent_buffer(eb, &cmp1, (unsigned long)item, - sizeof(cmp1)); - read_extent_buffer(leaf, &cmp2, (unsigned long)existing, - sizeof(cmp2)); - - /* - * we already have a pointer to this exact extent, - * we don't have to do anything - */ - if (memcmp(&cmp1, &cmp2, sizeof(cmp1)) == 0) { - btrfs_release_path(path); - goto out; - } - } - btrfs_release_path(path); - - /* drop any overlapping extents */ - ret = btrfs_drop_extents(trans, root, inode, start, extent_end, 1); - if (ret) - goto out; - - if (found_type == BTRFS_FILE_EXTENT_REG || - found_type == BTRFS_FILE_EXTENT_PREALLOC) { - u64 offset; - unsigned long dest_offset; - struct btrfs_key ins; - - ret = btrfs_insert_empty_item(trans, root, path, key, - sizeof(*item)); - if (ret) - goto out; - dest_offset = btrfs_item_ptr_offset(path->nodes[0], - path->slots[0]); - copy_extent_buffer(path->nodes[0], eb, dest_offset, - (unsigned long)item, sizeof(*item)); - - ins.objectid = btrfs_file_extent_disk_bytenr(eb, item); - ins.offset = btrfs_file_extent_disk_num_bytes(eb, item); - ins.type = BTRFS_EXTENT_ITEM_KEY; - offset = key->offset - btrfs_file_extent_offset(eb, item); - - /* - * Manually record dirty extent, as here we did a shallow - * file extent item copy and skip normal backref update, - * but modifying extent tree all by ourselves. - * So need to manually record dirty extent for qgroup, - * as the owner of the file extent changed from log tree - * (doesn't affect qgroup) to fs/file tree(affects qgroup) - */ - ret = btrfs_qgroup_insert_dirty_extent(trans, root->fs_info, - btrfs_file_extent_disk_bytenr(eb, item), - btrfs_file_extent_disk_num_bytes(eb, item), - GFP_NOFS); - if (ret < 0) - goto out; - - if (ins.objectid > 0) { - u64 csum_start; - u64 csum_end; - LIST_HEAD(ordered_sums); - /* - * is this extent already allocated in the extent - * allocation tree? If so, just add a reference - */ - ret = btrfs_lookup_data_extent(root, ins.objectid, - ins.offset); - if (ret == 0) { - ret = btrfs_inc_extent_ref(trans, root, - ins.objectid, ins.offset, - 0, root->root_key.objectid, - key->objectid, offset); - if (ret) - goto out; - } else { - /* - * insert the extent pointer in the extent - * allocation tree - */ - ret = btrfs_alloc_logged_file_extent(trans, - root, root->root_key.objectid, - key->objectid, offset, &ins); - if (ret) - goto out; - } - btrfs_release_path(path); - - if (btrfs_file_extent_compression(eb, item)) { - csum_start = ins.objectid; - csum_end = csum_start + ins.offset; - } else { - csum_start = ins.objectid + - btrfs_file_extent_offset(eb, item); - csum_end = csum_start + - btrfs_file_extent_num_bytes(eb, item); - } - - ret = btrfs_lookup_csums_range(root->log_root, - csum_start, csum_end - 1, - &ordered_sums, 0); - if (ret) - goto out; - /* - * Now delete all existing cums in the csum root that - * cover our range. We do this because we can have an - * extent that is completely referenced by one file - * extent item and partially referenced by another - * file extent item (like after using the clone or - * extent_same ioctls). In this case if we end up doing - * the replay of the one that partially references the - * extent first, and we do not do the csum deletion - * below, we can get 2 csum items in the csum tree that - * overlap each other. For example, imagine our log has - * the two following file extent items: - * - * key (257 EXTENT_DATA 409600) - * extent data disk byte 12845056 nr 102400 - * extent data offset 20480 nr 20480 ram 102400 - * - * key (257 EXTENT_DATA 819200) - * extent data disk byte 12845056 nr 102400 - * extent data offset 0 nr 102400 ram 102400 - * - * Where the second one fully references the 100K extent - * that starts at disk byte 12845056, and the log tree - * has a single csum item that covers the entire range - * of the extent: - * - * key (EXTENT_CSUM EXTENT_CSUM 12845056) itemsize 100 - * - * After the first file extent item is replayed, the - * csum tree gets the following csum item: - * - * key (EXTENT_CSUM EXTENT_CSUM 12865536) itemsize 20 - * - * Which covers the 20K sub-range starting at offset 20K - * of our extent. Now when we replay the second file - * extent item, if we do not delete existing csum items - * that cover any of its blocks, we end up getting two - * csum items in our csum tree that overlap each other: - * - * key (EXTENT_CSUM EXTENT_CSUM 12845056) itemsize 100 - * key (EXTENT_CSUM EXTENT_CSUM 12865536) itemsize 20 - * - * Which is a problem, because after this anyone trying - * to lookup up for the checksum of any block of our - * extent starting at an offset of 40K or higher, will - * end up looking at the second csum item only, which - * does not contain the checksum for any block starting - * at offset 40K or higher of our extent. - */ - while (!list_empty(&ordered_sums)) { - struct btrfs_ordered_sum *sums; - sums = list_entry(ordered_sums.next, - struct btrfs_ordered_sum, - list); - if (!ret) - ret = btrfs_del_csums(trans, - root->fs_info->csum_root, - sums->bytenr, - sums->len); - if (!ret) - ret = btrfs_csum_file_blocks(trans, - root->fs_info->csum_root, - sums); - list_del(&sums->list); - kfree(sums); - } - if (ret) - goto out; - } else { - btrfs_release_path(path); - } - } else if (found_type == BTRFS_FILE_EXTENT_INLINE) { - /* inline extents are easy, we just overwrite them */ - ret = overwrite_item(trans, root, path, eb, slot, key); - if (ret) - goto out; - } - - inode_add_bytes(inode, nbytes); - ret = btrfs_update_inode(trans, root, inode); -out: - if (inode) - iput(inode); - return ret; -} - -/* - * when cleaning up conflicts between the directory names in the - * subvolume, directory names in the log and directory names in the - * inode back references, we may have to unlink inodes from directories. - * - * This is a helper function to do the unlink of a specific directory - * item - */ -static noinline int drop_one_dir_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct inode *dir, - struct btrfs_dir_item *di) -{ - struct inode *inode; - char *name; - int name_len; - struct extent_buffer *leaf; - struct btrfs_key location; - int ret; - - leaf = path->nodes[0]; - - btrfs_dir_item_key_to_cpu(leaf, di, &location); - name_len = btrfs_dir_name_len(leaf, di); - name = kmalloc(name_len, GFP_NOFS); - if (!name) - return -ENOMEM; - - read_extent_buffer(leaf, name, (unsigned long)(di + 1), name_len); - btrfs_release_path(path); - - inode = read_one_inode(root, location.objectid); - if (!inode) { - ret = -EIO; - goto out; - } - - ret = link_to_fixup_dir(trans, root, path, location.objectid); - if (ret) - goto out; - - ret = btrfs_unlink_inode(trans, root, dir, inode, name, name_len); - if (ret) - goto out; - else - ret = btrfs_run_delayed_items(trans, root); -out: - kfree(name); - iput(inode); - return ret; -} - -/* - * helper function to see if a given name and sequence number found - * in an inode back reference are already in a directory and correctly - * point to this inode - */ -static noinline int inode_in_dir(struct btrfs_root *root, - struct btrfs_path *path, - u64 dirid, u64 objectid, u64 index, - const char *name, int name_len) -{ - struct btrfs_dir_item *di; - struct btrfs_key location; - int match = 0; - - di = btrfs_lookup_dir_index_item(NULL, root, path, dirid, - index, name, name_len, 0); - if (di && !IS_ERR(di)) { - btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location); - if (location.objectid != objectid) - goto out; - } else - goto out; - btrfs_release_path(path); - - di = btrfs_lookup_dir_item(NULL, root, path, dirid, name, name_len, 0); - if (di && !IS_ERR(di)) { - btrfs_dir_item_key_to_cpu(path->nodes[0], di, &location); - if (location.objectid != objectid) - goto out; - } else - goto out; - match = 1; -out: - btrfs_release_path(path); - return match; -} - -/* - * helper function to check a log tree for a named back reference in - * an inode. This is used to decide if a back reference that is - * found in the subvolume conflicts with what we find in the log. - * - * inode backreferences may have multiple refs in a single item, - * during replay we process one reference at a time, and we don't - * want to delete valid links to a file from the subvolume if that - * link is also in the log. - */ -static noinline int backref_in_log(struct btrfs_root *log, - struct btrfs_key *key, - u64 ref_objectid, - const char *name, int namelen) -{ - struct btrfs_path *path; - struct btrfs_inode_ref *ref; - unsigned long ptr; - unsigned long ptr_end; - unsigned long name_ptr; - int found_name_len; - int item_size; - int ret; - int match = 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - ret = btrfs_search_slot(NULL, log, key, path, 0, 0); - if (ret != 0) - goto out; - - ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]); - - if (key->type == BTRFS_INODE_EXTREF_KEY) { - if (btrfs_find_name_in_ext_backref(path, ref_objectid, - name, namelen, NULL)) - match = 1; - - goto out; - } - - item_size = btrfs_item_size_nr(path->nodes[0], path->slots[0]); - ptr_end = ptr + item_size; - while (ptr < ptr_end) { - ref = (struct btrfs_inode_ref *)ptr; - found_name_len = btrfs_inode_ref_name_len(path->nodes[0], ref); - if (found_name_len == namelen) { - name_ptr = (unsigned long)(ref + 1); - ret = memcmp_extent_buffer(path->nodes[0], name, - name_ptr, namelen); - if (ret == 0) { - match = 1; - goto out; - } - } - ptr = (unsigned long)(ref + 1) + found_name_len; - } -out: - btrfs_free_path(path); - return match; -} - -static inline int __add_inode_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct btrfs_root *log_root, - struct inode *dir, struct inode *inode, - struct extent_buffer *eb, - u64 inode_objectid, u64 parent_objectid, - u64 ref_index, char *name, int namelen, - int *search_done) -{ - int ret; - char *victim_name; - int victim_name_len; - struct extent_buffer *leaf; - struct btrfs_dir_item *di; - struct btrfs_key search_key; - struct btrfs_inode_extref *extref; - -again: - /* Search old style refs */ - search_key.objectid = inode_objectid; - search_key.type = BTRFS_INODE_REF_KEY; - search_key.offset = parent_objectid; - ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); - if (ret == 0) { - struct btrfs_inode_ref *victim_ref; - unsigned long ptr; - unsigned long ptr_end; - - leaf = path->nodes[0]; - - /* are we trying to overwrite a back ref for the root directory - * if so, just jump out, we're done - */ - if (search_key.objectid == search_key.offset) - return 1; - - /* check all the names in this back reference to see - * if they are in the log. if so, we allow them to stay - * otherwise they must be unlinked as a conflict - */ - ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); - ptr_end = ptr + btrfs_item_size_nr(leaf, path->slots[0]); - while (ptr < ptr_end) { - victim_ref = (struct btrfs_inode_ref *)ptr; - victim_name_len = btrfs_inode_ref_name_len(leaf, - victim_ref); - victim_name = kmalloc(victim_name_len, GFP_NOFS); - if (!victim_name) - return -ENOMEM; - - read_extent_buffer(leaf, victim_name, - (unsigned long)(victim_ref + 1), - victim_name_len); - - if (!backref_in_log(log_root, &search_key, - parent_objectid, - victim_name, - victim_name_len)) { - inc_nlink(inode); - btrfs_release_path(path); - - ret = btrfs_unlink_inode(trans, root, dir, - inode, victim_name, - victim_name_len); - kfree(victim_name); - if (ret) - return ret; - ret = btrfs_run_delayed_items(trans, root); - if (ret) - return ret; - *search_done = 1; - goto again; - } - kfree(victim_name); - - ptr = (unsigned long)(victim_ref + 1) + victim_name_len; - } - - /* - * NOTE: we have searched root tree and checked the - * corresponding ref, it does not need to check again. - */ - *search_done = 1; - } - btrfs_release_path(path); - - /* Same search but for extended refs */ - extref = btrfs_lookup_inode_extref(NULL, root, path, name, namelen, - inode_objectid, parent_objectid, 0, - 0); - if (!IS_ERR_OR_NULL(extref)) { - u32 item_size; - u32 cur_offset = 0; - unsigned long base; - struct inode *victim_parent; - - leaf = path->nodes[0]; - - item_size = btrfs_item_size_nr(leaf, path->slots[0]); - base = btrfs_item_ptr_offset(leaf, path->slots[0]); - - while (cur_offset < item_size) { - extref = (struct btrfs_inode_extref *)(base + cur_offset); - - victim_name_len = btrfs_inode_extref_name_len(leaf, extref); - - if (btrfs_inode_extref_parent(leaf, extref) != parent_objectid) - goto next; - - victim_name = kmalloc(victim_name_len, GFP_NOFS); - if (!victim_name) - return -ENOMEM; - read_extent_buffer(leaf, victim_name, (unsigned long)&extref->name, - victim_name_len); - - search_key.objectid = inode_objectid; - search_key.type = BTRFS_INODE_EXTREF_KEY; - search_key.offset = btrfs_extref_hash(parent_objectid, - victim_name, - victim_name_len); - ret = 0; - if (!backref_in_log(log_root, &search_key, - parent_objectid, victim_name, - victim_name_len)) { - ret = -ENOENT; - victim_parent = read_one_inode(root, - parent_objectid); - if (victim_parent) { - inc_nlink(inode); - btrfs_release_path(path); - - ret = btrfs_unlink_inode(trans, root, - victim_parent, - inode, - victim_name, - victim_name_len); - if (!ret) - ret = btrfs_run_delayed_items( - trans, root); - } - iput(victim_parent); - kfree(victim_name); - if (ret) - return ret; - *search_done = 1; - goto again; - } - kfree(victim_name); - if (ret) - return ret; -next: - cur_offset += victim_name_len + sizeof(*extref); - } - *search_done = 1; - } - btrfs_release_path(path); - - /* look for a conflicting sequence number */ - di = btrfs_lookup_dir_index_item(trans, root, path, btrfs_ino(dir), - ref_index, name, namelen, 0); - if (di && !IS_ERR(di)) { - ret = drop_one_dir_item(trans, root, path, dir, di); - if (ret) - return ret; - } - btrfs_release_path(path); - - /* look for a conflicing name */ - di = btrfs_lookup_dir_item(trans, root, path, btrfs_ino(dir), - name, namelen, 0); - if (di && !IS_ERR(di)) { - ret = drop_one_dir_item(trans, root, path, dir, di); - if (ret) - return ret; - } - btrfs_release_path(path); - - return 0; -} - -static int extref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr, - u32 *namelen, char **name, u64 *index, - u64 *parent_objectid) -{ - struct btrfs_inode_extref *extref; - - extref = (struct btrfs_inode_extref *)ref_ptr; - - *namelen = btrfs_inode_extref_name_len(eb, extref); - *name = kmalloc(*namelen, GFP_NOFS); - if (*name == NULL) - return -ENOMEM; - - read_extent_buffer(eb, *name, (unsigned long)&extref->name, - *namelen); - - *index = btrfs_inode_extref_index(eb, extref); - if (parent_objectid) - *parent_objectid = btrfs_inode_extref_parent(eb, extref); - - return 0; -} - -static int ref_get_fields(struct extent_buffer *eb, unsigned long ref_ptr, - u32 *namelen, char **name, u64 *index) -{ - struct btrfs_inode_ref *ref; - - ref = (struct btrfs_inode_ref *)ref_ptr; - - *namelen = btrfs_inode_ref_name_len(eb, ref); - *name = kmalloc(*namelen, GFP_NOFS); - if (*name == NULL) - return -ENOMEM; - - read_extent_buffer(eb, *name, (unsigned long)(ref + 1), *namelen); - - *index = btrfs_inode_ref_index(eb, ref); - - return 0; -} - -/* - * replay one inode back reference item found in the log tree. - * eb, slot and key refer to the buffer and key found in the log tree. - * root is the destination we are replaying into, and path is for temp - * use by this function. (it should be released on return). - */ -static noinline int add_inode_ref(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_root *log, - struct btrfs_path *path, - struct extent_buffer *eb, int slot, - struct btrfs_key *key) -{ - struct inode *dir = NULL; - struct inode *inode = NULL; - unsigned long ref_ptr; - unsigned long ref_end; - char *name = NULL; - int namelen; - int ret; - int search_done = 0; - int log_ref_ver = 0; - u64 parent_objectid; - u64 inode_objectid; - u64 ref_index = 0; - int ref_struct_size; - - ref_ptr = btrfs_item_ptr_offset(eb, slot); - ref_end = ref_ptr + btrfs_item_size_nr(eb, slot); - - if (key->type == BTRFS_INODE_EXTREF_KEY) { - struct btrfs_inode_extref *r; - - ref_struct_size = sizeof(struct btrfs_inode_extref); - log_ref_ver = 1; - r = (struct btrfs_inode_extref *)ref_ptr; - parent_objectid = btrfs_inode_extref_parent(eb, r); - } else { - ref_struct_size = sizeof(struct btrfs_inode_ref); - parent_objectid = key->offset; - } - inode_objectid = key->objectid; - - /* - * it is possible that we didn't log all the parent directories - * for a given inode. If we don't find the dir, just don't - * copy the back ref in. The link count fixup code will take - * care of the rest - */ - dir = read_one_inode(root, parent_objectid); - if (!dir) { - ret = -ENOENT; - goto out; - } - - inode = read_one_inode(root, inode_objectid); - if (!inode) { - ret = -EIO; - goto out; - } - - while (ref_ptr < ref_end) { - if (log_ref_ver) { - ret = extref_get_fields(eb, ref_ptr, &namelen, &name, - &ref_index, &parent_objectid); - /* - * parent object can change from one array - * item to another. - */ - if (!dir) - dir = read_one_inode(root, parent_objectid); - if (!dir) { - ret = -ENOENT; - goto out; - } - } else { - ret = ref_get_fields(eb, ref_ptr, &namelen, &name, - &ref_index); - } - if (ret) - goto out; - - /* if we already have a perfect match, we're done */ - if (!inode_in_dir(root, path, btrfs_ino(dir), btrfs_ino(inode), - ref_index, name, namelen)) { - /* - * look for a conflicting back reference in the - * metadata. if we find one we have to unlink that name - * of the file before we add our new link. Later on, we - * overwrite any existing back reference, and we don't - * want to create dangling pointers in the directory. - */ - - if (!search_done) { - ret = __add_inode_ref(trans, root, path, log, - dir, inode, eb, - inode_objectid, - parent_objectid, - ref_index, name, namelen, - &search_done); - if (ret) { - if (ret == 1) - ret = 0; - goto out; - } - } - - /* insert our name */ - ret = btrfs_add_link(trans, dir, inode, name, namelen, - 0, ref_index); - if (ret) - goto out; - - btrfs_update_inode(trans, root, inode); - } - - ref_ptr = (unsigned long)(ref_ptr + ref_struct_size) + namelen; - kfree(name); - name = NULL; - if (log_ref_ver) { - iput(dir); - dir = NULL; - } - } - - /* finally write the back reference in the inode */ - ret = overwrite_item(trans, root, path, eb, slot, key); -out: - btrfs_release_path(path); - kfree(name); - iput(dir); - iput(inode); - return ret; -} - -static int insert_orphan_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 ino) -{ - int ret; - - ret = btrfs_insert_orphan_item(trans, root, ino); - if (ret == -EEXIST) - ret = 0; - - return ret; -} - -static int count_inode_extrefs(struct btrfs_root *root, - struct inode *inode, struct btrfs_path *path) -{ - int ret = 0; - int name_len; - unsigned int nlink = 0; - u32 item_size; - u32 cur_offset = 0; - u64 inode_objectid = btrfs_ino(inode); - u64 offset = 0; - unsigned long ptr; - struct btrfs_inode_extref *extref; - struct extent_buffer *leaf; - - while (1) { - ret = btrfs_find_one_extref(root, inode_objectid, offset, path, - &extref, &offset); - if (ret) - break; - - leaf = path->nodes[0]; - item_size = btrfs_item_size_nr(leaf, path->slots[0]); - ptr = btrfs_item_ptr_offset(leaf, path->slots[0]); - cur_offset = 0; - - while (cur_offset < item_size) { - extref = (struct btrfs_inode_extref *) (ptr + cur_offset); - name_len = btrfs_inode_extref_name_len(leaf, extref); - - nlink++; - - cur_offset += name_len + sizeof(*extref); - } - - offset++; - btrfs_release_path(path); - } - btrfs_release_path(path); - - if (ret < 0 && ret != -ENOENT) - return ret; - return nlink; -} - -static int count_inode_refs(struct btrfs_root *root, - struct inode *inode, struct btrfs_path *path) -{ - int ret; - struct btrfs_key key; - unsigned int nlink = 0; - unsigned long ptr; - unsigned long ptr_end; - int name_len; - u64 ino = btrfs_ino(inode); - - key.objectid = ino; - key.type = BTRFS_INODE_REF_KEY; - key.offset = (u64)-1; - - while (1) { - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - break; - if (ret > 0) { - if (path->slots[0] == 0) - break; - path->slots[0]--; - } -process_slot: - btrfs_item_key_to_cpu(path->nodes[0], &key, - path->slots[0]); - if (key.objectid != ino || - key.type != BTRFS_INODE_REF_KEY) - break; - ptr = btrfs_item_ptr_offset(path->nodes[0], path->slots[0]); - ptr_end = ptr + btrfs_item_size_nr(path->nodes[0], - path->slots[0]); - while (ptr < ptr_end) { - struct btrfs_inode_ref *ref; - - ref = (struct btrfs_inode_ref *)ptr; - name_len = btrfs_inode_ref_name_len(path->nodes[0], - ref); - ptr = (unsigned long)(ref + 1) + name_len; - nlink++; - } - - if (key.offset == 0) - break; - if (path->slots[0] > 0) { - path->slots[0]--; - goto process_slot; - } - key.offset--; - btrfs_release_path(path); - } - btrfs_release_path(path); - - return nlink; -} - -/* - * There are a few corners where the link count of the file can't - * be properly maintained during replay. So, instead of adding - * lots of complexity to the log code, we just scan the backrefs - * for any file that has been through replay. - * - * The scan will update the link count on the inode to reflect the - * number of back refs found. If it goes down to zero, the iput - * will free the inode. - */ -static noinline int fixup_inode_link_count(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *inode) -{ - struct btrfs_path *path; - int ret; - u64 nlink = 0; - u64 ino = btrfs_ino(inode); - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - ret = count_inode_refs(root, inode, path); - if (ret < 0) - goto out; - - nlink = ret; - - ret = count_inode_extrefs(root, inode, path); - if (ret < 0) - goto out; - - nlink += ret; - - ret = 0; - - if (nlink != inode->i_nlink) { - set_nlink(inode, nlink); - btrfs_update_inode(trans, root, inode); - } - BTRFS_I(inode)->index_cnt = (u64)-1; - - if (inode->i_nlink == 0) { - if (S_ISDIR(inode->i_mode)) { - ret = replay_dir_deletes(trans, root, NULL, path, - ino, 1); - if (ret) - goto out; - } - ret = insert_orphan_item(trans, root, ino); - } - -out: - btrfs_free_path(path); - return ret; -} - -static noinline int fixup_inode_link_counts(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path) -{ - int ret; - struct btrfs_key key; - struct inode *inode; - - key.objectid = BTRFS_TREE_LOG_FIXUP_OBJECTID; - key.type = BTRFS_ORPHAN_ITEM_KEY; - key.offset = (u64)-1; - while (1) { - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret < 0) - break; - - if (ret == 1) { - if (path->slots[0] == 0) - break; - path->slots[0]--; - } - - btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); - if (key.objectid != BTRFS_TREE_LOG_FIXUP_OBJECTID || - key.type != BTRFS_ORPHAN_ITEM_KEY) - break; - - ret = btrfs_del_item(trans, root, path); - if (ret) - goto out; - - btrfs_release_path(path); - inode = read_one_inode(root, key.offset); - if (!inode) - return -EIO; - - ret = fixup_inode_link_count(trans, root, inode); - iput(inode); - if (ret) - goto out; - - /* - * fixup on a directory may create new entries, - * make sure we always look for the highset possible - * offset - */ - key.offset = (u64)-1; - } - ret = 0; -out: - btrfs_release_path(path); - return ret; -} - - -/* - * record a given inode in the fixup dir so we can check its link - * count when replay is done. The link count is incremented here - * so the inode won't go away until we check it - */ -static noinline int link_to_fixup_dir(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - u64 objectid) -{ - struct btrfs_key key; - int ret = 0; - struct inode *inode; - - inode = read_one_inode(root, objectid); - if (!inode) - return -EIO; - - key.objectid = BTRFS_TREE_LOG_FIXUP_OBJECTID; - key.type = BTRFS_ORPHAN_ITEM_KEY; - key.offset = objectid; - - ret = btrfs_insert_empty_item(trans, root, path, &key, 0); - - btrfs_release_path(path); - if (ret == 0) { - if (!inode->i_nlink) - set_nlink(inode, 1); - else - inc_nlink(inode); - ret = btrfs_update_inode(trans, root, inode); - } else if (ret == -EEXIST) { - ret = 0; - } else { - BUG(); /* Logic Error */ - } - iput(inode); - - return ret; -} - -/* - * when replaying the log for a directory, we only insert names - * for inodes that actually exist. This means an fsync on a directory - * does not implicitly fsync all the new files in it - */ -static noinline int insert_one_name(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - u64 dirid, u64 index, - char *name, int name_len, - struct btrfs_key *location) -{ - struct inode *inode; - struct inode *dir; - int ret; - - inode = read_one_inode(root, location->objectid); - if (!inode) - return -ENOENT; - - dir = read_one_inode(root, dirid); - if (!dir) { - iput(inode); - return -EIO; - } - - ret = btrfs_add_link(trans, dir, inode, name, name_len, 1, index); - - /* FIXME, put inode into FIXUP list */ - - iput(inode); - iput(dir); - return ret; -} - -/* - * Return true if an inode reference exists in the log for the given name, - * inode and parent inode. - */ -static bool name_in_log_ref(struct btrfs_root *log_root, - const char *name, const int name_len, - const u64 dirid, const u64 ino) -{ - struct btrfs_key search_key; - - search_key.objectid = ino; - search_key.type = BTRFS_INODE_REF_KEY; - search_key.offset = dirid; - if (backref_in_log(log_root, &search_key, dirid, name, name_len)) - return true; - - search_key.type = BTRFS_INODE_EXTREF_KEY; - search_key.offset = btrfs_extref_hash(dirid, name, name_len); - if (backref_in_log(log_root, &search_key, dirid, name, name_len)) - return true; - - return false; -} - -/* - * take a single entry in a log directory item and replay it into - * the subvolume. - * - * if a conflicting item exists in the subdirectory already, - * the inode it points to is unlinked and put into the link count - * fix up tree. - * - * If a name from the log points to a file or directory that does - * not exist in the FS, it is skipped. fsyncs on directories - * do not force down inodes inside that directory, just changes to the - * names or unlinks in a directory. - * - * Returns < 0 on error, 0 if the name wasn't replayed (dentry points to a - * non-existing inode) and 1 if the name was replayed. - */ -static noinline int replay_one_name(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct extent_buffer *eb, - struct btrfs_dir_item *di, - struct btrfs_key *key) -{ - char *name; - int name_len; - struct btrfs_dir_item *dst_di; - struct btrfs_key found_key; - struct btrfs_key log_key; - struct inode *dir; - u8 log_type; - int exists; - int ret = 0; - bool update_size = (key->type == BTRFS_DIR_INDEX_KEY); - bool name_added = false; - - dir = read_one_inode(root, key->objectid); - if (!dir) - return -EIO; - - name_len = btrfs_dir_name_len(eb, di); - name = kmalloc(name_len, GFP_NOFS); - if (!name) { - ret = -ENOMEM; - goto out; - } - - log_type = btrfs_dir_type(eb, di); - read_extent_buffer(eb, name, (unsigned long)(di + 1), - name_len); - - btrfs_dir_item_key_to_cpu(eb, di, &log_key); - exists = btrfs_lookup_inode(trans, root, path, &log_key, 0); - if (exists == 0) - exists = 1; - else - exists = 0; - btrfs_release_path(path); - - if (key->type == BTRFS_DIR_ITEM_KEY) { - dst_di = btrfs_lookup_dir_item(trans, root, path, key->objectid, - name, name_len, 1); - } else if (key->type == BTRFS_DIR_INDEX_KEY) { - dst_di = btrfs_lookup_dir_index_item(trans, root, path, - key->objectid, - key->offset, name, - name_len, 1); - } else { - /* Corruption */ - ret = -EINVAL; - goto out; - } - if (IS_ERR_OR_NULL(dst_di)) { - /* we need a sequence number to insert, so we only - * do inserts for the BTRFS_DIR_INDEX_KEY types - */ - if (key->type != BTRFS_DIR_INDEX_KEY) - goto out; - goto insert; - } - - btrfs_dir_item_key_to_cpu(path->nodes[0], dst_di, &found_key); - /* the existing item matches the logged item */ - if (found_key.objectid == log_key.objectid && - found_key.type == log_key.type && - found_key.offset == log_key.offset && - btrfs_dir_type(path->nodes[0], dst_di) == log_type) { - update_size = false; - goto out; - } - - /* - * don't drop the conflicting directory entry if the inode - * for the new entry doesn't exist - */ - if (!exists) - goto out; - - ret = drop_one_dir_item(trans, root, path, dir, dst_di); - if (ret) - goto out; - - if (key->type == BTRFS_DIR_INDEX_KEY) - goto insert; -out: - btrfs_release_path(path); - if (!ret && update_size) { - btrfs_i_size_write(dir, dir->i_size + name_len * 2); - ret = btrfs_update_inode(trans, root, dir); - } - kfree(name); - iput(dir); - if (!ret && name_added) - ret = 1; - return ret; - -insert: - if (name_in_log_ref(root->log_root, name, name_len, - key->objectid, log_key.objectid)) { - /* The dentry will be added later. */ - ret = 0; - update_size = false; - goto out; - } - btrfs_release_path(path); - ret = insert_one_name(trans, root, key->objectid, key->offset, - name, name_len, &log_key); - if (ret && ret != -ENOENT && ret != -EEXIST) - goto out; - if (!ret) - name_added = true; - update_size = false; - ret = 0; - goto out; -} - -/* - * find all the names in a directory item and reconcile them into - * the subvolume. Only BTRFS_DIR_ITEM_KEY types will have more than - * one name in a directory item, but the same code gets used for - * both directory index types - */ -static noinline int replay_one_dir_item(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, - struct extent_buffer *eb, int slot, - struct btrfs_key *key) -{ - int ret = 0; - u32 item_size = btrfs_item_size_nr(eb, slot); - struct btrfs_dir_item *di; - int name_len; - unsigned long ptr; - unsigned long ptr_end; - struct btrfs_path *fixup_path = NULL; - - ptr = btrfs_item_ptr_offset(eb, slot); - ptr_end = ptr + item_size; - while (ptr < ptr_end) { - di = (struct btrfs_dir_item *)ptr; - if (verify_dir_item(root, eb, di)) - return -EIO; - name_len = btrfs_dir_name_len(eb, di); - ret = replay_one_name(trans, root, path, eb, di, key); - if (ret < 0) - break; - ptr = (unsigned long)(di + 1); - ptr += name_len; - - /* - * If this entry refers to a non-directory (directories can not - * have a link count > 1) and it was added in the transaction - * that was not committed, make sure we fixup the link count of - * the inode it the entry points to. Otherwise something like - * the following would result in a directory pointing to an - * inode with a wrong link that does not account for this dir - * entry: - * - * mkdir testdir - * touch testdir/foo - * touch testdir/bar - * sync - * - * ln testdir/bar testdir/bar_link - * ln testdir/foo testdir/foo_link - * xfs_io -c "fsync" testdir/bar - * - * - * - * mount fs, log replay happens - * - * File foo would remain with a link count of 1 when it has two - * entries pointing to it in the directory testdir. This would - * make it impossible to ever delete the parent directory has - * it would result in stale dentries that can never be deleted. - */ - if (ret == 1 && btrfs_dir_type(eb, di) != BTRFS_FT_DIR) { - struct btrfs_key di_key; - - if (!fixup_path) { - fixup_path = btrfs_alloc_path(); - if (!fixup_path) { - ret = -ENOMEM; - break; - } - } - - btrfs_dir_item_key_to_cpu(eb, di, &di_key); - ret = link_to_fixup_dir(trans, root, fixup_path, - di_key.objectid); - if (ret) - break; - } - ret = 0; - } - btrfs_free_path(fixup_path); - return ret; -} - -/* - * directory replay has two parts. There are the standard directory - * items in the log copied from the subvolume, and range items - * created in the log while the subvolume was logged. - * - * The range items tell us which parts of the key space the log - * is authoritative for. During replay, if a key in the subvolume - * directory is in a logged range item, but not actually in the log - * that means it was deleted from the directory before the fsync - * and should be removed. - */ -static noinline int find_dir_range(struct btrfs_root *root, - struct btrfs_path *path, - u64 dirid, int key_type, - u64 *start_ret, u64 *end_ret) -{ - struct btrfs_key key; - u64 found_end; - struct btrfs_dir_log_item *item; - int ret; - int nritems; - - if (*start_ret == (u64)-1) - return 1; - - key.objectid = dirid; - key.type = key_type; - key.offset = *start_ret; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out; - if (ret > 0) { - if (path->slots[0] == 0) - goto out; - path->slots[0]--; - } - if (ret != 0) - btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); - - if (key.type != key_type || key.objectid != dirid) { - ret = 1; - goto next; - } - item = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_dir_log_item); - found_end = btrfs_dir_log_end(path->nodes[0], item); - - if (*start_ret >= key.offset && *start_ret <= found_end) { - ret = 0; - *start_ret = key.offset; - *end_ret = found_end; - goto out; - } - ret = 1; -next: - /* check the next slot in the tree to see if it is a valid item */ - nritems = btrfs_header_nritems(path->nodes[0]); - if (path->slots[0] >= nritems) { - ret = btrfs_next_leaf(root, path); - if (ret) - goto out; - } else { - path->slots[0]++; - } - - btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]); - - if (key.type != key_type || key.objectid != dirid) { - ret = 1; - goto out; - } - item = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_dir_log_item); - found_end = btrfs_dir_log_end(path->nodes[0], item); - *start_ret = key.offset; - *end_ret = found_end; - ret = 0; -out: - btrfs_release_path(path); - return ret; -} - -/* - * this looks for a given directory item in the log. If the directory - * item is not in the log, the item is removed and the inode it points - * to is unlinked - */ -static noinline int check_item_in_log(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_root *log, - struct btrfs_path *path, - struct btrfs_path *log_path, - struct inode *dir, - struct btrfs_key *dir_key) -{ - int ret; - struct extent_buffer *eb; - int slot; - u32 item_size; - struct btrfs_dir_item *di; - struct btrfs_dir_item *log_di; - int name_len; - unsigned long ptr; - unsigned long ptr_end; - char *name; - struct inode *inode; - struct btrfs_key location; - -again: - eb = path->nodes[0]; - slot = path->slots[0]; - item_size = btrfs_item_size_nr(eb, slot); - ptr = btrfs_item_ptr_offset(eb, slot); - ptr_end = ptr + item_size; - while (ptr < ptr_end) { - di = (struct btrfs_dir_item *)ptr; - if (verify_dir_item(root, eb, di)) { - ret = -EIO; - goto out; - } - - name_len = btrfs_dir_name_len(eb, di); - name = kmalloc(name_len, GFP_NOFS); - if (!name) { - ret = -ENOMEM; - goto out; - } - read_extent_buffer(eb, name, (unsigned long)(di + 1), - name_len); - log_di = NULL; - if (log && dir_key->type == BTRFS_DIR_ITEM_KEY) { - log_di = btrfs_lookup_dir_item(trans, log, log_path, - dir_key->objectid, - name, name_len, 0); - } else if (log && dir_key->type == BTRFS_DIR_INDEX_KEY) { - log_di = btrfs_lookup_dir_index_item(trans, log, - log_path, - dir_key->objectid, - dir_key->offset, - name, name_len, 0); - } - if (!log_di || (IS_ERR(log_di) && PTR_ERR(log_di) == -ENOENT)) { - btrfs_dir_item_key_to_cpu(eb, di, &location); - btrfs_release_path(path); - btrfs_release_path(log_path); - inode = read_one_inode(root, location.objectid); - if (!inode) { - kfree(name); - return -EIO; - } - - ret = link_to_fixup_dir(trans, root, - path, location.objectid); - if (ret) { - kfree(name); - iput(inode); - goto out; - } - - inc_nlink(inode); - ret = btrfs_unlink_inode(trans, root, dir, inode, - name, name_len); - if (!ret) - ret = btrfs_run_delayed_items(trans, root); - kfree(name); - iput(inode); - if (ret) - goto out; - - /* there might still be more names under this key - * check and repeat if required - */ - ret = btrfs_search_slot(NULL, root, dir_key, path, - 0, 0); - if (ret == 0) - goto again; - ret = 0; - goto out; - } else if (IS_ERR(log_di)) { - kfree(name); - return PTR_ERR(log_di); - } - btrfs_release_path(log_path); - kfree(name); - - ptr = (unsigned long)(di + 1); - ptr += name_len; - } - ret = 0; -out: - btrfs_release_path(path); - btrfs_release_path(log_path); - return ret; -} - -static int replay_xattr_deletes(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_root *log, - struct btrfs_path *path, - const u64 ino) -{ - struct btrfs_key search_key; - struct btrfs_path *log_path; - int i; - int nritems; - int ret; - - log_path = btrfs_alloc_path(); - if (!log_path) - return -ENOMEM; - - search_key.objectid = ino; - search_key.type = BTRFS_XATTR_ITEM_KEY; - search_key.offset = 0; -again: - ret = btrfs_search_slot(NULL, root, &search_key, path, 0, 0); - if (ret < 0) - goto out; -process_leaf: - nritems = btrfs_header_nritems(path->nodes[0]); - for (i = path->slots[0]; i < nritems; i++) { - struct btrfs_key key; - struct btrfs_dir_item *di; - struct btrfs_dir_item *log_di; - u32 total_size; - u32 cur; - - btrfs_item_key_to_cpu(path->nodes[0], &key, i); - if (key.objectid != ino || key.type != BTRFS_XATTR_ITEM_KEY) { - ret = 0; - goto out; - } - - di = btrfs_item_ptr(path->nodes[0], i, struct btrfs_dir_item); - total_size = btrfs_item_size_nr(path->nodes[0], i); - cur = 0; - while (cur < total_size) { - u16 name_len = btrfs_dir_name_len(path->nodes[0], di); - u16 data_len = btrfs_dir_data_len(path->nodes[0], di); - u32 this_len = sizeof(*di) + name_len + data_len; - char *name; - - name = kmalloc(name_len, GFP_NOFS); - if (!name) { - ret = -ENOMEM; - goto out; - } - read_extent_buffer(path->nodes[0], name, - (unsigned long)(di + 1), name_len); - - log_di = btrfs_lookup_xattr(NULL, log, log_path, ino, - name, name_len, 0); - btrfs_release_path(log_path); - if (!log_di) { - /* Doesn't exist in log tree, so delete it. */ - btrfs_release_path(path); - di = btrfs_lookup_xattr(trans, root, path, ino, - name, name_len, -1); - kfree(name); - if (IS_ERR(di)) { - ret = PTR_ERR(di); - goto out; - } - ASSERT(di); - ret = btrfs_delete_one_dir_name(trans, root, - path, di); - if (ret) - goto out; - btrfs_release_path(path); - search_key = key; - goto again; - } - kfree(name); - if (IS_ERR(log_di)) { - ret = PTR_ERR(log_di); - goto out; - } - cur += this_len; - di = (struct btrfs_dir_item *)((char *)di + this_len); - } - } - ret = btrfs_next_leaf(root, path); - if (ret > 0) - ret = 0; - else if (ret == 0) - goto process_leaf; -out: - btrfs_free_path(log_path); - btrfs_release_path(path); - return ret; -} - - -/* - * deletion replay happens before we copy any new directory items - * out of the log or out of backreferences from inodes. It - * scans the log to find ranges of keys that log is authoritative for, - * and then scans the directory to find items in those ranges that are - * not present in the log. - * - * Anything we don't find in the log is unlinked and removed from the - * directory. - */ -static noinline int replay_dir_deletes(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_root *log, - struct btrfs_path *path, - u64 dirid, int del_all) -{ - u64 range_start; - u64 range_end; - int key_type = BTRFS_DIR_LOG_ITEM_KEY; - int ret = 0; - struct btrfs_key dir_key; - struct btrfs_key found_key; - struct btrfs_path *log_path; - struct inode *dir; - - dir_key.objectid = dirid; - dir_key.type = BTRFS_DIR_ITEM_KEY; - log_path = btrfs_alloc_path(); - if (!log_path) - return -ENOMEM; - - dir = read_one_inode(root, dirid); - /* it isn't an error if the inode isn't there, that can happen - * because we replay the deletes before we copy in the inode item - * from the log - */ - if (!dir) { - btrfs_free_path(log_path); - return 0; - } -again: - range_start = 0; - range_end = 0; - while (1) { - if (del_all) - range_end = (u64)-1; - else { - ret = find_dir_range(log, path, dirid, key_type, - &range_start, &range_end); - if (ret != 0) - break; - } - - dir_key.offset = range_start; - while (1) { - int nritems; - ret = btrfs_search_slot(NULL, root, &dir_key, path, - 0, 0); - if (ret < 0) - goto out; - - nritems = btrfs_header_nritems(path->nodes[0]); - if (path->slots[0] >= nritems) { - ret = btrfs_next_leaf(root, path); - if (ret) - break; - } - btrfs_item_key_to_cpu(path->nodes[0], &found_key, - path->slots[0]); - if (found_key.objectid != dirid || - found_key.type != dir_key.type) - goto next_type; - - if (found_key.offset > range_end) - break; - - ret = check_item_in_log(trans, root, log, path, - log_path, dir, - &found_key); - if (ret) - goto out; - if (found_key.offset == (u64)-1) - break; - dir_key.offset = found_key.offset + 1; - } - btrfs_release_path(path); - if (range_end == (u64)-1) - break; - range_start = range_end + 1; - } - -next_type: - ret = 0; - if (key_type == BTRFS_DIR_LOG_ITEM_KEY) { - key_type = BTRFS_DIR_LOG_INDEX_KEY; - dir_key.type = BTRFS_DIR_INDEX_KEY; - btrfs_release_path(path); - goto again; - } -out: - btrfs_release_path(path); - btrfs_free_path(log_path); - iput(dir); - return ret; -} - -/* - * the process_func used to replay items from the log tree. This - * gets called in two different stages. The first stage just looks - * for inodes and makes sure they are all copied into the subvolume. - * - * The second stage copies all the other item types from the log into - * the subvolume. The two stage approach is slower, but gets rid of - * lots of complexity around inodes referencing other inodes that exist - * only in the log (references come from either directory items or inode - * back refs). - */ -static int replay_one_buffer(struct btrfs_root *log, struct extent_buffer *eb, - struct walk_control *wc, u64 gen) -{ - int nritems; - struct btrfs_path *path; - struct btrfs_root *root = wc->replay_dest; - struct btrfs_key key; - int level; - int i; - int ret; - - ret = btrfs_read_buffer(eb, gen); - if (ret) - return ret; - - level = btrfs_header_level(eb); - - if (level != 0) - return 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - nritems = btrfs_header_nritems(eb); - for (i = 0; i < nritems; i++) { - btrfs_item_key_to_cpu(eb, &key, i); - - /* inode keys are done during the first stage */ - if (key.type == BTRFS_INODE_ITEM_KEY && - wc->stage == LOG_WALK_REPLAY_INODES) { - struct btrfs_inode_item *inode_item; - u32 mode; - - inode_item = btrfs_item_ptr(eb, i, - struct btrfs_inode_item); - ret = replay_xattr_deletes(wc->trans, root, log, - path, key.objectid); - if (ret) - break; - mode = btrfs_inode_mode(eb, inode_item); - if (S_ISDIR(mode)) { - ret = replay_dir_deletes(wc->trans, - root, log, path, key.objectid, 0); - if (ret) - break; - } - ret = overwrite_item(wc->trans, root, path, - eb, i, &key); - if (ret) - break; - - /* for regular files, make sure corresponding - * orphan item exist. extents past the new EOF - * will be truncated later by orphan cleanup. - */ - if (S_ISREG(mode)) { - ret = insert_orphan_item(wc->trans, root, - key.objectid); - if (ret) - break; - } - - ret = link_to_fixup_dir(wc->trans, root, - path, key.objectid); - if (ret) - break; - } - - if (key.type == BTRFS_DIR_INDEX_KEY && - wc->stage == LOG_WALK_REPLAY_DIR_INDEX) { - ret = replay_one_dir_item(wc->trans, root, path, - eb, i, &key); - if (ret) - break; - } - - if (wc->stage < LOG_WALK_REPLAY_ALL) - continue; - - /* these keys are simply copied */ - if (key.type == BTRFS_XATTR_ITEM_KEY) { - ret = overwrite_item(wc->trans, root, path, - eb, i, &key); - if (ret) - break; - } else if (key.type == BTRFS_INODE_REF_KEY || - key.type == BTRFS_INODE_EXTREF_KEY) { - ret = add_inode_ref(wc->trans, root, log, path, - eb, i, &key); - if (ret && ret != -ENOENT) - break; - ret = 0; - } else if (key.type == BTRFS_EXTENT_DATA_KEY) { - ret = replay_one_extent(wc->trans, root, path, - eb, i, &key); - if (ret) - break; - } else if (key.type == BTRFS_DIR_ITEM_KEY) { - ret = replay_one_dir_item(wc->trans, root, path, - eb, i, &key); - if (ret) - break; - } - } - btrfs_free_path(path); - return ret; -} - -static noinline int walk_down_log_tree(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, int *level, - struct walk_control *wc) -{ - u64 root_owner; - u64 bytenr; - u64 ptr_gen; - struct extent_buffer *next; - struct extent_buffer *cur; - struct extent_buffer *parent; - u32 blocksize; - int ret = 0; - - WARN_ON(*level < 0); - WARN_ON(*level >= BTRFS_MAX_LEVEL); - - while (*level > 0) { - WARN_ON(*level < 0); - WARN_ON(*level >= BTRFS_MAX_LEVEL); - cur = path->nodes[*level]; - - WARN_ON(btrfs_header_level(cur) != *level); - - if (path->slots[*level] >= - btrfs_header_nritems(cur)) - break; - - bytenr = btrfs_node_blockptr(cur, path->slots[*level]); - ptr_gen = btrfs_node_ptr_generation(cur, path->slots[*level]); - blocksize = root->nodesize; - - parent = path->nodes[*level]; - root_owner = btrfs_header_owner(parent); - - next = btrfs_find_create_tree_block(root, bytenr); - if (IS_ERR(next)) - return PTR_ERR(next); - - if (*level == 1) { - ret = wc->process_func(root, next, wc, ptr_gen); - if (ret) { - free_extent_buffer(next); - return ret; - } - - path->slots[*level]++; - if (wc->free) { - ret = btrfs_read_buffer(next, ptr_gen); - if (ret) { - free_extent_buffer(next); - return ret; - } - - if (trans) { - btrfs_tree_lock(next); - btrfs_set_lock_blocking(next); - clean_tree_block(trans, root->fs_info, - next); - btrfs_wait_tree_block_writeback(next); - btrfs_tree_unlock(next); - } - - WARN_ON(root_owner != - BTRFS_TREE_LOG_OBJECTID); - ret = btrfs_free_and_pin_reserved_extent(root, - bytenr, blocksize); - if (ret) { - free_extent_buffer(next); - return ret; - } - } - free_extent_buffer(next); - continue; - } - ret = btrfs_read_buffer(next, ptr_gen); - if (ret) { - free_extent_buffer(next); - return ret; - } - - WARN_ON(*level <= 0); - if (path->nodes[*level-1]) - free_extent_buffer(path->nodes[*level-1]); - path->nodes[*level-1] = next; - *level = btrfs_header_level(next); - path->slots[*level] = 0; - cond_resched(); - } - WARN_ON(*level < 0); - WARN_ON(*level >= BTRFS_MAX_LEVEL); - - path->slots[*level] = btrfs_header_nritems(path->nodes[*level]); - - cond_resched(); - return 0; -} - -static noinline int walk_up_log_tree(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_path *path, int *level, - struct walk_control *wc) -{ - u64 root_owner; - int i; - int slot; - int ret; - - for (i = *level; i < BTRFS_MAX_LEVEL - 1 && path->nodes[i]; i++) { - slot = path->slots[i]; - if (slot + 1 < btrfs_header_nritems(path->nodes[i])) { - path->slots[i]++; - *level = i; - WARN_ON(*level == 0); - return 0; - } else { - struct extent_buffer *parent; - if (path->nodes[*level] == root->node) - parent = path->nodes[*level]; - else - parent = path->nodes[*level + 1]; - - root_owner = btrfs_header_owner(parent); - ret = wc->process_func(root, path->nodes[*level], wc, - btrfs_header_generation(path->nodes[*level])); - if (ret) - return ret; - - if (wc->free) { - struct extent_buffer *next; - - next = path->nodes[*level]; - - if (trans) { - btrfs_tree_lock(next); - btrfs_set_lock_blocking(next); - clean_tree_block(trans, root->fs_info, - next); - btrfs_wait_tree_block_writeback(next); - btrfs_tree_unlock(next); - } - - WARN_ON(root_owner != BTRFS_TREE_LOG_OBJECTID); - ret = btrfs_free_and_pin_reserved_extent(root, - path->nodes[*level]->start, - path->nodes[*level]->len); - if (ret) - return ret; - } - free_extent_buffer(path->nodes[*level]); - path->nodes[*level] = NULL; - *level = i + 1; - } - } - return 1; -} - -/* - * drop the reference count on the tree rooted at 'snap'. This traverses - * the tree freeing any blocks that have a ref count of zero after being - * decremented. - */ -static int walk_log_tree(struct btrfs_trans_handle *trans, - struct btrfs_root *log, struct walk_control *wc) -{ - int ret = 0; - int wret; - int level; - struct btrfs_path *path; - int orig_level; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - level = btrfs_header_level(log->node); - orig_level = level; - path->nodes[level] = log->node; - extent_buffer_get(log->node); - path->slots[level] = 0; - - while (1) { - wret = walk_down_log_tree(trans, log, path, &level, wc); - if (wret > 0) - break; - if (wret < 0) { - ret = wret; - goto out; - } - - wret = walk_up_log_tree(trans, log, path, &level, wc); - if (wret > 0) - break; - if (wret < 0) { - ret = wret; - goto out; - } - } - - /* was the root node processed? if not, catch it here */ - if (path->nodes[orig_level]) { - ret = wc->process_func(log, path->nodes[orig_level], wc, - btrfs_header_generation(path->nodes[orig_level])); - if (ret) - goto out; - if (wc->free) { - struct extent_buffer *next; - - next = path->nodes[orig_level]; - - if (trans) { - btrfs_tree_lock(next); - btrfs_set_lock_blocking(next); - clean_tree_block(trans, log->fs_info, next); - btrfs_wait_tree_block_writeback(next); - btrfs_tree_unlock(next); - } - - WARN_ON(log->root_key.objectid != - BTRFS_TREE_LOG_OBJECTID); - ret = btrfs_free_and_pin_reserved_extent(log, next->start, - next->len); - if (ret) - goto out; - } - } - -out: - btrfs_free_path(path); - return ret; -} - -/* - * helper function to update the item for a given subvolumes log root - * in the tree of log roots - */ -static int update_log_root(struct btrfs_trans_handle *trans, - struct btrfs_root *log) -{ - int ret; - - if (log->log_transid == 1) { - /* insert root item on the first sync */ - ret = btrfs_insert_root(trans, log->fs_info->log_root_tree, - &log->root_key, &log->root_item); - } else { - ret = btrfs_update_root(trans, log->fs_info->log_root_tree, - &log->root_key, &log->root_item); - } - return ret; -} - -static void wait_log_commit(struct btrfs_root *root, int transid) -{ - DEFINE_WAIT(wait); - int index = transid % 2; - - /* - * we only allow two pending log transactions at a time, - * so we know that if ours is more than 2 older than the - * current transaction, we're done - */ - do { - prepare_to_wait(&root->log_commit_wait[index], - &wait, TASK_UNINTERRUPTIBLE); - mutex_unlock(&root->log_mutex); - - if (root->log_transid_committed < transid && - atomic_read(&root->log_commit[index])) - schedule(); - - finish_wait(&root->log_commit_wait[index], &wait); - mutex_lock(&root->log_mutex); - } while (root->log_transid_committed < transid && - atomic_read(&root->log_commit[index])); -} - -static void wait_for_writer(struct btrfs_root *root) -{ - DEFINE_WAIT(wait); - - while (atomic_read(&root->log_writers)) { - prepare_to_wait(&root->log_writer_wait, - &wait, TASK_UNINTERRUPTIBLE); - mutex_unlock(&root->log_mutex); - if (atomic_read(&root->log_writers)) - schedule(); - finish_wait(&root->log_writer_wait, &wait); - mutex_lock(&root->log_mutex); - } -} - -static inline void btrfs_remove_log_ctx(struct btrfs_root *root, - struct btrfs_log_ctx *ctx) -{ - if (!ctx) - return; - - mutex_lock(&root->log_mutex); - list_del_init(&ctx->list); - mutex_unlock(&root->log_mutex); -} - -/* - * Invoked in log mutex context, or be sure there is no other task which - * can access the list. - */ -static inline void btrfs_remove_all_log_ctxs(struct btrfs_root *root, - int index, int error) -{ - struct btrfs_log_ctx *ctx; - struct btrfs_log_ctx *safe; - - list_for_each_entry_safe(ctx, safe, &root->log_ctxs[index], list) { - list_del_init(&ctx->list); - ctx->log_ret = error; - } - - INIT_LIST_HEAD(&root->log_ctxs[index]); -} - -/* - * btrfs_sync_log does sends a given tree log down to the disk and - * updates the super blocks to record it. When this call is done, - * you know that any inodes previously logged are safely on disk only - * if it returns 0. - * - * Any other return value means you need to call btrfs_commit_transaction. - * Some of the edge cases for fsyncing directories that have had unlinks - * or renames done in the past mean that sometimes the only safe - * fsync is to commit the whole FS. When btrfs_sync_log returns -EAGAIN, - * that has happened. - */ -int btrfs_sync_log(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct btrfs_log_ctx *ctx) -{ - int index1; - int index2; - int mark; - int ret; - struct btrfs_root *log = root->log_root; - struct btrfs_root *log_root_tree = root->fs_info->log_root_tree; - int log_transid = 0; - struct btrfs_log_ctx root_log_ctx; - struct blk_plug plug; - - mutex_lock(&root->log_mutex); - log_transid = ctx->log_transid; - if (root->log_transid_committed >= log_transid) { - mutex_unlock(&root->log_mutex); - return ctx->log_ret; - } - - index1 = log_transid % 2; - if (atomic_read(&root->log_commit[index1])) { - wait_log_commit(root, log_transid); - mutex_unlock(&root->log_mutex); - return ctx->log_ret; - } - ASSERT(log_transid == root->log_transid); - atomic_set(&root->log_commit[index1], 1); - - /* wait for previous tree log sync to complete */ - if (atomic_read(&root->log_commit[(index1 + 1) % 2])) - wait_log_commit(root, log_transid - 1); - - while (1) { - int batch = atomic_read(&root->log_batch); - /* when we're on an ssd, just kick the log commit out */ - if (!btrfs_test_opt(root->fs_info, SSD) && - test_bit(BTRFS_ROOT_MULTI_LOG_TASKS, &root->state)) { - mutex_unlock(&root->log_mutex); - schedule_timeout_uninterruptible(1); - mutex_lock(&root->log_mutex); - } - wait_for_writer(root); - if (batch == atomic_read(&root->log_batch)) - break; - } - - /* bail out if we need to do a full commit */ - if (btrfs_need_log_full_commit(root->fs_info, trans)) { - ret = -EAGAIN; - btrfs_free_logged_extents(log, log_transid); - mutex_unlock(&root->log_mutex); - goto out; - } - - if (log_transid % 2 == 0) - mark = EXTENT_DIRTY; - else - mark = EXTENT_NEW; - - /* we start IO on all the marked extents here, but we don't actually - * wait for them until later. - */ - blk_start_plug(&plug); - ret = btrfs_write_marked_extents(log, &log->dirty_log_pages, mark); - if (ret) { - blk_finish_plug(&plug); - btrfs_abort_transaction(trans, ret); - btrfs_free_logged_extents(log, log_transid); - btrfs_set_log_full_commit(root->fs_info, trans); - mutex_unlock(&root->log_mutex); - goto out; - } - - btrfs_set_root_node(&log->root_item, log->node); - - root->log_transid++; - log->log_transid = root->log_transid; - root->log_start_pid = 0; - /* - * IO has been started, blocks of the log tree have WRITTEN flag set - * in their headers. new modifications of the log will be written to - * new positions. so it's safe to allow log writers to go in. - */ - mutex_unlock(&root->log_mutex); - - btrfs_init_log_ctx(&root_log_ctx, NULL); - - mutex_lock(&log_root_tree->log_mutex); - atomic_inc(&log_root_tree->log_batch); - atomic_inc(&log_root_tree->log_writers); - - index2 = log_root_tree->log_transid % 2; - list_add_tail(&root_log_ctx.list, &log_root_tree->log_ctxs[index2]); - root_log_ctx.log_transid = log_root_tree->log_transid; - - mutex_unlock(&log_root_tree->log_mutex); - - ret = update_log_root(trans, log); - - mutex_lock(&log_root_tree->log_mutex); - if (atomic_dec_and_test(&log_root_tree->log_writers)) { - /* - * Implicit memory barrier after atomic_dec_and_test - */ - if (waitqueue_active(&log_root_tree->log_writer_wait)) - wake_up(&log_root_tree->log_writer_wait); - } - - if (ret) { - if (!list_empty(&root_log_ctx.list)) - list_del_init(&root_log_ctx.list); - - blk_finish_plug(&plug); - btrfs_set_log_full_commit(root->fs_info, trans); - - if (ret != -ENOSPC) { - btrfs_abort_transaction(trans, ret); - mutex_unlock(&log_root_tree->log_mutex); - goto out; - } - btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); - btrfs_free_logged_extents(log, log_transid); - mutex_unlock(&log_root_tree->log_mutex); - ret = -EAGAIN; - goto out; - } - - if (log_root_tree->log_transid_committed >= root_log_ctx.log_transid) { - blk_finish_plug(&plug); - list_del_init(&root_log_ctx.list); - mutex_unlock(&log_root_tree->log_mutex); - ret = root_log_ctx.log_ret; - goto out; - } - - index2 = root_log_ctx.log_transid % 2; - if (atomic_read(&log_root_tree->log_commit[index2])) { - blk_finish_plug(&plug); - ret = btrfs_wait_marked_extents(log, &log->dirty_log_pages, - mark); - btrfs_wait_logged_extents(trans, log, log_transid); - wait_log_commit(log_root_tree, - root_log_ctx.log_transid); - mutex_unlock(&log_root_tree->log_mutex); - if (!ret) - ret = root_log_ctx.log_ret; - goto out; - } - ASSERT(root_log_ctx.log_transid == log_root_tree->log_transid); - atomic_set(&log_root_tree->log_commit[index2], 1); - - if (atomic_read(&log_root_tree->log_commit[(index2 + 1) % 2])) { - wait_log_commit(log_root_tree, - root_log_ctx.log_transid - 1); - } - - wait_for_writer(log_root_tree); - - /* - * now that we've moved on to the tree of log tree roots, - * check the full commit flag again - */ - if (btrfs_need_log_full_commit(root->fs_info, trans)) { - blk_finish_plug(&plug); - btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); - btrfs_free_logged_extents(log, log_transid); - mutex_unlock(&log_root_tree->log_mutex); - ret = -EAGAIN; - goto out_wake_log_root; - } - - ret = btrfs_write_marked_extents(log_root_tree, - &log_root_tree->dirty_log_pages, - EXTENT_DIRTY | EXTENT_NEW); - blk_finish_plug(&plug); - if (ret) { - btrfs_set_log_full_commit(root->fs_info, trans); - btrfs_abort_transaction(trans, ret); - btrfs_free_logged_extents(log, log_transid); - mutex_unlock(&log_root_tree->log_mutex); - goto out_wake_log_root; - } - ret = btrfs_wait_marked_extents(log, &log->dirty_log_pages, mark); - if (!ret) - ret = btrfs_wait_marked_extents(log_root_tree, - &log_root_tree->dirty_log_pages, - EXTENT_NEW | EXTENT_DIRTY); - if (ret) { - btrfs_set_log_full_commit(root->fs_info, trans); - btrfs_free_logged_extents(log, log_transid); - mutex_unlock(&log_root_tree->log_mutex); - goto out_wake_log_root; - } - btrfs_wait_logged_extents(trans, log, log_transid); - - btrfs_set_super_log_root(root->fs_info->super_for_commit, - log_root_tree->node->start); - btrfs_set_super_log_root_level(root->fs_info->super_for_commit, - btrfs_header_level(log_root_tree->node)); - - log_root_tree->log_transid++; - mutex_unlock(&log_root_tree->log_mutex); - - /* - * nobody else is going to jump in and write the the ctree - * super here because the log_commit atomic below is protecting - * us. We must be called with a transaction handle pinning - * the running transaction open, so a full commit can't hop - * in and cause problems either. - */ - ret = write_ctree_super(trans, root->fs_info->tree_root, 1); - if (ret) { - btrfs_set_log_full_commit(root->fs_info, trans); - btrfs_abort_transaction(trans, ret); - goto out_wake_log_root; - } - - mutex_lock(&root->log_mutex); - if (root->last_log_commit < log_transid) - root->last_log_commit = log_transid; - mutex_unlock(&root->log_mutex); - -out_wake_log_root: - mutex_lock(&log_root_tree->log_mutex); - btrfs_remove_all_log_ctxs(log_root_tree, index2, ret); - - log_root_tree->log_transid_committed++; - atomic_set(&log_root_tree->log_commit[index2], 0); - mutex_unlock(&log_root_tree->log_mutex); - - /* - * The barrier before waitqueue_active is implied by mutex_unlock - */ - if (waitqueue_active(&log_root_tree->log_commit_wait[index2])) - wake_up(&log_root_tree->log_commit_wait[index2]); -out: - mutex_lock(&root->log_mutex); - btrfs_remove_all_log_ctxs(root, index1, ret); - root->log_transid_committed++; - atomic_set(&root->log_commit[index1], 0); - mutex_unlock(&root->log_mutex); - - /* - * The barrier before waitqueue_active is implied by mutex_unlock - */ - if (waitqueue_active(&root->log_commit_wait[index1])) - wake_up(&root->log_commit_wait[index1]); - return ret; -} - -static void free_log_tree(struct btrfs_trans_handle *trans, - struct btrfs_root *log) -{ - int ret; - u64 start; - u64 end; - struct walk_control wc = { - .free = 1, - .process_func = process_one_buffer - }; - - ret = walk_log_tree(trans, log, &wc); - /* I don't think this can happen but just in case */ - if (ret) - btrfs_abort_transaction(trans, ret); - - while (1) { - ret = find_first_extent_bit(&log->dirty_log_pages, - 0, &start, &end, EXTENT_DIRTY | EXTENT_NEW, - NULL); - if (ret) - break; - - clear_extent_bits(&log->dirty_log_pages, start, end, - EXTENT_DIRTY | EXTENT_NEW); - } - - /* - * We may have short-circuited the log tree with the full commit logic - * and left ordered extents on our list, so clear these out to keep us - * from leaking inodes and memory. - */ - btrfs_free_logged_extents(log, 0); - btrfs_free_logged_extents(log, 1); - - free_extent_buffer(log->node); - kfree(log); -} - -/* - * free all the extents used by the tree log. This should be called - * at commit time of the full transaction - */ -int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root) -{ - if (root->log_root) { - free_log_tree(trans, root->log_root); - root->log_root = NULL; - } - return 0; -} - -int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info) -{ - if (fs_info->log_root_tree) { - free_log_tree(trans, fs_info->log_root_tree); - fs_info->log_root_tree = NULL; - } - return 0; -} - -/* - * If both a file and directory are logged, and unlinks or renames are - * mixed in, we have a few interesting corners: - * - * create file X in dir Y - * link file X to X.link in dir Y - * fsync file X - * unlink file X but leave X.link - * fsync dir Y - * - * After a crash we would expect only X.link to exist. But file X - * didn't get fsync'd again so the log has back refs for X and X.link. - * - * We solve this by removing directory entries and inode backrefs from the - * log when a file that was logged in the current transaction is - * unlinked. Any later fsync will include the updated log entries, and - * we'll be able to reconstruct the proper directory items from backrefs. - * - * This optimizations allows us to avoid relogging the entire inode - * or the entire directory. - */ -int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - const char *name, int name_len, - struct inode *dir, u64 index) -{ - struct btrfs_root *log; - struct btrfs_dir_item *di; - struct btrfs_path *path; - int ret; - int err = 0; - int bytes_del = 0; - u64 dir_ino = btrfs_ino(dir); - - if (BTRFS_I(dir)->logged_trans < trans->transid) - return 0; - - ret = join_running_log_trans(root); - if (ret) - return 0; - - mutex_lock(&BTRFS_I(dir)->log_mutex); - - log = root->log_root; - path = btrfs_alloc_path(); - if (!path) { - err = -ENOMEM; - goto out_unlock; - } - - di = btrfs_lookup_dir_item(trans, log, path, dir_ino, - name, name_len, -1); - if (IS_ERR(di)) { - err = PTR_ERR(di); - goto fail; - } - if (di) { - ret = btrfs_delete_one_dir_name(trans, log, path, di); - bytes_del += name_len; - if (ret) { - err = ret; - goto fail; - } - } - btrfs_release_path(path); - di = btrfs_lookup_dir_index_item(trans, log, path, dir_ino, - index, name, name_len, -1); - if (IS_ERR(di)) { - err = PTR_ERR(di); - goto fail; - } - if (di) { - ret = btrfs_delete_one_dir_name(trans, log, path, di); - bytes_del += name_len; - if (ret) { - err = ret; - goto fail; - } - } - - /* update the directory size in the log to reflect the names - * we have removed - */ - if (bytes_del) { - struct btrfs_key key; - - key.objectid = dir_ino; - key.offset = 0; - key.type = BTRFS_INODE_ITEM_KEY; - btrfs_release_path(path); - - ret = btrfs_search_slot(trans, log, &key, path, 0, 1); - if (ret < 0) { - err = ret; - goto fail; - } - if (ret == 0) { - struct btrfs_inode_item *item; - u64 i_size; - - item = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_inode_item); - i_size = btrfs_inode_size(path->nodes[0], item); - if (i_size > bytes_del) - i_size -= bytes_del; - else - i_size = 0; - btrfs_set_inode_size(path->nodes[0], item, i_size); - btrfs_mark_buffer_dirty(path->nodes[0]); - } else - ret = 0; - btrfs_release_path(path); - } -fail: - btrfs_free_path(path); -out_unlock: - mutex_unlock(&BTRFS_I(dir)->log_mutex); - if (ret == -ENOSPC) { - btrfs_set_log_full_commit(root->fs_info, trans); - ret = 0; - } else if (ret < 0) - btrfs_abort_transaction(trans, ret); - - btrfs_end_log_trans(root); - - return err; -} - -/* see comments for btrfs_del_dir_entries_in_log */ -int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - const char *name, int name_len, - struct inode *inode, u64 dirid) -{ - struct btrfs_root *log; - u64 index; - int ret; - - if (BTRFS_I(inode)->logged_trans < trans->transid) - return 0; - - ret = join_running_log_trans(root); - if (ret) - return 0; - log = root->log_root; - mutex_lock(&BTRFS_I(inode)->log_mutex); - - ret = btrfs_del_inode_ref(trans, log, name, name_len, btrfs_ino(inode), - dirid, &index); - mutex_unlock(&BTRFS_I(inode)->log_mutex); - if (ret == -ENOSPC) { - btrfs_set_log_full_commit(root->fs_info, trans); - ret = 0; - } else if (ret < 0 && ret != -ENOENT) - btrfs_abort_transaction(trans, ret); - btrfs_end_log_trans(root); - - return ret; -} - -/* - * creates a range item in the log for 'dirid'. first_offset and - * last_offset tell us which parts of the key space the log should - * be considered authoritative for. - */ -static noinline int insert_dir_log_key(struct btrfs_trans_handle *trans, - struct btrfs_root *log, - struct btrfs_path *path, - int key_type, u64 dirid, - u64 first_offset, u64 last_offset) -{ - int ret; - struct btrfs_key key; - struct btrfs_dir_log_item *item; - - key.objectid = dirid; - key.offset = first_offset; - if (key_type == BTRFS_DIR_ITEM_KEY) - key.type = BTRFS_DIR_LOG_ITEM_KEY; - else - key.type = BTRFS_DIR_LOG_INDEX_KEY; - ret = btrfs_insert_empty_item(trans, log, path, &key, sizeof(*item)); - if (ret) - return ret; - - item = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_dir_log_item); - btrfs_set_dir_log_end(path->nodes[0], item, last_offset); - btrfs_mark_buffer_dirty(path->nodes[0]); - btrfs_release_path(path); - return 0; -} - -/* - * log all the items included in the current transaction for a given - * directory. This also creates the range items in the log tree required - * to replay anything deleted before the fsync - */ -static noinline int log_dir_items(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct inode *inode, - struct btrfs_path *path, - struct btrfs_path *dst_path, int key_type, - struct btrfs_log_ctx *ctx, - u64 min_offset, u64 *last_offset_ret) -{ - struct btrfs_key min_key; - struct btrfs_root *log = root->log_root; - struct extent_buffer *src; - int err = 0; - int ret; - int i; - int nritems; - u64 first_offset = min_offset; - u64 last_offset = (u64)-1; - u64 ino = btrfs_ino(inode); - - log = root->log_root; - - min_key.objectid = ino; - min_key.type = key_type; - min_key.offset = min_offset; - - ret = btrfs_search_forward(root, &min_key, path, trans->transid); - - /* - * we didn't find anything from this transaction, see if there - * is anything at all - */ - if (ret != 0 || min_key.objectid != ino || min_key.type != key_type) { - min_key.objectid = ino; - min_key.type = key_type; - min_key.offset = (u64)-1; - btrfs_release_path(path); - ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0); - if (ret < 0) { - btrfs_release_path(path); - return ret; - } - ret = btrfs_previous_item(root, path, ino, key_type); - - /* if ret == 0 there are items for this type, - * create a range to tell us the last key of this type. - * otherwise, there are no items in this directory after - * *min_offset, and we create a range to indicate that. - */ - if (ret == 0) { - struct btrfs_key tmp; - btrfs_item_key_to_cpu(path->nodes[0], &tmp, - path->slots[0]); - if (key_type == tmp.type) - first_offset = max(min_offset, tmp.offset) + 1; - } - goto done; - } - - /* go backward to find any previous key */ - ret = btrfs_previous_item(root, path, ino, key_type); - if (ret == 0) { - struct btrfs_key tmp; - btrfs_item_key_to_cpu(path->nodes[0], &tmp, path->slots[0]); - if (key_type == tmp.type) { - first_offset = tmp.offset; - ret = overwrite_item(trans, log, dst_path, - path->nodes[0], path->slots[0], - &tmp); - if (ret) { - err = ret; - goto done; - } - } - } - btrfs_release_path(path); - - /* find the first key from this transaction again */ - ret = btrfs_search_slot(NULL, root, &min_key, path, 0, 0); - if (WARN_ON(ret != 0)) - goto done; - - /* - * we have a block from this transaction, log every item in it - * from our directory - */ - while (1) { - struct btrfs_key tmp; - src = path->nodes[0]; - nritems = btrfs_header_nritems(src); - for (i = path->slots[0]; i < nritems; i++) { - struct btrfs_dir_item *di; - - btrfs_item_key_to_cpu(src, &min_key, i); - - if (min_key.objectid != ino || min_key.type != key_type) - goto done; - ret = overwrite_item(trans, log, dst_path, src, i, - &min_key); - if (ret) { - err = ret; - goto done; - } - - /* - * We must make sure that when we log a directory entry, - * the corresponding inode, after log replay, has a - * matching link count. For example: - * - * touch foo - * mkdir mydir - * sync - * ln foo mydir/bar - * xfs_io -c "fsync" mydir - * - * - * - * Would result in a fsync log that when replayed, our - * file inode would have a link count of 1, but we get - * two directory entries pointing to the same inode. - * After removing one of the names, it would not be - * possible to remove the other name, which resulted - * always in stale file handle errors, and would not - * be possible to rmdir the parent directory, since - * its i_size could never decrement to the value - * BTRFS_EMPTY_DIR_SIZE, resulting in -ENOTEMPTY errors. - */ - di = btrfs_item_ptr(src, i, struct btrfs_dir_item); - btrfs_dir_item_key_to_cpu(src, di, &tmp); - if (ctx && - (btrfs_dir_transid(src, di) == trans->transid || - btrfs_dir_type(src, di) == BTRFS_FT_DIR) && - tmp.type != BTRFS_ROOT_ITEM_KEY) - ctx->log_new_dentries = true; - } - path->slots[0] = nritems; - - /* - * look ahead to the next item and see if it is also - * from this directory and from this transaction - */ - ret = btrfs_next_leaf(root, path); - if (ret == 1) { - last_offset = (u64)-1; - goto done; - } - btrfs_item_key_to_cpu(path->nodes[0], &tmp, path->slots[0]); - if (tmp.objectid != ino || tmp.type != key_type) { - last_offset = (u64)-1; - goto done; - } - if (btrfs_header_generation(path->nodes[0]) != trans->transid) { - ret = overwrite_item(trans, log, dst_path, - path->nodes[0], path->slots[0], - &tmp); - if (ret) - err = ret; - else - last_offset = tmp.offset; - goto done; - } - } -done: - btrfs_release_path(path); - btrfs_release_path(dst_path); - - if (err == 0) { - *last_offset_ret = last_offset; - /* - * insert the log range keys to indicate where the log - * is valid - */ - ret = insert_dir_log_key(trans, log, path, key_type, - ino, first_offset, last_offset); - if (ret) - err = ret; - } - return err; -} - -/* - * logging directories is very similar to logging inodes, We find all the items - * from the current transaction and write them to the log. - * - * The recovery code scans the directory in the subvolume, and if it finds a - * key in the range logged that is not present in the log tree, then it means - * that dir entry was unlinked during the transaction. - * - * In order for that scan to work, we must include one key smaller than - * the smallest logged by this transaction and one key larger than the largest - * key logged by this transaction. - */ -static noinline int log_directory_changes(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct inode *inode, - struct btrfs_path *path, - struct btrfs_path *dst_path, - struct btrfs_log_ctx *ctx) -{ - u64 min_key; - u64 max_key; - int ret; - int key_type = BTRFS_DIR_ITEM_KEY; - -again: - min_key = 0; - max_key = 0; - while (1) { - ret = log_dir_items(trans, root, inode, path, - dst_path, key_type, ctx, min_key, - &max_key); - if (ret) - return ret; - if (max_key == (u64)-1) - break; - min_key = max_key + 1; - } - - if (key_type == BTRFS_DIR_ITEM_KEY) { - key_type = BTRFS_DIR_INDEX_KEY; - goto again; - } - return 0; -} - -/* - * a helper function to drop items from the log before we relog an - * inode. max_key_type indicates the highest item type to remove. - * This cannot be run for file data extents because it does not - * free the extents they point to. - */ -static int drop_objectid_items(struct btrfs_trans_handle *trans, - struct btrfs_root *log, - struct btrfs_path *path, - u64 objectid, int max_key_type) -{ - int ret; - struct btrfs_key key; - struct btrfs_key found_key; - int start_slot; - - key.objectid = objectid; - key.type = max_key_type; - key.offset = (u64)-1; - - while (1) { - ret = btrfs_search_slot(trans, log, &key, path, -1, 1); - BUG_ON(ret == 0); /* Logic error */ - if (ret < 0) - break; - - if (path->slots[0] == 0) - break; - - path->slots[0]--; - btrfs_item_key_to_cpu(path->nodes[0], &found_key, - path->slots[0]); - - if (found_key.objectid != objectid) - break; - - found_key.offset = 0; - found_key.type = 0; - ret = btrfs_bin_search(path->nodes[0], &found_key, 0, - &start_slot); - - ret = btrfs_del_items(trans, log, path, start_slot, - path->slots[0] - start_slot + 1); - /* - * If start slot isn't 0 then we don't need to re-search, we've - * found the last guy with the objectid in this tree. - */ - if (ret || start_slot != 0) - break; - btrfs_release_path(path); - } - btrfs_release_path(path); - if (ret > 0) - ret = 0; - return ret; -} - -static void fill_inode_item(struct btrfs_trans_handle *trans, - struct extent_buffer *leaf, - struct btrfs_inode_item *item, - struct inode *inode, int log_inode_only, - u64 logged_isize) -{ - struct btrfs_map_token token; - - btrfs_init_map_token(&token); - - if (log_inode_only) { - /* set the generation to zero so the recover code - * can tell the difference between an logging - * just to say 'this inode exists' and a logging - * to say 'update this inode with these values' - */ - btrfs_set_token_inode_generation(leaf, item, 0, &token); - btrfs_set_token_inode_size(leaf, item, logged_isize, &token); - } else { - btrfs_set_token_inode_generation(leaf, item, - BTRFS_I(inode)->generation, - &token); - btrfs_set_token_inode_size(leaf, item, inode->i_size, &token); - } - - btrfs_set_token_inode_uid(leaf, item, i_uid_read(inode), &token); - btrfs_set_token_inode_gid(leaf, item, i_gid_read(inode), &token); - btrfs_set_token_inode_mode(leaf, item, inode->i_mode, &token); - btrfs_set_token_inode_nlink(leaf, item, inode->i_nlink, &token); - - btrfs_set_token_timespec_sec(leaf, &item->atime, - inode->i_atime.tv_sec, &token); - btrfs_set_token_timespec_nsec(leaf, &item->atime, - inode->i_atime.tv_nsec, &token); - - btrfs_set_token_timespec_sec(leaf, &item->mtime, - inode->i_mtime.tv_sec, &token); - btrfs_set_token_timespec_nsec(leaf, &item->mtime, - inode->i_mtime.tv_nsec, &token); - - btrfs_set_token_timespec_sec(leaf, &item->ctime, - inode->i_ctime.tv_sec, &token); - btrfs_set_token_timespec_nsec(leaf, &item->ctime, - inode->i_ctime.tv_nsec, &token); - - btrfs_set_token_inode_nbytes(leaf, item, inode_get_bytes(inode), - &token); - - btrfs_set_token_inode_sequence(leaf, item, inode->i_version, &token); - btrfs_set_token_inode_transid(leaf, item, trans->transid, &token); - btrfs_set_token_inode_rdev(leaf, item, inode->i_rdev, &token); - btrfs_set_token_inode_flags(leaf, item, BTRFS_I(inode)->flags, &token); - btrfs_set_token_inode_block_group(leaf, item, 0, &token); -} - -static int log_inode_item(struct btrfs_trans_handle *trans, - struct btrfs_root *log, struct btrfs_path *path, - struct inode *inode) -{ - struct btrfs_inode_item *inode_item; - int ret; - - ret = btrfs_insert_empty_item(trans, log, path, - &BTRFS_I(inode)->location, - sizeof(*inode_item)); - if (ret && ret != -EEXIST) - return ret; - inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_inode_item); - fill_inode_item(trans, path->nodes[0], inode_item, inode, 0, 0); - btrfs_release_path(path); - return 0; -} - -static noinline int copy_items(struct btrfs_trans_handle *trans, - struct inode *inode, - struct btrfs_path *dst_path, - struct btrfs_path *src_path, u64 *last_extent, - int start_slot, int nr, int inode_only, - u64 logged_isize) -{ - unsigned long src_offset; - unsigned long dst_offset; - struct btrfs_root *log = BTRFS_I(inode)->root->log_root; - struct btrfs_file_extent_item *extent; - struct btrfs_inode_item *inode_item; - struct extent_buffer *src = src_path->nodes[0]; - struct btrfs_key first_key, last_key, key; - int ret; - struct btrfs_key *ins_keys; - u32 *ins_sizes; - char *ins_data; - int i; - struct list_head ordered_sums; - int skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; - bool has_extents = false; - bool need_find_last_extent = true; - bool done = false; - - INIT_LIST_HEAD(&ordered_sums); - - ins_data = kmalloc(nr * sizeof(struct btrfs_key) + - nr * sizeof(u32), GFP_NOFS); - if (!ins_data) - return -ENOMEM; - - first_key.objectid = (u64)-1; - - ins_sizes = (u32 *)ins_data; - ins_keys = (struct btrfs_key *)(ins_data + nr * sizeof(u32)); - - for (i = 0; i < nr; i++) { - ins_sizes[i] = btrfs_item_size_nr(src, i + start_slot); - btrfs_item_key_to_cpu(src, ins_keys + i, i + start_slot); - } - ret = btrfs_insert_empty_items(trans, log, dst_path, - ins_keys, ins_sizes, nr); - if (ret) { - kfree(ins_data); - return ret; - } - - for (i = 0; i < nr; i++, dst_path->slots[0]++) { - dst_offset = btrfs_item_ptr_offset(dst_path->nodes[0], - dst_path->slots[0]); - - src_offset = btrfs_item_ptr_offset(src, start_slot + i); - - if ((i == (nr - 1))) - last_key = ins_keys[i]; - - if (ins_keys[i].type == BTRFS_INODE_ITEM_KEY) { - inode_item = btrfs_item_ptr(dst_path->nodes[0], - dst_path->slots[0], - struct btrfs_inode_item); - fill_inode_item(trans, dst_path->nodes[0], inode_item, - inode, inode_only == LOG_INODE_EXISTS, - logged_isize); - } else { - copy_extent_buffer(dst_path->nodes[0], src, dst_offset, - src_offset, ins_sizes[i]); - } - - /* - * We set need_find_last_extent here in case we know we were - * processing other items and then walk into the first extent in - * the inode. If we don't hit an extent then nothing changes, - * we'll do the last search the next time around. - */ - if (ins_keys[i].type == BTRFS_EXTENT_DATA_KEY) { - has_extents = true; - if (first_key.objectid == (u64)-1) - first_key = ins_keys[i]; - } else { - need_find_last_extent = false; - } - - /* take a reference on file data extents so that truncates - * or deletes of this inode don't have to relog the inode - * again - */ - if (ins_keys[i].type == BTRFS_EXTENT_DATA_KEY && - !skip_csum) { - int found_type; - extent = btrfs_item_ptr(src, start_slot + i, - struct btrfs_file_extent_item); - - if (btrfs_file_extent_generation(src, extent) < trans->transid) - continue; - - found_type = btrfs_file_extent_type(src, extent); - if (found_type == BTRFS_FILE_EXTENT_REG) { - u64 ds, dl, cs, cl; - ds = btrfs_file_extent_disk_bytenr(src, - extent); - /* ds == 0 is a hole */ - if (ds == 0) - continue; - - dl = btrfs_file_extent_disk_num_bytes(src, - extent); - cs = btrfs_file_extent_offset(src, extent); - cl = btrfs_file_extent_num_bytes(src, - extent); - if (btrfs_file_extent_compression(src, - extent)) { - cs = 0; - cl = dl; - } - - ret = btrfs_lookup_csums_range( - log->fs_info->csum_root, - ds + cs, ds + cs + cl - 1, - &ordered_sums, 0); - if (ret) { - btrfs_release_path(dst_path); - kfree(ins_data); - return ret; - } - } - } - } - - btrfs_mark_buffer_dirty(dst_path->nodes[0]); - btrfs_release_path(dst_path); - kfree(ins_data); - - /* - * we have to do this after the loop above to avoid changing the - * log tree while trying to change the log tree. - */ - ret = 0; - while (!list_empty(&ordered_sums)) { - struct btrfs_ordered_sum *sums = list_entry(ordered_sums.next, - struct btrfs_ordered_sum, - list); - if (!ret) - ret = btrfs_csum_file_blocks(trans, log, sums); - list_del(&sums->list); - kfree(sums); - } - - if (!has_extents) - return ret; - - if (need_find_last_extent && *last_extent == first_key.offset) { - /* - * We don't have any leafs between our current one and the one - * we processed before that can have file extent items for our - * inode (and have a generation number smaller than our current - * transaction id). - */ - need_find_last_extent = false; - } - - /* - * Because we use btrfs_search_forward we could skip leaves that were - * not modified and then assume *last_extent is valid when it really - * isn't. So back up to the previous leaf and read the end of the last - * extent before we go and fill in holes. - */ - if (need_find_last_extent) { - u64 len; - - ret = btrfs_prev_leaf(BTRFS_I(inode)->root, src_path); - if (ret < 0) - return ret; - if (ret) - goto fill_holes; - if (src_path->slots[0]) - src_path->slots[0]--; - src = src_path->nodes[0]; - btrfs_item_key_to_cpu(src, &key, src_path->slots[0]); - if (key.objectid != btrfs_ino(inode) || - key.type != BTRFS_EXTENT_DATA_KEY) - goto fill_holes; - extent = btrfs_item_ptr(src, src_path->slots[0], - struct btrfs_file_extent_item); - if (btrfs_file_extent_type(src, extent) == - BTRFS_FILE_EXTENT_INLINE) { - len = btrfs_file_extent_inline_len(src, - src_path->slots[0], - extent); - *last_extent = ALIGN(key.offset + len, - log->sectorsize); - } else { - len = btrfs_file_extent_num_bytes(src, extent); - *last_extent = key.offset + len; - } - } -fill_holes: - /* So we did prev_leaf, now we need to move to the next leaf, but a few - * things could have happened - * - * 1) A merge could have happened, so we could currently be on a leaf - * that holds what we were copying in the first place. - * 2) A split could have happened, and now not all of the items we want - * are on the same leaf. - * - * So we need to adjust how we search for holes, we need to drop the - * path and re-search for the first extent key we found, and then walk - * forward until we hit the last one we copied. - */ - if (need_find_last_extent) { - /* btrfs_prev_leaf could return 1 without releasing the path */ - btrfs_release_path(src_path); - ret = btrfs_search_slot(NULL, BTRFS_I(inode)->root, &first_key, - src_path, 0, 0); - if (ret < 0) - return ret; - ASSERT(ret == 0); - src = src_path->nodes[0]; - i = src_path->slots[0]; - } else { - i = start_slot; - } - - /* - * Ok so here we need to go through and fill in any holes we may have - * to make sure that holes are punched for those areas in case they had - * extents previously. - */ - while (!done) { - u64 offset, len; - u64 extent_end; - - if (i >= btrfs_header_nritems(src_path->nodes[0])) { - ret = btrfs_next_leaf(BTRFS_I(inode)->root, src_path); - if (ret < 0) - return ret; - ASSERT(ret == 0); - src = src_path->nodes[0]; - i = 0; - } - - btrfs_item_key_to_cpu(src, &key, i); - if (!btrfs_comp_cpu_keys(&key, &last_key)) - done = true; - if (key.objectid != btrfs_ino(inode) || - key.type != BTRFS_EXTENT_DATA_KEY) { - i++; - continue; - } - extent = btrfs_item_ptr(src, i, struct btrfs_file_extent_item); - if (btrfs_file_extent_type(src, extent) == - BTRFS_FILE_EXTENT_INLINE) { - len = btrfs_file_extent_inline_len(src, i, extent); - extent_end = ALIGN(key.offset + len, log->sectorsize); - } else { - len = btrfs_file_extent_num_bytes(src, extent); - extent_end = key.offset + len; - } - i++; - - if (*last_extent == key.offset) { - *last_extent = extent_end; - continue; - } - offset = *last_extent; - len = key.offset - *last_extent; - ret = btrfs_insert_file_extent(trans, log, btrfs_ino(inode), - offset, 0, 0, len, 0, len, 0, - 0, 0); - if (ret) - break; - *last_extent = extent_end; - } - /* - * Need to let the callers know we dropped the path so they should - * re-search. - */ - if (!ret && need_find_last_extent) - ret = 1; - return ret; -} - -static int extent_cmp(void *priv, struct list_head *a, struct list_head *b) -{ - struct extent_map *em1, *em2; - - em1 = list_entry(a, struct extent_map, list); - em2 = list_entry(b, struct extent_map, list); - - if (em1->start < em2->start) - return -1; - else if (em1->start > em2->start) - return 1; - return 0; -} - -static int wait_ordered_extents(struct btrfs_trans_handle *trans, - struct inode *inode, - struct btrfs_root *root, - const struct extent_map *em, - const struct list_head *logged_list, - bool *ordered_io_error) -{ - struct btrfs_ordered_extent *ordered; - struct btrfs_root *log = root->log_root; - u64 mod_start = em->mod_start; - u64 mod_len = em->mod_len; - const bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; - u64 csum_offset; - u64 csum_len; - LIST_HEAD(ordered_sums); - int ret = 0; - - *ordered_io_error = false; - - if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags) || - em->block_start == EXTENT_MAP_HOLE) - return 0; - - /* - * Wait far any ordered extent that covers our extent map. If it - * finishes without an error, first check and see if our csums are on - * our outstanding ordered extents. - */ - list_for_each_entry(ordered, logged_list, log_list) { - struct btrfs_ordered_sum *sum; - - if (!mod_len) - break; - - if (ordered->file_offset + ordered->len <= mod_start || - mod_start + mod_len <= ordered->file_offset) - continue; - - if (!test_bit(BTRFS_ORDERED_IO_DONE, &ordered->flags) && - !test_bit(BTRFS_ORDERED_IOERR, &ordered->flags) && - !test_bit(BTRFS_ORDERED_DIRECT, &ordered->flags)) { - const u64 start = ordered->file_offset; - const u64 end = ordered->file_offset + ordered->len - 1; - - WARN_ON(ordered->inode != inode); - filemap_fdatawrite_range(inode->i_mapping, start, end); - } - - wait_event(ordered->wait, - (test_bit(BTRFS_ORDERED_IO_DONE, &ordered->flags) || - test_bit(BTRFS_ORDERED_IOERR, &ordered->flags))); - - if (test_bit(BTRFS_ORDERED_IOERR, &ordered->flags)) { - /* - * Clear the AS_EIO/AS_ENOSPC flags from the inode's - * i_mapping flags, so that the next fsync won't get - * an outdated io error too. - */ - filemap_check_errors(inode->i_mapping); - *ordered_io_error = true; - break; - } - /* - * We are going to copy all the csums on this ordered extent, so - * go ahead and adjust mod_start and mod_len in case this - * ordered extent has already been logged. - */ - if (ordered->file_offset > mod_start) { - if (ordered->file_offset + ordered->len >= - mod_start + mod_len) - mod_len = ordered->file_offset - mod_start; - /* - * If we have this case - * - * |--------- logged extent ---------| - * |----- ordered extent ----| - * - * Just don't mess with mod_start and mod_len, we'll - * just end up logging more csums than we need and it - * will be ok. - */ - } else { - if (ordered->file_offset + ordered->len < - mod_start + mod_len) { - mod_len = (mod_start + mod_len) - - (ordered->file_offset + ordered->len); - mod_start = ordered->file_offset + - ordered->len; - } else { - mod_len = 0; - } - } - - if (skip_csum) - continue; - - /* - * To keep us from looping for the above case of an ordered - * extent that falls inside of the logged extent. - */ - if (test_and_set_bit(BTRFS_ORDERED_LOGGED_CSUM, - &ordered->flags)) - continue; - - list_for_each_entry(sum, &ordered->list, list) { - ret = btrfs_csum_file_blocks(trans, log, sum); - if (ret) - break; - } - } - - if (*ordered_io_error || !mod_len || ret || skip_csum) - return ret; - - if (em->compress_type) { - csum_offset = 0; - csum_len = max(em->block_len, em->orig_block_len); - } else { - csum_offset = mod_start - em->start; - csum_len = mod_len; - } - - /* block start is already adjusted for the file extent offset. */ - ret = btrfs_lookup_csums_range(log->fs_info->csum_root, - em->block_start + csum_offset, - em->block_start + csum_offset + - csum_len - 1, &ordered_sums, 0); - if (ret) - return ret; - - while (!list_empty(&ordered_sums)) { - struct btrfs_ordered_sum *sums = list_entry(ordered_sums.next, - struct btrfs_ordered_sum, - list); - if (!ret) - ret = btrfs_csum_file_blocks(trans, log, sums); - list_del(&sums->list); - kfree(sums); - } - - return ret; -} - -static int log_one_extent(struct btrfs_trans_handle *trans, - struct inode *inode, struct btrfs_root *root, - const struct extent_map *em, - struct btrfs_path *path, - const struct list_head *logged_list, - struct btrfs_log_ctx *ctx) -{ - struct btrfs_root *log = root->log_root; - struct btrfs_file_extent_item *fi; - struct extent_buffer *leaf; - struct btrfs_map_token token; - struct btrfs_key key; - u64 extent_offset = em->start - em->orig_start; - u64 block_len; - int ret; - int extent_inserted = 0; - bool ordered_io_err = false; - - ret = wait_ordered_extents(trans, inode, root, em, logged_list, - &ordered_io_err); - if (ret) - return ret; - - if (ordered_io_err) { - ctx->io_err = -EIO; - return 0; - } - - btrfs_init_map_token(&token); - - ret = __btrfs_drop_extents(trans, log, inode, path, em->start, - em->start + em->len, NULL, 0, 1, - sizeof(*fi), &extent_inserted); - if (ret) - return ret; - - if (!extent_inserted) { - key.objectid = btrfs_ino(inode); - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = em->start; - - ret = btrfs_insert_empty_item(trans, log, path, &key, - sizeof(*fi)); - if (ret) - return ret; - } - leaf = path->nodes[0]; - fi = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - - btrfs_set_token_file_extent_generation(leaf, fi, trans->transid, - &token); - if (test_bit(EXTENT_FLAG_PREALLOC, &em->flags)) - btrfs_set_token_file_extent_type(leaf, fi, - BTRFS_FILE_EXTENT_PREALLOC, - &token); - else - btrfs_set_token_file_extent_type(leaf, fi, - BTRFS_FILE_EXTENT_REG, - &token); - - block_len = max(em->block_len, em->orig_block_len); - if (em->compress_type != BTRFS_COMPRESS_NONE) { - btrfs_set_token_file_extent_disk_bytenr(leaf, fi, - em->block_start, - &token); - btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, block_len, - &token); - } else if (em->block_start < EXTENT_MAP_LAST_BYTE) { - btrfs_set_token_file_extent_disk_bytenr(leaf, fi, - em->block_start - - extent_offset, &token); - btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, block_len, - &token); - } else { - btrfs_set_token_file_extent_disk_bytenr(leaf, fi, 0, &token); - btrfs_set_token_file_extent_disk_num_bytes(leaf, fi, 0, - &token); - } - - btrfs_set_token_file_extent_offset(leaf, fi, extent_offset, &token); - btrfs_set_token_file_extent_num_bytes(leaf, fi, em->len, &token); - btrfs_set_token_file_extent_ram_bytes(leaf, fi, em->ram_bytes, &token); - btrfs_set_token_file_extent_compression(leaf, fi, em->compress_type, - &token); - btrfs_set_token_file_extent_encryption(leaf, fi, 0, &token); - btrfs_set_token_file_extent_other_encoding(leaf, fi, 0, &token); - btrfs_mark_buffer_dirty(leaf); - - btrfs_release_path(path); - - return ret; -} - -static int btrfs_log_changed_extents(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *inode, - struct btrfs_path *path, - struct list_head *logged_list, - struct btrfs_log_ctx *ctx, - const u64 start, - const u64 end) -{ - struct extent_map *em, *n; - struct list_head extents; - struct extent_map_tree *tree = &BTRFS_I(inode)->extent_tree; - u64 test_gen; - int ret = 0; - int num = 0; - - INIT_LIST_HEAD(&extents); - - down_write(&BTRFS_I(inode)->dio_sem); - write_lock(&tree->lock); - test_gen = root->fs_info->last_trans_committed; - - list_for_each_entry_safe(em, n, &tree->modified_extents, list) { - list_del_init(&em->list); - - /* - * Just an arbitrary number, this can be really CPU intensive - * once we start getting a lot of extents, and really once we - * have a bunch of extents we just want to commit since it will - * be faster. - */ - if (++num > 32768) { - list_del_init(&tree->modified_extents); - ret = -EFBIG; - goto process; - } - - if (em->generation <= test_gen) - continue; - /* Need a ref to keep it from getting evicted from cache */ - atomic_inc(&em->refs); - set_bit(EXTENT_FLAG_LOGGING, &em->flags); - list_add_tail(&em->list, &extents); - num++; - } - - list_sort(NULL, &extents, extent_cmp); - btrfs_get_logged_extents(inode, logged_list, start, end); - /* - * Some ordered extents started by fsync might have completed - * before we could collect them into the list logged_list, which - * means they're gone, not in our logged_list nor in the inode's - * ordered tree. We want the application/user space to know an - * error happened while attempting to persist file data so that - * it can take proper action. If such error happened, we leave - * without writing to the log tree and the fsync must report the - * file data write error and not commit the current transaction. - */ - ret = filemap_check_errors(inode->i_mapping); - if (ret) - ctx->io_err = ret; -process: - while (!list_empty(&extents)) { - em = list_entry(extents.next, struct extent_map, list); - - list_del_init(&em->list); - - /* - * If we had an error we just need to delete everybody from our - * private list. - */ - if (ret) { - clear_em_logging(tree, em); - free_extent_map(em); - continue; - } - - write_unlock(&tree->lock); - - ret = log_one_extent(trans, inode, root, em, path, logged_list, - ctx); - write_lock(&tree->lock); - clear_em_logging(tree, em); - free_extent_map(em); - } - WARN_ON(!list_empty(&extents)); - write_unlock(&tree->lock); - up_write(&BTRFS_I(inode)->dio_sem); - - btrfs_release_path(path); - return ret; -} - -static int logged_inode_size(struct btrfs_root *log, struct inode *inode, - struct btrfs_path *path, u64 *size_ret) -{ - struct btrfs_key key; - int ret; - - key.objectid = btrfs_ino(inode); - key.type = BTRFS_INODE_ITEM_KEY; - key.offset = 0; - - ret = btrfs_search_slot(NULL, log, &key, path, 0, 0); - if (ret < 0) { - return ret; - } else if (ret > 0) { - *size_ret = 0; - } else { - struct btrfs_inode_item *item; - - item = btrfs_item_ptr(path->nodes[0], path->slots[0], - struct btrfs_inode_item); - *size_ret = btrfs_inode_size(path->nodes[0], item); - } - - btrfs_release_path(path); - return 0; -} - -/* - * At the moment we always log all xattrs. This is to figure out at log replay - * time which xattrs must have their deletion replayed. If a xattr is missing - * in the log tree and exists in the fs/subvol tree, we delete it. This is - * because if a xattr is deleted, the inode is fsynced and a power failure - * happens, causing the log to be replayed the next time the fs is mounted, - * we want the xattr to not exist anymore (same behaviour as other filesystems - * with a journal, ext3/4, xfs, f2fs, etc). - */ -static int btrfs_log_all_xattrs(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *inode, - struct btrfs_path *path, - struct btrfs_path *dst_path) -{ - int ret; - struct btrfs_key key; - const u64 ino = btrfs_ino(inode); - int ins_nr = 0; - int start_slot = 0; - - key.objectid = ino; - key.type = BTRFS_XATTR_ITEM_KEY; - key.offset = 0; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - return ret; - - while (true) { - int slot = path->slots[0]; - struct extent_buffer *leaf = path->nodes[0]; - int nritems = btrfs_header_nritems(leaf); - - if (slot >= nritems) { - if (ins_nr > 0) { - u64 last_extent = 0; - - ret = copy_items(trans, inode, dst_path, path, - &last_extent, start_slot, - ins_nr, 1, 0); - /* can't be 1, extent items aren't processed */ - ASSERT(ret <= 0); - if (ret < 0) - return ret; - ins_nr = 0; - } - ret = btrfs_next_leaf(root, path); - if (ret < 0) - return ret; - else if (ret > 0) - break; - continue; - } - - btrfs_item_key_to_cpu(leaf, &key, slot); - if (key.objectid != ino || key.type != BTRFS_XATTR_ITEM_KEY) - break; - - if (ins_nr == 0) - start_slot = slot; - ins_nr++; - path->slots[0]++; - cond_resched(); - } - if (ins_nr > 0) { - u64 last_extent = 0; - - ret = copy_items(trans, inode, dst_path, path, - &last_extent, start_slot, - ins_nr, 1, 0); - /* can't be 1, extent items aren't processed */ - ASSERT(ret <= 0); - if (ret < 0) - return ret; - } - - return 0; -} - -/* - * If the no holes feature is enabled we need to make sure any hole between the - * last extent and the i_size of our inode is explicitly marked in the log. This - * is to make sure that doing something like: - * - * 1) create file with 128Kb of data - * 2) truncate file to 64Kb - * 3) truncate file to 256Kb - * 4) fsync file - * 5) - * 6) mount fs and trigger log replay - * - * Will give us a file with a size of 256Kb, the first 64Kb of data match what - * the file had in its first 64Kb of data at step 1 and the last 192Kb of the - * file correspond to a hole. The presence of explicit holes in a log tree is - * what guarantees that log replay will remove/adjust file extent items in the - * fs/subvol tree. - * - * Here we do not need to care about holes between extents, that is already done - * by copy_items(). We also only need to do this in the full sync path, where we - * lookup for extents from the fs/subvol tree only. In the fast path case, we - * lookup the list of modified extent maps and if any represents a hole, we - * insert a corresponding extent representing a hole in the log tree. - */ -static int btrfs_log_trailing_hole(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *inode, - struct btrfs_path *path) -{ - int ret; - struct btrfs_key key; - u64 hole_start; - u64 hole_size; - struct extent_buffer *leaf; - struct btrfs_root *log = root->log_root; - const u64 ino = btrfs_ino(inode); - const u64 i_size = i_size_read(inode); - - if (!btrfs_fs_incompat(root->fs_info, NO_HOLES)) - return 0; - - key.objectid = ino; - key.type = BTRFS_EXTENT_DATA_KEY; - key.offset = (u64)-1; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - ASSERT(ret != 0); - if (ret < 0) - return ret; - - ASSERT(path->slots[0] > 0); - path->slots[0]--; - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - - if (key.objectid != ino || key.type != BTRFS_EXTENT_DATA_KEY) { - /* inode does not have any extents */ - hole_start = 0; - hole_size = i_size; - } else { - struct btrfs_file_extent_item *extent; - u64 len; - - /* - * If there's an extent beyond i_size, an explicit hole was - * already inserted by copy_items(). - */ - if (key.offset >= i_size) - return 0; - - extent = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_file_extent_item); - - if (btrfs_file_extent_type(leaf, extent) == - BTRFS_FILE_EXTENT_INLINE) { - len = btrfs_file_extent_inline_len(leaf, - path->slots[0], - extent); - ASSERT(len == i_size); - return 0; - } - - len = btrfs_file_extent_num_bytes(leaf, extent); - /* Last extent goes beyond i_size, no need to log a hole. */ - if (key.offset + len > i_size) - return 0; - hole_start = key.offset + len; - hole_size = i_size - hole_start; - } - btrfs_release_path(path); - - /* Last extent ends at i_size. */ - if (hole_size == 0) - return 0; - - hole_size = ALIGN(hole_size, root->sectorsize); - ret = btrfs_insert_file_extent(trans, log, ino, hole_start, 0, 0, - hole_size, 0, hole_size, 0, 0, 0); - return ret; -} - -/* - * When we are logging a new inode X, check if it doesn't have a reference that - * matches the reference from some other inode Y created in a past transaction - * and that was renamed in the current transaction. If we don't do this, then at - * log replay time we can lose inode Y (and all its files if it's a directory): - * - * mkdir /mnt/x - * echo "hello world" > /mnt/x/foobar - * sync - * mv /mnt/x /mnt/y - * mkdir /mnt/x # or touch /mnt/x - * xfs_io -c fsync /mnt/x - * - * mount fs, trigger log replay - * - * After the log replay procedure, we would lose the first directory and all its - * files (file foobar). - * For the case where inode Y is not a directory we simply end up losing it: - * - * echo "123" > /mnt/foo - * sync - * mv /mnt/foo /mnt/bar - * echo "abc" > /mnt/foo - * xfs_io -c fsync /mnt/foo - * - * - * We also need this for cases where a snapshot entry is replaced by some other - * entry (file or directory) otherwise we end up with an unreplayable log due to - * attempts to delete the snapshot entry (entry of type BTRFS_ROOT_ITEM_KEY) as - * if it were a regular entry: - * - * mkdir /mnt/x - * btrfs subvolume snapshot /mnt /mnt/x/snap - * btrfs subvolume delete /mnt/x/snap - * rmdir /mnt/x - * mkdir /mnt/x - * fsync /mnt/x or fsync some new file inside it - * - * - * The snapshot delete, rmdir of x, mkdir of a new x and the fsync all happen in - * the same transaction. - */ -static int btrfs_check_ref_name_override(struct extent_buffer *eb, - const int slot, - const struct btrfs_key *key, - struct inode *inode, - u64 *other_ino) -{ - int ret; - struct btrfs_path *search_path; - char *name = NULL; - u32 name_len = 0; - u32 item_size = btrfs_item_size_nr(eb, slot); - u32 cur_offset = 0; - unsigned long ptr = btrfs_item_ptr_offset(eb, slot); - - search_path = btrfs_alloc_path(); - if (!search_path) - return -ENOMEM; - search_path->search_commit_root = 1; - search_path->skip_locking = 1; - - while (cur_offset < item_size) { - u64 parent; - u32 this_name_len; - u32 this_len; - unsigned long name_ptr; - struct btrfs_dir_item *di; - - if (key->type == BTRFS_INODE_REF_KEY) { - struct btrfs_inode_ref *iref; - - iref = (struct btrfs_inode_ref *)(ptr + cur_offset); - parent = key->offset; - this_name_len = btrfs_inode_ref_name_len(eb, iref); - name_ptr = (unsigned long)(iref + 1); - this_len = sizeof(*iref) + this_name_len; - } else { - struct btrfs_inode_extref *extref; - - extref = (struct btrfs_inode_extref *)(ptr + - cur_offset); - parent = btrfs_inode_extref_parent(eb, extref); - this_name_len = btrfs_inode_extref_name_len(eb, extref); - name_ptr = (unsigned long)&extref->name; - this_len = sizeof(*extref) + this_name_len; - } - - if (this_name_len > name_len) { - char *new_name; - - new_name = krealloc(name, this_name_len, GFP_NOFS); - if (!new_name) { - ret = -ENOMEM; - goto out; - } - name_len = this_name_len; - name = new_name; - } - - read_extent_buffer(eb, name, name_ptr, this_name_len); - di = btrfs_lookup_dir_item(NULL, BTRFS_I(inode)->root, - search_path, parent, - name, this_name_len, 0); - if (di && !IS_ERR(di)) { - struct btrfs_key di_key; - - btrfs_dir_item_key_to_cpu(search_path->nodes[0], - di, &di_key); - if (di_key.type == BTRFS_INODE_ITEM_KEY) { - ret = 1; - *other_ino = di_key.objectid; - } else { - ret = -EAGAIN; - } - goto out; - } else if (IS_ERR(di)) { - ret = PTR_ERR(di); - goto out; - } - btrfs_release_path(search_path); - - cur_offset += this_len; - } - ret = 0; -out: - btrfs_free_path(search_path); - kfree(name); - return ret; -} - -/* log a single inode in the tree log. - * At least one parent directory for this inode must exist in the tree - * or be logged already. - * - * Any items from this inode changed by the current transaction are copied - * to the log tree. An extra reference is taken on any extents in this - * file, allowing us to avoid a whole pile of corner cases around logging - * blocks that have been removed from the tree. - * - * See LOG_INODE_ALL and related defines for a description of what inode_only - * does. - * - * This handles both files and directories. - */ -static int btrfs_log_inode(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct inode *inode, - int inode_only, - const loff_t start, - const loff_t end, - struct btrfs_log_ctx *ctx) -{ - struct btrfs_path *path; - struct btrfs_path *dst_path; - struct btrfs_key min_key; - struct btrfs_key max_key; - struct btrfs_root *log = root->log_root; - struct extent_buffer *src = NULL; - LIST_HEAD(logged_list); - u64 last_extent = 0; - int err = 0; - int ret; - int nritems; - int ins_start_slot = 0; - int ins_nr; - bool fast_search = false; - u64 ino = btrfs_ino(inode); - struct extent_map_tree *em_tree = &BTRFS_I(inode)->extent_tree; - u64 logged_isize = 0; - bool need_log_inode_item = true; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - dst_path = btrfs_alloc_path(); - if (!dst_path) { - btrfs_free_path(path); - return -ENOMEM; - } - - min_key.objectid = ino; - min_key.type = BTRFS_INODE_ITEM_KEY; - min_key.offset = 0; - - max_key.objectid = ino; - - - /* today the code can only do partial logging of directories */ - if (S_ISDIR(inode->i_mode) || - (!test_bit(BTRFS_INODE_NEEDS_FULL_SYNC, - &BTRFS_I(inode)->runtime_flags) && - inode_only == LOG_INODE_EXISTS)) - max_key.type = BTRFS_XATTR_ITEM_KEY; - else - max_key.type = (u8)-1; - max_key.offset = (u64)-1; - - /* - * Only run delayed items if we are a dir or a new file. - * Otherwise commit the delayed inode only, which is needed in - * order for the log replay code to mark inodes for link count - * fixup (create temporary BTRFS_TREE_LOG_FIXUP_OBJECTID items). - */ - if (S_ISDIR(inode->i_mode) || - BTRFS_I(inode)->generation > root->fs_info->last_trans_committed) - ret = btrfs_commit_inode_delayed_items(trans, inode); - else - ret = btrfs_commit_inode_delayed_inode(inode); - - if (ret) { - btrfs_free_path(path); - btrfs_free_path(dst_path); - return ret; - } - - mutex_lock(&BTRFS_I(inode)->log_mutex); - - /* - * a brute force approach to making sure we get the most uptodate - * copies of everything. - */ - if (S_ISDIR(inode->i_mode)) { - int max_key_type = BTRFS_DIR_LOG_INDEX_KEY; - - if (inode_only == LOG_INODE_EXISTS) - max_key_type = BTRFS_XATTR_ITEM_KEY; - ret = drop_objectid_items(trans, log, path, ino, max_key_type); - } else { - if (inode_only == LOG_INODE_EXISTS) { - /* - * Make sure the new inode item we write to the log has - * the same isize as the current one (if it exists). - * This is necessary to prevent data loss after log - * replay, and also to prevent doing a wrong expanding - * truncate - for e.g. create file, write 4K into offset - * 0, fsync, write 4K into offset 4096, add hard link, - * fsync some other file (to sync log), power fail - if - * we use the inode's current i_size, after log replay - * we get a 8Kb file, with the last 4Kb extent as a hole - * (zeroes), as if an expanding truncate happened, - * instead of getting a file of 4Kb only. - */ - err = logged_inode_size(log, inode, path, - &logged_isize); - if (err) - goto out_unlock; - } - if (test_bit(BTRFS_INODE_NEEDS_FULL_SYNC, - &BTRFS_I(inode)->runtime_flags)) { - if (inode_only == LOG_INODE_EXISTS) { - max_key.type = BTRFS_XATTR_ITEM_KEY; - ret = drop_objectid_items(trans, log, path, ino, - max_key.type); - } else { - clear_bit(BTRFS_INODE_NEEDS_FULL_SYNC, - &BTRFS_I(inode)->runtime_flags); - clear_bit(BTRFS_INODE_COPY_EVERYTHING, - &BTRFS_I(inode)->runtime_flags); - while(1) { - ret = btrfs_truncate_inode_items(trans, - log, inode, 0, 0); - if (ret != -EAGAIN) - break; - } - } - } else if (test_and_clear_bit(BTRFS_INODE_COPY_EVERYTHING, - &BTRFS_I(inode)->runtime_flags) || - inode_only == LOG_INODE_EXISTS) { - if (inode_only == LOG_INODE_ALL) - fast_search = true; - max_key.type = BTRFS_XATTR_ITEM_KEY; - ret = drop_objectid_items(trans, log, path, ino, - max_key.type); - } else { - if (inode_only == LOG_INODE_ALL) - fast_search = true; - goto log_extents; - } - - } - if (ret) { - err = ret; - goto out_unlock; - } - - while (1) { - ins_nr = 0; - ret = btrfs_search_forward(root, &min_key, - path, trans->transid); - if (ret < 0) { - err = ret; - goto out_unlock; - } - if (ret != 0) - break; -again: - /* note, ins_nr might be > 0 here, cleanup outside the loop */ - if (min_key.objectid != ino) - break; - if (min_key.type > max_key.type) - break; - - if (min_key.type == BTRFS_INODE_ITEM_KEY) - need_log_inode_item = false; - - if ((min_key.type == BTRFS_INODE_REF_KEY || - min_key.type == BTRFS_INODE_EXTREF_KEY) && - BTRFS_I(inode)->generation == trans->transid) { - u64 other_ino = 0; - - ret = btrfs_check_ref_name_override(path->nodes[0], - path->slots[0], - &min_key, inode, - &other_ino); - if (ret < 0) { - err = ret; - goto out_unlock; - } else if (ret > 0 && ctx && - other_ino != btrfs_ino(ctx->inode)) { - struct btrfs_key inode_key; - struct inode *other_inode; - - if (ins_nr > 0) { - ins_nr++; - } else { - ins_nr = 1; - ins_start_slot = path->slots[0]; - } - ret = copy_items(trans, inode, dst_path, path, - &last_extent, ins_start_slot, - ins_nr, inode_only, - logged_isize); - if (ret < 0) { - err = ret; - goto out_unlock; - } - ins_nr = 0; - btrfs_release_path(path); - inode_key.objectid = other_ino; - inode_key.type = BTRFS_INODE_ITEM_KEY; - inode_key.offset = 0; - other_inode = btrfs_iget(root->fs_info->sb, - &inode_key, root, - NULL); - /* - * If the other inode that had a conflicting dir - * entry was deleted in the current transaction, - * we don't need to do more work nor fallback to - * a transaction commit. - */ - if (IS_ERR(other_inode) && - PTR_ERR(other_inode) == -ENOENT) { - goto next_key; - } else if (IS_ERR(other_inode)) { - err = PTR_ERR(other_inode); - goto out_unlock; - } - /* - * We are safe logging the other inode without - * acquiring its i_mutex as long as we log with - * the LOG_INODE_EXISTS mode. We're safe against - * concurrent renames of the other inode as well - * because during a rename we pin the log and - * update the log with the new name before we - * unpin it. - */ - err = btrfs_log_inode(trans, root, other_inode, - LOG_INODE_EXISTS, - 0, LLONG_MAX, ctx); - iput(other_inode); - if (err) - goto out_unlock; - else - goto next_key; - } - } - - /* Skip xattrs, we log them later with btrfs_log_all_xattrs() */ - if (min_key.type == BTRFS_XATTR_ITEM_KEY) { - if (ins_nr == 0) - goto next_slot; - ret = copy_items(trans, inode, dst_path, path, - &last_extent, ins_start_slot, - ins_nr, inode_only, logged_isize); - if (ret < 0) { - err = ret; - goto out_unlock; - } - ins_nr = 0; - if (ret) { - btrfs_release_path(path); - continue; - } - goto next_slot; - } - - src = path->nodes[0]; - if (ins_nr && ins_start_slot + ins_nr == path->slots[0]) { - ins_nr++; - goto next_slot; - } else if (!ins_nr) { - ins_start_slot = path->slots[0]; - ins_nr = 1; - goto next_slot; - } - - ret = copy_items(trans, inode, dst_path, path, &last_extent, - ins_start_slot, ins_nr, inode_only, - logged_isize); - if (ret < 0) { - err = ret; - goto out_unlock; - } - if (ret) { - ins_nr = 0; - btrfs_release_path(path); - continue; - } - ins_nr = 1; - ins_start_slot = path->slots[0]; -next_slot: - - nritems = btrfs_header_nritems(path->nodes[0]); - path->slots[0]++; - if (path->slots[0] < nritems) { - btrfs_item_key_to_cpu(path->nodes[0], &min_key, - path->slots[0]); - goto again; - } - if (ins_nr) { - ret = copy_items(trans, inode, dst_path, path, - &last_extent, ins_start_slot, - ins_nr, inode_only, logged_isize); - if (ret < 0) { - err = ret; - goto out_unlock; - } - ret = 0; - ins_nr = 0; - } - btrfs_release_path(path); -next_key: - if (min_key.offset < (u64)-1) { - min_key.offset++; - } else if (min_key.type < max_key.type) { - min_key.type++; - min_key.offset = 0; - } else { - break; - } - } - if (ins_nr) { - ret = copy_items(trans, inode, dst_path, path, &last_extent, - ins_start_slot, ins_nr, inode_only, - logged_isize); - if (ret < 0) { - err = ret; - goto out_unlock; - } - ret = 0; - ins_nr = 0; - } - - btrfs_release_path(path); - btrfs_release_path(dst_path); - err = btrfs_log_all_xattrs(trans, root, inode, path, dst_path); - if (err) - goto out_unlock; - if (max_key.type >= BTRFS_EXTENT_DATA_KEY && !fast_search) { - btrfs_release_path(path); - btrfs_release_path(dst_path); - err = btrfs_log_trailing_hole(trans, root, inode, path); - if (err) - goto out_unlock; - } -log_extents: - btrfs_release_path(path); - btrfs_release_path(dst_path); - if (need_log_inode_item) { - err = log_inode_item(trans, log, dst_path, inode); - if (err) - goto out_unlock; - } - if (fast_search) { - ret = btrfs_log_changed_extents(trans, root, inode, dst_path, - &logged_list, ctx, start, end); - if (ret) { - err = ret; - goto out_unlock; - } - } else if (inode_only == LOG_INODE_ALL) { - struct extent_map *em, *n; - - write_lock(&em_tree->lock); - /* - * We can't just remove every em if we're called for a ranged - * fsync - that is, one that doesn't cover the whole possible - * file range (0 to LLONG_MAX). This is because we can have - * em's that fall outside the range we're logging and therefore - * their ordered operations haven't completed yet - * (btrfs_finish_ordered_io() not invoked yet). This means we - * didn't get their respective file extent item in the fs/subvol - * tree yet, and need to let the next fast fsync (one which - * consults the list of modified extent maps) find the em so - * that it logs a matching file extent item and waits for the - * respective ordered operation to complete (if it's still - * running). - * - * Removing every em outside the range we're logging would make - * the next fast fsync not log their matching file extent items, - * therefore making us lose data after a log replay. - */ - list_for_each_entry_safe(em, n, &em_tree->modified_extents, - list) { - const u64 mod_end = em->mod_start + em->mod_len - 1; - - if (em->mod_start >= start && mod_end <= end) - list_del_init(&em->list); - } - write_unlock(&em_tree->lock); - } - - if (inode_only == LOG_INODE_ALL && S_ISDIR(inode->i_mode)) { - ret = log_directory_changes(trans, root, inode, path, dst_path, - ctx); - if (ret) { - err = ret; - goto out_unlock; - } - } - - spin_lock(&BTRFS_I(inode)->lock); - BTRFS_I(inode)->logged_trans = trans->transid; - BTRFS_I(inode)->last_log_commit = BTRFS_I(inode)->last_sub_trans; - spin_unlock(&BTRFS_I(inode)->lock); -out_unlock: - if (unlikely(err)) - btrfs_put_logged_extents(&logged_list); - else - btrfs_submit_logged_extents(&logged_list, log); - mutex_unlock(&BTRFS_I(inode)->log_mutex); - - btrfs_free_path(path); - btrfs_free_path(dst_path); - return err; -} - -/* - * Check if we must fallback to a transaction commit when logging an inode. - * This must be called after logging the inode and is used only in the context - * when fsyncing an inode requires the need to log some other inode - in which - * case we can't lock the i_mutex of each other inode we need to log as that - * can lead to deadlocks with concurrent fsync against other inodes (as we can - * log inodes up or down in the hierarchy) or rename operations for example. So - * we take the log_mutex of the inode after we have logged it and then check for - * its last_unlink_trans value - this is safe because any task setting - * last_unlink_trans must take the log_mutex and it must do this before it does - * the actual unlink operation, so if we do this check before a concurrent task - * sets last_unlink_trans it means we've logged a consistent version/state of - * all the inode items, otherwise we are not sure and must do a transaction - * commit (the concurrent task might have only updated last_unlink_trans before - * we logged the inode or it might have also done the unlink). - */ -static bool btrfs_must_commit_transaction(struct btrfs_trans_handle *trans, - struct inode *inode) -{ - struct btrfs_fs_info *fs_info = BTRFS_I(inode)->root->fs_info; - bool ret = false; - - mutex_lock(&BTRFS_I(inode)->log_mutex); - if (BTRFS_I(inode)->last_unlink_trans > fs_info->last_trans_committed) { - /* - * Make sure any commits to the log are forced to be full - * commits. - */ - btrfs_set_log_full_commit(fs_info, trans); - ret = true; - } - mutex_unlock(&BTRFS_I(inode)->log_mutex); - - return ret; -} - -/* - * follow the dentry parent pointers up the chain and see if any - * of the directories in it require a full commit before they can - * be logged. Returns zero if nothing special needs to be done or 1 if - * a full commit is required. - */ -static noinline int check_parent_dirs_for_sync(struct btrfs_trans_handle *trans, - struct inode *inode, - struct dentry *parent, - struct super_block *sb, - u64 last_committed) -{ - int ret = 0; - struct dentry *old_parent = NULL; - struct inode *orig_inode = inode; - - /* - * for regular files, if its inode is already on disk, we don't - * have to worry about the parents at all. This is because - * we can use the last_unlink_trans field to record renames - * and other fun in this file. - */ - if (S_ISREG(inode->i_mode) && - BTRFS_I(inode)->generation <= last_committed && - BTRFS_I(inode)->last_unlink_trans <= last_committed) - goto out; - - if (!S_ISDIR(inode->i_mode)) { - if (!parent || d_really_is_negative(parent) || sb != parent->d_sb) - goto out; - inode = d_inode(parent); - } - - while (1) { - /* - * If we are logging a directory then we start with our inode, - * not our parent's inode, so we need to skip setting the - * logged_trans so that further down in the log code we don't - * think this inode has already been logged. - */ - if (inode != orig_inode) - BTRFS_I(inode)->logged_trans = trans->transid; - smp_mb(); - - if (btrfs_must_commit_transaction(trans, inode)) { - ret = 1; - break; - } - - if (!parent || d_really_is_negative(parent) || sb != parent->d_sb) - break; - - if (IS_ROOT(parent)) { - inode = d_inode(parent); - if (btrfs_must_commit_transaction(trans, inode)) - ret = 1; - break; - } - - parent = dget_parent(parent); - dput(old_parent); - old_parent = parent; - inode = d_inode(parent); - - } - dput(old_parent); -out: - return ret; -} - -struct btrfs_dir_list { - u64 ino; - struct list_head list; -}; - -/* - * Log the inodes of the new dentries of a directory. See log_dir_items() for - * details about the why it is needed. - * This is a recursive operation - if an existing dentry corresponds to a - * directory, that directory's new entries are logged too (same behaviour as - * ext3/4, xfs, f2fs, reiserfs, nilfs2). Note that when logging the inodes - * the dentries point to we do not lock their i_mutex, otherwise lockdep - * complains about the following circular lock dependency / possible deadlock: - * - * CPU0 CPU1 - * ---- ---- - * lock(&type->i_mutex_dir_key#3/2); - * lock(sb_internal#2); - * lock(&type->i_mutex_dir_key#3/2); - * lock(&sb->s_type->i_mutex_key#14); - * - * Where sb_internal is the lock (a counter that works as a lock) acquired by - * sb_start_intwrite() in btrfs_start_transaction(). - * Not locking i_mutex of the inodes is still safe because: - * - * 1) For regular files we log with a mode of LOG_INODE_EXISTS. It's possible - * that while logging the inode new references (names) are added or removed - * from the inode, leaving the logged inode item with a link count that does - * not match the number of logged inode reference items. This is fine because - * at log replay time we compute the real number of links and correct the - * link count in the inode item (see replay_one_buffer() and - * link_to_fixup_dir()); - * - * 2) For directories we log with a mode of LOG_INODE_ALL. It's possible that - * while logging the inode's items new items with keys BTRFS_DIR_ITEM_KEY and - * BTRFS_DIR_INDEX_KEY are added to fs/subvol tree and the logged inode item - * has a size that doesn't match the sum of the lengths of all the logged - * names. This does not result in a problem because if a dir_item key is - * logged but its matching dir_index key is not logged, at log replay time we - * don't use it to replay the respective name (see replay_one_name()). On the - * other hand if only the dir_index key ends up being logged, the respective - * name is added to the fs/subvol tree with both the dir_item and dir_index - * keys created (see replay_one_name()). - * The directory's inode item with a wrong i_size is not a problem as well, - * since we don't use it at log replay time to set the i_size in the inode - * item of the fs/subvol tree (see overwrite_item()). - */ -static int log_new_dir_dentries(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct inode *start_inode, - struct btrfs_log_ctx *ctx) -{ - struct btrfs_root *log = root->log_root; - struct btrfs_path *path; - LIST_HEAD(dir_list); - struct btrfs_dir_list *dir_elem; - int ret = 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - dir_elem = kmalloc(sizeof(*dir_elem), GFP_NOFS); - if (!dir_elem) { - btrfs_free_path(path); - return -ENOMEM; - } - dir_elem->ino = btrfs_ino(start_inode); - list_add_tail(&dir_elem->list, &dir_list); - - while (!list_empty(&dir_list)) { - struct extent_buffer *leaf; - struct btrfs_key min_key; - int nritems; - int i; - - dir_elem = list_first_entry(&dir_list, struct btrfs_dir_list, - list); - if (ret) - goto next_dir_inode; - - min_key.objectid = dir_elem->ino; - min_key.type = BTRFS_DIR_ITEM_KEY; - min_key.offset = 0; -again: - btrfs_release_path(path); - ret = btrfs_search_forward(log, &min_key, path, trans->transid); - if (ret < 0) { - goto next_dir_inode; - } else if (ret > 0) { - ret = 0; - goto next_dir_inode; - } - -process_leaf: - leaf = path->nodes[0]; - nritems = btrfs_header_nritems(leaf); - for (i = path->slots[0]; i < nritems; i++) { - struct btrfs_dir_item *di; - struct btrfs_key di_key; - struct inode *di_inode; - struct btrfs_dir_list *new_dir_elem; - int log_mode = LOG_INODE_EXISTS; - int type; - - btrfs_item_key_to_cpu(leaf, &min_key, i); - if (min_key.objectid != dir_elem->ino || - min_key.type != BTRFS_DIR_ITEM_KEY) - goto next_dir_inode; - - di = btrfs_item_ptr(leaf, i, struct btrfs_dir_item); - type = btrfs_dir_type(leaf, di); - if (btrfs_dir_transid(leaf, di) < trans->transid && - type != BTRFS_FT_DIR) - continue; - btrfs_dir_item_key_to_cpu(leaf, di, &di_key); - if (di_key.type == BTRFS_ROOT_ITEM_KEY) - continue; - - di_inode = btrfs_iget(root->fs_info->sb, &di_key, - root, NULL); - if (IS_ERR(di_inode)) { - ret = PTR_ERR(di_inode); - goto next_dir_inode; - } - - if (btrfs_inode_in_log(di_inode, trans->transid)) { - iput(di_inode); - continue; - } - - ctx->log_new_dentries = false; - if (type == BTRFS_FT_DIR || type == BTRFS_FT_SYMLINK) - log_mode = LOG_INODE_ALL; - btrfs_release_path(path); - ret = btrfs_log_inode(trans, root, di_inode, - log_mode, 0, LLONG_MAX, ctx); - if (!ret && - btrfs_must_commit_transaction(trans, di_inode)) - ret = 1; - iput(di_inode); - if (ret) - goto next_dir_inode; - if (ctx->log_new_dentries) { - new_dir_elem = kmalloc(sizeof(*new_dir_elem), - GFP_NOFS); - if (!new_dir_elem) { - ret = -ENOMEM; - goto next_dir_inode; - } - new_dir_elem->ino = di_key.objectid; - list_add_tail(&new_dir_elem->list, &dir_list); - } - break; - } - if (i == nritems) { - ret = btrfs_next_leaf(log, path); - if (ret < 0) { - goto next_dir_inode; - } else if (ret > 0) { - ret = 0; - goto next_dir_inode; - } - goto process_leaf; - } - if (min_key.offset < (u64)-1) { - min_key.offset++; - goto again; - } -next_dir_inode: - list_del(&dir_elem->list); - kfree(dir_elem); - } - - btrfs_free_path(path); - return ret; -} - -static int btrfs_log_all_parents(struct btrfs_trans_handle *trans, - struct inode *inode, - struct btrfs_log_ctx *ctx) -{ - int ret; - struct btrfs_path *path; - struct btrfs_key key; - struct btrfs_root *root = BTRFS_I(inode)->root; - const u64 ino = btrfs_ino(inode); - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->skip_locking = 1; - path->search_commit_root = 1; - - key.objectid = ino; - key.type = BTRFS_INODE_REF_KEY; - key.offset = 0; - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out; - - while (true) { - struct extent_buffer *leaf = path->nodes[0]; - int slot = path->slots[0]; - u32 cur_offset = 0; - u32 item_size; - unsigned long ptr; - - if (slot >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(root, path); - if (ret < 0) - goto out; - else if (ret > 0) - break; - continue; - } - - btrfs_item_key_to_cpu(leaf, &key, slot); - /* BTRFS_INODE_EXTREF_KEY is BTRFS_INODE_REF_KEY + 1 */ - if (key.objectid != ino || key.type > BTRFS_INODE_EXTREF_KEY) - break; - - item_size = btrfs_item_size_nr(leaf, slot); - ptr = btrfs_item_ptr_offset(leaf, slot); - while (cur_offset < item_size) { - struct btrfs_key inode_key; - struct inode *dir_inode; - - inode_key.type = BTRFS_INODE_ITEM_KEY; - inode_key.offset = 0; - - if (key.type == BTRFS_INODE_EXTREF_KEY) { - struct btrfs_inode_extref *extref; - - extref = (struct btrfs_inode_extref *) - (ptr + cur_offset); - inode_key.objectid = btrfs_inode_extref_parent( - leaf, extref); - cur_offset += sizeof(*extref); - cur_offset += btrfs_inode_extref_name_len(leaf, - extref); - } else { - inode_key.objectid = key.offset; - cur_offset = item_size; - } - - dir_inode = btrfs_iget(root->fs_info->sb, &inode_key, - root, NULL); - /* If parent inode was deleted, skip it. */ - if (IS_ERR(dir_inode)) - continue; - - if (ctx) - ctx->log_new_dentries = false; - ret = btrfs_log_inode(trans, root, dir_inode, - LOG_INODE_ALL, 0, LLONG_MAX, ctx); - if (!ret && - btrfs_must_commit_transaction(trans, dir_inode)) - ret = 1; - if (!ret && ctx && ctx->log_new_dentries) - ret = log_new_dir_dentries(trans, root, - dir_inode, ctx); - iput(dir_inode); - if (ret) - goto out; - } - path->slots[0]++; - } - ret = 0; -out: - btrfs_free_path(path); - return ret; -} - -/* - * helper function around btrfs_log_inode to make sure newly created - * parent directories also end up in the log. A minimal inode and backref - * only logging is done of any parent directories that are older than - * the last committed transaction - */ -static int btrfs_log_inode_parent(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct inode *inode, - struct dentry *parent, - const loff_t start, - const loff_t end, - int exists_only, - struct btrfs_log_ctx *ctx) -{ - int inode_only = exists_only ? LOG_INODE_EXISTS : LOG_INODE_ALL; - struct super_block *sb; - struct dentry *old_parent = NULL; - int ret = 0; - u64 last_committed = root->fs_info->last_trans_committed; - bool log_dentries = false; - struct inode *orig_inode = inode; - - sb = inode->i_sb; - - if (btrfs_test_opt(root->fs_info, NOTREELOG)) { - ret = 1; - goto end_no_trans; - } - - /* - * The prev transaction commit doesn't complete, we need do - * full commit by ourselves. - */ - if (root->fs_info->last_trans_log_full_commit > - root->fs_info->last_trans_committed) { - ret = 1; - goto end_no_trans; - } - - if (root != BTRFS_I(inode)->root || - btrfs_root_refs(&root->root_item) == 0) { - ret = 1; - goto end_no_trans; - } - - ret = check_parent_dirs_for_sync(trans, inode, parent, - sb, last_committed); - if (ret) - goto end_no_trans; - - if (btrfs_inode_in_log(inode, trans->transid)) { - ret = BTRFS_NO_LOG_SYNC; - goto end_no_trans; - } - - ret = start_log_trans(trans, root, ctx); - if (ret) - goto end_no_trans; - - ret = btrfs_log_inode(trans, root, inode, inode_only, start, end, ctx); - if (ret) - goto end_trans; - - /* - * for regular files, if its inode is already on disk, we don't - * have to worry about the parents at all. This is because - * we can use the last_unlink_trans field to record renames - * and other fun in this file. - */ - if (S_ISREG(inode->i_mode) && - BTRFS_I(inode)->generation <= last_committed && - BTRFS_I(inode)->last_unlink_trans <= last_committed) { - ret = 0; - goto end_trans; - } - - if (S_ISDIR(inode->i_mode) && ctx && ctx->log_new_dentries) - log_dentries = true; - - /* - * On unlink we must make sure all our current and old parent directory - * inodes are fully logged. This is to prevent leaving dangling - * directory index entries in directories that were our parents but are - * not anymore. Not doing this results in old parent directory being - * impossible to delete after log replay (rmdir will always fail with - * error -ENOTEMPTY). - * - * Example 1: - * - * mkdir testdir - * touch testdir/foo - * ln testdir/foo testdir/bar - * sync - * unlink testdir/bar - * xfs_io -c fsync testdir/foo - * - * mount fs, triggers log replay - * - * If we don't log the parent directory (testdir), after log replay the - * directory still has an entry pointing to the file inode using the bar - * name, but a matching BTRFS_INODE_[REF|EXTREF]_KEY does not exist and - * the file inode has a link count of 1. - * - * Example 2: - * - * mkdir testdir - * touch foo - * ln foo testdir/foo2 - * ln foo testdir/foo3 - * sync - * unlink testdir/foo3 - * xfs_io -c fsync foo - * - * mount fs, triggers log replay - * - * Similar as the first example, after log replay the parent directory - * testdir still has an entry pointing to the inode file with name foo3 - * but the file inode does not have a matching BTRFS_INODE_REF_KEY item - * and has a link count of 2. - */ - if (BTRFS_I(inode)->last_unlink_trans > last_committed) { - ret = btrfs_log_all_parents(trans, orig_inode, ctx); - if (ret) - goto end_trans; - } - - while (1) { - if (!parent || d_really_is_negative(parent) || sb != parent->d_sb) - break; - - inode = d_inode(parent); - if (root != BTRFS_I(inode)->root) - break; - - if (BTRFS_I(inode)->generation > last_committed) { - ret = btrfs_log_inode(trans, root, inode, - LOG_INODE_EXISTS, - 0, LLONG_MAX, ctx); - if (ret) - goto end_trans; - } - if (IS_ROOT(parent)) - break; - - parent = dget_parent(parent); - dput(old_parent); - old_parent = parent; - } - if (log_dentries) - ret = log_new_dir_dentries(trans, root, orig_inode, ctx); - else - ret = 0; -end_trans: - dput(old_parent); - if (ret < 0) { - btrfs_set_log_full_commit(root->fs_info, trans); - ret = 1; - } - - if (ret) - btrfs_remove_log_ctx(root, ctx); - btrfs_end_log_trans(root); -end_no_trans: - return ret; -} - -/* - * it is not safe to log dentry if the chunk root has added new - * chunks. This returns 0 if the dentry was logged, and 1 otherwise. - * If this returns 1, you must commit the transaction to safely get your - * data on disk. - */ -int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct dentry *dentry, - const loff_t start, - const loff_t end, - struct btrfs_log_ctx *ctx) -{ - struct dentry *parent = dget_parent(dentry); - int ret; - - ret = btrfs_log_inode_parent(trans, root, d_inode(dentry), parent, - start, end, 0, ctx); - dput(parent); - - return ret; -} - -/* - * should be called during mount to recover any replay any log trees - * from the FS - */ -int btrfs_recover_log_trees(struct btrfs_root *log_root_tree) -{ - int ret; - struct btrfs_path *path; - struct btrfs_trans_handle *trans; - struct btrfs_key key; - struct btrfs_key found_key; - struct btrfs_key tmp_key; - struct btrfs_root *log; - struct btrfs_fs_info *fs_info = log_root_tree->fs_info; - struct walk_control wc = { - .process_func = process_one_buffer, - .stage = 0, - }; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - set_bit(BTRFS_FS_LOG_RECOVERING, &fs_info->flags); - - trans = btrfs_start_transaction(fs_info->tree_root, 0); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto error; - } - - wc.trans = trans; - wc.pin = 1; - - ret = walk_log_tree(trans, log_root_tree, &wc); - if (ret) { - btrfs_handle_fs_error(fs_info, ret, - "Failed to pin buffers while recovering log root tree."); - goto error; - } - -again: - key.objectid = BTRFS_TREE_LOG_OBJECTID; - key.offset = (u64)-1; - key.type = BTRFS_ROOT_ITEM_KEY; - - while (1) { - ret = btrfs_search_slot(NULL, log_root_tree, &key, path, 0, 0); - - if (ret < 0) { - btrfs_handle_fs_error(fs_info, ret, - "Couldn't find tree log root."); - goto error; - } - if (ret > 0) { - if (path->slots[0] == 0) - break; - path->slots[0]--; - } - btrfs_item_key_to_cpu(path->nodes[0], &found_key, - path->slots[0]); - btrfs_release_path(path); - if (found_key.objectid != BTRFS_TREE_LOG_OBJECTID) - break; - - log = btrfs_read_fs_root(log_root_tree, &found_key); - if (IS_ERR(log)) { - ret = PTR_ERR(log); - btrfs_handle_fs_error(fs_info, ret, - "Couldn't read tree log root."); - goto error; - } - - tmp_key.objectid = found_key.offset; - tmp_key.type = BTRFS_ROOT_ITEM_KEY; - tmp_key.offset = (u64)-1; - - wc.replay_dest = btrfs_read_fs_root_no_name(fs_info, &tmp_key); - if (IS_ERR(wc.replay_dest)) { - ret = PTR_ERR(wc.replay_dest); - free_extent_buffer(log->node); - free_extent_buffer(log->commit_root); - kfree(log); - btrfs_handle_fs_error(fs_info, ret, - "Couldn't read target root for tree log recovery."); - goto error; - } - - wc.replay_dest->log_root = log; - btrfs_record_root_in_trans(trans, wc.replay_dest); - ret = walk_log_tree(trans, log, &wc); - - if (!ret && wc.stage == LOG_WALK_REPLAY_ALL) { - ret = fixup_inode_link_counts(trans, wc.replay_dest, - path); - } - - key.offset = found_key.offset - 1; - wc.replay_dest->log_root = NULL; - free_extent_buffer(log->node); - free_extent_buffer(log->commit_root); - kfree(log); - - if (ret) - goto error; - - if (found_key.offset == 0) - break; - } - btrfs_release_path(path); - - /* step one is to pin it all, step two is to replay just inodes */ - if (wc.pin) { - wc.pin = 0; - wc.process_func = replay_one_buffer; - wc.stage = LOG_WALK_REPLAY_INODES; - goto again; - } - /* step three is to replay everything */ - if (wc.stage < LOG_WALK_REPLAY_ALL) { - wc.stage++; - goto again; - } - - btrfs_free_path(path); - - /* step 4: commit the transaction, which also unpins the blocks */ - ret = btrfs_commit_transaction(trans, fs_info->tree_root); - if (ret) - return ret; - - free_extent_buffer(log_root_tree->node); - log_root_tree->log_root = NULL; - clear_bit(BTRFS_FS_LOG_RECOVERING, &fs_info->flags); - kfree(log_root_tree); - - return 0; -error: - if (wc.trans) - btrfs_end_transaction(wc.trans, fs_info->tree_root); - btrfs_free_path(path); - return ret; -} - -/* - * there are some corner cases where we want to force a full - * commit instead of allowing a directory to be logged. - * - * They revolve around files there were unlinked from the directory, and - * this function updates the parent directory so that a full commit is - * properly done if it is fsync'd later after the unlinks are done. - * - * Must be called before the unlink operations (updates to the subvolume tree, - * inodes, etc) are done. - */ -void btrfs_record_unlink_dir(struct btrfs_trans_handle *trans, - struct inode *dir, struct inode *inode, - int for_rename) -{ - /* - * when we're logging a file, if it hasn't been renamed - * or unlinked, and its inode is fully committed on disk, - * we don't have to worry about walking up the directory chain - * to log its parents. - * - * So, we use the last_unlink_trans field to put this transid - * into the file. When the file is logged we check it and - * don't log the parents if the file is fully on disk. - */ - mutex_lock(&BTRFS_I(inode)->log_mutex); - BTRFS_I(inode)->last_unlink_trans = trans->transid; - mutex_unlock(&BTRFS_I(inode)->log_mutex); - - /* - * if this directory was already logged any new - * names for this file/dir will get recorded - */ - smp_mb(); - if (BTRFS_I(dir)->logged_trans == trans->transid) - return; - - /* - * if the inode we're about to unlink was logged, - * the log will be properly updated for any new names - */ - if (BTRFS_I(inode)->logged_trans == trans->transid) - return; - - /* - * when renaming files across directories, if the directory - * there we're unlinking from gets fsync'd later on, there's - * no way to find the destination directory later and fsync it - * properly. So, we have to be conservative and force commits - * so the new name gets discovered. - */ - if (for_rename) - goto record; - - /* we can safely do the unlink without any special recording */ - return; - -record: - mutex_lock(&BTRFS_I(dir)->log_mutex); - BTRFS_I(dir)->last_unlink_trans = trans->transid; - mutex_unlock(&BTRFS_I(dir)->log_mutex); -} - -/* - * Make sure that if someone attempts to fsync the parent directory of a deleted - * snapshot, it ends up triggering a transaction commit. This is to guarantee - * that after replaying the log tree of the parent directory's root we will not - * see the snapshot anymore and at log replay time we will not see any log tree - * corresponding to the deleted snapshot's root, which could lead to replaying - * it after replaying the log tree of the parent directory (which would replay - * the snapshot delete operation). - * - * Must be called before the actual snapshot destroy operation (updates to the - * parent root and tree of tree roots trees, etc) are done. - */ -void btrfs_record_snapshot_destroy(struct btrfs_trans_handle *trans, - struct inode *dir) -{ - mutex_lock(&BTRFS_I(dir)->log_mutex); - BTRFS_I(dir)->last_unlink_trans = trans->transid; - mutex_unlock(&BTRFS_I(dir)->log_mutex); -} - -/* - * Call this after adding a new name for a file and it will properly - * update the log to reflect the new name. - * - * It will return zero if all goes well, and it will return 1 if a - * full transaction commit is required. - */ -int btrfs_log_new_name(struct btrfs_trans_handle *trans, - struct inode *inode, struct inode *old_dir, - struct dentry *parent) -{ - struct btrfs_root * root = BTRFS_I(inode)->root; - - /* - * this will force the logging code to walk the dentry chain - * up for the file - */ - if (S_ISREG(inode->i_mode)) - BTRFS_I(inode)->last_unlink_trans = trans->transid; - - /* - * if this inode hasn't been logged and directory we're renaming it - * from hasn't been logged, we don't need to log it - */ - if (BTRFS_I(inode)->logged_trans <= - root->fs_info->last_trans_committed && - (!old_dir || BTRFS_I(old_dir)->logged_trans <= - root->fs_info->last_trans_committed)) - return 0; - - return btrfs_log_inode_parent(trans, root, inode, parent, 0, - LLONG_MAX, 1, NULL); -} - diff --git a/src/linux/fs/btrfs/tree-log.h b/src/linux/fs/btrfs/tree-log.h deleted file mode 100644 index ab858e3..0000000 --- a/src/linux/fs/btrfs/tree-log.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2008 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __TREE_LOG_ -#define __TREE_LOG_ - -#include "ctree.h" -#include "transaction.h" - -/* return value for btrfs_log_dentry_safe that means we don't need to log it at all */ -#define BTRFS_NO_LOG_SYNC 256 - -struct btrfs_log_ctx { - int log_ret; - int log_transid; - int io_err; - bool log_new_dentries; - struct inode *inode; - struct list_head list; -}; - -static inline void btrfs_init_log_ctx(struct btrfs_log_ctx *ctx, - struct inode *inode) -{ - ctx->log_ret = 0; - ctx->log_transid = 0; - ctx->io_err = 0; - ctx->log_new_dentries = false; - ctx->inode = inode; - INIT_LIST_HEAD(&ctx->list); -} - -static inline void btrfs_set_log_full_commit(struct btrfs_fs_info *fs_info, - struct btrfs_trans_handle *trans) -{ - ACCESS_ONCE(fs_info->last_trans_log_full_commit) = trans->transid; -} - -static inline int btrfs_need_log_full_commit(struct btrfs_fs_info *fs_info, - struct btrfs_trans_handle *trans) -{ - return ACCESS_ONCE(fs_info->last_trans_log_full_commit) == - trans->transid; -} - -int btrfs_sync_log(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct btrfs_log_ctx *ctx); -int btrfs_free_log(struct btrfs_trans_handle *trans, struct btrfs_root *root); -int btrfs_free_log_root_tree(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info); -int btrfs_recover_log_trees(struct btrfs_root *tree_root); -int btrfs_log_dentry_safe(struct btrfs_trans_handle *trans, - struct btrfs_root *root, struct dentry *dentry, - const loff_t start, - const loff_t end, - struct btrfs_log_ctx *ctx); -int btrfs_del_dir_entries_in_log(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - const char *name, int name_len, - struct inode *dir, u64 index); -int btrfs_del_inode_ref_in_log(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - const char *name, int name_len, - struct inode *inode, u64 dirid); -void btrfs_end_log_trans(struct btrfs_root *root); -int btrfs_pin_log_trans(struct btrfs_root *root); -void btrfs_record_unlink_dir(struct btrfs_trans_handle *trans, - struct inode *dir, struct inode *inode, - int for_rename); -void btrfs_record_snapshot_destroy(struct btrfs_trans_handle *trans, - struct inode *dir); -int btrfs_log_new_name(struct btrfs_trans_handle *trans, - struct inode *inode, struct inode *old_dir, - struct dentry *parent); -#endif diff --git a/src/linux/fs/btrfs/ulist.c b/src/linux/fs/btrfs/ulist.c deleted file mode 100644 index b1434bb..0000000 --- a/src/linux/fs/btrfs/ulist.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * Copyright (C) 2011 STRATO AG - * written by Arne Jansen - * Distributed under the GNU GPL license version 2. - */ - -#include -#include "ulist.h" -#include "ctree.h" - -/* - * ulist is a generic data structure to hold a collection of unique u64 - * values. The only operations it supports is adding to the list and - * enumerating it. - * It is possible to store an auxiliary value along with the key. - * - * A sample usage for ulists is the enumeration of directed graphs without - * visiting a node twice. The pseudo-code could look like this: - * - * ulist = ulist_alloc(); - * ulist_add(ulist, root); - * ULIST_ITER_INIT(&uiter); - * - * while ((elem = ulist_next(ulist, &uiter)) { - * for (all child nodes n in elem) - * ulist_add(ulist, n); - * do something useful with the node; - * } - * ulist_free(ulist); - * - * This assumes the graph nodes are addressable by u64. This stems from the - * usage for tree enumeration in btrfs, where the logical addresses are - * 64 bit. - * - * It is also useful for tree enumeration which could be done elegantly - * recursively, but is not possible due to kernel stack limitations. The - * loop would be similar to the above. - */ - -/** - * ulist_init - freshly initialize a ulist - * @ulist: the ulist to initialize - * - * Note: don't use this function to init an already used ulist, use - * ulist_reinit instead. - */ -void ulist_init(struct ulist *ulist) -{ - INIT_LIST_HEAD(&ulist->nodes); - ulist->root = RB_ROOT; - ulist->nnodes = 0; -} - -/** - * ulist_fini - free up additionally allocated memory for the ulist - * @ulist: the ulist from which to free the additional memory - * - * This is useful in cases where the base 'struct ulist' has been statically - * allocated. - */ -static void ulist_fini(struct ulist *ulist) -{ - struct ulist_node *node; - struct ulist_node *next; - - list_for_each_entry_safe(node, next, &ulist->nodes, list) { - kfree(node); - } - ulist->root = RB_ROOT; - INIT_LIST_HEAD(&ulist->nodes); -} - -/** - * ulist_reinit - prepare a ulist for reuse - * @ulist: ulist to be reused - * - * Free up all additional memory allocated for the list elements and reinit - * the ulist. - */ -void ulist_reinit(struct ulist *ulist) -{ - ulist_fini(ulist); - ulist_init(ulist); -} - -/** - * ulist_alloc - dynamically allocate a ulist - * @gfp_mask: allocation flags to for base allocation - * - * The allocated ulist will be returned in an initialized state. - */ -struct ulist *ulist_alloc(gfp_t gfp_mask) -{ - struct ulist *ulist = kmalloc(sizeof(*ulist), gfp_mask); - - if (!ulist) - return NULL; - - ulist_init(ulist); - - return ulist; -} - -/** - * ulist_free - free dynamically allocated ulist - * @ulist: ulist to free - * - * It is not necessary to call ulist_fini before. - */ -void ulist_free(struct ulist *ulist) -{ - if (!ulist) - return; - ulist_fini(ulist); - kfree(ulist); -} - -static struct ulist_node *ulist_rbtree_search(struct ulist *ulist, u64 val) -{ - struct rb_node *n = ulist->root.rb_node; - struct ulist_node *u = NULL; - - while (n) { - u = rb_entry(n, struct ulist_node, rb_node); - if (u->val < val) - n = n->rb_right; - else if (u->val > val) - n = n->rb_left; - else - return u; - } - return NULL; -} - -static void ulist_rbtree_erase(struct ulist *ulist, struct ulist_node *node) -{ - rb_erase(&node->rb_node, &ulist->root); - list_del(&node->list); - kfree(node); - BUG_ON(ulist->nnodes == 0); - ulist->nnodes--; -} - -static int ulist_rbtree_insert(struct ulist *ulist, struct ulist_node *ins) -{ - struct rb_node **p = &ulist->root.rb_node; - struct rb_node *parent = NULL; - struct ulist_node *cur = NULL; - - while (*p) { - parent = *p; - cur = rb_entry(parent, struct ulist_node, rb_node); - - if (cur->val < ins->val) - p = &(*p)->rb_right; - else if (cur->val > ins->val) - p = &(*p)->rb_left; - else - return -EEXIST; - } - rb_link_node(&ins->rb_node, parent, p); - rb_insert_color(&ins->rb_node, &ulist->root); - return 0; -} - -/** - * ulist_add - add an element to the ulist - * @ulist: ulist to add the element to - * @val: value to add to ulist - * @aux: auxiliary value to store along with val - * @gfp_mask: flags to use for allocation - * - * Note: locking must be provided by the caller. In case of rwlocks write - * locking is needed - * - * Add an element to a ulist. The @val will only be added if it doesn't - * already exist. If it is added, the auxiliary value @aux is stored along with - * it. In case @val already exists in the ulist, @aux is ignored, even if - * it differs from the already stored value. - * - * ulist_add returns 0 if @val already exists in ulist and 1 if @val has been - * inserted. - * In case of allocation failure -ENOMEM is returned and the ulist stays - * unaltered. - */ -int ulist_add(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask) -{ - return ulist_add_merge(ulist, val, aux, NULL, gfp_mask); -} - -int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux, - u64 *old_aux, gfp_t gfp_mask) -{ - int ret; - struct ulist_node *node; - - node = ulist_rbtree_search(ulist, val); - if (node) { - if (old_aux) - *old_aux = node->aux; - return 0; - } - node = kmalloc(sizeof(*node), gfp_mask); - if (!node) - return -ENOMEM; - - node->val = val; - node->aux = aux; - - ret = ulist_rbtree_insert(ulist, node); - ASSERT(!ret); - list_add_tail(&node->list, &ulist->nodes); - ulist->nnodes++; - - return 1; -} - -/* - * ulist_del - delete one node from ulist - * @ulist: ulist to remove node from - * @val: value to delete - * @aux: aux to delete - * - * The deletion will only be done when *BOTH* val and aux matches. - * Return 0 for successful delete. - * Return > 0 for not found. - */ -int ulist_del(struct ulist *ulist, u64 val, u64 aux) -{ - struct ulist_node *node; - - node = ulist_rbtree_search(ulist, val); - /* Not found */ - if (!node) - return 1; - - if (node->aux != aux) - return 1; - - /* Found and delete */ - ulist_rbtree_erase(ulist, node); - return 0; -} - -/** - * ulist_next - iterate ulist - * @ulist: ulist to iterate - * @uiter: iterator variable, initialized with ULIST_ITER_INIT(&iterator) - * - * Note: locking must be provided by the caller. In case of rwlocks only read - * locking is needed - * - * This function is used to iterate an ulist. - * It returns the next element from the ulist or %NULL when the - * end is reached. No guarantee is made with respect to the order in which - * the elements are returned. They might neither be returned in order of - * addition nor in ascending order. - * It is allowed to call ulist_add during an enumeration. Newly added items - * are guaranteed to show up in the running enumeration. - */ -struct ulist_node *ulist_next(struct ulist *ulist, struct ulist_iterator *uiter) -{ - struct ulist_node *node; - - if (list_empty(&ulist->nodes)) - return NULL; - if (uiter->cur_list && uiter->cur_list->next == &ulist->nodes) - return NULL; - if (uiter->cur_list) { - uiter->cur_list = uiter->cur_list->next; - } else { - uiter->cur_list = ulist->nodes.next; - } - node = list_entry(uiter->cur_list, struct ulist_node, list); - return node; -} diff --git a/src/linux/fs/btrfs/ulist.h b/src/linux/fs/btrfs/ulist.h deleted file mode 100644 index a01a2c4..0000000 --- a/src/linux/fs/btrfs/ulist.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2011 STRATO AG - * written by Arne Jansen - * Distributed under the GNU GPL license version 2. - * - */ - -#ifndef __ULIST__ -#define __ULIST__ - -#include -#include - -/* - * ulist is a generic data structure to hold a collection of unique u64 - * values. The only operations it supports is adding to the list and - * enumerating it. - * It is possible to store an auxiliary value along with the key. - * - */ -struct ulist_iterator { -#ifdef CONFIG_BTRFS_DEBUG - int i; -#endif - struct list_head *cur_list; /* hint to start search */ -}; - -/* - * element of the list - */ -struct ulist_node { - u64 val; /* value to store */ - u64 aux; /* auxiliary value saved along with the val */ - -#ifdef CONFIG_BTRFS_DEBUG - int seqnum; /* sequence number this node is added */ -#endif - - struct list_head list; /* used to link node */ - struct rb_node rb_node; /* used to speed up search */ -}; - -struct ulist { - /* - * number of elements stored in list - */ - unsigned long nnodes; - - struct list_head nodes; - struct rb_root root; -}; - -void ulist_init(struct ulist *ulist); -void ulist_reinit(struct ulist *ulist); -struct ulist *ulist_alloc(gfp_t gfp_mask); -void ulist_free(struct ulist *ulist); -int ulist_add(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask); -int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux, - u64 *old_aux, gfp_t gfp_mask); -int ulist_del(struct ulist *ulist, u64 val, u64 aux); - -/* just like ulist_add_merge() but take a pointer for the aux data */ -static inline int ulist_add_merge_ptr(struct ulist *ulist, u64 val, void *aux, - void **old_aux, gfp_t gfp_mask) -{ -#if BITS_PER_LONG == 32 - u64 old64 = (uintptr_t)*old_aux; - int ret = ulist_add_merge(ulist, val, (uintptr_t)aux, &old64, gfp_mask); - *old_aux = (void *)((uintptr_t)old64); - return ret; -#else - return ulist_add_merge(ulist, val, (u64)aux, (u64 *)old_aux, gfp_mask); -#endif -} - -struct ulist_node *ulist_next(struct ulist *ulist, - struct ulist_iterator *uiter); - -#define ULIST_ITER_INIT(uiter) ((uiter)->cur_list = NULL) - -#endif diff --git a/src/linux/fs/btrfs/uuid-tree.c b/src/linux/fs/btrfs/uuid-tree.c deleted file mode 100644 index 7fc89e4..0000000 --- a/src/linux/fs/btrfs/uuid-tree.c +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Copyright (C) STRATO AG 2013. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ -#include -#include -#include "ctree.h" -#include "transaction.h" -#include "disk-io.h" -#include "print-tree.h" - - -static void btrfs_uuid_to_key(u8 *uuid, u8 type, struct btrfs_key *key) -{ - key->type = type; - key->objectid = get_unaligned_le64(uuid); - key->offset = get_unaligned_le64(uuid + sizeof(u64)); -} - -/* return -ENOENT for !found, < 0 for errors, or 0 if an item was found */ -static int btrfs_uuid_tree_lookup(struct btrfs_root *uuid_root, u8 *uuid, - u8 type, u64 subid) -{ - int ret; - struct btrfs_path *path = NULL; - struct extent_buffer *eb; - int slot; - u32 item_size; - unsigned long offset; - struct btrfs_key key; - - if (WARN_ON_ONCE(!uuid_root)) { - ret = -ENOENT; - goto out; - } - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - btrfs_uuid_to_key(uuid, type, &key); - ret = btrfs_search_slot(NULL, uuid_root, &key, path, 0, 0); - if (ret < 0) { - goto out; - } else if (ret > 0) { - ret = -ENOENT; - goto out; - } - - eb = path->nodes[0]; - slot = path->slots[0]; - item_size = btrfs_item_size_nr(eb, slot); - offset = btrfs_item_ptr_offset(eb, slot); - ret = -ENOENT; - - if (!IS_ALIGNED(item_size, sizeof(u64))) { - btrfs_warn(uuid_root->fs_info, - "uuid item with illegal size %lu!", - (unsigned long)item_size); - goto out; - } - while (item_size) { - __le64 data; - - read_extent_buffer(eb, &data, offset, sizeof(data)); - if (le64_to_cpu(data) == subid) { - ret = 0; - break; - } - offset += sizeof(data); - item_size -= sizeof(data); - } - -out: - btrfs_free_path(path); - return ret; -} - -int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans, - struct btrfs_root *uuid_root, u8 *uuid, u8 type, - u64 subid_cpu) -{ - int ret; - struct btrfs_path *path = NULL; - struct btrfs_key key; - struct extent_buffer *eb; - int slot; - unsigned long offset; - __le64 subid_le; - - ret = btrfs_uuid_tree_lookup(uuid_root, uuid, type, subid_cpu); - if (ret != -ENOENT) - return ret; - - if (WARN_ON_ONCE(!uuid_root)) { - ret = -EINVAL; - goto out; - } - - btrfs_uuid_to_key(uuid, type, &key); - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - ret = btrfs_insert_empty_item(trans, uuid_root, path, &key, - sizeof(subid_le)); - if (ret >= 0) { - /* Add an item for the type for the first time */ - eb = path->nodes[0]; - slot = path->slots[0]; - offset = btrfs_item_ptr_offset(eb, slot); - } else if (ret == -EEXIST) { - /* - * An item with that type already exists. - * Extend the item and store the new subid at the end. - */ - btrfs_extend_item(uuid_root, path, sizeof(subid_le)); - eb = path->nodes[0]; - slot = path->slots[0]; - offset = btrfs_item_ptr_offset(eb, slot); - offset += btrfs_item_size_nr(eb, slot) - sizeof(subid_le); - } else if (ret < 0) { - btrfs_warn(uuid_root->fs_info, - "insert uuid item failed %d (0x%016llx, 0x%016llx) type %u!", - ret, (unsigned long long)key.objectid, - (unsigned long long)key.offset, type); - goto out; - } - - ret = 0; - subid_le = cpu_to_le64(subid_cpu); - write_extent_buffer(eb, &subid_le, offset, sizeof(subid_le)); - btrfs_mark_buffer_dirty(eb); - -out: - btrfs_free_path(path); - return ret; -} - -int btrfs_uuid_tree_rem(struct btrfs_trans_handle *trans, - struct btrfs_root *uuid_root, u8 *uuid, u8 type, - u64 subid) -{ - int ret; - struct btrfs_path *path = NULL; - struct btrfs_key key; - struct extent_buffer *eb; - int slot; - unsigned long offset; - u32 item_size; - unsigned long move_dst; - unsigned long move_src; - unsigned long move_len; - - if (WARN_ON_ONCE(!uuid_root)) { - ret = -EINVAL; - goto out; - } - - btrfs_uuid_to_key(uuid, type, &key); - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - ret = btrfs_search_slot(trans, uuid_root, &key, path, -1, 1); - if (ret < 0) { - btrfs_warn(uuid_root->fs_info, - "error %d while searching for uuid item!", ret); - goto out; - } - if (ret > 0) { - ret = -ENOENT; - goto out; - } - - eb = path->nodes[0]; - slot = path->slots[0]; - offset = btrfs_item_ptr_offset(eb, slot); - item_size = btrfs_item_size_nr(eb, slot); - if (!IS_ALIGNED(item_size, sizeof(u64))) { - btrfs_warn(uuid_root->fs_info, - "uuid item with illegal size %lu!", - (unsigned long)item_size); - ret = -ENOENT; - goto out; - } - while (item_size) { - __le64 read_subid; - - read_extent_buffer(eb, &read_subid, offset, sizeof(read_subid)); - if (le64_to_cpu(read_subid) == subid) - break; - offset += sizeof(read_subid); - item_size -= sizeof(read_subid); - } - - if (!item_size) { - ret = -ENOENT; - goto out; - } - - item_size = btrfs_item_size_nr(eb, slot); - if (item_size == sizeof(subid)) { - ret = btrfs_del_item(trans, uuid_root, path); - goto out; - } - - move_dst = offset; - move_src = offset + sizeof(subid); - move_len = item_size - (move_src - btrfs_item_ptr_offset(eb, slot)); - memmove_extent_buffer(eb, move_dst, move_src, move_len); - btrfs_truncate_item(uuid_root, path, item_size - sizeof(subid), 1); - -out: - btrfs_free_path(path); - return ret; -} - -static int btrfs_uuid_iter_rem(struct btrfs_root *uuid_root, u8 *uuid, u8 type, - u64 subid) -{ - struct btrfs_trans_handle *trans; - int ret; - - /* 1 - for the uuid item */ - trans = btrfs_start_transaction(uuid_root, 1); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto out; - } - - ret = btrfs_uuid_tree_rem(trans, uuid_root, uuid, type, subid); - btrfs_end_transaction(trans, uuid_root); - -out: - return ret; -} - -int btrfs_uuid_tree_iterate(struct btrfs_fs_info *fs_info, - int (*check_func)(struct btrfs_fs_info *, u8 *, u8, - u64)) -{ - struct btrfs_root *root = fs_info->uuid_root; - struct btrfs_key key; - struct btrfs_path *path; - int ret = 0; - struct extent_buffer *leaf; - int slot; - u32 item_size; - unsigned long offset; - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - key.objectid = 0; - key.type = 0; - key.offset = 0; - -again_search_slot: - ret = btrfs_search_forward(root, &key, path, 0); - if (ret) { - if (ret > 0) - ret = 0; - goto out; - } - - while (1) { - cond_resched(); - leaf = path->nodes[0]; - slot = path->slots[0]; - btrfs_item_key_to_cpu(leaf, &key, slot); - - if (key.type != BTRFS_UUID_KEY_SUBVOL && - key.type != BTRFS_UUID_KEY_RECEIVED_SUBVOL) - goto skip; - - offset = btrfs_item_ptr_offset(leaf, slot); - item_size = btrfs_item_size_nr(leaf, slot); - if (!IS_ALIGNED(item_size, sizeof(u64))) { - btrfs_warn(fs_info, - "uuid item with illegal size %lu!", - (unsigned long)item_size); - goto skip; - } - while (item_size) { - u8 uuid[BTRFS_UUID_SIZE]; - __le64 subid_le; - u64 subid_cpu; - - put_unaligned_le64(key.objectid, uuid); - put_unaligned_le64(key.offset, uuid + sizeof(u64)); - read_extent_buffer(leaf, &subid_le, offset, - sizeof(subid_le)); - subid_cpu = le64_to_cpu(subid_le); - ret = check_func(fs_info, uuid, key.type, subid_cpu); - if (ret < 0) - goto out; - if (ret > 0) { - btrfs_release_path(path); - ret = btrfs_uuid_iter_rem(root, uuid, key.type, - subid_cpu); - if (ret == 0) { - /* - * this might look inefficient, but the - * justification is that it is an - * exception that check_func returns 1, - * and that in the regular case only one - * entry per UUID exists. - */ - goto again_search_slot; - } - if (ret < 0 && ret != -ENOENT) - goto out; - } - item_size -= sizeof(subid_le); - offset += sizeof(subid_le); - } - -skip: - ret = btrfs_next_item(root, path); - if (ret == 0) - continue; - else if (ret > 0) - ret = 0; - break; - } - -out: - btrfs_free_path(path); - if (ret) - btrfs_warn(fs_info, "btrfs_uuid_tree_iterate failed %d", ret); - return 0; -} diff --git a/src/linux/fs/btrfs/volumes.c b/src/linux/fs/btrfs/volumes.c deleted file mode 100644 index 71a60cc..0000000 --- a/src/linux/fs/btrfs/volumes.c +++ /dev/null @@ -1,7222 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ctree.h" -#include "extent_map.h" -#include "disk-io.h" -#include "transaction.h" -#include "print-tree.h" -#include "volumes.h" -#include "raid56.h" -#include "async-thread.h" -#include "check-integrity.h" -#include "rcu-string.h" -#include "math.h" -#include "dev-replace.h" -#include "sysfs.h" - -const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES] = { - [BTRFS_RAID_RAID10] = { - .sub_stripes = 2, - .dev_stripes = 1, - .devs_max = 0, /* 0 == as many as possible */ - .devs_min = 4, - .tolerated_failures = 1, - .devs_increment = 2, - .ncopies = 2, - }, - [BTRFS_RAID_RAID1] = { - .sub_stripes = 1, - .dev_stripes = 1, - .devs_max = 2, - .devs_min = 2, - .tolerated_failures = 1, - .devs_increment = 2, - .ncopies = 2, - }, - [BTRFS_RAID_DUP] = { - .sub_stripes = 1, - .dev_stripes = 2, - .devs_max = 1, - .devs_min = 1, - .tolerated_failures = 0, - .devs_increment = 1, - .ncopies = 2, - }, - [BTRFS_RAID_RAID0] = { - .sub_stripes = 1, - .dev_stripes = 1, - .devs_max = 0, - .devs_min = 2, - .tolerated_failures = 0, - .devs_increment = 1, - .ncopies = 1, - }, - [BTRFS_RAID_SINGLE] = { - .sub_stripes = 1, - .dev_stripes = 1, - .devs_max = 1, - .devs_min = 1, - .tolerated_failures = 0, - .devs_increment = 1, - .ncopies = 1, - }, - [BTRFS_RAID_RAID5] = { - .sub_stripes = 1, - .dev_stripes = 1, - .devs_max = 0, - .devs_min = 2, - .tolerated_failures = 1, - .devs_increment = 1, - .ncopies = 2, - }, - [BTRFS_RAID_RAID6] = { - .sub_stripes = 1, - .dev_stripes = 1, - .devs_max = 0, - .devs_min = 3, - .tolerated_failures = 2, - .devs_increment = 1, - .ncopies = 3, - }, -}; - -const u64 btrfs_raid_group[BTRFS_NR_RAID_TYPES] = { - [BTRFS_RAID_RAID10] = BTRFS_BLOCK_GROUP_RAID10, - [BTRFS_RAID_RAID1] = BTRFS_BLOCK_GROUP_RAID1, - [BTRFS_RAID_DUP] = BTRFS_BLOCK_GROUP_DUP, - [BTRFS_RAID_RAID0] = BTRFS_BLOCK_GROUP_RAID0, - [BTRFS_RAID_SINGLE] = 0, - [BTRFS_RAID_RAID5] = BTRFS_BLOCK_GROUP_RAID5, - [BTRFS_RAID_RAID6] = BTRFS_BLOCK_GROUP_RAID6, -}; - -/* - * Table to convert BTRFS_RAID_* to the error code if minimum number of devices - * condition is not met. Zero means there's no corresponding - * BTRFS_ERROR_DEV_*_NOT_MET value. - */ -const int btrfs_raid_mindev_error[BTRFS_NR_RAID_TYPES] = { - [BTRFS_RAID_RAID10] = BTRFS_ERROR_DEV_RAID10_MIN_NOT_MET, - [BTRFS_RAID_RAID1] = BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET, - [BTRFS_RAID_DUP] = 0, - [BTRFS_RAID_RAID0] = 0, - [BTRFS_RAID_SINGLE] = 0, - [BTRFS_RAID_RAID5] = BTRFS_ERROR_DEV_RAID5_MIN_NOT_MET, - [BTRFS_RAID_RAID6] = BTRFS_ERROR_DEV_RAID6_MIN_NOT_MET, -}; - -static int init_first_rw_device(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_device *device); -static int btrfs_relocate_sys_chunks(struct btrfs_root *root); -static void __btrfs_reset_dev_stats(struct btrfs_device *dev); -static void btrfs_dev_stat_print_on_error(struct btrfs_device *dev); -static void btrfs_dev_stat_print_on_load(struct btrfs_device *device); - -DEFINE_MUTEX(uuid_mutex); -static LIST_HEAD(fs_uuids); -struct list_head *btrfs_get_fs_uuids(void) -{ - return &fs_uuids; -} - -static struct btrfs_fs_devices *__alloc_fs_devices(void) -{ - struct btrfs_fs_devices *fs_devs; - - fs_devs = kzalloc(sizeof(*fs_devs), GFP_KERNEL); - if (!fs_devs) - return ERR_PTR(-ENOMEM); - - mutex_init(&fs_devs->device_list_mutex); - - INIT_LIST_HEAD(&fs_devs->devices); - INIT_LIST_HEAD(&fs_devs->resized_devices); - INIT_LIST_HEAD(&fs_devs->alloc_list); - INIT_LIST_HEAD(&fs_devs->list); - - return fs_devs; -} - -/** - * alloc_fs_devices - allocate struct btrfs_fs_devices - * @fsid: a pointer to UUID for this FS. If NULL a new UUID is - * generated. - * - * Return: a pointer to a new &struct btrfs_fs_devices on success; - * ERR_PTR() on error. Returned struct is not linked onto any lists and - * can be destroyed with kfree() right away. - */ -static struct btrfs_fs_devices *alloc_fs_devices(const u8 *fsid) -{ - struct btrfs_fs_devices *fs_devs; - - fs_devs = __alloc_fs_devices(); - if (IS_ERR(fs_devs)) - return fs_devs; - - if (fsid) - memcpy(fs_devs->fsid, fsid, BTRFS_FSID_SIZE); - else - generate_random_uuid(fs_devs->fsid); - - return fs_devs; -} - -static void free_fs_devices(struct btrfs_fs_devices *fs_devices) -{ - struct btrfs_device *device; - WARN_ON(fs_devices->opened); - while (!list_empty(&fs_devices->devices)) { - device = list_entry(fs_devices->devices.next, - struct btrfs_device, dev_list); - list_del(&device->dev_list); - rcu_string_free(device->name); - kfree(device); - } - kfree(fs_devices); -} - -static void btrfs_kobject_uevent(struct block_device *bdev, - enum kobject_action action) -{ - int ret; - - ret = kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, action); - if (ret) - pr_warn("BTRFS: Sending event '%d' to kobject: '%s' (%p): failed\n", - action, - kobject_name(&disk_to_dev(bdev->bd_disk)->kobj), - &disk_to_dev(bdev->bd_disk)->kobj); -} - -void btrfs_cleanup_fs_uuids(void) -{ - struct btrfs_fs_devices *fs_devices; - - while (!list_empty(&fs_uuids)) { - fs_devices = list_entry(fs_uuids.next, - struct btrfs_fs_devices, list); - list_del(&fs_devices->list); - free_fs_devices(fs_devices); - } -} - -static struct btrfs_device *__alloc_device(void) -{ - struct btrfs_device *dev; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) - return ERR_PTR(-ENOMEM); - - INIT_LIST_HEAD(&dev->dev_list); - INIT_LIST_HEAD(&dev->dev_alloc_list); - INIT_LIST_HEAD(&dev->resized_list); - - spin_lock_init(&dev->io_lock); - - spin_lock_init(&dev->reada_lock); - atomic_set(&dev->reada_in_flight, 0); - atomic_set(&dev->dev_stats_ccnt, 0); - btrfs_device_data_ordered_init(dev); - INIT_RADIX_TREE(&dev->reada_zones, GFP_NOFS & ~__GFP_DIRECT_RECLAIM); - INIT_RADIX_TREE(&dev->reada_extents, GFP_NOFS & ~__GFP_DIRECT_RECLAIM); - - return dev; -} - -static noinline struct btrfs_device *__find_device(struct list_head *head, - u64 devid, u8 *uuid) -{ - struct btrfs_device *dev; - - list_for_each_entry(dev, head, dev_list) { - if (dev->devid == devid && - (!uuid || !memcmp(dev->uuid, uuid, BTRFS_UUID_SIZE))) { - return dev; - } - } - return NULL; -} - -static noinline struct btrfs_fs_devices *find_fsid(u8 *fsid) -{ - struct btrfs_fs_devices *fs_devices; - - list_for_each_entry(fs_devices, &fs_uuids, list) { - if (memcmp(fsid, fs_devices->fsid, BTRFS_FSID_SIZE) == 0) - return fs_devices; - } - return NULL; -} - -static int -btrfs_get_bdev_and_sb(const char *device_path, fmode_t flags, void *holder, - int flush, struct block_device **bdev, - struct buffer_head **bh) -{ - int ret; - - *bdev = blkdev_get_by_path(device_path, flags, holder); - - if (IS_ERR(*bdev)) { - ret = PTR_ERR(*bdev); - goto error; - } - - if (flush) - filemap_write_and_wait((*bdev)->bd_inode->i_mapping); - ret = set_blocksize(*bdev, 4096); - if (ret) { - blkdev_put(*bdev, flags); - goto error; - } - invalidate_bdev(*bdev); - *bh = btrfs_read_dev_super(*bdev); - if (IS_ERR(*bh)) { - ret = PTR_ERR(*bh); - blkdev_put(*bdev, flags); - goto error; - } - - return 0; - -error: - *bdev = NULL; - *bh = NULL; - return ret; -} - -static void requeue_list(struct btrfs_pending_bios *pending_bios, - struct bio *head, struct bio *tail) -{ - - struct bio *old_head; - - old_head = pending_bios->head; - pending_bios->head = head; - if (pending_bios->tail) - tail->bi_next = old_head; - else - pending_bios->tail = tail; -} - -/* - * we try to collect pending bios for a device so we don't get a large - * number of procs sending bios down to the same device. This greatly - * improves the schedulers ability to collect and merge the bios. - * - * But, it also turns into a long list of bios to process and that is sure - * to eventually make the worker thread block. The solution here is to - * make some progress and then put this work struct back at the end of - * the list if the block device is congested. This way, multiple devices - * can make progress from a single worker thread. - */ -static noinline void run_scheduled_bios(struct btrfs_device *device) -{ - struct bio *pending; - struct backing_dev_info *bdi; - struct btrfs_fs_info *fs_info; - struct btrfs_pending_bios *pending_bios; - struct bio *tail; - struct bio *cur; - int again = 0; - unsigned long num_run; - unsigned long batch_run = 0; - unsigned long limit; - unsigned long last_waited = 0; - int force_reg = 0; - int sync_pending = 0; - struct blk_plug plug; - - /* - * this function runs all the bios we've collected for - * a particular device. We don't want to wander off to - * another device without first sending all of these down. - * So, setup a plug here and finish it off before we return - */ - blk_start_plug(&plug); - - bdi = blk_get_backing_dev_info(device->bdev); - fs_info = device->dev_root->fs_info; - limit = btrfs_async_submit_limit(fs_info); - limit = limit * 2 / 3; - -loop: - spin_lock(&device->io_lock); - -loop_lock: - num_run = 0; - - /* take all the bios off the list at once and process them - * later on (without the lock held). But, remember the - * tail and other pointers so the bios can be properly reinserted - * into the list if we hit congestion - */ - if (!force_reg && device->pending_sync_bios.head) { - pending_bios = &device->pending_sync_bios; - force_reg = 1; - } else { - pending_bios = &device->pending_bios; - force_reg = 0; - } - - pending = pending_bios->head; - tail = pending_bios->tail; - WARN_ON(pending && !tail); - - /* - * if pending was null this time around, no bios need processing - * at all and we can stop. Otherwise it'll loop back up again - * and do an additional check so no bios are missed. - * - * device->running_pending is used to synchronize with the - * schedule_bio code. - */ - if (device->pending_sync_bios.head == NULL && - device->pending_bios.head == NULL) { - again = 0; - device->running_pending = 0; - } else { - again = 1; - device->running_pending = 1; - } - - pending_bios->head = NULL; - pending_bios->tail = NULL; - - spin_unlock(&device->io_lock); - - while (pending) { - - rmb(); - /* we want to work on both lists, but do more bios on the - * sync list than the regular list - */ - if ((num_run > 32 && - pending_bios != &device->pending_sync_bios && - device->pending_sync_bios.head) || - (num_run > 64 && pending_bios == &device->pending_sync_bios && - device->pending_bios.head)) { - spin_lock(&device->io_lock); - requeue_list(pending_bios, pending, tail); - goto loop_lock; - } - - cur = pending; - pending = pending->bi_next; - cur->bi_next = NULL; - - /* - * atomic_dec_return implies a barrier for waitqueue_active - */ - if (atomic_dec_return(&fs_info->nr_async_bios) < limit && - waitqueue_active(&fs_info->async_submit_wait)) - wake_up(&fs_info->async_submit_wait); - - BUG_ON(atomic_read(&cur->__bi_cnt) == 0); - - /* - * if we're doing the sync list, record that our - * plug has some sync requests on it - * - * If we're doing the regular list and there are - * sync requests sitting around, unplug before - * we add more - */ - if (pending_bios == &device->pending_sync_bios) { - sync_pending = 1; - } else if (sync_pending) { - blk_finish_plug(&plug); - blk_start_plug(&plug); - sync_pending = 0; - } - - btrfsic_submit_bio(cur); - num_run++; - batch_run++; - - cond_resched(); - - /* - * we made progress, there is more work to do and the bdi - * is now congested. Back off and let other work structs - * run instead - */ - if (pending && bdi_write_congested(bdi) && batch_run > 8 && - fs_info->fs_devices->open_devices > 1) { - struct io_context *ioc; - - ioc = current->io_context; - - /* - * the main goal here is that we don't want to - * block if we're going to be able to submit - * more requests without blocking. - * - * This code does two great things, it pokes into - * the elevator code from a filesystem _and_ - * it makes assumptions about how batching works. - */ - if (ioc && ioc->nr_batch_requests > 0 && - time_before(jiffies, ioc->last_waited + HZ/50UL) && - (last_waited == 0 || - ioc->last_waited == last_waited)) { - /* - * we want to go through our batch of - * requests and stop. So, we copy out - * the ioc->last_waited time and test - * against it before looping - */ - last_waited = ioc->last_waited; - cond_resched(); - continue; - } - spin_lock(&device->io_lock); - requeue_list(pending_bios, pending, tail); - device->running_pending = 1; - - spin_unlock(&device->io_lock); - btrfs_queue_work(fs_info->submit_workers, - &device->work); - goto done; - } - /* unplug every 64 requests just for good measure */ - if (batch_run % 64 == 0) { - blk_finish_plug(&plug); - blk_start_plug(&plug); - sync_pending = 0; - } - } - - cond_resched(); - if (again) - goto loop; - - spin_lock(&device->io_lock); - if (device->pending_bios.head || device->pending_sync_bios.head) - goto loop_lock; - spin_unlock(&device->io_lock); - -done: - blk_finish_plug(&plug); -} - -static void pending_bios_fn(struct btrfs_work *work) -{ - struct btrfs_device *device; - - device = container_of(work, struct btrfs_device, work); - run_scheduled_bios(device); -} - - -void btrfs_free_stale_device(struct btrfs_device *cur_dev) -{ - struct btrfs_fs_devices *fs_devs; - struct btrfs_device *dev; - - if (!cur_dev->name) - return; - - list_for_each_entry(fs_devs, &fs_uuids, list) { - int del = 1; - - if (fs_devs->opened) - continue; - if (fs_devs->seeding) - continue; - - list_for_each_entry(dev, &fs_devs->devices, dev_list) { - - if (dev == cur_dev) - continue; - if (!dev->name) - continue; - - /* - * Todo: This won't be enough. What if the same device - * comes back (with new uuid and) with its mapper path? - * But for now, this does help as mostly an admin will - * either use mapper or non mapper path throughout. - */ - rcu_read_lock(); - del = strcmp(rcu_str_deref(dev->name), - rcu_str_deref(cur_dev->name)); - rcu_read_unlock(); - if (!del) - break; - } - - if (!del) { - /* delete the stale device */ - if (fs_devs->num_devices == 1) { - btrfs_sysfs_remove_fsid(fs_devs); - list_del(&fs_devs->list); - free_fs_devices(fs_devs); - } else { - fs_devs->num_devices--; - list_del(&dev->dev_list); - rcu_string_free(dev->name); - kfree(dev); - } - break; - } - } -} - -/* - * Add new device to list of registered devices - * - * Returns: - * 1 - first time device is seen - * 0 - device already known - * < 0 - error - */ -static noinline int device_list_add(const char *path, - struct btrfs_super_block *disk_super, - u64 devid, struct btrfs_fs_devices **fs_devices_ret) -{ - struct btrfs_device *device; - struct btrfs_fs_devices *fs_devices; - struct rcu_string *name; - int ret = 0; - u64 found_transid = btrfs_super_generation(disk_super); - - fs_devices = find_fsid(disk_super->fsid); - if (!fs_devices) { - fs_devices = alloc_fs_devices(disk_super->fsid); - if (IS_ERR(fs_devices)) - return PTR_ERR(fs_devices); - - list_add(&fs_devices->list, &fs_uuids); - - device = NULL; - } else { - device = __find_device(&fs_devices->devices, devid, - disk_super->dev_item.uuid); - } - - if (!device) { - if (fs_devices->opened) - return -EBUSY; - - device = btrfs_alloc_device(NULL, &devid, - disk_super->dev_item.uuid); - if (IS_ERR(device)) { - /* we can safely leave the fs_devices entry around */ - return PTR_ERR(device); - } - - name = rcu_string_strdup(path, GFP_NOFS); - if (!name) { - kfree(device); - return -ENOMEM; - } - rcu_assign_pointer(device->name, name); - - mutex_lock(&fs_devices->device_list_mutex); - list_add_rcu(&device->dev_list, &fs_devices->devices); - fs_devices->num_devices++; - mutex_unlock(&fs_devices->device_list_mutex); - - ret = 1; - device->fs_devices = fs_devices; - } else if (!device->name || strcmp(device->name->str, path)) { - /* - * When FS is already mounted. - * 1. If you are here and if the device->name is NULL that - * means this device was missing at time of FS mount. - * 2. If you are here and if the device->name is different - * from 'path' that means either - * a. The same device disappeared and reappeared with - * different name. or - * b. The missing-disk-which-was-replaced, has - * reappeared now. - * - * We must allow 1 and 2a above. But 2b would be a spurious - * and unintentional. - * - * Further in case of 1 and 2a above, the disk at 'path' - * would have missed some transaction when it was away and - * in case of 2a the stale bdev has to be updated as well. - * 2b must not be allowed at all time. - */ - - /* - * For now, we do allow update to btrfs_fs_device through the - * btrfs dev scan cli after FS has been mounted. We're still - * tracking a problem where systems fail mount by subvolume id - * when we reject replacement on a mounted FS. - */ - if (!fs_devices->opened && found_transid < device->generation) { - /* - * That is if the FS is _not_ mounted and if you - * are here, that means there is more than one - * disk with same uuid and devid.We keep the one - * with larger generation number or the last-in if - * generation are equal. - */ - return -EEXIST; - } - - name = rcu_string_strdup(path, GFP_NOFS); - if (!name) - return -ENOMEM; - rcu_string_free(device->name); - rcu_assign_pointer(device->name, name); - if (device->missing) { - fs_devices->missing_devices--; - device->missing = 0; - } - } - - /* - * Unmount does not free the btrfs_device struct but would zero - * generation along with most of the other members. So just update - * it back. We need it to pick the disk with largest generation - * (as above). - */ - if (!fs_devices->opened) - device->generation = found_transid; - - /* - * if there is new btrfs on an already registered device, - * then remove the stale device entry. - */ - if (ret > 0) - btrfs_free_stale_device(device); - - *fs_devices_ret = fs_devices; - - return ret; -} - -static struct btrfs_fs_devices *clone_fs_devices(struct btrfs_fs_devices *orig) -{ - struct btrfs_fs_devices *fs_devices; - struct btrfs_device *device; - struct btrfs_device *orig_dev; - - fs_devices = alloc_fs_devices(orig->fsid); - if (IS_ERR(fs_devices)) - return fs_devices; - - mutex_lock(&orig->device_list_mutex); - fs_devices->total_devices = orig->total_devices; - - /* We have held the volume lock, it is safe to get the devices. */ - list_for_each_entry(orig_dev, &orig->devices, dev_list) { - struct rcu_string *name; - - device = btrfs_alloc_device(NULL, &orig_dev->devid, - orig_dev->uuid); - if (IS_ERR(device)) - goto error; - - /* - * This is ok to do without rcu read locked because we hold the - * uuid mutex so nothing we touch in here is going to disappear. - */ - if (orig_dev->name) { - name = rcu_string_strdup(orig_dev->name->str, - GFP_KERNEL); - if (!name) { - kfree(device); - goto error; - } - rcu_assign_pointer(device->name, name); - } - - list_add(&device->dev_list, &fs_devices->devices); - device->fs_devices = fs_devices; - fs_devices->num_devices++; - } - mutex_unlock(&orig->device_list_mutex); - return fs_devices; -error: - mutex_unlock(&orig->device_list_mutex); - free_fs_devices(fs_devices); - return ERR_PTR(-ENOMEM); -} - -void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices, int step) -{ - struct btrfs_device *device, *next; - struct btrfs_device *latest_dev = NULL; - - mutex_lock(&uuid_mutex); -again: - /* This is the initialized path, it is safe to release the devices. */ - list_for_each_entry_safe(device, next, &fs_devices->devices, dev_list) { - if (device->in_fs_metadata) { - if (!device->is_tgtdev_for_dev_replace && - (!latest_dev || - device->generation > latest_dev->generation)) { - latest_dev = device; - } - continue; - } - - if (device->devid == BTRFS_DEV_REPLACE_DEVID) { - /* - * In the first step, keep the device which has - * the correct fsid and the devid that is used - * for the dev_replace procedure. - * In the second step, the dev_replace state is - * read from the device tree and it is known - * whether the procedure is really active or - * not, which means whether this device is - * used or whether it should be removed. - */ - if (step == 0 || device->is_tgtdev_for_dev_replace) { - continue; - } - } - if (device->bdev) { - blkdev_put(device->bdev, device->mode); - device->bdev = NULL; - fs_devices->open_devices--; - } - if (device->writeable) { - list_del_init(&device->dev_alloc_list); - device->writeable = 0; - if (!device->is_tgtdev_for_dev_replace) - fs_devices->rw_devices--; - } - list_del_init(&device->dev_list); - fs_devices->num_devices--; - rcu_string_free(device->name); - kfree(device); - } - - if (fs_devices->seed) { - fs_devices = fs_devices->seed; - goto again; - } - - fs_devices->latest_bdev = latest_dev->bdev; - - mutex_unlock(&uuid_mutex); -} - -static void __free_device(struct work_struct *work) -{ - struct btrfs_device *device; - - device = container_of(work, struct btrfs_device, rcu_work); - rcu_string_free(device->name); - kfree(device); -} - -static void free_device(struct rcu_head *head) -{ - struct btrfs_device *device; - - device = container_of(head, struct btrfs_device, rcu); - - INIT_WORK(&device->rcu_work, __free_device); - schedule_work(&device->rcu_work); -} - -static void btrfs_close_bdev(struct btrfs_device *device) -{ - if (device->bdev && device->writeable) { - sync_blockdev(device->bdev); - invalidate_bdev(device->bdev); - } - - if (device->bdev) - blkdev_put(device->bdev, device->mode); -} - -static void btrfs_prepare_close_one_device(struct btrfs_device *device) -{ - struct btrfs_fs_devices *fs_devices = device->fs_devices; - struct btrfs_device *new_device; - struct rcu_string *name; - - if (device->bdev) - fs_devices->open_devices--; - - if (device->writeable && - device->devid != BTRFS_DEV_REPLACE_DEVID) { - list_del_init(&device->dev_alloc_list); - fs_devices->rw_devices--; - } - - if (device->missing) - fs_devices->missing_devices--; - - new_device = btrfs_alloc_device(NULL, &device->devid, - device->uuid); - BUG_ON(IS_ERR(new_device)); /* -ENOMEM */ - - /* Safe because we are under uuid_mutex */ - if (device->name) { - name = rcu_string_strdup(device->name->str, GFP_NOFS); - BUG_ON(!name); /* -ENOMEM */ - rcu_assign_pointer(new_device->name, name); - } - - list_replace_rcu(&device->dev_list, &new_device->dev_list); - new_device->fs_devices = device->fs_devices; -} - -static int __btrfs_close_devices(struct btrfs_fs_devices *fs_devices) -{ - struct btrfs_device *device, *tmp; - struct list_head pending_put; - - INIT_LIST_HEAD(&pending_put); - - if (--fs_devices->opened > 0) - return 0; - - mutex_lock(&fs_devices->device_list_mutex); - list_for_each_entry_safe(device, tmp, &fs_devices->devices, dev_list) { - btrfs_prepare_close_one_device(device); - list_add(&device->dev_list, &pending_put); - } - mutex_unlock(&fs_devices->device_list_mutex); - - /* - * btrfs_show_devname() is using the device_list_mutex, - * sometimes call to blkdev_put() leads vfs calling - * into this func. So do put outside of device_list_mutex, - * as of now. - */ - while (!list_empty(&pending_put)) { - device = list_first_entry(&pending_put, - struct btrfs_device, dev_list); - list_del(&device->dev_list); - btrfs_close_bdev(device); - call_rcu(&device->rcu, free_device); - } - - WARN_ON(fs_devices->open_devices); - WARN_ON(fs_devices->rw_devices); - fs_devices->opened = 0; - fs_devices->seeding = 0; - - return 0; -} - -int btrfs_close_devices(struct btrfs_fs_devices *fs_devices) -{ - struct btrfs_fs_devices *seed_devices = NULL; - int ret; - - mutex_lock(&uuid_mutex); - ret = __btrfs_close_devices(fs_devices); - if (!fs_devices->opened) { - seed_devices = fs_devices->seed; - fs_devices->seed = NULL; - } - mutex_unlock(&uuid_mutex); - - while (seed_devices) { - fs_devices = seed_devices; - seed_devices = fs_devices->seed; - __btrfs_close_devices(fs_devices); - free_fs_devices(fs_devices); - } - /* - * Wait for rcu kworkers under __btrfs_close_devices - * to finish all blkdev_puts so device is really - * free when umount is done. - */ - rcu_barrier(); - return ret; -} - -static int __btrfs_open_devices(struct btrfs_fs_devices *fs_devices, - fmode_t flags, void *holder) -{ - struct request_queue *q; - struct block_device *bdev; - struct list_head *head = &fs_devices->devices; - struct btrfs_device *device; - struct btrfs_device *latest_dev = NULL; - struct buffer_head *bh; - struct btrfs_super_block *disk_super; - u64 devid; - int seeding = 1; - int ret = 0; - - flags |= FMODE_EXCL; - - list_for_each_entry(device, head, dev_list) { - if (device->bdev) - continue; - if (!device->name) - continue; - - /* Just open everything we can; ignore failures here */ - if (btrfs_get_bdev_and_sb(device->name->str, flags, holder, 1, - &bdev, &bh)) - continue; - - disk_super = (struct btrfs_super_block *)bh->b_data; - devid = btrfs_stack_device_id(&disk_super->dev_item); - if (devid != device->devid) - goto error_brelse; - - if (memcmp(device->uuid, disk_super->dev_item.uuid, - BTRFS_UUID_SIZE)) - goto error_brelse; - - device->generation = btrfs_super_generation(disk_super); - if (!latest_dev || - device->generation > latest_dev->generation) - latest_dev = device; - - if (btrfs_super_flags(disk_super) & BTRFS_SUPER_FLAG_SEEDING) { - device->writeable = 0; - } else { - device->writeable = !bdev_read_only(bdev); - seeding = 0; - } - - q = bdev_get_queue(bdev); - if (blk_queue_discard(q)) - device->can_discard = 1; - - device->bdev = bdev; - device->in_fs_metadata = 0; - device->mode = flags; - - if (!blk_queue_nonrot(bdev_get_queue(bdev))) - fs_devices->rotating = 1; - - fs_devices->open_devices++; - if (device->writeable && - device->devid != BTRFS_DEV_REPLACE_DEVID) { - fs_devices->rw_devices++; - list_add(&device->dev_alloc_list, - &fs_devices->alloc_list); - } - brelse(bh); - continue; - -error_brelse: - brelse(bh); - blkdev_put(bdev, flags); - continue; - } - if (fs_devices->open_devices == 0) { - ret = -EINVAL; - goto out; - } - fs_devices->seeding = seeding; - fs_devices->opened = 1; - fs_devices->latest_bdev = latest_dev->bdev; - fs_devices->total_rw_bytes = 0; -out: - return ret; -} - -int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, - fmode_t flags, void *holder) -{ - int ret; - - mutex_lock(&uuid_mutex); - if (fs_devices->opened) { - fs_devices->opened++; - ret = 0; - } else { - ret = __btrfs_open_devices(fs_devices, flags, holder); - } - mutex_unlock(&uuid_mutex); - return ret; -} - -void btrfs_release_disk_super(struct page *page) -{ - kunmap(page); - put_page(page); -} - -int btrfs_read_disk_super(struct block_device *bdev, u64 bytenr, - struct page **page, struct btrfs_super_block **disk_super) -{ - void *p; - pgoff_t index; - - /* make sure our super fits in the device */ - if (bytenr + PAGE_SIZE >= i_size_read(bdev->bd_inode)) - return 1; - - /* make sure our super fits in the page */ - if (sizeof(**disk_super) > PAGE_SIZE) - return 1; - - /* make sure our super doesn't straddle pages on disk */ - index = bytenr >> PAGE_SHIFT; - if ((bytenr + sizeof(**disk_super) - 1) >> PAGE_SHIFT != index) - return 1; - - /* pull in the page with our super */ - *page = read_cache_page_gfp(bdev->bd_inode->i_mapping, - index, GFP_KERNEL); - - if (IS_ERR_OR_NULL(*page)) - return 1; - - p = kmap(*page); - - /* align our pointer to the offset of the super block */ - *disk_super = p + (bytenr & ~PAGE_MASK); - - if (btrfs_super_bytenr(*disk_super) != bytenr || - btrfs_super_magic(*disk_super) != BTRFS_MAGIC) { - btrfs_release_disk_super(*page); - return 1; - } - - if ((*disk_super)->label[0] && - (*disk_super)->label[BTRFS_LABEL_SIZE - 1]) - (*disk_super)->label[BTRFS_LABEL_SIZE - 1] = '\0'; - - return 0; -} - -/* - * Look for a btrfs signature on a device. This may be called out of the mount path - * and we are not allowed to call set_blocksize during the scan. The superblock - * is read via pagecache - */ -int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, - struct btrfs_fs_devices **fs_devices_ret) -{ - struct btrfs_super_block *disk_super; - struct block_device *bdev; - struct page *page; - int ret = -EINVAL; - u64 devid; - u64 transid; - u64 total_devices; - u64 bytenr; - - /* - * we would like to check all the supers, but that would make - * a btrfs mount succeed after a mkfs from a different FS. - * So, we need to add a special mount option to scan for - * later supers, using BTRFS_SUPER_MIRROR_MAX instead - */ - bytenr = btrfs_sb_offset(0); - flags |= FMODE_EXCL; - mutex_lock(&uuid_mutex); - - bdev = blkdev_get_by_path(path, flags, holder); - if (IS_ERR(bdev)) { - ret = PTR_ERR(bdev); - goto error; - } - - if (btrfs_read_disk_super(bdev, bytenr, &page, &disk_super)) - goto error_bdev_put; - - devid = btrfs_stack_device_id(&disk_super->dev_item); - transid = btrfs_super_generation(disk_super); - total_devices = btrfs_super_num_devices(disk_super); - - ret = device_list_add(path, disk_super, devid, fs_devices_ret); - if (ret > 0) { - if (disk_super->label[0]) { - pr_info("BTRFS: device label %s ", disk_super->label); - } else { - pr_info("BTRFS: device fsid %pU ", disk_super->fsid); - } - - pr_cont("devid %llu transid %llu %s\n", devid, transid, path); - ret = 0; - } - if (!ret && fs_devices_ret) - (*fs_devices_ret)->total_devices = total_devices; - - btrfs_release_disk_super(page); - -error_bdev_put: - blkdev_put(bdev, flags); -error: - mutex_unlock(&uuid_mutex); - return ret; -} - -/* helper to account the used device space in the range */ -int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, - u64 end, u64 *length) -{ - struct btrfs_key key; - struct btrfs_root *root = device->dev_root; - struct btrfs_dev_extent *dev_extent; - struct btrfs_path *path; - u64 extent_end; - int ret; - int slot; - struct extent_buffer *l; - - *length = 0; - - if (start >= device->total_bytes || device->is_tgtdev_for_dev_replace) - return 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->reada = READA_FORWARD; - - key.objectid = device->devid; - key.offset = start; - key.type = BTRFS_DEV_EXTENT_KEY; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out; - if (ret > 0) { - ret = btrfs_previous_item(root, path, key.objectid, key.type); - if (ret < 0) - goto out; - } - - while (1) { - l = path->nodes[0]; - slot = path->slots[0]; - if (slot >= btrfs_header_nritems(l)) { - ret = btrfs_next_leaf(root, path); - if (ret == 0) - continue; - if (ret < 0) - goto out; - - break; - } - btrfs_item_key_to_cpu(l, &key, slot); - - if (key.objectid < device->devid) - goto next; - - if (key.objectid > device->devid) - break; - - if (key.type != BTRFS_DEV_EXTENT_KEY) - goto next; - - dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent); - extent_end = key.offset + btrfs_dev_extent_length(l, - dev_extent); - if (key.offset <= start && extent_end > end) { - *length = end - start + 1; - break; - } else if (key.offset <= start && extent_end > start) - *length += extent_end - start; - else if (key.offset > start && extent_end <= end) - *length += extent_end - key.offset; - else if (key.offset > start && key.offset <= end) { - *length += end - key.offset + 1; - break; - } else if (key.offset > end) - break; - -next: - path->slots[0]++; - } - ret = 0; -out: - btrfs_free_path(path); - return ret; -} - -static int contains_pending_extent(struct btrfs_transaction *transaction, - struct btrfs_device *device, - u64 *start, u64 len) -{ - struct btrfs_fs_info *fs_info = device->dev_root->fs_info; - struct extent_map *em; - struct list_head *search_list = &fs_info->pinned_chunks; - int ret = 0; - u64 physical_start = *start; - - if (transaction) - search_list = &transaction->pending_chunks; -again: - list_for_each_entry(em, search_list, list) { - struct map_lookup *map; - int i; - - map = em->map_lookup; - for (i = 0; i < map->num_stripes; i++) { - u64 end; - - if (map->stripes[i].dev != device) - continue; - if (map->stripes[i].physical >= physical_start + len || - map->stripes[i].physical + em->orig_block_len <= - physical_start) - continue; - /* - * Make sure that while processing the pinned list we do - * not override our *start with a lower value, because - * we can have pinned chunks that fall within this - * device hole and that have lower physical addresses - * than the pending chunks we processed before. If we - * do not take this special care we can end up getting - * 2 pending chunks that start at the same physical - * device offsets because the end offset of a pinned - * chunk can be equal to the start offset of some - * pending chunk. - */ - end = map->stripes[i].physical + em->orig_block_len; - if (end > *start) { - *start = end; - ret = 1; - } - } - } - if (search_list != &fs_info->pinned_chunks) { - search_list = &fs_info->pinned_chunks; - goto again; - } - - return ret; -} - - -/* - * find_free_dev_extent_start - find free space in the specified device - * @device: the device which we search the free space in - * @num_bytes: the size of the free space that we need - * @search_start: the position from which to begin the search - * @start: store the start of the free space. - * @len: the size of the free space. that we find, or the size - * of the max free space if we don't find suitable free space - * - * this uses a pretty simple search, the expectation is that it is - * called very infrequently and that a given device has a small number - * of extents - * - * @start is used to store the start of the free space if we find. But if we - * don't find suitable free space, it will be used to store the start position - * of the max free space. - * - * @len is used to store the size of the free space that we find. - * But if we don't find suitable free space, it is used to store the size of - * the max free space. - */ -int find_free_dev_extent_start(struct btrfs_transaction *transaction, - struct btrfs_device *device, u64 num_bytes, - u64 search_start, u64 *start, u64 *len) -{ - struct btrfs_key key; - struct btrfs_root *root = device->dev_root; - struct btrfs_dev_extent *dev_extent; - struct btrfs_path *path; - u64 hole_size; - u64 max_hole_start; - u64 max_hole_size; - u64 extent_end; - u64 search_end = device->total_bytes; - int ret; - int slot; - struct extent_buffer *l; - u64 min_search_start; - - /* - * We don't want to overwrite the superblock on the drive nor any area - * used by the boot loader (grub for example), so we make sure to start - * at an offset of at least 1MB. - */ - min_search_start = max(root->fs_info->alloc_start, 1024ull * 1024); - search_start = max(search_start, min_search_start); - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - max_hole_start = search_start; - max_hole_size = 0; - -again: - if (search_start >= search_end || device->is_tgtdev_for_dev_replace) { - ret = -ENOSPC; - goto out; - } - - path->reada = READA_FORWARD; - path->search_commit_root = 1; - path->skip_locking = 1; - - key.objectid = device->devid; - key.offset = search_start; - key.type = BTRFS_DEV_EXTENT_KEY; - - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto out; - if (ret > 0) { - ret = btrfs_previous_item(root, path, key.objectid, key.type); - if (ret < 0) - goto out; - } - - while (1) { - l = path->nodes[0]; - slot = path->slots[0]; - if (slot >= btrfs_header_nritems(l)) { - ret = btrfs_next_leaf(root, path); - if (ret == 0) - continue; - if (ret < 0) - goto out; - - break; - } - btrfs_item_key_to_cpu(l, &key, slot); - - if (key.objectid < device->devid) - goto next; - - if (key.objectid > device->devid) - break; - - if (key.type != BTRFS_DEV_EXTENT_KEY) - goto next; - - if (key.offset > search_start) { - hole_size = key.offset - search_start; - - /* - * Have to check before we set max_hole_start, otherwise - * we could end up sending back this offset anyway. - */ - if (contains_pending_extent(transaction, device, - &search_start, - hole_size)) { - if (key.offset >= search_start) { - hole_size = key.offset - search_start; - } else { - WARN_ON_ONCE(1); - hole_size = 0; - } - } - - if (hole_size > max_hole_size) { - max_hole_start = search_start; - max_hole_size = hole_size; - } - - /* - * If this free space is greater than which we need, - * it must be the max free space that we have found - * until now, so max_hole_start must point to the start - * of this free space and the length of this free space - * is stored in max_hole_size. Thus, we return - * max_hole_start and max_hole_size and go back to the - * caller. - */ - if (hole_size >= num_bytes) { - ret = 0; - goto out; - } - } - - dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent); - extent_end = key.offset + btrfs_dev_extent_length(l, - dev_extent); - if (extent_end > search_start) - search_start = extent_end; -next: - path->slots[0]++; - cond_resched(); - } - - /* - * At this point, search_start should be the end of - * allocated dev extents, and when shrinking the device, - * search_end may be smaller than search_start. - */ - if (search_end > search_start) { - hole_size = search_end - search_start; - - if (contains_pending_extent(transaction, device, &search_start, - hole_size)) { - btrfs_release_path(path); - goto again; - } - - if (hole_size > max_hole_size) { - max_hole_start = search_start; - max_hole_size = hole_size; - } - } - - /* See above. */ - if (max_hole_size < num_bytes) - ret = -ENOSPC; - else - ret = 0; - -out: - btrfs_free_path(path); - *start = max_hole_start; - if (len) - *len = max_hole_size; - return ret; -} - -int find_free_dev_extent(struct btrfs_trans_handle *trans, - struct btrfs_device *device, u64 num_bytes, - u64 *start, u64 *len) -{ - /* FIXME use last free of some kind */ - return find_free_dev_extent_start(trans->transaction, device, - num_bytes, 0, start, len); -} - -static int btrfs_free_dev_extent(struct btrfs_trans_handle *trans, - struct btrfs_device *device, - u64 start, u64 *dev_extent_len) -{ - int ret; - struct btrfs_path *path; - struct btrfs_root *root = device->dev_root; - struct btrfs_key key; - struct btrfs_key found_key; - struct extent_buffer *leaf = NULL; - struct btrfs_dev_extent *extent = NULL; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - key.objectid = device->devid; - key.offset = start; - key.type = BTRFS_DEV_EXTENT_KEY; -again: - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret > 0) { - ret = btrfs_previous_item(root, path, key.objectid, - BTRFS_DEV_EXTENT_KEY); - if (ret) - goto out; - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - extent = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_dev_extent); - BUG_ON(found_key.offset > start || found_key.offset + - btrfs_dev_extent_length(leaf, extent) < start); - key = found_key; - btrfs_release_path(path); - goto again; - } else if (ret == 0) { - leaf = path->nodes[0]; - extent = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_dev_extent); - } else { - btrfs_handle_fs_error(root->fs_info, ret, "Slot search failed"); - goto out; - } - - *dev_extent_len = btrfs_dev_extent_length(leaf, extent); - - ret = btrfs_del_item(trans, root, path); - if (ret) { - btrfs_handle_fs_error(root->fs_info, ret, - "Failed to remove dev extent item"); - } else { - set_bit(BTRFS_TRANS_HAVE_FREE_BGS, &trans->transaction->flags); - } -out: - btrfs_free_path(path); - return ret; -} - -static int btrfs_alloc_dev_extent(struct btrfs_trans_handle *trans, - struct btrfs_device *device, - u64 chunk_tree, u64 chunk_objectid, - u64 chunk_offset, u64 start, u64 num_bytes) -{ - int ret; - struct btrfs_path *path; - struct btrfs_root *root = device->dev_root; - struct btrfs_dev_extent *extent; - struct extent_buffer *leaf; - struct btrfs_key key; - - WARN_ON(!device->in_fs_metadata); - WARN_ON(device->is_tgtdev_for_dev_replace); - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - key.objectid = device->devid; - key.offset = start; - key.type = BTRFS_DEV_EXTENT_KEY; - ret = btrfs_insert_empty_item(trans, root, path, &key, - sizeof(*extent)); - if (ret) - goto out; - - leaf = path->nodes[0]; - extent = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_dev_extent); - btrfs_set_dev_extent_chunk_tree(leaf, extent, chunk_tree); - btrfs_set_dev_extent_chunk_objectid(leaf, extent, chunk_objectid); - btrfs_set_dev_extent_chunk_offset(leaf, extent, chunk_offset); - - write_extent_buffer(leaf, root->fs_info->chunk_tree_uuid, - btrfs_dev_extent_chunk_tree_uuid(extent), BTRFS_UUID_SIZE); - - btrfs_set_dev_extent_length(leaf, extent, num_bytes); - btrfs_mark_buffer_dirty(leaf); -out: - btrfs_free_path(path); - return ret; -} - -static u64 find_next_chunk(struct btrfs_fs_info *fs_info) -{ - struct extent_map_tree *em_tree; - struct extent_map *em; - struct rb_node *n; - u64 ret = 0; - - em_tree = &fs_info->mapping_tree.map_tree; - read_lock(&em_tree->lock); - n = rb_last(&em_tree->map); - if (n) { - em = rb_entry(n, struct extent_map, rb_node); - ret = em->start + em->len; - } - read_unlock(&em_tree->lock); - - return ret; -} - -static noinline int find_next_devid(struct btrfs_fs_info *fs_info, - u64 *devid_ret) -{ - int ret; - struct btrfs_key key; - struct btrfs_key found_key; - struct btrfs_path *path; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - key.objectid = BTRFS_DEV_ITEMS_OBJECTID; - key.type = BTRFS_DEV_ITEM_KEY; - key.offset = (u64)-1; - - ret = btrfs_search_slot(NULL, fs_info->chunk_root, &key, path, 0, 0); - if (ret < 0) - goto error; - - BUG_ON(ret == 0); /* Corruption */ - - ret = btrfs_previous_item(fs_info->chunk_root, path, - BTRFS_DEV_ITEMS_OBJECTID, - BTRFS_DEV_ITEM_KEY); - if (ret) { - *devid_ret = 1; - } else { - btrfs_item_key_to_cpu(path->nodes[0], &found_key, - path->slots[0]); - *devid_ret = found_key.offset + 1; - } - ret = 0; -error: - btrfs_free_path(path); - return ret; -} - -/* - * the device information is stored in the chunk root - * the btrfs_device struct should be fully filled in - */ -static int btrfs_add_device(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_device *device) -{ - int ret; - struct btrfs_path *path; - struct btrfs_dev_item *dev_item; - struct extent_buffer *leaf; - struct btrfs_key key; - unsigned long ptr; - - root = root->fs_info->chunk_root; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - key.objectid = BTRFS_DEV_ITEMS_OBJECTID; - key.type = BTRFS_DEV_ITEM_KEY; - key.offset = device->devid; - - ret = btrfs_insert_empty_item(trans, root, path, &key, - sizeof(*dev_item)); - if (ret) - goto out; - - leaf = path->nodes[0]; - dev_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dev_item); - - btrfs_set_device_id(leaf, dev_item, device->devid); - btrfs_set_device_generation(leaf, dev_item, 0); - btrfs_set_device_type(leaf, dev_item, device->type); - btrfs_set_device_io_align(leaf, dev_item, device->io_align); - btrfs_set_device_io_width(leaf, dev_item, device->io_width); - btrfs_set_device_sector_size(leaf, dev_item, device->sector_size); - btrfs_set_device_total_bytes(leaf, dev_item, - btrfs_device_get_disk_total_bytes(device)); - btrfs_set_device_bytes_used(leaf, dev_item, - btrfs_device_get_bytes_used(device)); - btrfs_set_device_group(leaf, dev_item, 0); - btrfs_set_device_seek_speed(leaf, dev_item, 0); - btrfs_set_device_bandwidth(leaf, dev_item, 0); - btrfs_set_device_start_offset(leaf, dev_item, 0); - - ptr = btrfs_device_uuid(dev_item); - write_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE); - ptr = btrfs_device_fsid(dev_item); - write_extent_buffer(leaf, root->fs_info->fsid, ptr, BTRFS_UUID_SIZE); - btrfs_mark_buffer_dirty(leaf); - - ret = 0; -out: - btrfs_free_path(path); - return ret; -} - -/* - * Function to update ctime/mtime for a given device path. - * Mainly used for ctime/mtime based probe like libblkid. - */ -static void update_dev_time(char *path_name) -{ - struct file *filp; - - filp = filp_open(path_name, O_RDWR, 0); - if (IS_ERR(filp)) - return; - file_update_time(filp); - filp_close(filp, NULL); -} - -static int btrfs_rm_dev_item(struct btrfs_root *root, - struct btrfs_device *device) -{ - int ret; - struct btrfs_path *path; - struct btrfs_key key; - struct btrfs_trans_handle *trans; - - root = root->fs_info->chunk_root; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) { - btrfs_free_path(path); - return PTR_ERR(trans); - } - key.objectid = BTRFS_DEV_ITEMS_OBJECTID; - key.type = BTRFS_DEV_ITEM_KEY; - key.offset = device->devid; - - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret < 0) - goto out; - - if (ret > 0) { - ret = -ENOENT; - goto out; - } - - ret = btrfs_del_item(trans, root, path); - if (ret) - goto out; -out: - btrfs_free_path(path); - btrfs_commit_transaction(trans, root); - return ret; -} - -/* - * Verify that @num_devices satisfies the RAID profile constraints in the whole - * filesystem. It's up to the caller to adjust that number regarding eg. device - * replace. - */ -static int btrfs_check_raid_min_devices(struct btrfs_fs_info *fs_info, - u64 num_devices) -{ - u64 all_avail; - unsigned seq; - int i; - - do { - seq = read_seqbegin(&fs_info->profiles_lock); - - all_avail = fs_info->avail_data_alloc_bits | - fs_info->avail_system_alloc_bits | - fs_info->avail_metadata_alloc_bits; - } while (read_seqretry(&fs_info->profiles_lock, seq)); - - for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) { - if (!(all_avail & btrfs_raid_group[i])) - continue; - - if (num_devices < btrfs_raid_array[i].devs_min) { - int ret = btrfs_raid_mindev_error[i]; - - if (ret) - return ret; - } - } - - return 0; -} - -struct btrfs_device *btrfs_find_next_active_device(struct btrfs_fs_devices *fs_devs, - struct btrfs_device *device) -{ - struct btrfs_device *next_device; - - list_for_each_entry(next_device, &fs_devs->devices, dev_list) { - if (next_device != device && - !next_device->missing && next_device->bdev) - return next_device; - } - - return NULL; -} - -/* - * Helper function to check if the given device is part of s_bdev / latest_bdev - * and replace it with the provided or the next active device, in the context - * where this function called, there should be always be another device (or - * this_dev) which is active. - */ -void btrfs_assign_next_active_device(struct btrfs_fs_info *fs_info, - struct btrfs_device *device, struct btrfs_device *this_dev) -{ - struct btrfs_device *next_device; - - if (this_dev) - next_device = this_dev; - else - next_device = btrfs_find_next_active_device(fs_info->fs_devices, - device); - ASSERT(next_device); - - if (fs_info->sb->s_bdev && - (fs_info->sb->s_bdev == device->bdev)) - fs_info->sb->s_bdev = next_device->bdev; - - if (fs_info->fs_devices->latest_bdev == device->bdev) - fs_info->fs_devices->latest_bdev = next_device->bdev; -} - -int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid) -{ - struct btrfs_device *device; - struct btrfs_fs_devices *cur_devices; - u64 num_devices; - int ret = 0; - bool clear_super = false; - - mutex_lock(&uuid_mutex); - - num_devices = root->fs_info->fs_devices->num_devices; - btrfs_dev_replace_lock(&root->fs_info->dev_replace, 0); - if (btrfs_dev_replace_is_ongoing(&root->fs_info->dev_replace)) { - WARN_ON(num_devices < 1); - num_devices--; - } - btrfs_dev_replace_unlock(&root->fs_info->dev_replace, 0); - - ret = btrfs_check_raid_min_devices(root->fs_info, num_devices - 1); - if (ret) - goto out; - - ret = btrfs_find_device_by_devspec(root, devid, device_path, - &device); - if (ret) - goto out; - - if (device->is_tgtdev_for_dev_replace) { - ret = BTRFS_ERROR_DEV_TGT_REPLACE; - goto out; - } - - if (device->writeable && root->fs_info->fs_devices->rw_devices == 1) { - ret = BTRFS_ERROR_DEV_ONLY_WRITABLE; - goto out; - } - - if (device->writeable) { - lock_chunks(root); - list_del_init(&device->dev_alloc_list); - device->fs_devices->rw_devices--; - unlock_chunks(root); - clear_super = true; - } - - mutex_unlock(&uuid_mutex); - ret = btrfs_shrink_device(device, 0); - mutex_lock(&uuid_mutex); - if (ret) - goto error_undo; - - /* - * TODO: the superblock still includes this device in its num_devices - * counter although write_all_supers() is not locked out. This - * could give a filesystem state which requires a degraded mount. - */ - ret = btrfs_rm_dev_item(root->fs_info->chunk_root, device); - if (ret) - goto error_undo; - - device->in_fs_metadata = 0; - btrfs_scrub_cancel_dev(root->fs_info, device); - - /* - * the device list mutex makes sure that we don't change - * the device list while someone else is writing out all - * the device supers. Whoever is writing all supers, should - * lock the device list mutex before getting the number of - * devices in the super block (super_copy). Conversely, - * whoever updates the number of devices in the super block - * (super_copy) should hold the device list mutex. - */ - - cur_devices = device->fs_devices; - mutex_lock(&root->fs_info->fs_devices->device_list_mutex); - list_del_rcu(&device->dev_list); - - device->fs_devices->num_devices--; - device->fs_devices->total_devices--; - - if (device->missing) - device->fs_devices->missing_devices--; - - btrfs_assign_next_active_device(root->fs_info, device, NULL); - - if (device->bdev) { - device->fs_devices->open_devices--; - /* remove sysfs entry */ - btrfs_sysfs_rm_device_link(root->fs_info->fs_devices, device); - } - - num_devices = btrfs_super_num_devices(root->fs_info->super_copy) - 1; - btrfs_set_super_num_devices(root->fs_info->super_copy, num_devices); - mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); - - /* - * at this point, the device is zero sized and detached from - * the devices list. All that's left is to zero out the old - * supers and free the device. - */ - if (device->writeable) - btrfs_scratch_superblocks(device->bdev, device->name->str); - - btrfs_close_bdev(device); - call_rcu(&device->rcu, free_device); - - if (cur_devices->open_devices == 0) { - struct btrfs_fs_devices *fs_devices; - fs_devices = root->fs_info->fs_devices; - while (fs_devices) { - if (fs_devices->seed == cur_devices) { - fs_devices->seed = cur_devices->seed; - break; - } - fs_devices = fs_devices->seed; - } - cur_devices->seed = NULL; - __btrfs_close_devices(cur_devices); - free_fs_devices(cur_devices); - } - - root->fs_info->num_tolerated_disk_barrier_failures = - btrfs_calc_num_tolerated_disk_barrier_failures(root->fs_info); - -out: - mutex_unlock(&uuid_mutex); - return ret; - -error_undo: - if (device->writeable) { - lock_chunks(root); - list_add(&device->dev_alloc_list, - &root->fs_info->fs_devices->alloc_list); - device->fs_devices->rw_devices++; - unlock_chunks(root); - } - goto out; -} - -void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_fs_info *fs_info, - struct btrfs_device *srcdev) -{ - struct btrfs_fs_devices *fs_devices; - - WARN_ON(!mutex_is_locked(&fs_info->fs_devices->device_list_mutex)); - - /* - * in case of fs with no seed, srcdev->fs_devices will point - * to fs_devices of fs_info. However when the dev being replaced is - * a seed dev it will point to the seed's local fs_devices. In short - * srcdev will have its correct fs_devices in both the cases. - */ - fs_devices = srcdev->fs_devices; - - list_del_rcu(&srcdev->dev_list); - list_del_rcu(&srcdev->dev_alloc_list); - fs_devices->num_devices--; - if (srcdev->missing) - fs_devices->missing_devices--; - - if (srcdev->writeable) - fs_devices->rw_devices--; - - if (srcdev->bdev) - fs_devices->open_devices--; -} - -void btrfs_rm_dev_replace_free_srcdev(struct btrfs_fs_info *fs_info, - struct btrfs_device *srcdev) -{ - struct btrfs_fs_devices *fs_devices = srcdev->fs_devices; - - if (srcdev->writeable) { - /* zero out the old super if it is writable */ - btrfs_scratch_superblocks(srcdev->bdev, srcdev->name->str); - } - - btrfs_close_bdev(srcdev); - - call_rcu(&srcdev->rcu, free_device); - - /* - * unless fs_devices is seed fs, num_devices shouldn't go - * zero - */ - BUG_ON(!fs_devices->num_devices && !fs_devices->seeding); - - /* if this is no devs we rather delete the fs_devices */ - if (!fs_devices->num_devices) { - struct btrfs_fs_devices *tmp_fs_devices; - - tmp_fs_devices = fs_info->fs_devices; - while (tmp_fs_devices) { - if (tmp_fs_devices->seed == fs_devices) { - tmp_fs_devices->seed = fs_devices->seed; - break; - } - tmp_fs_devices = tmp_fs_devices->seed; - } - fs_devices->seed = NULL; - __btrfs_close_devices(fs_devices); - free_fs_devices(fs_devices); - } -} - -void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, - struct btrfs_device *tgtdev) -{ - mutex_lock(&uuid_mutex); - WARN_ON(!tgtdev); - mutex_lock(&fs_info->fs_devices->device_list_mutex); - - btrfs_sysfs_rm_device_link(fs_info->fs_devices, tgtdev); - - if (tgtdev->bdev) - fs_info->fs_devices->open_devices--; - - fs_info->fs_devices->num_devices--; - - btrfs_assign_next_active_device(fs_info, tgtdev, NULL); - - list_del_rcu(&tgtdev->dev_list); - - mutex_unlock(&fs_info->fs_devices->device_list_mutex); - mutex_unlock(&uuid_mutex); - - /* - * The update_dev_time() with in btrfs_scratch_superblocks() - * may lead to a call to btrfs_show_devname() which will try - * to hold device_list_mutex. And here this device - * is already out of device list, so we don't have to hold - * the device_list_mutex lock. - */ - btrfs_scratch_superblocks(tgtdev->bdev, tgtdev->name->str); - - btrfs_close_bdev(tgtdev); - call_rcu(&tgtdev->rcu, free_device); -} - -static int btrfs_find_device_by_path(struct btrfs_root *root, char *device_path, - struct btrfs_device **device) -{ - int ret = 0; - struct btrfs_super_block *disk_super; - u64 devid; - u8 *dev_uuid; - struct block_device *bdev; - struct buffer_head *bh; - - *device = NULL; - ret = btrfs_get_bdev_and_sb(device_path, FMODE_READ, - root->fs_info->bdev_holder, 0, &bdev, &bh); - if (ret) - return ret; - disk_super = (struct btrfs_super_block *)bh->b_data; - devid = btrfs_stack_device_id(&disk_super->dev_item); - dev_uuid = disk_super->dev_item.uuid; - *device = btrfs_find_device(root->fs_info, devid, dev_uuid, - disk_super->fsid); - brelse(bh); - if (!*device) - ret = -ENOENT; - blkdev_put(bdev, FMODE_READ); - return ret; -} - -int btrfs_find_device_missing_or_by_path(struct btrfs_root *root, - char *device_path, - struct btrfs_device **device) -{ - *device = NULL; - if (strcmp(device_path, "missing") == 0) { - struct list_head *devices; - struct btrfs_device *tmp; - - devices = &root->fs_info->fs_devices->devices; - /* - * It is safe to read the devices since the volume_mutex - * is held by the caller. - */ - list_for_each_entry(tmp, devices, dev_list) { - if (tmp->in_fs_metadata && !tmp->bdev) { - *device = tmp; - break; - } - } - - if (!*device) - return BTRFS_ERROR_DEV_MISSING_NOT_FOUND; - - return 0; - } else { - return btrfs_find_device_by_path(root, device_path, device); - } -} - -/* - * Lookup a device given by device id, or the path if the id is 0. - */ -int btrfs_find_device_by_devspec(struct btrfs_root *root, u64 devid, - char *devpath, - struct btrfs_device **device) -{ - int ret; - - if (devid) { - ret = 0; - *device = btrfs_find_device(root->fs_info, devid, NULL, - NULL); - if (!*device) - ret = -ENOENT; - } else { - if (!devpath || !devpath[0]) - return -EINVAL; - - ret = btrfs_find_device_missing_or_by_path(root, devpath, - device); - } - return ret; -} - -/* - * does all the dirty work required for changing file system's UUID. - */ -static int btrfs_prepare_sprout(struct btrfs_root *root) -{ - struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; - struct btrfs_fs_devices *old_devices; - struct btrfs_fs_devices *seed_devices; - struct btrfs_super_block *disk_super = root->fs_info->super_copy; - struct btrfs_device *device; - u64 super_flags; - - BUG_ON(!mutex_is_locked(&uuid_mutex)); - if (!fs_devices->seeding) - return -EINVAL; - - seed_devices = __alloc_fs_devices(); - if (IS_ERR(seed_devices)) - return PTR_ERR(seed_devices); - - old_devices = clone_fs_devices(fs_devices); - if (IS_ERR(old_devices)) { - kfree(seed_devices); - return PTR_ERR(old_devices); - } - - list_add(&old_devices->list, &fs_uuids); - - memcpy(seed_devices, fs_devices, sizeof(*seed_devices)); - seed_devices->opened = 1; - INIT_LIST_HEAD(&seed_devices->devices); - INIT_LIST_HEAD(&seed_devices->alloc_list); - mutex_init(&seed_devices->device_list_mutex); - - mutex_lock(&root->fs_info->fs_devices->device_list_mutex); - list_splice_init_rcu(&fs_devices->devices, &seed_devices->devices, - synchronize_rcu); - list_for_each_entry(device, &seed_devices->devices, dev_list) - device->fs_devices = seed_devices; - - lock_chunks(root); - list_splice_init(&fs_devices->alloc_list, &seed_devices->alloc_list); - unlock_chunks(root); - - fs_devices->seeding = 0; - fs_devices->num_devices = 0; - fs_devices->open_devices = 0; - fs_devices->missing_devices = 0; - fs_devices->rotating = 0; - fs_devices->seed = seed_devices; - - generate_random_uuid(fs_devices->fsid); - memcpy(root->fs_info->fsid, fs_devices->fsid, BTRFS_FSID_SIZE); - memcpy(disk_super->fsid, fs_devices->fsid, BTRFS_FSID_SIZE); - mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); - - super_flags = btrfs_super_flags(disk_super) & - ~BTRFS_SUPER_FLAG_SEEDING; - btrfs_set_super_flags(disk_super, super_flags); - - return 0; -} - -/* - * Store the expected generation for seed devices in device items. - */ -static int btrfs_finish_sprout(struct btrfs_trans_handle *trans, - struct btrfs_root *root) -{ - struct btrfs_path *path; - struct extent_buffer *leaf; - struct btrfs_dev_item *dev_item; - struct btrfs_device *device; - struct btrfs_key key; - u8 fs_uuid[BTRFS_UUID_SIZE]; - u8 dev_uuid[BTRFS_UUID_SIZE]; - u64 devid; - int ret; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - root = root->fs_info->chunk_root; - key.objectid = BTRFS_DEV_ITEMS_OBJECTID; - key.offset = 0; - key.type = BTRFS_DEV_ITEM_KEY; - - while (1) { - ret = btrfs_search_slot(trans, root, &key, path, 0, 1); - if (ret < 0) - goto error; - - leaf = path->nodes[0]; -next_slot: - if (path->slots[0] >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(root, path); - if (ret > 0) - break; - if (ret < 0) - goto error; - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - btrfs_release_path(path); - continue; - } - - btrfs_item_key_to_cpu(leaf, &key, path->slots[0]); - if (key.objectid != BTRFS_DEV_ITEMS_OBJECTID || - key.type != BTRFS_DEV_ITEM_KEY) - break; - - dev_item = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_dev_item); - devid = btrfs_device_id(leaf, dev_item); - read_extent_buffer(leaf, dev_uuid, btrfs_device_uuid(dev_item), - BTRFS_UUID_SIZE); - read_extent_buffer(leaf, fs_uuid, btrfs_device_fsid(dev_item), - BTRFS_UUID_SIZE); - device = btrfs_find_device(root->fs_info, devid, dev_uuid, - fs_uuid); - BUG_ON(!device); /* Logic error */ - - if (device->fs_devices->seeding) { - btrfs_set_device_generation(leaf, dev_item, - device->generation); - btrfs_mark_buffer_dirty(leaf); - } - - path->slots[0]++; - goto next_slot; - } - ret = 0; -error: - btrfs_free_path(path); - return ret; -} - -int btrfs_init_new_device(struct btrfs_root *root, char *device_path) -{ - struct request_queue *q; - struct btrfs_trans_handle *trans; - struct btrfs_device *device; - struct block_device *bdev; - struct list_head *devices; - struct super_block *sb = root->fs_info->sb; - struct rcu_string *name; - u64 tmp; - int seeding_dev = 0; - int ret = 0; - - if ((sb->s_flags & MS_RDONLY) && !root->fs_info->fs_devices->seeding) - return -EROFS; - - bdev = blkdev_get_by_path(device_path, FMODE_WRITE | FMODE_EXCL, - root->fs_info->bdev_holder); - if (IS_ERR(bdev)) - return PTR_ERR(bdev); - - if (root->fs_info->fs_devices->seeding) { - seeding_dev = 1; - down_write(&sb->s_umount); - mutex_lock(&uuid_mutex); - } - - filemap_write_and_wait(bdev->bd_inode->i_mapping); - - devices = &root->fs_info->fs_devices->devices; - - mutex_lock(&root->fs_info->fs_devices->device_list_mutex); - list_for_each_entry(device, devices, dev_list) { - if (device->bdev == bdev) { - ret = -EEXIST; - mutex_unlock( - &root->fs_info->fs_devices->device_list_mutex); - goto error; - } - } - mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); - - device = btrfs_alloc_device(root->fs_info, NULL, NULL); - if (IS_ERR(device)) { - /* we can safely leave the fs_devices entry around */ - ret = PTR_ERR(device); - goto error; - } - - name = rcu_string_strdup(device_path, GFP_KERNEL); - if (!name) { - kfree(device); - ret = -ENOMEM; - goto error; - } - rcu_assign_pointer(device->name, name); - - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) { - rcu_string_free(device->name); - kfree(device); - ret = PTR_ERR(trans); - goto error; - } - - q = bdev_get_queue(bdev); - if (blk_queue_discard(q)) - device->can_discard = 1; - device->writeable = 1; - device->generation = trans->transid; - device->io_width = root->sectorsize; - device->io_align = root->sectorsize; - device->sector_size = root->sectorsize; - device->total_bytes = i_size_read(bdev->bd_inode); - device->disk_total_bytes = device->total_bytes; - device->commit_total_bytes = device->total_bytes; - device->dev_root = root->fs_info->dev_root; - device->bdev = bdev; - device->in_fs_metadata = 1; - device->is_tgtdev_for_dev_replace = 0; - device->mode = FMODE_EXCL; - device->dev_stats_valid = 1; - set_blocksize(device->bdev, 4096); - - if (seeding_dev) { - sb->s_flags &= ~MS_RDONLY; - ret = btrfs_prepare_sprout(root); - BUG_ON(ret); /* -ENOMEM */ - } - - device->fs_devices = root->fs_info->fs_devices; - - mutex_lock(&root->fs_info->fs_devices->device_list_mutex); - lock_chunks(root); - list_add_rcu(&device->dev_list, &root->fs_info->fs_devices->devices); - list_add(&device->dev_alloc_list, - &root->fs_info->fs_devices->alloc_list); - root->fs_info->fs_devices->num_devices++; - root->fs_info->fs_devices->open_devices++; - root->fs_info->fs_devices->rw_devices++; - root->fs_info->fs_devices->total_devices++; - root->fs_info->fs_devices->total_rw_bytes += device->total_bytes; - - spin_lock(&root->fs_info->free_chunk_lock); - root->fs_info->free_chunk_space += device->total_bytes; - spin_unlock(&root->fs_info->free_chunk_lock); - - if (!blk_queue_nonrot(bdev_get_queue(bdev))) - root->fs_info->fs_devices->rotating = 1; - - tmp = btrfs_super_total_bytes(root->fs_info->super_copy); - btrfs_set_super_total_bytes(root->fs_info->super_copy, - tmp + device->total_bytes); - - tmp = btrfs_super_num_devices(root->fs_info->super_copy); - btrfs_set_super_num_devices(root->fs_info->super_copy, - tmp + 1); - - /* add sysfs device entry */ - btrfs_sysfs_add_device_link(root->fs_info->fs_devices, device); - - /* - * we've got more storage, clear any full flags on the space - * infos - */ - btrfs_clear_space_info_full(root->fs_info); - - unlock_chunks(root); - mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); - - if (seeding_dev) { - lock_chunks(root); - ret = init_first_rw_device(trans, root, device); - unlock_chunks(root); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto error_trans; - } - } - - ret = btrfs_add_device(trans, root, device); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto error_trans; - } - - if (seeding_dev) { - char fsid_buf[BTRFS_UUID_UNPARSED_SIZE]; - - ret = btrfs_finish_sprout(trans, root); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto error_trans; - } - - /* Sprouting would change fsid of the mounted root, - * so rename the fsid on the sysfs - */ - snprintf(fsid_buf, BTRFS_UUID_UNPARSED_SIZE, "%pU", - root->fs_info->fsid); - if (kobject_rename(&root->fs_info->fs_devices->fsid_kobj, - fsid_buf)) - btrfs_warn(root->fs_info, - "sysfs: failed to create fsid for sprout"); - } - - root->fs_info->num_tolerated_disk_barrier_failures = - btrfs_calc_num_tolerated_disk_barrier_failures(root->fs_info); - ret = btrfs_commit_transaction(trans, root); - - if (seeding_dev) { - mutex_unlock(&uuid_mutex); - up_write(&sb->s_umount); - - if (ret) /* transaction commit */ - return ret; - - ret = btrfs_relocate_sys_chunks(root); - if (ret < 0) - btrfs_handle_fs_error(root->fs_info, ret, - "Failed to relocate sys chunks after device initialization. This can be fixed using the \"btrfs balance\" command."); - trans = btrfs_attach_transaction(root); - if (IS_ERR(trans)) { - if (PTR_ERR(trans) == -ENOENT) - return 0; - return PTR_ERR(trans); - } - ret = btrfs_commit_transaction(trans, root); - } - - /* Update ctime/mtime for libblkid */ - update_dev_time(device_path); - return ret; - -error_trans: - btrfs_end_transaction(trans, root); - rcu_string_free(device->name); - btrfs_sysfs_rm_device_link(root->fs_info->fs_devices, device); - kfree(device); -error: - blkdev_put(bdev, FMODE_EXCL); - if (seeding_dev) { - mutex_unlock(&uuid_mutex); - up_write(&sb->s_umount); - } - return ret; -} - -int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path, - struct btrfs_device *srcdev, - struct btrfs_device **device_out) -{ - struct request_queue *q; - struct btrfs_device *device; - struct block_device *bdev; - struct btrfs_fs_info *fs_info = root->fs_info; - struct list_head *devices; - struct rcu_string *name; - u64 devid = BTRFS_DEV_REPLACE_DEVID; - int ret = 0; - - *device_out = NULL; - if (fs_info->fs_devices->seeding) { - btrfs_err(fs_info, "the filesystem is a seed filesystem!"); - return -EINVAL; - } - - bdev = blkdev_get_by_path(device_path, FMODE_WRITE | FMODE_EXCL, - fs_info->bdev_holder); - if (IS_ERR(bdev)) { - btrfs_err(fs_info, "target device %s is invalid!", device_path); - return PTR_ERR(bdev); - } - - filemap_write_and_wait(bdev->bd_inode->i_mapping); - - devices = &fs_info->fs_devices->devices; - list_for_each_entry(device, devices, dev_list) { - if (device->bdev == bdev) { - btrfs_err(fs_info, - "target device is in the filesystem!"); - ret = -EEXIST; - goto error; - } - } - - - if (i_size_read(bdev->bd_inode) < - btrfs_device_get_total_bytes(srcdev)) { - btrfs_err(fs_info, - "target device is smaller than source device!"); - ret = -EINVAL; - goto error; - } - - - device = btrfs_alloc_device(NULL, &devid, NULL); - if (IS_ERR(device)) { - ret = PTR_ERR(device); - goto error; - } - - name = rcu_string_strdup(device_path, GFP_NOFS); - if (!name) { - kfree(device); - ret = -ENOMEM; - goto error; - } - rcu_assign_pointer(device->name, name); - - q = bdev_get_queue(bdev); - if (blk_queue_discard(q)) - device->can_discard = 1; - mutex_lock(&root->fs_info->fs_devices->device_list_mutex); - device->writeable = 1; - device->generation = 0; - device->io_width = root->sectorsize; - device->io_align = root->sectorsize; - device->sector_size = root->sectorsize; - device->total_bytes = btrfs_device_get_total_bytes(srcdev); - device->disk_total_bytes = btrfs_device_get_disk_total_bytes(srcdev); - device->bytes_used = btrfs_device_get_bytes_used(srcdev); - ASSERT(list_empty(&srcdev->resized_list)); - device->commit_total_bytes = srcdev->commit_total_bytes; - device->commit_bytes_used = device->bytes_used; - device->dev_root = fs_info->dev_root; - device->bdev = bdev; - device->in_fs_metadata = 1; - device->is_tgtdev_for_dev_replace = 1; - device->mode = FMODE_EXCL; - device->dev_stats_valid = 1; - set_blocksize(device->bdev, 4096); - device->fs_devices = fs_info->fs_devices; - list_add(&device->dev_list, &fs_info->fs_devices->devices); - fs_info->fs_devices->num_devices++; - fs_info->fs_devices->open_devices++; - mutex_unlock(&root->fs_info->fs_devices->device_list_mutex); - - *device_out = device; - return ret; - -error: - blkdev_put(bdev, FMODE_EXCL); - return ret; -} - -void btrfs_init_dev_replace_tgtdev_for_resume(struct btrfs_fs_info *fs_info, - struct btrfs_device *tgtdev) -{ - WARN_ON(fs_info->fs_devices->rw_devices == 0); - tgtdev->io_width = fs_info->dev_root->sectorsize; - tgtdev->io_align = fs_info->dev_root->sectorsize; - tgtdev->sector_size = fs_info->dev_root->sectorsize; - tgtdev->dev_root = fs_info->dev_root; - tgtdev->in_fs_metadata = 1; -} - -static noinline int btrfs_update_device(struct btrfs_trans_handle *trans, - struct btrfs_device *device) -{ - int ret; - struct btrfs_path *path; - struct btrfs_root *root; - struct btrfs_dev_item *dev_item; - struct extent_buffer *leaf; - struct btrfs_key key; - - root = device->dev_root->fs_info->chunk_root; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - key.objectid = BTRFS_DEV_ITEMS_OBJECTID; - key.type = BTRFS_DEV_ITEM_KEY; - key.offset = device->devid; - - ret = btrfs_search_slot(trans, root, &key, path, 0, 1); - if (ret < 0) - goto out; - - if (ret > 0) { - ret = -ENOENT; - goto out; - } - - leaf = path->nodes[0]; - dev_item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_dev_item); - - btrfs_set_device_id(leaf, dev_item, device->devid); - btrfs_set_device_type(leaf, dev_item, device->type); - btrfs_set_device_io_align(leaf, dev_item, device->io_align); - btrfs_set_device_io_width(leaf, dev_item, device->io_width); - btrfs_set_device_sector_size(leaf, dev_item, device->sector_size); - btrfs_set_device_total_bytes(leaf, dev_item, - btrfs_device_get_disk_total_bytes(device)); - btrfs_set_device_bytes_used(leaf, dev_item, - btrfs_device_get_bytes_used(device)); - btrfs_mark_buffer_dirty(leaf); - -out: - btrfs_free_path(path); - return ret; -} - -int btrfs_grow_device(struct btrfs_trans_handle *trans, - struct btrfs_device *device, u64 new_size) -{ - struct btrfs_super_block *super_copy = - device->dev_root->fs_info->super_copy; - struct btrfs_fs_devices *fs_devices; - u64 old_total; - u64 diff; - - if (!device->writeable) - return -EACCES; - - lock_chunks(device->dev_root); - old_total = btrfs_super_total_bytes(super_copy); - diff = new_size - device->total_bytes; - - if (new_size <= device->total_bytes || - device->is_tgtdev_for_dev_replace) { - unlock_chunks(device->dev_root); - return -EINVAL; - } - - fs_devices = device->dev_root->fs_info->fs_devices; - - btrfs_set_super_total_bytes(super_copy, old_total + diff); - device->fs_devices->total_rw_bytes += diff; - - btrfs_device_set_total_bytes(device, new_size); - btrfs_device_set_disk_total_bytes(device, new_size); - btrfs_clear_space_info_full(device->dev_root->fs_info); - if (list_empty(&device->resized_list)) - list_add_tail(&device->resized_list, - &fs_devices->resized_devices); - unlock_chunks(device->dev_root); - - return btrfs_update_device(trans, device); -} - -static int btrfs_free_chunk(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 chunk_objectid, - u64 chunk_offset) -{ - int ret; - struct btrfs_path *path; - struct btrfs_key key; - - root = root->fs_info->chunk_root; - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - key.objectid = chunk_objectid; - key.offset = chunk_offset; - key.type = BTRFS_CHUNK_ITEM_KEY; - - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret < 0) - goto out; - else if (ret > 0) { /* Logic error or corruption */ - btrfs_handle_fs_error(root->fs_info, -ENOENT, - "Failed lookup while freeing chunk."); - ret = -ENOENT; - goto out; - } - - ret = btrfs_del_item(trans, root, path); - if (ret < 0) - btrfs_handle_fs_error(root->fs_info, ret, - "Failed to delete chunk item."); -out: - btrfs_free_path(path); - return ret; -} - -static int btrfs_del_sys_chunk(struct btrfs_root *root, u64 chunk_objectid, u64 - chunk_offset) -{ - struct btrfs_super_block *super_copy = root->fs_info->super_copy; - struct btrfs_disk_key *disk_key; - struct btrfs_chunk *chunk; - u8 *ptr; - int ret = 0; - u32 num_stripes; - u32 array_size; - u32 len = 0; - u32 cur; - struct btrfs_key key; - - lock_chunks(root); - array_size = btrfs_super_sys_array_size(super_copy); - - ptr = super_copy->sys_chunk_array; - cur = 0; - - while (cur < array_size) { - disk_key = (struct btrfs_disk_key *)ptr; - btrfs_disk_key_to_cpu(&key, disk_key); - - len = sizeof(*disk_key); - - if (key.type == BTRFS_CHUNK_ITEM_KEY) { - chunk = (struct btrfs_chunk *)(ptr + len); - num_stripes = btrfs_stack_chunk_num_stripes(chunk); - len += btrfs_chunk_item_size(num_stripes); - } else { - ret = -EIO; - break; - } - if (key.objectid == chunk_objectid && - key.offset == chunk_offset) { - memmove(ptr, ptr + len, array_size - (cur + len)); - array_size -= len; - btrfs_set_super_sys_array_size(super_copy, array_size); - } else { - ptr += len; - cur += len; - } - } - unlock_chunks(root); - return ret; -} - -int btrfs_remove_chunk(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 chunk_offset) -{ - struct extent_map_tree *em_tree; - struct extent_map *em; - struct btrfs_root *extent_root = root->fs_info->extent_root; - struct map_lookup *map; - u64 dev_extent_len = 0; - u64 chunk_objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; - int i, ret = 0; - struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; - - /* Just in case */ - root = root->fs_info->chunk_root; - em_tree = &root->fs_info->mapping_tree.map_tree; - - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, chunk_offset, 1); - read_unlock(&em_tree->lock); - - if (!em || em->start > chunk_offset || - em->start + em->len < chunk_offset) { - /* - * This is a logic error, but we don't want to just rely on the - * user having built with ASSERT enabled, so if ASSERT doesn't - * do anything we still error out. - */ - ASSERT(0); - if (em) - free_extent_map(em); - return -EINVAL; - } - map = em->map_lookup; - lock_chunks(root->fs_info->chunk_root); - check_system_chunk(trans, extent_root, map->type); - unlock_chunks(root->fs_info->chunk_root); - - /* - * Take the device list mutex to prevent races with the final phase of - * a device replace operation that replaces the device object associated - * with map stripes (dev-replace.c:btrfs_dev_replace_finishing()). - */ - mutex_lock(&fs_devices->device_list_mutex); - for (i = 0; i < map->num_stripes; i++) { - struct btrfs_device *device = map->stripes[i].dev; - ret = btrfs_free_dev_extent(trans, device, - map->stripes[i].physical, - &dev_extent_len); - if (ret) { - mutex_unlock(&fs_devices->device_list_mutex); - btrfs_abort_transaction(trans, ret); - goto out; - } - - if (device->bytes_used > 0) { - lock_chunks(root); - btrfs_device_set_bytes_used(device, - device->bytes_used - dev_extent_len); - spin_lock(&root->fs_info->free_chunk_lock); - root->fs_info->free_chunk_space += dev_extent_len; - spin_unlock(&root->fs_info->free_chunk_lock); - btrfs_clear_space_info_full(root->fs_info); - unlock_chunks(root); - } - - if (map->stripes[i].dev) { - ret = btrfs_update_device(trans, map->stripes[i].dev); - if (ret) { - mutex_unlock(&fs_devices->device_list_mutex); - btrfs_abort_transaction(trans, ret); - goto out; - } - } - } - mutex_unlock(&fs_devices->device_list_mutex); - - ret = btrfs_free_chunk(trans, root, chunk_objectid, chunk_offset); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out; - } - - trace_btrfs_chunk_free(root, map, chunk_offset, em->len); - - if (map->type & BTRFS_BLOCK_GROUP_SYSTEM) { - ret = btrfs_del_sys_chunk(root, chunk_objectid, chunk_offset); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out; - } - } - - ret = btrfs_remove_block_group(trans, extent_root, chunk_offset, em); - if (ret) { - btrfs_abort_transaction(trans, ret); - goto out; - } - -out: - /* once for us */ - free_extent_map(em); - return ret; -} - -static int btrfs_relocate_chunk(struct btrfs_root *root, u64 chunk_offset) -{ - struct btrfs_root *extent_root; - struct btrfs_trans_handle *trans; - int ret; - - root = root->fs_info->chunk_root; - extent_root = root->fs_info->extent_root; - - /* - * Prevent races with automatic removal of unused block groups. - * After we relocate and before we remove the chunk with offset - * chunk_offset, automatic removal of the block group can kick in, - * resulting in a failure when calling btrfs_remove_chunk() below. - * - * Make sure to acquire this mutex before doing a tree search (dev - * or chunk trees) to find chunks. Otherwise the cleaner kthread might - * call btrfs_remove_chunk() (through btrfs_delete_unused_bgs()) after - * we release the path used to search the chunk/dev tree and before - * the current task acquires this mutex and calls us. - */ - ASSERT(mutex_is_locked(&root->fs_info->delete_unused_bgs_mutex)); - - ret = btrfs_can_relocate(extent_root, chunk_offset); - if (ret) - return -ENOSPC; - - /* step one, relocate all the extents inside this chunk */ - btrfs_scrub_pause(root); - ret = btrfs_relocate_block_group(extent_root, chunk_offset); - btrfs_scrub_continue(root); - if (ret) - return ret; - - trans = btrfs_start_trans_remove_block_group(root->fs_info, - chunk_offset); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - btrfs_handle_fs_error(root->fs_info, ret, NULL); - return ret; - } - - /* - * step two, delete the device extents and the - * chunk tree entries - */ - ret = btrfs_remove_chunk(trans, root, chunk_offset); - btrfs_end_transaction(trans, extent_root); - return ret; -} - -static int btrfs_relocate_sys_chunks(struct btrfs_root *root) -{ - struct btrfs_root *chunk_root = root->fs_info->chunk_root; - struct btrfs_path *path; - struct extent_buffer *leaf; - struct btrfs_chunk *chunk; - struct btrfs_key key; - struct btrfs_key found_key; - u64 chunk_type; - bool retried = false; - int failed = 0; - int ret; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - -again: - key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; - key.offset = (u64)-1; - key.type = BTRFS_CHUNK_ITEM_KEY; - - while (1) { - mutex_lock(&root->fs_info->delete_unused_bgs_mutex); - ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0); - if (ret < 0) { - mutex_unlock(&root->fs_info->delete_unused_bgs_mutex); - goto error; - } - BUG_ON(ret == 0); /* Corruption */ - - ret = btrfs_previous_item(chunk_root, path, key.objectid, - key.type); - if (ret) - mutex_unlock(&root->fs_info->delete_unused_bgs_mutex); - if (ret < 0) - goto error; - if (ret > 0) - break; - - leaf = path->nodes[0]; - btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); - - chunk = btrfs_item_ptr(leaf, path->slots[0], - struct btrfs_chunk); - chunk_type = btrfs_chunk_type(leaf, chunk); - btrfs_release_path(path); - - if (chunk_type & BTRFS_BLOCK_GROUP_SYSTEM) { - ret = btrfs_relocate_chunk(chunk_root, - found_key.offset); - if (ret == -ENOSPC) - failed++; - else - BUG_ON(ret); - } - mutex_unlock(&root->fs_info->delete_unused_bgs_mutex); - - if (found_key.offset == 0) - break; - key.offset = found_key.offset - 1; - } - ret = 0; - if (failed && !retried) { - failed = 0; - retried = true; - goto again; - } else if (WARN_ON(failed && retried)) { - ret = -ENOSPC; - } -error: - btrfs_free_path(path); - return ret; -} - -static int insert_balance_item(struct btrfs_root *root, - struct btrfs_balance_control *bctl) -{ - struct btrfs_trans_handle *trans; - struct btrfs_balance_item *item; - struct btrfs_disk_balance_args disk_bargs; - struct btrfs_path *path; - struct extent_buffer *leaf; - struct btrfs_key key; - int ret, err; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) { - btrfs_free_path(path); - return PTR_ERR(trans); - } - - key.objectid = BTRFS_BALANCE_OBJECTID; - key.type = BTRFS_TEMPORARY_ITEM_KEY; - key.offset = 0; - - ret = btrfs_insert_empty_item(trans, root, path, &key, - sizeof(*item)); - if (ret) - goto out; - - leaf = path->nodes[0]; - item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_balance_item); - - memset_extent_buffer(leaf, 0, (unsigned long)item, sizeof(*item)); - - btrfs_cpu_balance_args_to_disk(&disk_bargs, &bctl->data); - btrfs_set_balance_data(leaf, item, &disk_bargs); - btrfs_cpu_balance_args_to_disk(&disk_bargs, &bctl->meta); - btrfs_set_balance_meta(leaf, item, &disk_bargs); - btrfs_cpu_balance_args_to_disk(&disk_bargs, &bctl->sys); - btrfs_set_balance_sys(leaf, item, &disk_bargs); - - btrfs_set_balance_flags(leaf, item, bctl->flags); - - btrfs_mark_buffer_dirty(leaf); -out: - btrfs_free_path(path); - err = btrfs_commit_transaction(trans, root); - if (err && !ret) - ret = err; - return ret; -} - -static int del_balance_item(struct btrfs_root *root) -{ - struct btrfs_trans_handle *trans; - struct btrfs_path *path; - struct btrfs_key key; - int ret, err; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) { - btrfs_free_path(path); - return PTR_ERR(trans); - } - - key.objectid = BTRFS_BALANCE_OBJECTID; - key.type = BTRFS_TEMPORARY_ITEM_KEY; - key.offset = 0; - - ret = btrfs_search_slot(trans, root, &key, path, -1, 1); - if (ret < 0) - goto out; - if (ret > 0) { - ret = -ENOENT; - goto out; - } - - ret = btrfs_del_item(trans, root, path); -out: - btrfs_free_path(path); - err = btrfs_commit_transaction(trans, root); - if (err && !ret) - ret = err; - return ret; -} - -/* - * This is a heuristic used to reduce the number of chunks balanced on - * resume after balance was interrupted. - */ -static void update_balance_args(struct btrfs_balance_control *bctl) -{ - /* - * Turn on soft mode for chunk types that were being converted. - */ - if (bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) - bctl->data.flags |= BTRFS_BALANCE_ARGS_SOFT; - if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) - bctl->sys.flags |= BTRFS_BALANCE_ARGS_SOFT; - if (bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) - bctl->meta.flags |= BTRFS_BALANCE_ARGS_SOFT; - - /* - * Turn on usage filter if is not already used. The idea is - * that chunks that we have already balanced should be - * reasonably full. Don't do it for chunks that are being - * converted - that will keep us from relocating unconverted - * (albeit full) chunks. - */ - if (!(bctl->data.flags & BTRFS_BALANCE_ARGS_USAGE) && - !(bctl->data.flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) && - !(bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT)) { - bctl->data.flags |= BTRFS_BALANCE_ARGS_USAGE; - bctl->data.usage = 90; - } - if (!(bctl->sys.flags & BTRFS_BALANCE_ARGS_USAGE) && - !(bctl->sys.flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) && - !(bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT)) { - bctl->sys.flags |= BTRFS_BALANCE_ARGS_USAGE; - bctl->sys.usage = 90; - } - if (!(bctl->meta.flags & BTRFS_BALANCE_ARGS_USAGE) && - !(bctl->meta.flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) && - !(bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT)) { - bctl->meta.flags |= BTRFS_BALANCE_ARGS_USAGE; - bctl->meta.usage = 90; - } -} - -/* - * Should be called with both balance and volume mutexes held to - * serialize other volume operations (add_dev/rm_dev/resize) with - * restriper. Same goes for unset_balance_control. - */ -static void set_balance_control(struct btrfs_balance_control *bctl) -{ - struct btrfs_fs_info *fs_info = bctl->fs_info; - - BUG_ON(fs_info->balance_ctl); - - spin_lock(&fs_info->balance_lock); - fs_info->balance_ctl = bctl; - spin_unlock(&fs_info->balance_lock); -} - -static void unset_balance_control(struct btrfs_fs_info *fs_info) -{ - struct btrfs_balance_control *bctl = fs_info->balance_ctl; - - BUG_ON(!fs_info->balance_ctl); - - spin_lock(&fs_info->balance_lock); - fs_info->balance_ctl = NULL; - spin_unlock(&fs_info->balance_lock); - - kfree(bctl); -} - -/* - * Balance filters. Return 1 if chunk should be filtered out - * (should not be balanced). - */ -static int chunk_profiles_filter(u64 chunk_type, - struct btrfs_balance_args *bargs) -{ - chunk_type = chunk_to_extended(chunk_type) & - BTRFS_EXTENDED_PROFILE_MASK; - - if (bargs->profiles & chunk_type) - return 0; - - return 1; -} - -static int chunk_usage_range_filter(struct btrfs_fs_info *fs_info, u64 chunk_offset, - struct btrfs_balance_args *bargs) -{ - struct btrfs_block_group_cache *cache; - u64 chunk_used; - u64 user_thresh_min; - u64 user_thresh_max; - int ret = 1; - - cache = btrfs_lookup_block_group(fs_info, chunk_offset); - chunk_used = btrfs_block_group_used(&cache->item); - - if (bargs->usage_min == 0) - user_thresh_min = 0; - else - user_thresh_min = div_factor_fine(cache->key.offset, - bargs->usage_min); - - if (bargs->usage_max == 0) - user_thresh_max = 1; - else if (bargs->usage_max > 100) - user_thresh_max = cache->key.offset; - else - user_thresh_max = div_factor_fine(cache->key.offset, - bargs->usage_max); - - if (user_thresh_min <= chunk_used && chunk_used < user_thresh_max) - ret = 0; - - btrfs_put_block_group(cache); - return ret; -} - -static int chunk_usage_filter(struct btrfs_fs_info *fs_info, - u64 chunk_offset, struct btrfs_balance_args *bargs) -{ - struct btrfs_block_group_cache *cache; - u64 chunk_used, user_thresh; - int ret = 1; - - cache = btrfs_lookup_block_group(fs_info, chunk_offset); - chunk_used = btrfs_block_group_used(&cache->item); - - if (bargs->usage_min == 0) - user_thresh = 1; - else if (bargs->usage > 100) - user_thresh = cache->key.offset; - else - user_thresh = div_factor_fine(cache->key.offset, - bargs->usage); - - if (chunk_used < user_thresh) - ret = 0; - - btrfs_put_block_group(cache); - return ret; -} - -static int chunk_devid_filter(struct extent_buffer *leaf, - struct btrfs_chunk *chunk, - struct btrfs_balance_args *bargs) -{ - struct btrfs_stripe *stripe; - int num_stripes = btrfs_chunk_num_stripes(leaf, chunk); - int i; - - for (i = 0; i < num_stripes; i++) { - stripe = btrfs_stripe_nr(chunk, i); - if (btrfs_stripe_devid(leaf, stripe) == bargs->devid) - return 0; - } - - return 1; -} - -/* [pstart, pend) */ -static int chunk_drange_filter(struct extent_buffer *leaf, - struct btrfs_chunk *chunk, - u64 chunk_offset, - struct btrfs_balance_args *bargs) -{ - struct btrfs_stripe *stripe; - int num_stripes = btrfs_chunk_num_stripes(leaf, chunk); - u64 stripe_offset; - u64 stripe_length; - int factor; - int i; - - if (!(bargs->flags & BTRFS_BALANCE_ARGS_DEVID)) - return 0; - - if (btrfs_chunk_type(leaf, chunk) & (BTRFS_BLOCK_GROUP_DUP | - BTRFS_BLOCK_GROUP_RAID1 | BTRFS_BLOCK_GROUP_RAID10)) { - factor = num_stripes / 2; - } else if (btrfs_chunk_type(leaf, chunk) & BTRFS_BLOCK_GROUP_RAID5) { - factor = num_stripes - 1; - } else if (btrfs_chunk_type(leaf, chunk) & BTRFS_BLOCK_GROUP_RAID6) { - factor = num_stripes - 2; - } else { - factor = num_stripes; - } - - for (i = 0; i < num_stripes; i++) { - stripe = btrfs_stripe_nr(chunk, i); - if (btrfs_stripe_devid(leaf, stripe) != bargs->devid) - continue; - - stripe_offset = btrfs_stripe_offset(leaf, stripe); - stripe_length = btrfs_chunk_length(leaf, chunk); - stripe_length = div_u64(stripe_length, factor); - - if (stripe_offset < bargs->pend && - stripe_offset + stripe_length > bargs->pstart) - return 0; - } - - return 1; -} - -/* [vstart, vend) */ -static int chunk_vrange_filter(struct extent_buffer *leaf, - struct btrfs_chunk *chunk, - u64 chunk_offset, - struct btrfs_balance_args *bargs) -{ - if (chunk_offset < bargs->vend && - chunk_offset + btrfs_chunk_length(leaf, chunk) > bargs->vstart) - /* at least part of the chunk is inside this vrange */ - return 0; - - return 1; -} - -static int chunk_stripes_range_filter(struct extent_buffer *leaf, - struct btrfs_chunk *chunk, - struct btrfs_balance_args *bargs) -{ - int num_stripes = btrfs_chunk_num_stripes(leaf, chunk); - - if (bargs->stripes_min <= num_stripes - && num_stripes <= bargs->stripes_max) - return 0; - - return 1; -} - -static int chunk_soft_convert_filter(u64 chunk_type, - struct btrfs_balance_args *bargs) -{ - if (!(bargs->flags & BTRFS_BALANCE_ARGS_CONVERT)) - return 0; - - chunk_type = chunk_to_extended(chunk_type) & - BTRFS_EXTENDED_PROFILE_MASK; - - if (bargs->target == chunk_type) - return 1; - - return 0; -} - -static int should_balance_chunk(struct btrfs_root *root, - struct extent_buffer *leaf, - struct btrfs_chunk *chunk, u64 chunk_offset) -{ - struct btrfs_balance_control *bctl = root->fs_info->balance_ctl; - struct btrfs_balance_args *bargs = NULL; - u64 chunk_type = btrfs_chunk_type(leaf, chunk); - - /* type filter */ - if (!((chunk_type & BTRFS_BLOCK_GROUP_TYPE_MASK) & - (bctl->flags & BTRFS_BALANCE_TYPE_MASK))) { - return 0; - } - - if (chunk_type & BTRFS_BLOCK_GROUP_DATA) - bargs = &bctl->data; - else if (chunk_type & BTRFS_BLOCK_GROUP_SYSTEM) - bargs = &bctl->sys; - else if (chunk_type & BTRFS_BLOCK_GROUP_METADATA) - bargs = &bctl->meta; - - /* profiles filter */ - if ((bargs->flags & BTRFS_BALANCE_ARGS_PROFILES) && - chunk_profiles_filter(chunk_type, bargs)) { - return 0; - } - - /* usage filter */ - if ((bargs->flags & BTRFS_BALANCE_ARGS_USAGE) && - chunk_usage_filter(bctl->fs_info, chunk_offset, bargs)) { - return 0; - } else if ((bargs->flags & BTRFS_BALANCE_ARGS_USAGE_RANGE) && - chunk_usage_range_filter(bctl->fs_info, chunk_offset, bargs)) { - return 0; - } - - /* devid filter */ - if ((bargs->flags & BTRFS_BALANCE_ARGS_DEVID) && - chunk_devid_filter(leaf, chunk, bargs)) { - return 0; - } - - /* drange filter, makes sense only with devid filter */ - if ((bargs->flags & BTRFS_BALANCE_ARGS_DRANGE) && - chunk_drange_filter(leaf, chunk, chunk_offset, bargs)) { - return 0; - } - - /* vrange filter */ - if ((bargs->flags & BTRFS_BALANCE_ARGS_VRANGE) && - chunk_vrange_filter(leaf, chunk, chunk_offset, bargs)) { - return 0; - } - - /* stripes filter */ - if ((bargs->flags & BTRFS_BALANCE_ARGS_STRIPES_RANGE) && - chunk_stripes_range_filter(leaf, chunk, bargs)) { - return 0; - } - - /* soft profile changing mode */ - if ((bargs->flags & BTRFS_BALANCE_ARGS_SOFT) && - chunk_soft_convert_filter(chunk_type, bargs)) { - return 0; - } - - /* - * limited by count, must be the last filter - */ - if ((bargs->flags & BTRFS_BALANCE_ARGS_LIMIT)) { - if (bargs->limit == 0) - return 0; - else - bargs->limit--; - } else if ((bargs->flags & BTRFS_BALANCE_ARGS_LIMIT_RANGE)) { - /* - * Same logic as the 'limit' filter; the minimum cannot be - * determined here because we do not have the global information - * about the count of all chunks that satisfy the filters. - */ - if (bargs->limit_max == 0) - return 0; - else - bargs->limit_max--; - } - - return 1; -} - -static int __btrfs_balance(struct btrfs_fs_info *fs_info) -{ - struct btrfs_balance_control *bctl = fs_info->balance_ctl; - struct btrfs_root *chunk_root = fs_info->chunk_root; - struct btrfs_root *dev_root = fs_info->dev_root; - struct list_head *devices; - struct btrfs_device *device; - u64 old_size; - u64 size_to_free; - u64 chunk_type; - struct btrfs_chunk *chunk; - struct btrfs_path *path = NULL; - struct btrfs_key key; - struct btrfs_key found_key; - struct btrfs_trans_handle *trans; - struct extent_buffer *leaf; - int slot; - int ret; - int enospc_errors = 0; - bool counting = true; - /* The single value limit and min/max limits use the same bytes in the */ - u64 limit_data = bctl->data.limit; - u64 limit_meta = bctl->meta.limit; - u64 limit_sys = bctl->sys.limit; - u32 count_data = 0; - u32 count_meta = 0; - u32 count_sys = 0; - int chunk_reserved = 0; - u64 bytes_used = 0; - - /* step one make some room on all the devices */ - devices = &fs_info->fs_devices->devices; - list_for_each_entry(device, devices, dev_list) { - old_size = btrfs_device_get_total_bytes(device); - size_to_free = div_factor(old_size, 1); - size_to_free = min_t(u64, size_to_free, SZ_1M); - if (!device->writeable || - btrfs_device_get_total_bytes(device) - - btrfs_device_get_bytes_used(device) > size_to_free || - device->is_tgtdev_for_dev_replace) - continue; - - ret = btrfs_shrink_device(device, old_size - size_to_free); - if (ret == -ENOSPC) - break; - if (ret) { - /* btrfs_shrink_device never returns ret > 0 */ - WARN_ON(ret > 0); - goto error; - } - - trans = btrfs_start_transaction(dev_root, 0); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - btrfs_info_in_rcu(fs_info, - "resize: unable to start transaction after shrinking device %s (error %d), old size %llu, new size %llu", - rcu_str_deref(device->name), ret, - old_size, old_size - size_to_free); - goto error; - } - - ret = btrfs_grow_device(trans, device, old_size); - if (ret) { - btrfs_end_transaction(trans, dev_root); - /* btrfs_grow_device never returns ret > 0 */ - WARN_ON(ret > 0); - btrfs_info_in_rcu(fs_info, - "resize: unable to grow device after shrinking device %s (error %d), old size %llu, new size %llu", - rcu_str_deref(device->name), ret, - old_size, old_size - size_to_free); - goto error; - } - - btrfs_end_transaction(trans, dev_root); - } - - /* step two, relocate all the chunks */ - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto error; - } - - /* zero out stat counters */ - spin_lock(&fs_info->balance_lock); - memset(&bctl->stat, 0, sizeof(bctl->stat)); - spin_unlock(&fs_info->balance_lock); -again: - if (!counting) { - /* - * The single value limit and min/max limits use the same bytes - * in the - */ - bctl->data.limit = limit_data; - bctl->meta.limit = limit_meta; - bctl->sys.limit = limit_sys; - } - key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; - key.offset = (u64)-1; - key.type = BTRFS_CHUNK_ITEM_KEY; - - while (1) { - if ((!counting && atomic_read(&fs_info->balance_pause_req)) || - atomic_read(&fs_info->balance_cancel_req)) { - ret = -ECANCELED; - goto error; - } - - mutex_lock(&fs_info->delete_unused_bgs_mutex); - ret = btrfs_search_slot(NULL, chunk_root, &key, path, 0, 0); - if (ret < 0) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); - goto error; - } - - /* - * this shouldn't happen, it means the last relocate - * failed - */ - if (ret == 0) - BUG(); /* FIXME break ? */ - - ret = btrfs_previous_item(chunk_root, path, 0, - BTRFS_CHUNK_ITEM_KEY); - if (ret) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); - ret = 0; - break; - } - - leaf = path->nodes[0]; - slot = path->slots[0]; - btrfs_item_key_to_cpu(leaf, &found_key, slot); - - if (found_key.objectid != key.objectid) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); - break; - } - - chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk); - chunk_type = btrfs_chunk_type(leaf, chunk); - - if (!counting) { - spin_lock(&fs_info->balance_lock); - bctl->stat.considered++; - spin_unlock(&fs_info->balance_lock); - } - - ret = should_balance_chunk(chunk_root, leaf, chunk, - found_key.offset); - - btrfs_release_path(path); - if (!ret) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); - goto loop; - } - - if (counting) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); - spin_lock(&fs_info->balance_lock); - bctl->stat.expected++; - spin_unlock(&fs_info->balance_lock); - - if (chunk_type & BTRFS_BLOCK_GROUP_DATA) - count_data++; - else if (chunk_type & BTRFS_BLOCK_GROUP_SYSTEM) - count_sys++; - else if (chunk_type & BTRFS_BLOCK_GROUP_METADATA) - count_meta++; - - goto loop; - } - - /* - * Apply limit_min filter, no need to check if the LIMITS - * filter is used, limit_min is 0 by default - */ - if (((chunk_type & BTRFS_BLOCK_GROUP_DATA) && - count_data < bctl->data.limit_min) - || ((chunk_type & BTRFS_BLOCK_GROUP_METADATA) && - count_meta < bctl->meta.limit_min) - || ((chunk_type & BTRFS_BLOCK_GROUP_SYSTEM) && - count_sys < bctl->sys.limit_min)) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); - goto loop; - } - - ASSERT(fs_info->data_sinfo); - spin_lock(&fs_info->data_sinfo->lock); - bytes_used = fs_info->data_sinfo->bytes_used; - spin_unlock(&fs_info->data_sinfo->lock); - - if ((chunk_type & BTRFS_BLOCK_GROUP_DATA) && - !chunk_reserved && !bytes_used) { - trans = btrfs_start_transaction(chunk_root, 0); - if (IS_ERR(trans)) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); - ret = PTR_ERR(trans); - goto error; - } - - ret = btrfs_force_chunk_alloc(trans, chunk_root, - BTRFS_BLOCK_GROUP_DATA); - btrfs_end_transaction(trans, chunk_root); - if (ret < 0) { - mutex_unlock(&fs_info->delete_unused_bgs_mutex); - goto error; - } - chunk_reserved = 1; - } - - ret = btrfs_relocate_chunk(chunk_root, - found_key.offset); - mutex_unlock(&fs_info->delete_unused_bgs_mutex); - if (ret && ret != -ENOSPC) - goto error; - if (ret == -ENOSPC) { - enospc_errors++; - } else { - spin_lock(&fs_info->balance_lock); - bctl->stat.completed++; - spin_unlock(&fs_info->balance_lock); - } -loop: - if (found_key.offset == 0) - break; - key.offset = found_key.offset - 1; - } - - if (counting) { - btrfs_release_path(path); - counting = false; - goto again; - } -error: - btrfs_free_path(path); - if (enospc_errors) { - btrfs_info(fs_info, "%d enospc errors during balance", - enospc_errors); - if (!ret) - ret = -ENOSPC; - } - - return ret; -} - -/** - * alloc_profile_is_valid - see if a given profile is valid and reduced - * @flags: profile to validate - * @extended: if true @flags is treated as an extended profile - */ -static int alloc_profile_is_valid(u64 flags, int extended) -{ - u64 mask = (extended ? BTRFS_EXTENDED_PROFILE_MASK : - BTRFS_BLOCK_GROUP_PROFILE_MASK); - - flags &= ~BTRFS_BLOCK_GROUP_TYPE_MASK; - - /* 1) check that all other bits are zeroed */ - if (flags & ~mask) - return 0; - - /* 2) see if profile is reduced */ - if (flags == 0) - return !extended; /* "0" is valid for usual profiles */ - - /* true if exactly one bit set */ - return (flags & (flags - 1)) == 0; -} - -static inline int balance_need_close(struct btrfs_fs_info *fs_info) -{ - /* cancel requested || normal exit path */ - return atomic_read(&fs_info->balance_cancel_req) || - (atomic_read(&fs_info->balance_pause_req) == 0 && - atomic_read(&fs_info->balance_cancel_req) == 0); -} - -static void __cancel_balance(struct btrfs_fs_info *fs_info) -{ - int ret; - - unset_balance_control(fs_info); - ret = del_balance_item(fs_info->tree_root); - if (ret) - btrfs_handle_fs_error(fs_info, ret, NULL); - - atomic_set(&fs_info->mutually_exclusive_operation_running, 0); -} - -/* Non-zero return value signifies invalidity */ -static inline int validate_convert_profile(struct btrfs_balance_args *bctl_arg, - u64 allowed) -{ - return ((bctl_arg->flags & BTRFS_BALANCE_ARGS_CONVERT) && - (!alloc_profile_is_valid(bctl_arg->target, 1) || - (bctl_arg->target & ~allowed))); -} - -/* - * Should be called with both balance and volume mutexes held - */ -int btrfs_balance(struct btrfs_balance_control *bctl, - struct btrfs_ioctl_balance_args *bargs) -{ - struct btrfs_fs_info *fs_info = bctl->fs_info; - u64 allowed; - int mixed = 0; - int ret; - u64 num_devices; - unsigned seq; - - if (btrfs_fs_closing(fs_info) || - atomic_read(&fs_info->balance_pause_req) || - atomic_read(&fs_info->balance_cancel_req)) { - ret = -EINVAL; - goto out; - } - - allowed = btrfs_super_incompat_flags(fs_info->super_copy); - if (allowed & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) - mixed = 1; - - /* - * In case of mixed groups both data and meta should be picked, - * and identical options should be given for both of them. - */ - allowed = BTRFS_BALANCE_DATA | BTRFS_BALANCE_METADATA; - if (mixed && (bctl->flags & allowed)) { - if (!(bctl->flags & BTRFS_BALANCE_DATA) || - !(bctl->flags & BTRFS_BALANCE_METADATA) || - memcmp(&bctl->data, &bctl->meta, sizeof(bctl->data))) { - btrfs_err(fs_info, - "with mixed groups data and metadata balance options must be the same"); - ret = -EINVAL; - goto out; - } - } - - num_devices = fs_info->fs_devices->num_devices; - btrfs_dev_replace_lock(&fs_info->dev_replace, 0); - if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace)) { - BUG_ON(num_devices < 1); - num_devices--; - } - btrfs_dev_replace_unlock(&fs_info->dev_replace, 0); - allowed = BTRFS_AVAIL_ALLOC_BIT_SINGLE | BTRFS_BLOCK_GROUP_DUP; - if (num_devices > 1) - allowed |= (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID1); - if (num_devices > 2) - allowed |= BTRFS_BLOCK_GROUP_RAID5; - if (num_devices > 3) - allowed |= (BTRFS_BLOCK_GROUP_RAID10 | - BTRFS_BLOCK_GROUP_RAID6); - if (validate_convert_profile(&bctl->data, allowed)) { - btrfs_err(fs_info, - "unable to start balance with target data profile %llu", - bctl->data.target); - ret = -EINVAL; - goto out; - } - if (validate_convert_profile(&bctl->meta, allowed)) { - btrfs_err(fs_info, - "unable to start balance with target metadata profile %llu", - bctl->meta.target); - ret = -EINVAL; - goto out; - } - if (validate_convert_profile(&bctl->sys, allowed)) { - btrfs_err(fs_info, - "unable to start balance with target system profile %llu", - bctl->sys.target); - ret = -EINVAL; - goto out; - } - - /* allow to reduce meta or sys integrity only if force set */ - allowed = BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID10 | - BTRFS_BLOCK_GROUP_RAID5 | - BTRFS_BLOCK_GROUP_RAID6; - do { - seq = read_seqbegin(&fs_info->profiles_lock); - - if (((bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) && - (fs_info->avail_system_alloc_bits & allowed) && - !(bctl->sys.target & allowed)) || - ((bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) && - (fs_info->avail_metadata_alloc_bits & allowed) && - !(bctl->meta.target & allowed))) { - if (bctl->flags & BTRFS_BALANCE_FORCE) { - btrfs_info(fs_info, - "force reducing metadata integrity"); - } else { - btrfs_err(fs_info, - "balance will reduce metadata integrity, use force if you want this"); - ret = -EINVAL; - goto out; - } - } - } while (read_seqretry(&fs_info->profiles_lock, seq)); - - if (btrfs_get_num_tolerated_disk_barrier_failures(bctl->meta.target) < - btrfs_get_num_tolerated_disk_barrier_failures(bctl->data.target)) { - btrfs_warn(fs_info, - "metadata profile 0x%llx has lower redundancy than data profile 0x%llx", - bctl->meta.target, bctl->data.target); - } - - if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) { - fs_info->num_tolerated_disk_barrier_failures = min( - btrfs_calc_num_tolerated_disk_barrier_failures(fs_info), - btrfs_get_num_tolerated_disk_barrier_failures( - bctl->sys.target)); - } - - ret = insert_balance_item(fs_info->tree_root, bctl); - if (ret && ret != -EEXIST) - goto out; - - if (!(bctl->flags & BTRFS_BALANCE_RESUME)) { - BUG_ON(ret == -EEXIST); - set_balance_control(bctl); - } else { - BUG_ON(ret != -EEXIST); - spin_lock(&fs_info->balance_lock); - update_balance_args(bctl); - spin_unlock(&fs_info->balance_lock); - } - - atomic_inc(&fs_info->balance_running); - mutex_unlock(&fs_info->balance_mutex); - - ret = __btrfs_balance(fs_info); - - mutex_lock(&fs_info->balance_mutex); - atomic_dec(&fs_info->balance_running); - - if (bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) { - fs_info->num_tolerated_disk_barrier_failures = - btrfs_calc_num_tolerated_disk_barrier_failures(fs_info); - } - - if (bargs) { - memset(bargs, 0, sizeof(*bargs)); - update_ioctl_balance_args(fs_info, 0, bargs); - } - - if ((ret && ret != -ECANCELED && ret != -ENOSPC) || - balance_need_close(fs_info)) { - __cancel_balance(fs_info); - } - - wake_up(&fs_info->balance_wait_q); - - return ret; -out: - if (bctl->flags & BTRFS_BALANCE_RESUME) - __cancel_balance(fs_info); - else { - kfree(bctl); - atomic_set(&fs_info->mutually_exclusive_operation_running, 0); - } - return ret; -} - -static int balance_kthread(void *data) -{ - struct btrfs_fs_info *fs_info = data; - int ret = 0; - - mutex_lock(&fs_info->volume_mutex); - mutex_lock(&fs_info->balance_mutex); - - if (fs_info->balance_ctl) { - btrfs_info(fs_info, "continuing balance"); - ret = btrfs_balance(fs_info->balance_ctl, NULL); - } - - mutex_unlock(&fs_info->balance_mutex); - mutex_unlock(&fs_info->volume_mutex); - - return ret; -} - -int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info) -{ - struct task_struct *tsk; - - spin_lock(&fs_info->balance_lock); - if (!fs_info->balance_ctl) { - spin_unlock(&fs_info->balance_lock); - return 0; - } - spin_unlock(&fs_info->balance_lock); - - if (btrfs_test_opt(fs_info, SKIP_BALANCE)) { - btrfs_info(fs_info, "force skipping balance"); - return 0; - } - - tsk = kthread_run(balance_kthread, fs_info, "btrfs-balance"); - return PTR_ERR_OR_ZERO(tsk); -} - -int btrfs_recover_balance(struct btrfs_fs_info *fs_info) -{ - struct btrfs_balance_control *bctl; - struct btrfs_balance_item *item; - struct btrfs_disk_balance_args disk_bargs; - struct btrfs_path *path; - struct extent_buffer *leaf; - struct btrfs_key key; - int ret; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - key.objectid = BTRFS_BALANCE_OBJECTID; - key.type = BTRFS_TEMPORARY_ITEM_KEY; - key.offset = 0; - - ret = btrfs_search_slot(NULL, fs_info->tree_root, &key, path, 0, 0); - if (ret < 0) - goto out; - if (ret > 0) { /* ret = -ENOENT; */ - ret = 0; - goto out; - } - - bctl = kzalloc(sizeof(*bctl), GFP_NOFS); - if (!bctl) { - ret = -ENOMEM; - goto out; - } - - leaf = path->nodes[0]; - item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_balance_item); - - bctl->fs_info = fs_info; - bctl->flags = btrfs_balance_flags(leaf, item); - bctl->flags |= BTRFS_BALANCE_RESUME; - - btrfs_balance_data(leaf, item, &disk_bargs); - btrfs_disk_balance_args_to_cpu(&bctl->data, &disk_bargs); - btrfs_balance_meta(leaf, item, &disk_bargs); - btrfs_disk_balance_args_to_cpu(&bctl->meta, &disk_bargs); - btrfs_balance_sys(leaf, item, &disk_bargs); - btrfs_disk_balance_args_to_cpu(&bctl->sys, &disk_bargs); - - WARN_ON(atomic_xchg(&fs_info->mutually_exclusive_operation_running, 1)); - - mutex_lock(&fs_info->volume_mutex); - mutex_lock(&fs_info->balance_mutex); - - set_balance_control(bctl); - - mutex_unlock(&fs_info->balance_mutex); - mutex_unlock(&fs_info->volume_mutex); -out: - btrfs_free_path(path); - return ret; -} - -int btrfs_pause_balance(struct btrfs_fs_info *fs_info) -{ - int ret = 0; - - mutex_lock(&fs_info->balance_mutex); - if (!fs_info->balance_ctl) { - mutex_unlock(&fs_info->balance_mutex); - return -ENOTCONN; - } - - if (atomic_read(&fs_info->balance_running)) { - atomic_inc(&fs_info->balance_pause_req); - mutex_unlock(&fs_info->balance_mutex); - - wait_event(fs_info->balance_wait_q, - atomic_read(&fs_info->balance_running) == 0); - - mutex_lock(&fs_info->balance_mutex); - /* we are good with balance_ctl ripped off from under us */ - BUG_ON(atomic_read(&fs_info->balance_running)); - atomic_dec(&fs_info->balance_pause_req); - } else { - ret = -ENOTCONN; - } - - mutex_unlock(&fs_info->balance_mutex); - return ret; -} - -int btrfs_cancel_balance(struct btrfs_fs_info *fs_info) -{ - if (fs_info->sb->s_flags & MS_RDONLY) - return -EROFS; - - mutex_lock(&fs_info->balance_mutex); - if (!fs_info->balance_ctl) { - mutex_unlock(&fs_info->balance_mutex); - return -ENOTCONN; - } - - atomic_inc(&fs_info->balance_cancel_req); - /* - * if we are running just wait and return, balance item is - * deleted in btrfs_balance in this case - */ - if (atomic_read(&fs_info->balance_running)) { - mutex_unlock(&fs_info->balance_mutex); - wait_event(fs_info->balance_wait_q, - atomic_read(&fs_info->balance_running) == 0); - mutex_lock(&fs_info->balance_mutex); - } else { - /* __cancel_balance needs volume_mutex */ - mutex_unlock(&fs_info->balance_mutex); - mutex_lock(&fs_info->volume_mutex); - mutex_lock(&fs_info->balance_mutex); - - if (fs_info->balance_ctl) - __cancel_balance(fs_info); - - mutex_unlock(&fs_info->volume_mutex); - } - - BUG_ON(fs_info->balance_ctl || atomic_read(&fs_info->balance_running)); - atomic_dec(&fs_info->balance_cancel_req); - mutex_unlock(&fs_info->balance_mutex); - return 0; -} - -static int btrfs_uuid_scan_kthread(void *data) -{ - struct btrfs_fs_info *fs_info = data; - struct btrfs_root *root = fs_info->tree_root; - struct btrfs_key key; - struct btrfs_key max_key; - struct btrfs_path *path = NULL; - int ret = 0; - struct extent_buffer *eb; - int slot; - struct btrfs_root_item root_item; - u32 item_size; - struct btrfs_trans_handle *trans = NULL; - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - key.objectid = 0; - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = 0; - - max_key.objectid = (u64)-1; - max_key.type = BTRFS_ROOT_ITEM_KEY; - max_key.offset = (u64)-1; - - while (1) { - ret = btrfs_search_forward(root, &key, path, 0); - if (ret) { - if (ret > 0) - ret = 0; - break; - } - - if (key.type != BTRFS_ROOT_ITEM_KEY || - (key.objectid < BTRFS_FIRST_FREE_OBJECTID && - key.objectid != BTRFS_FS_TREE_OBJECTID) || - key.objectid > BTRFS_LAST_FREE_OBJECTID) - goto skip; - - eb = path->nodes[0]; - slot = path->slots[0]; - item_size = btrfs_item_size_nr(eb, slot); - if (item_size < sizeof(root_item)) - goto skip; - - read_extent_buffer(eb, &root_item, - btrfs_item_ptr_offset(eb, slot), - (int)sizeof(root_item)); - if (btrfs_root_refs(&root_item) == 0) - goto skip; - - if (!btrfs_is_empty_uuid(root_item.uuid) || - !btrfs_is_empty_uuid(root_item.received_uuid)) { - if (trans) - goto update_tree; - - btrfs_release_path(path); - /* - * 1 - subvol uuid item - * 1 - received_subvol uuid item - */ - trans = btrfs_start_transaction(fs_info->uuid_root, 2); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - break; - } - continue; - } else { - goto skip; - } -update_tree: - if (!btrfs_is_empty_uuid(root_item.uuid)) { - ret = btrfs_uuid_tree_add(trans, fs_info->uuid_root, - root_item.uuid, - BTRFS_UUID_KEY_SUBVOL, - key.objectid); - if (ret < 0) { - btrfs_warn(fs_info, "uuid_tree_add failed %d", - ret); - break; - } - } - - if (!btrfs_is_empty_uuid(root_item.received_uuid)) { - ret = btrfs_uuid_tree_add(trans, fs_info->uuid_root, - root_item.received_uuid, - BTRFS_UUID_KEY_RECEIVED_SUBVOL, - key.objectid); - if (ret < 0) { - btrfs_warn(fs_info, "uuid_tree_add failed %d", - ret); - break; - } - } - -skip: - if (trans) { - ret = btrfs_end_transaction(trans, fs_info->uuid_root); - trans = NULL; - if (ret) - break; - } - - btrfs_release_path(path); - if (key.offset < (u64)-1) { - key.offset++; - } else if (key.type < BTRFS_ROOT_ITEM_KEY) { - key.offset = 0; - key.type = BTRFS_ROOT_ITEM_KEY; - } else if (key.objectid < (u64)-1) { - key.offset = 0; - key.type = BTRFS_ROOT_ITEM_KEY; - key.objectid++; - } else { - break; - } - cond_resched(); - } - -out: - btrfs_free_path(path); - if (trans && !IS_ERR(trans)) - btrfs_end_transaction(trans, fs_info->uuid_root); - if (ret) - btrfs_warn(fs_info, "btrfs_uuid_scan_kthread failed %d", ret); - else - set_bit(BTRFS_FS_UPDATE_UUID_TREE_GEN, &fs_info->flags); - up(&fs_info->uuid_tree_rescan_sem); - return 0; -} - -/* - * Callback for btrfs_uuid_tree_iterate(). - * returns: - * 0 check succeeded, the entry is not outdated. - * < 0 if an error occurred. - * > 0 if the check failed, which means the caller shall remove the entry. - */ -static int btrfs_check_uuid_tree_entry(struct btrfs_fs_info *fs_info, - u8 *uuid, u8 type, u64 subid) -{ - struct btrfs_key key; - int ret = 0; - struct btrfs_root *subvol_root; - - if (type != BTRFS_UUID_KEY_SUBVOL && - type != BTRFS_UUID_KEY_RECEIVED_SUBVOL) - goto out; - - key.objectid = subid; - key.type = BTRFS_ROOT_ITEM_KEY; - key.offset = (u64)-1; - subvol_root = btrfs_read_fs_root_no_name(fs_info, &key); - if (IS_ERR(subvol_root)) { - ret = PTR_ERR(subvol_root); - if (ret == -ENOENT) - ret = 1; - goto out; - } - - switch (type) { - case BTRFS_UUID_KEY_SUBVOL: - if (memcmp(uuid, subvol_root->root_item.uuid, BTRFS_UUID_SIZE)) - ret = 1; - break; - case BTRFS_UUID_KEY_RECEIVED_SUBVOL: - if (memcmp(uuid, subvol_root->root_item.received_uuid, - BTRFS_UUID_SIZE)) - ret = 1; - break; - } - -out: - return ret; -} - -static int btrfs_uuid_rescan_kthread(void *data) -{ - struct btrfs_fs_info *fs_info = (struct btrfs_fs_info *)data; - int ret; - - /* - * 1st step is to iterate through the existing UUID tree and - * to delete all entries that contain outdated data. - * 2nd step is to add all missing entries to the UUID tree. - */ - ret = btrfs_uuid_tree_iterate(fs_info, btrfs_check_uuid_tree_entry); - if (ret < 0) { - btrfs_warn(fs_info, "iterating uuid_tree failed %d", ret); - up(&fs_info->uuid_tree_rescan_sem); - return ret; - } - return btrfs_uuid_scan_kthread(data); -} - -int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info) -{ - struct btrfs_trans_handle *trans; - struct btrfs_root *tree_root = fs_info->tree_root; - struct btrfs_root *uuid_root; - struct task_struct *task; - int ret; - - /* - * 1 - root node - * 1 - root item - */ - trans = btrfs_start_transaction(tree_root, 2); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - uuid_root = btrfs_create_tree(trans, fs_info, - BTRFS_UUID_TREE_OBJECTID); - if (IS_ERR(uuid_root)) { - ret = PTR_ERR(uuid_root); - btrfs_abort_transaction(trans, ret); - btrfs_end_transaction(trans, tree_root); - return ret; - } - - fs_info->uuid_root = uuid_root; - - ret = btrfs_commit_transaction(trans, tree_root); - if (ret) - return ret; - - down(&fs_info->uuid_tree_rescan_sem); - task = kthread_run(btrfs_uuid_scan_kthread, fs_info, "btrfs-uuid"); - if (IS_ERR(task)) { - /* fs_info->update_uuid_tree_gen remains 0 in all error case */ - btrfs_warn(fs_info, "failed to start uuid_scan task"); - up(&fs_info->uuid_tree_rescan_sem); - return PTR_ERR(task); - } - - return 0; -} - -int btrfs_check_uuid_tree(struct btrfs_fs_info *fs_info) -{ - struct task_struct *task; - - down(&fs_info->uuid_tree_rescan_sem); - task = kthread_run(btrfs_uuid_rescan_kthread, fs_info, "btrfs-uuid"); - if (IS_ERR(task)) { - /* fs_info->update_uuid_tree_gen remains 0 in all error case */ - btrfs_warn(fs_info, "failed to start uuid_rescan task"); - up(&fs_info->uuid_tree_rescan_sem); - return PTR_ERR(task); - } - - return 0; -} - -/* - * shrinking a device means finding all of the device extents past - * the new size, and then following the back refs to the chunks. - * The chunk relocation code actually frees the device extent - */ -int btrfs_shrink_device(struct btrfs_device *device, u64 new_size) -{ - struct btrfs_trans_handle *trans; - struct btrfs_root *root = device->dev_root; - struct btrfs_dev_extent *dev_extent = NULL; - struct btrfs_path *path; - u64 length; - u64 chunk_offset; - int ret; - int slot; - int failed = 0; - bool retried = false; - bool checked_pending_chunks = false; - struct extent_buffer *l; - struct btrfs_key key; - struct btrfs_super_block *super_copy = root->fs_info->super_copy; - u64 old_total = btrfs_super_total_bytes(super_copy); - u64 old_size = btrfs_device_get_total_bytes(device); - u64 diff = old_size - new_size; - - if (device->is_tgtdev_for_dev_replace) - return -EINVAL; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - path->reada = READA_FORWARD; - - lock_chunks(root); - - btrfs_device_set_total_bytes(device, new_size); - if (device->writeable) { - device->fs_devices->total_rw_bytes -= diff; - spin_lock(&root->fs_info->free_chunk_lock); - root->fs_info->free_chunk_space -= diff; - spin_unlock(&root->fs_info->free_chunk_lock); - } - unlock_chunks(root); - -again: - key.objectid = device->devid; - key.offset = (u64)-1; - key.type = BTRFS_DEV_EXTENT_KEY; - - do { - mutex_lock(&root->fs_info->delete_unused_bgs_mutex); - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) { - mutex_unlock(&root->fs_info->delete_unused_bgs_mutex); - goto done; - } - - ret = btrfs_previous_item(root, path, 0, key.type); - if (ret) - mutex_unlock(&root->fs_info->delete_unused_bgs_mutex); - if (ret < 0) - goto done; - if (ret) { - ret = 0; - btrfs_release_path(path); - break; - } - - l = path->nodes[0]; - slot = path->slots[0]; - btrfs_item_key_to_cpu(l, &key, path->slots[0]); - - if (key.objectid != device->devid) { - mutex_unlock(&root->fs_info->delete_unused_bgs_mutex); - btrfs_release_path(path); - break; - } - - dev_extent = btrfs_item_ptr(l, slot, struct btrfs_dev_extent); - length = btrfs_dev_extent_length(l, dev_extent); - - if (key.offset + length <= new_size) { - mutex_unlock(&root->fs_info->delete_unused_bgs_mutex); - btrfs_release_path(path); - break; - } - - chunk_offset = btrfs_dev_extent_chunk_offset(l, dev_extent); - btrfs_release_path(path); - - ret = btrfs_relocate_chunk(root, chunk_offset); - mutex_unlock(&root->fs_info->delete_unused_bgs_mutex); - if (ret && ret != -ENOSPC) - goto done; - if (ret == -ENOSPC) - failed++; - } while (key.offset-- > 0); - - if (failed && !retried) { - failed = 0; - retried = true; - goto again; - } else if (failed && retried) { - ret = -ENOSPC; - goto done; - } - - /* Shrinking succeeded, else we would be at "done". */ - trans = btrfs_start_transaction(root, 0); - if (IS_ERR(trans)) { - ret = PTR_ERR(trans); - goto done; - } - - lock_chunks(root); - - /* - * We checked in the above loop all device extents that were already in - * the device tree. However before we have updated the device's - * total_bytes to the new size, we might have had chunk allocations that - * have not complete yet (new block groups attached to transaction - * handles), and therefore their device extents were not yet in the - * device tree and we missed them in the loop above. So if we have any - * pending chunk using a device extent that overlaps the device range - * that we can not use anymore, commit the current transaction and - * repeat the search on the device tree - this way we guarantee we will - * not have chunks using device extents that end beyond 'new_size'. - */ - if (!checked_pending_chunks) { - u64 start = new_size; - u64 len = old_size - new_size; - - if (contains_pending_extent(trans->transaction, device, - &start, len)) { - unlock_chunks(root); - checked_pending_chunks = true; - failed = 0; - retried = false; - ret = btrfs_commit_transaction(trans, root); - if (ret) - goto done; - goto again; - } - } - - btrfs_device_set_disk_total_bytes(device, new_size); - if (list_empty(&device->resized_list)) - list_add_tail(&device->resized_list, - &root->fs_info->fs_devices->resized_devices); - - WARN_ON(diff > old_total); - btrfs_set_super_total_bytes(super_copy, old_total - diff); - unlock_chunks(root); - - /* Now btrfs_update_device() will change the on-disk size. */ - ret = btrfs_update_device(trans, device); - btrfs_end_transaction(trans, root); -done: - btrfs_free_path(path); - if (ret) { - lock_chunks(root); - btrfs_device_set_total_bytes(device, old_size); - if (device->writeable) - device->fs_devices->total_rw_bytes += diff; - spin_lock(&root->fs_info->free_chunk_lock); - root->fs_info->free_chunk_space += diff; - spin_unlock(&root->fs_info->free_chunk_lock); - unlock_chunks(root); - } - return ret; -} - -static int btrfs_add_system_chunk(struct btrfs_root *root, - struct btrfs_key *key, - struct btrfs_chunk *chunk, int item_size) -{ - struct btrfs_super_block *super_copy = root->fs_info->super_copy; - struct btrfs_disk_key disk_key; - u32 array_size; - u8 *ptr; - - lock_chunks(root); - array_size = btrfs_super_sys_array_size(super_copy); - if (array_size + item_size + sizeof(disk_key) - > BTRFS_SYSTEM_CHUNK_ARRAY_SIZE) { - unlock_chunks(root); - return -EFBIG; - } - - ptr = super_copy->sys_chunk_array + array_size; - btrfs_cpu_key_to_disk(&disk_key, key); - memcpy(ptr, &disk_key, sizeof(disk_key)); - ptr += sizeof(disk_key); - memcpy(ptr, chunk, item_size); - item_size += sizeof(disk_key); - btrfs_set_super_sys_array_size(super_copy, array_size + item_size); - unlock_chunks(root); - - return 0; -} - -/* - * sort the devices in descending order by max_avail, total_avail - */ -static int btrfs_cmp_device_info(const void *a, const void *b) -{ - const struct btrfs_device_info *di_a = a; - const struct btrfs_device_info *di_b = b; - - if (di_a->max_avail > di_b->max_avail) - return -1; - if (di_a->max_avail < di_b->max_avail) - return 1; - if (di_a->total_avail > di_b->total_avail) - return -1; - if (di_a->total_avail < di_b->total_avail) - return 1; - return 0; -} - -static u32 find_raid56_stripe_len(u32 data_devices, u32 dev_stripe_target) -{ - /* TODO allow them to set a preferred stripe size */ - return SZ_64K; -} - -static void check_raid56_incompat_flag(struct btrfs_fs_info *info, u64 type) -{ - if (!(type & BTRFS_BLOCK_GROUP_RAID56_MASK)) - return; - - btrfs_set_fs_incompat(info, RAID56); -} - -#define BTRFS_MAX_DEVS(r) ((BTRFS_MAX_ITEM_SIZE(r) \ - - sizeof(struct btrfs_chunk)) \ - / sizeof(struct btrfs_stripe) + 1) - -#define BTRFS_MAX_DEVS_SYS_CHUNK ((BTRFS_SYSTEM_CHUNK_ARRAY_SIZE \ - - 2 * sizeof(struct btrfs_disk_key) \ - - 2 * sizeof(struct btrfs_chunk)) \ - / sizeof(struct btrfs_stripe) + 1) - -static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans, - struct btrfs_root *extent_root, u64 start, - u64 type) -{ - struct btrfs_fs_info *info = extent_root->fs_info; - struct btrfs_fs_devices *fs_devices = info->fs_devices; - struct list_head *cur; - struct map_lookup *map = NULL; - struct extent_map_tree *em_tree; - struct extent_map *em; - struct btrfs_device_info *devices_info = NULL; - u64 total_avail; - int num_stripes; /* total number of stripes to allocate */ - int data_stripes; /* number of stripes that count for - block group size */ - int sub_stripes; /* sub_stripes info for map */ - int dev_stripes; /* stripes per dev */ - int devs_max; /* max devs to use */ - int devs_min; /* min devs needed */ - int devs_increment; /* ndevs has to be a multiple of this */ - int ncopies; /* how many copies to data has */ - int ret; - u64 max_stripe_size; - u64 max_chunk_size; - u64 stripe_size; - u64 num_bytes; - u64 raid_stripe_len = BTRFS_STRIPE_LEN; - int ndevs; - int i; - int j; - int index; - - BUG_ON(!alloc_profile_is_valid(type, 0)); - - if (list_empty(&fs_devices->alloc_list)) - return -ENOSPC; - - index = __get_raid_index(type); - - sub_stripes = btrfs_raid_array[index].sub_stripes; - dev_stripes = btrfs_raid_array[index].dev_stripes; - devs_max = btrfs_raid_array[index].devs_max; - devs_min = btrfs_raid_array[index].devs_min; - devs_increment = btrfs_raid_array[index].devs_increment; - ncopies = btrfs_raid_array[index].ncopies; - - if (type & BTRFS_BLOCK_GROUP_DATA) { - max_stripe_size = SZ_1G; - max_chunk_size = 10 * max_stripe_size; - if (!devs_max) - devs_max = BTRFS_MAX_DEVS(info->chunk_root); - } else if (type & BTRFS_BLOCK_GROUP_METADATA) { - /* for larger filesystems, use larger metadata chunks */ - if (fs_devices->total_rw_bytes > 50ULL * SZ_1G) - max_stripe_size = SZ_1G; - else - max_stripe_size = SZ_256M; - max_chunk_size = max_stripe_size; - if (!devs_max) - devs_max = BTRFS_MAX_DEVS(info->chunk_root); - } else if (type & BTRFS_BLOCK_GROUP_SYSTEM) { - max_stripe_size = SZ_32M; - max_chunk_size = 2 * max_stripe_size; - if (!devs_max) - devs_max = BTRFS_MAX_DEVS_SYS_CHUNK; - } else { - btrfs_err(info, "invalid chunk type 0x%llx requested", - type); - BUG_ON(1); - } - - /* we don't want a chunk larger than 10% of writeable space */ - max_chunk_size = min(div_factor(fs_devices->total_rw_bytes, 1), - max_chunk_size); - - devices_info = kcalloc(fs_devices->rw_devices, sizeof(*devices_info), - GFP_NOFS); - if (!devices_info) - return -ENOMEM; - - cur = fs_devices->alloc_list.next; - - /* - * in the first pass through the devices list, we gather information - * about the available holes on each device. - */ - ndevs = 0; - while (cur != &fs_devices->alloc_list) { - struct btrfs_device *device; - u64 max_avail; - u64 dev_offset; - - device = list_entry(cur, struct btrfs_device, dev_alloc_list); - - cur = cur->next; - - if (!device->writeable) { - WARN(1, KERN_ERR - "BTRFS: read-only device in alloc_list\n"); - continue; - } - - if (!device->in_fs_metadata || - device->is_tgtdev_for_dev_replace) - continue; - - if (device->total_bytes > device->bytes_used) - total_avail = device->total_bytes - device->bytes_used; - else - total_avail = 0; - - /* If there is no space on this device, skip it. */ - if (total_avail == 0) - continue; - - ret = find_free_dev_extent(trans, device, - max_stripe_size * dev_stripes, - &dev_offset, &max_avail); - if (ret && ret != -ENOSPC) - goto error; - - if (ret == 0) - max_avail = max_stripe_size * dev_stripes; - - if (max_avail < BTRFS_STRIPE_LEN * dev_stripes) - continue; - - if (ndevs == fs_devices->rw_devices) { - WARN(1, "%s: found more than %llu devices\n", - __func__, fs_devices->rw_devices); - break; - } - devices_info[ndevs].dev_offset = dev_offset; - devices_info[ndevs].max_avail = max_avail; - devices_info[ndevs].total_avail = total_avail; - devices_info[ndevs].dev = device; - ++ndevs; - } - - /* - * now sort the devices by hole size / available space - */ - sort(devices_info, ndevs, sizeof(struct btrfs_device_info), - btrfs_cmp_device_info, NULL); - - /* round down to number of usable stripes */ - ndevs -= ndevs % devs_increment; - - if (ndevs < devs_increment * sub_stripes || ndevs < devs_min) { - ret = -ENOSPC; - goto error; - } - - if (devs_max && ndevs > devs_max) - ndevs = devs_max; - /* - * the primary goal is to maximize the number of stripes, so use as many - * devices as possible, even if the stripes are not maximum sized. - */ - stripe_size = devices_info[ndevs-1].max_avail; - num_stripes = ndevs * dev_stripes; - - /* - * this will have to be fixed for RAID1 and RAID10 over - * more drives - */ - data_stripes = num_stripes / ncopies; - - if (type & BTRFS_BLOCK_GROUP_RAID5) { - raid_stripe_len = find_raid56_stripe_len(ndevs - 1, - extent_root->stripesize); - data_stripes = num_stripes - 1; - } - if (type & BTRFS_BLOCK_GROUP_RAID6) { - raid_stripe_len = find_raid56_stripe_len(ndevs - 2, - extent_root->stripesize); - data_stripes = num_stripes - 2; - } - - /* - * Use the number of data stripes to figure out how big this chunk - * is really going to be in terms of logical address space, - * and compare that answer with the max chunk size - */ - if (stripe_size * data_stripes > max_chunk_size) { - u64 mask = (1ULL << 24) - 1; - - stripe_size = div_u64(max_chunk_size, data_stripes); - - /* bump the answer up to a 16MB boundary */ - stripe_size = (stripe_size + mask) & ~mask; - - /* but don't go higher than the limits we found - * while searching for free extents - */ - if (stripe_size > devices_info[ndevs-1].max_avail) - stripe_size = devices_info[ndevs-1].max_avail; - } - - stripe_size = div_u64(stripe_size, dev_stripes); - - /* align to BTRFS_STRIPE_LEN */ - stripe_size = div_u64(stripe_size, raid_stripe_len); - stripe_size *= raid_stripe_len; - - map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS); - if (!map) { - ret = -ENOMEM; - goto error; - } - map->num_stripes = num_stripes; - - for (i = 0; i < ndevs; ++i) { - for (j = 0; j < dev_stripes; ++j) { - int s = i * dev_stripes + j; - map->stripes[s].dev = devices_info[i].dev; - map->stripes[s].physical = devices_info[i].dev_offset + - j * stripe_size; - } - } - map->sector_size = extent_root->sectorsize; - map->stripe_len = raid_stripe_len; - map->io_align = raid_stripe_len; - map->io_width = raid_stripe_len; - map->type = type; - map->sub_stripes = sub_stripes; - - num_bytes = stripe_size * data_stripes; - - trace_btrfs_chunk_alloc(info->chunk_root, map, start, num_bytes); - - em = alloc_extent_map(); - if (!em) { - kfree(map); - ret = -ENOMEM; - goto error; - } - set_bit(EXTENT_FLAG_FS_MAPPING, &em->flags); - em->map_lookup = map; - em->start = start; - em->len = num_bytes; - em->block_start = 0; - em->block_len = em->len; - em->orig_block_len = stripe_size; - - em_tree = &extent_root->fs_info->mapping_tree.map_tree; - write_lock(&em_tree->lock); - ret = add_extent_mapping(em_tree, em, 0); - if (!ret) { - list_add_tail(&em->list, &trans->transaction->pending_chunks); - atomic_inc(&em->refs); - } - write_unlock(&em_tree->lock); - if (ret) { - free_extent_map(em); - goto error; - } - - ret = btrfs_make_block_group(trans, extent_root, 0, type, - BTRFS_FIRST_CHUNK_TREE_OBJECTID, - start, num_bytes); - if (ret) - goto error_del_extent; - - for (i = 0; i < map->num_stripes; i++) { - num_bytes = map->stripes[i].dev->bytes_used + stripe_size; - btrfs_device_set_bytes_used(map->stripes[i].dev, num_bytes); - } - - spin_lock(&extent_root->fs_info->free_chunk_lock); - extent_root->fs_info->free_chunk_space -= (stripe_size * - map->num_stripes); - spin_unlock(&extent_root->fs_info->free_chunk_lock); - - free_extent_map(em); - check_raid56_incompat_flag(extent_root->fs_info, type); - - kfree(devices_info); - return 0; - -error_del_extent: - write_lock(&em_tree->lock); - remove_extent_mapping(em_tree, em); - write_unlock(&em_tree->lock); - - /* One for our allocation */ - free_extent_map(em); - /* One for the tree reference */ - free_extent_map(em); - /* One for the pending_chunks list reference */ - free_extent_map(em); -error: - kfree(devices_info); - return ret; -} - -int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans, - struct btrfs_root *extent_root, - u64 chunk_offset, u64 chunk_size) -{ - struct btrfs_key key; - struct btrfs_root *chunk_root = extent_root->fs_info->chunk_root; - struct btrfs_device *device; - struct btrfs_chunk *chunk; - struct btrfs_stripe *stripe; - struct extent_map_tree *em_tree; - struct extent_map *em; - struct map_lookup *map; - size_t item_size; - u64 dev_offset; - u64 stripe_size; - int i = 0; - int ret = 0; - - em_tree = &extent_root->fs_info->mapping_tree.map_tree; - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, chunk_offset, chunk_size); - read_unlock(&em_tree->lock); - - if (!em) { - btrfs_crit(extent_root->fs_info, - "unable to find logical %Lu len %Lu", - chunk_offset, chunk_size); - return -EINVAL; - } - - if (em->start != chunk_offset || em->len != chunk_size) { - btrfs_crit(extent_root->fs_info, - "found a bad mapping, wanted %Lu-%Lu, found %Lu-%Lu", - chunk_offset, chunk_size, em->start, em->len); - free_extent_map(em); - return -EINVAL; - } - - map = em->map_lookup; - item_size = btrfs_chunk_item_size(map->num_stripes); - stripe_size = em->orig_block_len; - - chunk = kzalloc(item_size, GFP_NOFS); - if (!chunk) { - ret = -ENOMEM; - goto out; - } - - /* - * Take the device list mutex to prevent races with the final phase of - * a device replace operation that replaces the device object associated - * with the map's stripes, because the device object's id can change - * at any time during that final phase of the device replace operation - * (dev-replace.c:btrfs_dev_replace_finishing()). - */ - mutex_lock(&chunk_root->fs_info->fs_devices->device_list_mutex); - for (i = 0; i < map->num_stripes; i++) { - device = map->stripes[i].dev; - dev_offset = map->stripes[i].physical; - - ret = btrfs_update_device(trans, device); - if (ret) - break; - ret = btrfs_alloc_dev_extent(trans, device, - chunk_root->root_key.objectid, - BTRFS_FIRST_CHUNK_TREE_OBJECTID, - chunk_offset, dev_offset, - stripe_size); - if (ret) - break; - } - if (ret) { - mutex_unlock(&chunk_root->fs_info->fs_devices->device_list_mutex); - goto out; - } - - stripe = &chunk->stripe; - for (i = 0; i < map->num_stripes; i++) { - device = map->stripes[i].dev; - dev_offset = map->stripes[i].physical; - - btrfs_set_stack_stripe_devid(stripe, device->devid); - btrfs_set_stack_stripe_offset(stripe, dev_offset); - memcpy(stripe->dev_uuid, device->uuid, BTRFS_UUID_SIZE); - stripe++; - } - mutex_unlock(&chunk_root->fs_info->fs_devices->device_list_mutex); - - btrfs_set_stack_chunk_length(chunk, chunk_size); - btrfs_set_stack_chunk_owner(chunk, extent_root->root_key.objectid); - btrfs_set_stack_chunk_stripe_len(chunk, map->stripe_len); - btrfs_set_stack_chunk_type(chunk, map->type); - btrfs_set_stack_chunk_num_stripes(chunk, map->num_stripes); - btrfs_set_stack_chunk_io_align(chunk, map->stripe_len); - btrfs_set_stack_chunk_io_width(chunk, map->stripe_len); - btrfs_set_stack_chunk_sector_size(chunk, extent_root->sectorsize); - btrfs_set_stack_chunk_sub_stripes(chunk, map->sub_stripes); - - key.objectid = BTRFS_FIRST_CHUNK_TREE_OBJECTID; - key.type = BTRFS_CHUNK_ITEM_KEY; - key.offset = chunk_offset; - - ret = btrfs_insert_item(trans, chunk_root, &key, chunk, item_size); - if (ret == 0 && map->type & BTRFS_BLOCK_GROUP_SYSTEM) { - /* - * TODO: Cleanup of inserted chunk root in case of - * failure. - */ - ret = btrfs_add_system_chunk(chunk_root, &key, chunk, - item_size); - } - -out: - kfree(chunk); - free_extent_map(em); - return ret; -} - -/* - * Chunk allocation falls into two parts. The first part does works - * that make the new allocated chunk useable, but not do any operation - * that modifies the chunk tree. The second part does the works that - * require modifying the chunk tree. This division is important for the - * bootstrap process of adding storage to a seed btrfs. - */ -int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, - struct btrfs_root *extent_root, u64 type) -{ - u64 chunk_offset; - - ASSERT(mutex_is_locked(&extent_root->fs_info->chunk_mutex)); - chunk_offset = find_next_chunk(extent_root->fs_info); - return __btrfs_alloc_chunk(trans, extent_root, chunk_offset, type); -} - -static noinline int init_first_rw_device(struct btrfs_trans_handle *trans, - struct btrfs_root *root, - struct btrfs_device *device) -{ - u64 chunk_offset; - u64 sys_chunk_offset; - u64 alloc_profile; - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_root *extent_root = fs_info->extent_root; - int ret; - - chunk_offset = find_next_chunk(fs_info); - alloc_profile = btrfs_get_alloc_profile(extent_root, 0); - ret = __btrfs_alloc_chunk(trans, extent_root, chunk_offset, - alloc_profile); - if (ret) - return ret; - - sys_chunk_offset = find_next_chunk(root->fs_info); - alloc_profile = btrfs_get_alloc_profile(fs_info->chunk_root, 0); - ret = __btrfs_alloc_chunk(trans, extent_root, sys_chunk_offset, - alloc_profile); - return ret; -} - -static inline int btrfs_chunk_max_errors(struct map_lookup *map) -{ - int max_errors; - - if (map->type & (BTRFS_BLOCK_GROUP_RAID1 | - BTRFS_BLOCK_GROUP_RAID10 | - BTRFS_BLOCK_GROUP_RAID5 | - BTRFS_BLOCK_GROUP_DUP)) { - max_errors = 1; - } else if (map->type & BTRFS_BLOCK_GROUP_RAID6) { - max_errors = 2; - } else { - max_errors = 0; - } - - return max_errors; -} - -int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset) -{ - struct extent_map *em; - struct map_lookup *map; - struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; - int readonly = 0; - int miss_ndevs = 0; - int i; - - read_lock(&map_tree->map_tree.lock); - em = lookup_extent_mapping(&map_tree->map_tree, chunk_offset, 1); - read_unlock(&map_tree->map_tree.lock); - if (!em) - return 1; - - map = em->map_lookup; - for (i = 0; i < map->num_stripes; i++) { - if (map->stripes[i].dev->missing) { - miss_ndevs++; - continue; - } - - if (!map->stripes[i].dev->writeable) { - readonly = 1; - goto end; - } - } - - /* - * If the number of missing devices is larger than max errors, - * we can not write the data into that chunk successfully, so - * set it readonly. - */ - if (miss_ndevs > btrfs_chunk_max_errors(map)) - readonly = 1; -end: - free_extent_map(em); - return readonly; -} - -void btrfs_mapping_init(struct btrfs_mapping_tree *tree) -{ - extent_map_tree_init(&tree->map_tree); -} - -void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree) -{ - struct extent_map *em; - - while (1) { - write_lock(&tree->map_tree.lock); - em = lookup_extent_mapping(&tree->map_tree, 0, (u64)-1); - if (em) - remove_extent_mapping(&tree->map_tree, em); - write_unlock(&tree->map_tree.lock); - if (!em) - break; - /* once for us */ - free_extent_map(em); - /* once for the tree */ - free_extent_map(em); - } -} - -int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len) -{ - struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; - struct extent_map *em; - struct map_lookup *map; - struct extent_map_tree *em_tree = &map_tree->map_tree; - int ret; - - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, logical, len); - read_unlock(&em_tree->lock); - - /* - * We could return errors for these cases, but that could get ugly and - * we'd probably do the same thing which is just not do anything else - * and exit, so return 1 so the callers don't try to use other copies. - */ - if (!em) { - btrfs_crit(fs_info, "No mapping for %Lu-%Lu", logical, - logical+len); - return 1; - } - - if (em->start > logical || em->start + em->len < logical) { - btrfs_crit(fs_info, "Invalid mapping for %Lu-%Lu, got %Lu-%Lu", - logical, logical+len, em->start, - em->start + em->len); - free_extent_map(em); - return 1; - } - - map = em->map_lookup; - if (map->type & (BTRFS_BLOCK_GROUP_DUP | BTRFS_BLOCK_GROUP_RAID1)) - ret = map->num_stripes; - else if (map->type & BTRFS_BLOCK_GROUP_RAID10) - ret = map->sub_stripes; - else if (map->type & BTRFS_BLOCK_GROUP_RAID5) - ret = 2; - else if (map->type & BTRFS_BLOCK_GROUP_RAID6) - ret = 3; - else - ret = 1; - free_extent_map(em); - - btrfs_dev_replace_lock(&fs_info->dev_replace, 0); - if (btrfs_dev_replace_is_ongoing(&fs_info->dev_replace)) - ret++; - btrfs_dev_replace_unlock(&fs_info->dev_replace, 0); - - return ret; -} - -unsigned long btrfs_full_stripe_len(struct btrfs_root *root, - struct btrfs_mapping_tree *map_tree, - u64 logical) -{ - struct extent_map *em; - struct map_lookup *map; - struct extent_map_tree *em_tree = &map_tree->map_tree; - unsigned long len = root->sectorsize; - - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, logical, len); - read_unlock(&em_tree->lock); - BUG_ON(!em); - - BUG_ON(em->start > logical || em->start + em->len < logical); - map = em->map_lookup; - if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) - len = map->stripe_len * nr_data_stripes(map); - free_extent_map(em); - return len; -} - -int btrfs_is_parity_mirror(struct btrfs_mapping_tree *map_tree, - u64 logical, u64 len, int mirror_num) -{ - struct extent_map *em; - struct map_lookup *map; - struct extent_map_tree *em_tree = &map_tree->map_tree; - int ret = 0; - - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, logical, len); - read_unlock(&em_tree->lock); - BUG_ON(!em); - - BUG_ON(em->start > logical || em->start + em->len < logical); - map = em->map_lookup; - if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) - ret = 1; - free_extent_map(em); - return ret; -} - -static int find_live_mirror(struct btrfs_fs_info *fs_info, - struct map_lookup *map, int first, int num, - int optimal, int dev_replace_is_ongoing) -{ - int i; - int tolerance; - struct btrfs_device *srcdev; - - if (dev_replace_is_ongoing && - fs_info->dev_replace.cont_reading_from_srcdev_mode == - BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_AVOID) - srcdev = fs_info->dev_replace.srcdev; - else - srcdev = NULL; - - /* - * try to avoid the drive that is the source drive for a - * dev-replace procedure, only choose it if no other non-missing - * mirror is available - */ - for (tolerance = 0; tolerance < 2; tolerance++) { - if (map->stripes[optimal].dev->bdev && - (tolerance || map->stripes[optimal].dev != srcdev)) - return optimal; - for (i = first; i < first + num; i++) { - if (map->stripes[i].dev->bdev && - (tolerance || map->stripes[i].dev != srcdev)) - return i; - } - } - - /* we couldn't find one that doesn't fail. Just return something - * and the io error handling code will clean up eventually - */ - return optimal; -} - -static inline int parity_smaller(u64 a, u64 b) -{ - return a > b; -} - -/* Bubble-sort the stripe set to put the parity/syndrome stripes last */ -static void sort_parity_stripes(struct btrfs_bio *bbio, int num_stripes) -{ - struct btrfs_bio_stripe s; - int i; - u64 l; - int again = 1; - - while (again) { - again = 0; - for (i = 0; i < num_stripes - 1; i++) { - if (parity_smaller(bbio->raid_map[i], - bbio->raid_map[i+1])) { - s = bbio->stripes[i]; - l = bbio->raid_map[i]; - bbio->stripes[i] = bbio->stripes[i+1]; - bbio->raid_map[i] = bbio->raid_map[i+1]; - bbio->stripes[i+1] = s; - bbio->raid_map[i+1] = l; - - again = 1; - } - } - } -} - -static struct btrfs_bio *alloc_btrfs_bio(int total_stripes, int real_stripes) -{ - struct btrfs_bio *bbio = kzalloc( - /* the size of the btrfs_bio */ - sizeof(struct btrfs_bio) + - /* plus the variable array for the stripes */ - sizeof(struct btrfs_bio_stripe) * (total_stripes) + - /* plus the variable array for the tgt dev */ - sizeof(int) * (real_stripes) + - /* - * plus the raid_map, which includes both the tgt dev - * and the stripes - */ - sizeof(u64) * (total_stripes), - GFP_NOFS|__GFP_NOFAIL); - - atomic_set(&bbio->error, 0); - atomic_set(&bbio->refs, 1); - - return bbio; -} - -void btrfs_get_bbio(struct btrfs_bio *bbio) -{ - WARN_ON(!atomic_read(&bbio->refs)); - atomic_inc(&bbio->refs); -} - -void btrfs_put_bbio(struct btrfs_bio *bbio) -{ - if (!bbio) - return; - if (atomic_dec_and_test(&bbio->refs)) - kfree(bbio); -} - -static int __btrfs_map_block(struct btrfs_fs_info *fs_info, int op, - u64 logical, u64 *length, - struct btrfs_bio **bbio_ret, - int mirror_num, int need_raid_map) -{ - struct extent_map *em; - struct map_lookup *map; - struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; - struct extent_map_tree *em_tree = &map_tree->map_tree; - u64 offset; - u64 stripe_offset; - u64 stripe_end_offset; - u64 stripe_nr; - u64 stripe_nr_orig; - u64 stripe_nr_end; - u64 stripe_len; - u32 stripe_index; - int i; - int ret = 0; - int num_stripes; - int max_errors = 0; - int tgtdev_indexes = 0; - struct btrfs_bio *bbio = NULL; - struct btrfs_dev_replace *dev_replace = &fs_info->dev_replace; - int dev_replace_is_ongoing = 0; - int num_alloc_stripes; - int patch_the_first_stripe_for_dev_replace = 0; - u64 physical_to_patch_in_first_stripe = 0; - u64 raid56_full_stripe_start = (u64)-1; - - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, logical, *length); - read_unlock(&em_tree->lock); - - if (!em) { - btrfs_crit(fs_info, "unable to find logical %llu len %llu", - logical, *length); - return -EINVAL; - } - - if (em->start > logical || em->start + em->len < logical) { - btrfs_crit(fs_info, - "found a bad mapping, wanted %Lu, found %Lu-%Lu", - logical, em->start, em->start + em->len); - free_extent_map(em); - return -EINVAL; - } - - map = em->map_lookup; - offset = logical - em->start; - - stripe_len = map->stripe_len; - stripe_nr = offset; - /* - * stripe_nr counts the total number of stripes we have to stride - * to get to this block - */ - stripe_nr = div64_u64(stripe_nr, stripe_len); - - stripe_offset = stripe_nr * stripe_len; - if (offset < stripe_offset) { - btrfs_crit(fs_info, - "stripe math has gone wrong, stripe_offset=%llu, offset=%llu, start=%llu, logical=%llu, stripe_len=%llu", - stripe_offset, offset, em->start, logical, - stripe_len); - free_extent_map(em); - return -EINVAL; - } - - /* stripe_offset is the offset of this block in its stripe*/ - stripe_offset = offset - stripe_offset; - - /* if we're here for raid56, we need to know the stripe aligned start */ - if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) { - unsigned long full_stripe_len = stripe_len * nr_data_stripes(map); - raid56_full_stripe_start = offset; - - /* allow a write of a full stripe, but make sure we don't - * allow straddling of stripes - */ - raid56_full_stripe_start = div64_u64(raid56_full_stripe_start, - full_stripe_len); - raid56_full_stripe_start *= full_stripe_len; - } - - if (op == REQ_OP_DISCARD) { - /* we don't discard raid56 yet */ - if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) { - ret = -EOPNOTSUPP; - goto out; - } - *length = min_t(u64, em->len - offset, *length); - } else if (map->type & BTRFS_BLOCK_GROUP_PROFILE_MASK) { - u64 max_len; - /* For writes to RAID[56], allow a full stripeset across all disks. - For other RAID types and for RAID[56] reads, just allow a single - stripe (on a single disk). */ - if ((map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) && - (op == REQ_OP_WRITE)) { - max_len = stripe_len * nr_data_stripes(map) - - (offset - raid56_full_stripe_start); - } else { - /* we limit the length of each bio to what fits in a stripe */ - max_len = stripe_len - stripe_offset; - } - *length = min_t(u64, em->len - offset, max_len); - } else { - *length = em->len - offset; - } - - /* This is for when we're called from btrfs_merge_bio_hook() and all - it cares about is the length */ - if (!bbio_ret) - goto out; - - btrfs_dev_replace_lock(dev_replace, 0); - dev_replace_is_ongoing = btrfs_dev_replace_is_ongoing(dev_replace); - if (!dev_replace_is_ongoing) - btrfs_dev_replace_unlock(dev_replace, 0); - else - btrfs_dev_replace_set_lock_blocking(dev_replace); - - if (dev_replace_is_ongoing && mirror_num == map->num_stripes + 1 && - op != REQ_OP_WRITE && op != REQ_OP_DISCARD && - op != REQ_GET_READ_MIRRORS && dev_replace->tgtdev != NULL) { - /* - * in dev-replace case, for repair case (that's the only - * case where the mirror is selected explicitly when - * calling btrfs_map_block), blocks left of the left cursor - * can also be read from the target drive. - * For REQ_GET_READ_MIRRORS, the target drive is added as - * the last one to the array of stripes. For READ, it also - * needs to be supported using the same mirror number. - * If the requested block is not left of the left cursor, - * EIO is returned. This can happen because btrfs_num_copies() - * returns one more in the dev-replace case. - */ - u64 tmp_length = *length; - struct btrfs_bio *tmp_bbio = NULL; - int tmp_num_stripes; - u64 srcdev_devid = dev_replace->srcdev->devid; - int index_srcdev = 0; - int found = 0; - u64 physical_of_found = 0; - - ret = __btrfs_map_block(fs_info, REQ_GET_READ_MIRRORS, - logical, &tmp_length, &tmp_bbio, 0, 0); - if (ret) { - WARN_ON(tmp_bbio != NULL); - goto out; - } - - tmp_num_stripes = tmp_bbio->num_stripes; - if (mirror_num > tmp_num_stripes) { - /* - * REQ_GET_READ_MIRRORS does not contain this - * mirror, that means that the requested area - * is not left of the left cursor - */ - ret = -EIO; - btrfs_put_bbio(tmp_bbio); - goto out; - } - - /* - * process the rest of the function using the mirror_num - * of the source drive. Therefore look it up first. - * At the end, patch the device pointer to the one of the - * target drive. - */ - for (i = 0; i < tmp_num_stripes; i++) { - if (tmp_bbio->stripes[i].dev->devid != srcdev_devid) - continue; - - /* - * In case of DUP, in order to keep it simple, only add - * the mirror with the lowest physical address - */ - if (found && - physical_of_found <= tmp_bbio->stripes[i].physical) - continue; - - index_srcdev = i; - found = 1; - physical_of_found = tmp_bbio->stripes[i].physical; - } - - btrfs_put_bbio(tmp_bbio); - - if (!found) { - WARN_ON(1); - ret = -EIO; - goto out; - } - - mirror_num = index_srcdev + 1; - patch_the_first_stripe_for_dev_replace = 1; - physical_to_patch_in_first_stripe = physical_of_found; - } else if (mirror_num > map->num_stripes) { - mirror_num = 0; - } - - num_stripes = 1; - stripe_index = 0; - stripe_nr_orig = stripe_nr; - stripe_nr_end = ALIGN(offset + *length, map->stripe_len); - stripe_nr_end = div_u64(stripe_nr_end, map->stripe_len); - stripe_end_offset = stripe_nr_end * map->stripe_len - - (offset + *length); - - if (map->type & BTRFS_BLOCK_GROUP_RAID0) { - if (op == REQ_OP_DISCARD) - num_stripes = min_t(u64, map->num_stripes, - stripe_nr_end - stripe_nr_orig); - stripe_nr = div_u64_rem(stripe_nr, map->num_stripes, - &stripe_index); - if (op != REQ_OP_WRITE && op != REQ_OP_DISCARD && - op != REQ_GET_READ_MIRRORS) - mirror_num = 1; - } else if (map->type & BTRFS_BLOCK_GROUP_RAID1) { - if (op == REQ_OP_WRITE || op == REQ_OP_DISCARD || - op == REQ_GET_READ_MIRRORS) - num_stripes = map->num_stripes; - else if (mirror_num) - stripe_index = mirror_num - 1; - else { - stripe_index = find_live_mirror(fs_info, map, 0, - map->num_stripes, - current->pid % map->num_stripes, - dev_replace_is_ongoing); - mirror_num = stripe_index + 1; - } - - } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { - if (op == REQ_OP_WRITE || op == REQ_OP_DISCARD || - op == REQ_GET_READ_MIRRORS) { - num_stripes = map->num_stripes; - } else if (mirror_num) { - stripe_index = mirror_num - 1; - } else { - mirror_num = 1; - } - - } else if (map->type & BTRFS_BLOCK_GROUP_RAID10) { - u32 factor = map->num_stripes / map->sub_stripes; - - stripe_nr = div_u64_rem(stripe_nr, factor, &stripe_index); - stripe_index *= map->sub_stripes; - - if (op == REQ_OP_WRITE || op == REQ_GET_READ_MIRRORS) - num_stripes = map->sub_stripes; - else if (op == REQ_OP_DISCARD) - num_stripes = min_t(u64, map->sub_stripes * - (stripe_nr_end - stripe_nr_orig), - map->num_stripes); - else if (mirror_num) - stripe_index += mirror_num - 1; - else { - int old_stripe_index = stripe_index; - stripe_index = find_live_mirror(fs_info, map, - stripe_index, - map->sub_stripes, stripe_index + - current->pid % map->sub_stripes, - dev_replace_is_ongoing); - mirror_num = stripe_index - old_stripe_index + 1; - } - - } else if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) { - if (need_raid_map && - (op == REQ_OP_WRITE || op == REQ_GET_READ_MIRRORS || - mirror_num > 1)) { - /* push stripe_nr back to the start of the full stripe */ - stripe_nr = div_u64(raid56_full_stripe_start, - stripe_len * nr_data_stripes(map)); - - /* RAID[56] write or recovery. Return all stripes */ - num_stripes = map->num_stripes; - max_errors = nr_parity_stripes(map); - - *length = map->stripe_len; - stripe_index = 0; - stripe_offset = 0; - } else { - /* - * Mirror #0 or #1 means the original data block. - * Mirror #2 is RAID5 parity block. - * Mirror #3 is RAID6 Q block. - */ - stripe_nr = div_u64_rem(stripe_nr, - nr_data_stripes(map), &stripe_index); - if (mirror_num > 1) - stripe_index = nr_data_stripes(map) + - mirror_num - 2; - - /* We distribute the parity blocks across stripes */ - div_u64_rem(stripe_nr + stripe_index, map->num_stripes, - &stripe_index); - if ((op != REQ_OP_WRITE && op != REQ_OP_DISCARD && - op != REQ_GET_READ_MIRRORS) && mirror_num <= 1) - mirror_num = 1; - } - } else { - /* - * after this, stripe_nr is the number of stripes on this - * device we have to walk to find the data, and stripe_index is - * the number of our device in the stripe array - */ - stripe_nr = div_u64_rem(stripe_nr, map->num_stripes, - &stripe_index); - mirror_num = stripe_index + 1; - } - if (stripe_index >= map->num_stripes) { - btrfs_crit(fs_info, - "stripe index math went horribly wrong, got stripe_index=%u, num_stripes=%u", - stripe_index, map->num_stripes); - ret = -EINVAL; - goto out; - } - - num_alloc_stripes = num_stripes; - if (dev_replace_is_ongoing) { - if (op == REQ_OP_WRITE || op == REQ_OP_DISCARD) - num_alloc_stripes <<= 1; - if (op == REQ_GET_READ_MIRRORS) - num_alloc_stripes++; - tgtdev_indexes = num_stripes; - } - - bbio = alloc_btrfs_bio(num_alloc_stripes, tgtdev_indexes); - if (!bbio) { - ret = -ENOMEM; - goto out; - } - if (dev_replace_is_ongoing) - bbio->tgtdev_map = (int *)(bbio->stripes + num_alloc_stripes); - - /* build raid_map */ - if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK && - need_raid_map && - ((op == REQ_OP_WRITE || op == REQ_GET_READ_MIRRORS) || - mirror_num > 1)) { - u64 tmp; - unsigned rot; - - bbio->raid_map = (u64 *)((void *)bbio->stripes + - sizeof(struct btrfs_bio_stripe) * - num_alloc_stripes + - sizeof(int) * tgtdev_indexes); - - /* Work out the disk rotation on this stripe-set */ - div_u64_rem(stripe_nr, num_stripes, &rot); - - /* Fill in the logical address of each stripe */ - tmp = stripe_nr * nr_data_stripes(map); - for (i = 0; i < nr_data_stripes(map); i++) - bbio->raid_map[(i+rot) % num_stripes] = - em->start + (tmp + i) * map->stripe_len; - - bbio->raid_map[(i+rot) % map->num_stripes] = RAID5_P_STRIPE; - if (map->type & BTRFS_BLOCK_GROUP_RAID6) - bbio->raid_map[(i+rot+1) % num_stripes] = - RAID6_Q_STRIPE; - } - - if (op == REQ_OP_DISCARD) { - u32 factor = 0; - u32 sub_stripes = 0; - u64 stripes_per_dev = 0; - u32 remaining_stripes = 0; - u32 last_stripe = 0; - - if (map->type & - (BTRFS_BLOCK_GROUP_RAID0 | BTRFS_BLOCK_GROUP_RAID10)) { - if (map->type & BTRFS_BLOCK_GROUP_RAID0) - sub_stripes = 1; - else - sub_stripes = map->sub_stripes; - - factor = map->num_stripes / sub_stripes; - stripes_per_dev = div_u64_rem(stripe_nr_end - - stripe_nr_orig, - factor, - &remaining_stripes); - div_u64_rem(stripe_nr_end - 1, factor, &last_stripe); - last_stripe *= sub_stripes; - } - - for (i = 0; i < num_stripes; i++) { - bbio->stripes[i].physical = - map->stripes[stripe_index].physical + - stripe_offset + stripe_nr * map->stripe_len; - bbio->stripes[i].dev = map->stripes[stripe_index].dev; - - if (map->type & (BTRFS_BLOCK_GROUP_RAID0 | - BTRFS_BLOCK_GROUP_RAID10)) { - bbio->stripes[i].length = stripes_per_dev * - map->stripe_len; - - if (i / sub_stripes < remaining_stripes) - bbio->stripes[i].length += - map->stripe_len; - - /* - * Special for the first stripe and - * the last stripe: - * - * |-------|...|-------| - * |----------| - * off end_off - */ - if (i < sub_stripes) - bbio->stripes[i].length -= - stripe_offset; - - if (stripe_index >= last_stripe && - stripe_index <= (last_stripe + - sub_stripes - 1)) - bbio->stripes[i].length -= - stripe_end_offset; - - if (i == sub_stripes - 1) - stripe_offset = 0; - } else - bbio->stripes[i].length = *length; - - stripe_index++; - if (stripe_index == map->num_stripes) { - /* This could only happen for RAID0/10 */ - stripe_index = 0; - stripe_nr++; - } - } - } else { - for (i = 0; i < num_stripes; i++) { - bbio->stripes[i].physical = - map->stripes[stripe_index].physical + - stripe_offset + - stripe_nr * map->stripe_len; - bbio->stripes[i].dev = - map->stripes[stripe_index].dev; - stripe_index++; - } - } - - if (op == REQ_OP_WRITE || op == REQ_GET_READ_MIRRORS) - max_errors = btrfs_chunk_max_errors(map); - - if (bbio->raid_map) - sort_parity_stripes(bbio, num_stripes); - - tgtdev_indexes = 0; - if (dev_replace_is_ongoing && - (op == REQ_OP_WRITE || op == REQ_OP_DISCARD) && - dev_replace->tgtdev != NULL) { - int index_where_to_add; - u64 srcdev_devid = dev_replace->srcdev->devid; - - /* - * duplicate the write operations while the dev replace - * procedure is running. Since the copying of the old disk - * to the new disk takes place at run time while the - * filesystem is mounted writable, the regular write - * operations to the old disk have to be duplicated to go - * to the new disk as well. - * Note that device->missing is handled by the caller, and - * that the write to the old disk is already set up in the - * stripes array. - */ - index_where_to_add = num_stripes; - for (i = 0; i < num_stripes; i++) { - if (bbio->stripes[i].dev->devid == srcdev_devid) { - /* write to new disk, too */ - struct btrfs_bio_stripe *new = - bbio->stripes + index_where_to_add; - struct btrfs_bio_stripe *old = - bbio->stripes + i; - - new->physical = old->physical; - new->length = old->length; - new->dev = dev_replace->tgtdev; - bbio->tgtdev_map[i] = index_where_to_add; - index_where_to_add++; - max_errors++; - tgtdev_indexes++; - } - } - num_stripes = index_where_to_add; - } else if (dev_replace_is_ongoing && (op == REQ_GET_READ_MIRRORS) && - dev_replace->tgtdev != NULL) { - u64 srcdev_devid = dev_replace->srcdev->devid; - int index_srcdev = 0; - int found = 0; - u64 physical_of_found = 0; - - /* - * During the dev-replace procedure, the target drive can - * also be used to read data in case it is needed to repair - * a corrupt block elsewhere. This is possible if the - * requested area is left of the left cursor. In this area, - * the target drive is a full copy of the source drive. - */ - for (i = 0; i < num_stripes; i++) { - if (bbio->stripes[i].dev->devid == srcdev_devid) { - /* - * In case of DUP, in order to keep it - * simple, only add the mirror with the - * lowest physical address - */ - if (found && - physical_of_found <= - bbio->stripes[i].physical) - continue; - index_srcdev = i; - found = 1; - physical_of_found = bbio->stripes[i].physical; - } - } - if (found) { - struct btrfs_bio_stripe *tgtdev_stripe = - bbio->stripes + num_stripes; - - tgtdev_stripe->physical = physical_of_found; - tgtdev_stripe->length = - bbio->stripes[index_srcdev].length; - tgtdev_stripe->dev = dev_replace->tgtdev; - bbio->tgtdev_map[index_srcdev] = num_stripes; - - tgtdev_indexes++; - num_stripes++; - } - } - - *bbio_ret = bbio; - bbio->map_type = map->type; - bbio->num_stripes = num_stripes; - bbio->max_errors = max_errors; - bbio->mirror_num = mirror_num; - bbio->num_tgtdevs = tgtdev_indexes; - - /* - * this is the case that REQ_READ && dev_replace_is_ongoing && - * mirror_num == num_stripes + 1 && dev_replace target drive is - * available as a mirror - */ - if (patch_the_first_stripe_for_dev_replace && num_stripes > 0) { - WARN_ON(num_stripes > 1); - bbio->stripes[0].dev = dev_replace->tgtdev; - bbio->stripes[0].physical = physical_to_patch_in_first_stripe; - bbio->mirror_num = map->num_stripes + 1; - } -out: - if (dev_replace_is_ongoing) { - btrfs_dev_replace_clear_lock_blocking(dev_replace); - btrfs_dev_replace_unlock(dev_replace, 0); - } - free_extent_map(em); - return ret; -} - -int btrfs_map_block(struct btrfs_fs_info *fs_info, int op, - u64 logical, u64 *length, - struct btrfs_bio **bbio_ret, int mirror_num) -{ - return __btrfs_map_block(fs_info, op, logical, length, bbio_ret, - mirror_num, 0); -} - -/* For Scrub/replace */ -int btrfs_map_sblock(struct btrfs_fs_info *fs_info, int op, - u64 logical, u64 *length, - struct btrfs_bio **bbio_ret, int mirror_num, - int need_raid_map) -{ - return __btrfs_map_block(fs_info, op, logical, length, bbio_ret, - mirror_num, need_raid_map); -} - -int btrfs_rmap_block(struct btrfs_fs_info *fs_info, - u64 chunk_start, u64 physical, u64 devid, - u64 **logical, int *naddrs, int *stripe_len) -{ - struct btrfs_mapping_tree *map_tree = &fs_info->mapping_tree; - struct extent_map_tree *em_tree = &map_tree->map_tree; - struct extent_map *em; - struct map_lookup *map; - u64 *buf; - u64 bytenr; - u64 length; - u64 stripe_nr; - u64 rmap_len; - int i, j, nr = 0; - - read_lock(&em_tree->lock); - em = lookup_extent_mapping(em_tree, chunk_start, 1); - read_unlock(&em_tree->lock); - - if (!em) { - btrfs_err(fs_info, "couldn't find em for chunk %Lu", - chunk_start); - return -EIO; - } - - if (em->start != chunk_start) { - btrfs_err(fs_info, "bad chunk start, em=%Lu, wanted=%Lu", - em->start, chunk_start); - free_extent_map(em); - return -EIO; - } - map = em->map_lookup; - - length = em->len; - rmap_len = map->stripe_len; - - if (map->type & BTRFS_BLOCK_GROUP_RAID10) - length = div_u64(length, map->num_stripes / map->sub_stripes); - else if (map->type & BTRFS_BLOCK_GROUP_RAID0) - length = div_u64(length, map->num_stripes); - else if (map->type & BTRFS_BLOCK_GROUP_RAID56_MASK) { - length = div_u64(length, nr_data_stripes(map)); - rmap_len = map->stripe_len * nr_data_stripes(map); - } - - buf = kcalloc(map->num_stripes, sizeof(u64), GFP_NOFS); - BUG_ON(!buf); /* -ENOMEM */ - - for (i = 0; i < map->num_stripes; i++) { - if (devid && map->stripes[i].dev->devid != devid) - continue; - if (map->stripes[i].physical > physical || - map->stripes[i].physical + length <= physical) - continue; - - stripe_nr = physical - map->stripes[i].physical; - stripe_nr = div_u64(stripe_nr, map->stripe_len); - - if (map->type & BTRFS_BLOCK_GROUP_RAID10) { - stripe_nr = stripe_nr * map->num_stripes + i; - stripe_nr = div_u64(stripe_nr, map->sub_stripes); - } else if (map->type & BTRFS_BLOCK_GROUP_RAID0) { - stripe_nr = stripe_nr * map->num_stripes + i; - } /* else if RAID[56], multiply by nr_data_stripes(). - * Alternatively, just use rmap_len below instead of - * map->stripe_len */ - - bytenr = chunk_start + stripe_nr * rmap_len; - WARN_ON(nr >= map->num_stripes); - for (j = 0; j < nr; j++) { - if (buf[j] == bytenr) - break; - } - if (j == nr) { - WARN_ON(nr >= map->num_stripes); - buf[nr++] = bytenr; - } - } - - *logical = buf; - *naddrs = nr; - *stripe_len = rmap_len; - - free_extent_map(em); - return 0; -} - -static inline void btrfs_end_bbio(struct btrfs_bio *bbio, struct bio *bio) -{ - bio->bi_private = bbio->private; - bio->bi_end_io = bbio->end_io; - bio_endio(bio); - - btrfs_put_bbio(bbio); -} - -static void btrfs_end_bio(struct bio *bio) -{ - struct btrfs_bio *bbio = bio->bi_private; - int is_orig_bio = 0; - - if (bio->bi_error) { - atomic_inc(&bbio->error); - if (bio->bi_error == -EIO || bio->bi_error == -EREMOTEIO) { - unsigned int stripe_index = - btrfs_io_bio(bio)->stripe_index; - struct btrfs_device *dev; - - BUG_ON(stripe_index >= bbio->num_stripes); - dev = bbio->stripes[stripe_index].dev; - if (dev->bdev) { - if (bio_op(bio) == REQ_OP_WRITE) - btrfs_dev_stat_inc(dev, - BTRFS_DEV_STAT_WRITE_ERRS); - else - btrfs_dev_stat_inc(dev, - BTRFS_DEV_STAT_READ_ERRS); - if ((bio->bi_opf & WRITE_FLUSH) == WRITE_FLUSH) - btrfs_dev_stat_inc(dev, - BTRFS_DEV_STAT_FLUSH_ERRS); - btrfs_dev_stat_print_on_error(dev); - } - } - } - - if (bio == bbio->orig_bio) - is_orig_bio = 1; - - btrfs_bio_counter_dec(bbio->fs_info); - - if (atomic_dec_and_test(&bbio->stripes_pending)) { - if (!is_orig_bio) { - bio_put(bio); - bio = bbio->orig_bio; - } - - btrfs_io_bio(bio)->mirror_num = bbio->mirror_num; - /* only send an error to the higher layers if it is - * beyond the tolerance of the btrfs bio - */ - if (atomic_read(&bbio->error) > bbio->max_errors) { - bio->bi_error = -EIO; - } else { - /* - * this bio is actually up to date, we didn't - * go over the max number of errors - */ - bio->bi_error = 0; - } - - btrfs_end_bbio(bbio, bio); - } else if (!is_orig_bio) { - bio_put(bio); - } -} - -/* - * see run_scheduled_bios for a description of why bios are collected for - * async submit. - * - * This will add one bio to the pending list for a device and make sure - * the work struct is scheduled. - */ -static noinline void btrfs_schedule_bio(struct btrfs_root *root, - struct btrfs_device *device, - struct bio *bio) -{ - int should_queue = 1; - struct btrfs_pending_bios *pending_bios; - - if (device->missing || !device->bdev) { - bio_io_error(bio); - return; - } - - /* don't bother with additional async steps for reads, right now */ - if (bio_op(bio) == REQ_OP_READ) { - bio_get(bio); - btrfsic_submit_bio(bio); - bio_put(bio); - return; - } - - /* - * nr_async_bios allows us to reliably return congestion to the - * higher layers. Otherwise, the async bio makes it appear we have - * made progress against dirty pages when we've really just put it - * on a queue for later - */ - atomic_inc(&root->fs_info->nr_async_bios); - WARN_ON(bio->bi_next); - bio->bi_next = NULL; - - spin_lock(&device->io_lock); - if (bio->bi_opf & REQ_SYNC) - pending_bios = &device->pending_sync_bios; - else - pending_bios = &device->pending_bios; - - if (pending_bios->tail) - pending_bios->tail->bi_next = bio; - - pending_bios->tail = bio; - if (!pending_bios->head) - pending_bios->head = bio; - if (device->running_pending) - should_queue = 0; - - spin_unlock(&device->io_lock); - - if (should_queue) - btrfs_queue_work(root->fs_info->submit_workers, - &device->work); -} - -static void submit_stripe_bio(struct btrfs_root *root, struct btrfs_bio *bbio, - struct bio *bio, u64 physical, int dev_nr, - int async) -{ - struct btrfs_device *dev = bbio->stripes[dev_nr].dev; - - bio->bi_private = bbio; - btrfs_io_bio(bio)->stripe_index = dev_nr; - bio->bi_end_io = btrfs_end_bio; - bio->bi_iter.bi_sector = physical >> 9; -#ifdef DEBUG - { - struct rcu_string *name; - - rcu_read_lock(); - name = rcu_dereference(dev->name); - btrfs_debug(fs_info, - "btrfs_map_bio: rw %d 0x%x, sector=%llu, dev=%lu (%s id %llu), size=%u", - bio_op(bio), bio->bi_opf, - (u64)bio->bi_iter.bi_sector, - (u_long)dev->bdev->bd_dev, name->str, dev->devid, - bio->bi_iter.bi_size); - rcu_read_unlock(); - } -#endif - bio->bi_bdev = dev->bdev; - - btrfs_bio_counter_inc_noblocked(root->fs_info); - - if (async) - btrfs_schedule_bio(root, dev, bio); - else - btrfsic_submit_bio(bio); -} - -static void bbio_error(struct btrfs_bio *bbio, struct bio *bio, u64 logical) -{ - atomic_inc(&bbio->error); - if (atomic_dec_and_test(&bbio->stripes_pending)) { - /* Should be the original bio. */ - WARN_ON(bio != bbio->orig_bio); - - btrfs_io_bio(bio)->mirror_num = bbio->mirror_num; - bio->bi_iter.bi_sector = logical >> 9; - bio->bi_error = -EIO; - btrfs_end_bbio(bbio, bio); - } -} - -int btrfs_map_bio(struct btrfs_root *root, struct bio *bio, - int mirror_num, int async_submit) -{ - struct btrfs_device *dev; - struct bio *first_bio = bio; - u64 logical = (u64)bio->bi_iter.bi_sector << 9; - u64 length = 0; - u64 map_length; - int ret; - int dev_nr; - int total_devs; - struct btrfs_bio *bbio = NULL; - - length = bio->bi_iter.bi_size; - map_length = length; - - btrfs_bio_counter_inc_blocked(root->fs_info); - ret = __btrfs_map_block(root->fs_info, bio_op(bio), logical, - &map_length, &bbio, mirror_num, 1); - if (ret) { - btrfs_bio_counter_dec(root->fs_info); - return ret; - } - - total_devs = bbio->num_stripes; - bbio->orig_bio = first_bio; - bbio->private = first_bio->bi_private; - bbio->end_io = first_bio->bi_end_io; - bbio->fs_info = root->fs_info; - atomic_set(&bbio->stripes_pending, bbio->num_stripes); - - if ((bbio->map_type & BTRFS_BLOCK_GROUP_RAID56_MASK) && - ((bio_op(bio) == REQ_OP_WRITE) || (mirror_num > 1))) { - /* In this case, map_length has been set to the length of - a single stripe; not the whole write */ - if (bio_op(bio) == REQ_OP_WRITE) { - ret = raid56_parity_write(root, bio, bbio, map_length); - } else { - ret = raid56_parity_recover(root, bio, bbio, map_length, - mirror_num, 1); - } - - btrfs_bio_counter_dec(root->fs_info); - return ret; - } - - if (map_length < length) { - btrfs_crit(root->fs_info, - "mapping failed logical %llu bio len %llu len %llu", - logical, length, map_length); - BUG(); - } - - for (dev_nr = 0; dev_nr < total_devs; dev_nr++) { - dev = bbio->stripes[dev_nr].dev; - if (!dev || !dev->bdev || - (bio_op(bio) == REQ_OP_WRITE && !dev->writeable)) { - bbio_error(bbio, first_bio, logical); - continue; - } - - if (dev_nr < total_devs - 1) { - bio = btrfs_bio_clone(first_bio, GFP_NOFS); - BUG_ON(!bio); /* -ENOMEM */ - } else - bio = first_bio; - - submit_stripe_bio(root, bbio, bio, - bbio->stripes[dev_nr].physical, dev_nr, - async_submit); - } - btrfs_bio_counter_dec(root->fs_info); - return 0; -} - -struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid, - u8 *uuid, u8 *fsid) -{ - struct btrfs_device *device; - struct btrfs_fs_devices *cur_devices; - - cur_devices = fs_info->fs_devices; - while (cur_devices) { - if (!fsid || - !memcmp(cur_devices->fsid, fsid, BTRFS_UUID_SIZE)) { - device = __find_device(&cur_devices->devices, - devid, uuid); - if (device) - return device; - } - cur_devices = cur_devices->seed; - } - return NULL; -} - -static struct btrfs_device *add_missing_dev(struct btrfs_root *root, - struct btrfs_fs_devices *fs_devices, - u64 devid, u8 *dev_uuid) -{ - struct btrfs_device *device; - - device = btrfs_alloc_device(NULL, &devid, dev_uuid); - if (IS_ERR(device)) - return NULL; - - list_add(&device->dev_list, &fs_devices->devices); - device->fs_devices = fs_devices; - fs_devices->num_devices++; - - device->missing = 1; - fs_devices->missing_devices++; - - return device; -} - -/** - * btrfs_alloc_device - allocate struct btrfs_device - * @fs_info: used only for generating a new devid, can be NULL if - * devid is provided (i.e. @devid != NULL). - * @devid: a pointer to devid for this device. If NULL a new devid - * is generated. - * @uuid: a pointer to UUID for this device. If NULL a new UUID - * is generated. - * - * Return: a pointer to a new &struct btrfs_device on success; ERR_PTR() - * on error. Returned struct is not linked onto any lists and can be - * destroyed with kfree() right away. - */ -struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info, - const u64 *devid, - const u8 *uuid) -{ - struct btrfs_device *dev; - u64 tmp; - - if (WARN_ON(!devid && !fs_info)) - return ERR_PTR(-EINVAL); - - dev = __alloc_device(); - if (IS_ERR(dev)) - return dev; - - if (devid) - tmp = *devid; - else { - int ret; - - ret = find_next_devid(fs_info, &tmp); - if (ret) { - kfree(dev); - return ERR_PTR(ret); - } - } - dev->devid = tmp; - - if (uuid) - memcpy(dev->uuid, uuid, BTRFS_UUID_SIZE); - else - generate_random_uuid(dev->uuid); - - btrfs_init_work(&dev->work, btrfs_submit_helper, - pending_bios_fn, NULL, NULL); - - return dev; -} - -/* Return -EIO if any error, otherwise return 0. */ -static int btrfs_check_chunk_valid(struct btrfs_root *root, - struct extent_buffer *leaf, - struct btrfs_chunk *chunk, u64 logical) -{ - u64 length; - u64 stripe_len; - u16 num_stripes; - u16 sub_stripes; - u64 type; - - length = btrfs_chunk_length(leaf, chunk); - stripe_len = btrfs_chunk_stripe_len(leaf, chunk); - num_stripes = btrfs_chunk_num_stripes(leaf, chunk); - sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk); - type = btrfs_chunk_type(leaf, chunk); - - if (!num_stripes) { - btrfs_err(root->fs_info, "invalid chunk num_stripes: %u", - num_stripes); - return -EIO; - } - if (!IS_ALIGNED(logical, root->sectorsize)) { - btrfs_err(root->fs_info, - "invalid chunk logical %llu", logical); - return -EIO; - } - if (btrfs_chunk_sector_size(leaf, chunk) != root->sectorsize) { - btrfs_err(root->fs_info, "invalid chunk sectorsize %u", - btrfs_chunk_sector_size(leaf, chunk)); - return -EIO; - } - if (!length || !IS_ALIGNED(length, root->sectorsize)) { - btrfs_err(root->fs_info, - "invalid chunk length %llu", length); - return -EIO; - } - if (!is_power_of_2(stripe_len) || stripe_len != BTRFS_STRIPE_LEN) { - btrfs_err(root->fs_info, "invalid chunk stripe length: %llu", - stripe_len); - return -EIO; - } - if (~(BTRFS_BLOCK_GROUP_TYPE_MASK | BTRFS_BLOCK_GROUP_PROFILE_MASK) & - type) { - btrfs_err(root->fs_info, "unrecognized chunk type: %llu", - ~(BTRFS_BLOCK_GROUP_TYPE_MASK | - BTRFS_BLOCK_GROUP_PROFILE_MASK) & - btrfs_chunk_type(leaf, chunk)); - return -EIO; - } - if ((type & BTRFS_BLOCK_GROUP_RAID10 && sub_stripes != 2) || - (type & BTRFS_BLOCK_GROUP_RAID1 && num_stripes < 1) || - (type & BTRFS_BLOCK_GROUP_RAID5 && num_stripes < 2) || - (type & BTRFS_BLOCK_GROUP_RAID6 && num_stripes < 3) || - (type & BTRFS_BLOCK_GROUP_DUP && num_stripes > 2) || - ((type & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0 && - num_stripes != 1)) { - btrfs_err(root->fs_info, - "invalid num_stripes:sub_stripes %u:%u for profile %llu", - num_stripes, sub_stripes, - type & BTRFS_BLOCK_GROUP_PROFILE_MASK); - return -EIO; - } - - return 0; -} - -static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key, - struct extent_buffer *leaf, - struct btrfs_chunk *chunk) -{ - struct btrfs_mapping_tree *map_tree = &root->fs_info->mapping_tree; - struct map_lookup *map; - struct extent_map *em; - u64 logical; - u64 length; - u64 stripe_len; - u64 devid; - u8 uuid[BTRFS_UUID_SIZE]; - int num_stripes; - int ret; - int i; - - logical = key->offset; - length = btrfs_chunk_length(leaf, chunk); - stripe_len = btrfs_chunk_stripe_len(leaf, chunk); - num_stripes = btrfs_chunk_num_stripes(leaf, chunk); - - ret = btrfs_check_chunk_valid(root, leaf, chunk, logical); - if (ret) - return ret; - - read_lock(&map_tree->map_tree.lock); - em = lookup_extent_mapping(&map_tree->map_tree, logical, 1); - read_unlock(&map_tree->map_tree.lock); - - /* already mapped? */ - if (em && em->start <= logical && em->start + em->len > logical) { - free_extent_map(em); - return 0; - } else if (em) { - free_extent_map(em); - } - - em = alloc_extent_map(); - if (!em) - return -ENOMEM; - map = kmalloc(map_lookup_size(num_stripes), GFP_NOFS); - if (!map) { - free_extent_map(em); - return -ENOMEM; - } - - set_bit(EXTENT_FLAG_FS_MAPPING, &em->flags); - em->map_lookup = map; - em->start = logical; - em->len = length; - em->orig_start = 0; - em->block_start = 0; - em->block_len = em->len; - - map->num_stripes = num_stripes; - map->io_width = btrfs_chunk_io_width(leaf, chunk); - map->io_align = btrfs_chunk_io_align(leaf, chunk); - map->sector_size = btrfs_chunk_sector_size(leaf, chunk); - map->stripe_len = btrfs_chunk_stripe_len(leaf, chunk); - map->type = btrfs_chunk_type(leaf, chunk); - map->sub_stripes = btrfs_chunk_sub_stripes(leaf, chunk); - for (i = 0; i < num_stripes; i++) { - map->stripes[i].physical = - btrfs_stripe_offset_nr(leaf, chunk, i); - devid = btrfs_stripe_devid_nr(leaf, chunk, i); - read_extent_buffer(leaf, uuid, (unsigned long) - btrfs_stripe_dev_uuid_nr(chunk, i), - BTRFS_UUID_SIZE); - map->stripes[i].dev = btrfs_find_device(root->fs_info, devid, - uuid, NULL); - if (!map->stripes[i].dev && - !btrfs_test_opt(root->fs_info, DEGRADED)) { - free_extent_map(em); - return -EIO; - } - if (!map->stripes[i].dev) { - map->stripes[i].dev = - add_missing_dev(root, root->fs_info->fs_devices, - devid, uuid); - if (!map->stripes[i].dev) { - free_extent_map(em); - return -EIO; - } - btrfs_warn(root->fs_info, - "devid %llu uuid %pU is missing", - devid, uuid); - } - map->stripes[i].dev->in_fs_metadata = 1; - } - - write_lock(&map_tree->map_tree.lock); - ret = add_extent_mapping(&map_tree->map_tree, em, 0); - write_unlock(&map_tree->map_tree.lock); - BUG_ON(ret); /* Tree corruption */ - free_extent_map(em); - - return 0; -} - -static void fill_device_from_item(struct extent_buffer *leaf, - struct btrfs_dev_item *dev_item, - struct btrfs_device *device) -{ - unsigned long ptr; - - device->devid = btrfs_device_id(leaf, dev_item); - device->disk_total_bytes = btrfs_device_total_bytes(leaf, dev_item); - device->total_bytes = device->disk_total_bytes; - device->commit_total_bytes = device->disk_total_bytes; - device->bytes_used = btrfs_device_bytes_used(leaf, dev_item); - device->commit_bytes_used = device->bytes_used; - device->type = btrfs_device_type(leaf, dev_item); - device->io_align = btrfs_device_io_align(leaf, dev_item); - device->io_width = btrfs_device_io_width(leaf, dev_item); - device->sector_size = btrfs_device_sector_size(leaf, dev_item); - WARN_ON(device->devid == BTRFS_DEV_REPLACE_DEVID); - device->is_tgtdev_for_dev_replace = 0; - - ptr = btrfs_device_uuid(dev_item); - read_extent_buffer(leaf, device->uuid, ptr, BTRFS_UUID_SIZE); -} - -static struct btrfs_fs_devices *open_seed_devices(struct btrfs_root *root, - u8 *fsid) -{ - struct btrfs_fs_devices *fs_devices; - int ret; - - BUG_ON(!mutex_is_locked(&uuid_mutex)); - - fs_devices = root->fs_info->fs_devices->seed; - while (fs_devices) { - if (!memcmp(fs_devices->fsid, fsid, BTRFS_UUID_SIZE)) - return fs_devices; - - fs_devices = fs_devices->seed; - } - - fs_devices = find_fsid(fsid); - if (!fs_devices) { - if (!btrfs_test_opt(root->fs_info, DEGRADED)) - return ERR_PTR(-ENOENT); - - fs_devices = alloc_fs_devices(fsid); - if (IS_ERR(fs_devices)) - return fs_devices; - - fs_devices->seeding = 1; - fs_devices->opened = 1; - return fs_devices; - } - - fs_devices = clone_fs_devices(fs_devices); - if (IS_ERR(fs_devices)) - return fs_devices; - - ret = __btrfs_open_devices(fs_devices, FMODE_READ, - root->fs_info->bdev_holder); - if (ret) { - free_fs_devices(fs_devices); - fs_devices = ERR_PTR(ret); - goto out; - } - - if (!fs_devices->seeding) { - __btrfs_close_devices(fs_devices); - free_fs_devices(fs_devices); - fs_devices = ERR_PTR(-EINVAL); - goto out; - } - - fs_devices->seed = root->fs_info->fs_devices->seed; - root->fs_info->fs_devices->seed = fs_devices; -out: - return fs_devices; -} - -static int read_one_dev(struct btrfs_root *root, - struct extent_buffer *leaf, - struct btrfs_dev_item *dev_item) -{ - struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; - struct btrfs_device *device; - u64 devid; - int ret; - u8 fs_uuid[BTRFS_UUID_SIZE]; - u8 dev_uuid[BTRFS_UUID_SIZE]; - - devid = btrfs_device_id(leaf, dev_item); - read_extent_buffer(leaf, dev_uuid, btrfs_device_uuid(dev_item), - BTRFS_UUID_SIZE); - read_extent_buffer(leaf, fs_uuid, btrfs_device_fsid(dev_item), - BTRFS_UUID_SIZE); - - if (memcmp(fs_uuid, root->fs_info->fsid, BTRFS_UUID_SIZE)) { - fs_devices = open_seed_devices(root, fs_uuid); - if (IS_ERR(fs_devices)) - return PTR_ERR(fs_devices); - } - - device = btrfs_find_device(root->fs_info, devid, dev_uuid, fs_uuid); - if (!device) { - if (!btrfs_test_opt(root->fs_info, DEGRADED)) - return -EIO; - - device = add_missing_dev(root, fs_devices, devid, dev_uuid); - if (!device) - return -ENOMEM; - btrfs_warn(root->fs_info, "devid %llu uuid %pU missing", - devid, dev_uuid); - } else { - if (!device->bdev && !btrfs_test_opt(root->fs_info, DEGRADED)) - return -EIO; - - if(!device->bdev && !device->missing) { - /* - * this happens when a device that was properly setup - * in the device info lists suddenly goes bad. - * device->bdev is NULL, and so we have to set - * device->missing to one here - */ - device->fs_devices->missing_devices++; - device->missing = 1; - } - - /* Move the device to its own fs_devices */ - if (device->fs_devices != fs_devices) { - ASSERT(device->missing); - - list_move(&device->dev_list, &fs_devices->devices); - device->fs_devices->num_devices--; - fs_devices->num_devices++; - - device->fs_devices->missing_devices--; - fs_devices->missing_devices++; - - device->fs_devices = fs_devices; - } - } - - if (device->fs_devices != root->fs_info->fs_devices) { - BUG_ON(device->writeable); - if (device->generation != - btrfs_device_generation(leaf, dev_item)) - return -EINVAL; - } - - fill_device_from_item(leaf, dev_item, device); - device->in_fs_metadata = 1; - if (device->writeable && !device->is_tgtdev_for_dev_replace) { - device->fs_devices->total_rw_bytes += device->total_bytes; - spin_lock(&root->fs_info->free_chunk_lock); - root->fs_info->free_chunk_space += device->total_bytes - - device->bytes_used; - spin_unlock(&root->fs_info->free_chunk_lock); - } - ret = 0; - return ret; -} - -int btrfs_read_sys_array(struct btrfs_root *root) -{ - struct btrfs_fs_info *fs_info = root->fs_info; - struct btrfs_super_block *super_copy = fs_info->super_copy; - struct extent_buffer *sb; - struct btrfs_disk_key *disk_key; - struct btrfs_chunk *chunk; - u8 *array_ptr; - unsigned long sb_array_offset; - int ret = 0; - u32 num_stripes; - u32 array_size; - u32 len = 0; - u32 cur_offset; - u64 type; - struct btrfs_key key; - - ASSERT(BTRFS_SUPER_INFO_SIZE <= root->nodesize); - /* - * This will create extent buffer of nodesize, superblock size is - * fixed to BTRFS_SUPER_INFO_SIZE. If nodesize > sb size, this will - * overallocate but we can keep it as-is, only the first page is used. - */ - sb = btrfs_find_create_tree_block(root, BTRFS_SUPER_INFO_OFFSET); - if (IS_ERR(sb)) - return PTR_ERR(sb); - set_extent_buffer_uptodate(sb); - btrfs_set_buffer_lockdep_class(root->root_key.objectid, sb, 0); - /* - * The sb extent buffer is artificial and just used to read the system array. - * set_extent_buffer_uptodate() call does not properly mark all it's - * pages up-to-date when the page is larger: extent does not cover the - * whole page and consequently check_page_uptodate does not find all - * the page's extents up-to-date (the hole beyond sb), - * write_extent_buffer then triggers a WARN_ON. - * - * Regular short extents go through mark_extent_buffer_dirty/writeback cycle, - * but sb spans only this function. Add an explicit SetPageUptodate call - * to silence the warning eg. on PowerPC 64. - */ - if (PAGE_SIZE > BTRFS_SUPER_INFO_SIZE) - SetPageUptodate(sb->pages[0]); - - write_extent_buffer(sb, super_copy, 0, BTRFS_SUPER_INFO_SIZE); - array_size = btrfs_super_sys_array_size(super_copy); - - array_ptr = super_copy->sys_chunk_array; - sb_array_offset = offsetof(struct btrfs_super_block, sys_chunk_array); - cur_offset = 0; - - while (cur_offset < array_size) { - disk_key = (struct btrfs_disk_key *)array_ptr; - len = sizeof(*disk_key); - if (cur_offset + len > array_size) - goto out_short_read; - - btrfs_disk_key_to_cpu(&key, disk_key); - - array_ptr += len; - sb_array_offset += len; - cur_offset += len; - - if (key.type == BTRFS_CHUNK_ITEM_KEY) { - chunk = (struct btrfs_chunk *)sb_array_offset; - /* - * At least one btrfs_chunk with one stripe must be - * present, exact stripe count check comes afterwards - */ - len = btrfs_chunk_item_size(1); - if (cur_offset + len > array_size) - goto out_short_read; - - num_stripes = btrfs_chunk_num_stripes(sb, chunk); - if (!num_stripes) { - btrfs_err(fs_info, - "invalid number of stripes %u in sys_array at offset %u", - num_stripes, cur_offset); - ret = -EIO; - break; - } - - type = btrfs_chunk_type(sb, chunk); - if ((type & BTRFS_BLOCK_GROUP_SYSTEM) == 0) { - btrfs_err(fs_info, - "invalid chunk type %llu in sys_array at offset %u", - type, cur_offset); - ret = -EIO; - break; - } - - len = btrfs_chunk_item_size(num_stripes); - if (cur_offset + len > array_size) - goto out_short_read; - - ret = read_one_chunk(root, &key, sb, chunk); - if (ret) - break; - } else { - btrfs_err(fs_info, - "unexpected item type %u in sys_array at offset %u", - (u32)key.type, cur_offset); - ret = -EIO; - break; - } - array_ptr += len; - sb_array_offset += len; - cur_offset += len; - } - clear_extent_buffer_uptodate(sb); - free_extent_buffer_stale(sb); - return ret; - -out_short_read: - btrfs_err(fs_info, "sys_array too short to read %u bytes at offset %u", - len, cur_offset); - clear_extent_buffer_uptodate(sb); - free_extent_buffer_stale(sb); - return -EIO; -} - -int btrfs_read_chunk_tree(struct btrfs_root *root) -{ - struct btrfs_path *path; - struct extent_buffer *leaf; - struct btrfs_key key; - struct btrfs_key found_key; - int ret; - int slot; - u64 total_dev = 0; - - root = root->fs_info->chunk_root; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - mutex_lock(&uuid_mutex); - lock_chunks(root); - - /* - * Read all device items, and then all the chunk items. All - * device items are found before any chunk item (their object id - * is smaller than the lowest possible object id for a chunk - * item - BTRFS_FIRST_CHUNK_TREE_OBJECTID). - */ - key.objectid = BTRFS_DEV_ITEMS_OBJECTID; - key.offset = 0; - key.type = 0; - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto error; - while (1) { - leaf = path->nodes[0]; - slot = path->slots[0]; - if (slot >= btrfs_header_nritems(leaf)) { - ret = btrfs_next_leaf(root, path); - if (ret == 0) - continue; - if (ret < 0) - goto error; - break; - } - btrfs_item_key_to_cpu(leaf, &found_key, slot); - if (found_key.type == BTRFS_DEV_ITEM_KEY) { - struct btrfs_dev_item *dev_item; - dev_item = btrfs_item_ptr(leaf, slot, - struct btrfs_dev_item); - ret = read_one_dev(root, leaf, dev_item); - if (ret) - goto error; - total_dev++; - } else if (found_key.type == BTRFS_CHUNK_ITEM_KEY) { - struct btrfs_chunk *chunk; - chunk = btrfs_item_ptr(leaf, slot, struct btrfs_chunk); - ret = read_one_chunk(root, &found_key, leaf, chunk); - if (ret) - goto error; - } - path->slots[0]++; - } - - /* - * After loading chunk tree, we've got all device information, - * do another round of validation checks. - */ - if (total_dev != root->fs_info->fs_devices->total_devices) { - btrfs_err(root->fs_info, - "super_num_devices %llu mismatch with num_devices %llu found here", - btrfs_super_num_devices(root->fs_info->super_copy), - total_dev); - ret = -EINVAL; - goto error; - } - if (btrfs_super_total_bytes(root->fs_info->super_copy) < - root->fs_info->fs_devices->total_rw_bytes) { - btrfs_err(root->fs_info, - "super_total_bytes %llu mismatch with fs_devices total_rw_bytes %llu", - btrfs_super_total_bytes(root->fs_info->super_copy), - root->fs_info->fs_devices->total_rw_bytes); - ret = -EINVAL; - goto error; - } - ret = 0; -error: - unlock_chunks(root); - mutex_unlock(&uuid_mutex); - - btrfs_free_path(path); - return ret; -} - -void btrfs_init_devices_late(struct btrfs_fs_info *fs_info) -{ - struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; - struct btrfs_device *device; - - while (fs_devices) { - mutex_lock(&fs_devices->device_list_mutex); - list_for_each_entry(device, &fs_devices->devices, dev_list) - device->dev_root = fs_info->dev_root; - mutex_unlock(&fs_devices->device_list_mutex); - - fs_devices = fs_devices->seed; - } -} - -static void __btrfs_reset_dev_stats(struct btrfs_device *dev) -{ - int i; - - for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++) - btrfs_dev_stat_reset(dev, i); -} - -int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info) -{ - struct btrfs_key key; - struct btrfs_key found_key; - struct btrfs_root *dev_root = fs_info->dev_root; - struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; - struct extent_buffer *eb; - int slot; - int ret = 0; - struct btrfs_device *device; - struct btrfs_path *path = NULL; - int i; - - path = btrfs_alloc_path(); - if (!path) { - ret = -ENOMEM; - goto out; - } - - mutex_lock(&fs_devices->device_list_mutex); - list_for_each_entry(device, &fs_devices->devices, dev_list) { - int item_size; - struct btrfs_dev_stats_item *ptr; - - key.objectid = BTRFS_DEV_STATS_OBJECTID; - key.type = BTRFS_PERSISTENT_ITEM_KEY; - key.offset = device->devid; - ret = btrfs_search_slot(NULL, dev_root, &key, path, 0, 0); - if (ret) { - __btrfs_reset_dev_stats(device); - device->dev_stats_valid = 1; - btrfs_release_path(path); - continue; - } - slot = path->slots[0]; - eb = path->nodes[0]; - btrfs_item_key_to_cpu(eb, &found_key, slot); - item_size = btrfs_item_size_nr(eb, slot); - - ptr = btrfs_item_ptr(eb, slot, - struct btrfs_dev_stats_item); - - for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++) { - if (item_size >= (1 + i) * sizeof(__le64)) - btrfs_dev_stat_set(device, i, - btrfs_dev_stats_value(eb, ptr, i)); - else - btrfs_dev_stat_reset(device, i); - } - - device->dev_stats_valid = 1; - btrfs_dev_stat_print_on_load(device); - btrfs_release_path(path); - } - mutex_unlock(&fs_devices->device_list_mutex); - -out: - btrfs_free_path(path); - return ret < 0 ? ret : 0; -} - -static int update_dev_stat_item(struct btrfs_trans_handle *trans, - struct btrfs_root *dev_root, - struct btrfs_device *device) -{ - struct btrfs_path *path; - struct btrfs_key key; - struct extent_buffer *eb; - struct btrfs_dev_stats_item *ptr; - int ret; - int i; - - key.objectid = BTRFS_DEV_STATS_OBJECTID; - key.type = BTRFS_PERSISTENT_ITEM_KEY; - key.offset = device->devid; - - path = btrfs_alloc_path(); - BUG_ON(!path); - ret = btrfs_search_slot(trans, dev_root, &key, path, -1, 1); - if (ret < 0) { - btrfs_warn_in_rcu(dev_root->fs_info, - "error %d while searching for dev_stats item for device %s", - ret, rcu_str_deref(device->name)); - goto out; - } - - if (ret == 0 && - btrfs_item_size_nr(path->nodes[0], path->slots[0]) < sizeof(*ptr)) { - /* need to delete old one and insert a new one */ - ret = btrfs_del_item(trans, dev_root, path); - if (ret != 0) { - btrfs_warn_in_rcu(dev_root->fs_info, - "delete too small dev_stats item for device %s failed %d", - rcu_str_deref(device->name), ret); - goto out; - } - ret = 1; - } - - if (ret == 1) { - /* need to insert a new item */ - btrfs_release_path(path); - ret = btrfs_insert_empty_item(trans, dev_root, path, - &key, sizeof(*ptr)); - if (ret < 0) { - btrfs_warn_in_rcu(dev_root->fs_info, - "insert dev_stats item for device %s failed %d", - rcu_str_deref(device->name), ret); - goto out; - } - } - - eb = path->nodes[0]; - ptr = btrfs_item_ptr(eb, path->slots[0], struct btrfs_dev_stats_item); - for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++) - btrfs_set_dev_stats_value(eb, ptr, i, - btrfs_dev_stat_read(device, i)); - btrfs_mark_buffer_dirty(eb); - -out: - btrfs_free_path(path); - return ret; -} - -/* - * called from commit_transaction. Writes all changed device stats to disk. - */ -int btrfs_run_dev_stats(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info) -{ - struct btrfs_root *dev_root = fs_info->dev_root; - struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; - struct btrfs_device *device; - int stats_cnt; - int ret = 0; - - mutex_lock(&fs_devices->device_list_mutex); - list_for_each_entry(device, &fs_devices->devices, dev_list) { - if (!device->dev_stats_valid || !btrfs_dev_stats_dirty(device)) - continue; - - stats_cnt = atomic_read(&device->dev_stats_ccnt); - ret = update_dev_stat_item(trans, dev_root, device); - if (!ret) - atomic_sub(stats_cnt, &device->dev_stats_ccnt); - } - mutex_unlock(&fs_devices->device_list_mutex); - - return ret; -} - -void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index) -{ - btrfs_dev_stat_inc(dev, index); - btrfs_dev_stat_print_on_error(dev); -} - -static void btrfs_dev_stat_print_on_error(struct btrfs_device *dev) -{ - if (!dev->dev_stats_valid) - return; - btrfs_err_rl_in_rcu(dev->dev_root->fs_info, - "bdev %s errs: wr %u, rd %u, flush %u, corrupt %u, gen %u", - rcu_str_deref(dev->name), - btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_WRITE_ERRS), - btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_READ_ERRS), - btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_FLUSH_ERRS), - btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_CORRUPTION_ERRS), - btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_GENERATION_ERRS)); -} - -static void btrfs_dev_stat_print_on_load(struct btrfs_device *dev) -{ - int i; - - for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++) - if (btrfs_dev_stat_read(dev, i) != 0) - break; - if (i == BTRFS_DEV_STAT_VALUES_MAX) - return; /* all values == 0, suppress message */ - - btrfs_info_in_rcu(dev->dev_root->fs_info, - "bdev %s errs: wr %u, rd %u, flush %u, corrupt %u, gen %u", - rcu_str_deref(dev->name), - btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_WRITE_ERRS), - btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_READ_ERRS), - btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_FLUSH_ERRS), - btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_CORRUPTION_ERRS), - btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_GENERATION_ERRS)); -} - -int btrfs_get_dev_stats(struct btrfs_root *root, - struct btrfs_ioctl_get_dev_stats *stats) -{ - struct btrfs_device *dev; - struct btrfs_fs_devices *fs_devices = root->fs_info->fs_devices; - int i; - - mutex_lock(&fs_devices->device_list_mutex); - dev = btrfs_find_device(root->fs_info, stats->devid, NULL, NULL); - mutex_unlock(&fs_devices->device_list_mutex); - - if (!dev) { - btrfs_warn(root->fs_info, - "get dev_stats failed, device not found"); - return -ENODEV; - } else if (!dev->dev_stats_valid) { - btrfs_warn(root->fs_info, - "get dev_stats failed, not yet valid"); - return -ENODEV; - } else if (stats->flags & BTRFS_DEV_STATS_RESET) { - for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++) { - if (stats->nr_items > i) - stats->values[i] = - btrfs_dev_stat_read_and_reset(dev, i); - else - btrfs_dev_stat_reset(dev, i); - } - } else { - for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++) - if (stats->nr_items > i) - stats->values[i] = btrfs_dev_stat_read(dev, i); - } - if (stats->nr_items > BTRFS_DEV_STAT_VALUES_MAX) - stats->nr_items = BTRFS_DEV_STAT_VALUES_MAX; - return 0; -} - -void btrfs_scratch_superblocks(struct block_device *bdev, char *device_path) -{ - struct buffer_head *bh; - struct btrfs_super_block *disk_super; - int copy_num; - - if (!bdev) - return; - - for (copy_num = 0; copy_num < BTRFS_SUPER_MIRROR_MAX; - copy_num++) { - - if (btrfs_read_dev_one_super(bdev, copy_num, &bh)) - continue; - - disk_super = (struct btrfs_super_block *)bh->b_data; - - memset(&disk_super->magic, 0, sizeof(disk_super->magic)); - set_buffer_dirty(bh); - sync_dirty_buffer(bh); - brelse(bh); - } - - /* Notify udev that device has changed */ - btrfs_kobject_uevent(bdev, KOBJ_CHANGE); - - /* Update ctime/mtime for device path for libblkid */ - update_dev_time(device_path); -} - -/* - * Update the size of all devices, which is used for writing out the - * super blocks. - */ -void btrfs_update_commit_device_size(struct btrfs_fs_info *fs_info) -{ - struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; - struct btrfs_device *curr, *next; - - if (list_empty(&fs_devices->resized_devices)) - return; - - mutex_lock(&fs_devices->device_list_mutex); - lock_chunks(fs_info->dev_root); - list_for_each_entry_safe(curr, next, &fs_devices->resized_devices, - resized_list) { - list_del_init(&curr->resized_list); - curr->commit_total_bytes = curr->disk_total_bytes; - } - unlock_chunks(fs_info->dev_root); - mutex_unlock(&fs_devices->device_list_mutex); -} - -/* Must be invoked during the transaction commit */ -void btrfs_update_commit_device_bytes_used(struct btrfs_root *root, - struct btrfs_transaction *transaction) -{ - struct extent_map *em; - struct map_lookup *map; - struct btrfs_device *dev; - int i; - - if (list_empty(&transaction->pending_chunks)) - return; - - /* In order to kick the device replace finish process */ - lock_chunks(root); - list_for_each_entry(em, &transaction->pending_chunks, list) { - map = em->map_lookup; - - for (i = 0; i < map->num_stripes; i++) { - dev = map->stripes[i].dev; - dev->commit_bytes_used = dev->bytes_used; - } - } - unlock_chunks(root); -} - -void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info) -{ - struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; - while (fs_devices) { - fs_devices->fs_info = fs_info; - fs_devices = fs_devices->seed; - } -} - -void btrfs_reset_fs_info_ptr(struct btrfs_fs_info *fs_info) -{ - struct btrfs_fs_devices *fs_devices = fs_info->fs_devices; - while (fs_devices) { - fs_devices->fs_info = NULL; - fs_devices = fs_devices->seed; - } -} diff --git a/src/linux/fs/btrfs/volumes.h b/src/linux/fs/btrfs/volumes.h deleted file mode 100644 index 09ed29c..0000000 --- a/src/linux/fs/btrfs/volumes.h +++ /dev/null @@ -1,529 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __BTRFS_VOLUMES_ -#define __BTRFS_VOLUMES_ - -#include -#include -#include -#include "async-thread.h" - -extern struct mutex uuid_mutex; - -#define BTRFS_STRIPE_LEN SZ_64K - -struct buffer_head; -struct btrfs_pending_bios { - struct bio *head; - struct bio *tail; -}; - -/* - * Use sequence counter to get consistent device stat data on - * 32-bit processors. - */ -#if BITS_PER_LONG==32 && defined(CONFIG_SMP) -#include -#define __BTRFS_NEED_DEVICE_DATA_ORDERED -#define btrfs_device_data_ordered_init(device) \ - seqcount_init(&device->data_seqcount) -#else -#define btrfs_device_data_ordered_init(device) do { } while (0) -#endif - -struct btrfs_device { - struct list_head dev_list; - struct list_head dev_alloc_list; - struct btrfs_fs_devices *fs_devices; - - struct btrfs_root *dev_root; - - struct rcu_string *name; - - u64 generation; - - spinlock_t io_lock ____cacheline_aligned; - int running_pending; - /* regular prio bios */ - struct btrfs_pending_bios pending_bios; - /* WRITE_SYNC bios */ - struct btrfs_pending_bios pending_sync_bios; - - struct block_device *bdev; - - /* the mode sent to blkdev_get */ - fmode_t mode; - - int writeable; - int in_fs_metadata; - int missing; - int can_discard; - int is_tgtdev_for_dev_replace; - -#ifdef __BTRFS_NEED_DEVICE_DATA_ORDERED - seqcount_t data_seqcount; -#endif - - /* the internal btrfs device id */ - u64 devid; - - /* size of the device in memory */ - u64 total_bytes; - - /* size of the device on disk */ - u64 disk_total_bytes; - - /* bytes used */ - u64 bytes_used; - - /* optimal io alignment for this device */ - u32 io_align; - - /* optimal io width for this device */ - u32 io_width; - /* type and info about this device */ - u64 type; - - /* minimal io size for this device */ - u32 sector_size; - - /* physical drive uuid (or lvm uuid) */ - u8 uuid[BTRFS_UUID_SIZE]; - - /* - * size of the device on the current transaction - * - * This variant is update when committing the transaction, - * and protected by device_list_mutex - */ - u64 commit_total_bytes; - - /* bytes used on the current transaction */ - u64 commit_bytes_used; - /* - * used to manage the device which is resized - * - * It is protected by chunk_lock. - */ - struct list_head resized_list; - - /* for sending down flush barriers */ - int nobarriers; - struct bio *flush_bio; - struct completion flush_wait; - - /* per-device scrub information */ - struct scrub_ctx *scrub_device; - - struct btrfs_work work; - struct rcu_head rcu; - struct work_struct rcu_work; - - /* readahead state */ - spinlock_t reada_lock; - atomic_t reada_in_flight; - u64 reada_next; - struct reada_zone *reada_curr_zone; - struct radix_tree_root reada_zones; - struct radix_tree_root reada_extents; - - /* disk I/O failure stats. For detailed description refer to - * enum btrfs_dev_stat_values in ioctl.h */ - int dev_stats_valid; - - /* Counter to record the change of device stats */ - atomic_t dev_stats_ccnt; - atomic_t dev_stat_values[BTRFS_DEV_STAT_VALUES_MAX]; -}; - -/* - * If we read those variants at the context of their own lock, we needn't - * use the following helpers, reading them directly is safe. - */ -#if BITS_PER_LONG==32 && defined(CONFIG_SMP) -#define BTRFS_DEVICE_GETSET_FUNCS(name) \ -static inline u64 \ -btrfs_device_get_##name(const struct btrfs_device *dev) \ -{ \ - u64 size; \ - unsigned int seq; \ - \ - do { \ - seq = read_seqcount_begin(&dev->data_seqcount); \ - size = dev->name; \ - } while (read_seqcount_retry(&dev->data_seqcount, seq)); \ - return size; \ -} \ - \ -static inline void \ -btrfs_device_set_##name(struct btrfs_device *dev, u64 size) \ -{ \ - preempt_disable(); \ - write_seqcount_begin(&dev->data_seqcount); \ - dev->name = size; \ - write_seqcount_end(&dev->data_seqcount); \ - preempt_enable(); \ -} -#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPT) -#define BTRFS_DEVICE_GETSET_FUNCS(name) \ -static inline u64 \ -btrfs_device_get_##name(const struct btrfs_device *dev) \ -{ \ - u64 size; \ - \ - preempt_disable(); \ - size = dev->name; \ - preempt_enable(); \ - return size; \ -} \ - \ -static inline void \ -btrfs_device_set_##name(struct btrfs_device *dev, u64 size) \ -{ \ - preempt_disable(); \ - dev->name = size; \ - preempt_enable(); \ -} -#else -#define BTRFS_DEVICE_GETSET_FUNCS(name) \ -static inline u64 \ -btrfs_device_get_##name(const struct btrfs_device *dev) \ -{ \ - return dev->name; \ -} \ - \ -static inline void \ -btrfs_device_set_##name(struct btrfs_device *dev, u64 size) \ -{ \ - dev->name = size; \ -} -#endif - -BTRFS_DEVICE_GETSET_FUNCS(total_bytes); -BTRFS_DEVICE_GETSET_FUNCS(disk_total_bytes); -BTRFS_DEVICE_GETSET_FUNCS(bytes_used); - -struct btrfs_fs_devices { - u8 fsid[BTRFS_FSID_SIZE]; /* FS specific uuid */ - - u64 num_devices; - u64 open_devices; - u64 rw_devices; - u64 missing_devices; - u64 total_rw_bytes; - u64 total_devices; - struct block_device *latest_bdev; - - /* all of the devices in the FS, protected by a mutex - * so we can safely walk it to write out the supers without - * worrying about add/remove by the multi-device code. - * Scrubbing super can kick off supers writing by holding - * this mutex lock. - */ - struct mutex device_list_mutex; - struct list_head devices; - - struct list_head resized_devices; - /* devices not currently being allocated */ - struct list_head alloc_list; - struct list_head list; - - struct btrfs_fs_devices *seed; - int seeding; - - int opened; - - /* set when we find or add a device that doesn't have the - * nonrot flag set - */ - int rotating; - - struct btrfs_fs_info *fs_info; - /* sysfs kobjects */ - struct kobject fsid_kobj; - struct kobject *device_dir_kobj; - struct completion kobj_unregister; -}; - -#define BTRFS_BIO_INLINE_CSUM_SIZE 64 - -/* - * we need the mirror number and stripe index to be passed around - * the call chain while we are processing end_io (especially errors). - * Really, what we need is a btrfs_bio structure that has this info - * and is properly sized with its stripe array, but we're not there - * quite yet. We have our own btrfs bioset, and all of the bios - * we allocate are actually btrfs_io_bios. We'll cram as much of - * struct btrfs_bio as we can into this over time. - */ -typedef void (btrfs_io_bio_end_io_t) (struct btrfs_io_bio *bio, int err); -struct btrfs_io_bio { - unsigned int mirror_num; - unsigned int stripe_index; - u64 logical; - u8 *csum; - u8 csum_inline[BTRFS_BIO_INLINE_CSUM_SIZE]; - u8 *csum_allocated; - btrfs_io_bio_end_io_t *end_io; - struct bio bio; -}; - -static inline struct btrfs_io_bio *btrfs_io_bio(struct bio *bio) -{ - return container_of(bio, struct btrfs_io_bio, bio); -} - -struct btrfs_bio_stripe { - struct btrfs_device *dev; - u64 physical; - u64 length; /* only used for discard mappings */ -}; - -struct btrfs_bio; -typedef void (btrfs_bio_end_io_t) (struct btrfs_bio *bio, int err); - -struct btrfs_bio { - atomic_t refs; - atomic_t stripes_pending; - struct btrfs_fs_info *fs_info; - u64 map_type; /* get from map_lookup->type */ - bio_end_io_t *end_io; - struct bio *orig_bio; - unsigned long flags; - void *private; - atomic_t error; - int max_errors; - int num_stripes; - int mirror_num; - int num_tgtdevs; - int *tgtdev_map; - /* - * logical block numbers for the start of each stripe - * The last one or two are p/q. These are sorted, - * so raid_map[0] is the start of our full stripe - */ - u64 *raid_map; - struct btrfs_bio_stripe stripes[]; -}; - -struct btrfs_device_info { - struct btrfs_device *dev; - u64 dev_offset; - u64 max_avail; - u64 total_avail; -}; - -struct btrfs_raid_attr { - int sub_stripes; /* sub_stripes info for map */ - int dev_stripes; /* stripes per dev */ - int devs_max; /* max devs to use */ - int devs_min; /* min devs needed */ - int tolerated_failures; /* max tolerated fail devs */ - int devs_increment; /* ndevs has to be a multiple of this */ - int ncopies; /* how many copies to data has */ -}; - -extern const struct btrfs_raid_attr btrfs_raid_array[BTRFS_NR_RAID_TYPES]; -extern const int btrfs_raid_mindev_error[BTRFS_NR_RAID_TYPES]; -extern const u64 btrfs_raid_group[BTRFS_NR_RAID_TYPES]; - -struct map_lookup { - u64 type; - int io_align; - int io_width; - u64 stripe_len; - int sector_size; - int num_stripes; - int sub_stripes; - struct btrfs_bio_stripe stripes[]; -}; - -#define map_lookup_size(n) (sizeof(struct map_lookup) + \ - (sizeof(struct btrfs_bio_stripe) * (n))) - -struct btrfs_balance_args; -struct btrfs_balance_progress; -struct btrfs_balance_control { - struct btrfs_fs_info *fs_info; - - struct btrfs_balance_args data; - struct btrfs_balance_args meta; - struct btrfs_balance_args sys; - - u64 flags; - - struct btrfs_balance_progress stat; -}; - -int btrfs_account_dev_extents_size(struct btrfs_device *device, u64 start, - u64 end, u64 *length); -void btrfs_get_bbio(struct btrfs_bio *bbio); -void btrfs_put_bbio(struct btrfs_bio *bbio); -int btrfs_map_block(struct btrfs_fs_info *fs_info, int op, - u64 logical, u64 *length, - struct btrfs_bio **bbio_ret, int mirror_num); -int btrfs_map_sblock(struct btrfs_fs_info *fs_info, int op, - u64 logical, u64 *length, - struct btrfs_bio **bbio_ret, int mirror_num, - int need_raid_map); -int btrfs_rmap_block(struct btrfs_fs_info *fs_info, - u64 chunk_start, u64 physical, u64 devid, - u64 **logical, int *naddrs, int *stripe_len); -int btrfs_read_sys_array(struct btrfs_root *root); -int btrfs_read_chunk_tree(struct btrfs_root *root); -int btrfs_alloc_chunk(struct btrfs_trans_handle *trans, - struct btrfs_root *extent_root, u64 type); -void btrfs_mapping_init(struct btrfs_mapping_tree *tree); -void btrfs_mapping_tree_free(struct btrfs_mapping_tree *tree); -int btrfs_map_bio(struct btrfs_root *root, struct bio *bio, - int mirror_num, int async_submit); -int btrfs_open_devices(struct btrfs_fs_devices *fs_devices, - fmode_t flags, void *holder); -int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder, - struct btrfs_fs_devices **fs_devices_ret); -int btrfs_close_devices(struct btrfs_fs_devices *fs_devices); -void btrfs_close_extra_devices(struct btrfs_fs_devices *fs_devices, int step); -void btrfs_assign_next_active_device(struct btrfs_fs_info *fs_info, - struct btrfs_device *device, struct btrfs_device *this_dev); -int btrfs_find_device_missing_or_by_path(struct btrfs_root *root, - char *device_path, - struct btrfs_device **device); -int btrfs_find_device_by_devspec(struct btrfs_root *root, u64 devid, - char *devpath, - struct btrfs_device **device); -struct btrfs_device *btrfs_alloc_device(struct btrfs_fs_info *fs_info, - const u64 *devid, - const u8 *uuid); -int btrfs_rm_device(struct btrfs_root *root, char *device_path, u64 devid); -void btrfs_cleanup_fs_uuids(void); -int btrfs_num_copies(struct btrfs_fs_info *fs_info, u64 logical, u64 len); -int btrfs_grow_device(struct btrfs_trans_handle *trans, - struct btrfs_device *device, u64 new_size); -struct btrfs_device *btrfs_find_device(struct btrfs_fs_info *fs_info, u64 devid, - u8 *uuid, u8 *fsid); -int btrfs_shrink_device(struct btrfs_device *device, u64 new_size); -int btrfs_init_new_device(struct btrfs_root *root, char *path); -int btrfs_init_dev_replace_tgtdev(struct btrfs_root *root, char *device_path, - struct btrfs_device *srcdev, - struct btrfs_device **device_out); -int btrfs_balance(struct btrfs_balance_control *bctl, - struct btrfs_ioctl_balance_args *bargs); -int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info); -int btrfs_recover_balance(struct btrfs_fs_info *fs_info); -int btrfs_pause_balance(struct btrfs_fs_info *fs_info); -int btrfs_cancel_balance(struct btrfs_fs_info *fs_info); -int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info); -int btrfs_check_uuid_tree(struct btrfs_fs_info *fs_info); -int btrfs_chunk_readonly(struct btrfs_root *root, u64 chunk_offset); -int find_free_dev_extent_start(struct btrfs_transaction *transaction, - struct btrfs_device *device, u64 num_bytes, - u64 search_start, u64 *start, u64 *max_avail); -int find_free_dev_extent(struct btrfs_trans_handle *trans, - struct btrfs_device *device, u64 num_bytes, - u64 *start, u64 *max_avail); -void btrfs_dev_stat_inc_and_print(struct btrfs_device *dev, int index); -int btrfs_get_dev_stats(struct btrfs_root *root, - struct btrfs_ioctl_get_dev_stats *stats); -void btrfs_init_devices_late(struct btrfs_fs_info *fs_info); -int btrfs_init_dev_stats(struct btrfs_fs_info *fs_info); -int btrfs_run_dev_stats(struct btrfs_trans_handle *trans, - struct btrfs_fs_info *fs_info); -void btrfs_rm_dev_replace_remove_srcdev(struct btrfs_fs_info *fs_info, - struct btrfs_device *srcdev); -void btrfs_rm_dev_replace_free_srcdev(struct btrfs_fs_info *fs_info, - struct btrfs_device *srcdev); -void btrfs_destroy_dev_replace_tgtdev(struct btrfs_fs_info *fs_info, - struct btrfs_device *tgtdev); -void btrfs_init_dev_replace_tgtdev_for_resume(struct btrfs_fs_info *fs_info, - struct btrfs_device *tgtdev); -void btrfs_scratch_superblocks(struct block_device *bdev, char *device_path); -int btrfs_is_parity_mirror(struct btrfs_mapping_tree *map_tree, - u64 logical, u64 len, int mirror_num); -unsigned long btrfs_full_stripe_len(struct btrfs_root *root, - struct btrfs_mapping_tree *map_tree, - u64 logical); -int btrfs_finish_chunk_alloc(struct btrfs_trans_handle *trans, - struct btrfs_root *extent_root, - u64 chunk_offset, u64 chunk_size); -int btrfs_remove_chunk(struct btrfs_trans_handle *trans, - struct btrfs_root *root, u64 chunk_offset); - -static inline int btrfs_dev_stats_dirty(struct btrfs_device *dev) -{ - return atomic_read(&dev->dev_stats_ccnt); -} - -static inline void btrfs_dev_stat_inc(struct btrfs_device *dev, - int index) -{ - atomic_inc(dev->dev_stat_values + index); - smp_mb__before_atomic(); - atomic_inc(&dev->dev_stats_ccnt); -} - -static inline int btrfs_dev_stat_read(struct btrfs_device *dev, - int index) -{ - return atomic_read(dev->dev_stat_values + index); -} - -static inline int btrfs_dev_stat_read_and_reset(struct btrfs_device *dev, - int index) -{ - int ret; - - ret = atomic_xchg(dev->dev_stat_values + index, 0); - smp_mb__before_atomic(); - atomic_inc(&dev->dev_stats_ccnt); - return ret; -} - -static inline void btrfs_dev_stat_set(struct btrfs_device *dev, - int index, unsigned long val) -{ - atomic_set(dev->dev_stat_values + index, val); - smp_mb__before_atomic(); - atomic_inc(&dev->dev_stats_ccnt); -} - -static inline void btrfs_dev_stat_reset(struct btrfs_device *dev, - int index) -{ - btrfs_dev_stat_set(dev, index, 0); -} - -void btrfs_update_commit_device_size(struct btrfs_fs_info *fs_info); -void btrfs_update_commit_device_bytes_used(struct btrfs_root *root, - struct btrfs_transaction *transaction); - -static inline void lock_chunks(struct btrfs_root *root) -{ - mutex_lock(&root->fs_info->chunk_mutex); -} - -static inline void unlock_chunks(struct btrfs_root *root) -{ - mutex_unlock(&root->fs_info->chunk_mutex); -} - -struct list_head *btrfs_get_fs_uuids(void); -void btrfs_set_fs_info_ptr(struct btrfs_fs_info *fs_info); -void btrfs_reset_fs_info_ptr(struct btrfs_fs_info *fs_info); - -#endif diff --git a/src/linux/fs/btrfs/xattr.c b/src/linux/fs/btrfs/xattr.c deleted file mode 100644 index fccbf55..0000000 --- a/src/linux/fs/btrfs/xattr.c +++ /dev/null @@ -1,468 +0,0 @@ -/* - * Copyright (C) 2007 Red Hat. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include "ctree.h" -#include "btrfs_inode.h" -#include "transaction.h" -#include "xattr.h" -#include "disk-io.h" -#include "props.h" -#include "locking.h" - - -ssize_t __btrfs_getxattr(struct inode *inode, const char *name, - void *buffer, size_t size) -{ - struct btrfs_dir_item *di; - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_path *path; - struct extent_buffer *leaf; - int ret = 0; - unsigned long data_ptr; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - - /* lookup the xattr by name */ - di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode), name, - strlen(name), 0); - if (!di) { - ret = -ENODATA; - goto out; - } else if (IS_ERR(di)) { - ret = PTR_ERR(di); - goto out; - } - - leaf = path->nodes[0]; - /* if size is 0, that means we want the size of the attr */ - if (!size) { - ret = btrfs_dir_data_len(leaf, di); - goto out; - } - - /* now get the data out of our dir_item */ - if (btrfs_dir_data_len(leaf, di) > size) { - ret = -ERANGE; - goto out; - } - - /* - * The way things are packed into the leaf is like this - * |struct btrfs_dir_item|name|data| - * where name is the xattr name, so security.foo, and data is the - * content of the xattr. data_ptr points to the location in memory - * where the data starts in the in memory leaf - */ - data_ptr = (unsigned long)((char *)(di + 1) + - btrfs_dir_name_len(leaf, di)); - read_extent_buffer(leaf, buffer, data_ptr, - btrfs_dir_data_len(leaf, di)); - ret = btrfs_dir_data_len(leaf, di); - -out: - btrfs_free_path(path); - return ret; -} - -static int do_setxattr(struct btrfs_trans_handle *trans, - struct inode *inode, const char *name, - const void *value, size_t size, int flags) -{ - struct btrfs_dir_item *di = NULL; - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_path *path; - size_t name_len = strlen(name); - int ret = 0; - - if (name_len + size > BTRFS_MAX_XATTR_SIZE(root)) - return -ENOSPC; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->skip_release_on_error = 1; - - if (!value) { - di = btrfs_lookup_xattr(trans, root, path, btrfs_ino(inode), - name, name_len, -1); - if (!di && (flags & XATTR_REPLACE)) - ret = -ENODATA; - else if (IS_ERR(di)) - ret = PTR_ERR(di); - else if (di) - ret = btrfs_delete_one_dir_name(trans, root, path, di); - goto out; - } - - /* - * For a replace we can't just do the insert blindly. - * Do a lookup first (read-only btrfs_search_slot), and return if xattr - * doesn't exist. If it exists, fall down below to the insert/replace - * path - we can't race with a concurrent xattr delete, because the VFS - * locks the inode's i_mutex before calling setxattr or removexattr. - */ - if (flags & XATTR_REPLACE) { - ASSERT(inode_is_locked(inode)); - di = btrfs_lookup_xattr(NULL, root, path, btrfs_ino(inode), - name, name_len, 0); - if (!di) - ret = -ENODATA; - else if (IS_ERR(di)) - ret = PTR_ERR(di); - if (ret) - goto out; - btrfs_release_path(path); - di = NULL; - } - - ret = btrfs_insert_xattr_item(trans, root, path, btrfs_ino(inode), - name, name_len, value, size); - if (ret == -EOVERFLOW) { - /* - * We have an existing item in a leaf, split_leaf couldn't - * expand it. That item might have or not a dir_item that - * matches our target xattr, so lets check. - */ - ret = 0; - btrfs_assert_tree_locked(path->nodes[0]); - di = btrfs_match_dir_item_name(root, path, name, name_len); - if (!di && !(flags & XATTR_REPLACE)) { - ret = -ENOSPC; - goto out; - } - } else if (ret == -EEXIST) { - ret = 0; - di = btrfs_match_dir_item_name(root, path, name, name_len); - ASSERT(di); /* logic error */ - } else if (ret) { - goto out; - } - - if (di && (flags & XATTR_CREATE)) { - ret = -EEXIST; - goto out; - } - - if (di) { - /* - * We're doing a replace, and it must be atomic, that is, at - * any point in time we have either the old or the new xattr - * value in the tree. We don't want readers (getxattr and - * listxattrs) to miss a value, this is specially important - * for ACLs. - */ - const int slot = path->slots[0]; - struct extent_buffer *leaf = path->nodes[0]; - const u16 old_data_len = btrfs_dir_data_len(leaf, di); - const u32 item_size = btrfs_item_size_nr(leaf, slot); - const u32 data_size = sizeof(*di) + name_len + size; - struct btrfs_item *item; - unsigned long data_ptr; - char *ptr; - - if (size > old_data_len) { - if (btrfs_leaf_free_space(root, leaf) < - (size - old_data_len)) { - ret = -ENOSPC; - goto out; - } - } - - if (old_data_len + name_len + sizeof(*di) == item_size) { - /* No other xattrs packed in the same leaf item. */ - if (size > old_data_len) - btrfs_extend_item(root, path, - size - old_data_len); - else if (size < old_data_len) - btrfs_truncate_item(root, path, data_size, 1); - } else { - /* There are other xattrs packed in the same item. */ - ret = btrfs_delete_one_dir_name(trans, root, path, di); - if (ret) - goto out; - btrfs_extend_item(root, path, data_size); - } - - item = btrfs_item_nr(slot); - ptr = btrfs_item_ptr(leaf, slot, char); - ptr += btrfs_item_size(leaf, item) - data_size; - di = (struct btrfs_dir_item *)ptr; - btrfs_set_dir_data_len(leaf, di, size); - data_ptr = ((unsigned long)(di + 1)) + name_len; - write_extent_buffer(leaf, value, data_ptr, size); - btrfs_mark_buffer_dirty(leaf); - } else { - /* - * Insert, and we had space for the xattr, so path->slots[0] is - * where our xattr dir_item is and btrfs_insert_xattr_item() - * filled it. - */ - } -out: - btrfs_free_path(path); - return ret; -} - -/* - * @value: "" makes the attribute to empty, NULL removes it - */ -int __btrfs_setxattr(struct btrfs_trans_handle *trans, - struct inode *inode, const char *name, - const void *value, size_t size, int flags) -{ - struct btrfs_root *root = BTRFS_I(inode)->root; - int ret; - - if (btrfs_root_readonly(root)) - return -EROFS; - - if (trans) - return do_setxattr(trans, inode, name, value, size, flags); - - trans = btrfs_start_transaction(root, 2); - if (IS_ERR(trans)) - return PTR_ERR(trans); - - ret = do_setxattr(trans, inode, name, value, size, flags); - if (ret) - goto out; - - inode_inc_iversion(inode); - inode->i_ctime = current_time(inode); - set_bit(BTRFS_INODE_COPY_EVERYTHING, &BTRFS_I(inode)->runtime_flags); - ret = btrfs_update_inode(trans, root, inode); - BUG_ON(ret); -out: - btrfs_end_transaction(trans, root); - return ret; -} - -ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size) -{ - struct btrfs_key key; - struct inode *inode = d_inode(dentry); - struct btrfs_root *root = BTRFS_I(inode)->root; - struct btrfs_path *path; - int ret = 0; - size_t total_size = 0, size_left = size; - - /* - * ok we want all objects associated with this id. - * NOTE: we set key.offset = 0; because we want to start with the - * first xattr that we find and walk forward - */ - key.objectid = btrfs_ino(inode); - key.type = BTRFS_XATTR_ITEM_KEY; - key.offset = 0; - - path = btrfs_alloc_path(); - if (!path) - return -ENOMEM; - path->reada = READA_FORWARD; - - /* search for our xattrs */ - ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); - if (ret < 0) - goto err; - - while (1) { - struct extent_buffer *leaf; - int slot; - struct btrfs_dir_item *di; - struct btrfs_key found_key; - u32 item_size; - u32 cur; - - leaf = path->nodes[0]; - slot = path->slots[0]; - - /* this is where we start walking through the path */ - if (slot >= btrfs_header_nritems(leaf)) { - /* - * if we've reached the last slot in this leaf we need - * to go to the next leaf and reset everything - */ - ret = btrfs_next_leaf(root, path); - if (ret < 0) - goto err; - else if (ret > 0) - break; - continue; - } - - btrfs_item_key_to_cpu(leaf, &found_key, slot); - - /* check to make sure this item is what we want */ - if (found_key.objectid != key.objectid) - break; - if (found_key.type > BTRFS_XATTR_ITEM_KEY) - break; - if (found_key.type < BTRFS_XATTR_ITEM_KEY) - goto next_item; - - di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item); - item_size = btrfs_item_size_nr(leaf, slot); - cur = 0; - while (cur < item_size) { - u16 name_len = btrfs_dir_name_len(leaf, di); - u16 data_len = btrfs_dir_data_len(leaf, di); - u32 this_len = sizeof(*di) + name_len + data_len; - unsigned long name_ptr = (unsigned long)(di + 1); - - if (verify_dir_item(root, leaf, di)) { - ret = -EIO; - goto err; - } - - total_size += name_len + 1; - /* - * We are just looking for how big our buffer needs to - * be. - */ - if (!size) - goto next; - - if (!buffer || (name_len + 1) > size_left) { - ret = -ERANGE; - goto err; - } - - read_extent_buffer(leaf, buffer, name_ptr, name_len); - buffer[name_len] = '\0'; - - size_left -= name_len + 1; - buffer += name_len + 1; -next: - cur += this_len; - di = (struct btrfs_dir_item *)((char *)di + this_len); - } -next_item: - path->slots[0]++; - } - ret = total_size; - -err: - btrfs_free_path(path); - - return ret; -} - -static int btrfs_xattr_handler_get(const struct xattr_handler *handler, - struct dentry *unused, struct inode *inode, - const char *name, void *buffer, size_t size) -{ - name = xattr_full_name(handler, name); - return __btrfs_getxattr(inode, name, buffer, size); -} - -static int btrfs_xattr_handler_set(const struct xattr_handler *handler, - struct dentry *unused, struct inode *inode, - const char *name, const void *buffer, - size_t size, int flags) -{ - name = xattr_full_name(handler, name); - return __btrfs_setxattr(NULL, inode, name, buffer, size, flags); -} - -static int btrfs_xattr_handler_set_prop(const struct xattr_handler *handler, - struct dentry *unused, struct inode *inode, - const char *name, const void *value, - size_t size, int flags) -{ - name = xattr_full_name(handler, name); - return btrfs_set_prop(inode, name, value, size, flags); -} - -static const struct xattr_handler btrfs_security_xattr_handler = { - .prefix = XATTR_SECURITY_PREFIX, - .get = btrfs_xattr_handler_get, - .set = btrfs_xattr_handler_set, -}; - -static const struct xattr_handler btrfs_trusted_xattr_handler = { - .prefix = XATTR_TRUSTED_PREFIX, - .get = btrfs_xattr_handler_get, - .set = btrfs_xattr_handler_set, -}; - -static const struct xattr_handler btrfs_user_xattr_handler = { - .prefix = XATTR_USER_PREFIX, - .get = btrfs_xattr_handler_get, - .set = btrfs_xattr_handler_set, -}; - -static const struct xattr_handler btrfs_btrfs_xattr_handler = { - .prefix = XATTR_BTRFS_PREFIX, - .get = btrfs_xattr_handler_get, - .set = btrfs_xattr_handler_set_prop, -}; - -const struct xattr_handler *btrfs_xattr_handlers[] = { - &btrfs_security_xattr_handler, -#ifdef CONFIG_BTRFS_FS_POSIX_ACL - &posix_acl_access_xattr_handler, - &posix_acl_default_xattr_handler, -#endif - &btrfs_trusted_xattr_handler, - &btrfs_user_xattr_handler, - &btrfs_btrfs_xattr_handler, - NULL, -}; - -static int btrfs_initxattrs(struct inode *inode, - const struct xattr *xattr_array, void *fs_info) -{ - const struct xattr *xattr; - struct btrfs_trans_handle *trans = fs_info; - char *name; - int err = 0; - - for (xattr = xattr_array; xattr->name != NULL; xattr++) { - name = kmalloc(XATTR_SECURITY_PREFIX_LEN + - strlen(xattr->name) + 1, GFP_KERNEL); - if (!name) { - err = -ENOMEM; - break; - } - strcpy(name, XATTR_SECURITY_PREFIX); - strcpy(name + XATTR_SECURITY_PREFIX_LEN, xattr->name); - err = __btrfs_setxattr(trans, inode, name, - xattr->value, xattr->value_len, 0); - kfree(name); - if (err < 0) - break; - } - return err; -} - -int btrfs_xattr_security_init(struct btrfs_trans_handle *trans, - struct inode *inode, struct inode *dir, - const struct qstr *qstr) -{ - return security_inode_init_security(inode, dir, qstr, - &btrfs_initxattrs, trans); -} diff --git a/src/linux/fs/btrfs/xattr.h b/src/linux/fs/btrfs/xattr.h deleted file mode 100644 index 15fc474..0000000 --- a/src/linux/fs/btrfs/xattr.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2007 Red Hat. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef __XATTR__ -#define __XATTR__ - -#include - -extern const struct xattr_handler *btrfs_xattr_handlers[]; - -extern ssize_t __btrfs_getxattr(struct inode *inode, const char *name, - void *buffer, size_t size); -extern int __btrfs_setxattr(struct btrfs_trans_handle *trans, - struct inode *inode, const char *name, - const void *value, size_t size, int flags); - -extern int btrfs_xattr_security_init(struct btrfs_trans_handle *trans, - struct inode *inode, struct inode *dir, - const struct qstr *qstr); - -#endif /* __XATTR__ */ diff --git a/src/linux/fs/btrfs/zlib.c b/src/linux/fs/btrfs/zlib.c deleted file mode 100644 index 441b81a..0000000 --- a/src/linux/fs/btrfs/zlib.c +++ /dev/null @@ -1,412 +0,0 @@ -/* - * Copyright (C) 2008 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - * - * Based on jffs2 zlib code: - * Copyright © 2001-2007 Red Hat, Inc. - * Created by David Woodhouse - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "compression.h" - -struct workspace { - z_stream strm; - char *buf; - struct list_head list; -}; - -static void zlib_free_workspace(struct list_head *ws) -{ - struct workspace *workspace = list_entry(ws, struct workspace, list); - - vfree(workspace->strm.workspace); - kfree(workspace->buf); - kfree(workspace); -} - -static struct list_head *zlib_alloc_workspace(void) -{ - struct workspace *workspace; - int workspacesize; - - workspace = kzalloc(sizeof(*workspace), GFP_NOFS); - if (!workspace) - return ERR_PTR(-ENOMEM); - - workspacesize = max(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL), - zlib_inflate_workspacesize()); - workspace->strm.workspace = vmalloc(workspacesize); - workspace->buf = kmalloc(PAGE_SIZE, GFP_NOFS); - if (!workspace->strm.workspace || !workspace->buf) - goto fail; - - INIT_LIST_HEAD(&workspace->list); - - return &workspace->list; -fail: - zlib_free_workspace(&workspace->list); - return ERR_PTR(-ENOMEM); -} - -static int zlib_compress_pages(struct list_head *ws, - struct address_space *mapping, - u64 start, unsigned long len, - struct page **pages, - unsigned long nr_dest_pages, - unsigned long *out_pages, - unsigned long *total_in, - unsigned long *total_out, - unsigned long max_out) -{ - struct workspace *workspace = list_entry(ws, struct workspace, list); - int ret; - char *data_in; - char *cpage_out; - int nr_pages = 0; - struct page *in_page = NULL; - struct page *out_page = NULL; - unsigned long bytes_left; - - *out_pages = 0; - *total_out = 0; - *total_in = 0; - - if (Z_OK != zlib_deflateInit(&workspace->strm, 3)) { - pr_warn("BTRFS: deflateInit failed\n"); - ret = -EIO; - goto out; - } - - workspace->strm.total_in = 0; - workspace->strm.total_out = 0; - - in_page = find_get_page(mapping, start >> PAGE_SHIFT); - data_in = kmap(in_page); - - out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); - if (out_page == NULL) { - ret = -ENOMEM; - goto out; - } - cpage_out = kmap(out_page); - pages[0] = out_page; - nr_pages = 1; - - workspace->strm.next_in = data_in; - workspace->strm.next_out = cpage_out; - workspace->strm.avail_out = PAGE_SIZE; - workspace->strm.avail_in = min(len, PAGE_SIZE); - - while (workspace->strm.total_in < len) { - ret = zlib_deflate(&workspace->strm, Z_SYNC_FLUSH); - if (ret != Z_OK) { - pr_debug("BTRFS: deflate in loop returned %d\n", - ret); - zlib_deflateEnd(&workspace->strm); - ret = -EIO; - goto out; - } - - /* we're making it bigger, give up */ - if (workspace->strm.total_in > 8192 && - workspace->strm.total_in < - workspace->strm.total_out) { - ret = -E2BIG; - goto out; - } - /* we need another page for writing out. Test this - * before the total_in so we will pull in a new page for - * the stream end if required - */ - if (workspace->strm.avail_out == 0) { - kunmap(out_page); - if (nr_pages == nr_dest_pages) { - out_page = NULL; - ret = -E2BIG; - goto out; - } - out_page = alloc_page(GFP_NOFS | __GFP_HIGHMEM); - if (out_page == NULL) { - ret = -ENOMEM; - goto out; - } - cpage_out = kmap(out_page); - pages[nr_pages] = out_page; - nr_pages++; - workspace->strm.avail_out = PAGE_SIZE; - workspace->strm.next_out = cpage_out; - } - /* we're all done */ - if (workspace->strm.total_in >= len) - break; - - /* we've read in a full page, get a new one */ - if (workspace->strm.avail_in == 0) { - if (workspace->strm.total_out > max_out) - break; - - bytes_left = len - workspace->strm.total_in; - kunmap(in_page); - put_page(in_page); - - start += PAGE_SIZE; - in_page = find_get_page(mapping, - start >> PAGE_SHIFT); - data_in = kmap(in_page); - workspace->strm.avail_in = min(bytes_left, - PAGE_SIZE); - workspace->strm.next_in = data_in; - } - } - workspace->strm.avail_in = 0; - ret = zlib_deflate(&workspace->strm, Z_FINISH); - zlib_deflateEnd(&workspace->strm); - - if (ret != Z_STREAM_END) { - ret = -EIO; - goto out; - } - - if (workspace->strm.total_out >= workspace->strm.total_in) { - ret = -E2BIG; - goto out; - } - - ret = 0; - *total_out = workspace->strm.total_out; - *total_in = workspace->strm.total_in; -out: - *out_pages = nr_pages; - if (out_page) - kunmap(out_page); - - if (in_page) { - kunmap(in_page); - put_page(in_page); - } - return ret; -} - -static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in, - u64 disk_start, - struct bio_vec *bvec, - int vcnt, - size_t srclen) -{ - struct workspace *workspace = list_entry(ws, struct workspace, list); - int ret = 0, ret2; - int wbits = MAX_WBITS; - char *data_in; - size_t total_out = 0; - unsigned long page_in_index = 0; - unsigned long page_out_index = 0; - unsigned long total_pages_in = DIV_ROUND_UP(srclen, PAGE_SIZE); - unsigned long buf_start; - unsigned long pg_offset; - - data_in = kmap(pages_in[page_in_index]); - workspace->strm.next_in = data_in; - workspace->strm.avail_in = min_t(size_t, srclen, PAGE_SIZE); - workspace->strm.total_in = 0; - - workspace->strm.total_out = 0; - workspace->strm.next_out = workspace->buf; - workspace->strm.avail_out = PAGE_SIZE; - pg_offset = 0; - - /* If it's deflate, and it's got no preset dictionary, then - we can tell zlib to skip the adler32 check. */ - if (srclen > 2 && !(data_in[1] & PRESET_DICT) && - ((data_in[0] & 0x0f) == Z_DEFLATED) && - !(((data_in[0]<<8) + data_in[1]) % 31)) { - - wbits = -((data_in[0] >> 4) + 8); - workspace->strm.next_in += 2; - workspace->strm.avail_in -= 2; - } - - if (Z_OK != zlib_inflateInit2(&workspace->strm, wbits)) { - pr_warn("BTRFS: inflateInit failed\n"); - return -EIO; - } - while (workspace->strm.total_in < srclen) { - ret = zlib_inflate(&workspace->strm, Z_NO_FLUSH); - if (ret != Z_OK && ret != Z_STREAM_END) - break; - - buf_start = total_out; - total_out = workspace->strm.total_out; - - /* we didn't make progress in this inflate call, we're done */ - if (buf_start == total_out) - break; - - ret2 = btrfs_decompress_buf2page(workspace->buf, buf_start, - total_out, disk_start, - bvec, vcnt, - &page_out_index, &pg_offset); - if (ret2 == 0) { - ret = 0; - goto done; - } - - workspace->strm.next_out = workspace->buf; - workspace->strm.avail_out = PAGE_SIZE; - - if (workspace->strm.avail_in == 0) { - unsigned long tmp; - kunmap(pages_in[page_in_index]); - page_in_index++; - if (page_in_index >= total_pages_in) { - data_in = NULL; - break; - } - data_in = kmap(pages_in[page_in_index]); - workspace->strm.next_in = data_in; - tmp = srclen - workspace->strm.total_in; - workspace->strm.avail_in = min(tmp, - PAGE_SIZE); - } - } - if (ret != Z_STREAM_END) - ret = -EIO; - else - ret = 0; -done: - zlib_inflateEnd(&workspace->strm); - if (data_in) - kunmap(pages_in[page_in_index]); - if (!ret) - btrfs_clear_biovec_end(bvec, vcnt, page_out_index, pg_offset); - return ret; -} - -static int zlib_decompress(struct list_head *ws, unsigned char *data_in, - struct page *dest_page, - unsigned long start_byte, - size_t srclen, size_t destlen) -{ - struct workspace *workspace = list_entry(ws, struct workspace, list); - int ret = 0; - int wbits = MAX_WBITS; - unsigned long bytes_left; - unsigned long total_out = 0; - unsigned long pg_offset = 0; - char *kaddr; - - destlen = min_t(unsigned long, destlen, PAGE_SIZE); - bytes_left = destlen; - - workspace->strm.next_in = data_in; - workspace->strm.avail_in = srclen; - workspace->strm.total_in = 0; - - workspace->strm.next_out = workspace->buf; - workspace->strm.avail_out = PAGE_SIZE; - workspace->strm.total_out = 0; - /* If it's deflate, and it's got no preset dictionary, then - we can tell zlib to skip the adler32 check. */ - if (srclen > 2 && !(data_in[1] & PRESET_DICT) && - ((data_in[0] & 0x0f) == Z_DEFLATED) && - !(((data_in[0]<<8) + data_in[1]) % 31)) { - - wbits = -((data_in[0] >> 4) + 8); - workspace->strm.next_in += 2; - workspace->strm.avail_in -= 2; - } - - if (Z_OK != zlib_inflateInit2(&workspace->strm, wbits)) { - pr_warn("BTRFS: inflateInit failed\n"); - return -EIO; - } - - while (bytes_left > 0) { - unsigned long buf_start; - unsigned long buf_offset; - unsigned long bytes; - - ret = zlib_inflate(&workspace->strm, Z_NO_FLUSH); - if (ret != Z_OK && ret != Z_STREAM_END) - break; - - buf_start = total_out; - total_out = workspace->strm.total_out; - - if (total_out == buf_start) { - ret = -EIO; - break; - } - - if (total_out <= start_byte) - goto next; - - if (total_out > start_byte && buf_start < start_byte) - buf_offset = start_byte - buf_start; - else - buf_offset = 0; - - bytes = min(PAGE_SIZE - pg_offset, - PAGE_SIZE - buf_offset); - bytes = min(bytes, bytes_left); - - kaddr = kmap_atomic(dest_page); - memcpy(kaddr + pg_offset, workspace->buf + buf_offset, bytes); - kunmap_atomic(kaddr); - - pg_offset += bytes; - bytes_left -= bytes; -next: - workspace->strm.next_out = workspace->buf; - workspace->strm.avail_out = PAGE_SIZE; - } - - if (ret != Z_STREAM_END && bytes_left != 0) - ret = -EIO; - else - ret = 0; - - zlib_inflateEnd(&workspace->strm); - - /* - * this should only happen if zlib returned fewer bytes than we - * expected. btrfs_get_block is responsible for zeroing from the - * end of the inline extent (destlen) to the end of the page - */ - if (pg_offset < destlen) { - kaddr = kmap_atomic(dest_page); - memset(kaddr + pg_offset, 0, destlen - pg_offset); - kunmap_atomic(kaddr); - } - return ret; -} - -const struct btrfs_compress_op btrfs_zlib_compress = { - .alloc_workspace = zlib_alloc_workspace, - .free_workspace = zlib_free_workspace, - .compress_pages = zlib_compress_pages, - .decompress_biovec = zlib_decompress_biovec, - .decompress = zlib_decompress, -}; diff --git a/src/linux/fs/buffer.c b/src/linux/fs/buffer.c deleted file mode 100644 index b205a62..0000000 --- a/src/linux/fs/buffer.c +++ /dev/null @@ -1,3487 +0,0 @@ -/* - * linux/fs/buffer.c - * - * Copyright (C) 1991, 1992, 2002 Linus Torvalds - */ - -/* - * Start bdflush() with kernel_thread not syscall - Paul Gortmaker, 12/95 - * - * Removed a lot of unnecessary code and simplified things now that - * the buffer cache isn't our primary cache - Andrew Tridgell 12/96 - * - * Speed up hash, lru, and free list operations. Use gfp() for allocating - * hash table, use SLAB cache for buffer heads. SMP threading. -DaveM - * - * Added 32k buffer block sizes - these are required older ARM systems. - RMK - * - * async buffer flushing, 1999 Andrea Arcangeli - */ - -#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 - -static int fsync_buffers_list(spinlock_t *lock, struct list_head *list); -static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh, - unsigned long bio_flags, - struct writeback_control *wbc); - -#define BH_ENTRY(list) list_entry((list), struct buffer_head, b_assoc_buffers) - -void init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *private) -{ - bh->b_end_io = handler; - bh->b_private = private; -} -EXPORT_SYMBOL(init_buffer); - -inline void touch_buffer(struct buffer_head *bh) -{ - trace_block_touch_buffer(bh); - mark_page_accessed(bh->b_page); -} -EXPORT_SYMBOL(touch_buffer); - -void __lock_buffer(struct buffer_head *bh) -{ - wait_on_bit_lock_io(&bh->b_state, BH_Lock, TASK_UNINTERRUPTIBLE); -} -EXPORT_SYMBOL(__lock_buffer); - -void unlock_buffer(struct buffer_head *bh) -{ - clear_bit_unlock(BH_Lock, &bh->b_state); - smp_mb__after_atomic(); - wake_up_bit(&bh->b_state, BH_Lock); -} -EXPORT_SYMBOL(unlock_buffer); - -/* - * Returns if the page has dirty or writeback buffers. If all the buffers - * are unlocked and clean then the PageDirty information is stale. If - * any of the pages are locked, it is assumed they are locked for IO. - */ -void buffer_check_dirty_writeback(struct page *page, - bool *dirty, bool *writeback) -{ - struct buffer_head *head, *bh; - *dirty = false; - *writeback = false; - - BUG_ON(!PageLocked(page)); - - if (!page_has_buffers(page)) - return; - - if (PageWriteback(page)) - *writeback = true; - - head = page_buffers(page); - bh = head; - do { - if (buffer_locked(bh)) - *writeback = true; - - if (buffer_dirty(bh)) - *dirty = true; - - bh = bh->b_this_page; - } while (bh != head); -} -EXPORT_SYMBOL(buffer_check_dirty_writeback); - -/* - * Block until a buffer comes unlocked. This doesn't stop it - * from becoming locked again - you have to lock it yourself - * if you want to preserve its state. - */ -void __wait_on_buffer(struct buffer_head * bh) -{ - wait_on_bit_io(&bh->b_state, BH_Lock, TASK_UNINTERRUPTIBLE); -} -EXPORT_SYMBOL(__wait_on_buffer); - -static void -__clear_page_buffers(struct page *page) -{ - ClearPagePrivate(page); - set_page_private(page, 0); - put_page(page); -} - -static void buffer_io_error(struct buffer_head *bh, char *msg) -{ - if (!test_bit(BH_Quiet, &bh->b_state)) - printk_ratelimited(KERN_ERR - "Buffer I/O error on dev %pg, logical block %llu%s\n", - bh->b_bdev, (unsigned long long)bh->b_blocknr, msg); -} - -/* - * End-of-IO handler helper function which does not touch the bh after - * unlocking it. - * Note: unlock_buffer() sort-of does touch the bh after unlocking it, but - * a race there is benign: unlock_buffer() only use the bh's address for - * hashing after unlocking the buffer, so it doesn't actually touch the bh - * itself. - */ -static void __end_buffer_read_notouch(struct buffer_head *bh, int uptodate) -{ - if (uptodate) { - set_buffer_uptodate(bh); - } else { - /* This happens, due to failed read-ahead attempts. */ - clear_buffer_uptodate(bh); - } - unlock_buffer(bh); -} - -/* - * Default synchronous end-of-IO handler.. Just mark it up-to-date and - * unlock the buffer. This is what ll_rw_block uses too. - */ -void end_buffer_read_sync(struct buffer_head *bh, int uptodate) -{ - __end_buffer_read_notouch(bh, uptodate); - put_bh(bh); -} -EXPORT_SYMBOL(end_buffer_read_sync); - -void end_buffer_write_sync(struct buffer_head *bh, int uptodate) -{ - if (uptodate) { - set_buffer_uptodate(bh); - } else { - buffer_io_error(bh, ", lost sync page write"); - set_buffer_write_io_error(bh); - clear_buffer_uptodate(bh); - } - unlock_buffer(bh); - put_bh(bh); -} -EXPORT_SYMBOL(end_buffer_write_sync); - -/* - * Various filesystems appear to want __find_get_block to be non-blocking. - * But it's the page lock which protects the buffers. To get around this, - * we get exclusion from try_to_free_buffers with the blockdev mapping's - * private_lock. - * - * Hack idea: for the blockdev mapping, i_bufferlist_lock contention - * may be quite high. This code could TryLock the page, and if that - * succeeds, there is no need to take private_lock. (But if - * private_lock is contended then so is mapping->tree_lock). - */ -static struct buffer_head * -__find_get_block_slow(struct block_device *bdev, sector_t block) -{ - struct inode *bd_inode = bdev->bd_inode; - struct address_space *bd_mapping = bd_inode->i_mapping; - struct buffer_head *ret = NULL; - pgoff_t index; - struct buffer_head *bh; - struct buffer_head *head; - struct page *page; - int all_mapped = 1; - - index = block >> (PAGE_SHIFT - bd_inode->i_blkbits); - page = find_get_page_flags(bd_mapping, index, FGP_ACCESSED); - if (!page) - goto out; - - spin_lock(&bd_mapping->private_lock); - if (!page_has_buffers(page)) - goto out_unlock; - head = page_buffers(page); - bh = head; - do { - if (!buffer_mapped(bh)) - all_mapped = 0; - else if (bh->b_blocknr == block) { - ret = bh; - get_bh(bh); - goto out_unlock; - } - bh = bh->b_this_page; - } while (bh != head); - - /* we might be here because some of the buffers on this page are - * not mapped. This is due to various races between - * file io on the block device and getblk. It gets dealt with - * elsewhere, don't buffer_error if we had some unmapped buffers - */ - if (all_mapped) { - printk("__find_get_block_slow() failed. " - "block=%llu, b_blocknr=%llu\n", - (unsigned long long)block, - (unsigned long long)bh->b_blocknr); - printk("b_state=0x%08lx, b_size=%zu\n", - bh->b_state, bh->b_size); - printk("device %pg blocksize: %d\n", bdev, - 1 << bd_inode->i_blkbits); - } -out_unlock: - spin_unlock(&bd_mapping->private_lock); - put_page(page); -out: - return ret; -} - -/* - * Kick the writeback threads then try to free up some ZONE_NORMAL memory. - */ -static void free_more_memory(void) -{ - struct zoneref *z; - int nid; - - wakeup_flusher_threads(1024, WB_REASON_FREE_MORE_MEM); - yield(); - - for_each_online_node(nid) { - - z = first_zones_zonelist(node_zonelist(nid, GFP_NOFS), - gfp_zone(GFP_NOFS), NULL); - if (z->zone) - try_to_free_pages(node_zonelist(nid, GFP_NOFS), 0, - GFP_NOFS, NULL); - } -} - -/* - * I/O completion handler for block_read_full_page() - pages - * which come unlocked at the end of I/O. - */ -static void end_buffer_async_read(struct buffer_head *bh, int uptodate) -{ - unsigned long flags; - struct buffer_head *first; - struct buffer_head *tmp; - struct page *page; - int page_uptodate = 1; - - BUG_ON(!buffer_async_read(bh)); - - page = bh->b_page; - if (uptodate) { - set_buffer_uptodate(bh); - } else { - clear_buffer_uptodate(bh); - buffer_io_error(bh, ", async page read"); - SetPageError(page); - } - - /* - * Be _very_ careful from here on. Bad things can happen if - * two buffer heads end IO at almost the same time and both - * decide that the page is now completely done. - */ - first = page_buffers(page); - local_irq_save(flags); - bit_spin_lock(BH_Uptodate_Lock, &first->b_state); - clear_buffer_async_read(bh); - unlock_buffer(bh); - tmp = bh; - do { - if (!buffer_uptodate(tmp)) - page_uptodate = 0; - if (buffer_async_read(tmp)) { - BUG_ON(!buffer_locked(tmp)); - goto still_busy; - } - tmp = tmp->b_this_page; - } while (tmp != bh); - bit_spin_unlock(BH_Uptodate_Lock, &first->b_state); - local_irq_restore(flags); - - /* - * If none of the buffers had errors and they are all - * uptodate then we can set the page uptodate. - */ - if (page_uptodate && !PageError(page)) - SetPageUptodate(page); - unlock_page(page); - return; - -still_busy: - bit_spin_unlock(BH_Uptodate_Lock, &first->b_state); - local_irq_restore(flags); - return; -} - -/* - * Completion handler for block_write_full_page() - pages which are unlocked - * during I/O, and which have PageWriteback cleared upon I/O completion. - */ -void end_buffer_async_write(struct buffer_head *bh, int uptodate) -{ - unsigned long flags; - struct buffer_head *first; - struct buffer_head *tmp; - struct page *page; - - BUG_ON(!buffer_async_write(bh)); - - page = bh->b_page; - if (uptodate) { - set_buffer_uptodate(bh); - } else { - buffer_io_error(bh, ", lost async page write"); - mapping_set_error(page->mapping, -EIO); - set_buffer_write_io_error(bh); - clear_buffer_uptodate(bh); - SetPageError(page); - } - - first = page_buffers(page); - local_irq_save(flags); - bit_spin_lock(BH_Uptodate_Lock, &first->b_state); - - clear_buffer_async_write(bh); - unlock_buffer(bh); - tmp = bh->b_this_page; - while (tmp != bh) { - if (buffer_async_write(tmp)) { - BUG_ON(!buffer_locked(tmp)); - goto still_busy; - } - tmp = tmp->b_this_page; - } - bit_spin_unlock(BH_Uptodate_Lock, &first->b_state); - local_irq_restore(flags); - end_page_writeback(page); - return; - -still_busy: - bit_spin_unlock(BH_Uptodate_Lock, &first->b_state); - local_irq_restore(flags); - return; -} -EXPORT_SYMBOL(end_buffer_async_write); - -/* - * If a page's buffers are under async readin (end_buffer_async_read - * completion) then there is a possibility that another thread of - * control could lock one of the buffers after it has completed - * but while some of the other buffers have not completed. This - * locked buffer would confuse end_buffer_async_read() into not unlocking - * the page. So the absence of BH_Async_Read tells end_buffer_async_read() - * that this buffer is not under async I/O. - * - * The page comes unlocked when it has no locked buffer_async buffers - * left. - * - * PageLocked prevents anyone starting new async I/O reads any of - * the buffers. - * - * PageWriteback is used to prevent simultaneous writeout of the same - * page. - * - * PageLocked prevents anyone from starting writeback of a page which is - * under read I/O (PageWriteback is only ever set against a locked page). - */ -static void mark_buffer_async_read(struct buffer_head *bh) -{ - bh->b_end_io = end_buffer_async_read; - set_buffer_async_read(bh); -} - -static void mark_buffer_async_write_endio(struct buffer_head *bh, - bh_end_io_t *handler) -{ - bh->b_end_io = handler; - set_buffer_async_write(bh); -} - -void mark_buffer_async_write(struct buffer_head *bh) -{ - mark_buffer_async_write_endio(bh, end_buffer_async_write); -} -EXPORT_SYMBOL(mark_buffer_async_write); - - -/* - * fs/buffer.c contains helper functions for buffer-backed address space's - * fsync functions. A common requirement for buffer-based filesystems is - * that certain data from the backing blockdev needs to be written out for - * a successful fsync(). For example, ext2 indirect blocks need to be - * written back and waited upon before fsync() returns. - * - * The functions mark_buffer_inode_dirty(), fsync_inode_buffers(), - * inode_has_buffers() and invalidate_inode_buffers() are provided for the - * management of a list of dependent buffers at ->i_mapping->private_list. - * - * Locking is a little subtle: try_to_free_buffers() will remove buffers - * from their controlling inode's queue when they are being freed. But - * try_to_free_buffers() will be operating against the *blockdev* mapping - * at the time, not against the S_ISREG file which depends on those buffers. - * So the locking for private_list is via the private_lock in the address_space - * which backs the buffers. Which is different from the address_space - * against which the buffers are listed. So for a particular address_space, - * mapping->private_lock does *not* protect mapping->private_list! In fact, - * mapping->private_list will always be protected by the backing blockdev's - * ->private_lock. - * - * Which introduces a requirement: all buffers on an address_space's - * ->private_list must be from the same address_space: the blockdev's. - * - * address_spaces which do not place buffers at ->private_list via these - * utility functions are free to use private_lock and private_list for - * whatever they want. The only requirement is that list_empty(private_list) - * be true at clear_inode() time. - * - * FIXME: clear_inode should not call invalidate_inode_buffers(). The - * filesystems should do that. invalidate_inode_buffers() should just go - * BUG_ON(!list_empty). - * - * FIXME: mark_buffer_dirty_inode() is a data-plane operation. It should - * take an address_space, not an inode. And it should be called - * mark_buffer_dirty_fsync() to clearly define why those buffers are being - * queued up. - * - * FIXME: mark_buffer_dirty_inode() doesn't need to add the buffer to the - * list if it is already on a list. Because if the buffer is on a list, - * it *must* already be on the right one. If not, the filesystem is being - * silly. This will save a ton of locking. But first we have to ensure - * that buffers are taken *off* the old inode's list when they are freed - * (presumably in truncate). That requires careful auditing of all - * filesystems (do it inside bforget()). It could also be done by bringing - * b_inode back. - */ - -/* - * The buffer's backing address_space's private_lock must be held - */ -static void __remove_assoc_queue(struct buffer_head *bh) -{ - list_del_init(&bh->b_assoc_buffers); - WARN_ON(!bh->b_assoc_map); - if (buffer_write_io_error(bh)) - set_bit(AS_EIO, &bh->b_assoc_map->flags); - bh->b_assoc_map = NULL; -} - -int inode_has_buffers(struct inode *inode) -{ - return !list_empty(&inode->i_data.private_list); -} - -/* - * osync is designed to support O_SYNC io. It waits synchronously for - * all already-submitted IO to complete, but does not queue any new - * writes to the disk. - * - * To do O_SYNC writes, just queue the buffer writes with ll_rw_block as - * you dirty the buffers, and then use osync_inode_buffers to wait for - * completion. Any other dirty buffers which are not yet queued for - * write will not be flushed to disk by the osync. - */ -static int osync_buffers_list(spinlock_t *lock, struct list_head *list) -{ - struct buffer_head *bh; - struct list_head *p; - int err = 0; - - spin_lock(lock); -repeat: - list_for_each_prev(p, list) { - bh = BH_ENTRY(p); - if (buffer_locked(bh)) { - get_bh(bh); - spin_unlock(lock); - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) - err = -EIO; - brelse(bh); - spin_lock(lock); - goto repeat; - } - } - spin_unlock(lock); - return err; -} - -static void do_thaw_one(struct super_block *sb, void *unused) -{ - while (sb->s_bdev && !thaw_bdev(sb->s_bdev, sb)) - printk(KERN_WARNING "Emergency Thaw on %pg\n", sb->s_bdev); -} - -static void do_thaw_all(struct work_struct *work) -{ - iterate_supers(do_thaw_one, NULL); - kfree(work); - printk(KERN_WARNING "Emergency Thaw complete\n"); -} - -/** - * emergency_thaw_all -- forcibly thaw every frozen filesystem - * - * Used for emergency unfreeze of all filesystems via SysRq - */ -void emergency_thaw_all(void) -{ - struct work_struct *work; - - work = kmalloc(sizeof(*work), GFP_ATOMIC); - if (work) { - INIT_WORK(work, do_thaw_all); - schedule_work(work); - } -} - -/** - * sync_mapping_buffers - write out & wait upon a mapping's "associated" buffers - * @mapping: the mapping which wants those buffers written - * - * Starts I/O against the buffers at mapping->private_list, and waits upon - * that I/O. - * - * Basically, this is a convenience function for fsync(). - * @mapping is a file or directory which needs those buffers to be written for - * a successful fsync(). - */ -int sync_mapping_buffers(struct address_space *mapping) -{ - struct address_space *buffer_mapping = mapping->private_data; - - if (buffer_mapping == NULL || list_empty(&mapping->private_list)) - return 0; - - return fsync_buffers_list(&buffer_mapping->private_lock, - &mapping->private_list); -} -EXPORT_SYMBOL(sync_mapping_buffers); - -/* - * Called when we've recently written block `bblock', and it is known that - * `bblock' was for a buffer_boundary() buffer. This means that the block at - * `bblock + 1' is probably a dirty indirect block. Hunt it down and, if it's - * dirty, schedule it for IO. So that indirects merge nicely with their data. - */ -void write_boundary_block(struct block_device *bdev, - sector_t bblock, unsigned blocksize) -{ - struct buffer_head *bh = __find_get_block(bdev, bblock + 1, blocksize); - if (bh) { - if (buffer_dirty(bh)) - ll_rw_block(REQ_OP_WRITE, 0, 1, &bh); - put_bh(bh); - } -} - -void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode) -{ - struct address_space *mapping = inode->i_mapping; - struct address_space *buffer_mapping = bh->b_page->mapping; - - mark_buffer_dirty(bh); - if (!mapping->private_data) { - mapping->private_data = buffer_mapping; - } else { - BUG_ON(mapping->private_data != buffer_mapping); - } - if (!bh->b_assoc_map) { - spin_lock(&buffer_mapping->private_lock); - list_move_tail(&bh->b_assoc_buffers, - &mapping->private_list); - bh->b_assoc_map = mapping; - spin_unlock(&buffer_mapping->private_lock); - } -} -EXPORT_SYMBOL(mark_buffer_dirty_inode); - -/* - * Mark the page dirty, and set it dirty in the radix tree, and mark the inode - * dirty. - * - * If warn is true, then emit a warning if the page is not uptodate and has - * not been truncated. - * - * The caller must hold lock_page_memcg(). - */ -static void __set_page_dirty(struct page *page, struct address_space *mapping, - int warn) -{ - unsigned long flags; - - spin_lock_irqsave(&mapping->tree_lock, flags); - if (page->mapping) { /* Race with truncate? */ - WARN_ON_ONCE(warn && !PageUptodate(page)); - account_page_dirtied(page, mapping); - radix_tree_tag_set(&mapping->page_tree, - page_index(page), PAGECACHE_TAG_DIRTY); - } - spin_unlock_irqrestore(&mapping->tree_lock, flags); -} - -/* - * Add a page to the dirty page list. - * - * It is a sad fact of life that this function is called from several places - * deeply under spinlocking. It may not sleep. - * - * If the page has buffers, the uptodate buffers are set dirty, to preserve - * dirty-state coherency between the page and the buffers. It the page does - * not have buffers then when they are later attached they will all be set - * dirty. - * - * The buffers are dirtied before the page is dirtied. There's a small race - * window in which a writepage caller may see the page cleanness but not the - * buffer dirtiness. That's fine. If this code were to set the page dirty - * before the buffers, a concurrent writepage caller could clear the page dirty - * bit, see a bunch of clean buffers and we'd end up with dirty buffers/clean - * page on the dirty page list. - * - * We use private_lock to lock against try_to_free_buffers while using the - * page's buffer list. Also use this to protect against clean buffers being - * added to the page after it was set dirty. - * - * FIXME: may need to call ->reservepage here as well. That's rather up to the - * address_space though. - */ -int __set_page_dirty_buffers(struct page *page) -{ - int newly_dirty; - struct address_space *mapping = page_mapping(page); - - if (unlikely(!mapping)) - return !TestSetPageDirty(page); - - spin_lock(&mapping->private_lock); - if (page_has_buffers(page)) { - struct buffer_head *head = page_buffers(page); - struct buffer_head *bh = head; - - do { - set_buffer_dirty(bh); - bh = bh->b_this_page; - } while (bh != head); - } - /* - * Lock out page->mem_cgroup migration to keep PageDirty - * synchronized with per-memcg dirty page counters. - */ - lock_page_memcg(page); - newly_dirty = !TestSetPageDirty(page); - spin_unlock(&mapping->private_lock); - - if (newly_dirty) - __set_page_dirty(page, mapping, 1); - - unlock_page_memcg(page); - - if (newly_dirty) - __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); - - return newly_dirty; -} -EXPORT_SYMBOL(__set_page_dirty_buffers); - -/* - * Write out and wait upon a list of buffers. - * - * We have conflicting pressures: we want to make sure that all - * initially dirty buffers get waited on, but that any subsequently - * dirtied buffers don't. After all, we don't want fsync to last - * forever if somebody is actively writing to the file. - * - * Do this in two main stages: first we copy dirty buffers to a - * temporary inode list, queueing the writes as we go. Then we clean - * up, waiting for those writes to complete. - * - * During this second stage, any subsequent updates to the file may end - * up refiling the buffer on the original inode's dirty list again, so - * there is a chance we will end up with a buffer queued for write but - * not yet completed on that list. So, as a final cleanup we go through - * the osync code to catch these locked, dirty buffers without requeuing - * any newly dirty buffers for write. - */ -static int fsync_buffers_list(spinlock_t *lock, struct list_head *list) -{ - struct buffer_head *bh; - struct list_head tmp; - struct address_space *mapping; - int err = 0, err2; - struct blk_plug plug; - - INIT_LIST_HEAD(&tmp); - blk_start_plug(&plug); - - spin_lock(lock); - while (!list_empty(list)) { - bh = BH_ENTRY(list->next); - mapping = bh->b_assoc_map; - __remove_assoc_queue(bh); - /* Avoid race with mark_buffer_dirty_inode() which does - * a lockless check and we rely on seeing the dirty bit */ - smp_mb(); - if (buffer_dirty(bh) || buffer_locked(bh)) { - list_add(&bh->b_assoc_buffers, &tmp); - bh->b_assoc_map = mapping; - if (buffer_dirty(bh)) { - get_bh(bh); - spin_unlock(lock); - /* - * Ensure any pending I/O completes so that - * write_dirty_buffer() actually writes the - * current contents - it is a noop if I/O is - * still in flight on potentially older - * contents. - */ - write_dirty_buffer(bh, WRITE_SYNC); - - /* - * Kick off IO for the previous mapping. Note - * that we will not run the very last mapping, - * wait_on_buffer() will do that for us - * through sync_buffer(). - */ - brelse(bh); - spin_lock(lock); - } - } - } - - spin_unlock(lock); - blk_finish_plug(&plug); - spin_lock(lock); - - while (!list_empty(&tmp)) { - bh = BH_ENTRY(tmp.prev); - get_bh(bh); - mapping = bh->b_assoc_map; - __remove_assoc_queue(bh); - /* Avoid race with mark_buffer_dirty_inode() which does - * a lockless check and we rely on seeing the dirty bit */ - smp_mb(); - if (buffer_dirty(bh)) { - list_add(&bh->b_assoc_buffers, - &mapping->private_list); - bh->b_assoc_map = mapping; - } - spin_unlock(lock); - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) - err = -EIO; - brelse(bh); - spin_lock(lock); - } - - spin_unlock(lock); - err2 = osync_buffers_list(lock, list); - if (err) - return err; - else - return err2; -} - -/* - * Invalidate any and all dirty buffers on a given inode. We are - * probably unmounting the fs, but that doesn't mean we have already - * done a sync(). Just drop the buffers from the inode list. - * - * NOTE: we take the inode's blockdev's mapping's private_lock. Which - * assumes that all the buffers are against the blockdev. Not true - * for reiserfs. - */ -void invalidate_inode_buffers(struct inode *inode) -{ - if (inode_has_buffers(inode)) { - struct address_space *mapping = &inode->i_data; - struct list_head *list = &mapping->private_list; - struct address_space *buffer_mapping = mapping->private_data; - - spin_lock(&buffer_mapping->private_lock); - while (!list_empty(list)) - __remove_assoc_queue(BH_ENTRY(list->next)); - spin_unlock(&buffer_mapping->private_lock); - } -} -EXPORT_SYMBOL(invalidate_inode_buffers); - -/* - * Remove any clean buffers from the inode's buffer list. This is called - * when we're trying to free the inode itself. Those buffers can pin it. - * - * Returns true if all buffers were removed. - */ -int remove_inode_buffers(struct inode *inode) -{ - int ret = 1; - - if (inode_has_buffers(inode)) { - struct address_space *mapping = &inode->i_data; - struct list_head *list = &mapping->private_list; - struct address_space *buffer_mapping = mapping->private_data; - - spin_lock(&buffer_mapping->private_lock); - while (!list_empty(list)) { - struct buffer_head *bh = BH_ENTRY(list->next); - if (buffer_dirty(bh)) { - ret = 0; - break; - } - __remove_assoc_queue(bh); - } - spin_unlock(&buffer_mapping->private_lock); - } - return ret; -} - -/* - * Create the appropriate buffers when given a page for data area and - * the size of each buffer.. Use the bh->b_this_page linked list to - * follow the buffers created. Return NULL if unable to create more - * buffers. - * - * The retry flag is used to differentiate async IO (paging, swapping) - * which may not fail from ordinary buffer allocations. - */ -struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size, - int retry) -{ - struct buffer_head *bh, *head; - long offset; - -try_again: - head = NULL; - offset = PAGE_SIZE; - while ((offset -= size) >= 0) { - bh = alloc_buffer_head(GFP_NOFS); - if (!bh) - goto no_grow; - - bh->b_this_page = head; - bh->b_blocknr = -1; - head = bh; - - bh->b_size = size; - - /* Link the buffer to its page */ - set_bh_page(bh, page, offset); - } - return head; -/* - * In case anything failed, we just free everything we got. - */ -no_grow: - if (head) { - do { - bh = head; - head = head->b_this_page; - free_buffer_head(bh); - } while (head); - } - - /* - * Return failure for non-async IO requests. Async IO requests - * are not allowed to fail, so we have to wait until buffer heads - * become available. But we don't want tasks sleeping with - * partially complete buffers, so all were released above. - */ - if (!retry) - return NULL; - - /* We're _really_ low on memory. Now we just - * wait for old buffer heads to become free due to - * finishing IO. Since this is an async request and - * the reserve list is empty, we're sure there are - * async buffer heads in use. - */ - free_more_memory(); - goto try_again; -} -EXPORT_SYMBOL_GPL(alloc_page_buffers); - -static inline void -link_dev_buffers(struct page *page, struct buffer_head *head) -{ - struct buffer_head *bh, *tail; - - bh = head; - do { - tail = bh; - bh = bh->b_this_page; - } while (bh); - tail->b_this_page = head; - attach_page_buffers(page, head); -} - -static sector_t blkdev_max_block(struct block_device *bdev, unsigned int size) -{ - sector_t retval = ~((sector_t)0); - loff_t sz = i_size_read(bdev->bd_inode); - - if (sz) { - unsigned int sizebits = blksize_bits(size); - retval = (sz >> sizebits); - } - return retval; -} - -/* - * Initialise the state of a blockdev page's buffers. - */ -static sector_t -init_page_buffers(struct page *page, struct block_device *bdev, - sector_t block, int size) -{ - struct buffer_head *head = page_buffers(page); - struct buffer_head *bh = head; - int uptodate = PageUptodate(page); - sector_t end_block = blkdev_max_block(I_BDEV(bdev->bd_inode), size); - - do { - if (!buffer_mapped(bh)) { - init_buffer(bh, NULL, NULL); - bh->b_bdev = bdev; - bh->b_blocknr = block; - if (uptodate) - set_buffer_uptodate(bh); - if (block < end_block) - set_buffer_mapped(bh); - } - block++; - bh = bh->b_this_page; - } while (bh != head); - - /* - * Caller needs to validate requested block against end of device. - */ - return end_block; -} - -/* - * Create the page-cache page that contains the requested block. - * - * This is used purely for blockdev mappings. - */ -static int -grow_dev_page(struct block_device *bdev, sector_t block, - pgoff_t index, int size, int sizebits, gfp_t gfp) -{ - struct inode *inode = bdev->bd_inode; - struct page *page; - struct buffer_head *bh; - sector_t end_block; - int ret = 0; /* Will call free_more_memory() */ - gfp_t gfp_mask; - - gfp_mask = mapping_gfp_constraint(inode->i_mapping, ~__GFP_FS) | gfp; - - /* - * XXX: __getblk_slow() can not really deal with failure and - * will endlessly loop on improvised global reclaim. Prefer - * looping in the allocator rather than here, at least that - * code knows what it's doing. - */ - gfp_mask |= __GFP_NOFAIL; - - page = find_or_create_page(inode->i_mapping, index, gfp_mask); - if (!page) - return ret; - - BUG_ON(!PageLocked(page)); - - if (page_has_buffers(page)) { - bh = page_buffers(page); - if (bh->b_size == size) { - end_block = init_page_buffers(page, bdev, - (sector_t)index << sizebits, - size); - goto done; - } - if (!try_to_free_buffers(page)) - goto failed; - } - - /* - * Allocate some buffers for this page - */ - bh = alloc_page_buffers(page, size, 0); - if (!bh) - goto failed; - - /* - * Link the page to the buffers and initialise them. Take the - * lock to be atomic wrt __find_get_block(), which does not - * run under the page lock. - */ - spin_lock(&inode->i_mapping->private_lock); - link_dev_buffers(page, bh); - end_block = init_page_buffers(page, bdev, (sector_t)index << sizebits, - size); - spin_unlock(&inode->i_mapping->private_lock); -done: - ret = (block < end_block) ? 1 : -ENXIO; -failed: - unlock_page(page); - put_page(page); - return ret; -} - -/* - * Create buffers for the specified block device block's page. If - * that page was dirty, the buffers are set dirty also. - */ -static int -grow_buffers(struct block_device *bdev, sector_t block, int size, gfp_t gfp) -{ - pgoff_t index; - int sizebits; - - sizebits = -1; - do { - sizebits++; - } while ((size << sizebits) < PAGE_SIZE); - - index = block >> sizebits; - - /* - * Check for a block which wants to lie outside our maximum possible - * pagecache index. (this comparison is done using sector_t types). - */ - if (unlikely(index != block >> sizebits)) { - printk(KERN_ERR "%s: requested out-of-range block %llu for " - "device %pg\n", - __func__, (unsigned long long)block, - bdev); - return -EIO; - } - - /* Create a page with the proper size buffers.. */ - return grow_dev_page(bdev, block, index, size, sizebits, gfp); -} - -static struct buffer_head * -__getblk_slow(struct block_device *bdev, sector_t block, - unsigned size, gfp_t gfp) -{ - /* Size must be multiple of hard sectorsize */ - if (unlikely(size & (bdev_logical_block_size(bdev)-1) || - (size < 512 || size > PAGE_SIZE))) { - printk(KERN_ERR "getblk(): invalid block size %d requested\n", - size); - printk(KERN_ERR "logical block size: %d\n", - bdev_logical_block_size(bdev)); - - dump_stack(); - return NULL; - } - - for (;;) { - struct buffer_head *bh; - int ret; - - bh = __find_get_block(bdev, block, size); - if (bh) - return bh; - - ret = grow_buffers(bdev, block, size, gfp); - if (ret < 0) - return NULL; - if (ret == 0) - free_more_memory(); - } -} - -/* - * The relationship between dirty buffers and dirty pages: - * - * Whenever a page has any dirty buffers, the page's dirty bit is set, and - * the page is tagged dirty in its radix tree. - * - * At all times, the dirtiness of the buffers represents the dirtiness of - * subsections of the page. If the page has buffers, the page dirty bit is - * merely a hint about the true dirty state. - * - * When a page is set dirty in its entirety, all its buffers are marked dirty - * (if the page has buffers). - * - * When a buffer is marked dirty, its page is dirtied, but the page's other - * buffers are not. - * - * Also. When blockdev buffers are explicitly read with bread(), they - * individually become uptodate. But their backing page remains not - * uptodate - even if all of its buffers are uptodate. A subsequent - * block_read_full_page() against that page will discover all the uptodate - * buffers, will set the page uptodate and will perform no I/O. - */ - -/** - * mark_buffer_dirty - mark a buffer_head as needing writeout - * @bh: the buffer_head to mark dirty - * - * mark_buffer_dirty() will set the dirty bit against the buffer, then set its - * backing page dirty, then tag the page as dirty in its address_space's radix - * tree and then attach the address_space's inode to its superblock's dirty - * inode list. - * - * mark_buffer_dirty() is atomic. It takes bh->b_page->mapping->private_lock, - * mapping->tree_lock and mapping->host->i_lock. - */ -void mark_buffer_dirty(struct buffer_head *bh) -{ - WARN_ON_ONCE(!buffer_uptodate(bh)); - - trace_block_dirty_buffer(bh); - - /* - * Very *carefully* optimize the it-is-already-dirty case. - * - * Don't let the final "is it dirty" escape to before we - * perhaps modified the buffer. - */ - if (buffer_dirty(bh)) { - smp_mb(); - if (buffer_dirty(bh)) - return; - } - - if (!test_set_buffer_dirty(bh)) { - struct page *page = bh->b_page; - struct address_space *mapping = NULL; - - lock_page_memcg(page); - if (!TestSetPageDirty(page)) { - mapping = page_mapping(page); - if (mapping) - __set_page_dirty(page, mapping, 0); - } - unlock_page_memcg(page); - if (mapping) - __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); - } -} -EXPORT_SYMBOL(mark_buffer_dirty); - -/* - * Decrement a buffer_head's reference count. If all buffers against a page - * have zero reference count, are clean and unlocked, and if the page is clean - * and unlocked then try_to_free_buffers() may strip the buffers from the page - * in preparation for freeing it (sometimes, rarely, buffers are removed from - * a page but it ends up not being freed, and buffers may later be reattached). - */ -void __brelse(struct buffer_head * buf) -{ - if (atomic_read(&buf->b_count)) { - put_bh(buf); - return; - } - WARN(1, KERN_ERR "VFS: brelse: Trying to free free buffer\n"); -} -EXPORT_SYMBOL(__brelse); - -/* - * bforget() is like brelse(), except it discards any - * potentially dirty data. - */ -void __bforget(struct buffer_head *bh) -{ - clear_buffer_dirty(bh); - if (bh->b_assoc_map) { - struct address_space *buffer_mapping = bh->b_page->mapping; - - spin_lock(&buffer_mapping->private_lock); - list_del_init(&bh->b_assoc_buffers); - bh->b_assoc_map = NULL; - spin_unlock(&buffer_mapping->private_lock); - } - __brelse(bh); -} -EXPORT_SYMBOL(__bforget); - -static struct buffer_head *__bread_slow(struct buffer_head *bh) -{ - lock_buffer(bh); - if (buffer_uptodate(bh)) { - unlock_buffer(bh); - return bh; - } else { - get_bh(bh); - bh->b_end_io = end_buffer_read_sync; - submit_bh(REQ_OP_READ, 0, bh); - wait_on_buffer(bh); - if (buffer_uptodate(bh)) - return bh; - } - brelse(bh); - return NULL; -} - -/* - * Per-cpu buffer LRU implementation. To reduce the cost of __find_get_block(). - * The bhs[] array is sorted - newest buffer is at bhs[0]. Buffers have their - * refcount elevated by one when they're in an LRU. A buffer can only appear - * once in a particular CPU's LRU. A single buffer can be present in multiple - * CPU's LRUs at the same time. - * - * This is a transparent caching front-end to sb_bread(), sb_getblk() and - * sb_find_get_block(). - * - * The LRUs themselves only need locking against invalidate_bh_lrus. We use - * a local interrupt disable for that. - */ - -#define BH_LRU_SIZE 16 - -struct bh_lru { - struct buffer_head *bhs[BH_LRU_SIZE]; -}; - -static DEFINE_PER_CPU(struct bh_lru, bh_lrus) = {{ NULL }}; - -#ifdef CONFIG_SMP -#define bh_lru_lock() local_irq_disable() -#define bh_lru_unlock() local_irq_enable() -#else -#define bh_lru_lock() preempt_disable() -#define bh_lru_unlock() preempt_enable() -#endif - -static inline void check_irqs_on(void) -{ -#ifdef irqs_disabled - BUG_ON(irqs_disabled()); -#endif -} - -/* - * The LRU management algorithm is dopey-but-simple. Sorry. - */ -static void bh_lru_install(struct buffer_head *bh) -{ - struct buffer_head *evictee = NULL; - - check_irqs_on(); - bh_lru_lock(); - if (__this_cpu_read(bh_lrus.bhs[0]) != bh) { - struct buffer_head *bhs[BH_LRU_SIZE]; - int in; - int out = 0; - - get_bh(bh); - bhs[out++] = bh; - for (in = 0; in < BH_LRU_SIZE; in++) { - struct buffer_head *bh2 = - __this_cpu_read(bh_lrus.bhs[in]); - - if (bh2 == bh) { - __brelse(bh2); - } else { - if (out >= BH_LRU_SIZE) { - BUG_ON(evictee != NULL); - evictee = bh2; - } else { - bhs[out++] = bh2; - } - } - } - while (out < BH_LRU_SIZE) - bhs[out++] = NULL; - memcpy(this_cpu_ptr(&bh_lrus.bhs), bhs, sizeof(bhs)); - } - bh_lru_unlock(); - - if (evictee) - __brelse(evictee); -} - -/* - * Look up the bh in this cpu's LRU. If it's there, move it to the head. - */ -static struct buffer_head * -lookup_bh_lru(struct block_device *bdev, sector_t block, unsigned size) -{ - struct buffer_head *ret = NULL; - unsigned int i; - - check_irqs_on(); - bh_lru_lock(); - for (i = 0; i < BH_LRU_SIZE; i++) { - struct buffer_head *bh = __this_cpu_read(bh_lrus.bhs[i]); - - if (bh && bh->b_blocknr == block && bh->b_bdev == bdev && - bh->b_size == size) { - if (i) { - while (i) { - __this_cpu_write(bh_lrus.bhs[i], - __this_cpu_read(bh_lrus.bhs[i - 1])); - i--; - } - __this_cpu_write(bh_lrus.bhs[0], bh); - } - get_bh(bh); - ret = bh; - break; - } - } - bh_lru_unlock(); - return ret; -} - -/* - * Perform a pagecache lookup for the matching buffer. If it's there, refresh - * it in the LRU and mark it as accessed. If it is not present then return - * NULL - */ -struct buffer_head * -__find_get_block(struct block_device *bdev, sector_t block, unsigned size) -{ - struct buffer_head *bh = lookup_bh_lru(bdev, block, size); - - if (bh == NULL) { - /* __find_get_block_slow will mark the page accessed */ - bh = __find_get_block_slow(bdev, block); - if (bh) - bh_lru_install(bh); - } else - touch_buffer(bh); - - return bh; -} -EXPORT_SYMBOL(__find_get_block); - -/* - * __getblk_gfp() will locate (and, if necessary, create) the buffer_head - * which corresponds to the passed block_device, block and size. The - * returned buffer has its reference count incremented. - * - * __getblk_gfp() will lock up the machine if grow_dev_page's - * try_to_free_buffers() attempt is failing. FIXME, perhaps? - */ -struct buffer_head * -__getblk_gfp(struct block_device *bdev, sector_t block, - unsigned size, gfp_t gfp) -{ - struct buffer_head *bh = __find_get_block(bdev, block, size); - - might_sleep(); - if (bh == NULL) - bh = __getblk_slow(bdev, block, size, gfp); - return bh; -} -EXPORT_SYMBOL(__getblk_gfp); - -/* - * Do async read-ahead on a buffer.. - */ -void __breadahead(struct block_device *bdev, sector_t block, unsigned size) -{ - struct buffer_head *bh = __getblk(bdev, block, size); - if (likely(bh)) { - ll_rw_block(REQ_OP_READ, REQ_RAHEAD, 1, &bh); - brelse(bh); - } -} -EXPORT_SYMBOL(__breadahead); - -/** - * __bread_gfp() - reads a specified block and returns the bh - * @bdev: the block_device to read from - * @block: number of block - * @size: size (in bytes) to read - * @gfp: page allocation flag - * - * Reads a specified block, and returns buffer head that contains it. - * The page cache can be allocated from non-movable area - * not to prevent page migration if you set gfp to zero. - * It returns NULL if the block was unreadable. - */ -struct buffer_head * -__bread_gfp(struct block_device *bdev, sector_t block, - unsigned size, gfp_t gfp) -{ - struct buffer_head *bh = __getblk_gfp(bdev, block, size, gfp); - - if (likely(bh) && !buffer_uptodate(bh)) - bh = __bread_slow(bh); - return bh; -} -EXPORT_SYMBOL(__bread_gfp); - -/* - * invalidate_bh_lrus() is called rarely - but not only at unmount. - * This doesn't race because it runs in each cpu either in irq - * or with preempt disabled. - */ -static void invalidate_bh_lru(void *arg) -{ - struct bh_lru *b = &get_cpu_var(bh_lrus); - int i; - - for (i = 0; i < BH_LRU_SIZE; i++) { - brelse(b->bhs[i]); - b->bhs[i] = NULL; - } - put_cpu_var(bh_lrus); -} - -static bool has_bh_in_lru(int cpu, void *dummy) -{ - struct bh_lru *b = per_cpu_ptr(&bh_lrus, cpu); - int i; - - for (i = 0; i < BH_LRU_SIZE; i++) { - if (b->bhs[i]) - return 1; - } - - return 0; -} - -void invalidate_bh_lrus(void) -{ - on_each_cpu_cond(has_bh_in_lru, invalidate_bh_lru, NULL, 1, GFP_KERNEL); -} -EXPORT_SYMBOL_GPL(invalidate_bh_lrus); - -void set_bh_page(struct buffer_head *bh, - struct page *page, unsigned long offset) -{ - bh->b_page = page; - BUG_ON(offset >= PAGE_SIZE); - if (PageHighMem(page)) - /* - * This catches illegal uses and preserves the offset: - */ - bh->b_data = (char *)(0 + offset); - else - bh->b_data = page_address(page) + offset; -} -EXPORT_SYMBOL(set_bh_page); - -/* - * Called when truncating a buffer on a page completely. - */ - -/* Bits that are cleared during an invalidate */ -#define BUFFER_FLAGS_DISCARD \ - (1 << BH_Mapped | 1 << BH_New | 1 << BH_Req | \ - 1 << BH_Delay | 1 << BH_Unwritten) - -static void discard_buffer(struct buffer_head * bh) -{ - unsigned long b_state, b_state_old; - - lock_buffer(bh); - clear_buffer_dirty(bh); - bh->b_bdev = NULL; - b_state = bh->b_state; - for (;;) { - b_state_old = cmpxchg(&bh->b_state, b_state, - (b_state & ~BUFFER_FLAGS_DISCARD)); - if (b_state_old == b_state) - break; - b_state = b_state_old; - } - unlock_buffer(bh); -} - -/** - * block_invalidatepage - invalidate part or all of a buffer-backed page - * - * @page: the page which is affected - * @offset: start of the range to invalidate - * @length: length of the range to invalidate - * - * block_invalidatepage() is called when all or part of the page has become - * invalidated by a truncate operation. - * - * block_invalidatepage() does not have to release all buffers, but it must - * ensure that no dirty buffer is left outside @offset and that no I/O - * is underway against any of the blocks which are outside the truncation - * point. Because the caller is about to free (and possibly reuse) those - * blocks on-disk. - */ -void block_invalidatepage(struct page *page, unsigned int offset, - unsigned int length) -{ - struct buffer_head *head, *bh, *next; - unsigned int curr_off = 0; - unsigned int stop = length + offset; - - BUG_ON(!PageLocked(page)); - if (!page_has_buffers(page)) - goto out; - - /* - * Check for overflow - */ - BUG_ON(stop > PAGE_SIZE || stop < length); - - head = page_buffers(page); - bh = head; - do { - unsigned int next_off = curr_off + bh->b_size; - next = bh->b_this_page; - - /* - * Are we still fully in range ? - */ - if (next_off > stop) - goto out; - - /* - * is this block fully invalidated? - */ - if (offset <= curr_off) - discard_buffer(bh); - curr_off = next_off; - bh = next; - } while (bh != head); - - /* - * We release buffers only if the entire page is being invalidated. - * The get_block cached value has been unconditionally invalidated, - * so real IO is not possible anymore. - */ - if (offset == 0) - try_to_release_page(page, 0); -out: - return; -} -EXPORT_SYMBOL(block_invalidatepage); - - -/* - * We attach and possibly dirty the buffers atomically wrt - * __set_page_dirty_buffers() via private_lock. try_to_free_buffers - * is already excluded via the page lock. - */ -void create_empty_buffers(struct page *page, - unsigned long blocksize, unsigned long b_state) -{ - struct buffer_head *bh, *head, *tail; - - head = alloc_page_buffers(page, blocksize, 1); - bh = head; - do { - bh->b_state |= b_state; - tail = bh; - bh = bh->b_this_page; - } while (bh); - tail->b_this_page = head; - - spin_lock(&page->mapping->private_lock); - if (PageUptodate(page) || PageDirty(page)) { - bh = head; - do { - if (PageDirty(page)) - set_buffer_dirty(bh); - if (PageUptodate(page)) - set_buffer_uptodate(bh); - bh = bh->b_this_page; - } while (bh != head); - } - attach_page_buffers(page, head); - spin_unlock(&page->mapping->private_lock); -} -EXPORT_SYMBOL(create_empty_buffers); - -/* - * We are taking a block for data and we don't want any output from any - * buffer-cache aliases starting from return from that function and - * until the moment when something will explicitly mark the buffer - * dirty (hopefully that will not happen until we will free that block ;-) - * We don't even need to mark it not-uptodate - nobody can expect - * anything from a newly allocated buffer anyway. We used to used - * unmap_buffer() for such invalidation, but that was wrong. We definitely - * don't want to mark the alias unmapped, for example - it would confuse - * anyone who might pick it with bread() afterwards... - * - * Also.. Note that bforget() doesn't lock the buffer. So there can - * be writeout I/O going on against recently-freed buffers. We don't - * wait on that I/O in bforget() - it's more efficient to wait on the I/O - * only if we really need to. That happens here. - */ -void unmap_underlying_metadata(struct block_device *bdev, sector_t block) -{ - struct buffer_head *old_bh; - - might_sleep(); - - old_bh = __find_get_block_slow(bdev, block); - if (old_bh) { - clear_buffer_dirty(old_bh); - wait_on_buffer(old_bh); - clear_buffer_req(old_bh); - __brelse(old_bh); - } -} -EXPORT_SYMBOL(unmap_underlying_metadata); - -/* - * Size is a power-of-two in the range 512..PAGE_SIZE, - * and the case we care about most is PAGE_SIZE. - * - * So this *could* possibly be written with those - * constraints in mind (relevant mostly if some - * architecture has a slow bit-scan instruction) - */ -static inline int block_size_bits(unsigned int blocksize) -{ - return ilog2(blocksize); -} - -static struct buffer_head *create_page_buffers(struct page *page, struct inode *inode, unsigned int b_state) -{ - BUG_ON(!PageLocked(page)); - - if (!page_has_buffers(page)) - create_empty_buffers(page, 1 << ACCESS_ONCE(inode->i_blkbits), b_state); - return page_buffers(page); -} - -/* - * NOTE! All mapped/uptodate combinations are valid: - * - * Mapped Uptodate Meaning - * - * No No "unknown" - must do get_block() - * No Yes "hole" - zero-filled - * Yes No "allocated" - allocated on disk, not read in - * Yes Yes "valid" - allocated and up-to-date in memory. - * - * "Dirty" is valid only with the last case (mapped+uptodate). - */ - -/* - * While block_write_full_page is writing back the dirty buffers under - * the page lock, whoever dirtied the buffers may decide to clean them - * again at any time. We handle that by only looking at the buffer - * state inside lock_buffer(). - * - * If block_write_full_page() is called for regular writeback - * (wbc->sync_mode == WB_SYNC_NONE) then it will redirty a page which has a - * locked buffer. This only can happen if someone has written the buffer - * directly, with submit_bh(). At the address_space level PageWriteback - * prevents this contention from occurring. - * - * If block_write_full_page() is called with wbc->sync_mode == - * WB_SYNC_ALL, the writes are posted using WRITE_SYNC; this - * causes the writes to be flagged as synchronous writes. - */ -int __block_write_full_page(struct inode *inode, struct page *page, - get_block_t *get_block, struct writeback_control *wbc, - bh_end_io_t *handler) -{ - int err; - sector_t block; - sector_t last_block; - struct buffer_head *bh, *head; - unsigned int blocksize, bbits; - int nr_underway = 0; - int write_flags = (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : 0); - - head = create_page_buffers(page, inode, - (1 << BH_Dirty)|(1 << BH_Uptodate)); - - /* - * Be very careful. We have no exclusion from __set_page_dirty_buffers - * here, and the (potentially unmapped) buffers may become dirty at - * any time. If a buffer becomes dirty here after we've inspected it - * then we just miss that fact, and the page stays dirty. - * - * Buffers outside i_size may be dirtied by __set_page_dirty_buffers; - * handle that here by just cleaning them. - */ - - bh = head; - blocksize = bh->b_size; - bbits = block_size_bits(blocksize); - - block = (sector_t)page->index << (PAGE_SHIFT - bbits); - last_block = (i_size_read(inode) - 1) >> bbits; - - /* - * Get all the dirty buffers mapped to disk addresses and - * handle any aliases from the underlying blockdev's mapping. - */ - do { - if (block > last_block) { - /* - * mapped buffers outside i_size will occur, because - * this page can be outside i_size when there is a - * truncate in progress. - */ - /* - * The buffer was zeroed by block_write_full_page() - */ - clear_buffer_dirty(bh); - set_buffer_uptodate(bh); - } else if ((!buffer_mapped(bh) || buffer_delay(bh)) && - buffer_dirty(bh)) { - WARN_ON(bh->b_size != blocksize); - err = get_block(inode, block, bh, 1); - if (err) - goto recover; - clear_buffer_delay(bh); - if (buffer_new(bh)) { - /* blockdev mappings never come here */ - clear_buffer_new(bh); - unmap_underlying_metadata(bh->b_bdev, - bh->b_blocknr); - } - } - bh = bh->b_this_page; - block++; - } while (bh != head); - - do { - if (!buffer_mapped(bh)) - continue; - /* - * If it's a fully non-blocking write attempt and we cannot - * lock the buffer then redirty the page. Note that this can - * potentially cause a busy-wait loop from writeback threads - * and kswapd activity, but those code paths have their own - * higher-level throttling. - */ - if (wbc->sync_mode != WB_SYNC_NONE) { - lock_buffer(bh); - } else if (!trylock_buffer(bh)) { - redirty_page_for_writepage(wbc, page); - continue; - } - if (test_clear_buffer_dirty(bh)) { - mark_buffer_async_write_endio(bh, handler); - } else { - unlock_buffer(bh); - } - } while ((bh = bh->b_this_page) != head); - - /* - * The page and its buffers are protected by PageWriteback(), so we can - * drop the bh refcounts early. - */ - BUG_ON(PageWriteback(page)); - set_page_writeback(page); - - do { - struct buffer_head *next = bh->b_this_page; - if (buffer_async_write(bh)) { - submit_bh_wbc(REQ_OP_WRITE, write_flags, bh, 0, wbc); - nr_underway++; - } - bh = next; - } while (bh != head); - unlock_page(page); - - err = 0; -done: - if (nr_underway == 0) { - /* - * The page was marked dirty, but the buffers were - * clean. Someone wrote them back by hand with - * ll_rw_block/submit_bh. A rare case. - */ - end_page_writeback(page); - - /* - * The page and buffer_heads can be released at any time from - * here on. - */ - } - return err; - -recover: - /* - * ENOSPC, or some other error. We may already have added some - * blocks to the file, so we need to write these out to avoid - * exposing stale data. - * The page is currently locked and not marked for writeback - */ - bh = head; - /* Recovery: lock and submit the mapped buffers */ - do { - if (buffer_mapped(bh) && buffer_dirty(bh) && - !buffer_delay(bh)) { - lock_buffer(bh); - mark_buffer_async_write_endio(bh, handler); - } else { - /* - * The buffer may have been set dirty during - * attachment to a dirty page. - */ - clear_buffer_dirty(bh); - } - } while ((bh = bh->b_this_page) != head); - SetPageError(page); - BUG_ON(PageWriteback(page)); - mapping_set_error(page->mapping, err); - set_page_writeback(page); - do { - struct buffer_head *next = bh->b_this_page; - if (buffer_async_write(bh)) { - clear_buffer_dirty(bh); - submit_bh_wbc(REQ_OP_WRITE, write_flags, bh, 0, wbc); - nr_underway++; - } - bh = next; - } while (bh != head); - unlock_page(page); - goto done; -} -EXPORT_SYMBOL(__block_write_full_page); - -/* - * If a page has any new buffers, zero them out here, and mark them uptodate - * and dirty so they'll be written out (in order to prevent uninitialised - * block data from leaking). And clear the new bit. - */ -void page_zero_new_buffers(struct page *page, unsigned from, unsigned to) -{ - unsigned int block_start, block_end; - struct buffer_head *head, *bh; - - BUG_ON(!PageLocked(page)); - if (!page_has_buffers(page)) - return; - - bh = head = page_buffers(page); - block_start = 0; - do { - block_end = block_start + bh->b_size; - - if (buffer_new(bh)) { - if (block_end > from && block_start < to) { - if (!PageUptodate(page)) { - unsigned start, size; - - start = max(from, block_start); - size = min(to, block_end) - start; - - zero_user(page, start, size); - set_buffer_uptodate(bh); - } - - clear_buffer_new(bh); - mark_buffer_dirty(bh); - } - } - - block_start = block_end; - bh = bh->b_this_page; - } while (bh != head); -} -EXPORT_SYMBOL(page_zero_new_buffers); - -static void -iomap_to_bh(struct inode *inode, sector_t block, struct buffer_head *bh, - struct iomap *iomap) -{ - loff_t offset = block << inode->i_blkbits; - - bh->b_bdev = iomap->bdev; - - /* - * Block points to offset in file we need to map, iomap contains - * the offset at which the map starts. If the map ends before the - * current block, then do not map the buffer and let the caller - * handle it. - */ - BUG_ON(offset >= iomap->offset + iomap->length); - - switch (iomap->type) { - case IOMAP_HOLE: - /* - * If the buffer is not up to date or beyond the current EOF, - * we need to mark it as new to ensure sub-block zeroing is - * executed if necessary. - */ - if (!buffer_uptodate(bh) || - (offset >= i_size_read(inode))) - set_buffer_new(bh); - break; - case IOMAP_DELALLOC: - if (!buffer_uptodate(bh) || - (offset >= i_size_read(inode))) - set_buffer_new(bh); - set_buffer_uptodate(bh); - set_buffer_mapped(bh); - set_buffer_delay(bh); - break; - case IOMAP_UNWRITTEN: - /* - * For unwritten regions, we always need to ensure that - * sub-block writes cause the regions in the block we are not - * writing to are zeroed. Set the buffer as new to ensure this. - */ - set_buffer_new(bh); - set_buffer_unwritten(bh); - /* FALLTHRU */ - case IOMAP_MAPPED: - if (offset >= i_size_read(inode)) - set_buffer_new(bh); - bh->b_blocknr = (iomap->blkno >> (inode->i_blkbits - 9)) + - ((offset - iomap->offset) >> inode->i_blkbits); - set_buffer_mapped(bh); - break; - } -} - -int __block_write_begin_int(struct page *page, loff_t pos, unsigned len, - get_block_t *get_block, struct iomap *iomap) -{ - unsigned from = pos & (PAGE_SIZE - 1); - unsigned to = from + len; - struct inode *inode = page->mapping->host; - unsigned block_start, block_end; - sector_t block; - int err = 0; - unsigned blocksize, bbits; - struct buffer_head *bh, *head, *wait[2], **wait_bh=wait; - - BUG_ON(!PageLocked(page)); - BUG_ON(from > PAGE_SIZE); - BUG_ON(to > PAGE_SIZE); - BUG_ON(from > to); - - head = create_page_buffers(page, inode, 0); - blocksize = head->b_size; - bbits = block_size_bits(blocksize); - - block = (sector_t)page->index << (PAGE_SHIFT - bbits); - - for(bh = head, block_start = 0; bh != head || !block_start; - block++, block_start=block_end, bh = bh->b_this_page) { - block_end = block_start + blocksize; - if (block_end <= from || block_start >= to) { - if (PageUptodate(page)) { - if (!buffer_uptodate(bh)) - set_buffer_uptodate(bh); - } - continue; - } - if (buffer_new(bh)) - clear_buffer_new(bh); - if (!buffer_mapped(bh)) { - WARN_ON(bh->b_size != blocksize); - if (get_block) { - err = get_block(inode, block, bh, 1); - if (err) - break; - } else { - iomap_to_bh(inode, block, bh, iomap); - } - - if (buffer_new(bh)) { - unmap_underlying_metadata(bh->b_bdev, - bh->b_blocknr); - if (PageUptodate(page)) { - clear_buffer_new(bh); - set_buffer_uptodate(bh); - mark_buffer_dirty(bh); - continue; - } - if (block_end > to || block_start < from) - zero_user_segments(page, - to, block_end, - block_start, from); - continue; - } - } - if (PageUptodate(page)) { - if (!buffer_uptodate(bh)) - set_buffer_uptodate(bh); - continue; - } - if (!buffer_uptodate(bh) && !buffer_delay(bh) && - !buffer_unwritten(bh) && - (block_start < from || block_end > to)) { - ll_rw_block(REQ_OP_READ, 0, 1, &bh); - *wait_bh++=bh; - } - } - /* - * If we issued read requests - let them complete. - */ - while(wait_bh > wait) { - wait_on_buffer(*--wait_bh); - if (!buffer_uptodate(*wait_bh)) - err = -EIO; - } - if (unlikely(err)) - page_zero_new_buffers(page, from, to); - return err; -} - -int __block_write_begin(struct page *page, loff_t pos, unsigned len, - get_block_t *get_block) -{ - return __block_write_begin_int(page, pos, len, get_block, NULL); -} -EXPORT_SYMBOL(__block_write_begin); - -static int __block_commit_write(struct inode *inode, struct page *page, - unsigned from, unsigned to) -{ - unsigned block_start, block_end; - int partial = 0; - unsigned blocksize; - struct buffer_head *bh, *head; - - bh = head = page_buffers(page); - blocksize = bh->b_size; - - block_start = 0; - do { - block_end = block_start + blocksize; - if (block_end <= from || block_start >= to) { - if (!buffer_uptodate(bh)) - partial = 1; - } else { - set_buffer_uptodate(bh); - mark_buffer_dirty(bh); - } - clear_buffer_new(bh); - - block_start = block_end; - bh = bh->b_this_page; - } while (bh != head); - - /* - * If this is a partial write which happened to make all buffers - * uptodate then we can optimize away a bogus readpage() for - * the next read(). Here we 'discover' whether the page went - * uptodate as a result of this (potentially partial) write. - */ - if (!partial) - SetPageUptodate(page); - return 0; -} - -/* - * block_write_begin takes care of the basic task of block allocation and - * bringing partial write blocks uptodate first. - * - * The filesystem needs to handle block truncation upon failure. - */ -int block_write_begin(struct address_space *mapping, loff_t pos, unsigned len, - unsigned flags, struct page **pagep, get_block_t *get_block) -{ - pgoff_t index = pos >> PAGE_SHIFT; - struct page *page; - int status; - - page = grab_cache_page_write_begin(mapping, index, flags); - if (!page) - return -ENOMEM; - - status = __block_write_begin(page, pos, len, get_block); - if (unlikely(status)) { - unlock_page(page); - put_page(page); - page = NULL; - } - - *pagep = page; - return status; -} -EXPORT_SYMBOL(block_write_begin); - -int block_write_end(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) -{ - struct inode *inode = mapping->host; - unsigned start; - - start = pos & (PAGE_SIZE - 1); - - if (unlikely(copied < len)) { - /* - * The buffers that were written will now be uptodate, so we - * don't have to worry about a readpage reading them and - * overwriting a partial write. However if we have encountered - * a short write and only partially written into a buffer, it - * will not be marked uptodate, so a readpage might come in and - * destroy our partial write. - * - * Do the simplest thing, and just treat any short write to a - * non uptodate page as a zero-length write, and force the - * caller to redo the whole thing. - */ - if (!PageUptodate(page)) - copied = 0; - - page_zero_new_buffers(page, start+copied, start+len); - } - flush_dcache_page(page); - - /* This could be a short (even 0-length) commit */ - __block_commit_write(inode, page, start, start+copied); - - return copied; -} -EXPORT_SYMBOL(block_write_end); - -int generic_write_end(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) -{ - struct inode *inode = mapping->host; - loff_t old_size = inode->i_size; - int i_size_changed = 0; - - copied = block_write_end(file, mapping, pos, len, copied, page, fsdata); - - /* - * No need to use i_size_read() here, the i_size - * cannot change under us because we hold i_mutex. - * - * But it's important to update i_size while still holding page lock: - * page writeout could otherwise come in and zero beyond i_size. - */ - if (pos+copied > inode->i_size) { - i_size_write(inode, pos+copied); - i_size_changed = 1; - } - - unlock_page(page); - put_page(page); - - if (old_size < pos) - pagecache_isize_extended(inode, old_size, pos); - /* - * Don't mark the inode dirty under page lock. First, it unnecessarily - * makes the holding time of page lock longer. Second, it forces lock - * ordering of page lock and transaction start for journaling - * filesystems. - */ - if (i_size_changed) - mark_inode_dirty(inode); - - return copied; -} -EXPORT_SYMBOL(generic_write_end); - -/* - * block_is_partially_uptodate checks whether buffers within a page are - * uptodate or not. - * - * Returns true if all buffers which correspond to a file portion - * we want to read are uptodate. - */ -int block_is_partially_uptodate(struct page *page, unsigned long from, - unsigned long count) -{ - unsigned block_start, block_end, blocksize; - unsigned to; - struct buffer_head *bh, *head; - int ret = 1; - - if (!page_has_buffers(page)) - return 0; - - head = page_buffers(page); - blocksize = head->b_size; - to = min_t(unsigned, PAGE_SIZE - from, count); - to = from + to; - if (from < blocksize && to > PAGE_SIZE - blocksize) - return 0; - - bh = head; - block_start = 0; - do { - block_end = block_start + blocksize; - if (block_end > from && block_start < to) { - if (!buffer_uptodate(bh)) { - ret = 0; - break; - } - if (block_end >= to) - break; - } - block_start = block_end; - bh = bh->b_this_page; - } while (bh != head); - - return ret; -} -EXPORT_SYMBOL(block_is_partially_uptodate); - -/* - * Generic "read page" function for block devices that have the normal - * get_block functionality. This is most of the block device filesystems. - * Reads the page asynchronously --- the unlock_buffer() and - * set/clear_buffer_uptodate() functions propagate buffer state into the - * page struct once IO has completed. - */ -int block_read_full_page(struct page *page, get_block_t *get_block) -{ - struct inode *inode = page->mapping->host; - sector_t iblock, lblock; - struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE]; - unsigned int blocksize, bbits; - int nr, i; - int fully_mapped = 1; - - head = create_page_buffers(page, inode, 0); - blocksize = head->b_size; - bbits = block_size_bits(blocksize); - - iblock = (sector_t)page->index << (PAGE_SHIFT - bbits); - lblock = (i_size_read(inode)+blocksize-1) >> bbits; - bh = head; - nr = 0; - i = 0; - - do { - if (buffer_uptodate(bh)) - continue; - - if (!buffer_mapped(bh)) { - int err = 0; - - fully_mapped = 0; - if (iblock < lblock) { - WARN_ON(bh->b_size != blocksize); - err = get_block(inode, iblock, bh, 0); - if (err) - SetPageError(page); - } - if (!buffer_mapped(bh)) { - zero_user(page, i * blocksize, blocksize); - if (!err) - set_buffer_uptodate(bh); - continue; - } - /* - * get_block() might have updated the buffer - * synchronously - */ - if (buffer_uptodate(bh)) - continue; - } - arr[nr++] = bh; - } while (i++, iblock++, (bh = bh->b_this_page) != head); - - if (fully_mapped) - SetPageMappedToDisk(page); - - if (!nr) { - /* - * All buffers are uptodate - we can set the page uptodate - * as well. But not if get_block() returned an error. - */ - if (!PageError(page)) - SetPageUptodate(page); - unlock_page(page); - return 0; - } - - /* Stage two: lock the buffers */ - for (i = 0; i < nr; i++) { - bh = arr[i]; - lock_buffer(bh); - mark_buffer_async_read(bh); - } - - /* - * Stage 3: start the IO. Check for uptodateness - * inside the buffer lock in case another process reading - * the underlying blockdev brought it uptodate (the sct fix). - */ - for (i = 0; i < nr; i++) { - bh = arr[i]; - if (buffer_uptodate(bh)) - end_buffer_async_read(bh, 1); - else - submit_bh(REQ_OP_READ, 0, bh); - } - return 0; -} -EXPORT_SYMBOL(block_read_full_page); - -/* utility function for filesystems that need to do work on expanding - * truncates. Uses filesystem pagecache writes to allow the filesystem to - * deal with the hole. - */ -int generic_cont_expand_simple(struct inode *inode, loff_t size) -{ - struct address_space *mapping = inode->i_mapping; - struct page *page; - void *fsdata; - int err; - - err = inode_newsize_ok(inode, size); - if (err) - goto out; - - err = pagecache_write_begin(NULL, mapping, size, 0, - AOP_FLAG_UNINTERRUPTIBLE|AOP_FLAG_CONT_EXPAND, - &page, &fsdata); - if (err) - goto out; - - err = pagecache_write_end(NULL, mapping, size, 0, 0, page, fsdata); - BUG_ON(err > 0); - -out: - return err; -} -EXPORT_SYMBOL(generic_cont_expand_simple); - -static int cont_expand_zero(struct file *file, struct address_space *mapping, - loff_t pos, loff_t *bytes) -{ - struct inode *inode = mapping->host; - unsigned blocksize = 1 << inode->i_blkbits; - struct page *page; - void *fsdata; - pgoff_t index, curidx; - loff_t curpos; - unsigned zerofrom, offset, len; - int err = 0; - - index = pos >> PAGE_SHIFT; - offset = pos & ~PAGE_MASK; - - while (index > (curidx = (curpos = *bytes)>>PAGE_SHIFT)) { - zerofrom = curpos & ~PAGE_MASK; - if (zerofrom & (blocksize-1)) { - *bytes |= (blocksize-1); - (*bytes)++; - } - len = PAGE_SIZE - zerofrom; - - err = pagecache_write_begin(file, mapping, curpos, len, - AOP_FLAG_UNINTERRUPTIBLE, - &page, &fsdata); - if (err) - goto out; - zero_user(page, zerofrom, len); - err = pagecache_write_end(file, mapping, curpos, len, len, - page, fsdata); - if (err < 0) - goto out; - BUG_ON(err != len); - err = 0; - - balance_dirty_pages_ratelimited(mapping); - - if (unlikely(fatal_signal_pending(current))) { - err = -EINTR; - goto out; - } - } - - /* page covers the boundary, find the boundary offset */ - if (index == curidx) { - zerofrom = curpos & ~PAGE_MASK; - /* if we will expand the thing last block will be filled */ - if (offset <= zerofrom) { - goto out; - } - if (zerofrom & (blocksize-1)) { - *bytes |= (blocksize-1); - (*bytes)++; - } - len = offset - zerofrom; - - err = pagecache_write_begin(file, mapping, curpos, len, - AOP_FLAG_UNINTERRUPTIBLE, - &page, &fsdata); - if (err) - goto out; - zero_user(page, zerofrom, len); - err = pagecache_write_end(file, mapping, curpos, len, len, - page, fsdata); - if (err < 0) - goto out; - BUG_ON(err != len); - err = 0; - } -out: - return err; -} - -/* - * For moronic filesystems that do not allow holes in file. - * We may have to extend the file. - */ -int cont_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata, - get_block_t *get_block, loff_t *bytes) -{ - struct inode *inode = mapping->host; - unsigned blocksize = 1 << inode->i_blkbits; - unsigned zerofrom; - int err; - - err = cont_expand_zero(file, mapping, pos, bytes); - if (err) - return err; - - zerofrom = *bytes & ~PAGE_MASK; - if (pos+len > *bytes && zerofrom & (blocksize-1)) { - *bytes |= (blocksize-1); - (*bytes)++; - } - - return block_write_begin(mapping, pos, len, flags, pagep, get_block); -} -EXPORT_SYMBOL(cont_write_begin); - -int block_commit_write(struct page *page, unsigned from, unsigned to) -{ - struct inode *inode = page->mapping->host; - __block_commit_write(inode,page,from,to); - return 0; -} -EXPORT_SYMBOL(block_commit_write); - -/* - * block_page_mkwrite() is not allowed to change the file size as it gets - * called from a page fault handler when a page is first dirtied. Hence we must - * be careful to check for EOF conditions here. We set the page up correctly - * for a written page which means we get ENOSPC checking when writing into - * holes and correct delalloc and unwritten extent mapping on filesystems that - * support these features. - * - * We are not allowed to take the i_mutex here so we have to play games to - * protect against truncate races as the page could now be beyond EOF. Because - * truncate writes the inode size before removing pages, once we have the - * page lock we can determine safely if the page is beyond EOF. If it is not - * beyond EOF, then the page is guaranteed safe against truncation until we - * unlock the page. - * - * Direct callers of this function should protect against filesystem freezing - * using sb_start_pagefault() - sb_end_pagefault() functions. - */ -int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, - get_block_t get_block) -{ - struct page *page = vmf->page; - struct inode *inode = file_inode(vma->vm_file); - unsigned long end; - loff_t size; - int ret; - - lock_page(page); - size = i_size_read(inode); - if ((page->mapping != inode->i_mapping) || - (page_offset(page) > size)) { - /* We overload EFAULT to mean page got truncated */ - ret = -EFAULT; - goto out_unlock; - } - - /* page is wholly or partially inside EOF */ - if (((page->index + 1) << PAGE_SHIFT) > size) - end = size & ~PAGE_MASK; - else - end = PAGE_SIZE; - - ret = __block_write_begin(page, 0, end, get_block); - if (!ret) - ret = block_commit_write(page, 0, end); - - if (unlikely(ret < 0)) - goto out_unlock; - set_page_dirty(page); - wait_for_stable_page(page); - return 0; -out_unlock: - unlock_page(page); - return ret; -} -EXPORT_SYMBOL(block_page_mkwrite); - -/* - * nobh_write_begin()'s prereads are special: the buffer_heads are freed - * immediately, while under the page lock. So it needs a special end_io - * handler which does not touch the bh after unlocking it. - */ -static void end_buffer_read_nobh(struct buffer_head *bh, int uptodate) -{ - __end_buffer_read_notouch(bh, uptodate); -} - -/* - * Attach the singly-linked list of buffers created by nobh_write_begin, to - * the page (converting it to circular linked list and taking care of page - * dirty races). - */ -static void attach_nobh_buffers(struct page *page, struct buffer_head *head) -{ - struct buffer_head *bh; - - BUG_ON(!PageLocked(page)); - - spin_lock(&page->mapping->private_lock); - bh = head; - do { - if (PageDirty(page)) - set_buffer_dirty(bh); - if (!bh->b_this_page) - bh->b_this_page = head; - bh = bh->b_this_page; - } while (bh != head); - attach_page_buffers(page, head); - spin_unlock(&page->mapping->private_lock); -} - -/* - * On entry, the page is fully not uptodate. - * On exit the page is fully uptodate in the areas outside (from,to) - * The filesystem needs to handle block truncation upon failure. - */ -int nobh_write_begin(struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata, - get_block_t *get_block) -{ - struct inode *inode = mapping->host; - const unsigned blkbits = inode->i_blkbits; - const unsigned blocksize = 1 << blkbits; - struct buffer_head *head, *bh; - struct page *page; - pgoff_t index; - unsigned from, to; - unsigned block_in_page; - unsigned block_start, block_end; - sector_t block_in_file; - int nr_reads = 0; - int ret = 0; - int is_mapped_to_disk = 1; - - index = pos >> PAGE_SHIFT; - from = pos & (PAGE_SIZE - 1); - to = from + len; - - page = grab_cache_page_write_begin(mapping, index, flags); - if (!page) - return -ENOMEM; - *pagep = page; - *fsdata = NULL; - - if (page_has_buffers(page)) { - ret = __block_write_begin(page, pos, len, get_block); - if (unlikely(ret)) - goto out_release; - return ret; - } - - if (PageMappedToDisk(page)) - return 0; - - /* - * Allocate buffers so that we can keep track of state, and potentially - * attach them to the page if an error occurs. In the common case of - * no error, they will just be freed again without ever being attached - * to the page (which is all OK, because we're under the page lock). - * - * Be careful: the buffer linked list is a NULL terminated one, rather - * than the circular one we're used to. - */ - head = alloc_page_buffers(page, blocksize, 0); - if (!head) { - ret = -ENOMEM; - goto out_release; - } - - block_in_file = (sector_t)page->index << (PAGE_SHIFT - blkbits); - - /* - * We loop across all blocks in the page, whether or not they are - * part of the affected region. This is so we can discover if the - * page is fully mapped-to-disk. - */ - for (block_start = 0, block_in_page = 0, bh = head; - block_start < PAGE_SIZE; - block_in_page++, block_start += blocksize, bh = bh->b_this_page) { - int create; - - block_end = block_start + blocksize; - bh->b_state = 0; - create = 1; - if (block_start >= to) - create = 0; - ret = get_block(inode, block_in_file + block_in_page, - bh, create); - if (ret) - goto failed; - if (!buffer_mapped(bh)) - is_mapped_to_disk = 0; - if (buffer_new(bh)) - unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); - if (PageUptodate(page)) { - set_buffer_uptodate(bh); - continue; - } - if (buffer_new(bh) || !buffer_mapped(bh)) { - zero_user_segments(page, block_start, from, - to, block_end); - continue; - } - if (buffer_uptodate(bh)) - continue; /* reiserfs does this */ - if (block_start < from || block_end > to) { - lock_buffer(bh); - bh->b_end_io = end_buffer_read_nobh; - submit_bh(REQ_OP_READ, 0, bh); - nr_reads++; - } - } - - if (nr_reads) { - /* - * The page is locked, so these buffers are protected from - * any VM or truncate activity. Hence we don't need to care - * for the buffer_head refcounts. - */ - for (bh = head; bh; bh = bh->b_this_page) { - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) - ret = -EIO; - } - if (ret) - goto failed; - } - - if (is_mapped_to_disk) - SetPageMappedToDisk(page); - - *fsdata = head; /* to be released by nobh_write_end */ - - return 0; - -failed: - BUG_ON(!ret); - /* - * Error recovery is a bit difficult. We need to zero out blocks that - * were newly allocated, and dirty them to ensure they get written out. - * Buffers need to be attached to the page at this point, otherwise - * the handling of potential IO errors during writeout would be hard - * (could try doing synchronous writeout, but what if that fails too?) - */ - attach_nobh_buffers(page, head); - page_zero_new_buffers(page, from, to); - -out_release: - unlock_page(page); - put_page(page); - *pagep = NULL; - - return ret; -} -EXPORT_SYMBOL(nobh_write_begin); - -int nobh_write_end(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) -{ - struct inode *inode = page->mapping->host; - struct buffer_head *head = fsdata; - struct buffer_head *bh; - BUG_ON(fsdata != NULL && page_has_buffers(page)); - - if (unlikely(copied < len) && head) - attach_nobh_buffers(page, head); - if (page_has_buffers(page)) - return generic_write_end(file, mapping, pos, len, - copied, page, fsdata); - - SetPageUptodate(page); - set_page_dirty(page); - if (pos+copied > inode->i_size) { - i_size_write(inode, pos+copied); - mark_inode_dirty(inode); - } - - unlock_page(page); - put_page(page); - - while (head) { - bh = head; - head = head->b_this_page; - free_buffer_head(bh); - } - - return copied; -} -EXPORT_SYMBOL(nobh_write_end); - -/* - * nobh_writepage() - based on block_full_write_page() except - * that it tries to operate without attaching bufferheads to - * the page. - */ -int nobh_writepage(struct page *page, get_block_t *get_block, - struct writeback_control *wbc) -{ - struct inode * const inode = page->mapping->host; - loff_t i_size = i_size_read(inode); - const pgoff_t end_index = i_size >> PAGE_SHIFT; - unsigned offset; - int ret; - - /* Is the page fully inside i_size? */ - if (page->index < end_index) - goto out; - - /* Is the page fully outside i_size? (truncate in progress) */ - offset = i_size & (PAGE_SIZE-1); - if (page->index >= end_index+1 || !offset) { - /* - * The page may have dirty, unmapped buffers. For example, - * they may have been added in ext3_writepage(). Make them - * freeable here, so the page does not leak. - */ -#if 0 - /* Not really sure about this - do we need this ? */ - if (page->mapping->a_ops->invalidatepage) - page->mapping->a_ops->invalidatepage(page, offset); -#endif - unlock_page(page); - return 0; /* don't care */ - } - - /* - * The page straddles i_size. It must be zeroed out on each and every - * writepage invocation because it may be mmapped. "A file is mapped - * in multiples of the page size. For a file that is not a multiple of - * the page size, the remaining memory is zeroed when mapped, and - * writes to that region are not written out to the file." - */ - zero_user_segment(page, offset, PAGE_SIZE); -out: - ret = mpage_writepage(page, get_block, wbc); - if (ret == -EAGAIN) - ret = __block_write_full_page(inode, page, get_block, wbc, - end_buffer_async_write); - return ret; -} -EXPORT_SYMBOL(nobh_writepage); - -int nobh_truncate_page(struct address_space *mapping, - loff_t from, get_block_t *get_block) -{ - pgoff_t index = from >> PAGE_SHIFT; - unsigned offset = from & (PAGE_SIZE-1); - unsigned blocksize; - sector_t iblock; - unsigned length, pos; - struct inode *inode = mapping->host; - struct page *page; - struct buffer_head map_bh; - int err; - - blocksize = 1 << inode->i_blkbits; - length = offset & (blocksize - 1); - - /* Block boundary? Nothing to do */ - if (!length) - return 0; - - length = blocksize - length; - iblock = (sector_t)index << (PAGE_SHIFT - inode->i_blkbits); - - page = grab_cache_page(mapping, index); - err = -ENOMEM; - if (!page) - goto out; - - if (page_has_buffers(page)) { -has_buffers: - unlock_page(page); - put_page(page); - return block_truncate_page(mapping, from, get_block); - } - - /* Find the buffer that contains "offset" */ - pos = blocksize; - while (offset >= pos) { - iblock++; - pos += blocksize; - } - - map_bh.b_size = blocksize; - map_bh.b_state = 0; - err = get_block(inode, iblock, &map_bh, 0); - if (err) - goto unlock; - /* unmapped? It's a hole - nothing to do */ - if (!buffer_mapped(&map_bh)) - goto unlock; - - /* Ok, it's mapped. Make sure it's up-to-date */ - if (!PageUptodate(page)) { - err = mapping->a_ops->readpage(NULL, page); - if (err) { - put_page(page); - goto out; - } - lock_page(page); - if (!PageUptodate(page)) { - err = -EIO; - goto unlock; - } - if (page_has_buffers(page)) - goto has_buffers; - } - zero_user(page, offset, length); - set_page_dirty(page); - err = 0; - -unlock: - unlock_page(page); - put_page(page); -out: - return err; -} -EXPORT_SYMBOL(nobh_truncate_page); - -int block_truncate_page(struct address_space *mapping, - loff_t from, get_block_t *get_block) -{ - pgoff_t index = from >> PAGE_SHIFT; - unsigned offset = from & (PAGE_SIZE-1); - unsigned blocksize; - sector_t iblock; - unsigned length, pos; - struct inode *inode = mapping->host; - struct page *page; - struct buffer_head *bh; - int err; - - blocksize = 1 << inode->i_blkbits; - length = offset & (blocksize - 1); - - /* Block boundary? Nothing to do */ - if (!length) - return 0; - - length = blocksize - length; - iblock = (sector_t)index << (PAGE_SHIFT - inode->i_blkbits); - - page = grab_cache_page(mapping, index); - err = -ENOMEM; - if (!page) - goto out; - - if (!page_has_buffers(page)) - create_empty_buffers(page, blocksize, 0); - - /* Find the buffer that contains "offset" */ - bh = page_buffers(page); - pos = blocksize; - while (offset >= pos) { - bh = bh->b_this_page; - iblock++; - pos += blocksize; - } - - err = 0; - if (!buffer_mapped(bh)) { - WARN_ON(bh->b_size != blocksize); - err = get_block(inode, iblock, bh, 0); - if (err) - goto unlock; - /* unmapped? It's a hole - nothing to do */ - if (!buffer_mapped(bh)) - goto unlock; - } - - /* Ok, it's mapped. Make sure it's up-to-date */ - if (PageUptodate(page)) - set_buffer_uptodate(bh); - - if (!buffer_uptodate(bh) && !buffer_delay(bh) && !buffer_unwritten(bh)) { - err = -EIO; - ll_rw_block(REQ_OP_READ, 0, 1, &bh); - wait_on_buffer(bh); - /* Uhhuh. Read error. Complain and punt. */ - if (!buffer_uptodate(bh)) - goto unlock; - } - - zero_user(page, offset, length); - mark_buffer_dirty(bh); - err = 0; - -unlock: - unlock_page(page); - put_page(page); -out: - return err; -} -EXPORT_SYMBOL(block_truncate_page); - -/* - * The generic ->writepage function for buffer-backed address_spaces - */ -int block_write_full_page(struct page *page, get_block_t *get_block, - struct writeback_control *wbc) -{ - struct inode * const inode = page->mapping->host; - loff_t i_size = i_size_read(inode); - const pgoff_t end_index = i_size >> PAGE_SHIFT; - unsigned offset; - - /* Is the page fully inside i_size? */ - if (page->index < end_index) - return __block_write_full_page(inode, page, get_block, wbc, - end_buffer_async_write); - - /* Is the page fully outside i_size? (truncate in progress) */ - offset = i_size & (PAGE_SIZE-1); - if (page->index >= end_index+1 || !offset) { - /* - * The page may have dirty, unmapped buffers. For example, - * they may have been added in ext3_writepage(). Make them - * freeable here, so the page does not leak. - */ - do_invalidatepage(page, 0, PAGE_SIZE); - unlock_page(page); - return 0; /* don't care */ - } - - /* - * The page straddles i_size. It must be zeroed out on each and every - * writepage invocation because it may be mmapped. "A file is mapped - * in multiples of the page size. For a file that is not a multiple of - * the page size, the remaining memory is zeroed when mapped, and - * writes to that region are not written out to the file." - */ - zero_user_segment(page, offset, PAGE_SIZE); - return __block_write_full_page(inode, page, get_block, wbc, - end_buffer_async_write); -} -EXPORT_SYMBOL(block_write_full_page); - -sector_t generic_block_bmap(struct address_space *mapping, sector_t block, - get_block_t *get_block) -{ - struct buffer_head tmp; - struct inode *inode = mapping->host; - tmp.b_state = 0; - tmp.b_blocknr = 0; - tmp.b_size = 1 << inode->i_blkbits; - get_block(inode, block, &tmp, 0); - return tmp.b_blocknr; -} -EXPORT_SYMBOL(generic_block_bmap); - -static void end_bio_bh_io_sync(struct bio *bio) -{ - struct buffer_head *bh = bio->bi_private; - - if (unlikely(bio_flagged(bio, BIO_QUIET))) - set_bit(BH_Quiet, &bh->b_state); - - bh->b_end_io(bh, !bio->bi_error); - bio_put(bio); -} - -/* - * This allows us to do IO even on the odd last sectors - * of a device, even if the block size is some multiple - * of the physical sector size. - * - * We'll just truncate the bio to the size of the device, - * and clear the end of the buffer head manually. - * - * Truly out-of-range accesses will turn into actual IO - * errors, this only handles the "we need to be able to - * do IO at the final sector" case. - */ -void guard_bio_eod(int op, struct bio *bio) -{ - sector_t maxsector; - struct bio_vec *bvec = &bio->bi_io_vec[bio->bi_vcnt - 1]; - unsigned truncated_bytes; - - maxsector = i_size_read(bio->bi_bdev->bd_inode) >> 9; - if (!maxsector) - return; - - /* - * If the *whole* IO is past the end of the device, - * let it through, and the IO layer will turn it into - * an EIO. - */ - if (unlikely(bio->bi_iter.bi_sector >= maxsector)) - return; - - maxsector -= bio->bi_iter.bi_sector; - if (likely((bio->bi_iter.bi_size >> 9) <= maxsector)) - return; - - /* Uhhuh. We've got a bio that straddles the device size! */ - truncated_bytes = bio->bi_iter.bi_size - (maxsector << 9); - - /* Truncate the bio.. */ - bio->bi_iter.bi_size -= truncated_bytes; - bvec->bv_len -= truncated_bytes; - - /* ..and clear the end of the buffer for reads */ - if (op == REQ_OP_READ) { - zero_user(bvec->bv_page, bvec->bv_offset + bvec->bv_len, - truncated_bytes); - } -} - -static int submit_bh_wbc(int op, int op_flags, struct buffer_head *bh, - unsigned long bio_flags, struct writeback_control *wbc) -{ - struct bio *bio; - - BUG_ON(!buffer_locked(bh)); - BUG_ON(!buffer_mapped(bh)); - BUG_ON(!bh->b_end_io); - BUG_ON(buffer_delay(bh)); - BUG_ON(buffer_unwritten(bh)); - - /* - * Only clear out a write error when rewriting - */ - if (test_set_buffer_req(bh) && (op == REQ_OP_WRITE)) - clear_buffer_write_io_error(bh); - - /* - * from here on down, it's all bio -- do the initial mapping, - * submit_bio -> generic_make_request may further map this bio around - */ - bio = bio_alloc(GFP_NOIO, 1); - - if (wbc) { - wbc_init_bio(wbc, bio); - wbc_account_io(wbc, bh->b_page, bh->b_size); - } - - bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9); - bio->bi_bdev = bh->b_bdev; - - bio_add_page(bio, bh->b_page, bh->b_size, bh_offset(bh)); - BUG_ON(bio->bi_iter.bi_size != bh->b_size); - - bio->bi_end_io = end_bio_bh_io_sync; - bio->bi_private = bh; - bio->bi_flags |= bio_flags; - - /* Take care of bh's that straddle the end of the device */ - guard_bio_eod(op, bio); - - if (buffer_meta(bh)) - op_flags |= REQ_META; - if (buffer_prio(bh)) - op_flags |= REQ_PRIO; - bio_set_op_attrs(bio, op, op_flags); - - submit_bio(bio); - return 0; -} - -int _submit_bh(int op, int op_flags, struct buffer_head *bh, - unsigned long bio_flags) -{ - return submit_bh_wbc(op, op_flags, bh, bio_flags, NULL); -} -EXPORT_SYMBOL_GPL(_submit_bh); - -int submit_bh(int op, int op_flags, struct buffer_head *bh) -{ - return submit_bh_wbc(op, op_flags, bh, 0, NULL); -} -EXPORT_SYMBOL(submit_bh); - -/** - * ll_rw_block: low-level access to block devices (DEPRECATED) - * @op: whether to %READ or %WRITE - * @op_flags: rq_flag_bits - * @nr: number of &struct buffer_heads in the array - * @bhs: array of pointers to &struct buffer_head - * - * ll_rw_block() takes an array of pointers to &struct buffer_heads, and - * requests an I/O operation on them, either a %REQ_OP_READ or a %REQ_OP_WRITE. - * @op_flags contains flags modifying the detailed I/O behavior, most notably - * %REQ_RAHEAD. - * - * This function drops any buffer that it cannot get a lock on (with the - * BH_Lock state bit), any buffer that appears to be clean when doing a write - * request, and any buffer that appears to be up-to-date when doing read - * request. Further it marks as clean buffers that are processed for - * writing (the buffer cache won't assume that they are actually clean - * until the buffer gets unlocked). - * - * ll_rw_block sets b_end_io to simple completion handler that marks - * the buffer up-to-date (if appropriate), unlocks the buffer and wakes - * any waiters. - * - * All of the buffers must be for the same device, and must also be a - * multiple of the current approved size for the device. - */ -void ll_rw_block(int op, int op_flags, int nr, struct buffer_head *bhs[]) -{ - int i; - - for (i = 0; i < nr; i++) { - struct buffer_head *bh = bhs[i]; - - if (!trylock_buffer(bh)) - continue; - if (op == WRITE) { - if (test_clear_buffer_dirty(bh)) { - bh->b_end_io = end_buffer_write_sync; - get_bh(bh); - submit_bh(op, op_flags, bh); - continue; - } - } else { - if (!buffer_uptodate(bh)) { - bh->b_end_io = end_buffer_read_sync; - get_bh(bh); - submit_bh(op, op_flags, bh); - continue; - } - } - unlock_buffer(bh); - } -} -EXPORT_SYMBOL(ll_rw_block); - -void write_dirty_buffer(struct buffer_head *bh, int op_flags) -{ - lock_buffer(bh); - if (!test_clear_buffer_dirty(bh)) { - unlock_buffer(bh); - return; - } - bh->b_end_io = end_buffer_write_sync; - get_bh(bh); - submit_bh(REQ_OP_WRITE, op_flags, bh); -} -EXPORT_SYMBOL(write_dirty_buffer); - -/* - * For a data-integrity writeout, we need to wait upon any in-progress I/O - * and then start new I/O and then wait upon it. The caller must have a ref on - * the buffer_head. - */ -int __sync_dirty_buffer(struct buffer_head *bh, int op_flags) -{ - int ret = 0; - - WARN_ON(atomic_read(&bh->b_count) < 1); - lock_buffer(bh); - if (test_clear_buffer_dirty(bh)) { - get_bh(bh); - bh->b_end_io = end_buffer_write_sync; - ret = submit_bh(REQ_OP_WRITE, op_flags, bh); - wait_on_buffer(bh); - if (!ret && !buffer_uptodate(bh)) - ret = -EIO; - } else { - unlock_buffer(bh); - } - return ret; -} -EXPORT_SYMBOL(__sync_dirty_buffer); - -int sync_dirty_buffer(struct buffer_head *bh) -{ - return __sync_dirty_buffer(bh, WRITE_SYNC); -} -EXPORT_SYMBOL(sync_dirty_buffer); - -/* - * try_to_free_buffers() checks if all the buffers on this particular page - * are unused, and releases them if so. - * - * Exclusion against try_to_free_buffers may be obtained by either - * locking the page or by holding its mapping's private_lock. - * - * If the page is dirty but all the buffers are clean then we need to - * be sure to mark the page clean as well. This is because the page - * may be against a block device, and a later reattachment of buffers - * to a dirty page will set *all* buffers dirty. Which would corrupt - * filesystem data on the same device. - * - * The same applies to regular filesystem pages: if all the buffers are - * clean then we set the page clean and proceed. To do that, we require - * total exclusion from __set_page_dirty_buffers(). That is obtained with - * private_lock. - * - * try_to_free_buffers() is non-blocking. - */ -static inline int buffer_busy(struct buffer_head *bh) -{ - return atomic_read(&bh->b_count) | - (bh->b_state & ((1 << BH_Dirty) | (1 << BH_Lock))); -} - -static int -drop_buffers(struct page *page, struct buffer_head **buffers_to_free) -{ - struct buffer_head *head = page_buffers(page); - struct buffer_head *bh; - - bh = head; - do { - if (buffer_write_io_error(bh) && page->mapping) - mapping_set_error(page->mapping, -EIO); - if (buffer_busy(bh)) - goto failed; - bh = bh->b_this_page; - } while (bh != head); - - do { - struct buffer_head *next = bh->b_this_page; - - if (bh->b_assoc_map) - __remove_assoc_queue(bh); - bh = next; - } while (bh != head); - *buffers_to_free = head; - __clear_page_buffers(page); - return 1; -failed: - return 0; -} - -int try_to_free_buffers(struct page *page) -{ - struct address_space * const mapping = page->mapping; - struct buffer_head *buffers_to_free = NULL; - int ret = 0; - - BUG_ON(!PageLocked(page)); - if (PageWriteback(page)) - return 0; - - if (mapping == NULL) { /* can this still happen? */ - ret = drop_buffers(page, &buffers_to_free); - goto out; - } - - spin_lock(&mapping->private_lock); - ret = drop_buffers(page, &buffers_to_free); - - /* - * If the filesystem writes its buffers by hand (eg ext3) - * then we can have clean buffers against a dirty page. We - * clean the page here; otherwise the VM will never notice - * that the filesystem did any IO at all. - * - * Also, during truncate, discard_buffer will have marked all - * the page's buffers clean. We discover that here and clean - * the page also. - * - * private_lock must be held over this entire operation in order - * to synchronise against __set_page_dirty_buffers and prevent the - * dirty bit from being lost. - */ - if (ret) - cancel_dirty_page(page); - spin_unlock(&mapping->private_lock); -out: - if (buffers_to_free) { - struct buffer_head *bh = buffers_to_free; - - do { - struct buffer_head *next = bh->b_this_page; - free_buffer_head(bh); - bh = next; - } while (bh != buffers_to_free); - } - return ret; -} -EXPORT_SYMBOL(try_to_free_buffers); - -/* - * There are no bdflush tunables left. But distributions are - * still running obsolete flush daemons, so we terminate them here. - * - * Use of bdflush() is deprecated and will be removed in a future kernel. - * The `flush-X' kernel threads fully replace bdflush daemons and this call. - */ -SYSCALL_DEFINE2(bdflush, int, func, long, data) -{ - static int msg_count; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (msg_count < 5) { - msg_count++; - printk(KERN_INFO - "warning: process `%s' used the obsolete bdflush" - " system call\n", current->comm); - printk(KERN_INFO "Fix your initscripts?\n"); - } - - if (func == 1) - do_exit(0); - return 0; -} - -/* - * Buffer-head allocation - */ -static struct kmem_cache *bh_cachep __read_mostly; - -/* - * Once the number of bh's in the machine exceeds this level, we start - * stripping them in writeback. - */ -static unsigned long max_buffer_heads; - -int buffer_heads_over_limit; - -struct bh_accounting { - int nr; /* Number of live bh's */ - int ratelimit; /* Limit cacheline bouncing */ -}; - -static DEFINE_PER_CPU(struct bh_accounting, bh_accounting) = {0, 0}; - -static void recalc_bh_state(void) -{ - int i; - int tot = 0; - - if (__this_cpu_inc_return(bh_accounting.ratelimit) - 1 < 4096) - return; - __this_cpu_write(bh_accounting.ratelimit, 0); - for_each_online_cpu(i) - tot += per_cpu(bh_accounting, i).nr; - buffer_heads_over_limit = (tot > max_buffer_heads); -} - -struct buffer_head *alloc_buffer_head(gfp_t gfp_flags) -{ - struct buffer_head *ret = kmem_cache_zalloc(bh_cachep, gfp_flags); - if (ret) { - INIT_LIST_HEAD(&ret->b_assoc_buffers); - preempt_disable(); - __this_cpu_inc(bh_accounting.nr); - recalc_bh_state(); - preempt_enable(); - } - return ret; -} -EXPORT_SYMBOL(alloc_buffer_head); - -void free_buffer_head(struct buffer_head *bh) -{ - BUG_ON(!list_empty(&bh->b_assoc_buffers)); - kmem_cache_free(bh_cachep, bh); - preempt_disable(); - __this_cpu_dec(bh_accounting.nr); - recalc_bh_state(); - preempt_enable(); -} -EXPORT_SYMBOL(free_buffer_head); - -static void buffer_exit_cpu(int cpu) -{ - int i; - struct bh_lru *b = &per_cpu(bh_lrus, cpu); - - for (i = 0; i < BH_LRU_SIZE; i++) { - brelse(b->bhs[i]); - b->bhs[i] = NULL; - } - this_cpu_add(bh_accounting.nr, per_cpu(bh_accounting, cpu).nr); - per_cpu(bh_accounting, cpu).nr = 0; -} - -static int buffer_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) -{ - if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) - buffer_exit_cpu((unsigned long)hcpu); - return NOTIFY_OK; -} - -/** - * bh_uptodate_or_lock - Test whether the buffer is uptodate - * @bh: struct buffer_head - * - * Return true if the buffer is up-to-date and false, - * with the buffer locked, if not. - */ -int bh_uptodate_or_lock(struct buffer_head *bh) -{ - if (!buffer_uptodate(bh)) { - lock_buffer(bh); - if (!buffer_uptodate(bh)) - return 0; - unlock_buffer(bh); - } - return 1; -} -EXPORT_SYMBOL(bh_uptodate_or_lock); - -/** - * bh_submit_read - Submit a locked buffer for reading - * @bh: struct buffer_head - * - * Returns zero on success and -EIO on error. - */ -int bh_submit_read(struct buffer_head *bh) -{ - BUG_ON(!buffer_locked(bh)); - - if (buffer_uptodate(bh)) { - unlock_buffer(bh); - return 0; - } - - get_bh(bh); - bh->b_end_io = end_buffer_read_sync; - submit_bh(REQ_OP_READ, 0, bh); - wait_on_buffer(bh); - if (buffer_uptodate(bh)) - return 0; - return -EIO; -} -EXPORT_SYMBOL(bh_submit_read); - -void __init buffer_init(void) -{ - unsigned long nrpages; - - bh_cachep = kmem_cache_create("buffer_head", - sizeof(struct buffer_head), 0, - (SLAB_RECLAIM_ACCOUNT|SLAB_PANIC| - SLAB_MEM_SPREAD), - NULL); - - /* - * Limit the bh occupancy to 10% of ZONE_NORMAL - */ - nrpages = (nr_free_buffer_pages() * 10) / 100; - max_buffer_heads = nrpages * (PAGE_SIZE / sizeof(struct buffer_head)); - hotcpu_notifier(buffer_cpu_notify, 0); -} diff --git a/src/linux/fs/cachefiles/Kconfig b/src/linux/fs/cachefiles/Kconfig deleted file mode 100644 index 80e9c61..0000000 --- a/src/linux/fs/cachefiles/Kconfig +++ /dev/null @@ -1,39 +0,0 @@ - -config CACHEFILES - tristate "Filesystem caching on files" - depends on FSCACHE && BLOCK - help - This permits use of a mounted filesystem as a cache for other - filesystems - primarily networking filesystems - thus allowing fast - local disk to enhance the speed of slower devices. - - See Documentation/filesystems/caching/cachefiles.txt for more - information. - -config CACHEFILES_DEBUG - bool "Debug CacheFiles" - depends on CACHEFILES - help - This permits debugging to be dynamically enabled in the filesystem - caching on files module. If this is set, the debugging output may be - enabled by setting bits in /sys/modules/cachefiles/parameter/debug or - by including a debugging specifier in /etc/cachefilesd.conf. - -config CACHEFILES_HISTOGRAM - bool "Gather latency information on CacheFiles" - depends on CACHEFILES && PROC_FS - help - - This option causes latency information to be gathered on CacheFiles - operation and exported through file: - - /proc/fs/cachefiles/histogram - - The generation of this histogram adds a certain amount of overhead to - execution as there are a number of points at which data is gathered, - and on a multi-CPU system these may be on cachelines that keep - bouncing between CPUs. On the other hand, the histogram may be - useful for debugging purposes. Saying 'N' here is recommended. - - See Documentation/filesystems/caching/cachefiles.txt for more - information. diff --git a/src/linux/fs/ceph/Kconfig b/src/linux/fs/ceph/Kconfig deleted file mode 100644 index 264e9bf..0000000 --- a/src/linux/fs/ceph/Kconfig +++ /dev/null @@ -1,40 +0,0 @@ -config CEPH_FS - tristate "Ceph distributed file system" - depends on INET - select CEPH_LIB - select LIBCRC32C - select CRYPTO_AES - select CRYPTO - default n - help - Choose Y or M here to include support for mounting the - experimental Ceph distributed file system. Ceph is an extremely - scalable file system designed to provide high performance, - reliable access to petabytes of storage. - - More information at http://ceph.newdream.net/. - - If unsure, say N. - -if CEPH_FS -config CEPH_FSCACHE - bool "Enable Ceph client caching support" - depends on CEPH_FS=m && FSCACHE || CEPH_FS=y && FSCACHE=y - help - Choose Y here to enable persistent, read-only local - caching support for Ceph clients using FS-Cache - -endif - -config CEPH_FS_POSIX_ACL - bool "Ceph POSIX Access Control Lists" - depends on CEPH_FS - select FS_POSIX_ACL - help - POSIX Access Control Lists (ACLs) support permissions for users and - groups beyond the owner/group/world scheme. - - To learn more about Access Control Lists, visit the POSIX ACLs for - Linux website . - - If you don't know what Access Control Lists are, say N diff --git a/src/linux/fs/char_dev.c b/src/linux/fs/char_dev.c deleted file mode 100644 index 44a240c..0000000 --- a/src/linux/fs/char_dev.c +++ /dev/null @@ -1,574 +0,0 @@ -/* - * linux/fs/char_dev.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -static struct kobj_map *cdev_map; - -static DEFINE_MUTEX(chrdevs_lock); - -static struct char_device_struct { - struct char_device_struct *next; - unsigned int major; - unsigned int baseminor; - int minorct; - char name[64]; - struct cdev *cdev; /* will die */ -} *chrdevs[CHRDEV_MAJOR_HASH_SIZE]; - -/* index in the above */ -static inline int major_to_index(unsigned major) -{ - return major % CHRDEV_MAJOR_HASH_SIZE; -} - -#ifdef CONFIG_PROC_FS - -void chrdev_show(struct seq_file *f, off_t offset) -{ - struct char_device_struct *cd; - - if (offset < CHRDEV_MAJOR_HASH_SIZE) { - mutex_lock(&chrdevs_lock); - for (cd = chrdevs[offset]; cd; cd = cd->next) - seq_printf(f, "%3d %s\n", cd->major, cd->name); - mutex_unlock(&chrdevs_lock); - } -} - -#endif /* CONFIG_PROC_FS */ - -/* - * Register a single major with a specified minor range. - * - * If major == 0 this functions will dynamically allocate a major and return - * its number. - * - * If major > 0 this function will attempt to reserve the passed range of - * minors and will return zero on success. - * - * Returns a -ve errno on failure. - */ -static struct char_device_struct * -__register_chrdev_region(unsigned int major, unsigned int baseminor, - int minorct, const char *name) -{ - struct char_device_struct *cd, **cp; - int ret = 0; - int i; - - cd = kzalloc(sizeof(struct char_device_struct), GFP_KERNEL); - if (cd == NULL) - return ERR_PTR(-ENOMEM); - - mutex_lock(&chrdevs_lock); - - /* temporary */ - if (major == 0) { - for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) { - if (chrdevs[i] == NULL) - break; - } - - if (i < CHRDEV_MAJOR_DYN_END) - pr_warn("CHRDEV \"%s\" major number %d goes below the dynamic allocation range\n", - name, i); - - if (i == 0) { - ret = -EBUSY; - goto out; - } - major = i; - } - - cd->major = major; - cd->baseminor = baseminor; - cd->minorct = minorct; - strlcpy(cd->name, name, sizeof(cd->name)); - - i = major_to_index(major); - - for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) - if ((*cp)->major > major || - ((*cp)->major == major && - (((*cp)->baseminor >= baseminor) || - ((*cp)->baseminor + (*cp)->minorct > baseminor)))) - break; - - /* Check for overlapping minor ranges. */ - if (*cp && (*cp)->major == major) { - int old_min = (*cp)->baseminor; - int old_max = (*cp)->baseminor + (*cp)->minorct - 1; - int new_min = baseminor; - int new_max = baseminor + minorct - 1; - - /* New driver overlaps from the left. */ - if (new_max >= old_min && new_max <= old_max) { - ret = -EBUSY; - goto out; - } - - /* New driver overlaps from the right. */ - if (new_min <= old_max && new_min >= old_min) { - ret = -EBUSY; - goto out; - } - } - - cd->next = *cp; - *cp = cd; - mutex_unlock(&chrdevs_lock); - return cd; -out: - mutex_unlock(&chrdevs_lock); - kfree(cd); - return ERR_PTR(ret); -} - -static struct char_device_struct * -__unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct) -{ - struct char_device_struct *cd = NULL, **cp; - int i = major_to_index(major); - - mutex_lock(&chrdevs_lock); - for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next) - if ((*cp)->major == major && - (*cp)->baseminor == baseminor && - (*cp)->minorct == minorct) - break; - if (*cp) { - cd = *cp; - *cp = cd->next; - } - mutex_unlock(&chrdevs_lock); - return cd; -} - -/** - * register_chrdev_region() - register a range of device numbers - * @from: the first in the desired range of device numbers; must include - * the major number. - * @count: the number of consecutive device numbers required - * @name: the name of the device or driver. - * - * Return value is zero on success, a negative error code on failure. - */ -int register_chrdev_region(dev_t from, unsigned count, const char *name) -{ - struct char_device_struct *cd; - dev_t to = from + count; - dev_t n, next; - - for (n = from; n < to; n = next) { - next = MKDEV(MAJOR(n)+1, 0); - if (next > to) - next = to; - cd = __register_chrdev_region(MAJOR(n), MINOR(n), - next - n, name); - if (IS_ERR(cd)) - goto fail; - } - return 0; -fail: - to = n; - for (n = from; n < to; n = next) { - next = MKDEV(MAJOR(n)+1, 0); - kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n)); - } - return PTR_ERR(cd); -} - -/** - * alloc_chrdev_region() - register a range of char device numbers - * @dev: output parameter for first assigned number - * @baseminor: first of the requested range of minor numbers - * @count: the number of minor numbers required - * @name: the name of the associated device or driver - * - * Allocates a range of char device numbers. The major number will be - * chosen dynamically, and returned (along with the first minor number) - * in @dev. Returns zero or a negative error code. - */ -int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, - const char *name) -{ - struct char_device_struct *cd; - cd = __register_chrdev_region(0, baseminor, count, name); - if (IS_ERR(cd)) - return PTR_ERR(cd); - *dev = MKDEV(cd->major, cd->baseminor); - return 0; -} - -/** - * __register_chrdev() - create and register a cdev occupying a range of minors - * @major: major device number or 0 for dynamic allocation - * @baseminor: first of the requested range of minor numbers - * @count: the number of minor numbers required - * @name: name of this range of devices - * @fops: file operations associated with this devices - * - * If @major == 0 this functions will dynamically allocate a major and return - * its number. - * - * If @major > 0 this function will attempt to reserve a device with the given - * major number and will return zero on success. - * - * Returns a -ve errno on failure. - * - * The name of this device has nothing to do with the name of the device in - * /dev. It only helps to keep track of the different owners of devices. If - * your module name has only one type of devices it's ok to use e.g. the name - * of the module here. - */ -int __register_chrdev(unsigned int major, unsigned int baseminor, - unsigned int count, const char *name, - const struct file_operations *fops) -{ - struct char_device_struct *cd; - struct cdev *cdev; - int err = -ENOMEM; - - cd = __register_chrdev_region(major, baseminor, count, name); - if (IS_ERR(cd)) - return PTR_ERR(cd); - - cdev = cdev_alloc(); - if (!cdev) - goto out2; - - cdev->owner = fops->owner; - cdev->ops = fops; - kobject_set_name(&cdev->kobj, "%s", name); - - err = cdev_add(cdev, MKDEV(cd->major, baseminor), count); - if (err) - goto out; - - cd->cdev = cdev; - - return major ? 0 : cd->major; -out: - kobject_put(&cdev->kobj); -out2: - kfree(__unregister_chrdev_region(cd->major, baseminor, count)); - return err; -} - -/** - * unregister_chrdev_region() - unregister a range of device numbers - * @from: the first in the range of numbers to unregister - * @count: the number of device numbers to unregister - * - * This function will unregister a range of @count device numbers, - * starting with @from. The caller should normally be the one who - * allocated those numbers in the first place... - */ -void unregister_chrdev_region(dev_t from, unsigned count) -{ - dev_t to = from + count; - dev_t n, next; - - for (n = from; n < to; n = next) { - next = MKDEV(MAJOR(n)+1, 0); - if (next > to) - next = to; - kfree(__unregister_chrdev_region(MAJOR(n), MINOR(n), next - n)); - } -} - -/** - * __unregister_chrdev - unregister and destroy a cdev - * @major: major device number - * @baseminor: first of the range of minor numbers - * @count: the number of minor numbers this cdev is occupying - * @name: name of this range of devices - * - * Unregister and destroy the cdev occupying the region described by - * @major, @baseminor and @count. This function undoes what - * __register_chrdev() did. - */ -void __unregister_chrdev(unsigned int major, unsigned int baseminor, - unsigned int count, const char *name) -{ - struct char_device_struct *cd; - - cd = __unregister_chrdev_region(major, baseminor, count); - if (cd && cd->cdev) - cdev_del(cd->cdev); - kfree(cd); -} - -static DEFINE_SPINLOCK(cdev_lock); - -static struct kobject *cdev_get(struct cdev *p) -{ - struct module *owner = p->owner; - struct kobject *kobj; - - if (owner && !try_module_get(owner)) - return NULL; - kobj = kobject_get(&p->kobj); - if (!kobj) - module_put(owner); - return kobj; -} - -void cdev_put(struct cdev *p) -{ - if (p) { - struct module *owner = p->owner; - kobject_put(&p->kobj); - module_put(owner); - } -} - -/* - * Called every time a character special file is opened - */ -static int chrdev_open(struct inode *inode, struct file *filp) -{ - const struct file_operations *fops; - struct cdev *p; - struct cdev *new = NULL; - int ret = 0; - - spin_lock(&cdev_lock); - p = inode->i_cdev; - if (!p) { - struct kobject *kobj; - int idx; - spin_unlock(&cdev_lock); - kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx); - if (!kobj) - return -ENXIO; - new = container_of(kobj, struct cdev, kobj); - spin_lock(&cdev_lock); - /* Check i_cdev again in case somebody beat us to it while - we dropped the lock. */ - p = inode->i_cdev; - if (!p) { - inode->i_cdev = p = new; - list_add(&inode->i_devices, &p->list); - new = NULL; - } else if (!cdev_get(p)) - ret = -ENXIO; - } else if (!cdev_get(p)) - ret = -ENXIO; - spin_unlock(&cdev_lock); - cdev_put(new); - if (ret) - return ret; - - ret = -ENXIO; - fops = fops_get(p->ops); - if (!fops) - goto out_cdev_put; - - replace_fops(filp, fops); - if (filp->f_op->open) { - ret = filp->f_op->open(inode, filp); - if (ret) - goto out_cdev_put; - } - - return 0; - - out_cdev_put: - cdev_put(p); - return ret; -} - -void cd_forget(struct inode *inode) -{ - spin_lock(&cdev_lock); - list_del_init(&inode->i_devices); - inode->i_cdev = NULL; - inode->i_mapping = &inode->i_data; - spin_unlock(&cdev_lock); -} - -static void cdev_purge(struct cdev *cdev) -{ - spin_lock(&cdev_lock); - while (!list_empty(&cdev->list)) { - struct inode *inode; - inode = container_of(cdev->list.next, struct inode, i_devices); - list_del_init(&inode->i_devices); - inode->i_cdev = NULL; - } - spin_unlock(&cdev_lock); -} - -/* - * Dummy default file-operations: the only thing this does - * is contain the open that then fills in the correct operations - * depending on the special file... - */ -const struct file_operations def_chr_fops = { - .open = chrdev_open, - .llseek = noop_llseek, -}; - -static struct kobject *exact_match(dev_t dev, int *part, void *data) -{ - struct cdev *p = data; - return &p->kobj; -} - -static int exact_lock(dev_t dev, void *data) -{ - struct cdev *p = data; - return cdev_get(p) ? 0 : -1; -} - -/** - * cdev_add() - add a char device to the system - * @p: the cdev structure for the device - * @dev: the first device number for which this device is responsible - * @count: the number of consecutive minor numbers corresponding to this - * device - * - * cdev_add() adds the device represented by @p to the system, making it - * live immediately. A negative error code is returned on failure. - */ -int cdev_add(struct cdev *p, dev_t dev, unsigned count) -{ - int error; - - p->dev = dev; - p->count = count; - - error = kobj_map(cdev_map, dev, count, NULL, - exact_match, exact_lock, p); - if (error) - return error; - - kobject_get(p->kobj.parent); - - return 0; -} - -static void cdev_unmap(dev_t dev, unsigned count) -{ - kobj_unmap(cdev_map, dev, count); -} - -/** - * cdev_del() - remove a cdev from the system - * @p: the cdev structure to be removed - * - * cdev_del() removes @p from the system, possibly freeing the structure - * itself. - */ -void cdev_del(struct cdev *p) -{ - cdev_unmap(p->dev, p->count); - kobject_put(&p->kobj); -} - - -static void cdev_default_release(struct kobject *kobj) -{ - struct cdev *p = container_of(kobj, struct cdev, kobj); - struct kobject *parent = kobj->parent; - - cdev_purge(p); - kobject_put(parent); -} - -static void cdev_dynamic_release(struct kobject *kobj) -{ - struct cdev *p = container_of(kobj, struct cdev, kobj); - struct kobject *parent = kobj->parent; - - cdev_purge(p); - kfree(p); - kobject_put(parent); -} - -static struct kobj_type ktype_cdev_default = { - .release = cdev_default_release, -}; - -static struct kobj_type ktype_cdev_dynamic = { - .release = cdev_dynamic_release, -}; - -/** - * cdev_alloc() - allocate a cdev structure - * - * Allocates and returns a cdev structure, or NULL on failure. - */ -struct cdev *cdev_alloc(void) -{ - struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL); - if (p) { - INIT_LIST_HEAD(&p->list); - kobject_init(&p->kobj, &ktype_cdev_dynamic); - } - return p; -} - -/** - * cdev_init() - initialize a cdev structure - * @cdev: the structure to initialize - * @fops: the file_operations for this device - * - * Initializes @cdev, remembering @fops, making it ready to add to the - * system with cdev_add(). - */ -void cdev_init(struct cdev *cdev, const struct file_operations *fops) -{ - memset(cdev, 0, sizeof *cdev); - INIT_LIST_HEAD(&cdev->list); - kobject_init(&cdev->kobj, &ktype_cdev_default); - cdev->ops = fops; -} - -static struct kobject *base_probe(dev_t dev, int *part, void *data) -{ - if (request_module("char-major-%d-%d", MAJOR(dev), MINOR(dev)) > 0) - /* Make old-style 2.4 aliases work */ - request_module("char-major-%d", MAJOR(dev)); - return NULL; -} - -void __init chrdev_init(void) -{ - cdev_map = kobj_map_init(base_probe, &chrdevs_lock); -} - - -/* Let modules do char dev stuff */ -EXPORT_SYMBOL(register_chrdev_region); -EXPORT_SYMBOL(unregister_chrdev_region); -EXPORT_SYMBOL(alloc_chrdev_region); -EXPORT_SYMBOL(cdev_init); -EXPORT_SYMBOL(cdev_alloc); -EXPORT_SYMBOL(cdev_del); -EXPORT_SYMBOL(cdev_add); -EXPORT_SYMBOL(__register_chrdev); -EXPORT_SYMBOL(__unregister_chrdev); diff --git a/src/linux/fs/cifs/Kconfig b/src/linux/fs/cifs/Kconfig deleted file mode 100644 index e7b478b..0000000 --- a/src/linux/fs/cifs/Kconfig +++ /dev/null @@ -1,211 +0,0 @@ -config CIFS - tristate "CIFS support (advanced network filesystem, SMBFS successor)" - depends on INET - select NLS - select CRYPTO - select CRYPTO_MD4 - select CRYPTO_MD5 - select CRYPTO_HMAC - select CRYPTO_ARC4 - select CRYPTO_ECB - select CRYPTO_DES - select CRYPTO_SHA256 - select CRYPTO_CMAC - help - This is the client VFS module for the Common Internet File System - (CIFS) protocol which is the successor to the Server Message Block - (SMB) protocol, the native file sharing mechanism for most early - PC operating systems. The CIFS protocol is fully supported by - file servers such as Windows 2000 (including Windows 2003, Windows 2008, - NT 4 and Windows XP) as well by Samba (which provides excellent CIFS - server support for Linux and many other operating systems). Limited - support for OS/2 and Windows ME and similar servers is provided as - well. - - The module also provides optional support for the followon - protocols for CIFS including SMB3, which enables - useful performance and security features (see the description - of CONFIG_CIFS_SMB2). - - The cifs module provides an advanced network file system - client for mounting to CIFS compliant servers. It includes - support for DFS (hierarchical name space), secure per-user - session establishment via Kerberos or NTLM or NTLMv2, - safe distributed caching (oplock), optional packet - signing, Unicode and other internationalization improvements. - If you need to mount to Samba or Windows from this machine, say Y. - -config CIFS_STATS - bool "CIFS statistics" - depends on CIFS - help - Enabling this option will cause statistics for each server share - mounted by the cifs client to be displayed in /proc/fs/cifs/Stats - -config CIFS_STATS2 - bool "Extended statistics" - depends on CIFS_STATS - help - Enabling this option will allow more detailed statistics on SMB - request timing to be displayed in /proc/fs/cifs/DebugData and also - allow optional logging of slow responses to dmesg (depending on the - value of /proc/fs/cifs/cifsFYI, see fs/cifs/README for more details). - These additional statistics may have a minor effect on performance - and memory utilization. - - Unless you are a developer or are doing network performance analysis - or tuning, say N. - -config CIFS_WEAK_PW_HASH - bool "Support legacy servers which use weaker LANMAN security" - depends on CIFS - help - Modern CIFS servers including Samba and most Windows versions - (since 1997) support stronger NTLM (and even NTLMv2 and Kerberos) - security mechanisms. These hash the password more securely - than the mechanisms used in the older LANMAN version of the - SMB protocol but LANMAN based authentication is needed to - establish sessions with some old SMB servers. - - Enabling this option allows the cifs module to mount to older - LANMAN based servers such as OS/2 and Windows 95, but such - mounts may be less secure than mounts using NTLM or more recent - security mechanisms if you are on a public network. Unless you - have a need to access old SMB servers (and are on a private - network) you probably want to say N. Even if this support - is enabled in the kernel build, LANMAN authentication will not be - used automatically. At runtime LANMAN mounts are disabled but - can be set to required (or optional) either in - /proc/fs/cifs (see fs/cifs/README for more detail) or via an - option on the mount command. This support is disabled by - default in order to reduce the possibility of a downgrade - attack. - - If unsure, say N. - -config CIFS_UPCALL - bool "Kerberos/SPNEGO advanced session setup" - depends on CIFS && KEYS - select DNS_RESOLVER - help - Enables an upcall mechanism for CIFS which accesses userspace helper - utilities to provide SPNEGO packaged (RFC 4178) Kerberos tickets - which are needed to mount to certain secure servers (for which more - secure Kerberos authentication is required). If unsure, say N. - -config CIFS_XATTR - bool "CIFS extended attributes" - depends on CIFS - help - Extended attributes are name:value pairs associated with inodes by - the kernel or by users (see the attr(5) manual page, or visit - for details). CIFS maps the name of - extended attributes beginning with the user namespace prefix - to SMB/CIFS EAs. EAs are stored on Windows servers without the - user namespace prefix, but their names are seen by Linux cifs clients - prefaced by the user namespace prefix. The system namespace - (used by some filesystems to store ACLs) is not supported at - this time. - - If unsure, say N. - -config CIFS_POSIX - bool "CIFS POSIX Extensions" - depends on CIFS_XATTR - help - Enabling this option will cause the cifs client to attempt to - negotiate a newer dialect with servers, such as Samba 3.0.5 - or later, that optionally can handle more POSIX like (rather - than Windows like) file behavior. It also enables - support for POSIX ACLs (getfacl and setfacl) to servers - (such as Samba 3.10 and later) which can negotiate - CIFS POSIX ACL support. If unsure, say N. - -config CIFS_ACL - bool "Provide CIFS ACL support" - depends on CIFS_XATTR && KEYS - help - Allows fetching CIFS/NTFS ACL from the server. The DACL blob - is handed over to the application/caller. See the man - page for getcifsacl for more information. - -config CIFS_DEBUG - bool "Enable CIFS debugging routines" - default y - depends on CIFS - help - Enabling this option adds helpful debugging messages to - the cifs code which increases the size of the cifs module. - If unsure, say Y. -config CIFS_DEBUG2 - bool "Enable additional CIFS debugging routines" - depends on CIFS_DEBUG - help - Enabling this option adds a few more debugging routines - to the cifs code which slightly increases the size of - the cifs module and can cause additional logging of debug - messages in some error paths, slowing performance. This - option can be turned off unless you are debugging - cifs problems. If unsure, say N. - -config CIFS_DFS_UPCALL - bool "DFS feature support" - depends on CIFS && KEYS - select DNS_RESOLVER - help - Distributed File System (DFS) support is used to access shares - transparently in an enterprise name space, even if the share - moves to a different server. This feature also enables - an upcall mechanism for CIFS which contacts userspace helper - utilities to provide server name resolution (host names to - IP addresses) which is needed for implicit mounts of DFS junction - points. If unsure, say N. - -config CIFS_NFSD_EXPORT - bool "Allow nfsd to export CIFS file system" - depends on CIFS && BROKEN - help - Allows NFS server to export a CIFS mounted share (nfsd over cifs) - -config CIFS_SMB2 - bool "SMB2 and SMB3 network file system support" - depends on CIFS && INET - select NLS - select KEYS - select FSCACHE - select DNS_RESOLVER - - help - This enables support for the Server Message Block version 2 - family of protocols, including SMB3. SMB3 support is - enabled on mount by specifying "vers=3.0" in the mount - options. These protocols are the successors to the popular - CIFS and SMB network file sharing protocols. SMB3 is the - native file sharing mechanism for the more recent - versions of Windows (Windows 8 and Windows 2012 and - later) and Samba server and many others support SMB3 well. - In general SMB3 enables better performance, security - and features, than would be possible with CIFS (Note that - when mounting to Samba, due to the CIFS POSIX extensions, - CIFS mounts can provide slightly better POSIX compatibility - than SMB3 mounts do though). Note that SMB2/SMB3 mount - options are also slightly simpler (compared to CIFS) due - to protocol improvements. - -config CIFS_SMB311 - bool "SMB3.1.1 network file system support (Experimental)" - depends on CIFS_SMB2 && INET - - help - This enables experimental support for the newest, SMB3.1.1, dialect. - This dialect includes improved security negotiation features. - If unsure, say N - -config CIFS_FSCACHE - bool "Provide CIFS client caching support" - depends on CIFS=m && FSCACHE || CIFS=y && FSCACHE=y - help - Makes CIFS FS-Cache capable. Say Y here if you want your CIFS data - to be cached locally on disk through the general filesystem cache - manager. If unsure, say N. - diff --git a/src/linux/fs/coda/Kconfig b/src/linux/fs/coda/Kconfig deleted file mode 100644 index c0e5a7f..0000000 --- a/src/linux/fs/coda/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -config CODA_FS - tristate "Coda file system support (advanced network fs)" - depends on INET - help - Coda is an advanced network file system, similar to NFS in that it - enables you to mount file systems of a remote server and access them - with regular Unix commands as if they were sitting on your hard - disk. Coda has several advantages over NFS: support for - disconnected operation (e.g. for laptops), read/write server - replication, security model for authentication and encryption, - persistent client caches and write back caching. - - If you say Y here, your Linux box will be able to act as a Coda - *client*. You will need user level code as well, both for the - client and server. Servers are currently user level, i.e. they need - no kernel support. Please read - and check out the Coda - home page . - - To compile the coda client support as a module, choose M here: the - module will be called coda. diff --git a/src/linux/fs/configfs/Kconfig b/src/linux/fs/configfs/Kconfig deleted file mode 100644 index 9febcde..0000000 --- a/src/linux/fs/configfs/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config CONFIGFS_FS - tristate "Userspace-driven configuration filesystem" - select SYSFS - help - configfs is a RAM-based filesystem that provides the converse - of sysfs's functionality. Where sysfs is a filesystem-based - view of kernel objects, configfs is a filesystem-based manager - of kernel objects, or config_items. - - Both sysfs and configfs can and should exist together on the - same system. One is not a replacement for the other. diff --git a/src/linux/fs/cramfs/Kconfig b/src/linux/fs/cramfs/Kconfig deleted file mode 100644 index 11b29d4..0000000 --- a/src/linux/fs/cramfs/Kconfig +++ /dev/null @@ -1,22 +0,0 @@ -config CRAMFS - tristate "Compressed ROM file system support (cramfs) (OBSOLETE)" - depends on BLOCK - select ZLIB_INFLATE - help - Saying Y here includes support for CramFs (Compressed ROM File - System). CramFs is designed to be a simple, small, and compressed - file system for ROM based embedded systems. CramFs is read-only, - limited to 256MB file systems (with 16MB files), and doesn't support - 16/32 bits uid/gid, hard links and timestamps. - - See and - for further information. - - To compile this as a module, choose M here: the module will be called - cramfs. Note that the root file system (the one containing the - directory /) cannot be compiled as a module. - - This filesystem is obsoleted by SquashFS, which is much better - in terms of performance and features. - - If unsure, say N. diff --git a/src/linux/fs/crypto/Kconfig b/src/linux/fs/crypto/Kconfig deleted file mode 100644 index 92348fa..0000000 --- a/src/linux/fs/crypto/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config FS_ENCRYPTION - tristate "FS Encryption (Per-file encryption)" - depends on BLOCK - select CRYPTO - select CRYPTO_AES - select CRYPTO_CBC - select CRYPTO_ECB - select CRYPTO_XTS - select CRYPTO_CTS - select CRYPTO_CTR - select CRYPTO_SHA256 - select KEYS - select ENCRYPTED_KEYS - help - Enable encryption of files and directories. This - feature is similar to ecryptfs, but it is more memory - efficient since it avoids caching the encrypted and - decrypted pages in the page cache. diff --git a/src/linux/fs/dcache.c b/src/linux/fs/dcache.c deleted file mode 100644 index 5c7cc95..0000000 --- a/src/linux/fs/dcache.c +++ /dev/null @@ -1,3620 +0,0 @@ -/* - * fs/dcache.c - * - * Complete reimplementation - * (C) 1997 Thomas Schoebel-Theuer, - * with heavy changes by Linus Torvalds - */ - -/* - * Notes on the allocation strategy: - * - * The dcache is a master of the icache - whenever a dcache entry - * exists, the inode will always exist. "iput()" is done either when - * the dcache entry is deleted or garbage collected. - */ - -#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 "internal.h" -#include "mount.h" - -/* - * Usage: - * dcache->d_inode->i_lock protects: - * - i_dentry, d_u.d_alias, d_inode of aliases - * dcache_hash_bucket lock protects: - * - the dcache hash table - * s_anon bl list spinlock protects: - * - the s_anon list (see __d_drop) - * dentry->d_sb->s_dentry_lru_lock protects: - * - the dcache lru lists and counters - * d_lock protects: - * - d_flags - * - d_name - * - d_lru - * - d_count - * - d_unhashed() - * - d_parent and d_subdirs - * - childrens' d_child and d_parent - * - d_u.d_alias, d_inode - * - * Ordering: - * dentry->d_inode->i_lock - * dentry->d_lock - * dentry->d_sb->s_dentry_lru_lock - * dcache_hash_bucket lock - * s_anon lock - * - * If there is an ancestor relationship: - * dentry->d_parent->...->d_parent->d_lock - * ... - * dentry->d_parent->d_lock - * dentry->d_lock - * - * If no ancestor relationship: - * if (dentry1 < dentry2) - * dentry1->d_lock - * dentry2->d_lock - */ -int sysctl_vfs_cache_pressure __read_mostly = 100; -EXPORT_SYMBOL_GPL(sysctl_vfs_cache_pressure); - -__cacheline_aligned_in_smp DEFINE_SEQLOCK(rename_lock); - -EXPORT_SYMBOL(rename_lock); - -static struct kmem_cache *dentry_cache __read_mostly; - -/* - * This is the single most critical data structure when it comes - * to the dcache: the hashtable for lookups. Somebody should try - * to make this good - I've just made it work. - * - * This hash-function tries to avoid losing too many bits of hash - * information, yet avoid using a prime hash-size or similar. - */ - -static unsigned int d_hash_mask __read_mostly; -static unsigned int d_hash_shift __read_mostly; - -static struct hlist_bl_head *dentry_hashtable __read_mostly; - -static inline struct hlist_bl_head *d_hash(unsigned int hash) -{ - return dentry_hashtable + (hash >> (32 - d_hash_shift)); -} - -#define IN_LOOKUP_SHIFT 10 -static struct hlist_bl_head in_lookup_hashtable[1 << IN_LOOKUP_SHIFT]; - -static inline struct hlist_bl_head *in_lookup_hash(const struct dentry *parent, - unsigned int hash) -{ - hash += (unsigned long) parent / L1_CACHE_BYTES; - return in_lookup_hashtable + hash_32(hash, IN_LOOKUP_SHIFT); -} - - -/* Statistics gathering. */ -struct dentry_stat_t dentry_stat = { - .age_limit = 45, -}; - -static DEFINE_PER_CPU(long, nr_dentry); -static DEFINE_PER_CPU(long, nr_dentry_unused); - -#if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS) - -/* - * Here we resort to our own counters instead of using generic per-cpu counters - * for consistency with what the vfs inode code does. We are expected to harvest - * better code and performance by having our own specialized counters. - * - * Please note that the loop is done over all possible CPUs, not over all online - * CPUs. The reason for this is that we don't want to play games with CPUs going - * on and off. If one of them goes off, we will just keep their counters. - * - * glommer: See cffbc8a for details, and if you ever intend to change this, - * please update all vfs counters to match. - */ -static long get_nr_dentry(void) -{ - int i; - long sum = 0; - for_each_possible_cpu(i) - sum += per_cpu(nr_dentry, i); - return sum < 0 ? 0 : sum; -} - -static long get_nr_dentry_unused(void) -{ - int i; - long sum = 0; - for_each_possible_cpu(i) - sum += per_cpu(nr_dentry_unused, i); - return sum < 0 ? 0 : sum; -} - -int proc_nr_dentry(struct ctl_table *table, int write, void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - dentry_stat.nr_dentry = get_nr_dentry(); - dentry_stat.nr_unused = get_nr_dentry_unused(); - return proc_doulongvec_minmax(table, write, buffer, lenp, ppos); -} -#endif - -/* - * Compare 2 name strings, return 0 if they match, otherwise non-zero. - * The strings are both count bytes long, and count is non-zero. - */ -#ifdef CONFIG_DCACHE_WORD_ACCESS - -#include -/* - * NOTE! 'cs' and 'scount' come from a dentry, so it has a - * aligned allocation for this particular component. We don't - * strictly need the load_unaligned_zeropad() safety, but it - * doesn't hurt either. - * - * In contrast, 'ct' and 'tcount' can be from a pathname, and do - * need the careful unaligned handling. - */ -static inline int dentry_string_cmp(const unsigned char *cs, const unsigned char *ct, unsigned tcount) -{ - unsigned long a,b,mask; - - for (;;) { - a = *(unsigned long *)cs; - b = load_unaligned_zeropad(ct); - if (tcount < sizeof(unsigned long)) - break; - if (unlikely(a != b)) - return 1; - cs += sizeof(unsigned long); - ct += sizeof(unsigned long); - tcount -= sizeof(unsigned long); - if (!tcount) - return 0; - } - mask = bytemask_from_count(tcount); - return unlikely(!!((a ^ b) & mask)); -} - -#else - -static inline int dentry_string_cmp(const unsigned char *cs, const unsigned char *ct, unsigned tcount) -{ - do { - if (*cs != *ct) - return 1; - cs++; - ct++; - tcount--; - } while (tcount); - return 0; -} - -#endif - -static inline int dentry_cmp(const struct dentry *dentry, const unsigned char *ct, unsigned tcount) -{ - /* - * Be careful about RCU walk racing with rename: - * use 'lockless_dereference' to fetch the name pointer. - * - * NOTE! Even if a rename will mean that the length - * was not loaded atomically, we don't care. The - * RCU walk will check the sequence count eventually, - * and catch it. And we won't overrun the buffer, - * because we're reading the name pointer atomically, - * and a dentry name is guaranteed to be properly - * terminated with a NUL byte. - * - * End result: even if 'len' is wrong, we'll exit - * early because the data cannot match (there can - * be no NUL in the ct/tcount data) - */ - const unsigned char *cs = lockless_dereference(dentry->d_name.name); - - return dentry_string_cmp(cs, ct, tcount); -} - -struct external_name { - union { - atomic_t count; - struct rcu_head head; - } u; - unsigned char name[]; -}; - -static inline struct external_name *external_name(struct dentry *dentry) -{ - return container_of(dentry->d_name.name, struct external_name, name[0]); -} - -static void __d_free(struct rcu_head *head) -{ - struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu); - - kmem_cache_free(dentry_cache, dentry); -} - -static void __d_free_external(struct rcu_head *head) -{ - struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu); - kfree(external_name(dentry)); - kmem_cache_free(dentry_cache, dentry); -} - -static inline int dname_external(const struct dentry *dentry) -{ - return dentry->d_name.name != dentry->d_iname; -} - -static inline void __d_set_inode_and_type(struct dentry *dentry, - struct inode *inode, - unsigned type_flags) -{ - unsigned flags; - - dentry->d_inode = inode; - flags = READ_ONCE(dentry->d_flags); - flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU); - flags |= type_flags; - WRITE_ONCE(dentry->d_flags, flags); -} - -static inline void __d_clear_type_and_inode(struct dentry *dentry) -{ - unsigned flags = READ_ONCE(dentry->d_flags); - - flags &= ~(DCACHE_ENTRY_TYPE | DCACHE_FALLTHRU); - WRITE_ONCE(dentry->d_flags, flags); - dentry->d_inode = NULL; -} - -static void dentry_free(struct dentry *dentry) -{ - WARN_ON(!hlist_unhashed(&dentry->d_u.d_alias)); - if (unlikely(dname_external(dentry))) { - struct external_name *p = external_name(dentry); - if (likely(atomic_dec_and_test(&p->u.count))) { - call_rcu(&dentry->d_u.d_rcu, __d_free_external); - return; - } - } - /* if dentry was never visible to RCU, immediate free is OK */ - if (!(dentry->d_flags & DCACHE_RCUACCESS)) - __d_free(&dentry->d_u.d_rcu); - else - call_rcu(&dentry->d_u.d_rcu, __d_free); -} - -/* - * Release the dentry's inode, using the filesystem - * d_iput() operation if defined. - */ -static void dentry_unlink_inode(struct dentry * dentry) - __releases(dentry->d_lock) - __releases(dentry->d_inode->i_lock) -{ - struct inode *inode = dentry->d_inode; - bool hashed = !d_unhashed(dentry); - - if (hashed) - raw_write_seqcount_begin(&dentry->d_seq); - __d_clear_type_and_inode(dentry); - hlist_del_init(&dentry->d_u.d_alias); - if (hashed) - raw_write_seqcount_end(&dentry->d_seq); - spin_unlock(&dentry->d_lock); - spin_unlock(&inode->i_lock); - if (!inode->i_nlink) - fsnotify_inoderemove(inode); - if (dentry->d_op && dentry->d_op->d_iput) - dentry->d_op->d_iput(dentry, inode); - else - iput(inode); -} - -/* - * The DCACHE_LRU_LIST bit is set whenever the 'd_lru' entry - * is in use - which includes both the "real" per-superblock - * LRU list _and_ the DCACHE_SHRINK_LIST use. - * - * The DCACHE_SHRINK_LIST bit is set whenever the dentry is - * on the shrink list (ie not on the superblock LRU list). - * - * The per-cpu "nr_dentry_unused" counters are updated with - * the DCACHE_LRU_LIST bit. - * - * These helper functions make sure we always follow the - * rules. d_lock must be held by the caller. - */ -#define D_FLAG_VERIFY(dentry,x) WARN_ON_ONCE(((dentry)->d_flags & (DCACHE_LRU_LIST | DCACHE_SHRINK_LIST)) != (x)) -static void d_lru_add(struct dentry *dentry) -{ - D_FLAG_VERIFY(dentry, 0); - dentry->d_flags |= DCACHE_LRU_LIST; - this_cpu_inc(nr_dentry_unused); - WARN_ON_ONCE(!list_lru_add(&dentry->d_sb->s_dentry_lru, &dentry->d_lru)); -} - -static void d_lru_del(struct dentry *dentry) -{ - D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST); - dentry->d_flags &= ~DCACHE_LRU_LIST; - this_cpu_dec(nr_dentry_unused); - WARN_ON_ONCE(!list_lru_del(&dentry->d_sb->s_dentry_lru, &dentry->d_lru)); -} - -static void d_shrink_del(struct dentry *dentry) -{ - D_FLAG_VERIFY(dentry, DCACHE_SHRINK_LIST | DCACHE_LRU_LIST); - list_del_init(&dentry->d_lru); - dentry->d_flags &= ~(DCACHE_SHRINK_LIST | DCACHE_LRU_LIST); - this_cpu_dec(nr_dentry_unused); -} - -static void d_shrink_add(struct dentry *dentry, struct list_head *list) -{ - D_FLAG_VERIFY(dentry, 0); - list_add(&dentry->d_lru, list); - dentry->d_flags |= DCACHE_SHRINK_LIST | DCACHE_LRU_LIST; - this_cpu_inc(nr_dentry_unused); -} - -/* - * These can only be called under the global LRU lock, ie during the - * callback for freeing the LRU list. "isolate" removes it from the - * LRU lists entirely, while shrink_move moves it to the indicated - * private list. - */ -static void d_lru_isolate(struct list_lru_one *lru, struct dentry *dentry) -{ - D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST); - dentry->d_flags &= ~DCACHE_LRU_LIST; - this_cpu_dec(nr_dentry_unused); - list_lru_isolate(lru, &dentry->d_lru); -} - -static void d_lru_shrink_move(struct list_lru_one *lru, struct dentry *dentry, - struct list_head *list) -{ - D_FLAG_VERIFY(dentry, DCACHE_LRU_LIST); - dentry->d_flags |= DCACHE_SHRINK_LIST; - list_lru_isolate_move(lru, &dentry->d_lru, list); -} - -/* - * dentry_lru_(add|del)_list) must be called with d_lock held. - */ -static void dentry_lru_add(struct dentry *dentry) -{ - if (unlikely(!(dentry->d_flags & DCACHE_LRU_LIST))) - d_lru_add(dentry); -} - -/** - * d_drop - drop a dentry - * @dentry: dentry to drop - * - * d_drop() unhashes the entry from the parent dentry hashes, so that it won't - * be found through a VFS lookup any more. Note that this is different from - * deleting the dentry - d_delete will try to mark the dentry negative if - * possible, giving a successful _negative_ lookup, while d_drop will - * just make the cache lookup fail. - * - * d_drop() is used mainly for stuff that wants to invalidate a dentry for some - * reason (NFS timeouts or autofs deletes). - * - * __d_drop requires dentry->d_lock. - */ -void __d_drop(struct dentry *dentry) -{ - if (!d_unhashed(dentry)) { - struct hlist_bl_head *b; - /* - * Hashed dentries are normally on the dentry hashtable, - * with the exception of those newly allocated by - * d_obtain_alias, which are always IS_ROOT: - */ - if (unlikely(IS_ROOT(dentry))) - b = &dentry->d_sb->s_anon; - else - b = d_hash(dentry->d_name.hash); - - hlist_bl_lock(b); - __hlist_bl_del(&dentry->d_hash); - dentry->d_hash.pprev = NULL; - hlist_bl_unlock(b); - /* After this call, in-progress rcu-walk path lookup will fail. */ - write_seqcount_invalidate(&dentry->d_seq); - } -} -EXPORT_SYMBOL(__d_drop); - -void d_drop(struct dentry *dentry) -{ - spin_lock(&dentry->d_lock); - __d_drop(dentry); - spin_unlock(&dentry->d_lock); -} -EXPORT_SYMBOL(d_drop); - -static inline void dentry_unlist(struct dentry *dentry, struct dentry *parent) -{ - struct dentry *next; - /* - * Inform d_walk() and shrink_dentry_list() that we are no longer - * attached to the dentry tree - */ - dentry->d_flags |= DCACHE_DENTRY_KILLED; - if (unlikely(list_empty(&dentry->d_child))) - return; - __list_del_entry(&dentry->d_child); - /* - * Cursors can move around the list of children. While we'd been - * a normal list member, it didn't matter - ->d_child.next would've - * been updated. However, from now on it won't be and for the - * things like d_walk() it might end up with a nasty surprise. - * Normally d_walk() doesn't care about cursors moving around - - * ->d_lock on parent prevents that and since a cursor has no children - * of its own, we get through it without ever unlocking the parent. - * There is one exception, though - if we ascend from a child that - * gets killed as soon as we unlock it, the next sibling is found - * using the value left in its ->d_child.next. And if _that_ - * pointed to a cursor, and cursor got moved (e.g. by lseek()) - * before d_walk() regains parent->d_lock, we'll end up skipping - * everything the cursor had been moved past. - * - * Solution: make sure that the pointer left behind in ->d_child.next - * points to something that won't be moving around. I.e. skip the - * cursors. - */ - while (dentry->d_child.next != &parent->d_subdirs) { - next = list_entry(dentry->d_child.next, struct dentry, d_child); - if (likely(!(next->d_flags & DCACHE_DENTRY_CURSOR))) - break; - dentry->d_child.next = next->d_child.next; - } -} - -static void __dentry_kill(struct dentry *dentry) -{ - struct dentry *parent = NULL; - bool can_free = true; - if (!IS_ROOT(dentry)) - parent = dentry->d_parent; - - /* - * The dentry is now unrecoverably dead to the world. - */ - lockref_mark_dead(&dentry->d_lockref); - - /* - * inform the fs via d_prune that this dentry is about to be - * unhashed and destroyed. - */ - if (dentry->d_flags & DCACHE_OP_PRUNE) - dentry->d_op->d_prune(dentry); - - if (dentry->d_flags & DCACHE_LRU_LIST) { - if (!(dentry->d_flags & DCACHE_SHRINK_LIST)) - d_lru_del(dentry); - } - /* if it was on the hash then remove it */ - __d_drop(dentry); - dentry_unlist(dentry, parent); - if (parent) - spin_unlock(&parent->d_lock); - if (dentry->d_inode) - dentry_unlink_inode(dentry); - else - spin_unlock(&dentry->d_lock); - this_cpu_dec(nr_dentry); - if (dentry->d_op && dentry->d_op->d_release) - dentry->d_op->d_release(dentry); - - spin_lock(&dentry->d_lock); - if (dentry->d_flags & DCACHE_SHRINK_LIST) { - dentry->d_flags |= DCACHE_MAY_FREE; - can_free = false; - } - spin_unlock(&dentry->d_lock); - if (likely(can_free)) - dentry_free(dentry); -} - -/* - * Finish off a dentry we've decided to kill. - * dentry->d_lock must be held, returns with it unlocked. - * If ref is non-zero, then decrement the refcount too. - * Returns dentry requiring refcount drop, or NULL if we're done. - */ -static struct dentry *dentry_kill(struct dentry *dentry) - __releases(dentry->d_lock) -{ - struct inode *inode = dentry->d_inode; - struct dentry *parent = NULL; - - if (inode && unlikely(!spin_trylock(&inode->i_lock))) - goto failed; - - if (!IS_ROOT(dentry)) { - parent = dentry->d_parent; - if (unlikely(!spin_trylock(&parent->d_lock))) { - if (inode) - spin_unlock(&inode->i_lock); - goto failed; - } - } - - __dentry_kill(dentry); - return parent; - -failed: - spin_unlock(&dentry->d_lock); - return dentry; /* try again with same dentry */ -} - -static inline struct dentry *lock_parent(struct dentry *dentry) -{ - struct dentry *parent = dentry->d_parent; - if (IS_ROOT(dentry)) - return NULL; - if (unlikely(dentry->d_lockref.count < 0)) - return NULL; - if (likely(spin_trylock(&parent->d_lock))) - return parent; - rcu_read_lock(); - spin_unlock(&dentry->d_lock); -again: - parent = ACCESS_ONCE(dentry->d_parent); - spin_lock(&parent->d_lock); - /* - * We can't blindly lock dentry until we are sure - * that we won't violate the locking order. - * Any changes of dentry->d_parent must have - * been done with parent->d_lock held, so - * spin_lock() above is enough of a barrier - * for checking if it's still our child. - */ - if (unlikely(parent != dentry->d_parent)) { - spin_unlock(&parent->d_lock); - goto again; - } - rcu_read_unlock(); - if (parent != dentry) - spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); - else - parent = NULL; - return parent; -} - -/* - * Try to do a lockless dput(), and return whether that was successful. - * - * If unsuccessful, we return false, having already taken the dentry lock. - * - * The caller needs to hold the RCU read lock, so that the dentry is - * guaranteed to stay around even if the refcount goes down to zero! - */ -static inline bool fast_dput(struct dentry *dentry) -{ - int ret; - unsigned int d_flags; - - /* - * If we have a d_op->d_delete() operation, we sould not - * let the dentry count go to zero, so use "put_or_lock". - */ - if (unlikely(dentry->d_flags & DCACHE_OP_DELETE)) - return lockref_put_or_lock(&dentry->d_lockref); - - /* - * .. otherwise, we can try to just decrement the - * lockref optimistically. - */ - ret = lockref_put_return(&dentry->d_lockref); - - /* - * If the lockref_put_return() failed due to the lock being held - * by somebody else, the fast path has failed. We will need to - * get the lock, and then check the count again. - */ - if (unlikely(ret < 0)) { - spin_lock(&dentry->d_lock); - if (dentry->d_lockref.count > 1) { - dentry->d_lockref.count--; - spin_unlock(&dentry->d_lock); - return 1; - } - return 0; - } - - /* - * If we weren't the last ref, we're done. - */ - if (ret) - return 1; - - /* - * Careful, careful. The reference count went down - * to zero, but we don't hold the dentry lock, so - * somebody else could get it again, and do another - * dput(), and we need to not race with that. - * - * However, there is a very special and common case - * where we don't care, because there is nothing to - * do: the dentry is still hashed, it does not have - * a 'delete' op, and it's referenced and already on - * the LRU list. - * - * NOTE! Since we aren't locked, these values are - * not "stable". However, it is sufficient that at - * some point after we dropped the reference the - * dentry was hashed and the flags had the proper - * value. Other dentry users may have re-gotten - * a reference to the dentry and change that, but - * our work is done - we can leave the dentry - * around with a zero refcount. - */ - smp_rmb(); - d_flags = ACCESS_ONCE(dentry->d_flags); - d_flags &= DCACHE_REFERENCED | DCACHE_LRU_LIST | DCACHE_DISCONNECTED; - - /* Nothing to do? Dropping the reference was all we needed? */ - if (d_flags == (DCACHE_REFERENCED | DCACHE_LRU_LIST) && !d_unhashed(dentry)) - return 1; - - /* - * Not the fast normal case? Get the lock. We've already decremented - * the refcount, but we'll need to re-check the situation after - * getting the lock. - */ - spin_lock(&dentry->d_lock); - - /* - * Did somebody else grab a reference to it in the meantime, and - * we're no longer the last user after all? Alternatively, somebody - * else could have killed it and marked it dead. Either way, we - * don't need to do anything else. - */ - if (dentry->d_lockref.count) { - spin_unlock(&dentry->d_lock); - return 1; - } - - /* - * Re-get the reference we optimistically dropped. We hold the - * lock, and we just tested that it was zero, so we can just - * set it to 1. - */ - dentry->d_lockref.count = 1; - return 0; -} - - -/* - * This is dput - * - * This is complicated by the fact that we do not want to put - * dentries that are no longer on any hash chain on the unused - * list: we'd much rather just get rid of them immediately. - * - * However, that implies that we have to traverse the dentry - * tree upwards to the parents which might _also_ now be - * scheduled for deletion (it may have been only waiting for - * its last child to go away). - * - * This tail recursion is done by hand as we don't want to depend - * on the compiler to always get this right (gcc generally doesn't). - * Real recursion would eat up our stack space. - */ - -/* - * dput - release a dentry - * @dentry: dentry to release - * - * Release a dentry. This will drop the usage count and if appropriate - * call the dentry unlink method as well as removing it from the queues and - * releasing its resources. If the parent dentries were scheduled for release - * they too may now get deleted. - */ -void dput(struct dentry *dentry) -{ - if (unlikely(!dentry)) - return; - -repeat: - might_sleep(); - - rcu_read_lock(); - if (likely(fast_dput(dentry))) { - rcu_read_unlock(); - return; - } - - /* Slow case: now with the dentry lock held */ - rcu_read_unlock(); - - WARN_ON(d_in_lookup(dentry)); - - /* Unreachable? Get rid of it */ - if (unlikely(d_unhashed(dentry))) - goto kill_it; - - if (unlikely(dentry->d_flags & DCACHE_DISCONNECTED)) - goto kill_it; - - if (unlikely(dentry->d_flags & DCACHE_OP_DELETE)) { - if (dentry->d_op->d_delete(dentry)) - goto kill_it; - } - - if (!(dentry->d_flags & DCACHE_REFERENCED)) - dentry->d_flags |= DCACHE_REFERENCED; - dentry_lru_add(dentry); - - dentry->d_lockref.count--; - spin_unlock(&dentry->d_lock); - return; - -kill_it: - dentry = dentry_kill(dentry); - if (dentry) { - cond_resched(); - goto repeat; - } -} -EXPORT_SYMBOL(dput); - - -/* This must be called with d_lock held */ -static inline void __dget_dlock(struct dentry *dentry) -{ - dentry->d_lockref.count++; -} - -static inline void __dget(struct dentry *dentry) -{ - lockref_get(&dentry->d_lockref); -} - -struct dentry *dget_parent(struct dentry *dentry) -{ - int gotref; - struct dentry *ret; - - /* - * Do optimistic parent lookup without any - * locking. - */ - rcu_read_lock(); - ret = ACCESS_ONCE(dentry->d_parent); - gotref = lockref_get_not_zero(&ret->d_lockref); - rcu_read_unlock(); - if (likely(gotref)) { - if (likely(ret == ACCESS_ONCE(dentry->d_parent))) - return ret; - dput(ret); - } - -repeat: - /* - * Don't need rcu_dereference because we re-check it was correct under - * the lock. - */ - rcu_read_lock(); - ret = dentry->d_parent; - spin_lock(&ret->d_lock); - if (unlikely(ret != dentry->d_parent)) { - spin_unlock(&ret->d_lock); - rcu_read_unlock(); - goto repeat; - } - rcu_read_unlock(); - BUG_ON(!ret->d_lockref.count); - ret->d_lockref.count++; - spin_unlock(&ret->d_lock); - return ret; -} -EXPORT_SYMBOL(dget_parent); - -/** - * d_find_alias - grab a hashed alias of inode - * @inode: inode in question - * - * If inode has a hashed alias, or is a directory and has any alias, - * acquire the reference to alias and return it. Otherwise return NULL. - * Notice that if inode is a directory there can be only one alias and - * it can be unhashed only if it has no children, or if it is the root - * of a filesystem, or if the directory was renamed and d_revalidate - * was the first vfs operation to notice. - * - * If the inode has an IS_ROOT, DCACHE_DISCONNECTED alias, then prefer - * any other hashed alias over that one. - */ -static struct dentry *__d_find_alias(struct inode *inode) -{ - struct dentry *alias, *discon_alias; - -again: - discon_alias = NULL; - hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { - spin_lock(&alias->d_lock); - if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) { - if (IS_ROOT(alias) && - (alias->d_flags & DCACHE_DISCONNECTED)) { - discon_alias = alias; - } else { - __dget_dlock(alias); - spin_unlock(&alias->d_lock); - return alias; - } - } - spin_unlock(&alias->d_lock); - } - if (discon_alias) { - alias = discon_alias; - spin_lock(&alias->d_lock); - if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) { - __dget_dlock(alias); - spin_unlock(&alias->d_lock); - return alias; - } - spin_unlock(&alias->d_lock); - goto again; - } - return NULL; -} - -struct dentry *d_find_alias(struct inode *inode) -{ - struct dentry *de = NULL; - - if (!hlist_empty(&inode->i_dentry)) { - spin_lock(&inode->i_lock); - de = __d_find_alias(inode); - spin_unlock(&inode->i_lock); - } - return de; -} -EXPORT_SYMBOL(d_find_alias); - -/* - * Try to kill dentries associated with this inode. - * WARNING: you must own a reference to inode. - */ -void d_prune_aliases(struct inode *inode) -{ - struct dentry *dentry; -restart: - spin_lock(&inode->i_lock); - hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { - spin_lock(&dentry->d_lock); - if (!dentry->d_lockref.count) { - struct dentry *parent = lock_parent(dentry); - if (likely(!dentry->d_lockref.count)) { - __dentry_kill(dentry); - dput(parent); - goto restart; - } - if (parent) - spin_unlock(&parent->d_lock); - } - spin_unlock(&dentry->d_lock); - } - spin_unlock(&inode->i_lock); -} -EXPORT_SYMBOL(d_prune_aliases); - -static void shrink_dentry_list(struct list_head *list) -{ - struct dentry *dentry, *parent; - - while (!list_empty(list)) { - struct inode *inode; - dentry = list_entry(list->prev, struct dentry, d_lru); - spin_lock(&dentry->d_lock); - parent = lock_parent(dentry); - - /* - * The dispose list is isolated and dentries are not accounted - * to the LRU here, so we can simply remove it from the list - * here regardless of whether it is referenced or not. - */ - d_shrink_del(dentry); - - /* - * We found an inuse dentry which was not removed from - * the LRU because of laziness during lookup. Do not free it. - */ - if (dentry->d_lockref.count > 0) { - spin_unlock(&dentry->d_lock); - if (parent) - spin_unlock(&parent->d_lock); - continue; - } - - - if (unlikely(dentry->d_flags & DCACHE_DENTRY_KILLED)) { - bool can_free = dentry->d_flags & DCACHE_MAY_FREE; - spin_unlock(&dentry->d_lock); - if (parent) - spin_unlock(&parent->d_lock); - if (can_free) - dentry_free(dentry); - continue; - } - - inode = dentry->d_inode; - if (inode && unlikely(!spin_trylock(&inode->i_lock))) { - d_shrink_add(dentry, list); - spin_unlock(&dentry->d_lock); - if (parent) - spin_unlock(&parent->d_lock); - continue; - } - - __dentry_kill(dentry); - - /* - * We need to prune ancestors too. This is necessary to prevent - * quadratic behavior of shrink_dcache_parent(), but is also - * expected to be beneficial in reducing dentry cache - * fragmentation. - */ - dentry = parent; - while (dentry && !lockref_put_or_lock(&dentry->d_lockref)) { - parent = lock_parent(dentry); - if (dentry->d_lockref.count != 1) { - dentry->d_lockref.count--; - spin_unlock(&dentry->d_lock); - if (parent) - spin_unlock(&parent->d_lock); - break; - } - inode = dentry->d_inode; /* can't be NULL */ - if (unlikely(!spin_trylock(&inode->i_lock))) { - spin_unlock(&dentry->d_lock); - if (parent) - spin_unlock(&parent->d_lock); - cpu_relax(); - continue; - } - __dentry_kill(dentry); - dentry = parent; - } - } -} - -static enum lru_status dentry_lru_isolate(struct list_head *item, - struct list_lru_one *lru, spinlock_t *lru_lock, void *arg) -{ - struct list_head *freeable = arg; - struct dentry *dentry = container_of(item, struct dentry, d_lru); - - - /* - * we are inverting the lru lock/dentry->d_lock here, - * so use a trylock. If we fail to get the lock, just skip - * it - */ - if (!spin_trylock(&dentry->d_lock)) - return LRU_SKIP; - - /* - * Referenced dentries are still in use. If they have active - * counts, just remove them from the LRU. Otherwise give them - * another pass through the LRU. - */ - if (dentry->d_lockref.count) { - d_lru_isolate(lru, dentry); - spin_unlock(&dentry->d_lock); - return LRU_REMOVED; - } - - if (dentry->d_flags & DCACHE_REFERENCED) { - dentry->d_flags &= ~DCACHE_REFERENCED; - spin_unlock(&dentry->d_lock); - - /* - * The list move itself will be made by the common LRU code. At - * this point, we've dropped the dentry->d_lock but keep the - * lru lock. This is safe to do, since every list movement is - * protected by the lru lock even if both locks are held. - * - * This is guaranteed by the fact that all LRU management - * functions are intermediated by the LRU API calls like - * list_lru_add and list_lru_del. List movement in this file - * only ever occur through this functions or through callbacks - * like this one, that are called from the LRU API. - * - * The only exceptions to this are functions like - * shrink_dentry_list, and code that first checks for the - * DCACHE_SHRINK_LIST flag. Those are guaranteed to be - * operating only with stack provided lists after they are - * properly isolated from the main list. It is thus, always a - * local access. - */ - return LRU_ROTATE; - } - - d_lru_shrink_move(lru, dentry, freeable); - spin_unlock(&dentry->d_lock); - - return LRU_REMOVED; -} - -/** - * prune_dcache_sb - shrink the dcache - * @sb: superblock - * @sc: shrink control, passed to list_lru_shrink_walk() - * - * Attempt to shrink the superblock dcache LRU by @sc->nr_to_scan entries. This - * is done when we need more memory and called from the superblock shrinker - * function. - * - * This function may fail to free any resources if all the dentries are in - * use. - */ -long prune_dcache_sb(struct super_block *sb, struct shrink_control *sc) -{ - LIST_HEAD(dispose); - long freed; - - freed = list_lru_shrink_walk(&sb->s_dentry_lru, sc, - dentry_lru_isolate, &dispose); - shrink_dentry_list(&dispose); - return freed; -} - -static enum lru_status dentry_lru_isolate_shrink(struct list_head *item, - struct list_lru_one *lru, spinlock_t *lru_lock, void *arg) -{ - struct list_head *freeable = arg; - struct dentry *dentry = container_of(item, struct dentry, d_lru); - - /* - * we are inverting the lru lock/dentry->d_lock here, - * so use a trylock. If we fail to get the lock, just skip - * it - */ - if (!spin_trylock(&dentry->d_lock)) - return LRU_SKIP; - - d_lru_shrink_move(lru, dentry, freeable); - spin_unlock(&dentry->d_lock); - - return LRU_REMOVED; -} - - -/** - * shrink_dcache_sb - shrink dcache for a superblock - * @sb: superblock - * - * Shrink the dcache for the specified super block. This is used to free - * the dcache before unmounting a file system. - */ -void shrink_dcache_sb(struct super_block *sb) -{ - long freed; - - do { - LIST_HEAD(dispose); - - freed = list_lru_walk(&sb->s_dentry_lru, - dentry_lru_isolate_shrink, &dispose, UINT_MAX); - - this_cpu_sub(nr_dentry_unused, freed); - shrink_dentry_list(&dispose); - } while (freed > 0); -} -EXPORT_SYMBOL(shrink_dcache_sb); - -/** - * enum d_walk_ret - action to talke during tree walk - * @D_WALK_CONTINUE: contrinue walk - * @D_WALK_QUIT: quit walk - * @D_WALK_NORETRY: quit when retry is needed - * @D_WALK_SKIP: skip this dentry and its children - */ -enum d_walk_ret { - D_WALK_CONTINUE, - D_WALK_QUIT, - D_WALK_NORETRY, - D_WALK_SKIP, -}; - -/** - * d_walk - walk the dentry tree - * @parent: start of walk - * @data: data passed to @enter() and @finish() - * @enter: callback when first entering the dentry - * @finish: callback when successfully finished the walk - * - * The @enter() and @finish() callbacks are called with d_lock held. - */ -static void d_walk(struct dentry *parent, void *data, - enum d_walk_ret (*enter)(void *, struct dentry *), - void (*finish)(void *)) -{ - struct dentry *this_parent; - struct list_head *next; - unsigned seq = 0; - enum d_walk_ret ret; - bool retry = true; - -again: - read_seqbegin_or_lock(&rename_lock, &seq); - this_parent = parent; - spin_lock(&this_parent->d_lock); - - ret = enter(data, this_parent); - switch (ret) { - case D_WALK_CONTINUE: - break; - case D_WALK_QUIT: - case D_WALK_SKIP: - goto out_unlock; - case D_WALK_NORETRY: - retry = false; - break; - } -repeat: - next = this_parent->d_subdirs.next; -resume: - while (next != &this_parent->d_subdirs) { - struct list_head *tmp = next; - struct dentry *dentry = list_entry(tmp, struct dentry, d_child); - next = tmp->next; - - if (unlikely(dentry->d_flags & DCACHE_DENTRY_CURSOR)) - continue; - - spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); - - ret = enter(data, dentry); - switch (ret) { - case D_WALK_CONTINUE: - break; - case D_WALK_QUIT: - spin_unlock(&dentry->d_lock); - goto out_unlock; - case D_WALK_NORETRY: - retry = false; - break; - case D_WALK_SKIP: - spin_unlock(&dentry->d_lock); - continue; - } - - if (!list_empty(&dentry->d_subdirs)) { - spin_unlock(&this_parent->d_lock); - spin_release(&dentry->d_lock.dep_map, 1, _RET_IP_); - this_parent = dentry; - spin_acquire(&this_parent->d_lock.dep_map, 0, 1, _RET_IP_); - goto repeat; - } - spin_unlock(&dentry->d_lock); - } - /* - * All done at this level ... ascend and resume the search. - */ - rcu_read_lock(); -ascend: - if (this_parent != parent) { - struct dentry *child = this_parent; - this_parent = child->d_parent; - - spin_unlock(&child->d_lock); - spin_lock(&this_parent->d_lock); - - /* might go back up the wrong parent if we have had a rename. */ - if (need_seqretry(&rename_lock, seq)) - goto rename_retry; - /* go into the first sibling still alive */ - do { - next = child->d_child.next; - if (next == &this_parent->d_subdirs) - goto ascend; - child = list_entry(next, struct dentry, d_child); - } while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)); - rcu_read_unlock(); - goto resume; - } - if (need_seqretry(&rename_lock, seq)) - goto rename_retry; - rcu_read_unlock(); - if (finish) - finish(data); - -out_unlock: - spin_unlock(&this_parent->d_lock); - done_seqretry(&rename_lock, seq); - return; - -rename_retry: - spin_unlock(&this_parent->d_lock); - rcu_read_unlock(); - BUG_ON(seq & 1); - if (!retry) - return; - seq = 1; - goto again; -} - -/* - * Search for at least 1 mount point in the dentry's subdirs. - * We descend to the next level whenever the d_subdirs - * list is non-empty and continue searching. - */ - -static enum d_walk_ret check_mount(void *data, struct dentry *dentry) -{ - int *ret = data; - if (d_mountpoint(dentry)) { - *ret = 1; - return D_WALK_QUIT; - } - return D_WALK_CONTINUE; -} - -/** - * have_submounts - check for mounts over a dentry - * @parent: dentry to check. - * - * Return true if the parent or its subdirectories contain - * a mount point - */ -int have_submounts(struct dentry *parent) -{ - int ret = 0; - - d_walk(parent, &ret, check_mount, NULL); - - return ret; -} -EXPORT_SYMBOL(have_submounts); - -/* - * Called by mount code to set a mountpoint and check if the mountpoint is - * reachable (e.g. NFS can unhash a directory dentry and then the complete - * subtree can become unreachable). - * - * Only one of d_invalidate() and d_set_mounted() must succeed. For - * this reason take rename_lock and d_lock on dentry and ancestors. - */ -int d_set_mounted(struct dentry *dentry) -{ - struct dentry *p; - int ret = -ENOENT; - write_seqlock(&rename_lock); - for (p = dentry->d_parent; !IS_ROOT(p); p = p->d_parent) { - /* Need exclusion wrt. d_invalidate() */ - spin_lock(&p->d_lock); - if (unlikely(d_unhashed(p))) { - spin_unlock(&p->d_lock); - goto out; - } - spin_unlock(&p->d_lock); - } - spin_lock(&dentry->d_lock); - if (!d_unlinked(dentry)) { - dentry->d_flags |= DCACHE_MOUNTED; - ret = 0; - } - spin_unlock(&dentry->d_lock); -out: - write_sequnlock(&rename_lock); - return ret; -} - -/* - * Search the dentry child list of the specified parent, - * and move any unused dentries to the end of the unused - * list for prune_dcache(). We descend to the next level - * whenever the d_subdirs list is non-empty and continue - * searching. - * - * It returns zero iff there are no unused children, - * otherwise it returns the number of children moved to - * the end of the unused list. This may not be the total - * number of unused children, because select_parent can - * drop the lock and return early due to latency - * constraints. - */ - -struct select_data { - struct dentry *start; - struct list_head dispose; - int found; -}; - -static enum d_walk_ret select_collect(void *_data, struct dentry *dentry) -{ - struct select_data *data = _data; - enum d_walk_ret ret = D_WALK_CONTINUE; - - if (data->start == dentry) - goto out; - - if (dentry->d_flags & DCACHE_SHRINK_LIST) { - data->found++; - } else { - if (dentry->d_flags & DCACHE_LRU_LIST) - d_lru_del(dentry); - if (!dentry->d_lockref.count) { - d_shrink_add(dentry, &data->dispose); - data->found++; - } - } - /* - * We can return to the caller if we have found some (this - * ensures forward progress). We'll be coming back to find - * the rest. - */ - if (!list_empty(&data->dispose)) - ret = need_resched() ? D_WALK_QUIT : D_WALK_NORETRY; -out: - return ret; -} - -/** - * shrink_dcache_parent - prune dcache - * @parent: parent of entries to prune - * - * Prune the dcache to remove unused children of the parent dentry. - */ -void shrink_dcache_parent(struct dentry *parent) -{ - for (;;) { - struct select_data data; - - INIT_LIST_HEAD(&data.dispose); - data.start = parent; - data.found = 0; - - d_walk(parent, &data, select_collect, NULL); - if (!data.found) - break; - - shrink_dentry_list(&data.dispose); - cond_resched(); - } -} -EXPORT_SYMBOL(shrink_dcache_parent); - -static enum d_walk_ret umount_check(void *_data, struct dentry *dentry) -{ - /* it has busy descendents; complain about those instead */ - if (!list_empty(&dentry->d_subdirs)) - return D_WALK_CONTINUE; - - /* root with refcount 1 is fine */ - if (dentry == _data && dentry->d_lockref.count == 1) - return D_WALK_CONTINUE; - - printk(KERN_ERR "BUG: Dentry %p{i=%lx,n=%pd} " - " still in use (%d) [unmount of %s %s]\n", - dentry, - dentry->d_inode ? - dentry->d_inode->i_ino : 0UL, - dentry, - dentry->d_lockref.count, - dentry->d_sb->s_type->name, - dentry->d_sb->s_id); - WARN_ON(1); - return D_WALK_CONTINUE; -} - -static void do_one_tree(struct dentry *dentry) -{ - shrink_dcache_parent(dentry); - d_walk(dentry, dentry, umount_check, NULL); - d_drop(dentry); - dput(dentry); -} - -/* - * destroy the dentries attached to a superblock on unmounting - */ -void shrink_dcache_for_umount(struct super_block *sb) -{ - struct dentry *dentry; - - WARN(down_read_trylock(&sb->s_umount), "s_umount should've been locked"); - - dentry = sb->s_root; - sb->s_root = NULL; - do_one_tree(dentry); - - while (!hlist_bl_empty(&sb->s_anon)) { - dentry = dget(hlist_bl_entry(hlist_bl_first(&sb->s_anon), struct dentry, d_hash)); - do_one_tree(dentry); - } -} - -struct detach_data { - struct select_data select; - struct dentry *mountpoint; -}; -static enum d_walk_ret detach_and_collect(void *_data, struct dentry *dentry) -{ - struct detach_data *data = _data; - - if (d_mountpoint(dentry)) { - __dget_dlock(dentry); - data->mountpoint = dentry; - return D_WALK_QUIT; - } - - return select_collect(&data->select, dentry); -} - -static void check_and_drop(void *_data) -{ - struct detach_data *data = _data; - - if (!data->mountpoint && !data->select.found) - __d_drop(data->select.start); -} - -/** - * d_invalidate - detach submounts, prune dcache, and drop - * @dentry: dentry to invalidate (aka detach, prune and drop) - * - * no dcache lock. - * - * The final d_drop is done as an atomic operation relative to - * rename_lock ensuring there are no races with d_set_mounted. This - * ensures there are no unhashed dentries on the path to a mountpoint. - */ -void d_invalidate(struct dentry *dentry) -{ - /* - * If it's already been dropped, return OK. - */ - spin_lock(&dentry->d_lock); - if (d_unhashed(dentry)) { - spin_unlock(&dentry->d_lock); - return; - } - spin_unlock(&dentry->d_lock); - - /* Negative dentries can be dropped without further checks */ - if (!dentry->d_inode) { - d_drop(dentry); - return; - } - - for (;;) { - struct detach_data data; - - data.mountpoint = NULL; - INIT_LIST_HEAD(&data.select.dispose); - data.select.start = dentry; - data.select.found = 0; - - d_walk(dentry, &data, detach_and_collect, check_and_drop); - - if (data.select.found) - shrink_dentry_list(&data.select.dispose); - - if (data.mountpoint) { - detach_mounts(data.mountpoint); - dput(data.mountpoint); - } - - if (!data.mountpoint && !data.select.found) - break; - - cond_resched(); - } -} -EXPORT_SYMBOL(d_invalidate); - -/** - * __d_alloc - allocate a dcache entry - * @sb: filesystem it will belong to - * @name: qstr of the name - * - * Allocates a dentry. It returns %NULL if there is insufficient memory - * available. On a success the dentry is returned. The name passed in is - * copied and the copy passed in may be reused after this call. - */ - -struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name) -{ - struct dentry *dentry; - char *dname; - int err; - - dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL); - if (!dentry) - return NULL; - - /* - * We guarantee that the inline name is always NUL-terminated. - * This way the memcpy() done by the name switching in rename - * will still always have a NUL at the end, even if we might - * be overwriting an internal NUL character - */ - dentry->d_iname[DNAME_INLINE_LEN-1] = 0; - if (unlikely(!name)) { - static const struct qstr anon = QSTR_INIT("/", 1); - name = &anon; - dname = dentry->d_iname; - } else if (name->len > DNAME_INLINE_LEN-1) { - size_t size = offsetof(struct external_name, name[1]); - struct external_name *p = kmalloc(size + name->len, - GFP_KERNEL_ACCOUNT); - if (!p) { - kmem_cache_free(dentry_cache, dentry); - return NULL; - } - atomic_set(&p->u.count, 1); - dname = p->name; - if (IS_ENABLED(CONFIG_DCACHE_WORD_ACCESS)) - kasan_unpoison_shadow(dname, - round_up(name->len + 1, sizeof(unsigned long))); - } else { - dname = dentry->d_iname; - } - - dentry->d_name.len = name->len; - dentry->d_name.hash = name->hash; - memcpy(dname, name->name, name->len); - dname[name->len] = 0; - - /* Make sure we always see the terminating NUL character */ - smp_wmb(); - dentry->d_name.name = dname; - - dentry->d_lockref.count = 1; - dentry->d_flags = 0; - spin_lock_init(&dentry->d_lock); - seqcount_init(&dentry->d_seq); - dentry->d_inode = NULL; - dentry->d_parent = dentry; - dentry->d_sb = sb; - dentry->d_op = NULL; - dentry->d_fsdata = NULL; - INIT_HLIST_BL_NODE(&dentry->d_hash); - INIT_LIST_HEAD(&dentry->d_lru); - INIT_LIST_HEAD(&dentry->d_subdirs); - INIT_HLIST_NODE(&dentry->d_u.d_alias); - INIT_LIST_HEAD(&dentry->d_child); - d_set_d_op(dentry, dentry->d_sb->s_d_op); - - if (dentry->d_op && dentry->d_op->d_init) { - err = dentry->d_op->d_init(dentry); - if (err) { - if (dname_external(dentry)) - kfree(external_name(dentry)); - kmem_cache_free(dentry_cache, dentry); - return NULL; - } - } - - this_cpu_inc(nr_dentry); - - return dentry; -} - -/** - * d_alloc - allocate a dcache entry - * @parent: parent of entry to allocate - * @name: qstr of the name - * - * Allocates a dentry. It returns %NULL if there is insufficient memory - * available. On a success the dentry is returned. The name passed in is - * copied and the copy passed in may be reused after this call. - */ -struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) -{ - struct dentry *dentry = __d_alloc(parent->d_sb, name); - if (!dentry) - return NULL; - dentry->d_flags |= DCACHE_RCUACCESS; - spin_lock(&parent->d_lock); - /* - * don't need child lock because it is not subject - * to concurrency here - */ - __dget_dlock(parent); - dentry->d_parent = parent; - list_add(&dentry->d_child, &parent->d_subdirs); - spin_unlock(&parent->d_lock); - - return dentry; -} -EXPORT_SYMBOL(d_alloc); - -struct dentry *d_alloc_cursor(struct dentry * parent) -{ - struct dentry *dentry = __d_alloc(parent->d_sb, NULL); - if (dentry) { - dentry->d_flags |= DCACHE_RCUACCESS | DCACHE_DENTRY_CURSOR; - dentry->d_parent = dget(parent); - } - return dentry; -} - -/** - * d_alloc_pseudo - allocate a dentry (for lookup-less filesystems) - * @sb: the superblock - * @name: qstr of the name - * - * For a filesystem that just pins its dentries in memory and never - * performs lookups at all, return an unhashed IS_ROOT dentry. - */ -struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name) -{ - return __d_alloc(sb, name); -} -EXPORT_SYMBOL(d_alloc_pseudo); - -struct dentry *d_alloc_name(struct dentry *parent, const char *name) -{ - struct qstr q; - - q.name = name; - q.hash_len = hashlen_string(parent, name); - return d_alloc(parent, &q); -} -EXPORT_SYMBOL(d_alloc_name); - -void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op) -{ - WARN_ON_ONCE(dentry->d_op); - WARN_ON_ONCE(dentry->d_flags & (DCACHE_OP_HASH | - DCACHE_OP_COMPARE | - DCACHE_OP_REVALIDATE | - DCACHE_OP_WEAK_REVALIDATE | - DCACHE_OP_DELETE | - DCACHE_OP_REAL)); - dentry->d_op = op; - if (!op) - return; - if (op->d_hash) - dentry->d_flags |= DCACHE_OP_HASH; - if (op->d_compare) - dentry->d_flags |= DCACHE_OP_COMPARE; - if (op->d_revalidate) - dentry->d_flags |= DCACHE_OP_REVALIDATE; - if (op->d_weak_revalidate) - dentry->d_flags |= DCACHE_OP_WEAK_REVALIDATE; - if (op->d_delete) - dentry->d_flags |= DCACHE_OP_DELETE; - if (op->d_prune) - dentry->d_flags |= DCACHE_OP_PRUNE; - if (op->d_real) - dentry->d_flags |= DCACHE_OP_REAL; - -} -EXPORT_SYMBOL(d_set_d_op); - - -/* - * d_set_fallthru - Mark a dentry as falling through to a lower layer - * @dentry - The dentry to mark - * - * Mark a dentry as falling through to the lower layer (as set with - * d_pin_lower()). This flag may be recorded on the medium. - */ -void d_set_fallthru(struct dentry *dentry) -{ - spin_lock(&dentry->d_lock); - dentry->d_flags |= DCACHE_FALLTHRU; - spin_unlock(&dentry->d_lock); -} -EXPORT_SYMBOL(d_set_fallthru); - -static unsigned d_flags_for_inode(struct inode *inode) -{ - unsigned add_flags = DCACHE_REGULAR_TYPE; - - if (!inode) - return DCACHE_MISS_TYPE; - - if (S_ISDIR(inode->i_mode)) { - add_flags = DCACHE_DIRECTORY_TYPE; - if (unlikely(!(inode->i_opflags & IOP_LOOKUP))) { - if (unlikely(!inode->i_op->lookup)) - add_flags = DCACHE_AUTODIR_TYPE; - else - inode->i_opflags |= IOP_LOOKUP; - } - goto type_determined; - } - - if (unlikely(!(inode->i_opflags & IOP_NOFOLLOW))) { - if (unlikely(inode->i_op->get_link)) { - add_flags = DCACHE_SYMLINK_TYPE; - goto type_determined; - } - inode->i_opflags |= IOP_NOFOLLOW; - } - - if (unlikely(!S_ISREG(inode->i_mode))) - add_flags = DCACHE_SPECIAL_TYPE; - -type_determined: - if (unlikely(IS_AUTOMOUNT(inode))) - add_flags |= DCACHE_NEED_AUTOMOUNT; - return add_flags; -} - -static void __d_instantiate(struct dentry *dentry, struct inode *inode) -{ - unsigned add_flags = d_flags_for_inode(inode); - WARN_ON(d_in_lookup(dentry)); - - spin_lock(&dentry->d_lock); - hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry); - raw_write_seqcount_begin(&dentry->d_seq); - __d_set_inode_and_type(dentry, inode, add_flags); - raw_write_seqcount_end(&dentry->d_seq); - fsnotify_update_flags(dentry); - spin_unlock(&dentry->d_lock); -} - -/** - * d_instantiate - fill in inode information for a dentry - * @entry: dentry to complete - * @inode: inode to attach to this dentry - * - * Fill in inode information in the entry. - * - * This turns negative dentries into productive full members - * of society. - * - * NOTE! This assumes that the inode count has been incremented - * (or otherwise set) by the caller to indicate that it is now - * in use by the dcache. - */ - -void d_instantiate(struct dentry *entry, struct inode * inode) -{ - BUG_ON(!hlist_unhashed(&entry->d_u.d_alias)); - if (inode) { - security_d_instantiate(entry, inode); - spin_lock(&inode->i_lock); - __d_instantiate(entry, inode); - spin_unlock(&inode->i_lock); - } -} -EXPORT_SYMBOL(d_instantiate); - -/** - * d_instantiate_no_diralias - instantiate a non-aliased dentry - * @entry: dentry to complete - * @inode: inode to attach to this dentry - * - * Fill in inode information in the entry. If a directory alias is found, then - * return an error (and drop inode). Together with d_materialise_unique() this - * guarantees that a directory inode may never have more than one alias. - */ -int d_instantiate_no_diralias(struct dentry *entry, struct inode *inode) -{ - BUG_ON(!hlist_unhashed(&entry->d_u.d_alias)); - - security_d_instantiate(entry, inode); - spin_lock(&inode->i_lock); - if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry)) { - spin_unlock(&inode->i_lock); - iput(inode); - return -EBUSY; - } - __d_instantiate(entry, inode); - spin_unlock(&inode->i_lock); - - return 0; -} -EXPORT_SYMBOL(d_instantiate_no_diralias); - -struct dentry *d_make_root(struct inode *root_inode) -{ - struct dentry *res = NULL; - - if (root_inode) { - res = __d_alloc(root_inode->i_sb, NULL); - if (res) - d_instantiate(res, root_inode); - else - iput(root_inode); - } - return res; -} -EXPORT_SYMBOL(d_make_root); - -static struct dentry * __d_find_any_alias(struct inode *inode) -{ - struct dentry *alias; - - if (hlist_empty(&inode->i_dentry)) - return NULL; - alias = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias); - __dget(alias); - return alias; -} - -/** - * d_find_any_alias - find any alias for a given inode - * @inode: inode to find an alias for - * - * If any aliases exist for the given inode, take and return a - * reference for one of them. If no aliases exist, return %NULL. - */ -struct dentry *d_find_any_alias(struct inode *inode) -{ - struct dentry *de; - - spin_lock(&inode->i_lock); - de = __d_find_any_alias(inode); - spin_unlock(&inode->i_lock); - return de; -} -EXPORT_SYMBOL(d_find_any_alias); - -static struct dentry *__d_obtain_alias(struct inode *inode, int disconnected) -{ - struct dentry *tmp; - struct dentry *res; - unsigned add_flags; - - if (!inode) - return ERR_PTR(-ESTALE); - if (IS_ERR(inode)) - return ERR_CAST(inode); - - res = d_find_any_alias(inode); - if (res) - goto out_iput; - - tmp = __d_alloc(inode->i_sb, NULL); - if (!tmp) { - res = ERR_PTR(-ENOMEM); - goto out_iput; - } - - security_d_instantiate(tmp, inode); - spin_lock(&inode->i_lock); - res = __d_find_any_alias(inode); - if (res) { - spin_unlock(&inode->i_lock); - dput(tmp); - goto out_iput; - } - - /* attach a disconnected dentry */ - add_flags = d_flags_for_inode(inode); - - if (disconnected) - add_flags |= DCACHE_DISCONNECTED; - - spin_lock(&tmp->d_lock); - __d_set_inode_and_type(tmp, inode, add_flags); - hlist_add_head(&tmp->d_u.d_alias, &inode->i_dentry); - hlist_bl_lock(&tmp->d_sb->s_anon); - hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon); - hlist_bl_unlock(&tmp->d_sb->s_anon); - spin_unlock(&tmp->d_lock); - spin_unlock(&inode->i_lock); - - return tmp; - - out_iput: - iput(inode); - return res; -} - -/** - * d_obtain_alias - find or allocate a DISCONNECTED dentry for a given inode - * @inode: inode to allocate the dentry for - * - * Obtain a dentry for an inode resulting from NFS filehandle conversion or - * similar open by handle operations. The returned dentry may be anonymous, - * or may have a full name (if the inode was already in the cache). - * - * When called on a directory inode, we must ensure that the inode only ever - * has one dentry. If a dentry is found, that is returned instead of - * allocating a new one. - * - * On successful return, the reference to the inode has been transferred - * to the dentry. In case of an error the reference on the inode is released. - * To make it easier to use in export operations a %NULL or IS_ERR inode may - * be passed in and the error will be propagated to the return value, - * with a %NULL @inode replaced by ERR_PTR(-ESTALE). - */ -struct dentry *d_obtain_alias(struct inode *inode) -{ - return __d_obtain_alias(inode, 1); -} -EXPORT_SYMBOL(d_obtain_alias); - -/** - * d_obtain_root - find or allocate a dentry for a given inode - * @inode: inode to allocate the dentry for - * - * Obtain an IS_ROOT dentry for the root of a filesystem. - * - * We must ensure that directory inodes only ever have one dentry. If a - * dentry is found, that is returned instead of allocating a new one. - * - * On successful return, the reference to the inode has been transferred - * to the dentry. In case of an error the reference on the inode is - * released. A %NULL or IS_ERR inode may be passed in and will be the - * error will be propagate to the return value, with a %NULL @inode - * replaced by ERR_PTR(-ESTALE). - */ -struct dentry *d_obtain_root(struct inode *inode) -{ - return __d_obtain_alias(inode, 0); -} -EXPORT_SYMBOL(d_obtain_root); - -/** - * d_add_ci - lookup or allocate new dentry with case-exact name - * @inode: the inode case-insensitive lookup has found - * @dentry: the negative dentry that was passed to the parent's lookup func - * @name: the case-exact name to be associated with the returned dentry - * - * This is to avoid filling the dcache with case-insensitive names to the - * same inode, only the actual correct case is stored in the dcache for - * case-insensitive filesystems. - * - * For a case-insensitive lookup match and if the the case-exact dentry - * already exists in in the dcache, use it and return it. - * - * If no entry exists with the exact case name, allocate new dentry with - * the exact case, and return the spliced entry. - */ -struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode, - struct qstr *name) -{ - struct dentry *found, *res; - - /* - * First check if a dentry matching the name already exists, - * if not go ahead and create it now. - */ - found = d_hash_and_lookup(dentry->d_parent, name); - if (found) { - iput(inode); - return found; - } - if (d_in_lookup(dentry)) { - found = d_alloc_parallel(dentry->d_parent, name, - dentry->d_wait); - if (IS_ERR(found) || !d_in_lookup(found)) { - iput(inode); - return found; - } - } else { - found = d_alloc(dentry->d_parent, name); - if (!found) { - iput(inode); - return ERR_PTR(-ENOMEM); - } - } - res = d_splice_alias(inode, found); - if (res) { - dput(found); - return res; - } - return found; -} -EXPORT_SYMBOL(d_add_ci); - - -static inline bool d_same_name(const struct dentry *dentry, - const struct dentry *parent, - const struct qstr *name) -{ - if (likely(!(parent->d_flags & DCACHE_OP_COMPARE))) { - if (dentry->d_name.len != name->len) - return false; - return dentry_cmp(dentry, name->name, name->len) == 0; - } - return parent->d_op->d_compare(dentry, - dentry->d_name.len, dentry->d_name.name, - name) == 0; -} - -/** - * __d_lookup_rcu - search for a dentry (racy, store-free) - * @parent: parent dentry - * @name: qstr of name we wish to find - * @seqp: returns d_seq value at the point where the dentry was found - * Returns: dentry, or NULL - * - * __d_lookup_rcu is the dcache lookup function for rcu-walk name - * resolution (store-free path walking) design described in - * Documentation/filesystems/path-lookup.txt. - * - * This is not to be used outside core vfs. - * - * __d_lookup_rcu must only be used in rcu-walk mode, ie. with vfsmount lock - * held, and rcu_read_lock held. The returned dentry must not be stored into - * without taking d_lock and checking d_seq sequence count against @seq - * returned here. - * - * A refcount may be taken on the found dentry with the d_rcu_to_refcount - * function. - * - * Alternatively, __d_lookup_rcu may be called again to look up the child of - * the returned dentry, so long as its parent's seqlock is checked after the - * child is looked up. Thus, an interlocking stepping of sequence lock checks - * is formed, giving integrity down the path walk. - * - * NOTE! The caller *has* to check the resulting dentry against the sequence - * number we've returned before using any of the resulting dentry state! - */ -struct dentry *__d_lookup_rcu(const struct dentry *parent, - const struct qstr *name, - unsigned *seqp) -{ - u64 hashlen = name->hash_len; - const unsigned char *str = name->name; - struct hlist_bl_head *b = d_hash(hashlen_hash(hashlen)); - struct hlist_bl_node *node; - struct dentry *dentry; - - /* - * Note: There is significant duplication with __d_lookup_rcu which is - * required to prevent single threaded performance regressions - * especially on architectures where smp_rmb (in seqcounts) are costly. - * Keep the two functions in sync. - */ - - /* - * The hash list is protected using RCU. - * - * Carefully use d_seq when comparing a candidate dentry, to avoid - * races with d_move(). - * - * It is possible that concurrent renames can mess up our list - * walk here and result in missing our dentry, resulting in the - * false-negative result. d_lookup() protects against concurrent - * renames using rename_lock seqlock. - * - * See Documentation/filesystems/path-lookup.txt for more details. - */ - hlist_bl_for_each_entry_rcu(dentry, node, b, d_hash) { - unsigned seq; - -seqretry: - /* - * The dentry sequence count protects us from concurrent - * renames, and thus protects parent and name fields. - * - * The caller must perform a seqcount check in order - * to do anything useful with the returned dentry. - * - * NOTE! We do a "raw" seqcount_begin here. That means that - * we don't wait for the sequence count to stabilize if it - * is in the middle of a sequence change. If we do the slow - * dentry compare, we will do seqretries until it is stable, - * and if we end up with a successful lookup, we actually - * want to exit RCU lookup anyway. - * - * Note that raw_seqcount_begin still *does* smp_rmb(), so - * we are still guaranteed NUL-termination of ->d_name.name. - */ - seq = raw_seqcount_begin(&dentry->d_seq); - if (dentry->d_parent != parent) - continue; - if (d_unhashed(dentry)) - continue; - - if (unlikely(parent->d_flags & DCACHE_OP_COMPARE)) { - int tlen; - const char *tname; - if (dentry->d_name.hash != hashlen_hash(hashlen)) - continue; - tlen = dentry->d_name.len; - tname = dentry->d_name.name; - /* we want a consistent (name,len) pair */ - if (read_seqcount_retry(&dentry->d_seq, seq)) { - cpu_relax(); - goto seqretry; - } - if (parent->d_op->d_compare(dentry, - tlen, tname, name) != 0) - continue; - } else { - if (dentry->d_name.hash_len != hashlen) - continue; - if (dentry_cmp(dentry, str, hashlen_len(hashlen)) != 0) - continue; - } - *seqp = seq; - return dentry; - } - return NULL; -} - -/** - * d_lookup - search for a dentry - * @parent: parent dentry - * @name: qstr of name we wish to find - * Returns: dentry, or NULL - * - * d_lookup searches the children of the parent dentry for the name in - * question. If the dentry is found its reference count is incremented and the - * dentry is returned. The caller must use dput to free the entry when it has - * finished using it. %NULL is returned if the dentry does not exist. - */ -struct dentry *d_lookup(const struct dentry *parent, const struct qstr *name) -{ - struct dentry *dentry; - unsigned seq; - - do { - seq = read_seqbegin(&rename_lock); - dentry = __d_lookup(parent, name); - if (dentry) - break; - } while (read_seqretry(&rename_lock, seq)); - return dentry; -} -EXPORT_SYMBOL(d_lookup); - -/** - * __d_lookup - search for a dentry (racy) - * @parent: parent dentry - * @name: qstr of name we wish to find - * Returns: dentry, or NULL - * - * __d_lookup is like d_lookup, however it may (rarely) return a - * false-negative result due to unrelated rename activity. - * - * __d_lookup is slightly faster by avoiding rename_lock read seqlock, - * however it must be used carefully, eg. with a following d_lookup in - * the case of failure. - * - * __d_lookup callers must be commented. - */ -struct dentry *__d_lookup(const struct dentry *parent, const struct qstr *name) -{ - unsigned int hash = name->hash; - struct hlist_bl_head *b = d_hash(hash); - struct hlist_bl_node *node; - struct dentry *found = NULL; - struct dentry *dentry; - - /* - * Note: There is significant duplication with __d_lookup_rcu which is - * required to prevent single threaded performance regressions - * especially on architectures where smp_rmb (in seqcounts) are costly. - * Keep the two functions in sync. - */ - - /* - * The hash list is protected using RCU. - * - * Take d_lock when comparing a candidate dentry, to avoid races - * with d_move(). - * - * It is possible that concurrent renames can mess up our list - * walk here and result in missing our dentry, resulting in the - * false-negative result. d_lookup() protects against concurrent - * renames using rename_lock seqlock. - * - * See Documentation/filesystems/path-lookup.txt for more details. - */ - rcu_read_lock(); - - hlist_bl_for_each_entry_rcu(dentry, node, b, d_hash) { - - if (dentry->d_name.hash != hash) - continue; - - spin_lock(&dentry->d_lock); - if (dentry->d_parent != parent) - goto next; - if (d_unhashed(dentry)) - goto next; - - if (!d_same_name(dentry, parent, name)) - goto next; - - dentry->d_lockref.count++; - found = dentry; - spin_unlock(&dentry->d_lock); - break; -next: - spin_unlock(&dentry->d_lock); - } - rcu_read_unlock(); - - return found; -} - -/** - * d_hash_and_lookup - hash the qstr then search for a dentry - * @dir: Directory to search in - * @name: qstr of name we wish to find - * - * On lookup failure NULL is returned; on bad name - ERR_PTR(-error) - */ -struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name) -{ - /* - * Check for a fs-specific hash function. Note that we must - * calculate the standard hash first, as the d_op->d_hash() - * routine may choose to leave the hash value unchanged. - */ - name->hash = full_name_hash(dir, name->name, name->len); - if (dir->d_flags & DCACHE_OP_HASH) { - int err = dir->d_op->d_hash(dir, name); - if (unlikely(err < 0)) - return ERR_PTR(err); - } - return d_lookup(dir, name); -} -EXPORT_SYMBOL(d_hash_and_lookup); - -/* - * When a file is deleted, we have two options: - * - turn this dentry into a negative dentry - * - unhash this dentry and free it. - * - * Usually, we want to just turn this into - * a negative dentry, but if anybody else is - * currently using the dentry or the inode - * we can't do that and we fall back on removing - * it from the hash queues and waiting for - * it to be deleted later when it has no users - */ - -/** - * d_delete - delete a dentry - * @dentry: The dentry to delete - * - * Turn the dentry into a negative dentry if possible, otherwise - * remove it from the hash queues so it can be deleted later - */ - -void d_delete(struct dentry * dentry) -{ - struct inode *inode; - int isdir = 0; - /* - * Are we the only user? - */ -again: - spin_lock(&dentry->d_lock); - inode = dentry->d_inode; - isdir = S_ISDIR(inode->i_mode); - if (dentry->d_lockref.count == 1) { - if (!spin_trylock(&inode->i_lock)) { - spin_unlock(&dentry->d_lock); - cpu_relax(); - goto again; - } - dentry->d_flags &= ~DCACHE_CANT_MOUNT; - dentry_unlink_inode(dentry); - fsnotify_nameremove(dentry, isdir); - return; - } - - if (!d_unhashed(dentry)) - __d_drop(dentry); - - spin_unlock(&dentry->d_lock); - - fsnotify_nameremove(dentry, isdir); -} -EXPORT_SYMBOL(d_delete); - -static void __d_rehash(struct dentry *entry) -{ - struct hlist_bl_head *b = d_hash(entry->d_name.hash); - BUG_ON(!d_unhashed(entry)); - hlist_bl_lock(b); - hlist_bl_add_head_rcu(&entry->d_hash, b); - hlist_bl_unlock(b); -} - -/** - * d_rehash - add an entry back to the hash - * @entry: dentry to add to the hash - * - * Adds a dentry to the hash according to its name. - */ - -void d_rehash(struct dentry * entry) -{ - spin_lock(&entry->d_lock); - __d_rehash(entry); - spin_unlock(&entry->d_lock); -} -EXPORT_SYMBOL(d_rehash); - -static inline unsigned start_dir_add(struct inode *dir) -{ - - for (;;) { - unsigned n = dir->i_dir_seq; - if (!(n & 1) && cmpxchg(&dir->i_dir_seq, n, n + 1) == n) - return n; - cpu_relax(); - } -} - -static inline void end_dir_add(struct inode *dir, unsigned n) -{ - smp_store_release(&dir->i_dir_seq, n + 2); -} - -static void d_wait_lookup(struct dentry *dentry) -{ - if (d_in_lookup(dentry)) { - DECLARE_WAITQUEUE(wait, current); - add_wait_queue(dentry->d_wait, &wait); - do { - set_current_state(TASK_UNINTERRUPTIBLE); - spin_unlock(&dentry->d_lock); - schedule(); - spin_lock(&dentry->d_lock); - } while (d_in_lookup(dentry)); - } -} - -struct dentry *d_alloc_parallel(struct dentry *parent, - const struct qstr *name, - wait_queue_head_t *wq) -{ - unsigned int hash = name->hash; - struct hlist_bl_head *b = in_lookup_hash(parent, hash); - struct hlist_bl_node *node; - struct dentry *new = d_alloc(parent, name); - struct dentry *dentry; - unsigned seq, r_seq, d_seq; - - if (unlikely(!new)) - return ERR_PTR(-ENOMEM); - -retry: - rcu_read_lock(); - seq = smp_load_acquire(&parent->d_inode->i_dir_seq) & ~1; - r_seq = read_seqbegin(&rename_lock); - dentry = __d_lookup_rcu(parent, name, &d_seq); - if (unlikely(dentry)) { - if (!lockref_get_not_dead(&dentry->d_lockref)) { - rcu_read_unlock(); - goto retry; - } - if (read_seqcount_retry(&dentry->d_seq, d_seq)) { - rcu_read_unlock(); - dput(dentry); - goto retry; - } - rcu_read_unlock(); - dput(new); - return dentry; - } - if (unlikely(read_seqretry(&rename_lock, r_seq))) { - rcu_read_unlock(); - goto retry; - } - hlist_bl_lock(b); - if (unlikely(parent->d_inode->i_dir_seq != seq)) { - hlist_bl_unlock(b); - rcu_read_unlock(); - goto retry; - } - /* - * No changes for the parent since the beginning of d_lookup(). - * Since all removals from the chain happen with hlist_bl_lock(), - * any potential in-lookup matches are going to stay here until - * we unlock the chain. All fields are stable in everything - * we encounter. - */ - hlist_bl_for_each_entry(dentry, node, b, d_u.d_in_lookup_hash) { - if (dentry->d_name.hash != hash) - continue; - if (dentry->d_parent != parent) - continue; - if (!d_same_name(dentry, parent, name)) - continue; - hlist_bl_unlock(b); - /* now we can try to grab a reference */ - if (!lockref_get_not_dead(&dentry->d_lockref)) { - rcu_read_unlock(); - goto retry; - } - - rcu_read_unlock(); - /* - * somebody is likely to be still doing lookup for it; - * wait for them to finish - */ - spin_lock(&dentry->d_lock); - d_wait_lookup(dentry); - /* - * it's not in-lookup anymore; in principle we should repeat - * everything from dcache lookup, but it's likely to be what - * d_lookup() would've found anyway. If it is, just return it; - * otherwise we really have to repeat the whole thing. - */ - if (unlikely(dentry->d_name.hash != hash)) - goto mismatch; - if (unlikely(dentry->d_parent != parent)) - goto mismatch; - if (unlikely(d_unhashed(dentry))) - goto mismatch; - if (unlikely(!d_same_name(dentry, parent, name))) - goto mismatch; - /* OK, it *is* a hashed match; return it */ - spin_unlock(&dentry->d_lock); - dput(new); - return dentry; - } - rcu_read_unlock(); - /* we can't take ->d_lock here; it's OK, though. */ - new->d_flags |= DCACHE_PAR_LOOKUP; - new->d_wait = wq; - hlist_bl_add_head_rcu(&new->d_u.d_in_lookup_hash, b); - hlist_bl_unlock(b); - return new; -mismatch: - spin_unlock(&dentry->d_lock); - dput(dentry); - goto retry; -} -EXPORT_SYMBOL(d_alloc_parallel); - -void __d_lookup_done(struct dentry *dentry) -{ - struct hlist_bl_head *b = in_lookup_hash(dentry->d_parent, - dentry->d_name.hash); - hlist_bl_lock(b); - dentry->d_flags &= ~DCACHE_PAR_LOOKUP; - __hlist_bl_del(&dentry->d_u.d_in_lookup_hash); - wake_up_all(dentry->d_wait); - dentry->d_wait = NULL; - hlist_bl_unlock(b); - INIT_HLIST_NODE(&dentry->d_u.d_alias); - INIT_LIST_HEAD(&dentry->d_lru); -} -EXPORT_SYMBOL(__d_lookup_done); - -/* inode->i_lock held if inode is non-NULL */ - -static inline void __d_add(struct dentry *dentry, struct inode *inode) -{ - struct inode *dir = NULL; - unsigned n; - spin_lock(&dentry->d_lock); - if (unlikely(d_in_lookup(dentry))) { - dir = dentry->d_parent->d_inode; - n = start_dir_add(dir); - __d_lookup_done(dentry); - } - if (inode) { - unsigned add_flags = d_flags_for_inode(inode); - hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry); - raw_write_seqcount_begin(&dentry->d_seq); - __d_set_inode_and_type(dentry, inode, add_flags); - raw_write_seqcount_end(&dentry->d_seq); - fsnotify_update_flags(dentry); - } - __d_rehash(dentry); - if (dir) - end_dir_add(dir, n); - spin_unlock(&dentry->d_lock); - if (inode) - spin_unlock(&inode->i_lock); -} - -/** - * d_add - add dentry to hash queues - * @entry: dentry to add - * @inode: The inode to attach to this dentry - * - * This adds the entry to the hash queues and initializes @inode. - * The entry was actually filled in earlier during d_alloc(). - */ - -void d_add(struct dentry *entry, struct inode *inode) -{ - if (inode) { - security_d_instantiate(entry, inode); - spin_lock(&inode->i_lock); - } - __d_add(entry, inode); -} -EXPORT_SYMBOL(d_add); - -/** - * d_exact_alias - find and hash an exact unhashed alias - * @entry: dentry to add - * @inode: The inode to go with this dentry - * - * If an unhashed dentry with the same name/parent and desired - * inode already exists, hash and return it. Otherwise, return - * NULL. - * - * Parent directory should be locked. - */ -struct dentry *d_exact_alias(struct dentry *entry, struct inode *inode) -{ - struct dentry *alias; - unsigned int hash = entry->d_name.hash; - - spin_lock(&inode->i_lock); - hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { - /* - * Don't need alias->d_lock here, because aliases with - * d_parent == entry->d_parent are not subject to name or - * parent changes, because the parent inode i_mutex is held. - */ - if (alias->d_name.hash != hash) - continue; - if (alias->d_parent != entry->d_parent) - continue; - if (!d_same_name(alias, entry->d_parent, &entry->d_name)) - continue; - spin_lock(&alias->d_lock); - if (!d_unhashed(alias)) { - spin_unlock(&alias->d_lock); - alias = NULL; - } else { - __dget_dlock(alias); - __d_rehash(alias); - spin_unlock(&alias->d_lock); - } - spin_unlock(&inode->i_lock); - return alias; - } - spin_unlock(&inode->i_lock); - return NULL; -} -EXPORT_SYMBOL(d_exact_alias); - -/** - * dentry_update_name_case - update case insensitive dentry with a new name - * @dentry: dentry to be updated - * @name: new name - * - * Update a case insensitive dentry with new case of name. - * - * dentry must have been returned by d_lookup with name @name. Old and new - * name lengths must match (ie. no d_compare which allows mismatched name - * lengths). - * - * Parent inode i_mutex must be held over d_lookup and into this call (to - * keep renames and concurrent inserts, and readdir(2) away). - */ -void dentry_update_name_case(struct dentry *dentry, const struct qstr *name) -{ - BUG_ON(!inode_is_locked(dentry->d_parent->d_inode)); - BUG_ON(dentry->d_name.len != name->len); /* d_lookup gives this */ - - spin_lock(&dentry->d_lock); - write_seqcount_begin(&dentry->d_seq); - memcpy((unsigned char *)dentry->d_name.name, name->name, name->len); - write_seqcount_end(&dentry->d_seq); - spin_unlock(&dentry->d_lock); -} -EXPORT_SYMBOL(dentry_update_name_case); - -static void swap_names(struct dentry *dentry, struct dentry *target) -{ - if (unlikely(dname_external(target))) { - if (unlikely(dname_external(dentry))) { - /* - * Both external: swap the pointers - */ - swap(target->d_name.name, dentry->d_name.name); - } else { - /* - * dentry:internal, target:external. Steal target's - * storage and make target internal. - */ - memcpy(target->d_iname, dentry->d_name.name, - dentry->d_name.len + 1); - dentry->d_name.name = target->d_name.name; - target->d_name.name = target->d_iname; - } - } else { - if (unlikely(dname_external(dentry))) { - /* - * dentry:external, target:internal. Give dentry's - * storage to target and make dentry internal - */ - memcpy(dentry->d_iname, target->d_name.name, - target->d_name.len + 1); - target->d_name.name = dentry->d_name.name; - dentry->d_name.name = dentry->d_iname; - } else { - /* - * Both are internal. - */ - unsigned int i; - BUILD_BUG_ON(!IS_ALIGNED(DNAME_INLINE_LEN, sizeof(long))); - kmemcheck_mark_initialized(dentry->d_iname, DNAME_INLINE_LEN); - kmemcheck_mark_initialized(target->d_iname, DNAME_INLINE_LEN); - for (i = 0; i < DNAME_INLINE_LEN / sizeof(long); i++) { - swap(((long *) &dentry->d_iname)[i], - ((long *) &target->d_iname)[i]); - } - } - } - swap(dentry->d_name.hash_len, target->d_name.hash_len); -} - -static void copy_name(struct dentry *dentry, struct dentry *target) -{ - struct external_name *old_name = NULL; - if (unlikely(dname_external(dentry))) - old_name = external_name(dentry); - if (unlikely(dname_external(target))) { - atomic_inc(&external_name(target)->u.count); - dentry->d_name = target->d_name; - } else { - memcpy(dentry->d_iname, target->d_name.name, - target->d_name.len + 1); - dentry->d_name.name = dentry->d_iname; - dentry->d_name.hash_len = target->d_name.hash_len; - } - if (old_name && likely(atomic_dec_and_test(&old_name->u.count))) - kfree_rcu(old_name, u.head); -} - -static void dentry_lock_for_move(struct dentry *dentry, struct dentry *target) -{ - /* - * XXXX: do we really need to take target->d_lock? - */ - if (IS_ROOT(dentry) || dentry->d_parent == target->d_parent) - spin_lock(&target->d_parent->d_lock); - else { - if (d_ancestor(dentry->d_parent, target->d_parent)) { - spin_lock(&dentry->d_parent->d_lock); - spin_lock_nested(&target->d_parent->d_lock, - DENTRY_D_LOCK_NESTED); - } else { - spin_lock(&target->d_parent->d_lock); - spin_lock_nested(&dentry->d_parent->d_lock, - DENTRY_D_LOCK_NESTED); - } - } - if (target < dentry) { - spin_lock_nested(&target->d_lock, 2); - spin_lock_nested(&dentry->d_lock, 3); - } else { - spin_lock_nested(&dentry->d_lock, 2); - spin_lock_nested(&target->d_lock, 3); - } -} - -static void dentry_unlock_for_move(struct dentry *dentry, struct dentry *target) -{ - if (target->d_parent != dentry->d_parent) - spin_unlock(&dentry->d_parent->d_lock); - if (target->d_parent != target) - spin_unlock(&target->d_parent->d_lock); - spin_unlock(&target->d_lock); - spin_unlock(&dentry->d_lock); -} - -/* - * When switching names, the actual string doesn't strictly have to - * be preserved in the target - because we're dropping the target - * anyway. As such, we can just do a simple memcpy() to copy over - * the new name before we switch, unless we are going to rehash - * it. Note that if we *do* unhash the target, we are not allowed - * to rehash it without giving it a new name/hash key - whether - * we swap or overwrite the names here, resulting name won't match - * the reality in filesystem; it's only there for d_path() purposes. - * Note that all of this is happening under rename_lock, so the - * any hash lookup seeing it in the middle of manipulations will - * be discarded anyway. So we do not care what happens to the hash - * key in that case. - */ -/* - * __d_move - move a dentry - * @dentry: entry to move - * @target: new dentry - * @exchange: exchange the two dentries - * - * Update the dcache to reflect the move of a file name. Negative - * dcache entries should not be moved in this way. Caller must hold - * rename_lock, the i_mutex of the source and target directories, - * and the sb->s_vfs_rename_mutex if they differ. See lock_rename(). - */ -static void __d_move(struct dentry *dentry, struct dentry *target, - bool exchange) -{ - struct inode *dir = NULL; - unsigned n; - if (!dentry->d_inode) - printk(KERN_WARNING "VFS: moving negative dcache entry\n"); - - BUG_ON(d_ancestor(dentry, target)); - BUG_ON(d_ancestor(target, dentry)); - - dentry_lock_for_move(dentry, target); - if (unlikely(d_in_lookup(target))) { - dir = target->d_parent->d_inode; - n = start_dir_add(dir); - __d_lookup_done(target); - } - - write_seqcount_begin(&dentry->d_seq); - write_seqcount_begin_nested(&target->d_seq, DENTRY_D_LOCK_NESTED); - - /* unhash both */ - /* __d_drop does write_seqcount_barrier, but they're OK to nest. */ - __d_drop(dentry); - __d_drop(target); - - /* Switch the names.. */ - if (exchange) - swap_names(dentry, target); - else - copy_name(dentry, target); - - /* rehash in new place(s) */ - __d_rehash(dentry); - if (exchange) - __d_rehash(target); - - /* ... and switch them in the tree */ - if (IS_ROOT(dentry)) { - /* splicing a tree */ - dentry->d_flags |= DCACHE_RCUACCESS; - dentry->d_parent = target->d_parent; - target->d_parent = target; - list_del_init(&target->d_child); - list_move(&dentry->d_child, &dentry->d_parent->d_subdirs); - } else { - /* swapping two dentries */ - swap(dentry->d_parent, target->d_parent); - list_move(&target->d_child, &target->d_parent->d_subdirs); - list_move(&dentry->d_child, &dentry->d_parent->d_subdirs); - if (exchange) - fsnotify_update_flags(target); - fsnotify_update_flags(dentry); - } - - write_seqcount_end(&target->d_seq); - write_seqcount_end(&dentry->d_seq); - - if (dir) - end_dir_add(dir, n); - dentry_unlock_for_move(dentry, target); -} - -/* - * d_move - move a dentry - * @dentry: entry to move - * @target: new dentry - * - * Update the dcache to reflect the move of a file name. Negative - * dcache entries should not be moved in this way. See the locking - * requirements for __d_move. - */ -void d_move(struct dentry *dentry, struct dentry *target) -{ - write_seqlock(&rename_lock); - __d_move(dentry, target, false); - write_sequnlock(&rename_lock); -} -EXPORT_SYMBOL(d_move); - -/* - * d_exchange - exchange two dentries - * @dentry1: first dentry - * @dentry2: second dentry - */ -void d_exchange(struct dentry *dentry1, struct dentry *dentry2) -{ - write_seqlock(&rename_lock); - - WARN_ON(!dentry1->d_inode); - WARN_ON(!dentry2->d_inode); - WARN_ON(IS_ROOT(dentry1)); - WARN_ON(IS_ROOT(dentry2)); - - __d_move(dentry1, dentry2, true); - - write_sequnlock(&rename_lock); -} - -/** - * d_ancestor - search for an ancestor - * @p1: ancestor dentry - * @p2: child dentry - * - * Returns the ancestor dentry of p2 which is a child of p1, if p1 is - * an ancestor of p2, else NULL. - */ -struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2) -{ - struct dentry *p; - - for (p = p2; !IS_ROOT(p); p = p->d_parent) { - if (p->d_parent == p1) - return p; - } - return NULL; -} - -/* - * This helper attempts to cope with remotely renamed directories - * - * It assumes that the caller is already holding - * dentry->d_parent->d_inode->i_mutex, and rename_lock - * - * Note: If ever the locking in lock_rename() changes, then please - * remember to update this too... - */ -static int __d_unalias(struct inode *inode, - struct dentry *dentry, struct dentry *alias) -{ - struct mutex *m1 = NULL; - struct rw_semaphore *m2 = NULL; - int ret = -ESTALE; - - /* If alias and dentry share a parent, then no extra locks required */ - if (alias->d_parent == dentry->d_parent) - goto out_unalias; - - /* See lock_rename() */ - if (!mutex_trylock(&dentry->d_sb->s_vfs_rename_mutex)) - goto out_err; - m1 = &dentry->d_sb->s_vfs_rename_mutex; - if (!inode_trylock_shared(alias->d_parent->d_inode)) - goto out_err; - m2 = &alias->d_parent->d_inode->i_rwsem; -out_unalias: - __d_move(alias, dentry, false); - ret = 0; -out_err: - if (m2) - up_read(m2); - if (m1) - mutex_unlock(m1); - return ret; -} - -/** - * d_splice_alias - splice a disconnected dentry into the tree if one exists - * @inode: the inode which may have a disconnected dentry - * @dentry: a negative dentry which we want to point to the inode. - * - * If inode is a directory and has an IS_ROOT alias, then d_move that in - * place of the given dentry and return it, else simply d_add the inode - * to the dentry and return NULL. - * - * If a non-IS_ROOT directory is found, the filesystem is corrupt, and - * we should error out: directories can't have multiple aliases. - * - * This is needed in the lookup routine of any filesystem that is exportable - * (via knfsd) so that we can build dcache paths to directories effectively. - * - * If a dentry was found and moved, then it is returned. Otherwise NULL - * is returned. This matches the expected return value of ->lookup. - * - * Cluster filesystems may call this function with a negative, hashed dentry. - * In that case, we know that the inode will be a regular file, and also this - * will only occur during atomic_open. So we need to check for the dentry - * being already hashed only in the final case. - */ -struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry) -{ - if (IS_ERR(inode)) - return ERR_CAST(inode); - - BUG_ON(!d_unhashed(dentry)); - - if (!inode) - goto out; - - security_d_instantiate(dentry, inode); - spin_lock(&inode->i_lock); - if (S_ISDIR(inode->i_mode)) { - struct dentry *new = __d_find_any_alias(inode); - if (unlikely(new)) { - /* The reference to new ensures it remains an alias */ - spin_unlock(&inode->i_lock); - write_seqlock(&rename_lock); - if (unlikely(d_ancestor(new, dentry))) { - write_sequnlock(&rename_lock); - dput(new); - new = ERR_PTR(-ELOOP); - pr_warn_ratelimited( - "VFS: Lookup of '%s' in %s %s" - " would have caused loop\n", - dentry->d_name.name, - inode->i_sb->s_type->name, - inode->i_sb->s_id); - } else if (!IS_ROOT(new)) { - int err = __d_unalias(inode, dentry, new); - write_sequnlock(&rename_lock); - if (err) { - dput(new); - new = ERR_PTR(err); - } - } else { - __d_move(new, dentry, false); - write_sequnlock(&rename_lock); - } - iput(inode); - return new; - } - } -out: - __d_add(dentry, inode); - return NULL; -} -EXPORT_SYMBOL(d_splice_alias); - -static int prepend(char **buffer, int *buflen, const char *str, int namelen) -{ - *buflen -= namelen; - if (*buflen < 0) - return -ENAMETOOLONG; - *buffer -= namelen; - memcpy(*buffer, str, namelen); - return 0; -} - -/** - * prepend_name - prepend a pathname in front of current buffer pointer - * @buffer: buffer pointer - * @buflen: allocated length of the buffer - * @name: name string and length qstr structure - * - * With RCU path tracing, it may race with d_move(). Use ACCESS_ONCE() to - * make sure that either the old or the new name pointer and length are - * fetched. However, there may be mismatch between length and pointer. - * The length cannot be trusted, we need to copy it byte-by-byte until - * the length is reached or a null byte is found. It also prepends "/" at - * the beginning of the name. The sequence number check at the caller will - * retry it again when a d_move() does happen. So any garbage in the buffer - * due to mismatched pointer and length will be discarded. - * - * Data dependency barrier is needed to make sure that we see that terminating - * NUL. Alpha strikes again, film at 11... - */ -static int prepend_name(char **buffer, int *buflen, const struct qstr *name) -{ - const char *dname = ACCESS_ONCE(name->name); - u32 dlen = ACCESS_ONCE(name->len); - char *p; - - smp_read_barrier_depends(); - - *buflen -= dlen + 1; - if (*buflen < 0) - return -ENAMETOOLONG; - p = *buffer -= dlen + 1; - *p++ = '/'; - while (dlen--) { - char c = *dname++; - if (!c) - break; - *p++ = c; - } - return 0; -} - -/** - * prepend_path - Prepend path string to a buffer - * @path: the dentry/vfsmount to report - * @root: root vfsmnt/dentry - * @buffer: pointer to the end of the buffer - * @buflen: pointer to buffer length - * - * The function will first try to write out the pathname without taking any - * lock other than the RCU read lock to make sure that dentries won't go away. - * It only checks the sequence number of the global rename_lock as any change - * in the dentry's d_seq will be preceded by changes in the rename_lock - * sequence number. If the sequence number had been changed, it will restart - * the whole pathname back-tracing sequence again by taking the rename_lock. - * In this case, there is no need to take the RCU read lock as the recursive - * parent pointer references will keep the dentry chain alive as long as no - * rename operation is performed. - */ -static int prepend_path(const struct path *path, - const struct path *root, - char **buffer, int *buflen) -{ - struct dentry *dentry; - struct vfsmount *vfsmnt; - struct mount *mnt; - int error = 0; - unsigned seq, m_seq = 0; - char *bptr; - int blen; - - rcu_read_lock(); -restart_mnt: - read_seqbegin_or_lock(&mount_lock, &m_seq); - seq = 0; - rcu_read_lock(); -restart: - bptr = *buffer; - blen = *buflen; - error = 0; - dentry = path->dentry; - vfsmnt = path->mnt; - mnt = real_mount(vfsmnt); - read_seqbegin_or_lock(&rename_lock, &seq); - while (dentry != root->dentry || vfsmnt != root->mnt) { - struct dentry * parent; - - if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { - struct mount *parent = ACCESS_ONCE(mnt->mnt_parent); - /* Escaped? */ - if (dentry != vfsmnt->mnt_root) { - bptr = *buffer; - blen = *buflen; - error = 3; - break; - } - /* Global root? */ - if (mnt != parent) { - dentry = ACCESS_ONCE(mnt->mnt_mountpoint); - mnt = parent; - vfsmnt = &mnt->mnt; - continue; - } - if (!error) - error = is_mounted(vfsmnt) ? 1 : 2; - break; - } - parent = dentry->d_parent; - prefetch(parent); - error = prepend_name(&bptr, &blen, &dentry->d_name); - if (error) - break; - - dentry = parent; - } - if (!(seq & 1)) - rcu_read_unlock(); - if (need_seqretry(&rename_lock, seq)) { - seq = 1; - goto restart; - } - done_seqretry(&rename_lock, seq); - - if (!(m_seq & 1)) - rcu_read_unlock(); - if (need_seqretry(&mount_lock, m_seq)) { - m_seq = 1; - goto restart_mnt; - } - done_seqretry(&mount_lock, m_seq); - - if (error >= 0 && bptr == *buffer) { - if (--blen < 0) - error = -ENAMETOOLONG; - else - *--bptr = '/'; - } - *buffer = bptr; - *buflen = blen; - return error; -} - -/** - * __d_path - return the path of a dentry - * @path: the dentry/vfsmount to report - * @root: root vfsmnt/dentry - * @buf: buffer to return value in - * @buflen: buffer length - * - * Convert a dentry into an ASCII path name. - * - * Returns a pointer into the buffer or an error code if the - * path was too long. - * - * "buflen" should be positive. - * - * If the path is not reachable from the supplied root, return %NULL. - */ -char *__d_path(const struct path *path, - const struct path *root, - char *buf, int buflen) -{ - char *res = buf + buflen; - int error; - - prepend(&res, &buflen, "\0", 1); - error = prepend_path(path, root, &res, &buflen); - - if (error < 0) - return ERR_PTR(error); - if (error > 0) - return NULL; - return res; -} - -char *d_absolute_path(const struct path *path, - char *buf, int buflen) -{ - struct path root = {}; - char *res = buf + buflen; - int error; - - prepend(&res, &buflen, "\0", 1); - error = prepend_path(path, &root, &res, &buflen); - - if (error > 1) - error = -EINVAL; - if (error < 0) - return ERR_PTR(error); - return res; -} - -/* - * same as __d_path but appends "(deleted)" for unlinked files. - */ -static int path_with_deleted(const struct path *path, - const struct path *root, - char **buf, int *buflen) -{ - prepend(buf, buflen, "\0", 1); - if (d_unlinked(path->dentry)) { - int error = prepend(buf, buflen, " (deleted)", 10); - if (error) - return error; - } - - return prepend_path(path, root, buf, buflen); -} - -static int prepend_unreachable(char **buffer, int *buflen) -{ - return prepend(buffer, buflen, "(unreachable)", 13); -} - -static void get_fs_root_rcu(struct fs_struct *fs, struct path *root) -{ - unsigned seq; - - do { - seq = read_seqcount_begin(&fs->seq); - *root = fs->root; - } while (read_seqcount_retry(&fs->seq, seq)); -} - -/** - * d_path - return the path of a dentry - * @path: path to report - * @buf: buffer to return value in - * @buflen: buffer length - * - * Convert a dentry into an ASCII path name. If the entry has been deleted - * the string " (deleted)" is appended. Note that this is ambiguous. - * - * Returns a pointer into the buffer or an error code if the path was - * too long. Note: Callers should use the returned pointer, not the passed - * in buffer, to use the name! The implementation often starts at an offset - * into the buffer, and may leave 0 bytes at the start. - * - * "buflen" should be positive. - */ -char *d_path(const struct path *path, char *buf, int buflen) -{ - char *res = buf + buflen; - struct path root; - int error; - - /* - * We have various synthetic filesystems that never get mounted. On - * these filesystems dentries are never used for lookup purposes, and - * thus don't need to be hashed. They also don't need a name until a - * user wants to identify the object in /proc/pid/fd/. The little hack - * below allows us to generate a name for these objects on demand: - * - * Some pseudo inodes are mountable. When they are mounted - * path->dentry == path->mnt->mnt_root. In that case don't call d_dname - * and instead have d_path return the mounted path. - */ - if (path->dentry->d_op && path->dentry->d_op->d_dname && - (!IS_ROOT(path->dentry) || path->dentry != path->mnt->mnt_root)) - return path->dentry->d_op->d_dname(path->dentry, buf, buflen); - - rcu_read_lock(); - get_fs_root_rcu(current->fs, &root); - error = path_with_deleted(path, &root, &res, &buflen); - rcu_read_unlock(); - - if (error < 0) - res = ERR_PTR(error); - return res; -} -EXPORT_SYMBOL(d_path); - -/* - * Helper function for dentry_operations.d_dname() members - */ -char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen, - const char *fmt, ...) -{ - va_list args; - char temp[64]; - int sz; - - va_start(args, fmt); - sz = vsnprintf(temp, sizeof(temp), fmt, args) + 1; - va_end(args); - - if (sz > sizeof(temp) || sz > buflen) - return ERR_PTR(-ENAMETOOLONG); - - buffer += buflen - sz; - return memcpy(buffer, temp, sz); -} - -char *simple_dname(struct dentry *dentry, char *buffer, int buflen) -{ - char *end = buffer + buflen; - /* these dentries are never renamed, so d_lock is not needed */ - if (prepend(&end, &buflen, " (deleted)", 11) || - prepend(&end, &buflen, dentry->d_name.name, dentry->d_name.len) || - prepend(&end, &buflen, "/", 1)) - end = ERR_PTR(-ENAMETOOLONG); - return end; -} -EXPORT_SYMBOL(simple_dname); - -/* - * Write full pathname from the root of the filesystem into the buffer. - */ -static char *__dentry_path(struct dentry *d, char *buf, int buflen) -{ - struct dentry *dentry; - char *end, *retval; - int len, seq = 0; - int error = 0; - - if (buflen < 2) - goto Elong; - - rcu_read_lock(); -restart: - dentry = d; - end = buf + buflen; - len = buflen; - prepend(&end, &len, "\0", 1); - /* Get '/' right */ - retval = end-1; - *retval = '/'; - read_seqbegin_or_lock(&rename_lock, &seq); - while (!IS_ROOT(dentry)) { - struct dentry *parent = dentry->d_parent; - - prefetch(parent); - error = prepend_name(&end, &len, &dentry->d_name); - if (error) - break; - - retval = end; - dentry = parent; - } - if (!(seq & 1)) - rcu_read_unlock(); - if (need_seqretry(&rename_lock, seq)) { - seq = 1; - goto restart; - } - done_seqretry(&rename_lock, seq); - if (error) - goto Elong; - return retval; -Elong: - return ERR_PTR(-ENAMETOOLONG); -} - -char *dentry_path_raw(struct dentry *dentry, char *buf, int buflen) -{ - return __dentry_path(dentry, buf, buflen); -} -EXPORT_SYMBOL(dentry_path_raw); - -char *dentry_path(struct dentry *dentry, char *buf, int buflen) -{ - char *p = NULL; - char *retval; - - if (d_unlinked(dentry)) { - p = buf + buflen; - if (prepend(&p, &buflen, "//deleted", 10) != 0) - goto Elong; - buflen++; - } - retval = __dentry_path(dentry, buf, buflen); - if (!IS_ERR(retval) && p) - *p = '/'; /* restore '/' overriden with '\0' */ - return retval; -Elong: - return ERR_PTR(-ENAMETOOLONG); -} - -static void get_fs_root_and_pwd_rcu(struct fs_struct *fs, struct path *root, - struct path *pwd) -{ - unsigned seq; - - do { - seq = read_seqcount_begin(&fs->seq); - *root = fs->root; - *pwd = fs->pwd; - } while (read_seqcount_retry(&fs->seq, seq)); -} - -/* - * NOTE! The user-level library version returns a - * character pointer. The kernel system call just - * returns the length of the buffer filled (which - * includes the ending '\0' character), or a negative - * error value. So libc would do something like - * - * char *getcwd(char * buf, size_t size) - * { - * int retval; - * - * retval = sys_getcwd(buf, size); - * if (retval >= 0) - * return buf; - * errno = -retval; - * return NULL; - * } - */ -SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) -{ - int error; - struct path pwd, root; - char *page = __getname(); - - if (!page) - return -ENOMEM; - - rcu_read_lock(); - get_fs_root_and_pwd_rcu(current->fs, &root, &pwd); - - error = -ENOENT; - if (!d_unlinked(pwd.dentry)) { - unsigned long len; - char *cwd = page + PATH_MAX; - int buflen = PATH_MAX; - - prepend(&cwd, &buflen, "\0", 1); - error = prepend_path(&pwd, &root, &cwd, &buflen); - rcu_read_unlock(); - - if (error < 0) - goto out; - - /* Unreachable from current root */ - if (error > 0) { - error = prepend_unreachable(&cwd, &buflen); - if (error) - goto out; - } - - error = -ERANGE; - len = PATH_MAX + page - cwd; - if (len <= size) { - error = len; - if (copy_to_user(buf, cwd, len)) - error = -EFAULT; - } - } else { - rcu_read_unlock(); - } - -out: - __putname(page); - return error; -} - -/* - * Test whether new_dentry is a subdirectory of old_dentry. - * - * Trivially implemented using the dcache structure - */ - -/** - * is_subdir - is new dentry a subdirectory of old_dentry - * @new_dentry: new dentry - * @old_dentry: old dentry - * - * Returns true if new_dentry is a subdirectory of the parent (at any depth). - * Returns false otherwise. - * Caller must ensure that "new_dentry" is pinned before calling is_subdir() - */ - -bool is_subdir(struct dentry *new_dentry, struct dentry *old_dentry) -{ - bool result; - unsigned seq; - - if (new_dentry == old_dentry) - return true; - - do { - /* for restarting inner loop in case of seq retry */ - seq = read_seqbegin(&rename_lock); - /* - * Need rcu_readlock to protect against the d_parent trashing - * due to d_move - */ - rcu_read_lock(); - if (d_ancestor(old_dentry, new_dentry)) - result = true; - else - result = false; - rcu_read_unlock(); - } while (read_seqretry(&rename_lock, seq)); - - return result; -} - -static enum d_walk_ret d_genocide_kill(void *data, struct dentry *dentry) -{ - struct dentry *root = data; - if (dentry != root) { - if (d_unhashed(dentry) || !dentry->d_inode) - return D_WALK_SKIP; - - if (!(dentry->d_flags & DCACHE_GENOCIDE)) { - dentry->d_flags |= DCACHE_GENOCIDE; - dentry->d_lockref.count--; - } - } - return D_WALK_CONTINUE; -} - -void d_genocide(struct dentry *parent) -{ - d_walk(parent, parent, d_genocide_kill, NULL); -} - -void d_tmpfile(struct dentry *dentry, struct inode *inode) -{ - inode_dec_link_count(inode); - BUG_ON(dentry->d_name.name != dentry->d_iname || - !hlist_unhashed(&dentry->d_u.d_alias) || - !d_unlinked(dentry)); - spin_lock(&dentry->d_parent->d_lock); - spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); - dentry->d_name.len = sprintf(dentry->d_iname, "#%llu", - (unsigned long long)inode->i_ino); - spin_unlock(&dentry->d_lock); - spin_unlock(&dentry->d_parent->d_lock); - d_instantiate(dentry, inode); -} -EXPORT_SYMBOL(d_tmpfile); - -static __initdata unsigned long dhash_entries; -static int __init set_dhash_entries(char *str) -{ - if (!str) - return 0; - dhash_entries = simple_strtoul(str, &str, 0); - return 1; -} -__setup("dhash_entries=", set_dhash_entries); - -static void __init dcache_init_early(void) -{ - unsigned int loop; - - /* If hashes are distributed across NUMA nodes, defer - * hash allocation until vmalloc space is available. - */ - if (hashdist) - return; - - dentry_hashtable = - alloc_large_system_hash("Dentry cache", - sizeof(struct hlist_bl_head), - dhash_entries, - 13, - HASH_EARLY, - &d_hash_shift, - &d_hash_mask, - 0, - 0); - - for (loop = 0; loop < (1U << d_hash_shift); loop++) - INIT_HLIST_BL_HEAD(dentry_hashtable + loop); -} - -static void __init dcache_init(void) -{ - unsigned int loop; - - /* - * A constructor could be added for stable state like the lists, - * but it is probably not worth it because of the cache nature - * of the dcache. - */ - dentry_cache = KMEM_CACHE(dentry, - SLAB_RECLAIM_ACCOUNT|SLAB_PANIC|SLAB_MEM_SPREAD|SLAB_ACCOUNT); - - /* Hash may have been set up in dcache_init_early */ - if (!hashdist) - return; - - dentry_hashtable = - alloc_large_system_hash("Dentry cache", - sizeof(struct hlist_bl_head), - dhash_entries, - 13, - 0, - &d_hash_shift, - &d_hash_mask, - 0, - 0); - - for (loop = 0; loop < (1U << d_hash_shift); loop++) - INIT_HLIST_BL_HEAD(dentry_hashtable + loop); -} - -/* SLAB cache for __getname() consumers */ -struct kmem_cache *names_cachep __read_mostly; -EXPORT_SYMBOL(names_cachep); - -EXPORT_SYMBOL(d_genocide); - -void __init vfs_caches_init_early(void) -{ - dcache_init_early(); - inode_init_early(); -} - -void __init vfs_caches_init(void) -{ - names_cachep = kmem_cache_create("names_cache", PATH_MAX, 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); - - dcache_init(); - inode_init(); - files_init(); - files_maxfiles_init(); - mnt_init(); - bdev_cache_init(); - chrdev_init(); -} diff --git a/src/linux/fs/devpts/Makefile b/src/linux/fs/devpts/Makefile deleted file mode 100644 index 236696e..0000000 --- a/src/linux/fs/devpts/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for the Linux /dev/pts virtual filesystem. -# - -obj-$(CONFIG_UNIX98_PTYS) += devpts.o - -devpts-$(CONFIG_UNIX98_PTYS) := inode.o diff --git a/src/linux/fs/devpts/inode.c b/src/linux/fs/devpts/inode.c deleted file mode 100644 index 108df2e..0000000 --- a/src/linux/fs/devpts/inode.c +++ /dev/null @@ -1,598 +0,0 @@ -/* -*- linux-c -*- --------------------------------------------------------- * - * - * linux/fs/devpts/inode.c - * - * Copyright 1998-2004 H. Peter Anvin -- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * ------------------------------------------------------------------------- */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEVPTS_DEFAULT_MODE 0600 -/* - * ptmx is a new node in /dev/pts and will be unused in legacy (single- - * instance) mode. To prevent surprises in user space, set permissions of - * ptmx to 0. Use 'chmod' or remount with '-o ptmxmode' to set meaningful - * permissions. - */ -#define DEVPTS_DEFAULT_PTMX_MODE 0000 -#define PTMX_MINOR 2 - -/* - * sysctl support for setting limits on the number of Unix98 ptys allocated. - * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly. - */ -static int pty_limit = NR_UNIX98_PTY_DEFAULT; -static int pty_reserve = NR_UNIX98_PTY_RESERVE; -static int pty_limit_min; -static int pty_limit_max = INT_MAX; -static int pty_count; - -static struct ctl_table pty_table[] = { - { - .procname = "max", - .maxlen = sizeof(int), - .mode = 0644, - .data = &pty_limit, - .proc_handler = proc_dointvec_minmax, - .extra1 = &pty_limit_min, - .extra2 = &pty_limit_max, - }, { - .procname = "reserve", - .maxlen = sizeof(int), - .mode = 0644, - .data = &pty_reserve, - .proc_handler = proc_dointvec_minmax, - .extra1 = &pty_limit_min, - .extra2 = &pty_limit_max, - }, { - .procname = "nr", - .maxlen = sizeof(int), - .mode = 0444, - .data = &pty_count, - .proc_handler = proc_dointvec, - }, - {} -}; - -static struct ctl_table pty_kern_table[] = { - { - .procname = "pty", - .mode = 0555, - .child = pty_table, - }, - {} -}; - -static struct ctl_table pty_root_table[] = { - { - .procname = "kernel", - .mode = 0555, - .child = pty_kern_table, - }, - {} -}; - -static DEFINE_MUTEX(allocated_ptys_lock); - -struct pts_mount_opts { - int setuid; - int setgid; - kuid_t uid; - kgid_t gid; - umode_t mode; - umode_t ptmxmode; - int reserve; - int max; -}; - -enum { - Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance, Opt_max, - Opt_err -}; - -static const match_table_t tokens = { - {Opt_uid, "uid=%u"}, - {Opt_gid, "gid=%u"}, - {Opt_mode, "mode=%o"}, - {Opt_ptmxmode, "ptmxmode=%o"}, - {Opt_newinstance, "newinstance"}, - {Opt_max, "max=%d"}, - {Opt_err, NULL} -}; - -struct pts_fs_info { - struct ida allocated_ptys; - struct pts_mount_opts mount_opts; - struct super_block *sb; - struct dentry *ptmx_dentry; -}; - -static inline struct pts_fs_info *DEVPTS_SB(struct super_block *sb) -{ - return sb->s_fs_info; -} - -struct pts_fs_info *devpts_acquire(struct file *filp) -{ - struct pts_fs_info *result; - struct path path; - struct super_block *sb; - int err; - - path = filp->f_path; - path_get(&path); - - /* Has the devpts filesystem already been found? */ - sb = path.mnt->mnt_sb; - if (sb->s_magic != DEVPTS_SUPER_MAGIC) { - /* Is a devpts filesystem at "pts" in the same directory? */ - err = path_pts(&path); - if (err) { - result = ERR_PTR(err); - goto out; - } - - /* Is the path the root of a devpts filesystem? */ - result = ERR_PTR(-ENODEV); - sb = path.mnt->mnt_sb; - if ((sb->s_magic != DEVPTS_SUPER_MAGIC) || - (path.mnt->mnt_root != sb->s_root)) - goto out; - } - - /* - * pty code needs to hold extra references in case of last /dev/tty close - */ - atomic_inc(&sb->s_active); - result = DEVPTS_SB(sb); - -out: - path_put(&path); - return result; -} - -void devpts_release(struct pts_fs_info *fsi) -{ - deactivate_super(fsi->sb); -} - -#define PARSE_MOUNT 0 -#define PARSE_REMOUNT 1 - -/* - * parse_mount_options(): - * Set @opts to mount options specified in @data. If an option is not - * specified in @data, set it to its default value. - * - * Note: @data may be NULL (in which case all options are set to default). - */ -static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts) -{ - char *p; - kuid_t uid; - kgid_t gid; - - opts->setuid = 0; - opts->setgid = 0; - opts->uid = GLOBAL_ROOT_UID; - opts->gid = GLOBAL_ROOT_GID; - opts->mode = DEVPTS_DEFAULT_MODE; - opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE; - opts->max = NR_UNIX98_PTY_MAX; - - /* Only allow instances mounted from the initial mount - * namespace to tap the reserve pool of ptys. - */ - if (op == PARSE_MOUNT) - opts->reserve = - (current->nsproxy->mnt_ns == init_task.nsproxy->mnt_ns); - - while ((p = strsep(&data, ",")) != NULL) { - substring_t args[MAX_OPT_ARGS]; - int token; - int option; - - if (!*p) - continue; - - token = match_token(p, tokens, args); - switch (token) { - case Opt_uid: - if (match_int(&args[0], &option)) - return -EINVAL; - uid = make_kuid(current_user_ns(), option); - if (!uid_valid(uid)) - return -EINVAL; - opts->uid = uid; - opts->setuid = 1; - break; - case Opt_gid: - if (match_int(&args[0], &option)) - return -EINVAL; - gid = make_kgid(current_user_ns(), option); - if (!gid_valid(gid)) - return -EINVAL; - opts->gid = gid; - opts->setgid = 1; - break; - case Opt_mode: - if (match_octal(&args[0], &option)) - return -EINVAL; - opts->mode = option & S_IALLUGO; - break; - case Opt_ptmxmode: - if (match_octal(&args[0], &option)) - return -EINVAL; - opts->ptmxmode = option & S_IALLUGO; - break; - case Opt_newinstance: - break; - case Opt_max: - if (match_int(&args[0], &option) || - option < 0 || option > NR_UNIX98_PTY_MAX) - return -EINVAL; - opts->max = option; - break; - default: - pr_err("called with bogus options\n"); - return -EINVAL; - } - } - - return 0; -} - -static int mknod_ptmx(struct super_block *sb) -{ - int mode; - int rc = -ENOMEM; - struct dentry *dentry; - struct inode *inode; - struct dentry *root = sb->s_root; - struct pts_fs_info *fsi = DEVPTS_SB(sb); - struct pts_mount_opts *opts = &fsi->mount_opts; - kuid_t ptmx_uid = current_fsuid(); - kgid_t ptmx_gid = current_fsgid(); - - inode_lock(d_inode(root)); - - /* If we have already created ptmx node, return */ - if (fsi->ptmx_dentry) { - rc = 0; - goto out; - } - - dentry = d_alloc_name(root, "ptmx"); - if (!dentry) { - pr_err("Unable to alloc dentry for ptmx node\n"); - goto out; - } - - /* - * Create a new 'ptmx' node in this mount of devpts. - */ - inode = new_inode(sb); - if (!inode) { - pr_err("Unable to alloc inode for ptmx node\n"); - dput(dentry); - goto out; - } - - inode->i_ino = 2; - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); - - mode = S_IFCHR|opts->ptmxmode; - init_special_inode(inode, mode, MKDEV(TTYAUX_MAJOR, 2)); - inode->i_uid = ptmx_uid; - inode->i_gid = ptmx_gid; - - d_add(dentry, inode); - - fsi->ptmx_dentry = dentry; - rc = 0; -out: - inode_unlock(d_inode(root)); - return rc; -} - -static void update_ptmx_mode(struct pts_fs_info *fsi) -{ - struct inode *inode; - if (fsi->ptmx_dentry) { - inode = d_inode(fsi->ptmx_dentry); - inode->i_mode = S_IFCHR|fsi->mount_opts.ptmxmode; - } -} - -static int devpts_remount(struct super_block *sb, int *flags, char *data) -{ - int err; - struct pts_fs_info *fsi = DEVPTS_SB(sb); - struct pts_mount_opts *opts = &fsi->mount_opts; - - err = parse_mount_options(data, PARSE_REMOUNT, opts); - - /* - * parse_mount_options() restores options to default values - * before parsing and may have changed ptmxmode. So, update the - * mode in the inode too. Bogus options don't fail the remount, - * so do this even on error return. - */ - update_ptmx_mode(fsi); - - return err; -} - -static int devpts_show_options(struct seq_file *seq, struct dentry *root) -{ - struct pts_fs_info *fsi = DEVPTS_SB(root->d_sb); - struct pts_mount_opts *opts = &fsi->mount_opts; - - if (opts->setuid) - seq_printf(seq, ",uid=%u", - from_kuid_munged(&init_user_ns, opts->uid)); - if (opts->setgid) - seq_printf(seq, ",gid=%u", - from_kgid_munged(&init_user_ns, opts->gid)); - seq_printf(seq, ",mode=%03o", opts->mode); - seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode); - if (opts->max < NR_UNIX98_PTY_MAX) - seq_printf(seq, ",max=%d", opts->max); - - return 0; -} - -static const struct super_operations devpts_sops = { - .statfs = simple_statfs, - .remount_fs = devpts_remount, - .show_options = devpts_show_options, -}; - -static void *new_pts_fs_info(struct super_block *sb) -{ - struct pts_fs_info *fsi; - - fsi = kzalloc(sizeof(struct pts_fs_info), GFP_KERNEL); - if (!fsi) - return NULL; - - ida_init(&fsi->allocated_ptys); - fsi->mount_opts.mode = DEVPTS_DEFAULT_MODE; - fsi->mount_opts.ptmxmode = DEVPTS_DEFAULT_PTMX_MODE; - fsi->sb = sb; - - return fsi; -} - -static int -devpts_fill_super(struct super_block *s, void *data, int silent) -{ - struct inode *inode; - int error; - - s->s_iflags &= ~SB_I_NODEV; - s->s_blocksize = 1024; - s->s_blocksize_bits = 10; - s->s_magic = DEVPTS_SUPER_MAGIC; - s->s_op = &devpts_sops; - s->s_time_gran = 1; - - error = -ENOMEM; - s->s_fs_info = new_pts_fs_info(s); - if (!s->s_fs_info) - goto fail; - - error = parse_mount_options(data, PARSE_MOUNT, &DEVPTS_SB(s)->mount_opts); - if (error) - goto fail; - - error = -ENOMEM; - inode = new_inode(s); - if (!inode) - goto fail; - inode->i_ino = 1; - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); - inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; - inode->i_op = &simple_dir_inode_operations; - inode->i_fop = &simple_dir_operations; - set_nlink(inode, 2); - - s->s_root = d_make_root(inode); - if (!s->s_root) { - pr_err("get root dentry failed\n"); - goto fail; - } - - error = mknod_ptmx(s); - if (error) - goto fail_dput; - - return 0; -fail_dput: - dput(s->s_root); - s->s_root = NULL; -fail: - return error; -} - -/* - * devpts_mount() - * - * Mount a new (private) instance of devpts. PTYs created in this - * instance are independent of the PTYs in other devpts instances. - */ -static struct dentry *devpts_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_nodev(fs_type, flags, data, devpts_fill_super); -} - -static void devpts_kill_sb(struct super_block *sb) -{ - struct pts_fs_info *fsi = DEVPTS_SB(sb); - - if (fsi) - ida_destroy(&fsi->allocated_ptys); - kfree(fsi); - kill_litter_super(sb); -} - -static struct file_system_type devpts_fs_type = { - .name = "devpts", - .mount = devpts_mount, - .kill_sb = devpts_kill_sb, - .fs_flags = FS_USERNS_MOUNT, -}; - -/* - * The normal naming convention is simply /dev/pts/; this conforms - * to the System V naming convention - */ - -int devpts_new_index(struct pts_fs_info *fsi) -{ - int index; - int ida_ret; - -retry: - if (!ida_pre_get(&fsi->allocated_ptys, GFP_KERNEL)) - return -ENOMEM; - - mutex_lock(&allocated_ptys_lock); - if (pty_count >= (pty_limit - - (fsi->mount_opts.reserve ? 0 : pty_reserve))) { - mutex_unlock(&allocated_ptys_lock); - return -ENOSPC; - } - - ida_ret = ida_get_new(&fsi->allocated_ptys, &index); - if (ida_ret < 0) { - mutex_unlock(&allocated_ptys_lock); - if (ida_ret == -EAGAIN) - goto retry; - return -EIO; - } - - if (index >= fsi->mount_opts.max) { - ida_remove(&fsi->allocated_ptys, index); - mutex_unlock(&allocated_ptys_lock); - return -ENOSPC; - } - pty_count++; - mutex_unlock(&allocated_ptys_lock); - return index; -} - -void devpts_kill_index(struct pts_fs_info *fsi, int idx) -{ - mutex_lock(&allocated_ptys_lock); - ida_remove(&fsi->allocated_ptys, idx); - pty_count--; - mutex_unlock(&allocated_ptys_lock); -} - -/** - * devpts_pty_new -- create a new inode in /dev/pts/ - * @ptmx_inode: inode of the master - * @device: major+minor of the node to be created - * @index: used as a name of the node - * @priv: what's given back by devpts_get_priv - * - * The created inode is returned. Remove it from /dev/pts/ by devpts_pty_kill. - */ -struct dentry *devpts_pty_new(struct pts_fs_info *fsi, int index, void *priv) -{ - struct dentry *dentry; - struct super_block *sb = fsi->sb; - struct inode *inode; - struct dentry *root; - struct pts_mount_opts *opts; - char s[12]; - - root = sb->s_root; - opts = &fsi->mount_opts; - - inode = new_inode(sb); - if (!inode) - return ERR_PTR(-ENOMEM); - - inode->i_ino = index + 3; - inode->i_uid = opts->setuid ? opts->uid : current_fsuid(); - inode->i_gid = opts->setgid ? opts->gid : current_fsgid(); - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); - init_special_inode(inode, S_IFCHR|opts->mode, MKDEV(UNIX98_PTY_SLAVE_MAJOR, index)); - - sprintf(s, "%d", index); - - dentry = d_alloc_name(root, s); - if (dentry) { - dentry->d_fsdata = priv; - d_add(dentry, inode); - fsnotify_create(d_inode(root), dentry); - } else { - iput(inode); - dentry = ERR_PTR(-ENOMEM); - } - - return dentry; -} - -/** - * devpts_get_priv -- get private data for a slave - * @pts_inode: inode of the slave - * - * Returns whatever was passed as priv in devpts_pty_new for a given inode. - */ -void *devpts_get_priv(struct dentry *dentry) -{ - if (dentry->d_sb->s_magic != DEVPTS_SUPER_MAGIC) - return NULL; - return dentry->d_fsdata; -} - -/** - * devpts_pty_kill -- remove inode form /dev/pts/ - * @inode: inode of the slave to be removed - * - * This is an inverse operation of devpts_pty_new. - */ -void devpts_pty_kill(struct dentry *dentry) -{ - WARN_ON_ONCE(dentry->d_sb->s_magic != DEVPTS_SUPER_MAGIC); - - dentry->d_fsdata = NULL; - drop_nlink(dentry->d_inode); - d_delete(dentry); - dput(dentry); /* d_alloc_name() in devpts_pty_new() */ -} - -static int __init init_devpts_fs(void) -{ - int err = register_filesystem(&devpts_fs_type); - if (!err) { - register_sysctl_table(pty_root_table); - } - return err; -} -module_init(init_devpts_fs) diff --git a/src/linux/fs/direct-io.c b/src/linux/fs/direct-io.c deleted file mode 100644 index fb9aa16..0000000 --- a/src/linux/fs/direct-io.c +++ /dev/null @@ -1,1370 +0,0 @@ -/* - * fs/direct-io.c - * - * Copyright (C) 2002, Linus Torvalds. - * - * O_DIRECT - * - * 04Jul2002 Andrew Morton - * Initial version - * 11Sep2002 janetinc@us.ibm.com - * added readv/writev support. - * 29Oct2002 Andrew Morton - * rewrote bio_add_page() support. - * 30Oct2002 pbadari@us.ibm.com - * added support for non-aligned IO. - * 06Nov2002 pbadari@us.ibm.com - * added asynchronous IO support. - * 21Jul2003 nathans@sgi.com - * added IO completion notifier. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * How many user pages to map in one call to get_user_pages(). This determines - * the size of a structure in the slab cache - */ -#define DIO_PAGES 64 - -/* - * This code generally works in units of "dio_blocks". A dio_block is - * somewhere between the hard sector size and the filesystem block size. it - * is determined on a per-invocation basis. When talking to the filesystem - * we need to convert dio_blocks to fs_blocks by scaling the dio_block quantity - * down by dio->blkfactor. Similarly, fs-blocksize quantities are converted - * to bio_block quantities by shifting left by blkfactor. - * - * If blkfactor is zero then the user's request was aligned to the filesystem's - * blocksize. - */ - -/* dio_state only used in the submission path */ - -struct dio_submit { - struct bio *bio; /* bio under assembly */ - unsigned blkbits; /* doesn't change */ - unsigned blkfactor; /* When we're using an alignment which - is finer than the filesystem's soft - blocksize, this specifies how much - finer. blkfactor=2 means 1/4-block - alignment. Does not change */ - unsigned start_zero_done; /* flag: sub-blocksize zeroing has - been performed at the start of a - write */ - int pages_in_io; /* approximate total IO pages */ - sector_t block_in_file; /* Current offset into the underlying - file in dio_block units. */ - unsigned blocks_available; /* At block_in_file. changes */ - int reap_counter; /* rate limit reaping */ - sector_t final_block_in_request;/* doesn't change */ - int boundary; /* prev block is at a boundary */ - get_block_t *get_block; /* block mapping function */ - dio_submit_t *submit_io; /* IO submition function */ - - loff_t logical_offset_in_bio; /* current first logical block in bio */ - sector_t final_block_in_bio; /* current final block in bio + 1 */ - sector_t next_block_for_io; /* next block to be put under IO, - in dio_blocks units */ - - /* - * Deferred addition of a page to the dio. These variables are - * private to dio_send_cur_page(), submit_page_section() and - * dio_bio_add_page(). - */ - struct page *cur_page; /* The page */ - unsigned cur_page_offset; /* Offset into it, in bytes */ - unsigned cur_page_len; /* Nr of bytes at cur_page_offset */ - sector_t cur_page_block; /* Where it starts */ - loff_t cur_page_fs_offset; /* Offset in file */ - - struct iov_iter *iter; - /* - * Page queue. These variables belong to dio_refill_pages() and - * dio_get_page(). - */ - unsigned head; /* next page to process */ - unsigned tail; /* last valid page + 1 */ - size_t from, to; -}; - -/* dio_state communicated between submission path and end_io */ -struct dio { - int flags; /* doesn't change */ - int op; - int op_flags; - blk_qc_t bio_cookie; - struct block_device *bio_bdev; - struct inode *inode; - loff_t i_size; /* i_size when submitted */ - dio_iodone_t *end_io; /* IO completion function */ - - void *private; /* copy from map_bh.b_private */ - - /* BIO completion state */ - spinlock_t bio_lock; /* protects BIO fields below */ - int page_errors; /* errno from get_user_pages() */ - int is_async; /* is IO async ? */ - bool defer_completion; /* defer AIO completion to workqueue? */ - bool should_dirty; /* if pages should be dirtied */ - int io_error; /* IO error in completion path */ - unsigned long refcount; /* direct_io_worker() and bios */ - struct bio *bio_list; /* singly linked via bi_private */ - struct task_struct *waiter; /* waiting task (NULL if none) */ - - /* AIO related stuff */ - struct kiocb *iocb; /* kiocb */ - ssize_t result; /* IO result */ - - /* - * pages[] (and any fields placed after it) are not zeroed out at - * allocation time. Don't add new fields after pages[] unless you - * wish that they not be zeroed. - */ - union { - struct page *pages[DIO_PAGES]; /* page buffer */ - struct work_struct complete_work;/* deferred AIO completion */ - }; -} ____cacheline_aligned_in_smp; - -static struct kmem_cache *dio_cache __read_mostly; - -/* - * How many pages are in the queue? - */ -static inline unsigned dio_pages_present(struct dio_submit *sdio) -{ - return sdio->tail - sdio->head; -} - -/* - * Go grab and pin some userspace pages. Typically we'll get 64 at a time. - */ -static inline int dio_refill_pages(struct dio *dio, struct dio_submit *sdio) -{ - ssize_t ret; - - ret = iov_iter_get_pages(sdio->iter, dio->pages, LONG_MAX, DIO_PAGES, - &sdio->from); - - if (ret < 0 && sdio->blocks_available && (dio->op == REQ_OP_WRITE)) { - struct page *page = ZERO_PAGE(0); - /* - * A memory fault, but the filesystem has some outstanding - * mapped blocks. We need to use those blocks up to avoid - * leaking stale data in the file. - */ - if (dio->page_errors == 0) - dio->page_errors = ret; - get_page(page); - dio->pages[0] = page; - sdio->head = 0; - sdio->tail = 1; - sdio->from = 0; - sdio->to = PAGE_SIZE; - return 0; - } - - if (ret >= 0) { - iov_iter_advance(sdio->iter, ret); - ret += sdio->from; - sdio->head = 0; - sdio->tail = (ret + PAGE_SIZE - 1) / PAGE_SIZE; - sdio->to = ((ret - 1) & (PAGE_SIZE - 1)) + 1; - return 0; - } - return ret; -} - -/* - * Get another userspace page. Returns an ERR_PTR on error. Pages are - * buffered inside the dio so that we can call get_user_pages() against a - * decent number of pages, less frequently. To provide nicer use of the - * L1 cache. - */ -static inline struct page *dio_get_page(struct dio *dio, - struct dio_submit *sdio) -{ - if (dio_pages_present(sdio) == 0) { - int ret; - - ret = dio_refill_pages(dio, sdio); - if (ret) - return ERR_PTR(ret); - BUG_ON(dio_pages_present(sdio) == 0); - } - return dio->pages[sdio->head]; -} - -/** - * dio_complete() - called when all DIO BIO I/O has been completed - * @offset: the byte offset in the file of the completed operation - * - * This drops i_dio_count, lets interested parties know that a DIO operation - * has completed, and calculates the resulting return code for the operation. - * - * It lets the filesystem know if it registered an interest earlier via - * get_block. Pass the private field of the map buffer_head so that - * filesystems can use it to hold additional state between get_block calls and - * dio_complete. - */ -static ssize_t dio_complete(struct dio *dio, ssize_t ret, bool is_async) -{ - loff_t offset = dio->iocb->ki_pos; - ssize_t transferred = 0; - - /* - * AIO submission can race with bio completion to get here while - * expecting to have the last io completed by bio completion. - * In that case -EIOCBQUEUED is in fact not an error we want - * to preserve through this call. - */ - if (ret == -EIOCBQUEUED) - ret = 0; - - if (dio->result) { - transferred = dio->result; - - /* Check for short read case */ - if ((dio->op == REQ_OP_READ) && - ((offset + transferred) > dio->i_size)) - transferred = dio->i_size - offset; - /* ignore EFAULT if some IO has been done */ - if (unlikely(ret == -EFAULT) && transferred) - ret = 0; - } - - if (ret == 0) - ret = dio->page_errors; - if (ret == 0) - ret = dio->io_error; - if (ret == 0) - ret = transferred; - - if (dio->end_io) { - int err; - - // XXX: ki_pos?? - err = dio->end_io(dio->iocb, offset, ret, dio->private); - if (err) - ret = err; - } - - if (!(dio->flags & DIO_SKIP_DIO_COUNT)) - inode_dio_end(dio->inode); - - if (is_async) { - /* - * generic_write_sync expects ki_pos to have been updated - * already, but the submission path only does this for - * synchronous I/O. - */ - dio->iocb->ki_pos += transferred; - - if (dio->op == REQ_OP_WRITE) - ret = generic_write_sync(dio->iocb, transferred); - dio->iocb->ki_complete(dio->iocb, ret, 0); - } - - kmem_cache_free(dio_cache, dio); - return ret; -} - -static void dio_aio_complete_work(struct work_struct *work) -{ - struct dio *dio = container_of(work, struct dio, complete_work); - - dio_complete(dio, 0, true); -} - -static int dio_bio_complete(struct dio *dio, struct bio *bio); - -/* - * Asynchronous IO callback. - */ -static void dio_bio_end_aio(struct bio *bio) -{ - struct dio *dio = bio->bi_private; - unsigned long remaining; - unsigned long flags; - - /* cleanup the bio */ - dio_bio_complete(dio, bio); - - spin_lock_irqsave(&dio->bio_lock, flags); - remaining = --dio->refcount; - if (remaining == 1 && dio->waiter) - wake_up_process(dio->waiter); - spin_unlock_irqrestore(&dio->bio_lock, flags); - - if (remaining == 0) { - if (dio->result && dio->defer_completion) { - INIT_WORK(&dio->complete_work, dio_aio_complete_work); - queue_work(dio->inode->i_sb->s_dio_done_wq, - &dio->complete_work); - } else { - dio_complete(dio, 0, true); - } - } -} - -/* - * The BIO completion handler simply queues the BIO up for the process-context - * handler. - * - * During I/O bi_private points at the dio. After I/O, bi_private is used to - * implement a singly-linked list of completed BIOs, at dio->bio_list. - */ -static void dio_bio_end_io(struct bio *bio) -{ - struct dio *dio = bio->bi_private; - unsigned long flags; - - spin_lock_irqsave(&dio->bio_lock, flags); - bio->bi_private = dio->bio_list; - dio->bio_list = bio; - if (--dio->refcount == 1 && dio->waiter) - wake_up_process(dio->waiter); - spin_unlock_irqrestore(&dio->bio_lock, flags); -} - -/** - * dio_end_io - handle the end io action for the given bio - * @bio: The direct io bio thats being completed - * @error: Error if there was one - * - * This is meant to be called by any filesystem that uses their own dio_submit_t - * so that the DIO specific endio actions are dealt with after the filesystem - * has done it's completion work. - */ -void dio_end_io(struct bio *bio, int error) -{ - struct dio *dio = bio->bi_private; - - if (dio->is_async) - dio_bio_end_aio(bio); - else - dio_bio_end_io(bio); -} -EXPORT_SYMBOL_GPL(dio_end_io); - -static inline void -dio_bio_alloc(struct dio *dio, struct dio_submit *sdio, - struct block_device *bdev, - sector_t first_sector, int nr_vecs) -{ - struct bio *bio; - - /* - * bio_alloc() is guaranteed to return a bio when called with - * __GFP_RECLAIM and we request a valid number of vectors. - */ - bio = bio_alloc(GFP_KERNEL, nr_vecs); - - bio->bi_bdev = bdev; - bio->bi_iter.bi_sector = first_sector; - bio_set_op_attrs(bio, dio->op, dio->op_flags); - if (dio->is_async) - bio->bi_end_io = dio_bio_end_aio; - else - bio->bi_end_io = dio_bio_end_io; - - sdio->bio = bio; - sdio->logical_offset_in_bio = sdio->cur_page_fs_offset; -} - -/* - * In the AIO read case we speculatively dirty the pages before starting IO. - * During IO completion, any of these pages which happen to have been written - * back will be redirtied by bio_check_pages_dirty(). - * - * bios hold a dio reference between submit_bio and ->end_io. - */ -static inline void dio_bio_submit(struct dio *dio, struct dio_submit *sdio) -{ - struct bio *bio = sdio->bio; - unsigned long flags; - - bio->bi_private = dio; - - spin_lock_irqsave(&dio->bio_lock, flags); - dio->refcount++; - spin_unlock_irqrestore(&dio->bio_lock, flags); - - if (dio->is_async && dio->op == REQ_OP_READ && dio->should_dirty) - bio_set_pages_dirty(bio); - - dio->bio_bdev = bio->bi_bdev; - - if (sdio->submit_io) { - sdio->submit_io(bio, dio->inode, sdio->logical_offset_in_bio); - dio->bio_cookie = BLK_QC_T_NONE; - } else - dio->bio_cookie = submit_bio(bio); - - sdio->bio = NULL; - sdio->boundary = 0; - sdio->logical_offset_in_bio = 0; -} - -/* - * Release any resources in case of a failure - */ -static inline void dio_cleanup(struct dio *dio, struct dio_submit *sdio) -{ - while (sdio->head < sdio->tail) - put_page(dio->pages[sdio->head++]); -} - -/* - * Wait for the next BIO to complete. Remove it and return it. NULL is - * returned once all BIOs have been completed. This must only be called once - * all bios have been issued so that dio->refcount can only decrease. This - * requires that that the caller hold a reference on the dio. - */ -static struct bio *dio_await_one(struct dio *dio) -{ - unsigned long flags; - struct bio *bio = NULL; - - spin_lock_irqsave(&dio->bio_lock, flags); - - /* - * Wait as long as the list is empty and there are bios in flight. bio - * completion drops the count, maybe adds to the list, and wakes while - * holding the bio_lock so we don't need set_current_state()'s barrier - * and can call it after testing our condition. - */ - while (dio->refcount > 1 && dio->bio_list == NULL) { - __set_current_state(TASK_UNINTERRUPTIBLE); - dio->waiter = current; - spin_unlock_irqrestore(&dio->bio_lock, flags); - if (!(dio->iocb->ki_flags & IOCB_HIPRI) || - !blk_poll(bdev_get_queue(dio->bio_bdev), dio->bio_cookie)) - io_schedule(); - /* wake up sets us TASK_RUNNING */ - spin_lock_irqsave(&dio->bio_lock, flags); - dio->waiter = NULL; - } - if (dio->bio_list) { - bio = dio->bio_list; - dio->bio_list = bio->bi_private; - } - spin_unlock_irqrestore(&dio->bio_lock, flags); - return bio; -} - -/* - * Process one completed BIO. No locks are held. - */ -static int dio_bio_complete(struct dio *dio, struct bio *bio) -{ - struct bio_vec *bvec; - unsigned i; - int err; - - if (bio->bi_error) - dio->io_error = -EIO; - - if (dio->is_async && dio->op == REQ_OP_READ && dio->should_dirty) { - err = bio->bi_error; - bio_check_pages_dirty(bio); /* transfers ownership */ - } else { - bio_for_each_segment_all(bvec, bio, i) { - struct page *page = bvec->bv_page; - - if (dio->op == REQ_OP_READ && !PageCompound(page) && - dio->should_dirty) - set_page_dirty_lock(page); - put_page(page); - } - err = bio->bi_error; - bio_put(bio); - } - return err; -} - -/* - * Wait on and process all in-flight BIOs. This must only be called once - * all bios have been issued so that the refcount can only decrease. - * This just waits for all bios to make it through dio_bio_complete. IO - * errors are propagated through dio->io_error and should be propagated via - * dio_complete(). - */ -static void dio_await_completion(struct dio *dio) -{ - struct bio *bio; - do { - bio = dio_await_one(dio); - if (bio) - dio_bio_complete(dio, bio); - } while (bio); -} - -/* - * A really large O_DIRECT read or write can generate a lot of BIOs. So - * to keep the memory consumption sane we periodically reap any completed BIOs - * during the BIO generation phase. - * - * This also helps to limit the peak amount of pinned userspace memory. - */ -static inline int dio_bio_reap(struct dio *dio, struct dio_submit *sdio) -{ - int ret = 0; - - if (sdio->reap_counter++ >= 64) { - while (dio->bio_list) { - unsigned long flags; - struct bio *bio; - int ret2; - - spin_lock_irqsave(&dio->bio_lock, flags); - bio = dio->bio_list; - dio->bio_list = bio->bi_private; - spin_unlock_irqrestore(&dio->bio_lock, flags); - ret2 = dio_bio_complete(dio, bio); - if (ret == 0) - ret = ret2; - } - sdio->reap_counter = 0; - } - return ret; -} - -/* - * Create workqueue for deferred direct IO completions. We allocate the - * workqueue when it's first needed. This avoids creating workqueue for - * filesystems that don't need it and also allows us to create the workqueue - * late enough so the we can include s_id in the name of the workqueue. - */ -static int sb_init_dio_done_wq(struct super_block *sb) -{ - struct workqueue_struct *old; - struct workqueue_struct *wq = alloc_workqueue("dio/%s", - WQ_MEM_RECLAIM, 0, - sb->s_id); - if (!wq) - return -ENOMEM; - /* - * This has to be atomic as more DIOs can race to create the workqueue - */ - old = cmpxchg(&sb->s_dio_done_wq, NULL, wq); - /* Someone created workqueue before us? Free ours... */ - if (old) - destroy_workqueue(wq); - return 0; -} - -static int dio_set_defer_completion(struct dio *dio) -{ - struct super_block *sb = dio->inode->i_sb; - - if (dio->defer_completion) - return 0; - dio->defer_completion = true; - if (!sb->s_dio_done_wq) - return sb_init_dio_done_wq(sb); - return 0; -} - -/* - * Call into the fs to map some more disk blocks. We record the current number - * of available blocks at sdio->blocks_available. These are in units of the - * fs blocksize, (1 << inode->i_blkbits). - * - * The fs is allowed to map lots of blocks at once. If it wants to do that, - * it uses the passed inode-relative block number as the file offset, as usual. - * - * get_block() is passed the number of i_blkbits-sized blocks which direct_io - * has remaining to do. The fs should not map more than this number of blocks. - * - * If the fs has mapped a lot of blocks, it should populate bh->b_size to - * indicate how much contiguous disk space has been made available at - * bh->b_blocknr. - * - * If *any* of the mapped blocks are new, then the fs must set buffer_new(). - * This isn't very efficient... - * - * In the case of filesystem holes: the fs may return an arbitrarily-large - * hole by returning an appropriate value in b_size and by clearing - * buffer_mapped(). However the direct-io code will only process holes one - * block at a time - it will repeatedly call get_block() as it walks the hole. - */ -static int get_more_blocks(struct dio *dio, struct dio_submit *sdio, - struct buffer_head *map_bh) -{ - int ret; - sector_t fs_startblk; /* Into file, in filesystem-sized blocks */ - sector_t fs_endblk; /* Into file, in filesystem-sized blocks */ - unsigned long fs_count; /* Number of filesystem-sized blocks */ - int create; - unsigned int i_blkbits = sdio->blkbits + sdio->blkfactor; - - /* - * If there was a memory error and we've overwritten all the - * mapped blocks then we can now return that memory error - */ - ret = dio->page_errors; - if (ret == 0) { - BUG_ON(sdio->block_in_file >= sdio->final_block_in_request); - fs_startblk = sdio->block_in_file >> sdio->blkfactor; - fs_endblk = (sdio->final_block_in_request - 1) >> - sdio->blkfactor; - fs_count = fs_endblk - fs_startblk + 1; - - map_bh->b_state = 0; - map_bh->b_size = fs_count << i_blkbits; - - /* - * For writes that could fill holes inside i_size on a - * DIO_SKIP_HOLES filesystem we forbid block creations: only - * overwrites are permitted. We will return early to the caller - * once we see an unmapped buffer head returned, and the caller - * will fall back to buffered I/O. - * - * Otherwise the decision is left to the get_blocks method, - * which may decide to handle it or also return an unmapped - * buffer head. - */ - create = dio->op == REQ_OP_WRITE; - if (dio->flags & DIO_SKIP_HOLES) { - if (fs_startblk <= ((i_size_read(dio->inode) - 1) >> - i_blkbits)) - create = 0; - } - - ret = (*sdio->get_block)(dio->inode, fs_startblk, - map_bh, create); - - /* Store for completion */ - dio->private = map_bh->b_private; - - if (ret == 0 && buffer_defer_completion(map_bh)) - ret = dio_set_defer_completion(dio); - } - return ret; -} - -/* - * There is no bio. Make one now. - */ -static inline int dio_new_bio(struct dio *dio, struct dio_submit *sdio, - sector_t start_sector, struct buffer_head *map_bh) -{ - sector_t sector; - int ret, nr_pages; - - ret = dio_bio_reap(dio, sdio); - if (ret) - goto out; - sector = start_sector << (sdio->blkbits - 9); - nr_pages = min(sdio->pages_in_io, BIO_MAX_PAGES); - BUG_ON(nr_pages <= 0); - dio_bio_alloc(dio, sdio, map_bh->b_bdev, sector, nr_pages); - sdio->boundary = 0; -out: - return ret; -} - -/* - * Attempt to put the current chunk of 'cur_page' into the current BIO. If - * that was successful then update final_block_in_bio and take a ref against - * the just-added page. - * - * Return zero on success. Non-zero means the caller needs to start a new BIO. - */ -static inline int dio_bio_add_page(struct dio_submit *sdio) -{ - int ret; - - ret = bio_add_page(sdio->bio, sdio->cur_page, - sdio->cur_page_len, sdio->cur_page_offset); - if (ret == sdio->cur_page_len) { - /* - * Decrement count only, if we are done with this page - */ - if ((sdio->cur_page_len + sdio->cur_page_offset) == PAGE_SIZE) - sdio->pages_in_io--; - get_page(sdio->cur_page); - sdio->final_block_in_bio = sdio->cur_page_block + - (sdio->cur_page_len >> sdio->blkbits); - ret = 0; - } else { - ret = 1; - } - return ret; -} - -/* - * Put cur_page under IO. The section of cur_page which is described by - * cur_page_offset,cur_page_len is put into a BIO. The section of cur_page - * starts on-disk at cur_page_block. - * - * We take a ref against the page here (on behalf of its presence in the bio). - * - * The caller of this function is responsible for removing cur_page from the - * dio, and for dropping the refcount which came from that presence. - */ -static inline int dio_send_cur_page(struct dio *dio, struct dio_submit *sdio, - struct buffer_head *map_bh) -{ - int ret = 0; - - if (sdio->bio) { - loff_t cur_offset = sdio->cur_page_fs_offset; - loff_t bio_next_offset = sdio->logical_offset_in_bio + - sdio->bio->bi_iter.bi_size; - - /* - * See whether this new request is contiguous with the old. - * - * Btrfs cannot handle having logically non-contiguous requests - * submitted. For example if you have - * - * Logical: [0-4095][HOLE][8192-12287] - * Physical: [0-4095] [4096-8191] - * - * We cannot submit those pages together as one BIO. So if our - * current logical offset in the file does not equal what would - * be the next logical offset in the bio, submit the bio we - * have. - */ - if (sdio->final_block_in_bio != sdio->cur_page_block || - cur_offset != bio_next_offset) - dio_bio_submit(dio, sdio); - } - - if (sdio->bio == NULL) { - ret = dio_new_bio(dio, sdio, sdio->cur_page_block, map_bh); - if (ret) - goto out; - } - - if (dio_bio_add_page(sdio) != 0) { - dio_bio_submit(dio, sdio); - ret = dio_new_bio(dio, sdio, sdio->cur_page_block, map_bh); - if (ret == 0) { - ret = dio_bio_add_page(sdio); - BUG_ON(ret != 0); - } - } -out: - return ret; -} - -/* - * An autonomous function to put a chunk of a page under deferred IO. - * - * The caller doesn't actually know (or care) whether this piece of page is in - * a BIO, or is under IO or whatever. We just take care of all possible - * situations here. The separation between the logic of do_direct_IO() and - * that of submit_page_section() is important for clarity. Please don't break. - * - * The chunk of page starts on-disk at blocknr. - * - * We perform deferred IO, by recording the last-submitted page inside our - * private part of the dio structure. If possible, we just expand the IO - * across that page here. - * - * If that doesn't work out then we put the old page into the bio and add this - * page to the dio instead. - */ -static inline int -submit_page_section(struct dio *dio, struct dio_submit *sdio, struct page *page, - unsigned offset, unsigned len, sector_t blocknr, - struct buffer_head *map_bh) -{ - int ret = 0; - - if (dio->op == REQ_OP_WRITE) { - /* - * Read accounting is performed in submit_bio() - */ - task_io_account_write(len); - } - - /* - * Can we just grow the current page's presence in the dio? - */ - if (sdio->cur_page == page && - sdio->cur_page_offset + sdio->cur_page_len == offset && - sdio->cur_page_block + - (sdio->cur_page_len >> sdio->blkbits) == blocknr) { - sdio->cur_page_len += len; - goto out; - } - - /* - * If there's a deferred page already there then send it. - */ - if (sdio->cur_page) { - ret = dio_send_cur_page(dio, sdio, map_bh); - put_page(sdio->cur_page); - sdio->cur_page = NULL; - if (ret) - return ret; - } - - get_page(page); /* It is in dio */ - sdio->cur_page = page; - sdio->cur_page_offset = offset; - sdio->cur_page_len = len; - sdio->cur_page_block = blocknr; - sdio->cur_page_fs_offset = sdio->block_in_file << sdio->blkbits; -out: - /* - * If sdio->boundary then we want to schedule the IO now to - * avoid metadata seeks. - */ - if (sdio->boundary) { - ret = dio_send_cur_page(dio, sdio, map_bh); - dio_bio_submit(dio, sdio); - put_page(sdio->cur_page); - sdio->cur_page = NULL; - } - return ret; -} - -/* - * Clean any dirty buffers in the blockdev mapping which alias newly-created - * file blocks. Only called for S_ISREG files - blockdevs do not set - * buffer_new - */ -static void clean_blockdev_aliases(struct dio *dio, struct buffer_head *map_bh) -{ - unsigned i; - unsigned nblocks; - - nblocks = map_bh->b_size >> dio->inode->i_blkbits; - - for (i = 0; i < nblocks; i++) { - unmap_underlying_metadata(map_bh->b_bdev, - map_bh->b_blocknr + i); - } -} - -/* - * If we are not writing the entire block and get_block() allocated - * the block for us, we need to fill-in the unused portion of the - * block with zeros. This happens only if user-buffer, fileoffset or - * io length is not filesystem block-size multiple. - * - * `end' is zero if we're doing the start of the IO, 1 at the end of the - * IO. - */ -static inline void dio_zero_block(struct dio *dio, struct dio_submit *sdio, - int end, struct buffer_head *map_bh) -{ - unsigned dio_blocks_per_fs_block; - unsigned this_chunk_blocks; /* In dio_blocks */ - unsigned this_chunk_bytes; - struct page *page; - - sdio->start_zero_done = 1; - if (!sdio->blkfactor || !buffer_new(map_bh)) - return; - - dio_blocks_per_fs_block = 1 << sdio->blkfactor; - this_chunk_blocks = sdio->block_in_file & (dio_blocks_per_fs_block - 1); - - if (!this_chunk_blocks) - return; - - /* - * We need to zero out part of an fs block. It is either at the - * beginning or the end of the fs block. - */ - if (end) - this_chunk_blocks = dio_blocks_per_fs_block - this_chunk_blocks; - - this_chunk_bytes = this_chunk_blocks << sdio->blkbits; - - page = ZERO_PAGE(0); - if (submit_page_section(dio, sdio, page, 0, this_chunk_bytes, - sdio->next_block_for_io, map_bh)) - return; - - sdio->next_block_for_io += this_chunk_blocks; -} - -/* - * Walk the user pages, and the file, mapping blocks to disk and generating - * a sequence of (page,offset,len,block) mappings. These mappings are injected - * into submit_page_section(), which takes care of the next stage of submission - * - * Direct IO against a blockdev is different from a file. Because we can - * happily perform page-sized but 512-byte aligned IOs. It is important that - * blockdev IO be able to have fine alignment and large sizes. - * - * So what we do is to permit the ->get_block function to populate bh.b_size - * with the size of IO which is permitted at this offset and this i_blkbits. - * - * For best results, the blockdev should be set up with 512-byte i_blkbits and - * it should set b_size to PAGE_SIZE or more inside get_block(). This gives - * fine alignment but still allows this function to work in PAGE_SIZE units. - */ -static int do_direct_IO(struct dio *dio, struct dio_submit *sdio, - struct buffer_head *map_bh) -{ - const unsigned blkbits = sdio->blkbits; - int ret = 0; - - while (sdio->block_in_file < sdio->final_block_in_request) { - struct page *page; - size_t from, to; - - page = dio_get_page(dio, sdio); - if (IS_ERR(page)) { - ret = PTR_ERR(page); - goto out; - } - from = sdio->head ? 0 : sdio->from; - to = (sdio->head == sdio->tail - 1) ? sdio->to : PAGE_SIZE; - sdio->head++; - - while (from < to) { - unsigned this_chunk_bytes; /* # of bytes mapped */ - unsigned this_chunk_blocks; /* # of blocks */ - unsigned u; - - if (sdio->blocks_available == 0) { - /* - * Need to go and map some more disk - */ - unsigned long blkmask; - unsigned long dio_remainder; - - ret = get_more_blocks(dio, sdio, map_bh); - if (ret) { - put_page(page); - goto out; - } - if (!buffer_mapped(map_bh)) - goto do_holes; - - sdio->blocks_available = - map_bh->b_size >> sdio->blkbits; - sdio->next_block_for_io = - map_bh->b_blocknr << sdio->blkfactor; - if (buffer_new(map_bh)) - clean_blockdev_aliases(dio, map_bh); - - if (!sdio->blkfactor) - goto do_holes; - - blkmask = (1 << sdio->blkfactor) - 1; - dio_remainder = (sdio->block_in_file & blkmask); - - /* - * If we are at the start of IO and that IO - * starts partway into a fs-block, - * dio_remainder will be non-zero. If the IO - * is a read then we can simply advance the IO - * cursor to the first block which is to be - * read. But if the IO is a write and the - * block was newly allocated we cannot do that; - * the start of the fs block must be zeroed out - * on-disk - */ - if (!buffer_new(map_bh)) - sdio->next_block_for_io += dio_remainder; - sdio->blocks_available -= dio_remainder; - } -do_holes: - /* Handle holes */ - if (!buffer_mapped(map_bh)) { - loff_t i_size_aligned; - - /* AKPM: eargh, -ENOTBLK is a hack */ - if (dio->op == REQ_OP_WRITE) { - put_page(page); - return -ENOTBLK; - } - - /* - * Be sure to account for a partial block as the - * last block in the file - */ - i_size_aligned = ALIGN(i_size_read(dio->inode), - 1 << blkbits); - if (sdio->block_in_file >= - i_size_aligned >> blkbits) { - /* We hit eof */ - put_page(page); - goto out; - } - zero_user(page, from, 1 << blkbits); - sdio->block_in_file++; - from += 1 << blkbits; - dio->result += 1 << blkbits; - goto next_block; - } - - /* - * If we're performing IO which has an alignment which - * is finer than the underlying fs, go check to see if - * we must zero out the start of this block. - */ - if (unlikely(sdio->blkfactor && !sdio->start_zero_done)) - dio_zero_block(dio, sdio, 0, map_bh); - - /* - * Work out, in this_chunk_blocks, how much disk we - * can add to this page - */ - this_chunk_blocks = sdio->blocks_available; - u = (to - from) >> blkbits; - if (this_chunk_blocks > u) - this_chunk_blocks = u; - u = sdio->final_block_in_request - sdio->block_in_file; - if (this_chunk_blocks > u) - this_chunk_blocks = u; - this_chunk_bytes = this_chunk_blocks << blkbits; - BUG_ON(this_chunk_bytes == 0); - - if (this_chunk_blocks == sdio->blocks_available) - sdio->boundary = buffer_boundary(map_bh); - ret = submit_page_section(dio, sdio, page, - from, - this_chunk_bytes, - sdio->next_block_for_io, - map_bh); - if (ret) { - put_page(page); - goto out; - } - sdio->next_block_for_io += this_chunk_blocks; - - sdio->block_in_file += this_chunk_blocks; - from += this_chunk_bytes; - dio->result += this_chunk_bytes; - sdio->blocks_available -= this_chunk_blocks; -next_block: - BUG_ON(sdio->block_in_file > sdio->final_block_in_request); - if (sdio->block_in_file == sdio->final_block_in_request) - break; - } - - /* Drop the ref which was taken in get_user_pages() */ - put_page(page); - } -out: - return ret; -} - -static inline int drop_refcount(struct dio *dio) -{ - int ret2; - unsigned long flags; - - /* - * Sync will always be dropping the final ref and completing the - * operation. AIO can if it was a broken operation described above or - * in fact if all the bios race to complete before we get here. In - * that case dio_complete() translates the EIOCBQUEUED into the proper - * return code that the caller will hand to ->complete(). - * - * This is managed by the bio_lock instead of being an atomic_t so that - * completion paths can drop their ref and use the remaining count to - * decide to wake the submission path atomically. - */ - spin_lock_irqsave(&dio->bio_lock, flags); - ret2 = --dio->refcount; - spin_unlock_irqrestore(&dio->bio_lock, flags); - return ret2; -} - -/* - * This is a library function for use by filesystem drivers. - * - * The locking rules are governed by the flags parameter: - * - if the flags value contains DIO_LOCKING we use a fancy locking - * scheme for dumb filesystems. - * For writes this function is called under i_mutex and returns with - * i_mutex held, for reads, i_mutex is not held on entry, but it is - * taken and dropped again before returning. - * - if the flags value does NOT contain DIO_LOCKING we don't use any - * internal locking but rather rely on the filesystem to synchronize - * direct I/O reads/writes versus each other and truncate. - * - * To help with locking against truncate we incremented the i_dio_count - * counter before starting direct I/O, and decrement it once we are done. - * Truncate can wait for it to reach zero to provide exclusion. It is - * expected that filesystem provide exclusion between new direct I/O - * and truncates. For DIO_LOCKING filesystems this is done by i_mutex, - * but other filesystems need to take care of this on their own. - * - * NOTE: if you pass "sdio" to anything by pointer make sure that function - * is always inlined. Otherwise gcc is unable to split the structure into - * individual fields and will generate much worse code. This is important - * for the whole file. - */ -static inline ssize_t -do_blockdev_direct_IO(struct kiocb *iocb, struct inode *inode, - struct block_device *bdev, struct iov_iter *iter, - get_block_t get_block, dio_iodone_t end_io, - dio_submit_t submit_io, int flags) -{ - unsigned i_blkbits = ACCESS_ONCE(inode->i_blkbits); - unsigned blkbits = i_blkbits; - unsigned blocksize_mask = (1 << blkbits) - 1; - ssize_t retval = -EINVAL; - size_t count = iov_iter_count(iter); - loff_t offset = iocb->ki_pos; - loff_t end = offset + count; - struct dio *dio; - struct dio_submit sdio = { 0, }; - struct buffer_head map_bh = { 0, }; - struct blk_plug plug; - unsigned long align = offset | iov_iter_alignment(iter); - - /* - * Avoid references to bdev if not absolutely needed to give - * the early prefetch in the caller enough time. - */ - - if (align & blocksize_mask) { - if (bdev) - blkbits = blksize_bits(bdev_logical_block_size(bdev)); - blocksize_mask = (1 << blkbits) - 1; - if (align & blocksize_mask) - goto out; - } - - /* watch out for a 0 len io from a tricksy fs */ - if (iov_iter_rw(iter) == READ && !iov_iter_count(iter)) - return 0; - - dio = kmem_cache_alloc(dio_cache, GFP_KERNEL); - retval = -ENOMEM; - if (!dio) - goto out; - /* - * Believe it or not, zeroing out the page array caused a .5% - * performance regression in a database benchmark. So, we take - * care to only zero out what's needed. - */ - memset(dio, 0, offsetof(struct dio, pages)); - - dio->flags = flags; - if (dio->flags & DIO_LOCKING) { - if (iov_iter_rw(iter) == READ) { - struct address_space *mapping = - iocb->ki_filp->f_mapping; - - /* will be released by direct_io_worker */ - inode_lock(inode); - - retval = filemap_write_and_wait_range(mapping, offset, - end - 1); - if (retval) { - inode_unlock(inode); - kmem_cache_free(dio_cache, dio); - goto out; - } - } - } - - /* Once we sampled i_size check for reads beyond EOF */ - dio->i_size = i_size_read(inode); - if (iov_iter_rw(iter) == READ && offset >= dio->i_size) { - if (dio->flags & DIO_LOCKING) - inode_unlock(inode); - kmem_cache_free(dio_cache, dio); - retval = 0; - goto out; - } - - /* - * For file extending writes updating i_size before data writeouts - * complete can expose uninitialized blocks in dumb filesystems. - * In that case we need to wait for I/O completion even if asked - * for an asynchronous write. - */ - if (is_sync_kiocb(iocb)) - dio->is_async = false; - else if (!(dio->flags & DIO_ASYNC_EXTEND) && - iov_iter_rw(iter) == WRITE && end > i_size_read(inode)) - dio->is_async = false; - else - dio->is_async = true; - - dio->inode = inode; - if (iov_iter_rw(iter) == WRITE) { - dio->op = REQ_OP_WRITE; - dio->op_flags = WRITE_ODIRECT; - } else { - dio->op = REQ_OP_READ; - } - - /* - * For AIO O_(D)SYNC writes we need to defer completions to a workqueue - * so that we can call ->fsync. - */ - if (dio->is_async && iov_iter_rw(iter) == WRITE && - ((iocb->ki_filp->f_flags & O_DSYNC) || - IS_SYNC(iocb->ki_filp->f_mapping->host))) { - retval = dio_set_defer_completion(dio); - if (retval) { - /* - * We grab i_mutex only for reads so we don't have - * to release it here - */ - kmem_cache_free(dio_cache, dio); - goto out; - } - } - - /* - * Will be decremented at I/O completion time. - */ - if (!(dio->flags & DIO_SKIP_DIO_COUNT)) - inode_dio_begin(inode); - - retval = 0; - sdio.blkbits = blkbits; - sdio.blkfactor = i_blkbits - blkbits; - sdio.block_in_file = offset >> blkbits; - - sdio.get_block = get_block; - dio->end_io = end_io; - sdio.submit_io = submit_io; - sdio.final_block_in_bio = -1; - sdio.next_block_for_io = -1; - - dio->iocb = iocb; - - spin_lock_init(&dio->bio_lock); - dio->refcount = 1; - - dio->should_dirty = (iter->type == ITER_IOVEC); - sdio.iter = iter; - sdio.final_block_in_request = - (offset + iov_iter_count(iter)) >> blkbits; - - /* - * In case of non-aligned buffers, we may need 2 more - * pages since we need to zero out first and last block. - */ - if (unlikely(sdio.blkfactor)) - sdio.pages_in_io = 2; - - sdio.pages_in_io += iov_iter_npages(iter, INT_MAX); - - blk_start_plug(&plug); - - retval = do_direct_IO(dio, &sdio, &map_bh); - if (retval) - dio_cleanup(dio, &sdio); - - if (retval == -ENOTBLK) { - /* - * The remaining part of the request will be - * be handled by buffered I/O when we return - */ - retval = 0; - } - /* - * There may be some unwritten disk at the end of a part-written - * fs-block-sized block. Go zero that now. - */ - dio_zero_block(dio, &sdio, 1, &map_bh); - - if (sdio.cur_page) { - ssize_t ret2; - - ret2 = dio_send_cur_page(dio, &sdio, &map_bh); - if (retval == 0) - retval = ret2; - put_page(sdio.cur_page); - sdio.cur_page = NULL; - } - if (sdio.bio) - dio_bio_submit(dio, &sdio); - - blk_finish_plug(&plug); - - /* - * It is possible that, we return short IO due to end of file. - * In that case, we need to release all the pages we got hold on. - */ - dio_cleanup(dio, &sdio); - - /* - * All block lookups have been performed. For READ requests - * we can let i_mutex go now that its achieved its purpose - * of protecting us from looking up uninitialized blocks. - */ - if (iov_iter_rw(iter) == READ && (dio->flags & DIO_LOCKING)) - inode_unlock(dio->inode); - - /* - * The only time we want to leave bios in flight is when a successful - * partial aio read or full aio write have been setup. In that case - * bio completion will call aio_complete. The only time it's safe to - * call aio_complete is when we return -EIOCBQUEUED, so we key on that. - * This had *better* be the only place that raises -EIOCBQUEUED. - */ - BUG_ON(retval == -EIOCBQUEUED); - if (dio->is_async && retval == 0 && dio->result && - (iov_iter_rw(iter) == READ || dio->result == count)) - retval = -EIOCBQUEUED; - else - dio_await_completion(dio); - - if (drop_refcount(dio) == 0) { - retval = dio_complete(dio, retval, false); - } else - BUG_ON(retval != -EIOCBQUEUED); - -out: - return retval; -} - -ssize_t __blockdev_direct_IO(struct kiocb *iocb, struct inode *inode, - struct block_device *bdev, struct iov_iter *iter, - get_block_t get_block, - dio_iodone_t end_io, dio_submit_t submit_io, - int flags) -{ - /* - * The block device state is needed in the end to finally - * submit everything. Since it's likely to be cache cold - * prefetch it here as first thing to hide some of the - * latency. - * - * Attempt to prefetch the pieces we likely need later. - */ - prefetch(&bdev->bd_disk->part_tbl); - prefetch(bdev->bd_queue); - prefetch((char *)bdev->bd_queue + SMP_CACHE_BYTES); - - return do_blockdev_direct_IO(iocb, inode, bdev, iter, get_block, - end_io, submit_io, flags); -} - -EXPORT_SYMBOL(__blockdev_direct_IO); - -static __init int dio_init(void) -{ - dio_cache = KMEM_CACHE(dio, SLAB_PANIC); - return 0; -} -module_init(dio_init) diff --git a/src/linux/fs/dlm/Kconfig b/src/linux/fs/dlm/Kconfig deleted file mode 100644 index e4242c3..0000000 --- a/src/linux/fs/dlm/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -menuconfig DLM - tristate "Distributed Lock Manager (DLM)" - depends on INET - depends on SYSFS && CONFIGFS_FS && (IPV6 || IPV6=n) - select IP_SCTP - help - A general purpose distributed lock manager for kernel or userspace - applications. - -config DLM_DEBUG - bool "DLM debugging" - depends on DLM - help - Under the debugfs mount point, the name of each lockspace will - appear as a file in the "dlm" directory. The output is the - list of resource and locks the local node knows about. diff --git a/src/linux/fs/drop_caches.c b/src/linux/fs/drop_caches.c deleted file mode 100644 index d72d52b..0000000 --- a/src/linux/fs/drop_caches.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Implement the manual drop-all-pagecache function - */ - -#include -#include -#include -#include -#include -#include -#include "internal.h" - -/* A global variable is a bit ugly, but it keeps the code simple */ -int sysctl_drop_caches; - -static void drop_pagecache_sb(struct super_block *sb, void *unused) -{ - struct inode *inode, *toput_inode = NULL; - - spin_lock(&sb->s_inode_list_lock); - list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { - spin_lock(&inode->i_lock); - if ((inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) || - (inode->i_mapping->nrpages == 0)) { - spin_unlock(&inode->i_lock); - continue; - } - __iget(inode); - spin_unlock(&inode->i_lock); - spin_unlock(&sb->s_inode_list_lock); - - invalidate_mapping_pages(inode->i_mapping, 0, -1); - iput(toput_inode); - toput_inode = inode; - - spin_lock(&sb->s_inode_list_lock); - } - spin_unlock(&sb->s_inode_list_lock); - iput(toput_inode); -} - -int drop_caches_sysctl_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *length, loff_t *ppos) -{ - int ret; - - ret = proc_dointvec_minmax(table, write, buffer, length, ppos); - if (ret) - return ret; - if (write) { - static int stfu; - - if (sysctl_drop_caches & 1) { - iterate_supers(drop_pagecache_sb, NULL); - count_vm_event(DROP_PAGECACHE); - } - if (sysctl_drop_caches & 2) { - drop_slab(); - count_vm_event(DROP_SLAB); - } - if (!stfu) { - pr_info("%s (%d): drop_caches: %d\n", - current->comm, task_pid_nr(current), - sysctl_drop_caches); - } - stfu |= sysctl_drop_caches & 4; - } - return 0; -} diff --git a/src/linux/fs/ecryptfs/Kconfig b/src/linux/fs/ecryptfs/Kconfig deleted file mode 100644 index 434aa31..0000000 --- a/src/linux/fs/ecryptfs/Kconfig +++ /dev/null @@ -1,22 +0,0 @@ -config ECRYPT_FS - tristate "eCrypt filesystem layer support" - depends on KEYS && CRYPTO && (ENCRYPTED_KEYS || ENCRYPTED_KEYS=n) - select CRYPTO_ECB - select CRYPTO_CBC - select CRYPTO_MD5 - help - Encrypted filesystem that operates on the VFS layer. See - to learn more about - eCryptfs. Userspace components are required and can be - obtained from . - - To compile this file system support as a module, choose M here: the - module will be called ecryptfs. - -config ECRYPT_FS_MESSAGING - bool "Enable notifications for userspace key wrap/unwrap" - depends on ECRYPT_FS - help - Enables the /dev/ecryptfs entry for use by ecryptfsd. This allows - for userspace to wrap/unwrap file encryption keys by other - backends, like OpenSSL. diff --git a/src/linux/fs/efivarfs/Kconfig b/src/linux/fs/efivarfs/Kconfig deleted file mode 100644 index c2499ef..0000000 --- a/src/linux/fs/efivarfs/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config EFIVAR_FS - tristate "EFI Variable filesystem" - depends on EFI - default m - help - efivarfs is a replacement filesystem for the old EFI - variable support via sysfs, as it doesn't suffer from the - same 1024-byte variable size limit. - - To compile this file system support as a module, choose M - here. The module will be called efivarfs. - - If unsure, say N. diff --git a/src/linux/fs/efs/Kconfig b/src/linux/fs/efs/Kconfig deleted file mode 100644 index d020e3c..0000000 --- a/src/linux/fs/efs/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config EFS_FS - tristate "EFS file system support (read only)" - depends on BLOCK - help - EFS is an older file system used for non-ISO9660 CD-ROMs and hard - disk partitions by SGI's IRIX operating system (IRIX 6.0 and newer - uses the XFS file system for hard disk partitions however). - - This implementation only offers read-only access. If you don't know - what all this is about, it's safe to say N. For more information - about EFS see its home page at . - - To compile the EFS file system support as a module, choose M here: the - module will be called efs. diff --git a/src/linux/fs/eventfd.c b/src/linux/fs/eventfd.c deleted file mode 100644 index 1231cd1..0000000 --- a/src/linux/fs/eventfd.c +++ /dev/null @@ -1,487 +0,0 @@ -/* - * fs/eventfd.c - * - * Copyright (C) 2007 Davide Libenzi - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct eventfd_ctx { - struct kref kref; - wait_queue_head_t wqh; - /* - * Every time that a write(2) is performed on an eventfd, the - * value of the __u64 being written is added to "count" and a - * wakeup is performed on "wqh". A read(2) will return the "count" - * value to userspace, and will reset "count" to zero. The kernel - * side eventfd_signal() also, adds to the "count" counter and - * issue a wakeup. - */ - __u64 count; - unsigned int flags; -}; - -/** - * eventfd_signal - Adds @n to the eventfd counter. - * @ctx: [in] Pointer to the eventfd context. - * @n: [in] Value of the counter to be added to the eventfd internal counter. - * The value cannot be negative. - * - * This function is supposed to be called by the kernel in paths that do not - * allow sleeping. In this function we allow the counter to reach the ULLONG_MAX - * value, and we signal this as overflow condition by returning a POLLERR - * to poll(2). - * - * Returns the amount by which the counter was incremented. This will be less - * than @n if the counter has overflowed. - */ -__u64 eventfd_signal(struct eventfd_ctx *ctx, __u64 n) -{ - unsigned long flags; - - spin_lock_irqsave(&ctx->wqh.lock, flags); - if (ULLONG_MAX - ctx->count < n) - n = ULLONG_MAX - ctx->count; - ctx->count += n; - if (waitqueue_active(&ctx->wqh)) - wake_up_locked_poll(&ctx->wqh, POLLIN); - spin_unlock_irqrestore(&ctx->wqh.lock, flags); - - return n; -} -EXPORT_SYMBOL_GPL(eventfd_signal); - -static void eventfd_free_ctx(struct eventfd_ctx *ctx) -{ - kfree(ctx); -} - -static void eventfd_free(struct kref *kref) -{ - struct eventfd_ctx *ctx = container_of(kref, struct eventfd_ctx, kref); - - eventfd_free_ctx(ctx); -} - -/** - * eventfd_ctx_get - Acquires a reference to the internal eventfd context. - * @ctx: [in] Pointer to the eventfd context. - * - * Returns: In case of success, returns a pointer to the eventfd context. - */ -struct eventfd_ctx *eventfd_ctx_get(struct eventfd_ctx *ctx) -{ - kref_get(&ctx->kref); - return ctx; -} -EXPORT_SYMBOL_GPL(eventfd_ctx_get); - -/** - * eventfd_ctx_put - Releases a reference to the internal eventfd context. - * @ctx: [in] Pointer to eventfd context. - * - * The eventfd context reference must have been previously acquired either - * with eventfd_ctx_get() or eventfd_ctx_fdget(). - */ -void eventfd_ctx_put(struct eventfd_ctx *ctx) -{ - kref_put(&ctx->kref, eventfd_free); -} -EXPORT_SYMBOL_GPL(eventfd_ctx_put); - -static int eventfd_release(struct inode *inode, struct file *file) -{ - struct eventfd_ctx *ctx = file->private_data; - - wake_up_poll(&ctx->wqh, POLLHUP); - eventfd_ctx_put(ctx); - return 0; -} - -static unsigned int eventfd_poll(struct file *file, poll_table *wait) -{ - struct eventfd_ctx *ctx = file->private_data; - unsigned int events = 0; - u64 count; - - poll_wait(file, &ctx->wqh, wait); - - /* - * All writes to ctx->count occur within ctx->wqh.lock. This read - * can be done outside ctx->wqh.lock because we know that poll_wait - * takes that lock (through add_wait_queue) if our caller will sleep. - * - * The read _can_ therefore seep into add_wait_queue's critical - * section, but cannot move above it! add_wait_queue's spin_lock acts - * as an acquire barrier and ensures that the read be ordered properly - * against the writes. The following CAN happen and is safe: - * - * poll write - * ----------------- ------------ - * lock ctx->wqh.lock (in poll_wait) - * count = ctx->count - * __add_wait_queue - * unlock ctx->wqh.lock - * lock ctx->qwh.lock - * ctx->count += n - * if (waitqueue_active) - * wake_up_locked_poll - * unlock ctx->qwh.lock - * eventfd_poll returns 0 - * - * but the following, which would miss a wakeup, cannot happen: - * - * poll write - * ----------------- ------------ - * count = ctx->count (INVALID!) - * lock ctx->qwh.lock - * ctx->count += n - * **waitqueue_active is false** - * **no wake_up_locked_poll!** - * unlock ctx->qwh.lock - * lock ctx->wqh.lock (in poll_wait) - * __add_wait_queue - * unlock ctx->wqh.lock - * eventfd_poll returns 0 - */ - count = READ_ONCE(ctx->count); - - if (count > 0) - events |= POLLIN; - if (count == ULLONG_MAX) - events |= POLLERR; - if (ULLONG_MAX - 1 > count) - events |= POLLOUT; - - return events; -} - -static void eventfd_ctx_do_read(struct eventfd_ctx *ctx, __u64 *cnt) -{ - *cnt = (ctx->flags & EFD_SEMAPHORE) ? 1 : ctx->count; - ctx->count -= *cnt; -} - -/** - * eventfd_ctx_remove_wait_queue - Read the current counter and removes wait queue. - * @ctx: [in] Pointer to eventfd context. - * @wait: [in] Wait queue to be removed. - * @cnt: [out] Pointer to the 64-bit counter value. - * - * Returns %0 if successful, or the following error codes: - * - * -EAGAIN : The operation would have blocked. - * - * This is used to atomically remove a wait queue entry from the eventfd wait - * queue head, and read/reset the counter value. - */ -int eventfd_ctx_remove_wait_queue(struct eventfd_ctx *ctx, wait_queue_t *wait, - __u64 *cnt) -{ - unsigned long flags; - - spin_lock_irqsave(&ctx->wqh.lock, flags); - eventfd_ctx_do_read(ctx, cnt); - __remove_wait_queue(&ctx->wqh, wait); - if (*cnt != 0 && waitqueue_active(&ctx->wqh)) - wake_up_locked_poll(&ctx->wqh, POLLOUT); - spin_unlock_irqrestore(&ctx->wqh.lock, flags); - - return *cnt != 0 ? 0 : -EAGAIN; -} -EXPORT_SYMBOL_GPL(eventfd_ctx_remove_wait_queue); - -/** - * eventfd_ctx_read - Reads the eventfd counter or wait if it is zero. - * @ctx: [in] Pointer to eventfd context. - * @no_wait: [in] Different from zero if the operation should not block. - * @cnt: [out] Pointer to the 64-bit counter value. - * - * Returns %0 if successful, or the following error codes: - * - * -EAGAIN : The operation would have blocked but @no_wait was non-zero. - * -ERESTARTSYS : A signal interrupted the wait operation. - * - * If @no_wait is zero, the function might sleep until the eventfd internal - * counter becomes greater than zero. - */ -ssize_t eventfd_ctx_read(struct eventfd_ctx *ctx, int no_wait, __u64 *cnt) -{ - ssize_t res; - DECLARE_WAITQUEUE(wait, current); - - spin_lock_irq(&ctx->wqh.lock); - *cnt = 0; - res = -EAGAIN; - if (ctx->count > 0) - res = 0; - else if (!no_wait) { - __add_wait_queue(&ctx->wqh, &wait); - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (ctx->count > 0) { - res = 0; - break; - } - if (signal_pending(current)) { - res = -ERESTARTSYS; - break; - } - spin_unlock_irq(&ctx->wqh.lock); - schedule(); - spin_lock_irq(&ctx->wqh.lock); - } - __remove_wait_queue(&ctx->wqh, &wait); - __set_current_state(TASK_RUNNING); - } - if (likely(res == 0)) { - eventfd_ctx_do_read(ctx, cnt); - if (waitqueue_active(&ctx->wqh)) - wake_up_locked_poll(&ctx->wqh, POLLOUT); - } - spin_unlock_irq(&ctx->wqh.lock); - - return res; -} -EXPORT_SYMBOL_GPL(eventfd_ctx_read); - -static ssize_t eventfd_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - struct eventfd_ctx *ctx = file->private_data; - ssize_t res; - __u64 cnt; - - if (count < sizeof(cnt)) - return -EINVAL; - res = eventfd_ctx_read(ctx, file->f_flags & O_NONBLOCK, &cnt); - if (res < 0) - return res; - - return put_user(cnt, (__u64 __user *) buf) ? -EFAULT : sizeof(cnt); -} - -static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t count, - loff_t *ppos) -{ - struct eventfd_ctx *ctx = file->private_data; - ssize_t res; - __u64 ucnt; - DECLARE_WAITQUEUE(wait, current); - - if (count < sizeof(ucnt)) - return -EINVAL; - if (copy_from_user(&ucnt, buf, sizeof(ucnt))) - return -EFAULT; - if (ucnt == ULLONG_MAX) - return -EINVAL; - spin_lock_irq(&ctx->wqh.lock); - res = -EAGAIN; - if (ULLONG_MAX - ctx->count > ucnt) - res = sizeof(ucnt); - else if (!(file->f_flags & O_NONBLOCK)) { - __add_wait_queue(&ctx->wqh, &wait); - for (res = 0;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (ULLONG_MAX - ctx->count > ucnt) { - res = sizeof(ucnt); - break; - } - if (signal_pending(current)) { - res = -ERESTARTSYS; - break; - } - spin_unlock_irq(&ctx->wqh.lock); - schedule(); - spin_lock_irq(&ctx->wqh.lock); - } - __remove_wait_queue(&ctx->wqh, &wait); - __set_current_state(TASK_RUNNING); - } - if (likely(res > 0)) { - ctx->count += ucnt; - if (waitqueue_active(&ctx->wqh)) - wake_up_locked_poll(&ctx->wqh, POLLIN); - } - spin_unlock_irq(&ctx->wqh.lock); - - return res; -} - -#ifdef CONFIG_PROC_FS -static void eventfd_show_fdinfo(struct seq_file *m, struct file *f) -{ - struct eventfd_ctx *ctx = f->private_data; - - spin_lock_irq(&ctx->wqh.lock); - seq_printf(m, "eventfd-count: %16llx\n", - (unsigned long long)ctx->count); - spin_unlock_irq(&ctx->wqh.lock); -} -#endif - -static const struct file_operations eventfd_fops = { -#ifdef CONFIG_PROC_FS - .show_fdinfo = eventfd_show_fdinfo, -#endif - .release = eventfd_release, - .poll = eventfd_poll, - .read = eventfd_read, - .write = eventfd_write, - .llseek = noop_llseek, -}; - -/** - * eventfd_fget - Acquire a reference of an eventfd file descriptor. - * @fd: [in] Eventfd file descriptor. - * - * Returns a pointer to the eventfd file structure in case of success, or the - * following error pointer: - * - * -EBADF : Invalid @fd file descriptor. - * -EINVAL : The @fd file descriptor is not an eventfd file. - */ -struct file *eventfd_fget(int fd) -{ - struct file *file; - - file = fget(fd); - if (!file) - return ERR_PTR(-EBADF); - if (file->f_op != &eventfd_fops) { - fput(file); - return ERR_PTR(-EINVAL); - } - - return file; -} -EXPORT_SYMBOL_GPL(eventfd_fget); - -/** - * eventfd_ctx_fdget - Acquires a reference to the internal eventfd context. - * @fd: [in] Eventfd file descriptor. - * - * Returns a pointer to the internal eventfd context, otherwise the error - * pointers returned by the following functions: - * - * eventfd_fget - */ -struct eventfd_ctx *eventfd_ctx_fdget(int fd) -{ - struct eventfd_ctx *ctx; - struct fd f = fdget(fd); - if (!f.file) - return ERR_PTR(-EBADF); - ctx = eventfd_ctx_fileget(f.file); - fdput(f); - return ctx; -} -EXPORT_SYMBOL_GPL(eventfd_ctx_fdget); - -/** - * eventfd_ctx_fileget - Acquires a reference to the internal eventfd context. - * @file: [in] Eventfd file pointer. - * - * Returns a pointer to the internal eventfd context, otherwise the error - * pointer: - * - * -EINVAL : The @fd file descriptor is not an eventfd file. - */ -struct eventfd_ctx *eventfd_ctx_fileget(struct file *file) -{ - if (file->f_op != &eventfd_fops) - return ERR_PTR(-EINVAL); - - return eventfd_ctx_get(file->private_data); -} -EXPORT_SYMBOL_GPL(eventfd_ctx_fileget); - -/** - * eventfd_file_create - Creates an eventfd file pointer. - * @count: Initial eventfd counter value. - * @flags: Flags for the eventfd file. - * - * This function creates an eventfd file pointer, w/out installing it into - * the fd table. This is useful when the eventfd file is used during the - * initialization of data structures that require extra setup after the eventfd - * creation. So the eventfd creation is split into the file pointer creation - * phase, and the file descriptor installation phase. - * In this way races with userspace closing the newly installed file descriptor - * can be avoided. - * Returns an eventfd file pointer, or a proper error pointer. - */ -struct file *eventfd_file_create(unsigned int count, int flags) -{ - struct file *file; - struct eventfd_ctx *ctx; - - /* Check the EFD_* constants for consistency. */ - BUILD_BUG_ON(EFD_CLOEXEC != O_CLOEXEC); - BUILD_BUG_ON(EFD_NONBLOCK != O_NONBLOCK); - - if (flags & ~EFD_FLAGS_SET) - return ERR_PTR(-EINVAL); - - ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return ERR_PTR(-ENOMEM); - - kref_init(&ctx->kref); - init_waitqueue_head(&ctx->wqh); - ctx->count = count; - ctx->flags = flags; - - file = anon_inode_getfile("[eventfd]", &eventfd_fops, ctx, - O_RDWR | (flags & EFD_SHARED_FCNTL_FLAGS)); - if (IS_ERR(file)) - eventfd_free_ctx(ctx); - - return file; -} - -SYSCALL_DEFINE2(eventfd2, unsigned int, count, int, flags) -{ - int fd, error; - struct file *file; - - error = get_unused_fd_flags(flags & EFD_SHARED_FCNTL_FLAGS); - if (error < 0) - return error; - fd = error; - - file = eventfd_file_create(count, flags); - if (IS_ERR(file)) { - error = PTR_ERR(file); - goto err_put_unused_fd; - } - fd_install(fd, file); - - return fd; - -err_put_unused_fd: - put_unused_fd(fd); - - return error; -} - -SYSCALL_DEFINE1(eventfd, unsigned int, count) -{ - return sys_eventfd2(count, 0); -} - diff --git a/src/linux/fs/eventpoll.c b/src/linux/fs/eventpoll.c deleted file mode 100644 index 10db912..0000000 --- a/src/linux/fs/eventpoll.c +++ /dev/null @@ -1,2177 +0,0 @@ -/* - * fs/eventpoll.c (Efficient event retrieval implementation) - * Copyright (C) 2001,...,2009 Davide Libenzi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Davide Libenzi - * - */ - -#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 -#include -#include -#include - -/* - * LOCKING: - * There are three level of locking required by epoll : - * - * 1) epmutex (mutex) - * 2) ep->mtx (mutex) - * 3) ep->lock (spinlock) - * - * The acquire order is the one listed above, from 1 to 3. - * We need a spinlock (ep->lock) because we manipulate objects - * from inside the poll callback, that might be triggered from - * a wake_up() that in turn might be called from IRQ context. - * So we can't sleep inside the poll callback and hence we need - * a spinlock. During the event transfer loop (from kernel to - * user space) we could end up sleeping due a copy_to_user(), so - * we need a lock that will allow us to sleep. This lock is a - * mutex (ep->mtx). It is acquired during the event transfer loop, - * during epoll_ctl(EPOLL_CTL_DEL) and during eventpoll_release_file(). - * Then we also need a global mutex to serialize eventpoll_release_file() - * and ep_free(). - * This mutex is acquired by ep_free() during the epoll file - * cleanup path and it is also acquired by eventpoll_release_file() - * if a file has been pushed inside an epoll set and it is then - * close()d without a previous call to epoll_ctl(EPOLL_CTL_DEL). - * It is also acquired when inserting an epoll fd onto another epoll - * fd. We do this so that we walk the epoll tree and ensure that this - * insertion does not create a cycle of epoll file descriptors, which - * could lead to deadlock. We need a global mutex to prevent two - * simultaneous inserts (A into B and B into A) from racing and - * constructing a cycle without either insert observing that it is - * going to. - * It is necessary to acquire multiple "ep->mtx"es at once in the - * case when one epoll fd is added to another. In this case, we - * always acquire the locks in the order of nesting (i.e. after - * epoll_ctl(e1, EPOLL_CTL_ADD, e2), e1->mtx will always be acquired - * before e2->mtx). Since we disallow cycles of epoll file - * descriptors, this ensures that the mutexes are well-ordered. In - * order to communicate this nesting to lockdep, when walking a tree - * of epoll file descriptors, we use the current recursion depth as - * the lockdep subkey. - * It is possible to drop the "ep->mtx" and to use the global - * mutex "epmutex" (together with "ep->lock") to have it working, - * but having "ep->mtx" will make the interface more scalable. - * Events that require holding "epmutex" are very rare, while for - * normal operations the epoll private "ep->mtx" will guarantee - * a better scalability. - */ - -/* Epoll private bits inside the event mask */ -#define EP_PRIVATE_BITS (EPOLLWAKEUP | EPOLLONESHOT | EPOLLET | EPOLLEXCLUSIVE) - -#define EPOLLINOUT_BITS (POLLIN | POLLOUT) - -#define EPOLLEXCLUSIVE_OK_BITS (EPOLLINOUT_BITS | POLLERR | POLLHUP | \ - EPOLLWAKEUP | EPOLLET | EPOLLEXCLUSIVE) - -/* Maximum number of nesting allowed inside epoll sets */ -#define EP_MAX_NESTS 4 - -#define EP_MAX_EVENTS (INT_MAX / sizeof(struct epoll_event)) - -#define EP_UNACTIVE_PTR ((void *) -1L) - -#define EP_ITEM_COST (sizeof(struct epitem) + sizeof(struct eppoll_entry)) - -struct epoll_filefd { - struct file *file; - int fd; -} __packed; - -/* - * Structure used to track possible nested calls, for too deep recursions - * and loop cycles. - */ -struct nested_call_node { - struct list_head llink; - void *cookie; - void *ctx; -}; - -/* - * This structure is used as collector for nested calls, to check for - * maximum recursion dept and loop cycles. - */ -struct nested_calls { - struct list_head tasks_call_list; - spinlock_t lock; -}; - -/* - * Each file descriptor added to the eventpoll interface will - * have an entry of this type linked to the "rbr" RB tree. - * Avoid increasing the size of this struct, there can be many thousands - * of these on a server and we do not want this to take another cache line. - */ -struct epitem { - union { - /* RB tree node links this structure to the eventpoll RB tree */ - struct rb_node rbn; - /* Used to free the struct epitem */ - struct rcu_head rcu; - }; - - /* List header used to link this structure to the eventpoll ready list */ - struct list_head rdllink; - - /* - * Works together "struct eventpoll"->ovflist in keeping the - * single linked chain of items. - */ - struct epitem *next; - - /* The file descriptor information this item refers to */ - struct epoll_filefd ffd; - - /* Number of active wait queue attached to poll operations */ - int nwait; - - /* List containing poll wait queues */ - struct list_head pwqlist; - - /* The "container" of this item */ - struct eventpoll *ep; - - /* List header used to link this item to the "struct file" items list */ - struct list_head fllink; - - /* wakeup_source used when EPOLLWAKEUP is set */ - struct wakeup_source __rcu *ws; - - /* The structure that describe the interested events and the source fd */ - struct epoll_event event; -}; - -/* - * This structure is stored inside the "private_data" member of the file - * structure and represents the main data structure for the eventpoll - * interface. - */ -struct eventpoll { - /* Protect the access to this structure */ - spinlock_t lock; - - /* - * This mutex is used to ensure that files are not removed - * while epoll is using them. This is held during the event - * collection loop, the file cleanup path, the epoll file exit - * code and the ctl operations. - */ - struct mutex mtx; - - /* Wait queue used by sys_epoll_wait() */ - wait_queue_head_t wq; - - /* Wait queue used by file->poll() */ - wait_queue_head_t poll_wait; - - /* List of ready file descriptors */ - struct list_head rdllist; - - /* RB tree root used to store monitored fd structs */ - struct rb_root rbr; - - /* - * This is a single linked list that chains all the "struct epitem" that - * happened while transferring ready events to userspace w/out - * holding ->lock. - */ - struct epitem *ovflist; - - /* wakeup_source used when ep_scan_ready_list is running */ - struct wakeup_source *ws; - - /* The user that created the eventpoll descriptor */ - struct user_struct *user; - - struct file *file; - - /* used to optimize loop detection check */ - int visited; - struct list_head visited_list_link; -}; - -/* Wait structure used by the poll hooks */ -struct eppoll_entry { - /* List header used to link this structure to the "struct epitem" */ - struct list_head llink; - - /* The "base" pointer is set to the container "struct epitem" */ - struct epitem *base; - - /* - * Wait queue item that will be linked to the target file wait - * queue head. - */ - wait_queue_t wait; - - /* The wait queue head that linked the "wait" wait queue item */ - wait_queue_head_t *whead; -}; - -/* Wrapper struct used by poll queueing */ -struct ep_pqueue { - poll_table pt; - struct epitem *epi; -}; - -/* Used by the ep_send_events() function as callback private data */ -struct ep_send_events_data { - int maxevents; - struct epoll_event __user *events; -}; - -/* - * Configuration options available inside /proc/sys/fs/epoll/ - */ -/* Maximum number of epoll watched descriptors, per user */ -static long max_user_watches __read_mostly; - -/* - * This mutex is used to serialize ep_free() and eventpoll_release_file(). - */ -static DEFINE_MUTEX(epmutex); - -/* Used to check for epoll file descriptor inclusion loops */ -static struct nested_calls poll_loop_ncalls; - -/* Used for safe wake up implementation */ -static struct nested_calls poll_safewake_ncalls; - -/* Used to call file's f_op->poll() under the nested calls boundaries */ -static struct nested_calls poll_readywalk_ncalls; - -/* Slab cache used to allocate "struct epitem" */ -static struct kmem_cache *epi_cache __read_mostly; - -/* Slab cache used to allocate "struct eppoll_entry" */ -static struct kmem_cache *pwq_cache __read_mostly; - -/* Visited nodes during ep_loop_check(), so we can unset them when we finish */ -static LIST_HEAD(visited_list); - -/* - * List of files with newly added links, where we may need to limit the number - * of emanating paths. Protected by the epmutex. - */ -static LIST_HEAD(tfile_check_list); - -#ifdef CONFIG_SYSCTL - -#include - -static long zero; -static long long_max = LONG_MAX; - -struct ctl_table epoll_table[] = { - { - .procname = "max_user_watches", - .data = &max_user_watches, - .maxlen = sizeof(max_user_watches), - .mode = 0644, - .proc_handler = proc_doulongvec_minmax, - .extra1 = &zero, - .extra2 = &long_max, - }, - { } -}; -#endif /* CONFIG_SYSCTL */ - -static const struct file_operations eventpoll_fops; - -static inline int is_file_epoll(struct file *f) -{ - return f->f_op == &eventpoll_fops; -} - -/* Setup the structure that is used as key for the RB tree */ -static inline void ep_set_ffd(struct epoll_filefd *ffd, - struct file *file, int fd) -{ - ffd->file = file; - ffd->fd = fd; -} - -/* Compare RB tree keys */ -static inline int ep_cmp_ffd(struct epoll_filefd *p1, - struct epoll_filefd *p2) -{ - return (p1->file > p2->file ? +1: - (p1->file < p2->file ? -1 : p1->fd - p2->fd)); -} - -/* Tells us if the item is currently linked */ -static inline int ep_is_linked(struct list_head *p) -{ - return !list_empty(p); -} - -static inline struct eppoll_entry *ep_pwq_from_wait(wait_queue_t *p) -{ - return container_of(p, struct eppoll_entry, wait); -} - -/* Get the "struct epitem" from a wait queue pointer */ -static inline struct epitem *ep_item_from_wait(wait_queue_t *p) -{ - return container_of(p, struct eppoll_entry, wait)->base; -} - -/* Get the "struct epitem" from an epoll queue wrapper */ -static inline struct epitem *ep_item_from_epqueue(poll_table *p) -{ - return container_of(p, struct ep_pqueue, pt)->epi; -} - -/* Tells if the epoll_ctl(2) operation needs an event copy from userspace */ -static inline int ep_op_has_event(int op) -{ - return op != EPOLL_CTL_DEL; -} - -/* Initialize the poll safe wake up structure */ -static void ep_nested_calls_init(struct nested_calls *ncalls) -{ - INIT_LIST_HEAD(&ncalls->tasks_call_list); - spin_lock_init(&ncalls->lock); -} - -/** - * ep_events_available - Checks if ready events might be available. - * - * @ep: Pointer to the eventpoll context. - * - * Returns: Returns a value different than zero if ready events are available, - * or zero otherwise. - */ -static inline int ep_events_available(struct eventpoll *ep) -{ - return !list_empty(&ep->rdllist) || ep->ovflist != EP_UNACTIVE_PTR; -} - -/** - * ep_call_nested - Perform a bound (possibly) nested call, by checking - * that the recursion limit is not exceeded, and that - * the same nested call (by the meaning of same cookie) is - * no re-entered. - * - * @ncalls: Pointer to the nested_calls structure to be used for this call. - * @max_nests: Maximum number of allowed nesting calls. - * @nproc: Nested call core function pointer. - * @priv: Opaque data to be passed to the @nproc callback. - * @cookie: Cookie to be used to identify this nested call. - * @ctx: This instance context. - * - * Returns: Returns the code returned by the @nproc callback, or -1 if - * the maximum recursion limit has been exceeded. - */ -static int ep_call_nested(struct nested_calls *ncalls, int max_nests, - int (*nproc)(void *, void *, int), void *priv, - void *cookie, void *ctx) -{ - int error, call_nests = 0; - unsigned long flags; - struct list_head *lsthead = &ncalls->tasks_call_list; - struct nested_call_node *tncur; - struct nested_call_node tnode; - - spin_lock_irqsave(&ncalls->lock, flags); - - /* - * Try to see if the current task is already inside this wakeup call. - * We use a list here, since the population inside this set is always - * very much limited. - */ - list_for_each_entry(tncur, lsthead, llink) { - if (tncur->ctx == ctx && - (tncur->cookie == cookie || ++call_nests > max_nests)) { - /* - * Ops ... loop detected or maximum nest level reached. - * We abort this wake by breaking the cycle itself. - */ - error = -1; - goto out_unlock; - } - } - - /* Add the current task and cookie to the list */ - tnode.ctx = ctx; - tnode.cookie = cookie; - list_add(&tnode.llink, lsthead); - - spin_unlock_irqrestore(&ncalls->lock, flags); - - /* Call the nested function */ - error = (*nproc)(priv, cookie, call_nests); - - /* Remove the current task from the list */ - spin_lock_irqsave(&ncalls->lock, flags); - list_del(&tnode.llink); -out_unlock: - spin_unlock_irqrestore(&ncalls->lock, flags); - - return error; -} - -/* - * As described in commit 0ccf831cb lockdep: annotate epoll - * the use of wait queues used by epoll is done in a very controlled - * manner. Wake ups can nest inside each other, but are never done - * with the same locking. For example: - * - * dfd = socket(...); - * efd1 = epoll_create(); - * efd2 = epoll_create(); - * epoll_ctl(efd1, EPOLL_CTL_ADD, dfd, ...); - * epoll_ctl(efd2, EPOLL_CTL_ADD, efd1, ...); - * - * When a packet arrives to the device underneath "dfd", the net code will - * issue a wake_up() on its poll wake list. Epoll (efd1) has installed a - * callback wakeup entry on that queue, and the wake_up() performed by the - * "dfd" net code will end up in ep_poll_callback(). At this point epoll - * (efd1) notices that it may have some event ready, so it needs to wake up - * the waiters on its poll wait list (efd2). So it calls ep_poll_safewake() - * that ends up in another wake_up(), after having checked about the - * recursion constraints. That are, no more than EP_MAX_POLLWAKE_NESTS, to - * avoid stack blasting. - * - * When CONFIG_DEBUG_LOCK_ALLOC is enabled, make sure lockdep can handle - * this special case of epoll. - */ -#ifdef CONFIG_DEBUG_LOCK_ALLOC -static inline void ep_wake_up_nested(wait_queue_head_t *wqueue, - unsigned long events, int subclass) -{ - unsigned long flags; - - spin_lock_irqsave_nested(&wqueue->lock, flags, subclass); - wake_up_locked_poll(wqueue, events); - spin_unlock_irqrestore(&wqueue->lock, flags); -} -#else -static inline void ep_wake_up_nested(wait_queue_head_t *wqueue, - unsigned long events, int subclass) -{ - wake_up_poll(wqueue, events); -} -#endif - -static int ep_poll_wakeup_proc(void *priv, void *cookie, int call_nests) -{ - ep_wake_up_nested((wait_queue_head_t *) cookie, POLLIN, - 1 + call_nests); - return 0; -} - -/* - * Perform a safe wake up of the poll wait list. The problem is that - * with the new callback'd wake up system, it is possible that the - * poll callback is reentered from inside the call to wake_up() done - * on the poll wait queue head. The rule is that we cannot reenter the - * wake up code from the same task more than EP_MAX_NESTS times, - * and we cannot reenter the same wait queue head at all. This will - * enable to have a hierarchy of epoll file descriptor of no more than - * EP_MAX_NESTS deep. - */ -static void ep_poll_safewake(wait_queue_head_t *wq) -{ - int this_cpu = get_cpu(); - - ep_call_nested(&poll_safewake_ncalls, EP_MAX_NESTS, - ep_poll_wakeup_proc, NULL, wq, (void *) (long) this_cpu); - - put_cpu(); -} - -static void ep_remove_wait_queue(struct eppoll_entry *pwq) -{ - wait_queue_head_t *whead; - - rcu_read_lock(); - /* If it is cleared by POLLFREE, it should be rcu-safe */ - whead = rcu_dereference(pwq->whead); - if (whead) - remove_wait_queue(whead, &pwq->wait); - rcu_read_unlock(); -} - -/* - * This function unregisters poll callbacks from the associated file - * descriptor. Must be called with "mtx" held (or "epmutex" if called from - * ep_free). - */ -static void ep_unregister_pollwait(struct eventpoll *ep, struct epitem *epi) -{ - struct list_head *lsthead = &epi->pwqlist; - struct eppoll_entry *pwq; - - while (!list_empty(lsthead)) { - pwq = list_first_entry(lsthead, struct eppoll_entry, llink); - - list_del(&pwq->llink); - ep_remove_wait_queue(pwq); - kmem_cache_free(pwq_cache, pwq); - } -} - -/* call only when ep->mtx is held */ -static inline struct wakeup_source *ep_wakeup_source(struct epitem *epi) -{ - return rcu_dereference_check(epi->ws, lockdep_is_held(&epi->ep->mtx)); -} - -/* call only when ep->mtx is held */ -static inline void ep_pm_stay_awake(struct epitem *epi) -{ - struct wakeup_source *ws = ep_wakeup_source(epi); - - if (ws) - __pm_stay_awake(ws); -} - -static inline bool ep_has_wakeup_source(struct epitem *epi) -{ - return rcu_access_pointer(epi->ws) ? true : false; -} - -/* call when ep->mtx cannot be held (ep_poll_callback) */ -static inline void ep_pm_stay_awake_rcu(struct epitem *epi) -{ - struct wakeup_source *ws; - - rcu_read_lock(); - ws = rcu_dereference(epi->ws); - if (ws) - __pm_stay_awake(ws); - rcu_read_unlock(); -} - -/** - * ep_scan_ready_list - Scans the ready list in a way that makes possible for - * the scan code, to call f_op->poll(). Also allows for - * O(NumReady) performance. - * - * @ep: Pointer to the epoll private data structure. - * @sproc: Pointer to the scan callback. - * @priv: Private opaque data passed to the @sproc callback. - * @depth: The current depth of recursive f_op->poll calls. - * @ep_locked: caller already holds ep->mtx - * - * Returns: The same integer error code returned by the @sproc callback. - */ -static int ep_scan_ready_list(struct eventpoll *ep, - int (*sproc)(struct eventpoll *, - struct list_head *, void *), - void *priv, int depth, bool ep_locked) -{ - int error, pwake = 0; - unsigned long flags; - struct epitem *epi, *nepi; - LIST_HEAD(txlist); - - /* - * We need to lock this because we could be hit by - * eventpoll_release_file() and epoll_ctl(). - */ - - if (!ep_locked) - mutex_lock_nested(&ep->mtx, depth); - - /* - * Steal the ready list, and re-init the original one to the - * empty list. Also, set ep->ovflist to NULL so that events - * happening while looping w/out locks, are not lost. We cannot - * have the poll callback to queue directly on ep->rdllist, - * because we want the "sproc" callback to be able to do it - * in a lockless way. - */ - spin_lock_irqsave(&ep->lock, flags); - list_splice_init(&ep->rdllist, &txlist); - ep->ovflist = NULL; - spin_unlock_irqrestore(&ep->lock, flags); - - /* - * Now call the callback function. - */ - error = (*sproc)(ep, &txlist, priv); - - spin_lock_irqsave(&ep->lock, flags); - /* - * During the time we spent inside the "sproc" callback, some - * other events might have been queued by the poll callback. - * We re-insert them inside the main ready-list here. - */ - for (nepi = ep->ovflist; (epi = nepi) != NULL; - nepi = epi->next, epi->next = EP_UNACTIVE_PTR) { - /* - * We need to check if the item is already in the list. - * During the "sproc" callback execution time, items are - * queued into ->ovflist but the "txlist" might already - * contain them, and the list_splice() below takes care of them. - */ - if (!ep_is_linked(&epi->rdllink)) { - list_add_tail(&epi->rdllink, &ep->rdllist); - ep_pm_stay_awake(epi); - } - } - /* - * We need to set back ep->ovflist to EP_UNACTIVE_PTR, so that after - * releasing the lock, events will be queued in the normal way inside - * ep->rdllist. - */ - ep->ovflist = EP_UNACTIVE_PTR; - - /* - * Quickly re-inject items left on "txlist". - */ - list_splice(&txlist, &ep->rdllist); - __pm_relax(ep->ws); - - if (!list_empty(&ep->rdllist)) { - /* - * Wake up (if active) both the eventpoll wait list and - * the ->poll() wait list (delayed after we release the lock). - */ - if (waitqueue_active(&ep->wq)) - wake_up_locked(&ep->wq); - if (waitqueue_active(&ep->poll_wait)) - pwake++; - } - spin_unlock_irqrestore(&ep->lock, flags); - - if (!ep_locked) - mutex_unlock(&ep->mtx); - - /* We have to call this outside the lock */ - if (pwake) - ep_poll_safewake(&ep->poll_wait); - - return error; -} - -static void epi_rcu_free(struct rcu_head *head) -{ - struct epitem *epi = container_of(head, struct epitem, rcu); - kmem_cache_free(epi_cache, epi); -} - -/* - * Removes a "struct epitem" from the eventpoll RB tree and deallocates - * all the associated resources. Must be called with "mtx" held. - */ -static int ep_remove(struct eventpoll *ep, struct epitem *epi) -{ - unsigned long flags; - struct file *file = epi->ffd.file; - - /* - * Removes poll wait queue hooks. We _have_ to do this without holding - * the "ep->lock" otherwise a deadlock might occur. This because of the - * sequence of the lock acquisition. Here we do "ep->lock" then the wait - * queue head lock when unregistering the wait queue. The wakeup callback - * will run by holding the wait queue head lock and will call our callback - * that will try to get "ep->lock". - */ - ep_unregister_pollwait(ep, epi); - - /* Remove the current item from the list of epoll hooks */ - spin_lock(&file->f_lock); - list_del_rcu(&epi->fllink); - spin_unlock(&file->f_lock); - - rb_erase(&epi->rbn, &ep->rbr); - - spin_lock_irqsave(&ep->lock, flags); - if (ep_is_linked(&epi->rdllink)) - list_del_init(&epi->rdllink); - spin_unlock_irqrestore(&ep->lock, flags); - - wakeup_source_unregister(ep_wakeup_source(epi)); - /* - * At this point it is safe to free the eventpoll item. Use the union - * field epi->rcu, since we are trying to minimize the size of - * 'struct epitem'. The 'rbn' field is no longer in use. Protected by - * ep->mtx. The rcu read side, reverse_path_check_proc(), does not make - * use of the rbn field. - */ - call_rcu(&epi->rcu, epi_rcu_free); - - atomic_long_dec(&ep->user->epoll_watches); - - return 0; -} - -static void ep_free(struct eventpoll *ep) -{ - struct rb_node *rbp; - struct epitem *epi; - - /* We need to release all tasks waiting for these file */ - if (waitqueue_active(&ep->poll_wait)) - ep_poll_safewake(&ep->poll_wait); - - /* - * We need to lock this because we could be hit by - * eventpoll_release_file() while we're freeing the "struct eventpoll". - * We do not need to hold "ep->mtx" here because the epoll file - * is on the way to be removed and no one has references to it - * anymore. The only hit might come from eventpoll_release_file() but - * holding "epmutex" is sufficient here. - */ - mutex_lock(&epmutex); - - /* - * Walks through the whole tree by unregistering poll callbacks. - */ - for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) { - epi = rb_entry(rbp, struct epitem, rbn); - - ep_unregister_pollwait(ep, epi); - cond_resched(); - } - - /* - * Walks through the whole tree by freeing each "struct epitem". At this - * point we are sure no poll callbacks will be lingering around, and also by - * holding "epmutex" we can be sure that no file cleanup code will hit - * us during this operation. So we can avoid the lock on "ep->lock". - * We do not need to lock ep->mtx, either, we only do it to prevent - * a lockdep warning. - */ - mutex_lock(&ep->mtx); - while ((rbp = rb_first(&ep->rbr)) != NULL) { - epi = rb_entry(rbp, struct epitem, rbn); - ep_remove(ep, epi); - cond_resched(); - } - mutex_unlock(&ep->mtx); - - mutex_unlock(&epmutex); - mutex_destroy(&ep->mtx); - free_uid(ep->user); - wakeup_source_unregister(ep->ws); - kfree(ep); -} - -static int ep_eventpoll_release(struct inode *inode, struct file *file) -{ - struct eventpoll *ep = file->private_data; - - if (ep) - ep_free(ep); - - return 0; -} - -static inline unsigned int ep_item_poll(struct epitem *epi, poll_table *pt) -{ - pt->_key = epi->event.events; - - return epi->ffd.file->f_op->poll(epi->ffd.file, pt) & epi->event.events; -} - -static int ep_read_events_proc(struct eventpoll *ep, struct list_head *head, - void *priv) -{ - struct epitem *epi, *tmp; - poll_table pt; - - init_poll_funcptr(&pt, NULL); - - list_for_each_entry_safe(epi, tmp, head, rdllink) { - if (ep_item_poll(epi, &pt)) - return POLLIN | POLLRDNORM; - else { - /* - * Item has been dropped into the ready list by the poll - * callback, but it's not actually ready, as far as - * caller requested events goes. We can remove it here. - */ - __pm_relax(ep_wakeup_source(epi)); - list_del_init(&epi->rdllink); - } - } - - return 0; -} - -static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead, - poll_table *pt); - -struct readyevents_arg { - struct eventpoll *ep; - bool locked; -}; - -static int ep_poll_readyevents_proc(void *priv, void *cookie, int call_nests) -{ - struct readyevents_arg *arg = priv; - - return ep_scan_ready_list(arg->ep, ep_read_events_proc, NULL, - call_nests + 1, arg->locked); -} - -static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait) -{ - int pollflags; - struct eventpoll *ep = file->private_data; - struct readyevents_arg arg; - - /* - * During ep_insert() we already hold the ep->mtx for the tfile. - * Prevent re-aquisition. - */ - arg.locked = wait && (wait->_qproc == ep_ptable_queue_proc); - arg.ep = ep; - - /* Insert inside our poll wait queue */ - poll_wait(file, &ep->poll_wait, wait); - - /* - * Proceed to find out if wanted events are really available inside - * the ready list. This need to be done under ep_call_nested() - * supervision, since the call to f_op->poll() done on listed files - * could re-enter here. - */ - pollflags = ep_call_nested(&poll_readywalk_ncalls, EP_MAX_NESTS, - ep_poll_readyevents_proc, &arg, ep, current); - - return pollflags != -1 ? pollflags : 0; -} - -#ifdef CONFIG_PROC_FS -static void ep_show_fdinfo(struct seq_file *m, struct file *f) -{ - struct eventpoll *ep = f->private_data; - struct rb_node *rbp; - - mutex_lock(&ep->mtx); - for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) { - struct epitem *epi = rb_entry(rbp, struct epitem, rbn); - - seq_printf(m, "tfd: %8d events: %8x data: %16llx\n", - epi->ffd.fd, epi->event.events, - (long long)epi->event.data); - if (seq_has_overflowed(m)) - break; - } - mutex_unlock(&ep->mtx); -} -#endif - -/* File callbacks that implement the eventpoll file behaviour */ -static const struct file_operations eventpoll_fops = { -#ifdef CONFIG_PROC_FS - .show_fdinfo = ep_show_fdinfo, -#endif - .release = ep_eventpoll_release, - .poll = ep_eventpoll_poll, - .llseek = noop_llseek, -}; - -/* - * This is called from eventpoll_release() to unlink files from the eventpoll - * interface. We need to have this facility to cleanup correctly files that are - * closed without being removed from the eventpoll interface. - */ -void eventpoll_release_file(struct file *file) -{ - struct eventpoll *ep; - struct epitem *epi, *next; - - /* - * We don't want to get "file->f_lock" because it is not - * necessary. It is not necessary because we're in the "struct file" - * cleanup path, and this means that no one is using this file anymore. - * So, for example, epoll_ctl() cannot hit here since if we reach this - * point, the file counter already went to zero and fget() would fail. - * The only hit might come from ep_free() but by holding the mutex - * will correctly serialize the operation. We do need to acquire - * "ep->mtx" after "epmutex" because ep_remove() requires it when called - * from anywhere but ep_free(). - * - * Besides, ep_remove() acquires the lock, so we can't hold it here. - */ - mutex_lock(&epmutex); - list_for_each_entry_safe(epi, next, &file->f_ep_links, fllink) { - ep = epi->ep; - mutex_lock_nested(&ep->mtx, 0); - ep_remove(ep, epi); - mutex_unlock(&ep->mtx); - } - mutex_unlock(&epmutex); -} - -static int ep_alloc(struct eventpoll **pep) -{ - int error; - struct user_struct *user; - struct eventpoll *ep; - - user = get_current_user(); - error = -ENOMEM; - ep = kzalloc(sizeof(*ep), GFP_KERNEL); - if (unlikely(!ep)) - goto free_uid; - - spin_lock_init(&ep->lock); - mutex_init(&ep->mtx); - init_waitqueue_head(&ep->wq); - init_waitqueue_head(&ep->poll_wait); - INIT_LIST_HEAD(&ep->rdllist); - ep->rbr = RB_ROOT; - ep->ovflist = EP_UNACTIVE_PTR; - ep->user = user; - - *pep = ep; - - return 0; - -free_uid: - free_uid(user); - return error; -} - -/* - * Search the file inside the eventpoll tree. The RB tree operations - * are protected by the "mtx" mutex, and ep_find() must be called with - * "mtx" held. - */ -static struct epitem *ep_find(struct eventpoll *ep, struct file *file, int fd) -{ - int kcmp; - struct rb_node *rbp; - struct epitem *epi, *epir = NULL; - struct epoll_filefd ffd; - - ep_set_ffd(&ffd, file, fd); - for (rbp = ep->rbr.rb_node; rbp; ) { - epi = rb_entry(rbp, struct epitem, rbn); - kcmp = ep_cmp_ffd(&ffd, &epi->ffd); - if (kcmp > 0) - rbp = rbp->rb_right; - else if (kcmp < 0) - rbp = rbp->rb_left; - else { - epir = epi; - break; - } - } - - return epir; -} - -/* - * This is the callback that is passed to the wait queue wakeup - * mechanism. It is called by the stored file descriptors when they - * have events to report. - */ -static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *key) -{ - int pwake = 0; - unsigned long flags; - struct epitem *epi = ep_item_from_wait(wait); - struct eventpoll *ep = epi->ep; - int ewake = 0; - - if ((unsigned long)key & POLLFREE) { - ep_pwq_from_wait(wait)->whead = NULL; - /* - * whead = NULL above can race with ep_remove_wait_queue() - * which can do another remove_wait_queue() after us, so we - * can't use __remove_wait_queue(). whead->lock is held by - * the caller. - */ - list_del_init(&wait->task_list); - } - - spin_lock_irqsave(&ep->lock, flags); - - /* - * If the event mask does not contain any poll(2) event, we consider the - * descriptor to be disabled. This condition is likely the effect of the - * EPOLLONESHOT bit that disables the descriptor when an event is received, - * until the next EPOLL_CTL_MOD will be issued. - */ - if (!(epi->event.events & ~EP_PRIVATE_BITS)) - goto out_unlock; - - /* - * Check the events coming with the callback. At this stage, not - * every device reports the events in the "key" parameter of the - * callback. We need to be able to handle both cases here, hence the - * test for "key" != NULL before the event match test. - */ - if (key && !((unsigned long) key & epi->event.events)) - goto out_unlock; - - /* - * If we are transferring events to userspace, we can hold no locks - * (because we're accessing user memory, and because of linux f_op->poll() - * semantics). All the events that happen during that period of time are - * chained in ep->ovflist and requeued later on. - */ - if (unlikely(ep->ovflist != EP_UNACTIVE_PTR)) { - if (epi->next == EP_UNACTIVE_PTR) { - epi->next = ep->ovflist; - ep->ovflist = epi; - if (epi->ws) { - /* - * Activate ep->ws since epi->ws may get - * deactivated at any time. - */ - __pm_stay_awake(ep->ws); - } - - } - goto out_unlock; - } - - /* If this file is already in the ready list we exit soon */ - if (!ep_is_linked(&epi->rdllink)) { - list_add_tail(&epi->rdllink, &ep->rdllist); - ep_pm_stay_awake_rcu(epi); - } - - /* - * Wake up ( if active ) both the eventpoll wait list and the ->poll() - * wait list. - */ - if (waitqueue_active(&ep->wq)) { - if ((epi->event.events & EPOLLEXCLUSIVE) && - !((unsigned long)key & POLLFREE)) { - switch ((unsigned long)key & EPOLLINOUT_BITS) { - case POLLIN: - if (epi->event.events & POLLIN) - ewake = 1; - break; - case POLLOUT: - if (epi->event.events & POLLOUT) - ewake = 1; - break; - case 0: - ewake = 1; - break; - } - } - wake_up_locked(&ep->wq); - } - if (waitqueue_active(&ep->poll_wait)) - pwake++; - -out_unlock: - spin_unlock_irqrestore(&ep->lock, flags); - - /* We have to call this outside the lock */ - if (pwake) - ep_poll_safewake(&ep->poll_wait); - - if (epi->event.events & EPOLLEXCLUSIVE) - return ewake; - - return 1; -} - -/* - * This is the callback that is used to add our wait queue to the - * target file wakeup lists. - */ -static void ep_ptable_queue_proc(struct file *file, wait_queue_head_t *whead, - poll_table *pt) -{ - struct epitem *epi = ep_item_from_epqueue(pt); - struct eppoll_entry *pwq; - - if (epi->nwait >= 0 && (pwq = kmem_cache_alloc(pwq_cache, GFP_KERNEL))) { - init_waitqueue_func_entry(&pwq->wait, ep_poll_callback); - pwq->whead = whead; - pwq->base = epi; - if (epi->event.events & EPOLLEXCLUSIVE) - add_wait_queue_exclusive(whead, &pwq->wait); - else - add_wait_queue(whead, &pwq->wait); - list_add_tail(&pwq->llink, &epi->pwqlist); - epi->nwait++; - } else { - /* We have to signal that an error occurred */ - epi->nwait = -1; - } -} - -static void ep_rbtree_insert(struct eventpoll *ep, struct epitem *epi) -{ - int kcmp; - struct rb_node **p = &ep->rbr.rb_node, *parent = NULL; - struct epitem *epic; - - while (*p) { - parent = *p; - epic = rb_entry(parent, struct epitem, rbn); - kcmp = ep_cmp_ffd(&epi->ffd, &epic->ffd); - if (kcmp > 0) - p = &parent->rb_right; - else - p = &parent->rb_left; - } - rb_link_node(&epi->rbn, parent, p); - rb_insert_color(&epi->rbn, &ep->rbr); -} - - - -#define PATH_ARR_SIZE 5 -/* - * These are the number paths of length 1 to 5, that we are allowing to emanate - * from a single file of interest. For example, we allow 1000 paths of length - * 1, to emanate from each file of interest. This essentially represents the - * potential wakeup paths, which need to be limited in order to avoid massive - * uncontrolled wakeup storms. The common use case should be a single ep which - * is connected to n file sources. In this case each file source has 1 path - * of length 1. Thus, the numbers below should be more than sufficient. These - * path limits are enforced during an EPOLL_CTL_ADD operation, since a modify - * and delete can't add additional paths. Protected by the epmutex. - */ -static const int path_limits[PATH_ARR_SIZE] = { 1000, 500, 100, 50, 10 }; -static int path_count[PATH_ARR_SIZE]; - -static int path_count_inc(int nests) -{ - /* Allow an arbitrary number of depth 1 paths */ - if (nests == 0) - return 0; - - if (++path_count[nests] > path_limits[nests]) - return -1; - return 0; -} - -static void path_count_init(void) -{ - int i; - - for (i = 0; i < PATH_ARR_SIZE; i++) - path_count[i] = 0; -} - -static int reverse_path_check_proc(void *priv, void *cookie, int call_nests) -{ - int error = 0; - struct file *file = priv; - struct file *child_file; - struct epitem *epi; - - /* CTL_DEL can remove links here, but that can't increase our count */ - rcu_read_lock(); - list_for_each_entry_rcu(epi, &file->f_ep_links, fllink) { - child_file = epi->ep->file; - if (is_file_epoll(child_file)) { - if (list_empty(&child_file->f_ep_links)) { - if (path_count_inc(call_nests)) { - error = -1; - break; - } - } else { - error = ep_call_nested(&poll_loop_ncalls, - EP_MAX_NESTS, - reverse_path_check_proc, - child_file, child_file, - current); - } - if (error != 0) - break; - } else { - printk(KERN_ERR "reverse_path_check_proc: " - "file is not an ep!\n"); - } - } - rcu_read_unlock(); - return error; -} - -/** - * reverse_path_check - The tfile_check_list is list of file *, which have - * links that are proposed to be newly added. We need to - * make sure that those added links don't add too many - * paths such that we will spend all our time waking up - * eventpoll objects. - * - * Returns: Returns zero if the proposed links don't create too many paths, - * -1 otherwise. - */ -static int reverse_path_check(void) -{ - int error = 0; - struct file *current_file; - - /* let's call this for all tfiles */ - list_for_each_entry(current_file, &tfile_check_list, f_tfile_llink) { - path_count_init(); - error = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS, - reverse_path_check_proc, current_file, - current_file, current); - if (error) - break; - } - return error; -} - -static int ep_create_wakeup_source(struct epitem *epi) -{ - const char *name; - struct wakeup_source *ws; - - if (!epi->ep->ws) { - epi->ep->ws = wakeup_source_register("eventpoll"); - if (!epi->ep->ws) - return -ENOMEM; - } - - name = epi->ffd.file->f_path.dentry->d_name.name; - ws = wakeup_source_register(name); - - if (!ws) - return -ENOMEM; - rcu_assign_pointer(epi->ws, ws); - - return 0; -} - -/* rare code path, only used when EPOLL_CTL_MOD removes a wakeup source */ -static noinline void ep_destroy_wakeup_source(struct epitem *epi) -{ - struct wakeup_source *ws = ep_wakeup_source(epi); - - RCU_INIT_POINTER(epi->ws, NULL); - - /* - * wait for ep_pm_stay_awake_rcu to finish, synchronize_rcu is - * used internally by wakeup_source_remove, too (called by - * wakeup_source_unregister), so we cannot use call_rcu - */ - synchronize_rcu(); - wakeup_source_unregister(ws); -} - -/* - * Must be called with "mtx" held. - */ -static int ep_insert(struct eventpoll *ep, struct epoll_event *event, - struct file *tfile, int fd, int full_check) -{ - int error, revents, pwake = 0; - unsigned long flags; - long user_watches; - struct epitem *epi; - struct ep_pqueue epq; - - user_watches = atomic_long_read(&ep->user->epoll_watches); - if (unlikely(user_watches >= max_user_watches)) - return -ENOSPC; - if (!(epi = kmem_cache_alloc(epi_cache, GFP_KERNEL))) - return -ENOMEM; - - /* Item initialization follow here ... */ - INIT_LIST_HEAD(&epi->rdllink); - INIT_LIST_HEAD(&epi->fllink); - INIT_LIST_HEAD(&epi->pwqlist); - epi->ep = ep; - ep_set_ffd(&epi->ffd, tfile, fd); - epi->event = *event; - epi->nwait = 0; - epi->next = EP_UNACTIVE_PTR; - if (epi->event.events & EPOLLWAKEUP) { - error = ep_create_wakeup_source(epi); - if (error) - goto error_create_wakeup_source; - } else { - RCU_INIT_POINTER(epi->ws, NULL); - } - - /* Initialize the poll table using the queue callback */ - epq.epi = epi; - init_poll_funcptr(&epq.pt, ep_ptable_queue_proc); - - /* - * Attach the item to the poll hooks and get current event bits. - * We can safely use the file* here because its usage count has - * been increased by the caller of this function. Note that after - * this operation completes, the poll callback can start hitting - * the new item. - */ - revents = ep_item_poll(epi, &epq.pt); - - /* - * We have to check if something went wrong during the poll wait queue - * install process. Namely an allocation for a wait queue failed due - * high memory pressure. - */ - error = -ENOMEM; - if (epi->nwait < 0) - goto error_unregister; - - /* Add the current item to the list of active epoll hook for this file */ - spin_lock(&tfile->f_lock); - list_add_tail_rcu(&epi->fllink, &tfile->f_ep_links); - spin_unlock(&tfile->f_lock); - - /* - * Add the current item to the RB tree. All RB tree operations are - * protected by "mtx", and ep_insert() is called with "mtx" held. - */ - ep_rbtree_insert(ep, epi); - - /* now check if we've created too many backpaths */ - error = -EINVAL; - if (full_check && reverse_path_check()) - goto error_remove_epi; - - /* We have to drop the new item inside our item list to keep track of it */ - spin_lock_irqsave(&ep->lock, flags); - - /* If the file is already "ready" we drop it inside the ready list */ - if ((revents & event->events) && !ep_is_linked(&epi->rdllink)) { - list_add_tail(&epi->rdllink, &ep->rdllist); - ep_pm_stay_awake(epi); - - /* Notify waiting tasks that events are available */ - if (waitqueue_active(&ep->wq)) - wake_up_locked(&ep->wq); - if (waitqueue_active(&ep->poll_wait)) - pwake++; - } - - spin_unlock_irqrestore(&ep->lock, flags); - - atomic_long_inc(&ep->user->epoll_watches); - - /* We have to call this outside the lock */ - if (pwake) - ep_poll_safewake(&ep->poll_wait); - - return 0; - -error_remove_epi: - spin_lock(&tfile->f_lock); - list_del_rcu(&epi->fllink); - spin_unlock(&tfile->f_lock); - - rb_erase(&epi->rbn, &ep->rbr); - -error_unregister: - ep_unregister_pollwait(ep, epi); - - /* - * We need to do this because an event could have been arrived on some - * allocated wait queue. Note that we don't care about the ep->ovflist - * list, since that is used/cleaned only inside a section bound by "mtx". - * And ep_insert() is called with "mtx" held. - */ - spin_lock_irqsave(&ep->lock, flags); - if (ep_is_linked(&epi->rdllink)) - list_del_init(&epi->rdllink); - spin_unlock_irqrestore(&ep->lock, flags); - - wakeup_source_unregister(ep_wakeup_source(epi)); - -error_create_wakeup_source: - kmem_cache_free(epi_cache, epi); - - return error; -} - -/* - * Modify the interest event mask by dropping an event if the new mask - * has a match in the current file status. Must be called with "mtx" held. - */ -static int ep_modify(struct eventpoll *ep, struct epitem *epi, struct epoll_event *event) -{ - int pwake = 0; - unsigned int revents; - poll_table pt; - - init_poll_funcptr(&pt, NULL); - - /* - * Set the new event interest mask before calling f_op->poll(); - * otherwise we might miss an event that happens between the - * f_op->poll() call and the new event set registering. - */ - epi->event.events = event->events; /* need barrier below */ - epi->event.data = event->data; /* protected by mtx */ - if (epi->event.events & EPOLLWAKEUP) { - if (!ep_has_wakeup_source(epi)) - ep_create_wakeup_source(epi); - } else if (ep_has_wakeup_source(epi)) { - ep_destroy_wakeup_source(epi); - } - - /* - * The following barrier has two effects: - * - * 1) Flush epi changes above to other CPUs. This ensures - * we do not miss events from ep_poll_callback if an - * event occurs immediately after we call f_op->poll(). - * We need this because we did not take ep->lock while - * changing epi above (but ep_poll_callback does take - * ep->lock). - * - * 2) We also need to ensure we do not miss _past_ events - * when calling f_op->poll(). This barrier also - * pairs with the barrier in wq_has_sleeper (see - * comments for wq_has_sleeper). - * - * This barrier will now guarantee ep_poll_callback or f_op->poll - * (or both) will notice the readiness of an item. - */ - smp_mb(); - - /* - * Get current event bits. We can safely use the file* here because - * its usage count has been increased by the caller of this function. - */ - revents = ep_item_poll(epi, &pt); - - /* - * If the item is "hot" and it is not registered inside the ready - * list, push it inside. - */ - if (revents & event->events) { - spin_lock_irq(&ep->lock); - if (!ep_is_linked(&epi->rdllink)) { - list_add_tail(&epi->rdllink, &ep->rdllist); - ep_pm_stay_awake(epi); - - /* Notify waiting tasks that events are available */ - if (waitqueue_active(&ep->wq)) - wake_up_locked(&ep->wq); - if (waitqueue_active(&ep->poll_wait)) - pwake++; - } - spin_unlock_irq(&ep->lock); - } - - /* We have to call this outside the lock */ - if (pwake) - ep_poll_safewake(&ep->poll_wait); - - return 0; -} - -static int ep_send_events_proc(struct eventpoll *ep, struct list_head *head, - void *priv) -{ - struct ep_send_events_data *esed = priv; - int eventcnt; - unsigned int revents; - struct epitem *epi; - struct epoll_event __user *uevent; - struct wakeup_source *ws; - poll_table pt; - - init_poll_funcptr(&pt, NULL); - - /* - * We can loop without lock because we are passed a task private list. - * Items cannot vanish during the loop because ep_scan_ready_list() is - * holding "mtx" during this call. - */ - for (eventcnt = 0, uevent = esed->events; - !list_empty(head) && eventcnt < esed->maxevents;) { - epi = list_first_entry(head, struct epitem, rdllink); - - /* - * Activate ep->ws before deactivating epi->ws to prevent - * triggering auto-suspend here (in case we reactive epi->ws - * below). - * - * This could be rearranged to delay the deactivation of epi->ws - * instead, but then epi->ws would temporarily be out of sync - * with ep_is_linked(). - */ - ws = ep_wakeup_source(epi); - if (ws) { - if (ws->active) - __pm_stay_awake(ep->ws); - __pm_relax(ws); - } - - list_del_init(&epi->rdllink); - - revents = ep_item_poll(epi, &pt); - - /* - * If the event mask intersect the caller-requested one, - * deliver the event to userspace. Again, ep_scan_ready_list() - * is holding "mtx", so no operations coming from userspace - * can change the item. - */ - if (revents) { - if (__put_user(revents, &uevent->events) || - __put_user(epi->event.data, &uevent->data)) { - list_add(&epi->rdllink, head); - ep_pm_stay_awake(epi); - return eventcnt ? eventcnt : -EFAULT; - } - eventcnt++; - uevent++; - if (epi->event.events & EPOLLONESHOT) - epi->event.events &= EP_PRIVATE_BITS; - else if (!(epi->event.events & EPOLLET)) { - /* - * If this file has been added with Level - * Trigger mode, we need to insert back inside - * the ready list, so that the next call to - * epoll_wait() will check again the events - * availability. At this point, no one can insert - * into ep->rdllist besides us. The epoll_ctl() - * callers are locked out by - * ep_scan_ready_list() holding "mtx" and the - * poll callback will queue them in ep->ovflist. - */ - list_add_tail(&epi->rdllink, &ep->rdllist); - ep_pm_stay_awake(epi); - } - } - } - - return eventcnt; -} - -static int ep_send_events(struct eventpoll *ep, - struct epoll_event __user *events, int maxevents) -{ - struct ep_send_events_data esed; - - esed.maxevents = maxevents; - esed.events = events; - - return ep_scan_ready_list(ep, ep_send_events_proc, &esed, 0, false); -} - -static inline struct timespec64 ep_set_mstimeout(long ms) -{ - struct timespec64 now, ts = { - .tv_sec = ms / MSEC_PER_SEC, - .tv_nsec = NSEC_PER_MSEC * (ms % MSEC_PER_SEC), - }; - - ktime_get_ts64(&now); - return timespec64_add_safe(now, ts); -} - -/** - * ep_poll - Retrieves ready events, and delivers them to the caller supplied - * event buffer. - * - * @ep: Pointer to the eventpoll context. - * @events: Pointer to the userspace buffer where the ready events should be - * stored. - * @maxevents: Size (in terms of number of events) of the caller event buffer. - * @timeout: Maximum timeout for the ready events fetch operation, in - * milliseconds. If the @timeout is zero, the function will not block, - * while if the @timeout is less than zero, the function will block - * until at least one event has been retrieved (or an error - * occurred). - * - * Returns: Returns the number of ready events which have been fetched, or an - * error code, in case of error. - */ -static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, - int maxevents, long timeout) -{ - int res = 0, eavail, timed_out = 0; - unsigned long flags; - u64 slack = 0; - wait_queue_t wait; - ktime_t expires, *to = NULL; - - if (timeout > 0) { - struct timespec64 end_time = ep_set_mstimeout(timeout); - - slack = select_estimate_accuracy(&end_time); - to = &expires; - *to = timespec64_to_ktime(end_time); - } else if (timeout == 0) { - /* - * Avoid the unnecessary trip to the wait queue loop, if the - * caller specified a non blocking operation. - */ - timed_out = 1; - spin_lock_irqsave(&ep->lock, flags); - goto check_events; - } - -fetch_events: - spin_lock_irqsave(&ep->lock, flags); - - if (!ep_events_available(ep)) { - /* - * We don't have any available event to return to the caller. - * We need to sleep here, and we will be wake up by - * ep_poll_callback() when events will become available. - */ - init_waitqueue_entry(&wait, current); - __add_wait_queue_exclusive(&ep->wq, &wait); - - for (;;) { - /* - * We don't want to sleep if the ep_poll_callback() sends us - * a wakeup in between. That's why we set the task state - * to TASK_INTERRUPTIBLE before doing the checks. - */ - set_current_state(TASK_INTERRUPTIBLE); - if (ep_events_available(ep) || timed_out) - break; - if (signal_pending(current)) { - res = -EINTR; - break; - } - - spin_unlock_irqrestore(&ep->lock, flags); - if (!schedule_hrtimeout_range(to, slack, HRTIMER_MODE_ABS)) - timed_out = 1; - - spin_lock_irqsave(&ep->lock, flags); - } - - __remove_wait_queue(&ep->wq, &wait); - __set_current_state(TASK_RUNNING); - } -check_events: - /* Is it worth to try to dig for events ? */ - eavail = ep_events_available(ep); - - spin_unlock_irqrestore(&ep->lock, flags); - - /* - * Try to transfer events to user space. In case we get 0 events and - * there's still timeout left over, we go trying again in search of - * more luck. - */ - if (!res && eavail && - !(res = ep_send_events(ep, events, maxevents)) && !timed_out) - goto fetch_events; - - return res; -} - -/** - * ep_loop_check_proc - Callback function to be passed to the @ep_call_nested() - * API, to verify that adding an epoll file inside another - * epoll structure, does not violate the constraints, in - * terms of closed loops, or too deep chains (which can - * result in excessive stack usage). - * - * @priv: Pointer to the epoll file to be currently checked. - * @cookie: Original cookie for this call. This is the top-of-the-chain epoll - * data structure pointer. - * @call_nests: Current dept of the @ep_call_nested() call stack. - * - * Returns: Returns zero if adding the epoll @file inside current epoll - * structure @ep does not violate the constraints, or -1 otherwise. - */ -static int ep_loop_check_proc(void *priv, void *cookie, int call_nests) -{ - int error = 0; - struct file *file = priv; - struct eventpoll *ep = file->private_data; - struct eventpoll *ep_tovisit; - struct rb_node *rbp; - struct epitem *epi; - - mutex_lock_nested(&ep->mtx, call_nests + 1); - ep->visited = 1; - list_add(&ep->visited_list_link, &visited_list); - for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) { - epi = rb_entry(rbp, struct epitem, rbn); - if (unlikely(is_file_epoll(epi->ffd.file))) { - ep_tovisit = epi->ffd.file->private_data; - if (ep_tovisit->visited) - continue; - error = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS, - ep_loop_check_proc, epi->ffd.file, - ep_tovisit, current); - if (error != 0) - break; - } else { - /* - * If we've reached a file that is not associated with - * an ep, then we need to check if the newly added - * links are going to add too many wakeup paths. We do - * this by adding it to the tfile_check_list, if it's - * not already there, and calling reverse_path_check() - * during ep_insert(). - */ - if (list_empty(&epi->ffd.file->f_tfile_llink)) - list_add(&epi->ffd.file->f_tfile_llink, - &tfile_check_list); - } - } - mutex_unlock(&ep->mtx); - - return error; -} - -/** - * ep_loop_check - Performs a check to verify that adding an epoll file (@file) - * another epoll file (represented by @ep) does not create - * closed loops or too deep chains. - * - * @ep: Pointer to the epoll private data structure. - * @file: Pointer to the epoll file to be checked. - * - * Returns: Returns zero if adding the epoll @file inside current epoll - * structure @ep does not violate the constraints, or -1 otherwise. - */ -static int ep_loop_check(struct eventpoll *ep, struct file *file) -{ - int ret; - struct eventpoll *ep_cur, *ep_next; - - ret = ep_call_nested(&poll_loop_ncalls, EP_MAX_NESTS, - ep_loop_check_proc, file, ep, current); - /* clear visited list */ - list_for_each_entry_safe(ep_cur, ep_next, &visited_list, - visited_list_link) { - ep_cur->visited = 0; - list_del(&ep_cur->visited_list_link); - } - return ret; -} - -static void clear_tfile_check_list(void) -{ - struct file *file; - - /* first clear the tfile_check_list */ - while (!list_empty(&tfile_check_list)) { - file = list_first_entry(&tfile_check_list, struct file, - f_tfile_llink); - list_del_init(&file->f_tfile_llink); - } - INIT_LIST_HEAD(&tfile_check_list); -} - -/* - * Open an eventpoll file descriptor. - */ -SYSCALL_DEFINE1(epoll_create1, int, flags) -{ - int error, fd; - struct eventpoll *ep = NULL; - struct file *file; - - /* Check the EPOLL_* constant for consistency. */ - BUILD_BUG_ON(EPOLL_CLOEXEC != O_CLOEXEC); - - if (flags & ~EPOLL_CLOEXEC) - return -EINVAL; - /* - * Create the internal data structure ("struct eventpoll"). - */ - error = ep_alloc(&ep); - if (error < 0) - return error; - /* - * Creates all the items needed to setup an eventpoll file. That is, - * a file structure and a free file descriptor. - */ - fd = get_unused_fd_flags(O_RDWR | (flags & O_CLOEXEC)); - if (fd < 0) { - error = fd; - goto out_free_ep; - } - file = anon_inode_getfile("[eventpoll]", &eventpoll_fops, ep, - O_RDWR | (flags & O_CLOEXEC)); - if (IS_ERR(file)) { - error = PTR_ERR(file); - goto out_free_fd; - } - ep->file = file; - fd_install(fd, file); - return fd; - -out_free_fd: - put_unused_fd(fd); -out_free_ep: - ep_free(ep); - return error; -} - -SYSCALL_DEFINE1(epoll_create, int, size) -{ - if (size <= 0) - return -EINVAL; - - return sys_epoll_create1(0); -} - -/* - * The following function implements the controller interface for - * the eventpoll file that enables the insertion/removal/change of - * file descriptors inside the interest set. - */ -SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, - struct epoll_event __user *, event) -{ - int error; - int full_check = 0; - struct fd f, tf; - struct eventpoll *ep; - struct epitem *epi; - struct epoll_event epds; - struct eventpoll *tep = NULL; - - error = -EFAULT; - if (ep_op_has_event(op) && - copy_from_user(&epds, event, sizeof(struct epoll_event))) - goto error_return; - - error = -EBADF; - f = fdget(epfd); - if (!f.file) - goto error_return; - - /* Get the "struct file *" for the target file */ - tf = fdget(fd); - if (!tf.file) - goto error_fput; - - /* The target file descriptor must support poll */ - error = -EPERM; - if (!tf.file->f_op->poll) - goto error_tgt_fput; - - /* Check if EPOLLWAKEUP is allowed */ - if (ep_op_has_event(op)) - ep_take_care_of_epollwakeup(&epds); - - /* - * We have to check that the file structure underneath the file descriptor - * the user passed to us _is_ an eventpoll file. And also we do not permit - * adding an epoll file descriptor inside itself. - */ - error = -EINVAL; - if (f.file == tf.file || !is_file_epoll(f.file)) - goto error_tgt_fput; - - /* - * epoll adds to the wakeup queue at EPOLL_CTL_ADD time only, - * so EPOLLEXCLUSIVE is not allowed for a EPOLL_CTL_MOD operation. - * Also, we do not currently supported nested exclusive wakeups. - */ - if (epds.events & EPOLLEXCLUSIVE) { - if (op == EPOLL_CTL_MOD) - goto error_tgt_fput; - if (op == EPOLL_CTL_ADD && (is_file_epoll(tf.file) || - (epds.events & ~EPOLLEXCLUSIVE_OK_BITS))) - goto error_tgt_fput; - } - - /* - * At this point it is safe to assume that the "private_data" contains - * our own data structure. - */ - ep = f.file->private_data; - - /* - * When we insert an epoll file descriptor, inside another epoll file - * descriptor, there is the change of creating closed loops, which are - * better be handled here, than in more critical paths. While we are - * checking for loops we also determine the list of files reachable - * and hang them on the tfile_check_list, so we can check that we - * haven't created too many possible wakeup paths. - * - * We do not need to take the global 'epumutex' on EPOLL_CTL_ADD when - * the epoll file descriptor is attaching directly to a wakeup source, - * unless the epoll file descriptor is nested. The purpose of taking the - * 'epmutex' on add is to prevent complex toplogies such as loops and - * deep wakeup paths from forming in parallel through multiple - * EPOLL_CTL_ADD operations. - */ - mutex_lock_nested(&ep->mtx, 0); - if (op == EPOLL_CTL_ADD) { - if (!list_empty(&f.file->f_ep_links) || - is_file_epoll(tf.file)) { - full_check = 1; - mutex_unlock(&ep->mtx); - mutex_lock(&epmutex); - if (is_file_epoll(tf.file)) { - error = -ELOOP; - if (ep_loop_check(ep, tf.file) != 0) { - clear_tfile_check_list(); - goto error_tgt_fput; - } - } else - list_add(&tf.file->f_tfile_llink, - &tfile_check_list); - mutex_lock_nested(&ep->mtx, 0); - if (is_file_epoll(tf.file)) { - tep = tf.file->private_data; - mutex_lock_nested(&tep->mtx, 1); - } - } - } - - /* - * Try to lookup the file inside our RB tree, Since we grabbed "mtx" - * above, we can be sure to be able to use the item looked up by - * ep_find() till we release the mutex. - */ - epi = ep_find(ep, tf.file, fd); - - error = -EINVAL; - switch (op) { - case EPOLL_CTL_ADD: - if (!epi) { - epds.events |= POLLERR | POLLHUP; - error = ep_insert(ep, &epds, tf.file, fd, full_check); - } else - error = -EEXIST; - if (full_check) - clear_tfile_check_list(); - break; - case EPOLL_CTL_DEL: - if (epi) - error = ep_remove(ep, epi); - else - error = -ENOENT; - break; - case EPOLL_CTL_MOD: - if (epi) { - if (!(epi->event.events & EPOLLEXCLUSIVE)) { - epds.events |= POLLERR | POLLHUP; - error = ep_modify(ep, epi, &epds); - } - } else - error = -ENOENT; - break; - } - if (tep != NULL) - mutex_unlock(&tep->mtx); - mutex_unlock(&ep->mtx); - -error_tgt_fput: - if (full_check) - mutex_unlock(&epmutex); - - fdput(tf); -error_fput: - fdput(f); -error_return: - - return error; -} - -/* - * Implement the event wait interface for the eventpoll file. It is the kernel - * part of the user space epoll_wait(2). - */ -SYSCALL_DEFINE4(epoll_wait, int, epfd, struct epoll_event __user *, events, - int, maxevents, int, timeout) -{ - int error; - struct fd f; - struct eventpoll *ep; - - /* The maximum number of event must be greater than zero */ - if (maxevents <= 0 || maxevents > EP_MAX_EVENTS) - return -EINVAL; - - /* Verify that the area passed by the user is writeable */ - if (!access_ok(VERIFY_WRITE, events, maxevents * sizeof(struct epoll_event))) - return -EFAULT; - - /* Get the "struct file *" for the eventpoll file */ - f = fdget(epfd); - if (!f.file) - return -EBADF; - - /* - * We have to check that the file structure underneath the fd - * the user passed to us _is_ an eventpoll file. - */ - error = -EINVAL; - if (!is_file_epoll(f.file)) - goto error_fput; - - /* - * At this point it is safe to assume that the "private_data" contains - * our own data structure. - */ - ep = f.file->private_data; - - /* Time to fish for events ... */ - error = ep_poll(ep, events, maxevents, timeout); - -error_fput: - fdput(f); - return error; -} - -/* - * Implement the event wait interface for the eventpoll file. It is the kernel - * part of the user space epoll_pwait(2). - */ -SYSCALL_DEFINE6(epoll_pwait, int, epfd, struct epoll_event __user *, events, - int, maxevents, int, timeout, const sigset_t __user *, sigmask, - size_t, sigsetsize) -{ - int error; - sigset_t ksigmask, sigsaved; - - /* - * If the caller wants a certain signal mask to be set during the wait, - * we apply it here. - */ - if (sigmask) { - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask))) - return -EFAULT; - sigsaved = current->blocked; - set_current_blocked(&ksigmask); - } - - error = sys_epoll_wait(epfd, events, maxevents, timeout); - - /* - * If we changed the signal mask, we need to restore the original one. - * In case we've got a signal while waiting, we do not restore the - * signal mask yet, and we allow do_signal() to deliver the signal on - * the way back to userspace, before the signal mask is restored. - */ - if (sigmask) { - if (error == -EINTR) { - memcpy(¤t->saved_sigmask, &sigsaved, - sizeof(sigsaved)); - set_restore_sigmask(); - } else - set_current_blocked(&sigsaved); - } - - return error; -} - -#ifdef CONFIG_COMPAT -COMPAT_SYSCALL_DEFINE6(epoll_pwait, int, epfd, - struct epoll_event __user *, events, - int, maxevents, int, timeout, - const compat_sigset_t __user *, sigmask, - compat_size_t, sigsetsize) -{ - long err; - compat_sigset_t csigmask; - sigset_t ksigmask, sigsaved; - - /* - * If the caller wants a certain signal mask to be set during the wait, - * we apply it here. - */ - if (sigmask) { - if (sigsetsize != sizeof(compat_sigset_t)) - return -EINVAL; - if (copy_from_user(&csigmask, sigmask, sizeof(csigmask))) - return -EFAULT; - sigset_from_compat(&ksigmask, &csigmask); - sigsaved = current->blocked; - set_current_blocked(&ksigmask); - } - - err = sys_epoll_wait(epfd, events, maxevents, timeout); - - /* - * If we changed the signal mask, we need to restore the original one. - * In case we've got a signal while waiting, we do not restore the - * signal mask yet, and we allow do_signal() to deliver the signal on - * the way back to userspace, before the signal mask is restored. - */ - if (sigmask) { - if (err == -EINTR) { - memcpy(¤t->saved_sigmask, &sigsaved, - sizeof(sigsaved)); - set_restore_sigmask(); - } else - set_current_blocked(&sigsaved); - } - - return err; -} -#endif - -static int __init eventpoll_init(void) -{ - struct sysinfo si; - - si_meminfo(&si); - /* - * Allows top 4% of lomem to be allocated for epoll watches (per user). - */ - max_user_watches = (((si.totalram - si.totalhigh) / 25) << PAGE_SHIFT) / - EP_ITEM_COST; - BUG_ON(max_user_watches < 0); - - /* - * Initialize the structure used to perform epoll file descriptor - * inclusion loops checks. - */ - ep_nested_calls_init(&poll_loop_ncalls); - - /* Initialize the structure used to perform safe poll wait head wake ups */ - ep_nested_calls_init(&poll_safewake_ncalls); - - /* Initialize the structure used to perform file's f_op->poll() calls */ - ep_nested_calls_init(&poll_readywalk_ncalls); - - /* - * We can have many thousands of epitems, so prevent this from - * using an extra cache line on 64-bit (and smaller) CPUs - */ - BUILD_BUG_ON(sizeof(void *) <= 8 && sizeof(struct epitem) > 128); - - /* Allocates slab cache used to allocate "struct epitem" items */ - epi_cache = kmem_cache_create("eventpoll_epi", sizeof(struct epitem), - 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); - - /* Allocates slab cache used to allocate "struct eppoll_entry" */ - pwq_cache = kmem_cache_create("eventpoll_pwq", - sizeof(struct eppoll_entry), 0, SLAB_PANIC, NULL); - - return 0; -} -fs_initcall(eventpoll_init); diff --git a/src/linux/fs/exec.c b/src/linux/fs/exec.c deleted file mode 100644 index 4e497b9..0000000 --- a/src/linux/fs/exec.c +++ /dev/null @@ -1,1905 +0,0 @@ -/* - * linux/fs/exec.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -/* - * #!-checking implemented by tytso. - */ -/* - * Demand-loading implemented 01.12.91 - no need to read anything but - * the header into memory. The inode of the executable is put into - * "current->executable", and page faults do the actual loading. Clean. - * - * Once more I can proudly say that linux stood up to being changed: it - * was less than 2 hours work to get demand-loading completely implemented. - * - * Demand loading changed July 1993 by Eric Youngdale. Use mmap instead, - * current->executable is only used by the procfs. This allows a dispatch - * table to check for several different types of binary formats. We keep - * trying until we recognize the file or we run out of supported binary - * formats. - */ - -#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 -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include "internal.h" - -#include - -int suid_dumpable = 0; - -static LIST_HEAD(formats); -static DEFINE_RWLOCK(binfmt_lock); - -void __register_binfmt(struct linux_binfmt * fmt, int insert) -{ - BUG_ON(!fmt); - if (WARN_ON(!fmt->load_binary)) - return; - write_lock(&binfmt_lock); - insert ? list_add(&fmt->lh, &formats) : - list_add_tail(&fmt->lh, &formats); - write_unlock(&binfmt_lock); -} - -EXPORT_SYMBOL(__register_binfmt); - -void unregister_binfmt(struct linux_binfmt * fmt) -{ - write_lock(&binfmt_lock); - list_del(&fmt->lh); - write_unlock(&binfmt_lock); -} - -EXPORT_SYMBOL(unregister_binfmt); - -static inline void put_binfmt(struct linux_binfmt * fmt) -{ - module_put(fmt->module); -} - -bool path_noexec(const struct path *path) -{ - return (path->mnt->mnt_flags & MNT_NOEXEC) || - (path->mnt->mnt_sb->s_iflags & SB_I_NOEXEC); -} - -#ifdef CONFIG_USELIB -/* - * Note that a shared library must be both readable and executable due to - * security reasons. - * - * Also note that we take the address to load from from the file itself. - */ -SYSCALL_DEFINE1(uselib, const char __user *, library) -{ - struct linux_binfmt *fmt; - struct file *file; - struct filename *tmp = getname(library); - int error = PTR_ERR(tmp); - static const struct open_flags uselib_flags = { - .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, - .acc_mode = MAY_READ | MAY_EXEC, - .intent = LOOKUP_OPEN, - .lookup_flags = LOOKUP_FOLLOW, - }; - - if (IS_ERR(tmp)) - goto out; - - file = do_filp_open(AT_FDCWD, tmp, &uselib_flags); - putname(tmp); - error = PTR_ERR(file); - if (IS_ERR(file)) - goto out; - - error = -EINVAL; - if (!S_ISREG(file_inode(file)->i_mode)) - goto exit; - - error = -EACCES; - if (path_noexec(&file->f_path)) - goto exit; - - fsnotify_open(file); - - error = -ENOEXEC; - - read_lock(&binfmt_lock); - list_for_each_entry(fmt, &formats, lh) { - if (!fmt->load_shlib) - continue; - if (!try_module_get(fmt->module)) - continue; - read_unlock(&binfmt_lock); - error = fmt->load_shlib(file); - read_lock(&binfmt_lock); - put_binfmt(fmt); - if (error != -ENOEXEC) - break; - } - read_unlock(&binfmt_lock); -exit: - fput(file); -out: - return error; -} -#endif /* #ifdef CONFIG_USELIB */ - -#ifdef CONFIG_MMU -/* - * The nascent bprm->mm is not visible until exec_mmap() but it can - * use a lot of memory, account these pages in current->mm temporary - * for oom_badness()->get_mm_rss(). Once exec succeeds or fails, we - * change the counter back via acct_arg_size(0). - */ -static void acct_arg_size(struct linux_binprm *bprm, unsigned long pages) -{ - struct mm_struct *mm = current->mm; - long diff = (long)(pages - bprm->vma_pages); - - if (!mm || !diff) - return; - - bprm->vma_pages = pages; - add_mm_counter(mm, MM_ANONPAGES, diff); -} - -static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, - int write) -{ - struct page *page; - int ret; - unsigned int gup_flags = FOLL_FORCE; - -#ifdef CONFIG_STACK_GROWSUP - if (write) { - ret = expand_downwards(bprm->vma, pos); - if (ret < 0) - return NULL; - } -#endif - - if (write) - gup_flags |= FOLL_WRITE; - - /* - * We are doing an exec(). 'current' is the process - * doing the exec and bprm->mm is the new process's mm. - */ - ret = get_user_pages_remote(current, bprm->mm, pos, 1, gup_flags, - &page, NULL); - if (ret <= 0) - return NULL; - - if (write) { - unsigned long size = bprm->vma->vm_end - bprm->vma->vm_start; - struct rlimit *rlim; - - acct_arg_size(bprm, size / PAGE_SIZE); - - /* - * We've historically supported up to 32 pages (ARG_MAX) - * of argument strings even with small stacks - */ - if (size <= ARG_MAX) - return page; - - /* - * Limit to 1/4-th the stack size for the argv+env strings. - * This ensures that: - * - the remaining binfmt code will not run out of stack space, - * - the program will have a reasonable amount of stack left - * to work from. - */ - rlim = current->signal->rlim; - if (size > ACCESS_ONCE(rlim[RLIMIT_STACK].rlim_cur) / 4) { - put_page(page); - return NULL; - } - } - - return page; -} - -static void put_arg_page(struct page *page) -{ - put_page(page); -} - -static void free_arg_pages(struct linux_binprm *bprm) -{ -} - -static void flush_arg_page(struct linux_binprm *bprm, unsigned long pos, - struct page *page) -{ - flush_cache_page(bprm->vma, pos, page_to_pfn(page)); -} - -static int __bprm_mm_init(struct linux_binprm *bprm) -{ - int err; - struct vm_area_struct *vma = NULL; - struct mm_struct *mm = bprm->mm; - - bprm->vma = vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); - if (!vma) - return -ENOMEM; - - if (down_write_killable(&mm->mmap_sem)) { - err = -EINTR; - goto err_free; - } - vma->vm_mm = mm; - - /* - * Place the stack at the largest stack address the architecture - * supports. Later, we'll move this to an appropriate place. We don't - * use STACK_TOP because that can depend on attributes which aren't - * configured yet. - */ - BUILD_BUG_ON(VM_STACK_FLAGS & VM_STACK_INCOMPLETE_SETUP); - vma->vm_end = STACK_TOP_MAX; - vma->vm_start = vma->vm_end - PAGE_SIZE; - vma->vm_flags = VM_SOFTDIRTY | VM_STACK_FLAGS | VM_STACK_INCOMPLETE_SETUP; - vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); - INIT_LIST_HEAD(&vma->anon_vma_chain); - - err = insert_vm_struct(mm, vma); - if (err) - goto err; - - mm->stack_vm = mm->total_vm = 1; - arch_bprm_mm_init(mm, vma); - up_write(&mm->mmap_sem); - bprm->p = vma->vm_end - sizeof(void *); - return 0; -err: - up_write(&mm->mmap_sem); -err_free: - bprm->vma = NULL; - kmem_cache_free(vm_area_cachep, vma); - return err; -} - -static bool valid_arg_len(struct linux_binprm *bprm, long len) -{ - return len <= MAX_ARG_STRLEN; -} - -#else - -static inline void acct_arg_size(struct linux_binprm *bprm, unsigned long pages) -{ -} - -static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos, - int write) -{ - struct page *page; - - page = bprm->page[pos / PAGE_SIZE]; - if (!page && write) { - page = alloc_page(GFP_HIGHUSER|__GFP_ZERO); - if (!page) - return NULL; - bprm->page[pos / PAGE_SIZE] = page; - } - - return page; -} - -static void put_arg_page(struct page *page) -{ -} - -static void free_arg_page(struct linux_binprm *bprm, int i) -{ - if (bprm->page[i]) { - __free_page(bprm->page[i]); - bprm->page[i] = NULL; - } -} - -static void free_arg_pages(struct linux_binprm *bprm) -{ - int i; - - for (i = 0; i < MAX_ARG_PAGES; i++) - free_arg_page(bprm, i); -} - -static void flush_arg_page(struct linux_binprm *bprm, unsigned long pos, - struct page *page) -{ -} - -static int __bprm_mm_init(struct linux_binprm *bprm) -{ - bprm->p = PAGE_SIZE * MAX_ARG_PAGES - sizeof(void *); - return 0; -} - -static bool valid_arg_len(struct linux_binprm *bprm, long len) -{ - return len <= bprm->p; -} - -#endif /* CONFIG_MMU */ - -/* - * Create a new mm_struct and populate it with a temporary stack - * vm_area_struct. We don't have enough context at this point to set the stack - * flags, permissions, and offset, so we use temporary values. We'll update - * them later in setup_arg_pages(). - */ -static int bprm_mm_init(struct linux_binprm *bprm) -{ - int err; - struct mm_struct *mm = NULL; - - bprm->mm = mm = mm_alloc(); - err = -ENOMEM; - if (!mm) - goto err; - - err = __bprm_mm_init(bprm); - if (err) - goto err; - - return 0; - -err: - if (mm) { - bprm->mm = NULL; - mmdrop(mm); - } - - return err; -} - -struct user_arg_ptr { -#ifdef CONFIG_COMPAT - bool is_compat; -#endif - union { - const char __user *const __user *native; -#ifdef CONFIG_COMPAT - const compat_uptr_t __user *compat; -#endif - } ptr; -}; - -static const char __user *get_user_arg_ptr(struct user_arg_ptr argv, int nr) -{ - const char __user *native; - -#ifdef CONFIG_COMPAT - if (unlikely(argv.is_compat)) { - compat_uptr_t compat; - - if (get_user(compat, argv.ptr.compat + nr)) - return ERR_PTR(-EFAULT); - - return compat_ptr(compat); - } -#endif - - if (get_user(native, argv.ptr.native + nr)) - return ERR_PTR(-EFAULT); - - return native; -} - -/* - * count() counts the number of strings in array ARGV. - */ -static int count(struct user_arg_ptr argv, int max) -{ - int i = 0; - - if (argv.ptr.native != NULL) { - for (;;) { - const char __user *p = get_user_arg_ptr(argv, i); - - if (!p) - break; - - if (IS_ERR(p)) - return -EFAULT; - - if (i >= max) - return -E2BIG; - ++i; - - if (fatal_signal_pending(current)) - return -ERESTARTNOHAND; - cond_resched(); - } - } - return i; -} - -/* - * 'copy_strings()' copies argument/environment strings from the old - * processes's memory to the new process's stack. The call to get_user_pages() - * ensures the destination page is created and not swapped out. - */ -static int copy_strings(int argc, struct user_arg_ptr argv, - struct linux_binprm *bprm) -{ - struct page *kmapped_page = NULL; - char *kaddr = NULL; - unsigned long kpos = 0; - int ret; - - while (argc-- > 0) { - const char __user *str; - int len; - unsigned long pos; - - ret = -EFAULT; - str = get_user_arg_ptr(argv, argc); - if (IS_ERR(str)) - goto out; - - len = strnlen_user(str, MAX_ARG_STRLEN); - if (!len) - goto out; - - ret = -E2BIG; - if (!valid_arg_len(bprm, len)) - goto out; - - /* We're going to work our way backwords. */ - pos = bprm->p; - str += len; - bprm->p -= len; - - while (len > 0) { - int offset, bytes_to_copy; - - if (fatal_signal_pending(current)) { - ret = -ERESTARTNOHAND; - goto out; - } - cond_resched(); - - offset = pos % PAGE_SIZE; - if (offset == 0) - offset = PAGE_SIZE; - - bytes_to_copy = offset; - if (bytes_to_copy > len) - bytes_to_copy = len; - - offset -= bytes_to_copy; - pos -= bytes_to_copy; - str -= bytes_to_copy; - len -= bytes_to_copy; - - if (!kmapped_page || kpos != (pos & PAGE_MASK)) { - struct page *page; - - page = get_arg_page(bprm, pos, 1); - if (!page) { - ret = -E2BIG; - goto out; - } - - if (kmapped_page) { - flush_kernel_dcache_page(kmapped_page); - kunmap(kmapped_page); - put_arg_page(kmapped_page); - } - kmapped_page = page; - kaddr = kmap(kmapped_page); - kpos = pos & PAGE_MASK; - flush_arg_page(bprm, kpos, kmapped_page); - } - if (copy_from_user(kaddr+offset, str, bytes_to_copy)) { - ret = -EFAULT; - goto out; - } - } - } - ret = 0; -out: - if (kmapped_page) { - flush_kernel_dcache_page(kmapped_page); - kunmap(kmapped_page); - put_arg_page(kmapped_page); - } - return ret; -} - -/* - * Like copy_strings, but get argv and its values from kernel memory. - */ -int copy_strings_kernel(int argc, const char *const *__argv, - struct linux_binprm *bprm) -{ - int r; - mm_segment_t oldfs = get_fs(); - struct user_arg_ptr argv = { - .ptr.native = (const char __user *const __user *)__argv, - }; - - set_fs(KERNEL_DS); - r = copy_strings(argc, argv, bprm); - set_fs(oldfs); - - return r; -} -EXPORT_SYMBOL(copy_strings_kernel); - -#ifdef CONFIG_MMU - -/* - * During bprm_mm_init(), we create a temporary stack at STACK_TOP_MAX. Once - * the binfmt code determines where the new stack should reside, we shift it to - * its final location. The process proceeds as follows: - * - * 1) Use shift to calculate the new vma endpoints. - * 2) Extend vma to cover both the old and new ranges. This ensures the - * arguments passed to subsequent functions are consistent. - * 3) Move vma's page tables to the new range. - * 4) Free up any cleared pgd range. - * 5) Shrink the vma to cover only the new range. - */ -static int shift_arg_pages(struct vm_area_struct *vma, unsigned long shift) -{ - struct mm_struct *mm = vma->vm_mm; - unsigned long old_start = vma->vm_start; - unsigned long old_end = vma->vm_end; - unsigned long length = old_end - old_start; - unsigned long new_start = old_start - shift; - unsigned long new_end = old_end - shift; - struct mmu_gather tlb; - - BUG_ON(new_start > new_end); - - /* - * ensure there are no vmas between where we want to go - * and where we are - */ - if (vma != find_vma(mm, new_start)) - return -EFAULT; - - /* - * cover the whole range: [new_start, old_end) - */ - if (vma_adjust(vma, new_start, old_end, vma->vm_pgoff, NULL)) - return -ENOMEM; - - /* - * move the page tables downwards, on failure we rely on - * process cleanup to remove whatever mess we made. - */ - if (length != move_page_tables(vma, old_start, - vma, new_start, length, false)) - return -ENOMEM; - - lru_add_drain(); - tlb_gather_mmu(&tlb, mm, old_start, old_end); - if (new_end > old_start) { - /* - * when the old and new regions overlap clear from new_end. - */ - free_pgd_range(&tlb, new_end, old_end, new_end, - vma->vm_next ? vma->vm_next->vm_start : USER_PGTABLES_CEILING); - } else { - /* - * otherwise, clean from old_start; this is done to not touch - * the address space in [new_end, old_start) some architectures - * have constraints on va-space that make this illegal (IA64) - - * for the others its just a little faster. - */ - free_pgd_range(&tlb, old_start, old_end, new_end, - vma->vm_next ? vma->vm_next->vm_start : USER_PGTABLES_CEILING); - } - tlb_finish_mmu(&tlb, old_start, old_end); - - /* - * Shrink the vma to just the new range. Always succeeds. - */ - vma_adjust(vma, new_start, new_end, vma->vm_pgoff, NULL); - - return 0; -} - -/* - * Finalizes the stack vm_area_struct. The flags and permissions are updated, - * the stack is optionally relocated, and some extra space is added. - */ -int setup_arg_pages(struct linux_binprm *bprm, - unsigned long stack_top, - int executable_stack) -{ - unsigned long ret; - unsigned long stack_shift; - struct mm_struct *mm = current->mm; - struct vm_area_struct *vma = bprm->vma; - struct vm_area_struct *prev = NULL; - unsigned long vm_flags; - unsigned long stack_base; - unsigned long stack_size; - unsigned long stack_expand; - unsigned long rlim_stack; - -#ifdef CONFIG_STACK_GROWSUP - /* Limit stack size */ - stack_base = rlimit_max(RLIMIT_STACK); - if (stack_base > STACK_SIZE_MAX) - stack_base = STACK_SIZE_MAX; - - /* Add space for stack randomization. */ - stack_base += (STACK_RND_MASK << PAGE_SHIFT); - - /* Make sure we didn't let the argument array grow too large. */ - if (vma->vm_end - vma->vm_start > stack_base) - return -ENOMEM; - - stack_base = PAGE_ALIGN(stack_top - stack_base); - - stack_shift = vma->vm_start - stack_base; - mm->arg_start = bprm->p - stack_shift; - bprm->p = vma->vm_end - stack_shift; -#else - stack_top = arch_align_stack(stack_top); - stack_top = PAGE_ALIGN(stack_top); - - if (unlikely(stack_top < mmap_min_addr) || - unlikely(vma->vm_end - vma->vm_start >= stack_top - mmap_min_addr)) - return -ENOMEM; - - stack_shift = vma->vm_end - stack_top; - - bprm->p -= stack_shift; - mm->arg_start = bprm->p; -#endif - - if (bprm->loader) - bprm->loader -= stack_shift; - bprm->exec -= stack_shift; - - if (down_write_killable(&mm->mmap_sem)) - return -EINTR; - - vm_flags = VM_STACK_FLAGS; - - /* - * Adjust stack execute permissions; explicitly enable for - * EXSTACK_ENABLE_X, disable for EXSTACK_DISABLE_X and leave alone - * (arch default) otherwise. - */ - if (unlikely(executable_stack == EXSTACK_ENABLE_X)) - vm_flags |= VM_EXEC; - else if (executable_stack == EXSTACK_DISABLE_X) - vm_flags &= ~VM_EXEC; - vm_flags |= mm->def_flags; - vm_flags |= VM_STACK_INCOMPLETE_SETUP; - - ret = mprotect_fixup(vma, &prev, vma->vm_start, vma->vm_end, - vm_flags); - if (ret) - goto out_unlock; - BUG_ON(prev != vma); - - /* Move stack pages down in memory. */ - if (stack_shift) { - ret = shift_arg_pages(vma, stack_shift); - if (ret) - goto out_unlock; - } - - /* mprotect_fixup is overkill to remove the temporary stack flags */ - vma->vm_flags &= ~VM_STACK_INCOMPLETE_SETUP; - - stack_expand = 131072UL; /* randomly 32*4k (or 2*64k) pages */ - stack_size = vma->vm_end - vma->vm_start; - /* - * Align this down to a page boundary as expand_stack - * will align it up. - */ - rlim_stack = rlimit(RLIMIT_STACK) & PAGE_MASK; -#ifdef CONFIG_STACK_GROWSUP - if (stack_size + stack_expand > rlim_stack) - stack_base = vma->vm_start + rlim_stack; - else - stack_base = vma->vm_end + stack_expand; -#else - if (stack_size + stack_expand > rlim_stack) - stack_base = vma->vm_end - rlim_stack; - else - stack_base = vma->vm_start - stack_expand; -#endif - current->mm->start_stack = bprm->p; - ret = expand_stack(vma, stack_base); - if (ret) - ret = -EFAULT; - -out_unlock: - up_write(&mm->mmap_sem); - return ret; -} -EXPORT_SYMBOL(setup_arg_pages); - -#else - -/* - * Transfer the program arguments and environment from the holding pages - * onto the stack. The provided stack pointer is adjusted accordingly. - */ -int transfer_args_to_stack(struct linux_binprm *bprm, - unsigned long *sp_location) -{ - unsigned long index, stop, sp; - int ret = 0; - - stop = bprm->p >> PAGE_SHIFT; - sp = *sp_location; - - for (index = MAX_ARG_PAGES - 1; index >= stop; index--) { - unsigned int offset = index == stop ? bprm->p & ~PAGE_MASK : 0; - char *src = kmap(bprm->page[index]) + offset; - sp -= PAGE_SIZE - offset; - if (copy_to_user((void *) sp, src, PAGE_SIZE - offset) != 0) - ret = -EFAULT; - kunmap(bprm->page[index]); - if (ret) - goto out; - } - - *sp_location = sp; - -out: - return ret; -} -EXPORT_SYMBOL(transfer_args_to_stack); - -#endif /* CONFIG_MMU */ - -static struct file *do_open_execat(int fd, struct filename *name, int flags) -{ - struct file *file; - int err; - struct open_flags open_exec_flags = { - .open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, - .acc_mode = MAY_EXEC, - .intent = LOOKUP_OPEN, - .lookup_flags = LOOKUP_FOLLOW, - }; - - if ((flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0) - return ERR_PTR(-EINVAL); - if (flags & AT_SYMLINK_NOFOLLOW) - open_exec_flags.lookup_flags &= ~LOOKUP_FOLLOW; - if (flags & AT_EMPTY_PATH) - open_exec_flags.lookup_flags |= LOOKUP_EMPTY; - - file = do_filp_open(fd, name, &open_exec_flags); - if (IS_ERR(file)) - goto out; - - err = -EACCES; - if (!S_ISREG(file_inode(file)->i_mode)) - goto exit; - - if (path_noexec(&file->f_path)) - goto exit; - - err = deny_write_access(file); - if (err) - goto exit; - - if (name->name[0] != '\0') - fsnotify_open(file); - -out: - return file; - -exit: - fput(file); - return ERR_PTR(err); -} - -struct file *open_exec(const char *name) -{ - struct filename *filename = getname_kernel(name); - struct file *f = ERR_CAST(filename); - - if (!IS_ERR(filename)) { - f = do_open_execat(AT_FDCWD, filename, 0); - putname(filename); - } - return f; -} -EXPORT_SYMBOL(open_exec); - -int kernel_read(struct file *file, loff_t offset, - char *addr, unsigned long count) -{ - mm_segment_t old_fs; - loff_t pos = offset; - int result; - - old_fs = get_fs(); - set_fs(get_ds()); - /* The cast to a user pointer is valid due to the set_fs() */ - result = vfs_read(file, (void __user *)addr, count, &pos); - set_fs(old_fs); - return result; -} - -EXPORT_SYMBOL(kernel_read); - -int kernel_read_file(struct file *file, void **buf, loff_t *size, - loff_t max_size, enum kernel_read_file_id id) -{ - loff_t i_size, pos; - ssize_t bytes = 0; - int ret; - - if (!S_ISREG(file_inode(file)->i_mode) || max_size < 0) - return -EINVAL; - - ret = security_kernel_read_file(file, id); - if (ret) - return ret; - - ret = deny_write_access(file); - if (ret) - return ret; - - i_size = i_size_read(file_inode(file)); - if (max_size > 0 && i_size > max_size) { - ret = -EFBIG; - goto out; - } - if (i_size <= 0) { - ret = -EINVAL; - goto out; - } - - if (id != READING_FIRMWARE_PREALLOC_BUFFER) - *buf = vmalloc(i_size); - if (!*buf) { - ret = -ENOMEM; - goto out; - } - - pos = 0; - while (pos < i_size) { - bytes = kernel_read(file, pos, (char *)(*buf) + pos, - i_size - pos); - if (bytes < 0) { - ret = bytes; - goto out; - } - - if (bytes == 0) - break; - pos += bytes; - } - - if (pos != i_size) { - ret = -EIO; - goto out_free; - } - - ret = security_kernel_post_read_file(file, *buf, i_size, id); - if (!ret) - *size = pos; - -out_free: - if (ret < 0) { - if (id != READING_FIRMWARE_PREALLOC_BUFFER) { - vfree(*buf); - *buf = NULL; - } - } - -out: - allow_write_access(file); - return ret; -} -EXPORT_SYMBOL_GPL(kernel_read_file); - -int kernel_read_file_from_path(char *path, void **buf, loff_t *size, - loff_t max_size, enum kernel_read_file_id id) -{ - struct file *file; - int ret; - - if (!path || !*path) - return -EINVAL; - - file = filp_open(path, O_RDONLY, 0); - if (IS_ERR(file)) - return PTR_ERR(file); - - ret = kernel_read_file(file, buf, size, max_size, id); - fput(file); - return ret; -} -EXPORT_SYMBOL_GPL(kernel_read_file_from_path); - -int kernel_read_file_from_fd(int fd, void **buf, loff_t *size, loff_t max_size, - enum kernel_read_file_id id) -{ - struct fd f = fdget(fd); - int ret = -EBADF; - - if (!f.file) - goto out; - - ret = kernel_read_file(f.file, buf, size, max_size, id); -out: - fdput(f); - return ret; -} -EXPORT_SYMBOL_GPL(kernel_read_file_from_fd); - -ssize_t read_code(struct file *file, unsigned long addr, loff_t pos, size_t len) -{ - ssize_t res = vfs_read(file, (void __user *)addr, len, &pos); - if (res > 0) - flush_icache_range(addr, addr + len); - return res; -} -EXPORT_SYMBOL(read_code); - -static int exec_mmap(struct mm_struct *mm) -{ - struct task_struct *tsk; - struct mm_struct *old_mm, *active_mm; - - /* Notify parent that we're no longer interested in the old VM */ - tsk = current; - old_mm = current->mm; - mm_release(tsk, old_mm); - - if (old_mm) { - sync_mm_rss(old_mm); - /* - * Make sure that if there is a core dump in progress - * for the old mm, we get out and die instead of going - * through with the exec. We must hold mmap_sem around - * checking core_state and changing tsk->mm. - */ - down_read(&old_mm->mmap_sem); - if (unlikely(old_mm->core_state)) { - up_read(&old_mm->mmap_sem); - return -EINTR; - } - } - task_lock(tsk); - active_mm = tsk->active_mm; - tsk->mm = mm; - tsk->active_mm = mm; - activate_mm(active_mm, mm); - tsk->mm->vmacache_seqnum = 0; - vmacache_flush(tsk); - task_unlock(tsk); - if (old_mm) { - up_read(&old_mm->mmap_sem); - BUG_ON(active_mm != old_mm); - setmax_mm_hiwater_rss(&tsk->signal->maxrss, old_mm); - mm_update_next_owner(old_mm); - mmput(old_mm); - return 0; - } - mmdrop(active_mm); - return 0; -} - -/* - * This function makes sure the current process has its own signal table, - * so that flush_signal_handlers can later reset the handlers without - * disturbing other processes. (Other processes might share the signal - * table via the CLONE_SIGHAND option to clone().) - */ -static int de_thread(struct task_struct *tsk) -{ - struct signal_struct *sig = tsk->signal; - struct sighand_struct *oldsighand = tsk->sighand; - spinlock_t *lock = &oldsighand->siglock; - - if (thread_group_empty(tsk)) - goto no_thread_group; - - /* - * Kill all other threads in the thread group. - */ - spin_lock_irq(lock); - if (signal_group_exit(sig)) { - /* - * Another group action in progress, just - * return so that the signal is processed. - */ - spin_unlock_irq(lock); - return -EAGAIN; - } - - sig->group_exit_task = tsk; - sig->notify_count = zap_other_threads(tsk); - if (!thread_group_leader(tsk)) - sig->notify_count--; - - while (sig->notify_count) { - __set_current_state(TASK_KILLABLE); - spin_unlock_irq(lock); - schedule(); - if (unlikely(__fatal_signal_pending(tsk))) - goto killed; - spin_lock_irq(lock); - } - spin_unlock_irq(lock); - - /* - * At this point all other threads have exited, all we have to - * do is to wait for the thread group leader to become inactive, - * and to assume its PID: - */ - if (!thread_group_leader(tsk)) { - struct task_struct *leader = tsk->group_leader; - - for (;;) { - threadgroup_change_begin(tsk); - write_lock_irq(&tasklist_lock); - /* - * Do this under tasklist_lock to ensure that - * exit_notify() can't miss ->group_exit_task - */ - sig->notify_count = -1; - if (likely(leader->exit_state)) - break; - __set_current_state(TASK_KILLABLE); - write_unlock_irq(&tasklist_lock); - threadgroup_change_end(tsk); - schedule(); - if (unlikely(__fatal_signal_pending(tsk))) - goto killed; - } - - /* - * The only record we have of the real-time age of a - * process, regardless of execs it's done, is start_time. - * All the past CPU time is accumulated in signal_struct - * from sister threads now dead. But in this non-leader - * exec, nothing survives from the original leader thread, - * whose birth marks the true age of this process now. - * When we take on its identity by switching to its PID, we - * also take its birthdate (always earlier than our own). - */ - tsk->start_time = leader->start_time; - tsk->real_start_time = leader->real_start_time; - - BUG_ON(!same_thread_group(leader, tsk)); - BUG_ON(has_group_leader_pid(tsk)); - /* - * An exec() starts a new thread group with the - * TGID of the previous thread group. Rehash the - * two threads with a switched PID, and release - * the former thread group leader: - */ - - /* Become a process group leader with the old leader's pid. - * The old leader becomes a thread of the this thread group. - * Note: The old leader also uses this pid until release_task - * is called. Odd but simple and correct. - */ - tsk->pid = leader->pid; - change_pid(tsk, PIDTYPE_PID, task_pid(leader)); - transfer_pid(leader, tsk, PIDTYPE_PGID); - transfer_pid(leader, tsk, PIDTYPE_SID); - - list_replace_rcu(&leader->tasks, &tsk->tasks); - list_replace_init(&leader->sibling, &tsk->sibling); - - tsk->group_leader = tsk; - leader->group_leader = tsk; - - tsk->exit_signal = SIGCHLD; - leader->exit_signal = -1; - - BUG_ON(leader->exit_state != EXIT_ZOMBIE); - leader->exit_state = EXIT_DEAD; - - /* - * We are going to release_task()->ptrace_unlink() silently, - * the tracer can sleep in do_wait(). EXIT_DEAD guarantees - * the tracer wont't block again waiting for this thread. - */ - if (unlikely(leader->ptrace)) - __wake_up_parent(leader, leader->parent); - write_unlock_irq(&tasklist_lock); - threadgroup_change_end(tsk); - - release_task(leader); - } - - sig->group_exit_task = NULL; - sig->notify_count = 0; - -no_thread_group: - /* we have changed execution domain */ - tsk->exit_signal = SIGCHLD; - - exit_itimers(sig); - flush_itimer_signals(); - - if (atomic_read(&oldsighand->count) != 1) { - struct sighand_struct *newsighand; - /* - * This ->sighand is shared with the CLONE_SIGHAND - * but not CLONE_THREAD task, switch to the new one. - */ - newsighand = kmem_cache_alloc(sighand_cachep, GFP_KERNEL); - if (!newsighand) - return -ENOMEM; - - atomic_set(&newsighand->count, 1); - memcpy(newsighand->action, oldsighand->action, - sizeof(newsighand->action)); - - write_lock_irq(&tasklist_lock); - spin_lock(&oldsighand->siglock); - rcu_assign_pointer(tsk->sighand, newsighand); - spin_unlock(&oldsighand->siglock); - write_unlock_irq(&tasklist_lock); - - __cleanup_sighand(oldsighand); - } - - BUG_ON(!thread_group_leader(tsk)); - return 0; - -killed: - /* protects against exit_notify() and __exit_signal() */ - read_lock(&tasklist_lock); - sig->group_exit_task = NULL; - sig->notify_count = 0; - read_unlock(&tasklist_lock); - return -EAGAIN; -} - -char *get_task_comm(char *buf, struct task_struct *tsk) -{ - /* buf must be at least sizeof(tsk->comm) in size */ - task_lock(tsk); - strncpy(buf, tsk->comm, sizeof(tsk->comm)); - task_unlock(tsk); - return buf; -} -EXPORT_SYMBOL_GPL(get_task_comm); - -/* - * These functions flushes out all traces of the currently running executable - * so that a new one can be started - */ - -void __set_task_comm(struct task_struct *tsk, const char *buf, bool exec) -{ - task_lock(tsk); - trace_task_rename(tsk, buf); - strlcpy(tsk->comm, buf, sizeof(tsk->comm)); - task_unlock(tsk); - perf_event_comm(tsk, exec); -} - -int flush_old_exec(struct linux_binprm * bprm) -{ - int retval; - - /* - * Make sure we have a private signal table and that - * we are unassociated from the previous thread group. - */ - retval = de_thread(current); - if (retval) - goto out; - - /* - * Must be called _before_ exec_mmap() as bprm->mm is - * not visibile until then. This also enables the update - * to be lockless. - */ - set_mm_exe_file(bprm->mm, bprm->file); - - /* - * Release all of the old mmap stuff - */ - acct_arg_size(bprm, 0); - retval = exec_mmap(bprm->mm); - if (retval) - goto out; - - bprm->mm = NULL; /* We're using it now */ - - set_fs(USER_DS); - current->flags &= ~(PF_RANDOMIZE | PF_FORKNOEXEC | PF_KTHREAD | - PF_NOFREEZE | PF_NO_SETAFFINITY); - flush_thread(); - current->personality &= ~bprm->per_clear; - - return 0; - -out: - return retval; -} -EXPORT_SYMBOL(flush_old_exec); - -void would_dump(struct linux_binprm *bprm, struct file *file) -{ - if (inode_permission(file_inode(file), MAY_READ) < 0) - bprm->interp_flags |= BINPRM_FLAGS_ENFORCE_NONDUMP; -} -EXPORT_SYMBOL(would_dump); - -void setup_new_exec(struct linux_binprm * bprm) -{ - arch_pick_mmap_layout(current->mm); - - /* This is the point of no return */ - current->sas_ss_sp = current->sas_ss_size = 0; - - if (uid_eq(current_euid(), current_uid()) && gid_eq(current_egid(), current_gid())) - set_dumpable(current->mm, SUID_DUMP_USER); - else - set_dumpable(current->mm, suid_dumpable); - - perf_event_exec(); - __set_task_comm(current, kbasename(bprm->filename), true); - - /* Set the new mm task size. We have to do that late because it may - * depend on TIF_32BIT which is only updated in flush_thread() on - * some architectures like powerpc - */ - current->mm->task_size = TASK_SIZE; - - /* install the new credentials */ - if (!uid_eq(bprm->cred->uid, current_euid()) || - !gid_eq(bprm->cred->gid, current_egid())) { - current->pdeath_signal = 0; - } else { - would_dump(bprm, bprm->file); - if (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP) - set_dumpable(current->mm, suid_dumpable); - } - - /* An exec changes our domain. We are no longer part of the thread - group */ - current->self_exec_id++; - flush_signal_handlers(current, 0); - do_close_on_exec(current->files); -} -EXPORT_SYMBOL(setup_new_exec); - -/* - * Prepare credentials and lock ->cred_guard_mutex. - * install_exec_creds() commits the new creds and drops the lock. - * Or, if exec fails before, free_bprm() should release ->cred and - * and unlock. - */ -int prepare_bprm_creds(struct linux_binprm *bprm) -{ - if (mutex_lock_interruptible(¤t->signal->cred_guard_mutex)) - return -ERESTARTNOINTR; - - bprm->cred = prepare_exec_creds(); - if (likely(bprm->cred)) - return 0; - - mutex_unlock(¤t->signal->cred_guard_mutex); - return -ENOMEM; -} - -static void free_bprm(struct linux_binprm *bprm) -{ - free_arg_pages(bprm); - if (bprm->cred) { - mutex_unlock(¤t->signal->cred_guard_mutex); - abort_creds(bprm->cred); - } - if (bprm->file) { - allow_write_access(bprm->file); - fput(bprm->file); - } - /* If a binfmt changed the interp, free it. */ - if (bprm->interp != bprm->filename) - kfree(bprm->interp); - kfree(bprm); -} - -int bprm_change_interp(char *interp, struct linux_binprm *bprm) -{ - /* If a binfmt changed the interp, free it first. */ - if (bprm->interp != bprm->filename) - kfree(bprm->interp); - bprm->interp = kstrdup(interp, GFP_KERNEL); - if (!bprm->interp) - return -ENOMEM; - return 0; -} -EXPORT_SYMBOL(bprm_change_interp); - -/* - * install the new credentials for this executable - */ -void install_exec_creds(struct linux_binprm *bprm) -{ - security_bprm_committing_creds(bprm); - - commit_creds(bprm->cred); - bprm->cred = NULL; - - /* - * Disable monitoring for regular users - * when executing setuid binaries. Must - * wait until new credentials are committed - * by commit_creds() above - */ - if (get_dumpable(current->mm) != SUID_DUMP_USER) - perf_event_exit_task(current); - /* - * cred_guard_mutex must be held at least to this point to prevent - * ptrace_attach() from altering our determination of the task's - * credentials; any time after this it may be unlocked. - */ - security_bprm_committed_creds(bprm); - mutex_unlock(¤t->signal->cred_guard_mutex); -} -EXPORT_SYMBOL(install_exec_creds); - -/* - * determine how safe it is to execute the proposed program - * - the caller must hold ->cred_guard_mutex to protect against - * PTRACE_ATTACH or seccomp thread-sync - */ -static void check_unsafe_exec(struct linux_binprm *bprm) -{ - struct task_struct *p = current, *t; - unsigned n_fs; - - if (p->ptrace) { - if (p->ptrace & PT_PTRACE_CAP) - bprm->unsafe |= LSM_UNSAFE_PTRACE_CAP; - else - bprm->unsafe |= LSM_UNSAFE_PTRACE; - } - - /* - * This isn't strictly necessary, but it makes it harder for LSMs to - * mess up. - */ - if (task_no_new_privs(current)) - bprm->unsafe |= LSM_UNSAFE_NO_NEW_PRIVS; - - t = p; - n_fs = 1; - spin_lock(&p->fs->lock); - rcu_read_lock(); - while_each_thread(p, t) { - if (t->fs == p->fs) - n_fs++; - } - rcu_read_unlock(); - - if (p->fs->users > n_fs) - bprm->unsafe |= LSM_UNSAFE_SHARE; - else - p->fs->in_exec = 1; - spin_unlock(&p->fs->lock); -} - -static void bprm_fill_uid(struct linux_binprm *bprm) -{ - struct inode *inode; - unsigned int mode; - kuid_t uid; - kgid_t gid; - - /* - * Since this can be called multiple times (via prepare_binprm), - * we must clear any previous work done when setting set[ug]id - * bits from any earlier bprm->file uses (for example when run - * first for a setuid script then again for its interpreter). - */ - bprm->cred->euid = current_euid(); - bprm->cred->egid = current_egid(); - - if (!mnt_may_suid(bprm->file->f_path.mnt)) - return; - - if (task_no_new_privs(current)) - return; - - inode = file_inode(bprm->file); - mode = READ_ONCE(inode->i_mode); - if (!(mode & (S_ISUID|S_ISGID))) - return; - - /* Be careful if suid/sgid is set */ - inode_lock(inode); - - /* reload atomically mode/uid/gid now that lock held */ - mode = inode->i_mode; - uid = inode->i_uid; - gid = inode->i_gid; - inode_unlock(inode); - - /* We ignore suid/sgid if there are no mappings for them in the ns */ - if (!kuid_has_mapping(bprm->cred->user_ns, uid) || - !kgid_has_mapping(bprm->cred->user_ns, gid)) - return; - - if (mode & S_ISUID) { - bprm->per_clear |= PER_CLEAR_ON_SETID; - bprm->cred->euid = uid; - } - - if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) { - bprm->per_clear |= PER_CLEAR_ON_SETID; - bprm->cred->egid = gid; - } -} - -/* - * Fill the binprm structure from the inode. - * Check permissions, then read the first 128 (BINPRM_BUF_SIZE) bytes - * - * This may be called multiple times for binary chains (scripts for example). - */ -int prepare_binprm(struct linux_binprm *bprm) -{ - int retval; - - bprm_fill_uid(bprm); - - /* fill in binprm security blob */ - retval = security_bprm_set_creds(bprm); - if (retval) - return retval; - bprm->cred_prepared = 1; - - memset(bprm->buf, 0, BINPRM_BUF_SIZE); - return kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE); -} - -EXPORT_SYMBOL(prepare_binprm); - -/* - * Arguments are '\0' separated strings found at the location bprm->p - * points to; chop off the first by relocating brpm->p to right after - * the first '\0' encountered. - */ -int remove_arg_zero(struct linux_binprm *bprm) -{ - int ret = 0; - unsigned long offset; - char *kaddr; - struct page *page; - - if (!bprm->argc) - return 0; - - do { - offset = bprm->p & ~PAGE_MASK; - page = get_arg_page(bprm, bprm->p, 0); - if (!page) { - ret = -EFAULT; - goto out; - } - kaddr = kmap_atomic(page); - - for (; offset < PAGE_SIZE && kaddr[offset]; - offset++, bprm->p++) - ; - - kunmap_atomic(kaddr); - put_arg_page(page); - } while (offset == PAGE_SIZE); - - bprm->p++; - bprm->argc--; - ret = 0; - -out: - return ret; -} -EXPORT_SYMBOL(remove_arg_zero); - -#define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e)) -/* - * cycle the list of binary formats handler, until one recognizes the image - */ -int search_binary_handler(struct linux_binprm *bprm) -{ - bool need_retry = IS_ENABLED(CONFIG_MODULES); - struct linux_binfmt *fmt; - int retval; - - /* This allows 4 levels of binfmt rewrites before failing hard. */ - if (bprm->recursion_depth > 5) - return -ELOOP; - - retval = security_bprm_check(bprm); - if (retval) - return retval; - - retval = -ENOENT; - retry: - read_lock(&binfmt_lock); - list_for_each_entry(fmt, &formats, lh) { - if (!try_module_get(fmt->module)) - continue; - read_unlock(&binfmt_lock); - bprm->recursion_depth++; - retval = fmt->load_binary(bprm); - read_lock(&binfmt_lock); - put_binfmt(fmt); - bprm->recursion_depth--; - if (retval < 0 && !bprm->mm) { - /* we got to flush_old_exec() and failed after it */ - read_unlock(&binfmt_lock); - force_sigsegv(SIGSEGV, current); - return retval; - } - if (retval != -ENOEXEC || !bprm->file) { - read_unlock(&binfmt_lock); - return retval; - } - } - read_unlock(&binfmt_lock); - - if (need_retry) { - if (printable(bprm->buf[0]) && printable(bprm->buf[1]) && - printable(bprm->buf[2]) && printable(bprm->buf[3])) - return retval; - if (request_module("binfmt-%04x", *(ushort *)(bprm->buf + 2)) < 0) - return retval; - need_retry = false; - goto retry; - } - - return retval; -} -EXPORT_SYMBOL(search_binary_handler); - -static int exec_binprm(struct linux_binprm *bprm) -{ - pid_t old_pid, old_vpid; - int ret; - - /* Need to fetch pid before load_binary changes it */ - old_pid = current->pid; - rcu_read_lock(); - old_vpid = task_pid_nr_ns(current, task_active_pid_ns(current->parent)); - rcu_read_unlock(); - - ret = search_binary_handler(bprm); - if (ret >= 0) { - audit_bprm(bprm); - trace_sched_process_exec(current, old_pid, bprm); - ptrace_event(PTRACE_EVENT_EXEC, old_vpid); - proc_exec_connector(current); - } - - return ret; -} - -/* - * sys_execve() executes a new program. - */ -static int do_execveat_common(int fd, struct filename *filename, - struct user_arg_ptr argv, - struct user_arg_ptr envp, - int flags) -{ - char *pathbuf = NULL; - struct linux_binprm *bprm; - struct file *file; - struct files_struct *displaced; - int retval; - - if (IS_ERR(filename)) - return PTR_ERR(filename); - - /* - * We move the actual failure in case of RLIMIT_NPROC excess from - * set*uid() to execve() because too many poorly written programs - * don't check setuid() return code. Here we additionally recheck - * whether NPROC limit is still exceeded. - */ - if ((current->flags & PF_NPROC_EXCEEDED) && - atomic_read(¤t_user()->processes) > rlimit(RLIMIT_NPROC)) { - retval = -EAGAIN; - goto out_ret; - } - - /* We're below the limit (still or again), so we don't want to make - * further execve() calls fail. */ - current->flags &= ~PF_NPROC_EXCEEDED; - - retval = unshare_files(&displaced); - if (retval) - goto out_ret; - - retval = -ENOMEM; - bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); - if (!bprm) - goto out_files; - - retval = prepare_bprm_creds(bprm); - if (retval) - goto out_free; - - check_unsafe_exec(bprm); - current->in_execve = 1; - - file = do_open_execat(fd, filename, flags); - retval = PTR_ERR(file); - if (IS_ERR(file)) - goto out_unmark; - - sched_exec(); - - bprm->file = file; - if (fd == AT_FDCWD || filename->name[0] == '/') { - bprm->filename = filename->name; - } else { - if (filename->name[0] == '\0') - pathbuf = kasprintf(GFP_TEMPORARY, "/dev/fd/%d", fd); - else - pathbuf = kasprintf(GFP_TEMPORARY, "/dev/fd/%d/%s", - fd, filename->name); - if (!pathbuf) { - retval = -ENOMEM; - goto out_unmark; - } - /* - * Record that a name derived from an O_CLOEXEC fd will be - * inaccessible after exec. Relies on having exclusive access to - * current->files (due to unshare_files above). - */ - if (close_on_exec(fd, rcu_dereference_raw(current->files->fdt))) - bprm->interp_flags |= BINPRM_FLAGS_PATH_INACCESSIBLE; - bprm->filename = pathbuf; - } - bprm->interp = bprm->filename; - - retval = bprm_mm_init(bprm); - if (retval) - goto out_unmark; - - bprm->argc = count(argv, MAX_ARG_STRINGS); - if ((retval = bprm->argc) < 0) - goto out; - - bprm->envc = count(envp, MAX_ARG_STRINGS); - if ((retval = bprm->envc) < 0) - goto out; - - retval = prepare_binprm(bprm); - if (retval < 0) - goto out; - - retval = copy_strings_kernel(1, &bprm->filename, bprm); - if (retval < 0) - goto out; - - bprm->exec = bprm->p; - retval = copy_strings(bprm->envc, envp, bprm); - if (retval < 0) - goto out; - - retval = copy_strings(bprm->argc, argv, bprm); - if (retval < 0) - goto out; - - retval = exec_binprm(bprm); - if (retval < 0) - goto out; - - /* execve succeeded */ - current->fs->in_exec = 0; - current->in_execve = 0; - acct_update_integrals(current); - task_numa_free(current); - free_bprm(bprm); - kfree(pathbuf); - putname(filename); - if (displaced) - put_files_struct(displaced); - return retval; - -out: - if (bprm->mm) { - acct_arg_size(bprm, 0); - mmput(bprm->mm); - } - -out_unmark: - current->fs->in_exec = 0; - current->in_execve = 0; - -out_free: - free_bprm(bprm); - kfree(pathbuf); - -out_files: - if (displaced) - reset_files_struct(displaced); -out_ret: - putname(filename); - return retval; -} - -int do_execve(struct filename *filename, - const char __user *const __user *__argv, - const char __user *const __user *__envp) -{ - struct user_arg_ptr argv = { .ptr.native = __argv }; - struct user_arg_ptr envp = { .ptr.native = __envp }; - return do_execveat_common(AT_FDCWD, filename, argv, envp, 0); -} - -int do_execveat(int fd, struct filename *filename, - const char __user *const __user *__argv, - const char __user *const __user *__envp, - int flags) -{ - struct user_arg_ptr argv = { .ptr.native = __argv }; - struct user_arg_ptr envp = { .ptr.native = __envp }; - - return do_execveat_common(fd, filename, argv, envp, flags); -} - -#ifdef CONFIG_COMPAT -static int compat_do_execve(struct filename *filename, - const compat_uptr_t __user *__argv, - const compat_uptr_t __user *__envp) -{ - struct user_arg_ptr argv = { - .is_compat = true, - .ptr.compat = __argv, - }; - struct user_arg_ptr envp = { - .is_compat = true, - .ptr.compat = __envp, - }; - return do_execveat_common(AT_FDCWD, filename, argv, envp, 0); -} - -static int compat_do_execveat(int fd, struct filename *filename, - const compat_uptr_t __user *__argv, - const compat_uptr_t __user *__envp, - int flags) -{ - struct user_arg_ptr argv = { - .is_compat = true, - .ptr.compat = __argv, - }; - struct user_arg_ptr envp = { - .is_compat = true, - .ptr.compat = __envp, - }; - return do_execveat_common(fd, filename, argv, envp, flags); -} -#endif - -void set_binfmt(struct linux_binfmt *new) -{ - struct mm_struct *mm = current->mm; - - if (mm->binfmt) - module_put(mm->binfmt->module); - - mm->binfmt = new; - if (new) - __module_get(new->module); -} -EXPORT_SYMBOL(set_binfmt); - -/* - * set_dumpable stores three-value SUID_DUMP_* into mm->flags. - */ -void set_dumpable(struct mm_struct *mm, int value) -{ - unsigned long old, new; - - if (WARN_ON((unsigned)value > SUID_DUMP_ROOT)) - return; - - do { - old = ACCESS_ONCE(mm->flags); - new = (old & ~MMF_DUMPABLE_MASK) | value; - } while (cmpxchg(&mm->flags, old, new) != old); -} - -SYSCALL_DEFINE3(execve, - const char __user *, filename, - const char __user *const __user *, argv, - const char __user *const __user *, envp) -{ - return do_execve(getname(filename), argv, envp); -} - -SYSCALL_DEFINE5(execveat, - int, fd, const char __user *, filename, - const char __user *const __user *, argv, - const char __user *const __user *, envp, - int, flags) -{ - int lookup_flags = (flags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0; - - return do_execveat(fd, - getname_flags(filename, lookup_flags, NULL), - argv, envp, flags); -} - -#ifdef CONFIG_COMPAT -COMPAT_SYSCALL_DEFINE3(execve, const char __user *, filename, - const compat_uptr_t __user *, argv, - const compat_uptr_t __user *, envp) -{ - return compat_do_execve(getname(filename), argv, envp); -} - -COMPAT_SYSCALL_DEFINE5(execveat, int, fd, - const char __user *, filename, - const compat_uptr_t __user *, argv, - const compat_uptr_t __user *, envp, - int, flags) -{ - int lookup_flags = (flags & AT_EMPTY_PATH) ? LOOKUP_EMPTY : 0; - - return compat_do_execveat(fd, - getname_flags(filename, lookup_flags, NULL), - argv, envp, flags); -} -#endif diff --git a/src/linux/fs/exofs/Kbuild b/src/linux/fs/exofs/Kbuild deleted file mode 100644 index a364fd0..0000000 --- a/src/linux/fs/exofs/Kbuild +++ /dev/null @@ -1,20 +0,0 @@ -# -# Kbuild for the EXOFS module -# -# Copyright (C) 2008 Panasas Inc. All rights reserved. -# -# Authors: -# Boaz Harrosh -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License version 2 -# -# Kbuild - Gets included from the Kernels Makefile and build system -# - -# ore module library -libore-y := ore.o ore_raid.o -obj-$(CONFIG_ORE) += libore.o - -exofs-y := inode.o file.o namei.o dir.o super.o sys.o -obj-$(CONFIG_EXOFS_FS) += exofs.o diff --git a/src/linux/fs/exofs/Kconfig b/src/linux/fs/exofs/Kconfig deleted file mode 100644 index 86194b2..0000000 --- a/src/linux/fs/exofs/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config EXOFS_FS - tristate "exofs: OSD based file system support" - depends on SCSI_OSD_ULD - help - EXOFS is a file system that uses an OSD storage device, - as its backing storage. - -# Debugging-related stuff -config EXOFS_DEBUG - bool "Enable debugging" - depends on EXOFS_FS - help - This option enables EXOFS debug prints. diff --git a/src/linux/fs/exofs/Kconfig.ore b/src/linux/fs/exofs/Kconfig.ore deleted file mode 100644 index 2daf232..0000000 --- a/src/linux/fs/exofs/Kconfig.ore +++ /dev/null @@ -1,14 +0,0 @@ -# ORE - Objects Raid Engine (libore.ko) -# -# Note ORE needs to "select ASYNC_XOR". So Not to force multiple selects -# for every ORE user we do it like this. Any user should add itself here -# at the "depends on EXOFS_FS || ..." with an ||. The dependencies are -# selected here, and we default to "ON". So in effect it is like been -# selected by any of the users. -config ORE - tristate - depends on EXOFS_FS || PNFS_OBJLAYOUT - select ASYNC_XOR - select RAID6_PQ - select ASYNC_PQ - default SCSI_OSD_ULD diff --git a/src/linux/fs/exportfs/Makefile b/src/linux/fs/exportfs/Makefile deleted file mode 100644 index d7c5d4d..0000000 --- a/src/linux/fs/exportfs/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# -# Makefile for the filesystem export support routines. - -obj-$(CONFIG_EXPORTFS) += exportfs.o - -exportfs-objs := expfs.o diff --git a/src/linux/fs/exportfs/expfs.c b/src/linux/fs/exportfs/expfs.c deleted file mode 100644 index a4b531b..0000000 --- a/src/linux/fs/exportfs/expfs.c +++ /dev/null @@ -1,550 +0,0 @@ -/* - * Copyright (C) Neil Brown 2002 - * Copyright (C) Christoph Hellwig 2007 - * - * This file contains the code mapping from inodes to NFS file handles, - * and for mapping back from file handles to dentries. - * - * For details on why we do all the strange and hairy things in here - * take a look at Documentation/filesystems/nfs/Exporting. - */ -#include -#include -#include -#include -#include -#include -#include - -#define dprintk(fmt, args...) do{}while(0) - - -static int get_name(const struct path *path, char *name, struct dentry *child); - - -static int exportfs_get_name(struct vfsmount *mnt, struct dentry *dir, - char *name, struct dentry *child) -{ - const struct export_operations *nop = dir->d_sb->s_export_op; - struct path path = {.mnt = mnt, .dentry = dir}; - - if (nop->get_name) - return nop->get_name(dir, name, child); - else - return get_name(&path, name, child); -} - -/* - * Check if the dentry or any of it's aliases is acceptable. - */ -static struct dentry * -find_acceptable_alias(struct dentry *result, - int (*acceptable)(void *context, struct dentry *dentry), - void *context) -{ - struct dentry *dentry, *toput = NULL; - struct inode *inode; - - if (acceptable(context, result)) - return result; - - inode = result->d_inode; - spin_lock(&inode->i_lock); - hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) { - dget(dentry); - spin_unlock(&inode->i_lock); - if (toput) - dput(toput); - if (dentry != result && acceptable(context, dentry)) { - dput(result); - return dentry; - } - spin_lock(&inode->i_lock); - toput = dentry; - } - spin_unlock(&inode->i_lock); - - if (toput) - dput(toput); - return NULL; -} - -static bool dentry_connected(struct dentry *dentry) -{ - dget(dentry); - while (dentry->d_flags & DCACHE_DISCONNECTED) { - struct dentry *parent = dget_parent(dentry); - - dput(dentry); - if (IS_ROOT(dentry)) { - dput(parent); - return false; - } - dentry = parent; - } - dput(dentry); - return true; -} - -static void clear_disconnected(struct dentry *dentry) -{ - dget(dentry); - while (dentry->d_flags & DCACHE_DISCONNECTED) { - struct dentry *parent = dget_parent(dentry); - - WARN_ON_ONCE(IS_ROOT(dentry)); - - spin_lock(&dentry->d_lock); - dentry->d_flags &= ~DCACHE_DISCONNECTED; - spin_unlock(&dentry->d_lock); - - dput(dentry); - dentry = parent; - } - dput(dentry); -} - -/* - * Reconnect a directory dentry with its parent. - * - * This can return a dentry, or NULL, or an error. - * - * In the first case the returned dentry is the parent of the given - * dentry, and may itself need to be reconnected to its parent. - * - * In the NULL case, a concurrent VFS operation has either renamed or - * removed this directory. The concurrent operation has reconnected our - * dentry, so we no longer need to. - */ -static struct dentry *reconnect_one(struct vfsmount *mnt, - struct dentry *dentry, char *nbuf) -{ - struct dentry *parent; - struct dentry *tmp; - int err; - - parent = ERR_PTR(-EACCES); - inode_lock(dentry->d_inode); - if (mnt->mnt_sb->s_export_op->get_parent) - parent = mnt->mnt_sb->s_export_op->get_parent(dentry); - inode_unlock(dentry->d_inode); - - if (IS_ERR(parent)) { - dprintk("%s: get_parent of %ld failed, err %d\n", - __func__, dentry->d_inode->i_ino, PTR_ERR(parent)); - return parent; - } - - dprintk("%s: find name of %lu in %lu\n", __func__, - dentry->d_inode->i_ino, parent->d_inode->i_ino); - err = exportfs_get_name(mnt, parent, nbuf, dentry); - if (err == -ENOENT) - goto out_reconnected; - if (err) - goto out_err; - dprintk("%s: found name: %s\n", __func__, nbuf); - tmp = lookup_one_len_unlocked(nbuf, parent, strlen(nbuf)); - if (IS_ERR(tmp)) { - dprintk("%s: lookup failed: %d\n", __func__, PTR_ERR(tmp)); - goto out_err; - } - if (tmp != dentry) { - /* - * Somebody has renamed it since exportfs_get_name(); - * great, since it could've only been renamed if it - * got looked up and thus connected, and it would - * remain connected afterwards. We are done. - */ - dput(tmp); - goto out_reconnected; - } - dput(tmp); - if (IS_ROOT(dentry)) { - err = -ESTALE; - goto out_err; - } - return parent; - -out_err: - dput(parent); - return ERR_PTR(err); -out_reconnected: - dput(parent); - /* - * Someone must have renamed our entry into another parent, in - * which case it has been reconnected by the rename. - * - * Or someone removed it entirely, in which case filehandle - * lookup will succeed but the directory is now IS_DEAD and - * subsequent operations on it will fail. - * - * Alternatively, maybe there was no race at all, and the - * filesystem is just corrupt and gave us a parent that doesn't - * actually contain any entry pointing to this inode. So, - * double check that this worked and return -ESTALE if not: - */ - if (!dentry_connected(dentry)) - return ERR_PTR(-ESTALE); - return NULL; -} - -/* - * Make sure target_dir is fully connected to the dentry tree. - * - * On successful return, DCACHE_DISCONNECTED will be cleared on - * target_dir, and target_dir->d_parent->...->d_parent will reach the - * root of the filesystem. - * - * Whenever DCACHE_DISCONNECTED is unset, target_dir is fully connected. - * But the converse is not true: target_dir may have DCACHE_DISCONNECTED - * set but already be connected. In that case we'll verify the - * connection to root and then clear the flag. - * - * Note that target_dir could be removed by a concurrent operation. In - * that case reconnect_path may still succeed with target_dir fully - * connected, but further operations using the filehandle will fail when - * necessary (due to S_DEAD being set on the directory). - */ -static int -reconnect_path(struct vfsmount *mnt, struct dentry *target_dir, char *nbuf) -{ - struct dentry *dentry, *parent; - - dentry = dget(target_dir); - - while (dentry->d_flags & DCACHE_DISCONNECTED) { - BUG_ON(dentry == mnt->mnt_sb->s_root); - - if (IS_ROOT(dentry)) - parent = reconnect_one(mnt, dentry, nbuf); - else - parent = dget_parent(dentry); - - if (!parent) - break; - dput(dentry); - if (IS_ERR(parent)) - return PTR_ERR(parent); - dentry = parent; - } - dput(dentry); - clear_disconnected(target_dir); - return 0; -} - -struct getdents_callback { - struct dir_context ctx; - char *name; /* name that was found. It already points to a - buffer NAME_MAX+1 is size */ - u64 ino; /* the inum we are looking for */ - int found; /* inode matched? */ - int sequence; /* sequence counter */ -}; - -/* - * A rather strange filldir function to capture - * the name matching the specified inode number. - */ -static int filldir_one(struct dir_context *ctx, const char *name, int len, - loff_t pos, u64 ino, unsigned int d_type) -{ - struct getdents_callback *buf = - container_of(ctx, struct getdents_callback, ctx); - int result = 0; - - buf->sequence++; - if (buf->ino == ino && len <= NAME_MAX) { - memcpy(buf->name, name, len); - buf->name[len] = '\0'; - buf->found = 1; - result = -1; - } - return result; -} - -/** - * get_name - default export_operations->get_name function - * @path: the directory in which to find a name - * @name: a pointer to a %NAME_MAX+1 char buffer to store the name - * @child: the dentry for the child directory. - * - * calls readdir on the parent until it finds an entry with - * the same inode number as the child, and returns that. - */ -static int get_name(const struct path *path, char *name, struct dentry *child) -{ - const struct cred *cred = current_cred(); - struct inode *dir = path->dentry->d_inode; - int error; - struct file *file; - struct kstat stat; - struct path child_path = { - .mnt = path->mnt, - .dentry = child, - }; - struct getdents_callback buffer = { - .ctx.actor = filldir_one, - .name = name, - }; - - error = -ENOTDIR; - if (!dir || !S_ISDIR(dir->i_mode)) - goto out; - error = -EINVAL; - if (!dir->i_fop) - goto out; - /* - * inode->i_ino is unsigned long, kstat->ino is u64, so the - * former would be insufficient on 32-bit hosts when the - * filesystem supports 64-bit inode numbers. So we need to - * actually call ->getattr, not just read i_ino: - */ - error = vfs_getattr_nosec(&child_path, &stat); - if (error) - return error; - buffer.ino = stat.ino; - /* - * Open the directory ... - */ - file = dentry_open(path, O_RDONLY, cred); - error = PTR_ERR(file); - if (IS_ERR(file)) - goto out; - - error = -EINVAL; - if (!file->f_op->iterate && !file->f_op->iterate_shared) - goto out_close; - - buffer.sequence = 0; - while (1) { - int old_seq = buffer.sequence; - - error = iterate_dir(file, &buffer.ctx); - if (buffer.found) { - error = 0; - break; - } - - if (error < 0) - break; - - error = -ENOENT; - if (old_seq == buffer.sequence) - break; - } - -out_close: - fput(file); -out: - return error; -} - -/** - * export_encode_fh - default export_operations->encode_fh function - * @inode: the object to encode - * @fid: where to store the file handle fragment - * @max_len: maximum length to store there - * @parent: parent directory inode, if wanted - * - * This default encode_fh function assumes that the 32 inode number - * is suitable for locating an inode, and that the generation number - * can be used to check that it is still valid. It places them in the - * filehandle fragment where export_decode_fh expects to find them. - */ -static int export_encode_fh(struct inode *inode, struct fid *fid, - int *max_len, struct inode *parent) -{ - int len = *max_len; - int type = FILEID_INO32_GEN; - - if (parent && (len < 4)) { - *max_len = 4; - return FILEID_INVALID; - } else if (len < 2) { - *max_len = 2; - return FILEID_INVALID; - } - - len = 2; - fid->i32.ino = inode->i_ino; - fid->i32.gen = inode->i_generation; - if (parent) { - fid->i32.parent_ino = parent->i_ino; - fid->i32.parent_gen = parent->i_generation; - len = 4; - type = FILEID_INO32_GEN_PARENT; - } - *max_len = len; - return type; -} - -int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid, - int *max_len, struct inode *parent) -{ - const struct export_operations *nop = inode->i_sb->s_export_op; - - if (nop && nop->encode_fh) - return nop->encode_fh(inode, fid->raw, max_len, parent); - - return export_encode_fh(inode, fid, max_len, parent); -} -EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh); - -int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len, - int connectable) -{ - int error; - struct dentry *p = NULL; - struct inode *inode = dentry->d_inode, *parent = NULL; - - if (connectable && !S_ISDIR(inode->i_mode)) { - p = dget_parent(dentry); - /* - * note that while p might've ceased to be our parent already, - * it's still pinned by and still positive. - */ - parent = p->d_inode; - } - - error = exportfs_encode_inode_fh(inode, fid, max_len, parent); - dput(p); - - return error; -} -EXPORT_SYMBOL_GPL(exportfs_encode_fh); - -struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid, - int fh_len, int fileid_type, - int (*acceptable)(void *, struct dentry *), void *context) -{ - const struct export_operations *nop = mnt->mnt_sb->s_export_op; - struct dentry *result, *alias; - char nbuf[NAME_MAX+1]; - int err; - - /* - * Try to get any dentry for the given file handle from the filesystem. - */ - if (!nop || !nop->fh_to_dentry) - return ERR_PTR(-ESTALE); - result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type); - if (PTR_ERR(result) == -ENOMEM) - return ERR_CAST(result); - if (IS_ERR_OR_NULL(result)) - return ERR_PTR(-ESTALE); - - if (d_is_dir(result)) { - /* - * This request is for a directory. - * - * On the positive side there is only one dentry for each - * directory inode. On the negative side this implies that we - * to ensure our dentry is connected all the way up to the - * filesystem root. - */ - if (result->d_flags & DCACHE_DISCONNECTED) { - err = reconnect_path(mnt, result, nbuf); - if (err) - goto err_result; - } - - if (!acceptable(context, result)) { - err = -EACCES; - goto err_result; - } - - return result; - } else { - /* - * It's not a directory. Life is a little more complicated. - */ - struct dentry *target_dir, *nresult; - - /* - * See if either the dentry we just got from the filesystem - * or any alias for it is acceptable. This is always true - * if this filesystem is exported without the subtreecheck - * option. If the filesystem is exported with the subtree - * check option there's a fair chance we need to look at - * the parent directory in the file handle and make sure - * it's connected to the filesystem root. - */ - alias = find_acceptable_alias(result, acceptable, context); - if (alias) - return alias; - - /* - * Try to extract a dentry for the parent directory from the - * file handle. If this fails we'll have to give up. - */ - err = -ESTALE; - if (!nop->fh_to_parent) - goto err_result; - - target_dir = nop->fh_to_parent(mnt->mnt_sb, fid, - fh_len, fileid_type); - if (!target_dir) - goto err_result; - err = PTR_ERR(target_dir); - if (IS_ERR(target_dir)) - goto err_result; - - /* - * And as usual we need to make sure the parent directory is - * connected to the filesystem root. The VFS really doesn't - * like disconnected directories.. - */ - err = reconnect_path(mnt, target_dir, nbuf); - if (err) { - dput(target_dir); - goto err_result; - } - - /* - * Now that we've got both a well-connected parent and a - * dentry for the inode we're after, make sure that our - * inode is actually connected to the parent. - */ - err = exportfs_get_name(mnt, target_dir, nbuf, result); - if (!err) { - inode_lock(target_dir->d_inode); - nresult = lookup_one_len(nbuf, target_dir, - strlen(nbuf)); - inode_unlock(target_dir->d_inode); - if (!IS_ERR(nresult)) { - if (nresult->d_inode) { - dput(result); - result = nresult; - } else - dput(nresult); - } - } - - /* - * At this point we are done with the parent, but it's pinned - * by the child dentry anyway. - */ - dput(target_dir); - - /* - * And finally make sure the dentry is actually acceptable - * to NFSD. - */ - alias = find_acceptable_alias(result, acceptable, context); - if (!alias) { - err = -EACCES; - goto err_result; - } - - return alias; - } - - err_result: - dput(result); - if (err != -ENOMEM) - err = -ESTALE; - return ERR_PTR(err); -} -EXPORT_SYMBOL_GPL(exportfs_decode_fh); - -MODULE_LICENSE("GPL"); diff --git a/src/linux/fs/ext2/Kconfig b/src/linux/fs/ext2/Kconfig deleted file mode 100644 index 36bea5a..0000000 --- a/src/linux/fs/ext2/Kconfig +++ /dev/null @@ -1,45 +0,0 @@ -config EXT2_FS - tristate "Second extended fs support" - select FS_IOMAP if FS_DAX - help - Ext2 is a standard Linux file system for hard disks. - - To compile this file system support as a module, choose M here: the - module will be called ext2. - - If unsure, say Y. - -config EXT2_FS_XATTR - bool "Ext2 extended attributes" - depends on EXT2_FS - help - Extended attributes are name:value pairs associated with inodes by - the kernel or by users (see the attr(5) manual page, or visit - for details). - - If unsure, say N. - -config EXT2_FS_POSIX_ACL - bool "Ext2 POSIX Access Control Lists" - depends on EXT2_FS_XATTR - select FS_POSIX_ACL - help - Posix Access Control Lists (ACLs) support permissions for users and - groups beyond the owner/group/world scheme. - - To learn more about Access Control Lists, visit the Posix ACLs for - Linux website . - - If you don't know what Access Control Lists are, say N - -config EXT2_FS_SECURITY - bool "Ext2 Security Labels" - depends on EXT2_FS_XATTR - help - Security labels support alternative access control models - implemented by security modules like SELinux. This option - enables an extended attribute handler for file security - labels in the ext2 filesystem. - - If you are not using a security module that requires using - extended attributes for file security labels, say N. diff --git a/src/linux/fs/ext4/Kconfig b/src/linux/fs/ext4/Kconfig deleted file mode 100644 index e38039f..0000000 --- a/src/linux/fs/ext4/Kconfig +++ /dev/null @@ -1,124 +0,0 @@ -# Ext3 configs are here for backward compatibility with old configs which may -# have EXT3_FS set but not EXT4_FS set and thus would result in non-bootable -# kernels after the removal of ext3 driver. -config EXT3_FS - tristate "The Extended 3 (ext3) filesystem" - # These must match EXT4_FS selects... - select EXT4_FS - select JBD2 - select CRC16 - select CRYPTO - select CRYPTO_CRC32C - help - This config option is here only for backward compatibility. ext3 - filesystem is now handled by the ext4 driver. - -config EXT3_FS_POSIX_ACL - bool "Ext3 POSIX Access Control Lists" - depends on EXT3_FS - select EXT4_FS_POSIX_ACL - select FS_POSIX_ACL - help - This config option is here only for backward compatibility. ext3 - filesystem is now handled by the ext4 driver. - -config EXT3_FS_SECURITY - bool "Ext3 Security Labels" - depends on EXT3_FS - select EXT4_FS_SECURITY - help - This config option is here only for backward compatibility. ext3 - filesystem is now handled by the ext4 driver. - -config EXT4_FS - tristate "The Extended 4 (ext4) filesystem" - # Please update EXT3_FS selects when changing these - select JBD2 - select CRC16 - select CRYPTO - select CRYPTO_CRC32C - help - This is the next generation of the ext3 filesystem. - - Unlike the change from ext2 filesystem to ext3 filesystem, - the on-disk format of ext4 is not forwards compatible with - ext3; it is based on extent maps and it supports 48-bit - physical block numbers. The ext4 filesystem also supports delayed - allocation, persistent preallocation, high resolution time stamps, - and a number of other features to improve performance and speed - up fsck time. For more information, please see the web pages at - http://ext4.wiki.kernel.org. - - The ext4 filesystem supports mounting an ext3 filesystem; while there - are some performance gains from the delayed allocation and inode - table readahead, the best performance gains require enabling ext4 - features in the filesystem using tune2fs, or formatting a new - filesystem as an ext4 filesystem initially. Without explicit enabling - of ext4 features, the on disk filesystem format stays fully backward - compatible. - - To compile this file system support as a module, choose M here. The - module will be called ext4. - - If unsure, say N. - -config EXT4_USE_FOR_EXT2 - bool "Use ext4 for ext2 file systems" - depends on EXT4_FS - depends on EXT2_FS=n - default y - help - Allow the ext4 file system driver code to be used for ext2 - file system mounts. This allows users to reduce their - compiled kernel size by using one file system driver for - ext2, ext3, and ext4 file systems. - -config EXT4_FS_POSIX_ACL - bool "Ext4 POSIX Access Control Lists" - depends on EXT4_FS - select FS_POSIX_ACL - help - POSIX Access Control Lists (ACLs) support permissions for users and - groups beyond the owner/group/world scheme. - - To learn more about Access Control Lists, visit the POSIX ACLs for - Linux website . - - If you don't know what Access Control Lists are, say N - -config EXT4_FS_SECURITY - bool "Ext4 Security Labels" - depends on EXT4_FS - help - Security labels support alternative access control models - implemented by security modules like SELinux. This option - enables an extended attribute handler for file security - labels in the ext4 filesystem. - - If you are not using a security module that requires using - extended attributes for file security labels, say N. - -config EXT4_ENCRYPTION - bool "Ext4 Encryption" - depends on EXT4_FS - select FS_ENCRYPTION - help - Enable encryption of ext4 files and directories. This - feature is similar to ecryptfs, but it is more memory - efficient since it avoids caching the encrypted and - decrypted pages in the page cache. - -config EXT4_FS_ENCRYPTION - bool - default y - depends on EXT4_ENCRYPTION - -config EXT4_DEBUG - bool "EXT4 debugging support" - depends on EXT4_FS - help - Enables run-time debugging support for the ext4 filesystem. - - If you select Y here, then you will be able to turn on debugging - with a command such as: - echo 1 > /sys/module/ext4/parameters/mballoc_debug diff --git a/src/linux/fs/ext4/Makefile b/src/linux/fs/ext4/Makefile deleted file mode 100644 index 354103f..0000000 --- a/src/linux/fs/ext4/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# -# Makefile for the linux ext4-filesystem routines. -# - -obj-$(CONFIG_EXT4_FS) += ext4.o - -ext4-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o page-io.o \ - ioctl.o namei.o super.o symlink.o hash.o resize.o extents.o \ - ext4_jbd2.o migrate.o mballoc.o block_validity.o move_extent.o \ - mmp.o indirect.o extents_status.o xattr.o xattr_user.o \ - xattr_trusted.o inline.o readpage.o sysfs.o - -ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o -ext4-$(CONFIG_EXT4_FS_SECURITY) += xattr_security.o diff --git a/src/linux/fs/ext4/acl.c b/src/linux/fs/ext4/acl.c deleted file mode 100644 index dfa5199..0000000 --- a/src/linux/fs/ext4/acl.c +++ /dev/null @@ -1,276 +0,0 @@ -/* - * linux/fs/ext4/acl.c - * - * Copyright (C) 2001-2003 Andreas Gruenbacher, - */ - -#include "ext4_jbd2.h" -#include "ext4.h" -#include "xattr.h" -#include "acl.h" - -/* - * Convert from filesystem to in-memory representation. - */ -static struct posix_acl * -ext4_acl_from_disk(const void *value, size_t size) -{ - const char *end = (char *)value + size; - int n, count; - struct posix_acl *acl; - - if (!value) - return NULL; - if (size < sizeof(ext4_acl_header)) - return ERR_PTR(-EINVAL); - if (((ext4_acl_header *)value)->a_version != - cpu_to_le32(EXT4_ACL_VERSION)) - return ERR_PTR(-EINVAL); - value = (char *)value + sizeof(ext4_acl_header); - count = ext4_acl_count(size); - if (count < 0) - return ERR_PTR(-EINVAL); - if (count == 0) - return NULL; - acl = posix_acl_alloc(count, GFP_NOFS); - if (!acl) - return ERR_PTR(-ENOMEM); - for (n = 0; n < count; n++) { - ext4_acl_entry *entry = - (ext4_acl_entry *)value; - if ((char *)value + sizeof(ext4_acl_entry_short) > end) - goto fail; - acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag); - acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm); - - switch (acl->a_entries[n].e_tag) { - case ACL_USER_OBJ: - case ACL_GROUP_OBJ: - case ACL_MASK: - case ACL_OTHER: - value = (char *)value + - sizeof(ext4_acl_entry_short); - break; - - case ACL_USER: - value = (char *)value + sizeof(ext4_acl_entry); - if ((char *)value > end) - goto fail; - acl->a_entries[n].e_uid = - make_kuid(&init_user_ns, - le32_to_cpu(entry->e_id)); - break; - case ACL_GROUP: - value = (char *)value + sizeof(ext4_acl_entry); - if ((char *)value > end) - goto fail; - acl->a_entries[n].e_gid = - make_kgid(&init_user_ns, - le32_to_cpu(entry->e_id)); - break; - - default: - goto fail; - } - } - if (value != end) - goto fail; - return acl; - -fail: - posix_acl_release(acl); - return ERR_PTR(-EINVAL); -} - -/* - * Convert from in-memory to filesystem representation. - */ -static void * -ext4_acl_to_disk(const struct posix_acl *acl, size_t *size) -{ - ext4_acl_header *ext_acl; - char *e; - size_t n; - - *size = ext4_acl_size(acl->a_count); - ext_acl = kmalloc(sizeof(ext4_acl_header) + acl->a_count * - sizeof(ext4_acl_entry), GFP_NOFS); - if (!ext_acl) - return ERR_PTR(-ENOMEM); - ext_acl->a_version = cpu_to_le32(EXT4_ACL_VERSION); - e = (char *)ext_acl + sizeof(ext4_acl_header); - for (n = 0; n < acl->a_count; n++) { - const struct posix_acl_entry *acl_e = &acl->a_entries[n]; - ext4_acl_entry *entry = (ext4_acl_entry *)e; - entry->e_tag = cpu_to_le16(acl_e->e_tag); - entry->e_perm = cpu_to_le16(acl_e->e_perm); - switch (acl_e->e_tag) { - case ACL_USER: - entry->e_id = cpu_to_le32( - from_kuid(&init_user_ns, acl_e->e_uid)); - e += sizeof(ext4_acl_entry); - break; - case ACL_GROUP: - entry->e_id = cpu_to_le32( - from_kgid(&init_user_ns, acl_e->e_gid)); - e += sizeof(ext4_acl_entry); - break; - - case ACL_USER_OBJ: - case ACL_GROUP_OBJ: - case ACL_MASK: - case ACL_OTHER: - e += sizeof(ext4_acl_entry_short); - break; - - default: - goto fail; - } - } - return (char *)ext_acl; - -fail: - kfree(ext_acl); - return ERR_PTR(-EINVAL); -} - -/* - * Inode operation get_posix_acl(). - * - * inode->i_mutex: don't care - */ -struct posix_acl * -ext4_get_acl(struct inode *inode, int type) -{ - int name_index; - char *value = NULL; - struct posix_acl *acl; - int retval; - - switch (type) { - case ACL_TYPE_ACCESS: - name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; - break; - case ACL_TYPE_DEFAULT: - name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT; - break; - default: - BUG(); - } - retval = ext4_xattr_get(inode, name_index, "", NULL, 0); - if (retval > 0) { - value = kmalloc(retval, GFP_NOFS); - if (!value) - return ERR_PTR(-ENOMEM); - retval = ext4_xattr_get(inode, name_index, "", value, retval); - } - if (retval > 0) - acl = ext4_acl_from_disk(value, retval); - else if (retval == -ENODATA || retval == -ENOSYS) - acl = NULL; - else - acl = ERR_PTR(retval); - kfree(value); - - return acl; -} - -/* - * Set the access or default ACL of an inode. - * - * inode->i_mutex: down unless called from ext4_new_inode - */ -static int -__ext4_set_acl(handle_t *handle, struct inode *inode, int type, - struct posix_acl *acl) -{ - int name_index; - void *value = NULL; - size_t size = 0; - int error; - - switch (type) { - case ACL_TYPE_ACCESS: - name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS; - if (acl) { - error = posix_acl_update_mode(inode, &inode->i_mode, &acl); - if (error) - return error; - inode->i_ctime = ext4_current_time(inode); - ext4_mark_inode_dirty(handle, inode); - } - break; - - case ACL_TYPE_DEFAULT: - name_index = EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT; - if (!S_ISDIR(inode->i_mode)) - return acl ? -EACCES : 0; - break; - - default: - return -EINVAL; - } - if (acl) { - value = ext4_acl_to_disk(acl, &size); - if (IS_ERR(value)) - return (int)PTR_ERR(value); - } - - error = ext4_xattr_set_handle(handle, inode, name_index, "", - value, size, 0); - - kfree(value); - if (!error) - set_cached_acl(inode, type, acl); - - return error; -} - -int -ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type) -{ - handle_t *handle; - int error, retries = 0; - -retry: - handle = ext4_journal_start(inode, EXT4_HT_XATTR, - ext4_jbd2_credits_xattr(inode)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - - error = __ext4_set_acl(handle, inode, type, acl); - ext4_journal_stop(handle); - if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) - goto retry; - return error; -} - -/* - * Initialize the ACLs of a new inode. Called from ext4_new_inode. - * - * dir->i_mutex: down - * inode->i_mutex: up (access to inode is still exclusive) - */ -int -ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) -{ - struct posix_acl *default_acl, *acl; - int error; - - error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); - if (error) - return error; - - if (default_acl) { - error = __ext4_set_acl(handle, inode, ACL_TYPE_DEFAULT, - default_acl); - posix_acl_release(default_acl); - } - if (acl) { - if (!error) - error = __ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, - acl); - posix_acl_release(acl); - } - return error; -} diff --git a/src/linux/fs/ext4/acl.h b/src/linux/fs/ext4/acl.h deleted file mode 100644 index da2c795..0000000 --- a/src/linux/fs/ext4/acl.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - File: fs/ext4/acl.h - - (C) 2001 Andreas Gruenbacher, -*/ - -#include - -#define EXT4_ACL_VERSION 0x0001 - -typedef struct { - __le16 e_tag; - __le16 e_perm; - __le32 e_id; -} ext4_acl_entry; - -typedef struct { - __le16 e_tag; - __le16 e_perm; -} ext4_acl_entry_short; - -typedef struct { - __le32 a_version; -} ext4_acl_header; - -static inline size_t ext4_acl_size(int count) -{ - if (count <= 4) { - return sizeof(ext4_acl_header) + - count * sizeof(ext4_acl_entry_short); - } else { - return sizeof(ext4_acl_header) + - 4 * sizeof(ext4_acl_entry_short) + - (count - 4) * sizeof(ext4_acl_entry); - } -} - -static inline int ext4_acl_count(size_t size) -{ - ssize_t s; - size -= sizeof(ext4_acl_header); - s = size - 4 * sizeof(ext4_acl_entry_short); - if (s < 0) { - if (size % sizeof(ext4_acl_entry_short)) - return -1; - return size / sizeof(ext4_acl_entry_short); - } else { - if (s % sizeof(ext4_acl_entry)) - return -1; - return s / sizeof(ext4_acl_entry) + 4; - } -} - -#ifdef CONFIG_EXT4_FS_POSIX_ACL - -/* acl.c */ -struct posix_acl *ext4_get_acl(struct inode *inode, int type); -int ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type); -extern int ext4_init_acl(handle_t *, struct inode *, struct inode *); - -#else /* CONFIG_EXT4_FS_POSIX_ACL */ -#include -#define ext4_get_acl NULL -#define ext4_set_acl NULL - -static inline int -ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir) -{ - return 0; -} -#endif /* CONFIG_EXT4_FS_POSIX_ACL */ - diff --git a/src/linux/fs/ext4/balloc.c b/src/linux/fs/ext4/balloc.c deleted file mode 100644 index e04ec86..0000000 --- a/src/linux/fs/ext4/balloc.c +++ /dev/null @@ -1,893 +0,0 @@ -/* - * linux/fs/ext4/balloc.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * Enhanced block allocation by Stephen Tweedie (sct@redhat.com), 1993 - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - */ - -#include -#include -#include -#include -#include -#include "ext4.h" -#include "ext4_jbd2.h" -#include "mballoc.h" - -#include - -static unsigned ext4_num_base_meta_clusters(struct super_block *sb, - ext4_group_t block_group); -/* - * balloc.c contains the blocks allocation and deallocation routines - */ - -/* - * Calculate block group number for a given block number - */ -ext4_group_t ext4_get_group_number(struct super_block *sb, - ext4_fsblk_t block) -{ - ext4_group_t group; - - if (test_opt2(sb, STD_GROUP_SIZE)) - group = (block - - le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) >> - (EXT4_BLOCK_SIZE_BITS(sb) + EXT4_CLUSTER_BITS(sb) + 3); - else - ext4_get_group_no_and_offset(sb, block, &group, NULL); - return group; -} - -/* - * Calculate the block group number and offset into the block/cluster - * allocation bitmap, given a block number - */ -void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr, - ext4_group_t *blockgrpp, ext4_grpblk_t *offsetp) -{ - struct ext4_super_block *es = EXT4_SB(sb)->s_es; - ext4_grpblk_t offset; - - blocknr = blocknr - le32_to_cpu(es->s_first_data_block); - offset = do_div(blocknr, EXT4_BLOCKS_PER_GROUP(sb)) >> - EXT4_SB(sb)->s_cluster_bits; - if (offsetp) - *offsetp = offset; - if (blockgrpp) - *blockgrpp = blocknr; - -} - -/* - * Check whether the 'block' lives within the 'block_group'. Returns 1 if so - * and 0 otherwise. - */ -static inline int ext4_block_in_group(struct super_block *sb, - ext4_fsblk_t block, - ext4_group_t block_group) -{ - ext4_group_t actual_group; - - actual_group = ext4_get_group_number(sb, block); - return (actual_group == block_group) ? 1 : 0; -} - -/* Return the number of clusters used for file system metadata; this - * represents the overhead needed by the file system. - */ -static unsigned ext4_num_overhead_clusters(struct super_block *sb, - ext4_group_t block_group, - struct ext4_group_desc *gdp) -{ - unsigned num_clusters; - int block_cluster = -1, inode_cluster = -1, itbl_cluster = -1, i, c; - ext4_fsblk_t start = ext4_group_first_block_no(sb, block_group); - ext4_fsblk_t itbl_blk; - struct ext4_sb_info *sbi = EXT4_SB(sb); - - /* This is the number of clusters used by the superblock, - * block group descriptors, and reserved block group - * descriptor blocks */ - num_clusters = ext4_num_base_meta_clusters(sb, block_group); - - /* - * For the allocation bitmaps and inode table, we first need - * to check to see if the block is in the block group. If it - * is, then check to see if the cluster is already accounted - * for in the clusters used for the base metadata cluster, or - * if we can increment the base metadata cluster to include - * that block. Otherwise, we will have to track the cluster - * used for the allocation bitmap or inode table explicitly. - * Normally all of these blocks are contiguous, so the special - * case handling shouldn't be necessary except for *very* - * unusual file system layouts. - */ - if (ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp), block_group)) { - block_cluster = EXT4_B2C(sbi, - ext4_block_bitmap(sb, gdp) - start); - if (block_cluster < num_clusters) - block_cluster = -1; - else if (block_cluster == num_clusters) { - num_clusters++; - block_cluster = -1; - } - } - - if (ext4_block_in_group(sb, ext4_inode_bitmap(sb, gdp), block_group)) { - inode_cluster = EXT4_B2C(sbi, - ext4_inode_bitmap(sb, gdp) - start); - if (inode_cluster < num_clusters) - inode_cluster = -1; - else if (inode_cluster == num_clusters) { - num_clusters++; - inode_cluster = -1; - } - } - - itbl_blk = ext4_inode_table(sb, gdp); - for (i = 0; i < sbi->s_itb_per_group; i++) { - if (ext4_block_in_group(sb, itbl_blk + i, block_group)) { - c = EXT4_B2C(sbi, itbl_blk + i - start); - if ((c < num_clusters) || (c == inode_cluster) || - (c == block_cluster) || (c == itbl_cluster)) - continue; - if (c == num_clusters) { - num_clusters++; - continue; - } - num_clusters++; - itbl_cluster = c; - } - } - - if (block_cluster != -1) - num_clusters++; - if (inode_cluster != -1) - num_clusters++; - - return num_clusters; -} - -static unsigned int num_clusters_in_group(struct super_block *sb, - ext4_group_t block_group) -{ - unsigned int blocks; - - if (block_group == ext4_get_groups_count(sb) - 1) { - /* - * Even though mke2fs always initializes the first and - * last group, just in case some other tool was used, - * we need to make sure we calculate the right free - * blocks. - */ - blocks = ext4_blocks_count(EXT4_SB(sb)->s_es) - - ext4_group_first_block_no(sb, block_group); - } else - blocks = EXT4_BLOCKS_PER_GROUP(sb); - return EXT4_NUM_B2C(EXT4_SB(sb), blocks); -} - -/* Initializes an uninitialized block bitmap */ -static int ext4_init_block_bitmap(struct super_block *sb, - struct buffer_head *bh, - ext4_group_t block_group, - struct ext4_group_desc *gdp) -{ - unsigned int bit, bit_max; - struct ext4_sb_info *sbi = EXT4_SB(sb); - ext4_fsblk_t start, tmp; - int flex_bg = 0; - struct ext4_group_info *grp; - - J_ASSERT_BH(bh, buffer_locked(bh)); - - /* If checksum is bad mark all blocks used to prevent allocation - * essentially implementing a per-group read-only flag. */ - if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { - grp = ext4_get_group_info(sb, block_group); - if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) - percpu_counter_sub(&sbi->s_freeclusters_counter, - grp->bb_free); - set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); - if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { - int count; - count = ext4_free_inodes_count(sb, gdp); - percpu_counter_sub(&sbi->s_freeinodes_counter, - count); - } - set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); - return -EFSBADCRC; - } - memset(bh->b_data, 0, sb->s_blocksize); - - bit_max = ext4_num_base_meta_clusters(sb, block_group); - if ((bit_max >> 3) >= bh->b_size) - return -EFSCORRUPTED; - - for (bit = 0; bit < bit_max; bit++) - ext4_set_bit(bit, bh->b_data); - - start = ext4_group_first_block_no(sb, block_group); - - if (ext4_has_feature_flex_bg(sb)) - flex_bg = 1; - - /* Set bits for block and inode bitmaps, and inode table */ - tmp = ext4_block_bitmap(sb, gdp); - if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) - ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data); - - tmp = ext4_inode_bitmap(sb, gdp); - if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) - ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data); - - tmp = ext4_inode_table(sb, gdp); - for (; tmp < ext4_inode_table(sb, gdp) + - sbi->s_itb_per_group; tmp++) { - if (!flex_bg || ext4_block_in_group(sb, tmp, block_group)) - ext4_set_bit(EXT4_B2C(sbi, tmp - start), bh->b_data); - } - - /* - * Also if the number of blocks within the group is less than - * the blocksize * 8 ( which is the size of bitmap ), set rest - * of the block bitmap to 1 - */ - ext4_mark_bitmap_end(num_clusters_in_group(sb, block_group), - sb->s_blocksize * 8, bh->b_data); - ext4_block_bitmap_csum_set(sb, block_group, gdp, bh); - ext4_group_desc_csum_set(sb, block_group, gdp); - return 0; -} - -/* Return the number of free blocks in a block group. It is used when - * the block bitmap is uninitialized, so we can't just count the bits - * in the bitmap. */ -unsigned ext4_free_clusters_after_init(struct super_block *sb, - ext4_group_t block_group, - struct ext4_group_desc *gdp) -{ - return num_clusters_in_group(sb, block_group) - - ext4_num_overhead_clusters(sb, block_group, gdp); -} - -/* - * The free blocks are managed by bitmaps. A file system contains several - * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap - * block for inodes, N blocks for the inode table and data blocks. - * - * The file system contains group descriptors which are located after the - * super block. Each descriptor contains the number of the bitmap block and - * the free blocks count in the block. The descriptors are loaded in memory - * when a file system is mounted (see ext4_fill_super). - */ - -/** - * ext4_get_group_desc() -- load group descriptor from disk - * @sb: super block - * @block_group: given block group - * @bh: pointer to the buffer head to store the block - * group descriptor - */ -struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb, - ext4_group_t block_group, - struct buffer_head **bh) -{ - unsigned int group_desc; - unsigned int offset; - ext4_group_t ngroups = ext4_get_groups_count(sb); - struct ext4_group_desc *desc; - struct ext4_sb_info *sbi = EXT4_SB(sb); - - if (block_group >= ngroups) { - ext4_error(sb, "block_group >= groups_count - block_group = %u," - " groups_count = %u", block_group, ngroups); - - return NULL; - } - - group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb); - offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1); - if (!sbi->s_group_desc[group_desc]) { - ext4_error(sb, "Group descriptor not loaded - " - "block_group = %u, group_desc = %u, desc = %u", - block_group, group_desc, offset); - return NULL; - } - - desc = (struct ext4_group_desc *)( - (__u8 *)sbi->s_group_desc[group_desc]->b_data + - offset * EXT4_DESC_SIZE(sb)); - if (bh) - *bh = sbi->s_group_desc[group_desc]; - return desc; -} - -/* - * Return the block number which was discovered to be invalid, or 0 if - * the block bitmap is valid. - */ -static ext4_fsblk_t ext4_valid_block_bitmap(struct super_block *sb, - struct ext4_group_desc *desc, - ext4_group_t block_group, - struct buffer_head *bh) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - ext4_grpblk_t offset; - ext4_grpblk_t next_zero_bit; - ext4_fsblk_t blk; - ext4_fsblk_t group_first_block; - - if (ext4_has_feature_flex_bg(sb)) { - /* with FLEX_BG, the inode/block bitmaps and itable - * blocks may not be in the group at all - * so the bitmap validation will be skipped for those groups - * or it has to also read the block group where the bitmaps - * are located to verify they are set. - */ - return 0; - } - group_first_block = ext4_group_first_block_no(sb, block_group); - - /* check whether block bitmap block number is set */ - blk = ext4_block_bitmap(sb, desc); - offset = blk - group_first_block; - if (!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data)) - /* bad block bitmap */ - return blk; - - /* check whether the inode bitmap block number is set */ - blk = ext4_inode_bitmap(sb, desc); - offset = blk - group_first_block; - if (!ext4_test_bit(EXT4_B2C(sbi, offset), bh->b_data)) - /* bad block bitmap */ - return blk; - - /* check whether the inode table block number is set */ - blk = ext4_inode_table(sb, desc); - offset = blk - group_first_block; - next_zero_bit = ext4_find_next_zero_bit(bh->b_data, - EXT4_B2C(sbi, offset + EXT4_SB(sb)->s_itb_per_group), - EXT4_B2C(sbi, offset)); - if (next_zero_bit < - EXT4_B2C(sbi, offset + EXT4_SB(sb)->s_itb_per_group)) - /* bad bitmap for inode tables */ - return blk; - return 0; -} - -static int ext4_validate_block_bitmap(struct super_block *sb, - struct ext4_group_desc *desc, - ext4_group_t block_group, - struct buffer_head *bh) -{ - ext4_fsblk_t blk; - struct ext4_group_info *grp = ext4_get_group_info(sb, block_group); - struct ext4_sb_info *sbi = EXT4_SB(sb); - - if (buffer_verified(bh)) - return 0; - if (EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) - return -EFSCORRUPTED; - - ext4_lock_group(sb, block_group); - if (unlikely(!ext4_block_bitmap_csum_verify(sb, block_group, - desc, bh))) { - ext4_unlock_group(sb, block_group); - ext4_error(sb, "bg %u: bad block bitmap checksum", block_group); - if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) - percpu_counter_sub(&sbi->s_freeclusters_counter, - grp->bb_free); - set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); - return -EFSBADCRC; - } - blk = ext4_valid_block_bitmap(sb, desc, block_group, bh); - if (unlikely(blk != 0)) { - ext4_unlock_group(sb, block_group); - ext4_error(sb, "bg %u: block %llu: invalid block bitmap", - block_group, blk); - if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) - percpu_counter_sub(&sbi->s_freeclusters_counter, - grp->bb_free); - set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); - return -EFSCORRUPTED; - } - set_buffer_verified(bh); - ext4_unlock_group(sb, block_group); - return 0; -} - -/** - * ext4_read_block_bitmap_nowait() - * @sb: super block - * @block_group: given block group - * - * Read the bitmap for a given block_group,and validate the - * bits for block/inode/inode tables are set in the bitmaps - * - * Return buffer_head on success or NULL in case of failure. - */ -struct buffer_head * -ext4_read_block_bitmap_nowait(struct super_block *sb, ext4_group_t block_group) -{ - struct ext4_group_desc *desc; - struct buffer_head *bh; - ext4_fsblk_t bitmap_blk; - int err; - - desc = ext4_get_group_desc(sb, block_group, NULL); - if (!desc) - return ERR_PTR(-EFSCORRUPTED); - bitmap_blk = ext4_block_bitmap(sb, desc); - bh = sb_getblk(sb, bitmap_blk); - if (unlikely(!bh)) { - ext4_error(sb, "Cannot get buffer for block bitmap - " - "block_group = %u, block_bitmap = %llu", - block_group, bitmap_blk); - return ERR_PTR(-ENOMEM); - } - - if (bitmap_uptodate(bh)) - goto verify; - - lock_buffer(bh); - if (bitmap_uptodate(bh)) { - unlock_buffer(bh); - goto verify; - } - ext4_lock_group(sb, block_group); - if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { - err = ext4_init_block_bitmap(sb, bh, block_group, desc); - set_bitmap_uptodate(bh); - set_buffer_uptodate(bh); - ext4_unlock_group(sb, block_group); - unlock_buffer(bh); - if (err) { - ext4_error(sb, "Failed to init block bitmap for group " - "%u: %d", block_group, err); - goto out; - } - goto verify; - } - ext4_unlock_group(sb, block_group); - if (buffer_uptodate(bh)) { - /* - * if not uninit if bh is uptodate, - * bitmap is also uptodate - */ - set_bitmap_uptodate(bh); - unlock_buffer(bh); - goto verify; - } - /* - * submit the buffer_head for reading - */ - set_buffer_new(bh); - trace_ext4_read_block_bitmap_load(sb, block_group); - bh->b_end_io = ext4_end_bitmap_read; - get_bh(bh); - submit_bh(REQ_OP_READ, REQ_META | REQ_PRIO, bh); - return bh; -verify: - err = ext4_validate_block_bitmap(sb, desc, block_group, bh); - if (err) - goto out; - return bh; -out: - put_bh(bh); - return ERR_PTR(err); -} - -/* Returns 0 on success, 1 on error */ -int ext4_wait_block_bitmap(struct super_block *sb, ext4_group_t block_group, - struct buffer_head *bh) -{ - struct ext4_group_desc *desc; - - if (!buffer_new(bh)) - return 0; - desc = ext4_get_group_desc(sb, block_group, NULL); - if (!desc) - return -EFSCORRUPTED; - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) { - ext4_error(sb, "Cannot read block bitmap - " - "block_group = %u, block_bitmap = %llu", - block_group, (unsigned long long) bh->b_blocknr); - return -EIO; - } - clear_buffer_new(bh); - /* Panic or remount fs read-only if block bitmap is invalid */ - return ext4_validate_block_bitmap(sb, desc, block_group, bh); -} - -struct buffer_head * -ext4_read_block_bitmap(struct super_block *sb, ext4_group_t block_group) -{ - struct buffer_head *bh; - int err; - - bh = ext4_read_block_bitmap_nowait(sb, block_group); - if (IS_ERR(bh)) - return bh; - err = ext4_wait_block_bitmap(sb, block_group, bh); - if (err) { - put_bh(bh); - return ERR_PTR(err); - } - return bh; -} - -/** - * ext4_has_free_clusters() - * @sbi: in-core super block structure. - * @nclusters: number of needed blocks - * @flags: flags from ext4_mb_new_blocks() - * - * Check if filesystem has nclusters free & available for allocation. - * On success return 1, return 0 on failure. - */ -static int ext4_has_free_clusters(struct ext4_sb_info *sbi, - s64 nclusters, unsigned int flags) -{ - s64 free_clusters, dirty_clusters, rsv, resv_clusters; - struct percpu_counter *fcc = &sbi->s_freeclusters_counter; - struct percpu_counter *dcc = &sbi->s_dirtyclusters_counter; - - free_clusters = percpu_counter_read_positive(fcc); - dirty_clusters = percpu_counter_read_positive(dcc); - resv_clusters = atomic64_read(&sbi->s_resv_clusters); - - /* - * r_blocks_count should always be multiple of the cluster ratio so - * we are safe to do a plane bit shift only. - */ - rsv = (ext4_r_blocks_count(sbi->s_es) >> sbi->s_cluster_bits) + - resv_clusters; - - if (free_clusters - (nclusters + rsv + dirty_clusters) < - EXT4_FREECLUSTERS_WATERMARK) { - free_clusters = percpu_counter_sum_positive(fcc); - dirty_clusters = percpu_counter_sum_positive(dcc); - } - /* Check whether we have space after accounting for current - * dirty clusters & root reserved clusters. - */ - if (free_clusters >= (rsv + nclusters + dirty_clusters)) - return 1; - - /* Hm, nope. Are (enough) root reserved clusters available? */ - if (uid_eq(sbi->s_resuid, current_fsuid()) || - (!gid_eq(sbi->s_resgid, GLOBAL_ROOT_GID) && in_group_p(sbi->s_resgid)) || - capable(CAP_SYS_RESOURCE) || - (flags & EXT4_MB_USE_ROOT_BLOCKS)) { - - if (free_clusters >= (nclusters + dirty_clusters + - resv_clusters)) - return 1; - } - /* No free blocks. Let's see if we can dip into reserved pool */ - if (flags & EXT4_MB_USE_RESERVED) { - if (free_clusters >= (nclusters + dirty_clusters)) - return 1; - } - - return 0; -} - -int ext4_claim_free_clusters(struct ext4_sb_info *sbi, - s64 nclusters, unsigned int flags) -{ - if (ext4_has_free_clusters(sbi, nclusters, flags)) { - percpu_counter_add(&sbi->s_dirtyclusters_counter, nclusters); - return 0; - } else - return -ENOSPC; -} - -/** - * ext4_should_retry_alloc() - * @sb: super block - * @retries number of attemps has been made - * - * ext4_should_retry_alloc() is called when ENOSPC is returned, and if - * it is profitable to retry the operation, this function will wait - * for the current or committing transaction to complete, and then - * return TRUE. - * - * if the total number of retries exceed three times, return FALSE. - */ -int ext4_should_retry_alloc(struct super_block *sb, int *retries) -{ - if (!ext4_has_free_clusters(EXT4_SB(sb), 1, 0) || - (*retries)++ > 3 || - !EXT4_SB(sb)->s_journal) - return 0; - - jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id); - - smp_mb(); - if (EXT4_SB(sb)->s_mb_free_pending) - jbd2_journal_force_commit_nested(EXT4_SB(sb)->s_journal); - return 1; -} - -/* - * ext4_new_meta_blocks() -- allocate block for meta data (indexing) blocks - * - * @handle: handle to this transaction - * @inode: file inode - * @goal: given target block(filesystem wide) - * @count: pointer to total number of clusters needed - * @errp: error code - * - * Return 1st allocated block number on success, *count stores total account - * error stores in errp pointer - */ -ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode, - ext4_fsblk_t goal, unsigned int flags, - unsigned long *count, int *errp) -{ - struct ext4_allocation_request ar; - ext4_fsblk_t ret; - - memset(&ar, 0, sizeof(ar)); - /* Fill with neighbour allocated blocks */ - ar.inode = inode; - ar.goal = goal; - ar.len = count ? *count : 1; - ar.flags = flags; - - ret = ext4_mb_new_blocks(handle, &ar, errp); - if (count) - *count = ar.len; - /* - * Account for the allocated meta blocks. We will never - * fail EDQUOT for metdata, but we do account for it. - */ - if (!(*errp) && (flags & EXT4_MB_DELALLOC_RESERVED)) { - dquot_alloc_block_nofail(inode, - EXT4_C2B(EXT4_SB(inode->i_sb), ar.len)); - } - return ret; -} - -/** - * ext4_count_free_clusters() -- count filesystem free clusters - * @sb: superblock - * - * Adds up the number of free clusters from each block group. - */ -ext4_fsblk_t ext4_count_free_clusters(struct super_block *sb) -{ - ext4_fsblk_t desc_count; - struct ext4_group_desc *gdp; - ext4_group_t i; - ext4_group_t ngroups = ext4_get_groups_count(sb); - struct ext4_group_info *grp; -#ifdef EXT4FS_DEBUG - struct ext4_super_block *es; - ext4_fsblk_t bitmap_count; - unsigned int x; - struct buffer_head *bitmap_bh = NULL; - - es = EXT4_SB(sb)->s_es; - desc_count = 0; - bitmap_count = 0; - gdp = NULL; - - for (i = 0; i < ngroups; i++) { - gdp = ext4_get_group_desc(sb, i, NULL); - if (!gdp) - continue; - grp = NULL; - if (EXT4_SB(sb)->s_group_info) - grp = ext4_get_group_info(sb, i); - if (!grp || !EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) - desc_count += ext4_free_group_clusters(sb, gdp); - brelse(bitmap_bh); - bitmap_bh = ext4_read_block_bitmap(sb, i); - if (IS_ERR(bitmap_bh)) { - bitmap_bh = NULL; - continue; - } - - x = ext4_count_free(bitmap_bh->b_data, - EXT4_CLUSTERS_PER_GROUP(sb) / 8); - printk(KERN_DEBUG "group %u: stored = %d, counted = %u\n", - i, ext4_free_group_clusters(sb, gdp), x); - bitmap_count += x; - } - brelse(bitmap_bh); - printk(KERN_DEBUG "ext4_count_free_clusters: stored = %llu" - ", computed = %llu, %llu\n", - EXT4_NUM_B2C(EXT4_SB(sb), ext4_free_blocks_count(es)), - desc_count, bitmap_count); - return bitmap_count; -#else - desc_count = 0; - for (i = 0; i < ngroups; i++) { - gdp = ext4_get_group_desc(sb, i, NULL); - if (!gdp) - continue; - grp = NULL; - if (EXT4_SB(sb)->s_group_info) - grp = ext4_get_group_info(sb, i); - if (!grp || !EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) - desc_count += ext4_free_group_clusters(sb, gdp); - } - - return desc_count; -#endif -} - -static inline int test_root(ext4_group_t a, int b) -{ - while (1) { - if (a < b) - return 0; - if (a == b) - return 1; - if ((a % b) != 0) - return 0; - a = a / b; - } -} - -/** - * ext4_bg_has_super - number of blocks used by the superblock in group - * @sb: superblock for filesystem - * @group: group number to check - * - * Return the number of blocks used by the superblock (primary or backup) - * in this group. Currently this will be only 0 or 1. - */ -int ext4_bg_has_super(struct super_block *sb, ext4_group_t group) -{ - struct ext4_super_block *es = EXT4_SB(sb)->s_es; - - if (group == 0) - return 1; - if (ext4_has_feature_sparse_super2(sb)) { - if (group == le32_to_cpu(es->s_backup_bgs[0]) || - group == le32_to_cpu(es->s_backup_bgs[1])) - return 1; - return 0; - } - if ((group <= 1) || !ext4_has_feature_sparse_super(sb)) - return 1; - if (!(group & 1)) - return 0; - if (test_root(group, 3) || (test_root(group, 5)) || - test_root(group, 7)) - return 1; - - return 0; -} - -static unsigned long ext4_bg_num_gdb_meta(struct super_block *sb, - ext4_group_t group) -{ - unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb); - ext4_group_t first = metagroup * EXT4_DESC_PER_BLOCK(sb); - ext4_group_t last = first + EXT4_DESC_PER_BLOCK(sb) - 1; - - if (group == first || group == first + 1 || group == last) - return 1; - return 0; -} - -static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb, - ext4_group_t group) -{ - if (!ext4_bg_has_super(sb, group)) - return 0; - - if (ext4_has_feature_meta_bg(sb)) - return le32_to_cpu(EXT4_SB(sb)->s_es->s_first_meta_bg); - else - return EXT4_SB(sb)->s_gdb_count; -} - -/** - * ext4_bg_num_gdb - number of blocks used by the group table in group - * @sb: superblock for filesystem - * @group: group number to check - * - * Return the number of blocks used by the group descriptor table - * (primary or backup) in this group. In the future there may be a - * different number of descriptor blocks in each group. - */ -unsigned long ext4_bg_num_gdb(struct super_block *sb, ext4_group_t group) -{ - unsigned long first_meta_bg = - le32_to_cpu(EXT4_SB(sb)->s_es->s_first_meta_bg); - unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb); - - if (!ext4_has_feature_meta_bg(sb) || metagroup < first_meta_bg) - return ext4_bg_num_gdb_nometa(sb, group); - - return ext4_bg_num_gdb_meta(sb,group); - -} - -/* - * This function returns the number of file system metadata clusters at - * the beginning of a block group, including the reserved gdt blocks. - */ -static unsigned ext4_num_base_meta_clusters(struct super_block *sb, - ext4_group_t block_group) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - unsigned num; - - /* Check for superblock and gdt backups in this group */ - num = ext4_bg_has_super(sb, block_group); - - if (!ext4_has_feature_meta_bg(sb) || - block_group < le32_to_cpu(sbi->s_es->s_first_meta_bg) * - sbi->s_desc_per_block) { - if (num) { - num += ext4_bg_num_gdb(sb, block_group); - num += le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks); - } - } else { /* For META_BG_BLOCK_GROUPS */ - num += ext4_bg_num_gdb(sb, block_group); - } - return EXT4_NUM_B2C(sbi, num); -} -/** - * ext4_inode_to_goal_block - return a hint for block allocation - * @inode: inode for block allocation - * - * Return the ideal location to start allocating blocks for a - * newly created inode. - */ -ext4_fsblk_t ext4_inode_to_goal_block(struct inode *inode) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - ext4_group_t block_group; - ext4_grpblk_t colour; - int flex_size = ext4_flex_bg_size(EXT4_SB(inode->i_sb)); - ext4_fsblk_t bg_start; - ext4_fsblk_t last_block; - - block_group = ei->i_block_group; - if (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) { - /* - * If there are at least EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME - * block groups per flexgroup, reserve the first block - * group for directories and special files. Regular - * files will start at the second block group. This - * tends to speed up directory access and improves - * fsck times. - */ - block_group &= ~(flex_size-1); - if (S_ISREG(inode->i_mode)) - block_group++; - } - bg_start = ext4_group_first_block_no(inode->i_sb, block_group); - last_block = ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es) - 1; - - /* - * If we are doing delayed allocation, we don't need take - * colour into account. - */ - if (test_opt(inode->i_sb, DELALLOC)) - return bg_start; - - if (bg_start + EXT4_BLOCKS_PER_GROUP(inode->i_sb) <= last_block) - colour = (current->pid % 16) * - (EXT4_BLOCKS_PER_GROUP(inode->i_sb) / 16); - else - colour = (current->pid % 16) * ((last_block - bg_start) / 16); - return bg_start + colour; -} - diff --git a/src/linux/fs/ext4/bitmap.c b/src/linux/fs/ext4/bitmap.c deleted file mode 100644 index 4a606af..0000000 --- a/src/linux/fs/ext4/bitmap.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * linux/fs/ext4/bitmap.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - */ - -#include -#include "ext4.h" - -unsigned int ext4_count_free(char *bitmap, unsigned int numchars) -{ - return numchars * BITS_PER_BYTE - memweight(bitmap, numchars); -} - -int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, - struct ext4_group_desc *gdp, - struct buffer_head *bh, int sz) -{ - __u32 hi; - __u32 provided, calculated; - struct ext4_sb_info *sbi = EXT4_SB(sb); - - if (!ext4_has_metadata_csum(sb)) - return 1; - - provided = le16_to_cpu(gdp->bg_inode_bitmap_csum_lo); - calculated = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz); - if (sbi->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END) { - hi = le16_to_cpu(gdp->bg_inode_bitmap_csum_hi); - provided |= (hi << 16); - } else - calculated &= 0xFFFF; - - return provided == calculated; -} - -void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group, - struct ext4_group_desc *gdp, - struct buffer_head *bh, int sz) -{ - __u32 csum; - struct ext4_sb_info *sbi = EXT4_SB(sb); - - if (!ext4_has_metadata_csum(sb)) - return; - - csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz); - gdp->bg_inode_bitmap_csum_lo = cpu_to_le16(csum & 0xFFFF); - if (sbi->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END) - gdp->bg_inode_bitmap_csum_hi = cpu_to_le16(csum >> 16); -} - -int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, - struct ext4_group_desc *gdp, - struct buffer_head *bh) -{ - __u32 hi; - __u32 provided, calculated; - struct ext4_sb_info *sbi = EXT4_SB(sb); - int sz = EXT4_CLUSTERS_PER_GROUP(sb) / 8; - - if (!ext4_has_metadata_csum(sb)) - return 1; - - provided = le16_to_cpu(gdp->bg_block_bitmap_csum_lo); - calculated = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz); - if (sbi->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_END) { - hi = le16_to_cpu(gdp->bg_block_bitmap_csum_hi); - provided |= (hi << 16); - } else - calculated &= 0xFFFF; - - if (provided == calculated) - return 1; - - return 0; -} - -void ext4_block_bitmap_csum_set(struct super_block *sb, ext4_group_t group, - struct ext4_group_desc *gdp, - struct buffer_head *bh) -{ - int sz = EXT4_CLUSTERS_PER_GROUP(sb) / 8; - __u32 csum; - struct ext4_sb_info *sbi = EXT4_SB(sb); - - if (!ext4_has_metadata_csum(sb)) - return; - - csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz); - gdp->bg_block_bitmap_csum_lo = cpu_to_le16(csum & 0xFFFF); - if (sbi->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_END) - gdp->bg_block_bitmap_csum_hi = cpu_to_le16(csum >> 16); -} diff --git a/src/linux/fs/ext4/block_validity.c b/src/linux/fs/ext4/block_validity.c deleted file mode 100644 index fdb1954..0000000 --- a/src/linux/fs/ext4/block_validity.c +++ /dev/null @@ -1,242 +0,0 @@ -/* - * linux/fs/ext4/block_validity.c - * - * Copyright (C) 2009 - * Theodore Ts'o (tytso@mit.edu) - * - * Track which blocks in the filesystem are metadata blocks that - * should never be used as data blocks by files or directories. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ext4.h" - -struct ext4_system_zone { - struct rb_node node; - ext4_fsblk_t start_blk; - unsigned int count; -}; - -static struct kmem_cache *ext4_system_zone_cachep; - -int __init ext4_init_system_zone(void) -{ - ext4_system_zone_cachep = KMEM_CACHE(ext4_system_zone, 0); - if (ext4_system_zone_cachep == NULL) - return -ENOMEM; - return 0; -} - -void ext4_exit_system_zone(void) -{ - kmem_cache_destroy(ext4_system_zone_cachep); -} - -static inline int can_merge(struct ext4_system_zone *entry1, - struct ext4_system_zone *entry2) -{ - if ((entry1->start_blk + entry1->count) == entry2->start_blk) - return 1; - return 0; -} - -/* - * Mark a range of blocks as belonging to the "system zone" --- that - * is, filesystem metadata blocks which should never be used by - * inodes. - */ -static int add_system_zone(struct ext4_sb_info *sbi, - ext4_fsblk_t start_blk, - unsigned int count) -{ - struct ext4_system_zone *new_entry = NULL, *entry; - struct rb_node **n = &sbi->system_blks.rb_node, *node; - struct rb_node *parent = NULL, *new_node = NULL; - - while (*n) { - parent = *n; - entry = rb_entry(parent, struct ext4_system_zone, node); - if (start_blk < entry->start_blk) - n = &(*n)->rb_left; - else if (start_blk >= (entry->start_blk + entry->count)) - n = &(*n)->rb_right; - else { - if (start_blk + count > (entry->start_blk + - entry->count)) - entry->count = (start_blk + count - - entry->start_blk); - new_node = *n; - new_entry = rb_entry(new_node, struct ext4_system_zone, - node); - break; - } - } - - if (!new_entry) { - new_entry = kmem_cache_alloc(ext4_system_zone_cachep, - GFP_KERNEL); - if (!new_entry) - return -ENOMEM; - new_entry->start_blk = start_blk; - new_entry->count = count; - new_node = &new_entry->node; - - rb_link_node(new_node, parent, n); - rb_insert_color(new_node, &sbi->system_blks); - } - - /* Can we merge to the left? */ - node = rb_prev(new_node); - if (node) { - entry = rb_entry(node, struct ext4_system_zone, node); - if (can_merge(entry, new_entry)) { - new_entry->start_blk = entry->start_blk; - new_entry->count += entry->count; - rb_erase(node, &sbi->system_blks); - kmem_cache_free(ext4_system_zone_cachep, entry); - } - } - - /* Can we merge to the right? */ - node = rb_next(new_node); - if (node) { - entry = rb_entry(node, struct ext4_system_zone, node); - if (can_merge(new_entry, entry)) { - new_entry->count += entry->count; - rb_erase(node, &sbi->system_blks); - kmem_cache_free(ext4_system_zone_cachep, entry); - } - } - return 0; -} - -static void debug_print_tree(struct ext4_sb_info *sbi) -{ - struct rb_node *node; - struct ext4_system_zone *entry; - int first = 1; - - printk(KERN_INFO "System zones: "); - node = rb_first(&sbi->system_blks); - while (node) { - entry = rb_entry(node, struct ext4_system_zone, node); - printk(KERN_CONT "%s%llu-%llu", first ? "" : ", ", - entry->start_blk, entry->start_blk + entry->count - 1); - first = 0; - node = rb_next(node); - } - printk(KERN_CONT "\n"); -} - -int ext4_setup_system_zone(struct super_block *sb) -{ - ext4_group_t ngroups = ext4_get_groups_count(sb); - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_group_desc *gdp; - ext4_group_t i; - int flex_size = ext4_flex_bg_size(sbi); - int ret; - - if (!test_opt(sb, BLOCK_VALIDITY)) { - if (EXT4_SB(sb)->system_blks.rb_node) - ext4_release_system_zone(sb); - return 0; - } - if (EXT4_SB(sb)->system_blks.rb_node) - return 0; - - for (i=0; i < ngroups; i++) { - if (ext4_bg_has_super(sb, i) && - ((i < 5) || ((i % flex_size) == 0))) - add_system_zone(sbi, ext4_group_first_block_no(sb, i), - ext4_bg_num_gdb(sb, i) + 1); - gdp = ext4_get_group_desc(sb, i, NULL); - ret = add_system_zone(sbi, ext4_block_bitmap(sb, gdp), 1); - if (ret) - return ret; - ret = add_system_zone(sbi, ext4_inode_bitmap(sb, gdp), 1); - if (ret) - return ret; - ret = add_system_zone(sbi, ext4_inode_table(sb, gdp), - sbi->s_itb_per_group); - if (ret) - return ret; - } - - if (test_opt(sb, DEBUG)) - debug_print_tree(EXT4_SB(sb)); - return 0; -} - -/* Called when the filesystem is unmounted */ -void ext4_release_system_zone(struct super_block *sb) -{ - struct ext4_system_zone *entry, *n; - - rbtree_postorder_for_each_entry_safe(entry, n, - &EXT4_SB(sb)->system_blks, node) - kmem_cache_free(ext4_system_zone_cachep, entry); - - EXT4_SB(sb)->system_blks = RB_ROOT; -} - -/* - * Returns 1 if the passed-in block region (start_blk, - * start_blk+count) is valid; 0 if some part of the block region - * overlaps with filesystem metadata blocks. - */ -int ext4_data_block_valid(struct ext4_sb_info *sbi, ext4_fsblk_t start_blk, - unsigned int count) -{ - struct ext4_system_zone *entry; - struct rb_node *n = sbi->system_blks.rb_node; - - if ((start_blk <= le32_to_cpu(sbi->s_es->s_first_data_block)) || - (start_blk + count < start_blk) || - (start_blk + count > ext4_blocks_count(sbi->s_es))) { - sbi->s_es->s_last_error_block = cpu_to_le64(start_blk); - return 0; - } - while (n) { - entry = rb_entry(n, struct ext4_system_zone, node); - if (start_blk + count - 1 < entry->start_blk) - n = n->rb_left; - else if (start_blk >= (entry->start_blk + entry->count)) - n = n->rb_right; - else { - sbi->s_es->s_last_error_block = cpu_to_le64(start_blk); - return 0; - } - } - return 1; -} - -int ext4_check_blockref(const char *function, unsigned int line, - struct inode *inode, __le32 *p, unsigned int max) -{ - struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es; - __le32 *bref = p; - unsigned int blk; - - while (bref < p+max) { - blk = le32_to_cpu(*bref++); - if (blk && - unlikely(!ext4_data_block_valid(EXT4_SB(inode->i_sb), - blk, 1))) { - es->s_last_error_block = cpu_to_le64(blk); - ext4_error_inode(inode, function, line, blk, - "invalid block"); - return -EFSCORRUPTED; - } - } - return 0; -} - diff --git a/src/linux/fs/ext4/dir.c b/src/linux/fs/ext4/dir.c deleted file mode 100644 index e8b3650..0000000 --- a/src/linux/fs/ext4/dir.c +++ /dev/null @@ -1,662 +0,0 @@ -/* - * linux/fs/ext4/dir.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/dir.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * ext4 directory handling functions - * - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - * - * Hash Tree Directory indexing (c) 2001 Daniel Phillips - * - */ - -#include -#include -#include -#include "ext4.h" -#include "xattr.h" - -static int ext4_dx_readdir(struct file *, struct dir_context *); - -/** - * Check if the given dir-inode refers to an htree-indexed directory - * (or a directory which could potentially get converted to use htree - * indexing). - * - * Return 1 if it is a dx dir, 0 if not - */ -static int is_dx_dir(struct inode *inode) -{ - struct super_block *sb = inode->i_sb; - - if (ext4_has_feature_dir_index(inode->i_sb) && - ((ext4_test_inode_flag(inode, EXT4_INODE_INDEX)) || - ((inode->i_size >> sb->s_blocksize_bits) == 1) || - ext4_has_inline_data(inode))) - return 1; - - return 0; -} - -/* - * Return 0 if the directory entry is OK, and 1 if there is a problem - * - * Note: this is the opposite of what ext2 and ext3 historically returned... - * - * bh passed here can be an inode block or a dir data block, depending - * on the inode inline data flag. - */ -int __ext4_check_dir_entry(const char *function, unsigned int line, - struct inode *dir, struct file *filp, - struct ext4_dir_entry_2 *de, - struct buffer_head *bh, char *buf, int size, - unsigned int offset) -{ - const char *error_msg = NULL; - const int rlen = ext4_rec_len_from_disk(de->rec_len, - dir->i_sb->s_blocksize); - - if (unlikely(rlen < EXT4_DIR_REC_LEN(1))) - error_msg = "rec_len is smaller than minimal"; - else if (unlikely(rlen % 4 != 0)) - error_msg = "rec_len % 4 != 0"; - else if (unlikely(rlen < EXT4_DIR_REC_LEN(de->name_len))) - error_msg = "rec_len is too small for name_len"; - else if (unlikely(((char *) de - buf) + rlen > size)) - error_msg = "directory entry across range"; - else if (unlikely(le32_to_cpu(de->inode) > - le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count))) - error_msg = "inode out of bounds"; - else - return 0; - - if (filp) - ext4_error_file(filp, function, line, bh->b_blocknr, - "bad entry in directory: %s - offset=%u(%u), " - "inode=%u, rec_len=%d, name_len=%d", - error_msg, (unsigned) (offset % size), - offset, le32_to_cpu(de->inode), - rlen, de->name_len); - else - ext4_error_inode(dir, function, line, bh->b_blocknr, - "bad entry in directory: %s - offset=%u(%u), " - "inode=%u, rec_len=%d, name_len=%d", - error_msg, (unsigned) (offset % size), - offset, le32_to_cpu(de->inode), - rlen, de->name_len); - - return 1; -} - -static int ext4_readdir(struct file *file, struct dir_context *ctx) -{ - unsigned int offset; - int i; - struct ext4_dir_entry_2 *de; - int err; - struct inode *inode = file_inode(file); - struct super_block *sb = inode->i_sb; - struct buffer_head *bh = NULL; - int dir_has_error = 0; - struct fscrypt_str fstr = FSTR_INIT(NULL, 0); - - if (ext4_encrypted_inode(inode)) { - err = fscrypt_get_encryption_info(inode); - if (err && err != -ENOKEY) - return err; - } - - if (is_dx_dir(inode)) { - err = ext4_dx_readdir(file, ctx); - if (err != ERR_BAD_DX_DIR) { - return err; - } - /* - * We don't set the inode dirty flag since it's not - * critical that it get flushed back to the disk. - */ - ext4_clear_inode_flag(file_inode(file), - EXT4_INODE_INDEX); - } - - if (ext4_has_inline_data(inode)) { - int has_inline_data = 1; - err = ext4_read_inline_dir(file, ctx, - &has_inline_data); - if (has_inline_data) - return err; - } - - if (ext4_encrypted_inode(inode)) { - err = fscrypt_fname_alloc_buffer(inode, EXT4_NAME_LEN, &fstr); - if (err < 0) - return err; - } - - offset = ctx->pos & (sb->s_blocksize - 1); - - while (ctx->pos < inode->i_size) { - struct ext4_map_blocks map; - - if (fatal_signal_pending(current)) { - err = -ERESTARTSYS; - goto errout; - } - cond_resched(); - map.m_lblk = ctx->pos >> EXT4_BLOCK_SIZE_BITS(sb); - map.m_len = 1; - err = ext4_map_blocks(NULL, inode, &map, 0); - if (err > 0) { - pgoff_t index = map.m_pblk >> - (PAGE_SHIFT - inode->i_blkbits); - if (!ra_has_index(&file->f_ra, index)) - page_cache_sync_readahead( - sb->s_bdev->bd_inode->i_mapping, - &file->f_ra, file, - index, 1); - file->f_ra.prev_pos = (loff_t)index << PAGE_SHIFT; - bh = ext4_bread(NULL, inode, map.m_lblk, 0); - if (IS_ERR(bh)) { - err = PTR_ERR(bh); - bh = NULL; - goto errout; - } - } - - if (!bh) { - if (!dir_has_error) { - EXT4_ERROR_FILE(file, 0, - "directory contains a " - "hole at offset %llu", - (unsigned long long) ctx->pos); - dir_has_error = 1; - } - /* corrupt size? Maybe no more blocks to read */ - if (ctx->pos > inode->i_blocks << 9) - break; - ctx->pos += sb->s_blocksize - offset; - continue; - } - - /* Check the checksum */ - if (!buffer_verified(bh) && - !ext4_dirent_csum_verify(inode, - (struct ext4_dir_entry *)bh->b_data)) { - EXT4_ERROR_FILE(file, 0, "directory fails checksum " - "at offset %llu", - (unsigned long long)ctx->pos); - ctx->pos += sb->s_blocksize - offset; - brelse(bh); - bh = NULL; - continue; - } - set_buffer_verified(bh); - - /* If the dir block has changed since the last call to - * readdir(2), then we might be pointing to an invalid - * dirent right now. Scan from the start of the block - * to make sure. */ - if (file->f_version != inode->i_version) { - for (i = 0; i < sb->s_blocksize && i < offset; ) { - de = (struct ext4_dir_entry_2 *) - (bh->b_data + i); - /* It's too expensive to do a full - * dirent test each time round this - * loop, but we do have to test at - * least that it is non-zero. A - * failure will be detected in the - * dirent test below. */ - if (ext4_rec_len_from_disk(de->rec_len, - sb->s_blocksize) < EXT4_DIR_REC_LEN(1)) - break; - i += ext4_rec_len_from_disk(de->rec_len, - sb->s_blocksize); - } - offset = i; - ctx->pos = (ctx->pos & ~(sb->s_blocksize - 1)) - | offset; - file->f_version = inode->i_version; - } - - while (ctx->pos < inode->i_size - && offset < sb->s_blocksize) { - de = (struct ext4_dir_entry_2 *) (bh->b_data + offset); - if (ext4_check_dir_entry(inode, file, de, bh, - bh->b_data, bh->b_size, - offset)) { - /* - * On error, skip to the next block - */ - ctx->pos = (ctx->pos | - (sb->s_blocksize - 1)) + 1; - break; - } - offset += ext4_rec_len_from_disk(de->rec_len, - sb->s_blocksize); - if (le32_to_cpu(de->inode)) { - if (!ext4_encrypted_inode(inode)) { - if (!dir_emit(ctx, de->name, - de->name_len, - le32_to_cpu(de->inode), - get_dtype(sb, de->file_type))) - goto done; - } else { - int save_len = fstr.len; - struct fscrypt_str de_name = - FSTR_INIT(de->name, - de->name_len); - - /* Directory is encrypted */ - err = fscrypt_fname_disk_to_usr(inode, - 0, 0, &de_name, &fstr); - de_name = fstr; - fstr.len = save_len; - if (err) - goto errout; - if (!dir_emit(ctx, - de_name.name, de_name.len, - le32_to_cpu(de->inode), - get_dtype(sb, de->file_type))) - goto done; - } - } - ctx->pos += ext4_rec_len_from_disk(de->rec_len, - sb->s_blocksize); - } - if ((ctx->pos < inode->i_size) && !dir_relax_shared(inode)) - goto done; - brelse(bh); - bh = NULL; - offset = 0; - } -done: - err = 0; -errout: -#ifdef CONFIG_EXT4_FS_ENCRYPTION - fscrypt_fname_free_buffer(&fstr); -#endif - brelse(bh); - return err; -} - -static inline int is_32bit_api(void) -{ -#ifdef CONFIG_COMPAT - return in_compat_syscall(); -#else - return (BITS_PER_LONG == 32); -#endif -} - -/* - * These functions convert from the major/minor hash to an f_pos - * value for dx directories - * - * Upper layer (for example NFS) should specify FMODE_32BITHASH or - * FMODE_64BITHASH explicitly. On the other hand, we allow ext4 to be mounted - * directly on both 32-bit and 64-bit nodes, under such case, neither - * FMODE_32BITHASH nor FMODE_64BITHASH is specified. - */ -static inline loff_t hash2pos(struct file *filp, __u32 major, __u32 minor) -{ - if ((filp->f_mode & FMODE_32BITHASH) || - (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api())) - return major >> 1; - else - return ((__u64)(major >> 1) << 32) | (__u64)minor; -} - -static inline __u32 pos2maj_hash(struct file *filp, loff_t pos) -{ - if ((filp->f_mode & FMODE_32BITHASH) || - (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api())) - return (pos << 1) & 0xffffffff; - else - return ((pos >> 32) << 1) & 0xffffffff; -} - -static inline __u32 pos2min_hash(struct file *filp, loff_t pos) -{ - if ((filp->f_mode & FMODE_32BITHASH) || - (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api())) - return 0; - else - return pos & 0xffffffff; -} - -/* - * Return 32- or 64-bit end-of-file for dx directories - */ -static inline loff_t ext4_get_htree_eof(struct file *filp) -{ - if ((filp->f_mode & FMODE_32BITHASH) || - (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api())) - return EXT4_HTREE_EOF_32BIT; - else - return EXT4_HTREE_EOF_64BIT; -} - - -/* - * ext4_dir_llseek() calls generic_file_llseek_size to handle htree - * directories, where the "offset" is in terms of the filename hash - * value instead of the byte offset. - * - * Because we may return a 64-bit hash that is well beyond offset limits, - * we need to pass the max hash as the maximum allowable offset in - * the htree directory case. - * - * For non-htree, ext4_llseek already chooses the proper max offset. - */ -static loff_t ext4_dir_llseek(struct file *file, loff_t offset, int whence) -{ - struct inode *inode = file->f_mapping->host; - int dx_dir = is_dx_dir(inode); - loff_t htree_max = ext4_get_htree_eof(file); - - if (likely(dx_dir)) - return generic_file_llseek_size(file, offset, whence, - htree_max, htree_max); - else - return ext4_llseek(file, offset, whence); -} - -/* - * This structure holds the nodes of the red-black tree used to store - * the directory entry in hash order. - */ -struct fname { - __u32 hash; - __u32 minor_hash; - struct rb_node rb_hash; - struct fname *next; - __u32 inode; - __u8 name_len; - __u8 file_type; - char name[0]; -}; - -/* - * This functoin implements a non-recursive way of freeing all of the - * nodes in the red-black tree. - */ -static void free_rb_tree_fname(struct rb_root *root) -{ - struct fname *fname, *next; - - rbtree_postorder_for_each_entry_safe(fname, next, root, rb_hash) - while (fname) { - struct fname *old = fname; - fname = fname->next; - kfree(old); - } - - *root = RB_ROOT; -} - - -static struct dir_private_info *ext4_htree_create_dir_info(struct file *filp, - loff_t pos) -{ - struct dir_private_info *p; - - p = kzalloc(sizeof(struct dir_private_info), GFP_KERNEL); - if (!p) - return NULL; - p->curr_hash = pos2maj_hash(filp, pos); - p->curr_minor_hash = pos2min_hash(filp, pos); - return p; -} - -void ext4_htree_free_dir_info(struct dir_private_info *p) -{ - free_rb_tree_fname(&p->root); - kfree(p); -} - -/* - * Given a directory entry, enter it into the fname rb tree. - * - * When filename encryption is enabled, the dirent will hold the - * encrypted filename, while the htree will hold decrypted filename. - * The decrypted filename is passed in via ent_name. parameter. - */ -int ext4_htree_store_dirent(struct file *dir_file, __u32 hash, - __u32 minor_hash, - struct ext4_dir_entry_2 *dirent, - struct fscrypt_str *ent_name) -{ - struct rb_node **p, *parent = NULL; - struct fname *fname, *new_fn; - struct dir_private_info *info; - int len; - - info = dir_file->private_data; - p = &info->root.rb_node; - - /* Create and allocate the fname structure */ - len = sizeof(struct fname) + ent_name->len + 1; - new_fn = kzalloc(len, GFP_KERNEL); - if (!new_fn) - return -ENOMEM; - new_fn->hash = hash; - new_fn->minor_hash = minor_hash; - new_fn->inode = le32_to_cpu(dirent->inode); - new_fn->name_len = ent_name->len; - new_fn->file_type = dirent->file_type; - memcpy(new_fn->name, ent_name->name, ent_name->len); - new_fn->name[ent_name->len] = 0; - - while (*p) { - parent = *p; - fname = rb_entry(parent, struct fname, rb_hash); - - /* - * If the hash and minor hash match up, then we put - * them on a linked list. This rarely happens... - */ - if ((new_fn->hash == fname->hash) && - (new_fn->minor_hash == fname->minor_hash)) { - new_fn->next = fname->next; - fname->next = new_fn; - return 0; - } - - if (new_fn->hash < fname->hash) - p = &(*p)->rb_left; - else if (new_fn->hash > fname->hash) - p = &(*p)->rb_right; - else if (new_fn->minor_hash < fname->minor_hash) - p = &(*p)->rb_left; - else /* if (new_fn->minor_hash > fname->minor_hash) */ - p = &(*p)->rb_right; - } - - rb_link_node(&new_fn->rb_hash, parent, p); - rb_insert_color(&new_fn->rb_hash, &info->root); - return 0; -} - - - -/* - * This is a helper function for ext4_dx_readdir. It calls filldir - * for all entres on the fname linked list. (Normally there is only - * one entry on the linked list, unless there are 62 bit hash collisions.) - */ -static int call_filldir(struct file *file, struct dir_context *ctx, - struct fname *fname) -{ - struct dir_private_info *info = file->private_data; - struct inode *inode = file_inode(file); - struct super_block *sb = inode->i_sb; - - if (!fname) { - ext4_msg(sb, KERN_ERR, "%s:%d: inode #%lu: comm %s: " - "called with null fname?!?", __func__, __LINE__, - inode->i_ino, current->comm); - return 0; - } - ctx->pos = hash2pos(file, fname->hash, fname->minor_hash); - while (fname) { - if (!dir_emit(ctx, fname->name, - fname->name_len, - fname->inode, - get_dtype(sb, fname->file_type))) { - info->extra_fname = fname; - return 1; - } - fname = fname->next; - } - return 0; -} - -static int ext4_dx_readdir(struct file *file, struct dir_context *ctx) -{ - struct dir_private_info *info = file->private_data; - struct inode *inode = file_inode(file); - struct fname *fname; - int ret; - - if (!info) { - info = ext4_htree_create_dir_info(file, ctx->pos); - if (!info) - return -ENOMEM; - file->private_data = info; - } - - if (ctx->pos == ext4_get_htree_eof(file)) - return 0; /* EOF */ - - /* Some one has messed with f_pos; reset the world */ - if (info->last_pos != ctx->pos) { - free_rb_tree_fname(&info->root); - info->curr_node = NULL; - info->extra_fname = NULL; - info->curr_hash = pos2maj_hash(file, ctx->pos); - info->curr_minor_hash = pos2min_hash(file, ctx->pos); - } - - /* - * If there are any leftover names on the hash collision - * chain, return them first. - */ - if (info->extra_fname) { - if (call_filldir(file, ctx, info->extra_fname)) - goto finished; - info->extra_fname = NULL; - goto next_node; - } else if (!info->curr_node) - info->curr_node = rb_first(&info->root); - - while (1) { - /* - * Fill the rbtree if we have no more entries, - * or the inode has changed since we last read in the - * cached entries. - */ - if ((!info->curr_node) || - (file->f_version != inode->i_version)) { - info->curr_node = NULL; - free_rb_tree_fname(&info->root); - file->f_version = inode->i_version; - ret = ext4_htree_fill_tree(file, info->curr_hash, - info->curr_minor_hash, - &info->next_hash); - if (ret < 0) - return ret; - if (ret == 0) { - ctx->pos = ext4_get_htree_eof(file); - break; - } - info->curr_node = rb_first(&info->root); - } - - fname = rb_entry(info->curr_node, struct fname, rb_hash); - info->curr_hash = fname->hash; - info->curr_minor_hash = fname->minor_hash; - if (call_filldir(file, ctx, fname)) - break; - next_node: - info->curr_node = rb_next(info->curr_node); - if (info->curr_node) { - fname = rb_entry(info->curr_node, struct fname, - rb_hash); - info->curr_hash = fname->hash; - info->curr_minor_hash = fname->minor_hash; - } else { - if (info->next_hash == ~0) { - ctx->pos = ext4_get_htree_eof(file); - break; - } - info->curr_hash = info->next_hash; - info->curr_minor_hash = 0; - } - } -finished: - info->last_pos = ctx->pos; - return 0; -} - -static int ext4_dir_open(struct inode * inode, struct file * filp) -{ - if (ext4_encrypted_inode(inode)) - return fscrypt_get_encryption_info(inode) ? -EACCES : 0; - return 0; -} - -static int ext4_release_dir(struct inode *inode, struct file *filp) -{ - if (filp->private_data) - ext4_htree_free_dir_info(filp->private_data); - - return 0; -} - -int ext4_check_all_de(struct inode *dir, struct buffer_head *bh, void *buf, - int buf_size) -{ - struct ext4_dir_entry_2 *de; - int rlen; - unsigned int offset = 0; - char *top; - - de = (struct ext4_dir_entry_2 *)buf; - top = buf + buf_size; - while ((char *) de < top) { - if (ext4_check_dir_entry(dir, NULL, de, bh, - buf, buf_size, offset)) - return -EFSCORRUPTED; - rlen = ext4_rec_len_from_disk(de->rec_len, buf_size); - de = (struct ext4_dir_entry_2 *)((char *)de + rlen); - offset += rlen; - } - if ((char *) de > top) - return -EFSCORRUPTED; - - return 0; -} - -const struct file_operations ext4_dir_operations = { - .llseek = ext4_dir_llseek, - .read = generic_read_dir, - .iterate_shared = ext4_readdir, - .unlocked_ioctl = ext4_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ext4_compat_ioctl, -#endif - .fsync = ext4_sync_file, - .open = ext4_dir_open, - .release = ext4_release_dir, -}; diff --git a/src/linux/fs/ext4/ext4.h b/src/linux/fs/ext4/ext4.h deleted file mode 100644 index a8a750f..0000000 --- a/src/linux/fs/ext4/ext4.h +++ /dev/null @@ -1,3280 +0,0 @@ -/* - * ext4.h - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/include/linux/minix_fs.h - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#ifndef _EXT4_H -#define _EXT4_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef __KERNEL__ -#include -#endif - -/* - * The fourth extended filesystem constants/structures - */ - -/* - * with AGGRESSIVE_CHECK allocator runs consistency checks over - * structures. these checks slow things down a lot - */ -#define AGGRESSIVE_CHECK__ - -/* - * with DOUBLE_CHECK defined mballoc creates persistent in-core - * bitmaps, maintains and uses them to check for double allocations - */ -#define DOUBLE_CHECK__ - -/* - * Define EXT4FS_DEBUG to produce debug messages - */ -#undef EXT4FS_DEBUG - -/* - * Debug code - */ -#ifdef EXT4FS_DEBUG -#define ext4_debug(f, a...) \ - do { \ - printk(KERN_DEBUG "EXT4-fs DEBUG (%s, %d): %s:", \ - __FILE__, __LINE__, __func__); \ - printk(KERN_DEBUG f, ## a); \ - } while (0) -#else -#define ext4_debug(fmt, ...) no_printk(fmt, ##__VA_ARGS__) -#endif - -/* - * Turn on EXT_DEBUG to get lots of info about extents operations. - */ -#define EXT_DEBUG__ -#ifdef EXT_DEBUG -#define ext_debug(fmt, ...) printk(fmt, ##__VA_ARGS__) -#else -#define ext_debug(fmt, ...) no_printk(fmt, ##__VA_ARGS__) -#endif - -/* data type for block offset of block group */ -typedef int ext4_grpblk_t; - -/* data type for filesystem-wide blocks number */ -typedef unsigned long long ext4_fsblk_t; - -/* data type for file logical block number */ -typedef __u32 ext4_lblk_t; - -/* data type for block group number */ -typedef unsigned int ext4_group_t; - -enum SHIFT_DIRECTION { - SHIFT_LEFT = 0, - SHIFT_RIGHT, -}; - -/* - * Flags used in mballoc's allocation_context flags field. - * - * Also used to show what's going on for debugging purposes when the - * flag field is exported via the traceport interface - */ - -/* prefer goal again. length */ -#define EXT4_MB_HINT_MERGE 0x0001 -/* blocks already reserved */ -#define EXT4_MB_HINT_RESERVED 0x0002 -/* metadata is being allocated */ -#define EXT4_MB_HINT_METADATA 0x0004 -/* first blocks in the file */ -#define EXT4_MB_HINT_FIRST 0x0008 -/* search for the best chunk */ -#define EXT4_MB_HINT_BEST 0x0010 -/* data is being allocated */ -#define EXT4_MB_HINT_DATA 0x0020 -/* don't preallocate (for tails) */ -#define EXT4_MB_HINT_NOPREALLOC 0x0040 -/* allocate for locality group */ -#define EXT4_MB_HINT_GROUP_ALLOC 0x0080 -/* allocate goal blocks or none */ -#define EXT4_MB_HINT_GOAL_ONLY 0x0100 -/* goal is meaningful */ -#define EXT4_MB_HINT_TRY_GOAL 0x0200 -/* blocks already pre-reserved by delayed allocation */ -#define EXT4_MB_DELALLOC_RESERVED 0x0400 -/* We are doing stream allocation */ -#define EXT4_MB_STREAM_ALLOC 0x0800 -/* Use reserved root blocks if needed */ -#define EXT4_MB_USE_ROOT_BLOCKS 0x1000 -/* Use blocks from reserved pool */ -#define EXT4_MB_USE_RESERVED 0x2000 - -struct ext4_allocation_request { - /* target inode for block we're allocating */ - struct inode *inode; - /* how many blocks we want to allocate */ - unsigned int len; - /* logical block in target inode */ - ext4_lblk_t logical; - /* the closest logical allocated block to the left */ - ext4_lblk_t lleft; - /* the closest logical allocated block to the right */ - ext4_lblk_t lright; - /* phys. target (a hint) */ - ext4_fsblk_t goal; - /* phys. block for the closest logical allocated block to the left */ - ext4_fsblk_t pleft; - /* phys. block for the closest logical allocated block to the right */ - ext4_fsblk_t pright; - /* flags. see above EXT4_MB_HINT_* */ - unsigned int flags; -}; - -/* - * Logical to physical block mapping, used by ext4_map_blocks() - * - * This structure is used to pass requests into ext4_map_blocks() as - * well as to store the information returned by ext4_map_blocks(). It - * takes less room on the stack than a struct buffer_head. - */ -#define EXT4_MAP_NEW (1 << BH_New) -#define EXT4_MAP_MAPPED (1 << BH_Mapped) -#define EXT4_MAP_UNWRITTEN (1 << BH_Unwritten) -#define EXT4_MAP_BOUNDARY (1 << BH_Boundary) -#define EXT4_MAP_FLAGS (EXT4_MAP_NEW | EXT4_MAP_MAPPED |\ - EXT4_MAP_UNWRITTEN | EXT4_MAP_BOUNDARY) - -struct ext4_map_blocks { - ext4_fsblk_t m_pblk; - ext4_lblk_t m_lblk; - unsigned int m_len; - unsigned int m_flags; -}; - -/* - * Flags for ext4_io_end->flags - */ -#define EXT4_IO_END_UNWRITTEN 0x0001 - -/* - * For converting unwritten extents on a work queue. 'handle' is used for - * buffered writeback. - */ -typedef struct ext4_io_end { - struct list_head list; /* per-file finished IO list */ - handle_t *handle; /* handle reserved for extent - * conversion */ - struct inode *inode; /* file being written to */ - struct bio *bio; /* Linked list of completed - * bios covering the extent */ - unsigned int flag; /* unwritten or not */ - atomic_t count; /* reference counter */ - loff_t offset; /* offset in the file */ - ssize_t size; /* size of the extent */ -} ext4_io_end_t; - -struct ext4_io_submit { - struct writeback_control *io_wbc; - struct bio *io_bio; - ext4_io_end_t *io_end; - sector_t io_next_block; -}; - -/* - * Special inodes numbers - */ -#define EXT4_BAD_INO 1 /* Bad blocks inode */ -#define EXT4_ROOT_INO 2 /* Root inode */ -#define EXT4_USR_QUOTA_INO 3 /* User quota inode */ -#define EXT4_GRP_QUOTA_INO 4 /* Group quota inode */ -#define EXT4_BOOT_LOADER_INO 5 /* Boot loader inode */ -#define EXT4_UNDEL_DIR_INO 6 /* Undelete directory inode */ -#define EXT4_RESIZE_INO 7 /* Reserved group descriptors inode */ -#define EXT4_JOURNAL_INO 8 /* Journal inode */ - -/* First non-reserved inode for old ext4 filesystems */ -#define EXT4_GOOD_OLD_FIRST_INO 11 - -/* - * Maximal count of links to a file - */ -#define EXT4_LINK_MAX 65000 - -/* - * Macro-instructions used to manage several block sizes - */ -#define EXT4_MIN_BLOCK_SIZE 1024 -#define EXT4_MAX_BLOCK_SIZE 65536 -#define EXT4_MIN_BLOCK_LOG_SIZE 10 -#define EXT4_MAX_BLOCK_LOG_SIZE 16 -#define EXT4_MAX_CLUSTER_LOG_SIZE 30 -#ifdef __KERNEL__ -# define EXT4_BLOCK_SIZE(s) ((s)->s_blocksize) -#else -# define EXT4_BLOCK_SIZE(s) (EXT4_MIN_BLOCK_SIZE << (s)->s_log_block_size) -#endif -#define EXT4_ADDR_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / sizeof(__u32)) -#define EXT4_CLUSTER_SIZE(s) (EXT4_BLOCK_SIZE(s) << \ - EXT4_SB(s)->s_cluster_bits) -#ifdef __KERNEL__ -# define EXT4_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) -# define EXT4_CLUSTER_BITS(s) (EXT4_SB(s)->s_cluster_bits) -#else -# define EXT4_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) -#endif -#ifdef __KERNEL__ -#define EXT4_ADDR_PER_BLOCK_BITS(s) (EXT4_SB(s)->s_addr_per_block_bits) -#define EXT4_INODE_SIZE(s) (EXT4_SB(s)->s_inode_size) -#define EXT4_FIRST_INO(s) (EXT4_SB(s)->s_first_ino) -#else -#define EXT4_INODE_SIZE(s) (((s)->s_rev_level == EXT4_GOOD_OLD_REV) ? \ - EXT4_GOOD_OLD_INODE_SIZE : \ - (s)->s_inode_size) -#define EXT4_FIRST_INO(s) (((s)->s_rev_level == EXT4_GOOD_OLD_REV) ? \ - EXT4_GOOD_OLD_FIRST_INO : \ - (s)->s_first_ino) -#endif -#define EXT4_BLOCK_ALIGN(size, blkbits) ALIGN((size), (1 << (blkbits))) -#define EXT4_MAX_BLOCKS(size, offset, blkbits) \ - ((EXT4_BLOCK_ALIGN(size + offset, blkbits) >> blkbits) - (offset >> \ - blkbits)) - -/* Translate a block number to a cluster number */ -#define EXT4_B2C(sbi, blk) ((blk) >> (sbi)->s_cluster_bits) -/* Translate a cluster number to a block number */ -#define EXT4_C2B(sbi, cluster) ((cluster) << (sbi)->s_cluster_bits) -/* Translate # of blks to # of clusters */ -#define EXT4_NUM_B2C(sbi, blks) (((blks) + (sbi)->s_cluster_ratio - 1) >> \ - (sbi)->s_cluster_bits) -/* Mask out the low bits to get the starting block of the cluster */ -#define EXT4_PBLK_CMASK(s, pblk) ((pblk) & \ - ~((ext4_fsblk_t) (s)->s_cluster_ratio - 1)) -#define EXT4_LBLK_CMASK(s, lblk) ((lblk) & \ - ~((ext4_lblk_t) (s)->s_cluster_ratio - 1)) -/* Get the cluster offset */ -#define EXT4_PBLK_COFF(s, pblk) ((pblk) & \ - ((ext4_fsblk_t) (s)->s_cluster_ratio - 1)) -#define EXT4_LBLK_COFF(s, lblk) ((lblk) & \ - ((ext4_lblk_t) (s)->s_cluster_ratio - 1)) - -/* - * Structure of a blocks group descriptor - */ -struct ext4_group_desc -{ - __le32 bg_block_bitmap_lo; /* Blocks bitmap block */ - __le32 bg_inode_bitmap_lo; /* Inodes bitmap block */ - __le32 bg_inode_table_lo; /* Inodes table block */ - __le16 bg_free_blocks_count_lo;/* Free blocks count */ - __le16 bg_free_inodes_count_lo;/* Free inodes count */ - __le16 bg_used_dirs_count_lo; /* Directories count */ - __le16 bg_flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */ - __le32 bg_exclude_bitmap_lo; /* Exclude bitmap for snapshots */ - __le16 bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bbitmap) LE */ - __le16 bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+ibitmap) LE */ - __le16 bg_itable_unused_lo; /* Unused inodes count */ - __le16 bg_checksum; /* crc16(sb_uuid+group+desc) */ - __le32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */ - __le32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */ - __le32 bg_inode_table_hi; /* Inodes table block MSB */ - __le16 bg_free_blocks_count_hi;/* Free blocks count MSB */ - __le16 bg_free_inodes_count_hi;/* Free inodes count MSB */ - __le16 bg_used_dirs_count_hi; /* Directories count MSB */ - __le16 bg_itable_unused_hi; /* Unused inodes count MSB */ - __le32 bg_exclude_bitmap_hi; /* Exclude bitmap block MSB */ - __le16 bg_block_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+bbitmap) BE */ - __le16 bg_inode_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+ibitmap) BE */ - __u32 bg_reserved; -}; - -#define EXT4_BG_INODE_BITMAP_CSUM_HI_END \ - (offsetof(struct ext4_group_desc, bg_inode_bitmap_csum_hi) + \ - sizeof(__le16)) -#define EXT4_BG_BLOCK_BITMAP_CSUM_HI_END \ - (offsetof(struct ext4_group_desc, bg_block_bitmap_csum_hi) + \ - sizeof(__le16)) - -/* - * Structure of a flex block group info - */ - -struct flex_groups { - atomic64_t free_clusters; - atomic_t free_inodes; - atomic_t used_dirs; -}; - -#define EXT4_BG_INODE_UNINIT 0x0001 /* Inode table/bitmap not in use */ -#define EXT4_BG_BLOCK_UNINIT 0x0002 /* Block bitmap not in use */ -#define EXT4_BG_INODE_ZEROED 0x0004 /* On-disk itable initialized to zero */ - -/* - * Macro-instructions used to manage group descriptors - */ -#define EXT4_MIN_DESC_SIZE 32 -#define EXT4_MIN_DESC_SIZE_64BIT 64 -#define EXT4_MAX_DESC_SIZE EXT4_MIN_BLOCK_SIZE -#define EXT4_DESC_SIZE(s) (EXT4_SB(s)->s_desc_size) -#ifdef __KERNEL__ -# define EXT4_BLOCKS_PER_GROUP(s) (EXT4_SB(s)->s_blocks_per_group) -# define EXT4_CLUSTERS_PER_GROUP(s) (EXT4_SB(s)->s_clusters_per_group) -# define EXT4_DESC_PER_BLOCK(s) (EXT4_SB(s)->s_desc_per_block) -# define EXT4_INODES_PER_GROUP(s) (EXT4_SB(s)->s_inodes_per_group) -# define EXT4_DESC_PER_BLOCK_BITS(s) (EXT4_SB(s)->s_desc_per_block_bits) -#else -# define EXT4_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) -# define EXT4_DESC_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / EXT4_DESC_SIZE(s)) -# define EXT4_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) -#endif - -/* - * Constants relative to the data blocks - */ -#define EXT4_NDIR_BLOCKS 12 -#define EXT4_IND_BLOCK EXT4_NDIR_BLOCKS -#define EXT4_DIND_BLOCK (EXT4_IND_BLOCK + 1) -#define EXT4_TIND_BLOCK (EXT4_DIND_BLOCK + 1) -#define EXT4_N_BLOCKS (EXT4_TIND_BLOCK + 1) - -/* - * Inode flags - */ -#define EXT4_SECRM_FL 0x00000001 /* Secure deletion */ -#define EXT4_UNRM_FL 0x00000002 /* Undelete */ -#define EXT4_COMPR_FL 0x00000004 /* Compress file */ -#define EXT4_SYNC_FL 0x00000008 /* Synchronous updates */ -#define EXT4_IMMUTABLE_FL 0x00000010 /* Immutable file */ -#define EXT4_APPEND_FL 0x00000020 /* writes to file may only append */ -#define EXT4_NODUMP_FL 0x00000040 /* do not dump file */ -#define EXT4_NOATIME_FL 0x00000080 /* do not update atime */ -/* Reserved for compression usage... */ -#define EXT4_DIRTY_FL 0x00000100 -#define EXT4_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */ -#define EXT4_NOCOMPR_FL 0x00000400 /* Don't compress */ - /* nb: was previously EXT2_ECOMPR_FL */ -#define EXT4_ENCRYPT_FL 0x00000800 /* encrypted file */ -/* End compression flags --- maybe not all used */ -#define EXT4_INDEX_FL 0x00001000 /* hash-indexed directory */ -#define EXT4_IMAGIC_FL 0x00002000 /* AFS directory */ -#define EXT4_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */ -#define EXT4_NOTAIL_FL 0x00008000 /* file tail should not be merged */ -#define EXT4_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ -#define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ -#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */ -#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ -#define EXT4_EA_INODE_FL 0x00200000 /* Inode used for large EA */ -#define EXT4_EOFBLOCKS_FL 0x00400000 /* Blocks allocated beyond EOF */ -#define EXT4_INLINE_DATA_FL 0x10000000 /* Inode has inline data. */ -#define EXT4_PROJINHERIT_FL 0x20000000 /* Create with parents projid */ -#define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ - -#define EXT4_FL_USER_VISIBLE 0x304BDFFF /* User visible flags */ -#define EXT4_FL_USER_MODIFIABLE 0x204380FF /* User modifiable flags */ - -#define EXT4_FL_XFLAG_VISIBLE (EXT4_SYNC_FL | \ - EXT4_IMMUTABLE_FL | \ - EXT4_APPEND_FL | \ - EXT4_NODUMP_FL | \ - EXT4_NOATIME_FL | \ - EXT4_PROJINHERIT_FL) - -/* Flags that should be inherited by new inodes from their parent. */ -#define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\ - EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\ - EXT4_NOCOMPR_FL | EXT4_JOURNAL_DATA_FL |\ - EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL |\ - EXT4_PROJINHERIT_FL) - -/* Flags that are appropriate for regular files (all but dir-specific ones). */ -#define EXT4_REG_FLMASK (~(EXT4_DIRSYNC_FL | EXT4_TOPDIR_FL)) - -/* Flags that are appropriate for non-directories/regular files. */ -#define EXT4_OTHER_FLMASK (EXT4_NODUMP_FL | EXT4_NOATIME_FL) - -/* Mask out flags that are inappropriate for the given type of inode. */ -static inline __u32 ext4_mask_flags(umode_t mode, __u32 flags) -{ - if (S_ISDIR(mode)) - return flags; - else if (S_ISREG(mode)) - return flags & EXT4_REG_FLMASK; - else - return flags & EXT4_OTHER_FLMASK; -} - -/* - * Inode flags used for atomic set/get - */ -enum { - EXT4_INODE_SECRM = 0, /* Secure deletion */ - EXT4_INODE_UNRM = 1, /* Undelete */ - EXT4_INODE_COMPR = 2, /* Compress file */ - EXT4_INODE_SYNC = 3, /* Synchronous updates */ - EXT4_INODE_IMMUTABLE = 4, /* Immutable file */ - EXT4_INODE_APPEND = 5, /* writes to file may only append */ - EXT4_INODE_NODUMP = 6, /* do not dump file */ - EXT4_INODE_NOATIME = 7, /* do not update atime */ -/* Reserved for compression usage... */ - EXT4_INODE_DIRTY = 8, - EXT4_INODE_COMPRBLK = 9, /* One or more compressed clusters */ - EXT4_INODE_NOCOMPR = 10, /* Don't compress */ - EXT4_INODE_ENCRYPT = 11, /* Encrypted file */ -/* End compression flags --- maybe not all used */ - EXT4_INODE_INDEX = 12, /* hash-indexed directory */ - EXT4_INODE_IMAGIC = 13, /* AFS directory */ - EXT4_INODE_JOURNAL_DATA = 14, /* file data should be journaled */ - EXT4_INODE_NOTAIL = 15, /* file tail should not be merged */ - EXT4_INODE_DIRSYNC = 16, /* dirsync behaviour (directories only) */ - EXT4_INODE_TOPDIR = 17, /* Top of directory hierarchies*/ - EXT4_INODE_HUGE_FILE = 18, /* Set to each huge file */ - EXT4_INODE_EXTENTS = 19, /* Inode uses extents */ - EXT4_INODE_EA_INODE = 21, /* Inode used for large EA */ - EXT4_INODE_EOFBLOCKS = 22, /* Blocks allocated beyond EOF */ - EXT4_INODE_INLINE_DATA = 28, /* Data in inode. */ - EXT4_INODE_PROJINHERIT = 29, /* Create with parents projid */ - EXT4_INODE_RESERVED = 31, /* reserved for ext4 lib */ -}; - -/* - * Since it's pretty easy to mix up bit numbers and hex values, we use a - * build-time check to make sure that EXT4_XXX_FL is consistent with respect to - * EXT4_INODE_XXX. If all is well, the macros will be dropped, so, it won't cost - * any extra space in the compiled kernel image, otherwise, the build will fail. - * It's important that these values are the same, since we are using - * EXT4_INODE_XXX to test for flag values, but EXT4_XXX_FL must be consistent - * with the values of FS_XXX_FL defined in include/linux/fs.h and the on-disk - * values found in ext2, ext3 and ext4 filesystems, and of course the values - * defined in e2fsprogs. - * - * It's not paranoia if the Murphy's Law really *is* out to get you. :-) - */ -#define TEST_FLAG_VALUE(FLAG) (EXT4_##FLAG##_FL == (1 << EXT4_INODE_##FLAG)) -#define CHECK_FLAG_VALUE(FLAG) BUILD_BUG_ON(!TEST_FLAG_VALUE(FLAG)) - -static inline void ext4_check_flag_values(void) -{ - CHECK_FLAG_VALUE(SECRM); - CHECK_FLAG_VALUE(UNRM); - CHECK_FLAG_VALUE(COMPR); - CHECK_FLAG_VALUE(SYNC); - CHECK_FLAG_VALUE(IMMUTABLE); - CHECK_FLAG_VALUE(APPEND); - CHECK_FLAG_VALUE(NODUMP); - CHECK_FLAG_VALUE(NOATIME); - CHECK_FLAG_VALUE(DIRTY); - CHECK_FLAG_VALUE(COMPRBLK); - CHECK_FLAG_VALUE(NOCOMPR); - CHECK_FLAG_VALUE(ENCRYPT); - CHECK_FLAG_VALUE(INDEX); - CHECK_FLAG_VALUE(IMAGIC); - CHECK_FLAG_VALUE(JOURNAL_DATA); - CHECK_FLAG_VALUE(NOTAIL); - CHECK_FLAG_VALUE(DIRSYNC); - CHECK_FLAG_VALUE(TOPDIR); - CHECK_FLAG_VALUE(HUGE_FILE); - CHECK_FLAG_VALUE(EXTENTS); - CHECK_FLAG_VALUE(EA_INODE); - CHECK_FLAG_VALUE(EOFBLOCKS); - CHECK_FLAG_VALUE(INLINE_DATA); - CHECK_FLAG_VALUE(PROJINHERIT); - CHECK_FLAG_VALUE(RESERVED); -} - -/* Used to pass group descriptor data when online resize is done */ -struct ext4_new_group_input { - __u32 group; /* Group number for this data */ - __u64 block_bitmap; /* Absolute block number of block bitmap */ - __u64 inode_bitmap; /* Absolute block number of inode bitmap */ - __u64 inode_table; /* Absolute block number of inode table start */ - __u32 blocks_count; /* Total number of blocks in this group */ - __u16 reserved_blocks; /* Number of reserved blocks in this group */ - __u16 unused; -}; - -#if defined(__KERNEL__) && defined(CONFIG_COMPAT) -struct compat_ext4_new_group_input { - u32 group; - compat_u64 block_bitmap; - compat_u64 inode_bitmap; - compat_u64 inode_table; - u32 blocks_count; - u16 reserved_blocks; - u16 unused; -}; -#endif - -/* The struct ext4_new_group_input in kernel space, with free_blocks_count */ -struct ext4_new_group_data { - __u32 group; - __u64 block_bitmap; - __u64 inode_bitmap; - __u64 inode_table; - __u32 blocks_count; - __u16 reserved_blocks; - __u16 unused; - __u32 free_blocks_count; -}; - -/* Indexes used to index group tables in ext4_new_group_data */ -enum { - BLOCK_BITMAP = 0, /* block bitmap */ - INODE_BITMAP, /* inode bitmap */ - INODE_TABLE, /* inode tables */ - GROUP_TABLE_COUNT, -}; - -/* - * Flags used by ext4_map_blocks() - */ - /* Allocate any needed blocks and/or convert an unwritten - extent to be an initialized ext4 */ -#define EXT4_GET_BLOCKS_CREATE 0x0001 - /* Request the creation of an unwritten extent */ -#define EXT4_GET_BLOCKS_UNWRIT_EXT 0x0002 -#define EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT (EXT4_GET_BLOCKS_UNWRIT_EXT|\ - EXT4_GET_BLOCKS_CREATE) - /* Caller is from the delayed allocation writeout path - * finally doing the actual allocation of delayed blocks */ -#define EXT4_GET_BLOCKS_DELALLOC_RESERVE 0x0004 - /* caller is from the direct IO path, request to creation of an - unwritten extents if not allocated, split the unwritten - extent if blocks has been preallocated already*/ -#define EXT4_GET_BLOCKS_PRE_IO 0x0008 -#define EXT4_GET_BLOCKS_CONVERT 0x0010 -#define EXT4_GET_BLOCKS_IO_CREATE_EXT (EXT4_GET_BLOCKS_PRE_IO|\ - EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT) - /* Convert extent to initialized after IO complete */ -#define EXT4_GET_BLOCKS_IO_CONVERT_EXT (EXT4_GET_BLOCKS_CONVERT|\ - EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT) - /* Eventual metadata allocation (due to growing extent tree) - * should not fail, so try to use reserved blocks for that.*/ -#define EXT4_GET_BLOCKS_METADATA_NOFAIL 0x0020 - /* Don't normalize allocation size (used for fallocate) */ -#define EXT4_GET_BLOCKS_NO_NORMALIZE 0x0040 - /* Request will not result in inode size update (user for fallocate) */ -#define EXT4_GET_BLOCKS_KEEP_SIZE 0x0080 - /* Convert written extents to unwritten */ -#define EXT4_GET_BLOCKS_CONVERT_UNWRITTEN 0x0100 - /* Write zeros to newly created written extents */ -#define EXT4_GET_BLOCKS_ZERO 0x0200 -#define EXT4_GET_BLOCKS_CREATE_ZERO (EXT4_GET_BLOCKS_CREATE |\ - EXT4_GET_BLOCKS_ZERO) - /* Caller will submit data before dropping transaction handle. This - * allows jbd2 to avoid submitting data before commit. */ -#define EXT4_GET_BLOCKS_IO_SUBMIT 0x0400 - -/* - * The bit position of these flags must not overlap with any of the - * EXT4_GET_BLOCKS_*. They are used by ext4_find_extent(), - * read_extent_tree_block(), ext4_split_extent_at(), - * ext4_ext_insert_extent(), and ext4_ext_create_new_leaf(). - * EXT4_EX_NOCACHE is used to indicate that the we shouldn't be - * caching the extents when reading from the extent tree while a - * truncate or punch hole operation is in progress. - */ -#define EXT4_EX_NOCACHE 0x40000000 -#define EXT4_EX_FORCE_CACHE 0x20000000 - -/* - * Flags used by ext4_free_blocks - */ -#define EXT4_FREE_BLOCKS_METADATA 0x0001 -#define EXT4_FREE_BLOCKS_FORGET 0x0002 -#define EXT4_FREE_BLOCKS_VALIDATED 0x0004 -#define EXT4_FREE_BLOCKS_NO_QUOT_UPDATE 0x0008 -#define EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER 0x0010 -#define EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER 0x0020 - -/* - * ioctl commands - */ -#define EXT4_IOC_GETFLAGS FS_IOC_GETFLAGS -#define EXT4_IOC_SETFLAGS FS_IOC_SETFLAGS -#define EXT4_IOC_GETVERSION _IOR('f', 3, long) -#define EXT4_IOC_SETVERSION _IOW('f', 4, long) -#define EXT4_IOC_GETVERSION_OLD FS_IOC_GETVERSION -#define EXT4_IOC_SETVERSION_OLD FS_IOC_SETVERSION -#define EXT4_IOC_GETRSVSZ _IOR('f', 5, long) -#define EXT4_IOC_SETRSVSZ _IOW('f', 6, long) -#define EXT4_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long) -#define EXT4_IOC_GROUP_ADD _IOW('f', 8, struct ext4_new_group_input) -#define EXT4_IOC_MIGRATE _IO('f', 9) - /* note ioctl 10 reserved for an early version of the FIEMAP ioctl */ - /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */ -#define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12) -#define EXT4_IOC_MOVE_EXT _IOWR('f', 15, struct move_extent) -#define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64) -#define EXT4_IOC_SWAP_BOOT _IO('f', 17) -#define EXT4_IOC_PRECACHE_EXTENTS _IO('f', 18) -#define EXT4_IOC_SET_ENCRYPTION_POLICY FS_IOC_SET_ENCRYPTION_POLICY -#define EXT4_IOC_GET_ENCRYPTION_PWSALT FS_IOC_GET_ENCRYPTION_PWSALT -#define EXT4_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY - -#ifndef FS_IOC_FSGETXATTR -/* Until the uapi changes get merged for project quota... */ - -#define FS_IOC_FSGETXATTR _IOR('X', 31, struct fsxattr) -#define FS_IOC_FSSETXATTR _IOW('X', 32, struct fsxattr) - -/* - * Structure for FS_IOC_FSGETXATTR and FS_IOC_FSSETXATTR. - */ -struct fsxattr { - __u32 fsx_xflags; /* xflags field value (get/set) */ - __u32 fsx_extsize; /* extsize field value (get/set)*/ - __u32 fsx_nextents; /* nextents field value (get) */ - __u32 fsx_projid; /* project identifier (get/set) */ - unsigned char fsx_pad[12]; -}; - -/* - * Flags for the fsx_xflags field - */ -#define FS_XFLAG_REALTIME 0x00000001 /* data in realtime volume */ -#define FS_XFLAG_PREALLOC 0x00000002 /* preallocated file extents */ -#define FS_XFLAG_IMMUTABLE 0x00000008 /* file cannot be modified */ -#define FS_XFLAG_APPEND 0x00000010 /* all writes append */ -#define FS_XFLAG_SYNC 0x00000020 /* all writes synchronous */ -#define FS_XFLAG_NOATIME 0x00000040 /* do not update access time */ -#define FS_XFLAG_NODUMP 0x00000080 /* do not include in backups */ -#define FS_XFLAG_RTINHERIT 0x00000100 /* create with rt bit set */ -#define FS_XFLAG_PROJINHERIT 0x00000200 /* create with parents projid */ -#define FS_XFLAG_NOSYMLINKS 0x00000400 /* disallow symlink creation */ -#define FS_XFLAG_EXTSIZE 0x00000800 /* extent size allocator hint */ -#define FS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */ -#define FS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */ -#define FS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */ -#define FS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ -#endif /* !defined(FS_IOC_FSGETXATTR) */ - -#define EXT4_IOC_FSGETXATTR FS_IOC_FSGETXATTR -#define EXT4_IOC_FSSETXATTR FS_IOC_FSSETXATTR - -#if defined(__KERNEL__) && defined(CONFIG_COMPAT) -/* - * ioctl commands in 32 bit emulation - */ -#define EXT4_IOC32_GETFLAGS FS_IOC32_GETFLAGS -#define EXT4_IOC32_SETFLAGS FS_IOC32_SETFLAGS -#define EXT4_IOC32_GETVERSION _IOR('f', 3, int) -#define EXT4_IOC32_SETVERSION _IOW('f', 4, int) -#define EXT4_IOC32_GETRSVSZ _IOR('f', 5, int) -#define EXT4_IOC32_SETRSVSZ _IOW('f', 6, int) -#define EXT4_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int) -#define EXT4_IOC32_GROUP_ADD _IOW('f', 8, struct compat_ext4_new_group_input) -#define EXT4_IOC32_GETVERSION_OLD FS_IOC32_GETVERSION -#define EXT4_IOC32_SETVERSION_OLD FS_IOC32_SETVERSION -#endif - -/* Max physical block we can address w/o extents */ -#define EXT4_MAX_BLOCK_FILE_PHYS 0xFFFFFFFF - -/* - * Structure of an inode on the disk - */ -struct ext4_inode { - __le16 i_mode; /* File mode */ - __le16 i_uid; /* Low 16 bits of Owner Uid */ - __le32 i_size_lo; /* Size in bytes */ - __le32 i_atime; /* Access time */ - __le32 i_ctime; /* Inode Change time */ - __le32 i_mtime; /* Modification time */ - __le32 i_dtime; /* Deletion Time */ - __le16 i_gid; /* Low 16 bits of Group Id */ - __le16 i_links_count; /* Links count */ - __le32 i_blocks_lo; /* Blocks count */ - __le32 i_flags; /* File flags */ - union { - struct { - __le32 l_i_version; - } linux1; - struct { - __u32 h_i_translator; - } hurd1; - struct { - __u32 m_i_reserved1; - } masix1; - } osd1; /* OS dependent 1 */ - __le32 i_block[EXT4_N_BLOCKS];/* Pointers to blocks */ - __le32 i_generation; /* File version (for NFS) */ - __le32 i_file_acl_lo; /* File ACL */ - __le32 i_size_high; - __le32 i_obso_faddr; /* Obsoleted fragment address */ - union { - struct { - __le16 l_i_blocks_high; /* were l_i_reserved1 */ - __le16 l_i_file_acl_high; - __le16 l_i_uid_high; /* these 2 fields */ - __le16 l_i_gid_high; /* were reserved2[0] */ - __le16 l_i_checksum_lo;/* crc32c(uuid+inum+inode) LE */ - __le16 l_i_reserved; - } linux2; - struct { - __le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ - __u16 h_i_mode_high; - __u16 h_i_uid_high; - __u16 h_i_gid_high; - __u32 h_i_author; - } hurd2; - struct { - __le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */ - __le16 m_i_file_acl_high; - __u32 m_i_reserved2[2]; - } masix2; - } osd2; /* OS dependent 2 */ - __le16 i_extra_isize; - __le16 i_checksum_hi; /* crc32c(uuid+inum+inode) BE */ - __le32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */ - __le32 i_mtime_extra; /* extra Modification time(nsec << 2 | epoch) */ - __le32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */ - __le32 i_crtime; /* File Creation time */ - __le32 i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */ - __le32 i_version_hi; /* high 32 bits for 64-bit version */ - __le32 i_projid; /* Project ID */ -}; - -struct move_extent { - __u32 reserved; /* should be zero */ - __u32 donor_fd; /* donor file descriptor */ - __u64 orig_start; /* logical start offset in block for orig */ - __u64 donor_start; /* logical start offset in block for donor */ - __u64 len; /* block length to be moved */ - __u64 moved_len; /* moved block length */ -}; - -#define EXT4_EPOCH_BITS 2 -#define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1) -#define EXT4_NSEC_MASK (~0UL << EXT4_EPOCH_BITS) - -/* - * Extended fields will fit into an inode if the filesystem was formatted - * with large inodes (-I 256 or larger) and there are not currently any EAs - * consuming all of the available space. For new inodes we always reserve - * enough space for the kernel's known extended fields, but for inodes - * created with an old kernel this might not have been the case. None of - * the extended inode fields is critical for correct filesystem operation. - * This macro checks if a certain field fits in the inode. Note that - * inode-size = GOOD_OLD_INODE_SIZE + i_extra_isize - */ -#define EXT4_FITS_IN_INODE(ext4_inode, einode, field) \ - ((offsetof(typeof(*ext4_inode), field) + \ - sizeof((ext4_inode)->field)) \ - <= (EXT4_GOOD_OLD_INODE_SIZE + \ - (einode)->i_extra_isize)) \ - -/* - * We use an encoding that preserves the times for extra epoch "00": - * - * extra msb of adjust for signed - * epoch 32-bit 32-bit tv_sec to - * bits time decoded 64-bit tv_sec 64-bit tv_sec valid time range - * 0 0 1 -0x80000000..-0x00000001 0x000000000 1901-12-13..1969-12-31 - * 0 0 0 0x000000000..0x07fffffff 0x000000000 1970-01-01..2038-01-19 - * 0 1 1 0x080000000..0x0ffffffff 0x100000000 2038-01-19..2106-02-07 - * 0 1 0 0x100000000..0x17fffffff 0x100000000 2106-02-07..2174-02-25 - * 1 0 1 0x180000000..0x1ffffffff 0x200000000 2174-02-25..2242-03-16 - * 1 0 0 0x200000000..0x27fffffff 0x200000000 2242-03-16..2310-04-04 - * 1 1 1 0x280000000..0x2ffffffff 0x300000000 2310-04-04..2378-04-22 - * 1 1 0 0x300000000..0x37fffffff 0x300000000 2378-04-22..2446-05-10 - * - * Note that previous versions of the kernel on 64-bit systems would - * incorrectly use extra epoch bits 1,1 for dates between 1901 and - * 1970. e2fsck will correct this, assuming that it is run on the - * affected filesystem before 2242. - */ - -static inline __le32 ext4_encode_extra_time(struct timespec *time) -{ - u32 extra = sizeof(time->tv_sec) > 4 ? - ((time->tv_sec - (s32)time->tv_sec) >> 32) & EXT4_EPOCH_MASK : 0; - return cpu_to_le32(extra | (time->tv_nsec << EXT4_EPOCH_BITS)); -} - -static inline void ext4_decode_extra_time(struct timespec *time, __le32 extra) -{ - if (unlikely(sizeof(time->tv_sec) > 4 && - (extra & cpu_to_le32(EXT4_EPOCH_MASK)))) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0) - /* Handle legacy encoding of pre-1970 dates with epoch - * bits 1,1. We assume that by kernel version 4.20, - * everyone will have run fsck over the affected - * filesystems to correct the problem. (This - * backwards compatibility may be removed before this - * time, at the discretion of the ext4 developers.) - */ - u64 extra_bits = le32_to_cpu(extra) & EXT4_EPOCH_MASK; - if (extra_bits == 3 && ((time->tv_sec) & 0x80000000) != 0) - extra_bits = 0; - time->tv_sec += extra_bits << 32; -#else - time->tv_sec += (u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK) << 32; -#endif - } - time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS; -} - -#define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode) \ -do { \ - (raw_inode)->xtime = cpu_to_le32((inode)->xtime.tv_sec); \ - if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) \ - (raw_inode)->xtime ## _extra = \ - ext4_encode_extra_time(&(inode)->xtime); \ -} while (0) - -#define EXT4_EINODE_SET_XTIME(xtime, einode, raw_inode) \ -do { \ - if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime)) \ - (raw_inode)->xtime = cpu_to_le32((einode)->xtime.tv_sec); \ - if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra)) \ - (raw_inode)->xtime ## _extra = \ - ext4_encode_extra_time(&(einode)->xtime); \ -} while (0) - -#define EXT4_INODE_GET_XTIME(xtime, inode, raw_inode) \ -do { \ - (inode)->xtime.tv_sec = (signed)le32_to_cpu((raw_inode)->xtime); \ - if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) \ - ext4_decode_extra_time(&(inode)->xtime, \ - raw_inode->xtime ## _extra); \ - else \ - (inode)->xtime.tv_nsec = 0; \ -} while (0) - -#define EXT4_EINODE_GET_XTIME(xtime, einode, raw_inode) \ -do { \ - if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime)) \ - (einode)->xtime.tv_sec = \ - (signed)le32_to_cpu((raw_inode)->xtime); \ - else \ - (einode)->xtime.tv_sec = 0; \ - if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra)) \ - ext4_decode_extra_time(&(einode)->xtime, \ - raw_inode->xtime ## _extra); \ - else \ - (einode)->xtime.tv_nsec = 0; \ -} while (0) - -#define i_disk_version osd1.linux1.l_i_version - -#if defined(__KERNEL__) || defined(__linux__) -#define i_reserved1 osd1.linux1.l_i_reserved1 -#define i_file_acl_high osd2.linux2.l_i_file_acl_high -#define i_blocks_high osd2.linux2.l_i_blocks_high -#define i_uid_low i_uid -#define i_gid_low i_gid -#define i_uid_high osd2.linux2.l_i_uid_high -#define i_gid_high osd2.linux2.l_i_gid_high -#define i_checksum_lo osd2.linux2.l_i_checksum_lo - -#elif defined(__GNU__) - -#define i_translator osd1.hurd1.h_i_translator -#define i_uid_high osd2.hurd2.h_i_uid_high -#define i_gid_high osd2.hurd2.h_i_gid_high -#define i_author osd2.hurd2.h_i_author - -#elif defined(__masix__) - -#define i_reserved1 osd1.masix1.m_i_reserved1 -#define i_file_acl_high osd2.masix2.m_i_file_acl_high -#define i_reserved2 osd2.masix2.m_i_reserved2 - -#endif /* defined(__KERNEL__) || defined(__linux__) */ - -#include "extents_status.h" - -/* - * Lock subclasses for i_data_sem in the ext4_inode_info structure. - * - * These are needed to avoid lockdep false positives when we need to - * allocate blocks to the quota inode during ext4_map_blocks(), while - * holding i_data_sem for a normal (non-quota) inode. Since we don't - * do quota tracking for the quota inode, this avoids deadlock (as - * well as infinite recursion, since it isn't turtles all the way - * down...) - * - * I_DATA_SEM_NORMAL - Used for most inodes - * I_DATA_SEM_OTHER - Used by move_inode.c for the second normal inode - * where the second inode has larger inode number - * than the first - * I_DATA_SEM_QUOTA - Used for quota inodes only - */ -enum { - I_DATA_SEM_NORMAL = 0, - I_DATA_SEM_OTHER, - I_DATA_SEM_QUOTA, -}; - - -/* - * fourth extended file system inode data in memory - */ -struct ext4_inode_info { - __le32 i_data[15]; /* unconverted */ - __u32 i_dtime; - ext4_fsblk_t i_file_acl; - - /* - * i_block_group is the number of the block group which contains - * this file's inode. Constant across the lifetime of the inode, - * it is ued for making block allocation decisions - we try to - * place a file's data blocks near its inode block, and new inodes - * near to their parent directory's inode. - */ - ext4_group_t i_block_group; - ext4_lblk_t i_dir_start_lookup; -#if (BITS_PER_LONG < 64) - unsigned long i_state_flags; /* Dynamic state flags */ -#endif - unsigned long i_flags; - - /* - * Extended attributes can be read independently of the main file - * data. Taking i_mutex even when reading would cause contention - * between readers of EAs and writers of regular file data, so - * instead we synchronize on xattr_sem when reading or changing - * EAs. - */ - struct rw_semaphore xattr_sem; - - struct list_head i_orphan; /* unlinked but open inodes */ - - /* - * i_disksize keeps track of what the inode size is ON DISK, not - * in memory. During truncate, i_size is set to the new size by - * the VFS prior to calling ext4_truncate(), but the filesystem won't - * set i_disksize to 0 until the truncate is actually under way. - * - * The intent is that i_disksize always represents the blocks which - * are used by this file. This allows recovery to restart truncate - * on orphans if we crash during truncate. We actually write i_disksize - * into the on-disk inode when writing inodes out, instead of i_size. - * - * The only time when i_disksize and i_size may be different is when - * a truncate is in progress. The only things which change i_disksize - * are ext4_get_block (growth) and ext4_truncate (shrinkth). - */ - loff_t i_disksize; - - /* - * i_data_sem is for serialising ext4_truncate() against - * ext4_getblock(). In the 2.4 ext2 design, great chunks of inode's - * data tree are chopped off during truncate. We can't do that in - * ext4 because whenever we perform intermediate commits during - * truncate, the inode and all the metadata blocks *must* be in a - * consistent state which allows truncation of the orphans to restart - * during recovery. Hence we must fix the get_block-vs-truncate race - * by other means, so we have i_data_sem. - */ - struct rw_semaphore i_data_sem; - /* - * i_mmap_sem is for serializing page faults with truncate / punch hole - * operations. We have to make sure that new page cannot be faulted in - * a section of the inode that is being punched. We cannot easily use - * i_data_sem for this since we need protection for the whole punch - * operation and i_data_sem ranks below transaction start so we have - * to occasionally drop it. - */ - struct rw_semaphore i_mmap_sem; - struct inode vfs_inode; - struct jbd2_inode *jinode; - - spinlock_t i_raw_lock; /* protects updates to the raw inode */ - - /* - * File creation time. Its function is same as that of - * struct timespec i_{a,c,m}time in the generic inode. - */ - struct timespec i_crtime; - - /* mballoc */ - struct list_head i_prealloc_list; - spinlock_t i_prealloc_lock; - - /* extents status tree */ - struct ext4_es_tree i_es_tree; - rwlock_t i_es_lock; - struct list_head i_es_list; - unsigned int i_es_all_nr; /* protected by i_es_lock */ - unsigned int i_es_shk_nr; /* protected by i_es_lock */ - ext4_lblk_t i_es_shrink_lblk; /* Offset where we start searching for - extents to shrink. Protected by - i_es_lock */ - - /* ialloc */ - ext4_group_t i_last_alloc_group; - - /* allocation reservation info for delalloc */ - /* In case of bigalloc, these refer to clusters rather than blocks */ - unsigned int i_reserved_data_blocks; - unsigned int i_reserved_meta_blocks; - unsigned int i_allocated_meta_blocks; - ext4_lblk_t i_da_metadata_calc_last_lblock; - int i_da_metadata_calc_len; - - /* on-disk additional length */ - __u16 i_extra_isize; - - /* Indicate the inline data space. */ - u16 i_inline_off; - u16 i_inline_size; - -#ifdef CONFIG_QUOTA - /* quota space reservation, managed internally by quota code */ - qsize_t i_reserved_quota; -#endif - - /* Lock protecting lists below */ - spinlock_t i_completed_io_lock; - /* - * Completed IOs that need unwritten extents handling and have - * transaction reserved - */ - struct list_head i_rsv_conversion_list; - struct work_struct i_rsv_conversion_work; - atomic_t i_unwritten; /* Nr. of inflight conversions pending */ - - spinlock_t i_block_reservation_lock; - - /* - * Transactions that contain inode's metadata needed to complete - * fsync and fdatasync, respectively. - */ - tid_t i_sync_tid; - tid_t i_datasync_tid; - -#ifdef CONFIG_QUOTA - struct dquot *i_dquot[MAXQUOTAS]; -#endif - - /* Precomputed uuid+inum+igen checksum for seeding inode checksums */ - __u32 i_csum_seed; - - kprojid_t i_projid; -}; - -/* - * File system states - */ -#define EXT4_VALID_FS 0x0001 /* Unmounted cleanly */ -#define EXT4_ERROR_FS 0x0002 /* Errors detected */ -#define EXT4_ORPHAN_FS 0x0004 /* Orphans being recovered */ - -/* - * Misc. filesystem flags - */ -#define EXT2_FLAGS_SIGNED_HASH 0x0001 /* Signed dirhash in use */ -#define EXT2_FLAGS_UNSIGNED_HASH 0x0002 /* Unsigned dirhash in use */ -#define EXT2_FLAGS_TEST_FILESYS 0x0004 /* to test development code */ - -/* - * Mount flags set via mount options or defaults - */ -#define EXT4_MOUNT_GRPID 0x00004 /* Create files with directory's group */ -#define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */ -#define EXT4_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */ -#define EXT4_MOUNT_ERRORS_RO 0x00020 /* Remount fs ro on errors */ -#define EXT4_MOUNT_ERRORS_PANIC 0x00040 /* Panic on errors */ -#define EXT4_MOUNT_ERRORS_MASK 0x00070 -#define EXT4_MOUNT_MINIX_DF 0x00080 /* Mimics the Minix statfs */ -#define EXT4_MOUNT_NOLOAD 0x00100 /* Don't use existing journal*/ -#ifdef CONFIG_FS_DAX -#define EXT4_MOUNT_DAX 0x00200 /* Direct Access */ -#else -#define EXT4_MOUNT_DAX 0 -#endif -#define EXT4_MOUNT_DATA_FLAGS 0x00C00 /* Mode for data writes: */ -#define EXT4_MOUNT_JOURNAL_DATA 0x00400 /* Write data to journal */ -#define EXT4_MOUNT_ORDERED_DATA 0x00800 /* Flush data before commit */ -#define EXT4_MOUNT_WRITEBACK_DATA 0x00C00 /* No data ordering */ -#define EXT4_MOUNT_UPDATE_JOURNAL 0x01000 /* Update the journal format */ -#define EXT4_MOUNT_NO_UID32 0x02000 /* Disable 32-bit UIDs */ -#define EXT4_MOUNT_XATTR_USER 0x04000 /* Extended user attributes */ -#define EXT4_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */ -#define EXT4_MOUNT_NO_AUTO_DA_ALLOC 0x10000 /* No auto delalloc mapping */ -#define EXT4_MOUNT_BARRIER 0x20000 /* Use block barriers */ -#define EXT4_MOUNT_QUOTA 0x40000 /* Some quota option set */ -#define EXT4_MOUNT_USRQUOTA 0x80000 /* "old" user quota, - * enable enforcement for hidden - * quota files */ -#define EXT4_MOUNT_GRPQUOTA 0x100000 /* "old" group quota, enable - * enforcement for hidden quota - * files */ -#define EXT4_MOUNT_PRJQUOTA 0x200000 /* Enable project quota - * enforcement */ -#define EXT4_MOUNT_DIOREAD_NOLOCK 0x400000 /* Enable support for dio read nolocking */ -#define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000 /* Journal checksums */ -#define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */ -#define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */ -#define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */ -#define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */ -#define EXT4_MOUNT_DISCARD 0x40000000 /* Issue DISCARD requests */ -#define EXT4_MOUNT_INIT_INODE_TABLE 0x80000000 /* Initialize uninitialized itables */ - -/* - * Mount flags set either automatically (could not be set by mount option) - * based on per file system feature or property or in special cases such as - * distinguishing between explicit mount option definition and default. - */ -#define EXT4_MOUNT2_EXPLICIT_DELALLOC 0x00000001 /* User explicitly - specified delalloc */ -#define EXT4_MOUNT2_STD_GROUP_SIZE 0x00000002 /* We have standard group - size of blocksize * 8 - blocks */ -#define EXT4_MOUNT2_HURD_COMPAT 0x00000004 /* Support HURD-castrated - file systems */ - -#define EXT4_MOUNT2_EXPLICIT_JOURNAL_CHECKSUM 0x00000008 /* User explicitly - specified journal checksum */ - -#define clear_opt(sb, opt) EXT4_SB(sb)->s_mount_opt &= \ - ~EXT4_MOUNT_##opt -#define set_opt(sb, opt) EXT4_SB(sb)->s_mount_opt |= \ - EXT4_MOUNT_##opt -#define test_opt(sb, opt) (EXT4_SB(sb)->s_mount_opt & \ - EXT4_MOUNT_##opt) - -#define clear_opt2(sb, opt) EXT4_SB(sb)->s_mount_opt2 &= \ - ~EXT4_MOUNT2_##opt -#define set_opt2(sb, opt) EXT4_SB(sb)->s_mount_opt2 |= \ - EXT4_MOUNT2_##opt -#define test_opt2(sb, opt) (EXT4_SB(sb)->s_mount_opt2 & \ - EXT4_MOUNT2_##opt) - -#define ext4_test_and_set_bit __test_and_set_bit_le -#define ext4_set_bit __set_bit_le -#define ext4_set_bit_atomic ext2_set_bit_atomic -#define ext4_test_and_clear_bit __test_and_clear_bit_le -#define ext4_clear_bit __clear_bit_le -#define ext4_clear_bit_atomic ext2_clear_bit_atomic -#define ext4_test_bit test_bit_le -#define ext4_find_next_zero_bit find_next_zero_bit_le -#define ext4_find_next_bit find_next_bit_le - -extern void ext4_set_bits(void *bm, int cur, int len); - -/* - * Maximal mount counts between two filesystem checks - */ -#define EXT4_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ -#define EXT4_DFL_CHECKINTERVAL 0 /* Don't use interval check */ - -/* - * Behaviour when detecting errors - */ -#define EXT4_ERRORS_CONTINUE 1 /* Continue execution */ -#define EXT4_ERRORS_RO 2 /* Remount fs read-only */ -#define EXT4_ERRORS_PANIC 3 /* Panic */ -#define EXT4_ERRORS_DEFAULT EXT4_ERRORS_CONTINUE - -/* Metadata checksum algorithm codes */ -#define EXT4_CRC32C_CHKSUM 1 - -/* - * Structure of the super block - */ -struct ext4_super_block { -/*00*/ __le32 s_inodes_count; /* Inodes count */ - __le32 s_blocks_count_lo; /* Blocks count */ - __le32 s_r_blocks_count_lo; /* Reserved blocks count */ - __le32 s_free_blocks_count_lo; /* Free blocks count */ -/*10*/ __le32 s_free_inodes_count; /* Free inodes count */ - __le32 s_first_data_block; /* First Data Block */ - __le32 s_log_block_size; /* Block size */ - __le32 s_log_cluster_size; /* Allocation cluster size */ -/*20*/ __le32 s_blocks_per_group; /* # Blocks per group */ - __le32 s_clusters_per_group; /* # Clusters per group */ - __le32 s_inodes_per_group; /* # Inodes per group */ - __le32 s_mtime; /* Mount time */ -/*30*/ __le32 s_wtime; /* Write time */ - __le16 s_mnt_count; /* Mount count */ - __le16 s_max_mnt_count; /* Maximal mount count */ - __le16 s_magic; /* Magic signature */ - __le16 s_state; /* File system state */ - __le16 s_errors; /* Behaviour when detecting errors */ - __le16 s_minor_rev_level; /* minor revision level */ -/*40*/ __le32 s_lastcheck; /* time of last check */ - __le32 s_checkinterval; /* max. time between checks */ - __le32 s_creator_os; /* OS */ - __le32 s_rev_level; /* Revision level */ -/*50*/ __le16 s_def_resuid; /* Default uid for reserved blocks */ - __le16 s_def_resgid; /* Default gid for reserved blocks */ - /* - * These fields are for EXT4_DYNAMIC_REV superblocks only. - * - * Note: the difference between the compatible feature set and - * the incompatible feature set is that if there is a bit set - * in the incompatible feature set that the kernel doesn't - * know about, it should refuse to mount the filesystem. - * - * e2fsck's requirements are more strict; if it doesn't know - * about a feature in either the compatible or incompatible - * feature set, it must abort and not try to meddle with - * things it doesn't understand... - */ - __le32 s_first_ino; /* First non-reserved inode */ - __le16 s_inode_size; /* size of inode structure */ - __le16 s_block_group_nr; /* block group # of this superblock */ - __le32 s_feature_compat; /* compatible feature set */ -/*60*/ __le32 s_feature_incompat; /* incompatible feature set */ - __le32 s_feature_ro_compat; /* readonly-compatible feature set */ -/*68*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */ -/*78*/ char s_volume_name[16]; /* volume name */ -/*88*/ char s_last_mounted[64]; /* directory where last mounted */ -/*C8*/ __le32 s_algorithm_usage_bitmap; /* For compression */ - /* - * Performance hints. Directory preallocation should only - * happen if the EXT4_FEATURE_COMPAT_DIR_PREALLOC flag is on. - */ - __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ - __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ - __le16 s_reserved_gdt_blocks; /* Per group desc for online growth */ - /* - * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set. - */ -/*D0*/ __u8 s_journal_uuid[16]; /* uuid of journal superblock */ -/*E0*/ __le32 s_journal_inum; /* inode number of journal file */ - __le32 s_journal_dev; /* device number of journal file */ - __le32 s_last_orphan; /* start of list of inodes to delete */ - __le32 s_hash_seed[4]; /* HTREE hash seed */ - __u8 s_def_hash_version; /* Default hash version to use */ - __u8 s_jnl_backup_type; - __le16 s_desc_size; /* size of group descriptor */ -/*100*/ __le32 s_default_mount_opts; - __le32 s_first_meta_bg; /* First metablock block group */ - __le32 s_mkfs_time; /* When the filesystem was created */ - __le32 s_jnl_blocks[17]; /* Backup of the journal inode */ - /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */ -/*150*/ __le32 s_blocks_count_hi; /* Blocks count */ - __le32 s_r_blocks_count_hi; /* Reserved blocks count */ - __le32 s_free_blocks_count_hi; /* Free blocks count */ - __le16 s_min_extra_isize; /* All inodes have at least # bytes */ - __le16 s_want_extra_isize; /* New inodes should reserve # bytes */ - __le32 s_flags; /* Miscellaneous flags */ - __le16 s_raid_stride; /* RAID stride */ - __le16 s_mmp_update_interval; /* # seconds to wait in MMP checking */ - __le64 s_mmp_block; /* Block for multi-mount protection */ - __le32 s_raid_stripe_width; /* blocks on all data disks (N*stride)*/ - __u8 s_log_groups_per_flex; /* FLEX_BG group size */ - __u8 s_checksum_type; /* metadata checksum algorithm used */ - __u8 s_encryption_level; /* versioning level for encryption */ - __u8 s_reserved_pad; /* Padding to next 32bits */ - __le64 s_kbytes_written; /* nr of lifetime kilobytes written */ - __le32 s_snapshot_inum; /* Inode number of active snapshot */ - __le32 s_snapshot_id; /* sequential ID of active snapshot */ - __le64 s_snapshot_r_blocks_count; /* reserved blocks for active - snapshot's future use */ - __le32 s_snapshot_list; /* inode number of the head of the - on-disk snapshot list */ -#define EXT4_S_ERR_START offsetof(struct ext4_super_block, s_error_count) - __le32 s_error_count; /* number of fs errors */ - __le32 s_first_error_time; /* first time an error happened */ - __le32 s_first_error_ino; /* inode involved in first error */ - __le64 s_first_error_block; /* block involved of first error */ - __u8 s_first_error_func[32]; /* function where the error happened */ - __le32 s_first_error_line; /* line number where error happened */ - __le32 s_last_error_time; /* most recent time of an error */ - __le32 s_last_error_ino; /* inode involved in last error */ - __le32 s_last_error_line; /* line number where error happened */ - __le64 s_last_error_block; /* block involved of last error */ - __u8 s_last_error_func[32]; /* function where the error happened */ -#define EXT4_S_ERR_END offsetof(struct ext4_super_block, s_mount_opts) - __u8 s_mount_opts[64]; - __le32 s_usr_quota_inum; /* inode for tracking user quota */ - __le32 s_grp_quota_inum; /* inode for tracking group quota */ - __le32 s_overhead_clusters; /* overhead blocks/clusters in fs */ - __le32 s_backup_bgs[2]; /* groups with sparse_super2 SBs */ - __u8 s_encrypt_algos[4]; /* Encryption algorithms in use */ - __u8 s_encrypt_pw_salt[16]; /* Salt used for string2key algorithm */ - __le32 s_lpf_ino; /* Location of the lost+found inode */ - __le32 s_prj_quota_inum; /* inode for tracking project quota */ - __le32 s_checksum_seed; /* crc32c(uuid) if csum_seed set */ - __le32 s_reserved[98]; /* Padding to the end of the block */ - __le32 s_checksum; /* crc32c(superblock) */ -}; - -#define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START) - -#ifdef __KERNEL__ - -/* - * run-time mount flags - */ -#define EXT4_MF_MNTDIR_SAMPLED 0x0001 -#define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */ -#define EXT4_MF_TEST_DUMMY_ENCRYPTION 0x0004 - -#ifdef CONFIG_EXT4_FS_ENCRYPTION -#define DUMMY_ENCRYPTION_ENABLED(sbi) (unlikely((sbi)->s_mount_flags & \ - EXT4_MF_TEST_DUMMY_ENCRYPTION)) -#else -#define DUMMY_ENCRYPTION_ENABLED(sbi) (0) -#endif - -/* Number of quota types we support */ -#define EXT4_MAXQUOTAS 3 - -#ifdef CONFIG_EXT4_FS_ENCRYPTION -#define EXT4_KEY_DESC_PREFIX "ext4:" -#define EXT4_KEY_DESC_PREFIX_SIZE 5 -#endif - -/* - * fourth extended-fs super-block data in memory - */ -struct ext4_sb_info { - unsigned long s_desc_size; /* Size of a group descriptor in bytes */ - unsigned long s_inodes_per_block;/* Number of inodes per block */ - unsigned long s_blocks_per_group;/* Number of blocks in a group */ - unsigned long s_clusters_per_group; /* Number of clusters in a group */ - unsigned long s_inodes_per_group;/* Number of inodes in a group */ - unsigned long s_itb_per_group; /* Number of inode table blocks per group */ - unsigned long s_gdb_count; /* Number of group descriptor blocks */ - unsigned long s_desc_per_block; /* Number of group descriptors per block */ - ext4_group_t s_groups_count; /* Number of groups in the fs */ - ext4_group_t s_blockfile_groups;/* Groups acceptable for non-extent files */ - unsigned long s_overhead; /* # of fs overhead clusters */ - unsigned int s_cluster_ratio; /* Number of blocks per cluster */ - unsigned int s_cluster_bits; /* log2 of s_cluster_ratio */ - loff_t s_bitmap_maxbytes; /* max bytes for bitmap files */ - struct buffer_head * s_sbh; /* Buffer containing the super block */ - struct ext4_super_block *s_es; /* Pointer to the super block in the buffer */ - struct buffer_head **s_group_desc; - unsigned int s_mount_opt; - unsigned int s_mount_opt2; - unsigned int s_mount_flags; - unsigned int s_def_mount_opt; - ext4_fsblk_t s_sb_block; - atomic64_t s_resv_clusters; - kuid_t s_resuid; - kgid_t s_resgid; - unsigned short s_mount_state; - unsigned short s_pad; - int s_addr_per_block_bits; - int s_desc_per_block_bits; - int s_inode_size; - int s_first_ino; - unsigned int s_inode_readahead_blks; - unsigned int s_inode_goal; - spinlock_t s_next_gen_lock; - u32 s_next_generation; - u32 s_hash_seed[4]; - int s_def_hash_version; - int s_hash_unsigned; /* 3 if hash should be signed, 0 if not */ - struct percpu_counter s_freeclusters_counter; - struct percpu_counter s_freeinodes_counter; - struct percpu_counter s_dirs_counter; - struct percpu_counter s_dirtyclusters_counter; - struct blockgroup_lock *s_blockgroup_lock; - struct proc_dir_entry *s_proc; - struct kobject s_kobj; - struct completion s_kobj_unregister; - struct super_block *s_sb; - - /* Journaling */ - struct journal_s *s_journal; - struct list_head s_orphan; - struct mutex s_orphan_lock; - unsigned long s_resize_flags; /* Flags indicating if there - is a resizer */ - unsigned long s_commit_interval; - u32 s_max_batch_time; - u32 s_min_batch_time; - struct block_device *journal_bdev; -#ifdef CONFIG_QUOTA - char *s_qf_names[EXT4_MAXQUOTAS]; /* Names of quota files with journalled quota */ - int s_jquota_fmt; /* Format of quota to use */ -#endif - unsigned int s_want_extra_isize; /* New inodes should reserve # bytes */ - struct rb_root system_blks; - -#ifdef EXTENTS_STATS - /* ext4 extents stats */ - unsigned long s_ext_min; - unsigned long s_ext_max; - unsigned long s_depth_max; - spinlock_t s_ext_stats_lock; - unsigned long s_ext_blocks; - unsigned long s_ext_extents; -#endif - - /* for buddy allocator */ - struct ext4_group_info ***s_group_info; - struct inode *s_buddy_cache; - spinlock_t s_md_lock; - unsigned short *s_mb_offsets; - unsigned int *s_mb_maxs; - unsigned int s_group_info_size; - unsigned int s_mb_free_pending; - - /* tunables */ - unsigned long s_stripe; - unsigned int s_mb_stream_request; - unsigned int s_mb_max_to_scan; - unsigned int s_mb_min_to_scan; - unsigned int s_mb_stats; - unsigned int s_mb_order2_reqs; - unsigned int s_mb_group_prealloc; - unsigned int s_max_dir_size_kb; - /* where last allocation was done - for stream allocation */ - unsigned long s_mb_last_group; - unsigned long s_mb_last_start; - - /* stats for buddy allocator */ - atomic_t s_bal_reqs; /* number of reqs with len > 1 */ - atomic_t s_bal_success; /* we found long enough chunks */ - atomic_t s_bal_allocated; /* in blocks */ - atomic_t s_bal_ex_scanned; /* total extents scanned */ - atomic_t s_bal_goals; /* goal hits */ - atomic_t s_bal_breaks; /* too long searches */ - atomic_t s_bal_2orders; /* 2^order hits */ - spinlock_t s_bal_lock; - unsigned long s_mb_buddies_generated; - unsigned long long s_mb_generation_time; - atomic_t s_mb_lost_chunks; - atomic_t s_mb_preallocated; - atomic_t s_mb_discarded; - atomic_t s_lock_busy; - - /* locality groups */ - struct ext4_locality_group __percpu *s_locality_groups; - - /* for write statistics */ - unsigned long s_sectors_written_start; - u64 s_kbytes_written; - - /* the size of zero-out chunk */ - unsigned int s_extent_max_zeroout_kb; - - unsigned int s_log_groups_per_flex; - struct flex_groups *s_flex_groups; - ext4_group_t s_flex_groups_allocated; - - /* workqueue for reserved extent conversions (buffered io) */ - struct workqueue_struct *rsv_conversion_wq; - - /* timer for periodic error stats printing */ - struct timer_list s_err_report; - - /* Lazy inode table initialization info */ - struct ext4_li_request *s_li_request; - /* Wait multiplier for lazy initialization thread */ - unsigned int s_li_wait_mult; - - /* Kernel thread for multiple mount protection */ - struct task_struct *s_mmp_tsk; - - /* record the last minlen when FITRIM is called. */ - atomic_t s_last_trim_minblks; - - /* Reference to checksum algorithm driver via cryptoapi */ - struct crypto_shash *s_chksum_driver; - - /* Precomputed FS UUID checksum for seeding other checksums */ - __u32 s_csum_seed; - - /* Reclaim extents from extent status tree */ - struct shrinker s_es_shrinker; - struct list_head s_es_list; /* List of inodes with reclaimable extents */ - long s_es_nr_inode; - struct ext4_es_stats s_es_stats; - struct mb_cache *s_mb_cache; - spinlock_t s_es_lock ____cacheline_aligned_in_smp; - - /* Ratelimit ext4 messages. */ - struct ratelimit_state s_err_ratelimit_state; - struct ratelimit_state s_warning_ratelimit_state; - struct ratelimit_state s_msg_ratelimit_state; - - /* Barrier between changing inodes' journal flags and writepages ops. */ - struct percpu_rw_semaphore s_journal_flag_rwsem; - - /* Encryption support */ -#ifdef CONFIG_EXT4_FS_ENCRYPTION - u8 key_prefix[EXT4_KEY_DESC_PREFIX_SIZE]; - u8 key_prefix_size; -#endif -}; - -static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb) -{ - return sb->s_fs_info; -} -static inline struct ext4_inode_info *EXT4_I(struct inode *inode) -{ - return container_of(inode, struct ext4_inode_info, vfs_inode); -} - -static inline struct timespec ext4_current_time(struct inode *inode) -{ - return (inode->i_sb->s_time_gran < NSEC_PER_SEC) ? - current_fs_time(inode->i_sb) : CURRENT_TIME_SEC; -} - -static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino) -{ - return ino == EXT4_ROOT_INO || - ino == EXT4_USR_QUOTA_INO || - ino == EXT4_GRP_QUOTA_INO || - ino == EXT4_BOOT_LOADER_INO || - ino == EXT4_JOURNAL_INO || - ino == EXT4_RESIZE_INO || - (ino >= EXT4_FIRST_INO(sb) && - ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count)); -} - -/* - * Inode dynamic state flags - */ -enum { - EXT4_STATE_JDATA, /* journaled data exists */ - EXT4_STATE_NEW, /* inode is newly created */ - EXT4_STATE_XATTR, /* has in-inode xattrs */ - EXT4_STATE_NO_EXPAND, /* No space for expansion */ - EXT4_STATE_DA_ALLOC_CLOSE, /* Alloc DA blks on close */ - EXT4_STATE_EXT_MIGRATE, /* Inode is migrating */ - EXT4_STATE_DIO_UNWRITTEN, /* need convert on dio done*/ - EXT4_STATE_NEWENTRY, /* File just added to dir */ - EXT4_STATE_DIOREAD_LOCK, /* Disable support for dio read - nolocking */ - EXT4_STATE_MAY_INLINE_DATA, /* may have in-inode data */ - EXT4_STATE_EXT_PRECACHED, /* extents have been precached */ -}; - -#define EXT4_INODE_BIT_FNS(name, field, offset) \ -static inline int ext4_test_inode_##name(struct inode *inode, int bit) \ -{ \ - return test_bit(bit + (offset), &EXT4_I(inode)->i_##field); \ -} \ -static inline void ext4_set_inode_##name(struct inode *inode, int bit) \ -{ \ - set_bit(bit + (offset), &EXT4_I(inode)->i_##field); \ -} \ -static inline void ext4_clear_inode_##name(struct inode *inode, int bit) \ -{ \ - clear_bit(bit + (offset), &EXT4_I(inode)->i_##field); \ -} - -/* Add these declarations here only so that these functions can be - * found by name. Otherwise, they are very hard to locate. */ -static inline int ext4_test_inode_flag(struct inode *inode, int bit); -static inline void ext4_set_inode_flag(struct inode *inode, int bit); -static inline void ext4_clear_inode_flag(struct inode *inode, int bit); -EXT4_INODE_BIT_FNS(flag, flags, 0) - -/* Add these declarations here only so that these functions can be - * found by name. Otherwise, they are very hard to locate. */ -static inline int ext4_test_inode_state(struct inode *inode, int bit); -static inline void ext4_set_inode_state(struct inode *inode, int bit); -static inline void ext4_clear_inode_state(struct inode *inode, int bit); -#if (BITS_PER_LONG < 64) -EXT4_INODE_BIT_FNS(state, state_flags, 0) - -static inline void ext4_clear_state_flags(struct ext4_inode_info *ei) -{ - (ei)->i_state_flags = 0; -} -#else -EXT4_INODE_BIT_FNS(state, flags, 32) - -static inline void ext4_clear_state_flags(struct ext4_inode_info *ei) -{ - /* We depend on the fact that callers will set i_flags */ -} -#endif -#else -/* Assume that user mode programs are passing in an ext4fs superblock, not - * a kernel struct super_block. This will allow us to call the feature-test - * macros from user land. */ -#define EXT4_SB(sb) (sb) -#endif - -/* - * Returns true if the inode is inode is encrypted - */ -#define NEXT_ORPHAN(inode) EXT4_I(inode)->i_dtime - -/* - * Codes for operating systems - */ -#define EXT4_OS_LINUX 0 -#define EXT4_OS_HURD 1 -#define EXT4_OS_MASIX 2 -#define EXT4_OS_FREEBSD 3 -#define EXT4_OS_LITES 4 - -/* - * Revision levels - */ -#define EXT4_GOOD_OLD_REV 0 /* The good old (original) format */ -#define EXT4_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */ - -#define EXT4_CURRENT_REV EXT4_GOOD_OLD_REV -#define EXT4_MAX_SUPP_REV EXT4_DYNAMIC_REV - -#define EXT4_GOOD_OLD_INODE_SIZE 128 - -/* - * Feature set definitions - */ - -#define EXT4_FEATURE_COMPAT_DIR_PREALLOC 0x0001 -#define EXT4_FEATURE_COMPAT_IMAGIC_INODES 0x0002 -#define EXT4_FEATURE_COMPAT_HAS_JOURNAL 0x0004 -#define EXT4_FEATURE_COMPAT_EXT_ATTR 0x0008 -#define EXT4_FEATURE_COMPAT_RESIZE_INODE 0x0010 -#define EXT4_FEATURE_COMPAT_DIR_INDEX 0x0020 -#define EXT4_FEATURE_COMPAT_SPARSE_SUPER2 0x0200 - -#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 -#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 -#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 -#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008 -#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010 -#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020 -#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040 -#define EXT4_FEATURE_RO_COMPAT_QUOTA 0x0100 -#define EXT4_FEATURE_RO_COMPAT_BIGALLOC 0x0200 -/* - * METADATA_CSUM also enables group descriptor checksums (GDT_CSUM). When - * METADATA_CSUM is set, group descriptor checksums use the same algorithm as - * all other data structures' checksums. However, the METADATA_CSUM and - * GDT_CSUM bits are mutually exclusive. - */ -#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM 0x0400 -#define EXT4_FEATURE_RO_COMPAT_READONLY 0x1000 -#define EXT4_FEATURE_RO_COMPAT_PROJECT 0x2000 - -#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001 -#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002 -#define EXT4_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ -#define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ -#define EXT4_FEATURE_INCOMPAT_META_BG 0x0010 -#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */ -#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 -#define EXT4_FEATURE_INCOMPAT_MMP 0x0100 -#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 -#define EXT4_FEATURE_INCOMPAT_EA_INODE 0x0400 /* EA in inode */ -#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000 /* data in dirent */ -#define EXT4_FEATURE_INCOMPAT_CSUM_SEED 0x2000 -#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */ -#define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */ -#define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000 - -#define EXT4_FEATURE_COMPAT_FUNCS(name, flagname) \ -static inline bool ext4_has_feature_##name(struct super_block *sb) \ -{ \ - return ((EXT4_SB(sb)->s_es->s_feature_compat & \ - cpu_to_le32(EXT4_FEATURE_COMPAT_##flagname)) != 0); \ -} \ -static inline void ext4_set_feature_##name(struct super_block *sb) \ -{ \ - EXT4_SB(sb)->s_es->s_feature_compat |= \ - cpu_to_le32(EXT4_FEATURE_COMPAT_##flagname); \ -} \ -static inline void ext4_clear_feature_##name(struct super_block *sb) \ -{ \ - EXT4_SB(sb)->s_es->s_feature_compat &= \ - ~cpu_to_le32(EXT4_FEATURE_COMPAT_##flagname); \ -} - -#define EXT4_FEATURE_RO_COMPAT_FUNCS(name, flagname) \ -static inline bool ext4_has_feature_##name(struct super_block *sb) \ -{ \ - return ((EXT4_SB(sb)->s_es->s_feature_ro_compat & \ - cpu_to_le32(EXT4_FEATURE_RO_COMPAT_##flagname)) != 0); \ -} \ -static inline void ext4_set_feature_##name(struct super_block *sb) \ -{ \ - EXT4_SB(sb)->s_es->s_feature_ro_compat |= \ - cpu_to_le32(EXT4_FEATURE_RO_COMPAT_##flagname); \ -} \ -static inline void ext4_clear_feature_##name(struct super_block *sb) \ -{ \ - EXT4_SB(sb)->s_es->s_feature_ro_compat &= \ - ~cpu_to_le32(EXT4_FEATURE_RO_COMPAT_##flagname); \ -} - -#define EXT4_FEATURE_INCOMPAT_FUNCS(name, flagname) \ -static inline bool ext4_has_feature_##name(struct super_block *sb) \ -{ \ - return ((EXT4_SB(sb)->s_es->s_feature_incompat & \ - cpu_to_le32(EXT4_FEATURE_INCOMPAT_##flagname)) != 0); \ -} \ -static inline void ext4_set_feature_##name(struct super_block *sb) \ -{ \ - EXT4_SB(sb)->s_es->s_feature_incompat |= \ - cpu_to_le32(EXT4_FEATURE_INCOMPAT_##flagname); \ -} \ -static inline void ext4_clear_feature_##name(struct super_block *sb) \ -{ \ - EXT4_SB(sb)->s_es->s_feature_incompat &= \ - ~cpu_to_le32(EXT4_FEATURE_INCOMPAT_##flagname); \ -} - -EXT4_FEATURE_COMPAT_FUNCS(dir_prealloc, DIR_PREALLOC) -EXT4_FEATURE_COMPAT_FUNCS(imagic_inodes, IMAGIC_INODES) -EXT4_FEATURE_COMPAT_FUNCS(journal, HAS_JOURNAL) -EXT4_FEATURE_COMPAT_FUNCS(xattr, EXT_ATTR) -EXT4_FEATURE_COMPAT_FUNCS(resize_inode, RESIZE_INODE) -EXT4_FEATURE_COMPAT_FUNCS(dir_index, DIR_INDEX) -EXT4_FEATURE_COMPAT_FUNCS(sparse_super2, SPARSE_SUPER2) - -EXT4_FEATURE_RO_COMPAT_FUNCS(sparse_super, SPARSE_SUPER) -EXT4_FEATURE_RO_COMPAT_FUNCS(large_file, LARGE_FILE) -EXT4_FEATURE_RO_COMPAT_FUNCS(btree_dir, BTREE_DIR) -EXT4_FEATURE_RO_COMPAT_FUNCS(huge_file, HUGE_FILE) -EXT4_FEATURE_RO_COMPAT_FUNCS(gdt_csum, GDT_CSUM) -EXT4_FEATURE_RO_COMPAT_FUNCS(dir_nlink, DIR_NLINK) -EXT4_FEATURE_RO_COMPAT_FUNCS(extra_isize, EXTRA_ISIZE) -EXT4_FEATURE_RO_COMPAT_FUNCS(quota, QUOTA) -EXT4_FEATURE_RO_COMPAT_FUNCS(bigalloc, BIGALLOC) -EXT4_FEATURE_RO_COMPAT_FUNCS(metadata_csum, METADATA_CSUM) -EXT4_FEATURE_RO_COMPAT_FUNCS(readonly, READONLY) -EXT4_FEATURE_RO_COMPAT_FUNCS(project, PROJECT) - -EXT4_FEATURE_INCOMPAT_FUNCS(compression, COMPRESSION) -EXT4_FEATURE_INCOMPAT_FUNCS(filetype, FILETYPE) -EXT4_FEATURE_INCOMPAT_FUNCS(journal_needs_recovery, RECOVER) -EXT4_FEATURE_INCOMPAT_FUNCS(journal_dev, JOURNAL_DEV) -EXT4_FEATURE_INCOMPAT_FUNCS(meta_bg, META_BG) -EXT4_FEATURE_INCOMPAT_FUNCS(extents, EXTENTS) -EXT4_FEATURE_INCOMPAT_FUNCS(64bit, 64BIT) -EXT4_FEATURE_INCOMPAT_FUNCS(mmp, MMP) -EXT4_FEATURE_INCOMPAT_FUNCS(flex_bg, FLEX_BG) -EXT4_FEATURE_INCOMPAT_FUNCS(ea_inode, EA_INODE) -EXT4_FEATURE_INCOMPAT_FUNCS(dirdata, DIRDATA) -EXT4_FEATURE_INCOMPAT_FUNCS(csum_seed, CSUM_SEED) -EXT4_FEATURE_INCOMPAT_FUNCS(largedir, LARGEDIR) -EXT4_FEATURE_INCOMPAT_FUNCS(inline_data, INLINE_DATA) -EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, ENCRYPT) - -#define EXT2_FEATURE_COMPAT_SUPP EXT4_FEATURE_COMPAT_EXT_ATTR -#define EXT2_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \ - EXT4_FEATURE_INCOMPAT_META_BG) -#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \ - EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \ - EXT4_FEATURE_RO_COMPAT_BTREE_DIR) - -#define EXT3_FEATURE_COMPAT_SUPP EXT4_FEATURE_COMPAT_EXT_ATTR -#define EXT3_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \ - EXT4_FEATURE_INCOMPAT_RECOVER| \ - EXT4_FEATURE_INCOMPAT_META_BG) -#define EXT3_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \ - EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \ - EXT4_FEATURE_RO_COMPAT_BTREE_DIR) - -#define EXT4_FEATURE_COMPAT_SUPP EXT4_FEATURE_COMPAT_EXT_ATTR -#define EXT4_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \ - EXT4_FEATURE_INCOMPAT_RECOVER| \ - EXT4_FEATURE_INCOMPAT_META_BG| \ - EXT4_FEATURE_INCOMPAT_EXTENTS| \ - EXT4_FEATURE_INCOMPAT_64BIT| \ - EXT4_FEATURE_INCOMPAT_FLEX_BG| \ - EXT4_FEATURE_INCOMPAT_MMP | \ - EXT4_FEATURE_INCOMPAT_INLINE_DATA | \ - EXT4_FEATURE_INCOMPAT_ENCRYPT | \ - EXT4_FEATURE_INCOMPAT_CSUM_SEED) -#define EXT4_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \ - EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \ - EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \ - EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \ - EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \ - EXT4_FEATURE_RO_COMPAT_BTREE_DIR |\ - EXT4_FEATURE_RO_COMPAT_HUGE_FILE |\ - EXT4_FEATURE_RO_COMPAT_BIGALLOC |\ - EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|\ - EXT4_FEATURE_RO_COMPAT_QUOTA |\ - EXT4_FEATURE_RO_COMPAT_PROJECT) - -#define EXTN_FEATURE_FUNCS(ver) \ -static inline bool ext4_has_unknown_ext##ver##_compat_features(struct super_block *sb) \ -{ \ - return ((EXT4_SB(sb)->s_es->s_feature_compat & \ - cpu_to_le32(~EXT##ver##_FEATURE_COMPAT_SUPP)) != 0); \ -} \ -static inline bool ext4_has_unknown_ext##ver##_ro_compat_features(struct super_block *sb) \ -{ \ - return ((EXT4_SB(sb)->s_es->s_feature_ro_compat & \ - cpu_to_le32(~EXT##ver##_FEATURE_RO_COMPAT_SUPP)) != 0); \ -} \ -static inline bool ext4_has_unknown_ext##ver##_incompat_features(struct super_block *sb) \ -{ \ - return ((EXT4_SB(sb)->s_es->s_feature_incompat & \ - cpu_to_le32(~EXT##ver##_FEATURE_INCOMPAT_SUPP)) != 0); \ -} - -EXTN_FEATURE_FUNCS(2) -EXTN_FEATURE_FUNCS(3) -EXTN_FEATURE_FUNCS(4) - -static inline bool ext4_has_compat_features(struct super_block *sb) -{ - return (EXT4_SB(sb)->s_es->s_feature_compat != 0); -} -static inline bool ext4_has_ro_compat_features(struct super_block *sb) -{ - return (EXT4_SB(sb)->s_es->s_feature_ro_compat != 0); -} -static inline bool ext4_has_incompat_features(struct super_block *sb) -{ - return (EXT4_SB(sb)->s_es->s_feature_incompat != 0); -} - -/* - * Default values for user and/or group using reserved blocks - */ -#define EXT4_DEF_RESUID 0 -#define EXT4_DEF_RESGID 0 - -/* - * Default project ID - */ -#define EXT4_DEF_PROJID 0 - -#define EXT4_DEF_INODE_READAHEAD_BLKS 32 - -/* - * Default mount options - */ -#define EXT4_DEFM_DEBUG 0x0001 -#define EXT4_DEFM_BSDGROUPS 0x0002 -#define EXT4_DEFM_XATTR_USER 0x0004 -#define EXT4_DEFM_ACL 0x0008 -#define EXT4_DEFM_UID16 0x0010 -#define EXT4_DEFM_JMODE 0x0060 -#define EXT4_DEFM_JMODE_DATA 0x0020 -#define EXT4_DEFM_JMODE_ORDERED 0x0040 -#define EXT4_DEFM_JMODE_WBACK 0x0060 -#define EXT4_DEFM_NOBARRIER 0x0100 -#define EXT4_DEFM_BLOCK_VALIDITY 0x0200 -#define EXT4_DEFM_DISCARD 0x0400 -#define EXT4_DEFM_NODELALLOC 0x0800 - -/* - * Default journal batch times - */ -#define EXT4_DEF_MIN_BATCH_TIME 0 -#define EXT4_DEF_MAX_BATCH_TIME 15000 /* 15ms */ - -/* - * Minimum number of groups in a flexgroup before we separate out - * directories into the first block group of a flexgroup - */ -#define EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME 4 - -/* - * Structure of a directory entry - */ -#define EXT4_NAME_LEN 255 - -struct ext4_dir_entry { - __le32 inode; /* Inode number */ - __le16 rec_len; /* Directory entry length */ - __le16 name_len; /* Name length */ - char name[EXT4_NAME_LEN]; /* File name */ -}; - -/* - * The new version of the directory entry. Since EXT4 structures are - * stored in intel byte order, and the name_len field could never be - * bigger than 255 chars, it's safe to reclaim the extra byte for the - * file_type field. - */ -struct ext4_dir_entry_2 { - __le32 inode; /* Inode number */ - __le16 rec_len; /* Directory entry length */ - __u8 name_len; /* Name length */ - __u8 file_type; - char name[EXT4_NAME_LEN]; /* File name */ -}; - -/* - * This is a bogus directory entry at the end of each leaf block that - * records checksums. - */ -struct ext4_dir_entry_tail { - __le32 det_reserved_zero1; /* Pretend to be unused */ - __le16 det_rec_len; /* 12 */ - __u8 det_reserved_zero2; /* Zero name length */ - __u8 det_reserved_ft; /* 0xDE, fake file type */ - __le32 det_checksum; /* crc32c(uuid+inum+dirblock) */ -}; - -#define EXT4_DIRENT_TAIL(block, blocksize) \ - ((struct ext4_dir_entry_tail *)(((void *)(block)) + \ - ((blocksize) - \ - sizeof(struct ext4_dir_entry_tail)))) - -/* - * Ext4 directory file types. Only the low 3 bits are used. The - * other bits are reserved for now. - */ -#define EXT4_FT_UNKNOWN 0 -#define EXT4_FT_REG_FILE 1 -#define EXT4_FT_DIR 2 -#define EXT4_FT_CHRDEV 3 -#define EXT4_FT_BLKDEV 4 -#define EXT4_FT_FIFO 5 -#define EXT4_FT_SOCK 6 -#define EXT4_FT_SYMLINK 7 - -#define EXT4_FT_MAX 8 - -#define EXT4_FT_DIR_CSUM 0xDE - -/* - * EXT4_DIR_PAD defines the directory entries boundaries - * - * NOTE: It must be a multiple of 4 - */ -#define EXT4_DIR_PAD 4 -#define EXT4_DIR_ROUND (EXT4_DIR_PAD - 1) -#define EXT4_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT4_DIR_ROUND) & \ - ~EXT4_DIR_ROUND) -#define EXT4_MAX_REC_LEN ((1<<16)-1) - -/* - * If we ever get support for fs block sizes > page_size, we'll need - * to remove the #if statements in the next two functions... - */ -static inline unsigned int -ext4_rec_len_from_disk(__le16 dlen, unsigned blocksize) -{ - unsigned len = le16_to_cpu(dlen); - -#if (PAGE_SIZE >= 65536) - if (len == EXT4_MAX_REC_LEN || len == 0) - return blocksize; - return (len & 65532) | ((len & 3) << 16); -#else - return len; -#endif -} - -static inline __le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize) -{ - if ((len > blocksize) || (blocksize > (1 << 18)) || (len & 3)) - BUG(); -#if (PAGE_SIZE >= 65536) - if (len < 65536) - return cpu_to_le16(len); - if (len == blocksize) { - if (blocksize == 65536) - return cpu_to_le16(EXT4_MAX_REC_LEN); - else - return cpu_to_le16(0); - } - return cpu_to_le16((len & 65532) | ((len >> 16) & 3)); -#else - return cpu_to_le16(len); -#endif -} - -/* - * Hash Tree Directory indexing - * (c) Daniel Phillips, 2001 - */ - -#define is_dx(dir) (ext4_has_feature_dir_index((dir)->i_sb) && \ - ext4_test_inode_flag((dir), EXT4_INODE_INDEX)) -#define EXT4_DIR_LINK_MAX(dir) (!is_dx(dir) && (dir)->i_nlink >= EXT4_LINK_MAX) -#define EXT4_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1) - -/* Legal values for the dx_root hash_version field: */ - -#define DX_HASH_LEGACY 0 -#define DX_HASH_HALF_MD4 1 -#define DX_HASH_TEA 2 -#define DX_HASH_LEGACY_UNSIGNED 3 -#define DX_HASH_HALF_MD4_UNSIGNED 4 -#define DX_HASH_TEA_UNSIGNED 5 - -static inline u32 ext4_chksum(struct ext4_sb_info *sbi, u32 crc, - const void *address, unsigned int length) -{ - struct { - struct shash_desc shash; - char ctx[4]; - } desc; - int err; - - BUG_ON(crypto_shash_descsize(sbi->s_chksum_driver)!=sizeof(desc.ctx)); - - desc.shash.tfm = sbi->s_chksum_driver; - desc.shash.flags = 0; - *(u32 *)desc.ctx = crc; - - err = crypto_shash_update(&desc.shash, address, length); - BUG_ON(err); - - return *(u32 *)desc.ctx; -} - -#ifdef __KERNEL__ - -/* hash info structure used by the directory hash */ -struct dx_hash_info -{ - u32 hash; - u32 minor_hash; - int hash_version; - u32 *seed; -}; - - -/* 32 and 64 bit signed EOF for dx directories */ -#define EXT4_HTREE_EOF_32BIT ((1UL << (32 - 1)) - 1) -#define EXT4_HTREE_EOF_64BIT ((1ULL << (64 - 1)) - 1) - - -/* - * Control parameters used by ext4_htree_next_block - */ -#define HASH_NB_ALWAYS 1 - -struct ext4_filename { - const struct qstr *usr_fname; - struct fscrypt_str disk_name; - struct dx_hash_info hinfo; -#ifdef CONFIG_EXT4_FS_ENCRYPTION - struct fscrypt_str crypto_buf; -#endif -}; - -#define fname_name(p) ((p)->disk_name.name) -#define fname_len(p) ((p)->disk_name.len) - -/* - * Describe an inode's exact location on disk and in memory - */ -struct ext4_iloc -{ - struct buffer_head *bh; - unsigned long offset; - ext4_group_t block_group; -}; - -static inline struct ext4_inode *ext4_raw_inode(struct ext4_iloc *iloc) -{ - return (struct ext4_inode *) (iloc->bh->b_data + iloc->offset); -} - -/* - * This structure is stuffed into the struct file's private_data field - * for directories. It is where we put information so that we can do - * readdir operations in hash tree order. - */ -struct dir_private_info { - struct rb_root root; - struct rb_node *curr_node; - struct fname *extra_fname; - loff_t last_pos; - __u32 curr_hash; - __u32 curr_minor_hash; - __u32 next_hash; -}; - -/* calculate the first block number of the group */ -static inline ext4_fsblk_t -ext4_group_first_block_no(struct super_block *sb, ext4_group_t group_no) -{ - return group_no * (ext4_fsblk_t)EXT4_BLOCKS_PER_GROUP(sb) + - le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); -} - -/* - * Special error return code only used by dx_probe() and its callers. - */ -#define ERR_BAD_DX_DIR (-(MAX_ERRNO - 1)) - -/* - * Timeout and state flag for lazy initialization inode thread. - */ -#define EXT4_DEF_LI_WAIT_MULT 10 -#define EXT4_DEF_LI_MAX_START_DELAY 5 -#define EXT4_LAZYINIT_QUIT 0x0001 -#define EXT4_LAZYINIT_RUNNING 0x0002 - -/* - * Lazy inode table initialization info - */ -struct ext4_lazy_init { - unsigned long li_state; - struct list_head li_request_list; - struct mutex li_list_mtx; -}; - -struct ext4_li_request { - struct super_block *lr_super; - struct ext4_sb_info *lr_sbi; - ext4_group_t lr_next_group; - struct list_head lr_request; - unsigned long lr_next_sched; - unsigned long lr_timeout; -}; - -struct ext4_features { - struct kobject f_kobj; - struct completion f_kobj_unregister; -}; - -/* - * This structure will be used for multiple mount protection. It will be - * written into the block number saved in the s_mmp_block field in the - * superblock. Programs that check MMP should assume that if - * SEQ_FSCK (or any unknown code above SEQ_MAX) is present then it is NOT safe - * to use the filesystem, regardless of how old the timestamp is. - */ -#define EXT4_MMP_MAGIC 0x004D4D50U /* ASCII for MMP */ -#define EXT4_MMP_SEQ_CLEAN 0xFF4D4D50U /* mmp_seq value for clean unmount */ -#define EXT4_MMP_SEQ_FSCK 0xE24D4D50U /* mmp_seq value when being fscked */ -#define EXT4_MMP_SEQ_MAX 0xE24D4D4FU /* maximum valid mmp_seq value */ - -struct mmp_struct { - __le32 mmp_magic; /* Magic number for MMP */ - __le32 mmp_seq; /* Sequence no. updated periodically */ - - /* - * mmp_time, mmp_nodename & mmp_bdevname are only used for information - * purposes and do not affect the correctness of the algorithm - */ - __le64 mmp_time; /* Time last updated */ - char mmp_nodename[64]; /* Node which last updated MMP block */ - char mmp_bdevname[32]; /* Bdev which last updated MMP block */ - - /* - * mmp_check_interval is used to verify if the MMP block has been - * updated on the block device. The value is updated based on the - * maximum time to write the MMP block during an update cycle. - */ - __le16 mmp_check_interval; - - __le16 mmp_pad1; - __le32 mmp_pad2[226]; - __le32 mmp_checksum; /* crc32c(uuid+mmp_block) */ -}; - -/* arguments passed to the mmp thread */ -struct mmpd_data { - struct buffer_head *bh; /* bh from initial read_mmp_block() */ - struct super_block *sb; /* super block of the fs */ -}; - -/* - * Check interval multiplier - * The MMP block is written every update interval and initially checked every - * update interval x the multiplier (the value is then adapted based on the - * write latency). The reason is that writes can be delayed under load and we - * don't want readers to incorrectly assume that the filesystem is no longer - * in use. - */ -#define EXT4_MMP_CHECK_MULT 2UL - -/* - * Minimum interval for MMP checking in seconds. - */ -#define EXT4_MMP_MIN_CHECK_INTERVAL 5UL - -/* - * Maximum interval for MMP checking in seconds. - */ -#define EXT4_MMP_MAX_CHECK_INTERVAL 300UL - -/* - * Function prototypes - */ - -/* - * Ok, these declarations are also in but none of the - * ext4 source programs needs to include it so they are duplicated here. - */ -# define NORET_TYPE /**/ -# define ATTRIB_NORET __attribute__((noreturn)) -# define NORET_AND noreturn, - -/* bitmap.c */ -extern unsigned int ext4_count_free(char *bitmap, unsigned numchars); -void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group, - struct ext4_group_desc *gdp, - struct buffer_head *bh, int sz); -int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, - struct ext4_group_desc *gdp, - struct buffer_head *bh, int sz); -void ext4_block_bitmap_csum_set(struct super_block *sb, ext4_group_t group, - struct ext4_group_desc *gdp, - struct buffer_head *bh); -int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group, - struct ext4_group_desc *gdp, - struct buffer_head *bh); - -/* balloc.c */ -extern void ext4_get_group_no_and_offset(struct super_block *sb, - ext4_fsblk_t blocknr, - ext4_group_t *blockgrpp, - ext4_grpblk_t *offsetp); -extern ext4_group_t ext4_get_group_number(struct super_block *sb, - ext4_fsblk_t block); - -extern unsigned int ext4_block_group(struct super_block *sb, - ext4_fsblk_t blocknr); -extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb, - ext4_fsblk_t blocknr); -extern int ext4_bg_has_super(struct super_block *sb, ext4_group_t group); -extern unsigned long ext4_bg_num_gdb(struct super_block *sb, - ext4_group_t group); -extern ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode, - ext4_fsblk_t goal, - unsigned int flags, - unsigned long *count, - int *errp); -extern int ext4_claim_free_clusters(struct ext4_sb_info *sbi, - s64 nclusters, unsigned int flags); -extern ext4_fsblk_t ext4_count_free_clusters(struct super_block *); -extern void ext4_check_blocks_bitmap(struct super_block *); -extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb, - ext4_group_t block_group, - struct buffer_head ** bh); -extern int ext4_should_retry_alloc(struct super_block *sb, int *retries); - -extern struct buffer_head *ext4_read_block_bitmap_nowait(struct super_block *sb, - ext4_group_t block_group); -extern int ext4_wait_block_bitmap(struct super_block *sb, - ext4_group_t block_group, - struct buffer_head *bh); -extern struct buffer_head *ext4_read_block_bitmap(struct super_block *sb, - ext4_group_t block_group); -extern unsigned ext4_free_clusters_after_init(struct super_block *sb, - ext4_group_t block_group, - struct ext4_group_desc *gdp); -ext4_fsblk_t ext4_inode_to_goal_block(struct inode *); - -static inline int ext4_sb_has_crypto(struct super_block *sb) -{ - return ext4_has_feature_encrypt(sb); -} - -static inline bool ext4_encrypted_inode(struct inode *inode) -{ - return ext4_test_inode_flag(inode, EXT4_INODE_ENCRYPT); -} - -#ifdef CONFIG_EXT4_FS_ENCRYPTION -static inline int ext4_fname_setup_filename(struct inode *dir, - const struct qstr *iname, - int lookup, struct ext4_filename *fname) -{ - struct fscrypt_name name; - int err; - - memset(fname, 0, sizeof(struct ext4_filename)); - - err = fscrypt_setup_filename(dir, iname, lookup, &name); - - fname->usr_fname = name.usr_fname; - fname->disk_name = name.disk_name; - fname->hinfo.hash = name.hash; - fname->hinfo.minor_hash = name.minor_hash; - fname->crypto_buf = name.crypto_buf; - return err; -} - -static inline void ext4_fname_free_filename(struct ext4_filename *fname) -{ - struct fscrypt_name name; - - name.crypto_buf = fname->crypto_buf; - fscrypt_free_filename(&name); - - fname->crypto_buf.name = NULL; - fname->usr_fname = NULL; - fname->disk_name.name = NULL; -} -#else -static inline int ext4_fname_setup_filename(struct inode *dir, - const struct qstr *iname, - int lookup, struct ext4_filename *fname) -{ - fname->usr_fname = iname; - fname->disk_name.name = (unsigned char *) iname->name; - fname->disk_name.len = iname->len; - return 0; -} -static inline void ext4_fname_free_filename(struct ext4_filename *fname) { } - -#define fscrypt_set_d_op(i) -#define fscrypt_get_ctx fscrypt_notsupp_get_ctx -#define fscrypt_release_ctx fscrypt_notsupp_release_ctx -#define fscrypt_encrypt_page fscrypt_notsupp_encrypt_page -#define fscrypt_decrypt_page fscrypt_notsupp_decrypt_page -#define fscrypt_decrypt_bio_pages fscrypt_notsupp_decrypt_bio_pages -#define fscrypt_pullback_bio_page fscrypt_notsupp_pullback_bio_page -#define fscrypt_restore_control_page fscrypt_notsupp_restore_control_page -#define fscrypt_zeroout_range fscrypt_notsupp_zeroout_range -#define fscrypt_process_policy fscrypt_notsupp_process_policy -#define fscrypt_get_policy fscrypt_notsupp_get_policy -#define fscrypt_has_permitted_context fscrypt_notsupp_has_permitted_context -#define fscrypt_inherit_context fscrypt_notsupp_inherit_context -#define fscrypt_get_encryption_info fscrypt_notsupp_get_encryption_info -#define fscrypt_put_encryption_info fscrypt_notsupp_put_encryption_info -#define fscrypt_setup_filename fscrypt_notsupp_setup_filename -#define fscrypt_free_filename fscrypt_notsupp_free_filename -#define fscrypt_fname_encrypted_size fscrypt_notsupp_fname_encrypted_size -#define fscrypt_fname_alloc_buffer fscrypt_notsupp_fname_alloc_buffer -#define fscrypt_fname_free_buffer fscrypt_notsupp_fname_free_buffer -#define fscrypt_fname_disk_to_usr fscrypt_notsupp_fname_disk_to_usr -#define fscrypt_fname_usr_to_disk fscrypt_notsupp_fname_usr_to_disk -#endif - -/* dir.c */ -extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *, - struct file *, - struct ext4_dir_entry_2 *, - struct buffer_head *, char *, int, - unsigned int); -#define ext4_check_dir_entry(dir, filp, de, bh, buf, size, offset) \ - unlikely(__ext4_check_dir_entry(__func__, __LINE__, (dir), (filp), \ - (de), (bh), (buf), (size), (offset))) -extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash, - __u32 minor_hash, - struct ext4_dir_entry_2 *dirent, - struct fscrypt_str *ent_name); -extern void ext4_htree_free_dir_info(struct dir_private_info *p); -extern int ext4_find_dest_de(struct inode *dir, struct inode *inode, - struct buffer_head *bh, - void *buf, int buf_size, - struct ext4_filename *fname, - struct ext4_dir_entry_2 **dest_de); -int ext4_insert_dentry(struct inode *dir, - struct inode *inode, - struct ext4_dir_entry_2 *de, - int buf_size, - struct ext4_filename *fname); -static inline void ext4_update_dx_flag(struct inode *inode) -{ - if (!ext4_has_feature_dir_index(inode->i_sb)) - ext4_clear_inode_flag(inode, EXT4_INODE_INDEX); -} -static unsigned char ext4_filetype_table[] = { - DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK -}; - -static inline unsigned char get_dtype(struct super_block *sb, int filetype) -{ - if (!ext4_has_feature_filetype(sb) || filetype >= EXT4_FT_MAX) - return DT_UNKNOWN; - - return ext4_filetype_table[filetype]; -} -extern int ext4_check_all_de(struct inode *dir, struct buffer_head *bh, - void *buf, int buf_size); - -/* fsync.c */ -extern int ext4_sync_file(struct file *, loff_t, loff_t, int); - -/* hash.c */ -extern int ext4fs_dirhash(const char *name, int len, struct - dx_hash_info *hinfo); - -/* ialloc.c */ -extern struct inode *__ext4_new_inode(handle_t *, struct inode *, umode_t, - const struct qstr *qstr, __u32 goal, - uid_t *owner, int handle_type, - unsigned int line_no, int nblocks); - -#define ext4_new_inode(handle, dir, mode, qstr, goal, owner) \ - __ext4_new_inode((handle), (dir), (mode), (qstr), (goal), (owner), \ - 0, 0, 0) -#define ext4_new_inode_start_handle(dir, mode, qstr, goal, owner, \ - type, nblocks) \ - __ext4_new_inode(NULL, (dir), (mode), (qstr), (goal), (owner), \ - (type), __LINE__, (nblocks)) - - -extern void ext4_free_inode(handle_t *, struct inode *); -extern struct inode * ext4_orphan_get(struct super_block *, unsigned long); -extern unsigned long ext4_count_free_inodes(struct super_block *); -extern unsigned long ext4_count_dirs(struct super_block *); -extern void ext4_check_inodes_bitmap(struct super_block *); -extern void ext4_mark_bitmap_end(int start_bit, int end_bit, char *bitmap); -extern int ext4_init_inode_table(struct super_block *sb, - ext4_group_t group, int barrier); -extern void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate); - -/* mballoc.c */ -extern const struct file_operations ext4_seq_mb_groups_fops; -extern long ext4_mb_stats; -extern long ext4_mb_max_to_scan; -extern int ext4_mb_init(struct super_block *); -extern int ext4_mb_release(struct super_block *); -extern ext4_fsblk_t ext4_mb_new_blocks(handle_t *, - struct ext4_allocation_request *, int *); -extern int ext4_mb_reserve_blocks(struct super_block *, int); -extern void ext4_discard_preallocations(struct inode *); -extern int __init ext4_init_mballoc(void); -extern void ext4_exit_mballoc(void); -extern void ext4_free_blocks(handle_t *handle, struct inode *inode, - struct buffer_head *bh, ext4_fsblk_t block, - unsigned long count, int flags); -extern int ext4_mb_alloc_groupinfo(struct super_block *sb, - ext4_group_t ngroups); -extern int ext4_mb_add_groupinfo(struct super_block *sb, - ext4_group_t i, struct ext4_group_desc *desc); -extern int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, - ext4_fsblk_t block, unsigned long count); -extern int ext4_trim_fs(struct super_block *, struct fstrim_range *); - -/* inode.c */ -int ext4_inode_is_fast_symlink(struct inode *inode); -struct buffer_head *ext4_getblk(handle_t *, struct inode *, ext4_lblk_t, int); -struct buffer_head *ext4_bread(handle_t *, struct inode *, ext4_lblk_t, int); -int ext4_get_block_unwritten(struct inode *inode, sector_t iblock, - struct buffer_head *bh_result, int create); -int ext4_dax_get_block(struct inode *inode, sector_t iblock, - struct buffer_head *bh_result, int create); -int ext4_get_block(struct inode *inode, sector_t iblock, - struct buffer_head *bh_result, int create); -int ext4_dio_get_block(struct inode *inode, sector_t iblock, - struct buffer_head *bh_result, int create); -int ext4_da_get_block_prep(struct inode *inode, sector_t iblock, - struct buffer_head *bh, int create); -int ext4_walk_page_buffers(handle_t *handle, - struct buffer_head *head, - unsigned from, - unsigned to, - int *partial, - int (*fn)(handle_t *handle, - struct buffer_head *bh)); -int do_journal_get_write_access(handle_t *handle, - struct buffer_head *bh); -#define FALL_BACK_TO_NONDELALLOC 1 -#define CONVERT_INLINE_DATA 2 - -extern struct inode *ext4_iget(struct super_block *, unsigned long); -extern struct inode *ext4_iget_normal(struct super_block *, unsigned long); -extern int ext4_write_inode(struct inode *, struct writeback_control *); -extern int ext4_setattr(struct dentry *, struct iattr *); -extern int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry, - struct kstat *stat); -extern void ext4_evict_inode(struct inode *); -extern void ext4_clear_inode(struct inode *); -extern int ext4_sync_inode(handle_t *, struct inode *); -extern void ext4_dirty_inode(struct inode *, int); -extern int ext4_change_inode_journal_flag(struct inode *, int); -extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *); -extern int ext4_inode_attach_jinode(struct inode *inode); -extern int ext4_can_truncate(struct inode *inode); -extern void ext4_truncate(struct inode *); -extern int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length); -extern int ext4_truncate_restart_trans(handle_t *, struct inode *, int nblocks); -extern void ext4_set_inode_flags(struct inode *); -extern void ext4_get_inode_flags(struct ext4_inode_info *); -extern int ext4_alloc_da_blocks(struct inode *inode); -extern void ext4_set_aops(struct inode *inode); -extern int ext4_writepage_trans_blocks(struct inode *); -extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks); -extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode, - loff_t lstart, loff_t lend); -extern int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); -extern int ext4_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf); -extern qsize_t *ext4_get_reserved_space(struct inode *inode); -extern int ext4_get_projid(struct inode *inode, kprojid_t *projid); -extern void ext4_da_update_reserve_space(struct inode *inode, - int used, int quota_claim); -extern int ext4_issue_zeroout(struct inode *inode, ext4_lblk_t lblk, - ext4_fsblk_t pblk, ext4_lblk_t len); -extern int ext4_get_next_extent(struct inode *inode, ext4_lblk_t lblk, - unsigned int map_len, - struct extent_status *result); - -/* indirect.c */ -extern int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, - struct ext4_map_blocks *map, int flags); -extern int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock); -extern int ext4_ind_trans_blocks(struct inode *inode, int nrblocks); -extern void ext4_ind_truncate(handle_t *, struct inode *inode); -extern int ext4_ind_remove_space(handle_t *handle, struct inode *inode, - ext4_lblk_t start, ext4_lblk_t end); - -/* ioctl.c */ -extern long ext4_ioctl(struct file *, unsigned int, unsigned long); -extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long); - -/* migrate.c */ -extern int ext4_ext_migrate(struct inode *); -extern int ext4_ind_migrate(struct inode *inode); - -/* namei.c */ -extern int ext4_dirent_csum_verify(struct inode *inode, - struct ext4_dir_entry *dirent); -extern int ext4_orphan_add(handle_t *, struct inode *); -extern int ext4_orphan_del(handle_t *, struct inode *); -extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash, - __u32 start_minor_hash, __u32 *next_hash); -extern int ext4_search_dir(struct buffer_head *bh, - char *search_buf, - int buf_size, - struct inode *dir, - struct ext4_filename *fname, - const struct qstr *d_name, - unsigned int offset, - struct ext4_dir_entry_2 **res_dir); -extern int ext4_generic_delete_entry(handle_t *handle, - struct inode *dir, - struct ext4_dir_entry_2 *de_del, - struct buffer_head *bh, - void *entry_buf, - int buf_size, - int csum_size); -extern bool ext4_empty_dir(struct inode *inode); - -/* resize.c */ -extern int ext4_group_add(struct super_block *sb, - struct ext4_new_group_data *input); -extern int ext4_group_extend(struct super_block *sb, - struct ext4_super_block *es, - ext4_fsblk_t n_blocks_count); -extern int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count); - -/* super.c */ -extern int ext4_seq_options_show(struct seq_file *seq, void *offset); -extern int ext4_calculate_overhead(struct super_block *sb); -extern void ext4_superblock_csum_set(struct super_block *sb); -extern void *ext4_kvmalloc(size_t size, gfp_t flags); -extern void *ext4_kvzalloc(size_t size, gfp_t flags); -extern int ext4_alloc_flex_bg_array(struct super_block *sb, - ext4_group_t ngroup); -extern const char *ext4_decode_error(struct super_block *sb, int errno, - char nbuf[16]); - -extern __printf(4, 5) -void __ext4_error(struct super_block *, const char *, unsigned int, - const char *, ...); -extern __printf(5, 6) -void __ext4_error_inode(struct inode *, const char *, unsigned int, ext4_fsblk_t, - const char *, ...); -extern __printf(5, 6) -void __ext4_error_file(struct file *, const char *, unsigned int, ext4_fsblk_t, - const char *, ...); -extern void __ext4_std_error(struct super_block *, const char *, - unsigned int, int); -extern __printf(4, 5) -void __ext4_abort(struct super_block *, const char *, unsigned int, - const char *, ...); -extern __printf(4, 5) -void __ext4_warning(struct super_block *, const char *, unsigned int, - const char *, ...); -extern __printf(4, 5) -void __ext4_warning_inode(const struct inode *inode, const char *function, - unsigned int line, const char *fmt, ...); -extern __printf(3, 4) -void __ext4_msg(struct super_block *, const char *, const char *, ...); -extern void __dump_mmp_msg(struct super_block *, struct mmp_struct *mmp, - const char *, unsigned int, const char *); -extern __printf(7, 8) -void __ext4_grp_locked_error(const char *, unsigned int, - struct super_block *, ext4_group_t, - unsigned long, ext4_fsblk_t, - const char *, ...); - -#define EXT4_ERROR_INODE(inode, fmt, a...) \ - ext4_error_inode((inode), __func__, __LINE__, 0, (fmt), ## a) - -#define EXT4_ERROR_INODE_BLOCK(inode, block, fmt, a...) \ - ext4_error_inode((inode), __func__, __LINE__, (block), (fmt), ## a) - -#define EXT4_ERROR_FILE(file, block, fmt, a...) \ - ext4_error_file((file), __func__, __LINE__, (block), (fmt), ## a) - -#ifdef CONFIG_PRINTK - -#define ext4_error_inode(inode, func, line, block, fmt, ...) \ - __ext4_error_inode(inode, func, line, block, fmt, ##__VA_ARGS__) -#define ext4_error_file(file, func, line, block, fmt, ...) \ - __ext4_error_file(file, func, line, block, fmt, ##__VA_ARGS__) -#define ext4_error(sb, fmt, ...) \ - __ext4_error(sb, __func__, __LINE__, fmt, ##__VA_ARGS__) -#define ext4_abort(sb, fmt, ...) \ - __ext4_abort(sb, __func__, __LINE__, fmt, ##__VA_ARGS__) -#define ext4_warning(sb, fmt, ...) \ - __ext4_warning(sb, __func__, __LINE__, fmt, ##__VA_ARGS__) -#define ext4_warning_inode(inode, fmt, ...) \ - __ext4_warning_inode(inode, __func__, __LINE__, fmt, ##__VA_ARGS__) -#define ext4_msg(sb, level, fmt, ...) \ - __ext4_msg(sb, level, fmt, ##__VA_ARGS__) -#define dump_mmp_msg(sb, mmp, msg) \ - __dump_mmp_msg(sb, mmp, __func__, __LINE__, msg) -#define ext4_grp_locked_error(sb, grp, ino, block, fmt, ...) \ - __ext4_grp_locked_error(__func__, __LINE__, sb, grp, ino, block, \ - fmt, ##__VA_ARGS__) - -#else - -#define ext4_error_inode(inode, func, line, block, fmt, ...) \ -do { \ - no_printk(fmt, ##__VA_ARGS__); \ - __ext4_error_inode(inode, "", 0, block, " "); \ -} while (0) -#define ext4_error_file(file, func, line, block, fmt, ...) \ -do { \ - no_printk(fmt, ##__VA_ARGS__); \ - __ext4_error_file(file, "", 0, block, " "); \ -} while (0) -#define ext4_error(sb, fmt, ...) \ -do { \ - no_printk(fmt, ##__VA_ARGS__); \ - __ext4_error(sb, "", 0, " "); \ -} while (0) -#define ext4_abort(sb, fmt, ...) \ -do { \ - no_printk(fmt, ##__VA_ARGS__); \ - __ext4_abort(sb, "", 0, " "); \ -} while (0) -#define ext4_warning(sb, fmt, ...) \ -do { \ - no_printk(fmt, ##__VA_ARGS__); \ - __ext4_warning(sb, "", 0, " "); \ -} while (0) -#define ext4_warning_inode(inode, fmt, ...) \ -do { \ - no_printk(fmt, ##__VA_ARGS__); \ - __ext4_warning_inode(inode, "", 0, " "); \ -} while (0) -#define ext4_msg(sb, level, fmt, ...) \ -do { \ - no_printk(fmt, ##__VA_ARGS__); \ - __ext4_msg(sb, "", " "); \ -} while (0) -#define dump_mmp_msg(sb, mmp, msg) \ - __dump_mmp_msg(sb, mmp, "", 0, "") -#define ext4_grp_locked_error(sb, grp, ino, block, fmt, ...) \ -do { \ - no_printk(fmt, ##__VA_ARGS__); \ - __ext4_grp_locked_error("", 0, sb, grp, ino, block, " "); \ -} while (0) - -#endif - -extern void ext4_update_dynamic_rev(struct super_block *sb); -extern int ext4_update_compat_feature(handle_t *handle, struct super_block *sb, - __u32 compat); -extern int ext4_update_rocompat_feature(handle_t *handle, - struct super_block *sb, __u32 rocompat); -extern int ext4_update_incompat_feature(handle_t *handle, - struct super_block *sb, __u32 incompat); -extern ext4_fsblk_t ext4_block_bitmap(struct super_block *sb, - struct ext4_group_desc *bg); -extern ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb, - struct ext4_group_desc *bg); -extern ext4_fsblk_t ext4_inode_table(struct super_block *sb, - struct ext4_group_desc *bg); -extern __u32 ext4_free_group_clusters(struct super_block *sb, - struct ext4_group_desc *bg); -extern __u32 ext4_free_inodes_count(struct super_block *sb, - struct ext4_group_desc *bg); -extern __u32 ext4_used_dirs_count(struct super_block *sb, - struct ext4_group_desc *bg); -extern __u32 ext4_itable_unused_count(struct super_block *sb, - struct ext4_group_desc *bg); -extern void ext4_block_bitmap_set(struct super_block *sb, - struct ext4_group_desc *bg, ext4_fsblk_t blk); -extern void ext4_inode_bitmap_set(struct super_block *sb, - struct ext4_group_desc *bg, ext4_fsblk_t blk); -extern void ext4_inode_table_set(struct super_block *sb, - struct ext4_group_desc *bg, ext4_fsblk_t blk); -extern void ext4_free_group_clusters_set(struct super_block *sb, - struct ext4_group_desc *bg, - __u32 count); -extern void ext4_free_inodes_set(struct super_block *sb, - struct ext4_group_desc *bg, __u32 count); -extern void ext4_used_dirs_set(struct super_block *sb, - struct ext4_group_desc *bg, __u32 count); -extern void ext4_itable_unused_set(struct super_block *sb, - struct ext4_group_desc *bg, __u32 count); -extern int ext4_group_desc_csum_verify(struct super_block *sb, __u32 group, - struct ext4_group_desc *gdp); -extern void ext4_group_desc_csum_set(struct super_block *sb, __u32 group, - struct ext4_group_desc *gdp); -extern int ext4_register_li_request(struct super_block *sb, - ext4_group_t first_not_zeroed); - -static inline int ext4_has_group_desc_csum(struct super_block *sb) -{ - return ext4_has_feature_gdt_csum(sb) || - EXT4_SB(sb)->s_chksum_driver != NULL; -} - -static inline int ext4_has_metadata_csum(struct super_block *sb) -{ - WARN_ON_ONCE(ext4_has_feature_metadata_csum(sb) && - !EXT4_SB(sb)->s_chksum_driver); - - return (EXT4_SB(sb)->s_chksum_driver != NULL); -} -static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es) -{ - return ((ext4_fsblk_t)le32_to_cpu(es->s_blocks_count_hi) << 32) | - le32_to_cpu(es->s_blocks_count_lo); -} - -static inline ext4_fsblk_t ext4_r_blocks_count(struct ext4_super_block *es) -{ - return ((ext4_fsblk_t)le32_to_cpu(es->s_r_blocks_count_hi) << 32) | - le32_to_cpu(es->s_r_blocks_count_lo); -} - -static inline ext4_fsblk_t ext4_free_blocks_count(struct ext4_super_block *es) -{ - return ((ext4_fsblk_t)le32_to_cpu(es->s_free_blocks_count_hi) << 32) | - le32_to_cpu(es->s_free_blocks_count_lo); -} - -static inline void ext4_blocks_count_set(struct ext4_super_block *es, - ext4_fsblk_t blk) -{ - es->s_blocks_count_lo = cpu_to_le32((u32)blk); - es->s_blocks_count_hi = cpu_to_le32(blk >> 32); -} - -static inline void ext4_free_blocks_count_set(struct ext4_super_block *es, - ext4_fsblk_t blk) -{ - es->s_free_blocks_count_lo = cpu_to_le32((u32)blk); - es->s_free_blocks_count_hi = cpu_to_le32(blk >> 32); -} - -static inline void ext4_r_blocks_count_set(struct ext4_super_block *es, - ext4_fsblk_t blk) -{ - es->s_r_blocks_count_lo = cpu_to_le32((u32)blk); - es->s_r_blocks_count_hi = cpu_to_le32(blk >> 32); -} - -static inline loff_t ext4_isize(struct ext4_inode *raw_inode) -{ - if (S_ISREG(le16_to_cpu(raw_inode->i_mode))) - return ((loff_t)le32_to_cpu(raw_inode->i_size_high) << 32) | - le32_to_cpu(raw_inode->i_size_lo); - else - return (loff_t) le32_to_cpu(raw_inode->i_size_lo); -} - -static inline void ext4_isize_set(struct ext4_inode *raw_inode, loff_t i_size) -{ - raw_inode->i_size_lo = cpu_to_le32(i_size); - raw_inode->i_size_high = cpu_to_le32(i_size >> 32); -} - -static inline -struct ext4_group_info *ext4_get_group_info(struct super_block *sb, - ext4_group_t group) -{ - struct ext4_group_info ***grp_info; - long indexv, indexh; - BUG_ON(group >= EXT4_SB(sb)->s_groups_count); - grp_info = EXT4_SB(sb)->s_group_info; - indexv = group >> (EXT4_DESC_PER_BLOCK_BITS(sb)); - indexh = group & ((EXT4_DESC_PER_BLOCK(sb)) - 1); - return grp_info[indexv][indexh]; -} - -/* - * Reading s_groups_count requires using smp_rmb() afterwards. See - * the locking protocol documented in the comments of ext4_group_add() - * in resize.c - */ -static inline ext4_group_t ext4_get_groups_count(struct super_block *sb) -{ - ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count; - - smp_rmb(); - return ngroups; -} - -static inline ext4_group_t ext4_flex_group(struct ext4_sb_info *sbi, - ext4_group_t block_group) -{ - return block_group >> sbi->s_log_groups_per_flex; -} - -static inline unsigned int ext4_flex_bg_size(struct ext4_sb_info *sbi) -{ - return 1 << sbi->s_log_groups_per_flex; -} - -#define ext4_std_error(sb, errno) \ -do { \ - if ((errno)) \ - __ext4_std_error((sb), __func__, __LINE__, (errno)); \ -} while (0) - -#ifdef CONFIG_SMP -/* Each CPU can accumulate percpu_counter_batch clusters in their local - * counters. So we need to make sure we have free clusters more - * than percpu_counter_batch * nr_cpu_ids. Also add a window of 4 times. - */ -#define EXT4_FREECLUSTERS_WATERMARK (4 * (percpu_counter_batch * nr_cpu_ids)) -#else -#define EXT4_FREECLUSTERS_WATERMARK 0 -#endif - -/* Update i_disksize. Requires i_mutex to avoid races with truncate */ -static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize) -{ - WARN_ON_ONCE(S_ISREG(inode->i_mode) && - !inode_is_locked(inode)); - down_write(&EXT4_I(inode)->i_data_sem); - if (newsize > EXT4_I(inode)->i_disksize) - EXT4_I(inode)->i_disksize = newsize; - up_write(&EXT4_I(inode)->i_data_sem); -} - -/* Update i_size, i_disksize. Requires i_mutex to avoid races with truncate */ -static inline int ext4_update_inode_size(struct inode *inode, loff_t newsize) -{ - int changed = 0; - - if (newsize > inode->i_size) { - i_size_write(inode, newsize); - changed = 1; - } - if (newsize > EXT4_I(inode)->i_disksize) { - ext4_update_i_disksize(inode, newsize); - changed |= 2; - } - return changed; -} - -int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset, - loff_t len); - -struct ext4_group_info { - unsigned long bb_state; - struct rb_root bb_free_root; - ext4_grpblk_t bb_first_free; /* first free block */ - ext4_grpblk_t bb_free; /* total free blocks */ - ext4_grpblk_t bb_fragments; /* nr of freespace fragments */ - ext4_grpblk_t bb_largest_free_order;/* order of largest frag in BG */ - struct list_head bb_prealloc_list; -#ifdef DOUBLE_CHECK - void *bb_bitmap; -#endif - struct rw_semaphore alloc_sem; - ext4_grpblk_t bb_counters[]; /* Nr of free power-of-two-block - * regions, index is order. - * bb_counters[3] = 5 means - * 5 free 8-block regions. */ -}; - -#define EXT4_GROUP_INFO_NEED_INIT_BIT 0 -#define EXT4_GROUP_INFO_WAS_TRIMMED_BIT 1 -#define EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT 2 -#define EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT 3 - -#define EXT4_MB_GRP_NEED_INIT(grp) \ - (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state))) -#define EXT4_MB_GRP_BBITMAP_CORRUPT(grp) \ - (test_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &((grp)->bb_state))) -#define EXT4_MB_GRP_IBITMAP_CORRUPT(grp) \ - (test_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &((grp)->bb_state))) - -#define EXT4_MB_GRP_WAS_TRIMMED(grp) \ - (test_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state))) -#define EXT4_MB_GRP_SET_TRIMMED(grp) \ - (set_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state))) -#define EXT4_MB_GRP_CLEAR_TRIMMED(grp) \ - (clear_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state))) - -#define EXT4_MAX_CONTENTION 8 -#define EXT4_CONTENTION_THRESHOLD 2 - -static inline spinlock_t *ext4_group_lock_ptr(struct super_block *sb, - ext4_group_t group) -{ - return bgl_lock_ptr(EXT4_SB(sb)->s_blockgroup_lock, group); -} - -/* - * Returns true if the filesystem is busy enough that attempts to - * access the block group locks has run into contention. - */ -static inline int ext4_fs_is_busy(struct ext4_sb_info *sbi) -{ - return (atomic_read(&sbi->s_lock_busy) > EXT4_CONTENTION_THRESHOLD); -} - -static inline void ext4_lock_group(struct super_block *sb, ext4_group_t group) -{ - spinlock_t *lock = ext4_group_lock_ptr(sb, group); - if (spin_trylock(lock)) - /* - * We're able to grab the lock right away, so drop the - * lock contention counter. - */ - atomic_add_unless(&EXT4_SB(sb)->s_lock_busy, -1, 0); - else { - /* - * The lock is busy, so bump the contention counter, - * and then wait on the spin lock. - */ - atomic_add_unless(&EXT4_SB(sb)->s_lock_busy, 1, - EXT4_MAX_CONTENTION); - spin_lock(lock); - } -} - -static inline void ext4_unlock_group(struct super_block *sb, - ext4_group_t group) -{ - spin_unlock(ext4_group_lock_ptr(sb, group)); -} - -/* - * Block validity checking - */ -#define ext4_check_indirect_blockref(inode, bh) \ - ext4_check_blockref(__func__, __LINE__, inode, \ - (__le32 *)(bh)->b_data, \ - EXT4_ADDR_PER_BLOCK((inode)->i_sb)) - -#define ext4_ind_check_inode(inode) \ - ext4_check_blockref(__func__, __LINE__, inode, \ - EXT4_I(inode)->i_data, \ - EXT4_NDIR_BLOCKS) - -/* - * Inodes and files operations - */ - -/* dir.c */ -extern const struct file_operations ext4_dir_operations; - -/* file.c */ -extern const struct inode_operations ext4_file_inode_operations; -extern const struct file_operations ext4_file_operations; -extern loff_t ext4_llseek(struct file *file, loff_t offset, int origin); - -/* inline.c */ -extern int ext4_get_max_inline_size(struct inode *inode); -extern int ext4_find_inline_data_nolock(struct inode *inode); -extern int ext4_init_inline_data(handle_t *handle, struct inode *inode, - unsigned int len); -extern int ext4_destroy_inline_data(handle_t *handle, struct inode *inode); - -extern int ext4_readpage_inline(struct inode *inode, struct page *page); -extern int ext4_try_to_write_inline_data(struct address_space *mapping, - struct inode *inode, - loff_t pos, unsigned len, - unsigned flags, - struct page **pagep); -extern int ext4_write_inline_data_end(struct inode *inode, - loff_t pos, unsigned len, - unsigned copied, - struct page *page); -extern struct buffer_head * -ext4_journalled_write_inline_data(struct inode *inode, - unsigned len, - struct page *page); -extern int ext4_da_write_inline_data_begin(struct address_space *mapping, - struct inode *inode, - loff_t pos, unsigned len, - unsigned flags, - struct page **pagep, - void **fsdata); -extern int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, - unsigned len, unsigned copied, - struct page *page); -extern int ext4_try_add_inline_entry(handle_t *handle, - struct ext4_filename *fname, - struct inode *dir, struct inode *inode); -extern int ext4_try_create_inline_dir(handle_t *handle, - struct inode *parent, - struct inode *inode); -extern int ext4_read_inline_dir(struct file *filp, - struct dir_context *ctx, - int *has_inline_data); -extern int htree_inlinedir_to_tree(struct file *dir_file, - struct inode *dir, ext4_lblk_t block, - struct dx_hash_info *hinfo, - __u32 start_hash, __u32 start_minor_hash, - int *has_inline_data); -extern struct buffer_head *ext4_find_inline_entry(struct inode *dir, - struct ext4_filename *fname, - const struct qstr *d_name, - struct ext4_dir_entry_2 **res_dir, - int *has_inline_data); -extern int ext4_delete_inline_entry(handle_t *handle, - struct inode *dir, - struct ext4_dir_entry_2 *de_del, - struct buffer_head *bh, - int *has_inline_data); -extern bool empty_inline_dir(struct inode *dir, int *has_inline_data); -extern struct buffer_head *ext4_get_first_inline_block(struct inode *inode, - struct ext4_dir_entry_2 **parent_de, - int *retval); -extern int ext4_inline_data_fiemap(struct inode *inode, - struct fiemap_extent_info *fieinfo, - int *has_inline, __u64 start, __u64 len); -extern int ext4_try_to_evict_inline_data(handle_t *handle, - struct inode *inode, - int needed); -extern void ext4_inline_data_truncate(struct inode *inode, int *has_inline); - -extern int ext4_convert_inline_data(struct inode *inode); - -static inline int ext4_has_inline_data(struct inode *inode) -{ - return ext4_test_inode_flag(inode, EXT4_INODE_INLINE_DATA) && - EXT4_I(inode)->i_inline_off; -} - -/* namei.c */ -extern const struct inode_operations ext4_dir_inode_operations; -extern const struct inode_operations ext4_special_inode_operations; -extern struct dentry *ext4_get_parent(struct dentry *child); -extern struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode, - struct ext4_dir_entry_2 *de, - int blocksize, int csum_size, - unsigned int parent_ino, int dotdot_real_len); -extern void initialize_dirent_tail(struct ext4_dir_entry_tail *t, - unsigned int blocksize); -extern int ext4_handle_dirty_dirent_node(handle_t *handle, - struct inode *inode, - struct buffer_head *bh); -#define S_SHIFT 12 -static unsigned char ext4_type_by_mode[S_IFMT >> S_SHIFT] = { - [S_IFREG >> S_SHIFT] = EXT4_FT_REG_FILE, - [S_IFDIR >> S_SHIFT] = EXT4_FT_DIR, - [S_IFCHR >> S_SHIFT] = EXT4_FT_CHRDEV, - [S_IFBLK >> S_SHIFT] = EXT4_FT_BLKDEV, - [S_IFIFO >> S_SHIFT] = EXT4_FT_FIFO, - [S_IFSOCK >> S_SHIFT] = EXT4_FT_SOCK, - [S_IFLNK >> S_SHIFT] = EXT4_FT_SYMLINK, -}; - -static inline void ext4_set_de_type(struct super_block *sb, - struct ext4_dir_entry_2 *de, - umode_t mode) { - if (ext4_has_feature_filetype(sb)) - de->file_type = ext4_type_by_mode[(mode & S_IFMT)>>S_SHIFT]; -} - -/* readpages.c */ -extern int ext4_mpage_readpages(struct address_space *mapping, - struct list_head *pages, struct page *page, - unsigned nr_pages); - -/* symlink.c */ -extern const struct inode_operations ext4_encrypted_symlink_inode_operations; -extern const struct inode_operations ext4_symlink_inode_operations; -extern const struct inode_operations ext4_fast_symlink_inode_operations; - -/* sysfs.c */ -extern int ext4_register_sysfs(struct super_block *sb); -extern void ext4_unregister_sysfs(struct super_block *sb); -extern int __init ext4_init_sysfs(void); -extern void ext4_exit_sysfs(void); - -/* block_validity */ -extern void ext4_release_system_zone(struct super_block *sb); -extern int ext4_setup_system_zone(struct super_block *sb); -extern int __init ext4_init_system_zone(void); -extern void ext4_exit_system_zone(void); -extern int ext4_data_block_valid(struct ext4_sb_info *sbi, - ext4_fsblk_t start_blk, - unsigned int count); -extern int ext4_check_blockref(const char *, unsigned int, - struct inode *, __le32 *, unsigned int); - -/* extents.c */ -struct ext4_ext_path; -struct ext4_extent; - -/* - * Maximum number of logical blocks in a file; ext4_extent's ee_block is - * __le32. - */ -#define EXT_MAX_BLOCKS 0xffffffff - -extern int ext4_ext_tree_init(handle_t *handle, struct inode *); -extern int ext4_ext_writepage_trans_blocks(struct inode *, int); -extern int ext4_ext_index_trans_blocks(struct inode *inode, int extents); -extern int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, - struct ext4_map_blocks *map, int flags); -extern void ext4_ext_truncate(handle_t *, struct inode *); -extern int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, - ext4_lblk_t end); -extern void ext4_ext_init(struct super_block *); -extern void ext4_ext_release(struct super_block *); -extern long ext4_fallocate(struct file *file, int mode, loff_t offset, - loff_t len); -extern int ext4_convert_unwritten_extents(handle_t *handle, struct inode *inode, - loff_t offset, ssize_t len); -extern int ext4_map_blocks(handle_t *handle, struct inode *inode, - struct ext4_map_blocks *map, int flags); -extern int ext4_ext_calc_metadata_amount(struct inode *inode, - ext4_lblk_t lblocks); -extern int ext4_ext_calc_credits_for_single_extent(struct inode *inode, - int num, - struct ext4_ext_path *path); -extern int ext4_can_extents_be_merged(struct inode *inode, - struct ext4_extent *ex1, - struct ext4_extent *ex2); -extern int ext4_ext_insert_extent(handle_t *, struct inode *, - struct ext4_ext_path **, - struct ext4_extent *, int); -extern struct ext4_ext_path *ext4_find_extent(struct inode *, ext4_lblk_t, - struct ext4_ext_path **, - int flags); -extern void ext4_ext_drop_refs(struct ext4_ext_path *); -extern int ext4_ext_check_inode(struct inode *inode); -extern int ext4_find_delalloc_range(struct inode *inode, - ext4_lblk_t lblk_start, - ext4_lblk_t lblk_end); -extern int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk); -extern ext4_lblk_t ext4_ext_next_allocated_block(struct ext4_ext_path *path); -extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, - __u64 start, __u64 len); -extern int ext4_ext_precache(struct inode *inode); -extern int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len); -extern int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len); -extern int ext4_swap_extents(handle_t *handle, struct inode *inode1, - struct inode *inode2, ext4_lblk_t lblk1, - ext4_lblk_t lblk2, ext4_lblk_t count, - int mark_unwritten,int *err); - -/* move_extent.c */ -extern void ext4_double_down_write_data_sem(struct inode *first, - struct inode *second); -extern void ext4_double_up_write_data_sem(struct inode *orig_inode, - struct inode *donor_inode); -extern int ext4_move_extents(struct file *o_filp, struct file *d_filp, - __u64 start_orig, __u64 start_donor, - __u64 len, __u64 *moved_len); - -/* page-io.c */ -extern int __init ext4_init_pageio(void); -extern void ext4_exit_pageio(void); -extern ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags); -extern ext4_io_end_t *ext4_get_io_end(ext4_io_end_t *io_end); -extern int ext4_put_io_end(ext4_io_end_t *io_end); -extern void ext4_put_io_end_defer(ext4_io_end_t *io_end); -extern void ext4_io_submit_init(struct ext4_io_submit *io, - struct writeback_control *wbc); -extern void ext4_end_io_rsv_work(struct work_struct *work); -extern void ext4_io_submit(struct ext4_io_submit *io); -extern int ext4_bio_write_page(struct ext4_io_submit *io, - struct page *page, - int len, - struct writeback_control *wbc, - bool keep_towrite); - -/* mmp.c */ -extern int ext4_multi_mount_protect(struct super_block *, ext4_fsblk_t); - -/* - * Add new method to test whether block and inode bitmaps are properly - * initialized. With uninit_bg reading the block from disk is not enough - * to mark the bitmap uptodate. We need to also zero-out the bitmap - */ -#define BH_BITMAP_UPTODATE BH_JBDPrivateStart - -static inline int bitmap_uptodate(struct buffer_head *bh) -{ - return (buffer_uptodate(bh) && - test_bit(BH_BITMAP_UPTODATE, &(bh)->b_state)); -} -static inline void set_bitmap_uptodate(struct buffer_head *bh) -{ - set_bit(BH_BITMAP_UPTODATE, &(bh)->b_state); -} - -/* - * Disable DIO read nolock optimization, so new dioreaders will be forced - * to grab i_mutex - */ -static inline void ext4_inode_block_unlocked_dio(struct inode *inode) -{ - ext4_set_inode_state(inode, EXT4_STATE_DIOREAD_LOCK); - smp_mb(); -} -static inline void ext4_inode_resume_unlocked_dio(struct inode *inode) -{ - smp_mb(); - ext4_clear_inode_state(inode, EXT4_STATE_DIOREAD_LOCK); -} - -#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1) - -/* For ioend & aio unwritten conversion wait queues */ -#define EXT4_WQ_HASH_SZ 37 -#define ext4_ioend_wq(v) (&ext4__ioend_wq[((unsigned long)(v)) %\ - EXT4_WQ_HASH_SZ]) -extern wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ]; - -#define EXT4_RESIZING 0 -extern int ext4_resize_begin(struct super_block *sb); -extern void ext4_resize_end(struct super_block *sb); - -static inline void ext4_set_io_unwritten_flag(struct inode *inode, - struct ext4_io_end *io_end) -{ - if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) { - io_end->flag |= EXT4_IO_END_UNWRITTEN; - atomic_inc(&EXT4_I(inode)->i_unwritten); - } -} - -static inline void ext4_clear_io_unwritten_flag(ext4_io_end_t *io_end) -{ - struct inode *inode = io_end->inode; - - if (io_end->flag & EXT4_IO_END_UNWRITTEN) { - io_end->flag &= ~EXT4_IO_END_UNWRITTEN; - /* Wake up anyone waiting on unwritten extent conversion */ - if (atomic_dec_and_test(&EXT4_I(inode)->i_unwritten)) - wake_up_all(ext4_ioend_wq(inode)); - } -} - -static inline bool ext4_aligned_io(struct inode *inode, loff_t off, loff_t len) -{ - int blksize = 1 << inode->i_blkbits; - - return IS_ALIGNED(off, blksize) && IS_ALIGNED(len, blksize); -} - -#endif /* __KERNEL__ */ - -#define EFSBADCRC EBADMSG /* Bad CRC detected */ -#define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ - -#endif /* _EXT4_H */ diff --git a/src/linux/fs/ext4/ext4_extents.h b/src/linux/fs/ext4/ext4_extents.h deleted file mode 100644 index 8ecf84b..0000000 --- a/src/linux/fs/ext4/ext4_extents.h +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright (c) 2003-2006, Cluster File Systems, Inc, info@clusterfs.com - * Written by Alex Tomas - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- - */ - -#ifndef _EXT4_EXTENTS -#define _EXT4_EXTENTS - -#include "ext4.h" - -/* - * With AGGRESSIVE_TEST defined, the capacity of index/leaf blocks - * becomes very small, so index split, in-depth growing and - * other hard changes happen much more often. - * This is for debug purposes only. - */ -#define AGGRESSIVE_TEST_ - -/* - * With EXTENTS_STATS defined, the number of blocks and extents - * are collected in the truncate path. They'll be shown at - * umount time. - */ -#define EXTENTS_STATS__ - -/* - * If CHECK_BINSEARCH is defined, then the results of the binary search - * will also be checked by linear search. - */ -#define CHECK_BINSEARCH__ - -/* - * If EXT_STATS is defined then stats numbers are collected. - * These number will be displayed at umount time. - */ -#define EXT_STATS_ - - -/* - * ext4_inode has i_block array (60 bytes total). - * The first 12 bytes store ext4_extent_header; - * the remainder stores an array of ext4_extent. - * For non-inode extent blocks, ext4_extent_tail - * follows the array. - */ - -/* - * This is the extent tail on-disk structure. - * All other extent structures are 12 bytes long. It turns out that - * block_size % 12 >= 4 for at least all powers of 2 greater than 512, which - * covers all valid ext4 block sizes. Therefore, this tail structure can be - * crammed into the end of the block without having to rebalance the tree. - */ -struct ext4_extent_tail { - __le32 et_checksum; /* crc32c(uuid+inum+extent_block) */ -}; - -/* - * This is the extent on-disk structure. - * It's used at the bottom of the tree. - */ -struct ext4_extent { - __le32 ee_block; /* first logical block extent covers */ - __le16 ee_len; /* number of blocks covered by extent */ - __le16 ee_start_hi; /* high 16 bits of physical block */ - __le32 ee_start_lo; /* low 32 bits of physical block */ -}; - -/* - * This is index on-disk structure. - * It's used at all the levels except the bottom. - */ -struct ext4_extent_idx { - __le32 ei_block; /* index covers logical blocks from 'block' */ - __le32 ei_leaf_lo; /* pointer to the physical block of the next * - * level. leaf or next index could be there */ - __le16 ei_leaf_hi; /* high 16 bits of physical block */ - __u16 ei_unused; -}; - -/* - * Each block (leaves and indexes), even inode-stored has header. - */ -struct ext4_extent_header { - __le16 eh_magic; /* probably will support different formats */ - __le16 eh_entries; /* number of valid entries */ - __le16 eh_max; /* capacity of store in entries */ - __le16 eh_depth; /* has tree real underlying blocks? */ - __le32 eh_generation; /* generation of the tree */ -}; - -#define EXT4_EXT_MAGIC cpu_to_le16(0xf30a) - -#define EXT4_EXTENT_TAIL_OFFSET(hdr) \ - (sizeof(struct ext4_extent_header) + \ - (sizeof(struct ext4_extent) * le16_to_cpu((hdr)->eh_max))) - -static inline struct ext4_extent_tail * -find_ext4_extent_tail(struct ext4_extent_header *eh) -{ - return (struct ext4_extent_tail *)(((void *)eh) + - EXT4_EXTENT_TAIL_OFFSET(eh)); -} - -/* - * Array of ext4_ext_path contains path to some extent. - * Creation/lookup routines use it for traversal/splitting/etc. - * Truncate uses it to simulate recursive walking. - */ -struct ext4_ext_path { - ext4_fsblk_t p_block; - __u16 p_depth; - __u16 p_maxdepth; - struct ext4_extent *p_ext; - struct ext4_extent_idx *p_idx; - struct ext4_extent_header *p_hdr; - struct buffer_head *p_bh; -}; - -/* - * structure for external API - */ - -/* - * EXT_INIT_MAX_LEN is the maximum number of blocks we can have in an - * initialized extent. This is 2^15 and not (2^16 - 1), since we use the - * MSB of ee_len field in the extent datastructure to signify if this - * particular extent is an initialized extent or an unwritten (i.e. - * preallocated). - * EXT_UNWRITTEN_MAX_LEN is the maximum number of blocks we can have in an - * unwritten extent. - * If ee_len is <= 0x8000, it is an initialized extent. Otherwise, it is an - * unwritten one. In other words, if MSB of ee_len is set, it is an - * unwritten extent with only one special scenario when ee_len = 0x8000. - * In this case we can not have an unwritten extent of zero length and - * thus we make it as a special case of initialized extent with 0x8000 length. - * This way we get better extent-to-group alignment for initialized extents. - * Hence, the maximum number of blocks we can have in an *initialized* - * extent is 2^15 (32768) and in an *unwritten* extent is 2^15-1 (32767). - */ -#define EXT_INIT_MAX_LEN (1UL << 15) -#define EXT_UNWRITTEN_MAX_LEN (EXT_INIT_MAX_LEN - 1) - - -#define EXT_FIRST_EXTENT(__hdr__) \ - ((struct ext4_extent *) (((char *) (__hdr__)) + \ - sizeof(struct ext4_extent_header))) -#define EXT_FIRST_INDEX(__hdr__) \ - ((struct ext4_extent_idx *) (((char *) (__hdr__)) + \ - sizeof(struct ext4_extent_header))) -#define EXT_HAS_FREE_INDEX(__path__) \ - (le16_to_cpu((__path__)->p_hdr->eh_entries) \ - < le16_to_cpu((__path__)->p_hdr->eh_max)) -#define EXT_LAST_EXTENT(__hdr__) \ - (EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1) -#define EXT_LAST_INDEX(__hdr__) \ - (EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_entries) - 1) -#define EXT_MAX_EXTENT(__hdr__) \ - (EXT_FIRST_EXTENT((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1) -#define EXT_MAX_INDEX(__hdr__) \ - (EXT_FIRST_INDEX((__hdr__)) + le16_to_cpu((__hdr__)->eh_max) - 1) - -static inline struct ext4_extent_header *ext_inode_hdr(struct inode *inode) -{ - return (struct ext4_extent_header *) EXT4_I(inode)->i_data; -} - -static inline struct ext4_extent_header *ext_block_hdr(struct buffer_head *bh) -{ - return (struct ext4_extent_header *) bh->b_data; -} - -static inline unsigned short ext_depth(struct inode *inode) -{ - return le16_to_cpu(ext_inode_hdr(inode)->eh_depth); -} - -static inline void ext4_ext_mark_unwritten(struct ext4_extent *ext) -{ - /* We can not have an unwritten extent of zero length! */ - BUG_ON((le16_to_cpu(ext->ee_len) & ~EXT_INIT_MAX_LEN) == 0); - ext->ee_len |= cpu_to_le16(EXT_INIT_MAX_LEN); -} - -static inline int ext4_ext_is_unwritten(struct ext4_extent *ext) -{ - /* Extent with ee_len of 0x8000 is treated as an initialized extent */ - return (le16_to_cpu(ext->ee_len) > EXT_INIT_MAX_LEN); -} - -static inline int ext4_ext_get_actual_len(struct ext4_extent *ext) -{ - return (le16_to_cpu(ext->ee_len) <= EXT_INIT_MAX_LEN ? - le16_to_cpu(ext->ee_len) : - (le16_to_cpu(ext->ee_len) - EXT_INIT_MAX_LEN)); -} - -static inline void ext4_ext_mark_initialized(struct ext4_extent *ext) -{ - ext->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ext)); -} - -/* - * ext4_ext_pblock: - * combine low and high parts of physical block number into ext4_fsblk_t - */ -static inline ext4_fsblk_t ext4_ext_pblock(struct ext4_extent *ex) -{ - ext4_fsblk_t block; - - block = le32_to_cpu(ex->ee_start_lo); - block |= ((ext4_fsblk_t) le16_to_cpu(ex->ee_start_hi) << 31) << 1; - return block; -} - -/* - * ext4_idx_pblock: - * combine low and high parts of a leaf physical block number into ext4_fsblk_t - */ -static inline ext4_fsblk_t ext4_idx_pblock(struct ext4_extent_idx *ix) -{ - ext4_fsblk_t block; - - block = le32_to_cpu(ix->ei_leaf_lo); - block |= ((ext4_fsblk_t) le16_to_cpu(ix->ei_leaf_hi) << 31) << 1; - return block; -} - -/* - * ext4_ext_store_pblock: - * stores a large physical block number into an extent struct, - * breaking it into parts - */ -static inline void ext4_ext_store_pblock(struct ext4_extent *ex, - ext4_fsblk_t pb) -{ - ex->ee_start_lo = cpu_to_le32((unsigned long) (pb & 0xffffffff)); - ex->ee_start_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & - 0xffff); -} - -/* - * ext4_idx_store_pblock: - * stores a large physical block number into an index struct, - * breaking it into parts - */ -static inline void ext4_idx_store_pblock(struct ext4_extent_idx *ix, - ext4_fsblk_t pb) -{ - ix->ei_leaf_lo = cpu_to_le32((unsigned long) (pb & 0xffffffff)); - ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & - 0xffff); -} - -#define ext4_ext_dirty(handle, inode, path) \ - __ext4_ext_dirty(__func__, __LINE__, (handle), (inode), (path)) -int __ext4_ext_dirty(const char *where, unsigned int line, handle_t *handle, - struct inode *inode, struct ext4_ext_path *path); - -#endif /* _EXT4_EXTENTS */ - diff --git a/src/linux/fs/ext4/ext4_jbd2.c b/src/linux/fs/ext4/ext4_jbd2.c deleted file mode 100644 index e770c1e..0000000 --- a/src/linux/fs/ext4/ext4_jbd2.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Interface between ext4 and JBD - */ - -#include "ext4_jbd2.h" - -#include - -/* Just increment the non-pointer handle value */ -static handle_t *ext4_get_nojournal(void) -{ - handle_t *handle = current->journal_info; - unsigned long ref_cnt = (unsigned long)handle; - - BUG_ON(ref_cnt >= EXT4_NOJOURNAL_MAX_REF_COUNT); - - ref_cnt++; - handle = (handle_t *)ref_cnt; - - current->journal_info = handle; - return handle; -} - - -/* Decrement the non-pointer handle value */ -static void ext4_put_nojournal(handle_t *handle) -{ - unsigned long ref_cnt = (unsigned long)handle; - - BUG_ON(ref_cnt == 0); - - ref_cnt--; - handle = (handle_t *)ref_cnt; - - current->journal_info = handle; -} - -/* - * Wrappers for jbd2_journal_start/end. - */ -static int ext4_journal_check_start(struct super_block *sb) -{ - journal_t *journal; - - might_sleep(); - if (sb->s_flags & MS_RDONLY) - return -EROFS; - WARN_ON(sb->s_writers.frozen == SB_FREEZE_COMPLETE); - journal = EXT4_SB(sb)->s_journal; - /* - * Special case here: if the journal has aborted behind our - * backs (eg. EIO in the commit thread), then we still need to - * take the FS itself readonly cleanly. - */ - if (journal && is_journal_aborted(journal)) { - ext4_abort(sb, "Detected aborted journal"); - return -EROFS; - } - return 0; -} - -handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line, - int type, int blocks, int rsv_blocks) -{ - journal_t *journal; - int err; - - trace_ext4_journal_start(sb, blocks, rsv_blocks, _RET_IP_); - err = ext4_journal_check_start(sb); - if (err < 0) - return ERR_PTR(err); - - journal = EXT4_SB(sb)->s_journal; - if (!journal) - return ext4_get_nojournal(); - return jbd2__journal_start(journal, blocks, rsv_blocks, GFP_NOFS, - type, line); -} - -int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle) -{ - struct super_block *sb; - int err; - int rc; - - if (!ext4_handle_valid(handle)) { - ext4_put_nojournal(handle); - return 0; - } - - err = handle->h_err; - if (!handle->h_transaction) { - rc = jbd2_journal_stop(handle); - return err ? err : rc; - } - - sb = handle->h_transaction->t_journal->j_private; - rc = jbd2_journal_stop(handle); - - if (!err) - err = rc; - if (err) - __ext4_std_error(sb, where, line, err); - return err; -} - -handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line, - int type) -{ - struct super_block *sb; - int err; - - if (!ext4_handle_valid(handle)) - return ext4_get_nojournal(); - - sb = handle->h_journal->j_private; - trace_ext4_journal_start_reserved(sb, handle->h_buffer_credits, - _RET_IP_); - err = ext4_journal_check_start(sb); - if (err < 0) { - jbd2_journal_free_reserved(handle); - return ERR_PTR(err); - } - - err = jbd2_journal_start_reserved(handle, type, line); - if (err < 0) - return ERR_PTR(err); - return handle; -} - -static void ext4_journal_abort_handle(const char *caller, unsigned int line, - const char *err_fn, - struct buffer_head *bh, - handle_t *handle, int err) -{ - char nbuf[16]; - const char *errstr = ext4_decode_error(NULL, err, nbuf); - - BUG_ON(!ext4_handle_valid(handle)); - - if (bh) - BUFFER_TRACE(bh, "abort"); - - if (!handle->h_err) - handle->h_err = err; - - if (is_handle_aborted(handle)) - return; - - printk(KERN_ERR "EXT4-fs: %s:%d: aborting transaction: %s in %s\n", - caller, line, errstr, err_fn); - - jbd2_journal_abort_handle(handle); -} - -int __ext4_journal_get_write_access(const char *where, unsigned int line, - handle_t *handle, struct buffer_head *bh) -{ - int err = 0; - - might_sleep(); - - if (ext4_handle_valid(handle)) { - err = jbd2_journal_get_write_access(handle, bh); - if (err) - ext4_journal_abort_handle(where, line, __func__, bh, - handle, err); - } - return err; -} - -/* - * The ext4 forget function must perform a revoke if we are freeing data - * which has been journaled. Metadata (eg. indirect blocks) must be - * revoked in all cases. - * - * "bh" may be NULL: a metadata block may have been freed from memory - * but there may still be a record of it in the journal, and that record - * still needs to be revoked. - * - * If the handle isn't valid we're not journaling, but we still need to - * call into ext4_journal_revoke() to put the buffer head. - */ -int __ext4_forget(const char *where, unsigned int line, handle_t *handle, - int is_metadata, struct inode *inode, - struct buffer_head *bh, ext4_fsblk_t blocknr) -{ - int err; - - might_sleep(); - - trace_ext4_forget(inode, is_metadata, blocknr); - BUFFER_TRACE(bh, "enter"); - - jbd_debug(4, "forgetting bh %p: is_metadata = %d, mode %o, " - "data mode %x\n", - bh, is_metadata, inode->i_mode, - test_opt(inode->i_sb, DATA_FLAGS)); - - /* In the no journal case, we can just do a bforget and return */ - if (!ext4_handle_valid(handle)) { - bforget(bh); - return 0; - } - - /* Never use the revoke function if we are doing full data - * journaling: there is no need to, and a V1 superblock won't - * support it. Otherwise, only skip the revoke on un-journaled - * data blocks. */ - - if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA || - (!is_metadata && !ext4_should_journal_data(inode))) { - if (bh) { - BUFFER_TRACE(bh, "call jbd2_journal_forget"); - err = jbd2_journal_forget(handle, bh); - if (err) - ext4_journal_abort_handle(where, line, __func__, - bh, handle, err); - return err; - } - return 0; - } - - /* - * data!=journal && (is_metadata || should_journal_data(inode)) - */ - BUFFER_TRACE(bh, "call jbd2_journal_revoke"); - err = jbd2_journal_revoke(handle, blocknr, bh); - if (err) { - ext4_journal_abort_handle(where, line, __func__, - bh, handle, err); - __ext4_abort(inode->i_sb, where, line, - "error %d when attempting revoke", err); - } - BUFFER_TRACE(bh, "exit"); - return err; -} - -int __ext4_journal_get_create_access(const char *where, unsigned int line, - handle_t *handle, struct buffer_head *bh) -{ - int err = 0; - - if (ext4_handle_valid(handle)) { - err = jbd2_journal_get_create_access(handle, bh); - if (err) - ext4_journal_abort_handle(where, line, __func__, - bh, handle, err); - } - return err; -} - -int __ext4_handle_dirty_metadata(const char *where, unsigned int line, - handle_t *handle, struct inode *inode, - struct buffer_head *bh) -{ - int err = 0; - - might_sleep(); - - set_buffer_meta(bh); - set_buffer_prio(bh); - if (ext4_handle_valid(handle)) { - err = jbd2_journal_dirty_metadata(handle, bh); - /* Errors can only happen due to aborted journal or a nasty bug */ - if (!is_handle_aborted(handle) && WARN_ON_ONCE(err)) { - ext4_journal_abort_handle(where, line, __func__, bh, - handle, err); - if (inode == NULL) { - pr_err("EXT4: jbd2_journal_dirty_metadata " - "failed: handle type %u started at " - "line %u, credits %u/%u, errcode %d", - handle->h_type, - handle->h_line_no, - handle->h_requested_credits, - handle->h_buffer_credits, err); - return err; - } - ext4_error_inode(inode, where, line, - bh->b_blocknr, - "journal_dirty_metadata failed: " - "handle type %u started at line %u, " - "credits %u/%u, errcode %d", - handle->h_type, - handle->h_line_no, - handle->h_requested_credits, - handle->h_buffer_credits, err); - } - } else { - if (inode) - mark_buffer_dirty_inode(bh, inode); - else - mark_buffer_dirty(bh); - if (inode && inode_needs_sync(inode)) { - sync_dirty_buffer(bh); - if (buffer_req(bh) && !buffer_uptodate(bh)) { - struct ext4_super_block *es; - - es = EXT4_SB(inode->i_sb)->s_es; - es->s_last_error_block = - cpu_to_le64(bh->b_blocknr); - ext4_error_inode(inode, where, line, - bh->b_blocknr, - "IO error syncing itable block"); - err = -EIO; - } - } - } - return err; -} - -int __ext4_handle_dirty_super(const char *where, unsigned int line, - handle_t *handle, struct super_block *sb) -{ - struct buffer_head *bh = EXT4_SB(sb)->s_sbh; - int err = 0; - - ext4_superblock_csum_set(sb); - if (ext4_handle_valid(handle)) { - err = jbd2_journal_dirty_metadata(handle, bh); - if (err) - ext4_journal_abort_handle(where, line, __func__, - bh, handle, err); - } else - mark_buffer_dirty(bh); - return err; -} diff --git a/src/linux/fs/ext4/ext4_jbd2.h b/src/linux/fs/ext4/ext4_jbd2.h deleted file mode 100644 index b1d52c1..0000000 --- a/src/linux/fs/ext4/ext4_jbd2.h +++ /dev/null @@ -1,467 +0,0 @@ -/* - * ext4_jbd2.h - * - * Written by Stephen C. Tweedie , 1999 - * - * Copyright 1998--1999 Red Hat corp --- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * Ext4-specific journaling extensions. - */ - -#ifndef _EXT4_JBD2_H -#define _EXT4_JBD2_H - -#include -#include -#include "ext4.h" - -#define EXT4_JOURNAL(inode) (EXT4_SB((inode)->i_sb)->s_journal) - -/* Define the number of blocks we need to account to a transaction to - * modify one block of data. - * - * We may have to touch one inode, one bitmap buffer, up to three - * indirection blocks, the group and superblock summaries, and the data - * block to complete the transaction. - * - * For extents-enabled fs we may have to allocate and modify up to - * 5 levels of tree, data block (for each of these we need bitmap + group - * summaries), root which is stored in the inode, sb - */ - -#define EXT4_SINGLEDATA_TRANS_BLOCKS(sb) \ - (ext4_has_feature_extents(sb) ? 20U : 8U) - -/* Extended attribute operations touch at most two data buffers, - * two bitmap buffers, and two group summaries, in addition to the inode - * and the superblock, which are already accounted for. */ - -#define EXT4_XATTR_TRANS_BLOCKS 6U - -/* Define the minimum size for a transaction which modifies data. This - * needs to take into account the fact that we may end up modifying two - * quota files too (one for the group, one for the user quota). The - * superblock only gets updated once, of course, so don't bother - * counting that again for the quota updates. */ - -#define EXT4_DATA_TRANS_BLOCKS(sb) (EXT4_SINGLEDATA_TRANS_BLOCKS(sb) + \ - EXT4_XATTR_TRANS_BLOCKS - 2 + \ - EXT4_MAXQUOTAS_TRANS_BLOCKS(sb)) - -/* - * Define the number of metadata blocks we need to account to modify data. - * - * This include super block, inode block, quota blocks and xattr blocks - */ -#define EXT4_META_TRANS_BLOCKS(sb) (EXT4_XATTR_TRANS_BLOCKS + \ - EXT4_MAXQUOTAS_TRANS_BLOCKS(sb)) - -/* Define an arbitrary limit for the amount of data we will anticipate - * writing to any given transaction. For unbounded transactions such as - * write(2) and truncate(2) we can write more than this, but we always - * start off at the maximum transaction size and grow the transaction - * optimistically as we go. */ - -#define EXT4_MAX_TRANS_DATA 64U - -/* We break up a large truncate or write transaction once the handle's - * buffer credits gets this low, we need either to extend the - * transaction or to start a new one. Reserve enough space here for - * inode, bitmap, superblock, group and indirection updates for at least - * one block, plus two quota updates. Quota allocations are not - * needed. */ - -#define EXT4_RESERVE_TRANS_BLOCKS 12U - -#define EXT4_INDEX_EXTRA_TRANS_BLOCKS 8 - -#ifdef CONFIG_QUOTA -/* Amount of blocks needed for quota update - we know that the structure was - * allocated so we need to update only data block */ -#define EXT4_QUOTA_TRANS_BLOCKS(sb) ((test_opt(sb, QUOTA) ||\ - ext4_has_feature_quota(sb)) ? 1 : 0) -/* Amount of blocks needed for quota insert/delete - we do some block writes - * but inode, sb and group updates are done only once */ -#define EXT4_QUOTA_INIT_BLOCKS(sb) ((test_opt(sb, QUOTA) ||\ - ext4_has_feature_quota(sb)) ?\ - (DQUOT_INIT_ALLOC*(EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)\ - +3+DQUOT_INIT_REWRITE) : 0) - -#define EXT4_QUOTA_DEL_BLOCKS(sb) ((test_opt(sb, QUOTA) ||\ - ext4_has_feature_quota(sb)) ?\ - (DQUOT_DEL_ALLOC*(EXT4_SINGLEDATA_TRANS_BLOCKS(sb)-3)\ - +3+DQUOT_DEL_REWRITE) : 0) -#else -#define EXT4_QUOTA_TRANS_BLOCKS(sb) 0 -#define EXT4_QUOTA_INIT_BLOCKS(sb) 0 -#define EXT4_QUOTA_DEL_BLOCKS(sb) 0 -#endif -#define EXT4_MAXQUOTAS_TRANS_BLOCKS(sb) (EXT4_MAXQUOTAS*EXT4_QUOTA_TRANS_BLOCKS(sb)) -#define EXT4_MAXQUOTAS_INIT_BLOCKS(sb) (EXT4_MAXQUOTAS*EXT4_QUOTA_INIT_BLOCKS(sb)) -#define EXT4_MAXQUOTAS_DEL_BLOCKS(sb) (EXT4_MAXQUOTAS*EXT4_QUOTA_DEL_BLOCKS(sb)) - -static inline int ext4_jbd2_credits_xattr(struct inode *inode) -{ - int credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb); - - /* - * In case of inline data, we may push out the data to a block, - * so we need to reserve credits for this eventuality - */ - if (ext4_has_inline_data(inode)) - credits += ext4_writepage_trans_blocks(inode) + 1; - return credits; -} - - -/* - * Ext4 handle operation types -- for logging purposes - */ -#define EXT4_HT_MISC 0 -#define EXT4_HT_INODE 1 -#define EXT4_HT_WRITE_PAGE 2 -#define EXT4_HT_MAP_BLOCKS 3 -#define EXT4_HT_DIR 4 -#define EXT4_HT_TRUNCATE 5 -#define EXT4_HT_QUOTA 6 -#define EXT4_HT_RESIZE 7 -#define EXT4_HT_MIGRATE 8 -#define EXT4_HT_MOVE_EXTENTS 9 -#define EXT4_HT_XATTR 10 -#define EXT4_HT_EXT_CONVERT 11 -#define EXT4_HT_MAX 12 - -/** - * struct ext4_journal_cb_entry - Base structure for callback information. - * - * This struct is a 'seed' structure for a using with your own callback - * structs. If you are using callbacks you must allocate one of these - * or another struct of your own definition which has this struct - * as it's first element and pass it to ext4_journal_callback_add(). - */ -struct ext4_journal_cb_entry { - /* list information for other callbacks attached to the same handle */ - struct list_head jce_list; - - /* Function to call with this callback structure */ - void (*jce_func)(struct super_block *sb, - struct ext4_journal_cb_entry *jce, int error); - - /* user data goes here */ -}; - -/** - * ext4_journal_callback_add: add a function to call after transaction commit - * @handle: active journal transaction handle to register callback on - * @func: callback function to call after the transaction has committed: - * @sb: superblock of current filesystem for transaction - * @jce: returned journal callback data - * @rc: journal state at commit (0 = transaction committed properly) - * @jce: journal callback data (internal and function private data struct) - * - * The registered function will be called in the context of the journal thread - * after the transaction for which the handle was created has completed. - * - * No locks are held when the callback function is called, so it is safe to - * call blocking functions from within the callback, but the callback should - * not block or run for too long, or the filesystem will be blocked waiting for - * the next transaction to commit. No journaling functions can be used, or - * there is a risk of deadlock. - * - * There is no guaranteed calling order of multiple registered callbacks on - * the same transaction. - */ -static inline void _ext4_journal_callback_add(handle_t *handle, - struct ext4_journal_cb_entry *jce) -{ - /* Add the jce to transaction's private list */ - list_add_tail(&jce->jce_list, &handle->h_transaction->t_private_list); -} - -static inline void ext4_journal_callback_add(handle_t *handle, - void (*func)(struct super_block *sb, - struct ext4_journal_cb_entry *jce, - int rc), - struct ext4_journal_cb_entry *jce) -{ - struct ext4_sb_info *sbi = - EXT4_SB(handle->h_transaction->t_journal->j_private); - - /* Add the jce to transaction's private list */ - jce->jce_func = func; - spin_lock(&sbi->s_md_lock); - _ext4_journal_callback_add(handle, jce); - spin_unlock(&sbi->s_md_lock); -} - - -/** - * ext4_journal_callback_del: delete a registered callback - * @handle: active journal transaction handle on which callback was registered - * @jce: registered journal callback entry to unregister - * Return true if object was successfully removed - */ -static inline bool ext4_journal_callback_try_del(handle_t *handle, - struct ext4_journal_cb_entry *jce) -{ - bool deleted; - struct ext4_sb_info *sbi = - EXT4_SB(handle->h_transaction->t_journal->j_private); - - spin_lock(&sbi->s_md_lock); - deleted = !list_empty(&jce->jce_list); - list_del_init(&jce->jce_list); - spin_unlock(&sbi->s_md_lock); - return deleted; -} - -int -ext4_mark_iloc_dirty(handle_t *handle, - struct inode *inode, - struct ext4_iloc *iloc); - -/* - * On success, We end up with an outstanding reference count against - * iloc->bh. This _must_ be cleaned up later. - */ - -int ext4_reserve_inode_write(handle_t *handle, struct inode *inode, - struct ext4_iloc *iloc); - -int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode); - -/* - * Wrapper functions with which ext4 calls into JBD. - */ -int __ext4_journal_get_write_access(const char *where, unsigned int line, - handle_t *handle, struct buffer_head *bh); - -int __ext4_forget(const char *where, unsigned int line, handle_t *handle, - int is_metadata, struct inode *inode, - struct buffer_head *bh, ext4_fsblk_t blocknr); - -int __ext4_journal_get_create_access(const char *where, unsigned int line, - handle_t *handle, struct buffer_head *bh); - -int __ext4_handle_dirty_metadata(const char *where, unsigned int line, - handle_t *handle, struct inode *inode, - struct buffer_head *bh); - -int __ext4_handle_dirty_super(const char *where, unsigned int line, - handle_t *handle, struct super_block *sb); - -#define ext4_journal_get_write_access(handle, bh) \ - __ext4_journal_get_write_access(__func__, __LINE__, (handle), (bh)) -#define ext4_forget(handle, is_metadata, inode, bh, block_nr) \ - __ext4_forget(__func__, __LINE__, (handle), (is_metadata), (inode), \ - (bh), (block_nr)) -#define ext4_journal_get_create_access(handle, bh) \ - __ext4_journal_get_create_access(__func__, __LINE__, (handle), (bh)) -#define ext4_handle_dirty_metadata(handle, inode, bh) \ - __ext4_handle_dirty_metadata(__func__, __LINE__, (handle), (inode), \ - (bh)) -#define ext4_handle_dirty_super(handle, sb) \ - __ext4_handle_dirty_super(__func__, __LINE__, (handle), (sb)) - -handle_t *__ext4_journal_start_sb(struct super_block *sb, unsigned int line, - int type, int blocks, int rsv_blocks); -int __ext4_journal_stop(const char *where, unsigned int line, handle_t *handle); - -#define EXT4_NOJOURNAL_MAX_REF_COUNT ((unsigned long) 4096) - -/* Note: Do not use this for NULL handles. This is only to determine if - * a properly allocated handle is using a journal or not. */ -static inline int ext4_handle_valid(handle_t *handle) -{ - if ((unsigned long)handle < EXT4_NOJOURNAL_MAX_REF_COUNT) - return 0; - return 1; -} - -static inline void ext4_handle_sync(handle_t *handle) -{ - if (ext4_handle_valid(handle)) - handle->h_sync = 1; -} - -static inline int ext4_handle_is_aborted(handle_t *handle) -{ - if (ext4_handle_valid(handle)) - return is_handle_aborted(handle); - return 0; -} - -static inline int ext4_handle_has_enough_credits(handle_t *handle, int needed) -{ - if (ext4_handle_valid(handle) && handle->h_buffer_credits < needed) - return 0; - return 1; -} - -#define ext4_journal_start_sb(sb, type, nblocks) \ - __ext4_journal_start_sb((sb), __LINE__, (type), (nblocks), 0) - -#define ext4_journal_start(inode, type, nblocks) \ - __ext4_journal_start((inode), __LINE__, (type), (nblocks), 0) - -#define ext4_journal_start_with_reserve(inode, type, blocks, rsv_blocks) \ - __ext4_journal_start((inode), __LINE__, (type), (blocks), (rsv_blocks)) - -static inline handle_t *__ext4_journal_start(struct inode *inode, - unsigned int line, int type, - int blocks, int rsv_blocks) -{ - return __ext4_journal_start_sb(inode->i_sb, line, type, blocks, - rsv_blocks); -} - -#define ext4_journal_stop(handle) \ - __ext4_journal_stop(__func__, __LINE__, (handle)) - -#define ext4_journal_start_reserved(handle, type) \ - __ext4_journal_start_reserved((handle), __LINE__, (type)) - -handle_t *__ext4_journal_start_reserved(handle_t *handle, unsigned int line, - int type); - -static inline void ext4_journal_free_reserved(handle_t *handle) -{ - if (ext4_handle_valid(handle)) - jbd2_journal_free_reserved(handle); -} - -static inline handle_t *ext4_journal_current_handle(void) -{ - return journal_current_handle(); -} - -static inline int ext4_journal_extend(handle_t *handle, int nblocks) -{ - if (ext4_handle_valid(handle)) - return jbd2_journal_extend(handle, nblocks); - return 0; -} - -static inline int ext4_journal_restart(handle_t *handle, int nblocks) -{ - if (ext4_handle_valid(handle)) - return jbd2_journal_restart(handle, nblocks); - return 0; -} - -static inline int ext4_journal_blocks_per_page(struct inode *inode) -{ - if (EXT4_JOURNAL(inode) != NULL) - return jbd2_journal_blocks_per_page(inode); - return 0; -} - -static inline int ext4_journal_force_commit(journal_t *journal) -{ - if (journal) - return jbd2_journal_force_commit(journal); - return 0; -} - -static inline int ext4_jbd2_inode_add_write(handle_t *handle, - struct inode *inode) -{ - if (ext4_handle_valid(handle)) - return jbd2_journal_inode_add_write(handle, - EXT4_I(inode)->jinode); - return 0; -} - -static inline int ext4_jbd2_inode_add_wait(handle_t *handle, - struct inode *inode) -{ - if (ext4_handle_valid(handle)) - return jbd2_journal_inode_add_wait(handle, - EXT4_I(inode)->jinode); - return 0; -} - -static inline void ext4_update_inode_fsync_trans(handle_t *handle, - struct inode *inode, - int datasync) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - - if (ext4_handle_valid(handle)) { - ei->i_sync_tid = handle->h_transaction->t_tid; - if (datasync) - ei->i_datasync_tid = handle->h_transaction->t_tid; - } -} - -/* super.c */ -int ext4_force_commit(struct super_block *sb); - -/* - * Ext4 inode journal modes - */ -#define EXT4_INODE_JOURNAL_DATA_MODE 0x01 /* journal data mode */ -#define EXT4_INODE_ORDERED_DATA_MODE 0x02 /* ordered data mode */ -#define EXT4_INODE_WRITEBACK_DATA_MODE 0x04 /* writeback data mode */ - -static inline int ext4_inode_journal_mode(struct inode *inode) -{ - if (EXT4_JOURNAL(inode) == NULL) - return EXT4_INODE_WRITEBACK_DATA_MODE; /* writeback */ - /* We do not support data journalling with delayed allocation */ - if (!S_ISREG(inode->i_mode) || - test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) - return EXT4_INODE_JOURNAL_DATA_MODE; /* journal data */ - if (ext4_test_inode_flag(inode, EXT4_INODE_JOURNAL_DATA) && - !test_opt(inode->i_sb, DELALLOC)) - return EXT4_INODE_JOURNAL_DATA_MODE; /* journal data */ - if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) - return EXT4_INODE_ORDERED_DATA_MODE; /* ordered */ - if (test_opt(inode->i_sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) - return EXT4_INODE_WRITEBACK_DATA_MODE; /* writeback */ - else - BUG(); -} - -static inline int ext4_should_journal_data(struct inode *inode) -{ - return ext4_inode_journal_mode(inode) & EXT4_INODE_JOURNAL_DATA_MODE; -} - -static inline int ext4_should_order_data(struct inode *inode) -{ - return ext4_inode_journal_mode(inode) & EXT4_INODE_ORDERED_DATA_MODE; -} - -static inline int ext4_should_writeback_data(struct inode *inode) -{ - return ext4_inode_journal_mode(inode) & EXT4_INODE_WRITEBACK_DATA_MODE; -} - -/* - * This function controls whether or not we should try to go down the - * dioread_nolock code paths, which makes it safe to avoid taking - * i_mutex for direct I/O reads. This only works for extent-based - * files, and it doesn't work if data journaling is enabled, since the - * dioread_nolock code uses b_private to pass information back to the - * I/O completion handler, and this conflicts with the jbd's use of - * b_private. - */ -static inline int ext4_should_dioread_nolock(struct inode *inode) -{ - if (!test_opt(inode->i_sb, DIOREAD_NOLOCK)) - return 0; - if (!S_ISREG(inode->i_mode)) - return 0; - if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) - return 0; - if (ext4_should_journal_data(inode)) - return 0; - return 1; -} - -#endif /* _EXT4_JBD2_H */ diff --git a/src/linux/fs/ext4/extents.c b/src/linux/fs/ext4/extents.c deleted file mode 100644 index c930a01..0000000 --- a/src/linux/fs/ext4/extents.c +++ /dev/null @@ -1,5951 +0,0 @@ -/* - * Copyright (c) 2003-2006, Cluster File Systems, Inc, info@clusterfs.com - * Written by Alex Tomas - * - * Architecture independence: - * Copyright (c) 2005, Bull S.A. - * Written by Pierre Peiffer - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- - */ - -/* - * Extents support for EXT4 - * - * TODO: - * - ext4*_error() should be used in some situations - * - analyze all BUG()/BUG_ON(), use -EIO where appropriate - * - smart tree reduction - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ext4_jbd2.h" -#include "ext4_extents.h" -#include "xattr.h" - -#include - -/* - * used by extent splitting. - */ -#define EXT4_EXT_MAY_ZEROOUT 0x1 /* safe to zeroout if split fails \ - due to ENOSPC */ -#define EXT4_EXT_MARK_UNWRIT1 0x2 /* mark first half unwritten */ -#define EXT4_EXT_MARK_UNWRIT2 0x4 /* mark second half unwritten */ - -#define EXT4_EXT_DATA_VALID1 0x8 /* first half contains valid data */ -#define EXT4_EXT_DATA_VALID2 0x10 /* second half contains valid data */ - -static __le32 ext4_extent_block_csum(struct inode *inode, - struct ext4_extent_header *eh) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - __u32 csum; - - csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)eh, - EXT4_EXTENT_TAIL_OFFSET(eh)); - return cpu_to_le32(csum); -} - -static int ext4_extent_block_csum_verify(struct inode *inode, - struct ext4_extent_header *eh) -{ - struct ext4_extent_tail *et; - - if (!ext4_has_metadata_csum(inode->i_sb)) - return 1; - - et = find_ext4_extent_tail(eh); - if (et->et_checksum != ext4_extent_block_csum(inode, eh)) - return 0; - return 1; -} - -static void ext4_extent_block_csum_set(struct inode *inode, - struct ext4_extent_header *eh) -{ - struct ext4_extent_tail *et; - - if (!ext4_has_metadata_csum(inode->i_sb)) - return; - - et = find_ext4_extent_tail(eh); - et->et_checksum = ext4_extent_block_csum(inode, eh); -} - -static int ext4_split_extent(handle_t *handle, - struct inode *inode, - struct ext4_ext_path **ppath, - struct ext4_map_blocks *map, - int split_flag, - int flags); - -static int ext4_split_extent_at(handle_t *handle, - struct inode *inode, - struct ext4_ext_path **ppath, - ext4_lblk_t split, - int split_flag, - int flags); - -static int ext4_find_delayed_extent(struct inode *inode, - struct extent_status *newes); - -static int ext4_ext_truncate_extend_restart(handle_t *handle, - struct inode *inode, - int needed) -{ - int err; - - if (!ext4_handle_valid(handle)) - return 0; - if (handle->h_buffer_credits >= needed) - return 0; - /* - * If we need to extend the journal get a few extra blocks - * while we're at it for efficiency's sake. - */ - needed += 3; - err = ext4_journal_extend(handle, needed - handle->h_buffer_credits); - if (err <= 0) - return err; - err = ext4_truncate_restart_trans(handle, inode, needed); - if (err == 0) - err = -EAGAIN; - - return err; -} - -/* - * could return: - * - EROFS - * - ENOMEM - */ -static int ext4_ext_get_access(handle_t *handle, struct inode *inode, - struct ext4_ext_path *path) -{ - if (path->p_bh) { - /* path points to block */ - BUFFER_TRACE(path->p_bh, "get_write_access"); - return ext4_journal_get_write_access(handle, path->p_bh); - } - /* path points to leaf/index in inode body */ - /* we use in-core data, no need to protect them */ - return 0; -} - -/* - * could return: - * - EROFS - * - ENOMEM - * - EIO - */ -int __ext4_ext_dirty(const char *where, unsigned int line, handle_t *handle, - struct inode *inode, struct ext4_ext_path *path) -{ - int err; - - WARN_ON(!rwsem_is_locked(&EXT4_I(inode)->i_data_sem)); - if (path->p_bh) { - ext4_extent_block_csum_set(inode, ext_block_hdr(path->p_bh)); - /* path points to block */ - err = __ext4_handle_dirty_metadata(where, line, handle, - inode, path->p_bh); - } else { - /* path points to leaf/index in inode body */ - err = ext4_mark_inode_dirty(handle, inode); - } - return err; -} - -static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode, - struct ext4_ext_path *path, - ext4_lblk_t block) -{ - if (path) { - int depth = path->p_depth; - struct ext4_extent *ex; - - /* - * Try to predict block placement assuming that we are - * filling in a file which will eventually be - * non-sparse --- i.e., in the case of libbfd writing - * an ELF object sections out-of-order but in a way - * the eventually results in a contiguous object or - * executable file, or some database extending a table - * space file. However, this is actually somewhat - * non-ideal if we are writing a sparse file such as - * qemu or KVM writing a raw image file that is going - * to stay fairly sparse, since it will end up - * fragmenting the file system's free space. Maybe we - * should have some hueristics or some way to allow - * userspace to pass a hint to file system, - * especially if the latter case turns out to be - * common. - */ - ex = path[depth].p_ext; - if (ex) { - ext4_fsblk_t ext_pblk = ext4_ext_pblock(ex); - ext4_lblk_t ext_block = le32_to_cpu(ex->ee_block); - - if (block > ext_block) - return ext_pblk + (block - ext_block); - else - return ext_pblk - (ext_block - block); - } - - /* it looks like index is empty; - * try to find starting block from index itself */ - if (path[depth].p_bh) - return path[depth].p_bh->b_blocknr; - } - - /* OK. use inode's group */ - return ext4_inode_to_goal_block(inode); -} - -/* - * Allocation for a meta data block - */ -static ext4_fsblk_t -ext4_ext_new_meta_block(handle_t *handle, struct inode *inode, - struct ext4_ext_path *path, - struct ext4_extent *ex, int *err, unsigned int flags) -{ - ext4_fsblk_t goal, newblock; - - goal = ext4_ext_find_goal(inode, path, le32_to_cpu(ex->ee_block)); - newblock = ext4_new_meta_blocks(handle, inode, goal, flags, - NULL, err); - return newblock; -} - -static inline int ext4_ext_space_block(struct inode *inode, int check) -{ - int size; - - size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header)) - / sizeof(struct ext4_extent); -#ifdef AGGRESSIVE_TEST - if (!check && size > 6) - size = 6; -#endif - return size; -} - -static inline int ext4_ext_space_block_idx(struct inode *inode, int check) -{ - int size; - - size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header)) - / sizeof(struct ext4_extent_idx); -#ifdef AGGRESSIVE_TEST - if (!check && size > 5) - size = 5; -#endif - return size; -} - -static inline int ext4_ext_space_root(struct inode *inode, int check) -{ - int size; - - size = sizeof(EXT4_I(inode)->i_data); - size -= sizeof(struct ext4_extent_header); - size /= sizeof(struct ext4_extent); -#ifdef AGGRESSIVE_TEST - if (!check && size > 3) - size = 3; -#endif - return size; -} - -static inline int ext4_ext_space_root_idx(struct inode *inode, int check) -{ - int size; - - size = sizeof(EXT4_I(inode)->i_data); - size -= sizeof(struct ext4_extent_header); - size /= sizeof(struct ext4_extent_idx); -#ifdef AGGRESSIVE_TEST - if (!check && size > 4) - size = 4; -#endif - return size; -} - -static inline int -ext4_force_split_extent_at(handle_t *handle, struct inode *inode, - struct ext4_ext_path **ppath, ext4_lblk_t lblk, - int nofail) -{ - struct ext4_ext_path *path = *ppath; - int unwritten = ext4_ext_is_unwritten(path[path->p_depth].p_ext); - - return ext4_split_extent_at(handle, inode, ppath, lblk, unwritten ? - EXT4_EXT_MARK_UNWRIT1|EXT4_EXT_MARK_UNWRIT2 : 0, - EXT4_EX_NOCACHE | EXT4_GET_BLOCKS_PRE_IO | - (nofail ? EXT4_GET_BLOCKS_METADATA_NOFAIL:0)); -} - -/* - * Calculate the number of metadata blocks needed - * to allocate @blocks - * Worse case is one block per extent - */ -int ext4_ext_calc_metadata_amount(struct inode *inode, ext4_lblk_t lblock) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - int idxs; - - idxs = ((inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header)) - / sizeof(struct ext4_extent_idx)); - - /* - * If the new delayed allocation block is contiguous with the - * previous da block, it can share index blocks with the - * previous block, so we only need to allocate a new index - * block every idxs leaf blocks. At ldxs**2 blocks, we need - * an additional index block, and at ldxs**3 blocks, yet - * another index blocks. - */ - if (ei->i_da_metadata_calc_len && - ei->i_da_metadata_calc_last_lblock+1 == lblock) { - int num = 0; - - if ((ei->i_da_metadata_calc_len % idxs) == 0) - num++; - if ((ei->i_da_metadata_calc_len % (idxs*idxs)) == 0) - num++; - if ((ei->i_da_metadata_calc_len % (idxs*idxs*idxs)) == 0) { - num++; - ei->i_da_metadata_calc_len = 0; - } else - ei->i_da_metadata_calc_len++; - ei->i_da_metadata_calc_last_lblock++; - return num; - } - - /* - * In the worst case we need a new set of index blocks at - * every level of the inode's extent tree. - */ - ei->i_da_metadata_calc_len = 1; - ei->i_da_metadata_calc_last_lblock = lblock; - return ext_depth(inode) + 1; -} - -static int -ext4_ext_max_entries(struct inode *inode, int depth) -{ - int max; - - if (depth == ext_depth(inode)) { - if (depth == 0) - max = ext4_ext_space_root(inode, 1); - else - max = ext4_ext_space_root_idx(inode, 1); - } else { - if (depth == 0) - max = ext4_ext_space_block(inode, 1); - else - max = ext4_ext_space_block_idx(inode, 1); - } - - return max; -} - -static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext) -{ - ext4_fsblk_t block = ext4_ext_pblock(ext); - int len = ext4_ext_get_actual_len(ext); - ext4_lblk_t lblock = le32_to_cpu(ext->ee_block); - - /* - * We allow neither: - * - zero length - * - overflow/wrap-around - */ - if (lblock + len <= lblock) - return 0; - return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, len); -} - -static int ext4_valid_extent_idx(struct inode *inode, - struct ext4_extent_idx *ext_idx) -{ - ext4_fsblk_t block = ext4_idx_pblock(ext_idx); - - return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, 1); -} - -static int ext4_valid_extent_entries(struct inode *inode, - struct ext4_extent_header *eh, - int depth) -{ - unsigned short entries; - if (eh->eh_entries == 0) - return 1; - - entries = le16_to_cpu(eh->eh_entries); - - if (depth == 0) { - /* leaf entries */ - struct ext4_extent *ext = EXT_FIRST_EXTENT(eh); - struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es; - ext4_fsblk_t pblock = 0; - ext4_lblk_t lblock = 0; - ext4_lblk_t prev = 0; - int len = 0; - while (entries) { - if (!ext4_valid_extent(inode, ext)) - return 0; - - /* Check for overlapping extents */ - lblock = le32_to_cpu(ext->ee_block); - len = ext4_ext_get_actual_len(ext); - if ((lblock <= prev) && prev) { - pblock = ext4_ext_pblock(ext); - es->s_last_error_block = cpu_to_le64(pblock); - return 0; - } - ext++; - entries--; - prev = lblock + len - 1; - } - } else { - struct ext4_extent_idx *ext_idx = EXT_FIRST_INDEX(eh); - while (entries) { - if (!ext4_valid_extent_idx(inode, ext_idx)) - return 0; - ext_idx++; - entries--; - } - } - return 1; -} - -static int __ext4_ext_check(const char *function, unsigned int line, - struct inode *inode, struct ext4_extent_header *eh, - int depth, ext4_fsblk_t pblk) -{ - const char *error_msg; - int max = 0, err = -EFSCORRUPTED; - - if (unlikely(eh->eh_magic != EXT4_EXT_MAGIC)) { - error_msg = "invalid magic"; - goto corrupted; - } - if (unlikely(le16_to_cpu(eh->eh_depth) != depth)) { - error_msg = "unexpected eh_depth"; - goto corrupted; - } - if (unlikely(eh->eh_max == 0)) { - error_msg = "invalid eh_max"; - goto corrupted; - } - max = ext4_ext_max_entries(inode, depth); - if (unlikely(le16_to_cpu(eh->eh_max) > max)) { - error_msg = "too large eh_max"; - goto corrupted; - } - if (unlikely(le16_to_cpu(eh->eh_entries) > le16_to_cpu(eh->eh_max))) { - error_msg = "invalid eh_entries"; - goto corrupted; - } - if (!ext4_valid_extent_entries(inode, eh, depth)) { - error_msg = "invalid extent entries"; - goto corrupted; - } - if (unlikely(depth > 32)) { - error_msg = "too large eh_depth"; - goto corrupted; - } - /* Verify checksum on non-root extent tree nodes */ - if (ext_depth(inode) != depth && - !ext4_extent_block_csum_verify(inode, eh)) { - error_msg = "extent tree corrupted"; - err = -EFSBADCRC; - goto corrupted; - } - return 0; - -corrupted: - ext4_error_inode(inode, function, line, 0, - "pblk %llu bad header/extent: %s - magic %x, " - "entries %u, max %u(%u), depth %u(%u)", - (unsigned long long) pblk, error_msg, - le16_to_cpu(eh->eh_magic), - le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max), - max, le16_to_cpu(eh->eh_depth), depth); - return err; -} - -#define ext4_ext_check(inode, eh, depth, pblk) \ - __ext4_ext_check(__func__, __LINE__, (inode), (eh), (depth), (pblk)) - -int ext4_ext_check_inode(struct inode *inode) -{ - return ext4_ext_check(inode, ext_inode_hdr(inode), ext_depth(inode), 0); -} - -static struct buffer_head * -__read_extent_tree_block(const char *function, unsigned int line, - struct inode *inode, ext4_fsblk_t pblk, int depth, - int flags) -{ - struct buffer_head *bh; - int err; - - bh = sb_getblk_gfp(inode->i_sb, pblk, __GFP_MOVABLE | GFP_NOFS); - if (unlikely(!bh)) - return ERR_PTR(-ENOMEM); - - if (!bh_uptodate_or_lock(bh)) { - trace_ext4_ext_load_extent(inode, pblk, _RET_IP_); - err = bh_submit_read(bh); - if (err < 0) - goto errout; - } - if (buffer_verified(bh) && !(flags & EXT4_EX_FORCE_CACHE)) - return bh; - err = __ext4_ext_check(function, line, inode, - ext_block_hdr(bh), depth, pblk); - if (err) - goto errout; - set_buffer_verified(bh); - /* - * If this is a leaf block, cache all of its entries - */ - if (!(flags & EXT4_EX_NOCACHE) && depth == 0) { - struct ext4_extent_header *eh = ext_block_hdr(bh); - struct ext4_extent *ex = EXT_FIRST_EXTENT(eh); - ext4_lblk_t prev = 0; - int i; - - for (i = le16_to_cpu(eh->eh_entries); i > 0; i--, ex++) { - unsigned int status = EXTENT_STATUS_WRITTEN; - ext4_lblk_t lblk = le32_to_cpu(ex->ee_block); - int len = ext4_ext_get_actual_len(ex); - - if (prev && (prev != lblk)) - ext4_es_cache_extent(inode, prev, - lblk - prev, ~0, - EXTENT_STATUS_HOLE); - - if (ext4_ext_is_unwritten(ex)) - status = EXTENT_STATUS_UNWRITTEN; - ext4_es_cache_extent(inode, lblk, len, - ext4_ext_pblock(ex), status); - prev = lblk + len; - } - } - return bh; -errout: - put_bh(bh); - return ERR_PTR(err); - -} - -#define read_extent_tree_block(inode, pblk, depth, flags) \ - __read_extent_tree_block(__func__, __LINE__, (inode), (pblk), \ - (depth), (flags)) - -/* - * This function is called to cache a file's extent information in the - * extent status tree - */ -int ext4_ext_precache(struct inode *inode) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - struct ext4_ext_path *path = NULL; - struct buffer_head *bh; - int i = 0, depth, ret = 0; - - if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) - return 0; /* not an extent-mapped inode */ - - down_read(&ei->i_data_sem); - depth = ext_depth(inode); - - path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), - GFP_NOFS); - if (path == NULL) { - up_read(&ei->i_data_sem); - return -ENOMEM; - } - - /* Don't cache anything if there are no external extent blocks */ - if (depth == 0) - goto out; - path[0].p_hdr = ext_inode_hdr(inode); - ret = ext4_ext_check(inode, path[0].p_hdr, depth, 0); - if (ret) - goto out; - path[0].p_idx = EXT_FIRST_INDEX(path[0].p_hdr); - while (i >= 0) { - /* - * If this is a leaf block or we've reached the end of - * the index block, go up - */ - if ((i == depth) || - path[i].p_idx > EXT_LAST_INDEX(path[i].p_hdr)) { - brelse(path[i].p_bh); - path[i].p_bh = NULL; - i--; - continue; - } - bh = read_extent_tree_block(inode, - ext4_idx_pblock(path[i].p_idx++), - depth - i - 1, - EXT4_EX_FORCE_CACHE); - if (IS_ERR(bh)) { - ret = PTR_ERR(bh); - break; - } - i++; - path[i].p_bh = bh; - path[i].p_hdr = ext_block_hdr(bh); - path[i].p_idx = EXT_FIRST_INDEX(path[i].p_hdr); - } - ext4_set_inode_state(inode, EXT4_STATE_EXT_PRECACHED); -out: - up_read(&ei->i_data_sem); - ext4_ext_drop_refs(path); - kfree(path); - return ret; -} - -#ifdef EXT_DEBUG -static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path) -{ - int k, l = path->p_depth; - - ext_debug("path:"); - for (k = 0; k <= l; k++, path++) { - if (path->p_idx) { - ext_debug(" %d->%llu", le32_to_cpu(path->p_idx->ei_block), - ext4_idx_pblock(path->p_idx)); - } else if (path->p_ext) { - ext_debug(" %d:[%d]%d:%llu ", - le32_to_cpu(path->p_ext->ee_block), - ext4_ext_is_unwritten(path->p_ext), - ext4_ext_get_actual_len(path->p_ext), - ext4_ext_pblock(path->p_ext)); - } else - ext_debug(" []"); - } - ext_debug("\n"); -} - -static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path) -{ - int depth = ext_depth(inode); - struct ext4_extent_header *eh; - struct ext4_extent *ex; - int i; - - if (!path) - return; - - eh = path[depth].p_hdr; - ex = EXT_FIRST_EXTENT(eh); - - ext_debug("Displaying leaf extents for inode %lu\n", inode->i_ino); - - for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) { - ext_debug("%d:[%d]%d:%llu ", le32_to_cpu(ex->ee_block), - ext4_ext_is_unwritten(ex), - ext4_ext_get_actual_len(ex), ext4_ext_pblock(ex)); - } - ext_debug("\n"); -} - -static void ext4_ext_show_move(struct inode *inode, struct ext4_ext_path *path, - ext4_fsblk_t newblock, int level) -{ - int depth = ext_depth(inode); - struct ext4_extent *ex; - - if (depth != level) { - struct ext4_extent_idx *idx; - idx = path[level].p_idx; - while (idx <= EXT_MAX_INDEX(path[level].p_hdr)) { - ext_debug("%d: move %d:%llu in new index %llu\n", level, - le32_to_cpu(idx->ei_block), - ext4_idx_pblock(idx), - newblock); - idx++; - } - - return; - } - - ex = path[depth].p_ext; - while (ex <= EXT_MAX_EXTENT(path[depth].p_hdr)) { - ext_debug("move %d:%llu:[%d]%d in new leaf %llu\n", - le32_to_cpu(ex->ee_block), - ext4_ext_pblock(ex), - ext4_ext_is_unwritten(ex), - ext4_ext_get_actual_len(ex), - newblock); - ex++; - } -} - -#else -#define ext4_ext_show_path(inode, path) -#define ext4_ext_show_leaf(inode, path) -#define ext4_ext_show_move(inode, path, newblock, level) -#endif - -void ext4_ext_drop_refs(struct ext4_ext_path *path) -{ - int depth, i; - - if (!path) - return; - depth = path->p_depth; - for (i = 0; i <= depth; i++, path++) - if (path->p_bh) { - brelse(path->p_bh); - path->p_bh = NULL; - } -} - -/* - * ext4_ext_binsearch_idx: - * binary search for the closest index of the given block - * the header must be checked before calling this - */ -static void -ext4_ext_binsearch_idx(struct inode *inode, - struct ext4_ext_path *path, ext4_lblk_t block) -{ - struct ext4_extent_header *eh = path->p_hdr; - struct ext4_extent_idx *r, *l, *m; - - - ext_debug("binsearch for %u(idx): ", block); - - l = EXT_FIRST_INDEX(eh) + 1; - r = EXT_LAST_INDEX(eh); - while (l <= r) { - m = l + (r - l) / 2; - if (block < le32_to_cpu(m->ei_block)) - r = m - 1; - else - l = m + 1; - ext_debug("%p(%u):%p(%u):%p(%u) ", l, le32_to_cpu(l->ei_block), - m, le32_to_cpu(m->ei_block), - r, le32_to_cpu(r->ei_block)); - } - - path->p_idx = l - 1; - ext_debug(" -> %u->%lld ", le32_to_cpu(path->p_idx->ei_block), - ext4_idx_pblock(path->p_idx)); - -#ifdef CHECK_BINSEARCH - { - struct ext4_extent_idx *chix, *ix; - int k; - - chix = ix = EXT_FIRST_INDEX(eh); - for (k = 0; k < le16_to_cpu(eh->eh_entries); k++, ix++) { - if (k != 0 && - le32_to_cpu(ix->ei_block) <= le32_to_cpu(ix[-1].ei_block)) { - printk(KERN_DEBUG "k=%d, ix=0x%p, " - "first=0x%p\n", k, - ix, EXT_FIRST_INDEX(eh)); - printk(KERN_DEBUG "%u <= %u\n", - le32_to_cpu(ix->ei_block), - le32_to_cpu(ix[-1].ei_block)); - } - BUG_ON(k && le32_to_cpu(ix->ei_block) - <= le32_to_cpu(ix[-1].ei_block)); - if (block < le32_to_cpu(ix->ei_block)) - break; - chix = ix; - } - BUG_ON(chix != path->p_idx); - } -#endif - -} - -/* - * ext4_ext_binsearch: - * binary search for closest extent of the given block - * the header must be checked before calling this - */ -static void -ext4_ext_binsearch(struct inode *inode, - struct ext4_ext_path *path, ext4_lblk_t block) -{ - struct ext4_extent_header *eh = path->p_hdr; - struct ext4_extent *r, *l, *m; - - if (eh->eh_entries == 0) { - /* - * this leaf is empty: - * we get such a leaf in split/add case - */ - return; - } - - ext_debug("binsearch for %u: ", block); - - l = EXT_FIRST_EXTENT(eh) + 1; - r = EXT_LAST_EXTENT(eh); - - while (l <= r) { - m = l + (r - l) / 2; - if (block < le32_to_cpu(m->ee_block)) - r = m - 1; - else - l = m + 1; - ext_debug("%p(%u):%p(%u):%p(%u) ", l, le32_to_cpu(l->ee_block), - m, le32_to_cpu(m->ee_block), - r, le32_to_cpu(r->ee_block)); - } - - path->p_ext = l - 1; - ext_debug(" -> %d:%llu:[%d]%d ", - le32_to_cpu(path->p_ext->ee_block), - ext4_ext_pblock(path->p_ext), - ext4_ext_is_unwritten(path->p_ext), - ext4_ext_get_actual_len(path->p_ext)); - -#ifdef CHECK_BINSEARCH - { - struct ext4_extent *chex, *ex; - int k; - - chex = ex = EXT_FIRST_EXTENT(eh); - for (k = 0; k < le16_to_cpu(eh->eh_entries); k++, ex++) { - BUG_ON(k && le32_to_cpu(ex->ee_block) - <= le32_to_cpu(ex[-1].ee_block)); - if (block < le32_to_cpu(ex->ee_block)) - break; - chex = ex; - } - BUG_ON(chex != path->p_ext); - } -#endif - -} - -int ext4_ext_tree_init(handle_t *handle, struct inode *inode) -{ - struct ext4_extent_header *eh; - - eh = ext_inode_hdr(inode); - eh->eh_depth = 0; - eh->eh_entries = 0; - eh->eh_magic = EXT4_EXT_MAGIC; - eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode, 0)); - ext4_mark_inode_dirty(handle, inode); - return 0; -} - -struct ext4_ext_path * -ext4_find_extent(struct inode *inode, ext4_lblk_t block, - struct ext4_ext_path **orig_path, int flags) -{ - struct ext4_extent_header *eh; - struct buffer_head *bh; - struct ext4_ext_path *path = orig_path ? *orig_path : NULL; - short int depth, i, ppos = 0; - int ret; - - eh = ext_inode_hdr(inode); - depth = ext_depth(inode); - - if (path) { - ext4_ext_drop_refs(path); - if (depth > path[0].p_maxdepth) { - kfree(path); - *orig_path = path = NULL; - } - } - if (!path) { - /* account possible depth increase */ - path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 2), - GFP_NOFS); - if (unlikely(!path)) - return ERR_PTR(-ENOMEM); - path[0].p_maxdepth = depth + 1; - } - path[0].p_hdr = eh; - path[0].p_bh = NULL; - - i = depth; - /* walk through the tree */ - while (i) { - ext_debug("depth %d: num %d, max %d\n", - ppos, le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max)); - - ext4_ext_binsearch_idx(inode, path + ppos, block); - path[ppos].p_block = ext4_idx_pblock(path[ppos].p_idx); - path[ppos].p_depth = i; - path[ppos].p_ext = NULL; - - bh = read_extent_tree_block(inode, path[ppos].p_block, --i, - flags); - if (IS_ERR(bh)) { - ret = PTR_ERR(bh); - goto err; - } - - eh = ext_block_hdr(bh); - ppos++; - path[ppos].p_bh = bh; - path[ppos].p_hdr = eh; - } - - path[ppos].p_depth = i; - path[ppos].p_ext = NULL; - path[ppos].p_idx = NULL; - - /* find extent */ - ext4_ext_binsearch(inode, path + ppos, block); - /* if not an empty leaf */ - if (path[ppos].p_ext) - path[ppos].p_block = ext4_ext_pblock(path[ppos].p_ext); - - ext4_ext_show_path(inode, path); - - return path; - -err: - ext4_ext_drop_refs(path); - kfree(path); - if (orig_path) - *orig_path = NULL; - return ERR_PTR(ret); -} - -/* - * ext4_ext_insert_index: - * insert new index [@logical;@ptr] into the block at @curp; - * check where to insert: before @curp or after @curp - */ -static int ext4_ext_insert_index(handle_t *handle, struct inode *inode, - struct ext4_ext_path *curp, - int logical, ext4_fsblk_t ptr) -{ - struct ext4_extent_idx *ix; - int len, err; - - err = ext4_ext_get_access(handle, inode, curp); - if (err) - return err; - - if (unlikely(logical == le32_to_cpu(curp->p_idx->ei_block))) { - EXT4_ERROR_INODE(inode, - "logical %d == ei_block %d!", - logical, le32_to_cpu(curp->p_idx->ei_block)); - return -EFSCORRUPTED; - } - - if (unlikely(le16_to_cpu(curp->p_hdr->eh_entries) - >= le16_to_cpu(curp->p_hdr->eh_max))) { - EXT4_ERROR_INODE(inode, - "eh_entries %d >= eh_max %d!", - le16_to_cpu(curp->p_hdr->eh_entries), - le16_to_cpu(curp->p_hdr->eh_max)); - return -EFSCORRUPTED; - } - - if (logical > le32_to_cpu(curp->p_idx->ei_block)) { - /* insert after */ - ext_debug("insert new index %d after: %llu\n", logical, ptr); - ix = curp->p_idx + 1; - } else { - /* insert before */ - ext_debug("insert new index %d before: %llu\n", logical, ptr); - ix = curp->p_idx; - } - - len = EXT_LAST_INDEX(curp->p_hdr) - ix + 1; - BUG_ON(len < 0); - if (len > 0) { - ext_debug("insert new index %d: " - "move %d indices from 0x%p to 0x%p\n", - logical, len, ix, ix + 1); - memmove(ix + 1, ix, len * sizeof(struct ext4_extent_idx)); - } - - if (unlikely(ix > EXT_MAX_INDEX(curp->p_hdr))) { - EXT4_ERROR_INODE(inode, "ix > EXT_MAX_INDEX!"); - return -EFSCORRUPTED; - } - - ix->ei_block = cpu_to_le32(logical); - ext4_idx_store_pblock(ix, ptr); - le16_add_cpu(&curp->p_hdr->eh_entries, 1); - - if (unlikely(ix > EXT_LAST_INDEX(curp->p_hdr))) { - EXT4_ERROR_INODE(inode, "ix > EXT_LAST_INDEX!"); - return -EFSCORRUPTED; - } - - err = ext4_ext_dirty(handle, inode, curp); - ext4_std_error(inode->i_sb, err); - - return err; -} - -/* - * ext4_ext_split: - * inserts new subtree into the path, using free index entry - * at depth @at: - * - allocates all needed blocks (new leaf and all intermediate index blocks) - * - makes decision where to split - * - moves remaining extents and index entries (right to the split point) - * into the newly allocated blocks - * - initializes subtree - */ -static int ext4_ext_split(handle_t *handle, struct inode *inode, - unsigned int flags, - struct ext4_ext_path *path, - struct ext4_extent *newext, int at) -{ - struct buffer_head *bh = NULL; - int depth = ext_depth(inode); - struct ext4_extent_header *neh; - struct ext4_extent_idx *fidx; - int i = at, k, m, a; - ext4_fsblk_t newblock, oldblock; - __le32 border; - ext4_fsblk_t *ablocks = NULL; /* array of allocated blocks */ - int err = 0; - - /* make decision: where to split? */ - /* FIXME: now decision is simplest: at current extent */ - - /* if current leaf will be split, then we should use - * border from split point */ - if (unlikely(path[depth].p_ext > EXT_MAX_EXTENT(path[depth].p_hdr))) { - EXT4_ERROR_INODE(inode, "p_ext > EXT_MAX_EXTENT!"); - return -EFSCORRUPTED; - } - if (path[depth].p_ext != EXT_MAX_EXTENT(path[depth].p_hdr)) { - border = path[depth].p_ext[1].ee_block; - ext_debug("leaf will be split." - " next leaf starts at %d\n", - le32_to_cpu(border)); - } else { - border = newext->ee_block; - ext_debug("leaf will be added." - " next leaf starts at %d\n", - le32_to_cpu(border)); - } - - /* - * If error occurs, then we break processing - * and mark filesystem read-only. index won't - * be inserted and tree will be in consistent - * state. Next mount will repair buffers too. - */ - - /* - * Get array to track all allocated blocks. - * We need this to handle errors and free blocks - * upon them. - */ - ablocks = kzalloc(sizeof(ext4_fsblk_t) * depth, GFP_NOFS); - if (!ablocks) - return -ENOMEM; - - /* allocate all needed blocks */ - ext_debug("allocate %d blocks for indexes/leaf\n", depth - at); - for (a = 0; a < depth - at; a++) { - newblock = ext4_ext_new_meta_block(handle, inode, path, - newext, &err, flags); - if (newblock == 0) - goto cleanup; - ablocks[a] = newblock; - } - - /* initialize new leaf */ - newblock = ablocks[--a]; - if (unlikely(newblock == 0)) { - EXT4_ERROR_INODE(inode, "newblock == 0!"); - err = -EFSCORRUPTED; - goto cleanup; - } - bh = sb_getblk_gfp(inode->i_sb, newblock, __GFP_MOVABLE | GFP_NOFS); - if (unlikely(!bh)) { - err = -ENOMEM; - goto cleanup; - } - lock_buffer(bh); - - err = ext4_journal_get_create_access(handle, bh); - if (err) - goto cleanup; - - neh = ext_block_hdr(bh); - neh->eh_entries = 0; - neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0)); - neh->eh_magic = EXT4_EXT_MAGIC; - neh->eh_depth = 0; - - /* move remainder of path[depth] to the new leaf */ - if (unlikely(path[depth].p_hdr->eh_entries != - path[depth].p_hdr->eh_max)) { - EXT4_ERROR_INODE(inode, "eh_entries %d != eh_max %d!", - path[depth].p_hdr->eh_entries, - path[depth].p_hdr->eh_max); - err = -EFSCORRUPTED; - goto cleanup; - } - /* start copy from next extent */ - m = EXT_MAX_EXTENT(path[depth].p_hdr) - path[depth].p_ext++; - ext4_ext_show_move(inode, path, newblock, depth); - if (m) { - struct ext4_extent *ex; - ex = EXT_FIRST_EXTENT(neh); - memmove(ex, path[depth].p_ext, sizeof(struct ext4_extent) * m); - le16_add_cpu(&neh->eh_entries, m); - } - - ext4_extent_block_csum_set(inode, neh); - set_buffer_uptodate(bh); - unlock_buffer(bh); - - err = ext4_handle_dirty_metadata(handle, inode, bh); - if (err) - goto cleanup; - brelse(bh); - bh = NULL; - - /* correct old leaf */ - if (m) { - err = ext4_ext_get_access(handle, inode, path + depth); - if (err) - goto cleanup; - le16_add_cpu(&path[depth].p_hdr->eh_entries, -m); - err = ext4_ext_dirty(handle, inode, path + depth); - if (err) - goto cleanup; - - } - - /* create intermediate indexes */ - k = depth - at - 1; - if (unlikely(k < 0)) { - EXT4_ERROR_INODE(inode, "k %d < 0!", k); - err = -EFSCORRUPTED; - goto cleanup; - } - if (k) - ext_debug("create %d intermediate indices\n", k); - /* insert new index into current index block */ - /* current depth stored in i var */ - i = depth - 1; - while (k--) { - oldblock = newblock; - newblock = ablocks[--a]; - bh = sb_getblk(inode->i_sb, newblock); - if (unlikely(!bh)) { - err = -ENOMEM; - goto cleanup; - } - lock_buffer(bh); - - err = ext4_journal_get_create_access(handle, bh); - if (err) - goto cleanup; - - neh = ext_block_hdr(bh); - neh->eh_entries = cpu_to_le16(1); - neh->eh_magic = EXT4_EXT_MAGIC; - neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode, 0)); - neh->eh_depth = cpu_to_le16(depth - i); - fidx = EXT_FIRST_INDEX(neh); - fidx->ei_block = border; - ext4_idx_store_pblock(fidx, oldblock); - - ext_debug("int.index at %d (block %llu): %u -> %llu\n", - i, newblock, le32_to_cpu(border), oldblock); - - /* move remainder of path[i] to the new index block */ - if (unlikely(EXT_MAX_INDEX(path[i].p_hdr) != - EXT_LAST_INDEX(path[i].p_hdr))) { - EXT4_ERROR_INODE(inode, - "EXT_MAX_INDEX != EXT_LAST_INDEX ee_block %d!", - le32_to_cpu(path[i].p_ext->ee_block)); - err = -EFSCORRUPTED; - goto cleanup; - } - /* start copy indexes */ - m = EXT_MAX_INDEX(path[i].p_hdr) - path[i].p_idx++; - ext_debug("cur 0x%p, last 0x%p\n", path[i].p_idx, - EXT_MAX_INDEX(path[i].p_hdr)); - ext4_ext_show_move(inode, path, newblock, i); - if (m) { - memmove(++fidx, path[i].p_idx, - sizeof(struct ext4_extent_idx) * m); - le16_add_cpu(&neh->eh_entries, m); - } - ext4_extent_block_csum_set(inode, neh); - set_buffer_uptodate(bh); - unlock_buffer(bh); - - err = ext4_handle_dirty_metadata(handle, inode, bh); - if (err) - goto cleanup; - brelse(bh); - bh = NULL; - - /* correct old index */ - if (m) { - err = ext4_ext_get_access(handle, inode, path + i); - if (err) - goto cleanup; - le16_add_cpu(&path[i].p_hdr->eh_entries, -m); - err = ext4_ext_dirty(handle, inode, path + i); - if (err) - goto cleanup; - } - - i--; - } - - /* insert new index */ - err = ext4_ext_insert_index(handle, inode, path + at, - le32_to_cpu(border), newblock); - -cleanup: - if (bh) { - if (buffer_locked(bh)) - unlock_buffer(bh); - brelse(bh); - } - - if (err) { - /* free all allocated blocks in error case */ - for (i = 0; i < depth; i++) { - if (!ablocks[i]) - continue; - ext4_free_blocks(handle, inode, NULL, ablocks[i], 1, - EXT4_FREE_BLOCKS_METADATA); - } - } - kfree(ablocks); - - return err; -} - -/* - * ext4_ext_grow_indepth: - * implements tree growing procedure: - * - allocates new block - * - moves top-level data (index block or leaf) into the new block - * - initializes new top-level, creating index that points to the - * just created block - */ -static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode, - unsigned int flags) -{ - struct ext4_extent_header *neh; - struct buffer_head *bh; - ext4_fsblk_t newblock, goal = 0; - struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es; - int err = 0; - - /* Try to prepend new index to old one */ - if (ext_depth(inode)) - goal = ext4_idx_pblock(EXT_FIRST_INDEX(ext_inode_hdr(inode))); - if (goal > le32_to_cpu(es->s_first_data_block)) { - flags |= EXT4_MB_HINT_TRY_GOAL; - goal--; - } else - goal = ext4_inode_to_goal_block(inode); - newblock = ext4_new_meta_blocks(handle, inode, goal, flags, - NULL, &err); - if (newblock == 0) - return err; - - bh = sb_getblk_gfp(inode->i_sb, newblock, __GFP_MOVABLE | GFP_NOFS); - if (unlikely(!bh)) - return -ENOMEM; - lock_buffer(bh); - - err = ext4_journal_get_create_access(handle, bh); - if (err) { - unlock_buffer(bh); - goto out; - } - - /* move top-level index/leaf into new block */ - memmove(bh->b_data, EXT4_I(inode)->i_data, - sizeof(EXT4_I(inode)->i_data)); - - /* set size of new block */ - neh = ext_block_hdr(bh); - /* old root could have indexes or leaves - * so calculate e_max right way */ - if (ext_depth(inode)) - neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode, 0)); - else - neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0)); - neh->eh_magic = EXT4_EXT_MAGIC; - ext4_extent_block_csum_set(inode, neh); - set_buffer_uptodate(bh); - unlock_buffer(bh); - - err = ext4_handle_dirty_metadata(handle, inode, bh); - if (err) - goto out; - - /* Update top-level index: num,max,pointer */ - neh = ext_inode_hdr(inode); - neh->eh_entries = cpu_to_le16(1); - ext4_idx_store_pblock(EXT_FIRST_INDEX(neh), newblock); - if (neh->eh_depth == 0) { - /* Root extent block becomes index block */ - neh->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode, 0)); - EXT_FIRST_INDEX(neh)->ei_block = - EXT_FIRST_EXTENT(neh)->ee_block; - } - ext_debug("new root: num %d(%d), lblock %d, ptr %llu\n", - le16_to_cpu(neh->eh_entries), le16_to_cpu(neh->eh_max), - le32_to_cpu(EXT_FIRST_INDEX(neh)->ei_block), - ext4_idx_pblock(EXT_FIRST_INDEX(neh))); - - le16_add_cpu(&neh->eh_depth, 1); - ext4_mark_inode_dirty(handle, inode); -out: - brelse(bh); - - return err; -} - -/* - * ext4_ext_create_new_leaf: - * finds empty index and adds new leaf. - * if no free index is found, then it requests in-depth growing. - */ -static int ext4_ext_create_new_leaf(handle_t *handle, struct inode *inode, - unsigned int mb_flags, - unsigned int gb_flags, - struct ext4_ext_path **ppath, - struct ext4_extent *newext) -{ - struct ext4_ext_path *path = *ppath; - struct ext4_ext_path *curp; - int depth, i, err = 0; - -repeat: - i = depth = ext_depth(inode); - - /* walk up to the tree and look for free index entry */ - curp = path + depth; - while (i > 0 && !EXT_HAS_FREE_INDEX(curp)) { - i--; - curp--; - } - - /* we use already allocated block for index block, - * so subsequent data blocks should be contiguous */ - if (EXT_HAS_FREE_INDEX(curp)) { - /* if we found index with free entry, then use that - * entry: create all needed subtree and add new leaf */ - err = ext4_ext_split(handle, inode, mb_flags, path, newext, i); - if (err) - goto out; - - /* refill path */ - path = ext4_find_extent(inode, - (ext4_lblk_t)le32_to_cpu(newext->ee_block), - ppath, gb_flags); - if (IS_ERR(path)) - err = PTR_ERR(path); - } else { - /* tree is full, time to grow in depth */ - err = ext4_ext_grow_indepth(handle, inode, mb_flags); - if (err) - goto out; - - /* refill path */ - path = ext4_find_extent(inode, - (ext4_lblk_t)le32_to_cpu(newext->ee_block), - ppath, gb_flags); - if (IS_ERR(path)) { - err = PTR_ERR(path); - goto out; - } - - /* - * only first (depth 0 -> 1) produces free space; - * in all other cases we have to split the grown tree - */ - depth = ext_depth(inode); - if (path[depth].p_hdr->eh_entries == path[depth].p_hdr->eh_max) { - /* now we need to split */ - goto repeat; - } - } - -out: - return err; -} - -/* - * search the closest allocated block to the left for *logical - * and returns it at @logical + it's physical address at @phys - * if *logical is the smallest allocated block, the function - * returns 0 at @phys - * return value contains 0 (success) or error code - */ -static int ext4_ext_search_left(struct inode *inode, - struct ext4_ext_path *path, - ext4_lblk_t *logical, ext4_fsblk_t *phys) -{ - struct ext4_extent_idx *ix; - struct ext4_extent *ex; - int depth, ee_len; - - if (unlikely(path == NULL)) { - EXT4_ERROR_INODE(inode, "path == NULL *logical %d!", *logical); - return -EFSCORRUPTED; - } - depth = path->p_depth; - *phys = 0; - - if (depth == 0 && path->p_ext == NULL) - return 0; - - /* usually extent in the path covers blocks smaller - * then *logical, but it can be that extent is the - * first one in the file */ - - ex = path[depth].p_ext; - ee_len = ext4_ext_get_actual_len(ex); - if (*logical < le32_to_cpu(ex->ee_block)) { - if (unlikely(EXT_FIRST_EXTENT(path[depth].p_hdr) != ex)) { - EXT4_ERROR_INODE(inode, - "EXT_FIRST_EXTENT != ex *logical %d ee_block %d!", - *logical, le32_to_cpu(ex->ee_block)); - return -EFSCORRUPTED; - } - while (--depth >= 0) { - ix = path[depth].p_idx; - if (unlikely(ix != EXT_FIRST_INDEX(path[depth].p_hdr))) { - EXT4_ERROR_INODE(inode, - "ix (%d) != EXT_FIRST_INDEX (%d) (depth %d)!", - ix != NULL ? le32_to_cpu(ix->ei_block) : 0, - EXT_FIRST_INDEX(path[depth].p_hdr) != NULL ? - le32_to_cpu(EXT_FIRST_INDEX(path[depth].p_hdr)->ei_block) : 0, - depth); - return -EFSCORRUPTED; - } - } - return 0; - } - - if (unlikely(*logical < (le32_to_cpu(ex->ee_block) + ee_len))) { - EXT4_ERROR_INODE(inode, - "logical %d < ee_block %d + ee_len %d!", - *logical, le32_to_cpu(ex->ee_block), ee_len); - return -EFSCORRUPTED; - } - - *logical = le32_to_cpu(ex->ee_block) + ee_len - 1; - *phys = ext4_ext_pblock(ex) + ee_len - 1; - return 0; -} - -/* - * search the closest allocated block to the right for *logical - * and returns it at @logical + it's physical address at @phys - * if *logical is the largest allocated block, the function - * returns 0 at @phys - * return value contains 0 (success) or error code - */ -static int ext4_ext_search_right(struct inode *inode, - struct ext4_ext_path *path, - ext4_lblk_t *logical, ext4_fsblk_t *phys, - struct ext4_extent **ret_ex) -{ - struct buffer_head *bh = NULL; - struct ext4_extent_header *eh; - struct ext4_extent_idx *ix; - struct ext4_extent *ex; - ext4_fsblk_t block; - int depth; /* Note, NOT eh_depth; depth from top of tree */ - int ee_len; - - if (unlikely(path == NULL)) { - EXT4_ERROR_INODE(inode, "path == NULL *logical %d!", *logical); - return -EFSCORRUPTED; - } - depth = path->p_depth; - *phys = 0; - - if (depth == 0 && path->p_ext == NULL) - return 0; - - /* usually extent in the path covers blocks smaller - * then *logical, but it can be that extent is the - * first one in the file */ - - ex = path[depth].p_ext; - ee_len = ext4_ext_get_actual_len(ex); - if (*logical < le32_to_cpu(ex->ee_block)) { - if (unlikely(EXT_FIRST_EXTENT(path[depth].p_hdr) != ex)) { - EXT4_ERROR_INODE(inode, - "first_extent(path[%d].p_hdr) != ex", - depth); - return -EFSCORRUPTED; - } - while (--depth >= 0) { - ix = path[depth].p_idx; - if (unlikely(ix != EXT_FIRST_INDEX(path[depth].p_hdr))) { - EXT4_ERROR_INODE(inode, - "ix != EXT_FIRST_INDEX *logical %d!", - *logical); - return -EFSCORRUPTED; - } - } - goto found_extent; - } - - if (unlikely(*logical < (le32_to_cpu(ex->ee_block) + ee_len))) { - EXT4_ERROR_INODE(inode, - "logical %d < ee_block %d + ee_len %d!", - *logical, le32_to_cpu(ex->ee_block), ee_len); - return -EFSCORRUPTED; - } - - if (ex != EXT_LAST_EXTENT(path[depth].p_hdr)) { - /* next allocated block in this leaf */ - ex++; - goto found_extent; - } - - /* go up and search for index to the right */ - while (--depth >= 0) { - ix = path[depth].p_idx; - if (ix != EXT_LAST_INDEX(path[depth].p_hdr)) - goto got_index; - } - - /* we've gone up to the root and found no index to the right */ - return 0; - -got_index: - /* we've found index to the right, let's - * follow it and find the closest allocated - * block to the right */ - ix++; - block = ext4_idx_pblock(ix); - while (++depth < path->p_depth) { - /* subtract from p_depth to get proper eh_depth */ - bh = read_extent_tree_block(inode, block, - path->p_depth - depth, 0); - if (IS_ERR(bh)) - return PTR_ERR(bh); - eh = ext_block_hdr(bh); - ix = EXT_FIRST_INDEX(eh); - block = ext4_idx_pblock(ix); - put_bh(bh); - } - - bh = read_extent_tree_block(inode, block, path->p_depth - depth, 0); - if (IS_ERR(bh)) - return PTR_ERR(bh); - eh = ext_block_hdr(bh); - ex = EXT_FIRST_EXTENT(eh); -found_extent: - *logical = le32_to_cpu(ex->ee_block); - *phys = ext4_ext_pblock(ex); - *ret_ex = ex; - if (bh) - put_bh(bh); - return 0; -} - -/* - * ext4_ext_next_allocated_block: - * returns allocated block in subsequent extent or EXT_MAX_BLOCKS. - * NOTE: it considers block number from index entry as - * allocated block. Thus, index entries have to be consistent - * with leaves. - */ -ext4_lblk_t -ext4_ext_next_allocated_block(struct ext4_ext_path *path) -{ - int depth; - - BUG_ON(path == NULL); - depth = path->p_depth; - - if (depth == 0 && path->p_ext == NULL) - return EXT_MAX_BLOCKS; - - while (depth >= 0) { - if (depth == path->p_depth) { - /* leaf */ - if (path[depth].p_ext && - path[depth].p_ext != - EXT_LAST_EXTENT(path[depth].p_hdr)) - return le32_to_cpu(path[depth].p_ext[1].ee_block); - } else { - /* index */ - if (path[depth].p_idx != - EXT_LAST_INDEX(path[depth].p_hdr)) - return le32_to_cpu(path[depth].p_idx[1].ei_block); - } - depth--; - } - - return EXT_MAX_BLOCKS; -} - -/* - * ext4_ext_next_leaf_block: - * returns first allocated block from next leaf or EXT_MAX_BLOCKS - */ -static ext4_lblk_t ext4_ext_next_leaf_block(struct ext4_ext_path *path) -{ - int depth; - - BUG_ON(path == NULL); - depth = path->p_depth; - - /* zero-tree has no leaf blocks at all */ - if (depth == 0) - return EXT_MAX_BLOCKS; - - /* go to index block */ - depth--; - - while (depth >= 0) { - if (path[depth].p_idx != - EXT_LAST_INDEX(path[depth].p_hdr)) - return (ext4_lblk_t) - le32_to_cpu(path[depth].p_idx[1].ei_block); - depth--; - } - - return EXT_MAX_BLOCKS; -} - -/* - * ext4_ext_correct_indexes: - * if leaf gets modified and modified extent is first in the leaf, - * then we have to correct all indexes above. - * TODO: do we need to correct tree in all cases? - */ -static int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode, - struct ext4_ext_path *path) -{ - struct ext4_extent_header *eh; - int depth = ext_depth(inode); - struct ext4_extent *ex; - __le32 border; - int k, err = 0; - - eh = path[depth].p_hdr; - ex = path[depth].p_ext; - - if (unlikely(ex == NULL || eh == NULL)) { - EXT4_ERROR_INODE(inode, - "ex %p == NULL or eh %p == NULL", ex, eh); - return -EFSCORRUPTED; - } - - if (depth == 0) { - /* there is no tree at all */ - return 0; - } - - if (ex != EXT_FIRST_EXTENT(eh)) { - /* we correct tree if first leaf got modified only */ - return 0; - } - - /* - * TODO: we need correction if border is smaller than current one - */ - k = depth - 1; - border = path[depth].p_ext->ee_block; - err = ext4_ext_get_access(handle, inode, path + k); - if (err) - return err; - path[k].p_idx->ei_block = border; - err = ext4_ext_dirty(handle, inode, path + k); - if (err) - return err; - - while (k--) { - /* change all left-side indexes */ - if (path[k+1].p_idx != EXT_FIRST_INDEX(path[k+1].p_hdr)) - break; - err = ext4_ext_get_access(handle, inode, path + k); - if (err) - break; - path[k].p_idx->ei_block = border; - err = ext4_ext_dirty(handle, inode, path + k); - if (err) - break; - } - - return err; -} - -int -ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1, - struct ext4_extent *ex2) -{ - unsigned short ext1_ee_len, ext2_ee_len; - - if (ext4_ext_is_unwritten(ex1) != ext4_ext_is_unwritten(ex2)) - return 0; - - ext1_ee_len = ext4_ext_get_actual_len(ex1); - ext2_ee_len = ext4_ext_get_actual_len(ex2); - - if (le32_to_cpu(ex1->ee_block) + ext1_ee_len != - le32_to_cpu(ex2->ee_block)) - return 0; - - /* - * To allow future support for preallocated extents to be added - * as an RO_COMPAT feature, refuse to merge to extents if - * this can result in the top bit of ee_len being set. - */ - if (ext1_ee_len + ext2_ee_len > EXT_INIT_MAX_LEN) - return 0; - /* - * The check for IO to unwritten extent is somewhat racy as we - * increment i_unwritten / set EXT4_STATE_DIO_UNWRITTEN only after - * dropping i_data_sem. But reserved blocks should save us in that - * case. - */ - if (ext4_ext_is_unwritten(ex1) && - (ext4_test_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN) || - atomic_read(&EXT4_I(inode)->i_unwritten) || - (ext1_ee_len + ext2_ee_len > EXT_UNWRITTEN_MAX_LEN))) - return 0; -#ifdef AGGRESSIVE_TEST - if (ext1_ee_len >= 4) - return 0; -#endif - - if (ext4_ext_pblock(ex1) + ext1_ee_len == ext4_ext_pblock(ex2)) - return 1; - return 0; -} - -/* - * This function tries to merge the "ex" extent to the next extent in the tree. - * It always tries to merge towards right. If you want to merge towards - * left, pass "ex - 1" as argument instead of "ex". - * Returns 0 if the extents (ex and ex+1) were _not_ merged and returns - * 1 if they got merged. - */ -static int ext4_ext_try_to_merge_right(struct inode *inode, - struct ext4_ext_path *path, - struct ext4_extent *ex) -{ - struct ext4_extent_header *eh; - unsigned int depth, len; - int merge_done = 0, unwritten; - - depth = ext_depth(inode); - BUG_ON(path[depth].p_hdr == NULL); - eh = path[depth].p_hdr; - - while (ex < EXT_LAST_EXTENT(eh)) { - if (!ext4_can_extents_be_merged(inode, ex, ex + 1)) - break; - /* merge with next extent! */ - unwritten = ext4_ext_is_unwritten(ex); - ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex) - + ext4_ext_get_actual_len(ex + 1)); - if (unwritten) - ext4_ext_mark_unwritten(ex); - - if (ex + 1 < EXT_LAST_EXTENT(eh)) { - len = (EXT_LAST_EXTENT(eh) - ex - 1) - * sizeof(struct ext4_extent); - memmove(ex + 1, ex + 2, len); - } - le16_add_cpu(&eh->eh_entries, -1); - merge_done = 1; - WARN_ON(eh->eh_entries == 0); - if (!eh->eh_entries) - EXT4_ERROR_INODE(inode, "eh->eh_entries = 0!"); - } - - return merge_done; -} - -/* - * This function does a very simple check to see if we can collapse - * an extent tree with a single extent tree leaf block into the inode. - */ -static void ext4_ext_try_to_merge_up(handle_t *handle, - struct inode *inode, - struct ext4_ext_path *path) -{ - size_t s; - unsigned max_root = ext4_ext_space_root(inode, 0); - ext4_fsblk_t blk; - - if ((path[0].p_depth != 1) || - (le16_to_cpu(path[0].p_hdr->eh_entries) != 1) || - (le16_to_cpu(path[1].p_hdr->eh_entries) > max_root)) - return; - - /* - * We need to modify the block allocation bitmap and the block - * group descriptor to release the extent tree block. If we - * can't get the journal credits, give up. - */ - if (ext4_journal_extend(handle, 2)) - return; - - /* - * Copy the extent data up to the inode - */ - blk = ext4_idx_pblock(path[0].p_idx); - s = le16_to_cpu(path[1].p_hdr->eh_entries) * - sizeof(struct ext4_extent_idx); - s += sizeof(struct ext4_extent_header); - - path[1].p_maxdepth = path[0].p_maxdepth; - memcpy(path[0].p_hdr, path[1].p_hdr, s); - path[0].p_depth = 0; - path[0].p_ext = EXT_FIRST_EXTENT(path[0].p_hdr) + - (path[1].p_ext - EXT_FIRST_EXTENT(path[1].p_hdr)); - path[0].p_hdr->eh_max = cpu_to_le16(max_root); - - brelse(path[1].p_bh); - ext4_free_blocks(handle, inode, NULL, blk, 1, - EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET); -} - -/* - * This function tries to merge the @ex extent to neighbours in the tree. - * return 1 if merge left else 0. - */ -static void ext4_ext_try_to_merge(handle_t *handle, - struct inode *inode, - struct ext4_ext_path *path, - struct ext4_extent *ex) { - struct ext4_extent_header *eh; - unsigned int depth; - int merge_done = 0; - - depth = ext_depth(inode); - BUG_ON(path[depth].p_hdr == NULL); - eh = path[depth].p_hdr; - - if (ex > EXT_FIRST_EXTENT(eh)) - merge_done = ext4_ext_try_to_merge_right(inode, path, ex - 1); - - if (!merge_done) - (void) ext4_ext_try_to_merge_right(inode, path, ex); - - ext4_ext_try_to_merge_up(handle, inode, path); -} - -/* - * check if a portion of the "newext" extent overlaps with an - * existing extent. - * - * If there is an overlap discovered, it updates the length of the newext - * such that there will be no overlap, and then returns 1. - * If there is no overlap found, it returns 0. - */ -static unsigned int ext4_ext_check_overlap(struct ext4_sb_info *sbi, - struct inode *inode, - struct ext4_extent *newext, - struct ext4_ext_path *path) -{ - ext4_lblk_t b1, b2; - unsigned int depth, len1; - unsigned int ret = 0; - - b1 = le32_to_cpu(newext->ee_block); - len1 = ext4_ext_get_actual_len(newext); - depth = ext_depth(inode); - if (!path[depth].p_ext) - goto out; - b2 = EXT4_LBLK_CMASK(sbi, le32_to_cpu(path[depth].p_ext->ee_block)); - - /* - * get the next allocated block if the extent in the path - * is before the requested block(s) - */ - if (b2 < b1) { - b2 = ext4_ext_next_allocated_block(path); - if (b2 == EXT_MAX_BLOCKS) - goto out; - b2 = EXT4_LBLK_CMASK(sbi, b2); - } - - /* check for wrap through zero on extent logical start block*/ - if (b1 + len1 < b1) { - len1 = EXT_MAX_BLOCKS - b1; - newext->ee_len = cpu_to_le16(len1); - ret = 1; - } - - /* check for overlap */ - if (b1 + len1 > b2) { - newext->ee_len = cpu_to_le16(b2 - b1); - ret = 1; - } -out: - return ret; -} - -/* - * ext4_ext_insert_extent: - * tries to merge requsted extent into the existing extent or - * inserts requested extent as new one into the tree, - * creating new leaf in the no-space case. - */ -int ext4_ext_insert_extent(handle_t *handle, struct inode *inode, - struct ext4_ext_path **ppath, - struct ext4_extent *newext, int gb_flags) -{ - struct ext4_ext_path *path = *ppath; - struct ext4_extent_header *eh; - struct ext4_extent *ex, *fex; - struct ext4_extent *nearex; /* nearest extent */ - struct ext4_ext_path *npath = NULL; - int depth, len, err; - ext4_lblk_t next; - int mb_flags = 0, unwritten; - - if (gb_flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) - mb_flags |= EXT4_MB_DELALLOC_RESERVED; - if (unlikely(ext4_ext_get_actual_len(newext) == 0)) { - EXT4_ERROR_INODE(inode, "ext4_ext_get_actual_len(newext) == 0"); - return -EFSCORRUPTED; - } - depth = ext_depth(inode); - ex = path[depth].p_ext; - eh = path[depth].p_hdr; - if (unlikely(path[depth].p_hdr == NULL)) { - EXT4_ERROR_INODE(inode, "path[%d].p_hdr == NULL", depth); - return -EFSCORRUPTED; - } - - /* try to insert block into found extent and return */ - if (ex && !(gb_flags & EXT4_GET_BLOCKS_PRE_IO)) { - - /* - * Try to see whether we should rather test the extent on - * right from ex, or from the left of ex. This is because - * ext4_find_extent() can return either extent on the - * left, or on the right from the searched position. This - * will make merging more effective. - */ - if (ex < EXT_LAST_EXTENT(eh) && - (le32_to_cpu(ex->ee_block) + - ext4_ext_get_actual_len(ex) < - le32_to_cpu(newext->ee_block))) { - ex += 1; - goto prepend; - } else if ((ex > EXT_FIRST_EXTENT(eh)) && - (le32_to_cpu(newext->ee_block) + - ext4_ext_get_actual_len(newext) < - le32_to_cpu(ex->ee_block))) - ex -= 1; - - /* Try to append newex to the ex */ - if (ext4_can_extents_be_merged(inode, ex, newext)) { - ext_debug("append [%d]%d block to %u:[%d]%d" - "(from %llu)\n", - ext4_ext_is_unwritten(newext), - ext4_ext_get_actual_len(newext), - le32_to_cpu(ex->ee_block), - ext4_ext_is_unwritten(ex), - ext4_ext_get_actual_len(ex), - ext4_ext_pblock(ex)); - err = ext4_ext_get_access(handle, inode, - path + depth); - if (err) - return err; - unwritten = ext4_ext_is_unwritten(ex); - ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex) - + ext4_ext_get_actual_len(newext)); - if (unwritten) - ext4_ext_mark_unwritten(ex); - eh = path[depth].p_hdr; - nearex = ex; - goto merge; - } - -prepend: - /* Try to prepend newex to the ex */ - if (ext4_can_extents_be_merged(inode, newext, ex)) { - ext_debug("prepend %u[%d]%d block to %u:[%d]%d" - "(from %llu)\n", - le32_to_cpu(newext->ee_block), - ext4_ext_is_unwritten(newext), - ext4_ext_get_actual_len(newext), - le32_to_cpu(ex->ee_block), - ext4_ext_is_unwritten(ex), - ext4_ext_get_actual_len(ex), - ext4_ext_pblock(ex)); - err = ext4_ext_get_access(handle, inode, - path + depth); - if (err) - return err; - - unwritten = ext4_ext_is_unwritten(ex); - ex->ee_block = newext->ee_block; - ext4_ext_store_pblock(ex, ext4_ext_pblock(newext)); - ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex) - + ext4_ext_get_actual_len(newext)); - if (unwritten) - ext4_ext_mark_unwritten(ex); - eh = path[depth].p_hdr; - nearex = ex; - goto merge; - } - } - - depth = ext_depth(inode); - eh = path[depth].p_hdr; - if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max)) - goto has_space; - - /* probably next leaf has space for us? */ - fex = EXT_LAST_EXTENT(eh); - next = EXT_MAX_BLOCKS; - if (le32_to_cpu(newext->ee_block) > le32_to_cpu(fex->ee_block)) - next = ext4_ext_next_leaf_block(path); - if (next != EXT_MAX_BLOCKS) { - ext_debug("next leaf block - %u\n", next); - BUG_ON(npath != NULL); - npath = ext4_find_extent(inode, next, NULL, 0); - if (IS_ERR(npath)) - return PTR_ERR(npath); - BUG_ON(npath->p_depth != path->p_depth); - eh = npath[depth].p_hdr; - if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max)) { - ext_debug("next leaf isn't full(%d)\n", - le16_to_cpu(eh->eh_entries)); - path = npath; - goto has_space; - } - ext_debug("next leaf has no free space(%d,%d)\n", - le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max)); - } - - /* - * There is no free space in the found leaf. - * We're gonna add a new leaf in the tree. - */ - if (gb_flags & EXT4_GET_BLOCKS_METADATA_NOFAIL) - mb_flags |= EXT4_MB_USE_RESERVED; - err = ext4_ext_create_new_leaf(handle, inode, mb_flags, gb_flags, - ppath, newext); - if (err) - goto cleanup; - depth = ext_depth(inode); - eh = path[depth].p_hdr; - -has_space: - nearex = path[depth].p_ext; - - err = ext4_ext_get_access(handle, inode, path + depth); - if (err) - goto cleanup; - - if (!nearex) { - /* there is no extent in this leaf, create first one */ - ext_debug("first extent in the leaf: %u:%llu:[%d]%d\n", - le32_to_cpu(newext->ee_block), - ext4_ext_pblock(newext), - ext4_ext_is_unwritten(newext), - ext4_ext_get_actual_len(newext)); - nearex = EXT_FIRST_EXTENT(eh); - } else { - if (le32_to_cpu(newext->ee_block) - > le32_to_cpu(nearex->ee_block)) { - /* Insert after */ - ext_debug("insert %u:%llu:[%d]%d before: " - "nearest %p\n", - le32_to_cpu(newext->ee_block), - ext4_ext_pblock(newext), - ext4_ext_is_unwritten(newext), - ext4_ext_get_actual_len(newext), - nearex); - nearex++; - } else { - /* Insert before */ - BUG_ON(newext->ee_block == nearex->ee_block); - ext_debug("insert %u:%llu:[%d]%d after: " - "nearest %p\n", - le32_to_cpu(newext->ee_block), - ext4_ext_pblock(newext), - ext4_ext_is_unwritten(newext), - ext4_ext_get_actual_len(newext), - nearex); - } - len = EXT_LAST_EXTENT(eh) - nearex + 1; - if (len > 0) { - ext_debug("insert %u:%llu:[%d]%d: " - "move %d extents from 0x%p to 0x%p\n", - le32_to_cpu(newext->ee_block), - ext4_ext_pblock(newext), - ext4_ext_is_unwritten(newext), - ext4_ext_get_actual_len(newext), - len, nearex, nearex + 1); - memmove(nearex + 1, nearex, - len * sizeof(struct ext4_extent)); - } - } - - le16_add_cpu(&eh->eh_entries, 1); - path[depth].p_ext = nearex; - nearex->ee_block = newext->ee_block; - ext4_ext_store_pblock(nearex, ext4_ext_pblock(newext)); - nearex->ee_len = newext->ee_len; - -merge: - /* try to merge extents */ - if (!(gb_flags & EXT4_GET_BLOCKS_PRE_IO)) - ext4_ext_try_to_merge(handle, inode, path, nearex); - - - /* time to correct all indexes above */ - err = ext4_ext_correct_indexes(handle, inode, path); - if (err) - goto cleanup; - - err = ext4_ext_dirty(handle, inode, path + path->p_depth); - -cleanup: - ext4_ext_drop_refs(npath); - kfree(npath); - return err; -} - -static int ext4_fill_fiemap_extents(struct inode *inode, - ext4_lblk_t block, ext4_lblk_t num, - struct fiemap_extent_info *fieinfo) -{ - struct ext4_ext_path *path = NULL; - struct ext4_extent *ex; - struct extent_status es; - ext4_lblk_t next, next_del, start = 0, end = 0; - ext4_lblk_t last = block + num; - int exists, depth = 0, err = 0; - unsigned int flags = 0; - unsigned char blksize_bits = inode->i_sb->s_blocksize_bits; - - while (block < last && block != EXT_MAX_BLOCKS) { - num = last - block; - /* find extent for this block */ - down_read(&EXT4_I(inode)->i_data_sem); - - path = ext4_find_extent(inode, block, &path, 0); - if (IS_ERR(path)) { - up_read(&EXT4_I(inode)->i_data_sem); - err = PTR_ERR(path); - path = NULL; - break; - } - - depth = ext_depth(inode); - if (unlikely(path[depth].p_hdr == NULL)) { - up_read(&EXT4_I(inode)->i_data_sem); - EXT4_ERROR_INODE(inode, "path[%d].p_hdr == NULL", depth); - err = -EFSCORRUPTED; - break; - } - ex = path[depth].p_ext; - next = ext4_ext_next_allocated_block(path); - - flags = 0; - exists = 0; - if (!ex) { - /* there is no extent yet, so try to allocate - * all requested space */ - start = block; - end = block + num; - } else if (le32_to_cpu(ex->ee_block) > block) { - /* need to allocate space before found extent */ - start = block; - end = le32_to_cpu(ex->ee_block); - if (block + num < end) - end = block + num; - } else if (block >= le32_to_cpu(ex->ee_block) - + ext4_ext_get_actual_len(ex)) { - /* need to allocate space after found extent */ - start = block; - end = block + num; - if (end >= next) - end = next; - } else if (block >= le32_to_cpu(ex->ee_block)) { - /* - * some part of requested space is covered - * by found extent - */ - start = block; - end = le32_to_cpu(ex->ee_block) - + ext4_ext_get_actual_len(ex); - if (block + num < end) - end = block + num; - exists = 1; - } else { - BUG(); - } - BUG_ON(end <= start); - - if (!exists) { - es.es_lblk = start; - es.es_len = end - start; - es.es_pblk = 0; - } else { - es.es_lblk = le32_to_cpu(ex->ee_block); - es.es_len = ext4_ext_get_actual_len(ex); - es.es_pblk = ext4_ext_pblock(ex); - if (ext4_ext_is_unwritten(ex)) - flags |= FIEMAP_EXTENT_UNWRITTEN; - } - - /* - * Find delayed extent and update es accordingly. We call - * it even in !exists case to find out whether es is the - * last existing extent or not. - */ - next_del = ext4_find_delayed_extent(inode, &es); - if (!exists && next_del) { - exists = 1; - flags |= (FIEMAP_EXTENT_DELALLOC | - FIEMAP_EXTENT_UNKNOWN); - } - up_read(&EXT4_I(inode)->i_data_sem); - - if (unlikely(es.es_len == 0)) { - EXT4_ERROR_INODE(inode, "es.es_len == 0"); - err = -EFSCORRUPTED; - break; - } - - /* - * This is possible iff next == next_del == EXT_MAX_BLOCKS. - * we need to check next == EXT_MAX_BLOCKS because it is - * possible that an extent is with unwritten and delayed - * status due to when an extent is delayed allocated and - * is allocated by fallocate status tree will track both of - * them in a extent. - * - * So we could return a unwritten and delayed extent, and - * its block is equal to 'next'. - */ - if (next == next_del && next == EXT_MAX_BLOCKS) { - flags |= FIEMAP_EXTENT_LAST; - if (unlikely(next_del != EXT_MAX_BLOCKS || - next != EXT_MAX_BLOCKS)) { - EXT4_ERROR_INODE(inode, - "next extent == %u, next " - "delalloc extent = %u", - next, next_del); - err = -EFSCORRUPTED; - break; - } - } - - if (exists) { - err = fiemap_fill_next_extent(fieinfo, - (__u64)es.es_lblk << blksize_bits, - (__u64)es.es_pblk << blksize_bits, - (__u64)es.es_len << blksize_bits, - flags); - if (err < 0) - break; - if (err == 1) { - err = 0; - break; - } - } - - block = es.es_lblk + es.es_len; - } - - ext4_ext_drop_refs(path); - kfree(path); - return err; -} - -/* - * ext4_ext_determine_hole - determine hole around given block - * @inode: inode we lookup in - * @path: path in extent tree to @lblk - * @lblk: pointer to logical block around which we want to determine hole - * - * Determine hole length (and start if easily possible) around given logical - * block. We don't try too hard to find the beginning of the hole but @path - * actually points to extent before @lblk, we provide it. - * - * The function returns the length of a hole starting at @lblk. We update @lblk - * to the beginning of the hole if we managed to find it. - */ -static ext4_lblk_t ext4_ext_determine_hole(struct inode *inode, - struct ext4_ext_path *path, - ext4_lblk_t *lblk) -{ - int depth = ext_depth(inode); - struct ext4_extent *ex; - ext4_lblk_t len; - - ex = path[depth].p_ext; - if (ex == NULL) { - /* there is no extent yet, so gap is [0;-] */ - *lblk = 0; - len = EXT_MAX_BLOCKS; - } else if (*lblk < le32_to_cpu(ex->ee_block)) { - len = le32_to_cpu(ex->ee_block) - *lblk; - } else if (*lblk >= le32_to_cpu(ex->ee_block) - + ext4_ext_get_actual_len(ex)) { - ext4_lblk_t next; - - *lblk = le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex); - next = ext4_ext_next_allocated_block(path); - BUG_ON(next == *lblk); - len = next - *lblk; - } else { - BUG(); - } - return len; -} - -/* - * ext4_ext_put_gap_in_cache: - * calculate boundaries of the gap that the requested block fits into - * and cache this gap - */ -static void -ext4_ext_put_gap_in_cache(struct inode *inode, ext4_lblk_t hole_start, - ext4_lblk_t hole_len) -{ - struct extent_status es; - - ext4_es_find_delayed_extent_range(inode, hole_start, - hole_start + hole_len - 1, &es); - if (es.es_len) { - /* There's delayed extent containing lblock? */ - if (es.es_lblk <= hole_start) - return; - hole_len = min(es.es_lblk - hole_start, hole_len); - } - ext_debug(" -> %u:%u\n", hole_start, hole_len); - ext4_es_insert_extent(inode, hole_start, hole_len, ~0, - EXTENT_STATUS_HOLE); -} - -/* - * ext4_ext_rm_idx: - * removes index from the index block. - */ -static int ext4_ext_rm_idx(handle_t *handle, struct inode *inode, - struct ext4_ext_path *path, int depth) -{ - int err; - ext4_fsblk_t leaf; - - /* free index block */ - depth--; - path = path + depth; - leaf = ext4_idx_pblock(path->p_idx); - if (unlikely(path->p_hdr->eh_entries == 0)) { - EXT4_ERROR_INODE(inode, "path->p_hdr->eh_entries == 0"); - return -EFSCORRUPTED; - } - err = ext4_ext_get_access(handle, inode, path); - if (err) - return err; - - if (path->p_idx != EXT_LAST_INDEX(path->p_hdr)) { - int len = EXT_LAST_INDEX(path->p_hdr) - path->p_idx; - len *= sizeof(struct ext4_extent_idx); - memmove(path->p_idx, path->p_idx + 1, len); - } - - le16_add_cpu(&path->p_hdr->eh_entries, -1); - err = ext4_ext_dirty(handle, inode, path); - if (err) - return err; - ext_debug("index is empty, remove it, free block %llu\n", leaf); - trace_ext4_ext_rm_idx(inode, leaf); - - ext4_free_blocks(handle, inode, NULL, leaf, 1, - EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET); - - while (--depth >= 0) { - if (path->p_idx != EXT_FIRST_INDEX(path->p_hdr)) - break; - path--; - err = ext4_ext_get_access(handle, inode, path); - if (err) - break; - path->p_idx->ei_block = (path+1)->p_idx->ei_block; - err = ext4_ext_dirty(handle, inode, path); - if (err) - break; - } - return err; -} - -/* - * ext4_ext_calc_credits_for_single_extent: - * This routine returns max. credits that needed to insert an extent - * to the extent tree. - * When pass the actual path, the caller should calculate credits - * under i_data_sem. - */ -int ext4_ext_calc_credits_for_single_extent(struct inode *inode, int nrblocks, - struct ext4_ext_path *path) -{ - if (path) { - int depth = ext_depth(inode); - int ret = 0; - - /* probably there is space in leaf? */ - if (le16_to_cpu(path[depth].p_hdr->eh_entries) - < le16_to_cpu(path[depth].p_hdr->eh_max)) { - - /* - * There are some space in the leaf tree, no - * need to account for leaf block credit - * - * bitmaps and block group descriptor blocks - * and other metadata blocks still need to be - * accounted. - */ - /* 1 bitmap, 1 block group descriptor */ - ret = 2 + EXT4_META_TRANS_BLOCKS(inode->i_sb); - return ret; - } - } - - return ext4_chunk_trans_blocks(inode, nrblocks); -} - -/* - * How many index/leaf blocks need to change/allocate to add @extents extents? - * - * If we add a single extent, then in the worse case, each tree level - * index/leaf need to be changed in case of the tree split. - * - * If more extents are inserted, they could cause the whole tree split more - * than once, but this is really rare. - */ -int ext4_ext_index_trans_blocks(struct inode *inode, int extents) -{ - int index; - int depth; - - /* If we are converting the inline data, only one is needed here. */ - if (ext4_has_inline_data(inode)) - return 1; - - depth = ext_depth(inode); - - if (extents <= 1) - index = depth * 2; - else - index = depth * 3; - - return index; -} - -static inline int get_default_free_blocks_flags(struct inode *inode) -{ - if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) - return EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET; - else if (ext4_should_journal_data(inode)) - return EXT4_FREE_BLOCKS_FORGET; - return 0; -} - -static int ext4_remove_blocks(handle_t *handle, struct inode *inode, - struct ext4_extent *ex, - long long *partial_cluster, - ext4_lblk_t from, ext4_lblk_t to) -{ - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - unsigned short ee_len = ext4_ext_get_actual_len(ex); - ext4_fsblk_t pblk; - int flags = get_default_free_blocks_flags(inode); - - /* - * For bigalloc file systems, we never free a partial cluster - * at the beginning of the extent. Instead, we make a note - * that we tried freeing the cluster, and check to see if we - * need to free it on a subsequent call to ext4_remove_blocks, - * or at the end of ext4_ext_rm_leaf or ext4_ext_remove_space. - */ - flags |= EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER; - - trace_ext4_remove_blocks(inode, ex, from, to, *partial_cluster); - /* - * If we have a partial cluster, and it's different from the - * cluster of the last block, we need to explicitly free the - * partial cluster here. - */ - pblk = ext4_ext_pblock(ex) + ee_len - 1; - if (*partial_cluster > 0 && - *partial_cluster != (long long) EXT4_B2C(sbi, pblk)) { - ext4_free_blocks(handle, inode, NULL, - EXT4_C2B(sbi, *partial_cluster), - sbi->s_cluster_ratio, flags); - *partial_cluster = 0; - } - -#ifdef EXTENTS_STATS - { - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - spin_lock(&sbi->s_ext_stats_lock); - sbi->s_ext_blocks += ee_len; - sbi->s_ext_extents++; - if (ee_len < sbi->s_ext_min) - sbi->s_ext_min = ee_len; - if (ee_len > sbi->s_ext_max) - sbi->s_ext_max = ee_len; - if (ext_depth(inode) > sbi->s_depth_max) - sbi->s_depth_max = ext_depth(inode); - spin_unlock(&sbi->s_ext_stats_lock); - } -#endif - if (from >= le32_to_cpu(ex->ee_block) - && to == le32_to_cpu(ex->ee_block) + ee_len - 1) { - /* tail removal */ - ext4_lblk_t num; - long long first_cluster; - - num = le32_to_cpu(ex->ee_block) + ee_len - from; - pblk = ext4_ext_pblock(ex) + ee_len - num; - /* - * Usually we want to free partial cluster at the end of the - * extent, except for the situation when the cluster is still - * used by any other extent (partial_cluster is negative). - */ - if (*partial_cluster < 0 && - *partial_cluster == -(long long) EXT4_B2C(sbi, pblk+num-1)) - flags |= EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER; - - ext_debug("free last %u blocks starting %llu partial %lld\n", - num, pblk, *partial_cluster); - ext4_free_blocks(handle, inode, NULL, pblk, num, flags); - /* - * If the block range to be freed didn't start at the - * beginning of a cluster, and we removed the entire - * extent and the cluster is not used by any other extent, - * save the partial cluster here, since we might need to - * delete if we determine that the truncate or punch hole - * operation has removed all of the blocks in the cluster. - * If that cluster is used by another extent, preserve its - * negative value so it isn't freed later on. - * - * If the whole extent wasn't freed, we've reached the - * start of the truncated/punched region and have finished - * removing blocks. If there's a partial cluster here it's - * shared with the remainder of the extent and is no longer - * a candidate for removal. - */ - if (EXT4_PBLK_COFF(sbi, pblk) && ee_len == num) { - first_cluster = (long long) EXT4_B2C(sbi, pblk); - if (first_cluster != -*partial_cluster) - *partial_cluster = first_cluster; - } else { - *partial_cluster = 0; - } - } else - ext4_error(sbi->s_sb, "strange request: removal(2) " - "%u-%u from %u:%u", - from, to, le32_to_cpu(ex->ee_block), ee_len); - return 0; -} - - -/* - * ext4_ext_rm_leaf() Removes the extents associated with the - * blocks appearing between "start" and "end". Both "start" - * and "end" must appear in the same extent or EIO is returned. - * - * @handle: The journal handle - * @inode: The files inode - * @path: The path to the leaf - * @partial_cluster: The cluster which we'll have to free if all extents - * has been released from it. However, if this value is - * negative, it's a cluster just to the right of the - * punched region and it must not be freed. - * @start: The first block to remove - * @end: The last block to remove - */ -static int -ext4_ext_rm_leaf(handle_t *handle, struct inode *inode, - struct ext4_ext_path *path, - long long *partial_cluster, - ext4_lblk_t start, ext4_lblk_t end) -{ - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - int err = 0, correct_index = 0; - int depth = ext_depth(inode), credits; - struct ext4_extent_header *eh; - ext4_lblk_t a, b; - unsigned num; - ext4_lblk_t ex_ee_block; - unsigned short ex_ee_len; - unsigned unwritten = 0; - struct ext4_extent *ex; - ext4_fsblk_t pblk; - - /* the header must be checked already in ext4_ext_remove_space() */ - ext_debug("truncate since %u in leaf to %u\n", start, end); - if (!path[depth].p_hdr) - path[depth].p_hdr = ext_block_hdr(path[depth].p_bh); - eh = path[depth].p_hdr; - if (unlikely(path[depth].p_hdr == NULL)) { - EXT4_ERROR_INODE(inode, "path[%d].p_hdr == NULL", depth); - return -EFSCORRUPTED; - } - /* find where to start removing */ - ex = path[depth].p_ext; - if (!ex) - ex = EXT_LAST_EXTENT(eh); - - ex_ee_block = le32_to_cpu(ex->ee_block); - ex_ee_len = ext4_ext_get_actual_len(ex); - - trace_ext4_ext_rm_leaf(inode, start, ex, *partial_cluster); - - while (ex >= EXT_FIRST_EXTENT(eh) && - ex_ee_block + ex_ee_len > start) { - - if (ext4_ext_is_unwritten(ex)) - unwritten = 1; - else - unwritten = 0; - - ext_debug("remove ext %u:[%d]%d\n", ex_ee_block, - unwritten, ex_ee_len); - path[depth].p_ext = ex; - - a = ex_ee_block > start ? ex_ee_block : start; - b = ex_ee_block+ex_ee_len - 1 < end ? - ex_ee_block+ex_ee_len - 1 : end; - - ext_debug(" border %u:%u\n", a, b); - - /* If this extent is beyond the end of the hole, skip it */ - if (end < ex_ee_block) { - /* - * We're going to skip this extent and move to another, - * so note that its first cluster is in use to avoid - * freeing it when removing blocks. Eventually, the - * right edge of the truncated/punched region will - * be just to the left. - */ - if (sbi->s_cluster_ratio > 1) { - pblk = ext4_ext_pblock(ex); - *partial_cluster = - -(long long) EXT4_B2C(sbi, pblk); - } - ex--; - ex_ee_block = le32_to_cpu(ex->ee_block); - ex_ee_len = ext4_ext_get_actual_len(ex); - continue; - } else if (b != ex_ee_block + ex_ee_len - 1) { - EXT4_ERROR_INODE(inode, - "can not handle truncate %u:%u " - "on extent %u:%u", - start, end, ex_ee_block, - ex_ee_block + ex_ee_len - 1); - err = -EFSCORRUPTED; - goto out; - } else if (a != ex_ee_block) { - /* remove tail of the extent */ - num = a - ex_ee_block; - } else { - /* remove whole extent: excellent! */ - num = 0; - } - /* - * 3 for leaf, sb, and inode plus 2 (bmap and group - * descriptor) for each block group; assume two block - * groups plus ex_ee_len/blocks_per_block_group for - * the worst case - */ - credits = 7 + 2*(ex_ee_len/EXT4_BLOCKS_PER_GROUP(inode->i_sb)); - if (ex == EXT_FIRST_EXTENT(eh)) { - correct_index = 1; - credits += (ext_depth(inode)) + 1; - } - credits += EXT4_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb); - - err = ext4_ext_truncate_extend_restart(handle, inode, credits); - if (err) - goto out; - - err = ext4_ext_get_access(handle, inode, path + depth); - if (err) - goto out; - - err = ext4_remove_blocks(handle, inode, ex, partial_cluster, - a, b); - if (err) - goto out; - - if (num == 0) - /* this extent is removed; mark slot entirely unused */ - ext4_ext_store_pblock(ex, 0); - - ex->ee_len = cpu_to_le16(num); - /* - * Do not mark unwritten if all the blocks in the - * extent have been removed. - */ - if (unwritten && num) - ext4_ext_mark_unwritten(ex); - /* - * If the extent was completely released, - * we need to remove it from the leaf - */ - if (num == 0) { - if (end != EXT_MAX_BLOCKS - 1) { - /* - * For hole punching, we need to scoot all the - * extents up when an extent is removed so that - * we dont have blank extents in the middle - */ - memmove(ex, ex+1, (EXT_LAST_EXTENT(eh) - ex) * - sizeof(struct ext4_extent)); - - /* Now get rid of the one at the end */ - memset(EXT_LAST_EXTENT(eh), 0, - sizeof(struct ext4_extent)); - } - le16_add_cpu(&eh->eh_entries, -1); - } - - err = ext4_ext_dirty(handle, inode, path + depth); - if (err) - goto out; - - ext_debug("new extent: %u:%u:%llu\n", ex_ee_block, num, - ext4_ext_pblock(ex)); - ex--; - ex_ee_block = le32_to_cpu(ex->ee_block); - ex_ee_len = ext4_ext_get_actual_len(ex); - } - - if (correct_index && eh->eh_entries) - err = ext4_ext_correct_indexes(handle, inode, path); - - /* - * If there's a partial cluster and at least one extent remains in - * the leaf, free the partial cluster if it isn't shared with the - * current extent. If it is shared with the current extent - * we zero partial_cluster because we've reached the start of the - * truncated/punched region and we're done removing blocks. - */ - if (*partial_cluster > 0 && ex >= EXT_FIRST_EXTENT(eh)) { - pblk = ext4_ext_pblock(ex) + ex_ee_len - 1; - if (*partial_cluster != (long long) EXT4_B2C(sbi, pblk)) { - ext4_free_blocks(handle, inode, NULL, - EXT4_C2B(sbi, *partial_cluster), - sbi->s_cluster_ratio, - get_default_free_blocks_flags(inode)); - } - *partial_cluster = 0; - } - - /* if this leaf is free, then we should - * remove it from index block above */ - if (err == 0 && eh->eh_entries == 0 && path[depth].p_bh != NULL) - err = ext4_ext_rm_idx(handle, inode, path, depth); - -out: - return err; -} - -/* - * ext4_ext_more_to_rm: - * returns 1 if current index has to be freed (even partial) - */ -static int -ext4_ext_more_to_rm(struct ext4_ext_path *path) -{ - BUG_ON(path->p_idx == NULL); - - if (path->p_idx < EXT_FIRST_INDEX(path->p_hdr)) - return 0; - - /* - * if truncate on deeper level happened, it wasn't partial, - * so we have to consider current index for truncation - */ - if (le16_to_cpu(path->p_hdr->eh_entries) == path->p_block) - return 0; - return 1; -} - -int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, - ext4_lblk_t end) -{ - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - int depth = ext_depth(inode); - struct ext4_ext_path *path = NULL; - long long partial_cluster = 0; - handle_t *handle; - int i = 0, err = 0; - - ext_debug("truncate since %u to %u\n", start, end); - - /* probably first extent we're gonna free will be last in block */ - handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, depth + 1); - if (IS_ERR(handle)) - return PTR_ERR(handle); - -again: - trace_ext4_ext_remove_space(inode, start, end, depth); - - /* - * Check if we are removing extents inside the extent tree. If that - * is the case, we are going to punch a hole inside the extent tree - * so we have to check whether we need to split the extent covering - * the last block to remove so we can easily remove the part of it - * in ext4_ext_rm_leaf(). - */ - if (end < EXT_MAX_BLOCKS - 1) { - struct ext4_extent *ex; - ext4_lblk_t ee_block, ex_end, lblk; - ext4_fsblk_t pblk; - - /* find extent for or closest extent to this block */ - path = ext4_find_extent(inode, end, NULL, EXT4_EX_NOCACHE); - if (IS_ERR(path)) { - ext4_journal_stop(handle); - return PTR_ERR(path); - } - depth = ext_depth(inode); - /* Leaf not may not exist only if inode has no blocks at all */ - ex = path[depth].p_ext; - if (!ex) { - if (depth) { - EXT4_ERROR_INODE(inode, - "path[%d].p_hdr == NULL", - depth); - err = -EFSCORRUPTED; - } - goto out; - } - - ee_block = le32_to_cpu(ex->ee_block); - ex_end = ee_block + ext4_ext_get_actual_len(ex) - 1; - - /* - * See if the last block is inside the extent, if so split - * the extent at 'end' block so we can easily remove the - * tail of the first part of the split extent in - * ext4_ext_rm_leaf(). - */ - if (end >= ee_block && end < ex_end) { - - /* - * If we're going to split the extent, note that - * the cluster containing the block after 'end' is - * in use to avoid freeing it when removing blocks. - */ - if (sbi->s_cluster_ratio > 1) { - pblk = ext4_ext_pblock(ex) + end - ee_block + 2; - partial_cluster = - -(long long) EXT4_B2C(sbi, pblk); - } - - /* - * Split the extent in two so that 'end' is the last - * block in the first new extent. Also we should not - * fail removing space due to ENOSPC so try to use - * reserved block if that happens. - */ - err = ext4_force_split_extent_at(handle, inode, &path, - end + 1, 1); - if (err < 0) - goto out; - - } else if (sbi->s_cluster_ratio > 1 && end >= ex_end) { - /* - * If there's an extent to the right its first cluster - * contains the immediate right boundary of the - * truncated/punched region. Set partial_cluster to - * its negative value so it won't be freed if shared - * with the current extent. The end < ee_block case - * is handled in ext4_ext_rm_leaf(). - */ - lblk = ex_end + 1; - err = ext4_ext_search_right(inode, path, &lblk, &pblk, - &ex); - if (err) - goto out; - if (pblk) - partial_cluster = - -(long long) EXT4_B2C(sbi, pblk); - } - } - /* - * We start scanning from right side, freeing all the blocks - * after i_size and walking into the tree depth-wise. - */ - depth = ext_depth(inode); - if (path) { - int k = i = depth; - while (--k > 0) - path[k].p_block = - le16_to_cpu(path[k].p_hdr->eh_entries)+1; - } else { - path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), - GFP_NOFS); - if (path == NULL) { - ext4_journal_stop(handle); - return -ENOMEM; - } - path[0].p_maxdepth = path[0].p_depth = depth; - path[0].p_hdr = ext_inode_hdr(inode); - i = 0; - - if (ext4_ext_check(inode, path[0].p_hdr, depth, 0)) { - err = -EFSCORRUPTED; - goto out; - } - } - err = 0; - - while (i >= 0 && err == 0) { - if (i == depth) { - /* this is leaf block */ - err = ext4_ext_rm_leaf(handle, inode, path, - &partial_cluster, start, - end); - /* root level has p_bh == NULL, brelse() eats this */ - brelse(path[i].p_bh); - path[i].p_bh = NULL; - i--; - continue; - } - - /* this is index block */ - if (!path[i].p_hdr) { - ext_debug("initialize header\n"); - path[i].p_hdr = ext_block_hdr(path[i].p_bh); - } - - if (!path[i].p_idx) { - /* this level hasn't been touched yet */ - path[i].p_idx = EXT_LAST_INDEX(path[i].p_hdr); - path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries)+1; - ext_debug("init index ptr: hdr 0x%p, num %d\n", - path[i].p_hdr, - le16_to_cpu(path[i].p_hdr->eh_entries)); - } else { - /* we were already here, see at next index */ - path[i].p_idx--; - } - - ext_debug("level %d - index, first 0x%p, cur 0x%p\n", - i, EXT_FIRST_INDEX(path[i].p_hdr), - path[i].p_idx); - if (ext4_ext_more_to_rm(path + i)) { - struct buffer_head *bh; - /* go to the next level */ - ext_debug("move to level %d (block %llu)\n", - i + 1, ext4_idx_pblock(path[i].p_idx)); - memset(path + i + 1, 0, sizeof(*path)); - bh = read_extent_tree_block(inode, - ext4_idx_pblock(path[i].p_idx), depth - i - 1, - EXT4_EX_NOCACHE); - if (IS_ERR(bh)) { - /* should we reset i_size? */ - err = PTR_ERR(bh); - break; - } - /* Yield here to deal with large extent trees. - * Should be a no-op if we did IO above. */ - cond_resched(); - if (WARN_ON(i + 1 > depth)) { - err = -EFSCORRUPTED; - break; - } - path[i + 1].p_bh = bh; - - /* save actual number of indexes since this - * number is changed at the next iteration */ - path[i].p_block = le16_to_cpu(path[i].p_hdr->eh_entries); - i++; - } else { - /* we finished processing this index, go up */ - if (path[i].p_hdr->eh_entries == 0 && i > 0) { - /* index is empty, remove it; - * handle must be already prepared by the - * truncatei_leaf() */ - err = ext4_ext_rm_idx(handle, inode, path, i); - } - /* root level has p_bh == NULL, brelse() eats this */ - brelse(path[i].p_bh); - path[i].p_bh = NULL; - i--; - ext_debug("return to level %d\n", i); - } - } - - trace_ext4_ext_remove_space_done(inode, start, end, depth, - partial_cluster, path->p_hdr->eh_entries); - - /* - * If we still have something in the partial cluster and we have removed - * even the first extent, then we should free the blocks in the partial - * cluster as well. (This code will only run when there are no leaves - * to the immediate left of the truncated/punched region.) - */ - if (partial_cluster > 0 && err == 0) { - /* don't zero partial_cluster since it's not used afterwards */ - ext4_free_blocks(handle, inode, NULL, - EXT4_C2B(sbi, partial_cluster), - sbi->s_cluster_ratio, - get_default_free_blocks_flags(inode)); - } - - /* TODO: flexible tree reduction should be here */ - if (path->p_hdr->eh_entries == 0) { - /* - * truncate to zero freed all the tree, - * so we need to correct eh_depth - */ - err = ext4_ext_get_access(handle, inode, path); - if (err == 0) { - ext_inode_hdr(inode)->eh_depth = 0; - ext_inode_hdr(inode)->eh_max = - cpu_to_le16(ext4_ext_space_root(inode, 0)); - err = ext4_ext_dirty(handle, inode, path); - } - } -out: - ext4_ext_drop_refs(path); - kfree(path); - path = NULL; - if (err == -EAGAIN) - goto again; - ext4_journal_stop(handle); - - return err; -} - -/* - * called at mount time - */ -void ext4_ext_init(struct super_block *sb) -{ - /* - * possible initialization would be here - */ - - if (ext4_has_feature_extents(sb)) { -#if defined(AGGRESSIVE_TEST) || defined(CHECK_BINSEARCH) || defined(EXTENTS_STATS) - printk(KERN_INFO "EXT4-fs: file extents enabled" -#ifdef AGGRESSIVE_TEST - ", aggressive tests" -#endif -#ifdef CHECK_BINSEARCH - ", check binsearch" -#endif -#ifdef EXTENTS_STATS - ", stats" -#endif - "\n"); -#endif -#ifdef EXTENTS_STATS - spin_lock_init(&EXT4_SB(sb)->s_ext_stats_lock); - EXT4_SB(sb)->s_ext_min = 1 << 30; - EXT4_SB(sb)->s_ext_max = 0; -#endif - } -} - -/* - * called at umount time - */ -void ext4_ext_release(struct super_block *sb) -{ - if (!ext4_has_feature_extents(sb)) - return; - -#ifdef EXTENTS_STATS - if (EXT4_SB(sb)->s_ext_blocks && EXT4_SB(sb)->s_ext_extents) { - struct ext4_sb_info *sbi = EXT4_SB(sb); - printk(KERN_ERR "EXT4-fs: %lu blocks in %lu extents (%lu ave)\n", - sbi->s_ext_blocks, sbi->s_ext_extents, - sbi->s_ext_blocks / sbi->s_ext_extents); - printk(KERN_ERR "EXT4-fs: extents: %lu min, %lu max, max depth %lu\n", - sbi->s_ext_min, sbi->s_ext_max, sbi->s_depth_max); - } -#endif -} - -static int ext4_zeroout_es(struct inode *inode, struct ext4_extent *ex) -{ - ext4_lblk_t ee_block; - ext4_fsblk_t ee_pblock; - unsigned int ee_len; - - ee_block = le32_to_cpu(ex->ee_block); - ee_len = ext4_ext_get_actual_len(ex); - ee_pblock = ext4_ext_pblock(ex); - - if (ee_len == 0) - return 0; - - return ext4_es_insert_extent(inode, ee_block, ee_len, ee_pblock, - EXTENT_STATUS_WRITTEN); -} - -/* FIXME!! we need to try to merge to left or right after zero-out */ -static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex) -{ - ext4_fsblk_t ee_pblock; - unsigned int ee_len; - - ee_len = ext4_ext_get_actual_len(ex); - ee_pblock = ext4_ext_pblock(ex); - return ext4_issue_zeroout(inode, le32_to_cpu(ex->ee_block), ee_pblock, - ee_len); -} - -/* - * ext4_split_extent_at() splits an extent at given block. - * - * @handle: the journal handle - * @inode: the file inode - * @path: the path to the extent - * @split: the logical block where the extent is splitted. - * @split_flags: indicates if the extent could be zeroout if split fails, and - * the states(init or unwritten) of new extents. - * @flags: flags used to insert new extent to extent tree. - * - * - * Splits extent [a, b] into two extents [a, @split) and [@split, b], states - * of which are deterimined by split_flag. - * - * There are two cases: - * a> the extent are splitted into two extent. - * b> split is not needed, and just mark the extent. - * - * return 0 on success. - */ -static int ext4_split_extent_at(handle_t *handle, - struct inode *inode, - struct ext4_ext_path **ppath, - ext4_lblk_t split, - int split_flag, - int flags) -{ - struct ext4_ext_path *path = *ppath; - ext4_fsblk_t newblock; - ext4_lblk_t ee_block; - struct ext4_extent *ex, newex, orig_ex, zero_ex; - struct ext4_extent *ex2 = NULL; - unsigned int ee_len, depth; - int err = 0; - - BUG_ON((split_flag & (EXT4_EXT_DATA_VALID1 | EXT4_EXT_DATA_VALID2)) == - (EXT4_EXT_DATA_VALID1 | EXT4_EXT_DATA_VALID2)); - - ext_debug("ext4_split_extents_at: inode %lu, logical" - "block %llu\n", inode->i_ino, (unsigned long long)split); - - ext4_ext_show_leaf(inode, path); - - depth = ext_depth(inode); - ex = path[depth].p_ext; - ee_block = le32_to_cpu(ex->ee_block); - ee_len = ext4_ext_get_actual_len(ex); - newblock = split - ee_block + ext4_ext_pblock(ex); - - BUG_ON(split < ee_block || split >= (ee_block + ee_len)); - BUG_ON(!ext4_ext_is_unwritten(ex) && - split_flag & (EXT4_EXT_MAY_ZEROOUT | - EXT4_EXT_MARK_UNWRIT1 | - EXT4_EXT_MARK_UNWRIT2)); - - err = ext4_ext_get_access(handle, inode, path + depth); - if (err) - goto out; - - if (split == ee_block) { - /* - * case b: block @split is the block that the extent begins with - * then we just change the state of the extent, and splitting - * is not needed. - */ - if (split_flag & EXT4_EXT_MARK_UNWRIT2) - ext4_ext_mark_unwritten(ex); - else - ext4_ext_mark_initialized(ex); - - if (!(flags & EXT4_GET_BLOCKS_PRE_IO)) - ext4_ext_try_to_merge(handle, inode, path, ex); - - err = ext4_ext_dirty(handle, inode, path + path->p_depth); - goto out; - } - - /* case a */ - memcpy(&orig_ex, ex, sizeof(orig_ex)); - ex->ee_len = cpu_to_le16(split - ee_block); - if (split_flag & EXT4_EXT_MARK_UNWRIT1) - ext4_ext_mark_unwritten(ex); - - /* - * path may lead to new leaf, not to original leaf any more - * after ext4_ext_insert_extent() returns, - */ - err = ext4_ext_dirty(handle, inode, path + depth); - if (err) - goto fix_extent_len; - - ex2 = &newex; - ex2->ee_block = cpu_to_le32(split); - ex2->ee_len = cpu_to_le16(ee_len - (split - ee_block)); - ext4_ext_store_pblock(ex2, newblock); - if (split_flag & EXT4_EXT_MARK_UNWRIT2) - ext4_ext_mark_unwritten(ex2); - - err = ext4_ext_insert_extent(handle, inode, ppath, &newex, flags); - if (err == -ENOSPC && (EXT4_EXT_MAY_ZEROOUT & split_flag)) { - if (split_flag & (EXT4_EXT_DATA_VALID1|EXT4_EXT_DATA_VALID2)) { - if (split_flag & EXT4_EXT_DATA_VALID1) { - err = ext4_ext_zeroout(inode, ex2); - zero_ex.ee_block = ex2->ee_block; - zero_ex.ee_len = cpu_to_le16( - ext4_ext_get_actual_len(ex2)); - ext4_ext_store_pblock(&zero_ex, - ext4_ext_pblock(ex2)); - } else { - err = ext4_ext_zeroout(inode, ex); - zero_ex.ee_block = ex->ee_block; - zero_ex.ee_len = cpu_to_le16( - ext4_ext_get_actual_len(ex)); - ext4_ext_store_pblock(&zero_ex, - ext4_ext_pblock(ex)); - } - } else { - err = ext4_ext_zeroout(inode, &orig_ex); - zero_ex.ee_block = orig_ex.ee_block; - zero_ex.ee_len = cpu_to_le16( - ext4_ext_get_actual_len(&orig_ex)); - ext4_ext_store_pblock(&zero_ex, - ext4_ext_pblock(&orig_ex)); - } - - if (err) - goto fix_extent_len; - /* update the extent length and mark as initialized */ - ex->ee_len = cpu_to_le16(ee_len); - ext4_ext_try_to_merge(handle, inode, path, ex); - err = ext4_ext_dirty(handle, inode, path + path->p_depth); - if (err) - goto fix_extent_len; - - /* update extent status tree */ - err = ext4_zeroout_es(inode, &zero_ex); - - goto out; - } else if (err) - goto fix_extent_len; - -out: - ext4_ext_show_leaf(inode, path); - return err; - -fix_extent_len: - ex->ee_len = orig_ex.ee_len; - ext4_ext_dirty(handle, inode, path + path->p_depth); - return err; -} - -/* - * ext4_split_extents() splits an extent and mark extent which is covered - * by @map as split_flags indicates - * - * It may result in splitting the extent into multiple extents (up to three) - * There are three possibilities: - * a> There is no split required - * b> Splits in two extents: Split is happening at either end of the extent - * c> Splits in three extents: Somone is splitting in middle of the extent - * - */ -static int ext4_split_extent(handle_t *handle, - struct inode *inode, - struct ext4_ext_path **ppath, - struct ext4_map_blocks *map, - int split_flag, - int flags) -{ - struct ext4_ext_path *path = *ppath; - ext4_lblk_t ee_block; - struct ext4_extent *ex; - unsigned int ee_len, depth; - int err = 0; - int unwritten; - int split_flag1, flags1; - int allocated = map->m_len; - - depth = ext_depth(inode); - ex = path[depth].p_ext; - ee_block = le32_to_cpu(ex->ee_block); - ee_len = ext4_ext_get_actual_len(ex); - unwritten = ext4_ext_is_unwritten(ex); - - if (map->m_lblk + map->m_len < ee_block + ee_len) { - split_flag1 = split_flag & EXT4_EXT_MAY_ZEROOUT; - flags1 = flags | EXT4_GET_BLOCKS_PRE_IO; - if (unwritten) - split_flag1 |= EXT4_EXT_MARK_UNWRIT1 | - EXT4_EXT_MARK_UNWRIT2; - if (split_flag & EXT4_EXT_DATA_VALID2) - split_flag1 |= EXT4_EXT_DATA_VALID1; - err = ext4_split_extent_at(handle, inode, ppath, - map->m_lblk + map->m_len, split_flag1, flags1); - if (err) - goto out; - } else { - allocated = ee_len - (map->m_lblk - ee_block); - } - /* - * Update path is required because previous ext4_split_extent_at() may - * result in split of original leaf or extent zeroout. - */ - path = ext4_find_extent(inode, map->m_lblk, ppath, 0); - if (IS_ERR(path)) - return PTR_ERR(path); - depth = ext_depth(inode); - ex = path[depth].p_ext; - if (!ex) { - EXT4_ERROR_INODE(inode, "unexpected hole at %lu", - (unsigned long) map->m_lblk); - return -EFSCORRUPTED; - } - unwritten = ext4_ext_is_unwritten(ex); - split_flag1 = 0; - - if (map->m_lblk >= ee_block) { - split_flag1 = split_flag & EXT4_EXT_DATA_VALID2; - if (unwritten) { - split_flag1 |= EXT4_EXT_MARK_UNWRIT1; - split_flag1 |= split_flag & (EXT4_EXT_MAY_ZEROOUT | - EXT4_EXT_MARK_UNWRIT2); - } - err = ext4_split_extent_at(handle, inode, ppath, - map->m_lblk, split_flag1, flags); - if (err) - goto out; - } - - ext4_ext_show_leaf(inode, path); -out: - return err ? err : allocated; -} - -/* - * This function is called by ext4_ext_map_blocks() if someone tries to write - * to an unwritten extent. It may result in splitting the unwritten - * extent into multiple extents (up to three - one initialized and two - * unwritten). - * There are three possibilities: - * a> There is no split required: Entire extent should be initialized - * b> Splits in two extents: Write is happening at either end of the extent - * c> Splits in three extents: Somone is writing in middle of the extent - * - * Pre-conditions: - * - The extent pointed to by 'path' is unwritten. - * - The extent pointed to by 'path' contains a superset - * of the logical span [map->m_lblk, map->m_lblk + map->m_len). - * - * Post-conditions on success: - * - the returned value is the number of blocks beyond map->l_lblk - * that are allocated and initialized. - * It is guaranteed to be >= map->m_len. - */ -static int ext4_ext_convert_to_initialized(handle_t *handle, - struct inode *inode, - struct ext4_map_blocks *map, - struct ext4_ext_path **ppath, - int flags) -{ - struct ext4_ext_path *path = *ppath; - struct ext4_sb_info *sbi; - struct ext4_extent_header *eh; - struct ext4_map_blocks split_map; - struct ext4_extent zero_ex; - struct ext4_extent *ex, *abut_ex; - ext4_lblk_t ee_block, eof_block; - unsigned int ee_len, depth, map_len = map->m_len; - int allocated = 0, max_zeroout = 0; - int err = 0; - int split_flag = 0; - - ext_debug("ext4_ext_convert_to_initialized: inode %lu, logical" - "block %llu, max_blocks %u\n", inode->i_ino, - (unsigned long long)map->m_lblk, map_len); - - sbi = EXT4_SB(inode->i_sb); - eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >> - inode->i_sb->s_blocksize_bits; - if (eof_block < map->m_lblk + map_len) - eof_block = map->m_lblk + map_len; - - depth = ext_depth(inode); - eh = path[depth].p_hdr; - ex = path[depth].p_ext; - ee_block = le32_to_cpu(ex->ee_block); - ee_len = ext4_ext_get_actual_len(ex); - zero_ex.ee_len = 0; - - trace_ext4_ext_convert_to_initialized_enter(inode, map, ex); - - /* Pre-conditions */ - BUG_ON(!ext4_ext_is_unwritten(ex)); - BUG_ON(!in_range(map->m_lblk, ee_block, ee_len)); - - /* - * Attempt to transfer newly initialized blocks from the currently - * unwritten extent to its neighbor. This is much cheaper - * than an insertion followed by a merge as those involve costly - * memmove() calls. Transferring to the left is the common case in - * steady state for workloads doing fallocate(FALLOC_FL_KEEP_SIZE) - * followed by append writes. - * - * Limitations of the current logic: - * - L1: we do not deal with writes covering the whole extent. - * This would require removing the extent if the transfer - * is possible. - * - L2: we only attempt to merge with an extent stored in the - * same extent tree node. - */ - if ((map->m_lblk == ee_block) && - /* See if we can merge left */ - (map_len < ee_len) && /*L1*/ - (ex > EXT_FIRST_EXTENT(eh))) { /*L2*/ - ext4_lblk_t prev_lblk; - ext4_fsblk_t prev_pblk, ee_pblk; - unsigned int prev_len; - - abut_ex = ex - 1; - prev_lblk = le32_to_cpu(abut_ex->ee_block); - prev_len = ext4_ext_get_actual_len(abut_ex); - prev_pblk = ext4_ext_pblock(abut_ex); - ee_pblk = ext4_ext_pblock(ex); - - /* - * A transfer of blocks from 'ex' to 'abut_ex' is allowed - * upon those conditions: - * - C1: abut_ex is initialized, - * - C2: abut_ex is logically abutting ex, - * - C3: abut_ex is physically abutting ex, - * - C4: abut_ex can receive the additional blocks without - * overflowing the (initialized) length limit. - */ - if ((!ext4_ext_is_unwritten(abut_ex)) && /*C1*/ - ((prev_lblk + prev_len) == ee_block) && /*C2*/ - ((prev_pblk + prev_len) == ee_pblk) && /*C3*/ - (prev_len < (EXT_INIT_MAX_LEN - map_len))) { /*C4*/ - err = ext4_ext_get_access(handle, inode, path + depth); - if (err) - goto out; - - trace_ext4_ext_convert_to_initialized_fastpath(inode, - map, ex, abut_ex); - - /* Shift the start of ex by 'map_len' blocks */ - ex->ee_block = cpu_to_le32(ee_block + map_len); - ext4_ext_store_pblock(ex, ee_pblk + map_len); - ex->ee_len = cpu_to_le16(ee_len - map_len); - ext4_ext_mark_unwritten(ex); /* Restore the flag */ - - /* Extend abut_ex by 'map_len' blocks */ - abut_ex->ee_len = cpu_to_le16(prev_len + map_len); - - /* Result: number of initialized blocks past m_lblk */ - allocated = map_len; - } - } else if (((map->m_lblk + map_len) == (ee_block + ee_len)) && - (map_len < ee_len) && /*L1*/ - ex < EXT_LAST_EXTENT(eh)) { /*L2*/ - /* See if we can merge right */ - ext4_lblk_t next_lblk; - ext4_fsblk_t next_pblk, ee_pblk; - unsigned int next_len; - - abut_ex = ex + 1; - next_lblk = le32_to_cpu(abut_ex->ee_block); - next_len = ext4_ext_get_actual_len(abut_ex); - next_pblk = ext4_ext_pblock(abut_ex); - ee_pblk = ext4_ext_pblock(ex); - - /* - * A transfer of blocks from 'ex' to 'abut_ex' is allowed - * upon those conditions: - * - C1: abut_ex is initialized, - * - C2: abut_ex is logically abutting ex, - * - C3: abut_ex is physically abutting ex, - * - C4: abut_ex can receive the additional blocks without - * overflowing the (initialized) length limit. - */ - if ((!ext4_ext_is_unwritten(abut_ex)) && /*C1*/ - ((map->m_lblk + map_len) == next_lblk) && /*C2*/ - ((ee_pblk + ee_len) == next_pblk) && /*C3*/ - (next_len < (EXT_INIT_MAX_LEN - map_len))) { /*C4*/ - err = ext4_ext_get_access(handle, inode, path + depth); - if (err) - goto out; - - trace_ext4_ext_convert_to_initialized_fastpath(inode, - map, ex, abut_ex); - - /* Shift the start of abut_ex by 'map_len' blocks */ - abut_ex->ee_block = cpu_to_le32(next_lblk - map_len); - ext4_ext_store_pblock(abut_ex, next_pblk - map_len); - ex->ee_len = cpu_to_le16(ee_len - map_len); - ext4_ext_mark_unwritten(ex); /* Restore the flag */ - - /* Extend abut_ex by 'map_len' blocks */ - abut_ex->ee_len = cpu_to_le16(next_len + map_len); - - /* Result: number of initialized blocks past m_lblk */ - allocated = map_len; - } - } - if (allocated) { - /* Mark the block containing both extents as dirty */ - ext4_ext_dirty(handle, inode, path + depth); - - /* Update path to point to the right extent */ - path[depth].p_ext = abut_ex; - goto out; - } else - allocated = ee_len - (map->m_lblk - ee_block); - - WARN_ON(map->m_lblk < ee_block); - /* - * It is safe to convert extent to initialized via explicit - * zeroout only if extent is fully inside i_size or new_size. - */ - split_flag |= ee_block + ee_len <= eof_block ? EXT4_EXT_MAY_ZEROOUT : 0; - - if (EXT4_EXT_MAY_ZEROOUT & split_flag) - max_zeroout = sbi->s_extent_max_zeroout_kb >> - (inode->i_sb->s_blocksize_bits - 10); - - if (ext4_encrypted_inode(inode)) - max_zeroout = 0; - - /* If extent is less than s_max_zeroout_kb, zeroout directly */ - if (max_zeroout && (ee_len <= max_zeroout)) { - err = ext4_ext_zeroout(inode, ex); - if (err) - goto out; - zero_ex.ee_block = ex->ee_block; - zero_ex.ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)); - ext4_ext_store_pblock(&zero_ex, ext4_ext_pblock(ex)); - - err = ext4_ext_get_access(handle, inode, path + depth); - if (err) - goto out; - ext4_ext_mark_initialized(ex); - ext4_ext_try_to_merge(handle, inode, path, ex); - err = ext4_ext_dirty(handle, inode, path + path->p_depth); - goto out; - } - - /* - * four cases: - * 1. split the extent into three extents. - * 2. split the extent into two extents, zeroout the first half. - * 3. split the extent into two extents, zeroout the second half. - * 4. split the extent into two extents with out zeroout. - */ - split_map.m_lblk = map->m_lblk; - split_map.m_len = map->m_len; - - if (max_zeroout && (allocated > map->m_len)) { - if (allocated <= max_zeroout) { - /* case 3 */ - zero_ex.ee_block = - cpu_to_le32(map->m_lblk); - zero_ex.ee_len = cpu_to_le16(allocated); - ext4_ext_store_pblock(&zero_ex, - ext4_ext_pblock(ex) + map->m_lblk - ee_block); - err = ext4_ext_zeroout(inode, &zero_ex); - if (err) - goto out; - split_map.m_lblk = map->m_lblk; - split_map.m_len = allocated; - } else if (map->m_lblk - ee_block + map->m_len < max_zeroout) { - /* case 2 */ - if (map->m_lblk != ee_block) { - zero_ex.ee_block = ex->ee_block; - zero_ex.ee_len = cpu_to_le16(map->m_lblk - - ee_block); - ext4_ext_store_pblock(&zero_ex, - ext4_ext_pblock(ex)); - err = ext4_ext_zeroout(inode, &zero_ex); - if (err) - goto out; - } - - split_map.m_lblk = ee_block; - split_map.m_len = map->m_lblk - ee_block + map->m_len; - allocated = map->m_len; - } - } - - err = ext4_split_extent(handle, inode, ppath, &split_map, split_flag, - flags); - if (err > 0) - err = 0; -out: - /* If we have gotten a failure, don't zero out status tree */ - if (!err) - err = ext4_zeroout_es(inode, &zero_ex); - return err ? err : allocated; -} - -/* - * This function is called by ext4_ext_map_blocks() from - * ext4_get_blocks_dio_write() when DIO to write - * to an unwritten extent. - * - * Writing to an unwritten extent may result in splitting the unwritten - * extent into multiple initialized/unwritten extents (up to three) - * There are three possibilities: - * a> There is no split required: Entire extent should be unwritten - * b> Splits in two extents: Write is happening at either end of the extent - * c> Splits in three extents: Somone is writing in middle of the extent - * - * This works the same way in the case of initialized -> unwritten conversion. - * - * One of more index blocks maybe needed if the extent tree grow after - * the unwritten extent split. To prevent ENOSPC occur at the IO - * complete, we need to split the unwritten extent before DIO submit - * the IO. The unwritten extent called at this time will be split - * into three unwritten extent(at most). After IO complete, the part - * being filled will be convert to initialized by the end_io callback function - * via ext4_convert_unwritten_extents(). - * - * Returns the size of unwritten extent to be written on success. - */ -static int ext4_split_convert_extents(handle_t *handle, - struct inode *inode, - struct ext4_map_blocks *map, - struct ext4_ext_path **ppath, - int flags) -{ - struct ext4_ext_path *path = *ppath; - ext4_lblk_t eof_block; - ext4_lblk_t ee_block; - struct ext4_extent *ex; - unsigned int ee_len; - int split_flag = 0, depth; - - ext_debug("%s: inode %lu, logical block %llu, max_blocks %u\n", - __func__, inode->i_ino, - (unsigned long long)map->m_lblk, map->m_len); - - eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >> - inode->i_sb->s_blocksize_bits; - if (eof_block < map->m_lblk + map->m_len) - eof_block = map->m_lblk + map->m_len; - /* - * It is safe to convert extent to initialized via explicit - * zeroout only if extent is fully insde i_size or new_size. - */ - depth = ext_depth(inode); - ex = path[depth].p_ext; - ee_block = le32_to_cpu(ex->ee_block); - ee_len = ext4_ext_get_actual_len(ex); - - /* Convert to unwritten */ - if (flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN) { - split_flag |= EXT4_EXT_DATA_VALID1; - /* Convert to initialized */ - } else if (flags & EXT4_GET_BLOCKS_CONVERT) { - split_flag |= ee_block + ee_len <= eof_block ? - EXT4_EXT_MAY_ZEROOUT : 0; - split_flag |= (EXT4_EXT_MARK_UNWRIT2 | EXT4_EXT_DATA_VALID2); - } - flags |= EXT4_GET_BLOCKS_PRE_IO; - return ext4_split_extent(handle, inode, ppath, map, split_flag, flags); -} - -static int ext4_convert_unwritten_extents_endio(handle_t *handle, - struct inode *inode, - struct ext4_map_blocks *map, - struct ext4_ext_path **ppath) -{ - struct ext4_ext_path *path = *ppath; - struct ext4_extent *ex; - ext4_lblk_t ee_block; - unsigned int ee_len; - int depth; - int err = 0; - - depth = ext_depth(inode); - ex = path[depth].p_ext; - ee_block = le32_to_cpu(ex->ee_block); - ee_len = ext4_ext_get_actual_len(ex); - - ext_debug("ext4_convert_unwritten_extents_endio: inode %lu, logical" - "block %llu, max_blocks %u\n", inode->i_ino, - (unsigned long long)ee_block, ee_len); - - /* If extent is larger than requested it is a clear sign that we still - * have some extent state machine issues left. So extent_split is still - * required. - * TODO: Once all related issues will be fixed this situation should be - * illegal. - */ - if (ee_block != map->m_lblk || ee_len > map->m_len) { -#ifdef EXT4_DEBUG - ext4_warning("Inode (%ld) finished: extent logical block %llu," - " len %u; IO logical block %llu, len %u", - inode->i_ino, (unsigned long long)ee_block, ee_len, - (unsigned long long)map->m_lblk, map->m_len); -#endif - err = ext4_split_convert_extents(handle, inode, map, ppath, - EXT4_GET_BLOCKS_CONVERT); - if (err < 0) - return err; - path = ext4_find_extent(inode, map->m_lblk, ppath, 0); - if (IS_ERR(path)) - return PTR_ERR(path); - depth = ext_depth(inode); - ex = path[depth].p_ext; - } - - err = ext4_ext_get_access(handle, inode, path + depth); - if (err) - goto out; - /* first mark the extent as initialized */ - ext4_ext_mark_initialized(ex); - - /* note: ext4_ext_correct_indexes() isn't needed here because - * borders are not changed - */ - ext4_ext_try_to_merge(handle, inode, path, ex); - - /* Mark modified extent as dirty */ - err = ext4_ext_dirty(handle, inode, path + path->p_depth); -out: - ext4_ext_show_leaf(inode, path); - return err; -} - -static void unmap_underlying_metadata_blocks(struct block_device *bdev, - sector_t block, int count) -{ - int i; - for (i = 0; i < count; i++) - unmap_underlying_metadata(bdev, block + i); -} - -/* - * Handle EOFBLOCKS_FL flag, clearing it if necessary - */ -static int check_eofblocks_fl(handle_t *handle, struct inode *inode, - ext4_lblk_t lblk, - struct ext4_ext_path *path, - unsigned int len) -{ - int i, depth; - struct ext4_extent_header *eh; - struct ext4_extent *last_ex; - - if (!ext4_test_inode_flag(inode, EXT4_INODE_EOFBLOCKS)) - return 0; - - depth = ext_depth(inode); - eh = path[depth].p_hdr; - - /* - * We're going to remove EOFBLOCKS_FL entirely in future so we - * do not care for this case anymore. Simply remove the flag - * if there are no extents. - */ - if (unlikely(!eh->eh_entries)) - goto out; - last_ex = EXT_LAST_EXTENT(eh); - /* - * We should clear the EOFBLOCKS_FL flag if we are writing the - * last block in the last extent in the file. We test this by - * first checking to see if the caller to - * ext4_ext_get_blocks() was interested in the last block (or - * a block beyond the last block) in the current extent. If - * this turns out to be false, we can bail out from this - * function immediately. - */ - if (lblk + len < le32_to_cpu(last_ex->ee_block) + - ext4_ext_get_actual_len(last_ex)) - return 0; - /* - * If the caller does appear to be planning to write at or - * beyond the end of the current extent, we then test to see - * if the current extent is the last extent in the file, by - * checking to make sure it was reached via the rightmost node - * at each level of the tree. - */ - for (i = depth-1; i >= 0; i--) - if (path[i].p_idx != EXT_LAST_INDEX(path[i].p_hdr)) - return 0; -out: - ext4_clear_inode_flag(inode, EXT4_INODE_EOFBLOCKS); - return ext4_mark_inode_dirty(handle, inode); -} - -/** - * ext4_find_delalloc_range: find delayed allocated block in the given range. - * - * Return 1 if there is a delalloc block in the range, otherwise 0. - */ -int ext4_find_delalloc_range(struct inode *inode, - ext4_lblk_t lblk_start, - ext4_lblk_t lblk_end) -{ - struct extent_status es; - - ext4_es_find_delayed_extent_range(inode, lblk_start, lblk_end, &es); - if (es.es_len == 0) - return 0; /* there is no delay extent in this tree */ - else if (es.es_lblk <= lblk_start && - lblk_start < es.es_lblk + es.es_len) - return 1; - else if (lblk_start <= es.es_lblk && es.es_lblk <= lblk_end) - return 1; - else - return 0; -} - -int ext4_find_delalloc_cluster(struct inode *inode, ext4_lblk_t lblk) -{ - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - ext4_lblk_t lblk_start, lblk_end; - lblk_start = EXT4_LBLK_CMASK(sbi, lblk); - lblk_end = lblk_start + sbi->s_cluster_ratio - 1; - - return ext4_find_delalloc_range(inode, lblk_start, lblk_end); -} - -/** - * Determines how many complete clusters (out of those specified by the 'map') - * are under delalloc and were reserved quota for. - * This function is called when we are writing out the blocks that were - * originally written with their allocation delayed, but then the space was - * allocated using fallocate() before the delayed allocation could be resolved. - * The cases to look for are: - * ('=' indicated delayed allocated blocks - * '-' indicates non-delayed allocated blocks) - * (a) partial clusters towards beginning and/or end outside of allocated range - * are not delalloc'ed. - * Ex: - * |----c---=|====c====|====c====|===-c----| - * |++++++ allocated ++++++| - * ==> 4 complete clusters in above example - * - * (b) partial cluster (outside of allocated range) towards either end is - * marked for delayed allocation. In this case, we will exclude that - * cluster. - * Ex: - * |----====c========|========c========| - * |++++++ allocated ++++++| - * ==> 1 complete clusters in above example - * - * Ex: - * |================c================| - * |++++++ allocated ++++++| - * ==> 0 complete clusters in above example - * - * The ext4_da_update_reserve_space will be called only if we - * determine here that there were some "entire" clusters that span - * this 'allocated' range. - * In the non-bigalloc case, this function will just end up returning num_blks - * without ever calling ext4_find_delalloc_range. - */ -static unsigned int -get_reserved_cluster_alloc(struct inode *inode, ext4_lblk_t lblk_start, - unsigned int num_blks) -{ - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - ext4_lblk_t alloc_cluster_start, alloc_cluster_end; - ext4_lblk_t lblk_from, lblk_to, c_offset; - unsigned int allocated_clusters = 0; - - alloc_cluster_start = EXT4_B2C(sbi, lblk_start); - alloc_cluster_end = EXT4_B2C(sbi, lblk_start + num_blks - 1); - - /* max possible clusters for this allocation */ - allocated_clusters = alloc_cluster_end - alloc_cluster_start + 1; - - trace_ext4_get_reserved_cluster_alloc(inode, lblk_start, num_blks); - - /* Check towards left side */ - c_offset = EXT4_LBLK_COFF(sbi, lblk_start); - if (c_offset) { - lblk_from = EXT4_LBLK_CMASK(sbi, lblk_start); - lblk_to = lblk_from + c_offset - 1; - - if (ext4_find_delalloc_range(inode, lblk_from, lblk_to)) - allocated_clusters--; - } - - /* Now check towards right. */ - c_offset = EXT4_LBLK_COFF(sbi, lblk_start + num_blks); - if (allocated_clusters && c_offset) { - lblk_from = lblk_start + num_blks; - lblk_to = lblk_from + (sbi->s_cluster_ratio - c_offset) - 1; - - if (ext4_find_delalloc_range(inode, lblk_from, lblk_to)) - allocated_clusters--; - } - - return allocated_clusters; -} - -static int -convert_initialized_extent(handle_t *handle, struct inode *inode, - struct ext4_map_blocks *map, - struct ext4_ext_path **ppath, - unsigned int allocated) -{ - struct ext4_ext_path *path = *ppath; - struct ext4_extent *ex; - ext4_lblk_t ee_block; - unsigned int ee_len; - int depth; - int err = 0; - - /* - * Make sure that the extent is no bigger than we support with - * unwritten extent - */ - if (map->m_len > EXT_UNWRITTEN_MAX_LEN) - map->m_len = EXT_UNWRITTEN_MAX_LEN / 2; - - depth = ext_depth(inode); - ex = path[depth].p_ext; - ee_block = le32_to_cpu(ex->ee_block); - ee_len = ext4_ext_get_actual_len(ex); - - ext_debug("%s: inode %lu, logical" - "block %llu, max_blocks %u\n", __func__, inode->i_ino, - (unsigned long long)ee_block, ee_len); - - if (ee_block != map->m_lblk || ee_len > map->m_len) { - err = ext4_split_convert_extents(handle, inode, map, ppath, - EXT4_GET_BLOCKS_CONVERT_UNWRITTEN); - if (err < 0) - return err; - path = ext4_find_extent(inode, map->m_lblk, ppath, 0); - if (IS_ERR(path)) - return PTR_ERR(path); - depth = ext_depth(inode); - ex = path[depth].p_ext; - if (!ex) { - EXT4_ERROR_INODE(inode, "unexpected hole at %lu", - (unsigned long) map->m_lblk); - return -EFSCORRUPTED; - } - } - - err = ext4_ext_get_access(handle, inode, path + depth); - if (err) - return err; - /* first mark the extent as unwritten */ - ext4_ext_mark_unwritten(ex); - - /* note: ext4_ext_correct_indexes() isn't needed here because - * borders are not changed - */ - ext4_ext_try_to_merge(handle, inode, path, ex); - - /* Mark modified extent as dirty */ - err = ext4_ext_dirty(handle, inode, path + path->p_depth); - if (err) - return err; - ext4_ext_show_leaf(inode, path); - - ext4_update_inode_fsync_trans(handle, inode, 1); - err = check_eofblocks_fl(handle, inode, map->m_lblk, path, map->m_len); - if (err) - return err; - map->m_flags |= EXT4_MAP_UNWRITTEN; - if (allocated > map->m_len) - allocated = map->m_len; - map->m_len = allocated; - return allocated; -} - -static int -ext4_ext_handle_unwritten_extents(handle_t *handle, struct inode *inode, - struct ext4_map_blocks *map, - struct ext4_ext_path **ppath, int flags, - unsigned int allocated, ext4_fsblk_t newblock) -{ - struct ext4_ext_path *path = *ppath; - int ret = 0; - int err = 0; - - ext_debug("ext4_ext_handle_unwritten_extents: inode %lu, logical " - "block %llu, max_blocks %u, flags %x, allocated %u\n", - inode->i_ino, (unsigned long long)map->m_lblk, map->m_len, - flags, allocated); - ext4_ext_show_leaf(inode, path); - - /* - * When writing into unwritten space, we should not fail to - * allocate metadata blocks for the new extent block if needed. - */ - flags |= EXT4_GET_BLOCKS_METADATA_NOFAIL; - - trace_ext4_ext_handle_unwritten_extents(inode, map, flags, - allocated, newblock); - - /* get_block() before submit the IO, split the extent */ - if (flags & EXT4_GET_BLOCKS_PRE_IO) { - ret = ext4_split_convert_extents(handle, inode, map, ppath, - flags | EXT4_GET_BLOCKS_CONVERT); - if (ret <= 0) - goto out; - map->m_flags |= EXT4_MAP_UNWRITTEN; - goto out; - } - /* IO end_io complete, convert the filled extent to written */ - if (flags & EXT4_GET_BLOCKS_CONVERT) { - if (flags & EXT4_GET_BLOCKS_ZERO) { - if (allocated > map->m_len) - allocated = map->m_len; - err = ext4_issue_zeroout(inode, map->m_lblk, newblock, - allocated); - if (err < 0) - goto out2; - } - ret = ext4_convert_unwritten_extents_endio(handle, inode, map, - ppath); - if (ret >= 0) { - ext4_update_inode_fsync_trans(handle, inode, 1); - err = check_eofblocks_fl(handle, inode, map->m_lblk, - path, map->m_len); - } else - err = ret; - map->m_flags |= EXT4_MAP_MAPPED; - map->m_pblk = newblock; - if (allocated > map->m_len) - allocated = map->m_len; - map->m_len = allocated; - goto out2; - } - /* buffered IO case */ - /* - * repeat fallocate creation request - * we already have an unwritten extent - */ - if (flags & EXT4_GET_BLOCKS_UNWRIT_EXT) { - map->m_flags |= EXT4_MAP_UNWRITTEN; - goto map_out; - } - - /* buffered READ or buffered write_begin() lookup */ - if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) { - /* - * We have blocks reserved already. We - * return allocated blocks so that delalloc - * won't do block reservation for us. But - * the buffer head will be unmapped so that - * a read from the block returns 0s. - */ - map->m_flags |= EXT4_MAP_UNWRITTEN; - goto out1; - } - - /* buffered write, writepage time, convert*/ - ret = ext4_ext_convert_to_initialized(handle, inode, map, ppath, flags); - if (ret >= 0) - ext4_update_inode_fsync_trans(handle, inode, 1); -out: - if (ret <= 0) { - err = ret; - goto out2; - } else - allocated = ret; - map->m_flags |= EXT4_MAP_NEW; - /* - * if we allocated more blocks than requested - * we need to make sure we unmap the extra block - * allocated. The actual needed block will get - * unmapped later when we find the buffer_head marked - * new. - */ - if (allocated > map->m_len) { - unmap_underlying_metadata_blocks(inode->i_sb->s_bdev, - newblock + map->m_len, - allocated - map->m_len); - allocated = map->m_len; - } - map->m_len = allocated; - - /* - * If we have done fallocate with the offset that is already - * delayed allocated, we would have block reservation - * and quota reservation done in the delayed write path. - * But fallocate would have already updated quota and block - * count for this offset. So cancel these reservation - */ - if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) { - unsigned int reserved_clusters; - reserved_clusters = get_reserved_cluster_alloc(inode, - map->m_lblk, map->m_len); - if (reserved_clusters) - ext4_da_update_reserve_space(inode, - reserved_clusters, - 0); - } - -map_out: - map->m_flags |= EXT4_MAP_MAPPED; - if ((flags & EXT4_GET_BLOCKS_KEEP_SIZE) == 0) { - err = check_eofblocks_fl(handle, inode, map->m_lblk, path, - map->m_len); - if (err < 0) - goto out2; - } -out1: - if (allocated > map->m_len) - allocated = map->m_len; - ext4_ext_show_leaf(inode, path); - map->m_pblk = newblock; - map->m_len = allocated; -out2: - return err ? err : allocated; -} - -/* - * get_implied_cluster_alloc - check to see if the requested - * allocation (in the map structure) overlaps with a cluster already - * allocated in an extent. - * @sb The filesystem superblock structure - * @map The requested lblk->pblk mapping - * @ex The extent structure which might contain an implied - * cluster allocation - * - * This function is called by ext4_ext_map_blocks() after we failed to - * find blocks that were already in the inode's extent tree. Hence, - * we know that the beginning of the requested region cannot overlap - * the extent from the inode's extent tree. There are three cases we - * want to catch. The first is this case: - * - * |--- cluster # N--| - * |--- extent ---| |---- requested region ---| - * |==========| - * - * The second case that we need to test for is this one: - * - * |--------- cluster # N ----------------| - * |--- requested region --| |------- extent ----| - * |=======================| - * - * The third case is when the requested region lies between two extents - * within the same cluster: - * |------------- cluster # N-------------| - * |----- ex -----| |---- ex_right ----| - * |------ requested region ------| - * |================| - * - * In each of the above cases, we need to set the map->m_pblk and - * map->m_len so it corresponds to the return the extent labelled as - * "|====|" from cluster #N, since it is already in use for data in - * cluster EXT4_B2C(sbi, map->m_lblk). We will then return 1 to - * signal to ext4_ext_map_blocks() that map->m_pblk should be treated - * as a new "allocated" block region. Otherwise, we will return 0 and - * ext4_ext_map_blocks() will then allocate one or more new clusters - * by calling ext4_mb_new_blocks(). - */ -static int get_implied_cluster_alloc(struct super_block *sb, - struct ext4_map_blocks *map, - struct ext4_extent *ex, - struct ext4_ext_path *path) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - ext4_lblk_t c_offset = EXT4_LBLK_COFF(sbi, map->m_lblk); - ext4_lblk_t ex_cluster_start, ex_cluster_end; - ext4_lblk_t rr_cluster_start; - ext4_lblk_t ee_block = le32_to_cpu(ex->ee_block); - ext4_fsblk_t ee_start = ext4_ext_pblock(ex); - unsigned short ee_len = ext4_ext_get_actual_len(ex); - - /* The extent passed in that we are trying to match */ - ex_cluster_start = EXT4_B2C(sbi, ee_block); - ex_cluster_end = EXT4_B2C(sbi, ee_block + ee_len - 1); - - /* The requested region passed into ext4_map_blocks() */ - rr_cluster_start = EXT4_B2C(sbi, map->m_lblk); - - if ((rr_cluster_start == ex_cluster_end) || - (rr_cluster_start == ex_cluster_start)) { - if (rr_cluster_start == ex_cluster_end) - ee_start += ee_len - 1; - map->m_pblk = EXT4_PBLK_CMASK(sbi, ee_start) + c_offset; - map->m_len = min(map->m_len, - (unsigned) sbi->s_cluster_ratio - c_offset); - /* - * Check for and handle this case: - * - * |--------- cluster # N-------------| - * |------- extent ----| - * |--- requested region ---| - * |===========| - */ - - if (map->m_lblk < ee_block) - map->m_len = min(map->m_len, ee_block - map->m_lblk); - - /* - * Check for the case where there is already another allocated - * block to the right of 'ex' but before the end of the cluster. - * - * |------------- cluster # N-------------| - * |----- ex -----| |---- ex_right ----| - * |------ requested region ------| - * |================| - */ - if (map->m_lblk > ee_block) { - ext4_lblk_t next = ext4_ext_next_allocated_block(path); - map->m_len = min(map->m_len, next - map->m_lblk); - } - - trace_ext4_get_implied_cluster_alloc_exit(sb, map, 1); - return 1; - } - - trace_ext4_get_implied_cluster_alloc_exit(sb, map, 0); - return 0; -} - - -/* - * Block allocation/map/preallocation routine for extents based files - * - * - * Need to be called with - * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system block - * (ie, create is zero). Otherwise down_write(&EXT4_I(inode)->i_data_sem) - * - * return > 0, number of of blocks already mapped/allocated - * if create == 0 and these are pre-allocated blocks - * buffer head is unmapped - * otherwise blocks are mapped - * - * return = 0, if plain look up failed (blocks have not been allocated) - * buffer head is unmapped - * - * return < 0, error case. - */ -int ext4_ext_map_blocks(handle_t *handle, struct inode *inode, - struct ext4_map_blocks *map, int flags) -{ - struct ext4_ext_path *path = NULL; - struct ext4_extent newex, *ex, *ex2; - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - ext4_fsblk_t newblock = 0; - int free_on_err = 0, err = 0, depth, ret; - unsigned int allocated = 0, offset = 0; - unsigned int allocated_clusters = 0; - struct ext4_allocation_request ar; - ext4_lblk_t cluster_offset; - bool map_from_cluster = false; - - ext_debug("blocks %u/%u requested for inode %lu\n", - map->m_lblk, map->m_len, inode->i_ino); - trace_ext4_ext_map_blocks_enter(inode, map->m_lblk, map->m_len, flags); - - /* find extent for this block */ - path = ext4_find_extent(inode, map->m_lblk, NULL, 0); - if (IS_ERR(path)) { - err = PTR_ERR(path); - path = NULL; - goto out2; - } - - depth = ext_depth(inode); - - /* - * consistent leaf must not be empty; - * this situation is possible, though, _during_ tree modification; - * this is why assert can't be put in ext4_find_extent() - */ - if (unlikely(path[depth].p_ext == NULL && depth != 0)) { - EXT4_ERROR_INODE(inode, "bad extent address " - "lblock: %lu, depth: %d pblock %lld", - (unsigned long) map->m_lblk, depth, - path[depth].p_block); - err = -EFSCORRUPTED; - goto out2; - } - - ex = path[depth].p_ext; - if (ex) { - ext4_lblk_t ee_block = le32_to_cpu(ex->ee_block); - ext4_fsblk_t ee_start = ext4_ext_pblock(ex); - unsigned short ee_len; - - - /* - * unwritten extents are treated as holes, except that - * we split out initialized portions during a write. - */ - ee_len = ext4_ext_get_actual_len(ex); - - trace_ext4_ext_show_extent(inode, ee_block, ee_start, ee_len); - - /* if found extent covers block, simply return it */ - if (in_range(map->m_lblk, ee_block, ee_len)) { - newblock = map->m_lblk - ee_block + ee_start; - /* number of remaining blocks in the extent */ - allocated = ee_len - (map->m_lblk - ee_block); - ext_debug("%u fit into %u:%d -> %llu\n", map->m_lblk, - ee_block, ee_len, newblock); - - /* - * If the extent is initialized check whether the - * caller wants to convert it to unwritten. - */ - if ((!ext4_ext_is_unwritten(ex)) && - (flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN)) { - allocated = convert_initialized_extent( - handle, inode, map, &path, - allocated); - goto out2; - } else if (!ext4_ext_is_unwritten(ex)) - goto out; - - ret = ext4_ext_handle_unwritten_extents( - handle, inode, map, &path, flags, - allocated, newblock); - if (ret < 0) - err = ret; - else - allocated = ret; - goto out2; - } - } - - /* - * requested block isn't allocated yet; - * we couldn't try to create block if create flag is zero - */ - if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) { - ext4_lblk_t hole_start, hole_len; - - hole_start = map->m_lblk; - hole_len = ext4_ext_determine_hole(inode, path, &hole_start); - /* - * put just found gap into cache to speed up - * subsequent requests - */ - ext4_ext_put_gap_in_cache(inode, hole_start, hole_len); - - /* Update hole_len to reflect hole size after map->m_lblk */ - if (hole_start != map->m_lblk) - hole_len -= map->m_lblk - hole_start; - map->m_pblk = 0; - map->m_len = min_t(unsigned int, map->m_len, hole_len); - - goto out2; - } - - /* - * Okay, we need to do block allocation. - */ - newex.ee_block = cpu_to_le32(map->m_lblk); - cluster_offset = EXT4_LBLK_COFF(sbi, map->m_lblk); - - /* - * If we are doing bigalloc, check to see if the extent returned - * by ext4_find_extent() implies a cluster we can use. - */ - if (cluster_offset && ex && - get_implied_cluster_alloc(inode->i_sb, map, ex, path)) { - ar.len = allocated = map->m_len; - newblock = map->m_pblk; - map_from_cluster = true; - goto got_allocated_blocks; - } - - /* find neighbour allocated blocks */ - ar.lleft = map->m_lblk; - err = ext4_ext_search_left(inode, path, &ar.lleft, &ar.pleft); - if (err) - goto out2; - ar.lright = map->m_lblk; - ex2 = NULL; - err = ext4_ext_search_right(inode, path, &ar.lright, &ar.pright, &ex2); - if (err) - goto out2; - - /* Check if the extent after searching to the right implies a - * cluster we can use. */ - if ((sbi->s_cluster_ratio > 1) && ex2 && - get_implied_cluster_alloc(inode->i_sb, map, ex2, path)) { - ar.len = allocated = map->m_len; - newblock = map->m_pblk; - map_from_cluster = true; - goto got_allocated_blocks; - } - - /* - * See if request is beyond maximum number of blocks we can have in - * a single extent. For an initialized extent this limit is - * EXT_INIT_MAX_LEN and for an unwritten extent this limit is - * EXT_UNWRITTEN_MAX_LEN. - */ - if (map->m_len > EXT_INIT_MAX_LEN && - !(flags & EXT4_GET_BLOCKS_UNWRIT_EXT)) - map->m_len = EXT_INIT_MAX_LEN; - else if (map->m_len > EXT_UNWRITTEN_MAX_LEN && - (flags & EXT4_GET_BLOCKS_UNWRIT_EXT)) - map->m_len = EXT_UNWRITTEN_MAX_LEN; - - /* Check if we can really insert (m_lblk)::(m_lblk + m_len) extent */ - newex.ee_len = cpu_to_le16(map->m_len); - err = ext4_ext_check_overlap(sbi, inode, &newex, path); - if (err) - allocated = ext4_ext_get_actual_len(&newex); - else - allocated = map->m_len; - - /* allocate new block */ - ar.inode = inode; - ar.goal = ext4_ext_find_goal(inode, path, map->m_lblk); - ar.logical = map->m_lblk; - /* - * We calculate the offset from the beginning of the cluster - * for the logical block number, since when we allocate a - * physical cluster, the physical block should start at the - * same offset from the beginning of the cluster. This is - * needed so that future calls to get_implied_cluster_alloc() - * work correctly. - */ - offset = EXT4_LBLK_COFF(sbi, map->m_lblk); - ar.len = EXT4_NUM_B2C(sbi, offset+allocated); - ar.goal -= offset; - ar.logical -= offset; - if (S_ISREG(inode->i_mode)) - ar.flags = EXT4_MB_HINT_DATA; - else - /* disable in-core preallocation for non-regular files */ - ar.flags = 0; - if (flags & EXT4_GET_BLOCKS_NO_NORMALIZE) - ar.flags |= EXT4_MB_HINT_NOPREALLOC; - if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) - ar.flags |= EXT4_MB_DELALLOC_RESERVED; - if (flags & EXT4_GET_BLOCKS_METADATA_NOFAIL) - ar.flags |= EXT4_MB_USE_RESERVED; - newblock = ext4_mb_new_blocks(handle, &ar, &err); - if (!newblock) - goto out2; - ext_debug("allocate new block: goal %llu, found %llu/%u\n", - ar.goal, newblock, allocated); - free_on_err = 1; - allocated_clusters = ar.len; - ar.len = EXT4_C2B(sbi, ar.len) - offset; - if (ar.len > allocated) - ar.len = allocated; - -got_allocated_blocks: - /* try to insert new extent into found leaf and return */ - ext4_ext_store_pblock(&newex, newblock + offset); - newex.ee_len = cpu_to_le16(ar.len); - /* Mark unwritten */ - if (flags & EXT4_GET_BLOCKS_UNWRIT_EXT){ - ext4_ext_mark_unwritten(&newex); - map->m_flags |= EXT4_MAP_UNWRITTEN; - } - - err = 0; - if ((flags & EXT4_GET_BLOCKS_KEEP_SIZE) == 0) - err = check_eofblocks_fl(handle, inode, map->m_lblk, - path, ar.len); - if (!err) - err = ext4_ext_insert_extent(handle, inode, &path, - &newex, flags); - - if (err && free_on_err) { - int fb_flags = flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE ? - EXT4_FREE_BLOCKS_NO_QUOT_UPDATE : 0; - /* free data blocks we just allocated */ - /* not a good idea to call discard here directly, - * but otherwise we'd need to call it every free() */ - ext4_discard_preallocations(inode); - ext4_free_blocks(handle, inode, NULL, newblock, - EXT4_C2B(sbi, allocated_clusters), fb_flags); - goto out2; - } - - /* previous routine could use block we allocated */ - newblock = ext4_ext_pblock(&newex); - allocated = ext4_ext_get_actual_len(&newex); - if (allocated > map->m_len) - allocated = map->m_len; - map->m_flags |= EXT4_MAP_NEW; - - /* - * Update reserved blocks/metadata blocks after successful - * block allocation which had been deferred till now. - */ - if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) { - unsigned int reserved_clusters; - /* - * Check how many clusters we had reserved this allocated range - */ - reserved_clusters = get_reserved_cluster_alloc(inode, - map->m_lblk, allocated); - if (!map_from_cluster) { - BUG_ON(allocated_clusters < reserved_clusters); - if (reserved_clusters < allocated_clusters) { - struct ext4_inode_info *ei = EXT4_I(inode); - int reservation = allocated_clusters - - reserved_clusters; - /* - * It seems we claimed few clusters outside of - * the range of this allocation. We should give - * it back to the reservation pool. This can - * happen in the following case: - * - * * Suppose s_cluster_ratio is 4 (i.e., each - * cluster has 4 blocks. Thus, the clusters - * are [0-3],[4-7],[8-11]... - * * First comes delayed allocation write for - * logical blocks 10 & 11. Since there were no - * previous delayed allocated blocks in the - * range [8-11], we would reserve 1 cluster - * for this write. - * * Next comes write for logical blocks 3 to 8. - * In this case, we will reserve 2 clusters - * (for [0-3] and [4-7]; and not for [8-11] as - * that range has a delayed allocated blocks. - * Thus total reserved clusters now becomes 3. - * * Now, during the delayed allocation writeout - * time, we will first write blocks [3-8] and - * allocate 3 clusters for writing these - * blocks. Also, we would claim all these - * three clusters above. - * * Now when we come here to writeout the - * blocks [10-11], we would expect to claim - * the reservation of 1 cluster we had made - * (and we would claim it since there are no - * more delayed allocated blocks in the range - * [8-11]. But our reserved cluster count had - * already gone to 0. - * - * Thus, at the step 4 above when we determine - * that there are still some unwritten delayed - * allocated blocks outside of our current - * block range, we should increment the - * reserved clusters count so that when the - * remaining blocks finally gets written, we - * could claim them. - */ - dquot_reserve_block(inode, - EXT4_C2B(sbi, reservation)); - spin_lock(&ei->i_block_reservation_lock); - ei->i_reserved_data_blocks += reservation; - spin_unlock(&ei->i_block_reservation_lock); - } - /* - * We will claim quota for all newly allocated blocks. - * We're updating the reserved space *after* the - * correction above so we do not accidentally free - * all the metadata reservation because we might - * actually need it later on. - */ - ext4_da_update_reserve_space(inode, allocated_clusters, - 1); - } - } - - /* - * Cache the extent and update transaction to commit on fdatasync only - * when it is _not_ an unwritten extent. - */ - if ((flags & EXT4_GET_BLOCKS_UNWRIT_EXT) == 0) - ext4_update_inode_fsync_trans(handle, inode, 1); - else - ext4_update_inode_fsync_trans(handle, inode, 0); -out: - if (allocated > map->m_len) - allocated = map->m_len; - ext4_ext_show_leaf(inode, path); - map->m_flags |= EXT4_MAP_MAPPED; - map->m_pblk = newblock; - map->m_len = allocated; -out2: - ext4_ext_drop_refs(path); - kfree(path); - - trace_ext4_ext_map_blocks_exit(inode, flags, map, - err ? err : allocated); - return err ? err : allocated; -} - -void ext4_ext_truncate(handle_t *handle, struct inode *inode) -{ - struct super_block *sb = inode->i_sb; - ext4_lblk_t last_block; - int err = 0; - - /* - * TODO: optimization is possible here. - * Probably we need not scan at all, - * because page truncation is enough. - */ - - /* we have to know where to truncate from in crash case */ - EXT4_I(inode)->i_disksize = inode->i_size; - ext4_mark_inode_dirty(handle, inode); - - last_block = (inode->i_size + sb->s_blocksize - 1) - >> EXT4_BLOCK_SIZE_BITS(sb); -retry: - err = ext4_es_remove_extent(inode, last_block, - EXT_MAX_BLOCKS - last_block); - if (err == -ENOMEM) { - cond_resched(); - congestion_wait(BLK_RW_ASYNC, HZ/50); - goto retry; - } - if (err) { - ext4_std_error(inode->i_sb, err); - return; - } - err = ext4_ext_remove_space(inode, last_block, EXT_MAX_BLOCKS - 1); - ext4_std_error(inode->i_sb, err); -} - -static int ext4_alloc_file_blocks(struct file *file, ext4_lblk_t offset, - ext4_lblk_t len, loff_t new_size, - int flags, int mode) -{ - struct inode *inode = file_inode(file); - handle_t *handle; - int ret = 0; - int ret2 = 0; - int retries = 0; - int depth = 0; - struct ext4_map_blocks map; - unsigned int credits; - loff_t epos; - - BUG_ON(!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)); - map.m_lblk = offset; - map.m_len = len; - /* - * Don't normalize the request if it can fit in one extent so - * that it doesn't get unnecessarily split into multiple - * extents. - */ - if (len <= EXT_UNWRITTEN_MAX_LEN) - flags |= EXT4_GET_BLOCKS_NO_NORMALIZE; - - /* - * credits to insert 1 extent into extent tree - */ - credits = ext4_chunk_trans_blocks(inode, len); - depth = ext_depth(inode); - -retry: - while (ret >= 0 && len) { - /* - * Recalculate credits when extent tree depth changes. - */ - if (depth >= 0 && depth != ext_depth(inode)) { - credits = ext4_chunk_trans_blocks(inode, len); - depth = ext_depth(inode); - } - - handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, - credits); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - break; - } - ret = ext4_map_blocks(handle, inode, &map, flags); - if (ret <= 0) { - ext4_debug("inode #%lu: block %u: len %u: " - "ext4_ext_map_blocks returned %d", - inode->i_ino, map.m_lblk, - map.m_len, ret); - ext4_mark_inode_dirty(handle, inode); - ret2 = ext4_journal_stop(handle); - break; - } - map.m_lblk += ret; - map.m_len = len = len - ret; - epos = (loff_t)map.m_lblk << inode->i_blkbits; - inode->i_ctime = ext4_current_time(inode); - if (new_size) { - if (epos > new_size) - epos = new_size; - if (ext4_update_inode_size(inode, epos) & 0x1) - inode->i_mtime = inode->i_ctime; - } else { - if (epos > inode->i_size) - ext4_set_inode_flag(inode, - EXT4_INODE_EOFBLOCKS); - } - ext4_mark_inode_dirty(handle, inode); - ret2 = ext4_journal_stop(handle); - if (ret2) - break; - } - if (ret == -ENOSPC && - ext4_should_retry_alloc(inode->i_sb, &retries)) { - ret = 0; - goto retry; - } - - return ret > 0 ? ret2 : ret; -} - -static long ext4_zero_range(struct file *file, loff_t offset, - loff_t len, int mode) -{ - struct inode *inode = file_inode(file); - handle_t *handle = NULL; - unsigned int max_blocks; - loff_t new_size = 0; - int ret = 0; - int flags; - int credits; - int partial_begin, partial_end; - loff_t start, end; - ext4_lblk_t lblk; - unsigned int blkbits = inode->i_blkbits; - - trace_ext4_zero_range(inode, offset, len, mode); - - if (!S_ISREG(inode->i_mode)) - return -EINVAL; - - /* Call ext4_force_commit to flush all data in case of data=journal. */ - if (ext4_should_journal_data(inode)) { - ret = ext4_force_commit(inode->i_sb); - if (ret) - return ret; - } - - /* - * Round up offset. This is not fallocate, we neet to zero out - * blocks, so convert interior block aligned part of the range to - * unwritten and possibly manually zero out unaligned parts of the - * range. - */ - start = round_up(offset, 1 << blkbits); - end = round_down((offset + len), 1 << blkbits); - - if (start < offset || end > offset + len) - return -EINVAL; - partial_begin = offset & ((1 << blkbits) - 1); - partial_end = (offset + len) & ((1 << blkbits) - 1); - - lblk = start >> blkbits; - max_blocks = (end >> blkbits); - if (max_blocks < lblk) - max_blocks = 0; - else - max_blocks -= lblk; - - inode_lock(inode); - - /* - * Indirect files do not support unwritten extnets - */ - if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { - ret = -EOPNOTSUPP; - goto out_mutex; - } - - if (!(mode & FALLOC_FL_KEEP_SIZE) && - offset + len > i_size_read(inode)) { - new_size = offset + len; - ret = inode_newsize_ok(inode, new_size); - if (ret) - goto out_mutex; - } - - flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT; - if (mode & FALLOC_FL_KEEP_SIZE) - flags |= EXT4_GET_BLOCKS_KEEP_SIZE; - - /* Wait all existing dio workers, newcomers will block on i_mutex */ - ext4_inode_block_unlocked_dio(inode); - inode_dio_wait(inode); - - /* Preallocate the range including the unaligned edges */ - if (partial_begin || partial_end) { - ret = ext4_alloc_file_blocks(file, - round_down(offset, 1 << blkbits) >> blkbits, - (round_up((offset + len), 1 << blkbits) - - round_down(offset, 1 << blkbits)) >> blkbits, - new_size, flags, mode); - if (ret) - goto out_dio; - - } - - /* Zero range excluding the unaligned edges */ - if (max_blocks > 0) { - flags |= (EXT4_GET_BLOCKS_CONVERT_UNWRITTEN | - EXT4_EX_NOCACHE); - - /* - * Prevent page faults from reinstantiating pages we have - * released from page cache. - */ - down_write(&EXT4_I(inode)->i_mmap_sem); - ret = ext4_update_disksize_before_punch(inode, offset, len); - if (ret) { - up_write(&EXT4_I(inode)->i_mmap_sem); - goto out_dio; - } - /* Now release the pages and zero block aligned part of pages */ - truncate_pagecache_range(inode, start, end - 1); - inode->i_mtime = inode->i_ctime = ext4_current_time(inode); - - ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, - flags, mode); - up_write(&EXT4_I(inode)->i_mmap_sem); - if (ret) - goto out_dio; - } - if (!partial_begin && !partial_end) - goto out_dio; - - /* - * In worst case we have to writeout two nonadjacent unwritten - * blocks and update the inode - */ - credits = (2 * ext4_ext_index_trans_blocks(inode, 2)) + 1; - if (ext4_should_journal_data(inode)) - credits += 2; - handle = ext4_journal_start(inode, EXT4_HT_MISC, credits); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - ext4_std_error(inode->i_sb, ret); - goto out_dio; - } - - inode->i_mtime = inode->i_ctime = ext4_current_time(inode); - if (new_size) { - ext4_update_inode_size(inode, new_size); - } else { - /* - * Mark that we allocate beyond EOF so the subsequent truncate - * can proceed even if the new size is the same as i_size. - */ - if ((offset + len) > i_size_read(inode)) - ext4_set_inode_flag(inode, EXT4_INODE_EOFBLOCKS); - } - ext4_mark_inode_dirty(handle, inode); - - /* Zero out partial block at the edges of the range */ - ret = ext4_zero_partial_blocks(handle, inode, offset, len); - - if (file->f_flags & O_SYNC) - ext4_handle_sync(handle); - - ext4_journal_stop(handle); -out_dio: - ext4_inode_resume_unlocked_dio(inode); -out_mutex: - inode_unlock(inode); - return ret; -} - -/* - * preallocate space for a file. This implements ext4's fallocate file - * operation, which gets called from sys_fallocate system call. - * For block-mapped files, posix_fallocate should fall back to the method - * of writing zeroes to the required new blocks (the same behavior which is - * expected for file systems which do not support fallocate() system call). - */ -long ext4_fallocate(struct file *file, int mode, loff_t offset, loff_t len) -{ - struct inode *inode = file_inode(file); - loff_t new_size = 0; - unsigned int max_blocks; - int ret = 0; - int flags; - ext4_lblk_t lblk; - unsigned int blkbits = inode->i_blkbits; - - /* - * Encrypted inodes can't handle collapse range or insert - * range since we would need to re-encrypt blocks with a - * different IV or XTS tweak (which are based on the logical - * block number). - * - * XXX It's not clear why zero range isn't working, but we'll - * leave it disabled for encrypted inodes for now. This is a - * bug we should fix.... - */ - if (ext4_encrypted_inode(inode) && - (mode & (FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_INSERT_RANGE | - FALLOC_FL_ZERO_RANGE))) - return -EOPNOTSUPP; - - /* Return error if mode is not supported */ - if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | - FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE | - FALLOC_FL_INSERT_RANGE)) - return -EOPNOTSUPP; - - if (mode & FALLOC_FL_PUNCH_HOLE) - return ext4_punch_hole(inode, offset, len); - - ret = ext4_convert_inline_data(inode); - if (ret) - return ret; - - if (mode & FALLOC_FL_COLLAPSE_RANGE) - return ext4_collapse_range(inode, offset, len); - - if (mode & FALLOC_FL_INSERT_RANGE) - return ext4_insert_range(inode, offset, len); - - if (mode & FALLOC_FL_ZERO_RANGE) - return ext4_zero_range(file, offset, len, mode); - - trace_ext4_fallocate_enter(inode, offset, len, mode); - lblk = offset >> blkbits; - - max_blocks = EXT4_MAX_BLOCKS(len, offset, blkbits); - flags = EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT; - if (mode & FALLOC_FL_KEEP_SIZE) - flags |= EXT4_GET_BLOCKS_KEEP_SIZE; - - inode_lock(inode); - - /* - * We only support preallocation for extent-based files only - */ - if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { - ret = -EOPNOTSUPP; - goto out; - } - - if (!(mode & FALLOC_FL_KEEP_SIZE) && - offset + len > i_size_read(inode)) { - new_size = offset + len; - ret = inode_newsize_ok(inode, new_size); - if (ret) - goto out; - } - - /* Wait all existing dio workers, newcomers will block on i_mutex */ - ext4_inode_block_unlocked_dio(inode); - inode_dio_wait(inode); - - ret = ext4_alloc_file_blocks(file, lblk, max_blocks, new_size, - flags, mode); - ext4_inode_resume_unlocked_dio(inode); - if (ret) - goto out; - - if (file->f_flags & O_SYNC && EXT4_SB(inode->i_sb)->s_journal) { - ret = jbd2_complete_transaction(EXT4_SB(inode->i_sb)->s_journal, - EXT4_I(inode)->i_sync_tid); - } -out: - inode_unlock(inode); - trace_ext4_fallocate_exit(inode, offset, max_blocks, ret); - return ret; -} - -/* - * This function convert a range of blocks to written extents - * The caller of this function will pass the start offset and the size. - * all unwritten extents within this range will be converted to - * written extents. - * - * This function is called from the direct IO end io call back - * function, to convert the fallocated extents after IO is completed. - * Returns 0 on success. - */ -int ext4_convert_unwritten_extents(handle_t *handle, struct inode *inode, - loff_t offset, ssize_t len) -{ - unsigned int max_blocks; - int ret = 0; - int ret2 = 0; - struct ext4_map_blocks map; - unsigned int credits, blkbits = inode->i_blkbits; - - map.m_lblk = offset >> blkbits; - max_blocks = EXT4_MAX_BLOCKS(len, offset, blkbits); - - /* - * This is somewhat ugly but the idea is clear: When transaction is - * reserved, everything goes into it. Otherwise we rather start several - * smaller transactions for conversion of each extent separately. - */ - if (handle) { - handle = ext4_journal_start_reserved(handle, - EXT4_HT_EXT_CONVERT); - if (IS_ERR(handle)) - return PTR_ERR(handle); - credits = 0; - } else { - /* - * credits to insert 1 extent into extent tree - */ - credits = ext4_chunk_trans_blocks(inode, max_blocks); - } - while (ret >= 0 && ret < max_blocks) { - map.m_lblk += ret; - map.m_len = (max_blocks -= ret); - if (credits) { - handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, - credits); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - break; - } - } - ret = ext4_map_blocks(handle, inode, &map, - EXT4_GET_BLOCKS_IO_CONVERT_EXT); - if (ret <= 0) - ext4_warning(inode->i_sb, - "inode #%lu: block %u: len %u: " - "ext4_ext_map_blocks returned %d", - inode->i_ino, map.m_lblk, - map.m_len, ret); - ext4_mark_inode_dirty(handle, inode); - if (credits) - ret2 = ext4_journal_stop(handle); - if (ret <= 0 || ret2) - break; - } - if (!credits) - ret2 = ext4_journal_stop(handle); - return ret > 0 ? ret2 : ret; -} - -/* - * If newes is not existing extent (newes->ec_pblk equals zero) find - * delayed extent at start of newes and update newes accordingly and - * return start of the next delayed extent. - * - * If newes is existing extent (newes->ec_pblk is not equal zero) - * return start of next delayed extent or EXT_MAX_BLOCKS if no delayed - * extent found. Leave newes unmodified. - */ -static int ext4_find_delayed_extent(struct inode *inode, - struct extent_status *newes) -{ - struct extent_status es; - ext4_lblk_t block, next_del; - - if (newes->es_pblk == 0) { - ext4_es_find_delayed_extent_range(inode, newes->es_lblk, - newes->es_lblk + newes->es_len - 1, &es); - - /* - * No extent in extent-tree contains block @newes->es_pblk, - * then the block may stay in 1)a hole or 2)delayed-extent. - */ - if (es.es_len == 0) - /* A hole found. */ - return 0; - - if (es.es_lblk > newes->es_lblk) { - /* A hole found. */ - newes->es_len = min(es.es_lblk - newes->es_lblk, - newes->es_len); - return 0; - } - - newes->es_len = es.es_lblk + es.es_len - newes->es_lblk; - } - - block = newes->es_lblk + newes->es_len; - ext4_es_find_delayed_extent_range(inode, block, EXT_MAX_BLOCKS, &es); - if (es.es_len == 0) - next_del = EXT_MAX_BLOCKS; - else - next_del = es.es_lblk; - - return next_del; -} -/* fiemap flags we can handle specified here */ -#define EXT4_FIEMAP_FLAGS (FIEMAP_FLAG_SYNC|FIEMAP_FLAG_XATTR) - -static int ext4_xattr_fiemap(struct inode *inode, - struct fiemap_extent_info *fieinfo) -{ - __u64 physical = 0; - __u64 length; - __u32 flags = FIEMAP_EXTENT_LAST; - int blockbits = inode->i_sb->s_blocksize_bits; - int error = 0; - - /* in-inode? */ - if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) { - struct ext4_iloc iloc; - int offset; /* offset of xattr in inode */ - - error = ext4_get_inode_loc(inode, &iloc); - if (error) - return error; - physical = (__u64)iloc.bh->b_blocknr << blockbits; - offset = EXT4_GOOD_OLD_INODE_SIZE + - EXT4_I(inode)->i_extra_isize; - physical += offset; - length = EXT4_SB(inode->i_sb)->s_inode_size - offset; - flags |= FIEMAP_EXTENT_DATA_INLINE; - brelse(iloc.bh); - } else { /* external block */ - physical = (__u64)EXT4_I(inode)->i_file_acl << blockbits; - length = inode->i_sb->s_blocksize; - } - - if (physical) - error = fiemap_fill_next_extent(fieinfo, 0, physical, - length, flags); - return (error < 0 ? error : 0); -} - -int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, - __u64 start, __u64 len) -{ - ext4_lblk_t start_blk; - int error = 0; - - if (ext4_has_inline_data(inode)) { - int has_inline = 1; - - error = ext4_inline_data_fiemap(inode, fieinfo, &has_inline, - start, len); - - if (has_inline) - return error; - } - - if (fieinfo->fi_flags & FIEMAP_FLAG_CACHE) { - error = ext4_ext_precache(inode); - if (error) - return error; - } - - /* fallback to generic here if not in extents fmt */ - if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) - return generic_block_fiemap(inode, fieinfo, start, len, - ext4_get_block); - - if (fiemap_check_flags(fieinfo, EXT4_FIEMAP_FLAGS)) - return -EBADR; - - if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) { - error = ext4_xattr_fiemap(inode, fieinfo); - } else { - ext4_lblk_t len_blks; - __u64 last_blk; - - start_blk = start >> inode->i_sb->s_blocksize_bits; - last_blk = (start + len - 1) >> inode->i_sb->s_blocksize_bits; - if (last_blk >= EXT_MAX_BLOCKS) - last_blk = EXT_MAX_BLOCKS-1; - len_blks = ((ext4_lblk_t) last_blk) - start_blk + 1; - - /* - * Walk the extent tree gathering extent information - * and pushing extents back to the user. - */ - error = ext4_fill_fiemap_extents(inode, start_blk, - len_blks, fieinfo); - } - return error; -} - -/* - * ext4_access_path: - * Function to access the path buffer for marking it dirty. - * It also checks if there are sufficient credits left in the journal handle - * to update path. - */ -static int -ext4_access_path(handle_t *handle, struct inode *inode, - struct ext4_ext_path *path) -{ - int credits, err; - - if (!ext4_handle_valid(handle)) - return 0; - - /* - * Check if need to extend journal credits - * 3 for leaf, sb, and inode plus 2 (bmap and group - * descriptor) for each block group; assume two block - * groups - */ - if (handle->h_buffer_credits < 7) { - credits = ext4_writepage_trans_blocks(inode); - err = ext4_ext_truncate_extend_restart(handle, inode, credits); - /* EAGAIN is success */ - if (err && err != -EAGAIN) - return err; - } - - err = ext4_ext_get_access(handle, inode, path); - return err; -} - -/* - * ext4_ext_shift_path_extents: - * Shift the extents of a path structure lying between path[depth].p_ext - * and EXT_LAST_EXTENT(path[depth].p_hdr), by @shift blocks. @SHIFT tells - * if it is right shift or left shift operation. - */ -static int -ext4_ext_shift_path_extents(struct ext4_ext_path *path, ext4_lblk_t shift, - struct inode *inode, handle_t *handle, - enum SHIFT_DIRECTION SHIFT) -{ - int depth, err = 0; - struct ext4_extent *ex_start, *ex_last; - bool update = 0; - depth = path->p_depth; - - while (depth >= 0) { - if (depth == path->p_depth) { - ex_start = path[depth].p_ext; - if (!ex_start) - return -EFSCORRUPTED; - - ex_last = EXT_LAST_EXTENT(path[depth].p_hdr); - - err = ext4_access_path(handle, inode, path + depth); - if (err) - goto out; - - if (ex_start == EXT_FIRST_EXTENT(path[depth].p_hdr)) - update = 1; - - while (ex_start <= ex_last) { - if (SHIFT == SHIFT_LEFT) { - le32_add_cpu(&ex_start->ee_block, - -shift); - /* Try to merge to the left. */ - if ((ex_start > - EXT_FIRST_EXTENT(path[depth].p_hdr)) - && - ext4_ext_try_to_merge_right(inode, - path, ex_start - 1)) - ex_last--; - else - ex_start++; - } else { - le32_add_cpu(&ex_last->ee_block, shift); - ext4_ext_try_to_merge_right(inode, path, - ex_last); - ex_last--; - } - } - err = ext4_ext_dirty(handle, inode, path + depth); - if (err) - goto out; - - if (--depth < 0 || !update) - break; - } - - /* Update index too */ - err = ext4_access_path(handle, inode, path + depth); - if (err) - goto out; - - if (SHIFT == SHIFT_LEFT) - le32_add_cpu(&path[depth].p_idx->ei_block, -shift); - else - le32_add_cpu(&path[depth].p_idx->ei_block, shift); - err = ext4_ext_dirty(handle, inode, path + depth); - if (err) - goto out; - - /* we are done if current index is not a starting index */ - if (path[depth].p_idx != EXT_FIRST_INDEX(path[depth].p_hdr)) - break; - - depth--; - } - -out: - return err; -} - -/* - * ext4_ext_shift_extents: - * All the extents which lies in the range from @start to the last allocated - * block for the @inode are shifted either towards left or right (depending - * upon @SHIFT) by @shift blocks. - * On success, 0 is returned, error otherwise. - */ -static int -ext4_ext_shift_extents(struct inode *inode, handle_t *handle, - ext4_lblk_t start, ext4_lblk_t shift, - enum SHIFT_DIRECTION SHIFT) -{ - struct ext4_ext_path *path; - int ret = 0, depth; - struct ext4_extent *extent; - ext4_lblk_t stop, *iterator, ex_start, ex_end; - - /* Let path point to the last extent */ - path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL, 0); - if (IS_ERR(path)) - return PTR_ERR(path); - - depth = path->p_depth; - extent = path[depth].p_ext; - if (!extent) - goto out; - - stop = le32_to_cpu(extent->ee_block) + - ext4_ext_get_actual_len(extent); - - /* - * In case of left shift, Don't start shifting extents until we make - * sure the hole is big enough to accommodate the shift. - */ - if (SHIFT == SHIFT_LEFT) { - path = ext4_find_extent(inode, start - 1, &path, 0); - if (IS_ERR(path)) - return PTR_ERR(path); - depth = path->p_depth; - extent = path[depth].p_ext; - if (extent) { - ex_start = le32_to_cpu(extent->ee_block); - ex_end = le32_to_cpu(extent->ee_block) + - ext4_ext_get_actual_len(extent); - } else { - ex_start = 0; - ex_end = 0; - } - - if ((start == ex_start && shift > ex_start) || - (shift > start - ex_end)) { - ext4_ext_drop_refs(path); - kfree(path); - return -EINVAL; - } - } - - /* - * In case of left shift, iterator points to start and it is increased - * till we reach stop. In case of right shift, iterator points to stop - * and it is decreased till we reach start. - */ - if (SHIFT == SHIFT_LEFT) - iterator = &start; - else - iterator = &stop; - - /* Its safe to start updating extents */ - while (start < stop) { - path = ext4_find_extent(inode, *iterator, &path, 0); - if (IS_ERR(path)) - return PTR_ERR(path); - depth = path->p_depth; - extent = path[depth].p_ext; - if (!extent) { - EXT4_ERROR_INODE(inode, "unexpected hole at %lu", - (unsigned long) *iterator); - return -EFSCORRUPTED; - } - if (SHIFT == SHIFT_LEFT && *iterator > - le32_to_cpu(extent->ee_block)) { - /* Hole, move to the next extent */ - if (extent < EXT_LAST_EXTENT(path[depth].p_hdr)) { - path[depth].p_ext++; - } else { - *iterator = ext4_ext_next_allocated_block(path); - continue; - } - } - - if (SHIFT == SHIFT_LEFT) { - extent = EXT_LAST_EXTENT(path[depth].p_hdr); - *iterator = le32_to_cpu(extent->ee_block) + - ext4_ext_get_actual_len(extent); - } else { - extent = EXT_FIRST_EXTENT(path[depth].p_hdr); - *iterator = le32_to_cpu(extent->ee_block) > 0 ? - le32_to_cpu(extent->ee_block) - 1 : 0; - /* Update path extent in case we need to stop */ - while (le32_to_cpu(extent->ee_block) < start) - extent++; - path[depth].p_ext = extent; - } - ret = ext4_ext_shift_path_extents(path, shift, inode, - handle, SHIFT); - if (ret) - break; - } -out: - ext4_ext_drop_refs(path); - kfree(path); - return ret; -} - -/* - * ext4_collapse_range: - * This implements the fallocate's collapse range functionality for ext4 - * Returns: 0 and non-zero on error. - */ -int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len) -{ - struct super_block *sb = inode->i_sb; - ext4_lblk_t punch_start, punch_stop; - handle_t *handle; - unsigned int credits; - loff_t new_size, ioffset; - int ret; - - /* - * We need to test this early because xfstests assumes that a - * collapse range of (0, 1) will return EOPNOTSUPP if the file - * system does not support collapse range. - */ - if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) - return -EOPNOTSUPP; - - /* Collapse range works only on fs block size aligned offsets. */ - if (offset & (EXT4_CLUSTER_SIZE(sb) - 1) || - len & (EXT4_CLUSTER_SIZE(sb) - 1)) - return -EINVAL; - - if (!S_ISREG(inode->i_mode)) - return -EINVAL; - - trace_ext4_collapse_range(inode, offset, len); - - punch_start = offset >> EXT4_BLOCK_SIZE_BITS(sb); - punch_stop = (offset + len) >> EXT4_BLOCK_SIZE_BITS(sb); - - /* Call ext4_force_commit to flush all data in case of data=journal. */ - if (ext4_should_journal_data(inode)) { - ret = ext4_force_commit(inode->i_sb); - if (ret) - return ret; - } - - inode_lock(inode); - /* - * There is no need to overlap collapse range with EOF, in which case - * it is effectively a truncate operation - */ - if (offset + len >= i_size_read(inode)) { - ret = -EINVAL; - goto out_mutex; - } - - /* Currently just for extent based files */ - if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) { - ret = -EOPNOTSUPP; - goto out_mutex; - } - - /* Wait for existing dio to complete */ - ext4_inode_block_unlocked_dio(inode); - inode_dio_wait(inode); - - /* - * Prevent page faults from reinstantiating pages we have released from - * page cache. - */ - down_write(&EXT4_I(inode)->i_mmap_sem); - /* - * Need to round down offset to be aligned with page size boundary - * for page size > block size. - */ - ioffset = round_down(offset, PAGE_SIZE); - /* - * Write tail of the last page before removed range since it will get - * removed from the page cache below. - */ - ret = filemap_write_and_wait_range(inode->i_mapping, ioffset, offset); - if (ret) - goto out_mmap; - /* - * Write data that will be shifted to preserve them when discarding - * page cache below. We are also protected from pages becoming dirty - * by i_mmap_sem. - */ - ret = filemap_write_and_wait_range(inode->i_mapping, offset + len, - LLONG_MAX); - if (ret) - goto out_mmap; - truncate_pagecache(inode, ioffset); - - credits = ext4_writepage_trans_blocks(inode); - handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - goto out_mmap; - } - - down_write(&EXT4_I(inode)->i_data_sem); - ext4_discard_preallocations(inode); - - ret = ext4_es_remove_extent(inode, punch_start, - EXT_MAX_BLOCKS - punch_start); - if (ret) { - up_write(&EXT4_I(inode)->i_data_sem); - goto out_stop; - } - - ret = ext4_ext_remove_space(inode, punch_start, punch_stop - 1); - if (ret) { - up_write(&EXT4_I(inode)->i_data_sem); - goto out_stop; - } - ext4_discard_preallocations(inode); - - ret = ext4_ext_shift_extents(inode, handle, punch_stop, - punch_stop - punch_start, SHIFT_LEFT); - if (ret) { - up_write(&EXT4_I(inode)->i_data_sem); - goto out_stop; - } - - new_size = i_size_read(inode) - len; - i_size_write(inode, new_size); - EXT4_I(inode)->i_disksize = new_size; - - up_write(&EXT4_I(inode)->i_data_sem); - if (IS_SYNC(inode)) - ext4_handle_sync(handle); - inode->i_mtime = inode->i_ctime = ext4_current_time(inode); - ext4_mark_inode_dirty(handle, inode); - -out_stop: - ext4_journal_stop(handle); -out_mmap: - up_write(&EXT4_I(inode)->i_mmap_sem); - ext4_inode_resume_unlocked_dio(inode); -out_mutex: - inode_unlock(inode); - return ret; -} - -/* - * ext4_insert_range: - * This function implements the FALLOC_FL_INSERT_RANGE flag of fallocate. - * The data blocks starting from @offset to the EOF are shifted by @len - * towards right to create a hole in the @inode. Inode size is increased - * by len bytes. - * Returns 0 on success, error otherwise. - */ -int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len) -{ - struct super_block *sb = inode->i_sb; - handle_t *handle; - struct ext4_ext_path *path; - struct ext4_extent *extent; - ext4_lblk_t offset_lblk, len_lblk, ee_start_lblk = 0; - unsigned int credits, ee_len; - int ret = 0, depth, split_flag = 0; - loff_t ioffset; - - /* - * We need to test this early because xfstests assumes that an - * insert range of (0, 1) will return EOPNOTSUPP if the file - * system does not support insert range. - */ - if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) - return -EOPNOTSUPP; - - /* Insert range works only on fs block size aligned offsets. */ - if (offset & (EXT4_CLUSTER_SIZE(sb) - 1) || - len & (EXT4_CLUSTER_SIZE(sb) - 1)) - return -EINVAL; - - if (!S_ISREG(inode->i_mode)) - return -EOPNOTSUPP; - - trace_ext4_insert_range(inode, offset, len); - - offset_lblk = offset >> EXT4_BLOCK_SIZE_BITS(sb); - len_lblk = len >> EXT4_BLOCK_SIZE_BITS(sb); - - /* Call ext4_force_commit to flush all data in case of data=journal */ - if (ext4_should_journal_data(inode)) { - ret = ext4_force_commit(inode->i_sb); - if (ret) - return ret; - } - - inode_lock(inode); - /* Currently just for extent based files */ - if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) { - ret = -EOPNOTSUPP; - goto out_mutex; - } - - /* Check for wrap through zero */ - if (inode->i_size + len > inode->i_sb->s_maxbytes) { - ret = -EFBIG; - goto out_mutex; - } - - /* Offset should be less than i_size */ - if (offset >= i_size_read(inode)) { - ret = -EINVAL; - goto out_mutex; - } - - /* Wait for existing dio to complete */ - ext4_inode_block_unlocked_dio(inode); - inode_dio_wait(inode); - - /* - * Prevent page faults from reinstantiating pages we have released from - * page cache. - */ - down_write(&EXT4_I(inode)->i_mmap_sem); - /* - * Need to round down to align start offset to page size boundary - * for page size > block size. - */ - ioffset = round_down(offset, PAGE_SIZE); - /* Write out all dirty pages */ - ret = filemap_write_and_wait_range(inode->i_mapping, ioffset, - LLONG_MAX); - if (ret) - goto out_mmap; - truncate_pagecache(inode, ioffset); - - credits = ext4_writepage_trans_blocks(inode); - handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - goto out_mmap; - } - - /* Expand file to avoid data loss if there is error while shifting */ - inode->i_size += len; - EXT4_I(inode)->i_disksize += len; - inode->i_mtime = inode->i_ctime = ext4_current_time(inode); - ret = ext4_mark_inode_dirty(handle, inode); - if (ret) - goto out_stop; - - down_write(&EXT4_I(inode)->i_data_sem); - ext4_discard_preallocations(inode); - - path = ext4_find_extent(inode, offset_lblk, NULL, 0); - if (IS_ERR(path)) { - up_write(&EXT4_I(inode)->i_data_sem); - goto out_stop; - } - - depth = ext_depth(inode); - extent = path[depth].p_ext; - if (extent) { - ee_start_lblk = le32_to_cpu(extent->ee_block); - ee_len = ext4_ext_get_actual_len(extent); - - /* - * If offset_lblk is not the starting block of extent, split - * the extent @offset_lblk - */ - if ((offset_lblk > ee_start_lblk) && - (offset_lblk < (ee_start_lblk + ee_len))) { - if (ext4_ext_is_unwritten(extent)) - split_flag = EXT4_EXT_MARK_UNWRIT1 | - EXT4_EXT_MARK_UNWRIT2; - ret = ext4_split_extent_at(handle, inode, &path, - offset_lblk, split_flag, - EXT4_EX_NOCACHE | - EXT4_GET_BLOCKS_PRE_IO | - EXT4_GET_BLOCKS_METADATA_NOFAIL); - } - - ext4_ext_drop_refs(path); - kfree(path); - if (ret < 0) { - up_write(&EXT4_I(inode)->i_data_sem); - goto out_stop; - } - } else { - ext4_ext_drop_refs(path); - kfree(path); - } - - ret = ext4_es_remove_extent(inode, offset_lblk, - EXT_MAX_BLOCKS - offset_lblk); - if (ret) { - up_write(&EXT4_I(inode)->i_data_sem); - goto out_stop; - } - - /* - * if offset_lblk lies in a hole which is at start of file, use - * ee_start_lblk to shift extents - */ - ret = ext4_ext_shift_extents(inode, handle, - ee_start_lblk > offset_lblk ? ee_start_lblk : offset_lblk, - len_lblk, SHIFT_RIGHT); - - up_write(&EXT4_I(inode)->i_data_sem); - if (IS_SYNC(inode)) - ext4_handle_sync(handle); - -out_stop: - ext4_journal_stop(handle); -out_mmap: - up_write(&EXT4_I(inode)->i_mmap_sem); - ext4_inode_resume_unlocked_dio(inode); -out_mutex: - inode_unlock(inode); - return ret; -} - -/** - * ext4_swap_extents - Swap extents between two inodes - * - * @inode1: First inode - * @inode2: Second inode - * @lblk1: Start block for first inode - * @lblk2: Start block for second inode - * @count: Number of blocks to swap - * @mark_unwritten: Mark second inode's extents as unwritten after swap - * @erp: Pointer to save error value - * - * This helper routine does exactly what is promise "swap extents". All other - * stuff such as page-cache locking consistency, bh mapping consistency or - * extent's data copying must be performed by caller. - * Locking: - * i_mutex is held for both inodes - * i_data_sem is locked for write for both inodes - * Assumptions: - * All pages from requested range are locked for both inodes - */ -int -ext4_swap_extents(handle_t *handle, struct inode *inode1, - struct inode *inode2, ext4_lblk_t lblk1, ext4_lblk_t lblk2, - ext4_lblk_t count, int unwritten, int *erp) -{ - struct ext4_ext_path *path1 = NULL; - struct ext4_ext_path *path2 = NULL; - int replaced_count = 0; - - BUG_ON(!rwsem_is_locked(&EXT4_I(inode1)->i_data_sem)); - BUG_ON(!rwsem_is_locked(&EXT4_I(inode2)->i_data_sem)); - BUG_ON(!inode_is_locked(inode1)); - BUG_ON(!inode_is_locked(inode2)); - - *erp = ext4_es_remove_extent(inode1, lblk1, count); - if (unlikely(*erp)) - return 0; - *erp = ext4_es_remove_extent(inode2, lblk2, count); - if (unlikely(*erp)) - return 0; - - while (count) { - struct ext4_extent *ex1, *ex2, tmp_ex; - ext4_lblk_t e1_blk, e2_blk; - int e1_len, e2_len, len; - int split = 0; - - path1 = ext4_find_extent(inode1, lblk1, NULL, EXT4_EX_NOCACHE); - if (IS_ERR(path1)) { - *erp = PTR_ERR(path1); - path1 = NULL; - finish: - count = 0; - goto repeat; - } - path2 = ext4_find_extent(inode2, lblk2, NULL, EXT4_EX_NOCACHE); - if (IS_ERR(path2)) { - *erp = PTR_ERR(path2); - path2 = NULL; - goto finish; - } - ex1 = path1[path1->p_depth].p_ext; - ex2 = path2[path2->p_depth].p_ext; - /* Do we have somthing to swap ? */ - if (unlikely(!ex2 || !ex1)) - goto finish; - - e1_blk = le32_to_cpu(ex1->ee_block); - e2_blk = le32_to_cpu(ex2->ee_block); - e1_len = ext4_ext_get_actual_len(ex1); - e2_len = ext4_ext_get_actual_len(ex2); - - /* Hole handling */ - if (!in_range(lblk1, e1_blk, e1_len) || - !in_range(lblk2, e2_blk, e2_len)) { - ext4_lblk_t next1, next2; - - /* if hole after extent, then go to next extent */ - next1 = ext4_ext_next_allocated_block(path1); - next2 = ext4_ext_next_allocated_block(path2); - /* If hole before extent, then shift to that extent */ - if (e1_blk > lblk1) - next1 = e1_blk; - if (e2_blk > lblk2) - next2 = e1_blk; - /* Do we have something to swap */ - if (next1 == EXT_MAX_BLOCKS || next2 == EXT_MAX_BLOCKS) - goto finish; - /* Move to the rightest boundary */ - len = next1 - lblk1; - if (len < next2 - lblk2) - len = next2 - lblk2; - if (len > count) - len = count; - lblk1 += len; - lblk2 += len; - count -= len; - goto repeat; - } - - /* Prepare left boundary */ - if (e1_blk < lblk1) { - split = 1; - *erp = ext4_force_split_extent_at(handle, inode1, - &path1, lblk1, 0); - if (unlikely(*erp)) - goto finish; - } - if (e2_blk < lblk2) { - split = 1; - *erp = ext4_force_split_extent_at(handle, inode2, - &path2, lblk2, 0); - if (unlikely(*erp)) - goto finish; - } - /* ext4_split_extent_at() may result in leaf extent split, - * path must to be revalidated. */ - if (split) - goto repeat; - - /* Prepare right boundary */ - len = count; - if (len > e1_blk + e1_len - lblk1) - len = e1_blk + e1_len - lblk1; - if (len > e2_blk + e2_len - lblk2) - len = e2_blk + e2_len - lblk2; - - if (len != e1_len) { - split = 1; - *erp = ext4_force_split_extent_at(handle, inode1, - &path1, lblk1 + len, 0); - if (unlikely(*erp)) - goto finish; - } - if (len != e2_len) { - split = 1; - *erp = ext4_force_split_extent_at(handle, inode2, - &path2, lblk2 + len, 0); - if (*erp) - goto finish; - } - /* ext4_split_extent_at() may result in leaf extent split, - * path must to be revalidated. */ - if (split) - goto repeat; - - BUG_ON(e2_len != e1_len); - *erp = ext4_ext_get_access(handle, inode1, path1 + path1->p_depth); - if (unlikely(*erp)) - goto finish; - *erp = ext4_ext_get_access(handle, inode2, path2 + path2->p_depth); - if (unlikely(*erp)) - goto finish; - - /* Both extents are fully inside boundaries. Swap it now */ - tmp_ex = *ex1; - ext4_ext_store_pblock(ex1, ext4_ext_pblock(ex2)); - ext4_ext_store_pblock(ex2, ext4_ext_pblock(&tmp_ex)); - ex1->ee_len = cpu_to_le16(e2_len); - ex2->ee_len = cpu_to_le16(e1_len); - if (unwritten) - ext4_ext_mark_unwritten(ex2); - if (ext4_ext_is_unwritten(&tmp_ex)) - ext4_ext_mark_unwritten(ex1); - - ext4_ext_try_to_merge(handle, inode2, path2, ex2); - ext4_ext_try_to_merge(handle, inode1, path1, ex1); - *erp = ext4_ext_dirty(handle, inode2, path2 + - path2->p_depth); - if (unlikely(*erp)) - goto finish; - *erp = ext4_ext_dirty(handle, inode1, path1 + - path1->p_depth); - /* - * Looks scarry ah..? second inode already points to new blocks, - * and it was successfully dirtied. But luckily error may happen - * only due to journal error, so full transaction will be - * aborted anyway. - */ - if (unlikely(*erp)) - goto finish; - lblk1 += len; - lblk2 += len; - replaced_count += len; - count -= len; - - repeat: - ext4_ext_drop_refs(path1); - kfree(path1); - ext4_ext_drop_refs(path2); - kfree(path2); - path1 = path2 = NULL; - } - return replaced_count; -} diff --git a/src/linux/fs/ext4/extents_status.c b/src/linux/fs/ext4/extents_status.c deleted file mode 100644 index 37e0592..0000000 --- a/src/linux/fs/ext4/extents_status.c +++ /dev/null @@ -1,1254 +0,0 @@ -/* - * fs/ext4/extents_status.c - * - * Written by Yongqiang Yang - * Modified by - * Allison Henderson - * Hugh Dickins - * Zheng Liu - * - * Ext4 extents status tree core functions. - */ -#include -#include -#include -#include "ext4.h" - -#include - -/* - * According to previous discussion in Ext4 Developer Workshop, we - * will introduce a new structure called io tree to track all extent - * status in order to solve some problems that we have met - * (e.g. Reservation space warning), and provide extent-level locking. - * Delay extent tree is the first step to achieve this goal. It is - * original built by Yongqiang Yang. At that time it is called delay - * extent tree, whose goal is only track delayed extents in memory to - * simplify the implementation of fiemap and bigalloc, and introduce - * lseek SEEK_DATA/SEEK_HOLE support. That is why it is still called - * delay extent tree at the first commit. But for better understand - * what it does, it has been rename to extent status tree. - * - * Step1: - * Currently the first step has been done. All delayed extents are - * tracked in the tree. It maintains the delayed extent when a delayed - * allocation is issued, and the delayed extent is written out or - * invalidated. Therefore the implementation of fiemap and bigalloc - * are simplified, and SEEK_DATA/SEEK_HOLE are introduced. - * - * The following comment describes the implemenmtation of extent - * status tree and future works. - * - * Step2: - * In this step all extent status are tracked by extent status tree. - * Thus, we can first try to lookup a block mapping in this tree before - * finding it in extent tree. Hence, single extent cache can be removed - * because extent status tree can do a better job. Extents in status - * tree are loaded on-demand. Therefore, the extent status tree may not - * contain all of the extents in a file. Meanwhile we define a shrinker - * to reclaim memory from extent status tree because fragmented extent - * tree will make status tree cost too much memory. written/unwritten/- - * hole extents in the tree will be reclaimed by this shrinker when we - * are under high memory pressure. Delayed extents will not be - * reclimed because fiemap, bigalloc, and seek_data/hole need it. - */ - -/* - * Extent status tree implementation for ext4. - * - * - * ========================================================================== - * Extent status tree tracks all extent status. - * - * 1. Why we need to implement extent status tree? - * - * Without extent status tree, ext4 identifies a delayed extent by looking - * up page cache, this has several deficiencies - complicated, buggy, - * and inefficient code. - * - * FIEMAP, SEEK_HOLE/DATA, bigalloc, and writeout all need to know if a - * block or a range of blocks are belonged to a delayed extent. - * - * Let us have a look at how they do without extent status tree. - * -- FIEMAP - * FIEMAP looks up page cache to identify delayed allocations from holes. - * - * -- SEEK_HOLE/DATA - * SEEK_HOLE/DATA has the same problem as FIEMAP. - * - * -- bigalloc - * bigalloc looks up page cache to figure out if a block is - * already under delayed allocation or not to determine whether - * quota reserving is needed for the cluster. - * - * -- writeout - * Writeout looks up whole page cache to see if a buffer is - * mapped, If there are not very many delayed buffers, then it is - * time comsuming. - * - * With extent status tree implementation, FIEMAP, SEEK_HOLE/DATA, - * bigalloc and writeout can figure out if a block or a range of - * blocks is under delayed allocation(belonged to a delayed extent) or - * not by searching the extent tree. - * - * - * ========================================================================== - * 2. Ext4 extent status tree impelmentation - * - * -- extent - * A extent is a range of blocks which are contiguous logically and - * physically. Unlike extent in extent tree, this extent in ext4 is - * a in-memory struct, there is no corresponding on-disk data. There - * is no limit on length of extent, so an extent can contain as many - * blocks as they are contiguous logically and physically. - * - * -- extent status tree - * Every inode has an extent status tree and all allocation blocks - * are added to the tree with different status. The extent in the - * tree are ordered by logical block no. - * - * -- operations on a extent status tree - * There are three important operations on a delayed extent tree: find - * next extent, adding a extent(a range of blocks) and removing a extent. - * - * -- race on a extent status tree - * Extent status tree is protected by inode->i_es_lock. - * - * -- memory consumption - * Fragmented extent tree will make extent status tree cost too much - * memory. Hence, we will reclaim written/unwritten/hole extents from - * the tree under a heavy memory pressure. - * - * - * ========================================================================== - * 3. Performance analysis - * - * -- overhead - * 1. There is a cache extent for write access, so if writes are - * not very random, adding space operaions are in O(1) time. - * - * -- gain - * 2. Code is much simpler, more readable, more maintainable and - * more efficient. - * - * - * ========================================================================== - * 4. TODO list - * - * -- Refactor delayed space reservation - * - * -- Extent-level locking - */ - -static struct kmem_cache *ext4_es_cachep; - -static int __es_insert_extent(struct inode *inode, struct extent_status *newes); -static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk, - ext4_lblk_t end); -static int es_reclaim_extents(struct ext4_inode_info *ei, int *nr_to_scan); -static int __es_shrink(struct ext4_sb_info *sbi, int nr_to_scan, - struct ext4_inode_info *locked_ei); - -int __init ext4_init_es(void) -{ - ext4_es_cachep = kmem_cache_create("ext4_extent_status", - sizeof(struct extent_status), - 0, (SLAB_RECLAIM_ACCOUNT), NULL); - if (ext4_es_cachep == NULL) - return -ENOMEM; - return 0; -} - -void ext4_exit_es(void) -{ - if (ext4_es_cachep) - kmem_cache_destroy(ext4_es_cachep); -} - -void ext4_es_init_tree(struct ext4_es_tree *tree) -{ - tree->root = RB_ROOT; - tree->cache_es = NULL; -} - -#ifdef ES_DEBUG__ -static void ext4_es_print_tree(struct inode *inode) -{ - struct ext4_es_tree *tree; - struct rb_node *node; - - printk(KERN_DEBUG "status extents for inode %lu:", inode->i_ino); - tree = &EXT4_I(inode)->i_es_tree; - node = rb_first(&tree->root); - while (node) { - struct extent_status *es; - es = rb_entry(node, struct extent_status, rb_node); - printk(KERN_DEBUG " [%u/%u) %llu %x", - es->es_lblk, es->es_len, - ext4_es_pblock(es), ext4_es_status(es)); - node = rb_next(node); - } - printk(KERN_DEBUG "\n"); -} -#else -#define ext4_es_print_tree(inode) -#endif - -static inline ext4_lblk_t ext4_es_end(struct extent_status *es) -{ - BUG_ON(es->es_lblk + es->es_len < es->es_lblk); - return es->es_lblk + es->es_len - 1; -} - -/* - * search through the tree for an delayed extent with a given offset. If - * it can't be found, try to find next extent. - */ -static struct extent_status *__es_tree_search(struct rb_root *root, - ext4_lblk_t lblk) -{ - struct rb_node *node = root->rb_node; - struct extent_status *es = NULL; - - while (node) { - es = rb_entry(node, struct extent_status, rb_node); - if (lblk < es->es_lblk) - node = node->rb_left; - else if (lblk > ext4_es_end(es)) - node = node->rb_right; - else - return es; - } - - if (es && lblk < es->es_lblk) - return es; - - if (es && lblk > ext4_es_end(es)) { - node = rb_next(&es->rb_node); - return node ? rb_entry(node, struct extent_status, rb_node) : - NULL; - } - - return NULL; -} - -/* - * ext4_es_find_delayed_extent_range: find the 1st delayed extent covering - * @es->lblk if it exists, otherwise, the next extent after @es->lblk. - * - * @inode: the inode which owns delayed extents - * @lblk: the offset where we start to search - * @end: the offset where we stop to search - * @es: delayed extent that we found - */ -void ext4_es_find_delayed_extent_range(struct inode *inode, - ext4_lblk_t lblk, ext4_lblk_t end, - struct extent_status *es) -{ - struct ext4_es_tree *tree = NULL; - struct extent_status *es1 = NULL; - struct rb_node *node; - - BUG_ON(es == NULL); - BUG_ON(end < lblk); - trace_ext4_es_find_delayed_extent_range_enter(inode, lblk); - - read_lock(&EXT4_I(inode)->i_es_lock); - tree = &EXT4_I(inode)->i_es_tree; - - /* find extent in cache firstly */ - es->es_lblk = es->es_len = es->es_pblk = 0; - if (tree->cache_es) { - es1 = tree->cache_es; - if (in_range(lblk, es1->es_lblk, es1->es_len)) { - es_debug("%u cached by [%u/%u) %llu %x\n", - lblk, es1->es_lblk, es1->es_len, - ext4_es_pblock(es1), ext4_es_status(es1)); - goto out; - } - } - - es1 = __es_tree_search(&tree->root, lblk); - -out: - if (es1 && !ext4_es_is_delayed(es1)) { - while ((node = rb_next(&es1->rb_node)) != NULL) { - es1 = rb_entry(node, struct extent_status, rb_node); - if (es1->es_lblk > end) { - es1 = NULL; - break; - } - if (ext4_es_is_delayed(es1)) - break; - } - } - - if (es1 && ext4_es_is_delayed(es1)) { - tree->cache_es = es1; - es->es_lblk = es1->es_lblk; - es->es_len = es1->es_len; - es->es_pblk = es1->es_pblk; - } - - read_unlock(&EXT4_I(inode)->i_es_lock); - - trace_ext4_es_find_delayed_extent_range_exit(inode, es); -} - -static void ext4_es_list_add(struct inode *inode) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - - if (!list_empty(&ei->i_es_list)) - return; - - spin_lock(&sbi->s_es_lock); - if (list_empty(&ei->i_es_list)) { - list_add_tail(&ei->i_es_list, &sbi->s_es_list); - sbi->s_es_nr_inode++; - } - spin_unlock(&sbi->s_es_lock); -} - -static void ext4_es_list_del(struct inode *inode) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - - spin_lock(&sbi->s_es_lock); - if (!list_empty(&ei->i_es_list)) { - list_del_init(&ei->i_es_list); - sbi->s_es_nr_inode--; - WARN_ON_ONCE(sbi->s_es_nr_inode < 0); - } - spin_unlock(&sbi->s_es_lock); -} - -static struct extent_status * -ext4_es_alloc_extent(struct inode *inode, ext4_lblk_t lblk, ext4_lblk_t len, - ext4_fsblk_t pblk) -{ - struct extent_status *es; - es = kmem_cache_alloc(ext4_es_cachep, GFP_ATOMIC); - if (es == NULL) - return NULL; - es->es_lblk = lblk; - es->es_len = len; - es->es_pblk = pblk; - - /* - * We don't count delayed extent because we never try to reclaim them - */ - if (!ext4_es_is_delayed(es)) { - if (!EXT4_I(inode)->i_es_shk_nr++) - ext4_es_list_add(inode); - percpu_counter_inc(&EXT4_SB(inode->i_sb)-> - s_es_stats.es_stats_shk_cnt); - } - - EXT4_I(inode)->i_es_all_nr++; - percpu_counter_inc(&EXT4_SB(inode->i_sb)->s_es_stats.es_stats_all_cnt); - - return es; -} - -static void ext4_es_free_extent(struct inode *inode, struct extent_status *es) -{ - EXT4_I(inode)->i_es_all_nr--; - percpu_counter_dec(&EXT4_SB(inode->i_sb)->s_es_stats.es_stats_all_cnt); - - /* Decrease the shrink counter when this es is not delayed */ - if (!ext4_es_is_delayed(es)) { - BUG_ON(EXT4_I(inode)->i_es_shk_nr == 0); - if (!--EXT4_I(inode)->i_es_shk_nr) - ext4_es_list_del(inode); - percpu_counter_dec(&EXT4_SB(inode->i_sb)-> - s_es_stats.es_stats_shk_cnt); - } - - kmem_cache_free(ext4_es_cachep, es); -} - -/* - * Check whether or not two extents can be merged - * Condition: - * - logical block number is contiguous - * - physical block number is contiguous - * - status is equal - */ -static int ext4_es_can_be_merged(struct extent_status *es1, - struct extent_status *es2) -{ - if (ext4_es_type(es1) != ext4_es_type(es2)) - return 0; - - if (((__u64) es1->es_len) + es2->es_len > EXT_MAX_BLOCKS) { - pr_warn("ES assertion failed when merging extents. " - "The sum of lengths of es1 (%d) and es2 (%d) " - "is bigger than allowed file size (%d)\n", - es1->es_len, es2->es_len, EXT_MAX_BLOCKS); - WARN_ON(1); - return 0; - } - - if (((__u64) es1->es_lblk) + es1->es_len != es2->es_lblk) - return 0; - - if ((ext4_es_is_written(es1) || ext4_es_is_unwritten(es1)) && - (ext4_es_pblock(es1) + es1->es_len == ext4_es_pblock(es2))) - return 1; - - if (ext4_es_is_hole(es1)) - return 1; - - /* we need to check delayed extent is without unwritten status */ - if (ext4_es_is_delayed(es1) && !ext4_es_is_unwritten(es1)) - return 1; - - return 0; -} - -static struct extent_status * -ext4_es_try_to_merge_left(struct inode *inode, struct extent_status *es) -{ - struct ext4_es_tree *tree = &EXT4_I(inode)->i_es_tree; - struct extent_status *es1; - struct rb_node *node; - - node = rb_prev(&es->rb_node); - if (!node) - return es; - - es1 = rb_entry(node, struct extent_status, rb_node); - if (ext4_es_can_be_merged(es1, es)) { - es1->es_len += es->es_len; - if (ext4_es_is_referenced(es)) - ext4_es_set_referenced(es1); - rb_erase(&es->rb_node, &tree->root); - ext4_es_free_extent(inode, es); - es = es1; - } - - return es; -} - -static struct extent_status * -ext4_es_try_to_merge_right(struct inode *inode, struct extent_status *es) -{ - struct ext4_es_tree *tree = &EXT4_I(inode)->i_es_tree; - struct extent_status *es1; - struct rb_node *node; - - node = rb_next(&es->rb_node); - if (!node) - return es; - - es1 = rb_entry(node, struct extent_status, rb_node); - if (ext4_es_can_be_merged(es, es1)) { - es->es_len += es1->es_len; - if (ext4_es_is_referenced(es1)) - ext4_es_set_referenced(es); - rb_erase(node, &tree->root); - ext4_es_free_extent(inode, es1); - } - - return es; -} - -#ifdef ES_AGGRESSIVE_TEST -#include "ext4_extents.h" /* Needed when ES_AGGRESSIVE_TEST is defined */ - -static void ext4_es_insert_extent_ext_check(struct inode *inode, - struct extent_status *es) -{ - struct ext4_ext_path *path = NULL; - struct ext4_extent *ex; - ext4_lblk_t ee_block; - ext4_fsblk_t ee_start; - unsigned short ee_len; - int depth, ee_status, es_status; - - path = ext4_find_extent(inode, es->es_lblk, NULL, EXT4_EX_NOCACHE); - if (IS_ERR(path)) - return; - - depth = ext_depth(inode); - ex = path[depth].p_ext; - - if (ex) { - - ee_block = le32_to_cpu(ex->ee_block); - ee_start = ext4_ext_pblock(ex); - ee_len = ext4_ext_get_actual_len(ex); - - ee_status = ext4_ext_is_unwritten(ex) ? 1 : 0; - es_status = ext4_es_is_unwritten(es) ? 1 : 0; - - /* - * Make sure ex and es are not overlap when we try to insert - * a delayed/hole extent. - */ - if (!ext4_es_is_written(es) && !ext4_es_is_unwritten(es)) { - if (in_range(es->es_lblk, ee_block, ee_len)) { - pr_warn("ES insert assertion failed for " - "inode: %lu we can find an extent " - "at block [%d/%d/%llu/%c], but we " - "want to add a delayed/hole extent " - "[%d/%d/%llu/%x]\n", - inode->i_ino, ee_block, ee_len, - ee_start, ee_status ? 'u' : 'w', - es->es_lblk, es->es_len, - ext4_es_pblock(es), ext4_es_status(es)); - } - goto out; - } - - /* - * We don't check ee_block == es->es_lblk, etc. because es - * might be a part of whole extent, vice versa. - */ - if (es->es_lblk < ee_block || - ext4_es_pblock(es) != ee_start + es->es_lblk - ee_block) { - pr_warn("ES insert assertion failed for inode: %lu " - "ex_status [%d/%d/%llu/%c] != " - "es_status [%d/%d/%llu/%c]\n", inode->i_ino, - ee_block, ee_len, ee_start, - ee_status ? 'u' : 'w', es->es_lblk, es->es_len, - ext4_es_pblock(es), es_status ? 'u' : 'w'); - goto out; - } - - if (ee_status ^ es_status) { - pr_warn("ES insert assertion failed for inode: %lu " - "ex_status [%d/%d/%llu/%c] != " - "es_status [%d/%d/%llu/%c]\n", inode->i_ino, - ee_block, ee_len, ee_start, - ee_status ? 'u' : 'w', es->es_lblk, es->es_len, - ext4_es_pblock(es), es_status ? 'u' : 'w'); - } - } else { - /* - * We can't find an extent on disk. So we need to make sure - * that we don't want to add an written/unwritten extent. - */ - if (!ext4_es_is_delayed(es) && !ext4_es_is_hole(es)) { - pr_warn("ES insert assertion failed for inode: %lu " - "can't find an extent at block %d but we want " - "to add a written/unwritten extent " - "[%d/%d/%llu/%x]\n", inode->i_ino, - es->es_lblk, es->es_lblk, es->es_len, - ext4_es_pblock(es), ext4_es_status(es)); - } - } -out: - ext4_ext_drop_refs(path); - kfree(path); -} - -static void ext4_es_insert_extent_ind_check(struct inode *inode, - struct extent_status *es) -{ - struct ext4_map_blocks map; - int retval; - - /* - * Here we call ext4_ind_map_blocks to lookup a block mapping because - * 'Indirect' structure is defined in indirect.c. So we couldn't - * access direct/indirect tree from outside. It is too dirty to define - * this function in indirect.c file. - */ - - map.m_lblk = es->es_lblk; - map.m_len = es->es_len; - - retval = ext4_ind_map_blocks(NULL, inode, &map, 0); - if (retval > 0) { - if (ext4_es_is_delayed(es) || ext4_es_is_hole(es)) { - /* - * We want to add a delayed/hole extent but this - * block has been allocated. - */ - pr_warn("ES insert assertion failed for inode: %lu " - "We can find blocks but we want to add a " - "delayed/hole extent [%d/%d/%llu/%x]\n", - inode->i_ino, es->es_lblk, es->es_len, - ext4_es_pblock(es), ext4_es_status(es)); - return; - } else if (ext4_es_is_written(es)) { - if (retval != es->es_len) { - pr_warn("ES insert assertion failed for " - "inode: %lu retval %d != es_len %d\n", - inode->i_ino, retval, es->es_len); - return; - } - if (map.m_pblk != ext4_es_pblock(es)) { - pr_warn("ES insert assertion failed for " - "inode: %lu m_pblk %llu != " - "es_pblk %llu\n", - inode->i_ino, map.m_pblk, - ext4_es_pblock(es)); - return; - } - } else { - /* - * We don't need to check unwritten extent because - * indirect-based file doesn't have it. - */ - BUG_ON(1); - } - } else if (retval == 0) { - if (ext4_es_is_written(es)) { - pr_warn("ES insert assertion failed for inode: %lu " - "We can't find the block but we want to add " - "a written extent [%d/%d/%llu/%x]\n", - inode->i_ino, es->es_lblk, es->es_len, - ext4_es_pblock(es), ext4_es_status(es)); - return; - } - } -} - -static inline void ext4_es_insert_extent_check(struct inode *inode, - struct extent_status *es) -{ - /* - * We don't need to worry about the race condition because - * caller takes i_data_sem locking. - */ - BUG_ON(!rwsem_is_locked(&EXT4_I(inode)->i_data_sem)); - if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) - ext4_es_insert_extent_ext_check(inode, es); - else - ext4_es_insert_extent_ind_check(inode, es); -} -#else -static inline void ext4_es_insert_extent_check(struct inode *inode, - struct extent_status *es) -{ -} -#endif - -static int __es_insert_extent(struct inode *inode, struct extent_status *newes) -{ - struct ext4_es_tree *tree = &EXT4_I(inode)->i_es_tree; - struct rb_node **p = &tree->root.rb_node; - struct rb_node *parent = NULL; - struct extent_status *es; - - while (*p) { - parent = *p; - es = rb_entry(parent, struct extent_status, rb_node); - - if (newes->es_lblk < es->es_lblk) { - if (ext4_es_can_be_merged(newes, es)) { - /* - * Here we can modify es_lblk directly - * because it isn't overlapped. - */ - es->es_lblk = newes->es_lblk; - es->es_len += newes->es_len; - if (ext4_es_is_written(es) || - ext4_es_is_unwritten(es)) - ext4_es_store_pblock(es, - newes->es_pblk); - es = ext4_es_try_to_merge_left(inode, es); - goto out; - } - p = &(*p)->rb_left; - } else if (newes->es_lblk > ext4_es_end(es)) { - if (ext4_es_can_be_merged(es, newes)) { - es->es_len += newes->es_len; - es = ext4_es_try_to_merge_right(inode, es); - goto out; - } - p = &(*p)->rb_right; - } else { - BUG_ON(1); - return -EINVAL; - } - } - - es = ext4_es_alloc_extent(inode, newes->es_lblk, newes->es_len, - newes->es_pblk); - if (!es) - return -ENOMEM; - rb_link_node(&es->rb_node, parent, p); - rb_insert_color(&es->rb_node, &tree->root); - -out: - tree->cache_es = es; - return 0; -} - -/* - * ext4_es_insert_extent() adds information to an inode's extent - * status tree. - * - * Return 0 on success, error code on failure. - */ -int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk, - ext4_lblk_t len, ext4_fsblk_t pblk, - unsigned int status) -{ - struct extent_status newes; - ext4_lblk_t end = lblk + len - 1; - int err = 0; - - es_debug("add [%u/%u) %llu %x to extent status tree of inode %lu\n", - lblk, len, pblk, status, inode->i_ino); - - if (!len) - return 0; - - BUG_ON(end < lblk); - - if ((status & EXTENT_STATUS_DELAYED) && - (status & EXTENT_STATUS_WRITTEN)) { - ext4_warning(inode->i_sb, "Inserting extent [%u/%u] as " - " delayed and written which can potentially " - " cause data loss.", lblk, len); - WARN_ON(1); - } - - newes.es_lblk = lblk; - newes.es_len = len; - ext4_es_store_pblock_status(&newes, pblk, status); - trace_ext4_es_insert_extent(inode, &newes); - - ext4_es_insert_extent_check(inode, &newes); - - write_lock(&EXT4_I(inode)->i_es_lock); - err = __es_remove_extent(inode, lblk, end); - if (err != 0) - goto error; -retry: - err = __es_insert_extent(inode, &newes); - if (err == -ENOMEM && __es_shrink(EXT4_SB(inode->i_sb), - 128, EXT4_I(inode))) - goto retry; - if (err == -ENOMEM && !ext4_es_is_delayed(&newes)) - err = 0; - -error: - write_unlock(&EXT4_I(inode)->i_es_lock); - - ext4_es_print_tree(inode); - - return err; -} - -/* - * ext4_es_cache_extent() inserts information into the extent status - * tree if and only if there isn't information about the range in - * question already. - */ -void ext4_es_cache_extent(struct inode *inode, ext4_lblk_t lblk, - ext4_lblk_t len, ext4_fsblk_t pblk, - unsigned int status) -{ - struct extent_status *es; - struct extent_status newes; - ext4_lblk_t end = lblk + len - 1; - - newes.es_lblk = lblk; - newes.es_len = len; - ext4_es_store_pblock_status(&newes, pblk, status); - trace_ext4_es_cache_extent(inode, &newes); - - if (!len) - return; - - BUG_ON(end < lblk); - - write_lock(&EXT4_I(inode)->i_es_lock); - - es = __es_tree_search(&EXT4_I(inode)->i_es_tree.root, lblk); - if (!es || es->es_lblk > end) - __es_insert_extent(inode, &newes); - write_unlock(&EXT4_I(inode)->i_es_lock); -} - -/* - * ext4_es_lookup_extent() looks up an extent in extent status tree. - * - * ext4_es_lookup_extent is called by ext4_map_blocks/ext4_da_map_blocks. - * - * Return: 1 on found, 0 on not - */ -int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk, - struct extent_status *es) -{ - struct ext4_es_tree *tree; - struct ext4_es_stats *stats; - struct extent_status *es1 = NULL; - struct rb_node *node; - int found = 0; - - trace_ext4_es_lookup_extent_enter(inode, lblk); - es_debug("lookup extent in block %u\n", lblk); - - tree = &EXT4_I(inode)->i_es_tree; - read_lock(&EXT4_I(inode)->i_es_lock); - - /* find extent in cache firstly */ - es->es_lblk = es->es_len = es->es_pblk = 0; - if (tree->cache_es) { - es1 = tree->cache_es; - if (in_range(lblk, es1->es_lblk, es1->es_len)) { - es_debug("%u cached by [%u/%u)\n", - lblk, es1->es_lblk, es1->es_len); - found = 1; - goto out; - } - } - - node = tree->root.rb_node; - while (node) { - es1 = rb_entry(node, struct extent_status, rb_node); - if (lblk < es1->es_lblk) - node = node->rb_left; - else if (lblk > ext4_es_end(es1)) - node = node->rb_right; - else { - found = 1; - break; - } - } - -out: - stats = &EXT4_SB(inode->i_sb)->s_es_stats; - if (found) { - BUG_ON(!es1); - es->es_lblk = es1->es_lblk; - es->es_len = es1->es_len; - es->es_pblk = es1->es_pblk; - if (!ext4_es_is_referenced(es1)) - ext4_es_set_referenced(es1); - stats->es_stats_cache_hits++; - } else { - stats->es_stats_cache_misses++; - } - - read_unlock(&EXT4_I(inode)->i_es_lock); - - trace_ext4_es_lookup_extent_exit(inode, es, found); - return found; -} - -static int __es_remove_extent(struct inode *inode, ext4_lblk_t lblk, - ext4_lblk_t end) -{ - struct ext4_es_tree *tree = &EXT4_I(inode)->i_es_tree; - struct rb_node *node; - struct extent_status *es; - struct extent_status orig_es; - ext4_lblk_t len1, len2; - ext4_fsblk_t block; - int err; - -retry: - err = 0; - es = __es_tree_search(&tree->root, lblk); - if (!es) - goto out; - if (es->es_lblk > end) - goto out; - - /* Simply invalidate cache_es. */ - tree->cache_es = NULL; - - orig_es.es_lblk = es->es_lblk; - orig_es.es_len = es->es_len; - orig_es.es_pblk = es->es_pblk; - - len1 = lblk > es->es_lblk ? lblk - es->es_lblk : 0; - len2 = ext4_es_end(es) > end ? ext4_es_end(es) - end : 0; - if (len1 > 0) - es->es_len = len1; - if (len2 > 0) { - if (len1 > 0) { - struct extent_status newes; - - newes.es_lblk = end + 1; - newes.es_len = len2; - block = 0x7FDEADBEEFULL; - if (ext4_es_is_written(&orig_es) || - ext4_es_is_unwritten(&orig_es)) - block = ext4_es_pblock(&orig_es) + - orig_es.es_len - len2; - ext4_es_store_pblock_status(&newes, block, - ext4_es_status(&orig_es)); - err = __es_insert_extent(inode, &newes); - if (err) { - es->es_lblk = orig_es.es_lblk; - es->es_len = orig_es.es_len; - if ((err == -ENOMEM) && - __es_shrink(EXT4_SB(inode->i_sb), - 128, EXT4_I(inode))) - goto retry; - goto out; - } - } else { - es->es_lblk = end + 1; - es->es_len = len2; - if (ext4_es_is_written(es) || - ext4_es_is_unwritten(es)) { - block = orig_es.es_pblk + orig_es.es_len - len2; - ext4_es_store_pblock(es, block); - } - } - goto out; - } - - if (len1 > 0) { - node = rb_next(&es->rb_node); - if (node) - es = rb_entry(node, struct extent_status, rb_node); - else - es = NULL; - } - - while (es && ext4_es_end(es) <= end) { - node = rb_next(&es->rb_node); - rb_erase(&es->rb_node, &tree->root); - ext4_es_free_extent(inode, es); - if (!node) { - es = NULL; - break; - } - es = rb_entry(node, struct extent_status, rb_node); - } - - if (es && es->es_lblk < end + 1) { - ext4_lblk_t orig_len = es->es_len; - - len1 = ext4_es_end(es) - end; - es->es_lblk = end + 1; - es->es_len = len1; - if (ext4_es_is_written(es) || ext4_es_is_unwritten(es)) { - block = es->es_pblk + orig_len - len1; - ext4_es_store_pblock(es, block); - } - } - -out: - return err; -} - -/* - * ext4_es_remove_extent() removes a space from a extent status tree. - * - * Return 0 on success, error code on failure. - */ -int ext4_es_remove_extent(struct inode *inode, ext4_lblk_t lblk, - ext4_lblk_t len) -{ - ext4_lblk_t end; - int err = 0; - - trace_ext4_es_remove_extent(inode, lblk, len); - es_debug("remove [%u/%u) from extent status tree of inode %lu\n", - lblk, len, inode->i_ino); - - if (!len) - return err; - - end = lblk + len - 1; - BUG_ON(end < lblk); - - /* - * ext4_clear_inode() depends on us taking i_es_lock unconditionally - * so that we are sure __es_shrink() is done with the inode before it - * is reclaimed. - */ - write_lock(&EXT4_I(inode)->i_es_lock); - err = __es_remove_extent(inode, lblk, end); - write_unlock(&EXT4_I(inode)->i_es_lock); - ext4_es_print_tree(inode); - return err; -} - -static int __es_shrink(struct ext4_sb_info *sbi, int nr_to_scan, - struct ext4_inode_info *locked_ei) -{ - struct ext4_inode_info *ei; - struct ext4_es_stats *es_stats; - ktime_t start_time; - u64 scan_time; - int nr_to_walk; - int nr_shrunk = 0; - int retried = 0, nr_skipped = 0; - - es_stats = &sbi->s_es_stats; - start_time = ktime_get(); - -retry: - spin_lock(&sbi->s_es_lock); - nr_to_walk = sbi->s_es_nr_inode; - while (nr_to_walk-- > 0) { - if (list_empty(&sbi->s_es_list)) { - spin_unlock(&sbi->s_es_lock); - goto out; - } - ei = list_first_entry(&sbi->s_es_list, struct ext4_inode_info, - i_es_list); - /* Move the inode to the tail */ - list_move_tail(&ei->i_es_list, &sbi->s_es_list); - - /* - * Normally we try hard to avoid shrinking precached inodes, - * but we will as a last resort. - */ - if (!retried && ext4_test_inode_state(&ei->vfs_inode, - EXT4_STATE_EXT_PRECACHED)) { - nr_skipped++; - continue; - } - - if (ei == locked_ei || !write_trylock(&ei->i_es_lock)) { - nr_skipped++; - continue; - } - /* - * Now we hold i_es_lock which protects us from inode reclaim - * freeing inode under us - */ - spin_unlock(&sbi->s_es_lock); - - nr_shrunk += es_reclaim_extents(ei, &nr_to_scan); - write_unlock(&ei->i_es_lock); - - if (nr_to_scan <= 0) - goto out; - spin_lock(&sbi->s_es_lock); - } - spin_unlock(&sbi->s_es_lock); - - /* - * If we skipped any inodes, and we weren't able to make any - * forward progress, try again to scan precached inodes. - */ - if ((nr_shrunk == 0) && nr_skipped && !retried) { - retried++; - goto retry; - } - - if (locked_ei && nr_shrunk == 0) - nr_shrunk = es_reclaim_extents(locked_ei, &nr_to_scan); - -out: - scan_time = ktime_to_ns(ktime_sub(ktime_get(), start_time)); - if (likely(es_stats->es_stats_scan_time)) - es_stats->es_stats_scan_time = (scan_time + - es_stats->es_stats_scan_time*3) / 4; - else - es_stats->es_stats_scan_time = scan_time; - if (scan_time > es_stats->es_stats_max_scan_time) - es_stats->es_stats_max_scan_time = scan_time; - if (likely(es_stats->es_stats_shrunk)) - es_stats->es_stats_shrunk = (nr_shrunk + - es_stats->es_stats_shrunk*3) / 4; - else - es_stats->es_stats_shrunk = nr_shrunk; - - trace_ext4_es_shrink(sbi->s_sb, nr_shrunk, scan_time, - nr_skipped, retried); - return nr_shrunk; -} - -static unsigned long ext4_es_count(struct shrinker *shrink, - struct shrink_control *sc) -{ - unsigned long nr; - struct ext4_sb_info *sbi; - - sbi = container_of(shrink, struct ext4_sb_info, s_es_shrinker); - nr = percpu_counter_read_positive(&sbi->s_es_stats.es_stats_shk_cnt); - trace_ext4_es_shrink_count(sbi->s_sb, sc->nr_to_scan, nr); - return nr; -} - -static unsigned long ext4_es_scan(struct shrinker *shrink, - struct shrink_control *sc) -{ - struct ext4_sb_info *sbi = container_of(shrink, - struct ext4_sb_info, s_es_shrinker); - int nr_to_scan = sc->nr_to_scan; - int ret, nr_shrunk; - - ret = percpu_counter_read_positive(&sbi->s_es_stats.es_stats_shk_cnt); - trace_ext4_es_shrink_scan_enter(sbi->s_sb, nr_to_scan, ret); - - if (!nr_to_scan) - return ret; - - nr_shrunk = __es_shrink(sbi, nr_to_scan, NULL); - - trace_ext4_es_shrink_scan_exit(sbi->s_sb, nr_shrunk, ret); - return nr_shrunk; -} - -int ext4_seq_es_shrinker_info_show(struct seq_file *seq, void *v) -{ - struct ext4_sb_info *sbi = EXT4_SB((struct super_block *) seq->private); - struct ext4_es_stats *es_stats = &sbi->s_es_stats; - struct ext4_inode_info *ei, *max = NULL; - unsigned int inode_cnt = 0; - - if (v != SEQ_START_TOKEN) - return 0; - - /* here we just find an inode that has the max nr. of objects */ - spin_lock(&sbi->s_es_lock); - list_for_each_entry(ei, &sbi->s_es_list, i_es_list) { - inode_cnt++; - if (max && max->i_es_all_nr < ei->i_es_all_nr) - max = ei; - else if (!max) - max = ei; - } - spin_unlock(&sbi->s_es_lock); - - seq_printf(seq, "stats:\n %lld objects\n %lld reclaimable objects\n", - percpu_counter_sum_positive(&es_stats->es_stats_all_cnt), - percpu_counter_sum_positive(&es_stats->es_stats_shk_cnt)); - seq_printf(seq, " %lu/%lu cache hits/misses\n", - es_stats->es_stats_cache_hits, - es_stats->es_stats_cache_misses); - if (inode_cnt) - seq_printf(seq, " %d inodes on list\n", inode_cnt); - - seq_printf(seq, "average:\n %llu us scan time\n", - div_u64(es_stats->es_stats_scan_time, 1000)); - seq_printf(seq, " %lu shrunk objects\n", es_stats->es_stats_shrunk); - if (inode_cnt) - seq_printf(seq, - "maximum:\n %lu inode (%u objects, %u reclaimable)\n" - " %llu us max scan time\n", - max->vfs_inode.i_ino, max->i_es_all_nr, max->i_es_shk_nr, - div_u64(es_stats->es_stats_max_scan_time, 1000)); - - return 0; -} - -int ext4_es_register_shrinker(struct ext4_sb_info *sbi) -{ - int err; - - /* Make sure we have enough bits for physical block number */ - BUILD_BUG_ON(ES_SHIFT < 48); - INIT_LIST_HEAD(&sbi->s_es_list); - sbi->s_es_nr_inode = 0; - spin_lock_init(&sbi->s_es_lock); - sbi->s_es_stats.es_stats_shrunk = 0; - sbi->s_es_stats.es_stats_cache_hits = 0; - sbi->s_es_stats.es_stats_cache_misses = 0; - sbi->s_es_stats.es_stats_scan_time = 0; - sbi->s_es_stats.es_stats_max_scan_time = 0; - err = percpu_counter_init(&sbi->s_es_stats.es_stats_all_cnt, 0, GFP_KERNEL); - if (err) - return err; - err = percpu_counter_init(&sbi->s_es_stats.es_stats_shk_cnt, 0, GFP_KERNEL); - if (err) - goto err1; - - sbi->s_es_shrinker.scan_objects = ext4_es_scan; - sbi->s_es_shrinker.count_objects = ext4_es_count; - sbi->s_es_shrinker.seeks = DEFAULT_SEEKS; - err = register_shrinker(&sbi->s_es_shrinker); - if (err) - goto err2; - - return 0; - -err2: - percpu_counter_destroy(&sbi->s_es_stats.es_stats_shk_cnt); -err1: - percpu_counter_destroy(&sbi->s_es_stats.es_stats_all_cnt); - return err; -} - -void ext4_es_unregister_shrinker(struct ext4_sb_info *sbi) -{ - percpu_counter_destroy(&sbi->s_es_stats.es_stats_all_cnt); - percpu_counter_destroy(&sbi->s_es_stats.es_stats_shk_cnt); - unregister_shrinker(&sbi->s_es_shrinker); -} - -/* - * Shrink extents in given inode from ei->i_es_shrink_lblk till end. Scan at - * most *nr_to_scan extents, update *nr_to_scan accordingly. - * - * Return 0 if we hit end of tree / interval, 1 if we exhausted nr_to_scan. - * Increment *nr_shrunk by the number of reclaimed extents. Also update - * ei->i_es_shrink_lblk to where we should continue scanning. - */ -static int es_do_reclaim_extents(struct ext4_inode_info *ei, ext4_lblk_t end, - int *nr_to_scan, int *nr_shrunk) -{ - struct inode *inode = &ei->vfs_inode; - struct ext4_es_tree *tree = &ei->i_es_tree; - struct extent_status *es; - struct rb_node *node; - - es = __es_tree_search(&tree->root, ei->i_es_shrink_lblk); - if (!es) - goto out_wrap; - node = &es->rb_node; - while (*nr_to_scan > 0) { - if (es->es_lblk > end) { - ei->i_es_shrink_lblk = end + 1; - return 0; - } - - (*nr_to_scan)--; - node = rb_next(&es->rb_node); - /* - * We can't reclaim delayed extent from status tree because - * fiemap, bigallic, and seek_data/hole need to use it. - */ - if (ext4_es_is_delayed(es)) - goto next; - if (ext4_es_is_referenced(es)) { - ext4_es_clear_referenced(es); - goto next; - } - - rb_erase(&es->rb_node, &tree->root); - ext4_es_free_extent(inode, es); - (*nr_shrunk)++; -next: - if (!node) - goto out_wrap; - es = rb_entry(node, struct extent_status, rb_node); - } - ei->i_es_shrink_lblk = es->es_lblk; - return 1; -out_wrap: - ei->i_es_shrink_lblk = 0; - return 0; -} - -static int es_reclaim_extents(struct ext4_inode_info *ei, int *nr_to_scan) -{ - struct inode *inode = &ei->vfs_inode; - int nr_shrunk = 0; - ext4_lblk_t start = ei->i_es_shrink_lblk; - static DEFINE_RATELIMIT_STATE(_rs, DEFAULT_RATELIMIT_INTERVAL, - DEFAULT_RATELIMIT_BURST); - - if (ei->i_es_shk_nr == 0) - return 0; - - if (ext4_test_inode_state(inode, EXT4_STATE_EXT_PRECACHED) && - __ratelimit(&_rs)) - ext4_warning(inode->i_sb, "forced shrink of precached extents"); - - if (!es_do_reclaim_extents(ei, EXT_MAX_BLOCKS, nr_to_scan, &nr_shrunk) && - start != 0) - es_do_reclaim_extents(ei, start - 1, nr_to_scan, &nr_shrunk); - - ei->i_es_tree.cache_es = NULL; - return nr_shrunk; -} diff --git a/src/linux/fs/ext4/extents_status.h b/src/linux/fs/ext4/extents_status.h deleted file mode 100644 index f7aa24f..0000000 --- a/src/linux/fs/ext4/extents_status.h +++ /dev/null @@ -1,177 +0,0 @@ -/* - * fs/ext4/extents_status.h - * - * Written by Yongqiang Yang - * Modified by - * Allison Henderson - * Zheng Liu - * - */ - -#ifndef _EXT4_EXTENTS_STATUS_H -#define _EXT4_EXTENTS_STATUS_H - -/* - * Turn on ES_DEBUG__ to get lots of info about extent status operations. - */ -#ifdef ES_DEBUG__ -#define es_debug(fmt, ...) printk(fmt, ##__VA_ARGS__) -#else -#define es_debug(fmt, ...) no_printk(fmt, ##__VA_ARGS__) -#endif - -/* - * With ES_AGGRESSIVE_TEST defined, the result of es caching will be - * checked with old map_block's result. - */ -#define ES_AGGRESSIVE_TEST__ - -/* - * These flags live in the high bits of extent_status.es_pblk - */ -enum { - ES_WRITTEN_B, - ES_UNWRITTEN_B, - ES_DELAYED_B, - ES_HOLE_B, - ES_REFERENCED_B, - ES_FLAGS -}; - -#define ES_SHIFT (sizeof(ext4_fsblk_t)*8 - ES_FLAGS) -#define ES_MASK (~((ext4_fsblk_t)0) << ES_SHIFT) - -#define EXTENT_STATUS_WRITTEN (1 << ES_WRITTEN_B) -#define EXTENT_STATUS_UNWRITTEN (1 << ES_UNWRITTEN_B) -#define EXTENT_STATUS_DELAYED (1 << ES_DELAYED_B) -#define EXTENT_STATUS_HOLE (1 << ES_HOLE_B) -#define EXTENT_STATUS_REFERENCED (1 << ES_REFERENCED_B) - -#define ES_TYPE_MASK ((ext4_fsblk_t)(EXTENT_STATUS_WRITTEN | \ - EXTENT_STATUS_UNWRITTEN | \ - EXTENT_STATUS_DELAYED | \ - EXTENT_STATUS_HOLE) << ES_SHIFT) - -struct ext4_sb_info; -struct ext4_extent; - -struct extent_status { - struct rb_node rb_node; - ext4_lblk_t es_lblk; /* first logical block extent covers */ - ext4_lblk_t es_len; /* length of extent in block */ - ext4_fsblk_t es_pblk; /* first physical block */ -}; - -struct ext4_es_tree { - struct rb_root root; - struct extent_status *cache_es; /* recently accessed extent */ -}; - -struct ext4_es_stats { - unsigned long es_stats_shrunk; - unsigned long es_stats_cache_hits; - unsigned long es_stats_cache_misses; - u64 es_stats_scan_time; - u64 es_stats_max_scan_time; - struct percpu_counter es_stats_all_cnt; - struct percpu_counter es_stats_shk_cnt; -}; - -extern int __init ext4_init_es(void); -extern void ext4_exit_es(void); -extern void ext4_es_init_tree(struct ext4_es_tree *tree); - -extern int ext4_es_insert_extent(struct inode *inode, ext4_lblk_t lblk, - ext4_lblk_t len, ext4_fsblk_t pblk, - unsigned int status); -extern void ext4_es_cache_extent(struct inode *inode, ext4_lblk_t lblk, - ext4_lblk_t len, ext4_fsblk_t pblk, - unsigned int status); -extern int ext4_es_remove_extent(struct inode *inode, ext4_lblk_t lblk, - ext4_lblk_t len); -extern void ext4_es_find_delayed_extent_range(struct inode *inode, - ext4_lblk_t lblk, ext4_lblk_t end, - struct extent_status *es); -extern int ext4_es_lookup_extent(struct inode *inode, ext4_lblk_t lblk, - struct extent_status *es); - -static inline unsigned int ext4_es_status(struct extent_status *es) -{ - return es->es_pblk >> ES_SHIFT; -} - -static inline unsigned int ext4_es_type(struct extent_status *es) -{ - return (es->es_pblk & ES_TYPE_MASK) >> ES_SHIFT; -} - -static inline int ext4_es_is_written(struct extent_status *es) -{ - return (ext4_es_type(es) & EXTENT_STATUS_WRITTEN) != 0; -} - -static inline int ext4_es_is_unwritten(struct extent_status *es) -{ - return (ext4_es_type(es) & EXTENT_STATUS_UNWRITTEN) != 0; -} - -static inline int ext4_es_is_delayed(struct extent_status *es) -{ - return (ext4_es_type(es) & EXTENT_STATUS_DELAYED) != 0; -} - -static inline int ext4_es_is_hole(struct extent_status *es) -{ - return (ext4_es_type(es) & EXTENT_STATUS_HOLE) != 0; -} - -static inline void ext4_es_set_referenced(struct extent_status *es) -{ - es->es_pblk |= ((ext4_fsblk_t)EXTENT_STATUS_REFERENCED) << ES_SHIFT; -} - -static inline void ext4_es_clear_referenced(struct extent_status *es) -{ - es->es_pblk &= ~(((ext4_fsblk_t)EXTENT_STATUS_REFERENCED) << ES_SHIFT); -} - -static inline int ext4_es_is_referenced(struct extent_status *es) -{ - return (ext4_es_status(es) & EXTENT_STATUS_REFERENCED) != 0; -} - -static inline ext4_fsblk_t ext4_es_pblock(struct extent_status *es) -{ - return es->es_pblk & ~ES_MASK; -} - -static inline void ext4_es_store_pblock(struct extent_status *es, - ext4_fsblk_t pb) -{ - ext4_fsblk_t block; - - block = (pb & ~ES_MASK) | (es->es_pblk & ES_MASK); - es->es_pblk = block; -} - -static inline void ext4_es_store_status(struct extent_status *es, - unsigned int status) -{ - es->es_pblk = (((ext4_fsblk_t)status << ES_SHIFT) & ES_MASK) | - (es->es_pblk & ~ES_MASK); -} - -static inline void ext4_es_store_pblock_status(struct extent_status *es, - ext4_fsblk_t pb, - unsigned int status) -{ - es->es_pblk = (((ext4_fsblk_t)status << ES_SHIFT) & ES_MASK) | - (pb & ~ES_MASK); -} - -extern int ext4_es_register_shrinker(struct ext4_sb_info *sbi); -extern void ext4_es_unregister_shrinker(struct ext4_sb_info *sbi); - -extern int ext4_seq_es_shrinker_info_show(struct seq_file *seq, void *v); - -#endif /* _EXT4_EXTENTS_STATUS_H */ diff --git a/src/linux/fs/ext4/file.c b/src/linux/fs/ext4/file.c deleted file mode 100644 index 2a822d3..0000000 --- a/src/linux/fs/ext4/file.c +++ /dev/null @@ -1,714 +0,0 @@ -/* - * linux/fs/ext4/file.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/file.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * ext4 fs regular file handling primitives - * - * 64-bit file support on 64-bit platforms by Jakub Jelinek - * (jj@sunsite.ms.mff.cuni.cz) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "ext4.h" -#include "ext4_jbd2.h" -#include "xattr.h" -#include "acl.h" - -/* - * Called when an inode is released. Note that this is different - * from ext4_file_open: open gets called at every open, but release - * gets called only when /all/ the files are closed. - */ -static int ext4_release_file(struct inode *inode, struct file *filp) -{ - if (ext4_test_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE)) { - ext4_alloc_da_blocks(inode); - ext4_clear_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE); - } - /* if we are the last writer on the inode, drop the block reservation */ - if ((filp->f_mode & FMODE_WRITE) && - (atomic_read(&inode->i_writecount) == 1) && - !EXT4_I(inode)->i_reserved_data_blocks) - { - down_write(&EXT4_I(inode)->i_data_sem); - ext4_discard_preallocations(inode); - up_write(&EXT4_I(inode)->i_data_sem); - } - if (is_dx(inode) && filp->private_data) - ext4_htree_free_dir_info(filp->private_data); - - return 0; -} - -static void ext4_unwritten_wait(struct inode *inode) -{ - wait_queue_head_t *wq = ext4_ioend_wq(inode); - - wait_event(*wq, (atomic_read(&EXT4_I(inode)->i_unwritten) == 0)); -} - -/* - * This tests whether the IO in question is block-aligned or not. - * Ext4 utilizes unwritten extents when hole-filling during direct IO, and they - * are converted to written only after the IO is complete. Until they are - * mapped, these blocks appear as holes, so dio_zero_block() will assume that - * it needs to zero out portions of the start and/or end block. If 2 AIO - * threads are at work on the same unwritten block, they must be synchronized - * or one thread will zero the other's data, causing corruption. - */ -static int -ext4_unaligned_aio(struct inode *inode, struct iov_iter *from, loff_t pos) -{ - struct super_block *sb = inode->i_sb; - int blockmask = sb->s_blocksize - 1; - - if (pos >= i_size_read(inode)) - return 0; - - if ((pos | iov_iter_alignment(from)) & blockmask) - return 1; - - return 0; -} - -static ssize_t -ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from) -{ - struct inode *inode = file_inode(iocb->ki_filp); - int o_direct = iocb->ki_flags & IOCB_DIRECT; - int unaligned_aio = 0; - int overwrite = 0; - ssize_t ret; - - inode_lock(inode); - ret = generic_write_checks(iocb, from); - if (ret <= 0) - goto out; - - /* - * Unaligned direct AIO must be serialized among each other as zeroing - * of partial blocks of two competing unaligned AIOs can result in data - * corruption. - */ - if (o_direct && ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) && - !is_sync_kiocb(iocb) && - ext4_unaligned_aio(inode, from, iocb->ki_pos)) { - unaligned_aio = 1; - ext4_unwritten_wait(inode); - } - - /* - * If we have encountered a bitmap-format file, the size limit - * is smaller than s_maxbytes, which is for extent-mapped files. - */ - if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - - if (iocb->ki_pos >= sbi->s_bitmap_maxbytes) { - ret = -EFBIG; - goto out; - } - iov_iter_truncate(from, sbi->s_bitmap_maxbytes - iocb->ki_pos); - } - - iocb->private = &overwrite; - if (o_direct) { - size_t length = iov_iter_count(from); - loff_t pos = iocb->ki_pos; - - /* check whether we do a DIO overwrite or not */ - if (ext4_should_dioread_nolock(inode) && !unaligned_aio && - pos + length <= i_size_read(inode)) { - struct ext4_map_blocks map; - unsigned int blkbits = inode->i_blkbits; - int err, len; - - map.m_lblk = pos >> blkbits; - map.m_len = EXT4_MAX_BLOCKS(length, pos, blkbits); - len = map.m_len; - - err = ext4_map_blocks(NULL, inode, &map, 0); - /* - * 'err==len' means that all of blocks has - * been preallocated no matter they are - * initialized or not. For excluding - * unwritten extents, we need to check - * m_flags. There are two conditions that - * indicate for initialized extents. 1) If we - * hit extent cache, EXT4_MAP_MAPPED flag is - * returned; 2) If we do a real lookup, - * non-flags are returned. So we should check - * these two conditions. - */ - if (err == len && (map.m_flags & EXT4_MAP_MAPPED)) - overwrite = 1; - } - } - - ret = __generic_file_write_iter(iocb, from); - inode_unlock(inode); - - if (ret > 0) - ret = generic_write_sync(iocb, ret); - - return ret; - -out: - inode_unlock(inode); - return ret; -} - -#ifdef CONFIG_FS_DAX -static int ext4_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - int result; - handle_t *handle = NULL; - struct inode *inode = file_inode(vma->vm_file); - struct super_block *sb = inode->i_sb; - bool write = vmf->flags & FAULT_FLAG_WRITE; - - if (write) { - sb_start_pagefault(sb); - file_update_time(vma->vm_file); - down_read(&EXT4_I(inode)->i_mmap_sem); - handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE, - EXT4_DATA_TRANS_BLOCKS(sb)); - } else - down_read(&EXT4_I(inode)->i_mmap_sem); - - if (IS_ERR(handle)) - result = VM_FAULT_SIGBUS; - else - result = dax_fault(vma, vmf, ext4_dax_get_block); - - if (write) { - if (!IS_ERR(handle)) - ext4_journal_stop(handle); - up_read(&EXT4_I(inode)->i_mmap_sem); - sb_end_pagefault(sb); - } else - up_read(&EXT4_I(inode)->i_mmap_sem); - - return result; -} - -static int ext4_dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr, - pmd_t *pmd, unsigned int flags) -{ - int result; - handle_t *handle = NULL; - struct inode *inode = file_inode(vma->vm_file); - struct super_block *sb = inode->i_sb; - bool write = flags & FAULT_FLAG_WRITE; - - if (write) { - sb_start_pagefault(sb); - file_update_time(vma->vm_file); - down_read(&EXT4_I(inode)->i_mmap_sem); - handle = ext4_journal_start_sb(sb, EXT4_HT_WRITE_PAGE, - ext4_chunk_trans_blocks(inode, - PMD_SIZE / PAGE_SIZE)); - } else - down_read(&EXT4_I(inode)->i_mmap_sem); - - if (IS_ERR(handle)) - result = VM_FAULT_SIGBUS; - else - result = dax_pmd_fault(vma, addr, pmd, flags, - ext4_dax_get_block); - - if (write) { - if (!IS_ERR(handle)) - ext4_journal_stop(handle); - up_read(&EXT4_I(inode)->i_mmap_sem); - sb_end_pagefault(sb); - } else - up_read(&EXT4_I(inode)->i_mmap_sem); - - return result; -} - -/* - * Handle write fault for VM_MIXEDMAP mappings. Similarly to ext4_dax_fault() - * handler we check for races agaist truncate. Note that since we cycle through - * i_mmap_sem, we are sure that also any hole punching that began before we - * were called is finished by now and so if it included part of the file we - * are working on, our pte will get unmapped and the check for pte_same() in - * wp_pfn_shared() fails. Thus fault gets retried and things work out as - * desired. - */ -static int ext4_dax_pfn_mkwrite(struct vm_area_struct *vma, - struct vm_fault *vmf) -{ - struct inode *inode = file_inode(vma->vm_file); - struct super_block *sb = inode->i_sb; - loff_t size; - int ret; - - sb_start_pagefault(sb); - file_update_time(vma->vm_file); - down_read(&EXT4_I(inode)->i_mmap_sem); - size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT; - if (vmf->pgoff >= size) - ret = VM_FAULT_SIGBUS; - else - ret = dax_pfn_mkwrite(vma, vmf); - up_read(&EXT4_I(inode)->i_mmap_sem); - sb_end_pagefault(sb); - - return ret; -} - -static const struct vm_operations_struct ext4_dax_vm_ops = { - .fault = ext4_dax_fault, - .pmd_fault = ext4_dax_pmd_fault, - .page_mkwrite = ext4_dax_fault, - .pfn_mkwrite = ext4_dax_pfn_mkwrite, -}; -#else -#define ext4_dax_vm_ops ext4_file_vm_ops -#endif - -static const struct vm_operations_struct ext4_file_vm_ops = { - .fault = ext4_filemap_fault, - .map_pages = filemap_map_pages, - .page_mkwrite = ext4_page_mkwrite, -}; - -static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct inode *inode = file->f_mapping->host; - - if (ext4_encrypted_inode(inode)) { - int err = fscrypt_get_encryption_info(inode); - if (err) - return 0; - if (!fscrypt_has_encryption_key(inode)) - return -ENOKEY; - } - file_accessed(file); - if (IS_DAX(file_inode(file))) { - vma->vm_ops = &ext4_dax_vm_ops; - vma->vm_flags |= VM_MIXEDMAP | VM_HUGEPAGE; - } else { - vma->vm_ops = &ext4_file_vm_ops; - } - return 0; -} - -static int ext4_file_open(struct inode * inode, struct file * filp) -{ - struct super_block *sb = inode->i_sb; - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - struct vfsmount *mnt = filp->f_path.mnt; - struct dentry *dir; - struct path path; - char buf[64], *cp; - int ret; - - if (unlikely(!(sbi->s_mount_flags & EXT4_MF_MNTDIR_SAMPLED) && - !(sb->s_flags & MS_RDONLY))) { - sbi->s_mount_flags |= EXT4_MF_MNTDIR_SAMPLED; - /* - * Sample where the filesystem has been mounted and - * store it in the superblock for sysadmin convenience - * when trying to sort through large numbers of block - * devices or filesystem images. - */ - memset(buf, 0, sizeof(buf)); - path.mnt = mnt; - path.dentry = mnt->mnt_root; - cp = d_path(&path, buf, sizeof(buf)); - if (!IS_ERR(cp)) { - handle_t *handle; - int err; - - handle = ext4_journal_start_sb(sb, EXT4_HT_MISC, 1); - if (IS_ERR(handle)) - return PTR_ERR(handle); - BUFFER_TRACE(sbi->s_sbh, "get_write_access"); - err = ext4_journal_get_write_access(handle, sbi->s_sbh); - if (err) { - ext4_journal_stop(handle); - return err; - } - strlcpy(sbi->s_es->s_last_mounted, cp, - sizeof(sbi->s_es->s_last_mounted)); - ext4_handle_dirty_super(handle, sb); - ext4_journal_stop(handle); - } - } - if (ext4_encrypted_inode(inode)) { - ret = fscrypt_get_encryption_info(inode); - if (ret) - return -EACCES; - if (!fscrypt_has_encryption_key(inode)) - return -ENOKEY; - } - - dir = dget_parent(file_dentry(filp)); - if (ext4_encrypted_inode(d_inode(dir)) && - !fscrypt_has_permitted_context(d_inode(dir), inode)) { - ext4_warning(inode->i_sb, - "Inconsistent encryption contexts: %lu/%lu", - (unsigned long) d_inode(dir)->i_ino, - (unsigned long) inode->i_ino); - dput(dir); - return -EPERM; - } - dput(dir); - /* - * Set up the jbd2_inode if we are opening the inode for - * writing and the journal is present - */ - if (filp->f_mode & FMODE_WRITE) { - ret = ext4_inode_attach_jinode(inode); - if (ret < 0) - return ret; - } - return dquot_file_open(inode, filp); -} - -/* - * Here we use ext4_map_blocks() to get a block mapping for a extent-based - * file rather than ext4_ext_walk_space() because we can introduce - * SEEK_DATA/SEEK_HOLE for block-mapped and extent-mapped file at the same - * function. When extent status tree has been fully implemented, it will - * track all extent status for a file and we can directly use it to - * retrieve the offset for SEEK_DATA/SEEK_HOLE. - */ - -/* - * When we retrieve the offset for SEEK_DATA/SEEK_HOLE, we would need to - * lookup page cache to check whether or not there has some data between - * [startoff, endoff] because, if this range contains an unwritten extent, - * we determine this extent as a data or a hole according to whether the - * page cache has data or not. - */ -static int ext4_find_unwritten_pgoff(struct inode *inode, - int whence, - ext4_lblk_t end_blk, - loff_t *offset) -{ - struct pagevec pvec; - unsigned int blkbits; - pgoff_t index; - pgoff_t end; - loff_t endoff; - loff_t startoff; - loff_t lastoff; - int found = 0; - - blkbits = inode->i_sb->s_blocksize_bits; - startoff = *offset; - lastoff = startoff; - endoff = (loff_t)end_blk << blkbits; - - index = startoff >> PAGE_SHIFT; - end = endoff >> PAGE_SHIFT; - - pagevec_init(&pvec, 0); - do { - int i, num; - unsigned long nr_pages; - - num = min_t(pgoff_t, end - index, PAGEVEC_SIZE); - nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index, - (pgoff_t)num); - if (nr_pages == 0) { - if (whence == SEEK_DATA) - break; - - BUG_ON(whence != SEEK_HOLE); - /* - * If this is the first time to go into the loop and - * offset is not beyond the end offset, it will be a - * hole at this offset - */ - if (lastoff == startoff || lastoff < endoff) - found = 1; - break; - } - - /* - * If this is the first time to go into the loop and - * offset is smaller than the first page offset, it will be a - * hole at this offset. - */ - if (lastoff == startoff && whence == SEEK_HOLE && - lastoff < page_offset(pvec.pages[0])) { - found = 1; - break; - } - - for (i = 0; i < nr_pages; i++) { - struct page *page = pvec.pages[i]; - struct buffer_head *bh, *head; - - /* - * If the current offset is not beyond the end of given - * range, it will be a hole. - */ - if (lastoff < endoff && whence == SEEK_HOLE && - page->index > end) { - found = 1; - *offset = lastoff; - goto out; - } - - lock_page(page); - - if (unlikely(page->mapping != inode->i_mapping)) { - unlock_page(page); - continue; - } - - if (!page_has_buffers(page)) { - unlock_page(page); - continue; - } - - if (page_has_buffers(page)) { - lastoff = page_offset(page); - bh = head = page_buffers(page); - do { - if (buffer_uptodate(bh) || - buffer_unwritten(bh)) { - if (whence == SEEK_DATA) - found = 1; - } else { - if (whence == SEEK_HOLE) - found = 1; - } - if (found) { - *offset = max_t(loff_t, - startoff, lastoff); - unlock_page(page); - goto out; - } - lastoff += bh->b_size; - bh = bh->b_this_page; - } while (bh != head); - } - - lastoff = page_offset(page) + PAGE_SIZE; - unlock_page(page); - } - - /* - * The no. of pages is less than our desired, that would be a - * hole in there. - */ - if (nr_pages < num && whence == SEEK_HOLE) { - found = 1; - *offset = lastoff; - break; - } - - index = pvec.pages[i - 1]->index + 1; - pagevec_release(&pvec); - } while (index <= end); - -out: - pagevec_release(&pvec); - return found; -} - -/* - * ext4_seek_data() retrieves the offset for SEEK_DATA. - */ -static loff_t ext4_seek_data(struct file *file, loff_t offset, loff_t maxsize) -{ - struct inode *inode = file->f_mapping->host; - struct extent_status es; - ext4_lblk_t start, last, end; - loff_t dataoff, isize; - int blkbits; - int ret; - - inode_lock(inode); - - isize = i_size_read(inode); - if (offset >= isize) { - inode_unlock(inode); - return -ENXIO; - } - - blkbits = inode->i_sb->s_blocksize_bits; - start = offset >> blkbits; - last = start; - end = isize >> blkbits; - dataoff = offset; - - do { - ret = ext4_get_next_extent(inode, last, end - last + 1, &es); - if (ret <= 0) { - /* No extent found -> no data */ - if (ret == 0) - ret = -ENXIO; - inode_unlock(inode); - return ret; - } - - last = es.es_lblk; - if (last != start) - dataoff = (loff_t)last << blkbits; - if (!ext4_es_is_unwritten(&es)) - break; - - /* - * If there is a unwritten extent at this offset, - * it will be as a data or a hole according to page - * cache that has data or not. - */ - if (ext4_find_unwritten_pgoff(inode, SEEK_DATA, - es.es_lblk + es.es_len, &dataoff)) - break; - last += es.es_len; - dataoff = (loff_t)last << blkbits; - cond_resched(); - } while (last <= end); - - inode_unlock(inode); - - if (dataoff > isize) - return -ENXIO; - - return vfs_setpos(file, dataoff, maxsize); -} - -/* - * ext4_seek_hole() retrieves the offset for SEEK_HOLE. - */ -static loff_t ext4_seek_hole(struct file *file, loff_t offset, loff_t maxsize) -{ - struct inode *inode = file->f_mapping->host; - struct extent_status es; - ext4_lblk_t start, last, end; - loff_t holeoff, isize; - int blkbits; - int ret; - - inode_lock(inode); - - isize = i_size_read(inode); - if (offset >= isize) { - inode_unlock(inode); - return -ENXIO; - } - - blkbits = inode->i_sb->s_blocksize_bits; - start = offset >> blkbits; - last = start; - end = isize >> blkbits; - holeoff = offset; - - do { - ret = ext4_get_next_extent(inode, last, end - last + 1, &es); - if (ret < 0) { - inode_unlock(inode); - return ret; - } - /* Found a hole? */ - if (ret == 0 || es.es_lblk > last) { - if (last != start) - holeoff = (loff_t)last << blkbits; - break; - } - /* - * If there is a unwritten extent at this offset, - * it will be as a data or a hole according to page - * cache that has data or not. - */ - if (ext4_es_is_unwritten(&es) && - ext4_find_unwritten_pgoff(inode, SEEK_HOLE, - last + es.es_len, &holeoff)) - break; - - last += es.es_len; - holeoff = (loff_t)last << blkbits; - cond_resched(); - } while (last <= end); - - inode_unlock(inode); - - if (holeoff > isize) - holeoff = isize; - - return vfs_setpos(file, holeoff, maxsize); -} - -/* - * ext4_llseek() handles both block-mapped and extent-mapped maxbytes values - * by calling generic_file_llseek_size() with the appropriate maxbytes - * value for each. - */ -loff_t ext4_llseek(struct file *file, loff_t offset, int whence) -{ - struct inode *inode = file->f_mapping->host; - loff_t maxbytes; - - if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) - maxbytes = EXT4_SB(inode->i_sb)->s_bitmap_maxbytes; - else - maxbytes = inode->i_sb->s_maxbytes; - - switch (whence) { - case SEEK_SET: - case SEEK_CUR: - case SEEK_END: - return generic_file_llseek_size(file, offset, whence, - maxbytes, i_size_read(inode)); - case SEEK_DATA: - return ext4_seek_data(file, offset, maxbytes); - case SEEK_HOLE: - return ext4_seek_hole(file, offset, maxbytes); - } - - return -EINVAL; -} - -const struct file_operations ext4_file_operations = { - .llseek = ext4_llseek, - .read_iter = generic_file_read_iter, - .write_iter = ext4_file_write_iter, - .unlocked_ioctl = ext4_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = ext4_compat_ioctl, -#endif - .mmap = ext4_file_mmap, - .open = ext4_file_open, - .release = ext4_release_file, - .fsync = ext4_sync_file, - .get_unmapped_area = thp_get_unmapped_area, - .splice_read = generic_file_splice_read, - .splice_write = iter_file_splice_write, - .fallocate = ext4_fallocate, -}; - -const struct inode_operations ext4_file_inode_operations = { - .setattr = ext4_setattr, - .getattr = ext4_getattr, - .listxattr = ext4_listxattr, - .get_acl = ext4_get_acl, - .set_acl = ext4_set_acl, - .fiemap = ext4_fiemap, -}; - diff --git a/src/linux/fs/ext4/fsync.c b/src/linux/fs/ext4/fsync.c deleted file mode 100644 index 88effb1..0000000 --- a/src/linux/fs/ext4/fsync.c +++ /dev/null @@ -1,160 +0,0 @@ -/* - * linux/fs/ext4/fsync.c - * - * Copyright (C) 1993 Stephen Tweedie (sct@redhat.com) - * from - * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * from - * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds - * - * ext4fs fsync primitive - * - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - * - * Removed unnecessary code duplication for little endian machines - * and excessive __inline__s. - * Andi Kleen, 1997 - * - * Major simplications and cleanup - we only need to do the metadata, because - * we can depend on generic_block_fdatasync() to sync the data blocks. - */ - -#include -#include -#include -#include -#include - -#include "ext4.h" -#include "ext4_jbd2.h" - -#include - -/* - * If we're not journaling and this is a just-created file, we have to - * sync our parent directory (if it was freshly created) since - * otherwise it will only be written by writeback, leaving a huge - * window during which a crash may lose the file. This may apply for - * the parent directory's parent as well, and so on recursively, if - * they are also freshly created. - */ -static int ext4_sync_parent(struct inode *inode) -{ - struct dentry *dentry = NULL; - struct inode *next; - int ret = 0; - - if (!ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) - return 0; - inode = igrab(inode); - while (ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) { - ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY); - dentry = d_find_any_alias(inode); - if (!dentry) - break; - next = igrab(d_inode(dentry->d_parent)); - dput(dentry); - if (!next) - break; - iput(inode); - inode = next; - /* - * The directory inode may have gone through rmdir by now. But - * the inode itself and its blocks are still allocated (we hold - * a reference to the inode so it didn't go through - * ext4_evict_inode()) and so we are safe to flush metadata - * blocks and the inode. - */ - ret = sync_mapping_buffers(inode->i_mapping); - if (ret) - break; - ret = sync_inode_metadata(inode, 1); - if (ret) - break; - } - iput(inode); - return ret; -} - -/* - * akpm: A new design for ext4_sync_file(). - * - * This is only called from sys_fsync(), sys_fdatasync() and sys_msync(). - * There cannot be a transaction open by this task. - * Another task could have dirtied this inode. Its data can be in any - * state in the journalling system. - * - * What we do is just kick off a commit and wait on it. This will snapshot the - * inode to disk. - */ - -int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync) -{ - struct inode *inode = file->f_mapping->host; - struct ext4_inode_info *ei = EXT4_I(inode); - journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; - int ret = 0, err; - tid_t commit_tid; - bool needs_barrier = false; - - J_ASSERT(ext4_journal_current_handle() == NULL); - - trace_ext4_sync_file_enter(file, datasync); - - if (inode->i_sb->s_flags & MS_RDONLY) { - /* Make sure that we read updated s_mount_flags value */ - smp_rmb(); - if (EXT4_SB(inode->i_sb)->s_mount_flags & EXT4_MF_FS_ABORTED) - ret = -EROFS; - goto out; - } - - if (!journal) { - ret = __generic_file_fsync(file, start, end, datasync); - if (!ret) - ret = ext4_sync_parent(inode); - if (test_opt(inode->i_sb, BARRIER)) - goto issue_flush; - goto out; - } - - ret = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (ret) - return ret; - /* - * data=writeback,ordered: - * The caller's filemap_fdatawrite()/wait will sync the data. - * Metadata is in the journal, we wait for proper transaction to - * commit here. - * - * data=journal: - * filemap_fdatawrite won't do anything (the buffers are clean). - * ext4_force_commit will write the file data into the journal and - * will wait on that. - * filemap_fdatawait() will encounter a ton of newly-dirtied pages - * (they were dirtied by commit). But that's OK - the blocks are - * safe in-journal, which is all fsync() needs to ensure. - */ - if (ext4_should_journal_data(inode)) { - ret = ext4_force_commit(inode->i_sb); - goto out; - } - - commit_tid = datasync ? ei->i_datasync_tid : ei->i_sync_tid; - if (journal->j_flags & JBD2_BARRIER && - !jbd2_trans_will_send_data_barrier(journal, commit_tid)) - needs_barrier = true; - ret = jbd2_complete_transaction(journal, commit_tid); - if (needs_barrier) { - issue_flush: - err = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); - if (!ret) - ret = err; - } -out: - trace_ext4_sync_file_exit(inode, ret); - return ret; -} diff --git a/src/linux/fs/ext4/hash.c b/src/linux/fs/ext4/hash.c deleted file mode 100644 index e026aa9..0000000 --- a/src/linux/fs/ext4/hash.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * linux/fs/ext4/hash.c - * - * Copyright (C) 2002 by Theodore Ts'o - * - * This file is released under the GPL v2. - * - * This file may be redistributed under the terms of the GNU Public - * License. - */ - -#include -#include -#include "ext4.h" - -#define DELTA 0x9E3779B9 - -static void TEA_transform(__u32 buf[4], __u32 const in[]) -{ - __u32 sum = 0; - __u32 b0 = buf[0], b1 = buf[1]; - __u32 a = in[0], b = in[1], c = in[2], d = in[3]; - int n = 16; - - do { - sum += DELTA; - b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); - b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); - } while (--n); - - buf[0] += b0; - buf[1] += b1; -} - - -/* The old legacy hash */ -static __u32 dx_hack_hash_unsigned(const char *name, int len) -{ - __u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; - const unsigned char *ucp = (const unsigned char *) name; - - while (len--) { - hash = hash1 + (hash0 ^ (((int) *ucp++) * 7152373)); - - if (hash & 0x80000000) - hash -= 0x7fffffff; - hash1 = hash0; - hash0 = hash; - } - return hash0 << 1; -} - -static __u32 dx_hack_hash_signed(const char *name, int len) -{ - __u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; - const signed char *scp = (const signed char *) name; - - while (len--) { - hash = hash1 + (hash0 ^ (((int) *scp++) * 7152373)); - - if (hash & 0x80000000) - hash -= 0x7fffffff; - hash1 = hash0; - hash0 = hash; - } - return hash0 << 1; -} - -static void str2hashbuf_signed(const char *msg, int len, __u32 *buf, int num) -{ - __u32 pad, val; - int i; - const signed char *scp = (const signed char *) msg; - - pad = (__u32)len | ((__u32)len << 8); - pad |= pad << 16; - - val = pad; - if (len > num*4) - len = num * 4; - for (i = 0; i < len; i++) { - if ((i % 4) == 0) - val = pad; - val = ((int) scp[i]) + (val << 8); - if ((i % 4) == 3) { - *buf++ = val; - val = pad; - num--; - } - } - if (--num >= 0) - *buf++ = val; - while (--num >= 0) - *buf++ = pad; -} - -static void str2hashbuf_unsigned(const char *msg, int len, __u32 *buf, int num) -{ - __u32 pad, val; - int i; - const unsigned char *ucp = (const unsigned char *) msg; - - pad = (__u32)len | ((__u32)len << 8); - pad |= pad << 16; - - val = pad; - if (len > num*4) - len = num * 4; - for (i = 0; i < len; i++) { - if ((i % 4) == 0) - val = pad; - val = ((int) ucp[i]) + (val << 8); - if ((i % 4) == 3) { - *buf++ = val; - val = pad; - num--; - } - } - if (--num >= 0) - *buf++ = val; - while (--num >= 0) - *buf++ = pad; -} - -/* - * Returns the hash of a filename. If len is 0 and name is NULL, then - * this function can be used to test whether or not a hash version is - * supported. - * - * The seed is an 4 longword (32 bits) "secret" which can be used to - * uniquify a hash. If the seed is all zero's, then some default seed - * may be used. - * - * A particular hash version specifies whether or not the seed is - * represented, and whether or not the returned hash is 32 bits or 64 - * bits. 32 bit hashes will return 0 for the minor hash. - */ -int ext4fs_dirhash(const char *name, int len, struct dx_hash_info *hinfo) -{ - __u32 hash; - __u32 minor_hash = 0; - const char *p; - int i; - __u32 in[8], buf[4]; - void (*str2hashbuf)(const char *, int, __u32 *, int) = - str2hashbuf_signed; - - /* Initialize the default seed for the hash checksum functions */ - buf[0] = 0x67452301; - buf[1] = 0xefcdab89; - buf[2] = 0x98badcfe; - buf[3] = 0x10325476; - - /* Check to see if the seed is all zero's */ - if (hinfo->seed) { - for (i = 0; i < 4; i++) { - if (hinfo->seed[i]) { - memcpy(buf, hinfo->seed, sizeof(buf)); - break; - } - } - } - - switch (hinfo->hash_version) { - case DX_HASH_LEGACY_UNSIGNED: - hash = dx_hack_hash_unsigned(name, len); - break; - case DX_HASH_LEGACY: - hash = dx_hack_hash_signed(name, len); - break; - case DX_HASH_HALF_MD4_UNSIGNED: - str2hashbuf = str2hashbuf_unsigned; - case DX_HASH_HALF_MD4: - p = name; - while (len > 0) { - (*str2hashbuf)(p, len, in, 8); - half_md4_transform(buf, in); - len -= 32; - p += 32; - } - minor_hash = buf[2]; - hash = buf[1]; - break; - case DX_HASH_TEA_UNSIGNED: - str2hashbuf = str2hashbuf_unsigned; - case DX_HASH_TEA: - p = name; - while (len > 0) { - (*str2hashbuf)(p, len, in, 4); - TEA_transform(buf, in); - len -= 16; - p += 16; - } - hash = buf[0]; - minor_hash = buf[1]; - break; - default: - hinfo->hash = 0; - return -1; - } - hash = hash & ~1; - if (hash == (EXT4_HTREE_EOF_32BIT << 1)) - hash = (EXT4_HTREE_EOF_32BIT - 1) << 1; - hinfo->hash = hash; - hinfo->minor_hash = minor_hash; - return 0; -} diff --git a/src/linux/fs/ext4/ialloc.c b/src/linux/fs/ext4/ialloc.c deleted file mode 100644 index 170421e..0000000 --- a/src/linux/fs/ext4/ialloc.c +++ /dev/null @@ -1,1391 +0,0 @@ -/* - * linux/fs/ext4/ialloc.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * BSD ufs-inspired inode and directory allocation by - * Stephen Tweedie (sct@redhat.com), 1993 - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ext4.h" -#include "ext4_jbd2.h" -#include "xattr.h" -#include "acl.h" - -#include - -/* - * ialloc.c contains the inodes allocation and deallocation routines - */ - -/* - * The free inodes are managed by bitmaps. A file system contains several - * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap - * block for inodes, N blocks for the inode table and data blocks. - * - * The file system contains group descriptors which are located after the - * super block. Each descriptor contains the number of the bitmap block and - * the free blocks count in the block. - */ - -/* - * To avoid calling the atomic setbit hundreds or thousands of times, we only - * need to use it within a single byte (to ensure we get endianness right). - * We can use memset for the rest of the bitmap as there are no other users. - */ -void ext4_mark_bitmap_end(int start_bit, int end_bit, char *bitmap) -{ - int i; - - if (start_bit >= end_bit) - return; - - ext4_debug("mark end bits +%d through +%d used\n", start_bit, end_bit); - for (i = start_bit; i < ((start_bit + 7) & ~7UL); i++) - ext4_set_bit(i, bitmap); - if (i < end_bit) - memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3); -} - -/* Initializes an uninitialized inode bitmap */ -static int ext4_init_inode_bitmap(struct super_block *sb, - struct buffer_head *bh, - ext4_group_t block_group, - struct ext4_group_desc *gdp) -{ - struct ext4_group_info *grp; - struct ext4_sb_info *sbi = EXT4_SB(sb); - J_ASSERT_BH(bh, buffer_locked(bh)); - - /* If checksum is bad mark all blocks and inodes use to prevent - * allocation, essentially implementing a per-group read-only flag. */ - if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) { - grp = ext4_get_group_info(sb, block_group); - if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) - percpu_counter_sub(&sbi->s_freeclusters_counter, - grp->bb_free); - set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); - if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { - int count; - count = ext4_free_inodes_count(sb, gdp); - percpu_counter_sub(&sbi->s_freeinodes_counter, - count); - } - set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); - return -EFSBADCRC; - } - - memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8); - ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8, - bh->b_data); - ext4_inode_bitmap_csum_set(sb, block_group, gdp, bh, - EXT4_INODES_PER_GROUP(sb) / 8); - ext4_group_desc_csum_set(sb, block_group, gdp); - - return 0; -} - -void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate) -{ - if (uptodate) { - set_buffer_uptodate(bh); - set_bitmap_uptodate(bh); - } - unlock_buffer(bh); - put_bh(bh); -} - -static int ext4_validate_inode_bitmap(struct super_block *sb, - struct ext4_group_desc *desc, - ext4_group_t block_group, - struct buffer_head *bh) -{ - ext4_fsblk_t blk; - struct ext4_group_info *grp = ext4_get_group_info(sb, block_group); - struct ext4_sb_info *sbi = EXT4_SB(sb); - - if (buffer_verified(bh)) - return 0; - if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) - return -EFSCORRUPTED; - - ext4_lock_group(sb, block_group); - blk = ext4_inode_bitmap(sb, desc); - if (!ext4_inode_bitmap_csum_verify(sb, block_group, desc, bh, - EXT4_INODES_PER_GROUP(sb) / 8)) { - ext4_unlock_group(sb, block_group); - ext4_error(sb, "Corrupt inode bitmap - block_group = %u, " - "inode_bitmap = %llu", block_group, blk); - grp = ext4_get_group_info(sb, block_group); - if (!EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { - int count; - count = ext4_free_inodes_count(sb, desc); - percpu_counter_sub(&sbi->s_freeinodes_counter, - count); - } - set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); - return -EFSBADCRC; - } - set_buffer_verified(bh); - ext4_unlock_group(sb, block_group); - return 0; -} - -/* - * Read the inode allocation bitmap for a given block_group, reading - * into the specified slot in the superblock's bitmap cache. - * - * Return buffer_head of bitmap on success or NULL. - */ -static struct buffer_head * -ext4_read_inode_bitmap(struct super_block *sb, ext4_group_t block_group) -{ - struct ext4_group_desc *desc; - struct buffer_head *bh = NULL; - ext4_fsblk_t bitmap_blk; - int err; - - desc = ext4_get_group_desc(sb, block_group, NULL); - if (!desc) - return ERR_PTR(-EFSCORRUPTED); - - bitmap_blk = ext4_inode_bitmap(sb, desc); - bh = sb_getblk(sb, bitmap_blk); - if (unlikely(!bh)) { - ext4_error(sb, "Cannot read inode bitmap - " - "block_group = %u, inode_bitmap = %llu", - block_group, bitmap_blk); - return ERR_PTR(-EIO); - } - if (bitmap_uptodate(bh)) - goto verify; - - lock_buffer(bh); - if (bitmap_uptodate(bh)) { - unlock_buffer(bh); - goto verify; - } - - ext4_lock_group(sb, block_group); - if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { - err = ext4_init_inode_bitmap(sb, bh, block_group, desc); - set_bitmap_uptodate(bh); - set_buffer_uptodate(bh); - set_buffer_verified(bh); - ext4_unlock_group(sb, block_group); - unlock_buffer(bh); - if (err) { - ext4_error(sb, "Failed to init inode bitmap for group " - "%u: %d", block_group, err); - goto out; - } - return bh; - } - ext4_unlock_group(sb, block_group); - - if (buffer_uptodate(bh)) { - /* - * if not uninit if bh is uptodate, - * bitmap is also uptodate - */ - set_bitmap_uptodate(bh); - unlock_buffer(bh); - goto verify; - } - /* - * submit the buffer_head for reading - */ - trace_ext4_load_inode_bitmap(sb, block_group); - bh->b_end_io = ext4_end_bitmap_read; - get_bh(bh); - submit_bh(REQ_OP_READ, REQ_META | REQ_PRIO, bh); - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) { - put_bh(bh); - ext4_error(sb, "Cannot read inode bitmap - " - "block_group = %u, inode_bitmap = %llu", - block_group, bitmap_blk); - return ERR_PTR(-EIO); - } - -verify: - err = ext4_validate_inode_bitmap(sb, desc, block_group, bh); - if (err) - goto out; - return bh; -out: - put_bh(bh); - return ERR_PTR(err); -} - -/* - * NOTE! When we get the inode, we're the only people - * that have access to it, and as such there are no - * race conditions we have to worry about. The inode - * is not on the hash-lists, and it cannot be reached - * through the filesystem because the directory entry - * has been deleted earlier. - * - * HOWEVER: we must make sure that we get no aliases, - * which means that we have to call "clear_inode()" - * _before_ we mark the inode not in use in the inode - * bitmaps. Otherwise a newly created file might use - * the same inode number (not actually the same pointer - * though), and then we'd have two inodes sharing the - * same inode number and space on the harddisk. - */ -void ext4_free_inode(handle_t *handle, struct inode *inode) -{ - struct super_block *sb = inode->i_sb; - int is_directory; - unsigned long ino; - struct buffer_head *bitmap_bh = NULL; - struct buffer_head *bh2; - ext4_group_t block_group; - unsigned long bit; - struct ext4_group_desc *gdp; - struct ext4_super_block *es; - struct ext4_sb_info *sbi; - int fatal = 0, err, count, cleared; - struct ext4_group_info *grp; - - if (!sb) { - printk(KERN_ERR "EXT4-fs: %s:%d: inode on " - "nonexistent device\n", __func__, __LINE__); - return; - } - if (atomic_read(&inode->i_count) > 1) { - ext4_msg(sb, KERN_ERR, "%s:%d: inode #%lu: count=%d", - __func__, __LINE__, inode->i_ino, - atomic_read(&inode->i_count)); - return; - } - if (inode->i_nlink) { - ext4_msg(sb, KERN_ERR, "%s:%d: inode #%lu: nlink=%d\n", - __func__, __LINE__, inode->i_ino, inode->i_nlink); - return; - } - sbi = EXT4_SB(sb); - - ino = inode->i_ino; - ext4_debug("freeing inode %lu\n", ino); - trace_ext4_free_inode(inode); - - /* - * Note: we must free any quota before locking the superblock, - * as writing the quota to disk may need the lock as well. - */ - dquot_initialize(inode); - ext4_xattr_delete_inode(handle, inode); - dquot_free_inode(inode); - dquot_drop(inode); - - is_directory = S_ISDIR(inode->i_mode); - - /* Do this BEFORE marking the inode not in use or returning an error */ - ext4_clear_inode(inode); - - es = EXT4_SB(sb)->s_es; - if (ino < EXT4_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { - ext4_error(sb, "reserved or nonexistent inode %lu", ino); - goto error_return; - } - block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb); - bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb); - bitmap_bh = ext4_read_inode_bitmap(sb, block_group); - /* Don't bother if the inode bitmap is corrupt. */ - grp = ext4_get_group_info(sb, block_group); - if (IS_ERR(bitmap_bh)) { - fatal = PTR_ERR(bitmap_bh); - bitmap_bh = NULL; - goto error_return; - } - if (unlikely(EXT4_MB_GRP_IBITMAP_CORRUPT(grp))) { - fatal = -EFSCORRUPTED; - goto error_return; - } - - BUFFER_TRACE(bitmap_bh, "get_write_access"); - fatal = ext4_journal_get_write_access(handle, bitmap_bh); - if (fatal) - goto error_return; - - fatal = -ESRCH; - gdp = ext4_get_group_desc(sb, block_group, &bh2); - if (gdp) { - BUFFER_TRACE(bh2, "get_write_access"); - fatal = ext4_journal_get_write_access(handle, bh2); - } - ext4_lock_group(sb, block_group); - cleared = ext4_test_and_clear_bit(bit, bitmap_bh->b_data); - if (fatal || !cleared) { - ext4_unlock_group(sb, block_group); - goto out; - } - - count = ext4_free_inodes_count(sb, gdp) + 1; - ext4_free_inodes_set(sb, gdp, count); - if (is_directory) { - count = ext4_used_dirs_count(sb, gdp) - 1; - ext4_used_dirs_set(sb, gdp, count); - percpu_counter_dec(&sbi->s_dirs_counter); - } - ext4_inode_bitmap_csum_set(sb, block_group, gdp, bitmap_bh, - EXT4_INODES_PER_GROUP(sb) / 8); - ext4_group_desc_csum_set(sb, block_group, gdp); - ext4_unlock_group(sb, block_group); - - percpu_counter_inc(&sbi->s_freeinodes_counter); - if (sbi->s_log_groups_per_flex) { - ext4_group_t f = ext4_flex_group(sbi, block_group); - - atomic_inc(&sbi->s_flex_groups[f].free_inodes); - if (is_directory) - atomic_dec(&sbi->s_flex_groups[f].used_dirs); - } - BUFFER_TRACE(bh2, "call ext4_handle_dirty_metadata"); - fatal = ext4_handle_dirty_metadata(handle, NULL, bh2); -out: - if (cleared) { - BUFFER_TRACE(bitmap_bh, "call ext4_handle_dirty_metadata"); - err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); - if (!fatal) - fatal = err; - } else { - ext4_error(sb, "bit already cleared for inode %lu", ino); - if (gdp && !EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { - int count; - count = ext4_free_inodes_count(sb, gdp); - percpu_counter_sub(&sbi->s_freeinodes_counter, - count); - } - set_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &grp->bb_state); - } - -error_return: - brelse(bitmap_bh); - ext4_std_error(sb, fatal); -} - -struct orlov_stats { - __u64 free_clusters; - __u32 free_inodes; - __u32 used_dirs; -}; - -/* - * Helper function for Orlov's allocator; returns critical information - * for a particular block group or flex_bg. If flex_size is 1, then g - * is a block group number; otherwise it is flex_bg number. - */ -static void get_orlov_stats(struct super_block *sb, ext4_group_t g, - int flex_size, struct orlov_stats *stats) -{ - struct ext4_group_desc *desc; - struct flex_groups *flex_group = EXT4_SB(sb)->s_flex_groups; - - if (flex_size > 1) { - stats->free_inodes = atomic_read(&flex_group[g].free_inodes); - stats->free_clusters = atomic64_read(&flex_group[g].free_clusters); - stats->used_dirs = atomic_read(&flex_group[g].used_dirs); - return; - } - - desc = ext4_get_group_desc(sb, g, NULL); - if (desc) { - stats->free_inodes = ext4_free_inodes_count(sb, desc); - stats->free_clusters = ext4_free_group_clusters(sb, desc); - stats->used_dirs = ext4_used_dirs_count(sb, desc); - } else { - stats->free_inodes = 0; - stats->free_clusters = 0; - stats->used_dirs = 0; - } -} - -/* - * Orlov's allocator for directories. - * - * We always try to spread first-level directories. - * - * If there are blockgroups with both free inodes and free blocks counts - * not worse than average we return one with smallest directory count. - * Otherwise we simply return a random group. - * - * For the rest rules look so: - * - * It's OK to put directory into a group unless - * it has too many directories already (max_dirs) or - * it has too few free inodes left (min_inodes) or - * it has too few free blocks left (min_blocks) or - * Parent's group is preferred, if it doesn't satisfy these - * conditions we search cyclically through the rest. If none - * of the groups look good we just look for a group with more - * free inodes than average (starting at parent's group). - */ - -static int find_group_orlov(struct super_block *sb, struct inode *parent, - ext4_group_t *group, umode_t mode, - const struct qstr *qstr) -{ - ext4_group_t parent_group = EXT4_I(parent)->i_block_group; - struct ext4_sb_info *sbi = EXT4_SB(sb); - ext4_group_t real_ngroups = ext4_get_groups_count(sb); - int inodes_per_group = EXT4_INODES_PER_GROUP(sb); - unsigned int freei, avefreei, grp_free; - ext4_fsblk_t freeb, avefreec; - unsigned int ndirs; - int max_dirs, min_inodes; - ext4_grpblk_t min_clusters; - ext4_group_t i, grp, g, ngroups; - struct ext4_group_desc *desc; - struct orlov_stats stats; - int flex_size = ext4_flex_bg_size(sbi); - struct dx_hash_info hinfo; - - ngroups = real_ngroups; - if (flex_size > 1) { - ngroups = (real_ngroups + flex_size - 1) >> - sbi->s_log_groups_per_flex; - parent_group >>= sbi->s_log_groups_per_flex; - } - - freei = percpu_counter_read_positive(&sbi->s_freeinodes_counter); - avefreei = freei / ngroups; - freeb = EXT4_C2B(sbi, - percpu_counter_read_positive(&sbi->s_freeclusters_counter)); - avefreec = freeb; - do_div(avefreec, ngroups); - ndirs = percpu_counter_read_positive(&sbi->s_dirs_counter); - - if (S_ISDIR(mode) && - ((parent == d_inode(sb->s_root)) || - (ext4_test_inode_flag(parent, EXT4_INODE_TOPDIR)))) { - int best_ndir = inodes_per_group; - int ret = -1; - - if (qstr) { - hinfo.hash_version = DX_HASH_HALF_MD4; - hinfo.seed = sbi->s_hash_seed; - ext4fs_dirhash(qstr->name, qstr->len, &hinfo); - grp = hinfo.hash; - } else - grp = prandom_u32(); - parent_group = (unsigned)grp % ngroups; - for (i = 0; i < ngroups; i++) { - g = (parent_group + i) % ngroups; - get_orlov_stats(sb, g, flex_size, &stats); - if (!stats.free_inodes) - continue; - if (stats.used_dirs >= best_ndir) - continue; - if (stats.free_inodes < avefreei) - continue; - if (stats.free_clusters < avefreec) - continue; - grp = g; - ret = 0; - best_ndir = stats.used_dirs; - } - if (ret) - goto fallback; - found_flex_bg: - if (flex_size == 1) { - *group = grp; - return 0; - } - - /* - * We pack inodes at the beginning of the flexgroup's - * inode tables. Block allocation decisions will do - * something similar, although regular files will - * start at 2nd block group of the flexgroup. See - * ext4_ext_find_goal() and ext4_find_near(). - */ - grp *= flex_size; - for (i = 0; i < flex_size; i++) { - if (grp+i >= real_ngroups) - break; - desc = ext4_get_group_desc(sb, grp+i, NULL); - if (desc && ext4_free_inodes_count(sb, desc)) { - *group = grp+i; - return 0; - } - } - goto fallback; - } - - max_dirs = ndirs / ngroups + inodes_per_group / 16; - min_inodes = avefreei - inodes_per_group*flex_size / 4; - if (min_inodes < 1) - min_inodes = 1; - min_clusters = avefreec - EXT4_CLUSTERS_PER_GROUP(sb)*flex_size / 4; - - /* - * Start looking in the flex group where we last allocated an - * inode for this parent directory - */ - if (EXT4_I(parent)->i_last_alloc_group != ~0) { - parent_group = EXT4_I(parent)->i_last_alloc_group; - if (flex_size > 1) - parent_group >>= sbi->s_log_groups_per_flex; - } - - for (i = 0; i < ngroups; i++) { - grp = (parent_group + i) % ngroups; - get_orlov_stats(sb, grp, flex_size, &stats); - if (stats.used_dirs >= max_dirs) - continue; - if (stats.free_inodes < min_inodes) - continue; - if (stats.free_clusters < min_clusters) - continue; - goto found_flex_bg; - } - -fallback: - ngroups = real_ngroups; - avefreei = freei / ngroups; -fallback_retry: - parent_group = EXT4_I(parent)->i_block_group; - for (i = 0; i < ngroups; i++) { - grp = (parent_group + i) % ngroups; - desc = ext4_get_group_desc(sb, grp, NULL); - if (desc) { - grp_free = ext4_free_inodes_count(sb, desc); - if (grp_free && grp_free >= avefreei) { - *group = grp; - return 0; - } - } - } - - if (avefreei) { - /* - * The free-inodes counter is approximate, and for really small - * filesystems the above test can fail to find any blockgroups - */ - avefreei = 0; - goto fallback_retry; - } - - return -1; -} - -static int find_group_other(struct super_block *sb, struct inode *parent, - ext4_group_t *group, umode_t mode) -{ - ext4_group_t parent_group = EXT4_I(parent)->i_block_group; - ext4_group_t i, last, ngroups = ext4_get_groups_count(sb); - struct ext4_group_desc *desc; - int flex_size = ext4_flex_bg_size(EXT4_SB(sb)); - - /* - * Try to place the inode is the same flex group as its - * parent. If we can't find space, use the Orlov algorithm to - * find another flex group, and store that information in the - * parent directory's inode information so that use that flex - * group for future allocations. - */ - if (flex_size > 1) { - int retry = 0; - - try_again: - parent_group &= ~(flex_size-1); - last = parent_group + flex_size; - if (last > ngroups) - last = ngroups; - for (i = parent_group; i < last; i++) { - desc = ext4_get_group_desc(sb, i, NULL); - if (desc && ext4_free_inodes_count(sb, desc)) { - *group = i; - return 0; - } - } - if (!retry && EXT4_I(parent)->i_last_alloc_group != ~0) { - retry = 1; - parent_group = EXT4_I(parent)->i_last_alloc_group; - goto try_again; - } - /* - * If this didn't work, use the Orlov search algorithm - * to find a new flex group; we pass in the mode to - * avoid the topdir algorithms. - */ - *group = parent_group + flex_size; - if (*group > ngroups) - *group = 0; - return find_group_orlov(sb, parent, group, mode, NULL); - } - - /* - * Try to place the inode in its parent directory - */ - *group = parent_group; - desc = ext4_get_group_desc(sb, *group, NULL); - if (desc && ext4_free_inodes_count(sb, desc) && - ext4_free_group_clusters(sb, desc)) - return 0; - - /* - * We're going to place this inode in a different blockgroup from its - * parent. We want to cause files in a common directory to all land in - * the same blockgroup. But we want files which are in a different - * directory which shares a blockgroup with our parent to land in a - * different blockgroup. - * - * So add our directory's i_ino into the starting point for the hash. - */ - *group = (*group + parent->i_ino) % ngroups; - - /* - * Use a quadratic hash to find a group with a free inode and some free - * blocks. - */ - for (i = 1; i < ngroups; i <<= 1) { - *group += i; - if (*group >= ngroups) - *group -= ngroups; - desc = ext4_get_group_desc(sb, *group, NULL); - if (desc && ext4_free_inodes_count(sb, desc) && - ext4_free_group_clusters(sb, desc)) - return 0; - } - - /* - * That failed: try linear search for a free inode, even if that group - * has no free blocks. - */ - *group = parent_group; - for (i = 0; i < ngroups; i++) { - if (++*group >= ngroups) - *group = 0; - desc = ext4_get_group_desc(sb, *group, NULL); - if (desc && ext4_free_inodes_count(sb, desc)) - return 0; - } - - return -1; -} - -/* - * In no journal mode, if an inode has recently been deleted, we want - * to avoid reusing it until we're reasonably sure the inode table - * block has been written back to disk. (Yes, these values are - * somewhat arbitrary...) - */ -#define RECENTCY_MIN 5 -#define RECENTCY_DIRTY 30 - -static int recently_deleted(struct super_block *sb, ext4_group_t group, int ino) -{ - struct ext4_group_desc *gdp; - struct ext4_inode *raw_inode; - struct buffer_head *bh; - unsigned long dtime, now; - int inodes_per_block = EXT4_SB(sb)->s_inodes_per_block; - int offset, ret = 0, recentcy = RECENTCY_MIN; - - gdp = ext4_get_group_desc(sb, group, NULL); - if (unlikely(!gdp)) - return 0; - - bh = sb_getblk(sb, ext4_inode_table(sb, gdp) + - (ino / inodes_per_block)); - if (unlikely(!bh) || !buffer_uptodate(bh)) - /* - * If the block is not in the buffer cache, then it - * must have been written out. - */ - goto out; - - offset = (ino % inodes_per_block) * EXT4_INODE_SIZE(sb); - raw_inode = (struct ext4_inode *) (bh->b_data + offset); - dtime = le32_to_cpu(raw_inode->i_dtime); - now = get_seconds(); - if (buffer_dirty(bh)) - recentcy += RECENTCY_DIRTY; - - if (dtime && (dtime < now) && (now < dtime + recentcy)) - ret = 1; -out: - brelse(bh); - return ret; -} - -/* - * There are two policies for allocating an inode. If the new inode is - * a directory, then a forward search is made for a block group with both - * free space and a low directory-to-inode ratio; if that fails, then of - * the groups with above-average free space, that group with the fewest - * directories already is chosen. - * - * For other inodes, search forward from the parent directory's block - * group to find a free inode. - */ -struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir, - umode_t mode, const struct qstr *qstr, - __u32 goal, uid_t *owner, int handle_type, - unsigned int line_no, int nblocks) -{ - struct super_block *sb; - struct buffer_head *inode_bitmap_bh = NULL; - struct buffer_head *group_desc_bh; - ext4_group_t ngroups, group = 0; - unsigned long ino = 0; - struct inode *inode; - struct ext4_group_desc *gdp = NULL; - struct ext4_inode_info *ei; - struct ext4_sb_info *sbi; - int ret2, err; - struct inode *ret; - ext4_group_t i; - ext4_group_t flex_group; - struct ext4_group_info *grp; - int encrypt = 0; - - /* Cannot create files in a deleted directory */ - if (!dir || !dir->i_nlink) - return ERR_PTR(-EPERM); - - if ((ext4_encrypted_inode(dir) || - DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb))) && - (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) { - err = fscrypt_get_encryption_info(dir); - if (err) - return ERR_PTR(err); - if (!fscrypt_has_encryption_key(dir)) - return ERR_PTR(-EPERM); - if (!handle) - nblocks += EXT4_DATA_TRANS_BLOCKS(dir->i_sb); - encrypt = 1; - } - - sb = dir->i_sb; - ngroups = ext4_get_groups_count(sb); - trace_ext4_request_inode(dir, mode); - inode = new_inode(sb); - if (!inode) - return ERR_PTR(-ENOMEM); - ei = EXT4_I(inode); - sbi = EXT4_SB(sb); - - /* - * Initialize owners and quota early so that we don't have to account - * for quota initialization worst case in standard inode creating - * transaction - */ - if (owner) { - inode->i_mode = mode; - i_uid_write(inode, owner[0]); - i_gid_write(inode, owner[1]); - } else if (test_opt(sb, GRPID)) { - inode->i_mode = mode; - inode->i_uid = current_fsuid(); - inode->i_gid = dir->i_gid; - } else - inode_init_owner(inode, dir, mode); - - if (ext4_has_feature_project(sb) && - ext4_test_inode_flag(dir, EXT4_INODE_PROJINHERIT)) - ei->i_projid = EXT4_I(dir)->i_projid; - else - ei->i_projid = make_kprojid(&init_user_ns, EXT4_DEF_PROJID); - - err = dquot_initialize(inode); - if (err) - goto out; - - if (!goal) - goal = sbi->s_inode_goal; - - if (goal && goal <= le32_to_cpu(sbi->s_es->s_inodes_count)) { - group = (goal - 1) / EXT4_INODES_PER_GROUP(sb); - ino = (goal - 1) % EXT4_INODES_PER_GROUP(sb); - ret2 = 0; - goto got_group; - } - - if (S_ISDIR(mode)) - ret2 = find_group_orlov(sb, dir, &group, mode, qstr); - else - ret2 = find_group_other(sb, dir, &group, mode); - -got_group: - EXT4_I(dir)->i_last_alloc_group = group; - err = -ENOSPC; - if (ret2 == -1) - goto out; - - /* - * Normally we will only go through one pass of this loop, - * unless we get unlucky and it turns out the group we selected - * had its last inode grabbed by someone else. - */ - for (i = 0; i < ngroups; i++, ino = 0) { - err = -EIO; - - gdp = ext4_get_group_desc(sb, group, &group_desc_bh); - if (!gdp) - goto out; - - /* - * Check free inodes count before loading bitmap. - */ - if (ext4_free_inodes_count(sb, gdp) == 0) { - if (++group == ngroups) - group = 0; - continue; - } - - grp = ext4_get_group_info(sb, group); - /* Skip groups with already-known suspicious inode tables */ - if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp)) { - if (++group == ngroups) - group = 0; - continue; - } - - brelse(inode_bitmap_bh); - inode_bitmap_bh = ext4_read_inode_bitmap(sb, group); - /* Skip groups with suspicious inode tables */ - if (EXT4_MB_GRP_IBITMAP_CORRUPT(grp) || - IS_ERR(inode_bitmap_bh)) { - inode_bitmap_bh = NULL; - if (++group == ngroups) - group = 0; - continue; - } - -repeat_in_this_group: - ino = ext4_find_next_zero_bit((unsigned long *) - inode_bitmap_bh->b_data, - EXT4_INODES_PER_GROUP(sb), ino); - if (ino >= EXT4_INODES_PER_GROUP(sb)) - goto next_group; - if (group == 0 && (ino+1) < EXT4_FIRST_INO(sb)) { - ext4_error(sb, "reserved inode found cleared - " - "inode=%lu", ino + 1); - continue; - } - if ((EXT4_SB(sb)->s_journal == NULL) && - recently_deleted(sb, group, ino)) { - ino++; - goto next_inode; - } - if (!handle) { - BUG_ON(nblocks <= 0); - handle = __ext4_journal_start_sb(dir->i_sb, line_no, - handle_type, nblocks, - 0); - if (IS_ERR(handle)) { - err = PTR_ERR(handle); - ext4_std_error(sb, err); - goto out; - } - } - BUFFER_TRACE(inode_bitmap_bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, inode_bitmap_bh); - if (err) { - ext4_std_error(sb, err); - goto out; - } - ext4_lock_group(sb, group); - ret2 = ext4_test_and_set_bit(ino, inode_bitmap_bh->b_data); - ext4_unlock_group(sb, group); - ino++; /* the inode bitmap is zero-based */ - if (!ret2) - goto got; /* we grabbed the inode! */ -next_inode: - if (ino < EXT4_INODES_PER_GROUP(sb)) - goto repeat_in_this_group; -next_group: - if (++group == ngroups) - group = 0; - } - err = -ENOSPC; - goto out; - -got: - BUFFER_TRACE(inode_bitmap_bh, "call ext4_handle_dirty_metadata"); - err = ext4_handle_dirty_metadata(handle, NULL, inode_bitmap_bh); - if (err) { - ext4_std_error(sb, err); - goto out; - } - - BUFFER_TRACE(group_desc_bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, group_desc_bh); - if (err) { - ext4_std_error(sb, err); - goto out; - } - - /* We may have to initialize the block bitmap if it isn't already */ - if (ext4_has_group_desc_csum(sb) && - gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { - struct buffer_head *block_bitmap_bh; - - block_bitmap_bh = ext4_read_block_bitmap(sb, group); - if (IS_ERR(block_bitmap_bh)) { - err = PTR_ERR(block_bitmap_bh); - goto out; - } - BUFFER_TRACE(block_bitmap_bh, "get block bitmap access"); - err = ext4_journal_get_write_access(handle, block_bitmap_bh); - if (err) { - brelse(block_bitmap_bh); - ext4_std_error(sb, err); - goto out; - } - - BUFFER_TRACE(block_bitmap_bh, "dirty block bitmap"); - err = ext4_handle_dirty_metadata(handle, NULL, block_bitmap_bh); - - /* recheck and clear flag under lock if we still need to */ - ext4_lock_group(sb, group); - if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { - gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); - ext4_free_group_clusters_set(sb, gdp, - ext4_free_clusters_after_init(sb, group, gdp)); - ext4_block_bitmap_csum_set(sb, group, gdp, - block_bitmap_bh); - ext4_group_desc_csum_set(sb, group, gdp); - } - ext4_unlock_group(sb, group); - brelse(block_bitmap_bh); - - if (err) { - ext4_std_error(sb, err); - goto out; - } - } - - /* Update the relevant bg descriptor fields */ - if (ext4_has_group_desc_csum(sb)) { - int free; - struct ext4_group_info *grp = ext4_get_group_info(sb, group); - - down_read(&grp->alloc_sem); /* protect vs itable lazyinit */ - ext4_lock_group(sb, group); /* while we modify the bg desc */ - free = EXT4_INODES_PER_GROUP(sb) - - ext4_itable_unused_count(sb, gdp); - if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) { - gdp->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT); - free = 0; - } - /* - * Check the relative inode number against the last used - * relative inode number in this group. if it is greater - * we need to update the bg_itable_unused count - */ - if (ino > free) - ext4_itable_unused_set(sb, gdp, - (EXT4_INODES_PER_GROUP(sb) - ino)); - up_read(&grp->alloc_sem); - } else { - ext4_lock_group(sb, group); - } - - ext4_free_inodes_set(sb, gdp, ext4_free_inodes_count(sb, gdp) - 1); - if (S_ISDIR(mode)) { - ext4_used_dirs_set(sb, gdp, ext4_used_dirs_count(sb, gdp) + 1); - if (sbi->s_log_groups_per_flex) { - ext4_group_t f = ext4_flex_group(sbi, group); - - atomic_inc(&sbi->s_flex_groups[f].used_dirs); - } - } - if (ext4_has_group_desc_csum(sb)) { - ext4_inode_bitmap_csum_set(sb, group, gdp, inode_bitmap_bh, - EXT4_INODES_PER_GROUP(sb) / 8); - ext4_group_desc_csum_set(sb, group, gdp); - } - ext4_unlock_group(sb, group); - - BUFFER_TRACE(group_desc_bh, "call ext4_handle_dirty_metadata"); - err = ext4_handle_dirty_metadata(handle, NULL, group_desc_bh); - if (err) { - ext4_std_error(sb, err); - goto out; - } - - percpu_counter_dec(&sbi->s_freeinodes_counter); - if (S_ISDIR(mode)) - percpu_counter_inc(&sbi->s_dirs_counter); - - if (sbi->s_log_groups_per_flex) { - flex_group = ext4_flex_group(sbi, group); - atomic_dec(&sbi->s_flex_groups[flex_group].free_inodes); - } - - inode->i_ino = ino + group * EXT4_INODES_PER_GROUP(sb); - /* This is the optimal IO size (for stat), not the fs block size */ - inode->i_blocks = 0; - inode->i_mtime = inode->i_atime = inode->i_ctime = ei->i_crtime = - ext4_current_time(inode); - - memset(ei->i_data, 0, sizeof(ei->i_data)); - ei->i_dir_start_lookup = 0; - ei->i_disksize = 0; - - /* Don't inherit extent flag from directory, amongst others. */ - ei->i_flags = - ext4_mask_flags(mode, EXT4_I(dir)->i_flags & EXT4_FL_INHERITED); - ei->i_file_acl = 0; - ei->i_dtime = 0; - ei->i_block_group = group; - ei->i_last_alloc_group = ~0; - - ext4_set_inode_flags(inode); - if (IS_DIRSYNC(inode)) - ext4_handle_sync(handle); - if (insert_inode_locked(inode) < 0) { - /* - * Likely a bitmap corruption causing inode to be allocated - * twice. - */ - err = -EIO; - ext4_error(sb, "failed to insert inode %lu: doubly allocated?", - inode->i_ino); - goto out; - } - spin_lock(&sbi->s_next_gen_lock); - inode->i_generation = sbi->s_next_generation++; - spin_unlock(&sbi->s_next_gen_lock); - - /* Precompute checksum seed for inode metadata */ - if (ext4_has_metadata_csum(sb)) { - __u32 csum; - __le32 inum = cpu_to_le32(inode->i_ino); - __le32 gen = cpu_to_le32(inode->i_generation); - csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&inum, - sizeof(inum)); - ei->i_csum_seed = ext4_chksum(sbi, csum, (__u8 *)&gen, - sizeof(gen)); - } - - ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */ - ext4_set_inode_state(inode, EXT4_STATE_NEW); - - ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize; - ei->i_inline_off = 0; - if (ext4_has_feature_inline_data(sb)) - ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); - ret = inode; - err = dquot_alloc_inode(inode); - if (err) - goto fail_drop; - - err = ext4_init_acl(handle, inode, dir); - if (err) - goto fail_free_drop; - - err = ext4_init_security(handle, inode, dir, qstr); - if (err) - goto fail_free_drop; - - if (ext4_has_feature_extents(sb)) { - /* set extent flag only for directory, file and normal symlink*/ - if (S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode)) { - ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS); - ext4_ext_tree_init(handle, inode); - } - } - - if (ext4_handle_valid(handle)) { - ei->i_sync_tid = handle->h_transaction->t_tid; - ei->i_datasync_tid = handle->h_transaction->t_tid; - } - - if (encrypt) { - /* give pointer to avoid set_context with journal ops. */ - err = fscrypt_inherit_context(dir, inode, &encrypt, true); - if (err) - goto fail_free_drop; - } - - err = ext4_mark_inode_dirty(handle, inode); - if (err) { - ext4_std_error(sb, err); - goto fail_free_drop; - } - - ext4_debug("allocating inode %lu\n", inode->i_ino); - trace_ext4_allocate_inode(inode, dir, mode); - brelse(inode_bitmap_bh); - return ret; - -fail_free_drop: - dquot_free_inode(inode); -fail_drop: - clear_nlink(inode); - unlock_new_inode(inode); -out: - dquot_drop(inode); - inode->i_flags |= S_NOQUOTA; - iput(inode); - brelse(inode_bitmap_bh); - return ERR_PTR(err); -} - -/* Verify that we are loading a valid orphan from disk */ -struct inode *ext4_orphan_get(struct super_block *sb, unsigned long ino) -{ - unsigned long max_ino = le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count); - ext4_group_t block_group; - int bit; - struct buffer_head *bitmap_bh = NULL; - struct inode *inode = NULL; - int err = -EFSCORRUPTED; - - if (ino < EXT4_FIRST_INO(sb) || ino > max_ino) - goto bad_orphan; - - block_group = (ino - 1) / EXT4_INODES_PER_GROUP(sb); - bit = (ino - 1) % EXT4_INODES_PER_GROUP(sb); - bitmap_bh = ext4_read_inode_bitmap(sb, block_group); - if (IS_ERR(bitmap_bh)) { - ext4_error(sb, "inode bitmap error %ld for orphan %lu", - ino, PTR_ERR(bitmap_bh)); - return (struct inode *) bitmap_bh; - } - - /* Having the inode bit set should be a 100% indicator that this - * is a valid orphan (no e2fsck run on fs). Orphans also include - * inodes that were being truncated, so we can't check i_nlink==0. - */ - if (!ext4_test_bit(bit, bitmap_bh->b_data)) - goto bad_orphan; - - inode = ext4_iget(sb, ino); - if (IS_ERR(inode)) { - err = PTR_ERR(inode); - ext4_error(sb, "couldn't read orphan inode %lu (err %d)", - ino, err); - return inode; - } - - /* - * If the orphans has i_nlinks > 0 then it should be able to - * be truncated, otherwise it won't be removed from the orphan - * list during processing and an infinite loop will result. - * Similarly, it must not be a bad inode. - */ - if ((inode->i_nlink && !ext4_can_truncate(inode)) || - is_bad_inode(inode)) - goto bad_orphan; - - if (NEXT_ORPHAN(inode) > max_ino) - goto bad_orphan; - brelse(bitmap_bh); - return inode; - -bad_orphan: - ext4_error(sb, "bad orphan inode %lu", ino); - if (bitmap_bh) - printk(KERN_ERR "ext4_test_bit(bit=%d, block=%llu) = %d\n", - bit, (unsigned long long)bitmap_bh->b_blocknr, - ext4_test_bit(bit, bitmap_bh->b_data)); - if (inode) { - printk(KERN_ERR "is_bad_inode(inode)=%d\n", - is_bad_inode(inode)); - printk(KERN_ERR "NEXT_ORPHAN(inode)=%u\n", - NEXT_ORPHAN(inode)); - printk(KERN_ERR "max_ino=%lu\n", max_ino); - printk(KERN_ERR "i_nlink=%u\n", inode->i_nlink); - /* Avoid freeing blocks if we got a bad deleted inode */ - if (inode->i_nlink == 0) - inode->i_blocks = 0; - iput(inode); - } - brelse(bitmap_bh); - return ERR_PTR(err); -} - -unsigned long ext4_count_free_inodes(struct super_block *sb) -{ - unsigned long desc_count; - struct ext4_group_desc *gdp; - ext4_group_t i, ngroups = ext4_get_groups_count(sb); -#ifdef EXT4FS_DEBUG - struct ext4_super_block *es; - unsigned long bitmap_count, x; - struct buffer_head *bitmap_bh = NULL; - - es = EXT4_SB(sb)->s_es; - desc_count = 0; - bitmap_count = 0; - gdp = NULL; - for (i = 0; i < ngroups; i++) { - gdp = ext4_get_group_desc(sb, i, NULL); - if (!gdp) - continue; - desc_count += ext4_free_inodes_count(sb, gdp); - brelse(bitmap_bh); - bitmap_bh = ext4_read_inode_bitmap(sb, i); - if (IS_ERR(bitmap_bh)) { - bitmap_bh = NULL; - continue; - } - - x = ext4_count_free(bitmap_bh->b_data, - EXT4_INODES_PER_GROUP(sb) / 8); - printk(KERN_DEBUG "group %lu: stored = %d, counted = %lu\n", - (unsigned long) i, ext4_free_inodes_count(sb, gdp), x); - bitmap_count += x; - } - brelse(bitmap_bh); - printk(KERN_DEBUG "ext4_count_free_inodes: " - "stored = %u, computed = %lu, %lu\n", - le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count); - return desc_count; -#else - desc_count = 0; - for (i = 0; i < ngroups; i++) { - gdp = ext4_get_group_desc(sb, i, NULL); - if (!gdp) - continue; - desc_count += ext4_free_inodes_count(sb, gdp); - cond_resched(); - } - return desc_count; -#endif -} - -/* Called at mount-time, super-block is locked */ -unsigned long ext4_count_dirs(struct super_block * sb) -{ - unsigned long count = 0; - ext4_group_t i, ngroups = ext4_get_groups_count(sb); - - for (i = 0; i < ngroups; i++) { - struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL); - if (!gdp) - continue; - count += ext4_used_dirs_count(sb, gdp); - } - return count; -} - -/* - * Zeroes not yet zeroed inode table - just write zeroes through the whole - * inode table. Must be called without any spinlock held. The only place - * where it is called from on active part of filesystem is ext4lazyinit - * thread, so we do not need any special locks, however we have to prevent - * inode allocation from the current group, so we take alloc_sem lock, to - * block ext4_new_inode() until we are finished. - */ -int ext4_init_inode_table(struct super_block *sb, ext4_group_t group, - int barrier) -{ - struct ext4_group_info *grp = ext4_get_group_info(sb, group); - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_group_desc *gdp = NULL; - struct buffer_head *group_desc_bh; - handle_t *handle; - ext4_fsblk_t blk; - int num, ret = 0, used_blks = 0; - - /* This should not happen, but just to be sure check this */ - if (sb->s_flags & MS_RDONLY) { - ret = 1; - goto out; - } - - gdp = ext4_get_group_desc(sb, group, &group_desc_bh); - if (!gdp) - goto out; - - /* - * We do not need to lock this, because we are the only one - * handling this flag. - */ - if (gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED)) - goto out; - - handle = ext4_journal_start_sb(sb, EXT4_HT_MISC, 1); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - goto out; - } - - down_write(&grp->alloc_sem); - /* - * If inode bitmap was already initialized there may be some - * used inodes so we need to skip blocks with used inodes in - * inode table. - */ - if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT))) - used_blks = DIV_ROUND_UP((EXT4_INODES_PER_GROUP(sb) - - ext4_itable_unused_count(sb, gdp)), - sbi->s_inodes_per_block); - - if ((used_blks < 0) || (used_blks > sbi->s_itb_per_group)) { - ext4_error(sb, "Something is wrong with group %u: " - "used itable blocks: %d; " - "itable unused count: %u", - group, used_blks, - ext4_itable_unused_count(sb, gdp)); - ret = 1; - goto err_out; - } - - blk = ext4_inode_table(sb, gdp) + used_blks; - num = sbi->s_itb_per_group - used_blks; - - BUFFER_TRACE(group_desc_bh, "get_write_access"); - ret = ext4_journal_get_write_access(handle, - group_desc_bh); - if (ret) - goto err_out; - - /* - * Skip zeroout if the inode table is full. But we set the ZEROED - * flag anyway, because obviously, when it is full it does not need - * further zeroing. - */ - if (unlikely(num == 0)) - goto skip_zeroout; - - ext4_debug("going to zero out inode table in group %d\n", - group); - ret = sb_issue_zeroout(sb, blk, num, GFP_NOFS); - if (ret < 0) - goto err_out; - if (barrier) - blkdev_issue_flush(sb->s_bdev, GFP_NOFS, NULL); - -skip_zeroout: - ext4_lock_group(sb, group); - gdp->bg_flags |= cpu_to_le16(EXT4_BG_INODE_ZEROED); - ext4_group_desc_csum_set(sb, group, gdp); - ext4_unlock_group(sb, group); - - BUFFER_TRACE(group_desc_bh, - "call ext4_handle_dirty_metadata"); - ret = ext4_handle_dirty_metadata(handle, NULL, - group_desc_bh); - -err_out: - up_write(&grp->alloc_sem); - ext4_journal_stop(handle); -out: - return ret; -} diff --git a/src/linux/fs/ext4/indirect.c b/src/linux/fs/ext4/indirect.c deleted file mode 100644 index bc15c2c..0000000 --- a/src/linux/fs/ext4/indirect.c +++ /dev/null @@ -1,1448 +0,0 @@ -/* - * linux/fs/ext4/indirect.c - * - * from - * - * linux/fs/ext4/inode.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/inode.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Goal-directed block allocation by Stephen Tweedie - * (sct@redhat.com), 1993, 1998 - */ - -#include "ext4_jbd2.h" -#include "truncate.h" -#include -#include - -#include - -typedef struct { - __le32 *p; - __le32 key; - struct buffer_head *bh; -} Indirect; - -static inline void add_chain(Indirect *p, struct buffer_head *bh, __le32 *v) -{ - p->key = *(p->p = v); - p->bh = bh; -} - -/** - * ext4_block_to_path - parse the block number into array of offsets - * @inode: inode in question (we are only interested in its superblock) - * @i_block: block number to be parsed - * @offsets: array to store the offsets in - * @boundary: set this non-zero if the referred-to block is likely to be - * followed (on disk) by an indirect block. - * - * To store the locations of file's data ext4 uses a data structure common - * for UNIX filesystems - tree of pointers anchored in the inode, with - * data blocks at leaves and indirect blocks in intermediate nodes. - * This function translates the block number into path in that tree - - * return value is the path length and @offsets[n] is the offset of - * pointer to (n+1)th node in the nth one. If @block is out of range - * (negative or too large) warning is printed and zero returned. - * - * Note: function doesn't find node addresses, so no IO is needed. All - * we need to know is the capacity of indirect blocks (taken from the - * inode->i_sb). - */ - -/* - * Portability note: the last comparison (check that we fit into triple - * indirect block) is spelled differently, because otherwise on an - * architecture with 32-bit longs and 8Kb pages we might get into trouble - * if our filesystem had 8Kb blocks. We might use long long, but that would - * kill us on x86. Oh, well, at least the sign propagation does not matter - - * i_block would have to be negative in the very beginning, so we would not - * get there at all. - */ - -static int ext4_block_to_path(struct inode *inode, - ext4_lblk_t i_block, - ext4_lblk_t offsets[4], int *boundary) -{ - int ptrs = EXT4_ADDR_PER_BLOCK(inode->i_sb); - int ptrs_bits = EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb); - const long direct_blocks = EXT4_NDIR_BLOCKS, - indirect_blocks = ptrs, - double_blocks = (1 << (ptrs_bits * 2)); - int n = 0; - int final = 0; - - if (i_block < direct_blocks) { - offsets[n++] = i_block; - final = direct_blocks; - } else if ((i_block -= direct_blocks) < indirect_blocks) { - offsets[n++] = EXT4_IND_BLOCK; - offsets[n++] = i_block; - final = ptrs; - } else if ((i_block -= indirect_blocks) < double_blocks) { - offsets[n++] = EXT4_DIND_BLOCK; - offsets[n++] = i_block >> ptrs_bits; - offsets[n++] = i_block & (ptrs - 1); - final = ptrs; - } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) { - offsets[n++] = EXT4_TIND_BLOCK; - offsets[n++] = i_block >> (ptrs_bits * 2); - offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1); - offsets[n++] = i_block & (ptrs - 1); - final = ptrs; - } else { - ext4_warning(inode->i_sb, "block %lu > max in inode %lu", - i_block + direct_blocks + - indirect_blocks + double_blocks, inode->i_ino); - } - if (boundary) - *boundary = final - 1 - (i_block & (ptrs - 1)); - return n; -} - -/** - * ext4_get_branch - read the chain of indirect blocks leading to data - * @inode: inode in question - * @depth: depth of the chain (1 - direct pointer, etc.) - * @offsets: offsets of pointers in inode/indirect blocks - * @chain: place to store the result - * @err: here we store the error value - * - * Function fills the array of triples and returns %NULL - * if everything went OK or the pointer to the last filled triple - * (incomplete one) otherwise. Upon the return chain[i].key contains - * the number of (i+1)-th block in the chain (as it is stored in memory, - * i.e. little-endian 32-bit), chain[i].p contains the address of that - * number (it points into struct inode for i==0 and into the bh->b_data - * for i>0) and chain[i].bh points to the buffer_head of i-th indirect - * block for i>0 and NULL for i==0. In other words, it holds the block - * numbers of the chain, addresses they were taken from (and where we can - * verify that chain did not change) and buffer_heads hosting these - * numbers. - * - * Function stops when it stumbles upon zero pointer (absent block) - * (pointer to last triple returned, *@err == 0) - * or when it gets an IO error reading an indirect block - * (ditto, *@err == -EIO) - * or when it reads all @depth-1 indirect blocks successfully and finds - * the whole chain, all way to the data (returns %NULL, *err == 0). - * - * Need to be called with - * down_read(&EXT4_I(inode)->i_data_sem) - */ -static Indirect *ext4_get_branch(struct inode *inode, int depth, - ext4_lblk_t *offsets, - Indirect chain[4], int *err) -{ - struct super_block *sb = inode->i_sb; - Indirect *p = chain; - struct buffer_head *bh; - int ret = -EIO; - - *err = 0; - /* i_data is not going away, no lock needed */ - add_chain(chain, NULL, EXT4_I(inode)->i_data + *offsets); - if (!p->key) - goto no_block; - while (--depth) { - bh = sb_getblk(sb, le32_to_cpu(p->key)); - if (unlikely(!bh)) { - ret = -ENOMEM; - goto failure; - } - - if (!bh_uptodate_or_lock(bh)) { - if (bh_submit_read(bh) < 0) { - put_bh(bh); - goto failure; - } - /* validate block references */ - if (ext4_check_indirect_blockref(inode, bh)) { - put_bh(bh); - goto failure; - } - } - - add_chain(++p, bh, (__le32 *)bh->b_data + *++offsets); - /* Reader: end */ - if (!p->key) - goto no_block; - } - return NULL; - -failure: - *err = ret; -no_block: - return p; -} - -/** - * ext4_find_near - find a place for allocation with sufficient locality - * @inode: owner - * @ind: descriptor of indirect block. - * - * This function returns the preferred place for block allocation. - * It is used when heuristic for sequential allocation fails. - * Rules are: - * + if there is a block to the left of our position - allocate near it. - * + if pointer will live in indirect block - allocate near that block. - * + if pointer will live in inode - allocate in the same - * cylinder group. - * - * In the latter case we colour the starting block by the callers PID to - * prevent it from clashing with concurrent allocations for a different inode - * in the same block group. The PID is used here so that functionally related - * files will be close-by on-disk. - * - * Caller must make sure that @ind is valid and will stay that way. - */ -static ext4_fsblk_t ext4_find_near(struct inode *inode, Indirect *ind) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - __le32 *start = ind->bh ? (__le32 *) ind->bh->b_data : ei->i_data; - __le32 *p; - - /* Try to find previous block */ - for (p = ind->p - 1; p >= start; p--) { - if (*p) - return le32_to_cpu(*p); - } - - /* No such thing, so let's try location of indirect block */ - if (ind->bh) - return ind->bh->b_blocknr; - - /* - * It is going to be referred to from the inode itself? OK, just put it - * into the same cylinder group then. - */ - return ext4_inode_to_goal_block(inode); -} - -/** - * ext4_find_goal - find a preferred place for allocation. - * @inode: owner - * @block: block we want - * @partial: pointer to the last triple within a chain - * - * Normally this function find the preferred place for block allocation, - * returns it. - * Because this is only used for non-extent files, we limit the block nr - * to 32 bits. - */ -static ext4_fsblk_t ext4_find_goal(struct inode *inode, ext4_lblk_t block, - Indirect *partial) -{ - ext4_fsblk_t goal; - - /* - * XXX need to get goal block from mballoc's data structures - */ - - goal = ext4_find_near(inode, partial); - goal = goal & EXT4_MAX_BLOCK_FILE_PHYS; - return goal; -} - -/** - * ext4_blks_to_allocate - Look up the block map and count the number - * of direct blocks need to be allocated for the given branch. - * - * @branch: chain of indirect blocks - * @k: number of blocks need for indirect blocks - * @blks: number of data blocks to be mapped. - * @blocks_to_boundary: the offset in the indirect block - * - * return the total number of blocks to be allocate, including the - * direct and indirect blocks. - */ -static int ext4_blks_to_allocate(Indirect *branch, int k, unsigned int blks, - int blocks_to_boundary) -{ - unsigned int count = 0; - - /* - * Simple case, [t,d]Indirect block(s) has not allocated yet - * then it's clear blocks on that path have not allocated - */ - if (k > 0) { - /* right now we don't handle cross boundary allocation */ - if (blks < blocks_to_boundary + 1) - count += blks; - else - count += blocks_to_boundary + 1; - return count; - } - - count++; - while (count < blks && count <= blocks_to_boundary && - le32_to_cpu(*(branch[0].p + count)) == 0) { - count++; - } - return count; -} - -/** - * ext4_alloc_branch - allocate and set up a chain of blocks. - * @handle: handle for this transaction - * @inode: owner - * @indirect_blks: number of allocated indirect blocks - * @blks: number of allocated direct blocks - * @goal: preferred place for allocation - * @offsets: offsets (in the blocks) to store the pointers to next. - * @branch: place to store the chain in. - * - * This function allocates blocks, zeroes out all but the last one, - * links them into chain and (if we are synchronous) writes them to disk. - * In other words, it prepares a branch that can be spliced onto the - * inode. It stores the information about that chain in the branch[], in - * the same format as ext4_get_branch() would do. We are calling it after - * we had read the existing part of chain and partial points to the last - * triple of that (one with zero ->key). Upon the exit we have the same - * picture as after the successful ext4_get_block(), except that in one - * place chain is disconnected - *branch->p is still zero (we did not - * set the last link), but branch->key contains the number that should - * be placed into *branch->p to fill that gap. - * - * If allocation fails we free all blocks we've allocated (and forget - * their buffer_heads) and return the error value the from failed - * ext4_alloc_block() (normally -ENOSPC). Otherwise we set the chain - * as described above and return 0. - */ -static int ext4_alloc_branch(handle_t *handle, - struct ext4_allocation_request *ar, - int indirect_blks, ext4_lblk_t *offsets, - Indirect *branch) -{ - struct buffer_head * bh; - ext4_fsblk_t b, new_blocks[4]; - __le32 *p; - int i, j, err, len = 1; - - for (i = 0; i <= indirect_blks; i++) { - if (i == indirect_blks) { - new_blocks[i] = ext4_mb_new_blocks(handle, ar, &err); - } else - ar->goal = new_blocks[i] = ext4_new_meta_blocks(handle, - ar->inode, ar->goal, - ar->flags & EXT4_MB_DELALLOC_RESERVED, - NULL, &err); - if (err) { - i--; - goto failed; - } - branch[i].key = cpu_to_le32(new_blocks[i]); - if (i == 0) - continue; - - bh = branch[i].bh = sb_getblk(ar->inode->i_sb, new_blocks[i-1]); - if (unlikely(!bh)) { - err = -ENOMEM; - goto failed; - } - lock_buffer(bh); - BUFFER_TRACE(bh, "call get_create_access"); - err = ext4_journal_get_create_access(handle, bh); - if (err) { - unlock_buffer(bh); - goto failed; - } - - memset(bh->b_data, 0, bh->b_size); - p = branch[i].p = (__le32 *) bh->b_data + offsets[i]; - b = new_blocks[i]; - - if (i == indirect_blks) - len = ar->len; - for (j = 0; j < len; j++) - *p++ = cpu_to_le32(b++); - - BUFFER_TRACE(bh, "marking uptodate"); - set_buffer_uptodate(bh); - unlock_buffer(bh); - - BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); - err = ext4_handle_dirty_metadata(handle, ar->inode, bh); - if (err) - goto failed; - } - return 0; -failed: - for (; i >= 0; i--) { - /* - * We want to ext4_forget() only freshly allocated indirect - * blocks. Buffer for new_blocks[i-1] is at branch[i].bh and - * buffer at branch[0].bh is indirect block / inode already - * existing before ext4_alloc_branch() was called. - */ - if (i > 0 && i != indirect_blks && branch[i].bh) - ext4_forget(handle, 1, ar->inode, branch[i].bh, - branch[i].bh->b_blocknr); - ext4_free_blocks(handle, ar->inode, NULL, new_blocks[i], - (i == indirect_blks) ? ar->len : 1, 0); - } - return err; -} - -/** - * ext4_splice_branch - splice the allocated branch onto inode. - * @handle: handle for this transaction - * @inode: owner - * @block: (logical) number of block we are adding - * @chain: chain of indirect blocks (with a missing link - see - * ext4_alloc_branch) - * @where: location of missing link - * @num: number of indirect blocks we are adding - * @blks: number of direct blocks we are adding - * - * This function fills the missing link and does all housekeeping needed in - * inode (->i_blocks, etc.). In case of success we end up with the full - * chain to new block and return 0. - */ -static int ext4_splice_branch(handle_t *handle, - struct ext4_allocation_request *ar, - Indirect *where, int num) -{ - int i; - int err = 0; - ext4_fsblk_t current_block; - - /* - * If we're splicing into a [td]indirect block (as opposed to the - * inode) then we need to get write access to the [td]indirect block - * before the splice. - */ - if (where->bh) { - BUFFER_TRACE(where->bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, where->bh); - if (err) - goto err_out; - } - /* That's it */ - - *where->p = where->key; - - /* - * Update the host buffer_head or inode to point to more just allocated - * direct blocks blocks - */ - if (num == 0 && ar->len > 1) { - current_block = le32_to_cpu(where->key) + 1; - for (i = 1; i < ar->len; i++) - *(where->p + i) = cpu_to_le32(current_block++); - } - - /* We are done with atomic stuff, now do the rest of housekeeping */ - /* had we spliced it onto indirect block? */ - if (where->bh) { - /* - * If we spliced it onto an indirect block, we haven't - * altered the inode. Note however that if it is being spliced - * onto an indirect block at the very end of the file (the - * file is growing) then we *will* alter the inode to reflect - * the new i_size. But that is not done here - it is done in - * generic_commit_write->__mark_inode_dirty->ext4_dirty_inode. - */ - jbd_debug(5, "splicing indirect only\n"); - BUFFER_TRACE(where->bh, "call ext4_handle_dirty_metadata"); - err = ext4_handle_dirty_metadata(handle, ar->inode, where->bh); - if (err) - goto err_out; - } else { - /* - * OK, we spliced it into the inode itself on a direct block. - */ - ext4_mark_inode_dirty(handle, ar->inode); - jbd_debug(5, "splicing direct\n"); - } - return err; - -err_out: - for (i = 1; i <= num; i++) { - /* - * branch[i].bh is newly allocated, so there is no - * need to revoke the block, which is why we don't - * need to set EXT4_FREE_BLOCKS_METADATA. - */ - ext4_free_blocks(handle, ar->inode, where[i].bh, 0, 1, - EXT4_FREE_BLOCKS_FORGET); - } - ext4_free_blocks(handle, ar->inode, NULL, le32_to_cpu(where[num].key), - ar->len, 0); - - return err; -} - -/* - * The ext4_ind_map_blocks() function handles non-extents inodes - * (i.e., using the traditional indirect/double-indirect i_blocks - * scheme) for ext4_map_blocks(). - * - * Allocation strategy is simple: if we have to allocate something, we will - * have to go the whole way to leaf. So let's do it before attaching anything - * to tree, set linkage between the newborn blocks, write them if sync is - * required, recheck the path, free and repeat if check fails, otherwise - * set the last missing link (that will protect us from any truncate-generated - * removals - all blocks on the path are immune now) and possibly force the - * write on the parent block. - * That has a nice additional property: no special recovery from the failed - * allocations is needed - we simply release blocks and do not touch anything - * reachable from inode. - * - * `handle' can be NULL if create == 0. - * - * return > 0, # of blocks mapped or allocated. - * return = 0, if plain lookup failed. - * return < 0, error case. - * - * The ext4_ind_get_blocks() function should be called with - * down_write(&EXT4_I(inode)->i_data_sem) if allocating filesystem - * blocks (i.e., flags has EXT4_GET_BLOCKS_CREATE set) or - * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system - * blocks. - */ -int ext4_ind_map_blocks(handle_t *handle, struct inode *inode, - struct ext4_map_blocks *map, - int flags) -{ - struct ext4_allocation_request ar; - int err = -EIO; - ext4_lblk_t offsets[4]; - Indirect chain[4]; - Indirect *partial; - int indirect_blks; - int blocks_to_boundary = 0; - int depth; - int count = 0; - ext4_fsblk_t first_block = 0; - - trace_ext4_ind_map_blocks_enter(inode, map->m_lblk, map->m_len, flags); - J_ASSERT(!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))); - J_ASSERT(handle != NULL || (flags & EXT4_GET_BLOCKS_CREATE) == 0); - depth = ext4_block_to_path(inode, map->m_lblk, offsets, - &blocks_to_boundary); - - if (depth == 0) - goto out; - - partial = ext4_get_branch(inode, depth, offsets, chain, &err); - - /* Simplest case - block found, no allocation needed */ - if (!partial) { - first_block = le32_to_cpu(chain[depth - 1].key); - count++; - /*map more blocks*/ - while (count < map->m_len && count <= blocks_to_boundary) { - ext4_fsblk_t blk; - - blk = le32_to_cpu(*(chain[depth-1].p + count)); - - if (blk == first_block + count) - count++; - else - break; - } - goto got_it; - } - - /* Next simple case - plain lookup failed */ - if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) { - unsigned epb = inode->i_sb->s_blocksize / sizeof(u32); - int i; - - /* Count number blocks in a subtree under 'partial' */ - count = 1; - for (i = 0; partial + i != chain + depth - 1; i++) - count *= epb; - /* Fill in size of a hole we found */ - map->m_pblk = 0; - map->m_len = min_t(unsigned int, map->m_len, count); - goto cleanup; - } - - /* Failed read of indirect block */ - if (err == -EIO) - goto cleanup; - - /* - * Okay, we need to do block allocation. - */ - if (ext4_has_feature_bigalloc(inode->i_sb)) { - EXT4_ERROR_INODE(inode, "Can't allocate blocks for " - "non-extent mapped inodes with bigalloc"); - return -EFSCORRUPTED; - } - - /* Set up for the direct block allocation */ - memset(&ar, 0, sizeof(ar)); - ar.inode = inode; - ar.logical = map->m_lblk; - if (S_ISREG(inode->i_mode)) - ar.flags = EXT4_MB_HINT_DATA; - if (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) - ar.flags |= EXT4_MB_DELALLOC_RESERVED; - if (flags & EXT4_GET_BLOCKS_METADATA_NOFAIL) - ar.flags |= EXT4_MB_USE_RESERVED; - - ar.goal = ext4_find_goal(inode, map->m_lblk, partial); - - /* the number of blocks need to allocate for [d,t]indirect blocks */ - indirect_blks = (chain + depth) - partial - 1; - - /* - * Next look up the indirect map to count the totoal number of - * direct blocks to allocate for this branch. - */ - ar.len = ext4_blks_to_allocate(partial, indirect_blks, - map->m_len, blocks_to_boundary); - - /* - * Block out ext4_truncate while we alter the tree - */ - err = ext4_alloc_branch(handle, &ar, indirect_blks, - offsets + (partial - chain), partial); - - /* - * The ext4_splice_branch call will free and forget any buffers - * on the new chain if there is a failure, but that risks using - * up transaction credits, especially for bitmaps where the - * credits cannot be returned. Can we handle this somehow? We - * may need to return -EAGAIN upwards in the worst case. --sct - */ - if (!err) - err = ext4_splice_branch(handle, &ar, partial, indirect_blks); - if (err) - goto cleanup; - - map->m_flags |= EXT4_MAP_NEW; - - ext4_update_inode_fsync_trans(handle, inode, 1); - count = ar.len; -got_it: - map->m_flags |= EXT4_MAP_MAPPED; - map->m_pblk = le32_to_cpu(chain[depth-1].key); - map->m_len = count; - if (count > blocks_to_boundary) - map->m_flags |= EXT4_MAP_BOUNDARY; - err = count; - /* Clean up and exit */ - partial = chain + depth - 1; /* the whole chain */ -cleanup: - while (partial > chain) { - BUFFER_TRACE(partial->bh, "call brelse"); - brelse(partial->bh); - partial--; - } -out: - trace_ext4_ind_map_blocks_exit(inode, flags, map, err); - return err; -} - -/* - * Calculate the number of metadata blocks need to reserve - * to allocate a new block at @lblocks for non extent file based file - */ -int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - sector_t dind_mask = ~((sector_t)EXT4_ADDR_PER_BLOCK(inode->i_sb) - 1); - int blk_bits; - - if (lblock < EXT4_NDIR_BLOCKS) - return 0; - - lblock -= EXT4_NDIR_BLOCKS; - - if (ei->i_da_metadata_calc_len && - (lblock & dind_mask) == ei->i_da_metadata_calc_last_lblock) { - ei->i_da_metadata_calc_len++; - return 0; - } - ei->i_da_metadata_calc_last_lblock = lblock & dind_mask; - ei->i_da_metadata_calc_len = 1; - blk_bits = order_base_2(lblock); - return (blk_bits / EXT4_ADDR_PER_BLOCK_BITS(inode->i_sb)) + 1; -} - -/* - * Calculate number of indirect blocks touched by mapping @nrblocks logically - * contiguous blocks - */ -int ext4_ind_trans_blocks(struct inode *inode, int nrblocks) -{ - /* - * With N contiguous data blocks, we need at most - * N/EXT4_ADDR_PER_BLOCK(inode->i_sb) + 1 indirect blocks, - * 2 dindirect blocks, and 1 tindirect block - */ - return DIV_ROUND_UP(nrblocks, EXT4_ADDR_PER_BLOCK(inode->i_sb)) + 4; -} - -/* - * Truncate transactions can be complex and absolutely huge. So we need to - * be able to restart the transaction at a conventient checkpoint to make - * sure we don't overflow the journal. - * - * Try to extend this transaction for the purposes of truncation. If - * extend fails, we need to propagate the failure up and restart the - * transaction in the top-level truncate loop. --sct - * - * Returns 0 if we managed to create more room. If we can't create more - * room, and the transaction must be restarted we return 1. - */ -static int try_to_extend_transaction(handle_t *handle, struct inode *inode) -{ - if (!ext4_handle_valid(handle)) - return 0; - if (ext4_handle_has_enough_credits(handle, EXT4_RESERVE_TRANS_BLOCKS+1)) - return 0; - if (!ext4_journal_extend(handle, ext4_blocks_for_truncate(inode))) - return 0; - return 1; -} - -/* - * Probably it should be a library function... search for first non-zero word - * or memcmp with zero_page, whatever is better for particular architecture. - * Linus? - */ -static inline int all_zeroes(__le32 *p, __le32 *q) -{ - while (p < q) - if (*p++) - return 0; - return 1; -} - -/** - * ext4_find_shared - find the indirect blocks for partial truncation. - * @inode: inode in question - * @depth: depth of the affected branch - * @offsets: offsets of pointers in that branch (see ext4_block_to_path) - * @chain: place to store the pointers to partial indirect blocks - * @top: place to the (detached) top of branch - * - * This is a helper function used by ext4_truncate(). - * - * When we do truncate() we may have to clean the ends of several - * indirect blocks but leave the blocks themselves alive. Block is - * partially truncated if some data below the new i_size is referred - * from it (and it is on the path to the first completely truncated - * data block, indeed). We have to free the top of that path along - * with everything to the right of the path. Since no allocation - * past the truncation point is possible until ext4_truncate() - * finishes, we may safely do the latter, but top of branch may - * require special attention - pageout below the truncation point - * might try to populate it. - * - * We atomically detach the top of branch from the tree, store the - * block number of its root in *@top, pointers to buffer_heads of - * partially truncated blocks - in @chain[].bh and pointers to - * their last elements that should not be removed - in - * @chain[].p. Return value is the pointer to last filled element - * of @chain. - * - * The work left to caller to do the actual freeing of subtrees: - * a) free the subtree starting from *@top - * b) free the subtrees whose roots are stored in - * (@chain[i].p+1 .. end of @chain[i].bh->b_data) - * c) free the subtrees growing from the inode past the @chain[0]. - * (no partially truncated stuff there). */ - -static Indirect *ext4_find_shared(struct inode *inode, int depth, - ext4_lblk_t offsets[4], Indirect chain[4], - __le32 *top) -{ - Indirect *partial, *p; - int k, err; - - *top = 0; - /* Make k index the deepest non-null offset + 1 */ - for (k = depth; k > 1 && !offsets[k-1]; k--) - ; - partial = ext4_get_branch(inode, k, offsets, chain, &err); - /* Writer: pointers */ - if (!partial) - partial = chain + k-1; - /* - * If the branch acquired continuation since we've looked at it - - * fine, it should all survive and (new) top doesn't belong to us. - */ - if (!partial->key && *partial->p) - /* Writer: end */ - goto no_top; - for (p = partial; (p > chain) && all_zeroes((__le32 *) p->bh->b_data, p->p); p--) - ; - /* - * OK, we've found the last block that must survive. The rest of our - * branch should be detached before unlocking. However, if that rest - * of branch is all ours and does not grow immediately from the inode - * it's easier to cheat and just decrement partial->p. - */ - if (p == chain + k - 1 && p > chain) { - p->p--; - } else { - *top = *p->p; - /* Nope, don't do this in ext4. Must leave the tree intact */ -#if 0 - *p->p = 0; -#endif - } - /* Writer: end */ - - while (partial > p) { - brelse(partial->bh); - partial--; - } -no_top: - return partial; -} - -/* - * Zero a number of block pointers in either an inode or an indirect block. - * If we restart the transaction we must again get write access to the - * indirect block for further modification. - * - * We release `count' blocks on disk, but (last - first) may be greater - * than `count' because there can be holes in there. - * - * Return 0 on success, 1 on invalid block range - * and < 0 on fatal error. - */ -static int ext4_clear_blocks(handle_t *handle, struct inode *inode, - struct buffer_head *bh, - ext4_fsblk_t block_to_free, - unsigned long count, __le32 *first, - __le32 *last) -{ - __le32 *p; - int flags = EXT4_FREE_BLOCKS_VALIDATED; - int err; - - if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) - flags |= EXT4_FREE_BLOCKS_FORGET | EXT4_FREE_BLOCKS_METADATA; - else if (ext4_should_journal_data(inode)) - flags |= EXT4_FREE_BLOCKS_FORGET; - - if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), block_to_free, - count)) { - EXT4_ERROR_INODE(inode, "attempt to clear invalid " - "blocks %llu len %lu", - (unsigned long long) block_to_free, count); - return 1; - } - - if (try_to_extend_transaction(handle, inode)) { - if (bh) { - BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); - err = ext4_handle_dirty_metadata(handle, inode, bh); - if (unlikely(err)) - goto out_err; - } - err = ext4_mark_inode_dirty(handle, inode); - if (unlikely(err)) - goto out_err; - err = ext4_truncate_restart_trans(handle, inode, - ext4_blocks_for_truncate(inode)); - if (unlikely(err)) - goto out_err; - if (bh) { - BUFFER_TRACE(bh, "retaking write access"); - err = ext4_journal_get_write_access(handle, bh); - if (unlikely(err)) - goto out_err; - } - } - - for (p = first; p < last; p++) - *p = 0; - - ext4_free_blocks(handle, inode, NULL, block_to_free, count, flags); - return 0; -out_err: - ext4_std_error(inode->i_sb, err); - return err; -} - -/** - * ext4_free_data - free a list of data blocks - * @handle: handle for this transaction - * @inode: inode we are dealing with - * @this_bh: indirect buffer_head which contains *@first and *@last - * @first: array of block numbers - * @last: points immediately past the end of array - * - * We are freeing all blocks referred from that array (numbers are stored as - * little-endian 32-bit) and updating @inode->i_blocks appropriately. - * - * We accumulate contiguous runs of blocks to free. Conveniently, if these - * blocks are contiguous then releasing them at one time will only affect one - * or two bitmap blocks (+ group descriptor(s) and superblock) and we won't - * actually use a lot of journal space. - * - * @this_bh will be %NULL if @first and @last point into the inode's direct - * block pointers. - */ -static void ext4_free_data(handle_t *handle, struct inode *inode, - struct buffer_head *this_bh, - __le32 *first, __le32 *last) -{ - ext4_fsblk_t block_to_free = 0; /* Starting block # of a run */ - unsigned long count = 0; /* Number of blocks in the run */ - __le32 *block_to_free_p = NULL; /* Pointer into inode/ind - corresponding to - block_to_free */ - ext4_fsblk_t nr; /* Current block # */ - __le32 *p; /* Pointer into inode/ind - for current block */ - int err = 0; - - if (this_bh) { /* For indirect block */ - BUFFER_TRACE(this_bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, this_bh); - /* Important: if we can't update the indirect pointers - * to the blocks, we can't free them. */ - if (err) - return; - } - - for (p = first; p < last; p++) { - nr = le32_to_cpu(*p); - if (nr) { - /* accumulate blocks to free if they're contiguous */ - if (count == 0) { - block_to_free = nr; - block_to_free_p = p; - count = 1; - } else if (nr == block_to_free + count) { - count++; - } else { - err = ext4_clear_blocks(handle, inode, this_bh, - block_to_free, count, - block_to_free_p, p); - if (err) - break; - block_to_free = nr; - block_to_free_p = p; - count = 1; - } - } - } - - if (!err && count > 0) - err = ext4_clear_blocks(handle, inode, this_bh, block_to_free, - count, block_to_free_p, p); - if (err < 0) - /* fatal error */ - return; - - if (this_bh) { - BUFFER_TRACE(this_bh, "call ext4_handle_dirty_metadata"); - - /* - * The buffer head should have an attached journal head at this - * point. However, if the data is corrupted and an indirect - * block pointed to itself, it would have been detached when - * the block was cleared. Check for this instead of OOPSing. - */ - if ((EXT4_JOURNAL(inode) == NULL) || bh2jh(this_bh)) - ext4_handle_dirty_metadata(handle, inode, this_bh); - else - EXT4_ERROR_INODE(inode, - "circular indirect block detected at " - "block %llu", - (unsigned long long) this_bh->b_blocknr); - } -} - -/** - * ext4_free_branches - free an array of branches - * @handle: JBD handle for this transaction - * @inode: inode we are dealing with - * @parent_bh: the buffer_head which contains *@first and *@last - * @first: array of block numbers - * @last: pointer immediately past the end of array - * @depth: depth of the branches to free - * - * We are freeing all blocks referred from these branches (numbers are - * stored as little-endian 32-bit) and updating @inode->i_blocks - * appropriately. - */ -static void ext4_free_branches(handle_t *handle, struct inode *inode, - struct buffer_head *parent_bh, - __le32 *first, __le32 *last, int depth) -{ - ext4_fsblk_t nr; - __le32 *p; - - if (ext4_handle_is_aborted(handle)) - return; - - if (depth--) { - struct buffer_head *bh; - int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb); - p = last; - while (--p >= first) { - nr = le32_to_cpu(*p); - if (!nr) - continue; /* A hole */ - - if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), - nr, 1)) { - EXT4_ERROR_INODE(inode, - "invalid indirect mapped " - "block %lu (level %d)", - (unsigned long) nr, depth); - break; - } - - /* Go read the buffer for the next level down */ - bh = sb_bread(inode->i_sb, nr); - - /* - * A read failure? Report error and clear slot - * (should be rare). - */ - if (!bh) { - EXT4_ERROR_INODE_BLOCK(inode, nr, - "Read failure"); - continue; - } - - /* This zaps the entire block. Bottom up. */ - BUFFER_TRACE(bh, "free child branches"); - ext4_free_branches(handle, inode, bh, - (__le32 *) bh->b_data, - (__le32 *) bh->b_data + addr_per_block, - depth); - brelse(bh); - - /* - * Everything below this this pointer has been - * released. Now let this top-of-subtree go. - * - * We want the freeing of this indirect block to be - * atomic in the journal with the updating of the - * bitmap block which owns it. So make some room in - * the journal. - * - * We zero the parent pointer *after* freeing its - * pointee in the bitmaps, so if extend_transaction() - * for some reason fails to put the bitmap changes and - * the release into the same transaction, recovery - * will merely complain about releasing a free block, - * rather than leaking blocks. - */ - if (ext4_handle_is_aborted(handle)) - return; - if (try_to_extend_transaction(handle, inode)) { - ext4_mark_inode_dirty(handle, inode); - ext4_truncate_restart_trans(handle, inode, - ext4_blocks_for_truncate(inode)); - } - - /* - * The forget flag here is critical because if - * we are journaling (and not doing data - * journaling), we have to make sure a revoke - * record is written to prevent the journal - * replay from overwriting the (former) - * indirect block if it gets reallocated as a - * data block. This must happen in the same - * transaction where the data blocks are - * actually freed. - */ - ext4_free_blocks(handle, inode, NULL, nr, 1, - EXT4_FREE_BLOCKS_METADATA| - EXT4_FREE_BLOCKS_FORGET); - - if (parent_bh) { - /* - * The block which we have just freed is - * pointed to by an indirect block: journal it - */ - BUFFER_TRACE(parent_bh, "get_write_access"); - if (!ext4_journal_get_write_access(handle, - parent_bh)){ - *p = 0; - BUFFER_TRACE(parent_bh, - "call ext4_handle_dirty_metadata"); - ext4_handle_dirty_metadata(handle, - inode, - parent_bh); - } - } - } - } else { - /* We have reached the bottom of the tree. */ - BUFFER_TRACE(parent_bh, "free data blocks"); - ext4_free_data(handle, inode, parent_bh, first, last); - } -} - -void ext4_ind_truncate(handle_t *handle, struct inode *inode) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - __le32 *i_data = ei->i_data; - int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb); - ext4_lblk_t offsets[4]; - Indirect chain[4]; - Indirect *partial; - __le32 nr = 0; - int n = 0; - ext4_lblk_t last_block, max_block; - unsigned blocksize = inode->i_sb->s_blocksize; - - last_block = (inode->i_size + blocksize-1) - >> EXT4_BLOCK_SIZE_BITS(inode->i_sb); - max_block = (EXT4_SB(inode->i_sb)->s_bitmap_maxbytes + blocksize-1) - >> EXT4_BLOCK_SIZE_BITS(inode->i_sb); - - if (last_block != max_block) { - n = ext4_block_to_path(inode, last_block, offsets, NULL); - if (n == 0) - return; - } - - ext4_es_remove_extent(inode, last_block, EXT_MAX_BLOCKS - last_block); - - /* - * The orphan list entry will now protect us from any crash which - * occurs before the truncate completes, so it is now safe to propagate - * the new, shorter inode size (held for now in i_size) into the - * on-disk inode. We do this via i_disksize, which is the value which - * ext4 *really* writes onto the disk inode. - */ - ei->i_disksize = inode->i_size; - - if (last_block == max_block) { - /* - * It is unnecessary to free any data blocks if last_block is - * equal to the indirect block limit. - */ - return; - } else if (n == 1) { /* direct blocks */ - ext4_free_data(handle, inode, NULL, i_data+offsets[0], - i_data + EXT4_NDIR_BLOCKS); - goto do_indirects; - } - - partial = ext4_find_shared(inode, n, offsets, chain, &nr); - /* Kill the top of shared branch (not detached) */ - if (nr) { - if (partial == chain) { - /* Shared branch grows from the inode */ - ext4_free_branches(handle, inode, NULL, - &nr, &nr+1, (chain+n-1) - partial); - *partial->p = 0; - /* - * We mark the inode dirty prior to restart, - * and prior to stop. No need for it here. - */ - } else { - /* Shared branch grows from an indirect block */ - BUFFER_TRACE(partial->bh, "get_write_access"); - ext4_free_branches(handle, inode, partial->bh, - partial->p, - partial->p+1, (chain+n-1) - partial); - } - } - /* Clear the ends of indirect blocks on the shared branch */ - while (partial > chain) { - ext4_free_branches(handle, inode, partial->bh, partial->p + 1, - (__le32*)partial->bh->b_data+addr_per_block, - (chain+n-1) - partial); - BUFFER_TRACE(partial->bh, "call brelse"); - brelse(partial->bh); - partial--; - } -do_indirects: - /* Kill the remaining (whole) subtrees */ - switch (offsets[0]) { - default: - nr = i_data[EXT4_IND_BLOCK]; - if (nr) { - ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1); - i_data[EXT4_IND_BLOCK] = 0; - } - case EXT4_IND_BLOCK: - nr = i_data[EXT4_DIND_BLOCK]; - if (nr) { - ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2); - i_data[EXT4_DIND_BLOCK] = 0; - } - case EXT4_DIND_BLOCK: - nr = i_data[EXT4_TIND_BLOCK]; - if (nr) { - ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3); - i_data[EXT4_TIND_BLOCK] = 0; - } - case EXT4_TIND_BLOCK: - ; - } -} - -/** - * ext4_ind_remove_space - remove space from the range - * @handle: JBD handle for this transaction - * @inode: inode we are dealing with - * @start: First block to remove - * @end: One block after the last block to remove (exclusive) - * - * Free the blocks in the defined range (end is exclusive endpoint of - * range). This is used by ext4_punch_hole(). - */ -int ext4_ind_remove_space(handle_t *handle, struct inode *inode, - ext4_lblk_t start, ext4_lblk_t end) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - __le32 *i_data = ei->i_data; - int addr_per_block = EXT4_ADDR_PER_BLOCK(inode->i_sb); - ext4_lblk_t offsets[4], offsets2[4]; - Indirect chain[4], chain2[4]; - Indirect *partial, *partial2; - ext4_lblk_t max_block; - __le32 nr = 0, nr2 = 0; - int n = 0, n2 = 0; - unsigned blocksize = inode->i_sb->s_blocksize; - - max_block = (EXT4_SB(inode->i_sb)->s_bitmap_maxbytes + blocksize-1) - >> EXT4_BLOCK_SIZE_BITS(inode->i_sb); - if (end >= max_block) - end = max_block; - if ((start >= end) || (start > max_block)) - return 0; - - n = ext4_block_to_path(inode, start, offsets, NULL); - n2 = ext4_block_to_path(inode, end, offsets2, NULL); - - BUG_ON(n > n2); - - if ((n == 1) && (n == n2)) { - /* We're punching only within direct block range */ - ext4_free_data(handle, inode, NULL, i_data + offsets[0], - i_data + offsets2[0]); - return 0; - } else if (n2 > n) { - /* - * Start and end are on a different levels so we're going to - * free partial block at start, and partial block at end of - * the range. If there are some levels in between then - * do_indirects label will take care of that. - */ - - if (n == 1) { - /* - * Start is at the direct block level, free - * everything to the end of the level. - */ - ext4_free_data(handle, inode, NULL, i_data + offsets[0], - i_data + EXT4_NDIR_BLOCKS); - goto end_range; - } - - - partial = ext4_find_shared(inode, n, offsets, chain, &nr); - if (nr) { - if (partial == chain) { - /* Shared branch grows from the inode */ - ext4_free_branches(handle, inode, NULL, - &nr, &nr+1, (chain+n-1) - partial); - *partial->p = 0; - } else { - /* Shared branch grows from an indirect block */ - BUFFER_TRACE(partial->bh, "get_write_access"); - ext4_free_branches(handle, inode, partial->bh, - partial->p, - partial->p+1, (chain+n-1) - partial); - } - } - - /* - * Clear the ends of indirect blocks on the shared branch - * at the start of the range - */ - while (partial > chain) { - ext4_free_branches(handle, inode, partial->bh, - partial->p + 1, - (__le32 *)partial->bh->b_data+addr_per_block, - (chain+n-1) - partial); - BUFFER_TRACE(partial->bh, "call brelse"); - brelse(partial->bh); - partial--; - } - -end_range: - partial2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2); - if (nr2) { - if (partial2 == chain2) { - /* - * Remember, end is exclusive so here we're at - * the start of the next level we're not going - * to free. Everything was covered by the start - * of the range. - */ - goto do_indirects; - } - } else { - /* - * ext4_find_shared returns Indirect structure which - * points to the last element which should not be - * removed by truncate. But this is end of the range - * in punch_hole so we need to point to the next element - */ - partial2->p++; - } - - /* - * Clear the ends of indirect blocks on the shared branch - * at the end of the range - */ - while (partial2 > chain2) { - ext4_free_branches(handle, inode, partial2->bh, - (__le32 *)partial2->bh->b_data, - partial2->p, - (chain2+n2-1) - partial2); - BUFFER_TRACE(partial2->bh, "call brelse"); - brelse(partial2->bh); - partial2--; - } - goto do_indirects; - } - - /* Punch happened within the same level (n == n2) */ - partial = ext4_find_shared(inode, n, offsets, chain, &nr); - partial2 = ext4_find_shared(inode, n2, offsets2, chain2, &nr2); - - /* Free top, but only if partial2 isn't its subtree. */ - if (nr) { - int level = min(partial - chain, partial2 - chain2); - int i; - int subtree = 1; - - for (i = 0; i <= level; i++) { - if (offsets[i] != offsets2[i]) { - subtree = 0; - break; - } - } - - if (!subtree) { - if (partial == chain) { - /* Shared branch grows from the inode */ - ext4_free_branches(handle, inode, NULL, - &nr, &nr+1, - (chain+n-1) - partial); - *partial->p = 0; - } else { - /* Shared branch grows from an indirect block */ - BUFFER_TRACE(partial->bh, "get_write_access"); - ext4_free_branches(handle, inode, partial->bh, - partial->p, - partial->p+1, - (chain+n-1) - partial); - } - } - } - - if (!nr2) { - /* - * ext4_find_shared returns Indirect structure which - * points to the last element which should not be - * removed by truncate. But this is end of the range - * in punch_hole so we need to point to the next element - */ - partial2->p++; - } - - while (partial > chain || partial2 > chain2) { - int depth = (chain+n-1) - partial; - int depth2 = (chain2+n2-1) - partial2; - - if (partial > chain && partial2 > chain2 && - partial->bh->b_blocknr == partial2->bh->b_blocknr) { - /* - * We've converged on the same block. Clear the range, - * then we're done. - */ - ext4_free_branches(handle, inode, partial->bh, - partial->p + 1, - partial2->p, - (chain+n-1) - partial); - BUFFER_TRACE(partial->bh, "call brelse"); - brelse(partial->bh); - BUFFER_TRACE(partial2->bh, "call brelse"); - brelse(partial2->bh); - return 0; - } - - /* - * The start and end partial branches may not be at the same - * level even though the punch happened within one level. So, we - * give them a chance to arrive at the same level, then walk - * them in step with each other until we converge on the same - * block. - */ - if (partial > chain && depth <= depth2) { - ext4_free_branches(handle, inode, partial->bh, - partial->p + 1, - (__le32 *)partial->bh->b_data+addr_per_block, - (chain+n-1) - partial); - BUFFER_TRACE(partial->bh, "call brelse"); - brelse(partial->bh); - partial--; - } - if (partial2 > chain2 && depth2 <= depth) { - ext4_free_branches(handle, inode, partial2->bh, - (__le32 *)partial2->bh->b_data, - partial2->p, - (chain2+n2-1) - partial2); - BUFFER_TRACE(partial2->bh, "call brelse"); - brelse(partial2->bh); - partial2--; - } - } - return 0; - -do_indirects: - /* Kill the remaining (whole) subtrees */ - switch (offsets[0]) { - default: - if (++n >= n2) - return 0; - nr = i_data[EXT4_IND_BLOCK]; - if (nr) { - ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 1); - i_data[EXT4_IND_BLOCK] = 0; - } - case EXT4_IND_BLOCK: - if (++n >= n2) - return 0; - nr = i_data[EXT4_DIND_BLOCK]; - if (nr) { - ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 2); - i_data[EXT4_DIND_BLOCK] = 0; - } - case EXT4_DIND_BLOCK: - if (++n >= n2) - return 0; - nr = i_data[EXT4_TIND_BLOCK]; - if (nr) { - ext4_free_branches(handle, inode, NULL, &nr, &nr+1, 3); - i_data[EXT4_TIND_BLOCK] = 0; - } - case EXT4_TIND_BLOCK: - ; - } - return 0; -} diff --git a/src/linux/fs/ext4/inline.c b/src/linux/fs/ext4/inline.c deleted file mode 100644 index f74d5ee..0000000 --- a/src/linux/fs/ext4/inline.c +++ /dev/null @@ -1,2020 +0,0 @@ -/* - * Copyright (c) 2012 Taobao. - * Written by Tao Ma - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include - -#include "ext4_jbd2.h" -#include "ext4.h" -#include "xattr.h" -#include "truncate.h" - -#define EXT4_XATTR_SYSTEM_DATA "data" -#define EXT4_MIN_INLINE_DATA_SIZE ((sizeof(__le32) * EXT4_N_BLOCKS)) -#define EXT4_INLINE_DOTDOT_OFFSET 2 -#define EXT4_INLINE_DOTDOT_SIZE 4 - -static int ext4_get_inline_size(struct inode *inode) -{ - if (EXT4_I(inode)->i_inline_off) - return EXT4_I(inode)->i_inline_size; - - return 0; -} - -static int get_max_inline_xattr_value_size(struct inode *inode, - struct ext4_iloc *iloc) -{ - struct ext4_xattr_ibody_header *header; - struct ext4_xattr_entry *entry; - struct ext4_inode *raw_inode; - int free, min_offs; - - min_offs = EXT4_SB(inode->i_sb)->s_inode_size - - EXT4_GOOD_OLD_INODE_SIZE - - EXT4_I(inode)->i_extra_isize - - sizeof(struct ext4_xattr_ibody_header); - - /* - * We need to subtract another sizeof(__u32) since an in-inode xattr - * needs an empty 4 bytes to indicate the gap between the xattr entry - * and the name/value pair. - */ - if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR)) - return EXT4_XATTR_SIZE(min_offs - - EXT4_XATTR_LEN(strlen(EXT4_XATTR_SYSTEM_DATA)) - - EXT4_XATTR_ROUND - sizeof(__u32)); - - raw_inode = ext4_raw_inode(iloc); - header = IHDR(inode, raw_inode); - entry = IFIRST(header); - - /* Compute min_offs. */ - for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) { - if (!entry->e_value_block && entry->e_value_size) { - size_t offs = le16_to_cpu(entry->e_value_offs); - if (offs < min_offs) - min_offs = offs; - } - } - free = min_offs - - ((void *)entry - (void *)IFIRST(header)) - sizeof(__u32); - - if (EXT4_I(inode)->i_inline_off) { - entry = (struct ext4_xattr_entry *) - ((void *)raw_inode + EXT4_I(inode)->i_inline_off); - - free += EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size)); - goto out; - } - - free -= EXT4_XATTR_LEN(strlen(EXT4_XATTR_SYSTEM_DATA)); - - if (free > EXT4_XATTR_ROUND) - free = EXT4_XATTR_SIZE(free - EXT4_XATTR_ROUND); - else - free = 0; - -out: - return free; -} - -/* - * Get the maximum size we now can store in an inode. - * If we can't find the space for a xattr entry, don't use the space - * of the extents since we have no space to indicate the inline data. - */ -int ext4_get_max_inline_size(struct inode *inode) -{ - int error, max_inline_size; - struct ext4_iloc iloc; - - if (EXT4_I(inode)->i_extra_isize == 0) - return 0; - - error = ext4_get_inode_loc(inode, &iloc); - if (error) { - ext4_error_inode(inode, __func__, __LINE__, 0, - "can't get inode location %lu", - inode->i_ino); - return 0; - } - - down_read(&EXT4_I(inode)->xattr_sem); - max_inline_size = get_max_inline_xattr_value_size(inode, &iloc); - up_read(&EXT4_I(inode)->xattr_sem); - - brelse(iloc.bh); - - if (!max_inline_size) - return 0; - - return max_inline_size + EXT4_MIN_INLINE_DATA_SIZE; -} - -/* - * this function does not take xattr_sem, which is OK because it is - * currently only used in a code path coming form ext4_iget, before - * the new inode has been unlocked - */ -int ext4_find_inline_data_nolock(struct inode *inode) -{ - struct ext4_xattr_ibody_find is = { - .s = { .not_found = -ENODATA, }, - }; - struct ext4_xattr_info i = { - .name_index = EXT4_XATTR_INDEX_SYSTEM, - .name = EXT4_XATTR_SYSTEM_DATA, - }; - int error; - - if (EXT4_I(inode)->i_extra_isize == 0) - return 0; - - error = ext4_get_inode_loc(inode, &is.iloc); - if (error) - return error; - - error = ext4_xattr_ibody_find(inode, &i, &is); - if (error) - goto out; - - if (!is.s.not_found) { - EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here - - (void *)ext4_raw_inode(&is.iloc)); - EXT4_I(inode)->i_inline_size = EXT4_MIN_INLINE_DATA_SIZE + - le32_to_cpu(is.s.here->e_value_size); - ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); - } -out: - brelse(is.iloc.bh); - return error; -} - -static int ext4_read_inline_data(struct inode *inode, void *buffer, - unsigned int len, - struct ext4_iloc *iloc) -{ - struct ext4_xattr_entry *entry; - struct ext4_xattr_ibody_header *header; - int cp_len = 0; - struct ext4_inode *raw_inode; - - if (!len) - return 0; - - BUG_ON(len > EXT4_I(inode)->i_inline_size); - - cp_len = len < EXT4_MIN_INLINE_DATA_SIZE ? - len : EXT4_MIN_INLINE_DATA_SIZE; - - raw_inode = ext4_raw_inode(iloc); - memcpy(buffer, (void *)(raw_inode->i_block), cp_len); - - len -= cp_len; - buffer += cp_len; - - if (!len) - goto out; - - header = IHDR(inode, raw_inode); - entry = (struct ext4_xattr_entry *)((void *)raw_inode + - EXT4_I(inode)->i_inline_off); - len = min_t(unsigned int, len, - (unsigned int)le32_to_cpu(entry->e_value_size)); - - memcpy(buffer, - (void *)IFIRST(header) + le16_to_cpu(entry->e_value_offs), len); - cp_len += len; - -out: - return cp_len; -} - -/* - * write the buffer to the inline inode. - * If 'create' is set, we don't need to do the extra copy in the xattr - * value since it is already handled by ext4_xattr_ibody_inline_set. - * That saves us one memcpy. - */ -static void ext4_write_inline_data(struct inode *inode, struct ext4_iloc *iloc, - void *buffer, loff_t pos, unsigned int len) -{ - struct ext4_xattr_entry *entry; - struct ext4_xattr_ibody_header *header; - struct ext4_inode *raw_inode; - int cp_len = 0; - - BUG_ON(!EXT4_I(inode)->i_inline_off); - BUG_ON(pos + len > EXT4_I(inode)->i_inline_size); - - raw_inode = ext4_raw_inode(iloc); - buffer += pos; - - if (pos < EXT4_MIN_INLINE_DATA_SIZE) { - cp_len = pos + len > EXT4_MIN_INLINE_DATA_SIZE ? - EXT4_MIN_INLINE_DATA_SIZE - pos : len; - memcpy((void *)raw_inode->i_block + pos, buffer, cp_len); - - len -= cp_len; - buffer += cp_len; - pos += cp_len; - } - - if (!len) - return; - - pos -= EXT4_MIN_INLINE_DATA_SIZE; - header = IHDR(inode, raw_inode); - entry = (struct ext4_xattr_entry *)((void *)raw_inode + - EXT4_I(inode)->i_inline_off); - - memcpy((void *)IFIRST(header) + le16_to_cpu(entry->e_value_offs) + pos, - buffer, len); -} - -static int ext4_create_inline_data(handle_t *handle, - struct inode *inode, unsigned len) -{ - int error; - void *value = NULL; - struct ext4_xattr_ibody_find is = { - .s = { .not_found = -ENODATA, }, - }; - struct ext4_xattr_info i = { - .name_index = EXT4_XATTR_INDEX_SYSTEM, - .name = EXT4_XATTR_SYSTEM_DATA, - }; - - error = ext4_get_inode_loc(inode, &is.iloc); - if (error) - return error; - - BUFFER_TRACE(is.iloc.bh, "get_write_access"); - error = ext4_journal_get_write_access(handle, is.iloc.bh); - if (error) - goto out; - - if (len > EXT4_MIN_INLINE_DATA_SIZE) { - value = EXT4_ZERO_XATTR_VALUE; - len -= EXT4_MIN_INLINE_DATA_SIZE; - } else { - value = ""; - len = 0; - } - - /* Insert the the xttr entry. */ - i.value = value; - i.value_len = len; - - error = ext4_xattr_ibody_find(inode, &i, &is); - if (error) - goto out; - - BUG_ON(!is.s.not_found); - - error = ext4_xattr_ibody_inline_set(handle, inode, &i, &is); - if (error) { - if (error == -ENOSPC) - ext4_clear_inode_state(inode, - EXT4_STATE_MAY_INLINE_DATA); - goto out; - } - - memset((void *)ext4_raw_inode(&is.iloc)->i_block, - 0, EXT4_MIN_INLINE_DATA_SIZE); - - EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here - - (void *)ext4_raw_inode(&is.iloc)); - EXT4_I(inode)->i_inline_size = len + EXT4_MIN_INLINE_DATA_SIZE; - ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS); - ext4_set_inode_flag(inode, EXT4_INODE_INLINE_DATA); - get_bh(is.iloc.bh); - error = ext4_mark_iloc_dirty(handle, inode, &is.iloc); - -out: - brelse(is.iloc.bh); - return error; -} - -static int ext4_update_inline_data(handle_t *handle, struct inode *inode, - unsigned int len) -{ - int error; - void *value = NULL; - struct ext4_xattr_ibody_find is = { - .s = { .not_found = -ENODATA, }, - }; - struct ext4_xattr_info i = { - .name_index = EXT4_XATTR_INDEX_SYSTEM, - .name = EXT4_XATTR_SYSTEM_DATA, - }; - - /* If the old space is ok, write the data directly. */ - if (len <= EXT4_I(inode)->i_inline_size) - return 0; - - error = ext4_get_inode_loc(inode, &is.iloc); - if (error) - return error; - - error = ext4_xattr_ibody_find(inode, &i, &is); - if (error) - goto out; - - BUG_ON(is.s.not_found); - - len -= EXT4_MIN_INLINE_DATA_SIZE; - value = kzalloc(len, GFP_NOFS); - if (!value) - goto out; - - error = ext4_xattr_ibody_get(inode, i.name_index, i.name, - value, len); - if (error == -ENODATA) - goto out; - - BUFFER_TRACE(is.iloc.bh, "get_write_access"); - error = ext4_journal_get_write_access(handle, is.iloc.bh); - if (error) - goto out; - - /* Update the xttr entry. */ - i.value = value; - i.value_len = len; - - error = ext4_xattr_ibody_inline_set(handle, inode, &i, &is); - if (error) - goto out; - - EXT4_I(inode)->i_inline_off = (u16)((void *)is.s.here - - (void *)ext4_raw_inode(&is.iloc)); - EXT4_I(inode)->i_inline_size = EXT4_MIN_INLINE_DATA_SIZE + - le32_to_cpu(is.s.here->e_value_size); - ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); - get_bh(is.iloc.bh); - error = ext4_mark_iloc_dirty(handle, inode, &is.iloc); - -out: - kfree(value); - brelse(is.iloc.bh); - return error; -} - -static int ext4_prepare_inline_data(handle_t *handle, struct inode *inode, - unsigned int len) -{ - int ret, size; - struct ext4_inode_info *ei = EXT4_I(inode); - - if (!ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) - return -ENOSPC; - - size = ext4_get_max_inline_size(inode); - if (size < len) - return -ENOSPC; - - down_write(&EXT4_I(inode)->xattr_sem); - - if (ei->i_inline_off) - ret = ext4_update_inline_data(handle, inode, len); - else - ret = ext4_create_inline_data(handle, inode, len); - - up_write(&EXT4_I(inode)->xattr_sem); - - return ret; -} - -static int ext4_destroy_inline_data_nolock(handle_t *handle, - struct inode *inode) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - struct ext4_xattr_ibody_find is = { - .s = { .not_found = 0, }, - }; - struct ext4_xattr_info i = { - .name_index = EXT4_XATTR_INDEX_SYSTEM, - .name = EXT4_XATTR_SYSTEM_DATA, - .value = NULL, - .value_len = 0, - }; - int error; - - if (!ei->i_inline_off) - return 0; - - error = ext4_get_inode_loc(inode, &is.iloc); - if (error) - return error; - - error = ext4_xattr_ibody_find(inode, &i, &is); - if (error) - goto out; - - BUFFER_TRACE(is.iloc.bh, "get_write_access"); - error = ext4_journal_get_write_access(handle, is.iloc.bh); - if (error) - goto out; - - error = ext4_xattr_ibody_inline_set(handle, inode, &i, &is); - if (error) - goto out; - - memset((void *)ext4_raw_inode(&is.iloc)->i_block, - 0, EXT4_MIN_INLINE_DATA_SIZE); - - if (ext4_has_feature_extents(inode->i_sb)) { - if (S_ISDIR(inode->i_mode) || - S_ISREG(inode->i_mode) || S_ISLNK(inode->i_mode)) { - ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS); - ext4_ext_tree_init(handle, inode); - } - } - ext4_clear_inode_flag(inode, EXT4_INODE_INLINE_DATA); - - get_bh(is.iloc.bh); - error = ext4_mark_iloc_dirty(handle, inode, &is.iloc); - - EXT4_I(inode)->i_inline_off = 0; - EXT4_I(inode)->i_inline_size = 0; - ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); -out: - brelse(is.iloc.bh); - if (error == -ENODATA) - error = 0; - return error; -} - -static int ext4_read_inline_page(struct inode *inode, struct page *page) -{ - void *kaddr; - int ret = 0; - size_t len; - struct ext4_iloc iloc; - - BUG_ON(!PageLocked(page)); - BUG_ON(!ext4_has_inline_data(inode)); - BUG_ON(page->index); - - if (!EXT4_I(inode)->i_inline_off) { - ext4_warning(inode->i_sb, "inode %lu doesn't have inline data.", - inode->i_ino); - goto out; - } - - ret = ext4_get_inode_loc(inode, &iloc); - if (ret) - goto out; - - len = min_t(size_t, ext4_get_inline_size(inode), i_size_read(inode)); - kaddr = kmap_atomic(page); - ret = ext4_read_inline_data(inode, kaddr, len, &iloc); - flush_dcache_page(page); - kunmap_atomic(kaddr); - zero_user_segment(page, len, PAGE_SIZE); - SetPageUptodate(page); - brelse(iloc.bh); - -out: - return ret; -} - -int ext4_readpage_inline(struct inode *inode, struct page *page) -{ - int ret = 0; - - down_read(&EXT4_I(inode)->xattr_sem); - if (!ext4_has_inline_data(inode)) { - up_read(&EXT4_I(inode)->xattr_sem); - return -EAGAIN; - } - - /* - * Current inline data can only exist in the 1st page, - * So for all the other pages, just set them uptodate. - */ - if (!page->index) - ret = ext4_read_inline_page(inode, page); - else if (!PageUptodate(page)) { - zero_user_segment(page, 0, PAGE_SIZE); - SetPageUptodate(page); - } - - up_read(&EXT4_I(inode)->xattr_sem); - - unlock_page(page); - return ret >= 0 ? 0 : ret; -} - -static int ext4_convert_inline_data_to_extent(struct address_space *mapping, - struct inode *inode, - unsigned flags) -{ - int ret, needed_blocks; - handle_t *handle = NULL; - int retries = 0, sem_held = 0; - struct page *page = NULL; - unsigned from, to; - struct ext4_iloc iloc; - - if (!ext4_has_inline_data(inode)) { - /* - * clear the flag so that no new write - * will trap here again. - */ - ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); - return 0; - } - - needed_blocks = ext4_writepage_trans_blocks(inode); - - ret = ext4_get_inode_loc(inode, &iloc); - if (ret) - return ret; - -retry: - handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, needed_blocks); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - handle = NULL; - goto out; - } - - /* We cannot recurse into the filesystem as the transaction is already - * started */ - flags |= AOP_FLAG_NOFS; - - page = grab_cache_page_write_begin(mapping, 0, flags); - if (!page) { - ret = -ENOMEM; - goto out; - } - - down_write(&EXT4_I(inode)->xattr_sem); - sem_held = 1; - /* If some one has already done this for us, just exit. */ - if (!ext4_has_inline_data(inode)) { - ret = 0; - goto out; - } - - from = 0; - to = ext4_get_inline_size(inode); - if (!PageUptodate(page)) { - ret = ext4_read_inline_page(inode, page); - if (ret < 0) - goto out; - } - - ret = ext4_destroy_inline_data_nolock(handle, inode); - if (ret) - goto out; - - if (ext4_should_dioread_nolock(inode)) { - ret = __block_write_begin(page, from, to, - ext4_get_block_unwritten); - } else - ret = __block_write_begin(page, from, to, ext4_get_block); - - if (!ret && ext4_should_journal_data(inode)) { - ret = ext4_walk_page_buffers(handle, page_buffers(page), - from, to, NULL, - do_journal_get_write_access); - } - - if (ret) { - unlock_page(page); - put_page(page); - page = NULL; - ext4_orphan_add(handle, inode); - up_write(&EXT4_I(inode)->xattr_sem); - sem_held = 0; - ext4_journal_stop(handle); - handle = NULL; - ext4_truncate_failed_write(inode); - /* - * If truncate failed early the inode might - * still be on the orphan list; we need to - * make sure the inode is removed from the - * orphan list in that case. - */ - if (inode->i_nlink) - ext4_orphan_del(NULL, inode); - } - - if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) - goto retry; - - if (page) - block_commit_write(page, from, to); -out: - if (page) { - unlock_page(page); - put_page(page); - } - if (sem_held) - up_write(&EXT4_I(inode)->xattr_sem); - if (handle) - ext4_journal_stop(handle); - brelse(iloc.bh); - return ret; -} - -/* - * Try to write data in the inode. - * If the inode has inline data, check whether the new write can be - * in the inode also. If not, create the page the handle, move the data - * to the page make it update and let the later codes create extent for it. - */ -int ext4_try_to_write_inline_data(struct address_space *mapping, - struct inode *inode, - loff_t pos, unsigned len, - unsigned flags, - struct page **pagep) -{ - int ret; - handle_t *handle; - struct page *page; - struct ext4_iloc iloc; - - if (pos + len > ext4_get_max_inline_size(inode)) - goto convert; - - ret = ext4_get_inode_loc(inode, &iloc); - if (ret) - return ret; - - /* - * The possible write could happen in the inode, - * so try to reserve the space in inode first. - */ - handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - handle = NULL; - goto out; - } - - ret = ext4_prepare_inline_data(handle, inode, pos + len); - if (ret && ret != -ENOSPC) - goto out; - - /* We don't have space in inline inode, so convert it to extent. */ - if (ret == -ENOSPC) { - ext4_journal_stop(handle); - brelse(iloc.bh); - goto convert; - } - - flags |= AOP_FLAG_NOFS; - - page = grab_cache_page_write_begin(mapping, 0, flags); - if (!page) { - ret = -ENOMEM; - goto out; - } - - *pagep = page; - down_read(&EXT4_I(inode)->xattr_sem); - if (!ext4_has_inline_data(inode)) { - ret = 0; - unlock_page(page); - put_page(page); - goto out_up_read; - } - - if (!PageUptodate(page)) { - ret = ext4_read_inline_page(inode, page); - if (ret < 0) - goto out_up_read; - } - - ret = 1; - handle = NULL; -out_up_read: - up_read(&EXT4_I(inode)->xattr_sem); -out: - if (handle) - ext4_journal_stop(handle); - brelse(iloc.bh); - return ret; -convert: - return ext4_convert_inline_data_to_extent(mapping, - inode, flags); -} - -int ext4_write_inline_data_end(struct inode *inode, loff_t pos, unsigned len, - unsigned copied, struct page *page) -{ - int ret; - void *kaddr; - struct ext4_iloc iloc; - - if (unlikely(copied < len)) { - if (!PageUptodate(page)) { - copied = 0; - goto out; - } - } - - ret = ext4_get_inode_loc(inode, &iloc); - if (ret) { - ext4_std_error(inode->i_sb, ret); - copied = 0; - goto out; - } - - down_write(&EXT4_I(inode)->xattr_sem); - BUG_ON(!ext4_has_inline_data(inode)); - - kaddr = kmap_atomic(page); - ext4_write_inline_data(inode, &iloc, kaddr, pos, len); - kunmap_atomic(kaddr); - SetPageUptodate(page); - /* clear page dirty so that writepages wouldn't work for us. */ - ClearPageDirty(page); - - up_write(&EXT4_I(inode)->xattr_sem); - brelse(iloc.bh); -out: - return copied; -} - -struct buffer_head * -ext4_journalled_write_inline_data(struct inode *inode, - unsigned len, - struct page *page) -{ - int ret; - void *kaddr; - struct ext4_iloc iloc; - - ret = ext4_get_inode_loc(inode, &iloc); - if (ret) { - ext4_std_error(inode->i_sb, ret); - return NULL; - } - - down_write(&EXT4_I(inode)->xattr_sem); - kaddr = kmap_atomic(page); - ext4_write_inline_data(inode, &iloc, kaddr, 0, len); - kunmap_atomic(kaddr); - up_write(&EXT4_I(inode)->xattr_sem); - - return iloc.bh; -} - -/* - * Try to make the page cache and handle ready for the inline data case. - * We can call this function in 2 cases: - * 1. The inode is created and the first write exceeds inline size. We can - * clear the inode state safely. - * 2. The inode has inline data, then we need to read the data, make it - * update and dirty so that ext4_da_writepages can handle it. We don't - * need to start the journal since the file's metatdata isn't changed now. - */ -static int ext4_da_convert_inline_data_to_extent(struct address_space *mapping, - struct inode *inode, - unsigned flags, - void **fsdata) -{ - int ret = 0, inline_size; - struct page *page; - - page = grab_cache_page_write_begin(mapping, 0, flags); - if (!page) - return -ENOMEM; - - down_read(&EXT4_I(inode)->xattr_sem); - if (!ext4_has_inline_data(inode)) { - ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); - goto out; - } - - inline_size = ext4_get_inline_size(inode); - - if (!PageUptodate(page)) { - ret = ext4_read_inline_page(inode, page); - if (ret < 0) - goto out; - } - - ret = __block_write_begin(page, 0, inline_size, - ext4_da_get_block_prep); - if (ret) { - up_read(&EXT4_I(inode)->xattr_sem); - unlock_page(page); - put_page(page); - ext4_truncate_failed_write(inode); - return ret; - } - - SetPageDirty(page); - SetPageUptodate(page); - ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); - *fsdata = (void *)CONVERT_INLINE_DATA; - -out: - up_read(&EXT4_I(inode)->xattr_sem); - if (page) { - unlock_page(page); - put_page(page); - } - return ret; -} - -/* - * Prepare the write for the inline data. - * If the the data can be written into the inode, we just read - * the page and make it uptodate, and start the journal. - * Otherwise read the page, makes it dirty so that it can be - * handle in writepages(the i_disksize update is left to the - * normal ext4_da_write_end). - */ -int ext4_da_write_inline_data_begin(struct address_space *mapping, - struct inode *inode, - loff_t pos, unsigned len, - unsigned flags, - struct page **pagep, - void **fsdata) -{ - int ret, inline_size; - handle_t *handle; - struct page *page; - struct ext4_iloc iloc; - int retries; - - ret = ext4_get_inode_loc(inode, &iloc); - if (ret) - return ret; - -retry_journal: - handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - goto out; - } - - inline_size = ext4_get_max_inline_size(inode); - - ret = -ENOSPC; - if (inline_size >= pos + len) { - ret = ext4_prepare_inline_data(handle, inode, pos + len); - if (ret && ret != -ENOSPC) - goto out_journal; - } - - /* - * We cannot recurse into the filesystem as the transaction - * is already started. - */ - flags |= AOP_FLAG_NOFS; - - if (ret == -ENOSPC) { - ret = ext4_da_convert_inline_data_to_extent(mapping, - inode, - flags, - fsdata); - ext4_journal_stop(handle); - if (ret == -ENOSPC && - ext4_should_retry_alloc(inode->i_sb, &retries)) - goto retry_journal; - goto out; - } - - - page = grab_cache_page_write_begin(mapping, 0, flags); - if (!page) { - ret = -ENOMEM; - goto out_journal; - } - - down_read(&EXT4_I(inode)->xattr_sem); - if (!ext4_has_inline_data(inode)) { - ret = 0; - goto out_release_page; - } - - if (!PageUptodate(page)) { - ret = ext4_read_inline_page(inode, page); - if (ret < 0) - goto out_release_page; - } - - up_read(&EXT4_I(inode)->xattr_sem); - *pagep = page; - brelse(iloc.bh); - return 1; -out_release_page: - up_read(&EXT4_I(inode)->xattr_sem); - unlock_page(page); - put_page(page); -out_journal: - ext4_journal_stop(handle); -out: - brelse(iloc.bh); - return ret; -} - -int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos, - unsigned len, unsigned copied, - struct page *page) -{ - int i_size_changed = 0; - - copied = ext4_write_inline_data_end(inode, pos, len, copied, page); - - /* - * No need to use i_size_read() here, the i_size - * cannot change under us because we hold i_mutex. - * - * But it's important to update i_size while still holding page lock: - * page writeout could otherwise come in and zero beyond i_size. - */ - if (pos+copied > inode->i_size) { - i_size_write(inode, pos+copied); - i_size_changed = 1; - } - unlock_page(page); - put_page(page); - - /* - * Don't mark the inode dirty under page lock. First, it unnecessarily - * makes the holding time of page lock longer. Second, it forces lock - * ordering of page lock and transaction start for journaling - * filesystems. - */ - if (i_size_changed) - mark_inode_dirty(inode); - - return copied; -} - -#ifdef INLINE_DIR_DEBUG -void ext4_show_inline_dir(struct inode *dir, struct buffer_head *bh, - void *inline_start, int inline_size) -{ - int offset; - unsigned short de_len; - struct ext4_dir_entry_2 *de = inline_start; - void *dlimit = inline_start + inline_size; - - trace_printk("inode %lu\n", dir->i_ino); - offset = 0; - while ((void *)de < dlimit) { - de_len = ext4_rec_len_from_disk(de->rec_len, inline_size); - trace_printk("de: off %u rlen %u name %.*s nlen %u ino %u\n", - offset, de_len, de->name_len, de->name, - de->name_len, le32_to_cpu(de->inode)); - if (ext4_check_dir_entry(dir, NULL, de, bh, - inline_start, inline_size, offset)) - BUG(); - - offset += de_len; - de = (struct ext4_dir_entry_2 *) ((char *) de + de_len); - } -} -#else -#define ext4_show_inline_dir(dir, bh, inline_start, inline_size) -#endif - -/* - * Add a new entry into a inline dir. - * It will return -ENOSPC if no space is available, and -EIO - * and -EEXIST if directory entry already exists. - */ -static int ext4_add_dirent_to_inline(handle_t *handle, - struct ext4_filename *fname, - struct inode *dir, - struct inode *inode, - struct ext4_iloc *iloc, - void *inline_start, int inline_size) -{ - int err; - struct ext4_dir_entry_2 *de; - - err = ext4_find_dest_de(dir, inode, iloc->bh, inline_start, - inline_size, fname, &de); - if (err) - return err; - - BUFFER_TRACE(iloc->bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, iloc->bh); - if (err) - return err; - ext4_insert_dentry(dir, inode, de, inline_size, fname); - - ext4_show_inline_dir(dir, iloc->bh, inline_start, inline_size); - - /* - * XXX shouldn't update any times until successful - * completion of syscall, but too many callers depend - * on this. - * - * XXX similarly, too many callers depend on - * ext4_new_inode() setting the times, but error - * recovery deletes the inode, so the worst that can - * happen is that the times are slightly out of date - * and/or different from the directory change time. - */ - dir->i_mtime = dir->i_ctime = ext4_current_time(dir); - ext4_update_dx_flag(dir); - dir->i_version++; - ext4_mark_inode_dirty(handle, dir); - return 1; -} - -static void *ext4_get_inline_xattr_pos(struct inode *inode, - struct ext4_iloc *iloc) -{ - struct ext4_xattr_entry *entry; - struct ext4_xattr_ibody_header *header; - - BUG_ON(!EXT4_I(inode)->i_inline_off); - - header = IHDR(inode, ext4_raw_inode(iloc)); - entry = (struct ext4_xattr_entry *)((void *)ext4_raw_inode(iloc) + - EXT4_I(inode)->i_inline_off); - - return (void *)IFIRST(header) + le16_to_cpu(entry->e_value_offs); -} - -/* Set the final de to cover the whole block. */ -static void ext4_update_final_de(void *de_buf, int old_size, int new_size) -{ - struct ext4_dir_entry_2 *de, *prev_de; - void *limit; - int de_len; - - de = (struct ext4_dir_entry_2 *)de_buf; - if (old_size) { - limit = de_buf + old_size; - do { - prev_de = de; - de_len = ext4_rec_len_from_disk(de->rec_len, old_size); - de_buf += de_len; - de = (struct ext4_dir_entry_2 *)de_buf; - } while (de_buf < limit); - - prev_de->rec_len = ext4_rec_len_to_disk(de_len + new_size - - old_size, new_size); - } else { - /* this is just created, so create an empty entry. */ - de->inode = 0; - de->rec_len = ext4_rec_len_to_disk(new_size, new_size); - } -} - -static int ext4_update_inline_dir(handle_t *handle, struct inode *dir, - struct ext4_iloc *iloc) -{ - int ret; - int old_size = EXT4_I(dir)->i_inline_size - EXT4_MIN_INLINE_DATA_SIZE; - int new_size = get_max_inline_xattr_value_size(dir, iloc); - - if (new_size - old_size <= EXT4_DIR_REC_LEN(1)) - return -ENOSPC; - - ret = ext4_update_inline_data(handle, dir, - new_size + EXT4_MIN_INLINE_DATA_SIZE); - if (ret) - return ret; - - ext4_update_final_de(ext4_get_inline_xattr_pos(dir, iloc), old_size, - EXT4_I(dir)->i_inline_size - - EXT4_MIN_INLINE_DATA_SIZE); - dir->i_size = EXT4_I(dir)->i_disksize = EXT4_I(dir)->i_inline_size; - return 0; -} - -static void ext4_restore_inline_data(handle_t *handle, struct inode *inode, - struct ext4_iloc *iloc, - void *buf, int inline_size) -{ - ext4_create_inline_data(handle, inode, inline_size); - ext4_write_inline_data(inode, iloc, buf, 0, inline_size); - ext4_set_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); -} - -static int ext4_finish_convert_inline_dir(handle_t *handle, - struct inode *inode, - struct buffer_head *dir_block, - void *buf, - int inline_size) -{ - int err, csum_size = 0, header_size = 0; - struct ext4_dir_entry_2 *de; - struct ext4_dir_entry_tail *t; - void *target = dir_block->b_data; - - /* - * First create "." and ".." and then copy the dir information - * back to the block. - */ - de = (struct ext4_dir_entry_2 *)target; - de = ext4_init_dot_dotdot(inode, de, - inode->i_sb->s_blocksize, csum_size, - le32_to_cpu(((struct ext4_dir_entry_2 *)buf)->inode), 1); - header_size = (void *)de - target; - - memcpy((void *)de, buf + EXT4_INLINE_DOTDOT_SIZE, - inline_size - EXT4_INLINE_DOTDOT_SIZE); - - if (ext4_has_metadata_csum(inode->i_sb)) - csum_size = sizeof(struct ext4_dir_entry_tail); - - inode->i_size = inode->i_sb->s_blocksize; - i_size_write(inode, inode->i_sb->s_blocksize); - EXT4_I(inode)->i_disksize = inode->i_sb->s_blocksize; - ext4_update_final_de(dir_block->b_data, - inline_size - EXT4_INLINE_DOTDOT_SIZE + header_size, - inode->i_sb->s_blocksize - csum_size); - - if (csum_size) { - t = EXT4_DIRENT_TAIL(dir_block->b_data, - inode->i_sb->s_blocksize); - initialize_dirent_tail(t, inode->i_sb->s_blocksize); - } - set_buffer_uptodate(dir_block); - err = ext4_handle_dirty_dirent_node(handle, inode, dir_block); - if (err) - goto out; - set_buffer_verified(dir_block); -out: - return err; -} - -static int ext4_convert_inline_data_nolock(handle_t *handle, - struct inode *inode, - struct ext4_iloc *iloc) -{ - int error; - void *buf = NULL; - struct buffer_head *data_bh = NULL; - struct ext4_map_blocks map; - int inline_size; - - inline_size = ext4_get_inline_size(inode); - buf = kmalloc(inline_size, GFP_NOFS); - if (!buf) { - error = -ENOMEM; - goto out; - } - - error = ext4_read_inline_data(inode, buf, inline_size, iloc); - if (error < 0) - goto out; - - /* - * Make sure the inline directory entries pass checks before we try to - * convert them, so that we avoid touching stuff that needs fsck. - */ - if (S_ISDIR(inode->i_mode)) { - error = ext4_check_all_de(inode, iloc->bh, - buf + EXT4_INLINE_DOTDOT_SIZE, - inline_size - EXT4_INLINE_DOTDOT_SIZE); - if (error) - goto out; - } - - error = ext4_destroy_inline_data_nolock(handle, inode); - if (error) - goto out; - - map.m_lblk = 0; - map.m_len = 1; - map.m_flags = 0; - error = ext4_map_blocks(handle, inode, &map, EXT4_GET_BLOCKS_CREATE); - if (error < 0) - goto out_restore; - if (!(map.m_flags & EXT4_MAP_MAPPED)) { - error = -EIO; - goto out_restore; - } - - data_bh = sb_getblk(inode->i_sb, map.m_pblk); - if (!data_bh) { - error = -ENOMEM; - goto out_restore; - } - - lock_buffer(data_bh); - error = ext4_journal_get_create_access(handle, data_bh); - if (error) { - unlock_buffer(data_bh); - error = -EIO; - goto out_restore; - } - memset(data_bh->b_data, 0, inode->i_sb->s_blocksize); - - if (!S_ISDIR(inode->i_mode)) { - memcpy(data_bh->b_data, buf, inline_size); - set_buffer_uptodate(data_bh); - error = ext4_handle_dirty_metadata(handle, - inode, data_bh); - } else { - error = ext4_finish_convert_inline_dir(handle, inode, data_bh, - buf, inline_size); - } - - unlock_buffer(data_bh); -out_restore: - if (error) - ext4_restore_inline_data(handle, inode, iloc, buf, inline_size); - -out: - brelse(data_bh); - kfree(buf); - return error; -} - -/* - * Try to add the new entry to the inline data. - * If succeeds, return 0. If not, extended the inline dir and copied data to - * the new created block. - */ -int ext4_try_add_inline_entry(handle_t *handle, struct ext4_filename *fname, - struct inode *dir, struct inode *inode) -{ - int ret, inline_size; - void *inline_start; - struct ext4_iloc iloc; - - ret = ext4_get_inode_loc(dir, &iloc); - if (ret) - return ret; - - down_write(&EXT4_I(dir)->xattr_sem); - if (!ext4_has_inline_data(dir)) - goto out; - - inline_start = (void *)ext4_raw_inode(&iloc)->i_block + - EXT4_INLINE_DOTDOT_SIZE; - inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DOTDOT_SIZE; - - ret = ext4_add_dirent_to_inline(handle, fname, dir, inode, &iloc, - inline_start, inline_size); - if (ret != -ENOSPC) - goto out; - - /* check whether it can be inserted to inline xattr space. */ - inline_size = EXT4_I(dir)->i_inline_size - - EXT4_MIN_INLINE_DATA_SIZE; - if (!inline_size) { - /* Try to use the xattr space.*/ - ret = ext4_update_inline_dir(handle, dir, &iloc); - if (ret && ret != -ENOSPC) - goto out; - - inline_size = EXT4_I(dir)->i_inline_size - - EXT4_MIN_INLINE_DATA_SIZE; - } - - if (inline_size) { - inline_start = ext4_get_inline_xattr_pos(dir, &iloc); - - ret = ext4_add_dirent_to_inline(handle, fname, dir, - inode, &iloc, inline_start, - inline_size); - - if (ret != -ENOSPC) - goto out; - } - - /* - * The inline space is filled up, so create a new block for it. - * As the extent tree will be created, we have to save the inline - * dir first. - */ - ret = ext4_convert_inline_data_nolock(handle, dir, &iloc); - -out: - ext4_mark_inode_dirty(handle, dir); - up_write(&EXT4_I(dir)->xattr_sem); - brelse(iloc.bh); - return ret; -} - -/* - * This function fills a red-black tree with information from an - * inlined dir. It returns the number directory entries loaded - * into the tree. If there is an error it is returned in err. - */ -int htree_inlinedir_to_tree(struct file *dir_file, - struct inode *dir, ext4_lblk_t block, - struct dx_hash_info *hinfo, - __u32 start_hash, __u32 start_minor_hash, - int *has_inline_data) -{ - int err = 0, count = 0; - unsigned int parent_ino; - int pos; - struct ext4_dir_entry_2 *de; - struct inode *inode = file_inode(dir_file); - int ret, inline_size = 0; - struct ext4_iloc iloc; - void *dir_buf = NULL; - struct ext4_dir_entry_2 fake; - struct fscrypt_str tmp_str; - - ret = ext4_get_inode_loc(inode, &iloc); - if (ret) - return ret; - - down_read(&EXT4_I(inode)->xattr_sem); - if (!ext4_has_inline_data(inode)) { - up_read(&EXT4_I(inode)->xattr_sem); - *has_inline_data = 0; - goto out; - } - - inline_size = ext4_get_inline_size(inode); - dir_buf = kmalloc(inline_size, GFP_NOFS); - if (!dir_buf) { - ret = -ENOMEM; - up_read(&EXT4_I(inode)->xattr_sem); - goto out; - } - - ret = ext4_read_inline_data(inode, dir_buf, inline_size, &iloc); - up_read(&EXT4_I(inode)->xattr_sem); - if (ret < 0) - goto out; - - pos = 0; - parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode); - while (pos < inline_size) { - /* - * As inlined dir doesn't store any information about '.' and - * only the inode number of '..' is stored, we have to handle - * them differently. - */ - if (pos == 0) { - fake.inode = cpu_to_le32(inode->i_ino); - fake.name_len = 1; - strcpy(fake.name, "."); - fake.rec_len = ext4_rec_len_to_disk( - EXT4_DIR_REC_LEN(fake.name_len), - inline_size); - ext4_set_de_type(inode->i_sb, &fake, S_IFDIR); - de = &fake; - pos = EXT4_INLINE_DOTDOT_OFFSET; - } else if (pos == EXT4_INLINE_DOTDOT_OFFSET) { - fake.inode = cpu_to_le32(parent_ino); - fake.name_len = 2; - strcpy(fake.name, ".."); - fake.rec_len = ext4_rec_len_to_disk( - EXT4_DIR_REC_LEN(fake.name_len), - inline_size); - ext4_set_de_type(inode->i_sb, &fake, S_IFDIR); - de = &fake; - pos = EXT4_INLINE_DOTDOT_SIZE; - } else { - de = (struct ext4_dir_entry_2 *)(dir_buf + pos); - pos += ext4_rec_len_from_disk(de->rec_len, inline_size); - if (ext4_check_dir_entry(inode, dir_file, de, - iloc.bh, dir_buf, - inline_size, pos)) { - ret = count; - goto out; - } - } - - ext4fs_dirhash(de->name, de->name_len, hinfo); - if ((hinfo->hash < start_hash) || - ((hinfo->hash == start_hash) && - (hinfo->minor_hash < start_minor_hash))) - continue; - if (de->inode == 0) - continue; - tmp_str.name = de->name; - tmp_str.len = de->name_len; - err = ext4_htree_store_dirent(dir_file, hinfo->hash, - hinfo->minor_hash, de, &tmp_str); - if (err) { - count = err; - goto out; - } - count++; - } - ret = count; -out: - kfree(dir_buf); - brelse(iloc.bh); - return ret; -} - -/* - * So this function is called when the volume is mkfsed with - * dir_index disabled. In order to keep f_pos persistent - * after we convert from an inlined dir to a blocked based, - * we just pretend that we are a normal dir and return the - * offset as if '.' and '..' really take place. - * - */ -int ext4_read_inline_dir(struct file *file, - struct dir_context *ctx, - int *has_inline_data) -{ - unsigned int offset, parent_ino; - int i; - struct ext4_dir_entry_2 *de; - struct super_block *sb; - struct inode *inode = file_inode(file); - int ret, inline_size = 0; - struct ext4_iloc iloc; - void *dir_buf = NULL; - int dotdot_offset, dotdot_size, extra_offset, extra_size; - - ret = ext4_get_inode_loc(inode, &iloc); - if (ret) - return ret; - - down_read(&EXT4_I(inode)->xattr_sem); - if (!ext4_has_inline_data(inode)) { - up_read(&EXT4_I(inode)->xattr_sem); - *has_inline_data = 0; - goto out; - } - - inline_size = ext4_get_inline_size(inode); - dir_buf = kmalloc(inline_size, GFP_NOFS); - if (!dir_buf) { - ret = -ENOMEM; - up_read(&EXT4_I(inode)->xattr_sem); - goto out; - } - - ret = ext4_read_inline_data(inode, dir_buf, inline_size, &iloc); - up_read(&EXT4_I(inode)->xattr_sem); - if (ret < 0) - goto out; - - ret = 0; - sb = inode->i_sb; - parent_ino = le32_to_cpu(((struct ext4_dir_entry_2 *)dir_buf)->inode); - offset = ctx->pos; - - /* - * dotdot_offset and dotdot_size is the real offset and - * size for ".." and "." if the dir is block based while - * the real size for them are only EXT4_INLINE_DOTDOT_SIZE. - * So we will use extra_offset and extra_size to indicate them - * during the inline dir iteration. - */ - dotdot_offset = EXT4_DIR_REC_LEN(1); - dotdot_size = dotdot_offset + EXT4_DIR_REC_LEN(2); - extra_offset = dotdot_size - EXT4_INLINE_DOTDOT_SIZE; - extra_size = extra_offset + inline_size; - - /* - * If the version has changed since the last call to - * readdir(2), then we might be pointing to an invalid - * dirent right now. Scan from the start of the inline - * dir to make sure. - */ - if (file->f_version != inode->i_version) { - for (i = 0; i < extra_size && i < offset;) { - /* - * "." is with offset 0 and - * ".." is dotdot_offset. - */ - if (!i) { - i = dotdot_offset; - continue; - } else if (i == dotdot_offset) { - i = dotdot_size; - continue; - } - /* for other entry, the real offset in - * the buf has to be tuned accordingly. - */ - de = (struct ext4_dir_entry_2 *) - (dir_buf + i - extra_offset); - /* It's too expensive to do a full - * dirent test each time round this - * loop, but we do have to test at - * least that it is non-zero. A - * failure will be detected in the - * dirent test below. */ - if (ext4_rec_len_from_disk(de->rec_len, extra_size) - < EXT4_DIR_REC_LEN(1)) - break; - i += ext4_rec_len_from_disk(de->rec_len, - extra_size); - } - offset = i; - ctx->pos = offset; - file->f_version = inode->i_version; - } - - while (ctx->pos < extra_size) { - if (ctx->pos == 0) { - if (!dir_emit(ctx, ".", 1, inode->i_ino, DT_DIR)) - goto out; - ctx->pos = dotdot_offset; - continue; - } - - if (ctx->pos == dotdot_offset) { - if (!dir_emit(ctx, "..", 2, parent_ino, DT_DIR)) - goto out; - ctx->pos = dotdot_size; - continue; - } - - de = (struct ext4_dir_entry_2 *) - (dir_buf + ctx->pos - extra_offset); - if (ext4_check_dir_entry(inode, file, de, iloc.bh, dir_buf, - extra_size, ctx->pos)) - goto out; - if (le32_to_cpu(de->inode)) { - if (!dir_emit(ctx, de->name, de->name_len, - le32_to_cpu(de->inode), - get_dtype(sb, de->file_type))) - goto out; - } - ctx->pos += ext4_rec_len_from_disk(de->rec_len, extra_size); - } -out: - kfree(dir_buf); - brelse(iloc.bh); - return ret; -} - -struct buffer_head *ext4_get_first_inline_block(struct inode *inode, - struct ext4_dir_entry_2 **parent_de, - int *retval) -{ - struct ext4_iloc iloc; - - *retval = ext4_get_inode_loc(inode, &iloc); - if (*retval) - return NULL; - - *parent_de = (struct ext4_dir_entry_2 *)ext4_raw_inode(&iloc)->i_block; - - return iloc.bh; -} - -/* - * Try to create the inline data for the new dir. - * If it succeeds, return 0, otherwise return the error. - * In case of ENOSPC, the caller should create the normal disk layout dir. - */ -int ext4_try_create_inline_dir(handle_t *handle, struct inode *parent, - struct inode *inode) -{ - int ret, inline_size = EXT4_MIN_INLINE_DATA_SIZE; - struct ext4_iloc iloc; - struct ext4_dir_entry_2 *de; - - ret = ext4_get_inode_loc(inode, &iloc); - if (ret) - return ret; - - ret = ext4_prepare_inline_data(handle, inode, inline_size); - if (ret) - goto out; - - /* - * For inline dir, we only save the inode information for the ".." - * and create a fake dentry to cover the left space. - */ - de = (struct ext4_dir_entry_2 *)ext4_raw_inode(&iloc)->i_block; - de->inode = cpu_to_le32(parent->i_ino); - de = (struct ext4_dir_entry_2 *)((void *)de + EXT4_INLINE_DOTDOT_SIZE); - de->inode = 0; - de->rec_len = ext4_rec_len_to_disk( - inline_size - EXT4_INLINE_DOTDOT_SIZE, - inline_size); - set_nlink(inode, 2); - inode->i_size = EXT4_I(inode)->i_disksize = inline_size; -out: - brelse(iloc.bh); - return ret; -} - -struct buffer_head *ext4_find_inline_entry(struct inode *dir, - struct ext4_filename *fname, - const struct qstr *d_name, - struct ext4_dir_entry_2 **res_dir, - int *has_inline_data) -{ - int ret; - struct ext4_iloc iloc; - void *inline_start; - int inline_size; - - if (ext4_get_inode_loc(dir, &iloc)) - return NULL; - - down_read(&EXT4_I(dir)->xattr_sem); - if (!ext4_has_inline_data(dir)) { - *has_inline_data = 0; - goto out; - } - - inline_start = (void *)ext4_raw_inode(&iloc)->i_block + - EXT4_INLINE_DOTDOT_SIZE; - inline_size = EXT4_MIN_INLINE_DATA_SIZE - EXT4_INLINE_DOTDOT_SIZE; - ret = ext4_search_dir(iloc.bh, inline_start, inline_size, - dir, fname, d_name, 0, res_dir); - if (ret == 1) - goto out_find; - if (ret < 0) - goto out; - - if (ext4_get_inline_size(dir) == EXT4_MIN_INLINE_DATA_SIZE) - goto out; - - inline_start = ext4_get_inline_xattr_pos(dir, &iloc); - inline_size = ext4_get_inline_size(dir) - EXT4_MIN_INLINE_DATA_SIZE; - - ret = ext4_search_dir(iloc.bh, inline_start, inline_size, - dir, fname, d_name, 0, res_dir); - if (ret == 1) - goto out_find; - -out: - brelse(iloc.bh); - iloc.bh = NULL; -out_find: - up_read(&EXT4_I(dir)->xattr_sem); - return iloc.bh; -} - -int ext4_delete_inline_entry(handle_t *handle, - struct inode *dir, - struct ext4_dir_entry_2 *de_del, - struct buffer_head *bh, - int *has_inline_data) -{ - int err, inline_size; - struct ext4_iloc iloc; - void *inline_start; - - err = ext4_get_inode_loc(dir, &iloc); - if (err) - return err; - - down_write(&EXT4_I(dir)->xattr_sem); - if (!ext4_has_inline_data(dir)) { - *has_inline_data = 0; - goto out; - } - - if ((void *)de_del - ((void *)ext4_raw_inode(&iloc)->i_block) < - EXT4_MIN_INLINE_DATA_SIZE) { - inline_start = (void *)ext4_raw_inode(&iloc)->i_block + - EXT4_INLINE_DOTDOT_SIZE; - inline_size = EXT4_MIN_INLINE_DATA_SIZE - - EXT4_INLINE_DOTDOT_SIZE; - } else { - inline_start = ext4_get_inline_xattr_pos(dir, &iloc); - inline_size = ext4_get_inline_size(dir) - - EXT4_MIN_INLINE_DATA_SIZE; - } - - BUFFER_TRACE(bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, bh); - if (err) - goto out; - - err = ext4_generic_delete_entry(handle, dir, de_del, bh, - inline_start, inline_size, 0); - if (err) - goto out; - - err = ext4_mark_inode_dirty(handle, dir); - if (unlikely(err)) - goto out; - - ext4_show_inline_dir(dir, iloc.bh, inline_start, inline_size); -out: - up_write(&EXT4_I(dir)->xattr_sem); - brelse(iloc.bh); - if (err != -ENOENT) - ext4_std_error(dir->i_sb, err); - return err; -} - -/* - * Get the inline dentry at offset. - */ -static inline struct ext4_dir_entry_2 * -ext4_get_inline_entry(struct inode *inode, - struct ext4_iloc *iloc, - unsigned int offset, - void **inline_start, - int *inline_size) -{ - void *inline_pos; - - BUG_ON(offset > ext4_get_inline_size(inode)); - - if (offset < EXT4_MIN_INLINE_DATA_SIZE) { - inline_pos = (void *)ext4_raw_inode(iloc)->i_block; - *inline_size = EXT4_MIN_INLINE_DATA_SIZE; - } else { - inline_pos = ext4_get_inline_xattr_pos(inode, iloc); - offset -= EXT4_MIN_INLINE_DATA_SIZE; - *inline_size = ext4_get_inline_size(inode) - - EXT4_MIN_INLINE_DATA_SIZE; - } - - if (inline_start) - *inline_start = inline_pos; - return (struct ext4_dir_entry_2 *)(inline_pos + offset); -} - -bool empty_inline_dir(struct inode *dir, int *has_inline_data) -{ - int err, inline_size; - struct ext4_iloc iloc; - void *inline_pos; - unsigned int offset; - struct ext4_dir_entry_2 *de; - bool ret = true; - - err = ext4_get_inode_loc(dir, &iloc); - if (err) { - EXT4_ERROR_INODE(dir, "error %d getting inode %lu block", - err, dir->i_ino); - return true; - } - - down_read(&EXT4_I(dir)->xattr_sem); - if (!ext4_has_inline_data(dir)) { - *has_inline_data = 0; - goto out; - } - - de = (struct ext4_dir_entry_2 *)ext4_raw_inode(&iloc)->i_block; - if (!le32_to_cpu(de->inode)) { - ext4_warning(dir->i_sb, - "bad inline directory (dir #%lu) - no `..'", - dir->i_ino); - ret = true; - goto out; - } - - offset = EXT4_INLINE_DOTDOT_SIZE; - while (offset < dir->i_size) { - de = ext4_get_inline_entry(dir, &iloc, offset, - &inline_pos, &inline_size); - if (ext4_check_dir_entry(dir, NULL, de, - iloc.bh, inline_pos, - inline_size, offset)) { - ext4_warning(dir->i_sb, - "bad inline directory (dir #%lu) - " - "inode %u, rec_len %u, name_len %d" - "inline size %d", - dir->i_ino, le32_to_cpu(de->inode), - le16_to_cpu(de->rec_len), de->name_len, - inline_size); - ret = true; - goto out; - } - if (le32_to_cpu(de->inode)) { - ret = false; - goto out; - } - offset += ext4_rec_len_from_disk(de->rec_len, inline_size); - } - -out: - up_read(&EXT4_I(dir)->xattr_sem); - brelse(iloc.bh); - return ret; -} - -int ext4_destroy_inline_data(handle_t *handle, struct inode *inode) -{ - int ret; - - down_write(&EXT4_I(inode)->xattr_sem); - ret = ext4_destroy_inline_data_nolock(handle, inode); - up_write(&EXT4_I(inode)->xattr_sem); - - return ret; -} - -int ext4_inline_data_fiemap(struct inode *inode, - struct fiemap_extent_info *fieinfo, - int *has_inline, __u64 start, __u64 len) -{ - __u64 physical = 0; - __u64 inline_len; - __u32 flags = FIEMAP_EXTENT_DATA_INLINE | FIEMAP_EXTENT_NOT_ALIGNED | - FIEMAP_EXTENT_LAST; - int error = 0; - struct ext4_iloc iloc; - - down_read(&EXT4_I(inode)->xattr_sem); - if (!ext4_has_inline_data(inode)) { - *has_inline = 0; - goto out; - } - inline_len = min_t(size_t, ext4_get_inline_size(inode), - i_size_read(inode)); - if (start >= inline_len) - goto out; - if (start + len < inline_len) - inline_len = start + len; - inline_len -= start; - - error = ext4_get_inode_loc(inode, &iloc); - if (error) - goto out; - - physical = (__u64)iloc.bh->b_blocknr << inode->i_sb->s_blocksize_bits; - physical += (char *)ext4_raw_inode(&iloc) - iloc.bh->b_data; - physical += offsetof(struct ext4_inode, i_block); - - if (physical) - error = fiemap_fill_next_extent(fieinfo, start, physical, - inline_len, flags); - brelse(iloc.bh); -out: - up_read(&EXT4_I(inode)->xattr_sem); - return (error < 0 ? error : 0); -} - -/* - * Called during xattr set, and if we can sparse space 'needed', - * just create the extent tree evict the data to the outer block. - * - * We use jbd2 instead of page cache to move data to the 1st block - * so that the whole transaction can be committed as a whole and - * the data isn't lost because of the delayed page cache write. - */ -int ext4_try_to_evict_inline_data(handle_t *handle, - struct inode *inode, - int needed) -{ - int error; - struct ext4_xattr_entry *entry; - struct ext4_inode *raw_inode; - struct ext4_iloc iloc; - - error = ext4_get_inode_loc(inode, &iloc); - if (error) - return error; - - raw_inode = ext4_raw_inode(&iloc); - entry = (struct ext4_xattr_entry *)((void *)raw_inode + - EXT4_I(inode)->i_inline_off); - if (EXT4_XATTR_LEN(entry->e_name_len) + - EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size)) < needed) { - error = -ENOSPC; - goto out; - } - - error = ext4_convert_inline_data_nolock(handle, inode, &iloc); -out: - brelse(iloc.bh); - return error; -} - -void ext4_inline_data_truncate(struct inode *inode, int *has_inline) -{ - handle_t *handle; - int inline_size, value_len, needed_blocks; - size_t i_size; - void *value = NULL; - struct ext4_xattr_ibody_find is = { - .s = { .not_found = -ENODATA, }, - }; - struct ext4_xattr_info i = { - .name_index = EXT4_XATTR_INDEX_SYSTEM, - .name = EXT4_XATTR_SYSTEM_DATA, - }; - - - needed_blocks = ext4_writepage_trans_blocks(inode); - handle = ext4_journal_start(inode, EXT4_HT_INODE, needed_blocks); - if (IS_ERR(handle)) - return; - - down_write(&EXT4_I(inode)->xattr_sem); - if (!ext4_has_inline_data(inode)) { - *has_inline = 0; - ext4_journal_stop(handle); - return; - } - - if (ext4_orphan_add(handle, inode)) - goto out; - - if (ext4_get_inode_loc(inode, &is.iloc)) - goto out; - - down_write(&EXT4_I(inode)->i_data_sem); - i_size = inode->i_size; - inline_size = ext4_get_inline_size(inode); - EXT4_I(inode)->i_disksize = i_size; - - if (i_size < inline_size) { - /* Clear the content in the xattr space. */ - if (inline_size > EXT4_MIN_INLINE_DATA_SIZE) { - if (ext4_xattr_ibody_find(inode, &i, &is)) - goto out_error; - - BUG_ON(is.s.not_found); - - value_len = le32_to_cpu(is.s.here->e_value_size); - value = kmalloc(value_len, GFP_NOFS); - if (!value) - goto out_error; - - if (ext4_xattr_ibody_get(inode, i.name_index, i.name, - value, value_len)) - goto out_error; - - i.value = value; - i.value_len = i_size > EXT4_MIN_INLINE_DATA_SIZE ? - i_size - EXT4_MIN_INLINE_DATA_SIZE : 0; - if (ext4_xattr_ibody_inline_set(handle, inode, &i, &is)) - goto out_error; - } - - /* Clear the content within i_blocks. */ - if (i_size < EXT4_MIN_INLINE_DATA_SIZE) { - void *p = (void *) ext4_raw_inode(&is.iloc)->i_block; - memset(p + i_size, 0, - EXT4_MIN_INLINE_DATA_SIZE - i_size); - } - - EXT4_I(inode)->i_inline_size = i_size < - EXT4_MIN_INLINE_DATA_SIZE ? - EXT4_MIN_INLINE_DATA_SIZE : i_size; - } - -out_error: - up_write(&EXT4_I(inode)->i_data_sem); -out: - brelse(is.iloc.bh); - up_write(&EXT4_I(inode)->xattr_sem); - kfree(value); - if (inode->i_nlink) - ext4_orphan_del(handle, inode); - - inode->i_mtime = inode->i_ctime = ext4_current_time(inode); - ext4_mark_inode_dirty(handle, inode); - if (IS_SYNC(inode)) - ext4_handle_sync(handle); - - ext4_journal_stop(handle); - return; -} - -int ext4_convert_inline_data(struct inode *inode) -{ - int error, needed_blocks; - handle_t *handle; - struct ext4_iloc iloc; - - if (!ext4_has_inline_data(inode)) { - ext4_clear_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA); - return 0; - } - - needed_blocks = ext4_writepage_trans_blocks(inode); - - iloc.bh = NULL; - error = ext4_get_inode_loc(inode, &iloc); - if (error) - return error; - - handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, needed_blocks); - if (IS_ERR(handle)) { - error = PTR_ERR(handle); - goto out_free; - } - - down_write(&EXT4_I(inode)->xattr_sem); - if (!ext4_has_inline_data(inode)) { - up_write(&EXT4_I(inode)->xattr_sem); - goto out; - } - - error = ext4_convert_inline_data_nolock(handle, inode, &iloc); - up_write(&EXT4_I(inode)->xattr_sem); -out: - ext4_journal_stop(handle); -out_free: - brelse(iloc.bh); - return error; -} diff --git a/src/linux/fs/ext4/inode.c b/src/linux/fs/ext4/inode.c deleted file mode 100644 index 9c06472..0000000 --- a/src/linux/fs/ext4/inode.c +++ /dev/null @@ -1,5818 +0,0 @@ -/* - * linux/fs/ext4/inode.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/inode.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * 64-bit file support on 64-bit platforms by Jakub Jelinek - * (jj@sunsite.ms.mff.cuni.cz) - * - * Assorted race fixes, rewrite of ext4_get_block() by Al Viro, 2000 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ext4_jbd2.h" -#include "xattr.h" -#include "acl.h" -#include "truncate.h" - -#include - -#define MPAGE_DA_EXTENT_TAIL 0x01 - -static __u32 ext4_inode_csum(struct inode *inode, struct ext4_inode *raw, - struct ext4_inode_info *ei) -{ - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - __u32 csum; - __u16 dummy_csum = 0; - int offset = offsetof(struct ext4_inode, i_checksum_lo); - unsigned int csum_size = sizeof(dummy_csum); - - csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)raw, offset); - csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum, csum_size); - offset += csum_size; - csum = ext4_chksum(sbi, csum, (__u8 *)raw + offset, - EXT4_GOOD_OLD_INODE_SIZE - offset); - - if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) { - offset = offsetof(struct ext4_inode, i_checksum_hi); - csum = ext4_chksum(sbi, csum, (__u8 *)raw + - EXT4_GOOD_OLD_INODE_SIZE, - offset - EXT4_GOOD_OLD_INODE_SIZE); - if (EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi)) { - csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum, - csum_size); - offset += csum_size; - csum = ext4_chksum(sbi, csum, (__u8 *)raw + offset, - EXT4_INODE_SIZE(inode->i_sb) - - offset); - } - } - - return csum; -} - -static int ext4_inode_csum_verify(struct inode *inode, struct ext4_inode *raw, - struct ext4_inode_info *ei) -{ - __u32 provided, calculated; - - if (EXT4_SB(inode->i_sb)->s_es->s_creator_os != - cpu_to_le32(EXT4_OS_LINUX) || - !ext4_has_metadata_csum(inode->i_sb)) - return 1; - - provided = le16_to_cpu(raw->i_checksum_lo); - calculated = ext4_inode_csum(inode, raw, ei); - if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE && - EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi)) - provided |= ((__u32)le16_to_cpu(raw->i_checksum_hi)) << 16; - else - calculated &= 0xFFFF; - - return provided == calculated; -} - -static void ext4_inode_csum_set(struct inode *inode, struct ext4_inode *raw, - struct ext4_inode_info *ei) -{ - __u32 csum; - - if (EXT4_SB(inode->i_sb)->s_es->s_creator_os != - cpu_to_le32(EXT4_OS_LINUX) || - !ext4_has_metadata_csum(inode->i_sb)) - return; - - csum = ext4_inode_csum(inode, raw, ei); - raw->i_checksum_lo = cpu_to_le16(csum & 0xFFFF); - if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE && - EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi)) - raw->i_checksum_hi = cpu_to_le16(csum >> 16); -} - -static inline int ext4_begin_ordered_truncate(struct inode *inode, - loff_t new_size) -{ - trace_ext4_begin_ordered_truncate(inode, new_size); - /* - * If jinode is zero, then we never opened the file for - * writing, so there's no need to call - * jbd2_journal_begin_ordered_truncate() since there's no - * outstanding writes we need to flush. - */ - if (!EXT4_I(inode)->jinode) - return 0; - return jbd2_journal_begin_ordered_truncate(EXT4_JOURNAL(inode), - EXT4_I(inode)->jinode, - new_size); -} - -static void ext4_invalidatepage(struct page *page, unsigned int offset, - unsigned int length); -static int __ext4_journalled_writepage(struct page *page, unsigned int len); -static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh); -static int ext4_meta_trans_blocks(struct inode *inode, int lblocks, - int pextents); - -/* - * Test whether an inode is a fast symlink. - */ -int ext4_inode_is_fast_symlink(struct inode *inode) -{ - int ea_blocks = EXT4_I(inode)->i_file_acl ? - EXT4_CLUSTER_SIZE(inode->i_sb) >> 9 : 0; - - if (ext4_has_inline_data(inode)) - return 0; - - return (S_ISLNK(inode->i_mode) && inode->i_blocks - ea_blocks == 0); -} - -/* - * Restart the transaction associated with *handle. This does a commit, - * so before we call here everything must be consistently dirtied against - * this transaction. - */ -int ext4_truncate_restart_trans(handle_t *handle, struct inode *inode, - int nblocks) -{ - int ret; - - /* - * Drop i_data_sem to avoid deadlock with ext4_map_blocks. At this - * moment, get_block can be called only for blocks inside i_size since - * page cache has been already dropped and writes are blocked by - * i_mutex. So we can safely drop the i_data_sem here. - */ - BUG_ON(EXT4_JOURNAL(inode) == NULL); - jbd_debug(2, "restarting handle %p\n", handle); - up_write(&EXT4_I(inode)->i_data_sem); - ret = ext4_journal_restart(handle, nblocks); - down_write(&EXT4_I(inode)->i_data_sem); - ext4_discard_preallocations(inode); - - return ret; -} - -/* - * Called at the last iput() if i_nlink is zero. - */ -void ext4_evict_inode(struct inode *inode) -{ - handle_t *handle; - int err; - - trace_ext4_evict_inode(inode); - - if (inode->i_nlink) { - /* - * When journalling data dirty buffers are tracked only in the - * journal. So although mm thinks everything is clean and - * ready for reaping the inode might still have some pages to - * write in the running transaction or waiting to be - * checkpointed. Thus calling jbd2_journal_invalidatepage() - * (via truncate_inode_pages()) to discard these buffers can - * cause data loss. Also even if we did not discard these - * buffers, we would have no way to find them after the inode - * is reaped and thus user could see stale data if he tries to - * read them before the transaction is checkpointed. So be - * careful and force everything to disk here... We use - * ei->i_datasync_tid to store the newest transaction - * containing inode's data. - * - * Note that directories do not have this problem because they - * don't use page cache. - */ - if (inode->i_ino != EXT4_JOURNAL_INO && - ext4_should_journal_data(inode) && - (S_ISLNK(inode->i_mode) || S_ISREG(inode->i_mode))) { - journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; - tid_t commit_tid = EXT4_I(inode)->i_datasync_tid; - - jbd2_complete_transaction(journal, commit_tid); - filemap_write_and_wait(&inode->i_data); - } - truncate_inode_pages_final(&inode->i_data); - - goto no_delete; - } - - if (is_bad_inode(inode)) - goto no_delete; - dquot_initialize(inode); - - if (ext4_should_order_data(inode)) - ext4_begin_ordered_truncate(inode, 0); - truncate_inode_pages_final(&inode->i_data); - - /* - * Protect us against freezing - iput() caller didn't have to have any - * protection against it - */ - sb_start_intwrite(inode->i_sb); - handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, - ext4_blocks_for_truncate(inode)+3); - if (IS_ERR(handle)) { - ext4_std_error(inode->i_sb, PTR_ERR(handle)); - /* - * If we're going to skip the normal cleanup, we still need to - * make sure that the in-core orphan linked list is properly - * cleaned up. - */ - ext4_orphan_del(NULL, inode); - sb_end_intwrite(inode->i_sb); - goto no_delete; - } - - if (IS_SYNC(inode)) - ext4_handle_sync(handle); - inode->i_size = 0; - err = ext4_mark_inode_dirty(handle, inode); - if (err) { - ext4_warning(inode->i_sb, - "couldn't mark inode dirty (err %d)", err); - goto stop_handle; - } - if (inode->i_blocks) - ext4_truncate(inode); - - /* - * ext4_ext_truncate() doesn't reserve any slop when it - * restarts journal transactions; therefore there may not be - * enough credits left in the handle to remove the inode from - * the orphan list and set the dtime field. - */ - if (!ext4_handle_has_enough_credits(handle, 3)) { - err = ext4_journal_extend(handle, 3); - if (err > 0) - err = ext4_journal_restart(handle, 3); - if (err != 0) { - ext4_warning(inode->i_sb, - "couldn't extend journal (err %d)", err); - stop_handle: - ext4_journal_stop(handle); - ext4_orphan_del(NULL, inode); - sb_end_intwrite(inode->i_sb); - goto no_delete; - } - } - - /* - * Kill off the orphan record which ext4_truncate created. - * AKPM: I think this can be inside the above `if'. - * Note that ext4_orphan_del() has to be able to cope with the - * deletion of a non-existent orphan - this is because we don't - * know if ext4_truncate() actually created an orphan record. - * (Well, we could do this if we need to, but heck - it works) - */ - ext4_orphan_del(handle, inode); - EXT4_I(inode)->i_dtime = get_seconds(); - - /* - * One subtle ordering requirement: if anything has gone wrong - * (transaction abort, IO errors, whatever), then we can still - * do these next steps (the fs will already have been marked as - * having errors), but we can't free the inode if the mark_dirty - * fails. - */ - if (ext4_mark_inode_dirty(handle, inode)) - /* If that failed, just do the required in-core inode clear. */ - ext4_clear_inode(inode); - else - ext4_free_inode(handle, inode); - ext4_journal_stop(handle); - sb_end_intwrite(inode->i_sb); - return; -no_delete: - ext4_clear_inode(inode); /* We must guarantee clearing of inode... */ -} - -#ifdef CONFIG_QUOTA -qsize_t *ext4_get_reserved_space(struct inode *inode) -{ - return &EXT4_I(inode)->i_reserved_quota; -} -#endif - -/* - * Called with i_data_sem down, which is important since we can call - * ext4_discard_preallocations() from here. - */ -void ext4_da_update_reserve_space(struct inode *inode, - int used, int quota_claim) -{ - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - struct ext4_inode_info *ei = EXT4_I(inode); - - spin_lock(&ei->i_block_reservation_lock); - trace_ext4_da_update_reserve_space(inode, used, quota_claim); - if (unlikely(used > ei->i_reserved_data_blocks)) { - ext4_warning(inode->i_sb, "%s: ino %lu, used %d " - "with only %d reserved data blocks", - __func__, inode->i_ino, used, - ei->i_reserved_data_blocks); - WARN_ON(1); - used = ei->i_reserved_data_blocks; - } - - /* Update per-inode reservations */ - ei->i_reserved_data_blocks -= used; - percpu_counter_sub(&sbi->s_dirtyclusters_counter, used); - - spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); - - /* Update quota subsystem for data blocks */ - if (quota_claim) - dquot_claim_block(inode, EXT4_C2B(sbi, used)); - else { - /* - * We did fallocate with an offset that is already delayed - * allocated. So on delayed allocated writeback we should - * not re-claim the quota for fallocated blocks. - */ - dquot_release_reservation_block(inode, EXT4_C2B(sbi, used)); - } - - /* - * If we have done all the pending block allocations and if - * there aren't any writers on the inode, we can discard the - * inode's preallocations. - */ - if ((ei->i_reserved_data_blocks == 0) && - (atomic_read(&inode->i_writecount) == 0)) - ext4_discard_preallocations(inode); -} - -static int __check_block_validity(struct inode *inode, const char *func, - unsigned int line, - struct ext4_map_blocks *map) -{ - if (!ext4_data_block_valid(EXT4_SB(inode->i_sb), map->m_pblk, - map->m_len)) { - ext4_error_inode(inode, func, line, map->m_pblk, - "lblock %lu mapped to illegal pblock " - "(length %d)", (unsigned long) map->m_lblk, - map->m_len); - return -EFSCORRUPTED; - } - return 0; -} - -int ext4_issue_zeroout(struct inode *inode, ext4_lblk_t lblk, ext4_fsblk_t pblk, - ext4_lblk_t len) -{ - int ret; - - if (ext4_encrypted_inode(inode)) - return fscrypt_zeroout_range(inode, lblk, pblk, len); - - ret = sb_issue_zeroout(inode->i_sb, pblk, len, GFP_NOFS); - if (ret > 0) - ret = 0; - - return ret; -} - -#define check_block_validity(inode, map) \ - __check_block_validity((inode), __func__, __LINE__, (map)) - -#ifdef ES_AGGRESSIVE_TEST -static void ext4_map_blocks_es_recheck(handle_t *handle, - struct inode *inode, - struct ext4_map_blocks *es_map, - struct ext4_map_blocks *map, - int flags) -{ - int retval; - - map->m_flags = 0; - /* - * There is a race window that the result is not the same. - * e.g. xfstests #223 when dioread_nolock enables. The reason - * is that we lookup a block mapping in extent status tree with - * out taking i_data_sem. So at the time the unwritten extent - * could be converted. - */ - down_read(&EXT4_I(inode)->i_data_sem); - if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) { - retval = ext4_ext_map_blocks(handle, inode, map, flags & - EXT4_GET_BLOCKS_KEEP_SIZE); - } else { - retval = ext4_ind_map_blocks(handle, inode, map, flags & - EXT4_GET_BLOCKS_KEEP_SIZE); - } - up_read((&EXT4_I(inode)->i_data_sem)); - - /* - * We don't check m_len because extent will be collpased in status - * tree. So the m_len might not equal. - */ - if (es_map->m_lblk != map->m_lblk || - es_map->m_flags != map->m_flags || - es_map->m_pblk != map->m_pblk) { - printk("ES cache assertion failed for inode: %lu " - "es_cached ex [%d/%d/%llu/%x] != " - "found ex [%d/%d/%llu/%x] retval %d flags %x\n", - inode->i_ino, es_map->m_lblk, es_map->m_len, - es_map->m_pblk, es_map->m_flags, map->m_lblk, - map->m_len, map->m_pblk, map->m_flags, - retval, flags); - } -} -#endif /* ES_AGGRESSIVE_TEST */ - -/* - * The ext4_map_blocks() function tries to look up the requested blocks, - * and returns if the blocks are already mapped. - * - * Otherwise it takes the write lock of the i_data_sem and allocate blocks - * and store the allocated blocks in the result buffer head and mark it - * mapped. - * - * If file type is extents based, it will call ext4_ext_map_blocks(), - * Otherwise, call with ext4_ind_map_blocks() to handle indirect mapping - * based files - * - * On success, it returns the number of blocks being mapped or allocated. if - * create==0 and the blocks are pre-allocated and unwritten, the resulting @map - * is marked as unwritten. If the create == 1, it will mark @map as mapped. - * - * It returns 0 if plain look up failed (blocks have not been allocated), in - * that case, @map is returned as unmapped but we still do fill map->m_len to - * indicate the length of a hole starting at map->m_lblk. - * - * It returns the error in case of allocation failure. - */ -int ext4_map_blocks(handle_t *handle, struct inode *inode, - struct ext4_map_blocks *map, int flags) -{ - struct extent_status es; - int retval; - int ret = 0; -#ifdef ES_AGGRESSIVE_TEST - struct ext4_map_blocks orig_map; - - memcpy(&orig_map, map, sizeof(*map)); -#endif - - map->m_flags = 0; - ext_debug("ext4_map_blocks(): inode %lu, flag %d, max_blocks %u," - "logical block %lu\n", inode->i_ino, flags, map->m_len, - (unsigned long) map->m_lblk); - - /* - * ext4_map_blocks returns an int, and m_len is an unsigned int - */ - if (unlikely(map->m_len > INT_MAX)) - map->m_len = INT_MAX; - - /* We can handle the block number less than EXT_MAX_BLOCKS */ - if (unlikely(map->m_lblk >= EXT_MAX_BLOCKS)) - return -EFSCORRUPTED; - - /* Lookup extent status tree firstly */ - if (ext4_es_lookup_extent(inode, map->m_lblk, &es)) { - if (ext4_es_is_written(&es) || ext4_es_is_unwritten(&es)) { - map->m_pblk = ext4_es_pblock(&es) + - map->m_lblk - es.es_lblk; - map->m_flags |= ext4_es_is_written(&es) ? - EXT4_MAP_MAPPED : EXT4_MAP_UNWRITTEN; - retval = es.es_len - (map->m_lblk - es.es_lblk); - if (retval > map->m_len) - retval = map->m_len; - map->m_len = retval; - } else if (ext4_es_is_delayed(&es) || ext4_es_is_hole(&es)) { - map->m_pblk = 0; - retval = es.es_len - (map->m_lblk - es.es_lblk); - if (retval > map->m_len) - retval = map->m_len; - map->m_len = retval; - retval = 0; - } else { - BUG_ON(1); - } -#ifdef ES_AGGRESSIVE_TEST - ext4_map_blocks_es_recheck(handle, inode, map, - &orig_map, flags); -#endif - goto found; - } - - /* - * Try to see if we can get the block without requesting a new - * file system block. - */ - down_read(&EXT4_I(inode)->i_data_sem); - if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) { - retval = ext4_ext_map_blocks(handle, inode, map, flags & - EXT4_GET_BLOCKS_KEEP_SIZE); - } else { - retval = ext4_ind_map_blocks(handle, inode, map, flags & - EXT4_GET_BLOCKS_KEEP_SIZE); - } - if (retval > 0) { - unsigned int status; - - if (unlikely(retval != map->m_len)) { - ext4_warning(inode->i_sb, - "ES len assertion failed for inode " - "%lu: retval %d != map->m_len %d", - inode->i_ino, retval, map->m_len); - WARN_ON(1); - } - - status = map->m_flags & EXT4_MAP_UNWRITTEN ? - EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; - if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) && - !(status & EXTENT_STATUS_WRITTEN) && - ext4_find_delalloc_range(inode, map->m_lblk, - map->m_lblk + map->m_len - 1)) - status |= EXTENT_STATUS_DELAYED; - ret = ext4_es_insert_extent(inode, map->m_lblk, - map->m_len, map->m_pblk, status); - if (ret < 0) - retval = ret; - } - up_read((&EXT4_I(inode)->i_data_sem)); - -found: - if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) { - ret = check_block_validity(inode, map); - if (ret != 0) - return ret; - } - - /* If it is only a block(s) look up */ - if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) - return retval; - - /* - * Returns if the blocks have already allocated - * - * Note that if blocks have been preallocated - * ext4_ext_get_block() returns the create = 0 - * with buffer head unmapped. - */ - if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) - /* - * If we need to convert extent to unwritten - * we continue and do the actual work in - * ext4_ext_map_blocks() - */ - if (!(flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN)) - return retval; - - /* - * Here we clear m_flags because after allocating an new extent, - * it will be set again. - */ - map->m_flags &= ~EXT4_MAP_FLAGS; - - /* - * New blocks allocate and/or writing to unwritten extent - * will possibly result in updating i_data, so we take - * the write lock of i_data_sem, and call get_block() - * with create == 1 flag. - */ - down_write(&EXT4_I(inode)->i_data_sem); - - /* - * We need to check for EXT4 here because migrate - * could have changed the inode type in between - */ - if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) { - retval = ext4_ext_map_blocks(handle, inode, map, flags); - } else { - retval = ext4_ind_map_blocks(handle, inode, map, flags); - - if (retval > 0 && map->m_flags & EXT4_MAP_NEW) { - /* - * We allocated new blocks which will result in - * i_data's format changing. Force the migrate - * to fail by clearing migrate flags - */ - ext4_clear_inode_state(inode, EXT4_STATE_EXT_MIGRATE); - } - - /* - * Update reserved blocks/metadata blocks after successful - * block allocation which had been deferred till now. We don't - * support fallocate for non extent files. So we can update - * reserve space here. - */ - if ((retval > 0) && - (flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE)) - ext4_da_update_reserve_space(inode, retval, 1); - } - - if (retval > 0) { - unsigned int status; - - if (unlikely(retval != map->m_len)) { - ext4_warning(inode->i_sb, - "ES len assertion failed for inode " - "%lu: retval %d != map->m_len %d", - inode->i_ino, retval, map->m_len); - WARN_ON(1); - } - - /* - * We have to zeroout blocks before inserting them into extent - * status tree. Otherwise someone could look them up there and - * use them before they are really zeroed. We also have to - * unmap metadata before zeroing as otherwise writeback can - * overwrite zeros with stale data from block device. - */ - if (flags & EXT4_GET_BLOCKS_ZERO && - map->m_flags & EXT4_MAP_MAPPED && - map->m_flags & EXT4_MAP_NEW) { - ext4_lblk_t i; - - for (i = 0; i < map->m_len; i++) { - unmap_underlying_metadata(inode->i_sb->s_bdev, - map->m_pblk + i); - } - ret = ext4_issue_zeroout(inode, map->m_lblk, - map->m_pblk, map->m_len); - if (ret) { - retval = ret; - goto out_sem; - } - } - - /* - * If the extent has been zeroed out, we don't need to update - * extent status tree. - */ - if ((flags & EXT4_GET_BLOCKS_PRE_IO) && - ext4_es_lookup_extent(inode, map->m_lblk, &es)) { - if (ext4_es_is_written(&es)) - goto out_sem; - } - status = map->m_flags & EXT4_MAP_UNWRITTEN ? - EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; - if (!(flags & EXT4_GET_BLOCKS_DELALLOC_RESERVE) && - !(status & EXTENT_STATUS_WRITTEN) && - ext4_find_delalloc_range(inode, map->m_lblk, - map->m_lblk + map->m_len - 1)) - status |= EXTENT_STATUS_DELAYED; - ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len, - map->m_pblk, status); - if (ret < 0) { - retval = ret; - goto out_sem; - } - } - -out_sem: - up_write((&EXT4_I(inode)->i_data_sem)); - if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) { - ret = check_block_validity(inode, map); - if (ret != 0) - return ret; - - /* - * Inodes with freshly allocated blocks where contents will be - * visible after transaction commit must be on transaction's - * ordered data list. - */ - if (map->m_flags & EXT4_MAP_NEW && - !(map->m_flags & EXT4_MAP_UNWRITTEN) && - !(flags & EXT4_GET_BLOCKS_ZERO) && - !IS_NOQUOTA(inode) && - ext4_should_order_data(inode)) { - if (flags & EXT4_GET_BLOCKS_IO_SUBMIT) - ret = ext4_jbd2_inode_add_wait(handle, inode); - else - ret = ext4_jbd2_inode_add_write(handle, inode); - if (ret) - return ret; - } - } - return retval; -} - -/* - * Update EXT4_MAP_FLAGS in bh->b_state. For buffer heads attached to pages - * we have to be careful as someone else may be manipulating b_state as well. - */ -static void ext4_update_bh_state(struct buffer_head *bh, unsigned long flags) -{ - unsigned long old_state; - unsigned long new_state; - - flags &= EXT4_MAP_FLAGS; - - /* Dummy buffer_head? Set non-atomically. */ - if (!bh->b_page) { - bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | flags; - return; - } - /* - * Someone else may be modifying b_state. Be careful! This is ugly but - * once we get rid of using bh as a container for mapping information - * to pass to / from get_block functions, this can go away. - */ - do { - old_state = READ_ONCE(bh->b_state); - new_state = (old_state & ~EXT4_MAP_FLAGS) | flags; - } while (unlikely( - cmpxchg(&bh->b_state, old_state, new_state) != old_state)); -} - -static int _ext4_get_block(struct inode *inode, sector_t iblock, - struct buffer_head *bh, int flags) -{ - struct ext4_map_blocks map; - int ret = 0; - - if (ext4_has_inline_data(inode)) - return -ERANGE; - - map.m_lblk = iblock; - map.m_len = bh->b_size >> inode->i_blkbits; - - ret = ext4_map_blocks(ext4_journal_current_handle(), inode, &map, - flags); - if (ret > 0) { - map_bh(bh, inode->i_sb, map.m_pblk); - ext4_update_bh_state(bh, map.m_flags); - bh->b_size = inode->i_sb->s_blocksize * map.m_len; - ret = 0; - } - return ret; -} - -int ext4_get_block(struct inode *inode, sector_t iblock, - struct buffer_head *bh, int create) -{ - return _ext4_get_block(inode, iblock, bh, - create ? EXT4_GET_BLOCKS_CREATE : 0); -} - -/* - * Get block function used when preparing for buffered write if we require - * creating an unwritten extent if blocks haven't been allocated. The extent - * will be converted to written after the IO is complete. - */ -int ext4_get_block_unwritten(struct inode *inode, sector_t iblock, - struct buffer_head *bh_result, int create) -{ - ext4_debug("ext4_get_block_unwritten: inode %lu, create flag %d\n", - inode->i_ino, create); - return _ext4_get_block(inode, iblock, bh_result, - EXT4_GET_BLOCKS_IO_CREATE_EXT); -} - -/* Maximum number of blocks we map for direct IO at once. */ -#define DIO_MAX_BLOCKS 4096 - -/* - * Get blocks function for the cases that need to start a transaction - - * generally difference cases of direct IO and DAX IO. It also handles retries - * in case of ENOSPC. - */ -static int ext4_get_block_trans(struct inode *inode, sector_t iblock, - struct buffer_head *bh_result, int flags) -{ - int dio_credits; - handle_t *handle; - int retries = 0; - int ret; - - /* Trim mapping request to maximum we can map at once for DIO */ - if (bh_result->b_size >> inode->i_blkbits > DIO_MAX_BLOCKS) - bh_result->b_size = DIO_MAX_BLOCKS << inode->i_blkbits; - dio_credits = ext4_chunk_trans_blocks(inode, - bh_result->b_size >> inode->i_blkbits); -retry: - handle = ext4_journal_start(inode, EXT4_HT_MAP_BLOCKS, dio_credits); - if (IS_ERR(handle)) - return PTR_ERR(handle); - - ret = _ext4_get_block(inode, iblock, bh_result, flags); - ext4_journal_stop(handle); - - if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) - goto retry; - return ret; -} - -/* Get block function for DIO reads and writes to inodes without extents */ -int ext4_dio_get_block(struct inode *inode, sector_t iblock, - struct buffer_head *bh, int create) -{ - /* We don't expect handle for direct IO */ - WARN_ON_ONCE(ext4_journal_current_handle()); - - if (!create) - return _ext4_get_block(inode, iblock, bh, 0); - return ext4_get_block_trans(inode, iblock, bh, EXT4_GET_BLOCKS_CREATE); -} - -/* - * Get block function for AIO DIO writes when we create unwritten extent if - * blocks are not allocated yet. The extent will be converted to written - * after IO is complete. - */ -static int ext4_dio_get_block_unwritten_async(struct inode *inode, - sector_t iblock, struct buffer_head *bh_result, int create) -{ - int ret; - - /* We don't expect handle for direct IO */ - WARN_ON_ONCE(ext4_journal_current_handle()); - - ret = ext4_get_block_trans(inode, iblock, bh_result, - EXT4_GET_BLOCKS_IO_CREATE_EXT); - - /* - * When doing DIO using unwritten extents, we need io_end to convert - * unwritten extents to written on IO completion. We allocate io_end - * once we spot unwritten extent and store it in b_private. Generic - * DIO code keeps b_private set and furthermore passes the value to - * our completion callback in 'private' argument. - */ - if (!ret && buffer_unwritten(bh_result)) { - if (!bh_result->b_private) { - ext4_io_end_t *io_end; - - io_end = ext4_init_io_end(inode, GFP_KERNEL); - if (!io_end) - return -ENOMEM; - bh_result->b_private = io_end; - ext4_set_io_unwritten_flag(inode, io_end); - } - set_buffer_defer_completion(bh_result); - } - - return ret; -} - -/* - * Get block function for non-AIO DIO writes when we create unwritten extent if - * blocks are not allocated yet. The extent will be converted to written - * after IO is complete from ext4_ext_direct_IO() function. - */ -static int ext4_dio_get_block_unwritten_sync(struct inode *inode, - sector_t iblock, struct buffer_head *bh_result, int create) -{ - int ret; - - /* We don't expect handle for direct IO */ - WARN_ON_ONCE(ext4_journal_current_handle()); - - ret = ext4_get_block_trans(inode, iblock, bh_result, - EXT4_GET_BLOCKS_IO_CREATE_EXT); - - /* - * Mark inode as having pending DIO writes to unwritten extents. - * ext4_ext_direct_IO() checks this flag and converts extents to - * written. - */ - if (!ret && buffer_unwritten(bh_result)) - ext4_set_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN); - - return ret; -} - -static int ext4_dio_get_block_overwrite(struct inode *inode, sector_t iblock, - struct buffer_head *bh_result, int create) -{ - int ret; - - ext4_debug("ext4_dio_get_block_overwrite: inode %lu, create flag %d\n", - inode->i_ino, create); - /* We don't expect handle for direct IO */ - WARN_ON_ONCE(ext4_journal_current_handle()); - - ret = _ext4_get_block(inode, iblock, bh_result, 0); - /* - * Blocks should have been preallocated! ext4_file_write_iter() checks - * that. - */ - WARN_ON_ONCE(!buffer_mapped(bh_result) || buffer_unwritten(bh_result)); - - return ret; -} - - -/* - * `handle' can be NULL if create is zero - */ -struct buffer_head *ext4_getblk(handle_t *handle, struct inode *inode, - ext4_lblk_t block, int map_flags) -{ - struct ext4_map_blocks map; - struct buffer_head *bh; - int create = map_flags & EXT4_GET_BLOCKS_CREATE; - int err; - - J_ASSERT(handle != NULL || create == 0); - - map.m_lblk = block; - map.m_len = 1; - err = ext4_map_blocks(handle, inode, &map, map_flags); - - if (err == 0) - return create ? ERR_PTR(-ENOSPC) : NULL; - if (err < 0) - return ERR_PTR(err); - - bh = sb_getblk(inode->i_sb, map.m_pblk); - if (unlikely(!bh)) - return ERR_PTR(-ENOMEM); - if (map.m_flags & EXT4_MAP_NEW) { - J_ASSERT(create != 0); - J_ASSERT(handle != NULL); - - /* - * Now that we do not always journal data, we should - * keep in mind whether this should always journal the - * new buffer as metadata. For now, regular file - * writes use ext4_get_block instead, so it's not a - * problem. - */ - lock_buffer(bh); - BUFFER_TRACE(bh, "call get_create_access"); - err = ext4_journal_get_create_access(handle, bh); - if (unlikely(err)) { - unlock_buffer(bh); - goto errout; - } - if (!buffer_uptodate(bh)) { - memset(bh->b_data, 0, inode->i_sb->s_blocksize); - set_buffer_uptodate(bh); - } - unlock_buffer(bh); - BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); - err = ext4_handle_dirty_metadata(handle, inode, bh); - if (unlikely(err)) - goto errout; - } else - BUFFER_TRACE(bh, "not a new buffer"); - return bh; -errout: - brelse(bh); - return ERR_PTR(err); -} - -struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode, - ext4_lblk_t block, int map_flags) -{ - struct buffer_head *bh; - - bh = ext4_getblk(handle, inode, block, map_flags); - if (IS_ERR(bh)) - return bh; - if (!bh || buffer_uptodate(bh)) - return bh; - ll_rw_block(REQ_OP_READ, REQ_META | REQ_PRIO, 1, &bh); - wait_on_buffer(bh); - if (buffer_uptodate(bh)) - return bh; - put_bh(bh); - return ERR_PTR(-EIO); -} - -int ext4_walk_page_buffers(handle_t *handle, - struct buffer_head *head, - unsigned from, - unsigned to, - int *partial, - int (*fn)(handle_t *handle, - struct buffer_head *bh)) -{ - struct buffer_head *bh; - unsigned block_start, block_end; - unsigned blocksize = head->b_size; - int err, ret = 0; - struct buffer_head *next; - - for (bh = head, block_start = 0; - ret == 0 && (bh != head || !block_start); - block_start = block_end, bh = next) { - next = bh->b_this_page; - block_end = block_start + blocksize; - if (block_end <= from || block_start >= to) { - if (partial && !buffer_uptodate(bh)) - *partial = 1; - continue; - } - err = (*fn)(handle, bh); - if (!ret) - ret = err; - } - return ret; -} - -/* - * To preserve ordering, it is essential that the hole instantiation and - * the data write be encapsulated in a single transaction. We cannot - * close off a transaction and start a new one between the ext4_get_block() - * and the commit_write(). So doing the jbd2_journal_start at the start of - * prepare_write() is the right place. - * - * Also, this function can nest inside ext4_writepage(). In that case, we - * *know* that ext4_writepage() has generated enough buffer credits to do the - * whole page. So we won't block on the journal in that case, which is good, - * because the caller may be PF_MEMALLOC. - * - * By accident, ext4 can be reentered when a transaction is open via - * quota file writes. If we were to commit the transaction while thus - * reentered, there can be a deadlock - we would be holding a quota - * lock, and the commit would never complete if another thread had a - * transaction open and was blocking on the quota lock - a ranking - * violation. - * - * So what we do is to rely on the fact that jbd2_journal_stop/journal_start - * will _not_ run commit under these circumstances because handle->h_ref - * is elevated. We'll still have enough credits for the tiny quotafile - * write. - */ -int do_journal_get_write_access(handle_t *handle, - struct buffer_head *bh) -{ - int dirty = buffer_dirty(bh); - int ret; - - if (!buffer_mapped(bh) || buffer_freed(bh)) - return 0; - /* - * __block_write_begin() could have dirtied some buffers. Clean - * the dirty bit as jbd2_journal_get_write_access() could complain - * otherwise about fs integrity issues. Setting of the dirty bit - * by __block_write_begin() isn't a real problem here as we clear - * the bit before releasing a page lock and thus writeback cannot - * ever write the buffer. - */ - if (dirty) - clear_buffer_dirty(bh); - BUFFER_TRACE(bh, "get write access"); - ret = ext4_journal_get_write_access(handle, bh); - if (!ret && dirty) - ret = ext4_handle_dirty_metadata(handle, NULL, bh); - return ret; -} - -#ifdef CONFIG_EXT4_FS_ENCRYPTION -static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, - get_block_t *get_block) -{ - unsigned from = pos & (PAGE_SIZE - 1); - unsigned to = from + len; - struct inode *inode = page->mapping->host; - unsigned block_start, block_end; - sector_t block; - int err = 0; - unsigned blocksize = inode->i_sb->s_blocksize; - unsigned bbits; - struct buffer_head *bh, *head, *wait[2], **wait_bh = wait; - bool decrypt = false; - - BUG_ON(!PageLocked(page)); - BUG_ON(from > PAGE_SIZE); - BUG_ON(to > PAGE_SIZE); - BUG_ON(from > to); - - if (!page_has_buffers(page)) - create_empty_buffers(page, blocksize, 0); - head = page_buffers(page); - bbits = ilog2(blocksize); - block = (sector_t)page->index << (PAGE_SHIFT - bbits); - - for (bh = head, block_start = 0; bh != head || !block_start; - block++, block_start = block_end, bh = bh->b_this_page) { - block_end = block_start + blocksize; - if (block_end <= from || block_start >= to) { - if (PageUptodate(page)) { - if (!buffer_uptodate(bh)) - set_buffer_uptodate(bh); - } - continue; - } - if (buffer_new(bh)) - clear_buffer_new(bh); - if (!buffer_mapped(bh)) { - WARN_ON(bh->b_size != blocksize); - err = get_block(inode, block, bh, 1); - if (err) - break; - if (buffer_new(bh)) { - unmap_underlying_metadata(bh->b_bdev, - bh->b_blocknr); - if (PageUptodate(page)) { - clear_buffer_new(bh); - set_buffer_uptodate(bh); - mark_buffer_dirty(bh); - continue; - } - if (block_end > to || block_start < from) - zero_user_segments(page, to, block_end, - block_start, from); - continue; - } - } - if (PageUptodate(page)) { - if (!buffer_uptodate(bh)) - set_buffer_uptodate(bh); - continue; - } - if (!buffer_uptodate(bh) && !buffer_delay(bh) && - !buffer_unwritten(bh) && - (block_start < from || block_end > to)) { - ll_rw_block(REQ_OP_READ, 0, 1, &bh); - *wait_bh++ = bh; - decrypt = ext4_encrypted_inode(inode) && - S_ISREG(inode->i_mode); - } - } - /* - * If we issued read requests, let them complete. - */ - while (wait_bh > wait) { - wait_on_buffer(*--wait_bh); - if (!buffer_uptodate(*wait_bh)) - err = -EIO; - } - if (unlikely(err)) - page_zero_new_buffers(page, from, to); - else if (decrypt) - err = fscrypt_decrypt_page(page); - return err; -} -#endif - -static int ext4_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) -{ - struct inode *inode = mapping->host; - int ret, needed_blocks; - handle_t *handle; - int retries = 0; - struct page *page; - pgoff_t index; - unsigned from, to; - - trace_ext4_write_begin(inode, pos, len, flags); - /* - * Reserve one block more for addition to orphan list in case - * we allocate blocks but write fails for some reason - */ - needed_blocks = ext4_writepage_trans_blocks(inode) + 1; - index = pos >> PAGE_SHIFT; - from = pos & (PAGE_SIZE - 1); - to = from + len; - - if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) { - ret = ext4_try_to_write_inline_data(mapping, inode, pos, len, - flags, pagep); - if (ret < 0) - return ret; - if (ret == 1) - return 0; - } - - /* - * grab_cache_page_write_begin() can take a long time if the - * system is thrashing due to memory pressure, or if the page - * is being written back. So grab it first before we start - * the transaction handle. This also allows us to allocate - * the page (if needed) without using GFP_NOFS. - */ -retry_grab: - page = grab_cache_page_write_begin(mapping, index, flags); - if (!page) - return -ENOMEM; - unlock_page(page); - -retry_journal: - handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, needed_blocks); - if (IS_ERR(handle)) { - put_page(page); - return PTR_ERR(handle); - } - - lock_page(page); - if (page->mapping != mapping) { - /* The page got truncated from under us */ - unlock_page(page); - put_page(page); - ext4_journal_stop(handle); - goto retry_grab; - } - /* In case writeback began while the page was unlocked */ - wait_for_stable_page(page); - -#ifdef CONFIG_EXT4_FS_ENCRYPTION - if (ext4_should_dioread_nolock(inode)) - ret = ext4_block_write_begin(page, pos, len, - ext4_get_block_unwritten); - else - ret = ext4_block_write_begin(page, pos, len, - ext4_get_block); -#else - if (ext4_should_dioread_nolock(inode)) - ret = __block_write_begin(page, pos, len, - ext4_get_block_unwritten); - else - ret = __block_write_begin(page, pos, len, ext4_get_block); -#endif - if (!ret && ext4_should_journal_data(inode)) { - ret = ext4_walk_page_buffers(handle, page_buffers(page), - from, to, NULL, - do_journal_get_write_access); - } - - if (ret) { - unlock_page(page); - /* - * __block_write_begin may have instantiated a few blocks - * outside i_size. Trim these off again. Don't need - * i_size_read because we hold i_mutex. - * - * Add inode to orphan list in case we crash before - * truncate finishes - */ - if (pos + len > inode->i_size && ext4_can_truncate(inode)) - ext4_orphan_add(handle, inode); - - ext4_journal_stop(handle); - if (pos + len > inode->i_size) { - ext4_truncate_failed_write(inode); - /* - * If truncate failed early the inode might - * still be on the orphan list; we need to - * make sure the inode is removed from the - * orphan list in that case. - */ - if (inode->i_nlink) - ext4_orphan_del(NULL, inode); - } - - if (ret == -ENOSPC && - ext4_should_retry_alloc(inode->i_sb, &retries)) - goto retry_journal; - put_page(page); - return ret; - } - *pagep = page; - return ret; -} - -/* For write_end() in data=journal mode */ -static int write_end_fn(handle_t *handle, struct buffer_head *bh) -{ - int ret; - if (!buffer_mapped(bh) || buffer_freed(bh)) - return 0; - set_buffer_uptodate(bh); - ret = ext4_handle_dirty_metadata(handle, NULL, bh); - clear_buffer_meta(bh); - clear_buffer_prio(bh); - return ret; -} - -/* - * We need to pick up the new inode size which generic_commit_write gave us - * `file' can be NULL - eg, when called from page_symlink(). - * - * ext4 never places buffers on inode->i_mapping->private_list. metadata - * buffers are managed internally. - */ -static int ext4_write_end(struct file *file, - struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) -{ - handle_t *handle = ext4_journal_current_handle(); - struct inode *inode = mapping->host; - loff_t old_size = inode->i_size; - int ret = 0, ret2; - int i_size_changed = 0; - - trace_ext4_write_end(inode, pos, len, copied); - if (ext4_has_inline_data(inode)) { - ret = ext4_write_inline_data_end(inode, pos, len, - copied, page); - if (ret < 0) - goto errout; - copied = ret; - } else - copied = block_write_end(file, mapping, pos, - len, copied, page, fsdata); - /* - * it's important to update i_size while still holding page lock: - * page writeout could otherwise come in and zero beyond i_size. - */ - i_size_changed = ext4_update_inode_size(inode, pos + copied); - unlock_page(page); - put_page(page); - - if (old_size < pos) - pagecache_isize_extended(inode, old_size, pos); - /* - * Don't mark the inode dirty under page lock. First, it unnecessarily - * makes the holding time of page lock longer. Second, it forces lock - * ordering of page lock and transaction start for journaling - * filesystems. - */ - if (i_size_changed) - ext4_mark_inode_dirty(handle, inode); - - if (pos + len > inode->i_size && ext4_can_truncate(inode)) - /* if we have allocated more blocks and copied - * less. We will have blocks allocated outside - * inode->i_size. So truncate them - */ - ext4_orphan_add(handle, inode); -errout: - ret2 = ext4_journal_stop(handle); - if (!ret) - ret = ret2; - - if (pos + len > inode->i_size) { - ext4_truncate_failed_write(inode); - /* - * If truncate failed early the inode might still be - * on the orphan list; we need to make sure the inode - * is removed from the orphan list in that case. - */ - if (inode->i_nlink) - ext4_orphan_del(NULL, inode); - } - - return ret ? ret : copied; -} - -/* - * This is a private version of page_zero_new_buffers() which doesn't - * set the buffer to be dirty, since in data=journalled mode we need - * to call ext4_handle_dirty_metadata() instead. - */ -static void zero_new_buffers(struct page *page, unsigned from, unsigned to) -{ - unsigned int block_start = 0, block_end; - struct buffer_head *head, *bh; - - bh = head = page_buffers(page); - do { - block_end = block_start + bh->b_size; - if (buffer_new(bh)) { - if (block_end > from && block_start < to) { - if (!PageUptodate(page)) { - unsigned start, size; - - start = max(from, block_start); - size = min(to, block_end) - start; - - zero_user(page, start, size); - set_buffer_uptodate(bh); - } - clear_buffer_new(bh); - } - } - block_start = block_end; - bh = bh->b_this_page; - } while (bh != head); -} - -static int ext4_journalled_write_end(struct file *file, - struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) -{ - handle_t *handle = ext4_journal_current_handle(); - struct inode *inode = mapping->host; - loff_t old_size = inode->i_size; - int ret = 0, ret2; - int partial = 0; - unsigned from, to; - int size_changed = 0; - - trace_ext4_journalled_write_end(inode, pos, len, copied); - from = pos & (PAGE_SIZE - 1); - to = from + len; - - BUG_ON(!ext4_handle_valid(handle)); - - if (ext4_has_inline_data(inode)) - copied = ext4_write_inline_data_end(inode, pos, len, - copied, page); - else { - if (copied < len) { - if (!PageUptodate(page)) - copied = 0; - zero_new_buffers(page, from+copied, to); - } - - ret = ext4_walk_page_buffers(handle, page_buffers(page), from, - to, &partial, write_end_fn); - if (!partial) - SetPageUptodate(page); - } - size_changed = ext4_update_inode_size(inode, pos + copied); - ext4_set_inode_state(inode, EXT4_STATE_JDATA); - EXT4_I(inode)->i_datasync_tid = handle->h_transaction->t_tid; - unlock_page(page); - put_page(page); - - if (old_size < pos) - pagecache_isize_extended(inode, old_size, pos); - - if (size_changed) { - ret2 = ext4_mark_inode_dirty(handle, inode); - if (!ret) - ret = ret2; - } - - if (pos + len > inode->i_size && ext4_can_truncate(inode)) - /* if we have allocated more blocks and copied - * less. We will have blocks allocated outside - * inode->i_size. So truncate them - */ - ext4_orphan_add(handle, inode); - - ret2 = ext4_journal_stop(handle); - if (!ret) - ret = ret2; - if (pos + len > inode->i_size) { - ext4_truncate_failed_write(inode); - /* - * If truncate failed early the inode might still be - * on the orphan list; we need to make sure the inode - * is removed from the orphan list in that case. - */ - if (inode->i_nlink) - ext4_orphan_del(NULL, inode); - } - - return ret ? ret : copied; -} - -/* - * Reserve space for a single cluster - */ -static int ext4_da_reserve_space(struct inode *inode) -{ - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - struct ext4_inode_info *ei = EXT4_I(inode); - int ret; - - /* - * We will charge metadata quota at writeout time; this saves - * us from metadata over-estimation, though we may go over by - * a small amount in the end. Here we just reserve for data. - */ - ret = dquot_reserve_block(inode, EXT4_C2B(sbi, 1)); - if (ret) - return ret; - - spin_lock(&ei->i_block_reservation_lock); - if (ext4_claim_free_clusters(sbi, 1, 0)) { - spin_unlock(&ei->i_block_reservation_lock); - dquot_release_reservation_block(inode, EXT4_C2B(sbi, 1)); - return -ENOSPC; - } - ei->i_reserved_data_blocks++; - trace_ext4_da_reserve_space(inode); - spin_unlock(&ei->i_block_reservation_lock); - - return 0; /* success */ -} - -static void ext4_da_release_space(struct inode *inode, int to_free) -{ - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - struct ext4_inode_info *ei = EXT4_I(inode); - - if (!to_free) - return; /* Nothing to release, exit */ - - spin_lock(&EXT4_I(inode)->i_block_reservation_lock); - - trace_ext4_da_release_space(inode, to_free); - if (unlikely(to_free > ei->i_reserved_data_blocks)) { - /* - * if there aren't enough reserved blocks, then the - * counter is messed up somewhere. Since this - * function is called from invalidate page, it's - * harmless to return without any action. - */ - ext4_warning(inode->i_sb, "ext4_da_release_space: " - "ino %lu, to_free %d with only %d reserved " - "data blocks", inode->i_ino, to_free, - ei->i_reserved_data_blocks); - WARN_ON(1); - to_free = ei->i_reserved_data_blocks; - } - ei->i_reserved_data_blocks -= to_free; - - /* update fs dirty data blocks counter */ - percpu_counter_sub(&sbi->s_dirtyclusters_counter, to_free); - - spin_unlock(&EXT4_I(inode)->i_block_reservation_lock); - - dquot_release_reservation_block(inode, EXT4_C2B(sbi, to_free)); -} - -static void ext4_da_page_release_reservation(struct page *page, - unsigned int offset, - unsigned int length) -{ - int to_release = 0, contiguous_blks = 0; - struct buffer_head *head, *bh; - unsigned int curr_off = 0; - struct inode *inode = page->mapping->host; - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - unsigned int stop = offset + length; - int num_clusters; - ext4_fsblk_t lblk; - - BUG_ON(stop > PAGE_SIZE || stop < length); - - head = page_buffers(page); - bh = head; - do { - unsigned int next_off = curr_off + bh->b_size; - - if (next_off > stop) - break; - - if ((offset <= curr_off) && (buffer_delay(bh))) { - to_release++; - contiguous_blks++; - clear_buffer_delay(bh); - } else if (contiguous_blks) { - lblk = page->index << - (PAGE_SHIFT - inode->i_blkbits); - lblk += (curr_off >> inode->i_blkbits) - - contiguous_blks; - ext4_es_remove_extent(inode, lblk, contiguous_blks); - contiguous_blks = 0; - } - curr_off = next_off; - } while ((bh = bh->b_this_page) != head); - - if (contiguous_blks) { - lblk = page->index << (PAGE_SHIFT - inode->i_blkbits); - lblk += (curr_off >> inode->i_blkbits) - contiguous_blks; - ext4_es_remove_extent(inode, lblk, contiguous_blks); - } - - /* If we have released all the blocks belonging to a cluster, then we - * need to release the reserved space for that cluster. */ - num_clusters = EXT4_NUM_B2C(sbi, to_release); - while (num_clusters > 0) { - lblk = (page->index << (PAGE_SHIFT - inode->i_blkbits)) + - ((num_clusters - 1) << sbi->s_cluster_bits); - if (sbi->s_cluster_ratio == 1 || - !ext4_find_delalloc_cluster(inode, lblk)) - ext4_da_release_space(inode, 1); - - num_clusters--; - } -} - -/* - * Delayed allocation stuff - */ - -struct mpage_da_data { - struct inode *inode; - struct writeback_control *wbc; - - pgoff_t first_page; /* The first page to write */ - pgoff_t next_page; /* Current page to examine */ - pgoff_t last_page; /* Last page to examine */ - /* - * Extent to map - this can be after first_page because that can be - * fully mapped. We somewhat abuse m_flags to store whether the extent - * is delalloc or unwritten. - */ - struct ext4_map_blocks map; - struct ext4_io_submit io_submit; /* IO submission data */ -}; - -static void mpage_release_unused_pages(struct mpage_da_data *mpd, - bool invalidate) -{ - int nr_pages, i; - pgoff_t index, end; - struct pagevec pvec; - struct inode *inode = mpd->inode; - struct address_space *mapping = inode->i_mapping; - - /* This is necessary when next_page == 0. */ - if (mpd->first_page >= mpd->next_page) - return; - - index = mpd->first_page; - end = mpd->next_page - 1; - if (invalidate) { - ext4_lblk_t start, last; - start = index << (PAGE_SHIFT - inode->i_blkbits); - last = end << (PAGE_SHIFT - inode->i_blkbits); - ext4_es_remove_extent(inode, start, last - start + 1); - } - - pagevec_init(&pvec, 0); - while (index <= end) { - nr_pages = pagevec_lookup(&pvec, mapping, index, PAGEVEC_SIZE); - if (nr_pages == 0) - break; - for (i = 0; i < nr_pages; i++) { - struct page *page = pvec.pages[i]; - if (page->index > end) - break; - BUG_ON(!PageLocked(page)); - BUG_ON(PageWriteback(page)); - if (invalidate) { - if (page_mapped(page)) - clear_page_dirty_for_io(page); - block_invalidatepage(page, 0, PAGE_SIZE); - ClearPageUptodate(page); - } - unlock_page(page); - } - index = pvec.pages[nr_pages - 1]->index + 1; - pagevec_release(&pvec); - } -} - -static void ext4_print_free_blocks(struct inode *inode) -{ - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - struct super_block *sb = inode->i_sb; - struct ext4_inode_info *ei = EXT4_I(inode); - - ext4_msg(sb, KERN_CRIT, "Total free blocks count %lld", - EXT4_C2B(EXT4_SB(inode->i_sb), - ext4_count_free_clusters(sb))); - ext4_msg(sb, KERN_CRIT, "Free/Dirty block details"); - ext4_msg(sb, KERN_CRIT, "free_blocks=%lld", - (long long) EXT4_C2B(EXT4_SB(sb), - percpu_counter_sum(&sbi->s_freeclusters_counter))); - ext4_msg(sb, KERN_CRIT, "dirty_blocks=%lld", - (long long) EXT4_C2B(EXT4_SB(sb), - percpu_counter_sum(&sbi->s_dirtyclusters_counter))); - ext4_msg(sb, KERN_CRIT, "Block reservation details"); - ext4_msg(sb, KERN_CRIT, "i_reserved_data_blocks=%u", - ei->i_reserved_data_blocks); - return; -} - -static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh) -{ - return (buffer_delay(bh) || buffer_unwritten(bh)) && buffer_dirty(bh); -} - -/* - * This function is grabs code from the very beginning of - * ext4_map_blocks, but assumes that the caller is from delayed write - * time. This function looks up the requested blocks and sets the - * buffer delay bit under the protection of i_data_sem. - */ -static int ext4_da_map_blocks(struct inode *inode, sector_t iblock, - struct ext4_map_blocks *map, - struct buffer_head *bh) -{ - struct extent_status es; - int retval; - sector_t invalid_block = ~((sector_t) 0xffff); -#ifdef ES_AGGRESSIVE_TEST - struct ext4_map_blocks orig_map; - - memcpy(&orig_map, map, sizeof(*map)); -#endif - - if (invalid_block < ext4_blocks_count(EXT4_SB(inode->i_sb)->s_es)) - invalid_block = ~0; - - map->m_flags = 0; - ext_debug("ext4_da_map_blocks(): inode %lu, max_blocks %u," - "logical block %lu\n", inode->i_ino, map->m_len, - (unsigned long) map->m_lblk); - - /* Lookup extent status tree firstly */ - if (ext4_es_lookup_extent(inode, iblock, &es)) { - if (ext4_es_is_hole(&es)) { - retval = 0; - down_read(&EXT4_I(inode)->i_data_sem); - goto add_delayed; - } - - /* - * Delayed extent could be allocated by fallocate. - * So we need to check it. - */ - if (ext4_es_is_delayed(&es) && !ext4_es_is_unwritten(&es)) { - map_bh(bh, inode->i_sb, invalid_block); - set_buffer_new(bh); - set_buffer_delay(bh); - return 0; - } - - map->m_pblk = ext4_es_pblock(&es) + iblock - es.es_lblk; - retval = es.es_len - (iblock - es.es_lblk); - if (retval > map->m_len) - retval = map->m_len; - map->m_len = retval; - if (ext4_es_is_written(&es)) - map->m_flags |= EXT4_MAP_MAPPED; - else if (ext4_es_is_unwritten(&es)) - map->m_flags |= EXT4_MAP_UNWRITTEN; - else - BUG_ON(1); - -#ifdef ES_AGGRESSIVE_TEST - ext4_map_blocks_es_recheck(NULL, inode, map, &orig_map, 0); -#endif - return retval; - } - - /* - * Try to see if we can get the block without requesting a new - * file system block. - */ - down_read(&EXT4_I(inode)->i_data_sem); - if (ext4_has_inline_data(inode)) - retval = 0; - else if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) - retval = ext4_ext_map_blocks(NULL, inode, map, 0); - else - retval = ext4_ind_map_blocks(NULL, inode, map, 0); - -add_delayed: - if (retval == 0) { - int ret; - /* - * XXX: __block_prepare_write() unmaps passed block, - * is it OK? - */ - /* - * If the block was allocated from previously allocated cluster, - * then we don't need to reserve it again. However we still need - * to reserve metadata for every block we're going to write. - */ - if (EXT4_SB(inode->i_sb)->s_cluster_ratio == 1 || - !ext4_find_delalloc_cluster(inode, map->m_lblk)) { - ret = ext4_da_reserve_space(inode); - if (ret) { - /* not enough space to reserve */ - retval = ret; - goto out_unlock; - } - } - - ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len, - ~0, EXTENT_STATUS_DELAYED); - if (ret) { - retval = ret; - goto out_unlock; - } - - map_bh(bh, inode->i_sb, invalid_block); - set_buffer_new(bh); - set_buffer_delay(bh); - } else if (retval > 0) { - int ret; - unsigned int status; - - if (unlikely(retval != map->m_len)) { - ext4_warning(inode->i_sb, - "ES len assertion failed for inode " - "%lu: retval %d != map->m_len %d", - inode->i_ino, retval, map->m_len); - WARN_ON(1); - } - - status = map->m_flags & EXT4_MAP_UNWRITTEN ? - EXTENT_STATUS_UNWRITTEN : EXTENT_STATUS_WRITTEN; - ret = ext4_es_insert_extent(inode, map->m_lblk, map->m_len, - map->m_pblk, status); - if (ret != 0) - retval = ret; - } - -out_unlock: - up_read((&EXT4_I(inode)->i_data_sem)); - - return retval; -} - -/* - * This is a special get_block_t callback which is used by - * ext4_da_write_begin(). It will either return mapped block or - * reserve space for a single block. - * - * For delayed buffer_head we have BH_Mapped, BH_New, BH_Delay set. - * We also have b_blocknr = -1 and b_bdev initialized properly - * - * For unwritten buffer_head we have BH_Mapped, BH_New, BH_Unwritten set. - * We also have b_blocknr = physicalblock mapping unwritten extent and b_bdev - * initialized properly. - */ -int ext4_da_get_block_prep(struct inode *inode, sector_t iblock, - struct buffer_head *bh, int create) -{ - struct ext4_map_blocks map; - int ret = 0; - - BUG_ON(create == 0); - BUG_ON(bh->b_size != inode->i_sb->s_blocksize); - - map.m_lblk = iblock; - map.m_len = 1; - - /* - * first, we need to know whether the block is allocated already - * preallocated blocks are unmapped but should treated - * the same as allocated blocks. - */ - ret = ext4_da_map_blocks(inode, iblock, &map, bh); - if (ret <= 0) - return ret; - - map_bh(bh, inode->i_sb, map.m_pblk); - ext4_update_bh_state(bh, map.m_flags); - - if (buffer_unwritten(bh)) { - /* A delayed write to unwritten bh should be marked - * new and mapped. Mapped ensures that we don't do - * get_block multiple times when we write to the same - * offset and new ensures that we do proper zero out - * for partial write. - */ - set_buffer_new(bh); - set_buffer_mapped(bh); - } - return 0; -} - -static int bget_one(handle_t *handle, struct buffer_head *bh) -{ - get_bh(bh); - return 0; -} - -static int bput_one(handle_t *handle, struct buffer_head *bh) -{ - put_bh(bh); - return 0; -} - -static int __ext4_journalled_writepage(struct page *page, - unsigned int len) -{ - struct address_space *mapping = page->mapping; - struct inode *inode = mapping->host; - struct buffer_head *page_bufs = NULL; - handle_t *handle = NULL; - int ret = 0, err = 0; - int inline_data = ext4_has_inline_data(inode); - struct buffer_head *inode_bh = NULL; - - ClearPageChecked(page); - - if (inline_data) { - BUG_ON(page->index != 0); - BUG_ON(len > ext4_get_max_inline_size(inode)); - inode_bh = ext4_journalled_write_inline_data(inode, len, page); - if (inode_bh == NULL) - goto out; - } else { - page_bufs = page_buffers(page); - if (!page_bufs) { - BUG(); - goto out; - } - ext4_walk_page_buffers(handle, page_bufs, 0, len, - NULL, bget_one); - } - /* - * We need to release the page lock before we start the - * journal, so grab a reference so the page won't disappear - * out from under us. - */ - get_page(page); - unlock_page(page); - - handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, - ext4_writepage_trans_blocks(inode)); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - put_page(page); - goto out_no_pagelock; - } - BUG_ON(!ext4_handle_valid(handle)); - - lock_page(page); - put_page(page); - if (page->mapping != mapping) { - /* The page got truncated from under us */ - ext4_journal_stop(handle); - ret = 0; - goto out; - } - - if (inline_data) { - BUFFER_TRACE(inode_bh, "get write access"); - ret = ext4_journal_get_write_access(handle, inode_bh); - - err = ext4_handle_dirty_metadata(handle, inode, inode_bh); - - } else { - ret = ext4_walk_page_buffers(handle, page_bufs, 0, len, NULL, - do_journal_get_write_access); - - err = ext4_walk_page_buffers(handle, page_bufs, 0, len, NULL, - write_end_fn); - } - if (ret == 0) - ret = err; - EXT4_I(inode)->i_datasync_tid = handle->h_transaction->t_tid; - err = ext4_journal_stop(handle); - if (!ret) - ret = err; - - if (!ext4_has_inline_data(inode)) - ext4_walk_page_buffers(NULL, page_bufs, 0, len, - NULL, bput_one); - ext4_set_inode_state(inode, EXT4_STATE_JDATA); -out: - unlock_page(page); -out_no_pagelock: - brelse(inode_bh); - return ret; -} - -/* - * Note that we don't need to start a transaction unless we're journaling data - * because we should have holes filled from ext4_page_mkwrite(). We even don't - * need to file the inode to the transaction's list in ordered mode because if - * we are writing back data added by write(), the inode is already there and if - * we are writing back data modified via mmap(), no one guarantees in which - * transaction the data will hit the disk. In case we are journaling data, we - * cannot start transaction directly because transaction start ranks above page - * lock so we have to do some magic. - * - * This function can get called via... - * - ext4_writepages after taking page lock (have journal handle) - * - journal_submit_inode_data_buffers (no journal handle) - * - shrink_page_list via the kswapd/direct reclaim (no journal handle) - * - grab_page_cache when doing write_begin (have journal handle) - * - * We don't do any block allocation in this function. If we have page with - * multiple blocks we need to write those buffer_heads that are mapped. This - * is important for mmaped based write. So if we do with blocksize 1K - * truncate(f, 1024); - * a = mmap(f, 0, 4096); - * a[0] = 'a'; - * truncate(f, 4096); - * we have in the page first buffer_head mapped via page_mkwrite call back - * but other buffer_heads would be unmapped but dirty (dirty done via the - * do_wp_page). So writepage should write the first block. If we modify - * the mmap area beyond 1024 we will again get a page_fault and the - * page_mkwrite callback will do the block allocation and mark the - * buffer_heads mapped. - * - * We redirty the page if we have any buffer_heads that is either delay or - * unwritten in the page. - * - * We can get recursively called as show below. - * - * ext4_writepage() -> kmalloc() -> __alloc_pages() -> page_launder() -> - * ext4_writepage() - * - * But since we don't do any block allocation we should not deadlock. - * Page also have the dirty flag cleared so we don't get recurive page_lock. - */ -static int ext4_writepage(struct page *page, - struct writeback_control *wbc) -{ - int ret = 0; - loff_t size; - unsigned int len; - struct buffer_head *page_bufs = NULL; - struct inode *inode = page->mapping->host; - struct ext4_io_submit io_submit; - bool keep_towrite = false; - - trace_ext4_writepage(page); - size = i_size_read(inode); - if (page->index == size >> PAGE_SHIFT) - len = size & ~PAGE_MASK; - else - len = PAGE_SIZE; - - page_bufs = page_buffers(page); - /* - * We cannot do block allocation or other extent handling in this - * function. If there are buffers needing that, we have to redirty - * the page. But we may reach here when we do a journal commit via - * journal_submit_inode_data_buffers() and in that case we must write - * allocated buffers to achieve data=ordered mode guarantees. - * - * Also, if there is only one buffer per page (the fs block - * size == the page size), if one buffer needs block - * allocation or needs to modify the extent tree to clear the - * unwritten flag, we know that the page can't be written at - * all, so we might as well refuse the write immediately. - * Unfortunately if the block size != page size, we can't as - * easily detect this case using ext4_walk_page_buffers(), but - * for the extremely common case, this is an optimization that - * skips a useless round trip through ext4_bio_write_page(). - */ - if (ext4_walk_page_buffers(NULL, page_bufs, 0, len, NULL, - ext4_bh_delay_or_unwritten)) { - redirty_page_for_writepage(wbc, page); - if ((current->flags & PF_MEMALLOC) || - (inode->i_sb->s_blocksize == PAGE_SIZE)) { - /* - * For memory cleaning there's no point in writing only - * some buffers. So just bail out. Warn if we came here - * from direct reclaim. - */ - WARN_ON_ONCE((current->flags & (PF_MEMALLOC|PF_KSWAPD)) - == PF_MEMALLOC); - unlock_page(page); - return 0; - } - keep_towrite = true; - } - - if (PageChecked(page) && ext4_should_journal_data(inode)) - /* - * It's mmapped pagecache. Add buffers and journal it. There - * doesn't seem much point in redirtying the page here. - */ - return __ext4_journalled_writepage(page, len); - - ext4_io_submit_init(&io_submit, wbc); - io_submit.io_end = ext4_init_io_end(inode, GFP_NOFS); - if (!io_submit.io_end) { - redirty_page_for_writepage(wbc, page); - unlock_page(page); - return -ENOMEM; - } - ret = ext4_bio_write_page(&io_submit, page, len, wbc, keep_towrite); - ext4_io_submit(&io_submit); - /* Drop io_end reference we got from init */ - ext4_put_io_end_defer(io_submit.io_end); - return ret; -} - -static int mpage_submit_page(struct mpage_da_data *mpd, struct page *page) -{ - int len; - loff_t size = i_size_read(mpd->inode); - int err; - - BUG_ON(page->index != mpd->first_page); - if (page->index == size >> PAGE_SHIFT) - len = size & ~PAGE_MASK; - else - len = PAGE_SIZE; - clear_page_dirty_for_io(page); - err = ext4_bio_write_page(&mpd->io_submit, page, len, mpd->wbc, false); - if (!err) - mpd->wbc->nr_to_write--; - mpd->first_page++; - - return err; -} - -#define BH_FLAGS ((1 << BH_Unwritten) | (1 << BH_Delay)) - -/* - * mballoc gives us at most this number of blocks... - * XXX: That seems to be only a limitation of ext4_mb_normalize_request(). - * The rest of mballoc seems to handle chunks up to full group size. - */ -#define MAX_WRITEPAGES_EXTENT_LEN 2048 - -/* - * mpage_add_bh_to_extent - try to add bh to extent of blocks to map - * - * @mpd - extent of blocks - * @lblk - logical number of the block in the file - * @bh - buffer head we want to add to the extent - * - * The function is used to collect contig. blocks in the same state. If the - * buffer doesn't require mapping for writeback and we haven't started the - * extent of buffers to map yet, the function returns 'true' immediately - the - * caller can write the buffer right away. Otherwise the function returns true - * if the block has been added to the extent, false if the block couldn't be - * added. - */ -static bool mpage_add_bh_to_extent(struct mpage_da_data *mpd, ext4_lblk_t lblk, - struct buffer_head *bh) -{ - struct ext4_map_blocks *map = &mpd->map; - - /* Buffer that doesn't need mapping for writeback? */ - if (!buffer_dirty(bh) || !buffer_mapped(bh) || - (!buffer_delay(bh) && !buffer_unwritten(bh))) { - /* So far no extent to map => we write the buffer right away */ - if (map->m_len == 0) - return true; - return false; - } - - /* First block in the extent? */ - if (map->m_len == 0) { - map->m_lblk = lblk; - map->m_len = 1; - map->m_flags = bh->b_state & BH_FLAGS; - return true; - } - - /* Don't go larger than mballoc is willing to allocate */ - if (map->m_len >= MAX_WRITEPAGES_EXTENT_LEN) - return false; - - /* Can we merge the block to our big extent? */ - if (lblk == map->m_lblk + map->m_len && - (bh->b_state & BH_FLAGS) == map->m_flags) { - map->m_len++; - return true; - } - return false; -} - -/* - * mpage_process_page_bufs - submit page buffers for IO or add them to extent - * - * @mpd - extent of blocks for mapping - * @head - the first buffer in the page - * @bh - buffer we should start processing from - * @lblk - logical number of the block in the file corresponding to @bh - * - * Walk through page buffers from @bh upto @head (exclusive) and either submit - * the page for IO if all buffers in this page were mapped and there's no - * accumulated extent of buffers to map or add buffers in the page to the - * extent of buffers to map. The function returns 1 if the caller can continue - * by processing the next page, 0 if it should stop adding buffers to the - * extent to map because we cannot extend it anymore. It can also return value - * < 0 in case of error during IO submission. - */ -static int mpage_process_page_bufs(struct mpage_da_data *mpd, - struct buffer_head *head, - struct buffer_head *bh, - ext4_lblk_t lblk) -{ - struct inode *inode = mpd->inode; - int err; - ext4_lblk_t blocks = (i_size_read(inode) + (1 << inode->i_blkbits) - 1) - >> inode->i_blkbits; - - do { - BUG_ON(buffer_locked(bh)); - - if (lblk >= blocks || !mpage_add_bh_to_extent(mpd, lblk, bh)) { - /* Found extent to map? */ - if (mpd->map.m_len) - return 0; - /* Everything mapped so far and we hit EOF */ - break; - } - } while (lblk++, (bh = bh->b_this_page) != head); - /* So far everything mapped? Submit the page for IO. */ - if (mpd->map.m_len == 0) { - err = mpage_submit_page(mpd, head->b_page); - if (err < 0) - return err; - } - return lblk < blocks; -} - -/* - * mpage_map_buffers - update buffers corresponding to changed extent and - * submit fully mapped pages for IO - * - * @mpd - description of extent to map, on return next extent to map - * - * Scan buffers corresponding to changed extent (we expect corresponding pages - * to be already locked) and update buffer state according to new extent state. - * We map delalloc buffers to their physical location, clear unwritten bits, - * and mark buffers as uninit when we perform writes to unwritten extents - * and do extent conversion after IO is finished. If the last page is not fully - * mapped, we update @map to the next extent in the last page that needs - * mapping. Otherwise we submit the page for IO. - */ -static int mpage_map_and_submit_buffers(struct mpage_da_data *mpd) -{ - struct pagevec pvec; - int nr_pages, i; - struct inode *inode = mpd->inode; - struct buffer_head *head, *bh; - int bpp_bits = PAGE_SHIFT - inode->i_blkbits; - pgoff_t start, end; - ext4_lblk_t lblk; - sector_t pblock; - int err; - - start = mpd->map.m_lblk >> bpp_bits; - end = (mpd->map.m_lblk + mpd->map.m_len - 1) >> bpp_bits; - lblk = start << bpp_bits; - pblock = mpd->map.m_pblk; - - pagevec_init(&pvec, 0); - while (start <= end) { - nr_pages = pagevec_lookup(&pvec, inode->i_mapping, start, - PAGEVEC_SIZE); - if (nr_pages == 0) - break; - for (i = 0; i < nr_pages; i++) { - struct page *page = pvec.pages[i]; - - if (page->index > end) - break; - /* Up to 'end' pages must be contiguous */ - BUG_ON(page->index != start); - bh = head = page_buffers(page); - do { - if (lblk < mpd->map.m_lblk) - continue; - if (lblk >= mpd->map.m_lblk + mpd->map.m_len) { - /* - * Buffer after end of mapped extent. - * Find next buffer in the page to map. - */ - mpd->map.m_len = 0; - mpd->map.m_flags = 0; - /* - * FIXME: If dioread_nolock supports - * blocksize < pagesize, we need to make - * sure we add size mapped so far to - * io_end->size as the following call - * can submit the page for IO. - */ - err = mpage_process_page_bufs(mpd, head, - bh, lblk); - pagevec_release(&pvec); - if (err > 0) - err = 0; - return err; - } - if (buffer_delay(bh)) { - clear_buffer_delay(bh); - bh->b_blocknr = pblock++; - } - clear_buffer_unwritten(bh); - } while (lblk++, (bh = bh->b_this_page) != head); - - /* - * FIXME: This is going to break if dioread_nolock - * supports blocksize < pagesize as we will try to - * convert potentially unmapped parts of inode. - */ - mpd->io_submit.io_end->size += PAGE_SIZE; - /* Page fully mapped - let IO run! */ - err = mpage_submit_page(mpd, page); - if (err < 0) { - pagevec_release(&pvec); - return err; - } - start++; - } - pagevec_release(&pvec); - } - /* Extent fully mapped and matches with page boundary. We are done. */ - mpd->map.m_len = 0; - mpd->map.m_flags = 0; - return 0; -} - -static int mpage_map_one_extent(handle_t *handle, struct mpage_da_data *mpd) -{ - struct inode *inode = mpd->inode; - struct ext4_map_blocks *map = &mpd->map; - int get_blocks_flags; - int err, dioread_nolock; - - trace_ext4_da_write_pages_extent(inode, map); - /* - * Call ext4_map_blocks() to allocate any delayed allocation blocks, or - * to convert an unwritten extent to be initialized (in the case - * where we have written into one or more preallocated blocks). It is - * possible that we're going to need more metadata blocks than - * previously reserved. However we must not fail because we're in - * writeback and there is nothing we can do about it so it might result - * in data loss. So use reserved blocks to allocate metadata if - * possible. - * - * We pass in the magic EXT4_GET_BLOCKS_DELALLOC_RESERVE if - * the blocks in question are delalloc blocks. This indicates - * that the blocks and quotas has already been checked when - * the data was copied into the page cache. - */ - get_blocks_flags = EXT4_GET_BLOCKS_CREATE | - EXT4_GET_BLOCKS_METADATA_NOFAIL | - EXT4_GET_BLOCKS_IO_SUBMIT; - dioread_nolock = ext4_should_dioread_nolock(inode); - if (dioread_nolock) - get_blocks_flags |= EXT4_GET_BLOCKS_IO_CREATE_EXT; - if (map->m_flags & (1 << BH_Delay)) - get_blocks_flags |= EXT4_GET_BLOCKS_DELALLOC_RESERVE; - - err = ext4_map_blocks(handle, inode, map, get_blocks_flags); - if (err < 0) - return err; - if (dioread_nolock && (map->m_flags & EXT4_MAP_UNWRITTEN)) { - if (!mpd->io_submit.io_end->handle && - ext4_handle_valid(handle)) { - mpd->io_submit.io_end->handle = handle->h_rsv_handle; - handle->h_rsv_handle = NULL; - } - ext4_set_io_unwritten_flag(inode, mpd->io_submit.io_end); - } - - BUG_ON(map->m_len == 0); - if (map->m_flags & EXT4_MAP_NEW) { - struct block_device *bdev = inode->i_sb->s_bdev; - int i; - - for (i = 0; i < map->m_len; i++) - unmap_underlying_metadata(bdev, map->m_pblk + i); - } - return 0; -} - -/* - * mpage_map_and_submit_extent - map extent starting at mpd->lblk of length - * mpd->len and submit pages underlying it for IO - * - * @handle - handle for journal operations - * @mpd - extent to map - * @give_up_on_write - we set this to true iff there is a fatal error and there - * is no hope of writing the data. The caller should discard - * dirty pages to avoid infinite loops. - * - * The function maps extent starting at mpd->lblk of length mpd->len. If it is - * delayed, blocks are allocated, if it is unwritten, we may need to convert - * them to initialized or split the described range from larger unwritten - * extent. Note that we need not map all the described range since allocation - * can return less blocks or the range is covered by more unwritten extents. We - * cannot map more because we are limited by reserved transaction credits. On - * the other hand we always make sure that the last touched page is fully - * mapped so that it can be written out (and thus forward progress is - * guaranteed). After mapping we submit all mapped pages for IO. - */ -static int mpage_map_and_submit_extent(handle_t *handle, - struct mpage_da_data *mpd, - bool *give_up_on_write) -{ - struct inode *inode = mpd->inode; - struct ext4_map_blocks *map = &mpd->map; - int err; - loff_t disksize; - int progress = 0; - - mpd->io_submit.io_end->offset = - ((loff_t)map->m_lblk) << inode->i_blkbits; - do { - err = mpage_map_one_extent(handle, mpd); - if (err < 0) { - struct super_block *sb = inode->i_sb; - - if (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED) - goto invalidate_dirty_pages; - /* - * Let the uper layers retry transient errors. - * In the case of ENOSPC, if ext4_count_free_blocks() - * is non-zero, a commit should free up blocks. - */ - if ((err == -ENOMEM) || - (err == -ENOSPC && ext4_count_free_clusters(sb))) { - if (progress) - goto update_disksize; - return err; - } - ext4_msg(sb, KERN_CRIT, - "Delayed block allocation failed for " - "inode %lu at logical offset %llu with" - " max blocks %u with error %d", - inode->i_ino, - (unsigned long long)map->m_lblk, - (unsigned)map->m_len, -err); - ext4_msg(sb, KERN_CRIT, - "This should not happen!! Data will " - "be lost\n"); - if (err == -ENOSPC) - ext4_print_free_blocks(inode); - invalidate_dirty_pages: - *give_up_on_write = true; - return err; - } - progress = 1; - /* - * Update buffer state, submit mapped pages, and get us new - * extent to map - */ - err = mpage_map_and_submit_buffers(mpd); - if (err < 0) - goto update_disksize; - } while (map->m_len); - -update_disksize: - /* - * Update on-disk size after IO is submitted. Races with - * truncate are avoided by checking i_size under i_data_sem. - */ - disksize = ((loff_t)mpd->first_page) << PAGE_SHIFT; - if (disksize > EXT4_I(inode)->i_disksize) { - int err2; - loff_t i_size; - - down_write(&EXT4_I(inode)->i_data_sem); - i_size = i_size_read(inode); - if (disksize > i_size) - disksize = i_size; - if (disksize > EXT4_I(inode)->i_disksize) - EXT4_I(inode)->i_disksize = disksize; - err2 = ext4_mark_inode_dirty(handle, inode); - up_write(&EXT4_I(inode)->i_data_sem); - if (err2) - ext4_error(inode->i_sb, - "Failed to mark inode %lu dirty", - inode->i_ino); - if (!err) - err = err2; - } - return err; -} - -/* - * Calculate the total number of credits to reserve for one writepages - * iteration. This is called from ext4_writepages(). We map an extent of - * up to MAX_WRITEPAGES_EXTENT_LEN blocks and then we go on and finish mapping - * the last partial page. So in total we can map MAX_WRITEPAGES_EXTENT_LEN + - * bpp - 1 blocks in bpp different extents. - */ -static int ext4_da_writepages_trans_blocks(struct inode *inode) -{ - int bpp = ext4_journal_blocks_per_page(inode); - - return ext4_meta_trans_blocks(inode, - MAX_WRITEPAGES_EXTENT_LEN + bpp - 1, bpp); -} - -/* - * mpage_prepare_extent_to_map - find & lock contiguous range of dirty pages - * and underlying extent to map - * - * @mpd - where to look for pages - * - * Walk dirty pages in the mapping. If they are fully mapped, submit them for - * IO immediately. When we find a page which isn't mapped we start accumulating - * extent of buffers underlying these pages that needs mapping (formed by - * either delayed or unwritten buffers). We also lock the pages containing - * these buffers. The extent found is returned in @mpd structure (starting at - * mpd->lblk with length mpd->len blocks). - * - * Note that this function can attach bios to one io_end structure which are - * neither logically nor physically contiguous. Although it may seem as an - * unnecessary complication, it is actually inevitable in blocksize < pagesize - * case as we need to track IO to all buffers underlying a page in one io_end. - */ -static int mpage_prepare_extent_to_map(struct mpage_da_data *mpd) -{ - struct address_space *mapping = mpd->inode->i_mapping; - struct pagevec pvec; - unsigned int nr_pages; - long left = mpd->wbc->nr_to_write; - pgoff_t index = mpd->first_page; - pgoff_t end = mpd->last_page; - int tag; - int i, err = 0; - int blkbits = mpd->inode->i_blkbits; - ext4_lblk_t lblk; - struct buffer_head *head; - - if (mpd->wbc->sync_mode == WB_SYNC_ALL || mpd->wbc->tagged_writepages) - tag = PAGECACHE_TAG_TOWRITE; - else - tag = PAGECACHE_TAG_DIRTY; - - pagevec_init(&pvec, 0); - mpd->map.m_len = 0; - mpd->next_page = index; - while (index <= end) { - nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag, - min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1); - if (nr_pages == 0) - goto out; - - for (i = 0; i < nr_pages; i++) { - struct page *page = pvec.pages[i]; - - /* - * At this point, the page may be truncated or - * invalidated (changing page->mapping to NULL), or - * even swizzled back from swapper_space to tmpfs file - * mapping. However, page->index will not change - * because we have a reference on the page. - */ - if (page->index > end) - goto out; - - /* - * Accumulated enough dirty pages? This doesn't apply - * to WB_SYNC_ALL mode. For integrity sync we have to - * keep going because someone may be concurrently - * dirtying pages, and we might have synced a lot of - * newly appeared dirty pages, but have not synced all - * of the old dirty pages. - */ - if (mpd->wbc->sync_mode == WB_SYNC_NONE && left <= 0) - goto out; - - /* If we can't merge this page, we are done. */ - if (mpd->map.m_len > 0 && mpd->next_page != page->index) - goto out; - - lock_page(page); - /* - * If the page is no longer dirty, or its mapping no - * longer corresponds to inode we are writing (which - * means it has been truncated or invalidated), or the - * page is already under writeback and we are not doing - * a data integrity writeback, skip the page - */ - if (!PageDirty(page) || - (PageWriteback(page) && - (mpd->wbc->sync_mode == WB_SYNC_NONE)) || - unlikely(page->mapping != mapping)) { - unlock_page(page); - continue; - } - - wait_on_page_writeback(page); - BUG_ON(PageWriteback(page)); - - if (mpd->map.m_len == 0) - mpd->first_page = page->index; - mpd->next_page = page->index + 1; - /* Add all dirty buffers to mpd */ - lblk = ((ext4_lblk_t)page->index) << - (PAGE_SHIFT - blkbits); - head = page_buffers(page); - err = mpage_process_page_bufs(mpd, head, head, lblk); - if (err <= 0) - goto out; - err = 0; - left--; - } - pagevec_release(&pvec); - cond_resched(); - } - return 0; -out: - pagevec_release(&pvec); - return err; -} - -static int __writepage(struct page *page, struct writeback_control *wbc, - void *data) -{ - struct address_space *mapping = data; - int ret = ext4_writepage(page, wbc); - mapping_set_error(mapping, ret); - return ret; -} - -static int ext4_writepages(struct address_space *mapping, - struct writeback_control *wbc) -{ - pgoff_t writeback_index = 0; - long nr_to_write = wbc->nr_to_write; - int range_whole = 0; - int cycled = 1; - handle_t *handle = NULL; - struct mpage_da_data mpd; - struct inode *inode = mapping->host; - int needed_blocks, rsv_blocks = 0, ret = 0; - struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb); - bool done; - struct blk_plug plug; - bool give_up_on_write = false; - - percpu_down_read(&sbi->s_journal_flag_rwsem); - trace_ext4_writepages(inode, wbc); - - if (dax_mapping(mapping)) { - ret = dax_writeback_mapping_range(mapping, inode->i_sb->s_bdev, - wbc); - goto out_writepages; - } - - /* - * No pages to write? This is mainly a kludge to avoid starting - * a transaction for special inodes like journal inode on last iput() - * because that could violate lock ordering on umount - */ - if (!mapping->nrpages || !mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) - goto out_writepages; - - if (ext4_should_journal_data(inode)) { - struct blk_plug plug; - - blk_start_plug(&plug); - ret = write_cache_pages(mapping, wbc, __writepage, mapping); - blk_finish_plug(&plug); - goto out_writepages; - } - - /* - * If the filesystem has aborted, it is read-only, so return - * right away instead of dumping stack traces later on that - * will obscure the real source of the problem. We test - * EXT4_MF_FS_ABORTED instead of sb->s_flag's MS_RDONLY because - * the latter could be true if the filesystem is mounted - * read-only, and in that case, ext4_writepages should - * *never* be called, so if that ever happens, we would want - * the stack trace. - */ - if (unlikely(sbi->s_mount_flags & EXT4_MF_FS_ABORTED)) { - ret = -EROFS; - goto out_writepages; - } - - if (ext4_should_dioread_nolock(inode)) { - /* - * We may need to convert up to one extent per block in - * the page and we may dirty the inode. - */ - rsv_blocks = 1 + (PAGE_SIZE >> inode->i_blkbits); - } - - /* - * If we have inline data and arrive here, it means that - * we will soon create the block for the 1st page, so - * we'd better clear the inline data here. - */ - if (ext4_has_inline_data(inode)) { - /* Just inode will be modified... */ - handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - goto out_writepages; - } - BUG_ON(ext4_test_inode_state(inode, - EXT4_STATE_MAY_INLINE_DATA)); - ext4_destroy_inline_data(handle, inode); - ext4_journal_stop(handle); - } - - if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) - range_whole = 1; - - if (wbc->range_cyclic) { - writeback_index = mapping->writeback_index; - if (writeback_index) - cycled = 0; - mpd.first_page = writeback_index; - mpd.last_page = -1; - } else { - mpd.first_page = wbc->range_start >> PAGE_SHIFT; - mpd.last_page = wbc->range_end >> PAGE_SHIFT; - } - - mpd.inode = inode; - mpd.wbc = wbc; - ext4_io_submit_init(&mpd.io_submit, wbc); -retry: - if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages) - tag_pages_for_writeback(mapping, mpd.first_page, mpd.last_page); - done = false; - blk_start_plug(&plug); - while (!done && mpd.first_page <= mpd.last_page) { - /* For each extent of pages we use new io_end */ - mpd.io_submit.io_end = ext4_init_io_end(inode, GFP_KERNEL); - if (!mpd.io_submit.io_end) { - ret = -ENOMEM; - break; - } - - /* - * We have two constraints: We find one extent to map and we - * must always write out whole page (makes a difference when - * blocksize < pagesize) so that we don't block on IO when we - * try to write out the rest of the page. Journalled mode is - * not supported by delalloc. - */ - BUG_ON(ext4_should_journal_data(inode)); - needed_blocks = ext4_da_writepages_trans_blocks(inode); - - /* start a new transaction */ - handle = ext4_journal_start_with_reserve(inode, - EXT4_HT_WRITE_PAGE, needed_blocks, rsv_blocks); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - ext4_msg(inode->i_sb, KERN_CRIT, "%s: jbd2_start: " - "%ld pages, ino %lu; err %d", __func__, - wbc->nr_to_write, inode->i_ino, ret); - /* Release allocated io_end */ - ext4_put_io_end(mpd.io_submit.io_end); - break; - } - - trace_ext4_da_write_pages(inode, mpd.first_page, mpd.wbc); - ret = mpage_prepare_extent_to_map(&mpd); - if (!ret) { - if (mpd.map.m_len) - ret = mpage_map_and_submit_extent(handle, &mpd, - &give_up_on_write); - else { - /* - * We scanned the whole range (or exhausted - * nr_to_write), submitted what was mapped and - * didn't find anything needing mapping. We are - * done. - */ - done = true; - } - } - /* - * Caution: If the handle is synchronous, - * ext4_journal_stop() can wait for transaction commit - * to finish which may depend on writeback of pages to - * complete or on page lock to be released. In that - * case, we have to wait until after after we have - * submitted all the IO, released page locks we hold, - * and dropped io_end reference (for extent conversion - * to be able to complete) before stopping the handle. - */ - if (!ext4_handle_valid(handle) || handle->h_sync == 0) { - ext4_journal_stop(handle); - handle = NULL; - } - /* Submit prepared bio */ - ext4_io_submit(&mpd.io_submit); - /* Unlock pages we didn't use */ - mpage_release_unused_pages(&mpd, give_up_on_write); - /* - * Drop our io_end reference we got from init. We have - * to be careful and use deferred io_end finishing if - * we are still holding the transaction as we can - * release the last reference to io_end which may end - * up doing unwritten extent conversion. - */ - if (handle) { - ext4_put_io_end_defer(mpd.io_submit.io_end); - ext4_journal_stop(handle); - } else - ext4_put_io_end(mpd.io_submit.io_end); - - if (ret == -ENOSPC && sbi->s_journal) { - /* - * Commit the transaction which would - * free blocks released in the transaction - * and try again - */ - jbd2_journal_force_commit_nested(sbi->s_journal); - ret = 0; - continue; - } - /* Fatal error - ENOMEM, EIO... */ - if (ret) - break; - } - blk_finish_plug(&plug); - if (!ret && !cycled && wbc->nr_to_write > 0) { - cycled = 1; - mpd.last_page = writeback_index - 1; - mpd.first_page = 0; - goto retry; - } - - /* Update index */ - if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) - /* - * Set the writeback_index so that range_cyclic - * mode will write it back later - */ - mapping->writeback_index = mpd.first_page; - -out_writepages: - trace_ext4_writepages_result(inode, wbc, ret, - nr_to_write - wbc->nr_to_write); - percpu_up_read(&sbi->s_journal_flag_rwsem); - return ret; -} - -static int ext4_nonda_switch(struct super_block *sb) -{ - s64 free_clusters, dirty_clusters; - struct ext4_sb_info *sbi = EXT4_SB(sb); - - /* - * switch to non delalloc mode if we are running low - * on free block. The free block accounting via percpu - * counters can get slightly wrong with percpu_counter_batch getting - * accumulated on each CPU without updating global counters - * Delalloc need an accurate free block accounting. So switch - * to non delalloc when we are near to error range. - */ - free_clusters = - percpu_counter_read_positive(&sbi->s_freeclusters_counter); - dirty_clusters = - percpu_counter_read_positive(&sbi->s_dirtyclusters_counter); - /* - * Start pushing delalloc when 1/2 of free blocks are dirty. - */ - if (dirty_clusters && (free_clusters < 2 * dirty_clusters)) - try_to_writeback_inodes_sb(sb, WB_REASON_FS_FREE_SPACE); - - if (2 * free_clusters < 3 * dirty_clusters || - free_clusters < (dirty_clusters + EXT4_FREECLUSTERS_WATERMARK)) { - /* - * free block count is less than 150% of dirty blocks - * or free blocks is less than watermark - */ - return 1; - } - return 0; -} - -/* We always reserve for an inode update; the superblock could be there too */ -static int ext4_da_write_credits(struct inode *inode, loff_t pos, unsigned len) -{ - if (likely(ext4_has_feature_large_file(inode->i_sb))) - return 1; - - if (pos + len <= 0x7fffffffULL) - return 1; - - /* We might need to update the superblock to set LARGE_FILE */ - return 2; -} - -static int ext4_da_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) -{ - int ret, retries = 0; - struct page *page; - pgoff_t index; - struct inode *inode = mapping->host; - handle_t *handle; - - index = pos >> PAGE_SHIFT; - - if (ext4_nonda_switch(inode->i_sb)) { - *fsdata = (void *)FALL_BACK_TO_NONDELALLOC; - return ext4_write_begin(file, mapping, pos, - len, flags, pagep, fsdata); - } - *fsdata = (void *)0; - trace_ext4_da_write_begin(inode, pos, len, flags); - - if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) { - ret = ext4_da_write_inline_data_begin(mapping, inode, - pos, len, flags, - pagep, fsdata); - if (ret < 0) - return ret; - if (ret == 1) - return 0; - } - - /* - * grab_cache_page_write_begin() can take a long time if the - * system is thrashing due to memory pressure, or if the page - * is being written back. So grab it first before we start - * the transaction handle. This also allows us to allocate - * the page (if needed) without using GFP_NOFS. - */ -retry_grab: - page = grab_cache_page_write_begin(mapping, index, flags); - if (!page) - return -ENOMEM; - unlock_page(page); - - /* - * With delayed allocation, we don't log the i_disksize update - * if there is delayed block allocation. But we still need - * to journalling the i_disksize update if writes to the end - * of file which has an already mapped buffer. - */ -retry_journal: - handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, - ext4_da_write_credits(inode, pos, len)); - if (IS_ERR(handle)) { - put_page(page); - return PTR_ERR(handle); - } - - lock_page(page); - if (page->mapping != mapping) { - /* The page got truncated from under us */ - unlock_page(page); - put_page(page); - ext4_journal_stop(handle); - goto retry_grab; - } - /* In case writeback began while the page was unlocked */ - wait_for_stable_page(page); - -#ifdef CONFIG_EXT4_FS_ENCRYPTION - ret = ext4_block_write_begin(page, pos, len, - ext4_da_get_block_prep); -#else - ret = __block_write_begin(page, pos, len, ext4_da_get_block_prep); -#endif - if (ret < 0) { - unlock_page(page); - ext4_journal_stop(handle); - /* - * block_write_begin may have instantiated a few blocks - * outside i_size. Trim these off again. Don't need - * i_size_read because we hold i_mutex. - */ - if (pos + len > inode->i_size) - ext4_truncate_failed_write(inode); - - if (ret == -ENOSPC && - ext4_should_retry_alloc(inode->i_sb, &retries)) - goto retry_journal; - - put_page(page); - return ret; - } - - *pagep = page; - return ret; -} - -/* - * Check if we should update i_disksize - * when write to the end of file but not require block allocation - */ -static int ext4_da_should_update_i_disksize(struct page *page, - unsigned long offset) -{ - struct buffer_head *bh; - struct inode *inode = page->mapping->host; - unsigned int idx; - int i; - - bh = page_buffers(page); - idx = offset >> inode->i_blkbits; - - for (i = 0; i < idx; i++) - bh = bh->b_this_page; - - if (!buffer_mapped(bh) || (buffer_delay(bh)) || buffer_unwritten(bh)) - return 0; - return 1; -} - -static int ext4_da_write_end(struct file *file, - struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) -{ - struct inode *inode = mapping->host; - int ret = 0, ret2; - handle_t *handle = ext4_journal_current_handle(); - loff_t new_i_size; - unsigned long start, end; - int write_mode = (int)(unsigned long)fsdata; - - if (write_mode == FALL_BACK_TO_NONDELALLOC) - return ext4_write_end(file, mapping, pos, - len, copied, page, fsdata); - - trace_ext4_da_write_end(inode, pos, len, copied); - start = pos & (PAGE_SIZE - 1); - end = start + copied - 1; - - /* - * generic_write_end() will run mark_inode_dirty() if i_size - * changes. So let's piggyback the i_disksize mark_inode_dirty - * into that. - */ - new_i_size = pos + copied; - if (copied && new_i_size > EXT4_I(inode)->i_disksize) { - if (ext4_has_inline_data(inode) || - ext4_da_should_update_i_disksize(page, end)) { - ext4_update_i_disksize(inode, new_i_size); - /* We need to mark inode dirty even if - * new_i_size is less that inode->i_size - * bu greater than i_disksize.(hint delalloc) - */ - ext4_mark_inode_dirty(handle, inode); - } - } - - if (write_mode != CONVERT_INLINE_DATA && - ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA) && - ext4_has_inline_data(inode)) - ret2 = ext4_da_write_inline_data_end(inode, pos, len, copied, - page); - else - ret2 = generic_write_end(file, mapping, pos, len, copied, - page, fsdata); - - copied = ret2; - if (ret2 < 0) - ret = ret2; - ret2 = ext4_journal_stop(handle); - if (!ret) - ret = ret2; - - return ret ? ret : copied; -} - -static void ext4_da_invalidatepage(struct page *page, unsigned int offset, - unsigned int length) -{ - /* - * Drop reserved blocks - */ - BUG_ON(!PageLocked(page)); - if (!page_has_buffers(page)) - goto out; - - ext4_da_page_release_reservation(page, offset, length); - -out: - ext4_invalidatepage(page, offset, length); - - return; -} - -/* - * Force all delayed allocation blocks to be allocated for a given inode. - */ -int ext4_alloc_da_blocks(struct inode *inode) -{ - trace_ext4_alloc_da_blocks(inode); - - if (!EXT4_I(inode)->i_reserved_data_blocks) - return 0; - - /* - * We do something simple for now. The filemap_flush() will - * also start triggering a write of the data blocks, which is - * not strictly speaking necessary (and for users of - * laptop_mode, not even desirable). However, to do otherwise - * would require replicating code paths in: - * - * ext4_writepages() -> - * write_cache_pages() ---> (via passed in callback function) - * __mpage_da_writepage() --> - * mpage_add_bh_to_extent() - * mpage_da_map_blocks() - * - * The problem is that write_cache_pages(), located in - * mm/page-writeback.c, marks pages clean in preparation for - * doing I/O, which is not desirable if we're not planning on - * doing I/O at all. - * - * We could call write_cache_pages(), and then redirty all of - * the pages by calling redirty_page_for_writepage() but that - * would be ugly in the extreme. So instead we would need to - * replicate parts of the code in the above functions, - * simplifying them because we wouldn't actually intend to - * write out the pages, but rather only collect contiguous - * logical block extents, call the multi-block allocator, and - * then update the buffer heads with the block allocations. - * - * For now, though, we'll cheat by calling filemap_flush(), - * which will map the blocks, and start the I/O, but not - * actually wait for the I/O to complete. - */ - return filemap_flush(inode->i_mapping); -} - -/* - * bmap() is special. It gets used by applications such as lilo and by - * the swapper to find the on-disk block of a specific piece of data. - * - * Naturally, this is dangerous if the block concerned is still in the - * journal. If somebody makes a swapfile on an ext4 data-journaling - * filesystem and enables swap, then they may get a nasty shock when the - * data getting swapped to that swapfile suddenly gets overwritten by - * the original zero's written out previously to the journal and - * awaiting writeback in the kernel's buffer cache. - * - * So, if we see any bmap calls here on a modified, data-journaled file, - * take extra steps to flush any blocks which might be in the cache. - */ -static sector_t ext4_bmap(struct address_space *mapping, sector_t block) -{ - struct inode *inode = mapping->host; - journal_t *journal; - int err; - - /* - * We can get here for an inline file via the FIBMAP ioctl - */ - if (ext4_has_inline_data(inode)) - return 0; - - if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY) && - test_opt(inode->i_sb, DELALLOC)) { - /* - * With delalloc we want to sync the file - * so that we can make sure we allocate - * blocks for file - */ - filemap_write_and_wait(mapping); - } - - if (EXT4_JOURNAL(inode) && - ext4_test_inode_state(inode, EXT4_STATE_JDATA)) { - /* - * This is a REALLY heavyweight approach, but the use of - * bmap on dirty files is expected to be extremely rare: - * only if we run lilo or swapon on a freshly made file - * do we expect this to happen. - * - * (bmap requires CAP_SYS_RAWIO so this does not - * represent an unprivileged user DOS attack --- we'd be - * in trouble if mortal users could trigger this path at - * will.) - * - * NB. EXT4_STATE_JDATA is not set on files other than - * regular files. If somebody wants to bmap a directory - * or symlink and gets confused because the buffer - * hasn't yet been flushed to disk, they deserve - * everything they get. - */ - - ext4_clear_inode_state(inode, EXT4_STATE_JDATA); - journal = EXT4_JOURNAL(inode); - jbd2_journal_lock_updates(journal); - err = jbd2_journal_flush(journal); - jbd2_journal_unlock_updates(journal); - - if (err) - return 0; - } - - return generic_block_bmap(mapping, block, ext4_get_block); -} - -static int ext4_readpage(struct file *file, struct page *page) -{ - int ret = -EAGAIN; - struct inode *inode = page->mapping->host; - - trace_ext4_readpage(page); - - if (ext4_has_inline_data(inode)) - ret = ext4_readpage_inline(inode, page); - - if (ret == -EAGAIN) - return ext4_mpage_readpages(page->mapping, NULL, page, 1); - - return ret; -} - -static int -ext4_readpages(struct file *file, struct address_space *mapping, - struct list_head *pages, unsigned nr_pages) -{ - struct inode *inode = mapping->host; - - /* If the file has inline data, no need to do readpages. */ - if (ext4_has_inline_data(inode)) - return 0; - - return ext4_mpage_readpages(mapping, pages, NULL, nr_pages); -} - -static void ext4_invalidatepage(struct page *page, unsigned int offset, - unsigned int length) -{ - trace_ext4_invalidatepage(page, offset, length); - - /* No journalling happens on data buffers when this function is used */ - WARN_ON(page_has_buffers(page) && buffer_jbd(page_buffers(page))); - - block_invalidatepage(page, offset, length); -} - -static int __ext4_journalled_invalidatepage(struct page *page, - unsigned int offset, - unsigned int length) -{ - journal_t *journal = EXT4_JOURNAL(page->mapping->host); - - trace_ext4_journalled_invalidatepage(page, offset, length); - - /* - * If it's a full truncate we just forget about the pending dirtying - */ - if (offset == 0 && length == PAGE_SIZE) - ClearPageChecked(page); - - return jbd2_journal_invalidatepage(journal, page, offset, length); -} - -/* Wrapper for aops... */ -static void ext4_journalled_invalidatepage(struct page *page, - unsigned int offset, - unsigned int length) -{ - WARN_ON(__ext4_journalled_invalidatepage(page, offset, length) < 0); -} - -static int ext4_releasepage(struct page *page, gfp_t wait) -{ - journal_t *journal = EXT4_JOURNAL(page->mapping->host); - - trace_ext4_releasepage(page); - - /* Page has dirty journalled data -> cannot release */ - if (PageChecked(page)) - return 0; - if (journal) - return jbd2_journal_try_to_free_buffers(journal, page, wait); - else - return try_to_free_buffers(page); -} - -#ifdef CONFIG_FS_DAX -/* - * Get block function for DAX IO and mmap faults. It takes care of converting - * unwritten extents to written ones and initializes new / converted blocks - * to zeros. - */ -int ext4_dax_get_block(struct inode *inode, sector_t iblock, - struct buffer_head *bh_result, int create) -{ - int ret; - - ext4_debug("inode %lu, create flag %d\n", inode->i_ino, create); - if (!create) - return _ext4_get_block(inode, iblock, bh_result, 0); - - ret = ext4_get_block_trans(inode, iblock, bh_result, - EXT4_GET_BLOCKS_PRE_IO | - EXT4_GET_BLOCKS_CREATE_ZERO); - if (ret < 0) - return ret; - - if (buffer_unwritten(bh_result)) { - /* - * We are protected by i_mmap_sem or i_mutex so we know block - * cannot go away from under us even though we dropped - * i_data_sem. Convert extent to written and write zeros there. - */ - ret = ext4_get_block_trans(inode, iblock, bh_result, - EXT4_GET_BLOCKS_CONVERT | - EXT4_GET_BLOCKS_CREATE_ZERO); - if (ret < 0) - return ret; - } - /* - * At least for now we have to clear BH_New so that DAX code - * doesn't attempt to zero blocks again in a racy way. - */ - clear_buffer_new(bh_result); - return 0; -} -#else -/* Just define empty function, it will never get called. */ -int ext4_dax_get_block(struct inode *inode, sector_t iblock, - struct buffer_head *bh_result, int create) -{ - BUG(); - return 0; -} -#endif - -static int ext4_end_io_dio(struct kiocb *iocb, loff_t offset, - ssize_t size, void *private) -{ - ext4_io_end_t *io_end = private; - - /* if not async direct IO just return */ - if (!io_end) - return 0; - - ext_debug("ext4_end_io_dio(): io_end 0x%p " - "for inode %lu, iocb 0x%p, offset %llu, size %zd\n", - io_end, io_end->inode->i_ino, iocb, offset, size); - - /* - * Error during AIO DIO. We cannot convert unwritten extents as the - * data was not written. Just clear the unwritten flag and drop io_end. - */ - if (size <= 0) { - ext4_clear_io_unwritten_flag(io_end); - size = 0; - } - io_end->offset = offset; - io_end->size = size; - ext4_put_io_end(io_end); - - return 0; -} - -/* - * Handling of direct IO writes. - * - * For ext4 extent files, ext4 will do direct-io write even to holes, - * preallocated extents, and those write extend the file, no need to - * fall back to buffered IO. - * - * For holes, we fallocate those blocks, mark them as unwritten - * If those blocks were preallocated, we mark sure they are split, but - * still keep the range to write as unwritten. - * - * The unwritten extents will be converted to written when DIO is completed. - * For async direct IO, since the IO may still pending when return, we - * set up an end_io call back function, which will do the conversion - * when async direct IO completed. - * - * If the O_DIRECT write will extend the file then add this inode to the - * orphan list. So recovery will truncate it back to the original size - * if the machine crashes during the write. - * - */ -static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) -{ - struct file *file = iocb->ki_filp; - struct inode *inode = file->f_mapping->host; - struct ext4_inode_info *ei = EXT4_I(inode); - ssize_t ret; - loff_t offset = iocb->ki_pos; - size_t count = iov_iter_count(iter); - int overwrite = 0; - get_block_t *get_block_func = NULL; - int dio_flags = 0; - loff_t final_size = offset + count; - int orphan = 0; - handle_t *handle; - - if (final_size > inode->i_size) { - /* Credits for sb + inode write */ - handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - goto out; - } - ret = ext4_orphan_add(handle, inode); - if (ret) { - ext4_journal_stop(handle); - goto out; - } - orphan = 1; - ei->i_disksize = inode->i_size; - ext4_journal_stop(handle); - } - - BUG_ON(iocb->private == NULL); - - /* - * Make all waiters for direct IO properly wait also for extent - * conversion. This also disallows race between truncate() and - * overwrite DIO as i_dio_count needs to be incremented under i_mutex. - */ - inode_dio_begin(inode); - - /* If we do a overwrite dio, i_mutex locking can be released */ - overwrite = *((int *)iocb->private); - - if (overwrite) - inode_unlock(inode); - - /* - * For extent mapped files we could direct write to holes and fallocate. - * - * Allocated blocks to fill the hole are marked as unwritten to prevent - * parallel buffered read to expose the stale data before DIO complete - * the data IO. - * - * As to previously fallocated extents, ext4 get_block will just simply - * mark the buffer mapped but still keep the extents unwritten. - * - * For non AIO case, we will convert those unwritten extents to written - * after return back from blockdev_direct_IO. That way we save us from - * allocating io_end structure and also the overhead of offloading - * the extent convertion to a workqueue. - * - * For async DIO, the conversion needs to be deferred when the - * IO is completed. The ext4 end_io callback function will be - * called to take care of the conversion work. Here for async - * case, we allocate an io_end structure to hook to the iocb. - */ - iocb->private = NULL; - if (overwrite) - get_block_func = ext4_dio_get_block_overwrite; - else if (IS_DAX(inode)) { - /* - * We can avoid zeroing for aligned DAX writes beyond EOF. Other - * writes need zeroing either because they can race with page - * faults or because they use partial blocks. - */ - if (round_down(offset, 1<i_blkbits) >= inode->i_size && - ext4_aligned_io(inode, offset, count)) - get_block_func = ext4_dio_get_block; - else - get_block_func = ext4_dax_get_block; - dio_flags = DIO_LOCKING; - } else if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS) || - round_down(offset, 1 << inode->i_blkbits) >= inode->i_size) { - get_block_func = ext4_dio_get_block; - dio_flags = DIO_LOCKING | DIO_SKIP_HOLES; - } else if (is_sync_kiocb(iocb)) { - get_block_func = ext4_dio_get_block_unwritten_sync; - dio_flags = DIO_LOCKING; - } else { - get_block_func = ext4_dio_get_block_unwritten_async; - dio_flags = DIO_LOCKING; - } -#ifdef CONFIG_EXT4_FS_ENCRYPTION - BUG_ON(ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)); -#endif - if (IS_DAX(inode)) { - ret = dax_do_io(iocb, inode, iter, get_block_func, - ext4_end_io_dio, dio_flags); - } else - ret = __blockdev_direct_IO(iocb, inode, - inode->i_sb->s_bdev, iter, - get_block_func, - ext4_end_io_dio, NULL, dio_flags); - - if (ret > 0 && !overwrite && ext4_test_inode_state(inode, - EXT4_STATE_DIO_UNWRITTEN)) { - int err; - /* - * for non AIO case, since the IO is already - * completed, we could do the conversion right here - */ - err = ext4_convert_unwritten_extents(NULL, inode, - offset, ret); - if (err < 0) - ret = err; - ext4_clear_inode_state(inode, EXT4_STATE_DIO_UNWRITTEN); - } - - inode_dio_end(inode); - /* take i_mutex locking again if we do a ovewrite dio */ - if (overwrite) - inode_lock(inode); - - if (ret < 0 && final_size > inode->i_size) - ext4_truncate_failed_write(inode); - - /* Handle extending of i_size after direct IO write */ - if (orphan) { - int err; - - /* Credits for sb + inode write */ - handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); - if (IS_ERR(handle)) { - /* This is really bad luck. We've written the data - * but cannot extend i_size. Bail out and pretend - * the write failed... */ - ret = PTR_ERR(handle); - if (inode->i_nlink) - ext4_orphan_del(NULL, inode); - - goto out; - } - if (inode->i_nlink) - ext4_orphan_del(handle, inode); - if (ret > 0) { - loff_t end = offset + ret; - if (end > inode->i_size) { - ei->i_disksize = end; - i_size_write(inode, end); - /* - * We're going to return a positive `ret' - * here due to non-zero-length I/O, so there's - * no way of reporting error returns from - * ext4_mark_inode_dirty() to userspace. So - * ignore it. - */ - ext4_mark_inode_dirty(handle, inode); - } - } - err = ext4_journal_stop(handle); - if (ret == 0) - ret = err; - } -out: - return ret; -} - -static ssize_t ext4_direct_IO_read(struct kiocb *iocb, struct iov_iter *iter) -{ - struct address_space *mapping = iocb->ki_filp->f_mapping; - struct inode *inode = mapping->host; - ssize_t ret; - - /* - * Shared inode_lock is enough for us - it protects against concurrent - * writes & truncates and since we take care of writing back page cache, - * we are protected against page writeback as well. - */ - inode_lock_shared(inode); - if (IS_DAX(inode)) { - ret = dax_do_io(iocb, inode, iter, ext4_dio_get_block, NULL, 0); - } else { - size_t count = iov_iter_count(iter); - - ret = filemap_write_and_wait_range(mapping, iocb->ki_pos, - iocb->ki_pos + count); - if (ret) - goto out_unlock; - ret = __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, - iter, ext4_dio_get_block, - NULL, NULL, 0); - } -out_unlock: - inode_unlock_shared(inode); - return ret; -} - -static ssize_t ext4_direct_IO(struct kiocb *iocb, struct iov_iter *iter) -{ - struct file *file = iocb->ki_filp; - struct inode *inode = file->f_mapping->host; - size_t count = iov_iter_count(iter); - loff_t offset = iocb->ki_pos; - ssize_t ret; - -#ifdef CONFIG_EXT4_FS_ENCRYPTION - if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode)) - return 0; -#endif - - /* - * If we are doing data journalling we don't support O_DIRECT - */ - if (ext4_should_journal_data(inode)) - return 0; - - /* Let buffer I/O handle the inline data case. */ - if (ext4_has_inline_data(inode)) - return 0; - - trace_ext4_direct_IO_enter(inode, offset, count, iov_iter_rw(iter)); - if (iov_iter_rw(iter) == READ) - ret = ext4_direct_IO_read(iocb, iter); - else - ret = ext4_direct_IO_write(iocb, iter); - trace_ext4_direct_IO_exit(inode, offset, count, iov_iter_rw(iter), ret); - return ret; -} - -/* - * Pages can be marked dirty completely asynchronously from ext4's journalling - * activity. By filemap_sync_pte(), try_to_unmap_one(), etc. We cannot do - * much here because ->set_page_dirty is called under VFS locks. The page is - * not necessarily locked. - * - * We cannot just dirty the page and leave attached buffers clean, because the - * buffers' dirty state is "definitive". We cannot just set the buffers dirty - * or jbddirty because all the journalling code will explode. - * - * So what we do is to mark the page "pending dirty" and next time writepage - * is called, propagate that into the buffers appropriately. - */ -static int ext4_journalled_set_page_dirty(struct page *page) -{ - SetPageChecked(page); - return __set_page_dirty_nobuffers(page); -} - -static const struct address_space_operations ext4_aops = { - .readpage = ext4_readpage, - .readpages = ext4_readpages, - .writepage = ext4_writepage, - .writepages = ext4_writepages, - .write_begin = ext4_write_begin, - .write_end = ext4_write_end, - .bmap = ext4_bmap, - .invalidatepage = ext4_invalidatepage, - .releasepage = ext4_releasepage, - .direct_IO = ext4_direct_IO, - .migratepage = buffer_migrate_page, - .is_partially_uptodate = block_is_partially_uptodate, - .error_remove_page = generic_error_remove_page, -}; - -static const struct address_space_operations ext4_journalled_aops = { - .readpage = ext4_readpage, - .readpages = ext4_readpages, - .writepage = ext4_writepage, - .writepages = ext4_writepages, - .write_begin = ext4_write_begin, - .write_end = ext4_journalled_write_end, - .set_page_dirty = ext4_journalled_set_page_dirty, - .bmap = ext4_bmap, - .invalidatepage = ext4_journalled_invalidatepage, - .releasepage = ext4_releasepage, - .direct_IO = ext4_direct_IO, - .is_partially_uptodate = block_is_partially_uptodate, - .error_remove_page = generic_error_remove_page, -}; - -static const struct address_space_operations ext4_da_aops = { - .readpage = ext4_readpage, - .readpages = ext4_readpages, - .writepage = ext4_writepage, - .writepages = ext4_writepages, - .write_begin = ext4_da_write_begin, - .write_end = ext4_da_write_end, - .bmap = ext4_bmap, - .invalidatepage = ext4_da_invalidatepage, - .releasepage = ext4_releasepage, - .direct_IO = ext4_direct_IO, - .migratepage = buffer_migrate_page, - .is_partially_uptodate = block_is_partially_uptodate, - .error_remove_page = generic_error_remove_page, -}; - -void ext4_set_aops(struct inode *inode) -{ - switch (ext4_inode_journal_mode(inode)) { - case EXT4_INODE_ORDERED_DATA_MODE: - case EXT4_INODE_WRITEBACK_DATA_MODE: - break; - case EXT4_INODE_JOURNAL_DATA_MODE: - inode->i_mapping->a_ops = &ext4_journalled_aops; - return; - default: - BUG(); - } - if (test_opt(inode->i_sb, DELALLOC)) - inode->i_mapping->a_ops = &ext4_da_aops; - else - inode->i_mapping->a_ops = &ext4_aops; -} - -static int __ext4_block_zero_page_range(handle_t *handle, - struct address_space *mapping, loff_t from, loff_t length) -{ - ext4_fsblk_t index = from >> PAGE_SHIFT; - unsigned offset = from & (PAGE_SIZE-1); - unsigned blocksize, pos; - ext4_lblk_t iblock; - struct inode *inode = mapping->host; - struct buffer_head *bh; - struct page *page; - int err = 0; - - page = find_or_create_page(mapping, from >> PAGE_SHIFT, - mapping_gfp_constraint(mapping, ~__GFP_FS)); - if (!page) - return -ENOMEM; - - blocksize = inode->i_sb->s_blocksize; - - iblock = index << (PAGE_SHIFT - inode->i_sb->s_blocksize_bits); - - if (!page_has_buffers(page)) - create_empty_buffers(page, blocksize, 0); - - /* Find the buffer that contains "offset" */ - bh = page_buffers(page); - pos = blocksize; - while (offset >= pos) { - bh = bh->b_this_page; - iblock++; - pos += blocksize; - } - if (buffer_freed(bh)) { - BUFFER_TRACE(bh, "freed: skip"); - goto unlock; - } - if (!buffer_mapped(bh)) { - BUFFER_TRACE(bh, "unmapped"); - ext4_get_block(inode, iblock, bh, 0); - /* unmapped? It's a hole - nothing to do */ - if (!buffer_mapped(bh)) { - BUFFER_TRACE(bh, "still unmapped"); - goto unlock; - } - } - - /* Ok, it's mapped. Make sure it's up-to-date */ - if (PageUptodate(page)) - set_buffer_uptodate(bh); - - if (!buffer_uptodate(bh)) { - err = -EIO; - ll_rw_block(REQ_OP_READ, 0, 1, &bh); - wait_on_buffer(bh); - /* Uhhuh. Read error. Complain and punt. */ - if (!buffer_uptodate(bh)) - goto unlock; - if (S_ISREG(inode->i_mode) && - ext4_encrypted_inode(inode)) { - /* We expect the key to be set. */ - BUG_ON(!fscrypt_has_encryption_key(inode)); - BUG_ON(blocksize != PAGE_SIZE); - WARN_ON_ONCE(fscrypt_decrypt_page(page)); - } - } - if (ext4_should_journal_data(inode)) { - BUFFER_TRACE(bh, "get write access"); - err = ext4_journal_get_write_access(handle, bh); - if (err) - goto unlock; - } - zero_user(page, offset, length); - BUFFER_TRACE(bh, "zeroed end of block"); - - if (ext4_should_journal_data(inode)) { - err = ext4_handle_dirty_metadata(handle, inode, bh); - } else { - err = 0; - mark_buffer_dirty(bh); - if (ext4_should_order_data(inode)) - err = ext4_jbd2_inode_add_write(handle, inode); - } - -unlock: - unlock_page(page); - put_page(page); - return err; -} - -/* - * ext4_block_zero_page_range() zeros out a mapping of length 'length' - * starting from file offset 'from'. The range to be zero'd must - * be contained with in one block. If the specified range exceeds - * the end of the block it will be shortened to end of the block - * that cooresponds to 'from' - */ -static int ext4_block_zero_page_range(handle_t *handle, - struct address_space *mapping, loff_t from, loff_t length) -{ - struct inode *inode = mapping->host; - unsigned offset = from & (PAGE_SIZE-1); - unsigned blocksize = inode->i_sb->s_blocksize; - unsigned max = blocksize - (offset & (blocksize - 1)); - - /* - * correct length if it does not fall between - * 'from' and the end of the block - */ - if (length > max || length < 0) - length = max; - - if (IS_DAX(inode)) - return dax_zero_page_range(inode, from, length, ext4_get_block); - return __ext4_block_zero_page_range(handle, mapping, from, length); -} - -/* - * ext4_block_truncate_page() zeroes out a mapping from file offset `from' - * up to the end of the block which corresponds to `from'. - * This required during truncate. We need to physically zero the tail end - * of that block so it doesn't yield old data if the file is later grown. - */ -static int ext4_block_truncate_page(handle_t *handle, - struct address_space *mapping, loff_t from) -{ - unsigned offset = from & (PAGE_SIZE-1); - unsigned length; - unsigned blocksize; - struct inode *inode = mapping->host; - - blocksize = inode->i_sb->s_blocksize; - length = blocksize - (offset & (blocksize - 1)); - - return ext4_block_zero_page_range(handle, mapping, from, length); -} - -int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode, - loff_t lstart, loff_t length) -{ - struct super_block *sb = inode->i_sb; - struct address_space *mapping = inode->i_mapping; - unsigned partial_start, partial_end; - ext4_fsblk_t start, end; - loff_t byte_end = (lstart + length - 1); - int err = 0; - - partial_start = lstart & (sb->s_blocksize - 1); - partial_end = byte_end & (sb->s_blocksize - 1); - - start = lstart >> sb->s_blocksize_bits; - end = byte_end >> sb->s_blocksize_bits; - - /* Handle partial zero within the single block */ - if (start == end && - (partial_start || (partial_end != sb->s_blocksize - 1))) { - err = ext4_block_zero_page_range(handle, mapping, - lstart, length); - return err; - } - /* Handle partial zero out on the start of the range */ - if (partial_start) { - err = ext4_block_zero_page_range(handle, mapping, - lstart, sb->s_blocksize); - if (err) - return err; - } - /* Handle partial zero out on the end of the range */ - if (partial_end != sb->s_blocksize - 1) - err = ext4_block_zero_page_range(handle, mapping, - byte_end - partial_end, - partial_end + 1); - return err; -} - -int ext4_can_truncate(struct inode *inode) -{ - if (S_ISREG(inode->i_mode)) - return 1; - if (S_ISDIR(inode->i_mode)) - return 1; - if (S_ISLNK(inode->i_mode)) - return !ext4_inode_is_fast_symlink(inode); - return 0; -} - -/* - * We have to make sure i_disksize gets properly updated before we truncate - * page cache due to hole punching or zero range. Otherwise i_disksize update - * can get lost as it may have been postponed to submission of writeback but - * that will never happen after we truncate page cache. - */ -int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset, - loff_t len) -{ - handle_t *handle; - loff_t size = i_size_read(inode); - - WARN_ON(!inode_is_locked(inode)); - if (offset > size || offset + len < size) - return 0; - - if (EXT4_I(inode)->i_disksize >= size) - return 0; - - handle = ext4_journal_start(inode, EXT4_HT_MISC, 1); - if (IS_ERR(handle)) - return PTR_ERR(handle); - ext4_update_i_disksize(inode, size); - ext4_mark_inode_dirty(handle, inode); - ext4_journal_stop(handle); - - return 0; -} - -/* - * ext4_punch_hole: punches a hole in a file by releasing the blocks - * associated with the given offset and length - * - * @inode: File inode - * @offset: The offset where the hole will begin - * @len: The length of the hole - * - * Returns: 0 on success or negative on failure - */ - -int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length) -{ - struct super_block *sb = inode->i_sb; - ext4_lblk_t first_block, stop_block; - struct address_space *mapping = inode->i_mapping; - loff_t first_block_offset, last_block_offset; - handle_t *handle; - unsigned int credits; - int ret = 0; - - if (!S_ISREG(inode->i_mode)) - return -EOPNOTSUPP; - - trace_ext4_punch_hole(inode, offset, length, 0); - - /* - * Write out all dirty pages to avoid race conditions - * Then release them. - */ - if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { - ret = filemap_write_and_wait_range(mapping, offset, - offset + length - 1); - if (ret) - return ret; - } - - inode_lock(inode); - - /* No need to punch hole beyond i_size */ - if (offset >= inode->i_size) - goto out_mutex; - - /* - * If the hole extends beyond i_size, set the hole - * to end after the page that contains i_size - */ - if (offset + length > inode->i_size) { - length = inode->i_size + - PAGE_SIZE - (inode->i_size & (PAGE_SIZE - 1)) - - offset; - } - - if (offset & (sb->s_blocksize - 1) || - (offset + length) & (sb->s_blocksize - 1)) { - /* - * Attach jinode to inode for jbd2 if we do any zeroing of - * partial block - */ - ret = ext4_inode_attach_jinode(inode); - if (ret < 0) - goto out_mutex; - - } - - /* Wait all existing dio workers, newcomers will block on i_mutex */ - ext4_inode_block_unlocked_dio(inode); - inode_dio_wait(inode); - - /* - * Prevent page faults from reinstantiating pages we have released from - * page cache. - */ - down_write(&EXT4_I(inode)->i_mmap_sem); - first_block_offset = round_up(offset, sb->s_blocksize); - last_block_offset = round_down((offset + length), sb->s_blocksize) - 1; - - /* Now release the pages and zero block aligned part of pages*/ - if (last_block_offset > first_block_offset) { - ret = ext4_update_disksize_before_punch(inode, offset, length); - if (ret) - goto out_dio; - truncate_pagecache_range(inode, first_block_offset, - last_block_offset); - } - - if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) - credits = ext4_writepage_trans_blocks(inode); - else - credits = ext4_blocks_for_truncate(inode); - handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits); - if (IS_ERR(handle)) { - ret = PTR_ERR(handle); - ext4_std_error(sb, ret); - goto out_dio; - } - - ret = ext4_zero_partial_blocks(handle, inode, offset, - length); - if (ret) - goto out_stop; - - first_block = (offset + sb->s_blocksize - 1) >> - EXT4_BLOCK_SIZE_BITS(sb); - stop_block = (offset + length) >> EXT4_BLOCK_SIZE_BITS(sb); - - /* If there are no blocks to remove, return now */ - if (first_block >= stop_block) - goto out_stop; - - down_write(&EXT4_I(inode)->i_data_sem); - ext4_discard_preallocations(inode); - - ret = ext4_es_remove_extent(inode, first_block, - stop_block - first_block); - if (ret) { - up_write(&EXT4_I(inode)->i_data_sem); - goto out_stop; - } - - if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) - ret = ext4_ext_remove_space(inode, first_block, - stop_block - 1); - else - ret = ext4_ind_remove_space(handle, inode, first_block, - stop_block); - - up_write(&EXT4_I(inode)->i_data_sem); - if (IS_SYNC(inode)) - ext4_handle_sync(handle); - - inode->i_mtime = inode->i_ctime = ext4_current_time(inode); - ext4_mark_inode_dirty(handle, inode); -out_stop: - ext4_journal_stop(handle); -out_dio: - up_write(&EXT4_I(inode)->i_mmap_sem); - ext4_inode_resume_unlocked_dio(inode); -out_mutex: - inode_unlock(inode); - return ret; -} - -int ext4_inode_attach_jinode(struct inode *inode) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - struct jbd2_inode *jinode; - - if (ei->jinode || !EXT4_SB(inode->i_sb)->s_journal) - return 0; - - jinode = jbd2_alloc_inode(GFP_KERNEL); - spin_lock(&inode->i_lock); - if (!ei->jinode) { - if (!jinode) { - spin_unlock(&inode->i_lock); - return -ENOMEM; - } - ei->jinode = jinode; - jbd2_journal_init_jbd_inode(ei->jinode, inode); - jinode = NULL; - } - spin_unlock(&inode->i_lock); - if (unlikely(jinode != NULL)) - jbd2_free_inode(jinode); - return 0; -} - -/* - * ext4_truncate() - * - * We block out ext4_get_block() block instantiations across the entire - * transaction, and VFS/VM ensures that ext4_truncate() cannot run - * simultaneously on behalf of the same inode. - * - * As we work through the truncate and commit bits of it to the journal there - * is one core, guiding principle: the file's tree must always be consistent on - * disk. We must be able to restart the truncate after a crash. - * - * The file's tree may be transiently inconsistent in memory (although it - * probably isn't), but whenever we close off and commit a journal transaction, - * the contents of (the filesystem + the journal) must be consistent and - * restartable. It's pretty simple, really: bottom up, right to left (although - * left-to-right works OK too). - * - * Note that at recovery time, journal replay occurs *before* the restart of - * truncate against the orphan inode list. - * - * The committed inode has the new, desired i_size (which is the same as - * i_disksize in this case). After a crash, ext4_orphan_cleanup() will see - * that this inode's truncate did not complete and it will again call - * ext4_truncate() to have another go. So there will be instantiated blocks - * to the right of the truncation point in a crashed ext4 filesystem. But - * that's fine - as long as they are linked from the inode, the post-crash - * ext4_truncate() run will find them and release them. - */ -void ext4_truncate(struct inode *inode) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - unsigned int credits; - handle_t *handle; - struct address_space *mapping = inode->i_mapping; - - /* - * There is a possibility that we're either freeing the inode - * or it's a completely new inode. In those cases we might not - * have i_mutex locked because it's not necessary. - */ - if (!(inode->i_state & (I_NEW|I_FREEING))) - WARN_ON(!inode_is_locked(inode)); - trace_ext4_truncate_enter(inode); - - if (!ext4_can_truncate(inode)) - return; - - ext4_clear_inode_flag(inode, EXT4_INODE_EOFBLOCKS); - - if (inode->i_size == 0 && !test_opt(inode->i_sb, NO_AUTO_DA_ALLOC)) - ext4_set_inode_state(inode, EXT4_STATE_DA_ALLOC_CLOSE); - - if (ext4_has_inline_data(inode)) { - int has_inline = 1; - - ext4_inline_data_truncate(inode, &has_inline); - if (has_inline) - return; - } - - /* If we zero-out tail of the page, we have to create jinode for jbd2 */ - if (inode->i_size & (inode->i_sb->s_blocksize - 1)) { - if (ext4_inode_attach_jinode(inode) < 0) - return; - } - - if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) - credits = ext4_writepage_trans_blocks(inode); - else - credits = ext4_blocks_for_truncate(inode); - - handle = ext4_journal_start(inode, EXT4_HT_TRUNCATE, credits); - if (IS_ERR(handle)) { - ext4_std_error(inode->i_sb, PTR_ERR(handle)); - return; - } - - if (inode->i_size & (inode->i_sb->s_blocksize - 1)) - ext4_block_truncate_page(handle, mapping, inode->i_size); - - /* - * We add the inode to the orphan list, so that if this - * truncate spans multiple transactions, and we crash, we will - * resume the truncate when the filesystem recovers. It also - * marks the inode dirty, to catch the new size. - * - * Implication: the file must always be in a sane, consistent - * truncatable state while each transaction commits. - */ - if (ext4_orphan_add(handle, inode)) - goto out_stop; - - down_write(&EXT4_I(inode)->i_data_sem); - - ext4_discard_preallocations(inode); - - if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) - ext4_ext_truncate(handle, inode); - else - ext4_ind_truncate(handle, inode); - - up_write(&ei->i_data_sem); - - if (IS_SYNC(inode)) - ext4_handle_sync(handle); - -out_stop: - /* - * If this was a simple ftruncate() and the file will remain alive, - * then we need to clear up the orphan record which we created above. - * However, if this was a real unlink then we were called by - * ext4_evict_inode(), and we allow that function to clean up the - * orphan info for us. - */ - if (inode->i_nlink) - ext4_orphan_del(handle, inode); - - inode->i_mtime = inode->i_ctime = ext4_current_time(inode); - ext4_mark_inode_dirty(handle, inode); - ext4_journal_stop(handle); - - trace_ext4_truncate_exit(inode); -} - -/* - * ext4_get_inode_loc returns with an extra refcount against the inode's - * underlying buffer_head on success. If 'in_mem' is true, we have all - * data in memory that is needed to recreate the on-disk version of this - * inode. - */ -static int __ext4_get_inode_loc(struct inode *inode, - struct ext4_iloc *iloc, int in_mem) -{ - struct ext4_group_desc *gdp; - struct buffer_head *bh; - struct super_block *sb = inode->i_sb; - ext4_fsblk_t block; - int inodes_per_block, inode_offset; - - iloc->bh = NULL; - if (!ext4_valid_inum(sb, inode->i_ino)) - return -EFSCORRUPTED; - - iloc->block_group = (inode->i_ino - 1) / EXT4_INODES_PER_GROUP(sb); - gdp = ext4_get_group_desc(sb, iloc->block_group, NULL); - if (!gdp) - return -EIO; - - /* - * Figure out the offset within the block group inode table - */ - inodes_per_block = EXT4_SB(sb)->s_inodes_per_block; - inode_offset = ((inode->i_ino - 1) % - EXT4_INODES_PER_GROUP(sb)); - block = ext4_inode_table(sb, gdp) + (inode_offset / inodes_per_block); - iloc->offset = (inode_offset % inodes_per_block) * EXT4_INODE_SIZE(sb); - - bh = sb_getblk(sb, block); - if (unlikely(!bh)) - return -ENOMEM; - if (!buffer_uptodate(bh)) { - lock_buffer(bh); - - /* - * If the buffer has the write error flag, we have failed - * to write out another inode in the same block. In this - * case, we don't have to read the block because we may - * read the old inode data successfully. - */ - if (buffer_write_io_error(bh) && !buffer_uptodate(bh)) - set_buffer_uptodate(bh); - - if (buffer_uptodate(bh)) { - /* someone brought it uptodate while we waited */ - unlock_buffer(bh); - goto has_buffer; - } - - /* - * If we have all information of the inode in memory and this - * is the only valid inode in the block, we need not read the - * block. - */ - if (in_mem) { - struct buffer_head *bitmap_bh; - int i, start; - - start = inode_offset & ~(inodes_per_block - 1); - - /* Is the inode bitmap in cache? */ - bitmap_bh = sb_getblk(sb, ext4_inode_bitmap(sb, gdp)); - if (unlikely(!bitmap_bh)) - goto make_io; - - /* - * If the inode bitmap isn't in cache then the - * optimisation may end up performing two reads instead - * of one, so skip it. - */ - if (!buffer_uptodate(bitmap_bh)) { - brelse(bitmap_bh); - goto make_io; - } - for (i = start; i < start + inodes_per_block; i++) { - if (i == inode_offset) - continue; - if (ext4_test_bit(i, bitmap_bh->b_data)) - break; - } - brelse(bitmap_bh); - if (i == start + inodes_per_block) { - /* all other inodes are free, so skip I/O */ - memset(bh->b_data, 0, bh->b_size); - set_buffer_uptodate(bh); - unlock_buffer(bh); - goto has_buffer; - } - } - -make_io: - /* - * If we need to do any I/O, try to pre-readahead extra - * blocks from the inode table. - */ - if (EXT4_SB(sb)->s_inode_readahead_blks) { - ext4_fsblk_t b, end, table; - unsigned num; - __u32 ra_blks = EXT4_SB(sb)->s_inode_readahead_blks; - - table = ext4_inode_table(sb, gdp); - /* s_inode_readahead_blks is always a power of 2 */ - b = block & ~((ext4_fsblk_t) ra_blks - 1); - if (table > b) - b = table; - end = b + ra_blks; - num = EXT4_INODES_PER_GROUP(sb); - if (ext4_has_group_desc_csum(sb)) - num -= ext4_itable_unused_count(sb, gdp); - table += num / inodes_per_block; - if (end > table) - end = table; - while (b <= end) - sb_breadahead(sb, b++); - } - - /* - * There are other valid inodes in the buffer, this inode - * has in-inode xattrs, or we don't have this inode in memory. - * Read the block from disk. - */ - trace_ext4_load_inode(inode); - get_bh(bh); - bh->b_end_io = end_buffer_read_sync; - submit_bh(REQ_OP_READ, REQ_META | REQ_PRIO, bh); - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) { - EXT4_ERROR_INODE_BLOCK(inode, block, - "unable to read itable block"); - brelse(bh); - return -EIO; - } - } -has_buffer: - iloc->bh = bh; - return 0; -} - -int ext4_get_inode_loc(struct inode *inode, struct ext4_iloc *iloc) -{ - /* We have all inode data except xattrs in memory here. */ - return __ext4_get_inode_loc(inode, iloc, - !ext4_test_inode_state(inode, EXT4_STATE_XATTR)); -} - -void ext4_set_inode_flags(struct inode *inode) -{ - unsigned int flags = EXT4_I(inode)->i_flags; - unsigned int new_fl = 0; - - if (flags & EXT4_SYNC_FL) - new_fl |= S_SYNC; - if (flags & EXT4_APPEND_FL) - new_fl |= S_APPEND; - if (flags & EXT4_IMMUTABLE_FL) - new_fl |= S_IMMUTABLE; - if (flags & EXT4_NOATIME_FL) - new_fl |= S_NOATIME; - if (flags & EXT4_DIRSYNC_FL) - new_fl |= S_DIRSYNC; - if (test_opt(inode->i_sb, DAX) && S_ISREG(inode->i_mode)) - new_fl |= S_DAX; - inode_set_flags(inode, new_fl, - S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC|S_DAX); -} - -/* Propagate flags from i_flags to EXT4_I(inode)->i_flags */ -void ext4_get_inode_flags(struct ext4_inode_info *ei) -{ - unsigned int vfs_fl; - unsigned long old_fl, new_fl; - - do { - vfs_fl = ei->vfs_inode.i_flags; - old_fl = ei->i_flags; - new_fl = old_fl & ~(EXT4_SYNC_FL|EXT4_APPEND_FL| - EXT4_IMMUTABLE_FL|EXT4_NOATIME_FL| - EXT4_DIRSYNC_FL); - if (vfs_fl & S_SYNC) - new_fl |= EXT4_SYNC_FL; - if (vfs_fl & S_APPEND) - new_fl |= EXT4_APPEND_FL; - if (vfs_fl & S_IMMUTABLE) - new_fl |= EXT4_IMMUTABLE_FL; - if (vfs_fl & S_NOATIME) - new_fl |= EXT4_NOATIME_FL; - if (vfs_fl & S_DIRSYNC) - new_fl |= EXT4_DIRSYNC_FL; - } while (cmpxchg(&ei->i_flags, old_fl, new_fl) != old_fl); -} - -static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode, - struct ext4_inode_info *ei) -{ - blkcnt_t i_blocks ; - struct inode *inode = &(ei->vfs_inode); - struct super_block *sb = inode->i_sb; - - if (ext4_has_feature_huge_file(sb)) { - /* we are using combined 48 bit field */ - i_blocks = ((u64)le16_to_cpu(raw_inode->i_blocks_high)) << 32 | - le32_to_cpu(raw_inode->i_blocks_lo); - if (ext4_test_inode_flag(inode, EXT4_INODE_HUGE_FILE)) { - /* i_blocks represent file system block size */ - return i_blocks << (inode->i_blkbits - 9); - } else { - return i_blocks; - } - } else { - return le32_to_cpu(raw_inode->i_blocks_lo); - } -} - -static inline void ext4_iget_extra_inode(struct inode *inode, - struct ext4_inode *raw_inode, - struct ext4_inode_info *ei) -{ - __le32 *magic = (void *)raw_inode + - EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize; - if (*magic == cpu_to_le32(EXT4_XATTR_MAGIC)) { - ext4_set_inode_state(inode, EXT4_STATE_XATTR); - ext4_find_inline_data_nolock(inode); - } else - EXT4_I(inode)->i_inline_off = 0; -} - -int ext4_get_projid(struct inode *inode, kprojid_t *projid) -{ - if (!ext4_has_feature_project(inode->i_sb)) - return -EOPNOTSUPP; - *projid = EXT4_I(inode)->i_projid; - return 0; -} - -struct inode *ext4_iget(struct super_block *sb, unsigned long ino) -{ - struct ext4_iloc iloc; - struct ext4_inode *raw_inode; - struct ext4_inode_info *ei; - struct inode *inode; - journal_t *journal = EXT4_SB(sb)->s_journal; - long ret; - int block; - uid_t i_uid; - gid_t i_gid; - projid_t i_projid; - - inode = iget_locked(sb, ino); - if (!inode) - return ERR_PTR(-ENOMEM); - if (!(inode->i_state & I_NEW)) - return inode; - - ei = EXT4_I(inode); - iloc.bh = NULL; - - ret = __ext4_get_inode_loc(inode, &iloc, 0); - if (ret < 0) - goto bad_inode; - raw_inode = ext4_raw_inode(&iloc); - - if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) { - ei->i_extra_isize = le16_to_cpu(raw_inode->i_extra_isize); - if (EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize > - EXT4_INODE_SIZE(inode->i_sb)) { - EXT4_ERROR_INODE(inode, "bad extra_isize (%u != %u)", - EXT4_GOOD_OLD_INODE_SIZE + ei->i_extra_isize, - EXT4_INODE_SIZE(inode->i_sb)); - ret = -EFSCORRUPTED; - goto bad_inode; - } - } else - ei->i_extra_isize = 0; - - /* Precompute checksum seed for inode metadata */ - if (ext4_has_metadata_csum(sb)) { - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - __u32 csum; - __le32 inum = cpu_to_le32(inode->i_ino); - __le32 gen = raw_inode->i_generation; - csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&inum, - sizeof(inum)); - ei->i_csum_seed = ext4_chksum(sbi, csum, (__u8 *)&gen, - sizeof(gen)); - } - - if (!ext4_inode_csum_verify(inode, raw_inode, ei)) { - EXT4_ERROR_INODE(inode, "checksum invalid"); - ret = -EFSBADCRC; - goto bad_inode; - } - - inode->i_mode = le16_to_cpu(raw_inode->i_mode); - i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); - i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); - if (ext4_has_feature_project(sb) && - EXT4_INODE_SIZE(sb) > EXT4_GOOD_OLD_INODE_SIZE && - EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) - i_projid = (projid_t)le32_to_cpu(raw_inode->i_projid); - else - i_projid = EXT4_DEF_PROJID; - - if (!(test_opt(inode->i_sb, NO_UID32))) { - i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; - i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; - } - i_uid_write(inode, i_uid); - i_gid_write(inode, i_gid); - ei->i_projid = make_kprojid(&init_user_ns, i_projid); - set_nlink(inode, le16_to_cpu(raw_inode->i_links_count)); - - ext4_clear_state_flags(ei); /* Only relevant on 32-bit archs */ - ei->i_inline_off = 0; - ei->i_dir_start_lookup = 0; - ei->i_dtime = le32_to_cpu(raw_inode->i_dtime); - /* We now have enough fields to check if the inode was active or not. - * This is needed because nfsd might try to access dead inodes - * the test is that same one that e2fsck uses - * NeilBrown 1999oct15 - */ - if (inode->i_nlink == 0) { - if ((inode->i_mode == 0 || - !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS)) && - ino != EXT4_BOOT_LOADER_INO) { - /* this inode is deleted */ - ret = -ESTALE; - goto bad_inode; - } - /* The only unlinked inodes we let through here have - * valid i_mode and are being read by the orphan - * recovery code: that's fine, we're about to complete - * the process of deleting those. - * OR it is the EXT4_BOOT_LOADER_INO which is - * not initialized on a new filesystem. */ - } - ei->i_flags = le32_to_cpu(raw_inode->i_flags); - inode->i_blocks = ext4_inode_blocks(raw_inode, ei); - ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl_lo); - if (ext4_has_feature_64bit(sb)) - ei->i_file_acl |= - ((__u64)le16_to_cpu(raw_inode->i_file_acl_high)) << 32; - inode->i_size = ext4_isize(raw_inode); - ei->i_disksize = inode->i_size; -#ifdef CONFIG_QUOTA - ei->i_reserved_quota = 0; -#endif - inode->i_generation = le32_to_cpu(raw_inode->i_generation); - ei->i_block_group = iloc.block_group; - ei->i_last_alloc_group = ~0; - /* - * NOTE! The in-memory inode i_data array is in little-endian order - * even on big-endian machines: we do NOT byteswap the block numbers! - */ - for (block = 0; block < EXT4_N_BLOCKS; block++) - ei->i_data[block] = raw_inode->i_block[block]; - INIT_LIST_HEAD(&ei->i_orphan); - - /* - * Set transaction id's of transactions that have to be committed - * to finish f[data]sync. We set them to currently running transaction - * as we cannot be sure that the inode or some of its metadata isn't - * part of the transaction - the inode could have been reclaimed and - * now it is reread from disk. - */ - if (journal) { - transaction_t *transaction; - tid_t tid; - - read_lock(&journal->j_state_lock); - if (journal->j_running_transaction) - transaction = journal->j_running_transaction; - else - transaction = journal->j_committing_transaction; - if (transaction) - tid = transaction->t_tid; - else - tid = journal->j_commit_sequence; - read_unlock(&journal->j_state_lock); - ei->i_sync_tid = tid; - ei->i_datasync_tid = tid; - } - - if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) { - if (ei->i_extra_isize == 0) { - /* The extra space is currently unused. Use it. */ - ei->i_extra_isize = sizeof(struct ext4_inode) - - EXT4_GOOD_OLD_INODE_SIZE; - } else { - ext4_iget_extra_inode(inode, raw_inode, ei); - } - } - - EXT4_INODE_GET_XTIME(i_ctime, inode, raw_inode); - EXT4_INODE_GET_XTIME(i_mtime, inode, raw_inode); - EXT4_INODE_GET_XTIME(i_atime, inode, raw_inode); - EXT4_EINODE_GET_XTIME(i_crtime, ei, raw_inode); - - if (likely(!test_opt2(inode->i_sb, HURD_COMPAT))) { - inode->i_version = le32_to_cpu(raw_inode->i_disk_version); - if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) { - if (EXT4_FITS_IN_INODE(raw_inode, ei, i_version_hi)) - inode->i_version |= - (__u64)(le32_to_cpu(raw_inode->i_version_hi)) << 32; - } - } - - ret = 0; - if (ei->i_file_acl && - !ext4_data_block_valid(EXT4_SB(sb), ei->i_file_acl, 1)) { - EXT4_ERROR_INODE(inode, "bad extended attribute block %llu", - ei->i_file_acl); - ret = -EFSCORRUPTED; - goto bad_inode; - } else if (!ext4_has_inline_data(inode)) { - if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) { - if ((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || - (S_ISLNK(inode->i_mode) && - !ext4_inode_is_fast_symlink(inode)))) - /* Validate extent which is part of inode */ - ret = ext4_ext_check_inode(inode); - } else if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || - (S_ISLNK(inode->i_mode) && - !ext4_inode_is_fast_symlink(inode))) { - /* Validate block references which are part of inode */ - ret = ext4_ind_check_inode(inode); - } - } - if (ret) - goto bad_inode; - - if (S_ISREG(inode->i_mode)) { - inode->i_op = &ext4_file_inode_operations; - inode->i_fop = &ext4_file_operations; - ext4_set_aops(inode); - } else if (S_ISDIR(inode->i_mode)) { - inode->i_op = &ext4_dir_inode_operations; - inode->i_fop = &ext4_dir_operations; - } else if (S_ISLNK(inode->i_mode)) { - if (ext4_encrypted_inode(inode)) { - inode->i_op = &ext4_encrypted_symlink_inode_operations; - ext4_set_aops(inode); - } else if (ext4_inode_is_fast_symlink(inode)) { - inode->i_link = (char *)ei->i_data; - inode->i_op = &ext4_fast_symlink_inode_operations; - nd_terminate_link(ei->i_data, inode->i_size, - sizeof(ei->i_data) - 1); - } else { - inode->i_op = &ext4_symlink_inode_operations; - ext4_set_aops(inode); - } - inode_nohighmem(inode); - } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || - S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { - inode->i_op = &ext4_special_inode_operations; - if (raw_inode->i_block[0]) - init_special_inode(inode, inode->i_mode, - old_decode_dev(le32_to_cpu(raw_inode->i_block[0]))); - else - init_special_inode(inode, inode->i_mode, - new_decode_dev(le32_to_cpu(raw_inode->i_block[1]))); - } else if (ino == EXT4_BOOT_LOADER_INO) { - make_bad_inode(inode); - } else { - ret = -EFSCORRUPTED; - EXT4_ERROR_INODE(inode, "bogus i_mode (%o)", inode->i_mode); - goto bad_inode; - } - brelse(iloc.bh); - ext4_set_inode_flags(inode); - unlock_new_inode(inode); - return inode; - -bad_inode: - brelse(iloc.bh); - iget_failed(inode); - return ERR_PTR(ret); -} - -struct inode *ext4_iget_normal(struct super_block *sb, unsigned long ino) -{ - if (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO) - return ERR_PTR(-EFSCORRUPTED); - return ext4_iget(sb, ino); -} - -static int ext4_inode_blocks_set(handle_t *handle, - struct ext4_inode *raw_inode, - struct ext4_inode_info *ei) -{ - struct inode *inode = &(ei->vfs_inode); - u64 i_blocks = inode->i_blocks; - struct super_block *sb = inode->i_sb; - - if (i_blocks <= ~0U) { - /* - * i_blocks can be represented in a 32 bit variable - * as multiple of 512 bytes - */ - raw_inode->i_blocks_lo = cpu_to_le32(i_blocks); - raw_inode->i_blocks_high = 0; - ext4_clear_inode_flag(inode, EXT4_INODE_HUGE_FILE); - return 0; - } - if (!ext4_has_feature_huge_file(sb)) - return -EFBIG; - - if (i_blocks <= 0xffffffffffffULL) { - /* - * i_blocks can be represented in a 48 bit variable - * as multiple of 512 bytes - */ - raw_inode->i_blocks_lo = cpu_to_le32(i_blocks); - raw_inode->i_blocks_high = cpu_to_le16(i_blocks >> 32); - ext4_clear_inode_flag(inode, EXT4_INODE_HUGE_FILE); - } else { - ext4_set_inode_flag(inode, EXT4_INODE_HUGE_FILE); - /* i_block is stored in file system block size */ - i_blocks = i_blocks >> (inode->i_blkbits - 9); - raw_inode->i_blocks_lo = cpu_to_le32(i_blocks); - raw_inode->i_blocks_high = cpu_to_le16(i_blocks >> 32); - } - return 0; -} - -struct other_inode { - unsigned long orig_ino; - struct ext4_inode *raw_inode; -}; - -static int other_inode_match(struct inode * inode, unsigned long ino, - void *data) -{ - struct other_inode *oi = (struct other_inode *) data; - - if ((inode->i_ino != ino) || - (inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW | - I_DIRTY_SYNC | I_DIRTY_DATASYNC)) || - ((inode->i_state & I_DIRTY_TIME) == 0)) - return 0; - spin_lock(&inode->i_lock); - if (((inode->i_state & (I_FREEING | I_WILL_FREE | I_NEW | - I_DIRTY_SYNC | I_DIRTY_DATASYNC)) == 0) && - (inode->i_state & I_DIRTY_TIME)) { - struct ext4_inode_info *ei = EXT4_I(inode); - - inode->i_state &= ~(I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED); - spin_unlock(&inode->i_lock); - - spin_lock(&ei->i_raw_lock); - EXT4_INODE_SET_XTIME(i_ctime, inode, oi->raw_inode); - EXT4_INODE_SET_XTIME(i_mtime, inode, oi->raw_inode); - EXT4_INODE_SET_XTIME(i_atime, inode, oi->raw_inode); - ext4_inode_csum_set(inode, oi->raw_inode, ei); - spin_unlock(&ei->i_raw_lock); - trace_ext4_other_inode_update_time(inode, oi->orig_ino); - return -1; - } - spin_unlock(&inode->i_lock); - return -1; -} - -/* - * Opportunistically update the other time fields for other inodes in - * the same inode table block. - */ -static void ext4_update_other_inodes_time(struct super_block *sb, - unsigned long orig_ino, char *buf) -{ - struct other_inode oi; - unsigned long ino; - int i, inodes_per_block = EXT4_SB(sb)->s_inodes_per_block; - int inode_size = EXT4_INODE_SIZE(sb); - - oi.orig_ino = orig_ino; - /* - * Calculate the first inode in the inode table block. Inode - * numbers are one-based. That is, the first inode in a block - * (assuming 4k blocks and 256 byte inodes) is (n*16 + 1). - */ - ino = ((orig_ino - 1) & ~(inodes_per_block - 1)) + 1; - for (i = 0; i < inodes_per_block; i++, ino++, buf += inode_size) { - if (ino == orig_ino) - continue; - oi.raw_inode = (struct ext4_inode *) buf; - (void) find_inode_nowait(sb, ino, other_inode_match, &oi); - } -} - -/* - * Post the struct inode info into an on-disk inode location in the - * buffer-cache. This gobbles the caller's reference to the - * buffer_head in the inode location struct. - * - * The caller must have write access to iloc->bh. - */ -static int ext4_do_update_inode(handle_t *handle, - struct inode *inode, - struct ext4_iloc *iloc) -{ - struct ext4_inode *raw_inode = ext4_raw_inode(iloc); - struct ext4_inode_info *ei = EXT4_I(inode); - struct buffer_head *bh = iloc->bh; - struct super_block *sb = inode->i_sb; - int err = 0, rc, block; - int need_datasync = 0, set_large_file = 0; - uid_t i_uid; - gid_t i_gid; - projid_t i_projid; - - spin_lock(&ei->i_raw_lock); - - /* For fields not tracked in the in-memory inode, - * initialise them to zero for new inodes. */ - if (ext4_test_inode_state(inode, EXT4_STATE_NEW)) - memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size); - - ext4_get_inode_flags(ei); - raw_inode->i_mode = cpu_to_le16(inode->i_mode); - i_uid = i_uid_read(inode); - i_gid = i_gid_read(inode); - i_projid = from_kprojid(&init_user_ns, ei->i_projid); - if (!(test_opt(inode->i_sb, NO_UID32))) { - raw_inode->i_uid_low = cpu_to_le16(low_16_bits(i_uid)); - raw_inode->i_gid_low = cpu_to_le16(low_16_bits(i_gid)); -/* - * Fix up interoperability with old kernels. Otherwise, old inodes get - * re-used with the upper 16 bits of the uid/gid intact - */ - if (ei->i_dtime && list_empty(&ei->i_orphan)) { - raw_inode->i_uid_high = 0; - raw_inode->i_gid_high = 0; - } else { - raw_inode->i_uid_high = - cpu_to_le16(high_16_bits(i_uid)); - raw_inode->i_gid_high = - cpu_to_le16(high_16_bits(i_gid)); - } - } else { - raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(i_uid)); - raw_inode->i_gid_low = cpu_to_le16(fs_high2lowgid(i_gid)); - raw_inode->i_uid_high = 0; - raw_inode->i_gid_high = 0; - } - raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); - - EXT4_INODE_SET_XTIME(i_ctime, inode, raw_inode); - EXT4_INODE_SET_XTIME(i_mtime, inode, raw_inode); - EXT4_INODE_SET_XTIME(i_atime, inode, raw_inode); - EXT4_EINODE_SET_XTIME(i_crtime, ei, raw_inode); - - err = ext4_inode_blocks_set(handle, raw_inode, ei); - if (err) { - spin_unlock(&ei->i_raw_lock); - goto out_brelse; - } - raw_inode->i_dtime = cpu_to_le32(ei->i_dtime); - raw_inode->i_flags = cpu_to_le32(ei->i_flags & 0xFFFFFFFF); - if (likely(!test_opt2(inode->i_sb, HURD_COMPAT))) - raw_inode->i_file_acl_high = - cpu_to_le16(ei->i_file_acl >> 32); - raw_inode->i_file_acl_lo = cpu_to_le32(ei->i_file_acl); - if (ei->i_disksize != ext4_isize(raw_inode)) { - ext4_isize_set(raw_inode, ei->i_disksize); - need_datasync = 1; - } - if (ei->i_disksize > 0x7fffffffULL) { - if (!ext4_has_feature_large_file(sb) || - EXT4_SB(sb)->s_es->s_rev_level == - cpu_to_le32(EXT4_GOOD_OLD_REV)) - set_large_file = 1; - } - raw_inode->i_generation = cpu_to_le32(inode->i_generation); - if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { - if (old_valid_dev(inode->i_rdev)) { - raw_inode->i_block[0] = - cpu_to_le32(old_encode_dev(inode->i_rdev)); - raw_inode->i_block[1] = 0; - } else { - raw_inode->i_block[0] = 0; - raw_inode->i_block[1] = - cpu_to_le32(new_encode_dev(inode->i_rdev)); - raw_inode->i_block[2] = 0; - } - } else if (!ext4_has_inline_data(inode)) { - for (block = 0; block < EXT4_N_BLOCKS; block++) - raw_inode->i_block[block] = ei->i_data[block]; - } - - if (likely(!test_opt2(inode->i_sb, HURD_COMPAT))) { - raw_inode->i_disk_version = cpu_to_le32(inode->i_version); - if (ei->i_extra_isize) { - if (EXT4_FITS_IN_INODE(raw_inode, ei, i_version_hi)) - raw_inode->i_version_hi = - cpu_to_le32(inode->i_version >> 32); - raw_inode->i_extra_isize = - cpu_to_le16(ei->i_extra_isize); - } - } - - BUG_ON(!ext4_has_feature_project(inode->i_sb) && - i_projid != EXT4_DEF_PROJID); - - if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE && - EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) - raw_inode->i_projid = cpu_to_le32(i_projid); - - ext4_inode_csum_set(inode, raw_inode, ei); - spin_unlock(&ei->i_raw_lock); - if (inode->i_sb->s_flags & MS_LAZYTIME) - ext4_update_other_inodes_time(inode->i_sb, inode->i_ino, - bh->b_data); - - BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); - rc = ext4_handle_dirty_metadata(handle, NULL, bh); - if (!err) - err = rc; - ext4_clear_inode_state(inode, EXT4_STATE_NEW); - if (set_large_file) { - BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get write access"); - err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); - if (err) - goto out_brelse; - ext4_update_dynamic_rev(sb); - ext4_set_feature_large_file(sb); - ext4_handle_sync(handle); - err = ext4_handle_dirty_super(handle, sb); - } - ext4_update_inode_fsync_trans(handle, inode, need_datasync); -out_brelse: - brelse(bh); - ext4_std_error(inode->i_sb, err); - return err; -} - -/* - * ext4_write_inode() - * - * We are called from a few places: - * - * - Within generic_file_aio_write() -> generic_write_sync() for O_SYNC files. - * Here, there will be no transaction running. We wait for any running - * transaction to commit. - * - * - Within flush work (sys_sync(), kupdate and such). - * We wait on commit, if told to. - * - * - Within iput_final() -> write_inode_now() - * We wait on commit, if told to. - * - * In all cases it is actually safe for us to return without doing anything, - * because the inode has been copied into a raw inode buffer in - * ext4_mark_inode_dirty(). This is a correctness thing for WB_SYNC_ALL - * writeback. - * - * Note that we are absolutely dependent upon all inode dirtiers doing the - * right thing: they *must* call mark_inode_dirty() after dirtying info in - * which we are interested. - * - * It would be a bug for them to not do this. The code: - * - * mark_inode_dirty(inode) - * stuff(); - * inode->i_size = expr; - * - * is in error because write_inode() could occur while `stuff()' is running, - * and the new i_size will be lost. Plus the inode will no longer be on the - * superblock's dirty inode list. - */ -int ext4_write_inode(struct inode *inode, struct writeback_control *wbc) -{ - int err; - - if (WARN_ON_ONCE(current->flags & PF_MEMALLOC)) - return 0; - - if (EXT4_SB(inode->i_sb)->s_journal) { - if (ext4_journal_current_handle()) { - jbd_debug(1, "called recursively, non-PF_MEMALLOC!\n"); - dump_stack(); - return -EIO; - } - - /* - * No need to force transaction in WB_SYNC_NONE mode. Also - * ext4_sync_fs() will force the commit after everything is - * written. - */ - if (wbc->sync_mode != WB_SYNC_ALL || wbc->for_sync) - return 0; - - err = ext4_force_commit(inode->i_sb); - } else { - struct ext4_iloc iloc; - - err = __ext4_get_inode_loc(inode, &iloc, 0); - if (err) - return err; - /* - * sync(2) will flush the whole buffer cache. No need to do - * it here separately for each inode. - */ - if (wbc->sync_mode == WB_SYNC_ALL && !wbc->for_sync) - sync_dirty_buffer(iloc.bh); - if (buffer_req(iloc.bh) && !buffer_uptodate(iloc.bh)) { - EXT4_ERROR_INODE_BLOCK(inode, iloc.bh->b_blocknr, - "IO error syncing inode"); - err = -EIO; - } - brelse(iloc.bh); - } - return err; -} - -/* - * In data=journal mode ext4_journalled_invalidatepage() may fail to invalidate - * buffers that are attached to a page stradding i_size and are undergoing - * commit. In that case we have to wait for commit to finish and try again. - */ -static void ext4_wait_for_tail_page_commit(struct inode *inode) -{ - struct page *page; - unsigned offset; - journal_t *journal = EXT4_SB(inode->i_sb)->s_journal; - tid_t commit_tid = 0; - int ret; - - offset = inode->i_size & (PAGE_SIZE - 1); - /* - * All buffers in the last page remain valid? Then there's nothing to - * do. We do the check mainly to optimize the common PAGE_SIZE == - * blocksize case - */ - if (offset > PAGE_SIZE - (1 << inode->i_blkbits)) - return; - while (1) { - page = find_lock_page(inode->i_mapping, - inode->i_size >> PAGE_SHIFT); - if (!page) - return; - ret = __ext4_journalled_invalidatepage(page, offset, - PAGE_SIZE - offset); - unlock_page(page); - put_page(page); - if (ret != -EBUSY) - return; - commit_tid = 0; - read_lock(&journal->j_state_lock); - if (journal->j_committing_transaction) - commit_tid = journal->j_committing_transaction->t_tid; - read_unlock(&journal->j_state_lock); - if (commit_tid) - jbd2_log_wait_commit(journal, commit_tid); - } -} - -/* - * ext4_setattr() - * - * Called from notify_change. - * - * We want to trap VFS attempts to truncate the file as soon as - * possible. In particular, we want to make sure that when the VFS - * shrinks i_size, we put the inode on the orphan list and modify - * i_disksize immediately, so that during the subsequent flushing of - * dirty pages and freeing of disk blocks, we can guarantee that any - * commit will leave the blocks being flushed in an unused state on - * disk. (On recovery, the inode will get truncated and the blocks will - * be freed, so we have a strong guarantee that no future commit will - * leave these blocks visible to the user.) - * - * Another thing we have to assure is that if we are in ordered mode - * and inode is still attached to the committing transaction, we must - * we start writeout of all the dirty pages which are being truncated. - * This way we are sure that all the data written in the previous - * transaction are already on disk (truncate waits for pages under - * writeback). - * - * Called with inode->i_mutex down. - */ -int ext4_setattr(struct dentry *dentry, struct iattr *attr) -{ - struct inode *inode = d_inode(dentry); - int error, rc = 0; - int orphan = 0; - const unsigned int ia_valid = attr->ia_valid; - - error = setattr_prepare(dentry, attr); - if (error) - return error; - - if (is_quota_modification(inode, attr)) { - error = dquot_initialize(inode); - if (error) - return error; - } - if ((ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) || - (ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid))) { - handle_t *handle; - - /* (user+group)*(old+new) structure, inode write (sb, - * inode block, ? - but truncate inode update has it) */ - handle = ext4_journal_start(inode, EXT4_HT_QUOTA, - (EXT4_MAXQUOTAS_INIT_BLOCKS(inode->i_sb) + - EXT4_MAXQUOTAS_DEL_BLOCKS(inode->i_sb)) + 3); - if (IS_ERR(handle)) { - error = PTR_ERR(handle); - goto err_out; - } - error = dquot_transfer(inode, attr); - if (error) { - ext4_journal_stop(handle); - return error; - } - /* Update corresponding info in inode so that everything is in - * one transaction */ - if (attr->ia_valid & ATTR_UID) - inode->i_uid = attr->ia_uid; - if (attr->ia_valid & ATTR_GID) - inode->i_gid = attr->ia_gid; - error = ext4_mark_inode_dirty(handle, inode); - ext4_journal_stop(handle); - } - - if (attr->ia_valid & ATTR_SIZE) { - handle_t *handle; - loff_t oldsize = inode->i_size; - int shrink = (attr->ia_size <= inode->i_size); - - if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) { - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - - if (attr->ia_size > sbi->s_bitmap_maxbytes) - return -EFBIG; - } - if (!S_ISREG(inode->i_mode)) - return -EINVAL; - - if (IS_I_VERSION(inode) && attr->ia_size != inode->i_size) - inode_inc_iversion(inode); - - if (ext4_should_order_data(inode) && - (attr->ia_size < inode->i_size)) { - error = ext4_begin_ordered_truncate(inode, - attr->ia_size); - if (error) - goto err_out; - } - if (attr->ia_size != inode->i_size) { - handle = ext4_journal_start(inode, EXT4_HT_INODE, 3); - if (IS_ERR(handle)) { - error = PTR_ERR(handle); - goto err_out; - } - if (ext4_handle_valid(handle) && shrink) { - error = ext4_orphan_add(handle, inode); - orphan = 1; - } - /* - * Update c/mtime on truncate up, ext4_truncate() will - * update c/mtime in shrink case below - */ - if (!shrink) { - inode->i_mtime = ext4_current_time(inode); - inode->i_ctime = inode->i_mtime; - } - down_write(&EXT4_I(inode)->i_data_sem); - EXT4_I(inode)->i_disksize = attr->ia_size; - rc = ext4_mark_inode_dirty(handle, inode); - if (!error) - error = rc; - /* - * We have to update i_size under i_data_sem together - * with i_disksize to avoid races with writeback code - * running ext4_wb_update_i_disksize(). - */ - if (!error) - i_size_write(inode, attr->ia_size); - up_write(&EXT4_I(inode)->i_data_sem); - ext4_journal_stop(handle); - if (error) { - if (orphan) - ext4_orphan_del(NULL, inode); - goto err_out; - } - } - if (!shrink) - pagecache_isize_extended(inode, oldsize, inode->i_size); - - /* - * Blocks are going to be removed from the inode. Wait - * for dio in flight. Temporarily disable - * dioread_nolock to prevent livelock. - */ - if (orphan) { - if (!ext4_should_journal_data(inode)) { - ext4_inode_block_unlocked_dio(inode); - inode_dio_wait(inode); - ext4_inode_resume_unlocked_dio(inode); - } else - ext4_wait_for_tail_page_commit(inode); - } - down_write(&EXT4_I(inode)->i_mmap_sem); - /* - * Truncate pagecache after we've waited for commit - * in data=journal mode to make pages freeable. - */ - truncate_pagecache(inode, inode->i_size); - if (shrink) - ext4_truncate(inode); - up_write(&EXT4_I(inode)->i_mmap_sem); - } - - if (!rc) { - setattr_copy(inode, attr); - mark_inode_dirty(inode); - } - - /* - * If the call to ext4_truncate failed to get a transaction handle at - * all, we need to clean up the in-core orphan list manually. - */ - if (orphan && inode->i_nlink) - ext4_orphan_del(NULL, inode); - - if (!rc && (ia_valid & ATTR_MODE)) - rc = posix_acl_chmod(inode, inode->i_mode); - -err_out: - ext4_std_error(inode->i_sb, error); - if (!error) - error = rc; - return error; -} - -int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry, - struct kstat *stat) -{ - struct inode *inode; - unsigned long long delalloc_blocks; - - inode = d_inode(dentry); - generic_fillattr(inode, stat); - - /* - * If there is inline data in the inode, the inode will normally not - * have data blocks allocated (it may have an external xattr block). - * Report at least one sector for such files, so tools like tar, rsync, - * others doen't incorrectly think the file is completely sparse. - */ - if (unlikely(ext4_has_inline_data(inode))) - stat->blocks += (stat->size + 511) >> 9; - - /* - * We can't update i_blocks if the block allocation is delayed - * otherwise in the case of system crash before the real block - * allocation is done, we will have i_blocks inconsistent with - * on-disk file blocks. - * We always keep i_blocks updated together with real - * allocation. But to not confuse with user, stat - * will return the blocks that include the delayed allocation - * blocks for this file. - */ - delalloc_blocks = EXT4_C2B(EXT4_SB(inode->i_sb), - EXT4_I(inode)->i_reserved_data_blocks); - stat->blocks += delalloc_blocks << (inode->i_sb->s_blocksize_bits - 9); - return 0; -} - -static int ext4_index_trans_blocks(struct inode *inode, int lblocks, - int pextents) -{ - if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) - return ext4_ind_trans_blocks(inode, lblocks); - return ext4_ext_index_trans_blocks(inode, pextents); -} - -/* - * Account for index blocks, block groups bitmaps and block group - * descriptor blocks if modify datablocks and index blocks - * worse case, the indexs blocks spread over different block groups - * - * If datablocks are discontiguous, they are possible to spread over - * different block groups too. If they are contiguous, with flexbg, - * they could still across block group boundary. - * - * Also account for superblock, inode, quota and xattr blocks - */ -static int ext4_meta_trans_blocks(struct inode *inode, int lblocks, - int pextents) -{ - ext4_group_t groups, ngroups = ext4_get_groups_count(inode->i_sb); - int gdpblocks; - int idxblocks; - int ret = 0; - - /* - * How many index blocks need to touch to map @lblocks logical blocks - * to @pextents physical extents? - */ - idxblocks = ext4_index_trans_blocks(inode, lblocks, pextents); - - ret = idxblocks; - - /* - * Now let's see how many group bitmaps and group descriptors need - * to account - */ - groups = idxblocks + pextents; - gdpblocks = groups; - if (groups > ngroups) - groups = ngroups; - if (groups > EXT4_SB(inode->i_sb)->s_gdb_count) - gdpblocks = EXT4_SB(inode->i_sb)->s_gdb_count; - - /* bitmaps and block group descriptor blocks */ - ret += groups + gdpblocks; - - /* Blocks for super block, inode, quota and xattr blocks */ - ret += EXT4_META_TRANS_BLOCKS(inode->i_sb); - - return ret; -} - -/* - * Calculate the total number of credits to reserve to fit - * the modification of a single pages into a single transaction, - * which may include multiple chunks of block allocations. - * - * This could be called via ext4_write_begin() - * - * We need to consider the worse case, when - * one new block per extent. - */ -int ext4_writepage_trans_blocks(struct inode *inode) -{ - int bpp = ext4_journal_blocks_per_page(inode); - int ret; - - ret = ext4_meta_trans_blocks(inode, bpp, bpp); - - /* Account for data blocks for journalled mode */ - if (ext4_should_journal_data(inode)) - ret += bpp; - return ret; -} - -/* - * Calculate the journal credits for a chunk of data modification. - * - * This is called from DIO, fallocate or whoever calling - * ext4_map_blocks() to map/allocate a chunk of contiguous disk blocks. - * - * journal buffers for data blocks are not included here, as DIO - * and fallocate do no need to journal data buffers. - */ -int ext4_chunk_trans_blocks(struct inode *inode, int nrblocks) -{ - return ext4_meta_trans_blocks(inode, nrblocks, 1); -} - -/* - * The caller must have previously called ext4_reserve_inode_write(). - * Give this, we know that the caller already has write access to iloc->bh. - */ -int ext4_mark_iloc_dirty(handle_t *handle, - struct inode *inode, struct ext4_iloc *iloc) -{ - int err = 0; - - if (IS_I_VERSION(inode)) - inode_inc_iversion(inode); - - /* the do_update_inode consumes one bh->b_count */ - get_bh(iloc->bh); - - /* ext4_do_update_inode() does jbd2_journal_dirty_metadata */ - err = ext4_do_update_inode(handle, inode, iloc); - put_bh(iloc->bh); - return err; -} - -/* - * On success, We end up with an outstanding reference count against - * iloc->bh. This _must_ be cleaned up later. - */ - -int -ext4_reserve_inode_write(handle_t *handle, struct inode *inode, - struct ext4_iloc *iloc) -{ - int err; - - err = ext4_get_inode_loc(inode, iloc); - if (!err) { - BUFFER_TRACE(iloc->bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, iloc->bh); - if (err) { - brelse(iloc->bh); - iloc->bh = NULL; - } - } - ext4_std_error(inode->i_sb, err); - return err; -} - -/* - * Expand an inode by new_extra_isize bytes. - * Returns 0 on success or negative error number on failure. - */ -static int ext4_expand_extra_isize(struct inode *inode, - unsigned int new_extra_isize, - struct ext4_iloc iloc, - handle_t *handle) -{ - struct ext4_inode *raw_inode; - struct ext4_xattr_ibody_header *header; - - if (EXT4_I(inode)->i_extra_isize >= new_extra_isize) - return 0; - - raw_inode = ext4_raw_inode(&iloc); - - header = IHDR(inode, raw_inode); - - /* No extended attributes present */ - if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR) || - header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC)) { - memset((void *)raw_inode + EXT4_GOOD_OLD_INODE_SIZE, 0, - new_extra_isize); - EXT4_I(inode)->i_extra_isize = new_extra_isize; - return 0; - } - - /* try to expand with EAs present */ - return ext4_expand_extra_isize_ea(inode, new_extra_isize, - raw_inode, handle); -} - -/* - * What we do here is to mark the in-core inode as clean with respect to inode - * dirtiness (it may still be data-dirty). - * This means that the in-core inode may be reaped by prune_icache - * without having to perform any I/O. This is a very good thing, - * because *any* task may call prune_icache - even ones which - * have a transaction open against a different journal. - * - * Is this cheating? Not really. Sure, we haven't written the - * inode out, but prune_icache isn't a user-visible syncing function. - * Whenever the user wants stuff synced (sys_sync, sys_msync, sys_fsync) - * we start and wait on commits. - */ -int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode) -{ - struct ext4_iloc iloc; - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - static unsigned int mnt_count; - int err, ret; - - might_sleep(); - trace_ext4_mark_inode_dirty(inode, _RET_IP_); - err = ext4_reserve_inode_write(handle, inode, &iloc); - if (err) - return err; - if (ext4_handle_valid(handle) && - EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize && - !ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND)) { - /* - * We need extra buffer credits since we may write into EA block - * with this same handle. If journal_extend fails, then it will - * only result in a minor loss of functionality for that inode. - * If this is felt to be critical, then e2fsck should be run to - * force a large enough s_min_extra_isize. - */ - if ((jbd2_journal_extend(handle, - EXT4_DATA_TRANS_BLOCKS(inode->i_sb))) == 0) { - ret = ext4_expand_extra_isize(inode, - sbi->s_want_extra_isize, - iloc, handle); - if (ret) { - if (mnt_count != - le16_to_cpu(sbi->s_es->s_mnt_count)) { - ext4_warning(inode->i_sb, - "Unable to expand inode %lu. Delete" - " some EAs or run e2fsck.", - inode->i_ino); - mnt_count = - le16_to_cpu(sbi->s_es->s_mnt_count); - } - } - } - } - return ext4_mark_iloc_dirty(handle, inode, &iloc); -} - -/* - * ext4_dirty_inode() is called from __mark_inode_dirty() - * - * We're really interested in the case where a file is being extended. - * i_size has been changed by generic_commit_write() and we thus need - * to include the updated inode in the current transaction. - * - * Also, dquot_alloc_block() will always dirty the inode when blocks - * are allocated to the file. - * - * If the inode is marked synchronous, we don't honour that here - doing - * so would cause a commit on atime updates, which we don't bother doing. - * We handle synchronous inodes at the highest possible level. - * - * If only the I_DIRTY_TIME flag is set, we can skip everything. If - * I_DIRTY_TIME and I_DIRTY_SYNC is set, the only inode fields we need - * to copy into the on-disk inode structure are the timestamp files. - */ -void ext4_dirty_inode(struct inode *inode, int flags) -{ - handle_t *handle; - - if (flags == I_DIRTY_TIME) - return; - handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); - if (IS_ERR(handle)) - goto out; - - ext4_mark_inode_dirty(handle, inode); - - ext4_journal_stop(handle); -out: - return; -} - -#if 0 -/* - * Bind an inode's backing buffer_head into this transaction, to prevent - * it from being flushed to disk early. Unlike - * ext4_reserve_inode_write, this leaves behind no bh reference and - * returns no iloc structure, so the caller needs to repeat the iloc - * lookup to mark the inode dirty later. - */ -static int ext4_pin_inode(handle_t *handle, struct inode *inode) -{ - struct ext4_iloc iloc; - - int err = 0; - if (handle) { - err = ext4_get_inode_loc(inode, &iloc); - if (!err) { - BUFFER_TRACE(iloc.bh, "get_write_access"); - err = jbd2_journal_get_write_access(handle, iloc.bh); - if (!err) - err = ext4_handle_dirty_metadata(handle, - NULL, - iloc.bh); - brelse(iloc.bh); - } - } - ext4_std_error(inode->i_sb, err); - return err; -} -#endif - -int ext4_change_inode_journal_flag(struct inode *inode, int val) -{ - journal_t *journal; - handle_t *handle; - int err; - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - - /* - * We have to be very careful here: changing a data block's - * journaling status dynamically is dangerous. If we write a - * data block to the journal, change the status and then delete - * that block, we risk forgetting to revoke the old log record - * from the journal and so a subsequent replay can corrupt data. - * So, first we make sure that the journal is empty and that - * nobody is changing anything. - */ - - journal = EXT4_JOURNAL(inode); - if (!journal) - return 0; - if (is_journal_aborted(journal)) - return -EROFS; - - /* Wait for all existing dio workers */ - ext4_inode_block_unlocked_dio(inode); - inode_dio_wait(inode); - - /* - * Before flushing the journal and switching inode's aops, we have - * to flush all dirty data the inode has. There can be outstanding - * delayed allocations, there can be unwritten extents created by - * fallocate or buffered writes in dioread_nolock mode covered by - * dirty data which can be converted only after flushing the dirty - * data (and journalled aops don't know how to handle these cases). - */ - if (val) { - down_write(&EXT4_I(inode)->i_mmap_sem); - err = filemap_write_and_wait(inode->i_mapping); - if (err < 0) { - up_write(&EXT4_I(inode)->i_mmap_sem); - ext4_inode_resume_unlocked_dio(inode); - return err; - } - } - - percpu_down_write(&sbi->s_journal_flag_rwsem); - jbd2_journal_lock_updates(journal); - - /* - * OK, there are no updates running now, and all cached data is - * synced to disk. We are now in a completely consistent state - * which doesn't have anything in the journal, and we know that - * no filesystem updates are running, so it is safe to modify - * the inode's in-core data-journaling state flag now. - */ - - if (val) - ext4_set_inode_flag(inode, EXT4_INODE_JOURNAL_DATA); - else { - err = jbd2_journal_flush(journal); - if (err < 0) { - jbd2_journal_unlock_updates(journal); - percpu_up_write(&sbi->s_journal_flag_rwsem); - ext4_inode_resume_unlocked_dio(inode); - return err; - } - ext4_clear_inode_flag(inode, EXT4_INODE_JOURNAL_DATA); - } - ext4_set_aops(inode); - - jbd2_journal_unlock_updates(journal); - percpu_up_write(&sbi->s_journal_flag_rwsem); - - if (val) - up_write(&EXT4_I(inode)->i_mmap_sem); - ext4_inode_resume_unlocked_dio(inode); - - /* Finally we can mark the inode as dirty. */ - - handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); - if (IS_ERR(handle)) - return PTR_ERR(handle); - - err = ext4_mark_inode_dirty(handle, inode); - ext4_handle_sync(handle); - ext4_journal_stop(handle); - ext4_std_error(inode->i_sb, err); - - return err; -} - -static int ext4_bh_unmapped(handle_t *handle, struct buffer_head *bh) -{ - return !buffer_mapped(bh); -} - -int ext4_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct page *page = vmf->page; - loff_t size; - unsigned long len; - int ret; - struct file *file = vma->vm_file; - struct inode *inode = file_inode(file); - struct address_space *mapping = inode->i_mapping; - handle_t *handle; - get_block_t *get_block; - int retries = 0; - - sb_start_pagefault(inode->i_sb); - file_update_time(vma->vm_file); - - down_read(&EXT4_I(inode)->i_mmap_sem); - /* Delalloc case is easy... */ - if (test_opt(inode->i_sb, DELALLOC) && - !ext4_should_journal_data(inode) && - !ext4_nonda_switch(inode->i_sb)) { - do { - ret = block_page_mkwrite(vma, vmf, - ext4_da_get_block_prep); - } while (ret == -ENOSPC && - ext4_should_retry_alloc(inode->i_sb, &retries)); - goto out_ret; - } - - lock_page(page); - size = i_size_read(inode); - /* Page got truncated from under us? */ - if (page->mapping != mapping || page_offset(page) > size) { - unlock_page(page); - ret = VM_FAULT_NOPAGE; - goto out; - } - - if (page->index == size >> PAGE_SHIFT) - len = size & ~PAGE_MASK; - else - len = PAGE_SIZE; - /* - * Return if we have all the buffers mapped. This avoids the need to do - * journal_start/journal_stop which can block and take a long time - */ - if (page_has_buffers(page)) { - if (!ext4_walk_page_buffers(NULL, page_buffers(page), - 0, len, NULL, - ext4_bh_unmapped)) { - /* Wait so that we don't change page under IO */ - wait_for_stable_page(page); - ret = VM_FAULT_LOCKED; - goto out; - } - } - unlock_page(page); - /* OK, we need to fill the hole... */ - if (ext4_should_dioread_nolock(inode)) - get_block = ext4_get_block_unwritten; - else - get_block = ext4_get_block; -retry_alloc: - handle = ext4_journal_start(inode, EXT4_HT_WRITE_PAGE, - ext4_writepage_trans_blocks(inode)); - if (IS_ERR(handle)) { - ret = VM_FAULT_SIGBUS; - goto out; - } - ret = block_page_mkwrite(vma, vmf, get_block); - if (!ret && ext4_should_journal_data(inode)) { - if (ext4_walk_page_buffers(handle, page_buffers(page), 0, - PAGE_SIZE, NULL, do_journal_get_write_access)) { - unlock_page(page); - ret = VM_FAULT_SIGBUS; - ext4_journal_stop(handle); - goto out; - } - ext4_set_inode_state(inode, EXT4_STATE_JDATA); - } - ext4_journal_stop(handle); - if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) - goto retry_alloc; -out_ret: - ret = block_page_mkwrite_return(ret); -out: - up_read(&EXT4_I(inode)->i_mmap_sem); - sb_end_pagefault(inode->i_sb); - return ret; -} - -int ext4_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct inode *inode = file_inode(vma->vm_file); - int err; - - down_read(&EXT4_I(inode)->i_mmap_sem); - err = filemap_fault(vma, vmf); - up_read(&EXT4_I(inode)->i_mmap_sem); - - return err; -} - -/* - * Find the first extent at or after @lblk in an inode that is not a hole. - * Search for @map_len blocks at most. The extent is returned in @result. - * - * The function returns 1 if we found an extent. The function returns 0 in - * case there is no extent at or after @lblk and in that case also sets - * @result->es_len to 0. In case of error, the error code is returned. - */ -int ext4_get_next_extent(struct inode *inode, ext4_lblk_t lblk, - unsigned int map_len, struct extent_status *result) -{ - struct ext4_map_blocks map; - struct extent_status es = {}; - int ret; - - map.m_lblk = lblk; - map.m_len = map_len; - - /* - * For non-extent based files this loop may iterate several times since - * we do not determine full hole size. - */ - while (map.m_len > 0) { - ret = ext4_map_blocks(NULL, inode, &map, 0); - if (ret < 0) - return ret; - /* There's extent covering m_lblk? Just return it. */ - if (ret > 0) { - int status; - - ext4_es_store_pblock(result, map.m_pblk); - result->es_lblk = map.m_lblk; - result->es_len = map.m_len; - if (map.m_flags & EXT4_MAP_UNWRITTEN) - status = EXTENT_STATUS_UNWRITTEN; - else - status = EXTENT_STATUS_WRITTEN; - ext4_es_store_status(result, status); - return 1; - } - ext4_es_find_delayed_extent_range(inode, map.m_lblk, - map.m_lblk + map.m_len - 1, - &es); - /* Is delalloc data before next block in extent tree? */ - if (es.es_len && es.es_lblk < map.m_lblk + map.m_len) { - ext4_lblk_t offset = 0; - - if (es.es_lblk < lblk) - offset = lblk - es.es_lblk; - result->es_lblk = es.es_lblk + offset; - ext4_es_store_pblock(result, - ext4_es_pblock(&es) + offset); - result->es_len = es.es_len - offset; - ext4_es_store_status(result, ext4_es_status(&es)); - - return 1; - } - /* There's a hole at m_lblk, advance us after it */ - map.m_lblk += map.m_len; - map_len -= map.m_len; - map.m_len = map_len; - cond_resched(); - } - result->es_len = 0; - return 0; -} diff --git a/src/linux/fs/ext4/ioctl.c b/src/linux/fs/ext4/ioctl.c deleted file mode 100644 index bf5ae8e..0000000 --- a/src/linux/fs/ext4/ioctl.c +++ /dev/null @@ -1,962 +0,0 @@ -/* - * linux/fs/ext4/ioctl.c - * - * Copyright (C) 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ext4_jbd2.h" -#include "ext4.h" - -/** - * Swap memory between @a and @b for @len bytes. - * - * @a: pointer to first memory area - * @b: pointer to second memory area - * @len: number of bytes to swap - * - */ -static void memswap(void *a, void *b, size_t len) -{ - unsigned char *ap, *bp; - - ap = (unsigned char *)a; - bp = (unsigned char *)b; - while (len-- > 0) { - swap(*ap, *bp); - ap++; - bp++; - } -} - -/** - * Swap i_data and associated attributes between @inode1 and @inode2. - * This function is used for the primary swap between inode1 and inode2 - * and also to revert this primary swap in case of errors. - * - * Therefore you have to make sure, that calling this method twice - * will revert all changes. - * - * @inode1: pointer to first inode - * @inode2: pointer to second inode - */ -static void swap_inode_data(struct inode *inode1, struct inode *inode2) -{ - loff_t isize; - struct ext4_inode_info *ei1; - struct ext4_inode_info *ei2; - - ei1 = EXT4_I(inode1); - ei2 = EXT4_I(inode2); - - memswap(&inode1->i_flags, &inode2->i_flags, sizeof(inode1->i_flags)); - memswap(&inode1->i_version, &inode2->i_version, - sizeof(inode1->i_version)); - memswap(&inode1->i_blocks, &inode2->i_blocks, - sizeof(inode1->i_blocks)); - memswap(&inode1->i_bytes, &inode2->i_bytes, sizeof(inode1->i_bytes)); - memswap(&inode1->i_atime, &inode2->i_atime, sizeof(inode1->i_atime)); - memswap(&inode1->i_mtime, &inode2->i_mtime, sizeof(inode1->i_mtime)); - - memswap(ei1->i_data, ei2->i_data, sizeof(ei1->i_data)); - memswap(&ei1->i_flags, &ei2->i_flags, sizeof(ei1->i_flags)); - memswap(&ei1->i_disksize, &ei2->i_disksize, sizeof(ei1->i_disksize)); - ext4_es_remove_extent(inode1, 0, EXT_MAX_BLOCKS); - ext4_es_remove_extent(inode2, 0, EXT_MAX_BLOCKS); - - isize = i_size_read(inode1); - i_size_write(inode1, i_size_read(inode2)); - i_size_write(inode2, isize); -} - -/** - * Swap the information from the given @inode and the inode - * EXT4_BOOT_LOADER_INO. It will basically swap i_data and all other - * important fields of the inodes. - * - * @sb: the super block of the filesystem - * @inode: the inode to swap with EXT4_BOOT_LOADER_INO - * - */ -static long swap_inode_boot_loader(struct super_block *sb, - struct inode *inode) -{ - handle_t *handle; - int err; - struct inode *inode_bl; - struct ext4_inode_info *ei_bl; - struct ext4_sb_info *sbi = EXT4_SB(sb); - - if (inode->i_nlink != 1 || !S_ISREG(inode->i_mode)) - return -EINVAL; - - if (!inode_owner_or_capable(inode) || !capable(CAP_SYS_ADMIN)) - return -EPERM; - - inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO); - if (IS_ERR(inode_bl)) - return PTR_ERR(inode_bl); - ei_bl = EXT4_I(inode_bl); - - filemap_flush(inode->i_mapping); - filemap_flush(inode_bl->i_mapping); - - /* Protect orig inodes against a truncate and make sure, - * that only 1 swap_inode_boot_loader is running. */ - lock_two_nondirectories(inode, inode_bl); - - truncate_inode_pages(&inode->i_data, 0); - truncate_inode_pages(&inode_bl->i_data, 0); - - /* Wait for all existing dio workers */ - ext4_inode_block_unlocked_dio(inode); - ext4_inode_block_unlocked_dio(inode_bl); - inode_dio_wait(inode); - inode_dio_wait(inode_bl); - - handle = ext4_journal_start(inode_bl, EXT4_HT_MOVE_EXTENTS, 2); - if (IS_ERR(handle)) { - err = -EINVAL; - goto journal_err_out; - } - - /* Protect extent tree against block allocations via delalloc */ - ext4_double_down_write_data_sem(inode, inode_bl); - - if (inode_bl->i_nlink == 0) { - /* this inode has never been used as a BOOT_LOADER */ - set_nlink(inode_bl, 1); - i_uid_write(inode_bl, 0); - i_gid_write(inode_bl, 0); - inode_bl->i_flags = 0; - ei_bl->i_flags = 0; - inode_bl->i_version = 1; - i_size_write(inode_bl, 0); - inode_bl->i_mode = S_IFREG; - if (ext4_has_feature_extents(sb)) { - ext4_set_inode_flag(inode_bl, EXT4_INODE_EXTENTS); - ext4_ext_tree_init(handle, inode_bl); - } else - memset(ei_bl->i_data, 0, sizeof(ei_bl->i_data)); - } - - swap_inode_data(inode, inode_bl); - - inode->i_ctime = inode_bl->i_ctime = ext4_current_time(inode); - - spin_lock(&sbi->s_next_gen_lock); - inode->i_generation = sbi->s_next_generation++; - inode_bl->i_generation = sbi->s_next_generation++; - spin_unlock(&sbi->s_next_gen_lock); - - ext4_discard_preallocations(inode); - - err = ext4_mark_inode_dirty(handle, inode); - if (err < 0) { - ext4_warning(inode->i_sb, - "couldn't mark inode #%lu dirty (err %d)", - inode->i_ino, err); - /* Revert all changes: */ - swap_inode_data(inode, inode_bl); - } else { - err = ext4_mark_inode_dirty(handle, inode_bl); - if (err < 0) { - ext4_warning(inode_bl->i_sb, - "couldn't mark inode #%lu dirty (err %d)", - inode_bl->i_ino, err); - /* Revert all changes: */ - swap_inode_data(inode, inode_bl); - ext4_mark_inode_dirty(handle, inode); - } - } - ext4_journal_stop(handle); - ext4_double_up_write_data_sem(inode, inode_bl); - -journal_err_out: - ext4_inode_resume_unlocked_dio(inode); - ext4_inode_resume_unlocked_dio(inode_bl); - unlock_two_nondirectories(inode, inode_bl); - iput(inode_bl); - return err; -} - -static int uuid_is_zero(__u8 u[16]) -{ - int i; - - for (i = 0; i < 16; i++) - if (u[i]) - return 0; - return 1; -} - -static int ext4_ioctl_setflags(struct inode *inode, - unsigned int flags) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - handle_t *handle = NULL; - int err = -EPERM, migrate = 0; - struct ext4_iloc iloc; - unsigned int oldflags, mask, i; - unsigned int jflag; - - /* Is it quota file? Do not allow user to mess with it */ - if (IS_NOQUOTA(inode)) - goto flags_out; - - oldflags = ei->i_flags; - - /* The JOURNAL_DATA flag is modifiable only by root */ - jflag = flags & EXT4_JOURNAL_DATA_FL; - - /* - * The IMMUTABLE and APPEND_ONLY flags can only be changed by - * the relevant capability. - * - * This test looks nicer. Thanks to Pauline Middelink - */ - if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) { - if (!capable(CAP_LINUX_IMMUTABLE)) - goto flags_out; - } - - /* - * The JOURNAL_DATA flag can only be changed by - * the relevant capability. - */ - if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) { - if (!capable(CAP_SYS_RESOURCE)) - goto flags_out; - } - if ((flags ^ oldflags) & EXT4_EXTENTS_FL) - migrate = 1; - - if (flags & EXT4_EOFBLOCKS_FL) { - /* we don't support adding EOFBLOCKS flag */ - if (!(oldflags & EXT4_EOFBLOCKS_FL)) { - err = -EOPNOTSUPP; - goto flags_out; - } - } else if (oldflags & EXT4_EOFBLOCKS_FL) - ext4_truncate(inode); - - handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); - if (IS_ERR(handle)) { - err = PTR_ERR(handle); - goto flags_out; - } - if (IS_SYNC(inode)) - ext4_handle_sync(handle); - err = ext4_reserve_inode_write(handle, inode, &iloc); - if (err) - goto flags_err; - - for (i = 0, mask = 1; i < 32; i++, mask <<= 1) { - if (!(mask & EXT4_FL_USER_MODIFIABLE)) - continue; - if (mask & flags) - ext4_set_inode_flag(inode, i); - else - ext4_clear_inode_flag(inode, i); - } - - ext4_set_inode_flags(inode); - inode->i_ctime = ext4_current_time(inode); - - err = ext4_mark_iloc_dirty(handle, inode, &iloc); -flags_err: - ext4_journal_stop(handle); - if (err) - goto flags_out; - - if ((jflag ^ oldflags) & (EXT4_JOURNAL_DATA_FL)) - err = ext4_change_inode_journal_flag(inode, jflag); - if (err) - goto flags_out; - if (migrate) { - if (flags & EXT4_EXTENTS_FL) - err = ext4_ext_migrate(inode); - else - err = ext4_ind_migrate(inode); - } - -flags_out: - return err; -} - -#ifdef CONFIG_QUOTA -static int ext4_ioctl_setproject(struct file *filp, __u32 projid) -{ - struct inode *inode = file_inode(filp); - struct super_block *sb = inode->i_sb; - struct ext4_inode_info *ei = EXT4_I(inode); - int err, rc; - handle_t *handle; - kprojid_t kprojid; - struct ext4_iloc iloc; - struct ext4_inode *raw_inode; - struct dquot *transfer_to[MAXQUOTAS] = { }; - - if (!ext4_has_feature_project(sb)) { - if (projid != EXT4_DEF_PROJID) - return -EOPNOTSUPP; - else - return 0; - } - - if (EXT4_INODE_SIZE(sb) <= EXT4_GOOD_OLD_INODE_SIZE) - return -EOPNOTSUPP; - - kprojid = make_kprojid(&init_user_ns, (projid_t)projid); - - if (projid_eq(kprojid, EXT4_I(inode)->i_projid)) - return 0; - - err = mnt_want_write_file(filp); - if (err) - return err; - - err = -EPERM; - inode_lock(inode); - /* Is it quota file? Do not allow user to mess with it */ - if (IS_NOQUOTA(inode)) - goto out_unlock; - - err = ext4_get_inode_loc(inode, &iloc); - if (err) - goto out_unlock; - - raw_inode = ext4_raw_inode(&iloc); - if (!EXT4_FITS_IN_INODE(raw_inode, ei, i_projid)) { - err = -EOVERFLOW; - brelse(iloc.bh); - goto out_unlock; - } - brelse(iloc.bh); - - dquot_initialize(inode); - - handle = ext4_journal_start(inode, EXT4_HT_QUOTA, - EXT4_QUOTA_INIT_BLOCKS(sb) + - EXT4_QUOTA_DEL_BLOCKS(sb) + 3); - if (IS_ERR(handle)) { - err = PTR_ERR(handle); - goto out_unlock; - } - - err = ext4_reserve_inode_write(handle, inode, &iloc); - if (err) - goto out_stop; - - transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid)); - if (!IS_ERR(transfer_to[PRJQUOTA])) { - err = __dquot_transfer(inode, transfer_to); - dqput(transfer_to[PRJQUOTA]); - if (err) - goto out_dirty; - } - - EXT4_I(inode)->i_projid = kprojid; - inode->i_ctime = ext4_current_time(inode); -out_dirty: - rc = ext4_mark_iloc_dirty(handle, inode, &iloc); - if (!err) - err = rc; -out_stop: - ext4_journal_stop(handle); -out_unlock: - inode_unlock(inode); - mnt_drop_write_file(filp); - return err; -} -#else -static int ext4_ioctl_setproject(struct file *filp, __u32 projid) -{ - if (projid != EXT4_DEF_PROJID) - return -EOPNOTSUPP; - return 0; -} -#endif - -/* Transfer internal flags to xflags */ -static inline __u32 ext4_iflags_to_xflags(unsigned long iflags) -{ - __u32 xflags = 0; - - if (iflags & EXT4_SYNC_FL) - xflags |= FS_XFLAG_SYNC; - if (iflags & EXT4_IMMUTABLE_FL) - xflags |= FS_XFLAG_IMMUTABLE; - if (iflags & EXT4_APPEND_FL) - xflags |= FS_XFLAG_APPEND; - if (iflags & EXT4_NODUMP_FL) - xflags |= FS_XFLAG_NODUMP; - if (iflags & EXT4_NOATIME_FL) - xflags |= FS_XFLAG_NOATIME; - if (iflags & EXT4_PROJINHERIT_FL) - xflags |= FS_XFLAG_PROJINHERIT; - return xflags; -} - -/* Transfer xflags flags to internal */ -static inline unsigned long ext4_xflags_to_iflags(__u32 xflags) -{ - unsigned long iflags = 0; - - if (xflags & FS_XFLAG_SYNC) - iflags |= EXT4_SYNC_FL; - if (xflags & FS_XFLAG_IMMUTABLE) - iflags |= EXT4_IMMUTABLE_FL; - if (xflags & FS_XFLAG_APPEND) - iflags |= EXT4_APPEND_FL; - if (xflags & FS_XFLAG_NODUMP) - iflags |= EXT4_NODUMP_FL; - if (xflags & FS_XFLAG_NOATIME) - iflags |= EXT4_NOATIME_FL; - if (xflags & FS_XFLAG_PROJINHERIT) - iflags |= EXT4_PROJINHERIT_FL; - - return iflags; -} - -long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - struct inode *inode = file_inode(filp); - struct super_block *sb = inode->i_sb; - struct ext4_inode_info *ei = EXT4_I(inode); - unsigned int flags; - - ext4_debug("cmd = %u, arg = %lu\n", cmd, arg); - - switch (cmd) { - case EXT4_IOC_GETFLAGS: - ext4_get_inode_flags(ei); - flags = ei->i_flags & EXT4_FL_USER_VISIBLE; - return put_user(flags, (int __user *) arg); - case EXT4_IOC_SETFLAGS: { - int err; - - if (!inode_owner_or_capable(inode)) - return -EACCES; - - if (get_user(flags, (int __user *) arg)) - return -EFAULT; - - err = mnt_want_write_file(filp); - if (err) - return err; - - flags = ext4_mask_flags(inode->i_mode, flags); - - inode_lock(inode); - err = ext4_ioctl_setflags(inode, flags); - inode_unlock(inode); - mnt_drop_write_file(filp); - return err; - } - case EXT4_IOC_GETVERSION: - case EXT4_IOC_GETVERSION_OLD: - return put_user(inode->i_generation, (int __user *) arg); - case EXT4_IOC_SETVERSION: - case EXT4_IOC_SETVERSION_OLD: { - handle_t *handle; - struct ext4_iloc iloc; - __u32 generation; - int err; - - if (!inode_owner_or_capable(inode)) - return -EPERM; - - if (ext4_has_metadata_csum(inode->i_sb)) { - ext4_warning(sb, "Setting inode version is not " - "supported with metadata_csum enabled."); - return -ENOTTY; - } - - err = mnt_want_write_file(filp); - if (err) - return err; - if (get_user(generation, (int __user *) arg)) { - err = -EFAULT; - goto setversion_out; - } - - inode_lock(inode); - handle = ext4_journal_start(inode, EXT4_HT_INODE, 1); - if (IS_ERR(handle)) { - err = PTR_ERR(handle); - goto unlock_out; - } - err = ext4_reserve_inode_write(handle, inode, &iloc); - if (err == 0) { - inode->i_ctime = ext4_current_time(inode); - inode->i_generation = generation; - err = ext4_mark_iloc_dirty(handle, inode, &iloc); - } - ext4_journal_stop(handle); - -unlock_out: - inode_unlock(inode); -setversion_out: - mnt_drop_write_file(filp); - return err; - } - case EXT4_IOC_GROUP_EXTEND: { - ext4_fsblk_t n_blocks_count; - int err, err2=0; - - err = ext4_resize_begin(sb); - if (err) - return err; - - if (get_user(n_blocks_count, (__u32 __user *)arg)) { - err = -EFAULT; - goto group_extend_out; - } - - if (ext4_has_feature_bigalloc(sb)) { - ext4_msg(sb, KERN_ERR, - "Online resizing not supported with bigalloc"); - err = -EOPNOTSUPP; - goto group_extend_out; - } - - err = mnt_want_write_file(filp); - if (err) - goto group_extend_out; - - err = ext4_group_extend(sb, EXT4_SB(sb)->s_es, n_blocks_count); - if (EXT4_SB(sb)->s_journal) { - jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); - err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); - jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); - } - if (err == 0) - err = err2; - mnt_drop_write_file(filp); -group_extend_out: - ext4_resize_end(sb); - return err; - } - - case EXT4_IOC_MOVE_EXT: { - struct move_extent me; - struct fd donor; - int err; - - if (!(filp->f_mode & FMODE_READ) || - !(filp->f_mode & FMODE_WRITE)) - return -EBADF; - - if (copy_from_user(&me, - (struct move_extent __user *)arg, sizeof(me))) - return -EFAULT; - me.moved_len = 0; - - donor = fdget(me.donor_fd); - if (!donor.file) - return -EBADF; - - if (!(donor.file->f_mode & FMODE_WRITE)) { - err = -EBADF; - goto mext_out; - } - - if (ext4_has_feature_bigalloc(sb)) { - ext4_msg(sb, KERN_ERR, - "Online defrag not supported with bigalloc"); - err = -EOPNOTSUPP; - goto mext_out; - } else if (IS_DAX(inode)) { - ext4_msg(sb, KERN_ERR, - "Online defrag not supported with DAX"); - err = -EOPNOTSUPP; - goto mext_out; - } - - err = mnt_want_write_file(filp); - if (err) - goto mext_out; - - err = ext4_move_extents(filp, donor.file, me.orig_start, - me.donor_start, me.len, &me.moved_len); - mnt_drop_write_file(filp); - - if (copy_to_user((struct move_extent __user *)arg, - &me, sizeof(me))) - err = -EFAULT; -mext_out: - fdput(donor); - return err; - } - - case EXT4_IOC_GROUP_ADD: { - struct ext4_new_group_data input; - int err, err2=0; - - err = ext4_resize_begin(sb); - if (err) - return err; - - if (copy_from_user(&input, (struct ext4_new_group_input __user *)arg, - sizeof(input))) { - err = -EFAULT; - goto group_add_out; - } - - if (ext4_has_feature_bigalloc(sb)) { - ext4_msg(sb, KERN_ERR, - "Online resizing not supported with bigalloc"); - err = -EOPNOTSUPP; - goto group_add_out; - } - - err = mnt_want_write_file(filp); - if (err) - goto group_add_out; - - err = ext4_group_add(sb, &input); - if (EXT4_SB(sb)->s_journal) { - jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); - err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); - jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); - } - if (err == 0) - err = err2; - mnt_drop_write_file(filp); - if (!err && ext4_has_group_desc_csum(sb) && - test_opt(sb, INIT_INODE_TABLE)) - err = ext4_register_li_request(sb, input.group); -group_add_out: - ext4_resize_end(sb); - return err; - } - - case EXT4_IOC_MIGRATE: - { - int err; - if (!inode_owner_or_capable(inode)) - return -EACCES; - - err = mnt_want_write_file(filp); - if (err) - return err; - /* - * inode_mutex prevent write and truncate on the file. - * Read still goes through. We take i_data_sem in - * ext4_ext_swap_inode_data before we switch the - * inode format to prevent read. - */ - inode_lock((inode)); - err = ext4_ext_migrate(inode); - inode_unlock((inode)); - mnt_drop_write_file(filp); - return err; - } - - case EXT4_IOC_ALLOC_DA_BLKS: - { - int err; - if (!inode_owner_or_capable(inode)) - return -EACCES; - - err = mnt_want_write_file(filp); - if (err) - return err; - err = ext4_alloc_da_blocks(inode); - mnt_drop_write_file(filp); - return err; - } - - case EXT4_IOC_SWAP_BOOT: - { - int err; - if (!(filp->f_mode & FMODE_WRITE)) - return -EBADF; - err = mnt_want_write_file(filp); - if (err) - return err; - err = swap_inode_boot_loader(sb, inode); - mnt_drop_write_file(filp); - return err; - } - - case EXT4_IOC_RESIZE_FS: { - ext4_fsblk_t n_blocks_count; - int err = 0, err2 = 0; - ext4_group_t o_group = EXT4_SB(sb)->s_groups_count; - - if (ext4_has_feature_bigalloc(sb)) { - ext4_msg(sb, KERN_ERR, - "Online resizing not (yet) supported with bigalloc"); - return -EOPNOTSUPP; - } - - if (copy_from_user(&n_blocks_count, (__u64 __user *)arg, - sizeof(__u64))) { - return -EFAULT; - } - - err = ext4_resize_begin(sb); - if (err) - return err; - - err = mnt_want_write_file(filp); - if (err) - goto resizefs_out; - - err = ext4_resize_fs(sb, n_blocks_count); - if (EXT4_SB(sb)->s_journal) { - jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); - err2 = jbd2_journal_flush(EXT4_SB(sb)->s_journal); - jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); - } - if (err == 0) - err = err2; - mnt_drop_write_file(filp); - if (!err && (o_group > EXT4_SB(sb)->s_groups_count) && - ext4_has_group_desc_csum(sb) && - test_opt(sb, INIT_INODE_TABLE)) - err = ext4_register_li_request(sb, o_group); - -resizefs_out: - ext4_resize_end(sb); - return err; - } - - case FITRIM: - { - struct request_queue *q = bdev_get_queue(sb->s_bdev); - struct fstrim_range range; - int ret = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (!blk_queue_discard(q)) - return -EOPNOTSUPP; - - if (copy_from_user(&range, (struct fstrim_range __user *)arg, - sizeof(range))) - return -EFAULT; - - range.minlen = max((unsigned int)range.minlen, - q->limits.discard_granularity); - ret = ext4_trim_fs(sb, &range); - if (ret < 0) - return ret; - - if (copy_to_user((struct fstrim_range __user *)arg, &range, - sizeof(range))) - return -EFAULT; - - return 0; - } - case EXT4_IOC_PRECACHE_EXTENTS: - return ext4_ext_precache(inode); - case EXT4_IOC_SET_ENCRYPTION_POLICY: { -#ifdef CONFIG_EXT4_FS_ENCRYPTION - struct fscrypt_policy policy; - - if (!ext4_has_feature_encrypt(sb)) - return -EOPNOTSUPP; - - if (copy_from_user(&policy, - (struct fscrypt_policy __user *)arg, - sizeof(policy))) - return -EFAULT; - return fscrypt_process_policy(filp, &policy); -#else - return -EOPNOTSUPP; -#endif - } - case EXT4_IOC_GET_ENCRYPTION_PWSALT: { - int err, err2; - struct ext4_sb_info *sbi = EXT4_SB(sb); - handle_t *handle; - - if (!ext4_sb_has_crypto(sb)) - return -EOPNOTSUPP; - if (uuid_is_zero(sbi->s_es->s_encrypt_pw_salt)) { - err = mnt_want_write_file(filp); - if (err) - return err; - handle = ext4_journal_start_sb(sb, EXT4_HT_MISC, 1); - if (IS_ERR(handle)) { - err = PTR_ERR(handle); - goto pwsalt_err_exit; - } - err = ext4_journal_get_write_access(handle, sbi->s_sbh); - if (err) - goto pwsalt_err_journal; - generate_random_uuid(sbi->s_es->s_encrypt_pw_salt); - err = ext4_handle_dirty_metadata(handle, NULL, - sbi->s_sbh); - pwsalt_err_journal: - err2 = ext4_journal_stop(handle); - if (err2 && !err) - err = err2; - pwsalt_err_exit: - mnt_drop_write_file(filp); - if (err) - return err; - } - if (copy_to_user((void __user *) arg, - sbi->s_es->s_encrypt_pw_salt, 16)) - return -EFAULT; - return 0; - } - case EXT4_IOC_GET_ENCRYPTION_POLICY: { -#ifdef CONFIG_EXT4_FS_ENCRYPTION - struct fscrypt_policy policy; - int err = 0; - - if (!ext4_encrypted_inode(inode)) - return -ENOENT; - err = fscrypt_get_policy(inode, &policy); - if (err) - return err; - if (copy_to_user((void __user *)arg, &policy, sizeof(policy))) - return -EFAULT; - return 0; -#else - return -EOPNOTSUPP; -#endif - } - case EXT4_IOC_FSGETXATTR: - { - struct fsxattr fa; - - memset(&fa, 0, sizeof(struct fsxattr)); - ext4_get_inode_flags(ei); - fa.fsx_xflags = ext4_iflags_to_xflags(ei->i_flags & EXT4_FL_USER_VISIBLE); - - if (ext4_has_feature_project(inode->i_sb)) { - fa.fsx_projid = (__u32)from_kprojid(&init_user_ns, - EXT4_I(inode)->i_projid); - } - - if (copy_to_user((struct fsxattr __user *)arg, - &fa, sizeof(fa))) - return -EFAULT; - return 0; - } - case EXT4_IOC_FSSETXATTR: - { - struct fsxattr fa; - int err; - - if (copy_from_user(&fa, (struct fsxattr __user *)arg, - sizeof(fa))) - return -EFAULT; - - /* Make sure caller has proper permission */ - if (!inode_owner_or_capable(inode)) - return -EACCES; - - err = mnt_want_write_file(filp); - if (err) - return err; - - flags = ext4_xflags_to_iflags(fa.fsx_xflags); - flags = ext4_mask_flags(inode->i_mode, flags); - - inode_lock(inode); - flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) | - (flags & EXT4_FL_XFLAG_VISIBLE); - err = ext4_ioctl_setflags(inode, flags); - inode_unlock(inode); - mnt_drop_write_file(filp); - if (err) - return err; - - err = ext4_ioctl_setproject(filp, fa.fsx_projid); - if (err) - return err; - - return 0; - } - default: - return -ENOTTY; - } -} - -#ifdef CONFIG_COMPAT -long ext4_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - /* These are just misnamed, they actually get/put from/to user an int */ - switch (cmd) { - case EXT4_IOC32_GETFLAGS: - cmd = EXT4_IOC_GETFLAGS; - break; - case EXT4_IOC32_SETFLAGS: - cmd = EXT4_IOC_SETFLAGS; - break; - case EXT4_IOC32_GETVERSION: - cmd = EXT4_IOC_GETVERSION; - break; - case EXT4_IOC32_SETVERSION: - cmd = EXT4_IOC_SETVERSION; - break; - case EXT4_IOC32_GROUP_EXTEND: - cmd = EXT4_IOC_GROUP_EXTEND; - break; - case EXT4_IOC32_GETVERSION_OLD: - cmd = EXT4_IOC_GETVERSION_OLD; - break; - case EXT4_IOC32_SETVERSION_OLD: - cmd = EXT4_IOC_SETVERSION_OLD; - break; - case EXT4_IOC32_GETRSVSZ: - cmd = EXT4_IOC_GETRSVSZ; - break; - case EXT4_IOC32_SETRSVSZ: - cmd = EXT4_IOC_SETRSVSZ; - break; - case EXT4_IOC32_GROUP_ADD: { - struct compat_ext4_new_group_input __user *uinput; - struct ext4_new_group_input input; - mm_segment_t old_fs; - int err; - - uinput = compat_ptr(arg); - err = get_user(input.group, &uinput->group); - err |= get_user(input.block_bitmap, &uinput->block_bitmap); - err |= get_user(input.inode_bitmap, &uinput->inode_bitmap); - err |= get_user(input.inode_table, &uinput->inode_table); - err |= get_user(input.blocks_count, &uinput->blocks_count); - err |= get_user(input.reserved_blocks, - &uinput->reserved_blocks); - if (err) - return -EFAULT; - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = ext4_ioctl(file, EXT4_IOC_GROUP_ADD, - (unsigned long) &input); - set_fs(old_fs); - return err; - } - case EXT4_IOC_MOVE_EXT: - case EXT4_IOC_RESIZE_FS: - case EXT4_IOC_PRECACHE_EXTENTS: - case EXT4_IOC_SET_ENCRYPTION_POLICY: - case EXT4_IOC_GET_ENCRYPTION_PWSALT: - case EXT4_IOC_GET_ENCRYPTION_POLICY: - break; - default: - return -ENOIOCTLCMD; - } - return ext4_ioctl(file, cmd, (unsigned long) compat_ptr(arg)); -} -#endif diff --git a/src/linux/fs/ext4/mballoc.c b/src/linux/fs/ext4/mballoc.c deleted file mode 100644 index f418f55..0000000 --- a/src/linux/fs/ext4/mballoc.c +++ /dev/null @@ -1,5260 +0,0 @@ -/* - * Copyright (c) 2003-2006, Cluster File Systems, Inc, info@clusterfs.com - * Written by Alex Tomas - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- - */ - - -/* - * mballoc.c contains the multiblocks allocation routines - */ - -#include "ext4_jbd2.h" -#include "mballoc.h" -#include -#include -#include -#include -#include - -#ifdef CONFIG_EXT4_DEBUG -ushort ext4_mballoc_debug __read_mostly; - -module_param_named(mballoc_debug, ext4_mballoc_debug, ushort, 0644); -MODULE_PARM_DESC(mballoc_debug, "Debugging level for ext4's mballoc"); -#endif - -/* - * MUSTDO: - * - test ext4_ext_search_left() and ext4_ext_search_right() - * - search for metadata in few groups - * - * TODO v4: - * - normalization should take into account whether file is still open - * - discard preallocations if no free space left (policy?) - * - don't normalize tails - * - quota - * - reservation for superuser - * - * TODO v3: - * - bitmap read-ahead (proposed by Oleg Drokin aka green) - * - track min/max extents in each group for better group selection - * - mb_mark_used() may allocate chunk right after splitting buddy - * - tree of groups sorted by number of free blocks - * - error handling - */ - -/* - * The allocation request involve request for multiple number of blocks - * near to the goal(block) value specified. - * - * During initialization phase of the allocator we decide to use the - * group preallocation or inode preallocation depending on the size of - * the file. The size of the file could be the resulting file size we - * would have after allocation, or the current file size, which ever - * is larger. If the size is less than sbi->s_mb_stream_request we - * select to use the group preallocation. The default value of - * s_mb_stream_request is 16 blocks. This can also be tuned via - * /sys/fs/ext4//mb_stream_req. The value is represented in - * terms of number of blocks. - * - * The main motivation for having small file use group preallocation is to - * ensure that we have small files closer together on the disk. - * - * First stage the allocator looks at the inode prealloc list, - * ext4_inode_info->i_prealloc_list, which contains list of prealloc - * spaces for this particular inode. The inode prealloc space is - * represented as: - * - * pa_lstart -> the logical start block for this prealloc space - * pa_pstart -> the physical start block for this prealloc space - * pa_len -> length for this prealloc space (in clusters) - * pa_free -> free space available in this prealloc space (in clusters) - * - * The inode preallocation space is used looking at the _logical_ start - * block. If only the logical file block falls within the range of prealloc - * space we will consume the particular prealloc space. This makes sure that - * we have contiguous physical blocks representing the file blocks - * - * The important thing to be noted in case of inode prealloc space is that - * we don't modify the values associated to inode prealloc space except - * pa_free. - * - * If we are not able to find blocks in the inode prealloc space and if we - * have the group allocation flag set then we look at the locality group - * prealloc space. These are per CPU prealloc list represented as - * - * ext4_sb_info.s_locality_groups[smp_processor_id()] - * - * The reason for having a per cpu locality group is to reduce the contention - * between CPUs. It is possible to get scheduled at this point. - * - * The locality group prealloc space is used looking at whether we have - * enough free space (pa_free) within the prealloc space. - * - * If we can't allocate blocks via inode prealloc or/and locality group - * prealloc then we look at the buddy cache. The buddy cache is represented - * by ext4_sb_info.s_buddy_cache (struct inode) whose file offset gets - * mapped to the buddy and bitmap information regarding different - * groups. The buddy information is attached to buddy cache inode so that - * we can access them through the page cache. The information regarding - * each group is loaded via ext4_mb_load_buddy. The information involve - * block bitmap and buddy information. The information are stored in the - * inode as: - * - * { page } - * [ group 0 bitmap][ group 0 buddy] [group 1][ group 1]... - * - * - * one block each for bitmap and buddy information. So for each group we - * take up 2 blocks. A page can contain blocks_per_page (PAGE_SIZE / - * blocksize) blocks. So it can have information regarding groups_per_page - * which is blocks_per_page/2 - * - * The buddy cache inode is not stored on disk. The inode is thrown - * away when the filesystem is unmounted. - * - * We look for count number of blocks in the buddy cache. If we were able - * to locate that many free blocks we return with additional information - * regarding rest of the contiguous physical block available - * - * Before allocating blocks via buddy cache we normalize the request - * blocks. This ensure we ask for more blocks that we needed. The extra - * blocks that we get after allocation is added to the respective prealloc - * list. In case of inode preallocation we follow a list of heuristics - * based on file size. This can be found in ext4_mb_normalize_request. If - * we are doing a group prealloc we try to normalize the request to - * sbi->s_mb_group_prealloc. The default value of s_mb_group_prealloc is - * dependent on the cluster size; for non-bigalloc file systems, it is - * 512 blocks. This can be tuned via - * /sys/fs/ext4//mb_group_prealloc. The value is represented in - * terms of number of blocks. If we have mounted the file system with -O - * stripe= option the group prealloc request is normalized to the - * the smallest multiple of the stripe value (sbi->s_stripe) which is - * greater than the default mb_group_prealloc. - * - * The regular allocator (using the buddy cache) supports a few tunables. - * - * /sys/fs/ext4//mb_min_to_scan - * /sys/fs/ext4//mb_max_to_scan - * /sys/fs/ext4//mb_order2_req - * - * The regular allocator uses buddy scan only if the request len is power of - * 2 blocks and the order of allocation is >= sbi->s_mb_order2_reqs. The - * value of s_mb_order2_reqs can be tuned via - * /sys/fs/ext4//mb_order2_req. If the request len is equal to - * stripe size (sbi->s_stripe), we try to search for contiguous block in - * stripe size. This should result in better allocation on RAID setups. If - * not, we search in the specific group using bitmap for best extents. The - * tunable min_to_scan and max_to_scan control the behaviour here. - * min_to_scan indicate how long the mballoc __must__ look for a best - * extent and max_to_scan indicates how long the mballoc __can__ look for a - * best extent in the found extents. Searching for the blocks starts with - * the group specified as the goal value in allocation context via - * ac_g_ex. Each group is first checked based on the criteria whether it - * can be used for allocation. ext4_mb_good_group explains how the groups are - * checked. - * - * Both the prealloc space are getting populated as above. So for the first - * request we will hit the buddy cache which will result in this prealloc - * space getting filled. The prealloc space is then later used for the - * subsequent request. - */ - -/* - * mballoc operates on the following data: - * - on-disk bitmap - * - in-core buddy (actually includes buddy and bitmap) - * - preallocation descriptors (PAs) - * - * there are two types of preallocations: - * - inode - * assiged to specific inode and can be used for this inode only. - * it describes part of inode's space preallocated to specific - * physical blocks. any block from that preallocated can be used - * independent. the descriptor just tracks number of blocks left - * unused. so, before taking some block from descriptor, one must - * make sure corresponded logical block isn't allocated yet. this - * also means that freeing any block within descriptor's range - * must discard all preallocated blocks. - * - locality group - * assigned to specific locality group which does not translate to - * permanent set of inodes: inode can join and leave group. space - * from this type of preallocation can be used for any inode. thus - * it's consumed from the beginning to the end. - * - * relation between them can be expressed as: - * in-core buddy = on-disk bitmap + preallocation descriptors - * - * this mean blocks mballoc considers used are: - * - allocated blocks (persistent) - * - preallocated blocks (non-persistent) - * - * consistency in mballoc world means that at any time a block is either - * free or used in ALL structures. notice: "any time" should not be read - * literally -- time is discrete and delimited by locks. - * - * to keep it simple, we don't use block numbers, instead we count number of - * blocks: how many blocks marked used/free in on-disk bitmap, buddy and PA. - * - * all operations can be expressed as: - * - init buddy: buddy = on-disk + PAs - * - new PA: buddy += N; PA = N - * - use inode PA: on-disk += N; PA -= N - * - discard inode PA buddy -= on-disk - PA; PA = 0 - * - use locality group PA on-disk += N; PA -= N - * - discard locality group PA buddy -= PA; PA = 0 - * note: 'buddy -= on-disk - PA' is used to show that on-disk bitmap - * is used in real operation because we can't know actual used - * bits from PA, only from on-disk bitmap - * - * if we follow this strict logic, then all operations above should be atomic. - * given some of them can block, we'd have to use something like semaphores - * killing performance on high-end SMP hardware. let's try to relax it using - * the following knowledge: - * 1) if buddy is referenced, it's already initialized - * 2) while block is used in buddy and the buddy is referenced, - * nobody can re-allocate that block - * 3) we work on bitmaps and '+' actually means 'set bits'. if on-disk has - * bit set and PA claims same block, it's OK. IOW, one can set bit in - * on-disk bitmap if buddy has same bit set or/and PA covers corresponded - * block - * - * so, now we're building a concurrency table: - * - init buddy vs. - * - new PA - * blocks for PA are allocated in the buddy, buddy must be referenced - * until PA is linked to allocation group to avoid concurrent buddy init - * - use inode PA - * we need to make sure that either on-disk bitmap or PA has uptodate data - * given (3) we care that PA-=N operation doesn't interfere with init - * - discard inode PA - * the simplest way would be to have buddy initialized by the discard - * - use locality group PA - * again PA-=N must be serialized with init - * - discard locality group PA - * the simplest way would be to have buddy initialized by the discard - * - new PA vs. - * - use inode PA - * i_data_sem serializes them - * - discard inode PA - * discard process must wait until PA isn't used by another process - * - use locality group PA - * some mutex should serialize them - * - discard locality group PA - * discard process must wait until PA isn't used by another process - * - use inode PA - * - use inode PA - * i_data_sem or another mutex should serializes them - * - discard inode PA - * discard process must wait until PA isn't used by another process - * - use locality group PA - * nothing wrong here -- they're different PAs covering different blocks - * - discard locality group PA - * discard process must wait until PA isn't used by another process - * - * now we're ready to make few consequences: - * - PA is referenced and while it is no discard is possible - * - PA is referenced until block isn't marked in on-disk bitmap - * - PA changes only after on-disk bitmap - * - discard must not compete with init. either init is done before - * any discard or they're serialized somehow - * - buddy init as sum of on-disk bitmap and PAs is done atomically - * - * a special case when we've used PA to emptiness. no need to modify buddy - * in this case, but we should care about concurrent init - * - */ - - /* - * Logic in few words: - * - * - allocation: - * load group - * find blocks - * mark bits in on-disk bitmap - * release group - * - * - use preallocation: - * find proper PA (per-inode or group) - * load group - * mark bits in on-disk bitmap - * release group - * release PA - * - * - free: - * load group - * mark bits in on-disk bitmap - * release group - * - * - discard preallocations in group: - * mark PAs deleted - * move them onto local list - * load on-disk bitmap - * load group - * remove PA from object (inode or locality group) - * mark free blocks in-core - * - * - discard inode's preallocations: - */ - -/* - * Locking rules - * - * Locks: - * - bitlock on a group (group) - * - object (inode/locality) (object) - * - per-pa lock (pa) - * - * Paths: - * - new pa - * object - * group - * - * - find and use pa: - * pa - * - * - release consumed pa: - * pa - * group - * object - * - * - generate in-core bitmap: - * group - * pa - * - * - discard all for given object (inode, locality group): - * object - * pa - * group - * - * - discard all for given group: - * group - * pa - * group - * object - * - */ -static struct kmem_cache *ext4_pspace_cachep; -static struct kmem_cache *ext4_ac_cachep; -static struct kmem_cache *ext4_free_data_cachep; - -/* We create slab caches for groupinfo data structures based on the - * superblock block size. There will be one per mounted filesystem for - * each unique s_blocksize_bits */ -#define NR_GRPINFO_CACHES 8 -static struct kmem_cache *ext4_groupinfo_caches[NR_GRPINFO_CACHES]; - -static const char *ext4_groupinfo_slab_names[NR_GRPINFO_CACHES] = { - "ext4_groupinfo_1k", "ext4_groupinfo_2k", "ext4_groupinfo_4k", - "ext4_groupinfo_8k", "ext4_groupinfo_16k", "ext4_groupinfo_32k", - "ext4_groupinfo_64k", "ext4_groupinfo_128k" -}; - -static void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap, - ext4_group_t group); -static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap, - ext4_group_t group); -static void ext4_free_data_callback(struct super_block *sb, - struct ext4_journal_cb_entry *jce, int rc); - -static inline void *mb_correct_addr_and_bit(int *bit, void *addr) -{ -#if BITS_PER_LONG == 64 - *bit += ((unsigned long) addr & 7UL) << 3; - addr = (void *) ((unsigned long) addr & ~7UL); -#elif BITS_PER_LONG == 32 - *bit += ((unsigned long) addr & 3UL) << 3; - addr = (void *) ((unsigned long) addr & ~3UL); -#else -#error "how many bits you are?!" -#endif - return addr; -} - -static inline int mb_test_bit(int bit, void *addr) -{ - /* - * ext4_test_bit on architecture like powerpc - * needs unsigned long aligned address - */ - addr = mb_correct_addr_and_bit(&bit, addr); - return ext4_test_bit(bit, addr); -} - -static inline void mb_set_bit(int bit, void *addr) -{ - addr = mb_correct_addr_and_bit(&bit, addr); - ext4_set_bit(bit, addr); -} - -static inline void mb_clear_bit(int bit, void *addr) -{ - addr = mb_correct_addr_and_bit(&bit, addr); - ext4_clear_bit(bit, addr); -} - -static inline int mb_test_and_clear_bit(int bit, void *addr) -{ - addr = mb_correct_addr_and_bit(&bit, addr); - return ext4_test_and_clear_bit(bit, addr); -} - -static inline int mb_find_next_zero_bit(void *addr, int max, int start) -{ - int fix = 0, ret, tmpmax; - addr = mb_correct_addr_and_bit(&fix, addr); - tmpmax = max + fix; - start += fix; - - ret = ext4_find_next_zero_bit(addr, tmpmax, start) - fix; - if (ret > max) - return max; - return ret; -} - -static inline int mb_find_next_bit(void *addr, int max, int start) -{ - int fix = 0, ret, tmpmax; - addr = mb_correct_addr_and_bit(&fix, addr); - tmpmax = max + fix; - start += fix; - - ret = ext4_find_next_bit(addr, tmpmax, start) - fix; - if (ret > max) - return max; - return ret; -} - -static void *mb_find_buddy(struct ext4_buddy *e4b, int order, int *max) -{ - char *bb; - - BUG_ON(e4b->bd_bitmap == e4b->bd_buddy); - BUG_ON(max == NULL); - - if (order > e4b->bd_blkbits + 1) { - *max = 0; - return NULL; - } - - /* at order 0 we see each particular block */ - if (order == 0) { - *max = 1 << (e4b->bd_blkbits + 3); - return e4b->bd_bitmap; - } - - bb = e4b->bd_buddy + EXT4_SB(e4b->bd_sb)->s_mb_offsets[order]; - *max = EXT4_SB(e4b->bd_sb)->s_mb_maxs[order]; - - return bb; -} - -#ifdef DOUBLE_CHECK -static void mb_free_blocks_double(struct inode *inode, struct ext4_buddy *e4b, - int first, int count) -{ - int i; - struct super_block *sb = e4b->bd_sb; - - if (unlikely(e4b->bd_info->bb_bitmap == NULL)) - return; - assert_spin_locked(ext4_group_lock_ptr(sb, e4b->bd_group)); - for (i = 0; i < count; i++) { - if (!mb_test_bit(first + i, e4b->bd_info->bb_bitmap)) { - ext4_fsblk_t blocknr; - - blocknr = ext4_group_first_block_no(sb, e4b->bd_group); - blocknr += EXT4_C2B(EXT4_SB(sb), first + i); - ext4_grp_locked_error(sb, e4b->bd_group, - inode ? inode->i_ino : 0, - blocknr, - "freeing block already freed " - "(bit %u)", - first + i); - } - mb_clear_bit(first + i, e4b->bd_info->bb_bitmap); - } -} - -static void mb_mark_used_double(struct ext4_buddy *e4b, int first, int count) -{ - int i; - - if (unlikely(e4b->bd_info->bb_bitmap == NULL)) - return; - assert_spin_locked(ext4_group_lock_ptr(e4b->bd_sb, e4b->bd_group)); - for (i = 0; i < count; i++) { - BUG_ON(mb_test_bit(first + i, e4b->bd_info->bb_bitmap)); - mb_set_bit(first + i, e4b->bd_info->bb_bitmap); - } -} - -static void mb_cmp_bitmaps(struct ext4_buddy *e4b, void *bitmap) -{ - if (memcmp(e4b->bd_info->bb_bitmap, bitmap, e4b->bd_sb->s_blocksize)) { - unsigned char *b1, *b2; - int i; - b1 = (unsigned char *) e4b->bd_info->bb_bitmap; - b2 = (unsigned char *) bitmap; - for (i = 0; i < e4b->bd_sb->s_blocksize; i++) { - if (b1[i] != b2[i]) { - ext4_msg(e4b->bd_sb, KERN_ERR, - "corruption in group %u " - "at byte %u(%u): %x in copy != %x " - "on disk/prealloc", - e4b->bd_group, i, i * 8, b1[i], b2[i]); - BUG(); - } - } - } -} - -#else -static inline void mb_free_blocks_double(struct inode *inode, - struct ext4_buddy *e4b, int first, int count) -{ - return; -} -static inline void mb_mark_used_double(struct ext4_buddy *e4b, - int first, int count) -{ - return; -} -static inline void mb_cmp_bitmaps(struct ext4_buddy *e4b, void *bitmap) -{ - return; -} -#endif - -#ifdef AGGRESSIVE_CHECK - -#define MB_CHECK_ASSERT(assert) \ -do { \ - if (!(assert)) { \ - printk(KERN_EMERG \ - "Assertion failure in %s() at %s:%d: \"%s\"\n", \ - function, file, line, # assert); \ - BUG(); \ - } \ -} while (0) - -static int __mb_check_buddy(struct ext4_buddy *e4b, char *file, - const char *function, int line) -{ - struct super_block *sb = e4b->bd_sb; - int order = e4b->bd_blkbits + 1; - int max; - int max2; - int i; - int j; - int k; - int count; - struct ext4_group_info *grp; - int fragments = 0; - int fstart; - struct list_head *cur; - void *buddy; - void *buddy2; - - { - static int mb_check_counter; - if (mb_check_counter++ % 100 != 0) - return 0; - } - - while (order > 1) { - buddy = mb_find_buddy(e4b, order, &max); - MB_CHECK_ASSERT(buddy); - buddy2 = mb_find_buddy(e4b, order - 1, &max2); - MB_CHECK_ASSERT(buddy2); - MB_CHECK_ASSERT(buddy != buddy2); - MB_CHECK_ASSERT(max * 2 == max2); - - count = 0; - for (i = 0; i < max; i++) { - - if (mb_test_bit(i, buddy)) { - /* only single bit in buddy2 may be 1 */ - if (!mb_test_bit(i << 1, buddy2)) { - MB_CHECK_ASSERT( - mb_test_bit((i<<1)+1, buddy2)); - } else if (!mb_test_bit((i << 1) + 1, buddy2)) { - MB_CHECK_ASSERT( - mb_test_bit(i << 1, buddy2)); - } - continue; - } - - /* both bits in buddy2 must be 1 */ - MB_CHECK_ASSERT(mb_test_bit(i << 1, buddy2)); - MB_CHECK_ASSERT(mb_test_bit((i << 1) + 1, buddy2)); - - for (j = 0; j < (1 << order); j++) { - k = (i * (1 << order)) + j; - MB_CHECK_ASSERT( - !mb_test_bit(k, e4b->bd_bitmap)); - } - count++; - } - MB_CHECK_ASSERT(e4b->bd_info->bb_counters[order] == count); - order--; - } - - fstart = -1; - buddy = mb_find_buddy(e4b, 0, &max); - for (i = 0; i < max; i++) { - if (!mb_test_bit(i, buddy)) { - MB_CHECK_ASSERT(i >= e4b->bd_info->bb_first_free); - if (fstart == -1) { - fragments++; - fstart = i; - } - continue; - } - fstart = -1; - /* check used bits only */ - for (j = 0; j < e4b->bd_blkbits + 1; j++) { - buddy2 = mb_find_buddy(e4b, j, &max2); - k = i >> j; - MB_CHECK_ASSERT(k < max2); - MB_CHECK_ASSERT(mb_test_bit(k, buddy2)); - } - } - MB_CHECK_ASSERT(!EXT4_MB_GRP_NEED_INIT(e4b->bd_info)); - MB_CHECK_ASSERT(e4b->bd_info->bb_fragments == fragments); - - grp = ext4_get_group_info(sb, e4b->bd_group); - list_for_each(cur, &grp->bb_prealloc_list) { - ext4_group_t groupnr; - struct ext4_prealloc_space *pa; - pa = list_entry(cur, struct ext4_prealloc_space, pa_group_list); - ext4_get_group_no_and_offset(sb, pa->pa_pstart, &groupnr, &k); - MB_CHECK_ASSERT(groupnr == e4b->bd_group); - for (i = 0; i < pa->pa_len; i++) - MB_CHECK_ASSERT(mb_test_bit(k + i, buddy)); - } - return 0; -} -#undef MB_CHECK_ASSERT -#define mb_check_buddy(e4b) __mb_check_buddy(e4b, \ - __FILE__, __func__, __LINE__) -#else -#define mb_check_buddy(e4b) -#endif - -/* - * Divide blocks started from @first with length @len into - * smaller chunks with power of 2 blocks. - * Clear the bits in bitmap which the blocks of the chunk(s) covered, - * then increase bb_counters[] for corresponded chunk size. - */ -static void ext4_mb_mark_free_simple(struct super_block *sb, - void *buddy, ext4_grpblk_t first, ext4_grpblk_t len, - struct ext4_group_info *grp) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - ext4_grpblk_t min; - ext4_grpblk_t max; - ext4_grpblk_t chunk; - unsigned short border; - - BUG_ON(len > EXT4_CLUSTERS_PER_GROUP(sb)); - - border = 2 << sb->s_blocksize_bits; - - while (len > 0) { - /* find how many blocks can be covered since this position */ - max = ffs(first | border) - 1; - - /* find how many blocks of power 2 we need to mark */ - min = fls(len) - 1; - - if (max < min) - min = max; - chunk = 1 << min; - - /* mark multiblock chunks only */ - grp->bb_counters[min]++; - if (min > 0) - mb_clear_bit(first >> min, - buddy + sbi->s_mb_offsets[min]); - - len -= chunk; - first += chunk; - } -} - -/* - * Cache the order of the largest free extent we have available in this block - * group. - */ -static void -mb_set_largest_free_order(struct super_block *sb, struct ext4_group_info *grp) -{ - int i; - int bits; - - grp->bb_largest_free_order = -1; /* uninit */ - - bits = sb->s_blocksize_bits + 1; - for (i = bits; i >= 0; i--) { - if (grp->bb_counters[i] > 0) { - grp->bb_largest_free_order = i; - break; - } - } -} - -static noinline_for_stack -void ext4_mb_generate_buddy(struct super_block *sb, - void *buddy, void *bitmap, ext4_group_t group) -{ - struct ext4_group_info *grp = ext4_get_group_info(sb, group); - struct ext4_sb_info *sbi = EXT4_SB(sb); - ext4_grpblk_t max = EXT4_CLUSTERS_PER_GROUP(sb); - ext4_grpblk_t i = 0; - ext4_grpblk_t first; - ext4_grpblk_t len; - unsigned free = 0; - unsigned fragments = 0; - unsigned long long period = get_cycles(); - - /* initialize buddy from bitmap which is aggregation - * of on-disk bitmap and preallocations */ - i = mb_find_next_zero_bit(bitmap, max, 0); - grp->bb_first_free = i; - while (i < max) { - fragments++; - first = i; - i = mb_find_next_bit(bitmap, max, i); - len = i - first; - free += len; - if (len > 1) - ext4_mb_mark_free_simple(sb, buddy, first, len, grp); - else - grp->bb_counters[0]++; - if (i < max) - i = mb_find_next_zero_bit(bitmap, max, i); - } - grp->bb_fragments = fragments; - - if (free != grp->bb_free) { - ext4_grp_locked_error(sb, group, 0, 0, - "block bitmap and bg descriptor " - "inconsistent: %u vs %u free clusters", - free, grp->bb_free); - /* - * If we intend to continue, we consider group descriptor - * corrupt and update bb_free using bitmap value - */ - grp->bb_free = free; - if (!EXT4_MB_GRP_BBITMAP_CORRUPT(grp)) - percpu_counter_sub(&sbi->s_freeclusters_counter, - grp->bb_free); - set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &grp->bb_state); - } - mb_set_largest_free_order(sb, grp); - - clear_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &(grp->bb_state)); - - period = get_cycles() - period; - spin_lock(&EXT4_SB(sb)->s_bal_lock); - EXT4_SB(sb)->s_mb_buddies_generated++; - EXT4_SB(sb)->s_mb_generation_time += period; - spin_unlock(&EXT4_SB(sb)->s_bal_lock); -} - -static void mb_regenerate_buddy(struct ext4_buddy *e4b) -{ - int count; - int order = 1; - void *buddy; - - while ((buddy = mb_find_buddy(e4b, order++, &count))) { - ext4_set_bits(buddy, 0, count); - } - e4b->bd_info->bb_fragments = 0; - memset(e4b->bd_info->bb_counters, 0, - sizeof(*e4b->bd_info->bb_counters) * - (e4b->bd_sb->s_blocksize_bits + 2)); - - ext4_mb_generate_buddy(e4b->bd_sb, e4b->bd_buddy, - e4b->bd_bitmap, e4b->bd_group); -} - -/* The buddy information is attached the buddy cache inode - * for convenience. The information regarding each group - * is loaded via ext4_mb_load_buddy. The information involve - * block bitmap and buddy information. The information are - * stored in the inode as - * - * { page } - * [ group 0 bitmap][ group 0 buddy] [group 1][ group 1]... - * - * - * one block each for bitmap and buddy information. - * So for each group we take up 2 blocks. A page can - * contain blocks_per_page (PAGE_SIZE / blocksize) blocks. - * So it can have information regarding groups_per_page which - * is blocks_per_page/2 - * - * Locking note: This routine takes the block group lock of all groups - * for this page; do not hold this lock when calling this routine! - */ - -static int ext4_mb_init_cache(struct page *page, char *incore, gfp_t gfp) -{ - ext4_group_t ngroups; - int blocksize; - int blocks_per_page; - int groups_per_page; - int err = 0; - int i; - ext4_group_t first_group, group; - int first_block; - struct super_block *sb; - struct buffer_head *bhs; - struct buffer_head **bh = NULL; - struct inode *inode; - char *data; - char *bitmap; - struct ext4_group_info *grinfo; - - mb_debug(1, "init page %lu\n", page->index); - - inode = page->mapping->host; - sb = inode->i_sb; - ngroups = ext4_get_groups_count(sb); - blocksize = 1 << inode->i_blkbits; - blocks_per_page = PAGE_SIZE / blocksize; - - groups_per_page = blocks_per_page >> 1; - if (groups_per_page == 0) - groups_per_page = 1; - - /* allocate buffer_heads to read bitmaps */ - if (groups_per_page > 1) { - i = sizeof(struct buffer_head *) * groups_per_page; - bh = kzalloc(i, gfp); - if (bh == NULL) { - err = -ENOMEM; - goto out; - } - } else - bh = &bhs; - - first_group = page->index * blocks_per_page / 2; - - /* read all groups the page covers into the cache */ - for (i = 0, group = first_group; i < groups_per_page; i++, group++) { - if (group >= ngroups) - break; - - grinfo = ext4_get_group_info(sb, group); - /* - * If page is uptodate then we came here after online resize - * which added some new uninitialized group info structs, so - * we must skip all initialized uptodate buddies on the page, - * which may be currently in use by an allocating task. - */ - if (PageUptodate(page) && !EXT4_MB_GRP_NEED_INIT(grinfo)) { - bh[i] = NULL; - continue; - } - bh[i] = ext4_read_block_bitmap_nowait(sb, group); - if (IS_ERR(bh[i])) { - err = PTR_ERR(bh[i]); - bh[i] = NULL; - goto out; - } - mb_debug(1, "read bitmap for group %u\n", group); - } - - /* wait for I/O completion */ - for (i = 0, group = first_group; i < groups_per_page; i++, group++) { - int err2; - - if (!bh[i]) - continue; - err2 = ext4_wait_block_bitmap(sb, group, bh[i]); - if (!err) - err = err2; - } - - first_block = page->index * blocks_per_page; - for (i = 0; i < blocks_per_page; i++) { - group = (first_block + i) >> 1; - if (group >= ngroups) - break; - - if (!bh[group - first_group]) - /* skip initialized uptodate buddy */ - continue; - - if (!buffer_verified(bh[group - first_group])) - /* Skip faulty bitmaps */ - continue; - err = 0; - - /* - * data carry information regarding this - * particular group in the format specified - * above - * - */ - data = page_address(page) + (i * blocksize); - bitmap = bh[group - first_group]->b_data; - - /* - * We place the buddy block and bitmap block - * close together - */ - if ((first_block + i) & 1) { - /* this is block of buddy */ - BUG_ON(incore == NULL); - mb_debug(1, "put buddy for group %u in page %lu/%x\n", - group, page->index, i * blocksize); - trace_ext4_mb_buddy_bitmap_load(sb, group); - grinfo = ext4_get_group_info(sb, group); - grinfo->bb_fragments = 0; - memset(grinfo->bb_counters, 0, - sizeof(*grinfo->bb_counters) * - (sb->s_blocksize_bits+2)); - /* - * incore got set to the group block bitmap below - */ - ext4_lock_group(sb, group); - /* init the buddy */ - memset(data, 0xff, blocksize); - ext4_mb_generate_buddy(sb, data, incore, group); - ext4_unlock_group(sb, group); - incore = NULL; - } else { - /* this is block of bitmap */ - BUG_ON(incore != NULL); - mb_debug(1, "put bitmap for group %u in page %lu/%x\n", - group, page->index, i * blocksize); - trace_ext4_mb_bitmap_load(sb, group); - - /* see comments in ext4_mb_put_pa() */ - ext4_lock_group(sb, group); - memcpy(data, bitmap, blocksize); - - /* mark all preallocated blks used in in-core bitmap */ - ext4_mb_generate_from_pa(sb, data, group); - ext4_mb_generate_from_freelist(sb, data, group); - ext4_unlock_group(sb, group); - - /* set incore so that the buddy information can be - * generated using this - */ - incore = data; - } - } - SetPageUptodate(page); - -out: - if (bh) { - for (i = 0; i < groups_per_page; i++) - brelse(bh[i]); - if (bh != &bhs) - kfree(bh); - } - return err; -} - -/* - * Lock the buddy and bitmap pages. This make sure other parallel init_group - * on the same buddy page doesn't happen whild holding the buddy page lock. - * Return locked buddy and bitmap pages on e4b struct. If buddy and bitmap - * are on the same page e4b->bd_buddy_page is NULL and return value is 0. - */ -static int ext4_mb_get_buddy_page_lock(struct super_block *sb, - ext4_group_t group, struct ext4_buddy *e4b, gfp_t gfp) -{ - struct inode *inode = EXT4_SB(sb)->s_buddy_cache; - int block, pnum, poff; - int blocks_per_page; - struct page *page; - - e4b->bd_buddy_page = NULL; - e4b->bd_bitmap_page = NULL; - - blocks_per_page = PAGE_SIZE / sb->s_blocksize; - /* - * the buddy cache inode stores the block bitmap - * and buddy information in consecutive blocks. - * So for each group we need two blocks. - */ - block = group * 2; - pnum = block / blocks_per_page; - poff = block % blocks_per_page; - page = find_or_create_page(inode->i_mapping, pnum, gfp); - if (!page) - return -ENOMEM; - BUG_ON(page->mapping != inode->i_mapping); - e4b->bd_bitmap_page = page; - e4b->bd_bitmap = page_address(page) + (poff * sb->s_blocksize); - - if (blocks_per_page >= 2) { - /* buddy and bitmap are on the same page */ - return 0; - } - - block++; - pnum = block / blocks_per_page; - page = find_or_create_page(inode->i_mapping, pnum, gfp); - if (!page) - return -ENOMEM; - BUG_ON(page->mapping != inode->i_mapping); - e4b->bd_buddy_page = page; - return 0; -} - -static void ext4_mb_put_buddy_page_lock(struct ext4_buddy *e4b) -{ - if (e4b->bd_bitmap_page) { - unlock_page(e4b->bd_bitmap_page); - put_page(e4b->bd_bitmap_page); - } - if (e4b->bd_buddy_page) { - unlock_page(e4b->bd_buddy_page); - put_page(e4b->bd_buddy_page); - } -} - -/* - * Locking note: This routine calls ext4_mb_init_cache(), which takes the - * block group lock of all groups for this page; do not hold the BG lock when - * calling this routine! - */ -static noinline_for_stack -int ext4_mb_init_group(struct super_block *sb, ext4_group_t group, gfp_t gfp) -{ - - struct ext4_group_info *this_grp; - struct ext4_buddy e4b; - struct page *page; - int ret = 0; - - might_sleep(); - mb_debug(1, "init group %u\n", group); - this_grp = ext4_get_group_info(sb, group); - /* - * This ensures that we don't reinit the buddy cache - * page which map to the group from which we are already - * allocating. If we are looking at the buddy cache we would - * have taken a reference using ext4_mb_load_buddy and that - * would have pinned buddy page to page cache. - * The call to ext4_mb_get_buddy_page_lock will mark the - * page accessed. - */ - ret = ext4_mb_get_buddy_page_lock(sb, group, &e4b, gfp); - if (ret || !EXT4_MB_GRP_NEED_INIT(this_grp)) { - /* - * somebody initialized the group - * return without doing anything - */ - goto err; - } - - page = e4b.bd_bitmap_page; - ret = ext4_mb_init_cache(page, NULL, gfp); - if (ret) - goto err; - if (!PageUptodate(page)) { - ret = -EIO; - goto err; - } - - if (e4b.bd_buddy_page == NULL) { - /* - * If both the bitmap and buddy are in - * the same page we don't need to force - * init the buddy - */ - ret = 0; - goto err; - } - /* init buddy cache */ - page = e4b.bd_buddy_page; - ret = ext4_mb_init_cache(page, e4b.bd_bitmap, gfp); - if (ret) - goto err; - if (!PageUptodate(page)) { - ret = -EIO; - goto err; - } -err: - ext4_mb_put_buddy_page_lock(&e4b); - return ret; -} - -/* - * Locking note: This routine calls ext4_mb_init_cache(), which takes the - * block group lock of all groups for this page; do not hold the BG lock when - * calling this routine! - */ -static noinline_for_stack int -ext4_mb_load_buddy_gfp(struct super_block *sb, ext4_group_t group, - struct ext4_buddy *e4b, gfp_t gfp) -{ - int blocks_per_page; - int block; - int pnum; - int poff; - struct page *page; - int ret; - struct ext4_group_info *grp; - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct inode *inode = sbi->s_buddy_cache; - - might_sleep(); - mb_debug(1, "load group %u\n", group); - - blocks_per_page = PAGE_SIZE / sb->s_blocksize; - grp = ext4_get_group_info(sb, group); - - e4b->bd_blkbits = sb->s_blocksize_bits; - e4b->bd_info = grp; - e4b->bd_sb = sb; - e4b->bd_group = group; - e4b->bd_buddy_page = NULL; - e4b->bd_bitmap_page = NULL; - - if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) { - /* - * we need full data about the group - * to make a good selection - */ - ret = ext4_mb_init_group(sb, group, gfp); - if (ret) - return ret; - } - - /* - * the buddy cache inode stores the block bitmap - * and buddy information in consecutive blocks. - * So for each group we need two blocks. - */ - block = group * 2; - pnum = block / blocks_per_page; - poff = block % blocks_per_page; - - /* we could use find_or_create_page(), but it locks page - * what we'd like to avoid in fast path ... */ - page = find_get_page_flags(inode->i_mapping, pnum, FGP_ACCESSED); - if (page == NULL || !PageUptodate(page)) { - if (page) - /* - * drop the page reference and try - * to get the page with lock. If we - * are not uptodate that implies - * somebody just created the page but - * is yet to initialize the same. So - * wait for it to initialize. - */ - put_page(page); - page = find_or_create_page(inode->i_mapping, pnum, gfp); - if (page) { - BUG_ON(page->mapping != inode->i_mapping); - if (!PageUptodate(page)) { - ret = ext4_mb_init_cache(page, NULL, gfp); - if (ret) { - unlock_page(page); - goto err; - } - mb_cmp_bitmaps(e4b, page_address(page) + - (poff * sb->s_blocksize)); - } - unlock_page(page); - } - } - if (page == NULL) { - ret = -ENOMEM; - goto err; - } - if (!PageUptodate(page)) { - ret = -EIO; - goto err; - } - - /* Pages marked accessed already */ - e4b->bd_bitmap_page = page; - e4b->bd_bitmap = page_address(page) + (poff * sb->s_blocksize); - - block++; - pnum = block / blocks_per_page; - poff = block % blocks_per_page; - - page = find_get_page_flags(inode->i_mapping, pnum, FGP_ACCESSED); - if (page == NULL || !PageUptodate(page)) { - if (page) - put_page(page); - page = find_or_create_page(inode->i_mapping, pnum, gfp); - if (page) { - BUG_ON(page->mapping != inode->i_mapping); - if (!PageUptodate(page)) { - ret = ext4_mb_init_cache(page, e4b->bd_bitmap, - gfp); - if (ret) { - unlock_page(page); - goto err; - } - } - unlock_page(page); - } - } - if (page == NULL) { - ret = -ENOMEM; - goto err; - } - if (!PageUptodate(page)) { - ret = -EIO; - goto err; - } - - /* Pages marked accessed already */ - e4b->bd_buddy_page = page; - e4b->bd_buddy = page_address(page) + (poff * sb->s_blocksize); - - BUG_ON(e4b->bd_bitmap_page == NULL); - BUG_ON(e4b->bd_buddy_page == NULL); - - return 0; - -err: - if (page) - put_page(page); - if (e4b->bd_bitmap_page) - put_page(e4b->bd_bitmap_page); - if (e4b->bd_buddy_page) - put_page(e4b->bd_buddy_page); - e4b->bd_buddy = NULL; - e4b->bd_bitmap = NULL; - return ret; -} - -static int ext4_mb_load_buddy(struct super_block *sb, ext4_group_t group, - struct ext4_buddy *e4b) -{ - return ext4_mb_load_buddy_gfp(sb, group, e4b, GFP_NOFS); -} - -static void ext4_mb_unload_buddy(struct ext4_buddy *e4b) -{ - if (e4b->bd_bitmap_page) - put_page(e4b->bd_bitmap_page); - if (e4b->bd_buddy_page) - put_page(e4b->bd_buddy_page); -} - - -static int mb_find_order_for_block(struct ext4_buddy *e4b, int block) -{ - int order = 1; - int bb_incr = 1 << (e4b->bd_blkbits - 1); - void *bb; - - BUG_ON(e4b->bd_bitmap == e4b->bd_buddy); - BUG_ON(block >= (1 << (e4b->bd_blkbits + 3))); - - bb = e4b->bd_buddy; - while (order <= e4b->bd_blkbits + 1) { - block = block >> 1; - if (!mb_test_bit(block, bb)) { - /* this block is part of buddy of order 'order' */ - return order; - } - bb += bb_incr; - bb_incr >>= 1; - order++; - } - return 0; -} - -static void mb_clear_bits(void *bm, int cur, int len) -{ - __u32 *addr; - - len = cur + len; - while (cur < len) { - if ((cur & 31) == 0 && (len - cur) >= 32) { - /* fast path: clear whole word at once */ - addr = bm + (cur >> 3); - *addr = 0; - cur += 32; - continue; - } - mb_clear_bit(cur, bm); - cur++; - } -} - -/* clear bits in given range - * will return first found zero bit if any, -1 otherwise - */ -static int mb_test_and_clear_bits(void *bm, int cur, int len) -{ - __u32 *addr; - int zero_bit = -1; - - len = cur + len; - while (cur < len) { - if ((cur & 31) == 0 && (len - cur) >= 32) { - /* fast path: clear whole word at once */ - addr = bm + (cur >> 3); - if (*addr != (__u32)(-1) && zero_bit == -1) - zero_bit = cur + mb_find_next_zero_bit(addr, 32, 0); - *addr = 0; - cur += 32; - continue; - } - if (!mb_test_and_clear_bit(cur, bm) && zero_bit == -1) - zero_bit = cur; - cur++; - } - - return zero_bit; -} - -void ext4_set_bits(void *bm, int cur, int len) -{ - __u32 *addr; - - len = cur + len; - while (cur < len) { - if ((cur & 31) == 0 && (len - cur) >= 32) { - /* fast path: set whole word at once */ - addr = bm + (cur >> 3); - *addr = 0xffffffff; - cur += 32; - continue; - } - mb_set_bit(cur, bm); - cur++; - } -} - -/* - * _________________________________________________________________ */ - -static inline int mb_buddy_adjust_border(int* bit, void* bitmap, int side) -{ - if (mb_test_bit(*bit + side, bitmap)) { - mb_clear_bit(*bit, bitmap); - (*bit) -= side; - return 1; - } - else { - (*bit) += side; - mb_set_bit(*bit, bitmap); - return -1; - } -} - -static void mb_buddy_mark_free(struct ext4_buddy *e4b, int first, int last) -{ - int max; - int order = 1; - void *buddy = mb_find_buddy(e4b, order, &max); - - while (buddy) { - void *buddy2; - - /* Bits in range [first; last] are known to be set since - * corresponding blocks were allocated. Bits in range - * (first; last) will stay set because they form buddies on - * upper layer. We just deal with borders if they don't - * align with upper layer and then go up. - * Releasing entire group is all about clearing - * single bit of highest order buddy. - */ - - /* Example: - * --------------------------------- - * | 1 | 1 | 1 | 1 | - * --------------------------------- - * | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | - * --------------------------------- - * 0 1 2 3 4 5 6 7 - * \_____________________/ - * - * Neither [1] nor [6] is aligned to above layer. - * Left neighbour [0] is free, so mark it busy, - * decrease bb_counters and extend range to - * [0; 6] - * Right neighbour [7] is busy. It can't be coaleasced with [6], so - * mark [6] free, increase bb_counters and shrink range to - * [0; 5]. - * Then shift range to [0; 2], go up and do the same. - */ - - - if (first & 1) - e4b->bd_info->bb_counters[order] += mb_buddy_adjust_border(&first, buddy, -1); - if (!(last & 1)) - e4b->bd_info->bb_counters[order] += mb_buddy_adjust_border(&last, buddy, 1); - if (first > last) - break; - order++; - - if (first == last || !(buddy2 = mb_find_buddy(e4b, order, &max))) { - mb_clear_bits(buddy, first, last - first + 1); - e4b->bd_info->bb_counters[order - 1] += last - first + 1; - break; - } - first >>= 1; - last >>= 1; - buddy = buddy2; - } -} - -static void mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, - int first, int count) -{ - int left_is_free = 0; - int right_is_free = 0; - int block; - int last = first + count - 1; - struct super_block *sb = e4b->bd_sb; - - if (WARN_ON(count == 0)) - return; - BUG_ON(last >= (sb->s_blocksize << 3)); - assert_spin_locked(ext4_group_lock_ptr(sb, e4b->bd_group)); - /* Don't bother if the block group is corrupt. */ - if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info))) - return; - - mb_check_buddy(e4b); - mb_free_blocks_double(inode, e4b, first, count); - - e4b->bd_info->bb_free += count; - if (first < e4b->bd_info->bb_first_free) - e4b->bd_info->bb_first_free = first; - - /* access memory sequentially: check left neighbour, - * clear range and then check right neighbour - */ - if (first != 0) - left_is_free = !mb_test_bit(first - 1, e4b->bd_bitmap); - block = mb_test_and_clear_bits(e4b->bd_bitmap, first, count); - if (last + 1 < EXT4_SB(sb)->s_mb_maxs[0]) - right_is_free = !mb_test_bit(last + 1, e4b->bd_bitmap); - - if (unlikely(block != -1)) { - struct ext4_sb_info *sbi = EXT4_SB(sb); - ext4_fsblk_t blocknr; - - blocknr = ext4_group_first_block_no(sb, e4b->bd_group); - blocknr += EXT4_C2B(EXT4_SB(sb), block); - ext4_grp_locked_error(sb, e4b->bd_group, - inode ? inode->i_ino : 0, - blocknr, - "freeing already freed block " - "(bit %u); block bitmap corrupt.", - block); - if (!EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info)) - percpu_counter_sub(&sbi->s_freeclusters_counter, - e4b->bd_info->bb_free); - /* Mark the block group as corrupt. */ - set_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, - &e4b->bd_info->bb_state); - mb_regenerate_buddy(e4b); - goto done; - } - - /* let's maintain fragments counter */ - if (left_is_free && right_is_free) - e4b->bd_info->bb_fragments--; - else if (!left_is_free && !right_is_free) - e4b->bd_info->bb_fragments++; - - /* buddy[0] == bd_bitmap is a special case, so handle - * it right away and let mb_buddy_mark_free stay free of - * zero order checks. - * Check if neighbours are to be coaleasced, - * adjust bitmap bb_counters and borders appropriately. - */ - if (first & 1) { - first += !left_is_free; - e4b->bd_info->bb_counters[0] += left_is_free ? -1 : 1; - } - if (!(last & 1)) { - last -= !right_is_free; - e4b->bd_info->bb_counters[0] += right_is_free ? -1 : 1; - } - - if (first <= last) - mb_buddy_mark_free(e4b, first >> 1, last >> 1); - -done: - mb_set_largest_free_order(sb, e4b->bd_info); - mb_check_buddy(e4b); -} - -static int mb_find_extent(struct ext4_buddy *e4b, int block, - int needed, struct ext4_free_extent *ex) -{ - int next = block; - int max, order; - void *buddy; - - assert_spin_locked(ext4_group_lock_ptr(e4b->bd_sb, e4b->bd_group)); - BUG_ON(ex == NULL); - - buddy = mb_find_buddy(e4b, 0, &max); - BUG_ON(buddy == NULL); - BUG_ON(block >= max); - if (mb_test_bit(block, buddy)) { - ex->fe_len = 0; - ex->fe_start = 0; - ex->fe_group = 0; - return 0; - } - - /* find actual order */ - order = mb_find_order_for_block(e4b, block); - block = block >> order; - - ex->fe_len = 1 << order; - ex->fe_start = block << order; - ex->fe_group = e4b->bd_group; - - /* calc difference from given start */ - next = next - ex->fe_start; - ex->fe_len -= next; - ex->fe_start += next; - - while (needed > ex->fe_len && - mb_find_buddy(e4b, order, &max)) { - - if (block + 1 >= max) - break; - - next = (block + 1) * (1 << order); - if (mb_test_bit(next, e4b->bd_bitmap)) - break; - - order = mb_find_order_for_block(e4b, next); - - block = next >> order; - ex->fe_len += 1 << order; - } - - BUG_ON(ex->fe_start + ex->fe_len > (1 << (e4b->bd_blkbits + 3))); - return ex->fe_len; -} - -static int mb_mark_used(struct ext4_buddy *e4b, struct ext4_free_extent *ex) -{ - int ord; - int mlen = 0; - int max = 0; - int cur; - int start = ex->fe_start; - int len = ex->fe_len; - unsigned ret = 0; - int len0 = len; - void *buddy; - - BUG_ON(start + len > (e4b->bd_sb->s_blocksize << 3)); - BUG_ON(e4b->bd_group != ex->fe_group); - assert_spin_locked(ext4_group_lock_ptr(e4b->bd_sb, e4b->bd_group)); - mb_check_buddy(e4b); - mb_mark_used_double(e4b, start, len); - - e4b->bd_info->bb_free -= len; - if (e4b->bd_info->bb_first_free == start) - e4b->bd_info->bb_first_free += len; - - /* let's maintain fragments counter */ - if (start != 0) - mlen = !mb_test_bit(start - 1, e4b->bd_bitmap); - if (start + len < EXT4_SB(e4b->bd_sb)->s_mb_maxs[0]) - max = !mb_test_bit(start + len, e4b->bd_bitmap); - if (mlen && max) - e4b->bd_info->bb_fragments++; - else if (!mlen && !max) - e4b->bd_info->bb_fragments--; - - /* let's maintain buddy itself */ - while (len) { - ord = mb_find_order_for_block(e4b, start); - - if (((start >> ord) << ord) == start && len >= (1 << ord)) { - /* the whole chunk may be allocated at once! */ - mlen = 1 << ord; - buddy = mb_find_buddy(e4b, ord, &max); - BUG_ON((start >> ord) >= max); - mb_set_bit(start >> ord, buddy); - e4b->bd_info->bb_counters[ord]--; - start += mlen; - len -= mlen; - BUG_ON(len < 0); - continue; - } - - /* store for history */ - if (ret == 0) - ret = len | (ord << 16); - - /* we have to split large buddy */ - BUG_ON(ord <= 0); - buddy = mb_find_buddy(e4b, ord, &max); - mb_set_bit(start >> ord, buddy); - e4b->bd_info->bb_counters[ord]--; - - ord--; - cur = (start >> ord) & ~1U; - buddy = mb_find_buddy(e4b, ord, &max); - mb_clear_bit(cur, buddy); - mb_clear_bit(cur + 1, buddy); - e4b->bd_info->bb_counters[ord]++; - e4b->bd_info->bb_counters[ord]++; - } - mb_set_largest_free_order(e4b->bd_sb, e4b->bd_info); - - ext4_set_bits(e4b->bd_bitmap, ex->fe_start, len0); - mb_check_buddy(e4b); - - return ret; -} - -/* - * Must be called under group lock! - */ -static void ext4_mb_use_best_found(struct ext4_allocation_context *ac, - struct ext4_buddy *e4b) -{ - struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb); - int ret; - - BUG_ON(ac->ac_b_ex.fe_group != e4b->bd_group); - BUG_ON(ac->ac_status == AC_STATUS_FOUND); - - ac->ac_b_ex.fe_len = min(ac->ac_b_ex.fe_len, ac->ac_g_ex.fe_len); - ac->ac_b_ex.fe_logical = ac->ac_g_ex.fe_logical; - ret = mb_mark_used(e4b, &ac->ac_b_ex); - - /* preallocation can change ac_b_ex, thus we store actually - * allocated blocks for history */ - ac->ac_f_ex = ac->ac_b_ex; - - ac->ac_status = AC_STATUS_FOUND; - ac->ac_tail = ret & 0xffff; - ac->ac_buddy = ret >> 16; - - /* - * take the page reference. We want the page to be pinned - * so that we don't get a ext4_mb_init_cache_call for this - * group until we update the bitmap. That would mean we - * double allocate blocks. The reference is dropped - * in ext4_mb_release_context - */ - ac->ac_bitmap_page = e4b->bd_bitmap_page; - get_page(ac->ac_bitmap_page); - ac->ac_buddy_page = e4b->bd_buddy_page; - get_page(ac->ac_buddy_page); - /* store last allocated for subsequent stream allocation */ - if (ac->ac_flags & EXT4_MB_STREAM_ALLOC) { - spin_lock(&sbi->s_md_lock); - sbi->s_mb_last_group = ac->ac_f_ex.fe_group; - sbi->s_mb_last_start = ac->ac_f_ex.fe_start; - spin_unlock(&sbi->s_md_lock); - } -} - -/* - * regular allocator, for general purposes allocation - */ - -static void ext4_mb_check_limits(struct ext4_allocation_context *ac, - struct ext4_buddy *e4b, - int finish_group) -{ - struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb); - struct ext4_free_extent *bex = &ac->ac_b_ex; - struct ext4_free_extent *gex = &ac->ac_g_ex; - struct ext4_free_extent ex; - int max; - - if (ac->ac_status == AC_STATUS_FOUND) - return; - /* - * We don't want to scan for a whole year - */ - if (ac->ac_found > sbi->s_mb_max_to_scan && - !(ac->ac_flags & EXT4_MB_HINT_FIRST)) { - ac->ac_status = AC_STATUS_BREAK; - return; - } - - /* - * Haven't found good chunk so far, let's continue - */ - if (bex->fe_len < gex->fe_len) - return; - - if ((finish_group || ac->ac_found > sbi->s_mb_min_to_scan) - && bex->fe_group == e4b->bd_group) { - /* recheck chunk's availability - we don't know - * when it was found (within this lock-unlock - * period or not) */ - max = mb_find_extent(e4b, bex->fe_start, gex->fe_len, &ex); - if (max >= gex->fe_len) { - ext4_mb_use_best_found(ac, e4b); - return; - } - } -} - -/* - * The routine checks whether found extent is good enough. If it is, - * then the extent gets marked used and flag is set to the context - * to stop scanning. Otherwise, the extent is compared with the - * previous found extent and if new one is better, then it's stored - * in the context. Later, the best found extent will be used, if - * mballoc can't find good enough extent. - * - * FIXME: real allocation policy is to be designed yet! - */ -static void ext4_mb_measure_extent(struct ext4_allocation_context *ac, - struct ext4_free_extent *ex, - struct ext4_buddy *e4b) -{ - struct ext4_free_extent *bex = &ac->ac_b_ex; - struct ext4_free_extent *gex = &ac->ac_g_ex; - - BUG_ON(ex->fe_len <= 0); - BUG_ON(ex->fe_len > EXT4_CLUSTERS_PER_GROUP(ac->ac_sb)); - BUG_ON(ex->fe_start >= EXT4_CLUSTERS_PER_GROUP(ac->ac_sb)); - BUG_ON(ac->ac_status != AC_STATUS_CONTINUE); - - ac->ac_found++; - - /* - * The special case - take what you catch first - */ - if (unlikely(ac->ac_flags & EXT4_MB_HINT_FIRST)) { - *bex = *ex; - ext4_mb_use_best_found(ac, e4b); - return; - } - - /* - * Let's check whether the chuck is good enough - */ - if (ex->fe_len == gex->fe_len) { - *bex = *ex; - ext4_mb_use_best_found(ac, e4b); - return; - } - - /* - * If this is first found extent, just store it in the context - */ - if (bex->fe_len == 0) { - *bex = *ex; - return; - } - - /* - * If new found extent is better, store it in the context - */ - if (bex->fe_len < gex->fe_len) { - /* if the request isn't satisfied, any found extent - * larger than previous best one is better */ - if (ex->fe_len > bex->fe_len) - *bex = *ex; - } else if (ex->fe_len > gex->fe_len) { - /* if the request is satisfied, then we try to find - * an extent that still satisfy the request, but is - * smaller than previous one */ - if (ex->fe_len < bex->fe_len) - *bex = *ex; - } - - ext4_mb_check_limits(ac, e4b, 0); -} - -static noinline_for_stack -int ext4_mb_try_best_found(struct ext4_allocation_context *ac, - struct ext4_buddy *e4b) -{ - struct ext4_free_extent ex = ac->ac_b_ex; - ext4_group_t group = ex.fe_group; - int max; - int err; - - BUG_ON(ex.fe_len <= 0); - err = ext4_mb_load_buddy(ac->ac_sb, group, e4b); - if (err) - return err; - - ext4_lock_group(ac->ac_sb, group); - max = mb_find_extent(e4b, ex.fe_start, ex.fe_len, &ex); - - if (max > 0) { - ac->ac_b_ex = ex; - ext4_mb_use_best_found(ac, e4b); - } - - ext4_unlock_group(ac->ac_sb, group); - ext4_mb_unload_buddy(e4b); - - return 0; -} - -static noinline_for_stack -int ext4_mb_find_by_goal(struct ext4_allocation_context *ac, - struct ext4_buddy *e4b) -{ - ext4_group_t group = ac->ac_g_ex.fe_group; - int max; - int err; - struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb); - struct ext4_group_info *grp = ext4_get_group_info(ac->ac_sb, group); - struct ext4_free_extent ex; - - if (!(ac->ac_flags & EXT4_MB_HINT_TRY_GOAL)) - return 0; - if (grp->bb_free == 0) - return 0; - - err = ext4_mb_load_buddy(ac->ac_sb, group, e4b); - if (err) - return err; - - if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(e4b->bd_info))) { - ext4_mb_unload_buddy(e4b); - return 0; - } - - ext4_lock_group(ac->ac_sb, group); - max = mb_find_extent(e4b, ac->ac_g_ex.fe_start, - ac->ac_g_ex.fe_len, &ex); - ex.fe_logical = 0xDEADFA11; /* debug value */ - - if (max >= ac->ac_g_ex.fe_len && ac->ac_g_ex.fe_len == sbi->s_stripe) { - ext4_fsblk_t start; - - start = ext4_group_first_block_no(ac->ac_sb, e4b->bd_group) + - ex.fe_start; - /* use do_div to get remainder (would be 64-bit modulo) */ - if (do_div(start, sbi->s_stripe) == 0) { - ac->ac_found++; - ac->ac_b_ex = ex; - ext4_mb_use_best_found(ac, e4b); - } - } else if (max >= ac->ac_g_ex.fe_len) { - BUG_ON(ex.fe_len <= 0); - BUG_ON(ex.fe_group != ac->ac_g_ex.fe_group); - BUG_ON(ex.fe_start != ac->ac_g_ex.fe_start); - ac->ac_found++; - ac->ac_b_ex = ex; - ext4_mb_use_best_found(ac, e4b); - } else if (max > 0 && (ac->ac_flags & EXT4_MB_HINT_MERGE)) { - /* Sometimes, caller may want to merge even small - * number of blocks to an existing extent */ - BUG_ON(ex.fe_len <= 0); - BUG_ON(ex.fe_group != ac->ac_g_ex.fe_group); - BUG_ON(ex.fe_start != ac->ac_g_ex.fe_start); - ac->ac_found++; - ac->ac_b_ex = ex; - ext4_mb_use_best_found(ac, e4b); - } - ext4_unlock_group(ac->ac_sb, group); - ext4_mb_unload_buddy(e4b); - - return 0; -} - -/* - * The routine scans buddy structures (not bitmap!) from given order - * to max order and tries to find big enough chunk to satisfy the req - */ -static noinline_for_stack -void ext4_mb_simple_scan_group(struct ext4_allocation_context *ac, - struct ext4_buddy *e4b) -{ - struct super_block *sb = ac->ac_sb; - struct ext4_group_info *grp = e4b->bd_info; - void *buddy; - int i; - int k; - int max; - - BUG_ON(ac->ac_2order <= 0); - for (i = ac->ac_2order; i <= sb->s_blocksize_bits + 1; i++) { - if (grp->bb_counters[i] == 0) - continue; - - buddy = mb_find_buddy(e4b, i, &max); - BUG_ON(buddy == NULL); - - k = mb_find_next_zero_bit(buddy, max, 0); - BUG_ON(k >= max); - - ac->ac_found++; - - ac->ac_b_ex.fe_len = 1 << i; - ac->ac_b_ex.fe_start = k << i; - ac->ac_b_ex.fe_group = e4b->bd_group; - - ext4_mb_use_best_found(ac, e4b); - - BUG_ON(ac->ac_b_ex.fe_len != ac->ac_g_ex.fe_len); - - if (EXT4_SB(sb)->s_mb_stats) - atomic_inc(&EXT4_SB(sb)->s_bal_2orders); - - break; - } -} - -/* - * The routine scans the group and measures all found extents. - * In order to optimize scanning, caller must pass number of - * free blocks in the group, so the routine can know upper limit. - */ -static noinline_for_stack -void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac, - struct ext4_buddy *e4b) -{ - struct super_block *sb = ac->ac_sb; - void *bitmap = e4b->bd_bitmap; - struct ext4_free_extent ex; - int i; - int free; - - free = e4b->bd_info->bb_free; - BUG_ON(free <= 0); - - i = e4b->bd_info->bb_first_free; - - while (free && ac->ac_status == AC_STATUS_CONTINUE) { - i = mb_find_next_zero_bit(bitmap, - EXT4_CLUSTERS_PER_GROUP(sb), i); - if (i >= EXT4_CLUSTERS_PER_GROUP(sb)) { - /* - * IF we have corrupt bitmap, we won't find any - * free blocks even though group info says we - * we have free blocks - */ - ext4_grp_locked_error(sb, e4b->bd_group, 0, 0, - "%d free clusters as per " - "group info. But bitmap says 0", - free); - break; - } - - mb_find_extent(e4b, i, ac->ac_g_ex.fe_len, &ex); - BUG_ON(ex.fe_len <= 0); - if (free < ex.fe_len) { - ext4_grp_locked_error(sb, e4b->bd_group, 0, 0, - "%d free clusters as per " - "group info. But got %d blocks", - free, ex.fe_len); - /* - * The number of free blocks differs. This mostly - * indicate that the bitmap is corrupt. So exit - * without claiming the space. - */ - break; - } - ex.fe_logical = 0xDEADC0DE; /* debug value */ - ext4_mb_measure_extent(ac, &ex, e4b); - - i += ex.fe_len; - free -= ex.fe_len; - } - - ext4_mb_check_limits(ac, e4b, 1); -} - -/* - * This is a special case for storages like raid5 - * we try to find stripe-aligned chunks for stripe-size-multiple requests - */ -static noinline_for_stack -void ext4_mb_scan_aligned(struct ext4_allocation_context *ac, - struct ext4_buddy *e4b) -{ - struct super_block *sb = ac->ac_sb; - struct ext4_sb_info *sbi = EXT4_SB(sb); - void *bitmap = e4b->bd_bitmap; - struct ext4_free_extent ex; - ext4_fsblk_t first_group_block; - ext4_fsblk_t a; - ext4_grpblk_t i; - int max; - - BUG_ON(sbi->s_stripe == 0); - - /* find first stripe-aligned block in group */ - first_group_block = ext4_group_first_block_no(sb, e4b->bd_group); - - a = first_group_block + sbi->s_stripe - 1; - do_div(a, sbi->s_stripe); - i = (a * sbi->s_stripe) - first_group_block; - - while (i < EXT4_CLUSTERS_PER_GROUP(sb)) { - if (!mb_test_bit(i, bitmap)) { - max = mb_find_extent(e4b, i, sbi->s_stripe, &ex); - if (max >= sbi->s_stripe) { - ac->ac_found++; - ex.fe_logical = 0xDEADF00D; /* debug value */ - ac->ac_b_ex = ex; - ext4_mb_use_best_found(ac, e4b); - break; - } - } - i += sbi->s_stripe; - } -} - -/* - * This is now called BEFORE we load the buddy bitmap. - * Returns either 1 or 0 indicating that the group is either suitable - * for the allocation or not. In addition it can also return negative - * error code when something goes wrong. - */ -static int ext4_mb_good_group(struct ext4_allocation_context *ac, - ext4_group_t group, int cr) -{ - unsigned free, fragments; - int flex_size = ext4_flex_bg_size(EXT4_SB(ac->ac_sb)); - struct ext4_group_info *grp = ext4_get_group_info(ac->ac_sb, group); - - BUG_ON(cr < 0 || cr >= 4); - - free = grp->bb_free; - if (free == 0) - return 0; - if (cr <= 2 && free < ac->ac_g_ex.fe_len) - return 0; - - if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT(grp))) - return 0; - - /* We only do this if the grp has never been initialized */ - if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) { - int ret = ext4_mb_init_group(ac->ac_sb, group, GFP_NOFS); - if (ret) - return ret; - } - - fragments = grp->bb_fragments; - if (fragments == 0) - return 0; - - switch (cr) { - case 0: - BUG_ON(ac->ac_2order == 0); - - /* Avoid using the first bg of a flexgroup for data files */ - if ((ac->ac_flags & EXT4_MB_HINT_DATA) && - (flex_size >= EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME) && - ((group % flex_size) == 0)) - return 0; - - if ((ac->ac_2order > ac->ac_sb->s_blocksize_bits+1) || - (free / fragments) >= ac->ac_g_ex.fe_len) - return 1; - - if (grp->bb_largest_free_order < ac->ac_2order) - return 0; - - return 1; - case 1: - if ((free / fragments) >= ac->ac_g_ex.fe_len) - return 1; - break; - case 2: - if (free >= ac->ac_g_ex.fe_len) - return 1; - break; - case 3: - return 1; - default: - BUG(); - } - - return 0; -} - -static noinline_for_stack int -ext4_mb_regular_allocator(struct ext4_allocation_context *ac) -{ - ext4_group_t ngroups, group, i; - int cr; - int err = 0, first_err = 0; - struct ext4_sb_info *sbi; - struct super_block *sb; - struct ext4_buddy e4b; - - sb = ac->ac_sb; - sbi = EXT4_SB(sb); - ngroups = ext4_get_groups_count(sb); - /* non-extent files are limited to low blocks/groups */ - if (!(ext4_test_inode_flag(ac->ac_inode, EXT4_INODE_EXTENTS))) - ngroups = sbi->s_blockfile_groups; - - BUG_ON(ac->ac_status == AC_STATUS_FOUND); - - /* first, try the goal */ - err = ext4_mb_find_by_goal(ac, &e4b); - if (err || ac->ac_status == AC_STATUS_FOUND) - goto out; - - if (unlikely(ac->ac_flags & EXT4_MB_HINT_GOAL_ONLY)) - goto out; - - /* - * ac->ac2_order is set only if the fe_len is a power of 2 - * if ac2_order is set we also set criteria to 0 so that we - * try exact allocation using buddy. - */ - i = fls(ac->ac_g_ex.fe_len); - ac->ac_2order = 0; - /* - * We search using buddy data only if the order of the request - * is greater than equal to the sbi_s_mb_order2_reqs - * You can tune it via /sys/fs/ext4//mb_order2_req - */ - if (i >= sbi->s_mb_order2_reqs) { - /* - * This should tell if fe_len is exactly power of 2 - */ - if ((ac->ac_g_ex.fe_len & (~(1 << (i - 1)))) == 0) - ac->ac_2order = i - 1; - } - - /* if stream allocation is enabled, use global goal */ - if (ac->ac_flags & EXT4_MB_STREAM_ALLOC) { - /* TBD: may be hot point */ - spin_lock(&sbi->s_md_lock); - ac->ac_g_ex.fe_group = sbi->s_mb_last_group; - ac->ac_g_ex.fe_start = sbi->s_mb_last_start; - spin_unlock(&sbi->s_md_lock); - } - - /* Let's just scan groups to find more-less suitable blocks */ - cr = ac->ac_2order ? 0 : 1; - /* - * cr == 0 try to get exact allocation, - * cr == 3 try to get anything - */ -repeat: - for (; cr < 4 && ac->ac_status == AC_STATUS_CONTINUE; cr++) { - ac->ac_criteria = cr; - /* - * searching for the right group start - * from the goal value specified - */ - group = ac->ac_g_ex.fe_group; - - for (i = 0; i < ngroups; group++, i++) { - int ret = 0; - cond_resched(); - /* - * Artificially restricted ngroups for non-extent - * files makes group > ngroups possible on first loop. - */ - if (group >= ngroups) - group = 0; - - /* This now checks without needing the buddy page */ - ret = ext4_mb_good_group(ac, group, cr); - if (ret <= 0) { - if (!first_err) - first_err = ret; - continue; - } - - err = ext4_mb_load_buddy(sb, group, &e4b); - if (err) - goto out; - - ext4_lock_group(sb, group); - - /* - * We need to check again after locking the - * block group - */ - ret = ext4_mb_good_group(ac, group, cr); - if (ret <= 0) { - ext4_unlock_group(sb, group); - ext4_mb_unload_buddy(&e4b); - if (!first_err) - first_err = ret; - continue; - } - - ac->ac_groups_scanned++; - if (cr == 0 && ac->ac_2order < sb->s_blocksize_bits+2) - ext4_mb_simple_scan_group(ac, &e4b); - else if (cr == 1 && sbi->s_stripe && - !(ac->ac_g_ex.fe_len % sbi->s_stripe)) - ext4_mb_scan_aligned(ac, &e4b); - else - ext4_mb_complex_scan_group(ac, &e4b); - - ext4_unlock_group(sb, group); - ext4_mb_unload_buddy(&e4b); - - if (ac->ac_status != AC_STATUS_CONTINUE) - break; - } - } - - if (ac->ac_b_ex.fe_len > 0 && ac->ac_status != AC_STATUS_FOUND && - !(ac->ac_flags & EXT4_MB_HINT_FIRST)) { - /* - * We've been searching too long. Let's try to allocate - * the best chunk we've found so far - */ - - ext4_mb_try_best_found(ac, &e4b); - if (ac->ac_status != AC_STATUS_FOUND) { - /* - * Someone more lucky has already allocated it. - * The only thing we can do is just take first - * found block(s) - printk(KERN_DEBUG "EXT4-fs: someone won our chunk\n"); - */ - ac->ac_b_ex.fe_group = 0; - ac->ac_b_ex.fe_start = 0; - ac->ac_b_ex.fe_len = 0; - ac->ac_status = AC_STATUS_CONTINUE; - ac->ac_flags |= EXT4_MB_HINT_FIRST; - cr = 3; - atomic_inc(&sbi->s_mb_lost_chunks); - goto repeat; - } - } -out: - if (!err && ac->ac_status != AC_STATUS_FOUND && first_err) - err = first_err; - return err; -} - -static void *ext4_mb_seq_groups_start(struct seq_file *seq, loff_t *pos) -{ - struct super_block *sb = seq->private; - ext4_group_t group; - - if (*pos < 0 || *pos >= ext4_get_groups_count(sb)) - return NULL; - group = *pos + 1; - return (void *) ((unsigned long) group); -} - -static void *ext4_mb_seq_groups_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct super_block *sb = seq->private; - ext4_group_t group; - - ++*pos; - if (*pos < 0 || *pos >= ext4_get_groups_count(sb)) - return NULL; - group = *pos + 1; - return (void *) ((unsigned long) group); -} - -static int ext4_mb_seq_groups_show(struct seq_file *seq, void *v) -{ - struct super_block *sb = seq->private; - ext4_group_t group = (ext4_group_t) ((unsigned long) v); - int i; - int err, buddy_loaded = 0; - struct ext4_buddy e4b; - struct ext4_group_info *grinfo; - struct sg { - struct ext4_group_info info; - ext4_grpblk_t counters[16]; - } sg; - - group--; - if (group == 0) - seq_puts(seq, "#group: free frags first [" - " 2^0 2^1 2^2 2^3 2^4 2^5 2^6 " - " 2^7 2^8 2^9 2^10 2^11 2^12 2^13 ]\n"); - - i = (sb->s_blocksize_bits + 2) * sizeof(sg.info.bb_counters[0]) + - sizeof(struct ext4_group_info); - grinfo = ext4_get_group_info(sb, group); - /* Load the group info in memory only if not already loaded. */ - if (unlikely(EXT4_MB_GRP_NEED_INIT(grinfo))) { - err = ext4_mb_load_buddy(sb, group, &e4b); - if (err) { - seq_printf(seq, "#%-5u: I/O error\n", group); - return 0; - } - buddy_loaded = 1; - } - - memcpy(&sg, ext4_get_group_info(sb, group), i); - - if (buddy_loaded) - ext4_mb_unload_buddy(&e4b); - - seq_printf(seq, "#%-5u: %-5u %-5u %-5u [", group, sg.info.bb_free, - sg.info.bb_fragments, sg.info.bb_first_free); - for (i = 0; i <= 13; i++) - seq_printf(seq, " %-5u", i <= sb->s_blocksize_bits + 1 ? - sg.info.bb_counters[i] : 0); - seq_printf(seq, " ]\n"); - - return 0; -} - -static void ext4_mb_seq_groups_stop(struct seq_file *seq, void *v) -{ -} - -static const struct seq_operations ext4_mb_seq_groups_ops = { - .start = ext4_mb_seq_groups_start, - .next = ext4_mb_seq_groups_next, - .stop = ext4_mb_seq_groups_stop, - .show = ext4_mb_seq_groups_show, -}; - -static int ext4_mb_seq_groups_open(struct inode *inode, struct file *file) -{ - struct super_block *sb = PDE_DATA(inode); - int rc; - - rc = seq_open(file, &ext4_mb_seq_groups_ops); - if (rc == 0) { - struct seq_file *m = file->private_data; - m->private = sb; - } - return rc; - -} - -const struct file_operations ext4_seq_mb_groups_fops = { - .open = ext4_mb_seq_groups_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static struct kmem_cache *get_groupinfo_cache(int blocksize_bits) -{ - int cache_index = blocksize_bits - EXT4_MIN_BLOCK_LOG_SIZE; - struct kmem_cache *cachep = ext4_groupinfo_caches[cache_index]; - - BUG_ON(!cachep); - return cachep; -} - -/* - * Allocate the top-level s_group_info array for the specified number - * of groups - */ -int ext4_mb_alloc_groupinfo(struct super_block *sb, ext4_group_t ngroups) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - unsigned size; - struct ext4_group_info ***new_groupinfo; - - size = (ngroups + EXT4_DESC_PER_BLOCK(sb) - 1) >> - EXT4_DESC_PER_BLOCK_BITS(sb); - if (size <= sbi->s_group_info_size) - return 0; - - size = roundup_pow_of_two(sizeof(*sbi->s_group_info) * size); - new_groupinfo = ext4_kvzalloc(size, GFP_KERNEL); - if (!new_groupinfo) { - ext4_msg(sb, KERN_ERR, "can't allocate buddy meta group"); - return -ENOMEM; - } - if (sbi->s_group_info) { - memcpy(new_groupinfo, sbi->s_group_info, - sbi->s_group_info_size * sizeof(*sbi->s_group_info)); - kvfree(sbi->s_group_info); - } - sbi->s_group_info = new_groupinfo; - sbi->s_group_info_size = size / sizeof(*sbi->s_group_info); - ext4_debug("allocated s_groupinfo array for %d meta_bg's\n", - sbi->s_group_info_size); - return 0; -} - -/* Create and initialize ext4_group_info data for the given group. */ -int ext4_mb_add_groupinfo(struct super_block *sb, ext4_group_t group, - struct ext4_group_desc *desc) -{ - int i; - int metalen = 0; - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_group_info **meta_group_info; - struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits); - - /* - * First check if this group is the first of a reserved block. - * If it's true, we have to allocate a new table of pointers - * to ext4_group_info structures - */ - if (group % EXT4_DESC_PER_BLOCK(sb) == 0) { - metalen = sizeof(*meta_group_info) << - EXT4_DESC_PER_BLOCK_BITS(sb); - meta_group_info = kmalloc(metalen, GFP_NOFS); - if (meta_group_info == NULL) { - ext4_msg(sb, KERN_ERR, "can't allocate mem " - "for a buddy group"); - goto exit_meta_group_info; - } - sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)] = - meta_group_info; - } - - meta_group_info = - sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)]; - i = group & (EXT4_DESC_PER_BLOCK(sb) - 1); - - meta_group_info[i] = kmem_cache_zalloc(cachep, GFP_NOFS); - if (meta_group_info[i] == NULL) { - ext4_msg(sb, KERN_ERR, "can't allocate buddy mem"); - goto exit_group_info; - } - set_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, - &(meta_group_info[i]->bb_state)); - - /* - * initialize bb_free to be able to skip - * empty groups without initialization - */ - if (desc->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { - meta_group_info[i]->bb_free = - ext4_free_clusters_after_init(sb, group, desc); - } else { - meta_group_info[i]->bb_free = - ext4_free_group_clusters(sb, desc); - } - - INIT_LIST_HEAD(&meta_group_info[i]->bb_prealloc_list); - init_rwsem(&meta_group_info[i]->alloc_sem); - meta_group_info[i]->bb_free_root = RB_ROOT; - meta_group_info[i]->bb_largest_free_order = -1; /* uninit */ - -#ifdef DOUBLE_CHECK - { - struct buffer_head *bh; - meta_group_info[i]->bb_bitmap = - kmalloc(sb->s_blocksize, GFP_NOFS); - BUG_ON(meta_group_info[i]->bb_bitmap == NULL); - bh = ext4_read_block_bitmap(sb, group); - BUG_ON(IS_ERR_OR_NULL(bh)); - memcpy(meta_group_info[i]->bb_bitmap, bh->b_data, - sb->s_blocksize); - put_bh(bh); - } -#endif - - return 0; - -exit_group_info: - /* If a meta_group_info table has been allocated, release it now */ - if (group % EXT4_DESC_PER_BLOCK(sb) == 0) { - kfree(sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)]); - sbi->s_group_info[group >> EXT4_DESC_PER_BLOCK_BITS(sb)] = NULL; - } -exit_meta_group_info: - return -ENOMEM; -} /* ext4_mb_add_groupinfo */ - -static int ext4_mb_init_backend(struct super_block *sb) -{ - ext4_group_t ngroups = ext4_get_groups_count(sb); - ext4_group_t i; - struct ext4_sb_info *sbi = EXT4_SB(sb); - int err; - struct ext4_group_desc *desc; - struct kmem_cache *cachep; - - err = ext4_mb_alloc_groupinfo(sb, ngroups); - if (err) - return err; - - sbi->s_buddy_cache = new_inode(sb); - if (sbi->s_buddy_cache == NULL) { - ext4_msg(sb, KERN_ERR, "can't get new inode"); - goto err_freesgi; - } - /* To avoid potentially colliding with an valid on-disk inode number, - * use EXT4_BAD_INO for the buddy cache inode number. This inode is - * not in the inode hash, so it should never be found by iget(), but - * this will avoid confusion if it ever shows up during debugging. */ - sbi->s_buddy_cache->i_ino = EXT4_BAD_INO; - EXT4_I(sbi->s_buddy_cache)->i_disksize = 0; - for (i = 0; i < ngroups; i++) { - desc = ext4_get_group_desc(sb, i, NULL); - if (desc == NULL) { - ext4_msg(sb, KERN_ERR, "can't read descriptor %u", i); - goto err_freebuddy; - } - if (ext4_mb_add_groupinfo(sb, i, desc) != 0) - goto err_freebuddy; - } - - return 0; - -err_freebuddy: - cachep = get_groupinfo_cache(sb->s_blocksize_bits); - while (i-- > 0) - kmem_cache_free(cachep, ext4_get_group_info(sb, i)); - i = sbi->s_group_info_size; - while (i-- > 0) - kfree(sbi->s_group_info[i]); - iput(sbi->s_buddy_cache); -err_freesgi: - kvfree(sbi->s_group_info); - return -ENOMEM; -} - -static void ext4_groupinfo_destroy_slabs(void) -{ - int i; - - for (i = 0; i < NR_GRPINFO_CACHES; i++) { - if (ext4_groupinfo_caches[i]) - kmem_cache_destroy(ext4_groupinfo_caches[i]); - ext4_groupinfo_caches[i] = NULL; - } -} - -static int ext4_groupinfo_create_slab(size_t size) -{ - static DEFINE_MUTEX(ext4_grpinfo_slab_create_mutex); - int slab_size; - int blocksize_bits = order_base_2(size); - int cache_index = blocksize_bits - EXT4_MIN_BLOCK_LOG_SIZE; - struct kmem_cache *cachep; - - if (cache_index >= NR_GRPINFO_CACHES) - return -EINVAL; - - if (unlikely(cache_index < 0)) - cache_index = 0; - - mutex_lock(&ext4_grpinfo_slab_create_mutex); - if (ext4_groupinfo_caches[cache_index]) { - mutex_unlock(&ext4_grpinfo_slab_create_mutex); - return 0; /* Already created */ - } - - slab_size = offsetof(struct ext4_group_info, - bb_counters[blocksize_bits + 2]); - - cachep = kmem_cache_create(ext4_groupinfo_slab_names[cache_index], - slab_size, 0, SLAB_RECLAIM_ACCOUNT, - NULL); - - ext4_groupinfo_caches[cache_index] = cachep; - - mutex_unlock(&ext4_grpinfo_slab_create_mutex); - if (!cachep) { - printk(KERN_EMERG - "EXT4-fs: no memory for groupinfo slab cache\n"); - return -ENOMEM; - } - - return 0; -} - -int ext4_mb_init(struct super_block *sb) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - unsigned i, j; - unsigned offset, offset_incr; - unsigned max; - int ret; - - i = (sb->s_blocksize_bits + 2) * sizeof(*sbi->s_mb_offsets); - - sbi->s_mb_offsets = kmalloc(i, GFP_KERNEL); - if (sbi->s_mb_offsets == NULL) { - ret = -ENOMEM; - goto out; - } - - i = (sb->s_blocksize_bits + 2) * sizeof(*sbi->s_mb_maxs); - sbi->s_mb_maxs = kmalloc(i, GFP_KERNEL); - if (sbi->s_mb_maxs == NULL) { - ret = -ENOMEM; - goto out; - } - - ret = ext4_groupinfo_create_slab(sb->s_blocksize); - if (ret < 0) - goto out; - - /* order 0 is regular bitmap */ - sbi->s_mb_maxs[0] = sb->s_blocksize << 3; - sbi->s_mb_offsets[0] = 0; - - i = 1; - offset = 0; - offset_incr = 1 << (sb->s_blocksize_bits - 1); - max = sb->s_blocksize << 2; - do { - sbi->s_mb_offsets[i] = offset; - sbi->s_mb_maxs[i] = max; - offset += offset_incr; - offset_incr = offset_incr >> 1; - max = max >> 1; - i++; - } while (i <= sb->s_blocksize_bits + 1); - - spin_lock_init(&sbi->s_md_lock); - spin_lock_init(&sbi->s_bal_lock); - sbi->s_mb_free_pending = 0; - - sbi->s_mb_max_to_scan = MB_DEFAULT_MAX_TO_SCAN; - sbi->s_mb_min_to_scan = MB_DEFAULT_MIN_TO_SCAN; - sbi->s_mb_stats = MB_DEFAULT_STATS; - sbi->s_mb_stream_request = MB_DEFAULT_STREAM_THRESHOLD; - sbi->s_mb_order2_reqs = MB_DEFAULT_ORDER2_REQS; - /* - * The default group preallocation is 512, which for 4k block - * sizes translates to 2 megabytes. However for bigalloc file - * systems, this is probably too big (i.e, if the cluster size - * is 1 megabyte, then group preallocation size becomes half a - * gigabyte!). As a default, we will keep a two megabyte - * group pralloc size for cluster sizes up to 64k, and after - * that, we will force a minimum group preallocation size of - * 32 clusters. This translates to 8 megs when the cluster - * size is 256k, and 32 megs when the cluster size is 1 meg, - * which seems reasonable as a default. - */ - sbi->s_mb_group_prealloc = max(MB_DEFAULT_GROUP_PREALLOC >> - sbi->s_cluster_bits, 32); - /* - * If there is a s_stripe > 1, then we set the s_mb_group_prealloc - * to the lowest multiple of s_stripe which is bigger than - * the s_mb_group_prealloc as determined above. We want - * the preallocation size to be an exact multiple of the - * RAID stripe size so that preallocations don't fragment - * the stripes. - */ - if (sbi->s_stripe > 1) { - sbi->s_mb_group_prealloc = roundup( - sbi->s_mb_group_prealloc, sbi->s_stripe); - } - - sbi->s_locality_groups = alloc_percpu(struct ext4_locality_group); - if (sbi->s_locality_groups == NULL) { - ret = -ENOMEM; - goto out; - } - for_each_possible_cpu(i) { - struct ext4_locality_group *lg; - lg = per_cpu_ptr(sbi->s_locality_groups, i); - mutex_init(&lg->lg_mutex); - for (j = 0; j < PREALLOC_TB_SIZE; j++) - INIT_LIST_HEAD(&lg->lg_prealloc_list[j]); - spin_lock_init(&lg->lg_prealloc_lock); - } - - /* init file for buddy data */ - ret = ext4_mb_init_backend(sb); - if (ret != 0) - goto out_free_locality_groups; - - return 0; - -out_free_locality_groups: - free_percpu(sbi->s_locality_groups); - sbi->s_locality_groups = NULL; -out: - kfree(sbi->s_mb_offsets); - sbi->s_mb_offsets = NULL; - kfree(sbi->s_mb_maxs); - sbi->s_mb_maxs = NULL; - return ret; -} - -/* need to called with the ext4 group lock held */ -static void ext4_mb_cleanup_pa(struct ext4_group_info *grp) -{ - struct ext4_prealloc_space *pa; - struct list_head *cur, *tmp; - int count = 0; - - list_for_each_safe(cur, tmp, &grp->bb_prealloc_list) { - pa = list_entry(cur, struct ext4_prealloc_space, pa_group_list); - list_del(&pa->pa_group_list); - count++; - kmem_cache_free(ext4_pspace_cachep, pa); - } - if (count) - mb_debug(1, "mballoc: %u PAs left\n", count); - -} - -int ext4_mb_release(struct super_block *sb) -{ - ext4_group_t ngroups = ext4_get_groups_count(sb); - ext4_group_t i; - int num_meta_group_infos; - struct ext4_group_info *grinfo; - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct kmem_cache *cachep = get_groupinfo_cache(sb->s_blocksize_bits); - - if (sbi->s_group_info) { - for (i = 0; i < ngroups; i++) { - grinfo = ext4_get_group_info(sb, i); -#ifdef DOUBLE_CHECK - kfree(grinfo->bb_bitmap); -#endif - ext4_lock_group(sb, i); - ext4_mb_cleanup_pa(grinfo); - ext4_unlock_group(sb, i); - kmem_cache_free(cachep, grinfo); - } - num_meta_group_infos = (ngroups + - EXT4_DESC_PER_BLOCK(sb) - 1) >> - EXT4_DESC_PER_BLOCK_BITS(sb); - for (i = 0; i < num_meta_group_infos; i++) - kfree(sbi->s_group_info[i]); - kvfree(sbi->s_group_info); - } - kfree(sbi->s_mb_offsets); - kfree(sbi->s_mb_maxs); - iput(sbi->s_buddy_cache); - if (sbi->s_mb_stats) { - ext4_msg(sb, KERN_INFO, - "mballoc: %u blocks %u reqs (%u success)", - atomic_read(&sbi->s_bal_allocated), - atomic_read(&sbi->s_bal_reqs), - atomic_read(&sbi->s_bal_success)); - ext4_msg(sb, KERN_INFO, - "mballoc: %u extents scanned, %u goal hits, " - "%u 2^N hits, %u breaks, %u lost", - atomic_read(&sbi->s_bal_ex_scanned), - atomic_read(&sbi->s_bal_goals), - atomic_read(&sbi->s_bal_2orders), - atomic_read(&sbi->s_bal_breaks), - atomic_read(&sbi->s_mb_lost_chunks)); - ext4_msg(sb, KERN_INFO, - "mballoc: %lu generated and it took %Lu", - sbi->s_mb_buddies_generated, - sbi->s_mb_generation_time); - ext4_msg(sb, KERN_INFO, - "mballoc: %u preallocated, %u discarded", - atomic_read(&sbi->s_mb_preallocated), - atomic_read(&sbi->s_mb_discarded)); - } - - free_percpu(sbi->s_locality_groups); - - return 0; -} - -static inline int ext4_issue_discard(struct super_block *sb, - ext4_group_t block_group, ext4_grpblk_t cluster, int count) -{ - ext4_fsblk_t discard_block; - - discard_block = (EXT4_C2B(EXT4_SB(sb), cluster) + - ext4_group_first_block_no(sb, block_group)); - count = EXT4_C2B(EXT4_SB(sb), count); - trace_ext4_discard_blocks(sb, - (unsigned long long) discard_block, count); - return sb_issue_discard(sb, discard_block, count, GFP_NOFS, 0); -} - -/* - * This function is called by the jbd2 layer once the commit has finished, - * so we know we can free the blocks that were released with that commit. - */ -static void ext4_free_data_callback(struct super_block *sb, - struct ext4_journal_cb_entry *jce, - int rc) -{ - struct ext4_free_data *entry = (struct ext4_free_data *)jce; - struct ext4_buddy e4b; - struct ext4_group_info *db; - int err, count = 0, count2 = 0; - - mb_debug(1, "gonna free %u blocks in group %u (0x%p):", - entry->efd_count, entry->efd_group, entry); - - if (test_opt(sb, DISCARD)) { - err = ext4_issue_discard(sb, entry->efd_group, - entry->efd_start_cluster, - entry->efd_count); - if (err && err != -EOPNOTSUPP) - ext4_msg(sb, KERN_WARNING, "discard request in" - " group:%d block:%d count:%d failed" - " with %d", entry->efd_group, - entry->efd_start_cluster, - entry->efd_count, err); - } - - err = ext4_mb_load_buddy(sb, entry->efd_group, &e4b); - /* we expect to find existing buddy because it's pinned */ - BUG_ON(err != 0); - - spin_lock(&EXT4_SB(sb)->s_md_lock); - EXT4_SB(sb)->s_mb_free_pending -= entry->efd_count; - spin_unlock(&EXT4_SB(sb)->s_md_lock); - - db = e4b.bd_info; - /* there are blocks to put in buddy to make them really free */ - count += entry->efd_count; - count2++; - ext4_lock_group(sb, entry->efd_group); - /* Take it out of per group rb tree */ - rb_erase(&entry->efd_node, &(db->bb_free_root)); - mb_free_blocks(NULL, &e4b, entry->efd_start_cluster, entry->efd_count); - - /* - * Clear the trimmed flag for the group so that the next - * ext4_trim_fs can trim it. - * If the volume is mounted with -o discard, online discard - * is supported and the free blocks will be trimmed online. - */ - if (!test_opt(sb, DISCARD)) - EXT4_MB_GRP_CLEAR_TRIMMED(db); - - if (!db->bb_free_root.rb_node) { - /* No more items in the per group rb tree - * balance refcounts from ext4_mb_free_metadata() - */ - put_page(e4b.bd_buddy_page); - put_page(e4b.bd_bitmap_page); - } - ext4_unlock_group(sb, entry->efd_group); - kmem_cache_free(ext4_free_data_cachep, entry); - ext4_mb_unload_buddy(&e4b); - - mb_debug(1, "freed %u blocks in %u structures\n", count, count2); -} - -int __init ext4_init_mballoc(void) -{ - ext4_pspace_cachep = KMEM_CACHE(ext4_prealloc_space, - SLAB_RECLAIM_ACCOUNT); - if (ext4_pspace_cachep == NULL) - return -ENOMEM; - - ext4_ac_cachep = KMEM_CACHE(ext4_allocation_context, - SLAB_RECLAIM_ACCOUNT); - if (ext4_ac_cachep == NULL) { - kmem_cache_destroy(ext4_pspace_cachep); - return -ENOMEM; - } - - ext4_free_data_cachep = KMEM_CACHE(ext4_free_data, - SLAB_RECLAIM_ACCOUNT); - if (ext4_free_data_cachep == NULL) { - kmem_cache_destroy(ext4_pspace_cachep); - kmem_cache_destroy(ext4_ac_cachep); - return -ENOMEM; - } - return 0; -} - -void ext4_exit_mballoc(void) -{ - /* - * Wait for completion of call_rcu()'s on ext4_pspace_cachep - * before destroying the slab cache. - */ - rcu_barrier(); - kmem_cache_destroy(ext4_pspace_cachep); - kmem_cache_destroy(ext4_ac_cachep); - kmem_cache_destroy(ext4_free_data_cachep); - ext4_groupinfo_destroy_slabs(); -} - - -/* - * Check quota and mark chosen space (ac->ac_b_ex) non-free in bitmaps - * Returns 0 if success or error code - */ -static noinline_for_stack int -ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, - handle_t *handle, unsigned int reserv_clstrs) -{ - struct buffer_head *bitmap_bh = NULL; - struct ext4_group_desc *gdp; - struct buffer_head *gdp_bh; - struct ext4_sb_info *sbi; - struct super_block *sb; - ext4_fsblk_t block; - int err, len; - - BUG_ON(ac->ac_status != AC_STATUS_FOUND); - BUG_ON(ac->ac_b_ex.fe_len <= 0); - - sb = ac->ac_sb; - sbi = EXT4_SB(sb); - - bitmap_bh = ext4_read_block_bitmap(sb, ac->ac_b_ex.fe_group); - if (IS_ERR(bitmap_bh)) { - err = PTR_ERR(bitmap_bh); - bitmap_bh = NULL; - goto out_err; - } - - BUFFER_TRACE(bitmap_bh, "getting write access"); - err = ext4_journal_get_write_access(handle, bitmap_bh); - if (err) - goto out_err; - - err = -EIO; - gdp = ext4_get_group_desc(sb, ac->ac_b_ex.fe_group, &gdp_bh); - if (!gdp) - goto out_err; - - ext4_debug("using block group %u(%d)\n", ac->ac_b_ex.fe_group, - ext4_free_group_clusters(sb, gdp)); - - BUFFER_TRACE(gdp_bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, gdp_bh); - if (err) - goto out_err; - - block = ext4_grp_offs_to_block(sb, &ac->ac_b_ex); - - len = EXT4_C2B(sbi, ac->ac_b_ex.fe_len); - if (!ext4_data_block_valid(sbi, block, len)) { - ext4_error(sb, "Allocating blocks %llu-%llu which overlap " - "fs metadata", block, block+len); - /* File system mounted not to panic on error - * Fix the bitmap and return EFSCORRUPTED - * We leak some of the blocks here. - */ - ext4_lock_group(sb, ac->ac_b_ex.fe_group); - ext4_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start, - ac->ac_b_ex.fe_len); - ext4_unlock_group(sb, ac->ac_b_ex.fe_group); - err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); - if (!err) - err = -EFSCORRUPTED; - goto out_err; - } - - ext4_lock_group(sb, ac->ac_b_ex.fe_group); -#ifdef AGGRESSIVE_CHECK - { - int i; - for (i = 0; i < ac->ac_b_ex.fe_len; i++) { - BUG_ON(mb_test_bit(ac->ac_b_ex.fe_start + i, - bitmap_bh->b_data)); - } - } -#endif - ext4_set_bits(bitmap_bh->b_data, ac->ac_b_ex.fe_start, - ac->ac_b_ex.fe_len); - if (gdp->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) { - gdp->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT); - ext4_free_group_clusters_set(sb, gdp, - ext4_free_clusters_after_init(sb, - ac->ac_b_ex.fe_group, gdp)); - } - len = ext4_free_group_clusters(sb, gdp) - ac->ac_b_ex.fe_len; - ext4_free_group_clusters_set(sb, gdp, len); - ext4_block_bitmap_csum_set(sb, ac->ac_b_ex.fe_group, gdp, bitmap_bh); - ext4_group_desc_csum_set(sb, ac->ac_b_ex.fe_group, gdp); - - ext4_unlock_group(sb, ac->ac_b_ex.fe_group); - percpu_counter_sub(&sbi->s_freeclusters_counter, ac->ac_b_ex.fe_len); - /* - * Now reduce the dirty block count also. Should not go negative - */ - if (!(ac->ac_flags & EXT4_MB_DELALLOC_RESERVED)) - /* release all the reserved blocks if non delalloc */ - percpu_counter_sub(&sbi->s_dirtyclusters_counter, - reserv_clstrs); - - if (sbi->s_log_groups_per_flex) { - ext4_group_t flex_group = ext4_flex_group(sbi, - ac->ac_b_ex.fe_group); - atomic64_sub(ac->ac_b_ex.fe_len, - &sbi->s_flex_groups[flex_group].free_clusters); - } - - err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); - if (err) - goto out_err; - err = ext4_handle_dirty_metadata(handle, NULL, gdp_bh); - -out_err: - brelse(bitmap_bh); - return err; -} - -/* - * here we normalize request for locality group - * Group request are normalized to s_mb_group_prealloc, which goes to - * s_strip if we set the same via mount option. - * s_mb_group_prealloc can be configured via - * /sys/fs/ext4//mb_group_prealloc - * - * XXX: should we try to preallocate more than the group has now? - */ -static void ext4_mb_normalize_group_request(struct ext4_allocation_context *ac) -{ - struct super_block *sb = ac->ac_sb; - struct ext4_locality_group *lg = ac->ac_lg; - - BUG_ON(lg == NULL); - ac->ac_g_ex.fe_len = EXT4_SB(sb)->s_mb_group_prealloc; - mb_debug(1, "#%u: goal %u blocks for locality group\n", - current->pid, ac->ac_g_ex.fe_len); -} - -/* - * Normalization means making request better in terms of - * size and alignment - */ -static noinline_for_stack void -ext4_mb_normalize_request(struct ext4_allocation_context *ac, - struct ext4_allocation_request *ar) -{ - struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb); - int bsbits, max; - ext4_lblk_t end; - loff_t size, start_off; - loff_t orig_size __maybe_unused; - ext4_lblk_t start; - struct ext4_inode_info *ei = EXT4_I(ac->ac_inode); - struct ext4_prealloc_space *pa; - - /* do normalize only data requests, metadata requests - do not need preallocation */ - if (!(ac->ac_flags & EXT4_MB_HINT_DATA)) - return; - - /* sometime caller may want exact blocks */ - if (unlikely(ac->ac_flags & EXT4_MB_HINT_GOAL_ONLY)) - return; - - /* caller may indicate that preallocation isn't - * required (it's a tail, for example) */ - if (ac->ac_flags & EXT4_MB_HINT_NOPREALLOC) - return; - - if (ac->ac_flags & EXT4_MB_HINT_GROUP_ALLOC) { - ext4_mb_normalize_group_request(ac); - return ; - } - - bsbits = ac->ac_sb->s_blocksize_bits; - - /* first, let's learn actual file size - * given current request is allocated */ - size = ac->ac_o_ex.fe_logical + EXT4_C2B(sbi, ac->ac_o_ex.fe_len); - size = size << bsbits; - if (size < i_size_read(ac->ac_inode)) - size = i_size_read(ac->ac_inode); - orig_size = size; - - /* max size of free chunks */ - max = 2 << bsbits; - -#define NRL_CHECK_SIZE(req, size, max, chunk_size) \ - (req <= (size) || max <= (chunk_size)) - - /* first, try to predict filesize */ - /* XXX: should this table be tunable? */ - start_off = 0; - if (size <= 16 * 1024) { - size = 16 * 1024; - } else if (size <= 32 * 1024) { - size = 32 * 1024; - } else if (size <= 64 * 1024) { - size = 64 * 1024; - } else if (size <= 128 * 1024) { - size = 128 * 1024; - } else if (size <= 256 * 1024) { - size = 256 * 1024; - } else if (size <= 512 * 1024) { - size = 512 * 1024; - } else if (size <= 1024 * 1024) { - size = 1024 * 1024; - } else if (NRL_CHECK_SIZE(size, 4 * 1024 * 1024, max, 2 * 1024)) { - start_off = ((loff_t)ac->ac_o_ex.fe_logical >> - (21 - bsbits)) << 21; - size = 2 * 1024 * 1024; - } else if (NRL_CHECK_SIZE(size, 8 * 1024 * 1024, max, 4 * 1024)) { - start_off = ((loff_t)ac->ac_o_ex.fe_logical >> - (22 - bsbits)) << 22; - size = 4 * 1024 * 1024; - } else if (NRL_CHECK_SIZE(ac->ac_o_ex.fe_len, - (8<<20)>>bsbits, max, 8 * 1024)) { - start_off = ((loff_t)ac->ac_o_ex.fe_logical >> - (23 - bsbits)) << 23; - size = 8 * 1024 * 1024; - } else { - start_off = (loff_t) ac->ac_o_ex.fe_logical << bsbits; - size = (loff_t) EXT4_C2B(EXT4_SB(ac->ac_sb), - ac->ac_o_ex.fe_len) << bsbits; - } - size = size >> bsbits; - start = start_off >> bsbits; - - /* don't cover already allocated blocks in selected range */ - if (ar->pleft && start <= ar->lleft) { - size -= ar->lleft + 1 - start; - start = ar->lleft + 1; - } - if (ar->pright && start + size - 1 >= ar->lright) - size -= start + size - ar->lright; - - end = start + size; - - /* check we don't cross already preallocated blocks */ - rcu_read_lock(); - list_for_each_entry_rcu(pa, &ei->i_prealloc_list, pa_inode_list) { - ext4_lblk_t pa_end; - - if (pa->pa_deleted) - continue; - spin_lock(&pa->pa_lock); - if (pa->pa_deleted) { - spin_unlock(&pa->pa_lock); - continue; - } - - pa_end = pa->pa_lstart + EXT4_C2B(EXT4_SB(ac->ac_sb), - pa->pa_len); - - /* PA must not overlap original request */ - BUG_ON(!(ac->ac_o_ex.fe_logical >= pa_end || - ac->ac_o_ex.fe_logical < pa->pa_lstart)); - - /* skip PAs this normalized request doesn't overlap with */ - if (pa->pa_lstart >= end || pa_end <= start) { - spin_unlock(&pa->pa_lock); - continue; - } - BUG_ON(pa->pa_lstart <= start && pa_end >= end); - - /* adjust start or end to be adjacent to this pa */ - if (pa_end <= ac->ac_o_ex.fe_logical) { - BUG_ON(pa_end < start); - start = pa_end; - } else if (pa->pa_lstart > ac->ac_o_ex.fe_logical) { - BUG_ON(pa->pa_lstart > end); - end = pa->pa_lstart; - } - spin_unlock(&pa->pa_lock); - } - rcu_read_unlock(); - size = end - start; - - /* XXX: extra loop to check we really don't overlap preallocations */ - rcu_read_lock(); - list_for_each_entry_rcu(pa, &ei->i_prealloc_list, pa_inode_list) { - ext4_lblk_t pa_end; - - spin_lock(&pa->pa_lock); - if (pa->pa_deleted == 0) { - pa_end = pa->pa_lstart + EXT4_C2B(EXT4_SB(ac->ac_sb), - pa->pa_len); - BUG_ON(!(start >= pa_end || end <= pa->pa_lstart)); - } - spin_unlock(&pa->pa_lock); - } - rcu_read_unlock(); - - if (start + size <= ac->ac_o_ex.fe_logical && - start > ac->ac_o_ex.fe_logical) { - ext4_msg(ac->ac_sb, KERN_ERR, - "start %lu, size %lu, fe_logical %lu", - (unsigned long) start, (unsigned long) size, - (unsigned long) ac->ac_o_ex.fe_logical); - BUG(); - } - BUG_ON(size <= 0 || size > EXT4_BLOCKS_PER_GROUP(ac->ac_sb)); - - /* now prepare goal request */ - - /* XXX: is it better to align blocks WRT to logical - * placement or satisfy big request as is */ - ac->ac_g_ex.fe_logical = start; - ac->ac_g_ex.fe_len = EXT4_NUM_B2C(sbi, size); - - /* define goal start in order to merge */ - if (ar->pright && (ar->lright == (start + size))) { - /* merge to the right */ - ext4_get_group_no_and_offset(ac->ac_sb, ar->pright - size, - &ac->ac_f_ex.fe_group, - &ac->ac_f_ex.fe_start); - ac->ac_flags |= EXT4_MB_HINT_TRY_GOAL; - } - if (ar->pleft && (ar->lleft + 1 == start)) { - /* merge to the left */ - ext4_get_group_no_and_offset(ac->ac_sb, ar->pleft + 1, - &ac->ac_f_ex.fe_group, - &ac->ac_f_ex.fe_start); - ac->ac_flags |= EXT4_MB_HINT_TRY_GOAL; - } - - mb_debug(1, "goal: %u(was %u) blocks at %u\n", (unsigned) size, - (unsigned) orig_size, (unsigned) start); -} - -static void ext4_mb_collect_stats(struct ext4_allocation_context *ac) -{ - struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb); - - if (sbi->s_mb_stats && ac->ac_g_ex.fe_len > 1) { - atomic_inc(&sbi->s_bal_reqs); - atomic_add(ac->ac_b_ex.fe_len, &sbi->s_bal_allocated); - if (ac->ac_b_ex.fe_len >= ac->ac_o_ex.fe_len) - atomic_inc(&sbi->s_bal_success); - atomic_add(ac->ac_found, &sbi->s_bal_ex_scanned); - if (ac->ac_g_ex.fe_start == ac->ac_b_ex.fe_start && - ac->ac_g_ex.fe_group == ac->ac_b_ex.fe_group) - atomic_inc(&sbi->s_bal_goals); - if (ac->ac_found > sbi->s_mb_max_to_scan) - atomic_inc(&sbi->s_bal_breaks); - } - - if (ac->ac_op == EXT4_MB_HISTORY_ALLOC) - trace_ext4_mballoc_alloc(ac); - else - trace_ext4_mballoc_prealloc(ac); -} - -/* - * Called on failure; free up any blocks from the inode PA for this - * context. We don't need this for MB_GROUP_PA because we only change - * pa_free in ext4_mb_release_context(), but on failure, we've already - * zeroed out ac->ac_b_ex.fe_len, so group_pa->pa_free is not changed. - */ -static void ext4_discard_allocated_blocks(struct ext4_allocation_context *ac) -{ - struct ext4_prealloc_space *pa = ac->ac_pa; - struct ext4_buddy e4b; - int err; - - if (pa == NULL) { - if (ac->ac_f_ex.fe_len == 0) - return; - err = ext4_mb_load_buddy(ac->ac_sb, ac->ac_f_ex.fe_group, &e4b); - if (err) { - /* - * This should never happen since we pin the - * pages in the ext4_allocation_context so - * ext4_mb_load_buddy() should never fail. - */ - WARN(1, "mb_load_buddy failed (%d)", err); - return; - } - ext4_lock_group(ac->ac_sb, ac->ac_f_ex.fe_group); - mb_free_blocks(ac->ac_inode, &e4b, ac->ac_f_ex.fe_start, - ac->ac_f_ex.fe_len); - ext4_unlock_group(ac->ac_sb, ac->ac_f_ex.fe_group); - ext4_mb_unload_buddy(&e4b); - return; - } - if (pa->pa_type == MB_INODE_PA) - pa->pa_free += ac->ac_b_ex.fe_len; -} - -/* - * use blocks preallocated to inode - */ -static void ext4_mb_use_inode_pa(struct ext4_allocation_context *ac, - struct ext4_prealloc_space *pa) -{ - struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb); - ext4_fsblk_t start; - ext4_fsblk_t end; - int len; - - /* found preallocated blocks, use them */ - start = pa->pa_pstart + (ac->ac_o_ex.fe_logical - pa->pa_lstart); - end = min(pa->pa_pstart + EXT4_C2B(sbi, pa->pa_len), - start + EXT4_C2B(sbi, ac->ac_o_ex.fe_len)); - len = EXT4_NUM_B2C(sbi, end - start); - ext4_get_group_no_and_offset(ac->ac_sb, start, &ac->ac_b_ex.fe_group, - &ac->ac_b_ex.fe_start); - ac->ac_b_ex.fe_len = len; - ac->ac_status = AC_STATUS_FOUND; - ac->ac_pa = pa; - - BUG_ON(start < pa->pa_pstart); - BUG_ON(end > pa->pa_pstart + EXT4_C2B(sbi, pa->pa_len)); - BUG_ON(pa->pa_free < len); - pa->pa_free -= len; - - mb_debug(1, "use %llu/%u from inode pa %p\n", start, len, pa); -} - -/* - * use blocks preallocated to locality group - */ -static void ext4_mb_use_group_pa(struct ext4_allocation_context *ac, - struct ext4_prealloc_space *pa) -{ - unsigned int len = ac->ac_o_ex.fe_len; - - ext4_get_group_no_and_offset(ac->ac_sb, pa->pa_pstart, - &ac->ac_b_ex.fe_group, - &ac->ac_b_ex.fe_start); - ac->ac_b_ex.fe_len = len; - ac->ac_status = AC_STATUS_FOUND; - ac->ac_pa = pa; - - /* we don't correct pa_pstart or pa_plen here to avoid - * possible race when the group is being loaded concurrently - * instead we correct pa later, after blocks are marked - * in on-disk bitmap -- see ext4_mb_release_context() - * Other CPUs are prevented from allocating from this pa by lg_mutex - */ - mb_debug(1, "use %u/%u from group pa %p\n", pa->pa_lstart-len, len, pa); -} - -/* - * Return the prealloc space that have minimal distance - * from the goal block. @cpa is the prealloc - * space that is having currently known minimal distance - * from the goal block. - */ -static struct ext4_prealloc_space * -ext4_mb_check_group_pa(ext4_fsblk_t goal_block, - struct ext4_prealloc_space *pa, - struct ext4_prealloc_space *cpa) -{ - ext4_fsblk_t cur_distance, new_distance; - - if (cpa == NULL) { - atomic_inc(&pa->pa_count); - return pa; - } - cur_distance = abs(goal_block - cpa->pa_pstart); - new_distance = abs(goal_block - pa->pa_pstart); - - if (cur_distance <= new_distance) - return cpa; - - /* drop the previous reference */ - atomic_dec(&cpa->pa_count); - atomic_inc(&pa->pa_count); - return pa; -} - -/* - * search goal blocks in preallocated space - */ -static noinline_for_stack int -ext4_mb_use_preallocated(struct ext4_allocation_context *ac) -{ - struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb); - int order, i; - struct ext4_inode_info *ei = EXT4_I(ac->ac_inode); - struct ext4_locality_group *lg; - struct ext4_prealloc_space *pa, *cpa = NULL; - ext4_fsblk_t goal_block; - - /* only data can be preallocated */ - if (!(ac->ac_flags & EXT4_MB_HINT_DATA)) - return 0; - - /* first, try per-file preallocation */ - rcu_read_lock(); - list_for_each_entry_rcu(pa, &ei->i_prealloc_list, pa_inode_list) { - - /* all fields in this condition don't change, - * so we can skip locking for them */ - if (ac->ac_o_ex.fe_logical < pa->pa_lstart || - ac->ac_o_ex.fe_logical >= (pa->pa_lstart + - EXT4_C2B(sbi, pa->pa_len))) - continue; - - /* non-extent files can't have physical blocks past 2^32 */ - if (!(ext4_test_inode_flag(ac->ac_inode, EXT4_INODE_EXTENTS)) && - (pa->pa_pstart + EXT4_C2B(sbi, pa->pa_len) > - EXT4_MAX_BLOCK_FILE_PHYS)) - continue; - - /* found preallocated blocks, use them */ - spin_lock(&pa->pa_lock); - if (pa->pa_deleted == 0 && pa->pa_free) { - atomic_inc(&pa->pa_count); - ext4_mb_use_inode_pa(ac, pa); - spin_unlock(&pa->pa_lock); - ac->ac_criteria = 10; - rcu_read_unlock(); - return 1; - } - spin_unlock(&pa->pa_lock); - } - rcu_read_unlock(); - - /* can we use group allocation? */ - if (!(ac->ac_flags & EXT4_MB_HINT_GROUP_ALLOC)) - return 0; - - /* inode may have no locality group for some reason */ - lg = ac->ac_lg; - if (lg == NULL) - return 0; - order = fls(ac->ac_o_ex.fe_len) - 1; - if (order > PREALLOC_TB_SIZE - 1) - /* The max size of hash table is PREALLOC_TB_SIZE */ - order = PREALLOC_TB_SIZE - 1; - - goal_block = ext4_grp_offs_to_block(ac->ac_sb, &ac->ac_g_ex); - /* - * search for the prealloc space that is having - * minimal distance from the goal block. - */ - for (i = order; i < PREALLOC_TB_SIZE; i++) { - rcu_read_lock(); - list_for_each_entry_rcu(pa, &lg->lg_prealloc_list[i], - pa_inode_list) { - spin_lock(&pa->pa_lock); - if (pa->pa_deleted == 0 && - pa->pa_free >= ac->ac_o_ex.fe_len) { - - cpa = ext4_mb_check_group_pa(goal_block, - pa, cpa); - } - spin_unlock(&pa->pa_lock); - } - rcu_read_unlock(); - } - if (cpa) { - ext4_mb_use_group_pa(ac, cpa); - ac->ac_criteria = 20; - return 1; - } - return 0; -} - -/* - * the function goes through all block freed in the group - * but not yet committed and marks them used in in-core bitmap. - * buddy must be generated from this bitmap - * Need to be called with the ext4 group lock held - */ -static void ext4_mb_generate_from_freelist(struct super_block *sb, void *bitmap, - ext4_group_t group) -{ - struct rb_node *n; - struct ext4_group_info *grp; - struct ext4_free_data *entry; - - grp = ext4_get_group_info(sb, group); - n = rb_first(&(grp->bb_free_root)); - - while (n) { - entry = rb_entry(n, struct ext4_free_data, efd_node); - ext4_set_bits(bitmap, entry->efd_start_cluster, entry->efd_count); - n = rb_next(n); - } - return; -} - -/* - * the function goes through all preallocation in this group and marks them - * used in in-core bitmap. buddy must be generated from this bitmap - * Need to be called with ext4 group lock held - */ -static noinline_for_stack -void ext4_mb_generate_from_pa(struct super_block *sb, void *bitmap, - ext4_group_t group) -{ - struct ext4_group_info *grp = ext4_get_group_info(sb, group); - struct ext4_prealloc_space *pa; - struct list_head *cur; - ext4_group_t groupnr; - ext4_grpblk_t start; - int preallocated = 0; - int len; - - /* all form of preallocation discards first load group, - * so the only competing code is preallocation use. - * we don't need any locking here - * notice we do NOT ignore preallocations with pa_deleted - * otherwise we could leave used blocks available for - * allocation in buddy when concurrent ext4_mb_put_pa() - * is dropping preallocation - */ - list_for_each(cur, &grp->bb_prealloc_list) { - pa = list_entry(cur, struct ext4_prealloc_space, pa_group_list); - spin_lock(&pa->pa_lock); - ext4_get_group_no_and_offset(sb, pa->pa_pstart, - &groupnr, &start); - len = pa->pa_len; - spin_unlock(&pa->pa_lock); - if (unlikely(len == 0)) - continue; - BUG_ON(groupnr != group); - ext4_set_bits(bitmap, start, len); - preallocated += len; - } - mb_debug(1, "prellocated %u for group %u\n", preallocated, group); -} - -static void ext4_mb_pa_callback(struct rcu_head *head) -{ - struct ext4_prealloc_space *pa; - pa = container_of(head, struct ext4_prealloc_space, u.pa_rcu); - - BUG_ON(atomic_read(&pa->pa_count)); - BUG_ON(pa->pa_deleted == 0); - kmem_cache_free(ext4_pspace_cachep, pa); -} - -/* - * drops a reference to preallocated space descriptor - * if this was the last reference and the space is consumed - */ -static void ext4_mb_put_pa(struct ext4_allocation_context *ac, - struct super_block *sb, struct ext4_prealloc_space *pa) -{ - ext4_group_t grp; - ext4_fsblk_t grp_blk; - - /* in this short window concurrent discard can set pa_deleted */ - spin_lock(&pa->pa_lock); - if (!atomic_dec_and_test(&pa->pa_count) || pa->pa_free != 0) { - spin_unlock(&pa->pa_lock); - return; - } - - if (pa->pa_deleted == 1) { - spin_unlock(&pa->pa_lock); - return; - } - - pa->pa_deleted = 1; - spin_unlock(&pa->pa_lock); - - grp_blk = pa->pa_pstart; - /* - * If doing group-based preallocation, pa_pstart may be in the - * next group when pa is used up - */ - if (pa->pa_type == MB_GROUP_PA) - grp_blk--; - - grp = ext4_get_group_number(sb, grp_blk); - - /* - * possible race: - * - * P1 (buddy init) P2 (regular allocation) - * find block B in PA - * copy on-disk bitmap to buddy - * mark B in on-disk bitmap - * drop PA from group - * mark all PAs in buddy - * - * thus, P1 initializes buddy with B available. to prevent this - * we make "copy" and "mark all PAs" atomic and serialize "drop PA" - * against that pair - */ - ext4_lock_group(sb, grp); - list_del(&pa->pa_group_list); - ext4_unlock_group(sb, grp); - - spin_lock(pa->pa_obj_lock); - list_del_rcu(&pa->pa_inode_list); - spin_unlock(pa->pa_obj_lock); - - call_rcu(&(pa)->u.pa_rcu, ext4_mb_pa_callback); -} - -/* - * creates new preallocated space for given inode - */ -static noinline_for_stack int -ext4_mb_new_inode_pa(struct ext4_allocation_context *ac) -{ - struct super_block *sb = ac->ac_sb; - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_prealloc_space *pa; - struct ext4_group_info *grp; - struct ext4_inode_info *ei; - - /* preallocate only when found space is larger then requested */ - BUG_ON(ac->ac_o_ex.fe_len >= ac->ac_b_ex.fe_len); - BUG_ON(ac->ac_status != AC_STATUS_FOUND); - BUG_ON(!S_ISREG(ac->ac_inode->i_mode)); - - pa = kmem_cache_alloc(ext4_pspace_cachep, GFP_NOFS); - if (pa == NULL) - return -ENOMEM; - - if (ac->ac_b_ex.fe_len < ac->ac_g_ex.fe_len) { - int winl; - int wins; - int win; - int offs; - - /* we can't allocate as much as normalizer wants. - * so, found space must get proper lstart - * to cover original request */ - BUG_ON(ac->ac_g_ex.fe_logical > ac->ac_o_ex.fe_logical); - BUG_ON(ac->ac_g_ex.fe_len < ac->ac_o_ex.fe_len); - - /* we're limited by original request in that - * logical block must be covered any way - * winl is window we can move our chunk within */ - winl = ac->ac_o_ex.fe_logical - ac->ac_g_ex.fe_logical; - - /* also, we should cover whole original request */ - wins = EXT4_C2B(sbi, ac->ac_b_ex.fe_len - ac->ac_o_ex.fe_len); - - /* the smallest one defines real window */ - win = min(winl, wins); - - offs = ac->ac_o_ex.fe_logical % - EXT4_C2B(sbi, ac->ac_b_ex.fe_len); - if (offs && offs < win) - win = offs; - - ac->ac_b_ex.fe_logical = ac->ac_o_ex.fe_logical - - EXT4_NUM_B2C(sbi, win); - BUG_ON(ac->ac_o_ex.fe_logical < ac->ac_b_ex.fe_logical); - BUG_ON(ac->ac_o_ex.fe_len > ac->ac_b_ex.fe_len); - } - - /* preallocation can change ac_b_ex, thus we store actually - * allocated blocks for history */ - ac->ac_f_ex = ac->ac_b_ex; - - pa->pa_lstart = ac->ac_b_ex.fe_logical; - pa->pa_pstart = ext4_grp_offs_to_block(sb, &ac->ac_b_ex); - pa->pa_len = ac->ac_b_ex.fe_len; - pa->pa_free = pa->pa_len; - atomic_set(&pa->pa_count, 1); - spin_lock_init(&pa->pa_lock); - INIT_LIST_HEAD(&pa->pa_inode_list); - INIT_LIST_HEAD(&pa->pa_group_list); - pa->pa_deleted = 0; - pa->pa_type = MB_INODE_PA; - - mb_debug(1, "new inode pa %p: %llu/%u for %u\n", pa, - pa->pa_pstart, pa->pa_len, pa->pa_lstart); - trace_ext4_mb_new_inode_pa(ac, pa); - - ext4_mb_use_inode_pa(ac, pa); - atomic_add(pa->pa_free, &sbi->s_mb_preallocated); - - ei = EXT4_I(ac->ac_inode); - grp = ext4_get_group_info(sb, ac->ac_b_ex.fe_group); - - pa->pa_obj_lock = &ei->i_prealloc_lock; - pa->pa_inode = ac->ac_inode; - - ext4_lock_group(sb, ac->ac_b_ex.fe_group); - list_add(&pa->pa_group_list, &grp->bb_prealloc_list); - ext4_unlock_group(sb, ac->ac_b_ex.fe_group); - - spin_lock(pa->pa_obj_lock); - list_add_rcu(&pa->pa_inode_list, &ei->i_prealloc_list); - spin_unlock(pa->pa_obj_lock); - - return 0; -} - -/* - * creates new preallocated space for locality group inodes belongs to - */ -static noinline_for_stack int -ext4_mb_new_group_pa(struct ext4_allocation_context *ac) -{ - struct super_block *sb = ac->ac_sb; - struct ext4_locality_group *lg; - struct ext4_prealloc_space *pa; - struct ext4_group_info *grp; - - /* preallocate only when found space is larger then requested */ - BUG_ON(ac->ac_o_ex.fe_len >= ac->ac_b_ex.fe_len); - BUG_ON(ac->ac_status != AC_STATUS_FOUND); - BUG_ON(!S_ISREG(ac->ac_inode->i_mode)); - - BUG_ON(ext4_pspace_cachep == NULL); - pa = kmem_cache_alloc(ext4_pspace_cachep, GFP_NOFS); - if (pa == NULL) - return -ENOMEM; - - /* preallocation can change ac_b_ex, thus we store actually - * allocated blocks for history */ - ac->ac_f_ex = ac->ac_b_ex; - - pa->pa_pstart = ext4_grp_offs_to_block(sb, &ac->ac_b_ex); - pa->pa_lstart = pa->pa_pstart; - pa->pa_len = ac->ac_b_ex.fe_len; - pa->pa_free = pa->pa_len; - atomic_set(&pa->pa_count, 1); - spin_lock_init(&pa->pa_lock); - INIT_LIST_HEAD(&pa->pa_inode_list); - INIT_LIST_HEAD(&pa->pa_group_list); - pa->pa_deleted = 0; - pa->pa_type = MB_GROUP_PA; - - mb_debug(1, "new group pa %p: %llu/%u for %u\n", pa, - pa->pa_pstart, pa->pa_len, pa->pa_lstart); - trace_ext4_mb_new_group_pa(ac, pa); - - ext4_mb_use_group_pa(ac, pa); - atomic_add(pa->pa_free, &EXT4_SB(sb)->s_mb_preallocated); - - grp = ext4_get_group_info(sb, ac->ac_b_ex.fe_group); - lg = ac->ac_lg; - BUG_ON(lg == NULL); - - pa->pa_obj_lock = &lg->lg_prealloc_lock; - pa->pa_inode = NULL; - - ext4_lock_group(sb, ac->ac_b_ex.fe_group); - list_add(&pa->pa_group_list, &grp->bb_prealloc_list); - ext4_unlock_group(sb, ac->ac_b_ex.fe_group); - - /* - * We will later add the new pa to the right bucket - * after updating the pa_free in ext4_mb_release_context - */ - return 0; -} - -static int ext4_mb_new_preallocation(struct ext4_allocation_context *ac) -{ - int err; - - if (ac->ac_flags & EXT4_MB_HINT_GROUP_ALLOC) - err = ext4_mb_new_group_pa(ac); - else - err = ext4_mb_new_inode_pa(ac); - return err; -} - -/* - * finds all unused blocks in on-disk bitmap, frees them in - * in-core bitmap and buddy. - * @pa must be unlinked from inode and group lists, so that - * nobody else can find/use it. - * the caller MUST hold group/inode locks. - * TODO: optimize the case when there are no in-core structures yet - */ -static noinline_for_stack int -ext4_mb_release_inode_pa(struct ext4_buddy *e4b, struct buffer_head *bitmap_bh, - struct ext4_prealloc_space *pa) -{ - struct super_block *sb = e4b->bd_sb; - struct ext4_sb_info *sbi = EXT4_SB(sb); - unsigned int end; - unsigned int next; - ext4_group_t group; - ext4_grpblk_t bit; - unsigned long long grp_blk_start; - int err = 0; - int free = 0; - - BUG_ON(pa->pa_deleted == 0); - ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, &bit); - grp_blk_start = pa->pa_pstart - EXT4_C2B(sbi, bit); - BUG_ON(group != e4b->bd_group && pa->pa_len != 0); - end = bit + pa->pa_len; - - while (bit < end) { - bit = mb_find_next_zero_bit(bitmap_bh->b_data, end, bit); - if (bit >= end) - break; - next = mb_find_next_bit(bitmap_bh->b_data, end, bit); - mb_debug(1, " free preallocated %u/%u in group %u\n", - (unsigned) ext4_group_first_block_no(sb, group) + bit, - (unsigned) next - bit, (unsigned) group); - free += next - bit; - - trace_ext4_mballoc_discard(sb, NULL, group, bit, next - bit); - trace_ext4_mb_release_inode_pa(pa, (grp_blk_start + - EXT4_C2B(sbi, bit)), - next - bit); - mb_free_blocks(pa->pa_inode, e4b, bit, next - bit); - bit = next + 1; - } - if (free != pa->pa_free) { - ext4_msg(e4b->bd_sb, KERN_CRIT, - "pa %p: logic %lu, phys. %lu, len %lu", - pa, (unsigned long) pa->pa_lstart, - (unsigned long) pa->pa_pstart, - (unsigned long) pa->pa_len); - ext4_grp_locked_error(sb, group, 0, 0, "free %u, pa_free %u", - free, pa->pa_free); - /* - * pa is already deleted so we use the value obtained - * from the bitmap and continue. - */ - } - atomic_add(free, &sbi->s_mb_discarded); - - return err; -} - -static noinline_for_stack int -ext4_mb_release_group_pa(struct ext4_buddy *e4b, - struct ext4_prealloc_space *pa) -{ - struct super_block *sb = e4b->bd_sb; - ext4_group_t group; - ext4_grpblk_t bit; - - trace_ext4_mb_release_group_pa(sb, pa); - BUG_ON(pa->pa_deleted == 0); - ext4_get_group_no_and_offset(sb, pa->pa_pstart, &group, &bit); - BUG_ON(group != e4b->bd_group && pa->pa_len != 0); - mb_free_blocks(pa->pa_inode, e4b, bit, pa->pa_len); - atomic_add(pa->pa_len, &EXT4_SB(sb)->s_mb_discarded); - trace_ext4_mballoc_discard(sb, NULL, group, bit, pa->pa_len); - - return 0; -} - -/* - * releases all preallocations in given group - * - * first, we need to decide discard policy: - * - when do we discard - * 1) ENOSPC - * - how many do we discard - * 1) how many requested - */ -static noinline_for_stack int -ext4_mb_discard_group_preallocations(struct super_block *sb, - ext4_group_t group, int needed) -{ - struct ext4_group_info *grp = ext4_get_group_info(sb, group); - struct buffer_head *bitmap_bh = NULL; - struct ext4_prealloc_space *pa, *tmp; - struct list_head list; - struct ext4_buddy e4b; - int err; - int busy = 0; - int free = 0; - - mb_debug(1, "discard preallocation for group %u\n", group); - - if (list_empty(&grp->bb_prealloc_list)) - return 0; - - bitmap_bh = ext4_read_block_bitmap(sb, group); - if (IS_ERR(bitmap_bh)) { - err = PTR_ERR(bitmap_bh); - ext4_error(sb, "Error %d reading block bitmap for %u", - err, group); - return 0; - } - - err = ext4_mb_load_buddy(sb, group, &e4b); - if (err) { - ext4_error(sb, "Error loading buddy information for %u", group); - put_bh(bitmap_bh); - return 0; - } - - if (needed == 0) - needed = EXT4_CLUSTERS_PER_GROUP(sb) + 1; - - INIT_LIST_HEAD(&list); -repeat: - ext4_lock_group(sb, group); - list_for_each_entry_safe(pa, tmp, - &grp->bb_prealloc_list, pa_group_list) { - spin_lock(&pa->pa_lock); - if (atomic_read(&pa->pa_count)) { - spin_unlock(&pa->pa_lock); - busy = 1; - continue; - } - if (pa->pa_deleted) { - spin_unlock(&pa->pa_lock); - continue; - } - - /* seems this one can be freed ... */ - pa->pa_deleted = 1; - - /* we can trust pa_free ... */ - free += pa->pa_free; - - spin_unlock(&pa->pa_lock); - - list_del(&pa->pa_group_list); - list_add(&pa->u.pa_tmp_list, &list); - } - - /* if we still need more blocks and some PAs were used, try again */ - if (free < needed && busy) { - busy = 0; - ext4_unlock_group(sb, group); - cond_resched(); - goto repeat; - } - - /* found anything to free? */ - if (list_empty(&list)) { - BUG_ON(free != 0); - goto out; - } - - /* now free all selected PAs */ - list_for_each_entry_safe(pa, tmp, &list, u.pa_tmp_list) { - - /* remove from object (inode or locality group) */ - spin_lock(pa->pa_obj_lock); - list_del_rcu(&pa->pa_inode_list); - spin_unlock(pa->pa_obj_lock); - - if (pa->pa_type == MB_GROUP_PA) - ext4_mb_release_group_pa(&e4b, pa); - else - ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa); - - list_del(&pa->u.pa_tmp_list); - call_rcu(&(pa)->u.pa_rcu, ext4_mb_pa_callback); - } - -out: - ext4_unlock_group(sb, group); - ext4_mb_unload_buddy(&e4b); - put_bh(bitmap_bh); - return free; -} - -/* - * releases all non-used preallocated blocks for given inode - * - * It's important to discard preallocations under i_data_sem - * We don't want another block to be served from the prealloc - * space when we are discarding the inode prealloc space. - * - * FIXME!! Make sure it is valid at all the call sites - */ -void ext4_discard_preallocations(struct inode *inode) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - struct super_block *sb = inode->i_sb; - struct buffer_head *bitmap_bh = NULL; - struct ext4_prealloc_space *pa, *tmp; - ext4_group_t group = 0; - struct list_head list; - struct ext4_buddy e4b; - int err; - - if (!S_ISREG(inode->i_mode)) { - /*BUG_ON(!list_empty(&ei->i_prealloc_list));*/ - return; - } - - mb_debug(1, "discard preallocation for inode %lu\n", inode->i_ino); - trace_ext4_discard_preallocations(inode); - - INIT_LIST_HEAD(&list); - -repeat: - /* first, collect all pa's in the inode */ - spin_lock(&ei->i_prealloc_lock); - while (!list_empty(&ei->i_prealloc_list)) { - pa = list_entry(ei->i_prealloc_list.next, - struct ext4_prealloc_space, pa_inode_list); - BUG_ON(pa->pa_obj_lock != &ei->i_prealloc_lock); - spin_lock(&pa->pa_lock); - if (atomic_read(&pa->pa_count)) { - /* this shouldn't happen often - nobody should - * use preallocation while we're discarding it */ - spin_unlock(&pa->pa_lock); - spin_unlock(&ei->i_prealloc_lock); - ext4_msg(sb, KERN_ERR, - "uh-oh! used pa while discarding"); - WARN_ON(1); - schedule_timeout_uninterruptible(HZ); - goto repeat; - - } - if (pa->pa_deleted == 0) { - pa->pa_deleted = 1; - spin_unlock(&pa->pa_lock); - list_del_rcu(&pa->pa_inode_list); - list_add(&pa->u.pa_tmp_list, &list); - continue; - } - - /* someone is deleting pa right now */ - spin_unlock(&pa->pa_lock); - spin_unlock(&ei->i_prealloc_lock); - - /* we have to wait here because pa_deleted - * doesn't mean pa is already unlinked from - * the list. as we might be called from - * ->clear_inode() the inode will get freed - * and concurrent thread which is unlinking - * pa from inode's list may access already - * freed memory, bad-bad-bad */ - - /* XXX: if this happens too often, we can - * add a flag to force wait only in case - * of ->clear_inode(), but not in case of - * regular truncate */ - schedule_timeout_uninterruptible(HZ); - goto repeat; - } - spin_unlock(&ei->i_prealloc_lock); - - list_for_each_entry_safe(pa, tmp, &list, u.pa_tmp_list) { - BUG_ON(pa->pa_type != MB_INODE_PA); - group = ext4_get_group_number(sb, pa->pa_pstart); - - err = ext4_mb_load_buddy(sb, group, &e4b); - if (err) { - ext4_error(sb, "Error loading buddy information for %u", - group); - continue; - } - - bitmap_bh = ext4_read_block_bitmap(sb, group); - if (IS_ERR(bitmap_bh)) { - err = PTR_ERR(bitmap_bh); - ext4_error(sb, "Error %d reading block bitmap for %u", - err, group); - ext4_mb_unload_buddy(&e4b); - continue; - } - - ext4_lock_group(sb, group); - list_del(&pa->pa_group_list); - ext4_mb_release_inode_pa(&e4b, bitmap_bh, pa); - ext4_unlock_group(sb, group); - - ext4_mb_unload_buddy(&e4b); - put_bh(bitmap_bh); - - list_del(&pa->u.pa_tmp_list); - call_rcu(&(pa)->u.pa_rcu, ext4_mb_pa_callback); - } -} - -#ifdef CONFIG_EXT4_DEBUG -static void ext4_mb_show_ac(struct ext4_allocation_context *ac) -{ - struct super_block *sb = ac->ac_sb; - ext4_group_t ngroups, i; - - if (!ext4_mballoc_debug || - (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)) - return; - - ext4_msg(ac->ac_sb, KERN_ERR, "Can't allocate:" - " Allocation context details:"); - ext4_msg(ac->ac_sb, KERN_ERR, "status %d flags %d", - ac->ac_status, ac->ac_flags); - ext4_msg(ac->ac_sb, KERN_ERR, "orig %lu/%lu/%lu@%lu, " - "goal %lu/%lu/%lu@%lu, " - "best %lu/%lu/%lu@%lu cr %d", - (unsigned long)ac->ac_o_ex.fe_group, - (unsigned long)ac->ac_o_ex.fe_start, - (unsigned long)ac->ac_o_ex.fe_len, - (unsigned long)ac->ac_o_ex.fe_logical, - (unsigned long)ac->ac_g_ex.fe_group, - (unsigned long)ac->ac_g_ex.fe_start, - (unsigned long)ac->ac_g_ex.fe_len, - (unsigned long)ac->ac_g_ex.fe_logical, - (unsigned long)ac->ac_b_ex.fe_group, - (unsigned long)ac->ac_b_ex.fe_start, - (unsigned long)ac->ac_b_ex.fe_len, - (unsigned long)ac->ac_b_ex.fe_logical, - (int)ac->ac_criteria); - ext4_msg(ac->ac_sb, KERN_ERR, "%d found", ac->ac_found); - ext4_msg(ac->ac_sb, KERN_ERR, "groups: "); - ngroups = ext4_get_groups_count(sb); - for (i = 0; i < ngroups; i++) { - struct ext4_group_info *grp = ext4_get_group_info(sb, i); - struct ext4_prealloc_space *pa; - ext4_grpblk_t start; - struct list_head *cur; - ext4_lock_group(sb, i); - list_for_each(cur, &grp->bb_prealloc_list) { - pa = list_entry(cur, struct ext4_prealloc_space, - pa_group_list); - spin_lock(&pa->pa_lock); - ext4_get_group_no_and_offset(sb, pa->pa_pstart, - NULL, &start); - spin_unlock(&pa->pa_lock); - printk(KERN_ERR "PA:%u:%d:%u \n", i, - start, pa->pa_len); - } - ext4_unlock_group(sb, i); - - if (grp->bb_free == 0) - continue; - printk(KERN_ERR "%u: %d/%d \n", - i, grp->bb_free, grp->bb_fragments); - } - printk(KERN_ERR "\n"); -} -#else -static inline void ext4_mb_show_ac(struct ext4_allocation_context *ac) -{ - return; -} -#endif - -/* - * We use locality group preallocation for small size file. The size of the - * file is determined by the current size or the resulting size after - * allocation which ever is larger - * - * One can tune this size via /sys/fs/ext4//mb_stream_req - */ -static void ext4_mb_group_or_file(struct ext4_allocation_context *ac) -{ - struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb); - int bsbits = ac->ac_sb->s_blocksize_bits; - loff_t size, isize; - - if (!(ac->ac_flags & EXT4_MB_HINT_DATA)) - return; - - if (unlikely(ac->ac_flags & EXT4_MB_HINT_GOAL_ONLY)) - return; - - size = ac->ac_o_ex.fe_logical + EXT4_C2B(sbi, ac->ac_o_ex.fe_len); - isize = (i_size_read(ac->ac_inode) + ac->ac_sb->s_blocksize - 1) - >> bsbits; - - if ((size == isize) && - !ext4_fs_is_busy(sbi) && - (atomic_read(&ac->ac_inode->i_writecount) == 0)) { - ac->ac_flags |= EXT4_MB_HINT_NOPREALLOC; - return; - } - - if (sbi->s_mb_group_prealloc <= 0) { - ac->ac_flags |= EXT4_MB_STREAM_ALLOC; - return; - } - - /* don't use group allocation for large files */ - size = max(size, isize); - if (size > sbi->s_mb_stream_request) { - ac->ac_flags |= EXT4_MB_STREAM_ALLOC; - return; - } - - BUG_ON(ac->ac_lg != NULL); - /* - * locality group prealloc space are per cpu. The reason for having - * per cpu locality group is to reduce the contention between block - * request from multiple CPUs. - */ - ac->ac_lg = raw_cpu_ptr(sbi->s_locality_groups); - - /* we're going to use group allocation */ - ac->ac_flags |= EXT4_MB_HINT_GROUP_ALLOC; - - /* serialize all allocations in the group */ - mutex_lock(&ac->ac_lg->lg_mutex); -} - -static noinline_for_stack int -ext4_mb_initialize_context(struct ext4_allocation_context *ac, - struct ext4_allocation_request *ar) -{ - struct super_block *sb = ar->inode->i_sb; - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_super_block *es = sbi->s_es; - ext4_group_t group; - unsigned int len; - ext4_fsblk_t goal; - ext4_grpblk_t block; - - /* we can't allocate > group size */ - len = ar->len; - - /* just a dirty hack to filter too big requests */ - if (len >= EXT4_CLUSTERS_PER_GROUP(sb)) - len = EXT4_CLUSTERS_PER_GROUP(sb); - - /* start searching from the goal */ - goal = ar->goal; - if (goal < le32_to_cpu(es->s_first_data_block) || - goal >= ext4_blocks_count(es)) - goal = le32_to_cpu(es->s_first_data_block); - ext4_get_group_no_and_offset(sb, goal, &group, &block); - - /* set up allocation goals */ - ac->ac_b_ex.fe_logical = EXT4_LBLK_CMASK(sbi, ar->logical); - ac->ac_status = AC_STATUS_CONTINUE; - ac->ac_sb = sb; - ac->ac_inode = ar->inode; - ac->ac_o_ex.fe_logical = ac->ac_b_ex.fe_logical; - ac->ac_o_ex.fe_group = group; - ac->ac_o_ex.fe_start = block; - ac->ac_o_ex.fe_len = len; - ac->ac_g_ex = ac->ac_o_ex; - ac->ac_flags = ar->flags; - - /* we have to define context: we'll we work with a file or - * locality group. this is a policy, actually */ - ext4_mb_group_or_file(ac); - - mb_debug(1, "init ac: %u blocks @ %u, goal %u, flags %x, 2^%d, " - "left: %u/%u, right %u/%u to %swritable\n", - (unsigned) ar->len, (unsigned) ar->logical, - (unsigned) ar->goal, ac->ac_flags, ac->ac_2order, - (unsigned) ar->lleft, (unsigned) ar->pleft, - (unsigned) ar->lright, (unsigned) ar->pright, - atomic_read(&ar->inode->i_writecount) ? "" : "non-"); - return 0; - -} - -static noinline_for_stack void -ext4_mb_discard_lg_preallocations(struct super_block *sb, - struct ext4_locality_group *lg, - int order, int total_entries) -{ - ext4_group_t group = 0; - struct ext4_buddy e4b; - struct list_head discard_list; - struct ext4_prealloc_space *pa, *tmp; - - mb_debug(1, "discard locality group preallocation\n"); - - INIT_LIST_HEAD(&discard_list); - - spin_lock(&lg->lg_prealloc_lock); - list_for_each_entry_rcu(pa, &lg->lg_prealloc_list[order], - pa_inode_list) { - spin_lock(&pa->pa_lock); - if (atomic_read(&pa->pa_count)) { - /* - * This is the pa that we just used - * for block allocation. So don't - * free that - */ - spin_unlock(&pa->pa_lock); - continue; - } - if (pa->pa_deleted) { - spin_unlock(&pa->pa_lock); - continue; - } - /* only lg prealloc space */ - BUG_ON(pa->pa_type != MB_GROUP_PA); - - /* seems this one can be freed ... */ - pa->pa_deleted = 1; - spin_unlock(&pa->pa_lock); - - list_del_rcu(&pa->pa_inode_list); - list_add(&pa->u.pa_tmp_list, &discard_list); - - total_entries--; - if (total_entries <= 5) { - /* - * we want to keep only 5 entries - * allowing it to grow to 8. This - * mak sure we don't call discard - * soon for this list. - */ - break; - } - } - spin_unlock(&lg->lg_prealloc_lock); - - list_for_each_entry_safe(pa, tmp, &discard_list, u.pa_tmp_list) { - - group = ext4_get_group_number(sb, pa->pa_pstart); - if (ext4_mb_load_buddy(sb, group, &e4b)) { - ext4_error(sb, "Error loading buddy information for %u", - group); - continue; - } - ext4_lock_group(sb, group); - list_del(&pa->pa_group_list); - ext4_mb_release_group_pa(&e4b, pa); - ext4_unlock_group(sb, group); - - ext4_mb_unload_buddy(&e4b); - list_del(&pa->u.pa_tmp_list); - call_rcu(&(pa)->u.pa_rcu, ext4_mb_pa_callback); - } -} - -/* - * We have incremented pa_count. So it cannot be freed at this - * point. Also we hold lg_mutex. So no parallel allocation is - * possible from this lg. That means pa_free cannot be updated. - * - * A parallel ext4_mb_discard_group_preallocations is possible. - * which can cause the lg_prealloc_list to be updated. - */ - -static void ext4_mb_add_n_trim(struct ext4_allocation_context *ac) -{ - int order, added = 0, lg_prealloc_count = 1; - struct super_block *sb = ac->ac_sb; - struct ext4_locality_group *lg = ac->ac_lg; - struct ext4_prealloc_space *tmp_pa, *pa = ac->ac_pa; - - order = fls(pa->pa_free) - 1; - if (order > PREALLOC_TB_SIZE - 1) - /* The max size of hash table is PREALLOC_TB_SIZE */ - order = PREALLOC_TB_SIZE - 1; - /* Add the prealloc space to lg */ - spin_lock(&lg->lg_prealloc_lock); - list_for_each_entry_rcu(tmp_pa, &lg->lg_prealloc_list[order], - pa_inode_list) { - spin_lock(&tmp_pa->pa_lock); - if (tmp_pa->pa_deleted) { - spin_unlock(&tmp_pa->pa_lock); - continue; - } - if (!added && pa->pa_free < tmp_pa->pa_free) { - /* Add to the tail of the previous entry */ - list_add_tail_rcu(&pa->pa_inode_list, - &tmp_pa->pa_inode_list); - added = 1; - /* - * we want to count the total - * number of entries in the list - */ - } - spin_unlock(&tmp_pa->pa_lock); - lg_prealloc_count++; - } - if (!added) - list_add_tail_rcu(&pa->pa_inode_list, - &lg->lg_prealloc_list[order]); - spin_unlock(&lg->lg_prealloc_lock); - - /* Now trim the list to be not more than 8 elements */ - if (lg_prealloc_count > 8) { - ext4_mb_discard_lg_preallocations(sb, lg, - order, lg_prealloc_count); - return; - } - return ; -} - -/* - * release all resource we used in allocation - */ -static int ext4_mb_release_context(struct ext4_allocation_context *ac) -{ - struct ext4_sb_info *sbi = EXT4_SB(ac->ac_sb); - struct ext4_prealloc_space *pa = ac->ac_pa; - if (pa) { - if (pa->pa_type == MB_GROUP_PA) { - /* see comment in ext4_mb_use_group_pa() */ - spin_lock(&pa->pa_lock); - pa->pa_pstart += EXT4_C2B(sbi, ac->ac_b_ex.fe_len); - pa->pa_lstart += EXT4_C2B(sbi, ac->ac_b_ex.fe_len); - pa->pa_free -= ac->ac_b_ex.fe_len; - pa->pa_len -= ac->ac_b_ex.fe_len; - spin_unlock(&pa->pa_lock); - } - } - if (pa) { - /* - * We want to add the pa to the right bucket. - * Remove it from the list and while adding - * make sure the list to which we are adding - * doesn't grow big. - */ - if ((pa->pa_type == MB_GROUP_PA) && likely(pa->pa_free)) { - spin_lock(pa->pa_obj_lock); - list_del_rcu(&pa->pa_inode_list); - spin_unlock(pa->pa_obj_lock); - ext4_mb_add_n_trim(ac); - } - ext4_mb_put_pa(ac, ac->ac_sb, pa); - } - if (ac->ac_bitmap_page) - put_page(ac->ac_bitmap_page); - if (ac->ac_buddy_page) - put_page(ac->ac_buddy_page); - if (ac->ac_flags & EXT4_MB_HINT_GROUP_ALLOC) - mutex_unlock(&ac->ac_lg->lg_mutex); - ext4_mb_collect_stats(ac); - return 0; -} - -static int ext4_mb_discard_preallocations(struct super_block *sb, int needed) -{ - ext4_group_t i, ngroups = ext4_get_groups_count(sb); - int ret; - int freed = 0; - - trace_ext4_mb_discard_preallocations(sb, needed); - for (i = 0; i < ngroups && needed > 0; i++) { - ret = ext4_mb_discard_group_preallocations(sb, i, needed); - freed += ret; - needed -= ret; - } - - return freed; -} - -/* - * Main entry point into mballoc to allocate blocks - * it tries to use preallocation first, then falls back - * to usual allocation - */ -ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, - struct ext4_allocation_request *ar, int *errp) -{ - int freed; - struct ext4_allocation_context *ac = NULL; - struct ext4_sb_info *sbi; - struct super_block *sb; - ext4_fsblk_t block = 0; - unsigned int inquota = 0; - unsigned int reserv_clstrs = 0; - - might_sleep(); - sb = ar->inode->i_sb; - sbi = EXT4_SB(sb); - - trace_ext4_request_blocks(ar); - - /* Allow to use superuser reservation for quota file */ - if (IS_NOQUOTA(ar->inode)) - ar->flags |= EXT4_MB_USE_ROOT_BLOCKS; - - if ((ar->flags & EXT4_MB_DELALLOC_RESERVED) == 0) { - /* Without delayed allocation we need to verify - * there is enough free blocks to do block allocation - * and verify allocation doesn't exceed the quota limits. - */ - while (ar->len && - ext4_claim_free_clusters(sbi, ar->len, ar->flags)) { - - /* let others to free the space */ - cond_resched(); - ar->len = ar->len >> 1; - } - if (!ar->len) { - *errp = -ENOSPC; - return 0; - } - reserv_clstrs = ar->len; - if (ar->flags & EXT4_MB_USE_ROOT_BLOCKS) { - dquot_alloc_block_nofail(ar->inode, - EXT4_C2B(sbi, ar->len)); - } else { - while (ar->len && - dquot_alloc_block(ar->inode, - EXT4_C2B(sbi, ar->len))) { - - ar->flags |= EXT4_MB_HINT_NOPREALLOC; - ar->len--; - } - } - inquota = ar->len; - if (ar->len == 0) { - *errp = -EDQUOT; - goto out; - } - } - - ac = kmem_cache_zalloc(ext4_ac_cachep, GFP_NOFS); - if (!ac) { - ar->len = 0; - *errp = -ENOMEM; - goto out; - } - - *errp = ext4_mb_initialize_context(ac, ar); - if (*errp) { - ar->len = 0; - goto out; - } - - ac->ac_op = EXT4_MB_HISTORY_PREALLOC; - if (!ext4_mb_use_preallocated(ac)) { - ac->ac_op = EXT4_MB_HISTORY_ALLOC; - ext4_mb_normalize_request(ac, ar); -repeat: - /* allocate space in core */ - *errp = ext4_mb_regular_allocator(ac); - if (*errp) - goto discard_and_exit; - - /* as we've just preallocated more space than - * user requested originally, we store allocated - * space in a special descriptor */ - if (ac->ac_status == AC_STATUS_FOUND && - ac->ac_o_ex.fe_len < ac->ac_b_ex.fe_len) - *errp = ext4_mb_new_preallocation(ac); - if (*errp) { - discard_and_exit: - ext4_discard_allocated_blocks(ac); - goto errout; - } - } - if (likely(ac->ac_status == AC_STATUS_FOUND)) { - *errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_clstrs); - if (*errp) { - ext4_discard_allocated_blocks(ac); - goto errout; - } else { - block = ext4_grp_offs_to_block(sb, &ac->ac_b_ex); - ar->len = ac->ac_b_ex.fe_len; - } - } else { - freed = ext4_mb_discard_preallocations(sb, ac->ac_o_ex.fe_len); - if (freed) - goto repeat; - *errp = -ENOSPC; - } - -errout: - if (*errp) { - ac->ac_b_ex.fe_len = 0; - ar->len = 0; - ext4_mb_show_ac(ac); - } - ext4_mb_release_context(ac); -out: - if (ac) - kmem_cache_free(ext4_ac_cachep, ac); - if (inquota && ar->len < inquota) - dquot_free_block(ar->inode, EXT4_C2B(sbi, inquota - ar->len)); - if (!ar->len) { - if ((ar->flags & EXT4_MB_DELALLOC_RESERVED) == 0) - /* release all the reserved blocks if non delalloc */ - percpu_counter_sub(&sbi->s_dirtyclusters_counter, - reserv_clstrs); - } - - trace_ext4_allocate_blocks(ar, (unsigned long long)block); - - return block; -} - -/* - * We can merge two free data extents only if the physical blocks - * are contiguous, AND the extents were freed by the same transaction, - * AND the blocks are associated with the same group. - */ -static int can_merge(struct ext4_free_data *entry1, - struct ext4_free_data *entry2) -{ - if ((entry1->efd_tid == entry2->efd_tid) && - (entry1->efd_group == entry2->efd_group) && - ((entry1->efd_start_cluster + entry1->efd_count) == entry2->efd_start_cluster)) - return 1; - return 0; -} - -static noinline_for_stack int -ext4_mb_free_metadata(handle_t *handle, struct ext4_buddy *e4b, - struct ext4_free_data *new_entry) -{ - ext4_group_t group = e4b->bd_group; - ext4_grpblk_t cluster; - ext4_grpblk_t clusters = new_entry->efd_count; - struct ext4_free_data *entry; - struct ext4_group_info *db = e4b->bd_info; - struct super_block *sb = e4b->bd_sb; - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct rb_node **n = &db->bb_free_root.rb_node, *node; - struct rb_node *parent = NULL, *new_node; - - BUG_ON(!ext4_handle_valid(handle)); - BUG_ON(e4b->bd_bitmap_page == NULL); - BUG_ON(e4b->bd_buddy_page == NULL); - - new_node = &new_entry->efd_node; - cluster = new_entry->efd_start_cluster; - - if (!*n) { - /* first free block exent. We need to - protect buddy cache from being freed, - * otherwise we'll refresh it from - * on-disk bitmap and lose not-yet-available - * blocks */ - get_page(e4b->bd_buddy_page); - get_page(e4b->bd_bitmap_page); - } - while (*n) { - parent = *n; - entry = rb_entry(parent, struct ext4_free_data, efd_node); - if (cluster < entry->efd_start_cluster) - n = &(*n)->rb_left; - else if (cluster >= (entry->efd_start_cluster + entry->efd_count)) - n = &(*n)->rb_right; - else { - ext4_grp_locked_error(sb, group, 0, - ext4_group_first_block_no(sb, group) + - EXT4_C2B(sbi, cluster), - "Block already on to-be-freed list"); - return 0; - } - } - - rb_link_node(new_node, parent, n); - rb_insert_color(new_node, &db->bb_free_root); - - /* Now try to see the extent can be merged to left and right */ - node = rb_prev(new_node); - if (node) { - entry = rb_entry(node, struct ext4_free_data, efd_node); - if (can_merge(entry, new_entry) && - ext4_journal_callback_try_del(handle, &entry->efd_jce)) { - new_entry->efd_start_cluster = entry->efd_start_cluster; - new_entry->efd_count += entry->efd_count; - rb_erase(node, &(db->bb_free_root)); - kmem_cache_free(ext4_free_data_cachep, entry); - } - } - - node = rb_next(new_node); - if (node) { - entry = rb_entry(node, struct ext4_free_data, efd_node); - if (can_merge(new_entry, entry) && - ext4_journal_callback_try_del(handle, &entry->efd_jce)) { - new_entry->efd_count += entry->efd_count; - rb_erase(node, &(db->bb_free_root)); - kmem_cache_free(ext4_free_data_cachep, entry); - } - } - /* Add the extent to transaction's private list */ - new_entry->efd_jce.jce_func = ext4_free_data_callback; - spin_lock(&sbi->s_md_lock); - _ext4_journal_callback_add(handle, &new_entry->efd_jce); - sbi->s_mb_free_pending += clusters; - spin_unlock(&sbi->s_md_lock); - return 0; -} - -/** - * ext4_free_blocks() -- Free given blocks and update quota - * @handle: handle for this transaction - * @inode: inode - * @block: start physical block to free - * @count: number of blocks to count - * @flags: flags used by ext4_free_blocks - */ -void ext4_free_blocks(handle_t *handle, struct inode *inode, - struct buffer_head *bh, ext4_fsblk_t block, - unsigned long count, int flags) -{ - struct buffer_head *bitmap_bh = NULL; - struct super_block *sb = inode->i_sb; - struct ext4_group_desc *gdp; - unsigned int overflow; - ext4_grpblk_t bit; - struct buffer_head *gd_bh; - ext4_group_t block_group; - struct ext4_sb_info *sbi; - struct ext4_buddy e4b; - unsigned int count_clusters; - int err = 0; - int ret; - - might_sleep(); - if (bh) { - if (block) - BUG_ON(block != bh->b_blocknr); - else - block = bh->b_blocknr; - } - - sbi = EXT4_SB(sb); - if (!(flags & EXT4_FREE_BLOCKS_VALIDATED) && - !ext4_data_block_valid(sbi, block, count)) { - ext4_error(sb, "Freeing blocks not in datazone - " - "block = %llu, count = %lu", block, count); - goto error_return; - } - - ext4_debug("freeing block %llu\n", block); - trace_ext4_free_blocks(inode, block, count, flags); - - if (bh && (flags & EXT4_FREE_BLOCKS_FORGET)) { - BUG_ON(count > 1); - - ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA, - inode, bh, block); - } - - /* - * If the extent to be freed does not begin on a cluster - * boundary, we need to deal with partial clusters at the - * beginning and end of the extent. Normally we will free - * blocks at the beginning or the end unless we are explicitly - * requested to avoid doing so. - */ - overflow = EXT4_PBLK_COFF(sbi, block); - if (overflow) { - if (flags & EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER) { - overflow = sbi->s_cluster_ratio - overflow; - block += overflow; - if (count > overflow) - count -= overflow; - else - return; - } else { - block -= overflow; - count += overflow; - } - } - overflow = EXT4_LBLK_COFF(sbi, count); - if (overflow) { - if (flags & EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER) { - if (count > overflow) - count -= overflow; - else - return; - } else - count += sbi->s_cluster_ratio - overflow; - } - - if (!bh && (flags & EXT4_FREE_BLOCKS_FORGET)) { - int i; - int is_metadata = flags & EXT4_FREE_BLOCKS_METADATA; - - for (i = 0; i < count; i++) { - cond_resched(); - if (is_metadata) - bh = sb_find_get_block(inode->i_sb, block + i); - ext4_forget(handle, is_metadata, inode, bh, block + i); - } - } - -do_more: - overflow = 0; - ext4_get_group_no_and_offset(sb, block, &block_group, &bit); - - if (unlikely(EXT4_MB_GRP_BBITMAP_CORRUPT( - ext4_get_group_info(sb, block_group)))) - return; - - /* - * Check to see if we are freeing blocks across a group - * boundary. - */ - if (EXT4_C2B(sbi, bit) + count > EXT4_BLOCKS_PER_GROUP(sb)) { - overflow = EXT4_C2B(sbi, bit) + count - - EXT4_BLOCKS_PER_GROUP(sb); - count -= overflow; - } - count_clusters = EXT4_NUM_B2C(sbi, count); - bitmap_bh = ext4_read_block_bitmap(sb, block_group); - if (IS_ERR(bitmap_bh)) { - err = PTR_ERR(bitmap_bh); - bitmap_bh = NULL; - goto error_return; - } - gdp = ext4_get_group_desc(sb, block_group, &gd_bh); - if (!gdp) { - err = -EIO; - goto error_return; - } - - if (in_range(ext4_block_bitmap(sb, gdp), block, count) || - in_range(ext4_inode_bitmap(sb, gdp), block, count) || - in_range(block, ext4_inode_table(sb, gdp), - EXT4_SB(sb)->s_itb_per_group) || - in_range(block + count - 1, ext4_inode_table(sb, gdp), - EXT4_SB(sb)->s_itb_per_group)) { - - ext4_error(sb, "Freeing blocks in system zone - " - "Block = %llu, count = %lu", block, count); - /* err = 0. ext4_std_error should be a no op */ - goto error_return; - } - - BUFFER_TRACE(bitmap_bh, "getting write access"); - err = ext4_journal_get_write_access(handle, bitmap_bh); - if (err) - goto error_return; - - /* - * We are about to modify some metadata. Call the journal APIs - * to unshare ->b_data if a currently-committing transaction is - * using it - */ - BUFFER_TRACE(gd_bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, gd_bh); - if (err) - goto error_return; -#ifdef AGGRESSIVE_CHECK - { - int i; - for (i = 0; i < count_clusters; i++) - BUG_ON(!mb_test_bit(bit + i, bitmap_bh->b_data)); - } -#endif - trace_ext4_mballoc_free(sb, inode, block_group, bit, count_clusters); - - /* __GFP_NOFAIL: retry infinitely, ignore TIF_MEMDIE and memcg limit. */ - err = ext4_mb_load_buddy_gfp(sb, block_group, &e4b, - GFP_NOFS|__GFP_NOFAIL); - if (err) - goto error_return; - - /* - * We need to make sure we don't reuse the freed block until after the - * transaction is committed. We make an exception if the inode is to be - * written in writeback mode since writeback mode has weak data - * consistency guarantees. - */ - if (ext4_handle_valid(handle) && - ((flags & EXT4_FREE_BLOCKS_METADATA) || - !ext4_should_writeback_data(inode))) { - struct ext4_free_data *new_entry; - /* - * We use __GFP_NOFAIL because ext4_free_blocks() is not allowed - * to fail. - */ - new_entry = kmem_cache_alloc(ext4_free_data_cachep, - GFP_NOFS|__GFP_NOFAIL); - new_entry->efd_start_cluster = bit; - new_entry->efd_group = block_group; - new_entry->efd_count = count_clusters; - new_entry->efd_tid = handle->h_transaction->t_tid; - - ext4_lock_group(sb, block_group); - mb_clear_bits(bitmap_bh->b_data, bit, count_clusters); - ext4_mb_free_metadata(handle, &e4b, new_entry); - } else { - /* need to update group_info->bb_free and bitmap - * with group lock held. generate_buddy look at - * them with group lock_held - */ - if (test_opt(sb, DISCARD)) { - err = ext4_issue_discard(sb, block_group, bit, count); - if (err && err != -EOPNOTSUPP) - ext4_msg(sb, KERN_WARNING, "discard request in" - " group:%d block:%d count:%lu failed" - " with %d", block_group, bit, count, - err); - } else - EXT4_MB_GRP_CLEAR_TRIMMED(e4b.bd_info); - - ext4_lock_group(sb, block_group); - mb_clear_bits(bitmap_bh->b_data, bit, count_clusters); - mb_free_blocks(inode, &e4b, bit, count_clusters); - } - - ret = ext4_free_group_clusters(sb, gdp) + count_clusters; - ext4_free_group_clusters_set(sb, gdp, ret); - ext4_block_bitmap_csum_set(sb, block_group, gdp, bitmap_bh); - ext4_group_desc_csum_set(sb, block_group, gdp); - ext4_unlock_group(sb, block_group); - - if (sbi->s_log_groups_per_flex) { - ext4_group_t flex_group = ext4_flex_group(sbi, block_group); - atomic64_add(count_clusters, - &sbi->s_flex_groups[flex_group].free_clusters); - } - - if (!(flags & EXT4_FREE_BLOCKS_NO_QUOT_UPDATE)) - dquot_free_block(inode, EXT4_C2B(sbi, count_clusters)); - percpu_counter_add(&sbi->s_freeclusters_counter, count_clusters); - - ext4_mb_unload_buddy(&e4b); - - /* We dirtied the bitmap block */ - BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); - err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); - - /* And the group descriptor block */ - BUFFER_TRACE(gd_bh, "dirtied group descriptor block"); - ret = ext4_handle_dirty_metadata(handle, NULL, gd_bh); - if (!err) - err = ret; - - if (overflow && !err) { - block += count; - count = overflow; - put_bh(bitmap_bh); - goto do_more; - } -error_return: - brelse(bitmap_bh); - ext4_std_error(sb, err); - return; -} - -/** - * ext4_group_add_blocks() -- Add given blocks to an existing group - * @handle: handle to this transaction - * @sb: super block - * @block: start physical block to add to the block group - * @count: number of blocks to free - * - * This marks the blocks as free in the bitmap and buddy. - */ -int ext4_group_add_blocks(handle_t *handle, struct super_block *sb, - ext4_fsblk_t block, unsigned long count) -{ - struct buffer_head *bitmap_bh = NULL; - struct buffer_head *gd_bh; - ext4_group_t block_group; - ext4_grpblk_t bit; - unsigned int i; - struct ext4_group_desc *desc; - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_buddy e4b; - int err = 0, ret, blk_free_count; - ext4_grpblk_t blocks_freed; - - ext4_debug("Adding block(s) %llu-%llu\n", block, block + count - 1); - - if (count == 0) - return 0; - - ext4_get_group_no_and_offset(sb, block, &block_group, &bit); - /* - * Check to see if we are freeing blocks across a group - * boundary. - */ - if (bit + count > EXT4_BLOCKS_PER_GROUP(sb)) { - ext4_warning(sb, "too much blocks added to group %u", - block_group); - err = -EINVAL; - goto error_return; - } - - bitmap_bh = ext4_read_block_bitmap(sb, block_group); - if (IS_ERR(bitmap_bh)) { - err = PTR_ERR(bitmap_bh); - bitmap_bh = NULL; - goto error_return; - } - - desc = ext4_get_group_desc(sb, block_group, &gd_bh); - if (!desc) { - err = -EIO; - goto error_return; - } - - if (in_range(ext4_block_bitmap(sb, desc), block, count) || - in_range(ext4_inode_bitmap(sb, desc), block, count) || - in_range(block, ext4_inode_table(sb, desc), sbi->s_itb_per_group) || - in_range(block + count - 1, ext4_inode_table(sb, desc), - sbi->s_itb_per_group)) { - ext4_error(sb, "Adding blocks in system zones - " - "Block = %llu, count = %lu", - block, count); - err = -EINVAL; - goto error_return; - } - - BUFFER_TRACE(bitmap_bh, "getting write access"); - err = ext4_journal_get_write_access(handle, bitmap_bh); - if (err) - goto error_return; - - /* - * We are about to modify some metadata. Call the journal APIs - * to unshare ->b_data if a currently-committing transaction is - * using it - */ - BUFFER_TRACE(gd_bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, gd_bh); - if (err) - goto error_return; - - for (i = 0, blocks_freed = 0; i < count; i++) { - BUFFER_TRACE(bitmap_bh, "clear bit"); - if (!mb_test_bit(bit + i, bitmap_bh->b_data)) { - ext4_error(sb, "bit already cleared for block %llu", - (ext4_fsblk_t)(block + i)); - BUFFER_TRACE(bitmap_bh, "bit already cleared"); - } else { - blocks_freed++; - } - } - - err = ext4_mb_load_buddy(sb, block_group, &e4b); - if (err) - goto error_return; - - /* - * need to update group_info->bb_free and bitmap - * with group lock held. generate_buddy look at - * them with group lock_held - */ - ext4_lock_group(sb, block_group); - mb_clear_bits(bitmap_bh->b_data, bit, count); - mb_free_blocks(NULL, &e4b, bit, count); - blk_free_count = blocks_freed + ext4_free_group_clusters(sb, desc); - ext4_free_group_clusters_set(sb, desc, blk_free_count); - ext4_block_bitmap_csum_set(sb, block_group, desc, bitmap_bh); - ext4_group_desc_csum_set(sb, block_group, desc); - ext4_unlock_group(sb, block_group); - percpu_counter_add(&sbi->s_freeclusters_counter, - EXT4_NUM_B2C(sbi, blocks_freed)); - - if (sbi->s_log_groups_per_flex) { - ext4_group_t flex_group = ext4_flex_group(sbi, block_group); - atomic64_add(EXT4_NUM_B2C(sbi, blocks_freed), - &sbi->s_flex_groups[flex_group].free_clusters); - } - - ext4_mb_unload_buddy(&e4b); - - /* We dirtied the bitmap block */ - BUFFER_TRACE(bitmap_bh, "dirtied bitmap block"); - err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); - - /* And the group descriptor block */ - BUFFER_TRACE(gd_bh, "dirtied group descriptor block"); - ret = ext4_handle_dirty_metadata(handle, NULL, gd_bh); - if (!err) - err = ret; - -error_return: - brelse(bitmap_bh); - ext4_std_error(sb, err); - return err; -} - -/** - * ext4_trim_extent -- function to TRIM one single free extent in the group - * @sb: super block for the file system - * @start: starting block of the free extent in the alloc. group - * @count: number of blocks to TRIM - * @group: alloc. group we are working with - * @e4b: ext4 buddy for the group - * - * Trim "count" blocks starting at "start" in the "group". To assure that no - * one will allocate those blocks, mark it as used in buddy bitmap. This must - * be called with under the group lock. - */ -static int ext4_trim_extent(struct super_block *sb, int start, int count, - ext4_group_t group, struct ext4_buddy *e4b) -__releases(bitlock) -__acquires(bitlock) -{ - struct ext4_free_extent ex; - int ret = 0; - - trace_ext4_trim_extent(sb, group, start, count); - - assert_spin_locked(ext4_group_lock_ptr(sb, group)); - - ex.fe_start = start; - ex.fe_group = group; - ex.fe_len = count; - - /* - * Mark blocks used, so no one can reuse them while - * being trimmed. - */ - mb_mark_used(e4b, &ex); - ext4_unlock_group(sb, group); - ret = ext4_issue_discard(sb, group, start, count); - ext4_lock_group(sb, group); - mb_free_blocks(NULL, e4b, start, ex.fe_len); - return ret; -} - -/** - * ext4_trim_all_free -- function to trim all free space in alloc. group - * @sb: super block for file system - * @group: group to be trimmed - * @start: first group block to examine - * @max: last group block to examine - * @minblocks: minimum extent block count - * - * ext4_trim_all_free walks through group's buddy bitmap searching for free - * extents. When the free block is found, ext4_trim_extent is called to TRIM - * the extent. - * - * - * ext4_trim_all_free walks through group's block bitmap searching for free - * extents. When the free extent is found, mark it as used in group buddy - * bitmap. Then issue a TRIM command on this extent and free the extent in - * the group buddy bitmap. This is done until whole group is scanned. - */ -static ext4_grpblk_t -ext4_trim_all_free(struct super_block *sb, ext4_group_t group, - ext4_grpblk_t start, ext4_grpblk_t max, - ext4_grpblk_t minblocks) -{ - void *bitmap; - ext4_grpblk_t next, count = 0, free_count = 0; - struct ext4_buddy e4b; - int ret = 0; - - trace_ext4_trim_all_free(sb, group, start, max); - - ret = ext4_mb_load_buddy(sb, group, &e4b); - if (ret) { - ext4_error(sb, "Error in loading buddy " - "information for %u", group); - return ret; - } - bitmap = e4b.bd_bitmap; - - ext4_lock_group(sb, group); - if (EXT4_MB_GRP_WAS_TRIMMED(e4b.bd_info) && - minblocks >= atomic_read(&EXT4_SB(sb)->s_last_trim_minblks)) - goto out; - - start = (e4b.bd_info->bb_first_free > start) ? - e4b.bd_info->bb_first_free : start; - - while (start <= max) { - start = mb_find_next_zero_bit(bitmap, max + 1, start); - if (start > max) - break; - next = mb_find_next_bit(bitmap, max + 1, start); - - if ((next - start) >= minblocks) { - ret = ext4_trim_extent(sb, start, - next - start, group, &e4b); - if (ret && ret != -EOPNOTSUPP) - break; - ret = 0; - count += next - start; - } - free_count += next - start; - start = next + 1; - - if (fatal_signal_pending(current)) { - count = -ERESTARTSYS; - break; - } - - if (need_resched()) { - ext4_unlock_group(sb, group); - cond_resched(); - ext4_lock_group(sb, group); - } - - if ((e4b.bd_info->bb_free - free_count) < minblocks) - break; - } - - if (!ret) { - ret = count; - EXT4_MB_GRP_SET_TRIMMED(e4b.bd_info); - } -out: - ext4_unlock_group(sb, group); - ext4_mb_unload_buddy(&e4b); - - ext4_debug("trimmed %d blocks in the group %d\n", - count, group); - - return ret; -} - -/** - * ext4_trim_fs() -- trim ioctl handle function - * @sb: superblock for filesystem - * @range: fstrim_range structure - * - * start: First Byte to trim - * len: number of Bytes to trim from start - * minlen: minimum extent length in Bytes - * ext4_trim_fs goes through all allocation groups containing Bytes from - * start to start+len. For each such a group ext4_trim_all_free function - * is invoked to trim all free space. - */ -int ext4_trim_fs(struct super_block *sb, struct fstrim_range *range) -{ - struct ext4_group_info *grp; - ext4_group_t group, first_group, last_group; - ext4_grpblk_t cnt = 0, first_cluster, last_cluster; - uint64_t start, end, minlen, trimmed = 0; - ext4_fsblk_t first_data_blk = - le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block); - ext4_fsblk_t max_blks = ext4_blocks_count(EXT4_SB(sb)->s_es); - int ret = 0; - - start = range->start >> sb->s_blocksize_bits; - end = start + (range->len >> sb->s_blocksize_bits) - 1; - minlen = EXT4_NUM_B2C(EXT4_SB(sb), - range->minlen >> sb->s_blocksize_bits); - - if (minlen > EXT4_CLUSTERS_PER_GROUP(sb) || - start >= max_blks || - range->len < sb->s_blocksize) - return -EINVAL; - if (end >= max_blks) - end = max_blks - 1; - if (end <= first_data_blk) - goto out; - if (start < first_data_blk) - start = first_data_blk; - - /* Determine first and last group to examine based on start and end */ - ext4_get_group_no_and_offset(sb, (ext4_fsblk_t) start, - &first_group, &first_cluster); - ext4_get_group_no_and_offset(sb, (ext4_fsblk_t) end, - &last_group, &last_cluster); - - /* end now represents the last cluster to discard in this group */ - end = EXT4_CLUSTERS_PER_GROUP(sb) - 1; - - for (group = first_group; group <= last_group; group++) { - grp = ext4_get_group_info(sb, group); - /* We only do this if the grp has never been initialized */ - if (unlikely(EXT4_MB_GRP_NEED_INIT(grp))) { - ret = ext4_mb_init_group(sb, group, GFP_NOFS); - if (ret) - break; - } - - /* - * For all the groups except the last one, last cluster will - * always be EXT4_CLUSTERS_PER_GROUP(sb)-1, so we only need to - * change it for the last group, note that last_cluster is - * already computed earlier by ext4_get_group_no_and_offset() - */ - if (group == last_group) - end = last_cluster; - - if (grp->bb_free >= minlen) { - cnt = ext4_trim_all_free(sb, group, first_cluster, - end, minlen); - if (cnt < 0) { - ret = cnt; - break; - } - trimmed += cnt; - } - - /* - * For every group except the first one, we are sure - * that the first cluster to discard will be cluster #0. - */ - first_cluster = 0; - } - - if (!ret) - atomic_set(&EXT4_SB(sb)->s_last_trim_minblks, minlen); - -out: - range->len = EXT4_C2B(EXT4_SB(sb), trimmed) << sb->s_blocksize_bits; - return ret; -} diff --git a/src/linux/fs/ext4/mballoc.h b/src/linux/fs/ext4/mballoc.h deleted file mode 100644 index 1aba469..0000000 --- a/src/linux/fs/ext4/mballoc.h +++ /dev/null @@ -1,202 +0,0 @@ -/* - * fs/ext4/mballoc.h - * - * Written by: Alex Tomas - * - */ -#ifndef _EXT4_MBALLOC_H -#define _EXT4_MBALLOC_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ext4_jbd2.h" -#include "ext4.h" - -/* - */ -#ifdef CONFIG_EXT4_DEBUG -extern ushort ext4_mballoc_debug; - -#define mb_debug(n, fmt, ...) \ -do { \ - if ((n) <= ext4_mballoc_debug) { \ - printk(KERN_DEBUG "(%s, %d): %s: " fmt, \ - __FILE__, __LINE__, __func__, ##__VA_ARGS__); \ - } \ -} while (0) -#else -#define mb_debug(n, fmt, ...) no_printk(fmt, ##__VA_ARGS__) -#endif - -#define EXT4_MB_HISTORY_ALLOC 1 /* allocation */ -#define EXT4_MB_HISTORY_PREALLOC 2 /* preallocated blocks used */ - -/* - * How long mballoc can look for a best extent (in found extents) - */ -#define MB_DEFAULT_MAX_TO_SCAN 200 - -/* - * How long mballoc must look for a best extent - */ -#define MB_DEFAULT_MIN_TO_SCAN 10 - -/* - * with 'ext4_mb_stats' allocator will collect stats that will be - * shown at umount. The collecting costs though! - */ -#define MB_DEFAULT_STATS 0 - -/* - * files smaller than MB_DEFAULT_STREAM_THRESHOLD are served - * by the stream allocator, which purpose is to pack requests - * as close each to other as possible to produce smooth I/O traffic - * We use locality group prealloc space for stream request. - * We can tune the same via /proc/fs/ext4//stream_req - */ -#define MB_DEFAULT_STREAM_THRESHOLD 16 /* 64K */ - -/* - * for which requests use 2^N search using buddies - */ -#define MB_DEFAULT_ORDER2_REQS 2 - -/* - * default group prealloc size 512 blocks - */ -#define MB_DEFAULT_GROUP_PREALLOC 512 - - -struct ext4_free_data { - /* MUST be the first member */ - struct ext4_journal_cb_entry efd_jce; - - /* ext4_free_data private data starts from here */ - - /* this links the free block information from group_info */ - struct rb_node efd_node; - - /* group which free block extent belongs */ - ext4_group_t efd_group; - - /* free block extent */ - ext4_grpblk_t efd_start_cluster; - ext4_grpblk_t efd_count; - - /* transaction which freed this extent */ - tid_t efd_tid; -}; - -struct ext4_prealloc_space { - struct list_head pa_inode_list; - struct list_head pa_group_list; - union { - struct list_head pa_tmp_list; - struct rcu_head pa_rcu; - } u; - spinlock_t pa_lock; - atomic_t pa_count; - unsigned pa_deleted; - ext4_fsblk_t pa_pstart; /* phys. block */ - ext4_lblk_t pa_lstart; /* log. block */ - ext4_grpblk_t pa_len; /* len of preallocated chunk */ - ext4_grpblk_t pa_free; /* how many blocks are free */ - unsigned short pa_type; /* pa type. inode or group */ - spinlock_t *pa_obj_lock; - struct inode *pa_inode; /* hack, for history only */ -}; - -enum { - MB_INODE_PA = 0, - MB_GROUP_PA = 1 -}; - -struct ext4_free_extent { - ext4_lblk_t fe_logical; - ext4_grpblk_t fe_start; /* In cluster units */ - ext4_group_t fe_group; - ext4_grpblk_t fe_len; /* In cluster units */ -}; - -/* - * Locality group: - * we try to group all related changes together - * so that writeback can flush/allocate them together as well - * Size of lg_prealloc_list hash is determined by MB_DEFAULT_GROUP_PREALLOC - * (512). We store prealloc space into the hash based on the pa_free blocks - * order value.ie, fls(pa_free)-1; - */ -#define PREALLOC_TB_SIZE 10 -struct ext4_locality_group { - /* for allocator */ - /* to serialize allocates */ - struct mutex lg_mutex; - /* list of preallocations */ - struct list_head lg_prealloc_list[PREALLOC_TB_SIZE]; - spinlock_t lg_prealloc_lock; -}; - -struct ext4_allocation_context { - struct inode *ac_inode; - struct super_block *ac_sb; - - /* original request */ - struct ext4_free_extent ac_o_ex; - - /* goal request (normalized ac_o_ex) */ - struct ext4_free_extent ac_g_ex; - - /* the best found extent */ - struct ext4_free_extent ac_b_ex; - - /* copy of the best found extent taken before preallocation efforts */ - struct ext4_free_extent ac_f_ex; - - __u16 ac_groups_scanned; - __u16 ac_found; - __u16 ac_tail; - __u16 ac_buddy; - __u16 ac_flags; /* allocation hints */ - __u8 ac_status; - __u8 ac_criteria; - __u8 ac_2order; /* if request is to allocate 2^N blocks and - * N > 0, the field stores N, otherwise 0 */ - __u8 ac_op; /* operation, for history only */ - struct page *ac_bitmap_page; - struct page *ac_buddy_page; - struct ext4_prealloc_space *ac_pa; - struct ext4_locality_group *ac_lg; -}; - -#define AC_STATUS_CONTINUE 1 -#define AC_STATUS_FOUND 2 -#define AC_STATUS_BREAK 3 - -struct ext4_buddy { - struct page *bd_buddy_page; - void *bd_buddy; - struct page *bd_bitmap_page; - void *bd_bitmap; - struct ext4_group_info *bd_info; - struct super_block *bd_sb; - __u16 bd_blkbits; - ext4_group_t bd_group; -}; - -static inline ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb, - struct ext4_free_extent *fex) -{ - return ext4_group_first_block_no(sb, fex->fe_group) + - (fex->fe_start << EXT4_SB(sb)->s_cluster_bits); -} -#endif diff --git a/src/linux/fs/ext4/migrate.c b/src/linux/fs/ext4/migrate.c deleted file mode 100644 index 364ea4d..0000000 --- a/src/linux/fs/ext4/migrate.c +++ /dev/null @@ -1,680 +0,0 @@ -/* - * Copyright IBM Corporation, 2007 - * Author Aneesh Kumar K.V - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - */ - -#include -#include "ext4_jbd2.h" -#include "ext4_extents.h" - -/* - * The contiguous blocks details which can be - * represented by a single extent - */ -struct migrate_struct { - ext4_lblk_t first_block, last_block, curr_block; - ext4_fsblk_t first_pblock, last_pblock; -}; - -static int finish_range(handle_t *handle, struct inode *inode, - struct migrate_struct *lb) - -{ - int retval = 0, needed; - struct ext4_extent newext; - struct ext4_ext_path *path; - if (lb->first_pblock == 0) - return 0; - - /* Add the extent to temp inode*/ - newext.ee_block = cpu_to_le32(lb->first_block); - newext.ee_len = cpu_to_le16(lb->last_block - lb->first_block + 1); - ext4_ext_store_pblock(&newext, lb->first_pblock); - /* Locking only for convinience since we are operating on temp inode */ - down_write(&EXT4_I(inode)->i_data_sem); - path = ext4_find_extent(inode, lb->first_block, NULL, 0); - if (IS_ERR(path)) { - retval = PTR_ERR(path); - path = NULL; - goto err_out; - } - - /* - * Calculate the credit needed to inserting this extent - * Since we are doing this in loop we may accumalate extra - * credit. But below we try to not accumalate too much - * of them by restarting the journal. - */ - needed = ext4_ext_calc_credits_for_single_extent(inode, - lb->last_block - lb->first_block + 1, path); - - /* - * Make sure the credit we accumalated is not really high - */ - if (needed && ext4_handle_has_enough_credits(handle, - EXT4_RESERVE_TRANS_BLOCKS)) { - up_write((&EXT4_I(inode)->i_data_sem)); - retval = ext4_journal_restart(handle, needed); - down_write((&EXT4_I(inode)->i_data_sem)); - if (retval) - goto err_out; - } else if (needed) { - retval = ext4_journal_extend(handle, needed); - if (retval) { - /* - * IF not able to extend the journal restart the journal - */ - up_write((&EXT4_I(inode)->i_data_sem)); - retval = ext4_journal_restart(handle, needed); - down_write((&EXT4_I(inode)->i_data_sem)); - if (retval) - goto err_out; - } - } - retval = ext4_ext_insert_extent(handle, inode, &path, &newext, 0); -err_out: - up_write((&EXT4_I(inode)->i_data_sem)); - ext4_ext_drop_refs(path); - kfree(path); - lb->first_pblock = 0; - return retval; -} - -static int update_extent_range(handle_t *handle, struct inode *inode, - ext4_fsblk_t pblock, struct migrate_struct *lb) -{ - int retval; - /* - * See if we can add on to the existing range (if it exists) - */ - if (lb->first_pblock && - (lb->last_pblock+1 == pblock) && - (lb->last_block+1 == lb->curr_block)) { - lb->last_pblock = pblock; - lb->last_block = lb->curr_block; - lb->curr_block++; - return 0; - } - /* - * Start a new range. - */ - retval = finish_range(handle, inode, lb); - lb->first_pblock = lb->last_pblock = pblock; - lb->first_block = lb->last_block = lb->curr_block; - lb->curr_block++; - return retval; -} - -static int update_ind_extent_range(handle_t *handle, struct inode *inode, - ext4_fsblk_t pblock, - struct migrate_struct *lb) -{ - struct buffer_head *bh; - __le32 *i_data; - int i, retval = 0; - unsigned long max_entries = inode->i_sb->s_blocksize >> 2; - - bh = sb_bread(inode->i_sb, pblock); - if (!bh) - return -EIO; - - i_data = (__le32 *)bh->b_data; - for (i = 0; i < max_entries; i++) { - if (i_data[i]) { - retval = update_extent_range(handle, inode, - le32_to_cpu(i_data[i]), lb); - if (retval) - break; - } else { - lb->curr_block++; - } - } - put_bh(bh); - return retval; - -} - -static int update_dind_extent_range(handle_t *handle, struct inode *inode, - ext4_fsblk_t pblock, - struct migrate_struct *lb) -{ - struct buffer_head *bh; - __le32 *i_data; - int i, retval = 0; - unsigned long max_entries = inode->i_sb->s_blocksize >> 2; - - bh = sb_bread(inode->i_sb, pblock); - if (!bh) - return -EIO; - - i_data = (__le32 *)bh->b_data; - for (i = 0; i < max_entries; i++) { - if (i_data[i]) { - retval = update_ind_extent_range(handle, inode, - le32_to_cpu(i_data[i]), lb); - if (retval) - break; - } else { - /* Only update the file block number */ - lb->curr_block += max_entries; - } - } - put_bh(bh); - return retval; - -} - -static int update_tind_extent_range(handle_t *handle, struct inode *inode, - ext4_fsblk_t pblock, - struct migrate_struct *lb) -{ - struct buffer_head *bh; - __le32 *i_data; - int i, retval = 0; - unsigned long max_entries = inode->i_sb->s_blocksize >> 2; - - bh = sb_bread(inode->i_sb, pblock); - if (!bh) - return -EIO; - - i_data = (__le32 *)bh->b_data; - for (i = 0; i < max_entries; i++) { - if (i_data[i]) { - retval = update_dind_extent_range(handle, inode, - le32_to_cpu(i_data[i]), lb); - if (retval) - break; - } else { - /* Only update the file block number */ - lb->curr_block += max_entries * max_entries; - } - } - put_bh(bh); - return retval; - -} - -static int extend_credit_for_blkdel(handle_t *handle, struct inode *inode) -{ - int retval = 0, needed; - - if (ext4_handle_has_enough_credits(handle, EXT4_RESERVE_TRANS_BLOCKS+1)) - return 0; - /* - * We are freeing a blocks. During this we touch - * superblock, group descriptor and block bitmap. - * So allocate a credit of 3. We may update - * quota (user and group). - */ - needed = 3 + EXT4_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb); - - if (ext4_journal_extend(handle, needed) != 0) - retval = ext4_journal_restart(handle, needed); - - return retval; -} - -static int free_dind_blocks(handle_t *handle, - struct inode *inode, __le32 i_data) -{ - int i; - __le32 *tmp_idata; - struct buffer_head *bh; - unsigned long max_entries = inode->i_sb->s_blocksize >> 2; - - bh = sb_bread(inode->i_sb, le32_to_cpu(i_data)); - if (!bh) - return -EIO; - - tmp_idata = (__le32 *)bh->b_data; - for (i = 0; i < max_entries; i++) { - if (tmp_idata[i]) { - extend_credit_for_blkdel(handle, inode); - ext4_free_blocks(handle, inode, NULL, - le32_to_cpu(tmp_idata[i]), 1, - EXT4_FREE_BLOCKS_METADATA | - EXT4_FREE_BLOCKS_FORGET); - } - } - put_bh(bh); - extend_credit_for_blkdel(handle, inode); - ext4_free_blocks(handle, inode, NULL, le32_to_cpu(i_data), 1, - EXT4_FREE_BLOCKS_METADATA | - EXT4_FREE_BLOCKS_FORGET); - return 0; -} - -static int free_tind_blocks(handle_t *handle, - struct inode *inode, __le32 i_data) -{ - int i, retval = 0; - __le32 *tmp_idata; - struct buffer_head *bh; - unsigned long max_entries = inode->i_sb->s_blocksize >> 2; - - bh = sb_bread(inode->i_sb, le32_to_cpu(i_data)); - if (!bh) - return -EIO; - - tmp_idata = (__le32 *)bh->b_data; - for (i = 0; i < max_entries; i++) { - if (tmp_idata[i]) { - retval = free_dind_blocks(handle, - inode, tmp_idata[i]); - if (retval) { - put_bh(bh); - return retval; - } - } - } - put_bh(bh); - extend_credit_for_blkdel(handle, inode); - ext4_free_blocks(handle, inode, NULL, le32_to_cpu(i_data), 1, - EXT4_FREE_BLOCKS_METADATA | - EXT4_FREE_BLOCKS_FORGET); - return 0; -} - -static int free_ind_block(handle_t *handle, struct inode *inode, __le32 *i_data) -{ - int retval; - - /* ei->i_data[EXT4_IND_BLOCK] */ - if (i_data[0]) { - extend_credit_for_blkdel(handle, inode); - ext4_free_blocks(handle, inode, NULL, - le32_to_cpu(i_data[0]), 1, - EXT4_FREE_BLOCKS_METADATA | - EXT4_FREE_BLOCKS_FORGET); - } - - /* ei->i_data[EXT4_DIND_BLOCK] */ - if (i_data[1]) { - retval = free_dind_blocks(handle, inode, i_data[1]); - if (retval) - return retval; - } - - /* ei->i_data[EXT4_TIND_BLOCK] */ - if (i_data[2]) { - retval = free_tind_blocks(handle, inode, i_data[2]); - if (retval) - return retval; - } - return 0; -} - -static int ext4_ext_swap_inode_data(handle_t *handle, struct inode *inode, - struct inode *tmp_inode) -{ - int retval; - __le32 i_data[3]; - struct ext4_inode_info *ei = EXT4_I(inode); - struct ext4_inode_info *tmp_ei = EXT4_I(tmp_inode); - - /* - * One credit accounted for writing the - * i_data field of the original inode - */ - retval = ext4_journal_extend(handle, 1); - if (retval) { - retval = ext4_journal_restart(handle, 1); - if (retval) - goto err_out; - } - - i_data[0] = ei->i_data[EXT4_IND_BLOCK]; - i_data[1] = ei->i_data[EXT4_DIND_BLOCK]; - i_data[2] = ei->i_data[EXT4_TIND_BLOCK]; - - down_write(&EXT4_I(inode)->i_data_sem); - /* - * if EXT4_STATE_EXT_MIGRATE is cleared a block allocation - * happened after we started the migrate. We need to - * fail the migrate - */ - if (!ext4_test_inode_state(inode, EXT4_STATE_EXT_MIGRATE)) { - retval = -EAGAIN; - up_write(&EXT4_I(inode)->i_data_sem); - goto err_out; - } else - ext4_clear_inode_state(inode, EXT4_STATE_EXT_MIGRATE); - /* - * We have the extent map build with the tmp inode. - * Now copy the i_data across - */ - ext4_set_inode_flag(inode, EXT4_INODE_EXTENTS); - memcpy(ei->i_data, tmp_ei->i_data, sizeof(ei->i_data)); - - /* - * Update i_blocks with the new blocks that got - * allocated while adding extents for extent index - * blocks. - * - * While converting to extents we need not - * update the original inode i_blocks for extent blocks - * via quota APIs. The quota update happened via tmp_inode already. - */ - spin_lock(&inode->i_lock); - inode->i_blocks += tmp_inode->i_blocks; - spin_unlock(&inode->i_lock); - up_write(&EXT4_I(inode)->i_data_sem); - - /* - * We mark the inode dirty after, because we decrement the - * i_blocks when freeing the indirect meta-data blocks - */ - retval = free_ind_block(handle, inode, i_data); - ext4_mark_inode_dirty(handle, inode); - -err_out: - return retval; -} - -static int free_ext_idx(handle_t *handle, struct inode *inode, - struct ext4_extent_idx *ix) -{ - int i, retval = 0; - ext4_fsblk_t block; - struct buffer_head *bh; - struct ext4_extent_header *eh; - - block = ext4_idx_pblock(ix); - bh = sb_bread(inode->i_sb, block); - if (!bh) - return -EIO; - - eh = (struct ext4_extent_header *)bh->b_data; - if (eh->eh_depth != 0) { - ix = EXT_FIRST_INDEX(eh); - for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ix++) { - retval = free_ext_idx(handle, inode, ix); - if (retval) - break; - } - } - put_bh(bh); - extend_credit_for_blkdel(handle, inode); - ext4_free_blocks(handle, inode, NULL, block, 1, - EXT4_FREE_BLOCKS_METADATA | EXT4_FREE_BLOCKS_FORGET); - return retval; -} - -/* - * Free the extent meta data blocks only - */ -static int free_ext_block(handle_t *handle, struct inode *inode) -{ - int i, retval = 0; - struct ext4_inode_info *ei = EXT4_I(inode); - struct ext4_extent_header *eh = (struct ext4_extent_header *)ei->i_data; - struct ext4_extent_idx *ix; - if (eh->eh_depth == 0) - /* - * No extra blocks allocated for extent meta data - */ - return 0; - ix = EXT_FIRST_INDEX(eh); - for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ix++) { - retval = free_ext_idx(handle, inode, ix); - if (retval) - return retval; - } - return retval; -} - -int ext4_ext_migrate(struct inode *inode) -{ - handle_t *handle; - int retval = 0, i; - __le32 *i_data; - struct ext4_inode_info *ei; - struct inode *tmp_inode = NULL; - struct migrate_struct lb; - unsigned long max_entries; - __u32 goal; - uid_t owner[2]; - - /* - * If the filesystem does not support extents, or the inode - * already is extent-based, error out. - */ - if (!ext4_has_feature_extents(inode->i_sb) || - (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) - return -EINVAL; - - if (S_ISLNK(inode->i_mode) && inode->i_blocks == 0) - /* - * don't migrate fast symlink - */ - return retval; - - /* - * Worst case we can touch the allocation bitmaps, a bgd - * block, and a block to link in the orphan list. We do need - * need to worry about credits for modifying the quota inode. - */ - handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, - 4 + EXT4_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb)); - - if (IS_ERR(handle)) { - retval = PTR_ERR(handle); - return retval; - } - goal = (((inode->i_ino - 1) / EXT4_INODES_PER_GROUP(inode->i_sb)) * - EXT4_INODES_PER_GROUP(inode->i_sb)) + 1; - owner[0] = i_uid_read(inode); - owner[1] = i_gid_read(inode); - tmp_inode = ext4_new_inode(handle, d_inode(inode->i_sb->s_root), - S_IFREG, NULL, goal, owner); - if (IS_ERR(tmp_inode)) { - retval = PTR_ERR(tmp_inode); - ext4_journal_stop(handle); - return retval; - } - i_size_write(tmp_inode, i_size_read(inode)); - /* - * Set the i_nlink to zero so it will be deleted later - * when we drop inode reference. - */ - clear_nlink(tmp_inode); - - ext4_ext_tree_init(handle, tmp_inode); - ext4_orphan_add(handle, tmp_inode); - ext4_journal_stop(handle); - - /* - * start with one credit accounted for - * superblock modification. - * - * For the tmp_inode we already have committed the - * transaction that created the inode. Later as and - * when we add extents we extent the journal - */ - /* - * Even though we take i_mutex we can still cause block - * allocation via mmap write to holes. If we have allocated - * new blocks we fail migrate. New block allocation will - * clear EXT4_STATE_EXT_MIGRATE flag. The flag is updated - * with i_data_sem held to prevent racing with block - * allocation. - */ - down_read(&EXT4_I(inode)->i_data_sem); - ext4_set_inode_state(inode, EXT4_STATE_EXT_MIGRATE); - up_read((&EXT4_I(inode)->i_data_sem)); - - handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, 1); - if (IS_ERR(handle)) { - /* - * It is impossible to update on-disk structures without - * a handle, so just rollback in-core changes and live other - * work to orphan_list_cleanup() - */ - ext4_orphan_del(NULL, tmp_inode); - retval = PTR_ERR(handle); - goto out; - } - - ei = EXT4_I(inode); - i_data = ei->i_data; - memset(&lb, 0, sizeof(lb)); - - /* 32 bit block address 4 bytes */ - max_entries = inode->i_sb->s_blocksize >> 2; - for (i = 0; i < EXT4_NDIR_BLOCKS; i++) { - if (i_data[i]) { - retval = update_extent_range(handle, tmp_inode, - le32_to_cpu(i_data[i]), &lb); - if (retval) - goto err_out; - } else - lb.curr_block++; - } - if (i_data[EXT4_IND_BLOCK]) { - retval = update_ind_extent_range(handle, tmp_inode, - le32_to_cpu(i_data[EXT4_IND_BLOCK]), &lb); - if (retval) - goto err_out; - } else - lb.curr_block += max_entries; - if (i_data[EXT4_DIND_BLOCK]) { - retval = update_dind_extent_range(handle, tmp_inode, - le32_to_cpu(i_data[EXT4_DIND_BLOCK]), &lb); - if (retval) - goto err_out; - } else - lb.curr_block += max_entries * max_entries; - if (i_data[EXT4_TIND_BLOCK]) { - retval = update_tind_extent_range(handle, tmp_inode, - le32_to_cpu(i_data[EXT4_TIND_BLOCK]), &lb); - if (retval) - goto err_out; - } - /* - * Build the last extent - */ - retval = finish_range(handle, tmp_inode, &lb); -err_out: - if (retval) - /* - * Failure case delete the extent information with the - * tmp_inode - */ - free_ext_block(handle, tmp_inode); - else { - retval = ext4_ext_swap_inode_data(handle, inode, tmp_inode); - if (retval) - /* - * if we fail to swap inode data free the extent - * details of the tmp inode - */ - free_ext_block(handle, tmp_inode); - } - - /* We mark the tmp_inode dirty via ext4_ext_tree_init. */ - if (ext4_journal_extend(handle, 1) != 0) - ext4_journal_restart(handle, 1); - - /* - * Mark the tmp_inode as of size zero - */ - i_size_write(tmp_inode, 0); - - /* - * set the i_blocks count to zero - * so that the ext4_evict_inode() does the - * right job - * - * We don't need to take the i_lock because - * the inode is not visible to user space. - */ - tmp_inode->i_blocks = 0; - - /* Reset the extent details */ - ext4_ext_tree_init(handle, tmp_inode); - ext4_journal_stop(handle); -out: - unlock_new_inode(tmp_inode); - iput(tmp_inode); - - return retval; -} - -/* - * Migrate a simple extent-based inode to use the i_blocks[] array - */ -int ext4_ind_migrate(struct inode *inode) -{ - struct ext4_extent_header *eh; - struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es; - struct ext4_inode_info *ei = EXT4_I(inode); - struct ext4_extent *ex; - unsigned int i, len; - ext4_lblk_t start, end; - ext4_fsblk_t blk; - handle_t *handle; - int ret; - - if (!ext4_has_feature_extents(inode->i_sb) || - (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) - return -EINVAL; - - if (ext4_has_feature_bigalloc(inode->i_sb)) - return -EOPNOTSUPP; - - /* - * In order to get correct extent info, force all delayed allocation - * blocks to be allocated, otherwise delayed allocation blocks may not - * be reflected and bypass the checks on extent header. - */ - if (test_opt(inode->i_sb, DELALLOC)) - ext4_alloc_da_blocks(inode); - - handle = ext4_journal_start(inode, EXT4_HT_MIGRATE, 1); - if (IS_ERR(handle)) - return PTR_ERR(handle); - - down_write(&EXT4_I(inode)->i_data_sem); - ret = ext4_ext_check_inode(inode); - if (ret) - goto errout; - - eh = ext_inode_hdr(inode); - ex = EXT_FIRST_EXTENT(eh); - if (ext4_blocks_count(es) > EXT4_MAX_BLOCK_FILE_PHYS || - eh->eh_depth != 0 || le16_to_cpu(eh->eh_entries) > 1) { - ret = -EOPNOTSUPP; - goto errout; - } - if (eh->eh_entries == 0) - blk = len = start = end = 0; - else { - len = le16_to_cpu(ex->ee_len); - blk = ext4_ext_pblock(ex); - start = le32_to_cpu(ex->ee_block); - end = start + len - 1; - if (end >= EXT4_NDIR_BLOCKS) { - ret = -EOPNOTSUPP; - goto errout; - } - } - - ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS); - memset(ei->i_data, 0, sizeof(ei->i_data)); - for (i = start; i <= end; i++) - ei->i_data[i] = cpu_to_le32(blk++); - ext4_mark_inode_dirty(handle, inode); -errout: - ext4_journal_stop(handle); - up_write(&EXT4_I(inode)->i_data_sem); - return ret; -} diff --git a/src/linux/fs/ext4/mmp.c b/src/linux/fs/ext4/mmp.c deleted file mode 100644 index d89754e..0000000 --- a/src/linux/fs/ext4/mmp.c +++ /dev/null @@ -1,399 +0,0 @@ -#include -#include -#include -#include -#include - -#include "ext4.h" - -/* Checksumming functions */ -static __le32 ext4_mmp_csum(struct super_block *sb, struct mmp_struct *mmp) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - int offset = offsetof(struct mmp_struct, mmp_checksum); - __u32 csum; - - csum = ext4_chksum(sbi, sbi->s_csum_seed, (char *)mmp, offset); - - return cpu_to_le32(csum); -} - -static int ext4_mmp_csum_verify(struct super_block *sb, struct mmp_struct *mmp) -{ - if (!ext4_has_metadata_csum(sb)) - return 1; - - return mmp->mmp_checksum == ext4_mmp_csum(sb, mmp); -} - -static void ext4_mmp_csum_set(struct super_block *sb, struct mmp_struct *mmp) -{ - if (!ext4_has_metadata_csum(sb)) - return; - - mmp->mmp_checksum = ext4_mmp_csum(sb, mmp); -} - -/* - * Write the MMP block using WRITE_SYNC to try to get the block on-disk - * faster. - */ -static int write_mmp_block(struct super_block *sb, struct buffer_head *bh) -{ - struct mmp_struct *mmp = (struct mmp_struct *)(bh->b_data); - - /* - * We protect against freezing so that we don't create dirty buffers - * on frozen filesystem. - */ - sb_start_write(sb); - ext4_mmp_csum_set(sb, mmp); - mark_buffer_dirty(bh); - lock_buffer(bh); - bh->b_end_io = end_buffer_write_sync; - get_bh(bh); - submit_bh(REQ_OP_WRITE, WRITE_SYNC | REQ_META | REQ_PRIO, bh); - wait_on_buffer(bh); - sb_end_write(sb); - if (unlikely(!buffer_uptodate(bh))) - return 1; - - return 0; -} - -/* - * Read the MMP block. It _must_ be read from disk and hence we clear the - * uptodate flag on the buffer. - */ -static int read_mmp_block(struct super_block *sb, struct buffer_head **bh, - ext4_fsblk_t mmp_block) -{ - struct mmp_struct *mmp; - int ret; - - if (*bh) - clear_buffer_uptodate(*bh); - - /* This would be sb_bread(sb, mmp_block), except we need to be sure - * that the MD RAID device cache has been bypassed, and that the read - * is not blocked in the elevator. */ - if (!*bh) { - *bh = sb_getblk(sb, mmp_block); - if (!*bh) { - ret = -ENOMEM; - goto warn_exit; - } - } - - get_bh(*bh); - lock_buffer(*bh); - (*bh)->b_end_io = end_buffer_read_sync; - submit_bh(REQ_OP_READ, READ_SYNC | REQ_META | REQ_PRIO, *bh); - wait_on_buffer(*bh); - if (!buffer_uptodate(*bh)) { - ret = -EIO; - goto warn_exit; - } - mmp = (struct mmp_struct *)((*bh)->b_data); - if (le32_to_cpu(mmp->mmp_magic) != EXT4_MMP_MAGIC) { - ret = -EFSCORRUPTED; - goto warn_exit; - } - if (!ext4_mmp_csum_verify(sb, mmp)) { - ret = -EFSBADCRC; - goto warn_exit; - } - return 0; -warn_exit: - brelse(*bh); - *bh = NULL; - ext4_warning(sb, "Error %d while reading MMP block %llu", - ret, mmp_block); - return ret; -} - -/* - * Dump as much information as possible to help the admin. - */ -void __dump_mmp_msg(struct super_block *sb, struct mmp_struct *mmp, - const char *function, unsigned int line, const char *msg) -{ - __ext4_warning(sb, function, line, "%s", msg); - __ext4_warning(sb, function, line, - "MMP failure info: last update time: %llu, last update " - "node: %s, last update device: %s", - (long long unsigned int) le64_to_cpu(mmp->mmp_time), - mmp->mmp_nodename, mmp->mmp_bdevname); -} - -/* - * kmmpd will update the MMP sequence every s_mmp_update_interval seconds - */ -static int kmmpd(void *data) -{ - struct super_block *sb = ((struct mmpd_data *) data)->sb; - struct buffer_head *bh = ((struct mmpd_data *) data)->bh; - struct ext4_super_block *es = EXT4_SB(sb)->s_es; - struct mmp_struct *mmp; - ext4_fsblk_t mmp_block; - u32 seq = 0; - unsigned long failed_writes = 0; - int mmp_update_interval = le16_to_cpu(es->s_mmp_update_interval); - unsigned mmp_check_interval; - unsigned long last_update_time; - unsigned long diff; - int retval; - - mmp_block = le64_to_cpu(es->s_mmp_block); - mmp = (struct mmp_struct *)(bh->b_data); - mmp->mmp_time = cpu_to_le64(get_seconds()); - /* - * Start with the higher mmp_check_interval and reduce it if - * the MMP block is being updated on time. - */ - mmp_check_interval = max(EXT4_MMP_CHECK_MULT * mmp_update_interval, - EXT4_MMP_MIN_CHECK_INTERVAL); - mmp->mmp_check_interval = cpu_to_le16(mmp_check_interval); - bdevname(bh->b_bdev, mmp->mmp_bdevname); - - memcpy(mmp->mmp_nodename, init_utsname()->nodename, - sizeof(mmp->mmp_nodename)); - - while (!kthread_should_stop()) { - if (++seq > EXT4_MMP_SEQ_MAX) - seq = 1; - - mmp->mmp_seq = cpu_to_le32(seq); - mmp->mmp_time = cpu_to_le64(get_seconds()); - last_update_time = jiffies; - - retval = write_mmp_block(sb, bh); - /* - * Don't spew too many error messages. Print one every - * (s_mmp_update_interval * 60) seconds. - */ - if (retval) { - if ((failed_writes % 60) == 0) - ext4_error(sb, "Error writing to MMP block"); - failed_writes++; - } - - if (!(le32_to_cpu(es->s_feature_incompat) & - EXT4_FEATURE_INCOMPAT_MMP)) { - ext4_warning(sb, "kmmpd being stopped since MMP feature" - " has been disabled."); - goto exit_thread; - } - - if (sb->s_flags & MS_RDONLY) { - ext4_warning(sb, "kmmpd being stopped since filesystem " - "has been remounted as readonly."); - goto exit_thread; - } - - diff = jiffies - last_update_time; - if (diff < mmp_update_interval * HZ) - schedule_timeout_interruptible(mmp_update_interval * - HZ - diff); - - /* - * We need to make sure that more than mmp_check_interval - * seconds have not passed since writing. If that has happened - * we need to check if the MMP block is as we left it. - */ - diff = jiffies - last_update_time; - if (diff > mmp_check_interval * HZ) { - struct buffer_head *bh_check = NULL; - struct mmp_struct *mmp_check; - - retval = read_mmp_block(sb, &bh_check, mmp_block); - if (retval) { - ext4_error(sb, "error reading MMP data: %d", - retval); - goto exit_thread; - } - - mmp_check = (struct mmp_struct *)(bh_check->b_data); - if (mmp->mmp_seq != mmp_check->mmp_seq || - memcmp(mmp->mmp_nodename, mmp_check->mmp_nodename, - sizeof(mmp->mmp_nodename))) { - dump_mmp_msg(sb, mmp_check, - "Error while updating MMP info. " - "The filesystem seems to have been" - " multiply mounted."); - ext4_error(sb, "abort"); - put_bh(bh_check); - retval = -EBUSY; - goto exit_thread; - } - put_bh(bh_check); - } - - /* - * Adjust the mmp_check_interval depending on how much time - * it took for the MMP block to be written. - */ - mmp_check_interval = max(min(EXT4_MMP_CHECK_MULT * diff / HZ, - EXT4_MMP_MAX_CHECK_INTERVAL), - EXT4_MMP_MIN_CHECK_INTERVAL); - mmp->mmp_check_interval = cpu_to_le16(mmp_check_interval); - } - - /* - * Unmount seems to be clean. - */ - mmp->mmp_seq = cpu_to_le32(EXT4_MMP_SEQ_CLEAN); - mmp->mmp_time = cpu_to_le64(get_seconds()); - - retval = write_mmp_block(sb, bh); - -exit_thread: - EXT4_SB(sb)->s_mmp_tsk = NULL; - kfree(data); - brelse(bh); - return retval; -} - -/* - * Get a random new sequence number but make sure it is not greater than - * EXT4_MMP_SEQ_MAX. - */ -static unsigned int mmp_new_seq(void) -{ - u32 new_seq; - - do { - new_seq = prandom_u32(); - } while (new_seq > EXT4_MMP_SEQ_MAX); - - return new_seq; -} - -/* - * Protect the filesystem from being mounted more than once. - */ -int ext4_multi_mount_protect(struct super_block *sb, - ext4_fsblk_t mmp_block) -{ - struct ext4_super_block *es = EXT4_SB(sb)->s_es; - struct buffer_head *bh = NULL; - struct mmp_struct *mmp = NULL; - struct mmpd_data *mmpd_data; - u32 seq; - unsigned int mmp_check_interval = le16_to_cpu(es->s_mmp_update_interval); - unsigned int wait_time = 0; - int retval; - - if (mmp_block < le32_to_cpu(es->s_first_data_block) || - mmp_block >= ext4_blocks_count(es)) { - ext4_warning(sb, "Invalid MMP block in superblock"); - goto failed; - } - - retval = read_mmp_block(sb, &bh, mmp_block); - if (retval) - goto failed; - - mmp = (struct mmp_struct *)(bh->b_data); - - if (mmp_check_interval < EXT4_MMP_MIN_CHECK_INTERVAL) - mmp_check_interval = EXT4_MMP_MIN_CHECK_INTERVAL; - - /* - * If check_interval in MMP block is larger, use that instead of - * update_interval from the superblock. - */ - if (le16_to_cpu(mmp->mmp_check_interval) > mmp_check_interval) - mmp_check_interval = le16_to_cpu(mmp->mmp_check_interval); - - seq = le32_to_cpu(mmp->mmp_seq); - if (seq == EXT4_MMP_SEQ_CLEAN) - goto skip; - - if (seq == EXT4_MMP_SEQ_FSCK) { - dump_mmp_msg(sb, mmp, "fsck is running on the filesystem"); - goto failed; - } - - wait_time = min(mmp_check_interval * 2 + 1, - mmp_check_interval + 60); - - /* Print MMP interval if more than 20 secs. */ - if (wait_time > EXT4_MMP_MIN_CHECK_INTERVAL * 4) - ext4_warning(sb, "MMP interval %u higher than expected, please" - " wait.\n", wait_time * 2); - - if (schedule_timeout_interruptible(HZ * wait_time) != 0) { - ext4_warning(sb, "MMP startup interrupted, failing mount\n"); - goto failed; - } - - retval = read_mmp_block(sb, &bh, mmp_block); - if (retval) - goto failed; - mmp = (struct mmp_struct *)(bh->b_data); - if (seq != le32_to_cpu(mmp->mmp_seq)) { - dump_mmp_msg(sb, mmp, - "Device is already active on another node."); - goto failed; - } - -skip: - /* - * write a new random sequence number. - */ - seq = mmp_new_seq(); - mmp->mmp_seq = cpu_to_le32(seq); - - retval = write_mmp_block(sb, bh); - if (retval) - goto failed; - - /* - * wait for MMP interval and check mmp_seq. - */ - if (schedule_timeout_interruptible(HZ * wait_time) != 0) { - ext4_warning(sb, "MMP startup interrupted, failing mount"); - goto failed; - } - - retval = read_mmp_block(sb, &bh, mmp_block); - if (retval) - goto failed; - mmp = (struct mmp_struct *)(bh->b_data); - if (seq != le32_to_cpu(mmp->mmp_seq)) { - dump_mmp_msg(sb, mmp, - "Device is already active on another node."); - goto failed; - } - - mmpd_data = kmalloc(sizeof(struct mmpd_data), GFP_KERNEL); - if (!mmpd_data) { - ext4_warning(sb, "not enough memory for mmpd_data"); - goto failed; - } - mmpd_data->sb = sb; - mmpd_data->bh = bh; - - /* - * Start a kernel thread to update the MMP block periodically. - */ - EXT4_SB(sb)->s_mmp_tsk = kthread_run(kmmpd, mmpd_data, "kmmpd-%s", - bdevname(bh->b_bdev, - mmp->mmp_bdevname)); - if (IS_ERR(EXT4_SB(sb)->s_mmp_tsk)) { - EXT4_SB(sb)->s_mmp_tsk = NULL; - kfree(mmpd_data); - ext4_warning(sb, "Unable to create kmmpd thread for %s.", - sb->s_id); - goto failed; - } - - return 0; - -failed: - brelse(bh); - return 1; -} - - diff --git a/src/linux/fs/ext4/move_extent.c b/src/linux/fs/ext4/move_extent.c deleted file mode 100644 index 6fc14de..0000000 --- a/src/linux/fs/ext4/move_extent.c +++ /dev/null @@ -1,709 +0,0 @@ -/* - * Copyright (c) 2008,2009 NEC Software Tohoku, Ltd. - * Written by Takashi Sato - * Akira Fujita - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include "ext4_jbd2.h" -#include "ext4.h" -#include "ext4_extents.h" - -/** - * get_ext_path - Find an extent path for designated logical block number. - * - * @inode: an inode which is searched - * @lblock: logical block number to find an extent path - * @path: pointer to an extent path pointer (for output) - * - * ext4_find_extent wrapper. Return 0 on success, or a negative error value - * on failure. - */ -static inline int -get_ext_path(struct inode *inode, ext4_lblk_t lblock, - struct ext4_ext_path **ppath) -{ - struct ext4_ext_path *path; - - path = ext4_find_extent(inode, lblock, ppath, EXT4_EX_NOCACHE); - if (IS_ERR(path)) - return PTR_ERR(path); - if (path[ext_depth(inode)].p_ext == NULL) { - ext4_ext_drop_refs(path); - kfree(path); - *ppath = NULL; - return -ENODATA; - } - *ppath = path; - return 0; -} - -/** - * ext4_double_down_write_data_sem - Acquire two inodes' write lock - * of i_data_sem - * - * Acquire write lock of i_data_sem of the two inodes - */ -void -ext4_double_down_write_data_sem(struct inode *first, struct inode *second) -{ - if (first < second) { - down_write(&EXT4_I(first)->i_data_sem); - down_write_nested(&EXT4_I(second)->i_data_sem, I_DATA_SEM_OTHER); - } else { - down_write(&EXT4_I(second)->i_data_sem); - down_write_nested(&EXT4_I(first)->i_data_sem, I_DATA_SEM_OTHER); - - } -} - -/** - * ext4_double_up_write_data_sem - Release two inodes' write lock of i_data_sem - * - * @orig_inode: original inode structure to be released its lock first - * @donor_inode: donor inode structure to be released its lock second - * Release write lock of i_data_sem of two inodes (orig and donor). - */ -void -ext4_double_up_write_data_sem(struct inode *orig_inode, - struct inode *donor_inode) -{ - up_write(&EXT4_I(orig_inode)->i_data_sem); - up_write(&EXT4_I(donor_inode)->i_data_sem); -} - -/** - * mext_check_coverage - Check that all extents in range has the same type - * - * @inode: inode in question - * @from: block offset of inode - * @count: block count to be checked - * @unwritten: extents expected to be unwritten - * @err: pointer to save error value - * - * Return 1 if all extents in range has expected type, and zero otherwise. - */ -static int -mext_check_coverage(struct inode *inode, ext4_lblk_t from, ext4_lblk_t count, - int unwritten, int *err) -{ - struct ext4_ext_path *path = NULL; - struct ext4_extent *ext; - int ret = 0; - ext4_lblk_t last = from + count; - while (from < last) { - *err = get_ext_path(inode, from, &path); - if (*err) - goto out; - ext = path[ext_depth(inode)].p_ext; - if (unwritten != ext4_ext_is_unwritten(ext)) - goto out; - from += ext4_ext_get_actual_len(ext); - ext4_ext_drop_refs(path); - } - ret = 1; -out: - ext4_ext_drop_refs(path); - kfree(path); - return ret; -} - -/** - * mext_page_double_lock - Grab and lock pages on both @inode1 and @inode2 - * - * @inode1: the inode structure - * @inode2: the inode structure - * @index1: page index - * @index2: page index - * @page: result page vector - * - * Grab two locked pages for inode's by inode order - */ -static int -mext_page_double_lock(struct inode *inode1, struct inode *inode2, - pgoff_t index1, pgoff_t index2, struct page *page[2]) -{ - struct address_space *mapping[2]; - unsigned fl = AOP_FLAG_NOFS; - - BUG_ON(!inode1 || !inode2); - if (inode1 < inode2) { - mapping[0] = inode1->i_mapping; - mapping[1] = inode2->i_mapping; - } else { - pgoff_t tmp = index1; - index1 = index2; - index2 = tmp; - mapping[0] = inode2->i_mapping; - mapping[1] = inode1->i_mapping; - } - - page[0] = grab_cache_page_write_begin(mapping[0], index1, fl); - if (!page[0]) - return -ENOMEM; - - page[1] = grab_cache_page_write_begin(mapping[1], index2, fl); - if (!page[1]) { - unlock_page(page[0]); - put_page(page[0]); - return -ENOMEM; - } - /* - * grab_cache_page_write_begin() may not wait on page's writeback if - * BDI not demand that. But it is reasonable to be very conservative - * here and explicitly wait on page's writeback - */ - wait_on_page_writeback(page[0]); - wait_on_page_writeback(page[1]); - if (inode1 > inode2) - swap(page[0], page[1]); - - return 0; -} - -/* Force page buffers uptodate w/o dropping page's lock */ -static int -mext_page_mkuptodate(struct page *page, unsigned from, unsigned to) -{ - struct inode *inode = page->mapping->host; - sector_t block; - struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE]; - unsigned int blocksize, block_start, block_end; - int i, err, nr = 0, partial = 0; - BUG_ON(!PageLocked(page)); - BUG_ON(PageWriteback(page)); - - if (PageUptodate(page)) - return 0; - - blocksize = 1 << inode->i_blkbits; - if (!page_has_buffers(page)) - create_empty_buffers(page, blocksize, 0); - - head = page_buffers(page); - block = (sector_t)page->index << (PAGE_SHIFT - inode->i_blkbits); - for (bh = head, block_start = 0; bh != head || !block_start; - block++, block_start = block_end, bh = bh->b_this_page) { - block_end = block_start + blocksize; - if (block_end <= from || block_start >= to) { - if (!buffer_uptodate(bh)) - partial = 1; - continue; - } - if (buffer_uptodate(bh)) - continue; - if (!buffer_mapped(bh)) { - err = ext4_get_block(inode, block, bh, 0); - if (err) { - SetPageError(page); - return err; - } - if (!buffer_mapped(bh)) { - zero_user(page, block_start, blocksize); - set_buffer_uptodate(bh); - continue; - } - } - BUG_ON(nr >= MAX_BUF_PER_PAGE); - arr[nr++] = bh; - } - /* No io required */ - if (!nr) - goto out; - - for (i = 0; i < nr; i++) { - bh = arr[i]; - if (!bh_uptodate_or_lock(bh)) { - err = bh_submit_read(bh); - if (err) - return err; - } - } -out: - if (!partial) - SetPageUptodate(page); - return 0; -} - -/** - * move_extent_per_page - Move extent data per page - * - * @o_filp: file structure of original file - * @donor_inode: donor inode - * @orig_page_offset: page index on original file - * @donor_page_offset: page index on donor file - * @data_offset_in_page: block index where data swapping starts - * @block_len_in_page: the number of blocks to be swapped - * @unwritten: orig extent is unwritten or not - * @err: pointer to save return value - * - * Save the data in original inode blocks and replace original inode extents - * with donor inode extents by calling ext4_swap_extents(). - * Finally, write out the saved data in new original inode blocks. Return - * replaced block count. - */ -static int -move_extent_per_page(struct file *o_filp, struct inode *donor_inode, - pgoff_t orig_page_offset, pgoff_t donor_page_offset, - int data_offset_in_page, - int block_len_in_page, int unwritten, int *err) -{ - struct inode *orig_inode = file_inode(o_filp); - struct page *pagep[2] = {NULL, NULL}; - handle_t *handle; - ext4_lblk_t orig_blk_offset, donor_blk_offset; - unsigned long blocksize = orig_inode->i_sb->s_blocksize; - unsigned int tmp_data_size, data_size, replaced_size; - int i, err2, jblocks, retries = 0; - int replaced_count = 0; - int from = data_offset_in_page << orig_inode->i_blkbits; - int blocks_per_page = PAGE_SIZE >> orig_inode->i_blkbits; - struct super_block *sb = orig_inode->i_sb; - struct buffer_head *bh = NULL; - - /* - * It needs twice the amount of ordinary journal buffers because - * inode and donor_inode may change each different metadata blocks. - */ -again: - *err = 0; - jblocks = ext4_writepage_trans_blocks(orig_inode) * 2; - handle = ext4_journal_start(orig_inode, EXT4_HT_MOVE_EXTENTS, jblocks); - if (IS_ERR(handle)) { - *err = PTR_ERR(handle); - return 0; - } - - orig_blk_offset = orig_page_offset * blocks_per_page + - data_offset_in_page; - - donor_blk_offset = donor_page_offset * blocks_per_page + - data_offset_in_page; - - /* Calculate data_size */ - if ((orig_blk_offset + block_len_in_page - 1) == - ((orig_inode->i_size - 1) >> orig_inode->i_blkbits)) { - /* Replace the last block */ - tmp_data_size = orig_inode->i_size & (blocksize - 1); - /* - * If data_size equal zero, it shows data_size is multiples of - * blocksize. So we set appropriate value. - */ - if (tmp_data_size == 0) - tmp_data_size = blocksize; - - data_size = tmp_data_size + - ((block_len_in_page - 1) << orig_inode->i_blkbits); - } else - data_size = block_len_in_page << orig_inode->i_blkbits; - - replaced_size = data_size; - - *err = mext_page_double_lock(orig_inode, donor_inode, orig_page_offset, - donor_page_offset, pagep); - if (unlikely(*err < 0)) - goto stop_journal; - /* - * If orig extent was unwritten it can become initialized - * at any time after i_data_sem was dropped, in order to - * serialize with delalloc we have recheck extent while we - * hold page's lock, if it is still the case data copy is not - * necessary, just swap data blocks between orig and donor. - */ - if (unwritten) { - ext4_double_down_write_data_sem(orig_inode, donor_inode); - /* If any of extents in range became initialized we have to - * fallback to data copying */ - unwritten = mext_check_coverage(orig_inode, orig_blk_offset, - block_len_in_page, 1, err); - if (*err) - goto drop_data_sem; - - unwritten &= mext_check_coverage(donor_inode, donor_blk_offset, - block_len_in_page, 1, err); - if (*err) - goto drop_data_sem; - - if (!unwritten) { - ext4_double_up_write_data_sem(orig_inode, donor_inode); - goto data_copy; - } - if ((page_has_private(pagep[0]) && - !try_to_release_page(pagep[0], 0)) || - (page_has_private(pagep[1]) && - !try_to_release_page(pagep[1], 0))) { - *err = -EBUSY; - goto drop_data_sem; - } - replaced_count = ext4_swap_extents(handle, orig_inode, - donor_inode, orig_blk_offset, - donor_blk_offset, - block_len_in_page, 1, err); - drop_data_sem: - ext4_double_up_write_data_sem(orig_inode, donor_inode); - goto unlock_pages; - } -data_copy: - *err = mext_page_mkuptodate(pagep[0], from, from + replaced_size); - if (*err) - goto unlock_pages; - - /* At this point all buffers in range are uptodate, old mapping layout - * is no longer required, try to drop it now. */ - if ((page_has_private(pagep[0]) && !try_to_release_page(pagep[0], 0)) || - (page_has_private(pagep[1]) && !try_to_release_page(pagep[1], 0))) { - *err = -EBUSY; - goto unlock_pages; - } - ext4_double_down_write_data_sem(orig_inode, donor_inode); - replaced_count = ext4_swap_extents(handle, orig_inode, donor_inode, - orig_blk_offset, donor_blk_offset, - block_len_in_page, 1, err); - ext4_double_up_write_data_sem(orig_inode, donor_inode); - if (*err) { - if (replaced_count) { - block_len_in_page = replaced_count; - replaced_size = - block_len_in_page << orig_inode->i_blkbits; - } else - goto unlock_pages; - } - /* Perform all necessary steps similar write_begin()/write_end() - * but keeping in mind that i_size will not change */ - if (!page_has_buffers(pagep[0])) - create_empty_buffers(pagep[0], 1 << orig_inode->i_blkbits, 0); - bh = page_buffers(pagep[0]); - for (i = 0; i < data_offset_in_page; i++) - bh = bh->b_this_page; - for (i = 0; i < block_len_in_page; i++) { - *err = ext4_get_block(orig_inode, orig_blk_offset + i, bh, 0); - if (*err < 0) - break; - bh = bh->b_this_page; - } - if (!*err) - *err = block_commit_write(pagep[0], from, from + replaced_size); - - if (unlikely(*err < 0)) - goto repair_branches; - - /* Even in case of data=writeback it is reasonable to pin - * inode to transaction, to prevent unexpected data loss */ - *err = ext4_jbd2_inode_add_write(handle, orig_inode); - -unlock_pages: - unlock_page(pagep[0]); - put_page(pagep[0]); - unlock_page(pagep[1]); - put_page(pagep[1]); -stop_journal: - ext4_journal_stop(handle); - if (*err == -ENOSPC && - ext4_should_retry_alloc(sb, &retries)) - goto again; - /* Buffer was busy because probably is pinned to journal transaction, - * force transaction commit may help to free it. */ - if (*err == -EBUSY && retries++ < 4 && EXT4_SB(sb)->s_journal && - jbd2_journal_force_commit_nested(EXT4_SB(sb)->s_journal)) - goto again; - return replaced_count; - -repair_branches: - /* - * This should never ever happen! - * Extents are swapped already, but we are not able to copy data. - * Try to swap extents to it's original places - */ - ext4_double_down_write_data_sem(orig_inode, donor_inode); - replaced_count = ext4_swap_extents(handle, donor_inode, orig_inode, - orig_blk_offset, donor_blk_offset, - block_len_in_page, 0, &err2); - ext4_double_up_write_data_sem(orig_inode, donor_inode); - if (replaced_count != block_len_in_page) { - EXT4_ERROR_INODE_BLOCK(orig_inode, (sector_t)(orig_blk_offset), - "Unable to copy data block," - " data will be lost."); - *err = -EIO; - } - replaced_count = 0; - goto unlock_pages; -} - -/** - * mext_check_arguments - Check whether move extent can be done - * - * @orig_inode: original inode - * @donor_inode: donor inode - * @orig_start: logical start offset in block for orig - * @donor_start: logical start offset in block for donor - * @len: the number of blocks to be moved - * - * Check the arguments of ext4_move_extents() whether the files can be - * exchanged with each other. - * Return 0 on success, or a negative error value on failure. - */ -static int -mext_check_arguments(struct inode *orig_inode, - struct inode *donor_inode, __u64 orig_start, - __u64 donor_start, __u64 *len) -{ - __u64 orig_eof, donor_eof; - unsigned int blkbits = orig_inode->i_blkbits; - unsigned int blocksize = 1 << blkbits; - - orig_eof = (i_size_read(orig_inode) + blocksize - 1) >> blkbits; - donor_eof = (i_size_read(donor_inode) + blocksize - 1) >> blkbits; - - - if (donor_inode->i_mode & (S_ISUID|S_ISGID)) { - ext4_debug("ext4 move extent: suid or sgid is set" - " to donor file [ino:orig %lu, donor %lu]\n", - orig_inode->i_ino, donor_inode->i_ino); - return -EINVAL; - } - - if (IS_IMMUTABLE(donor_inode) || IS_APPEND(donor_inode)) - return -EPERM; - - /* Ext4 move extent does not support swapfile */ - if (IS_SWAPFILE(orig_inode) || IS_SWAPFILE(donor_inode)) { - ext4_debug("ext4 move extent: The argument files should " - "not be swapfile [ino:orig %lu, donor %lu]\n", - orig_inode->i_ino, donor_inode->i_ino); - return -EBUSY; - } - - if (IS_NOQUOTA(orig_inode) || IS_NOQUOTA(donor_inode)) { - ext4_debug("ext4 move extent: The argument files should " - "not be quota files [ino:orig %lu, donor %lu]\n", - orig_inode->i_ino, donor_inode->i_ino); - return -EBUSY; - } - - /* Ext4 move extent supports only extent based file */ - if (!(ext4_test_inode_flag(orig_inode, EXT4_INODE_EXTENTS))) { - ext4_debug("ext4 move extent: orig file is not extents " - "based file [ino:orig %lu]\n", orig_inode->i_ino); - return -EOPNOTSUPP; - } else if (!(ext4_test_inode_flag(donor_inode, EXT4_INODE_EXTENTS))) { - ext4_debug("ext4 move extent: donor file is not extents " - "based file [ino:donor %lu]\n", donor_inode->i_ino); - return -EOPNOTSUPP; - } - - if ((!orig_inode->i_size) || (!donor_inode->i_size)) { - ext4_debug("ext4 move extent: File size is 0 byte\n"); - return -EINVAL; - } - - /* Start offset should be same */ - if ((orig_start & ~(PAGE_MASK >> orig_inode->i_blkbits)) != - (donor_start & ~(PAGE_MASK >> orig_inode->i_blkbits))) { - ext4_debug("ext4 move extent: orig and donor's start " - "offset are not alligned [ino:orig %lu, donor %lu]\n", - orig_inode->i_ino, donor_inode->i_ino); - return -EINVAL; - } - - if ((orig_start >= EXT_MAX_BLOCKS) || - (donor_start >= EXT_MAX_BLOCKS) || - (*len > EXT_MAX_BLOCKS) || - (donor_start + *len >= EXT_MAX_BLOCKS) || - (orig_start + *len >= EXT_MAX_BLOCKS)) { - ext4_debug("ext4 move extent: Can't handle over [%u] blocks " - "[ino:orig %lu, donor %lu]\n", EXT_MAX_BLOCKS, - orig_inode->i_ino, donor_inode->i_ino); - return -EINVAL; - } - if (orig_eof < orig_start + *len - 1) - *len = orig_eof - orig_start; - if (donor_eof < donor_start + *len - 1) - *len = donor_eof - donor_start; - if (!*len) { - ext4_debug("ext4 move extent: len should not be 0 " - "[ino:orig %lu, donor %lu]\n", orig_inode->i_ino, - donor_inode->i_ino); - return -EINVAL; - } - - return 0; -} - -/** - * ext4_move_extents - Exchange the specified range of a file - * - * @o_filp: file structure of the original file - * @d_filp: file structure of the donor file - * @orig_blk: start offset in block for orig - * @donor_blk: start offset in block for donor - * @len: the number of blocks to be moved - * @moved_len: moved block length - * - * This function returns 0 and moved block length is set in moved_len - * if succeed, otherwise returns error value. - * - */ -int -ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk, - __u64 donor_blk, __u64 len, __u64 *moved_len) -{ - struct inode *orig_inode = file_inode(o_filp); - struct inode *donor_inode = file_inode(d_filp); - struct ext4_ext_path *path = NULL; - int blocks_per_page = PAGE_SIZE >> orig_inode->i_blkbits; - ext4_lblk_t o_end, o_start = orig_blk; - ext4_lblk_t d_start = donor_blk; - int ret; - - if (orig_inode->i_sb != donor_inode->i_sb) { - ext4_debug("ext4 move extent: The argument files " - "should be in same FS [ino:orig %lu, donor %lu]\n", - orig_inode->i_ino, donor_inode->i_ino); - return -EINVAL; - } - - /* orig and donor should be different inodes */ - if (orig_inode == donor_inode) { - ext4_debug("ext4 move extent: The argument files should not " - "be same inode [ino:orig %lu, donor %lu]\n", - orig_inode->i_ino, donor_inode->i_ino); - return -EINVAL; - } - - /* Regular file check */ - if (!S_ISREG(orig_inode->i_mode) || !S_ISREG(donor_inode->i_mode)) { - ext4_debug("ext4 move extent: The argument files should be " - "regular file [ino:orig %lu, donor %lu]\n", - orig_inode->i_ino, donor_inode->i_ino); - return -EINVAL; - } - - /* TODO: it's not obvious how to swap blocks for inodes with full - journaling enabled */ - if (ext4_should_journal_data(orig_inode) || - ext4_should_journal_data(donor_inode)) { - ext4_msg(orig_inode->i_sb, KERN_ERR, - "Online defrag not supported with data journaling"); - return -EOPNOTSUPP; - } - - if (ext4_encrypted_inode(orig_inode) || - ext4_encrypted_inode(donor_inode)) { - ext4_msg(orig_inode->i_sb, KERN_ERR, - "Online defrag not supported for encrypted files"); - return -EOPNOTSUPP; - } - - /* Protect orig and donor inodes against a truncate */ - lock_two_nondirectories(orig_inode, donor_inode); - - /* Wait for all existing dio workers */ - ext4_inode_block_unlocked_dio(orig_inode); - ext4_inode_block_unlocked_dio(donor_inode); - inode_dio_wait(orig_inode); - inode_dio_wait(donor_inode); - - /* Protect extent tree against block allocations via delalloc */ - ext4_double_down_write_data_sem(orig_inode, donor_inode); - /* Check the filesystem environment whether move_extent can be done */ - ret = mext_check_arguments(orig_inode, donor_inode, orig_blk, - donor_blk, &len); - if (ret) - goto out; - o_end = o_start + len; - - while (o_start < o_end) { - struct ext4_extent *ex; - ext4_lblk_t cur_blk, next_blk; - pgoff_t orig_page_index, donor_page_index; - int offset_in_page; - int unwritten, cur_len; - - ret = get_ext_path(orig_inode, o_start, &path); - if (ret) - goto out; - ex = path[path->p_depth].p_ext; - next_blk = ext4_ext_next_allocated_block(path); - cur_blk = le32_to_cpu(ex->ee_block); - cur_len = ext4_ext_get_actual_len(ex); - /* Check hole before the start pos */ - if (cur_blk + cur_len - 1 < o_start) { - if (next_blk == EXT_MAX_BLOCKS) { - o_start = o_end; - ret = -ENODATA; - goto out; - } - d_start += next_blk - o_start; - o_start = next_blk; - continue; - /* Check hole after the start pos */ - } else if (cur_blk > o_start) { - /* Skip hole */ - d_start += cur_blk - o_start; - o_start = cur_blk; - /* Extent inside requested range ?*/ - if (cur_blk >= o_end) - goto out; - } else { /* in_range(o_start, o_blk, o_len) */ - cur_len += cur_blk - o_start; - } - unwritten = ext4_ext_is_unwritten(ex); - if (o_end - o_start < cur_len) - cur_len = o_end - o_start; - - orig_page_index = o_start >> (PAGE_SHIFT - - orig_inode->i_blkbits); - donor_page_index = d_start >> (PAGE_SHIFT - - donor_inode->i_blkbits); - offset_in_page = o_start % blocks_per_page; - if (cur_len > blocks_per_page- offset_in_page) - cur_len = blocks_per_page - offset_in_page; - /* - * Up semaphore to avoid following problems: - * a. transaction deadlock among ext4_journal_start, - * ->write_begin via pagefault, and jbd2_journal_commit - * b. racing with ->readpage, ->write_begin, and ext4_get_block - * in move_extent_per_page - */ - ext4_double_up_write_data_sem(orig_inode, donor_inode); - /* Swap original branches with new branches */ - move_extent_per_page(o_filp, donor_inode, - orig_page_index, donor_page_index, - offset_in_page, cur_len, - unwritten, &ret); - ext4_double_down_write_data_sem(orig_inode, donor_inode); - if (ret < 0) - break; - o_start += cur_len; - d_start += cur_len; - } - *moved_len = o_start - orig_blk; - if (*moved_len > len) - *moved_len = len; - -out: - if (*moved_len) { - ext4_discard_preallocations(orig_inode); - ext4_discard_preallocations(donor_inode); - } - - ext4_ext_drop_refs(path); - kfree(path); - ext4_double_up_write_data_sem(orig_inode, donor_inode); - ext4_inode_resume_unlocked_dio(orig_inode); - ext4_inode_resume_unlocked_dio(donor_inode); - unlock_two_nondirectories(orig_inode, donor_inode); - - return ret; -} diff --git a/src/linux/fs/ext4/namei.c b/src/linux/fs/ext4/namei.c deleted file mode 100644 index 104f8bf..0000000 --- a/src/linux/fs/ext4/namei.c +++ /dev/null @@ -1,3896 +0,0 @@ -/* - * linux/fs/ext4/namei.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/namei.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - * Directory entry file type support and forward compatibility hooks - * for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998 - * Hash Tree Directory indexing (c) - * Daniel Phillips, 2001 - * Hash Tree Directory indexing porting - * Christopher Li, 2002 - * Hash Tree Directory indexing cleanup - * Theodore Ts'o, 2002 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ext4.h" -#include "ext4_jbd2.h" - -#include "xattr.h" -#include "acl.h" - -#include -/* - * define how far ahead to read directories while searching them. - */ -#define NAMEI_RA_CHUNKS 2 -#define NAMEI_RA_BLOCKS 4 -#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) - -static struct buffer_head *ext4_append(handle_t *handle, - struct inode *inode, - ext4_lblk_t *block) -{ - struct buffer_head *bh; - int err; - - if (unlikely(EXT4_SB(inode->i_sb)->s_max_dir_size_kb && - ((inode->i_size >> 10) >= - EXT4_SB(inode->i_sb)->s_max_dir_size_kb))) - return ERR_PTR(-ENOSPC); - - *block = inode->i_size >> inode->i_sb->s_blocksize_bits; - - bh = ext4_bread(handle, inode, *block, EXT4_GET_BLOCKS_CREATE); - if (IS_ERR(bh)) - return bh; - inode->i_size += inode->i_sb->s_blocksize; - EXT4_I(inode)->i_disksize = inode->i_size; - BUFFER_TRACE(bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, bh); - if (err) { - brelse(bh); - ext4_std_error(inode->i_sb, err); - return ERR_PTR(err); - } - return bh; -} - -static int ext4_dx_csum_verify(struct inode *inode, - struct ext4_dir_entry *dirent); - -typedef enum { - EITHER, INDEX, DIRENT -} dirblock_type_t; - -#define ext4_read_dirblock(inode, block, type) \ - __ext4_read_dirblock((inode), (block), (type), __func__, __LINE__) - -static struct buffer_head *__ext4_read_dirblock(struct inode *inode, - ext4_lblk_t block, - dirblock_type_t type, - const char *func, - unsigned int line) -{ - struct buffer_head *bh; - struct ext4_dir_entry *dirent; - int is_dx_block = 0; - - bh = ext4_bread(NULL, inode, block, 0); - if (IS_ERR(bh)) { - __ext4_warning(inode->i_sb, func, line, - "inode #%lu: lblock %lu: comm %s: " - "error %ld reading directory block", - inode->i_ino, (unsigned long)block, - current->comm, PTR_ERR(bh)); - - return bh; - } - if (!bh) { - ext4_error_inode(inode, func, line, block, - "Directory hole found"); - return ERR_PTR(-EFSCORRUPTED); - } - dirent = (struct ext4_dir_entry *) bh->b_data; - /* Determine whether or not we have an index block */ - if (is_dx(inode)) { - if (block == 0) - is_dx_block = 1; - else if (ext4_rec_len_from_disk(dirent->rec_len, - inode->i_sb->s_blocksize) == - inode->i_sb->s_blocksize) - is_dx_block = 1; - } - if (!is_dx_block && type == INDEX) { - ext4_error_inode(inode, func, line, block, - "directory leaf block found instead of index block"); - return ERR_PTR(-EFSCORRUPTED); - } - if (!ext4_has_metadata_csum(inode->i_sb) || - buffer_verified(bh)) - return bh; - - /* - * An empty leaf block can get mistaken for a index block; for - * this reason, we can only check the index checksum when the - * caller is sure it should be an index block. - */ - if (is_dx_block && type == INDEX) { - if (ext4_dx_csum_verify(inode, dirent)) - set_buffer_verified(bh); - else { - ext4_error_inode(inode, func, line, block, - "Directory index failed checksum"); - brelse(bh); - return ERR_PTR(-EFSBADCRC); - } - } - if (!is_dx_block) { - if (ext4_dirent_csum_verify(inode, dirent)) - set_buffer_verified(bh); - else { - ext4_error_inode(inode, func, line, block, - "Directory block failed checksum"); - brelse(bh); - return ERR_PTR(-EFSBADCRC); - } - } - return bh; -} - -#ifndef assert -#define assert(test) J_ASSERT(test) -#endif - -#ifdef DX_DEBUG -#define dxtrace(command) command -#else -#define dxtrace(command) -#endif - -struct fake_dirent -{ - __le32 inode; - __le16 rec_len; - u8 name_len; - u8 file_type; -}; - -struct dx_countlimit -{ - __le16 limit; - __le16 count; -}; - -struct dx_entry -{ - __le32 hash; - __le32 block; -}; - -/* - * dx_root_info is laid out so that if it should somehow get overlaid by a - * dirent the two low bits of the hash version will be zero. Therefore, the - * hash version mod 4 should never be 0. Sincerely, the paranoia department. - */ - -struct dx_root -{ - struct fake_dirent dot; - char dot_name[4]; - struct fake_dirent dotdot; - char dotdot_name[4]; - struct dx_root_info - { - __le32 reserved_zero; - u8 hash_version; - u8 info_length; /* 8 */ - u8 indirect_levels; - u8 unused_flags; - } - info; - struct dx_entry entries[0]; -}; - -struct dx_node -{ - struct fake_dirent fake; - struct dx_entry entries[0]; -}; - - -struct dx_frame -{ - struct buffer_head *bh; - struct dx_entry *entries; - struct dx_entry *at; -}; - -struct dx_map_entry -{ - u32 hash; - u16 offs; - u16 size; -}; - -/* - * This goes at the end of each htree block. - */ -struct dx_tail { - u32 dt_reserved; - __le32 dt_checksum; /* crc32c(uuid+inum+dirblock) */ -}; - -static inline ext4_lblk_t dx_get_block(struct dx_entry *entry); -static void dx_set_block(struct dx_entry *entry, ext4_lblk_t value); -static inline unsigned dx_get_hash(struct dx_entry *entry); -static void dx_set_hash(struct dx_entry *entry, unsigned value); -static unsigned dx_get_count(struct dx_entry *entries); -static unsigned dx_get_limit(struct dx_entry *entries); -static void dx_set_count(struct dx_entry *entries, unsigned value); -static void dx_set_limit(struct dx_entry *entries, unsigned value); -static unsigned dx_root_limit(struct inode *dir, unsigned infosize); -static unsigned dx_node_limit(struct inode *dir); -static struct dx_frame *dx_probe(struct ext4_filename *fname, - struct inode *dir, - struct dx_hash_info *hinfo, - struct dx_frame *frame); -static void dx_release(struct dx_frame *frames); -static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de, - unsigned blocksize, struct dx_hash_info *hinfo, - struct dx_map_entry map[]); -static void dx_sort_map(struct dx_map_entry *map, unsigned count); -static struct ext4_dir_entry_2 *dx_move_dirents(char *from, char *to, - struct dx_map_entry *offsets, int count, unsigned blocksize); -static struct ext4_dir_entry_2* dx_pack_dirents(char *base, unsigned blocksize); -static void dx_insert_block(struct dx_frame *frame, - u32 hash, ext4_lblk_t block); -static int ext4_htree_next_block(struct inode *dir, __u32 hash, - struct dx_frame *frame, - struct dx_frame *frames, - __u32 *start_hash); -static struct buffer_head * ext4_dx_find_entry(struct inode *dir, - struct ext4_filename *fname, - struct ext4_dir_entry_2 **res_dir); -static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, - struct inode *dir, struct inode *inode); - -/* checksumming functions */ -void initialize_dirent_tail(struct ext4_dir_entry_tail *t, - unsigned int blocksize) -{ - memset(t, 0, sizeof(struct ext4_dir_entry_tail)); - t->det_rec_len = ext4_rec_len_to_disk( - sizeof(struct ext4_dir_entry_tail), blocksize); - t->det_reserved_ft = EXT4_FT_DIR_CSUM; -} - -/* Walk through a dirent block to find a checksum "dirent" at the tail */ -static struct ext4_dir_entry_tail *get_dirent_tail(struct inode *inode, - struct ext4_dir_entry *de) -{ - struct ext4_dir_entry_tail *t; - -#ifdef PARANOID - struct ext4_dir_entry *d, *top; - - d = de; - top = (struct ext4_dir_entry *)(((void *)de) + - (EXT4_BLOCK_SIZE(inode->i_sb) - - sizeof(struct ext4_dir_entry_tail))); - while (d < top && d->rec_len) - d = (struct ext4_dir_entry *)(((void *)d) + - le16_to_cpu(d->rec_len)); - - if (d != top) - return NULL; - - t = (struct ext4_dir_entry_tail *)d; -#else - t = EXT4_DIRENT_TAIL(de, EXT4_BLOCK_SIZE(inode->i_sb)); -#endif - - if (t->det_reserved_zero1 || - le16_to_cpu(t->det_rec_len) != sizeof(struct ext4_dir_entry_tail) || - t->det_reserved_zero2 || - t->det_reserved_ft != EXT4_FT_DIR_CSUM) - return NULL; - - return t; -} - -static __le32 ext4_dirent_csum(struct inode *inode, - struct ext4_dir_entry *dirent, int size) -{ - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - struct ext4_inode_info *ei = EXT4_I(inode); - __u32 csum; - - csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)dirent, size); - return cpu_to_le32(csum); -} - -#define warn_no_space_for_csum(inode) \ - __warn_no_space_for_csum((inode), __func__, __LINE__) - -static void __warn_no_space_for_csum(struct inode *inode, const char *func, - unsigned int line) -{ - __ext4_warning_inode(inode, func, line, - "No space for directory leaf checksum. Please run e2fsck -D."); -} - -int ext4_dirent_csum_verify(struct inode *inode, struct ext4_dir_entry *dirent) -{ - struct ext4_dir_entry_tail *t; - - if (!ext4_has_metadata_csum(inode->i_sb)) - return 1; - - t = get_dirent_tail(inode, dirent); - if (!t) { - warn_no_space_for_csum(inode); - return 0; - } - - if (t->det_checksum != ext4_dirent_csum(inode, dirent, - (void *)t - (void *)dirent)) - return 0; - - return 1; -} - -static void ext4_dirent_csum_set(struct inode *inode, - struct ext4_dir_entry *dirent) -{ - struct ext4_dir_entry_tail *t; - - if (!ext4_has_metadata_csum(inode->i_sb)) - return; - - t = get_dirent_tail(inode, dirent); - if (!t) { - warn_no_space_for_csum(inode); - return; - } - - t->det_checksum = ext4_dirent_csum(inode, dirent, - (void *)t - (void *)dirent); -} - -int ext4_handle_dirty_dirent_node(handle_t *handle, - struct inode *inode, - struct buffer_head *bh) -{ - ext4_dirent_csum_set(inode, (struct ext4_dir_entry *)bh->b_data); - return ext4_handle_dirty_metadata(handle, inode, bh); -} - -static struct dx_countlimit *get_dx_countlimit(struct inode *inode, - struct ext4_dir_entry *dirent, - int *offset) -{ - struct ext4_dir_entry *dp; - struct dx_root_info *root; - int count_offset; - - if (le16_to_cpu(dirent->rec_len) == EXT4_BLOCK_SIZE(inode->i_sb)) - count_offset = 8; - else if (le16_to_cpu(dirent->rec_len) == 12) { - dp = (struct ext4_dir_entry *)(((void *)dirent) + 12); - if (le16_to_cpu(dp->rec_len) != - EXT4_BLOCK_SIZE(inode->i_sb) - 12) - return NULL; - root = (struct dx_root_info *)(((void *)dp + 12)); - if (root->reserved_zero || - root->info_length != sizeof(struct dx_root_info)) - return NULL; - count_offset = 32; - } else - return NULL; - - if (offset) - *offset = count_offset; - return (struct dx_countlimit *)(((void *)dirent) + count_offset); -} - -static __le32 ext4_dx_csum(struct inode *inode, struct ext4_dir_entry *dirent, - int count_offset, int count, struct dx_tail *t) -{ - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - struct ext4_inode_info *ei = EXT4_I(inode); - __u32 csum; - int size; - __u32 dummy_csum = 0; - int offset = offsetof(struct dx_tail, dt_checksum); - - size = count_offset + (count * sizeof(struct dx_entry)); - csum = ext4_chksum(sbi, ei->i_csum_seed, (__u8 *)dirent, size); - csum = ext4_chksum(sbi, csum, (__u8 *)t, offset); - csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum, sizeof(dummy_csum)); - - return cpu_to_le32(csum); -} - -static int ext4_dx_csum_verify(struct inode *inode, - struct ext4_dir_entry *dirent) -{ - struct dx_countlimit *c; - struct dx_tail *t; - int count_offset, limit, count; - - if (!ext4_has_metadata_csum(inode->i_sb)) - return 1; - - c = get_dx_countlimit(inode, dirent, &count_offset); - if (!c) { - EXT4_ERROR_INODE(inode, "dir seems corrupt? Run e2fsck -D."); - return 0; - } - limit = le16_to_cpu(c->limit); - count = le16_to_cpu(c->count); - if (count_offset + (limit * sizeof(struct dx_entry)) > - EXT4_BLOCK_SIZE(inode->i_sb) - sizeof(struct dx_tail)) { - warn_no_space_for_csum(inode); - return 0; - } - t = (struct dx_tail *)(((struct dx_entry *)c) + limit); - - if (t->dt_checksum != ext4_dx_csum(inode, dirent, count_offset, - count, t)) - return 0; - return 1; -} - -static void ext4_dx_csum_set(struct inode *inode, struct ext4_dir_entry *dirent) -{ - struct dx_countlimit *c; - struct dx_tail *t; - int count_offset, limit, count; - - if (!ext4_has_metadata_csum(inode->i_sb)) - return; - - c = get_dx_countlimit(inode, dirent, &count_offset); - if (!c) { - EXT4_ERROR_INODE(inode, "dir seems corrupt? Run e2fsck -D."); - return; - } - limit = le16_to_cpu(c->limit); - count = le16_to_cpu(c->count); - if (count_offset + (limit * sizeof(struct dx_entry)) > - EXT4_BLOCK_SIZE(inode->i_sb) - sizeof(struct dx_tail)) { - warn_no_space_for_csum(inode); - return; - } - t = (struct dx_tail *)(((struct dx_entry *)c) + limit); - - t->dt_checksum = ext4_dx_csum(inode, dirent, count_offset, count, t); -} - -static inline int ext4_handle_dirty_dx_node(handle_t *handle, - struct inode *inode, - struct buffer_head *bh) -{ - ext4_dx_csum_set(inode, (struct ext4_dir_entry *)bh->b_data); - return ext4_handle_dirty_metadata(handle, inode, bh); -} - -/* - * p is at least 6 bytes before the end of page - */ -static inline struct ext4_dir_entry_2 * -ext4_next_entry(struct ext4_dir_entry_2 *p, unsigned long blocksize) -{ - return (struct ext4_dir_entry_2 *)((char *)p + - ext4_rec_len_from_disk(p->rec_len, blocksize)); -} - -/* - * Future: use high four bits of block for coalesce-on-delete flags - * Mask them off for now. - */ - -static inline ext4_lblk_t dx_get_block(struct dx_entry *entry) -{ - return le32_to_cpu(entry->block) & 0x00ffffff; -} - -static inline void dx_set_block(struct dx_entry *entry, ext4_lblk_t value) -{ - entry->block = cpu_to_le32(value); -} - -static inline unsigned dx_get_hash(struct dx_entry *entry) -{ - return le32_to_cpu(entry->hash); -} - -static inline void dx_set_hash(struct dx_entry *entry, unsigned value) -{ - entry->hash = cpu_to_le32(value); -} - -static inline unsigned dx_get_count(struct dx_entry *entries) -{ - return le16_to_cpu(((struct dx_countlimit *) entries)->count); -} - -static inline unsigned dx_get_limit(struct dx_entry *entries) -{ - return le16_to_cpu(((struct dx_countlimit *) entries)->limit); -} - -static inline void dx_set_count(struct dx_entry *entries, unsigned value) -{ - ((struct dx_countlimit *) entries)->count = cpu_to_le16(value); -} - -static inline void dx_set_limit(struct dx_entry *entries, unsigned value) -{ - ((struct dx_countlimit *) entries)->limit = cpu_to_le16(value); -} - -static inline unsigned dx_root_limit(struct inode *dir, unsigned infosize) -{ - unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(1) - - EXT4_DIR_REC_LEN(2) - infosize; - - if (ext4_has_metadata_csum(dir->i_sb)) - entry_space -= sizeof(struct dx_tail); - return entry_space / sizeof(struct dx_entry); -} - -static inline unsigned dx_node_limit(struct inode *dir) -{ - unsigned entry_space = dir->i_sb->s_blocksize - EXT4_DIR_REC_LEN(0); - - if (ext4_has_metadata_csum(dir->i_sb)) - entry_space -= sizeof(struct dx_tail); - return entry_space / sizeof(struct dx_entry); -} - -/* - * Debug - */ -#ifdef DX_DEBUG -static void dx_show_index(char * label, struct dx_entry *entries) -{ - int i, n = dx_get_count (entries); - printk(KERN_DEBUG "%s index", label); - for (i = 0; i < n; i++) { - printk(KERN_CONT " %x->%lu", - i ? dx_get_hash(entries + i) : 0, - (unsigned long)dx_get_block(entries + i)); - } - printk(KERN_CONT "\n"); -} - -struct stats -{ - unsigned names; - unsigned space; - unsigned bcount; -}; - -static struct stats dx_show_leaf(struct inode *dir, - struct dx_hash_info *hinfo, - struct ext4_dir_entry_2 *de, - int size, int show_names) -{ - unsigned names = 0, space = 0; - char *base = (char *) de; - struct dx_hash_info h = *hinfo; - - printk("names: "); - while ((char *) de < base + size) - { - if (de->inode) - { - if (show_names) - { -#ifdef CONFIG_EXT4_FS_ENCRYPTION - int len; - char *name; - struct fscrypt_str fname_crypto_str = - FSTR_INIT(NULL, 0); - int res = 0; - - name = de->name; - len = de->name_len; - if (ext4_encrypted_inode(dir)) - res = fscrypt_get_encryption_info(dir); - if (res) { - printk(KERN_WARNING "Error setting up" - " fname crypto: %d\n", res); - } - if (!fscrypt_has_encryption_key(dir)) { - /* Directory is not encrypted */ - ext4fs_dirhash(de->name, - de->name_len, &h); - printk("%*.s:(U)%x.%u ", len, - name, h.hash, - (unsigned) ((char *) de - - base)); - } else { - struct fscrypt_str de_name = - FSTR_INIT(name, len); - - /* Directory is encrypted */ - res = fscrypt_fname_alloc_buffer( - dir, len, - &fname_crypto_str); - if (res) - printk(KERN_WARNING "Error " - "allocating crypto " - "buffer--skipping " - "crypto\n"); - res = fscrypt_fname_disk_to_usr(dir, - 0, 0, &de_name, - &fname_crypto_str); - if (res) { - printk(KERN_WARNING "Error " - "converting filename " - "from disk to usr" - "\n"); - name = "??"; - len = 2; - } else { - name = fname_crypto_str.name; - len = fname_crypto_str.len; - } - ext4fs_dirhash(de->name, de->name_len, - &h); - printk("%*.s:(E)%x.%u ", len, name, - h.hash, (unsigned) ((char *) de - - base)); - fscrypt_fname_free_buffer( - &fname_crypto_str); - } -#else - int len = de->name_len; - char *name = de->name; - ext4fs_dirhash(de->name, de->name_len, &h); - printk("%*.s:%x.%u ", len, name, h.hash, - (unsigned) ((char *) de - base)); -#endif - } - space += EXT4_DIR_REC_LEN(de->name_len); - names++; - } - de = ext4_next_entry(de, size); - } - printk(KERN_CONT "(%i)\n", names); - return (struct stats) { names, space, 1 }; -} - -struct stats dx_show_entries(struct dx_hash_info *hinfo, struct inode *dir, - struct dx_entry *entries, int levels) -{ - unsigned blocksize = dir->i_sb->s_blocksize; - unsigned count = dx_get_count(entries), names = 0, space = 0, i; - unsigned bcount = 0; - struct buffer_head *bh; - printk("%i indexed blocks...\n", count); - for (i = 0; i < count; i++, entries++) - { - ext4_lblk_t block = dx_get_block(entries); - ext4_lblk_t hash = i ? dx_get_hash(entries): 0; - u32 range = i < count - 1? (dx_get_hash(entries + 1) - hash): ~hash; - struct stats stats; - printk("%s%3u:%03u hash %8x/%8x ",levels?"":" ", i, block, hash, range); - bh = ext4_bread(NULL,dir, block, 0); - if (!bh || IS_ERR(bh)) - continue; - stats = levels? - dx_show_entries(hinfo, dir, ((struct dx_node *) bh->b_data)->entries, levels - 1): - dx_show_leaf(dir, hinfo, (struct ext4_dir_entry_2 *) - bh->b_data, blocksize, 0); - names += stats.names; - space += stats.space; - bcount += stats.bcount; - brelse(bh); - } - if (bcount) - printk(KERN_DEBUG "%snames %u, fullness %u (%u%%)\n", - levels ? "" : " ", names, space/bcount, - (space/bcount)*100/blocksize); - return (struct stats) { names, space, bcount}; -} -#endif /* DX_DEBUG */ - -/* - * Probe for a directory leaf block to search. - * - * dx_probe can return ERR_BAD_DX_DIR, which means there was a format - * error in the directory index, and the caller should fall back to - * searching the directory normally. The callers of dx_probe **MUST** - * check for this error code, and make sure it never gets reflected - * back to userspace. - */ -static struct dx_frame * -dx_probe(struct ext4_filename *fname, struct inode *dir, - struct dx_hash_info *hinfo, struct dx_frame *frame_in) -{ - unsigned count, indirect; - struct dx_entry *at, *entries, *p, *q, *m; - struct dx_root *root; - struct dx_frame *frame = frame_in; - struct dx_frame *ret_err = ERR_PTR(ERR_BAD_DX_DIR); - u32 hash; - - frame->bh = ext4_read_dirblock(dir, 0, INDEX); - if (IS_ERR(frame->bh)) - return (struct dx_frame *) frame->bh; - - root = (struct dx_root *) frame->bh->b_data; - if (root->info.hash_version != DX_HASH_TEA && - root->info.hash_version != DX_HASH_HALF_MD4 && - root->info.hash_version != DX_HASH_LEGACY) { - ext4_warning_inode(dir, "Unrecognised inode hash code %u", - root->info.hash_version); - goto fail; - } - if (fname) - hinfo = &fname->hinfo; - hinfo->hash_version = root->info.hash_version; - if (hinfo->hash_version <= DX_HASH_TEA) - hinfo->hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; - hinfo->seed = EXT4_SB(dir->i_sb)->s_hash_seed; - if (fname && fname_name(fname)) - ext4fs_dirhash(fname_name(fname), fname_len(fname), hinfo); - hash = hinfo->hash; - - if (root->info.unused_flags & 1) { - ext4_warning_inode(dir, "Unimplemented hash flags: %#06x", - root->info.unused_flags); - goto fail; - } - - indirect = root->info.indirect_levels; - if (indirect > 1) { - ext4_warning_inode(dir, "Unimplemented hash depth: %#06x", - root->info.indirect_levels); - goto fail; - } - - entries = (struct dx_entry *)(((char *)&root->info) + - root->info.info_length); - - if (dx_get_limit(entries) != dx_root_limit(dir, - root->info.info_length)) { - ext4_warning_inode(dir, "dx entry: limit %u != root limit %u", - dx_get_limit(entries), - dx_root_limit(dir, root->info.info_length)); - goto fail; - } - - dxtrace(printk("Look up %x", hash)); - while (1) { - count = dx_get_count(entries); - if (!count || count > dx_get_limit(entries)) { - ext4_warning_inode(dir, - "dx entry: count %u beyond limit %u", - count, dx_get_limit(entries)); - goto fail; - } - - p = entries + 1; - q = entries + count - 1; - while (p <= q) { - m = p + (q - p) / 2; - dxtrace(printk(KERN_CONT ".")); - if (dx_get_hash(m) > hash) - q = m - 1; - else - p = m + 1; - } - - if (0) { // linear search cross check - unsigned n = count - 1; - at = entries; - while (n--) - { - dxtrace(printk(KERN_CONT ",")); - if (dx_get_hash(++at) > hash) - { - at--; - break; - } - } - assert (at == p - 1); - } - - at = p - 1; - dxtrace(printk(KERN_CONT " %x->%u\n", - at == entries ? 0 : dx_get_hash(at), - dx_get_block(at))); - frame->entries = entries; - frame->at = at; - if (!indirect--) - return frame; - frame++; - frame->bh = ext4_read_dirblock(dir, dx_get_block(at), INDEX); - if (IS_ERR(frame->bh)) { - ret_err = (struct dx_frame *) frame->bh; - frame->bh = NULL; - goto fail; - } - entries = ((struct dx_node *) frame->bh->b_data)->entries; - - if (dx_get_limit(entries) != dx_node_limit(dir)) { - ext4_warning_inode(dir, - "dx entry: limit %u != node limit %u", - dx_get_limit(entries), dx_node_limit(dir)); - goto fail; - } - } -fail: - while (frame >= frame_in) { - brelse(frame->bh); - frame--; - } - - if (ret_err == ERR_PTR(ERR_BAD_DX_DIR)) - ext4_warning_inode(dir, - "Corrupt directory, running e2fsck is recommended"); - return ret_err; -} - -static void dx_release(struct dx_frame *frames) -{ - if (frames[0].bh == NULL) - return; - - if (((struct dx_root *)frames[0].bh->b_data)->info.indirect_levels) - brelse(frames[1].bh); - brelse(frames[0].bh); -} - -/* - * This function increments the frame pointer to search the next leaf - * block, and reads in the necessary intervening nodes if the search - * should be necessary. Whether or not the search is necessary is - * controlled by the hash parameter. If the hash value is even, then - * the search is only continued if the next block starts with that - * hash value. This is used if we are searching for a specific file. - * - * If the hash value is HASH_NB_ALWAYS, then always go to the next block. - * - * This function returns 1 if the caller should continue to search, - * or 0 if it should not. If there is an error reading one of the - * index blocks, it will a negative error code. - * - * If start_hash is non-null, it will be filled in with the starting - * hash of the next page. - */ -static int ext4_htree_next_block(struct inode *dir, __u32 hash, - struct dx_frame *frame, - struct dx_frame *frames, - __u32 *start_hash) -{ - struct dx_frame *p; - struct buffer_head *bh; - int num_frames = 0; - __u32 bhash; - - p = frame; - /* - * Find the next leaf page by incrementing the frame pointer. - * If we run out of entries in the interior node, loop around and - * increment pointer in the parent node. When we break out of - * this loop, num_frames indicates the number of interior - * nodes need to be read. - */ - while (1) { - if (++(p->at) < p->entries + dx_get_count(p->entries)) - break; - if (p == frames) - return 0; - num_frames++; - p--; - } - - /* - * If the hash is 1, then continue only if the next page has a - * continuation hash of any value. This is used for readdir - * handling. Otherwise, check to see if the hash matches the - * desired contiuation hash. If it doesn't, return since - * there's no point to read in the successive index pages. - */ - bhash = dx_get_hash(p->at); - if (start_hash) - *start_hash = bhash; - if ((hash & 1) == 0) { - if ((bhash & ~1) != hash) - return 0; - } - /* - * If the hash is HASH_NB_ALWAYS, we always go to the next - * block so no check is necessary - */ - while (num_frames--) { - bh = ext4_read_dirblock(dir, dx_get_block(p->at), INDEX); - if (IS_ERR(bh)) - return PTR_ERR(bh); - p++; - brelse(p->bh); - p->bh = bh; - p->at = p->entries = ((struct dx_node *) bh->b_data)->entries; - } - return 1; -} - - -/* - * This function fills a red-black tree with information from a - * directory block. It returns the number directory entries loaded - * into the tree. If there is an error it is returned in err. - */ -static int htree_dirblock_to_tree(struct file *dir_file, - struct inode *dir, ext4_lblk_t block, - struct dx_hash_info *hinfo, - __u32 start_hash, __u32 start_minor_hash) -{ - struct buffer_head *bh; - struct ext4_dir_entry_2 *de, *top; - int err = 0, count = 0; - struct fscrypt_str fname_crypto_str = FSTR_INIT(NULL, 0), tmp_str; - - dxtrace(printk(KERN_INFO "In htree dirblock_to_tree: block %lu\n", - (unsigned long)block)); - bh = ext4_read_dirblock(dir, block, DIRENT); - if (IS_ERR(bh)) - return PTR_ERR(bh); - - de = (struct ext4_dir_entry_2 *) bh->b_data; - top = (struct ext4_dir_entry_2 *) ((char *) de + - dir->i_sb->s_blocksize - - EXT4_DIR_REC_LEN(0)); -#ifdef CONFIG_EXT4_FS_ENCRYPTION - /* Check if the directory is encrypted */ - if (ext4_encrypted_inode(dir)) { - err = fscrypt_get_encryption_info(dir); - if (err < 0) { - brelse(bh); - return err; - } - err = fscrypt_fname_alloc_buffer(dir, EXT4_NAME_LEN, - &fname_crypto_str); - if (err < 0) { - brelse(bh); - return err; - } - } -#endif - for (; de < top; de = ext4_next_entry(de, dir->i_sb->s_blocksize)) { - if (ext4_check_dir_entry(dir, NULL, de, bh, - bh->b_data, bh->b_size, - (block<i_sb)) - + ((char *)de - bh->b_data))) { - /* silently ignore the rest of the block */ - break; - } - ext4fs_dirhash(de->name, de->name_len, hinfo); - if ((hinfo->hash < start_hash) || - ((hinfo->hash == start_hash) && - (hinfo->minor_hash < start_minor_hash))) - continue; - if (de->inode == 0) - continue; - if (!ext4_encrypted_inode(dir)) { - tmp_str.name = de->name; - tmp_str.len = de->name_len; - err = ext4_htree_store_dirent(dir_file, - hinfo->hash, hinfo->minor_hash, de, - &tmp_str); - } else { - int save_len = fname_crypto_str.len; - struct fscrypt_str de_name = FSTR_INIT(de->name, - de->name_len); - - /* Directory is encrypted */ - err = fscrypt_fname_disk_to_usr(dir, hinfo->hash, - hinfo->minor_hash, &de_name, - &fname_crypto_str); - if (err) { - count = err; - goto errout; - } - err = ext4_htree_store_dirent(dir_file, - hinfo->hash, hinfo->minor_hash, de, - &fname_crypto_str); - fname_crypto_str.len = save_len; - } - if (err != 0) { - count = err; - goto errout; - } - count++; - } -errout: - brelse(bh); -#ifdef CONFIG_EXT4_FS_ENCRYPTION - fscrypt_fname_free_buffer(&fname_crypto_str); -#endif - return count; -} - - -/* - * This function fills a red-black tree with information from a - * directory. We start scanning the directory in hash order, starting - * at start_hash and start_minor_hash. - * - * This function returns the number of entries inserted into the tree, - * or a negative error code. - */ -int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash, - __u32 start_minor_hash, __u32 *next_hash) -{ - struct dx_hash_info hinfo; - struct ext4_dir_entry_2 *de; - struct dx_frame frames[2], *frame; - struct inode *dir; - ext4_lblk_t block; - int count = 0; - int ret, err; - __u32 hashval; - struct fscrypt_str tmp_str; - - dxtrace(printk(KERN_DEBUG "In htree_fill_tree, start hash: %x:%x\n", - start_hash, start_minor_hash)); - dir = file_inode(dir_file); - if (!(ext4_test_inode_flag(dir, EXT4_INODE_INDEX))) { - hinfo.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version; - if (hinfo.hash_version <= DX_HASH_TEA) - hinfo.hash_version += - EXT4_SB(dir->i_sb)->s_hash_unsigned; - hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; - if (ext4_has_inline_data(dir)) { - int has_inline_data = 1; - count = htree_inlinedir_to_tree(dir_file, dir, 0, - &hinfo, start_hash, - start_minor_hash, - &has_inline_data); - if (has_inline_data) { - *next_hash = ~0; - return count; - } - } - count = htree_dirblock_to_tree(dir_file, dir, 0, &hinfo, - start_hash, start_minor_hash); - *next_hash = ~0; - return count; - } - hinfo.hash = start_hash; - hinfo.minor_hash = 0; - frame = dx_probe(NULL, dir, &hinfo, frames); - if (IS_ERR(frame)) - return PTR_ERR(frame); - - /* Add '.' and '..' from the htree header */ - if (!start_hash && !start_minor_hash) { - de = (struct ext4_dir_entry_2 *) frames[0].bh->b_data; - tmp_str.name = de->name; - tmp_str.len = de->name_len; - err = ext4_htree_store_dirent(dir_file, 0, 0, - de, &tmp_str); - if (err != 0) - goto errout; - count++; - } - if (start_hash < 2 || (start_hash ==2 && start_minor_hash==0)) { - de = (struct ext4_dir_entry_2 *) frames[0].bh->b_data; - de = ext4_next_entry(de, dir->i_sb->s_blocksize); - tmp_str.name = de->name; - tmp_str.len = de->name_len; - err = ext4_htree_store_dirent(dir_file, 2, 0, - de, &tmp_str); - if (err != 0) - goto errout; - count++; - } - - while (1) { - if (fatal_signal_pending(current)) { - err = -ERESTARTSYS; - goto errout; - } - cond_resched(); - block = dx_get_block(frame->at); - ret = htree_dirblock_to_tree(dir_file, dir, block, &hinfo, - start_hash, start_minor_hash); - if (ret < 0) { - err = ret; - goto errout; - } - count += ret; - hashval = ~0; - ret = ext4_htree_next_block(dir, HASH_NB_ALWAYS, - frame, frames, &hashval); - *next_hash = hashval; - if (ret < 0) { - err = ret; - goto errout; - } - /* - * Stop if: (a) there are no more entries, or - * (b) we have inserted at least one entry and the - * next hash value is not a continuation - */ - if ((ret == 0) || - (count && ((hashval & 1) == 0))) - break; - } - dx_release(frames); - dxtrace(printk(KERN_DEBUG "Fill tree: returned %d entries, " - "next hash: %x\n", count, *next_hash)); - return count; -errout: - dx_release(frames); - return (err); -} - -static inline int search_dirblock(struct buffer_head *bh, - struct inode *dir, - struct ext4_filename *fname, - const struct qstr *d_name, - unsigned int offset, - struct ext4_dir_entry_2 **res_dir) -{ - return ext4_search_dir(bh, bh->b_data, dir->i_sb->s_blocksize, dir, - fname, d_name, offset, res_dir); -} - -/* - * Directory block splitting, compacting - */ - -/* - * Create map of hash values, offsets, and sizes, stored at end of block. - * Returns number of entries mapped. - */ -static int dx_make_map(struct inode *dir, struct ext4_dir_entry_2 *de, - unsigned blocksize, struct dx_hash_info *hinfo, - struct dx_map_entry *map_tail) -{ - int count = 0; - char *base = (char *) de; - struct dx_hash_info h = *hinfo; - - while ((char *) de < base + blocksize) { - if (de->name_len && de->inode) { - ext4fs_dirhash(de->name, de->name_len, &h); - map_tail--; - map_tail->hash = h.hash; - map_tail->offs = ((char *) de - base)>>2; - map_tail->size = le16_to_cpu(de->rec_len); - count++; - cond_resched(); - } - /* XXX: do we need to check rec_len == 0 case? -Chris */ - de = ext4_next_entry(de, blocksize); - } - return count; -} - -/* Sort map by hash value */ -static void dx_sort_map (struct dx_map_entry *map, unsigned count) -{ - struct dx_map_entry *p, *q, *top = map + count - 1; - int more; - /* Combsort until bubble sort doesn't suck */ - while (count > 2) { - count = count*10/13; - if (count - 9 < 2) /* 9, 10 -> 11 */ - count = 11; - for (p = top, q = p - count; q >= map; p--, q--) - if (p->hash < q->hash) - swap(*p, *q); - } - /* Garden variety bubble sort */ - do { - more = 0; - q = top; - while (q-- > map) { - if (q[1].hash >= q[0].hash) - continue; - swap(*(q+1), *q); - more = 1; - } - } while(more); -} - -static void dx_insert_block(struct dx_frame *frame, u32 hash, ext4_lblk_t block) -{ - struct dx_entry *entries = frame->entries; - struct dx_entry *old = frame->at, *new = old + 1; - int count = dx_get_count(entries); - - assert(count < dx_get_limit(entries)); - assert(old < entries + count); - memmove(new + 1, new, (char *)(entries + count) - (char *)(new)); - dx_set_hash(new, hash); - dx_set_block(new, block); - dx_set_count(entries, count + 1); -} - -/* - * NOTE! unlike strncmp, ext4_match returns 1 for success, 0 for failure. - * - * `len <= EXT4_NAME_LEN' is guaranteed by caller. - * `de != NULL' is guaranteed by caller. - */ -static inline int ext4_match(struct ext4_filename *fname, - struct ext4_dir_entry_2 *de) -{ - const void *name = fname_name(fname); - u32 len = fname_len(fname); - - if (!de->inode) - return 0; - -#ifdef CONFIG_EXT4_FS_ENCRYPTION - if (unlikely(!name)) { - if (fname->usr_fname->name[0] == '_') { - int ret; - if (de->name_len < 16) - return 0; - ret = memcmp(de->name + de->name_len - 16, - fname->crypto_buf.name + 8, 16); - return (ret == 0) ? 1 : 0; - } - name = fname->crypto_buf.name; - len = fname->crypto_buf.len; - } -#endif - if (de->name_len != len) - return 0; - return (memcmp(de->name, name, len) == 0) ? 1 : 0; -} - -/* - * Returns 0 if not found, -1 on failure, and 1 on success - */ -int ext4_search_dir(struct buffer_head *bh, char *search_buf, int buf_size, - struct inode *dir, struct ext4_filename *fname, - const struct qstr *d_name, - unsigned int offset, struct ext4_dir_entry_2 **res_dir) -{ - struct ext4_dir_entry_2 * de; - char * dlimit; - int de_len; - int res; - - de = (struct ext4_dir_entry_2 *)search_buf; - dlimit = search_buf + buf_size; - while ((char *) de < dlimit) { - /* this code is executed quadratically often */ - /* do minimal checking `by hand' */ - if ((char *) de + de->name_len <= dlimit) { - res = ext4_match(fname, de); - if (res < 0) { - res = -1; - goto return_result; - } - if (res > 0) { - /* found a match - just to be sure, do - * a full check */ - if (ext4_check_dir_entry(dir, NULL, de, bh, - bh->b_data, - bh->b_size, offset)) { - res = -1; - goto return_result; - } - *res_dir = de; - res = 1; - goto return_result; - } - - } - /* prevent looping on a bad block */ - de_len = ext4_rec_len_from_disk(de->rec_len, - dir->i_sb->s_blocksize); - if (de_len <= 0) { - res = -1; - goto return_result; - } - offset += de_len; - de = (struct ext4_dir_entry_2 *) ((char *) de + de_len); - } - - res = 0; -return_result: - return res; -} - -static int is_dx_internal_node(struct inode *dir, ext4_lblk_t block, - struct ext4_dir_entry *de) -{ - struct super_block *sb = dir->i_sb; - - if (!is_dx(dir)) - return 0; - if (block == 0) - return 1; - if (de->inode == 0 && - ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize) == - sb->s_blocksize) - return 1; - return 0; -} - -/* - * ext4_find_entry() - * - * finds an entry in the specified directory with the wanted name. It - * returns the cache buffer in which the entry was found, and the entry - * itself (as a parameter - res_dir). It does NOT read the inode of the - * entry - you'll have to do that yourself if you want to. - * - * The returned buffer_head has ->b_count elevated. The caller is expected - * to brelse() it when appropriate. - */ -static struct buffer_head * ext4_find_entry (struct inode *dir, - const struct qstr *d_name, - struct ext4_dir_entry_2 **res_dir, - int *inlined) -{ - struct super_block *sb; - struct buffer_head *bh_use[NAMEI_RA_SIZE]; - struct buffer_head *bh, *ret = NULL; - ext4_lblk_t start, block, b; - const u8 *name = d_name->name; - int ra_max = 0; /* Number of bh's in the readahead - buffer, bh_use[] */ - int ra_ptr = 0; /* Current index into readahead - buffer */ - int num = 0; - ext4_lblk_t nblocks; - int i, namelen, retval; - struct ext4_filename fname; - - *res_dir = NULL; - sb = dir->i_sb; - namelen = d_name->len; - if (namelen > EXT4_NAME_LEN) - return NULL; - - retval = ext4_fname_setup_filename(dir, d_name, 1, &fname); - if (retval) - return ERR_PTR(retval); - - if (ext4_has_inline_data(dir)) { - int has_inline_data = 1; - ret = ext4_find_inline_entry(dir, &fname, d_name, res_dir, - &has_inline_data); - if (has_inline_data) { - if (inlined) - *inlined = 1; - goto cleanup_and_exit; - } - } - - if ((namelen <= 2) && (name[0] == '.') && - (name[1] == '.' || name[1] == '\0')) { - /* - * "." or ".." will only be in the first block - * NFS may look up ".."; "." should be handled by the VFS - */ - block = start = 0; - nblocks = 1; - goto restart; - } - if (is_dx(dir)) { - ret = ext4_dx_find_entry(dir, &fname, res_dir); - /* - * On success, or if the error was file not found, - * return. Otherwise, fall back to doing a search the - * old fashioned way. - */ - if (!IS_ERR(ret) || PTR_ERR(ret) != ERR_BAD_DX_DIR) - goto cleanup_and_exit; - dxtrace(printk(KERN_DEBUG "ext4_find_entry: dx failed, " - "falling back\n")); - } - nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb); - start = EXT4_I(dir)->i_dir_start_lookup; - if (start >= nblocks) - start = 0; - block = start; -restart: - do { - /* - * We deal with the read-ahead logic here. - */ - if (ra_ptr >= ra_max) { - /* Refill the readahead buffer */ - ra_ptr = 0; - b = block; - for (ra_max = 0; ra_max < NAMEI_RA_SIZE; ra_max++) { - /* - * Terminate if we reach the end of the - * directory and must wrap, or if our - * search has finished at this block. - */ - if (b >= nblocks || (num && block == start)) { - bh_use[ra_max] = NULL; - break; - } - num++; - bh = ext4_getblk(NULL, dir, b++, 0); - if (IS_ERR(bh)) { - if (ra_max == 0) { - ret = bh; - goto cleanup_and_exit; - } - break; - } - bh_use[ra_max] = bh; - if (bh) - ll_rw_block(REQ_OP_READ, - REQ_META | REQ_PRIO, - 1, &bh); - } - } - if ((bh = bh_use[ra_ptr++]) == NULL) - goto next; - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) { - /* read error, skip block & hope for the best */ - EXT4_ERROR_INODE(dir, "reading directory lblock %lu", - (unsigned long) block); - brelse(bh); - goto next; - } - if (!buffer_verified(bh) && - !is_dx_internal_node(dir, block, - (struct ext4_dir_entry *)bh->b_data) && - !ext4_dirent_csum_verify(dir, - (struct ext4_dir_entry *)bh->b_data)) { - EXT4_ERROR_INODE(dir, "checksumming directory " - "block %lu", (unsigned long)block); - brelse(bh); - goto next; - } - set_buffer_verified(bh); - i = search_dirblock(bh, dir, &fname, d_name, - block << EXT4_BLOCK_SIZE_BITS(sb), res_dir); - if (i == 1) { - EXT4_I(dir)->i_dir_start_lookup = block; - ret = bh; - goto cleanup_and_exit; - } else { - brelse(bh); - if (i < 0) - goto cleanup_and_exit; - } - next: - if (++block >= nblocks) - block = 0; - } while (block != start); - - /* - * If the directory has grown while we were searching, then - * search the last part of the directory before giving up. - */ - block = nblocks; - nblocks = dir->i_size >> EXT4_BLOCK_SIZE_BITS(sb); - if (block < nblocks) { - start = 0; - goto restart; - } - -cleanup_and_exit: - /* Clean up the read-ahead blocks */ - for (; ra_ptr < ra_max; ra_ptr++) - brelse(bh_use[ra_ptr]); - ext4_fname_free_filename(&fname); - return ret; -} - -static struct buffer_head * ext4_dx_find_entry(struct inode *dir, - struct ext4_filename *fname, - struct ext4_dir_entry_2 **res_dir) -{ - struct super_block * sb = dir->i_sb; - struct dx_frame frames[2], *frame; - const struct qstr *d_name = fname->usr_fname; - struct buffer_head *bh; - ext4_lblk_t block; - int retval; - -#ifdef CONFIG_EXT4_FS_ENCRYPTION - *res_dir = NULL; -#endif - frame = dx_probe(fname, dir, NULL, frames); - if (IS_ERR(frame)) - return (struct buffer_head *) frame; - do { - block = dx_get_block(frame->at); - bh = ext4_read_dirblock(dir, block, DIRENT); - if (IS_ERR(bh)) - goto errout; - - retval = search_dirblock(bh, dir, fname, d_name, - block << EXT4_BLOCK_SIZE_BITS(sb), - res_dir); - if (retval == 1) - goto success; - brelse(bh); - if (retval == -1) { - bh = ERR_PTR(ERR_BAD_DX_DIR); - goto errout; - } - - /* Check to see if we should continue to search */ - retval = ext4_htree_next_block(dir, fname->hinfo.hash, frame, - frames, NULL); - if (retval < 0) { - ext4_warning_inode(dir, - "error %d reading directory index block", - retval); - bh = ERR_PTR(retval); - goto errout; - } - } while (retval == 1); - - bh = NULL; -errout: - dxtrace(printk(KERN_DEBUG "%s not found\n", d_name->name)); -success: - dx_release(frames); - return bh; -} - -static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) -{ - struct inode *inode; - struct ext4_dir_entry_2 *de; - struct buffer_head *bh; - - if (ext4_encrypted_inode(dir)) { - int res = fscrypt_get_encryption_info(dir); - - /* - * DCACHE_ENCRYPTED_WITH_KEY is set if the dentry is - * created while the directory was encrypted and we - * have access to the key. - */ - if (fscrypt_has_encryption_key(dir)) - fscrypt_set_encrypted_dentry(dentry); - fscrypt_set_d_op(dentry); - if (res && res != -ENOKEY) - return ERR_PTR(res); - } - - if (dentry->d_name.len > EXT4_NAME_LEN) - return ERR_PTR(-ENAMETOOLONG); - - bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL); - if (IS_ERR(bh)) - return (struct dentry *) bh; - inode = NULL; - if (bh) { - __u32 ino = le32_to_cpu(de->inode); - brelse(bh); - if (!ext4_valid_inum(dir->i_sb, ino)) { - EXT4_ERROR_INODE(dir, "bad inode number: %u", ino); - return ERR_PTR(-EFSCORRUPTED); - } - if (unlikely(ino == dir->i_ino)) { - EXT4_ERROR_INODE(dir, "'%pd' linked to parent dir", - dentry); - return ERR_PTR(-EFSCORRUPTED); - } - inode = ext4_iget_normal(dir->i_sb, ino); - if (inode == ERR_PTR(-ESTALE)) { - EXT4_ERROR_INODE(dir, - "deleted inode referenced: %u", - ino); - return ERR_PTR(-EFSCORRUPTED); - } - if (!IS_ERR(inode) && ext4_encrypted_inode(dir) && - (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)) && - !fscrypt_has_permitted_context(dir, inode)) { - int nokey = ext4_encrypted_inode(inode) && - !fscrypt_has_encryption_key(inode); - iput(inode); - if (nokey) - return ERR_PTR(-ENOKEY); - ext4_warning(inode->i_sb, - "Inconsistent encryption contexts: %lu/%lu", - (unsigned long) dir->i_ino, - (unsigned long) inode->i_ino); - return ERR_PTR(-EPERM); - } - } - return d_splice_alias(inode, dentry); -} - - -struct dentry *ext4_get_parent(struct dentry *child) -{ - __u32 ino; - static const struct qstr dotdot = QSTR_INIT("..", 2); - struct ext4_dir_entry_2 * de; - struct buffer_head *bh; - - bh = ext4_find_entry(d_inode(child), &dotdot, &de, NULL); - if (IS_ERR(bh)) - return (struct dentry *) bh; - if (!bh) - return ERR_PTR(-ENOENT); - ino = le32_to_cpu(de->inode); - brelse(bh); - - if (!ext4_valid_inum(child->d_sb, ino)) { - EXT4_ERROR_INODE(d_inode(child), - "bad parent inode number: %u", ino); - return ERR_PTR(-EFSCORRUPTED); - } - - return d_obtain_alias(ext4_iget_normal(child->d_sb, ino)); -} - -/* - * Move count entries from end of map between two memory locations. - * Returns pointer to last entry moved. - */ -static struct ext4_dir_entry_2 * -dx_move_dirents(char *from, char *to, struct dx_map_entry *map, int count, - unsigned blocksize) -{ - unsigned rec_len = 0; - - while (count--) { - struct ext4_dir_entry_2 *de = (struct ext4_dir_entry_2 *) - (from + (map->offs<<2)); - rec_len = EXT4_DIR_REC_LEN(de->name_len); - memcpy (to, de, rec_len); - ((struct ext4_dir_entry_2 *) to)->rec_len = - ext4_rec_len_to_disk(rec_len, blocksize); - de->inode = 0; - map++; - to += rec_len; - } - return (struct ext4_dir_entry_2 *) (to - rec_len); -} - -/* - * Compact each dir entry in the range to the minimal rec_len. - * Returns pointer to last entry in range. - */ -static struct ext4_dir_entry_2* dx_pack_dirents(char *base, unsigned blocksize) -{ - struct ext4_dir_entry_2 *next, *to, *prev, *de = (struct ext4_dir_entry_2 *) base; - unsigned rec_len = 0; - - prev = to = de; - while ((char*)de < base + blocksize) { - next = ext4_next_entry(de, blocksize); - if (de->inode && de->name_len) { - rec_len = EXT4_DIR_REC_LEN(de->name_len); - if (de > to) - memmove(to, de, rec_len); - to->rec_len = ext4_rec_len_to_disk(rec_len, blocksize); - prev = to; - to = (struct ext4_dir_entry_2 *) (((char *) to) + rec_len); - } - de = next; - } - return prev; -} - -/* - * Split a full leaf block to make room for a new dir entry. - * Allocate a new block, and move entries so that they are approx. equally full. - * Returns pointer to de in block into which the new entry will be inserted. - */ -static struct ext4_dir_entry_2 *do_split(handle_t *handle, struct inode *dir, - struct buffer_head **bh,struct dx_frame *frame, - struct dx_hash_info *hinfo) -{ - unsigned blocksize = dir->i_sb->s_blocksize; - unsigned count, continued; - struct buffer_head *bh2; - ext4_lblk_t newblock; - u32 hash2; - struct dx_map_entry *map; - char *data1 = (*bh)->b_data, *data2; - unsigned split, move, size; - struct ext4_dir_entry_2 *de = NULL, *de2; - struct ext4_dir_entry_tail *t; - int csum_size = 0; - int err = 0, i; - - if (ext4_has_metadata_csum(dir->i_sb)) - csum_size = sizeof(struct ext4_dir_entry_tail); - - bh2 = ext4_append(handle, dir, &newblock); - if (IS_ERR(bh2)) { - brelse(*bh); - *bh = NULL; - return (struct ext4_dir_entry_2 *) bh2; - } - - BUFFER_TRACE(*bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, *bh); - if (err) - goto journal_error; - - BUFFER_TRACE(frame->bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, frame->bh); - if (err) - goto journal_error; - - data2 = bh2->b_data; - - /* create map in the end of data2 block */ - map = (struct dx_map_entry *) (data2 + blocksize); - count = dx_make_map(dir, (struct ext4_dir_entry_2 *) data1, - blocksize, hinfo, map); - map -= count; - dx_sort_map(map, count); - /* Split the existing block in the middle, size-wise */ - size = 0; - move = 0; - for (i = count-1; i >= 0; i--) { - /* is more than half of this entry in 2nd half of the block? */ - if (size + map[i].size/2 > blocksize/2) - break; - size += map[i].size; - move++; - } - /* map index at which we will split */ - split = count - move; - hash2 = map[split].hash; - continued = hash2 == map[split - 1].hash; - dxtrace(printk(KERN_INFO "Split block %lu at %x, %i/%i\n", - (unsigned long)dx_get_block(frame->at), - hash2, split, count-split)); - - /* Fancy dance to stay within two buffers */ - de2 = dx_move_dirents(data1, data2, map + split, count - split, - blocksize); - de = dx_pack_dirents(data1, blocksize); - de->rec_len = ext4_rec_len_to_disk(data1 + (blocksize - csum_size) - - (char *) de, - blocksize); - de2->rec_len = ext4_rec_len_to_disk(data2 + (blocksize - csum_size) - - (char *) de2, - blocksize); - if (csum_size) { - t = EXT4_DIRENT_TAIL(data2, blocksize); - initialize_dirent_tail(t, blocksize); - - t = EXT4_DIRENT_TAIL(data1, blocksize); - initialize_dirent_tail(t, blocksize); - } - - dxtrace(dx_show_leaf(dir, hinfo, (struct ext4_dir_entry_2 *) data1, - blocksize, 1)); - dxtrace(dx_show_leaf(dir, hinfo, (struct ext4_dir_entry_2 *) data2, - blocksize, 1)); - - /* Which block gets the new entry? */ - if (hinfo->hash >= hash2) { - swap(*bh, bh2); - de = de2; - } - dx_insert_block(frame, hash2 + continued, newblock); - err = ext4_handle_dirty_dirent_node(handle, dir, bh2); - if (err) - goto journal_error; - err = ext4_handle_dirty_dx_node(handle, dir, frame->bh); - if (err) - goto journal_error; - brelse(bh2); - dxtrace(dx_show_index("frame", frame->entries)); - return de; - -journal_error: - brelse(*bh); - brelse(bh2); - *bh = NULL; - ext4_std_error(dir->i_sb, err); - return ERR_PTR(err); -} - -int ext4_find_dest_de(struct inode *dir, struct inode *inode, - struct buffer_head *bh, - void *buf, int buf_size, - struct ext4_filename *fname, - struct ext4_dir_entry_2 **dest_de) -{ - struct ext4_dir_entry_2 *de; - unsigned short reclen = EXT4_DIR_REC_LEN(fname_len(fname)); - int nlen, rlen; - unsigned int offset = 0; - char *top; - int res; - - de = (struct ext4_dir_entry_2 *)buf; - top = buf + buf_size - reclen; - while ((char *) de <= top) { - if (ext4_check_dir_entry(dir, NULL, de, bh, - buf, buf_size, offset)) { - res = -EFSCORRUPTED; - goto return_result; - } - /* Provide crypto context and crypto buffer to ext4 match */ - res = ext4_match(fname, de); - if (res < 0) - goto return_result; - if (res > 0) { - res = -EEXIST; - goto return_result; - } - nlen = EXT4_DIR_REC_LEN(de->name_len); - rlen = ext4_rec_len_from_disk(de->rec_len, buf_size); - if ((de->inode ? rlen - nlen : rlen) >= reclen) - break; - de = (struct ext4_dir_entry_2 *)((char *)de + rlen); - offset += rlen; - } - - if ((char *) de > top) - res = -ENOSPC; - else { - *dest_de = de; - res = 0; - } -return_result: - return res; -} - -int ext4_insert_dentry(struct inode *dir, - struct inode *inode, - struct ext4_dir_entry_2 *de, - int buf_size, - struct ext4_filename *fname) -{ - - int nlen, rlen; - - nlen = EXT4_DIR_REC_LEN(de->name_len); - rlen = ext4_rec_len_from_disk(de->rec_len, buf_size); - if (de->inode) { - struct ext4_dir_entry_2 *de1 = - (struct ext4_dir_entry_2 *)((char *)de + nlen); - de1->rec_len = ext4_rec_len_to_disk(rlen - nlen, buf_size); - de->rec_len = ext4_rec_len_to_disk(nlen, buf_size); - de = de1; - } - de->file_type = EXT4_FT_UNKNOWN; - de->inode = cpu_to_le32(inode->i_ino); - ext4_set_de_type(inode->i_sb, de, inode->i_mode); - de->name_len = fname_len(fname); - memcpy(de->name, fname_name(fname), fname_len(fname)); - return 0; -} - -/* - * Add a new entry into a directory (leaf) block. If de is non-NULL, - * it points to a directory entry which is guaranteed to be large - * enough for new directory entry. If de is NULL, then - * add_dirent_to_buf will attempt search the directory block for - * space. It will return -ENOSPC if no space is available, and -EIO - * and -EEXIST if directory entry already exists. - */ -static int add_dirent_to_buf(handle_t *handle, struct ext4_filename *fname, - struct inode *dir, - struct inode *inode, struct ext4_dir_entry_2 *de, - struct buffer_head *bh) -{ - unsigned int blocksize = dir->i_sb->s_blocksize; - int csum_size = 0; - int err; - - if (ext4_has_metadata_csum(inode->i_sb)) - csum_size = sizeof(struct ext4_dir_entry_tail); - - if (!de) { - err = ext4_find_dest_de(dir, inode, bh, bh->b_data, - blocksize - csum_size, fname, &de); - if (err) - return err; - } - BUFFER_TRACE(bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, bh); - if (err) { - ext4_std_error(dir->i_sb, err); - return err; - } - - /* By now the buffer is marked for journaling. Due to crypto operations, - * the following function call may fail */ - err = ext4_insert_dentry(dir, inode, de, blocksize, fname); - if (err < 0) - return err; - - /* - * XXX shouldn't update any times until successful - * completion of syscall, but too many callers depend - * on this. - * - * XXX similarly, too many callers depend on - * ext4_new_inode() setting the times, but error - * recovery deletes the inode, so the worst that can - * happen is that the times are slightly out of date - * and/or different from the directory change time. - */ - dir->i_mtime = dir->i_ctime = ext4_current_time(dir); - ext4_update_dx_flag(dir); - dir->i_version++; - ext4_mark_inode_dirty(handle, dir); - BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); - err = ext4_handle_dirty_dirent_node(handle, dir, bh); - if (err) - ext4_std_error(dir->i_sb, err); - return 0; -} - -/* - * This converts a one block unindexed directory to a 3 block indexed - * directory, and adds the dentry to the indexed directory. - */ -static int make_indexed_dir(handle_t *handle, struct ext4_filename *fname, - struct inode *dir, - struct inode *inode, struct buffer_head *bh) -{ - struct buffer_head *bh2; - struct dx_root *root; - struct dx_frame frames[2], *frame; - struct dx_entry *entries; - struct ext4_dir_entry_2 *de, *de2; - struct ext4_dir_entry_tail *t; - char *data1, *top; - unsigned len; - int retval; - unsigned blocksize; - ext4_lblk_t block; - struct fake_dirent *fde; - int csum_size = 0; - - if (ext4_has_metadata_csum(inode->i_sb)) - csum_size = sizeof(struct ext4_dir_entry_tail); - - blocksize = dir->i_sb->s_blocksize; - dxtrace(printk(KERN_DEBUG "Creating index: inode %lu\n", dir->i_ino)); - BUFFER_TRACE(bh, "get_write_access"); - retval = ext4_journal_get_write_access(handle, bh); - if (retval) { - ext4_std_error(dir->i_sb, retval); - brelse(bh); - return retval; - } - root = (struct dx_root *) bh->b_data; - - /* The 0th block becomes the root, move the dirents out */ - fde = &root->dotdot; - de = (struct ext4_dir_entry_2 *)((char *)fde + - ext4_rec_len_from_disk(fde->rec_len, blocksize)); - if ((char *) de >= (((char *) root) + blocksize)) { - EXT4_ERROR_INODE(dir, "invalid rec_len for '..'"); - brelse(bh); - return -EFSCORRUPTED; - } - len = ((char *) root) + (blocksize - csum_size) - (char *) de; - - /* Allocate new block for the 0th block's dirents */ - bh2 = ext4_append(handle, dir, &block); - if (IS_ERR(bh2)) { - brelse(bh); - return PTR_ERR(bh2); - } - ext4_set_inode_flag(dir, EXT4_INODE_INDEX); - data1 = bh2->b_data; - - memcpy (data1, de, len); - de = (struct ext4_dir_entry_2 *) data1; - top = data1 + len; - while ((char *)(de2 = ext4_next_entry(de, blocksize)) < top) - de = de2; - de->rec_len = ext4_rec_len_to_disk(data1 + (blocksize - csum_size) - - (char *) de, - blocksize); - - if (csum_size) { - t = EXT4_DIRENT_TAIL(data1, blocksize); - initialize_dirent_tail(t, blocksize); - } - - /* Initialize the root; the dot dirents already exist */ - de = (struct ext4_dir_entry_2 *) (&root->dotdot); - de->rec_len = ext4_rec_len_to_disk(blocksize - EXT4_DIR_REC_LEN(2), - blocksize); - memset (&root->info, 0, sizeof(root->info)); - root->info.info_length = sizeof(root->info); - root->info.hash_version = EXT4_SB(dir->i_sb)->s_def_hash_version; - entries = root->entries; - dx_set_block(entries, 1); - dx_set_count(entries, 1); - dx_set_limit(entries, dx_root_limit(dir, sizeof(root->info))); - - /* Initialize as for dx_probe */ - fname->hinfo.hash_version = root->info.hash_version; - if (fname->hinfo.hash_version <= DX_HASH_TEA) - fname->hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned; - fname->hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed; - ext4fs_dirhash(fname_name(fname), fname_len(fname), &fname->hinfo); - - memset(frames, 0, sizeof(frames)); - frame = frames; - frame->entries = entries; - frame->at = entries; - frame->bh = bh; - - retval = ext4_handle_dirty_dx_node(handle, dir, frame->bh); - if (retval) - goto out_frames; - retval = ext4_handle_dirty_dirent_node(handle, dir, bh2); - if (retval) - goto out_frames; - - de = do_split(handle,dir, &bh2, frame, &fname->hinfo); - if (IS_ERR(de)) { - retval = PTR_ERR(de); - goto out_frames; - } - - retval = add_dirent_to_buf(handle, fname, dir, inode, de, bh2); -out_frames: - /* - * Even if the block split failed, we have to properly write - * out all the changes we did so far. Otherwise we can end up - * with corrupted filesystem. - */ - if (retval) - ext4_mark_inode_dirty(handle, dir); - dx_release(frames); - brelse(bh2); - return retval; -} - -/* - * ext4_add_entry() - * - * adds a file entry to the specified directory, using the same - * semantics as ext4_find_entry(). It returns NULL if it failed. - * - * NOTE!! The inode part of 'de' is left at 0 - which means you - * may not sleep between calling this and putting something into - * the entry, as someone else might have used it while you slept. - */ -static int ext4_add_entry(handle_t *handle, struct dentry *dentry, - struct inode *inode) -{ - struct inode *dir = d_inode(dentry->d_parent); - struct buffer_head *bh = NULL; - struct ext4_dir_entry_2 *de; - struct ext4_dir_entry_tail *t; - struct super_block *sb; - struct ext4_filename fname; - int retval; - int dx_fallback=0; - unsigned blocksize; - ext4_lblk_t block, blocks; - int csum_size = 0; - - if (ext4_has_metadata_csum(inode->i_sb)) - csum_size = sizeof(struct ext4_dir_entry_tail); - - sb = dir->i_sb; - blocksize = sb->s_blocksize; - if (!dentry->d_name.len) - return -EINVAL; - - retval = ext4_fname_setup_filename(dir, &dentry->d_name, 0, &fname); - if (retval) - return retval; - - if (ext4_has_inline_data(dir)) { - retval = ext4_try_add_inline_entry(handle, &fname, dir, inode); - if (retval < 0) - goto out; - if (retval == 1) { - retval = 0; - goto out; - } - } - - if (is_dx(dir)) { - retval = ext4_dx_add_entry(handle, &fname, dir, inode); - if (!retval || (retval != ERR_BAD_DX_DIR)) - goto out; - ext4_clear_inode_flag(dir, EXT4_INODE_INDEX); - dx_fallback++; - ext4_mark_inode_dirty(handle, dir); - } - blocks = dir->i_size >> sb->s_blocksize_bits; - for (block = 0; block < blocks; block++) { - bh = ext4_read_dirblock(dir, block, DIRENT); - if (IS_ERR(bh)) { - retval = PTR_ERR(bh); - bh = NULL; - goto out; - } - retval = add_dirent_to_buf(handle, &fname, dir, inode, - NULL, bh); - if (retval != -ENOSPC) - goto out; - - if (blocks == 1 && !dx_fallback && - ext4_has_feature_dir_index(sb)) { - retval = make_indexed_dir(handle, &fname, dir, - inode, bh); - bh = NULL; /* make_indexed_dir releases bh */ - goto out; - } - brelse(bh); - } - bh = ext4_append(handle, dir, &block); - if (IS_ERR(bh)) { - retval = PTR_ERR(bh); - bh = NULL; - goto out; - } - de = (struct ext4_dir_entry_2 *) bh->b_data; - de->inode = 0; - de->rec_len = ext4_rec_len_to_disk(blocksize - csum_size, blocksize); - - if (csum_size) { - t = EXT4_DIRENT_TAIL(bh->b_data, blocksize); - initialize_dirent_tail(t, blocksize); - } - - retval = add_dirent_to_buf(handle, &fname, dir, inode, de, bh); -out: - ext4_fname_free_filename(&fname); - brelse(bh); - if (retval == 0) - ext4_set_inode_state(inode, EXT4_STATE_NEWENTRY); - return retval; -} - -/* - * Returns 0 for success, or a negative error value - */ -static int ext4_dx_add_entry(handle_t *handle, struct ext4_filename *fname, - struct inode *dir, struct inode *inode) -{ - struct dx_frame frames[2], *frame; - struct dx_entry *entries, *at; - struct buffer_head *bh; - struct super_block *sb = dir->i_sb; - struct ext4_dir_entry_2 *de; - int err; - - frame = dx_probe(fname, dir, NULL, frames); - if (IS_ERR(frame)) - return PTR_ERR(frame); - entries = frame->entries; - at = frame->at; - bh = ext4_read_dirblock(dir, dx_get_block(frame->at), DIRENT); - if (IS_ERR(bh)) { - err = PTR_ERR(bh); - bh = NULL; - goto cleanup; - } - - BUFFER_TRACE(bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, bh); - if (err) - goto journal_error; - - err = add_dirent_to_buf(handle, fname, dir, inode, NULL, bh); - if (err != -ENOSPC) - goto cleanup; - - /* Block full, should compress but for now just split */ - dxtrace(printk(KERN_DEBUG "using %u of %u node entries\n", - dx_get_count(entries), dx_get_limit(entries))); - /* Need to split index? */ - if (dx_get_count(entries) == dx_get_limit(entries)) { - ext4_lblk_t newblock; - unsigned icount = dx_get_count(entries); - int levels = frame - frames; - struct dx_entry *entries2; - struct dx_node *node2; - struct buffer_head *bh2; - - if (levels && (dx_get_count(frames->entries) == - dx_get_limit(frames->entries))) { - ext4_warning_inode(dir, "Directory index full!"); - err = -ENOSPC; - goto cleanup; - } - bh2 = ext4_append(handle, dir, &newblock); - if (IS_ERR(bh2)) { - err = PTR_ERR(bh2); - goto cleanup; - } - node2 = (struct dx_node *)(bh2->b_data); - entries2 = node2->entries; - memset(&node2->fake, 0, sizeof(struct fake_dirent)); - node2->fake.rec_len = ext4_rec_len_to_disk(sb->s_blocksize, - sb->s_blocksize); - BUFFER_TRACE(frame->bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, frame->bh); - if (err) - goto journal_error; - if (levels) { - unsigned icount1 = icount/2, icount2 = icount - icount1; - unsigned hash2 = dx_get_hash(entries + icount1); - dxtrace(printk(KERN_DEBUG "Split index %i/%i\n", - icount1, icount2)); - - BUFFER_TRACE(frame->bh, "get_write_access"); /* index root */ - err = ext4_journal_get_write_access(handle, - frames[0].bh); - if (err) - goto journal_error; - - memcpy((char *) entries2, (char *) (entries + icount1), - icount2 * sizeof(struct dx_entry)); - dx_set_count(entries, icount1); - dx_set_count(entries2, icount2); - dx_set_limit(entries2, dx_node_limit(dir)); - - /* Which index block gets the new entry? */ - if (at - entries >= icount1) { - frame->at = at = at - entries - icount1 + entries2; - frame->entries = entries = entries2; - swap(frame->bh, bh2); - } - dx_insert_block(frames + 0, hash2, newblock); - dxtrace(dx_show_index("node", frames[1].entries)); - dxtrace(dx_show_index("node", - ((struct dx_node *) bh2->b_data)->entries)); - err = ext4_handle_dirty_dx_node(handle, dir, bh2); - if (err) - goto journal_error; - brelse (bh2); - } else { - dxtrace(printk(KERN_DEBUG - "Creating second level index...\n")); - memcpy((char *) entries2, (char *) entries, - icount * sizeof(struct dx_entry)); - dx_set_limit(entries2, dx_node_limit(dir)); - - /* Set up root */ - dx_set_count(entries, 1); - dx_set_block(entries + 0, newblock); - ((struct dx_root *) frames[0].bh->b_data)->info.indirect_levels = 1; - - /* Add new access path frame */ - frame = frames + 1; - frame->at = at = at - entries + entries2; - frame->entries = entries = entries2; - frame->bh = bh2; - err = ext4_journal_get_write_access(handle, - frame->bh); - if (err) - goto journal_error; - } - err = ext4_handle_dirty_dx_node(handle, dir, frames[0].bh); - if (err) { - ext4_std_error(inode->i_sb, err); - goto cleanup; - } - } - de = do_split(handle, dir, &bh, frame, &fname->hinfo); - if (IS_ERR(de)) { - err = PTR_ERR(de); - goto cleanup; - } - err = add_dirent_to_buf(handle, fname, dir, inode, de, bh); - goto cleanup; - -journal_error: - ext4_std_error(dir->i_sb, err); -cleanup: - brelse(bh); - dx_release(frames); - return err; -} - -/* - * ext4_generic_delete_entry deletes a directory entry by merging it - * with the previous entry - */ -int ext4_generic_delete_entry(handle_t *handle, - struct inode *dir, - struct ext4_dir_entry_2 *de_del, - struct buffer_head *bh, - void *entry_buf, - int buf_size, - int csum_size) -{ - struct ext4_dir_entry_2 *de, *pde; - unsigned int blocksize = dir->i_sb->s_blocksize; - int i; - - i = 0; - pde = NULL; - de = (struct ext4_dir_entry_2 *)entry_buf; - while (i < buf_size - csum_size) { - if (ext4_check_dir_entry(dir, NULL, de, bh, - bh->b_data, bh->b_size, i)) - return -EFSCORRUPTED; - if (de == de_del) { - if (pde) - pde->rec_len = ext4_rec_len_to_disk( - ext4_rec_len_from_disk(pde->rec_len, - blocksize) + - ext4_rec_len_from_disk(de->rec_len, - blocksize), - blocksize); - else - de->inode = 0; - dir->i_version++; - return 0; - } - i += ext4_rec_len_from_disk(de->rec_len, blocksize); - pde = de; - de = ext4_next_entry(de, blocksize); - } - return -ENOENT; -} - -static int ext4_delete_entry(handle_t *handle, - struct inode *dir, - struct ext4_dir_entry_2 *de_del, - struct buffer_head *bh) -{ - int err, csum_size = 0; - - if (ext4_has_inline_data(dir)) { - int has_inline_data = 1; - err = ext4_delete_inline_entry(handle, dir, de_del, bh, - &has_inline_data); - if (has_inline_data) - return err; - } - - if (ext4_has_metadata_csum(dir->i_sb)) - csum_size = sizeof(struct ext4_dir_entry_tail); - - BUFFER_TRACE(bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, bh); - if (unlikely(err)) - goto out; - - err = ext4_generic_delete_entry(handle, dir, de_del, - bh, bh->b_data, - dir->i_sb->s_blocksize, csum_size); - if (err) - goto out; - - BUFFER_TRACE(bh, "call ext4_handle_dirty_metadata"); - err = ext4_handle_dirty_dirent_node(handle, dir, bh); - if (unlikely(err)) - goto out; - - return 0; -out: - if (err != -ENOENT) - ext4_std_error(dir->i_sb, err); - return err; -} - -/* - * DIR_NLINK feature is set if 1) nlinks > EXT4_LINK_MAX or 2) nlinks == 2, - * since this indicates that nlinks count was previously 1. - */ -static void ext4_inc_count(handle_t *handle, struct inode *inode) -{ - inc_nlink(inode); - if (is_dx(inode) && inode->i_nlink > 1) { - /* limit is 16-bit i_links_count */ - if (inode->i_nlink >= EXT4_LINK_MAX || inode->i_nlink == 2) { - set_nlink(inode, 1); - ext4_set_feature_dir_nlink(inode->i_sb); - } - } -} - -/* - * If a directory had nlink == 1, then we should let it be 1. This indicates - * directory has >EXT4_LINK_MAX subdirs. - */ -static void ext4_dec_count(handle_t *handle, struct inode *inode) -{ - if (!S_ISDIR(inode->i_mode) || inode->i_nlink > 2) - drop_nlink(inode); -} - - -static int ext4_add_nondir(handle_t *handle, - struct dentry *dentry, struct inode *inode) -{ - int err = ext4_add_entry(handle, dentry, inode); - if (!err) { - ext4_mark_inode_dirty(handle, inode); - unlock_new_inode(inode); - d_instantiate(dentry, inode); - return 0; - } - drop_nlink(inode); - unlock_new_inode(inode); - iput(inode); - return err; -} - -/* - * By the time this is called, we already have created - * the directory cache entry for the new file, but it - * is so far negative - it has no inode. - * - * If the create succeeds, we fill in the inode information - * with d_instantiate(). - */ -static int ext4_create(struct inode *dir, struct dentry *dentry, umode_t mode, - bool excl) -{ - handle_t *handle; - struct inode *inode; - int err, credits, retries = 0; - - err = dquot_initialize(dir); - if (err) - return err; - - credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3); -retry: - inode = ext4_new_inode_start_handle(dir, mode, &dentry->d_name, 0, - NULL, EXT4_HT_DIR, credits); - handle = ext4_journal_current_handle(); - err = PTR_ERR(inode); - if (!IS_ERR(inode)) { - inode->i_op = &ext4_file_inode_operations; - inode->i_fop = &ext4_file_operations; - ext4_set_aops(inode); - err = ext4_add_nondir(handle, dentry, inode); - if (!err && IS_DIRSYNC(dir)) - ext4_handle_sync(handle); - } - if (handle) - ext4_journal_stop(handle); - if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) - goto retry; - return err; -} - -static int ext4_mknod(struct inode *dir, struct dentry *dentry, - umode_t mode, dev_t rdev) -{ - handle_t *handle; - struct inode *inode; - int err, credits, retries = 0; - - err = dquot_initialize(dir); - if (err) - return err; - - credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3); -retry: - inode = ext4_new_inode_start_handle(dir, mode, &dentry->d_name, 0, - NULL, EXT4_HT_DIR, credits); - handle = ext4_journal_current_handle(); - err = PTR_ERR(inode); - if (!IS_ERR(inode)) { - init_special_inode(inode, inode->i_mode, rdev); - inode->i_op = &ext4_special_inode_operations; - err = ext4_add_nondir(handle, dentry, inode); - if (!err && IS_DIRSYNC(dir)) - ext4_handle_sync(handle); - } - if (handle) - ext4_journal_stop(handle); - if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) - goto retry; - return err; -} - -static int ext4_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) -{ - handle_t *handle; - struct inode *inode; - int err, retries = 0; - - err = dquot_initialize(dir); - if (err) - return err; - -retry: - inode = ext4_new_inode_start_handle(dir, mode, - NULL, 0, NULL, - EXT4_HT_DIR, - EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) + - 4 + EXT4_XATTR_TRANS_BLOCKS); - handle = ext4_journal_current_handle(); - err = PTR_ERR(inode); - if (!IS_ERR(inode)) { - inode->i_op = &ext4_file_inode_operations; - inode->i_fop = &ext4_file_operations; - ext4_set_aops(inode); - d_tmpfile(dentry, inode); - err = ext4_orphan_add(handle, inode); - if (err) - goto err_unlock_inode; - mark_inode_dirty(inode); - unlock_new_inode(inode); - } - if (handle) - ext4_journal_stop(handle); - if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) - goto retry; - return err; -err_unlock_inode: - ext4_journal_stop(handle); - unlock_new_inode(inode); - return err; -} - -struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode, - struct ext4_dir_entry_2 *de, - int blocksize, int csum_size, - unsigned int parent_ino, int dotdot_real_len) -{ - de->inode = cpu_to_le32(inode->i_ino); - de->name_len = 1; - de->rec_len = ext4_rec_len_to_disk(EXT4_DIR_REC_LEN(de->name_len), - blocksize); - strcpy(de->name, "."); - ext4_set_de_type(inode->i_sb, de, S_IFDIR); - - de = ext4_next_entry(de, blocksize); - de->inode = cpu_to_le32(parent_ino); - de->name_len = 2; - if (!dotdot_real_len) - de->rec_len = ext4_rec_len_to_disk(blocksize - - (csum_size + EXT4_DIR_REC_LEN(1)), - blocksize); - else - de->rec_len = ext4_rec_len_to_disk( - EXT4_DIR_REC_LEN(de->name_len), blocksize); - strcpy(de->name, ".."); - ext4_set_de_type(inode->i_sb, de, S_IFDIR); - - return ext4_next_entry(de, blocksize); -} - -static int ext4_init_new_dir(handle_t *handle, struct inode *dir, - struct inode *inode) -{ - struct buffer_head *dir_block = NULL; - struct ext4_dir_entry_2 *de; - struct ext4_dir_entry_tail *t; - ext4_lblk_t block = 0; - unsigned int blocksize = dir->i_sb->s_blocksize; - int csum_size = 0; - int err; - - if (ext4_has_metadata_csum(dir->i_sb)) - csum_size = sizeof(struct ext4_dir_entry_tail); - - if (ext4_test_inode_state(inode, EXT4_STATE_MAY_INLINE_DATA)) { - err = ext4_try_create_inline_dir(handle, dir, inode); - if (err < 0 && err != -ENOSPC) - goto out; - if (!err) - goto out; - } - - inode->i_size = 0; - dir_block = ext4_append(handle, inode, &block); - if (IS_ERR(dir_block)) - return PTR_ERR(dir_block); - de = (struct ext4_dir_entry_2 *)dir_block->b_data; - ext4_init_dot_dotdot(inode, de, blocksize, csum_size, dir->i_ino, 0); - set_nlink(inode, 2); - if (csum_size) { - t = EXT4_DIRENT_TAIL(dir_block->b_data, blocksize); - initialize_dirent_tail(t, blocksize); - } - - BUFFER_TRACE(dir_block, "call ext4_handle_dirty_metadata"); - err = ext4_handle_dirty_dirent_node(handle, inode, dir_block); - if (err) - goto out; - set_buffer_verified(dir_block); -out: - brelse(dir_block); - return err; -} - -static int ext4_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) -{ - handle_t *handle; - struct inode *inode; - int err, credits, retries = 0; - - if (EXT4_DIR_LINK_MAX(dir)) - return -EMLINK; - - err = dquot_initialize(dir); - if (err) - return err; - - credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3); -retry: - inode = ext4_new_inode_start_handle(dir, S_IFDIR | mode, - &dentry->d_name, - 0, NULL, EXT4_HT_DIR, credits); - handle = ext4_journal_current_handle(); - err = PTR_ERR(inode); - if (IS_ERR(inode)) - goto out_stop; - - inode->i_op = &ext4_dir_inode_operations; - inode->i_fop = &ext4_dir_operations; - err = ext4_init_new_dir(handle, dir, inode); - if (err) - goto out_clear_inode; - err = ext4_mark_inode_dirty(handle, inode); - if (!err) - err = ext4_add_entry(handle, dentry, inode); - if (err) { -out_clear_inode: - clear_nlink(inode); - unlock_new_inode(inode); - ext4_mark_inode_dirty(handle, inode); - iput(inode); - goto out_stop; - } - ext4_inc_count(handle, dir); - ext4_update_dx_flag(dir); - err = ext4_mark_inode_dirty(handle, dir); - if (err) - goto out_clear_inode; - unlock_new_inode(inode); - d_instantiate(dentry, inode); - if (IS_DIRSYNC(dir)) - ext4_handle_sync(handle); - -out_stop: - if (handle) - ext4_journal_stop(handle); - if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) - goto retry; - return err; -} - -/* - * routine to check that the specified directory is empty (for rmdir) - */ -bool ext4_empty_dir(struct inode *inode) -{ - unsigned int offset; - struct buffer_head *bh; - struct ext4_dir_entry_2 *de, *de1; - struct super_block *sb; - - if (ext4_has_inline_data(inode)) { - int has_inline_data = 1; - int ret; - - ret = empty_inline_dir(inode, &has_inline_data); - if (has_inline_data) - return ret; - } - - sb = inode->i_sb; - if (inode->i_size < EXT4_DIR_REC_LEN(1) + EXT4_DIR_REC_LEN(2)) { - EXT4_ERROR_INODE(inode, "invalid size"); - return true; - } - bh = ext4_read_dirblock(inode, 0, EITHER); - if (IS_ERR(bh)) - return true; - - de = (struct ext4_dir_entry_2 *) bh->b_data; - de1 = ext4_next_entry(de, sb->s_blocksize); - if (le32_to_cpu(de->inode) != inode->i_ino || - le32_to_cpu(de1->inode) == 0 || - strcmp(".", de->name) || strcmp("..", de1->name)) { - ext4_warning_inode(inode, "directory missing '.' and/or '..'"); - brelse(bh); - return true; - } - offset = ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize) + - ext4_rec_len_from_disk(de1->rec_len, sb->s_blocksize); - de = ext4_next_entry(de1, sb->s_blocksize); - while (offset < inode->i_size) { - if ((void *) de >= (void *) (bh->b_data+sb->s_blocksize)) { - unsigned int lblock; - brelse(bh); - lblock = offset >> EXT4_BLOCK_SIZE_BITS(sb); - bh = ext4_read_dirblock(inode, lblock, EITHER); - if (IS_ERR(bh)) - return true; - de = (struct ext4_dir_entry_2 *) bh->b_data; - } - if (ext4_check_dir_entry(inode, NULL, de, bh, - bh->b_data, bh->b_size, offset)) { - de = (struct ext4_dir_entry_2 *)(bh->b_data + - sb->s_blocksize); - offset = (offset | (sb->s_blocksize - 1)) + 1; - continue; - } - if (le32_to_cpu(de->inode)) { - brelse(bh); - return false; - } - offset += ext4_rec_len_from_disk(de->rec_len, sb->s_blocksize); - de = ext4_next_entry(de, sb->s_blocksize); - } - brelse(bh); - return true; -} - -/* - * ext4_orphan_add() links an unlinked or truncated inode into a list of - * such inodes, starting at the superblock, in case we crash before the - * file is closed/deleted, or in case the inode truncate spans multiple - * transactions and the last transaction is not recovered after a crash. - * - * At filesystem recovery time, we walk this list deleting unlinked - * inodes and truncating linked inodes in ext4_orphan_cleanup(). - * - * Orphan list manipulation functions must be called under i_mutex unless - * we are just creating the inode or deleting it. - */ -int ext4_orphan_add(handle_t *handle, struct inode *inode) -{ - struct super_block *sb = inode->i_sb; - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_iloc iloc; - int err = 0, rc; - bool dirty = false; - - if (!sbi->s_journal || is_bad_inode(inode)) - return 0; - - WARN_ON_ONCE(!(inode->i_state & (I_NEW | I_FREEING)) && - !inode_is_locked(inode)); - /* - * Exit early if inode already is on orphan list. This is a big speedup - * since we don't have to contend on the global s_orphan_lock. - */ - if (!list_empty(&EXT4_I(inode)->i_orphan)) - return 0; - - /* - * Orphan handling is only valid for files with data blocks - * being truncated, or files being unlinked. Note that we either - * hold i_mutex, or the inode can not be referenced from outside, - * so i_nlink should not be bumped due to race - */ - J_ASSERT((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || - S_ISLNK(inode->i_mode)) || inode->i_nlink == 0); - - BUFFER_TRACE(sbi->s_sbh, "get_write_access"); - err = ext4_journal_get_write_access(handle, sbi->s_sbh); - if (err) - goto out; - - err = ext4_reserve_inode_write(handle, inode, &iloc); - if (err) - goto out; - - mutex_lock(&sbi->s_orphan_lock); - /* - * Due to previous errors inode may be already a part of on-disk - * orphan list. If so skip on-disk list modification. - */ - if (!NEXT_ORPHAN(inode) || NEXT_ORPHAN(inode) > - (le32_to_cpu(sbi->s_es->s_inodes_count))) { - /* Insert this inode at the head of the on-disk orphan list */ - NEXT_ORPHAN(inode) = le32_to_cpu(sbi->s_es->s_last_orphan); - sbi->s_es->s_last_orphan = cpu_to_le32(inode->i_ino); - dirty = true; - } - list_add(&EXT4_I(inode)->i_orphan, &sbi->s_orphan); - mutex_unlock(&sbi->s_orphan_lock); - - if (dirty) { - err = ext4_handle_dirty_super(handle, sb); - rc = ext4_mark_iloc_dirty(handle, inode, &iloc); - if (!err) - err = rc; - if (err) { - /* - * We have to remove inode from in-memory list if - * addition to on disk orphan list failed. Stray orphan - * list entries can cause panics at unmount time. - */ - mutex_lock(&sbi->s_orphan_lock); - list_del_init(&EXT4_I(inode)->i_orphan); - mutex_unlock(&sbi->s_orphan_lock); - } - } - jbd_debug(4, "superblock will point to %lu\n", inode->i_ino); - jbd_debug(4, "orphan inode %lu will point to %d\n", - inode->i_ino, NEXT_ORPHAN(inode)); -out: - ext4_std_error(sb, err); - return err; -} - -/* - * ext4_orphan_del() removes an unlinked or truncated inode from the list - * of such inodes stored on disk, because it is finally being cleaned up. - */ -int ext4_orphan_del(handle_t *handle, struct inode *inode) -{ - struct list_head *prev; - struct ext4_inode_info *ei = EXT4_I(inode); - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - __u32 ino_next; - struct ext4_iloc iloc; - int err = 0; - - if (!sbi->s_journal && !(sbi->s_mount_state & EXT4_ORPHAN_FS)) - return 0; - - WARN_ON_ONCE(!(inode->i_state & (I_NEW | I_FREEING)) && - !inode_is_locked(inode)); - /* Do this quick check before taking global s_orphan_lock. */ - if (list_empty(&ei->i_orphan)) - return 0; - - if (handle) { - /* Grab inode buffer early before taking global s_orphan_lock */ - err = ext4_reserve_inode_write(handle, inode, &iloc); - } - - mutex_lock(&sbi->s_orphan_lock); - jbd_debug(4, "remove inode %lu from orphan list\n", inode->i_ino); - - prev = ei->i_orphan.prev; - list_del_init(&ei->i_orphan); - - /* If we're on an error path, we may not have a valid - * transaction handle with which to update the orphan list on - * disk, but we still need to remove the inode from the linked - * list in memory. */ - if (!handle || err) { - mutex_unlock(&sbi->s_orphan_lock); - goto out_err; - } - - ino_next = NEXT_ORPHAN(inode); - if (prev == &sbi->s_orphan) { - jbd_debug(4, "superblock will point to %u\n", ino_next); - BUFFER_TRACE(sbi->s_sbh, "get_write_access"); - err = ext4_journal_get_write_access(handle, sbi->s_sbh); - if (err) { - mutex_unlock(&sbi->s_orphan_lock); - goto out_brelse; - } - sbi->s_es->s_last_orphan = cpu_to_le32(ino_next); - mutex_unlock(&sbi->s_orphan_lock); - err = ext4_handle_dirty_super(handle, inode->i_sb); - } else { - struct ext4_iloc iloc2; - struct inode *i_prev = - &list_entry(prev, struct ext4_inode_info, i_orphan)->vfs_inode; - - jbd_debug(4, "orphan inode %lu will point to %u\n", - i_prev->i_ino, ino_next); - err = ext4_reserve_inode_write(handle, i_prev, &iloc2); - if (err) { - mutex_unlock(&sbi->s_orphan_lock); - goto out_brelse; - } - NEXT_ORPHAN(i_prev) = ino_next; - err = ext4_mark_iloc_dirty(handle, i_prev, &iloc2); - mutex_unlock(&sbi->s_orphan_lock); - } - if (err) - goto out_brelse; - NEXT_ORPHAN(inode) = 0; - err = ext4_mark_iloc_dirty(handle, inode, &iloc); -out_err: - ext4_std_error(inode->i_sb, err); - return err; - -out_brelse: - brelse(iloc.bh); - goto out_err; -} - -static int ext4_rmdir(struct inode *dir, struct dentry *dentry) -{ - int retval; - struct inode *inode; - struct buffer_head *bh; - struct ext4_dir_entry_2 *de; - handle_t *handle = NULL; - - /* Initialize quotas before so that eventual writes go in - * separate transaction */ - retval = dquot_initialize(dir); - if (retval) - return retval; - retval = dquot_initialize(d_inode(dentry)); - if (retval) - return retval; - - retval = -ENOENT; - bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL); - if (IS_ERR(bh)) - return PTR_ERR(bh); - if (!bh) - goto end_rmdir; - - inode = d_inode(dentry); - - retval = -EFSCORRUPTED; - if (le32_to_cpu(de->inode) != inode->i_ino) - goto end_rmdir; - - retval = -ENOTEMPTY; - if (!ext4_empty_dir(inode)) - goto end_rmdir; - - handle = ext4_journal_start(dir, EXT4_HT_DIR, - EXT4_DATA_TRANS_BLOCKS(dir->i_sb)); - if (IS_ERR(handle)) { - retval = PTR_ERR(handle); - handle = NULL; - goto end_rmdir; - } - - if (IS_DIRSYNC(dir)) - ext4_handle_sync(handle); - - retval = ext4_delete_entry(handle, dir, de, bh); - if (retval) - goto end_rmdir; - if (!EXT4_DIR_LINK_EMPTY(inode)) - ext4_warning_inode(inode, - "empty directory '%.*s' has too many links (%u)", - dentry->d_name.len, dentry->d_name.name, - inode->i_nlink); - inode->i_version++; - clear_nlink(inode); - /* There's no need to set i_disksize: the fact that i_nlink is - * zero will ensure that the right thing happens during any - * recovery. */ - inode->i_size = 0; - ext4_orphan_add(handle, inode); - inode->i_ctime = dir->i_ctime = dir->i_mtime = ext4_current_time(inode); - ext4_mark_inode_dirty(handle, inode); - ext4_dec_count(handle, dir); - ext4_update_dx_flag(dir); - ext4_mark_inode_dirty(handle, dir); - -end_rmdir: - brelse(bh); - if (handle) - ext4_journal_stop(handle); - return retval; -} - -static int ext4_unlink(struct inode *dir, struct dentry *dentry) -{ - int retval; - struct inode *inode; - struct buffer_head *bh; - struct ext4_dir_entry_2 *de; - handle_t *handle = NULL; - - trace_ext4_unlink_enter(dir, dentry); - /* Initialize quotas before so that eventual writes go - * in separate transaction */ - retval = dquot_initialize(dir); - if (retval) - return retval; - retval = dquot_initialize(d_inode(dentry)); - if (retval) - return retval; - - retval = -ENOENT; - bh = ext4_find_entry(dir, &dentry->d_name, &de, NULL); - if (IS_ERR(bh)) - return PTR_ERR(bh); - if (!bh) - goto end_unlink; - - inode = d_inode(dentry); - - retval = -EFSCORRUPTED; - if (le32_to_cpu(de->inode) != inode->i_ino) - goto end_unlink; - - handle = ext4_journal_start(dir, EXT4_HT_DIR, - EXT4_DATA_TRANS_BLOCKS(dir->i_sb)); - if (IS_ERR(handle)) { - retval = PTR_ERR(handle); - handle = NULL; - goto end_unlink; - } - - if (IS_DIRSYNC(dir)) - ext4_handle_sync(handle); - - if (inode->i_nlink == 0) { - ext4_warning_inode(inode, "Deleting file '%.*s' with no links", - dentry->d_name.len, dentry->d_name.name); - set_nlink(inode, 1); - } - retval = ext4_delete_entry(handle, dir, de, bh); - if (retval) - goto end_unlink; - dir->i_ctime = dir->i_mtime = ext4_current_time(dir); - ext4_update_dx_flag(dir); - ext4_mark_inode_dirty(handle, dir); - drop_nlink(inode); - if (!inode->i_nlink) - ext4_orphan_add(handle, inode); - inode->i_ctime = ext4_current_time(inode); - ext4_mark_inode_dirty(handle, inode); - -end_unlink: - brelse(bh); - if (handle) - ext4_journal_stop(handle); - trace_ext4_unlink_exit(dentry, retval); - return retval; -} - -static int ext4_symlink(struct inode *dir, - struct dentry *dentry, const char *symname) -{ - handle_t *handle; - struct inode *inode; - int err, len = strlen(symname); - int credits; - bool encryption_required; - struct fscrypt_str disk_link; - struct fscrypt_symlink_data *sd = NULL; - - disk_link.len = len + 1; - disk_link.name = (char *) symname; - - encryption_required = (ext4_encrypted_inode(dir) || - DUMMY_ENCRYPTION_ENABLED(EXT4_SB(dir->i_sb))); - if (encryption_required) { - err = fscrypt_get_encryption_info(dir); - if (err) - return err; - if (!fscrypt_has_encryption_key(dir)) - return -EPERM; - disk_link.len = (fscrypt_fname_encrypted_size(dir, len) + - sizeof(struct fscrypt_symlink_data)); - sd = kzalloc(disk_link.len, GFP_KERNEL); - if (!sd) - return -ENOMEM; - } - - if (disk_link.len > dir->i_sb->s_blocksize) { - err = -ENAMETOOLONG; - goto err_free_sd; - } - - err = dquot_initialize(dir); - if (err) - goto err_free_sd; - - if ((disk_link.len > EXT4_N_BLOCKS * 4)) { - /* - * For non-fast symlinks, we just allocate inode and put it on - * orphan list in the first transaction => we need bitmap, - * group descriptor, sb, inode block, quota blocks, and - * possibly selinux xattr blocks. - */ - credits = 4 + EXT4_MAXQUOTAS_INIT_BLOCKS(dir->i_sb) + - EXT4_XATTR_TRANS_BLOCKS; - } else { - /* - * Fast symlink. We have to add entry to directory - * (EXT4_DATA_TRANS_BLOCKS + EXT4_INDEX_EXTRA_TRANS_BLOCKS), - * allocate new inode (bitmap, group descriptor, inode block, - * quota blocks, sb is already counted in previous macros). - */ - credits = EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3; - } - - inode = ext4_new_inode_start_handle(dir, S_IFLNK|S_IRWXUGO, - &dentry->d_name, 0, NULL, - EXT4_HT_DIR, credits); - handle = ext4_journal_current_handle(); - if (IS_ERR(inode)) { - if (handle) - ext4_journal_stop(handle); - err = PTR_ERR(inode); - goto err_free_sd; - } - - if (encryption_required) { - struct qstr istr; - struct fscrypt_str ostr = - FSTR_INIT(sd->encrypted_path, disk_link.len); - - istr.name = (const unsigned char *) symname; - istr.len = len; - err = fscrypt_fname_usr_to_disk(inode, &istr, &ostr); - if (err) - goto err_drop_inode; - sd->len = cpu_to_le16(ostr.len); - disk_link.name = (char *) sd; - inode->i_op = &ext4_encrypted_symlink_inode_operations; - } - - if ((disk_link.len > EXT4_N_BLOCKS * 4)) { - if (!encryption_required) - inode->i_op = &ext4_symlink_inode_operations; - inode_nohighmem(inode); - ext4_set_aops(inode); - /* - * We cannot call page_symlink() with transaction started - * because it calls into ext4_write_begin() which can wait - * for transaction commit if we are running out of space - * and thus we deadlock. So we have to stop transaction now - * and restart it when symlink contents is written. - * - * To keep fs consistent in case of crash, we have to put inode - * to orphan list in the mean time. - */ - drop_nlink(inode); - err = ext4_orphan_add(handle, inode); - ext4_journal_stop(handle); - handle = NULL; - if (err) - goto err_drop_inode; - err = __page_symlink(inode, disk_link.name, disk_link.len, 1); - if (err) - goto err_drop_inode; - /* - * Now inode is being linked into dir (EXT4_DATA_TRANS_BLOCKS - * + EXT4_INDEX_EXTRA_TRANS_BLOCKS), inode is also modified - */ - handle = ext4_journal_start(dir, EXT4_HT_DIR, - EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT4_INDEX_EXTRA_TRANS_BLOCKS + 1); - if (IS_ERR(handle)) { - err = PTR_ERR(handle); - handle = NULL; - goto err_drop_inode; - } - set_nlink(inode, 1); - err = ext4_orphan_del(handle, inode); - if (err) - goto err_drop_inode; - } else { - /* clear the extent format for fast symlink */ - ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS); - if (!encryption_required) { - inode->i_op = &ext4_fast_symlink_inode_operations; - inode->i_link = (char *)&EXT4_I(inode)->i_data; - } - memcpy((char *)&EXT4_I(inode)->i_data, disk_link.name, - disk_link.len); - inode->i_size = disk_link.len - 1; - } - EXT4_I(inode)->i_disksize = inode->i_size; - err = ext4_add_nondir(handle, dentry, inode); - if (!err && IS_DIRSYNC(dir)) - ext4_handle_sync(handle); - - if (handle) - ext4_journal_stop(handle); - kfree(sd); - return err; -err_drop_inode: - if (handle) - ext4_journal_stop(handle); - clear_nlink(inode); - unlock_new_inode(inode); - iput(inode); -err_free_sd: - kfree(sd); - return err; -} - -static int ext4_link(struct dentry *old_dentry, - struct inode *dir, struct dentry *dentry) -{ - handle_t *handle; - struct inode *inode = d_inode(old_dentry); - int err, retries = 0; - - if (inode->i_nlink >= EXT4_LINK_MAX) - return -EMLINK; - if (ext4_encrypted_inode(dir) && - !fscrypt_has_permitted_context(dir, inode)) - return -EPERM; - - if ((ext4_test_inode_flag(dir, EXT4_INODE_PROJINHERIT)) && - (!projid_eq(EXT4_I(dir)->i_projid, - EXT4_I(old_dentry->d_inode)->i_projid))) - return -EXDEV; - - err = dquot_initialize(dir); - if (err) - return err; - -retry: - handle = ext4_journal_start(dir, EXT4_HT_DIR, - (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + - EXT4_INDEX_EXTRA_TRANS_BLOCKS) + 1); - if (IS_ERR(handle)) - return PTR_ERR(handle); - - if (IS_DIRSYNC(dir)) - ext4_handle_sync(handle); - - inode->i_ctime = ext4_current_time(inode); - ext4_inc_count(handle, inode); - ihold(inode); - - err = ext4_add_entry(handle, dentry, inode); - if (!err) { - ext4_mark_inode_dirty(handle, inode); - /* this can happen only for tmpfile being - * linked the first time - */ - if (inode->i_nlink == 1) - ext4_orphan_del(handle, inode); - d_instantiate(dentry, inode); - } else { - drop_nlink(inode); - iput(inode); - } - ext4_journal_stop(handle); - if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries)) - goto retry; - return err; -} - - -/* - * Try to find buffer head where contains the parent block. - * It should be the inode block if it is inlined or the 1st block - * if it is a normal dir. - */ -static struct buffer_head *ext4_get_first_dir_block(handle_t *handle, - struct inode *inode, - int *retval, - struct ext4_dir_entry_2 **parent_de, - int *inlined) -{ - struct buffer_head *bh; - - if (!ext4_has_inline_data(inode)) { - bh = ext4_read_dirblock(inode, 0, EITHER); - if (IS_ERR(bh)) { - *retval = PTR_ERR(bh); - return NULL; - } - *parent_de = ext4_next_entry( - (struct ext4_dir_entry_2 *)bh->b_data, - inode->i_sb->s_blocksize); - return bh; - } - - *inlined = 1; - return ext4_get_first_inline_block(inode, parent_de, retval); -} - -struct ext4_renament { - struct inode *dir; - struct dentry *dentry; - struct inode *inode; - bool is_dir; - int dir_nlink_delta; - - /* entry for "dentry" */ - struct buffer_head *bh; - struct ext4_dir_entry_2 *de; - int inlined; - - /* entry for ".." in inode if it's a directory */ - struct buffer_head *dir_bh; - struct ext4_dir_entry_2 *parent_de; - int dir_inlined; -}; - -static int ext4_rename_dir_prepare(handle_t *handle, struct ext4_renament *ent) -{ - int retval; - - ent->dir_bh = ext4_get_first_dir_block(handle, ent->inode, - &retval, &ent->parent_de, - &ent->dir_inlined); - if (!ent->dir_bh) - return retval; - if (le32_to_cpu(ent->parent_de->inode) != ent->dir->i_ino) - return -EFSCORRUPTED; - BUFFER_TRACE(ent->dir_bh, "get_write_access"); - return ext4_journal_get_write_access(handle, ent->dir_bh); -} - -static int ext4_rename_dir_finish(handle_t *handle, struct ext4_renament *ent, - unsigned dir_ino) -{ - int retval; - - ent->parent_de->inode = cpu_to_le32(dir_ino); - BUFFER_TRACE(ent->dir_bh, "call ext4_handle_dirty_metadata"); - if (!ent->dir_inlined) { - if (is_dx(ent->inode)) { - retval = ext4_handle_dirty_dx_node(handle, - ent->inode, - ent->dir_bh); - } else { - retval = ext4_handle_dirty_dirent_node(handle, - ent->inode, - ent->dir_bh); - } - } else { - retval = ext4_mark_inode_dirty(handle, ent->inode); - } - if (retval) { - ext4_std_error(ent->dir->i_sb, retval); - return retval; - } - return 0; -} - -static int ext4_setent(handle_t *handle, struct ext4_renament *ent, - unsigned ino, unsigned file_type) -{ - int retval; - - BUFFER_TRACE(ent->bh, "get write access"); - retval = ext4_journal_get_write_access(handle, ent->bh); - if (retval) - return retval; - ent->de->inode = cpu_to_le32(ino); - if (ext4_has_feature_filetype(ent->dir->i_sb)) - ent->de->file_type = file_type; - ent->dir->i_version++; - ent->dir->i_ctime = ent->dir->i_mtime = - ext4_current_time(ent->dir); - ext4_mark_inode_dirty(handle, ent->dir); - BUFFER_TRACE(ent->bh, "call ext4_handle_dirty_metadata"); - if (!ent->inlined) { - retval = ext4_handle_dirty_dirent_node(handle, - ent->dir, ent->bh); - if (unlikely(retval)) { - ext4_std_error(ent->dir->i_sb, retval); - return retval; - } - } - brelse(ent->bh); - ent->bh = NULL; - - return 0; -} - -static int ext4_find_delete_entry(handle_t *handle, struct inode *dir, - const struct qstr *d_name) -{ - int retval = -ENOENT; - struct buffer_head *bh; - struct ext4_dir_entry_2 *de; - - bh = ext4_find_entry(dir, d_name, &de, NULL); - if (IS_ERR(bh)) - return PTR_ERR(bh); - if (bh) { - retval = ext4_delete_entry(handle, dir, de, bh); - brelse(bh); - } - return retval; -} - -static void ext4_rename_delete(handle_t *handle, struct ext4_renament *ent, - int force_reread) -{ - int retval; - /* - * ent->de could have moved from under us during htree split, so make - * sure that we are deleting the right entry. We might also be pointing - * to a stale entry in the unused part of ent->bh so just checking inum - * and the name isn't enough. - */ - if (le32_to_cpu(ent->de->inode) != ent->inode->i_ino || - ent->de->name_len != ent->dentry->d_name.len || - strncmp(ent->de->name, ent->dentry->d_name.name, - ent->de->name_len) || - force_reread) { - retval = ext4_find_delete_entry(handle, ent->dir, - &ent->dentry->d_name); - } else { - retval = ext4_delete_entry(handle, ent->dir, ent->de, ent->bh); - if (retval == -ENOENT) { - retval = ext4_find_delete_entry(handle, ent->dir, - &ent->dentry->d_name); - } - } - - if (retval) { - ext4_warning_inode(ent->dir, - "Deleting old file: nlink %d, error=%d", - ent->dir->i_nlink, retval); - } -} - -static void ext4_update_dir_count(handle_t *handle, struct ext4_renament *ent) -{ - if (ent->dir_nlink_delta) { - if (ent->dir_nlink_delta == -1) - ext4_dec_count(handle, ent->dir); - else - ext4_inc_count(handle, ent->dir); - ext4_mark_inode_dirty(handle, ent->dir); - } -} - -static struct inode *ext4_whiteout_for_rename(struct ext4_renament *ent, - int credits, handle_t **h) -{ - struct inode *wh; - handle_t *handle; - int retries = 0; - - /* - * for inode block, sb block, group summaries, - * and inode bitmap - */ - credits += (EXT4_MAXQUOTAS_TRANS_BLOCKS(ent->dir->i_sb) + - EXT4_XATTR_TRANS_BLOCKS + 4); -retry: - wh = ext4_new_inode_start_handle(ent->dir, S_IFCHR | WHITEOUT_MODE, - &ent->dentry->d_name, 0, NULL, - EXT4_HT_DIR, credits); - - handle = ext4_journal_current_handle(); - if (IS_ERR(wh)) { - if (handle) - ext4_journal_stop(handle); - if (PTR_ERR(wh) == -ENOSPC && - ext4_should_retry_alloc(ent->dir->i_sb, &retries)) - goto retry; - } else { - *h = handle; - init_special_inode(wh, wh->i_mode, WHITEOUT_DEV); - wh->i_op = &ext4_special_inode_operations; - } - return wh; -} - -/* - * Anybody can rename anything with this: the permission checks are left to the - * higher-level routines. - * - * n.b. old_{dentry,inode) refers to the source dentry/inode - * while new_{dentry,inode) refers to the destination dentry/inode - * This comes from rename(const char *oldpath, const char *newpath) - */ -static int ext4_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry, - unsigned int flags) -{ - handle_t *handle = NULL; - struct ext4_renament old = { - .dir = old_dir, - .dentry = old_dentry, - .inode = d_inode(old_dentry), - }; - struct ext4_renament new = { - .dir = new_dir, - .dentry = new_dentry, - .inode = d_inode(new_dentry), - }; - int force_reread; - int retval; - struct inode *whiteout = NULL; - int credits; - u8 old_file_type; - - if ((ext4_test_inode_flag(new_dir, EXT4_INODE_PROJINHERIT)) && - (!projid_eq(EXT4_I(new_dir)->i_projid, - EXT4_I(old_dentry->d_inode)->i_projid))) - return -EXDEV; - - retval = dquot_initialize(old.dir); - if (retval) - return retval; - retval = dquot_initialize(new.dir); - if (retval) - return retval; - - /* Initialize quotas before so that eventual writes go - * in separate transaction */ - if (new.inode) { - retval = dquot_initialize(new.inode); - if (retval) - return retval; - } - - old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, &old.de, NULL); - if (IS_ERR(old.bh)) - return PTR_ERR(old.bh); - /* - * Check for inode number is _not_ due to possible IO errors. - * We might rmdir the source, keep it as pwd of some process - * and merrily kill the link to whatever was created under the - * same name. Goodbye sticky bit ;-< - */ - retval = -ENOENT; - if (!old.bh || le32_to_cpu(old.de->inode) != old.inode->i_ino) - goto end_rename; - - if ((old.dir != new.dir) && - ext4_encrypted_inode(new.dir) && - !fscrypt_has_permitted_context(new.dir, old.inode)) { - retval = -EPERM; - goto end_rename; - } - - new.bh = ext4_find_entry(new.dir, &new.dentry->d_name, - &new.de, &new.inlined); - if (IS_ERR(new.bh)) { - retval = PTR_ERR(new.bh); - new.bh = NULL; - goto end_rename; - } - if (new.bh) { - if (!new.inode) { - brelse(new.bh); - new.bh = NULL; - } - } - if (new.inode && !test_opt(new.dir->i_sb, NO_AUTO_DA_ALLOC)) - ext4_alloc_da_blocks(old.inode); - - credits = (2 * EXT4_DATA_TRANS_BLOCKS(old.dir->i_sb) + - EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2); - if (!(flags & RENAME_WHITEOUT)) { - handle = ext4_journal_start(old.dir, EXT4_HT_DIR, credits); - if (IS_ERR(handle)) { - retval = PTR_ERR(handle); - handle = NULL; - goto end_rename; - } - } else { - whiteout = ext4_whiteout_for_rename(&old, credits, &handle); - if (IS_ERR(whiteout)) { - retval = PTR_ERR(whiteout); - whiteout = NULL; - goto end_rename; - } - } - - if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir)) - ext4_handle_sync(handle); - - if (S_ISDIR(old.inode->i_mode)) { - if (new.inode) { - retval = -ENOTEMPTY; - if (!ext4_empty_dir(new.inode)) - goto end_rename; - } else { - retval = -EMLINK; - if (new.dir != old.dir && EXT4_DIR_LINK_MAX(new.dir)) - goto end_rename; - } - retval = ext4_rename_dir_prepare(handle, &old); - if (retval) - goto end_rename; - } - /* - * If we're renaming a file within an inline_data dir and adding or - * setting the new dirent causes a conversion from inline_data to - * extents/blockmap, we need to force the dirent delete code to - * re-read the directory, or else we end up trying to delete a dirent - * from what is now the extent tree root (or a block map). - */ - force_reread = (new.dir->i_ino == old.dir->i_ino && - ext4_test_inode_flag(new.dir, EXT4_INODE_INLINE_DATA)); - - old_file_type = old.de->file_type; - if (whiteout) { - /* - * Do this before adding a new entry, so the old entry is sure - * to be still pointing to the valid old entry. - */ - retval = ext4_setent(handle, &old, whiteout->i_ino, - EXT4_FT_CHRDEV); - if (retval) - goto end_rename; - ext4_mark_inode_dirty(handle, whiteout); - } - if (!new.bh) { - retval = ext4_add_entry(handle, new.dentry, old.inode); - if (retval) - goto end_rename; - } else { - retval = ext4_setent(handle, &new, - old.inode->i_ino, old_file_type); - if (retval) - goto end_rename; - } - if (force_reread) - force_reread = !ext4_test_inode_flag(new.dir, - EXT4_INODE_INLINE_DATA); - - /* - * Like most other Unix systems, set the ctime for inodes on a - * rename. - */ - old.inode->i_ctime = ext4_current_time(old.inode); - ext4_mark_inode_dirty(handle, old.inode); - - if (!whiteout) { - /* - * ok, that's it - */ - ext4_rename_delete(handle, &old, force_reread); - } - - if (new.inode) { - ext4_dec_count(handle, new.inode); - new.inode->i_ctime = ext4_current_time(new.inode); - } - old.dir->i_ctime = old.dir->i_mtime = ext4_current_time(old.dir); - ext4_update_dx_flag(old.dir); - if (old.dir_bh) { - retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino); - if (retval) - goto end_rename; - - ext4_dec_count(handle, old.dir); - if (new.inode) { - /* checked ext4_empty_dir above, can't have another - * parent, ext4_dec_count() won't work for many-linked - * dirs */ - clear_nlink(new.inode); - } else { - ext4_inc_count(handle, new.dir); - ext4_update_dx_flag(new.dir); - ext4_mark_inode_dirty(handle, new.dir); - } - } - ext4_mark_inode_dirty(handle, old.dir); - if (new.inode) { - ext4_mark_inode_dirty(handle, new.inode); - if (!new.inode->i_nlink) - ext4_orphan_add(handle, new.inode); - } - retval = 0; - -end_rename: - brelse(old.dir_bh); - brelse(old.bh); - brelse(new.bh); - if (whiteout) { - if (retval) - drop_nlink(whiteout); - unlock_new_inode(whiteout); - iput(whiteout); - } - if (handle) - ext4_journal_stop(handle); - return retval; -} - -static int ext4_cross_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry) -{ - handle_t *handle = NULL; - struct ext4_renament old = { - .dir = old_dir, - .dentry = old_dentry, - .inode = d_inode(old_dentry), - }; - struct ext4_renament new = { - .dir = new_dir, - .dentry = new_dentry, - .inode = d_inode(new_dentry), - }; - u8 new_file_type; - int retval; - - if ((ext4_encrypted_inode(old_dir) || - ext4_encrypted_inode(new_dir)) && - (old_dir != new_dir) && - (!fscrypt_has_permitted_context(new_dir, old.inode) || - !fscrypt_has_permitted_context(old_dir, new.inode))) - return -EPERM; - - if ((ext4_test_inode_flag(new_dir, EXT4_INODE_PROJINHERIT) && - !projid_eq(EXT4_I(new_dir)->i_projid, - EXT4_I(old_dentry->d_inode)->i_projid)) || - (ext4_test_inode_flag(old_dir, EXT4_INODE_PROJINHERIT) && - !projid_eq(EXT4_I(old_dir)->i_projid, - EXT4_I(new_dentry->d_inode)->i_projid))) - return -EXDEV; - - retval = dquot_initialize(old.dir); - if (retval) - return retval; - retval = dquot_initialize(new.dir); - if (retval) - return retval; - - old.bh = ext4_find_entry(old.dir, &old.dentry->d_name, - &old.de, &old.inlined); - if (IS_ERR(old.bh)) - return PTR_ERR(old.bh); - /* - * Check for inode number is _not_ due to possible IO errors. - * We might rmdir the source, keep it as pwd of some process - * and merrily kill the link to whatever was created under the - * same name. Goodbye sticky bit ;-< - */ - retval = -ENOENT; - if (!old.bh || le32_to_cpu(old.de->inode) != old.inode->i_ino) - goto end_rename; - - new.bh = ext4_find_entry(new.dir, &new.dentry->d_name, - &new.de, &new.inlined); - if (IS_ERR(new.bh)) { - retval = PTR_ERR(new.bh); - new.bh = NULL; - goto end_rename; - } - - /* RENAME_EXCHANGE case: old *and* new must both exist */ - if (!new.bh || le32_to_cpu(new.de->inode) != new.inode->i_ino) - goto end_rename; - - handle = ext4_journal_start(old.dir, EXT4_HT_DIR, - (2 * EXT4_DATA_TRANS_BLOCKS(old.dir->i_sb) + - 2 * EXT4_INDEX_EXTRA_TRANS_BLOCKS + 2)); - if (IS_ERR(handle)) { - retval = PTR_ERR(handle); - handle = NULL; - goto end_rename; - } - - if (IS_DIRSYNC(old.dir) || IS_DIRSYNC(new.dir)) - ext4_handle_sync(handle); - - if (S_ISDIR(old.inode->i_mode)) { - old.is_dir = true; - retval = ext4_rename_dir_prepare(handle, &old); - if (retval) - goto end_rename; - } - if (S_ISDIR(new.inode->i_mode)) { - new.is_dir = true; - retval = ext4_rename_dir_prepare(handle, &new); - if (retval) - goto end_rename; - } - - /* - * Other than the special case of overwriting a directory, parents' - * nlink only needs to be modified if this is a cross directory rename. - */ - if (old.dir != new.dir && old.is_dir != new.is_dir) { - old.dir_nlink_delta = old.is_dir ? -1 : 1; - new.dir_nlink_delta = -old.dir_nlink_delta; - retval = -EMLINK; - if ((old.dir_nlink_delta > 0 && EXT4_DIR_LINK_MAX(old.dir)) || - (new.dir_nlink_delta > 0 && EXT4_DIR_LINK_MAX(new.dir))) - goto end_rename; - } - - new_file_type = new.de->file_type; - retval = ext4_setent(handle, &new, old.inode->i_ino, old.de->file_type); - if (retval) - goto end_rename; - - retval = ext4_setent(handle, &old, new.inode->i_ino, new_file_type); - if (retval) - goto end_rename; - - /* - * Like most other Unix systems, set the ctime for inodes on a - * rename. - */ - old.inode->i_ctime = ext4_current_time(old.inode); - new.inode->i_ctime = ext4_current_time(new.inode); - ext4_mark_inode_dirty(handle, old.inode); - ext4_mark_inode_dirty(handle, new.inode); - - if (old.dir_bh) { - retval = ext4_rename_dir_finish(handle, &old, new.dir->i_ino); - if (retval) - goto end_rename; - } - if (new.dir_bh) { - retval = ext4_rename_dir_finish(handle, &new, old.dir->i_ino); - if (retval) - goto end_rename; - } - ext4_update_dir_count(handle, &old); - ext4_update_dir_count(handle, &new); - retval = 0; - -end_rename: - brelse(old.dir_bh); - brelse(new.dir_bh); - brelse(old.bh); - brelse(new.bh); - if (handle) - ext4_journal_stop(handle); - return retval; -} - -static int ext4_rename2(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry, - unsigned int flags) -{ - if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) - return -EINVAL; - - if (flags & RENAME_EXCHANGE) { - return ext4_cross_rename(old_dir, old_dentry, - new_dir, new_dentry); - } - - return ext4_rename(old_dir, old_dentry, new_dir, new_dentry, flags); -} - -/* - * directories can handle most operations... - */ -const struct inode_operations ext4_dir_inode_operations = { - .create = ext4_create, - .lookup = ext4_lookup, - .link = ext4_link, - .unlink = ext4_unlink, - .symlink = ext4_symlink, - .mkdir = ext4_mkdir, - .rmdir = ext4_rmdir, - .mknod = ext4_mknod, - .tmpfile = ext4_tmpfile, - .rename = ext4_rename2, - .setattr = ext4_setattr, - .listxattr = ext4_listxattr, - .get_acl = ext4_get_acl, - .set_acl = ext4_set_acl, - .fiemap = ext4_fiemap, -}; - -const struct inode_operations ext4_special_inode_operations = { - .setattr = ext4_setattr, - .listxattr = ext4_listxattr, - .get_acl = ext4_get_acl, - .set_acl = ext4_set_acl, -}; diff --git a/src/linux/fs/ext4/page-io.c b/src/linux/fs/ext4/page-io.c deleted file mode 100644 index 0094923..0000000 --- a/src/linux/fs/ext4/page-io.c +++ /dev/null @@ -1,524 +0,0 @@ -/* - * linux/fs/ext4/page-io.c - * - * This contains the new page_io functions for ext4 - * - * Written by Theodore Ts'o, 2010. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ext4_jbd2.h" -#include "xattr.h" -#include "acl.h" - -static struct kmem_cache *io_end_cachep; - -int __init ext4_init_pageio(void) -{ - io_end_cachep = KMEM_CACHE(ext4_io_end, SLAB_RECLAIM_ACCOUNT); - if (io_end_cachep == NULL) - return -ENOMEM; - return 0; -} - -void ext4_exit_pageio(void) -{ - kmem_cache_destroy(io_end_cachep); -} - -/* - * Print an buffer I/O error compatible with the fs/buffer.c. This - * provides compatibility with dmesg scrapers that look for a specific - * buffer I/O error message. We really need a unified error reporting - * structure to userspace ala Digital Unix's uerf system, but it's - * probably not going to happen in my lifetime, due to LKML politics... - */ -static void buffer_io_error(struct buffer_head *bh) -{ - printk_ratelimited(KERN_ERR "Buffer I/O error on device %pg, logical block %llu\n", - bh->b_bdev, - (unsigned long long)bh->b_blocknr); -} - -static void ext4_finish_bio(struct bio *bio) -{ - int i; - struct bio_vec *bvec; - - bio_for_each_segment_all(bvec, bio, i) { - struct page *page = bvec->bv_page; -#ifdef CONFIG_EXT4_FS_ENCRYPTION - struct page *data_page = NULL; -#endif - struct buffer_head *bh, *head; - unsigned bio_start = bvec->bv_offset; - unsigned bio_end = bio_start + bvec->bv_len; - unsigned under_io = 0; - unsigned long flags; - - if (!page) - continue; - -#ifdef CONFIG_EXT4_FS_ENCRYPTION - if (!page->mapping) { - /* The bounce data pages are unmapped. */ - data_page = page; - fscrypt_pullback_bio_page(&page, false); - } -#endif - - if (bio->bi_error) { - SetPageError(page); - mapping_set_error(page->mapping, -EIO); - } - bh = head = page_buffers(page); - /* - * We check all buffers in the page under BH_Uptodate_Lock - * to avoid races with other end io clearing async_write flags - */ - local_irq_save(flags); - bit_spin_lock(BH_Uptodate_Lock, &head->b_state); - do { - if (bh_offset(bh) < bio_start || - bh_offset(bh) + bh->b_size > bio_end) { - if (buffer_async_write(bh)) - under_io++; - continue; - } - clear_buffer_async_write(bh); - if (bio->bi_error) - buffer_io_error(bh); - } while ((bh = bh->b_this_page) != head); - bit_spin_unlock(BH_Uptodate_Lock, &head->b_state); - local_irq_restore(flags); - if (!under_io) { -#ifdef CONFIG_EXT4_FS_ENCRYPTION - if (data_page) - fscrypt_restore_control_page(data_page); -#endif - end_page_writeback(page); - } - } -} - -static void ext4_release_io_end(ext4_io_end_t *io_end) -{ - struct bio *bio, *next_bio; - - BUG_ON(!list_empty(&io_end->list)); - BUG_ON(io_end->flag & EXT4_IO_END_UNWRITTEN); - WARN_ON(io_end->handle); - - for (bio = io_end->bio; bio; bio = next_bio) { - next_bio = bio->bi_private; - ext4_finish_bio(bio); - bio_put(bio); - } - kmem_cache_free(io_end_cachep, io_end); -} - -/* - * Check a range of space and convert unwritten extents to written. Note that - * we are protected from truncate touching same part of extent tree by the - * fact that truncate code waits for all DIO to finish (thus exclusion from - * direct IO is achieved) and also waits for PageWriteback bits. Thus we - * cannot get to ext4_ext_truncate() before all IOs overlapping that range are - * completed (happens from ext4_free_ioend()). - */ -static int ext4_end_io(ext4_io_end_t *io) -{ - struct inode *inode = io->inode; - loff_t offset = io->offset; - ssize_t size = io->size; - handle_t *handle = io->handle; - int ret = 0; - - ext4_debug("ext4_end_io_nolock: io 0x%p from inode %lu,list->next 0x%p," - "list->prev 0x%p\n", - io, inode->i_ino, io->list.next, io->list.prev); - - io->handle = NULL; /* Following call will use up the handle */ - ret = ext4_convert_unwritten_extents(handle, inode, offset, size); - if (ret < 0) { - ext4_msg(inode->i_sb, KERN_EMERG, - "failed to convert unwritten extents to written " - "extents -- potential data loss! " - "(inode %lu, offset %llu, size %zd, error %d)", - inode->i_ino, offset, size, ret); - } - ext4_clear_io_unwritten_flag(io); - ext4_release_io_end(io); - return ret; -} - -static void dump_completed_IO(struct inode *inode, struct list_head *head) -{ -#ifdef EXT4FS_DEBUG - struct list_head *cur, *before, *after; - ext4_io_end_t *io, *io0, *io1; - - if (list_empty(head)) - return; - - ext4_debug("Dump inode %lu completed io list\n", inode->i_ino); - list_for_each_entry(io, head, list) { - cur = &io->list; - before = cur->prev; - io0 = container_of(before, ext4_io_end_t, list); - after = cur->next; - io1 = container_of(after, ext4_io_end_t, list); - - ext4_debug("io 0x%p from inode %lu,prev 0x%p,next 0x%p\n", - io, inode->i_ino, io0, io1); - } -#endif -} - -/* Add the io_end to per-inode completed end_io list. */ -static void ext4_add_complete_io(ext4_io_end_t *io_end) -{ - struct ext4_inode_info *ei = EXT4_I(io_end->inode); - struct ext4_sb_info *sbi = EXT4_SB(io_end->inode->i_sb); - struct workqueue_struct *wq; - unsigned long flags; - - /* Only reserved conversions from writeback should enter here */ - WARN_ON(!(io_end->flag & EXT4_IO_END_UNWRITTEN)); - WARN_ON(!io_end->handle && sbi->s_journal); - spin_lock_irqsave(&ei->i_completed_io_lock, flags); - wq = sbi->rsv_conversion_wq; - if (list_empty(&ei->i_rsv_conversion_list)) - queue_work(wq, &ei->i_rsv_conversion_work); - list_add_tail(&io_end->list, &ei->i_rsv_conversion_list); - spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); -} - -static int ext4_do_flush_completed_IO(struct inode *inode, - struct list_head *head) -{ - ext4_io_end_t *io; - struct list_head unwritten; - unsigned long flags; - struct ext4_inode_info *ei = EXT4_I(inode); - int err, ret = 0; - - spin_lock_irqsave(&ei->i_completed_io_lock, flags); - dump_completed_IO(inode, head); - list_replace_init(head, &unwritten); - spin_unlock_irqrestore(&ei->i_completed_io_lock, flags); - - while (!list_empty(&unwritten)) { - io = list_entry(unwritten.next, ext4_io_end_t, list); - BUG_ON(!(io->flag & EXT4_IO_END_UNWRITTEN)); - list_del_init(&io->list); - - err = ext4_end_io(io); - if (unlikely(!ret && err)) - ret = err; - } - return ret; -} - -/* - * work on completed IO, to convert unwritten extents to extents - */ -void ext4_end_io_rsv_work(struct work_struct *work) -{ - struct ext4_inode_info *ei = container_of(work, struct ext4_inode_info, - i_rsv_conversion_work); - ext4_do_flush_completed_IO(&ei->vfs_inode, &ei->i_rsv_conversion_list); -} - -ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags) -{ - ext4_io_end_t *io = kmem_cache_zalloc(io_end_cachep, flags); - if (io) { - io->inode = inode; - INIT_LIST_HEAD(&io->list); - atomic_set(&io->count, 1); - } - return io; -} - -void ext4_put_io_end_defer(ext4_io_end_t *io_end) -{ - if (atomic_dec_and_test(&io_end->count)) { - if (!(io_end->flag & EXT4_IO_END_UNWRITTEN) || !io_end->size) { - ext4_release_io_end(io_end); - return; - } - ext4_add_complete_io(io_end); - } -} - -int ext4_put_io_end(ext4_io_end_t *io_end) -{ - int err = 0; - - if (atomic_dec_and_test(&io_end->count)) { - if (io_end->flag & EXT4_IO_END_UNWRITTEN) { - err = ext4_convert_unwritten_extents(io_end->handle, - io_end->inode, io_end->offset, - io_end->size); - io_end->handle = NULL; - ext4_clear_io_unwritten_flag(io_end); - } - ext4_release_io_end(io_end); - } - return err; -} - -ext4_io_end_t *ext4_get_io_end(ext4_io_end_t *io_end) -{ - atomic_inc(&io_end->count); - return io_end; -} - -/* BIO completion function for page writeback */ -static void ext4_end_bio(struct bio *bio) -{ - ext4_io_end_t *io_end = bio->bi_private; - sector_t bi_sector = bio->bi_iter.bi_sector; - - BUG_ON(!io_end); - bio->bi_end_io = NULL; - - if (bio->bi_error) { - struct inode *inode = io_end->inode; - - ext4_warning(inode->i_sb, "I/O error %d writing to inode %lu " - "(offset %llu size %ld starting block %llu)", - bio->bi_error, inode->i_ino, - (unsigned long long) io_end->offset, - (long) io_end->size, - (unsigned long long) - bi_sector >> (inode->i_blkbits - 9)); - mapping_set_error(inode->i_mapping, bio->bi_error); - } - - if (io_end->flag & EXT4_IO_END_UNWRITTEN) { - /* - * Link bio into list hanging from io_end. We have to do it - * atomically as bio completions can be racing against each - * other. - */ - bio->bi_private = xchg(&io_end->bio, bio); - ext4_put_io_end_defer(io_end); - } else { - /* - * Drop io_end reference early. Inode can get freed once - * we finish the bio. - */ - ext4_put_io_end_defer(io_end); - ext4_finish_bio(bio); - bio_put(bio); - } -} - -void ext4_io_submit(struct ext4_io_submit *io) -{ - struct bio *bio = io->io_bio; - - if (bio) { - int io_op_flags = io->io_wbc->sync_mode == WB_SYNC_ALL ? - WRITE_SYNC : 0; - bio_set_op_attrs(io->io_bio, REQ_OP_WRITE, io_op_flags); - submit_bio(io->io_bio); - } - io->io_bio = NULL; -} - -void ext4_io_submit_init(struct ext4_io_submit *io, - struct writeback_control *wbc) -{ - io->io_wbc = wbc; - io->io_bio = NULL; - io->io_end = NULL; -} - -static int io_submit_init_bio(struct ext4_io_submit *io, - struct buffer_head *bh) -{ - struct bio *bio; - - bio = bio_alloc(GFP_NOIO, BIO_MAX_PAGES); - if (!bio) - return -ENOMEM; - wbc_init_bio(io->io_wbc, bio); - bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9); - bio->bi_bdev = bh->b_bdev; - bio->bi_end_io = ext4_end_bio; - bio->bi_private = ext4_get_io_end(io->io_end); - io->io_bio = bio; - io->io_next_block = bh->b_blocknr; - return 0; -} - -static int io_submit_add_bh(struct ext4_io_submit *io, - struct inode *inode, - struct page *page, - struct buffer_head *bh) -{ - int ret; - - if (io->io_bio && bh->b_blocknr != io->io_next_block) { -submit_and_retry: - ext4_io_submit(io); - } - if (io->io_bio == NULL) { - ret = io_submit_init_bio(io, bh); - if (ret) - return ret; - } - ret = bio_add_page(io->io_bio, page, bh->b_size, bh_offset(bh)); - if (ret != bh->b_size) - goto submit_and_retry; - wbc_account_io(io->io_wbc, page, bh->b_size); - io->io_next_block++; - return 0; -} - -int ext4_bio_write_page(struct ext4_io_submit *io, - struct page *page, - int len, - struct writeback_control *wbc, - bool keep_towrite) -{ - struct page *data_page = NULL; - struct inode *inode = page->mapping->host; - unsigned block_start; - struct buffer_head *bh, *head; - int ret = 0; - int nr_submitted = 0; - int nr_to_submit = 0; - - BUG_ON(!PageLocked(page)); - BUG_ON(PageWriteback(page)); - - if (keep_towrite) - set_page_writeback_keepwrite(page); - else - set_page_writeback(page); - ClearPageError(page); - - /* - * Comments copied from block_write_full_page: - * - * The page straddles i_size. It must be zeroed out on each and every - * writepage invocation because it may be mmapped. "A file is mapped - * in multiples of the page size. For a file that is not a multiple of - * the page size, the remaining memory is zeroed when mapped, and - * writes to that region are not written out to the file." - */ - if (len < PAGE_SIZE) - zero_user_segment(page, len, PAGE_SIZE); - /* - * In the first loop we prepare and mark buffers to submit. We have to - * mark all buffers in the page before submitting so that - * end_page_writeback() cannot be called from ext4_bio_end_io() when IO - * on the first buffer finishes and we are still working on submitting - * the second buffer. - */ - bh = head = page_buffers(page); - do { - block_start = bh_offset(bh); - if (block_start >= len) { - clear_buffer_dirty(bh); - set_buffer_uptodate(bh); - continue; - } - if (!buffer_dirty(bh) || buffer_delay(bh) || - !buffer_mapped(bh) || buffer_unwritten(bh)) { - /* A hole? We can safely clear the dirty bit */ - if (!buffer_mapped(bh)) - clear_buffer_dirty(bh); - if (io->io_bio) - ext4_io_submit(io); - continue; - } - if (buffer_new(bh)) { - clear_buffer_new(bh); - unmap_underlying_metadata(bh->b_bdev, bh->b_blocknr); - } - set_buffer_async_write(bh); - nr_to_submit++; - } while ((bh = bh->b_this_page) != head); - - bh = head = page_buffers(page); - - if (ext4_encrypted_inode(inode) && S_ISREG(inode->i_mode) && - nr_to_submit) { - gfp_t gfp_flags = GFP_NOFS; - - retry_encrypt: - data_page = fscrypt_encrypt_page(inode, page, gfp_flags); - if (IS_ERR(data_page)) { - ret = PTR_ERR(data_page); - if (ret == -ENOMEM && wbc->sync_mode == WB_SYNC_ALL) { - if (io->io_bio) { - ext4_io_submit(io); - congestion_wait(BLK_RW_ASYNC, HZ/50); - } - gfp_flags |= __GFP_NOFAIL; - goto retry_encrypt; - } - data_page = NULL; - goto out; - } - } - - /* Now submit buffers to write */ - do { - if (!buffer_async_write(bh)) - continue; - ret = io_submit_add_bh(io, inode, - data_page ? data_page : page, bh); - if (ret) { - /* - * We only get here on ENOMEM. Not much else - * we can do but mark the page as dirty, and - * better luck next time. - */ - break; - } - nr_submitted++; - clear_buffer_dirty(bh); - } while ((bh = bh->b_this_page) != head); - - /* Error stopped previous loop? Clean up buffers... */ - if (ret) { - out: - if (data_page) - fscrypt_restore_control_page(data_page); - printk_ratelimited(KERN_ERR "%s: ret = %d\n", __func__, ret); - redirty_page_for_writepage(wbc, page); - do { - clear_buffer_async_write(bh); - bh = bh->b_this_page; - } while (bh != head); - } - unlock_page(page); - /* Nothing submitted - we have to end page writeback */ - if (!nr_submitted) - end_page_writeback(page); - return ret; -} diff --git a/src/linux/fs/ext4/readpage.c b/src/linux/fs/ext4/readpage.c deleted file mode 100644 index a81b829..0000000 --- a/src/linux/fs/ext4/readpage.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * linux/fs/ext4/readpage.c - * - * Copyright (C) 2002, Linus Torvalds. - * Copyright (C) 2015, Google, Inc. - * - * This was originally taken from fs/mpage.c - * - * The intent is the ext4_mpage_readpages() function here is intended - * to replace mpage_readpages() in the general case, not just for - * encrypted files. It has some limitations (see below), where it - * will fall back to read_block_full_page(), but these limitations - * should only be hit when page_size != block_size. - * - * This will allow us to attach a callback function to support ext4 - * encryption. - * - * If anything unusual happens, such as: - * - * - encountering a page which has buffers - * - encountering a page which has a non-hole after a hole - * - encountering a page with non-contiguous blocks - * - * then this code just gives up and calls the buffer_head-based read function. - * It does handle a page which has holes at the end - that is a common case: - * the end-of-file on blocksize < PAGE_SIZE setups. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ext4.h" - -static inline bool ext4_bio_encrypted(struct bio *bio) -{ -#ifdef CONFIG_EXT4_FS_ENCRYPTION - return unlikely(bio->bi_private != NULL); -#else - return false; -#endif -} - -/* - * I/O completion handler for multipage BIOs. - * - * The mpage code never puts partial pages into a BIO (except for end-of-file). - * If a page does not map to a contiguous run of blocks then it simply falls - * back to block_read_full_page(). - * - * Why is this? If a page's completion depends on a number of different BIOs - * which can complete in any order (or at the same time) then determining the - * status of that page is hard. See end_buffer_async_read() for the details. - * There is no point in duplicating all that complexity. - */ -static void mpage_end_io(struct bio *bio) -{ - struct bio_vec *bv; - int i; - - if (ext4_bio_encrypted(bio)) { - if (bio->bi_error) { - fscrypt_release_ctx(bio->bi_private); - } else { - fscrypt_decrypt_bio_pages(bio->bi_private, bio); - return; - } - } - bio_for_each_segment_all(bv, bio, i) { - struct page *page = bv->bv_page; - - if (!bio->bi_error) { - SetPageUptodate(page); - } else { - ClearPageUptodate(page); - SetPageError(page); - } - unlock_page(page); - } - - bio_put(bio); -} - -int ext4_mpage_readpages(struct address_space *mapping, - struct list_head *pages, struct page *page, - unsigned nr_pages) -{ - struct bio *bio = NULL; - sector_t last_block_in_bio = 0; - - struct inode *inode = mapping->host; - const unsigned blkbits = inode->i_blkbits; - const unsigned blocks_per_page = PAGE_SIZE >> blkbits; - const unsigned blocksize = 1 << blkbits; - sector_t block_in_file; - sector_t last_block; - sector_t last_block_in_file; - sector_t blocks[MAX_BUF_PER_PAGE]; - unsigned page_block; - struct block_device *bdev = inode->i_sb->s_bdev; - int length; - unsigned relative_block = 0; - struct ext4_map_blocks map; - - map.m_pblk = 0; - map.m_lblk = 0; - map.m_len = 0; - map.m_flags = 0; - - for (; nr_pages; nr_pages--) { - int fully_mapped = 1; - unsigned first_hole = blocks_per_page; - - prefetchw(&page->flags); - if (pages) { - page = list_entry(pages->prev, struct page, lru); - list_del(&page->lru); - if (add_to_page_cache_lru(page, mapping, page->index, - readahead_gfp_mask(mapping))) - goto next_page; - } - - if (page_has_buffers(page)) - goto confused; - - block_in_file = (sector_t)page->index << (PAGE_SHIFT - blkbits); - last_block = block_in_file + nr_pages * blocks_per_page; - last_block_in_file = (i_size_read(inode) + blocksize - 1) >> blkbits; - if (last_block > last_block_in_file) - last_block = last_block_in_file; - page_block = 0; - - /* - * Map blocks using the previous result first. - */ - if ((map.m_flags & EXT4_MAP_MAPPED) && - block_in_file > map.m_lblk && - block_in_file < (map.m_lblk + map.m_len)) { - unsigned map_offset = block_in_file - map.m_lblk; - unsigned last = map.m_len - map_offset; - - for (relative_block = 0; ; relative_block++) { - if (relative_block == last) { - /* needed? */ - map.m_flags &= ~EXT4_MAP_MAPPED; - break; - } - if (page_block == blocks_per_page) - break; - blocks[page_block] = map.m_pblk + map_offset + - relative_block; - page_block++; - block_in_file++; - } - } - - /* - * Then do more ext4_map_blocks() calls until we are - * done with this page. - */ - while (page_block < blocks_per_page) { - if (block_in_file < last_block) { - map.m_lblk = block_in_file; - map.m_len = last_block - block_in_file; - - if (ext4_map_blocks(NULL, inode, &map, 0) < 0) { - set_error_page: - SetPageError(page); - zero_user_segment(page, 0, - PAGE_SIZE); - unlock_page(page); - goto next_page; - } - } - if ((map.m_flags & EXT4_MAP_MAPPED) == 0) { - fully_mapped = 0; - if (first_hole == blocks_per_page) - first_hole = page_block; - page_block++; - block_in_file++; - continue; - } - if (first_hole != blocks_per_page) - goto confused; /* hole -> non-hole */ - - /* Contiguous blocks? */ - if (page_block && blocks[page_block-1] != map.m_pblk-1) - goto confused; - for (relative_block = 0; ; relative_block++) { - if (relative_block == map.m_len) { - /* needed? */ - map.m_flags &= ~EXT4_MAP_MAPPED; - break; - } else if (page_block == blocks_per_page) - break; - blocks[page_block] = map.m_pblk+relative_block; - page_block++; - block_in_file++; - } - } - if (first_hole != blocks_per_page) { - zero_user_segment(page, first_hole << blkbits, - PAGE_SIZE); - if (first_hole == 0) { - SetPageUptodate(page); - unlock_page(page); - goto next_page; - } - } else if (fully_mapped) { - SetPageMappedToDisk(page); - } - if (fully_mapped && blocks_per_page == 1 && - !PageUptodate(page) && cleancache_get_page(page) == 0) { - SetPageUptodate(page); - goto confused; - } - - /* - * This page will go to BIO. Do we need to send this - * BIO off first? - */ - if (bio && (last_block_in_bio != blocks[0] - 1)) { - submit_and_realloc: - submit_bio(bio); - bio = NULL; - } - if (bio == NULL) { - struct fscrypt_ctx *ctx = NULL; - - if (ext4_encrypted_inode(inode) && - S_ISREG(inode->i_mode)) { - ctx = fscrypt_get_ctx(inode, GFP_NOFS); - if (IS_ERR(ctx)) - goto set_error_page; - } - bio = bio_alloc(GFP_KERNEL, - min_t(int, nr_pages, BIO_MAX_PAGES)); - if (!bio) { - if (ctx) - fscrypt_release_ctx(ctx); - goto set_error_page; - } - bio->bi_bdev = bdev; - bio->bi_iter.bi_sector = blocks[0] << (blkbits - 9); - bio->bi_end_io = mpage_end_io; - bio->bi_private = ctx; - bio_set_op_attrs(bio, REQ_OP_READ, 0); - } - - length = first_hole << blkbits; - if (bio_add_page(bio, page, length, 0) < length) - goto submit_and_realloc; - - if (((map.m_flags & EXT4_MAP_BOUNDARY) && - (relative_block == map.m_len)) || - (first_hole != blocks_per_page)) { - submit_bio(bio); - bio = NULL; - } else - last_block_in_bio = blocks[blocks_per_page - 1]; - goto next_page; - confused: - if (bio) { - submit_bio(bio); - bio = NULL; - } - if (!PageUptodate(page)) - block_read_full_page(page, ext4_get_block); - else - unlock_page(page); - next_page: - if (pages) - put_page(page); - } - BUG_ON(pages && !list_empty(pages)); - if (bio) - submit_bio(bio); - return 0; -} diff --git a/src/linux/fs/ext4/resize.c b/src/linux/fs/ext4/resize.c deleted file mode 100644 index cf68100..0000000 --- a/src/linux/fs/ext4/resize.c +++ /dev/null @@ -1,2018 +0,0 @@ -/* - * linux/fs/ext4/resize.c - * - * Support for resizing an ext4 filesystem while it is mounted. - * - * Copyright (C) 2001, 2002 Andreas Dilger - * - * This could probably be made into a module, because it is not often in use. - */ - - -#define EXT4FS_DEBUG - -#include -#include - -#include "ext4_jbd2.h" - -int ext4_resize_begin(struct super_block *sb) -{ - int ret = 0; - - if (!capable(CAP_SYS_RESOURCE)) - return -EPERM; - - /* - * If we are not using the primary superblock/GDT copy don't resize, - * because the user tools have no way of handling this. Probably a - * bad time to do it anyways. - */ - if (EXT4_SB(sb)->s_sbh->b_blocknr != - le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block)) { - ext4_warning(sb, "won't resize using backup superblock at %llu", - (unsigned long long)EXT4_SB(sb)->s_sbh->b_blocknr); - return -EPERM; - } - - /* - * We are not allowed to do online-resizing on a filesystem mounted - * with error, because it can destroy the filesystem easily. - */ - if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) { - ext4_warning(sb, "There are errors in the filesystem, " - "so online resizing is not allowed"); - return -EPERM; - } - - if (test_and_set_bit_lock(EXT4_RESIZING, &EXT4_SB(sb)->s_resize_flags)) - ret = -EBUSY; - - return ret; -} - -void ext4_resize_end(struct super_block *sb) -{ - clear_bit_unlock(EXT4_RESIZING, &EXT4_SB(sb)->s_resize_flags); - smp_mb__after_atomic(); -} - -static ext4_group_t ext4_meta_bg_first_group(struct super_block *sb, - ext4_group_t group) { - return (group >> EXT4_DESC_PER_BLOCK_BITS(sb)) << - EXT4_DESC_PER_BLOCK_BITS(sb); -} - -static ext4_fsblk_t ext4_meta_bg_first_block_no(struct super_block *sb, - ext4_group_t group) { - group = ext4_meta_bg_first_group(sb, group); - return ext4_group_first_block_no(sb, group); -} - -static ext4_grpblk_t ext4_group_overhead_blocks(struct super_block *sb, - ext4_group_t group) { - ext4_grpblk_t overhead; - overhead = ext4_bg_num_gdb(sb, group); - if (ext4_bg_has_super(sb, group)) - overhead += 1 + - le16_to_cpu(EXT4_SB(sb)->s_es->s_reserved_gdt_blocks); - return overhead; -} - -#define outside(b, first, last) ((b) < (first) || (b) >= (last)) -#define inside(b, first, last) ((b) >= (first) && (b) < (last)) - -static int verify_group_input(struct super_block *sb, - struct ext4_new_group_data *input) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_super_block *es = sbi->s_es; - ext4_fsblk_t start = ext4_blocks_count(es); - ext4_fsblk_t end = start + input->blocks_count; - ext4_group_t group = input->group; - ext4_fsblk_t itend = input->inode_table + sbi->s_itb_per_group; - unsigned overhead; - ext4_fsblk_t metaend; - struct buffer_head *bh = NULL; - ext4_grpblk_t free_blocks_count, offset; - int err = -EINVAL; - - if (group != sbi->s_groups_count) { - ext4_warning(sb, "Cannot add at group %u (only %u groups)", - input->group, sbi->s_groups_count); - return -EINVAL; - } - - overhead = ext4_group_overhead_blocks(sb, group); - metaend = start + overhead; - input->free_blocks_count = free_blocks_count = - input->blocks_count - 2 - overhead - sbi->s_itb_per_group; - - if (test_opt(sb, DEBUG)) - printk(KERN_DEBUG "EXT4-fs: adding %s group %u: %u blocks " - "(%d free, %u reserved)\n", - ext4_bg_has_super(sb, input->group) ? "normal" : - "no-super", input->group, input->blocks_count, - free_blocks_count, input->reserved_blocks); - - ext4_get_group_no_and_offset(sb, start, NULL, &offset); - if (offset != 0) - ext4_warning(sb, "Last group not full"); - else if (input->reserved_blocks > input->blocks_count / 5) - ext4_warning(sb, "Reserved blocks too high (%u)", - input->reserved_blocks); - else if (free_blocks_count < 0) - ext4_warning(sb, "Bad blocks count %u", - input->blocks_count); - else if (!(bh = sb_bread(sb, end - 1))) - ext4_warning(sb, "Cannot read last block (%llu)", - end - 1); - else if (outside(input->block_bitmap, start, end)) - ext4_warning(sb, "Block bitmap not in group (block %llu)", - (unsigned long long)input->block_bitmap); - else if (outside(input->inode_bitmap, start, end)) - ext4_warning(sb, "Inode bitmap not in group (block %llu)", - (unsigned long long)input->inode_bitmap); - else if (outside(input->inode_table, start, end) || - outside(itend - 1, start, end)) - ext4_warning(sb, "Inode table not in group (blocks %llu-%llu)", - (unsigned long long)input->inode_table, itend - 1); - else if (input->inode_bitmap == input->block_bitmap) - ext4_warning(sb, "Block bitmap same as inode bitmap (%llu)", - (unsigned long long)input->block_bitmap); - else if (inside(input->block_bitmap, input->inode_table, itend)) - ext4_warning(sb, "Block bitmap (%llu) in inode table " - "(%llu-%llu)", - (unsigned long long)input->block_bitmap, - (unsigned long long)input->inode_table, itend - 1); - else if (inside(input->inode_bitmap, input->inode_table, itend)) - ext4_warning(sb, "Inode bitmap (%llu) in inode table " - "(%llu-%llu)", - (unsigned long long)input->inode_bitmap, - (unsigned long long)input->inode_table, itend - 1); - else if (inside(input->block_bitmap, start, metaend)) - ext4_warning(sb, "Block bitmap (%llu) in GDT table (%llu-%llu)", - (unsigned long long)input->block_bitmap, - start, metaend - 1); - else if (inside(input->inode_bitmap, start, metaend)) - ext4_warning(sb, "Inode bitmap (%llu) in GDT table (%llu-%llu)", - (unsigned long long)input->inode_bitmap, - start, metaend - 1); - else if (inside(input->inode_table, start, metaend) || - inside(itend - 1, start, metaend)) - ext4_warning(sb, "Inode table (%llu-%llu) overlaps GDT table " - "(%llu-%llu)", - (unsigned long long)input->inode_table, - itend - 1, start, metaend - 1); - else - err = 0; - brelse(bh); - - return err; -} - -/* - * ext4_new_flex_group_data is used by 64bit-resize interface to add a flex - * group each time. - */ -struct ext4_new_flex_group_data { - struct ext4_new_group_data *groups; /* new_group_data for groups - in the flex group */ - __u16 *bg_flags; /* block group flags of groups - in @groups */ - ext4_group_t count; /* number of groups in @groups - */ -}; - -/* - * alloc_flex_gd() allocates a ext4_new_flex_group_data with size of - * @flexbg_size. - * - * Returns NULL on failure otherwise address of the allocated structure. - */ -static struct ext4_new_flex_group_data *alloc_flex_gd(unsigned long flexbg_size) -{ - struct ext4_new_flex_group_data *flex_gd; - - flex_gd = kmalloc(sizeof(*flex_gd), GFP_NOFS); - if (flex_gd == NULL) - goto out3; - - if (flexbg_size >= UINT_MAX / sizeof(struct ext4_new_group_data)) - goto out2; - flex_gd->count = flexbg_size; - - flex_gd->groups = kmalloc(sizeof(struct ext4_new_group_data) * - flexbg_size, GFP_NOFS); - if (flex_gd->groups == NULL) - goto out2; - - flex_gd->bg_flags = kmalloc(flexbg_size * sizeof(__u16), GFP_NOFS); - if (flex_gd->bg_flags == NULL) - goto out1; - - return flex_gd; - -out1: - kfree(flex_gd->groups); -out2: - kfree(flex_gd); -out3: - return NULL; -} - -static void free_flex_gd(struct ext4_new_flex_group_data *flex_gd) -{ - kfree(flex_gd->bg_flags); - kfree(flex_gd->groups); - kfree(flex_gd); -} - -/* - * ext4_alloc_group_tables() allocates block bitmaps, inode bitmaps - * and inode tables for a flex group. - * - * This function is used by 64bit-resize. Note that this function allocates - * group tables from the 1st group of groups contained by @flexgd, which may - * be a partial of a flex group. - * - * @sb: super block of fs to which the groups belongs - * - * Returns 0 on a successful allocation of the metadata blocks in the - * block group. - */ -static int ext4_alloc_group_tables(struct super_block *sb, - struct ext4_new_flex_group_data *flex_gd, - int flexbg_size) -{ - struct ext4_new_group_data *group_data = flex_gd->groups; - ext4_fsblk_t start_blk; - ext4_fsblk_t last_blk; - ext4_group_t src_group; - ext4_group_t bb_index = 0; - ext4_group_t ib_index = 0; - ext4_group_t it_index = 0; - ext4_group_t group; - ext4_group_t last_group; - unsigned overhead; - __u16 uninit_mask = (flexbg_size > 1) ? ~EXT4_BG_BLOCK_UNINIT : ~0; - - BUG_ON(flex_gd->count == 0 || group_data == NULL); - - src_group = group_data[0].group; - last_group = src_group + flex_gd->count - 1; - - BUG_ON((flexbg_size > 1) && ((src_group & ~(flexbg_size - 1)) != - (last_group & ~(flexbg_size - 1)))); -next_group: - group = group_data[0].group; - if (src_group >= group_data[0].group + flex_gd->count) - return -ENOSPC; - start_blk = ext4_group_first_block_no(sb, src_group); - last_blk = start_blk + group_data[src_group - group].blocks_count; - - overhead = ext4_group_overhead_blocks(sb, src_group); - - start_blk += overhead; - - /* We collect contiguous blocks as much as possible. */ - src_group++; - for (; src_group <= last_group; src_group++) { - overhead = ext4_group_overhead_blocks(sb, src_group); - if (overhead == 0) - last_blk += group_data[src_group - group].blocks_count; - else - break; - } - - /* Allocate block bitmaps */ - for (; bb_index < flex_gd->count; bb_index++) { - if (start_blk >= last_blk) - goto next_group; - group_data[bb_index].block_bitmap = start_blk++; - group = ext4_get_group_number(sb, start_blk - 1); - group -= group_data[0].group; - group_data[group].free_blocks_count--; - flex_gd->bg_flags[group] &= uninit_mask; - } - - /* Allocate inode bitmaps */ - for (; ib_index < flex_gd->count; ib_index++) { - if (start_blk >= last_blk) - goto next_group; - group_data[ib_index].inode_bitmap = start_blk++; - group = ext4_get_group_number(sb, start_blk - 1); - group -= group_data[0].group; - group_data[group].free_blocks_count--; - flex_gd->bg_flags[group] &= uninit_mask; - } - - /* Allocate inode tables */ - for (; it_index < flex_gd->count; it_index++) { - unsigned int itb = EXT4_SB(sb)->s_itb_per_group; - ext4_fsblk_t next_group_start; - - if (start_blk + itb > last_blk) - goto next_group; - group_data[it_index].inode_table = start_blk; - group = ext4_get_group_number(sb, start_blk); - next_group_start = ext4_group_first_block_no(sb, group + 1); - group -= group_data[0].group; - - if (start_blk + itb > next_group_start) { - flex_gd->bg_flags[group + 1] &= uninit_mask; - overhead = start_blk + itb - next_group_start; - group_data[group + 1].free_blocks_count -= overhead; - itb -= overhead; - } - - group_data[group].free_blocks_count -= itb; - flex_gd->bg_flags[group] &= uninit_mask; - start_blk += EXT4_SB(sb)->s_itb_per_group; - } - - if (test_opt(sb, DEBUG)) { - int i; - group = group_data[0].group; - - printk(KERN_DEBUG "EXT4-fs: adding a flex group with " - "%d groups, flexbg size is %d:\n", flex_gd->count, - flexbg_size); - - for (i = 0; i < flex_gd->count; i++) { - printk(KERN_DEBUG "adding %s group %u: %u " - "blocks (%d free)\n", - ext4_bg_has_super(sb, group + i) ? "normal" : - "no-super", group + i, - group_data[i].blocks_count, - group_data[i].free_blocks_count); - } - } - return 0; -} - -static struct buffer_head *bclean(handle_t *handle, struct super_block *sb, - ext4_fsblk_t blk) -{ - struct buffer_head *bh; - int err; - - bh = sb_getblk(sb, blk); - if (unlikely(!bh)) - return ERR_PTR(-ENOMEM); - BUFFER_TRACE(bh, "get_write_access"); - if ((err = ext4_journal_get_write_access(handle, bh))) { - brelse(bh); - bh = ERR_PTR(err); - } else { - memset(bh->b_data, 0, sb->s_blocksize); - set_buffer_uptodate(bh); - } - - return bh; -} - -/* - * If we have fewer than thresh credits, extend by EXT4_MAX_TRANS_DATA. - * If that fails, restart the transaction & regain write access for the - * buffer head which is used for block_bitmap modifications. - */ -static int extend_or_restart_transaction(handle_t *handle, int thresh) -{ - int err; - - if (ext4_handle_has_enough_credits(handle, thresh)) - return 0; - - err = ext4_journal_extend(handle, EXT4_MAX_TRANS_DATA); - if (err < 0) - return err; - if (err) { - err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA); - if (err) - return err; - } - - return 0; -} - -/* - * set_flexbg_block_bitmap() mark @count blocks starting from @block used. - * - * Helper function for ext4_setup_new_group_blocks() which set . - * - * @sb: super block - * @handle: journal handle - * @flex_gd: flex group data - */ -static int set_flexbg_block_bitmap(struct super_block *sb, handle_t *handle, - struct ext4_new_flex_group_data *flex_gd, - ext4_fsblk_t block, ext4_group_t count) -{ - ext4_group_t count2; - - ext4_debug("mark blocks [%llu/%u] used\n", block, count); - for (count2 = count; count > 0; count -= count2, block += count2) { - ext4_fsblk_t start; - struct buffer_head *bh; - ext4_group_t group; - int err; - - group = ext4_get_group_number(sb, block); - start = ext4_group_first_block_no(sb, group); - group -= flex_gd->groups[0].group; - - count2 = EXT4_BLOCKS_PER_GROUP(sb) - (block - start); - if (count2 > count) - count2 = count; - - if (flex_gd->bg_flags[group] & EXT4_BG_BLOCK_UNINIT) { - BUG_ON(flex_gd->count > 1); - continue; - } - - err = extend_or_restart_transaction(handle, 1); - if (err) - return err; - - bh = sb_getblk(sb, flex_gd->groups[group].block_bitmap); - if (unlikely(!bh)) - return -ENOMEM; - - BUFFER_TRACE(bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, bh); - if (err) - return err; - ext4_debug("mark block bitmap %#04llx (+%llu/%u)\n", block, - block - start, count2); - ext4_set_bits(bh->b_data, block - start, count2); - - err = ext4_handle_dirty_metadata(handle, NULL, bh); - if (unlikely(err)) - return err; - brelse(bh); - } - - return 0; -} - -/* - * Set up the block and inode bitmaps, and the inode table for the new groups. - * This doesn't need to be part of the main transaction, since we are only - * changing blocks outside the actual filesystem. We still do journaling to - * ensure the recovery is correct in case of a failure just after resize. - * If any part of this fails, we simply abort the resize. - * - * setup_new_flex_group_blocks handles a flex group as follow: - * 1. copy super block and GDT, and initialize group tables if necessary. - * In this step, we only set bits in blocks bitmaps for blocks taken by - * super block and GDT. - * 2. allocate group tables in block bitmaps, that is, set bits in block - * bitmap for blocks taken by group tables. - */ -static int setup_new_flex_group_blocks(struct super_block *sb, - struct ext4_new_flex_group_data *flex_gd) -{ - int group_table_count[] = {1, 1, EXT4_SB(sb)->s_itb_per_group}; - ext4_fsblk_t start; - ext4_fsblk_t block; - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_super_block *es = sbi->s_es; - struct ext4_new_group_data *group_data = flex_gd->groups; - __u16 *bg_flags = flex_gd->bg_flags; - handle_t *handle; - ext4_group_t group, count; - struct buffer_head *bh = NULL; - int reserved_gdb, i, j, err = 0, err2; - int meta_bg; - - BUG_ON(!flex_gd->count || !group_data || - group_data[0].group != sbi->s_groups_count); - - reserved_gdb = le16_to_cpu(es->s_reserved_gdt_blocks); - meta_bg = ext4_has_feature_meta_bg(sb); - - /* This transaction may be extended/restarted along the way */ - handle = ext4_journal_start_sb(sb, EXT4_HT_RESIZE, EXT4_MAX_TRANS_DATA); - if (IS_ERR(handle)) - return PTR_ERR(handle); - - group = group_data[0].group; - for (i = 0; i < flex_gd->count; i++, group++) { - unsigned long gdblocks; - ext4_grpblk_t overhead; - - gdblocks = ext4_bg_num_gdb(sb, group); - start = ext4_group_first_block_no(sb, group); - - if (meta_bg == 0 && !ext4_bg_has_super(sb, group)) - goto handle_itb; - - if (meta_bg == 1) { - ext4_group_t first_group; - first_group = ext4_meta_bg_first_group(sb, group); - if (first_group != group + 1 && - first_group != group + EXT4_DESC_PER_BLOCK(sb) - 1) - goto handle_itb; - } - - block = start + ext4_bg_has_super(sb, group); - /* Copy all of the GDT blocks into the backup in this group */ - for (j = 0; j < gdblocks; j++, block++) { - struct buffer_head *gdb; - - ext4_debug("update backup group %#04llx\n", block); - err = extend_or_restart_transaction(handle, 1); - if (err) - goto out; - - gdb = sb_getblk(sb, block); - if (unlikely(!gdb)) { - err = -ENOMEM; - goto out; - } - - BUFFER_TRACE(gdb, "get_write_access"); - err = ext4_journal_get_write_access(handle, gdb); - if (err) { - brelse(gdb); - goto out; - } - memcpy(gdb->b_data, sbi->s_group_desc[j]->b_data, - gdb->b_size); - set_buffer_uptodate(gdb); - - err = ext4_handle_dirty_metadata(handle, NULL, gdb); - if (unlikely(err)) { - brelse(gdb); - goto out; - } - brelse(gdb); - } - - /* Zero out all of the reserved backup group descriptor - * table blocks - */ - if (ext4_bg_has_super(sb, group)) { - err = sb_issue_zeroout(sb, gdblocks + start + 1, - reserved_gdb, GFP_NOFS); - if (err) - goto out; - } - -handle_itb: - /* Initialize group tables of the grop @group */ - if (!(bg_flags[i] & EXT4_BG_INODE_ZEROED)) - goto handle_bb; - - /* Zero out all of the inode table blocks */ - block = group_data[i].inode_table; - ext4_debug("clear inode table blocks %#04llx -> %#04lx\n", - block, sbi->s_itb_per_group); - err = sb_issue_zeroout(sb, block, sbi->s_itb_per_group, - GFP_NOFS); - if (err) - goto out; - -handle_bb: - if (bg_flags[i] & EXT4_BG_BLOCK_UNINIT) - goto handle_ib; - - /* Initialize block bitmap of the @group */ - block = group_data[i].block_bitmap; - err = extend_or_restart_transaction(handle, 1); - if (err) - goto out; - - bh = bclean(handle, sb, block); - if (IS_ERR(bh)) { - err = PTR_ERR(bh); - bh = NULL; - goto out; - } - overhead = ext4_group_overhead_blocks(sb, group); - if (overhead != 0) { - ext4_debug("mark backup superblock %#04llx (+0)\n", - start); - ext4_set_bits(bh->b_data, 0, overhead); - } - ext4_mark_bitmap_end(group_data[i].blocks_count, - sb->s_blocksize * 8, bh->b_data); - err = ext4_handle_dirty_metadata(handle, NULL, bh); - if (err) - goto out; - brelse(bh); - -handle_ib: - if (bg_flags[i] & EXT4_BG_INODE_UNINIT) - continue; - - /* Initialize inode bitmap of the @group */ - block = group_data[i].inode_bitmap; - err = extend_or_restart_transaction(handle, 1); - if (err) - goto out; - /* Mark unused entries in inode bitmap used */ - bh = bclean(handle, sb, block); - if (IS_ERR(bh)) { - err = PTR_ERR(bh); - bh = NULL; - goto out; - } - - ext4_mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), - sb->s_blocksize * 8, bh->b_data); - err = ext4_handle_dirty_metadata(handle, NULL, bh); - if (err) - goto out; - brelse(bh); - } - bh = NULL; - - /* Mark group tables in block bitmap */ - for (j = 0; j < GROUP_TABLE_COUNT; j++) { - count = group_table_count[j]; - start = (&group_data[0].block_bitmap)[j]; - block = start; - for (i = 1; i < flex_gd->count; i++) { - block += group_table_count[j]; - if (block == (&group_data[i].block_bitmap)[j]) { - count += group_table_count[j]; - continue; - } - err = set_flexbg_block_bitmap(sb, handle, - flex_gd, start, count); - if (err) - goto out; - count = group_table_count[j]; - start = (&group_data[i].block_bitmap)[j]; - block = start; - } - - if (count) { - err = set_flexbg_block_bitmap(sb, handle, - flex_gd, start, count); - if (err) - goto out; - } - } - -out: - brelse(bh); - err2 = ext4_journal_stop(handle); - if (err2 && !err) - err = err2; - - return err; -} - -/* - * Iterate through the groups which hold BACKUP superblock/GDT copies in an - * ext4 filesystem. The counters should be initialized to 1, 5, and 7 before - * calling this for the first time. In a sparse filesystem it will be the - * sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ... - * For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ... - */ -static unsigned ext4_list_backups(struct super_block *sb, unsigned *three, - unsigned *five, unsigned *seven) -{ - unsigned *min = three; - int mult = 3; - unsigned ret; - - if (!ext4_has_feature_sparse_super(sb)) { - ret = *min; - *min += 1; - return ret; - } - - if (*five < *min) { - min = five; - mult = 5; - } - if (*seven < *min) { - min = seven; - mult = 7; - } - - ret = *min; - *min *= mult; - - return ret; -} - -/* - * Check that all of the backup GDT blocks are held in the primary GDT block. - * It is assumed that they are stored in group order. Returns the number of - * groups in current filesystem that have BACKUPS, or -ve error code. - */ -static int verify_reserved_gdb(struct super_block *sb, - ext4_group_t end, - struct buffer_head *primary) -{ - const ext4_fsblk_t blk = primary->b_blocknr; - unsigned three = 1; - unsigned five = 5; - unsigned seven = 7; - unsigned grp; - __le32 *p = (__le32 *)primary->b_data; - int gdbackups = 0; - - while ((grp = ext4_list_backups(sb, &three, &five, &seven)) < end) { - if (le32_to_cpu(*p++) != - grp * EXT4_BLOCKS_PER_GROUP(sb) + blk){ - ext4_warning(sb, "reserved GDT %llu" - " missing grp %d (%llu)", - blk, grp, - grp * - (ext4_fsblk_t)EXT4_BLOCKS_PER_GROUP(sb) + - blk); - return -EINVAL; - } - if (++gdbackups > EXT4_ADDR_PER_BLOCK(sb)) - return -EFBIG; - } - - return gdbackups; -} - -/* - * Called when we need to bring a reserved group descriptor table block into - * use from the resize inode. The primary copy of the new GDT block currently - * is an indirect block (under the double indirect block in the resize inode). - * The new backup GDT blocks will be stored as leaf blocks in this indirect - * block, in group order. Even though we know all the block numbers we need, - * we check to ensure that the resize inode has actually reserved these blocks. - * - * Don't need to update the block bitmaps because the blocks are still in use. - * - * We get all of the error cases out of the way, so that we are sure to not - * fail once we start modifying the data on disk, because JBD has no rollback. - */ -static int add_new_gdb(handle_t *handle, struct inode *inode, - ext4_group_t group) -{ - struct super_block *sb = inode->i_sb; - struct ext4_super_block *es = EXT4_SB(sb)->s_es; - unsigned long gdb_num = group / EXT4_DESC_PER_BLOCK(sb); - ext4_fsblk_t gdblock = EXT4_SB(sb)->s_sbh->b_blocknr + 1 + gdb_num; - struct buffer_head **o_group_desc, **n_group_desc; - struct buffer_head *dind; - struct buffer_head *gdb_bh; - int gdbackups; - struct ext4_iloc iloc; - __le32 *data; - int err; - - if (test_opt(sb, DEBUG)) - printk(KERN_DEBUG - "EXT4-fs: ext4_add_new_gdb: adding group block %lu\n", - gdb_num); - - gdb_bh = sb_bread(sb, gdblock); - if (!gdb_bh) - return -EIO; - - gdbackups = verify_reserved_gdb(sb, group, gdb_bh); - if (gdbackups < 0) { - err = gdbackups; - goto exit_bh; - } - - data = EXT4_I(inode)->i_data + EXT4_DIND_BLOCK; - dind = sb_bread(sb, le32_to_cpu(*data)); - if (!dind) { - err = -EIO; - goto exit_bh; - } - - data = (__le32 *)dind->b_data; - if (le32_to_cpu(data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)]) != gdblock) { - ext4_warning(sb, "new group %u GDT block %llu not reserved", - group, gdblock); - err = -EINVAL; - goto exit_dind; - } - - BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access"); - err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); - if (unlikely(err)) - goto exit_dind; - - BUFFER_TRACE(gdb_bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, gdb_bh); - if (unlikely(err)) - goto exit_dind; - - BUFFER_TRACE(dind, "get_write_access"); - err = ext4_journal_get_write_access(handle, dind); - if (unlikely(err)) - ext4_std_error(sb, err); - - /* ext4_reserve_inode_write() gets a reference on the iloc */ - err = ext4_reserve_inode_write(handle, inode, &iloc); - if (unlikely(err)) - goto exit_dind; - - n_group_desc = ext4_kvmalloc((gdb_num + 1) * - sizeof(struct buffer_head *), - GFP_NOFS); - if (!n_group_desc) { - err = -ENOMEM; - ext4_warning(sb, "not enough memory for %lu groups", - gdb_num + 1); - goto exit_inode; - } - - /* - * Finally, we have all of the possible failures behind us... - * - * Remove new GDT block from inode double-indirect block and clear out - * the new GDT block for use (which also "frees" the backup GDT blocks - * from the reserved inode). We don't need to change the bitmaps for - * these blocks, because they are marked as in-use from being in the - * reserved inode, and will become GDT blocks (primary and backup). - */ - data[gdb_num % EXT4_ADDR_PER_BLOCK(sb)] = 0; - err = ext4_handle_dirty_metadata(handle, NULL, dind); - if (unlikely(err)) { - ext4_std_error(sb, err); - goto exit_inode; - } - inode->i_blocks -= (gdbackups + 1) * sb->s_blocksize >> 9; - ext4_mark_iloc_dirty(handle, inode, &iloc); - memset(gdb_bh->b_data, 0, sb->s_blocksize); - err = ext4_handle_dirty_metadata(handle, NULL, gdb_bh); - if (unlikely(err)) { - ext4_std_error(sb, err); - goto exit_inode; - } - brelse(dind); - - o_group_desc = EXT4_SB(sb)->s_group_desc; - memcpy(n_group_desc, o_group_desc, - EXT4_SB(sb)->s_gdb_count * sizeof(struct buffer_head *)); - n_group_desc[gdb_num] = gdb_bh; - EXT4_SB(sb)->s_group_desc = n_group_desc; - EXT4_SB(sb)->s_gdb_count++; - kvfree(o_group_desc); - - le16_add_cpu(&es->s_reserved_gdt_blocks, -1); - err = ext4_handle_dirty_super(handle, sb); - if (err) - ext4_std_error(sb, err); - - return err; - -exit_inode: - kvfree(n_group_desc); - brelse(iloc.bh); -exit_dind: - brelse(dind); -exit_bh: - brelse(gdb_bh); - - ext4_debug("leaving with error %d\n", err); - return err; -} - -/* - * add_new_gdb_meta_bg is the sister of add_new_gdb. - */ -static int add_new_gdb_meta_bg(struct super_block *sb, - handle_t *handle, ext4_group_t group) { - ext4_fsblk_t gdblock; - struct buffer_head *gdb_bh; - struct buffer_head **o_group_desc, **n_group_desc; - unsigned long gdb_num = group / EXT4_DESC_PER_BLOCK(sb); - int err; - - gdblock = ext4_meta_bg_first_block_no(sb, group) + - ext4_bg_has_super(sb, group); - gdb_bh = sb_bread(sb, gdblock); - if (!gdb_bh) - return -EIO; - n_group_desc = ext4_kvmalloc((gdb_num + 1) * - sizeof(struct buffer_head *), - GFP_NOFS); - if (!n_group_desc) { - err = -ENOMEM; - ext4_warning(sb, "not enough memory for %lu groups", - gdb_num + 1); - return err; - } - - o_group_desc = EXT4_SB(sb)->s_group_desc; - memcpy(n_group_desc, o_group_desc, - EXT4_SB(sb)->s_gdb_count * sizeof(struct buffer_head *)); - n_group_desc[gdb_num] = gdb_bh; - EXT4_SB(sb)->s_group_desc = n_group_desc; - EXT4_SB(sb)->s_gdb_count++; - kvfree(o_group_desc); - BUFFER_TRACE(gdb_bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, gdb_bh); - if (unlikely(err)) - brelse(gdb_bh); - return err; -} - -/* - * Called when we are adding a new group which has a backup copy of each of - * the GDT blocks (i.e. sparse group) and there are reserved GDT blocks. - * We need to add these reserved backup GDT blocks to the resize inode, so - * that they are kept for future resizing and not allocated to files. - * - * Each reserved backup GDT block will go into a different indirect block. - * The indirect blocks are actually the primary reserved GDT blocks, - * so we know in advance what their block numbers are. We only get the - * double-indirect block to verify it is pointing to the primary reserved - * GDT blocks so we don't overwrite a data block by accident. The reserved - * backup GDT blocks are stored in their reserved primary GDT block. - */ -static int reserve_backup_gdb(handle_t *handle, struct inode *inode, - ext4_group_t group) -{ - struct super_block *sb = inode->i_sb; - int reserved_gdb =le16_to_cpu(EXT4_SB(sb)->s_es->s_reserved_gdt_blocks); - struct buffer_head **primary; - struct buffer_head *dind; - struct ext4_iloc iloc; - ext4_fsblk_t blk; - __le32 *data, *end; - int gdbackups = 0; - int res, i; - int err; - - primary = kmalloc(reserved_gdb * sizeof(*primary), GFP_NOFS); - if (!primary) - return -ENOMEM; - - data = EXT4_I(inode)->i_data + EXT4_DIND_BLOCK; - dind = sb_bread(sb, le32_to_cpu(*data)); - if (!dind) { - err = -EIO; - goto exit_free; - } - - blk = EXT4_SB(sb)->s_sbh->b_blocknr + 1 + EXT4_SB(sb)->s_gdb_count; - data = (__le32 *)dind->b_data + (EXT4_SB(sb)->s_gdb_count % - EXT4_ADDR_PER_BLOCK(sb)); - end = (__le32 *)dind->b_data + EXT4_ADDR_PER_BLOCK(sb); - - /* Get each reserved primary GDT block and verify it holds backups */ - for (res = 0; res < reserved_gdb; res++, blk++) { - if (le32_to_cpu(*data) != blk) { - ext4_warning(sb, "reserved block %llu" - " not at offset %ld", - blk, - (long)(data - (__le32 *)dind->b_data)); - err = -EINVAL; - goto exit_bh; - } - primary[res] = sb_bread(sb, blk); - if (!primary[res]) { - err = -EIO; - goto exit_bh; - } - gdbackups = verify_reserved_gdb(sb, group, primary[res]); - if (gdbackups < 0) { - brelse(primary[res]); - err = gdbackups; - goto exit_bh; - } - if (++data >= end) - data = (__le32 *)dind->b_data; - } - - for (i = 0; i < reserved_gdb; i++) { - BUFFER_TRACE(primary[i], "get_write_access"); - if ((err = ext4_journal_get_write_access(handle, primary[i]))) - goto exit_bh; - } - - if ((err = ext4_reserve_inode_write(handle, inode, &iloc))) - goto exit_bh; - - /* - * Finally we can add each of the reserved backup GDT blocks from - * the new group to its reserved primary GDT block. - */ - blk = group * EXT4_BLOCKS_PER_GROUP(sb); - for (i = 0; i < reserved_gdb; i++) { - int err2; - data = (__le32 *)primary[i]->b_data; - /* printk("reserving backup %lu[%u] = %lu\n", - primary[i]->b_blocknr, gdbackups, - blk + primary[i]->b_blocknr); */ - data[gdbackups] = cpu_to_le32(blk + primary[i]->b_blocknr); - err2 = ext4_handle_dirty_metadata(handle, NULL, primary[i]); - if (!err) - err = err2; - } - inode->i_blocks += reserved_gdb * sb->s_blocksize >> 9; - ext4_mark_iloc_dirty(handle, inode, &iloc); - -exit_bh: - while (--res >= 0) - brelse(primary[res]); - brelse(dind); - -exit_free: - kfree(primary); - - return err; -} - -/* - * Update the backup copies of the ext4 metadata. These don't need to be part - * of the main resize transaction, because e2fsck will re-write them if there - * is a problem (basically only OOM will cause a problem). However, we - * _should_ update the backups if possible, in case the primary gets trashed - * for some reason and we need to run e2fsck from a backup superblock. The - * important part is that the new block and inode counts are in the backup - * superblocks, and the location of the new group metadata in the GDT backups. - * - * We do not need take the s_resize_lock for this, because these - * blocks are not otherwise touched by the filesystem code when it is - * mounted. We don't need to worry about last changing from - * sbi->s_groups_count, because the worst that can happen is that we - * do not copy the full number of backups at this time. The resize - * which changed s_groups_count will backup again. - */ -static void update_backups(struct super_block *sb, sector_t blk_off, char *data, - int size, int meta_bg) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - ext4_group_t last; - const int bpg = EXT4_BLOCKS_PER_GROUP(sb); - unsigned three = 1; - unsigned five = 5; - unsigned seven = 7; - ext4_group_t group = 0; - int rest = sb->s_blocksize - size; - handle_t *handle; - int err = 0, err2; - - handle = ext4_journal_start_sb(sb, EXT4_HT_RESIZE, EXT4_MAX_TRANS_DATA); - if (IS_ERR(handle)) { - group = 1; - err = PTR_ERR(handle); - goto exit_err; - } - - if (meta_bg == 0) { - group = ext4_list_backups(sb, &three, &five, &seven); - last = sbi->s_groups_count; - } else { - group = ext4_get_group_number(sb, blk_off) + 1; - last = (ext4_group_t)(group + EXT4_DESC_PER_BLOCK(sb) - 2); - } - - while (group < sbi->s_groups_count) { - struct buffer_head *bh; - ext4_fsblk_t backup_block; - - /* Out of journal space, and can't get more - abort - so sad */ - if (ext4_handle_valid(handle) && - handle->h_buffer_credits == 0 && - ext4_journal_extend(handle, EXT4_MAX_TRANS_DATA) && - (err = ext4_journal_restart(handle, EXT4_MAX_TRANS_DATA))) - break; - - if (meta_bg == 0) - backup_block = ((ext4_fsblk_t)group) * bpg + blk_off; - else - backup_block = (ext4_group_first_block_no(sb, group) + - ext4_bg_has_super(sb, group)); - - bh = sb_getblk(sb, backup_block); - if (unlikely(!bh)) { - err = -ENOMEM; - break; - } - ext4_debug("update metadata backup %llu(+%llu)\n", - backup_block, backup_block - - ext4_group_first_block_no(sb, group)); - BUFFER_TRACE(bh, "get_write_access"); - if ((err = ext4_journal_get_write_access(handle, bh))) - break; - lock_buffer(bh); - memcpy(bh->b_data, data, size); - if (rest) - memset(bh->b_data + size, 0, rest); - set_buffer_uptodate(bh); - unlock_buffer(bh); - err = ext4_handle_dirty_metadata(handle, NULL, bh); - if (unlikely(err)) - ext4_std_error(sb, err); - brelse(bh); - - if (meta_bg == 0) - group = ext4_list_backups(sb, &three, &five, &seven); - else if (group == last) - break; - else - group = last; - } - if ((err2 = ext4_journal_stop(handle)) && !err) - err = err2; - - /* - * Ugh! Need to have e2fsck write the backup copies. It is too - * late to revert the resize, we shouldn't fail just because of - * the backup copies (they are only needed in case of corruption). - * - * However, if we got here we have a journal problem too, so we - * can't really start a transaction to mark the superblock. - * Chicken out and just set the flag on the hope it will be written - * to disk, and if not - we will simply wait until next fsck. - */ -exit_err: - if (err) { - ext4_warning(sb, "can't update backup for group %u (err %d), " - "forcing fsck on next reboot", group, err); - sbi->s_mount_state &= ~EXT4_VALID_FS; - sbi->s_es->s_state &= cpu_to_le16(~EXT4_VALID_FS); - mark_buffer_dirty(sbi->s_sbh); - } -} - -/* - * ext4_add_new_descs() adds @count group descriptor of groups - * starting at @group - * - * @handle: journal handle - * @sb: super block - * @group: the group no. of the first group desc to be added - * @resize_inode: the resize inode - * @count: number of group descriptors to be added - */ -static int ext4_add_new_descs(handle_t *handle, struct super_block *sb, - ext4_group_t group, struct inode *resize_inode, - ext4_group_t count) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_super_block *es = sbi->s_es; - struct buffer_head *gdb_bh; - int i, gdb_off, gdb_num, err = 0; - int meta_bg; - - meta_bg = ext4_has_feature_meta_bg(sb); - for (i = 0; i < count; i++, group++) { - int reserved_gdb = ext4_bg_has_super(sb, group) ? - le16_to_cpu(es->s_reserved_gdt_blocks) : 0; - - gdb_off = group % EXT4_DESC_PER_BLOCK(sb); - gdb_num = group / EXT4_DESC_PER_BLOCK(sb); - - /* - * We will only either add reserved group blocks to a backup group - * or remove reserved blocks for the first group in a new group block. - * Doing both would be mean more complex code, and sane people don't - * use non-sparse filesystems anymore. This is already checked above. - */ - if (gdb_off) { - gdb_bh = sbi->s_group_desc[gdb_num]; - BUFFER_TRACE(gdb_bh, "get_write_access"); - err = ext4_journal_get_write_access(handle, gdb_bh); - - if (!err && reserved_gdb && ext4_bg_num_gdb(sb, group)) - err = reserve_backup_gdb(handle, resize_inode, group); - } else if (meta_bg != 0) { - err = add_new_gdb_meta_bg(sb, handle, group); - } else { - err = add_new_gdb(handle, resize_inode, group); - } - if (err) - break; - } - return err; -} - -static struct buffer_head *ext4_get_bitmap(struct super_block *sb, __u64 block) -{ - struct buffer_head *bh = sb_getblk(sb, block); - if (unlikely(!bh)) - return NULL; - if (!bh_uptodate_or_lock(bh)) { - if (bh_submit_read(bh) < 0) { - brelse(bh); - return NULL; - } - } - - return bh; -} - -static int ext4_set_bitmap_checksums(struct super_block *sb, - ext4_group_t group, - struct ext4_group_desc *gdp, - struct ext4_new_group_data *group_data) -{ - struct buffer_head *bh; - - if (!ext4_has_metadata_csum(sb)) - return 0; - - bh = ext4_get_bitmap(sb, group_data->inode_bitmap); - if (!bh) - return -EIO; - ext4_inode_bitmap_csum_set(sb, group, gdp, bh, - EXT4_INODES_PER_GROUP(sb) / 8); - brelse(bh); - - bh = ext4_get_bitmap(sb, group_data->block_bitmap); - if (!bh) - return -EIO; - ext4_block_bitmap_csum_set(sb, group, gdp, bh); - brelse(bh); - - return 0; -} - -/* - * ext4_setup_new_descs() will set up the group descriptor descriptors of a flex bg - */ -static int ext4_setup_new_descs(handle_t *handle, struct super_block *sb, - struct ext4_new_flex_group_data *flex_gd) -{ - struct ext4_new_group_data *group_data = flex_gd->groups; - struct ext4_group_desc *gdp; - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct buffer_head *gdb_bh; - ext4_group_t group; - __u16 *bg_flags = flex_gd->bg_flags; - int i, gdb_off, gdb_num, err = 0; - - - for (i = 0; i < flex_gd->count; i++, group_data++, bg_flags++) { - group = group_data->group; - - gdb_off = group % EXT4_DESC_PER_BLOCK(sb); - gdb_num = group / EXT4_DESC_PER_BLOCK(sb); - - /* - * get_write_access() has been called on gdb_bh by ext4_add_new_desc(). - */ - gdb_bh = sbi->s_group_desc[gdb_num]; - /* Update group descriptor block for new group */ - gdp = (struct ext4_group_desc *)(gdb_bh->b_data + - gdb_off * EXT4_DESC_SIZE(sb)); - - memset(gdp, 0, EXT4_DESC_SIZE(sb)); - ext4_block_bitmap_set(sb, gdp, group_data->block_bitmap); - ext4_inode_bitmap_set(sb, gdp, group_data->inode_bitmap); - err = ext4_set_bitmap_checksums(sb, group, gdp, group_data); - if (err) { - ext4_std_error(sb, err); - break; - } - - ext4_inode_table_set(sb, gdp, group_data->inode_table); - ext4_free_group_clusters_set(sb, gdp, - EXT4_NUM_B2C(sbi, group_data->free_blocks_count)); - ext4_free_inodes_set(sb, gdp, EXT4_INODES_PER_GROUP(sb)); - if (ext4_has_group_desc_csum(sb)) - ext4_itable_unused_set(sb, gdp, - EXT4_INODES_PER_GROUP(sb)); - gdp->bg_flags = cpu_to_le16(*bg_flags); - ext4_group_desc_csum_set(sb, group, gdp); - - err = ext4_handle_dirty_metadata(handle, NULL, gdb_bh); - if (unlikely(err)) { - ext4_std_error(sb, err); - break; - } - - /* - * We can allocate memory for mb_alloc based on the new group - * descriptor - */ - err = ext4_mb_add_groupinfo(sb, group, gdp); - if (err) - break; - } - return err; -} - -/* - * ext4_update_super() updates the super block so that the newly added - * groups can be seen by the filesystem. - * - * @sb: super block - * @flex_gd: new added groups - */ -static void ext4_update_super(struct super_block *sb, - struct ext4_new_flex_group_data *flex_gd) -{ - ext4_fsblk_t blocks_count = 0; - ext4_fsblk_t free_blocks = 0; - ext4_fsblk_t reserved_blocks = 0; - struct ext4_new_group_data *group_data = flex_gd->groups; - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_super_block *es = sbi->s_es; - int i; - - BUG_ON(flex_gd->count == 0 || group_data == NULL); - /* - * Make the new blocks and inodes valid next. We do this before - * increasing the group count so that once the group is enabled, - * all of its blocks and inodes are already valid. - * - * We always allocate group-by-group, then block-by-block or - * inode-by-inode within a group, so enabling these - * blocks/inodes before the group is live won't actually let us - * allocate the new space yet. - */ - for (i = 0; i < flex_gd->count; i++) { - blocks_count += group_data[i].blocks_count; - free_blocks += group_data[i].free_blocks_count; - } - - reserved_blocks = ext4_r_blocks_count(es) * 100; - reserved_blocks = div64_u64(reserved_blocks, ext4_blocks_count(es)); - reserved_blocks *= blocks_count; - do_div(reserved_blocks, 100); - - ext4_blocks_count_set(es, ext4_blocks_count(es) + blocks_count); - ext4_free_blocks_count_set(es, ext4_free_blocks_count(es) + free_blocks); - le32_add_cpu(&es->s_inodes_count, EXT4_INODES_PER_GROUP(sb) * - flex_gd->count); - le32_add_cpu(&es->s_free_inodes_count, EXT4_INODES_PER_GROUP(sb) * - flex_gd->count); - - ext4_debug("free blocks count %llu", ext4_free_blocks_count(es)); - /* - * We need to protect s_groups_count against other CPUs seeing - * inconsistent state in the superblock. - * - * The precise rules we use are: - * - * * Writers must perform a smp_wmb() after updating all - * dependent data and before modifying the groups count - * - * * Readers must perform an smp_rmb() after reading the groups - * count and before reading any dependent data. - * - * NB. These rules can be relaxed when checking the group count - * while freeing data, as we can only allocate from a block - * group after serialising against the group count, and we can - * only then free after serialising in turn against that - * allocation. - */ - smp_wmb(); - - /* Update the global fs size fields */ - sbi->s_groups_count += flex_gd->count; - sbi->s_blockfile_groups = min_t(ext4_group_t, sbi->s_groups_count, - (EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb))); - - /* Update the reserved block counts only once the new group is - * active. */ - ext4_r_blocks_count_set(es, ext4_r_blocks_count(es) + - reserved_blocks); - - /* Update the free space counts */ - percpu_counter_add(&sbi->s_freeclusters_counter, - EXT4_NUM_B2C(sbi, free_blocks)); - percpu_counter_add(&sbi->s_freeinodes_counter, - EXT4_INODES_PER_GROUP(sb) * flex_gd->count); - - ext4_debug("free blocks count %llu", - percpu_counter_read(&sbi->s_freeclusters_counter)); - if (ext4_has_feature_flex_bg(sb) && sbi->s_log_groups_per_flex) { - ext4_group_t flex_group; - flex_group = ext4_flex_group(sbi, group_data[0].group); - atomic64_add(EXT4_NUM_B2C(sbi, free_blocks), - &sbi->s_flex_groups[flex_group].free_clusters); - atomic_add(EXT4_INODES_PER_GROUP(sb) * flex_gd->count, - &sbi->s_flex_groups[flex_group].free_inodes); - } - - /* - * Update the fs overhead information - */ - ext4_calculate_overhead(sb); - - if (test_opt(sb, DEBUG)) - printk(KERN_DEBUG "EXT4-fs: added group %u:" - "%llu blocks(%llu free %llu reserved)\n", flex_gd->count, - blocks_count, free_blocks, reserved_blocks); -} - -/* Add a flex group to an fs. Ensure we handle all possible error conditions - * _before_ we start modifying the filesystem, because we cannot abort the - * transaction and not have it write the data to disk. - */ -static int ext4_flex_group_add(struct super_block *sb, - struct inode *resize_inode, - struct ext4_new_flex_group_data *flex_gd) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_super_block *es = sbi->s_es; - ext4_fsblk_t o_blocks_count; - ext4_grpblk_t last; - ext4_group_t group; - handle_t *handle; - unsigned reserved_gdb; - int err = 0, err2 = 0, credit; - - BUG_ON(!flex_gd->count || !flex_gd->groups || !flex_gd->bg_flags); - - reserved_gdb = le16_to_cpu(es->s_reserved_gdt_blocks); - o_blocks_count = ext4_blocks_count(es); - ext4_get_group_no_and_offset(sb, o_blocks_count, &group, &last); - BUG_ON(last); - - err = setup_new_flex_group_blocks(sb, flex_gd); - if (err) - goto exit; - /* - * We will always be modifying at least the superblock and GDT - * blocks. If we are adding a group past the last current GDT block, - * we will also modify the inode and the dindirect block. If we - * are adding a group with superblock/GDT backups we will also - * modify each of the reserved GDT dindirect blocks. - */ - credit = 3; /* sb, resize inode, resize inode dindirect */ - /* GDT blocks */ - credit += 1 + DIV_ROUND_UP(flex_gd->count, EXT4_DESC_PER_BLOCK(sb)); - credit += reserved_gdb; /* Reserved GDT dindirect blocks */ - handle = ext4_journal_start_sb(sb, EXT4_HT_RESIZE, credit); - if (IS_ERR(handle)) { - err = PTR_ERR(handle); - goto exit; - } - - BUFFER_TRACE(sbi->s_sbh, "get_write_access"); - err = ext4_journal_get_write_access(handle, sbi->s_sbh); - if (err) - goto exit_journal; - - group = flex_gd->groups[0].group; - BUG_ON(group != EXT4_SB(sb)->s_groups_count); - err = ext4_add_new_descs(handle, sb, group, - resize_inode, flex_gd->count); - if (err) - goto exit_journal; - - err = ext4_setup_new_descs(handle, sb, flex_gd); - if (err) - goto exit_journal; - - ext4_update_super(sb, flex_gd); - - err = ext4_handle_dirty_super(handle, sb); - -exit_journal: - err2 = ext4_journal_stop(handle); - if (!err) - err = err2; - - if (!err) { - int gdb_num = group / EXT4_DESC_PER_BLOCK(sb); - int gdb_num_end = ((group + flex_gd->count - 1) / - EXT4_DESC_PER_BLOCK(sb)); - int meta_bg = ext4_has_feature_meta_bg(sb); - sector_t old_gdb = 0; - - update_backups(sb, sbi->s_sbh->b_blocknr, (char *)es, - sizeof(struct ext4_super_block), 0); - for (; gdb_num <= gdb_num_end; gdb_num++) { - struct buffer_head *gdb_bh; - - gdb_bh = sbi->s_group_desc[gdb_num]; - if (old_gdb == gdb_bh->b_blocknr) - continue; - update_backups(sb, gdb_bh->b_blocknr, gdb_bh->b_data, - gdb_bh->b_size, meta_bg); - old_gdb = gdb_bh->b_blocknr; - } - } -exit: - return err; -} - -static int ext4_setup_next_flex_gd(struct super_block *sb, - struct ext4_new_flex_group_data *flex_gd, - ext4_fsblk_t n_blocks_count, - unsigned long flexbg_size) -{ - struct ext4_super_block *es = EXT4_SB(sb)->s_es; - struct ext4_new_group_data *group_data = flex_gd->groups; - ext4_fsblk_t o_blocks_count; - ext4_group_t n_group; - ext4_group_t group; - ext4_group_t last_group; - ext4_grpblk_t last; - ext4_grpblk_t blocks_per_group; - unsigned long i; - - blocks_per_group = EXT4_BLOCKS_PER_GROUP(sb); - - o_blocks_count = ext4_blocks_count(es); - - if (o_blocks_count == n_blocks_count) - return 0; - - ext4_get_group_no_and_offset(sb, o_blocks_count, &group, &last); - BUG_ON(last); - ext4_get_group_no_and_offset(sb, n_blocks_count - 1, &n_group, &last); - - last_group = group | (flexbg_size - 1); - if (last_group > n_group) - last_group = n_group; - - flex_gd->count = last_group - group + 1; - - for (i = 0; i < flex_gd->count; i++) { - int overhead; - - group_data[i].group = group + i; - group_data[i].blocks_count = blocks_per_group; - overhead = ext4_group_overhead_blocks(sb, group + i); - group_data[i].free_blocks_count = blocks_per_group - overhead; - if (ext4_has_group_desc_csum(sb)) { - flex_gd->bg_flags[i] = EXT4_BG_BLOCK_UNINIT | - EXT4_BG_INODE_UNINIT; - if (!test_opt(sb, INIT_INODE_TABLE)) - flex_gd->bg_flags[i] |= EXT4_BG_INODE_ZEROED; - } else - flex_gd->bg_flags[i] = EXT4_BG_INODE_ZEROED; - } - - if (last_group == n_group && ext4_has_group_desc_csum(sb)) - /* We need to initialize block bitmap of last group. */ - flex_gd->bg_flags[i - 1] &= ~EXT4_BG_BLOCK_UNINIT; - - if ((last_group == n_group) && (last != blocks_per_group - 1)) { - group_data[i - 1].blocks_count = last + 1; - group_data[i - 1].free_blocks_count -= blocks_per_group- - last - 1; - } - - return 1; -} - -/* Add group descriptor data to an existing or new group descriptor block. - * Ensure we handle all possible error conditions _before_ we start modifying - * the filesystem, because we cannot abort the transaction and not have it - * write the data to disk. - * - * If we are on a GDT block boundary, we need to get the reserved GDT block. - * Otherwise, we may need to add backup GDT blocks for a sparse group. - * - * We only need to hold the superblock lock while we are actually adding - * in the new group's counts to the superblock. Prior to that we have - * not really "added" the group at all. We re-check that we are still - * adding in the last group in case things have changed since verifying. - */ -int ext4_group_add(struct super_block *sb, struct ext4_new_group_data *input) -{ - struct ext4_new_flex_group_data flex_gd; - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_super_block *es = sbi->s_es; - int reserved_gdb = ext4_bg_has_super(sb, input->group) ? - le16_to_cpu(es->s_reserved_gdt_blocks) : 0; - struct inode *inode = NULL; - int gdb_off; - int err; - __u16 bg_flags = 0; - - gdb_off = input->group % EXT4_DESC_PER_BLOCK(sb); - - if (gdb_off == 0 && !ext4_has_feature_sparse_super(sb)) { - ext4_warning(sb, "Can't resize non-sparse filesystem further"); - return -EPERM; - } - - if (ext4_blocks_count(es) + input->blocks_count < - ext4_blocks_count(es)) { - ext4_warning(sb, "blocks_count overflow"); - return -EINVAL; - } - - if (le32_to_cpu(es->s_inodes_count) + EXT4_INODES_PER_GROUP(sb) < - le32_to_cpu(es->s_inodes_count)) { - ext4_warning(sb, "inodes_count overflow"); - return -EINVAL; - } - - if (reserved_gdb || gdb_off == 0) { - if (ext4_has_feature_resize_inode(sb) || - !le16_to_cpu(es->s_reserved_gdt_blocks)) { - ext4_warning(sb, - "No reserved GDT blocks, can't resize"); - return -EPERM; - } - inode = ext4_iget(sb, EXT4_RESIZE_INO); - if (IS_ERR(inode)) { - ext4_warning(sb, "Error opening resize inode"); - return PTR_ERR(inode); - } - } - - - err = verify_group_input(sb, input); - if (err) - goto out; - - err = ext4_alloc_flex_bg_array(sb, input->group + 1); - if (err) - goto out; - - err = ext4_mb_alloc_groupinfo(sb, input->group + 1); - if (err) - goto out; - - flex_gd.count = 1; - flex_gd.groups = input; - flex_gd.bg_flags = &bg_flags; - err = ext4_flex_group_add(sb, inode, &flex_gd); -out: - iput(inode); - return err; -} /* ext4_group_add */ - -/* - * extend a group without checking assuming that checking has been done. - */ -static int ext4_group_extend_no_check(struct super_block *sb, - ext4_fsblk_t o_blocks_count, ext4_grpblk_t add) -{ - struct ext4_super_block *es = EXT4_SB(sb)->s_es; - handle_t *handle; - int err = 0, err2; - - /* We will update the superblock, one block bitmap, and - * one group descriptor via ext4_group_add_blocks(). - */ - handle = ext4_journal_start_sb(sb, EXT4_HT_RESIZE, 3); - if (IS_ERR(handle)) { - err = PTR_ERR(handle); - ext4_warning(sb, "error %d on journal start", err); - return err; - } - - BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access"); - err = ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh); - if (err) { - ext4_warning(sb, "error %d on journal write access", err); - goto errout; - } - - ext4_blocks_count_set(es, o_blocks_count + add); - ext4_free_blocks_count_set(es, ext4_free_blocks_count(es) + add); - ext4_debug("freeing blocks %llu through %llu\n", o_blocks_count, - o_blocks_count + add); - /* We add the blocks to the bitmap and set the group need init bit */ - err = ext4_group_add_blocks(handle, sb, o_blocks_count, add); - if (err) - goto errout; - ext4_handle_dirty_super(handle, sb); - ext4_debug("freed blocks %llu through %llu\n", o_blocks_count, - o_blocks_count + add); -errout: - err2 = ext4_journal_stop(handle); - if (err2 && !err) - err = err2; - - if (!err) { - if (test_opt(sb, DEBUG)) - printk(KERN_DEBUG "EXT4-fs: extended group to %llu " - "blocks\n", ext4_blocks_count(es)); - update_backups(sb, EXT4_SB(sb)->s_sbh->b_blocknr, - (char *)es, sizeof(struct ext4_super_block), 0); - } - return err; -} - -/* - * Extend the filesystem to the new number of blocks specified. This entry - * point is only used to extend the current filesystem to the end of the last - * existing group. It can be accessed via ioctl, or by "remount,resize=" - * for emergencies (because it has no dependencies on reserved blocks). - * - * If we _really_ wanted, we could use default values to call ext4_group_add() - * allow the "remount" trick to work for arbitrary resizing, assuming enough - * GDT blocks are reserved to grow to the desired size. - */ -int ext4_group_extend(struct super_block *sb, struct ext4_super_block *es, - ext4_fsblk_t n_blocks_count) -{ - ext4_fsblk_t o_blocks_count; - ext4_grpblk_t last; - ext4_grpblk_t add; - struct buffer_head *bh; - int err; - ext4_group_t group; - - o_blocks_count = ext4_blocks_count(es); - - if (test_opt(sb, DEBUG)) - ext4_msg(sb, KERN_DEBUG, - "extending last group from %llu to %llu blocks", - o_blocks_count, n_blocks_count); - - if (n_blocks_count == 0 || n_blocks_count == o_blocks_count) - return 0; - - if (n_blocks_count > (sector_t)(~0ULL) >> (sb->s_blocksize_bits - 9)) { - ext4_msg(sb, KERN_ERR, - "filesystem too large to resize to %llu blocks safely", - n_blocks_count); - if (sizeof(sector_t) < 8) - ext4_warning(sb, "CONFIG_LBDAF not enabled"); - return -EINVAL; - } - - if (n_blocks_count < o_blocks_count) { - ext4_warning(sb, "can't shrink FS - resize aborted"); - return -EINVAL; - } - - /* Handle the remaining blocks in the last group only. */ - ext4_get_group_no_and_offset(sb, o_blocks_count, &group, &last); - - if (last == 0) { - ext4_warning(sb, "need to use ext2online to resize further"); - return -EPERM; - } - - add = EXT4_BLOCKS_PER_GROUP(sb) - last; - - if (o_blocks_count + add < o_blocks_count) { - ext4_warning(sb, "blocks_count overflow"); - return -EINVAL; - } - - if (o_blocks_count + add > n_blocks_count) - add = n_blocks_count - o_blocks_count; - - if (o_blocks_count + add < n_blocks_count) - ext4_warning(sb, "will only finish group (%llu blocks, %u new)", - o_blocks_count + add, add); - - /* See if the device is actually as big as what was requested */ - bh = sb_bread(sb, o_blocks_count + add - 1); - if (!bh) { - ext4_warning(sb, "can't read last block, resize aborted"); - return -ENOSPC; - } - brelse(bh); - - err = ext4_group_extend_no_check(sb, o_blocks_count, add); - return err; -} /* ext4_group_extend */ - - -static int num_desc_blocks(struct super_block *sb, ext4_group_t groups) -{ - return (groups + EXT4_DESC_PER_BLOCK(sb) - 1) / EXT4_DESC_PER_BLOCK(sb); -} - -/* - * Release the resize inode and drop the resize_inode feature if there - * are no more reserved gdt blocks, and then convert the file system - * to enable meta_bg - */ -static int ext4_convert_meta_bg(struct super_block *sb, struct inode *inode) -{ - handle_t *handle; - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_super_block *es = sbi->s_es; - struct ext4_inode_info *ei = EXT4_I(inode); - ext4_fsblk_t nr; - int i, ret, err = 0; - int credits = 1; - - ext4_msg(sb, KERN_INFO, "Converting file system to meta_bg"); - if (inode) { - if (es->s_reserved_gdt_blocks) { - ext4_error(sb, "Unexpected non-zero " - "s_reserved_gdt_blocks"); - return -EPERM; - } - - /* Do a quick sanity check of the resize inode */ - if (inode->i_blocks != 1 << (inode->i_blkbits - 9)) - goto invalid_resize_inode; - for (i = 0; i < EXT4_N_BLOCKS; i++) { - if (i == EXT4_DIND_BLOCK) { - if (ei->i_data[i]) - continue; - else - goto invalid_resize_inode; - } - if (ei->i_data[i]) - goto invalid_resize_inode; - } - credits += 3; /* block bitmap, bg descriptor, resize inode */ - } - - handle = ext4_journal_start_sb(sb, EXT4_HT_RESIZE, credits); - if (IS_ERR(handle)) - return PTR_ERR(handle); - - BUFFER_TRACE(sbi->s_sbh, "get_write_access"); - err = ext4_journal_get_write_access(handle, sbi->s_sbh); - if (err) - goto errout; - - ext4_clear_feature_resize_inode(sb); - ext4_set_feature_meta_bg(sb); - sbi->s_es->s_first_meta_bg = - cpu_to_le32(num_desc_blocks(sb, sbi->s_groups_count)); - - err = ext4_handle_dirty_super(handle, sb); - if (err) { - ext4_std_error(sb, err); - goto errout; - } - - if (inode) { - nr = le32_to_cpu(ei->i_data[EXT4_DIND_BLOCK]); - ext4_free_blocks(handle, inode, NULL, nr, 1, - EXT4_FREE_BLOCKS_METADATA | - EXT4_FREE_BLOCKS_FORGET); - ei->i_data[EXT4_DIND_BLOCK] = 0; - inode->i_blocks = 0; - - err = ext4_mark_inode_dirty(handle, inode); - if (err) - ext4_std_error(sb, err); - } - -errout: - ret = ext4_journal_stop(handle); - if (!err) - err = ret; - return ret; - -invalid_resize_inode: - ext4_error(sb, "corrupted/inconsistent resize inode"); - return -EINVAL; -} - -/* - * ext4_resize_fs() resizes a fs to new size specified by @n_blocks_count - * - * @sb: super block of the fs to be resized - * @n_blocks_count: the number of blocks resides in the resized fs - */ -int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count) -{ - struct ext4_new_flex_group_data *flex_gd = NULL; - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_super_block *es = sbi->s_es; - struct buffer_head *bh; - struct inode *resize_inode = NULL; - ext4_grpblk_t add, offset; - unsigned long n_desc_blocks; - unsigned long o_desc_blocks; - ext4_group_t o_group; - ext4_group_t n_group; - ext4_fsblk_t o_blocks_count; - ext4_fsblk_t n_blocks_count_retry = 0; - unsigned long last_update_time = 0; - int err = 0, flexbg_size = 1 << sbi->s_log_groups_per_flex; - int meta_bg; - - /* See if the device is actually as big as what was requested */ - bh = sb_bread(sb, n_blocks_count - 1); - if (!bh) { - ext4_warning(sb, "can't read last block, resize aborted"); - return -ENOSPC; - } - brelse(bh); - -retry: - o_blocks_count = ext4_blocks_count(es); - - ext4_msg(sb, KERN_INFO, "resizing filesystem from %llu " - "to %llu blocks", o_blocks_count, n_blocks_count); - - if (n_blocks_count < o_blocks_count) { - /* On-line shrinking not supported */ - ext4_warning(sb, "can't shrink FS - resize aborted"); - return -EINVAL; - } - - if (n_blocks_count == o_blocks_count) - /* Nothing need to do */ - return 0; - - n_group = ext4_get_group_number(sb, n_blocks_count - 1); - if (n_group > (0xFFFFFFFFUL / EXT4_INODES_PER_GROUP(sb))) { - ext4_warning(sb, "resize would cause inodes_count overflow"); - return -EINVAL; - } - ext4_get_group_no_and_offset(sb, o_blocks_count - 1, &o_group, &offset); - - n_desc_blocks = num_desc_blocks(sb, n_group + 1); - o_desc_blocks = num_desc_blocks(sb, sbi->s_groups_count); - - meta_bg = ext4_has_feature_meta_bg(sb); - - if (ext4_has_feature_resize_inode(sb)) { - if (meta_bg) { - ext4_error(sb, "resize_inode and meta_bg enabled " - "simultaneously"); - return -EINVAL; - } - if (n_desc_blocks > o_desc_blocks + - le16_to_cpu(es->s_reserved_gdt_blocks)) { - n_blocks_count_retry = n_blocks_count; - n_desc_blocks = o_desc_blocks + - le16_to_cpu(es->s_reserved_gdt_blocks); - n_group = n_desc_blocks * EXT4_DESC_PER_BLOCK(sb); - n_blocks_count = n_group * EXT4_BLOCKS_PER_GROUP(sb); - n_group--; /* set to last group number */ - } - - if (!resize_inode) - resize_inode = ext4_iget(sb, EXT4_RESIZE_INO); - if (IS_ERR(resize_inode)) { - ext4_warning(sb, "Error opening resize inode"); - return PTR_ERR(resize_inode); - } - } - - if ((!resize_inode && !meta_bg) || n_blocks_count == o_blocks_count) { - err = ext4_convert_meta_bg(sb, resize_inode); - if (err) - goto out; - if (resize_inode) { - iput(resize_inode); - resize_inode = NULL; - } - if (n_blocks_count_retry) { - n_blocks_count = n_blocks_count_retry; - n_blocks_count_retry = 0; - goto retry; - } - } - - /* extend the last group */ - if (n_group == o_group) - add = n_blocks_count - o_blocks_count; - else - add = EXT4_BLOCKS_PER_GROUP(sb) - (offset + 1); - if (add > 0) { - err = ext4_group_extend_no_check(sb, o_blocks_count, add); - if (err) - goto out; - } - - if (ext4_blocks_count(es) == n_blocks_count) - goto out; - - err = ext4_alloc_flex_bg_array(sb, n_group + 1); - if (err) - return err; - - err = ext4_mb_alloc_groupinfo(sb, n_group + 1); - if (err) - goto out; - - flex_gd = alloc_flex_gd(flexbg_size); - if (flex_gd == NULL) { - err = -ENOMEM; - goto out; - } - - /* Add flex groups. Note that a regular group is a - * flex group with 1 group. - */ - while (ext4_setup_next_flex_gd(sb, flex_gd, n_blocks_count, - flexbg_size)) { - if (jiffies - last_update_time > HZ * 10) { - if (last_update_time) - ext4_msg(sb, KERN_INFO, - "resized to %llu blocks", - ext4_blocks_count(es)); - last_update_time = jiffies; - } - if (ext4_alloc_group_tables(sb, flex_gd, flexbg_size) != 0) - break; - err = ext4_flex_group_add(sb, resize_inode, flex_gd); - if (unlikely(err)) - break; - } - - if (!err && n_blocks_count_retry) { - n_blocks_count = n_blocks_count_retry; - n_blocks_count_retry = 0; - free_flex_gd(flex_gd); - flex_gd = NULL; - goto retry; - } - -out: - if (flex_gd) - free_flex_gd(flex_gd); - if (resize_inode != NULL) - iput(resize_inode); - ext4_msg(sb, KERN_INFO, "resized filesystem to %llu", n_blocks_count); - return err; -} diff --git a/src/linux/fs/ext4/super.c b/src/linux/fs/ext4/super.c deleted file mode 100644 index 52b0530..0000000 --- a/src/linux/fs/ext4/super.c +++ /dev/null @@ -1,5642 +0,0 @@ -/* - * linux/fs/ext4/super.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/inode.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Big-endian to little-endian byte-swapping/bitmaps by - * David S. Miller (davem@caip.rutgers.edu), 1995 - */ - -#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 "ext4.h" -#include "ext4_extents.h" /* Needed for trace points definition */ -#include "ext4_jbd2.h" -#include "xattr.h" -#include "acl.h" -#include "mballoc.h" - -#define CREATE_TRACE_POINTS -#include - -static struct ext4_lazy_init *ext4_li_info; -static struct mutex ext4_li_mtx; -static struct ratelimit_state ext4_mount_msg_ratelimit; - -static int ext4_load_journal(struct super_block *, struct ext4_super_block *, - unsigned long journal_devnum); -static int ext4_show_options(struct seq_file *seq, struct dentry *root); -static int ext4_commit_super(struct super_block *sb, int sync); -static void ext4_mark_recovery_complete(struct super_block *sb, - struct ext4_super_block *es); -static void ext4_clear_journal_err(struct super_block *sb, - struct ext4_super_block *es); -static int ext4_sync_fs(struct super_block *sb, int wait); -static int ext4_remount(struct super_block *sb, int *flags, char *data); -static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf); -static int ext4_unfreeze(struct super_block *sb); -static int ext4_freeze(struct super_block *sb); -static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data); -static inline int ext2_feature_set_ok(struct super_block *sb); -static inline int ext3_feature_set_ok(struct super_block *sb); -static int ext4_feature_set_ok(struct super_block *sb, int readonly); -static void ext4_destroy_lazyinit_thread(void); -static void ext4_unregister_li_request(struct super_block *sb); -static void ext4_clear_request_list(void); -static struct inode *ext4_get_journal_inode(struct super_block *sb, - unsigned int journal_inum); - -/* - * Lock ordering - * - * Note the difference between i_mmap_sem (EXT4_I(inode)->i_mmap_sem) and - * i_mmap_rwsem (inode->i_mmap_rwsem)! - * - * page fault path: - * mmap_sem -> sb_start_pagefault -> i_mmap_sem (r) -> transaction start -> - * page lock -> i_data_sem (rw) - * - * buffered write path: - * sb_start_write -> i_mutex -> mmap_sem - * sb_start_write -> i_mutex -> transaction start -> page lock -> - * i_data_sem (rw) - * - * truncate: - * sb_start_write -> i_mutex -> EXT4_STATE_DIOREAD_LOCK (w) -> i_mmap_sem (w) -> - * i_mmap_rwsem (w) -> page lock - * sb_start_write -> i_mutex -> EXT4_STATE_DIOREAD_LOCK (w) -> i_mmap_sem (w) -> - * transaction start -> i_data_sem (rw) - * - * direct IO: - * sb_start_write -> i_mutex -> EXT4_STATE_DIOREAD_LOCK (r) -> mmap_sem - * sb_start_write -> i_mutex -> EXT4_STATE_DIOREAD_LOCK (r) -> - * transaction start -> i_data_sem (rw) - * - * writepages: - * transaction start -> page lock(s) -> i_data_sem (rw) - */ - -#if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT2) -static struct file_system_type ext2_fs_type = { - .owner = THIS_MODULE, - .name = "ext2", - .mount = ext4_mount, - .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, -}; -MODULE_ALIAS_FS("ext2"); -MODULE_ALIAS("ext2"); -#define IS_EXT2_SB(sb) ((sb)->s_bdev->bd_holder == &ext2_fs_type) -#else -#define IS_EXT2_SB(sb) (0) -#endif - - -static struct file_system_type ext3_fs_type = { - .owner = THIS_MODULE, - .name = "ext3", - .mount = ext4_mount, - .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, -}; -MODULE_ALIAS_FS("ext3"); -MODULE_ALIAS("ext3"); -#define IS_EXT3_SB(sb) ((sb)->s_bdev->bd_holder == &ext3_fs_type) - -static int ext4_verify_csum_type(struct super_block *sb, - struct ext4_super_block *es) -{ - if (!ext4_has_feature_metadata_csum(sb)) - return 1; - - return es->s_checksum_type == EXT4_CRC32C_CHKSUM; -} - -static __le32 ext4_superblock_csum(struct super_block *sb, - struct ext4_super_block *es) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - int offset = offsetof(struct ext4_super_block, s_checksum); - __u32 csum; - - csum = ext4_chksum(sbi, ~0, (char *)es, offset); - - return cpu_to_le32(csum); -} - -static int ext4_superblock_csum_verify(struct super_block *sb, - struct ext4_super_block *es) -{ - if (!ext4_has_metadata_csum(sb)) - return 1; - - return es->s_checksum == ext4_superblock_csum(sb, es); -} - -void ext4_superblock_csum_set(struct super_block *sb) -{ - struct ext4_super_block *es = EXT4_SB(sb)->s_es; - - if (!ext4_has_metadata_csum(sb)) - return; - - es->s_checksum = ext4_superblock_csum(sb, es); -} - -void *ext4_kvmalloc(size_t size, gfp_t flags) -{ - void *ret; - - ret = kmalloc(size, flags | __GFP_NOWARN); - if (!ret) - ret = __vmalloc(size, flags, PAGE_KERNEL); - return ret; -} - -void *ext4_kvzalloc(size_t size, gfp_t flags) -{ - void *ret; - - ret = kzalloc(size, flags | __GFP_NOWARN); - if (!ret) - ret = __vmalloc(size, flags | __GFP_ZERO, PAGE_KERNEL); - return ret; -} - -ext4_fsblk_t ext4_block_bitmap(struct super_block *sb, - struct ext4_group_desc *bg) -{ - return le32_to_cpu(bg->bg_block_bitmap_lo) | - (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? - (ext4_fsblk_t)le32_to_cpu(bg->bg_block_bitmap_hi) << 32 : 0); -} - -ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb, - struct ext4_group_desc *bg) -{ - return le32_to_cpu(bg->bg_inode_bitmap_lo) | - (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? - (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_bitmap_hi) << 32 : 0); -} - -ext4_fsblk_t ext4_inode_table(struct super_block *sb, - struct ext4_group_desc *bg) -{ - return le32_to_cpu(bg->bg_inode_table_lo) | - (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? - (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0); -} - -__u32 ext4_free_group_clusters(struct super_block *sb, - struct ext4_group_desc *bg) -{ - return le16_to_cpu(bg->bg_free_blocks_count_lo) | - (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? - (__u32)le16_to_cpu(bg->bg_free_blocks_count_hi) << 16 : 0); -} - -__u32 ext4_free_inodes_count(struct super_block *sb, - struct ext4_group_desc *bg) -{ - return le16_to_cpu(bg->bg_free_inodes_count_lo) | - (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? - (__u32)le16_to_cpu(bg->bg_free_inodes_count_hi) << 16 : 0); -} - -__u32 ext4_used_dirs_count(struct super_block *sb, - struct ext4_group_desc *bg) -{ - return le16_to_cpu(bg->bg_used_dirs_count_lo) | - (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? - (__u32)le16_to_cpu(bg->bg_used_dirs_count_hi) << 16 : 0); -} - -__u32 ext4_itable_unused_count(struct super_block *sb, - struct ext4_group_desc *bg) -{ - return le16_to_cpu(bg->bg_itable_unused_lo) | - (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ? - (__u32)le16_to_cpu(bg->bg_itable_unused_hi) << 16 : 0); -} - -void ext4_block_bitmap_set(struct super_block *sb, - struct ext4_group_desc *bg, ext4_fsblk_t blk) -{ - bg->bg_block_bitmap_lo = cpu_to_le32((u32)blk); - if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) - bg->bg_block_bitmap_hi = cpu_to_le32(blk >> 32); -} - -void ext4_inode_bitmap_set(struct super_block *sb, - struct ext4_group_desc *bg, ext4_fsblk_t blk) -{ - bg->bg_inode_bitmap_lo = cpu_to_le32((u32)blk); - if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) - bg->bg_inode_bitmap_hi = cpu_to_le32(blk >> 32); -} - -void ext4_inode_table_set(struct super_block *sb, - struct ext4_group_desc *bg, ext4_fsblk_t blk) -{ - bg->bg_inode_table_lo = cpu_to_le32((u32)blk); - if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) - bg->bg_inode_table_hi = cpu_to_le32(blk >> 32); -} - -void ext4_free_group_clusters_set(struct super_block *sb, - struct ext4_group_desc *bg, __u32 count) -{ - bg->bg_free_blocks_count_lo = cpu_to_le16((__u16)count); - if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) - bg->bg_free_blocks_count_hi = cpu_to_le16(count >> 16); -} - -void ext4_free_inodes_set(struct super_block *sb, - struct ext4_group_desc *bg, __u32 count) -{ - bg->bg_free_inodes_count_lo = cpu_to_le16((__u16)count); - if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) - bg->bg_free_inodes_count_hi = cpu_to_le16(count >> 16); -} - -void ext4_used_dirs_set(struct super_block *sb, - struct ext4_group_desc *bg, __u32 count) -{ - bg->bg_used_dirs_count_lo = cpu_to_le16((__u16)count); - if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) - bg->bg_used_dirs_count_hi = cpu_to_le16(count >> 16); -} - -void ext4_itable_unused_set(struct super_block *sb, - struct ext4_group_desc *bg, __u32 count) -{ - bg->bg_itable_unused_lo = cpu_to_le16((__u16)count); - if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT) - bg->bg_itable_unused_hi = cpu_to_le16(count >> 16); -} - - -static void __save_error_info(struct super_block *sb, const char *func, - unsigned int line) -{ - struct ext4_super_block *es = EXT4_SB(sb)->s_es; - - EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; - if (bdev_read_only(sb->s_bdev)) - return; - es->s_state |= cpu_to_le16(EXT4_ERROR_FS); - es->s_last_error_time = cpu_to_le32(get_seconds()); - strncpy(es->s_last_error_func, func, sizeof(es->s_last_error_func)); - es->s_last_error_line = cpu_to_le32(line); - if (!es->s_first_error_time) { - es->s_first_error_time = es->s_last_error_time; - strncpy(es->s_first_error_func, func, - sizeof(es->s_first_error_func)); - es->s_first_error_line = cpu_to_le32(line); - es->s_first_error_ino = es->s_last_error_ino; - es->s_first_error_block = es->s_last_error_block; - } - /* - * Start the daily error reporting function if it hasn't been - * started already - */ - if (!es->s_error_count) - mod_timer(&EXT4_SB(sb)->s_err_report, jiffies + 24*60*60*HZ); - le32_add_cpu(&es->s_error_count, 1); -} - -static void save_error_info(struct super_block *sb, const char *func, - unsigned int line) -{ - __save_error_info(sb, func, line); - ext4_commit_super(sb, 1); -} - -/* - * The del_gendisk() function uninitializes the disk-specific data - * structures, including the bdi structure, without telling anyone - * else. Once this happens, any attempt to call mark_buffer_dirty() - * (for example, by ext4_commit_super), will cause a kernel OOPS. - * This is a kludge to prevent these oops until we can put in a proper - * hook in del_gendisk() to inform the VFS and file system layers. - */ -static int block_device_ejected(struct super_block *sb) -{ - struct inode *bd_inode = sb->s_bdev->bd_inode; - struct backing_dev_info *bdi = inode_to_bdi(bd_inode); - - return bdi->dev == NULL; -} - -static void ext4_journal_commit_callback(journal_t *journal, transaction_t *txn) -{ - struct super_block *sb = journal->j_private; - struct ext4_sb_info *sbi = EXT4_SB(sb); - int error = is_journal_aborted(journal); - struct ext4_journal_cb_entry *jce; - - BUG_ON(txn->t_state == T_FINISHED); - spin_lock(&sbi->s_md_lock); - while (!list_empty(&txn->t_private_list)) { - jce = list_entry(txn->t_private_list.next, - struct ext4_journal_cb_entry, jce_list); - list_del_init(&jce->jce_list); - spin_unlock(&sbi->s_md_lock); - jce->jce_func(sb, jce, error); - spin_lock(&sbi->s_md_lock); - } - spin_unlock(&sbi->s_md_lock); -} - -/* Deal with the reporting of failure conditions on a filesystem such as - * inconsistencies detected or read IO failures. - * - * On ext2, we can store the error state of the filesystem in the - * superblock. That is not possible on ext4, because we may have other - * write ordering constraints on the superblock which prevent us from - * writing it out straight away; and given that the journal is about to - * be aborted, we can't rely on the current, or future, transactions to - * write out the superblock safely. - * - * We'll just use the jbd2_journal_abort() error code to record an error in - * the journal instead. On recovery, the journal will complain about - * that error until we've noted it down and cleared it. - */ - -static void ext4_handle_error(struct super_block *sb) -{ - if (sb->s_flags & MS_RDONLY) - return; - - if (!test_opt(sb, ERRORS_CONT)) { - journal_t *journal = EXT4_SB(sb)->s_journal; - - EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED; - if (journal) - jbd2_journal_abort(journal, -EIO); - } - if (test_opt(sb, ERRORS_RO)) { - ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only"); - /* - * Make sure updated value of ->s_mount_flags will be visible - * before ->s_flags update - */ - smp_wmb(); - sb->s_flags |= MS_RDONLY; - } - if (test_opt(sb, ERRORS_PANIC)) { - if (EXT4_SB(sb)->s_journal && - !(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR)) - return; - panic("EXT4-fs (device %s): panic forced after error\n", - sb->s_id); - } -} - -#define ext4_error_ratelimit(sb) \ - ___ratelimit(&(EXT4_SB(sb)->s_err_ratelimit_state), \ - "EXT4-fs error") - -void __ext4_error(struct super_block *sb, const char *function, - unsigned int line, const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - if (ext4_error_ratelimit(sb)) { - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; - printk(KERN_CRIT - "EXT4-fs error (device %s): %s:%d: comm %s: %pV\n", - sb->s_id, function, line, current->comm, &vaf); - va_end(args); - } - save_error_info(sb, function, line); - ext4_handle_error(sb); -} - -void __ext4_error_inode(struct inode *inode, const char *function, - unsigned int line, ext4_fsblk_t block, - const char *fmt, ...) -{ - va_list args; - struct va_format vaf; - struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es; - - es->s_last_error_ino = cpu_to_le32(inode->i_ino); - es->s_last_error_block = cpu_to_le64(block); - if (ext4_error_ratelimit(inode->i_sb)) { - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; - if (block) - printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: " - "inode #%lu: block %llu: comm %s: %pV\n", - inode->i_sb->s_id, function, line, inode->i_ino, - block, current->comm, &vaf); - else - printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: " - "inode #%lu: comm %s: %pV\n", - inode->i_sb->s_id, function, line, inode->i_ino, - current->comm, &vaf); - va_end(args); - } - save_error_info(inode->i_sb, function, line); - ext4_handle_error(inode->i_sb); -} - -void __ext4_error_file(struct file *file, const char *function, - unsigned int line, ext4_fsblk_t block, - const char *fmt, ...) -{ - va_list args; - struct va_format vaf; - struct ext4_super_block *es; - struct inode *inode = file_inode(file); - char pathname[80], *path; - - es = EXT4_SB(inode->i_sb)->s_es; - es->s_last_error_ino = cpu_to_le32(inode->i_ino); - if (ext4_error_ratelimit(inode->i_sb)) { - path = file_path(file, pathname, sizeof(pathname)); - if (IS_ERR(path)) - path = "(unknown)"; - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; - if (block) - printk(KERN_CRIT - "EXT4-fs error (device %s): %s:%d: inode #%lu: " - "block %llu: comm %s: path %s: %pV\n", - inode->i_sb->s_id, function, line, inode->i_ino, - block, current->comm, path, &vaf); - else - printk(KERN_CRIT - "EXT4-fs error (device %s): %s:%d: inode #%lu: " - "comm %s: path %s: %pV\n", - inode->i_sb->s_id, function, line, inode->i_ino, - current->comm, path, &vaf); - va_end(args); - } - save_error_info(inode->i_sb, function, line); - ext4_handle_error(inode->i_sb); -} - -const char *ext4_decode_error(struct super_block *sb, int errno, - char nbuf[16]) -{ - char *errstr = NULL; - - switch (errno) { - case -EFSCORRUPTED: - errstr = "Corrupt filesystem"; - break; - case -EFSBADCRC: - errstr = "Filesystem failed CRC"; - break; - case -EIO: - errstr = "IO failure"; - break; - case -ENOMEM: - errstr = "Out of memory"; - break; - case -EROFS: - if (!sb || (EXT4_SB(sb)->s_journal && - EXT4_SB(sb)->s_journal->j_flags & JBD2_ABORT)) - errstr = "Journal has aborted"; - else - errstr = "Readonly filesystem"; - break; - default: - /* If the caller passed in an extra buffer for unknown - * errors, textualise them now. Else we just return - * NULL. */ - if (nbuf) { - /* Check for truncated error codes... */ - if (snprintf(nbuf, 16, "error %d", -errno) >= 0) - errstr = nbuf; - } - break; - } - - return errstr; -} - -/* __ext4_std_error decodes expected errors from journaling functions - * automatically and invokes the appropriate error response. */ - -void __ext4_std_error(struct super_block *sb, const char *function, - unsigned int line, int errno) -{ - char nbuf[16]; - const char *errstr; - - /* Special case: if the error is EROFS, and we're not already - * inside a transaction, then there's really no point in logging - * an error. */ - if (errno == -EROFS && journal_current_handle() == NULL && - (sb->s_flags & MS_RDONLY)) - return; - - if (ext4_error_ratelimit(sb)) { - errstr = ext4_decode_error(sb, errno, nbuf); - printk(KERN_CRIT "EXT4-fs error (device %s) in %s:%d: %s\n", - sb->s_id, function, line, errstr); - } - - save_error_info(sb, function, line); - ext4_handle_error(sb); -} - -/* - * ext4_abort is a much stronger failure handler than ext4_error. The - * abort function may be used to deal with unrecoverable failures such - * as journal IO errors or ENOMEM at a critical moment in log management. - * - * We unconditionally force the filesystem into an ABORT|READONLY state, - * unless the error response on the fs has been set to panic in which - * case we take the easy way out and panic immediately. - */ - -void __ext4_abort(struct super_block *sb, const char *function, - unsigned int line, const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - save_error_info(sb, function, line); - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; - printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: %pV\n", - sb->s_id, function, line, &vaf); - va_end(args); - - if ((sb->s_flags & MS_RDONLY) == 0) { - ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only"); - EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED; - /* - * Make sure updated value of ->s_mount_flags will be visible - * before ->s_flags update - */ - smp_wmb(); - sb->s_flags |= MS_RDONLY; - if (EXT4_SB(sb)->s_journal) - jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO); - save_error_info(sb, function, line); - } - if (test_opt(sb, ERRORS_PANIC)) { - if (EXT4_SB(sb)->s_journal && - !(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR)) - return; - panic("EXT4-fs panic from previous error\n"); - } -} - -void __ext4_msg(struct super_block *sb, - const char *prefix, const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - if (!___ratelimit(&(EXT4_SB(sb)->s_msg_ratelimit_state), "EXT4-fs")) - return; - - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; - printk("%sEXT4-fs (%s): %pV\n", prefix, sb->s_id, &vaf); - va_end(args); -} - -#define ext4_warning_ratelimit(sb) \ - ___ratelimit(&(EXT4_SB(sb)->s_warning_ratelimit_state), \ - "EXT4-fs warning") - -void __ext4_warning(struct super_block *sb, const char *function, - unsigned int line, const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - if (!ext4_warning_ratelimit(sb)) - return; - - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; - printk(KERN_WARNING "EXT4-fs warning (device %s): %s:%d: %pV\n", - sb->s_id, function, line, &vaf); - va_end(args); -} - -void __ext4_warning_inode(const struct inode *inode, const char *function, - unsigned int line, const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - if (!ext4_warning_ratelimit(inode->i_sb)) - return; - - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; - printk(KERN_WARNING "EXT4-fs warning (device %s): %s:%d: " - "inode #%lu: comm %s: %pV\n", inode->i_sb->s_id, - function, line, inode->i_ino, current->comm, &vaf); - va_end(args); -} - -void __ext4_grp_locked_error(const char *function, unsigned int line, - struct super_block *sb, ext4_group_t grp, - unsigned long ino, ext4_fsblk_t block, - const char *fmt, ...) -__releases(bitlock) -__acquires(bitlock) -{ - struct va_format vaf; - va_list args; - struct ext4_super_block *es = EXT4_SB(sb)->s_es; - - es->s_last_error_ino = cpu_to_le32(ino); - es->s_last_error_block = cpu_to_le64(block); - __save_error_info(sb, function, line); - - if (ext4_error_ratelimit(sb)) { - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; - printk(KERN_CRIT "EXT4-fs error (device %s): %s:%d: group %u, ", - sb->s_id, function, line, grp); - if (ino) - printk(KERN_CONT "inode %lu: ", ino); - if (block) - printk(KERN_CONT "block %llu:", - (unsigned long long) block); - printk(KERN_CONT "%pV\n", &vaf); - va_end(args); - } - - if (test_opt(sb, ERRORS_CONT)) { - ext4_commit_super(sb, 0); - return; - } - - ext4_unlock_group(sb, grp); - ext4_handle_error(sb); - /* - * We only get here in the ERRORS_RO case; relocking the group - * may be dangerous, but nothing bad will happen since the - * filesystem will have already been marked read/only and the - * journal has been aborted. We return 1 as a hint to callers - * who might what to use the return value from - * ext4_grp_locked_error() to distinguish between the - * ERRORS_CONT and ERRORS_RO case, and perhaps return more - * aggressively from the ext4 function in question, with a - * more appropriate error code. - */ - ext4_lock_group(sb, grp); - return; -} - -void ext4_update_dynamic_rev(struct super_block *sb) -{ - struct ext4_super_block *es = EXT4_SB(sb)->s_es; - - if (le32_to_cpu(es->s_rev_level) > EXT4_GOOD_OLD_REV) - return; - - ext4_warning(sb, - "updating to rev %d because of new feature flag, " - "running e2fsck is recommended", - EXT4_DYNAMIC_REV); - - es->s_first_ino = cpu_to_le32(EXT4_GOOD_OLD_FIRST_INO); - es->s_inode_size = cpu_to_le16(EXT4_GOOD_OLD_INODE_SIZE); - es->s_rev_level = cpu_to_le32(EXT4_DYNAMIC_REV); - /* leave es->s_feature_*compat flags alone */ - /* es->s_uuid will be set by e2fsck if empty */ - - /* - * The rest of the superblock fields should be zero, and if not it - * means they are likely already in use, so leave them alone. We - * can leave it up to e2fsck to clean up any inconsistencies there. - */ -} - -/* - * Open the external journal device - */ -static struct block_device *ext4_blkdev_get(dev_t dev, struct super_block *sb) -{ - struct block_device *bdev; - char b[BDEVNAME_SIZE]; - - bdev = blkdev_get_by_dev(dev, FMODE_READ|FMODE_WRITE|FMODE_EXCL, sb); - if (IS_ERR(bdev)) - goto fail; - return bdev; - -fail: - ext4_msg(sb, KERN_ERR, "failed to open journal device %s: %ld", - __bdevname(dev, b), PTR_ERR(bdev)); - return NULL; -} - -/* - * Release the journal device - */ -static void ext4_blkdev_put(struct block_device *bdev) -{ - blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); -} - -static void ext4_blkdev_remove(struct ext4_sb_info *sbi) -{ - struct block_device *bdev; - bdev = sbi->journal_bdev; - if (bdev) { - ext4_blkdev_put(bdev); - sbi->journal_bdev = NULL; - } -} - -static inline struct inode *orphan_list_entry(struct list_head *l) -{ - return &list_entry(l, struct ext4_inode_info, i_orphan)->vfs_inode; -} - -static void dump_orphan_list(struct super_block *sb, struct ext4_sb_info *sbi) -{ - struct list_head *l; - - ext4_msg(sb, KERN_ERR, "sb orphan head is %d", - le32_to_cpu(sbi->s_es->s_last_orphan)); - - printk(KERN_ERR "sb_info orphan list:\n"); - list_for_each(l, &sbi->s_orphan) { - struct inode *inode = orphan_list_entry(l); - printk(KERN_ERR " " - "inode %s:%lu at %p: mode %o, nlink %d, next %d\n", - inode->i_sb->s_id, inode->i_ino, inode, - inode->i_mode, inode->i_nlink, - NEXT_ORPHAN(inode)); - } -} - -static void ext4_put_super(struct super_block *sb) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_super_block *es = sbi->s_es; - int i, err; - - ext4_unregister_li_request(sb); - dquot_disable(sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); - - flush_workqueue(sbi->rsv_conversion_wq); - destroy_workqueue(sbi->rsv_conversion_wq); - - if (sbi->s_journal) { - err = jbd2_journal_destroy(sbi->s_journal); - sbi->s_journal = NULL; - if (err < 0) - ext4_abort(sb, "Couldn't clean up the journal"); - } - - ext4_unregister_sysfs(sb); - ext4_es_unregister_shrinker(sbi); - del_timer_sync(&sbi->s_err_report); - ext4_release_system_zone(sb); - ext4_mb_release(sb); - ext4_ext_release(sb); - - if (!(sb->s_flags & MS_RDONLY)) { - ext4_clear_feature_journal_needs_recovery(sb); - es->s_state = cpu_to_le16(sbi->s_mount_state); - } - if (!(sb->s_flags & MS_RDONLY)) - ext4_commit_super(sb, 1); - - for (i = 0; i < sbi->s_gdb_count; i++) - brelse(sbi->s_group_desc[i]); - kvfree(sbi->s_group_desc); - kvfree(sbi->s_flex_groups); - percpu_counter_destroy(&sbi->s_freeclusters_counter); - percpu_counter_destroy(&sbi->s_freeinodes_counter); - percpu_counter_destroy(&sbi->s_dirs_counter); - percpu_counter_destroy(&sbi->s_dirtyclusters_counter); - percpu_free_rwsem(&sbi->s_journal_flag_rwsem); - brelse(sbi->s_sbh); -#ifdef CONFIG_QUOTA - for (i = 0; i < EXT4_MAXQUOTAS; i++) - kfree(sbi->s_qf_names[i]); -#endif - - /* Debugging code just in case the in-memory inode orphan list - * isn't empty. The on-disk one can be non-empty if we've - * detected an error and taken the fs readonly, but the - * in-memory list had better be clean by this point. */ - if (!list_empty(&sbi->s_orphan)) - dump_orphan_list(sb, sbi); - J_ASSERT(list_empty(&sbi->s_orphan)); - - sync_blockdev(sb->s_bdev); - invalidate_bdev(sb->s_bdev); - if (sbi->journal_bdev && sbi->journal_bdev != sb->s_bdev) { - /* - * Invalidate the journal device's buffers. We don't want them - * floating about in memory - the physical journal device may - * hotswapped, and it breaks the `ro-after' testing code. - */ - sync_blockdev(sbi->journal_bdev); - invalidate_bdev(sbi->journal_bdev); - ext4_blkdev_remove(sbi); - } - if (sbi->s_mb_cache) { - ext4_xattr_destroy_cache(sbi->s_mb_cache); - sbi->s_mb_cache = NULL; - } - if (sbi->s_mmp_tsk) - kthread_stop(sbi->s_mmp_tsk); - sb->s_fs_info = NULL; - /* - * Now that we are completely done shutting down the - * superblock, we need to actually destroy the kobject. - */ - kobject_put(&sbi->s_kobj); - wait_for_completion(&sbi->s_kobj_unregister); - if (sbi->s_chksum_driver) - crypto_free_shash(sbi->s_chksum_driver); - kfree(sbi->s_blockgroup_lock); - kfree(sbi); -} - -static struct kmem_cache *ext4_inode_cachep; - -/* - * Called inside transaction, so use GFP_NOFS - */ -static struct inode *ext4_alloc_inode(struct super_block *sb) -{ - struct ext4_inode_info *ei; - - ei = kmem_cache_alloc(ext4_inode_cachep, GFP_NOFS); - if (!ei) - return NULL; - - ei->vfs_inode.i_version = 1; - spin_lock_init(&ei->i_raw_lock); - INIT_LIST_HEAD(&ei->i_prealloc_list); - spin_lock_init(&ei->i_prealloc_lock); - ext4_es_init_tree(&ei->i_es_tree); - rwlock_init(&ei->i_es_lock); - INIT_LIST_HEAD(&ei->i_es_list); - ei->i_es_all_nr = 0; - ei->i_es_shk_nr = 0; - ei->i_es_shrink_lblk = 0; - ei->i_reserved_data_blocks = 0; - ei->i_reserved_meta_blocks = 0; - ei->i_allocated_meta_blocks = 0; - ei->i_da_metadata_calc_len = 0; - ei->i_da_metadata_calc_last_lblock = 0; - spin_lock_init(&(ei->i_block_reservation_lock)); -#ifdef CONFIG_QUOTA - ei->i_reserved_quota = 0; - memset(&ei->i_dquot, 0, sizeof(ei->i_dquot)); -#endif - ei->jinode = NULL; - INIT_LIST_HEAD(&ei->i_rsv_conversion_list); - spin_lock_init(&ei->i_completed_io_lock); - ei->i_sync_tid = 0; - ei->i_datasync_tid = 0; - atomic_set(&ei->i_unwritten, 0); - INIT_WORK(&ei->i_rsv_conversion_work, ext4_end_io_rsv_work); - return &ei->vfs_inode; -} - -static int ext4_drop_inode(struct inode *inode) -{ - int drop = generic_drop_inode(inode); - - trace_ext4_drop_inode(inode, drop); - return drop; -} - -static void ext4_i_callback(struct rcu_head *head) -{ - struct inode *inode = container_of(head, struct inode, i_rcu); - kmem_cache_free(ext4_inode_cachep, EXT4_I(inode)); -} - -static void ext4_destroy_inode(struct inode *inode) -{ - if (!list_empty(&(EXT4_I(inode)->i_orphan))) { - ext4_msg(inode->i_sb, KERN_ERR, - "Inode %lu (%p): orphan list check failed!", - inode->i_ino, EXT4_I(inode)); - print_hex_dump(KERN_INFO, "", DUMP_PREFIX_ADDRESS, 16, 4, - EXT4_I(inode), sizeof(struct ext4_inode_info), - true); - dump_stack(); - } - call_rcu(&inode->i_rcu, ext4_i_callback); -} - -static void init_once(void *foo) -{ - struct ext4_inode_info *ei = (struct ext4_inode_info *) foo; - - INIT_LIST_HEAD(&ei->i_orphan); - init_rwsem(&ei->xattr_sem); - init_rwsem(&ei->i_data_sem); - init_rwsem(&ei->i_mmap_sem); - inode_init_once(&ei->vfs_inode); -} - -static int __init init_inodecache(void) -{ - ext4_inode_cachep = kmem_cache_create("ext4_inode_cache", - sizeof(struct ext4_inode_info), - 0, (SLAB_RECLAIM_ACCOUNT| - SLAB_MEM_SPREAD|SLAB_ACCOUNT), - init_once); - if (ext4_inode_cachep == NULL) - return -ENOMEM; - return 0; -} - -static void destroy_inodecache(void) -{ - /* - * Make sure all delayed rcu free inodes are flushed before we - * destroy cache. - */ - rcu_barrier(); - kmem_cache_destroy(ext4_inode_cachep); -} - -void ext4_clear_inode(struct inode *inode) -{ - invalidate_inode_buffers(inode); - clear_inode(inode); - dquot_drop(inode); - ext4_discard_preallocations(inode); - ext4_es_remove_extent(inode, 0, EXT_MAX_BLOCKS); - if (EXT4_I(inode)->jinode) { - jbd2_journal_release_jbd_inode(EXT4_JOURNAL(inode), - EXT4_I(inode)->jinode); - jbd2_free_inode(EXT4_I(inode)->jinode); - EXT4_I(inode)->jinode = NULL; - } -#ifdef CONFIG_EXT4_FS_ENCRYPTION - fscrypt_put_encryption_info(inode, NULL); -#endif -} - -static struct inode *ext4_nfs_get_inode(struct super_block *sb, - u64 ino, u32 generation) -{ - struct inode *inode; - - if (ino < EXT4_FIRST_INO(sb) && ino != EXT4_ROOT_INO) - return ERR_PTR(-ESTALE); - if (ino > le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count)) - return ERR_PTR(-ESTALE); - - /* iget isn't really right if the inode is currently unallocated!! - * - * ext4_read_inode will return a bad_inode if the inode had been - * deleted, so we should be safe. - * - * Currently we don't know the generation for parent directory, so - * a generation of 0 means "accept any" - */ - inode = ext4_iget_normal(sb, ino); - if (IS_ERR(inode)) - return ERR_CAST(inode); - if (generation && inode->i_generation != generation) { - iput(inode); - return ERR_PTR(-ESTALE); - } - - return inode; -} - -static struct dentry *ext4_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, - ext4_nfs_get_inode); -} - -static struct dentry *ext4_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, - ext4_nfs_get_inode); -} - -/* - * Try to release metadata pages (indirect blocks, directories) which are - * mapped via the block device. Since these pages could have journal heads - * which would prevent try_to_free_buffers() from freeing them, we must use - * jbd2 layer's try_to_free_buffers() function to release them. - */ -static int bdev_try_to_free_page(struct super_block *sb, struct page *page, - gfp_t wait) -{ - journal_t *journal = EXT4_SB(sb)->s_journal; - - WARN_ON(PageChecked(page)); - if (!page_has_buffers(page)) - return 0; - if (journal) - return jbd2_journal_try_to_free_buffers(journal, page, - wait & ~__GFP_DIRECT_RECLAIM); - return try_to_free_buffers(page); -} - -#ifdef CONFIG_EXT4_FS_ENCRYPTION -static int ext4_get_context(struct inode *inode, void *ctx, size_t len) -{ - return ext4_xattr_get(inode, EXT4_XATTR_INDEX_ENCRYPTION, - EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx, len); -} - -static int ext4_key_prefix(struct inode *inode, u8 **key) -{ - *key = EXT4_SB(inode->i_sb)->key_prefix; - return EXT4_SB(inode->i_sb)->key_prefix_size; -} - -static int ext4_prepare_context(struct inode *inode) -{ - return ext4_convert_inline_data(inode); -} - -static int ext4_set_context(struct inode *inode, const void *ctx, size_t len, - void *fs_data) -{ - handle_t *handle; - int res, res2; - - /* fs_data is null when internally used. */ - if (fs_data) { - res = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION, - EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx, - len, 0); - if (!res) { - ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT); - ext4_clear_inode_state(inode, - EXT4_STATE_MAY_INLINE_DATA); - } - return res; - } - - handle = ext4_journal_start(inode, EXT4_HT_MISC, - ext4_jbd2_credits_xattr(inode)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - - res = ext4_xattr_set(inode, EXT4_XATTR_INDEX_ENCRYPTION, - EXT4_XATTR_NAME_ENCRYPTION_CONTEXT, ctx, - len, 0); - if (!res) { - ext4_set_inode_flag(inode, EXT4_INODE_ENCRYPT); - res = ext4_mark_inode_dirty(handle, inode); - if (res) - EXT4_ERROR_INODE(inode, "Failed to mark inode dirty"); - } - res2 = ext4_journal_stop(handle); - if (!res) - res = res2; - return res; -} - -static int ext4_dummy_context(struct inode *inode) -{ - return DUMMY_ENCRYPTION_ENABLED(EXT4_SB(inode->i_sb)); -} - -static unsigned ext4_max_namelen(struct inode *inode) -{ - return S_ISLNK(inode->i_mode) ? inode->i_sb->s_blocksize : - EXT4_NAME_LEN; -} - -static struct fscrypt_operations ext4_cryptops = { - .get_context = ext4_get_context, - .key_prefix = ext4_key_prefix, - .prepare_context = ext4_prepare_context, - .set_context = ext4_set_context, - .dummy_context = ext4_dummy_context, - .is_encrypted = ext4_encrypted_inode, - .empty_dir = ext4_empty_dir, - .max_namelen = ext4_max_namelen, -}; -#else -static struct fscrypt_operations ext4_cryptops = { - .is_encrypted = ext4_encrypted_inode, -}; -#endif - -#ifdef CONFIG_QUOTA -static char *quotatypes[] = INITQFNAMES; -#define QTYPE2NAME(t) (quotatypes[t]) - -static int ext4_write_dquot(struct dquot *dquot); -static int ext4_acquire_dquot(struct dquot *dquot); -static int ext4_release_dquot(struct dquot *dquot); -static int ext4_mark_dquot_dirty(struct dquot *dquot); -static int ext4_write_info(struct super_block *sb, int type); -static int ext4_quota_on(struct super_block *sb, int type, int format_id, - struct path *path); -static int ext4_quota_off(struct super_block *sb, int type); -static int ext4_quota_on_mount(struct super_block *sb, int type); -static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data, - size_t len, loff_t off); -static ssize_t ext4_quota_write(struct super_block *sb, int type, - const char *data, size_t len, loff_t off); -static int ext4_quota_enable(struct super_block *sb, int type, int format_id, - unsigned int flags); -static int ext4_enable_quotas(struct super_block *sb); -static int ext4_get_next_id(struct super_block *sb, struct kqid *qid); - -static struct dquot **ext4_get_dquots(struct inode *inode) -{ - return EXT4_I(inode)->i_dquot; -} - -static const struct dquot_operations ext4_quota_operations = { - .get_reserved_space = ext4_get_reserved_space, - .write_dquot = ext4_write_dquot, - .acquire_dquot = ext4_acquire_dquot, - .release_dquot = ext4_release_dquot, - .mark_dirty = ext4_mark_dquot_dirty, - .write_info = ext4_write_info, - .alloc_dquot = dquot_alloc, - .destroy_dquot = dquot_destroy, - .get_projid = ext4_get_projid, - .get_next_id = ext4_get_next_id, -}; - -static const struct quotactl_ops ext4_qctl_operations = { - .quota_on = ext4_quota_on, - .quota_off = ext4_quota_off, - .quota_sync = dquot_quota_sync, - .get_state = dquot_get_state, - .set_info = dquot_set_dqinfo, - .get_dqblk = dquot_get_dqblk, - .set_dqblk = dquot_set_dqblk, - .get_nextdqblk = dquot_get_next_dqblk, -}; -#endif - -static const struct super_operations ext4_sops = { - .alloc_inode = ext4_alloc_inode, - .destroy_inode = ext4_destroy_inode, - .write_inode = ext4_write_inode, - .dirty_inode = ext4_dirty_inode, - .drop_inode = ext4_drop_inode, - .evict_inode = ext4_evict_inode, - .put_super = ext4_put_super, - .sync_fs = ext4_sync_fs, - .freeze_fs = ext4_freeze, - .unfreeze_fs = ext4_unfreeze, - .statfs = ext4_statfs, - .remount_fs = ext4_remount, - .show_options = ext4_show_options, -#ifdef CONFIG_QUOTA - .quota_read = ext4_quota_read, - .quota_write = ext4_quota_write, - .get_dquots = ext4_get_dquots, -#endif - .bdev_try_to_free_page = bdev_try_to_free_page, -}; - -static const struct export_operations ext4_export_ops = { - .fh_to_dentry = ext4_fh_to_dentry, - .fh_to_parent = ext4_fh_to_parent, - .get_parent = ext4_get_parent, -}; - -enum { - Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid, - Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro, - Opt_nouid32, Opt_debug, Opt_removed, - Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, - Opt_auto_da_alloc, Opt_noauto_da_alloc, Opt_noload, - Opt_commit, Opt_min_batch_time, Opt_max_batch_time, Opt_journal_dev, - Opt_journal_path, Opt_journal_checksum, Opt_journal_async_commit, - Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback, - Opt_data_err_abort, Opt_data_err_ignore, Opt_test_dummy_encryption, - Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, - Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota, - Opt_noquota, Opt_barrier, Opt_nobarrier, Opt_err, - Opt_usrquota, Opt_grpquota, Opt_prjquota, Opt_i_version, Opt_dax, - Opt_stripe, Opt_delalloc, Opt_nodelalloc, Opt_mblk_io_submit, - Opt_lazytime, Opt_nolazytime, - Opt_nomblk_io_submit, Opt_block_validity, Opt_noblock_validity, - Opt_inode_readahead_blks, Opt_journal_ioprio, - Opt_dioread_nolock, Opt_dioread_lock, - Opt_discard, Opt_nodiscard, Opt_init_itable, Opt_noinit_itable, - Opt_max_dir_size_kb, Opt_nojournal_checksum, -}; - -static const match_table_t tokens = { - {Opt_bsd_df, "bsddf"}, - {Opt_minix_df, "minixdf"}, - {Opt_grpid, "grpid"}, - {Opt_grpid, "bsdgroups"}, - {Opt_nogrpid, "nogrpid"}, - {Opt_nogrpid, "sysvgroups"}, - {Opt_resgid, "resgid=%u"}, - {Opt_resuid, "resuid=%u"}, - {Opt_sb, "sb=%u"}, - {Opt_err_cont, "errors=continue"}, - {Opt_err_panic, "errors=panic"}, - {Opt_err_ro, "errors=remount-ro"}, - {Opt_nouid32, "nouid32"}, - {Opt_debug, "debug"}, - {Opt_removed, "oldalloc"}, - {Opt_removed, "orlov"}, - {Opt_user_xattr, "user_xattr"}, - {Opt_nouser_xattr, "nouser_xattr"}, - {Opt_acl, "acl"}, - {Opt_noacl, "noacl"}, - {Opt_noload, "norecovery"}, - {Opt_noload, "noload"}, - {Opt_removed, "nobh"}, - {Opt_removed, "bh"}, - {Opt_commit, "commit=%u"}, - {Opt_min_batch_time, "min_batch_time=%u"}, - {Opt_max_batch_time, "max_batch_time=%u"}, - {Opt_journal_dev, "journal_dev=%u"}, - {Opt_journal_path, "journal_path=%s"}, - {Opt_journal_checksum, "journal_checksum"}, - {Opt_nojournal_checksum, "nojournal_checksum"}, - {Opt_journal_async_commit, "journal_async_commit"}, - {Opt_abort, "abort"}, - {Opt_data_journal, "data=journal"}, - {Opt_data_ordered, "data=ordered"}, - {Opt_data_writeback, "data=writeback"}, - {Opt_data_err_abort, "data_err=abort"}, - {Opt_data_err_ignore, "data_err=ignore"}, - {Opt_offusrjquota, "usrjquota="}, - {Opt_usrjquota, "usrjquota=%s"}, - {Opt_offgrpjquota, "grpjquota="}, - {Opt_grpjquota, "grpjquota=%s"}, - {Opt_jqfmt_vfsold, "jqfmt=vfsold"}, - {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"}, - {Opt_jqfmt_vfsv1, "jqfmt=vfsv1"}, - {Opt_grpquota, "grpquota"}, - {Opt_noquota, "noquota"}, - {Opt_quota, "quota"}, - {Opt_usrquota, "usrquota"}, - {Opt_prjquota, "prjquota"}, - {Opt_barrier, "barrier=%u"}, - {Opt_barrier, "barrier"}, - {Opt_nobarrier, "nobarrier"}, - {Opt_i_version, "i_version"}, - {Opt_dax, "dax"}, - {Opt_stripe, "stripe=%u"}, - {Opt_delalloc, "delalloc"}, - {Opt_lazytime, "lazytime"}, - {Opt_nolazytime, "nolazytime"}, - {Opt_nodelalloc, "nodelalloc"}, - {Opt_removed, "mblk_io_submit"}, - {Opt_removed, "nomblk_io_submit"}, - {Opt_block_validity, "block_validity"}, - {Opt_noblock_validity, "noblock_validity"}, - {Opt_inode_readahead_blks, "inode_readahead_blks=%u"}, - {Opt_journal_ioprio, "journal_ioprio=%u"}, - {Opt_auto_da_alloc, "auto_da_alloc=%u"}, - {Opt_auto_da_alloc, "auto_da_alloc"}, - {Opt_noauto_da_alloc, "noauto_da_alloc"}, - {Opt_dioread_nolock, "dioread_nolock"}, - {Opt_dioread_lock, "dioread_lock"}, - {Opt_discard, "discard"}, - {Opt_nodiscard, "nodiscard"}, - {Opt_init_itable, "init_itable=%u"}, - {Opt_init_itable, "init_itable"}, - {Opt_noinit_itable, "noinit_itable"}, - {Opt_max_dir_size_kb, "max_dir_size_kb=%u"}, - {Opt_test_dummy_encryption, "test_dummy_encryption"}, - {Opt_removed, "check=none"}, /* mount option from ext2/3 */ - {Opt_removed, "nocheck"}, /* mount option from ext2/3 */ - {Opt_removed, "reservation"}, /* mount option from ext2/3 */ - {Opt_removed, "noreservation"}, /* mount option from ext2/3 */ - {Opt_removed, "journal=%u"}, /* mount option from ext2/3 */ - {Opt_err, NULL}, -}; - -static ext4_fsblk_t get_sb_block(void **data) -{ - ext4_fsblk_t sb_block; - char *options = (char *) *data; - - if (!options || strncmp(options, "sb=", 3) != 0) - return 1; /* Default location */ - - options += 3; - /* TODO: use simple_strtoll with >32bit ext4 */ - sb_block = simple_strtoul(options, &options, 0); - if (*options && *options != ',') { - printk(KERN_ERR "EXT4-fs: Invalid sb specification: %s\n", - (char *) *data); - return 1; - } - if (*options == ',') - options++; - *data = (void *) options; - - return sb_block; -} - -#define DEFAULT_JOURNAL_IOPRIO (IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 3)) -static char deprecated_msg[] = "Mount option \"%s\" will be removed by %s\n" - "Contact linux-ext4@vger.kernel.org if you think we should keep it.\n"; - -#ifdef CONFIG_QUOTA -static int set_qf_name(struct super_block *sb, int qtype, substring_t *args) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - char *qname; - int ret = -1; - - if (sb_any_quota_loaded(sb) && - !sbi->s_qf_names[qtype]) { - ext4_msg(sb, KERN_ERR, - "Cannot change journaled " - "quota options when quota turned on"); - return -1; - } - if (ext4_has_feature_quota(sb)) { - ext4_msg(sb, KERN_INFO, "Journaled quota options " - "ignored when QUOTA feature is enabled"); - return 1; - } - qname = match_strdup(args); - if (!qname) { - ext4_msg(sb, KERN_ERR, - "Not enough memory for storing quotafile name"); - return -1; - } - if (sbi->s_qf_names[qtype]) { - if (strcmp(sbi->s_qf_names[qtype], qname) == 0) - ret = 1; - else - ext4_msg(sb, KERN_ERR, - "%s quota file already specified", - QTYPE2NAME(qtype)); - goto errout; - } - if (strchr(qname, '/')) { - ext4_msg(sb, KERN_ERR, - "quotafile must be on filesystem root"); - goto errout; - } - sbi->s_qf_names[qtype] = qname; - set_opt(sb, QUOTA); - return 1; -errout: - kfree(qname); - return ret; -} - -static int clear_qf_name(struct super_block *sb, int qtype) -{ - - struct ext4_sb_info *sbi = EXT4_SB(sb); - - if (sb_any_quota_loaded(sb) && - sbi->s_qf_names[qtype]) { - ext4_msg(sb, KERN_ERR, "Cannot change journaled quota options" - " when quota turned on"); - return -1; - } - kfree(sbi->s_qf_names[qtype]); - sbi->s_qf_names[qtype] = NULL; - return 1; -} -#endif - -#define MOPT_SET 0x0001 -#define MOPT_CLEAR 0x0002 -#define MOPT_NOSUPPORT 0x0004 -#define MOPT_EXPLICIT 0x0008 -#define MOPT_CLEAR_ERR 0x0010 -#define MOPT_GTE0 0x0020 -#ifdef CONFIG_QUOTA -#define MOPT_Q 0 -#define MOPT_QFMT 0x0040 -#else -#define MOPT_Q MOPT_NOSUPPORT -#define MOPT_QFMT MOPT_NOSUPPORT -#endif -#define MOPT_DATAJ 0x0080 -#define MOPT_NO_EXT2 0x0100 -#define MOPT_NO_EXT3 0x0200 -#define MOPT_EXT4_ONLY (MOPT_NO_EXT2 | MOPT_NO_EXT3) -#define MOPT_STRING 0x0400 - -static const struct mount_opts { - int token; - int mount_opt; - int flags; -} ext4_mount_opts[] = { - {Opt_minix_df, EXT4_MOUNT_MINIX_DF, MOPT_SET}, - {Opt_bsd_df, EXT4_MOUNT_MINIX_DF, MOPT_CLEAR}, - {Opt_grpid, EXT4_MOUNT_GRPID, MOPT_SET}, - {Opt_nogrpid, EXT4_MOUNT_GRPID, MOPT_CLEAR}, - {Opt_block_validity, EXT4_MOUNT_BLOCK_VALIDITY, MOPT_SET}, - {Opt_noblock_validity, EXT4_MOUNT_BLOCK_VALIDITY, MOPT_CLEAR}, - {Opt_dioread_nolock, EXT4_MOUNT_DIOREAD_NOLOCK, - MOPT_EXT4_ONLY | MOPT_SET}, - {Opt_dioread_lock, EXT4_MOUNT_DIOREAD_NOLOCK, - MOPT_EXT4_ONLY | MOPT_CLEAR}, - {Opt_discard, EXT4_MOUNT_DISCARD, MOPT_SET}, - {Opt_nodiscard, EXT4_MOUNT_DISCARD, MOPT_CLEAR}, - {Opt_delalloc, EXT4_MOUNT_DELALLOC, - MOPT_EXT4_ONLY | MOPT_SET | MOPT_EXPLICIT}, - {Opt_nodelalloc, EXT4_MOUNT_DELALLOC, - MOPT_EXT4_ONLY | MOPT_CLEAR}, - {Opt_nojournal_checksum, EXT4_MOUNT_JOURNAL_CHECKSUM, - MOPT_EXT4_ONLY | MOPT_CLEAR}, - {Opt_journal_checksum, EXT4_MOUNT_JOURNAL_CHECKSUM, - MOPT_EXT4_ONLY | MOPT_SET | MOPT_EXPLICIT}, - {Opt_journal_async_commit, (EXT4_MOUNT_JOURNAL_ASYNC_COMMIT | - EXT4_MOUNT_JOURNAL_CHECKSUM), - MOPT_EXT4_ONLY | MOPT_SET | MOPT_EXPLICIT}, - {Opt_noload, EXT4_MOUNT_NOLOAD, MOPT_NO_EXT2 | MOPT_SET}, - {Opt_err_panic, EXT4_MOUNT_ERRORS_PANIC, MOPT_SET | MOPT_CLEAR_ERR}, - {Opt_err_ro, EXT4_MOUNT_ERRORS_RO, MOPT_SET | MOPT_CLEAR_ERR}, - {Opt_err_cont, EXT4_MOUNT_ERRORS_CONT, MOPT_SET | MOPT_CLEAR_ERR}, - {Opt_data_err_abort, EXT4_MOUNT_DATA_ERR_ABORT, - MOPT_NO_EXT2}, - {Opt_data_err_ignore, EXT4_MOUNT_DATA_ERR_ABORT, - MOPT_NO_EXT2}, - {Opt_barrier, EXT4_MOUNT_BARRIER, MOPT_SET}, - {Opt_nobarrier, EXT4_MOUNT_BARRIER, MOPT_CLEAR}, - {Opt_noauto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_SET}, - {Opt_auto_da_alloc, EXT4_MOUNT_NO_AUTO_DA_ALLOC, MOPT_CLEAR}, - {Opt_noinit_itable, EXT4_MOUNT_INIT_INODE_TABLE, MOPT_CLEAR}, - {Opt_commit, 0, MOPT_GTE0}, - {Opt_max_batch_time, 0, MOPT_GTE0}, - {Opt_min_batch_time, 0, MOPT_GTE0}, - {Opt_inode_readahead_blks, 0, MOPT_GTE0}, - {Opt_init_itable, 0, MOPT_GTE0}, - {Opt_dax, EXT4_MOUNT_DAX, MOPT_SET}, - {Opt_stripe, 0, MOPT_GTE0}, - {Opt_resuid, 0, MOPT_GTE0}, - {Opt_resgid, 0, MOPT_GTE0}, - {Opt_journal_dev, 0, MOPT_NO_EXT2 | MOPT_GTE0}, - {Opt_journal_path, 0, MOPT_NO_EXT2 | MOPT_STRING}, - {Opt_journal_ioprio, 0, MOPT_NO_EXT2 | MOPT_GTE0}, - {Opt_data_journal, EXT4_MOUNT_JOURNAL_DATA, MOPT_NO_EXT2 | MOPT_DATAJ}, - {Opt_data_ordered, EXT4_MOUNT_ORDERED_DATA, MOPT_NO_EXT2 | MOPT_DATAJ}, - {Opt_data_writeback, EXT4_MOUNT_WRITEBACK_DATA, - MOPT_NO_EXT2 | MOPT_DATAJ}, - {Opt_user_xattr, EXT4_MOUNT_XATTR_USER, MOPT_SET}, - {Opt_nouser_xattr, EXT4_MOUNT_XATTR_USER, MOPT_CLEAR}, -#ifdef CONFIG_EXT4_FS_POSIX_ACL - {Opt_acl, EXT4_MOUNT_POSIX_ACL, MOPT_SET}, - {Opt_noacl, EXT4_MOUNT_POSIX_ACL, MOPT_CLEAR}, -#else - {Opt_acl, 0, MOPT_NOSUPPORT}, - {Opt_noacl, 0, MOPT_NOSUPPORT}, -#endif - {Opt_nouid32, EXT4_MOUNT_NO_UID32, MOPT_SET}, - {Opt_debug, EXT4_MOUNT_DEBUG, MOPT_SET}, - {Opt_quota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA, MOPT_SET | MOPT_Q}, - {Opt_usrquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA, - MOPT_SET | MOPT_Q}, - {Opt_grpquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_GRPQUOTA, - MOPT_SET | MOPT_Q}, - {Opt_prjquota, EXT4_MOUNT_QUOTA | EXT4_MOUNT_PRJQUOTA, - MOPT_SET | MOPT_Q}, - {Opt_noquota, (EXT4_MOUNT_QUOTA | EXT4_MOUNT_USRQUOTA | - EXT4_MOUNT_GRPQUOTA | EXT4_MOUNT_PRJQUOTA), - MOPT_CLEAR | MOPT_Q}, - {Opt_usrjquota, 0, MOPT_Q}, - {Opt_grpjquota, 0, MOPT_Q}, - {Opt_offusrjquota, 0, MOPT_Q}, - {Opt_offgrpjquota, 0, MOPT_Q}, - {Opt_jqfmt_vfsold, QFMT_VFS_OLD, MOPT_QFMT}, - {Opt_jqfmt_vfsv0, QFMT_VFS_V0, MOPT_QFMT}, - {Opt_jqfmt_vfsv1, QFMT_VFS_V1, MOPT_QFMT}, - {Opt_max_dir_size_kb, 0, MOPT_GTE0}, - {Opt_test_dummy_encryption, 0, MOPT_GTE0}, - {Opt_err, 0, 0} -}; - -static int handle_mount_opt(struct super_block *sb, char *opt, int token, - substring_t *args, unsigned long *journal_devnum, - unsigned int *journal_ioprio, int is_remount) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - const struct mount_opts *m; - kuid_t uid; - kgid_t gid; - int arg = 0; - -#ifdef CONFIG_QUOTA - if (token == Opt_usrjquota) - return set_qf_name(sb, USRQUOTA, &args[0]); - else if (token == Opt_grpjquota) - return set_qf_name(sb, GRPQUOTA, &args[0]); - else if (token == Opt_offusrjquota) - return clear_qf_name(sb, USRQUOTA); - else if (token == Opt_offgrpjquota) - return clear_qf_name(sb, GRPQUOTA); -#endif - switch (token) { - case Opt_noacl: - case Opt_nouser_xattr: - ext4_msg(sb, KERN_WARNING, deprecated_msg, opt, "3.5"); - break; - case Opt_sb: - return 1; /* handled by get_sb_block() */ - case Opt_removed: - ext4_msg(sb, KERN_WARNING, "Ignoring removed %s option", opt); - return 1; - case Opt_abort: - sbi->s_mount_flags |= EXT4_MF_FS_ABORTED; - return 1; - case Opt_i_version: - sb->s_flags |= MS_I_VERSION; - return 1; - case Opt_lazytime: - sb->s_flags |= MS_LAZYTIME; - return 1; - case Opt_nolazytime: - sb->s_flags &= ~MS_LAZYTIME; - return 1; - } - - for (m = ext4_mount_opts; m->token != Opt_err; m++) - if (token == m->token) - break; - - if (m->token == Opt_err) { - ext4_msg(sb, KERN_ERR, "Unrecognized mount option \"%s\" " - "or missing value", opt); - return -1; - } - - if ((m->flags & MOPT_NO_EXT2) && IS_EXT2_SB(sb)) { - ext4_msg(sb, KERN_ERR, - "Mount option \"%s\" incompatible with ext2", opt); - return -1; - } - if ((m->flags & MOPT_NO_EXT3) && IS_EXT3_SB(sb)) { - ext4_msg(sb, KERN_ERR, - "Mount option \"%s\" incompatible with ext3", opt); - return -1; - } - - if (args->from && !(m->flags & MOPT_STRING) && match_int(args, &arg)) - return -1; - if (args->from && (m->flags & MOPT_GTE0) && (arg < 0)) - return -1; - if (m->flags & MOPT_EXPLICIT) { - if (m->mount_opt & EXT4_MOUNT_DELALLOC) { - set_opt2(sb, EXPLICIT_DELALLOC); - } else if (m->mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) { - set_opt2(sb, EXPLICIT_JOURNAL_CHECKSUM); - } else - return -1; - } - if (m->flags & MOPT_CLEAR_ERR) - clear_opt(sb, ERRORS_MASK); - if (token == Opt_noquota && sb_any_quota_loaded(sb)) { - ext4_msg(sb, KERN_ERR, "Cannot change quota " - "options when quota turned on"); - return -1; - } - - if (m->flags & MOPT_NOSUPPORT) { - ext4_msg(sb, KERN_ERR, "%s option not supported", opt); - } else if (token == Opt_commit) { - if (arg == 0) - arg = JBD2_DEFAULT_MAX_COMMIT_AGE; - sbi->s_commit_interval = HZ * arg; - } else if (token == Opt_max_batch_time) { - sbi->s_max_batch_time = arg; - } else if (token == Opt_min_batch_time) { - sbi->s_min_batch_time = arg; - } else if (token == Opt_inode_readahead_blks) { - if (arg && (arg > (1 << 30) || !is_power_of_2(arg))) { - ext4_msg(sb, KERN_ERR, - "EXT4-fs: inode_readahead_blks must be " - "0 or a power of 2 smaller than 2^31"); - return -1; - } - sbi->s_inode_readahead_blks = arg; - } else if (token == Opt_init_itable) { - set_opt(sb, INIT_INODE_TABLE); - if (!args->from) - arg = EXT4_DEF_LI_WAIT_MULT; - sbi->s_li_wait_mult = arg; - } else if (token == Opt_max_dir_size_kb) { - sbi->s_max_dir_size_kb = arg; - } else if (token == Opt_stripe) { - sbi->s_stripe = arg; - } else if (token == Opt_resuid) { - uid = make_kuid(current_user_ns(), arg); - if (!uid_valid(uid)) { - ext4_msg(sb, KERN_ERR, "Invalid uid value %d", arg); - return -1; - } - sbi->s_resuid = uid; - } else if (token == Opt_resgid) { - gid = make_kgid(current_user_ns(), arg); - if (!gid_valid(gid)) { - ext4_msg(sb, KERN_ERR, "Invalid gid value %d", arg); - return -1; - } - sbi->s_resgid = gid; - } else if (token == Opt_journal_dev) { - if (is_remount) { - ext4_msg(sb, KERN_ERR, - "Cannot specify journal on remount"); - return -1; - } - *journal_devnum = arg; - } else if (token == Opt_journal_path) { - char *journal_path; - struct inode *journal_inode; - struct path path; - int error; - - if (is_remount) { - ext4_msg(sb, KERN_ERR, - "Cannot specify journal on remount"); - return -1; - } - journal_path = match_strdup(&args[0]); - if (!journal_path) { - ext4_msg(sb, KERN_ERR, "error: could not dup " - "journal device string"); - return -1; - } - - error = kern_path(journal_path, LOOKUP_FOLLOW, &path); - if (error) { - ext4_msg(sb, KERN_ERR, "error: could not find " - "journal device path: error %d", error); - kfree(journal_path); - return -1; - } - - journal_inode = d_inode(path.dentry); - if (!S_ISBLK(journal_inode->i_mode)) { - ext4_msg(sb, KERN_ERR, "error: journal path %s " - "is not a block device", journal_path); - path_put(&path); - kfree(journal_path); - return -1; - } - - *journal_devnum = new_encode_dev(journal_inode->i_rdev); - path_put(&path); - kfree(journal_path); - } else if (token == Opt_journal_ioprio) { - if (arg > 7) { - ext4_msg(sb, KERN_ERR, "Invalid journal IO priority" - " (must be 0-7)"); - return -1; - } - *journal_ioprio = - IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, arg); - } else if (token == Opt_test_dummy_encryption) { -#ifdef CONFIG_EXT4_FS_ENCRYPTION - sbi->s_mount_flags |= EXT4_MF_TEST_DUMMY_ENCRYPTION; - ext4_msg(sb, KERN_WARNING, - "Test dummy encryption mode enabled"); -#else - ext4_msg(sb, KERN_WARNING, - "Test dummy encryption mount option ignored"); -#endif - } else if (m->flags & MOPT_DATAJ) { - if (is_remount) { - if (!sbi->s_journal) - ext4_msg(sb, KERN_WARNING, "Remounting file system with no journal so ignoring journalled data option"); - else if (test_opt(sb, DATA_FLAGS) != m->mount_opt) { - ext4_msg(sb, KERN_ERR, - "Cannot change data mode on remount"); - return -1; - } - } else { - clear_opt(sb, DATA_FLAGS); - sbi->s_mount_opt |= m->mount_opt; - } -#ifdef CONFIG_QUOTA - } else if (m->flags & MOPT_QFMT) { - if (sb_any_quota_loaded(sb) && - sbi->s_jquota_fmt != m->mount_opt) { - ext4_msg(sb, KERN_ERR, "Cannot change journaled " - "quota options when quota turned on"); - return -1; - } - if (ext4_has_feature_quota(sb)) { - ext4_msg(sb, KERN_INFO, - "Quota format mount options ignored " - "when QUOTA feature is enabled"); - return 1; - } - sbi->s_jquota_fmt = m->mount_opt; -#endif - } else if (token == Opt_dax) { -#ifdef CONFIG_FS_DAX - ext4_msg(sb, KERN_WARNING, - "DAX enabled. Warning: EXPERIMENTAL, use at your own risk"); - sbi->s_mount_opt |= m->mount_opt; -#else - ext4_msg(sb, KERN_INFO, "dax option not supported"); - return -1; -#endif - } else if (token == Opt_data_err_abort) { - sbi->s_mount_opt |= m->mount_opt; - } else if (token == Opt_data_err_ignore) { - sbi->s_mount_opt &= ~m->mount_opt; - } else { - if (!args->from) - arg = 1; - if (m->flags & MOPT_CLEAR) - arg = !arg; - else if (unlikely(!(m->flags & MOPT_SET))) { - ext4_msg(sb, KERN_WARNING, - "buggy handling of option %s", opt); - WARN_ON(1); - return -1; - } - if (arg != 0) - sbi->s_mount_opt |= m->mount_opt; - else - sbi->s_mount_opt &= ~m->mount_opt; - } - return 1; -} - -static int parse_options(char *options, struct super_block *sb, - unsigned long *journal_devnum, - unsigned int *journal_ioprio, - int is_remount) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - char *p; - substring_t args[MAX_OPT_ARGS]; - int token; - - if (!options) - return 1; - - while ((p = strsep(&options, ",")) != NULL) { - if (!*p) - continue; - /* - * Initialize args struct so we know whether arg was - * found; some options take optional arguments. - */ - args[0].to = args[0].from = NULL; - token = match_token(p, tokens, args); - if (handle_mount_opt(sb, p, token, args, journal_devnum, - journal_ioprio, is_remount) < 0) - return 0; - } -#ifdef CONFIG_QUOTA - /* - * We do the test below only for project quotas. 'usrquota' and - * 'grpquota' mount options are allowed even without quota feature - * to support legacy quotas in quota files. - */ - if (test_opt(sb, PRJQUOTA) && !ext4_has_feature_project(sb)) { - ext4_msg(sb, KERN_ERR, "Project quota feature not enabled. " - "Cannot enable project quota enforcement."); - return 0; - } - if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) { - if (test_opt(sb, USRQUOTA) && sbi->s_qf_names[USRQUOTA]) - clear_opt(sb, USRQUOTA); - - if (test_opt(sb, GRPQUOTA) && sbi->s_qf_names[GRPQUOTA]) - clear_opt(sb, GRPQUOTA); - - if (test_opt(sb, GRPQUOTA) || test_opt(sb, USRQUOTA)) { - ext4_msg(sb, KERN_ERR, "old and new quota " - "format mixing"); - return 0; - } - - if (!sbi->s_jquota_fmt) { - ext4_msg(sb, KERN_ERR, "journaled quota format " - "not specified"); - return 0; - } - } -#endif - if (test_opt(sb, DIOREAD_NOLOCK)) { - int blocksize = - BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size); - - if (blocksize < PAGE_SIZE) { - ext4_msg(sb, KERN_ERR, "can't mount with " - "dioread_nolock if block size != PAGE_SIZE"); - return 0; - } - } - if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA && - test_opt(sb, JOURNAL_ASYNC_COMMIT)) { - ext4_msg(sb, KERN_ERR, "can't mount with journal_async_commit " - "in data=ordered mode"); - return 0; - } - return 1; -} - -static inline void ext4_show_quota_options(struct seq_file *seq, - struct super_block *sb) -{ -#if defined(CONFIG_QUOTA) - struct ext4_sb_info *sbi = EXT4_SB(sb); - - if (sbi->s_jquota_fmt) { - char *fmtname = ""; - - switch (sbi->s_jquota_fmt) { - case QFMT_VFS_OLD: - fmtname = "vfsold"; - break; - case QFMT_VFS_V0: - fmtname = "vfsv0"; - break; - case QFMT_VFS_V1: - fmtname = "vfsv1"; - break; - } - seq_printf(seq, ",jqfmt=%s", fmtname); - } - - if (sbi->s_qf_names[USRQUOTA]) - seq_show_option(seq, "usrjquota", sbi->s_qf_names[USRQUOTA]); - - if (sbi->s_qf_names[GRPQUOTA]) - seq_show_option(seq, "grpjquota", sbi->s_qf_names[GRPQUOTA]); -#endif -} - -static const char *token2str(int token) -{ - const struct match_token *t; - - for (t = tokens; t->token != Opt_err; t++) - if (t->token == token && !strchr(t->pattern, '=')) - break; - return t->pattern; -} - -/* - * Show an option if - * - it's set to a non-default value OR - * - if the per-sb default is different from the global default - */ -static int _ext4_show_options(struct seq_file *seq, struct super_block *sb, - int nodefs) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_super_block *es = sbi->s_es; - int def_errors, def_mount_opt = nodefs ? 0 : sbi->s_def_mount_opt; - const struct mount_opts *m; - char sep = nodefs ? '\n' : ','; - -#define SEQ_OPTS_PUTS(str) seq_printf(seq, "%c" str, sep) -#define SEQ_OPTS_PRINT(str, arg) seq_printf(seq, "%c" str, sep, arg) - - if (sbi->s_sb_block != 1) - SEQ_OPTS_PRINT("sb=%llu", sbi->s_sb_block); - - for (m = ext4_mount_opts; m->token != Opt_err; m++) { - int want_set = m->flags & MOPT_SET; - if (((m->flags & (MOPT_SET|MOPT_CLEAR)) == 0) || - (m->flags & MOPT_CLEAR_ERR)) - continue; - if (!(m->mount_opt & (sbi->s_mount_opt ^ def_mount_opt))) - continue; /* skip if same as the default */ - if ((want_set && - (sbi->s_mount_opt & m->mount_opt) != m->mount_opt) || - (!want_set && (sbi->s_mount_opt & m->mount_opt))) - continue; /* select Opt_noFoo vs Opt_Foo */ - SEQ_OPTS_PRINT("%s", token2str(m->token)); - } - - if (nodefs || !uid_eq(sbi->s_resuid, make_kuid(&init_user_ns, EXT4_DEF_RESUID)) || - le16_to_cpu(es->s_def_resuid) != EXT4_DEF_RESUID) - SEQ_OPTS_PRINT("resuid=%u", - from_kuid_munged(&init_user_ns, sbi->s_resuid)); - if (nodefs || !gid_eq(sbi->s_resgid, make_kgid(&init_user_ns, EXT4_DEF_RESGID)) || - le16_to_cpu(es->s_def_resgid) != EXT4_DEF_RESGID) - SEQ_OPTS_PRINT("resgid=%u", - from_kgid_munged(&init_user_ns, sbi->s_resgid)); - def_errors = nodefs ? -1 : le16_to_cpu(es->s_errors); - if (test_opt(sb, ERRORS_RO) && def_errors != EXT4_ERRORS_RO) - SEQ_OPTS_PUTS("errors=remount-ro"); - if (test_opt(sb, ERRORS_CONT) && def_errors != EXT4_ERRORS_CONTINUE) - SEQ_OPTS_PUTS("errors=continue"); - if (test_opt(sb, ERRORS_PANIC) && def_errors != EXT4_ERRORS_PANIC) - SEQ_OPTS_PUTS("errors=panic"); - if (nodefs || sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) - SEQ_OPTS_PRINT("commit=%lu", sbi->s_commit_interval / HZ); - if (nodefs || sbi->s_min_batch_time != EXT4_DEF_MIN_BATCH_TIME) - SEQ_OPTS_PRINT("min_batch_time=%u", sbi->s_min_batch_time); - if (nodefs || sbi->s_max_batch_time != EXT4_DEF_MAX_BATCH_TIME) - SEQ_OPTS_PRINT("max_batch_time=%u", sbi->s_max_batch_time); - if (sb->s_flags & MS_I_VERSION) - SEQ_OPTS_PUTS("i_version"); - if (nodefs || sbi->s_stripe) - SEQ_OPTS_PRINT("stripe=%lu", sbi->s_stripe); - if (EXT4_MOUNT_DATA_FLAGS & (sbi->s_mount_opt ^ def_mount_opt)) { - if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) - SEQ_OPTS_PUTS("data=journal"); - else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) - SEQ_OPTS_PUTS("data=ordered"); - else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_WRITEBACK_DATA) - SEQ_OPTS_PUTS("data=writeback"); - } - if (nodefs || - sbi->s_inode_readahead_blks != EXT4_DEF_INODE_READAHEAD_BLKS) - SEQ_OPTS_PRINT("inode_readahead_blks=%u", - sbi->s_inode_readahead_blks); - - if (nodefs || (test_opt(sb, INIT_INODE_TABLE) && - (sbi->s_li_wait_mult != EXT4_DEF_LI_WAIT_MULT))) - SEQ_OPTS_PRINT("init_itable=%u", sbi->s_li_wait_mult); - if (nodefs || sbi->s_max_dir_size_kb) - SEQ_OPTS_PRINT("max_dir_size_kb=%u", sbi->s_max_dir_size_kb); - if (test_opt(sb, DATA_ERR_ABORT)) - SEQ_OPTS_PUTS("data_err=abort"); - - ext4_show_quota_options(seq, sb); - return 0; -} - -static int ext4_show_options(struct seq_file *seq, struct dentry *root) -{ - return _ext4_show_options(seq, root->d_sb, 0); -} - -int ext4_seq_options_show(struct seq_file *seq, void *offset) -{ - struct super_block *sb = seq->private; - int rc; - - seq_puts(seq, (sb->s_flags & MS_RDONLY) ? "ro" : "rw"); - rc = _ext4_show_options(seq, sb, 1); - seq_puts(seq, "\n"); - return rc; -} - -static int ext4_setup_super(struct super_block *sb, struct ext4_super_block *es, - int read_only) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - int res = 0; - - if (le32_to_cpu(es->s_rev_level) > EXT4_MAX_SUPP_REV) { - ext4_msg(sb, KERN_ERR, "revision level too high, " - "forcing read-only mode"); - res = MS_RDONLY; - } - if (read_only) - goto done; - if (!(sbi->s_mount_state & EXT4_VALID_FS)) - ext4_msg(sb, KERN_WARNING, "warning: mounting unchecked fs, " - "running e2fsck is recommended"); - else if (sbi->s_mount_state & EXT4_ERROR_FS) - ext4_msg(sb, KERN_WARNING, - "warning: mounting fs with errors, " - "running e2fsck is recommended"); - else if ((__s16) le16_to_cpu(es->s_max_mnt_count) > 0 && - le16_to_cpu(es->s_mnt_count) >= - (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count)) - ext4_msg(sb, KERN_WARNING, - "warning: maximal mount count reached, " - "running e2fsck is recommended"); - else if (le32_to_cpu(es->s_checkinterval) && - (le32_to_cpu(es->s_lastcheck) + - le32_to_cpu(es->s_checkinterval) <= get_seconds())) - ext4_msg(sb, KERN_WARNING, - "warning: checktime reached, " - "running e2fsck is recommended"); - if (!sbi->s_journal) - es->s_state &= cpu_to_le16(~EXT4_VALID_FS); - if (!(__s16) le16_to_cpu(es->s_max_mnt_count)) - es->s_max_mnt_count = cpu_to_le16(EXT4_DFL_MAX_MNT_COUNT); - le16_add_cpu(&es->s_mnt_count, 1); - es->s_mtime = cpu_to_le32(get_seconds()); - ext4_update_dynamic_rev(sb); - if (sbi->s_journal) - ext4_set_feature_journal_needs_recovery(sb); - - ext4_commit_super(sb, 1); -done: - if (test_opt(sb, DEBUG)) - printk(KERN_INFO "[EXT4 FS bs=%lu, gc=%u, " - "bpg=%lu, ipg=%lu, mo=%04x, mo2=%04x]\n", - sb->s_blocksize, - sbi->s_groups_count, - EXT4_BLOCKS_PER_GROUP(sb), - EXT4_INODES_PER_GROUP(sb), - sbi->s_mount_opt, sbi->s_mount_opt2); - - cleancache_init_fs(sb); - return res; -} - -int ext4_alloc_flex_bg_array(struct super_block *sb, ext4_group_t ngroup) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct flex_groups *new_groups; - int size; - - if (!sbi->s_log_groups_per_flex) - return 0; - - size = ext4_flex_group(sbi, ngroup - 1) + 1; - if (size <= sbi->s_flex_groups_allocated) - return 0; - - size = roundup_pow_of_two(size * sizeof(struct flex_groups)); - new_groups = ext4_kvzalloc(size, GFP_KERNEL); - if (!new_groups) { - ext4_msg(sb, KERN_ERR, "not enough memory for %d flex groups", - size / (int) sizeof(struct flex_groups)); - return -ENOMEM; - } - - if (sbi->s_flex_groups) { - memcpy(new_groups, sbi->s_flex_groups, - (sbi->s_flex_groups_allocated * - sizeof(struct flex_groups))); - kvfree(sbi->s_flex_groups); - } - sbi->s_flex_groups = new_groups; - sbi->s_flex_groups_allocated = size / sizeof(struct flex_groups); - return 0; -} - -static int ext4_fill_flex_info(struct super_block *sb) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_group_desc *gdp = NULL; - ext4_group_t flex_group; - int i, err; - - sbi->s_log_groups_per_flex = sbi->s_es->s_log_groups_per_flex; - if (sbi->s_log_groups_per_flex < 1 || sbi->s_log_groups_per_flex > 31) { - sbi->s_log_groups_per_flex = 0; - return 1; - } - - err = ext4_alloc_flex_bg_array(sb, sbi->s_groups_count); - if (err) - goto failed; - - for (i = 0; i < sbi->s_groups_count; i++) { - gdp = ext4_get_group_desc(sb, i, NULL); - - flex_group = ext4_flex_group(sbi, i); - atomic_add(ext4_free_inodes_count(sb, gdp), - &sbi->s_flex_groups[flex_group].free_inodes); - atomic64_add(ext4_free_group_clusters(sb, gdp), - &sbi->s_flex_groups[flex_group].free_clusters); - atomic_add(ext4_used_dirs_count(sb, gdp), - &sbi->s_flex_groups[flex_group].used_dirs); - } - - return 1; -failed: - return 0; -} - -static __le16 ext4_group_desc_csum(struct super_block *sb, __u32 block_group, - struct ext4_group_desc *gdp) -{ - int offset = offsetof(struct ext4_group_desc, bg_checksum); - __u16 crc = 0; - __le32 le_group = cpu_to_le32(block_group); - struct ext4_sb_info *sbi = EXT4_SB(sb); - - if (ext4_has_metadata_csum(sbi->s_sb)) { - /* Use new metadata_csum algorithm */ - __u32 csum32; - __u16 dummy_csum = 0; - - csum32 = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&le_group, - sizeof(le_group)); - csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp, offset); - csum32 = ext4_chksum(sbi, csum32, (__u8 *)&dummy_csum, - sizeof(dummy_csum)); - offset += sizeof(dummy_csum); - if (offset < sbi->s_desc_size) - csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp + offset, - sbi->s_desc_size - offset); - - crc = csum32 & 0xFFFF; - goto out; - } - - /* old crc16 code */ - if (!ext4_has_feature_gdt_csum(sb)) - return 0; - - crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid)); - crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group)); - crc = crc16(crc, (__u8 *)gdp, offset); - offset += sizeof(gdp->bg_checksum); /* skip checksum */ - /* for checksum of struct ext4_group_desc do the rest...*/ - if (ext4_has_feature_64bit(sb) && - offset < le16_to_cpu(sbi->s_es->s_desc_size)) - crc = crc16(crc, (__u8 *)gdp + offset, - le16_to_cpu(sbi->s_es->s_desc_size) - - offset); - -out: - return cpu_to_le16(crc); -} - -int ext4_group_desc_csum_verify(struct super_block *sb, __u32 block_group, - struct ext4_group_desc *gdp) -{ - if (ext4_has_group_desc_csum(sb) && - (gdp->bg_checksum != ext4_group_desc_csum(sb, block_group, gdp))) - return 0; - - return 1; -} - -void ext4_group_desc_csum_set(struct super_block *sb, __u32 block_group, - struct ext4_group_desc *gdp) -{ - if (!ext4_has_group_desc_csum(sb)) - return; - gdp->bg_checksum = ext4_group_desc_csum(sb, block_group, gdp); -} - -/* Called at mount-time, super-block is locked */ -static int ext4_check_descriptors(struct super_block *sb, - ext4_fsblk_t sb_block, - ext4_group_t *first_not_zeroed) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block); - ext4_fsblk_t last_block; - ext4_fsblk_t block_bitmap; - ext4_fsblk_t inode_bitmap; - ext4_fsblk_t inode_table; - int flexbg_flag = 0; - ext4_group_t i, grp = sbi->s_groups_count; - - if (ext4_has_feature_flex_bg(sb)) - flexbg_flag = 1; - - ext4_debug("Checking group descriptors"); - - for (i = 0; i < sbi->s_groups_count; i++) { - struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, NULL); - - if (i == sbi->s_groups_count - 1 || flexbg_flag) - last_block = ext4_blocks_count(sbi->s_es) - 1; - else - last_block = first_block + - (EXT4_BLOCKS_PER_GROUP(sb) - 1); - - if ((grp == sbi->s_groups_count) && - !(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))) - grp = i; - - block_bitmap = ext4_block_bitmap(sb, gdp); - if (block_bitmap == sb_block) { - ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " - "Block bitmap for group %u overlaps " - "superblock", i); - } - if (block_bitmap < first_block || block_bitmap > last_block) { - ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " - "Block bitmap for group %u not in group " - "(block %llu)!", i, block_bitmap); - return 0; - } - inode_bitmap = ext4_inode_bitmap(sb, gdp); - if (inode_bitmap == sb_block) { - ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " - "Inode bitmap for group %u overlaps " - "superblock", i); - } - if (inode_bitmap < first_block || inode_bitmap > last_block) { - ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " - "Inode bitmap for group %u not in group " - "(block %llu)!", i, inode_bitmap); - return 0; - } - inode_table = ext4_inode_table(sb, gdp); - if (inode_table == sb_block) { - ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " - "Inode table for group %u overlaps " - "superblock", i); - } - if (inode_table < first_block || - inode_table + sbi->s_itb_per_group - 1 > last_block) { - ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " - "Inode table for group %u not in group " - "(block %llu)!", i, inode_table); - return 0; - } - ext4_lock_group(sb, i); - if (!ext4_group_desc_csum_verify(sb, i, gdp)) { - ext4_msg(sb, KERN_ERR, "ext4_check_descriptors: " - "Checksum for group %u failed (%u!=%u)", - i, le16_to_cpu(ext4_group_desc_csum(sb, i, - gdp)), le16_to_cpu(gdp->bg_checksum)); - if (!(sb->s_flags & MS_RDONLY)) { - ext4_unlock_group(sb, i); - return 0; - } - } - ext4_unlock_group(sb, i); - if (!flexbg_flag) - first_block += EXT4_BLOCKS_PER_GROUP(sb); - } - if (NULL != first_not_zeroed) - *first_not_zeroed = grp; - return 1; -} - -/* ext4_orphan_cleanup() walks a singly-linked list of inodes (starting at - * the superblock) which were deleted from all directories, but held open by - * a process at the time of a crash. We walk the list and try to delete these - * inodes at recovery time (only with a read-write filesystem). - * - * In order to keep the orphan inode chain consistent during traversal (in - * case of crash during recovery), we link each inode into the superblock - * orphan list_head and handle it the same way as an inode deletion during - * normal operation (which journals the operations for us). - * - * We only do an iget() and an iput() on each inode, which is very safe if we - * accidentally point at an in-use or already deleted inode. The worst that - * can happen in this case is that we get a "bit already cleared" message from - * ext4_free_inode(). The only reason we would point at a wrong inode is if - * e2fsck was run on this filesystem, and it must have already done the orphan - * inode cleanup for us, so we can safely abort without any further action. - */ -static void ext4_orphan_cleanup(struct super_block *sb, - struct ext4_super_block *es) -{ - unsigned int s_flags = sb->s_flags; - int nr_orphans = 0, nr_truncates = 0; -#ifdef CONFIG_QUOTA - int i; -#endif - if (!es->s_last_orphan) { - jbd_debug(4, "no orphan inodes to clean up\n"); - return; - } - - if (bdev_read_only(sb->s_bdev)) { - ext4_msg(sb, KERN_ERR, "write access " - "unavailable, skipping orphan cleanup"); - return; - } - - /* Check if feature set would not allow a r/w mount */ - if (!ext4_feature_set_ok(sb, 0)) { - ext4_msg(sb, KERN_INFO, "Skipping orphan cleanup due to " - "unknown ROCOMPAT features"); - return; - } - - if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) { - /* don't clear list on RO mount w/ errors */ - if (es->s_last_orphan && !(s_flags & MS_RDONLY)) { - ext4_msg(sb, KERN_INFO, "Errors on filesystem, " - "clearing orphan list.\n"); - es->s_last_orphan = 0; - } - jbd_debug(1, "Skipping orphan recovery on fs with errors.\n"); - return; - } - - if (s_flags & MS_RDONLY) { - ext4_msg(sb, KERN_INFO, "orphan cleanup on readonly fs"); - sb->s_flags &= ~MS_RDONLY; - } -#ifdef CONFIG_QUOTA - /* Needed for iput() to work correctly and not trash data */ - sb->s_flags |= MS_ACTIVE; - /* Turn on quotas so that they are updated correctly */ - for (i = 0; i < EXT4_MAXQUOTAS; i++) { - if (EXT4_SB(sb)->s_qf_names[i]) { - int ret = ext4_quota_on_mount(sb, i); - if (ret < 0) - ext4_msg(sb, KERN_ERR, - "Cannot turn on journaled " - "quota: error %d", ret); - } - } -#endif - - while (es->s_last_orphan) { - struct inode *inode; - - /* - * We may have encountered an error during cleanup; if - * so, skip the rest. - */ - if (EXT4_SB(sb)->s_mount_state & EXT4_ERROR_FS) { - jbd_debug(1, "Skipping orphan recovery on fs with errors.\n"); - es->s_last_orphan = 0; - break; - } - - inode = ext4_orphan_get(sb, le32_to_cpu(es->s_last_orphan)); - if (IS_ERR(inode)) { - es->s_last_orphan = 0; - break; - } - - list_add(&EXT4_I(inode)->i_orphan, &EXT4_SB(sb)->s_orphan); - dquot_initialize(inode); - if (inode->i_nlink) { - if (test_opt(sb, DEBUG)) - ext4_msg(sb, KERN_DEBUG, - "%s: truncating inode %lu to %lld bytes", - __func__, inode->i_ino, inode->i_size); - jbd_debug(2, "truncating inode %lu to %lld bytes\n", - inode->i_ino, inode->i_size); - inode_lock(inode); - truncate_inode_pages(inode->i_mapping, inode->i_size); - ext4_truncate(inode); - inode_unlock(inode); - nr_truncates++; - } else { - if (test_opt(sb, DEBUG)) - ext4_msg(sb, KERN_DEBUG, - "%s: deleting unreferenced inode %lu", - __func__, inode->i_ino); - jbd_debug(2, "deleting unreferenced inode %lu\n", - inode->i_ino); - nr_orphans++; - } - iput(inode); /* The delete magic happens here! */ - } - -#define PLURAL(x) (x), ((x) == 1) ? "" : "s" - - if (nr_orphans) - ext4_msg(sb, KERN_INFO, "%d orphan inode%s deleted", - PLURAL(nr_orphans)); - if (nr_truncates) - ext4_msg(sb, KERN_INFO, "%d truncate%s cleaned up", - PLURAL(nr_truncates)); -#ifdef CONFIG_QUOTA - /* Turn quotas off */ - for (i = 0; i < EXT4_MAXQUOTAS; i++) { - if (sb_dqopt(sb)->files[i]) - dquot_quota_off(sb, i); - } -#endif - sb->s_flags = s_flags; /* Restore MS_RDONLY status */ -} - -/* - * Maximal extent format file size. - * Resulting logical blkno at s_maxbytes must fit in our on-disk - * extent format containers, within a sector_t, and within i_blocks - * in the vfs. ext4 inode has 48 bits of i_block in fsblock units, - * so that won't be a limiting factor. - * - * However there is other limiting factor. We do store extents in the form - * of starting block and length, hence the resulting length of the extent - * covering maximum file size must fit into on-disk format containers as - * well. Given that length is always by 1 unit bigger than max unit (because - * we count 0 as well) we have to lower the s_maxbytes by one fs block. - * - * Note, this does *not* consider any metadata overhead for vfs i_blocks. - */ -static loff_t ext4_max_size(int blkbits, int has_huge_files) -{ - loff_t res; - loff_t upper_limit = MAX_LFS_FILESIZE; - - /* small i_blocks in vfs inode? */ - if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) { - /* - * CONFIG_LBDAF is not enabled implies the inode - * i_block represent total blocks in 512 bytes - * 32 == size of vfs inode i_blocks * 8 - */ - upper_limit = (1LL << 32) - 1; - - /* total blocks in file system block size */ - upper_limit >>= (blkbits - 9); - upper_limit <<= blkbits; - } - - /* - * 32-bit extent-start container, ee_block. We lower the maxbytes - * by one fs block, so ee_len can cover the extent of maximum file - * size - */ - res = (1LL << 32) - 1; - res <<= blkbits; - - /* Sanity check against vm- & vfs- imposed limits */ - if (res > upper_limit) - res = upper_limit; - - return res; -} - -/* - * Maximal bitmap file size. There is a direct, and {,double-,triple-}indirect - * block limit, and also a limit of (2^48 - 1) 512-byte sectors in i_blocks. - * We need to be 1 filesystem block less than the 2^48 sector limit. - */ -static loff_t ext4_max_bitmap_size(int bits, int has_huge_files) -{ - loff_t res = EXT4_NDIR_BLOCKS; - int meta_blocks; - loff_t upper_limit; - /* This is calculated to be the largest file size for a dense, block - * mapped file such that the file's total number of 512-byte sectors, - * including data and all indirect blocks, does not exceed (2^48 - 1). - * - * __u32 i_blocks_lo and _u16 i_blocks_high represent the total - * number of 512-byte sectors of the file. - */ - - if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) { - /* - * !has_huge_files or CONFIG_LBDAF not enabled implies that - * the inode i_block field represents total file blocks in - * 2^32 512-byte sectors == size of vfs inode i_blocks * 8 - */ - upper_limit = (1LL << 32) - 1; - - /* total blocks in file system block size */ - upper_limit >>= (bits - 9); - - } else { - /* - * We use 48 bit ext4_inode i_blocks - * With EXT4_HUGE_FILE_FL set the i_blocks - * represent total number of blocks in - * file system block size - */ - upper_limit = (1LL << 48) - 1; - - } - - /* indirect blocks */ - meta_blocks = 1; - /* double indirect blocks */ - meta_blocks += 1 + (1LL << (bits-2)); - /* tripple indirect blocks */ - meta_blocks += 1 + (1LL << (bits-2)) + (1LL << (2*(bits-2))); - - upper_limit -= meta_blocks; - upper_limit <<= bits; - - res += 1LL << (bits-2); - res += 1LL << (2*(bits-2)); - res += 1LL << (3*(bits-2)); - res <<= bits; - if (res > upper_limit) - res = upper_limit; - - if (res > MAX_LFS_FILESIZE) - res = MAX_LFS_FILESIZE; - - return res; -} - -static ext4_fsblk_t descriptor_loc(struct super_block *sb, - ext4_fsblk_t logical_sb_block, int nr) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - ext4_group_t bg, first_meta_bg; - int has_super = 0; - - first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg); - - if (!ext4_has_feature_meta_bg(sb) || nr < first_meta_bg) - return logical_sb_block + nr + 1; - bg = sbi->s_desc_per_block * nr; - if (ext4_bg_has_super(sb, bg)) - has_super = 1; - - /* - * If we have a meta_bg fs with 1k blocks, group 0's GDT is at - * block 2, not 1. If s_first_data_block == 0 (bigalloc is enabled - * on modern mke2fs or blksize > 1k on older mke2fs) then we must - * compensate. - */ - if (sb->s_blocksize == 1024 && nr == 0 && - le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block) == 0) - has_super++; - - return (has_super + ext4_group_first_block_no(sb, bg)); -} - -/** - * ext4_get_stripe_size: Get the stripe size. - * @sbi: In memory super block info - * - * If we have specified it via mount option, then - * use the mount option value. If the value specified at mount time is - * greater than the blocks per group use the super block value. - * If the super block value is greater than blocks per group return 0. - * Allocator needs it be less than blocks per group. - * - */ -static unsigned long ext4_get_stripe_size(struct ext4_sb_info *sbi) -{ - unsigned long stride = le16_to_cpu(sbi->s_es->s_raid_stride); - unsigned long stripe_width = - le32_to_cpu(sbi->s_es->s_raid_stripe_width); - int ret; - - if (sbi->s_stripe && sbi->s_stripe <= sbi->s_blocks_per_group) - ret = sbi->s_stripe; - else if (stripe_width <= sbi->s_blocks_per_group) - ret = stripe_width; - else if (stride <= sbi->s_blocks_per_group) - ret = stride; - else - ret = 0; - - /* - * If the stripe width is 1, this makes no sense and - * we set it to 0 to turn off stripe handling code. - */ - if (ret <= 1) - ret = 0; - - return ret; -} - -/* - * Check whether this filesystem can be mounted based on - * the features present and the RDONLY/RDWR mount requested. - * Returns 1 if this filesystem can be mounted as requested, - * 0 if it cannot be. - */ -static int ext4_feature_set_ok(struct super_block *sb, int readonly) -{ - if (ext4_has_unknown_ext4_incompat_features(sb)) { - ext4_msg(sb, KERN_ERR, - "Couldn't mount because of " - "unsupported optional features (%x)", - (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_incompat) & - ~EXT4_FEATURE_INCOMPAT_SUPP)); - return 0; - } - - if (readonly) - return 1; - - if (ext4_has_feature_readonly(sb)) { - ext4_msg(sb, KERN_INFO, "filesystem is read-only"); - sb->s_flags |= MS_RDONLY; - return 1; - } - - /* Check that feature set is OK for a read-write mount */ - if (ext4_has_unknown_ext4_ro_compat_features(sb)) { - ext4_msg(sb, KERN_ERR, "couldn't mount RDWR because of " - "unsupported optional features (%x)", - (le32_to_cpu(EXT4_SB(sb)->s_es->s_feature_ro_compat) & - ~EXT4_FEATURE_RO_COMPAT_SUPP)); - return 0; - } - /* - * Large file size enabled file system can only be mounted - * read-write on 32-bit systems if kernel is built with CONFIG_LBDAF - */ - if (ext4_has_feature_huge_file(sb)) { - if (sizeof(blkcnt_t) < sizeof(u64)) { - ext4_msg(sb, KERN_ERR, "Filesystem with huge files " - "cannot be mounted RDWR without " - "CONFIG_LBDAF"); - return 0; - } - } - if (ext4_has_feature_bigalloc(sb) && !ext4_has_feature_extents(sb)) { - ext4_msg(sb, KERN_ERR, - "Can't support bigalloc feature without " - "extents feature\n"); - return 0; - } - -#ifndef CONFIG_QUOTA - if (ext4_has_feature_quota(sb) && !readonly) { - ext4_msg(sb, KERN_ERR, - "Filesystem with quota feature cannot be mounted RDWR " - "without CONFIG_QUOTA"); - return 0; - } - if (ext4_has_feature_project(sb) && !readonly) { - ext4_msg(sb, KERN_ERR, - "Filesystem with project quota feature cannot be mounted RDWR " - "without CONFIG_QUOTA"); - return 0; - } -#endif /* CONFIG_QUOTA */ - return 1; -} - -/* - * This function is called once a day if we have errors logged - * on the file system - */ -static void print_daily_error_info(unsigned long arg) -{ - struct super_block *sb = (struct super_block *) arg; - struct ext4_sb_info *sbi; - struct ext4_super_block *es; - - sbi = EXT4_SB(sb); - es = sbi->s_es; - - if (es->s_error_count) - /* fsck newer than v1.41.13 is needed to clean this condition. */ - ext4_msg(sb, KERN_NOTICE, "error count since last fsck: %u", - le32_to_cpu(es->s_error_count)); - if (es->s_first_error_time) { - printk(KERN_NOTICE "EXT4-fs (%s): initial error at time %u: %.*s:%d", - sb->s_id, le32_to_cpu(es->s_first_error_time), - (int) sizeof(es->s_first_error_func), - es->s_first_error_func, - le32_to_cpu(es->s_first_error_line)); - if (es->s_first_error_ino) - printk(KERN_CONT ": inode %u", - le32_to_cpu(es->s_first_error_ino)); - if (es->s_first_error_block) - printk(KERN_CONT ": block %llu", (unsigned long long) - le64_to_cpu(es->s_first_error_block)); - printk(KERN_CONT "\n"); - } - if (es->s_last_error_time) { - printk(KERN_NOTICE "EXT4-fs (%s): last error at time %u: %.*s:%d", - sb->s_id, le32_to_cpu(es->s_last_error_time), - (int) sizeof(es->s_last_error_func), - es->s_last_error_func, - le32_to_cpu(es->s_last_error_line)); - if (es->s_last_error_ino) - printk(KERN_CONT ": inode %u", - le32_to_cpu(es->s_last_error_ino)); - if (es->s_last_error_block) - printk(KERN_CONT ": block %llu", (unsigned long long) - le64_to_cpu(es->s_last_error_block)); - printk(KERN_CONT "\n"); - } - mod_timer(&sbi->s_err_report, jiffies + 24*60*60*HZ); /* Once a day */ -} - -/* Find next suitable group and run ext4_init_inode_table */ -static int ext4_run_li_request(struct ext4_li_request *elr) -{ - struct ext4_group_desc *gdp = NULL; - ext4_group_t group, ngroups; - struct super_block *sb; - unsigned long timeout = 0; - int ret = 0; - - sb = elr->lr_super; - ngroups = EXT4_SB(sb)->s_groups_count; - - for (group = elr->lr_next_group; group < ngroups; group++) { - gdp = ext4_get_group_desc(sb, group, NULL); - if (!gdp) { - ret = 1; - break; - } - - if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))) - break; - } - - if (group >= ngroups) - ret = 1; - - if (!ret) { - timeout = jiffies; - ret = ext4_init_inode_table(sb, group, - elr->lr_timeout ? 0 : 1); - if (elr->lr_timeout == 0) { - timeout = (jiffies - timeout) * - elr->lr_sbi->s_li_wait_mult; - elr->lr_timeout = timeout; - } - elr->lr_next_sched = jiffies + elr->lr_timeout; - elr->lr_next_group = group + 1; - } - return ret; -} - -/* - * Remove lr_request from the list_request and free the - * request structure. Should be called with li_list_mtx held - */ -static void ext4_remove_li_request(struct ext4_li_request *elr) -{ - struct ext4_sb_info *sbi; - - if (!elr) - return; - - sbi = elr->lr_sbi; - - list_del(&elr->lr_request); - sbi->s_li_request = NULL; - kfree(elr); -} - -static void ext4_unregister_li_request(struct super_block *sb) -{ - mutex_lock(&ext4_li_mtx); - if (!ext4_li_info) { - mutex_unlock(&ext4_li_mtx); - return; - } - - mutex_lock(&ext4_li_info->li_list_mtx); - ext4_remove_li_request(EXT4_SB(sb)->s_li_request); - mutex_unlock(&ext4_li_info->li_list_mtx); - mutex_unlock(&ext4_li_mtx); -} - -static struct task_struct *ext4_lazyinit_task; - -/* - * This is the function where ext4lazyinit thread lives. It walks - * through the request list searching for next scheduled filesystem. - * When such a fs is found, run the lazy initialization request - * (ext4_rn_li_request) and keep track of the time spend in this - * function. Based on that time we compute next schedule time of - * the request. When walking through the list is complete, compute - * next waking time and put itself into sleep. - */ -static int ext4_lazyinit_thread(void *arg) -{ - struct ext4_lazy_init *eli = (struct ext4_lazy_init *)arg; - struct list_head *pos, *n; - struct ext4_li_request *elr; - unsigned long next_wakeup, cur; - - BUG_ON(NULL == eli); - -cont_thread: - while (true) { - next_wakeup = MAX_JIFFY_OFFSET; - - mutex_lock(&eli->li_list_mtx); - if (list_empty(&eli->li_request_list)) { - mutex_unlock(&eli->li_list_mtx); - goto exit_thread; - } - list_for_each_safe(pos, n, &eli->li_request_list) { - int err = 0; - int progress = 0; - elr = list_entry(pos, struct ext4_li_request, - lr_request); - - if (time_before(jiffies, elr->lr_next_sched)) { - if (time_before(elr->lr_next_sched, next_wakeup)) - next_wakeup = elr->lr_next_sched; - continue; - } - if (down_read_trylock(&elr->lr_super->s_umount)) { - if (sb_start_write_trylock(elr->lr_super)) { - progress = 1; - /* - * We hold sb->s_umount, sb can not - * be removed from the list, it is - * now safe to drop li_list_mtx - */ - mutex_unlock(&eli->li_list_mtx); - err = ext4_run_li_request(elr); - sb_end_write(elr->lr_super); - mutex_lock(&eli->li_list_mtx); - n = pos->next; - } - up_read((&elr->lr_super->s_umount)); - } - /* error, remove the lazy_init job */ - if (err) { - ext4_remove_li_request(elr); - continue; - } - if (!progress) { - elr->lr_next_sched = jiffies + - (prandom_u32() - % (EXT4_DEF_LI_MAX_START_DELAY * HZ)); - } - if (time_before(elr->lr_next_sched, next_wakeup)) - next_wakeup = elr->lr_next_sched; - } - mutex_unlock(&eli->li_list_mtx); - - try_to_freeze(); - - cur = jiffies; - if ((time_after_eq(cur, next_wakeup)) || - (MAX_JIFFY_OFFSET == next_wakeup)) { - cond_resched(); - continue; - } - - schedule_timeout_interruptible(next_wakeup - cur); - - if (kthread_should_stop()) { - ext4_clear_request_list(); - goto exit_thread; - } - } - -exit_thread: - /* - * It looks like the request list is empty, but we need - * to check it under the li_list_mtx lock, to prevent any - * additions into it, and of course we should lock ext4_li_mtx - * to atomically free the list and ext4_li_info, because at - * this point another ext4 filesystem could be registering - * new one. - */ - mutex_lock(&ext4_li_mtx); - mutex_lock(&eli->li_list_mtx); - if (!list_empty(&eli->li_request_list)) { - mutex_unlock(&eli->li_list_mtx); - mutex_unlock(&ext4_li_mtx); - goto cont_thread; - } - mutex_unlock(&eli->li_list_mtx); - kfree(ext4_li_info); - ext4_li_info = NULL; - mutex_unlock(&ext4_li_mtx); - - return 0; -} - -static void ext4_clear_request_list(void) -{ - struct list_head *pos, *n; - struct ext4_li_request *elr; - - mutex_lock(&ext4_li_info->li_list_mtx); - list_for_each_safe(pos, n, &ext4_li_info->li_request_list) { - elr = list_entry(pos, struct ext4_li_request, - lr_request); - ext4_remove_li_request(elr); - } - mutex_unlock(&ext4_li_info->li_list_mtx); -} - -static int ext4_run_lazyinit_thread(void) -{ - ext4_lazyinit_task = kthread_run(ext4_lazyinit_thread, - ext4_li_info, "ext4lazyinit"); - if (IS_ERR(ext4_lazyinit_task)) { - int err = PTR_ERR(ext4_lazyinit_task); - ext4_clear_request_list(); - kfree(ext4_li_info); - ext4_li_info = NULL; - printk(KERN_CRIT "EXT4-fs: error %d creating inode table " - "initialization thread\n", - err); - return err; - } - ext4_li_info->li_state |= EXT4_LAZYINIT_RUNNING; - return 0; -} - -/* - * Check whether it make sense to run itable init. thread or not. - * If there is at least one uninitialized inode table, return - * corresponding group number, else the loop goes through all - * groups and return total number of groups. - */ -static ext4_group_t ext4_has_uninit_itable(struct super_block *sb) -{ - ext4_group_t group, ngroups = EXT4_SB(sb)->s_groups_count; - struct ext4_group_desc *gdp = NULL; - - for (group = 0; group < ngroups; group++) { - gdp = ext4_get_group_desc(sb, group, NULL); - if (!gdp) - continue; - - if (!(gdp->bg_flags & cpu_to_le16(EXT4_BG_INODE_ZEROED))) - break; - } - - return group; -} - -static int ext4_li_info_new(void) -{ - struct ext4_lazy_init *eli = NULL; - - eli = kzalloc(sizeof(*eli), GFP_KERNEL); - if (!eli) - return -ENOMEM; - - INIT_LIST_HEAD(&eli->li_request_list); - mutex_init(&eli->li_list_mtx); - - eli->li_state |= EXT4_LAZYINIT_QUIT; - - ext4_li_info = eli; - - return 0; -} - -static struct ext4_li_request *ext4_li_request_new(struct super_block *sb, - ext4_group_t start) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_li_request *elr; - - elr = kzalloc(sizeof(*elr), GFP_KERNEL); - if (!elr) - return NULL; - - elr->lr_super = sb; - elr->lr_sbi = sbi; - elr->lr_next_group = start; - - /* - * Randomize first schedule time of the request to - * spread the inode table initialization requests - * better. - */ - elr->lr_next_sched = jiffies + (prandom_u32() % - (EXT4_DEF_LI_MAX_START_DELAY * HZ)); - return elr; -} - -int ext4_register_li_request(struct super_block *sb, - ext4_group_t first_not_zeroed) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_li_request *elr = NULL; - ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count; - int ret = 0; - - mutex_lock(&ext4_li_mtx); - if (sbi->s_li_request != NULL) { - /* - * Reset timeout so it can be computed again, because - * s_li_wait_mult might have changed. - */ - sbi->s_li_request->lr_timeout = 0; - goto out; - } - - if (first_not_zeroed == ngroups || - (sb->s_flags & MS_RDONLY) || - !test_opt(sb, INIT_INODE_TABLE)) - goto out; - - elr = ext4_li_request_new(sb, first_not_zeroed); - if (!elr) { - ret = -ENOMEM; - goto out; - } - - if (NULL == ext4_li_info) { - ret = ext4_li_info_new(); - if (ret) - goto out; - } - - mutex_lock(&ext4_li_info->li_list_mtx); - list_add(&elr->lr_request, &ext4_li_info->li_request_list); - mutex_unlock(&ext4_li_info->li_list_mtx); - - sbi->s_li_request = elr; - /* - * set elr to NULL here since it has been inserted to - * the request_list and the removal and free of it is - * handled by ext4_clear_request_list from now on. - */ - elr = NULL; - - if (!(ext4_li_info->li_state & EXT4_LAZYINIT_RUNNING)) { - ret = ext4_run_lazyinit_thread(); - if (ret) - goto out; - } -out: - mutex_unlock(&ext4_li_mtx); - if (ret) - kfree(elr); - return ret; -} - -/* - * We do not need to lock anything since this is called on - * module unload. - */ -static void ext4_destroy_lazyinit_thread(void) -{ - /* - * If thread exited earlier - * there's nothing to be done. - */ - if (!ext4_li_info || !ext4_lazyinit_task) - return; - - kthread_stop(ext4_lazyinit_task); -} - -static int set_journal_csum_feature_set(struct super_block *sb) -{ - int ret = 1; - int compat, incompat; - struct ext4_sb_info *sbi = EXT4_SB(sb); - - if (ext4_has_metadata_csum(sb)) { - /* journal checksum v3 */ - compat = 0; - incompat = JBD2_FEATURE_INCOMPAT_CSUM_V3; - } else { - /* journal checksum v1 */ - compat = JBD2_FEATURE_COMPAT_CHECKSUM; - incompat = 0; - } - - jbd2_journal_clear_features(sbi->s_journal, - JBD2_FEATURE_COMPAT_CHECKSUM, 0, - JBD2_FEATURE_INCOMPAT_CSUM_V3 | - JBD2_FEATURE_INCOMPAT_CSUM_V2); - if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) { - ret = jbd2_journal_set_features(sbi->s_journal, - compat, 0, - JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT | - incompat); - } else if (test_opt(sb, JOURNAL_CHECKSUM)) { - ret = jbd2_journal_set_features(sbi->s_journal, - compat, 0, - incompat); - jbd2_journal_clear_features(sbi->s_journal, 0, 0, - JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT); - } else { - jbd2_journal_clear_features(sbi->s_journal, 0, 0, - JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT); - } - - return ret; -} - -/* - * Note: calculating the overhead so we can be compatible with - * historical BSD practice is quite difficult in the face of - * clusters/bigalloc. This is because multiple metadata blocks from - * different block group can end up in the same allocation cluster. - * Calculating the exact overhead in the face of clustered allocation - * requires either O(all block bitmaps) in memory or O(number of block - * groups**2) in time. We will still calculate the superblock for - * older file systems --- and if we come across with a bigalloc file - * system with zero in s_overhead_clusters the estimate will be close to - * correct especially for very large cluster sizes --- but for newer - * file systems, it's better to calculate this figure once at mkfs - * time, and store it in the superblock. If the superblock value is - * present (even for non-bigalloc file systems), we will use it. - */ -static int count_overhead(struct super_block *sb, ext4_group_t grp, - char *buf) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_group_desc *gdp; - ext4_fsblk_t first_block, last_block, b; - ext4_group_t i, ngroups = ext4_get_groups_count(sb); - int s, j, count = 0; - - if (!ext4_has_feature_bigalloc(sb)) - return (ext4_bg_has_super(sb, grp) + ext4_bg_num_gdb(sb, grp) + - sbi->s_itb_per_group + 2); - - first_block = le32_to_cpu(sbi->s_es->s_first_data_block) + - (grp * EXT4_BLOCKS_PER_GROUP(sb)); - last_block = first_block + EXT4_BLOCKS_PER_GROUP(sb) - 1; - for (i = 0; i < ngroups; i++) { - gdp = ext4_get_group_desc(sb, i, NULL); - b = ext4_block_bitmap(sb, gdp); - if (b >= first_block && b <= last_block) { - ext4_set_bit(EXT4_B2C(sbi, b - first_block), buf); - count++; - } - b = ext4_inode_bitmap(sb, gdp); - if (b >= first_block && b <= last_block) { - ext4_set_bit(EXT4_B2C(sbi, b - first_block), buf); - count++; - } - b = ext4_inode_table(sb, gdp); - if (b >= first_block && b + sbi->s_itb_per_group <= last_block) - for (j = 0; j < sbi->s_itb_per_group; j++, b++) { - int c = EXT4_B2C(sbi, b - first_block); - ext4_set_bit(c, buf); - count++; - } - if (i != grp) - continue; - s = 0; - if (ext4_bg_has_super(sb, grp)) { - ext4_set_bit(s++, buf); - count++; - } - for (j = ext4_bg_num_gdb(sb, grp); j > 0; j--) { - ext4_set_bit(EXT4_B2C(sbi, s++), buf); - count++; - } - } - if (!count) - return 0; - return EXT4_CLUSTERS_PER_GROUP(sb) - - ext4_count_free(buf, EXT4_CLUSTERS_PER_GROUP(sb) / 8); -} - -/* - * Compute the overhead and stash it in sbi->s_overhead - */ -int ext4_calculate_overhead(struct super_block *sb) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_super_block *es = sbi->s_es; - struct inode *j_inode; - unsigned int j_blocks, j_inum = le32_to_cpu(es->s_journal_inum); - ext4_group_t i, ngroups = ext4_get_groups_count(sb); - ext4_fsblk_t overhead = 0; - char *buf = (char *) get_zeroed_page(GFP_NOFS); - - if (!buf) - return -ENOMEM; - - /* - * Compute the overhead (FS structures). This is constant - * for a given filesystem unless the number of block groups - * changes so we cache the previous value until it does. - */ - - /* - * All of the blocks before first_data_block are overhead - */ - overhead = EXT4_B2C(sbi, le32_to_cpu(es->s_first_data_block)); - - /* - * Add the overhead found in each block group - */ - for (i = 0; i < ngroups; i++) { - int blks; - - blks = count_overhead(sb, i, buf); - overhead += blks; - if (blks) - memset(buf, 0, PAGE_SIZE); - cond_resched(); - } - - /* - * Add the internal journal blocks whether the journal has been - * loaded or not - */ - if (sbi->s_journal && !sbi->journal_bdev) - overhead += EXT4_NUM_B2C(sbi, sbi->s_journal->j_maxlen); - else if (ext4_has_feature_journal(sb) && !sbi->s_journal) { - j_inode = ext4_get_journal_inode(sb, j_inum); - if (j_inode) { - j_blocks = j_inode->i_size >> sb->s_blocksize_bits; - overhead += EXT4_NUM_B2C(sbi, j_blocks); - iput(j_inode); - } else { - ext4_msg(sb, KERN_ERR, "can't get journal size"); - } - } - sbi->s_overhead = overhead; - smp_wmb(); - free_page((unsigned long) buf); - return 0; -} - -static void ext4_set_resv_clusters(struct super_block *sb) -{ - ext4_fsblk_t resv_clusters; - struct ext4_sb_info *sbi = EXT4_SB(sb); - - /* - * There's no need to reserve anything when we aren't using extents. - * The space estimates are exact, there are no unwritten extents, - * hole punching doesn't need new metadata... This is needed especially - * to keep ext2/3 backward compatibility. - */ - if (!ext4_has_feature_extents(sb)) - return; - /* - * By default we reserve 2% or 4096 clusters, whichever is smaller. - * This should cover the situations where we can not afford to run - * out of space like for example punch hole, or converting - * unwritten extents in delalloc path. In most cases such - * allocation would require 1, or 2 blocks, higher numbers are - * very rare. - */ - resv_clusters = (ext4_blocks_count(sbi->s_es) >> - sbi->s_cluster_bits); - - do_div(resv_clusters, 50); - resv_clusters = min_t(ext4_fsblk_t, resv_clusters, 4096); - - atomic64_set(&sbi->s_resv_clusters, resv_clusters); -} - -static int ext4_fill_super(struct super_block *sb, void *data, int silent) -{ - char *orig_data = kstrdup(data, GFP_KERNEL); - struct buffer_head *bh; - struct ext4_super_block *es = NULL; - struct ext4_sb_info *sbi; - ext4_fsblk_t block; - ext4_fsblk_t sb_block = get_sb_block(&data); - ext4_fsblk_t logical_sb_block; - unsigned long offset = 0; - unsigned long journal_devnum = 0; - unsigned long def_mount_opts; - struct inode *root; - const char *descr; - int ret = -ENOMEM; - int blocksize, clustersize; - unsigned int db_count; - unsigned int i; - int needs_recovery, has_huge_files, has_bigalloc; - __u64 blocks_count; - int err = 0; - unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO; - ext4_group_t first_not_zeroed; - - sbi = kzalloc(sizeof(*sbi), GFP_KERNEL); - if (!sbi) - goto out_free_orig; - - sbi->s_blockgroup_lock = - kzalloc(sizeof(struct blockgroup_lock), GFP_KERNEL); - if (!sbi->s_blockgroup_lock) { - kfree(sbi); - goto out_free_orig; - } - sb->s_fs_info = sbi; - sbi->s_sb = sb; - sbi->s_inode_readahead_blks = EXT4_DEF_INODE_READAHEAD_BLKS; - sbi->s_sb_block = sb_block; - if (sb->s_bdev->bd_part) - sbi->s_sectors_written_start = - part_stat_read(sb->s_bdev->bd_part, sectors[1]); - - /* Cleanup superblock name */ - strreplace(sb->s_id, '/', '!'); - - /* -EINVAL is default */ - ret = -EINVAL; - blocksize = sb_min_blocksize(sb, EXT4_MIN_BLOCK_SIZE); - if (!blocksize) { - ext4_msg(sb, KERN_ERR, "unable to set blocksize"); - goto out_fail; - } - - /* - * The ext4 superblock will not be buffer aligned for other than 1kB - * block sizes. We need to calculate the offset from buffer start. - */ - if (blocksize != EXT4_MIN_BLOCK_SIZE) { - logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE; - offset = do_div(logical_sb_block, blocksize); - } else { - logical_sb_block = sb_block; - } - - if (!(bh = sb_bread_unmovable(sb, logical_sb_block))) { - ext4_msg(sb, KERN_ERR, "unable to read superblock"); - goto out_fail; - } - /* - * Note: s_es must be initialized as soon as possible because - * some ext4 macro-instructions depend on its value - */ - es = (struct ext4_super_block *) (bh->b_data + offset); - sbi->s_es = es; - sb->s_magic = le16_to_cpu(es->s_magic); - if (sb->s_magic != EXT4_SUPER_MAGIC) - goto cantfind_ext4; - sbi->s_kbytes_written = le64_to_cpu(es->s_kbytes_written); - - /* Warn if metadata_csum and gdt_csum are both set. */ - if (ext4_has_feature_metadata_csum(sb) && - ext4_has_feature_gdt_csum(sb)) - ext4_warning(sb, "metadata_csum and uninit_bg are " - "redundant flags; please run fsck."); - - /* Check for a known checksum algorithm */ - if (!ext4_verify_csum_type(sb, es)) { - ext4_msg(sb, KERN_ERR, "VFS: Found ext4 filesystem with " - "unknown checksum algorithm."); - silent = 1; - goto cantfind_ext4; - } - - /* Load the checksum driver */ - if (ext4_has_feature_metadata_csum(sb)) { - sbi->s_chksum_driver = crypto_alloc_shash("crc32c", 0, 0); - if (IS_ERR(sbi->s_chksum_driver)) { - ext4_msg(sb, KERN_ERR, "Cannot load crc32c driver."); - ret = PTR_ERR(sbi->s_chksum_driver); - sbi->s_chksum_driver = NULL; - goto failed_mount; - } - } - - /* Check superblock checksum */ - if (!ext4_superblock_csum_verify(sb, es)) { - ext4_msg(sb, KERN_ERR, "VFS: Found ext4 filesystem with " - "invalid superblock checksum. Run e2fsck?"); - silent = 1; - ret = -EFSBADCRC; - goto cantfind_ext4; - } - - /* Precompute checksum seed for all metadata */ - if (ext4_has_feature_csum_seed(sb)) - sbi->s_csum_seed = le32_to_cpu(es->s_checksum_seed); - else if (ext4_has_metadata_csum(sb)) - sbi->s_csum_seed = ext4_chksum(sbi, ~0, es->s_uuid, - sizeof(es->s_uuid)); - - /* Set defaults before we parse the mount options */ - def_mount_opts = le32_to_cpu(es->s_default_mount_opts); - set_opt(sb, INIT_INODE_TABLE); - if (def_mount_opts & EXT4_DEFM_DEBUG) - set_opt(sb, DEBUG); - if (def_mount_opts & EXT4_DEFM_BSDGROUPS) - set_opt(sb, GRPID); - if (def_mount_opts & EXT4_DEFM_UID16) - set_opt(sb, NO_UID32); - /* xattr user namespace & acls are now defaulted on */ - set_opt(sb, XATTR_USER); -#ifdef CONFIG_EXT4_FS_POSIX_ACL - set_opt(sb, POSIX_ACL); -#endif - /* don't forget to enable journal_csum when metadata_csum is enabled. */ - if (ext4_has_metadata_csum(sb)) - set_opt(sb, JOURNAL_CHECKSUM); - - if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_DATA) - set_opt(sb, JOURNAL_DATA); - else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_ORDERED) - set_opt(sb, ORDERED_DATA); - else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_WBACK) - set_opt(sb, WRITEBACK_DATA); - - if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_PANIC) - set_opt(sb, ERRORS_PANIC); - else if (le16_to_cpu(sbi->s_es->s_errors) == EXT4_ERRORS_CONTINUE) - set_opt(sb, ERRORS_CONT); - else - set_opt(sb, ERRORS_RO); - /* block_validity enabled by default; disable with noblock_validity */ - set_opt(sb, BLOCK_VALIDITY); - if (def_mount_opts & EXT4_DEFM_DISCARD) - set_opt(sb, DISCARD); - - sbi->s_resuid = make_kuid(&init_user_ns, le16_to_cpu(es->s_def_resuid)); - sbi->s_resgid = make_kgid(&init_user_ns, le16_to_cpu(es->s_def_resgid)); - sbi->s_commit_interval = JBD2_DEFAULT_MAX_COMMIT_AGE * HZ; - sbi->s_min_batch_time = EXT4_DEF_MIN_BATCH_TIME; - sbi->s_max_batch_time = EXT4_DEF_MAX_BATCH_TIME; - - if ((def_mount_opts & EXT4_DEFM_NOBARRIER) == 0) - set_opt(sb, BARRIER); - - /* - * enable delayed allocation by default - * Use -o nodelalloc to turn it off - */ - if (!IS_EXT3_SB(sb) && !IS_EXT2_SB(sb) && - ((def_mount_opts & EXT4_DEFM_NODELALLOC) == 0)) - set_opt(sb, DELALLOC); - - /* - * set default s_li_wait_mult for lazyinit, for the case there is - * no mount option specified. - */ - sbi->s_li_wait_mult = EXT4_DEF_LI_WAIT_MULT; - - if (!parse_options((char *) sbi->s_es->s_mount_opts, sb, - &journal_devnum, &journal_ioprio, 0)) { - ext4_msg(sb, KERN_WARNING, - "failed to parse options in superblock: %s", - sbi->s_es->s_mount_opts); - } - sbi->s_def_mount_opt = sbi->s_mount_opt; - if (!parse_options((char *) data, sb, &journal_devnum, - &journal_ioprio, 0)) - goto failed_mount; - - if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) { - printk_once(KERN_WARNING "EXT4-fs: Warning: mounting " - "with data=journal disables delayed " - "allocation and O_DIRECT support!\n"); - if (test_opt2(sb, EXPLICIT_DELALLOC)) { - ext4_msg(sb, KERN_ERR, "can't mount with " - "both data=journal and delalloc"); - goto failed_mount; - } - if (test_opt(sb, DIOREAD_NOLOCK)) { - ext4_msg(sb, KERN_ERR, "can't mount with " - "both data=journal and dioread_nolock"); - goto failed_mount; - } - if (test_opt(sb, DAX)) { - ext4_msg(sb, KERN_ERR, "can't mount with " - "both data=journal and dax"); - goto failed_mount; - } - if (test_opt(sb, DELALLOC)) - clear_opt(sb, DELALLOC); - } else { - sb->s_iflags |= SB_I_CGROUPWB; - } - - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | - (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0); - - if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV && - (ext4_has_compat_features(sb) || - ext4_has_ro_compat_features(sb) || - ext4_has_incompat_features(sb))) - ext4_msg(sb, KERN_WARNING, - "feature flags set on rev 0 fs, " - "running e2fsck is recommended"); - - if (es->s_creator_os == cpu_to_le32(EXT4_OS_HURD)) { - set_opt2(sb, HURD_COMPAT); - if (ext4_has_feature_64bit(sb)) { - ext4_msg(sb, KERN_ERR, - "The Hurd can't support 64-bit file systems"); - goto failed_mount; - } - } - - if (IS_EXT2_SB(sb)) { - if (ext2_feature_set_ok(sb)) - ext4_msg(sb, KERN_INFO, "mounting ext2 file system " - "using the ext4 subsystem"); - else { - ext4_msg(sb, KERN_ERR, "couldn't mount as ext2 due " - "to feature incompatibilities"); - goto failed_mount; - } - } - - if (IS_EXT3_SB(sb)) { - if (ext3_feature_set_ok(sb)) - ext4_msg(sb, KERN_INFO, "mounting ext3 file system " - "using the ext4 subsystem"); - else { - ext4_msg(sb, KERN_ERR, "couldn't mount as ext3 due " - "to feature incompatibilities"); - goto failed_mount; - } - } - - /* - * Check feature flags regardless of the revision level, since we - * previously didn't change the revision level when setting the flags, - * so there is a chance incompat flags are set on a rev 0 filesystem. - */ - if (!ext4_feature_set_ok(sb, (sb->s_flags & MS_RDONLY))) - goto failed_mount; - - blocksize = BLOCK_SIZE << le32_to_cpu(es->s_log_block_size); - if (blocksize < EXT4_MIN_BLOCK_SIZE || - blocksize > EXT4_MAX_BLOCK_SIZE) { - ext4_msg(sb, KERN_ERR, - "Unsupported filesystem blocksize %d (%d log_block_size)", - blocksize, le32_to_cpu(es->s_log_block_size)); - goto failed_mount; - } - if (le32_to_cpu(es->s_log_block_size) > - (EXT4_MAX_BLOCK_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) { - ext4_msg(sb, KERN_ERR, - "Invalid log block size: %u", - le32_to_cpu(es->s_log_block_size)); - goto failed_mount; - } - - if (le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks) > (blocksize / 4)) { - ext4_msg(sb, KERN_ERR, - "Number of reserved GDT blocks insanely large: %d", - le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks)); - goto failed_mount; - } - - if (sbi->s_mount_opt & EXT4_MOUNT_DAX) { - err = bdev_dax_supported(sb, blocksize); - if (err) - goto failed_mount; - } - - if (ext4_has_feature_encrypt(sb) && es->s_encryption_level) { - ext4_msg(sb, KERN_ERR, "Unsupported encryption level %d", - es->s_encryption_level); - goto failed_mount; - } - - if (sb->s_blocksize != blocksize) { - /* Validate the filesystem blocksize */ - if (!sb_set_blocksize(sb, blocksize)) { - ext4_msg(sb, KERN_ERR, "bad block size %d", - blocksize); - goto failed_mount; - } - - brelse(bh); - logical_sb_block = sb_block * EXT4_MIN_BLOCK_SIZE; - offset = do_div(logical_sb_block, blocksize); - bh = sb_bread_unmovable(sb, logical_sb_block); - if (!bh) { - ext4_msg(sb, KERN_ERR, - "Can't read superblock on 2nd try"); - goto failed_mount; - } - es = (struct ext4_super_block *)(bh->b_data + offset); - sbi->s_es = es; - if (es->s_magic != cpu_to_le16(EXT4_SUPER_MAGIC)) { - ext4_msg(sb, KERN_ERR, - "Magic mismatch, very weird!"); - goto failed_mount; - } - } - - has_huge_files = ext4_has_feature_huge_file(sb); - sbi->s_bitmap_maxbytes = ext4_max_bitmap_size(sb->s_blocksize_bits, - has_huge_files); - sb->s_maxbytes = ext4_max_size(sb->s_blocksize_bits, has_huge_files); - - if (le32_to_cpu(es->s_rev_level) == EXT4_GOOD_OLD_REV) { - sbi->s_inode_size = EXT4_GOOD_OLD_INODE_SIZE; - sbi->s_first_ino = EXT4_GOOD_OLD_FIRST_INO; - } else { - sbi->s_inode_size = le16_to_cpu(es->s_inode_size); - sbi->s_first_ino = le32_to_cpu(es->s_first_ino); - if ((sbi->s_inode_size < EXT4_GOOD_OLD_INODE_SIZE) || - (!is_power_of_2(sbi->s_inode_size)) || - (sbi->s_inode_size > blocksize)) { - ext4_msg(sb, KERN_ERR, - "unsupported inode size: %d", - sbi->s_inode_size); - goto failed_mount; - } - if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) - sb->s_time_gran = 1 << (EXT4_EPOCH_BITS - 2); - } - - sbi->s_desc_size = le16_to_cpu(es->s_desc_size); - if (ext4_has_feature_64bit(sb)) { - if (sbi->s_desc_size < EXT4_MIN_DESC_SIZE_64BIT || - sbi->s_desc_size > EXT4_MAX_DESC_SIZE || - !is_power_of_2(sbi->s_desc_size)) { - ext4_msg(sb, KERN_ERR, - "unsupported descriptor size %lu", - sbi->s_desc_size); - goto failed_mount; - } - } else - sbi->s_desc_size = EXT4_MIN_DESC_SIZE; - - sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group); - sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group); - if (EXT4_INODE_SIZE(sb) == 0 || EXT4_INODES_PER_GROUP(sb) == 0) - goto cantfind_ext4; - - sbi->s_inodes_per_block = blocksize / EXT4_INODE_SIZE(sb); - if (sbi->s_inodes_per_block == 0) - goto cantfind_ext4; - sbi->s_itb_per_group = sbi->s_inodes_per_group / - sbi->s_inodes_per_block; - sbi->s_desc_per_block = blocksize / EXT4_DESC_SIZE(sb); - sbi->s_sbh = bh; - sbi->s_mount_state = le16_to_cpu(es->s_state); - sbi->s_addr_per_block_bits = ilog2(EXT4_ADDR_PER_BLOCK(sb)); - sbi->s_desc_per_block_bits = ilog2(EXT4_DESC_PER_BLOCK(sb)); - - for (i = 0; i < 4; i++) - sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); - sbi->s_def_hash_version = es->s_def_hash_version; - if (ext4_has_feature_dir_index(sb)) { - i = le32_to_cpu(es->s_flags); - if (i & EXT2_FLAGS_UNSIGNED_HASH) - sbi->s_hash_unsigned = 3; - else if ((i & EXT2_FLAGS_SIGNED_HASH) == 0) { -#ifdef __CHAR_UNSIGNED__ - if (!(sb->s_flags & MS_RDONLY)) - es->s_flags |= - cpu_to_le32(EXT2_FLAGS_UNSIGNED_HASH); - sbi->s_hash_unsigned = 3; -#else - if (!(sb->s_flags & MS_RDONLY)) - es->s_flags |= - cpu_to_le32(EXT2_FLAGS_SIGNED_HASH); -#endif - } - } - - /* Handle clustersize */ - clustersize = BLOCK_SIZE << le32_to_cpu(es->s_log_cluster_size); - has_bigalloc = ext4_has_feature_bigalloc(sb); - if (has_bigalloc) { - if (clustersize < blocksize) { - ext4_msg(sb, KERN_ERR, - "cluster size (%d) smaller than " - "block size (%d)", clustersize, blocksize); - goto failed_mount; - } - if (le32_to_cpu(es->s_log_cluster_size) > - (EXT4_MAX_CLUSTER_LOG_SIZE - EXT4_MIN_BLOCK_LOG_SIZE)) { - ext4_msg(sb, KERN_ERR, - "Invalid log cluster size: %u", - le32_to_cpu(es->s_log_cluster_size)); - goto failed_mount; - } - sbi->s_cluster_bits = le32_to_cpu(es->s_log_cluster_size) - - le32_to_cpu(es->s_log_block_size); - sbi->s_clusters_per_group = - le32_to_cpu(es->s_clusters_per_group); - if (sbi->s_clusters_per_group > blocksize * 8) { - ext4_msg(sb, KERN_ERR, - "#clusters per group too big: %lu", - sbi->s_clusters_per_group); - goto failed_mount; - } - if (sbi->s_blocks_per_group != - (sbi->s_clusters_per_group * (clustersize / blocksize))) { - ext4_msg(sb, KERN_ERR, "blocks per group (%lu) and " - "clusters per group (%lu) inconsistent", - sbi->s_blocks_per_group, - sbi->s_clusters_per_group); - goto failed_mount; - } - } else { - if (clustersize != blocksize) { - ext4_warning(sb, "fragment/cluster size (%d) != " - "block size (%d)", clustersize, - blocksize); - clustersize = blocksize; - } - if (sbi->s_blocks_per_group > blocksize * 8) { - ext4_msg(sb, KERN_ERR, - "#blocks per group too big: %lu", - sbi->s_blocks_per_group); - goto failed_mount; - } - sbi->s_clusters_per_group = sbi->s_blocks_per_group; - sbi->s_cluster_bits = 0; - } - sbi->s_cluster_ratio = clustersize / blocksize; - - if (sbi->s_inodes_per_group > blocksize * 8) { - ext4_msg(sb, KERN_ERR, - "#inodes per group too big: %lu", - sbi->s_inodes_per_group); - goto failed_mount; - } - - /* Do we have standard group size of clustersize * 8 blocks ? */ - if (sbi->s_blocks_per_group == clustersize << 3) - set_opt2(sb, STD_GROUP_SIZE); - - /* - * Test whether we have more sectors than will fit in sector_t, - * and whether the max offset is addressable by the page cache. - */ - err = generic_check_addressable(sb->s_blocksize_bits, - ext4_blocks_count(es)); - if (err) { - ext4_msg(sb, KERN_ERR, "filesystem" - " too large to mount safely on this system"); - if (sizeof(sector_t) < 8) - ext4_msg(sb, KERN_WARNING, "CONFIG_LBDAF not enabled"); - goto failed_mount; - } - - if (EXT4_BLOCKS_PER_GROUP(sb) == 0) - goto cantfind_ext4; - - /* check blocks count against device size */ - blocks_count = sb->s_bdev->bd_inode->i_size >> sb->s_blocksize_bits; - if (blocks_count && ext4_blocks_count(es) > blocks_count) { - ext4_msg(sb, KERN_WARNING, "bad geometry: block count %llu " - "exceeds size of device (%llu blocks)", - ext4_blocks_count(es), blocks_count); - goto failed_mount; - } - - /* - * It makes no sense for the first data block to be beyond the end - * of the filesystem. - */ - if (le32_to_cpu(es->s_first_data_block) >= ext4_blocks_count(es)) { - ext4_msg(sb, KERN_WARNING, "bad geometry: first data " - "block %u is beyond end of filesystem (%llu)", - le32_to_cpu(es->s_first_data_block), - ext4_blocks_count(es)); - goto failed_mount; - } - blocks_count = (ext4_blocks_count(es) - - le32_to_cpu(es->s_first_data_block) + - EXT4_BLOCKS_PER_GROUP(sb) - 1); - do_div(blocks_count, EXT4_BLOCKS_PER_GROUP(sb)); - if (blocks_count > ((uint64_t)1<<32) - EXT4_DESC_PER_BLOCK(sb)) { - ext4_msg(sb, KERN_WARNING, "groups count too large: %u " - "(block count %llu, first data block %u, " - "blocks per group %lu)", sbi->s_groups_count, - ext4_blocks_count(es), - le32_to_cpu(es->s_first_data_block), - EXT4_BLOCKS_PER_GROUP(sb)); - goto failed_mount; - } - sbi->s_groups_count = blocks_count; - sbi->s_blockfile_groups = min_t(ext4_group_t, sbi->s_groups_count, - (EXT4_MAX_BLOCK_FILE_PHYS / EXT4_BLOCKS_PER_GROUP(sb))); - db_count = (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) / - EXT4_DESC_PER_BLOCK(sb); - sbi->s_group_desc = ext4_kvmalloc(db_count * - sizeof(struct buffer_head *), - GFP_KERNEL); - if (sbi->s_group_desc == NULL) { - ext4_msg(sb, KERN_ERR, "not enough memory"); - ret = -ENOMEM; - goto failed_mount; - } - - bgl_lock_init(sbi->s_blockgroup_lock); - - for (i = 0; i < db_count; i++) { - block = descriptor_loc(sb, logical_sb_block, i); - sbi->s_group_desc[i] = sb_bread_unmovable(sb, block); - if (!sbi->s_group_desc[i]) { - ext4_msg(sb, KERN_ERR, - "can't read group descriptor %d", i); - db_count = i; - goto failed_mount2; - } - } - if (!ext4_check_descriptors(sb, logical_sb_block, &first_not_zeroed)) { - ext4_msg(sb, KERN_ERR, "group descriptors corrupted!"); - ret = -EFSCORRUPTED; - goto failed_mount2; - } - - sbi->s_gdb_count = db_count; - get_random_bytes(&sbi->s_next_generation, sizeof(u32)); - spin_lock_init(&sbi->s_next_gen_lock); - - setup_timer(&sbi->s_err_report, print_daily_error_info, - (unsigned long) sb); - - /* Register extent status tree shrinker */ - if (ext4_es_register_shrinker(sbi)) - goto failed_mount3; - - sbi->s_stripe = ext4_get_stripe_size(sbi); - sbi->s_extent_max_zeroout_kb = 32; - - /* - * set up enough so that it can read an inode - */ - sb->s_op = &ext4_sops; - sb->s_export_op = &ext4_export_ops; - sb->s_xattr = ext4_xattr_handlers; - sb->s_cop = &ext4_cryptops; -#ifdef CONFIG_QUOTA - sb->dq_op = &ext4_quota_operations; - if (ext4_has_feature_quota(sb)) - sb->s_qcop = &dquot_quotactl_sysfile_ops; - else - sb->s_qcop = &ext4_qctl_operations; - sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ; -#endif - memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid)); - - INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */ - mutex_init(&sbi->s_orphan_lock); - - sb->s_root = NULL; - - needs_recovery = (es->s_last_orphan != 0 || - ext4_has_feature_journal_needs_recovery(sb)); - - if (ext4_has_feature_mmp(sb) && !(sb->s_flags & MS_RDONLY)) - if (ext4_multi_mount_protect(sb, le64_to_cpu(es->s_mmp_block))) - goto failed_mount3a; - - /* - * The first inode we look at is the journal inode. Don't try - * root first: it may be modified in the journal! - */ - if (!test_opt(sb, NOLOAD) && ext4_has_feature_journal(sb)) { - if (ext4_load_journal(sb, es, journal_devnum)) - goto failed_mount3a; - } else if (test_opt(sb, NOLOAD) && !(sb->s_flags & MS_RDONLY) && - ext4_has_feature_journal_needs_recovery(sb)) { - ext4_msg(sb, KERN_ERR, "required journal recovery " - "suppressed and not mounted read-only"); - goto failed_mount_wq; - } else { - /* Nojournal mode, all journal mount options are illegal */ - if (test_opt2(sb, EXPLICIT_JOURNAL_CHECKSUM)) { - ext4_msg(sb, KERN_ERR, "can't mount with " - "journal_checksum, fs mounted w/o journal"); - goto failed_mount_wq; - } - if (test_opt(sb, JOURNAL_ASYNC_COMMIT)) { - ext4_msg(sb, KERN_ERR, "can't mount with " - "journal_async_commit, fs mounted w/o journal"); - goto failed_mount_wq; - } - if (sbi->s_commit_interval != JBD2_DEFAULT_MAX_COMMIT_AGE*HZ) { - ext4_msg(sb, KERN_ERR, "can't mount with " - "commit=%lu, fs mounted w/o journal", - sbi->s_commit_interval / HZ); - goto failed_mount_wq; - } - if (EXT4_MOUNT_DATA_FLAGS & - (sbi->s_mount_opt ^ sbi->s_def_mount_opt)) { - ext4_msg(sb, KERN_ERR, "can't mount with " - "data=, fs mounted w/o journal"); - goto failed_mount_wq; - } - sbi->s_def_mount_opt &= EXT4_MOUNT_JOURNAL_CHECKSUM; - clear_opt(sb, JOURNAL_CHECKSUM); - clear_opt(sb, DATA_FLAGS); - sbi->s_journal = NULL; - needs_recovery = 0; - goto no_journal; - } - - if (ext4_has_feature_64bit(sb) && - !jbd2_journal_set_features(EXT4_SB(sb)->s_journal, 0, 0, - JBD2_FEATURE_INCOMPAT_64BIT)) { - ext4_msg(sb, KERN_ERR, "Failed to set 64-bit journal feature"); - goto failed_mount_wq; - } - - if (!set_journal_csum_feature_set(sb)) { - ext4_msg(sb, KERN_ERR, "Failed to set journal checksum " - "feature set"); - goto failed_mount_wq; - } - - /* We have now updated the journal if required, so we can - * validate the data journaling mode. */ - switch (test_opt(sb, DATA_FLAGS)) { - case 0: - /* No mode set, assume a default based on the journal - * capabilities: ORDERED_DATA if the journal can - * cope, else JOURNAL_DATA - */ - if (jbd2_journal_check_available_features - (sbi->s_journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)) - set_opt(sb, ORDERED_DATA); - else - set_opt(sb, JOURNAL_DATA); - break; - - case EXT4_MOUNT_ORDERED_DATA: - case EXT4_MOUNT_WRITEBACK_DATA: - if (!jbd2_journal_check_available_features - (sbi->s_journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)) { - ext4_msg(sb, KERN_ERR, "Journal does not support " - "requested data journaling mode"); - goto failed_mount_wq; - } - default: - break; - } - set_task_ioprio(sbi->s_journal->j_task, journal_ioprio); - - sbi->s_journal->j_commit_callback = ext4_journal_commit_callback; - -no_journal: - sbi->s_mb_cache = ext4_xattr_create_cache(); - if (!sbi->s_mb_cache) { - ext4_msg(sb, KERN_ERR, "Failed to create an mb_cache"); - goto failed_mount_wq; - } - - if ((DUMMY_ENCRYPTION_ENABLED(sbi) || ext4_has_feature_encrypt(sb)) && - (blocksize != PAGE_SIZE)) { - ext4_msg(sb, KERN_ERR, - "Unsupported blocksize for fs encryption"); - goto failed_mount_wq; - } - - if (DUMMY_ENCRYPTION_ENABLED(sbi) && !(sb->s_flags & MS_RDONLY) && - !ext4_has_feature_encrypt(sb)) { - ext4_set_feature_encrypt(sb); - ext4_commit_super(sb, 1); - } - - /* - * Get the # of file system overhead blocks from the - * superblock if present. - */ - if (es->s_overhead_clusters) - sbi->s_overhead = le32_to_cpu(es->s_overhead_clusters); - else { - err = ext4_calculate_overhead(sb); - if (err) - goto failed_mount_wq; - } - - /* - * The maximum number of concurrent works can be high and - * concurrency isn't really necessary. Limit it to 1. - */ - EXT4_SB(sb)->rsv_conversion_wq = - alloc_workqueue("ext4-rsv-conversion", WQ_MEM_RECLAIM | WQ_UNBOUND, 1); - if (!EXT4_SB(sb)->rsv_conversion_wq) { - printk(KERN_ERR "EXT4-fs: failed to create workqueue\n"); - ret = -ENOMEM; - goto failed_mount4; - } - - /* - * The jbd2_journal_load will have done any necessary log recovery, - * so we can safely mount the rest of the filesystem now. - */ - - root = ext4_iget(sb, EXT4_ROOT_INO); - if (IS_ERR(root)) { - ext4_msg(sb, KERN_ERR, "get root inode failed"); - ret = PTR_ERR(root); - root = NULL; - goto failed_mount4; - } - if (!S_ISDIR(root->i_mode) || !root->i_blocks || !root->i_size) { - ext4_msg(sb, KERN_ERR, "corrupt root inode, run e2fsck"); - iput(root); - goto failed_mount4; - } - sb->s_root = d_make_root(root); - if (!sb->s_root) { - ext4_msg(sb, KERN_ERR, "get root dentry failed"); - ret = -ENOMEM; - goto failed_mount4; - } - - if (ext4_setup_super(sb, es, sb->s_flags & MS_RDONLY)) - sb->s_flags |= MS_RDONLY; - - /* determine the minimum size of new large inodes, if present */ - if (sbi->s_inode_size > EXT4_GOOD_OLD_INODE_SIZE) { - sbi->s_want_extra_isize = sizeof(struct ext4_inode) - - EXT4_GOOD_OLD_INODE_SIZE; - if (ext4_has_feature_extra_isize(sb)) { - if (sbi->s_want_extra_isize < - le16_to_cpu(es->s_want_extra_isize)) - sbi->s_want_extra_isize = - le16_to_cpu(es->s_want_extra_isize); - if (sbi->s_want_extra_isize < - le16_to_cpu(es->s_min_extra_isize)) - sbi->s_want_extra_isize = - le16_to_cpu(es->s_min_extra_isize); - } - } - /* Check if enough inode space is available */ - if (EXT4_GOOD_OLD_INODE_SIZE + sbi->s_want_extra_isize > - sbi->s_inode_size) { - sbi->s_want_extra_isize = sizeof(struct ext4_inode) - - EXT4_GOOD_OLD_INODE_SIZE; - ext4_msg(sb, KERN_INFO, "required extra inode space not" - "available"); - } - - ext4_set_resv_clusters(sb); - - err = ext4_setup_system_zone(sb); - if (err) { - ext4_msg(sb, KERN_ERR, "failed to initialize system " - "zone (%d)", err); - goto failed_mount4a; - } - - ext4_ext_init(sb); - err = ext4_mb_init(sb); - if (err) { - ext4_msg(sb, KERN_ERR, "failed to initialize mballoc (%d)", - err); - goto failed_mount5; - } - - block = ext4_count_free_clusters(sb); - ext4_free_blocks_count_set(sbi->s_es, - EXT4_C2B(sbi, block)); - err = percpu_counter_init(&sbi->s_freeclusters_counter, block, - GFP_KERNEL); - if (!err) { - unsigned long freei = ext4_count_free_inodes(sb); - sbi->s_es->s_free_inodes_count = cpu_to_le32(freei); - err = percpu_counter_init(&sbi->s_freeinodes_counter, freei, - GFP_KERNEL); - } - if (!err) - err = percpu_counter_init(&sbi->s_dirs_counter, - ext4_count_dirs(sb), GFP_KERNEL); - if (!err) - err = percpu_counter_init(&sbi->s_dirtyclusters_counter, 0, - GFP_KERNEL); - if (!err) - err = percpu_init_rwsem(&sbi->s_journal_flag_rwsem); - - if (err) { - ext4_msg(sb, KERN_ERR, "insufficient memory"); - goto failed_mount6; - } - - if (ext4_has_feature_flex_bg(sb)) - if (!ext4_fill_flex_info(sb)) { - ext4_msg(sb, KERN_ERR, - "unable to initialize " - "flex_bg meta info!"); - goto failed_mount6; - } - - err = ext4_register_li_request(sb, first_not_zeroed); - if (err) - goto failed_mount6; - - err = ext4_register_sysfs(sb); - if (err) - goto failed_mount7; - -#ifdef CONFIG_QUOTA - /* Enable quota usage during mount. */ - if (ext4_has_feature_quota(sb) && !(sb->s_flags & MS_RDONLY)) { - err = ext4_enable_quotas(sb); - if (err) - goto failed_mount8; - } -#endif /* CONFIG_QUOTA */ - - EXT4_SB(sb)->s_mount_state |= EXT4_ORPHAN_FS; - ext4_orphan_cleanup(sb, es); - EXT4_SB(sb)->s_mount_state &= ~EXT4_ORPHAN_FS; - if (needs_recovery) { - ext4_msg(sb, KERN_INFO, "recovery complete"); - ext4_mark_recovery_complete(sb, es); - } - if (EXT4_SB(sb)->s_journal) { - if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) - descr = " journalled data mode"; - else if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_ORDERED_DATA) - descr = " ordered data mode"; - else - descr = " writeback data mode"; - } else - descr = "out journal"; - - if (test_opt(sb, DISCARD)) { - struct request_queue *q = bdev_get_queue(sb->s_bdev); - if (!blk_queue_discard(q)) - ext4_msg(sb, KERN_WARNING, - "mounting with \"discard\" option, but " - "the device does not support discard"); - } - - if (___ratelimit(&ext4_mount_msg_ratelimit, "EXT4-fs mount")) - ext4_msg(sb, KERN_INFO, "mounted filesystem with%s. " - "Opts: %s%s%s", descr, sbi->s_es->s_mount_opts, - *sbi->s_es->s_mount_opts ? "; " : "", orig_data); - - if (es->s_error_count) - mod_timer(&sbi->s_err_report, jiffies + 300*HZ); /* 5 minutes */ - - /* Enable message ratelimiting. Default is 10 messages per 5 secs. */ - ratelimit_state_init(&sbi->s_err_ratelimit_state, 5 * HZ, 10); - ratelimit_state_init(&sbi->s_warning_ratelimit_state, 5 * HZ, 10); - ratelimit_state_init(&sbi->s_msg_ratelimit_state, 5 * HZ, 10); - - kfree(orig_data); -#ifdef CONFIG_EXT4_FS_ENCRYPTION - memcpy(sbi->key_prefix, EXT4_KEY_DESC_PREFIX, - EXT4_KEY_DESC_PREFIX_SIZE); - sbi->key_prefix_size = EXT4_KEY_DESC_PREFIX_SIZE; -#endif - return 0; - -cantfind_ext4: - if (!silent) - ext4_msg(sb, KERN_ERR, "VFS: Can't find ext4 filesystem"); - goto failed_mount; - -#ifdef CONFIG_QUOTA -failed_mount8: - ext4_unregister_sysfs(sb); -#endif -failed_mount7: - ext4_unregister_li_request(sb); -failed_mount6: - ext4_mb_release(sb); - if (sbi->s_flex_groups) - kvfree(sbi->s_flex_groups); - percpu_counter_destroy(&sbi->s_freeclusters_counter); - percpu_counter_destroy(&sbi->s_freeinodes_counter); - percpu_counter_destroy(&sbi->s_dirs_counter); - percpu_counter_destroy(&sbi->s_dirtyclusters_counter); -failed_mount5: - ext4_ext_release(sb); - ext4_release_system_zone(sb); -failed_mount4a: - dput(sb->s_root); - sb->s_root = NULL; -failed_mount4: - ext4_msg(sb, KERN_ERR, "mount failed"); - if (EXT4_SB(sb)->rsv_conversion_wq) - destroy_workqueue(EXT4_SB(sb)->rsv_conversion_wq); -failed_mount_wq: - if (sbi->s_mb_cache) { - ext4_xattr_destroy_cache(sbi->s_mb_cache); - sbi->s_mb_cache = NULL; - } - if (sbi->s_journal) { - jbd2_journal_destroy(sbi->s_journal); - sbi->s_journal = NULL; - } -failed_mount3a: - ext4_es_unregister_shrinker(sbi); -failed_mount3: - del_timer_sync(&sbi->s_err_report); - if (sbi->s_mmp_tsk) - kthread_stop(sbi->s_mmp_tsk); -failed_mount2: - for (i = 0; i < db_count; i++) - brelse(sbi->s_group_desc[i]); - kvfree(sbi->s_group_desc); -failed_mount: - if (sbi->s_chksum_driver) - crypto_free_shash(sbi->s_chksum_driver); -#ifdef CONFIG_QUOTA - for (i = 0; i < EXT4_MAXQUOTAS; i++) - kfree(sbi->s_qf_names[i]); -#endif - ext4_blkdev_remove(sbi); - brelse(bh); -out_fail: - sb->s_fs_info = NULL; - kfree(sbi->s_blockgroup_lock); - kfree(sbi); -out_free_orig: - kfree(orig_data); - return err ? err : ret; -} - -/* - * Setup any per-fs journal parameters now. We'll do this both on - * initial mount, once the journal has been initialised but before we've - * done any recovery; and again on any subsequent remount. - */ -static void ext4_init_journal_params(struct super_block *sb, journal_t *journal) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - - journal->j_commit_interval = sbi->s_commit_interval; - journal->j_min_batch_time = sbi->s_min_batch_time; - journal->j_max_batch_time = sbi->s_max_batch_time; - - write_lock(&journal->j_state_lock); - if (test_opt(sb, BARRIER)) - journal->j_flags |= JBD2_BARRIER; - else - journal->j_flags &= ~JBD2_BARRIER; - if (test_opt(sb, DATA_ERR_ABORT)) - journal->j_flags |= JBD2_ABORT_ON_SYNCDATA_ERR; - else - journal->j_flags &= ~JBD2_ABORT_ON_SYNCDATA_ERR; - write_unlock(&journal->j_state_lock); -} - -static struct inode *ext4_get_journal_inode(struct super_block *sb, - unsigned int journal_inum) -{ - struct inode *journal_inode; - - /* - * Test for the existence of a valid inode on disk. Bad things - * happen if we iget() an unused inode, as the subsequent iput() - * will try to delete it. - */ - journal_inode = ext4_iget(sb, journal_inum); - if (IS_ERR(journal_inode)) { - ext4_msg(sb, KERN_ERR, "no journal found"); - return NULL; - } - if (!journal_inode->i_nlink) { - make_bad_inode(journal_inode); - iput(journal_inode); - ext4_msg(sb, KERN_ERR, "journal inode is deleted"); - return NULL; - } - - jbd_debug(2, "Journal inode found at %p: %lld bytes\n", - journal_inode, journal_inode->i_size); - if (!S_ISREG(journal_inode->i_mode)) { - ext4_msg(sb, KERN_ERR, "invalid journal inode"); - iput(journal_inode); - return NULL; - } - return journal_inode; -} - -static journal_t *ext4_get_journal(struct super_block *sb, - unsigned int journal_inum) -{ - struct inode *journal_inode; - journal_t *journal; - - BUG_ON(!ext4_has_feature_journal(sb)); - - journal_inode = ext4_get_journal_inode(sb, journal_inum); - if (!journal_inode) - return NULL; - - journal = jbd2_journal_init_inode(journal_inode); - if (!journal) { - ext4_msg(sb, KERN_ERR, "Could not load journal inode"); - iput(journal_inode); - return NULL; - } - journal->j_private = sb; - ext4_init_journal_params(sb, journal); - return journal; -} - -static journal_t *ext4_get_dev_journal(struct super_block *sb, - dev_t j_dev) -{ - struct buffer_head *bh; - journal_t *journal; - ext4_fsblk_t start; - ext4_fsblk_t len; - int hblock, blocksize; - ext4_fsblk_t sb_block; - unsigned long offset; - struct ext4_super_block *es; - struct block_device *bdev; - - BUG_ON(!ext4_has_feature_journal(sb)); - - bdev = ext4_blkdev_get(j_dev, sb); - if (bdev == NULL) - return NULL; - - blocksize = sb->s_blocksize; - hblock = bdev_logical_block_size(bdev); - if (blocksize < hblock) { - ext4_msg(sb, KERN_ERR, - "blocksize too small for journal device"); - goto out_bdev; - } - - sb_block = EXT4_MIN_BLOCK_SIZE / blocksize; - offset = EXT4_MIN_BLOCK_SIZE % blocksize; - set_blocksize(bdev, blocksize); - if (!(bh = __bread(bdev, sb_block, blocksize))) { - ext4_msg(sb, KERN_ERR, "couldn't read superblock of " - "external journal"); - goto out_bdev; - } - - es = (struct ext4_super_block *) (bh->b_data + offset); - if ((le16_to_cpu(es->s_magic) != EXT4_SUPER_MAGIC) || - !(le32_to_cpu(es->s_feature_incompat) & - EXT4_FEATURE_INCOMPAT_JOURNAL_DEV)) { - ext4_msg(sb, KERN_ERR, "external journal has " - "bad superblock"); - brelse(bh); - goto out_bdev; - } - - if ((le32_to_cpu(es->s_feature_ro_compat) & - EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) && - es->s_checksum != ext4_superblock_csum(sb, es)) { - ext4_msg(sb, KERN_ERR, "external journal has " - "corrupt superblock"); - brelse(bh); - goto out_bdev; - } - - if (memcmp(EXT4_SB(sb)->s_es->s_journal_uuid, es->s_uuid, 16)) { - ext4_msg(sb, KERN_ERR, "journal UUID does not match"); - brelse(bh); - goto out_bdev; - } - - len = ext4_blocks_count(es); - start = sb_block + 1; - brelse(bh); /* we're done with the superblock */ - - journal = jbd2_journal_init_dev(bdev, sb->s_bdev, - start, len, blocksize); - if (!journal) { - ext4_msg(sb, KERN_ERR, "failed to create device journal"); - goto out_bdev; - } - journal->j_private = sb; - ll_rw_block(REQ_OP_READ, REQ_META | REQ_PRIO, 1, &journal->j_sb_buffer); - wait_on_buffer(journal->j_sb_buffer); - if (!buffer_uptodate(journal->j_sb_buffer)) { - ext4_msg(sb, KERN_ERR, "I/O error on journal device"); - goto out_journal; - } - if (be32_to_cpu(journal->j_superblock->s_nr_users) != 1) { - ext4_msg(sb, KERN_ERR, "External journal has more than one " - "user (unsupported) - %d", - be32_to_cpu(journal->j_superblock->s_nr_users)); - goto out_journal; - } - EXT4_SB(sb)->journal_bdev = bdev; - ext4_init_journal_params(sb, journal); - return journal; - -out_journal: - jbd2_journal_destroy(journal); -out_bdev: - ext4_blkdev_put(bdev); - return NULL; -} - -static int ext4_load_journal(struct super_block *sb, - struct ext4_super_block *es, - unsigned long journal_devnum) -{ - journal_t *journal; - unsigned int journal_inum = le32_to_cpu(es->s_journal_inum); - dev_t journal_dev; - int err = 0; - int really_read_only; - - BUG_ON(!ext4_has_feature_journal(sb)); - - if (journal_devnum && - journal_devnum != le32_to_cpu(es->s_journal_dev)) { - ext4_msg(sb, KERN_INFO, "external journal device major/minor " - "numbers have changed"); - journal_dev = new_decode_dev(journal_devnum); - } else - journal_dev = new_decode_dev(le32_to_cpu(es->s_journal_dev)); - - really_read_only = bdev_read_only(sb->s_bdev); - - /* - * Are we loading a blank journal or performing recovery after a - * crash? For recovery, we need to check in advance whether we - * can get read-write access to the device. - */ - if (ext4_has_feature_journal_needs_recovery(sb)) { - if (sb->s_flags & MS_RDONLY) { - ext4_msg(sb, KERN_INFO, "INFO: recovery " - "required on readonly filesystem"); - if (really_read_only) { - ext4_msg(sb, KERN_ERR, "write access " - "unavailable, cannot proceed"); - return -EROFS; - } - ext4_msg(sb, KERN_INFO, "write access will " - "be enabled during recovery"); - } - } - - if (journal_inum && journal_dev) { - ext4_msg(sb, KERN_ERR, "filesystem has both journal " - "and inode journals!"); - return -EINVAL; - } - - if (journal_inum) { - if (!(journal = ext4_get_journal(sb, journal_inum))) - return -EINVAL; - } else { - if (!(journal = ext4_get_dev_journal(sb, journal_dev))) - return -EINVAL; - } - - if (!(journal->j_flags & JBD2_BARRIER)) - ext4_msg(sb, KERN_INFO, "barriers disabled"); - - if (!ext4_has_feature_journal_needs_recovery(sb)) - err = jbd2_journal_wipe(journal, !really_read_only); - if (!err) { - char *save = kmalloc(EXT4_S_ERR_LEN, GFP_KERNEL); - if (save) - memcpy(save, ((char *) es) + - EXT4_S_ERR_START, EXT4_S_ERR_LEN); - err = jbd2_journal_load(journal); - if (save) - memcpy(((char *) es) + EXT4_S_ERR_START, - save, EXT4_S_ERR_LEN); - kfree(save); - } - - if (err) { - ext4_msg(sb, KERN_ERR, "error loading journal"); - jbd2_journal_destroy(journal); - return err; - } - - EXT4_SB(sb)->s_journal = journal; - ext4_clear_journal_err(sb, es); - - if (!really_read_only && journal_devnum && - journal_devnum != le32_to_cpu(es->s_journal_dev)) { - es->s_journal_dev = cpu_to_le32(journal_devnum); - - /* Make sure we flush the recovery flag to disk. */ - ext4_commit_super(sb, 1); - } - - return 0; -} - -static int ext4_commit_super(struct super_block *sb, int sync) -{ - struct ext4_super_block *es = EXT4_SB(sb)->s_es; - struct buffer_head *sbh = EXT4_SB(sb)->s_sbh; - int error = 0; - - if (!sbh || block_device_ejected(sb)) - return error; - /* - * If the file system is mounted read-only, don't update the - * superblock write time. This avoids updating the superblock - * write time when we are mounting the root file system - * read/only but we need to replay the journal; at that point, - * for people who are east of GMT and who make their clock - * tick in localtime for Windows bug-for-bug compatibility, - * the clock is set in the future, and this will cause e2fsck - * to complain and force a full file system check. - */ - if (!(sb->s_flags & MS_RDONLY)) - es->s_wtime = cpu_to_le32(get_seconds()); - if (sb->s_bdev->bd_part) - es->s_kbytes_written = - cpu_to_le64(EXT4_SB(sb)->s_kbytes_written + - ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) - - EXT4_SB(sb)->s_sectors_written_start) >> 1)); - else - es->s_kbytes_written = - cpu_to_le64(EXT4_SB(sb)->s_kbytes_written); - if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeclusters_counter)) - ext4_free_blocks_count_set(es, - EXT4_C2B(EXT4_SB(sb), percpu_counter_sum_positive( - &EXT4_SB(sb)->s_freeclusters_counter))); - if (percpu_counter_initialized(&EXT4_SB(sb)->s_freeinodes_counter)) - es->s_free_inodes_count = - cpu_to_le32(percpu_counter_sum_positive( - &EXT4_SB(sb)->s_freeinodes_counter)); - BUFFER_TRACE(sbh, "marking dirty"); - ext4_superblock_csum_set(sb); - lock_buffer(sbh); - if (buffer_write_io_error(sbh)) { - /* - * Oh, dear. A previous attempt to write the - * superblock failed. This could happen because the - * USB device was yanked out. Or it could happen to - * be a transient write error and maybe the block will - * be remapped. Nothing we can do but to retry the - * write and hope for the best. - */ - ext4_msg(sb, KERN_ERR, "previous I/O error to " - "superblock detected"); - clear_buffer_write_io_error(sbh); - set_buffer_uptodate(sbh); - } - mark_buffer_dirty(sbh); - unlock_buffer(sbh); - if (sync) { - error = __sync_dirty_buffer(sbh, - test_opt(sb, BARRIER) ? WRITE_FUA : WRITE_SYNC); - if (error) - return error; - - error = buffer_write_io_error(sbh); - if (error) { - ext4_msg(sb, KERN_ERR, "I/O error while writing " - "superblock"); - clear_buffer_write_io_error(sbh); - set_buffer_uptodate(sbh); - } - } - return error; -} - -/* - * Have we just finished recovery? If so, and if we are mounting (or - * remounting) the filesystem readonly, then we will end up with a - * consistent fs on disk. Record that fact. - */ -static void ext4_mark_recovery_complete(struct super_block *sb, - struct ext4_super_block *es) -{ - journal_t *journal = EXT4_SB(sb)->s_journal; - - if (!ext4_has_feature_journal(sb)) { - BUG_ON(journal != NULL); - return; - } - jbd2_journal_lock_updates(journal); - if (jbd2_journal_flush(journal) < 0) - goto out; - - if (ext4_has_feature_journal_needs_recovery(sb) && - sb->s_flags & MS_RDONLY) { - ext4_clear_feature_journal_needs_recovery(sb); - ext4_commit_super(sb, 1); - } - -out: - jbd2_journal_unlock_updates(journal); -} - -/* - * If we are mounting (or read-write remounting) a filesystem whose journal - * has recorded an error from a previous lifetime, move that error to the - * main filesystem now. - */ -static void ext4_clear_journal_err(struct super_block *sb, - struct ext4_super_block *es) -{ - journal_t *journal; - int j_errno; - const char *errstr; - - BUG_ON(!ext4_has_feature_journal(sb)); - - journal = EXT4_SB(sb)->s_journal; - - /* - * Now check for any error status which may have been recorded in the - * journal by a prior ext4_error() or ext4_abort() - */ - - j_errno = jbd2_journal_errno(journal); - if (j_errno) { - char nbuf[16]; - - errstr = ext4_decode_error(sb, j_errno, nbuf); - ext4_warning(sb, "Filesystem error recorded " - "from previous mount: %s", errstr); - ext4_warning(sb, "Marking fs in need of filesystem check."); - - EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS; - es->s_state |= cpu_to_le16(EXT4_ERROR_FS); - ext4_commit_super(sb, 1); - - jbd2_journal_clear_err(journal); - jbd2_journal_update_sb_errno(journal); - } -} - -/* - * Force the running and committing transactions to commit, - * and wait on the commit. - */ -int ext4_force_commit(struct super_block *sb) -{ - journal_t *journal; - - if (sb->s_flags & MS_RDONLY) - return 0; - - journal = EXT4_SB(sb)->s_journal; - return ext4_journal_force_commit(journal); -} - -static int ext4_sync_fs(struct super_block *sb, int wait) -{ - int ret = 0; - tid_t target; - bool needs_barrier = false; - struct ext4_sb_info *sbi = EXT4_SB(sb); - - trace_ext4_sync_fs(sb, wait); - flush_workqueue(sbi->rsv_conversion_wq); - /* - * Writeback quota in non-journalled quota case - journalled quota has - * no dirty dquots - */ - dquot_writeback_dquots(sb, -1); - /* - * Data writeback is possible w/o journal transaction, so barrier must - * being sent at the end of the function. But we can skip it if - * transaction_commit will do it for us. - */ - if (sbi->s_journal) { - target = jbd2_get_latest_transaction(sbi->s_journal); - if (wait && sbi->s_journal->j_flags & JBD2_BARRIER && - !jbd2_trans_will_send_data_barrier(sbi->s_journal, target)) - needs_barrier = true; - - if (jbd2_journal_start_commit(sbi->s_journal, &target)) { - if (wait) - ret = jbd2_log_wait_commit(sbi->s_journal, - target); - } - } else if (wait && test_opt(sb, BARRIER)) - needs_barrier = true; - if (needs_barrier) { - int err; - err = blkdev_issue_flush(sb->s_bdev, GFP_KERNEL, NULL); - if (!ret) - ret = err; - } - - return ret; -} - -/* - * LVM calls this function before a (read-only) snapshot is created. This - * gives us a chance to flush the journal completely and mark the fs clean. - * - * Note that only this function cannot bring a filesystem to be in a clean - * state independently. It relies on upper layer to stop all data & metadata - * modifications. - */ -static int ext4_freeze(struct super_block *sb) -{ - int error = 0; - journal_t *journal; - - if (sb->s_flags & MS_RDONLY) - return 0; - - journal = EXT4_SB(sb)->s_journal; - - if (journal) { - /* Now we set up the journal barrier. */ - jbd2_journal_lock_updates(journal); - - /* - * Don't clear the needs_recovery flag if we failed to - * flush the journal. - */ - error = jbd2_journal_flush(journal); - if (error < 0) - goto out; - - /* Journal blocked and flushed, clear needs_recovery flag. */ - ext4_clear_feature_journal_needs_recovery(sb); - } - - error = ext4_commit_super(sb, 1); -out: - if (journal) - /* we rely on upper layer to stop further updates */ - jbd2_journal_unlock_updates(journal); - return error; -} - -/* - * Called by LVM after the snapshot is done. We need to reset the RECOVER - * flag here, even though the filesystem is not technically dirty yet. - */ -static int ext4_unfreeze(struct super_block *sb) -{ - if (sb->s_flags & MS_RDONLY) - return 0; - - if (EXT4_SB(sb)->s_journal) { - /* Reset the needs_recovery flag before the fs is unlocked. */ - ext4_set_feature_journal_needs_recovery(sb); - } - - ext4_commit_super(sb, 1); - return 0; -} - -/* - * Structure to save mount options for ext4_remount's benefit - */ -struct ext4_mount_options { - unsigned long s_mount_opt; - unsigned long s_mount_opt2; - kuid_t s_resuid; - kgid_t s_resgid; - unsigned long s_commit_interval; - u32 s_min_batch_time, s_max_batch_time; -#ifdef CONFIG_QUOTA - int s_jquota_fmt; - char *s_qf_names[EXT4_MAXQUOTAS]; -#endif -}; - -static int ext4_remount(struct super_block *sb, int *flags, char *data) -{ - struct ext4_super_block *es; - struct ext4_sb_info *sbi = EXT4_SB(sb); - unsigned long old_sb_flags; - struct ext4_mount_options old_opts; - int enable_quota = 0; - ext4_group_t g; - unsigned int journal_ioprio = DEFAULT_JOURNAL_IOPRIO; - int err = 0; -#ifdef CONFIG_QUOTA - int i, j; -#endif - char *orig_data = kstrdup(data, GFP_KERNEL); - - /* Store the original options */ - old_sb_flags = sb->s_flags; - old_opts.s_mount_opt = sbi->s_mount_opt; - old_opts.s_mount_opt2 = sbi->s_mount_opt2; - old_opts.s_resuid = sbi->s_resuid; - old_opts.s_resgid = sbi->s_resgid; - old_opts.s_commit_interval = sbi->s_commit_interval; - old_opts.s_min_batch_time = sbi->s_min_batch_time; - old_opts.s_max_batch_time = sbi->s_max_batch_time; -#ifdef CONFIG_QUOTA - old_opts.s_jquota_fmt = sbi->s_jquota_fmt; - for (i = 0; i < EXT4_MAXQUOTAS; i++) - if (sbi->s_qf_names[i]) { - old_opts.s_qf_names[i] = kstrdup(sbi->s_qf_names[i], - GFP_KERNEL); - if (!old_opts.s_qf_names[i]) { - for (j = 0; j < i; j++) - kfree(old_opts.s_qf_names[j]); - kfree(orig_data); - return -ENOMEM; - } - } else - old_opts.s_qf_names[i] = NULL; -#endif - if (sbi->s_journal && sbi->s_journal->j_task->io_context) - journal_ioprio = sbi->s_journal->j_task->io_context->ioprio; - - if (!parse_options(data, sb, NULL, &journal_ioprio, 1)) { - err = -EINVAL; - goto restore_opts; - } - - if ((old_opts.s_mount_opt & EXT4_MOUNT_JOURNAL_CHECKSUM) ^ - test_opt(sb, JOURNAL_CHECKSUM)) { - ext4_msg(sb, KERN_ERR, "changing journal_checksum " - "during remount not supported; ignoring"); - sbi->s_mount_opt ^= EXT4_MOUNT_JOURNAL_CHECKSUM; - } - - if (test_opt(sb, DATA_FLAGS) == EXT4_MOUNT_JOURNAL_DATA) { - if (test_opt2(sb, EXPLICIT_DELALLOC)) { - ext4_msg(sb, KERN_ERR, "can't mount with " - "both data=journal and delalloc"); - err = -EINVAL; - goto restore_opts; - } - if (test_opt(sb, DIOREAD_NOLOCK)) { - ext4_msg(sb, KERN_ERR, "can't mount with " - "both data=journal and dioread_nolock"); - err = -EINVAL; - goto restore_opts; - } - if (test_opt(sb, DAX)) { - ext4_msg(sb, KERN_ERR, "can't mount with " - "both data=journal and dax"); - err = -EINVAL; - goto restore_opts; - } - } - - if ((sbi->s_mount_opt ^ old_opts.s_mount_opt) & EXT4_MOUNT_DAX) { - ext4_msg(sb, KERN_WARNING, "warning: refusing change of " - "dax flag with busy inodes while remounting"); - sbi->s_mount_opt ^= EXT4_MOUNT_DAX; - } - - if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED) - ext4_abort(sb, "Abort forced by user"); - - sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | - (test_opt(sb, POSIX_ACL) ? MS_POSIXACL : 0); - - es = sbi->s_es; - - if (sbi->s_journal) { - ext4_init_journal_params(sb, sbi->s_journal); - set_task_ioprio(sbi->s_journal->j_task, journal_ioprio); - } - - if (*flags & MS_LAZYTIME) - sb->s_flags |= MS_LAZYTIME; - - if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY)) { - if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED) { - err = -EROFS; - goto restore_opts; - } - - if (*flags & MS_RDONLY) { - err = sync_filesystem(sb); - if (err < 0) - goto restore_opts; - err = dquot_suspend(sb, -1); - if (err < 0) - goto restore_opts; - - /* - * First of all, the unconditional stuff we have to do - * to disable replay of the journal when we next remount - */ - sb->s_flags |= MS_RDONLY; - - /* - * OK, test if we are remounting a valid rw partition - * readonly, and if so set the rdonly flag and then - * mark the partition as valid again. - */ - if (!(es->s_state & cpu_to_le16(EXT4_VALID_FS)) && - (sbi->s_mount_state & EXT4_VALID_FS)) - es->s_state = cpu_to_le16(sbi->s_mount_state); - - if (sbi->s_journal) - ext4_mark_recovery_complete(sb, es); - } else { - /* Make sure we can mount this feature set readwrite */ - if (ext4_has_feature_readonly(sb) || - !ext4_feature_set_ok(sb, 0)) { - err = -EROFS; - goto restore_opts; - } - /* - * Make sure the group descriptor checksums - * are sane. If they aren't, refuse to remount r/w. - */ - for (g = 0; g < sbi->s_groups_count; g++) { - struct ext4_group_desc *gdp = - ext4_get_group_desc(sb, g, NULL); - - if (!ext4_group_desc_csum_verify(sb, g, gdp)) { - ext4_msg(sb, KERN_ERR, - "ext4_remount: Checksum for group %u failed (%u!=%u)", - g, le16_to_cpu(ext4_group_desc_csum(sb, g, gdp)), - le16_to_cpu(gdp->bg_checksum)); - err = -EFSBADCRC; - goto restore_opts; - } - } - - /* - * If we have an unprocessed orphan list hanging - * around from a previously readonly bdev mount, - * require a full umount/remount for now. - */ - if (es->s_last_orphan) { - ext4_msg(sb, KERN_WARNING, "Couldn't " - "remount RDWR because of unprocessed " - "orphan inode list. Please " - "umount/remount instead"); - err = -EINVAL; - goto restore_opts; - } - - /* - * Mounting a RDONLY partition read-write, so reread - * and store the current valid flag. (It may have - * been changed by e2fsck since we originally mounted - * the partition.) - */ - if (sbi->s_journal) - ext4_clear_journal_err(sb, es); - sbi->s_mount_state = le16_to_cpu(es->s_state); - if (!ext4_setup_super(sb, es, 0)) - sb->s_flags &= ~MS_RDONLY; - if (ext4_has_feature_mmp(sb)) - if (ext4_multi_mount_protect(sb, - le64_to_cpu(es->s_mmp_block))) { - err = -EROFS; - goto restore_opts; - } - enable_quota = 1; - } - } - - /* - * Reinitialize lazy itable initialization thread based on - * current settings - */ - if ((sb->s_flags & MS_RDONLY) || !test_opt(sb, INIT_INODE_TABLE)) - ext4_unregister_li_request(sb); - else { - ext4_group_t first_not_zeroed; - first_not_zeroed = ext4_has_uninit_itable(sb); - ext4_register_li_request(sb, first_not_zeroed); - } - - ext4_setup_system_zone(sb); - if (sbi->s_journal == NULL && !(old_sb_flags & MS_RDONLY)) - ext4_commit_super(sb, 1); - -#ifdef CONFIG_QUOTA - /* Release old quota file names */ - for (i = 0; i < EXT4_MAXQUOTAS; i++) - kfree(old_opts.s_qf_names[i]); - if (enable_quota) { - if (sb_any_quota_suspended(sb)) - dquot_resume(sb, -1); - else if (ext4_has_feature_quota(sb)) { - err = ext4_enable_quotas(sb); - if (err) - goto restore_opts; - } - } -#endif - - *flags = (*flags & ~MS_LAZYTIME) | (sb->s_flags & MS_LAZYTIME); - ext4_msg(sb, KERN_INFO, "re-mounted. Opts: %s", orig_data); - kfree(orig_data); - return 0; - -restore_opts: - sb->s_flags = old_sb_flags; - sbi->s_mount_opt = old_opts.s_mount_opt; - sbi->s_mount_opt2 = old_opts.s_mount_opt2; - sbi->s_resuid = old_opts.s_resuid; - sbi->s_resgid = old_opts.s_resgid; - sbi->s_commit_interval = old_opts.s_commit_interval; - sbi->s_min_batch_time = old_opts.s_min_batch_time; - sbi->s_max_batch_time = old_opts.s_max_batch_time; -#ifdef CONFIG_QUOTA - sbi->s_jquota_fmt = old_opts.s_jquota_fmt; - for (i = 0; i < EXT4_MAXQUOTAS; i++) { - kfree(sbi->s_qf_names[i]); - sbi->s_qf_names[i] = old_opts.s_qf_names[i]; - } -#endif - kfree(orig_data); - return err; -} - -#ifdef CONFIG_QUOTA -static int ext4_statfs_project(struct super_block *sb, - kprojid_t projid, struct kstatfs *buf) -{ - struct kqid qid; - struct dquot *dquot; - u64 limit; - u64 curblock; - - qid = make_kqid_projid(projid); - dquot = dqget(sb, qid); - if (IS_ERR(dquot)) - return PTR_ERR(dquot); - spin_lock(&dq_data_lock); - - limit = (dquot->dq_dqb.dqb_bsoftlimit ? - dquot->dq_dqb.dqb_bsoftlimit : - dquot->dq_dqb.dqb_bhardlimit) >> sb->s_blocksize_bits; - if (limit && buf->f_blocks > limit) { - curblock = dquot->dq_dqb.dqb_curspace >> sb->s_blocksize_bits; - buf->f_blocks = limit; - buf->f_bfree = buf->f_bavail = - (buf->f_blocks > curblock) ? - (buf->f_blocks - curblock) : 0; - } - - limit = dquot->dq_dqb.dqb_isoftlimit ? - dquot->dq_dqb.dqb_isoftlimit : - dquot->dq_dqb.dqb_ihardlimit; - if (limit && buf->f_files > limit) { - buf->f_files = limit; - buf->f_ffree = - (buf->f_files > dquot->dq_dqb.dqb_curinodes) ? - (buf->f_files - dquot->dq_dqb.dqb_curinodes) : 0; - } - - spin_unlock(&dq_data_lock); - dqput(dquot); - return 0; -} -#endif - -static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf) -{ - struct super_block *sb = dentry->d_sb; - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_super_block *es = sbi->s_es; - ext4_fsblk_t overhead = 0, resv_blocks; - u64 fsid; - s64 bfree; - resv_blocks = EXT4_C2B(sbi, atomic64_read(&sbi->s_resv_clusters)); - - if (!test_opt(sb, MINIX_DF)) - overhead = sbi->s_overhead; - - buf->f_type = EXT4_SUPER_MAGIC; - buf->f_bsize = sb->s_blocksize; - buf->f_blocks = ext4_blocks_count(es) - EXT4_C2B(sbi, overhead); - bfree = percpu_counter_sum_positive(&sbi->s_freeclusters_counter) - - percpu_counter_sum_positive(&sbi->s_dirtyclusters_counter); - /* prevent underflow in case that few free space is available */ - buf->f_bfree = EXT4_C2B(sbi, max_t(s64, bfree, 0)); - buf->f_bavail = buf->f_bfree - - (ext4_r_blocks_count(es) + resv_blocks); - if (buf->f_bfree < (ext4_r_blocks_count(es) + resv_blocks)) - buf->f_bavail = 0; - buf->f_files = le32_to_cpu(es->s_inodes_count); - buf->f_ffree = percpu_counter_sum_positive(&sbi->s_freeinodes_counter); - buf->f_namelen = EXT4_NAME_LEN; - fsid = le64_to_cpup((void *)es->s_uuid) ^ - le64_to_cpup((void *)es->s_uuid + sizeof(u64)); - buf->f_fsid.val[0] = fsid & 0xFFFFFFFFUL; - buf->f_fsid.val[1] = (fsid >> 32) & 0xFFFFFFFFUL; - -#ifdef CONFIG_QUOTA - if (ext4_test_inode_flag(dentry->d_inode, EXT4_INODE_PROJINHERIT) && - sb_has_quota_limits_enabled(sb, PRJQUOTA)) - ext4_statfs_project(sb, EXT4_I(dentry->d_inode)->i_projid, buf); -#endif - return 0; -} - -/* Helper function for writing quotas on sync - we need to start transaction - * before quota file is locked for write. Otherwise the are possible deadlocks: - * Process 1 Process 2 - * ext4_create() quota_sync() - * jbd2_journal_start() write_dquot() - * dquot_initialize() down(dqio_mutex) - * down(dqio_mutex) jbd2_journal_start() - * - */ - -#ifdef CONFIG_QUOTA - -static inline struct inode *dquot_to_inode(struct dquot *dquot) -{ - return sb_dqopt(dquot->dq_sb)->files[dquot->dq_id.type]; -} - -static int ext4_write_dquot(struct dquot *dquot) -{ - int ret, err; - handle_t *handle; - struct inode *inode; - - inode = dquot_to_inode(dquot); - handle = ext4_journal_start(inode, EXT4_HT_QUOTA, - EXT4_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - ret = dquot_commit(dquot); - err = ext4_journal_stop(handle); - if (!ret) - ret = err; - return ret; -} - -static int ext4_acquire_dquot(struct dquot *dquot) -{ - int ret, err; - handle_t *handle; - - handle = ext4_journal_start(dquot_to_inode(dquot), EXT4_HT_QUOTA, - EXT4_QUOTA_INIT_BLOCKS(dquot->dq_sb)); - if (IS_ERR(handle)) - return PTR_ERR(handle); - ret = dquot_acquire(dquot); - err = ext4_journal_stop(handle); - if (!ret) - ret = err; - return ret; -} - -static int ext4_release_dquot(struct dquot *dquot) -{ - int ret, err; - handle_t *handle; - - handle = ext4_journal_start(dquot_to_inode(dquot), EXT4_HT_QUOTA, - EXT4_QUOTA_DEL_BLOCKS(dquot->dq_sb)); - if (IS_ERR(handle)) { - /* Release dquot anyway to avoid endless cycle in dqput() */ - dquot_release(dquot); - return PTR_ERR(handle); - } - ret = dquot_release(dquot); - err = ext4_journal_stop(handle); - if (!ret) - ret = err; - return ret; -} - -static int ext4_mark_dquot_dirty(struct dquot *dquot) -{ - struct super_block *sb = dquot->dq_sb; - struct ext4_sb_info *sbi = EXT4_SB(sb); - - /* Are we journaling quotas? */ - if (ext4_has_feature_quota(sb) || - sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) { - dquot_mark_dquot_dirty(dquot); - return ext4_write_dquot(dquot); - } else { - return dquot_mark_dquot_dirty(dquot); - } -} - -static int ext4_write_info(struct super_block *sb, int type) -{ - int ret, err; - handle_t *handle; - - /* Data block + inode block */ - handle = ext4_journal_start(d_inode(sb->s_root), EXT4_HT_QUOTA, 2); - if (IS_ERR(handle)) - return PTR_ERR(handle); - ret = dquot_commit_info(sb, type); - err = ext4_journal_stop(handle); - if (!ret) - ret = err; - return ret; -} - -/* - * Turn on quotas during mount time - we need to find - * the quota file and such... - */ -static int ext4_quota_on_mount(struct super_block *sb, int type) -{ - return dquot_quota_on_mount(sb, EXT4_SB(sb)->s_qf_names[type], - EXT4_SB(sb)->s_jquota_fmt, type); -} - -static void lockdep_set_quota_inode(struct inode *inode, int subclass) -{ - struct ext4_inode_info *ei = EXT4_I(inode); - - /* The first argument of lockdep_set_subclass has to be - * *exactly* the same as the argument to init_rwsem() --- in - * this case, in init_once() --- or lockdep gets unhappy - * because the name of the lock is set using the - * stringification of the argument to init_rwsem(). - */ - (void) ei; /* shut up clang warning if !CONFIG_LOCKDEP */ - lockdep_set_subclass(&ei->i_data_sem, subclass); -} - -/* - * Standard function to be called on quota_on - */ -static int ext4_quota_on(struct super_block *sb, int type, int format_id, - struct path *path) -{ - int err; - - if (!test_opt(sb, QUOTA)) - return -EINVAL; - - /* Quotafile not on the same filesystem? */ - if (path->dentry->d_sb != sb) - return -EXDEV; - /* Journaling quota? */ - if (EXT4_SB(sb)->s_qf_names[type]) { - /* Quotafile not in fs root? */ - if (path->dentry->d_parent != sb->s_root) - ext4_msg(sb, KERN_WARNING, - "Quota file not on filesystem root. " - "Journaled quota will not work"); - } - - /* - * When we journal data on quota file, we have to flush journal to see - * all updates to the file when we bypass pagecache... - */ - if (EXT4_SB(sb)->s_journal && - ext4_should_journal_data(d_inode(path->dentry))) { - /* - * We don't need to lock updates but journal_flush() could - * otherwise be livelocked... - */ - jbd2_journal_lock_updates(EXT4_SB(sb)->s_journal); - err = jbd2_journal_flush(EXT4_SB(sb)->s_journal); - jbd2_journal_unlock_updates(EXT4_SB(sb)->s_journal); - if (err) - return err; - } - lockdep_set_quota_inode(path->dentry->d_inode, I_DATA_SEM_QUOTA); - err = dquot_quota_on(sb, type, format_id, path); - if (err) - lockdep_set_quota_inode(path->dentry->d_inode, - I_DATA_SEM_NORMAL); - return err; -} - -static int ext4_quota_enable(struct super_block *sb, int type, int format_id, - unsigned int flags) -{ - int err; - struct inode *qf_inode; - unsigned long qf_inums[EXT4_MAXQUOTAS] = { - le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum), - le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum), - le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum) - }; - - BUG_ON(!ext4_has_feature_quota(sb)); - - if (!qf_inums[type]) - return -EPERM; - - qf_inode = ext4_iget(sb, qf_inums[type]); - if (IS_ERR(qf_inode)) { - ext4_error(sb, "Bad quota inode # %lu", qf_inums[type]); - return PTR_ERR(qf_inode); - } - - /* Don't account quota for quota files to avoid recursion */ - qf_inode->i_flags |= S_NOQUOTA; - lockdep_set_quota_inode(qf_inode, I_DATA_SEM_QUOTA); - err = dquot_enable(qf_inode, type, format_id, flags); - iput(qf_inode); - if (err) - lockdep_set_quota_inode(qf_inode, I_DATA_SEM_NORMAL); - - return err; -} - -/* Enable usage tracking for all quota types. */ -static int ext4_enable_quotas(struct super_block *sb) -{ - int type, err = 0; - unsigned long qf_inums[EXT4_MAXQUOTAS] = { - le32_to_cpu(EXT4_SB(sb)->s_es->s_usr_quota_inum), - le32_to_cpu(EXT4_SB(sb)->s_es->s_grp_quota_inum), - le32_to_cpu(EXT4_SB(sb)->s_es->s_prj_quota_inum) - }; - bool quota_mopt[EXT4_MAXQUOTAS] = { - test_opt(sb, USRQUOTA), - test_opt(sb, GRPQUOTA), - test_opt(sb, PRJQUOTA), - }; - - sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE; - for (type = 0; type < EXT4_MAXQUOTAS; type++) { - if (qf_inums[type]) { - err = ext4_quota_enable(sb, type, QFMT_VFS_V1, - DQUOT_USAGE_ENABLED | - (quota_mopt[type] ? DQUOT_LIMITS_ENABLED : 0)); - if (err) { - ext4_warning(sb, - "Failed to enable quota tracking " - "(type=%d, err=%d). Please run " - "e2fsck to fix.", type, err); - return err; - } - } - } - return 0; -} - -static int ext4_quota_off(struct super_block *sb, int type) -{ - struct inode *inode = sb_dqopt(sb)->files[type]; - handle_t *handle; - - /* Force all delayed allocation blocks to be allocated. - * Caller already holds s_umount sem */ - if (test_opt(sb, DELALLOC)) - sync_filesystem(sb); - - if (!inode) - goto out; - - /* Update modification times of quota files when userspace can - * start looking at them */ - handle = ext4_journal_start(inode, EXT4_HT_QUOTA, 1); - if (IS_ERR(handle)) - goto out; - inode->i_mtime = inode->i_ctime = CURRENT_TIME; - ext4_mark_inode_dirty(handle, inode); - ext4_journal_stop(handle); - -out: - return dquot_quota_off(sb, type); -} - -/* Read data from quotafile - avoid pagecache and such because we cannot afford - * acquiring the locks... As quota files are never truncated and quota code - * itself serializes the operations (and no one else should touch the files) - * we don't have to be afraid of races */ -static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data, - size_t len, loff_t off) -{ - struct inode *inode = sb_dqopt(sb)->files[type]; - ext4_lblk_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb); - int offset = off & (sb->s_blocksize - 1); - int tocopy; - size_t toread; - struct buffer_head *bh; - loff_t i_size = i_size_read(inode); - - if (off > i_size) - return 0; - if (off+len > i_size) - len = i_size-off; - toread = len; - while (toread > 0) { - tocopy = sb->s_blocksize - offset < toread ? - sb->s_blocksize - offset : toread; - bh = ext4_bread(NULL, inode, blk, 0); - if (IS_ERR(bh)) - return PTR_ERR(bh); - if (!bh) /* A hole? */ - memset(data, 0, tocopy); - else - memcpy(data, bh->b_data+offset, tocopy); - brelse(bh); - offset = 0; - toread -= tocopy; - data += tocopy; - blk++; - } - return len; -} - -/* Write to quotafile (we know the transaction is already started and has - * enough credits) */ -static ssize_t ext4_quota_write(struct super_block *sb, int type, - const char *data, size_t len, loff_t off) -{ - struct inode *inode = sb_dqopt(sb)->files[type]; - ext4_lblk_t blk = off >> EXT4_BLOCK_SIZE_BITS(sb); - int err, offset = off & (sb->s_blocksize - 1); - int retries = 0; - struct buffer_head *bh; - handle_t *handle = journal_current_handle(); - - if (EXT4_SB(sb)->s_journal && !handle) { - ext4_msg(sb, KERN_WARNING, "Quota write (off=%llu, len=%llu)" - " cancelled because transaction is not started", - (unsigned long long)off, (unsigned long long)len); - return -EIO; - } - /* - * Since we account only one data block in transaction credits, - * then it is impossible to cross a block boundary. - */ - if (sb->s_blocksize - offset < len) { - ext4_msg(sb, KERN_WARNING, "Quota write (off=%llu, len=%llu)" - " cancelled because not block aligned", - (unsigned long long)off, (unsigned long long)len); - return -EIO; - } - - do { - bh = ext4_bread(handle, inode, blk, - EXT4_GET_BLOCKS_CREATE | - EXT4_GET_BLOCKS_METADATA_NOFAIL); - } while (IS_ERR(bh) && (PTR_ERR(bh) == -ENOSPC) && - ext4_should_retry_alloc(inode->i_sb, &retries)); - if (IS_ERR(bh)) - return PTR_ERR(bh); - if (!bh) - goto out; - BUFFER_TRACE(bh, "get write access"); - err = ext4_journal_get_write_access(handle, bh); - if (err) { - brelse(bh); - return err; - } - lock_buffer(bh); - memcpy(bh->b_data+offset, data, len); - flush_dcache_page(bh->b_page); - unlock_buffer(bh); - err = ext4_handle_dirty_metadata(handle, NULL, bh); - brelse(bh); -out: - if (inode->i_size < off + len) { - i_size_write(inode, off + len); - EXT4_I(inode)->i_disksize = inode->i_size; - ext4_mark_inode_dirty(handle, inode); - } - return len; -} - -static int ext4_get_next_id(struct super_block *sb, struct kqid *qid) -{ - const struct quota_format_ops *ops; - - if (!sb_has_quota_loaded(sb, qid->type)) - return -ESRCH; - ops = sb_dqopt(sb)->ops[qid->type]; - if (!ops || !ops->get_next_id) - return -ENOSYS; - return dquot_get_next_id(sb, qid); -} -#endif - -static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data) -{ - return mount_bdev(fs_type, flags, dev_name, data, ext4_fill_super); -} - -#if !defined(CONFIG_EXT2_FS) && !defined(CONFIG_EXT2_FS_MODULE) && defined(CONFIG_EXT4_USE_FOR_EXT2) -static inline void register_as_ext2(void) -{ - int err = register_filesystem(&ext2_fs_type); - if (err) - printk(KERN_WARNING - "EXT4-fs: Unable to register as ext2 (%d)\n", err); -} - -static inline void unregister_as_ext2(void) -{ - unregister_filesystem(&ext2_fs_type); -} - -static inline int ext2_feature_set_ok(struct super_block *sb) -{ - if (ext4_has_unknown_ext2_incompat_features(sb)) - return 0; - if (sb->s_flags & MS_RDONLY) - return 1; - if (ext4_has_unknown_ext2_ro_compat_features(sb)) - return 0; - return 1; -} -#else -static inline void register_as_ext2(void) { } -static inline void unregister_as_ext2(void) { } -static inline int ext2_feature_set_ok(struct super_block *sb) { return 0; } -#endif - -static inline void register_as_ext3(void) -{ - int err = register_filesystem(&ext3_fs_type); - if (err) - printk(KERN_WARNING - "EXT4-fs: Unable to register as ext3 (%d)\n", err); -} - -static inline void unregister_as_ext3(void) -{ - unregister_filesystem(&ext3_fs_type); -} - -static inline int ext3_feature_set_ok(struct super_block *sb) -{ - if (ext4_has_unknown_ext3_incompat_features(sb)) - return 0; - if (!ext4_has_feature_journal(sb)) - return 0; - if (sb->s_flags & MS_RDONLY) - return 1; - if (ext4_has_unknown_ext3_ro_compat_features(sb)) - return 0; - return 1; -} - -static struct file_system_type ext4_fs_type = { - .owner = THIS_MODULE, - .name = "ext4", - .mount = ext4_mount, - .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, -}; -MODULE_ALIAS_FS("ext4"); - -/* Shared across all ext4 file systems */ -wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ]; - -static int __init ext4_init_fs(void) -{ - int i, err; - - ratelimit_state_init(&ext4_mount_msg_ratelimit, 30 * HZ, 64); - ext4_li_info = NULL; - mutex_init(&ext4_li_mtx); - - /* Build-time check for flags consistency */ - ext4_check_flag_values(); - - for (i = 0; i < EXT4_WQ_HASH_SZ; i++) - init_waitqueue_head(&ext4__ioend_wq[i]); - - err = ext4_init_es(); - if (err) - return err; - - err = ext4_init_pageio(); - if (err) - goto out5; - - err = ext4_init_system_zone(); - if (err) - goto out4; - - err = ext4_init_sysfs(); - if (err) - goto out3; - - err = ext4_init_mballoc(); - if (err) - goto out2; - err = init_inodecache(); - if (err) - goto out1; - register_as_ext3(); - register_as_ext2(); - err = register_filesystem(&ext4_fs_type); - if (err) - goto out; - - return 0; -out: - unregister_as_ext2(); - unregister_as_ext3(); - destroy_inodecache(); -out1: - ext4_exit_mballoc(); -out2: - ext4_exit_sysfs(); -out3: - ext4_exit_system_zone(); -out4: - ext4_exit_pageio(); -out5: - ext4_exit_es(); - - return err; -} - -static void __exit ext4_exit_fs(void) -{ - ext4_destroy_lazyinit_thread(); - unregister_as_ext2(); - unregister_as_ext3(); - unregister_filesystem(&ext4_fs_type); - destroy_inodecache(); - ext4_exit_mballoc(); - ext4_exit_sysfs(); - ext4_exit_system_zone(); - ext4_exit_pageio(); - ext4_exit_es(); -} - -MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); -MODULE_DESCRIPTION("Fourth Extended Filesystem"); -MODULE_LICENSE("GPL"); -module_init(ext4_init_fs) -module_exit(ext4_exit_fs) diff --git a/src/linux/fs/ext4/symlink.c b/src/linux/fs/ext4/symlink.c deleted file mode 100644 index 557b3b0..0000000 --- a/src/linux/fs/ext4/symlink.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * linux/fs/ext4/symlink.c - * - * Only fast symlinks left here - the rest is done by generic code. AV, 1999 - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Laboratoire MASI - Institut Blaise Pascal - * Universite Pierre et Marie Curie (Paris VI) - * - * from - * - * linux/fs/minix/symlink.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * ext4 symlink handling code - */ - -#include -#include -#include "ext4.h" -#include "xattr.h" - -static const char *ext4_encrypted_get_link(struct dentry *dentry, - struct inode *inode, - struct delayed_call *done) -{ - struct page *cpage = NULL; - char *caddr, *paddr = NULL; - struct fscrypt_str cstr, pstr; - struct fscrypt_symlink_data *sd; - int res; - u32 max_size = inode->i_sb->s_blocksize; - - if (!dentry) - return ERR_PTR(-ECHILD); - - res = fscrypt_get_encryption_info(inode); - if (res) - return ERR_PTR(res); - - if (ext4_inode_is_fast_symlink(inode)) { - caddr = (char *) EXT4_I(inode)->i_data; - max_size = sizeof(EXT4_I(inode)->i_data); - } else { - cpage = read_mapping_page(inode->i_mapping, 0, NULL); - if (IS_ERR(cpage)) - return ERR_CAST(cpage); - caddr = page_address(cpage); - } - - /* Symlink is encrypted */ - sd = (struct fscrypt_symlink_data *)caddr; - cstr.name = sd->encrypted_path; - cstr.len = le16_to_cpu(sd->len); - if ((cstr.len + sizeof(struct fscrypt_symlink_data) - 1) > max_size) { - /* Symlink data on the disk is corrupted */ - res = -EFSCORRUPTED; - goto errout; - } - - res = fscrypt_fname_alloc_buffer(inode, cstr.len, &pstr); - if (res) - goto errout; - paddr = pstr.name; - - res = fscrypt_fname_disk_to_usr(inode, 0, 0, &cstr, &pstr); - if (res) - goto errout; - - /* Null-terminate the name */ - paddr[pstr.len] = '\0'; - if (cpage) - put_page(cpage); - set_delayed_call(done, kfree_link, paddr); - return paddr; -errout: - if (cpage) - put_page(cpage); - kfree(paddr); - return ERR_PTR(res); -} - -const struct inode_operations ext4_encrypted_symlink_inode_operations = { - .readlink = generic_readlink, - .get_link = ext4_encrypted_get_link, - .setattr = ext4_setattr, - .listxattr = ext4_listxattr, -}; - -const struct inode_operations ext4_symlink_inode_operations = { - .readlink = generic_readlink, - .get_link = page_get_link, - .setattr = ext4_setattr, - .listxattr = ext4_listxattr, -}; - -const struct inode_operations ext4_fast_symlink_inode_operations = { - .readlink = generic_readlink, - .get_link = simple_get_link, - .setattr = ext4_setattr, - .listxattr = ext4_listxattr, -}; diff --git a/src/linux/fs/ext4/sysfs.c b/src/linux/fs/ext4/sysfs.c deleted file mode 100644 index 42145be..0000000 --- a/src/linux/fs/ext4/sysfs.c +++ /dev/null @@ -1,451 +0,0 @@ -/* - * linux/fs/ext4/sysfs.c - * - * Copyright (C) 1992, 1993, 1994, 1995 - * Remy Card (card@masi.ibp.fr) - * Theodore Ts'o (tytso@mit.edu) - * - */ - -#include -#include -#include -#include - -#include "ext4.h" -#include "ext4_jbd2.h" - -typedef enum { - attr_noop, - attr_delayed_allocation_blocks, - attr_session_write_kbytes, - attr_lifetime_write_kbytes, - attr_reserved_clusters, - attr_inode_readahead, - attr_trigger_test_error, - attr_feature, - attr_pointer_ui, - attr_pointer_atomic, -} attr_id_t; - -typedef enum { - ptr_explicit, - ptr_ext4_sb_info_offset, - ptr_ext4_super_block_offset, -} attr_ptr_t; - -static const char *proc_dirname = "fs/ext4"; -static struct proc_dir_entry *ext4_proc_root; - -struct ext4_attr { - struct attribute attr; - short attr_id; - short attr_ptr; - union { - int offset; - void *explicit_ptr; - } u; -}; - -static ssize_t session_write_kbytes_show(struct ext4_attr *a, - struct ext4_sb_info *sbi, char *buf) -{ - struct super_block *sb = sbi->s_buddy_cache->i_sb; - - if (!sb->s_bdev->bd_part) - return snprintf(buf, PAGE_SIZE, "0\n"); - return snprintf(buf, PAGE_SIZE, "%lu\n", - (part_stat_read(sb->s_bdev->bd_part, sectors[1]) - - sbi->s_sectors_written_start) >> 1); -} - -static ssize_t lifetime_write_kbytes_show(struct ext4_attr *a, - struct ext4_sb_info *sbi, char *buf) -{ - struct super_block *sb = sbi->s_buddy_cache->i_sb; - - if (!sb->s_bdev->bd_part) - return snprintf(buf, PAGE_SIZE, "0\n"); - return snprintf(buf, PAGE_SIZE, "%llu\n", - (unsigned long long)(sbi->s_kbytes_written + - ((part_stat_read(sb->s_bdev->bd_part, sectors[1]) - - EXT4_SB(sb)->s_sectors_written_start) >> 1))); -} - -static ssize_t inode_readahead_blks_store(struct ext4_attr *a, - struct ext4_sb_info *sbi, - const char *buf, size_t count) -{ - unsigned long t; - int ret; - - ret = kstrtoul(skip_spaces(buf), 0, &t); - if (ret) - return ret; - - if (t && (!is_power_of_2(t) || t > 0x40000000)) - return -EINVAL; - - sbi->s_inode_readahead_blks = t; - return count; -} - -static ssize_t reserved_clusters_store(struct ext4_attr *a, - struct ext4_sb_info *sbi, - const char *buf, size_t count) -{ - unsigned long long val; - ext4_fsblk_t clusters = (ext4_blocks_count(sbi->s_es) >> - sbi->s_cluster_bits); - int ret; - - ret = kstrtoull(skip_spaces(buf), 0, &val); - if (!ret || val >= clusters) - return -EINVAL; - - atomic64_set(&sbi->s_resv_clusters, val); - return count; -} - -static ssize_t trigger_test_error(struct ext4_attr *a, - struct ext4_sb_info *sbi, - const char *buf, size_t count) -{ - int len = count; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (len && buf[len-1] == '\n') - len--; - - if (len) - ext4_error(sbi->s_sb, "%.*s", len, buf); - return count; -} - -#define EXT4_ATTR(_name,_mode,_id) \ -static struct ext4_attr ext4_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode }, \ - .attr_id = attr_##_id, \ -} - -#define EXT4_ATTR_FUNC(_name,_mode) EXT4_ATTR(_name,_mode,_name) - -#define EXT4_ATTR_FEATURE(_name) EXT4_ATTR(_name, 0444, feature) - -#define EXT4_ATTR_OFFSET(_name,_mode,_id,_struct,_elname) \ -static struct ext4_attr ext4_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode }, \ - .attr_id = attr_##_id, \ - .attr_ptr = ptr_##_struct##_offset, \ - .u = { \ - .offset = offsetof(struct _struct, _elname),\ - }, \ -} - -#define EXT4_RO_ATTR_ES_UI(_name,_elname) \ - EXT4_ATTR_OFFSET(_name, 0444, pointer_ui, ext4_super_block, _elname) - -#define EXT4_RW_ATTR_SBI_UI(_name,_elname) \ - EXT4_ATTR_OFFSET(_name, 0644, pointer_ui, ext4_sb_info, _elname) - -#define EXT4_ATTR_PTR(_name,_mode,_id,_ptr) \ -static struct ext4_attr ext4_attr_##_name = { \ - .attr = {.name = __stringify(_name), .mode = _mode }, \ - .attr_id = attr_##_id, \ - .attr_ptr = ptr_explicit, \ - .u = { \ - .explicit_ptr = _ptr, \ - }, \ -} - -#define ATTR_LIST(name) &ext4_attr_##name.attr - -EXT4_ATTR_FUNC(delayed_allocation_blocks, 0444); -EXT4_ATTR_FUNC(session_write_kbytes, 0444); -EXT4_ATTR_FUNC(lifetime_write_kbytes, 0444); -EXT4_ATTR_FUNC(reserved_clusters, 0644); - -EXT4_ATTR_OFFSET(inode_readahead_blks, 0644, inode_readahead, - ext4_sb_info, s_inode_readahead_blks); -EXT4_RW_ATTR_SBI_UI(inode_goal, s_inode_goal); -EXT4_RW_ATTR_SBI_UI(mb_stats, s_mb_stats); -EXT4_RW_ATTR_SBI_UI(mb_max_to_scan, s_mb_max_to_scan); -EXT4_RW_ATTR_SBI_UI(mb_min_to_scan, s_mb_min_to_scan); -EXT4_RW_ATTR_SBI_UI(mb_order2_req, s_mb_order2_reqs); -EXT4_RW_ATTR_SBI_UI(mb_stream_req, s_mb_stream_request); -EXT4_RW_ATTR_SBI_UI(mb_group_prealloc, s_mb_group_prealloc); -EXT4_RW_ATTR_SBI_UI(extent_max_zeroout_kb, s_extent_max_zeroout_kb); -EXT4_ATTR(trigger_fs_error, 0200, trigger_test_error); -EXT4_RW_ATTR_SBI_UI(err_ratelimit_interval_ms, s_err_ratelimit_state.interval); -EXT4_RW_ATTR_SBI_UI(err_ratelimit_burst, s_err_ratelimit_state.burst); -EXT4_RW_ATTR_SBI_UI(warning_ratelimit_interval_ms, s_warning_ratelimit_state.interval); -EXT4_RW_ATTR_SBI_UI(warning_ratelimit_burst, s_warning_ratelimit_state.burst); -EXT4_RW_ATTR_SBI_UI(msg_ratelimit_interval_ms, s_msg_ratelimit_state.interval); -EXT4_RW_ATTR_SBI_UI(msg_ratelimit_burst, s_msg_ratelimit_state.burst); -EXT4_RO_ATTR_ES_UI(errors_count, s_error_count); -EXT4_RO_ATTR_ES_UI(first_error_time, s_first_error_time); -EXT4_RO_ATTR_ES_UI(last_error_time, s_last_error_time); - -static unsigned int old_bump_val = 128; -EXT4_ATTR_PTR(max_writeback_mb_bump, 0444, pointer_ui, &old_bump_val); - -static struct attribute *ext4_attrs[] = { - ATTR_LIST(delayed_allocation_blocks), - ATTR_LIST(session_write_kbytes), - ATTR_LIST(lifetime_write_kbytes), - ATTR_LIST(reserved_clusters), - ATTR_LIST(inode_readahead_blks), - ATTR_LIST(inode_goal), - ATTR_LIST(mb_stats), - ATTR_LIST(mb_max_to_scan), - ATTR_LIST(mb_min_to_scan), - ATTR_LIST(mb_order2_req), - ATTR_LIST(mb_stream_req), - ATTR_LIST(mb_group_prealloc), - ATTR_LIST(max_writeback_mb_bump), - ATTR_LIST(extent_max_zeroout_kb), - ATTR_LIST(trigger_fs_error), - ATTR_LIST(err_ratelimit_interval_ms), - ATTR_LIST(err_ratelimit_burst), - ATTR_LIST(warning_ratelimit_interval_ms), - ATTR_LIST(warning_ratelimit_burst), - ATTR_LIST(msg_ratelimit_interval_ms), - ATTR_LIST(msg_ratelimit_burst), - ATTR_LIST(errors_count), - ATTR_LIST(first_error_time), - ATTR_LIST(last_error_time), - NULL, -}; - -/* Features this copy of ext4 supports */ -EXT4_ATTR_FEATURE(lazy_itable_init); -EXT4_ATTR_FEATURE(batched_discard); -EXT4_ATTR_FEATURE(meta_bg_resize); -#ifdef CONFIG_EXT4_FS_ENCRYPTION -EXT4_ATTR_FEATURE(encryption); -#endif -EXT4_ATTR_FEATURE(metadata_csum_seed); - -static struct attribute *ext4_feat_attrs[] = { - ATTR_LIST(lazy_itable_init), - ATTR_LIST(batched_discard), - ATTR_LIST(meta_bg_resize), -#ifdef CONFIG_EXT4_FS_ENCRYPTION - ATTR_LIST(encryption), -#endif - ATTR_LIST(metadata_csum_seed), - NULL, -}; - -static void *calc_ptr(struct ext4_attr *a, struct ext4_sb_info *sbi) -{ - switch (a->attr_ptr) { - case ptr_explicit: - return a->u.explicit_ptr; - case ptr_ext4_sb_info_offset: - return (void *) (((char *) sbi) + a->u.offset); - case ptr_ext4_super_block_offset: - return (void *) (((char *) sbi->s_es) + a->u.offset); - } - return NULL; -} - -static ssize_t ext4_attr_show(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info, - s_kobj); - struct ext4_attr *a = container_of(attr, struct ext4_attr, attr); - void *ptr = calc_ptr(a, sbi); - - switch (a->attr_id) { - case attr_delayed_allocation_blocks: - return snprintf(buf, PAGE_SIZE, "%llu\n", - (s64) EXT4_C2B(sbi, - percpu_counter_sum(&sbi->s_dirtyclusters_counter))); - case attr_session_write_kbytes: - return session_write_kbytes_show(a, sbi, buf); - case attr_lifetime_write_kbytes: - return lifetime_write_kbytes_show(a, sbi, buf); - case attr_reserved_clusters: - return snprintf(buf, PAGE_SIZE, "%llu\n", - (unsigned long long) - atomic64_read(&sbi->s_resv_clusters)); - case attr_inode_readahead: - case attr_pointer_ui: - if (!ptr) - return 0; - return snprintf(buf, PAGE_SIZE, "%u\n", - *((unsigned int *) ptr)); - case attr_pointer_atomic: - if (!ptr) - return 0; - return snprintf(buf, PAGE_SIZE, "%d\n", - atomic_read((atomic_t *) ptr)); - case attr_feature: - return snprintf(buf, PAGE_SIZE, "supported\n"); - } - - return 0; -} - -static ssize_t ext4_attr_store(struct kobject *kobj, - struct attribute *attr, - const char *buf, size_t len) -{ - struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info, - s_kobj); - struct ext4_attr *a = container_of(attr, struct ext4_attr, attr); - void *ptr = calc_ptr(a, sbi); - unsigned long t; - int ret; - - switch (a->attr_id) { - case attr_reserved_clusters: - return reserved_clusters_store(a, sbi, buf, len); - case attr_pointer_ui: - if (!ptr) - return 0; - ret = kstrtoul(skip_spaces(buf), 0, &t); - if (ret) - return ret; - *((unsigned int *) ptr) = t; - return len; - case attr_inode_readahead: - return inode_readahead_blks_store(a, sbi, buf, len); - case attr_trigger_test_error: - return trigger_test_error(a, sbi, buf, len); - } - return 0; -} - -static void ext4_sb_release(struct kobject *kobj) -{ - struct ext4_sb_info *sbi = container_of(kobj, struct ext4_sb_info, - s_kobj); - complete(&sbi->s_kobj_unregister); -} - -static const struct sysfs_ops ext4_attr_ops = { - .show = ext4_attr_show, - .store = ext4_attr_store, -}; - -static struct kobj_type ext4_sb_ktype = { - .default_attrs = ext4_attrs, - .sysfs_ops = &ext4_attr_ops, - .release = ext4_sb_release, -}; - -static struct kobj_type ext4_ktype = { - .sysfs_ops = &ext4_attr_ops, -}; - -static struct kset ext4_kset = { - .kobj = {.ktype = &ext4_ktype}, -}; - -static struct kobj_type ext4_feat_ktype = { - .default_attrs = ext4_feat_attrs, - .sysfs_ops = &ext4_attr_ops, -}; - -static struct kobject ext4_feat = { - .kset = &ext4_kset, -}; - -#define PROC_FILE_SHOW_DEFN(name) \ -static int name##_open(struct inode *inode, struct file *file) \ -{ \ - return single_open(file, ext4_seq_##name##_show, PDE_DATA(inode)); \ -} \ -\ -static const struct file_operations ext4_seq_##name##_fops = { \ - .open = name##_open, \ - .read = seq_read, \ - .llseek = seq_lseek, \ - .release = single_release, \ -} - -#define PROC_FILE_LIST(name) \ - { __stringify(name), &ext4_seq_##name##_fops } - -PROC_FILE_SHOW_DEFN(es_shrinker_info); -PROC_FILE_SHOW_DEFN(options); - -static struct ext4_proc_files { - const char *name; - const struct file_operations *fops; -} proc_files[] = { - PROC_FILE_LIST(options), - PROC_FILE_LIST(es_shrinker_info), - PROC_FILE_LIST(mb_groups), - { NULL, NULL }, -}; - -int ext4_register_sysfs(struct super_block *sb) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_proc_files *p; - int err; - - sbi->s_kobj.kset = &ext4_kset; - init_completion(&sbi->s_kobj_unregister); - err = kobject_init_and_add(&sbi->s_kobj, &ext4_sb_ktype, NULL, - "%s", sb->s_id); - if (err) - return err; - - if (ext4_proc_root) - sbi->s_proc = proc_mkdir(sb->s_id, ext4_proc_root); - - if (sbi->s_proc) { - for (p = proc_files; p->name; p++) - proc_create_data(p->name, S_IRUGO, sbi->s_proc, - p->fops, sb); - } - return 0; -} - -void ext4_unregister_sysfs(struct super_block *sb) -{ - struct ext4_sb_info *sbi = EXT4_SB(sb); - struct ext4_proc_files *p; - - if (sbi->s_proc) { - for (p = proc_files; p->name; p++) - remove_proc_entry(p->name, sbi->s_proc); - remove_proc_entry(sb->s_id, ext4_proc_root); - } - kobject_del(&sbi->s_kobj); -} - -int __init ext4_init_sysfs(void) -{ - int ret; - - kobject_set_name(&ext4_kset.kobj, "ext4"); - ext4_kset.kobj.parent = fs_kobj; - ret = kset_register(&ext4_kset); - if (ret) - return ret; - - ret = kobject_init_and_add(&ext4_feat, &ext4_feat_ktype, - NULL, "features"); - if (ret) - kset_unregister(&ext4_kset); - else - ext4_proc_root = proc_mkdir(proc_dirname, NULL); - return ret; -} - -void ext4_exit_sysfs(void) -{ - kobject_put(&ext4_feat); - kset_unregister(&ext4_kset); - remove_proc_entry(proc_dirname, NULL); - ext4_proc_root = NULL; -} - diff --git a/src/linux/fs/ext4/truncate.h b/src/linux/fs/ext4/truncate.h deleted file mode 100644 index c70d06a..0000000 --- a/src/linux/fs/ext4/truncate.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * linux/fs/ext4/truncate.h - * - * Common inline functions needed for truncate support - */ - -/* - * Truncate blocks that were not used by write. We have to truncate the - * pagecache as well so that corresponding buffers get properly unmapped. - */ -static inline void ext4_truncate_failed_write(struct inode *inode) -{ - down_write(&EXT4_I(inode)->i_mmap_sem); - truncate_inode_pages(inode->i_mapping, inode->i_size); - ext4_truncate(inode); - up_write(&EXT4_I(inode)->i_mmap_sem); -} - -/* - * Work out how many blocks we need to proceed with the next chunk of a - * truncate transaction. - */ -static inline unsigned long ext4_blocks_for_truncate(struct inode *inode) -{ - ext4_lblk_t needed; - - needed = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9); - - /* Give ourselves just enough room to cope with inodes in which - * i_blocks is corrupt: we've seen disk corruptions in the past - * which resulted in random data in an inode which looked enough - * like a regular file for ext4 to try to delete it. Things - * will go a bit crazy if that happens, but at least we should - * try not to panic the whole kernel. */ - if (needed < 2) - needed = 2; - - /* But we need to bound the transaction so we don't overflow the - * journal. */ - if (needed > EXT4_MAX_TRANS_DATA) - needed = EXT4_MAX_TRANS_DATA; - - return EXT4_DATA_TRANS_BLOCKS(inode->i_sb) + needed; -} - diff --git a/src/linux/fs/ext4/xattr.c b/src/linux/fs/ext4/xattr.c deleted file mode 100644 index d77be9e..0000000 --- a/src/linux/fs/ext4/xattr.c +++ /dev/null @@ -1,1807 +0,0 @@ -/* - * linux/fs/ext4/xattr.c - * - * Copyright (C) 2001-2003 Andreas Gruenbacher, - * - * Fix by Harrison Xing . - * Ext4 code with a lot of help from Eric Jarman . - * Extended attributes for symlinks and special files added per - * suggestion of Luka Renko . - * xattr consolidation Copyright (c) 2004 James Morris , - * Red Hat Inc. - * ea-in-inode support by Alex Tomas aka bzzz - * and Andreas Gruenbacher . - */ - -/* - * Extended attributes are stored directly in inodes (on file systems with - * inodes bigger than 128 bytes) and on additional disk blocks. The i_file_acl - * field contains the block number if an inode uses an additional block. All - * attributes must fit in the inode and one additional block. Blocks that - * contain the identical set of attributes may be shared among several inodes. - * Identical blocks are detected by keeping a cache of blocks that have - * recently been accessed. - * - * The attributes in inodes and on blocks have a different header; the entries - * are stored in the same format: - * - * +------------------+ - * | header | - * | entry 1 | | - * | entry 2 | | growing downwards - * | entry 3 | v - * | four null bytes | - * | . . . | - * | value 1 | ^ - * | value 3 | | growing upwards - * | value 2 | | - * +------------------+ - * - * The header is followed by multiple entry descriptors. In disk blocks, the - * entry descriptors are kept sorted. In inodes, they are unsorted. The - * attribute values are aligned to the end of the block in no specific order. - * - * Locking strategy - * ---------------- - * EXT4_I(inode)->i_file_acl is protected by EXT4_I(inode)->xattr_sem. - * EA blocks are only changed if they are exclusive to an inode, so - * holding xattr_sem also means that nothing but the EA block's reference - * count can change. Multiple writers to the same block are synchronized - * by the buffer lock. - */ - -#include -#include -#include -#include -#include -#include "ext4_jbd2.h" -#include "ext4.h" -#include "xattr.h" -#include "acl.h" - -#ifdef EXT4_XATTR_DEBUG -# define ea_idebug(inode, fmt, ...) \ - printk(KERN_DEBUG "inode %s:%lu: " fmt "\n", \ - inode->i_sb->s_id, inode->i_ino, ##__VA_ARGS__) -# define ea_bdebug(bh, fmt, ...) \ - printk(KERN_DEBUG "block %pg:%lu: " fmt "\n", \ - bh->b_bdev, (unsigned long)bh->b_blocknr, ##__VA_ARGS__) -#else -# define ea_idebug(inode, fmt, ...) no_printk(fmt, ##__VA_ARGS__) -# define ea_bdebug(bh, fmt, ...) no_printk(fmt, ##__VA_ARGS__) -#endif - -static void ext4_xattr_cache_insert(struct mb_cache *, struct buffer_head *); -static struct buffer_head *ext4_xattr_cache_find(struct inode *, - struct ext4_xattr_header *, - struct mb_cache_entry **); -static void ext4_xattr_rehash(struct ext4_xattr_header *, - struct ext4_xattr_entry *); -static int ext4_xattr_list(struct dentry *dentry, char *buffer, - size_t buffer_size); - -static const struct xattr_handler *ext4_xattr_handler_map[] = { - [EXT4_XATTR_INDEX_USER] = &ext4_xattr_user_handler, -#ifdef CONFIG_EXT4_FS_POSIX_ACL - [EXT4_XATTR_INDEX_POSIX_ACL_ACCESS] = &posix_acl_access_xattr_handler, - [EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT] = &posix_acl_default_xattr_handler, -#endif - [EXT4_XATTR_INDEX_TRUSTED] = &ext4_xattr_trusted_handler, -#ifdef CONFIG_EXT4_FS_SECURITY - [EXT4_XATTR_INDEX_SECURITY] = &ext4_xattr_security_handler, -#endif -}; - -const struct xattr_handler *ext4_xattr_handlers[] = { - &ext4_xattr_user_handler, - &ext4_xattr_trusted_handler, -#ifdef CONFIG_EXT4_FS_POSIX_ACL - &posix_acl_access_xattr_handler, - &posix_acl_default_xattr_handler, -#endif -#ifdef CONFIG_EXT4_FS_SECURITY - &ext4_xattr_security_handler, -#endif - NULL -}; - -#define EXT4_GET_MB_CACHE(inode) (((struct ext4_sb_info *) \ - inode->i_sb->s_fs_info)->s_mb_cache) - -static __le32 ext4_xattr_block_csum(struct inode *inode, - sector_t block_nr, - struct ext4_xattr_header *hdr) -{ - struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb); - __u32 csum; - __le64 dsk_block_nr = cpu_to_le64(block_nr); - __u32 dummy_csum = 0; - int offset = offsetof(struct ext4_xattr_header, h_checksum); - - csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&dsk_block_nr, - sizeof(dsk_block_nr)); - csum = ext4_chksum(sbi, csum, (__u8 *)hdr, offset); - csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum, sizeof(dummy_csum)); - offset += sizeof(dummy_csum); - csum = ext4_chksum(sbi, csum, (__u8 *)hdr + offset, - EXT4_BLOCK_SIZE(inode->i_sb) - offset); - - return cpu_to_le32(csum); -} - -static int ext4_xattr_block_csum_verify(struct inode *inode, - sector_t block_nr, - struct ext4_xattr_header *hdr) -{ - if (ext4_has_metadata_csum(inode->i_sb) && - (hdr->h_checksum != ext4_xattr_block_csum(inode, block_nr, hdr))) - return 0; - return 1; -} - -static void ext4_xattr_block_csum_set(struct inode *inode, - sector_t block_nr, - struct ext4_xattr_header *hdr) -{ - if (!ext4_has_metadata_csum(inode->i_sb)) - return; - - hdr->h_checksum = ext4_xattr_block_csum(inode, block_nr, hdr); -} - -static inline int ext4_handle_dirty_xattr_block(handle_t *handle, - struct inode *inode, - struct buffer_head *bh) -{ - ext4_xattr_block_csum_set(inode, bh->b_blocknr, BHDR(bh)); - return ext4_handle_dirty_metadata(handle, inode, bh); -} - -static inline const struct xattr_handler * -ext4_xattr_handler(int name_index) -{ - const struct xattr_handler *handler = NULL; - - if (name_index > 0 && name_index < ARRAY_SIZE(ext4_xattr_handler_map)) - handler = ext4_xattr_handler_map[name_index]; - return handler; -} - -/* - * Inode operation listxattr() - * - * d_inode(dentry)->i_mutex: don't care - */ -ssize_t -ext4_listxattr(struct dentry *dentry, char *buffer, size_t size) -{ - return ext4_xattr_list(dentry, buffer, size); -} - -static int -ext4_xattr_check_names(struct ext4_xattr_entry *entry, void *end, - void *value_start) -{ - struct ext4_xattr_entry *e = entry; - - while (!IS_LAST_ENTRY(e)) { - struct ext4_xattr_entry *next = EXT4_XATTR_NEXT(e); - if ((void *)next >= end) - return -EFSCORRUPTED; - e = next; - } - - while (!IS_LAST_ENTRY(entry)) { - if (entry->e_value_block != 0) - return -EFSCORRUPTED; - if (entry->e_value_size != 0 && - (value_start + le16_to_cpu(entry->e_value_offs) < - (void *)e + sizeof(__u32) || - value_start + le16_to_cpu(entry->e_value_offs) + - le32_to_cpu(entry->e_value_size) > end)) - return -EFSCORRUPTED; - entry = EXT4_XATTR_NEXT(entry); - } - - return 0; -} - -static inline int -ext4_xattr_check_block(struct inode *inode, struct buffer_head *bh) -{ - int error; - - if (buffer_verified(bh)) - return 0; - - if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) || - BHDR(bh)->h_blocks != cpu_to_le32(1)) - return -EFSCORRUPTED; - if (!ext4_xattr_block_csum_verify(inode, bh->b_blocknr, BHDR(bh))) - return -EFSBADCRC; - error = ext4_xattr_check_names(BFIRST(bh), bh->b_data + bh->b_size, - bh->b_data); - if (!error) - set_buffer_verified(bh); - return error; -} - -static int -__xattr_check_inode(struct inode *inode, struct ext4_xattr_ibody_header *header, - void *end, const char *function, unsigned int line) -{ - struct ext4_xattr_entry *entry = IFIRST(header); - int error = -EFSCORRUPTED; - - if (((void *) header >= end) || - (header->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC))) - goto errout; - error = ext4_xattr_check_names(entry, end, entry); -errout: - if (error) - __ext4_error_inode(inode, function, line, 0, - "corrupted in-inode xattr"); - return error; -} - -#define xattr_check_inode(inode, header, end) \ - __xattr_check_inode((inode), (header), (end), __func__, __LINE__) - -static inline int -ext4_xattr_check_entry(struct ext4_xattr_entry *entry, size_t size) -{ - size_t value_size = le32_to_cpu(entry->e_value_size); - - if (entry->e_value_block != 0 || value_size > size || - le16_to_cpu(entry->e_value_offs) + value_size > size) - return -EFSCORRUPTED; - return 0; -} - -static int -ext4_xattr_find_entry(struct ext4_xattr_entry **pentry, int name_index, - const char *name, size_t size, int sorted) -{ - struct ext4_xattr_entry *entry; - size_t name_len; - int cmp = 1; - - if (name == NULL) - return -EINVAL; - name_len = strlen(name); - entry = *pentry; - for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) { - cmp = name_index - entry->e_name_index; - if (!cmp) - cmp = name_len - entry->e_name_len; - if (!cmp) - cmp = memcmp(name, entry->e_name, name_len); - if (cmp <= 0 && (sorted || cmp == 0)) - break; - } - *pentry = entry; - if (!cmp && ext4_xattr_check_entry(entry, size)) - return -EFSCORRUPTED; - return cmp ? -ENODATA : 0; -} - -static int -ext4_xattr_block_get(struct inode *inode, int name_index, const char *name, - void *buffer, size_t buffer_size) -{ - struct buffer_head *bh = NULL; - struct ext4_xattr_entry *entry; - size_t size; - int error; - struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode); - - ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", - name_index, name, buffer, (long)buffer_size); - - error = -ENODATA; - if (!EXT4_I(inode)->i_file_acl) - goto cleanup; - ea_idebug(inode, "reading block %llu", - (unsigned long long)EXT4_I(inode)->i_file_acl); - bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl); - if (!bh) - goto cleanup; - ea_bdebug(bh, "b_count=%d, refcount=%d", - atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); - if (ext4_xattr_check_block(inode, bh)) { -bad_block: - EXT4_ERROR_INODE(inode, "bad block %llu", - EXT4_I(inode)->i_file_acl); - error = -EFSCORRUPTED; - goto cleanup; - } - ext4_xattr_cache_insert(ext4_mb_cache, bh); - entry = BFIRST(bh); - error = ext4_xattr_find_entry(&entry, name_index, name, bh->b_size, 1); - if (error == -EFSCORRUPTED) - goto bad_block; - if (error) - goto cleanup; - size = le32_to_cpu(entry->e_value_size); - if (buffer) { - error = -ERANGE; - if (size > buffer_size) - goto cleanup; - memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs), - size); - } - error = size; - -cleanup: - brelse(bh); - return error; -} - -int -ext4_xattr_ibody_get(struct inode *inode, int name_index, const char *name, - void *buffer, size_t buffer_size) -{ - struct ext4_xattr_ibody_header *header; - struct ext4_xattr_entry *entry; - struct ext4_inode *raw_inode; - struct ext4_iloc iloc; - size_t size; - void *end; - int error; - - if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR)) - return -ENODATA; - error = ext4_get_inode_loc(inode, &iloc); - if (error) - return error; - raw_inode = ext4_raw_inode(&iloc); - header = IHDR(inode, raw_inode); - entry = IFIRST(header); - end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; - error = xattr_check_inode(inode, header, end); - if (error) - goto cleanup; - error = ext4_xattr_find_entry(&entry, name_index, name, - end - (void *)entry, 0); - if (error) - goto cleanup; - size = le32_to_cpu(entry->e_value_size); - if (buffer) { - error = -ERANGE; - if (size > buffer_size) - goto cleanup; - memcpy(buffer, (void *)IFIRST(header) + - le16_to_cpu(entry->e_value_offs), size); - } - error = size; - -cleanup: - brelse(iloc.bh); - return error; -} - -/* - * ext4_xattr_get() - * - * Copy an extended attribute into the buffer - * provided, or compute the buffer size required. - * Buffer is NULL to compute the size of the buffer required. - * - * Returns a negative error number on failure, or the number of bytes - * used / required on success. - */ -int -ext4_xattr_get(struct inode *inode, int name_index, const char *name, - void *buffer, size_t buffer_size) -{ - int error; - - if (strlen(name) > 255) - return -ERANGE; - - down_read(&EXT4_I(inode)->xattr_sem); - error = ext4_xattr_ibody_get(inode, name_index, name, buffer, - buffer_size); - if (error == -ENODATA) - error = ext4_xattr_block_get(inode, name_index, name, buffer, - buffer_size); - up_read(&EXT4_I(inode)->xattr_sem); - return error; -} - -static int -ext4_xattr_list_entries(struct dentry *dentry, struct ext4_xattr_entry *entry, - char *buffer, size_t buffer_size) -{ - size_t rest = buffer_size; - - for (; !IS_LAST_ENTRY(entry); entry = EXT4_XATTR_NEXT(entry)) { - const struct xattr_handler *handler = - ext4_xattr_handler(entry->e_name_index); - - if (handler && (!handler->list || handler->list(dentry))) { - const char *prefix = handler->prefix ?: handler->name; - size_t prefix_len = strlen(prefix); - size_t size = prefix_len + entry->e_name_len + 1; - - if (buffer) { - if (size > rest) - return -ERANGE; - memcpy(buffer, prefix, prefix_len); - buffer += prefix_len; - memcpy(buffer, entry->e_name, entry->e_name_len); - buffer += entry->e_name_len; - *buffer++ = 0; - } - rest -= size; - } - } - return buffer_size - rest; /* total size */ -} - -static int -ext4_xattr_block_list(struct dentry *dentry, char *buffer, size_t buffer_size) -{ - struct inode *inode = d_inode(dentry); - struct buffer_head *bh = NULL; - int error; - struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode); - - ea_idebug(inode, "buffer=%p, buffer_size=%ld", - buffer, (long)buffer_size); - - error = 0; - if (!EXT4_I(inode)->i_file_acl) - goto cleanup; - ea_idebug(inode, "reading block %llu", - (unsigned long long)EXT4_I(inode)->i_file_acl); - bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl); - error = -EIO; - if (!bh) - goto cleanup; - ea_bdebug(bh, "b_count=%d, refcount=%d", - atomic_read(&(bh->b_count)), le32_to_cpu(BHDR(bh)->h_refcount)); - if (ext4_xattr_check_block(inode, bh)) { - EXT4_ERROR_INODE(inode, "bad block %llu", - EXT4_I(inode)->i_file_acl); - error = -EFSCORRUPTED; - goto cleanup; - } - ext4_xattr_cache_insert(ext4_mb_cache, bh); - error = ext4_xattr_list_entries(dentry, BFIRST(bh), buffer, buffer_size); - -cleanup: - brelse(bh); - - return error; -} - -static int -ext4_xattr_ibody_list(struct dentry *dentry, char *buffer, size_t buffer_size) -{ - struct inode *inode = d_inode(dentry); - struct ext4_xattr_ibody_header *header; - struct ext4_inode *raw_inode; - struct ext4_iloc iloc; - void *end; - int error; - - if (!ext4_test_inode_state(inode, EXT4_STATE_XATTR)) - return 0; - error = ext4_get_inode_loc(inode, &iloc); - if (error) - return error; - raw_inode = ext4_raw_inode(&iloc); - header = IHDR(inode, raw_inode); - end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; - error = xattr_check_inode(inode, header, end); - if (error) - goto cleanup; - error = ext4_xattr_list_entries(dentry, IFIRST(header), - buffer, buffer_size); - -cleanup: - brelse(iloc.bh); - return error; -} - -/* - * ext4_xattr_list() - * - * Copy a list of attribute names into the buffer - * provided, or compute the buffer size required. - * Buffer is NULL to compute the size of the buffer required. - * - * Returns a negative error number on failure, or the number of bytes - * used / required on success. - */ -static int -ext4_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size) -{ - int ret, ret2; - - down_read(&EXT4_I(d_inode(dentry))->xattr_sem); - ret = ret2 = ext4_xattr_ibody_list(dentry, buffer, buffer_size); - if (ret < 0) - goto errout; - if (buffer) { - buffer += ret; - buffer_size -= ret; - } - ret = ext4_xattr_block_list(dentry, buffer, buffer_size); - if (ret < 0) - goto errout; - ret += ret2; -errout: - up_read(&EXT4_I(d_inode(dentry))->xattr_sem); - return ret; -} - -/* - * If the EXT4_FEATURE_COMPAT_EXT_ATTR feature of this file system is - * not set, set it. - */ -static void ext4_xattr_update_super_block(handle_t *handle, - struct super_block *sb) -{ - if (ext4_has_feature_xattr(sb)) - return; - - BUFFER_TRACE(EXT4_SB(sb)->s_sbh, "get_write_access"); - if (ext4_journal_get_write_access(handle, EXT4_SB(sb)->s_sbh) == 0) { - ext4_set_feature_xattr(sb); - ext4_handle_dirty_super(handle, sb); - } -} - -/* - * Release the xattr block BH: If the reference count is > 1, decrement it; - * otherwise free the block. - */ -static void -ext4_xattr_release_block(handle_t *handle, struct inode *inode, - struct buffer_head *bh) -{ - struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode); - u32 hash, ref; - int error = 0; - - BUFFER_TRACE(bh, "get_write_access"); - error = ext4_journal_get_write_access(handle, bh); - if (error) - goto out; - - lock_buffer(bh); - hash = le32_to_cpu(BHDR(bh)->h_hash); - ref = le32_to_cpu(BHDR(bh)->h_refcount); - if (ref == 1) { - ea_bdebug(bh, "refcount now=0; freeing"); - /* - * This must happen under buffer lock for - * ext4_xattr_block_set() to reliably detect freed block - */ - mb_cache_entry_delete_block(ext4_mb_cache, hash, bh->b_blocknr); - get_bh(bh); - unlock_buffer(bh); - ext4_free_blocks(handle, inode, bh, 0, 1, - EXT4_FREE_BLOCKS_METADATA | - EXT4_FREE_BLOCKS_FORGET); - } else { - ref--; - BHDR(bh)->h_refcount = cpu_to_le32(ref); - if (ref == EXT4_XATTR_REFCOUNT_MAX - 1) { - struct mb_cache_entry *ce; - - ce = mb_cache_entry_get(ext4_mb_cache, hash, - bh->b_blocknr); - if (ce) { - ce->e_reusable = 1; - mb_cache_entry_put(ext4_mb_cache, ce); - } - } - - /* - * Beware of this ugliness: Releasing of xattr block references - * from different inodes can race and so we have to protect - * from a race where someone else frees the block (and releases - * its journal_head) before we are done dirtying the buffer. In - * nojournal mode this race is harmless and we actually cannot - * call ext4_handle_dirty_xattr_block() with locked buffer as - * that function can call sync_dirty_buffer() so for that case - * we handle the dirtying after unlocking the buffer. - */ - if (ext4_handle_valid(handle)) - error = ext4_handle_dirty_xattr_block(handle, inode, - bh); - unlock_buffer(bh); - if (!ext4_handle_valid(handle)) - error = ext4_handle_dirty_xattr_block(handle, inode, - bh); - if (IS_SYNC(inode)) - ext4_handle_sync(handle); - dquot_free_block(inode, EXT4_C2B(EXT4_SB(inode->i_sb), 1)); - ea_bdebug(bh, "refcount now=%d; releasing", - le32_to_cpu(BHDR(bh)->h_refcount)); - } -out: - ext4_std_error(inode->i_sb, error); - return; -} - -/* - * Find the available free space for EAs. This also returns the total number of - * bytes used by EA entries. - */ -static size_t ext4_xattr_free_space(struct ext4_xattr_entry *last, - size_t *min_offs, void *base, int *total) -{ - for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { - if (last->e_value_size) { - size_t offs = le16_to_cpu(last->e_value_offs); - if (offs < *min_offs) - *min_offs = offs; - } - if (total) - *total += EXT4_XATTR_LEN(last->e_name_len); - } - return (*min_offs - ((void *)last - base) - sizeof(__u32)); -} - -static int -ext4_xattr_set_entry(struct ext4_xattr_info *i, struct ext4_xattr_search *s) -{ - struct ext4_xattr_entry *last; - size_t free, min_offs = s->end - s->base, name_len = strlen(i->name); - - /* Compute min_offs and last. */ - last = s->first; - for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { - if (last->e_value_size) { - size_t offs = le16_to_cpu(last->e_value_offs); - if (offs < min_offs) - min_offs = offs; - } - } - free = min_offs - ((void *)last - s->base) - sizeof(__u32); - if (!s->not_found) { - if (s->here->e_value_size) { - size_t size = le32_to_cpu(s->here->e_value_size); - free += EXT4_XATTR_SIZE(size); - } - free += EXT4_XATTR_LEN(name_len); - } - if (i->value) { - if (free < EXT4_XATTR_LEN(name_len) + - EXT4_XATTR_SIZE(i->value_len)) - return -ENOSPC; - } - - if (i->value && s->not_found) { - /* Insert the new name. */ - size_t size = EXT4_XATTR_LEN(name_len); - size_t rest = (void *)last - (void *)s->here + sizeof(__u32); - memmove((void *)s->here + size, s->here, rest); - memset(s->here, 0, size); - s->here->e_name_index = i->name_index; - s->here->e_name_len = name_len; - memcpy(s->here->e_name, i->name, name_len); - } else { - if (s->here->e_value_size) { - void *first_val = s->base + min_offs; - size_t offs = le16_to_cpu(s->here->e_value_offs); - void *val = s->base + offs; - size_t size = EXT4_XATTR_SIZE( - le32_to_cpu(s->here->e_value_size)); - - if (i->value && size == EXT4_XATTR_SIZE(i->value_len)) { - /* The old and the new value have the same - size. Just replace. */ - s->here->e_value_size = - cpu_to_le32(i->value_len); - if (i->value == EXT4_ZERO_XATTR_VALUE) { - memset(val, 0, size); - } else { - /* Clear pad bytes first. */ - memset(val + size - EXT4_XATTR_PAD, 0, - EXT4_XATTR_PAD); - memcpy(val, i->value, i->value_len); - } - return 0; - } - - /* Remove the old value. */ - memmove(first_val + size, first_val, val - first_val); - memset(first_val, 0, size); - s->here->e_value_size = 0; - s->here->e_value_offs = 0; - min_offs += size; - - /* Adjust all value offsets. */ - last = s->first; - while (!IS_LAST_ENTRY(last)) { - size_t o = le16_to_cpu(last->e_value_offs); - if (last->e_value_size && o < offs) - last->e_value_offs = - cpu_to_le16(o + size); - last = EXT4_XATTR_NEXT(last); - } - } - if (!i->value) { - /* Remove the old name. */ - size_t size = EXT4_XATTR_LEN(name_len); - last = ENTRY((void *)last - size); - memmove(s->here, (void *)s->here + size, - (void *)last - (void *)s->here + sizeof(__u32)); - memset(last, 0, size); - } - } - - if (i->value) { - /* Insert the new value. */ - s->here->e_value_size = cpu_to_le32(i->value_len); - if (i->value_len) { - size_t size = EXT4_XATTR_SIZE(i->value_len); - void *val = s->base + min_offs - size; - s->here->e_value_offs = cpu_to_le16(min_offs - size); - if (i->value == EXT4_ZERO_XATTR_VALUE) { - memset(val, 0, size); - } else { - /* Clear the pad bytes first. */ - memset(val + size - EXT4_XATTR_PAD, 0, - EXT4_XATTR_PAD); - memcpy(val, i->value, i->value_len); - } - } - } - return 0; -} - -struct ext4_xattr_block_find { - struct ext4_xattr_search s; - struct buffer_head *bh; -}; - -static int -ext4_xattr_block_find(struct inode *inode, struct ext4_xattr_info *i, - struct ext4_xattr_block_find *bs) -{ - struct super_block *sb = inode->i_sb; - int error; - - ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", - i->name_index, i->name, i->value, (long)i->value_len); - - if (EXT4_I(inode)->i_file_acl) { - /* The inode already has an extended attribute block. */ - bs->bh = sb_bread(sb, EXT4_I(inode)->i_file_acl); - error = -EIO; - if (!bs->bh) - goto cleanup; - ea_bdebug(bs->bh, "b_count=%d, refcount=%d", - atomic_read(&(bs->bh->b_count)), - le32_to_cpu(BHDR(bs->bh)->h_refcount)); - if (ext4_xattr_check_block(inode, bs->bh)) { - EXT4_ERROR_INODE(inode, "bad block %llu", - EXT4_I(inode)->i_file_acl); - error = -EFSCORRUPTED; - goto cleanup; - } - /* Find the named attribute. */ - bs->s.base = BHDR(bs->bh); - bs->s.first = BFIRST(bs->bh); - bs->s.end = bs->bh->b_data + bs->bh->b_size; - bs->s.here = bs->s.first; - error = ext4_xattr_find_entry(&bs->s.here, i->name_index, - i->name, bs->bh->b_size, 1); - if (error && error != -ENODATA) - goto cleanup; - bs->s.not_found = error; - } - error = 0; - -cleanup: - return error; -} - -static int -ext4_xattr_block_set(handle_t *handle, struct inode *inode, - struct ext4_xattr_info *i, - struct ext4_xattr_block_find *bs) -{ - struct super_block *sb = inode->i_sb; - struct buffer_head *new_bh = NULL; - struct ext4_xattr_search *s = &bs->s; - struct mb_cache_entry *ce = NULL; - int error = 0; - struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode); - -#define header(x) ((struct ext4_xattr_header *)(x)) - - if (i->value && i->value_len > sb->s_blocksize) - return -ENOSPC; - if (s->base) { - BUFFER_TRACE(bs->bh, "get_write_access"); - error = ext4_journal_get_write_access(handle, bs->bh); - if (error) - goto cleanup; - lock_buffer(bs->bh); - - if (header(s->base)->h_refcount == cpu_to_le32(1)) { - __u32 hash = le32_to_cpu(BHDR(bs->bh)->h_hash); - - /* - * This must happen under buffer lock for - * ext4_xattr_block_set() to reliably detect modified - * block - */ - mb_cache_entry_delete_block(ext4_mb_cache, hash, - bs->bh->b_blocknr); - ea_bdebug(bs->bh, "modifying in-place"); - error = ext4_xattr_set_entry(i, s); - if (!error) { - if (!IS_LAST_ENTRY(s->first)) - ext4_xattr_rehash(header(s->base), - s->here); - ext4_xattr_cache_insert(ext4_mb_cache, - bs->bh); - } - unlock_buffer(bs->bh); - if (error == -EFSCORRUPTED) - goto bad_block; - if (!error) - error = ext4_handle_dirty_xattr_block(handle, - inode, - bs->bh); - if (error) - goto cleanup; - goto inserted; - } else { - int offset = (char *)s->here - bs->bh->b_data; - - unlock_buffer(bs->bh); - ea_bdebug(bs->bh, "cloning"); - s->base = kmalloc(bs->bh->b_size, GFP_NOFS); - error = -ENOMEM; - if (s->base == NULL) - goto cleanup; - memcpy(s->base, BHDR(bs->bh), bs->bh->b_size); - s->first = ENTRY(header(s->base)+1); - header(s->base)->h_refcount = cpu_to_le32(1); - s->here = ENTRY(s->base + offset); - s->end = s->base + bs->bh->b_size; - } - } else { - /* Allocate a buffer where we construct the new block. */ - s->base = kzalloc(sb->s_blocksize, GFP_NOFS); - /* assert(header == s->base) */ - error = -ENOMEM; - if (s->base == NULL) - goto cleanup; - header(s->base)->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC); - header(s->base)->h_blocks = cpu_to_le32(1); - header(s->base)->h_refcount = cpu_to_le32(1); - s->first = ENTRY(header(s->base)+1); - s->here = ENTRY(header(s->base)+1); - s->end = s->base + sb->s_blocksize; - } - - error = ext4_xattr_set_entry(i, s); - if (error == -EFSCORRUPTED) - goto bad_block; - if (error) - goto cleanup; - if (!IS_LAST_ENTRY(s->first)) - ext4_xattr_rehash(header(s->base), s->here); - -inserted: - if (!IS_LAST_ENTRY(s->first)) { - new_bh = ext4_xattr_cache_find(inode, header(s->base), &ce); - if (new_bh) { - /* We found an identical block in the cache. */ - if (new_bh == bs->bh) - ea_bdebug(new_bh, "keeping"); - else { - u32 ref; - - /* The old block is released after updating - the inode. */ - error = dquot_alloc_block(inode, - EXT4_C2B(EXT4_SB(sb), 1)); - if (error) - goto cleanup; - BUFFER_TRACE(new_bh, "get_write_access"); - error = ext4_journal_get_write_access(handle, - new_bh); - if (error) - goto cleanup_dquot; - lock_buffer(new_bh); - /* - * We have to be careful about races with - * freeing, rehashing or adding references to - * xattr block. Once we hold buffer lock xattr - * block's state is stable so we can check - * whether the block got freed / rehashed or - * not. Since we unhash mbcache entry under - * buffer lock when freeing / rehashing xattr - * block, checking whether entry is still - * hashed is reliable. Same rules hold for - * e_reusable handling. - */ - if (hlist_bl_unhashed(&ce->e_hash_list) || - !ce->e_reusable) { - /* - * Undo everything and check mbcache - * again. - */ - unlock_buffer(new_bh); - dquot_free_block(inode, - EXT4_C2B(EXT4_SB(sb), - 1)); - brelse(new_bh); - mb_cache_entry_put(ext4_mb_cache, ce); - ce = NULL; - new_bh = NULL; - goto inserted; - } - ref = le32_to_cpu(BHDR(new_bh)->h_refcount) + 1; - BHDR(new_bh)->h_refcount = cpu_to_le32(ref); - if (ref >= EXT4_XATTR_REFCOUNT_MAX) - ce->e_reusable = 0; - ea_bdebug(new_bh, "reusing; refcount now=%d", - ref); - unlock_buffer(new_bh); - error = ext4_handle_dirty_xattr_block(handle, - inode, - new_bh); - if (error) - goto cleanup_dquot; - } - mb_cache_entry_touch(ext4_mb_cache, ce); - mb_cache_entry_put(ext4_mb_cache, ce); - ce = NULL; - } else if (bs->bh && s->base == bs->bh->b_data) { - /* We were modifying this block in-place. */ - ea_bdebug(bs->bh, "keeping this block"); - new_bh = bs->bh; - get_bh(new_bh); - } else { - /* We need to allocate a new block */ - ext4_fsblk_t goal, block; - - goal = ext4_group_first_block_no(sb, - EXT4_I(inode)->i_block_group); - - /* non-extent files can't have physical blocks past 2^32 */ - if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) - goal = goal & EXT4_MAX_BLOCK_FILE_PHYS; - - block = ext4_new_meta_blocks(handle, inode, goal, 0, - NULL, &error); - if (error) - goto cleanup; - - if (!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS))) - BUG_ON(block > EXT4_MAX_BLOCK_FILE_PHYS); - - ea_idebug(inode, "creating block %llu", - (unsigned long long)block); - - new_bh = sb_getblk(sb, block); - if (unlikely(!new_bh)) { - error = -ENOMEM; -getblk_failed: - ext4_free_blocks(handle, inode, NULL, block, 1, - EXT4_FREE_BLOCKS_METADATA); - goto cleanup; - } - lock_buffer(new_bh); - error = ext4_journal_get_create_access(handle, new_bh); - if (error) { - unlock_buffer(new_bh); - error = -EIO; - goto getblk_failed; - } - memcpy(new_bh->b_data, s->base, new_bh->b_size); - set_buffer_uptodate(new_bh); - unlock_buffer(new_bh); - ext4_xattr_cache_insert(ext4_mb_cache, new_bh); - error = ext4_handle_dirty_xattr_block(handle, - inode, new_bh); - if (error) - goto cleanup; - } - } - - /* Update the inode. */ - EXT4_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0; - - /* Drop the previous xattr block. */ - if (bs->bh && bs->bh != new_bh) - ext4_xattr_release_block(handle, inode, bs->bh); - error = 0; - -cleanup: - if (ce) - mb_cache_entry_put(ext4_mb_cache, ce); - brelse(new_bh); - if (!(bs->bh && s->base == bs->bh->b_data)) - kfree(s->base); - - return error; - -cleanup_dquot: - dquot_free_block(inode, EXT4_C2B(EXT4_SB(sb), 1)); - goto cleanup; - -bad_block: - EXT4_ERROR_INODE(inode, "bad block %llu", - EXT4_I(inode)->i_file_acl); - goto cleanup; - -#undef header -} - -int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i, - struct ext4_xattr_ibody_find *is) -{ - struct ext4_xattr_ibody_header *header; - struct ext4_inode *raw_inode; - int error; - - if (EXT4_I(inode)->i_extra_isize == 0) - return 0; - raw_inode = ext4_raw_inode(&is->iloc); - header = IHDR(inode, raw_inode); - is->s.base = is->s.first = IFIRST(header); - is->s.here = is->s.first; - is->s.end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; - if (ext4_test_inode_state(inode, EXT4_STATE_XATTR)) { - error = xattr_check_inode(inode, header, is->s.end); - if (error) - return error; - /* Find the named attribute. */ - error = ext4_xattr_find_entry(&is->s.here, i->name_index, - i->name, is->s.end - - (void *)is->s.base, 0); - if (error && error != -ENODATA) - return error; - is->s.not_found = error; - } - return 0; -} - -int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode, - struct ext4_xattr_info *i, - struct ext4_xattr_ibody_find *is) -{ - struct ext4_xattr_ibody_header *header; - struct ext4_xattr_search *s = &is->s; - int error; - - if (EXT4_I(inode)->i_extra_isize == 0) - return -ENOSPC; - error = ext4_xattr_set_entry(i, s); - if (error) { - if (error == -ENOSPC && - ext4_has_inline_data(inode)) { - error = ext4_try_to_evict_inline_data(handle, inode, - EXT4_XATTR_LEN(strlen(i->name) + - EXT4_XATTR_SIZE(i->value_len))); - if (error) - return error; - error = ext4_xattr_ibody_find(inode, i, is); - if (error) - return error; - error = ext4_xattr_set_entry(i, s); - } - if (error) - return error; - } - header = IHDR(inode, ext4_raw_inode(&is->iloc)); - if (!IS_LAST_ENTRY(s->first)) { - header->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC); - ext4_set_inode_state(inode, EXT4_STATE_XATTR); - } else { - header->h_magic = cpu_to_le32(0); - ext4_clear_inode_state(inode, EXT4_STATE_XATTR); - } - return 0; -} - -static int ext4_xattr_ibody_set(handle_t *handle, struct inode *inode, - struct ext4_xattr_info *i, - struct ext4_xattr_ibody_find *is) -{ - struct ext4_xattr_ibody_header *header; - struct ext4_xattr_search *s = &is->s; - int error; - - if (EXT4_I(inode)->i_extra_isize == 0) - return -ENOSPC; - error = ext4_xattr_set_entry(i, s); - if (error) - return error; - header = IHDR(inode, ext4_raw_inode(&is->iloc)); - if (!IS_LAST_ENTRY(s->first)) { - header->h_magic = cpu_to_le32(EXT4_XATTR_MAGIC); - ext4_set_inode_state(inode, EXT4_STATE_XATTR); - } else { - header->h_magic = cpu_to_le32(0); - ext4_clear_inode_state(inode, EXT4_STATE_XATTR); - } - return 0; -} - -static int ext4_xattr_value_same(struct ext4_xattr_search *s, - struct ext4_xattr_info *i) -{ - void *value; - - if (le32_to_cpu(s->here->e_value_size) != i->value_len) - return 0; - value = ((void *)s->base) + le16_to_cpu(s->here->e_value_offs); - return !memcmp(value, i->value, i->value_len); -} - -/* - * ext4_xattr_set_handle() - * - * Create, replace or remove an extended attribute for this inode. Value - * is NULL to remove an existing extended attribute, and non-NULL to - * either replace an existing extended attribute, or create a new extended - * attribute. The flags XATTR_REPLACE and XATTR_CREATE - * specify that an extended attribute must exist and must not exist - * previous to the call, respectively. - * - * Returns 0, or a negative error number on failure. - */ -int -ext4_xattr_set_handle(handle_t *handle, struct inode *inode, int name_index, - const char *name, const void *value, size_t value_len, - int flags) -{ - struct ext4_xattr_info i = { - .name_index = name_index, - .name = name, - .value = value, - .value_len = value_len, - - }; - struct ext4_xattr_ibody_find is = { - .s = { .not_found = -ENODATA, }, - }; - struct ext4_xattr_block_find bs = { - .s = { .not_found = -ENODATA, }, - }; - unsigned long no_expand; - int error; - - if (!name) - return -EINVAL; - if (strlen(name) > 255) - return -ERANGE; - down_write(&EXT4_I(inode)->xattr_sem); - no_expand = ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND); - ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND); - - error = ext4_reserve_inode_write(handle, inode, &is.iloc); - if (error) - goto cleanup; - - if (ext4_test_inode_state(inode, EXT4_STATE_NEW)) { - struct ext4_inode *raw_inode = ext4_raw_inode(&is.iloc); - memset(raw_inode, 0, EXT4_SB(inode->i_sb)->s_inode_size); - ext4_clear_inode_state(inode, EXT4_STATE_NEW); - } - - error = ext4_xattr_ibody_find(inode, &i, &is); - if (error) - goto cleanup; - if (is.s.not_found) - error = ext4_xattr_block_find(inode, &i, &bs); - if (error) - goto cleanup; - if (is.s.not_found && bs.s.not_found) { - error = -ENODATA; - if (flags & XATTR_REPLACE) - goto cleanup; - error = 0; - if (!value) - goto cleanup; - } else { - error = -EEXIST; - if (flags & XATTR_CREATE) - goto cleanup; - } - if (!value) { - if (!is.s.not_found) - error = ext4_xattr_ibody_set(handle, inode, &i, &is); - else if (!bs.s.not_found) - error = ext4_xattr_block_set(handle, inode, &i, &bs); - } else { - error = 0; - /* Xattr value did not change? Save us some work and bail out */ - if (!is.s.not_found && ext4_xattr_value_same(&is.s, &i)) - goto cleanup; - if (!bs.s.not_found && ext4_xattr_value_same(&bs.s, &i)) - goto cleanup; - - error = ext4_xattr_ibody_set(handle, inode, &i, &is); - if (!error && !bs.s.not_found) { - i.value = NULL; - error = ext4_xattr_block_set(handle, inode, &i, &bs); - } else if (error == -ENOSPC) { - if (EXT4_I(inode)->i_file_acl && !bs.s.base) { - error = ext4_xattr_block_find(inode, &i, &bs); - if (error) - goto cleanup; - } - error = ext4_xattr_block_set(handle, inode, &i, &bs); - if (error) - goto cleanup; - if (!is.s.not_found) { - i.value = NULL; - error = ext4_xattr_ibody_set(handle, inode, &i, - &is); - } - } - } - if (!error) { - ext4_xattr_update_super_block(handle, inode->i_sb); - inode->i_ctime = ext4_current_time(inode); - if (!value) - ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND); - error = ext4_mark_iloc_dirty(handle, inode, &is.iloc); - /* - * The bh is consumed by ext4_mark_iloc_dirty, even with - * error != 0. - */ - is.iloc.bh = NULL; - if (IS_SYNC(inode)) - ext4_handle_sync(handle); - } - -cleanup: - brelse(is.iloc.bh); - brelse(bs.bh); - if (no_expand == 0) - ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND); - up_write(&EXT4_I(inode)->xattr_sem); - return error; -} - -/* - * ext4_xattr_set() - * - * Like ext4_xattr_set_handle, but start from an inode. This extended - * attribute modification is a filesystem transaction by itself. - * - * Returns 0, or a negative error number on failure. - */ -int -ext4_xattr_set(struct inode *inode, int name_index, const char *name, - const void *value, size_t value_len, int flags) -{ - handle_t *handle; - int error, retries = 0; - int credits = ext4_jbd2_credits_xattr(inode); - -retry: - handle = ext4_journal_start(inode, EXT4_HT_XATTR, credits); - if (IS_ERR(handle)) { - error = PTR_ERR(handle); - } else { - int error2; - - error = ext4_xattr_set_handle(handle, inode, name_index, name, - value, value_len, flags); - error2 = ext4_journal_stop(handle); - if (error == -ENOSPC && - ext4_should_retry_alloc(inode->i_sb, &retries)) - goto retry; - if (error == 0) - error = error2; - } - - return error; -} - -/* - * Shift the EA entries in the inode to create space for the increased - * i_extra_isize. - */ -static void ext4_xattr_shift_entries(struct ext4_xattr_entry *entry, - int value_offs_shift, void *to, - void *from, size_t n) -{ - struct ext4_xattr_entry *last = entry; - int new_offs; - - /* We always shift xattr headers further thus offsets get lower */ - BUG_ON(value_offs_shift > 0); - - /* Adjust the value offsets of the entries */ - for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { - if (last->e_value_size) { - new_offs = le16_to_cpu(last->e_value_offs) + - value_offs_shift; - last->e_value_offs = cpu_to_le16(new_offs); - } - } - /* Shift the entries by n bytes */ - memmove(to, from, n); -} - -/* - * Move xattr pointed to by 'entry' from inode into external xattr block - */ -static int ext4_xattr_move_to_block(handle_t *handle, struct inode *inode, - struct ext4_inode *raw_inode, - struct ext4_xattr_entry *entry) -{ - struct ext4_xattr_ibody_find *is = NULL; - struct ext4_xattr_block_find *bs = NULL; - char *buffer = NULL, *b_entry_name = NULL; - size_t value_offs, value_size; - struct ext4_xattr_info i = { - .value = NULL, - .value_len = 0, - .name_index = entry->e_name_index, - }; - struct ext4_xattr_ibody_header *header = IHDR(inode, raw_inode); - int error; - - value_offs = le16_to_cpu(entry->e_value_offs); - value_size = le32_to_cpu(entry->e_value_size); - - is = kzalloc(sizeof(struct ext4_xattr_ibody_find), GFP_NOFS); - bs = kzalloc(sizeof(struct ext4_xattr_block_find), GFP_NOFS); - buffer = kmalloc(value_size, GFP_NOFS); - b_entry_name = kmalloc(entry->e_name_len + 1, GFP_NOFS); - if (!is || !bs || !buffer || !b_entry_name) { - error = -ENOMEM; - goto out; - } - - is->s.not_found = -ENODATA; - bs->s.not_found = -ENODATA; - is->iloc.bh = NULL; - bs->bh = NULL; - - /* Save the entry name and the entry value */ - memcpy(buffer, (void *)IFIRST(header) + value_offs, value_size); - memcpy(b_entry_name, entry->e_name, entry->e_name_len); - b_entry_name[entry->e_name_len] = '\0'; - i.name = b_entry_name; - - error = ext4_get_inode_loc(inode, &is->iloc); - if (error) - goto out; - - error = ext4_xattr_ibody_find(inode, &i, is); - if (error) - goto out; - - /* Remove the chosen entry from the inode */ - error = ext4_xattr_ibody_set(handle, inode, &i, is); - if (error) - goto out; - - i.name = b_entry_name; - i.value = buffer; - i.value_len = value_size; - error = ext4_xattr_block_find(inode, &i, bs); - if (error) - goto out; - - /* Add entry which was removed from the inode into the block */ - error = ext4_xattr_block_set(handle, inode, &i, bs); - if (error) - goto out; - error = 0; -out: - kfree(b_entry_name); - kfree(buffer); - if (is) - brelse(is->iloc.bh); - kfree(is); - kfree(bs); - - return error; -} - -static int ext4_xattr_make_inode_space(handle_t *handle, struct inode *inode, - struct ext4_inode *raw_inode, - int isize_diff, size_t ifree, - size_t bfree, int *total_ino) -{ - struct ext4_xattr_ibody_header *header = IHDR(inode, raw_inode); - struct ext4_xattr_entry *small_entry; - struct ext4_xattr_entry *entry; - struct ext4_xattr_entry *last; - unsigned int entry_size; /* EA entry size */ - unsigned int total_size; /* EA entry size + value size */ - unsigned int min_total_size; - int error; - - while (isize_diff > ifree) { - entry = NULL; - small_entry = NULL; - min_total_size = ~0U; - last = IFIRST(header); - /* Find the entry best suited to be pushed into EA block */ - for (; !IS_LAST_ENTRY(last); last = EXT4_XATTR_NEXT(last)) { - total_size = - EXT4_XATTR_SIZE(le32_to_cpu(last->e_value_size)) + - EXT4_XATTR_LEN(last->e_name_len); - if (total_size <= bfree && - total_size < min_total_size) { - if (total_size + ifree < isize_diff) { - small_entry = last; - } else { - entry = last; - min_total_size = total_size; - } - } - } - - if (entry == NULL) { - if (small_entry == NULL) - return -ENOSPC; - entry = small_entry; - } - - entry_size = EXT4_XATTR_LEN(entry->e_name_len); - total_size = entry_size + - EXT4_XATTR_SIZE(le32_to_cpu(entry->e_value_size)); - error = ext4_xattr_move_to_block(handle, inode, raw_inode, - entry); - if (error) - return error; - - *total_ino -= entry_size; - ifree += total_size; - bfree -= total_size; - } - - return 0; -} - -/* - * Expand an inode by new_extra_isize bytes when EAs are present. - * Returns 0 on success or negative error number on failure. - */ -int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, - struct ext4_inode *raw_inode, handle_t *handle) -{ - struct ext4_xattr_ibody_header *header; - struct buffer_head *bh = NULL; - size_t min_offs; - size_t ifree, bfree; - int total_ino; - void *base, *end; - int error = 0, tried_min_extra_isize = 0; - int s_min_extra_isize = le16_to_cpu(EXT4_SB(inode->i_sb)->s_es->s_min_extra_isize); - int isize_diff; /* How much do we need to grow i_extra_isize */ - - down_write(&EXT4_I(inode)->xattr_sem); - /* - * Set EXT4_STATE_NO_EXPAND to avoid recursion when marking inode dirty - */ - ext4_set_inode_state(inode, EXT4_STATE_NO_EXPAND); -retry: - isize_diff = new_extra_isize - EXT4_I(inode)->i_extra_isize; - if (EXT4_I(inode)->i_extra_isize >= new_extra_isize) - goto out; - - header = IHDR(inode, raw_inode); - - /* - * Check if enough free space is available in the inode to shift the - * entries ahead by new_extra_isize. - */ - - base = IFIRST(header); - end = (void *)raw_inode + EXT4_SB(inode->i_sb)->s_inode_size; - min_offs = end - base; - total_ino = sizeof(struct ext4_xattr_ibody_header); - - error = xattr_check_inode(inode, header, end); - if (error) - goto cleanup; - - ifree = ext4_xattr_free_space(base, &min_offs, base, &total_ino); - if (ifree >= isize_diff) - goto shift; - - /* - * Enough free space isn't available in the inode, check if - * EA block can hold new_extra_isize bytes. - */ - if (EXT4_I(inode)->i_file_acl) { - bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl); - error = -EIO; - if (!bh) - goto cleanup; - if (ext4_xattr_check_block(inode, bh)) { - EXT4_ERROR_INODE(inode, "bad block %llu", - EXT4_I(inode)->i_file_acl); - error = -EFSCORRUPTED; - goto cleanup; - } - base = BHDR(bh); - end = bh->b_data + bh->b_size; - min_offs = end - base; - bfree = ext4_xattr_free_space(BFIRST(bh), &min_offs, base, - NULL); - if (bfree + ifree < isize_diff) { - if (!tried_min_extra_isize && s_min_extra_isize) { - tried_min_extra_isize++; - new_extra_isize = s_min_extra_isize; - brelse(bh); - goto retry; - } - error = -ENOSPC; - goto cleanup; - } - } else { - bfree = inode->i_sb->s_blocksize; - } - - error = ext4_xattr_make_inode_space(handle, inode, raw_inode, - isize_diff, ifree, bfree, - &total_ino); - if (error) { - if (error == -ENOSPC && !tried_min_extra_isize && - s_min_extra_isize) { - tried_min_extra_isize++; - new_extra_isize = s_min_extra_isize; - brelse(bh); - goto retry; - } - goto cleanup; - } -shift: - /* Adjust the offsets and shift the remaining entries ahead */ - ext4_xattr_shift_entries(IFIRST(header), EXT4_I(inode)->i_extra_isize - - new_extra_isize, (void *)raw_inode + - EXT4_GOOD_OLD_INODE_SIZE + new_extra_isize, - (void *)header, total_ino); - EXT4_I(inode)->i_extra_isize = new_extra_isize; - brelse(bh); -out: - ext4_clear_inode_state(inode, EXT4_STATE_NO_EXPAND); - up_write(&EXT4_I(inode)->xattr_sem); - return 0; - -cleanup: - brelse(bh); - /* - * We deliberately leave EXT4_STATE_NO_EXPAND set here since inode - * size expansion failed. - */ - up_write(&EXT4_I(inode)->xattr_sem); - return error; -} - - - -/* - * ext4_xattr_delete_inode() - * - * Free extended attribute resources associated with this inode. This - * is called immediately before an inode is freed. We have exclusive - * access to the inode. - */ -void -ext4_xattr_delete_inode(handle_t *handle, struct inode *inode) -{ - struct buffer_head *bh = NULL; - - if (!EXT4_I(inode)->i_file_acl) - goto cleanup; - bh = sb_bread(inode->i_sb, EXT4_I(inode)->i_file_acl); - if (!bh) { - EXT4_ERROR_INODE(inode, "block %llu read error", - EXT4_I(inode)->i_file_acl); - goto cleanup; - } - if (BHDR(bh)->h_magic != cpu_to_le32(EXT4_XATTR_MAGIC) || - BHDR(bh)->h_blocks != cpu_to_le32(1)) { - EXT4_ERROR_INODE(inode, "bad block %llu", - EXT4_I(inode)->i_file_acl); - goto cleanup; - } - ext4_xattr_release_block(handle, inode, bh); - EXT4_I(inode)->i_file_acl = 0; - -cleanup: - brelse(bh); -} - -/* - * ext4_xattr_cache_insert() - * - * Create a new entry in the extended attribute cache, and insert - * it unless such an entry is already in the cache. - * - * Returns 0, or a negative error number on failure. - */ -static void -ext4_xattr_cache_insert(struct mb_cache *ext4_mb_cache, struct buffer_head *bh) -{ - struct ext4_xattr_header *header = BHDR(bh); - __u32 hash = le32_to_cpu(header->h_hash); - int reusable = le32_to_cpu(header->h_refcount) < - EXT4_XATTR_REFCOUNT_MAX; - int error; - - error = mb_cache_entry_create(ext4_mb_cache, GFP_NOFS, hash, - bh->b_blocknr, reusable); - if (error) { - if (error == -EBUSY) - ea_bdebug(bh, "already in cache"); - } else - ea_bdebug(bh, "inserting [%x]", (int)hash); -} - -/* - * ext4_xattr_cmp() - * - * Compare two extended attribute blocks for equality. - * - * Returns 0 if the blocks are equal, 1 if they differ, and - * a negative error number on errors. - */ -static int -ext4_xattr_cmp(struct ext4_xattr_header *header1, - struct ext4_xattr_header *header2) -{ - struct ext4_xattr_entry *entry1, *entry2; - - entry1 = ENTRY(header1+1); - entry2 = ENTRY(header2+1); - while (!IS_LAST_ENTRY(entry1)) { - if (IS_LAST_ENTRY(entry2)) - return 1; - if (entry1->e_hash != entry2->e_hash || - entry1->e_name_index != entry2->e_name_index || - entry1->e_name_len != entry2->e_name_len || - entry1->e_value_size != entry2->e_value_size || - memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len)) - return 1; - if (entry1->e_value_block != 0 || entry2->e_value_block != 0) - return -EFSCORRUPTED; - if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs), - (char *)header2 + le16_to_cpu(entry2->e_value_offs), - le32_to_cpu(entry1->e_value_size))) - return 1; - - entry1 = EXT4_XATTR_NEXT(entry1); - entry2 = EXT4_XATTR_NEXT(entry2); - } - if (!IS_LAST_ENTRY(entry2)) - return 1; - return 0; -} - -/* - * ext4_xattr_cache_find() - * - * Find an identical extended attribute block. - * - * Returns a pointer to the block found, or NULL if such a block was - * not found or an error occurred. - */ -static struct buffer_head * -ext4_xattr_cache_find(struct inode *inode, struct ext4_xattr_header *header, - struct mb_cache_entry **pce) -{ - __u32 hash = le32_to_cpu(header->h_hash); - struct mb_cache_entry *ce; - struct mb_cache *ext4_mb_cache = EXT4_GET_MB_CACHE(inode); - - if (!header->h_hash) - return NULL; /* never share */ - ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); - ce = mb_cache_entry_find_first(ext4_mb_cache, hash); - while (ce) { - struct buffer_head *bh; - - bh = sb_bread(inode->i_sb, ce->e_block); - if (!bh) { - EXT4_ERROR_INODE(inode, "block %lu read error", - (unsigned long) ce->e_block); - } else if (ext4_xattr_cmp(header, BHDR(bh)) == 0) { - *pce = ce; - return bh; - } - brelse(bh); - ce = mb_cache_entry_find_next(ext4_mb_cache, ce); - } - return NULL; -} - -#define NAME_HASH_SHIFT 5 -#define VALUE_HASH_SHIFT 16 - -/* - * ext4_xattr_hash_entry() - * - * Compute the hash of an extended attribute. - */ -static inline void ext4_xattr_hash_entry(struct ext4_xattr_header *header, - struct ext4_xattr_entry *entry) -{ - __u32 hash = 0; - char *name = entry->e_name; - int n; - - for (n = 0; n < entry->e_name_len; n++) { - hash = (hash << NAME_HASH_SHIFT) ^ - (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^ - *name++; - } - - if (entry->e_value_size != 0) { - __le32 *value = (__le32 *)((char *)header + - le16_to_cpu(entry->e_value_offs)); - for (n = (le32_to_cpu(entry->e_value_size) + - EXT4_XATTR_ROUND) >> EXT4_XATTR_PAD_BITS; n; n--) { - hash = (hash << VALUE_HASH_SHIFT) ^ - (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^ - le32_to_cpu(*value++); - } - } - entry->e_hash = cpu_to_le32(hash); -} - -#undef NAME_HASH_SHIFT -#undef VALUE_HASH_SHIFT - -#define BLOCK_HASH_SHIFT 16 - -/* - * ext4_xattr_rehash() - * - * Re-compute the extended attribute hash value after an entry has changed. - */ -static void ext4_xattr_rehash(struct ext4_xattr_header *header, - struct ext4_xattr_entry *entry) -{ - struct ext4_xattr_entry *here; - __u32 hash = 0; - - ext4_xattr_hash_entry(header, entry); - here = ENTRY(header+1); - while (!IS_LAST_ENTRY(here)) { - if (!here->e_hash) { - /* Block is not shared if an entry's hash value == 0 */ - hash = 0; - break; - } - hash = (hash << BLOCK_HASH_SHIFT) ^ - (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^ - le32_to_cpu(here->e_hash); - here = EXT4_XATTR_NEXT(here); - } - header->h_hash = cpu_to_le32(hash); -} - -#undef BLOCK_HASH_SHIFT - -#define HASH_BUCKET_BITS 10 - -struct mb_cache * -ext4_xattr_create_cache(void) -{ - return mb_cache_create(HASH_BUCKET_BITS); -} - -void ext4_xattr_destroy_cache(struct mb_cache *cache) -{ - if (cache) - mb_cache_destroy(cache); -} - diff --git a/src/linux/fs/ext4/xattr.h b/src/linux/fs/ext4/xattr.h deleted file mode 100644 index a92e783..0000000 --- a/src/linux/fs/ext4/xattr.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - File: fs/ext4/xattr.h - - On-disk format of extended attributes for the ext4 filesystem. - - (C) 2001 Andreas Gruenbacher, -*/ - -#include - -/* Magic value in attribute blocks */ -#define EXT4_XATTR_MAGIC 0xEA020000 - -/* Maximum number of references to one attribute block */ -#define EXT4_XATTR_REFCOUNT_MAX 1024 - -/* Name indexes */ -#define EXT4_XATTR_INDEX_USER 1 -#define EXT4_XATTR_INDEX_POSIX_ACL_ACCESS 2 -#define EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT 3 -#define EXT4_XATTR_INDEX_TRUSTED 4 -#define EXT4_XATTR_INDEX_LUSTRE 5 -#define EXT4_XATTR_INDEX_SECURITY 6 -#define EXT4_XATTR_INDEX_SYSTEM 7 -#define EXT4_XATTR_INDEX_RICHACL 8 -#define EXT4_XATTR_INDEX_ENCRYPTION 9 -#define EXT4_XATTR_INDEX_HURD 10 /* Reserved for Hurd */ - -struct ext4_xattr_header { - __le32 h_magic; /* magic number for identification */ - __le32 h_refcount; /* reference count */ - __le32 h_blocks; /* number of disk blocks used */ - __le32 h_hash; /* hash value of all attributes */ - __le32 h_checksum; /* crc32c(uuid+id+xattrblock) */ - /* id = inum if refcount=1, blknum otherwise */ - __u32 h_reserved[3]; /* zero right now */ -}; - -struct ext4_xattr_ibody_header { - __le32 h_magic; /* magic number for identification */ -}; - -struct ext4_xattr_entry { - __u8 e_name_len; /* length of name */ - __u8 e_name_index; /* attribute name index */ - __le16 e_value_offs; /* offset in disk block of value */ - __le32 e_value_block; /* disk block attribute is stored on (n/i) */ - __le32 e_value_size; /* size of attribute value */ - __le32 e_hash; /* hash value of name and value */ - char e_name[0]; /* attribute name */ -}; - -#define EXT4_XATTR_PAD_BITS 2 -#define EXT4_XATTR_PAD (1<e_name_len))) -#define EXT4_XATTR_SIZE(size) \ - (((size) + EXT4_XATTR_ROUND) & ~EXT4_XATTR_ROUND) - -#define IHDR(inode, raw_inode) \ - ((struct ext4_xattr_ibody_header *) \ - ((void *)raw_inode + \ - EXT4_GOOD_OLD_INODE_SIZE + \ - EXT4_I(inode)->i_extra_isize)) -#define IFIRST(hdr) ((struct ext4_xattr_entry *)((hdr)+1)) - -#define BHDR(bh) ((struct ext4_xattr_header *)((bh)->b_data)) -#define ENTRY(ptr) ((struct ext4_xattr_entry *)(ptr)) -#define BFIRST(bh) ENTRY(BHDR(bh)+1) -#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) - -#define EXT4_ZERO_XATTR_VALUE ((void *)-1) - -struct ext4_xattr_info { - int name_index; - const char *name; - const void *value; - size_t value_len; -}; - -struct ext4_xattr_search { - struct ext4_xattr_entry *first; - void *base; - void *end; - struct ext4_xattr_entry *here; - int not_found; -}; - -struct ext4_xattr_ibody_find { - struct ext4_xattr_search s; - struct ext4_iloc iloc; -}; - -extern const struct xattr_handler ext4_xattr_user_handler; -extern const struct xattr_handler ext4_xattr_trusted_handler; -extern const struct xattr_handler ext4_xattr_security_handler; - -#define EXT4_XATTR_NAME_ENCRYPTION_CONTEXT "c" - -extern ssize_t ext4_listxattr(struct dentry *, char *, size_t); - -extern int ext4_xattr_get(struct inode *, int, const char *, void *, size_t); -extern int ext4_xattr_set(struct inode *, int, const char *, const void *, size_t, int); -extern int ext4_xattr_set_handle(handle_t *, struct inode *, int, const char *, const void *, size_t, int); - -extern void ext4_xattr_delete_inode(handle_t *, struct inode *); - -extern int ext4_expand_extra_isize_ea(struct inode *inode, int new_extra_isize, - struct ext4_inode *raw_inode, handle_t *handle); - -extern const struct xattr_handler *ext4_xattr_handlers[]; - -extern int ext4_xattr_ibody_find(struct inode *inode, struct ext4_xattr_info *i, - struct ext4_xattr_ibody_find *is); -extern int ext4_xattr_ibody_get(struct inode *inode, int name_index, - const char *name, - void *buffer, size_t buffer_size); -extern int ext4_xattr_ibody_inline_set(handle_t *handle, struct inode *inode, - struct ext4_xattr_info *i, - struct ext4_xattr_ibody_find *is); - -extern struct mb_cache *ext4_xattr_create_cache(void); -extern void ext4_xattr_destroy_cache(struct mb_cache *); - -#ifdef CONFIG_EXT4_FS_SECURITY -extern int ext4_init_security(handle_t *handle, struct inode *inode, - struct inode *dir, const struct qstr *qstr); -#else -static inline int ext4_init_security(handle_t *handle, struct inode *inode, - struct inode *dir, const struct qstr *qstr) -{ - return 0; -} -#endif diff --git a/src/linux/fs/ext4/xattr_security.c b/src/linux/fs/ext4/xattr_security.c deleted file mode 100644 index a892111..0000000 --- a/src/linux/fs/ext4/xattr_security.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * linux/fs/ext4/xattr_security.c - * Handler for storing security labels as extended attributes. - */ - -#include -#include -#include -#include -#include "ext4_jbd2.h" -#include "ext4.h" -#include "xattr.h" - -static int -ext4_xattr_security_get(const struct xattr_handler *handler, - struct dentry *unused, struct inode *inode, - const char *name, void *buffer, size_t size) -{ - return ext4_xattr_get(inode, EXT4_XATTR_INDEX_SECURITY, - name, buffer, size); -} - -static int -ext4_xattr_security_set(const struct xattr_handler *handler, - struct dentry *unused, struct inode *inode, - const char *name, const void *value, - size_t size, int flags) -{ - return ext4_xattr_set(inode, EXT4_XATTR_INDEX_SECURITY, - name, value, size, flags); -} - -static int -ext4_initxattrs(struct inode *inode, const struct xattr *xattr_array, - void *fs_info) -{ - const struct xattr *xattr; - handle_t *handle = fs_info; - int err = 0; - - for (xattr = xattr_array; xattr->name != NULL; xattr++) { - err = ext4_xattr_set_handle(handle, inode, - EXT4_XATTR_INDEX_SECURITY, - xattr->name, xattr->value, - xattr->value_len, 0); - if (err < 0) - break; - } - return err; -} - -int -ext4_init_security(handle_t *handle, struct inode *inode, struct inode *dir, - const struct qstr *qstr) -{ - return security_inode_init_security(inode, dir, qstr, - &ext4_initxattrs, handle); -} - -const struct xattr_handler ext4_xattr_security_handler = { - .prefix = XATTR_SECURITY_PREFIX, - .get = ext4_xattr_security_get, - .set = ext4_xattr_security_set, -}; diff --git a/src/linux/fs/ext4/xattr_trusted.c b/src/linux/fs/ext4/xattr_trusted.c deleted file mode 100644 index c7765c7..0000000 --- a/src/linux/fs/ext4/xattr_trusted.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - * linux/fs/ext4/xattr_trusted.c - * Handler for trusted extended attributes. - * - * Copyright (C) 2003 by Andreas Gruenbacher, - */ - -#include -#include -#include -#include "ext4_jbd2.h" -#include "ext4.h" -#include "xattr.h" - -static bool -ext4_xattr_trusted_list(struct dentry *dentry) -{ - return capable(CAP_SYS_ADMIN); -} - -static int -ext4_xattr_trusted_get(const struct xattr_handler *handler, - struct dentry *unused, struct inode *inode, - const char *name, void *buffer, size_t size) -{ - return ext4_xattr_get(inode, EXT4_XATTR_INDEX_TRUSTED, - name, buffer, size); -} - -static int -ext4_xattr_trusted_set(const struct xattr_handler *handler, - struct dentry *unused, struct inode *inode, - const char *name, const void *value, - size_t size, int flags) -{ - return ext4_xattr_set(inode, EXT4_XATTR_INDEX_TRUSTED, - name, value, size, flags); -} - -const struct xattr_handler ext4_xattr_trusted_handler = { - .prefix = XATTR_TRUSTED_PREFIX, - .list = ext4_xattr_trusted_list, - .get = ext4_xattr_trusted_get, - .set = ext4_xattr_trusted_set, -}; diff --git a/src/linux/fs/ext4/xattr_user.c b/src/linux/fs/ext4/xattr_user.c deleted file mode 100644 index ca20e42..0000000 --- a/src/linux/fs/ext4/xattr_user.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * linux/fs/ext4/xattr_user.c - * Handler for extended user attributes. - * - * Copyright (C) 2001 by Andreas Gruenbacher, - */ - -#include -#include -#include "ext4_jbd2.h" -#include "ext4.h" -#include "xattr.h" - -static bool -ext4_xattr_user_list(struct dentry *dentry) -{ - return test_opt(dentry->d_sb, XATTR_USER); -} - -static int -ext4_xattr_user_get(const struct xattr_handler *handler, - struct dentry *unused, struct inode *inode, - const char *name, void *buffer, size_t size) -{ - if (!test_opt(inode->i_sb, XATTR_USER)) - return -EOPNOTSUPP; - return ext4_xattr_get(inode, EXT4_XATTR_INDEX_USER, - name, buffer, size); -} - -static int -ext4_xattr_user_set(const struct xattr_handler *handler, - struct dentry *unused, struct inode *inode, - const char *name, const void *value, - size_t size, int flags) -{ - if (!test_opt(inode->i_sb, XATTR_USER)) - return -EOPNOTSUPP; - return ext4_xattr_set(inode, EXT4_XATTR_INDEX_USER, - name, value, size, flags); -} - -const struct xattr_handler ext4_xattr_user_handler = { - .prefix = XATTR_USER_PREFIX, - .list = ext4_xattr_user_list, - .get = ext4_xattr_user_get, - .set = ext4_xattr_user_set, -}; diff --git a/src/linux/fs/f2fs/Kconfig b/src/linux/fs/f2fs/Kconfig deleted file mode 100644 index 378c221..0000000 --- a/src/linux/fs/f2fs/Kconfig +++ /dev/null @@ -1,104 +0,0 @@ -config F2FS_FS - tristate "F2FS filesystem support" - depends on BLOCK - select CRYPTO - select CRYPTO_CRC32 - help - F2FS is based on Log-structured File System (LFS), which supports - versatile "flash-friendly" features. The design has been focused on - addressing the fundamental issues in LFS, which are snowball effect - of wandering tree and high cleaning overhead. - - Since flash-based storages show different characteristics according to - the internal geometry or flash memory management schemes aka FTL, F2FS - and tools support various parameters not only for configuring on-disk - layout, but also for selecting allocation and cleaning algorithms. - - If unsure, say N. - -config F2FS_STAT_FS - bool "F2FS Status Information" - depends on F2FS_FS && DEBUG_FS - default y - help - /sys/kernel/debug/f2fs/ contains information about all the partitions - mounted as f2fs. Each file shows the whole f2fs information. - - /sys/kernel/debug/f2fs/status includes: - - major filesystem information managed by f2fs currently - - average SIT information about whole segments - - current memory footprint consumed by f2fs. - -config F2FS_FS_XATTR - bool "F2FS extended attributes" - depends on F2FS_FS - default y - help - Extended attributes are name:value pairs associated with inodes by - the kernel or by users (see the attr(5) manual page, or visit - for details). - - If unsure, say N. - -config F2FS_FS_POSIX_ACL - bool "F2FS Access Control Lists" - depends on F2FS_FS_XATTR - select FS_POSIX_ACL - default y - help - Posix Access Control Lists (ACLs) support permissions for users and - groups beyond the owner/group/world scheme. - - To learn more about Access Control Lists, visit the POSIX ACLs for - Linux website . - - If you don't know what Access Control Lists are, say N - -config F2FS_FS_SECURITY - bool "F2FS Security Labels" - depends on F2FS_FS_XATTR - help - Security labels provide an access control facility to support Linux - Security Models (LSMs) accepted by AppArmor, SELinux, Smack and TOMOYO - Linux. This option enables an extended attribute handler for file - security labels in the f2fs filesystem, so that it requires enabling - the extended attribute support in advance. - - If you are not using a security module, say N. - -config F2FS_CHECK_FS - bool "F2FS consistency checking feature" - depends on F2FS_FS - help - Enables BUG_ONs which check the filesystem consistency in runtime. - - If you want to improve the performance, say N. - -config F2FS_FS_ENCRYPTION - bool "F2FS Encryption" - depends on F2FS_FS - depends on F2FS_FS_XATTR - select FS_ENCRYPTION - help - Enable encryption of f2fs files and directories. This - feature is similar to ecryptfs, but it is more memory - efficient since it avoids caching the encrypted and - decrypted pages in the page cache. - -config F2FS_IO_TRACE - bool "F2FS IO tracer" - depends on F2FS_FS - depends on FUNCTION_TRACER - help - F2FS IO trace is based on a function trace, which gathers process - information and block IO patterns in the filesystem level. - - If unsure, say N. - -config F2FS_FAULT_INJECTION - bool "F2FS fault injection facility" - depends on F2FS_FS - help - Test F2FS to inject faults such as ENOMEM, ENOSPC, and so on. - - If unsure, say N. diff --git a/src/linux/fs/fat/Kconfig b/src/linux/fs/fat/Kconfig deleted file mode 100644 index 3ff1772..0000000 --- a/src/linux/fs/fat/Kconfig +++ /dev/null @@ -1,116 +0,0 @@ -config FAT_FS - tristate - select NLS - help - If you want to use one of the FAT-based file systems (the MS-DOS and - VFAT (Windows 95) file systems), then you must say Y or M here - to include FAT support. You will then be able to mount partitions or - diskettes with FAT-based file systems and transparently access the - files on them, i.e. MSDOS files will look and behave just like all - other Unix files. - - This FAT support is not a file system in itself, it only provides - the foundation for the other file systems. You will have to say Y or - M to at least one of "MSDOS fs support" or "VFAT fs support" in - order to make use of it. - - Another way to read and write MSDOS floppies and hard drive - partitions from within Linux (but not transparently) is with the - mtools ("man mtools") program suite. You don't need to say Y here in - order to do that. - - If you need to move large files on floppies between a DOS and a - Linux box, say Y here, mount the floppy under Linux with an MSDOS - file system and use GNU tar's M option. GNU tar is a program - available for Unix and DOS ("man tar" or "info tar"). - - The FAT support will enlarge your kernel by about 37 KB. If unsure, - say Y. - - To compile this as a module, choose M here: the module will be called - fat. Note that if you compile the FAT support as a module, you - cannot compile any of the FAT-based file systems into the kernel - -- they will have to be modules as well. - -config MSDOS_FS - tristate "MSDOS fs support" - select FAT_FS - help - This allows you to mount MSDOS partitions of your hard drive (unless - they are compressed; to access compressed MSDOS partitions under - Linux, you can either use the DOS emulator DOSEMU, described in the - DOSEMU-HOWTO, available from - , or try dmsdosfs in - . If you - intend to use dosemu with a non-compressed MSDOS partition, say Y - here) and MSDOS floppies. This means that file access becomes - transparent, i.e. the MSDOS files look and behave just like all - other Unix files. - - If you have Windows 95 or Windows NT installed on your MSDOS - partitions, you should use the VFAT file system (say Y to "VFAT fs - support" below), or you will not be able to see the long filenames - generated by Windows 95 / Windows NT. - - This option will enlarge your kernel by about 7 KB. If unsure, - answer Y. This will only work if you said Y to "DOS FAT fs support" - as well. To compile this as a module, choose M here: the module will - be called msdos. - -config VFAT_FS - tristate "VFAT (Windows-95) fs support" - select FAT_FS - help - This option provides support for normal Windows file systems with - long filenames. That includes non-compressed FAT-based file systems - used by Windows 95, Windows 98, Windows NT 4.0, and the Unix - programs from the mtools package. - - The VFAT support enlarges your kernel by about 10 KB and it only - works if you said Y to the "DOS FAT fs support" above. Please read - the file for details. If - unsure, say Y. - - To compile this as a module, choose M here: the module will be called - vfat. - -config FAT_DEFAULT_CODEPAGE - int "Default codepage for FAT" - depends on MSDOS_FS || VFAT_FS - default 437 - help - This option should be set to the codepage of your FAT filesystems. - It can be overridden with the "codepage" mount option. - See for more information. - -config FAT_DEFAULT_IOCHARSET - string "Default iocharset for FAT" - depends on VFAT_FS - default "iso8859-1" - help - Set this to the default input/output character set you'd - like FAT to use. It should probably match the character set - that most of your FAT filesystems use, and can be overridden - with the "iocharset" mount option for FAT filesystems. - Note that "utf8" is not recommended for FAT filesystems. - If unsure, you shouldn't set "utf8" here - select the next option - instead if you would like to use UTF-8 encoded file names by default. - See for more information. - - Enable any character sets you need in File Systems/Native Language - Support. - -config FAT_DEFAULT_UTF8 - bool "Enable FAT UTF-8 option by default" - depends on VFAT_FS - default n - help - Set this if you would like to have "utf8" mount option set - by default when mounting FAT filesystems. - - Even if you say Y here can always disable UTF-8 for - particular mount by adding "utf8=0" to mount options. - - Say Y if you use UTF-8 encoding for file names, N otherwise. - - See for more information. diff --git a/src/linux/fs/fat/Makefile b/src/linux/fs/fat/Makefile deleted file mode 100644 index 964b634..0000000 --- a/src/linux/fs/fat/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile for the Linux fat filesystem support. -# - -obj-$(CONFIG_FAT_FS) += fat.o -obj-$(CONFIG_VFAT_FS) += vfat.o -obj-$(CONFIG_MSDOS_FS) += msdos.o - -fat-y := cache.o dir.o fatent.o file.o inode.o misc.o nfs.o -vfat-y := namei_vfat.o -msdos-y := namei_msdos.o diff --git a/src/linux/fs/fat/cache.c b/src/linux/fs/fat/cache.c deleted file mode 100644 index 5d38492..0000000 --- a/src/linux/fs/fat/cache.c +++ /dev/null @@ -1,380 +0,0 @@ -/* - * 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. - */ - -#include -#include "fat.h" - -/* this must be > 0. */ -#define FAT_MAX_CACHE 8 - -struct fat_cache { - struct list_head cache_list; - int nr_contig; /* number of contiguous clusters */ - int fcluster; /* cluster number in the file. */ - int dcluster; /* cluster number on disk. */ -}; - -struct fat_cache_id { - unsigned int id; - int nr_contig; - int fcluster; - int dcluster; -}; - -static inline int fat_max_cache(struct inode *inode) -{ - return FAT_MAX_CACHE; -} - -static struct kmem_cache *fat_cache_cachep; - -static void init_once(void *foo) -{ - struct fat_cache *cache = (struct fat_cache *)foo; - - INIT_LIST_HEAD(&cache->cache_list); -} - -int __init fat_cache_init(void) -{ - fat_cache_cachep = kmem_cache_create("fat_cache", - sizeof(struct fat_cache), - 0, SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, - init_once); - if (fat_cache_cachep == NULL) - return -ENOMEM; - return 0; -} - -void fat_cache_destroy(void) -{ - kmem_cache_destroy(fat_cache_cachep); -} - -static inline struct fat_cache *fat_cache_alloc(struct inode *inode) -{ - return kmem_cache_alloc(fat_cache_cachep, GFP_NOFS); -} - -static inline void fat_cache_free(struct fat_cache *cache) -{ - BUG_ON(!list_empty(&cache->cache_list)); - kmem_cache_free(fat_cache_cachep, cache); -} - -static inline void fat_cache_update_lru(struct inode *inode, - struct fat_cache *cache) -{ - if (MSDOS_I(inode)->cache_lru.next != &cache->cache_list) - list_move(&cache->cache_list, &MSDOS_I(inode)->cache_lru); -} - -static int fat_cache_lookup(struct inode *inode, int fclus, - struct fat_cache_id *cid, - int *cached_fclus, int *cached_dclus) -{ - static struct fat_cache nohit = { .fcluster = 0, }; - - struct fat_cache *hit = &nohit, *p; - int offset = -1; - - spin_lock(&MSDOS_I(inode)->cache_lru_lock); - list_for_each_entry(p, &MSDOS_I(inode)->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) { - fat_cache_update_lru(inode, hit); - - cid->id = MSDOS_I(inode)->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(&MSDOS_I(inode)->cache_lru_lock); - - return offset; -} - -static struct fat_cache *fat_cache_merge(struct inode *inode, - struct fat_cache_id *new) -{ - struct fat_cache *p; - - list_for_each_entry(p, &MSDOS_I(inode)->cache_lru, cache_list) { - /* Find the same part as "new" in cluster-chain. */ - if (p->fcluster == new->fcluster) { - BUG_ON(p->dcluster != new->dcluster); - if (new->nr_contig > p->nr_contig) - p->nr_contig = new->nr_contig; - return p; - } - } - return NULL; -} - -static void fat_cache_add(struct inode *inode, struct fat_cache_id *new) -{ - struct fat_cache *cache, *tmp; - - if (new->fcluster == -1) /* dummy cache */ - return; - - spin_lock(&MSDOS_I(inode)->cache_lru_lock); - if (new->id != FAT_CACHE_VALID && - new->id != MSDOS_I(inode)->cache_valid_id) - goto out; /* this cache was invalidated */ - - cache = fat_cache_merge(inode, new); - if (cache == NULL) { - if (MSDOS_I(inode)->nr_caches < fat_max_cache(inode)) { - MSDOS_I(inode)->nr_caches++; - spin_unlock(&MSDOS_I(inode)->cache_lru_lock); - - tmp = fat_cache_alloc(inode); - if (!tmp) { - spin_lock(&MSDOS_I(inode)->cache_lru_lock); - MSDOS_I(inode)->nr_caches--; - spin_unlock(&MSDOS_I(inode)->cache_lru_lock); - return; - } - - spin_lock(&MSDOS_I(inode)->cache_lru_lock); - cache = fat_cache_merge(inode, new); - if (cache != NULL) { - MSDOS_I(inode)->nr_caches--; - fat_cache_free(tmp); - goto out_update_lru; - } - cache = tmp; - } else { - struct list_head *p = MSDOS_I(inode)->cache_lru.prev; - cache = list_entry(p, struct fat_cache, cache_list); - } - cache->fcluster = new->fcluster; - cache->dcluster = new->dcluster; - cache->nr_contig = new->nr_contig; - } -out_update_lru: - fat_cache_update_lru(inode, cache); -out: - spin_unlock(&MSDOS_I(inode)->cache_lru_lock); -} - -/* - * Cache invalidation occurs rarely, thus the LRU chain is not updated. It - * fixes itself after a while. - */ -static void __fat_cache_inval_inode(struct inode *inode) -{ - struct msdos_inode_info *i = MSDOS_I(inode); - struct fat_cache *cache; - - while (!list_empty(&i->cache_lru)) { - cache = list_entry(i->cache_lru.next, - struct fat_cache, cache_list); - list_del_init(&cache->cache_list); - i->nr_caches--; - fat_cache_free(cache); - } - /* Update. The copy of caches before this id is discarded. */ - i->cache_valid_id++; - if (i->cache_valid_id == FAT_CACHE_VALID) - i->cache_valid_id++; -} - -void fat_cache_inval_inode(struct inode *inode) -{ - spin_lock(&MSDOS_I(inode)->cache_lru_lock); - __fat_cache_inval_inode(inode); - spin_unlock(&MSDOS_I(inode)->cache_lru_lock); -} - -static inline int cache_contiguous(struct fat_cache_id *cid, int dclus) -{ - cid->nr_contig++; - return ((cid->dcluster + cid->nr_contig) == dclus); -} - -static inline void cache_init(struct fat_cache_id *cid, int fclus, int dclus) -{ - cid->id = FAT_CACHE_VALID; - cid->fcluster = fclus; - cid->dcluster = dclus; - cid->nr_contig = 0; -} - -int fat_get_cluster(struct inode *inode, int cluster, int *fclus, int *dclus) -{ - struct super_block *sb = inode->i_sb; - const int limit = sb->s_maxbytes >> MSDOS_SB(sb)->cluster_bits; - struct fat_entry fatent; - struct fat_cache_id cid; - int nr; - - BUG_ON(MSDOS_I(inode)->i_start == 0); - - *fclus = 0; - *dclus = MSDOS_I(inode)->i_start; - if (cluster == 0) - return 0; - - if (fat_cache_lookup(inode, cluster, &cid, fclus, dclus) < 0) { - /* - * dummy, always not contiguous - * This is reinitialized by cache_init(), later. - */ - cache_init(&cid, -1, -1); - } - - fatent_init(&fatent); - while (*fclus < cluster) { - /* prevent the infinite loop of cluster chain */ - if (*fclus > limit) { - fat_fs_error_ratelimit(sb, - "%s: detected the cluster chain loop" - " (i_pos %lld)", __func__, - MSDOS_I(inode)->i_pos); - nr = -EIO; - goto out; - } - - nr = fat_ent_read(inode, &fatent, *dclus); - if (nr < 0) - goto out; - else if (nr == FAT_ENT_FREE) { - fat_fs_error_ratelimit(sb, - "%s: invalid cluster chain (i_pos %lld)", - __func__, - MSDOS_I(inode)->i_pos); - nr = -EIO; - goto out; - } else if (nr == FAT_ENT_EOF) { - fat_cache_add(inode, &cid); - goto out; - } - (*fclus)++; - *dclus = nr; - if (!cache_contiguous(&cid, *dclus)) - cache_init(&cid, *fclus, *dclus); - } - nr = 0; - fat_cache_add(inode, &cid); -out: - fatent_brelse(&fatent); - return nr; -} - -static int fat_bmap_cluster(struct inode *inode, int cluster) -{ - struct super_block *sb = inode->i_sb; - int ret, fclus, dclus; - - if (MSDOS_I(inode)->i_start == 0) - return 0; - - ret = fat_get_cluster(inode, cluster, &fclus, &dclus); - if (ret < 0) - return ret; - else if (ret == FAT_ENT_EOF) { - fat_fs_error(sb, "%s: request beyond EOF (i_pos %lld)", - __func__, MSDOS_I(inode)->i_pos); - return -EIO; - } - return dclus; -} - -int fat_get_mapped_cluster(struct inode *inode, sector_t sector, - sector_t last_block, - unsigned long *mapped_blocks, sector_t *bmap) -{ - struct super_block *sb = inode->i_sb; - struct msdos_sb_info *sbi = MSDOS_SB(sb); - int cluster, offset; - - cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits); - offset = sector & (sbi->sec_per_clus - 1); - cluster = fat_bmap_cluster(inode, cluster); - if (cluster < 0) - return cluster; - else if (cluster) { - *bmap = fat_clus_to_blknr(sbi, cluster) + offset; - *mapped_blocks = sbi->sec_per_clus - offset; - if (*mapped_blocks > last_block - sector) - *mapped_blocks = last_block - sector; - } - - return 0; -} - -static int is_exceed_eof(struct inode *inode, sector_t sector, - sector_t *last_block, int create) -{ - struct super_block *sb = inode->i_sb; - const unsigned long blocksize = sb->s_blocksize; - const unsigned char blocksize_bits = sb->s_blocksize_bits; - - *last_block = (i_size_read(inode) + (blocksize - 1)) >> blocksize_bits; - if (sector >= *last_block) { - if (!create) - return 1; - - /* - * ->mmu_private can access on only allocation path. - * (caller must hold ->i_mutex) - */ - *last_block = (MSDOS_I(inode)->mmu_private + (blocksize - 1)) - >> blocksize_bits; - if (sector >= *last_block) - return 1; - } - - return 0; -} - -int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys, - unsigned long *mapped_blocks, int create, bool from_bmap) -{ - struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); - sector_t last_block; - - *phys = 0; - *mapped_blocks = 0; - if ((sbi->fat_bits != 32) && (inode->i_ino == MSDOS_ROOT_INO)) { - if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits)) { - *phys = sector + sbi->dir_start; - *mapped_blocks = 1; - } - return 0; - } - - if (!from_bmap) { - if (is_exceed_eof(inode, sector, &last_block, create)) - return 0; - } else { - last_block = inode->i_blocks >> - (inode->i_sb->s_blocksize_bits - 9); - if (sector >= last_block) - return 0; - } - - return fat_get_mapped_cluster(inode, sector, last_block, mapped_blocks, - phys); -} diff --git a/src/linux/fs/fat/dir.c b/src/linux/fs/fat/dir.c deleted file mode 100644 index 81cecbe..0000000 --- a/src/linux/fs/fat/dir.c +++ /dev/null @@ -1,1408 +0,0 @@ -/* - * linux/fs/fat/dir.c - * - * directory handling functions for fat-based filesystems - * - * Written 1992,1993 by Werner Almesberger - * - * Hidden files 1995 by Albert Cahalan - * - * VFAT extensions by Gordon Chaffee - * Merged with msdos fs by Henrik Storner - * Rewritten for constant inumbers. Plugged buffer overrun in readdir(). AV - * Short name translation 1999, 2001 by Wolfram Pienkoss - */ - -#include -#include -#include -#include "fat.h" - -/* - * Maximum buffer size of short name. - * [(MSDOS_NAME + '.') * max one char + nul] - * For msdos style, ['.' (hidden) + MSDOS_NAME + '.' + nul] - */ -#define FAT_MAX_SHORT_SIZE ((MSDOS_NAME + 1) * NLS_MAX_CHARSET_SIZE + 1) -/* - * Maximum buffer size of unicode chars from slots. - * [(max longname slots * 13 (size in a slot) + nul) * sizeof(wchar_t)] - */ -#define FAT_MAX_UNI_CHARS ((MSDOS_SLOTS - 1) * 13 + 1) -#define FAT_MAX_UNI_SIZE (FAT_MAX_UNI_CHARS * sizeof(wchar_t)) - -static inline unsigned char fat_tolower(unsigned char c) -{ - return ((c >= 'A') && (c <= 'Z')) ? c+32 : c; -} - -static inline loff_t fat_make_i_pos(struct super_block *sb, - struct buffer_head *bh, - struct msdos_dir_entry *de) -{ - return ((loff_t)bh->b_blocknr << MSDOS_SB(sb)->dir_per_block_bits) - | (de - (struct msdos_dir_entry *)bh->b_data); -} - -static inline void fat_dir_readahead(struct inode *dir, sector_t iblock, - sector_t phys) -{ - struct super_block *sb = dir->i_sb; - struct msdos_sb_info *sbi = MSDOS_SB(sb); - struct buffer_head *bh; - int sec; - - /* This is not a first sector of cluster, or sec_per_clus == 1 */ - if ((iblock & (sbi->sec_per_clus - 1)) || sbi->sec_per_clus == 1) - return; - /* root dir of FAT12/FAT16 */ - if ((sbi->fat_bits != 32) && (dir->i_ino == MSDOS_ROOT_INO)) - return; - - bh = sb_find_get_block(sb, phys); - if (bh == NULL || !buffer_uptodate(bh)) { - for (sec = 0; sec < sbi->sec_per_clus; sec++) - sb_breadahead(sb, phys + sec); - } - brelse(bh); -} - -/* Returns the inode number of the directory entry at offset pos. If bh is - non-NULL, it is brelse'd before. Pos is incremented. The buffer header is - returned in bh. - AV. Most often we do it item-by-item. Makes sense to optimize. - AV. OK, there we go: if both bh and de are non-NULL we assume that we just - AV. want the next entry (took one explicit de=NULL in vfat/namei.c). - AV. It's done in fat_get_entry() (inlined), here the slow case lives. - AV. Additionally, when we return -1 (i.e. reached the end of directory) - AV. we make bh NULL. - */ -static int fat__get_entry(struct inode *dir, loff_t *pos, - struct buffer_head **bh, struct msdos_dir_entry **de) -{ - struct super_block *sb = dir->i_sb; - sector_t phys, iblock; - unsigned long mapped_blocks; - int err, offset; - -next: - if (*bh) - brelse(*bh); - - *bh = NULL; - iblock = *pos >> sb->s_blocksize_bits; - err = fat_bmap(dir, iblock, &phys, &mapped_blocks, 0, false); - if (err || !phys) - return -1; /* beyond EOF or error */ - - fat_dir_readahead(dir, iblock, phys); - - *bh = sb_bread(sb, phys); - if (*bh == NULL) { - fat_msg_ratelimit(sb, KERN_ERR, - "Directory bread(block %llu) failed", (llu)phys); - /* skip this block */ - *pos = (iblock + 1) << sb->s_blocksize_bits; - goto next; - } - - offset = *pos & (sb->s_blocksize - 1); - *pos += sizeof(struct msdos_dir_entry); - *de = (struct msdos_dir_entry *)((*bh)->b_data + offset); - - return 0; -} - -static inline int fat_get_entry(struct inode *dir, loff_t *pos, - struct buffer_head **bh, - struct msdos_dir_entry **de) -{ - /* Fast stuff first */ - if (*bh && *de && - (*de - (struct msdos_dir_entry *)(*bh)->b_data) < - MSDOS_SB(dir->i_sb)->dir_per_block - 1) { - *pos += sizeof(struct msdos_dir_entry); - (*de)++; - return 0; - } - return fat__get_entry(dir, pos, bh, de); -} - -/* - * Convert Unicode 16 to UTF-8, translated Unicode, or ASCII. - * If uni_xlate is enabled and we can't get a 1:1 conversion, use a - * colon as an escape character since it is normally invalid on the vfat - * filesystem. The following four characters are the hexadecimal digits - * of Unicode value. This lets us do a full dump and restore of Unicode - * filenames. We could get into some trouble with long Unicode names, - * but ignore that right now. - * Ahem... Stack smashing in ring 0 isn't fun. Fixed. - */ -static int uni16_to_x8(struct super_block *sb, unsigned char *ascii, - const wchar_t *uni, int len, struct nls_table *nls) -{ - int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate; - const wchar_t *ip; - wchar_t ec; - unsigned char *op; - int charlen; - - ip = uni; - op = ascii; - - while (*ip && ((len - NLS_MAX_CHARSET_SIZE) > 0)) { - ec = *ip++; - charlen = nls->uni2char(ec, op, NLS_MAX_CHARSET_SIZE); - if (charlen > 0) { - op += charlen; - len -= charlen; - } else { - if (uni_xlate == 1) { - *op++ = ':'; - op = hex_byte_pack(op, ec >> 8); - op = hex_byte_pack(op, ec); - len -= 5; - } else { - *op++ = '?'; - len--; - } - } - } - - if (unlikely(*ip)) { - fat_msg(sb, KERN_WARNING, - "filename was truncated while converting."); - } - - *op = 0; - return op - ascii; -} - -static inline int fat_uni_to_x8(struct super_block *sb, const wchar_t *uni, - unsigned char *buf, int size) -{ - struct msdos_sb_info *sbi = MSDOS_SB(sb); - if (sbi->options.utf8) - return utf16s_to_utf8s(uni, FAT_MAX_UNI_CHARS, - UTF16_HOST_ENDIAN, buf, size); - else - return uni16_to_x8(sb, buf, uni, size, sbi->nls_io); -} - -static inline int -fat_short2uni(struct nls_table *t, unsigned char *c, int clen, wchar_t *uni) -{ - int charlen; - - charlen = t->char2uni(c, clen, uni); - if (charlen < 0) { - *uni = 0x003f; /* a question mark */ - charlen = 1; - } - return charlen; -} - -static inline int -fat_short2lower_uni(struct nls_table *t, unsigned char *c, - int clen, wchar_t *uni) -{ - int charlen; - wchar_t wc; - - charlen = t->char2uni(c, clen, &wc); - if (charlen < 0) { - *uni = 0x003f; /* a question mark */ - charlen = 1; - } else if (charlen <= 1) { - unsigned char nc = t->charset2lower[*c]; - - if (!nc) - nc = *c; - - charlen = t->char2uni(&nc, 1, uni); - if (charlen < 0) { - *uni = 0x003f; /* a question mark */ - charlen = 1; - } - } else - *uni = wc; - - return charlen; -} - -static inline int -fat_shortname2uni(struct nls_table *nls, unsigned char *buf, int buf_size, - wchar_t *uni_buf, unsigned short opt, int lower) -{ - int len = 0; - - if (opt & VFAT_SFN_DISPLAY_LOWER) - len = fat_short2lower_uni(nls, buf, buf_size, uni_buf); - else if (opt & VFAT_SFN_DISPLAY_WIN95) - len = fat_short2uni(nls, buf, buf_size, uni_buf); - else if (opt & VFAT_SFN_DISPLAY_WINNT) { - if (lower) - len = fat_short2lower_uni(nls, buf, buf_size, uni_buf); - else - len = fat_short2uni(nls, buf, buf_size, uni_buf); - } else - len = fat_short2uni(nls, buf, buf_size, uni_buf); - - return len; -} - -static inline int fat_name_match(struct msdos_sb_info *sbi, - const unsigned char *a, int a_len, - const unsigned char *b, int b_len) -{ - if (a_len != b_len) - return 0; - - if (sbi->options.name_check != 's') - return !nls_strnicmp(sbi->nls_io, a, b, a_len); - else - return !memcmp(a, b, a_len); -} - -enum { PARSE_INVALID = 1, PARSE_NOT_LONGNAME, PARSE_EOF, }; - -/** - * fat_parse_long - Parse extended directory entry. - * - * This function returns zero on success, negative value on error, or one of - * the following: - * - * %PARSE_INVALID - Directory entry is invalid. - * %PARSE_NOT_LONGNAME - Directory entry does not contain longname. - * %PARSE_EOF - Directory has no more entries. - */ -static int fat_parse_long(struct inode *dir, loff_t *pos, - struct buffer_head **bh, struct msdos_dir_entry **de, - wchar_t **unicode, unsigned char *nr_slots) -{ - struct msdos_dir_slot *ds; - unsigned char id, slot, slots, alias_checksum; - - if (!*unicode) { - *unicode = __getname(); - if (!*unicode) { - brelse(*bh); - return -ENOMEM; - } - } -parse_long: - slots = 0; - ds = (struct msdos_dir_slot *)*de; - id = ds->id; - if (!(id & 0x40)) - return PARSE_INVALID; - slots = id & ~0x40; - if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */ - return PARSE_INVALID; - *nr_slots = slots; - alias_checksum = ds->alias_checksum; - - slot = slots; - while (1) { - int offset; - - slot--; - offset = slot * 13; - fat16_towchar(*unicode + offset, ds->name0_4, 5); - fat16_towchar(*unicode + offset + 5, ds->name5_10, 6); - fat16_towchar(*unicode + offset + 11, ds->name11_12, 2); - - if (ds->id & 0x40) - (*unicode)[offset + 13] = 0; - if (fat_get_entry(dir, pos, bh, de) < 0) - return PARSE_EOF; - if (slot == 0) - break; - ds = (struct msdos_dir_slot *)*de; - if (ds->attr != ATTR_EXT) - return PARSE_NOT_LONGNAME; - if ((ds->id & ~0x40) != slot) - goto parse_long; - if (ds->alias_checksum != alias_checksum) - goto parse_long; - } - if ((*de)->name[0] == DELETED_FLAG) - return PARSE_INVALID; - if ((*de)->attr == ATTR_EXT) - goto parse_long; - if (IS_FREE((*de)->name) || ((*de)->attr & ATTR_VOLUME)) - return PARSE_INVALID; - if (fat_checksum((*de)->name) != alias_checksum) - *nr_slots = 0; - - return 0; -} - -/** - * fat_parse_short - Parse MS-DOS (short) directory entry. - * @sb: superblock - * @de: directory entry to parse - * @name: FAT_MAX_SHORT_SIZE array in which to place extracted name - * @dot_hidden: Nonzero == prepend '.' to names with ATTR_HIDDEN - * - * Returns the number of characters extracted into 'name'. - */ -static int fat_parse_short(struct super_block *sb, - const struct msdos_dir_entry *de, - unsigned char *name, int dot_hidden) -{ - const struct msdos_sb_info *sbi = MSDOS_SB(sb); - int isvfat = sbi->options.isvfat; - int nocase = sbi->options.nocase; - unsigned short opt_shortname = sbi->options.shortname; - struct nls_table *nls_disk = sbi->nls_disk; - wchar_t uni_name[14]; - unsigned char c, work[MSDOS_NAME]; - unsigned char *ptname = name; - int chi, chl, i, j, k; - int dotoffset = 0; - int name_len = 0, uni_len = 0; - - if (!isvfat && dot_hidden && (de->attr & ATTR_HIDDEN)) { - *ptname++ = '.'; - dotoffset = 1; - } - - memcpy(work, de->name, sizeof(work)); - /* see namei.c, msdos_format_name */ - if (work[0] == 0x05) - work[0] = 0xE5; - - /* Filename */ - for (i = 0, j = 0; i < 8;) { - c = work[i]; - if (!c) - break; - chl = fat_shortname2uni(nls_disk, &work[i], 8 - i, - &uni_name[j++], opt_shortname, - de->lcase & CASE_LOWER_BASE); - if (chl <= 1) { - if (!isvfat) - ptname[i] = nocase ? c : fat_tolower(c); - i++; - if (c != ' ') { - name_len = i; - uni_len = j; - } - } else { - uni_len = j; - if (isvfat) - i += min(chl, 8-i); - else { - for (chi = 0; chi < chl && i < 8; chi++, i++) - ptname[i] = work[i]; - } - if (chl) - name_len = i; - } - } - - i = name_len; - j = uni_len; - fat_short2uni(nls_disk, ".", 1, &uni_name[j++]); - if (!isvfat) - ptname[i] = '.'; - i++; - - /* Extension */ - for (k = 8; k < MSDOS_NAME;) { - c = work[k]; - if (!c) - break; - chl = fat_shortname2uni(nls_disk, &work[k], MSDOS_NAME - k, - &uni_name[j++], opt_shortname, - de->lcase & CASE_LOWER_EXT); - if (chl <= 1) { - k++; - if (!isvfat) - ptname[i] = nocase ? c : fat_tolower(c); - i++; - if (c != ' ') { - name_len = i; - uni_len = j; - } - } else { - uni_len = j; - if (isvfat) { - int offset = min(chl, MSDOS_NAME-k); - k += offset; - i += offset; - } else { - for (chi = 0; chi < chl && k < MSDOS_NAME; - chi++, i++, k++) { - ptname[i] = work[k]; - } - } - if (chl) - name_len = i; - } - } - - if (name_len > 0) { - name_len += dotoffset; - - if (sbi->options.isvfat) { - uni_name[uni_len] = 0x0000; - name_len = fat_uni_to_x8(sb, uni_name, name, - FAT_MAX_SHORT_SIZE); - } - } - - return name_len; -} - -/* - * Return values: negative -> error/not found, 0 -> found. - */ -int fat_search_long(struct inode *inode, const unsigned char *name, - int name_len, struct fat_slot_info *sinfo) -{ - struct super_block *sb = inode->i_sb; - struct msdos_sb_info *sbi = MSDOS_SB(sb); - struct buffer_head *bh = NULL; - struct msdos_dir_entry *de; - unsigned char nr_slots; - wchar_t *unicode = NULL; - unsigned char bufname[FAT_MAX_SHORT_SIZE]; - loff_t cpos = 0; - int err, len; - - err = -ENOENT; - while (1) { - if (fat_get_entry(inode, &cpos, &bh, &de) == -1) - goto end_of_dir; -parse_record: - nr_slots = 0; - if (de->name[0] == DELETED_FLAG) - continue; - if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME)) - continue; - if (de->attr != ATTR_EXT && IS_FREE(de->name)) - continue; - if (de->attr == ATTR_EXT) { - int status = fat_parse_long(inode, &cpos, &bh, &de, - &unicode, &nr_slots); - if (status < 0) { - err = status; - goto end_of_dir; - } else if (status == PARSE_INVALID) - continue; - else if (status == PARSE_NOT_LONGNAME) - goto parse_record; - else if (status == PARSE_EOF) - goto end_of_dir; - } - - /* Never prepend '.' to hidden files here. - * That is done only for msdos mounts (and only when - * 'dotsOK=yes'); if we are executing here, it is in the - * context of a vfat mount. - */ - len = fat_parse_short(sb, de, bufname, 0); - if (len == 0) - continue; - - /* Compare shortname */ - if (fat_name_match(sbi, name, name_len, bufname, len)) - goto found; - - if (nr_slots) { - void *longname = unicode + FAT_MAX_UNI_CHARS; - int size = PATH_MAX - FAT_MAX_UNI_SIZE; - - /* Compare longname */ - len = fat_uni_to_x8(sb, unicode, longname, size); - if (fat_name_match(sbi, name, name_len, longname, len)) - goto found; - } - } - -found: - nr_slots++; /* include the de */ - sinfo->slot_off = cpos - nr_slots * sizeof(*de); - sinfo->nr_slots = nr_slots; - sinfo->de = de; - sinfo->bh = bh; - sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de); - err = 0; -end_of_dir: - if (unicode) - __putname(unicode); - - return err; -} -EXPORT_SYMBOL_GPL(fat_search_long); - -struct fat_ioctl_filldir_callback { - struct dir_context ctx; - void __user *dirent; - int result; - /* for dir ioctl */ - const char *longname; - int long_len; - const char *shortname; - int short_len; -}; - -static int __fat_readdir(struct inode *inode, struct file *file, - struct dir_context *ctx, int short_only, - struct fat_ioctl_filldir_callback *both) -{ - struct super_block *sb = inode->i_sb; - struct msdos_sb_info *sbi = MSDOS_SB(sb); - struct buffer_head *bh; - struct msdos_dir_entry *de; - unsigned char nr_slots; - wchar_t *unicode = NULL; - unsigned char bufname[FAT_MAX_SHORT_SIZE]; - int isvfat = sbi->options.isvfat; - const char *fill_name = NULL; - int fake_offset = 0; - loff_t cpos; - int short_len = 0, fill_len = 0; - int ret = 0; - - mutex_lock(&sbi->s_lock); - - cpos = ctx->pos; - /* Fake . and .. for the root directory. */ - if (inode->i_ino == MSDOS_ROOT_INO) { - if (!dir_emit_dots(file, ctx)) - goto out; - if (ctx->pos == 2) { - fake_offset = 1; - cpos = 0; - } - } - if (cpos & (sizeof(struct msdos_dir_entry) - 1)) { - ret = -ENOENT; - goto out; - } - - bh = NULL; -get_new: - if (fat_get_entry(inode, &cpos, &bh, &de) == -1) - goto end_of_dir; -parse_record: - nr_slots = 0; - /* - * Check for long filename entry, but if short_only, we don't - * need to parse long filename. - */ - if (isvfat && !short_only) { - if (de->name[0] == DELETED_FLAG) - goto record_end; - if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME)) - goto record_end; - if (de->attr != ATTR_EXT && IS_FREE(de->name)) - goto record_end; - } else { - if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name)) - goto record_end; - } - - if (isvfat && de->attr == ATTR_EXT) { - int status = fat_parse_long(inode, &cpos, &bh, &de, - &unicode, &nr_slots); - if (status < 0) { - bh = NULL; - ret = status; - goto end_of_dir; - } else if (status == PARSE_INVALID) - goto record_end; - else if (status == PARSE_NOT_LONGNAME) - goto parse_record; - else if (status == PARSE_EOF) - goto end_of_dir; - - if (nr_slots) { - void *longname = unicode + FAT_MAX_UNI_CHARS; - int size = PATH_MAX - FAT_MAX_UNI_SIZE; - int len = fat_uni_to_x8(sb, unicode, longname, size); - - fill_name = longname; - fill_len = len; - /* !both && !short_only, so we don't need shortname. */ - if (!both) - goto start_filldir; - - short_len = fat_parse_short(sb, de, bufname, - sbi->options.dotsOK); - if (short_len == 0) - goto record_end; - /* hack for fat_ioctl_filldir() */ - both->longname = fill_name; - both->long_len = fill_len; - both->shortname = bufname; - both->short_len = short_len; - fill_name = NULL; - fill_len = 0; - goto start_filldir; - } - } - - short_len = fat_parse_short(sb, de, bufname, sbi->options.dotsOK); - if (short_len == 0) - goto record_end; - - fill_name = bufname; - fill_len = short_len; - -start_filldir: - ctx->pos = cpos - (nr_slots + 1) * sizeof(struct msdos_dir_entry); - if (fake_offset && ctx->pos < 2) - ctx->pos = 2; - - if (!memcmp(de->name, MSDOS_DOT, MSDOS_NAME)) { - if (!dir_emit_dot(file, ctx)) - goto fill_failed; - } else if (!memcmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) { - if (!dir_emit_dotdot(file, ctx)) - goto fill_failed; - } else { - unsigned long inum; - loff_t i_pos = fat_make_i_pos(sb, bh, de); - struct inode *tmp = fat_iget(sb, i_pos); - if (tmp) { - inum = tmp->i_ino; - iput(tmp); - } else - inum = iunique(sb, MSDOS_ROOT_INO); - if (!dir_emit(ctx, fill_name, fill_len, inum, - (de->attr & ATTR_DIR) ? DT_DIR : DT_REG)) - goto fill_failed; - } - -record_end: - fake_offset = 0; - ctx->pos = cpos; - goto get_new; - -end_of_dir: - if (fake_offset && cpos < 2) - ctx->pos = 2; - else - ctx->pos = cpos; -fill_failed: - brelse(bh); - if (unicode) - __putname(unicode); -out: - mutex_unlock(&sbi->s_lock); - - return ret; -} - -static int fat_readdir(struct file *file, struct dir_context *ctx) -{ - return __fat_readdir(file_inode(file), file, ctx, 0, NULL); -} - -#define FAT_IOCTL_FILLDIR_FUNC(func, dirent_type) \ -static int func(struct dir_context *ctx, const char *name, int name_len, \ - loff_t offset, u64 ino, unsigned int d_type) \ -{ \ - struct fat_ioctl_filldir_callback *buf = \ - container_of(ctx, struct fat_ioctl_filldir_callback, ctx); \ - struct dirent_type __user *d1 = buf->dirent; \ - struct dirent_type __user *d2 = d1 + 1; \ - \ - if (buf->result) \ - return -EINVAL; \ - buf->result++; \ - \ - if (name != NULL) { \ - /* dirent has only short name */ \ - if (name_len >= sizeof(d1->d_name)) \ - name_len = sizeof(d1->d_name) - 1; \ - \ - if (put_user(0, d2->d_name) || \ - put_user(0, &d2->d_reclen) || \ - copy_to_user(d1->d_name, name, name_len) || \ - put_user(0, d1->d_name + name_len) || \ - put_user(name_len, &d1->d_reclen)) \ - goto efault; \ - } else { \ - /* dirent has short and long name */ \ - const char *longname = buf->longname; \ - int long_len = buf->long_len; \ - const char *shortname = buf->shortname; \ - int short_len = buf->short_len; \ - \ - if (long_len >= sizeof(d1->d_name)) \ - long_len = sizeof(d1->d_name) - 1; \ - if (short_len >= sizeof(d1->d_name)) \ - short_len = sizeof(d1->d_name) - 1; \ - \ - if (copy_to_user(d2->d_name, longname, long_len) || \ - put_user(0, d2->d_name + long_len) || \ - put_user(long_len, &d2->d_reclen) || \ - put_user(ino, &d2->d_ino) || \ - put_user(offset, &d2->d_off) || \ - copy_to_user(d1->d_name, shortname, short_len) || \ - put_user(0, d1->d_name + short_len) || \ - put_user(short_len, &d1->d_reclen)) \ - goto efault; \ - } \ - return 0; \ -efault: \ - buf->result = -EFAULT; \ - return -EFAULT; \ -} - -FAT_IOCTL_FILLDIR_FUNC(fat_ioctl_filldir, __fat_dirent) - -static int fat_ioctl_readdir(struct inode *inode, struct file *file, - void __user *dirent, filldir_t filldir, - int short_only, int both) -{ - struct fat_ioctl_filldir_callback buf = { - .ctx.actor = filldir, - .dirent = dirent - }; - int ret; - - buf.dirent = dirent; - buf.result = 0; - inode_lock_shared(inode); - buf.ctx.pos = file->f_pos; - ret = -ENOENT; - if (!IS_DEADDIR(inode)) { - ret = __fat_readdir(inode, file, &buf.ctx, - short_only, both ? &buf : NULL); - file->f_pos = buf.ctx.pos; - } - inode_unlock_shared(inode); - if (ret >= 0) - ret = buf.result; - return ret; -} - -static long fat_dir_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - struct inode *inode = file_inode(filp); - struct __fat_dirent __user *d1 = (struct __fat_dirent __user *)arg; - int short_only, both; - - switch (cmd) { - case VFAT_IOCTL_READDIR_SHORT: - short_only = 1; - both = 0; - break; - case VFAT_IOCTL_READDIR_BOTH: - short_only = 0; - both = 1; - break; - default: - return fat_generic_ioctl(filp, cmd, arg); - } - - if (!access_ok(VERIFY_WRITE, d1, sizeof(struct __fat_dirent[2]))) - return -EFAULT; - /* - * Yes, we don't need this put_user() absolutely. However old - * code didn't return the right value. So, app use this value, - * in order to check whether it is EOF. - */ - if (put_user(0, &d1->d_reclen)) - return -EFAULT; - - return fat_ioctl_readdir(inode, filp, d1, fat_ioctl_filldir, - short_only, both); -} - -#ifdef CONFIG_COMPAT -#define VFAT_IOCTL_READDIR_BOTH32 _IOR('r', 1, struct compat_dirent[2]) -#define VFAT_IOCTL_READDIR_SHORT32 _IOR('r', 2, struct compat_dirent[2]) - -FAT_IOCTL_FILLDIR_FUNC(fat_compat_ioctl_filldir, compat_dirent) - -static long fat_compat_dir_ioctl(struct file *filp, unsigned cmd, - unsigned long arg) -{ - struct inode *inode = file_inode(filp); - struct compat_dirent __user *d1 = compat_ptr(arg); - int short_only, both; - - switch (cmd) { - case VFAT_IOCTL_READDIR_SHORT32: - short_only = 1; - both = 0; - break; - case VFAT_IOCTL_READDIR_BOTH32: - short_only = 0; - both = 1; - break; - default: - return fat_generic_ioctl(filp, cmd, (unsigned long)arg); - } - - if (!access_ok(VERIFY_WRITE, d1, sizeof(struct compat_dirent[2]))) - return -EFAULT; - /* - * Yes, we don't need this put_user() absolutely. However old - * code didn't return the right value. So, app use this value, - * in order to check whether it is EOF. - */ - if (put_user(0, &d1->d_reclen)) - return -EFAULT; - - return fat_ioctl_readdir(inode, filp, d1, fat_compat_ioctl_filldir, - short_only, both); -} -#endif /* CONFIG_COMPAT */ - -const struct file_operations fat_dir_operations = { - .llseek = generic_file_llseek, - .read = generic_read_dir, - .iterate_shared = fat_readdir, - .unlocked_ioctl = fat_dir_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = fat_compat_dir_ioctl, -#endif - .fsync = fat_file_fsync, -}; - -static int fat_get_short_entry(struct inode *dir, loff_t *pos, - struct buffer_head **bh, - struct msdos_dir_entry **de) -{ - while (fat_get_entry(dir, pos, bh, de) >= 0) { - /* free entry or long name entry or volume label */ - if (!IS_FREE((*de)->name) && !((*de)->attr & ATTR_VOLUME)) - return 0; - } - return -ENOENT; -} - -/* - * The ".." entry can not provide the "struct fat_slot_info" information - * for inode, nor a usable i_pos. So, this function provides some information - * only. - * - * Since this function walks through the on-disk inodes within a directory, - * callers are responsible for taking any locks necessary to prevent the - * directory from changing. - */ -int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh, - struct msdos_dir_entry **de) -{ - loff_t offset = 0; - - *de = NULL; - while (fat_get_short_entry(dir, &offset, bh, de) >= 0) { - if (!strncmp((*de)->name, MSDOS_DOTDOT, MSDOS_NAME)) - return 0; - } - return -ENOENT; -} -EXPORT_SYMBOL_GPL(fat_get_dotdot_entry); - -/* See if directory is empty */ -int fat_dir_empty(struct inode *dir) -{ - struct buffer_head *bh; - struct msdos_dir_entry *de; - loff_t cpos; - int result = 0; - - bh = NULL; - cpos = 0; - while (fat_get_short_entry(dir, &cpos, &bh, &de) >= 0) { - if (strncmp(de->name, MSDOS_DOT , MSDOS_NAME) && - strncmp(de->name, MSDOS_DOTDOT, MSDOS_NAME)) { - result = -ENOTEMPTY; - break; - } - } - brelse(bh); - return result; -} -EXPORT_SYMBOL_GPL(fat_dir_empty); - -/* - * fat_subdirs counts the number of sub-directories of dir. It can be run - * on directories being created. - */ -int fat_subdirs(struct inode *dir) -{ - struct buffer_head *bh; - struct msdos_dir_entry *de; - loff_t cpos; - int count = 0; - - bh = NULL; - cpos = 0; - while (fat_get_short_entry(dir, &cpos, &bh, &de) >= 0) { - if (de->attr & ATTR_DIR) - count++; - } - brelse(bh); - return count; -} - -/* - * Scans a directory for a given file (name points to its formatted name). - * Returns an error code or zero. - */ -int fat_scan(struct inode *dir, const unsigned char *name, - struct fat_slot_info *sinfo) -{ - struct super_block *sb = dir->i_sb; - - sinfo->slot_off = 0; - sinfo->bh = NULL; - while (fat_get_short_entry(dir, &sinfo->slot_off, &sinfo->bh, - &sinfo->de) >= 0) { - if (!strncmp(sinfo->de->name, name, MSDOS_NAME)) { - sinfo->slot_off -= sizeof(*sinfo->de); - sinfo->nr_slots = 1; - sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de); - return 0; - } - } - return -ENOENT; -} -EXPORT_SYMBOL_GPL(fat_scan); - -/* - * Scans a directory for a given logstart. - * Returns an error code or zero. - */ -int fat_scan_logstart(struct inode *dir, int i_logstart, - struct fat_slot_info *sinfo) -{ - struct super_block *sb = dir->i_sb; - - sinfo->slot_off = 0; - sinfo->bh = NULL; - while (fat_get_short_entry(dir, &sinfo->slot_off, &sinfo->bh, - &sinfo->de) >= 0) { - if (fat_get_start(MSDOS_SB(sb), sinfo->de) == i_logstart) { - sinfo->slot_off -= sizeof(*sinfo->de); - sinfo->nr_slots = 1; - sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de); - return 0; - } - } - return -ENOENT; -} - -static int __fat_remove_entries(struct inode *dir, loff_t pos, int nr_slots) -{ - struct super_block *sb = dir->i_sb; - struct buffer_head *bh; - struct msdos_dir_entry *de, *endp; - int err = 0, orig_slots; - - while (nr_slots) { - bh = NULL; - if (fat_get_entry(dir, &pos, &bh, &de) < 0) { - err = -EIO; - break; - } - - orig_slots = nr_slots; - endp = (struct msdos_dir_entry *)(bh->b_data + sb->s_blocksize); - while (nr_slots && de < endp) { - de->name[0] = DELETED_FLAG; - de++; - nr_slots--; - } - mark_buffer_dirty_inode(bh, dir); - if (IS_DIRSYNC(dir)) - err = sync_dirty_buffer(bh); - brelse(bh); - if (err) - break; - - /* pos is *next* de's position, so this does `- sizeof(de)' */ - pos += ((orig_slots - nr_slots) * sizeof(*de)) - sizeof(*de); - } - - return err; -} - -int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo) -{ - struct super_block *sb = dir->i_sb; - struct msdos_dir_entry *de; - struct buffer_head *bh; - int err = 0, nr_slots; - - /* - * First stage: Remove the shortname. By this, the directory - * entry is removed. - */ - nr_slots = sinfo->nr_slots; - de = sinfo->de; - sinfo->de = NULL; - bh = sinfo->bh; - sinfo->bh = NULL; - while (nr_slots && de >= (struct msdos_dir_entry *)bh->b_data) { - de->name[0] = DELETED_FLAG; - de--; - nr_slots--; - } - mark_buffer_dirty_inode(bh, dir); - if (IS_DIRSYNC(dir)) - err = sync_dirty_buffer(bh); - brelse(bh); - if (err) - return err; - dir->i_version++; - - if (nr_slots) { - /* - * Second stage: remove the remaining longname slots. - * (This directory entry is already removed, and so return - * the success) - */ - err = __fat_remove_entries(dir, sinfo->slot_off, nr_slots); - if (err) { - fat_msg(sb, KERN_WARNING, - "Couldn't remove the long name slots"); - } - } - - dir->i_mtime = dir->i_atime = current_time(dir); - if (IS_DIRSYNC(dir)) - (void)fat_sync_inode(dir); - else - mark_inode_dirty(dir); - - return 0; -} -EXPORT_SYMBOL_GPL(fat_remove_entries); - -static int fat_zeroed_cluster(struct inode *dir, sector_t blknr, int nr_used, - struct buffer_head **bhs, int nr_bhs) -{ - struct super_block *sb = dir->i_sb; - sector_t last_blknr = blknr + MSDOS_SB(sb)->sec_per_clus; - int err, i, n; - - /* Zeroing the unused blocks on this cluster */ - blknr += nr_used; - n = nr_used; - while (blknr < last_blknr) { - bhs[n] = sb_getblk(sb, blknr); - if (!bhs[n]) { - err = -ENOMEM; - goto error; - } - memset(bhs[n]->b_data, 0, sb->s_blocksize); - set_buffer_uptodate(bhs[n]); - mark_buffer_dirty_inode(bhs[n], dir); - - n++; - blknr++; - if (n == nr_bhs) { - if (IS_DIRSYNC(dir)) { - err = fat_sync_bhs(bhs, n); - if (err) - goto error; - } - for (i = 0; i < n; i++) - brelse(bhs[i]); - n = 0; - } - } - if (IS_DIRSYNC(dir)) { - err = fat_sync_bhs(bhs, n); - if (err) - goto error; - } - for (i = 0; i < n; i++) - brelse(bhs[i]); - - return 0; - -error: - for (i = 0; i < n; i++) - bforget(bhs[i]); - return err; -} - -int fat_alloc_new_dir(struct inode *dir, struct timespec *ts) -{ - struct super_block *sb = dir->i_sb; - struct msdos_sb_info *sbi = MSDOS_SB(sb); - struct buffer_head *bhs[MAX_BUF_PER_PAGE]; - struct msdos_dir_entry *de; - sector_t blknr; - __le16 date, time; - u8 time_cs; - int err, cluster; - - err = fat_alloc_clusters(dir, &cluster, 1); - if (err) - goto error; - - blknr = fat_clus_to_blknr(sbi, cluster); - bhs[0] = sb_getblk(sb, blknr); - if (!bhs[0]) { - err = -ENOMEM; - goto error_free; - } - - fat_time_unix2fat(sbi, ts, &time, &date, &time_cs); - - de = (struct msdos_dir_entry *)bhs[0]->b_data; - /* filling the new directory slots ("." and ".." entries) */ - memcpy(de[0].name, MSDOS_DOT, MSDOS_NAME); - memcpy(de[1].name, MSDOS_DOTDOT, MSDOS_NAME); - de->attr = de[1].attr = ATTR_DIR; - de[0].lcase = de[1].lcase = 0; - de[0].time = de[1].time = time; - de[0].date = de[1].date = date; - if (sbi->options.isvfat) { - /* extra timestamps */ - de[0].ctime = de[1].ctime = time; - de[0].ctime_cs = de[1].ctime_cs = time_cs; - de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = date; - } else { - de[0].ctime = de[1].ctime = 0; - de[0].ctime_cs = de[1].ctime_cs = 0; - de[0].adate = de[0].cdate = de[1].adate = de[1].cdate = 0; - } - fat_set_start(&de[0], cluster); - fat_set_start(&de[1], MSDOS_I(dir)->i_logstart); - de[0].size = de[1].size = 0; - memset(de + 2, 0, sb->s_blocksize - 2 * sizeof(*de)); - set_buffer_uptodate(bhs[0]); - mark_buffer_dirty_inode(bhs[0], dir); - - err = fat_zeroed_cluster(dir, blknr, 1, bhs, MAX_BUF_PER_PAGE); - if (err) - goto error_free; - - return cluster; - -error_free: - fat_free_clusters(dir, cluster); -error: - return err; -} -EXPORT_SYMBOL_GPL(fat_alloc_new_dir); - -static int fat_add_new_entries(struct inode *dir, void *slots, int nr_slots, - int *nr_cluster, struct msdos_dir_entry **de, - struct buffer_head **bh, loff_t *i_pos) -{ - struct super_block *sb = dir->i_sb; - struct msdos_sb_info *sbi = MSDOS_SB(sb); - struct buffer_head *bhs[MAX_BUF_PER_PAGE]; - sector_t blknr, start_blknr, last_blknr; - unsigned long size, copy; - int err, i, n, offset, cluster[2]; - - /* - * The minimum cluster size is 512bytes, and maximum entry - * size is 32*slots (672bytes). So, iff the cluster size is - * 512bytes, we may need two clusters. - */ - size = nr_slots * sizeof(struct msdos_dir_entry); - *nr_cluster = (size + (sbi->cluster_size - 1)) >> sbi->cluster_bits; - BUG_ON(*nr_cluster > 2); - - err = fat_alloc_clusters(dir, cluster, *nr_cluster); - if (err) - goto error; - - /* - * First stage: Fill the directory entry. NOTE: This cluster - * is not referenced from any inode yet, so updates order is - * not important. - */ - i = n = copy = 0; - do { - start_blknr = blknr = fat_clus_to_blknr(sbi, cluster[i]); - last_blknr = start_blknr + sbi->sec_per_clus; - while (blknr < last_blknr) { - bhs[n] = sb_getblk(sb, blknr); - if (!bhs[n]) { - err = -ENOMEM; - goto error_nomem; - } - - /* fill the directory entry */ - copy = min(size, sb->s_blocksize); - memcpy(bhs[n]->b_data, slots, copy); - slots += copy; - size -= copy; - set_buffer_uptodate(bhs[n]); - mark_buffer_dirty_inode(bhs[n], dir); - if (!size) - break; - n++; - blknr++; - } - } while (++i < *nr_cluster); - - memset(bhs[n]->b_data + copy, 0, sb->s_blocksize - copy); - offset = copy - sizeof(struct msdos_dir_entry); - get_bh(bhs[n]); - *bh = bhs[n]; - *de = (struct msdos_dir_entry *)((*bh)->b_data + offset); - *i_pos = fat_make_i_pos(sb, *bh, *de); - - /* Second stage: clear the rest of cluster, and write outs */ - err = fat_zeroed_cluster(dir, start_blknr, ++n, bhs, MAX_BUF_PER_PAGE); - if (err) - goto error_free; - - return cluster[0]; - -error_free: - brelse(*bh); - *bh = NULL; - n = 0; -error_nomem: - for (i = 0; i < n; i++) - bforget(bhs[i]); - fat_free_clusters(dir, cluster[0]); -error: - return err; -} - -int fat_add_entries(struct inode *dir, void *slots, int nr_slots, - struct fat_slot_info *sinfo) -{ - struct super_block *sb = dir->i_sb; - struct msdos_sb_info *sbi = MSDOS_SB(sb); - struct buffer_head *bh, *prev, *bhs[3]; /* 32*slots (672bytes) */ - struct msdos_dir_entry *uninitialized_var(de); - int err, free_slots, i, nr_bhs; - loff_t pos, i_pos; - - sinfo->nr_slots = nr_slots; - - /* First stage: search free directory entries */ - free_slots = nr_bhs = 0; - bh = prev = NULL; - pos = 0; - err = -ENOSPC; - while (fat_get_entry(dir, &pos, &bh, &de) > -1) { - /* check the maximum size of directory */ - if (pos >= FAT_MAX_DIR_SIZE) - goto error; - - if (IS_FREE(de->name)) { - if (prev != bh) { - get_bh(bh); - bhs[nr_bhs] = prev = bh; - nr_bhs++; - } - free_slots++; - if (free_slots == nr_slots) - goto found; - } else { - for (i = 0; i < nr_bhs; i++) - brelse(bhs[i]); - prev = NULL; - free_slots = nr_bhs = 0; - } - } - if (dir->i_ino == MSDOS_ROOT_INO) { - if (sbi->fat_bits != 32) - goto error; - } else if (MSDOS_I(dir)->i_start == 0) { - fat_msg(sb, KERN_ERR, "Corrupted directory (i_pos %lld)", - MSDOS_I(dir)->i_pos); - err = -EIO; - goto error; - } - -found: - err = 0; - pos -= free_slots * sizeof(*de); - nr_slots -= free_slots; - if (free_slots) { - /* - * Second stage: filling the free entries with new entries. - * NOTE: If this slots has shortname, first, we write - * the long name slots, then write the short name. - */ - int size = free_slots * sizeof(*de); - int offset = pos & (sb->s_blocksize - 1); - int long_bhs = nr_bhs - (nr_slots == 0); - - /* Fill the long name slots. */ - for (i = 0; i < long_bhs; i++) { - int copy = min_t(int, sb->s_blocksize - offset, size); - memcpy(bhs[i]->b_data + offset, slots, copy); - mark_buffer_dirty_inode(bhs[i], dir); - offset = 0; - slots += copy; - size -= copy; - } - if (long_bhs && IS_DIRSYNC(dir)) - err = fat_sync_bhs(bhs, long_bhs); - if (!err && i < nr_bhs) { - /* Fill the short name slot. */ - int copy = min_t(int, sb->s_blocksize - offset, size); - memcpy(bhs[i]->b_data + offset, slots, copy); - mark_buffer_dirty_inode(bhs[i], dir); - if (IS_DIRSYNC(dir)) - err = sync_dirty_buffer(bhs[i]); - } - for (i = 0; i < nr_bhs; i++) - brelse(bhs[i]); - if (err) - goto error_remove; - } - - if (nr_slots) { - int cluster, nr_cluster; - - /* - * Third stage: allocate the cluster for new entries. - * And initialize the cluster with new entries, then - * add the cluster to dir. - */ - cluster = fat_add_new_entries(dir, slots, nr_slots, &nr_cluster, - &de, &bh, &i_pos); - if (cluster < 0) { - err = cluster; - goto error_remove; - } - err = fat_chain_add(dir, cluster, nr_cluster); - if (err) { - fat_free_clusters(dir, cluster); - goto error_remove; - } - if (dir->i_size & (sbi->cluster_size - 1)) { - fat_fs_error(sb, "Odd directory size"); - dir->i_size = (dir->i_size + sbi->cluster_size - 1) - & ~((loff_t)sbi->cluster_size - 1); - } - dir->i_size += nr_cluster << sbi->cluster_bits; - MSDOS_I(dir)->mmu_private += nr_cluster << sbi->cluster_bits; - } - sinfo->slot_off = pos; - sinfo->de = de; - sinfo->bh = bh; - sinfo->i_pos = fat_make_i_pos(sb, sinfo->bh, sinfo->de); - - return 0; - -error: - brelse(bh); - for (i = 0; i < nr_bhs; i++) - brelse(bhs[i]); - return err; - -error_remove: - brelse(bh); - if (free_slots) - __fat_remove_entries(dir, pos, free_slots); - return err; -} -EXPORT_SYMBOL_GPL(fat_add_entries); diff --git a/src/linux/fs/fat/fat.h b/src/linux/fs/fat/fat.h deleted file mode 100644 index e6b764a..0000000 --- a/src/linux/fs/fat/fat.h +++ /dev/null @@ -1,424 +0,0 @@ -#ifndef _FAT_H -#define _FAT_H - -#include -#include -#include -#include -#include - -/* - * vfat shortname flags - */ -#define VFAT_SFN_DISPLAY_LOWER 0x0001 /* convert to lowercase for display */ -#define VFAT_SFN_DISPLAY_WIN95 0x0002 /* emulate win95 rule for display */ -#define VFAT_SFN_DISPLAY_WINNT 0x0004 /* emulate winnt rule for display */ -#define VFAT_SFN_CREATE_WIN95 0x0100 /* emulate win95 rule for create */ -#define VFAT_SFN_CREATE_WINNT 0x0200 /* emulate winnt rule for create */ - -#define FAT_ERRORS_CONT 1 /* ignore error and continue */ -#define FAT_ERRORS_PANIC 2 /* panic on error */ -#define FAT_ERRORS_RO 3 /* remount r/o on error */ - -#define FAT_NFS_STALE_RW 1 /* NFS RW support, can cause ESTALE */ -#define FAT_NFS_NOSTALE_RO 2 /* NFS RO support, no ESTALE issue */ - -struct fat_mount_options { - kuid_t fs_uid; - kgid_t fs_gid; - unsigned short fs_fmask; - unsigned short fs_dmask; - unsigned short codepage; /* Codepage for shortname conversions */ - int time_offset; /* Offset of timestamps from UTC (in minutes) */ - char *iocharset; /* Charset used for filename input/display */ - unsigned short shortname; /* flags for shortname display/create rule */ - unsigned char name_check; /* r = relaxed, n = normal, s = strict */ - unsigned char errors; /* On error: continue, panic, remount-ro */ - unsigned char nfs; /* NFS support: nostale_ro, stale_rw */ - unsigned short allow_utime;/* permission for setting the [am]time */ - unsigned quiet:1, /* set = fake successful chmods and chowns */ - showexec:1, /* set = only set x bit for com/exe/bat */ - sys_immutable:1, /* set = system files are immutable */ - dotsOK:1, /* set = hidden and system files are named '.filename' */ - isvfat:1, /* 0=no vfat long filename support, 1=vfat support */ - utf8:1, /* Use of UTF-8 character set (Default) */ - unicode_xlate:1, /* create escape sequences for unhandled Unicode */ - numtail:1, /* Does first alias have a numeric '~1' type tail? */ - flush:1, /* write things quickly */ - nocase:1, /* Does this need case conversion? 0=need case conversion*/ - usefree:1, /* Use free_clusters for FAT32 */ - tz_set:1, /* Filesystem timestamps' offset set */ - rodir:1, /* allow ATTR_RO for directory */ - discard:1, /* Issue discard requests on deletions */ - dos1xfloppy:1; /* Assume default BPB for DOS 1.x floppies */ -}; - -#define FAT_HASH_BITS 8 -#define FAT_HASH_SIZE (1UL << FAT_HASH_BITS) - -/* - * MS-DOS file system in-core superblock data - */ -struct msdos_sb_info { - unsigned short sec_per_clus; /* sectors/cluster */ - unsigned short cluster_bits; /* log2(cluster_size) */ - unsigned int cluster_size; /* cluster size */ - unsigned char fats, fat_bits; /* number of FATs, FAT bits (12,16 or 32) */ - unsigned short fat_start; - unsigned long fat_length; /* FAT start & length (sec.) */ - unsigned long dir_start; - unsigned short dir_entries; /* root dir start & entries */ - unsigned long data_start; /* first data sector */ - unsigned long max_cluster; /* maximum cluster number */ - unsigned long root_cluster; /* first cluster of the root directory */ - unsigned long fsinfo_sector; /* sector number of FAT32 fsinfo */ - struct mutex fat_lock; - struct mutex nfs_build_inode_lock; - struct mutex s_lock; - unsigned int prev_free; /* previously allocated cluster number */ - unsigned int free_clusters; /* -1 if undefined */ - unsigned int free_clus_valid; /* is free_clusters valid? */ - struct fat_mount_options options; - struct nls_table *nls_disk; /* Codepage used on disk */ - struct nls_table *nls_io; /* Charset used for input and display */ - const void *dir_ops; /* Opaque; default directory operations */ - int dir_per_block; /* dir entries per block */ - int dir_per_block_bits; /* log2(dir_per_block) */ - unsigned int vol_id; /*volume ID*/ - - int fatent_shift; - const struct fatent_operations *fatent_ops; - struct inode *fat_inode; - struct inode *fsinfo_inode; - - struct ratelimit_state ratelimit; - - spinlock_t inode_hash_lock; - struct hlist_head inode_hashtable[FAT_HASH_SIZE]; - - spinlock_t dir_hash_lock; - struct hlist_head dir_hashtable[FAT_HASH_SIZE]; - - unsigned int dirty; /* fs state before mount */ - struct rcu_head rcu; -}; - -#define FAT_CACHE_VALID 0 /* special case for valid cache */ - -/* - * MS-DOS file system inode data in memory - */ -struct msdos_inode_info { - spinlock_t cache_lru_lock; - struct list_head cache_lru; - int nr_caches; - /* for avoiding the race between fat_free() and fat_get_cluster() */ - unsigned int cache_valid_id; - - /* NOTE: mmu_private is 64bits, so must hold ->i_mutex to access */ - loff_t mmu_private; /* physically allocated size */ - - int i_start; /* first cluster or 0 */ - int i_logstart; /* logical first cluster */ - int i_attrs; /* unused attribute bits */ - loff_t i_pos; /* on-disk position of directory entry or 0 */ - struct hlist_node i_fat_hash; /* hash by i_location */ - struct hlist_node i_dir_hash; /* hash by i_logstart */ - struct rw_semaphore truncate_lock; /* protect bmap against truncate */ - struct inode vfs_inode; -}; - -struct fat_slot_info { - loff_t i_pos; /* on-disk position of directory entry */ - loff_t slot_off; /* offset for slot or de start */ - int nr_slots; /* number of slots + 1(de) in filename */ - struct msdos_dir_entry *de; - struct buffer_head *bh; -}; - -static inline struct msdos_sb_info *MSDOS_SB(struct super_block *sb) -{ - return sb->s_fs_info; -} - -static inline struct msdos_inode_info *MSDOS_I(struct inode *inode) -{ - return container_of(inode, struct msdos_inode_info, vfs_inode); -} - -/* - * 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 fat_mode_can_hold_ro(struct inode *inode) -{ - struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); - umode_t mask; - - if (S_ISDIR(inode->i_mode)) { - if (!sbi->options.rodir) - return 0; - mask = ~sbi->options.fs_dmask; - } else - mask = ~sbi->options.fs_fmask; - - if (!(mask & S_IWUGO)) - return 0; - return 1; -} - -/* Convert attribute bits and a mask to the UNIX mode. */ -static inline umode_t fat_make_mode(struct msdos_sb_info *sbi, - u8 attrs, umode_t mode) -{ - if (attrs & ATTR_RO && !((attrs & ATTR_DIR) && !sbi->options.rodir)) - mode &= ~S_IWUGO; - - if (attrs & ATTR_DIR) - return (mode & ~sbi->options.fs_dmask) | S_IFDIR; - else - return (mode & ~sbi->options.fs_fmask) | S_IFREG; -} - -/* Return the FAT attribute byte for this inode */ -static inline u8 fat_make_attrs(struct inode *inode) -{ - u8 attrs = MSDOS_I(inode)->i_attrs; - if (S_ISDIR(inode->i_mode)) - attrs |= ATTR_DIR; - if (fat_mode_can_hold_ro(inode) && !(inode->i_mode & S_IWUGO)) - attrs |= ATTR_RO; - return attrs; -} - -static inline void fat_save_attrs(struct inode *inode, u8 attrs) -{ - if (fat_mode_can_hold_ro(inode)) - MSDOS_I(inode)->i_attrs = attrs & ATTR_UNUSED; - else - MSDOS_I(inode)->i_attrs = attrs & (ATTR_UNUSED | ATTR_RO); -} - -static inline unsigned char fat_checksum(const __u8 *name) -{ - unsigned char s = name[0]; - s = (s<<7) + (s>>1) + name[1]; s = (s<<7) + (s>>1) + name[2]; - s = (s<<7) + (s>>1) + name[3]; s = (s<<7) + (s>>1) + name[4]; - s = (s<<7) + (s>>1) + name[5]; s = (s<<7) + (s>>1) + name[6]; - s = (s<<7) + (s>>1) + name[7]; s = (s<<7) + (s>>1) + name[8]; - s = (s<<7) + (s>>1) + name[9]; s = (s<<7) + (s>>1) + name[10]; - return s; -} - -static inline sector_t fat_clus_to_blknr(struct msdos_sb_info *sbi, int clus) -{ - return ((sector_t)clus - FAT_START_ENT) * sbi->sec_per_clus - + sbi->data_start; -} - -static inline void fat_get_blknr_offset(struct msdos_sb_info *sbi, - loff_t i_pos, sector_t *blknr, int *offset) -{ - *blknr = i_pos >> sbi->dir_per_block_bits; - *offset = i_pos & (sbi->dir_per_block - 1); -} - -static inline loff_t fat_i_pos_read(struct msdos_sb_info *sbi, - struct inode *inode) -{ - loff_t i_pos; -#if BITS_PER_LONG == 32 - spin_lock(&sbi->inode_hash_lock); -#endif - i_pos = MSDOS_I(inode)->i_pos; -#if BITS_PER_LONG == 32 - spin_unlock(&sbi->inode_hash_lock); -#endif - return i_pos; -} - -static inline void fat16_towchar(wchar_t *dst, const __u8 *src, size_t len) -{ -#ifdef __BIG_ENDIAN - while (len--) { - *dst++ = src[0] | (src[1] << 8); - src += 2; - } -#else - memcpy(dst, src, len * 2); -#endif -} - -static inline int fat_get_start(const struct msdos_sb_info *sbi, - const struct msdos_dir_entry *de) -{ - int cluster = le16_to_cpu(de->start); - if (sbi->fat_bits == 32) - cluster |= (le16_to_cpu(de->starthi) << 16); - return cluster; -} - -static inline void fat_set_start(struct msdos_dir_entry *de, int cluster) -{ - de->start = cpu_to_le16(cluster); - de->starthi = cpu_to_le16(cluster >> 16); -} - -static inline void fatwchar_to16(__u8 *dst, const wchar_t *src, size_t len) -{ -#ifdef __BIG_ENDIAN - while (len--) { - dst[0] = *src & 0x00FF; - dst[1] = (*src & 0xFF00) >> 8; - dst += 2; - src++; - } -#else - memcpy(dst, src, len * 2); -#endif -} - -/* fat/cache.c */ -extern void fat_cache_inval_inode(struct inode *inode); -extern int fat_get_cluster(struct inode *inode, int cluster, - int *fclus, int *dclus); -extern int fat_get_mapped_cluster(struct inode *inode, sector_t sector, - sector_t last_block, - unsigned long *mapped_blocks, sector_t *bmap); -extern int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys, - unsigned long *mapped_blocks, int create, bool from_bmap); - -/* fat/dir.c */ -extern const struct file_operations fat_dir_operations; -extern int fat_search_long(struct inode *inode, const unsigned char *name, - int name_len, struct fat_slot_info *sinfo); -extern int fat_dir_empty(struct inode *dir); -extern int fat_subdirs(struct inode *dir); -extern int fat_scan(struct inode *dir, const unsigned char *name, - struct fat_slot_info *sinfo); -extern int fat_scan_logstart(struct inode *dir, int i_logstart, - struct fat_slot_info *sinfo); -extern int fat_get_dotdot_entry(struct inode *dir, struct buffer_head **bh, - struct msdos_dir_entry **de); -extern int fat_alloc_new_dir(struct inode *dir, struct timespec *ts); -extern int fat_add_entries(struct inode *dir, void *slots, int nr_slots, - struct fat_slot_info *sinfo); -extern int fat_remove_entries(struct inode *dir, struct fat_slot_info *sinfo); - -/* fat/fatent.c */ -struct fat_entry { - int entry; - union { - u8 *ent12_p[2]; - __le16 *ent16_p; - __le32 *ent32_p; - } u; - int nr_bhs; - struct buffer_head *bhs[2]; - struct inode *fat_inode; -}; - -static inline void fatent_init(struct fat_entry *fatent) -{ - fatent->nr_bhs = 0; - fatent->entry = 0; - fatent->u.ent32_p = NULL; - fatent->bhs[0] = fatent->bhs[1] = NULL; - fatent->fat_inode = NULL; -} - -static inline void fatent_set_entry(struct fat_entry *fatent, int entry) -{ - fatent->entry = entry; - fatent->u.ent32_p = NULL; -} - -static inline void fatent_brelse(struct fat_entry *fatent) -{ - int i; - fatent->u.ent32_p = NULL; - for (i = 0; i < fatent->nr_bhs; i++) - brelse(fatent->bhs[i]); - fatent->nr_bhs = 0; - fatent->bhs[0] = fatent->bhs[1] = NULL; - fatent->fat_inode = NULL; -} - -extern void fat_ent_access_init(struct super_block *sb); -extern int fat_ent_read(struct inode *inode, struct fat_entry *fatent, - int entry); -extern int fat_ent_write(struct inode *inode, struct fat_entry *fatent, - int new, int wait); -extern int fat_alloc_clusters(struct inode *inode, int *cluster, - int nr_cluster); -extern int fat_free_clusters(struct inode *inode, int cluster); -extern int fat_count_free_clusters(struct super_block *sb); - -/* fat/file.c */ -extern long fat_generic_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg); -extern const struct file_operations fat_file_operations; -extern const struct inode_operations fat_file_inode_operations; -extern int fat_setattr(struct dentry *dentry, struct iattr *attr); -extern void fat_truncate_blocks(struct inode *inode, loff_t offset); -extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, - struct kstat *stat); -extern int fat_file_fsync(struct file *file, loff_t start, loff_t end, - int datasync); - -/* fat/inode.c */ -extern int fat_block_truncate_page(struct inode *inode, loff_t from); -extern void fat_attach(struct inode *inode, loff_t i_pos); -extern void fat_detach(struct inode *inode); -extern struct inode *fat_iget(struct super_block *sb, loff_t i_pos); -extern struct inode *fat_build_inode(struct super_block *sb, - struct msdos_dir_entry *de, loff_t i_pos); -extern int fat_sync_inode(struct inode *inode); -extern int fat_fill_super(struct super_block *sb, void *data, int silent, - int isvfat, void (*setup)(struct super_block *)); -extern int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de); - -extern int fat_flush_inodes(struct super_block *sb, struct inode *i1, - struct inode *i2); -static inline unsigned long fat_dir_hash(int logstart) -{ - return hash_32(logstart, FAT_HASH_BITS); -} -extern int fat_add_cluster(struct inode *inode); - -/* fat/misc.c */ -extern __printf(3, 4) __cold -void __fat_fs_error(struct super_block *sb, int report, const char *fmt, ...); -#define fat_fs_error(sb, fmt, args...) \ - __fat_fs_error(sb, 1, fmt , ## args) -#define fat_fs_error_ratelimit(sb, fmt, args...) \ - __fat_fs_error(sb, __ratelimit(&MSDOS_SB(sb)->ratelimit), fmt , ## args) -__printf(3, 4) __cold -void fat_msg(struct super_block *sb, const char *level, const char *fmt, ...); -#define fat_msg_ratelimit(sb, level, fmt, args...) \ - do { \ - if (__ratelimit(&MSDOS_SB(sb)->ratelimit)) \ - fat_msg(sb, level, fmt, ## args); \ - } while (0) -extern int fat_clusters_flush(struct super_block *sb); -extern int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster); -extern void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts, - __le16 __time, __le16 __date, u8 time_cs); -extern void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec *ts, - __le16 *time, __le16 *date, u8 *time_cs); -extern int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs); - -int fat_cache_init(void); -void fat_cache_destroy(void); - -/* fat/nfs.c */ -extern const struct export_operations fat_export_ops; -extern const struct export_operations fat_export_ops_nostale; - -/* helper for printk */ -typedef unsigned long long llu; - -#endif /* !_FAT_H */ diff --git a/src/linux/fs/fat/fatent.c b/src/linux/fs/fat/fatent.c deleted file mode 100644 index 1d9a8c4..0000000 --- a/src/linux/fs/fat/fatent.c +++ /dev/null @@ -1,692 +0,0 @@ -/* - * Copyright (C) 2004, OGAWA Hirofumi - * Released under GPL v2. - */ - -#include -#include "fat.h" - -struct fatent_operations { - void (*ent_blocknr)(struct super_block *, int, int *, sector_t *); - void (*ent_set_ptr)(struct fat_entry *, int); - int (*ent_bread)(struct super_block *, struct fat_entry *, - int, sector_t); - int (*ent_get)(struct fat_entry *); - void (*ent_put)(struct fat_entry *, int); - int (*ent_next)(struct fat_entry *); -}; - -static DEFINE_SPINLOCK(fat12_entry_lock); - -static void fat12_ent_blocknr(struct super_block *sb, int entry, - int *offset, sector_t *blocknr) -{ - struct msdos_sb_info *sbi = MSDOS_SB(sb); - int bytes = entry + (entry >> 1); - WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry); - *offset = bytes & (sb->s_blocksize - 1); - *blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits); -} - -static void fat_ent_blocknr(struct super_block *sb, int entry, - int *offset, sector_t *blocknr) -{ - struct msdos_sb_info *sbi = MSDOS_SB(sb); - int bytes = (entry << sbi->fatent_shift); - WARN_ON(entry < FAT_START_ENT || sbi->max_cluster <= entry); - *offset = bytes & (sb->s_blocksize - 1); - *blocknr = sbi->fat_start + (bytes >> sb->s_blocksize_bits); -} - -static void fat12_ent_set_ptr(struct fat_entry *fatent, int offset) -{ - struct buffer_head **bhs = fatent->bhs; - if (fatent->nr_bhs == 1) { - WARN_ON(offset >= (bhs[0]->b_size - 1)); - fatent->u.ent12_p[0] = bhs[0]->b_data + offset; - fatent->u.ent12_p[1] = bhs[0]->b_data + (offset + 1); - } else { - WARN_ON(offset != (bhs[0]->b_size - 1)); - fatent->u.ent12_p[0] = bhs[0]->b_data + offset; - fatent->u.ent12_p[1] = bhs[1]->b_data; - } -} - -static void fat16_ent_set_ptr(struct fat_entry *fatent, int offset) -{ - WARN_ON(offset & (2 - 1)); - fatent->u.ent16_p = (__le16 *)(fatent->bhs[0]->b_data + offset); -} - -static void fat32_ent_set_ptr(struct fat_entry *fatent, int offset) -{ - WARN_ON(offset & (4 - 1)); - fatent->u.ent32_p = (__le32 *)(fatent->bhs[0]->b_data + offset); -} - -static int fat12_ent_bread(struct super_block *sb, struct fat_entry *fatent, - int offset, sector_t blocknr) -{ - struct buffer_head **bhs = fatent->bhs; - - WARN_ON(blocknr < MSDOS_SB(sb)->fat_start); - fatent->fat_inode = MSDOS_SB(sb)->fat_inode; - - bhs[0] = sb_bread(sb, blocknr); - if (!bhs[0]) - goto err; - - if ((offset + 1) < sb->s_blocksize) - fatent->nr_bhs = 1; - else { - /* This entry is block boundary, it needs the next block */ - blocknr++; - bhs[1] = sb_bread(sb, blocknr); - if (!bhs[1]) - goto err_brelse; - fatent->nr_bhs = 2; - } - fat12_ent_set_ptr(fatent, offset); - return 0; - -err_brelse: - brelse(bhs[0]); -err: - fat_msg(sb, KERN_ERR, "FAT read failed (blocknr %llu)", (llu)blocknr); - return -EIO; -} - -static int fat_ent_bread(struct super_block *sb, struct fat_entry *fatent, - int offset, sector_t blocknr) -{ - const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; - - WARN_ON(blocknr < MSDOS_SB(sb)->fat_start); - fatent->fat_inode = MSDOS_SB(sb)->fat_inode; - fatent->bhs[0] = sb_bread(sb, blocknr); - if (!fatent->bhs[0]) { - fat_msg(sb, KERN_ERR, "FAT read failed (blocknr %llu)", - (llu)blocknr); - return -EIO; - } - fatent->nr_bhs = 1; - ops->ent_set_ptr(fatent, offset); - return 0; -} - -static int fat12_ent_get(struct fat_entry *fatent) -{ - u8 **ent12_p = fatent->u.ent12_p; - int next; - - spin_lock(&fat12_entry_lock); - if (fatent->entry & 1) - next = (*ent12_p[0] >> 4) | (*ent12_p[1] << 4); - else - next = (*ent12_p[1] << 8) | *ent12_p[0]; - spin_unlock(&fat12_entry_lock); - - next &= 0x0fff; - if (next >= BAD_FAT12) - next = FAT_ENT_EOF; - return next; -} - -static int fat16_ent_get(struct fat_entry *fatent) -{ - int next = le16_to_cpu(*fatent->u.ent16_p); - WARN_ON((unsigned long)fatent->u.ent16_p & (2 - 1)); - if (next >= BAD_FAT16) - next = FAT_ENT_EOF; - return next; -} - -static int fat32_ent_get(struct fat_entry *fatent) -{ - int next = le32_to_cpu(*fatent->u.ent32_p) & 0x0fffffff; - WARN_ON((unsigned long)fatent->u.ent32_p & (4 - 1)); - if (next >= BAD_FAT32) - next = FAT_ENT_EOF; - return next; -} - -static void fat12_ent_put(struct fat_entry *fatent, int new) -{ - u8 **ent12_p = fatent->u.ent12_p; - - if (new == FAT_ENT_EOF) - new = EOF_FAT12; - - spin_lock(&fat12_entry_lock); - if (fatent->entry & 1) { - *ent12_p[0] = (new << 4) | (*ent12_p[0] & 0x0f); - *ent12_p[1] = new >> 4; - } else { - *ent12_p[0] = new & 0xff; - *ent12_p[1] = (*ent12_p[1] & 0xf0) | (new >> 8); - } - spin_unlock(&fat12_entry_lock); - - mark_buffer_dirty_inode(fatent->bhs[0], fatent->fat_inode); - if (fatent->nr_bhs == 2) - mark_buffer_dirty_inode(fatent->bhs[1], fatent->fat_inode); -} - -static void fat16_ent_put(struct fat_entry *fatent, int new) -{ - if (new == FAT_ENT_EOF) - new = EOF_FAT16; - - *fatent->u.ent16_p = cpu_to_le16(new); - mark_buffer_dirty_inode(fatent->bhs[0], fatent->fat_inode); -} - -static void fat32_ent_put(struct fat_entry *fatent, int new) -{ - WARN_ON(new & 0xf0000000); - new |= le32_to_cpu(*fatent->u.ent32_p) & ~0x0fffffff; - *fatent->u.ent32_p = cpu_to_le32(new); - mark_buffer_dirty_inode(fatent->bhs[0], fatent->fat_inode); -} - -static int fat12_ent_next(struct fat_entry *fatent) -{ - u8 **ent12_p = fatent->u.ent12_p; - struct buffer_head **bhs = fatent->bhs; - u8 *nextp = ent12_p[1] + 1 + (fatent->entry & 1); - - fatent->entry++; - if (fatent->nr_bhs == 1) { - WARN_ON(ent12_p[0] > (u8 *)(bhs[0]->b_data + - (bhs[0]->b_size - 2))); - WARN_ON(ent12_p[1] > (u8 *)(bhs[0]->b_data + - (bhs[0]->b_size - 1))); - if (nextp < (u8 *)(bhs[0]->b_data + (bhs[0]->b_size - 1))) { - ent12_p[0] = nextp - 1; - ent12_p[1] = nextp; - return 1; - } - } else { - WARN_ON(ent12_p[0] != (u8 *)(bhs[0]->b_data + - (bhs[0]->b_size - 1))); - WARN_ON(ent12_p[1] != (u8 *)bhs[1]->b_data); - ent12_p[0] = nextp - 1; - ent12_p[1] = nextp; - brelse(bhs[0]); - bhs[0] = bhs[1]; - fatent->nr_bhs = 1; - return 1; - } - ent12_p[0] = NULL; - ent12_p[1] = NULL; - return 0; -} - -static int fat16_ent_next(struct fat_entry *fatent) -{ - const struct buffer_head *bh = fatent->bhs[0]; - fatent->entry++; - if (fatent->u.ent16_p < (__le16 *)(bh->b_data + (bh->b_size - 2))) { - fatent->u.ent16_p++; - return 1; - } - fatent->u.ent16_p = NULL; - return 0; -} - -static int fat32_ent_next(struct fat_entry *fatent) -{ - const struct buffer_head *bh = fatent->bhs[0]; - fatent->entry++; - if (fatent->u.ent32_p < (__le32 *)(bh->b_data + (bh->b_size - 4))) { - fatent->u.ent32_p++; - return 1; - } - fatent->u.ent32_p = NULL; - return 0; -} - -static const struct fatent_operations fat12_ops = { - .ent_blocknr = fat12_ent_blocknr, - .ent_set_ptr = fat12_ent_set_ptr, - .ent_bread = fat12_ent_bread, - .ent_get = fat12_ent_get, - .ent_put = fat12_ent_put, - .ent_next = fat12_ent_next, -}; - -static const struct fatent_operations fat16_ops = { - .ent_blocknr = fat_ent_blocknr, - .ent_set_ptr = fat16_ent_set_ptr, - .ent_bread = fat_ent_bread, - .ent_get = fat16_ent_get, - .ent_put = fat16_ent_put, - .ent_next = fat16_ent_next, -}; - -static const struct fatent_operations fat32_ops = { - .ent_blocknr = fat_ent_blocknr, - .ent_set_ptr = fat32_ent_set_ptr, - .ent_bread = fat_ent_bread, - .ent_get = fat32_ent_get, - .ent_put = fat32_ent_put, - .ent_next = fat32_ent_next, -}; - -static inline void lock_fat(struct msdos_sb_info *sbi) -{ - mutex_lock(&sbi->fat_lock); -} - -static inline void unlock_fat(struct msdos_sb_info *sbi) -{ - mutex_unlock(&sbi->fat_lock); -} - -void fat_ent_access_init(struct super_block *sb) -{ - struct msdos_sb_info *sbi = MSDOS_SB(sb); - - mutex_init(&sbi->fat_lock); - - switch (sbi->fat_bits) { - case 32: - sbi->fatent_shift = 2; - sbi->fatent_ops = &fat32_ops; - break; - case 16: - sbi->fatent_shift = 1; - sbi->fatent_ops = &fat16_ops; - break; - case 12: - sbi->fatent_shift = -1; - sbi->fatent_ops = &fat12_ops; - break; - } -} - -static void mark_fsinfo_dirty(struct super_block *sb) -{ - struct msdos_sb_info *sbi = MSDOS_SB(sb); - - if (sb->s_flags & MS_RDONLY || sbi->fat_bits != 32) - return; - - __mark_inode_dirty(sbi->fsinfo_inode, I_DIRTY_SYNC); -} - -static inline int fat_ent_update_ptr(struct super_block *sb, - struct fat_entry *fatent, - int offset, sector_t blocknr) -{ - struct msdos_sb_info *sbi = MSDOS_SB(sb); - const struct fatent_operations *ops = sbi->fatent_ops; - struct buffer_head **bhs = fatent->bhs; - - /* Is this fatent's blocks including this entry? */ - if (!fatent->nr_bhs || bhs[0]->b_blocknr != blocknr) - return 0; - if (sbi->fat_bits == 12) { - if ((offset + 1) < sb->s_blocksize) { - /* This entry is on bhs[0]. */ - if (fatent->nr_bhs == 2) { - brelse(bhs[1]); - fatent->nr_bhs = 1; - } - } else { - /* This entry needs the next block. */ - if (fatent->nr_bhs != 2) - return 0; - if (bhs[1]->b_blocknr != (blocknr + 1)) - return 0; - } - } - ops->ent_set_ptr(fatent, offset); - return 1; -} - -int fat_ent_read(struct inode *inode, struct fat_entry *fatent, int entry) -{ - struct super_block *sb = inode->i_sb; - struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); - const struct fatent_operations *ops = sbi->fatent_ops; - int err, offset; - sector_t blocknr; - - if (entry < FAT_START_ENT || sbi->max_cluster <= entry) { - fatent_brelse(fatent); - fat_fs_error(sb, "invalid access to FAT (entry 0x%08x)", entry); - return -EIO; - } - - fatent_set_entry(fatent, entry); - ops->ent_blocknr(sb, entry, &offset, &blocknr); - - if (!fat_ent_update_ptr(sb, fatent, offset, blocknr)) { - fatent_brelse(fatent); - err = ops->ent_bread(sb, fatent, offset, blocknr); - if (err) - return err; - } - return ops->ent_get(fatent); -} - -/* FIXME: We can write the blocks as more big chunk. */ -static int fat_mirror_bhs(struct super_block *sb, struct buffer_head **bhs, - int nr_bhs) -{ - struct msdos_sb_info *sbi = MSDOS_SB(sb); - struct buffer_head *c_bh; - int err, n, copy; - - err = 0; - for (copy = 1; copy < sbi->fats; copy++) { - sector_t backup_fat = sbi->fat_length * copy; - - for (n = 0; n < nr_bhs; n++) { - c_bh = sb_getblk(sb, backup_fat + bhs[n]->b_blocknr); - if (!c_bh) { - err = -ENOMEM; - goto error; - } - memcpy(c_bh->b_data, bhs[n]->b_data, sb->s_blocksize); - set_buffer_uptodate(c_bh); - mark_buffer_dirty_inode(c_bh, sbi->fat_inode); - if (sb->s_flags & MS_SYNCHRONOUS) - err = sync_dirty_buffer(c_bh); - brelse(c_bh); - if (err) - goto error; - } - } -error: - return err; -} - -int fat_ent_write(struct inode *inode, struct fat_entry *fatent, - int new, int wait) -{ - struct super_block *sb = inode->i_sb; - const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; - int err; - - ops->ent_put(fatent, new); - if (wait) { - err = fat_sync_bhs(fatent->bhs, fatent->nr_bhs); - if (err) - return err; - } - return fat_mirror_bhs(sb, fatent->bhs, fatent->nr_bhs); -} - -static inline int fat_ent_next(struct msdos_sb_info *sbi, - struct fat_entry *fatent) -{ - if (sbi->fatent_ops->ent_next(fatent)) { - if (fatent->entry < sbi->max_cluster) - return 1; - } - return 0; -} - -static inline int fat_ent_read_block(struct super_block *sb, - struct fat_entry *fatent) -{ - const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; - sector_t blocknr; - int offset; - - fatent_brelse(fatent); - ops->ent_blocknr(sb, fatent->entry, &offset, &blocknr); - return ops->ent_bread(sb, fatent, offset, blocknr); -} - -static void fat_collect_bhs(struct buffer_head **bhs, int *nr_bhs, - struct fat_entry *fatent) -{ - int n, i; - - for (n = 0; n < fatent->nr_bhs; n++) { - for (i = 0; i < *nr_bhs; i++) { - if (fatent->bhs[n] == bhs[i]) - break; - } - if (i == *nr_bhs) { - get_bh(fatent->bhs[n]); - bhs[i] = fatent->bhs[n]; - (*nr_bhs)++; - } - } -} - -int fat_alloc_clusters(struct inode *inode, int *cluster, int nr_cluster) -{ - struct super_block *sb = inode->i_sb; - struct msdos_sb_info *sbi = MSDOS_SB(sb); - const struct fatent_operations *ops = sbi->fatent_ops; - struct fat_entry fatent, prev_ent; - struct buffer_head *bhs[MAX_BUF_PER_PAGE]; - int i, count, err, nr_bhs, idx_clus; - - BUG_ON(nr_cluster > (MAX_BUF_PER_PAGE / 2)); /* fixed limit */ - - lock_fat(sbi); - if (sbi->free_clusters != -1 && sbi->free_clus_valid && - sbi->free_clusters < nr_cluster) { - unlock_fat(sbi); - return -ENOSPC; - } - - err = nr_bhs = idx_clus = 0; - count = FAT_START_ENT; - fatent_init(&prev_ent); - fatent_init(&fatent); - fatent_set_entry(&fatent, sbi->prev_free + 1); - while (count < sbi->max_cluster) { - if (fatent.entry >= sbi->max_cluster) - fatent.entry = FAT_START_ENT; - fatent_set_entry(&fatent, fatent.entry); - err = fat_ent_read_block(sb, &fatent); - if (err) - goto out; - - /* Find the free entries in a block */ - do { - if (ops->ent_get(&fatent) == FAT_ENT_FREE) { - int entry = fatent.entry; - - /* make the cluster chain */ - ops->ent_put(&fatent, FAT_ENT_EOF); - if (prev_ent.nr_bhs) - ops->ent_put(&prev_ent, entry); - - fat_collect_bhs(bhs, &nr_bhs, &fatent); - - sbi->prev_free = entry; - if (sbi->free_clusters != -1) - sbi->free_clusters--; - - cluster[idx_clus] = entry; - idx_clus++; - if (idx_clus == nr_cluster) - goto out; - - /* - * fat_collect_bhs() gets ref-count of bhs, - * so we can still use the prev_ent. - */ - prev_ent = fatent; - } - count++; - if (count == sbi->max_cluster) - break; - } while (fat_ent_next(sbi, &fatent)); - } - - /* Couldn't allocate the free entries */ - sbi->free_clusters = 0; - sbi->free_clus_valid = 1; - err = -ENOSPC; - -out: - unlock_fat(sbi); - mark_fsinfo_dirty(sb); - fatent_brelse(&fatent); - if (!err) { - if (inode_needs_sync(inode)) - err = fat_sync_bhs(bhs, nr_bhs); - if (!err) - err = fat_mirror_bhs(sb, bhs, nr_bhs); - } - for (i = 0; i < nr_bhs; i++) - brelse(bhs[i]); - - if (err && idx_clus) - fat_free_clusters(inode, cluster[0]); - - return err; -} - -int fat_free_clusters(struct inode *inode, int cluster) -{ - struct super_block *sb = inode->i_sb; - struct msdos_sb_info *sbi = MSDOS_SB(sb); - const struct fatent_operations *ops = sbi->fatent_ops; - struct fat_entry fatent; - struct buffer_head *bhs[MAX_BUF_PER_PAGE]; - int i, err, nr_bhs; - int first_cl = cluster, dirty_fsinfo = 0; - - nr_bhs = 0; - fatent_init(&fatent); - lock_fat(sbi); - do { - cluster = fat_ent_read(inode, &fatent, cluster); - if (cluster < 0) { - err = cluster; - goto error; - } else if (cluster == FAT_ENT_FREE) { - fat_fs_error(sb, "%s: deleting FAT entry beyond EOF", - __func__); - err = -EIO; - goto error; - } - - if (sbi->options.discard) { - /* - * Issue discard for the sectors we no longer - * care about, batching contiguous clusters - * into one request - */ - if (cluster != fatent.entry + 1) { - int nr_clus = fatent.entry - first_cl + 1; - - sb_issue_discard(sb, - fat_clus_to_blknr(sbi, first_cl), - nr_clus * sbi->sec_per_clus, - GFP_NOFS, 0); - - first_cl = cluster; - } - } - - ops->ent_put(&fatent, FAT_ENT_FREE); - if (sbi->free_clusters != -1) { - sbi->free_clusters++; - dirty_fsinfo = 1; - } - - if (nr_bhs + fatent.nr_bhs > MAX_BUF_PER_PAGE) { - if (sb->s_flags & MS_SYNCHRONOUS) { - err = fat_sync_bhs(bhs, nr_bhs); - if (err) - goto error; - } - err = fat_mirror_bhs(sb, bhs, nr_bhs); - if (err) - goto error; - for (i = 0; i < nr_bhs; i++) - brelse(bhs[i]); - nr_bhs = 0; - } - fat_collect_bhs(bhs, &nr_bhs, &fatent); - } while (cluster != FAT_ENT_EOF); - - if (sb->s_flags & MS_SYNCHRONOUS) { - err = fat_sync_bhs(bhs, nr_bhs); - if (err) - goto error; - } - err = fat_mirror_bhs(sb, bhs, nr_bhs); -error: - fatent_brelse(&fatent); - for (i = 0; i < nr_bhs; i++) - brelse(bhs[i]); - unlock_fat(sbi); - if (dirty_fsinfo) - mark_fsinfo_dirty(sb); - - return err; -} -EXPORT_SYMBOL_GPL(fat_free_clusters); - -/* 128kb is the whole sectors for FAT12 and FAT16 */ -#define FAT_READA_SIZE (128 * 1024) - -static void fat_ent_reada(struct super_block *sb, struct fat_entry *fatent, - unsigned long reada_blocks) -{ - const struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; - sector_t blocknr; - int i, offset; - - ops->ent_blocknr(sb, fatent->entry, &offset, &blocknr); - - for (i = 0; i < reada_blocks; i++) - sb_breadahead(sb, blocknr + i); -} - -int fat_count_free_clusters(struct super_block *sb) -{ - struct msdos_sb_info *sbi = MSDOS_SB(sb); - const struct fatent_operations *ops = sbi->fatent_ops; - struct fat_entry fatent; - unsigned long reada_blocks, reada_mask, cur_block; - int err = 0, free; - - lock_fat(sbi); - if (sbi->free_clusters != -1 && sbi->free_clus_valid) - goto out; - - reada_blocks = FAT_READA_SIZE >> sb->s_blocksize_bits; - reada_mask = reada_blocks - 1; - cur_block = 0; - - free = 0; - fatent_init(&fatent); - fatent_set_entry(&fatent, FAT_START_ENT); - while (fatent.entry < sbi->max_cluster) { - /* readahead of fat blocks */ - if ((cur_block & reada_mask) == 0) { - unsigned long rest = sbi->fat_length - cur_block; - fat_ent_reada(sb, &fatent, min(reada_blocks, rest)); - } - cur_block++; - - err = fat_ent_read_block(sb, &fatent); - if (err) - goto out; - - do { - if (ops->ent_get(&fatent) == FAT_ENT_FREE) - free++; - } while (fat_ent_next(sbi, &fatent)); - } - sbi->free_clusters = free; - sbi->free_clus_valid = 1; - mark_fsinfo_dirty(sb); - fatent_brelse(&fatent); -out: - unlock_fat(sbi); - return err; -} diff --git a/src/linux/fs/fat/file.c b/src/linux/fs/fat/file.c deleted file mode 100644 index 3d04b12..0000000 --- a/src/linux/fs/fat/file.c +++ /dev/null @@ -1,521 +0,0 @@ -/* - * linux/fs/fat/file.c - * - * Written 1992,1993 by Werner Almesberger - * - * regular file handling primitives for fat-based filesystems - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "fat.h" - -static long fat_fallocate(struct file *file, int mode, - loff_t offset, loff_t len); - -static int fat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr) -{ - u32 attr; - - inode_lock(inode); - attr = fat_make_attrs(inode); - inode_unlock(inode); - - return put_user(attr, user_attr); -} - -static int fat_ioctl_set_attributes(struct file *file, u32 __user *user_attr) -{ - struct inode *inode = file_inode(file); - struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); - int is_dir = S_ISDIR(inode->i_mode); - u32 attr, oldattr; - struct iattr ia; - int err; - - err = get_user(attr, user_attr); - if (err) - goto out; - - err = mnt_want_write_file(file); - if (err) - goto out; - inode_lock(inode); - - /* - * ATTR_VOLUME and ATTR_DIR cannot be changed; this also - * prevents the user from turning us into a VFAT - * longname entry. Also, we obviously can't set - * any of the NTFS attributes in the high 24 bits. - */ - attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR); - /* Merge in ATTR_VOLUME and ATTR_DIR */ - attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) | - (is_dir ? ATTR_DIR : 0); - oldattr = fat_make_attrs(inode); - - /* Equivalent to a chmod() */ - ia.ia_valid = ATTR_MODE | ATTR_CTIME; - ia.ia_ctime = current_time(inode); - if (is_dir) - ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO); - else { - ia.ia_mode = fat_make_mode(sbi, attr, - S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO)); - } - - /* The root directory has no attributes */ - if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) { - err = -EINVAL; - goto out_unlock_inode; - } - - if (sbi->options.sys_immutable && - ((attr | oldattr) & ATTR_SYS) && - !capable(CAP_LINUX_IMMUTABLE)) { - err = -EPERM; - goto out_unlock_inode; - } - - /* - * The security check is questionable... We single - * out the RO attribute for checking by the security - * module, just because it maps to a file mode. - */ - err = security_inode_setattr(file->f_path.dentry, &ia); - if (err) - goto out_unlock_inode; - - /* This MUST be done before doing anything irreversible... */ - err = fat_setattr(file->f_path.dentry, &ia); - if (err) - goto out_unlock_inode; - - fsnotify_change(file->f_path.dentry, ia.ia_valid); - if (sbi->options.sys_immutable) { - if (attr & ATTR_SYS) - inode->i_flags |= S_IMMUTABLE; - else - inode->i_flags &= ~S_IMMUTABLE; - } - - fat_save_attrs(inode, attr); - mark_inode_dirty(inode); -out_unlock_inode: - inode_unlock(inode); - mnt_drop_write_file(file); -out: - return err; -} - -static int fat_ioctl_get_volume_id(struct inode *inode, u32 __user *user_attr) -{ - struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); - return put_user(sbi->vol_id, user_attr); -} - -long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - struct inode *inode = file_inode(filp); - u32 __user *user_attr = (u32 __user *)arg; - - switch (cmd) { - case FAT_IOCTL_GET_ATTRIBUTES: - return fat_ioctl_get_attributes(inode, user_attr); - case FAT_IOCTL_SET_ATTRIBUTES: - return fat_ioctl_set_attributes(filp, user_attr); - case FAT_IOCTL_GET_VOLUME_ID: - return fat_ioctl_get_volume_id(inode, user_attr); - default: - return -ENOTTY; /* Inappropriate ioctl for device */ - } -} - -#ifdef CONFIG_COMPAT -static long fat_generic_compat_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) - -{ - return fat_generic_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); -} -#endif - -static int fat_file_release(struct inode *inode, struct file *filp) -{ - if ((filp->f_mode & FMODE_WRITE) && - MSDOS_SB(inode->i_sb)->options.flush) { - fat_flush_inodes(inode->i_sb, inode, NULL); - congestion_wait(BLK_RW_ASYNC, HZ/10); - } - return 0; -} - -int fat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) -{ - struct inode *inode = filp->f_mapping->host; - int res, err; - - res = generic_file_fsync(filp, start, end, datasync); - err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping); - - return res ? res : err; -} - - -const struct file_operations fat_file_operations = { - .llseek = generic_file_llseek, - .read_iter = generic_file_read_iter, - .write_iter = generic_file_write_iter, - .mmap = generic_file_mmap, - .release = fat_file_release, - .unlocked_ioctl = fat_generic_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = fat_generic_compat_ioctl, -#endif - .fsync = fat_file_fsync, - .splice_read = generic_file_splice_read, - .fallocate = fat_fallocate, -}; - -static int fat_cont_expand(struct inode *inode, loff_t size) -{ - struct address_space *mapping = inode->i_mapping; - loff_t start = inode->i_size, count = size - inode->i_size; - int err; - - err = generic_cont_expand_simple(inode, size); - if (err) - goto out; - - inode->i_ctime = inode->i_mtime = current_time(inode); - mark_inode_dirty(inode); - if (IS_SYNC(inode)) { - int err2; - - /* - * Opencode syncing since we don't have a file open to use - * standard fsync path. - */ - 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) { - err = filemap_fdatawait_range(mapping, start, - start + count - 1); - } - } -out: - return err; -} - -/* - * Preallocate space for a file. This implements fat's fallocate file - * operation, which gets called from sys_fallocate system call. User - * space requests len bytes at offset. If FALLOC_FL_KEEP_SIZE is set - * we just allocate clusters without zeroing them out. Otherwise we - * allocate and zero out clusters via an expanding truncate. - */ -static long fat_fallocate(struct file *file, int mode, - loff_t offset, loff_t len) -{ - int nr_cluster; /* Number of clusters to be allocated */ - loff_t mm_bytes; /* Number of bytes to be allocated for file */ - loff_t ondisksize; /* block aligned on-disk size in bytes*/ - struct inode *inode = file->f_mapping->host; - struct super_block *sb = inode->i_sb; - struct msdos_sb_info *sbi = MSDOS_SB(sb); - int err = 0; - - /* No support for hole punch or other fallocate flags. */ - if (mode & ~FALLOC_FL_KEEP_SIZE) - return -EOPNOTSUPP; - - /* No support for dir */ - if (!S_ISREG(inode->i_mode)) - return -EOPNOTSUPP; - - inode_lock(inode); - if (mode & FALLOC_FL_KEEP_SIZE) { - ondisksize = inode->i_blocks << 9; - if ((offset + len) <= ondisksize) - goto error; - - /* First compute the number of clusters to be allocated */ - mm_bytes = offset + len - ondisksize; - nr_cluster = (mm_bytes + (sbi->cluster_size - 1)) >> - sbi->cluster_bits; - - /* Start the allocation.We are not zeroing out the clusters */ - while (nr_cluster-- > 0) { - err = fat_add_cluster(inode); - if (err) - goto error; - } - } else { - if ((offset + len) <= i_size_read(inode)) - goto error; - - /* This is just an expanding truncate */ - err = fat_cont_expand(inode, (offset + len)); - } - -error: - inode_unlock(inode); - return err; -} - -/* Free all clusters after the skip'th cluster. */ -static int fat_free(struct inode *inode, int skip) -{ - struct super_block *sb = inode->i_sb; - int err, wait, free_start, i_start, i_logstart; - - if (MSDOS_I(inode)->i_start == 0) - return 0; - - fat_cache_inval_inode(inode); - - wait = IS_DIRSYNC(inode); - i_start = free_start = MSDOS_I(inode)->i_start; - i_logstart = MSDOS_I(inode)->i_logstart; - - /* First, we write the new file size. */ - if (!skip) { - MSDOS_I(inode)->i_start = 0; - MSDOS_I(inode)->i_logstart = 0; - } - MSDOS_I(inode)->i_attrs |= ATTR_ARCH; - inode->i_ctime = inode->i_mtime = current_time(inode); - if (wait) { - err = fat_sync_inode(inode); - if (err) { - MSDOS_I(inode)->i_start = i_start; - MSDOS_I(inode)->i_logstart = i_logstart; - return err; - } - } else - mark_inode_dirty(inode); - - /* Write a new EOF, and get the remaining cluster chain for freeing. */ - if (skip) { - struct fat_entry fatent; - int ret, fclus, dclus; - - ret = fat_get_cluster(inode, skip - 1, &fclus, &dclus); - if (ret < 0) - return ret; - else if (ret == FAT_ENT_EOF) - return 0; - - fatent_init(&fatent); - ret = fat_ent_read(inode, &fatent, dclus); - if (ret == FAT_ENT_EOF) { - fatent_brelse(&fatent); - return 0; - } else if (ret == FAT_ENT_FREE) { - fat_fs_error(sb, - "%s: invalid cluster chain (i_pos %lld)", - __func__, MSDOS_I(inode)->i_pos); - ret = -EIO; - } else if (ret > 0) { - err = fat_ent_write(inode, &fatent, FAT_ENT_EOF, wait); - if (err) - ret = err; - } - fatent_brelse(&fatent); - if (ret < 0) - return ret; - - free_start = ret; - } - inode->i_blocks = skip << (MSDOS_SB(sb)->cluster_bits - 9); - - /* Freeing the remained cluster chain */ - return fat_free_clusters(inode, free_start); -} - -void fat_truncate_blocks(struct inode *inode, loff_t offset) -{ - struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); - const unsigned int cluster_size = sbi->cluster_size; - int nr_clusters; - - /* - * This protects against truncating a file bigger than it was then - * trying to write into the hole. - */ - if (MSDOS_I(inode)->mmu_private > offset) - MSDOS_I(inode)->mmu_private = offset; - - nr_clusters = (offset + (cluster_size - 1)) >> sbi->cluster_bits; - - fat_free(inode, nr_clusters); - fat_flush_inodes(inode->i_sb, inode, NULL); -} - -int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) -{ - struct inode *inode = d_inode(dentry); - generic_fillattr(inode, stat); - stat->blksize = MSDOS_SB(inode->i_sb)->cluster_size; - - if (MSDOS_SB(inode->i_sb)->options.nfs == FAT_NFS_NOSTALE_RO) { - /* Use i_pos for ino. This is used as fileid of nfs. */ - stat->ino = fat_i_pos_read(MSDOS_SB(inode->i_sb), inode); - } - return 0; -} -EXPORT_SYMBOL_GPL(fat_getattr); - -static int fat_sanitize_mode(const struct msdos_sb_info *sbi, - struct inode *inode, umode_t *mode_ptr) -{ - umode_t mask, perm; - - /* - * Note, the basic check is already done by a caller of - * (attr->ia_mode & ~FAT_VALID_MODE) - */ - - if (S_ISREG(inode->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. Of the - * w bits, either all (subject to umask) or none must be present. - * - * If fat_mode_can_hold_ro(inode) is false, can't change w bits. - */ - if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO))) - return -EPERM; - if (fat_mode_can_hold_ro(inode)) { - if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask))) - return -EPERM; - } else { - if ((perm & S_IWUGO) != (S_IWUGO & ~mask)) - return -EPERM; - } - - *mode_ptr &= S_IFMT | perm; - - return 0; -} - -static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode) -{ - umode_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; -} - -#define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET) -/* valid file mode bits */ -#define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO) - -int fat_setattr(struct dentry *dentry, struct iattr *attr) -{ - struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); - struct inode *inode = d_inode(dentry); - unsigned int ia_valid; - int error; - - /* Check for setting the inode time. */ - ia_valid = attr->ia_valid; - if (ia_valid & TIMES_SET_FLAGS) { - if (fat_allow_set_time(sbi, inode)) - attr->ia_valid &= ~TIMES_SET_FLAGS; - } - - error = setattr_prepare(dentry, attr); - attr->ia_valid = ia_valid; - if (error) { - if (sbi->options.quiet) - error = 0; - goto out; - } - - /* - * Expand the file. Since inode_setattr() updates ->i_size - * before calling the ->truncate(), but FAT needs to fill the - * hole before it. XXX: this is no longer true with new truncate - * sequence. - */ - if (attr->ia_valid & ATTR_SIZE) { - inode_dio_wait(inode); - - if (attr->ia_size > inode->i_size) { - error = fat_cont_expand(inode, attr->ia_size); - if (error || attr->ia_valid == ATTR_SIZE) - goto out; - attr->ia_valid &= ~ATTR_SIZE; - } - } - - 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 & ~FAT_VALID_MODE))) - error = -EPERM; - - if (error) { - if (sbi->options.quiet) - error = 0; - goto out; - } - - /* - * We don't return -EPERM here. Yes, strange, but this is too - * old behavior. - */ - if (attr->ia_valid & ATTR_MODE) { - if (fat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0) - attr->ia_valid &= ~ATTR_MODE; - } - - if (attr->ia_valid & ATTR_SIZE) { - error = fat_block_truncate_page(inode, attr->ia_size); - if (error) - goto out; - down_write(&MSDOS_I(inode)->truncate_lock); - truncate_setsize(inode, attr->ia_size); - fat_truncate_blocks(inode, attr->ia_size); - up_write(&MSDOS_I(inode)->truncate_lock); - } - - setattr_copy(inode, attr); - mark_inode_dirty(inode); -out: - return error; -} -EXPORT_SYMBOL_GPL(fat_setattr); - -const struct inode_operations fat_file_inode_operations = { - .setattr = fat_setattr, - .getattr = fat_getattr, -}; diff --git a/src/linux/fs/fat/inode.c b/src/linux/fs/fat/inode.c deleted file mode 100644 index 338d2f7..0000000 --- a/src/linux/fs/fat/inode.c +++ /dev/null @@ -1,1941 +0,0 @@ -/* - * linux/fs/fat/inode.c - * - * Written 1992,1993 by Werner Almesberger - * VFAT extensions by Gordon Chaffee, merged with msdos fs by Henrik Storner - * Rewritten for the constant inumbers support by Al Viro - * - * Fixes: - * - * Max Cohan: Fixed invalid FSINFO offset when info_sector is 0 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "fat.h" - -#ifndef CONFIG_FAT_DEFAULT_IOCHARSET -/* if user don't select VFAT, this is undefined. */ -#define CONFIG_FAT_DEFAULT_IOCHARSET "" -#endif - -#define KB_IN_SECTORS 2 - -/* - * A deserialized copy of the on-disk structure laid out in struct - * fat_boot_sector. - */ -struct fat_bios_param_block { - u16 fat_sector_size; - u8 fat_sec_per_clus; - u16 fat_reserved; - u8 fat_fats; - u16 fat_dir_entries; - u16 fat_sectors; - u16 fat_fat_length; - u32 fat_total_sect; - - u8 fat16_state; - u32 fat16_vol_id; - - u32 fat32_length; - u32 fat32_root_cluster; - u16 fat32_info_sector; - u8 fat32_state; - u32 fat32_vol_id; -}; - -static int fat_default_codepage = CONFIG_FAT_DEFAULT_CODEPAGE; -static char fat_default_iocharset[] = CONFIG_FAT_DEFAULT_IOCHARSET; - -static struct fat_floppy_defaults { - unsigned nr_sectors; - unsigned sec_per_clus; - unsigned dir_entries; - unsigned media; - unsigned fat_length; -} floppy_defaults[] = { -{ - .nr_sectors = 160 * KB_IN_SECTORS, - .sec_per_clus = 1, - .dir_entries = 64, - .media = 0xFE, - .fat_length = 1, -}, -{ - .nr_sectors = 180 * KB_IN_SECTORS, - .sec_per_clus = 1, - .dir_entries = 64, - .media = 0xFC, - .fat_length = 2, -}, -{ - .nr_sectors = 320 * KB_IN_SECTORS, - .sec_per_clus = 2, - .dir_entries = 112, - .media = 0xFF, - .fat_length = 1, -}, -{ - .nr_sectors = 360 * KB_IN_SECTORS, - .sec_per_clus = 2, - .dir_entries = 112, - .media = 0xFD, - .fat_length = 2, -}, -}; - -int fat_add_cluster(struct inode *inode) -{ - int err, cluster; - - err = fat_alloc_clusters(inode, &cluster, 1); - if (err) - return err; - /* FIXME: this cluster should be added after data of this - * cluster is writed */ - err = fat_chain_add(inode, cluster, 1); - if (err) - fat_free_clusters(inode, cluster); - return err; -} - -static inline int __fat_get_block(struct inode *inode, sector_t iblock, - unsigned long *max_blocks, - struct buffer_head *bh_result, int create) -{ - struct super_block *sb = inode->i_sb; - struct msdos_sb_info *sbi = MSDOS_SB(sb); - unsigned long mapped_blocks; - sector_t phys, last_block; - int err, offset; - - err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create, false); - if (err) - return err; - if (phys) { - map_bh(bh_result, sb, phys); - *max_blocks = min(mapped_blocks, *max_blocks); - return 0; - } - if (!create) - return 0; - - if (iblock != MSDOS_I(inode)->mmu_private >> sb->s_blocksize_bits) { - fat_fs_error(sb, "corrupted file size (i_pos %lld, %lld)", - MSDOS_I(inode)->i_pos, MSDOS_I(inode)->mmu_private); - return -EIO; - } - - last_block = inode->i_blocks >> (sb->s_blocksize_bits - 9); - offset = (unsigned long)iblock & (sbi->sec_per_clus - 1); - /* - * allocate a cluster according to the following. - * 1) no more available blocks - * 2) not part of fallocate region - */ - if (!offset && !(iblock < last_block)) { - /* TODO: multiple cluster allocation would be desirable. */ - err = fat_add_cluster(inode); - if (err) - return err; - } - /* available blocks on this cluster */ - mapped_blocks = sbi->sec_per_clus - offset; - - *max_blocks = min(mapped_blocks, *max_blocks); - MSDOS_I(inode)->mmu_private += *max_blocks << sb->s_blocksize_bits; - - err = fat_bmap(inode, iblock, &phys, &mapped_blocks, create, false); - if (err) - return err; - - BUG_ON(!phys); - BUG_ON(*max_blocks != mapped_blocks); - set_buffer_new(bh_result); - map_bh(bh_result, sb, phys); - - return 0; -} - -static int fat_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; - - err = __fat_get_block(inode, iblock, &max_blocks, bh_result, create); - if (err) - return err; - bh_result->b_size = max_blocks << sb->s_blocksize_bits; - return 0; -} - -static int fat_writepage(struct page *page, struct writeback_control *wbc) -{ - return block_write_full_page(page, fat_get_block, wbc); -} - -static int fat_writepages(struct address_space *mapping, - struct writeback_control *wbc) -{ - return mpage_writepages(mapping, wbc, fat_get_block); -} - -static int fat_readpage(struct file *file, struct page *page) -{ - return mpage_readpage(page, fat_get_block); -} - -static int fat_readpages(struct file *file, struct address_space *mapping, - struct list_head *pages, unsigned nr_pages) -{ - return mpage_readpages(mapping, pages, nr_pages, fat_get_block); -} - -static void fat_write_failed(struct address_space *mapping, loff_t to) -{ - struct inode *inode = mapping->host; - - if (to > inode->i_size) { - truncate_pagecache(inode, inode->i_size); - fat_truncate_blocks(inode, inode->i_size); - } -} - -static int fat_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) -{ - int err; - - *pagep = NULL; - err = cont_write_begin(file, mapping, pos, len, flags, - pagep, fsdata, fat_get_block, - &MSDOS_I(mapping->host)->mmu_private); - if (err < 0) - fat_write_failed(mapping, pos + len); - return err; -} - -static int fat_write_end(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *pagep, void *fsdata) -{ - struct inode *inode = mapping->host; - int err; - err = generic_write_end(file, mapping, pos, len, copied, pagep, fsdata); - if (err < len) - fat_write_failed(mapping, pos + len); - if (!(err < 0) && !(MSDOS_I(inode)->i_attrs & ATTR_ARCH)) { - inode->i_mtime = inode->i_ctime = current_time(inode); - MSDOS_I(inode)->i_attrs |= ATTR_ARCH; - mark_inode_dirty(inode); - } - return err; -} - -static ssize_t fat_direct_IO(struct kiocb *iocb, struct iov_iter *iter) -{ - struct file *file = iocb->ki_filp; - struct address_space *mapping = file->f_mapping; - struct inode *inode = mapping->host; - size_t count = iov_iter_count(iter); - loff_t offset = iocb->ki_pos; - ssize_t ret; - - if (iov_iter_rw(iter) == WRITE) { - /* - * FIXME: blockdev_direct_IO() doesn't use ->write_begin(), - * so we need to update the ->mmu_private to block boundary. - * - * But we must fill the remaining area or hole by nul for - * updating ->mmu_private. - * - * Return 0, and fallback to normal buffered write. - */ - loff_t size = offset + count; - if (MSDOS_I(inode)->mmu_private < size) - return 0; - } - - /* - * FAT need to use the DIO_LOCKING for avoiding the race - * condition of fat_get_block() and ->truncate(). - */ - ret = blockdev_direct_IO(iocb, inode, iter, fat_get_block); - if (ret < 0 && iov_iter_rw(iter) == WRITE) - fat_write_failed(mapping, offset + count); - - return ret; -} - -static int fat_get_block_bmap(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; - sector_t bmap; - unsigned long mapped_blocks; - - BUG_ON(create != 0); - - err = fat_bmap(inode, iblock, &bmap, &mapped_blocks, create, true); - if (err) - return err; - - if (bmap) { - map_bh(bh_result, sb, bmap); - max_blocks = min(mapped_blocks, max_blocks); - } - - bh_result->b_size = max_blocks << sb->s_blocksize_bits; - - return 0; -} - -static sector_t _fat_bmap(struct address_space *mapping, sector_t block) -{ - sector_t blocknr; - - /* fat_get_cluster() assumes the requested blocknr isn't truncated. */ - down_read(&MSDOS_I(mapping->host)->truncate_lock); - blocknr = generic_block_bmap(mapping, block, fat_get_block_bmap); - up_read(&MSDOS_I(mapping->host)->truncate_lock); - - return blocknr; -} - -/* - * fat_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 fat_block_truncate_page(struct inode *inode, loff_t from) -{ - return block_truncate_page(inode->i_mapping, from, fat_get_block); -} - -static const struct address_space_operations fat_aops = { - .readpage = fat_readpage, - .readpages = fat_readpages, - .writepage = fat_writepage, - .writepages = fat_writepages, - .write_begin = fat_write_begin, - .write_end = fat_write_end, - .direct_IO = fat_direct_IO, - .bmap = _fat_bmap -}; - -/* - * New FAT inode stuff. We do the following: - * a) i_ino is constant and has nothing with on-disk location. - * b) FAT manages its own cache of directory entries. - * c) *This* cache is indexed by on-disk location. - * d) inode has an associated directory entry, all right, but - * it may be unhashed. - * e) currently entries are stored within struct inode. That should - * change. - * f) we deal with races in the following way: - * 1. readdir() and lookup() do FAT-dir-cache lookup. - * 2. rename() unhashes the F-d-c entry and rehashes it in - * a new place. - * 3. unlink() and rmdir() unhash F-d-c entry. - * 4. fat_write_inode() checks whether the thing is unhashed. - * If it is we silently return. If it isn't we do bread(), - * check if the location is still valid and retry if it - * isn't. Otherwise we do changes. - * 5. Spinlock is used to protect hash/unhash/location check/lookup - * 6. fat_evict_inode() unhashes the F-d-c entry. - * 7. lookup() and readdir() do igrab() if they find a F-d-c entry - * and consider negative result as cache miss. - */ - -static void fat_hash_init(struct super_block *sb) -{ - struct msdos_sb_info *sbi = MSDOS_SB(sb); - int i; - - spin_lock_init(&sbi->inode_hash_lock); - for (i = 0; i < FAT_HASH_SIZE; i++) - INIT_HLIST_HEAD(&sbi->inode_hashtable[i]); -} - -static inline unsigned long fat_hash(loff_t i_pos) -{ - return hash_32(i_pos, FAT_HASH_BITS); -} - -static void dir_hash_init(struct super_block *sb) -{ - struct msdos_sb_info *sbi = MSDOS_SB(sb); - int i; - - spin_lock_init(&sbi->dir_hash_lock); - for (i = 0; i < FAT_HASH_SIZE; i++) - INIT_HLIST_HEAD(&sbi->dir_hashtable[i]); -} - -void fat_attach(struct inode *inode, loff_t i_pos) -{ - struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); - - if (inode->i_ino != MSDOS_ROOT_INO) { - struct hlist_head *head = sbi->inode_hashtable - + fat_hash(i_pos); - - spin_lock(&sbi->inode_hash_lock); - MSDOS_I(inode)->i_pos = i_pos; - hlist_add_head(&MSDOS_I(inode)->i_fat_hash, head); - spin_unlock(&sbi->inode_hash_lock); - } - - /* If NFS support is enabled, cache the mapping of start cluster - * to directory inode. This is used during reconnection of - * dentries to the filesystem root. - */ - if (S_ISDIR(inode->i_mode) && sbi->options.nfs) { - struct hlist_head *d_head = sbi->dir_hashtable; - d_head += fat_dir_hash(MSDOS_I(inode)->i_logstart); - - spin_lock(&sbi->dir_hash_lock); - hlist_add_head(&MSDOS_I(inode)->i_dir_hash, d_head); - spin_unlock(&sbi->dir_hash_lock); - } -} -EXPORT_SYMBOL_GPL(fat_attach); - -void fat_detach(struct inode *inode) -{ - struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); - spin_lock(&sbi->inode_hash_lock); - MSDOS_I(inode)->i_pos = 0; - hlist_del_init(&MSDOS_I(inode)->i_fat_hash); - spin_unlock(&sbi->inode_hash_lock); - - if (S_ISDIR(inode->i_mode) && sbi->options.nfs) { - spin_lock(&sbi->dir_hash_lock); - hlist_del_init(&MSDOS_I(inode)->i_dir_hash); - spin_unlock(&sbi->dir_hash_lock); - } -} -EXPORT_SYMBOL_GPL(fat_detach); - -struct inode *fat_iget(struct super_block *sb, loff_t i_pos) -{ - struct msdos_sb_info *sbi = MSDOS_SB(sb); - struct hlist_head *head = sbi->inode_hashtable + fat_hash(i_pos); - struct msdos_inode_info *i; - struct inode *inode = NULL; - - spin_lock(&sbi->inode_hash_lock); - hlist_for_each_entry(i, head, i_fat_hash) { - BUG_ON(i->vfs_inode.i_sb != sb); - if (i->i_pos != i_pos) - continue; - inode = igrab(&i->vfs_inode); - if (inode) - break; - } - spin_unlock(&sbi->inode_hash_lock); - return inode; -} - -static int is_exec(unsigned char *extension) -{ - unsigned char exe_extensions[] = "EXECOMBAT", *walk; - - for (walk = exe_extensions; *walk; walk += 3) - if (!strncmp(extension, walk, 3)) - return 1; - return 0; -} - -static int fat_calc_dir_size(struct inode *inode) -{ - struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); - int ret, fclus, dclus; - - inode->i_size = 0; - if (MSDOS_I(inode)->i_start == 0) - return 0; - - ret = fat_get_cluster(inode, FAT_ENT_EOF, &fclus, &dclus); - if (ret < 0) - return ret; - inode->i_size = (fclus + 1) << sbi->cluster_bits; - - return 0; -} - -static int fat_validate_dir(struct inode *dir) -{ - struct super_block *sb = dir->i_sb; - - if (dir->i_nlink < 2) { - /* Directory should have "."/".." entries at least. */ - fat_fs_error(sb, "corrupted directory (invalid entries)"); - return -EIO; - } - if (MSDOS_I(dir)->i_start == 0 || - MSDOS_I(dir)->i_start == MSDOS_SB(sb)->root_cluster) { - /* Directory should point valid cluster. */ - fat_fs_error(sb, "corrupted directory (invalid i_start)"); - return -EIO; - } - return 0; -} - -/* doesn't deal with root inode */ -int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) -{ - struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); - int error; - - MSDOS_I(inode)->i_pos = 0; - inode->i_uid = sbi->options.fs_uid; - inode->i_gid = sbi->options.fs_gid; - inode->i_version++; - inode->i_generation = get_seconds(); - - if ((de->attr & ATTR_DIR) && !IS_FREE(de->name)) { - inode->i_generation &= ~1; - inode->i_mode = fat_make_mode(sbi, de->attr, S_IRWXUGO); - inode->i_op = sbi->dir_ops; - inode->i_fop = &fat_dir_operations; - - MSDOS_I(inode)->i_start = fat_get_start(sbi, de); - MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start; - error = fat_calc_dir_size(inode); - if (error < 0) - return error; - MSDOS_I(inode)->mmu_private = inode->i_size; - - set_nlink(inode, fat_subdirs(inode)); - - error = fat_validate_dir(inode); - if (error < 0) - return error; - } else { /* not a directory */ - inode->i_generation |= 1; - inode->i_mode = fat_make_mode(sbi, de->attr, - ((sbi->options.showexec && !is_exec(de->name + 8)) - ? S_IRUGO|S_IWUGO : S_IRWXUGO)); - MSDOS_I(inode)->i_start = fat_get_start(sbi, de); - - MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start; - inode->i_size = le32_to_cpu(de->size); - inode->i_op = &fat_file_inode_operations; - inode->i_fop = &fat_file_operations; - inode->i_mapping->a_ops = &fat_aops; - MSDOS_I(inode)->mmu_private = inode->i_size; - } - if (de->attr & ATTR_SYS) { - if (sbi->options.sys_immutable) - inode->i_flags |= S_IMMUTABLE; - } - fat_save_attrs(inode, de->attr); - - inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) - & ~((loff_t)sbi->cluster_size - 1)) >> 9; - - fat_time_fat2unix(sbi, &inode->i_mtime, de->time, de->date, 0); - if (sbi->options.isvfat) { - fat_time_fat2unix(sbi, &inode->i_ctime, de->ctime, - de->cdate, de->ctime_cs); - fat_time_fat2unix(sbi, &inode->i_atime, 0, de->adate, 0); - } else - inode->i_ctime = inode->i_atime = inode->i_mtime; - - return 0; -} - -static inline void fat_lock_build_inode(struct msdos_sb_info *sbi) -{ - if (sbi->options.nfs == FAT_NFS_NOSTALE_RO) - mutex_lock(&sbi->nfs_build_inode_lock); -} - -static inline void fat_unlock_build_inode(struct msdos_sb_info *sbi) -{ - if (sbi->options.nfs == FAT_NFS_NOSTALE_RO) - mutex_unlock(&sbi->nfs_build_inode_lock); -} - -struct inode *fat_build_inode(struct super_block *sb, - struct msdos_dir_entry *de, loff_t i_pos) -{ - struct inode *inode; - int err; - - fat_lock_build_inode(MSDOS_SB(sb)); - inode = fat_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, MSDOS_ROOT_INO); - inode->i_version = 1; - err = fat_fill_inode(inode, de); - if (err) { - iput(inode); - inode = ERR_PTR(err); - goto out; - } - fat_attach(inode, i_pos); - insert_inode_hash(inode); -out: - fat_unlock_build_inode(MSDOS_SB(sb)); - return inode; -} - -EXPORT_SYMBOL_GPL(fat_build_inode); - -static int __fat_write_inode(struct inode *inode, int wait); - -static void fat_free_eofblocks(struct inode *inode) -{ - /* Release unwritten fallocated blocks on inode eviction. */ - if ((inode->i_blocks << 9) > - round_up(MSDOS_I(inode)->mmu_private, - MSDOS_SB(inode->i_sb)->cluster_size)) { - int err; - - fat_truncate_blocks(inode, MSDOS_I(inode)->mmu_private); - /* Fallocate results in updating the i_start/iogstart - * for the zero byte file. So, make it return to - * original state during evict and commit it to avoid - * any corruption on the next access to the cluster - * chain for the file. - */ - err = __fat_write_inode(inode, inode_needs_sync(inode)); - if (err) { - fat_msg(inode->i_sb, KERN_WARNING, "Failed to " - "update on disk inode for unused " - "fallocated blocks, inode could be " - "corrupted. Please run fsck"); - } - - } -} - -static void fat_evict_inode(struct inode *inode) -{ - truncate_inode_pages_final(&inode->i_data); - if (!inode->i_nlink) { - inode->i_size = 0; - fat_truncate_blocks(inode, 0); - } else - fat_free_eofblocks(inode); - - invalidate_inode_buffers(inode); - clear_inode(inode); - fat_cache_inval_inode(inode); - fat_detach(inode); -} - -static void fat_set_state(struct super_block *sb, - unsigned int set, unsigned int force) -{ - struct buffer_head *bh; - struct fat_boot_sector *b; - struct msdos_sb_info *sbi = MSDOS_SB(sb); - - /* do not change any thing if mounted read only */ - if ((sb->s_flags & MS_RDONLY) && !force) - return; - - /* do not change state if fs was dirty */ - if (sbi->dirty) { - /* warn only on set (mount). */ - if (set) - fat_msg(sb, KERN_WARNING, "Volume was not properly " - "unmounted. Some data may be corrupt. " - "Please run fsck."); - return; - } - - bh = sb_bread(sb, 0); - if (bh == NULL) { - fat_msg(sb, KERN_ERR, "unable to read boot sector " - "to mark fs as dirty"); - return; - } - - b = (struct fat_boot_sector *) bh->b_data; - - if (sbi->fat_bits == 32) { - if (set) - b->fat32.state |= FAT_STATE_DIRTY; - else - b->fat32.state &= ~FAT_STATE_DIRTY; - } else /* fat 16 and 12 */ { - if (set) - b->fat16.state |= FAT_STATE_DIRTY; - else - b->fat16.state &= ~FAT_STATE_DIRTY; - } - - mark_buffer_dirty(bh); - sync_dirty_buffer(bh); - brelse(bh); -} - -static void delayed_free(struct rcu_head *p) -{ - struct msdos_sb_info *sbi = container_of(p, struct msdos_sb_info, rcu); - unload_nls(sbi->nls_disk); - unload_nls(sbi->nls_io); - if (sbi->options.iocharset != fat_default_iocharset) - kfree(sbi->options.iocharset); - kfree(sbi); -} - -static void fat_put_super(struct super_block *sb) -{ - struct msdos_sb_info *sbi = MSDOS_SB(sb); - - fat_set_state(sb, 0, 0); - - iput(sbi->fsinfo_inode); - iput(sbi->fat_inode); - - call_rcu(&sbi->rcu, delayed_free); -} - -static struct kmem_cache *fat_inode_cachep; - -static struct inode *fat_alloc_inode(struct super_block *sb) -{ - struct msdos_inode_info *ei; - ei = kmem_cache_alloc(fat_inode_cachep, GFP_NOFS); - if (!ei) - return NULL; - - init_rwsem(&ei->truncate_lock); - return &ei->vfs_inode; -} - -static void fat_i_callback(struct rcu_head *head) -{ - struct inode *inode = container_of(head, struct inode, i_rcu); - kmem_cache_free(fat_inode_cachep, MSDOS_I(inode)); -} - -static void fat_destroy_inode(struct inode *inode) -{ - call_rcu(&inode->i_rcu, fat_i_callback); -} - -static void init_once(void *foo) -{ - struct msdos_inode_info *ei = (struct msdos_inode_info *)foo; - - spin_lock_init(&ei->cache_lru_lock); - ei->nr_caches = 0; - ei->cache_valid_id = FAT_CACHE_VALID + 1; - INIT_LIST_HEAD(&ei->cache_lru); - INIT_HLIST_NODE(&ei->i_fat_hash); - INIT_HLIST_NODE(&ei->i_dir_hash); - inode_init_once(&ei->vfs_inode); -} - -static int __init fat_init_inodecache(void) -{ - fat_inode_cachep = kmem_cache_create("fat_inode_cache", - sizeof(struct msdos_inode_info), - 0, (SLAB_RECLAIM_ACCOUNT| - SLAB_MEM_SPREAD|SLAB_ACCOUNT), - init_once); - if (fat_inode_cachep == NULL) - return -ENOMEM; - return 0; -} - -static void __exit fat_destroy_inodecache(void) -{ - /* - * Make sure all delayed rcu free inodes are flushed before we - * destroy cache. - */ - rcu_barrier(); - kmem_cache_destroy(fat_inode_cachep); -} - -static int fat_remount(struct super_block *sb, int *flags, char *data) -{ - int new_rdonly; - struct msdos_sb_info *sbi = MSDOS_SB(sb); - *flags |= MS_NODIRATIME | (sbi->options.isvfat ? 0 : MS_NOATIME); - - sync_filesystem(sb); - - /* make sure we update state on remount. */ - new_rdonly = *flags & MS_RDONLY; - if (new_rdonly != (sb->s_flags & MS_RDONLY)) { - if (new_rdonly) - fat_set_state(sb, 0, 0); - else - fat_set_state(sb, 1, 1); - } - return 0; -} - -static int fat_statfs(struct dentry *dentry, struct kstatfs *buf) -{ - struct super_block *sb = dentry->d_sb; - struct msdos_sb_info *sbi = MSDOS_SB(sb); - u64 id = huge_encode_dev(sb->s_bdev->bd_dev); - - /* If the count of free cluster is still unknown, counts it here. */ - if (sbi->free_clusters == -1 || !sbi->free_clus_valid) { - int err = fat_count_free_clusters(dentry->d_sb); - if (err) - return err; - } - - buf->f_type = dentry->d_sb->s_magic; - buf->f_bsize = sbi->cluster_size; - buf->f_blocks = sbi->max_cluster - FAT_START_ENT; - buf->f_bfree = sbi->free_clusters; - buf->f_bavail = sbi->free_clusters; - buf->f_fsid.val[0] = (u32)id; - buf->f_fsid.val[1] = (u32)(id >> 32); - buf->f_namelen = - (sbi->options.isvfat ? FAT_LFN_LEN : 12) * NLS_MAX_CHARSET_SIZE; - - return 0; -} - -static int __fat_write_inode(struct inode *inode, int wait) -{ - struct super_block *sb = inode->i_sb; - struct msdos_sb_info *sbi = MSDOS_SB(sb); - struct buffer_head *bh; - struct msdos_dir_entry *raw_entry; - loff_t i_pos; - sector_t blocknr; - int err, offset; - - if (inode->i_ino == MSDOS_ROOT_INO) - return 0; - -retry: - i_pos = fat_i_pos_read(sbi, inode); - if (!i_pos) - return 0; - - fat_get_blknr_offset(sbi, i_pos, &blocknr, &offset); - bh = sb_bread(sb, blocknr); - if (!bh) { - fat_msg(sb, KERN_ERR, "unable to read inode block " - "for updating (i_pos %lld)", i_pos); - return -EIO; - } - spin_lock(&sbi->inode_hash_lock); - if (i_pos != MSDOS_I(inode)->i_pos) { - spin_unlock(&sbi->inode_hash_lock); - brelse(bh); - goto retry; - } - - raw_entry = &((struct msdos_dir_entry *) (bh->b_data))[offset]; - if (S_ISDIR(inode->i_mode)) - raw_entry->size = 0; - else - raw_entry->size = cpu_to_le32(inode->i_size); - raw_entry->attr = fat_make_attrs(inode); - fat_set_start(raw_entry, MSDOS_I(inode)->i_logstart); - fat_time_unix2fat(sbi, &inode->i_mtime, &raw_entry->time, - &raw_entry->date, NULL); - if (sbi->options.isvfat) { - __le16 atime; - fat_time_unix2fat(sbi, &inode->i_ctime, &raw_entry->ctime, - &raw_entry->cdate, &raw_entry->ctime_cs); - fat_time_unix2fat(sbi, &inode->i_atime, &atime, - &raw_entry->adate, NULL); - } - spin_unlock(&sbi->inode_hash_lock); - mark_buffer_dirty(bh); - err = 0; - if (wait) - err = sync_dirty_buffer(bh); - brelse(bh); - return err; -} - -static int fat_write_inode(struct inode *inode, struct writeback_control *wbc) -{ - int err; - - if (inode->i_ino == MSDOS_FSINFO_INO) { - struct super_block *sb = inode->i_sb; - - mutex_lock(&MSDOS_SB(sb)->s_lock); - err = fat_clusters_flush(sb); - mutex_unlock(&MSDOS_SB(sb)->s_lock); - } else - err = __fat_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL); - - return err; -} - -int fat_sync_inode(struct inode *inode) -{ - return __fat_write_inode(inode, 1); -} - -EXPORT_SYMBOL_GPL(fat_sync_inode); - -static int fat_show_options(struct seq_file *m, struct dentry *root); -static const struct super_operations fat_sops = { - .alloc_inode = fat_alloc_inode, - .destroy_inode = fat_destroy_inode, - .write_inode = fat_write_inode, - .evict_inode = fat_evict_inode, - .put_super = fat_put_super, - .statfs = fat_statfs, - .remount_fs = fat_remount, - - .show_options = fat_show_options, -}; - -static int fat_show_options(struct seq_file *m, struct dentry *root) -{ - struct msdos_sb_info *sbi = MSDOS_SB(root->d_sb); - struct fat_mount_options *opts = &sbi->options; - int isvfat = opts->isvfat; - - 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", 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) - /* strip "cp" prefix from displayed option */ - seq_printf(m, ",codepage=%s", &sbi->nls_disk->charset[2]); - if (isvfat) { - if (sbi->nls_io) - seq_printf(m, ",iocharset=%s", sbi->nls_io->charset); - - switch (opts->shortname) { - case VFAT_SFN_DISPLAY_WIN95 | VFAT_SFN_CREATE_WIN95: - seq_puts(m, ",shortname=win95"); - break; - case VFAT_SFN_DISPLAY_WINNT | VFAT_SFN_CREATE_WINNT: - seq_puts(m, ",shortname=winnt"); - break; - case VFAT_SFN_DISPLAY_WINNT | VFAT_SFN_CREATE_WIN95: - seq_puts(m, ",shortname=mixed"); - break; - case VFAT_SFN_DISPLAY_LOWER | VFAT_SFN_CREATE_WIN95: - seq_puts(m, ",shortname=lower"); - break; - default: - seq_puts(m, ",shortname=unknown"); - break; - } - } - if (opts->name_check != 'n') - seq_printf(m, ",check=%c", opts->name_check); - if (opts->usefree) - seq_puts(m, ",usefree"); - if (opts->quiet) - seq_puts(m, ",quiet"); - if (opts->showexec) - seq_puts(m, ",showexec"); - if (opts->sys_immutable) - seq_puts(m, ",sys_immutable"); - if (!isvfat) { - if (opts->dotsOK) - seq_puts(m, ",dotsOK=yes"); - if (opts->nocase) - seq_puts(m, ",nocase"); - } else { - if (opts->utf8) - seq_puts(m, ",utf8"); - if (opts->unicode_xlate) - seq_puts(m, ",uni_xlate"); - if (!opts->numtail) - seq_puts(m, ",nonumtail"); - if (opts->rodir) - seq_puts(m, ",rodir"); - } - if (opts->flush) - seq_puts(m, ",flush"); - if (opts->tz_set) { - if (opts->time_offset) - seq_printf(m, ",time_offset=%d", opts->time_offset); - else - seq_puts(m, ",tz=UTC"); - } - if (opts->errors == FAT_ERRORS_CONT) - seq_puts(m, ",errors=continue"); - else if (opts->errors == FAT_ERRORS_PANIC) - seq_puts(m, ",errors=panic"); - else - seq_puts(m, ",errors=remount-ro"); - if (opts->nfs == FAT_NFS_NOSTALE_RO) - seq_puts(m, ",nfs=nostale_ro"); - else if (opts->nfs) - seq_puts(m, ",nfs=stale_rw"); - if (opts->discard) - seq_puts(m, ",discard"); - if (opts->dos1xfloppy) - seq_puts(m, ",dos1xfloppy"); - - return 0; -} - -enum { - Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid, - Opt_umask, Opt_dmask, Opt_fmask, Opt_allow_utime, Opt_codepage, - Opt_usefree, Opt_nocase, Opt_quiet, Opt_showexec, Opt_debug, - Opt_immutable, Opt_dots, Opt_nodots, - Opt_charset, Opt_shortname_lower, Opt_shortname_win95, - Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, - Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, - Opt_obsolete, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont, - Opt_err_panic, Opt_err_ro, Opt_discard, Opt_nfs, Opt_time_offset, - Opt_nfs_stale_rw, Opt_nfs_nostale_ro, Opt_err, Opt_dos1xfloppy, -}; - -static const match_table_t fat_tokens = { - {Opt_check_r, "check=relaxed"}, - {Opt_check_s, "check=strict"}, - {Opt_check_n, "check=normal"}, - {Opt_check_r, "check=r"}, - {Opt_check_s, "check=s"}, - {Opt_check_n, "check=n"}, - {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_usefree, "usefree"}, - {Opt_nocase, "nocase"}, - {Opt_quiet, "quiet"}, - {Opt_showexec, "showexec"}, - {Opt_debug, "debug"}, - {Opt_immutable, "sys_immutable"}, - {Opt_flush, "flush"}, - {Opt_tz_utc, "tz=UTC"}, - {Opt_time_offset, "time_offset=%d"}, - {Opt_err_cont, "errors=continue"}, - {Opt_err_panic, "errors=panic"}, - {Opt_err_ro, "errors=remount-ro"}, - {Opt_discard, "discard"}, - {Opt_nfs_stale_rw, "nfs"}, - {Opt_nfs_stale_rw, "nfs=stale_rw"}, - {Opt_nfs_nostale_ro, "nfs=nostale_ro"}, - {Opt_dos1xfloppy, "dos1xfloppy"}, - {Opt_obsolete, "conv=binary"}, - {Opt_obsolete, "conv=text"}, - {Opt_obsolete, "conv=auto"}, - {Opt_obsolete, "conv=b"}, - {Opt_obsolete, "conv=t"}, - {Opt_obsolete, "conv=a"}, - {Opt_obsolete, "fat=%u"}, - {Opt_obsolete, "blocksize=%u"}, - {Opt_obsolete, "cvf_format=%20s"}, - {Opt_obsolete, "cvf_options=%100s"}, - {Opt_obsolete, "posix"}, - {Opt_err, NULL}, -}; -static const match_table_t msdos_tokens = { - {Opt_nodots, "nodots"}, - {Opt_nodots, "dotsOK=no"}, - {Opt_dots, "dots"}, - {Opt_dots, "dotsOK=yes"}, - {Opt_err, NULL} -}; -static const match_table_t vfat_tokens = { - {Opt_charset, "iocharset=%s"}, - {Opt_shortname_lower, "shortname=lower"}, - {Opt_shortname_win95, "shortname=win95"}, - {Opt_shortname_winnt, "shortname=winnt"}, - {Opt_shortname_mixed, "shortname=mixed"}, - {Opt_utf8_no, "utf8=0"}, /* 0 or no or false */ - {Opt_utf8_no, "utf8=no"}, - {Opt_utf8_no, "utf8=false"}, - {Opt_utf8_yes, "utf8=1"}, /* empty or 1 or yes or true */ - {Opt_utf8_yes, "utf8=yes"}, - {Opt_utf8_yes, "utf8=true"}, - {Opt_utf8_yes, "utf8"}, - {Opt_uni_xl_no, "uni_xlate=0"}, /* 0 or no or false */ - {Opt_uni_xl_no, "uni_xlate=no"}, - {Opt_uni_xl_no, "uni_xlate=false"}, - {Opt_uni_xl_yes, "uni_xlate=1"}, /* empty or 1 or yes or true */ - {Opt_uni_xl_yes, "uni_xlate=yes"}, - {Opt_uni_xl_yes, "uni_xlate=true"}, - {Opt_uni_xl_yes, "uni_xlate"}, - {Opt_nonumtail_no, "nonumtail=0"}, /* 0 or no or false */ - {Opt_nonumtail_no, "nonumtail=no"}, - {Opt_nonumtail_no, "nonumtail=false"}, - {Opt_nonumtail_yes, "nonumtail=1"}, /* empty or 1 or yes or true */ - {Opt_nonumtail_yes, "nonumtail=yes"}, - {Opt_nonumtail_yes, "nonumtail=true"}, - {Opt_nonumtail_yes, "nonumtail"}, - {Opt_rodir, "rodir"}, - {Opt_err, NULL} -}; - -static int parse_options(struct super_block *sb, char *options, int is_vfat, - int silent, int *debug, struct fat_mount_options *opts) -{ - char *p; - substring_t args[MAX_OPT_ARGS]; - int option; - char *iocharset; - - opts->isvfat = is_vfat; - - opts->fs_uid = current_uid(); - opts->fs_gid = current_gid(); - opts->fs_fmask = opts->fs_dmask = current_umask(); - opts->allow_utime = -1; - opts->codepage = fat_default_codepage; - opts->iocharset = fat_default_iocharset; - if (is_vfat) { - opts->shortname = VFAT_SFN_DISPLAY_WINNT|VFAT_SFN_CREATE_WIN95; - opts->rodir = 0; - } else { - opts->shortname = 0; - opts->rodir = 1; - } - opts->name_check = 'n'; - opts->quiet = opts->showexec = opts->sys_immutable = opts->dotsOK = 0; - opts->unicode_xlate = 0; - opts->numtail = 1; - opts->usefree = opts->nocase = 0; - opts->tz_set = 0; - opts->nfs = 0; - opts->errors = FAT_ERRORS_RO; - *debug = 0; - - opts->utf8 = IS_ENABLED(CONFIG_FAT_DEFAULT_UTF8) && is_vfat; - - if (!options) - goto out; - - while ((p = strsep(&options, ",")) != NULL) { - int token; - if (!*p) - continue; - - token = match_token(p, fat_tokens, args); - if (token == Opt_err) { - if (is_vfat) - token = match_token(p, vfat_tokens, args); - else - token = match_token(p, msdos_tokens, args); - } - switch (token) { - case Opt_check_s: - opts->name_check = 's'; - break; - case Opt_check_r: - opts->name_check = 'r'; - break; - case Opt_check_n: - opts->name_check = 'n'; - break; - case Opt_usefree: - opts->usefree = 1; - break; - case Opt_nocase: - if (!is_vfat) - opts->nocase = 1; - else { - /* for backward compatibility */ - opts->shortname = VFAT_SFN_DISPLAY_WIN95 - | VFAT_SFN_CREATE_WIN95; - } - break; - case Opt_quiet: - opts->quiet = 1; - break; - case Opt_showexec: - opts->showexec = 1; - break; - case Opt_debug: - *debug = 1; - break; - case Opt_immutable: - opts->sys_immutable = 1; - break; - case Opt_uid: - if (match_int(&args[0], &option)) - return -EINVAL; - opts->fs_uid = make_kuid(current_user_ns(), option); - if (!uid_valid(opts->fs_uid)) - return -EINVAL; - break; - case Opt_gid: - if (match_int(&args[0], &option)) - return -EINVAL; - opts->fs_gid = make_kgid(current_user_ns(), option); - if (!gid_valid(opts->fs_gid)) - return -EINVAL; - break; - case Opt_umask: - if (match_octal(&args[0], &option)) - return -EINVAL; - opts->fs_fmask = opts->fs_dmask = option; - break; - case Opt_dmask: - if (match_octal(&args[0], &option)) - return -EINVAL; - opts->fs_dmask = option; - break; - case Opt_fmask: - if (match_octal(&args[0], &option)) - return -EINVAL; - opts->fs_fmask = option; - break; - case Opt_allow_utime: - if (match_octal(&args[0], &option)) - return -EINVAL; - opts->allow_utime = option & (S_IWGRP | S_IWOTH); - break; - case Opt_codepage: - if (match_int(&args[0], &option)) - return -EINVAL; - opts->codepage = option; - break; - case Opt_flush: - opts->flush = 1; - break; - case Opt_time_offset: - if (match_int(&args[0], &option)) - return -EINVAL; - /* - * GMT+-12 zones may have DST corrections so at least - * 13 hours difference is needed. Make the limit 24 - * just in case someone invents something unusual. - */ - if (option < -24 * 60 || option > 24 * 60) - return -EINVAL; - opts->tz_set = 1; - opts->time_offset = option; - break; - case Opt_tz_utc: - opts->tz_set = 1; - opts->time_offset = 0; - break; - case Opt_err_cont: - opts->errors = FAT_ERRORS_CONT; - break; - case Opt_err_panic: - opts->errors = FAT_ERRORS_PANIC; - break; - case Opt_err_ro: - opts->errors = FAT_ERRORS_RO; - break; - case Opt_nfs_stale_rw: - opts->nfs = FAT_NFS_STALE_RW; - break; - case Opt_nfs_nostale_ro: - opts->nfs = FAT_NFS_NOSTALE_RO; - break; - case Opt_dos1xfloppy: - opts->dos1xfloppy = 1; - break; - - /* msdos specific */ - case Opt_dots: - opts->dotsOK = 1; - break; - case Opt_nodots: - opts->dotsOK = 0; - break; - - /* vfat specific */ - case Opt_charset: - if (opts->iocharset != fat_default_iocharset) - kfree(opts->iocharset); - iocharset = match_strdup(&args[0]); - if (!iocharset) - return -ENOMEM; - opts->iocharset = iocharset; - break; - case Opt_shortname_lower: - opts->shortname = VFAT_SFN_DISPLAY_LOWER - | VFAT_SFN_CREATE_WIN95; - break; - case Opt_shortname_win95: - opts->shortname = VFAT_SFN_DISPLAY_WIN95 - | VFAT_SFN_CREATE_WIN95; - break; - case Opt_shortname_winnt: - opts->shortname = VFAT_SFN_DISPLAY_WINNT - | VFAT_SFN_CREATE_WINNT; - break; - case Opt_shortname_mixed: - opts->shortname = VFAT_SFN_DISPLAY_WINNT - | VFAT_SFN_CREATE_WIN95; - break; - case Opt_utf8_no: /* 0 or no or false */ - opts->utf8 = 0; - break; - case Opt_utf8_yes: /* empty or 1 or yes or true */ - opts->utf8 = 1; - break; - case Opt_uni_xl_no: /* 0 or no or false */ - opts->unicode_xlate = 0; - break; - case Opt_uni_xl_yes: /* empty or 1 or yes or true */ - opts->unicode_xlate = 1; - break; - case Opt_nonumtail_no: /* 0 or no or false */ - opts->numtail = 1; /* negated option */ - break; - case Opt_nonumtail_yes: /* empty or 1 or yes or true */ - opts->numtail = 0; /* negated option */ - break; - case Opt_rodir: - opts->rodir = 1; - break; - case Opt_discard: - opts->discard = 1; - break; - - /* obsolete mount options */ - case Opt_obsolete: - fat_msg(sb, KERN_INFO, "\"%s\" option is obsolete, " - "not supported now", p); - break; - /* unknown option */ - default: - if (!silent) { - fat_msg(sb, KERN_ERR, - "Unrecognized mount option \"%s\" " - "or missing value", p); - } - return -EINVAL; - } - } - -out: - /* UTF-8 doesn't provide FAT semantics */ - if (!strcmp(opts->iocharset, "utf8")) { - fat_msg(sb, KERN_WARNING, "utf8 is not a recommended IO charset" - " for FAT filesystems, filesystem will be " - "case sensitive!"); - } - - /* If user doesn't specify allow_utime, it's initialized from dmask. */ - if (opts->allow_utime == (unsigned short)-1) - opts->allow_utime = ~opts->fs_dmask & (S_IWGRP | S_IWOTH); - if (opts->unicode_xlate) - opts->utf8 = 0; - if (opts->nfs == FAT_NFS_NOSTALE_RO) { - sb->s_flags |= MS_RDONLY; - sb->s_export_op = &fat_export_ops_nostale; - } - - return 0; -} - -static int fat_read_root(struct inode *inode) -{ - struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); - int error; - - MSDOS_I(inode)->i_pos = MSDOS_ROOT_INO; - inode->i_uid = sbi->options.fs_uid; - inode->i_gid = sbi->options.fs_gid; - inode->i_version++; - inode->i_generation = 0; - inode->i_mode = fat_make_mode(sbi, ATTR_DIR, S_IRWXUGO); - inode->i_op = sbi->dir_ops; - inode->i_fop = &fat_dir_operations; - if (sbi->fat_bits == 32) { - MSDOS_I(inode)->i_start = sbi->root_cluster; - error = fat_calc_dir_size(inode); - if (error < 0) - return error; - } else { - MSDOS_I(inode)->i_start = 0; - inode->i_size = sbi->dir_entries * sizeof(struct msdos_dir_entry); - } - inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) - & ~((loff_t)sbi->cluster_size - 1)) >> 9; - MSDOS_I(inode)->i_logstart = 0; - MSDOS_I(inode)->mmu_private = inode->i_size; - - fat_save_attrs(inode, ATTR_DIR); - inode->i_mtime.tv_sec = inode->i_atime.tv_sec = inode->i_ctime.tv_sec = 0; - inode->i_mtime.tv_nsec = inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = 0; - set_nlink(inode, fat_subdirs(inode)+2); - - return 0; -} - -static unsigned long calc_fat_clusters(struct super_block *sb) -{ - struct msdos_sb_info *sbi = MSDOS_SB(sb); - - /* Divide first to avoid overflow */ - if (sbi->fat_bits != 12) { - unsigned long ent_per_sec = sb->s_blocksize * 8 / sbi->fat_bits; - return ent_per_sec * sbi->fat_length; - } - - return sbi->fat_length * sb->s_blocksize * 8 / sbi->fat_bits; -} - -static bool fat_bpb_is_zero(struct fat_boot_sector *b) -{ - if (get_unaligned_le16(&b->sector_size)) - return false; - if (b->sec_per_clus) - return false; - if (b->reserved) - return false; - if (b->fats) - return false; - if (get_unaligned_le16(&b->dir_entries)) - return false; - if (get_unaligned_le16(&b->sectors)) - return false; - if (b->media) - return false; - if (b->fat_length) - return false; - if (b->secs_track) - return false; - if (b->heads) - return false; - return true; -} - -static int fat_read_bpb(struct super_block *sb, struct fat_boot_sector *b, - int silent, struct fat_bios_param_block *bpb) -{ - int error = -EINVAL; - - /* Read in BPB ... */ - memset(bpb, 0, sizeof(*bpb)); - bpb->fat_sector_size = get_unaligned_le16(&b->sector_size); - bpb->fat_sec_per_clus = b->sec_per_clus; - bpb->fat_reserved = le16_to_cpu(b->reserved); - bpb->fat_fats = b->fats; - bpb->fat_dir_entries = get_unaligned_le16(&b->dir_entries); - bpb->fat_sectors = get_unaligned_le16(&b->sectors); - bpb->fat_fat_length = le16_to_cpu(b->fat_length); - bpb->fat_total_sect = le32_to_cpu(b->total_sect); - - bpb->fat16_state = b->fat16.state; - bpb->fat16_vol_id = get_unaligned_le32(b->fat16.vol_id); - - bpb->fat32_length = le32_to_cpu(b->fat32.length); - bpb->fat32_root_cluster = le32_to_cpu(b->fat32.root_cluster); - bpb->fat32_info_sector = le16_to_cpu(b->fat32.info_sector); - bpb->fat32_state = b->fat32.state; - bpb->fat32_vol_id = get_unaligned_le32(b->fat32.vol_id); - - /* Validate this looks like a FAT filesystem BPB */ - if (!bpb->fat_reserved) { - if (!silent) - fat_msg(sb, KERN_ERR, - "bogus number of reserved sectors"); - goto out; - } - if (!bpb->fat_fats) { - if (!silent) - fat_msg(sb, KERN_ERR, "bogus number of FAT structure"); - goto out; - } - - /* - * Earlier we checked here that b->secs_track and b->head are nonzero, - * but it turns out valid FAT filesystems can have zero there. - */ - - if (!fat_valid_media(b->media)) { - if (!silent) - fat_msg(sb, KERN_ERR, "invalid media value (0x%02x)", - (unsigned)b->media); - goto out; - } - - if (!is_power_of_2(bpb->fat_sector_size) - || (bpb->fat_sector_size < 512) - || (bpb->fat_sector_size > 4096)) { - if (!silent) - fat_msg(sb, KERN_ERR, "bogus logical sector size %u", - (unsigned)bpb->fat_sector_size); - goto out; - } - - if (!is_power_of_2(bpb->fat_sec_per_clus)) { - if (!silent) - fat_msg(sb, KERN_ERR, "bogus sectors per cluster %u", - (unsigned)bpb->fat_sec_per_clus); - goto out; - } - - error = 0; - -out: - return error; -} - -static int fat_read_static_bpb(struct super_block *sb, - struct fat_boot_sector *b, int silent, - struct fat_bios_param_block *bpb) -{ - static const char *notdos1x = "This doesn't look like a DOS 1.x volume"; - - struct fat_floppy_defaults *fdefaults = NULL; - int error = -EINVAL; - sector_t bd_sects; - unsigned i; - - bd_sects = i_size_read(sb->s_bdev->bd_inode) / SECTOR_SIZE; - - /* 16-bit DOS 1.x reliably wrote bootstrap short-jmp code */ - if (b->ignored[0] != 0xeb || b->ignored[2] != 0x90) { - if (!silent) - fat_msg(sb, KERN_ERR, - "%s; no bootstrapping code", notdos1x); - goto out; - } - - /* - * If any value in this region is non-zero, it isn't archaic - * DOS. - */ - if (!fat_bpb_is_zero(b)) { - if (!silent) - fat_msg(sb, KERN_ERR, - "%s; DOS 2.x BPB is non-zero", notdos1x); - goto out; - } - - for (i = 0; i < ARRAY_SIZE(floppy_defaults); i++) { - if (floppy_defaults[i].nr_sectors == bd_sects) { - fdefaults = &floppy_defaults[i]; - break; - } - } - - if (fdefaults == NULL) { - if (!silent) - fat_msg(sb, KERN_WARNING, - "This looks like a DOS 1.x volume, but isn't a recognized floppy size (%llu sectors)", - (u64)bd_sects); - goto out; - } - - if (!silent) - fat_msg(sb, KERN_INFO, - "This looks like a DOS 1.x volume; assuming default BPB values"); - - memset(bpb, 0, sizeof(*bpb)); - bpb->fat_sector_size = SECTOR_SIZE; - bpb->fat_sec_per_clus = fdefaults->sec_per_clus; - bpb->fat_reserved = 1; - bpb->fat_fats = 2; - bpb->fat_dir_entries = fdefaults->dir_entries; - bpb->fat_sectors = fdefaults->nr_sectors; - bpb->fat_fat_length = fdefaults->fat_length; - - error = 0; - -out: - return error; -} - -/* - * Read the super block of an MS-DOS FS. - */ -int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat, - void (*setup)(struct super_block *)) -{ - struct inode *root_inode = NULL, *fat_inode = NULL; - struct inode *fsinfo_inode = NULL; - struct buffer_head *bh; - struct fat_bios_param_block bpb; - struct msdos_sb_info *sbi; - u16 logical_sector_size; - u32 total_sectors, total_clusters, fat_clusters, rootdir_sectors; - int debug; - long error; - char buf[50]; - - /* - * GFP_KERNEL is ok here, because while we do hold the - * superblock 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 = kzalloc(sizeof(struct msdos_sb_info), GFP_KERNEL); - if (!sbi) - return -ENOMEM; - sb->s_fs_info = sbi; - - sb->s_flags |= MS_NODIRATIME; - sb->s_magic = MSDOS_SUPER_MAGIC; - sb->s_op = &fat_sops; - sb->s_export_op = &fat_export_ops; - mutex_init(&sbi->nfs_build_inode_lock); - ratelimit_state_init(&sbi->ratelimit, DEFAULT_RATELIMIT_INTERVAL, - DEFAULT_RATELIMIT_BURST); - - error = parse_options(sb, data, isvfat, silent, &debug, &sbi->options); - if (error) - goto out_fail; - - setup(sb); /* flavour-specific stuff that needs options */ - - error = -EIO; - sb_min_blocksize(sb, 512); - bh = sb_bread(sb, 0); - if (bh == NULL) { - fat_msg(sb, KERN_ERR, "unable to read boot sector"); - goto out_fail; - } - - error = fat_read_bpb(sb, (struct fat_boot_sector *)bh->b_data, silent, - &bpb); - if (error == -EINVAL && sbi->options.dos1xfloppy) - error = fat_read_static_bpb(sb, - (struct fat_boot_sector *)bh->b_data, silent, &bpb); - brelse(bh); - - if (error == -EINVAL) - goto out_invalid; - else if (error) - goto out_fail; - - logical_sector_size = bpb.fat_sector_size; - sbi->sec_per_clus = bpb.fat_sec_per_clus; - - error = -EIO; - if (logical_sector_size < sb->s_blocksize) { - fat_msg(sb, KERN_ERR, "logical sector size too small for device" - " (logical sector size = %u)", logical_sector_size); - goto out_fail; - } - - if (logical_sector_size > sb->s_blocksize) { - struct buffer_head *bh_resize; - - if (!sb_set_blocksize(sb, logical_sector_size)) { - fat_msg(sb, KERN_ERR, "unable to set blocksize %u", - logical_sector_size); - goto out_fail; - } - - /* Verify that the larger boot sector is fully readable */ - bh_resize = sb_bread(sb, 0); - if (bh_resize == NULL) { - fat_msg(sb, KERN_ERR, "unable to read boot sector" - " (logical sector size = %lu)", - sb->s_blocksize); - goto out_fail; - } - brelse(bh_resize); - } - - mutex_init(&sbi->s_lock); - sbi->cluster_size = sb->s_blocksize * sbi->sec_per_clus; - sbi->cluster_bits = ffs(sbi->cluster_size) - 1; - sbi->fats = bpb.fat_fats; - sbi->fat_bits = 0; /* Don't know yet */ - sbi->fat_start = bpb.fat_reserved; - sbi->fat_length = bpb.fat_fat_length; - sbi->root_cluster = 0; - sbi->free_clusters = -1; /* Don't know yet */ - sbi->free_clus_valid = 0; - sbi->prev_free = FAT_START_ENT; - sb->s_maxbytes = 0xffffffff; - - if (!sbi->fat_length && bpb.fat32_length) { - struct fat_boot_fsinfo *fsinfo; - struct buffer_head *fsinfo_bh; - - /* Must be FAT32 */ - sbi->fat_bits = 32; - sbi->fat_length = bpb.fat32_length; - sbi->root_cluster = bpb.fat32_root_cluster; - - /* MC - if info_sector is 0, don't multiply by 0 */ - sbi->fsinfo_sector = bpb.fat32_info_sector; - if (sbi->fsinfo_sector == 0) - sbi->fsinfo_sector = 1; - - fsinfo_bh = sb_bread(sb, sbi->fsinfo_sector); - if (fsinfo_bh == NULL) { - fat_msg(sb, KERN_ERR, "bread failed, FSINFO block" - " (sector = %lu)", sbi->fsinfo_sector); - goto out_fail; - } - - fsinfo = (struct fat_boot_fsinfo *)fsinfo_bh->b_data; - if (!IS_FSINFO(fsinfo)) { - fat_msg(sb, KERN_WARNING, "Invalid FSINFO signature: " - "0x%08x, 0x%08x (sector = %lu)", - le32_to_cpu(fsinfo->signature1), - le32_to_cpu(fsinfo->signature2), - sbi->fsinfo_sector); - } else { - if (sbi->options.usefree) - sbi->free_clus_valid = 1; - sbi->free_clusters = le32_to_cpu(fsinfo->free_clusters); - sbi->prev_free = le32_to_cpu(fsinfo->next_cluster); - } - - brelse(fsinfo_bh); - } - - /* interpret volume ID as a little endian 32 bit integer */ - if (sbi->fat_bits == 32) - sbi->vol_id = bpb.fat32_vol_id; - else /* fat 16 or 12 */ - sbi->vol_id = bpb.fat16_vol_id; - - sbi->dir_per_block = sb->s_blocksize / sizeof(struct msdos_dir_entry); - sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1; - - sbi->dir_start = sbi->fat_start + sbi->fats * sbi->fat_length; - sbi->dir_entries = bpb.fat_dir_entries; - if (sbi->dir_entries & (sbi->dir_per_block - 1)) { - if (!silent) - fat_msg(sb, KERN_ERR, "bogus number of directory entries" - " (%u)", sbi->dir_entries); - goto out_invalid; - } - - rootdir_sectors = sbi->dir_entries - * sizeof(struct msdos_dir_entry) / sb->s_blocksize; - sbi->data_start = sbi->dir_start + rootdir_sectors; - total_sectors = bpb.fat_sectors; - if (total_sectors == 0) - total_sectors = bpb.fat_total_sect; - - total_clusters = (total_sectors - sbi->data_start) / sbi->sec_per_clus; - - if (sbi->fat_bits != 32) - sbi->fat_bits = (total_clusters > MAX_FAT12) ? 16 : 12; - - /* some OSes set FAT_STATE_DIRTY and clean it on unmount. */ - if (sbi->fat_bits == 32) - sbi->dirty = bpb.fat32_state & FAT_STATE_DIRTY; - else /* fat 16 or 12 */ - sbi->dirty = bpb.fat16_state & FAT_STATE_DIRTY; - - /* check that FAT table does not overflow */ - fat_clusters = calc_fat_clusters(sb); - total_clusters = min(total_clusters, fat_clusters - FAT_START_ENT); - if (total_clusters > MAX_FAT(sb)) { - if (!silent) - fat_msg(sb, KERN_ERR, "count of clusters too big (%u)", - total_clusters); - goto out_invalid; - } - - sbi->max_cluster = total_clusters + FAT_START_ENT; - /* check the free_clusters, it's not necessarily correct */ - if (sbi->free_clusters != -1 && sbi->free_clusters > total_clusters) - sbi->free_clusters = -1; - /* check the prev_free, it's not necessarily correct */ - sbi->prev_free %= sbi->max_cluster; - if (sbi->prev_free < FAT_START_ENT) - sbi->prev_free = FAT_START_ENT; - - /* set up enough so that it can read an inode */ - fat_hash_init(sb); - dir_hash_init(sb); - fat_ent_access_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) - */ - - error = -EINVAL; - sprintf(buf, "cp%d", sbi->options.codepage); - sbi->nls_disk = load_nls(buf); - if (!sbi->nls_disk) { - fat_msg(sb, KERN_ERR, "codepage %s not found", buf); - goto out_fail; - } - - /* FIXME: utf8 is using iocharset for upper/lower conversion */ - if (sbi->options.isvfat) { - sbi->nls_io = load_nls(sbi->options.iocharset); - if (!sbi->nls_io) { - fat_msg(sb, KERN_ERR, "IO charset %s not found", - sbi->options.iocharset); - goto out_fail; - } - } - - error = -ENOMEM; - fat_inode = new_inode(sb); - if (!fat_inode) - goto out_fail; - MSDOS_I(fat_inode)->i_pos = 0; - sbi->fat_inode = fat_inode; - - fsinfo_inode = new_inode(sb); - if (!fsinfo_inode) - goto out_fail; - fsinfo_inode->i_ino = MSDOS_FSINFO_INO; - sbi->fsinfo_inode = fsinfo_inode; - insert_inode_hash(fsinfo_inode); - - root_inode = new_inode(sb); - if (!root_inode) - goto out_fail; - root_inode->i_ino = MSDOS_ROOT_INO; - root_inode->i_version = 1; - error = fat_read_root(root_inode); - if (error < 0) { - iput(root_inode); - goto out_fail; - } - error = -ENOMEM; - insert_inode_hash(root_inode); - fat_attach(root_inode, 0); - sb->s_root = d_make_root(root_inode); - if (!sb->s_root) { - fat_msg(sb, KERN_ERR, "get root inode failed"); - goto out_fail; - } - - if (sbi->options.discard) { - struct request_queue *q = bdev_get_queue(sb->s_bdev); - if (!blk_queue_discard(q)) - fat_msg(sb, KERN_WARNING, - "mounting with \"discard\" option, but " - "the device does not support discard"); - } - - fat_set_state(sb, 1, 0); - return 0; - -out_invalid: - error = -EINVAL; - if (!silent) - fat_msg(sb, KERN_INFO, "Can't find a valid FAT filesystem"); - -out_fail: - if (fsinfo_inode) - iput(fsinfo_inode); - if (fat_inode) - iput(fat_inode); - unload_nls(sbi->nls_io); - unload_nls(sbi->nls_disk); - if (sbi->options.iocharset != fat_default_iocharset) - kfree(sbi->options.iocharset); - sb->s_fs_info = NULL; - kfree(sbi); - return error; -} - -EXPORT_SYMBOL_GPL(fat_fill_super); - -/* - * helper function for fat_flush_inodes. This writes both the inode - * and the file data blocks, waiting for in flight data blocks before - * the start of the call. It does not wait for any io started - * during the call - */ -static int writeback_inode(struct inode *inode) -{ - - int ret; - - /* if we used wait=1, sync_inode_metadata waits for the io for the - * inode to finish. So wait=0 is sent down to sync_inode_metadata - * and filemap_fdatawrite is used for the data blocks - */ - ret = sync_inode_metadata(inode, 0); - if (!ret) - ret = filemap_fdatawrite(inode->i_mapping); - return ret; -} - -/* - * write data and metadata corresponding to i1 and i2. The io is - * started but we do not wait for any of it to finish. - * - * filemap_flush is used for the block device, so if there is a dirty - * page for a block already in flight, we will not wait and start the - * io over again - */ -int fat_flush_inodes(struct super_block *sb, struct inode *i1, struct inode *i2) -{ - int ret = 0; - if (!MSDOS_SB(sb)->options.flush) - return 0; - if (i1) - ret = writeback_inode(i1); - if (!ret && i2) - ret = writeback_inode(i2); - if (!ret) { - struct address_space *mapping = sb->s_bdev->bd_inode->i_mapping; - ret = filemap_flush(mapping); - } - return ret; -} -EXPORT_SYMBOL_GPL(fat_flush_inodes); - -static int __init init_fat_fs(void) -{ - int err; - - err = fat_cache_init(); - if (err) - return err; - - err = fat_init_inodecache(); - if (err) - goto failed; - - return 0; - -failed: - fat_cache_destroy(); - return err; -} - -static void __exit exit_fat_fs(void) -{ - fat_cache_destroy(); - fat_destroy_inodecache(); -} - -module_init(init_fat_fs) -module_exit(exit_fat_fs) - -MODULE_LICENSE("GPL"); diff --git a/src/linux/fs/fat/misc.c b/src/linux/fs/fat/misc.c deleted file mode 100644 index 8a86981..0000000 --- a/src/linux/fs/fat/misc.c +++ /dev/null @@ -1,278 +0,0 @@ -/* - * linux/fs/fat/misc.c - * - * 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) - */ - -#include "fat.h" - -/* - * fat_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 __fat_fs_error(struct super_block *sb, int report, const char *fmt, ...) -{ - struct fat_mount_options *opts = &MSDOS_SB(sb)->options; - va_list args; - struct va_format vaf; - - if (report) { - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; - fat_msg(sb, KERN_ERR, "error, %pV", &vaf); - va_end(args); - } - - if (opts->errors == FAT_ERRORS_PANIC) - panic("FAT-fs (%s): fs panic from previous error\n", sb->s_id); - else if (opts->errors == FAT_ERRORS_RO && !(sb->s_flags & MS_RDONLY)) { - sb->s_flags |= MS_RDONLY; - fat_msg(sb, KERN_ERR, "Filesystem has been set read-only"); - } -} -EXPORT_SYMBOL_GPL(__fat_fs_error); - -/** - * fat_msg() - print preformated FAT specific messages. Every thing what is - * not fat_fs_error() should be fat_msg(). - */ -void fat_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; - printk("%sFAT-fs (%s): %pV\n", level, sb->s_id, &vaf); - va_end(args); -} - -/* Flushes the number of free clusters on FAT32 */ -/* XXX: Need to write one per FSINFO block. Currently only writes 1 */ -int fat_clusters_flush(struct super_block *sb) -{ - struct msdos_sb_info *sbi = MSDOS_SB(sb); - struct buffer_head *bh; - struct fat_boot_fsinfo *fsinfo; - - if (sbi->fat_bits != 32) - return 0; - - bh = sb_bread(sb, sbi->fsinfo_sector); - if (bh == NULL) { - fat_msg(sb, KERN_ERR, "bread failed in fat_clusters_flush"); - return -EIO; - } - - fsinfo = (struct fat_boot_fsinfo *)bh->b_data; - /* Sanity check */ - if (!IS_FSINFO(fsinfo)) { - fat_msg(sb, KERN_ERR, "Invalid FSINFO signature: " - "0x%08x, 0x%08x (sector = %lu)", - le32_to_cpu(fsinfo->signature1), - le32_to_cpu(fsinfo->signature2), - sbi->fsinfo_sector); - } else { - if (sbi->free_clusters != -1) - fsinfo->free_clusters = cpu_to_le32(sbi->free_clusters); - if (sbi->prev_free != -1) - fsinfo->next_cluster = cpu_to_le32(sbi->prev_free); - mark_buffer_dirty(bh); - } - brelse(bh); - - return 0; -} - -/* - * fat_chain_add() adds a new cluster to the chain of clusters represented - * by inode. - */ -int fat_chain_add(struct inode *inode, int new_dclus, int nr_cluster) -{ - struct super_block *sb = inode->i_sb; - struct msdos_sb_info *sbi = MSDOS_SB(sb); - int ret, new_fclus, last; - - /* - * We must locate the last cluster of the file to add this new - * one (new_dclus) to the end of the link list (the FAT). - */ - last = new_fclus = 0; - if (MSDOS_I(inode)->i_start) { - int fclus, dclus; - - ret = fat_get_cluster(inode, FAT_ENT_EOF, &fclus, &dclus); - if (ret < 0) - return ret; - new_fclus = fclus + 1; - last = dclus; - } - - /* add new one to the last of the cluster chain */ - if (last) { - struct fat_entry fatent; - - fatent_init(&fatent); - ret = fat_ent_read(inode, &fatent, last); - if (ret >= 0) { - int wait = inode_needs_sync(inode); - ret = fat_ent_write(inode, &fatent, new_dclus, wait); - fatent_brelse(&fatent); - } - if (ret < 0) - return ret; - /* - * FIXME:Although we can add this cache, fat_cache_add() is - * assuming to be called after linear search with fat_cache_id. - */ -// fat_cache_add(inode, new_fclus, new_dclus); - } else { - MSDOS_I(inode)->i_start = new_dclus; - MSDOS_I(inode)->i_logstart = new_dclus; - /* - * Since generic_write_sync() synchronizes regular files later, - * we sync here only directories. - */ - if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode)) { - ret = fat_sync_inode(inode); - if (ret) - return ret; - } else - mark_inode_dirty(inode); - } - if (new_fclus != (inode->i_blocks >> (sbi->cluster_bits - 9))) { - fat_fs_error(sb, "clusters badly computed (%d != %llu)", - new_fclus, - (llu)(inode->i_blocks >> (sbi->cluster_bits - 9))); - fat_cache_inval_inode(inode); - } - inode->i_blocks += nr_cluster << (sbi->cluster_bits - 9); - - return 0; -} - -/* - * The epoch of FAT timestamp is 1980. - * : bits : value - * date: 0 - 4: day (1 - 31) - * date: 5 - 8: month (1 - 12) - * date: 9 - 15: year (0 - 127) from 1980 - * time: 0 - 4: sec (0 - 29) 2sec counts - * time: 5 - 10: min (0 - 59) - * time: 11 - 15: hour (0 - 23) - */ -#define SECS_PER_MIN 60 -#define SECS_PER_HOUR (60 * 60) -#define SECS_PER_DAY (SECS_PER_HOUR * 24) -/* days between 1.1.70 and 1.1.80 (2 leap days) */ -#define DAYS_DELTA (365 * 10 + 2) -/* 120 (2100 - 1980) isn't leap year */ -#define YEAR_2100 120 -#define IS_LEAP_YEAR(y) (!((y) & 3) && (y) != YEAR_2100) - -/* Linear day numbers of the respective 1sts in non-leap years. */ -static time_t days_in_year[] = { - /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ - 0, 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, -}; - -/* Convert a FAT time/date pair to a UNIX date (seconds since 1 1 70). */ -void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts, - __le16 __time, __le16 __date, u8 time_cs) -{ - u16 time = le16_to_cpu(__time), date = le16_to_cpu(__date); - time_t second, day, leap_day, month, year; - - year = date >> 9; - month = max(1, (date >> 5) & 0xf); - day = max(1, date & 0x1f) - 1; - - leap_day = (year + 3) / 4; - if (year > YEAR_2100) /* 2100 isn't leap year */ - leap_day--; - if (IS_LEAP_YEAR(year) && month > 2) - leap_day++; - - second = (time & 0x1f) << 1; - second += ((time >> 5) & 0x3f) * SECS_PER_MIN; - second += (time >> 11) * SECS_PER_HOUR; - second += (year * 365 + leap_day - + days_in_year[month] + day - + DAYS_DELTA) * SECS_PER_DAY; - - if (!sbi->options.tz_set) - second += sys_tz.tz_minuteswest * SECS_PER_MIN; - else - second -= sbi->options.time_offset * SECS_PER_MIN; - - if (time_cs) { - ts->tv_sec = second + (time_cs / 100); - ts->tv_nsec = (time_cs % 100) * 10000000; - } else { - ts->tv_sec = second; - ts->tv_nsec = 0; - } -} - -/* Convert linear UNIX date to a FAT time/date pair. */ -void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec *ts, - __le16 *time, __le16 *date, u8 *time_cs) -{ - struct tm tm; - time_to_tm(ts->tv_sec, - (sbi->options.tz_set ? sbi->options.time_offset : - -sys_tz.tz_minuteswest) * SECS_PER_MIN, &tm); - - /* FAT can only support year between 1980 to 2107 */ - if (tm.tm_year < 1980 - 1900) { - *time = 0; - *date = cpu_to_le16((0 << 9) | (1 << 5) | 1); - if (time_cs) - *time_cs = 0; - return; - } - if (tm.tm_year > 2107 - 1900) { - *time = cpu_to_le16((23 << 11) | (59 << 5) | 29); - *date = cpu_to_le16((127 << 9) | (12 << 5) | 31); - if (time_cs) - *time_cs = 199; - return; - } - - /* from 1900 -> from 1980 */ - tm.tm_year -= 80; - /* 0~11 -> 1~12 */ - tm.tm_mon++; - /* 0~59 -> 0~29(2sec counts) */ - tm.tm_sec >>= 1; - - *time = cpu_to_le16(tm.tm_hour << 11 | tm.tm_min << 5 | tm.tm_sec); - *date = cpu_to_le16(tm.tm_year << 9 | tm.tm_mon << 5 | tm.tm_mday); - if (time_cs) - *time_cs = (ts->tv_sec & 1) * 100 + ts->tv_nsec / 10000000; -} -EXPORT_SYMBOL_GPL(fat_time_unix2fat); - -int fat_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; -} diff --git a/src/linux/fs/fat/namei_vfat.c b/src/linux/fs/fat/namei_vfat.c deleted file mode 100644 index 6a7152d..0000000 --- a/src/linux/fs/fat/namei_vfat.c +++ /dev/null @@ -1,1104 +0,0 @@ -/* - * linux/fs/vfat/namei.c - * - * Written 1992,1993 by Werner Almesberger - * - * Windows95/Windows NT compatible extended MSDOS filesystem - * by Gordon Chaffee Copyright (C) 1995. Send bug reports for the - * VFAT filesystem to . Specify - * what file operation caused you trouble and if you can duplicate - * the problem, send a script that demonstrates it. - * - * Short name translation 1999, 2001 by Wolfram Pienkoss - * - * Support Multibyte characters and cleanup by - * OGAWA Hirofumi - */ - -#include -#include -#include -#include -#include "fat.h" - -static inline unsigned long vfat_d_version(struct dentry *dentry) -{ - return (unsigned long) dentry->d_fsdata; -} - -static inline void vfat_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 vfat_revalidate_shortname(struct dentry *dentry) -{ - int ret = 1; - spin_lock(&dentry->d_lock); - if (vfat_d_version(dentry) != d_inode(dentry->d_parent)->i_version) - ret = 0; - spin_unlock(&dentry->d_lock); - return ret; -} - -static int vfat_revalidate(struct dentry *dentry, unsigned int flags) -{ - if (flags & LOOKUP_RCU) - return -ECHILD; - - /* This is not negative dentry. Always valid. */ - if (d_really_is_positive(dentry)) - return 1; - return vfat_revalidate_shortname(dentry); -} - -static int vfat_revalidate_ci(struct dentry *dentry, unsigned int flags) -{ - 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; - - /* - * This may be nfsd (or something), anyway, we can't see the - * intent of this. So, since this can be for creation, drop it. - */ - if (!flags) - return 0; - - /* - * 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; - - return vfat_revalidate_shortname(dentry); -} - -/* returns the length of a struct qstr, ignoring trailing dots */ -static unsigned int __vfat_striptail_len(unsigned int len, const char *name) -{ - while (len && name[len - 1] == '.') - len--; - return len; -} - -static unsigned int vfat_striptail_len(const struct qstr *qstr) -{ - return __vfat_striptail_len(qstr->len, qstr->name); -} - -/* - * Compute the hash for the vfat name corresponding to the dentry. - * Note: if the name is invalid, we leave the hash code unchanged so - * that the existing dentry can be used. The vfat fs routines will - * return ENOENT or EINVAL as appropriate. - */ -static int vfat_hash(const struct dentry *dentry, struct qstr *qstr) -{ - qstr->hash = full_name_hash(dentry, qstr->name, vfat_striptail_len(qstr)); - return 0; -} - -/* - * Compute the hash for the vfat name corresponding to the dentry. - * Note: if the name is invalid, we leave the hash code unchanged so - * that the existing dentry can be used. The vfat fs routines will - * return ENOENT or EINVAL as appropriate. - */ -static int vfat_hashi(const struct dentry *dentry, struct qstr *qstr) -{ - struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io; - const unsigned char *name; - unsigned int len; - unsigned long hash; - - name = qstr->name; - len = vfat_striptail_len(qstr); - - hash = init_name_hash(dentry); - while (len--) - hash = partial_name_hash(nls_tolower(t, *name++), hash); - qstr->hash = end_name_hash(hash); - - return 0; -} - -/* - * Case insensitive compare of two vfat names. - */ -static int vfat_cmpi(const struct dentry *dentry, - unsigned int len, const char *str, const struct qstr *name) -{ - struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io; - unsigned int alen, blen; - - /* A filename cannot end in '.' or we treat it like it has none */ - alen = vfat_striptail_len(name); - blen = __vfat_striptail_len(len, str); - if (alen == blen) { - if (nls_strnicmp(t, name->name, str, alen) == 0) - return 0; - } - return 1; -} - -/* - * Case sensitive compare of two vfat names. - */ -static int vfat_cmp(const struct dentry *dentry, - unsigned int len, const char *str, const struct qstr *name) -{ - unsigned int alen, blen; - - /* A filename cannot end in '.' or we treat it like it has none */ - alen = vfat_striptail_len(name); - blen = __vfat_striptail_len(len, str); - if (alen == blen) { - if (strncmp(name->name, str, alen) == 0) - return 0; - } - return 1; -} - -static const struct dentry_operations vfat_ci_dentry_ops = { - .d_revalidate = vfat_revalidate_ci, - .d_hash = vfat_hashi, - .d_compare = vfat_cmpi, -}; - -static const struct dentry_operations vfat_dentry_ops = { - .d_revalidate = vfat_revalidate, - .d_hash = vfat_hash, - .d_compare = vfat_cmp, -}; - -/* Characters that are undesirable in an MS-DOS file name */ - -static inline wchar_t vfat_bad_char(wchar_t w) -{ - return (w < 0x0020) - || (w == '*') || (w == '?') || (w == '<') || (w == '>') - || (w == '|') || (w == '"') || (w == ':') || (w == '/') - || (w == '\\'); -} - -static inline wchar_t vfat_replace_char(wchar_t w) -{ - return (w == '[') || (w == ']') || (w == ';') || (w == ',') - || (w == '+') || (w == '='); -} - -static wchar_t vfat_skip_char(wchar_t w) -{ - return (w == '.') || (w == ' '); -} - -static inline int vfat_is_used_badchars(const wchar_t *s, int len) -{ - int i; - - for (i = 0; i < len; i++) - if (vfat_bad_char(s[i])) - return -EINVAL; - - if (s[i - 1] == ' ') /* last character cannot be space */ - return -EINVAL; - - return 0; -} - -static int vfat_find_form(struct inode *dir, unsigned char *name) -{ - struct fat_slot_info sinfo; - int err = fat_scan(dir, name, &sinfo); - if (err) - return -ENOENT; - brelse(sinfo.bh); - return 0; -} - -/* - * 1) Valid characters for the 8.3 format alias are any combination of - * letters, uppercase alphabets, digits, any of the - * following special characters: - * $ % ' ` - @ { } ~ ! # ( ) & _ ^ - * In this case Longfilename is not stored in disk. - * - * WinNT's Extension: - * File name and extension name is contain uppercase/lowercase - * only. And it is expressed by CASE_LOWER_BASE and CASE_LOWER_EXT. - * - * 2) File name is 8.3 format, but it contain the uppercase and - * lowercase char, muliti bytes char, etc. In this case numtail is not - * added, but Longfilename is stored. - * - * 3) When the one except for the above, or the following special - * character are contained: - * . [ ] ; , + = - * numtail is added, and Longfilename must be stored in disk . - */ -struct shortname_info { - unsigned char lower:1, - upper:1, - valid:1; -}; -#define INIT_SHORTNAME_INFO(x) do { \ - (x)->lower = 1; \ - (x)->upper = 1; \ - (x)->valid = 1; \ -} while (0) - -static inline int to_shortname_char(struct nls_table *nls, - unsigned char *buf, int buf_size, - wchar_t *src, struct shortname_info *info) -{ - int len; - - if (vfat_skip_char(*src)) { - info->valid = 0; - return 0; - } - if (vfat_replace_char(*src)) { - info->valid = 0; - buf[0] = '_'; - return 1; - } - - len = nls->uni2char(*src, buf, buf_size); - if (len <= 0) { - info->valid = 0; - buf[0] = '_'; - len = 1; - } else if (len == 1) { - unsigned char prev = buf[0]; - - if (buf[0] >= 0x7F) { - info->lower = 0; - info->upper = 0; - } - - buf[0] = nls_toupper(nls, buf[0]); - if (isalpha(buf[0])) { - if (buf[0] == prev) - info->lower = 0; - else - info->upper = 0; - } - } else { - info->lower = 0; - info->upper = 0; - } - - return len; -} - -/* - * Given a valid longname, create a unique shortname. Make sure the - * shortname does not exist - * Returns negative number on error, 0 for a normal - * return, and 1 for valid shortname - */ -static int vfat_create_shortname(struct inode *dir, struct nls_table *nls, - wchar_t *uname, int ulen, - unsigned char *name_res, unsigned char *lcase) -{ - struct fat_mount_options *opts = &MSDOS_SB(dir->i_sb)->options; - wchar_t *ip, *ext_start, *end, *name_start; - unsigned char base[9], ext[4], buf[5], *p; - unsigned char charbuf[NLS_MAX_CHARSET_SIZE]; - int chl, chi; - int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen; - int is_shortname; - struct shortname_info base_info, ext_info; - - is_shortname = 1; - INIT_SHORTNAME_INFO(&base_info); - INIT_SHORTNAME_INFO(&ext_info); - - /* Now, we need to create a shortname from the long name */ - ext_start = end = &uname[ulen]; - while (--ext_start >= uname) { - if (*ext_start == 0x002E) { /* is `.' */ - if (ext_start == end - 1) { - sz = ulen; - ext_start = NULL; - } - break; - } - } - - if (ext_start == uname - 1) { - sz = ulen; - ext_start = NULL; - } else if (ext_start) { - /* - * Names which start with a dot could be just - * an extension eg. "...test". In this case Win95 - * uses the extension as the name and sets no extension. - */ - name_start = &uname[0]; - while (name_start < ext_start) { - if (!vfat_skip_char(*name_start)) - break; - name_start++; - } - if (name_start != ext_start) { - sz = ext_start - uname; - ext_start++; - } else { - sz = ulen; - ext_start = NULL; - } - } - - numtail_baselen = 6; - numtail2_baselen = 2; - for (baselen = i = 0, p = base, ip = uname; i < sz; i++, ip++) { - chl = to_shortname_char(nls, charbuf, sizeof(charbuf), - ip, &base_info); - if (chl == 0) - continue; - - if (baselen < 2 && (baselen + chl) > 2) - numtail2_baselen = baselen; - if (baselen < 6 && (baselen + chl) > 6) - numtail_baselen = baselen; - for (chi = 0; chi < chl; chi++) { - *p++ = charbuf[chi]; - baselen++; - if (baselen >= 8) - break; - } - if (baselen >= 8) { - if ((chi < chl - 1) || (ip + 1) - uname < sz) - is_shortname = 0; - break; - } - } - if (baselen == 0) { - return -EINVAL; - } - - extlen = 0; - if (ext_start) { - for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) { - chl = to_shortname_char(nls, charbuf, sizeof(charbuf), - ip, &ext_info); - if (chl == 0) - continue; - - if ((extlen + chl) > 3) { - is_shortname = 0; - break; - } - for (chi = 0; chi < chl; chi++) { - *p++ = charbuf[chi]; - extlen++; - } - if (extlen >= 3) { - if (ip + 1 != end) - is_shortname = 0; - break; - } - } - } - ext[extlen] = '\0'; - base[baselen] = '\0'; - - /* Yes, it can happen. ".\xe5" would do it. */ - if (base[0] == DELETED_FLAG) - base[0] = 0x05; - - /* OK, at this point we know that base is not longer than 8 symbols, - * ext is not longer than 3, base is nonempty, both don't contain - * any bad symbols (lowercase transformed to uppercase). - */ - - memset(name_res, ' ', MSDOS_NAME); - memcpy(name_res, base, baselen); - memcpy(name_res + 8, ext, extlen); - *lcase = 0; - if (is_shortname && base_info.valid && ext_info.valid) { - if (vfat_find_form(dir, name_res) == 0) - return -EEXIST; - - if (opts->shortname & VFAT_SFN_CREATE_WIN95) { - return (base_info.upper && ext_info.upper); - } else if (opts->shortname & VFAT_SFN_CREATE_WINNT) { - if ((base_info.upper || base_info.lower) && - (ext_info.upper || ext_info.lower)) { - if (!base_info.upper && base_info.lower) - *lcase |= CASE_LOWER_BASE; - if (!ext_info.upper && ext_info.lower) - *lcase |= CASE_LOWER_EXT; - return 1; - } - return 0; - } else { - BUG(); - } - } - - if (opts->numtail == 0) - if (vfat_find_form(dir, name_res) < 0) - return 0; - - /* - * Try to find a unique extension. This used to - * iterate through all possibilities sequentially, - * but that gave extremely bad performance. Windows - * only tries a few cases before using random - * values for part of the base. - */ - - if (baselen > 6) { - baselen = numtail_baselen; - name_res[7] = ' '; - } - name_res[baselen] = '~'; - for (i = 1; i < 10; i++) { - name_res[baselen + 1] = i + '0'; - if (vfat_find_form(dir, name_res) < 0) - return 0; - } - - i = jiffies; - sz = (jiffies >> 16) & 0x7; - if (baselen > 2) { - baselen = numtail2_baselen; - name_res[7] = ' '; - } - name_res[baselen + 4] = '~'; - name_res[baselen + 5] = '1' + sz; - while (1) { - snprintf(buf, sizeof(buf), "%04X", i & 0xffff); - memcpy(&name_res[baselen], buf, 4); - if (vfat_find_form(dir, name_res) < 0) - break; - i -= 11; - } - return 0; -} - -/* Translate a string, including coded sequences into Unicode */ -static int -xlate_to_uni(const unsigned char *name, int len, unsigned char *outname, - int *longlen, int *outlen, int escape, int utf8, - struct nls_table *nls) -{ - const unsigned char *ip; - unsigned char nc; - unsigned char *op; - unsigned int ec; - int i, k, fill; - int charlen; - - if (utf8) { - *outlen = utf8s_to_utf16s(name, len, UTF16_HOST_ENDIAN, - (wchar_t *) outname, FAT_LFN_LEN + 2); - if (*outlen < 0) - return *outlen; - else if (*outlen > FAT_LFN_LEN) - return -ENAMETOOLONG; - - op = &outname[*outlen * sizeof(wchar_t)]; - } else { - for (i = 0, ip = name, op = outname, *outlen = 0; - i < len && *outlen < FAT_LFN_LEN; - *outlen += 1) { - if (escape && (*ip == ':')) { - if (i > len - 5) - return -EINVAL; - ec = 0; - for (k = 1; k < 5; k++) { - nc = ip[k]; - ec <<= 4; - if (nc >= '0' && nc <= '9') { - ec |= nc - '0'; - continue; - } - if (nc >= 'a' && nc <= 'f') { - ec |= nc - ('a' - 10); - continue; - } - if (nc >= 'A' && nc <= 'F') { - ec |= nc - ('A' - 10); - continue; - } - return -EINVAL; - } - *op++ = ec & 0xFF; - *op++ = ec >> 8; - ip += 5; - i += 5; - } else { - charlen = nls->char2uni(ip, len - i, - (wchar_t *)op); - if (charlen < 0) - return -EINVAL; - ip += charlen; - i += charlen; - op += 2; - } - } - if (i < len) - return -ENAMETOOLONG; - } - - *longlen = *outlen; - if (*outlen % 13) { - *op++ = 0; - *op++ = 0; - *outlen += 1; - if (*outlen % 13) { - fill = 13 - (*outlen % 13); - for (i = 0; i < fill; i++) { - *op++ = 0xff; - *op++ = 0xff; - } - *outlen += fill; - } - } - - return 0; -} - -static int vfat_build_slots(struct inode *dir, const unsigned char *name, - int len, int is_dir, int cluster, - struct timespec *ts, - struct msdos_dir_slot *slots, int *nr_slots) -{ - struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb); - struct fat_mount_options *opts = &sbi->options; - struct msdos_dir_slot *ps; - struct msdos_dir_entry *de; - unsigned char cksum, lcase; - unsigned char msdos_name[MSDOS_NAME]; - wchar_t *uname; - __le16 time, date; - u8 time_cs; - int err, ulen, usize, i; - loff_t offset; - - *nr_slots = 0; - - uname = __getname(); - if (!uname) - return -ENOMEM; - - err = xlate_to_uni(name, len, (unsigned char *)uname, &ulen, &usize, - opts->unicode_xlate, opts->utf8, sbi->nls_io); - if (err) - goto out_free; - - err = vfat_is_used_badchars(uname, ulen); - if (err) - goto out_free; - - err = vfat_create_shortname(dir, sbi->nls_disk, uname, ulen, - msdos_name, &lcase); - if (err < 0) - goto out_free; - else if (err == 1) { - de = (struct msdos_dir_entry *)slots; - err = 0; - goto shortname; - } - - /* build the entry of long file name */ - cksum = fat_checksum(msdos_name); - - *nr_slots = usize / 13; - for (ps = slots, i = *nr_slots; i > 0; i--, ps++) { - ps->id = i; - ps->attr = ATTR_EXT; - ps->reserved = 0; - ps->alias_checksum = cksum; - ps->start = 0; - offset = (i - 1) * 13; - fatwchar_to16(ps->name0_4, uname + offset, 5); - fatwchar_to16(ps->name5_10, uname + offset + 5, 6); - fatwchar_to16(ps->name11_12, uname + offset + 11, 2); - } - slots[0].id |= 0x40; - de = (struct msdos_dir_entry *)ps; - -shortname: - /* build the entry of 8.3 alias name */ - (*nr_slots)++; - memcpy(de->name, msdos_name, MSDOS_NAME); - de->attr = is_dir ? ATTR_DIR : ATTR_ARCH; - de->lcase = lcase; - fat_time_unix2fat(sbi, ts, &time, &date, &time_cs); - de->time = de->ctime = time; - de->date = de->cdate = de->adate = date; - de->ctime_cs = time_cs; - fat_set_start(de, cluster); - de->size = 0; -out_free: - __putname(uname); - return err; -} - -static int vfat_add_entry(struct inode *dir, const struct qstr *qname, - int is_dir, int cluster, struct timespec *ts, - struct fat_slot_info *sinfo) -{ - struct msdos_dir_slot *slots; - unsigned int len; - int err, nr_slots; - - len = vfat_striptail_len(qname); - if (len == 0) - return -ENOENT; - - slots = kmalloc(sizeof(*slots) * MSDOS_SLOTS, GFP_NOFS); - if (slots == NULL) - return -ENOMEM; - - err = vfat_build_slots(dir, qname->name, len, is_dir, cluster, ts, - slots, &nr_slots); - if (err) - goto cleanup; - - err = fat_add_entries(dir, slots, nr_slots, sinfo); - if (err) - goto cleanup; - - /* update timestamp */ - dir->i_ctime = dir->i_mtime = dir->i_atime = *ts; - if (IS_DIRSYNC(dir)) - (void)fat_sync_inode(dir); - else - mark_inode_dirty(dir); -cleanup: - kfree(slots); - return err; -} - -static int vfat_find(struct inode *dir, const struct qstr *qname, - struct fat_slot_info *sinfo) -{ - unsigned int len = vfat_striptail_len(qname); - if (len == 0) - return -ENOENT; - return fat_search_long(dir, qname->name, len, sinfo); -} - -/* - * (nfsd's) anonymous disconnected dentry? - * NOTE: !IS_ROOT() is not anonymous (I.e. d_splice_alias() did the job). - */ -static int vfat_d_anon_disconn(struct dentry *dentry) -{ - return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED); -} - -static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry, - unsigned int flags) -{ - struct super_block *sb = dir->i_sb; - struct fat_slot_info sinfo; - struct inode *inode; - struct dentry *alias; - int err; - - mutex_lock(&MSDOS_SB(sb)->s_lock); - - err = vfat_find(dir, &dentry->d_name, &sinfo); - if (err) { - if (err == -ENOENT) { - inode = NULL; - goto out; - } - goto error; - } - - inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); - brelse(sinfo.bh); - if (IS_ERR(inode)) { - err = PTR_ERR(inode); - goto error; - } - - 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 && - !vfat_d_anon_disconn(alias)) { - /* - * 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. - */ - BUG_ON(d_unhashed(alias)); - if (!S_ISDIR(inode->i_mode)) - d_move(alias, dentry); - iput(inode); - mutex_unlock(&MSDOS_SB(sb)->s_lock); - return alias; - } else - dput(alias); - -out: - mutex_unlock(&MSDOS_SB(sb)->s_lock); - if (!inode) - vfat_d_version_set(dentry, dir->i_version); - return d_splice_alias(inode, dentry); -error: - mutex_unlock(&MSDOS_SB(sb)->s_lock); - return ERR_PTR(err); -} - -static int vfat_create(struct inode *dir, struct dentry *dentry, umode_t mode, - bool excl) -{ - struct super_block *sb = dir->i_sb; - struct inode *inode; - struct fat_slot_info sinfo; - struct timespec ts; - int err; - - mutex_lock(&MSDOS_SB(sb)->s_lock); - - ts = current_time(dir); - err = vfat_add_entry(dir, &dentry->d_name, 0, 0, &ts, &sinfo); - if (err) - goto out; - dir->i_version++; - - inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); - brelse(sinfo.bh); - if (IS_ERR(inode)) { - err = PTR_ERR(inode); - goto out; - } - inode->i_version++; - inode->i_mtime = inode->i_atime = inode->i_ctime = ts; - /* timestamp is already written, so mark_inode_dirty() is unneeded. */ - - d_instantiate(dentry, inode); -out: - mutex_unlock(&MSDOS_SB(sb)->s_lock); - return err; -} - -static int vfat_rmdir(struct inode *dir, struct dentry *dentry) -{ - struct inode *inode = d_inode(dentry); - struct super_block *sb = dir->i_sb; - struct fat_slot_info sinfo; - int err; - - mutex_lock(&MSDOS_SB(sb)->s_lock); - - err = fat_dir_empty(inode); - if (err) - goto out; - err = vfat_find(dir, &dentry->d_name, &sinfo); - if (err) - goto out; - - err = fat_remove_entries(dir, &sinfo); /* and releases bh */ - if (err) - goto out; - drop_nlink(dir); - - clear_nlink(inode); - inode->i_mtime = inode->i_atime = current_time(inode); - fat_detach(inode); - vfat_d_version_set(dentry, dir->i_version); -out: - mutex_unlock(&MSDOS_SB(sb)->s_lock); - - return err; -} - -static int vfat_unlink(struct inode *dir, struct dentry *dentry) -{ - struct inode *inode = d_inode(dentry); - struct super_block *sb = dir->i_sb; - struct fat_slot_info sinfo; - int err; - - mutex_lock(&MSDOS_SB(sb)->s_lock); - - err = vfat_find(dir, &dentry->d_name, &sinfo); - if (err) - goto out; - - err = fat_remove_entries(dir, &sinfo); /* and releases bh */ - if (err) - goto out; - clear_nlink(inode); - inode->i_mtime = inode->i_atime = current_time(inode); - fat_detach(inode); - vfat_d_version_set(dentry, dir->i_version); -out: - mutex_unlock(&MSDOS_SB(sb)->s_lock); - - return err; -} - -static int vfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) -{ - struct super_block *sb = dir->i_sb; - struct inode *inode; - struct fat_slot_info sinfo; - struct timespec ts; - int err, cluster; - - mutex_lock(&MSDOS_SB(sb)->s_lock); - - ts = current_time(dir); - cluster = fat_alloc_new_dir(dir, &ts); - if (cluster < 0) { - err = cluster; - goto out; - } - err = vfat_add_entry(dir, &dentry->d_name, 1, cluster, &ts, &sinfo); - if (err) - goto out_free; - dir->i_version++; - inc_nlink(dir); - - inode = fat_build_inode(sb, sinfo.de, sinfo.i_pos); - brelse(sinfo.bh); - if (IS_ERR(inode)) { - err = PTR_ERR(inode); - /* the directory was completed, just return a error */ - goto out; - } - inode->i_version++; - set_nlink(inode, 2); - inode->i_mtime = inode->i_atime = inode->i_ctime = ts; - /* timestamp is already written, so mark_inode_dirty() is unneeded. */ - - d_instantiate(dentry, inode); - - mutex_unlock(&MSDOS_SB(sb)->s_lock); - return 0; - -out_free: - fat_free_clusters(dir, cluster); -out: - mutex_unlock(&MSDOS_SB(sb)->s_lock); - return err; -} - -static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry, - unsigned int flags) -{ - struct buffer_head *dotdot_bh; - struct msdos_dir_entry *dotdot_de; - struct inode *old_inode, *new_inode; - struct fat_slot_info old_sinfo, sinfo; - struct timespec ts; - loff_t new_i_pos; - int err, is_dir, update_dotdot, corrupt = 0; - struct super_block *sb = old_dir->i_sb; - - if (flags & ~RENAME_NOREPLACE) - return -EINVAL; - - old_sinfo.bh = sinfo.bh = dotdot_bh = NULL; - old_inode = d_inode(old_dentry); - new_inode = d_inode(new_dentry); - mutex_lock(&MSDOS_SB(sb)->s_lock); - err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo); - if (err) - goto out; - - is_dir = S_ISDIR(old_inode->i_mode); - update_dotdot = (is_dir && old_dir != new_dir); - if (update_dotdot) { - if (fat_get_dotdot_entry(old_inode, &dotdot_bh, &dotdot_de)) { - err = -EIO; - goto out; - } - } - - ts = current_time(old_dir); - if (new_inode) { - if (is_dir) { - err = fat_dir_empty(new_inode); - if (err) - goto out; - } - new_i_pos = MSDOS_I(new_inode)->i_pos; - fat_detach(new_inode); - } else { - err = vfat_add_entry(new_dir, &new_dentry->d_name, is_dir, 0, - &ts, &sinfo); - if (err) - goto out; - new_i_pos = sinfo.i_pos; - } - new_dir->i_version++; - - fat_detach(old_inode); - fat_attach(old_inode, new_i_pos); - if (IS_DIRSYNC(new_dir)) { - err = fat_sync_inode(old_inode); - if (err) - goto error_inode; - } else - mark_inode_dirty(old_inode); - - if (update_dotdot) { - fat_set_start(dotdot_de, MSDOS_I(new_dir)->i_logstart); - mark_buffer_dirty_inode(dotdot_bh, old_inode); - if (IS_DIRSYNC(new_dir)) { - err = sync_dirty_buffer(dotdot_bh); - if (err) - goto error_dotdot; - } - drop_nlink(old_dir); - if (!new_inode) - inc_nlink(new_dir); - } - - err = fat_remove_entries(old_dir, &old_sinfo); /* and releases bh */ - old_sinfo.bh = NULL; - if (err) - goto error_dotdot; - old_dir->i_version++; - old_dir->i_ctime = old_dir->i_mtime = ts; - if (IS_DIRSYNC(old_dir)) - (void)fat_sync_inode(old_dir); - else - mark_inode_dirty(old_dir); - - if (new_inode) { - drop_nlink(new_inode); - if (is_dir) - drop_nlink(new_inode); - new_inode->i_ctime = ts; - } -out: - brelse(sinfo.bh); - brelse(dotdot_bh); - brelse(old_sinfo.bh); - mutex_unlock(&MSDOS_SB(sb)->s_lock); - - return err; - -error_dotdot: - /* data cluster is shared, serious corruption */ - corrupt = 1; - - if (update_dotdot) { - fat_set_start(dotdot_de, MSDOS_I(old_dir)->i_logstart); - mark_buffer_dirty_inode(dotdot_bh, old_inode); - corrupt |= sync_dirty_buffer(dotdot_bh); - } -error_inode: - fat_detach(old_inode); - fat_attach(old_inode, old_sinfo.i_pos); - if (new_inode) { - fat_attach(new_inode, new_i_pos); - if (corrupt) - corrupt |= fat_sync_inode(new_inode); - } else { - /* - * If new entry was not sharing the data cluster, it - * shouldn't be serious corruption. - */ - int err2 = fat_remove_entries(new_dir, &sinfo); - if (corrupt) - corrupt |= err2; - sinfo.bh = NULL; - } - if (corrupt < 0) { - fat_fs_error(new_dir->i_sb, - "%s: Filesystem corrupted (i_pos %lld)", - __func__, sinfo.i_pos); - } - goto out; -} - -static const struct inode_operations vfat_dir_inode_operations = { - .create = vfat_create, - .lookup = vfat_lookup, - .unlink = vfat_unlink, - .mkdir = vfat_mkdir, - .rmdir = vfat_rmdir, - .rename = vfat_rename, - .setattr = fat_setattr, - .getattr = fat_getattr, -}; - -static void setup(struct super_block *sb) -{ - MSDOS_SB(sb)->dir_ops = &vfat_dir_inode_operations; - if (MSDOS_SB(sb)->options.name_check != 's') - sb->s_d_op = &vfat_ci_dentry_ops; - else - sb->s_d_op = &vfat_dentry_ops; -} - -static int vfat_fill_super(struct super_block *sb, void *data, int silent) -{ - return fat_fill_super(sb, data, silent, 1, setup); -} - -static struct dentry *vfat_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) -{ - return mount_bdev(fs_type, flags, dev_name, data, vfat_fill_super); -} - -static struct file_system_type vfat_fs_type = { - .owner = THIS_MODULE, - .name = "vfat", - .mount = vfat_mount, - .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, -}; -MODULE_ALIAS_FS("vfat"); - -static int __init init_vfat_fs(void) -{ - return register_filesystem(&vfat_fs_type); -} - -static void __exit exit_vfat_fs(void) -{ - unregister_filesystem(&vfat_fs_type); -} - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("VFAT filesystem support"); -MODULE_AUTHOR("Gordon Chaffee"); - -module_init(init_vfat_fs) -module_exit(exit_vfat_fs) diff --git a/src/linux/fs/fat/nfs.c b/src/linux/fs/fat/nfs.c deleted file mode 100644 index eb19265..0000000 --- a/src/linux/fs/fat/nfs.c +++ /dev/null @@ -1,301 +0,0 @@ -/* fs/fat/nfs.c - * - * This software is licensed under the terms of the GNU General Public - * License version 2, as published by the Free Software Foundation, and - * may be copied, distributed, and modified under those terms. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#include -#include "fat.h" - -struct fat_fid { - u32 i_gen; - u32 i_pos_low; - u16 i_pos_hi; - u16 parent_i_pos_hi; - u32 parent_i_pos_low; - u32 parent_i_gen; -}; - -#define FAT_FID_SIZE_WITHOUT_PARENT 3 -#define FAT_FID_SIZE_WITH_PARENT (sizeof(struct fat_fid)/sizeof(u32)) - -/** - * Look up a directory inode given its starting cluster. - */ -static struct inode *fat_dget(struct super_block *sb, int i_logstart) -{ - struct msdos_sb_info *sbi = MSDOS_SB(sb); - struct hlist_head *head; - struct msdos_inode_info *i; - struct inode *inode = NULL; - - head = sbi->dir_hashtable + fat_dir_hash(i_logstart); - spin_lock(&sbi->dir_hash_lock); - hlist_for_each_entry(i, head, i_dir_hash) { - BUG_ON(i->vfs_inode.i_sb != sb); - if (i->i_logstart != i_logstart) - continue; - inode = igrab(&i->vfs_inode); - if (inode) - break; - } - spin_unlock(&sbi->dir_hash_lock); - return inode; -} - -static struct inode *fat_ilookup(struct super_block *sb, u64 ino, loff_t i_pos) -{ - if (MSDOS_SB(sb)->options.nfs == FAT_NFS_NOSTALE_RO) - return fat_iget(sb, i_pos); - - else { - if ((ino < MSDOS_ROOT_INO) || (ino == MSDOS_FSINFO_INO)) - return NULL; - return ilookup(sb, ino); - } -} - -static struct inode *__fat_nfs_get_inode(struct super_block *sb, - u64 ino, u32 generation, loff_t i_pos) -{ - struct inode *inode = fat_ilookup(sb, ino, i_pos); - - if (inode && generation && (inode->i_generation != generation)) { - iput(inode); - inode = NULL; - } - if (inode == NULL && MSDOS_SB(sb)->options.nfs == FAT_NFS_NOSTALE_RO) { - struct buffer_head *bh = NULL; - struct msdos_dir_entry *de ; - sector_t blocknr; - int offset; - fat_get_blknr_offset(MSDOS_SB(sb), i_pos, &blocknr, &offset); - bh = sb_bread(sb, blocknr); - if (!bh) { - fat_msg(sb, KERN_ERR, - "unable to read block(%llu) for building NFS inode", - (llu)blocknr); - return inode; - } - de = (struct msdos_dir_entry *)bh->b_data; - /* If a file is deleted on server and client is not updated - * yet, we must not build the inode upon a lookup call. - */ - if (IS_FREE(de[offset].name)) - inode = NULL; - else - inode = fat_build_inode(sb, &de[offset], i_pos); - brelse(bh); - } - - return inode; -} - -static struct inode *fat_nfs_get_inode(struct super_block *sb, - u64 ino, u32 generation) -{ - - return __fat_nfs_get_inode(sb, ino, generation, 0); -} - -static int -fat_encode_fh_nostale(struct inode *inode, __u32 *fh, int *lenp, - struct inode *parent) -{ - int len = *lenp; - struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); - struct fat_fid *fid = (struct fat_fid *) fh; - loff_t i_pos; - int type = FILEID_FAT_WITHOUT_PARENT; - - if (parent) { - if (len < FAT_FID_SIZE_WITH_PARENT) { - *lenp = FAT_FID_SIZE_WITH_PARENT; - return FILEID_INVALID; - } - } else { - if (len < FAT_FID_SIZE_WITHOUT_PARENT) { - *lenp = FAT_FID_SIZE_WITHOUT_PARENT; - return FILEID_INVALID; - } - } - - i_pos = fat_i_pos_read(sbi, inode); - *lenp = FAT_FID_SIZE_WITHOUT_PARENT; - fid->i_gen = inode->i_generation; - fid->i_pos_low = i_pos & 0xFFFFFFFF; - fid->i_pos_hi = (i_pos >> 32) & 0xFFFF; - if (parent) { - i_pos = fat_i_pos_read(sbi, parent); - fid->parent_i_pos_hi = (i_pos >> 32) & 0xFFFF; - fid->parent_i_pos_low = i_pos & 0xFFFFFFFF; - fid->parent_i_gen = parent->i_generation; - type = FILEID_FAT_WITH_PARENT; - *lenp = FAT_FID_SIZE_WITH_PARENT; - } - - return type; -} - -/** - * Map a NFS file handle to a corresponding dentry. - * The dentry may or may not be connected to the filesystem root. - */ -static struct dentry *fat_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, - fat_nfs_get_inode); -} - -static struct dentry *fat_fh_to_dentry_nostale(struct super_block *sb, - struct fid *fh, int fh_len, - int fh_type) -{ - struct inode *inode = NULL; - struct fat_fid *fid = (struct fat_fid *)fh; - loff_t i_pos; - - switch (fh_type) { - case FILEID_FAT_WITHOUT_PARENT: - if (fh_len < FAT_FID_SIZE_WITHOUT_PARENT) - return NULL; - break; - case FILEID_FAT_WITH_PARENT: - if (fh_len < FAT_FID_SIZE_WITH_PARENT) - return NULL; - break; - default: - return NULL; - } - i_pos = fid->i_pos_hi; - i_pos = (i_pos << 32) | (fid->i_pos_low); - inode = __fat_nfs_get_inode(sb, 0, fid->i_gen, i_pos); - - return d_obtain_alias(inode); -} - -/* - * Find the parent for a file specified by NFS handle. - * This requires that the handle contain the i_ino of the parent. - */ -static struct dentry *fat_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, - fat_nfs_get_inode); -} - -static struct dentry *fat_fh_to_parent_nostale(struct super_block *sb, - struct fid *fh, int fh_len, - int fh_type) -{ - struct inode *inode = NULL; - struct fat_fid *fid = (struct fat_fid *)fh; - loff_t i_pos; - - if (fh_len < FAT_FID_SIZE_WITH_PARENT) - return NULL; - - switch (fh_type) { - case FILEID_FAT_WITH_PARENT: - i_pos = fid->parent_i_pos_hi; - i_pos = (i_pos << 32) | (fid->parent_i_pos_low); - inode = __fat_nfs_get_inode(sb, 0, fid->parent_i_gen, i_pos); - break; - } - - return d_obtain_alias(inode); -} - -/* - * Rebuild the parent for a directory that is not connected - * to the filesystem root - */ -static -struct inode *fat_rebuild_parent(struct super_block *sb, int parent_logstart) -{ - int search_clus, clus_to_match; - struct msdos_dir_entry *de; - struct inode *parent = NULL; - struct inode *dummy_grand_parent = NULL; - struct fat_slot_info sinfo; - struct msdos_sb_info *sbi = MSDOS_SB(sb); - sector_t blknr = fat_clus_to_blknr(sbi, parent_logstart); - struct buffer_head *parent_bh = sb_bread(sb, blknr); - if (!parent_bh) { - fat_msg(sb, KERN_ERR, - "unable to read cluster of parent directory"); - return NULL; - } - - de = (struct msdos_dir_entry *) parent_bh->b_data; - clus_to_match = fat_get_start(sbi, &de[0]); - search_clus = fat_get_start(sbi, &de[1]); - - dummy_grand_parent = fat_dget(sb, search_clus); - if (!dummy_grand_parent) { - dummy_grand_parent = new_inode(sb); - if (!dummy_grand_parent) { - brelse(parent_bh); - return parent; - } - - dummy_grand_parent->i_ino = iunique(sb, MSDOS_ROOT_INO); - fat_fill_inode(dummy_grand_parent, &de[1]); - MSDOS_I(dummy_grand_parent)->i_pos = -1; - } - - if (!fat_scan_logstart(dummy_grand_parent, clus_to_match, &sinfo)) - parent = fat_build_inode(sb, sinfo.de, sinfo.i_pos); - - brelse(parent_bh); - iput(dummy_grand_parent); - - return parent; -} - -/* - * Find the parent for a directory that is not currently connected to - * the filesystem root. - * - * On entry, the caller holds d_inode(child_dir)->i_mutex. - */ -static struct dentry *fat_get_parent(struct dentry *child_dir) -{ - struct super_block *sb = child_dir->d_sb; - struct buffer_head *bh = NULL; - struct msdos_dir_entry *de; - struct inode *parent_inode = NULL; - struct msdos_sb_info *sbi = MSDOS_SB(sb); - - if (!fat_get_dotdot_entry(d_inode(child_dir), &bh, &de)) { - int parent_logstart = fat_get_start(sbi, de); - parent_inode = fat_dget(sb, parent_logstart); - if (!parent_inode && sbi->options.nfs == FAT_NFS_NOSTALE_RO) - parent_inode = fat_rebuild_parent(sb, parent_logstart); - } - brelse(bh); - - return d_obtain_alias(parent_inode); -} - -const struct export_operations fat_export_ops = { - .fh_to_dentry = fat_fh_to_dentry, - .fh_to_parent = fat_fh_to_parent, - .get_parent = fat_get_parent, -}; - -const struct export_operations fat_export_ops_nostale = { - .encode_fh = fat_encode_fh_nostale, - .fh_to_dentry = fat_fh_to_dentry_nostale, - .fh_to_parent = fat_fh_to_parent_nostale, - .get_parent = fat_get_parent, -}; diff --git a/src/linux/fs/fcntl.c b/src/linux/fs/fcntl.c deleted file mode 100644 index 350a2c8..0000000 --- a/src/linux/fs/fcntl.c +++ /dev/null @@ -1,760 +0,0 @@ -/* - * linux/fs/fcntl.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME) - -static int setfl(int fd, struct file * filp, unsigned long arg) -{ - struct inode * inode = file_inode(filp); - int error = 0; - - /* - * O_APPEND cannot be cleared if the file is marked as append-only - * and the file is open for write. - */ - if (((arg ^ filp->f_flags) & O_APPEND) && IS_APPEND(inode)) - return -EPERM; - - /* O_NOATIME can only be set by the owner or superuser */ - if ((arg & O_NOATIME) && !(filp->f_flags & O_NOATIME)) - if (!inode_owner_or_capable(inode)) - return -EPERM; - - /* required for strict SunOS emulation */ - if (O_NONBLOCK != O_NDELAY) - if (arg & O_NDELAY) - arg |= O_NONBLOCK; - - /* Pipe packetized mode is controlled by O_DIRECT flag */ - if (!S_ISFIFO(filp->f_inode->i_mode) && (arg & O_DIRECT)) { - if (!filp->f_mapping || !filp->f_mapping->a_ops || - !filp->f_mapping->a_ops->direct_IO) - return -EINVAL; - } - - if (filp->f_op->check_flags) - error = filp->f_op->check_flags(arg); - if (error) - return error; - - /* - * ->fasync() is responsible for setting the FASYNC bit. - */ - if (((arg ^ filp->f_flags) & FASYNC) && filp->f_op->fasync) { - error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0); - if (error < 0) - goto out; - if (error > 0) - error = 0; - } - spin_lock(&filp->f_lock); - filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK); - spin_unlock(&filp->f_lock); - - out: - return error; -} - -static void f_modown(struct file *filp, struct pid *pid, enum pid_type type, - int force) -{ - write_lock_irq(&filp->f_owner.lock); - if (force || !filp->f_owner.pid) { - put_pid(filp->f_owner.pid); - filp->f_owner.pid = get_pid(pid); - filp->f_owner.pid_type = type; - - if (pid) { - const struct cred *cred = current_cred(); - filp->f_owner.uid = cred->uid; - filp->f_owner.euid = cred->euid; - } - } - write_unlock_irq(&filp->f_owner.lock); -} - -void __f_setown(struct file *filp, struct pid *pid, enum pid_type type, - int force) -{ - security_file_set_fowner(filp); - f_modown(filp, pid, type, force); -} -EXPORT_SYMBOL(__f_setown); - -void f_setown(struct file *filp, unsigned long arg, int force) -{ - enum pid_type type; - struct pid *pid; - int who = arg; - type = PIDTYPE_PID; - if (who < 0) { - type = PIDTYPE_PGID; - who = -who; - } - rcu_read_lock(); - pid = find_vpid(who); - __f_setown(filp, pid, type, force); - rcu_read_unlock(); -} -EXPORT_SYMBOL(f_setown); - -void f_delown(struct file *filp) -{ - f_modown(filp, NULL, PIDTYPE_PID, 1); -} - -pid_t f_getown(struct file *filp) -{ - pid_t pid; - read_lock(&filp->f_owner.lock); - pid = pid_vnr(filp->f_owner.pid); - if (filp->f_owner.pid_type == PIDTYPE_PGID) - pid = -pid; - read_unlock(&filp->f_owner.lock); - return pid; -} - -static int f_setown_ex(struct file *filp, unsigned long arg) -{ - struct f_owner_ex __user *owner_p = (void __user *)arg; - struct f_owner_ex owner; - struct pid *pid; - int type; - int ret; - - ret = copy_from_user(&owner, owner_p, sizeof(owner)); - if (ret) - return -EFAULT; - - switch (owner.type) { - case F_OWNER_TID: - type = PIDTYPE_MAX; - break; - - case F_OWNER_PID: - type = PIDTYPE_PID; - break; - - case F_OWNER_PGRP: - type = PIDTYPE_PGID; - break; - - default: - return -EINVAL; - } - - rcu_read_lock(); - pid = find_vpid(owner.pid); - if (owner.pid && !pid) - ret = -ESRCH; - else - __f_setown(filp, pid, type, 1); - rcu_read_unlock(); - - return ret; -} - -static int f_getown_ex(struct file *filp, unsigned long arg) -{ - struct f_owner_ex __user *owner_p = (void __user *)arg; - struct f_owner_ex owner; - int ret = 0; - - read_lock(&filp->f_owner.lock); - owner.pid = pid_vnr(filp->f_owner.pid); - switch (filp->f_owner.pid_type) { - case PIDTYPE_MAX: - owner.type = F_OWNER_TID; - break; - - case PIDTYPE_PID: - owner.type = F_OWNER_PID; - break; - - case PIDTYPE_PGID: - owner.type = F_OWNER_PGRP; - break; - - default: - WARN_ON(1); - ret = -EINVAL; - break; - } - read_unlock(&filp->f_owner.lock); - - if (!ret) { - ret = copy_to_user(owner_p, &owner, sizeof(owner)); - if (ret) - ret = -EFAULT; - } - return ret; -} - -#ifdef CONFIG_CHECKPOINT_RESTORE -static int f_getowner_uids(struct file *filp, unsigned long arg) -{ - struct user_namespace *user_ns = current_user_ns(); - uid_t __user *dst = (void __user *)arg; - uid_t src[2]; - int err; - - read_lock(&filp->f_owner.lock); - src[0] = from_kuid(user_ns, filp->f_owner.uid); - src[1] = from_kuid(user_ns, filp->f_owner.euid); - read_unlock(&filp->f_owner.lock); - - err = put_user(src[0], &dst[0]); - err |= put_user(src[1], &dst[1]); - - return err; -} -#else -static int f_getowner_uids(struct file *filp, unsigned long arg) -{ - return -EINVAL; -} -#endif - -static long do_fcntl(int fd, unsigned int cmd, unsigned long arg, - struct file *filp) -{ - long err = -EINVAL; - - switch (cmd) { - case F_DUPFD: - err = f_dupfd(arg, filp, 0); - break; - case F_DUPFD_CLOEXEC: - err = f_dupfd(arg, filp, O_CLOEXEC); - break; - case F_GETFD: - err = get_close_on_exec(fd) ? FD_CLOEXEC : 0; - break; - case F_SETFD: - err = 0; - set_close_on_exec(fd, arg & FD_CLOEXEC); - break; - case F_GETFL: - err = filp->f_flags; - break; - case F_SETFL: - err = setfl(fd, filp, arg); - break; -#if BITS_PER_LONG != 32 - /* 32-bit arches must use fcntl64() */ - case F_OFD_GETLK: -#endif - case F_GETLK: - err = fcntl_getlk(filp, cmd, (struct flock __user *) arg); - break; -#if BITS_PER_LONG != 32 - /* 32-bit arches must use fcntl64() */ - case F_OFD_SETLK: - case F_OFD_SETLKW: -#endif - /* Fallthrough */ - case F_SETLK: - case F_SETLKW: - err = fcntl_setlk(fd, filp, cmd, (struct flock __user *) arg); - break; - case F_GETOWN: - /* - * XXX If f_owner is a process group, the - * negative return value will get converted - * into an error. Oops. If we keep the - * current syscall conventions, the only way - * to fix this will be in libc. - */ - err = f_getown(filp); - force_successful_syscall_return(); - break; - case F_SETOWN: - f_setown(filp, arg, 1); - err = 0; - break; - case F_GETOWN_EX: - err = f_getown_ex(filp, arg); - break; - case F_SETOWN_EX: - err = f_setown_ex(filp, arg); - break; - case F_GETOWNER_UIDS: - err = f_getowner_uids(filp, arg); - break; - case F_GETSIG: - err = filp->f_owner.signum; - break; - case F_SETSIG: - /* arg == 0 restores default behaviour. */ - if (!valid_signal(arg)) { - break; - } - err = 0; - filp->f_owner.signum = arg; - break; - case F_GETLEASE: - err = fcntl_getlease(filp); - break; - case F_SETLEASE: - err = fcntl_setlease(fd, filp, arg); - break; - case F_NOTIFY: - err = fcntl_dirnotify(fd, filp, arg); - break; - case F_SETPIPE_SZ: - case F_GETPIPE_SZ: - err = pipe_fcntl(filp, cmd, arg); - break; - case F_ADD_SEALS: - case F_GET_SEALS: - err = shmem_fcntl(filp, cmd, arg); - break; - default: - break; - } - return err; -} - -static int check_fcntl_cmd(unsigned cmd) -{ - switch (cmd) { - case F_DUPFD: - case F_DUPFD_CLOEXEC: - case F_GETFD: - case F_SETFD: - case F_GETFL: - return 1; - } - return 0; -} - -SYSCALL_DEFINE3(fcntl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) -{ - struct fd f = fdget_raw(fd); - long err = -EBADF; - - if (!f.file) - goto out; - - if (unlikely(f.file->f_mode & FMODE_PATH)) { - if (!check_fcntl_cmd(cmd)) - goto out1; - } - - err = security_file_fcntl(f.file, cmd, arg); - if (!err) - err = do_fcntl(fd, cmd, arg, f.file); - -out1: - fdput(f); -out: - return err; -} - -#if BITS_PER_LONG == 32 -SYSCALL_DEFINE3(fcntl64, unsigned int, fd, unsigned int, cmd, - unsigned long, arg) -{ - struct fd f = fdget_raw(fd); - long err = -EBADF; - - if (!f.file) - goto out; - - if (unlikely(f.file->f_mode & FMODE_PATH)) { - if (!check_fcntl_cmd(cmd)) - goto out1; - } - - err = security_file_fcntl(f.file, cmd, arg); - if (err) - goto out1; - - switch (cmd) { - case F_GETLK64: - case F_OFD_GETLK: - err = fcntl_getlk64(f.file, cmd, (struct flock64 __user *) arg); - break; - case F_SETLK64: - case F_SETLKW64: - case F_OFD_SETLK: - case F_OFD_SETLKW: - err = fcntl_setlk64(fd, f.file, cmd, - (struct flock64 __user *) arg); - break; - default: - err = do_fcntl(fd, cmd, arg, f.file); - break; - } -out1: - fdput(f); -out: - return err; -} -#endif - -/* Table to convert sigio signal codes into poll band bitmaps */ - -static const long band_table[NSIGPOLL] = { - POLLIN | POLLRDNORM, /* POLL_IN */ - POLLOUT | POLLWRNORM | POLLWRBAND, /* POLL_OUT */ - POLLIN | POLLRDNORM | POLLMSG, /* POLL_MSG */ - POLLERR, /* POLL_ERR */ - POLLPRI | POLLRDBAND, /* POLL_PRI */ - POLLHUP | POLLERR /* POLL_HUP */ -}; - -static inline int sigio_perm(struct task_struct *p, - struct fown_struct *fown, int sig) -{ - const struct cred *cred; - int ret; - - rcu_read_lock(); - cred = __task_cred(p); - ret = ((uid_eq(fown->euid, GLOBAL_ROOT_UID) || - uid_eq(fown->euid, cred->suid) || uid_eq(fown->euid, cred->uid) || - uid_eq(fown->uid, cred->suid) || uid_eq(fown->uid, cred->uid)) && - !security_file_send_sigiotask(p, fown, sig)); - rcu_read_unlock(); - return ret; -} - -static void send_sigio_to_task(struct task_struct *p, - struct fown_struct *fown, - int fd, int reason, int group) -{ - /* - * F_SETSIG can change ->signum lockless in parallel, make - * sure we read it once and use the same value throughout. - */ - int signum = ACCESS_ONCE(fown->signum); - - if (!sigio_perm(p, fown, signum)) - return; - - switch (signum) { - siginfo_t si; - default: - /* Queue a rt signal with the appropriate fd as its - value. We use SI_SIGIO as the source, not - SI_KERNEL, since kernel signals always get - delivered even if we can't queue. Failure to - queue in this case _should_ be reported; we fall - back to SIGIO in that case. --sct */ - si.si_signo = signum; - si.si_errno = 0; - si.si_code = reason; - /* Make sure we are called with one of the POLL_* - reasons, otherwise we could leak kernel stack into - userspace. */ - BUG_ON((reason & __SI_MASK) != __SI_POLL); - if (reason - POLL_IN >= NSIGPOLL) - si.si_band = ~0L; - else - si.si_band = band_table[reason - POLL_IN]; - si.si_fd = fd; - if (!do_send_sig_info(signum, &si, p, group)) - break; - /* fall-through: fall back on the old plain SIGIO signal */ - case 0: - do_send_sig_info(SIGIO, SEND_SIG_PRIV, p, group); - } -} - -void send_sigio(struct fown_struct *fown, int fd, int band) -{ - struct task_struct *p; - enum pid_type type; - struct pid *pid; - int group = 1; - - read_lock(&fown->lock); - - type = fown->pid_type; - if (type == PIDTYPE_MAX) { - group = 0; - type = PIDTYPE_PID; - } - - pid = fown->pid; - if (!pid) - goto out_unlock_fown; - - read_lock(&tasklist_lock); - do_each_pid_task(pid, type, p) { - send_sigio_to_task(p, fown, fd, band, group); - } while_each_pid_task(pid, type, p); - read_unlock(&tasklist_lock); - out_unlock_fown: - read_unlock(&fown->lock); -} - -static void send_sigurg_to_task(struct task_struct *p, - struct fown_struct *fown, int group) -{ - if (sigio_perm(p, fown, SIGURG)) - do_send_sig_info(SIGURG, SEND_SIG_PRIV, p, group); -} - -int send_sigurg(struct fown_struct *fown) -{ - struct task_struct *p; - enum pid_type type; - struct pid *pid; - int group = 1; - int ret = 0; - - read_lock(&fown->lock); - - type = fown->pid_type; - if (type == PIDTYPE_MAX) { - group = 0; - type = PIDTYPE_PID; - } - - pid = fown->pid; - if (!pid) - goto out_unlock_fown; - - ret = 1; - - read_lock(&tasklist_lock); - do_each_pid_task(pid, type, p) { - send_sigurg_to_task(p, fown, group); - } while_each_pid_task(pid, type, p); - read_unlock(&tasklist_lock); - out_unlock_fown: - read_unlock(&fown->lock); - return ret; -} - -static DEFINE_SPINLOCK(fasync_lock); -static struct kmem_cache *fasync_cache __read_mostly; - -static void fasync_free_rcu(struct rcu_head *head) -{ - kmem_cache_free(fasync_cache, - container_of(head, struct fasync_struct, fa_rcu)); -} - -/* - * Remove a fasync entry. If successfully removed, return - * positive and clear the FASYNC flag. If no entry exists, - * do nothing and return 0. - * - * NOTE! It is very important that the FASYNC flag always - * match the state "is the filp on a fasync list". - * - */ -int fasync_remove_entry(struct file *filp, struct fasync_struct **fapp) -{ - struct fasync_struct *fa, **fp; - int result = 0; - - spin_lock(&filp->f_lock); - spin_lock(&fasync_lock); - for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { - if (fa->fa_file != filp) - continue; - - spin_lock_irq(&fa->fa_lock); - fa->fa_file = NULL; - spin_unlock_irq(&fa->fa_lock); - - *fp = fa->fa_next; - call_rcu(&fa->fa_rcu, fasync_free_rcu); - filp->f_flags &= ~FASYNC; - result = 1; - break; - } - spin_unlock(&fasync_lock); - spin_unlock(&filp->f_lock); - return result; -} - -struct fasync_struct *fasync_alloc(void) -{ - return kmem_cache_alloc(fasync_cache, GFP_KERNEL); -} - -/* - * NOTE! This can be used only for unused fasync entries: - * entries that actually got inserted on the fasync list - * need to be released by rcu - see fasync_remove_entry. - */ -void fasync_free(struct fasync_struct *new) -{ - kmem_cache_free(fasync_cache, new); -} - -/* - * Insert a new entry into the fasync list. Return the pointer to the - * old one if we didn't use the new one. - * - * NOTE! It is very important that the FASYNC flag always - * match the state "is the filp on a fasync list". - */ -struct fasync_struct *fasync_insert_entry(int fd, struct file *filp, struct fasync_struct **fapp, struct fasync_struct *new) -{ - struct fasync_struct *fa, **fp; - - spin_lock(&filp->f_lock); - spin_lock(&fasync_lock); - for (fp = fapp; (fa = *fp) != NULL; fp = &fa->fa_next) { - if (fa->fa_file != filp) - continue; - - spin_lock_irq(&fa->fa_lock); - fa->fa_fd = fd; - spin_unlock_irq(&fa->fa_lock); - goto out; - } - - spin_lock_init(&new->fa_lock); - new->magic = FASYNC_MAGIC; - new->fa_file = filp; - new->fa_fd = fd; - new->fa_next = *fapp; - rcu_assign_pointer(*fapp, new); - filp->f_flags |= FASYNC; - -out: - spin_unlock(&fasync_lock); - spin_unlock(&filp->f_lock); - return fa; -} - -/* - * Add a fasync entry. Return negative on error, positive if - * added, and zero if did nothing but change an existing one. - */ -static int fasync_add_entry(int fd, struct file *filp, struct fasync_struct **fapp) -{ - struct fasync_struct *new; - - new = fasync_alloc(); - if (!new) - return -ENOMEM; - - /* - * fasync_insert_entry() returns the old (update) entry if - * it existed. - * - * So free the (unused) new entry and return 0 to let the - * caller know that we didn't add any new fasync entries. - */ - if (fasync_insert_entry(fd, filp, fapp, new)) { - fasync_free(new); - return 0; - } - - return 1; -} - -/* - * fasync_helper() is used by almost all character device drivers - * to set up the fasync queue, and for regular files by the file - * lease code. It returns negative on error, 0 if it did no changes - * and positive if it added/deleted the entry. - */ -int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp) -{ - if (!on) - return fasync_remove_entry(filp, fapp); - return fasync_add_entry(fd, filp, fapp); -} - -EXPORT_SYMBOL(fasync_helper); - -/* - * rcu_read_lock() is held - */ -static void kill_fasync_rcu(struct fasync_struct *fa, int sig, int band) -{ - while (fa) { - struct fown_struct *fown; - unsigned long flags; - - if (fa->magic != FASYNC_MAGIC) { - printk(KERN_ERR "kill_fasync: bad magic number in " - "fasync_struct!\n"); - return; - } - spin_lock_irqsave(&fa->fa_lock, flags); - if (fa->fa_file) { - fown = &fa->fa_file->f_owner; - /* Don't send SIGURG to processes which have not set a - queued signum: SIGURG has its own default signalling - mechanism. */ - if (!(sig == SIGURG && fown->signum == 0)) - send_sigio(fown, fa->fa_fd, band); - } - spin_unlock_irqrestore(&fa->fa_lock, flags); - fa = rcu_dereference(fa->fa_next); - } -} - -void kill_fasync(struct fasync_struct **fp, int sig, int band) -{ - /* First a quick test without locking: usually - * the list is empty. - */ - if (*fp) { - rcu_read_lock(); - kill_fasync_rcu(rcu_dereference(*fp), sig, band); - rcu_read_unlock(); - } -} -EXPORT_SYMBOL(kill_fasync); - -static int __init fcntl_init(void) -{ - /* - * Please add new bits here to ensure allocation uniqueness. - * Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY - * is defined as O_NONBLOCK on some platforms and not on others. - */ - BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32( - O_RDONLY | O_WRONLY | O_RDWR | - O_CREAT | O_EXCL | O_NOCTTY | - O_TRUNC | O_APPEND | /* O_NONBLOCK | */ - __O_SYNC | O_DSYNC | FASYNC | - O_DIRECT | O_LARGEFILE | O_DIRECTORY | - O_NOFOLLOW | O_NOATIME | O_CLOEXEC | - __FMODE_EXEC | O_PATH | __O_TMPFILE | - __FMODE_NONOTIFY - )); - - fasync_cache = kmem_cache_create("fasync_cache", - sizeof(struct fasync_struct), 0, SLAB_PANIC, NULL); - return 0; -} - -module_init(fcntl_init) diff --git a/src/linux/fs/fhandle.c b/src/linux/fs/fhandle.c deleted file mode 100644 index ca3c3dd..0000000 --- a/src/linux/fs/fhandle.c +++ /dev/null @@ -1,266 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" -#include "mount.h" - -static long do_sys_name_to_handle(struct path *path, - struct file_handle __user *ufh, - int __user *mnt_id) -{ - long retval; - struct file_handle f_handle; - int handle_dwords, handle_bytes; - struct file_handle *handle = NULL; - - /* - * We need to make sure whether the file system - * support decoding of the file handle - */ - if (!path->dentry->d_sb->s_export_op || - !path->dentry->d_sb->s_export_op->fh_to_dentry) - return -EOPNOTSUPP; - - if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle))) - return -EFAULT; - - if (f_handle.handle_bytes > MAX_HANDLE_SZ) - return -EINVAL; - - handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes, - GFP_KERNEL); - if (!handle) - return -ENOMEM; - - /* convert handle size to multiple of sizeof(u32) */ - handle_dwords = f_handle.handle_bytes >> 2; - - /* we ask for a non connected handle */ - retval = exportfs_encode_fh(path->dentry, - (struct fid *)handle->f_handle, - &handle_dwords, 0); - handle->handle_type = retval; - /* convert handle size to bytes */ - handle_bytes = handle_dwords * sizeof(u32); - handle->handle_bytes = handle_bytes; - if ((handle->handle_bytes > f_handle.handle_bytes) || - (retval == FILEID_INVALID) || (retval == -ENOSPC)) { - /* As per old exportfs_encode_fh documentation - * we could return ENOSPC to indicate overflow - * But file system returned 255 always. So handle - * both the values - */ - /* - * set the handle size to zero so we copy only - * non variable part of the file_handle - */ - handle_bytes = 0; - retval = -EOVERFLOW; - } else - retval = 0; - /* copy the mount id */ - if (copy_to_user(mnt_id, &real_mount(path->mnt)->mnt_id, - sizeof(*mnt_id)) || - copy_to_user(ufh, handle, - sizeof(struct file_handle) + handle_bytes)) - retval = -EFAULT; - kfree(handle); - return retval; -} - -/** - * sys_name_to_handle_at: convert name to handle - * @dfd: directory relative to which name is interpreted if not absolute - * @name: name that should be converted to handle. - * @handle: resulting file handle - * @mnt_id: mount id of the file system containing the file - * @flag: flag value to indicate whether to follow symlink or not - * - * @handle->handle_size indicate the space available to store the - * variable part of the file handle in bytes. If there is not - * enough space, the field is updated to return the minimum - * value required. - */ -SYSCALL_DEFINE5(name_to_handle_at, int, dfd, const char __user *, name, - struct file_handle __user *, handle, int __user *, mnt_id, - int, flag) -{ - struct path path; - int lookup_flags; - int err; - - if ((flag & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0) - return -EINVAL; - - lookup_flags = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0; - if (flag & AT_EMPTY_PATH) - lookup_flags |= LOOKUP_EMPTY; - err = user_path_at(dfd, name, lookup_flags, &path); - if (!err) { - err = do_sys_name_to_handle(&path, handle, mnt_id); - path_put(&path); - } - return err; -} - -static struct vfsmount *get_vfsmount_from_fd(int fd) -{ - struct vfsmount *mnt; - - if (fd == AT_FDCWD) { - struct fs_struct *fs = current->fs; - spin_lock(&fs->lock); - mnt = mntget(fs->pwd.mnt); - spin_unlock(&fs->lock); - } else { - struct fd f = fdget(fd); - if (!f.file) - return ERR_PTR(-EBADF); - mnt = mntget(f.file->f_path.mnt); - fdput(f); - } - return mnt; -} - -static int vfs_dentry_acceptable(void *context, struct dentry *dentry) -{ - return 1; -} - -static int do_handle_to_path(int mountdirfd, struct file_handle *handle, - struct path *path) -{ - int retval = 0; - int handle_dwords; - - path->mnt = get_vfsmount_from_fd(mountdirfd); - if (IS_ERR(path->mnt)) { - retval = PTR_ERR(path->mnt); - goto out_err; - } - /* change the handle size to multiple of sizeof(u32) */ - handle_dwords = handle->handle_bytes >> 2; - path->dentry = exportfs_decode_fh(path->mnt, - (struct fid *)handle->f_handle, - handle_dwords, handle->handle_type, - vfs_dentry_acceptable, NULL); - if (IS_ERR(path->dentry)) { - retval = PTR_ERR(path->dentry); - goto out_mnt; - } - return 0; -out_mnt: - mntput(path->mnt); -out_err: - return retval; -} - -static int handle_to_path(int mountdirfd, struct file_handle __user *ufh, - struct path *path) -{ - int retval = 0; - struct file_handle f_handle; - struct file_handle *handle = NULL; - - /* - * With handle we don't look at the execute bit on the - * the directory. Ideally we would like CAP_DAC_SEARCH. - * But we don't have that - */ - if (!capable(CAP_DAC_READ_SEARCH)) { - retval = -EPERM; - goto out_err; - } - if (copy_from_user(&f_handle, ufh, sizeof(struct file_handle))) { - retval = -EFAULT; - goto out_err; - } - if ((f_handle.handle_bytes > MAX_HANDLE_SZ) || - (f_handle.handle_bytes == 0)) { - retval = -EINVAL; - goto out_err; - } - handle = kmalloc(sizeof(struct file_handle) + f_handle.handle_bytes, - GFP_KERNEL); - if (!handle) { - retval = -ENOMEM; - goto out_err; - } - /* copy the full handle */ - *handle = f_handle; - if (copy_from_user(&handle->f_handle, - &ufh->f_handle, - f_handle.handle_bytes)) { - retval = -EFAULT; - goto out_handle; - } - - retval = do_handle_to_path(mountdirfd, handle, path); - -out_handle: - kfree(handle); -out_err: - return retval; -} - -long do_handle_open(int mountdirfd, - struct file_handle __user *ufh, int open_flag) -{ - long retval = 0; - struct path path; - struct file *file; - int fd; - - retval = handle_to_path(mountdirfd, ufh, &path); - if (retval) - return retval; - - fd = get_unused_fd_flags(open_flag); - if (fd < 0) { - path_put(&path); - return fd; - } - file = file_open_root(path.dentry, path.mnt, "", open_flag, 0); - if (IS_ERR(file)) { - put_unused_fd(fd); - retval = PTR_ERR(file); - } else { - retval = fd; - fsnotify_open(file); - fd_install(fd, file); - } - path_put(&path); - return retval; -} - -/** - * sys_open_by_handle_at: Open the file handle - * @mountdirfd: directory file descriptor - * @handle: file handle to be opened - * @flag: open flags. - * - * @mountdirfd indicate the directory file descriptor - * of the mount point. file handle is decoded relative - * to the vfsmount pointed by the @mountdirfd. @flags - * value is same as the open(2) flags. - */ -SYSCALL_DEFINE3(open_by_handle_at, int, mountdirfd, - struct file_handle __user *, handle, - int, flags) -{ - long ret; - - if (force_o_largefile()) - flags |= O_LARGEFILE; - - ret = do_handle_open(mountdirfd, handle, flags); - return ret; -} diff --git a/src/linux/fs/file.c b/src/linux/fs/file.c deleted file mode 100644 index 69d6990..0000000 --- a/src/linux/fs/file.c +++ /dev/null @@ -1,987 +0,0 @@ -/* - * linux/fs/file.c - * - * Copyright (C) 1998-1999, Stephen Tweedie and Bill Hawes - * - * Manage the dynamic fd arrays in the process files_struct. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -unsigned int sysctl_nr_open __read_mostly = 1024*1024; -unsigned int sysctl_nr_open_min = BITS_PER_LONG; -/* our min() is unusable in constant expressions ;-/ */ -#define __const_min(x, y) ((x) < (y) ? (x) : (y)) -unsigned int sysctl_nr_open_max = - __const_min(INT_MAX, ~(size_t)0/sizeof(void *)) & -BITS_PER_LONG; - -static void *alloc_fdmem(size_t size) -{ - /* - * Very large allocations can stress page reclaim, so fall back to - * vmalloc() if the allocation size will be considered "large" by the VM. - */ - if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) { - void *data = kmalloc(size, GFP_KERNEL_ACCOUNT | - __GFP_NOWARN | __GFP_NORETRY); - if (data != NULL) - return data; - } - return __vmalloc(size, GFP_KERNEL_ACCOUNT | __GFP_HIGHMEM, PAGE_KERNEL); -} - -static void __free_fdtable(struct fdtable *fdt) -{ - kvfree(fdt->fd); - kvfree(fdt->open_fds); - kfree(fdt); -} - -static void free_fdtable_rcu(struct rcu_head *rcu) -{ - __free_fdtable(container_of(rcu, struct fdtable, rcu)); -} - -#define BITBIT_NR(nr) BITS_TO_LONGS(BITS_TO_LONGS(nr)) -#define BITBIT_SIZE(nr) (BITBIT_NR(nr) * sizeof(long)) - -/* - * Copy 'count' fd bits from the old table to the new table and clear the extra - * space if any. This does not copy the file pointers. Called with the files - * spinlock held for write. - */ -static void copy_fd_bitmaps(struct fdtable *nfdt, struct fdtable *ofdt, - unsigned int count) -{ - unsigned int cpy, set; - - cpy = count / BITS_PER_BYTE; - set = (nfdt->max_fds - count) / BITS_PER_BYTE; - memcpy(nfdt->open_fds, ofdt->open_fds, cpy); - memset((char *)nfdt->open_fds + cpy, 0, set); - memcpy(nfdt->close_on_exec, ofdt->close_on_exec, cpy); - memset((char *)nfdt->close_on_exec + cpy, 0, set); - - cpy = BITBIT_SIZE(count); - set = BITBIT_SIZE(nfdt->max_fds) - cpy; - memcpy(nfdt->full_fds_bits, ofdt->full_fds_bits, cpy); - memset((char *)nfdt->full_fds_bits + cpy, 0, set); -} - -/* - * Copy all file descriptors from the old table to the new, expanded table and - * clear the extra space. Called with the files spinlock held for write. - */ -static void copy_fdtable(struct fdtable *nfdt, struct fdtable *ofdt) -{ - unsigned int cpy, set; - - BUG_ON(nfdt->max_fds < ofdt->max_fds); - - cpy = ofdt->max_fds * sizeof(struct file *); - set = (nfdt->max_fds - ofdt->max_fds) * sizeof(struct file *); - memcpy(nfdt->fd, ofdt->fd, cpy); - memset((char *)nfdt->fd + cpy, 0, set); - - copy_fd_bitmaps(nfdt, ofdt, ofdt->max_fds); -} - -static struct fdtable * alloc_fdtable(unsigned int nr) -{ - struct fdtable *fdt; - void *data; - - /* - * Figure out how many fds we actually want to support in this fdtable. - * Allocation steps are keyed to the size of the fdarray, since it - * grows far faster than any of the other dynamic data. We try to fit - * the fdarray into comfortable page-tuned chunks: starting at 1024B - * and growing in powers of two from there on. - */ - nr /= (1024 / sizeof(struct file *)); - nr = roundup_pow_of_two(nr + 1); - nr *= (1024 / sizeof(struct file *)); - /* - * Note that this can drive nr *below* what we had passed if sysctl_nr_open - * had been set lower between the check in expand_files() and here. Deal - * with that in caller, it's cheaper that way. - * - * We make sure that nr remains a multiple of BITS_PER_LONG - otherwise - * bitmaps handling below becomes unpleasant, to put it mildly... - */ - if (unlikely(nr > sysctl_nr_open)) - nr = ((sysctl_nr_open - 1) | (BITS_PER_LONG - 1)) + 1; - - fdt = kmalloc(sizeof(struct fdtable), GFP_KERNEL_ACCOUNT); - if (!fdt) - goto out; - fdt->max_fds = nr; - data = alloc_fdmem(nr * sizeof(struct file *)); - if (!data) - goto out_fdt; - fdt->fd = data; - - data = alloc_fdmem(max_t(size_t, - 2 * nr / BITS_PER_BYTE + BITBIT_SIZE(nr), L1_CACHE_BYTES)); - if (!data) - goto out_arr; - fdt->open_fds = data; - data += nr / BITS_PER_BYTE; - fdt->close_on_exec = data; - data += nr / BITS_PER_BYTE; - fdt->full_fds_bits = data; - - return fdt; - -out_arr: - kvfree(fdt->fd); -out_fdt: - kfree(fdt); -out: - return NULL; -} - -/* - * Expand the file descriptor table. - * This function will allocate a new fdtable and both fd array and fdset, of - * the given size. - * Return <0 error code on error; 1 on successful completion. - * The files->file_lock should be held on entry, and will be held on exit. - */ -static int expand_fdtable(struct files_struct *files, unsigned int nr) - __releases(files->file_lock) - __acquires(files->file_lock) -{ - struct fdtable *new_fdt, *cur_fdt; - - spin_unlock(&files->file_lock); - new_fdt = alloc_fdtable(nr); - - /* make sure all __fd_install() have seen resize_in_progress - * or have finished their rcu_read_lock_sched() section. - */ - if (atomic_read(&files->count) > 1) - synchronize_sched(); - - spin_lock(&files->file_lock); - if (!new_fdt) - return -ENOMEM; - /* - * extremely unlikely race - sysctl_nr_open decreased between the check in - * caller and alloc_fdtable(). Cheaper to catch it here... - */ - if (unlikely(new_fdt->max_fds <= nr)) { - __free_fdtable(new_fdt); - return -EMFILE; - } - cur_fdt = files_fdtable(files); - BUG_ON(nr < cur_fdt->max_fds); - copy_fdtable(new_fdt, cur_fdt); - rcu_assign_pointer(files->fdt, new_fdt); - if (cur_fdt != &files->fdtab) - call_rcu(&cur_fdt->rcu, free_fdtable_rcu); - /* coupled with smp_rmb() in __fd_install() */ - smp_wmb(); - return 1; -} - -/* - * Expand files. - * This function will expand the file structures, if the requested size exceeds - * the current capacity and there is room for expansion. - * Return <0 error code on error; 0 when nothing done; 1 when files were - * expanded and execution may have blocked. - * The files->file_lock should be held on entry, and will be held on exit. - */ -static int expand_files(struct files_struct *files, unsigned int nr) - __releases(files->file_lock) - __acquires(files->file_lock) -{ - struct fdtable *fdt; - int expanded = 0; - -repeat: - fdt = files_fdtable(files); - - /* Do we need to expand? */ - if (nr < fdt->max_fds) - return expanded; - - /* Can we expand? */ - if (nr >= sysctl_nr_open) - return -EMFILE; - - if (unlikely(files->resize_in_progress)) { - spin_unlock(&files->file_lock); - expanded = 1; - wait_event(files->resize_wait, !files->resize_in_progress); - spin_lock(&files->file_lock); - goto repeat; - } - - /* All good, so we try */ - files->resize_in_progress = true; - expanded = expand_fdtable(files, nr); - files->resize_in_progress = false; - - wake_up_all(&files->resize_wait); - return expanded; -} - -static inline void __set_close_on_exec(unsigned int fd, struct fdtable *fdt) -{ - __set_bit(fd, fdt->close_on_exec); -} - -static inline void __clear_close_on_exec(unsigned int fd, struct fdtable *fdt) -{ - if (test_bit(fd, fdt->close_on_exec)) - __clear_bit(fd, fdt->close_on_exec); -} - -static inline void __set_open_fd(unsigned int fd, struct fdtable *fdt) -{ - __set_bit(fd, fdt->open_fds); - fd /= BITS_PER_LONG; - if (!~fdt->open_fds[fd]) - __set_bit(fd, fdt->full_fds_bits); -} - -static inline void __clear_open_fd(unsigned int fd, struct fdtable *fdt) -{ - __clear_bit(fd, fdt->open_fds); - __clear_bit(fd / BITS_PER_LONG, fdt->full_fds_bits); -} - -static unsigned int count_open_files(struct fdtable *fdt) -{ - unsigned int size = fdt->max_fds; - unsigned int i; - - /* Find the last open fd */ - for (i = size / BITS_PER_LONG; i > 0; ) { - if (fdt->open_fds[--i]) - break; - } - i = (i + 1) * BITS_PER_LONG; - return i; -} - -/* - * Allocate a new files structure and copy contents from the - * passed in files structure. - * errorp will be valid only when the returned files_struct is NULL. - */ -struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) -{ - struct files_struct *newf; - struct file **old_fds, **new_fds; - unsigned int open_files, i; - struct fdtable *old_fdt, *new_fdt; - - *errorp = -ENOMEM; - newf = kmem_cache_alloc(files_cachep, GFP_KERNEL); - if (!newf) - goto out; - - atomic_set(&newf->count, 1); - - spin_lock_init(&newf->file_lock); - newf->resize_in_progress = false; - init_waitqueue_head(&newf->resize_wait); - newf->next_fd = 0; - new_fdt = &newf->fdtab; - new_fdt->max_fds = NR_OPEN_DEFAULT; - new_fdt->close_on_exec = newf->close_on_exec_init; - new_fdt->open_fds = newf->open_fds_init; - new_fdt->full_fds_bits = newf->full_fds_bits_init; - new_fdt->fd = &newf->fd_array[0]; - - spin_lock(&oldf->file_lock); - old_fdt = files_fdtable(oldf); - open_files = count_open_files(old_fdt); - - /* - * Check whether we need to allocate a larger fd array and fd set. - */ - while (unlikely(open_files > new_fdt->max_fds)) { - spin_unlock(&oldf->file_lock); - - if (new_fdt != &newf->fdtab) - __free_fdtable(new_fdt); - - new_fdt = alloc_fdtable(open_files - 1); - if (!new_fdt) { - *errorp = -ENOMEM; - goto out_release; - } - - /* beyond sysctl_nr_open; nothing to do */ - if (unlikely(new_fdt->max_fds < open_files)) { - __free_fdtable(new_fdt); - *errorp = -EMFILE; - goto out_release; - } - - /* - * Reacquire the oldf lock and a pointer to its fd table - * who knows it may have a new bigger fd table. We need - * the latest pointer. - */ - spin_lock(&oldf->file_lock); - old_fdt = files_fdtable(oldf); - open_files = count_open_files(old_fdt); - } - - copy_fd_bitmaps(new_fdt, old_fdt, open_files); - - old_fds = old_fdt->fd; - new_fds = new_fdt->fd; - - for (i = open_files; i != 0; i--) { - struct file *f = *old_fds++; - if (f) { - get_file(f); - } else { - /* - * The fd may be claimed in the fd bitmap but not yet - * instantiated in the files array if a sibling thread - * is partway through open(). So make sure that this - * fd is available to the new process. - */ - __clear_open_fd(open_files - i, new_fdt); - } - rcu_assign_pointer(*new_fds++, f); - } - spin_unlock(&oldf->file_lock); - - /* clear the remainder */ - memset(new_fds, 0, (new_fdt->max_fds - open_files) * sizeof(struct file *)); - - rcu_assign_pointer(newf->fdt, new_fdt); - - return newf; - -out_release: - kmem_cache_free(files_cachep, newf); -out: - return NULL; -} - -static struct fdtable *close_files(struct files_struct * files) -{ - /* - * It is safe to dereference the fd table without RCU or - * ->file_lock because this is the last reference to the - * files structure. - */ - struct fdtable *fdt = rcu_dereference_raw(files->fdt); - unsigned int i, j = 0; - - for (;;) { - unsigned long set; - i = j * BITS_PER_LONG; - if (i >= fdt->max_fds) - break; - set = fdt->open_fds[j++]; - while (set) { - if (set & 1) { - struct file * file = xchg(&fdt->fd[i], NULL); - if (file) { - filp_close(file, files); - cond_resched_rcu_qs(); - } - } - i++; - set >>= 1; - } - } - - return fdt; -} - -struct files_struct *get_files_struct(struct task_struct *task) -{ - struct files_struct *files; - - task_lock(task); - files = task->files; - if (files) - atomic_inc(&files->count); - task_unlock(task); - - return files; -} - -void put_files_struct(struct files_struct *files) -{ - if (atomic_dec_and_test(&files->count)) { - struct fdtable *fdt = close_files(files); - - /* free the arrays if they are not embedded */ - if (fdt != &files->fdtab) - __free_fdtable(fdt); - kmem_cache_free(files_cachep, files); - } -} - -void reset_files_struct(struct files_struct *files) -{ - struct task_struct *tsk = current; - struct files_struct *old; - - old = tsk->files; - task_lock(tsk); - tsk->files = files; - task_unlock(tsk); - put_files_struct(old); -} - -void exit_files(struct task_struct *tsk) -{ - struct files_struct * files = tsk->files; - - if (files) { - task_lock(tsk); - tsk->files = NULL; - task_unlock(tsk); - put_files_struct(files); - } -} - -struct files_struct init_files = { - .count = ATOMIC_INIT(1), - .fdt = &init_files.fdtab, - .fdtab = { - .max_fds = NR_OPEN_DEFAULT, - .fd = &init_files.fd_array[0], - .close_on_exec = init_files.close_on_exec_init, - .open_fds = init_files.open_fds_init, - .full_fds_bits = init_files.full_fds_bits_init, - }, - .file_lock = __SPIN_LOCK_UNLOCKED(init_files.file_lock), -}; - -static unsigned int find_next_fd(struct fdtable *fdt, unsigned int start) -{ - unsigned int maxfd = fdt->max_fds; - unsigned int maxbit = maxfd / BITS_PER_LONG; - unsigned int bitbit = start / BITS_PER_LONG; - - bitbit = find_next_zero_bit(fdt->full_fds_bits, maxbit, bitbit) * BITS_PER_LONG; - if (bitbit > maxfd) - return maxfd; - if (bitbit > start) - start = bitbit; - return find_next_zero_bit(fdt->open_fds, maxfd, start); -} - -/* - * allocate a file descriptor, mark it busy. - */ -int __alloc_fd(struct files_struct *files, - unsigned start, unsigned end, unsigned flags) -{ - unsigned int fd; - int error; - struct fdtable *fdt; - - spin_lock(&files->file_lock); -repeat: - fdt = files_fdtable(files); - fd = start; - if (fd < files->next_fd) - fd = files->next_fd; - - if (fd < fdt->max_fds) - fd = find_next_fd(fdt, fd); - - /* - * N.B. For clone tasks sharing a files structure, this test - * will limit the total number of files that can be opened. - */ - error = -EMFILE; - if (fd >= end) - goto out; - - error = expand_files(files, fd); - if (error < 0) - goto out; - - /* - * If we needed to expand the fs array we - * might have blocked - try again. - */ - if (error) - goto repeat; - - if (start <= files->next_fd) - files->next_fd = fd + 1; - - __set_open_fd(fd, fdt); - if (flags & O_CLOEXEC) - __set_close_on_exec(fd, fdt); - else - __clear_close_on_exec(fd, fdt); - error = fd; -#if 1 - /* Sanity check */ - if (rcu_access_pointer(fdt->fd[fd]) != NULL) { - printk(KERN_WARNING "alloc_fd: slot %d not NULL!\n", fd); - rcu_assign_pointer(fdt->fd[fd], NULL); - } -#endif - -out: - spin_unlock(&files->file_lock); - return error; -} - -static int alloc_fd(unsigned start, unsigned flags) -{ - return __alloc_fd(current->files, start, rlimit(RLIMIT_NOFILE), flags); -} - -int get_unused_fd_flags(unsigned flags) -{ - return __alloc_fd(current->files, 0, rlimit(RLIMIT_NOFILE), flags); -} -EXPORT_SYMBOL(get_unused_fd_flags); - -static void __put_unused_fd(struct files_struct *files, unsigned int fd) -{ - struct fdtable *fdt = files_fdtable(files); - __clear_open_fd(fd, fdt); - if (fd < files->next_fd) - files->next_fd = fd; -} - -void put_unused_fd(unsigned int fd) -{ - struct files_struct *files = current->files; - spin_lock(&files->file_lock); - __put_unused_fd(files, fd); - spin_unlock(&files->file_lock); -} - -EXPORT_SYMBOL(put_unused_fd); - -/* - * Install a file pointer in the fd array. - * - * The VFS is full of places where we drop the files lock between - * setting the open_fds bitmap and installing the file in the file - * array. At any such point, we are vulnerable to a dup2() race - * installing a file in the array before us. We need to detect this and - * fput() the struct file we are about to overwrite in this case. - * - * It should never happen - if we allow dup2() do it, _really_ bad things - * will follow. - * - * NOTE: __fd_install() variant is really, really low-level; don't - * use it unless you are forced to by truly lousy API shoved down - * your throat. 'files' *MUST* be either current->files or obtained - * by get_files_struct(current) done by whoever had given it to you, - * or really bad things will happen. Normally you want to use - * fd_install() instead. - */ - -void __fd_install(struct files_struct *files, unsigned int fd, - struct file *file) -{ - struct fdtable *fdt; - - might_sleep(); - rcu_read_lock_sched(); - - while (unlikely(files->resize_in_progress)) { - rcu_read_unlock_sched(); - wait_event(files->resize_wait, !files->resize_in_progress); - rcu_read_lock_sched(); - } - /* coupled with smp_wmb() in expand_fdtable() */ - smp_rmb(); - fdt = rcu_dereference_sched(files->fdt); - BUG_ON(fdt->fd[fd] != NULL); - rcu_assign_pointer(fdt->fd[fd], file); - rcu_read_unlock_sched(); -} - -void fd_install(unsigned int fd, struct file *file) -{ - __fd_install(current->files, fd, file); -} - -EXPORT_SYMBOL(fd_install); - -/* - * The same warnings as for __alloc_fd()/__fd_install() apply here... - */ -int __close_fd(struct files_struct *files, unsigned fd) -{ - struct file *file; - struct fdtable *fdt; - - spin_lock(&files->file_lock); - fdt = files_fdtable(files); - if (fd >= fdt->max_fds) - goto out_unlock; - file = fdt->fd[fd]; - if (!file) - goto out_unlock; - rcu_assign_pointer(fdt->fd[fd], NULL); - __clear_close_on_exec(fd, fdt); - __put_unused_fd(files, fd); - spin_unlock(&files->file_lock); - return filp_close(file, files); - -out_unlock: - spin_unlock(&files->file_lock); - return -EBADF; -} - -void do_close_on_exec(struct files_struct *files) -{ - unsigned i; - struct fdtable *fdt; - - /* exec unshares first */ - spin_lock(&files->file_lock); - for (i = 0; ; i++) { - unsigned long set; - unsigned fd = i * BITS_PER_LONG; - fdt = files_fdtable(files); - if (fd >= fdt->max_fds) - break; - set = fdt->close_on_exec[i]; - if (!set) - continue; - fdt->close_on_exec[i] = 0; - for ( ; set ; fd++, set >>= 1) { - struct file *file; - if (!(set & 1)) - continue; - file = fdt->fd[fd]; - if (!file) - continue; - rcu_assign_pointer(fdt->fd[fd], NULL); - __put_unused_fd(files, fd); - spin_unlock(&files->file_lock); - filp_close(file, files); - cond_resched(); - spin_lock(&files->file_lock); - } - - } - spin_unlock(&files->file_lock); -} - -static struct file *__fget(unsigned int fd, fmode_t mask) -{ - struct files_struct *files = current->files; - struct file *file; - - rcu_read_lock(); -loop: - file = fcheck_files(files, fd); - if (file) { - /* File object ref couldn't be taken. - * dup2() atomicity guarantee is the reason - * we loop to catch the new file (or NULL pointer) - */ - if (file->f_mode & mask) - file = NULL; - else if (!get_file_rcu(file)) - goto loop; - } - rcu_read_unlock(); - - return file; -} - -struct file *fget(unsigned int fd) -{ - return __fget(fd, FMODE_PATH); -} -EXPORT_SYMBOL(fget); - -struct file *fget_raw(unsigned int fd) -{ - return __fget(fd, 0); -} -EXPORT_SYMBOL(fget_raw); - -/* - * Lightweight file lookup - no refcnt increment if fd table isn't shared. - * - * You can use this instead of fget if you satisfy all of the following - * conditions: - * 1) You must call fput_light before exiting the syscall and returning control - * to userspace (i.e. you cannot remember the returned struct file * after - * returning to userspace). - * 2) You must not call filp_close on the returned struct file * in between - * calls to fget_light and fput_light. - * 3) You must not clone the current task in between the calls to fget_light - * and fput_light. - * - * The fput_needed flag returned by fget_light should be passed to the - * corresponding fput_light. - */ -static unsigned long __fget_light(unsigned int fd, fmode_t mask) -{ - struct files_struct *files = current->files; - struct file *file; - - if (atomic_read(&files->count) == 1) { - file = __fcheck_files(files, fd); - if (!file || unlikely(file->f_mode & mask)) - return 0; - return (unsigned long)file; - } else { - file = __fget(fd, mask); - if (!file) - return 0; - return FDPUT_FPUT | (unsigned long)file; - } -} -unsigned long __fdget(unsigned int fd) -{ - return __fget_light(fd, FMODE_PATH); -} -EXPORT_SYMBOL(__fdget); - -unsigned long __fdget_raw(unsigned int fd) -{ - return __fget_light(fd, 0); -} - -unsigned long __fdget_pos(unsigned int fd) -{ - unsigned long v = __fdget(fd); - struct file *file = (struct file *)(v & ~3); - - if (file && (file->f_mode & FMODE_ATOMIC_POS)) { - if (file_count(file) > 1) { - v |= FDPUT_POS_UNLOCK; - mutex_lock(&file->f_pos_lock); - } - } - return v; -} - -void __f_unlock_pos(struct file *f) -{ - mutex_unlock(&f->f_pos_lock); -} - -/* - * We only lock f_pos if we have threads or if the file might be - * shared with another process. In both cases we'll have an elevated - * file count (done either by fdget() or by fork()). - */ - -void set_close_on_exec(unsigned int fd, int flag) -{ - struct files_struct *files = current->files; - struct fdtable *fdt; - spin_lock(&files->file_lock); - fdt = files_fdtable(files); - if (flag) - __set_close_on_exec(fd, fdt); - else - __clear_close_on_exec(fd, fdt); - spin_unlock(&files->file_lock); -} - -bool get_close_on_exec(unsigned int fd) -{ - struct files_struct *files = current->files; - struct fdtable *fdt; - bool res; - rcu_read_lock(); - fdt = files_fdtable(files); - res = close_on_exec(fd, fdt); - rcu_read_unlock(); - return res; -} - -static int do_dup2(struct files_struct *files, - struct file *file, unsigned fd, unsigned flags) -__releases(&files->file_lock) -{ - struct file *tofree; - struct fdtable *fdt; - - /* - * We need to detect attempts to do dup2() over allocated but still - * not finished descriptor. NB: OpenBSD avoids that at the price of - * extra work in their equivalent of fget() - they insert struct - * file immediately after grabbing descriptor, mark it larval if - * more work (e.g. actual opening) is needed and make sure that - * fget() treats larval files as absent. Potentially interesting, - * but while extra work in fget() is trivial, locking implications - * and amount of surgery on open()-related paths in VFS are not. - * FreeBSD fails with -EBADF in the same situation, NetBSD "solution" - * deadlocks in rather amusing ways, AFAICS. All of that is out of - * scope of POSIX or SUS, since neither considers shared descriptor - * tables and this condition does not arise without those. - */ - fdt = files_fdtable(files); - tofree = fdt->fd[fd]; - if (!tofree && fd_is_open(fd, fdt)) - goto Ebusy; - get_file(file); - rcu_assign_pointer(fdt->fd[fd], file); - __set_open_fd(fd, fdt); - if (flags & O_CLOEXEC) - __set_close_on_exec(fd, fdt); - else - __clear_close_on_exec(fd, fdt); - spin_unlock(&files->file_lock); - - if (tofree) - filp_close(tofree, files); - - return fd; - -Ebusy: - spin_unlock(&files->file_lock); - return -EBUSY; -} - -int replace_fd(unsigned fd, struct file *file, unsigned flags) -{ - int err; - struct files_struct *files = current->files; - - if (!file) - return __close_fd(files, fd); - - if (fd >= rlimit(RLIMIT_NOFILE)) - return -EBADF; - - spin_lock(&files->file_lock); - err = expand_files(files, fd); - if (unlikely(err < 0)) - goto out_unlock; - return do_dup2(files, file, fd, flags); - -out_unlock: - spin_unlock(&files->file_lock); - return err; -} - -SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags) -{ - int err = -EBADF; - struct file *file; - struct files_struct *files = current->files; - - if ((flags & ~O_CLOEXEC) != 0) - return -EINVAL; - - if (unlikely(oldfd == newfd)) - return -EINVAL; - - if (newfd >= rlimit(RLIMIT_NOFILE)) - return -EBADF; - - spin_lock(&files->file_lock); - err = expand_files(files, newfd); - file = fcheck(oldfd); - if (unlikely(!file)) - goto Ebadf; - if (unlikely(err < 0)) { - if (err == -EMFILE) - goto Ebadf; - goto out_unlock; - } - return do_dup2(files, file, newfd, flags); - -Ebadf: - err = -EBADF; -out_unlock: - spin_unlock(&files->file_lock); - return err; -} - -SYSCALL_DEFINE2(dup2, unsigned int, oldfd, unsigned int, newfd) -{ - if (unlikely(newfd == oldfd)) { /* corner case */ - struct files_struct *files = current->files; - int retval = oldfd; - - rcu_read_lock(); - if (!fcheck_files(files, oldfd)) - retval = -EBADF; - rcu_read_unlock(); - return retval; - } - return sys_dup3(oldfd, newfd, 0); -} - -SYSCALL_DEFINE1(dup, unsigned int, fildes) -{ - int ret = -EBADF; - struct file *file = fget_raw(fildes); - - if (file) { - ret = get_unused_fd_flags(0); - if (ret >= 0) - fd_install(ret, file); - else - fput(file); - } - return ret; -} - -int f_dupfd(unsigned int from, struct file *file, unsigned flags) -{ - int err; - if (from >= rlimit(RLIMIT_NOFILE)) - return -EINVAL; - err = alloc_fd(from, flags); - if (err >= 0) { - get_file(file); - fd_install(err, file); - } - return err; -} - -int iterate_fd(struct files_struct *files, unsigned n, - int (*f)(const void *, struct file *, unsigned), - const void *p) -{ - struct fdtable *fdt; - int res = 0; - if (!files) - return 0; - spin_lock(&files->file_lock); - for (fdt = files_fdtable(files); n < fdt->max_fds; n++) { - struct file *file; - file = rcu_dereference_check_fdtable(files, fdt->fd[n]); - if (!file) - continue; - res = f(p, file, n); - if (res) - break; - } - spin_unlock(&files->file_lock); - return res; -} -EXPORT_SYMBOL(iterate_fd); diff --git a/src/linux/fs/file_table.c b/src/linux/fs/file_table.c deleted file mode 100644 index ad17e05..0000000 --- a/src/linux/fs/file_table.c +++ /dev/null @@ -1,332 +0,0 @@ -/* - * linux/fs/file_table.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "internal.h" - -/* sysctl tunables... */ -struct files_stat_struct files_stat = { - .max_files = NR_FILE -}; - -/* SLAB cache for file structures */ -static struct kmem_cache *filp_cachep __read_mostly; - -static struct percpu_counter nr_files __cacheline_aligned_in_smp; - -static void file_free_rcu(struct rcu_head *head) -{ - struct file *f = container_of(head, struct file, f_u.fu_rcuhead); - - put_cred(f->f_cred); - kmem_cache_free(filp_cachep, f); -} - -static inline void file_free(struct file *f) -{ - percpu_counter_dec(&nr_files); - call_rcu(&f->f_u.fu_rcuhead, file_free_rcu); -} - -/* - * Return the total number of open files in the system - */ -static long get_nr_files(void) -{ - return percpu_counter_read_positive(&nr_files); -} - -/* - * Return the maximum number of open files in the system - */ -unsigned long get_max_files(void) -{ - return files_stat.max_files; -} -EXPORT_SYMBOL_GPL(get_max_files); - -/* - * Handle nr_files sysctl - */ -#if defined(CONFIG_SYSCTL) && defined(CONFIG_PROC_FS) -int proc_nr_files(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - files_stat.nr_files = get_nr_files(); - return proc_doulongvec_minmax(table, write, buffer, lenp, ppos); -} -#else -int proc_nr_files(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return -ENOSYS; -} -#endif - -/* Find an unused file structure and return a pointer to it. - * Returns an error pointer if some error happend e.g. we over file - * structures limit, run out of memory or operation is not permitted. - * - * Be very careful using this. You are responsible for - * getting write access to any mount that you might assign - * to this filp, if it is opened for write. If this is not - * done, you will imbalance int the mount's writer count - * and a warning at __fput() time. - */ -struct file *get_empty_filp(void) -{ - const struct cred *cred = current_cred(); - static long old_max; - struct file *f; - int error; - - /* - * Privileged users can go above max_files - */ - if (get_nr_files() >= files_stat.max_files && !capable(CAP_SYS_ADMIN)) { - /* - * percpu_counters are inaccurate. Do an expensive check before - * we go and fail. - */ - if (percpu_counter_sum_positive(&nr_files) >= files_stat.max_files) - goto over; - } - - f = kmem_cache_zalloc(filp_cachep, GFP_KERNEL); - if (unlikely(!f)) - return ERR_PTR(-ENOMEM); - - percpu_counter_inc(&nr_files); - f->f_cred = get_cred(cred); - error = security_file_alloc(f); - if (unlikely(error)) { - file_free(f); - return ERR_PTR(error); - } - - atomic_long_set(&f->f_count, 1); - rwlock_init(&f->f_owner.lock); - spin_lock_init(&f->f_lock); - mutex_init(&f->f_pos_lock); - eventpoll_init_file(f); - /* f->f_version: 0 */ - return f; - -over: - /* Ran out of filps - report that */ - if (get_nr_files() > old_max) { - pr_info("VFS: file-max limit %lu reached\n", get_max_files()); - old_max = get_nr_files(); - } - return ERR_PTR(-ENFILE); -} - -/** - * alloc_file - allocate and initialize a 'struct file' - * - * @path: the (dentry, vfsmount) pair for the new file - * @mode: the mode with which the new file will be opened - * @fop: the 'struct file_operations' for the new file - */ -struct file *alloc_file(struct path *path, fmode_t mode, - const struct file_operations *fop) -{ - struct file *file; - - file = get_empty_filp(); - if (IS_ERR(file)) - return file; - - file->f_path = *path; - file->f_inode = path->dentry->d_inode; - file->f_mapping = path->dentry->d_inode->i_mapping; - if ((mode & FMODE_READ) && - likely(fop->read || fop->read_iter)) - mode |= FMODE_CAN_READ; - if ((mode & FMODE_WRITE) && - likely(fop->write || fop->write_iter)) - mode |= FMODE_CAN_WRITE; - file->f_mode = mode; - file->f_op = fop; - if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) - i_readcount_inc(path->dentry->d_inode); - return file; -} -EXPORT_SYMBOL(alloc_file); - -/* the real guts of fput() - releasing the last reference to file - */ -static void __fput(struct file *file) -{ - struct dentry *dentry = file->f_path.dentry; - struct vfsmount *mnt = file->f_path.mnt; - struct inode *inode = file->f_inode; - - might_sleep(); - - fsnotify_close(file); - /* - * The function eventpoll_release() should be the first called - * in the file cleanup chain. - */ - eventpoll_release(file); - locks_remove_file(file); - - if (unlikely(file->f_flags & FASYNC)) { - if (file->f_op->fasync) - file->f_op->fasync(-1, file, 0); - } - ima_file_free(file); - if (file->f_op->release) - file->f_op->release(inode, file); - security_file_free(file); - if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL && - !(file->f_mode & FMODE_PATH))) { - cdev_put(inode->i_cdev); - } - fops_put(file->f_op); - put_pid(file->f_owner.pid); - if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) - i_readcount_dec(inode); - if (file->f_mode & FMODE_WRITER) { - put_write_access(inode); - __mnt_drop_write(mnt); - } - file->f_path.dentry = NULL; - file->f_path.mnt = NULL; - file->f_inode = NULL; - file_free(file); - dput(dentry); - mntput(mnt); -} - -static LLIST_HEAD(delayed_fput_list); -static void delayed_fput(struct work_struct *unused) -{ - struct llist_node *node = llist_del_all(&delayed_fput_list); - struct llist_node *next; - - for (; node; node = next) { - next = llist_next(node); - __fput(llist_entry(node, struct file, f_u.fu_llist)); - } -} - -static void ____fput(struct callback_head *work) -{ - __fput(container_of(work, struct file, f_u.fu_rcuhead)); -} - -/* - * If kernel thread really needs to have the final fput() it has done - * to complete, call this. The only user right now is the boot - we - * *do* need to make sure our writes to binaries on initramfs has - * not left us with opened struct file waiting for __fput() - execve() - * won't work without that. Please, don't add more callers without - * very good reasons; in particular, never call that with locks - * held and never call that from a thread that might need to do - * some work on any kind of umount. - */ -void flush_delayed_fput(void) -{ - delayed_fput(NULL); -} - -static DECLARE_DELAYED_WORK(delayed_fput_work, delayed_fput); - -void fput(struct file *file) -{ - if (atomic_long_dec_and_test(&file->f_count)) { - struct task_struct *task = current; - - if (likely(!in_interrupt() && !(task->flags & PF_KTHREAD))) { - init_task_work(&file->f_u.fu_rcuhead, ____fput); - if (!task_work_add(task, &file->f_u.fu_rcuhead, true)) - return; - /* - * After this task has run exit_task_work(), - * task_work_add() will fail. Fall through to delayed - * fput to avoid leaking *file. - */ - } - - if (llist_add(&file->f_u.fu_llist, &delayed_fput_list)) - schedule_delayed_work(&delayed_fput_work, 1); - } -} - -/* - * synchronous analog of fput(); for kernel threads that might be needed - * in some umount() (and thus can't use flush_delayed_fput() without - * risking deadlocks), need to wait for completion of __fput() and know - * for this specific struct file it won't involve anything that would - * need them. Use only if you really need it - at the very least, - * don't blindly convert fput() by kernel thread to that. - */ -void __fput_sync(struct file *file) -{ - if (atomic_long_dec_and_test(&file->f_count)) { - struct task_struct *task = current; - BUG_ON(!(task->flags & PF_KTHREAD)); - __fput(file); - } -} - -EXPORT_SYMBOL(fput); - -void put_filp(struct file *file) -{ - if (atomic_long_dec_and_test(&file->f_count)) { - security_file_free(file); - file_free(file); - } -} - -void __init files_init(void) -{ - filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0, - SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); - percpu_counter_init(&nr_files, 0, GFP_KERNEL); -} - -/* - * One file with associated inode and dcache is very roughly 1K. Per default - * do not use more than 10% of our memory for files. - */ -void __init files_maxfiles_init(void) -{ - unsigned long n; - unsigned long memreserve = (totalram_pages - nr_free_pages()) * 3/2; - - memreserve = min(memreserve, totalram_pages - 1); - n = ((totalram_pages - memreserve) * (PAGE_SIZE / 1024)) / 10; - - files_stat.max_files = max_t(unsigned long, n, NR_FILE); -} diff --git a/src/linux/fs/filesystems.c b/src/linux/fs/filesystems.c deleted file mode 100644 index c5618db..0000000 --- a/src/linux/fs/filesystems.c +++ /dev/null @@ -1,288 +0,0 @@ -/* - * linux/fs/filesystems.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * table of configured filesystems - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Handling of filesystem drivers list. - * Rules: - * Inclusion to/removals from/scanning of list are protected by spinlock. - * During the unload module must call unregister_filesystem(). - * We can access the fields of list element if: - * 1) spinlock is held or - * 2) we hold the reference to the module. - * The latter can be guaranteed by call of try_module_get(); if it - * returned 0 we must skip the element, otherwise we got the reference. - * Once the reference is obtained we can drop the spinlock. - */ - -static struct file_system_type *file_systems; -static DEFINE_RWLOCK(file_systems_lock); - -/* WARNING: This can be used only if we _already_ own a reference */ -void get_filesystem(struct file_system_type *fs) -{ - __module_get(fs->owner); -} - -void put_filesystem(struct file_system_type *fs) -{ - module_put(fs->owner); -} - -static struct file_system_type **find_filesystem(const char *name, unsigned len) -{ - struct file_system_type **p; - for (p = &file_systems; *p; p = &(*p)->next) - if (strncmp((*p)->name, name, len) == 0 && - !(*p)->name[len]) - break; - return p; -} - -/** - * register_filesystem - register a new filesystem - * @fs: the file system structure - * - * Adds the file system passed to the list of file systems the kernel - * is aware of for mount and other syscalls. Returns 0 on success, - * or a negative errno code on an error. - * - * The &struct file_system_type that is passed is linked into the kernel - * structures and must not be freed until the file system has been - * unregistered. - */ - -int register_filesystem(struct file_system_type * fs) -{ - int res = 0; - struct file_system_type ** p; - - BUG_ON(strchr(fs->name, '.')); - if (fs->next) - return -EBUSY; - write_lock(&file_systems_lock); - p = find_filesystem(fs->name, strlen(fs->name)); - if (*p) - res = -EBUSY; - else - *p = fs; - write_unlock(&file_systems_lock); - return res; -} - -EXPORT_SYMBOL(register_filesystem); - -/** - * unregister_filesystem - unregister a file system - * @fs: filesystem to unregister - * - * Remove a file system that was previously successfully registered - * with the kernel. An error is returned if the file system is not found. - * Zero is returned on a success. - * - * Once this function has returned the &struct file_system_type structure - * may be freed or reused. - */ - -int unregister_filesystem(struct file_system_type * fs) -{ - struct file_system_type ** tmp; - - write_lock(&file_systems_lock); - tmp = &file_systems; - while (*tmp) { - if (fs == *tmp) { - *tmp = fs->next; - fs->next = NULL; - write_unlock(&file_systems_lock); - synchronize_rcu(); - return 0; - } - tmp = &(*tmp)->next; - } - write_unlock(&file_systems_lock); - - return -EINVAL; -} - -EXPORT_SYMBOL(unregister_filesystem); - -#ifdef CONFIG_SYSFS_SYSCALL -static int fs_index(const char __user * __name) -{ - struct file_system_type * tmp; - struct filename *name; - int err, index; - - name = getname(__name); - err = PTR_ERR(name); - if (IS_ERR(name)) - return err; - - err = -EINVAL; - read_lock(&file_systems_lock); - for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) { - if (strcmp(tmp->name, name->name) == 0) { - err = index; - break; - } - } - read_unlock(&file_systems_lock); - putname(name); - return err; -} - -static int fs_name(unsigned int index, char __user * buf) -{ - struct file_system_type * tmp; - int len, res; - - read_lock(&file_systems_lock); - for (tmp = file_systems; tmp; tmp = tmp->next, index--) - if (index <= 0 && try_module_get(tmp->owner)) - break; - read_unlock(&file_systems_lock); - if (!tmp) - return -EINVAL; - - /* OK, we got the reference, so we can safely block */ - len = strlen(tmp->name) + 1; - res = copy_to_user(buf, tmp->name, len) ? -EFAULT : 0; - put_filesystem(tmp); - return res; -} - -static int fs_maxindex(void) -{ - struct file_system_type * tmp; - int index; - - read_lock(&file_systems_lock); - for (tmp = file_systems, index = 0 ; tmp ; tmp = tmp->next, index++) - ; - read_unlock(&file_systems_lock); - return index; -} - -/* - * Whee.. Weird sysv syscall. - */ -SYSCALL_DEFINE3(sysfs, int, option, unsigned long, arg1, unsigned long, arg2) -{ - int retval = -EINVAL; - - switch (option) { - case 1: - retval = fs_index((const char __user *) arg1); - break; - - case 2: - retval = fs_name(arg1, (char __user *) arg2); - break; - - case 3: - retval = fs_maxindex(); - break; - } - return retval; -} -#endif - -int __init get_filesystem_list(char *buf) -{ - int len = 0; - struct file_system_type * tmp; - - read_lock(&file_systems_lock); - tmp = file_systems; - while (tmp && len < PAGE_SIZE - 80) { - len += sprintf(buf+len, "%s\t%s\n", - (tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev", - tmp->name); - tmp = tmp->next; - } - read_unlock(&file_systems_lock); - return len; -} - -#ifdef CONFIG_PROC_FS -static int filesystems_proc_show(struct seq_file *m, void *v) -{ - struct file_system_type * tmp; - - read_lock(&file_systems_lock); - tmp = file_systems; - while (tmp) { - seq_printf(m, "%s\t%s\n", - (tmp->fs_flags & FS_REQUIRES_DEV) ? "" : "nodev", - tmp->name); - tmp = tmp->next; - } - read_unlock(&file_systems_lock); - return 0; -} - -static int filesystems_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, filesystems_proc_show, NULL); -} - -static const struct file_operations filesystems_proc_fops = { - .open = filesystems_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init proc_filesystems_init(void) -{ - proc_create("filesystems", 0, NULL, &filesystems_proc_fops); - return 0; -} -module_init(proc_filesystems_init); -#endif - -static struct file_system_type *__get_fs_type(const char *name, int len) -{ - struct file_system_type *fs; - - read_lock(&file_systems_lock); - fs = *(find_filesystem(name, len)); - if (fs && !try_module_get(fs->owner)) - fs = NULL; - read_unlock(&file_systems_lock); - return fs; -} - -struct file_system_type *get_fs_type(const char *name) -{ - struct file_system_type *fs; - const char *dot = strchr(name, '.'); - int len = dot ? dot - name : strlen(name); - - fs = __get_fs_type(name, len); - if (!fs && (request_module("fs-%.*s", len, name) == 0)) - fs = __get_fs_type(name, len); - - if (dot && fs && !(fs->fs_flags & FS_HAS_SUBTYPE)) { - put_filesystem(fs); - fs = NULL; - } - return fs; -} - -EXPORT_SYMBOL(get_fs_type); diff --git a/src/linux/fs/freevxfs/Kconfig b/src/linux/fs/freevxfs/Kconfig deleted file mode 100644 index ce49df1..0000000 --- a/src/linux/fs/freevxfs/Kconfig +++ /dev/null @@ -1,25 +0,0 @@ -config VXFS_FS - tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)" - depends on BLOCK - help - FreeVxFS is a file system driver that support the VERITAS VxFS(TM) - file system format. VERITAS VxFS(TM) is the standard file system - of SCO UnixWare (and possibly others) and optionally available - for Sunsoft Solaris, HP-UX and many other operating systems. However - these particular OS implementations of vxfs may differ in on-disk - data endianess and/or superblock offset. The vxfs module has been - tested with SCO UnixWare and HP-UX B.10.20 (pa-risc 1.1 arch.) - Currently only readonly access is supported and VxFX versions - 2, 3 and 4. Tests were performed with HP-UX VxFS version 3. - - NOTE: the file system type as used by mount(1), mount(2) and - fstab(5) is 'vxfs' as it describes the file system format, not - the actual driver. - - There is a userspace utility for HP-UX logical volumes which makes - creating HP-UX logical volumes easy from HP-UX disk block device file - or regular file with image of the disk. See: - https://sourceforge.net/projects/linux-vxfs/ - - To compile this as a module, choose M here: the module will be - called freevxfs. If unsure, say N. diff --git a/src/linux/fs/fs-writeback.c b/src/linux/fs/fs-writeback.c deleted file mode 100644 index 05713a5..0000000 --- a/src/linux/fs/fs-writeback.c +++ /dev/null @@ -1,2472 +0,0 @@ -/* - * fs/fs-writeback.c - * - * Copyright (C) 2002, Linus Torvalds. - * - * Contains all the functions related to writing back and waiting - * upon dirty inodes against superblocks, and writing back dirty - * pages against inodes. ie: data writeback. Writeout of the - * inode itself is not handled here. - * - * 10Apr2002 Andrew Morton - * Split out of fs/inode.c - * Additions for address_space-based writeback - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -/* - * 4MB minimal write chunk size - */ -#define MIN_WRITEBACK_PAGES (4096UL >> (PAGE_SHIFT - 10)) - -struct wb_completion { - atomic_t cnt; -}; - -/* - * Passed into wb_writeback(), essentially a subset of writeback_control - */ -struct wb_writeback_work { - long nr_pages; - struct super_block *sb; - unsigned long *older_than_this; - enum writeback_sync_modes sync_mode; - unsigned int tagged_writepages:1; - unsigned int for_kupdate:1; - unsigned int range_cyclic:1; - unsigned int for_background:1; - unsigned int for_sync:1; /* sync(2) WB_SYNC_ALL writeback */ - unsigned int auto_free:1; /* free on completion */ - enum wb_reason reason; /* why was writeback initiated? */ - - struct list_head list; /* pending work list */ - struct wb_completion *done; /* set if the caller waits */ -}; - -/* - * If one wants to wait for one or more wb_writeback_works, each work's - * ->done should be set to a wb_completion defined using the following - * macro. Once all work items are issued with wb_queue_work(), the caller - * can wait for the completion of all using wb_wait_for_completion(). Work - * items which are waited upon aren't freed automatically on completion. - */ -#define DEFINE_WB_COMPLETION_ONSTACK(cmpl) \ - struct wb_completion cmpl = { \ - .cnt = ATOMIC_INIT(1), \ - } - - -/* - * If an inode is constantly having its pages dirtied, but then the - * updates stop dirtytime_expire_interval seconds in the past, it's - * possible for the worst case time between when an inode has its - * timestamps updated and when they finally get written out to be two - * dirtytime_expire_intervals. We set the default to 12 hours (in - * seconds), which means most of the time inodes will have their - * timestamps written to disk after 12 hours, but in the worst case a - * few inodes might not their timestamps updated for 24 hours. - */ -unsigned int dirtytime_expire_interval = 12 * 60 * 60; - -static inline struct inode *wb_inode(struct list_head *head) -{ - return list_entry(head, struct inode, i_io_list); -} - -/* - * Include the creation of the trace points after defining the - * wb_writeback_work structure and inline functions so that the definition - * remains local to this file. - */ -#define CREATE_TRACE_POINTS -#include - -EXPORT_TRACEPOINT_SYMBOL_GPL(wbc_writepage); - -static bool wb_io_lists_populated(struct bdi_writeback *wb) -{ - if (wb_has_dirty_io(wb)) { - return false; - } else { - set_bit(WB_has_dirty_io, &wb->state); - WARN_ON_ONCE(!wb->avg_write_bandwidth); - atomic_long_add(wb->avg_write_bandwidth, - &wb->bdi->tot_write_bandwidth); - return true; - } -} - -static void wb_io_lists_depopulated(struct bdi_writeback *wb) -{ - if (wb_has_dirty_io(wb) && list_empty(&wb->b_dirty) && - list_empty(&wb->b_io) && list_empty(&wb->b_more_io)) { - clear_bit(WB_has_dirty_io, &wb->state); - WARN_ON_ONCE(atomic_long_sub_return(wb->avg_write_bandwidth, - &wb->bdi->tot_write_bandwidth) < 0); - } -} - -/** - * inode_io_list_move_locked - move an inode onto a bdi_writeback IO list - * @inode: inode to be moved - * @wb: target bdi_writeback - * @head: one of @wb->b_{dirty|io|more_io} - * - * Move @inode->i_io_list to @list of @wb and set %WB_has_dirty_io. - * Returns %true if @inode is the first occupant of the !dirty_time IO - * lists; otherwise, %false. - */ -static bool inode_io_list_move_locked(struct inode *inode, - struct bdi_writeback *wb, - struct list_head *head) -{ - assert_spin_locked(&wb->list_lock); - - list_move(&inode->i_io_list, head); - - /* dirty_time doesn't count as dirty_io until expiration */ - if (head != &wb->b_dirty_time) - return wb_io_lists_populated(wb); - - wb_io_lists_depopulated(wb); - return false; -} - -/** - * inode_io_list_del_locked - remove an inode from its bdi_writeback IO list - * @inode: inode to be removed - * @wb: bdi_writeback @inode is being removed from - * - * Remove @inode which may be on one of @wb->b_{dirty|io|more_io} lists and - * clear %WB_has_dirty_io if all are empty afterwards. - */ -static void inode_io_list_del_locked(struct inode *inode, - struct bdi_writeback *wb) -{ - assert_spin_locked(&wb->list_lock); - - list_del_init(&inode->i_io_list); - wb_io_lists_depopulated(wb); -} - -static void wb_wakeup(struct bdi_writeback *wb) -{ - spin_lock_bh(&wb->work_lock); - if (test_bit(WB_registered, &wb->state)) - mod_delayed_work(bdi_wq, &wb->dwork, 0); - spin_unlock_bh(&wb->work_lock); -} - -static void wb_queue_work(struct bdi_writeback *wb, - struct wb_writeback_work *work) -{ - trace_writeback_queue(wb, work); - - spin_lock_bh(&wb->work_lock); - if (!test_bit(WB_registered, &wb->state)) - goto out_unlock; - if (work->done) - atomic_inc(&work->done->cnt); - list_add_tail(&work->list, &wb->work_list); - mod_delayed_work(bdi_wq, &wb->dwork, 0); -out_unlock: - spin_unlock_bh(&wb->work_lock); -} - -/** - * wb_wait_for_completion - wait for completion of bdi_writeback_works - * @bdi: bdi work items were issued to - * @done: target wb_completion - * - * Wait for one or more work items issued to @bdi with their ->done field - * set to @done, which should have been defined with - * DEFINE_WB_COMPLETION_ONSTACK(). This function returns after all such - * work items are completed. Work items which are waited upon aren't freed - * automatically on completion. - */ -static void wb_wait_for_completion(struct backing_dev_info *bdi, - struct wb_completion *done) -{ - atomic_dec(&done->cnt); /* put down the initial count */ - wait_event(bdi->wb_waitq, !atomic_read(&done->cnt)); -} - -#ifdef CONFIG_CGROUP_WRITEBACK - -/* parameters for foreign inode detection, see wb_detach_inode() */ -#define WB_FRN_TIME_SHIFT 13 /* 1s = 2^13, upto 8 secs w/ 16bit */ -#define WB_FRN_TIME_AVG_SHIFT 3 /* avg = avg * 7/8 + new * 1/8 */ -#define WB_FRN_TIME_CUT_DIV 2 /* ignore rounds < avg / 2 */ -#define WB_FRN_TIME_PERIOD (2 * (1 << WB_FRN_TIME_SHIFT)) /* 2s */ - -#define WB_FRN_HIST_SLOTS 16 /* inode->i_wb_frn_history is 16bit */ -#define WB_FRN_HIST_UNIT (WB_FRN_TIME_PERIOD / WB_FRN_HIST_SLOTS) - /* each slot's duration is 2s / 16 */ -#define WB_FRN_HIST_THR_SLOTS (WB_FRN_HIST_SLOTS / 2) - /* if foreign slots >= 8, switch */ -#define WB_FRN_HIST_MAX_SLOTS (WB_FRN_HIST_THR_SLOTS / 2 + 1) - /* one round can affect upto 5 slots */ - -static atomic_t isw_nr_in_flight = ATOMIC_INIT(0); -static struct workqueue_struct *isw_wq; - -void __inode_attach_wb(struct inode *inode, struct page *page) -{ - struct backing_dev_info *bdi = inode_to_bdi(inode); - struct bdi_writeback *wb = NULL; - - if (inode_cgwb_enabled(inode)) { - struct cgroup_subsys_state *memcg_css; - - if (page) { - memcg_css = mem_cgroup_css_from_page(page); - wb = wb_get_create(bdi, memcg_css, GFP_ATOMIC); - } else { - /* must pin memcg_css, see wb_get_create() */ - memcg_css = task_get_css(current, memory_cgrp_id); - wb = wb_get_create(bdi, memcg_css, GFP_ATOMIC); - css_put(memcg_css); - } - } - - if (!wb) - wb = &bdi->wb; - - /* - * There may be multiple instances of this function racing to - * update the same inode. Use cmpxchg() to tell the winner. - */ - if (unlikely(cmpxchg(&inode->i_wb, NULL, wb))) - wb_put(wb); -} - -/** - * locked_inode_to_wb_and_lock_list - determine a locked inode's wb and lock it - * @inode: inode of interest with i_lock held - * - * Returns @inode's wb with its list_lock held. @inode->i_lock must be - * held on entry and is released on return. The returned wb is guaranteed - * to stay @inode's associated wb until its list_lock is released. - */ -static struct bdi_writeback * -locked_inode_to_wb_and_lock_list(struct inode *inode) - __releases(&inode->i_lock) - __acquires(&wb->list_lock) -{ - while (true) { - struct bdi_writeback *wb = inode_to_wb(inode); - - /* - * inode_to_wb() association is protected by both - * @inode->i_lock and @wb->list_lock but list_lock nests - * outside i_lock. Drop i_lock and verify that the - * association hasn't changed after acquiring list_lock. - */ - wb_get(wb); - spin_unlock(&inode->i_lock); - spin_lock(&wb->list_lock); - - /* i_wb may have changed inbetween, can't use inode_to_wb() */ - if (likely(wb == inode->i_wb)) { - wb_put(wb); /* @inode already has ref */ - return wb; - } - - spin_unlock(&wb->list_lock); - wb_put(wb); - cpu_relax(); - spin_lock(&inode->i_lock); - } -} - -/** - * inode_to_wb_and_lock_list - determine an inode's wb and lock it - * @inode: inode of interest - * - * Same as locked_inode_to_wb_and_lock_list() but @inode->i_lock isn't held - * on entry. - */ -static struct bdi_writeback *inode_to_wb_and_lock_list(struct inode *inode) - __acquires(&wb->list_lock) -{ - spin_lock(&inode->i_lock); - return locked_inode_to_wb_and_lock_list(inode); -} - -struct inode_switch_wbs_context { - struct inode *inode; - struct bdi_writeback *new_wb; - - struct rcu_head rcu_head; - struct work_struct work; -}; - -static void inode_switch_wbs_work_fn(struct work_struct *work) -{ - struct inode_switch_wbs_context *isw = - container_of(work, struct inode_switch_wbs_context, work); - struct inode *inode = isw->inode; - struct address_space *mapping = inode->i_mapping; - struct bdi_writeback *old_wb = inode->i_wb; - struct bdi_writeback *new_wb = isw->new_wb; - struct radix_tree_iter iter; - bool switched = false; - void **slot; - - /* - * By the time control reaches here, RCU grace period has passed - * since I_WB_SWITCH assertion and all wb stat update transactions - * between unlocked_inode_to_wb_begin/end() are guaranteed to be - * synchronizing against mapping->tree_lock. - * - * Grabbing old_wb->list_lock, inode->i_lock and mapping->tree_lock - * gives us exclusion against all wb related operations on @inode - * including IO list manipulations and stat updates. - */ - if (old_wb < new_wb) { - spin_lock(&old_wb->list_lock); - spin_lock_nested(&new_wb->list_lock, SINGLE_DEPTH_NESTING); - } else { - spin_lock(&new_wb->list_lock); - spin_lock_nested(&old_wb->list_lock, SINGLE_DEPTH_NESTING); - } - spin_lock(&inode->i_lock); - spin_lock_irq(&mapping->tree_lock); - - /* - * Once I_FREEING is visible under i_lock, the eviction path owns - * the inode and we shouldn't modify ->i_io_list. - */ - if (unlikely(inode->i_state & I_FREEING)) - goto skip_switch; - - /* - * Count and transfer stats. Note that PAGECACHE_TAG_DIRTY points - * to possibly dirty pages while PAGECACHE_TAG_WRITEBACK points to - * pages actually under underwriteback. - */ - radix_tree_for_each_tagged(slot, &mapping->page_tree, &iter, 0, - PAGECACHE_TAG_DIRTY) { - struct page *page = radix_tree_deref_slot_protected(slot, - &mapping->tree_lock); - if (likely(page) && PageDirty(page)) { - __dec_wb_stat(old_wb, WB_RECLAIMABLE); - __inc_wb_stat(new_wb, WB_RECLAIMABLE); - } - } - - radix_tree_for_each_tagged(slot, &mapping->page_tree, &iter, 0, - PAGECACHE_TAG_WRITEBACK) { - struct page *page = radix_tree_deref_slot_protected(slot, - &mapping->tree_lock); - if (likely(page)) { - WARN_ON_ONCE(!PageWriteback(page)); - __dec_wb_stat(old_wb, WB_WRITEBACK); - __inc_wb_stat(new_wb, WB_WRITEBACK); - } - } - - wb_get(new_wb); - - /* - * Transfer to @new_wb's IO list if necessary. The specific list - * @inode was on is ignored and the inode is put on ->b_dirty which - * is always correct including from ->b_dirty_time. The transfer - * preserves @inode->dirtied_when ordering. - */ - if (!list_empty(&inode->i_io_list)) { - struct inode *pos; - - inode_io_list_del_locked(inode, old_wb); - inode->i_wb = new_wb; - list_for_each_entry(pos, &new_wb->b_dirty, i_io_list) - if (time_after_eq(inode->dirtied_when, - pos->dirtied_when)) - break; - inode_io_list_move_locked(inode, new_wb, pos->i_io_list.prev); - } else { - inode->i_wb = new_wb; - } - - /* ->i_wb_frn updates may race wbc_detach_inode() but doesn't matter */ - inode->i_wb_frn_winner = 0; - inode->i_wb_frn_avg_time = 0; - inode->i_wb_frn_history = 0; - switched = true; -skip_switch: - /* - * Paired with load_acquire in unlocked_inode_to_wb_begin() and - * ensures that the new wb is visible if they see !I_WB_SWITCH. - */ - smp_store_release(&inode->i_state, inode->i_state & ~I_WB_SWITCH); - - spin_unlock_irq(&mapping->tree_lock); - spin_unlock(&inode->i_lock); - spin_unlock(&new_wb->list_lock); - spin_unlock(&old_wb->list_lock); - - if (switched) { - wb_wakeup(new_wb); - wb_put(old_wb); - } - wb_put(new_wb); - - iput(inode); - kfree(isw); - - atomic_dec(&isw_nr_in_flight); -} - -static void inode_switch_wbs_rcu_fn(struct rcu_head *rcu_head) -{ - struct inode_switch_wbs_context *isw = container_of(rcu_head, - struct inode_switch_wbs_context, rcu_head); - - /* needs to grab bh-unsafe locks, bounce to work item */ - INIT_WORK(&isw->work, inode_switch_wbs_work_fn); - queue_work(isw_wq, &isw->work); -} - -/** - * inode_switch_wbs - change the wb association of an inode - * @inode: target inode - * @new_wb_id: ID of the new wb - * - * Switch @inode's wb association to the wb identified by @new_wb_id. The - * switching is performed asynchronously and may fail silently. - */ -static void inode_switch_wbs(struct inode *inode, int new_wb_id) -{ - struct backing_dev_info *bdi = inode_to_bdi(inode); - struct cgroup_subsys_state *memcg_css; - struct inode_switch_wbs_context *isw; - - /* noop if seems to be already in progress */ - if (inode->i_state & I_WB_SWITCH) - return; - - isw = kzalloc(sizeof(*isw), GFP_ATOMIC); - if (!isw) - return; - - /* find and pin the new wb */ - rcu_read_lock(); - memcg_css = css_from_id(new_wb_id, &memory_cgrp_subsys); - if (memcg_css) - isw->new_wb = wb_get_create(bdi, memcg_css, GFP_ATOMIC); - rcu_read_unlock(); - if (!isw->new_wb) - goto out_free; - - /* while holding I_WB_SWITCH, no one else can update the association */ - spin_lock(&inode->i_lock); - if (!(inode->i_sb->s_flags & MS_ACTIVE) || - inode->i_state & (I_WB_SWITCH | I_FREEING) || - inode_to_wb(inode) == isw->new_wb) { - spin_unlock(&inode->i_lock); - goto out_free; - } - inode->i_state |= I_WB_SWITCH; - __iget(inode); - spin_unlock(&inode->i_lock); - - isw->inode = inode; - - atomic_inc(&isw_nr_in_flight); - - /* - * In addition to synchronizing among switchers, I_WB_SWITCH tells - * the RCU protected stat update paths to grab the mapping's - * tree_lock so that stat transfer can synchronize against them. - * Let's continue after I_WB_SWITCH is guaranteed to be visible. - */ - call_rcu(&isw->rcu_head, inode_switch_wbs_rcu_fn); - return; - -out_free: - if (isw->new_wb) - wb_put(isw->new_wb); - kfree(isw); -} - -/** - * wbc_attach_and_unlock_inode - associate wbc with target inode and unlock it - * @wbc: writeback_control of interest - * @inode: target inode - * - * @inode is locked and about to be written back under the control of @wbc. - * Record @inode's writeback context into @wbc and unlock the i_lock. On - * writeback completion, wbc_detach_inode() should be called. This is used - * to track the cgroup writeback context. - */ -void wbc_attach_and_unlock_inode(struct writeback_control *wbc, - struct inode *inode) -{ - if (!inode_cgwb_enabled(inode)) { - spin_unlock(&inode->i_lock); - return; - } - - wbc->wb = inode_to_wb(inode); - wbc->inode = inode; - - wbc->wb_id = wbc->wb->memcg_css->id; - wbc->wb_lcand_id = inode->i_wb_frn_winner; - wbc->wb_tcand_id = 0; - wbc->wb_bytes = 0; - wbc->wb_lcand_bytes = 0; - wbc->wb_tcand_bytes = 0; - - wb_get(wbc->wb); - spin_unlock(&inode->i_lock); - - /* - * A dying wb indicates that the memcg-blkcg mapping has changed - * and a new wb is already serving the memcg. Switch immediately. - */ - if (unlikely(wb_dying(wbc->wb))) - inode_switch_wbs(inode, wbc->wb_id); -} - -/** - * wbc_detach_inode - disassociate wbc from inode and perform foreign detection - * @wbc: writeback_control of the just finished writeback - * - * To be called after a writeback attempt of an inode finishes and undoes - * wbc_attach_and_unlock_inode(). Can be called under any context. - * - * As concurrent write sharing of an inode is expected to be very rare and - * memcg only tracks page ownership on first-use basis severely confining - * the usefulness of such sharing, cgroup writeback tracks ownership - * per-inode. While the support for concurrent write sharing of an inode - * is deemed unnecessary, an inode being written to by different cgroups at - * different points in time is a lot more common, and, more importantly, - * charging only by first-use can too readily lead to grossly incorrect - * behaviors (single foreign page can lead to gigabytes of writeback to be - * incorrectly attributed). - * - * To resolve this issue, cgroup writeback detects the majority dirtier of - * an inode and transfers the ownership to it. To avoid unnnecessary - * oscillation, the detection mechanism keeps track of history and gives - * out the switch verdict only if the foreign usage pattern is stable over - * a certain amount of time and/or writeback attempts. - * - * On each writeback attempt, @wbc tries to detect the majority writer - * using Boyer-Moore majority vote algorithm. In addition to the byte - * count from the majority voting, it also counts the bytes written for the - * current wb and the last round's winner wb (max of last round's current - * wb, the winner from two rounds ago, and the last round's majority - * candidate). Keeping track of the historical winner helps the algorithm - * to semi-reliably detect the most active writer even when it's not the - * absolute majority. - * - * Once the winner of the round is determined, whether the winner is - * foreign or not and how much IO time the round consumed is recorded in - * inode->i_wb_frn_history. If the amount of recorded foreign IO time is - * over a certain threshold, the switch verdict is given. - */ -void wbc_detach_inode(struct writeback_control *wbc) -{ - struct bdi_writeback *wb = wbc->wb; - struct inode *inode = wbc->inode; - unsigned long avg_time, max_bytes, max_time; - u16 history; - int max_id; - - if (!wb) - return; - - history = inode->i_wb_frn_history; - avg_time = inode->i_wb_frn_avg_time; - - /* pick the winner of this round */ - if (wbc->wb_bytes >= wbc->wb_lcand_bytes && - wbc->wb_bytes >= wbc->wb_tcand_bytes) { - max_id = wbc->wb_id; - max_bytes = wbc->wb_bytes; - } else if (wbc->wb_lcand_bytes >= wbc->wb_tcand_bytes) { - max_id = wbc->wb_lcand_id; - max_bytes = wbc->wb_lcand_bytes; - } else { - max_id = wbc->wb_tcand_id; - max_bytes = wbc->wb_tcand_bytes; - } - - /* - * Calculate the amount of IO time the winner consumed and fold it - * into the running average kept per inode. If the consumed IO - * time is lower than avag / WB_FRN_TIME_CUT_DIV, ignore it for - * deciding whether to switch or not. This is to prevent one-off - * small dirtiers from skewing the verdict. - */ - max_time = DIV_ROUND_UP((max_bytes >> PAGE_SHIFT) << WB_FRN_TIME_SHIFT, - wb->avg_write_bandwidth); - if (avg_time) - avg_time += (max_time >> WB_FRN_TIME_AVG_SHIFT) - - (avg_time >> WB_FRN_TIME_AVG_SHIFT); - else - avg_time = max_time; /* immediate catch up on first run */ - - if (max_time >= avg_time / WB_FRN_TIME_CUT_DIV) { - int slots; - - /* - * The switch verdict is reached if foreign wb's consume - * more than a certain proportion of IO time in a - * WB_FRN_TIME_PERIOD. This is loosely tracked by 16 slot - * history mask where each bit represents one sixteenth of - * the period. Determine the number of slots to shift into - * history from @max_time. - */ - slots = min(DIV_ROUND_UP(max_time, WB_FRN_HIST_UNIT), - (unsigned long)WB_FRN_HIST_MAX_SLOTS); - history <<= slots; - if (wbc->wb_id != max_id) - history |= (1U << slots) - 1; - - /* - * Switch if the current wb isn't the consistent winner. - * If there are multiple closely competing dirtiers, the - * inode may switch across them repeatedly over time, which - * is okay. The main goal is avoiding keeping an inode on - * the wrong wb for an extended period of time. - */ - if (hweight32(history) > WB_FRN_HIST_THR_SLOTS) - inode_switch_wbs(inode, max_id); - } - - /* - * Multiple instances of this function may race to update the - * following fields but we don't mind occassional inaccuracies. - */ - inode->i_wb_frn_winner = max_id; - inode->i_wb_frn_avg_time = min(avg_time, (unsigned long)U16_MAX); - inode->i_wb_frn_history = history; - - wb_put(wbc->wb); - wbc->wb = NULL; -} - -/** - * wbc_account_io - account IO issued during writeback - * @wbc: writeback_control of the writeback in progress - * @page: page being written out - * @bytes: number of bytes being written out - * - * @bytes from @page are about to written out during the writeback - * controlled by @wbc. Keep the book for foreign inode detection. See - * wbc_detach_inode(). - */ -void wbc_account_io(struct writeback_control *wbc, struct page *page, - size_t bytes) -{ - int id; - - /* - * pageout() path doesn't attach @wbc to the inode being written - * out. This is intentional as we don't want the function to block - * behind a slow cgroup. Ultimately, we want pageout() to kick off - * regular writeback instead of writing things out itself. - */ - if (!wbc->wb) - return; - - id = mem_cgroup_css_from_page(page)->id; - - if (id == wbc->wb_id) { - wbc->wb_bytes += bytes; - return; - } - - if (id == wbc->wb_lcand_id) - wbc->wb_lcand_bytes += bytes; - - /* Boyer-Moore majority vote algorithm */ - if (!wbc->wb_tcand_bytes) - wbc->wb_tcand_id = id; - if (id == wbc->wb_tcand_id) - wbc->wb_tcand_bytes += bytes; - else - wbc->wb_tcand_bytes -= min(bytes, wbc->wb_tcand_bytes); -} -EXPORT_SYMBOL_GPL(wbc_account_io); - -/** - * inode_congested - test whether an inode is congested - * @inode: inode to test for congestion (may be NULL) - * @cong_bits: mask of WB_[a]sync_congested bits to test - * - * Tests whether @inode is congested. @cong_bits is the mask of congestion - * bits to test and the return value is the mask of set bits. - * - * If cgroup writeback is enabled for @inode, the congestion state is - * determined by whether the cgwb (cgroup bdi_writeback) for the blkcg - * associated with @inode is congested; otherwise, the root wb's congestion - * state is used. - * - * @inode is allowed to be NULL as this function is often called on - * mapping->host which is NULL for the swapper space. - */ -int inode_congested(struct inode *inode, int cong_bits) -{ - /* - * Once set, ->i_wb never becomes NULL while the inode is alive. - * Start transaction iff ->i_wb is visible. - */ - if (inode && inode_to_wb_is_valid(inode)) { - struct bdi_writeback *wb; - bool locked, congested; - - wb = unlocked_inode_to_wb_begin(inode, &locked); - congested = wb_congested(wb, cong_bits); - unlocked_inode_to_wb_end(inode, locked); - return congested; - } - - return wb_congested(&inode_to_bdi(inode)->wb, cong_bits); -} -EXPORT_SYMBOL_GPL(inode_congested); - -/** - * wb_split_bdi_pages - split nr_pages to write according to bandwidth - * @wb: target bdi_writeback to split @nr_pages to - * @nr_pages: number of pages to write for the whole bdi - * - * Split @wb's portion of @nr_pages according to @wb's write bandwidth in - * relation to the total write bandwidth of all wb's w/ dirty inodes on - * @wb->bdi. - */ -static long wb_split_bdi_pages(struct bdi_writeback *wb, long nr_pages) -{ - unsigned long this_bw = wb->avg_write_bandwidth; - unsigned long tot_bw = atomic_long_read(&wb->bdi->tot_write_bandwidth); - - if (nr_pages == LONG_MAX) - return LONG_MAX; - - /* - * This may be called on clean wb's and proportional distribution - * may not make sense, just use the original @nr_pages in those - * cases. In general, we wanna err on the side of writing more. - */ - if (!tot_bw || this_bw >= tot_bw) - return nr_pages; - else - return DIV_ROUND_UP_ULL((u64)nr_pages * this_bw, tot_bw); -} - -/** - * bdi_split_work_to_wbs - split a wb_writeback_work to all wb's of a bdi - * @bdi: target backing_dev_info - * @base_work: wb_writeback_work to issue - * @skip_if_busy: skip wb's which already have writeback in progress - * - * Split and issue @base_work to all wb's (bdi_writeback's) of @bdi which - * have dirty inodes. If @base_work->nr_page isn't %LONG_MAX, it's - * distributed to the busy wbs according to each wb's proportion in the - * total active write bandwidth of @bdi. - */ -static void bdi_split_work_to_wbs(struct backing_dev_info *bdi, - struct wb_writeback_work *base_work, - bool skip_if_busy) -{ - struct bdi_writeback *last_wb = NULL; - struct bdi_writeback *wb = list_entry(&bdi->wb_list, - struct bdi_writeback, bdi_node); - - might_sleep(); -restart: - rcu_read_lock(); - list_for_each_entry_continue_rcu(wb, &bdi->wb_list, bdi_node) { - DEFINE_WB_COMPLETION_ONSTACK(fallback_work_done); - struct wb_writeback_work fallback_work; - struct wb_writeback_work *work; - long nr_pages; - - if (last_wb) { - wb_put(last_wb); - last_wb = NULL; - } - - /* SYNC_ALL writes out I_DIRTY_TIME too */ - if (!wb_has_dirty_io(wb) && - (base_work->sync_mode == WB_SYNC_NONE || - list_empty(&wb->b_dirty_time))) - continue; - if (skip_if_busy && writeback_in_progress(wb)) - continue; - - nr_pages = wb_split_bdi_pages(wb, base_work->nr_pages); - - work = kmalloc(sizeof(*work), GFP_ATOMIC); - if (work) { - *work = *base_work; - work->nr_pages = nr_pages; - work->auto_free = 1; - wb_queue_work(wb, work); - continue; - } - - /* alloc failed, execute synchronously using on-stack fallback */ - work = &fallback_work; - *work = *base_work; - work->nr_pages = nr_pages; - work->auto_free = 0; - work->done = &fallback_work_done; - - wb_queue_work(wb, work); - - /* - * Pin @wb so that it stays on @bdi->wb_list. This allows - * continuing iteration from @wb after dropping and - * regrabbing rcu read lock. - */ - wb_get(wb); - last_wb = wb; - - rcu_read_unlock(); - wb_wait_for_completion(bdi, &fallback_work_done); - goto restart; - } - rcu_read_unlock(); - - if (last_wb) - wb_put(last_wb); -} - -/** - * cgroup_writeback_umount - flush inode wb switches for umount - * - * This function is called when a super_block is about to be destroyed and - * flushes in-flight inode wb switches. An inode wb switch goes through - * RCU and then workqueue, so the two need to be flushed in order to ensure - * that all previously scheduled switches are finished. As wb switches are - * rare occurrences and synchronize_rcu() can take a while, perform - * flushing iff wb switches are in flight. - */ -void cgroup_writeback_umount(void) -{ - if (atomic_read(&isw_nr_in_flight)) { - synchronize_rcu(); - flush_workqueue(isw_wq); - } -} - -static int __init cgroup_writeback_init(void) -{ - isw_wq = alloc_workqueue("inode_switch_wbs", 0, 0); - if (!isw_wq) - return -ENOMEM; - return 0; -} -fs_initcall(cgroup_writeback_init); - -#else /* CONFIG_CGROUP_WRITEBACK */ - -static struct bdi_writeback * -locked_inode_to_wb_and_lock_list(struct inode *inode) - __releases(&inode->i_lock) - __acquires(&wb->list_lock) -{ - struct bdi_writeback *wb = inode_to_wb(inode); - - spin_unlock(&inode->i_lock); - spin_lock(&wb->list_lock); - return wb; -} - -static struct bdi_writeback *inode_to_wb_and_lock_list(struct inode *inode) - __acquires(&wb->list_lock) -{ - struct bdi_writeback *wb = inode_to_wb(inode); - - spin_lock(&wb->list_lock); - return wb; -} - -static long wb_split_bdi_pages(struct bdi_writeback *wb, long nr_pages) -{ - return nr_pages; -} - -static void bdi_split_work_to_wbs(struct backing_dev_info *bdi, - struct wb_writeback_work *base_work, - bool skip_if_busy) -{ - might_sleep(); - - if (!skip_if_busy || !writeback_in_progress(&bdi->wb)) { - base_work->auto_free = 0; - wb_queue_work(&bdi->wb, base_work); - } -} - -#endif /* CONFIG_CGROUP_WRITEBACK */ - -void wb_start_writeback(struct bdi_writeback *wb, long nr_pages, - bool range_cyclic, enum wb_reason reason) -{ - struct wb_writeback_work *work; - - if (!wb_has_dirty_io(wb)) - return; - - /* - * This is WB_SYNC_NONE writeback, so if allocation fails just - * wakeup the thread for old dirty data writeback - */ - work = kzalloc(sizeof(*work), - GFP_NOWAIT | __GFP_NOMEMALLOC | __GFP_NOWARN); - if (!work) { - trace_writeback_nowork(wb); - wb_wakeup(wb); - return; - } - - work->sync_mode = WB_SYNC_NONE; - work->nr_pages = nr_pages; - work->range_cyclic = range_cyclic; - work->reason = reason; - work->auto_free = 1; - - wb_queue_work(wb, work); -} - -/** - * wb_start_background_writeback - start background writeback - * @wb: bdi_writback to write from - * - * Description: - * This makes sure WB_SYNC_NONE background writeback happens. When - * this function returns, it is only guaranteed that for given wb - * some IO is happening if we are over background dirty threshold. - * Caller need not hold sb s_umount semaphore. - */ -void wb_start_background_writeback(struct bdi_writeback *wb) -{ - /* - * We just wake up the flusher thread. It will perform background - * writeback as soon as there is no other work to do. - */ - trace_writeback_wake_background(wb); - wb_wakeup(wb); -} - -/* - * Remove the inode from the writeback list it is on. - */ -void inode_io_list_del(struct inode *inode) -{ - struct bdi_writeback *wb; - - wb = inode_to_wb_and_lock_list(inode); - inode_io_list_del_locked(inode, wb); - spin_unlock(&wb->list_lock); -} - -/* - * mark an inode as under writeback on the sb - */ -void sb_mark_inode_writeback(struct inode *inode) -{ - struct super_block *sb = inode->i_sb; - unsigned long flags; - - if (list_empty(&inode->i_wb_list)) { - spin_lock_irqsave(&sb->s_inode_wblist_lock, flags); - if (list_empty(&inode->i_wb_list)) { - list_add_tail(&inode->i_wb_list, &sb->s_inodes_wb); - trace_sb_mark_inode_writeback(inode); - } - spin_unlock_irqrestore(&sb->s_inode_wblist_lock, flags); - } -} - -/* - * clear an inode as under writeback on the sb - */ -void sb_clear_inode_writeback(struct inode *inode) -{ - struct super_block *sb = inode->i_sb; - unsigned long flags; - - if (!list_empty(&inode->i_wb_list)) { - spin_lock_irqsave(&sb->s_inode_wblist_lock, flags); - if (!list_empty(&inode->i_wb_list)) { - list_del_init(&inode->i_wb_list); - trace_sb_clear_inode_writeback(inode); - } - spin_unlock_irqrestore(&sb->s_inode_wblist_lock, flags); - } -} - -/* - * Redirty an inode: set its when-it-was dirtied timestamp and move it to the - * furthest end of its superblock's dirty-inode list. - * - * Before stamping the inode's ->dirtied_when, we check to see whether it is - * already the most-recently-dirtied inode on the b_dirty list. If that is - * the case then the inode must have been redirtied while it was being written - * out and we don't reset its dirtied_when. - */ -static void redirty_tail(struct inode *inode, struct bdi_writeback *wb) -{ - if (!list_empty(&wb->b_dirty)) { - struct inode *tail; - - tail = wb_inode(wb->b_dirty.next); - if (time_before(inode->dirtied_when, tail->dirtied_when)) - inode->dirtied_when = jiffies; - } - inode_io_list_move_locked(inode, wb, &wb->b_dirty); -} - -/* - * requeue inode for re-scanning after bdi->b_io list is exhausted. - */ -static void requeue_io(struct inode *inode, struct bdi_writeback *wb) -{ - inode_io_list_move_locked(inode, wb, &wb->b_more_io); -} - -static void inode_sync_complete(struct inode *inode) -{ - inode->i_state &= ~I_SYNC; - /* If inode is clean an unused, put it into LRU now... */ - inode_add_lru(inode); - /* Waiters must see I_SYNC cleared before being woken up */ - smp_mb(); - wake_up_bit(&inode->i_state, __I_SYNC); -} - -static bool inode_dirtied_after(struct inode *inode, unsigned long t) -{ - bool ret = time_after(inode->dirtied_when, t); -#ifndef CONFIG_64BIT - /* - * For inodes being constantly redirtied, dirtied_when can get stuck. - * It _appears_ to be in the future, but is actually in distant past. - * This test is necessary to prevent such wrapped-around relative times - * from permanently stopping the whole bdi writeback. - */ - ret = ret && time_before_eq(inode->dirtied_when, jiffies); -#endif - return ret; -} - -#define EXPIRE_DIRTY_ATIME 0x0001 - -/* - * Move expired (dirtied before work->older_than_this) dirty inodes from - * @delaying_queue to @dispatch_queue. - */ -static int move_expired_inodes(struct list_head *delaying_queue, - struct list_head *dispatch_queue, - int flags, - struct wb_writeback_work *work) -{ - unsigned long *older_than_this = NULL; - unsigned long expire_time; - LIST_HEAD(tmp); - struct list_head *pos, *node; - struct super_block *sb = NULL; - struct inode *inode; - int do_sb_sort = 0; - int moved = 0; - - if ((flags & EXPIRE_DIRTY_ATIME) == 0) - older_than_this = work->older_than_this; - else if (!work->for_sync) { - expire_time = jiffies - (dirtytime_expire_interval * HZ); - older_than_this = &expire_time; - } - while (!list_empty(delaying_queue)) { - inode = wb_inode(delaying_queue->prev); - if (older_than_this && - inode_dirtied_after(inode, *older_than_this)) - break; - list_move(&inode->i_io_list, &tmp); - moved++; - if (flags & EXPIRE_DIRTY_ATIME) - set_bit(__I_DIRTY_TIME_EXPIRED, &inode->i_state); - if (sb_is_blkdev_sb(inode->i_sb)) - continue; - if (sb && sb != inode->i_sb) - do_sb_sort = 1; - sb = inode->i_sb; - } - - /* just one sb in list, splice to dispatch_queue and we're done */ - if (!do_sb_sort) { - list_splice(&tmp, dispatch_queue); - goto out; - } - - /* Move inodes from one superblock together */ - while (!list_empty(&tmp)) { - sb = wb_inode(tmp.prev)->i_sb; - list_for_each_prev_safe(pos, node, &tmp) { - inode = wb_inode(pos); - if (inode->i_sb == sb) - list_move(&inode->i_io_list, dispatch_queue); - } - } -out: - return moved; -} - -/* - * Queue all expired dirty inodes for io, eldest first. - * Before - * newly dirtied b_dirty b_io b_more_io - * =============> gf edc BA - * After - * newly dirtied b_dirty b_io b_more_io - * =============> g fBAedc - * | - * +--> dequeue for IO - */ -static void queue_io(struct bdi_writeback *wb, struct wb_writeback_work *work) -{ - int moved; - - assert_spin_locked(&wb->list_lock); - list_splice_init(&wb->b_more_io, &wb->b_io); - moved = move_expired_inodes(&wb->b_dirty, &wb->b_io, 0, work); - moved += move_expired_inodes(&wb->b_dirty_time, &wb->b_io, - EXPIRE_DIRTY_ATIME, work); - if (moved) - wb_io_lists_populated(wb); - trace_writeback_queue_io(wb, work, moved); -} - -static int write_inode(struct inode *inode, struct writeback_control *wbc) -{ - int ret; - - if (inode->i_sb->s_op->write_inode && !is_bad_inode(inode)) { - trace_writeback_write_inode_start(inode, wbc); - ret = inode->i_sb->s_op->write_inode(inode, wbc); - trace_writeback_write_inode(inode, wbc); - return ret; - } - return 0; -} - -/* - * Wait for writeback on an inode to complete. Called with i_lock held. - * Caller must make sure inode cannot go away when we drop i_lock. - */ -static void __inode_wait_for_writeback(struct inode *inode) - __releases(inode->i_lock) - __acquires(inode->i_lock) -{ - DEFINE_WAIT_BIT(wq, &inode->i_state, __I_SYNC); - wait_queue_head_t *wqh; - - wqh = bit_waitqueue(&inode->i_state, __I_SYNC); - while (inode->i_state & I_SYNC) { - spin_unlock(&inode->i_lock); - __wait_on_bit(wqh, &wq, bit_wait, - TASK_UNINTERRUPTIBLE); - spin_lock(&inode->i_lock); - } -} - -/* - * Wait for writeback on an inode to complete. Caller must have inode pinned. - */ -void inode_wait_for_writeback(struct inode *inode) -{ - spin_lock(&inode->i_lock); - __inode_wait_for_writeback(inode); - spin_unlock(&inode->i_lock); -} - -/* - * Sleep until I_SYNC is cleared. This function must be called with i_lock - * held and drops it. It is aimed for callers not holding any inode reference - * so once i_lock is dropped, inode can go away. - */ -static void inode_sleep_on_writeback(struct inode *inode) - __releases(inode->i_lock) -{ - DEFINE_WAIT(wait); - wait_queue_head_t *wqh = bit_waitqueue(&inode->i_state, __I_SYNC); - int sleep; - - prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE); - sleep = inode->i_state & I_SYNC; - spin_unlock(&inode->i_lock); - if (sleep) - schedule(); - finish_wait(wqh, &wait); -} - -/* - * Find proper writeback list for the inode depending on its current state and - * possibly also change of its state while we were doing writeback. Here we - * handle things such as livelock prevention or fairness of writeback among - * inodes. This function can be called only by flusher thread - noone else - * processes all inodes in writeback lists and requeueing inodes behind flusher - * thread's back can have unexpected consequences. - */ -static void requeue_inode(struct inode *inode, struct bdi_writeback *wb, - struct writeback_control *wbc) -{ - if (inode->i_state & I_FREEING) - return; - - /* - * Sync livelock prevention. Each inode is tagged and synced in one - * shot. If still dirty, it will be redirty_tail()'ed below. Update - * the dirty time to prevent enqueue and sync it again. - */ - if ((inode->i_state & I_DIRTY) && - (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages)) - inode->dirtied_when = jiffies; - - if (wbc->pages_skipped) { - /* - * writeback is not making progress due to locked - * buffers. Skip this inode for now. - */ - redirty_tail(inode, wb); - return; - } - - if (mapping_tagged(inode->i_mapping, PAGECACHE_TAG_DIRTY)) { - /* - * We didn't write back all the pages. nfs_writepages() - * sometimes bales out without doing anything. - */ - if (wbc->nr_to_write <= 0) { - /* Slice used up. Queue for next turn. */ - requeue_io(inode, wb); - } else { - /* - * Writeback blocked by something other than - * congestion. Delay the inode for some time to - * avoid spinning on the CPU (100% iowait) - * retrying writeback of the dirty page/inode - * that cannot be performed immediately. - */ - redirty_tail(inode, wb); - } - } else if (inode->i_state & I_DIRTY) { - /* - * Filesystems can dirty the inode during writeback operations, - * such as delayed allocation during submission or metadata - * updates after data IO completion. - */ - redirty_tail(inode, wb); - } else if (inode->i_state & I_DIRTY_TIME) { - inode->dirtied_when = jiffies; - inode_io_list_move_locked(inode, wb, &wb->b_dirty_time); - } else { - /* The inode is clean. Remove from writeback lists. */ - inode_io_list_del_locked(inode, wb); - } -} - -/* - * Write out an inode and its dirty pages. Do not update the writeback list - * linkage. That is left to the caller. The caller is also responsible for - * setting I_SYNC flag and calling inode_sync_complete() to clear it. - */ -static int -__writeback_single_inode(struct inode *inode, struct writeback_control *wbc) -{ - struct address_space *mapping = inode->i_mapping; - long nr_to_write = wbc->nr_to_write; - unsigned dirty; - int ret; - - WARN_ON(!(inode->i_state & I_SYNC)); - - trace_writeback_single_inode_start(inode, wbc, nr_to_write); - - ret = do_writepages(mapping, wbc); - - /* - * Make sure to wait on the data before writing out the metadata. - * This is important for filesystems that modify metadata on data - * I/O completion. We don't do it for sync(2) writeback because it has a - * separate, external IO completion path and ->sync_fs for guaranteeing - * inode metadata is written back correctly. - */ - if (wbc->sync_mode == WB_SYNC_ALL && !wbc->for_sync) { - int err = filemap_fdatawait(mapping); - if (ret == 0) - ret = err; - } - - /* - * Some filesystems may redirty the inode during the writeback - * due to delalloc, clear dirty metadata flags right before - * write_inode() - */ - spin_lock(&inode->i_lock); - - dirty = inode->i_state & I_DIRTY; - if (inode->i_state & I_DIRTY_TIME) { - if ((dirty & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) || - wbc->sync_mode == WB_SYNC_ALL || - unlikely(inode->i_state & I_DIRTY_TIME_EXPIRED) || - unlikely(time_after(jiffies, - (inode->dirtied_time_when + - dirtytime_expire_interval * HZ)))) { - dirty |= I_DIRTY_TIME | I_DIRTY_TIME_EXPIRED; - trace_writeback_lazytime(inode); - } - } else - inode->i_state &= ~I_DIRTY_TIME_EXPIRED; - inode->i_state &= ~dirty; - - /* - * Paired with smp_mb() in __mark_inode_dirty(). This allows - * __mark_inode_dirty() to test i_state without grabbing i_lock - - * either they see the I_DIRTY bits cleared or we see the dirtied - * inode. - * - * I_DIRTY_PAGES is always cleared together above even if @mapping - * still has dirty pages. The flag is reinstated after smp_mb() if - * necessary. This guarantees that either __mark_inode_dirty() - * sees clear I_DIRTY_PAGES or we see PAGECACHE_TAG_DIRTY. - */ - smp_mb(); - - if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) - inode->i_state |= I_DIRTY_PAGES; - - spin_unlock(&inode->i_lock); - - if (dirty & I_DIRTY_TIME) - mark_inode_dirty_sync(inode); - /* Don't write the inode if only I_DIRTY_PAGES was set */ - if (dirty & ~I_DIRTY_PAGES) { - int err = write_inode(inode, wbc); - if (ret == 0) - ret = err; - } - trace_writeback_single_inode(inode, wbc, nr_to_write); - return ret; -} - -/* - * Write out an inode's dirty pages. Either the caller has an active reference - * on the inode or the inode has I_WILL_FREE set. - * - * This function is designed to be called for writing back one inode which - * we go e.g. from filesystem. Flusher thread uses __writeback_single_inode() - * and does more profound writeback list handling in writeback_sb_inodes(). - */ -static int writeback_single_inode(struct inode *inode, - struct writeback_control *wbc) -{ - struct bdi_writeback *wb; - int ret = 0; - - spin_lock(&inode->i_lock); - if (!atomic_read(&inode->i_count)) - WARN_ON(!(inode->i_state & (I_WILL_FREE|I_FREEING))); - else - WARN_ON(inode->i_state & I_WILL_FREE); - - if (inode->i_state & I_SYNC) { - if (wbc->sync_mode != WB_SYNC_ALL) - goto out; - /* - * It's a data-integrity sync. We must wait. Since callers hold - * inode reference or inode has I_WILL_FREE set, it cannot go - * away under us. - */ - __inode_wait_for_writeback(inode); - } - WARN_ON(inode->i_state & I_SYNC); - /* - * Skip inode if it is clean and we have no outstanding writeback in - * WB_SYNC_ALL mode. We don't want to mess with writeback lists in this - * function since flusher thread may be doing for example sync in - * parallel and if we move the inode, it could get skipped. So here we - * make sure inode is on some writeback list and leave it there unless - * we have completely cleaned the inode. - */ - if (!(inode->i_state & I_DIRTY_ALL) && - (wbc->sync_mode != WB_SYNC_ALL || - !mapping_tagged(inode->i_mapping, PAGECACHE_TAG_WRITEBACK))) - goto out; - inode->i_state |= I_SYNC; - wbc_attach_and_unlock_inode(wbc, inode); - - ret = __writeback_single_inode(inode, wbc); - - wbc_detach_inode(wbc); - - wb = inode_to_wb_and_lock_list(inode); - spin_lock(&inode->i_lock); - /* - * If inode is clean, remove it from writeback lists. Otherwise don't - * touch it. See comment above for explanation. - */ - if (!(inode->i_state & I_DIRTY_ALL)) - inode_io_list_del_locked(inode, wb); - spin_unlock(&wb->list_lock); - inode_sync_complete(inode); -out: - spin_unlock(&inode->i_lock); - return ret; -} - -static long writeback_chunk_size(struct bdi_writeback *wb, - struct wb_writeback_work *work) -{ - long pages; - - /* - * WB_SYNC_ALL mode does livelock avoidance by syncing dirty - * inodes/pages in one big loop. Setting wbc.nr_to_write=LONG_MAX - * here avoids calling into writeback_inodes_wb() more than once. - * - * The intended call sequence for WB_SYNC_ALL writeback is: - * - * wb_writeback() - * writeback_sb_inodes() <== called only once - * write_cache_pages() <== called once for each inode - * (quickly) tag currently dirty pages - * (maybe slowly) sync all tagged pages - */ - if (work->sync_mode == WB_SYNC_ALL || work->tagged_writepages) - pages = LONG_MAX; - else { - pages = min(wb->avg_write_bandwidth / 2, - global_wb_domain.dirty_limit / DIRTY_SCOPE); - pages = min(pages, work->nr_pages); - pages = round_down(pages + MIN_WRITEBACK_PAGES, - MIN_WRITEBACK_PAGES); - } - - return pages; -} - -/* - * Write a portion of b_io inodes which belong to @sb. - * - * Return the number of pages and/or inodes written. - * - * NOTE! This is called with wb->list_lock held, and will - * unlock and relock that for each inode it ends up doing - * IO for. - */ -static long writeback_sb_inodes(struct super_block *sb, - struct bdi_writeback *wb, - struct wb_writeback_work *work) -{ - struct writeback_control wbc = { - .sync_mode = work->sync_mode, - .tagged_writepages = work->tagged_writepages, - .for_kupdate = work->for_kupdate, - .for_background = work->for_background, - .for_sync = work->for_sync, - .range_cyclic = work->range_cyclic, - .range_start = 0, - .range_end = LLONG_MAX, - }; - unsigned long start_time = jiffies; - long write_chunk; - long wrote = 0; /* count both pages and inodes */ - - while (!list_empty(&wb->b_io)) { - struct inode *inode = wb_inode(wb->b_io.prev); - struct bdi_writeback *tmp_wb; - - if (inode->i_sb != sb) { - if (work->sb) { - /* - * We only want to write back data for this - * superblock, move all inodes not belonging - * to it back onto the dirty list. - */ - redirty_tail(inode, wb); - continue; - } - - /* - * The inode belongs to a different superblock. - * Bounce back to the caller to unpin this and - * pin the next superblock. - */ - break; - } - - /* - * Don't bother with new inodes or inodes being freed, first - * kind does not need periodic writeout yet, and for the latter - * kind writeout is handled by the freer. - */ - spin_lock(&inode->i_lock); - if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) { - spin_unlock(&inode->i_lock); - redirty_tail(inode, wb); - continue; - } - if ((inode->i_state & I_SYNC) && wbc.sync_mode != WB_SYNC_ALL) { - /* - * If this inode is locked for writeback and we are not - * doing writeback-for-data-integrity, move it to - * b_more_io so that writeback can proceed with the - * other inodes on s_io. - * - * We'll have another go at writing back this inode - * when we completed a full scan of b_io. - */ - spin_unlock(&inode->i_lock); - requeue_io(inode, wb); - trace_writeback_sb_inodes_requeue(inode); - continue; - } - spin_unlock(&wb->list_lock); - - /* - * We already requeued the inode if it had I_SYNC set and we - * are doing WB_SYNC_NONE writeback. So this catches only the - * WB_SYNC_ALL case. - */ - if (inode->i_state & I_SYNC) { - /* Wait for I_SYNC. This function drops i_lock... */ - inode_sleep_on_writeback(inode); - /* Inode may be gone, start again */ - spin_lock(&wb->list_lock); - continue; - } - inode->i_state |= I_SYNC; - wbc_attach_and_unlock_inode(&wbc, inode); - - write_chunk = writeback_chunk_size(wb, work); - wbc.nr_to_write = write_chunk; - wbc.pages_skipped = 0; - - /* - * We use I_SYNC to pin the inode in memory. While it is set - * evict_inode() will wait so the inode cannot be freed. - */ - __writeback_single_inode(inode, &wbc); - - wbc_detach_inode(&wbc); - work->nr_pages -= write_chunk - wbc.nr_to_write; - wrote += write_chunk - wbc.nr_to_write; - - if (need_resched()) { - /* - * We're trying to balance between building up a nice - * long list of IOs to improve our merge rate, and - * getting those IOs out quickly for anyone throttling - * in balance_dirty_pages(). cond_resched() doesn't - * unplug, so get our IOs out the door before we - * give up the CPU. - */ - blk_flush_plug(current); - cond_resched(); - } - - /* - * Requeue @inode if still dirty. Be careful as @inode may - * have been switched to another wb in the meantime. - */ - tmp_wb = inode_to_wb_and_lock_list(inode); - spin_lock(&inode->i_lock); - if (!(inode->i_state & I_DIRTY_ALL)) - wrote++; - requeue_inode(inode, tmp_wb, &wbc); - inode_sync_complete(inode); - spin_unlock(&inode->i_lock); - - if (unlikely(tmp_wb != wb)) { - spin_unlock(&tmp_wb->list_lock); - spin_lock(&wb->list_lock); - } - - /* - * bail out to wb_writeback() often enough to check - * background threshold and other termination conditions. - */ - if (wrote) { - if (time_is_before_jiffies(start_time + HZ / 10UL)) - break; - if (work->nr_pages <= 0) - break; - } - } - return wrote; -} - -static long __writeback_inodes_wb(struct bdi_writeback *wb, - struct wb_writeback_work *work) -{ - unsigned long start_time = jiffies; - long wrote = 0; - - while (!list_empty(&wb->b_io)) { - struct inode *inode = wb_inode(wb->b_io.prev); - struct super_block *sb = inode->i_sb; - - if (!trylock_super(sb)) { - /* - * trylock_super() may fail consistently due to - * s_umount being grabbed by someone else. Don't use - * requeue_io() to avoid busy retrying the inode/sb. - */ - redirty_tail(inode, wb); - continue; - } - wrote += writeback_sb_inodes(sb, wb, work); - up_read(&sb->s_umount); - - /* refer to the same tests at the end of writeback_sb_inodes */ - if (wrote) { - if (time_is_before_jiffies(start_time + HZ / 10UL)) - break; - if (work->nr_pages <= 0) - break; - } - } - /* Leave any unwritten inodes on b_io */ - return wrote; -} - -static long writeback_inodes_wb(struct bdi_writeback *wb, long nr_pages, - enum wb_reason reason) -{ - struct wb_writeback_work work = { - .nr_pages = nr_pages, - .sync_mode = WB_SYNC_NONE, - .range_cyclic = 1, - .reason = reason, - }; - struct blk_plug plug; - - blk_start_plug(&plug); - spin_lock(&wb->list_lock); - if (list_empty(&wb->b_io)) - queue_io(wb, &work); - __writeback_inodes_wb(wb, &work); - spin_unlock(&wb->list_lock); - blk_finish_plug(&plug); - - return nr_pages - work.nr_pages; -} - -/* - * Explicit flushing or periodic writeback of "old" data. - * - * Define "old": the first time one of an inode's pages is dirtied, we mark the - * dirtying-time in the inode's address_space. So this periodic writeback code - * just walks the superblock inode list, writing back any inodes which are - * older than a specific point in time. - * - * Try to run once per dirty_writeback_interval. But if a writeback event - * takes longer than a dirty_writeback_interval interval, then leave a - * one-second gap. - * - * older_than_this takes precedence over nr_to_write. So we'll only write back - * all dirty pages if they are all attached to "old" mappings. - */ -static long wb_writeback(struct bdi_writeback *wb, - struct wb_writeback_work *work) -{ - unsigned long wb_start = jiffies; - long nr_pages = work->nr_pages; - unsigned long oldest_jif; - struct inode *inode; - long progress; - struct blk_plug plug; - - oldest_jif = jiffies; - work->older_than_this = &oldest_jif; - - blk_start_plug(&plug); - spin_lock(&wb->list_lock); - for (;;) { - /* - * Stop writeback when nr_pages has been consumed - */ - if (work->nr_pages <= 0) - break; - - /* - * Background writeout and kupdate-style writeback may - * run forever. Stop them if there is other work to do - * so that e.g. sync can proceed. They'll be restarted - * after the other works are all done. - */ - if ((work->for_background || work->for_kupdate) && - !list_empty(&wb->work_list)) - break; - - /* - * For background writeout, stop when we are below the - * background dirty threshold - */ - if (work->for_background && !wb_over_bg_thresh(wb)) - break; - - /* - * Kupdate and background works are special and we want to - * include all inodes that need writing. Livelock avoidance is - * handled by these works yielding to any other work so we are - * safe. - */ - if (work->for_kupdate) { - oldest_jif = jiffies - - msecs_to_jiffies(dirty_expire_interval * 10); - } else if (work->for_background) - oldest_jif = jiffies; - - trace_writeback_start(wb, work); - if (list_empty(&wb->b_io)) - queue_io(wb, work); - if (work->sb) - progress = writeback_sb_inodes(work->sb, wb, work); - else - progress = __writeback_inodes_wb(wb, work); - trace_writeback_written(wb, work); - - wb_update_bandwidth(wb, wb_start); - - /* - * Did we write something? Try for more - * - * Dirty inodes are moved to b_io for writeback in batches. - * The completion of the current batch does not necessarily - * mean the overall work is done. So we keep looping as long - * as made some progress on cleaning pages or inodes. - */ - if (progress) - continue; - /* - * No more inodes for IO, bail - */ - if (list_empty(&wb->b_more_io)) - break; - /* - * Nothing written. Wait for some inode to - * become available for writeback. Otherwise - * we'll just busyloop. - */ - if (!list_empty(&wb->b_more_io)) { - trace_writeback_wait(wb, work); - inode = wb_inode(wb->b_more_io.prev); - spin_lock(&inode->i_lock); - spin_unlock(&wb->list_lock); - /* This function drops i_lock... */ - inode_sleep_on_writeback(inode); - spin_lock(&wb->list_lock); - } - } - spin_unlock(&wb->list_lock); - blk_finish_plug(&plug); - - return nr_pages - work->nr_pages; -} - -/* - * Return the next wb_writeback_work struct that hasn't been processed yet. - */ -static struct wb_writeback_work *get_next_work_item(struct bdi_writeback *wb) -{ - struct wb_writeback_work *work = NULL; - - spin_lock_bh(&wb->work_lock); - if (!list_empty(&wb->work_list)) { - work = list_entry(wb->work_list.next, - struct wb_writeback_work, list); - list_del_init(&work->list); - } - spin_unlock_bh(&wb->work_lock); - return work; -} - -/* - * Add in the number of potentially dirty inodes, because each inode - * write can dirty pagecache in the underlying blockdev. - */ -static unsigned long get_nr_dirty_pages(void) -{ - return global_node_page_state(NR_FILE_DIRTY) + - global_node_page_state(NR_UNSTABLE_NFS) + - get_nr_dirty_inodes(); -} - -static long wb_check_background_flush(struct bdi_writeback *wb) -{ - if (wb_over_bg_thresh(wb)) { - - struct wb_writeback_work work = { - .nr_pages = LONG_MAX, - .sync_mode = WB_SYNC_NONE, - .for_background = 1, - .range_cyclic = 1, - .reason = WB_REASON_BACKGROUND, - }; - - return wb_writeback(wb, &work); - } - - return 0; -} - -static long wb_check_old_data_flush(struct bdi_writeback *wb) -{ - unsigned long expired; - long nr_pages; - - /* - * When set to zero, disable periodic writeback - */ - if (!dirty_writeback_interval) - return 0; - - expired = wb->last_old_flush + - msecs_to_jiffies(dirty_writeback_interval * 10); - if (time_before(jiffies, expired)) - return 0; - - wb->last_old_flush = jiffies; - nr_pages = get_nr_dirty_pages(); - - if (nr_pages) { - struct wb_writeback_work work = { - .nr_pages = nr_pages, - .sync_mode = WB_SYNC_NONE, - .for_kupdate = 1, - .range_cyclic = 1, - .reason = WB_REASON_PERIODIC, - }; - - return wb_writeback(wb, &work); - } - - return 0; -} - -/* - * Retrieve work items and do the writeback they describe - */ -static long wb_do_writeback(struct bdi_writeback *wb) -{ - struct wb_writeback_work *work; - long wrote = 0; - - set_bit(WB_writeback_running, &wb->state); - while ((work = get_next_work_item(wb)) != NULL) { - struct wb_completion *done = work->done; - - trace_writeback_exec(wb, work); - - wrote += wb_writeback(wb, work); - - if (work->auto_free) - kfree(work); - if (done && atomic_dec_and_test(&done->cnt)) - wake_up_all(&wb->bdi->wb_waitq); - } - - /* - * Check for periodic writeback, kupdated() style - */ - wrote += wb_check_old_data_flush(wb); - wrote += wb_check_background_flush(wb); - clear_bit(WB_writeback_running, &wb->state); - - return wrote; -} - -/* - * Handle writeback of dirty data for the device backed by this bdi. Also - * reschedules periodically and does kupdated style flushing. - */ -void wb_workfn(struct work_struct *work) -{ - struct bdi_writeback *wb = container_of(to_delayed_work(work), - struct bdi_writeback, dwork); - long pages_written; - - set_worker_desc("flush-%s", dev_name(wb->bdi->dev)); - current->flags |= PF_SWAPWRITE; - - if (likely(!current_is_workqueue_rescuer() || - !test_bit(WB_registered, &wb->state))) { - /* - * The normal path. Keep writing back @wb until its - * work_list is empty. Note that this path is also taken - * if @wb is shutting down even when we're running off the - * rescuer as work_list needs to be drained. - */ - do { - pages_written = wb_do_writeback(wb); - trace_writeback_pages_written(pages_written); - } while (!list_empty(&wb->work_list)); - } else { - /* - * bdi_wq can't get enough workers and we're running off - * the emergency worker. Don't hog it. Hopefully, 1024 is - * enough for efficient IO. - */ - pages_written = writeback_inodes_wb(wb, 1024, - WB_REASON_FORKER_THREAD); - trace_writeback_pages_written(pages_written); - } - - if (!list_empty(&wb->work_list)) - mod_delayed_work(bdi_wq, &wb->dwork, 0); - else if (wb_has_dirty_io(wb) && dirty_writeback_interval) - wb_wakeup_delayed(wb); - - current->flags &= ~PF_SWAPWRITE; -} - -/* - * Start writeback of `nr_pages' pages. If `nr_pages' is zero, write back - * the whole world. - */ -void wakeup_flusher_threads(long nr_pages, enum wb_reason reason) -{ - struct backing_dev_info *bdi; - - /* - * If we are expecting writeback progress we must submit plugged IO. - */ - if (blk_needs_flush_plug(current)) - blk_schedule_flush_plug(current); - - if (!nr_pages) - nr_pages = get_nr_dirty_pages(); - - rcu_read_lock(); - list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) { - struct bdi_writeback *wb; - - if (!bdi_has_dirty_io(bdi)) - continue; - - list_for_each_entry_rcu(wb, &bdi->wb_list, bdi_node) - wb_start_writeback(wb, wb_split_bdi_pages(wb, nr_pages), - false, reason); - } - rcu_read_unlock(); -} - -/* - * Wake up bdi's periodically to make sure dirtytime inodes gets - * written back periodically. We deliberately do *not* check the - * b_dirtytime list in wb_has_dirty_io(), since this would cause the - * kernel to be constantly waking up once there are any dirtytime - * inodes on the system. So instead we define a separate delayed work - * function which gets called much more rarely. (By default, only - * once every 12 hours.) - * - * If there is any other write activity going on in the file system, - * this function won't be necessary. But if the only thing that has - * happened on the file system is a dirtytime inode caused by an atime - * update, we need this infrastructure below to make sure that inode - * eventually gets pushed out to disk. - */ -static void wakeup_dirtytime_writeback(struct work_struct *w); -static DECLARE_DELAYED_WORK(dirtytime_work, wakeup_dirtytime_writeback); - -static void wakeup_dirtytime_writeback(struct work_struct *w) -{ - struct backing_dev_info *bdi; - - rcu_read_lock(); - list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) { - struct bdi_writeback *wb; - - list_for_each_entry_rcu(wb, &bdi->wb_list, bdi_node) - if (!list_empty(&wb->b_dirty_time)) - wb_wakeup(wb); - } - rcu_read_unlock(); - schedule_delayed_work(&dirtytime_work, dirtytime_expire_interval * HZ); -} - -static int __init start_dirtytime_writeback(void) -{ - schedule_delayed_work(&dirtytime_work, dirtytime_expire_interval * HZ); - return 0; -} -__initcall(start_dirtytime_writeback); - -int dirtytime_interval_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - int ret; - - ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); - if (ret == 0 && write) - mod_delayed_work(system_wq, &dirtytime_work, 0); - return ret; -} - -static noinline void block_dump___mark_inode_dirty(struct inode *inode) -{ - if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev")) { - struct dentry *dentry; - const char *name = "?"; - - dentry = d_find_alias(inode); - if (dentry) { - spin_lock(&dentry->d_lock); - name = (const char *) dentry->d_name.name; - } - printk(KERN_DEBUG - "%s(%d): dirtied inode %lu (%s) on %s\n", - current->comm, task_pid_nr(current), inode->i_ino, - name, inode->i_sb->s_id); - if (dentry) { - spin_unlock(&dentry->d_lock); - dput(dentry); - } - } -} - -/** - * __mark_inode_dirty - internal function - * @inode: inode to mark - * @flags: what kind of dirty (i.e. I_DIRTY_SYNC) - * Mark an inode as dirty. Callers should use mark_inode_dirty or - * mark_inode_dirty_sync. - * - * Put the inode on the super block's dirty list. - * - * CAREFUL! We mark it dirty unconditionally, but move it onto the - * dirty list only if it is hashed or if it refers to a blockdev. - * If it was not hashed, it will never be added to the dirty list - * even if it is later hashed, as it will have been marked dirty already. - * - * In short, make sure you hash any inodes _before_ you start marking - * them dirty. - * - * Note that for blockdevs, inode->dirtied_when represents the dirtying time of - * the block-special inode (/dev/hda1) itself. And the ->dirtied_when field of - * the kernel-internal blockdev inode represents the dirtying time of the - * blockdev's pages. This is why for I_DIRTY_PAGES we always use - * page->mapping->host, so the page-dirtying time is recorded in the internal - * blockdev inode. - */ -void __mark_inode_dirty(struct inode *inode, int flags) -{ -#define I_DIRTY_INODE (I_DIRTY_SYNC | I_DIRTY_DATASYNC) - struct super_block *sb = inode->i_sb; - int dirtytime; - - trace_writeback_mark_inode_dirty(inode, flags); - - /* - * Don't do this for I_DIRTY_PAGES - that doesn't actually - * dirty the inode itself - */ - if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_TIME)) { - trace_writeback_dirty_inode_start(inode, flags); - - if (sb->s_op->dirty_inode) - sb->s_op->dirty_inode(inode, flags); - - trace_writeback_dirty_inode(inode, flags); - } - if (flags & I_DIRTY_INODE) - flags &= ~I_DIRTY_TIME; - dirtytime = flags & I_DIRTY_TIME; - - /* - * Paired with smp_mb() in __writeback_single_inode() for the - * following lockless i_state test. See there for details. - */ - smp_mb(); - - if (((inode->i_state & flags) == flags) || - (dirtytime && (inode->i_state & I_DIRTY_INODE))) - return; - - if (unlikely(block_dump)) - block_dump___mark_inode_dirty(inode); - - spin_lock(&inode->i_lock); - if (dirtytime && (inode->i_state & I_DIRTY_INODE)) - goto out_unlock_inode; - if ((inode->i_state & flags) != flags) { - const int was_dirty = inode->i_state & I_DIRTY; - - inode_attach_wb(inode, NULL); - - if (flags & I_DIRTY_INODE) - inode->i_state &= ~I_DIRTY_TIME; - inode->i_state |= flags; - - /* - * If the inode is being synced, just update its dirty state. - * The unlocker will place the inode on the appropriate - * superblock list, based upon its state. - */ - if (inode->i_state & I_SYNC) - goto out_unlock_inode; - - /* - * Only add valid (hashed) inodes to the superblock's - * dirty list. Add blockdev inodes as well. - */ - if (!S_ISBLK(inode->i_mode)) { - if (inode_unhashed(inode)) - goto out_unlock_inode; - } - if (inode->i_state & I_FREEING) - goto out_unlock_inode; - - /* - * If the inode was already on b_dirty/b_io/b_more_io, don't - * reposition it (that would break b_dirty time-ordering). - */ - if (!was_dirty) { - struct bdi_writeback *wb; - struct list_head *dirty_list; - bool wakeup_bdi = false; - - wb = locked_inode_to_wb_and_lock_list(inode); - - WARN(bdi_cap_writeback_dirty(wb->bdi) && - !test_bit(WB_registered, &wb->state), - "bdi-%s not registered\n", wb->bdi->name); - - inode->dirtied_when = jiffies; - if (dirtytime) - inode->dirtied_time_when = jiffies; - - if (inode->i_state & (I_DIRTY_INODE | I_DIRTY_PAGES)) - dirty_list = &wb->b_dirty; - else - dirty_list = &wb->b_dirty_time; - - wakeup_bdi = inode_io_list_move_locked(inode, wb, - dirty_list); - - spin_unlock(&wb->list_lock); - trace_writeback_dirty_inode_enqueue(inode); - - /* - * If this is the first dirty inode for this bdi, - * we have to wake-up the corresponding bdi thread - * to make sure background write-back happens - * later. - */ - if (bdi_cap_writeback_dirty(wb->bdi) && wakeup_bdi) - wb_wakeup_delayed(wb); - return; - } - } -out_unlock_inode: - spin_unlock(&inode->i_lock); - -#undef I_DIRTY_INODE -} -EXPORT_SYMBOL(__mark_inode_dirty); - -/* - * The @s_sync_lock is used to serialise concurrent sync operations - * to avoid lock contention problems with concurrent wait_sb_inodes() calls. - * Concurrent callers will block on the s_sync_lock rather than doing contending - * walks. The queueing maintains sync(2) required behaviour as all the IO that - * has been issued up to the time this function is enter is guaranteed to be - * completed by the time we have gained the lock and waited for all IO that is - * in progress regardless of the order callers are granted the lock. - */ -static void wait_sb_inodes(struct super_block *sb) -{ - LIST_HEAD(sync_list); - - /* - * We need to be protected against the filesystem going from - * r/o to r/w or vice versa. - */ - WARN_ON(!rwsem_is_locked(&sb->s_umount)); - - mutex_lock(&sb->s_sync_lock); - - /* - * Splice the writeback list onto a temporary list to avoid waiting on - * inodes that have started writeback after this point. - * - * Use rcu_read_lock() to keep the inodes around until we have a - * reference. s_inode_wblist_lock protects sb->s_inodes_wb as well as - * the local list because inodes can be dropped from either by writeback - * completion. - */ - rcu_read_lock(); - spin_lock_irq(&sb->s_inode_wblist_lock); - list_splice_init(&sb->s_inodes_wb, &sync_list); - - /* - * Data integrity sync. Must wait for all pages under writeback, because - * there may have been pages dirtied before our sync call, but which had - * writeout started before we write it out. In which case, the inode - * may not be on the dirty list, but we still have to wait for that - * writeout. - */ - while (!list_empty(&sync_list)) { - struct inode *inode = list_first_entry(&sync_list, struct inode, - i_wb_list); - struct address_space *mapping = inode->i_mapping; - - /* - * Move each inode back to the wb list before we drop the lock - * to preserve consistency between i_wb_list and the mapping - * writeback tag. Writeback completion is responsible to remove - * the inode from either list once the writeback tag is cleared. - */ - list_move_tail(&inode->i_wb_list, &sb->s_inodes_wb); - - /* - * The mapping can appear untagged while still on-list since we - * do not have the mapping lock. Skip it here, wb completion - * will remove it. - */ - if (!mapping_tagged(mapping, PAGECACHE_TAG_WRITEBACK)) - continue; - - spin_unlock_irq(&sb->s_inode_wblist_lock); - - spin_lock(&inode->i_lock); - if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) { - spin_unlock(&inode->i_lock); - - spin_lock_irq(&sb->s_inode_wblist_lock); - continue; - } - __iget(inode); - spin_unlock(&inode->i_lock); - rcu_read_unlock(); - - /* - * We keep the error status of individual mapping so that - * applications can catch the writeback error using fsync(2). - * See filemap_fdatawait_keep_errors() for details. - */ - filemap_fdatawait_keep_errors(mapping); - - cond_resched(); - - iput(inode); - - rcu_read_lock(); - spin_lock_irq(&sb->s_inode_wblist_lock); - } - spin_unlock_irq(&sb->s_inode_wblist_lock); - rcu_read_unlock(); - mutex_unlock(&sb->s_sync_lock); -} - -static void __writeback_inodes_sb_nr(struct super_block *sb, unsigned long nr, - enum wb_reason reason, bool skip_if_busy) -{ - DEFINE_WB_COMPLETION_ONSTACK(done); - struct wb_writeback_work work = { - .sb = sb, - .sync_mode = WB_SYNC_NONE, - .tagged_writepages = 1, - .done = &done, - .nr_pages = nr, - .reason = reason, - }; - struct backing_dev_info *bdi = sb->s_bdi; - - if (!bdi_has_dirty_io(bdi) || bdi == &noop_backing_dev_info) - return; - WARN_ON(!rwsem_is_locked(&sb->s_umount)); - - bdi_split_work_to_wbs(sb->s_bdi, &work, skip_if_busy); - wb_wait_for_completion(bdi, &done); -} - -/** - * writeback_inodes_sb_nr - writeback dirty inodes from given super_block - * @sb: the superblock - * @nr: the number of pages to write - * @reason: reason why some writeback work initiated - * - * Start writeback on some inodes on this super_block. No guarantees are made - * on how many (if any) will be written, and this function does not wait - * for IO completion of submitted IO. - */ -void writeback_inodes_sb_nr(struct super_block *sb, - unsigned long nr, - enum wb_reason reason) -{ - __writeback_inodes_sb_nr(sb, nr, reason, false); -} -EXPORT_SYMBOL(writeback_inodes_sb_nr); - -/** - * writeback_inodes_sb - writeback dirty inodes from given super_block - * @sb: the superblock - * @reason: reason why some writeback work was initiated - * - * Start writeback on some inodes on this super_block. No guarantees are made - * on how many (if any) will be written, and this function does not wait - * for IO completion of submitted IO. - */ -void writeback_inodes_sb(struct super_block *sb, enum wb_reason reason) -{ - return writeback_inodes_sb_nr(sb, get_nr_dirty_pages(), reason); -} -EXPORT_SYMBOL(writeback_inodes_sb); - -/** - * try_to_writeback_inodes_sb_nr - try to start writeback if none underway - * @sb: the superblock - * @nr: the number of pages to write - * @reason: the reason of writeback - * - * Invoke writeback_inodes_sb_nr if no writeback is currently underway. - * Returns 1 if writeback was started, 0 if not. - */ -bool try_to_writeback_inodes_sb_nr(struct super_block *sb, unsigned long nr, - enum wb_reason reason) -{ - if (!down_read_trylock(&sb->s_umount)) - return false; - - __writeback_inodes_sb_nr(sb, nr, reason, true); - up_read(&sb->s_umount); - return true; -} -EXPORT_SYMBOL(try_to_writeback_inodes_sb_nr); - -/** - * try_to_writeback_inodes_sb - try to start writeback if none underway - * @sb: the superblock - * @reason: reason why some writeback work was initiated - * - * Implement by try_to_writeback_inodes_sb_nr() - * Returns 1 if writeback was started, 0 if not. - */ -bool try_to_writeback_inodes_sb(struct super_block *sb, enum wb_reason reason) -{ - return try_to_writeback_inodes_sb_nr(sb, get_nr_dirty_pages(), reason); -} -EXPORT_SYMBOL(try_to_writeback_inodes_sb); - -/** - * sync_inodes_sb - sync sb inode pages - * @sb: the superblock - * - * This function writes and waits on any dirty inode belonging to this - * super_block. - */ -void sync_inodes_sb(struct super_block *sb) -{ - DEFINE_WB_COMPLETION_ONSTACK(done); - struct wb_writeback_work work = { - .sb = sb, - .sync_mode = WB_SYNC_ALL, - .nr_pages = LONG_MAX, - .range_cyclic = 0, - .done = &done, - .reason = WB_REASON_SYNC, - .for_sync = 1, - }; - struct backing_dev_info *bdi = sb->s_bdi; - - /* - * Can't skip on !bdi_has_dirty() because we should wait for !dirty - * inodes under writeback and I_DIRTY_TIME inodes ignored by - * bdi_has_dirty() need to be written out too. - */ - if (bdi == &noop_backing_dev_info) - return; - WARN_ON(!rwsem_is_locked(&sb->s_umount)); - - bdi_split_work_to_wbs(bdi, &work, false); - wb_wait_for_completion(bdi, &done); - - wait_sb_inodes(sb); -} -EXPORT_SYMBOL(sync_inodes_sb); - -/** - * write_inode_now - write an inode to disk - * @inode: inode to write to disk - * @sync: whether the write should be synchronous or not - * - * This function commits an inode to disk immediately if it is dirty. This is - * primarily needed by knfsd. - * - * The caller must either have a ref on the inode or must have set I_WILL_FREE. - */ -int write_inode_now(struct inode *inode, int sync) -{ - struct writeback_control wbc = { - .nr_to_write = LONG_MAX, - .sync_mode = sync ? WB_SYNC_ALL : WB_SYNC_NONE, - .range_start = 0, - .range_end = LLONG_MAX, - }; - - if (!mapping_cap_writeback_dirty(inode->i_mapping)) - wbc.nr_to_write = 0; - - might_sleep(); - return writeback_single_inode(inode, &wbc); -} -EXPORT_SYMBOL(write_inode_now); - -/** - * sync_inode - write an inode and its pages to disk. - * @inode: the inode to sync - * @wbc: controls the writeback mode - * - * sync_inode() will write an inode and its pages to disk. It will also - * correctly update the inode on its superblock's dirty inode lists and will - * update inode->i_state. - * - * The caller must have a ref on the inode. - */ -int sync_inode(struct inode *inode, struct writeback_control *wbc) -{ - return writeback_single_inode(inode, wbc); -} -EXPORT_SYMBOL(sync_inode); - -/** - * sync_inode_metadata - write an inode to disk - * @inode: the inode to sync - * @wait: wait for I/O to complete. - * - * Write an inode to disk and adjust its dirty state after completion. - * - * Note: only writes the actual inode, no associated data or other metadata. - */ -int sync_inode_metadata(struct inode *inode, int wait) -{ - struct writeback_control wbc = { - .sync_mode = wait ? WB_SYNC_ALL : WB_SYNC_NONE, - .nr_to_write = 0, /* metadata-only */ - }; - - return sync_inode(inode, &wbc); -} -EXPORT_SYMBOL(sync_inode_metadata); diff --git a/src/linux/fs/fs_pin.c b/src/linux/fs/fs_pin.c deleted file mode 100644 index 611b540..0000000 --- a/src/linux/fs/fs_pin.c +++ /dev/null @@ -1,102 +0,0 @@ -#include -#include -#include -#include "internal.h" -#include "mount.h" - -static DEFINE_SPINLOCK(pin_lock); - -void pin_remove(struct fs_pin *pin) -{ - spin_lock(&pin_lock); - hlist_del_init(&pin->m_list); - hlist_del_init(&pin->s_list); - spin_unlock(&pin_lock); - spin_lock_irq(&pin->wait.lock); - pin->done = 1; - wake_up_locked(&pin->wait); - spin_unlock_irq(&pin->wait.lock); -} - -void pin_insert_group(struct fs_pin *pin, struct vfsmount *m, struct hlist_head *p) -{ - spin_lock(&pin_lock); - if (p) - hlist_add_head(&pin->s_list, p); - hlist_add_head(&pin->m_list, &real_mount(m)->mnt_pins); - spin_unlock(&pin_lock); -} - -void pin_insert(struct fs_pin *pin, struct vfsmount *m) -{ - pin_insert_group(pin, m, &m->mnt_sb->s_pins); -} - -void pin_kill(struct fs_pin *p) -{ - wait_queue_t wait; - - if (!p) { - rcu_read_unlock(); - return; - } - init_wait(&wait); - spin_lock_irq(&p->wait.lock); - if (likely(!p->done)) { - p->done = -1; - spin_unlock_irq(&p->wait.lock); - rcu_read_unlock(); - p->kill(p); - return; - } - if (p->done > 0) { - spin_unlock_irq(&p->wait.lock); - rcu_read_unlock(); - return; - } - __add_wait_queue(&p->wait, &wait); - while (1) { - set_current_state(TASK_UNINTERRUPTIBLE); - spin_unlock_irq(&p->wait.lock); - rcu_read_unlock(); - schedule(); - rcu_read_lock(); - if (likely(list_empty(&wait.task_list))) - break; - /* OK, we know p couldn't have been freed yet */ - spin_lock_irq(&p->wait.lock); - if (p->done > 0) { - spin_unlock_irq(&p->wait.lock); - break; - } - } - rcu_read_unlock(); -} - -void mnt_pin_kill(struct mount *m) -{ - while (1) { - struct hlist_node *p; - rcu_read_lock(); - p = ACCESS_ONCE(m->mnt_pins.first); - if (!p) { - rcu_read_unlock(); - break; - } - pin_kill(hlist_entry(p, struct fs_pin, m_list)); - } -} - -void group_pin_kill(struct hlist_head *p) -{ - while (1) { - struct hlist_node *q; - rcu_read_lock(); - q = ACCESS_ONCE(p->first); - if (!q) { - rcu_read_unlock(); - break; - } - pin_kill(hlist_entry(q, struct fs_pin, s_list)); - } -} diff --git a/src/linux/fs/fs_struct.c b/src/linux/fs/fs_struct.c deleted file mode 100644 index 7dca743..0000000 --- a/src/linux/fs/fs_struct.c +++ /dev/null @@ -1,166 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "internal.h" - -/* - * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values. - * It can block. - */ -void set_fs_root(struct fs_struct *fs, const struct path *path) -{ - struct path old_root; - - path_get(path); - spin_lock(&fs->lock); - write_seqcount_begin(&fs->seq); - old_root = fs->root; - fs->root = *path; - write_seqcount_end(&fs->seq); - spin_unlock(&fs->lock); - if (old_root.dentry) - path_put(&old_root); -} - -/* - * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values. - * It can block. - */ -void set_fs_pwd(struct fs_struct *fs, const struct path *path) -{ - struct path old_pwd; - - path_get(path); - spin_lock(&fs->lock); - write_seqcount_begin(&fs->seq); - old_pwd = fs->pwd; - fs->pwd = *path; - write_seqcount_end(&fs->seq); - spin_unlock(&fs->lock); - - if (old_pwd.dentry) - path_put(&old_pwd); -} - -static inline int replace_path(struct path *p, const struct path *old, const struct path *new) -{ - if (likely(p->dentry != old->dentry || p->mnt != old->mnt)) - return 0; - *p = *new; - return 1; -} - -void chroot_fs_refs(const struct path *old_root, const struct path *new_root) -{ - struct task_struct *g, *p; - struct fs_struct *fs; - int count = 0; - - read_lock(&tasklist_lock); - do_each_thread(g, p) { - task_lock(p); - fs = p->fs; - if (fs) { - int hits = 0; - spin_lock(&fs->lock); - write_seqcount_begin(&fs->seq); - hits += replace_path(&fs->root, old_root, new_root); - hits += replace_path(&fs->pwd, old_root, new_root); - write_seqcount_end(&fs->seq); - while (hits--) { - count++; - path_get(new_root); - } - spin_unlock(&fs->lock); - } - task_unlock(p); - } while_each_thread(g, p); - read_unlock(&tasklist_lock); - while (count--) - path_put(old_root); -} - -void free_fs_struct(struct fs_struct *fs) -{ - path_put(&fs->root); - path_put(&fs->pwd); - kmem_cache_free(fs_cachep, fs); -} - -void exit_fs(struct task_struct *tsk) -{ - struct fs_struct *fs = tsk->fs; - - if (fs) { - int kill; - task_lock(tsk); - spin_lock(&fs->lock); - tsk->fs = NULL; - kill = !--fs->users; - spin_unlock(&fs->lock); - task_unlock(tsk); - if (kill) - free_fs_struct(fs); - } -} - -struct fs_struct *copy_fs_struct(struct fs_struct *old) -{ - struct fs_struct *fs = kmem_cache_alloc(fs_cachep, GFP_KERNEL); - /* We don't need to lock fs - think why ;-) */ - if (fs) { - fs->users = 1; - fs->in_exec = 0; - spin_lock_init(&fs->lock); - seqcount_init(&fs->seq); - fs->umask = old->umask; - - spin_lock(&old->lock); - fs->root = old->root; - path_get(&fs->root); - fs->pwd = old->pwd; - path_get(&fs->pwd); - spin_unlock(&old->lock); - } - return fs; -} - -int unshare_fs_struct(void) -{ - struct fs_struct *fs = current->fs; - struct fs_struct *new_fs = copy_fs_struct(fs); - int kill; - - if (!new_fs) - return -ENOMEM; - - task_lock(current); - spin_lock(&fs->lock); - kill = !--fs->users; - current->fs = new_fs; - spin_unlock(&fs->lock); - task_unlock(current); - - if (kill) - free_fs_struct(fs); - - return 0; -} -EXPORT_SYMBOL_GPL(unshare_fs_struct); - -int current_umask(void) -{ - return current->fs->umask; -} -EXPORT_SYMBOL(current_umask); - -/* to be mentioned only in INIT_TASK */ -struct fs_struct init_fs = { - .users = 1, - .lock = __SPIN_LOCK_UNLOCKED(init_fs.lock), - .seq = SEQCNT_ZERO(init_fs.seq), - .umask = 0022, -}; diff --git a/src/linux/fs/fscache/Kconfig b/src/linux/fs/fscache/Kconfig deleted file mode 100644 index 3f6dfa9..0000000 --- a/src/linux/fs/fscache/Kconfig +++ /dev/null @@ -1,61 +0,0 @@ - -config FSCACHE - tristate "General filesystem local caching manager" - help - This option enables a generic filesystem caching manager that can be - used by various network and other filesystems to cache data locally. - Different sorts of caches can be plugged in, depending on the - resources available. - - See Documentation/filesystems/caching/fscache.txt for more information. - -config FSCACHE_STATS - bool "Gather statistical information on local caching" - depends on FSCACHE && PROC_FS - help - This option causes statistical information to be gathered on local - caching and exported through file: - - /proc/fs/fscache/stats - - The gathering of statistics adds a certain amount of overhead to - execution as there are a quite a few stats gathered, and on a - multi-CPU system these may be on cachelines that keep bouncing - between CPUs. On the other hand, the stats are very useful for - debugging purposes. Saying 'Y' here is recommended. - - See Documentation/filesystems/caching/fscache.txt for more information. - -config FSCACHE_HISTOGRAM - bool "Gather latency information on local caching" - depends on FSCACHE && PROC_FS - help - This option causes latency information to be gathered on local - caching and exported through file: - - /proc/fs/fscache/histogram - - The generation of this histogram adds a certain amount of overhead to - execution as there are a number of points at which data is gathered, - and on a multi-CPU system these may be on cachelines that keep - bouncing between CPUs. On the other hand, the histogram may be - useful for debugging purposes. Saying 'N' here is recommended. - - See Documentation/filesystems/caching/fscache.txt for more information. - -config FSCACHE_DEBUG - bool "Debug FS-Cache" - depends on FSCACHE - help - This permits debugging to be dynamically enabled in the local caching - management module. If this is set, the debugging output may be - enabled by setting bits in /sys/modules/fscache/parameter/debug. - - See Documentation/filesystems/caching/fscache.txt for more information. - -config FSCACHE_OBJECT_LIST - bool "Maintain global object list for debugging purposes" - depends on FSCACHE && PROC_FS - help - Maintain a global list of active fscache objects that can be - retrieved through /proc/fs/fscache/objects for debugging purposes diff --git a/src/linux/fs/fuse/Kconfig b/src/linux/fs/fuse/Kconfig deleted file mode 100644 index 76f09ce..0000000 --- a/src/linux/fs/fuse/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -config FUSE_FS - tristate "FUSE (Filesystem in Userspace) support" - select FS_POSIX_ACL - help - With FUSE it is possible to implement a fully functional filesystem - in a userspace program. - - There's also a companion library: libfuse2. This library is available - from the FUSE homepage: - - although chances are your distribution already has that library - installed if you've installed the "fuse" package itself. - - See for more information. - See for needed library/utility version. - - If you want to develop a userspace FS, or if you want to use - a filesystem based on FUSE, answer Y or M. - -config CUSE - tristate "Character device in Userspace support" - depends on FUSE_FS - help - This FUSE extension allows character devices to be - implemented in userspace. - - If you want to develop or use a userspace character device - based on CUSE, answer Y or M. diff --git a/src/linux/fs/gfs2/Kconfig b/src/linux/fs/gfs2/Kconfig deleted file mode 100644 index 90c6a8f..0000000 --- a/src/linux/fs/gfs2/Kconfig +++ /dev/null @@ -1,34 +0,0 @@ -config GFS2_FS - tristate "GFS2 file system support" - depends on (64BIT || LBDAF) - select FS_POSIX_ACL - select CRC32 - select QUOTACTL - help - A cluster filesystem. - - Allows a cluster of computers to simultaneously use a block device - that is shared between them (with FC, iSCSI, NBD, etc...). GFS reads - and writes to the block device like a local filesystem, but also uses - a lock module to allow the computers coordinate their I/O so - filesystem consistency is maintained. One of the nifty features of - GFS is perfect consistency -- changes made to the filesystem on one - machine show up immediately on all other machines in the cluster. - - To use the GFS2 filesystem in a cluster, you will need to enable - the locking module below. Documentation and utilities for GFS2 can - be found here: http://sources.redhat.com/cluster - - The "nolock" lock module is now built in to GFS2 by default. If - you want to use the DLM, be sure to enable IPv4/6 networking. - -config GFS2_FS_LOCKING_DLM - bool "GFS2 DLM locking" - depends on (GFS2_FS!=n) && NET && INET && (IPV6 || IPV6=n) && \ - CONFIGFS_FS && SYSFS && (DLM=y || DLM=GFS2_FS) - help - Multiple node locking module for GFS2 - - Most users of GFS2 will require this. It provides the locking - interface between GFS2 and the DLM, which is required to use GFS2 - in a cluster environment. diff --git a/src/linux/fs/hfs/Kconfig b/src/linux/fs/hfs/Kconfig deleted file mode 100644 index 998e3a6..0000000 --- a/src/linux/fs/hfs/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config HFS_FS - tristate "Apple Macintosh file system support" - depends on BLOCK - select NLS - help - If you say Y here, you will be able to mount Macintosh-formatted - floppy disks and hard drive partitions with full read-write access. - Please read to learn about - the available mount options. - - To compile this file system support as a module, choose M here: the - module will be called hfs. diff --git a/src/linux/fs/hfsplus/Kconfig b/src/linux/fs/hfsplus/Kconfig deleted file mode 100644 index 24bc20f..0000000 --- a/src/linux/fs/hfsplus/Kconfig +++ /dev/null @@ -1,31 +0,0 @@ -config HFSPLUS_FS - tristate "Apple Extended HFS file system support" - depends on BLOCK - select NLS - select NLS_UTF8 - help - If you say Y here, you will be able to mount extended format - Macintosh-formatted hard drive partitions with full read-write access. - - This file system is often called HFS+ and was introduced with - MacOS 8. It includes all Mac specific filesystem data such as - data forks and creator codes, but it also has several UNIX - style features such as file ownership and permissions. - -config HFSPLUS_FS_POSIX_ACL - bool "HFS+ POSIX Access Control Lists" - depends on HFSPLUS_FS - select FS_POSIX_ACL - help - POSIX Access Control Lists (ACLs) support permissions for users and - groups beyond the owner/group/world scheme. - - To learn more about Access Control Lists, visit the POSIX ACLs for - Linux website . - - It needs to understand that POSIX ACLs are treated only under - Linux. POSIX ACLs doesn't mean something under Mac OS X. - Mac OS X beginning with version 10.4 ("Tiger") support NFSv4 ACLs, - which are part of the NFSv4 standard. - - If you don't know what Access Control Lists are, say N diff --git a/src/linux/fs/hpfs/Kconfig b/src/linux/fs/hpfs/Kconfig deleted file mode 100644 index 56bd15c..0000000 --- a/src/linux/fs/hpfs/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config HPFS_FS - tristate "OS/2 HPFS file system support" - depends on BLOCK - help - OS/2 is IBM's operating system for PC's, the same as Warp, and HPFS - is the file system used for organizing files on OS/2 hard disk - partitions. Say Y if you want to be able to read files from and - write files to an OS/2 HPFS partition on your hard drive. OS/2 - floppies however are in regular MSDOS format, so you don't need this - option in order to be able to read them. Read - . - - To compile this file system support as a module, choose M here: the - module will be called hpfs. If unsure, say N. diff --git a/src/linux/fs/inode.c b/src/linux/fs/inode.c deleted file mode 100644 index 88110fd..0000000 --- a/src/linux/fs/inode.c +++ /dev/null @@ -1,2124 +0,0 @@ -/* - * (C) 1997 Linus Torvalds - * (C) 1999 Andrea Arcangeli (dynamic inode allocation) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for inode_has_buffers */ -#include -#include -#include -#include "internal.h" - -/* - * Inode locking rules: - * - * inode->i_lock protects: - * inode->i_state, inode->i_hash, __iget() - * Inode LRU list locks protect: - * inode->i_sb->s_inode_lru, inode->i_lru - * inode->i_sb->s_inode_list_lock protects: - * inode->i_sb->s_inodes, inode->i_sb_list - * bdi->wb.list_lock protects: - * bdi->wb.b_{dirty,io,more_io,dirty_time}, inode->i_io_list - * inode_hash_lock protects: - * inode_hashtable, inode->i_hash - * - * Lock ordering: - * - * inode->i_sb->s_inode_list_lock - * inode->i_lock - * Inode LRU list locks - * - * bdi->wb.list_lock - * inode->i_lock - * - * inode_hash_lock - * inode->i_sb->s_inode_list_lock - * inode->i_lock - * - * iunique_lock - * inode_hash_lock - */ - -static unsigned int i_hash_mask __read_mostly; -static unsigned int i_hash_shift __read_mostly; -static struct hlist_head *inode_hashtable __read_mostly; -static __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_hash_lock); - -/* - * Empty aops. Can be used for the cases where the user does not - * define any of the address_space operations. - */ -const struct address_space_operations empty_aops = { -}; -EXPORT_SYMBOL(empty_aops); - -/* - * Statistics gathering.. - */ -struct inodes_stat_t inodes_stat; - -static DEFINE_PER_CPU(unsigned long, nr_inodes); -static DEFINE_PER_CPU(unsigned long, nr_unused); - -static struct kmem_cache *inode_cachep __read_mostly; - -static long get_nr_inodes(void) -{ - int i; - long sum = 0; - for_each_possible_cpu(i) - sum += per_cpu(nr_inodes, i); - return sum < 0 ? 0 : sum; -} - -static inline long get_nr_inodes_unused(void) -{ - int i; - long sum = 0; - for_each_possible_cpu(i) - sum += per_cpu(nr_unused, i); - return sum < 0 ? 0 : sum; -} - -long get_nr_dirty_inodes(void) -{ - /* not actually dirty inodes, but a wild approximation */ - long nr_dirty = get_nr_inodes() - get_nr_inodes_unused(); - return nr_dirty > 0 ? nr_dirty : 0; -} - -/* - * Handle nr_inode sysctl - */ -#ifdef CONFIG_SYSCTL -int proc_nr_inodes(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - inodes_stat.nr_inodes = get_nr_inodes(); - inodes_stat.nr_unused = get_nr_inodes_unused(); - return proc_doulongvec_minmax(table, write, buffer, lenp, ppos); -} -#endif - -static int no_open(struct inode *inode, struct file *file) -{ - return -ENXIO; -} - -/** - * inode_init_always - perform inode structure intialisation - * @sb: superblock inode belongs to - * @inode: inode to initialise - * - * These are initializations that need to be done on every inode - * allocation as the fields are not initialised by slab allocation. - */ -int inode_init_always(struct super_block *sb, struct inode *inode) -{ - static const struct inode_operations empty_iops; - static const struct file_operations no_open_fops = {.open = no_open}; - struct address_space *const mapping = &inode->i_data; - - inode->i_sb = sb; - inode->i_blkbits = sb->s_blocksize_bits; - inode->i_flags = 0; - atomic_set(&inode->i_count, 1); - inode->i_op = &empty_iops; - inode->i_fop = &no_open_fops; - inode->__i_nlink = 1; - inode->i_opflags = 0; - if (sb->s_xattr) - inode->i_opflags |= IOP_XATTR; - i_uid_write(inode, 0); - i_gid_write(inode, 0); - atomic_set(&inode->i_writecount, 0); - inode->i_size = 0; - inode->i_blocks = 0; - inode->i_bytes = 0; - inode->i_generation = 0; - inode->i_pipe = NULL; - inode->i_bdev = NULL; - inode->i_cdev = NULL; - inode->i_link = NULL; - inode->i_dir_seq = 0; - inode->i_rdev = 0; - inode->dirtied_when = 0; - -#ifdef CONFIG_CGROUP_WRITEBACK - inode->i_wb_frn_winner = 0; - inode->i_wb_frn_avg_time = 0; - inode->i_wb_frn_history = 0; -#endif - - if (security_inode_alloc(inode)) - goto out; - spin_lock_init(&inode->i_lock); - lockdep_set_class(&inode->i_lock, &sb->s_type->i_lock_key); - - init_rwsem(&inode->i_rwsem); - lockdep_set_class(&inode->i_rwsem, &sb->s_type->i_mutex_key); - - atomic_set(&inode->i_dio_count, 0); - - mapping->a_ops = &empty_aops; - mapping->host = inode; - mapping->flags = 0; - atomic_set(&mapping->i_mmap_writable, 0); - mapping_set_gfp_mask(mapping, GFP_HIGHUSER_MOVABLE); - mapping->private_data = NULL; - mapping->writeback_index = 0; - inode->i_private = NULL; - inode->i_mapping = mapping; - INIT_HLIST_HEAD(&inode->i_dentry); /* buggered by rcu freeing */ -#ifdef CONFIG_FS_POSIX_ACL - inode->i_acl = inode->i_default_acl = ACL_NOT_CACHED; -#endif - -#ifdef CONFIG_FSNOTIFY - inode->i_fsnotify_mask = 0; -#endif - inode->i_flctx = NULL; - this_cpu_inc(nr_inodes); - - return 0; -out: - return -ENOMEM; -} -EXPORT_SYMBOL(inode_init_always); - -static struct inode *alloc_inode(struct super_block *sb) -{ - struct inode *inode; - - if (sb->s_op->alloc_inode) - inode = sb->s_op->alloc_inode(sb); - else - inode = kmem_cache_alloc(inode_cachep, GFP_KERNEL); - - if (!inode) - return NULL; - - if (unlikely(inode_init_always(sb, inode))) { - if (inode->i_sb->s_op->destroy_inode) - inode->i_sb->s_op->destroy_inode(inode); - else - kmem_cache_free(inode_cachep, inode); - return NULL; - } - - return inode; -} - -void free_inode_nonrcu(struct inode *inode) -{ - kmem_cache_free(inode_cachep, inode); -} -EXPORT_SYMBOL(free_inode_nonrcu); - -void __destroy_inode(struct inode *inode) -{ - BUG_ON(inode_has_buffers(inode)); - inode_detach_wb(inode); - security_inode_free(inode); - fsnotify_inode_delete(inode); - locks_free_lock_context(inode); - if (!inode->i_nlink) { - WARN_ON(atomic_long_read(&inode->i_sb->s_remove_count) == 0); - atomic_long_dec(&inode->i_sb->s_remove_count); - } - -#ifdef CONFIG_FS_POSIX_ACL - if (inode->i_acl && !is_uncached_acl(inode->i_acl)) - posix_acl_release(inode->i_acl); - if (inode->i_default_acl && !is_uncached_acl(inode->i_default_acl)) - posix_acl_release(inode->i_default_acl); -#endif - this_cpu_dec(nr_inodes); -} -EXPORT_SYMBOL(__destroy_inode); - -static void i_callback(struct rcu_head *head) -{ - struct inode *inode = container_of(head, struct inode, i_rcu); - kmem_cache_free(inode_cachep, inode); -} - -static void destroy_inode(struct inode *inode) -{ - BUG_ON(!list_empty(&inode->i_lru)); - __destroy_inode(inode); - if (inode->i_sb->s_op->destroy_inode) - inode->i_sb->s_op->destroy_inode(inode); - else - call_rcu(&inode->i_rcu, i_callback); -} - -/** - * drop_nlink - directly drop an inode's link count - * @inode: inode - * - * This is a low-level filesystem helper to replace any - * direct filesystem manipulation of i_nlink. In cases - * where we are attempting to track writes to the - * filesystem, a decrement to zero means an imminent - * write when the file is truncated and actually unlinked - * on the filesystem. - */ -void drop_nlink(struct inode *inode) -{ - WARN_ON(inode->i_nlink == 0); - inode->__i_nlink--; - if (!inode->i_nlink) - atomic_long_inc(&inode->i_sb->s_remove_count); -} -EXPORT_SYMBOL(drop_nlink); - -/** - * clear_nlink - directly zero an inode's link count - * @inode: inode - * - * This is a low-level filesystem helper to replace any - * direct filesystem manipulation of i_nlink. See - * drop_nlink() for why we care about i_nlink hitting zero. - */ -void clear_nlink(struct inode *inode) -{ - if (inode->i_nlink) { - inode->__i_nlink = 0; - atomic_long_inc(&inode->i_sb->s_remove_count); - } -} -EXPORT_SYMBOL(clear_nlink); - -/** - * set_nlink - directly set an inode's link count - * @inode: inode - * @nlink: new nlink (should be non-zero) - * - * This is a low-level filesystem helper to replace any - * direct filesystem manipulation of i_nlink. - */ -void set_nlink(struct inode *inode, unsigned int nlink) -{ - if (!nlink) { - clear_nlink(inode); - } else { - /* Yes, some filesystems do change nlink from zero to one */ - if (inode->i_nlink == 0) - atomic_long_dec(&inode->i_sb->s_remove_count); - - inode->__i_nlink = nlink; - } -} -EXPORT_SYMBOL(set_nlink); - -/** - * inc_nlink - directly increment an inode's link count - * @inode: inode - * - * This is a low-level filesystem helper to replace any - * direct filesystem manipulation of i_nlink. Currently, - * it is only here for parity with dec_nlink(). - */ -void inc_nlink(struct inode *inode) -{ - if (unlikely(inode->i_nlink == 0)) { - WARN_ON(!(inode->i_state & I_LINKABLE)); - atomic_long_dec(&inode->i_sb->s_remove_count); - } - - inode->__i_nlink++; -} -EXPORT_SYMBOL(inc_nlink); - -void address_space_init_once(struct address_space *mapping) -{ - memset(mapping, 0, sizeof(*mapping)); - INIT_RADIX_TREE(&mapping->page_tree, GFP_ATOMIC | __GFP_ACCOUNT); - spin_lock_init(&mapping->tree_lock); - init_rwsem(&mapping->i_mmap_rwsem); - INIT_LIST_HEAD(&mapping->private_list); - spin_lock_init(&mapping->private_lock); - mapping->i_mmap = RB_ROOT; -} -EXPORT_SYMBOL(address_space_init_once); - -/* - * These are initializations that only need to be done - * once, because the fields are idempotent across use - * of the inode, so let the slab aware of that. - */ -void inode_init_once(struct inode *inode) -{ - memset(inode, 0, sizeof(*inode)); - INIT_HLIST_NODE(&inode->i_hash); - INIT_LIST_HEAD(&inode->i_devices); - INIT_LIST_HEAD(&inode->i_io_list); - INIT_LIST_HEAD(&inode->i_wb_list); - INIT_LIST_HEAD(&inode->i_lru); - address_space_init_once(&inode->i_data); - i_size_ordered_init(inode); -#ifdef CONFIG_FSNOTIFY - INIT_HLIST_HEAD(&inode->i_fsnotify_marks); -#endif -} -EXPORT_SYMBOL(inode_init_once); - -static void init_once(void *foo) -{ - struct inode *inode = (struct inode *) foo; - - inode_init_once(inode); -} - -/* - * inode->i_lock must be held - */ -void __iget(struct inode *inode) -{ - atomic_inc(&inode->i_count); -} - -/* - * get additional reference to inode; caller must already hold one. - */ -void ihold(struct inode *inode) -{ - WARN_ON(atomic_inc_return(&inode->i_count) < 2); -} -EXPORT_SYMBOL(ihold); - -static void inode_lru_list_add(struct inode *inode) -{ - if (list_lru_add(&inode->i_sb->s_inode_lru, &inode->i_lru)) - this_cpu_inc(nr_unused); -} - -/* - * Add inode to LRU if needed (inode is unused and clean). - * - * Needs inode->i_lock held. - */ -void inode_add_lru(struct inode *inode) -{ - if (!(inode->i_state & (I_DIRTY_ALL | I_SYNC | - I_FREEING | I_WILL_FREE)) && - !atomic_read(&inode->i_count) && inode->i_sb->s_flags & MS_ACTIVE) - inode_lru_list_add(inode); -} - - -static void inode_lru_list_del(struct inode *inode) -{ - - if (list_lru_del(&inode->i_sb->s_inode_lru, &inode->i_lru)) - this_cpu_dec(nr_unused); -} - -/** - * inode_sb_list_add - add inode to the superblock list of inodes - * @inode: inode to add - */ -void inode_sb_list_add(struct inode *inode) -{ - spin_lock(&inode->i_sb->s_inode_list_lock); - list_add(&inode->i_sb_list, &inode->i_sb->s_inodes); - spin_unlock(&inode->i_sb->s_inode_list_lock); -} -EXPORT_SYMBOL_GPL(inode_sb_list_add); - -static inline void inode_sb_list_del(struct inode *inode) -{ - if (!list_empty(&inode->i_sb_list)) { - spin_lock(&inode->i_sb->s_inode_list_lock); - list_del_init(&inode->i_sb_list); - spin_unlock(&inode->i_sb->s_inode_list_lock); - } -} - -static unsigned long hash(struct super_block *sb, unsigned long hashval) -{ - unsigned long tmp; - - tmp = (hashval * (unsigned long)sb) ^ (GOLDEN_RATIO_PRIME + hashval) / - L1_CACHE_BYTES; - tmp = tmp ^ ((tmp ^ GOLDEN_RATIO_PRIME) >> i_hash_shift); - return tmp & i_hash_mask; -} - -/** - * __insert_inode_hash - hash an inode - * @inode: unhashed inode - * @hashval: unsigned long value used to locate this object in the - * inode_hashtable. - * - * Add an inode to the inode hash for this superblock. - */ -void __insert_inode_hash(struct inode *inode, unsigned long hashval) -{ - struct hlist_head *b = inode_hashtable + hash(inode->i_sb, hashval); - - spin_lock(&inode_hash_lock); - spin_lock(&inode->i_lock); - hlist_add_head(&inode->i_hash, b); - spin_unlock(&inode->i_lock); - spin_unlock(&inode_hash_lock); -} -EXPORT_SYMBOL(__insert_inode_hash); - -/** - * __remove_inode_hash - remove an inode from the hash - * @inode: inode to unhash - * - * Remove an inode from the superblock. - */ -void __remove_inode_hash(struct inode *inode) -{ - spin_lock(&inode_hash_lock); - spin_lock(&inode->i_lock); - hlist_del_init(&inode->i_hash); - spin_unlock(&inode->i_lock); - spin_unlock(&inode_hash_lock); -} -EXPORT_SYMBOL(__remove_inode_hash); - -void clear_inode(struct inode *inode) -{ - might_sleep(); - /* - * We have to cycle tree_lock here because reclaim can be still in the - * process of removing the last page (in __delete_from_page_cache()) - * and we must not free mapping under it. - */ - spin_lock_irq(&inode->i_data.tree_lock); - BUG_ON(inode->i_data.nrpages); - BUG_ON(inode->i_data.nrexceptional); - spin_unlock_irq(&inode->i_data.tree_lock); - BUG_ON(!list_empty(&inode->i_data.private_list)); - BUG_ON(!(inode->i_state & I_FREEING)); - BUG_ON(inode->i_state & I_CLEAR); - BUG_ON(!list_empty(&inode->i_wb_list)); - /* don't need i_lock here, no concurrent mods to i_state */ - inode->i_state = I_FREEING | I_CLEAR; -} -EXPORT_SYMBOL(clear_inode); - -/* - * Free the inode passed in, removing it from the lists it is still connected - * to. We remove any pages still attached to the inode and wait for any IO that - * is still in progress before finally destroying the inode. - * - * An inode must already be marked I_FREEING so that we avoid the inode being - * moved back onto lists if we race with other code that manipulates the lists - * (e.g. writeback_single_inode). The caller is responsible for setting this. - * - * An inode must already be removed from the LRU list before being evicted from - * the cache. This should occur atomically with setting the I_FREEING state - * flag, so no inodes here should ever be on the LRU when being evicted. - */ -static void evict(struct inode *inode) -{ - const struct super_operations *op = inode->i_sb->s_op; - - BUG_ON(!(inode->i_state & I_FREEING)); - BUG_ON(!list_empty(&inode->i_lru)); - - if (!list_empty(&inode->i_io_list)) - inode_io_list_del(inode); - - inode_sb_list_del(inode); - - /* - * Wait for flusher thread to be done with the inode so that filesystem - * does not start destroying it while writeback is still running. Since - * the inode has I_FREEING set, flusher thread won't start new work on - * the inode. We just have to wait for running writeback to finish. - */ - inode_wait_for_writeback(inode); - - if (op->evict_inode) { - op->evict_inode(inode); - } else { - truncate_inode_pages_final(&inode->i_data); - clear_inode(inode); - } - if (S_ISBLK(inode->i_mode) && inode->i_bdev) - bd_forget(inode); - if (S_ISCHR(inode->i_mode) && inode->i_cdev) - cd_forget(inode); - - remove_inode_hash(inode); - - spin_lock(&inode->i_lock); - wake_up_bit(&inode->i_state, __I_NEW); - BUG_ON(inode->i_state != (I_FREEING | I_CLEAR)); - spin_unlock(&inode->i_lock); - - destroy_inode(inode); -} - -/* - * dispose_list - dispose of the contents of a local list - * @head: the head of the list to free - * - * Dispose-list gets a local list with local inodes in it, so it doesn't - * need to worry about list corruption and SMP locks. - */ -static void dispose_list(struct list_head *head) -{ - while (!list_empty(head)) { - struct inode *inode; - - inode = list_first_entry(head, struct inode, i_lru); - list_del_init(&inode->i_lru); - - evict(inode); - cond_resched(); - } -} - -/** - * evict_inodes - evict all evictable inodes for a superblock - * @sb: superblock to operate on - * - * Make sure that no inodes with zero refcount are retained. This is - * called by superblock shutdown after having MS_ACTIVE flag removed, - * so any inode reaching zero refcount during or after that call will - * be immediately evicted. - */ -void evict_inodes(struct super_block *sb) -{ - struct inode *inode, *next; - LIST_HEAD(dispose); - -again: - spin_lock(&sb->s_inode_list_lock); - list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { - if (atomic_read(&inode->i_count)) - continue; - - spin_lock(&inode->i_lock); - if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) { - spin_unlock(&inode->i_lock); - continue; - } - - inode->i_state |= I_FREEING; - inode_lru_list_del(inode); - spin_unlock(&inode->i_lock); - list_add(&inode->i_lru, &dispose); - - /* - * We can have a ton of inodes to evict at unmount time given - * enough memory, check to see if we need to go to sleep for a - * bit so we don't livelock. - */ - if (need_resched()) { - spin_unlock(&sb->s_inode_list_lock); - cond_resched(); - dispose_list(&dispose); - goto again; - } - } - spin_unlock(&sb->s_inode_list_lock); - - dispose_list(&dispose); -} - -/** - * invalidate_inodes - attempt to free all inodes on a superblock - * @sb: superblock to operate on - * @kill_dirty: flag to guide handling of dirty inodes - * - * Attempts to free all inodes for a given superblock. If there were any - * busy inodes return a non-zero value, else zero. - * If @kill_dirty is set, discard dirty inodes too, otherwise treat - * them as busy. - */ -int invalidate_inodes(struct super_block *sb, bool kill_dirty) -{ - int busy = 0; - struct inode *inode, *next; - LIST_HEAD(dispose); - - spin_lock(&sb->s_inode_list_lock); - list_for_each_entry_safe(inode, next, &sb->s_inodes, i_sb_list) { - spin_lock(&inode->i_lock); - if (inode->i_state & (I_NEW | I_FREEING | I_WILL_FREE)) { - spin_unlock(&inode->i_lock); - continue; - } - if (inode->i_state & I_DIRTY_ALL && !kill_dirty) { - spin_unlock(&inode->i_lock); - busy = 1; - continue; - } - if (atomic_read(&inode->i_count)) { - spin_unlock(&inode->i_lock); - busy = 1; - continue; - } - - inode->i_state |= I_FREEING; - inode_lru_list_del(inode); - spin_unlock(&inode->i_lock); - list_add(&inode->i_lru, &dispose); - } - spin_unlock(&sb->s_inode_list_lock); - - dispose_list(&dispose); - - return busy; -} - -/* - * Isolate the inode from the LRU in preparation for freeing it. - * - * Any inodes which are pinned purely because of attached pagecache have their - * pagecache removed. If the inode has metadata buffers attached to - * mapping->private_list then try to remove them. - * - * If the inode has the I_REFERENCED flag set, then it means that it has been - * used recently - the flag is set in iput_final(). When we encounter such an - * inode, clear the flag and move it to the back of the LRU so it gets another - * pass through the LRU before it gets reclaimed. This is necessary because of - * the fact we are doing lazy LRU updates to minimise lock contention so the - * LRU does not have strict ordering. Hence we don't want to reclaim inodes - * with this flag set because they are the inodes that are out of order. - */ -static enum lru_status inode_lru_isolate(struct list_head *item, - struct list_lru_one *lru, spinlock_t *lru_lock, void *arg) -{ - struct list_head *freeable = arg; - struct inode *inode = container_of(item, struct inode, i_lru); - - /* - * we are inverting the lru lock/inode->i_lock here, so use a trylock. - * If we fail to get the lock, just skip it. - */ - if (!spin_trylock(&inode->i_lock)) - return LRU_SKIP; - - /* - * Referenced or dirty inodes are still in use. Give them another pass - * through the LRU as we canot reclaim them now. - */ - if (atomic_read(&inode->i_count) || - (inode->i_state & ~I_REFERENCED)) { - list_lru_isolate(lru, &inode->i_lru); - spin_unlock(&inode->i_lock); - this_cpu_dec(nr_unused); - return LRU_REMOVED; - } - - /* recently referenced inodes get one more pass */ - if (inode->i_state & I_REFERENCED) { - inode->i_state &= ~I_REFERENCED; - spin_unlock(&inode->i_lock); - return LRU_ROTATE; - } - - if (inode_has_buffers(inode) || inode->i_data.nrpages) { - __iget(inode); - spin_unlock(&inode->i_lock); - spin_unlock(lru_lock); - if (remove_inode_buffers(inode)) { - unsigned long reap; - reap = invalidate_mapping_pages(&inode->i_data, 0, -1); - if (current_is_kswapd()) - __count_vm_events(KSWAPD_INODESTEAL, reap); - else - __count_vm_events(PGINODESTEAL, reap); - if (current->reclaim_state) - current->reclaim_state->reclaimed_slab += reap; - } - iput(inode); - spin_lock(lru_lock); - return LRU_RETRY; - } - - WARN_ON(inode->i_state & I_NEW); - inode->i_state |= I_FREEING; - list_lru_isolate_move(lru, &inode->i_lru, freeable); - spin_unlock(&inode->i_lock); - - this_cpu_dec(nr_unused); - return LRU_REMOVED; -} - -/* - * Walk the superblock inode LRU for freeable inodes and attempt to free them. - * This is called from the superblock shrinker function with a number of inodes - * to trim from the LRU. Inodes to be freed are moved to a temporary list and - * then are freed outside inode_lock by dispose_list(). - */ -long prune_icache_sb(struct super_block *sb, struct shrink_control *sc) -{ - LIST_HEAD(freeable); - long freed; - - freed = list_lru_shrink_walk(&sb->s_inode_lru, sc, - inode_lru_isolate, &freeable); - dispose_list(&freeable); - return freed; -} - -static void __wait_on_freeing_inode(struct inode *inode); -/* - * Called with the inode lock held. - */ -static struct inode *find_inode(struct super_block *sb, - struct hlist_head *head, - int (*test)(struct inode *, void *), - void *data) -{ - struct inode *inode = NULL; - -repeat: - hlist_for_each_entry(inode, head, i_hash) { - if (inode->i_sb != sb) - continue; - if (!test(inode, data)) - continue; - spin_lock(&inode->i_lock); - if (inode->i_state & (I_FREEING|I_WILL_FREE)) { - __wait_on_freeing_inode(inode); - goto repeat; - } - __iget(inode); - spin_unlock(&inode->i_lock); - return inode; - } - return NULL; -} - -/* - * find_inode_fast is the fast path version of find_inode, see the comment at - * iget_locked for details. - */ -static struct inode *find_inode_fast(struct super_block *sb, - struct hlist_head *head, unsigned long ino) -{ - struct inode *inode = NULL; - -repeat: - hlist_for_each_entry(inode, head, i_hash) { - if (inode->i_ino != ino) - continue; - if (inode->i_sb != sb) - continue; - spin_lock(&inode->i_lock); - if (inode->i_state & (I_FREEING|I_WILL_FREE)) { - __wait_on_freeing_inode(inode); - goto repeat; - } - __iget(inode); - spin_unlock(&inode->i_lock); - return inode; - } - return NULL; -} - -/* - * Each cpu owns a range of LAST_INO_BATCH numbers. - * 'shared_last_ino' is dirtied only once out of LAST_INO_BATCH allocations, - * to renew the exhausted range. - * - * This does not significantly increase overflow rate because every CPU can - * consume at most LAST_INO_BATCH-1 unused inode numbers. So there is - * NR_CPUS*(LAST_INO_BATCH-1) wastage. At 4096 and 1024, this is ~0.1% of the - * 2^32 range, and is a worst-case. Even a 50% wastage would only increase - * overflow rate by 2x, which does not seem too significant. - * - * On a 32bit, non LFS stat() call, glibc will generate an EOVERFLOW - * error if st_ino won't fit in target struct field. Use 32bit counter - * here to attempt to avoid that. - */ -#define LAST_INO_BATCH 1024 -static DEFINE_PER_CPU(unsigned int, last_ino); - -unsigned int get_next_ino(void) -{ - unsigned int *p = &get_cpu_var(last_ino); - unsigned int res = *p; - -#ifdef CONFIG_SMP - if (unlikely((res & (LAST_INO_BATCH-1)) == 0)) { - static atomic_t shared_last_ino; - int next = atomic_add_return(LAST_INO_BATCH, &shared_last_ino); - - res = next - LAST_INO_BATCH; - } -#endif - - res++; - /* get_next_ino should not provide a 0 inode number */ - if (unlikely(!res)) - res++; - *p = res; - put_cpu_var(last_ino); - return res; -} -EXPORT_SYMBOL(get_next_ino); - -/** - * new_inode_pseudo - obtain an inode - * @sb: superblock - * - * Allocates a new inode for given superblock. - * Inode wont be chained in superblock s_inodes list - * This means : - * - fs can't be unmount - * - quotas, fsnotify, writeback can't work - */ -struct inode *new_inode_pseudo(struct super_block *sb) -{ - struct inode *inode = alloc_inode(sb); - - if (inode) { - spin_lock(&inode->i_lock); - inode->i_state = 0; - spin_unlock(&inode->i_lock); - INIT_LIST_HEAD(&inode->i_sb_list); - } - return inode; -} - -/** - * new_inode - obtain an inode - * @sb: superblock - * - * Allocates a new inode for given superblock. The default gfp_mask - * for allocations related to inode->i_mapping is GFP_HIGHUSER_MOVABLE. - * If HIGHMEM pages are unsuitable or it is known that pages allocated - * for the page cache are not reclaimable or migratable, - * mapping_set_gfp_mask() must be called with suitable flags on the - * newly created inode's mapping - * - */ -struct inode *new_inode(struct super_block *sb) -{ - struct inode *inode; - - spin_lock_prefetch(&sb->s_inode_list_lock); - - inode = new_inode_pseudo(sb); - if (inode) - inode_sb_list_add(inode); - return inode; -} -EXPORT_SYMBOL(new_inode); - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -void lockdep_annotate_inode_mutex_key(struct inode *inode) -{ - if (S_ISDIR(inode->i_mode)) { - struct file_system_type *type = inode->i_sb->s_type; - - /* Set new key only if filesystem hasn't already changed it */ - if (lockdep_match_class(&inode->i_rwsem, &type->i_mutex_key)) { - /* - * ensure nobody is actually holding i_mutex - */ - // mutex_destroy(&inode->i_mutex); - init_rwsem(&inode->i_rwsem); - lockdep_set_class(&inode->i_rwsem, - &type->i_mutex_dir_key); - } - } -} -EXPORT_SYMBOL(lockdep_annotate_inode_mutex_key); -#endif - -/** - * unlock_new_inode - clear the I_NEW state and wake up any waiters - * @inode: new inode to unlock - * - * Called when the inode is fully initialised to clear the new state of the - * inode and wake up anyone waiting for the inode to finish initialisation. - */ -void unlock_new_inode(struct inode *inode) -{ - lockdep_annotate_inode_mutex_key(inode); - spin_lock(&inode->i_lock); - WARN_ON(!(inode->i_state & I_NEW)); - inode->i_state &= ~I_NEW; - smp_mb(); - wake_up_bit(&inode->i_state, __I_NEW); - spin_unlock(&inode->i_lock); -} -EXPORT_SYMBOL(unlock_new_inode); - -/** - * lock_two_nondirectories - take two i_mutexes on non-directory objects - * - * Lock any non-NULL argument that is not a directory. - * Zero, one or two objects may be locked by this function. - * - * @inode1: first inode to lock - * @inode2: second inode to lock - */ -void lock_two_nondirectories(struct inode *inode1, struct inode *inode2) -{ - if (inode1 > inode2) - swap(inode1, inode2); - - if (inode1 && !S_ISDIR(inode1->i_mode)) - inode_lock(inode1); - if (inode2 && !S_ISDIR(inode2->i_mode) && inode2 != inode1) - inode_lock_nested(inode2, I_MUTEX_NONDIR2); -} -EXPORT_SYMBOL(lock_two_nondirectories); - -/** - * unlock_two_nondirectories - release locks from lock_two_nondirectories() - * @inode1: first inode to unlock - * @inode2: second inode to unlock - */ -void unlock_two_nondirectories(struct inode *inode1, struct inode *inode2) -{ - if (inode1 && !S_ISDIR(inode1->i_mode)) - inode_unlock(inode1); - if (inode2 && !S_ISDIR(inode2->i_mode) && inode2 != inode1) - inode_unlock(inode2); -} -EXPORT_SYMBOL(unlock_two_nondirectories); - -/** - * iget5_locked - obtain an inode from a mounted file system - * @sb: super block of file system - * @hashval: hash value (usually inode number) to get - * @test: callback used for comparisons between inodes - * @set: callback used to initialize a new struct inode - * @data: opaque data pointer to pass to @test and @set - * - * Search for the inode specified by @hashval and @data in the inode cache, - * and if present it is return it with an increased reference count. This is - * a generalized version of iget_locked() for file systems where the inode - * number is not sufficient for unique identification of an inode. - * - * If the inode is not in cache, allocate a new inode and return it locked, - * hashed, and with the I_NEW flag set. The file system gets to fill it in - * before unlocking it via unlock_new_inode(). - * - * Note both @test and @set are called with the inode_hash_lock held, so can't - * sleep. - */ -struct inode *iget5_locked(struct super_block *sb, unsigned long hashval, - int (*test)(struct inode *, void *), - int (*set)(struct inode *, void *), void *data) -{ - struct hlist_head *head = inode_hashtable + hash(sb, hashval); - struct inode *inode; -again: - spin_lock(&inode_hash_lock); - inode = find_inode(sb, head, test, data); - spin_unlock(&inode_hash_lock); - - if (inode) { - wait_on_inode(inode); - if (unlikely(inode_unhashed(inode))) { - iput(inode); - goto again; - } - return inode; - } - - inode = alloc_inode(sb); - if (inode) { - struct inode *old; - - spin_lock(&inode_hash_lock); - /* We released the lock, so.. */ - old = find_inode(sb, head, test, data); - if (!old) { - if (set(inode, data)) - goto set_failed; - - spin_lock(&inode->i_lock); - inode->i_state = I_NEW; - hlist_add_head(&inode->i_hash, head); - spin_unlock(&inode->i_lock); - inode_sb_list_add(inode); - spin_unlock(&inode_hash_lock); - - /* Return the locked inode with I_NEW set, the - * caller is responsible for filling in the contents - */ - return inode; - } - - /* - * Uhhuh, somebody else created the same inode under - * us. Use the old inode instead of the one we just - * allocated. - */ - spin_unlock(&inode_hash_lock); - destroy_inode(inode); - inode = old; - wait_on_inode(inode); - if (unlikely(inode_unhashed(inode))) { - iput(inode); - goto again; - } - } - return inode; - -set_failed: - spin_unlock(&inode_hash_lock); - destroy_inode(inode); - return NULL; -} -EXPORT_SYMBOL(iget5_locked); - -/** - * iget_locked - obtain an inode from a mounted file system - * @sb: super block of file system - * @ino: inode number to get - * - * Search for the inode specified by @ino in the inode cache and if present - * return it with an increased reference count. This is for file systems - * where the inode number is sufficient for unique identification of an inode. - * - * If the inode is not in cache, allocate a new inode and return it locked, - * hashed, and with the I_NEW flag set. The file system gets to fill it in - * before unlocking it via unlock_new_inode(). - */ -struct inode *iget_locked(struct super_block *sb, unsigned long ino) -{ - struct hlist_head *head = inode_hashtable + hash(sb, ino); - struct inode *inode; -again: - spin_lock(&inode_hash_lock); - inode = find_inode_fast(sb, head, ino); - spin_unlock(&inode_hash_lock); - if (inode) { - wait_on_inode(inode); - if (unlikely(inode_unhashed(inode))) { - iput(inode); - goto again; - } - return inode; - } - - inode = alloc_inode(sb); - if (inode) { - struct inode *old; - - spin_lock(&inode_hash_lock); - /* We released the lock, so.. */ - old = find_inode_fast(sb, head, ino); - if (!old) { - inode->i_ino = ino; - spin_lock(&inode->i_lock); - inode->i_state = I_NEW; - hlist_add_head(&inode->i_hash, head); - spin_unlock(&inode->i_lock); - inode_sb_list_add(inode); - spin_unlock(&inode_hash_lock); - - /* Return the locked inode with I_NEW set, the - * caller is responsible for filling in the contents - */ - return inode; - } - - /* - * Uhhuh, somebody else created the same inode under - * us. Use the old inode instead of the one we just - * allocated. - */ - spin_unlock(&inode_hash_lock); - destroy_inode(inode); - inode = old; - wait_on_inode(inode); - if (unlikely(inode_unhashed(inode))) { - iput(inode); - goto again; - } - } - return inode; -} -EXPORT_SYMBOL(iget_locked); - -/* - * search the inode cache for a matching inode number. - * If we find one, then the inode number we are trying to - * allocate is not unique and so we should not use it. - * - * Returns 1 if the inode number is unique, 0 if it is not. - */ -static int test_inode_iunique(struct super_block *sb, unsigned long ino) -{ - struct hlist_head *b = inode_hashtable + hash(sb, ino); - struct inode *inode; - - spin_lock(&inode_hash_lock); - hlist_for_each_entry(inode, b, i_hash) { - if (inode->i_ino == ino && inode->i_sb == sb) { - spin_unlock(&inode_hash_lock); - return 0; - } - } - spin_unlock(&inode_hash_lock); - - return 1; -} - -/** - * iunique - get a unique inode number - * @sb: superblock - * @max_reserved: highest reserved inode number - * - * Obtain an inode number that is unique on the system for a given - * superblock. This is used by file systems that have no natural - * permanent inode numbering system. An inode number is returned that - * is higher than the reserved limit but unique. - * - * BUGS: - * With a large number of inodes live on the file system this function - * currently becomes quite slow. - */ -ino_t iunique(struct super_block *sb, ino_t max_reserved) -{ - /* - * On a 32bit, non LFS stat() call, glibc will generate an EOVERFLOW - * error if st_ino won't fit in target struct field. Use 32bit counter - * here to attempt to avoid that. - */ - static DEFINE_SPINLOCK(iunique_lock); - static unsigned int counter; - ino_t res; - - spin_lock(&iunique_lock); - do { - if (counter <= max_reserved) - counter = max_reserved + 1; - res = counter++; - } while (!test_inode_iunique(sb, res)); - spin_unlock(&iunique_lock); - - return res; -} -EXPORT_SYMBOL(iunique); - -struct inode *igrab(struct inode *inode) -{ - spin_lock(&inode->i_lock); - if (!(inode->i_state & (I_FREEING|I_WILL_FREE))) { - __iget(inode); - spin_unlock(&inode->i_lock); - } else { - spin_unlock(&inode->i_lock); - /* - * Handle the case where s_op->clear_inode is not been - * called yet, and somebody is calling igrab - * while the inode is getting freed. - */ - inode = NULL; - } - return inode; -} -EXPORT_SYMBOL(igrab); - -/** - * ilookup5_nowait - search for an inode in the inode cache - * @sb: super block of file system to search - * @hashval: hash value (usually inode number) to search for - * @test: callback used for comparisons between inodes - * @data: opaque data pointer to pass to @test - * - * Search for the inode specified by @hashval and @data in the inode cache. - * If the inode is in the cache, the inode is returned with an incremented - * reference count. - * - * Note: I_NEW is not waited upon so you have to be very careful what you do - * with the returned inode. You probably should be using ilookup5() instead. - * - * Note2: @test is called with the inode_hash_lock held, so can't sleep. - */ -struct inode *ilookup5_nowait(struct super_block *sb, unsigned long hashval, - int (*test)(struct inode *, void *), void *data) -{ - struct hlist_head *head = inode_hashtable + hash(sb, hashval); - struct inode *inode; - - spin_lock(&inode_hash_lock); - inode = find_inode(sb, head, test, data); - spin_unlock(&inode_hash_lock); - - return inode; -} -EXPORT_SYMBOL(ilookup5_nowait); - -/** - * ilookup5 - search for an inode in the inode cache - * @sb: super block of file system to search - * @hashval: hash value (usually inode number) to search for - * @test: callback used for comparisons between inodes - * @data: opaque data pointer to pass to @test - * - * Search for the inode specified by @hashval and @data in the inode cache, - * and if the inode is in the cache, return the inode with an incremented - * reference count. Waits on I_NEW before returning the inode. - * returned with an incremented reference count. - * - * This is a generalized version of ilookup() for file systems where the - * inode number is not sufficient for unique identification of an inode. - * - * Note: @test is called with the inode_hash_lock held, so can't sleep. - */ -struct inode *ilookup5(struct super_block *sb, unsigned long hashval, - int (*test)(struct inode *, void *), void *data) -{ - struct inode *inode; -again: - inode = ilookup5_nowait(sb, hashval, test, data); - if (inode) { - wait_on_inode(inode); - if (unlikely(inode_unhashed(inode))) { - iput(inode); - goto again; - } - } - return inode; -} -EXPORT_SYMBOL(ilookup5); - -/** - * ilookup - search for an inode in the inode cache - * @sb: super block of file system to search - * @ino: inode number to search for - * - * Search for the inode @ino in the inode cache, and if the inode is in the - * cache, the inode is returned with an incremented reference count. - */ -struct inode *ilookup(struct super_block *sb, unsigned long ino) -{ - struct hlist_head *head = inode_hashtable + hash(sb, ino); - struct inode *inode; -again: - spin_lock(&inode_hash_lock); - inode = find_inode_fast(sb, head, ino); - spin_unlock(&inode_hash_lock); - - if (inode) { - wait_on_inode(inode); - if (unlikely(inode_unhashed(inode))) { - iput(inode); - goto again; - } - } - return inode; -} -EXPORT_SYMBOL(ilookup); - -/** - * find_inode_nowait - find an inode in the inode cache - * @sb: super block of file system to search - * @hashval: hash value (usually inode number) to search for - * @match: callback used for comparisons between inodes - * @data: opaque data pointer to pass to @match - * - * Search for the inode specified by @hashval and @data in the inode - * cache, where the helper function @match will return 0 if the inode - * does not match, 1 if the inode does match, and -1 if the search - * should be stopped. The @match function must be responsible for - * taking the i_lock spin_lock and checking i_state for an inode being - * freed or being initialized, and incrementing the reference count - * before returning 1. It also must not sleep, since it is called with - * the inode_hash_lock spinlock held. - * - * This is a even more generalized version of ilookup5() when the - * function must never block --- find_inode() can block in - * __wait_on_freeing_inode() --- or when the caller can not increment - * the reference count because the resulting iput() might cause an - * inode eviction. The tradeoff is that the @match funtion must be - * very carefully implemented. - */ -struct inode *find_inode_nowait(struct super_block *sb, - unsigned long hashval, - int (*match)(struct inode *, unsigned long, - void *), - void *data) -{ - struct hlist_head *head = inode_hashtable + hash(sb, hashval); - struct inode *inode, *ret_inode = NULL; - int mval; - - spin_lock(&inode_hash_lock); - hlist_for_each_entry(inode, head, i_hash) { - if (inode->i_sb != sb) - continue; - mval = match(inode, hashval, data); - if (mval == 0) - continue; - if (mval == 1) - ret_inode = inode; - goto out; - } -out: - spin_unlock(&inode_hash_lock); - return ret_inode; -} -EXPORT_SYMBOL(find_inode_nowait); - -int insert_inode_locked(struct inode *inode) -{ - struct super_block *sb = inode->i_sb; - ino_t ino = inode->i_ino; - struct hlist_head *head = inode_hashtable + hash(sb, ino); - - while (1) { - struct inode *old = NULL; - spin_lock(&inode_hash_lock); - hlist_for_each_entry(old, head, i_hash) { - if (old->i_ino != ino) - continue; - if (old->i_sb != sb) - continue; - spin_lock(&old->i_lock); - if (old->i_state & (I_FREEING|I_WILL_FREE)) { - spin_unlock(&old->i_lock); - continue; - } - break; - } - if (likely(!old)) { - spin_lock(&inode->i_lock); - inode->i_state |= I_NEW; - hlist_add_head(&inode->i_hash, head); - spin_unlock(&inode->i_lock); - spin_unlock(&inode_hash_lock); - return 0; - } - __iget(old); - spin_unlock(&old->i_lock); - spin_unlock(&inode_hash_lock); - wait_on_inode(old); - if (unlikely(!inode_unhashed(old))) { - iput(old); - return -EBUSY; - } - iput(old); - } -} -EXPORT_SYMBOL(insert_inode_locked); - -int insert_inode_locked4(struct inode *inode, unsigned long hashval, - int (*test)(struct inode *, void *), void *data) -{ - struct super_block *sb = inode->i_sb; - struct hlist_head *head = inode_hashtable + hash(sb, hashval); - - while (1) { - struct inode *old = NULL; - - spin_lock(&inode_hash_lock); - hlist_for_each_entry(old, head, i_hash) { - if (old->i_sb != sb) - continue; - if (!test(old, data)) - continue; - spin_lock(&old->i_lock); - if (old->i_state & (I_FREEING|I_WILL_FREE)) { - spin_unlock(&old->i_lock); - continue; - } - break; - } - if (likely(!old)) { - spin_lock(&inode->i_lock); - inode->i_state |= I_NEW; - hlist_add_head(&inode->i_hash, head); - spin_unlock(&inode->i_lock); - spin_unlock(&inode_hash_lock); - return 0; - } - __iget(old); - spin_unlock(&old->i_lock); - spin_unlock(&inode_hash_lock); - wait_on_inode(old); - if (unlikely(!inode_unhashed(old))) { - iput(old); - return -EBUSY; - } - iput(old); - } -} -EXPORT_SYMBOL(insert_inode_locked4); - - -int generic_delete_inode(struct inode *inode) -{ - return 1; -} -EXPORT_SYMBOL(generic_delete_inode); - -/* - * Called when we're dropping the last reference - * to an inode. - * - * Call the FS "drop_inode()" function, defaulting to - * the legacy UNIX filesystem behaviour. If it tells - * us to evict inode, do so. Otherwise, retain inode - * in cache if fs is alive, sync and evict if fs is - * shutting down. - */ -static void iput_final(struct inode *inode) -{ - struct super_block *sb = inode->i_sb; - const struct super_operations *op = inode->i_sb->s_op; - int drop; - - WARN_ON(inode->i_state & I_NEW); - - if (op->drop_inode) - drop = op->drop_inode(inode); - else - drop = generic_drop_inode(inode); - - if (!drop && (sb->s_flags & MS_ACTIVE)) { - inode->i_state |= I_REFERENCED; - inode_add_lru(inode); - spin_unlock(&inode->i_lock); - return; - } - - if (!drop) { - inode->i_state |= I_WILL_FREE; - spin_unlock(&inode->i_lock); - write_inode_now(inode, 1); - spin_lock(&inode->i_lock); - WARN_ON(inode->i_state & I_NEW); - inode->i_state &= ~I_WILL_FREE; - } - - inode->i_state |= I_FREEING; - if (!list_empty(&inode->i_lru)) - inode_lru_list_del(inode); - spin_unlock(&inode->i_lock); - - evict(inode); -} - -/** - * iput - put an inode - * @inode: inode to put - * - * Puts an inode, dropping its usage count. If the inode use count hits - * zero, the inode is then freed and may also be destroyed. - * - * Consequently, iput() can sleep. - */ -void iput(struct inode *inode) -{ - if (!inode) - return; - BUG_ON(inode->i_state & I_CLEAR); -retry: - if (atomic_dec_and_lock(&inode->i_count, &inode->i_lock)) { - if (inode->i_nlink && (inode->i_state & I_DIRTY_TIME)) { - atomic_inc(&inode->i_count); - inode->i_state &= ~I_DIRTY_TIME; - spin_unlock(&inode->i_lock); - trace_writeback_lazytime_iput(inode); - mark_inode_dirty_sync(inode); - goto retry; - } - iput_final(inode); - } -} -EXPORT_SYMBOL(iput); - -/** - * bmap - find a block number in a file - * @inode: inode of file - * @block: block to find - * - * Returns the block number on the device holding the inode that - * is the disk block number for the block of the file requested. - * That is, asked for block 4 of inode 1 the function will return the - * disk block relative to the disk start that holds that block of the - * file. - */ -sector_t bmap(struct inode *inode, sector_t block) -{ - sector_t res = 0; - if (inode->i_mapping->a_ops->bmap) - res = inode->i_mapping->a_ops->bmap(inode->i_mapping, block); - return res; -} -EXPORT_SYMBOL(bmap); - -/* - * Update times in overlayed inode from underlying real inode - */ -static void update_ovl_inode_times(struct dentry *dentry, struct inode *inode, - bool rcu) -{ - if (!rcu) { - struct inode *realinode = d_real_inode(dentry); - - if (unlikely(inode != realinode) && - (!timespec_equal(&inode->i_mtime, &realinode->i_mtime) || - !timespec_equal(&inode->i_ctime, &realinode->i_ctime))) { - inode->i_mtime = realinode->i_mtime; - inode->i_ctime = realinode->i_ctime; - } - } -} - -/* - * With relative atime, only update atime if the previous atime is - * earlier than either the ctime or mtime or if at least a day has - * passed since the last atime update. - */ -static int relatime_need_update(const struct path *path, struct inode *inode, - struct timespec now, bool rcu) -{ - - if (!(path->mnt->mnt_flags & MNT_RELATIME)) - return 1; - - update_ovl_inode_times(path->dentry, inode, rcu); - /* - * Is mtime younger than atime? If yes, update atime: - */ - if (timespec_compare(&inode->i_mtime, &inode->i_atime) >= 0) - return 1; - /* - * Is ctime younger than atime? If yes, update atime: - */ - if (timespec_compare(&inode->i_ctime, &inode->i_atime) >= 0) - return 1; - - /* - * Is the previous atime value older than a day? If yes, - * update atime: - */ - if ((long)(now.tv_sec - inode->i_atime.tv_sec) >= 24*60*60) - return 1; - /* - * Good, we can skip the atime update: - */ - return 0; -} - -int generic_update_time(struct inode *inode, struct timespec *time, int flags) -{ - int iflags = I_DIRTY_TIME; - - if (flags & S_ATIME) - inode->i_atime = *time; - if (flags & S_VERSION) - inode_inc_iversion(inode); - if (flags & S_CTIME) - inode->i_ctime = *time; - if (flags & S_MTIME) - inode->i_mtime = *time; - - if (!(inode->i_sb->s_flags & MS_LAZYTIME) || (flags & S_VERSION)) - iflags |= I_DIRTY_SYNC; - __mark_inode_dirty(inode, iflags); - return 0; -} -EXPORT_SYMBOL(generic_update_time); - -/* - * This does the actual work of updating an inodes time or version. Must have - * had called mnt_want_write() before calling this. - */ -static int update_time(struct inode *inode, struct timespec *time, int flags) -{ - int (*update_time)(struct inode *, struct timespec *, int); - - update_time = inode->i_op->update_time ? inode->i_op->update_time : - generic_update_time; - - return update_time(inode, time, flags); -} - -/** - * touch_atime - update the access time - * @path: the &struct path to update - * @inode: inode to update - * - * Update the accessed time on an inode and mark it for writeback. - * This function automatically handles read only file systems and media, - * as well as the "noatime" flag and inode specific "noatime" markers. - */ -bool __atime_needs_update(const struct path *path, struct inode *inode, - bool rcu) -{ - struct vfsmount *mnt = path->mnt; - struct timespec now; - - if (inode->i_flags & S_NOATIME) - return false; - - /* Atime updates will likely cause i_uid and i_gid to be written - * back improprely if their true value is unknown to the vfs. - */ - if (HAS_UNMAPPED_ID(inode)) - return false; - - if (IS_NOATIME(inode)) - return false; - if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode)) - return false; - - if (mnt->mnt_flags & MNT_NOATIME) - return false; - if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)) - return false; - - now = current_time(inode); - - if (!relatime_need_update(path, inode, now, rcu)) - return false; - - if (timespec_equal(&inode->i_atime, &now)) - return false; - - return true; -} - -void touch_atime(const struct path *path) -{ - struct vfsmount *mnt = path->mnt; - struct inode *inode = d_inode(path->dentry); - struct timespec now; - - if (!__atime_needs_update(path, inode, false)) - return; - - if (!sb_start_write_trylock(inode->i_sb)) - return; - - if (__mnt_want_write(mnt) != 0) - goto skip_update; - /* - * File systems can error out when updating inodes if they need to - * allocate new space to modify an inode (such is the case for - * Btrfs), but since we touch atime while walking down the path we - * really don't care if we failed to update the atime of the file, - * so just ignore the return value. - * We may also fail on filesystems that have the ability to make parts - * of the fs read only, e.g. subvolumes in Btrfs. - */ - now = current_time(inode); - update_time(inode, &now, S_ATIME); - __mnt_drop_write(mnt); -skip_update: - sb_end_write(inode->i_sb); -} -EXPORT_SYMBOL(touch_atime); - -/* - * The logic we want is - * - * if suid or (sgid and xgrp) - * remove privs - */ -int should_remove_suid(struct dentry *dentry) -{ - umode_t mode = d_inode(dentry)->i_mode; - int kill = 0; - - /* suid always must be killed */ - if (unlikely(mode & S_ISUID)) - kill = ATTR_KILL_SUID; - - /* - * sgid without any exec bits is just a mandatory locking mark; leave - * it alone. If some exec bits are set, it's a real sgid; kill it. - */ - if (unlikely((mode & S_ISGID) && (mode & S_IXGRP))) - kill |= ATTR_KILL_SGID; - - if (unlikely(kill && !capable(CAP_FSETID) && S_ISREG(mode))) - return kill; - - return 0; -} -EXPORT_SYMBOL(should_remove_suid); - -/* - * Return mask of changes for notify_change() that need to be done as a - * response to write or truncate. Return 0 if nothing has to be changed. - * Negative value on error (change should be denied). - */ -int dentry_needs_remove_privs(struct dentry *dentry) -{ - struct inode *inode = d_inode(dentry); - int mask = 0; - int ret; - - if (IS_NOSEC(inode)) - return 0; - - mask = should_remove_suid(dentry); - ret = security_inode_need_killpriv(dentry); - if (ret < 0) - return ret; - if (ret) - mask |= ATTR_KILL_PRIV; - return mask; -} - -static int __remove_privs(struct dentry *dentry, int kill) -{ - struct iattr newattrs; - - newattrs.ia_valid = ATTR_FORCE | kill; - /* - * Note we call this on write, so notify_change will not - * encounter any conflicting delegations: - */ - return notify_change(dentry, &newattrs, NULL); -} - -/* - * Remove special file priviledges (suid, capabilities) when file is written - * to or truncated. - */ -int file_remove_privs(struct file *file) -{ - struct dentry *dentry = file_dentry(file); - struct inode *inode = file_inode(file); - int kill; - int error = 0; - - /* Fast path for nothing security related */ - if (IS_NOSEC(inode)) - return 0; - - kill = dentry_needs_remove_privs(dentry); - if (kill < 0) - return kill; - if (kill) - error = __remove_privs(dentry, kill); - if (!error) - inode_has_no_xattr(inode); - - return error; -} -EXPORT_SYMBOL(file_remove_privs); - -/** - * file_update_time - update mtime and ctime time - * @file: file accessed - * - * Update the mtime and ctime members of an inode and mark the inode - * for writeback. Note that this function is meant exclusively for - * usage in the file write path of filesystems, and filesystems may - * choose to explicitly ignore update via this function with the - * S_NOCMTIME inode flag, e.g. for network filesystem where these - * timestamps are handled by the server. This can return an error for - * file systems who need to allocate space in order to update an inode. - */ - -int file_update_time(struct file *file) -{ - struct inode *inode = file_inode(file); - struct timespec now; - int sync_it = 0; - int ret; - - /* First try to exhaust all avenues to not sync */ - if (IS_NOCMTIME(inode)) - return 0; - - now = current_time(inode); - if (!timespec_equal(&inode->i_mtime, &now)) - sync_it = S_MTIME; - - if (!timespec_equal(&inode->i_ctime, &now)) - sync_it |= S_CTIME; - - if (IS_I_VERSION(inode)) - sync_it |= S_VERSION; - - if (!sync_it) - return 0; - - /* Finally allowed to write? Takes lock. */ - if (__mnt_want_write_file(file)) - return 0; - - ret = update_time(inode, &now, sync_it); - __mnt_drop_write_file(file); - - return ret; -} -EXPORT_SYMBOL(file_update_time); - -int inode_needs_sync(struct inode *inode) -{ - if (IS_SYNC(inode)) - return 1; - if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode)) - return 1; - return 0; -} -EXPORT_SYMBOL(inode_needs_sync); - -/* - * If we try to find an inode in the inode hash while it is being - * deleted, we have to wait until the filesystem completes its - * deletion before reporting that it isn't found. This function waits - * until the deletion _might_ have completed. Callers are responsible - * to recheck inode state. - * - * It doesn't matter if I_NEW is not set initially, a call to - * wake_up_bit(&inode->i_state, __I_NEW) after removing from the hash list - * will DTRT. - */ -static void __wait_on_freeing_inode(struct inode *inode) -{ - wait_queue_head_t *wq; - DEFINE_WAIT_BIT(wait, &inode->i_state, __I_NEW); - wq = bit_waitqueue(&inode->i_state, __I_NEW); - prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE); - spin_unlock(&inode->i_lock); - spin_unlock(&inode_hash_lock); - schedule(); - finish_wait(wq, &wait.wait); - spin_lock(&inode_hash_lock); -} - -static __initdata unsigned long ihash_entries; -static int __init set_ihash_entries(char *str) -{ - if (!str) - return 0; - ihash_entries = simple_strtoul(str, &str, 0); - return 1; -} -__setup("ihash_entries=", set_ihash_entries); - -/* - * Initialize the waitqueues and inode hash table. - */ -void __init inode_init_early(void) -{ - unsigned int loop; - - /* If hashes are distributed across NUMA nodes, defer - * hash allocation until vmalloc space is available. - */ - if (hashdist) - return; - - inode_hashtable = - alloc_large_system_hash("Inode-cache", - sizeof(struct hlist_head), - ihash_entries, - 14, - HASH_EARLY, - &i_hash_shift, - &i_hash_mask, - 0, - 0); - - for (loop = 0; loop < (1U << i_hash_shift); loop++) - INIT_HLIST_HEAD(&inode_hashtable[loop]); -} - -void __init inode_init(void) -{ - unsigned int loop; - - /* inode slab cache */ - inode_cachep = kmem_cache_create("inode_cache", - sizeof(struct inode), - 0, - (SLAB_RECLAIM_ACCOUNT|SLAB_PANIC| - SLAB_MEM_SPREAD|SLAB_ACCOUNT), - init_once); - - /* Hash may have been set up in inode_init_early */ - if (!hashdist) - return; - - inode_hashtable = - alloc_large_system_hash("Inode-cache", - sizeof(struct hlist_head), - ihash_entries, - 14, - 0, - &i_hash_shift, - &i_hash_mask, - 0, - 0); - - for (loop = 0; loop < (1U << i_hash_shift); loop++) - INIT_HLIST_HEAD(&inode_hashtable[loop]); -} - -void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev) -{ - inode->i_mode = mode; - if (S_ISCHR(mode)) { - inode->i_fop = &def_chr_fops; - inode->i_rdev = rdev; - } else if (S_ISBLK(mode)) { - inode->i_fop = &def_blk_fops; - inode->i_rdev = rdev; - } else if (S_ISFIFO(mode)) - inode->i_fop = &pipefifo_fops; - else if (S_ISSOCK(mode)) - ; /* leave it no_open_fops */ - else - printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for" - " inode %s:%lu\n", mode, inode->i_sb->s_id, - inode->i_ino); -} -EXPORT_SYMBOL(init_special_inode); - -/** - * inode_init_owner - Init uid,gid,mode for new inode according to posix standards - * @inode: New inode - * @dir: Directory inode - * @mode: mode of the new inode - */ -void inode_init_owner(struct inode *inode, const struct inode *dir, - umode_t mode) -{ - inode->i_uid = current_fsuid(); - if (dir && dir->i_mode & S_ISGID) { - inode->i_gid = dir->i_gid; - if (S_ISDIR(mode)) - mode |= S_ISGID; - } else - inode->i_gid = current_fsgid(); - inode->i_mode = mode; -} -EXPORT_SYMBOL(inode_init_owner); - -/** - * inode_owner_or_capable - check current task permissions to inode - * @inode: inode being checked - * - * Return true if current either has CAP_FOWNER in a namespace with the - * inode owner uid mapped, or owns the file. - */ -bool inode_owner_or_capable(const struct inode *inode) -{ - struct user_namespace *ns; - - if (uid_eq(current_fsuid(), inode->i_uid)) - return true; - - ns = current_user_ns(); - if (ns_capable(ns, CAP_FOWNER) && kuid_has_mapping(ns, inode->i_uid)) - return true; - return false; -} -EXPORT_SYMBOL(inode_owner_or_capable); - -/* - * Direct i/o helper functions - */ -static void __inode_dio_wait(struct inode *inode) -{ - wait_queue_head_t *wq = bit_waitqueue(&inode->i_state, __I_DIO_WAKEUP); - DEFINE_WAIT_BIT(q, &inode->i_state, __I_DIO_WAKEUP); - - do { - prepare_to_wait(wq, &q.wait, TASK_UNINTERRUPTIBLE); - if (atomic_read(&inode->i_dio_count)) - schedule(); - } while (atomic_read(&inode->i_dio_count)); - finish_wait(wq, &q.wait); -} - -/** - * inode_dio_wait - wait for outstanding DIO requests to finish - * @inode: inode to wait for - * - * Waits for all pending direct I/O requests to finish so that we can - * proceed with a truncate or equivalent operation. - * - * Must be called under a lock that serializes taking new references - * to i_dio_count, usually by inode->i_mutex. - */ -void inode_dio_wait(struct inode *inode) -{ - if (atomic_read(&inode->i_dio_count)) - __inode_dio_wait(inode); -} -EXPORT_SYMBOL(inode_dio_wait); - -/* - * inode_set_flags - atomically set some inode flags - * - * Note: the caller should be holding i_mutex, or else be sure that - * they have exclusive access to the inode structure (i.e., while the - * inode is being instantiated). The reason for the cmpxchg() loop - * --- which wouldn't be necessary if all code paths which modify - * i_flags actually followed this rule, is that there is at least one - * code path which doesn't today so we use cmpxchg() out of an abundance - * of caution. - * - * In the long run, i_mutex is overkill, and we should probably look - * at using the i_lock spinlock to protect i_flags, and then make sure - * it is so documented in include/linux/fs.h and that all code follows - * the locking convention!! - */ -void inode_set_flags(struct inode *inode, unsigned int flags, - unsigned int mask) -{ - unsigned int old_flags, new_flags; - - WARN_ON_ONCE(flags & ~mask); - do { - old_flags = ACCESS_ONCE(inode->i_flags); - new_flags = (old_flags & ~mask) | flags; - } while (unlikely(cmpxchg(&inode->i_flags, old_flags, - new_flags) != old_flags)); -} -EXPORT_SYMBOL(inode_set_flags); - -void inode_nohighmem(struct inode *inode) -{ - mapping_set_gfp_mask(inode->i_mapping, GFP_USER); -} -EXPORT_SYMBOL(inode_nohighmem); - -/** - * current_time - Return FS time - * @inode: inode. - * - * Return the current time truncated to the time granularity supported by - * the fs. - * - * Note that inode and inode->sb cannot be NULL. - * Otherwise, the function warns and returns time without truncation. - */ -struct timespec current_time(struct inode *inode) -{ - struct timespec now = current_kernel_time(); - - if (unlikely(!inode->i_sb)) { - WARN(1, "current_time() called with uninitialized super_block in the inode"); - return now; - } - - return timespec_trunc(now, inode->i_sb->s_time_gran); -} -EXPORT_SYMBOL(current_time); diff --git a/src/linux/fs/internal.h b/src/linux/fs/internal.h deleted file mode 100644 index f4da334..0000000 --- a/src/linux/fs/internal.h +++ /dev/null @@ -1,186 +0,0 @@ -/* fs/ internal definitions - * - * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -struct super_block; -struct file_system_type; -struct iomap; -struct iomap_ops; -struct linux_binprm; -struct path; -struct mount; -struct shrink_control; - -/* - * block_dev.c - */ -#ifdef CONFIG_BLOCK -extern void __init bdev_cache_init(void); - -extern int __sync_blockdev(struct block_device *bdev, int wait); - -#else -static inline void bdev_cache_init(void) -{ -} - -static inline int __sync_blockdev(struct block_device *bdev, int wait) -{ - return 0; -} -#endif - -/* - * buffer.c - */ -extern void guard_bio_eod(int rw, struct bio *bio); -extern int __block_write_begin_int(struct page *page, loff_t pos, unsigned len, - get_block_t *get_block, struct iomap *iomap); - -/* - * char_dev.c - */ -extern void __init chrdev_init(void); - -/* - * namei.c - */ -extern int user_path_mountpoint_at(int, const char __user *, unsigned int, struct path *); -extern int vfs_path_lookup(struct dentry *, struct vfsmount *, - const char *, unsigned int, struct path *); - -/* - * namespace.c - */ -extern void *copy_mount_options(const void __user *); -extern char *copy_mount_string(const void __user *); - -extern struct vfsmount *lookup_mnt(struct path *); -extern int finish_automount(struct vfsmount *, struct path *); - -extern int sb_prepare_remount_readonly(struct super_block *); - -extern void __init mnt_init(void); - -extern int __mnt_want_write(struct vfsmount *); -extern int __mnt_want_write_file(struct file *); -extern void __mnt_drop_write(struct vfsmount *); -extern void __mnt_drop_write_file(struct file *); - -/* - * fs_struct.c - */ -extern void chroot_fs_refs(const struct path *, const struct path *); - -/* - * file_table.c - */ -extern struct file *get_empty_filp(void); - -/* - * super.c - */ -extern int do_remount_sb(struct super_block *, int, void *, int); -extern bool trylock_super(struct super_block *sb); -extern struct dentry *mount_fs(struct file_system_type *, - int, const char *, void *); -extern struct super_block *user_get_super(dev_t); - -/* - * open.c - */ -struct open_flags { - int open_flag; - umode_t mode; - int acc_mode; - int intent; - int lookup_flags; -}; -extern struct file *do_filp_open(int dfd, struct filename *pathname, - const struct open_flags *op); -extern struct file *do_file_open_root(struct dentry *, struct vfsmount *, - const char *, const struct open_flags *); - -extern long do_handle_open(int mountdirfd, - struct file_handle __user *ufh, int open_flag); -extern int open_check_o_direct(struct file *f); -extern int vfs_open(const struct path *, struct file *, const struct cred *); -extern struct file *filp_clone_open(struct file *); - -/* - * inode.c - */ -extern long prune_icache_sb(struct super_block *sb, struct shrink_control *sc); -extern void inode_add_lru(struct inode *inode); -extern int dentry_needs_remove_privs(struct dentry *dentry); - -extern bool __atime_needs_update(const struct path *, struct inode *, bool); -static inline bool atime_needs_update_rcu(const struct path *path, - struct inode *inode) -{ - return __atime_needs_update(path, inode, true); -} - -extern bool atime_needs_update_rcu(const struct path *, struct inode *); - -/* - * fs-writeback.c - */ -extern void inode_io_list_del(struct inode *inode); - -extern long get_nr_dirty_inodes(void); -extern void evict_inodes(struct super_block *); -extern int invalidate_inodes(struct super_block *, bool); - -/* - * dcache.c - */ -extern struct dentry *__d_alloc(struct super_block *, const struct qstr *); -extern int d_set_mounted(struct dentry *dentry); -extern long prune_dcache_sb(struct super_block *sb, struct shrink_control *sc); -extern struct dentry *d_alloc_cursor(struct dentry *); - -/* - * read_write.c - */ -extern int rw_verify_area(int, struct file *, const loff_t *, size_t); - -/* - * pipe.c - */ -extern const struct file_operations pipefifo_fops; - -/* - * fs_pin.c - */ -extern void group_pin_kill(struct hlist_head *p); -extern void mnt_pin_kill(struct mount *m); - -/* - * fs/nsfs.c - */ -extern const struct dentry_operations ns_dentry_operations; - -/* - * fs/ioctl.c - */ -extern int do_vfs_ioctl(struct file *file, unsigned int fd, unsigned int cmd, - unsigned long arg); -extern long vfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); - -/* - * iomap support: - */ -typedef loff_t (*iomap_actor_t)(struct inode *inode, loff_t pos, loff_t len, - void *data, struct iomap *iomap); - -loff_t iomap_apply(struct inode *inode, loff_t pos, loff_t length, - unsigned flags, struct iomap_ops *ops, void *data, - iomap_actor_t actor); diff --git a/src/linux/fs/ioctl.c b/src/linux/fs/ioctl.c deleted file mode 100644 index c415668..0000000 --- a/src/linux/fs/ioctl.c +++ /dev/null @@ -1,697 +0,0 @@ -/* - * linux/fs/ioctl.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -#include - -/* So that the fiemap access checks can't overflow on 32 bit machines. */ -#define FIEMAP_MAX_EXTENTS (UINT_MAX / sizeof(struct fiemap_extent)) - -/** - * vfs_ioctl - call filesystem specific ioctl methods - * @filp: open file to invoke ioctl method on - * @cmd: ioctl command to execute - * @arg: command-specific argument for ioctl - * - * Invokes filesystem specific ->unlocked_ioctl, if one exists; otherwise - * returns -ENOTTY. - * - * Returns 0 on success, -errno on error. - */ -long vfs_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - int error = -ENOTTY; - - if (!filp->f_op->unlocked_ioctl) - goto out; - - error = filp->f_op->unlocked_ioctl(filp, cmd, arg); - if (error == -ENOIOCTLCMD) - error = -ENOTTY; - out: - return error; -} - -static int ioctl_fibmap(struct file *filp, int __user *p) -{ - struct address_space *mapping = filp->f_mapping; - int res, block; - - /* do we support this mess? */ - if (!mapping->a_ops->bmap) - return -EINVAL; - if (!capable(CAP_SYS_RAWIO)) - return -EPERM; - res = get_user(block, p); - if (res) - return res; - res = mapping->a_ops->bmap(mapping, block); - return put_user(res, p); -} - -/** - * fiemap_fill_next_extent - Fiemap helper function - * @fieinfo: Fiemap context passed into ->fiemap - * @logical: Extent logical start offset, in bytes - * @phys: Extent physical start offset, in bytes - * @len: Extent length, in bytes - * @flags: FIEMAP_EXTENT flags that describe this extent - * - * Called from file system ->fiemap callback. Will populate extent - * info as passed in via arguments and copy to user memory. On - * success, extent count on fieinfo is incremented. - * - * Returns 0 on success, -errno on error, 1 if this was the last - * extent that will fit in user array. - */ -#define SET_UNKNOWN_FLAGS (FIEMAP_EXTENT_DELALLOC) -#define SET_NO_UNMOUNTED_IO_FLAGS (FIEMAP_EXTENT_DATA_ENCRYPTED) -#define SET_NOT_ALIGNED_FLAGS (FIEMAP_EXTENT_DATA_TAIL|FIEMAP_EXTENT_DATA_INLINE) -int fiemap_fill_next_extent(struct fiemap_extent_info *fieinfo, u64 logical, - u64 phys, u64 len, u32 flags) -{ - struct fiemap_extent extent; - struct fiemap_extent __user *dest = fieinfo->fi_extents_start; - - /* only count the extents */ - if (fieinfo->fi_extents_max == 0) { - fieinfo->fi_extents_mapped++; - return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0; - } - - if (fieinfo->fi_extents_mapped >= fieinfo->fi_extents_max) - return 1; - - if (flags & SET_UNKNOWN_FLAGS) - flags |= FIEMAP_EXTENT_UNKNOWN; - if (flags & SET_NO_UNMOUNTED_IO_FLAGS) - flags |= FIEMAP_EXTENT_ENCODED; - if (flags & SET_NOT_ALIGNED_FLAGS) - flags |= FIEMAP_EXTENT_NOT_ALIGNED; - - memset(&extent, 0, sizeof(extent)); - extent.fe_logical = logical; - extent.fe_physical = phys; - extent.fe_length = len; - extent.fe_flags = flags; - - dest += fieinfo->fi_extents_mapped; - if (copy_to_user(dest, &extent, sizeof(extent))) - return -EFAULT; - - fieinfo->fi_extents_mapped++; - if (fieinfo->fi_extents_mapped == fieinfo->fi_extents_max) - return 1; - return (flags & FIEMAP_EXTENT_LAST) ? 1 : 0; -} -EXPORT_SYMBOL(fiemap_fill_next_extent); - -/** - * fiemap_check_flags - check validity of requested flags for fiemap - * @fieinfo: Fiemap context passed into ->fiemap - * @fs_flags: Set of fiemap flags that the file system understands - * - * Called from file system ->fiemap callback. This will compute the - * intersection of valid fiemap flags and those that the fs supports. That - * value is then compared against the user supplied flags. In case of bad user - * flags, the invalid values will be written into the fieinfo structure, and - * -EBADR is returned, which tells ioctl_fiemap() to return those values to - * userspace. For this reason, a return code of -EBADR should be preserved. - * - * Returns 0 on success, -EBADR on bad flags. - */ -int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags) -{ - u32 incompat_flags; - - incompat_flags = fieinfo->fi_flags & ~(FIEMAP_FLAGS_COMPAT & fs_flags); - if (incompat_flags) { - fieinfo->fi_flags = incompat_flags; - return -EBADR; - } - return 0; -} -EXPORT_SYMBOL(fiemap_check_flags); - -static int fiemap_check_ranges(struct super_block *sb, - u64 start, u64 len, u64 *new_len) -{ - u64 maxbytes = (u64) sb->s_maxbytes; - - *new_len = len; - - if (len == 0) - return -EINVAL; - - if (start > maxbytes) - return -EFBIG; - - /* - * Shrink request scope to what the fs can actually handle. - */ - if (len > maxbytes || (maxbytes - len) < start) - *new_len = maxbytes - start; - - return 0; -} - -static int ioctl_fiemap(struct file *filp, unsigned long arg) -{ - struct fiemap fiemap; - struct fiemap __user *ufiemap = (struct fiemap __user *) arg; - struct fiemap_extent_info fieinfo = { 0, }; - struct inode *inode = file_inode(filp); - struct super_block *sb = inode->i_sb; - u64 len; - int error; - - if (!inode->i_op->fiemap) - return -EOPNOTSUPP; - - if (copy_from_user(&fiemap, ufiemap, sizeof(fiemap))) - return -EFAULT; - - if (fiemap.fm_extent_count > FIEMAP_MAX_EXTENTS) - return -EINVAL; - - error = fiemap_check_ranges(sb, fiemap.fm_start, fiemap.fm_length, - &len); - if (error) - return error; - - fieinfo.fi_flags = fiemap.fm_flags; - fieinfo.fi_extents_max = fiemap.fm_extent_count; - fieinfo.fi_extents_start = ufiemap->fm_extents; - - if (fiemap.fm_extent_count != 0 && - !access_ok(VERIFY_WRITE, fieinfo.fi_extents_start, - fieinfo.fi_extents_max * sizeof(struct fiemap_extent))) - return -EFAULT; - - if (fieinfo.fi_flags & FIEMAP_FLAG_SYNC) - filemap_write_and_wait(inode->i_mapping); - - error = inode->i_op->fiemap(inode, &fieinfo, fiemap.fm_start, len); - fiemap.fm_flags = fieinfo.fi_flags; - fiemap.fm_mapped_extents = fieinfo.fi_extents_mapped; - if (copy_to_user(ufiemap, &fiemap, sizeof(fiemap))) - error = -EFAULT; - - return error; -} - -static long ioctl_file_clone(struct file *dst_file, unsigned long srcfd, - u64 off, u64 olen, u64 destoff) -{ - struct fd src_file = fdget(srcfd); - int ret; - - if (!src_file.file) - return -EBADF; - ret = vfs_clone_file_range(src_file.file, off, dst_file, destoff, olen); - fdput(src_file); - return ret; -} - -static long ioctl_file_clone_range(struct file *file, void __user *argp) -{ - struct file_clone_range args; - - if (copy_from_user(&args, argp, sizeof(args))) - return -EFAULT; - return ioctl_file_clone(file, args.src_fd, args.src_offset, - args.src_length, args.dest_offset); -} - -#ifdef CONFIG_BLOCK - -static inline sector_t logical_to_blk(struct inode *inode, loff_t offset) -{ - return (offset >> inode->i_blkbits); -} - -static inline loff_t blk_to_logical(struct inode *inode, sector_t blk) -{ - return (blk << inode->i_blkbits); -} - -/** - * __generic_block_fiemap - FIEMAP for block based inodes (no locking) - * @inode: the inode to map - * @fieinfo: the fiemap info struct that will be passed back to userspace - * @start: where to start mapping in the inode - * @len: how much space to map - * @get_block: the fs's get_block function - * - * This does FIEMAP for block based inodes. Basically it will just loop - * through get_block until we hit the number of extents we want to map, or we - * go past the end of the file and hit a hole. - * - * If it is possible to have data blocks beyond a hole past @inode->i_size, then - * please do not use this function, it will stop at the first unmapped block - * beyond i_size. - * - * If you use this function directly, you need to do your own locking. Use - * generic_block_fiemap if you want the locking done for you. - */ - -int __generic_block_fiemap(struct inode *inode, - struct fiemap_extent_info *fieinfo, loff_t start, - loff_t len, get_block_t *get_block) -{ - struct buffer_head map_bh; - sector_t start_blk, last_blk; - loff_t isize = i_size_read(inode); - u64 logical = 0, phys = 0, size = 0; - u32 flags = FIEMAP_EXTENT_MERGED; - bool past_eof = false, whole_file = false; - int ret = 0; - - ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC); - if (ret) - return ret; - - /* - * Either the i_mutex or other appropriate locking needs to be held - * since we expect isize to not change at all through the duration of - * this call. - */ - if (len >= isize) { - whole_file = true; - len = isize; - } - - /* - * Some filesystems can't deal with being asked to map less than - * blocksize, so make sure our len is at least block length. - */ - if (logical_to_blk(inode, len) == 0) - len = blk_to_logical(inode, 1); - - start_blk = logical_to_blk(inode, start); - last_blk = logical_to_blk(inode, start + len - 1); - - do { - /* - * we set b_size to the total size we want so it will map as - * many contiguous blocks as possible at once - */ - memset(&map_bh, 0, sizeof(struct buffer_head)); - map_bh.b_size = len; - - ret = get_block(inode, start_blk, &map_bh, 0); - if (ret) - break; - - /* HOLE */ - if (!buffer_mapped(&map_bh)) { - start_blk++; - - /* - * We want to handle the case where there is an - * allocated block at the front of the file, and then - * nothing but holes up to the end of the file properly, - * to make sure that extent at the front gets properly - * marked with FIEMAP_EXTENT_LAST - */ - if (!past_eof && - blk_to_logical(inode, start_blk) >= isize) - past_eof = 1; - - /* - * First hole after going past the EOF, this is our - * last extent - */ - if (past_eof && size) { - flags = FIEMAP_EXTENT_MERGED|FIEMAP_EXTENT_LAST; - ret = fiemap_fill_next_extent(fieinfo, logical, - phys, size, - flags); - } else if (size) { - ret = fiemap_fill_next_extent(fieinfo, logical, - phys, size, flags); - size = 0; - } - - /* if we have holes up to/past EOF then we're done */ - if (start_blk > last_blk || past_eof || ret) - break; - } else { - /* - * We have gone over the length of what we wanted to - * map, and it wasn't the entire file, so add the extent - * we got last time and exit. - * - * This is for the case where say we want to map all the - * way up to the second to the last block in a file, but - * the last block is a hole, making the second to last - * block FIEMAP_EXTENT_LAST. In this case we want to - * see if there is a hole after the second to last block - * so we can mark it properly. If we found data after - * we exceeded the length we were requesting, then we - * are good to go, just add the extent to the fieinfo - * and break - */ - if (start_blk > last_blk && !whole_file) { - ret = fiemap_fill_next_extent(fieinfo, logical, - phys, size, - flags); - break; - } - - /* - * if size != 0 then we know we already have an extent - * to add, so add it. - */ - if (size) { - ret = fiemap_fill_next_extent(fieinfo, logical, - phys, size, - flags); - if (ret) - break; - } - - logical = blk_to_logical(inode, start_blk); - phys = blk_to_logical(inode, map_bh.b_blocknr); - size = map_bh.b_size; - flags = FIEMAP_EXTENT_MERGED; - - start_blk += logical_to_blk(inode, size); - - /* - * If we are past the EOF, then we need to make sure as - * soon as we find a hole that the last extent we found - * is marked with FIEMAP_EXTENT_LAST - */ - if (!past_eof && logical + size >= isize) - past_eof = true; - } - cond_resched(); - if (fatal_signal_pending(current)) { - ret = -EINTR; - break; - } - - } while (1); - - /* If ret is 1 then we just hit the end of the extent array */ - if (ret == 1) - ret = 0; - - return ret; -} -EXPORT_SYMBOL(__generic_block_fiemap); - -/** - * generic_block_fiemap - FIEMAP for block based inodes - * @inode: The inode to map - * @fieinfo: The mapping information - * @start: The initial block to map - * @len: The length of the extect to attempt to map - * @get_block: The block mapping function for the fs - * - * Calls __generic_block_fiemap to map the inode, after taking - * the inode's mutex lock. - */ - -int generic_block_fiemap(struct inode *inode, - struct fiemap_extent_info *fieinfo, u64 start, - u64 len, get_block_t *get_block) -{ - int ret; - inode_lock(inode); - ret = __generic_block_fiemap(inode, fieinfo, start, len, get_block); - inode_unlock(inode); - return ret; -} -EXPORT_SYMBOL(generic_block_fiemap); - -#endif /* CONFIG_BLOCK */ - -/* - * This provides compatibility with legacy XFS pre-allocation ioctls - * which predate the fallocate syscall. - * - * Only the l_start, l_len and l_whence fields of the 'struct space_resv' - * are used here, rest are ignored. - */ -int ioctl_preallocate(struct file *filp, void __user *argp) -{ - struct inode *inode = file_inode(filp); - struct space_resv sr; - - if (copy_from_user(&sr, argp, sizeof(sr))) - return -EFAULT; - - switch (sr.l_whence) { - case SEEK_SET: - break; - case SEEK_CUR: - sr.l_start += filp->f_pos; - break; - case SEEK_END: - sr.l_start += i_size_read(inode); - break; - default: - return -EINVAL; - } - - return vfs_fallocate(filp, FALLOC_FL_KEEP_SIZE, sr.l_start, sr.l_len); -} - -static int file_ioctl(struct file *filp, unsigned int cmd, - unsigned long arg) -{ - struct inode *inode = file_inode(filp); - int __user *p = (int __user *)arg; - - switch (cmd) { - case FIBMAP: - return ioctl_fibmap(filp, p); - case FIONREAD: - return put_user(i_size_read(inode) - filp->f_pos, p); - case FS_IOC_RESVSP: - case FS_IOC_RESVSP64: - return ioctl_preallocate(filp, p); - } - - return vfs_ioctl(filp, cmd, arg); -} - -static int ioctl_fionbio(struct file *filp, int __user *argp) -{ - unsigned int flag; - int on, error; - - error = get_user(on, argp); - if (error) - return error; - flag = O_NONBLOCK; -#ifdef __sparc__ - /* SunOS compatibility item. */ - if (O_NONBLOCK != O_NDELAY) - flag |= O_NDELAY; -#endif - spin_lock(&filp->f_lock); - if (on) - filp->f_flags |= flag; - else - filp->f_flags &= ~flag; - spin_unlock(&filp->f_lock); - return error; -} - -static int ioctl_fioasync(unsigned int fd, struct file *filp, - int __user *argp) -{ - unsigned int flag; - int on, error; - - error = get_user(on, argp); - if (error) - return error; - flag = on ? FASYNC : 0; - - /* Did FASYNC state change ? */ - if ((flag ^ filp->f_flags) & FASYNC) { - if (filp->f_op->fasync) - /* fasync() adjusts filp->f_flags */ - error = filp->f_op->fasync(fd, filp, on); - else - error = -ENOTTY; - } - return error < 0 ? error : 0; -} - -static int ioctl_fsfreeze(struct file *filp) -{ - struct super_block *sb = file_inode(filp)->i_sb; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - /* If filesystem doesn't support freeze feature, return. */ - if (sb->s_op->freeze_fs == NULL && sb->s_op->freeze_super == NULL) - return -EOPNOTSUPP; - - /* Freeze */ - if (sb->s_op->freeze_super) - return sb->s_op->freeze_super(sb); - return freeze_super(sb); -} - -static int ioctl_fsthaw(struct file *filp) -{ - struct super_block *sb = file_inode(filp)->i_sb; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - /* Thaw */ - if (sb->s_op->thaw_super) - return sb->s_op->thaw_super(sb); - return thaw_super(sb); -} - -static int ioctl_file_dedupe_range(struct file *file, void __user *arg) -{ - struct file_dedupe_range __user *argp = arg; - struct file_dedupe_range *same = NULL; - int ret; - unsigned long size; - u16 count; - - if (get_user(count, &argp->dest_count)) { - ret = -EFAULT; - goto out; - } - - size = offsetof(struct file_dedupe_range __user, info[count]); - if (size > PAGE_SIZE) { - ret = -ENOMEM; - goto out; - } - - same = memdup_user(argp, size); - if (IS_ERR(same)) { - ret = PTR_ERR(same); - same = NULL; - goto out; - } - - same->dest_count = count; - ret = vfs_dedupe_file_range(file, same); - if (ret) - goto out; - - ret = copy_to_user(argp, same, size); - if (ret) - ret = -EFAULT; - -out: - kfree(same); - return ret; -} - -/* - * When you add any new common ioctls to the switches above and below - * please update compat_sys_ioctl() too. - * - * do_vfs_ioctl() is not for drivers and not intended to be EXPORT_SYMBOL()'d. - * It's just a simple helper for sys_ioctl and compat_sys_ioctl. - */ -int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, - unsigned long arg) -{ - int error = 0; - int __user *argp = (int __user *)arg; - struct inode *inode = file_inode(filp); - - switch (cmd) { - case FIOCLEX: - set_close_on_exec(fd, 1); - break; - - case FIONCLEX: - set_close_on_exec(fd, 0); - break; - - case FIONBIO: - error = ioctl_fionbio(filp, argp); - break; - - case FIOASYNC: - error = ioctl_fioasync(fd, filp, argp); - break; - - case FIOQSIZE: - if (S_ISDIR(inode->i_mode) || S_ISREG(inode->i_mode) || - S_ISLNK(inode->i_mode)) { - loff_t res = inode_get_bytes(inode); - error = copy_to_user(argp, &res, sizeof(res)) ? - -EFAULT : 0; - } else - error = -ENOTTY; - break; - - case FIFREEZE: - error = ioctl_fsfreeze(filp); - break; - - case FITHAW: - error = ioctl_fsthaw(filp); - break; - - case FS_IOC_FIEMAP: - return ioctl_fiemap(filp, arg); - - case FIGETBSZ: - return put_user(inode->i_sb->s_blocksize, argp); - - case FICLONE: - return ioctl_file_clone(filp, arg, 0, 0, 0); - - case FICLONERANGE: - return ioctl_file_clone_range(filp, argp); - - case FIDEDUPERANGE: - return ioctl_file_dedupe_range(filp, argp); - - default: - if (S_ISREG(inode->i_mode)) - error = file_ioctl(filp, cmd, arg); - else - error = vfs_ioctl(filp, cmd, arg); - break; - } - return error; -} - -SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) -{ - int error; - struct fd f = fdget(fd); - - if (!f.file) - return -EBADF; - error = security_file_ioctl(f.file, cmd, arg); - if (!error) - error = do_vfs_ioctl(f.file, fd, cmd, arg); - fdput(f); - return error; -} diff --git a/src/linux/fs/iomap.c b/src/linux/fs/iomap.c deleted file mode 100644 index a8ee8c3..0000000 --- a/src/linux/fs/iomap.c +++ /dev/null @@ -1,585 +0,0 @@ -/* - * Copyright (C) 2010 Red Hat, Inc. - * Copyright (c) 2016 Christoph Hellwig. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -/* - * Execute a iomap write on a segment of the mapping that spans a - * contiguous range of pages that have identical block mapping state. - * - * This avoids the need to map pages individually, do individual allocations - * for each page and most importantly avoid the need for filesystem specific - * locking per page. Instead, all the operations are amortised over the entire - * range of pages. It is assumed that the filesystems will lock whatever - * resources they require in the iomap_begin call, and release them in the - * iomap_end call. - */ -loff_t -iomap_apply(struct inode *inode, loff_t pos, loff_t length, unsigned flags, - struct iomap_ops *ops, void *data, iomap_actor_t actor) -{ - struct iomap iomap = { 0 }; - loff_t written = 0, ret; - - /* - * Need to map a range from start position for length bytes. This can - * span multiple pages - it is only guaranteed to return a range of a - * single type of pages (e.g. all into a hole, all mapped or all - * unwritten). Failure at this point has nothing to undo. - * - * If allocation is required for this range, reserve the space now so - * that the allocation is guaranteed to succeed later on. Once we copy - * the data into the page cache pages, then we cannot fail otherwise we - * expose transient stale data. If the reserve fails, we can safely - * back out at this point as there is nothing to undo. - */ - ret = ops->iomap_begin(inode, pos, length, flags, &iomap); - if (ret) - return ret; - if (WARN_ON(iomap.offset > pos)) - return -EIO; - - /* - * Cut down the length to the one actually provided by the filesystem, - * as it might not be able to give us the whole size that we requested. - */ - if (iomap.offset + iomap.length < pos + length) - length = iomap.offset + iomap.length - pos; - - /* - * Now that we have guaranteed that the space allocation will succeed. - * we can do the copy-in page by page without having to worry about - * failures exposing transient data. - */ - written = actor(inode, pos, length, data, &iomap); - - /* - * Now the data has been copied, commit the range we've copied. This - * should not fail unless the filesystem has had a fatal error. - */ - if (ops->iomap_end) { - ret = ops->iomap_end(inode, pos, length, - written > 0 ? written : 0, - flags, &iomap); - } - - return written ? written : ret; -} - -static void -iomap_write_failed(struct inode *inode, loff_t pos, unsigned len) -{ - loff_t i_size = i_size_read(inode); - - /* - * Only truncate newly allocated pages beyoned EOF, even if the - * write started inside the existing inode size. - */ - if (pos + len > i_size) - truncate_pagecache_range(inode, max(pos, i_size), pos + len); -} - -static int -iomap_write_begin(struct inode *inode, loff_t pos, unsigned len, unsigned flags, - struct page **pagep, struct iomap *iomap) -{ - pgoff_t index = pos >> PAGE_SHIFT; - struct page *page; - int status = 0; - - BUG_ON(pos + len > iomap->offset + iomap->length); - - page = grab_cache_page_write_begin(inode->i_mapping, index, flags); - if (!page) - return -ENOMEM; - - status = __block_write_begin_int(page, pos, len, NULL, iomap); - if (unlikely(status)) { - unlock_page(page); - put_page(page); - page = NULL; - - iomap_write_failed(inode, pos, len); - } - - *pagep = page; - return status; -} - -static int -iomap_write_end(struct inode *inode, loff_t pos, unsigned len, - unsigned copied, struct page *page) -{ - int ret; - - ret = generic_write_end(NULL, inode->i_mapping, pos, len, - copied, page, NULL); - if (ret < len) - iomap_write_failed(inode, pos, len); - return ret; -} - -static loff_t -iomap_write_actor(struct inode *inode, loff_t pos, loff_t length, void *data, - struct iomap *iomap) -{ - struct iov_iter *i = data; - long status = 0; - ssize_t written = 0; - unsigned int flags = AOP_FLAG_NOFS; - - /* - * Copies from kernel address space cannot fail (NFSD is a big user). - */ - if (!iter_is_iovec(i)) - flags |= AOP_FLAG_UNINTERRUPTIBLE; - - do { - struct page *page; - unsigned long offset; /* Offset into pagecache page */ - unsigned long bytes; /* Bytes to write to page */ - size_t copied; /* Bytes copied from user */ - - offset = (pos & (PAGE_SIZE - 1)); - bytes = min_t(unsigned long, PAGE_SIZE - offset, - iov_iter_count(i)); -again: - if (bytes > length) - bytes = length; - - /* - * Bring in the user page that we will copy from _first_. - * Otherwise there's a nasty deadlock on copying from the - * same page as we're writing to, without it being marked - * up-to-date. - * - * Not only is this an optimisation, but it is also required - * to check that the address is actually valid, when atomic - * usercopies are used, below. - */ - if (unlikely(iov_iter_fault_in_readable(i, bytes))) { - status = -EFAULT; - break; - } - - status = iomap_write_begin(inode, pos, bytes, flags, &page, - iomap); - if (unlikely(status)) - break; - - if (mapping_writably_mapped(inode->i_mapping)) - flush_dcache_page(page); - - copied = iov_iter_copy_from_user_atomic(page, i, offset, bytes); - - flush_dcache_page(page); - - status = iomap_write_end(inode, pos, bytes, copied, page); - if (unlikely(status < 0)) - break; - copied = status; - - cond_resched(); - - iov_iter_advance(i, copied); - if (unlikely(copied == 0)) { - /* - * If we were unable to copy any data at all, we must - * fall back to a single segment length write. - * - * If we didn't fallback here, we could livelock - * because not all segments in the iov can be copied at - * once without a pagefault. - */ - bytes = min_t(unsigned long, PAGE_SIZE - offset, - iov_iter_single_seg_count(i)); - goto again; - } - pos += copied; - written += copied; - length -= copied; - - balance_dirty_pages_ratelimited(inode->i_mapping); - } while (iov_iter_count(i) && length); - - return written ? written : status; -} - -ssize_t -iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *iter, - struct iomap_ops *ops) -{ - struct inode *inode = iocb->ki_filp->f_mapping->host; - loff_t pos = iocb->ki_pos, ret = 0, written = 0; - - while (iov_iter_count(iter)) { - ret = iomap_apply(inode, pos, iov_iter_count(iter), - IOMAP_WRITE, ops, iter, iomap_write_actor); - if (ret <= 0) - break; - pos += ret; - written += ret; - } - - return written ? written : ret; -} -EXPORT_SYMBOL_GPL(iomap_file_buffered_write); - -static struct page * -__iomap_read_page(struct inode *inode, loff_t offset) -{ - struct address_space *mapping = inode->i_mapping; - struct page *page; - - page = read_mapping_page(mapping, offset >> PAGE_SHIFT, NULL); - if (IS_ERR(page)) - return page; - if (!PageUptodate(page)) { - put_page(page); - return ERR_PTR(-EIO); - } - return page; -} - -static loff_t -iomap_dirty_actor(struct inode *inode, loff_t pos, loff_t length, void *data, - struct iomap *iomap) -{ - long status = 0; - ssize_t written = 0; - - do { - struct page *page, *rpage; - unsigned long offset; /* Offset into pagecache page */ - unsigned long bytes; /* Bytes to write to page */ - - offset = (pos & (PAGE_SIZE - 1)); - bytes = min_t(unsigned long, PAGE_SIZE - offset, length); - - rpage = __iomap_read_page(inode, pos); - if (IS_ERR(rpage)) - return PTR_ERR(rpage); - - status = iomap_write_begin(inode, pos, bytes, - AOP_FLAG_NOFS | AOP_FLAG_UNINTERRUPTIBLE, - &page, iomap); - put_page(rpage); - if (unlikely(status)) - return status; - - WARN_ON_ONCE(!PageUptodate(page)); - - status = iomap_write_end(inode, pos, bytes, bytes, page); - if (unlikely(status <= 0)) { - if (WARN_ON_ONCE(status == 0)) - return -EIO; - return status; - } - - cond_resched(); - - pos += status; - written += status; - length -= status; - - balance_dirty_pages_ratelimited(inode->i_mapping); - } while (length); - - return written; -} - -int -iomap_file_dirty(struct inode *inode, loff_t pos, loff_t len, - struct iomap_ops *ops) -{ - loff_t ret; - - while (len) { - ret = iomap_apply(inode, pos, len, IOMAP_WRITE, ops, NULL, - iomap_dirty_actor); - if (ret <= 0) - return ret; - pos += ret; - len -= ret; - } - - return 0; -} -EXPORT_SYMBOL_GPL(iomap_file_dirty); - -static int iomap_zero(struct inode *inode, loff_t pos, unsigned offset, - unsigned bytes, struct iomap *iomap) -{ - struct page *page; - int status; - - status = iomap_write_begin(inode, pos, bytes, - AOP_FLAG_UNINTERRUPTIBLE | AOP_FLAG_NOFS, &page, iomap); - if (status) - return status; - - zero_user(page, offset, bytes); - mark_page_accessed(page); - - return iomap_write_end(inode, pos, bytes, bytes, page); -} - -static int iomap_dax_zero(loff_t pos, unsigned offset, unsigned bytes, - struct iomap *iomap) -{ - sector_t sector = iomap->blkno + - (((pos & ~(PAGE_SIZE - 1)) - iomap->offset) >> 9); - - return __dax_zero_page_range(iomap->bdev, sector, offset, bytes); -} - -static loff_t -iomap_zero_range_actor(struct inode *inode, loff_t pos, loff_t count, - void *data, struct iomap *iomap) -{ - bool *did_zero = data; - loff_t written = 0; - int status; - - /* already zeroed? we're done. */ - if (iomap->type == IOMAP_HOLE || iomap->type == IOMAP_UNWRITTEN) - return count; - - do { - unsigned offset, bytes; - - offset = pos & (PAGE_SIZE - 1); /* Within page */ - bytes = min_t(unsigned, PAGE_SIZE - offset, count); - - if (IS_DAX(inode)) - status = iomap_dax_zero(pos, offset, bytes, iomap); - else - status = iomap_zero(inode, pos, offset, bytes, iomap); - if (status < 0) - return status; - - pos += bytes; - count -= bytes; - written += bytes; - if (did_zero) - *did_zero = true; - } while (count > 0); - - return written; -} - -int -iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, bool *did_zero, - struct iomap_ops *ops) -{ - loff_t ret; - - while (len > 0) { - ret = iomap_apply(inode, pos, len, IOMAP_ZERO, - ops, did_zero, iomap_zero_range_actor); - if (ret <= 0) - return ret; - - pos += ret; - len -= ret; - } - - return 0; -} -EXPORT_SYMBOL_GPL(iomap_zero_range); - -int -iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero, - struct iomap_ops *ops) -{ - unsigned blocksize = (1 << inode->i_blkbits); - unsigned off = pos & (blocksize - 1); - - /* Block boundary? Nothing to do */ - if (!off) - return 0; - return iomap_zero_range(inode, pos, blocksize - off, did_zero, ops); -} -EXPORT_SYMBOL_GPL(iomap_truncate_page); - -static loff_t -iomap_page_mkwrite_actor(struct inode *inode, loff_t pos, loff_t length, - void *data, struct iomap *iomap) -{ - struct page *page = data; - int ret; - - ret = __block_write_begin_int(page, pos, length, NULL, iomap); - if (ret) - return ret; - - block_commit_write(page, 0, length); - return length; -} - -int iomap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, - struct iomap_ops *ops) -{ - struct page *page = vmf->page; - struct inode *inode = file_inode(vma->vm_file); - unsigned long length; - loff_t offset, size; - ssize_t ret; - - lock_page(page); - size = i_size_read(inode); - if ((page->mapping != inode->i_mapping) || - (page_offset(page) > size)) { - /* We overload EFAULT to mean page got truncated */ - ret = -EFAULT; - goto out_unlock; - } - - /* page is wholly or partially inside EOF */ - if (((page->index + 1) << PAGE_SHIFT) > size) - length = size & ~PAGE_MASK; - else - length = PAGE_SIZE; - - offset = page_offset(page); - while (length > 0) { - ret = iomap_apply(inode, offset, length, IOMAP_WRITE, - ops, page, iomap_page_mkwrite_actor); - if (unlikely(ret <= 0)) - goto out_unlock; - offset += ret; - length -= ret; - } - - set_page_dirty(page); - wait_for_stable_page(page); - return 0; -out_unlock: - unlock_page(page); - return ret; -} -EXPORT_SYMBOL_GPL(iomap_page_mkwrite); - -struct fiemap_ctx { - struct fiemap_extent_info *fi; - struct iomap prev; -}; - -static int iomap_to_fiemap(struct fiemap_extent_info *fi, - struct iomap *iomap, u32 flags) -{ - switch (iomap->type) { - case IOMAP_HOLE: - /* skip holes */ - return 0; - case IOMAP_DELALLOC: - flags |= FIEMAP_EXTENT_DELALLOC | FIEMAP_EXTENT_UNKNOWN; - break; - case IOMAP_UNWRITTEN: - flags |= FIEMAP_EXTENT_UNWRITTEN; - break; - case IOMAP_MAPPED: - break; - } - - if (iomap->flags & IOMAP_F_MERGED) - flags |= FIEMAP_EXTENT_MERGED; - if (iomap->flags & IOMAP_F_SHARED) - flags |= FIEMAP_EXTENT_SHARED; - - return fiemap_fill_next_extent(fi, iomap->offset, - iomap->blkno != IOMAP_NULL_BLOCK ? iomap->blkno << 9: 0, - iomap->length, flags); - -} - -static loff_t -iomap_fiemap_actor(struct inode *inode, loff_t pos, loff_t length, void *data, - struct iomap *iomap) -{ - struct fiemap_ctx *ctx = data; - loff_t ret = length; - - if (iomap->type == IOMAP_HOLE) - return length; - - ret = iomap_to_fiemap(ctx->fi, &ctx->prev, 0); - ctx->prev = *iomap; - switch (ret) { - case 0: /* success */ - return length; - case 1: /* extent array full */ - return 0; - default: - return ret; - } -} - -int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fi, - loff_t start, loff_t len, struct iomap_ops *ops) -{ - struct fiemap_ctx ctx; - loff_t ret; - - memset(&ctx, 0, sizeof(ctx)); - ctx.fi = fi; - ctx.prev.type = IOMAP_HOLE; - - ret = fiemap_check_flags(fi, FIEMAP_FLAG_SYNC); - if (ret) - return ret; - - if (fi->fi_flags & FIEMAP_FLAG_SYNC) { - ret = filemap_write_and_wait(inode->i_mapping); - if (ret) - return ret; - } - - while (len > 0) { - ret = iomap_apply(inode, start, len, IOMAP_REPORT, ops, &ctx, - iomap_fiemap_actor); - /* inode with no (attribute) mapping will give ENOENT */ - if (ret == -ENOENT) - break; - if (ret < 0) - return ret; - if (ret == 0) - break; - - start += ret; - len -= ret; - } - - if (ctx.prev.type != IOMAP_HOLE) { - ret = iomap_to_fiemap(fi, &ctx.prev, FIEMAP_EXTENT_LAST); - if (ret < 0) - return ret; - } - - return 0; -} -EXPORT_SYMBOL_GPL(iomap_fiemap); diff --git a/src/linux/fs/isofs/Kconfig b/src/linux/fs/isofs/Kconfig deleted file mode 100644 index 8ab9878..0000000 --- a/src/linux/fs/isofs/Kconfig +++ /dev/null @@ -1,39 +0,0 @@ -config ISO9660_FS - tristate "ISO 9660 CDROM file system support" - help - This is the standard file system used on CD-ROMs. It was previously - known as "High Sierra File System" and is called "hsfs" on other - Unix systems. The so-called Rock-Ridge extensions which allow for - long Unix filenames and symbolic links are also supported by this - driver. If you have a CD-ROM drive and want to do more with it than - just listen to audio CDs and watch its LEDs, say Y (and read - and the CD-ROM-HOWTO, - available from ), thereby - enlarging your kernel by about 27 KB; otherwise say N. - - To compile this file system support as a module, choose M here: the - module will be called isofs. - -config JOLIET - bool "Microsoft Joliet CDROM extensions" - depends on ISO9660_FS - select NLS - help - Joliet is a Microsoft extension for the ISO 9660 CD-ROM file system - which allows for long filenames in unicode format (unicode is the - new 16 bit character code, successor to ASCII, which encodes the - characters of almost all languages of the world; see - for more information). Say Y here if you - want to be able to read Joliet CD-ROMs under Linux. - -config ZISOFS - bool "Transparent decompression extension" - depends on ISO9660_FS - select ZLIB_INFLATE - help - This is a Linux-specific extension to RockRidge which lets you store - data in compressed form on a CD-ROM and have it transparently - decompressed when the CD-ROM is accessed. See - for the tools - necessary to create such a filesystem. Say Y here if you want to be - able to read such compressed CD-ROMs. diff --git a/src/linux/fs/jbd2/Kconfig b/src/linux/fs/jbd2/Kconfig deleted file mode 100644 index 5a9f553..0000000 --- a/src/linux/fs/jbd2/Kconfig +++ /dev/null @@ -1,35 +0,0 @@ -config JBD2 - tristate - select CRC32 - select CRYPTO - select CRYPTO_CRC32C - help - This is a generic journaling layer for block devices that support - both 32-bit and 64-bit block numbers. It is currently used by - the ext4 and OCFS2 filesystems, but it could also be used to add - journal support to other file systems or block devices such - as RAID or LVM. - - If you are using ext4 or OCFS2, you need to say Y here. - If you are not using ext4 or OCFS2 then you will - probably want to say N. - - To compile this device as a module, choose M here. The module will be - called jbd2. If you are compiling ext4 or OCFS2 into the kernel, - you cannot compile this code as a module. - -config JBD2_DEBUG - bool "JBD2 (ext4) debugging support" - depends on JBD2 - help - If you are using the ext4 journaled file system (or - potentially any other filesystem/device using JBD2), this option - allows you to enable debugging output while the system is running, - in order to help track down any problems you are having. - By default, the debugging output will be turned off. - - If you select Y here, then you will be able to turn on debugging - with "echo N > /sys/module/jbd2/parameters/jbd2_debug", where N is a - number between 1 and 5. The higher the number, the more debugging - output is generated. To turn debugging off again, do - "echo 0 > /sys/module/jbd2/parameters/jbd2_debug". diff --git a/src/linux/fs/jbd2/Makefile b/src/linux/fs/jbd2/Makefile deleted file mode 100644 index 802a341..0000000 --- a/src/linux/fs/jbd2/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -# -# Makefile for the linux journaling routines. -# - -obj-$(CONFIG_JBD2) += jbd2.o - -jbd2-objs := transaction.o commit.o recovery.o checkpoint.o revoke.o journal.o diff --git a/src/linux/fs/jbd2/checkpoint.c b/src/linux/fs/jbd2/checkpoint.c deleted file mode 100644 index 684996c..0000000 --- a/src/linux/fs/jbd2/checkpoint.c +++ /dev/null @@ -1,669 +0,0 @@ -/* - * linux/fs/jbd2/checkpoint.c - * - * Written by Stephen C. Tweedie , 1999 - * - * Copyright 1999 Red Hat Software --- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * Checkpoint routines for the generic filesystem journaling code. - * Part of the ext2fs journaling system. - * - * Checkpointing is the process of ensuring that a section of the log is - * committed fully to disk, so that that portion of the log can be - * reused. - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * Unlink a buffer from a transaction checkpoint list. - * - * Called with j_list_lock held. - */ -static inline void __buffer_unlink_first(struct journal_head *jh) -{ - transaction_t *transaction = jh->b_cp_transaction; - - jh->b_cpnext->b_cpprev = jh->b_cpprev; - jh->b_cpprev->b_cpnext = jh->b_cpnext; - if (transaction->t_checkpoint_list == jh) { - transaction->t_checkpoint_list = jh->b_cpnext; - if (transaction->t_checkpoint_list == jh) - transaction->t_checkpoint_list = NULL; - } -} - -/* - * Unlink a buffer from a transaction checkpoint(io) list. - * - * Called with j_list_lock held. - */ -static inline void __buffer_unlink(struct journal_head *jh) -{ - transaction_t *transaction = jh->b_cp_transaction; - - __buffer_unlink_first(jh); - if (transaction->t_checkpoint_io_list == jh) { - transaction->t_checkpoint_io_list = jh->b_cpnext; - if (transaction->t_checkpoint_io_list == jh) - transaction->t_checkpoint_io_list = NULL; - } -} - -/* - * Move a buffer from the checkpoint list to the checkpoint io list - * - * Called with j_list_lock held - */ -static inline void __buffer_relink_io(struct journal_head *jh) -{ - transaction_t *transaction = jh->b_cp_transaction; - - __buffer_unlink_first(jh); - - if (!transaction->t_checkpoint_io_list) { - jh->b_cpnext = jh->b_cpprev = jh; - } else { - jh->b_cpnext = transaction->t_checkpoint_io_list; - jh->b_cpprev = transaction->t_checkpoint_io_list->b_cpprev; - jh->b_cpprev->b_cpnext = jh; - jh->b_cpnext->b_cpprev = jh; - } - transaction->t_checkpoint_io_list = jh; -} - -/* - * Try to release a checkpointed buffer from its transaction. - * Returns 1 if we released it and 2 if we also released the - * whole transaction. - * - * Requires j_list_lock - */ -static int __try_to_free_cp_buf(struct journal_head *jh) -{ - int ret = 0; - struct buffer_head *bh = jh2bh(jh); - - if (jh->b_transaction == NULL && !buffer_locked(bh) && - !buffer_dirty(bh) && !buffer_write_io_error(bh)) { - JBUFFER_TRACE(jh, "remove from checkpoint list"); - ret = __jbd2_journal_remove_checkpoint(jh) + 1; - } - return ret; -} - -/* - * __jbd2_log_wait_for_space: wait until there is space in the journal. - * - * Called under j-state_lock *only*. It will be unlocked if we have to wait - * for a checkpoint to free up some space in the log. - */ -void __jbd2_log_wait_for_space(journal_t *journal) -{ - int nblocks, space_left; - /* assert_spin_locked(&journal->j_state_lock); */ - - nblocks = jbd2_space_needed(journal); - while (jbd2_log_space_left(journal) < nblocks) { - write_unlock(&journal->j_state_lock); - mutex_lock(&journal->j_checkpoint_mutex); - - /* - * Test again, another process may have checkpointed while we - * were waiting for the checkpoint lock. If there are no - * transactions ready to be checkpointed, try to recover - * journal space by calling cleanup_journal_tail(), and if - * that doesn't work, by waiting for the currently committing - * transaction to complete. If there is absolutely no way - * to make progress, this is either a BUG or corrupted - * filesystem, so abort the journal and leave a stack - * trace for forensic evidence. - */ - write_lock(&journal->j_state_lock); - if (journal->j_flags & JBD2_ABORT) { - mutex_unlock(&journal->j_checkpoint_mutex); - return; - } - spin_lock(&journal->j_list_lock); - nblocks = jbd2_space_needed(journal); - space_left = jbd2_log_space_left(journal); - if (space_left < nblocks) { - int chkpt = journal->j_checkpoint_transactions != NULL; - tid_t tid = 0; - - if (journal->j_committing_transaction) - tid = journal->j_committing_transaction->t_tid; - spin_unlock(&journal->j_list_lock); - write_unlock(&journal->j_state_lock); - if (chkpt) { - jbd2_log_do_checkpoint(journal); - } else if (jbd2_cleanup_journal_tail(journal) == 0) { - /* We were able to recover space; yay! */ - ; - } else if (tid) { - /* - * jbd2_journal_commit_transaction() may want - * to take the checkpoint_mutex if JBD2_FLUSHED - * is set. So we need to temporarily drop it. - */ - mutex_unlock(&journal->j_checkpoint_mutex); - jbd2_log_wait_commit(journal, tid); - write_lock(&journal->j_state_lock); - continue; - } else { - printk(KERN_ERR "%s: needed %d blocks and " - "only had %d space available\n", - __func__, nblocks, space_left); - printk(KERN_ERR "%s: no way to get more " - "journal space in %s\n", __func__, - journal->j_devname); - WARN_ON(1); - jbd2_journal_abort(journal, 0); - } - write_lock(&journal->j_state_lock); - } else { - spin_unlock(&journal->j_list_lock); - } - mutex_unlock(&journal->j_checkpoint_mutex); - } -} - -static void -__flush_batch(journal_t *journal, int *batch_count) -{ - int i; - struct blk_plug plug; - - blk_start_plug(&plug); - for (i = 0; i < *batch_count; i++) - write_dirty_buffer(journal->j_chkpt_bhs[i], WRITE_SYNC); - blk_finish_plug(&plug); - - for (i = 0; i < *batch_count; i++) { - struct buffer_head *bh = journal->j_chkpt_bhs[i]; - BUFFER_TRACE(bh, "brelse"); - __brelse(bh); - } - *batch_count = 0; -} - -/* - * Perform an actual checkpoint. We take the first transaction on the - * list of transactions to be checkpointed and send all its buffers - * to disk. We submit larger chunks of data at once. - * - * The journal should be locked before calling this function. - * Called with j_checkpoint_mutex held. - */ -int jbd2_log_do_checkpoint(journal_t *journal) -{ - struct journal_head *jh; - struct buffer_head *bh; - transaction_t *transaction; - tid_t this_tid; - int result, batch_count = 0; - - jbd_debug(1, "Start checkpoint\n"); - - /* - * First thing: if there are any transactions in the log which - * don't need checkpointing, just eliminate them from the - * journal straight away. - */ - result = jbd2_cleanup_journal_tail(journal); - trace_jbd2_checkpoint(journal, result); - jbd_debug(1, "cleanup_journal_tail returned %d\n", result); - if (result <= 0) - return result; - - /* - * OK, we need to start writing disk blocks. Take one transaction - * and write it. - */ - result = 0; - spin_lock(&journal->j_list_lock); - if (!journal->j_checkpoint_transactions) - goto out; - transaction = journal->j_checkpoint_transactions; - if (transaction->t_chp_stats.cs_chp_time == 0) - transaction->t_chp_stats.cs_chp_time = jiffies; - this_tid = transaction->t_tid; -restart: - /* - * If someone cleaned up this transaction while we slept, we're - * done (maybe it's a new transaction, but it fell at the same - * address). - */ - if (journal->j_checkpoint_transactions != transaction || - transaction->t_tid != this_tid) - goto out; - - /* checkpoint all of the transaction's buffers */ - while (transaction->t_checkpoint_list) { - jh = transaction->t_checkpoint_list; - bh = jh2bh(jh); - - if (buffer_locked(bh)) { - spin_unlock(&journal->j_list_lock); - get_bh(bh); - wait_on_buffer(bh); - /* the journal_head may have gone by now */ - BUFFER_TRACE(bh, "brelse"); - __brelse(bh); - goto retry; - } - if (jh->b_transaction != NULL) { - transaction_t *t = jh->b_transaction; - tid_t tid = t->t_tid; - - transaction->t_chp_stats.cs_forced_to_close++; - spin_unlock(&journal->j_list_lock); - if (unlikely(journal->j_flags & JBD2_UNMOUNT)) - /* - * The journal thread is dead; so - * starting and waiting for a commit - * to finish will cause us to wait for - * a _very_ long time. - */ - printk(KERN_ERR - "JBD2: %s: Waiting for Godot: block %llu\n", - journal->j_devname, (unsigned long long) bh->b_blocknr); - - jbd2_log_start_commit(journal, tid); - jbd2_log_wait_commit(journal, tid); - goto retry; - } - if (!buffer_dirty(bh)) { - if (unlikely(buffer_write_io_error(bh)) && !result) - result = -EIO; - BUFFER_TRACE(bh, "remove from checkpoint"); - if (__jbd2_journal_remove_checkpoint(jh)) - /* The transaction was released; we're done */ - goto out; - continue; - } - /* - * Important: we are about to write the buffer, and - * possibly block, while still holding the journal - * lock. We cannot afford to let the transaction - * logic start messing around with this buffer before - * we write it to disk, as that would break - * recoverability. - */ - BUFFER_TRACE(bh, "queue"); - get_bh(bh); - J_ASSERT_BH(bh, !buffer_jwrite(bh)); - journal->j_chkpt_bhs[batch_count++] = bh; - __buffer_relink_io(jh); - transaction->t_chp_stats.cs_written++; - if ((batch_count == JBD2_NR_BATCH) || - need_resched() || - spin_needbreak(&journal->j_list_lock)) - goto unlock_and_flush; - } - - if (batch_count) { - unlock_and_flush: - spin_unlock(&journal->j_list_lock); - retry: - if (batch_count) - __flush_batch(journal, &batch_count); - spin_lock(&journal->j_list_lock); - goto restart; - } - - /* - * Now we issued all of the transaction's buffers, let's deal - * with the buffers that are out for I/O. - */ -restart2: - /* Did somebody clean up the transaction in the meanwhile? */ - if (journal->j_checkpoint_transactions != transaction || - transaction->t_tid != this_tid) - goto out; - - while (transaction->t_checkpoint_io_list) { - jh = transaction->t_checkpoint_io_list; - bh = jh2bh(jh); - if (buffer_locked(bh)) { - spin_unlock(&journal->j_list_lock); - get_bh(bh); - wait_on_buffer(bh); - /* the journal_head may have gone by now */ - BUFFER_TRACE(bh, "brelse"); - __brelse(bh); - spin_lock(&journal->j_list_lock); - goto restart2; - } - if (unlikely(buffer_write_io_error(bh)) && !result) - result = -EIO; - - /* - * Now in whatever state the buffer currently is, we - * know that it has been written out and so we can - * drop it from the list - */ - if (__jbd2_journal_remove_checkpoint(jh)) - break; - } -out: - spin_unlock(&journal->j_list_lock); - if (result < 0) - jbd2_journal_abort(journal, result); - else - result = jbd2_cleanup_journal_tail(journal); - - return (result < 0) ? result : 0; -} - -/* - * Check the list of checkpoint transactions for the journal to see if - * we have already got rid of any since the last update of the log tail - * in the journal superblock. If so, we can instantly roll the - * superblock forward to remove those transactions from the log. - * - * Return <0 on error, 0 on success, 1 if there was nothing to clean up. - * - * Called with the journal lock held. - * - * This is the only part of the journaling code which really needs to be - * aware of transaction aborts. Checkpointing involves writing to the - * main filesystem area rather than to the journal, so it can proceed - * even in abort state, but we must not update the super block if - * checkpointing may have failed. Otherwise, we would lose some metadata - * buffers which should be written-back to the filesystem. - */ - -int jbd2_cleanup_journal_tail(journal_t *journal) -{ - tid_t first_tid; - unsigned long blocknr; - - if (is_journal_aborted(journal)) - return -EIO; - - if (!jbd2_journal_get_log_tail(journal, &first_tid, &blocknr)) - return 1; - J_ASSERT(blocknr != 0); - - /* - * We need to make sure that any blocks that were recently written out - * --- perhaps by jbd2_log_do_checkpoint() --- are flushed out before - * we drop the transactions from the journal. It's unlikely this will - * be necessary, especially with an appropriately sized journal, but we - * need this to guarantee correctness. Fortunately - * jbd2_cleanup_journal_tail() doesn't get called all that often. - */ - if (journal->j_flags & JBD2_BARRIER) - blkdev_issue_flush(journal->j_fs_dev, GFP_NOFS, NULL); - - return __jbd2_update_log_tail(journal, first_tid, blocknr); -} - - -/* Checkpoint list management */ - -/* - * journal_clean_one_cp_list - * - * Find all the written-back checkpoint buffers in the given list and - * release them. If 'destroy' is set, clean all buffers unconditionally. - * - * Called with j_list_lock held. - * Returns 1 if we freed the transaction, 0 otherwise. - */ -static int journal_clean_one_cp_list(struct journal_head *jh, bool destroy) -{ - struct journal_head *last_jh; - struct journal_head *next_jh = jh; - int ret; - - if (!jh) - return 0; - - last_jh = jh->b_cpprev; - do { - jh = next_jh; - next_jh = jh->b_cpnext; - if (!destroy) - ret = __try_to_free_cp_buf(jh); - else - ret = __jbd2_journal_remove_checkpoint(jh) + 1; - if (!ret) - return 0; - if (ret == 2) - return 1; - /* - * This function only frees up some memory - * if possible so we dont have an obligation - * to finish processing. Bail out if preemption - * requested: - */ - if (need_resched()) - return 0; - } while (jh != last_jh); - - return 0; -} - -/* - * journal_clean_checkpoint_list - * - * Find all the written-back checkpoint buffers in the journal and release them. - * If 'destroy' is set, release all buffers unconditionally. - * - * Called with j_list_lock held. - */ -void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy) -{ - transaction_t *transaction, *last_transaction, *next_transaction; - int ret; - - transaction = journal->j_checkpoint_transactions; - if (!transaction) - return; - - last_transaction = transaction->t_cpprev; - next_transaction = transaction; - do { - transaction = next_transaction; - next_transaction = transaction->t_cpnext; - ret = journal_clean_one_cp_list(transaction->t_checkpoint_list, - destroy); - /* - * This function only frees up some memory if possible so we - * dont have an obligation to finish processing. Bail out if - * preemption requested: - */ - if (need_resched()) - return; - if (ret) - continue; - /* - * It is essential that we are as careful as in the case of - * t_checkpoint_list with removing the buffer from the list as - * we can possibly see not yet submitted buffers on io_list - */ - ret = journal_clean_one_cp_list(transaction-> - t_checkpoint_io_list, destroy); - if (need_resched()) - return; - /* - * Stop scanning if we couldn't free the transaction. This - * avoids pointless scanning of transactions which still - * weren't checkpointed. - */ - if (!ret) - return; - } while (transaction != last_transaction); -} - -/* - * Remove buffers from all checkpoint lists as journal is aborted and we just - * need to free memory - */ -void jbd2_journal_destroy_checkpoint(journal_t *journal) -{ - /* - * We loop because __jbd2_journal_clean_checkpoint_list() may abort - * early due to a need of rescheduling. - */ - while (1) { - spin_lock(&journal->j_list_lock); - if (!journal->j_checkpoint_transactions) { - spin_unlock(&journal->j_list_lock); - break; - } - __jbd2_journal_clean_checkpoint_list(journal, true); - spin_unlock(&journal->j_list_lock); - cond_resched(); - } -} - -/* - * journal_remove_checkpoint: called after a buffer has been committed - * to disk (either by being write-back flushed to disk, or being - * committed to the log). - * - * We cannot safely clean a transaction out of the log until all of the - * buffer updates committed in that transaction have safely been stored - * elsewhere on disk. To achieve this, all of the buffers in a - * transaction need to be maintained on the transaction's checkpoint - * lists until they have been rewritten, at which point this function is - * called to remove the buffer from the existing transaction's - * checkpoint lists. - * - * The function returns 1 if it frees the transaction, 0 otherwise. - * The function can free jh and bh. - * - * This function is called with j_list_lock held. - */ -int __jbd2_journal_remove_checkpoint(struct journal_head *jh) -{ - struct transaction_chp_stats_s *stats; - transaction_t *transaction; - journal_t *journal; - int ret = 0; - - JBUFFER_TRACE(jh, "entry"); - - if ((transaction = jh->b_cp_transaction) == NULL) { - JBUFFER_TRACE(jh, "not on transaction"); - goto out; - } - journal = transaction->t_journal; - - JBUFFER_TRACE(jh, "removing from transaction"); - __buffer_unlink(jh); - jh->b_cp_transaction = NULL; - jbd2_journal_put_journal_head(jh); - - if (transaction->t_checkpoint_list != NULL || - transaction->t_checkpoint_io_list != NULL) - goto out; - - /* - * There is one special case to worry about: if we have just pulled the - * buffer off a running or committing transaction's checkpoing list, - * then even if the checkpoint list is empty, the transaction obviously - * cannot be dropped! - * - * The locking here around t_state is a bit sleazy. - * See the comment at the end of jbd2_journal_commit_transaction(). - */ - if (transaction->t_state != T_FINISHED) - goto out; - - /* OK, that was the last buffer for the transaction: we can now - safely remove this transaction from the log */ - stats = &transaction->t_chp_stats; - if (stats->cs_chp_time) - stats->cs_chp_time = jbd2_time_diff(stats->cs_chp_time, - jiffies); - trace_jbd2_checkpoint_stats(journal->j_fs_dev->bd_dev, - transaction->t_tid, stats); - - __jbd2_journal_drop_transaction(journal, transaction); - jbd2_journal_free_transaction(transaction); - ret = 1; -out: - return ret; -} - -/* - * journal_insert_checkpoint: put a committed buffer onto a checkpoint - * list so that we know when it is safe to clean the transaction out of - * the log. - * - * Called with the journal locked. - * Called with j_list_lock held. - */ -void __jbd2_journal_insert_checkpoint(struct journal_head *jh, - transaction_t *transaction) -{ - JBUFFER_TRACE(jh, "entry"); - J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jbddirty(jh2bh(jh))); - J_ASSERT_JH(jh, jh->b_cp_transaction == NULL); - - /* Get reference for checkpointing transaction */ - jbd2_journal_grab_journal_head(jh2bh(jh)); - jh->b_cp_transaction = transaction; - - if (!transaction->t_checkpoint_list) { - jh->b_cpnext = jh->b_cpprev = jh; - } else { - jh->b_cpnext = transaction->t_checkpoint_list; - jh->b_cpprev = transaction->t_checkpoint_list->b_cpprev; - jh->b_cpprev->b_cpnext = jh; - jh->b_cpnext->b_cpprev = jh; - } - transaction->t_checkpoint_list = jh; -} - -/* - * We've finished with this transaction structure: adios... - * - * The transaction must have no links except for the checkpoint by this - * point. - * - * Called with the journal locked. - * Called with j_list_lock held. - */ - -void __jbd2_journal_drop_transaction(journal_t *journal, transaction_t *transaction) -{ - assert_spin_locked(&journal->j_list_lock); - if (transaction->t_cpnext) { - transaction->t_cpnext->t_cpprev = transaction->t_cpprev; - transaction->t_cpprev->t_cpnext = transaction->t_cpnext; - if (journal->j_checkpoint_transactions == transaction) - journal->j_checkpoint_transactions = - transaction->t_cpnext; - if (journal->j_checkpoint_transactions == transaction) - journal->j_checkpoint_transactions = NULL; - } - - J_ASSERT(transaction->t_state == T_FINISHED); - J_ASSERT(transaction->t_buffers == NULL); - J_ASSERT(transaction->t_forget == NULL); - J_ASSERT(transaction->t_shadow_list == NULL); - J_ASSERT(transaction->t_checkpoint_list == NULL); - J_ASSERT(transaction->t_checkpoint_io_list == NULL); - J_ASSERT(atomic_read(&transaction->t_updates) == 0); - J_ASSERT(journal->j_committing_transaction != transaction); - J_ASSERT(journal->j_running_transaction != transaction); - - trace_jbd2_drop_transaction(journal, transaction); - - jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid); -} diff --git a/src/linux/fs/jbd2/commit.c b/src/linux/fs/jbd2/commit.c deleted file mode 100644 index 31f8ca0..0000000 --- a/src/linux/fs/jbd2/commit.c +++ /dev/null @@ -1,1138 +0,0 @@ -/* - * linux/fs/jbd2/commit.c - * - * Written by Stephen C. Tweedie , 1998 - * - * Copyright 1998 Red Hat corp --- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * Journal commit routines for the generic filesystem journaling code; - * part of the ext2fs journaling system. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * IO end handler for temporary buffer_heads handling writes to the journal. - */ -static void journal_end_buffer_io_sync(struct buffer_head *bh, int uptodate) -{ - struct buffer_head *orig_bh = bh->b_private; - - BUFFER_TRACE(bh, ""); - if (uptodate) - set_buffer_uptodate(bh); - else - clear_buffer_uptodate(bh); - if (orig_bh) { - clear_bit_unlock(BH_Shadow, &orig_bh->b_state); - smp_mb__after_atomic(); - wake_up_bit(&orig_bh->b_state, BH_Shadow); - } - unlock_buffer(bh); -} - -/* - * When an ext4 file is truncated, it is possible that some pages are not - * successfully freed, because they are attached to a committing transaction. - * After the transaction commits, these pages are left on the LRU, with no - * ->mapping, and with attached buffers. These pages are trivially reclaimable - * by the VM, but their apparent absence upsets the VM accounting, and it makes - * the numbers in /proc/meminfo look odd. - * - * So here, we have a buffer which has just come off the forget list. Look to - * see if we can strip all buffers from the backing page. - * - * Called under lock_journal(), and possibly under journal_datalist_lock. The - * caller provided us with a ref against the buffer, and we drop that here. - */ -static void release_buffer_page(struct buffer_head *bh) -{ - struct page *page; - - if (buffer_dirty(bh)) - goto nope; - if (atomic_read(&bh->b_count) != 1) - goto nope; - page = bh->b_page; - if (!page) - goto nope; - if (page->mapping) - goto nope; - - /* OK, it's a truncated page */ - if (!trylock_page(page)) - goto nope; - - get_page(page); - __brelse(bh); - try_to_free_buffers(page); - unlock_page(page); - put_page(page); - return; - -nope: - __brelse(bh); -} - -static void jbd2_commit_block_csum_set(journal_t *j, struct buffer_head *bh) -{ - struct commit_header *h; - __u32 csum; - - if (!jbd2_journal_has_csum_v2or3(j)) - return; - - h = (struct commit_header *)(bh->b_data); - h->h_chksum_type = 0; - h->h_chksum_size = 0; - h->h_chksum[0] = 0; - csum = jbd2_chksum(j, j->j_csum_seed, bh->b_data, j->j_blocksize); - h->h_chksum[0] = cpu_to_be32(csum); -} - -/* - * Done it all: now submit the commit record. We should have - * cleaned up our previous buffers by now, so if we are in abort - * mode we can now just skip the rest of the journal write - * entirely. - * - * Returns 1 if the journal needs to be aborted or 0 on success - */ -static int journal_submit_commit_record(journal_t *journal, - transaction_t *commit_transaction, - struct buffer_head **cbh, - __u32 crc32_sum) -{ - struct commit_header *tmp; - struct buffer_head *bh; - int ret; - struct timespec64 now = current_kernel_time64(); - - *cbh = NULL; - - if (is_journal_aborted(journal)) - return 0; - - bh = jbd2_journal_get_descriptor_buffer(commit_transaction, - JBD2_COMMIT_BLOCK); - if (!bh) - return 1; - - tmp = (struct commit_header *)bh->b_data; - tmp->h_commit_sec = cpu_to_be64(now.tv_sec); - tmp->h_commit_nsec = cpu_to_be32(now.tv_nsec); - - if (jbd2_has_feature_checksum(journal)) { - tmp->h_chksum_type = JBD2_CRC32_CHKSUM; - tmp->h_chksum_size = JBD2_CRC32_CHKSUM_SIZE; - tmp->h_chksum[0] = cpu_to_be32(crc32_sum); - } - jbd2_commit_block_csum_set(journal, bh); - - BUFFER_TRACE(bh, "submit commit block"); - lock_buffer(bh); - clear_buffer_dirty(bh); - set_buffer_uptodate(bh); - bh->b_end_io = journal_end_buffer_io_sync; - - if (journal->j_flags & JBD2_BARRIER && - !jbd2_has_feature_async_commit(journal)) - ret = submit_bh(REQ_OP_WRITE, WRITE_SYNC | WRITE_FLUSH_FUA, bh); - else - ret = submit_bh(REQ_OP_WRITE, WRITE_SYNC, bh); - - *cbh = bh; - return ret; -} - -/* - * This function along with journal_submit_commit_record - * allows to write the commit record asynchronously. - */ -static int journal_wait_on_commit_record(journal_t *journal, - struct buffer_head *bh) -{ - int ret = 0; - - clear_buffer_dirty(bh); - wait_on_buffer(bh); - - if (unlikely(!buffer_uptodate(bh))) - ret = -EIO; - put_bh(bh); /* One for getblk() */ - - return ret; -} - -/* - * write the filemap data using writepage() address_space_operations. - * We don't do block allocation here even for delalloc. We don't - * use writepages() because with dealyed allocation we may be doing - * block allocation in writepages(). - */ -static int journal_submit_inode_data_buffers(struct address_space *mapping) -{ - int ret; - struct writeback_control wbc = { - .sync_mode = WB_SYNC_ALL, - .nr_to_write = mapping->nrpages * 2, - .range_start = 0, - .range_end = i_size_read(mapping->host), - }; - - ret = generic_writepages(mapping, &wbc); - return ret; -} - -/* - * Submit all the data buffers of inode associated with the transaction to - * disk. - * - * We are in a committing transaction. Therefore no new inode can be added to - * our inode list. We use JI_COMMIT_RUNNING flag to protect inode we currently - * operate on from being released while we write out pages. - */ -static int journal_submit_data_buffers(journal_t *journal, - transaction_t *commit_transaction) -{ - struct jbd2_inode *jinode; - int err, ret = 0; - struct address_space *mapping; - - spin_lock(&journal->j_list_lock); - list_for_each_entry(jinode, &commit_transaction->t_inode_list, i_list) { - if (!(jinode->i_flags & JI_WRITE_DATA)) - continue; - mapping = jinode->i_vfs_inode->i_mapping; - jinode->i_flags |= JI_COMMIT_RUNNING; - spin_unlock(&journal->j_list_lock); - /* - * submit the inode data buffers. We use writepage - * instead of writepages. Because writepages can do - * block allocation with delalloc. We need to write - * only allocated blocks here. - */ - trace_jbd2_submit_inode_data(jinode->i_vfs_inode); - err = journal_submit_inode_data_buffers(mapping); - if (!ret) - ret = err; - spin_lock(&journal->j_list_lock); - J_ASSERT(jinode->i_transaction == commit_transaction); - jinode->i_flags &= ~JI_COMMIT_RUNNING; - smp_mb(); - wake_up_bit(&jinode->i_flags, __JI_COMMIT_RUNNING); - } - spin_unlock(&journal->j_list_lock); - return ret; -} - -/* - * Wait for data submitted for writeout, refile inodes to proper - * transaction if needed. - * - */ -static int journal_finish_inode_data_buffers(journal_t *journal, - transaction_t *commit_transaction) -{ - struct jbd2_inode *jinode, *next_i; - int err, ret = 0; - - /* For locking, see the comment in journal_submit_data_buffers() */ - spin_lock(&journal->j_list_lock); - list_for_each_entry(jinode, &commit_transaction->t_inode_list, i_list) { - if (!(jinode->i_flags & JI_WAIT_DATA)) - continue; - jinode->i_flags |= JI_COMMIT_RUNNING; - spin_unlock(&journal->j_list_lock); - err = filemap_fdatawait(jinode->i_vfs_inode->i_mapping); - if (err) { - /* - * Because AS_EIO is cleared by - * filemap_fdatawait_range(), set it again so - * that user process can get -EIO from fsync(). - */ - mapping_set_error(jinode->i_vfs_inode->i_mapping, -EIO); - - if (!ret) - ret = err; - } - spin_lock(&journal->j_list_lock); - jinode->i_flags &= ~JI_COMMIT_RUNNING; - smp_mb(); - wake_up_bit(&jinode->i_flags, __JI_COMMIT_RUNNING); - } - - /* Now refile inode to proper lists */ - list_for_each_entry_safe(jinode, next_i, - &commit_transaction->t_inode_list, i_list) { - list_del(&jinode->i_list); - if (jinode->i_next_transaction) { - jinode->i_transaction = jinode->i_next_transaction; - jinode->i_next_transaction = NULL; - list_add(&jinode->i_list, - &jinode->i_transaction->t_inode_list); - } else { - jinode->i_transaction = NULL; - } - } - spin_unlock(&journal->j_list_lock); - - return ret; -} - -static __u32 jbd2_checksum_data(__u32 crc32_sum, struct buffer_head *bh) -{ - struct page *page = bh->b_page; - char *addr; - __u32 checksum; - - addr = kmap_atomic(page); - checksum = crc32_be(crc32_sum, - (void *)(addr + offset_in_page(bh->b_data)), bh->b_size); - kunmap_atomic(addr); - - return checksum; -} - -static void write_tag_block(journal_t *j, journal_block_tag_t *tag, - unsigned long long block) -{ - tag->t_blocknr = cpu_to_be32(block & (u32)~0); - if (jbd2_has_feature_64bit(j)) - tag->t_blocknr_high = cpu_to_be32((block >> 31) >> 1); -} - -static void jbd2_block_tag_csum_set(journal_t *j, journal_block_tag_t *tag, - struct buffer_head *bh, __u32 sequence) -{ - journal_block_tag3_t *tag3 = (journal_block_tag3_t *)tag; - struct page *page = bh->b_page; - __u8 *addr; - __u32 csum32; - __be32 seq; - - if (!jbd2_journal_has_csum_v2or3(j)) - return; - - seq = cpu_to_be32(sequence); - addr = kmap_atomic(page); - csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&seq, sizeof(seq)); - csum32 = jbd2_chksum(j, csum32, addr + offset_in_page(bh->b_data), - bh->b_size); - kunmap_atomic(addr); - - if (jbd2_has_feature_csum3(j)) - tag3->t_checksum = cpu_to_be32(csum32); - else - tag->t_checksum = cpu_to_be16(csum32); -} -/* - * jbd2_journal_commit_transaction - * - * The primary function for committing a transaction to the log. This - * function is called by the journal thread to begin a complete commit. - */ -void jbd2_journal_commit_transaction(journal_t *journal) -{ - struct transaction_stats_s stats; - transaction_t *commit_transaction; - struct journal_head *jh; - struct buffer_head *descriptor; - struct buffer_head **wbuf = journal->j_wbuf; - int bufs; - int flags; - int err; - unsigned long long blocknr; - ktime_t start_time; - u64 commit_time; - char *tagp = NULL; - journal_block_tag_t *tag = NULL; - int space_left = 0; - int first_tag = 0; - int tag_flag; - int i; - int tag_bytes = journal_tag_bytes(journal); - struct buffer_head *cbh = NULL; /* For transactional checksums */ - __u32 crc32_sum = ~0; - struct blk_plug plug; - /* Tail of the journal */ - unsigned long first_block; - tid_t first_tid; - int update_tail; - int csum_size = 0; - LIST_HEAD(io_bufs); - LIST_HEAD(log_bufs); - - if (jbd2_journal_has_csum_v2or3(journal)) - csum_size = sizeof(struct jbd2_journal_block_tail); - - /* - * First job: lock down the current transaction and wait for - * all outstanding updates to complete. - */ - - /* Do we need to erase the effects of a prior jbd2_journal_flush? */ - if (journal->j_flags & JBD2_FLUSHED) { - jbd_debug(3, "super block updated\n"); - mutex_lock(&journal->j_checkpoint_mutex); - /* - * We hold j_checkpoint_mutex so tail cannot change under us. - * We don't need any special data guarantees for writing sb - * since journal is empty and it is ok for write to be - * flushed only with transaction commit. - */ - jbd2_journal_update_sb_log_tail(journal, - journal->j_tail_sequence, - journal->j_tail, - WRITE_SYNC); - mutex_unlock(&journal->j_checkpoint_mutex); - } else { - jbd_debug(3, "superblock not updated\n"); - } - - J_ASSERT(journal->j_running_transaction != NULL); - J_ASSERT(journal->j_committing_transaction == NULL); - - commit_transaction = journal->j_running_transaction; - - trace_jbd2_start_commit(journal, commit_transaction); - jbd_debug(1, "JBD2: starting commit of transaction %d\n", - commit_transaction->t_tid); - - write_lock(&journal->j_state_lock); - J_ASSERT(commit_transaction->t_state == T_RUNNING); - commit_transaction->t_state = T_LOCKED; - - trace_jbd2_commit_locking(journal, commit_transaction); - stats.run.rs_wait = commit_transaction->t_max_wait; - stats.run.rs_request_delay = 0; - stats.run.rs_locked = jiffies; - if (commit_transaction->t_requested) - stats.run.rs_request_delay = - jbd2_time_diff(commit_transaction->t_requested, - stats.run.rs_locked); - stats.run.rs_running = jbd2_time_diff(commit_transaction->t_start, - stats.run.rs_locked); - - spin_lock(&commit_transaction->t_handle_lock); - while (atomic_read(&commit_transaction->t_updates)) { - DEFINE_WAIT(wait); - - prepare_to_wait(&journal->j_wait_updates, &wait, - TASK_UNINTERRUPTIBLE); - if (atomic_read(&commit_transaction->t_updates)) { - spin_unlock(&commit_transaction->t_handle_lock); - write_unlock(&journal->j_state_lock); - schedule(); - write_lock(&journal->j_state_lock); - spin_lock(&commit_transaction->t_handle_lock); - } - finish_wait(&journal->j_wait_updates, &wait); - } - spin_unlock(&commit_transaction->t_handle_lock); - - J_ASSERT (atomic_read(&commit_transaction->t_outstanding_credits) <= - journal->j_max_transaction_buffers); - - /* - * First thing we are allowed to do is to discard any remaining - * BJ_Reserved buffers. Note, it is _not_ permissible to assume - * that there are no such buffers: if a large filesystem - * operation like a truncate needs to split itself over multiple - * transactions, then it may try to do a jbd2_journal_restart() while - * there are still BJ_Reserved buffers outstanding. These must - * be released cleanly from the current transaction. - * - * In this case, the filesystem must still reserve write access - * again before modifying the buffer in the new transaction, but - * we do not require it to remember exactly which old buffers it - * has reserved. This is consistent with the existing behaviour - * that multiple jbd2_journal_get_write_access() calls to the same - * buffer are perfectly permissible. - */ - while (commit_transaction->t_reserved_list) { - jh = commit_transaction->t_reserved_list; - JBUFFER_TRACE(jh, "reserved, unused: refile"); - /* - * A jbd2_journal_get_undo_access()+jbd2_journal_release_buffer() may - * leave undo-committed data. - */ - if (jh->b_committed_data) { - struct buffer_head *bh = jh2bh(jh); - - jbd_lock_bh_state(bh); - jbd2_free(jh->b_committed_data, bh->b_size); - jh->b_committed_data = NULL; - jbd_unlock_bh_state(bh); - } - jbd2_journal_refile_buffer(journal, jh); - } - - /* - * Now try to drop any written-back buffers from the journal's - * checkpoint lists. We do this *before* commit because it potentially - * frees some memory - */ - spin_lock(&journal->j_list_lock); - __jbd2_journal_clean_checkpoint_list(journal, false); - spin_unlock(&journal->j_list_lock); - - jbd_debug(3, "JBD2: commit phase 1\n"); - - /* - * Clear revoked flag to reflect there is no revoked buffers - * in the next transaction which is going to be started. - */ - jbd2_clear_buffer_revoked_flags(journal); - - /* - * Switch to a new revoke table. - */ - jbd2_journal_switch_revoke_table(journal); - - /* - * Reserved credits cannot be claimed anymore, free them - */ - atomic_sub(atomic_read(&journal->j_reserved_credits), - &commit_transaction->t_outstanding_credits); - - trace_jbd2_commit_flushing(journal, commit_transaction); - stats.run.rs_flushing = jiffies; - stats.run.rs_locked = jbd2_time_diff(stats.run.rs_locked, - stats.run.rs_flushing); - - commit_transaction->t_state = T_FLUSH; - journal->j_committing_transaction = commit_transaction; - journal->j_running_transaction = NULL; - start_time = ktime_get(); - commit_transaction->t_log_start = journal->j_head; - wake_up(&journal->j_wait_transaction_locked); - write_unlock(&journal->j_state_lock); - - jbd_debug(3, "JBD2: commit phase 2a\n"); - - /* - * Now start flushing things to disk, in the order they appear - * on the transaction lists. Data blocks go first. - */ - err = journal_submit_data_buffers(journal, commit_transaction); - if (err) - jbd2_journal_abort(journal, err); - - blk_start_plug(&plug); - jbd2_journal_write_revoke_records(commit_transaction, &log_bufs); - - jbd_debug(3, "JBD2: commit phase 2b\n"); - - /* - * Way to go: we have now written out all of the data for a - * transaction! Now comes the tricky part: we need to write out - * metadata. Loop over the transaction's entire buffer list: - */ - write_lock(&journal->j_state_lock); - commit_transaction->t_state = T_COMMIT; - write_unlock(&journal->j_state_lock); - - trace_jbd2_commit_logging(journal, commit_transaction); - stats.run.rs_logging = jiffies; - stats.run.rs_flushing = jbd2_time_diff(stats.run.rs_flushing, - stats.run.rs_logging); - stats.run.rs_blocks = - atomic_read(&commit_transaction->t_outstanding_credits); - stats.run.rs_blocks_logged = 0; - - J_ASSERT(commit_transaction->t_nr_buffers <= - atomic_read(&commit_transaction->t_outstanding_credits)); - - err = 0; - bufs = 0; - descriptor = NULL; - while (commit_transaction->t_buffers) { - - /* Find the next buffer to be journaled... */ - - jh = commit_transaction->t_buffers; - - /* If we're in abort mode, we just un-journal the buffer and - release it. */ - - if (is_journal_aborted(journal)) { - clear_buffer_jbddirty(jh2bh(jh)); - JBUFFER_TRACE(jh, "journal is aborting: refile"); - jbd2_buffer_abort_trigger(jh, - jh->b_frozen_data ? - jh->b_frozen_triggers : - jh->b_triggers); - jbd2_journal_refile_buffer(journal, jh); - /* If that was the last one, we need to clean up - * any descriptor buffers which may have been - * already allocated, even if we are now - * aborting. */ - if (!commit_transaction->t_buffers) - goto start_journal_io; - continue; - } - - /* Make sure we have a descriptor block in which to - record the metadata buffer. */ - - if (!descriptor) { - J_ASSERT (bufs == 0); - - jbd_debug(4, "JBD2: get descriptor\n"); - - descriptor = jbd2_journal_get_descriptor_buffer( - commit_transaction, - JBD2_DESCRIPTOR_BLOCK); - if (!descriptor) { - jbd2_journal_abort(journal, -EIO); - continue; - } - - jbd_debug(4, "JBD2: got buffer %llu (%p)\n", - (unsigned long long)descriptor->b_blocknr, - descriptor->b_data); - tagp = &descriptor->b_data[sizeof(journal_header_t)]; - space_left = descriptor->b_size - - sizeof(journal_header_t); - first_tag = 1; - set_buffer_jwrite(descriptor); - set_buffer_dirty(descriptor); - wbuf[bufs++] = descriptor; - - /* Record it so that we can wait for IO - completion later */ - BUFFER_TRACE(descriptor, "ph3: file as descriptor"); - jbd2_file_log_bh(&log_bufs, descriptor); - } - - /* Where is the buffer to be written? */ - - err = jbd2_journal_next_log_block(journal, &blocknr); - /* If the block mapping failed, just abandon the buffer - and repeat this loop: we'll fall into the - refile-on-abort condition above. */ - if (err) { - jbd2_journal_abort(journal, err); - continue; - } - - /* - * start_this_handle() uses t_outstanding_credits to determine - * the free space in the log, but this counter is changed - * by jbd2_journal_next_log_block() also. - */ - atomic_dec(&commit_transaction->t_outstanding_credits); - - /* Bump b_count to prevent truncate from stumbling over - the shadowed buffer! @@@ This can go if we ever get - rid of the shadow pairing of buffers. */ - atomic_inc(&jh2bh(jh)->b_count); - - /* - * Make a temporary IO buffer with which to write it out - * (this will requeue the metadata buffer to BJ_Shadow). - */ - set_bit(BH_JWrite, &jh2bh(jh)->b_state); - JBUFFER_TRACE(jh, "ph3: write metadata"); - flags = jbd2_journal_write_metadata_buffer(commit_transaction, - jh, &wbuf[bufs], blocknr); - if (flags < 0) { - jbd2_journal_abort(journal, flags); - continue; - } - jbd2_file_log_bh(&io_bufs, wbuf[bufs]); - - /* Record the new block's tag in the current descriptor - buffer */ - - tag_flag = 0; - if (flags & 1) - tag_flag |= JBD2_FLAG_ESCAPE; - if (!first_tag) - tag_flag |= JBD2_FLAG_SAME_UUID; - - tag = (journal_block_tag_t *) tagp; - write_tag_block(journal, tag, jh2bh(jh)->b_blocknr); - tag->t_flags = cpu_to_be16(tag_flag); - jbd2_block_tag_csum_set(journal, tag, wbuf[bufs], - commit_transaction->t_tid); - tagp += tag_bytes; - space_left -= tag_bytes; - bufs++; - - if (first_tag) { - memcpy (tagp, journal->j_uuid, 16); - tagp += 16; - space_left -= 16; - first_tag = 0; - } - - /* If there's no more to do, or if the descriptor is full, - let the IO rip! */ - - if (bufs == journal->j_wbufsize || - commit_transaction->t_buffers == NULL || - space_left < tag_bytes + 16 + csum_size) { - - jbd_debug(4, "JBD2: Submit %d IOs\n", bufs); - - /* Write an end-of-descriptor marker before - submitting the IOs. "tag" still points to - the last tag we set up. */ - - tag->t_flags |= cpu_to_be16(JBD2_FLAG_LAST_TAG); - - jbd2_descriptor_block_csum_set(journal, descriptor); -start_journal_io: - for (i = 0; i < bufs; i++) { - struct buffer_head *bh = wbuf[i]; - /* - * Compute checksum. - */ - if (jbd2_has_feature_checksum(journal)) { - crc32_sum = - jbd2_checksum_data(crc32_sum, bh); - } - - lock_buffer(bh); - clear_buffer_dirty(bh); - set_buffer_uptodate(bh); - bh->b_end_io = journal_end_buffer_io_sync; - submit_bh(REQ_OP_WRITE, WRITE_SYNC, bh); - } - cond_resched(); - stats.run.rs_blocks_logged += bufs; - - /* Force a new descriptor to be generated next - time round the loop. */ - descriptor = NULL; - bufs = 0; - } - } - - err = journal_finish_inode_data_buffers(journal, commit_transaction); - if (err) { - printk(KERN_WARNING - "JBD2: Detected IO errors while flushing file data " - "on %s\n", journal->j_devname); - if (journal->j_flags & JBD2_ABORT_ON_SYNCDATA_ERR) - jbd2_journal_abort(journal, err); - err = 0; - } - - /* - * Get current oldest transaction in the log before we issue flush - * to the filesystem device. After the flush we can be sure that - * blocks of all older transactions are checkpointed to persistent - * storage and we will be safe to update journal start in the - * superblock with the numbers we get here. - */ - update_tail = - jbd2_journal_get_log_tail(journal, &first_tid, &first_block); - - write_lock(&journal->j_state_lock); - if (update_tail) { - long freed = first_block - journal->j_tail; - - if (first_block < journal->j_tail) - freed += journal->j_last - journal->j_first; - /* Update tail only if we free significant amount of space */ - if (freed < journal->j_maxlen / 4) - update_tail = 0; - } - J_ASSERT(commit_transaction->t_state == T_COMMIT); - commit_transaction->t_state = T_COMMIT_DFLUSH; - write_unlock(&journal->j_state_lock); - - /* - * If the journal is not located on the file system device, - * then we must flush the file system device before we issue - * the commit record - */ - if (commit_transaction->t_need_data_flush && - (journal->j_fs_dev != journal->j_dev) && - (journal->j_flags & JBD2_BARRIER)) - blkdev_issue_flush(journal->j_fs_dev, GFP_NOFS, NULL); - - /* Done it all: now write the commit record asynchronously. */ - if (jbd2_has_feature_async_commit(journal)) { - err = journal_submit_commit_record(journal, commit_transaction, - &cbh, crc32_sum); - if (err) - __jbd2_journal_abort_hard(journal); - } - - blk_finish_plug(&plug); - - /* Lo and behold: we have just managed to send a transaction to - the log. Before we can commit it, wait for the IO so far to - complete. Control buffers being written are on the - transaction's t_log_list queue, and metadata buffers are on - the io_bufs list. - - Wait for the buffers in reverse order. That way we are - less likely to be woken up until all IOs have completed, and - so we incur less scheduling load. - */ - - jbd_debug(3, "JBD2: commit phase 3\n"); - - while (!list_empty(&io_bufs)) { - struct buffer_head *bh = list_entry(io_bufs.prev, - struct buffer_head, - b_assoc_buffers); - - wait_on_buffer(bh); - cond_resched(); - - if (unlikely(!buffer_uptodate(bh))) - err = -EIO; - jbd2_unfile_log_bh(bh); - - /* - * The list contains temporary buffer heads created by - * jbd2_journal_write_metadata_buffer(). - */ - BUFFER_TRACE(bh, "dumping temporary bh"); - __brelse(bh); - J_ASSERT_BH(bh, atomic_read(&bh->b_count) == 0); - free_buffer_head(bh); - - /* We also have to refile the corresponding shadowed buffer */ - jh = commit_transaction->t_shadow_list->b_tprev; - bh = jh2bh(jh); - clear_buffer_jwrite(bh); - J_ASSERT_BH(bh, buffer_jbddirty(bh)); - J_ASSERT_BH(bh, !buffer_shadow(bh)); - - /* The metadata is now released for reuse, but we need - to remember it against this transaction so that when - we finally commit, we can do any checkpointing - required. */ - JBUFFER_TRACE(jh, "file as BJ_Forget"); - jbd2_journal_file_buffer(jh, commit_transaction, BJ_Forget); - JBUFFER_TRACE(jh, "brelse shadowed buffer"); - __brelse(bh); - } - - J_ASSERT (commit_transaction->t_shadow_list == NULL); - - jbd_debug(3, "JBD2: commit phase 4\n"); - - /* Here we wait for the revoke record and descriptor record buffers */ - while (!list_empty(&log_bufs)) { - struct buffer_head *bh; - - bh = list_entry(log_bufs.prev, struct buffer_head, b_assoc_buffers); - wait_on_buffer(bh); - cond_resched(); - - if (unlikely(!buffer_uptodate(bh))) - err = -EIO; - - BUFFER_TRACE(bh, "ph5: control buffer writeout done: unfile"); - clear_buffer_jwrite(bh); - jbd2_unfile_log_bh(bh); - __brelse(bh); /* One for getblk */ - /* AKPM: bforget here */ - } - - if (err) - jbd2_journal_abort(journal, err); - - jbd_debug(3, "JBD2: commit phase 5\n"); - write_lock(&journal->j_state_lock); - J_ASSERT(commit_transaction->t_state == T_COMMIT_DFLUSH); - commit_transaction->t_state = T_COMMIT_JFLUSH; - write_unlock(&journal->j_state_lock); - - if (!jbd2_has_feature_async_commit(journal)) { - err = journal_submit_commit_record(journal, commit_transaction, - &cbh, crc32_sum); - if (err) - __jbd2_journal_abort_hard(journal); - } - if (cbh) - err = journal_wait_on_commit_record(journal, cbh); - if (jbd2_has_feature_async_commit(journal) && - journal->j_flags & JBD2_BARRIER) { - blkdev_issue_flush(journal->j_dev, GFP_NOFS, NULL); - } - - if (err) - jbd2_journal_abort(journal, err); - - /* - * Now disk caches for filesystem device are flushed so we are safe to - * erase checkpointed transactions from the log by updating journal - * superblock. - */ - if (update_tail) - jbd2_update_log_tail(journal, first_tid, first_block); - - /* End of a transaction! Finally, we can do checkpoint - processing: any buffers committed as a result of this - transaction can be removed from any checkpoint list it was on - before. */ - - jbd_debug(3, "JBD2: commit phase 6\n"); - - J_ASSERT(list_empty(&commit_transaction->t_inode_list)); - J_ASSERT(commit_transaction->t_buffers == NULL); - J_ASSERT(commit_transaction->t_checkpoint_list == NULL); - J_ASSERT(commit_transaction->t_shadow_list == NULL); - -restart_loop: - /* - * As there are other places (journal_unmap_buffer()) adding buffers - * to this list we have to be careful and hold the j_list_lock. - */ - spin_lock(&journal->j_list_lock); - while (commit_transaction->t_forget) { - transaction_t *cp_transaction; - struct buffer_head *bh; - int try_to_free = 0; - - jh = commit_transaction->t_forget; - spin_unlock(&journal->j_list_lock); - bh = jh2bh(jh); - /* - * Get a reference so that bh cannot be freed before we are - * done with it. - */ - get_bh(bh); - jbd_lock_bh_state(bh); - J_ASSERT_JH(jh, jh->b_transaction == commit_transaction); - - /* - * If there is undo-protected committed data against - * this buffer, then we can remove it now. If it is a - * buffer needing such protection, the old frozen_data - * field now points to a committed version of the - * buffer, so rotate that field to the new committed - * data. - * - * Otherwise, we can just throw away the frozen data now. - * - * We also know that the frozen data has already fired - * its triggers if they exist, so we can clear that too. - */ - if (jh->b_committed_data) { - jbd2_free(jh->b_committed_data, bh->b_size); - jh->b_committed_data = NULL; - if (jh->b_frozen_data) { - jh->b_committed_data = jh->b_frozen_data; - jh->b_frozen_data = NULL; - jh->b_frozen_triggers = NULL; - } - } else if (jh->b_frozen_data) { - jbd2_free(jh->b_frozen_data, bh->b_size); - jh->b_frozen_data = NULL; - jh->b_frozen_triggers = NULL; - } - - spin_lock(&journal->j_list_lock); - cp_transaction = jh->b_cp_transaction; - if (cp_transaction) { - JBUFFER_TRACE(jh, "remove from old cp transaction"); - cp_transaction->t_chp_stats.cs_dropped++; - __jbd2_journal_remove_checkpoint(jh); - } - - /* Only re-checkpoint the buffer_head if it is marked - * dirty. If the buffer was added to the BJ_Forget list - * by jbd2_journal_forget, it may no longer be dirty and - * there's no point in keeping a checkpoint record for - * it. */ - - /* - * A buffer which has been freed while still being journaled by - * a previous transaction. - */ - if (buffer_freed(bh)) { - /* - * If the running transaction is the one containing - * "add to orphan" operation (b_next_transaction != - * NULL), we have to wait for that transaction to - * commit before we can really get rid of the buffer. - * So just clear b_modified to not confuse transaction - * credit accounting and refile the buffer to - * BJ_Forget of the running transaction. If the just - * committed transaction contains "add to orphan" - * operation, we can completely invalidate the buffer - * now. We are rather through in that since the - * buffer may be still accessible when blocksize < - * pagesize and it is attached to the last partial - * page. - */ - jh->b_modified = 0; - if (!jh->b_next_transaction) { - clear_buffer_freed(bh); - clear_buffer_jbddirty(bh); - clear_buffer_mapped(bh); - clear_buffer_new(bh); - clear_buffer_req(bh); - bh->b_bdev = NULL; - } - } - - if (buffer_jbddirty(bh)) { - JBUFFER_TRACE(jh, "add to new checkpointing trans"); - __jbd2_journal_insert_checkpoint(jh, commit_transaction); - if (is_journal_aborted(journal)) - clear_buffer_jbddirty(bh); - } else { - J_ASSERT_BH(bh, !buffer_dirty(bh)); - /* - * The buffer on BJ_Forget list and not jbddirty means - * it has been freed by this transaction and hence it - * could not have been reallocated until this - * transaction has committed. *BUT* it could be - * reallocated once we have written all the data to - * disk and before we process the buffer on BJ_Forget - * list. - */ - if (!jh->b_next_transaction) - try_to_free = 1; - } - JBUFFER_TRACE(jh, "refile or unfile buffer"); - __jbd2_journal_refile_buffer(jh); - jbd_unlock_bh_state(bh); - if (try_to_free) - release_buffer_page(bh); /* Drops bh reference */ - else - __brelse(bh); - cond_resched_lock(&journal->j_list_lock); - } - spin_unlock(&journal->j_list_lock); - /* - * This is a bit sleazy. We use j_list_lock to protect transition - * of a transaction into T_FINISHED state and calling - * __jbd2_journal_drop_transaction(). Otherwise we could race with - * other checkpointing code processing the transaction... - */ - write_lock(&journal->j_state_lock); - spin_lock(&journal->j_list_lock); - /* - * Now recheck if some buffers did not get attached to the transaction - * while the lock was dropped... - */ - if (commit_transaction->t_forget) { - spin_unlock(&journal->j_list_lock); - write_unlock(&journal->j_state_lock); - goto restart_loop; - } - - /* Add the transaction to the checkpoint list - * __journal_remove_checkpoint() can not destroy transaction - * under us because it is not marked as T_FINISHED yet */ - if (journal->j_checkpoint_transactions == NULL) { - journal->j_checkpoint_transactions = commit_transaction; - commit_transaction->t_cpnext = commit_transaction; - commit_transaction->t_cpprev = commit_transaction; - } else { - commit_transaction->t_cpnext = - journal->j_checkpoint_transactions; - commit_transaction->t_cpprev = - commit_transaction->t_cpnext->t_cpprev; - commit_transaction->t_cpnext->t_cpprev = - commit_transaction; - commit_transaction->t_cpprev->t_cpnext = - commit_transaction; - } - spin_unlock(&journal->j_list_lock); - - /* Done with this transaction! */ - - jbd_debug(3, "JBD2: commit phase 7\n"); - - J_ASSERT(commit_transaction->t_state == T_COMMIT_JFLUSH); - - commit_transaction->t_start = jiffies; - stats.run.rs_logging = jbd2_time_diff(stats.run.rs_logging, - commit_transaction->t_start); - - /* - * File the transaction statistics - */ - stats.ts_tid = commit_transaction->t_tid; - stats.run.rs_handle_count = - atomic_read(&commit_transaction->t_handle_count); - trace_jbd2_run_stats(journal->j_fs_dev->bd_dev, - commit_transaction->t_tid, &stats.run); - stats.ts_requested = (commit_transaction->t_requested) ? 1 : 0; - - commit_transaction->t_state = T_COMMIT_CALLBACK; - J_ASSERT(commit_transaction == journal->j_committing_transaction); - journal->j_commit_sequence = commit_transaction->t_tid; - journal->j_committing_transaction = NULL; - commit_time = ktime_to_ns(ktime_sub(ktime_get(), start_time)); - - /* - * weight the commit time higher than the average time so we don't - * react too strongly to vast changes in the commit time - */ - if (likely(journal->j_average_commit_time)) - journal->j_average_commit_time = (commit_time + - journal->j_average_commit_time*3) / 4; - else - journal->j_average_commit_time = commit_time; - - write_unlock(&journal->j_state_lock); - - if (journal->j_commit_callback) - journal->j_commit_callback(journal, commit_transaction); - - trace_jbd2_end_commit(journal, commit_transaction); - jbd_debug(1, "JBD2: commit %d complete, head %d\n", - journal->j_commit_sequence, journal->j_tail_sequence); - - write_lock(&journal->j_state_lock); - spin_lock(&journal->j_list_lock); - commit_transaction->t_state = T_FINISHED; - /* Check if the transaction can be dropped now that we are finished */ - if (commit_transaction->t_checkpoint_list == NULL && - commit_transaction->t_checkpoint_io_list == NULL) { - __jbd2_journal_drop_transaction(journal, commit_transaction); - jbd2_journal_free_transaction(commit_transaction); - } - spin_unlock(&journal->j_list_lock); - write_unlock(&journal->j_state_lock); - wake_up(&journal->j_wait_done_commit); - - /* - * Calculate overall stats - */ - spin_lock(&journal->j_history_lock); - journal->j_stats.ts_tid++; - journal->j_stats.ts_requested += stats.ts_requested; - journal->j_stats.run.rs_wait += stats.run.rs_wait; - journal->j_stats.run.rs_request_delay += stats.run.rs_request_delay; - journal->j_stats.run.rs_running += stats.run.rs_running; - journal->j_stats.run.rs_locked += stats.run.rs_locked; - journal->j_stats.run.rs_flushing += stats.run.rs_flushing; - journal->j_stats.run.rs_logging += stats.run.rs_logging; - journal->j_stats.run.rs_handle_count += stats.run.rs_handle_count; - journal->j_stats.run.rs_blocks += stats.run.rs_blocks; - journal->j_stats.run.rs_blocks_logged += stats.run.rs_blocks_logged; - spin_unlock(&journal->j_history_lock); -} diff --git a/src/linux/fs/jbd2/journal.c b/src/linux/fs/jbd2/journal.c deleted file mode 100644 index 927da49..0000000 --- a/src/linux/fs/jbd2/journal.c +++ /dev/null @@ -1,2678 +0,0 @@ -/* - * linux/fs/jbd2/journal.c - * - * Written by Stephen C. Tweedie , 1998 - * - * Copyright 1998 Red Hat corp --- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * Generic filesystem journal-writing code; part of the ext2fs - * journaling system. - * - * This file manages journals: areas of disk reserved for logging - * transactional updates. This includes the kernel journaling thread - * which is responsible for scheduling updates to the log. - * - * We do not actually manage the physical storage of the journal in this - * file: that is left to a per-journal policy function, which allows us - * to store the journal within a filesystem-specified area for ext2 - * journaling (ext2 can use a reserved inode for storing the log). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CREATE_TRACE_POINTS -#include - -#include -#include - -#ifdef CONFIG_JBD2_DEBUG -ushort jbd2_journal_enable_debug __read_mostly; -EXPORT_SYMBOL(jbd2_journal_enable_debug); - -module_param_named(jbd2_debug, jbd2_journal_enable_debug, ushort, 0644); -MODULE_PARM_DESC(jbd2_debug, "Debugging level for jbd2"); -#endif - -EXPORT_SYMBOL(jbd2_journal_extend); -EXPORT_SYMBOL(jbd2_journal_stop); -EXPORT_SYMBOL(jbd2_journal_lock_updates); -EXPORT_SYMBOL(jbd2_journal_unlock_updates); -EXPORT_SYMBOL(jbd2_journal_get_write_access); -EXPORT_SYMBOL(jbd2_journal_get_create_access); -EXPORT_SYMBOL(jbd2_journal_get_undo_access); -EXPORT_SYMBOL(jbd2_journal_set_triggers); -EXPORT_SYMBOL(jbd2_journal_dirty_metadata); -EXPORT_SYMBOL(jbd2_journal_forget); -#if 0 -EXPORT_SYMBOL(journal_sync_buffer); -#endif -EXPORT_SYMBOL(jbd2_journal_flush); -EXPORT_SYMBOL(jbd2_journal_revoke); - -EXPORT_SYMBOL(jbd2_journal_init_dev); -EXPORT_SYMBOL(jbd2_journal_init_inode); -EXPORT_SYMBOL(jbd2_journal_check_used_features); -EXPORT_SYMBOL(jbd2_journal_check_available_features); -EXPORT_SYMBOL(jbd2_journal_set_features); -EXPORT_SYMBOL(jbd2_journal_load); -EXPORT_SYMBOL(jbd2_journal_destroy); -EXPORT_SYMBOL(jbd2_journal_abort); -EXPORT_SYMBOL(jbd2_journal_errno); -EXPORT_SYMBOL(jbd2_journal_ack_err); -EXPORT_SYMBOL(jbd2_journal_clear_err); -EXPORT_SYMBOL(jbd2_log_wait_commit); -EXPORT_SYMBOL(jbd2_log_start_commit); -EXPORT_SYMBOL(jbd2_journal_start_commit); -EXPORT_SYMBOL(jbd2_journal_force_commit_nested); -EXPORT_SYMBOL(jbd2_journal_wipe); -EXPORT_SYMBOL(jbd2_journal_blocks_per_page); -EXPORT_SYMBOL(jbd2_journal_invalidatepage); -EXPORT_SYMBOL(jbd2_journal_try_to_free_buffers); -EXPORT_SYMBOL(jbd2_journal_force_commit); -EXPORT_SYMBOL(jbd2_journal_inode_add_write); -EXPORT_SYMBOL(jbd2_journal_inode_add_wait); -EXPORT_SYMBOL(jbd2_journal_init_jbd_inode); -EXPORT_SYMBOL(jbd2_journal_release_jbd_inode); -EXPORT_SYMBOL(jbd2_journal_begin_ordered_truncate); -EXPORT_SYMBOL(jbd2_inode_cache); - -static void __journal_abort_soft (journal_t *journal, int errno); -static int jbd2_journal_create_slab(size_t slab_size); - -#ifdef CONFIG_JBD2_DEBUG -void __jbd2_debug(int level, const char *file, const char *func, - unsigned int line, const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - if (level > jbd2_journal_enable_debug) - return; - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; - printk(KERN_DEBUG "%s: (%s, %u): %pV\n", file, func, line, &vaf); - va_end(args); -} -EXPORT_SYMBOL(__jbd2_debug); -#endif - -/* Checksumming functions */ -static int jbd2_verify_csum_type(journal_t *j, journal_superblock_t *sb) -{ - if (!jbd2_journal_has_csum_v2or3_feature(j)) - return 1; - - return sb->s_checksum_type == JBD2_CRC32C_CHKSUM; -} - -static __be32 jbd2_superblock_csum(journal_t *j, journal_superblock_t *sb) -{ - __u32 csum; - __be32 old_csum; - - old_csum = sb->s_checksum; - sb->s_checksum = 0; - csum = jbd2_chksum(j, ~0, (char *)sb, sizeof(journal_superblock_t)); - sb->s_checksum = old_csum; - - return cpu_to_be32(csum); -} - -static int jbd2_superblock_csum_verify(journal_t *j, journal_superblock_t *sb) -{ - if (!jbd2_journal_has_csum_v2or3(j)) - return 1; - - return sb->s_checksum == jbd2_superblock_csum(j, sb); -} - -static void jbd2_superblock_csum_set(journal_t *j, journal_superblock_t *sb) -{ - if (!jbd2_journal_has_csum_v2or3(j)) - return; - - sb->s_checksum = jbd2_superblock_csum(j, sb); -} - -/* - * Helper function used to manage commit timeouts - */ - -static void commit_timeout(unsigned long __data) -{ - struct task_struct * p = (struct task_struct *) __data; - - wake_up_process(p); -} - -/* - * kjournald2: The main thread function used to manage a logging device - * journal. - * - * This kernel thread is responsible for two things: - * - * 1) COMMIT: Every so often we need to commit the current state of the - * filesystem to disk. The journal thread is responsible for writing - * all of the metadata buffers to disk. - * - * 2) CHECKPOINT: We cannot reuse a used section of the log file until all - * of the data in that part of the log has been rewritten elsewhere on - * the disk. Flushing these old buffers to reclaim space in the log is - * known as checkpointing, and this thread is responsible for that job. - */ - -static int kjournald2(void *arg) -{ - journal_t *journal = arg; - transaction_t *transaction; - - /* - * Set up an interval timer which can be used to trigger a commit wakeup - * after the commit interval expires - */ - setup_timer(&journal->j_commit_timer, commit_timeout, - (unsigned long)current); - - set_freezable(); - - /* Record that the journal thread is running */ - journal->j_task = current; - wake_up(&journal->j_wait_done_commit); - - /* - * And now, wait forever for commit wakeup events. - */ - write_lock(&journal->j_state_lock); - -loop: - if (journal->j_flags & JBD2_UNMOUNT) - goto end_loop; - - jbd_debug(1, "commit_sequence=%d, commit_request=%d\n", - journal->j_commit_sequence, journal->j_commit_request); - - if (journal->j_commit_sequence != journal->j_commit_request) { - jbd_debug(1, "OK, requests differ\n"); - write_unlock(&journal->j_state_lock); - del_timer_sync(&journal->j_commit_timer); - jbd2_journal_commit_transaction(journal); - write_lock(&journal->j_state_lock); - goto loop; - } - - wake_up(&journal->j_wait_done_commit); - if (freezing(current)) { - /* - * The simpler the better. Flushing journal isn't a - * good idea, because that depends on threads that may - * be already stopped. - */ - jbd_debug(1, "Now suspending kjournald2\n"); - write_unlock(&journal->j_state_lock); - try_to_freeze(); - write_lock(&journal->j_state_lock); - } else { - /* - * We assume on resume that commits are already there, - * so we don't sleep - */ - DEFINE_WAIT(wait); - int should_sleep = 1; - - prepare_to_wait(&journal->j_wait_commit, &wait, - TASK_INTERRUPTIBLE); - if (journal->j_commit_sequence != journal->j_commit_request) - should_sleep = 0; - transaction = journal->j_running_transaction; - if (transaction && time_after_eq(jiffies, - transaction->t_expires)) - should_sleep = 0; - if (journal->j_flags & JBD2_UNMOUNT) - should_sleep = 0; - if (should_sleep) { - write_unlock(&journal->j_state_lock); - schedule(); - write_lock(&journal->j_state_lock); - } - finish_wait(&journal->j_wait_commit, &wait); - } - - jbd_debug(1, "kjournald2 wakes\n"); - - /* - * Were we woken up by a commit wakeup event? - */ - transaction = journal->j_running_transaction; - if (transaction && time_after_eq(jiffies, transaction->t_expires)) { - journal->j_commit_request = transaction->t_tid; - jbd_debug(1, "woke because of timeout\n"); - } - goto loop; - -end_loop: - write_unlock(&journal->j_state_lock); - del_timer_sync(&journal->j_commit_timer); - journal->j_task = NULL; - wake_up(&journal->j_wait_done_commit); - jbd_debug(1, "Journal thread exiting.\n"); - return 0; -} - -static int jbd2_journal_start_thread(journal_t *journal) -{ - struct task_struct *t; - - t = kthread_run(kjournald2, journal, "jbd2/%s", - journal->j_devname); - if (IS_ERR(t)) - return PTR_ERR(t); - - wait_event(journal->j_wait_done_commit, journal->j_task != NULL); - return 0; -} - -static void journal_kill_thread(journal_t *journal) -{ - write_lock(&journal->j_state_lock); - journal->j_flags |= JBD2_UNMOUNT; - - while (journal->j_task) { - write_unlock(&journal->j_state_lock); - wake_up(&journal->j_wait_commit); - wait_event(journal->j_wait_done_commit, journal->j_task == NULL); - write_lock(&journal->j_state_lock); - } - write_unlock(&journal->j_state_lock); -} - -/* - * jbd2_journal_write_metadata_buffer: write a metadata buffer to the journal. - * - * Writes a metadata buffer to a given disk block. The actual IO is not - * performed but a new buffer_head is constructed which labels the data - * to be written with the correct destination disk block. - * - * Any magic-number escaping which needs to be done will cause a - * copy-out here. If the buffer happens to start with the - * JBD2_MAGIC_NUMBER, then we can't write it to the log directly: the - * magic number is only written to the log for descripter blocks. In - * this case, we copy the data and replace the first word with 0, and we - * return a result code which indicates that this buffer needs to be - * marked as an escaped buffer in the corresponding log descriptor - * block. The missing word can then be restored when the block is read - * during recovery. - * - * If the source buffer has already been modified by a new transaction - * since we took the last commit snapshot, we use the frozen copy of - * that data for IO. If we end up using the existing buffer_head's data - * for the write, then we have to make sure nobody modifies it while the - * IO is in progress. do_get_write_access() handles this. - * - * The function returns a pointer to the buffer_head to be used for IO. - * - * - * Return value: - * <0: Error - * >=0: Finished OK - * - * On success: - * Bit 0 set == escape performed on the data - * Bit 1 set == buffer copy-out performed (kfree the data after IO) - */ - -int jbd2_journal_write_metadata_buffer(transaction_t *transaction, - struct journal_head *jh_in, - struct buffer_head **bh_out, - sector_t blocknr) -{ - int need_copy_out = 0; - int done_copy_out = 0; - int do_escape = 0; - char *mapped_data; - struct buffer_head *new_bh; - struct page *new_page; - unsigned int new_offset; - struct buffer_head *bh_in = jh2bh(jh_in); - journal_t *journal = transaction->t_journal; - - /* - * The buffer really shouldn't be locked: only the current committing - * transaction is allowed to write it, so nobody else is allowed - * to do any IO. - * - * akpm: except if we're journalling data, and write() output is - * also part of a shared mapping, and another thread has - * decided to launch a writepage() against this buffer. - */ - J_ASSERT_BH(bh_in, buffer_jbddirty(bh_in)); - - new_bh = alloc_buffer_head(GFP_NOFS|__GFP_NOFAIL); - - /* keep subsequent assertions sane */ - atomic_set(&new_bh->b_count, 1); - - jbd_lock_bh_state(bh_in); -repeat: - /* - * If a new transaction has already done a buffer copy-out, then - * we use that version of the data for the commit. - */ - if (jh_in->b_frozen_data) { - done_copy_out = 1; - new_page = virt_to_page(jh_in->b_frozen_data); - new_offset = offset_in_page(jh_in->b_frozen_data); - } else { - new_page = jh2bh(jh_in)->b_page; - new_offset = offset_in_page(jh2bh(jh_in)->b_data); - } - - mapped_data = kmap_atomic(new_page); - /* - * Fire data frozen trigger if data already wasn't frozen. Do this - * before checking for escaping, as the trigger may modify the magic - * offset. If a copy-out happens afterwards, it will have the correct - * data in the buffer. - */ - if (!done_copy_out) - jbd2_buffer_frozen_trigger(jh_in, mapped_data + new_offset, - jh_in->b_triggers); - - /* - * Check for escaping - */ - if (*((__be32 *)(mapped_data + new_offset)) == - cpu_to_be32(JBD2_MAGIC_NUMBER)) { - need_copy_out = 1; - do_escape = 1; - } - kunmap_atomic(mapped_data); - - /* - * Do we need to do a data copy? - */ - if (need_copy_out && !done_copy_out) { - char *tmp; - - jbd_unlock_bh_state(bh_in); - tmp = jbd2_alloc(bh_in->b_size, GFP_NOFS); - if (!tmp) { - brelse(new_bh); - return -ENOMEM; - } - jbd_lock_bh_state(bh_in); - if (jh_in->b_frozen_data) { - jbd2_free(tmp, bh_in->b_size); - goto repeat; - } - - jh_in->b_frozen_data = tmp; - mapped_data = kmap_atomic(new_page); - memcpy(tmp, mapped_data + new_offset, bh_in->b_size); - kunmap_atomic(mapped_data); - - new_page = virt_to_page(tmp); - new_offset = offset_in_page(tmp); - done_copy_out = 1; - - /* - * This isn't strictly necessary, as we're using frozen - * data for the escaping, but it keeps consistency with - * b_frozen_data usage. - */ - jh_in->b_frozen_triggers = jh_in->b_triggers; - } - - /* - * Did we need to do an escaping? Now we've done all the - * copying, we can finally do so. - */ - if (do_escape) { - mapped_data = kmap_atomic(new_page); - *((unsigned int *)(mapped_data + new_offset)) = 0; - kunmap_atomic(mapped_data); - } - - set_bh_page(new_bh, new_page, new_offset); - new_bh->b_size = bh_in->b_size; - new_bh->b_bdev = journal->j_dev; - new_bh->b_blocknr = blocknr; - new_bh->b_private = bh_in; - set_buffer_mapped(new_bh); - set_buffer_dirty(new_bh); - - *bh_out = new_bh; - - /* - * The to-be-written buffer needs to get moved to the io queue, - * and the original buffer whose contents we are shadowing or - * copying is moved to the transaction's shadow queue. - */ - JBUFFER_TRACE(jh_in, "file as BJ_Shadow"); - spin_lock(&journal->j_list_lock); - __jbd2_journal_file_buffer(jh_in, transaction, BJ_Shadow); - spin_unlock(&journal->j_list_lock); - set_buffer_shadow(bh_in); - jbd_unlock_bh_state(bh_in); - - return do_escape | (done_copy_out << 1); -} - -/* - * Allocation code for the journal file. Manage the space left in the - * journal, so that we can begin checkpointing when appropriate. - */ - -/* - * Called with j_state_lock locked for writing. - * Returns true if a transaction commit was started. - */ -int __jbd2_log_start_commit(journal_t *journal, tid_t target) -{ - /* Return if the txn has already requested to be committed */ - if (journal->j_commit_request == target) - return 0; - - /* - * The only transaction we can possibly wait upon is the - * currently running transaction (if it exists). Otherwise, - * the target tid must be an old one. - */ - if (journal->j_running_transaction && - journal->j_running_transaction->t_tid == target) { - /* - * We want a new commit: OK, mark the request and wakeup the - * commit thread. We do _not_ do the commit ourselves. - */ - - journal->j_commit_request = target; - jbd_debug(1, "JBD2: requesting commit %d/%d\n", - journal->j_commit_request, - journal->j_commit_sequence); - journal->j_running_transaction->t_requested = jiffies; - wake_up(&journal->j_wait_commit); - return 1; - } else if (!tid_geq(journal->j_commit_request, target)) - /* This should never happen, but if it does, preserve - the evidence before kjournald goes into a loop and - increments j_commit_sequence beyond all recognition. */ - WARN_ONCE(1, "JBD2: bad log_start_commit: %u %u %u %u\n", - journal->j_commit_request, - journal->j_commit_sequence, - target, journal->j_running_transaction ? - journal->j_running_transaction->t_tid : 0); - return 0; -} - -int jbd2_log_start_commit(journal_t *journal, tid_t tid) -{ - int ret; - - write_lock(&journal->j_state_lock); - ret = __jbd2_log_start_commit(journal, tid); - write_unlock(&journal->j_state_lock); - return ret; -} - -/* - * Force and wait any uncommitted transactions. We can only force the running - * transaction if we don't have an active handle, otherwise, we will deadlock. - * Returns: <0 in case of error, - * 0 if nothing to commit, - * 1 if transaction was successfully committed. - */ -static int __jbd2_journal_force_commit(journal_t *journal) -{ - transaction_t *transaction = NULL; - tid_t tid; - int need_to_start = 0, ret = 0; - - read_lock(&journal->j_state_lock); - if (journal->j_running_transaction && !current->journal_info) { - transaction = journal->j_running_transaction; - if (!tid_geq(journal->j_commit_request, transaction->t_tid)) - need_to_start = 1; - } else if (journal->j_committing_transaction) - transaction = journal->j_committing_transaction; - - if (!transaction) { - /* Nothing to commit */ - read_unlock(&journal->j_state_lock); - return 0; - } - tid = transaction->t_tid; - read_unlock(&journal->j_state_lock); - if (need_to_start) - jbd2_log_start_commit(journal, tid); - ret = jbd2_log_wait_commit(journal, tid); - if (!ret) - ret = 1; - - return ret; -} - -/** - * Force and wait upon a commit if the calling process is not within - * transaction. This is used for forcing out undo-protected data which contains - * bitmaps, when the fs is running out of space. - * - * @journal: journal to force - * Returns true if progress was made. - */ -int jbd2_journal_force_commit_nested(journal_t *journal) -{ - int ret; - - ret = __jbd2_journal_force_commit(journal); - return ret > 0; -} - -/** - * int journal_force_commit() - force any uncommitted transactions - * @journal: journal to force - * - * Caller want unconditional commit. We can only force the running transaction - * if we don't have an active handle, otherwise, we will deadlock. - */ -int jbd2_journal_force_commit(journal_t *journal) -{ - int ret; - - J_ASSERT(!current->journal_info); - ret = __jbd2_journal_force_commit(journal); - if (ret > 0) - ret = 0; - return ret; -} - -/* - * Start a commit of the current running transaction (if any). Returns true - * if a transaction is going to be committed (or is currently already - * committing), and fills its tid in at *ptid - */ -int jbd2_journal_start_commit(journal_t *journal, tid_t *ptid) -{ - int ret = 0; - - write_lock(&journal->j_state_lock); - if (journal->j_running_transaction) { - tid_t tid = journal->j_running_transaction->t_tid; - - __jbd2_log_start_commit(journal, tid); - /* There's a running transaction and we've just made sure - * it's commit has been scheduled. */ - if (ptid) - *ptid = tid; - ret = 1; - } else if (journal->j_committing_transaction) { - /* - * If commit has been started, then we have to wait for - * completion of that transaction. - */ - if (ptid) - *ptid = journal->j_committing_transaction->t_tid; - ret = 1; - } - write_unlock(&journal->j_state_lock); - return ret; -} - -/* - * Return 1 if a given transaction has not yet sent barrier request - * connected with a transaction commit. If 0 is returned, transaction - * may or may not have sent the barrier. Used to avoid sending barrier - * twice in common cases. - */ -int jbd2_trans_will_send_data_barrier(journal_t *journal, tid_t tid) -{ - int ret = 0; - transaction_t *commit_trans; - - if (!(journal->j_flags & JBD2_BARRIER)) - return 0; - read_lock(&journal->j_state_lock); - /* Transaction already committed? */ - if (tid_geq(journal->j_commit_sequence, tid)) - goto out; - commit_trans = journal->j_committing_transaction; - if (!commit_trans || commit_trans->t_tid != tid) { - ret = 1; - goto out; - } - /* - * Transaction is being committed and we already proceeded to - * submitting a flush to fs partition? - */ - if (journal->j_fs_dev != journal->j_dev) { - if (!commit_trans->t_need_data_flush || - commit_trans->t_state >= T_COMMIT_DFLUSH) - goto out; - } else { - if (commit_trans->t_state >= T_COMMIT_JFLUSH) - goto out; - } - ret = 1; -out: - read_unlock(&journal->j_state_lock); - return ret; -} -EXPORT_SYMBOL(jbd2_trans_will_send_data_barrier); - -/* - * Wait for a specified commit to complete. - * The caller may not hold the journal lock. - */ -int jbd2_log_wait_commit(journal_t *journal, tid_t tid) -{ - int err = 0; - - jbd2_might_wait_for_commit(journal); - read_lock(&journal->j_state_lock); -#ifdef CONFIG_JBD2_DEBUG - if (!tid_geq(journal->j_commit_request, tid)) { - printk(KERN_ERR - "%s: error: j_commit_request=%d, tid=%d\n", - __func__, journal->j_commit_request, tid); - } -#endif - while (tid_gt(tid, journal->j_commit_sequence)) { - jbd_debug(1, "JBD2: want %d, j_commit_sequence=%d\n", - tid, journal->j_commit_sequence); - read_unlock(&journal->j_state_lock); - wake_up(&journal->j_wait_commit); - wait_event(journal->j_wait_done_commit, - !tid_gt(tid, journal->j_commit_sequence)); - read_lock(&journal->j_state_lock); - } - read_unlock(&journal->j_state_lock); - - if (unlikely(is_journal_aborted(journal))) - err = -EIO; - return err; -} - -/* - * When this function returns the transaction corresponding to tid - * will be completed. If the transaction has currently running, start - * committing that transaction before waiting for it to complete. If - * the transaction id is stale, it is by definition already completed, - * so just return SUCCESS. - */ -int jbd2_complete_transaction(journal_t *journal, tid_t tid) -{ - int need_to_wait = 1; - - read_lock(&journal->j_state_lock); - if (journal->j_running_transaction && - journal->j_running_transaction->t_tid == tid) { - if (journal->j_commit_request != tid) { - /* transaction not yet started, so request it */ - read_unlock(&journal->j_state_lock); - jbd2_log_start_commit(journal, tid); - goto wait_commit; - } - } else if (!(journal->j_committing_transaction && - journal->j_committing_transaction->t_tid == tid)) - need_to_wait = 0; - read_unlock(&journal->j_state_lock); - if (!need_to_wait) - return 0; -wait_commit: - return jbd2_log_wait_commit(journal, tid); -} -EXPORT_SYMBOL(jbd2_complete_transaction); - -/* - * Log buffer allocation routines: - */ - -int jbd2_journal_next_log_block(journal_t *journal, unsigned long long *retp) -{ - unsigned long blocknr; - - write_lock(&journal->j_state_lock); - J_ASSERT(journal->j_free > 1); - - blocknr = journal->j_head; - journal->j_head++; - journal->j_free--; - if (journal->j_head == journal->j_last) - journal->j_head = journal->j_first; - write_unlock(&journal->j_state_lock); - return jbd2_journal_bmap(journal, blocknr, retp); -} - -/* - * Conversion of logical to physical block numbers for the journal - * - * On external journals the journal blocks are identity-mapped, so - * this is a no-op. If needed, we can use j_blk_offset - everything is - * ready. - */ -int jbd2_journal_bmap(journal_t *journal, unsigned long blocknr, - unsigned long long *retp) -{ - int err = 0; - unsigned long long ret; - - if (journal->j_inode) { - ret = bmap(journal->j_inode, blocknr); - if (ret) - *retp = ret; - else { - printk(KERN_ALERT "%s: journal block not found " - "at offset %lu on %s\n", - __func__, blocknr, journal->j_devname); - err = -EIO; - __journal_abort_soft(journal, err); - } - } else { - *retp = blocknr; /* +journal->j_blk_offset */ - } - return err; -} - -/* - * We play buffer_head aliasing tricks to write data/metadata blocks to - * the journal without copying their contents, but for journal - * descriptor blocks we do need to generate bona fide buffers. - * - * After the caller of jbd2_journal_get_descriptor_buffer() has finished modifying - * the buffer's contents they really should run flush_dcache_page(bh->b_page). - * But we don't bother doing that, so there will be coherency problems with - * mmaps of blockdevs which hold live JBD-controlled filesystems. - */ -struct buffer_head * -jbd2_journal_get_descriptor_buffer(transaction_t *transaction, int type) -{ - journal_t *journal = transaction->t_journal; - struct buffer_head *bh; - unsigned long long blocknr; - journal_header_t *header; - int err; - - err = jbd2_journal_next_log_block(journal, &blocknr); - - if (err) - return NULL; - - bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); - if (!bh) - return NULL; - lock_buffer(bh); - memset(bh->b_data, 0, journal->j_blocksize); - header = (journal_header_t *)bh->b_data; - header->h_magic = cpu_to_be32(JBD2_MAGIC_NUMBER); - header->h_blocktype = cpu_to_be32(type); - header->h_sequence = cpu_to_be32(transaction->t_tid); - set_buffer_uptodate(bh); - unlock_buffer(bh); - BUFFER_TRACE(bh, "return this buffer"); - return bh; -} - -void jbd2_descriptor_block_csum_set(journal_t *j, struct buffer_head *bh) -{ - struct jbd2_journal_block_tail *tail; - __u32 csum; - - if (!jbd2_journal_has_csum_v2or3(j)) - return; - - tail = (struct jbd2_journal_block_tail *)(bh->b_data + j->j_blocksize - - sizeof(struct jbd2_journal_block_tail)); - tail->t_checksum = 0; - csum = jbd2_chksum(j, j->j_csum_seed, bh->b_data, j->j_blocksize); - tail->t_checksum = cpu_to_be32(csum); -} - -/* - * Return tid of the oldest transaction in the journal and block in the journal - * where the transaction starts. - * - * If the journal is now empty, return which will be the next transaction ID - * we will write and where will that transaction start. - * - * The return value is 0 if journal tail cannot be pushed any further, 1 if - * it can. - */ -int jbd2_journal_get_log_tail(journal_t *journal, tid_t *tid, - unsigned long *block) -{ - transaction_t *transaction; - int ret; - - read_lock(&journal->j_state_lock); - spin_lock(&journal->j_list_lock); - transaction = journal->j_checkpoint_transactions; - if (transaction) { - *tid = transaction->t_tid; - *block = transaction->t_log_start; - } else if ((transaction = journal->j_committing_transaction) != NULL) { - *tid = transaction->t_tid; - *block = transaction->t_log_start; - } else if ((transaction = journal->j_running_transaction) != NULL) { - *tid = transaction->t_tid; - *block = journal->j_head; - } else { - *tid = journal->j_transaction_sequence; - *block = journal->j_head; - } - ret = tid_gt(*tid, journal->j_tail_sequence); - spin_unlock(&journal->j_list_lock); - read_unlock(&journal->j_state_lock); - - return ret; -} - -/* - * Update information in journal structure and in on disk journal superblock - * about log tail. This function does not check whether information passed in - * really pushes log tail further. It's responsibility of the caller to make - * sure provided log tail information is valid (e.g. by holding - * j_checkpoint_mutex all the time between computing log tail and calling this - * function as is the case with jbd2_cleanup_journal_tail()). - * - * Requires j_checkpoint_mutex - */ -int __jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block) -{ - unsigned long freed; - int ret; - - BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex)); - - /* - * We cannot afford for write to remain in drive's caches since as - * soon as we update j_tail, next transaction can start reusing journal - * space and if we lose sb update during power failure we'd replay - * old transaction with possibly newly overwritten data. - */ - ret = jbd2_journal_update_sb_log_tail(journal, tid, block, WRITE_FUA); - if (ret) - goto out; - - write_lock(&journal->j_state_lock); - freed = block - journal->j_tail; - if (block < journal->j_tail) - freed += journal->j_last - journal->j_first; - - trace_jbd2_update_log_tail(journal, tid, block, freed); - jbd_debug(1, - "Cleaning journal tail from %d to %d (offset %lu), " - "freeing %lu\n", - journal->j_tail_sequence, tid, block, freed); - - journal->j_free += freed; - journal->j_tail_sequence = tid; - journal->j_tail = block; - write_unlock(&journal->j_state_lock); - -out: - return ret; -} - -/* - * This is a variaon of __jbd2_update_log_tail which checks for validity of - * provided log tail and locks j_checkpoint_mutex. So it is safe against races - * with other threads updating log tail. - */ -void jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block) -{ - mutex_lock(&journal->j_checkpoint_mutex); - if (tid_gt(tid, journal->j_tail_sequence)) - __jbd2_update_log_tail(journal, tid, block); - mutex_unlock(&journal->j_checkpoint_mutex); -} - -struct jbd2_stats_proc_session { - journal_t *journal; - struct transaction_stats_s *stats; - int start; - int max; -}; - -static void *jbd2_seq_info_start(struct seq_file *seq, loff_t *pos) -{ - return *pos ? NULL : SEQ_START_TOKEN; -} - -static void *jbd2_seq_info_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return NULL; -} - -static int jbd2_seq_info_show(struct seq_file *seq, void *v) -{ - struct jbd2_stats_proc_session *s = seq->private; - - if (v != SEQ_START_TOKEN) - return 0; - seq_printf(seq, "%lu transactions (%lu requested), " - "each up to %u blocks\n", - s->stats->ts_tid, s->stats->ts_requested, - s->journal->j_max_transaction_buffers); - if (s->stats->ts_tid == 0) - return 0; - seq_printf(seq, "average: \n %ums waiting for transaction\n", - jiffies_to_msecs(s->stats->run.rs_wait / s->stats->ts_tid)); - seq_printf(seq, " %ums request delay\n", - (s->stats->ts_requested == 0) ? 0 : - jiffies_to_msecs(s->stats->run.rs_request_delay / - s->stats->ts_requested)); - seq_printf(seq, " %ums running transaction\n", - jiffies_to_msecs(s->stats->run.rs_running / s->stats->ts_tid)); - seq_printf(seq, " %ums transaction was being locked\n", - jiffies_to_msecs(s->stats->run.rs_locked / s->stats->ts_tid)); - seq_printf(seq, " %ums flushing data (in ordered mode)\n", - jiffies_to_msecs(s->stats->run.rs_flushing / s->stats->ts_tid)); - seq_printf(seq, " %ums logging transaction\n", - jiffies_to_msecs(s->stats->run.rs_logging / s->stats->ts_tid)); - seq_printf(seq, " %lluus average transaction commit time\n", - div_u64(s->journal->j_average_commit_time, 1000)); - seq_printf(seq, " %lu handles per transaction\n", - s->stats->run.rs_handle_count / s->stats->ts_tid); - seq_printf(seq, " %lu blocks per transaction\n", - s->stats->run.rs_blocks / s->stats->ts_tid); - seq_printf(seq, " %lu logged blocks per transaction\n", - s->stats->run.rs_blocks_logged / s->stats->ts_tid); - return 0; -} - -static void jbd2_seq_info_stop(struct seq_file *seq, void *v) -{ -} - -static const struct seq_operations jbd2_seq_info_ops = { - .start = jbd2_seq_info_start, - .next = jbd2_seq_info_next, - .stop = jbd2_seq_info_stop, - .show = jbd2_seq_info_show, -}; - -static int jbd2_seq_info_open(struct inode *inode, struct file *file) -{ - journal_t *journal = PDE_DATA(inode); - struct jbd2_stats_proc_session *s; - int rc, size; - - s = kmalloc(sizeof(*s), GFP_KERNEL); - if (s == NULL) - return -ENOMEM; - size = sizeof(struct transaction_stats_s); - s->stats = kmalloc(size, GFP_KERNEL); - if (s->stats == NULL) { - kfree(s); - return -ENOMEM; - } - spin_lock(&journal->j_history_lock); - memcpy(s->stats, &journal->j_stats, size); - s->journal = journal; - spin_unlock(&journal->j_history_lock); - - rc = seq_open(file, &jbd2_seq_info_ops); - if (rc == 0) { - struct seq_file *m = file->private_data; - m->private = s; - } else { - kfree(s->stats); - kfree(s); - } - return rc; - -} - -static int jbd2_seq_info_release(struct inode *inode, struct file *file) -{ - struct seq_file *seq = file->private_data; - struct jbd2_stats_proc_session *s = seq->private; - kfree(s->stats); - kfree(s); - return seq_release(inode, file); -} - -static const struct file_operations jbd2_seq_info_fops = { - .owner = THIS_MODULE, - .open = jbd2_seq_info_open, - .read = seq_read, - .llseek = seq_lseek, - .release = jbd2_seq_info_release, -}; - -static struct proc_dir_entry *proc_jbd2_stats; - -static void jbd2_stats_proc_init(journal_t *journal) -{ - journal->j_proc_entry = proc_mkdir(journal->j_devname, proc_jbd2_stats); - if (journal->j_proc_entry) { - proc_create_data("info", S_IRUGO, journal->j_proc_entry, - &jbd2_seq_info_fops, journal); - } -} - -static void jbd2_stats_proc_exit(journal_t *journal) -{ - remove_proc_entry("info", journal->j_proc_entry); - remove_proc_entry(journal->j_devname, proc_jbd2_stats); -} - -/* - * Management for journal control blocks: functions to create and - * destroy journal_t structures, and to initialise and read existing - * journal blocks from disk. */ - -/* First: create and setup a journal_t object in memory. We initialise - * very few fields yet: that has to wait until we have created the - * journal structures from from scratch, or loaded them from disk. */ - -static journal_t *journal_init_common(struct block_device *bdev, - struct block_device *fs_dev, - unsigned long long start, int len, int blocksize) -{ - static struct lock_class_key jbd2_trans_commit_key; - journal_t *journal; - int err; - struct buffer_head *bh; - int n; - - journal = kzalloc(sizeof(*journal), GFP_KERNEL); - if (!journal) - return NULL; - - init_waitqueue_head(&journal->j_wait_transaction_locked); - init_waitqueue_head(&journal->j_wait_done_commit); - init_waitqueue_head(&journal->j_wait_commit); - init_waitqueue_head(&journal->j_wait_updates); - init_waitqueue_head(&journal->j_wait_reserved); - mutex_init(&journal->j_barrier); - mutex_init(&journal->j_checkpoint_mutex); - spin_lock_init(&journal->j_revoke_lock); - spin_lock_init(&journal->j_list_lock); - rwlock_init(&journal->j_state_lock); - - journal->j_commit_interval = (HZ * JBD2_DEFAULT_MAX_COMMIT_AGE); - journal->j_min_batch_time = 0; - journal->j_max_batch_time = 15000; /* 15ms */ - atomic_set(&journal->j_reserved_credits, 0); - - /* The journal is marked for error until we succeed with recovery! */ - journal->j_flags = JBD2_ABORT; - - /* Set up a default-sized revoke table for the new mount. */ - err = jbd2_journal_init_revoke(journal, JOURNAL_REVOKE_DEFAULT_HASH); - if (err) { - kfree(journal); - return NULL; - } - - spin_lock_init(&journal->j_history_lock); - - lockdep_init_map(&journal->j_trans_commit_map, "jbd2_handle", - &jbd2_trans_commit_key, 0); - - /* journal descriptor can store up to n blocks -bzzz */ - journal->j_blocksize = blocksize; - journal->j_dev = bdev; - journal->j_fs_dev = fs_dev; - journal->j_blk_offset = start; - journal->j_maxlen = len; - n = journal->j_blocksize / sizeof(journal_block_tag_t); - journal->j_wbufsize = n; - journal->j_wbuf = kmalloc_array(n, sizeof(struct buffer_head *), - GFP_KERNEL); - if (!journal->j_wbuf) { - kfree(journal); - return NULL; - } - - bh = getblk_unmovable(journal->j_dev, start, journal->j_blocksize); - if (!bh) { - pr_err("%s: Cannot get buffer for journal superblock\n", - __func__); - kfree(journal->j_wbuf); - kfree(journal); - return NULL; - } - journal->j_sb_buffer = bh; - journal->j_superblock = (journal_superblock_t *)bh->b_data; - - return journal; -} - -/* jbd2_journal_init_dev and jbd2_journal_init_inode: - * - * Create a journal structure assigned some fixed set of disk blocks to - * the journal. We don't actually touch those disk blocks yet, but we - * need to set up all of the mapping information to tell the journaling - * system where the journal blocks are. - * - */ - -/** - * journal_t * jbd2_journal_init_dev() - creates and initialises a journal structure - * @bdev: Block device on which to create the journal - * @fs_dev: Device which hold journalled filesystem for this journal. - * @start: Block nr Start of journal. - * @len: Length of the journal in blocks. - * @blocksize: blocksize of journalling device - * - * Returns: a newly created journal_t * - * - * jbd2_journal_init_dev creates a journal which maps a fixed contiguous - * range of blocks on an arbitrary block device. - * - */ -journal_t *jbd2_journal_init_dev(struct block_device *bdev, - struct block_device *fs_dev, - unsigned long long start, int len, int blocksize) -{ - journal_t *journal; - - journal = journal_init_common(bdev, fs_dev, start, len, blocksize); - if (!journal) - return NULL; - - bdevname(journal->j_dev, journal->j_devname); - strreplace(journal->j_devname, '/', '!'); - jbd2_stats_proc_init(journal); - - return journal; -} - -/** - * journal_t * jbd2_journal_init_inode () - creates a journal which maps to a inode. - * @inode: An inode to create the journal in - * - * jbd2_journal_init_inode creates a journal which maps an on-disk inode as - * the journal. The inode must exist already, must support bmap() and - * must have all data blocks preallocated. - */ -journal_t *jbd2_journal_init_inode(struct inode *inode) -{ - journal_t *journal; - char *p; - unsigned long long blocknr; - - blocknr = bmap(inode, 0); - if (!blocknr) { - pr_err("%s: Cannot locate journal superblock\n", - __func__); - return NULL; - } - - jbd_debug(1, "JBD2: inode %s/%ld, size %lld, bits %d, blksize %ld\n", - inode->i_sb->s_id, inode->i_ino, (long long) inode->i_size, - inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize); - - journal = journal_init_common(inode->i_sb->s_bdev, inode->i_sb->s_bdev, - blocknr, inode->i_size >> inode->i_sb->s_blocksize_bits, - inode->i_sb->s_blocksize); - if (!journal) - return NULL; - - journal->j_inode = inode; - bdevname(journal->j_dev, journal->j_devname); - p = strreplace(journal->j_devname, '/', '!'); - sprintf(p, "-%lu", journal->j_inode->i_ino); - jbd2_stats_proc_init(journal); - - return journal; -} - -/* - * If the journal init or create aborts, we need to mark the journal - * superblock as being NULL to prevent the journal destroy from writing - * back a bogus superblock. - */ -static void journal_fail_superblock (journal_t *journal) -{ - struct buffer_head *bh = journal->j_sb_buffer; - brelse(bh); - journal->j_sb_buffer = NULL; -} - -/* - * Given a journal_t structure, initialise the various fields for - * startup of a new journaling session. We use this both when creating - * a journal, and after recovering an old journal to reset it for - * subsequent use. - */ - -static int journal_reset(journal_t *journal) -{ - journal_superblock_t *sb = journal->j_superblock; - unsigned long long first, last; - - first = be32_to_cpu(sb->s_first); - last = be32_to_cpu(sb->s_maxlen); - if (first + JBD2_MIN_JOURNAL_BLOCKS > last + 1) { - printk(KERN_ERR "JBD2: Journal too short (blocks %llu-%llu).\n", - first, last); - journal_fail_superblock(journal); - return -EINVAL; - } - - journal->j_first = first; - journal->j_last = last; - - journal->j_head = first; - journal->j_tail = first; - journal->j_free = last - first; - - journal->j_tail_sequence = journal->j_transaction_sequence; - journal->j_commit_sequence = journal->j_transaction_sequence - 1; - journal->j_commit_request = journal->j_commit_sequence; - - journal->j_max_transaction_buffers = journal->j_maxlen / 4; - - /* - * As a special case, if the on-disk copy is already marked as needing - * no recovery (s_start == 0), then we can safely defer the superblock - * update until the next commit by setting JBD2_FLUSHED. This avoids - * attempting a write to a potential-readonly device. - */ - if (sb->s_start == 0) { - jbd_debug(1, "JBD2: Skipping superblock update on recovered sb " - "(start %ld, seq %d, errno %d)\n", - journal->j_tail, journal->j_tail_sequence, - journal->j_errno); - journal->j_flags |= JBD2_FLUSHED; - } else { - /* Lock here to make assertions happy... */ - mutex_lock(&journal->j_checkpoint_mutex); - /* - * Update log tail information. We use WRITE_FUA since new - * transaction will start reusing journal space and so we - * must make sure information about current log tail is on - * disk before that. - */ - jbd2_journal_update_sb_log_tail(journal, - journal->j_tail_sequence, - journal->j_tail, - WRITE_FUA); - mutex_unlock(&journal->j_checkpoint_mutex); - } - return jbd2_journal_start_thread(journal); -} - -static int jbd2_write_superblock(journal_t *journal, int write_flags) -{ - struct buffer_head *bh = journal->j_sb_buffer; - journal_superblock_t *sb = journal->j_superblock; - int ret; - - trace_jbd2_write_superblock(journal, write_flags); - if (!(journal->j_flags & JBD2_BARRIER)) - write_flags &= ~(REQ_FUA | REQ_PREFLUSH); - lock_buffer(bh); - if (buffer_write_io_error(bh)) { - /* - * Oh, dear. A previous attempt to write the journal - * superblock failed. This could happen because the - * USB device was yanked out. Or it could happen to - * be a transient write error and maybe the block will - * be remapped. Nothing we can do but to retry the - * write and hope for the best. - */ - printk(KERN_ERR "JBD2: previous I/O error detected " - "for journal superblock update for %s.\n", - journal->j_devname); - clear_buffer_write_io_error(bh); - set_buffer_uptodate(bh); - } - jbd2_superblock_csum_set(journal, sb); - get_bh(bh); - bh->b_end_io = end_buffer_write_sync; - ret = submit_bh(REQ_OP_WRITE, write_flags, bh); - wait_on_buffer(bh); - if (buffer_write_io_error(bh)) { - clear_buffer_write_io_error(bh); - set_buffer_uptodate(bh); - ret = -EIO; - } - if (ret) { - printk(KERN_ERR "JBD2: Error %d detected when updating " - "journal superblock for %s.\n", ret, - journal->j_devname); - jbd2_journal_abort(journal, ret); - } - - return ret; -} - -/** - * jbd2_journal_update_sb_log_tail() - Update log tail in journal sb on disk. - * @journal: The journal to update. - * @tail_tid: TID of the new transaction at the tail of the log - * @tail_block: The first block of the transaction at the tail of the log - * @write_op: With which operation should we write the journal sb - * - * Update a journal's superblock information about log tail and write it to - * disk, waiting for the IO to complete. - */ -int jbd2_journal_update_sb_log_tail(journal_t *journal, tid_t tail_tid, - unsigned long tail_block, int write_op) -{ - journal_superblock_t *sb = journal->j_superblock; - int ret; - - BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex)); - jbd_debug(1, "JBD2: updating superblock (start %lu, seq %u)\n", - tail_block, tail_tid); - - sb->s_sequence = cpu_to_be32(tail_tid); - sb->s_start = cpu_to_be32(tail_block); - - ret = jbd2_write_superblock(journal, write_op); - if (ret) - goto out; - - /* Log is no longer empty */ - write_lock(&journal->j_state_lock); - WARN_ON(!sb->s_sequence); - journal->j_flags &= ~JBD2_FLUSHED; - write_unlock(&journal->j_state_lock); - -out: - return ret; -} - -/** - * jbd2_mark_journal_empty() - Mark on disk journal as empty. - * @journal: The journal to update. - * @write_op: With which operation should we write the journal sb - * - * Update a journal's dynamic superblock fields to show that journal is empty. - * Write updated superblock to disk waiting for IO to complete. - */ -static void jbd2_mark_journal_empty(journal_t *journal, int write_op) -{ - journal_superblock_t *sb = journal->j_superblock; - - BUG_ON(!mutex_is_locked(&journal->j_checkpoint_mutex)); - read_lock(&journal->j_state_lock); - /* Is it already empty? */ - if (sb->s_start == 0) { - read_unlock(&journal->j_state_lock); - return; - } - jbd_debug(1, "JBD2: Marking journal as empty (seq %d)\n", - journal->j_tail_sequence); - - sb->s_sequence = cpu_to_be32(journal->j_tail_sequence); - sb->s_start = cpu_to_be32(0); - read_unlock(&journal->j_state_lock); - - jbd2_write_superblock(journal, write_op); - - /* Log is no longer empty */ - write_lock(&journal->j_state_lock); - journal->j_flags |= JBD2_FLUSHED; - write_unlock(&journal->j_state_lock); -} - - -/** - * jbd2_journal_update_sb_errno() - Update error in the journal. - * @journal: The journal to update. - * - * Update a journal's errno. Write updated superblock to disk waiting for IO - * to complete. - */ -void jbd2_journal_update_sb_errno(journal_t *journal) -{ - journal_superblock_t *sb = journal->j_superblock; - - read_lock(&journal->j_state_lock); - jbd_debug(1, "JBD2: updating superblock error (errno %d)\n", - journal->j_errno); - sb->s_errno = cpu_to_be32(journal->j_errno); - read_unlock(&journal->j_state_lock); - - jbd2_write_superblock(journal, WRITE_FUA); -} -EXPORT_SYMBOL(jbd2_journal_update_sb_errno); - -/* - * Read the superblock for a given journal, performing initial - * validation of the format. - */ -static int journal_get_superblock(journal_t *journal) -{ - struct buffer_head *bh; - journal_superblock_t *sb; - int err = -EIO; - - bh = journal->j_sb_buffer; - - J_ASSERT(bh != NULL); - if (!buffer_uptodate(bh)) { - ll_rw_block(REQ_OP_READ, 0, 1, &bh); - wait_on_buffer(bh); - if (!buffer_uptodate(bh)) { - printk(KERN_ERR - "JBD2: IO error reading journal superblock\n"); - goto out; - } - } - - if (buffer_verified(bh)) - return 0; - - sb = journal->j_superblock; - - err = -EINVAL; - - if (sb->s_header.h_magic != cpu_to_be32(JBD2_MAGIC_NUMBER) || - sb->s_blocksize != cpu_to_be32(journal->j_blocksize)) { - printk(KERN_WARNING "JBD2: no valid journal superblock found\n"); - goto out; - } - - switch(be32_to_cpu(sb->s_header.h_blocktype)) { - case JBD2_SUPERBLOCK_V1: - journal->j_format_version = 1; - break; - case JBD2_SUPERBLOCK_V2: - journal->j_format_version = 2; - break; - default: - printk(KERN_WARNING "JBD2: unrecognised superblock format ID\n"); - goto out; - } - - if (be32_to_cpu(sb->s_maxlen) < journal->j_maxlen) - journal->j_maxlen = be32_to_cpu(sb->s_maxlen); - else if (be32_to_cpu(sb->s_maxlen) > journal->j_maxlen) { - printk(KERN_WARNING "JBD2: journal file too short\n"); - goto out; - } - - if (be32_to_cpu(sb->s_first) == 0 || - be32_to_cpu(sb->s_first) >= journal->j_maxlen) { - printk(KERN_WARNING - "JBD2: Invalid start block of journal: %u\n", - be32_to_cpu(sb->s_first)); - goto out; - } - - if (jbd2_has_feature_csum2(journal) && - jbd2_has_feature_csum3(journal)) { - /* Can't have checksum v2 and v3 at the same time! */ - printk(KERN_ERR "JBD2: Can't enable checksumming v2 and v3 " - "at the same time!\n"); - goto out; - } - - if (jbd2_journal_has_csum_v2or3_feature(journal) && - jbd2_has_feature_checksum(journal)) { - /* Can't have checksum v1 and v2 on at the same time! */ - printk(KERN_ERR "JBD2: Can't enable checksumming v1 and v2/3 " - "at the same time!\n"); - goto out; - } - - if (!jbd2_verify_csum_type(journal, sb)) { - printk(KERN_ERR "JBD2: Unknown checksum type\n"); - goto out; - } - - /* Load the checksum driver */ - if (jbd2_journal_has_csum_v2or3_feature(journal)) { - journal->j_chksum_driver = crypto_alloc_shash("crc32c", 0, 0); - if (IS_ERR(journal->j_chksum_driver)) { - printk(KERN_ERR "JBD2: Cannot load crc32c driver.\n"); - err = PTR_ERR(journal->j_chksum_driver); - journal->j_chksum_driver = NULL; - goto out; - } - } - - /* Check superblock checksum */ - if (!jbd2_superblock_csum_verify(journal, sb)) { - printk(KERN_ERR "JBD2: journal checksum error\n"); - err = -EFSBADCRC; - goto out; - } - - /* Precompute checksum seed for all metadata */ - if (jbd2_journal_has_csum_v2or3(journal)) - journal->j_csum_seed = jbd2_chksum(journal, ~0, sb->s_uuid, - sizeof(sb->s_uuid)); - - set_buffer_verified(bh); - - return 0; - -out: - journal_fail_superblock(journal); - return err; -} - -/* - * Load the on-disk journal superblock and read the key fields into the - * journal_t. - */ - -static int load_superblock(journal_t *journal) -{ - int err; - journal_superblock_t *sb; - - err = journal_get_superblock(journal); - if (err) - return err; - - sb = journal->j_superblock; - - journal->j_tail_sequence = be32_to_cpu(sb->s_sequence); - journal->j_tail = be32_to_cpu(sb->s_start); - journal->j_first = be32_to_cpu(sb->s_first); - journal->j_last = be32_to_cpu(sb->s_maxlen); - journal->j_errno = be32_to_cpu(sb->s_errno); - - return 0; -} - - -/** - * int jbd2_journal_load() - Read journal from disk. - * @journal: Journal to act on. - * - * Given a journal_t structure which tells us which disk blocks contain - * a journal, read the journal from disk to initialise the in-memory - * structures. - */ -int jbd2_journal_load(journal_t *journal) -{ - int err; - journal_superblock_t *sb; - - err = load_superblock(journal); - if (err) - return err; - - sb = journal->j_superblock; - /* If this is a V2 superblock, then we have to check the - * features flags on it. */ - - if (journal->j_format_version >= 2) { - if ((sb->s_feature_ro_compat & - ~cpu_to_be32(JBD2_KNOWN_ROCOMPAT_FEATURES)) || - (sb->s_feature_incompat & - ~cpu_to_be32(JBD2_KNOWN_INCOMPAT_FEATURES))) { - printk(KERN_WARNING - "JBD2: Unrecognised features on journal\n"); - return -EINVAL; - } - } - - /* - * Create a slab for this blocksize - */ - err = jbd2_journal_create_slab(be32_to_cpu(sb->s_blocksize)); - if (err) - return err; - - /* Let the recovery code check whether it needs to recover any - * data from the journal. */ - if (jbd2_journal_recover(journal)) - goto recovery_error; - - if (journal->j_failed_commit) { - printk(KERN_ERR "JBD2: journal transaction %u on %s " - "is corrupt.\n", journal->j_failed_commit, - journal->j_devname); - return -EFSCORRUPTED; - } - - /* OK, we've finished with the dynamic journal bits: - * reinitialise the dynamic contents of the superblock in memory - * and reset them on disk. */ - if (journal_reset(journal)) - goto recovery_error; - - journal->j_flags &= ~JBD2_ABORT; - journal->j_flags |= JBD2_LOADED; - return 0; - -recovery_error: - printk(KERN_WARNING "JBD2: recovery failed\n"); - return -EIO; -} - -/** - * void jbd2_journal_destroy() - Release a journal_t structure. - * @journal: Journal to act on. - * - * Release a journal_t structure once it is no longer in use by the - * journaled object. - * Return <0 if we couldn't clean up the journal. - */ -int jbd2_journal_destroy(journal_t *journal) -{ - int err = 0; - - /* Wait for the commit thread to wake up and die. */ - journal_kill_thread(journal); - - /* Force a final log commit */ - if (journal->j_running_transaction) - jbd2_journal_commit_transaction(journal); - - /* Force any old transactions to disk */ - - /* Totally anal locking here... */ - spin_lock(&journal->j_list_lock); - while (journal->j_checkpoint_transactions != NULL) { - spin_unlock(&journal->j_list_lock); - mutex_lock(&journal->j_checkpoint_mutex); - err = jbd2_log_do_checkpoint(journal); - mutex_unlock(&journal->j_checkpoint_mutex); - /* - * If checkpointing failed, just free the buffers to avoid - * looping forever - */ - if (err) { - jbd2_journal_destroy_checkpoint(journal); - spin_lock(&journal->j_list_lock); - break; - } - spin_lock(&journal->j_list_lock); - } - - J_ASSERT(journal->j_running_transaction == NULL); - J_ASSERT(journal->j_committing_transaction == NULL); - J_ASSERT(journal->j_checkpoint_transactions == NULL); - spin_unlock(&journal->j_list_lock); - - if (journal->j_sb_buffer) { - if (!is_journal_aborted(journal)) { - mutex_lock(&journal->j_checkpoint_mutex); - - write_lock(&journal->j_state_lock); - journal->j_tail_sequence = - ++journal->j_transaction_sequence; - write_unlock(&journal->j_state_lock); - - jbd2_mark_journal_empty(journal, WRITE_FLUSH_FUA); - mutex_unlock(&journal->j_checkpoint_mutex); - } else - err = -EIO; - brelse(journal->j_sb_buffer); - } - - if (journal->j_proc_entry) - jbd2_stats_proc_exit(journal); - iput(journal->j_inode); - if (journal->j_revoke) - jbd2_journal_destroy_revoke(journal); - if (journal->j_chksum_driver) - crypto_free_shash(journal->j_chksum_driver); - kfree(journal->j_wbuf); - kfree(journal); - - return err; -} - - -/** - *int jbd2_journal_check_used_features () - Check if features specified are used. - * @journal: Journal to check. - * @compat: bitmask of compatible features - * @ro: bitmask of features that force read-only mount - * @incompat: bitmask of incompatible features - * - * Check whether the journal uses all of a given set of - * features. Return true (non-zero) if it does. - **/ - -int jbd2_journal_check_used_features (journal_t *journal, unsigned long compat, - unsigned long ro, unsigned long incompat) -{ - journal_superblock_t *sb; - - if (!compat && !ro && !incompat) - return 1; - /* Load journal superblock if it is not loaded yet. */ - if (journal->j_format_version == 0 && - journal_get_superblock(journal) != 0) - return 0; - if (journal->j_format_version == 1) - return 0; - - sb = journal->j_superblock; - - if (((be32_to_cpu(sb->s_feature_compat) & compat) == compat) && - ((be32_to_cpu(sb->s_feature_ro_compat) & ro) == ro) && - ((be32_to_cpu(sb->s_feature_incompat) & incompat) == incompat)) - return 1; - - return 0; -} - -/** - * int jbd2_journal_check_available_features() - Check feature set in journalling layer - * @journal: Journal to check. - * @compat: bitmask of compatible features - * @ro: bitmask of features that force read-only mount - * @incompat: bitmask of incompatible features - * - * Check whether the journaling code supports the use of - * all of a given set of features on this journal. Return true - * (non-zero) if it can. */ - -int jbd2_journal_check_available_features (journal_t *journal, unsigned long compat, - unsigned long ro, unsigned long incompat) -{ - if (!compat && !ro && !incompat) - return 1; - - /* We can support any known requested features iff the - * superblock is in version 2. Otherwise we fail to support any - * extended sb features. */ - - if (journal->j_format_version != 2) - return 0; - - if ((compat & JBD2_KNOWN_COMPAT_FEATURES) == compat && - (ro & JBD2_KNOWN_ROCOMPAT_FEATURES) == ro && - (incompat & JBD2_KNOWN_INCOMPAT_FEATURES) == incompat) - return 1; - - return 0; -} - -/** - * int jbd2_journal_set_features () - Mark a given journal feature in the superblock - * @journal: Journal to act on. - * @compat: bitmask of compatible features - * @ro: bitmask of features that force read-only mount - * @incompat: bitmask of incompatible features - * - * Mark a given journal feature as present on the - * superblock. Returns true if the requested features could be set. - * - */ - -int jbd2_journal_set_features (journal_t *journal, unsigned long compat, - unsigned long ro, unsigned long incompat) -{ -#define INCOMPAT_FEATURE_ON(f) \ - ((incompat & (f)) && !(sb->s_feature_incompat & cpu_to_be32(f))) -#define COMPAT_FEATURE_ON(f) \ - ((compat & (f)) && !(sb->s_feature_compat & cpu_to_be32(f))) - journal_superblock_t *sb; - - if (jbd2_journal_check_used_features(journal, compat, ro, incompat)) - return 1; - - if (!jbd2_journal_check_available_features(journal, compat, ro, incompat)) - return 0; - - /* If enabling v2 checksums, turn on v3 instead */ - if (incompat & JBD2_FEATURE_INCOMPAT_CSUM_V2) { - incompat &= ~JBD2_FEATURE_INCOMPAT_CSUM_V2; - incompat |= JBD2_FEATURE_INCOMPAT_CSUM_V3; - } - - /* Asking for checksumming v3 and v1? Only give them v3. */ - if (incompat & JBD2_FEATURE_INCOMPAT_CSUM_V3 && - compat & JBD2_FEATURE_COMPAT_CHECKSUM) - compat &= ~JBD2_FEATURE_COMPAT_CHECKSUM; - - jbd_debug(1, "Setting new features 0x%lx/0x%lx/0x%lx\n", - compat, ro, incompat); - - sb = journal->j_superblock; - - /* If enabling v3 checksums, update superblock */ - if (INCOMPAT_FEATURE_ON(JBD2_FEATURE_INCOMPAT_CSUM_V3)) { - sb->s_checksum_type = JBD2_CRC32C_CHKSUM; - sb->s_feature_compat &= - ~cpu_to_be32(JBD2_FEATURE_COMPAT_CHECKSUM); - - /* Load the checksum driver */ - if (journal->j_chksum_driver == NULL) { - journal->j_chksum_driver = crypto_alloc_shash("crc32c", - 0, 0); - if (IS_ERR(journal->j_chksum_driver)) { - printk(KERN_ERR "JBD2: Cannot load crc32c " - "driver.\n"); - journal->j_chksum_driver = NULL; - return 0; - } - - /* Precompute checksum seed for all metadata */ - journal->j_csum_seed = jbd2_chksum(journal, ~0, - sb->s_uuid, - sizeof(sb->s_uuid)); - } - } - - /* If enabling v1 checksums, downgrade superblock */ - if (COMPAT_FEATURE_ON(JBD2_FEATURE_COMPAT_CHECKSUM)) - sb->s_feature_incompat &= - ~cpu_to_be32(JBD2_FEATURE_INCOMPAT_CSUM_V2 | - JBD2_FEATURE_INCOMPAT_CSUM_V3); - - sb->s_feature_compat |= cpu_to_be32(compat); - sb->s_feature_ro_compat |= cpu_to_be32(ro); - sb->s_feature_incompat |= cpu_to_be32(incompat); - - return 1; -#undef COMPAT_FEATURE_ON -#undef INCOMPAT_FEATURE_ON -} - -/* - * jbd2_journal_clear_features () - Clear a given journal feature in the - * superblock - * @journal: Journal to act on. - * @compat: bitmask of compatible features - * @ro: bitmask of features that force read-only mount - * @incompat: bitmask of incompatible features - * - * Clear a given journal feature as present on the - * superblock. - */ -void jbd2_journal_clear_features(journal_t *journal, unsigned long compat, - unsigned long ro, unsigned long incompat) -{ - journal_superblock_t *sb; - - jbd_debug(1, "Clear features 0x%lx/0x%lx/0x%lx\n", - compat, ro, incompat); - - sb = journal->j_superblock; - - sb->s_feature_compat &= ~cpu_to_be32(compat); - sb->s_feature_ro_compat &= ~cpu_to_be32(ro); - sb->s_feature_incompat &= ~cpu_to_be32(incompat); -} -EXPORT_SYMBOL(jbd2_journal_clear_features); - -/** - * int jbd2_journal_flush () - Flush journal - * @journal: Journal to act on. - * - * Flush all data for a given journal to disk and empty the journal. - * Filesystems can use this when remounting readonly to ensure that - * recovery does not need to happen on remount. - */ - -int jbd2_journal_flush(journal_t *journal) -{ - int err = 0; - transaction_t *transaction = NULL; - - write_lock(&journal->j_state_lock); - - /* Force everything buffered to the log... */ - if (journal->j_running_transaction) { - transaction = journal->j_running_transaction; - __jbd2_log_start_commit(journal, transaction->t_tid); - } else if (journal->j_committing_transaction) - transaction = journal->j_committing_transaction; - - /* Wait for the log commit to complete... */ - if (transaction) { - tid_t tid = transaction->t_tid; - - write_unlock(&journal->j_state_lock); - jbd2_log_wait_commit(journal, tid); - } else { - write_unlock(&journal->j_state_lock); - } - - /* ...and flush everything in the log out to disk. */ - spin_lock(&journal->j_list_lock); - while (!err && journal->j_checkpoint_transactions != NULL) { - spin_unlock(&journal->j_list_lock); - mutex_lock(&journal->j_checkpoint_mutex); - err = jbd2_log_do_checkpoint(journal); - mutex_unlock(&journal->j_checkpoint_mutex); - spin_lock(&journal->j_list_lock); - } - spin_unlock(&journal->j_list_lock); - - if (is_journal_aborted(journal)) - return -EIO; - - mutex_lock(&journal->j_checkpoint_mutex); - if (!err) { - err = jbd2_cleanup_journal_tail(journal); - if (err < 0) { - mutex_unlock(&journal->j_checkpoint_mutex); - goto out; - } - err = 0; - } - - /* Finally, mark the journal as really needing no recovery. - * This sets s_start==0 in the underlying superblock, which is - * the magic code for a fully-recovered superblock. Any future - * commits of data to the journal will restore the current - * s_start value. */ - jbd2_mark_journal_empty(journal, WRITE_FUA); - mutex_unlock(&journal->j_checkpoint_mutex); - write_lock(&journal->j_state_lock); - J_ASSERT(!journal->j_running_transaction); - J_ASSERT(!journal->j_committing_transaction); - J_ASSERT(!journal->j_checkpoint_transactions); - J_ASSERT(journal->j_head == journal->j_tail); - J_ASSERT(journal->j_tail_sequence == journal->j_transaction_sequence); - write_unlock(&journal->j_state_lock); -out: - return err; -} - -/** - * int jbd2_journal_wipe() - Wipe journal contents - * @journal: Journal to act on. - * @write: flag (see below) - * - * Wipe out all of the contents of a journal, safely. This will produce - * a warning if the journal contains any valid recovery information. - * Must be called between journal_init_*() and jbd2_journal_load(). - * - * If 'write' is non-zero, then we wipe out the journal on disk; otherwise - * we merely suppress recovery. - */ - -int jbd2_journal_wipe(journal_t *journal, int write) -{ - int err = 0; - - J_ASSERT (!(journal->j_flags & JBD2_LOADED)); - - err = load_superblock(journal); - if (err) - return err; - - if (!journal->j_tail) - goto no_recovery; - - printk(KERN_WARNING "JBD2: %s recovery information on journal\n", - write ? "Clearing" : "Ignoring"); - - err = jbd2_journal_skip_recovery(journal); - if (write) { - /* Lock to make assertions happy... */ - mutex_lock(&journal->j_checkpoint_mutex); - jbd2_mark_journal_empty(journal, WRITE_FUA); - mutex_unlock(&journal->j_checkpoint_mutex); - } - - no_recovery: - return err; -} - -/* - * Journal abort has very specific semantics, which we describe - * for journal abort. - * - * Two internal functions, which provide abort to the jbd layer - * itself are here. - */ - -/* - * Quick version for internal journal use (doesn't lock the journal). - * Aborts hard --- we mark the abort as occurred, but do _nothing_ else, - * and don't attempt to make any other journal updates. - */ -void __jbd2_journal_abort_hard(journal_t *journal) -{ - transaction_t *transaction; - - if (journal->j_flags & JBD2_ABORT) - return; - - printk(KERN_ERR "Aborting journal on device %s.\n", - journal->j_devname); - - write_lock(&journal->j_state_lock); - journal->j_flags |= JBD2_ABORT; - transaction = journal->j_running_transaction; - if (transaction) - __jbd2_log_start_commit(journal, transaction->t_tid); - write_unlock(&journal->j_state_lock); -} - -/* Soft abort: record the abort error status in the journal superblock, - * but don't do any other IO. */ -static void __journal_abort_soft (journal_t *journal, int errno) -{ - if (journal->j_flags & JBD2_ABORT) - return; - - if (!journal->j_errno) - journal->j_errno = errno; - - __jbd2_journal_abort_hard(journal); - - if (errno) { - jbd2_journal_update_sb_errno(journal); - write_lock(&journal->j_state_lock); - journal->j_flags |= JBD2_REC_ERR; - write_unlock(&journal->j_state_lock); - } -} - -/** - * void jbd2_journal_abort () - Shutdown the journal immediately. - * @journal: the journal to shutdown. - * @errno: an error number to record in the journal indicating - * the reason for the shutdown. - * - * Perform a complete, immediate shutdown of the ENTIRE - * journal (not of a single transaction). This operation cannot be - * undone without closing and reopening the journal. - * - * The jbd2_journal_abort function is intended to support higher level error - * recovery mechanisms such as the ext2/ext3 remount-readonly error - * mode. - * - * Journal abort has very specific semantics. Any existing dirty, - * unjournaled buffers in the main filesystem will still be written to - * disk by bdflush, but the journaling mechanism will be suspended - * immediately and no further transaction commits will be honoured. - * - * Any dirty, journaled buffers will be written back to disk without - * hitting the journal. Atomicity cannot be guaranteed on an aborted - * filesystem, but we _do_ attempt to leave as much data as possible - * behind for fsck to use for cleanup. - * - * Any attempt to get a new transaction handle on a journal which is in - * ABORT state will just result in an -EROFS error return. A - * jbd2_journal_stop on an existing handle will return -EIO if we have - * entered abort state during the update. - * - * Recursive transactions are not disturbed by journal abort until the - * final jbd2_journal_stop, which will receive the -EIO error. - * - * Finally, the jbd2_journal_abort call allows the caller to supply an errno - * which will be recorded (if possible) in the journal superblock. This - * allows a client to record failure conditions in the middle of a - * transaction without having to complete the transaction to record the - * failure to disk. ext3_error, for example, now uses this - * functionality. - * - * Errors which originate from within the journaling layer will NOT - * supply an errno; a null errno implies that absolutely no further - * writes are done to the journal (unless there are any already in - * progress). - * - */ - -void jbd2_journal_abort(journal_t *journal, int errno) -{ - __journal_abort_soft(journal, errno); -} - -/** - * int jbd2_journal_errno () - returns the journal's error state. - * @journal: journal to examine. - * - * This is the errno number set with jbd2_journal_abort(), the last - * time the journal was mounted - if the journal was stopped - * without calling abort this will be 0. - * - * If the journal has been aborted on this mount time -EROFS will - * be returned. - */ -int jbd2_journal_errno(journal_t *journal) -{ - int err; - - read_lock(&journal->j_state_lock); - if (journal->j_flags & JBD2_ABORT) - err = -EROFS; - else - err = journal->j_errno; - read_unlock(&journal->j_state_lock); - return err; -} - -/** - * int jbd2_journal_clear_err () - clears the journal's error state - * @journal: journal to act on. - * - * An error must be cleared or acked to take a FS out of readonly - * mode. - */ -int jbd2_journal_clear_err(journal_t *journal) -{ - int err = 0; - - write_lock(&journal->j_state_lock); - if (journal->j_flags & JBD2_ABORT) - err = -EROFS; - else - journal->j_errno = 0; - write_unlock(&journal->j_state_lock); - return err; -} - -/** - * void jbd2_journal_ack_err() - Ack journal err. - * @journal: journal to act on. - * - * An error must be cleared or acked to take a FS out of readonly - * mode. - */ -void jbd2_journal_ack_err(journal_t *journal) -{ - write_lock(&journal->j_state_lock); - if (journal->j_errno) - journal->j_flags |= JBD2_ACK_ERR; - write_unlock(&journal->j_state_lock); -} - -int jbd2_journal_blocks_per_page(struct inode *inode) -{ - return 1 << (PAGE_SHIFT - inode->i_sb->s_blocksize_bits); -} - -/* - * helper functions to deal with 32 or 64bit block numbers. - */ -size_t journal_tag_bytes(journal_t *journal) -{ - size_t sz; - - if (jbd2_has_feature_csum3(journal)) - return sizeof(journal_block_tag3_t); - - sz = sizeof(journal_block_tag_t); - - if (jbd2_has_feature_csum2(journal)) - sz += sizeof(__u16); - - if (jbd2_has_feature_64bit(journal)) - return sz; - else - return sz - sizeof(__u32); -} - -/* - * JBD memory management - * - * These functions are used to allocate block-sized chunks of memory - * used for making copies of buffer_head data. Very often it will be - * page-sized chunks of data, but sometimes it will be in - * sub-page-size chunks. (For example, 16k pages on Power systems - * with a 4k block file system.) For blocks smaller than a page, we - * use a SLAB allocator. There are slab caches for each block size, - * which are allocated at mount time, if necessary, and we only free - * (all of) the slab caches when/if the jbd2 module is unloaded. For - * this reason we don't need to a mutex to protect access to - * jbd2_slab[] allocating or releasing memory; only in - * jbd2_journal_create_slab(). - */ -#define JBD2_MAX_SLABS 8 -static struct kmem_cache *jbd2_slab[JBD2_MAX_SLABS]; - -static const char *jbd2_slab_names[JBD2_MAX_SLABS] = { - "jbd2_1k", "jbd2_2k", "jbd2_4k", "jbd2_8k", - "jbd2_16k", "jbd2_32k", "jbd2_64k", "jbd2_128k" -}; - - -static void jbd2_journal_destroy_slabs(void) -{ - int i; - - for (i = 0; i < JBD2_MAX_SLABS; i++) { - if (jbd2_slab[i]) - kmem_cache_destroy(jbd2_slab[i]); - jbd2_slab[i] = NULL; - } -} - -static int jbd2_journal_create_slab(size_t size) -{ - static DEFINE_MUTEX(jbd2_slab_create_mutex); - int i = order_base_2(size) - 10; - size_t slab_size; - - if (size == PAGE_SIZE) - return 0; - - if (i >= JBD2_MAX_SLABS) - return -EINVAL; - - if (unlikely(i < 0)) - i = 0; - mutex_lock(&jbd2_slab_create_mutex); - if (jbd2_slab[i]) { - mutex_unlock(&jbd2_slab_create_mutex); - return 0; /* Already created */ - } - - slab_size = 1 << (i+10); - jbd2_slab[i] = kmem_cache_create(jbd2_slab_names[i], slab_size, - slab_size, 0, NULL); - mutex_unlock(&jbd2_slab_create_mutex); - if (!jbd2_slab[i]) { - printk(KERN_EMERG "JBD2: no memory for jbd2_slab cache\n"); - return -ENOMEM; - } - return 0; -} - -static struct kmem_cache *get_slab(size_t size) -{ - int i = order_base_2(size) - 10; - - BUG_ON(i >= JBD2_MAX_SLABS); - if (unlikely(i < 0)) - i = 0; - BUG_ON(jbd2_slab[i] == NULL); - return jbd2_slab[i]; -} - -void *jbd2_alloc(size_t size, gfp_t flags) -{ - void *ptr; - - BUG_ON(size & (size-1)); /* Must be a power of 2 */ - - if (size < PAGE_SIZE) - ptr = kmem_cache_alloc(get_slab(size), flags); - else - ptr = (void *)__get_free_pages(flags, get_order(size)); - - /* Check alignment; SLUB has gotten this wrong in the past, - * and this can lead to user data corruption! */ - BUG_ON(((unsigned long) ptr) & (size-1)); - - return ptr; -} - -void jbd2_free(void *ptr, size_t size) -{ - if (size < PAGE_SIZE) - kmem_cache_free(get_slab(size), ptr); - else - free_pages((unsigned long)ptr, get_order(size)); -}; - -/* - * Journal_head storage management - */ -static struct kmem_cache *jbd2_journal_head_cache; -#ifdef CONFIG_JBD2_DEBUG -static atomic_t nr_journal_heads = ATOMIC_INIT(0); -#endif - -static int jbd2_journal_init_journal_head_cache(void) -{ - int retval; - - J_ASSERT(jbd2_journal_head_cache == NULL); - jbd2_journal_head_cache = kmem_cache_create("jbd2_journal_head", - sizeof(struct journal_head), - 0, /* offset */ - SLAB_TEMPORARY | SLAB_DESTROY_BY_RCU, - NULL); /* ctor */ - retval = 0; - if (!jbd2_journal_head_cache) { - retval = -ENOMEM; - printk(KERN_EMERG "JBD2: no memory for journal_head cache\n"); - } - return retval; -} - -static void jbd2_journal_destroy_journal_head_cache(void) -{ - if (jbd2_journal_head_cache) { - kmem_cache_destroy(jbd2_journal_head_cache); - jbd2_journal_head_cache = NULL; - } -} - -/* - * journal_head splicing and dicing - */ -static struct journal_head *journal_alloc_journal_head(void) -{ - struct journal_head *ret; - -#ifdef CONFIG_JBD2_DEBUG - atomic_inc(&nr_journal_heads); -#endif - ret = kmem_cache_zalloc(jbd2_journal_head_cache, GFP_NOFS); - if (!ret) { - jbd_debug(1, "out of memory for journal_head\n"); - pr_notice_ratelimited("ENOMEM in %s, retrying.\n", __func__); - ret = kmem_cache_zalloc(jbd2_journal_head_cache, - GFP_NOFS | __GFP_NOFAIL); - } - return ret; -} - -static void journal_free_journal_head(struct journal_head *jh) -{ -#ifdef CONFIG_JBD2_DEBUG - atomic_dec(&nr_journal_heads); - memset(jh, JBD2_POISON_FREE, sizeof(*jh)); -#endif - kmem_cache_free(jbd2_journal_head_cache, jh); -} - -/* - * A journal_head is attached to a buffer_head whenever JBD has an - * interest in the buffer. - * - * Whenever a buffer has an attached journal_head, its ->b_state:BH_JBD bit - * is set. This bit is tested in core kernel code where we need to take - * JBD-specific actions. Testing the zeroness of ->b_private is not reliable - * there. - * - * When a buffer has its BH_JBD bit set, its ->b_count is elevated by one. - * - * When a buffer has its BH_JBD bit set it is immune from being released by - * core kernel code, mainly via ->b_count. - * - * A journal_head is detached from its buffer_head when the journal_head's - * b_jcount reaches zero. Running transaction (b_transaction) and checkpoint - * transaction (b_cp_transaction) hold their references to b_jcount. - * - * Various places in the kernel want to attach a journal_head to a buffer_head - * _before_ attaching the journal_head to a transaction. To protect the - * journal_head in this situation, jbd2_journal_add_journal_head elevates the - * journal_head's b_jcount refcount by one. The caller must call - * jbd2_journal_put_journal_head() to undo this. - * - * So the typical usage would be: - * - * (Attach a journal_head if needed. Increments b_jcount) - * struct journal_head *jh = jbd2_journal_add_journal_head(bh); - * ... - * (Get another reference for transaction) - * jbd2_journal_grab_journal_head(bh); - * jh->b_transaction = xxx; - * (Put original reference) - * jbd2_journal_put_journal_head(jh); - */ - -/* - * Give a buffer_head a journal_head. - * - * May sleep. - */ -struct journal_head *jbd2_journal_add_journal_head(struct buffer_head *bh) -{ - struct journal_head *jh; - struct journal_head *new_jh = NULL; - -repeat: - if (!buffer_jbd(bh)) - new_jh = journal_alloc_journal_head(); - - jbd_lock_bh_journal_head(bh); - if (buffer_jbd(bh)) { - jh = bh2jh(bh); - } else { - J_ASSERT_BH(bh, - (atomic_read(&bh->b_count) > 0) || - (bh->b_page && bh->b_page->mapping)); - - if (!new_jh) { - jbd_unlock_bh_journal_head(bh); - goto repeat; - } - - jh = new_jh; - new_jh = NULL; /* We consumed it */ - set_buffer_jbd(bh); - bh->b_private = jh; - jh->b_bh = bh; - get_bh(bh); - BUFFER_TRACE(bh, "added journal_head"); - } - jh->b_jcount++; - jbd_unlock_bh_journal_head(bh); - if (new_jh) - journal_free_journal_head(new_jh); - return bh->b_private; -} - -/* - * Grab a ref against this buffer_head's journal_head. If it ended up not - * having a journal_head, return NULL - */ -struct journal_head *jbd2_journal_grab_journal_head(struct buffer_head *bh) -{ - struct journal_head *jh = NULL; - - jbd_lock_bh_journal_head(bh); - if (buffer_jbd(bh)) { - jh = bh2jh(bh); - jh->b_jcount++; - } - jbd_unlock_bh_journal_head(bh); - return jh; -} - -static void __journal_remove_journal_head(struct buffer_head *bh) -{ - struct journal_head *jh = bh2jh(bh); - - J_ASSERT_JH(jh, jh->b_jcount >= 0); - J_ASSERT_JH(jh, jh->b_transaction == NULL); - J_ASSERT_JH(jh, jh->b_next_transaction == NULL); - J_ASSERT_JH(jh, jh->b_cp_transaction == NULL); - J_ASSERT_JH(jh, jh->b_jlist == BJ_None); - J_ASSERT_BH(bh, buffer_jbd(bh)); - J_ASSERT_BH(bh, jh2bh(jh) == bh); - BUFFER_TRACE(bh, "remove journal_head"); - if (jh->b_frozen_data) { - printk(KERN_WARNING "%s: freeing b_frozen_data\n", __func__); - jbd2_free(jh->b_frozen_data, bh->b_size); - } - if (jh->b_committed_data) { - printk(KERN_WARNING "%s: freeing b_committed_data\n", __func__); - jbd2_free(jh->b_committed_data, bh->b_size); - } - bh->b_private = NULL; - jh->b_bh = NULL; /* debug, really */ - clear_buffer_jbd(bh); - journal_free_journal_head(jh); -} - -/* - * Drop a reference on the passed journal_head. If it fell to zero then - * release the journal_head from the buffer_head. - */ -void jbd2_journal_put_journal_head(struct journal_head *jh) -{ - struct buffer_head *bh = jh2bh(jh); - - jbd_lock_bh_journal_head(bh); - J_ASSERT_JH(jh, jh->b_jcount > 0); - --jh->b_jcount; - if (!jh->b_jcount) { - __journal_remove_journal_head(bh); - jbd_unlock_bh_journal_head(bh); - __brelse(bh); - } else - jbd_unlock_bh_journal_head(bh); -} - -/* - * Initialize jbd inode head - */ -void jbd2_journal_init_jbd_inode(struct jbd2_inode *jinode, struct inode *inode) -{ - jinode->i_transaction = NULL; - jinode->i_next_transaction = NULL; - jinode->i_vfs_inode = inode; - jinode->i_flags = 0; - INIT_LIST_HEAD(&jinode->i_list); -} - -/* - * Function to be called before we start removing inode from memory (i.e., - * clear_inode() is a fine place to be called from). It removes inode from - * transaction's lists. - */ -void jbd2_journal_release_jbd_inode(journal_t *journal, - struct jbd2_inode *jinode) -{ - if (!journal) - return; -restart: - spin_lock(&journal->j_list_lock); - /* Is commit writing out inode - we have to wait */ - if (jinode->i_flags & JI_COMMIT_RUNNING) { - wait_queue_head_t *wq; - DEFINE_WAIT_BIT(wait, &jinode->i_flags, __JI_COMMIT_RUNNING); - wq = bit_waitqueue(&jinode->i_flags, __JI_COMMIT_RUNNING); - prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE); - spin_unlock(&journal->j_list_lock); - schedule(); - finish_wait(wq, &wait.wait); - goto restart; - } - - if (jinode->i_transaction) { - list_del(&jinode->i_list); - jinode->i_transaction = NULL; - } - spin_unlock(&journal->j_list_lock); -} - - -#ifdef CONFIG_PROC_FS - -#define JBD2_STATS_PROC_NAME "fs/jbd2" - -static void __init jbd2_create_jbd_stats_proc_entry(void) -{ - proc_jbd2_stats = proc_mkdir(JBD2_STATS_PROC_NAME, NULL); -} - -static void __exit jbd2_remove_jbd_stats_proc_entry(void) -{ - if (proc_jbd2_stats) - remove_proc_entry(JBD2_STATS_PROC_NAME, NULL); -} - -#else - -#define jbd2_create_jbd_stats_proc_entry() do {} while (0) -#define jbd2_remove_jbd_stats_proc_entry() do {} while (0) - -#endif - -struct kmem_cache *jbd2_handle_cache, *jbd2_inode_cache; - -static int __init jbd2_journal_init_handle_cache(void) -{ - jbd2_handle_cache = KMEM_CACHE(jbd2_journal_handle, SLAB_TEMPORARY); - if (jbd2_handle_cache == NULL) { - printk(KERN_EMERG "JBD2: failed to create handle cache\n"); - return -ENOMEM; - } - jbd2_inode_cache = KMEM_CACHE(jbd2_inode, 0); - if (jbd2_inode_cache == NULL) { - printk(KERN_EMERG "JBD2: failed to create inode cache\n"); - kmem_cache_destroy(jbd2_handle_cache); - return -ENOMEM; - } - return 0; -} - -static void jbd2_journal_destroy_handle_cache(void) -{ - if (jbd2_handle_cache) - kmem_cache_destroy(jbd2_handle_cache); - if (jbd2_inode_cache) - kmem_cache_destroy(jbd2_inode_cache); - -} - -/* - * Module startup and shutdown - */ - -static int __init journal_init_caches(void) -{ - int ret; - - ret = jbd2_journal_init_revoke_caches(); - if (ret == 0) - ret = jbd2_journal_init_journal_head_cache(); - if (ret == 0) - ret = jbd2_journal_init_handle_cache(); - if (ret == 0) - ret = jbd2_journal_init_transaction_cache(); - return ret; -} - -static void jbd2_journal_destroy_caches(void) -{ - jbd2_journal_destroy_revoke_caches(); - jbd2_journal_destroy_journal_head_cache(); - jbd2_journal_destroy_handle_cache(); - jbd2_journal_destroy_transaction_cache(); - jbd2_journal_destroy_slabs(); -} - -static int __init journal_init(void) -{ - int ret; - - BUILD_BUG_ON(sizeof(struct journal_superblock_s) != 1024); - - ret = journal_init_caches(); - if (ret == 0) { - jbd2_create_jbd_stats_proc_entry(); - } else { - jbd2_journal_destroy_caches(); - } - return ret; -} - -static void __exit journal_exit(void) -{ -#ifdef CONFIG_JBD2_DEBUG - int n = atomic_read(&nr_journal_heads); - if (n) - printk(KERN_ERR "JBD2: leaked %d journal_heads!\n", n); -#endif - jbd2_remove_jbd_stats_proc_entry(); - jbd2_journal_destroy_caches(); -} - -MODULE_LICENSE("GPL"); -module_init(journal_init); -module_exit(journal_exit); - diff --git a/src/linux/fs/jbd2/recovery.c b/src/linux/fs/jbd2/recovery.c deleted file mode 100644 index 02dd336..0000000 --- a/src/linux/fs/jbd2/recovery.c +++ /dev/null @@ -1,855 +0,0 @@ -/* - * linux/fs/jbd2/recovery.c - * - * Written by Stephen C. Tweedie , 1999 - * - * Copyright 1999-2000 Red Hat Software --- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * Journal recovery routines for the generic filesystem journaling code; - * part of the ext2fs journaling system. - */ - -#ifndef __KERNEL__ -#include "jfs_user.h" -#else -#include -#include -#include -#include -#include -#include -#endif - -/* - * Maintain information about the progress of the recovery job, so that - * the different passes can carry information between them. - */ -struct recovery_info -{ - tid_t start_transaction; - tid_t end_transaction; - - int nr_replays; - int nr_revokes; - int nr_revoke_hits; -}; - -enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY}; -static int do_one_pass(journal_t *journal, - struct recovery_info *info, enum passtype pass); -static int scan_revoke_records(journal_t *, struct buffer_head *, - tid_t, struct recovery_info *); - -#ifdef __KERNEL__ - -/* Release readahead buffers after use */ -static void journal_brelse_array(struct buffer_head *b[], int n) -{ - while (--n >= 0) - brelse (b[n]); -} - - -/* - * When reading from the journal, we are going through the block device - * layer directly and so there is no readahead being done for us. We - * need to implement any readahead ourselves if we want it to happen at - * all. Recovery is basically one long sequential read, so make sure we - * do the IO in reasonably large chunks. - * - * This is not so critical that we need to be enormously clever about - * the readahead size, though. 128K is a purely arbitrary, good-enough - * fixed value. - */ - -#define MAXBUF 8 -static int do_readahead(journal_t *journal, unsigned int start) -{ - int err; - unsigned int max, nbufs, next; - unsigned long long blocknr; - struct buffer_head *bh; - - struct buffer_head * bufs[MAXBUF]; - - /* Do up to 128K of readahead */ - max = start + (128 * 1024 / journal->j_blocksize); - if (max > journal->j_maxlen) - max = journal->j_maxlen; - - /* Do the readahead itself. We'll submit MAXBUF buffer_heads at - * a time to the block device IO layer. */ - - nbufs = 0; - - for (next = start; next < max; next++) { - err = jbd2_journal_bmap(journal, next, &blocknr); - - if (err) { - printk(KERN_ERR "JBD2: bad block at offset %u\n", - next); - goto failed; - } - - bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); - if (!bh) { - err = -ENOMEM; - goto failed; - } - - if (!buffer_uptodate(bh) && !buffer_locked(bh)) { - bufs[nbufs++] = bh; - if (nbufs == MAXBUF) { - ll_rw_block(REQ_OP_READ, 0, nbufs, bufs); - journal_brelse_array(bufs, nbufs); - nbufs = 0; - } - } else - brelse(bh); - } - - if (nbufs) - ll_rw_block(REQ_OP_READ, 0, nbufs, bufs); - err = 0; - -failed: - if (nbufs) - journal_brelse_array(bufs, nbufs); - return err; -} - -#endif /* __KERNEL__ */ - - -/* - * Read a block from the journal - */ - -static int jread(struct buffer_head **bhp, journal_t *journal, - unsigned int offset) -{ - int err; - unsigned long long blocknr; - struct buffer_head *bh; - - *bhp = NULL; - - if (offset >= journal->j_maxlen) { - printk(KERN_ERR "JBD2: corrupted journal superblock\n"); - return -EFSCORRUPTED; - } - - err = jbd2_journal_bmap(journal, offset, &blocknr); - - if (err) { - printk(KERN_ERR "JBD2: bad block at offset %u\n", - offset); - return err; - } - - bh = __getblk(journal->j_dev, blocknr, journal->j_blocksize); - if (!bh) - return -ENOMEM; - - if (!buffer_uptodate(bh)) { - /* If this is a brand new buffer, start readahead. - Otherwise, we assume we are already reading it. */ - if (!buffer_req(bh)) - do_readahead(journal, offset); - wait_on_buffer(bh); - } - - if (!buffer_uptodate(bh)) { - printk(KERN_ERR "JBD2: Failed to read block at offset %u\n", - offset); - brelse(bh); - return -EIO; - } - - *bhp = bh; - return 0; -} - -static int jbd2_descriptor_block_csum_verify(journal_t *j, void *buf) -{ - struct jbd2_journal_block_tail *tail; - __be32 provided; - __u32 calculated; - - if (!jbd2_journal_has_csum_v2or3(j)) - return 1; - - tail = (struct jbd2_journal_block_tail *)(buf + j->j_blocksize - - sizeof(struct jbd2_journal_block_tail)); - provided = tail->t_checksum; - tail->t_checksum = 0; - calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); - tail->t_checksum = provided; - - return provided == cpu_to_be32(calculated); -} - -/* - * Count the number of in-use tags in a journal descriptor block. - */ - -static int count_tags(journal_t *journal, struct buffer_head *bh) -{ - char * tagp; - journal_block_tag_t * tag; - int nr = 0, size = journal->j_blocksize; - int tag_bytes = journal_tag_bytes(journal); - - if (jbd2_journal_has_csum_v2or3(journal)) - size -= sizeof(struct jbd2_journal_block_tail); - - tagp = &bh->b_data[sizeof(journal_header_t)]; - - while ((tagp - bh->b_data + tag_bytes) <= size) { - tag = (journal_block_tag_t *) tagp; - - nr++; - tagp += tag_bytes; - if (!(tag->t_flags & cpu_to_be16(JBD2_FLAG_SAME_UUID))) - tagp += 16; - - if (tag->t_flags & cpu_to_be16(JBD2_FLAG_LAST_TAG)) - break; - } - - return nr; -} - - -/* Make sure we wrap around the log correctly! */ -#define wrap(journal, var) \ -do { \ - if (var >= (journal)->j_last) \ - var -= ((journal)->j_last - (journal)->j_first); \ -} while (0) - -/** - * jbd2_journal_recover - recovers a on-disk journal - * @journal: the journal to recover - * - * The primary function for recovering the log contents when mounting a - * journaled device. - * - * Recovery is done in three passes. In the first pass, we look for the - * end of the log. In the second, we assemble the list of revoke - * blocks. In the third and final pass, we replay any un-revoked blocks - * in the log. - */ -int jbd2_journal_recover(journal_t *journal) -{ - int err, err2; - journal_superblock_t * sb; - - struct recovery_info info; - - memset(&info, 0, sizeof(info)); - sb = journal->j_superblock; - - /* - * The journal superblock's s_start field (the current log head) - * is always zero if, and only if, the journal was cleanly - * unmounted. - */ - - if (!sb->s_start) { - jbd_debug(1, "No recovery required, last transaction %d\n", - be32_to_cpu(sb->s_sequence)); - journal->j_transaction_sequence = be32_to_cpu(sb->s_sequence) + 1; - return 0; - } - - err = do_one_pass(journal, &info, PASS_SCAN); - if (!err) - err = do_one_pass(journal, &info, PASS_REVOKE); - if (!err) - err = do_one_pass(journal, &info, PASS_REPLAY); - - jbd_debug(1, "JBD2: recovery, exit status %d, " - "recovered transactions %u to %u\n", - err, info.start_transaction, info.end_transaction); - jbd_debug(1, "JBD2: Replayed %d and revoked %d/%d blocks\n", - info.nr_replays, info.nr_revoke_hits, info.nr_revokes); - - /* Restart the log at the next transaction ID, thus invalidating - * any existing commit records in the log. */ - journal->j_transaction_sequence = ++info.end_transaction; - - jbd2_journal_clear_revoke(journal); - err2 = sync_blockdev(journal->j_fs_dev); - if (!err) - err = err2; - /* Make sure all replayed data is on permanent storage */ - if (journal->j_flags & JBD2_BARRIER) { - err2 = blkdev_issue_flush(journal->j_fs_dev, GFP_KERNEL, NULL); - if (!err) - err = err2; - } - return err; -} - -/** - * jbd2_journal_skip_recovery - Start journal and wipe exiting records - * @journal: journal to startup - * - * Locate any valid recovery information from the journal and set up the - * journal structures in memory to ignore it (presumably because the - * caller has evidence that it is out of date). - * This function doesn't appear to be exported.. - * - * We perform one pass over the journal to allow us to tell the user how - * much recovery information is being erased, and to let us initialise - * the journal transaction sequence numbers to the next unused ID. - */ -int jbd2_journal_skip_recovery(journal_t *journal) -{ - int err; - - struct recovery_info info; - - memset (&info, 0, sizeof(info)); - - err = do_one_pass(journal, &info, PASS_SCAN); - - if (err) { - printk(KERN_ERR "JBD2: error %d scanning journal\n", err); - ++journal->j_transaction_sequence; - } else { -#ifdef CONFIG_JBD2_DEBUG - int dropped = info.end_transaction - - be32_to_cpu(journal->j_superblock->s_sequence); - jbd_debug(1, - "JBD2: ignoring %d transaction%s from the journal.\n", - dropped, (dropped == 1) ? "" : "s"); -#endif - journal->j_transaction_sequence = ++info.end_transaction; - } - - journal->j_tail = 0; - return err; -} - -static inline unsigned long long read_tag_block(journal_t *journal, - journal_block_tag_t *tag) -{ - unsigned long long block = be32_to_cpu(tag->t_blocknr); - if (jbd2_has_feature_64bit(journal)) - block |= (u64)be32_to_cpu(tag->t_blocknr_high) << 32; - return block; -} - -/* - * calc_chksums calculates the checksums for the blocks described in the - * descriptor block. - */ -static int calc_chksums(journal_t *journal, struct buffer_head *bh, - unsigned long *next_log_block, __u32 *crc32_sum) -{ - int i, num_blks, err; - unsigned long io_block; - struct buffer_head *obh; - - num_blks = count_tags(journal, bh); - /* Calculate checksum of the descriptor block. */ - *crc32_sum = crc32_be(*crc32_sum, (void *)bh->b_data, bh->b_size); - - for (i = 0; i < num_blks; i++) { - io_block = (*next_log_block)++; - wrap(journal, *next_log_block); - err = jread(&obh, journal, io_block); - if (err) { - printk(KERN_ERR "JBD2: IO error %d recovering block " - "%lu in log\n", err, io_block); - return 1; - } else { - *crc32_sum = crc32_be(*crc32_sum, (void *)obh->b_data, - obh->b_size); - } - put_bh(obh); - } - return 0; -} - -static int jbd2_commit_block_csum_verify(journal_t *j, void *buf) -{ - struct commit_header *h; - __be32 provided; - __u32 calculated; - - if (!jbd2_journal_has_csum_v2or3(j)) - return 1; - - h = buf; - provided = h->h_chksum[0]; - h->h_chksum[0] = 0; - calculated = jbd2_chksum(j, j->j_csum_seed, buf, j->j_blocksize); - h->h_chksum[0] = provided; - - return provided == cpu_to_be32(calculated); -} - -static int jbd2_block_tag_csum_verify(journal_t *j, journal_block_tag_t *tag, - void *buf, __u32 sequence) -{ - journal_block_tag3_t *tag3 = (journal_block_tag3_t *)tag; - __u32 csum32; - __be32 seq; - - if (!jbd2_journal_has_csum_v2or3(j)) - return 1; - - seq = cpu_to_be32(sequence); - csum32 = jbd2_chksum(j, j->j_csum_seed, (__u8 *)&seq, sizeof(seq)); - csum32 = jbd2_chksum(j, csum32, buf, j->j_blocksize); - - if (jbd2_has_feature_csum3(j)) - return tag3->t_checksum == cpu_to_be32(csum32); - else - return tag->t_checksum == cpu_to_be16(csum32); -} - -static int do_one_pass(journal_t *journal, - struct recovery_info *info, enum passtype pass) -{ - unsigned int first_commit_ID, next_commit_ID; - unsigned long next_log_block; - int err, success = 0; - journal_superblock_t * sb; - journal_header_t * tmp; - struct buffer_head * bh; - unsigned int sequence; - int blocktype; - int tag_bytes = journal_tag_bytes(journal); - __u32 crc32_sum = ~0; /* Transactional Checksums */ - int descr_csum_size = 0; - int block_error = 0; - - /* - * First thing is to establish what we expect to find in the log - * (in terms of transaction IDs), and where (in terms of log - * block offsets): query the superblock. - */ - - sb = journal->j_superblock; - next_commit_ID = be32_to_cpu(sb->s_sequence); - next_log_block = be32_to_cpu(sb->s_start); - - first_commit_ID = next_commit_ID; - if (pass == PASS_SCAN) - info->start_transaction = first_commit_ID; - - jbd_debug(1, "Starting recovery pass %d\n", pass); - - /* - * Now we walk through the log, transaction by transaction, - * making sure that each transaction has a commit block in the - * expected place. Each complete transaction gets replayed back - * into the main filesystem. - */ - - while (1) { - int flags; - char * tagp; - journal_block_tag_t * tag; - struct buffer_head * obh; - struct buffer_head * nbh; - - cond_resched(); - - /* If we already know where to stop the log traversal, - * check right now that we haven't gone past the end of - * the log. */ - - if (pass != PASS_SCAN) - if (tid_geq(next_commit_ID, info->end_transaction)) - break; - - jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n", - next_commit_ID, next_log_block, journal->j_last); - - /* Skip over each chunk of the transaction looking - * either the next descriptor block or the final commit - * record. */ - - jbd_debug(3, "JBD2: checking block %ld\n", next_log_block); - err = jread(&bh, journal, next_log_block); - if (err) - goto failed; - - next_log_block++; - wrap(journal, next_log_block); - - /* What kind of buffer is it? - * - * If it is a descriptor block, check that it has the - * expected sequence number. Otherwise, we're all done - * here. */ - - tmp = (journal_header_t *)bh->b_data; - - if (tmp->h_magic != cpu_to_be32(JBD2_MAGIC_NUMBER)) { - brelse(bh); - break; - } - - blocktype = be32_to_cpu(tmp->h_blocktype); - sequence = be32_to_cpu(tmp->h_sequence); - jbd_debug(3, "Found magic %d, sequence %d\n", - blocktype, sequence); - - if (sequence != next_commit_ID) { - brelse(bh); - break; - } - - /* OK, we have a valid descriptor block which matches - * all of the sequence number checks. What are we going - * to do with it? That depends on the pass... */ - - switch(blocktype) { - case JBD2_DESCRIPTOR_BLOCK: - /* Verify checksum first */ - if (jbd2_journal_has_csum_v2or3(journal)) - descr_csum_size = - sizeof(struct jbd2_journal_block_tail); - if (descr_csum_size > 0 && - !jbd2_descriptor_block_csum_verify(journal, - bh->b_data)) { - printk(KERN_ERR "JBD2: Invalid checksum " - "recovering block %lu in log\n", - next_log_block); - err = -EFSBADCRC; - brelse(bh); - goto failed; - } - - /* If it is a valid descriptor block, replay it - * in pass REPLAY; if journal_checksums enabled, then - * calculate checksums in PASS_SCAN, otherwise, - * just skip over the blocks it describes. */ - if (pass != PASS_REPLAY) { - if (pass == PASS_SCAN && - jbd2_has_feature_checksum(journal) && - !info->end_transaction) { - if (calc_chksums(journal, bh, - &next_log_block, - &crc32_sum)) { - put_bh(bh); - break; - } - put_bh(bh); - continue; - } - next_log_block += count_tags(journal, bh); - wrap(journal, next_log_block); - put_bh(bh); - continue; - } - - /* A descriptor block: we can now write all of - * the data blocks. Yay, useful work is finally - * getting done here! */ - - tagp = &bh->b_data[sizeof(journal_header_t)]; - while ((tagp - bh->b_data + tag_bytes) - <= journal->j_blocksize - descr_csum_size) { - unsigned long io_block; - - tag = (journal_block_tag_t *) tagp; - flags = be16_to_cpu(tag->t_flags); - - io_block = next_log_block++; - wrap(journal, next_log_block); - err = jread(&obh, journal, io_block); - if (err) { - /* Recover what we can, but - * report failure at the end. */ - success = err; - printk(KERN_ERR - "JBD2: IO error %d recovering " - "block %ld in log\n", - err, io_block); - } else { - unsigned long long blocknr; - - J_ASSERT(obh != NULL); - blocknr = read_tag_block(journal, - tag); - - /* If the block has been - * revoked, then we're all done - * here. */ - if (jbd2_journal_test_revoke - (journal, blocknr, - next_commit_ID)) { - brelse(obh); - ++info->nr_revoke_hits; - goto skip_write; - } - - /* Look for block corruption */ - if (!jbd2_block_tag_csum_verify( - journal, tag, obh->b_data, - be32_to_cpu(tmp->h_sequence))) { - brelse(obh); - success = -EFSBADCRC; - printk(KERN_ERR "JBD2: Invalid " - "checksum recovering " - "block %llu in log\n", - blocknr); - block_error = 1; - goto skip_write; - } - - /* Find a buffer for the new - * data being restored */ - nbh = __getblk(journal->j_fs_dev, - blocknr, - journal->j_blocksize); - if (nbh == NULL) { - printk(KERN_ERR - "JBD2: Out of memory " - "during recovery.\n"); - err = -ENOMEM; - brelse(bh); - brelse(obh); - goto failed; - } - - lock_buffer(nbh); - memcpy(nbh->b_data, obh->b_data, - journal->j_blocksize); - if (flags & JBD2_FLAG_ESCAPE) { - *((__be32 *)nbh->b_data) = - cpu_to_be32(JBD2_MAGIC_NUMBER); - } - - BUFFER_TRACE(nbh, "marking dirty"); - set_buffer_uptodate(nbh); - mark_buffer_dirty(nbh); - BUFFER_TRACE(nbh, "marking uptodate"); - ++info->nr_replays; - /* ll_rw_block(WRITE, 1, &nbh); */ - unlock_buffer(nbh); - brelse(obh); - brelse(nbh); - } - - skip_write: - tagp += tag_bytes; - if (!(flags & JBD2_FLAG_SAME_UUID)) - tagp += 16; - - if (flags & JBD2_FLAG_LAST_TAG) - break; - } - - brelse(bh); - continue; - - case JBD2_COMMIT_BLOCK: - /* How to differentiate between interrupted commit - * and journal corruption ? - * - * {nth transaction} - * Checksum Verification Failed - * | - * ____________________ - * | | - * async_commit sync_commit - * | | - * | GO TO NEXT "Journal Corruption" - * | TRANSACTION - * | - * {(n+1)th transanction} - * | - * _______|______________ - * | | - * Commit block found Commit block not found - * | | - * "Journal Corruption" | - * _____________|_________ - * | | - * nth trans corrupt OR nth trans - * and (n+1)th interrupted interrupted - * before commit block - * could reach the disk. - * (Cannot find the difference in above - * mentioned conditions. Hence assume - * "Interrupted Commit".) - */ - - /* Found an expected commit block: if checksums - * are present verify them in PASS_SCAN; else not - * much to do other than move on to the next sequence - * number. */ - if (pass == PASS_SCAN && - jbd2_has_feature_checksum(journal)) { - int chksum_err, chksum_seen; - struct commit_header *cbh = - (struct commit_header *)bh->b_data; - unsigned found_chksum = - be32_to_cpu(cbh->h_chksum[0]); - - chksum_err = chksum_seen = 0; - - if (info->end_transaction) { - journal->j_failed_commit = - info->end_transaction; - brelse(bh); - break; - } - - if (crc32_sum == found_chksum && - cbh->h_chksum_type == JBD2_CRC32_CHKSUM && - cbh->h_chksum_size == - JBD2_CRC32_CHKSUM_SIZE) - chksum_seen = 1; - else if (!(cbh->h_chksum_type == 0 && - cbh->h_chksum_size == 0 && - found_chksum == 0 && - !chksum_seen)) - /* - * If fs is mounted using an old kernel and then - * kernel with journal_chksum is used then we - * get a situation where the journal flag has - * checksum flag set but checksums are not - * present i.e chksum = 0, in the individual - * commit blocks. - * Hence to avoid checksum failures, in this - * situation, this extra check is added. - */ - chksum_err = 1; - - if (chksum_err) { - info->end_transaction = next_commit_ID; - - if (!jbd2_has_feature_async_commit(journal)) { - journal->j_failed_commit = - next_commit_ID; - brelse(bh); - break; - } - } - crc32_sum = ~0; - } - if (pass == PASS_SCAN && - !jbd2_commit_block_csum_verify(journal, - bh->b_data)) { - info->end_transaction = next_commit_ID; - - if (!jbd2_has_feature_async_commit(journal)) { - journal->j_failed_commit = - next_commit_ID; - brelse(bh); - break; - } - } - brelse(bh); - next_commit_ID++; - continue; - - case JBD2_REVOKE_BLOCK: - /* If we aren't in the REVOKE pass, then we can - * just skip over this block. */ - if (pass != PASS_REVOKE) { - brelse(bh); - continue; - } - - err = scan_revoke_records(journal, bh, - next_commit_ID, info); - brelse(bh); - if (err) - goto failed; - continue; - - default: - jbd_debug(3, "Unrecognised magic %d, end of scan.\n", - blocktype); - brelse(bh); - goto done; - } - } - - done: - /* - * We broke out of the log scan loop: either we came to the - * known end of the log or we found an unexpected block in the - * log. If the latter happened, then we know that the "current" - * transaction marks the end of the valid log. - */ - - if (pass == PASS_SCAN) { - if (!info->end_transaction) - info->end_transaction = next_commit_ID; - } else { - /* It's really bad news if different passes end up at - * different places (but possible due to IO errors). */ - if (info->end_transaction != next_commit_ID) { - printk(KERN_ERR "JBD2: recovery pass %d ended at " - "transaction %u, expected %u\n", - pass, next_commit_ID, info->end_transaction); - if (!success) - success = -EIO; - } - } - if (block_error && success == 0) - success = -EIO; - return success; - - failed: - return err; -} - -/* Scan a revoke record, marking all blocks mentioned as revoked. */ - -static int scan_revoke_records(journal_t *journal, struct buffer_head *bh, - tid_t sequence, struct recovery_info *info) -{ - jbd2_journal_revoke_header_t *header; - int offset, max; - int csum_size = 0; - __u32 rcount; - int record_len = 4; - - header = (jbd2_journal_revoke_header_t *) bh->b_data; - offset = sizeof(jbd2_journal_revoke_header_t); - rcount = be32_to_cpu(header->r_count); - - if (!jbd2_descriptor_block_csum_verify(journal, header)) - return -EFSBADCRC; - - if (jbd2_journal_has_csum_v2or3(journal)) - csum_size = sizeof(struct jbd2_journal_block_tail); - if (rcount > journal->j_blocksize - csum_size) - return -EINVAL; - max = rcount; - - if (jbd2_has_feature_64bit(journal)) - record_len = 8; - - while (offset + record_len <= max) { - unsigned long long blocknr; - int err; - - if (record_len == 4) - blocknr = be32_to_cpu(* ((__be32 *) (bh->b_data+offset))); - else - blocknr = be64_to_cpu(* ((__be64 *) (bh->b_data+offset))); - offset += record_len; - err = jbd2_journal_set_revoke(journal, blocknr, sequence); - if (err) - return err; - ++info->nr_revokes; - } - return 0; -} diff --git a/src/linux/fs/jbd2/revoke.c b/src/linux/fs/jbd2/revoke.c deleted file mode 100644 index 91171dc..0000000 --- a/src/linux/fs/jbd2/revoke.c +++ /dev/null @@ -1,737 +0,0 @@ -/* - * linux/fs/jbd2/revoke.c - * - * Written by Stephen C. Tweedie , 2000 - * - * Copyright 2000 Red Hat corp --- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * Journal revoke routines for the generic filesystem journaling code; - * part of the ext2fs journaling system. - * - * Revoke is the mechanism used to prevent old log records for deleted - * metadata from being replayed on top of newer data using the same - * blocks. The revoke mechanism is used in two separate places: - * - * + Commit: during commit we write the entire list of the current - * transaction's revoked blocks to the journal - * - * + Recovery: during recovery we record the transaction ID of all - * revoked blocks. If there are multiple revoke records in the log - * for a single block, only the last one counts, and if there is a log - * entry for a block beyond the last revoke, then that log entry still - * gets replayed. - * - * We can get interactions between revokes and new log data within a - * single transaction: - * - * Block is revoked and then journaled: - * The desired end result is the journaling of the new block, so we - * cancel the revoke before the transaction commits. - * - * Block is journaled and then revoked: - * The revoke must take precedence over the write of the block, so we - * need either to cancel the journal entry or to write the revoke - * later in the log than the log block. In this case, we choose the - * latter: journaling a block cancels any revoke record for that block - * in the current transaction, so any revoke for that block in the - * transaction must have happened after the block was journaled and so - * the revoke must take precedence. - * - * Block is revoked and then written as data: - * The data write is allowed to succeed, but the revoke is _not_ - * cancelled. We still need to prevent old log records from - * overwriting the new data. We don't even need to clear the revoke - * bit here. - * - * We cache revoke status of a buffer in the current transaction in b_states - * bits. As the name says, revokevalid flag indicates that the cached revoke - * status of a buffer is valid and we can rely on the cached status. - * - * Revoke information on buffers is a tri-state value: - * - * RevokeValid clear: no cached revoke status, need to look it up - * RevokeValid set, Revoked clear: - * buffer has not been revoked, and cancel_revoke - * need do nothing. - * RevokeValid set, Revoked set: - * buffer has been revoked. - * - * Locking rules: - * We keep two hash tables of revoke records. One hashtable belongs to the - * running transaction (is pointed to by journal->j_revoke), the other one - * belongs to the committing transaction. Accesses to the second hash table - * happen only from the kjournald and no other thread touches this table. Also - * journal_switch_revoke_table() which switches which hashtable belongs to the - * running and which to the committing transaction is called only from - * kjournald. Therefore we need no locks when accessing the hashtable belonging - * to the committing transaction. - * - * All users operating on the hash table belonging to the running transaction - * have a handle to the transaction. Therefore they are safe from kjournald - * switching hash tables under them. For operations on the lists of entries in - * the hash table j_revoke_lock is used. - * - * Finally, also replay code uses the hash tables but at this moment no one else - * can touch them (filesystem isn't mounted yet) and hence no locking is - * needed. - */ - -#ifndef __KERNEL__ -#include "jfs_user.h" -#else -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -static struct kmem_cache *jbd2_revoke_record_cache; -static struct kmem_cache *jbd2_revoke_table_cache; - -/* Each revoke record represents one single revoked block. During - journal replay, this involves recording the transaction ID of the - last transaction to revoke this block. */ - -struct jbd2_revoke_record_s -{ - struct list_head hash; - tid_t sequence; /* Used for recovery only */ - unsigned long long blocknr; -}; - - -/* The revoke table is just a simple hash table of revoke records. */ -struct jbd2_revoke_table_s -{ - /* It is conceivable that we might want a larger hash table - * for recovery. Must be a power of two. */ - int hash_size; - int hash_shift; - struct list_head *hash_table; -}; - - -#ifdef __KERNEL__ -static void write_one_revoke_record(transaction_t *, - struct list_head *, - struct buffer_head **, int *, - struct jbd2_revoke_record_s *); -static void flush_descriptor(journal_t *, struct buffer_head *, int); -#endif - -/* Utility functions to maintain the revoke table */ - -static inline int hash(journal_t *journal, unsigned long long block) -{ - return hash_64(block, journal->j_revoke->hash_shift); -} - -static int insert_revoke_hash(journal_t *journal, unsigned long long blocknr, - tid_t seq) -{ - struct list_head *hash_list; - struct jbd2_revoke_record_s *record; - gfp_t gfp_mask = GFP_NOFS; - - if (journal_oom_retry) - gfp_mask |= __GFP_NOFAIL; - record = kmem_cache_alloc(jbd2_revoke_record_cache, gfp_mask); - if (!record) - return -ENOMEM; - - record->sequence = seq; - record->blocknr = blocknr; - hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; - spin_lock(&journal->j_revoke_lock); - list_add(&record->hash, hash_list); - spin_unlock(&journal->j_revoke_lock); - return 0; -} - -/* Find a revoke record in the journal's hash table. */ - -static struct jbd2_revoke_record_s *find_revoke_record(journal_t *journal, - unsigned long long blocknr) -{ - struct list_head *hash_list; - struct jbd2_revoke_record_s *record; - - hash_list = &journal->j_revoke->hash_table[hash(journal, blocknr)]; - - spin_lock(&journal->j_revoke_lock); - record = (struct jbd2_revoke_record_s *) hash_list->next; - while (&(record->hash) != hash_list) { - if (record->blocknr == blocknr) { - spin_unlock(&journal->j_revoke_lock); - return record; - } - record = (struct jbd2_revoke_record_s *) record->hash.next; - } - spin_unlock(&journal->j_revoke_lock); - return NULL; -} - -void jbd2_journal_destroy_revoke_caches(void) -{ - if (jbd2_revoke_record_cache) { - kmem_cache_destroy(jbd2_revoke_record_cache); - jbd2_revoke_record_cache = NULL; - } - if (jbd2_revoke_table_cache) { - kmem_cache_destroy(jbd2_revoke_table_cache); - jbd2_revoke_table_cache = NULL; - } -} - -int __init jbd2_journal_init_revoke_caches(void) -{ - J_ASSERT(!jbd2_revoke_record_cache); - J_ASSERT(!jbd2_revoke_table_cache); - - jbd2_revoke_record_cache = KMEM_CACHE(jbd2_revoke_record_s, - SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY); - if (!jbd2_revoke_record_cache) - goto record_cache_failure; - - jbd2_revoke_table_cache = KMEM_CACHE(jbd2_revoke_table_s, - SLAB_TEMPORARY); - if (!jbd2_revoke_table_cache) - goto table_cache_failure; - return 0; -table_cache_failure: - jbd2_journal_destroy_revoke_caches(); -record_cache_failure: - return -ENOMEM; -} - -static struct jbd2_revoke_table_s *jbd2_journal_init_revoke_table(int hash_size) -{ - int shift = 0; - int tmp = hash_size; - struct jbd2_revoke_table_s *table; - - table = kmem_cache_alloc(jbd2_revoke_table_cache, GFP_KERNEL); - if (!table) - goto out; - - while((tmp >>= 1UL) != 0UL) - shift++; - - table->hash_size = hash_size; - table->hash_shift = shift; - table->hash_table = - kmalloc(hash_size * sizeof(struct list_head), GFP_KERNEL); - if (!table->hash_table) { - kmem_cache_free(jbd2_revoke_table_cache, table); - table = NULL; - goto out; - } - - for (tmp = 0; tmp < hash_size; tmp++) - INIT_LIST_HEAD(&table->hash_table[tmp]); - -out: - return table; -} - -static void jbd2_journal_destroy_revoke_table(struct jbd2_revoke_table_s *table) -{ - int i; - struct list_head *hash_list; - - for (i = 0; i < table->hash_size; i++) { - hash_list = &table->hash_table[i]; - J_ASSERT(list_empty(hash_list)); - } - - kfree(table->hash_table); - kmem_cache_free(jbd2_revoke_table_cache, table); -} - -/* Initialise the revoke table for a given journal to a given size. */ -int jbd2_journal_init_revoke(journal_t *journal, int hash_size) -{ - J_ASSERT(journal->j_revoke_table[0] == NULL); - J_ASSERT(is_power_of_2(hash_size)); - - journal->j_revoke_table[0] = jbd2_journal_init_revoke_table(hash_size); - if (!journal->j_revoke_table[0]) - goto fail0; - - journal->j_revoke_table[1] = jbd2_journal_init_revoke_table(hash_size); - if (!journal->j_revoke_table[1]) - goto fail1; - - journal->j_revoke = journal->j_revoke_table[1]; - - spin_lock_init(&journal->j_revoke_lock); - - return 0; - -fail1: - jbd2_journal_destroy_revoke_table(journal->j_revoke_table[0]); -fail0: - return -ENOMEM; -} - -/* Destroy a journal's revoke table. The table must already be empty! */ -void jbd2_journal_destroy_revoke(journal_t *journal) -{ - journal->j_revoke = NULL; - if (journal->j_revoke_table[0]) - jbd2_journal_destroy_revoke_table(journal->j_revoke_table[0]); - if (journal->j_revoke_table[1]) - jbd2_journal_destroy_revoke_table(journal->j_revoke_table[1]); -} - - -#ifdef __KERNEL__ - -/* - * jbd2_journal_revoke: revoke a given buffer_head from the journal. This - * prevents the block from being replayed during recovery if we take a - * crash after this current transaction commits. Any subsequent - * metadata writes of the buffer in this transaction cancel the - * revoke. - * - * Note that this call may block --- it is up to the caller to make - * sure that there are no further calls to journal_write_metadata - * before the revoke is complete. In ext3, this implies calling the - * revoke before clearing the block bitmap when we are deleting - * metadata. - * - * Revoke performs a jbd2_journal_forget on any buffer_head passed in as a - * parameter, but does _not_ forget the buffer_head if the bh was only - * found implicitly. - * - * bh_in may not be a journalled buffer - it may have come off - * the hash tables without an attached journal_head. - * - * If bh_in is non-zero, jbd2_journal_revoke() will decrement its b_count - * by one. - */ - -int jbd2_journal_revoke(handle_t *handle, unsigned long long blocknr, - struct buffer_head *bh_in) -{ - struct buffer_head *bh = NULL; - journal_t *journal; - struct block_device *bdev; - int err; - - might_sleep(); - if (bh_in) - BUFFER_TRACE(bh_in, "enter"); - - journal = handle->h_transaction->t_journal; - if (!jbd2_journal_set_features(journal, 0, 0, JBD2_FEATURE_INCOMPAT_REVOKE)){ - J_ASSERT (!"Cannot set revoke feature!"); - return -EINVAL; - } - - bdev = journal->j_fs_dev; - bh = bh_in; - - if (!bh) { - bh = __find_get_block(bdev, blocknr, journal->j_blocksize); - if (bh) - BUFFER_TRACE(bh, "found on hash"); - } -#ifdef JBD2_EXPENSIVE_CHECKING - else { - struct buffer_head *bh2; - - /* If there is a different buffer_head lying around in - * memory anywhere... */ - bh2 = __find_get_block(bdev, blocknr, journal->j_blocksize); - if (bh2) { - /* ... and it has RevokeValid status... */ - if (bh2 != bh && buffer_revokevalid(bh2)) - /* ...then it better be revoked too, - * since it's illegal to create a revoke - * record against a buffer_head which is - * not marked revoked --- that would - * risk missing a subsequent revoke - * cancel. */ - J_ASSERT_BH(bh2, buffer_revoked(bh2)); - put_bh(bh2); - } - } -#endif - - /* We really ought not ever to revoke twice in a row without - first having the revoke cancelled: it's illegal to free a - block twice without allocating it in between! */ - if (bh) { - if (!J_EXPECT_BH(bh, !buffer_revoked(bh), - "inconsistent data on disk")) { - if (!bh_in) - brelse(bh); - return -EIO; - } - set_buffer_revoked(bh); - set_buffer_revokevalid(bh); - if (bh_in) { - BUFFER_TRACE(bh_in, "call jbd2_journal_forget"); - jbd2_journal_forget(handle, bh_in); - } else { - BUFFER_TRACE(bh, "call brelse"); - __brelse(bh); - } - } - - jbd_debug(2, "insert revoke for block %llu, bh_in=%p\n",blocknr, bh_in); - err = insert_revoke_hash(journal, blocknr, - handle->h_transaction->t_tid); - BUFFER_TRACE(bh_in, "exit"); - return err; -} - -/* - * Cancel an outstanding revoke. For use only internally by the - * journaling code (called from jbd2_journal_get_write_access). - * - * We trust buffer_revoked() on the buffer if the buffer is already - * being journaled: if there is no revoke pending on the buffer, then we - * don't do anything here. - * - * This would break if it were possible for a buffer to be revoked and - * discarded, and then reallocated within the same transaction. In such - * a case we would have lost the revoked bit, but when we arrived here - * the second time we would still have a pending revoke to cancel. So, - * do not trust the Revoked bit on buffers unless RevokeValid is also - * set. - */ -int jbd2_journal_cancel_revoke(handle_t *handle, struct journal_head *jh) -{ - struct jbd2_revoke_record_s *record; - journal_t *journal = handle->h_transaction->t_journal; - int need_cancel; - int did_revoke = 0; /* akpm: debug */ - struct buffer_head *bh = jh2bh(jh); - - jbd_debug(4, "journal_head %p, cancelling revoke\n", jh); - - /* Is the existing Revoke bit valid? If so, we trust it, and - * only perform the full cancel if the revoke bit is set. If - * not, we can't trust the revoke bit, and we need to do the - * full search for a revoke record. */ - if (test_set_buffer_revokevalid(bh)) { - need_cancel = test_clear_buffer_revoked(bh); - } else { - need_cancel = 1; - clear_buffer_revoked(bh); - } - - if (need_cancel) { - record = find_revoke_record(journal, bh->b_blocknr); - if (record) { - jbd_debug(4, "cancelled existing revoke on " - "blocknr %llu\n", (unsigned long long)bh->b_blocknr); - spin_lock(&journal->j_revoke_lock); - list_del(&record->hash); - spin_unlock(&journal->j_revoke_lock); - kmem_cache_free(jbd2_revoke_record_cache, record); - did_revoke = 1; - } - } - -#ifdef JBD2_EXPENSIVE_CHECKING - /* There better not be one left behind by now! */ - record = find_revoke_record(journal, bh->b_blocknr); - J_ASSERT_JH(jh, record == NULL); -#endif - - /* Finally, have we just cleared revoke on an unhashed - * buffer_head? If so, we'd better make sure we clear the - * revoked status on any hashed alias too, otherwise the revoke - * state machine will get very upset later on. */ - if (need_cancel) { - struct buffer_head *bh2; - bh2 = __find_get_block(bh->b_bdev, bh->b_blocknr, bh->b_size); - if (bh2) { - if (bh2 != bh) - clear_buffer_revoked(bh2); - __brelse(bh2); - } - } - return did_revoke; -} - -/* - * journal_clear_revoked_flag clears revoked flag of buffers in - * revoke table to reflect there is no revoked buffers in the next - * transaction which is going to be started. - */ -void jbd2_clear_buffer_revoked_flags(journal_t *journal) -{ - struct jbd2_revoke_table_s *revoke = journal->j_revoke; - int i = 0; - - for (i = 0; i < revoke->hash_size; i++) { - struct list_head *hash_list; - struct list_head *list_entry; - hash_list = &revoke->hash_table[i]; - - list_for_each(list_entry, hash_list) { - struct jbd2_revoke_record_s *record; - struct buffer_head *bh; - record = (struct jbd2_revoke_record_s *)list_entry; - bh = __find_get_block(journal->j_fs_dev, - record->blocknr, - journal->j_blocksize); - if (bh) { - clear_buffer_revoked(bh); - __brelse(bh); - } - } - } -} - -/* journal_switch_revoke table select j_revoke for next transaction - * we do not want to suspend any processing until all revokes are - * written -bzzz - */ -void jbd2_journal_switch_revoke_table(journal_t *journal) -{ - int i; - - if (journal->j_revoke == journal->j_revoke_table[0]) - journal->j_revoke = journal->j_revoke_table[1]; - else - journal->j_revoke = journal->j_revoke_table[0]; - - for (i = 0; i < journal->j_revoke->hash_size; i++) - INIT_LIST_HEAD(&journal->j_revoke->hash_table[i]); -} - -/* - * Write revoke records to the journal for all entries in the current - * revoke hash, deleting the entries as we go. - */ -void jbd2_journal_write_revoke_records(transaction_t *transaction, - struct list_head *log_bufs) -{ - journal_t *journal = transaction->t_journal; - struct buffer_head *descriptor; - struct jbd2_revoke_record_s *record; - struct jbd2_revoke_table_s *revoke; - struct list_head *hash_list; - int i, offset, count; - - descriptor = NULL; - offset = 0; - count = 0; - - /* select revoke table for committing transaction */ - revoke = journal->j_revoke == journal->j_revoke_table[0] ? - journal->j_revoke_table[1] : journal->j_revoke_table[0]; - - for (i = 0; i < revoke->hash_size; i++) { - hash_list = &revoke->hash_table[i]; - - while (!list_empty(hash_list)) { - record = (struct jbd2_revoke_record_s *) - hash_list->next; - write_one_revoke_record(transaction, log_bufs, - &descriptor, &offset, record); - count++; - list_del(&record->hash); - kmem_cache_free(jbd2_revoke_record_cache, record); - } - } - if (descriptor) - flush_descriptor(journal, descriptor, offset); - jbd_debug(1, "Wrote %d revoke records\n", count); -} - -/* - * Write out one revoke record. We need to create a new descriptor - * block if the old one is full or if we have not already created one. - */ - -static void write_one_revoke_record(transaction_t *transaction, - struct list_head *log_bufs, - struct buffer_head **descriptorp, - int *offsetp, - struct jbd2_revoke_record_s *record) -{ - journal_t *journal = transaction->t_journal; - int csum_size = 0; - struct buffer_head *descriptor; - int sz, offset; - - /* If we are already aborting, this all becomes a noop. We - still need to go round the loop in - jbd2_journal_write_revoke_records in order to free all of the - revoke records: only the IO to the journal is omitted. */ - if (is_journal_aborted(journal)) - return; - - descriptor = *descriptorp; - offset = *offsetp; - - /* Do we need to leave space at the end for a checksum? */ - if (jbd2_journal_has_csum_v2or3(journal)) - csum_size = sizeof(struct jbd2_journal_block_tail); - - if (jbd2_has_feature_64bit(journal)) - sz = 8; - else - sz = 4; - - /* Make sure we have a descriptor with space left for the record */ - if (descriptor) { - if (offset + sz > journal->j_blocksize - csum_size) { - flush_descriptor(journal, descriptor, offset); - descriptor = NULL; - } - } - - if (!descriptor) { - descriptor = jbd2_journal_get_descriptor_buffer(transaction, - JBD2_REVOKE_BLOCK); - if (!descriptor) - return; - - /* Record it so that we can wait for IO completion later */ - BUFFER_TRACE(descriptor, "file in log_bufs"); - jbd2_file_log_bh(log_bufs, descriptor); - - offset = sizeof(jbd2_journal_revoke_header_t); - *descriptorp = descriptor; - } - - if (jbd2_has_feature_64bit(journal)) - * ((__be64 *)(&descriptor->b_data[offset])) = - cpu_to_be64(record->blocknr); - else - * ((__be32 *)(&descriptor->b_data[offset])) = - cpu_to_be32(record->blocknr); - offset += sz; - - *offsetp = offset; -} - -/* - * Flush a revoke descriptor out to the journal. If we are aborting, - * this is a noop; otherwise we are generating a buffer which needs to - * be waited for during commit, so it has to go onto the appropriate - * journal buffer list. - */ - -static void flush_descriptor(journal_t *journal, - struct buffer_head *descriptor, - int offset) -{ - jbd2_journal_revoke_header_t *header; - - if (is_journal_aborted(journal)) { - put_bh(descriptor); - return; - } - - header = (jbd2_journal_revoke_header_t *)descriptor->b_data; - header->r_count = cpu_to_be32(offset); - jbd2_descriptor_block_csum_set(journal, descriptor); - - set_buffer_jwrite(descriptor); - BUFFER_TRACE(descriptor, "write"); - set_buffer_dirty(descriptor); - write_dirty_buffer(descriptor, WRITE_SYNC); -} -#endif - -/* - * Revoke support for recovery. - * - * Recovery needs to be able to: - * - * record all revoke records, including the tid of the latest instance - * of each revoke in the journal - * - * check whether a given block in a given transaction should be replayed - * (ie. has not been revoked by a revoke record in that or a subsequent - * transaction) - * - * empty the revoke table after recovery. - */ - -/* - * First, setting revoke records. We create a new revoke record for - * every block ever revoked in the log as we scan it for recovery, and - * we update the existing records if we find multiple revokes for a - * single block. - */ - -int jbd2_journal_set_revoke(journal_t *journal, - unsigned long long blocknr, - tid_t sequence) -{ - struct jbd2_revoke_record_s *record; - - record = find_revoke_record(journal, blocknr); - if (record) { - /* If we have multiple occurrences, only record the - * latest sequence number in the hashed record */ - if (tid_gt(sequence, record->sequence)) - record->sequence = sequence; - return 0; - } - return insert_revoke_hash(journal, blocknr, sequence); -} - -/* - * Test revoke records. For a given block referenced in the log, has - * that block been revoked? A revoke record with a given transaction - * sequence number revokes all blocks in that transaction and earlier - * ones, but later transactions still need replayed. - */ - -int jbd2_journal_test_revoke(journal_t *journal, - unsigned long long blocknr, - tid_t sequence) -{ - struct jbd2_revoke_record_s *record; - - record = find_revoke_record(journal, blocknr); - if (!record) - return 0; - if (tid_gt(sequence, record->sequence)) - return 0; - return 1; -} - -/* - * Finally, once recovery is over, we need to clear the revoke table so - * that it can be reused by the running filesystem. - */ - -void jbd2_journal_clear_revoke(journal_t *journal) -{ - int i; - struct list_head *hash_list; - struct jbd2_revoke_record_s *record; - struct jbd2_revoke_table_s *revoke; - - revoke = journal->j_revoke; - - for (i = 0; i < revoke->hash_size; i++) { - hash_list = &revoke->hash_table[i]; - while (!list_empty(hash_list)) { - record = (struct jbd2_revoke_record_s*) hash_list->next; - list_del(&record->hash); - kmem_cache_free(jbd2_revoke_record_cache, record); - } - } -} diff --git a/src/linux/fs/jbd2/transaction.c b/src/linux/fs/jbd2/transaction.c deleted file mode 100644 index e165266..0000000 --- a/src/linux/fs/jbd2/transaction.c +++ /dev/null @@ -1,2589 +0,0 @@ -/* - * linux/fs/jbd2/transaction.c - * - * Written by Stephen C. Tweedie , 1998 - * - * Copyright 1998 Red Hat corp --- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * Generic filesystem transaction handling code; part of the ext2fs - * journaling system. - * - * This file manages transactions (compound commits managed by the - * journaling code) and handles (individual atomic operations by the - * filesystem). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh); -static void __jbd2_journal_unfile_buffer(struct journal_head *jh); - -static struct kmem_cache *transaction_cache; -int __init jbd2_journal_init_transaction_cache(void) -{ - J_ASSERT(!transaction_cache); - transaction_cache = kmem_cache_create("jbd2_transaction_s", - sizeof(transaction_t), - 0, - SLAB_HWCACHE_ALIGN|SLAB_TEMPORARY, - NULL); - if (transaction_cache) - return 0; - return -ENOMEM; -} - -void jbd2_journal_destroy_transaction_cache(void) -{ - if (transaction_cache) { - kmem_cache_destroy(transaction_cache); - transaction_cache = NULL; - } -} - -void jbd2_journal_free_transaction(transaction_t *transaction) -{ - if (unlikely(ZERO_OR_NULL_PTR(transaction))) - return; - kmem_cache_free(transaction_cache, transaction); -} - -/* - * jbd2_get_transaction: obtain a new transaction_t object. - * - * Simply allocate and initialise a new transaction. Create it in - * RUNNING state and add it to the current journal (which should not - * have an existing running transaction: we only make a new transaction - * once we have started to commit the old one). - * - * Preconditions: - * The journal MUST be locked. We don't perform atomic mallocs on the - * new transaction and we can't block without protecting against other - * processes trying to touch the journal while it is in transition. - * - */ - -static transaction_t * -jbd2_get_transaction(journal_t *journal, transaction_t *transaction) -{ - transaction->t_journal = journal; - transaction->t_state = T_RUNNING; - transaction->t_start_time = ktime_get(); - transaction->t_tid = journal->j_transaction_sequence++; - transaction->t_expires = jiffies + journal->j_commit_interval; - spin_lock_init(&transaction->t_handle_lock); - atomic_set(&transaction->t_updates, 0); - atomic_set(&transaction->t_outstanding_credits, - atomic_read(&journal->j_reserved_credits)); - atomic_set(&transaction->t_handle_count, 0); - INIT_LIST_HEAD(&transaction->t_inode_list); - INIT_LIST_HEAD(&transaction->t_private_list); - - /* Set up the commit timer for the new transaction. */ - journal->j_commit_timer.expires = round_jiffies_up(transaction->t_expires); - add_timer(&journal->j_commit_timer); - - J_ASSERT(journal->j_running_transaction == NULL); - journal->j_running_transaction = transaction; - transaction->t_max_wait = 0; - transaction->t_start = jiffies; - transaction->t_requested = 0; - - return transaction; -} - -/* - * Handle management. - * - * A handle_t is an object which represents a single atomic update to a - * filesystem, and which tracks all of the modifications which form part - * of that one update. - */ - -/* - * Update transaction's maximum wait time, if debugging is enabled. - * - * In order for t_max_wait to be reliable, it must be protected by a - * lock. But doing so will mean that start_this_handle() can not be - * run in parallel on SMP systems, which limits our scalability. So - * unless debugging is enabled, we no longer update t_max_wait, which - * means that maximum wait time reported by the jbd2_run_stats - * tracepoint will always be zero. - */ -static inline void update_t_max_wait(transaction_t *transaction, - unsigned long ts) -{ -#ifdef CONFIG_JBD2_DEBUG - if (jbd2_journal_enable_debug && - time_after(transaction->t_start, ts)) { - ts = jbd2_time_diff(ts, transaction->t_start); - spin_lock(&transaction->t_handle_lock); - if (ts > transaction->t_max_wait) - transaction->t_max_wait = ts; - spin_unlock(&transaction->t_handle_lock); - } -#endif -} - -/* - * Wait until running transaction passes T_LOCKED state. Also starts the commit - * if needed. The function expects running transaction to exist and releases - * j_state_lock. - */ -static void wait_transaction_locked(journal_t *journal) - __releases(journal->j_state_lock) -{ - DEFINE_WAIT(wait); - int need_to_start; - tid_t tid = journal->j_running_transaction->t_tid; - - prepare_to_wait(&journal->j_wait_transaction_locked, &wait, - TASK_UNINTERRUPTIBLE); - need_to_start = !tid_geq(journal->j_commit_request, tid); - read_unlock(&journal->j_state_lock); - if (need_to_start) - jbd2_log_start_commit(journal, tid); - jbd2_might_wait_for_commit(journal); - schedule(); - finish_wait(&journal->j_wait_transaction_locked, &wait); -} - -static void sub_reserved_credits(journal_t *journal, int blocks) -{ - atomic_sub(blocks, &journal->j_reserved_credits); - wake_up(&journal->j_wait_reserved); -} - -/* - * Wait until we can add credits for handle to the running transaction. Called - * with j_state_lock held for reading. Returns 0 if handle joined the running - * transaction. Returns 1 if we had to wait, j_state_lock is dropped, and - * caller must retry. - */ -static int add_transaction_credits(journal_t *journal, int blocks, - int rsv_blocks) -{ - transaction_t *t = journal->j_running_transaction; - int needed; - int total = blocks + rsv_blocks; - - /* - * If the current transaction is locked down for commit, wait - * for the lock to be released. - */ - if (t->t_state == T_LOCKED) { - wait_transaction_locked(journal); - return 1; - } - - /* - * If there is not enough space left in the log to write all - * potential buffers requested by this operation, we need to - * stall pending a log checkpoint to free some more log space. - */ - needed = atomic_add_return(total, &t->t_outstanding_credits); - if (needed > journal->j_max_transaction_buffers) { - /* - * If the current transaction is already too large, - * then start to commit it: we can then go back and - * attach this handle to a new transaction. - */ - atomic_sub(total, &t->t_outstanding_credits); - - /* - * Is the number of reserved credits in the current transaction too - * big to fit this handle? Wait until reserved credits are freed. - */ - if (atomic_read(&journal->j_reserved_credits) + total > - journal->j_max_transaction_buffers) { - read_unlock(&journal->j_state_lock); - jbd2_might_wait_for_commit(journal); - wait_event(journal->j_wait_reserved, - atomic_read(&journal->j_reserved_credits) + total <= - journal->j_max_transaction_buffers); - return 1; - } - - wait_transaction_locked(journal); - return 1; - } - - /* - * The commit code assumes that it can get enough log space - * without forcing a checkpoint. This is *critical* for - * correctness: a checkpoint of a buffer which is also - * associated with a committing transaction creates a deadlock, - * so commit simply cannot force through checkpoints. - * - * We must therefore ensure the necessary space in the journal - * *before* starting to dirty potentially checkpointed buffers - * in the new transaction. - */ - if (jbd2_log_space_left(journal) < jbd2_space_needed(journal)) { - atomic_sub(total, &t->t_outstanding_credits); - read_unlock(&journal->j_state_lock); - jbd2_might_wait_for_commit(journal); - write_lock(&journal->j_state_lock); - if (jbd2_log_space_left(journal) < jbd2_space_needed(journal)) - __jbd2_log_wait_for_space(journal); - write_unlock(&journal->j_state_lock); - return 1; - } - - /* No reservation? We are done... */ - if (!rsv_blocks) - return 0; - - needed = atomic_add_return(rsv_blocks, &journal->j_reserved_credits); - /* We allow at most half of a transaction to be reserved */ - if (needed > journal->j_max_transaction_buffers / 2) { - sub_reserved_credits(journal, rsv_blocks); - atomic_sub(total, &t->t_outstanding_credits); - read_unlock(&journal->j_state_lock); - jbd2_might_wait_for_commit(journal); - wait_event(journal->j_wait_reserved, - atomic_read(&journal->j_reserved_credits) + rsv_blocks - <= journal->j_max_transaction_buffers / 2); - return 1; - } - return 0; -} - -/* - * start_this_handle: Given a handle, deal with any locking or stalling - * needed to make sure that there is enough journal space for the handle - * to begin. Attach the handle to a transaction and set up the - * transaction's buffer credits. - */ - -static int start_this_handle(journal_t *journal, handle_t *handle, - gfp_t gfp_mask) -{ - transaction_t *transaction, *new_transaction = NULL; - int blocks = handle->h_buffer_credits; - int rsv_blocks = 0; - unsigned long ts = jiffies; - - if (handle->h_rsv_handle) - rsv_blocks = handle->h_rsv_handle->h_buffer_credits; - - /* - * Limit the number of reserved credits to 1/2 of maximum transaction - * size and limit the number of total credits to not exceed maximum - * transaction size per operation. - */ - if ((rsv_blocks > journal->j_max_transaction_buffers / 2) || - (rsv_blocks + blocks > journal->j_max_transaction_buffers)) { - printk(KERN_ERR "JBD2: %s wants too many credits " - "credits:%d rsv_credits:%d max:%d\n", - current->comm, blocks, rsv_blocks, - journal->j_max_transaction_buffers); - WARN_ON(1); - return -ENOSPC; - } - -alloc_transaction: - if (!journal->j_running_transaction) { - /* - * If __GFP_FS is not present, then we may be being called from - * inside the fs writeback layer, so we MUST NOT fail. - */ - if ((gfp_mask & __GFP_FS) == 0) - gfp_mask |= __GFP_NOFAIL; - new_transaction = kmem_cache_zalloc(transaction_cache, - gfp_mask); - if (!new_transaction) - return -ENOMEM; - } - - jbd_debug(3, "New handle %p going live.\n", handle); - - /* - * We need to hold j_state_lock until t_updates has been incremented, - * for proper journal barrier handling - */ -repeat: - read_lock(&journal->j_state_lock); - BUG_ON(journal->j_flags & JBD2_UNMOUNT); - if (is_journal_aborted(journal) || - (journal->j_errno != 0 && !(journal->j_flags & JBD2_ACK_ERR))) { - read_unlock(&journal->j_state_lock); - jbd2_journal_free_transaction(new_transaction); - return -EROFS; - } - - /* - * Wait on the journal's transaction barrier if necessary. Specifically - * we allow reserved handles to proceed because otherwise commit could - * deadlock on page writeback not being able to complete. - */ - if (!handle->h_reserved && journal->j_barrier_count) { - read_unlock(&journal->j_state_lock); - wait_event(journal->j_wait_transaction_locked, - journal->j_barrier_count == 0); - goto repeat; - } - - if (!journal->j_running_transaction) { - read_unlock(&journal->j_state_lock); - if (!new_transaction) - goto alloc_transaction; - write_lock(&journal->j_state_lock); - if (!journal->j_running_transaction && - (handle->h_reserved || !journal->j_barrier_count)) { - jbd2_get_transaction(journal, new_transaction); - new_transaction = NULL; - } - write_unlock(&journal->j_state_lock); - goto repeat; - } - - transaction = journal->j_running_transaction; - - if (!handle->h_reserved) { - /* We may have dropped j_state_lock - restart in that case */ - if (add_transaction_credits(journal, blocks, rsv_blocks)) - goto repeat; - } else { - /* - * We have handle reserved so we are allowed to join T_LOCKED - * transaction and we don't have to check for transaction size - * and journal space. - */ - sub_reserved_credits(journal, blocks); - handle->h_reserved = 0; - } - - /* OK, account for the buffers that this operation expects to - * use and add the handle to the running transaction. - */ - update_t_max_wait(transaction, ts); - handle->h_transaction = transaction; - handle->h_requested_credits = blocks; - handle->h_start_jiffies = jiffies; - atomic_inc(&transaction->t_updates); - atomic_inc(&transaction->t_handle_count); - jbd_debug(4, "Handle %p given %d credits (total %d, free %lu)\n", - handle, blocks, - atomic_read(&transaction->t_outstanding_credits), - jbd2_log_space_left(journal)); - read_unlock(&journal->j_state_lock); - current->journal_info = handle; - - rwsem_acquire_read(&journal->j_trans_commit_map, 0, 0, _THIS_IP_); - jbd2_journal_free_transaction(new_transaction); - return 0; -} - -/* Allocate a new handle. This should probably be in a slab... */ -static handle_t *new_handle(int nblocks) -{ - handle_t *handle = jbd2_alloc_handle(GFP_NOFS); - if (!handle) - return NULL; - handle->h_buffer_credits = nblocks; - handle->h_ref = 1; - - return handle; -} - -/** - * handle_t *jbd2_journal_start() - Obtain a new handle. - * @journal: Journal to start transaction on. - * @nblocks: number of block buffer we might modify - * - * We make sure that the transaction can guarantee at least nblocks of - * modified buffers in the log. We block until the log can guarantee - * that much space. Additionally, if rsv_blocks > 0, we also create another - * handle with rsv_blocks reserved blocks in the journal. This handle is - * is stored in h_rsv_handle. It is not attached to any particular transaction - * and thus doesn't block transaction commit. If the caller uses this reserved - * handle, it has to set h_rsv_handle to NULL as otherwise jbd2_journal_stop() - * on the parent handle will dispose the reserved one. Reserved handle has to - * be converted to a normal handle using jbd2_journal_start_reserved() before - * it can be used. - * - * Return a pointer to a newly allocated handle, or an ERR_PTR() value - * on failure. - */ -handle_t *jbd2__journal_start(journal_t *journal, int nblocks, int rsv_blocks, - gfp_t gfp_mask, unsigned int type, - unsigned int line_no) -{ - handle_t *handle = journal_current_handle(); - int err; - - if (!journal) - return ERR_PTR(-EROFS); - - if (handle) { - J_ASSERT(handle->h_transaction->t_journal == journal); - handle->h_ref++; - return handle; - } - - handle = new_handle(nblocks); - if (!handle) - return ERR_PTR(-ENOMEM); - if (rsv_blocks) { - handle_t *rsv_handle; - - rsv_handle = new_handle(rsv_blocks); - if (!rsv_handle) { - jbd2_free_handle(handle); - return ERR_PTR(-ENOMEM); - } - rsv_handle->h_reserved = 1; - rsv_handle->h_journal = journal; - handle->h_rsv_handle = rsv_handle; - } - - err = start_this_handle(journal, handle, gfp_mask); - if (err < 0) { - if (handle->h_rsv_handle) - jbd2_free_handle(handle->h_rsv_handle); - jbd2_free_handle(handle); - return ERR_PTR(err); - } - handle->h_type = type; - handle->h_line_no = line_no; - trace_jbd2_handle_start(journal->j_fs_dev->bd_dev, - handle->h_transaction->t_tid, type, - line_no, nblocks); - return handle; -} -EXPORT_SYMBOL(jbd2__journal_start); - - -handle_t *jbd2_journal_start(journal_t *journal, int nblocks) -{ - return jbd2__journal_start(journal, nblocks, 0, GFP_NOFS, 0, 0); -} -EXPORT_SYMBOL(jbd2_journal_start); - -void jbd2_journal_free_reserved(handle_t *handle) -{ - journal_t *journal = handle->h_journal; - - WARN_ON(!handle->h_reserved); - sub_reserved_credits(journal, handle->h_buffer_credits); - jbd2_free_handle(handle); -} -EXPORT_SYMBOL(jbd2_journal_free_reserved); - -/** - * int jbd2_journal_start_reserved(handle_t *handle) - start reserved handle - * @handle: handle to start - * - * Start handle that has been previously reserved with jbd2_journal_reserve(). - * This attaches @handle to the running transaction (or creates one if there's - * not transaction running). Unlike jbd2_journal_start() this function cannot - * block on journal commit, checkpointing, or similar stuff. It can block on - * memory allocation or frozen journal though. - * - * Return 0 on success, non-zero on error - handle is freed in that case. - */ -int jbd2_journal_start_reserved(handle_t *handle, unsigned int type, - unsigned int line_no) -{ - journal_t *journal = handle->h_journal; - int ret = -EIO; - - if (WARN_ON(!handle->h_reserved)) { - /* Someone passed in normal handle? Just stop it. */ - jbd2_journal_stop(handle); - return ret; - } - /* - * Usefulness of mixing of reserved and unreserved handles is - * questionable. So far nobody seems to need it so just error out. - */ - if (WARN_ON(current->journal_info)) { - jbd2_journal_free_reserved(handle); - return ret; - } - - handle->h_journal = NULL; - /* - * GFP_NOFS is here because callers are likely from writeback or - * similarly constrained call sites - */ - ret = start_this_handle(journal, handle, GFP_NOFS); - if (ret < 0) { - jbd2_journal_free_reserved(handle); - return ret; - } - handle->h_type = type; - handle->h_line_no = line_no; - return 0; -} -EXPORT_SYMBOL(jbd2_journal_start_reserved); - -/** - * int jbd2_journal_extend() - extend buffer credits. - * @handle: handle to 'extend' - * @nblocks: nr blocks to try to extend by. - * - * Some transactions, such as large extends and truncates, can be done - * atomically all at once or in several stages. The operation requests - * a credit for a number of buffer modifications in advance, but can - * extend its credit if it needs more. - * - * jbd2_journal_extend tries to give the running handle more buffer credits. - * It does not guarantee that allocation - this is a best-effort only. - * The calling process MUST be able to deal cleanly with a failure to - * extend here. - * - * Return 0 on success, non-zero on failure. - * - * return code < 0 implies an error - * return code > 0 implies normal transaction-full status. - */ -int jbd2_journal_extend(handle_t *handle, int nblocks) -{ - transaction_t *transaction = handle->h_transaction; - journal_t *journal; - int result; - int wanted; - - if (is_handle_aborted(handle)) - return -EROFS; - journal = transaction->t_journal; - - result = 1; - - read_lock(&journal->j_state_lock); - - /* Don't extend a locked-down transaction! */ - if (transaction->t_state != T_RUNNING) { - jbd_debug(3, "denied handle %p %d blocks: " - "transaction not running\n", handle, nblocks); - goto error_out; - } - - spin_lock(&transaction->t_handle_lock); - wanted = atomic_add_return(nblocks, - &transaction->t_outstanding_credits); - - if (wanted > journal->j_max_transaction_buffers) { - jbd_debug(3, "denied handle %p %d blocks: " - "transaction too large\n", handle, nblocks); - atomic_sub(nblocks, &transaction->t_outstanding_credits); - goto unlock; - } - - if (wanted + (wanted >> JBD2_CONTROL_BLOCKS_SHIFT) > - jbd2_log_space_left(journal)) { - jbd_debug(3, "denied handle %p %d blocks: " - "insufficient log space\n", handle, nblocks); - atomic_sub(nblocks, &transaction->t_outstanding_credits); - goto unlock; - } - - trace_jbd2_handle_extend(journal->j_fs_dev->bd_dev, - transaction->t_tid, - handle->h_type, handle->h_line_no, - handle->h_buffer_credits, - nblocks); - - handle->h_buffer_credits += nblocks; - handle->h_requested_credits += nblocks; - result = 0; - - jbd_debug(3, "extended handle %p by %d\n", handle, nblocks); -unlock: - spin_unlock(&transaction->t_handle_lock); -error_out: - read_unlock(&journal->j_state_lock); - return result; -} - - -/** - * int jbd2_journal_restart() - restart a handle . - * @handle: handle to restart - * @nblocks: nr credits requested - * - * Restart a handle for a multi-transaction filesystem - * operation. - * - * If the jbd2_journal_extend() call above fails to grant new buffer credits - * to a running handle, a call to jbd2_journal_restart will commit the - * handle's transaction so far and reattach the handle to a new - * transaction capable of guaranteeing the requested number of - * credits. We preserve reserved handle if there's any attached to the - * passed in handle. - */ -int jbd2__journal_restart(handle_t *handle, int nblocks, gfp_t gfp_mask) -{ - transaction_t *transaction = handle->h_transaction; - journal_t *journal; - tid_t tid; - int need_to_start, ret; - - /* If we've had an abort of any type, don't even think about - * actually doing the restart! */ - if (is_handle_aborted(handle)) - return 0; - journal = transaction->t_journal; - - /* - * First unlink the handle from its current transaction, and start the - * commit on that. - */ - J_ASSERT(atomic_read(&transaction->t_updates) > 0); - J_ASSERT(journal_current_handle() == handle); - - read_lock(&journal->j_state_lock); - spin_lock(&transaction->t_handle_lock); - atomic_sub(handle->h_buffer_credits, - &transaction->t_outstanding_credits); - if (handle->h_rsv_handle) { - sub_reserved_credits(journal, - handle->h_rsv_handle->h_buffer_credits); - } - if (atomic_dec_and_test(&transaction->t_updates)) - wake_up(&journal->j_wait_updates); - tid = transaction->t_tid; - spin_unlock(&transaction->t_handle_lock); - handle->h_transaction = NULL; - current->journal_info = NULL; - - jbd_debug(2, "restarting handle %p\n", handle); - need_to_start = !tid_geq(journal->j_commit_request, tid); - read_unlock(&journal->j_state_lock); - if (need_to_start) - jbd2_log_start_commit(journal, tid); - - rwsem_release(&journal->j_trans_commit_map, 1, _THIS_IP_); - handle->h_buffer_credits = nblocks; - ret = start_this_handle(journal, handle, gfp_mask); - return ret; -} -EXPORT_SYMBOL(jbd2__journal_restart); - - -int jbd2_journal_restart(handle_t *handle, int nblocks) -{ - return jbd2__journal_restart(handle, nblocks, GFP_NOFS); -} -EXPORT_SYMBOL(jbd2_journal_restart); - -/** - * void jbd2_journal_lock_updates () - establish a transaction barrier. - * @journal: Journal to establish a barrier on. - * - * This locks out any further updates from being started, and blocks - * until all existing updates have completed, returning only once the - * journal is in a quiescent state with no updates running. - * - * The journal lock should not be held on entry. - */ -void jbd2_journal_lock_updates(journal_t *journal) -{ - DEFINE_WAIT(wait); - - jbd2_might_wait_for_commit(journal); - - write_lock(&journal->j_state_lock); - ++journal->j_barrier_count; - - /* Wait until there are no reserved handles */ - if (atomic_read(&journal->j_reserved_credits)) { - write_unlock(&journal->j_state_lock); - wait_event(journal->j_wait_reserved, - atomic_read(&journal->j_reserved_credits) == 0); - write_lock(&journal->j_state_lock); - } - - /* Wait until there are no running updates */ - while (1) { - transaction_t *transaction = journal->j_running_transaction; - - if (!transaction) - break; - - spin_lock(&transaction->t_handle_lock); - prepare_to_wait(&journal->j_wait_updates, &wait, - TASK_UNINTERRUPTIBLE); - if (!atomic_read(&transaction->t_updates)) { - spin_unlock(&transaction->t_handle_lock); - finish_wait(&journal->j_wait_updates, &wait); - break; - } - spin_unlock(&transaction->t_handle_lock); - write_unlock(&journal->j_state_lock); - schedule(); - finish_wait(&journal->j_wait_updates, &wait); - write_lock(&journal->j_state_lock); - } - write_unlock(&journal->j_state_lock); - - /* - * We have now established a barrier against other normal updates, but - * we also need to barrier against other jbd2_journal_lock_updates() calls - * to make sure that we serialise special journal-locked operations - * too. - */ - mutex_lock(&journal->j_barrier); -} - -/** - * void jbd2_journal_unlock_updates (journal_t* journal) - release barrier - * @journal: Journal to release the barrier on. - * - * Release a transaction barrier obtained with jbd2_journal_lock_updates(). - * - * Should be called without the journal lock held. - */ -void jbd2_journal_unlock_updates (journal_t *journal) -{ - J_ASSERT(journal->j_barrier_count != 0); - - mutex_unlock(&journal->j_barrier); - write_lock(&journal->j_state_lock); - --journal->j_barrier_count; - write_unlock(&journal->j_state_lock); - wake_up(&journal->j_wait_transaction_locked); -} - -static void warn_dirty_buffer(struct buffer_head *bh) -{ - printk(KERN_WARNING - "JBD2: Spotted dirty metadata buffer (dev = %pg, blocknr = %llu). " - "There's a risk of filesystem corruption in case of system " - "crash.\n", - bh->b_bdev, (unsigned long long)bh->b_blocknr); -} - -/* Call t_frozen trigger and copy buffer data into jh->b_frozen_data. */ -static void jbd2_freeze_jh_data(struct journal_head *jh) -{ - struct page *page; - int offset; - char *source; - struct buffer_head *bh = jh2bh(jh); - - J_EXPECT_JH(jh, buffer_uptodate(bh), "Possible IO failure.\n"); - page = bh->b_page; - offset = offset_in_page(bh->b_data); - source = kmap_atomic(page); - /* Fire data frozen trigger just before we copy the data */ - jbd2_buffer_frozen_trigger(jh, source + offset, jh->b_triggers); - memcpy(jh->b_frozen_data, source + offset, bh->b_size); - kunmap_atomic(source); - - /* - * Now that the frozen data is saved off, we need to store any matching - * triggers. - */ - jh->b_frozen_triggers = jh->b_triggers; -} - -/* - * If the buffer is already part of the current transaction, then there - * is nothing we need to do. If it is already part of a prior - * transaction which we are still committing to disk, then we need to - * make sure that we do not overwrite the old copy: we do copy-out to - * preserve the copy going to disk. We also account the buffer against - * the handle's metadata buffer credits (unless the buffer is already - * part of the transaction, that is). - * - */ -static int -do_get_write_access(handle_t *handle, struct journal_head *jh, - int force_copy) -{ - struct buffer_head *bh; - transaction_t *transaction = handle->h_transaction; - journal_t *journal; - int error; - char *frozen_buffer = NULL; - unsigned long start_lock, time_lock; - - if (is_handle_aborted(handle)) - return -EROFS; - journal = transaction->t_journal; - - jbd_debug(5, "journal_head %p, force_copy %d\n", jh, force_copy); - - JBUFFER_TRACE(jh, "entry"); -repeat: - bh = jh2bh(jh); - - /* @@@ Need to check for errors here at some point. */ - - start_lock = jiffies; - lock_buffer(bh); - jbd_lock_bh_state(bh); - - /* If it takes too long to lock the buffer, trace it */ - time_lock = jbd2_time_diff(start_lock, jiffies); - if (time_lock > HZ/10) - trace_jbd2_lock_buffer_stall(bh->b_bdev->bd_dev, - jiffies_to_msecs(time_lock)); - - /* We now hold the buffer lock so it is safe to query the buffer - * state. Is the buffer dirty? - * - * If so, there are two possibilities. The buffer may be - * non-journaled, and undergoing a quite legitimate writeback. - * Otherwise, it is journaled, and we don't expect dirty buffers - * in that state (the buffers should be marked JBD_Dirty - * instead.) So either the IO is being done under our own - * control and this is a bug, or it's a third party IO such as - * dump(8) (which may leave the buffer scheduled for read --- - * ie. locked but not dirty) or tune2fs (which may actually have - * the buffer dirtied, ugh.) */ - - if (buffer_dirty(bh)) { - /* - * First question: is this buffer already part of the current - * transaction or the existing committing transaction? - */ - if (jh->b_transaction) { - J_ASSERT_JH(jh, - jh->b_transaction == transaction || - jh->b_transaction == - journal->j_committing_transaction); - if (jh->b_next_transaction) - J_ASSERT_JH(jh, jh->b_next_transaction == - transaction); - warn_dirty_buffer(bh); - } - /* - * In any case we need to clean the dirty flag and we must - * do it under the buffer lock to be sure we don't race - * with running write-out. - */ - JBUFFER_TRACE(jh, "Journalling dirty buffer"); - clear_buffer_dirty(bh); - set_buffer_jbddirty(bh); - } - - unlock_buffer(bh); - - error = -EROFS; - if (is_handle_aborted(handle)) { - jbd_unlock_bh_state(bh); - goto out; - } - error = 0; - - /* - * The buffer is already part of this transaction if b_transaction or - * b_next_transaction points to it - */ - if (jh->b_transaction == transaction || - jh->b_next_transaction == transaction) - goto done; - - /* - * this is the first time this transaction is touching this buffer, - * reset the modified flag - */ - jh->b_modified = 0; - - /* - * If the buffer is not journaled right now, we need to make sure it - * doesn't get written to disk before the caller actually commits the - * new data - */ - if (!jh->b_transaction) { - JBUFFER_TRACE(jh, "no transaction"); - J_ASSERT_JH(jh, !jh->b_next_transaction); - JBUFFER_TRACE(jh, "file as BJ_Reserved"); - /* - * Make sure all stores to jh (b_modified, b_frozen_data) are - * visible before attaching it to the running transaction. - * Paired with barrier in jbd2_write_access_granted() - */ - smp_wmb(); - spin_lock(&journal->j_list_lock); - __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved); - spin_unlock(&journal->j_list_lock); - goto done; - } - /* - * If there is already a copy-out version of this buffer, then we don't - * need to make another one - */ - if (jh->b_frozen_data) { - JBUFFER_TRACE(jh, "has frozen data"); - J_ASSERT_JH(jh, jh->b_next_transaction == NULL); - goto attach_next; - } - - JBUFFER_TRACE(jh, "owned by older transaction"); - J_ASSERT_JH(jh, jh->b_next_transaction == NULL); - J_ASSERT_JH(jh, jh->b_transaction == journal->j_committing_transaction); - - /* - * There is one case we have to be very careful about. If the - * committing transaction is currently writing this buffer out to disk - * and has NOT made a copy-out, then we cannot modify the buffer - * contents at all right now. The essence of copy-out is that it is - * the extra copy, not the primary copy, which gets journaled. If the - * primary copy is already going to disk then we cannot do copy-out - * here. - */ - if (buffer_shadow(bh)) { - JBUFFER_TRACE(jh, "on shadow: sleep"); - jbd_unlock_bh_state(bh); - wait_on_bit_io(&bh->b_state, BH_Shadow, TASK_UNINTERRUPTIBLE); - goto repeat; - } - - /* - * Only do the copy if the currently-owning transaction still needs it. - * If buffer isn't on BJ_Metadata list, the committing transaction is - * past that stage (here we use the fact that BH_Shadow is set under - * bh_state lock together with refiling to BJ_Shadow list and at this - * point we know the buffer doesn't have BH_Shadow set). - * - * Subtle point, though: if this is a get_undo_access, then we will be - * relying on the frozen_data to contain the new value of the - * committed_data record after the transaction, so we HAVE to force the - * frozen_data copy in that case. - */ - if (jh->b_jlist == BJ_Metadata || force_copy) { - JBUFFER_TRACE(jh, "generate frozen data"); - if (!frozen_buffer) { - JBUFFER_TRACE(jh, "allocate memory for buffer"); - jbd_unlock_bh_state(bh); - frozen_buffer = jbd2_alloc(jh2bh(jh)->b_size, - GFP_NOFS | __GFP_NOFAIL); - goto repeat; - } - jh->b_frozen_data = frozen_buffer; - frozen_buffer = NULL; - jbd2_freeze_jh_data(jh); - } -attach_next: - /* - * Make sure all stores to jh (b_modified, b_frozen_data) are visible - * before attaching it to the running transaction. Paired with barrier - * in jbd2_write_access_granted() - */ - smp_wmb(); - jh->b_next_transaction = transaction; - -done: - jbd_unlock_bh_state(bh); - - /* - * If we are about to journal a buffer, then any revoke pending on it is - * no longer valid - */ - jbd2_journal_cancel_revoke(handle, jh); - -out: - if (unlikely(frozen_buffer)) /* It's usually NULL */ - jbd2_free(frozen_buffer, bh->b_size); - - JBUFFER_TRACE(jh, "exit"); - return error; -} - -/* Fast check whether buffer is already attached to the required transaction */ -static bool jbd2_write_access_granted(handle_t *handle, struct buffer_head *bh, - bool undo) -{ - struct journal_head *jh; - bool ret = false; - - /* Dirty buffers require special handling... */ - if (buffer_dirty(bh)) - return false; - - /* - * RCU protects us from dereferencing freed pages. So the checks we do - * are guaranteed not to oops. However the jh slab object can get freed - * & reallocated while we work with it. So we have to be careful. When - * we see jh attached to the running transaction, we know it must stay - * so until the transaction is committed. Thus jh won't be freed and - * will be attached to the same bh while we run. However it can - * happen jh gets freed, reallocated, and attached to the transaction - * just after we get pointer to it from bh. So we have to be careful - * and recheck jh still belongs to our bh before we return success. - */ - rcu_read_lock(); - if (!buffer_jbd(bh)) - goto out; - /* This should be bh2jh() but that doesn't work with inline functions */ - jh = READ_ONCE(bh->b_private); - if (!jh) - goto out; - /* For undo access buffer must have data copied */ - if (undo && !jh->b_committed_data) - goto out; - if (jh->b_transaction != handle->h_transaction && - jh->b_next_transaction != handle->h_transaction) - goto out; - /* - * There are two reasons for the barrier here: - * 1) Make sure to fetch b_bh after we did previous checks so that we - * detect when jh went through free, realloc, attach to transaction - * while we were checking. Paired with implicit barrier in that path. - * 2) So that access to bh done after jbd2_write_access_granted() - * doesn't get reordered and see inconsistent state of concurrent - * do_get_write_access(). - */ - smp_mb(); - if (unlikely(jh->b_bh != bh)) - goto out; - ret = true; -out: - rcu_read_unlock(); - return ret; -} - -/** - * int jbd2_journal_get_write_access() - notify intent to modify a buffer for metadata (not data) update. - * @handle: transaction to add buffer modifications to - * @bh: bh to be used for metadata writes - * - * Returns an error code or 0 on success. - * - * In full data journalling mode the buffer may be of type BJ_AsyncData, - * because we're write()ing a buffer which is also part of a shared mapping. - */ - -int jbd2_journal_get_write_access(handle_t *handle, struct buffer_head *bh) -{ - struct journal_head *jh; - int rc; - - if (jbd2_write_access_granted(handle, bh, false)) - return 0; - - jh = jbd2_journal_add_journal_head(bh); - /* We do not want to get caught playing with fields which the - * log thread also manipulates. Make sure that the buffer - * completes any outstanding IO before proceeding. */ - rc = do_get_write_access(handle, jh, 0); - jbd2_journal_put_journal_head(jh); - return rc; -} - - -/* - * When the user wants to journal a newly created buffer_head - * (ie. getblk() returned a new buffer and we are going to populate it - * manually rather than reading off disk), then we need to keep the - * buffer_head locked until it has been completely filled with new - * data. In this case, we should be able to make the assertion that - * the bh is not already part of an existing transaction. - * - * The buffer should already be locked by the caller by this point. - * There is no lock ranking violation: it was a newly created, - * unlocked buffer beforehand. */ - -/** - * int jbd2_journal_get_create_access () - notify intent to use newly created bh - * @handle: transaction to new buffer to - * @bh: new buffer. - * - * Call this if you create a new bh. - */ -int jbd2_journal_get_create_access(handle_t *handle, struct buffer_head *bh) -{ - transaction_t *transaction = handle->h_transaction; - journal_t *journal; - struct journal_head *jh = jbd2_journal_add_journal_head(bh); - int err; - - jbd_debug(5, "journal_head %p\n", jh); - err = -EROFS; - if (is_handle_aborted(handle)) - goto out; - journal = transaction->t_journal; - err = 0; - - JBUFFER_TRACE(jh, "entry"); - /* - * The buffer may already belong to this transaction due to pre-zeroing - * in the filesystem's new_block code. It may also be on the previous, - * committing transaction's lists, but it HAS to be in Forget state in - * that case: the transaction must have deleted the buffer for it to be - * reused here. - */ - jbd_lock_bh_state(bh); - J_ASSERT_JH(jh, (jh->b_transaction == transaction || - jh->b_transaction == NULL || - (jh->b_transaction == journal->j_committing_transaction && - jh->b_jlist == BJ_Forget))); - - J_ASSERT_JH(jh, jh->b_next_transaction == NULL); - J_ASSERT_JH(jh, buffer_locked(jh2bh(jh))); - - if (jh->b_transaction == NULL) { - /* - * Previous jbd2_journal_forget() could have left the buffer - * with jbddirty bit set because it was being committed. When - * the commit finished, we've filed the buffer for - * checkpointing and marked it dirty. Now we are reallocating - * the buffer so the transaction freeing it must have - * committed and so it's safe to clear the dirty bit. - */ - clear_buffer_dirty(jh2bh(jh)); - /* first access by this transaction */ - jh->b_modified = 0; - - JBUFFER_TRACE(jh, "file as BJ_Reserved"); - spin_lock(&journal->j_list_lock); - __jbd2_journal_file_buffer(jh, transaction, BJ_Reserved); - spin_unlock(&journal->j_list_lock); - } else if (jh->b_transaction == journal->j_committing_transaction) { - /* first access by this transaction */ - jh->b_modified = 0; - - JBUFFER_TRACE(jh, "set next transaction"); - spin_lock(&journal->j_list_lock); - jh->b_next_transaction = transaction; - spin_unlock(&journal->j_list_lock); - } - jbd_unlock_bh_state(bh); - - /* - * akpm: I added this. ext3_alloc_branch can pick up new indirect - * blocks which contain freed but then revoked metadata. We need - * to cancel the revoke in case we end up freeing it yet again - * and the reallocating as data - this would cause a second revoke, - * which hits an assertion error. - */ - JBUFFER_TRACE(jh, "cancelling revoke"); - jbd2_journal_cancel_revoke(handle, jh); -out: - jbd2_journal_put_journal_head(jh); - return err; -} - -/** - * int jbd2_journal_get_undo_access() - Notify intent to modify metadata with - * non-rewindable consequences - * @handle: transaction - * @bh: buffer to undo - * - * Sometimes there is a need to distinguish between metadata which has - * been committed to disk and that which has not. The ext3fs code uses - * this for freeing and allocating space, we have to make sure that we - * do not reuse freed space until the deallocation has been committed, - * since if we overwrote that space we would make the delete - * un-rewindable in case of a crash. - * - * To deal with that, jbd2_journal_get_undo_access requests write access to a - * buffer for parts of non-rewindable operations such as delete - * operations on the bitmaps. The journaling code must keep a copy of - * the buffer's contents prior to the undo_access call until such time - * as we know that the buffer has definitely been committed to disk. - * - * We never need to know which transaction the committed data is part - * of, buffers touched here are guaranteed to be dirtied later and so - * will be committed to a new transaction in due course, at which point - * we can discard the old committed data pointer. - * - * Returns error number or 0 on success. - */ -int jbd2_journal_get_undo_access(handle_t *handle, struct buffer_head *bh) -{ - int err; - struct journal_head *jh; - char *committed_data = NULL; - - JBUFFER_TRACE(jh, "entry"); - if (jbd2_write_access_granted(handle, bh, true)) - return 0; - - jh = jbd2_journal_add_journal_head(bh); - /* - * Do this first --- it can drop the journal lock, so we want to - * make sure that obtaining the committed_data is done - * atomically wrt. completion of any outstanding commits. - */ - err = do_get_write_access(handle, jh, 1); - if (err) - goto out; - -repeat: - if (!jh->b_committed_data) - committed_data = jbd2_alloc(jh2bh(jh)->b_size, - GFP_NOFS|__GFP_NOFAIL); - - jbd_lock_bh_state(bh); - if (!jh->b_committed_data) { - /* Copy out the current buffer contents into the - * preserved, committed copy. */ - JBUFFER_TRACE(jh, "generate b_committed data"); - if (!committed_data) { - jbd_unlock_bh_state(bh); - goto repeat; - } - - jh->b_committed_data = committed_data; - committed_data = NULL; - memcpy(jh->b_committed_data, bh->b_data, bh->b_size); - } - jbd_unlock_bh_state(bh); -out: - jbd2_journal_put_journal_head(jh); - if (unlikely(committed_data)) - jbd2_free(committed_data, bh->b_size); - return err; -} - -/** - * void jbd2_journal_set_triggers() - Add triggers for commit writeout - * @bh: buffer to trigger on - * @type: struct jbd2_buffer_trigger_type containing the trigger(s). - * - * Set any triggers on this journal_head. This is always safe, because - * triggers for a committing buffer will be saved off, and triggers for - * a running transaction will match the buffer in that transaction. - * - * Call with NULL to clear the triggers. - */ -void jbd2_journal_set_triggers(struct buffer_head *bh, - struct jbd2_buffer_trigger_type *type) -{ - struct journal_head *jh = jbd2_journal_grab_journal_head(bh); - - if (WARN_ON(!jh)) - return; - jh->b_triggers = type; - jbd2_journal_put_journal_head(jh); -} - -void jbd2_buffer_frozen_trigger(struct journal_head *jh, void *mapped_data, - struct jbd2_buffer_trigger_type *triggers) -{ - struct buffer_head *bh = jh2bh(jh); - - if (!triggers || !triggers->t_frozen) - return; - - triggers->t_frozen(triggers, bh, mapped_data, bh->b_size); -} - -void jbd2_buffer_abort_trigger(struct journal_head *jh, - struct jbd2_buffer_trigger_type *triggers) -{ - if (!triggers || !triggers->t_abort) - return; - - triggers->t_abort(triggers, jh2bh(jh)); -} - -/** - * int jbd2_journal_dirty_metadata() - mark a buffer as containing dirty metadata - * @handle: transaction to add buffer to. - * @bh: buffer to mark - * - * mark dirty metadata which needs to be journaled as part of the current - * transaction. - * - * The buffer must have previously had jbd2_journal_get_write_access() - * called so that it has a valid journal_head attached to the buffer - * head. - * - * The buffer is placed on the transaction's metadata list and is marked - * as belonging to the transaction. - * - * Returns error number or 0 on success. - * - * Special care needs to be taken if the buffer already belongs to the - * current committing transaction (in which case we should have frozen - * data present for that commit). In that case, we don't relink the - * buffer: that only gets done when the old transaction finally - * completes its commit. - */ -int jbd2_journal_dirty_metadata(handle_t *handle, struct buffer_head *bh) -{ - transaction_t *transaction = handle->h_transaction; - journal_t *journal; - struct journal_head *jh; - int ret = 0; - - if (is_handle_aborted(handle)) - return -EROFS; - if (!buffer_jbd(bh)) { - ret = -EUCLEAN; - goto out; - } - /* - * We don't grab jh reference here since the buffer must be part - * of the running transaction. - */ - jh = bh2jh(bh); - /* - * This and the following assertions are unreliable since we may see jh - * in inconsistent state unless we grab bh_state lock. But this is - * crucial to catch bugs so let's do a reliable check until the - * lockless handling is fully proven. - */ - if (jh->b_transaction != transaction && - jh->b_next_transaction != transaction) { - jbd_lock_bh_state(bh); - J_ASSERT_JH(jh, jh->b_transaction == transaction || - jh->b_next_transaction == transaction); - jbd_unlock_bh_state(bh); - } - if (jh->b_modified == 1) { - /* If it's in our transaction it must be in BJ_Metadata list. */ - if (jh->b_transaction == transaction && - jh->b_jlist != BJ_Metadata) { - jbd_lock_bh_state(bh); - J_ASSERT_JH(jh, jh->b_transaction != transaction || - jh->b_jlist == BJ_Metadata); - jbd_unlock_bh_state(bh); - } - goto out; - } - - journal = transaction->t_journal; - jbd_debug(5, "journal_head %p\n", jh); - JBUFFER_TRACE(jh, "entry"); - - jbd_lock_bh_state(bh); - - if (jh->b_modified == 0) { - /* - * This buffer's got modified and becoming part - * of the transaction. This needs to be done - * once a transaction -bzzz - */ - jh->b_modified = 1; - if (handle->h_buffer_credits <= 0) { - ret = -ENOSPC; - goto out_unlock_bh; - } - handle->h_buffer_credits--; - } - - /* - * fastpath, to avoid expensive locking. If this buffer is already - * on the running transaction's metadata list there is nothing to do. - * Nobody can take it off again because there is a handle open. - * I _think_ we're OK here with SMP barriers - a mistaken decision will - * result in this test being false, so we go in and take the locks. - */ - if (jh->b_transaction == transaction && jh->b_jlist == BJ_Metadata) { - JBUFFER_TRACE(jh, "fastpath"); - if (unlikely(jh->b_transaction != - journal->j_running_transaction)) { - printk(KERN_ERR "JBD2: %s: " - "jh->b_transaction (%llu, %p, %u) != " - "journal->j_running_transaction (%p, %u)\n", - journal->j_devname, - (unsigned long long) bh->b_blocknr, - jh->b_transaction, - jh->b_transaction ? jh->b_transaction->t_tid : 0, - journal->j_running_transaction, - journal->j_running_transaction ? - journal->j_running_transaction->t_tid : 0); - ret = -EINVAL; - } - goto out_unlock_bh; - } - - set_buffer_jbddirty(bh); - - /* - * Metadata already on the current transaction list doesn't - * need to be filed. Metadata on another transaction's list must - * be committing, and will be refiled once the commit completes: - * leave it alone for now. - */ - if (jh->b_transaction != transaction) { - JBUFFER_TRACE(jh, "already on other transaction"); - if (unlikely(((jh->b_transaction != - journal->j_committing_transaction)) || - (jh->b_next_transaction != transaction))) { - printk(KERN_ERR "jbd2_journal_dirty_metadata: %s: " - "bad jh for block %llu: " - "transaction (%p, %u), " - "jh->b_transaction (%p, %u), " - "jh->b_next_transaction (%p, %u), jlist %u\n", - journal->j_devname, - (unsigned long long) bh->b_blocknr, - transaction, transaction->t_tid, - jh->b_transaction, - jh->b_transaction ? - jh->b_transaction->t_tid : 0, - jh->b_next_transaction, - jh->b_next_transaction ? - jh->b_next_transaction->t_tid : 0, - jh->b_jlist); - WARN_ON(1); - ret = -EINVAL; - } - /* And this case is illegal: we can't reuse another - * transaction's data buffer, ever. */ - goto out_unlock_bh; - } - - /* That test should have eliminated the following case: */ - J_ASSERT_JH(jh, jh->b_frozen_data == NULL); - - JBUFFER_TRACE(jh, "file as BJ_Metadata"); - spin_lock(&journal->j_list_lock); - __jbd2_journal_file_buffer(jh, transaction, BJ_Metadata); - spin_unlock(&journal->j_list_lock); -out_unlock_bh: - jbd_unlock_bh_state(bh); -out: - JBUFFER_TRACE(jh, "exit"); - return ret; -} - -/** - * void jbd2_journal_forget() - bforget() for potentially-journaled buffers. - * @handle: transaction handle - * @bh: bh to 'forget' - * - * We can only do the bforget if there are no commits pending against the - * buffer. If the buffer is dirty in the current running transaction we - * can safely unlink it. - * - * bh may not be a journalled buffer at all - it may be a non-JBD - * buffer which came off the hashtable. Check for this. - * - * Decrements bh->b_count by one. - * - * Allow this call even if the handle has aborted --- it may be part of - * the caller's cleanup after an abort. - */ -int jbd2_journal_forget (handle_t *handle, struct buffer_head *bh) -{ - transaction_t *transaction = handle->h_transaction; - journal_t *journal; - struct journal_head *jh; - int drop_reserve = 0; - int err = 0; - int was_modified = 0; - - if (is_handle_aborted(handle)) - return -EROFS; - journal = transaction->t_journal; - - BUFFER_TRACE(bh, "entry"); - - jbd_lock_bh_state(bh); - - if (!buffer_jbd(bh)) - goto not_jbd; - jh = bh2jh(bh); - - /* Critical error: attempting to delete a bitmap buffer, maybe? - * Don't do any jbd operations, and return an error. */ - if (!J_EXPECT_JH(jh, !jh->b_committed_data, - "inconsistent data on disk")) { - err = -EIO; - goto not_jbd; - } - - /* keep track of whether or not this transaction modified us */ - was_modified = jh->b_modified; - - /* - * The buffer's going from the transaction, we must drop - * all references -bzzz - */ - jh->b_modified = 0; - - if (jh->b_transaction == transaction) { - J_ASSERT_JH(jh, !jh->b_frozen_data); - - /* If we are forgetting a buffer which is already part - * of this transaction, then we can just drop it from - * the transaction immediately. */ - clear_buffer_dirty(bh); - clear_buffer_jbddirty(bh); - - JBUFFER_TRACE(jh, "belongs to current transaction: unfile"); - - /* - * we only want to drop a reference if this transaction - * modified the buffer - */ - if (was_modified) - drop_reserve = 1; - - /* - * We are no longer going to journal this buffer. - * However, the commit of this transaction is still - * important to the buffer: the delete that we are now - * processing might obsolete an old log entry, so by - * committing, we can satisfy the buffer's checkpoint. - * - * So, if we have a checkpoint on the buffer, we should - * now refile the buffer on our BJ_Forget list so that - * we know to remove the checkpoint after we commit. - */ - - spin_lock(&journal->j_list_lock); - if (jh->b_cp_transaction) { - __jbd2_journal_temp_unlink_buffer(jh); - __jbd2_journal_file_buffer(jh, transaction, BJ_Forget); - } else { - __jbd2_journal_unfile_buffer(jh); - if (!buffer_jbd(bh)) { - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - __bforget(bh); - goto drop; - } - } - spin_unlock(&journal->j_list_lock); - } else if (jh->b_transaction) { - J_ASSERT_JH(jh, (jh->b_transaction == - journal->j_committing_transaction)); - /* However, if the buffer is still owned by a prior - * (committing) transaction, we can't drop it yet... */ - JBUFFER_TRACE(jh, "belongs to older transaction"); - /* ... but we CAN drop it from the new transaction if we - * have also modified it since the original commit. */ - - if (jh->b_next_transaction) { - J_ASSERT(jh->b_next_transaction == transaction); - spin_lock(&journal->j_list_lock); - jh->b_next_transaction = NULL; - spin_unlock(&journal->j_list_lock); - - /* - * only drop a reference if this transaction modified - * the buffer - */ - if (was_modified) - drop_reserve = 1; - } - } - -not_jbd: - jbd_unlock_bh_state(bh); - __brelse(bh); -drop: - if (drop_reserve) { - /* no need to reserve log space for this block -bzzz */ - handle->h_buffer_credits++; - } - return err; -} - -/** - * int jbd2_journal_stop() - complete a transaction - * @handle: transaction to complete. - * - * All done for a particular handle. - * - * There is not much action needed here. We just return any remaining - * buffer credits to the transaction and remove the handle. The only - * complication is that we need to start a commit operation if the - * filesystem is marked for synchronous update. - * - * jbd2_journal_stop itself will not usually return an error, but it may - * do so in unusual circumstances. In particular, expect it to - * return -EIO if a jbd2_journal_abort has been executed since the - * transaction began. - */ -int jbd2_journal_stop(handle_t *handle) -{ - transaction_t *transaction = handle->h_transaction; - journal_t *journal; - int err = 0, wait_for_commit = 0; - tid_t tid; - pid_t pid; - - if (!transaction) { - /* - * Handle is already detached from the transaction so - * there is nothing to do other than decrease a refcount, - * or free the handle if refcount drops to zero - */ - if (--handle->h_ref > 0) { - jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1, - handle->h_ref); - return err; - } else { - if (handle->h_rsv_handle) - jbd2_free_handle(handle->h_rsv_handle); - goto free_and_exit; - } - } - journal = transaction->t_journal; - - J_ASSERT(journal_current_handle() == handle); - - if (is_handle_aborted(handle)) - err = -EIO; - else - J_ASSERT(atomic_read(&transaction->t_updates) > 0); - - if (--handle->h_ref > 0) { - jbd_debug(4, "h_ref %d -> %d\n", handle->h_ref + 1, - handle->h_ref); - return err; - } - - jbd_debug(4, "Handle %p going down\n", handle); - trace_jbd2_handle_stats(journal->j_fs_dev->bd_dev, - transaction->t_tid, - handle->h_type, handle->h_line_no, - jiffies - handle->h_start_jiffies, - handle->h_sync, handle->h_requested_credits, - (handle->h_requested_credits - - handle->h_buffer_credits)); - - /* - * Implement synchronous transaction batching. If the handle - * was synchronous, don't force a commit immediately. Let's - * yield and let another thread piggyback onto this - * transaction. Keep doing that while new threads continue to - * arrive. It doesn't cost much - we're about to run a commit - * and sleep on IO anyway. Speeds up many-threaded, many-dir - * operations by 30x or more... - * - * We try and optimize the sleep time against what the - * underlying disk can do, instead of having a static sleep - * time. This is useful for the case where our storage is so - * fast that it is more optimal to go ahead and force a flush - * and wait for the transaction to be committed than it is to - * wait for an arbitrary amount of time for new writers to - * join the transaction. We achieve this by measuring how - * long it takes to commit a transaction, and compare it with - * how long this transaction has been running, and if run time - * < commit time then we sleep for the delta and commit. This - * greatly helps super fast disks that would see slowdowns as - * more threads started doing fsyncs. - * - * But don't do this if this process was the most recent one - * to perform a synchronous write. We do this to detect the - * case where a single process is doing a stream of sync - * writes. No point in waiting for joiners in that case. - * - * Setting max_batch_time to 0 disables this completely. - */ - pid = current->pid; - if (handle->h_sync && journal->j_last_sync_writer != pid && - journal->j_max_batch_time) { - u64 commit_time, trans_time; - - journal->j_last_sync_writer = pid; - - read_lock(&journal->j_state_lock); - commit_time = journal->j_average_commit_time; - read_unlock(&journal->j_state_lock); - - trans_time = ktime_to_ns(ktime_sub(ktime_get(), - transaction->t_start_time)); - - commit_time = max_t(u64, commit_time, - 1000*journal->j_min_batch_time); - commit_time = min_t(u64, commit_time, - 1000*journal->j_max_batch_time); - - if (trans_time < commit_time) { - ktime_t expires = ktime_add_ns(ktime_get(), - commit_time); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_hrtimeout(&expires, HRTIMER_MODE_ABS); - } - } - - if (handle->h_sync) - transaction->t_synchronous_commit = 1; - current->journal_info = NULL; - atomic_sub(handle->h_buffer_credits, - &transaction->t_outstanding_credits); - - /* - * If the handle is marked SYNC, we need to set another commit - * going! We also want to force a commit if the current - * transaction is occupying too much of the log, or if the - * transaction is too old now. - */ - if (handle->h_sync || - (atomic_read(&transaction->t_outstanding_credits) > - journal->j_max_transaction_buffers) || - time_after_eq(jiffies, transaction->t_expires)) { - /* Do this even for aborted journals: an abort still - * completes the commit thread, it just doesn't write - * anything to disk. */ - - jbd_debug(2, "transaction too old, requesting commit for " - "handle %p\n", handle); - /* This is non-blocking */ - jbd2_log_start_commit(journal, transaction->t_tid); - - /* - * Special case: JBD2_SYNC synchronous updates require us - * to wait for the commit to complete. - */ - if (handle->h_sync && !(current->flags & PF_MEMALLOC)) - wait_for_commit = 1; - } - - /* - * Once we drop t_updates, if it goes to zero the transaction - * could start committing on us and eventually disappear. So - * once we do this, we must not dereference transaction - * pointer again. - */ - tid = transaction->t_tid; - if (atomic_dec_and_test(&transaction->t_updates)) { - wake_up(&journal->j_wait_updates); - if (journal->j_barrier_count) - wake_up(&journal->j_wait_transaction_locked); - } - - rwsem_release(&journal->j_trans_commit_map, 1, _THIS_IP_); - - if (wait_for_commit) - err = jbd2_log_wait_commit(journal, tid); - - if (handle->h_rsv_handle) - jbd2_journal_free_reserved(handle->h_rsv_handle); -free_and_exit: - jbd2_free_handle(handle); - return err; -} - -/* - * - * List management code snippets: various functions for manipulating the - * transaction buffer lists. - * - */ - -/* - * Append a buffer to a transaction list, given the transaction's list head - * pointer. - * - * j_list_lock is held. - * - * jbd_lock_bh_state(jh2bh(jh)) is held. - */ - -static inline void -__blist_add_buffer(struct journal_head **list, struct journal_head *jh) -{ - if (!*list) { - jh->b_tnext = jh->b_tprev = jh; - *list = jh; - } else { - /* Insert at the tail of the list to preserve order */ - struct journal_head *first = *list, *last = first->b_tprev; - jh->b_tprev = last; - jh->b_tnext = first; - last->b_tnext = first->b_tprev = jh; - } -} - -/* - * Remove a buffer from a transaction list, given the transaction's list - * head pointer. - * - * Called with j_list_lock held, and the journal may not be locked. - * - * jbd_lock_bh_state(jh2bh(jh)) is held. - */ - -static inline void -__blist_del_buffer(struct journal_head **list, struct journal_head *jh) -{ - if (*list == jh) { - *list = jh->b_tnext; - if (*list == jh) - *list = NULL; - } - jh->b_tprev->b_tnext = jh->b_tnext; - jh->b_tnext->b_tprev = jh->b_tprev; -} - -/* - * Remove a buffer from the appropriate transaction list. - * - * Note that this function can *change* the value of - * bh->b_transaction->t_buffers, t_forget, t_shadow_list, t_log_list or - * t_reserved_list. If the caller is holding onto a copy of one of these - * pointers, it could go bad. Generally the caller needs to re-read the - * pointer from the transaction_t. - * - * Called under j_list_lock. - */ -static void __jbd2_journal_temp_unlink_buffer(struct journal_head *jh) -{ - struct journal_head **list = NULL; - transaction_t *transaction; - struct buffer_head *bh = jh2bh(jh); - - J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh)); - transaction = jh->b_transaction; - if (transaction) - assert_spin_locked(&transaction->t_journal->j_list_lock); - - J_ASSERT_JH(jh, jh->b_jlist < BJ_Types); - if (jh->b_jlist != BJ_None) - J_ASSERT_JH(jh, transaction != NULL); - - switch (jh->b_jlist) { - case BJ_None: - return; - case BJ_Metadata: - transaction->t_nr_buffers--; - J_ASSERT_JH(jh, transaction->t_nr_buffers >= 0); - list = &transaction->t_buffers; - break; - case BJ_Forget: - list = &transaction->t_forget; - break; - case BJ_Shadow: - list = &transaction->t_shadow_list; - break; - case BJ_Reserved: - list = &transaction->t_reserved_list; - break; - } - - __blist_del_buffer(list, jh); - jh->b_jlist = BJ_None; - if (test_clear_buffer_jbddirty(bh)) - mark_buffer_dirty(bh); /* Expose it to the VM */ -} - -/* - * Remove buffer from all transactions. - * - * Called with bh_state lock and j_list_lock - * - * jh and bh may be already freed when this function returns. - */ -static void __jbd2_journal_unfile_buffer(struct journal_head *jh) -{ - __jbd2_journal_temp_unlink_buffer(jh); - jh->b_transaction = NULL; - jbd2_journal_put_journal_head(jh); -} - -void jbd2_journal_unfile_buffer(journal_t *journal, struct journal_head *jh) -{ - struct buffer_head *bh = jh2bh(jh); - - /* Get reference so that buffer cannot be freed before we unlock it */ - get_bh(bh); - jbd_lock_bh_state(bh); - spin_lock(&journal->j_list_lock); - __jbd2_journal_unfile_buffer(jh); - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - __brelse(bh); -} - -/* - * Called from jbd2_journal_try_to_free_buffers(). - * - * Called under jbd_lock_bh_state(bh) - */ -static void -__journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh) -{ - struct journal_head *jh; - - jh = bh2jh(bh); - - if (buffer_locked(bh) || buffer_dirty(bh)) - goto out; - - if (jh->b_next_transaction != NULL || jh->b_transaction != NULL) - goto out; - - spin_lock(&journal->j_list_lock); - if (jh->b_cp_transaction != NULL) { - /* written-back checkpointed metadata buffer */ - JBUFFER_TRACE(jh, "remove from checkpoint list"); - __jbd2_journal_remove_checkpoint(jh); - } - spin_unlock(&journal->j_list_lock); -out: - return; -} - -/** - * int jbd2_journal_try_to_free_buffers() - try to free page buffers. - * @journal: journal for operation - * @page: to try and free - * @gfp_mask: we use the mask to detect how hard should we try to release - * buffers. If __GFP_DIRECT_RECLAIM and __GFP_FS is set, we wait for commit - * code to release the buffers. - * - * - * For all the buffers on this page, - * if they are fully written out ordered data, move them onto BUF_CLEAN - * so try_to_free_buffers() can reap them. - * - * This function returns non-zero if we wish try_to_free_buffers() - * to be called. We do this if the page is releasable by try_to_free_buffers(). - * We also do it if the page has locked or dirty buffers and the caller wants - * us to perform sync or async writeout. - * - * This complicates JBD locking somewhat. We aren't protected by the - * BKL here. We wish to remove the buffer from its committing or - * running transaction's ->t_datalist via __jbd2_journal_unfile_buffer. - * - * This may *change* the value of transaction_t->t_datalist, so anyone - * who looks at t_datalist needs to lock against this function. - * - * Even worse, someone may be doing a jbd2_journal_dirty_data on this - * buffer. So we need to lock against that. jbd2_journal_dirty_data() - * will come out of the lock with the buffer dirty, which makes it - * ineligible for release here. - * - * Who else is affected by this? hmm... Really the only contender - * is do_get_write_access() - it could be looking at the buffer while - * journal_try_to_free_buffer() is changing its state. But that - * cannot happen because we never reallocate freed data as metadata - * while the data is part of a transaction. Yes? - * - * Return 0 on failure, 1 on success - */ -int jbd2_journal_try_to_free_buffers(journal_t *journal, - struct page *page, gfp_t gfp_mask) -{ - struct buffer_head *head; - struct buffer_head *bh; - int ret = 0; - - J_ASSERT(PageLocked(page)); - - head = page_buffers(page); - bh = head; - do { - struct journal_head *jh; - - /* - * We take our own ref against the journal_head here to avoid - * having to add tons of locking around each instance of - * jbd2_journal_put_journal_head(). - */ - jh = jbd2_journal_grab_journal_head(bh); - if (!jh) - continue; - - jbd_lock_bh_state(bh); - __journal_try_to_free_buffer(journal, bh); - jbd2_journal_put_journal_head(jh); - jbd_unlock_bh_state(bh); - if (buffer_jbd(bh)) - goto busy; - } while ((bh = bh->b_this_page) != head); - - ret = try_to_free_buffers(page); - -busy: - return ret; -} - -/* - * This buffer is no longer needed. If it is on an older transaction's - * checkpoint list we need to record it on this transaction's forget list - * to pin this buffer (and hence its checkpointing transaction) down until - * this transaction commits. If the buffer isn't on a checkpoint list, we - * release it. - * Returns non-zero if JBD no longer has an interest in the buffer. - * - * Called under j_list_lock. - * - * Called under jbd_lock_bh_state(bh). - */ -static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction) -{ - int may_free = 1; - struct buffer_head *bh = jh2bh(jh); - - if (jh->b_cp_transaction) { - JBUFFER_TRACE(jh, "on running+cp transaction"); - __jbd2_journal_temp_unlink_buffer(jh); - /* - * We don't want to write the buffer anymore, clear the - * bit so that we don't confuse checks in - * __journal_file_buffer - */ - clear_buffer_dirty(bh); - __jbd2_journal_file_buffer(jh, transaction, BJ_Forget); - may_free = 0; - } else { - JBUFFER_TRACE(jh, "on running transaction"); - __jbd2_journal_unfile_buffer(jh); - } - return may_free; -} - -/* - * jbd2_journal_invalidatepage - * - * This code is tricky. It has a number of cases to deal with. - * - * There are two invariants which this code relies on: - * - * i_size must be updated on disk before we start calling invalidatepage on the - * data. - * - * This is done in ext3 by defining an ext3_setattr method which - * updates i_size before truncate gets going. By maintaining this - * invariant, we can be sure that it is safe to throw away any buffers - * attached to the current transaction: once the transaction commits, - * we know that the data will not be needed. - * - * Note however that we can *not* throw away data belonging to the - * previous, committing transaction! - * - * Any disk blocks which *are* part of the previous, committing - * transaction (and which therefore cannot be discarded immediately) are - * not going to be reused in the new running transaction - * - * The bitmap committed_data images guarantee this: any block which is - * allocated in one transaction and removed in the next will be marked - * as in-use in the committed_data bitmap, so cannot be reused until - * the next transaction to delete the block commits. This means that - * leaving committing buffers dirty is quite safe: the disk blocks - * cannot be reallocated to a different file and so buffer aliasing is - * not possible. - * - * - * The above applies mainly to ordered data mode. In writeback mode we - * don't make guarantees about the order in which data hits disk --- in - * particular we don't guarantee that new dirty data is flushed before - * transaction commit --- so it is always safe just to discard data - * immediately in that mode. --sct - */ - -/* - * The journal_unmap_buffer helper function returns zero if the buffer - * concerned remains pinned as an anonymous buffer belonging to an older - * transaction. - * - * We're outside-transaction here. Either or both of j_running_transaction - * and j_committing_transaction may be NULL. - */ -static int journal_unmap_buffer(journal_t *journal, struct buffer_head *bh, - int partial_page) -{ - transaction_t *transaction; - struct journal_head *jh; - int may_free = 1; - - BUFFER_TRACE(bh, "entry"); - - /* - * It is safe to proceed here without the j_list_lock because the - * buffers cannot be stolen by try_to_free_buffers as long as we are - * holding the page lock. --sct - */ - - if (!buffer_jbd(bh)) - goto zap_buffer_unlocked; - - /* OK, we have data buffer in journaled mode */ - write_lock(&journal->j_state_lock); - jbd_lock_bh_state(bh); - spin_lock(&journal->j_list_lock); - - jh = jbd2_journal_grab_journal_head(bh); - if (!jh) - goto zap_buffer_no_jh; - - /* - * We cannot remove the buffer from checkpoint lists until the - * transaction adding inode to orphan list (let's call it T) - * is committed. Otherwise if the transaction changing the - * buffer would be cleaned from the journal before T is - * committed, a crash will cause that the correct contents of - * the buffer will be lost. On the other hand we have to - * clear the buffer dirty bit at latest at the moment when the - * transaction marking the buffer as freed in the filesystem - * structures is committed because from that moment on the - * block can be reallocated and used by a different page. - * Since the block hasn't been freed yet but the inode has - * already been added to orphan list, it is safe for us to add - * the buffer to BJ_Forget list of the newest transaction. - * - * Also we have to clear buffer_mapped flag of a truncated buffer - * because the buffer_head may be attached to the page straddling - * i_size (can happen only when blocksize < pagesize) and thus the - * buffer_head can be reused when the file is extended again. So we end - * up keeping around invalidated buffers attached to transactions' - * BJ_Forget list just to stop checkpointing code from cleaning up - * the transaction this buffer was modified in. - */ - transaction = jh->b_transaction; - if (transaction == NULL) { - /* First case: not on any transaction. If it - * has no checkpoint link, then we can zap it: - * it's a writeback-mode buffer so we don't care - * if it hits disk safely. */ - if (!jh->b_cp_transaction) { - JBUFFER_TRACE(jh, "not on any transaction: zap"); - goto zap_buffer; - } - - if (!buffer_dirty(bh)) { - /* bdflush has written it. We can drop it now */ - __jbd2_journal_remove_checkpoint(jh); - goto zap_buffer; - } - - /* OK, it must be in the journal but still not - * written fully to disk: it's metadata or - * journaled data... */ - - if (journal->j_running_transaction) { - /* ... and once the current transaction has - * committed, the buffer won't be needed any - * longer. */ - JBUFFER_TRACE(jh, "checkpointed: add to BJ_Forget"); - may_free = __dispose_buffer(jh, - journal->j_running_transaction); - goto zap_buffer; - } else { - /* There is no currently-running transaction. So the - * orphan record which we wrote for this file must have - * passed into commit. We must attach this buffer to - * the committing transaction, if it exists. */ - if (journal->j_committing_transaction) { - JBUFFER_TRACE(jh, "give to committing trans"); - may_free = __dispose_buffer(jh, - journal->j_committing_transaction); - goto zap_buffer; - } else { - /* The orphan record's transaction has - * committed. We can cleanse this buffer */ - clear_buffer_jbddirty(bh); - __jbd2_journal_remove_checkpoint(jh); - goto zap_buffer; - } - } - } else if (transaction == journal->j_committing_transaction) { - JBUFFER_TRACE(jh, "on committing transaction"); - /* - * The buffer is committing, we simply cannot touch - * it. If the page is straddling i_size we have to wait - * for commit and try again. - */ - if (partial_page) { - jbd2_journal_put_journal_head(jh); - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - write_unlock(&journal->j_state_lock); - return -EBUSY; - } - /* - * OK, buffer won't be reachable after truncate. We just set - * j_next_transaction to the running transaction (if there is - * one) and mark buffer as freed so that commit code knows it - * should clear dirty bits when it is done with the buffer. - */ - set_buffer_freed(bh); - if (journal->j_running_transaction && buffer_jbddirty(bh)) - jh->b_next_transaction = journal->j_running_transaction; - jbd2_journal_put_journal_head(jh); - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - write_unlock(&journal->j_state_lock); - return 0; - } else { - /* Good, the buffer belongs to the running transaction. - * We are writing our own transaction's data, not any - * previous one's, so it is safe to throw it away - * (remember that we expect the filesystem to have set - * i_size already for this truncate so recovery will not - * expose the disk blocks we are discarding here.) */ - J_ASSERT_JH(jh, transaction == journal->j_running_transaction); - JBUFFER_TRACE(jh, "on running transaction"); - may_free = __dispose_buffer(jh, transaction); - } - -zap_buffer: - /* - * This is tricky. Although the buffer is truncated, it may be reused - * if blocksize < pagesize and it is attached to the page straddling - * EOF. Since the buffer might have been added to BJ_Forget list of the - * running transaction, journal_get_write_access() won't clear - * b_modified and credit accounting gets confused. So clear b_modified - * here. - */ - jh->b_modified = 0; - jbd2_journal_put_journal_head(jh); -zap_buffer_no_jh: - spin_unlock(&journal->j_list_lock); - jbd_unlock_bh_state(bh); - write_unlock(&journal->j_state_lock); -zap_buffer_unlocked: - clear_buffer_dirty(bh); - J_ASSERT_BH(bh, !buffer_jbddirty(bh)); - clear_buffer_mapped(bh); - clear_buffer_req(bh); - clear_buffer_new(bh); - clear_buffer_delay(bh); - clear_buffer_unwritten(bh); - bh->b_bdev = NULL; - return may_free; -} - -/** - * void jbd2_journal_invalidatepage() - * @journal: journal to use for flush... - * @page: page to flush - * @offset: start of the range to invalidate - * @length: length of the range to invalidate - * - * Reap page buffers containing data after in the specified range in page. - * Can return -EBUSY if buffers are part of the committing transaction and - * the page is straddling i_size. Caller then has to wait for current commit - * and try again. - */ -int jbd2_journal_invalidatepage(journal_t *journal, - struct page *page, - unsigned int offset, - unsigned int length) -{ - struct buffer_head *head, *bh, *next; - unsigned int stop = offset + length; - unsigned int curr_off = 0; - int partial_page = (offset || length < PAGE_SIZE); - int may_free = 1; - int ret = 0; - - if (!PageLocked(page)) - BUG(); - if (!page_has_buffers(page)) - return 0; - - BUG_ON(stop > PAGE_SIZE || stop < length); - - /* We will potentially be playing with lists other than just the - * data lists (especially for journaled data mode), so be - * cautious in our locking. */ - - head = bh = page_buffers(page); - do { - unsigned int next_off = curr_off + bh->b_size; - next = bh->b_this_page; - - if (next_off > stop) - return 0; - - if (offset <= curr_off) { - /* This block is wholly outside the truncation point */ - lock_buffer(bh); - ret = journal_unmap_buffer(journal, bh, partial_page); - unlock_buffer(bh); - if (ret < 0) - return ret; - may_free &= ret; - } - curr_off = next_off; - bh = next; - - } while (bh != head); - - if (!partial_page) { - if (may_free && try_to_free_buffers(page)) - J_ASSERT(!page_has_buffers(page)); - } - return 0; -} - -/* - * File a buffer on the given transaction list. - */ -void __jbd2_journal_file_buffer(struct journal_head *jh, - transaction_t *transaction, int jlist) -{ - struct journal_head **list = NULL; - int was_dirty = 0; - struct buffer_head *bh = jh2bh(jh); - - J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh)); - assert_spin_locked(&transaction->t_journal->j_list_lock); - - J_ASSERT_JH(jh, jh->b_jlist < BJ_Types); - J_ASSERT_JH(jh, jh->b_transaction == transaction || - jh->b_transaction == NULL); - - if (jh->b_transaction && jh->b_jlist == jlist) - return; - - if (jlist == BJ_Metadata || jlist == BJ_Reserved || - jlist == BJ_Shadow || jlist == BJ_Forget) { - /* - * For metadata buffers, we track dirty bit in buffer_jbddirty - * instead of buffer_dirty. We should not see a dirty bit set - * here because we clear it in do_get_write_access but e.g. - * tune2fs can modify the sb and set the dirty bit at any time - * so we try to gracefully handle that. - */ - if (buffer_dirty(bh)) - warn_dirty_buffer(bh); - if (test_clear_buffer_dirty(bh) || - test_clear_buffer_jbddirty(bh)) - was_dirty = 1; - } - - if (jh->b_transaction) - __jbd2_journal_temp_unlink_buffer(jh); - else - jbd2_journal_grab_journal_head(bh); - jh->b_transaction = transaction; - - switch (jlist) { - case BJ_None: - J_ASSERT_JH(jh, !jh->b_committed_data); - J_ASSERT_JH(jh, !jh->b_frozen_data); - return; - case BJ_Metadata: - transaction->t_nr_buffers++; - list = &transaction->t_buffers; - break; - case BJ_Forget: - list = &transaction->t_forget; - break; - case BJ_Shadow: - list = &transaction->t_shadow_list; - break; - case BJ_Reserved: - list = &transaction->t_reserved_list; - break; - } - - __blist_add_buffer(list, jh); - jh->b_jlist = jlist; - - if (was_dirty) - set_buffer_jbddirty(bh); -} - -void jbd2_journal_file_buffer(struct journal_head *jh, - transaction_t *transaction, int jlist) -{ - jbd_lock_bh_state(jh2bh(jh)); - spin_lock(&transaction->t_journal->j_list_lock); - __jbd2_journal_file_buffer(jh, transaction, jlist); - spin_unlock(&transaction->t_journal->j_list_lock); - jbd_unlock_bh_state(jh2bh(jh)); -} - -/* - * Remove a buffer from its current buffer list in preparation for - * dropping it from its current transaction entirely. If the buffer has - * already started to be used by a subsequent transaction, refile the - * buffer on that transaction's metadata list. - * - * Called under j_list_lock - * Called under jbd_lock_bh_state(jh2bh(jh)) - * - * jh and bh may be already free when this function returns - */ -void __jbd2_journal_refile_buffer(struct journal_head *jh) -{ - int was_dirty, jlist; - struct buffer_head *bh = jh2bh(jh); - - J_ASSERT_JH(jh, jbd_is_locked_bh_state(bh)); - if (jh->b_transaction) - assert_spin_locked(&jh->b_transaction->t_journal->j_list_lock); - - /* If the buffer is now unused, just drop it. */ - if (jh->b_next_transaction == NULL) { - __jbd2_journal_unfile_buffer(jh); - return; - } - - /* - * It has been modified by a later transaction: add it to the new - * transaction's metadata list. - */ - - was_dirty = test_clear_buffer_jbddirty(bh); - __jbd2_journal_temp_unlink_buffer(jh); - /* - * We set b_transaction here because b_next_transaction will inherit - * our jh reference and thus __jbd2_journal_file_buffer() must not - * take a new one. - */ - jh->b_transaction = jh->b_next_transaction; - jh->b_next_transaction = NULL; - if (buffer_freed(bh)) - jlist = BJ_Forget; - else if (jh->b_modified) - jlist = BJ_Metadata; - else - jlist = BJ_Reserved; - __jbd2_journal_file_buffer(jh, jh->b_transaction, jlist); - J_ASSERT_JH(jh, jh->b_transaction->t_state == T_RUNNING); - - if (was_dirty) - set_buffer_jbddirty(bh); -} - -/* - * __jbd2_journal_refile_buffer() with necessary locking added. We take our - * bh reference so that we can safely unlock bh. - * - * The jh and bh may be freed by this call. - */ -void jbd2_journal_refile_buffer(journal_t *journal, struct journal_head *jh) -{ - struct buffer_head *bh = jh2bh(jh); - - /* Get reference so that buffer cannot be freed before we unlock it */ - get_bh(bh); - jbd_lock_bh_state(bh); - spin_lock(&journal->j_list_lock); - __jbd2_journal_refile_buffer(jh); - jbd_unlock_bh_state(bh); - spin_unlock(&journal->j_list_lock); - __brelse(bh); -} - -/* - * File inode in the inode list of the handle's transaction - */ -static int jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *jinode, - unsigned long flags) -{ - transaction_t *transaction = handle->h_transaction; - journal_t *journal; - - if (is_handle_aborted(handle)) - return -EROFS; - journal = transaction->t_journal; - - jbd_debug(4, "Adding inode %lu, tid:%d\n", jinode->i_vfs_inode->i_ino, - transaction->t_tid); - - /* - * First check whether inode isn't already on the transaction's - * lists without taking the lock. Note that this check is safe - * without the lock as we cannot race with somebody removing inode - * from the transaction. The reason is that we remove inode from the - * transaction only in journal_release_jbd_inode() and when we commit - * the transaction. We are guarded from the first case by holding - * a reference to the inode. We are safe against the second case - * because if jinode->i_transaction == transaction, commit code - * cannot touch the transaction because we hold reference to it, - * and if jinode->i_next_transaction == transaction, commit code - * will only file the inode where we want it. - */ - if ((jinode->i_transaction == transaction || - jinode->i_next_transaction == transaction) && - (jinode->i_flags & flags) == flags) - return 0; - - spin_lock(&journal->j_list_lock); - jinode->i_flags |= flags; - /* Is inode already attached where we need it? */ - if (jinode->i_transaction == transaction || - jinode->i_next_transaction == transaction) - goto done; - - /* - * We only ever set this variable to 1 so the test is safe. Since - * t_need_data_flush is likely to be set, we do the test to save some - * cacheline bouncing - */ - if (!transaction->t_need_data_flush) - transaction->t_need_data_flush = 1; - /* On some different transaction's list - should be - * the committing one */ - if (jinode->i_transaction) { - J_ASSERT(jinode->i_next_transaction == NULL); - J_ASSERT(jinode->i_transaction == - journal->j_committing_transaction); - jinode->i_next_transaction = transaction; - goto done; - } - /* Not on any transaction list... */ - J_ASSERT(!jinode->i_next_transaction); - jinode->i_transaction = transaction; - list_add(&jinode->i_list, &transaction->t_inode_list); -done: - spin_unlock(&journal->j_list_lock); - - return 0; -} - -int jbd2_journal_inode_add_write(handle_t *handle, struct jbd2_inode *jinode) -{ - return jbd2_journal_file_inode(handle, jinode, - JI_WRITE_DATA | JI_WAIT_DATA); -} - -int jbd2_journal_inode_add_wait(handle_t *handle, struct jbd2_inode *jinode) -{ - return jbd2_journal_file_inode(handle, jinode, JI_WAIT_DATA); -} - -/* - * File truncate and transaction commit interact with each other in a - * non-trivial way. If a transaction writing data block A is - * committing, we cannot discard the data by truncate until we have - * written them. Otherwise if we crashed after the transaction with - * write has committed but before the transaction with truncate has - * committed, we could see stale data in block A. This function is a - * helper to solve this problem. It starts writeout of the truncated - * part in case it is in the committing transaction. - * - * Filesystem code must call this function when inode is journaled in - * ordered mode before truncation happens and after the inode has been - * placed on orphan list with the new inode size. The second condition - * avoids the race that someone writes new data and we start - * committing the transaction after this function has been called but - * before a transaction for truncate is started (and furthermore it - * allows us to optimize the case where the addition to orphan list - * happens in the same transaction as write --- we don't have to write - * any data in such case). - */ -int jbd2_journal_begin_ordered_truncate(journal_t *journal, - struct jbd2_inode *jinode, - loff_t new_size) -{ - transaction_t *inode_trans, *commit_trans; - int ret = 0; - - /* This is a quick check to avoid locking if not necessary */ - if (!jinode->i_transaction) - goto out; - /* Locks are here just to force reading of recent values, it is - * enough that the transaction was not committing before we started - * a transaction adding the inode to orphan list */ - read_lock(&journal->j_state_lock); - commit_trans = journal->j_committing_transaction; - read_unlock(&journal->j_state_lock); - spin_lock(&journal->j_list_lock); - inode_trans = jinode->i_transaction; - spin_unlock(&journal->j_list_lock); - if (inode_trans == commit_trans) { - ret = filemap_fdatawrite_range(jinode->i_vfs_inode->i_mapping, - new_size, LLONG_MAX); - if (ret) - jbd2_journal_abort(journal, ret); - } -out: - return ret; -} diff --git a/src/linux/fs/jffs2/Kconfig b/src/linux/fs/jffs2/Kconfig deleted file mode 100644 index d8bb6c4..0000000 --- a/src/linux/fs/jffs2/Kconfig +++ /dev/null @@ -1,188 +0,0 @@ -config JFFS2_FS - tristate "Journalling Flash File System v2 (JFFS2) support" - select CRC32 - depends on MTD - help - JFFS2 is the second generation of the Journalling Flash File System - for use on diskless embedded devices. It provides improved wear - levelling, compression and support for hard links. You cannot use - this on normal block devices, only on 'MTD' devices. - - Further information on the design and implementation of JFFS2 is - available at . - -config JFFS2_FS_DEBUG - int "JFFS2 debugging verbosity (0 = quiet, 2 = noisy)" - depends on JFFS2_FS - default "0" - help - This controls the amount of debugging messages produced by the JFFS2 - code. Set it to zero for use in production systems. For evaluation, - testing and debugging, it's advisable to set it to one. This will - enable a few assertions and will print debugging messages at the - KERN_DEBUG loglevel, where they won't normally be visible. Level 2 - is unlikely to be useful - it enables extra debugging in certain - areas which at one point needed debugging, but when the bugs were - located and fixed, the detailed messages were relegated to level 2. - - If reporting bugs, please try to have available a full dump of the - messages at debug level 1 while the misbehaviour was occurring. - -config JFFS2_FS_WRITEBUFFER - bool "JFFS2 write-buffering support" - depends on JFFS2_FS - default y - help - This enables the write-buffering support in JFFS2. - - This functionality is required to support JFFS2 on the following - types of flash devices: - - NAND flash - - NOR flash with transparent ECC - - DataFlash - -config JFFS2_FS_WBUF_VERIFY - bool "Verify JFFS2 write-buffer reads" - depends on JFFS2_FS_WRITEBUFFER - default n - help - This causes JFFS2 to read back every page written through the - write-buffer, and check for errors. - -config JFFS2_SUMMARY - bool "JFFS2 summary support" - depends on JFFS2_FS - default n - help - This feature makes it possible to use summary information - for faster filesystem mount. - - The summary information can be inserted into a filesystem image - by the utility 'sumtool'. - - If unsure, say 'N'. - -config JFFS2_FS_XATTR - bool "JFFS2 XATTR support" - depends on JFFS2_FS - default n - help - Extended attributes are name:value pairs associated with inodes by - the kernel or by users (see the attr(5) manual page, or visit - for details). - - If unsure, say N. - -config JFFS2_FS_POSIX_ACL - bool "JFFS2 POSIX Access Control Lists" - depends on JFFS2_FS_XATTR - default y - select FS_POSIX_ACL - help - Posix Access Control Lists (ACLs) support permissions for users and - groups beyond the owner/group/world scheme. - - To learn more about Access Control Lists, visit the Posix ACLs for - Linux website . - - If you don't know what Access Control Lists are, say N - -config JFFS2_FS_SECURITY - bool "JFFS2 Security Labels" - depends on JFFS2_FS_XATTR - default y - help - Security labels support alternative access control models - implemented by security modules like SELinux. This option - enables an extended attribute handler for file security - labels in the jffs2 filesystem. - - If you are not using a security module that requires using - extended attributes for file security labels, say N. - -config JFFS2_COMPRESSION_OPTIONS - bool "Advanced compression options for JFFS2" - depends on JFFS2_FS - default n - help - Enabling this option allows you to explicitly choose which - compression modules, if any, are enabled in JFFS2. Removing - compressors can mean you cannot read existing file systems, - and enabling experimental compressors can mean that you - write a file system which cannot be read by a standard kernel. - - If unsure, you should _definitely_ say 'N'. - -config JFFS2_ZLIB - bool "JFFS2 ZLIB compression support" if JFFS2_COMPRESSION_OPTIONS - select ZLIB_INFLATE - select ZLIB_DEFLATE - depends on JFFS2_FS - default y - help - Zlib is designed to be a free, general-purpose, legally unencumbered, - lossless data-compression library for use on virtually any computer - hardware and operating system. See for - further information. - - Say 'Y' if unsure. - -config JFFS2_LZO - bool "JFFS2 LZO compression support" if JFFS2_COMPRESSION_OPTIONS - select LZO_COMPRESS - select LZO_DECOMPRESS - depends on JFFS2_FS - default n - help - minilzo-based compression. Generally works better than Zlib. - - This feature was added in July, 2007. Say 'N' if you need - compatibility with older bootloaders or kernels. - -config JFFS2_RTIME - bool "JFFS2 RTIME compression support" if JFFS2_COMPRESSION_OPTIONS - depends on JFFS2_FS - default y - help - Rtime does manage to recompress already-compressed data. Say 'Y' if unsure. - -config JFFS2_RUBIN - bool "JFFS2 RUBIN compression support" if JFFS2_COMPRESSION_OPTIONS - depends on JFFS2_FS - default n - help - RUBINMIPS and DYNRUBIN compressors. Say 'N' if unsure. - -choice - prompt "JFFS2 default compression mode" if JFFS2_COMPRESSION_OPTIONS - default JFFS2_CMODE_PRIORITY - depends on JFFS2_FS - help - You can set here the default compression mode of JFFS2 from - the available compression modes. Don't touch if unsure. - -config JFFS2_CMODE_NONE - bool "no compression" - help - Uses no compression. - -config JFFS2_CMODE_PRIORITY - bool "priority" - help - Tries the compressors in a predefined order and chooses the first - successful one. - -config JFFS2_CMODE_SIZE - bool "size" - help - Tries all compressors and chooses the one which has the smallest - result. - -config JFFS2_CMODE_FAVOURLZO - bool "Favour LZO" - help - Tries all compressors and chooses the one which has the smallest - result but gives some preference to LZO (which has faster - decompression) at the expense of size. - -endchoice diff --git a/src/linux/fs/jfs/Kconfig b/src/linux/fs/jfs/Kconfig deleted file mode 100644 index 57cef19..0000000 --- a/src/linux/fs/jfs/Kconfig +++ /dev/null @@ -1,50 +0,0 @@ -config JFS_FS - tristate "JFS filesystem support" - select NLS - select CRC32 - help - This is a port of IBM's Journaled Filesystem . More information is - available in the file . - - If you do not intend to use the JFS filesystem, say N. - -config JFS_POSIX_ACL - bool "JFS POSIX Access Control Lists" - depends on JFS_FS - select FS_POSIX_ACL - help - Posix Access Control Lists (ACLs) support permissions for users and - groups beyond the owner/group/world scheme. - - To learn more about Access Control Lists, visit the Posix ACLs for - Linux website . - - If you don't know what Access Control Lists are, say N - -config JFS_SECURITY - bool "JFS Security Labels" - depends on JFS_FS - help - Security labels support alternative access control models - implemented by security modules like SELinux. This option - enables an extended attribute handler for file security - labels in the jfs filesystem. - - If you are not using a security module that requires using - extended attributes for file security labels, say N. - -config JFS_DEBUG - bool "JFS debugging" - depends on JFS_FS - help - If you are experiencing any problems with the JFS filesystem, say - Y here. This will result in additional debugging messages to be - written to the system log. Under normal circumstances, this - results in very little overhead. - -config JFS_STATISTICS - bool "JFS statistics" - depends on JFS_FS - help - Enabling this option will cause statistics from the JFS file system - to be made available to the user in the /proc/fs/jfs/ directory. diff --git a/src/linux/fs/kernfs/Kconfig b/src/linux/fs/kernfs/Kconfig deleted file mode 100644 index 397b5f7..0000000 --- a/src/linux/fs/kernfs/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -# -# KERNFS should be selected by its users -# - -config KERNFS - bool - default n diff --git a/src/linux/fs/kernfs/Makefile b/src/linux/fs/kernfs/Makefile deleted file mode 100644 index 674337c..0000000 --- a/src/linux/fs/kernfs/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# -# Makefile for the kernfs pseudo filesystem -# - -obj-y := mount.o inode.o dir.o file.o symlink.o diff --git a/src/linux/fs/kernfs/dir.c b/src/linux/fs/kernfs/dir.c deleted file mode 100644 index cf4c636..0000000 --- a/src/linux/fs/kernfs/dir.c +++ /dev/null @@ -1,1604 +0,0 @@ -/* - * fs/kernfs/dir.c - kernfs directory implementation - * - * Copyright (c) 2001-3 Patrick Mochel - * Copyright (c) 2007 SUSE Linux Products GmbH - * Copyright (c) 2007, 2013 Tejun Heo - * - * This file is released under the GPLv2. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "kernfs-internal.h" - -DEFINE_MUTEX(kernfs_mutex); -static DEFINE_SPINLOCK(kernfs_rename_lock); /* kn->parent and ->name */ -static char kernfs_pr_cont_buf[PATH_MAX]; /* protected by rename_lock */ - -#define rb_to_kn(X) rb_entry((X), struct kernfs_node, rb) - -static bool kernfs_active(struct kernfs_node *kn) -{ - lockdep_assert_held(&kernfs_mutex); - return atomic_read(&kn->active) >= 0; -} - -static bool kernfs_lockdep(struct kernfs_node *kn) -{ -#ifdef CONFIG_DEBUG_LOCK_ALLOC - return kn->flags & KERNFS_LOCKDEP; -#else - return false; -#endif -} - -static int kernfs_name_locked(struct kernfs_node *kn, char *buf, size_t buflen) -{ - return strlcpy(buf, kn->parent ? kn->name : "/", buflen); -} - -/* kernfs_node_depth - compute depth from @from to @to */ -static size_t kernfs_depth(struct kernfs_node *from, struct kernfs_node *to) -{ - size_t depth = 0; - - while (to->parent && to != from) { - depth++; - to = to->parent; - } - return depth; -} - -static struct kernfs_node *kernfs_common_ancestor(struct kernfs_node *a, - struct kernfs_node *b) -{ - size_t da, db; - struct kernfs_root *ra = kernfs_root(a), *rb = kernfs_root(b); - - if (ra != rb) - return NULL; - - da = kernfs_depth(ra->kn, a); - db = kernfs_depth(rb->kn, b); - - while (da > db) { - a = a->parent; - da--; - } - while (db > da) { - b = b->parent; - db--; - } - - /* worst case b and a will be the same at root */ - while (b != a) { - b = b->parent; - a = a->parent; - } - - return a; -} - -/** - * kernfs_path_from_node_locked - find a pseudo-absolute path to @kn_to, - * where kn_from is treated as root of the path. - * @kn_from: kernfs node which should be treated as root for the path - * @kn_to: kernfs node to which path is needed - * @buf: buffer to copy the path into - * @buflen: size of @buf - * - * We need to handle couple of scenarios here: - * [1] when @kn_from is an ancestor of @kn_to at some level - * kn_from: /n1/n2/n3 - * kn_to: /n1/n2/n3/n4/n5 - * result: /n4/n5 - * - * [2] when @kn_from is on a different hierarchy and we need to find common - * ancestor between @kn_from and @kn_to. - * kn_from: /n1/n2/n3/n4 - * kn_to: /n1/n2/n5 - * result: /../../n5 - * OR - * kn_from: /n1/n2/n3/n4/n5 [depth=5] - * kn_to: /n1/n2/n3 [depth=3] - * result: /../.. - * - * Returns the length of the full path. If the full length is equal to or - * greater than @buflen, @buf contains the truncated path with the trailing - * '\0'. On error, -errno is returned. - */ -static int kernfs_path_from_node_locked(struct kernfs_node *kn_to, - struct kernfs_node *kn_from, - char *buf, size_t buflen) -{ - struct kernfs_node *kn, *common; - const char parent_str[] = "/.."; - size_t depth_from, depth_to, len = 0; - int i, j; - - if (!kn_from) - kn_from = kernfs_root(kn_to)->kn; - - if (kn_from == kn_to) - return strlcpy(buf, "/", buflen); - - common = kernfs_common_ancestor(kn_from, kn_to); - if (WARN_ON(!common)) - return -EINVAL; - - depth_to = kernfs_depth(common, kn_to); - depth_from = kernfs_depth(common, kn_from); - - if (buf) - buf[0] = '\0'; - - for (i = 0; i < depth_from; i++) - len += strlcpy(buf + len, parent_str, - len < buflen ? buflen - len : 0); - - /* Calculate how many bytes we need for the rest */ - for (i = depth_to - 1; i >= 0; i--) { - for (kn = kn_to, j = 0; j < i; j++) - kn = kn->parent; - len += strlcpy(buf + len, "/", - len < buflen ? buflen - len : 0); - len += strlcpy(buf + len, kn->name, - len < buflen ? buflen - len : 0); - } - - return len; -} - -/** - * kernfs_name - obtain the name of a given node - * @kn: kernfs_node of interest - * @buf: buffer to copy @kn's name into - * @buflen: size of @buf - * - * Copies the name of @kn into @buf of @buflen bytes. The behavior is - * similar to strlcpy(). It returns the length of @kn's name and if @buf - * isn't long enough, it's filled upto @buflen-1 and nul terminated. - * - * This function can be called from any context. - */ -int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&kernfs_rename_lock, flags); - ret = kernfs_name_locked(kn, buf, buflen); - spin_unlock_irqrestore(&kernfs_rename_lock, flags); - return ret; -} - -/** - * kernfs_path_from_node - build path of node @to relative to @from. - * @from: parent kernfs_node relative to which we need to build the path - * @to: kernfs_node of interest - * @buf: buffer to copy @to's path into - * @buflen: size of @buf - * - * Builds @to's path relative to @from in @buf. @from and @to must - * be on the same kernfs-root. If @from is not parent of @to, then a relative - * path (which includes '..'s) as needed to reach from @from to @to is - * returned. - * - * Returns the length of the full path. If the full length is equal to or - * greater than @buflen, @buf contains the truncated path with the trailing - * '\0'. On error, -errno is returned. - */ -int kernfs_path_from_node(struct kernfs_node *to, struct kernfs_node *from, - char *buf, size_t buflen) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&kernfs_rename_lock, flags); - ret = kernfs_path_from_node_locked(to, from, buf, buflen); - spin_unlock_irqrestore(&kernfs_rename_lock, flags); - return ret; -} -EXPORT_SYMBOL_GPL(kernfs_path_from_node); - -/** - * pr_cont_kernfs_name - pr_cont name of a kernfs_node - * @kn: kernfs_node of interest - * - * This function can be called from any context. - */ -void pr_cont_kernfs_name(struct kernfs_node *kn) -{ - unsigned long flags; - - spin_lock_irqsave(&kernfs_rename_lock, flags); - - kernfs_name_locked(kn, kernfs_pr_cont_buf, sizeof(kernfs_pr_cont_buf)); - pr_cont("%s", kernfs_pr_cont_buf); - - spin_unlock_irqrestore(&kernfs_rename_lock, flags); -} - -/** - * pr_cont_kernfs_path - pr_cont path of a kernfs_node - * @kn: kernfs_node of interest - * - * This function can be called from any context. - */ -void pr_cont_kernfs_path(struct kernfs_node *kn) -{ - unsigned long flags; - int sz; - - spin_lock_irqsave(&kernfs_rename_lock, flags); - - sz = kernfs_path_from_node_locked(kn, NULL, kernfs_pr_cont_buf, - sizeof(kernfs_pr_cont_buf)); - if (sz < 0) { - pr_cont("(error)"); - goto out; - } - - if (sz >= sizeof(kernfs_pr_cont_buf)) { - pr_cont("(name too long)"); - goto out; - } - - pr_cont("%s", kernfs_pr_cont_buf); - -out: - spin_unlock_irqrestore(&kernfs_rename_lock, flags); -} - -/** - * kernfs_get_parent - determine the parent node and pin it - * @kn: kernfs_node of interest - * - * Determines @kn's parent, pins and returns it. This function can be - * called from any context. - */ -struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn) -{ - struct kernfs_node *parent; - unsigned long flags; - - spin_lock_irqsave(&kernfs_rename_lock, flags); - parent = kn->parent; - kernfs_get(parent); - spin_unlock_irqrestore(&kernfs_rename_lock, flags); - - return parent; -} - -/** - * kernfs_name_hash - * @name: Null terminated string to hash - * @ns: Namespace tag to hash - * - * Returns 31 bit hash of ns + name (so it fits in an off_t ) - */ -static unsigned int kernfs_name_hash(const char *name, const void *ns) -{ - unsigned long hash = init_name_hash(ns); - unsigned int len = strlen(name); - while (len--) - hash = partial_name_hash(*name++, hash); - hash = end_name_hash(hash); - hash &= 0x7fffffffU; - /* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */ - if (hash < 2) - hash += 2; - if (hash >= INT_MAX) - hash = INT_MAX - 1; - return hash; -} - -static int kernfs_name_compare(unsigned int hash, const char *name, - const void *ns, const struct kernfs_node *kn) -{ - if (hash < kn->hash) - return -1; - if (hash > kn->hash) - return 1; - if (ns < kn->ns) - return -1; - if (ns > kn->ns) - return 1; - return strcmp(name, kn->name); -} - -static int kernfs_sd_compare(const struct kernfs_node *left, - const struct kernfs_node *right) -{ - return kernfs_name_compare(left->hash, left->name, left->ns, right); -} - -/** - * kernfs_link_sibling - link kernfs_node into sibling rbtree - * @kn: kernfs_node of interest - * - * Link @kn into its sibling rbtree which starts from - * @kn->parent->dir.children. - * - * Locking: - * mutex_lock(kernfs_mutex) - * - * RETURNS: - * 0 on susccess -EEXIST on failure. - */ -static int kernfs_link_sibling(struct kernfs_node *kn) -{ - struct rb_node **node = &kn->parent->dir.children.rb_node; - struct rb_node *parent = NULL; - - while (*node) { - struct kernfs_node *pos; - int result; - - pos = rb_to_kn(*node); - parent = *node; - result = kernfs_sd_compare(kn, pos); - if (result < 0) - node = &pos->rb.rb_left; - else if (result > 0) - node = &pos->rb.rb_right; - else - return -EEXIST; - } - - /* add new node and rebalance the tree */ - rb_link_node(&kn->rb, parent, node); - rb_insert_color(&kn->rb, &kn->parent->dir.children); - - /* successfully added, account subdir number */ - if (kernfs_type(kn) == KERNFS_DIR) - kn->parent->dir.subdirs++; - - return 0; -} - -/** - * kernfs_unlink_sibling - unlink kernfs_node from sibling rbtree - * @kn: kernfs_node of interest - * - * Try to unlink @kn from its sibling rbtree which starts from - * kn->parent->dir.children. Returns %true if @kn was actually - * removed, %false if @kn wasn't on the rbtree. - * - * Locking: - * mutex_lock(kernfs_mutex) - */ -static bool kernfs_unlink_sibling(struct kernfs_node *kn) -{ - if (RB_EMPTY_NODE(&kn->rb)) - return false; - - if (kernfs_type(kn) == KERNFS_DIR) - kn->parent->dir.subdirs--; - - rb_erase(&kn->rb, &kn->parent->dir.children); - RB_CLEAR_NODE(&kn->rb); - return true; -} - -/** - * kernfs_get_active - get an active reference to kernfs_node - * @kn: kernfs_node to get an active reference to - * - * Get an active reference of @kn. This function is noop if @kn - * is NULL. - * - * RETURNS: - * Pointer to @kn on success, NULL on failure. - */ -struct kernfs_node *kernfs_get_active(struct kernfs_node *kn) -{ - if (unlikely(!kn)) - return NULL; - - if (!atomic_inc_unless_negative(&kn->active)) - return NULL; - - if (kernfs_lockdep(kn)) - rwsem_acquire_read(&kn->dep_map, 0, 1, _RET_IP_); - return kn; -} - -/** - * kernfs_put_active - put an active reference to kernfs_node - * @kn: kernfs_node to put an active reference to - * - * Put an active reference to @kn. This function is noop if @kn - * is NULL. - */ -void kernfs_put_active(struct kernfs_node *kn) -{ - struct kernfs_root *root = kernfs_root(kn); - int v; - - if (unlikely(!kn)) - return; - - if (kernfs_lockdep(kn)) - rwsem_release(&kn->dep_map, 1, _RET_IP_); - v = atomic_dec_return(&kn->active); - if (likely(v != KN_DEACTIVATED_BIAS)) - return; - - wake_up_all(&root->deactivate_waitq); -} - -/** - * kernfs_drain - drain kernfs_node - * @kn: kernfs_node to drain - * - * Drain existing usages and nuke all existing mmaps of @kn. Mutiple - * removers may invoke this function concurrently on @kn and all will - * return after draining is complete. - */ -static void kernfs_drain(struct kernfs_node *kn) - __releases(&kernfs_mutex) __acquires(&kernfs_mutex) -{ - struct kernfs_root *root = kernfs_root(kn); - - lockdep_assert_held(&kernfs_mutex); - WARN_ON_ONCE(kernfs_active(kn)); - - mutex_unlock(&kernfs_mutex); - - if (kernfs_lockdep(kn)) { - rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_); - if (atomic_read(&kn->active) != KN_DEACTIVATED_BIAS) - lock_contended(&kn->dep_map, _RET_IP_); - } - - /* but everyone should wait for draining */ - wait_event(root->deactivate_waitq, - atomic_read(&kn->active) == KN_DEACTIVATED_BIAS); - - if (kernfs_lockdep(kn)) { - lock_acquired(&kn->dep_map, _RET_IP_); - rwsem_release(&kn->dep_map, 1, _RET_IP_); - } - - kernfs_unmap_bin_file(kn); - - mutex_lock(&kernfs_mutex); -} - -/** - * kernfs_get - get a reference count on a kernfs_node - * @kn: the target kernfs_node - */ -void kernfs_get(struct kernfs_node *kn) -{ - if (kn) { - WARN_ON(!atomic_read(&kn->count)); - atomic_inc(&kn->count); - } -} -EXPORT_SYMBOL_GPL(kernfs_get); - -/** - * kernfs_put - put a reference count on a kernfs_node - * @kn: the target kernfs_node - * - * Put a reference count of @kn and destroy it if it reached zero. - */ -void kernfs_put(struct kernfs_node *kn) -{ - struct kernfs_node *parent; - struct kernfs_root *root; - - if (!kn || !atomic_dec_and_test(&kn->count)) - return; - root = kernfs_root(kn); - repeat: - /* - * Moving/renaming is always done while holding reference. - * kn->parent won't change beneath us. - */ - parent = kn->parent; - - WARN_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS, - "kernfs_put: %s/%s: released with incorrect active_ref %d\n", - parent ? parent->name : "", kn->name, atomic_read(&kn->active)); - - if (kernfs_type(kn) == KERNFS_LINK) - kernfs_put(kn->symlink.target_kn); - - kfree_const(kn->name); - - if (kn->iattr) { - if (kn->iattr->ia_secdata) - security_release_secctx(kn->iattr->ia_secdata, - kn->iattr->ia_secdata_len); - simple_xattrs_free(&kn->iattr->xattrs); - } - kfree(kn->iattr); - ida_simple_remove(&root->ino_ida, kn->ino); - kmem_cache_free(kernfs_node_cache, kn); - - kn = parent; - if (kn) { - if (atomic_dec_and_test(&kn->count)) - goto repeat; - } else { - /* just released the root kn, free @root too */ - ida_destroy(&root->ino_ida); - kfree(root); - } -} -EXPORT_SYMBOL_GPL(kernfs_put); - -static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags) -{ - struct kernfs_node *kn; - - if (flags & LOOKUP_RCU) - return -ECHILD; - - /* Always perform fresh lookup for negatives */ - if (d_really_is_negative(dentry)) - goto out_bad_unlocked; - - kn = dentry->d_fsdata; - mutex_lock(&kernfs_mutex); - - /* The kernfs node has been deactivated */ - if (!kernfs_active(kn)) - goto out_bad; - - /* The kernfs node has been moved? */ - if (dentry->d_parent->d_fsdata != kn->parent) - goto out_bad; - - /* The kernfs node has been renamed */ - if (strcmp(dentry->d_name.name, kn->name) != 0) - goto out_bad; - - /* The kernfs node has been moved to a different namespace */ - if (kn->parent && kernfs_ns_enabled(kn->parent) && - kernfs_info(dentry->d_sb)->ns != kn->ns) - goto out_bad; - - mutex_unlock(&kernfs_mutex); - return 1; -out_bad: - mutex_unlock(&kernfs_mutex); -out_bad_unlocked: - return 0; -} - -static void kernfs_dop_release(struct dentry *dentry) -{ - kernfs_put(dentry->d_fsdata); -} - -const struct dentry_operations kernfs_dops = { - .d_revalidate = kernfs_dop_revalidate, - .d_release = kernfs_dop_release, -}; - -/** - * kernfs_node_from_dentry - determine kernfs_node associated with a dentry - * @dentry: the dentry in question - * - * Return the kernfs_node associated with @dentry. If @dentry is not a - * kernfs one, %NULL is returned. - * - * While the returned kernfs_node will stay accessible as long as @dentry - * is accessible, the returned node can be in any state and the caller is - * fully responsible for determining what's accessible. - */ -struct kernfs_node *kernfs_node_from_dentry(struct dentry *dentry) -{ - if (dentry->d_sb->s_op == &kernfs_sops) - return dentry->d_fsdata; - return NULL; -} - -static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root, - const char *name, umode_t mode, - unsigned flags) -{ - struct kernfs_node *kn; - int ret; - - name = kstrdup_const(name, GFP_KERNEL); - if (!name) - return NULL; - - kn = kmem_cache_zalloc(kernfs_node_cache, GFP_KERNEL); - if (!kn) - goto err_out1; - - ret = ida_simple_get(&root->ino_ida, 1, 0, GFP_KERNEL); - if (ret < 0) - goto err_out2; - kn->ino = ret; - - atomic_set(&kn->count, 1); - atomic_set(&kn->active, KN_DEACTIVATED_BIAS); - RB_CLEAR_NODE(&kn->rb); - - kn->name = name; - kn->mode = mode; - kn->flags = flags; - - return kn; - - err_out2: - kmem_cache_free(kernfs_node_cache, kn); - err_out1: - kfree_const(name); - return NULL; -} - -struct kernfs_node *kernfs_new_node(struct kernfs_node *parent, - const char *name, umode_t mode, - unsigned flags) -{ - struct kernfs_node *kn; - - kn = __kernfs_new_node(kernfs_root(parent), name, mode, flags); - if (kn) { - kernfs_get(parent); - kn->parent = parent; - } - return kn; -} - -/** - * kernfs_add_one - add kernfs_node to parent without warning - * @kn: kernfs_node to be added - * - * The caller must already have initialized @kn->parent. This - * function increments nlink of the parent's inode if @kn is a - * directory and link into the children list of the parent. - * - * RETURNS: - * 0 on success, -EEXIST if entry with the given name already - * exists. - */ -int kernfs_add_one(struct kernfs_node *kn) -{ - struct kernfs_node *parent = kn->parent; - struct kernfs_iattrs *ps_iattr; - bool has_ns; - int ret; - - mutex_lock(&kernfs_mutex); - - ret = -EINVAL; - has_ns = kernfs_ns_enabled(parent); - if (WARN(has_ns != (bool)kn->ns, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n", - has_ns ? "required" : "invalid", parent->name, kn->name)) - goto out_unlock; - - if (kernfs_type(parent) != KERNFS_DIR) - goto out_unlock; - - ret = -ENOENT; - if (parent->flags & KERNFS_EMPTY_DIR) - goto out_unlock; - - if ((parent->flags & KERNFS_ACTIVATED) && !kernfs_active(parent)) - goto out_unlock; - - kn->hash = kernfs_name_hash(kn->name, kn->ns); - - ret = kernfs_link_sibling(kn); - if (ret) - goto out_unlock; - - /* Update timestamps on the parent */ - ps_iattr = parent->iattr; - if (ps_iattr) { - struct iattr *ps_iattrs = &ps_iattr->ia_iattr; - ktime_get_real_ts(&ps_iattrs->ia_ctime); - ps_iattrs->ia_mtime = ps_iattrs->ia_ctime; - } - - mutex_unlock(&kernfs_mutex); - - /* - * Activate the new node unless CREATE_DEACTIVATED is requested. - * If not activated here, the kernfs user is responsible for - * activating the node with kernfs_activate(). A node which hasn't - * been activated is not visible to userland and its removal won't - * trigger deactivation. - */ - if (!(kernfs_root(kn)->flags & KERNFS_ROOT_CREATE_DEACTIVATED)) - kernfs_activate(kn); - return 0; - -out_unlock: - mutex_unlock(&kernfs_mutex); - return ret; -} - -/** - * kernfs_find_ns - find kernfs_node with the given name - * @parent: kernfs_node to search under - * @name: name to look for - * @ns: the namespace tag to use - * - * Look for kernfs_node with name @name under @parent. Returns pointer to - * the found kernfs_node on success, %NULL on failure. - */ -static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent, - const unsigned char *name, - const void *ns) -{ - struct rb_node *node = parent->dir.children.rb_node; - bool has_ns = kernfs_ns_enabled(parent); - unsigned int hash; - - lockdep_assert_held(&kernfs_mutex); - - if (has_ns != (bool)ns) { - WARN(1, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n", - has_ns ? "required" : "invalid", parent->name, name); - return NULL; - } - - hash = kernfs_name_hash(name, ns); - while (node) { - struct kernfs_node *kn; - int result; - - kn = rb_to_kn(node); - result = kernfs_name_compare(hash, name, ns, kn); - if (result < 0) - node = node->rb_left; - else if (result > 0) - node = node->rb_right; - else - return kn; - } - return NULL; -} - -static struct kernfs_node *kernfs_walk_ns(struct kernfs_node *parent, - const unsigned char *path, - const void *ns) -{ - size_t len; - char *p, *name; - - lockdep_assert_held(&kernfs_mutex); - - /* grab kernfs_rename_lock to piggy back on kernfs_pr_cont_buf */ - spin_lock_irq(&kernfs_rename_lock); - - len = strlcpy(kernfs_pr_cont_buf, path, sizeof(kernfs_pr_cont_buf)); - - if (len >= sizeof(kernfs_pr_cont_buf)) { - spin_unlock_irq(&kernfs_rename_lock); - return NULL; - } - - p = kernfs_pr_cont_buf; - - while ((name = strsep(&p, "/")) && parent) { - if (*name == '\0') - continue; - parent = kernfs_find_ns(parent, name, ns); - } - - spin_unlock_irq(&kernfs_rename_lock); - - return parent; -} - -/** - * kernfs_find_and_get_ns - find and get kernfs_node with the given name - * @parent: kernfs_node to search under - * @name: name to look for - * @ns: the namespace tag to use - * - * Look for kernfs_node with name @name under @parent and get a reference - * if found. This function may sleep and returns pointer to the found - * kernfs_node on success, %NULL on failure. - */ -struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, - const char *name, const void *ns) -{ - struct kernfs_node *kn; - - mutex_lock(&kernfs_mutex); - kn = kernfs_find_ns(parent, name, ns); - kernfs_get(kn); - mutex_unlock(&kernfs_mutex); - - return kn; -} -EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns); - -/** - * kernfs_walk_and_get_ns - find and get kernfs_node with the given path - * @parent: kernfs_node to search under - * @path: path to look for - * @ns: the namespace tag to use - * - * Look for kernfs_node with path @path under @parent and get a reference - * if found. This function may sleep and returns pointer to the found - * kernfs_node on success, %NULL on failure. - */ -struct kernfs_node *kernfs_walk_and_get_ns(struct kernfs_node *parent, - const char *path, const void *ns) -{ - struct kernfs_node *kn; - - mutex_lock(&kernfs_mutex); - kn = kernfs_walk_ns(parent, path, ns); - kernfs_get(kn); - mutex_unlock(&kernfs_mutex); - - return kn; -} - -/** - * kernfs_create_root - create a new kernfs hierarchy - * @scops: optional syscall operations for the hierarchy - * @flags: KERNFS_ROOT_* flags - * @priv: opaque data associated with the new directory - * - * Returns the root of the new hierarchy on success, ERR_PTR() value on - * failure. - */ -struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops, - unsigned int flags, void *priv) -{ - struct kernfs_root *root; - struct kernfs_node *kn; - - root = kzalloc(sizeof(*root), GFP_KERNEL); - if (!root) - return ERR_PTR(-ENOMEM); - - ida_init(&root->ino_ida); - INIT_LIST_HEAD(&root->supers); - - kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO, - KERNFS_DIR); - if (!kn) { - ida_destroy(&root->ino_ida); - kfree(root); - return ERR_PTR(-ENOMEM); - } - - kn->priv = priv; - kn->dir.root = root; - - root->syscall_ops = scops; - root->flags = flags; - root->kn = kn; - init_waitqueue_head(&root->deactivate_waitq); - - if (!(root->flags & KERNFS_ROOT_CREATE_DEACTIVATED)) - kernfs_activate(kn); - - return root; -} - -/** - * kernfs_destroy_root - destroy a kernfs hierarchy - * @root: root of the hierarchy to destroy - * - * Destroy the hierarchy anchored at @root by removing all existing - * directories and destroying @root. - */ -void kernfs_destroy_root(struct kernfs_root *root) -{ - kernfs_remove(root->kn); /* will also free @root */ -} - -/** - * kernfs_create_dir_ns - create a directory - * @parent: parent in which to create a new directory - * @name: name of the new directory - * @mode: mode of the new directory - * @priv: opaque data associated with the new directory - * @ns: optional namespace tag of the directory - * - * Returns the created node on success, ERR_PTR() value on failure. - */ -struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, - const char *name, umode_t mode, - void *priv, const void *ns) -{ - struct kernfs_node *kn; - int rc; - - /* allocate */ - kn = kernfs_new_node(parent, name, mode | S_IFDIR, KERNFS_DIR); - if (!kn) - return ERR_PTR(-ENOMEM); - - kn->dir.root = parent->dir.root; - kn->ns = ns; - kn->priv = priv; - - /* link in */ - rc = kernfs_add_one(kn); - if (!rc) - return kn; - - kernfs_put(kn); - return ERR_PTR(rc); -} - -/** - * kernfs_create_empty_dir - create an always empty directory - * @parent: parent in which to create a new directory - * @name: name of the new directory - * - * Returns the created node on success, ERR_PTR() value on failure. - */ -struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent, - const char *name) -{ - struct kernfs_node *kn; - int rc; - - /* allocate */ - kn = kernfs_new_node(parent, name, S_IRUGO|S_IXUGO|S_IFDIR, KERNFS_DIR); - if (!kn) - return ERR_PTR(-ENOMEM); - - kn->flags |= KERNFS_EMPTY_DIR; - kn->dir.root = parent->dir.root; - kn->ns = NULL; - kn->priv = NULL; - - /* link in */ - rc = kernfs_add_one(kn); - if (!rc) - return kn; - - kernfs_put(kn); - return ERR_PTR(rc); -} - -static struct dentry *kernfs_iop_lookup(struct inode *dir, - struct dentry *dentry, - unsigned int flags) -{ - struct dentry *ret; - struct kernfs_node *parent = dentry->d_parent->d_fsdata; - struct kernfs_node *kn; - struct inode *inode; - const void *ns = NULL; - - mutex_lock(&kernfs_mutex); - - if (kernfs_ns_enabled(parent)) - ns = kernfs_info(dir->i_sb)->ns; - - kn = kernfs_find_ns(parent, dentry->d_name.name, ns); - - /* no such entry */ - if (!kn || !kernfs_active(kn)) { - ret = NULL; - goto out_unlock; - } - kernfs_get(kn); - dentry->d_fsdata = kn; - - /* attach dentry and inode */ - inode = kernfs_get_inode(dir->i_sb, kn); - if (!inode) { - ret = ERR_PTR(-ENOMEM); - goto out_unlock; - } - - /* instantiate and hash dentry */ - ret = d_splice_alias(inode, dentry); - out_unlock: - mutex_unlock(&kernfs_mutex); - return ret; -} - -static int kernfs_iop_mkdir(struct inode *dir, struct dentry *dentry, - umode_t mode) -{ - struct kernfs_node *parent = dir->i_private; - struct kernfs_syscall_ops *scops = kernfs_root(parent)->syscall_ops; - int ret; - - if (!scops || !scops->mkdir) - return -EPERM; - - if (!kernfs_get_active(parent)) - return -ENODEV; - - ret = scops->mkdir(parent, dentry->d_name.name, mode); - - kernfs_put_active(parent); - return ret; -} - -static int kernfs_iop_rmdir(struct inode *dir, struct dentry *dentry) -{ - struct kernfs_node *kn = dentry->d_fsdata; - struct kernfs_syscall_ops *scops = kernfs_root(kn)->syscall_ops; - int ret; - - if (!scops || !scops->rmdir) - return -EPERM; - - if (!kernfs_get_active(kn)) - return -ENODEV; - - ret = scops->rmdir(kn); - - kernfs_put_active(kn); - return ret; -} - -static int kernfs_iop_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry, - unsigned int flags) -{ - struct kernfs_node *kn = old_dentry->d_fsdata; - struct kernfs_node *new_parent = new_dir->i_private; - struct kernfs_syscall_ops *scops = kernfs_root(kn)->syscall_ops; - int ret; - - if (flags) - return -EINVAL; - - if (!scops || !scops->rename) - return -EPERM; - - if (!kernfs_get_active(kn)) - return -ENODEV; - - if (!kernfs_get_active(new_parent)) { - kernfs_put_active(kn); - return -ENODEV; - } - - ret = scops->rename(kn, new_parent, new_dentry->d_name.name); - - kernfs_put_active(new_parent); - kernfs_put_active(kn); - return ret; -} - -const struct inode_operations kernfs_dir_iops = { - .lookup = kernfs_iop_lookup, - .permission = kernfs_iop_permission, - .setattr = kernfs_iop_setattr, - .getattr = kernfs_iop_getattr, - .listxattr = kernfs_iop_listxattr, - - .mkdir = kernfs_iop_mkdir, - .rmdir = kernfs_iop_rmdir, - .rename = kernfs_iop_rename, -}; - -static struct kernfs_node *kernfs_leftmost_descendant(struct kernfs_node *pos) -{ - struct kernfs_node *last; - - while (true) { - struct rb_node *rbn; - - last = pos; - - if (kernfs_type(pos) != KERNFS_DIR) - break; - - rbn = rb_first(&pos->dir.children); - if (!rbn) - break; - - pos = rb_to_kn(rbn); - } - - return last; -} - -/** - * kernfs_next_descendant_post - find the next descendant for post-order walk - * @pos: the current position (%NULL to initiate traversal) - * @root: kernfs_node whose descendants to walk - * - * Find the next descendant to visit for post-order traversal of @root's - * descendants. @root is included in the iteration and the last node to be - * visited. - */ -static struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos, - struct kernfs_node *root) -{ - struct rb_node *rbn; - - lockdep_assert_held(&kernfs_mutex); - - /* if first iteration, visit leftmost descendant which may be root */ - if (!pos) - return kernfs_leftmost_descendant(root); - - /* if we visited @root, we're done */ - if (pos == root) - return NULL; - - /* if there's an unvisited sibling, visit its leftmost descendant */ - rbn = rb_next(&pos->rb); - if (rbn) - return kernfs_leftmost_descendant(rb_to_kn(rbn)); - - /* no sibling left, visit parent */ - return pos->parent; -} - -/** - * kernfs_activate - activate a node which started deactivated - * @kn: kernfs_node whose subtree is to be activated - * - * If the root has KERNFS_ROOT_CREATE_DEACTIVATED set, a newly created node - * needs to be explicitly activated. A node which hasn't been activated - * isn't visible to userland and deactivation is skipped during its - * removal. This is useful to construct atomic init sequences where - * creation of multiple nodes should either succeed or fail atomically. - * - * The caller is responsible for ensuring that this function is not called - * after kernfs_remove*() is invoked on @kn. - */ -void kernfs_activate(struct kernfs_node *kn) -{ - struct kernfs_node *pos; - - mutex_lock(&kernfs_mutex); - - pos = NULL; - while ((pos = kernfs_next_descendant_post(pos, kn))) { - if (!pos || (pos->flags & KERNFS_ACTIVATED)) - continue; - - WARN_ON_ONCE(pos->parent && RB_EMPTY_NODE(&pos->rb)); - WARN_ON_ONCE(atomic_read(&pos->active) != KN_DEACTIVATED_BIAS); - - atomic_sub(KN_DEACTIVATED_BIAS, &pos->active); - pos->flags |= KERNFS_ACTIVATED; - } - - mutex_unlock(&kernfs_mutex); -} - -static void __kernfs_remove(struct kernfs_node *kn) -{ - struct kernfs_node *pos; - - lockdep_assert_held(&kernfs_mutex); - - /* - * Short-circuit if non-root @kn has already finished removal. - * This is for kernfs_remove_self() which plays with active ref - * after removal. - */ - if (!kn || (kn->parent && RB_EMPTY_NODE(&kn->rb))) - return; - - pr_debug("kernfs %s: removing\n", kn->name); - - /* prevent any new usage under @kn by deactivating all nodes */ - pos = NULL; - while ((pos = kernfs_next_descendant_post(pos, kn))) - if (kernfs_active(pos)) - atomic_add(KN_DEACTIVATED_BIAS, &pos->active); - - /* deactivate and unlink the subtree node-by-node */ - do { - pos = kernfs_leftmost_descendant(kn); - - /* - * kernfs_drain() drops kernfs_mutex temporarily and @pos's - * base ref could have been put by someone else by the time - * the function returns. Make sure it doesn't go away - * underneath us. - */ - kernfs_get(pos); - - /* - * Drain iff @kn was activated. This avoids draining and - * its lockdep annotations for nodes which have never been - * activated and allows embedding kernfs_remove() in create - * error paths without worrying about draining. - */ - if (kn->flags & KERNFS_ACTIVATED) - kernfs_drain(pos); - else - WARN_ON_ONCE(atomic_read(&kn->active) != KN_DEACTIVATED_BIAS); - - /* - * kernfs_unlink_sibling() succeeds once per node. Use it - * to decide who's responsible for cleanups. - */ - if (!pos->parent || kernfs_unlink_sibling(pos)) { - struct kernfs_iattrs *ps_iattr = - pos->parent ? pos->parent->iattr : NULL; - - /* update timestamps on the parent */ - if (ps_iattr) { - ktime_get_real_ts(&ps_iattr->ia_iattr.ia_ctime); - ps_iattr->ia_iattr.ia_mtime = - ps_iattr->ia_iattr.ia_ctime; - } - - kernfs_put(pos); - } - - kernfs_put(pos); - } while (pos != kn); -} - -/** - * kernfs_remove - remove a kernfs_node recursively - * @kn: the kernfs_node to remove - * - * Remove @kn along with all its subdirectories and files. - */ -void kernfs_remove(struct kernfs_node *kn) -{ - mutex_lock(&kernfs_mutex); - __kernfs_remove(kn); - mutex_unlock(&kernfs_mutex); -} - -/** - * kernfs_break_active_protection - break out of active protection - * @kn: the self kernfs_node - * - * The caller must be running off of a kernfs operation which is invoked - * with an active reference - e.g. one of kernfs_ops. Each invocation of - * this function must also be matched with an invocation of - * kernfs_unbreak_active_protection(). - * - * This function releases the active reference of @kn the caller is - * holding. Once this function is called, @kn may be removed at any point - * and the caller is solely responsible for ensuring that the objects it - * dereferences are accessible. - */ -void kernfs_break_active_protection(struct kernfs_node *kn) -{ - /* - * Take out ourself out of the active ref dependency chain. If - * we're called without an active ref, lockdep will complain. - */ - kernfs_put_active(kn); -} - -/** - * kernfs_unbreak_active_protection - undo kernfs_break_active_protection() - * @kn: the self kernfs_node - * - * If kernfs_break_active_protection() was called, this function must be - * invoked before finishing the kernfs operation. Note that while this - * function restores the active reference, it doesn't and can't actually - * restore the active protection - @kn may already or be in the process of - * being removed. Once kernfs_break_active_protection() is invoked, that - * protection is irreversibly gone for the kernfs operation instance. - * - * While this function may be called at any point after - * kernfs_break_active_protection() is invoked, its most useful location - * would be right before the enclosing kernfs operation returns. - */ -void kernfs_unbreak_active_protection(struct kernfs_node *kn) -{ - /* - * @kn->active could be in any state; however, the increment we do - * here will be undone as soon as the enclosing kernfs operation - * finishes and this temporary bump can't break anything. If @kn - * is alive, nothing changes. If @kn is being deactivated, the - * soon-to-follow put will either finish deactivation or restore - * deactivated state. If @kn is already removed, the temporary - * bump is guaranteed to be gone before @kn is released. - */ - atomic_inc(&kn->active); - if (kernfs_lockdep(kn)) - rwsem_acquire(&kn->dep_map, 0, 1, _RET_IP_); -} - -/** - * kernfs_remove_self - remove a kernfs_node from its own method - * @kn: the self kernfs_node to remove - * - * The caller must be running off of a kernfs operation which is invoked - * with an active reference - e.g. one of kernfs_ops. This can be used to - * implement a file operation which deletes itself. - * - * For example, the "delete" file for a sysfs device directory can be - * implemented by invoking kernfs_remove_self() on the "delete" file - * itself. This function breaks the circular dependency of trying to - * deactivate self while holding an active ref itself. It isn't necessary - * to modify the usual removal path to use kernfs_remove_self(). The - * "delete" implementation can simply invoke kernfs_remove_self() on self - * before proceeding with the usual removal path. kernfs will ignore later - * kernfs_remove() on self. - * - * kernfs_remove_self() can be called multiple times concurrently on the - * same kernfs_node. Only the first one actually performs removal and - * returns %true. All others will wait until the kernfs operation which - * won self-removal finishes and return %false. Note that the losers wait - * for the completion of not only the winning kernfs_remove_self() but also - * the whole kernfs_ops which won the arbitration. This can be used to - * guarantee, for example, all concurrent writes to a "delete" file to - * finish only after the whole operation is complete. - */ -bool kernfs_remove_self(struct kernfs_node *kn) -{ - bool ret; - - mutex_lock(&kernfs_mutex); - kernfs_break_active_protection(kn); - - /* - * SUICIDAL is used to arbitrate among competing invocations. Only - * the first one will actually perform removal. When the removal - * is complete, SUICIDED is set and the active ref is restored - * while holding kernfs_mutex. The ones which lost arbitration - * waits for SUICDED && drained which can happen only after the - * enclosing kernfs operation which executed the winning instance - * of kernfs_remove_self() finished. - */ - if (!(kn->flags & KERNFS_SUICIDAL)) { - kn->flags |= KERNFS_SUICIDAL; - __kernfs_remove(kn); - kn->flags |= KERNFS_SUICIDED; - ret = true; - } else { - wait_queue_head_t *waitq = &kernfs_root(kn)->deactivate_waitq; - DEFINE_WAIT(wait); - - while (true) { - prepare_to_wait(waitq, &wait, TASK_UNINTERRUPTIBLE); - - if ((kn->flags & KERNFS_SUICIDED) && - atomic_read(&kn->active) == KN_DEACTIVATED_BIAS) - break; - - mutex_unlock(&kernfs_mutex); - schedule(); - mutex_lock(&kernfs_mutex); - } - finish_wait(waitq, &wait); - WARN_ON_ONCE(!RB_EMPTY_NODE(&kn->rb)); - ret = false; - } - - /* - * This must be done while holding kernfs_mutex; otherwise, waiting - * for SUICIDED && deactivated could finish prematurely. - */ - kernfs_unbreak_active_protection(kn); - - mutex_unlock(&kernfs_mutex); - return ret; -} - -/** - * kernfs_remove_by_name_ns - find a kernfs_node by name and remove it - * @parent: parent of the target - * @name: name of the kernfs_node to remove - * @ns: namespace tag of the kernfs_node to remove - * - * Look for the kernfs_node with @name and @ns under @parent and remove it. - * Returns 0 on success, -ENOENT if such entry doesn't exist. - */ -int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, - const void *ns) -{ - struct kernfs_node *kn; - - if (!parent) { - WARN(1, KERN_WARNING "kernfs: can not remove '%s', no directory\n", - name); - return -ENOENT; - } - - mutex_lock(&kernfs_mutex); - - kn = kernfs_find_ns(parent, name, ns); - if (kn) - __kernfs_remove(kn); - - mutex_unlock(&kernfs_mutex); - - if (kn) - return 0; - else - return -ENOENT; -} - -/** - * kernfs_rename_ns - move and rename a kernfs_node - * @kn: target node - * @new_parent: new parent to put @sd under - * @new_name: new name - * @new_ns: new namespace tag - */ -int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, - const char *new_name, const void *new_ns) -{ - struct kernfs_node *old_parent; - const char *old_name = NULL; - int error; - - /* can't move or rename root */ - if (!kn->parent) - return -EINVAL; - - mutex_lock(&kernfs_mutex); - - error = -ENOENT; - if (!kernfs_active(kn) || !kernfs_active(new_parent) || - (new_parent->flags & KERNFS_EMPTY_DIR)) - goto out; - - error = 0; - if ((kn->parent == new_parent) && (kn->ns == new_ns) && - (strcmp(kn->name, new_name) == 0)) - goto out; /* nothing to rename */ - - error = -EEXIST; - if (kernfs_find_ns(new_parent, new_name, new_ns)) - goto out; - - /* rename kernfs_node */ - if (strcmp(kn->name, new_name) != 0) { - error = -ENOMEM; - new_name = kstrdup_const(new_name, GFP_KERNEL); - if (!new_name) - goto out; - } else { - new_name = NULL; - } - - /* - * Move to the appropriate place in the appropriate directories rbtree. - */ - kernfs_unlink_sibling(kn); - kernfs_get(new_parent); - - /* rename_lock protects ->parent and ->name accessors */ - spin_lock_irq(&kernfs_rename_lock); - - old_parent = kn->parent; - kn->parent = new_parent; - - kn->ns = new_ns; - if (new_name) { - old_name = kn->name; - kn->name = new_name; - } - - spin_unlock_irq(&kernfs_rename_lock); - - kn->hash = kernfs_name_hash(kn->name, kn->ns); - kernfs_link_sibling(kn); - - kernfs_put(old_parent); - kfree_const(old_name); - - error = 0; - out: - mutex_unlock(&kernfs_mutex); - return error; -} - -/* Relationship between s_mode and the DT_xxx types */ -static inline unsigned char dt_type(struct kernfs_node *kn) -{ - return (kn->mode >> 12) & 15; -} - -static int kernfs_dir_fop_release(struct inode *inode, struct file *filp) -{ - kernfs_put(filp->private_data); - return 0; -} - -static struct kernfs_node *kernfs_dir_pos(const void *ns, - struct kernfs_node *parent, loff_t hash, struct kernfs_node *pos) -{ - if (pos) { - int valid = kernfs_active(pos) && - pos->parent == parent && hash == pos->hash; - kernfs_put(pos); - if (!valid) - pos = NULL; - } - if (!pos && (hash > 1) && (hash < INT_MAX)) { - struct rb_node *node = parent->dir.children.rb_node; - while (node) { - pos = rb_to_kn(node); - - if (hash < pos->hash) - node = node->rb_left; - else if (hash > pos->hash) - node = node->rb_right; - else - break; - } - } - /* Skip over entries which are dying/dead or in the wrong namespace */ - while (pos && (!kernfs_active(pos) || pos->ns != ns)) { - struct rb_node *node = rb_next(&pos->rb); - if (!node) - pos = NULL; - else - pos = rb_to_kn(node); - } - return pos; -} - -static struct kernfs_node *kernfs_dir_next_pos(const void *ns, - struct kernfs_node *parent, ino_t ino, struct kernfs_node *pos) -{ - pos = kernfs_dir_pos(ns, parent, ino, pos); - if (pos) { - do { - struct rb_node *node = rb_next(&pos->rb); - if (!node) - pos = NULL; - else - pos = rb_to_kn(node); - } while (pos && (!kernfs_active(pos) || pos->ns != ns)); - } - return pos; -} - -static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx) -{ - struct dentry *dentry = file->f_path.dentry; - struct kernfs_node *parent = dentry->d_fsdata; - struct kernfs_node *pos = file->private_data; - const void *ns = NULL; - - if (!dir_emit_dots(file, ctx)) - return 0; - mutex_lock(&kernfs_mutex); - - if (kernfs_ns_enabled(parent)) - ns = kernfs_info(dentry->d_sb)->ns; - - for (pos = kernfs_dir_pos(ns, parent, ctx->pos, pos); - pos; - pos = kernfs_dir_next_pos(ns, parent, ctx->pos, pos)) { - const char *name = pos->name; - unsigned int type = dt_type(pos); - int len = strlen(name); - ino_t ino = pos->ino; - - ctx->pos = pos->hash; - file->private_data = pos; - kernfs_get(pos); - - mutex_unlock(&kernfs_mutex); - if (!dir_emit(ctx, name, len, ino, type)) - return 0; - mutex_lock(&kernfs_mutex); - } - mutex_unlock(&kernfs_mutex); - file->private_data = NULL; - ctx->pos = INT_MAX; - return 0; -} - -const struct file_operations kernfs_dir_fops = { - .read = generic_read_dir, - .iterate_shared = kernfs_fop_readdir, - .release = kernfs_dir_fop_release, - .llseek = generic_file_llseek, -}; diff --git a/src/linux/fs/kernfs/file.c b/src/linux/fs/kernfs/file.c deleted file mode 100644 index 78219d5..0000000 --- a/src/linux/fs/kernfs/file.c +++ /dev/null @@ -1,975 +0,0 @@ -/* - * fs/kernfs/file.c - kernfs file implementation - * - * Copyright (c) 2001-3 Patrick Mochel - * Copyright (c) 2007 SUSE Linux Products GmbH - * Copyright (c) 2007, 2013 Tejun Heo - * - * This file is released under the GPLv2. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "kernfs-internal.h" - -/* - * There's one kernfs_open_file for each open file and one kernfs_open_node - * for each kernfs_node with one or more open files. - * - * kernfs_node->attr.open points to kernfs_open_node. attr.open is - * protected by kernfs_open_node_lock. - * - * filp->private_data points to seq_file whose ->private points to - * kernfs_open_file. kernfs_open_files are chained at - * kernfs_open_node->files, which is protected by kernfs_open_file_mutex. - */ -static DEFINE_SPINLOCK(kernfs_open_node_lock); -static DEFINE_MUTEX(kernfs_open_file_mutex); - -struct kernfs_open_node { - atomic_t refcnt; - atomic_t event; - wait_queue_head_t poll; - struct list_head files; /* goes through kernfs_open_file.list */ -}; - -/* - * kernfs_notify() may be called from any context and bounces notifications - * through a work item. To minimize space overhead in kernfs_node, the - * pending queue is implemented as a singly linked list of kernfs_nodes. - * The list is terminated with the self pointer so that whether a - * kernfs_node is on the list or not can be determined by testing the next - * pointer for NULL. - */ -#define KERNFS_NOTIFY_EOL ((void *)&kernfs_notify_list) - -static DEFINE_SPINLOCK(kernfs_notify_lock); -static struct kernfs_node *kernfs_notify_list = KERNFS_NOTIFY_EOL; - -static struct kernfs_open_file *kernfs_of(struct file *file) -{ - return ((struct seq_file *)file->private_data)->private; -} - -/* - * Determine the kernfs_ops for the given kernfs_node. This function must - * be called while holding an active reference. - */ -static const struct kernfs_ops *kernfs_ops(struct kernfs_node *kn) -{ - if (kn->flags & KERNFS_LOCKDEP) - lockdep_assert_held(kn); - return kn->attr.ops; -} - -/* - * As kernfs_seq_stop() is also called after kernfs_seq_start() or - * kernfs_seq_next() failure, it needs to distinguish whether it's stopping - * a seq_file iteration which is fully initialized with an active reference - * or an aborted kernfs_seq_start() due to get_active failure. The - * position pointer is the only context for each seq_file iteration and - * thus the stop condition should be encoded in it. As the return value is - * directly visible to userland, ERR_PTR(-ENODEV) is the only acceptable - * choice to indicate get_active failure. - * - * Unfortunately, this is complicated due to the optional custom seq_file - * operations which may return ERR_PTR(-ENODEV) too. kernfs_seq_stop() - * can't distinguish whether ERR_PTR(-ENODEV) is from get_active failure or - * custom seq_file operations and thus can't decide whether put_active - * should be performed or not only on ERR_PTR(-ENODEV). - * - * This is worked around by factoring out the custom seq_stop() and - * put_active part into kernfs_seq_stop_active(), skipping it from - * kernfs_seq_stop() if ERR_PTR(-ENODEV) while invoking it directly after - * custom seq_file operations fail with ERR_PTR(-ENODEV) - this ensures - * that kernfs_seq_stop_active() is skipped only after get_active failure. - */ -static void kernfs_seq_stop_active(struct seq_file *sf, void *v) -{ - struct kernfs_open_file *of = sf->private; - const struct kernfs_ops *ops = kernfs_ops(of->kn); - - if (ops->seq_stop) - ops->seq_stop(sf, v); - kernfs_put_active(of->kn); -} - -static void *kernfs_seq_start(struct seq_file *sf, loff_t *ppos) -{ - struct kernfs_open_file *of = sf->private; - const struct kernfs_ops *ops; - - /* - * @of->mutex nests outside active ref and is primarily to ensure that - * the ops aren't called concurrently for the same open file. - */ - mutex_lock(&of->mutex); - if (!kernfs_get_active(of->kn)) - return ERR_PTR(-ENODEV); - - ops = kernfs_ops(of->kn); - if (ops->seq_start) { - void *next = ops->seq_start(sf, ppos); - /* see the comment above kernfs_seq_stop_active() */ - if (next == ERR_PTR(-ENODEV)) - kernfs_seq_stop_active(sf, next); - return next; - } else { - /* - * The same behavior and code as single_open(). Returns - * !NULL if pos is at the beginning; otherwise, NULL. - */ - return NULL + !*ppos; - } -} - -static void *kernfs_seq_next(struct seq_file *sf, void *v, loff_t *ppos) -{ - struct kernfs_open_file *of = sf->private; - const struct kernfs_ops *ops = kernfs_ops(of->kn); - - if (ops->seq_next) { - void *next = ops->seq_next(sf, v, ppos); - /* see the comment above kernfs_seq_stop_active() */ - if (next == ERR_PTR(-ENODEV)) - kernfs_seq_stop_active(sf, next); - return next; - } else { - /* - * The same behavior and code as single_open(), always - * terminate after the initial read. - */ - ++*ppos; - return NULL; - } -} - -static void kernfs_seq_stop(struct seq_file *sf, void *v) -{ - struct kernfs_open_file *of = sf->private; - - if (v != ERR_PTR(-ENODEV)) - kernfs_seq_stop_active(sf, v); - mutex_unlock(&of->mutex); -} - -static int kernfs_seq_show(struct seq_file *sf, void *v) -{ - struct kernfs_open_file *of = sf->private; - - of->event = atomic_read(&of->kn->attr.open->event); - - return of->kn->attr.ops->seq_show(sf, v); -} - -static const struct seq_operations kernfs_seq_ops = { - .start = kernfs_seq_start, - .next = kernfs_seq_next, - .stop = kernfs_seq_stop, - .show = kernfs_seq_show, -}; - -/* - * As reading a bin file can have side-effects, the exact offset and bytes - * specified in read(2) call should be passed to the read callback making - * it difficult to use seq_file. Implement simplistic custom buffering for - * bin files. - */ -static ssize_t kernfs_file_direct_read(struct kernfs_open_file *of, - char __user *user_buf, size_t count, - loff_t *ppos) -{ - ssize_t len = min_t(size_t, count, PAGE_SIZE); - const struct kernfs_ops *ops; - char *buf; - - buf = of->prealloc_buf; - if (buf) - mutex_lock(&of->prealloc_mutex); - else - buf = kmalloc(len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - /* - * @of->mutex nests outside active ref and is used both to ensure that - * the ops aren't called concurrently for the same open file. - */ - mutex_lock(&of->mutex); - if (!kernfs_get_active(of->kn)) { - len = -ENODEV; - mutex_unlock(&of->mutex); - goto out_free; - } - - of->event = atomic_read(&of->kn->attr.open->event); - ops = kernfs_ops(of->kn); - if (ops->read) - len = ops->read(of, buf, len, *ppos); - else - len = -EINVAL; - - kernfs_put_active(of->kn); - mutex_unlock(&of->mutex); - - if (len < 0) - goto out_free; - - if (copy_to_user(user_buf, buf, len)) { - len = -EFAULT; - goto out_free; - } - - *ppos += len; - - out_free: - if (buf == of->prealloc_buf) - mutex_unlock(&of->prealloc_mutex); - else - kfree(buf); - return len; -} - -/** - * kernfs_fop_read - kernfs vfs read callback - * @file: file pointer - * @user_buf: data to write - * @count: number of bytes - * @ppos: starting offset - */ -static ssize_t kernfs_fop_read(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct kernfs_open_file *of = kernfs_of(file); - - if (of->kn->flags & KERNFS_HAS_SEQ_SHOW) - return seq_read(file, user_buf, count, ppos); - else - return kernfs_file_direct_read(of, user_buf, count, ppos); -} - -/** - * kernfs_fop_write - kernfs vfs write callback - * @file: file pointer - * @user_buf: data to write - * @count: number of bytes - * @ppos: starting offset - * - * Copy data in from userland and pass it to the matching kernfs write - * operation. - * - * There is no easy way for us to know if userspace is only doing a partial - * write, so we don't support them. We expect the entire buffer to come on - * the first write. Hint: if you're writing a value, first read the file, - * modify only the the value you're changing, then write entire buffer - * back. - */ -static ssize_t kernfs_fop_write(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos) -{ - struct kernfs_open_file *of = kernfs_of(file); - const struct kernfs_ops *ops; - size_t len; - char *buf; - - if (of->atomic_write_len) { - len = count; - if (len > of->atomic_write_len) - return -E2BIG; - } else { - len = min_t(size_t, count, PAGE_SIZE); - } - - buf = of->prealloc_buf; - if (buf) - mutex_lock(&of->prealloc_mutex); - else - buf = kmalloc(len + 1, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - if (copy_from_user(buf, user_buf, len)) { - len = -EFAULT; - goto out_free; - } - buf[len] = '\0'; /* guarantee string termination */ - - /* - * @of->mutex nests outside active ref and is used both to ensure that - * the ops aren't called concurrently for the same open file. - */ - mutex_lock(&of->mutex); - if (!kernfs_get_active(of->kn)) { - mutex_unlock(&of->mutex); - len = -ENODEV; - goto out_free; - } - - ops = kernfs_ops(of->kn); - if (ops->write) - len = ops->write(of, buf, len, *ppos); - else - len = -EINVAL; - - kernfs_put_active(of->kn); - mutex_unlock(&of->mutex); - - if (len > 0) - *ppos += len; - -out_free: - if (buf == of->prealloc_buf) - mutex_unlock(&of->prealloc_mutex); - else - kfree(buf); - return len; -} - -static void kernfs_vma_open(struct vm_area_struct *vma) -{ - struct file *file = vma->vm_file; - struct kernfs_open_file *of = kernfs_of(file); - - if (!of->vm_ops) - return; - - if (!kernfs_get_active(of->kn)) - return; - - if (of->vm_ops->open) - of->vm_ops->open(vma); - - kernfs_put_active(of->kn); -} - -static int kernfs_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct file *file = vma->vm_file; - struct kernfs_open_file *of = kernfs_of(file); - int ret; - - if (!of->vm_ops) - return VM_FAULT_SIGBUS; - - if (!kernfs_get_active(of->kn)) - return VM_FAULT_SIGBUS; - - ret = VM_FAULT_SIGBUS; - if (of->vm_ops->fault) - ret = of->vm_ops->fault(vma, vmf); - - kernfs_put_active(of->kn); - return ret; -} - -static int kernfs_vma_page_mkwrite(struct vm_area_struct *vma, - struct vm_fault *vmf) -{ - struct file *file = vma->vm_file; - struct kernfs_open_file *of = kernfs_of(file); - int ret; - - if (!of->vm_ops) - return VM_FAULT_SIGBUS; - - if (!kernfs_get_active(of->kn)) - return VM_FAULT_SIGBUS; - - ret = 0; - if (of->vm_ops->page_mkwrite) - ret = of->vm_ops->page_mkwrite(vma, vmf); - else - file_update_time(file); - - kernfs_put_active(of->kn); - return ret; -} - -static int kernfs_vma_access(struct vm_area_struct *vma, unsigned long addr, - void *buf, int len, int write) -{ - struct file *file = vma->vm_file; - struct kernfs_open_file *of = kernfs_of(file); - int ret; - - if (!of->vm_ops) - return -EINVAL; - - if (!kernfs_get_active(of->kn)) - return -EINVAL; - - ret = -EINVAL; - if (of->vm_ops->access) - ret = of->vm_ops->access(vma, addr, buf, len, write); - - kernfs_put_active(of->kn); - return ret; -} - -#ifdef CONFIG_NUMA -static int kernfs_vma_set_policy(struct vm_area_struct *vma, - struct mempolicy *new) -{ - struct file *file = vma->vm_file; - struct kernfs_open_file *of = kernfs_of(file); - int ret; - - if (!of->vm_ops) - return 0; - - if (!kernfs_get_active(of->kn)) - return -EINVAL; - - ret = 0; - if (of->vm_ops->set_policy) - ret = of->vm_ops->set_policy(vma, new); - - kernfs_put_active(of->kn); - return ret; -} - -static struct mempolicy *kernfs_vma_get_policy(struct vm_area_struct *vma, - unsigned long addr) -{ - struct file *file = vma->vm_file; - struct kernfs_open_file *of = kernfs_of(file); - struct mempolicy *pol; - - if (!of->vm_ops) - return vma->vm_policy; - - if (!kernfs_get_active(of->kn)) - return vma->vm_policy; - - pol = vma->vm_policy; - if (of->vm_ops->get_policy) - pol = of->vm_ops->get_policy(vma, addr); - - kernfs_put_active(of->kn); - return pol; -} - -#endif - -static const struct vm_operations_struct kernfs_vm_ops = { - .open = kernfs_vma_open, - .fault = kernfs_vma_fault, - .page_mkwrite = kernfs_vma_page_mkwrite, - .access = kernfs_vma_access, -#ifdef CONFIG_NUMA - .set_policy = kernfs_vma_set_policy, - .get_policy = kernfs_vma_get_policy, -#endif -}; - -static int kernfs_fop_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct kernfs_open_file *of = kernfs_of(file); - const struct kernfs_ops *ops; - int rc; - - /* - * mmap path and of->mutex are prone to triggering spurious lockdep - * warnings and we don't want to add spurious locking dependency - * between the two. Check whether mmap is actually implemented - * without grabbing @of->mutex by testing HAS_MMAP flag. See the - * comment in kernfs_file_open() for more details. - */ - if (!(of->kn->flags & KERNFS_HAS_MMAP)) - return -ENODEV; - - mutex_lock(&of->mutex); - - rc = -ENODEV; - if (!kernfs_get_active(of->kn)) - goto out_unlock; - - ops = kernfs_ops(of->kn); - rc = ops->mmap(of, vma); - if (rc) - goto out_put; - - /* - * PowerPC's pci_mmap of legacy_mem uses shmem_zero_setup() - * to satisfy versions of X which crash if the mmap fails: that - * substitutes a new vm_file, and we don't then want bin_vm_ops. - */ - if (vma->vm_file != file) - goto out_put; - - rc = -EINVAL; - if (of->mmapped && of->vm_ops != vma->vm_ops) - goto out_put; - - /* - * It is not possible to successfully wrap close. - * So error if someone is trying to use close. - */ - rc = -EINVAL; - if (vma->vm_ops && vma->vm_ops->close) - goto out_put; - - rc = 0; - of->mmapped = 1; - of->vm_ops = vma->vm_ops; - vma->vm_ops = &kernfs_vm_ops; -out_put: - kernfs_put_active(of->kn); -out_unlock: - mutex_unlock(&of->mutex); - - return rc; -} - -/** - * kernfs_get_open_node - get or create kernfs_open_node - * @kn: target kernfs_node - * @of: kernfs_open_file for this instance of open - * - * If @kn->attr.open exists, increment its reference count; otherwise, - * create one. @of is chained to the files list. - * - * LOCKING: - * Kernel thread context (may sleep). - * - * RETURNS: - * 0 on success, -errno on failure. - */ -static int kernfs_get_open_node(struct kernfs_node *kn, - struct kernfs_open_file *of) -{ - struct kernfs_open_node *on, *new_on = NULL; - - retry: - mutex_lock(&kernfs_open_file_mutex); - spin_lock_irq(&kernfs_open_node_lock); - - if (!kn->attr.open && new_on) { - kn->attr.open = new_on; - new_on = NULL; - } - - on = kn->attr.open; - if (on) { - atomic_inc(&on->refcnt); - list_add_tail(&of->list, &on->files); - } - - spin_unlock_irq(&kernfs_open_node_lock); - mutex_unlock(&kernfs_open_file_mutex); - - if (on) { - kfree(new_on); - return 0; - } - - /* not there, initialize a new one and retry */ - new_on = kmalloc(sizeof(*new_on), GFP_KERNEL); - if (!new_on) - return -ENOMEM; - - atomic_set(&new_on->refcnt, 0); - atomic_set(&new_on->event, 1); - init_waitqueue_head(&new_on->poll); - INIT_LIST_HEAD(&new_on->files); - goto retry; -} - -/** - * kernfs_put_open_node - put kernfs_open_node - * @kn: target kernfs_nodet - * @of: associated kernfs_open_file - * - * Put @kn->attr.open and unlink @of from the files list. If - * reference count reaches zero, disassociate and free it. - * - * LOCKING: - * None. - */ -static void kernfs_put_open_node(struct kernfs_node *kn, - struct kernfs_open_file *of) -{ - struct kernfs_open_node *on = kn->attr.open; - unsigned long flags; - - mutex_lock(&kernfs_open_file_mutex); - spin_lock_irqsave(&kernfs_open_node_lock, flags); - - if (of) - list_del(&of->list); - - if (atomic_dec_and_test(&on->refcnt)) - kn->attr.open = NULL; - else - on = NULL; - - spin_unlock_irqrestore(&kernfs_open_node_lock, flags); - mutex_unlock(&kernfs_open_file_mutex); - - kfree(on); -} - -static int kernfs_fop_open(struct inode *inode, struct file *file) -{ - struct kernfs_node *kn = file->f_path.dentry->d_fsdata; - struct kernfs_root *root = kernfs_root(kn); - const struct kernfs_ops *ops; - struct kernfs_open_file *of; - bool has_read, has_write, has_mmap; - int error = -EACCES; - - if (!kernfs_get_active(kn)) - return -ENODEV; - - ops = kernfs_ops(kn); - - has_read = ops->seq_show || ops->read || ops->mmap; - has_write = ops->write || ops->mmap; - has_mmap = ops->mmap; - - /* see the flag definition for details */ - if (root->flags & KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK) { - if ((file->f_mode & FMODE_WRITE) && - (!(inode->i_mode & S_IWUGO) || !has_write)) - goto err_out; - - if ((file->f_mode & FMODE_READ) && - (!(inode->i_mode & S_IRUGO) || !has_read)) - goto err_out; - } - - /* allocate a kernfs_open_file for the file */ - error = -ENOMEM; - of = kzalloc(sizeof(struct kernfs_open_file), GFP_KERNEL); - if (!of) - goto err_out; - - /* - * The following is done to give a different lockdep key to - * @of->mutex for files which implement mmap. This is a rather - * crude way to avoid false positive lockdep warning around - * mm->mmap_sem - mmap nests @of->mutex under mm->mmap_sem and - * reading /sys/block/sda/trace/act_mask grabs sr_mutex, under - * which mm->mmap_sem nests, while holding @of->mutex. As each - * open file has a separate mutex, it's okay as long as those don't - * happen on the same file. At this point, we can't easily give - * each file a separate locking class. Let's differentiate on - * whether the file has mmap or not for now. - * - * Both paths of the branch look the same. They're supposed to - * look that way and give @of->mutex different static lockdep keys. - */ - if (has_mmap) - mutex_init(&of->mutex); - else - mutex_init(&of->mutex); - - of->kn = kn; - of->file = file; - - /* - * Write path needs to atomic_write_len outside active reference. - * Cache it in open_file. See kernfs_fop_write() for details. - */ - of->atomic_write_len = ops->atomic_write_len; - - error = -EINVAL; - /* - * ->seq_show is incompatible with ->prealloc, - * as seq_read does its own allocation. - * ->read must be used instead. - */ - if (ops->prealloc && ops->seq_show) - goto err_free; - if (ops->prealloc) { - int len = of->atomic_write_len ?: PAGE_SIZE; - of->prealloc_buf = kmalloc(len + 1, GFP_KERNEL); - error = -ENOMEM; - if (!of->prealloc_buf) - goto err_free; - mutex_init(&of->prealloc_mutex); - } - - /* - * Always instantiate seq_file even if read access doesn't use - * seq_file or is not requested. This unifies private data access - * and readable regular files are the vast majority anyway. - */ - if (ops->seq_show) - error = seq_open(file, &kernfs_seq_ops); - else - error = seq_open(file, NULL); - if (error) - goto err_free; - - ((struct seq_file *)file->private_data)->private = of; - - /* seq_file clears PWRITE unconditionally, restore it if WRITE */ - if (file->f_mode & FMODE_WRITE) - file->f_mode |= FMODE_PWRITE; - - /* make sure we have open node struct */ - error = kernfs_get_open_node(kn, of); - if (error) - goto err_close; - - /* open succeeded, put active references */ - kernfs_put_active(kn); - return 0; - -err_close: - seq_release(inode, file); -err_free: - kfree(of->prealloc_buf); - kfree(of); -err_out: - kernfs_put_active(kn); - return error; -} - -static int kernfs_fop_release(struct inode *inode, struct file *filp) -{ - struct kernfs_node *kn = filp->f_path.dentry->d_fsdata; - struct kernfs_open_file *of = kernfs_of(filp); - - kernfs_put_open_node(kn, of); - seq_release(inode, filp); - kfree(of->prealloc_buf); - kfree(of); - - return 0; -} - -void kernfs_unmap_bin_file(struct kernfs_node *kn) -{ - struct kernfs_open_node *on; - struct kernfs_open_file *of; - - if (!(kn->flags & KERNFS_HAS_MMAP)) - return; - - spin_lock_irq(&kernfs_open_node_lock); - on = kn->attr.open; - if (on) - atomic_inc(&on->refcnt); - spin_unlock_irq(&kernfs_open_node_lock); - if (!on) - return; - - mutex_lock(&kernfs_open_file_mutex); - list_for_each_entry(of, &on->files, list) { - struct inode *inode = file_inode(of->file); - unmap_mapping_range(inode->i_mapping, 0, 0, 1); - } - mutex_unlock(&kernfs_open_file_mutex); - - kernfs_put_open_node(kn, NULL); -} - -/* - * Kernfs attribute files are pollable. The idea is that you read - * the content and then you use 'poll' or 'select' to wait for - * the content to change. When the content changes (assuming the - * manager for the kobject supports notification), poll will - * return POLLERR|POLLPRI, and select will return the fd whether - * it is waiting for read, write, or exceptions. - * Once poll/select indicates that the value has changed, you - * need to close and re-open the file, or seek to 0 and read again. - * Reminder: this only works for attributes which actively support - * it, and it is not possible to test an attribute from userspace - * to see if it supports poll (Neither 'poll' nor 'select' return - * an appropriate error code). When in doubt, set a suitable timeout value. - */ -static unsigned int kernfs_fop_poll(struct file *filp, poll_table *wait) -{ - struct kernfs_open_file *of = kernfs_of(filp); - struct kernfs_node *kn = filp->f_path.dentry->d_fsdata; - struct kernfs_open_node *on = kn->attr.open; - - if (!kernfs_get_active(kn)) - goto trigger; - - poll_wait(filp, &on->poll, wait); - - kernfs_put_active(kn); - - if (of->event != atomic_read(&on->event)) - goto trigger; - - return DEFAULT_POLLMASK; - - trigger: - return DEFAULT_POLLMASK|POLLERR|POLLPRI; -} - -static void kernfs_notify_workfn(struct work_struct *work) -{ - struct kernfs_node *kn; - struct kernfs_open_node *on; - struct kernfs_super_info *info; -repeat: - /* pop one off the notify_list */ - spin_lock_irq(&kernfs_notify_lock); - kn = kernfs_notify_list; - if (kn == KERNFS_NOTIFY_EOL) { - spin_unlock_irq(&kernfs_notify_lock); - return; - } - kernfs_notify_list = kn->attr.notify_next; - kn->attr.notify_next = NULL; - spin_unlock_irq(&kernfs_notify_lock); - - /* kick poll */ - spin_lock_irq(&kernfs_open_node_lock); - - on = kn->attr.open; - if (on) { - atomic_inc(&on->event); - wake_up_interruptible(&on->poll); - } - - spin_unlock_irq(&kernfs_open_node_lock); - - /* kick fsnotify */ - mutex_lock(&kernfs_mutex); - - list_for_each_entry(info, &kernfs_root(kn)->supers, node) { - struct kernfs_node *parent; - struct inode *inode; - - /* - * We want fsnotify_modify() on @kn but as the - * modifications aren't originating from userland don't - * have the matching @file available. Look up the inodes - * and generate the events manually. - */ - inode = ilookup(info->sb, kn->ino); - if (!inode) - continue; - - parent = kernfs_get_parent(kn); - if (parent) { - struct inode *p_inode; - - p_inode = ilookup(info->sb, parent->ino); - if (p_inode) { - fsnotify(p_inode, FS_MODIFY | FS_EVENT_ON_CHILD, - inode, FSNOTIFY_EVENT_INODE, kn->name, 0); - iput(p_inode); - } - - kernfs_put(parent); - } - - fsnotify(inode, FS_MODIFY, inode, FSNOTIFY_EVENT_INODE, - kn->name, 0); - iput(inode); - } - - mutex_unlock(&kernfs_mutex); - kernfs_put(kn); - goto repeat; -} - -/** - * kernfs_notify - notify a kernfs file - * @kn: file to notify - * - * Notify @kn such that poll(2) on @kn wakes up. Maybe be called from any - * context. - */ -void kernfs_notify(struct kernfs_node *kn) -{ - static DECLARE_WORK(kernfs_notify_work, kernfs_notify_workfn); - unsigned long flags; - - if (WARN_ON(kernfs_type(kn) != KERNFS_FILE)) - return; - - spin_lock_irqsave(&kernfs_notify_lock, flags); - if (!kn->attr.notify_next) { - kernfs_get(kn); - kn->attr.notify_next = kernfs_notify_list; - kernfs_notify_list = kn; - schedule_work(&kernfs_notify_work); - } - spin_unlock_irqrestore(&kernfs_notify_lock, flags); -} -EXPORT_SYMBOL_GPL(kernfs_notify); - -const struct file_operations kernfs_file_fops = { - .read = kernfs_fop_read, - .write = kernfs_fop_write, - .llseek = generic_file_llseek, - .mmap = kernfs_fop_mmap, - .open = kernfs_fop_open, - .release = kernfs_fop_release, - .poll = kernfs_fop_poll, - .fsync = noop_fsync, -}; - -/** - * __kernfs_create_file - kernfs internal function to create a file - * @parent: directory to create the file in - * @name: name of the file - * @mode: mode of the file - * @size: size of the file - * @ops: kernfs operations for the file - * @priv: private data for the file - * @ns: optional namespace tag of the file - * @key: lockdep key for the file's active_ref, %NULL to disable lockdep - * - * Returns the created node on success, ERR_PTR() value on error. - */ -struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, - const char *name, - umode_t mode, loff_t size, - const struct kernfs_ops *ops, - void *priv, const void *ns, - struct lock_class_key *key) -{ - struct kernfs_node *kn; - unsigned flags; - int rc; - - flags = KERNFS_FILE; - - kn = kernfs_new_node(parent, name, (mode & S_IALLUGO) | S_IFREG, flags); - if (!kn) - return ERR_PTR(-ENOMEM); - - kn->attr.ops = ops; - kn->attr.size = size; - kn->ns = ns; - kn->priv = priv; - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - if (key) { - lockdep_init_map(&kn->dep_map, "s_active", key, 0); - kn->flags |= KERNFS_LOCKDEP; - } -#endif - - /* - * kn->attr.ops is accesible only while holding active ref. We - * need to know whether some ops are implemented outside active - * ref. Cache their existence in flags. - */ - if (ops->seq_show) - kn->flags |= KERNFS_HAS_SEQ_SHOW; - if (ops->mmap) - kn->flags |= KERNFS_HAS_MMAP; - - rc = kernfs_add_one(kn); - if (rc) { - kernfs_put(kn); - return ERR_PTR(rc); - } - return kn; -} diff --git a/src/linux/fs/kernfs/inode.c b/src/linux/fs/kernfs/inode.c deleted file mode 100644 index a198211..0000000 --- a/src/linux/fs/kernfs/inode.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * fs/kernfs/inode.c - kernfs inode implementation - * - * Copyright (c) 2001-3 Patrick Mochel - * Copyright (c) 2007 SUSE Linux Products GmbH - * Copyright (c) 2007, 2013 Tejun Heo - * - * This file is released under the GPLv2. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "kernfs-internal.h" - -static const struct address_space_operations kernfs_aops = { - .readpage = simple_readpage, - .write_begin = simple_write_begin, - .write_end = simple_write_end, -}; - -static const struct inode_operations kernfs_iops = { - .permission = kernfs_iop_permission, - .setattr = kernfs_iop_setattr, - .getattr = kernfs_iop_getattr, - .listxattr = kernfs_iop_listxattr, -}; - -static struct kernfs_iattrs *kernfs_iattrs(struct kernfs_node *kn) -{ - static DEFINE_MUTEX(iattr_mutex); - struct kernfs_iattrs *ret; - struct iattr *iattrs; - - mutex_lock(&iattr_mutex); - - if (kn->iattr) - goto out_unlock; - - kn->iattr = kzalloc(sizeof(struct kernfs_iattrs), GFP_KERNEL); - if (!kn->iattr) - goto out_unlock; - iattrs = &kn->iattr->ia_iattr; - - /* assign default attributes */ - iattrs->ia_mode = kn->mode; - iattrs->ia_uid = GLOBAL_ROOT_UID; - iattrs->ia_gid = GLOBAL_ROOT_GID; - - ktime_get_real_ts(&iattrs->ia_atime); - iattrs->ia_mtime = iattrs->ia_atime; - iattrs->ia_ctime = iattrs->ia_atime; - - simple_xattrs_init(&kn->iattr->xattrs); -out_unlock: - ret = kn->iattr; - mutex_unlock(&iattr_mutex); - return ret; -} - -static int __kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr) -{ - struct kernfs_iattrs *attrs; - struct iattr *iattrs; - unsigned int ia_valid = iattr->ia_valid; - - attrs = kernfs_iattrs(kn); - if (!attrs) - return -ENOMEM; - - iattrs = &attrs->ia_iattr; - - if (ia_valid & ATTR_UID) - iattrs->ia_uid = iattr->ia_uid; - if (ia_valid & ATTR_GID) - iattrs->ia_gid = iattr->ia_gid; - if (ia_valid & ATTR_ATIME) - iattrs->ia_atime = iattr->ia_atime; - if (ia_valid & ATTR_MTIME) - iattrs->ia_mtime = iattr->ia_mtime; - if (ia_valid & ATTR_CTIME) - iattrs->ia_ctime = iattr->ia_ctime; - if (ia_valid & ATTR_MODE) { - umode_t mode = iattr->ia_mode; - iattrs->ia_mode = kn->mode = mode; - } - return 0; -} - -/** - * kernfs_setattr - set iattr on a node - * @kn: target node - * @iattr: iattr to set - * - * Returns 0 on success, -errno on failure. - */ -int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr) -{ - int ret; - - mutex_lock(&kernfs_mutex); - ret = __kernfs_setattr(kn, iattr); - mutex_unlock(&kernfs_mutex); - return ret; -} - -int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr) -{ - struct inode *inode = d_inode(dentry); - struct kernfs_node *kn = dentry->d_fsdata; - int error; - - if (!kn) - return -EINVAL; - - mutex_lock(&kernfs_mutex); - error = setattr_prepare(dentry, iattr); - if (error) - goto out; - - error = __kernfs_setattr(kn, iattr); - if (error) - goto out; - - /* this ignores size changes */ - setattr_copy(inode, iattr); - -out: - mutex_unlock(&kernfs_mutex); - return error; -} - -static int kernfs_node_setsecdata(struct kernfs_iattrs *attrs, void **secdata, - u32 *secdata_len) -{ - void *old_secdata; - size_t old_secdata_len; - - old_secdata = attrs->ia_secdata; - old_secdata_len = attrs->ia_secdata_len; - - attrs->ia_secdata = *secdata; - attrs->ia_secdata_len = *secdata_len; - - *secdata = old_secdata; - *secdata_len = old_secdata_len; - return 0; -} - -ssize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size) -{ - struct kernfs_node *kn = dentry->d_fsdata; - struct kernfs_iattrs *attrs; - - attrs = kernfs_iattrs(kn); - if (!attrs) - return -ENOMEM; - - return simple_xattr_list(d_inode(dentry), &attrs->xattrs, buf, size); -} - -static inline void set_default_inode_attr(struct inode *inode, umode_t mode) -{ - inode->i_mode = mode; - inode->i_atime = inode->i_mtime = - inode->i_ctime = current_time(inode); -} - -static inline void set_inode_attr(struct inode *inode, struct iattr *iattr) -{ - struct super_block *sb = inode->i_sb; - inode->i_uid = iattr->ia_uid; - inode->i_gid = iattr->ia_gid; - inode->i_atime = timespec_trunc(iattr->ia_atime, sb->s_time_gran); - inode->i_mtime = timespec_trunc(iattr->ia_mtime, sb->s_time_gran); - inode->i_ctime = timespec_trunc(iattr->ia_ctime, sb->s_time_gran); -} - -static void kernfs_refresh_inode(struct kernfs_node *kn, struct inode *inode) -{ - struct kernfs_iattrs *attrs = kn->iattr; - - inode->i_mode = kn->mode; - if (attrs) { - /* - * kernfs_node has non-default attributes get them from - * persistent copy in kernfs_node. - */ - set_inode_attr(inode, &attrs->ia_iattr); - security_inode_notifysecctx(inode, attrs->ia_secdata, - attrs->ia_secdata_len); - } - - if (kernfs_type(kn) == KERNFS_DIR) - set_nlink(inode, kn->dir.subdirs + 2); -} - -int kernfs_iop_getattr(struct vfsmount *mnt, struct dentry *dentry, - struct kstat *stat) -{ - struct kernfs_node *kn = dentry->d_fsdata; - struct inode *inode = d_inode(dentry); - - mutex_lock(&kernfs_mutex); - kernfs_refresh_inode(kn, inode); - mutex_unlock(&kernfs_mutex); - - generic_fillattr(inode, stat); - return 0; -} - -static void kernfs_init_inode(struct kernfs_node *kn, struct inode *inode) -{ - kernfs_get(kn); - inode->i_private = kn; - inode->i_mapping->a_ops = &kernfs_aops; - inode->i_op = &kernfs_iops; - - set_default_inode_attr(inode, kn->mode); - kernfs_refresh_inode(kn, inode); - - /* initialize inode according to type */ - switch (kernfs_type(kn)) { - case KERNFS_DIR: - inode->i_op = &kernfs_dir_iops; - inode->i_fop = &kernfs_dir_fops; - if (kn->flags & KERNFS_EMPTY_DIR) - make_empty_dir_inode(inode); - break; - case KERNFS_FILE: - inode->i_size = kn->attr.size; - inode->i_fop = &kernfs_file_fops; - break; - case KERNFS_LINK: - inode->i_op = &kernfs_symlink_iops; - break; - default: - BUG(); - } - - unlock_new_inode(inode); -} - -/** - * kernfs_get_inode - get inode for kernfs_node - * @sb: super block - * @kn: kernfs_node to allocate inode for - * - * Get inode for @kn. If such inode doesn't exist, a new inode is - * allocated and basics are initialized. New inode is returned - * locked. - * - * LOCKING: - * Kernel thread context (may sleep). - * - * RETURNS: - * Pointer to allocated inode on success, NULL on failure. - */ -struct inode *kernfs_get_inode(struct super_block *sb, struct kernfs_node *kn) -{ - struct inode *inode; - - inode = iget_locked(sb, kn->ino); - if (inode && (inode->i_state & I_NEW)) - kernfs_init_inode(kn, inode); - - return inode; -} - -/* - * The kernfs_node serves as both an inode and a directory entry for - * kernfs. To prevent the kernfs inode numbers from being freed - * prematurely we take a reference to kernfs_node from the kernfs inode. A - * super_operations.evict_inode() implementation is needed to drop that - * reference upon inode destruction. - */ -void kernfs_evict_inode(struct inode *inode) -{ - struct kernfs_node *kn = inode->i_private; - - truncate_inode_pages_final(&inode->i_data); - clear_inode(inode); - kernfs_put(kn); -} - -int kernfs_iop_permission(struct inode *inode, int mask) -{ - struct kernfs_node *kn; - - if (mask & MAY_NOT_BLOCK) - return -ECHILD; - - kn = inode->i_private; - - mutex_lock(&kernfs_mutex); - kernfs_refresh_inode(kn, inode); - mutex_unlock(&kernfs_mutex); - - return generic_permission(inode, mask); -} - -static int kernfs_xattr_get(const struct xattr_handler *handler, - struct dentry *unused, struct inode *inode, - const char *suffix, void *value, size_t size) -{ - const char *name = xattr_full_name(handler, suffix); - struct kernfs_node *kn = inode->i_private; - struct kernfs_iattrs *attrs; - - attrs = kernfs_iattrs(kn); - if (!attrs) - return -ENOMEM; - - return simple_xattr_get(&attrs->xattrs, name, value, size); -} - -static int kernfs_xattr_set(const struct xattr_handler *handler, - struct dentry *unused, struct inode *inode, - const char *suffix, const void *value, - size_t size, int flags) -{ - const char *name = xattr_full_name(handler, suffix); - struct kernfs_node *kn = inode->i_private; - struct kernfs_iattrs *attrs; - - attrs = kernfs_iattrs(kn); - if (!attrs) - return -ENOMEM; - - return simple_xattr_set(&attrs->xattrs, name, value, size, flags); -} - -const struct xattr_handler kernfs_trusted_xattr_handler = { - .prefix = XATTR_TRUSTED_PREFIX, - .get = kernfs_xattr_get, - .set = kernfs_xattr_set, -}; - -static int kernfs_security_xattr_set(const struct xattr_handler *handler, - struct dentry *unused, struct inode *inode, - const char *suffix, const void *value, - size_t size, int flags) -{ - struct kernfs_node *kn = inode->i_private; - struct kernfs_iattrs *attrs; - void *secdata; - u32 secdata_len = 0; - int error; - - attrs = kernfs_iattrs(kn); - if (!attrs) - return -ENOMEM; - - error = security_inode_setsecurity(inode, suffix, value, size, flags); - if (error) - return error; - error = security_inode_getsecctx(inode, &secdata, &secdata_len); - if (error) - return error; - - mutex_lock(&kernfs_mutex); - error = kernfs_node_setsecdata(attrs, &secdata, &secdata_len); - mutex_unlock(&kernfs_mutex); - - if (secdata) - security_release_secctx(secdata, secdata_len); - return error; -} - -const struct xattr_handler kernfs_security_xattr_handler = { - .prefix = XATTR_SECURITY_PREFIX, - .get = kernfs_xattr_get, - .set = kernfs_security_xattr_set, -}; - -const struct xattr_handler *kernfs_xattr_handlers[] = { - &kernfs_trusted_xattr_handler, - &kernfs_security_xattr_handler, - NULL -}; diff --git a/src/linux/fs/kernfs/kernfs-internal.h b/src/linux/fs/kernfs/kernfs-internal.h deleted file mode 100644 index bfd551b..0000000 --- a/src/linux/fs/kernfs/kernfs-internal.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * fs/kernfs/kernfs-internal.h - kernfs internal header file - * - * Copyright (c) 2001-3 Patrick Mochel - * Copyright (c) 2007 SUSE Linux Products GmbH - * Copyright (c) 2007, 2013 Tejun Heo - * - * This file is released under the GPLv2. - */ - -#ifndef __KERNFS_INTERNAL_H -#define __KERNFS_INTERNAL_H - -#include -#include -#include -#include - -#include - -struct kernfs_iattrs { - struct iattr ia_iattr; - void *ia_secdata; - u32 ia_secdata_len; - - struct simple_xattrs xattrs; -}; - -/* +1 to avoid triggering overflow warning when negating it */ -#define KN_DEACTIVATED_BIAS (INT_MIN + 1) - -/* KERNFS_TYPE_MASK and types are defined in include/linux/kernfs.h */ - -/** - * kernfs_root - find out the kernfs_root a kernfs_node belongs to - * @kn: kernfs_node of interest - * - * Return the kernfs_root @kn belongs to. - */ -static inline struct kernfs_root *kernfs_root(struct kernfs_node *kn) -{ - /* if parent exists, it's always a dir; otherwise, @sd is a dir */ - if (kn->parent) - kn = kn->parent; - return kn->dir.root; -} - -/* - * mount.c - */ -struct kernfs_super_info { - struct super_block *sb; - - /* - * The root associated with this super_block. Each super_block is - * identified by the root and ns it's associated with. - */ - struct kernfs_root *root; - - /* - * Each sb is associated with one namespace tag, currently the - * network namespace of the task which mounted this kernfs - * instance. If multiple tags become necessary, make the following - * an array and compare kernfs_node tag against every entry. - */ - const void *ns; - - /* anchored at kernfs_root->supers, protected by kernfs_mutex */ - struct list_head node; -}; -#define kernfs_info(SB) ((struct kernfs_super_info *)(SB->s_fs_info)) - -extern const struct super_operations kernfs_sops; -extern struct kmem_cache *kernfs_node_cache; - -/* - * inode.c - */ -extern const struct xattr_handler *kernfs_xattr_handlers[]; -void kernfs_evict_inode(struct inode *inode); -int kernfs_iop_permission(struct inode *inode, int mask); -int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr); -int kernfs_iop_getattr(struct vfsmount *mnt, struct dentry *dentry, - struct kstat *stat); -ssize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size); - -/* - * dir.c - */ -extern struct mutex kernfs_mutex; -extern const struct dentry_operations kernfs_dops; -extern const struct file_operations kernfs_dir_fops; -extern const struct inode_operations kernfs_dir_iops; - -struct kernfs_node *kernfs_get_active(struct kernfs_node *kn); -void kernfs_put_active(struct kernfs_node *kn); -int kernfs_add_one(struct kernfs_node *kn); -struct kernfs_node *kernfs_new_node(struct kernfs_node *parent, - const char *name, umode_t mode, - unsigned flags); - -/* - * file.c - */ -extern const struct file_operations kernfs_file_fops; - -void kernfs_unmap_bin_file(struct kernfs_node *kn); - -/* - * symlink.c - */ -extern const struct inode_operations kernfs_symlink_iops; - -#endif /* __KERNFS_INTERNAL_H */ diff --git a/src/linux/fs/kernfs/mount.c b/src/linux/fs/kernfs/mount.c deleted file mode 100644 index d5b149a..0000000 --- a/src/linux/fs/kernfs/mount.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * fs/kernfs/mount.c - kernfs mount implementation - * - * Copyright (c) 2001-3 Patrick Mochel - * Copyright (c) 2007 SUSE Linux Products GmbH - * Copyright (c) 2007, 2013 Tejun Heo - * - * This file is released under the GPLv2. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "kernfs-internal.h" - -struct kmem_cache *kernfs_node_cache; - -static int kernfs_sop_remount_fs(struct super_block *sb, int *flags, char *data) -{ - struct kernfs_root *root = kernfs_info(sb)->root; - struct kernfs_syscall_ops *scops = root->syscall_ops; - - if (scops && scops->remount_fs) - return scops->remount_fs(root, flags, data); - return 0; -} - -static int kernfs_sop_show_options(struct seq_file *sf, struct dentry *dentry) -{ - struct kernfs_root *root = kernfs_root(dentry->d_fsdata); - struct kernfs_syscall_ops *scops = root->syscall_ops; - - if (scops && scops->show_options) - return scops->show_options(sf, root); - return 0; -} - -static int kernfs_sop_show_path(struct seq_file *sf, struct dentry *dentry) -{ - struct kernfs_node *node = dentry->d_fsdata; - struct kernfs_root *root = kernfs_root(node); - struct kernfs_syscall_ops *scops = root->syscall_ops; - - if (scops && scops->show_path) - return scops->show_path(sf, node, root); - - seq_dentry(sf, dentry, " \t\n\\"); - return 0; -} - -const struct super_operations kernfs_sops = { - .statfs = simple_statfs, - .drop_inode = generic_delete_inode, - .evict_inode = kernfs_evict_inode, - - .remount_fs = kernfs_sop_remount_fs, - .show_options = kernfs_sop_show_options, - .show_path = kernfs_sop_show_path, -}; - -/** - * kernfs_root_from_sb - determine kernfs_root associated with a super_block - * @sb: the super_block in question - * - * Return the kernfs_root associated with @sb. If @sb is not a kernfs one, - * %NULL is returned. - */ -struct kernfs_root *kernfs_root_from_sb(struct super_block *sb) -{ - if (sb->s_op == &kernfs_sops) - return kernfs_info(sb)->root; - return NULL; -} - -/* - * find the next ancestor in the path down to @child, where @parent was the - * ancestor whose descendant we want to find. - * - * Say the path is /a/b/c/d. @child is d, @parent is NULL. We return the root - * node. If @parent is b, then we return the node for c. - * Passing in d as @parent is not ok. - */ -static struct kernfs_node *find_next_ancestor(struct kernfs_node *child, - struct kernfs_node *parent) -{ - if (child == parent) { - pr_crit_once("BUG in find_next_ancestor: called with parent == child"); - return NULL; - } - - while (child->parent != parent) { - if (!child->parent) - return NULL; - child = child->parent; - } - - return child; -} - -/** - * kernfs_node_dentry - get a dentry for the given kernfs_node - * @kn: kernfs_node for which a dentry is needed - * @sb: the kernfs super_block - */ -struct dentry *kernfs_node_dentry(struct kernfs_node *kn, - struct super_block *sb) -{ - struct dentry *dentry; - struct kernfs_node *knparent = NULL; - - BUG_ON(sb->s_op != &kernfs_sops); - - dentry = dget(sb->s_root); - - /* Check if this is the root kernfs_node */ - if (!kn->parent) - return dentry; - - knparent = find_next_ancestor(kn, NULL); - if (WARN_ON(!knparent)) - return ERR_PTR(-EINVAL); - - do { - struct dentry *dtmp; - struct kernfs_node *kntmp; - - if (kn == knparent) - return dentry; - kntmp = find_next_ancestor(kn, knparent); - if (WARN_ON(!kntmp)) - return ERR_PTR(-EINVAL); - dtmp = lookup_one_len_unlocked(kntmp->name, dentry, - strlen(kntmp->name)); - dput(dentry); - if (IS_ERR(dtmp)) - return dtmp; - knparent = kntmp; - dentry = dtmp; - } while (true); -} - -static int kernfs_fill_super(struct super_block *sb, unsigned long magic) -{ - struct kernfs_super_info *info = kernfs_info(sb); - struct inode *inode; - struct dentry *root; - - info->sb = sb; - /* Userspace would break if executables or devices appear on sysfs */ - sb->s_iflags |= SB_I_NOEXEC | SB_I_NODEV; - sb->s_blocksize = PAGE_SIZE; - sb->s_blocksize_bits = PAGE_SHIFT; - sb->s_magic = magic; - sb->s_op = &kernfs_sops; - sb->s_xattr = kernfs_xattr_handlers; - sb->s_time_gran = 1; - - /* get root inode, initialize and unlock it */ - mutex_lock(&kernfs_mutex); - inode = kernfs_get_inode(sb, info->root->kn); - mutex_unlock(&kernfs_mutex); - if (!inode) { - pr_debug("kernfs: could not get root inode\n"); - return -ENOMEM; - } - - /* instantiate and link root dentry */ - root = d_make_root(inode); - if (!root) { - pr_debug("%s: could not get root dentry!\n", __func__); - return -ENOMEM; - } - kernfs_get(info->root->kn); - root->d_fsdata = info->root->kn; - sb->s_root = root; - sb->s_d_op = &kernfs_dops; - return 0; -} - -static int kernfs_test_super(struct super_block *sb, void *data) -{ - struct kernfs_super_info *sb_info = kernfs_info(sb); - struct kernfs_super_info *info = data; - - return sb_info->root == info->root && sb_info->ns == info->ns; -} - -static int kernfs_set_super(struct super_block *sb, void *data) -{ - int error; - error = set_anon_super(sb, data); - if (!error) - sb->s_fs_info = data; - return error; -} - -/** - * kernfs_super_ns - determine the namespace tag of a kernfs super_block - * @sb: super_block of interest - * - * Return the namespace tag associated with kernfs super_block @sb. - */ -const void *kernfs_super_ns(struct super_block *sb) -{ - struct kernfs_super_info *info = kernfs_info(sb); - - return info->ns; -} - -/** - * kernfs_mount_ns - kernfs mount helper - * @fs_type: file_system_type of the fs being mounted - * @flags: mount flags specified for the mount - * @root: kernfs_root of the hierarchy being mounted - * @magic: file system specific magic number - * @new_sb_created: tell the caller if we allocated a new superblock - * @ns: optional namespace tag of the mount - * - * This is to be called from each kernfs user's file_system_type->mount() - * implementation, which should pass through the specified @fs_type and - * @flags, and specify the hierarchy and namespace tag to mount via @root - * and @ns, respectively. - * - * The return value can be passed to the vfs layer verbatim. - */ -struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, - struct kernfs_root *root, unsigned long magic, - bool *new_sb_created, const void *ns) -{ - struct super_block *sb; - struct kernfs_super_info *info; - int error; - - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (!info) - return ERR_PTR(-ENOMEM); - - info->root = root; - info->ns = ns; - - sb = sget_userns(fs_type, kernfs_test_super, kernfs_set_super, flags, - &init_user_ns, info); - if (IS_ERR(sb) || sb->s_fs_info != info) - kfree(info); - if (IS_ERR(sb)) - return ERR_CAST(sb); - - if (new_sb_created) - *new_sb_created = !sb->s_root; - - if (!sb->s_root) { - struct kernfs_super_info *info = kernfs_info(sb); - - error = kernfs_fill_super(sb, magic); - if (error) { - deactivate_locked_super(sb); - return ERR_PTR(error); - } - sb->s_flags |= MS_ACTIVE; - - mutex_lock(&kernfs_mutex); - list_add(&info->node, &root->supers); - mutex_unlock(&kernfs_mutex); - } - - return dget(sb->s_root); -} - -/** - * kernfs_kill_sb - kill_sb for kernfs - * @sb: super_block being killed - * - * This can be used directly for file_system_type->kill_sb(). If a kernfs - * user needs extra cleanup, it can implement its own kill_sb() and call - * this function at the end. - */ -void kernfs_kill_sb(struct super_block *sb) -{ - struct kernfs_super_info *info = kernfs_info(sb); - struct kernfs_node *root_kn = sb->s_root->d_fsdata; - - mutex_lock(&kernfs_mutex); - list_del(&info->node); - mutex_unlock(&kernfs_mutex); - - /* - * Remove the superblock from fs_supers/s_instances - * so we can't find it, before freeing kernfs_super_info. - */ - kill_anon_super(sb); - kfree(info); - kernfs_put(root_kn); -} - -/** - * kernfs_pin_sb: try to pin the superblock associated with a kernfs_root - * @kernfs_root: the kernfs_root in question - * @ns: the namespace tag - * - * Pin the superblock so the superblock won't be destroyed in subsequent - * operations. This can be used to block ->kill_sb() which may be useful - * for kernfs users which dynamically manage superblocks. - * - * Returns NULL if there's no superblock associated to this kernfs_root, or - * -EINVAL if the superblock is being freed. - */ -struct super_block *kernfs_pin_sb(struct kernfs_root *root, const void *ns) -{ - struct kernfs_super_info *info; - struct super_block *sb = NULL; - - mutex_lock(&kernfs_mutex); - list_for_each_entry(info, &root->supers, node) { - if (info->ns == ns) { - sb = info->sb; - if (!atomic_inc_not_zero(&info->sb->s_active)) - sb = ERR_PTR(-EINVAL); - break; - } - } - mutex_unlock(&kernfs_mutex); - return sb; -} - -void __init kernfs_init(void) -{ - kernfs_node_cache = kmem_cache_create("kernfs_node_cache", - sizeof(struct kernfs_node), - 0, SLAB_PANIC, NULL); -} diff --git a/src/linux/fs/kernfs/symlink.c b/src/linux/fs/kernfs/symlink.c deleted file mode 100644 index 9b43ca0..0000000 --- a/src/linux/fs/kernfs/symlink.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * fs/kernfs/symlink.c - kernfs symlink implementation - * - * Copyright (c) 2001-3 Patrick Mochel - * Copyright (c) 2007 SUSE Linux Products GmbH - * Copyright (c) 2007, 2013 Tejun Heo - * - * This file is released under the GPLv2. - */ - -#include -#include -#include - -#include "kernfs-internal.h" - -/** - * kernfs_create_link - create a symlink - * @parent: directory to create the symlink in - * @name: name of the symlink - * @target: target node for the symlink to point to - * - * Returns the created node on success, ERR_PTR() value on error. - */ -struct kernfs_node *kernfs_create_link(struct kernfs_node *parent, - const char *name, - struct kernfs_node *target) -{ - struct kernfs_node *kn; - int error; - - kn = kernfs_new_node(parent, name, S_IFLNK|S_IRWXUGO, KERNFS_LINK); - if (!kn) - return ERR_PTR(-ENOMEM); - - if (kernfs_ns_enabled(parent)) - kn->ns = target->ns; - kn->symlink.target_kn = target; - kernfs_get(target); /* ref owned by symlink */ - - error = kernfs_add_one(kn); - if (!error) - return kn; - - kernfs_put(kn); - return ERR_PTR(error); -} - -static int kernfs_get_target_path(struct kernfs_node *parent, - struct kernfs_node *target, char *path) -{ - struct kernfs_node *base, *kn; - char *s = path; - int len = 0; - - /* go up to the root, stop at the base */ - base = parent; - while (base->parent) { - kn = target->parent; - while (kn->parent && base != kn) - kn = kn->parent; - - if (base == kn) - break; - - strcpy(s, "../"); - s += 3; - base = base->parent; - } - - /* determine end of target string for reverse fillup */ - kn = target; - while (kn->parent && kn != base) { - len += strlen(kn->name) + 1; - kn = kn->parent; - } - - /* check limits */ - if (len < 2) - return -EINVAL; - len--; - if ((s - path) + len > PATH_MAX) - return -ENAMETOOLONG; - - /* reverse fillup of target string from target to base */ - kn = target; - while (kn->parent && kn != base) { - int slen = strlen(kn->name); - - len -= slen; - strncpy(s + len, kn->name, slen); - if (len) - s[--len] = '/'; - - kn = kn->parent; - } - - return 0; -} - -static int kernfs_getlink(struct dentry *dentry, char *path) -{ - struct kernfs_node *kn = dentry->d_fsdata; - struct kernfs_node *parent = kn->parent; - struct kernfs_node *target = kn->symlink.target_kn; - int error; - - mutex_lock(&kernfs_mutex); - error = kernfs_get_target_path(parent, target, path); - mutex_unlock(&kernfs_mutex); - - return error; -} - -static const char *kernfs_iop_get_link(struct dentry *dentry, - struct inode *inode, - struct delayed_call *done) -{ - char *body; - int error; - - if (!dentry) - return ERR_PTR(-ECHILD); - body = kzalloc(PAGE_SIZE, GFP_KERNEL); - if (!body) - return ERR_PTR(-ENOMEM); - error = kernfs_getlink(dentry, body); - if (unlikely(error < 0)) { - kfree(body); - return ERR_PTR(error); - } - set_delayed_call(done, kfree_link, body); - return body; -} - -const struct inode_operations kernfs_symlink_iops = { - .listxattr = kernfs_iop_listxattr, - .readlink = generic_readlink, - .get_link = kernfs_iop_get_link, - .setattr = kernfs_iop_setattr, - .getattr = kernfs_iop_getattr, - .permission = kernfs_iop_permission, -}; diff --git a/src/linux/fs/libfs.c b/src/linux/fs/libfs.c deleted file mode 100644 index 48826d4..0000000 --- a/src/linux/fs/libfs.c +++ /dev/null @@ -1,1210 +0,0 @@ -/* - * fs/libfs.c - * Library for filesystems writers. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* sync_mapping_buffers */ - -#include - -#include "internal.h" - -int simple_getattr(struct vfsmount *mnt, struct dentry *dentry, - struct kstat *stat) -{ - struct inode *inode = d_inode(dentry); - generic_fillattr(inode, stat); - stat->blocks = inode->i_mapping->nrpages << (PAGE_SHIFT - 9); - return 0; -} -EXPORT_SYMBOL(simple_getattr); - -int simple_statfs(struct dentry *dentry, struct kstatfs *buf) -{ - buf->f_type = dentry->d_sb->s_magic; - buf->f_bsize = PAGE_SIZE; - buf->f_namelen = NAME_MAX; - return 0; -} -EXPORT_SYMBOL(simple_statfs); - -/* - * Retaining negative dentries for an in-memory filesystem just wastes - * memory and lookup time: arrange for them to be deleted immediately. - */ -int always_delete_dentry(const struct dentry *dentry) -{ - return 1; -} -EXPORT_SYMBOL(always_delete_dentry); - -const struct dentry_operations simple_dentry_operations = { - .d_delete = always_delete_dentry, -}; -EXPORT_SYMBOL(simple_dentry_operations); - -/* - * Lookup the data. This is trivial - if the dentry didn't already - * exist, we know it is negative. Set d_op to delete negative dentries. - */ -struct dentry *simple_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) -{ - if (dentry->d_name.len > NAME_MAX) - return ERR_PTR(-ENAMETOOLONG); - if (!dentry->d_sb->s_d_op) - d_set_d_op(dentry, &simple_dentry_operations); - d_add(dentry, NULL); - return NULL; -} -EXPORT_SYMBOL(simple_lookup); - -int dcache_dir_open(struct inode *inode, struct file *file) -{ - file->private_data = d_alloc_cursor(file->f_path.dentry); - - return file->private_data ? 0 : -ENOMEM; -} -EXPORT_SYMBOL(dcache_dir_open); - -int dcache_dir_close(struct inode *inode, struct file *file) -{ - dput(file->private_data); - return 0; -} -EXPORT_SYMBOL(dcache_dir_close); - -/* parent is locked at least shared */ -static struct dentry *next_positive(struct dentry *parent, - struct list_head *from, - int count) -{ - unsigned *seq = &parent->d_inode->i_dir_seq, n; - struct dentry *res; - struct list_head *p; - bool skipped; - int i; - -retry: - i = count; - skipped = false; - n = smp_load_acquire(seq) & ~1; - res = NULL; - rcu_read_lock(); - for (p = from->next; p != &parent->d_subdirs; p = p->next) { - struct dentry *d = list_entry(p, struct dentry, d_child); - if (!simple_positive(d)) { - skipped = true; - } else if (!--i) { - res = d; - break; - } - } - rcu_read_unlock(); - if (skipped) { - smp_rmb(); - if (unlikely(*seq != n)) - goto retry; - } - return res; -} - -static void move_cursor(struct dentry *cursor, struct list_head *after) -{ - struct dentry *parent = cursor->d_parent; - unsigned n, *seq = &parent->d_inode->i_dir_seq; - spin_lock(&parent->d_lock); - for (;;) { - n = *seq; - if (!(n & 1) && cmpxchg(seq, n, n + 1) == n) - break; - cpu_relax(); - } - __list_del(cursor->d_child.prev, cursor->d_child.next); - if (after) - list_add(&cursor->d_child, after); - else - list_add_tail(&cursor->d_child, &parent->d_subdirs); - smp_store_release(seq, n + 2); - spin_unlock(&parent->d_lock); -} - -loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence) -{ - struct dentry *dentry = file->f_path.dentry; - switch (whence) { - case 1: - offset += file->f_pos; - case 0: - if (offset >= 0) - break; - default: - return -EINVAL; - } - if (offset != file->f_pos) { - file->f_pos = offset; - if (file->f_pos >= 2) { - struct dentry *cursor = file->private_data; - struct dentry *to; - loff_t n = file->f_pos - 2; - - inode_lock_shared(dentry->d_inode); - to = next_positive(dentry, &dentry->d_subdirs, n); - move_cursor(cursor, to ? &to->d_child : NULL); - inode_unlock_shared(dentry->d_inode); - } - } - return offset; -} -EXPORT_SYMBOL(dcache_dir_lseek); - -/* Relationship between i_mode and the DT_xxx types */ -static inline unsigned char dt_type(struct inode *inode) -{ - return (inode->i_mode >> 12) & 15; -} - -/* - * Directory is locked and all positive dentries in it are safe, since - * for ramfs-type trees they can't go away without unlink() or rmdir(), - * both impossible due to the lock on directory. - */ - -int dcache_readdir(struct file *file, struct dir_context *ctx) -{ - struct dentry *dentry = file->f_path.dentry; - struct dentry *cursor = file->private_data; - struct list_head *p = &cursor->d_child; - struct dentry *next; - bool moved = false; - - if (!dir_emit_dots(file, ctx)) - return 0; - - if (ctx->pos == 2) - p = &dentry->d_subdirs; - while ((next = next_positive(dentry, p, 1)) != NULL) { - if (!dir_emit(ctx, next->d_name.name, next->d_name.len, - d_inode(next)->i_ino, dt_type(d_inode(next)))) - break; - moved = true; - p = &next->d_child; - ctx->pos++; - } - if (moved) - move_cursor(cursor, p); - return 0; -} -EXPORT_SYMBOL(dcache_readdir); - -ssize_t generic_read_dir(struct file *filp, char __user *buf, size_t siz, loff_t *ppos) -{ - return -EISDIR; -} -EXPORT_SYMBOL(generic_read_dir); - -const struct file_operations simple_dir_operations = { - .open = dcache_dir_open, - .release = dcache_dir_close, - .llseek = dcache_dir_lseek, - .read = generic_read_dir, - .iterate_shared = dcache_readdir, - .fsync = noop_fsync, -}; -EXPORT_SYMBOL(simple_dir_operations); - -const struct inode_operations simple_dir_inode_operations = { - .lookup = simple_lookup, -}; -EXPORT_SYMBOL(simple_dir_inode_operations); - -static const struct super_operations simple_super_operations = { - .statfs = simple_statfs, -}; - -/* - * Common helper for pseudo-filesystems (sockfs, pipefs, bdev - stuff that - * will never be mountable) - */ -struct dentry *mount_pseudo_xattr(struct file_system_type *fs_type, char *name, - const struct super_operations *ops, const struct xattr_handler **xattr, - const struct dentry_operations *dops, unsigned long magic) -{ - struct super_block *s; - struct dentry *dentry; - struct inode *root; - struct qstr d_name = QSTR_INIT(name, strlen(name)); - - s = sget(fs_type, NULL, set_anon_super, MS_NOUSER, NULL); - if (IS_ERR(s)) - return ERR_CAST(s); - - s->s_maxbytes = MAX_LFS_FILESIZE; - s->s_blocksize = PAGE_SIZE; - s->s_blocksize_bits = PAGE_SHIFT; - s->s_magic = magic; - s->s_op = ops ? ops : &simple_super_operations; - s->s_xattr = xattr; - s->s_time_gran = 1; - root = new_inode(s); - if (!root) - goto Enomem; - /* - * since this is the first inode, make it number 1. New inodes created - * after this must take care not to collide with it (by passing - * max_reserved of 1 to iunique). - */ - root->i_ino = 1; - root->i_mode = S_IFDIR | S_IRUSR | S_IWUSR; - root->i_atime = root->i_mtime = root->i_ctime = current_time(root); - dentry = __d_alloc(s, &d_name); - if (!dentry) { - iput(root); - goto Enomem; - } - d_instantiate(dentry, root); - s->s_root = dentry; - s->s_d_op = dops; - s->s_flags |= MS_ACTIVE; - return dget(s->s_root); - -Enomem: - deactivate_locked_super(s); - return ERR_PTR(-ENOMEM); -} -EXPORT_SYMBOL(mount_pseudo_xattr); - -int simple_open(struct inode *inode, struct file *file) -{ - if (inode->i_private) - file->private_data = inode->i_private; - return 0; -} -EXPORT_SYMBOL(simple_open); - -int simple_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) -{ - struct inode *inode = d_inode(old_dentry); - - inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode); - inc_nlink(inode); - ihold(inode); - dget(dentry); - d_instantiate(dentry, inode); - return 0; -} -EXPORT_SYMBOL(simple_link); - -int simple_empty(struct dentry *dentry) -{ - struct dentry *child; - int ret = 0; - - spin_lock(&dentry->d_lock); - list_for_each_entry(child, &dentry->d_subdirs, d_child) { - spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); - if (simple_positive(child)) { - spin_unlock(&child->d_lock); - goto out; - } - spin_unlock(&child->d_lock); - } - ret = 1; -out: - spin_unlock(&dentry->d_lock); - return ret; -} -EXPORT_SYMBOL(simple_empty); - -int simple_unlink(struct inode *dir, struct dentry *dentry) -{ - struct inode *inode = d_inode(dentry); - - inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode); - drop_nlink(inode); - dput(dentry); - return 0; -} -EXPORT_SYMBOL(simple_unlink); - -int simple_rmdir(struct inode *dir, struct dentry *dentry) -{ - if (!simple_empty(dentry)) - return -ENOTEMPTY; - - drop_nlink(d_inode(dentry)); - simple_unlink(dir, dentry); - drop_nlink(dir); - return 0; -} -EXPORT_SYMBOL(simple_rmdir); - -int simple_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry, - unsigned int flags) -{ - struct inode *inode = d_inode(old_dentry); - int they_are_dirs = d_is_dir(old_dentry); - - if (flags & ~RENAME_NOREPLACE) - return -EINVAL; - - if (!simple_empty(new_dentry)) - return -ENOTEMPTY; - - if (d_really_is_positive(new_dentry)) { - simple_unlink(new_dir, new_dentry); - if (they_are_dirs) { - drop_nlink(d_inode(new_dentry)); - drop_nlink(old_dir); - } - } else if (they_are_dirs) { - drop_nlink(old_dir); - inc_nlink(new_dir); - } - - old_dir->i_ctime = old_dir->i_mtime = new_dir->i_ctime = - new_dir->i_mtime = inode->i_ctime = current_time(old_dir); - - return 0; -} -EXPORT_SYMBOL(simple_rename); - -/** - * simple_setattr - setattr for simple filesystem - * @dentry: dentry - * @iattr: iattr structure - * - * Returns 0 on success, -error on failure. - * - * simple_setattr is a simple ->setattr implementation without a proper - * implementation of size changes. - * - * It can either be used for in-memory filesystems or special files - * on simple regular filesystems. Anything that needs to change on-disk - * or wire state on size changes needs its own setattr method. - */ -int simple_setattr(struct dentry *dentry, struct iattr *iattr) -{ - struct inode *inode = d_inode(dentry); - int error; - - error = setattr_prepare(dentry, iattr); - if (error) - return error; - - if (iattr->ia_valid & ATTR_SIZE) - truncate_setsize(inode, iattr->ia_size); - setattr_copy(inode, iattr); - mark_inode_dirty(inode); - return 0; -} -EXPORT_SYMBOL(simple_setattr); - -int simple_readpage(struct file *file, struct page *page) -{ - clear_highpage(page); - flush_dcache_page(page); - SetPageUptodate(page); - unlock_page(page); - return 0; -} -EXPORT_SYMBOL(simple_readpage); - -int simple_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) -{ - struct page *page; - pgoff_t index; - - index = pos >> PAGE_SHIFT; - - page = grab_cache_page_write_begin(mapping, index, flags); - if (!page) - return -ENOMEM; - - *pagep = page; - - if (!PageUptodate(page) && (len != PAGE_SIZE)) { - unsigned from = pos & (PAGE_SIZE - 1); - - zero_user_segments(page, 0, from, from + len, PAGE_SIZE); - } - return 0; -} -EXPORT_SYMBOL(simple_write_begin); - -/** - * simple_write_end - .write_end helper for non-block-device FSes - * @available: See .write_end of address_space_operations - * @file: " - * @mapping: " - * @pos: " - * @len: " - * @copied: " - * @page: " - * @fsdata: " - * - * simple_write_end does the minimum needed for updating a page after writing is - * done. It has the same API signature as the .write_end of - * address_space_operations vector. So it can just be set onto .write_end for - * FSes that don't need any other processing. i_mutex is assumed to be held. - * Block based filesystems should use generic_write_end(). - * NOTE: Even though i_size might get updated by this function, mark_inode_dirty - * is not called, so a filesystem that actually does store data in .write_inode - * should extend on what's done here with a call to mark_inode_dirty() in the - * case that i_size has changed. - */ -int simple_write_end(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) -{ - struct inode *inode = page->mapping->host; - loff_t last_pos = pos + copied; - - /* zero the stale part of the page if we did a short copy */ - if (copied < len) { - unsigned from = pos & (PAGE_SIZE - 1); - - zero_user(page, from + copied, len - copied); - } - - if (!PageUptodate(page)) - SetPageUptodate(page); - /* - * No need to use i_size_read() here, the i_size - * cannot change under us because we hold the i_mutex. - */ - if (last_pos > inode->i_size) - i_size_write(inode, last_pos); - - set_page_dirty(page); - unlock_page(page); - put_page(page); - - return copied; -} -EXPORT_SYMBOL(simple_write_end); - -/* - * the inodes created here are not hashed. If you use iunique to generate - * unique inode values later for this filesystem, then you must take care - * to pass it an appropriate max_reserved value to avoid collisions. - */ -int simple_fill_super(struct super_block *s, unsigned long magic, - struct tree_descr *files) -{ - struct inode *inode; - struct dentry *root; - struct dentry *dentry; - int i; - - s->s_blocksize = PAGE_SIZE; - s->s_blocksize_bits = PAGE_SHIFT; - s->s_magic = magic; - s->s_op = &simple_super_operations; - s->s_time_gran = 1; - - inode = new_inode(s); - if (!inode) - return -ENOMEM; - /* - * because the root inode is 1, the files array must not contain an - * entry at index 1 - */ - inode->i_ino = 1; - inode->i_mode = S_IFDIR | 0755; - inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); - inode->i_op = &simple_dir_inode_operations; - inode->i_fop = &simple_dir_operations; - set_nlink(inode, 2); - root = d_make_root(inode); - if (!root) - return -ENOMEM; - for (i = 0; !files->name || files->name[0]; i++, files++) { - if (!files->name) - continue; - - /* warn if it tries to conflict with the root inode */ - if (unlikely(i == 1)) - printk(KERN_WARNING "%s: %s passed in a files array" - "with an index of 1!\n", __func__, - s->s_type->name); - - dentry = d_alloc_name(root, files->name); - if (!dentry) - goto out; - inode = new_inode(s); - if (!inode) { - dput(dentry); - goto out; - } - inode->i_mode = S_IFREG | files->mode; - inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); - inode->i_fop = files->ops; - inode->i_ino = i; - d_add(dentry, inode); - } - s->s_root = root; - return 0; -out: - d_genocide(root); - shrink_dcache_parent(root); - dput(root); - return -ENOMEM; -} -EXPORT_SYMBOL(simple_fill_super); - -static DEFINE_SPINLOCK(pin_fs_lock); - -int simple_pin_fs(struct file_system_type *type, struct vfsmount **mount, int *count) -{ - struct vfsmount *mnt = NULL; - spin_lock(&pin_fs_lock); - if (unlikely(!*mount)) { - spin_unlock(&pin_fs_lock); - mnt = vfs_kern_mount(type, MS_KERNMOUNT, type->name, NULL); - if (IS_ERR(mnt)) - return PTR_ERR(mnt); - spin_lock(&pin_fs_lock); - if (!*mount) - *mount = mnt; - } - mntget(*mount); - ++*count; - spin_unlock(&pin_fs_lock); - mntput(mnt); - return 0; -} -EXPORT_SYMBOL(simple_pin_fs); - -void simple_release_fs(struct vfsmount **mount, int *count) -{ - struct vfsmount *mnt; - spin_lock(&pin_fs_lock); - mnt = *mount; - if (!--*count) - *mount = NULL; - spin_unlock(&pin_fs_lock); - mntput(mnt); -} -EXPORT_SYMBOL(simple_release_fs); - -/** - * simple_read_from_buffer - copy data from the buffer to user space - * @to: the user space buffer to read to - * @count: the maximum number of bytes to read - * @ppos: the current position in the buffer - * @from: the buffer to read from - * @available: the size of the buffer - * - * The simple_read_from_buffer() function reads up to @count bytes from the - * buffer @from at offset @ppos into the user space address starting at @to. - * - * On success, the number of bytes read is returned and the offset @ppos is - * advanced by this number, or negative value is returned on error. - **/ -ssize_t simple_read_from_buffer(void __user *to, size_t count, loff_t *ppos, - const void *from, size_t available) -{ - loff_t pos = *ppos; - size_t ret; - - if (pos < 0) - return -EINVAL; - if (pos >= available || !count) - return 0; - if (count > available - pos) - count = available - pos; - ret = copy_to_user(to, from + pos, count); - if (ret == count) - return -EFAULT; - count -= ret; - *ppos = pos + count; - return count; -} -EXPORT_SYMBOL(simple_read_from_buffer); - -/** - * simple_write_to_buffer - copy data from user space to the buffer - * @to: the buffer to write to - * @available: the size of the buffer - * @ppos: the current position in the buffer - * @from: the user space buffer to read from - * @count: the maximum number of bytes to read - * - * The simple_write_to_buffer() function reads up to @count bytes from the user - * space address starting at @from into the buffer @to at offset @ppos. - * - * On success, the number of bytes written is returned and the offset @ppos is - * advanced by this number, or negative value is returned on error. - **/ -ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos, - const void __user *from, size_t count) -{ - loff_t pos = *ppos; - size_t res; - - if (pos < 0) - return -EINVAL; - if (pos >= available || !count) - return 0; - if (count > available - pos) - count = available - pos; - res = copy_from_user(to + pos, from, count); - if (res == count) - return -EFAULT; - count -= res; - *ppos = pos + count; - return count; -} -EXPORT_SYMBOL(simple_write_to_buffer); - -/** - * memory_read_from_buffer - copy data from the buffer - * @to: the kernel space buffer to read to - * @count: the maximum number of bytes to read - * @ppos: the current position in the buffer - * @from: the buffer to read from - * @available: the size of the buffer - * - * The memory_read_from_buffer() function reads up to @count bytes from the - * buffer @from at offset @ppos into the kernel space address starting at @to. - * - * On success, the number of bytes read is returned and the offset @ppos is - * advanced by this number, or negative value is returned on error. - **/ -ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos, - const void *from, size_t available) -{ - loff_t pos = *ppos; - - if (pos < 0) - return -EINVAL; - if (pos >= available) - return 0; - if (count > available - pos) - count = available - pos; - memcpy(to, from + pos, count); - *ppos = pos + count; - - return count; -} -EXPORT_SYMBOL(memory_read_from_buffer); - -/* - * Transaction based IO. - * The file expects a single write which triggers the transaction, and then - * possibly a read which collects the result - which is stored in a - * file-local buffer. - */ - -void simple_transaction_set(struct file *file, size_t n) -{ - struct simple_transaction_argresp *ar = file->private_data; - - BUG_ON(n > SIMPLE_TRANSACTION_LIMIT); - - /* - * The barrier ensures that ar->size will really remain zero until - * ar->data is ready for reading. - */ - smp_mb(); - ar->size = n; -} -EXPORT_SYMBOL(simple_transaction_set); - -char *simple_transaction_get(struct file *file, const char __user *buf, size_t size) -{ - struct simple_transaction_argresp *ar; - static DEFINE_SPINLOCK(simple_transaction_lock); - - if (size > SIMPLE_TRANSACTION_LIMIT - 1) - return ERR_PTR(-EFBIG); - - ar = (struct simple_transaction_argresp *)get_zeroed_page(GFP_KERNEL); - if (!ar) - return ERR_PTR(-ENOMEM); - - spin_lock(&simple_transaction_lock); - - /* only one write allowed per open */ - if (file->private_data) { - spin_unlock(&simple_transaction_lock); - free_page((unsigned long)ar); - return ERR_PTR(-EBUSY); - } - - file->private_data = ar; - - spin_unlock(&simple_transaction_lock); - - if (copy_from_user(ar->data, buf, size)) - return ERR_PTR(-EFAULT); - - return ar->data; -} -EXPORT_SYMBOL(simple_transaction_get); - -ssize_t simple_transaction_read(struct file *file, char __user *buf, size_t size, loff_t *pos) -{ - struct simple_transaction_argresp *ar = file->private_data; - - if (!ar) - return 0; - return simple_read_from_buffer(buf, size, pos, ar->data, ar->size); -} -EXPORT_SYMBOL(simple_transaction_read); - -int simple_transaction_release(struct inode *inode, struct file *file) -{ - free_page((unsigned long)file->private_data); - return 0; -} -EXPORT_SYMBOL(simple_transaction_release); - -/* Simple attribute files */ - -struct simple_attr { - int (*get)(void *, u64 *); - int (*set)(void *, u64); - char get_buf[24]; /* enough to store a u64 and "\n\0" */ - char set_buf[24]; - void *data; - const char *fmt; /* format for read operation */ - struct mutex mutex; /* protects access to these buffers */ -}; - -/* simple_attr_open is called by an actual attribute open file operation - * to set the attribute specific access operations. */ -int simple_attr_open(struct inode *inode, struct file *file, - int (*get)(void *, u64 *), int (*set)(void *, u64), - const char *fmt) -{ - struct simple_attr *attr; - - attr = kmalloc(sizeof(*attr), GFP_KERNEL); - if (!attr) - return -ENOMEM; - - attr->get = get; - attr->set = set; - attr->data = inode->i_private; - attr->fmt = fmt; - mutex_init(&attr->mutex); - - file->private_data = attr; - - return nonseekable_open(inode, file); -} -EXPORT_SYMBOL_GPL(simple_attr_open); - -int simple_attr_release(struct inode *inode, struct file *file) -{ - kfree(file->private_data); - return 0; -} -EXPORT_SYMBOL_GPL(simple_attr_release); /* GPL-only? This? Really? */ - -/* read from the buffer that is filled with the get function */ -ssize_t simple_attr_read(struct file *file, char __user *buf, - size_t len, loff_t *ppos) -{ - struct simple_attr *attr; - size_t size; - ssize_t ret; - - attr = file->private_data; - - if (!attr->get) - return -EACCES; - - ret = mutex_lock_interruptible(&attr->mutex); - if (ret) - return ret; - - if (*ppos) { /* continued read */ - size = strlen(attr->get_buf); - } else { /* first read */ - u64 val; - ret = attr->get(attr->data, &val); - if (ret) - goto out; - - size = scnprintf(attr->get_buf, sizeof(attr->get_buf), - attr->fmt, (unsigned long long)val); - } - - ret = simple_read_from_buffer(buf, len, ppos, attr->get_buf, size); -out: - mutex_unlock(&attr->mutex); - return ret; -} -EXPORT_SYMBOL_GPL(simple_attr_read); - -/* interpret the buffer as a number to call the set function with */ -ssize_t simple_attr_write(struct file *file, const char __user *buf, - size_t len, loff_t *ppos) -{ - struct simple_attr *attr; - u64 val; - size_t size; - ssize_t ret; - - attr = file->private_data; - if (!attr->set) - return -EACCES; - - ret = mutex_lock_interruptible(&attr->mutex); - if (ret) - return ret; - - ret = -EFAULT; - size = min(sizeof(attr->set_buf) - 1, len); - if (copy_from_user(attr->set_buf, buf, size)) - goto out; - - attr->set_buf[size] = '\0'; - val = simple_strtoll(attr->set_buf, NULL, 0); - ret = attr->set(attr->data, val); - if (ret == 0) - ret = len; /* on success, claim we got the whole input */ -out: - mutex_unlock(&attr->mutex); - return ret; -} -EXPORT_SYMBOL_GPL(simple_attr_write); - -/** - * generic_fh_to_dentry - generic helper for the fh_to_dentry export operation - * @sb: filesystem to do the file handle conversion on - * @fid: file handle to convert - * @fh_len: length of the file handle in bytes - * @fh_type: type of file handle - * @get_inode: filesystem callback to retrieve inode - * - * This function decodes @fid as long as it has one of the well-known - * Linux filehandle types and calls @get_inode on it to retrieve the - * inode for the object specified in the file handle. - */ -struct dentry *generic_fh_to_dentry(struct super_block *sb, struct fid *fid, - int fh_len, int fh_type, struct inode *(*get_inode) - (struct super_block *sb, u64 ino, u32 gen)) -{ - struct inode *inode = NULL; - - if (fh_len < 2) - return NULL; - - switch (fh_type) { - case FILEID_INO32_GEN: - case FILEID_INO32_GEN_PARENT: - inode = get_inode(sb, fid->i32.ino, fid->i32.gen); - break; - } - - return d_obtain_alias(inode); -} -EXPORT_SYMBOL_GPL(generic_fh_to_dentry); - -/** - * generic_fh_to_parent - generic helper for the fh_to_parent export operation - * @sb: filesystem to do the file handle conversion on - * @fid: file handle to convert - * @fh_len: length of the file handle in bytes - * @fh_type: type of file handle - * @get_inode: filesystem callback to retrieve inode - * - * This function decodes @fid as long as it has one of the well-known - * Linux filehandle types and calls @get_inode on it to retrieve the - * inode for the _parent_ object specified in the file handle if it - * is specified in the file handle, or NULL otherwise. - */ -struct dentry *generic_fh_to_parent(struct super_block *sb, struct fid *fid, - int fh_len, int fh_type, struct inode *(*get_inode) - (struct super_block *sb, u64 ino, u32 gen)) -{ - struct inode *inode = NULL; - - if (fh_len <= 2) - return NULL; - - switch (fh_type) { - case FILEID_INO32_GEN_PARENT: - inode = get_inode(sb, fid->i32.parent_ino, - (fh_len > 3 ? fid->i32.parent_gen : 0)); - break; - } - - return d_obtain_alias(inode); -} -EXPORT_SYMBOL_GPL(generic_fh_to_parent); - -/** - * __generic_file_fsync - generic fsync implementation for simple filesystems - * - * @file: file to synchronize - * @start: start offset in bytes - * @end: end offset in bytes (inclusive) - * @datasync: only synchronize essential metadata if true - * - * This is a generic implementation of the fsync method for simple - * filesystems which track all non-inode metadata in the buffers list - * hanging off the address_space structure. - */ -int __generic_file_fsync(struct file *file, loff_t start, loff_t end, - int datasync) -{ - struct inode *inode = file->f_mapping->host; - int err; - int ret; - - err = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (err) - return err; - - inode_lock(inode); - ret = sync_mapping_buffers(inode->i_mapping); - if (!(inode->i_state & I_DIRTY_ALL)) - goto out; - if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) - goto out; - - err = sync_inode_metadata(inode, 1); - if (ret == 0) - ret = err; - -out: - inode_unlock(inode); - return ret; -} -EXPORT_SYMBOL(__generic_file_fsync); - -/** - * generic_file_fsync - generic fsync implementation for simple filesystems - * with flush - * @file: file to synchronize - * @start: start offset in bytes - * @end: end offset in bytes (inclusive) - * @datasync: only synchronize essential metadata if true - * - */ - -int generic_file_fsync(struct file *file, loff_t start, loff_t end, - int datasync) -{ - struct inode *inode = file->f_mapping->host; - int err; - - err = __generic_file_fsync(file, start, end, datasync); - if (err) - return err; - return blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); -} -EXPORT_SYMBOL(generic_file_fsync); - -/** - * generic_check_addressable - Check addressability of file system - * @blocksize_bits: log of file system block size - * @num_blocks: number of blocks in file system - * - * Determine whether a file system with @num_blocks blocks (and a - * block size of 2**@blocksize_bits) is addressable by the sector_t - * and page cache of the system. Return 0 if so and -EFBIG otherwise. - */ -int generic_check_addressable(unsigned blocksize_bits, u64 num_blocks) -{ - u64 last_fs_block = num_blocks - 1; - u64 last_fs_page = - last_fs_block >> (PAGE_SHIFT - blocksize_bits); - - if (unlikely(num_blocks == 0)) - return 0; - - if ((blocksize_bits < 9) || (blocksize_bits > PAGE_SHIFT)) - return -EINVAL; - - if ((last_fs_block > (sector_t)(~0ULL) >> (blocksize_bits - 9)) || - (last_fs_page > (pgoff_t)(~0ULL))) { - return -EFBIG; - } - return 0; -} -EXPORT_SYMBOL(generic_check_addressable); - -/* - * No-op implementation of ->fsync for in-memory filesystems. - */ -int noop_fsync(struct file *file, loff_t start, loff_t end, int datasync) -{ - return 0; -} -EXPORT_SYMBOL(noop_fsync); - -/* Because kfree isn't assignment-compatible with void(void*) ;-/ */ -void kfree_link(void *p) -{ - kfree(p); -} -EXPORT_SYMBOL(kfree_link); - -/* - * nop .set_page_dirty method so that people can use .page_mkwrite on - * anon inodes. - */ -static int anon_set_page_dirty(struct page *page) -{ - return 0; -}; - -/* - * A single inode exists for all anon_inode files. Contrary to pipes, - * anon_inode inodes have no associated per-instance data, so we need - * only allocate one of them. - */ -struct inode *alloc_anon_inode(struct super_block *s) -{ - static const struct address_space_operations anon_aops = { - .set_page_dirty = anon_set_page_dirty, - }; - struct inode *inode = new_inode_pseudo(s); - - if (!inode) - return ERR_PTR(-ENOMEM); - - inode->i_ino = get_next_ino(); - inode->i_mapping->a_ops = &anon_aops; - - /* - * Mark the inode dirty from the very beginning, - * that way it will never be moved to the dirty - * list because mark_inode_dirty() will think - * that it already _is_ on the dirty list. - */ - inode->i_state = I_DIRTY; - inode->i_mode = S_IRUSR | S_IWUSR; - inode->i_uid = current_fsuid(); - inode->i_gid = current_fsgid(); - inode->i_flags |= S_PRIVATE; - inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); - return inode; -} -EXPORT_SYMBOL(alloc_anon_inode); - -/** - * simple_nosetlease - generic helper for prohibiting leases - * @filp: file pointer - * @arg: type of lease to obtain - * @flp: new lease supplied for insertion - * @priv: private data for lm_setup operation - * - * Generic helper for filesystems that do not wish to allow leases to be set. - * All arguments are ignored and it just returns -EINVAL. - */ -int -simple_nosetlease(struct file *filp, long arg, struct file_lock **flp, - void **priv) -{ - return -EINVAL; -} -EXPORT_SYMBOL(simple_nosetlease); - -const char *simple_get_link(struct dentry *dentry, struct inode *inode, - struct delayed_call *done) -{ - return inode->i_link; -} -EXPORT_SYMBOL(simple_get_link); - -const struct inode_operations simple_symlink_inode_operations = { - .get_link = simple_get_link, - .readlink = generic_readlink -}; -EXPORT_SYMBOL(simple_symlink_inode_operations); - -/* - * Operations for a permanently empty directory. - */ -static struct dentry *empty_dir_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) -{ - return ERR_PTR(-ENOENT); -} - -static int empty_dir_getattr(struct vfsmount *mnt, struct dentry *dentry, - struct kstat *stat) -{ - struct inode *inode = d_inode(dentry); - generic_fillattr(inode, stat); - return 0; -} - -static int empty_dir_setattr(struct dentry *dentry, struct iattr *attr) -{ - return -EPERM; -} - -static ssize_t empty_dir_listxattr(struct dentry *dentry, char *list, size_t size) -{ - return -EOPNOTSUPP; -} - -static const struct inode_operations empty_dir_inode_operations = { - .lookup = empty_dir_lookup, - .permission = generic_permission, - .setattr = empty_dir_setattr, - .getattr = empty_dir_getattr, - .listxattr = empty_dir_listxattr, -}; - -static loff_t empty_dir_llseek(struct file *file, loff_t offset, int whence) -{ - /* An empty directory has two entries . and .. at offsets 0 and 1 */ - return generic_file_llseek_size(file, offset, whence, 2, 2); -} - -static int empty_dir_readdir(struct file *file, struct dir_context *ctx) -{ - dir_emit_dots(file, ctx); - return 0; -} - -static const struct file_operations empty_dir_operations = { - .llseek = empty_dir_llseek, - .read = generic_read_dir, - .iterate_shared = empty_dir_readdir, - .fsync = noop_fsync, -}; - - -void make_empty_dir_inode(struct inode *inode) -{ - set_nlink(inode, 2); - inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; - inode->i_uid = GLOBAL_ROOT_UID; - inode->i_gid = GLOBAL_ROOT_GID; - inode->i_rdev = 0; - inode->i_size = 0; - inode->i_blkbits = PAGE_SHIFT; - inode->i_blocks = 0; - - inode->i_op = &empty_dir_inode_operations; - inode->i_opflags &= ~IOP_XATTR; - inode->i_fop = &empty_dir_operations; -} - -bool is_empty_dir_inode(struct inode *inode) -{ - return (inode->i_fop == &empty_dir_operations) && - (inode->i_op == &empty_dir_inode_operations); -} diff --git a/src/linux/fs/logfs/Kconfig b/src/linux/fs/logfs/Kconfig deleted file mode 100644 index 2b45031..0000000 --- a/src/linux/fs/logfs/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -config LOGFS - tristate "LogFS file system" - depends on MTD || (!MTD && BLOCK) - select ZLIB_INFLATE - select ZLIB_DEFLATE - select CRC32 - select BTREE - help - Flash filesystem aimed to scale efficiently to large devices. - In comparison to JFFS2 it offers significantly faster mount - times and potentially less RAM usage, although the latter has - not been measured yet. - - In its current state it is still very experimental and should - not be used for other than testing purposes. - - If unsure, say N. diff --git a/src/linux/fs/mbcache.c b/src/linux/fs/mbcache.c deleted file mode 100644 index c5bd19f..0000000 --- a/src/linux/fs/mbcache.c +++ /dev/null @@ -1,437 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Mbcache is a simple key-value store. Keys need not be unique, however - * key-value pairs are expected to be unique (we use this fact in - * mb_cache_entry_delete_block()). - * - * Ext2 and ext4 use this cache for deduplication of extended attribute blocks. - * They use hash of a block contents as a key and block number as a value. - * That's why keys need not be unique (different xattr blocks may end up having - * the same hash). However block number always uniquely identifies a cache - * entry. - * - * We provide functions for creation and removal of entries, search by key, - * and a special "delete entry with given key-value pair" operation. Fixed - * size hash table is used for fast key lookups. - */ - -struct mb_cache { - /* Hash table of entries */ - struct hlist_bl_head *c_hash; - /* log2 of hash table size */ - int c_bucket_bits; - /* Maximum entries in cache to avoid degrading hash too much */ - int c_max_entries; - /* Protects c_list, c_entry_count */ - spinlock_t c_list_lock; - struct list_head c_list; - /* Number of entries in cache */ - unsigned long c_entry_count; - struct shrinker c_shrink; - /* Work for shrinking when the cache has too many entries */ - struct work_struct c_shrink_work; -}; - -static struct kmem_cache *mb_entry_cache; - -static unsigned long mb_cache_shrink(struct mb_cache *cache, - unsigned int nr_to_scan); - -static inline struct hlist_bl_head *mb_cache_entry_head(struct mb_cache *cache, - u32 key) -{ - return &cache->c_hash[hash_32(key, cache->c_bucket_bits)]; -} - -/* - * Number of entries to reclaim synchronously when there are too many entries - * in cache - */ -#define SYNC_SHRINK_BATCH 64 - -/* - * mb_cache_entry_create - create entry in cache - * @cache - cache where the entry should be created - * @mask - gfp mask with which the entry should be allocated - * @key - key of the entry - * @block - block that contains data - * @reusable - is the block reusable by other inodes? - * - * Creates entry in @cache with key @key and records that data is stored in - * block @block. The function returns -EBUSY if entry with the same key - * and for the same block already exists in cache. Otherwise 0 is returned. - */ -int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key, - sector_t block, bool reusable) -{ - struct mb_cache_entry *entry, *dup; - struct hlist_bl_node *dup_node; - struct hlist_bl_head *head; - - /* Schedule background reclaim if there are too many entries */ - if (cache->c_entry_count >= cache->c_max_entries) - schedule_work(&cache->c_shrink_work); - /* Do some sync reclaim if background reclaim cannot keep up */ - if (cache->c_entry_count >= 2*cache->c_max_entries) - mb_cache_shrink(cache, SYNC_SHRINK_BATCH); - - entry = kmem_cache_alloc(mb_entry_cache, mask); - if (!entry) - return -ENOMEM; - - INIT_LIST_HEAD(&entry->e_list); - /* One ref for hash, one ref returned */ - atomic_set(&entry->e_refcnt, 1); - entry->e_key = key; - entry->e_block = block; - entry->e_reusable = reusable; - head = mb_cache_entry_head(cache, key); - hlist_bl_lock(head); - hlist_bl_for_each_entry(dup, dup_node, head, e_hash_list) { - if (dup->e_key == key && dup->e_block == block) { - hlist_bl_unlock(head); - kmem_cache_free(mb_entry_cache, entry); - return -EBUSY; - } - } - hlist_bl_add_head(&entry->e_hash_list, head); - hlist_bl_unlock(head); - - spin_lock(&cache->c_list_lock); - list_add_tail(&entry->e_list, &cache->c_list); - /* Grab ref for LRU list */ - atomic_inc(&entry->e_refcnt); - cache->c_entry_count++; - spin_unlock(&cache->c_list_lock); - - return 0; -} -EXPORT_SYMBOL(mb_cache_entry_create); - -void __mb_cache_entry_free(struct mb_cache_entry *entry) -{ - kmem_cache_free(mb_entry_cache, entry); -} -EXPORT_SYMBOL(__mb_cache_entry_free); - -static struct mb_cache_entry *__entry_find(struct mb_cache *cache, - struct mb_cache_entry *entry, - u32 key) -{ - struct mb_cache_entry *old_entry = entry; - struct hlist_bl_node *node; - struct hlist_bl_head *head; - - head = mb_cache_entry_head(cache, key); - hlist_bl_lock(head); - if (entry && !hlist_bl_unhashed(&entry->e_hash_list)) - node = entry->e_hash_list.next; - else - node = hlist_bl_first(head); - while (node) { - entry = hlist_bl_entry(node, struct mb_cache_entry, - e_hash_list); - if (entry->e_key == key && entry->e_reusable) { - atomic_inc(&entry->e_refcnt); - goto out; - } - node = node->next; - } - entry = NULL; -out: - hlist_bl_unlock(head); - if (old_entry) - mb_cache_entry_put(cache, old_entry); - - return entry; -} - -/* - * mb_cache_entry_find_first - find the first entry in cache with given key - * @cache: cache where we should search - * @key: key to look for - * - * Search in @cache for entry with key @key. Grabs reference to the first - * entry found and returns the entry. - */ -struct mb_cache_entry *mb_cache_entry_find_first(struct mb_cache *cache, - u32 key) -{ - return __entry_find(cache, NULL, key); -} -EXPORT_SYMBOL(mb_cache_entry_find_first); - -/* - * mb_cache_entry_find_next - find next entry in cache with the same - * @cache: cache where we should search - * @entry: entry to start search from - * - * Finds next entry in the hash chain which has the same key as @entry. - * If @entry is unhashed (which can happen when deletion of entry races - * with the search), finds the first entry in the hash chain. The function - * drops reference to @entry and returns with a reference to the found entry. - */ -struct mb_cache_entry *mb_cache_entry_find_next(struct mb_cache *cache, - struct mb_cache_entry *entry) -{ - return __entry_find(cache, entry, entry->e_key); -} -EXPORT_SYMBOL(mb_cache_entry_find_next); - -/* - * mb_cache_entry_get - get a cache entry by block number (and key) - * @cache - cache we work with - * @key - key of block number @block - * @block - block number - */ -struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *cache, u32 key, - sector_t block) -{ - struct hlist_bl_node *node; - struct hlist_bl_head *head; - struct mb_cache_entry *entry; - - head = mb_cache_entry_head(cache, key); - hlist_bl_lock(head); - hlist_bl_for_each_entry(entry, node, head, e_hash_list) { - if (entry->e_key == key && entry->e_block == block) { - atomic_inc(&entry->e_refcnt); - goto out; - } - } - entry = NULL; -out: - hlist_bl_unlock(head); - return entry; -} -EXPORT_SYMBOL(mb_cache_entry_get); - -/* mb_cache_entry_delete_block - remove information about block from cache - * @cache - cache we work with - * @key - key of block @block - * @block - block number - * - * Remove entry from cache @cache with key @key with data stored in @block. - */ -void mb_cache_entry_delete_block(struct mb_cache *cache, u32 key, - sector_t block) -{ - struct hlist_bl_node *node; - struct hlist_bl_head *head; - struct mb_cache_entry *entry; - - head = mb_cache_entry_head(cache, key); - hlist_bl_lock(head); - hlist_bl_for_each_entry(entry, node, head, e_hash_list) { - if (entry->e_key == key && entry->e_block == block) { - /* We keep hash list reference to keep entry alive */ - hlist_bl_del_init(&entry->e_hash_list); - hlist_bl_unlock(head); - spin_lock(&cache->c_list_lock); - if (!list_empty(&entry->e_list)) { - list_del_init(&entry->e_list); - cache->c_entry_count--; - atomic_dec(&entry->e_refcnt); - } - spin_unlock(&cache->c_list_lock); - mb_cache_entry_put(cache, entry); - return; - } - } - hlist_bl_unlock(head); -} -EXPORT_SYMBOL(mb_cache_entry_delete_block); - -/* mb_cache_entry_touch - cache entry got used - * @cache - cache the entry belongs to - * @entry - entry that got used - * - * Marks entry as used to give hit higher chances of surviving in cache. - */ -void mb_cache_entry_touch(struct mb_cache *cache, - struct mb_cache_entry *entry) -{ - entry->e_referenced = 1; -} -EXPORT_SYMBOL(mb_cache_entry_touch); - -static unsigned long mb_cache_count(struct shrinker *shrink, - struct shrink_control *sc) -{ - struct mb_cache *cache = container_of(shrink, struct mb_cache, - c_shrink); - - return cache->c_entry_count; -} - -/* Shrink number of entries in cache */ -static unsigned long mb_cache_shrink(struct mb_cache *cache, - unsigned int nr_to_scan) -{ - struct mb_cache_entry *entry; - struct hlist_bl_head *head; - unsigned int shrunk = 0; - - spin_lock(&cache->c_list_lock); - while (nr_to_scan-- && !list_empty(&cache->c_list)) { - entry = list_first_entry(&cache->c_list, - struct mb_cache_entry, e_list); - if (entry->e_referenced) { - entry->e_referenced = 0; - list_move_tail(&cache->c_list, &entry->e_list); - continue; - } - list_del_init(&entry->e_list); - cache->c_entry_count--; - /* - * We keep LRU list reference so that entry doesn't go away - * from under us. - */ - spin_unlock(&cache->c_list_lock); - head = mb_cache_entry_head(cache, entry->e_key); - hlist_bl_lock(head); - if (!hlist_bl_unhashed(&entry->e_hash_list)) { - hlist_bl_del_init(&entry->e_hash_list); - atomic_dec(&entry->e_refcnt); - } - hlist_bl_unlock(head); - if (mb_cache_entry_put(cache, entry)) - shrunk++; - cond_resched(); - spin_lock(&cache->c_list_lock); - } - spin_unlock(&cache->c_list_lock); - - return shrunk; -} - -static unsigned long mb_cache_scan(struct shrinker *shrink, - struct shrink_control *sc) -{ - int nr_to_scan = sc->nr_to_scan; - struct mb_cache *cache = container_of(shrink, struct mb_cache, - c_shrink); - return mb_cache_shrink(cache, nr_to_scan); -} - -/* We shrink 1/X of the cache when we have too many entries in it */ -#define SHRINK_DIVISOR 16 - -static void mb_cache_shrink_worker(struct work_struct *work) -{ - struct mb_cache *cache = container_of(work, struct mb_cache, - c_shrink_work); - mb_cache_shrink(cache, cache->c_max_entries / SHRINK_DIVISOR); -} - -/* - * mb_cache_create - create cache - * @bucket_bits: log2 of the hash table size - * - * Create cache for keys with 2^bucket_bits hash entries. - */ -struct mb_cache *mb_cache_create(int bucket_bits) -{ - struct mb_cache *cache; - int bucket_count = 1 << bucket_bits; - int i; - - if (!try_module_get(THIS_MODULE)) - return NULL; - - cache = kzalloc(sizeof(struct mb_cache), GFP_KERNEL); - if (!cache) - goto err_out; - cache->c_bucket_bits = bucket_bits; - cache->c_max_entries = bucket_count << 4; - INIT_LIST_HEAD(&cache->c_list); - spin_lock_init(&cache->c_list_lock); - cache->c_hash = kmalloc(bucket_count * sizeof(struct hlist_bl_head), - GFP_KERNEL); - if (!cache->c_hash) { - kfree(cache); - goto err_out; - } - for (i = 0; i < bucket_count; i++) - INIT_HLIST_BL_HEAD(&cache->c_hash[i]); - - cache->c_shrink.count_objects = mb_cache_count; - cache->c_shrink.scan_objects = mb_cache_scan; - cache->c_shrink.seeks = DEFAULT_SEEKS; - if (register_shrinker(&cache->c_shrink)) { - kfree(cache->c_hash); - kfree(cache); - goto err_out; - } - - INIT_WORK(&cache->c_shrink_work, mb_cache_shrink_worker); - - return cache; - -err_out: - module_put(THIS_MODULE); - return NULL; -} -EXPORT_SYMBOL(mb_cache_create); - -/* - * mb_cache_destroy - destroy cache - * @cache: the cache to destroy - * - * Free all entries in cache and cache itself. Caller must make sure nobody - * (except shrinker) can reach @cache when calling this. - */ -void mb_cache_destroy(struct mb_cache *cache) -{ - struct mb_cache_entry *entry, *next; - - unregister_shrinker(&cache->c_shrink); - - /* - * We don't bother with any locking. Cache must not be used at this - * point. - */ - list_for_each_entry_safe(entry, next, &cache->c_list, e_list) { - if (!hlist_bl_unhashed(&entry->e_hash_list)) { - hlist_bl_del_init(&entry->e_hash_list); - atomic_dec(&entry->e_refcnt); - } else - WARN_ON(1); - list_del(&entry->e_list); - WARN_ON(atomic_read(&entry->e_refcnt) != 1); - mb_cache_entry_put(cache, entry); - } - kfree(cache->c_hash); - kfree(cache); - module_put(THIS_MODULE); -} -EXPORT_SYMBOL(mb_cache_destroy); - -static int __init mbcache_init(void) -{ - mb_entry_cache = kmem_cache_create("mbcache", - sizeof(struct mb_cache_entry), 0, - SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL); - BUG_ON(!mb_entry_cache); - return 0; -} - -static void __exit mbcache_exit(void) -{ - kmem_cache_destroy(mb_entry_cache); -} - -module_init(mbcache_init) -module_exit(mbcache_exit) - -MODULE_AUTHOR("Jan Kara "); -MODULE_DESCRIPTION("Meta block cache (for extended attributes)"); -MODULE_LICENSE("GPL"); diff --git a/src/linux/fs/minix/Kconfig b/src/linux/fs/minix/Kconfig deleted file mode 100644 index f2a0cfc..0000000 --- a/src/linux/fs/minix/Kconfig +++ /dev/null @@ -1,25 +0,0 @@ -config MINIX_FS - tristate "Minix file system support" - depends on BLOCK - help - Minix is a simple operating system used in many classes about OS's. - The minix file system (method to organize files on a hard disk - partition or a floppy disk) was the original file system for Linux, - but has been superseded by the second extended file system ext2fs. - You don't want to use the minix file system on your hard disk - because of certain built-in restrictions, but it is sometimes found - on older Linux floppy disks. This option will enlarge your kernel - by about 28 KB. If unsure, say N. - - To compile this file system support as a module, choose M here: the - module will be called minix. Note that the file system of your root - partition (the one containing the directory /) cannot be compiled as - a module. - -config MINIX_FS_NATIVE_ENDIAN - def_bool MINIX_FS - depends on M32R || MICROBLAZE || MIPS || S390 || SUPERH || SPARC || XTENSA || (M68K && !MMU) - -config MINIX_FS_BIG_ENDIAN_16BIT_INDEXED - def_bool MINIX_FS - depends on M68K && MMU diff --git a/src/linux/fs/mount.h b/src/linux/fs/mount.h deleted file mode 100644 index d2e25d7..0000000 --- a/src/linux/fs/mount.h +++ /dev/null @@ -1,141 +0,0 @@ -#include -#include -#include -#include -#include - -struct mnt_namespace { - atomic_t count; - struct ns_common ns; - struct mount * root; - struct list_head list; - struct user_namespace *user_ns; - struct ucounts *ucounts; - u64 seq; /* Sequence number to prevent loops */ - wait_queue_head_t poll; - u64 event; - unsigned int mounts; /* # of mounts in the namespace */ - unsigned int pending_mounts; -}; - -struct mnt_pcp { - int mnt_count; - int mnt_writers; -}; - -struct mountpoint { - struct hlist_node m_hash; - struct dentry *m_dentry; - struct hlist_head m_list; - int m_count; -}; - -struct mount { - struct hlist_node mnt_hash; - struct mount *mnt_parent; - struct dentry *mnt_mountpoint; - struct vfsmount mnt; - union { - struct rcu_head mnt_rcu; - struct llist_node mnt_llist; - }; -#ifdef CONFIG_SMP - struct mnt_pcp __percpu *mnt_pcp; -#else - int mnt_count; - int mnt_writers; -#endif - struct list_head mnt_mounts; /* list of children, anchored here */ - struct list_head mnt_child; /* and going through their mnt_child */ - struct list_head mnt_instance; /* mount instance on sb->s_mounts */ - const char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */ - struct list_head mnt_list; - struct list_head mnt_expire; /* link in fs-specific expiry list */ - struct list_head mnt_share; /* circular list of shared mounts */ - struct list_head mnt_slave_list;/* list of slave mounts */ - struct list_head mnt_slave; /* slave list entry */ - struct mount *mnt_master; /* slave is on master->mnt_slave_list */ - struct mnt_namespace *mnt_ns; /* containing namespace */ - struct mountpoint *mnt_mp; /* where is it mounted */ - struct hlist_node mnt_mp_list; /* list mounts with the same mountpoint */ -#ifdef CONFIG_FSNOTIFY - struct hlist_head mnt_fsnotify_marks; - __u32 mnt_fsnotify_mask; -#endif - int mnt_id; /* mount identifier */ - int mnt_group_id; /* peer group identifier */ - int mnt_expiry_mark; /* true if marked for expiry */ - struct hlist_head mnt_pins; - struct fs_pin mnt_umount; - struct dentry *mnt_ex_mountpoint; -}; - -#define MNT_NS_INTERNAL ERR_PTR(-EINVAL) /* distinct from any mnt_namespace */ - -static inline struct mount *real_mount(struct vfsmount *mnt) -{ - return container_of(mnt, struct mount, mnt); -} - -static inline int mnt_has_parent(struct mount *mnt) -{ - return mnt != mnt->mnt_parent; -} - -static inline int is_mounted(struct vfsmount *mnt) -{ - /* neither detached nor internal? */ - return !IS_ERR_OR_NULL(real_mount(mnt)->mnt_ns); -} - -extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *); -extern struct mount *__lookup_mnt_last(struct vfsmount *, struct dentry *); - -extern int __legitimize_mnt(struct vfsmount *, unsigned); -extern bool legitimize_mnt(struct vfsmount *, unsigned); - -extern void __detach_mounts(struct dentry *dentry); - -static inline void detach_mounts(struct dentry *dentry) -{ - if (!d_mountpoint(dentry)) - return; - __detach_mounts(dentry); -} - -static inline void get_mnt_ns(struct mnt_namespace *ns) -{ - atomic_inc(&ns->count); -} - -extern seqlock_t mount_lock; - -static inline void lock_mount_hash(void) -{ - write_seqlock(&mount_lock); -} - -static inline void unlock_mount_hash(void) -{ - write_sequnlock(&mount_lock); -} - -struct proc_mounts { - struct mnt_namespace *ns; - struct path root; - int (*show)(struct seq_file *, struct vfsmount *); - void *cached_mount; - u64 cached_event; - loff_t cached_index; -}; - -extern const struct seq_operations mounts_op; - -extern bool __is_local_mountpoint(struct dentry *dentry); -static inline bool is_local_mountpoint(struct dentry *dentry) -{ - if (!d_mountpoint(dentry)) - return false; - - return __is_local_mountpoint(dentry); -} diff --git a/src/linux/fs/mpage.c b/src/linux/fs/mpage.c deleted file mode 100644 index d2413af..0000000 --- a/src/linux/fs/mpage.c +++ /dev/null @@ -1,734 +0,0 @@ -/* - * fs/mpage.c - * - * Copyright (C) 2002, Linus Torvalds. - * - * Contains functions related to preparing and submitting BIOs which contain - * multiple pagecache pages. - * - * 15May2002 Andrew Morton - * Initial version - * 27Jun2002 axboe@suse.de - * use bio_add_page() to build bio's just the right size - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -/* - * I/O completion handler for multipage BIOs. - * - * The mpage code never puts partial pages into a BIO (except for end-of-file). - * If a page does not map to a contiguous run of blocks then it simply falls - * back to block_read_full_page(). - * - * Why is this? If a page's completion depends on a number of different BIOs - * which can complete in any order (or at the same time) then determining the - * status of that page is hard. See end_buffer_async_read() for the details. - * There is no point in duplicating all that complexity. - */ -static void mpage_end_io(struct bio *bio) -{ - struct bio_vec *bv; - int i; - - bio_for_each_segment_all(bv, bio, i) { - struct page *page = bv->bv_page; - page_endio(page, op_is_write(bio_op(bio)), bio->bi_error); - } - - bio_put(bio); -} - -static struct bio *mpage_bio_submit(int op, int op_flags, struct bio *bio) -{ - bio->bi_end_io = mpage_end_io; - bio_set_op_attrs(bio, op, op_flags); - guard_bio_eod(op, bio); - submit_bio(bio); - return NULL; -} - -static struct bio * -mpage_alloc(struct block_device *bdev, - sector_t first_sector, int nr_vecs, - gfp_t gfp_flags) -{ - struct bio *bio; - - /* Restrict the given (page cache) mask for slab allocations */ - gfp_flags &= GFP_KERNEL; - bio = bio_alloc(gfp_flags, nr_vecs); - - if (bio == NULL && (current->flags & PF_MEMALLOC)) { - while (!bio && (nr_vecs /= 2)) - bio = bio_alloc(gfp_flags, nr_vecs); - } - - if (bio) { - bio->bi_bdev = bdev; - bio->bi_iter.bi_sector = first_sector; - } - return bio; -} - -/* - * support function for mpage_readpages. The fs supplied get_block might - * return an up to date buffer. This is used to map that buffer into - * the page, which allows readpage to avoid triggering a duplicate call - * to get_block. - * - * The idea is to avoid adding buffers to pages that don't already have - * them. So when the buffer is up to date and the page size == block size, - * this marks the page up to date instead of adding new buffers. - */ -static void -map_buffer_to_page(struct page *page, struct buffer_head *bh, int page_block) -{ - struct inode *inode = page->mapping->host; - struct buffer_head *page_bh, *head; - int block = 0; - - if (!page_has_buffers(page)) { - /* - * don't make any buffers if there is only one buffer on - * the page and the page just needs to be set up to date - */ - if (inode->i_blkbits == PAGE_SHIFT && - buffer_uptodate(bh)) { - SetPageUptodate(page); - return; - } - create_empty_buffers(page, 1 << inode->i_blkbits, 0); - } - head = page_buffers(page); - page_bh = head; - do { - if (block == page_block) { - page_bh->b_state = bh->b_state; - page_bh->b_bdev = bh->b_bdev; - page_bh->b_blocknr = bh->b_blocknr; - break; - } - page_bh = page_bh->b_this_page; - block++; - } while (page_bh != head); -} - -/* - * This is the worker routine which does all the work of mapping the disk - * blocks and constructs largest possible bios, submits them for IO if the - * blocks are not contiguous on the disk. - * - * We pass a buffer_head back and forth and use its buffer_mapped() flag to - * represent the validity of its disk mapping and to decide when to do the next - * get_block() call. - */ -static struct bio * -do_mpage_readpage(struct bio *bio, struct page *page, unsigned nr_pages, - sector_t *last_block_in_bio, struct buffer_head *map_bh, - unsigned long *first_logical_block, get_block_t get_block, - gfp_t gfp) -{ - struct inode *inode = page->mapping->host; - const unsigned blkbits = inode->i_blkbits; - const unsigned blocks_per_page = PAGE_SIZE >> blkbits; - const unsigned blocksize = 1 << blkbits; - sector_t block_in_file; - sector_t last_block; - sector_t last_block_in_file; - sector_t blocks[MAX_BUF_PER_PAGE]; - unsigned page_block; - unsigned first_hole = blocks_per_page; - struct block_device *bdev = NULL; - int length; - int fully_mapped = 1; - unsigned nblocks; - unsigned relative_block; - - if (page_has_buffers(page)) - goto confused; - - block_in_file = (sector_t)page->index << (PAGE_SHIFT - blkbits); - last_block = block_in_file + nr_pages * blocks_per_page; - last_block_in_file = (i_size_read(inode) + blocksize - 1) >> blkbits; - if (last_block > last_block_in_file) - last_block = last_block_in_file; - page_block = 0; - - /* - * Map blocks using the result from the previous get_blocks call first. - */ - nblocks = map_bh->b_size >> blkbits; - if (buffer_mapped(map_bh) && block_in_file > *first_logical_block && - block_in_file < (*first_logical_block + nblocks)) { - unsigned map_offset = block_in_file - *first_logical_block; - unsigned last = nblocks - map_offset; - - for (relative_block = 0; ; relative_block++) { - if (relative_block == last) { - clear_buffer_mapped(map_bh); - break; - } - if (page_block == blocks_per_page) - break; - blocks[page_block] = map_bh->b_blocknr + map_offset + - relative_block; - page_block++; - block_in_file++; - } - bdev = map_bh->b_bdev; - } - - /* - * Then do more get_blocks calls until we are done with this page. - */ - map_bh->b_page = page; - while (page_block < blocks_per_page) { - map_bh->b_state = 0; - map_bh->b_size = 0; - - if (block_in_file < last_block) { - map_bh->b_size = (last_block-block_in_file) << blkbits; - if (get_block(inode, block_in_file, map_bh, 0)) - goto confused; - *first_logical_block = block_in_file; - } - - if (!buffer_mapped(map_bh)) { - fully_mapped = 0; - if (first_hole == blocks_per_page) - first_hole = page_block; - page_block++; - block_in_file++; - continue; - } - - /* some filesystems will copy data into the page during - * the get_block call, in which case we don't want to - * read it again. map_buffer_to_page copies the data - * we just collected from get_block into the page's buffers - * so readpage doesn't have to repeat the get_block call - */ - if (buffer_uptodate(map_bh)) { - map_buffer_to_page(page, map_bh, page_block); - goto confused; - } - - if (first_hole != blocks_per_page) - goto confused; /* hole -> non-hole */ - - /* Contiguous blocks? */ - if (page_block && blocks[page_block-1] != map_bh->b_blocknr-1) - goto confused; - nblocks = map_bh->b_size >> blkbits; - for (relative_block = 0; ; relative_block++) { - if (relative_block == nblocks) { - clear_buffer_mapped(map_bh); - break; - } else if (page_block == blocks_per_page) - break; - blocks[page_block] = map_bh->b_blocknr+relative_block; - page_block++; - block_in_file++; - } - bdev = map_bh->b_bdev; - } - - if (first_hole != blocks_per_page) { - zero_user_segment(page, first_hole << blkbits, PAGE_SIZE); - if (first_hole == 0) { - SetPageUptodate(page); - unlock_page(page); - goto out; - } - } else if (fully_mapped) { - SetPageMappedToDisk(page); - } - - if (fully_mapped && blocks_per_page == 1 && !PageUptodate(page) && - cleancache_get_page(page) == 0) { - SetPageUptodate(page); - goto confused; - } - - /* - * This page will go to BIO. Do we need to send this BIO off first? - */ - if (bio && (*last_block_in_bio != blocks[0] - 1)) - bio = mpage_bio_submit(REQ_OP_READ, 0, bio); - -alloc_new: - if (bio == NULL) { - if (first_hole == blocks_per_page) { - if (!bdev_read_page(bdev, blocks[0] << (blkbits - 9), - page)) - goto out; - } - bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9), - min_t(int, nr_pages, BIO_MAX_PAGES), gfp); - if (bio == NULL) - goto confused; - } - - length = first_hole << blkbits; - if (bio_add_page(bio, page, length, 0) < length) { - bio = mpage_bio_submit(REQ_OP_READ, 0, bio); - goto alloc_new; - } - - relative_block = block_in_file - *first_logical_block; - nblocks = map_bh->b_size >> blkbits; - if ((buffer_boundary(map_bh) && relative_block == nblocks) || - (first_hole != blocks_per_page)) - bio = mpage_bio_submit(REQ_OP_READ, 0, bio); - else - *last_block_in_bio = blocks[blocks_per_page - 1]; -out: - return bio; - -confused: - if (bio) - bio = mpage_bio_submit(REQ_OP_READ, 0, bio); - if (!PageUptodate(page)) - block_read_full_page(page, get_block); - else - unlock_page(page); - goto out; -} - -/** - * mpage_readpages - populate an address space with some pages & start reads against them - * @mapping: the address_space - * @pages: The address of a list_head which contains the target pages. These - * pages have their ->index populated and are otherwise uninitialised. - * The page at @pages->prev has the lowest file offset, and reads should be - * issued in @pages->prev to @pages->next order. - * @nr_pages: The number of pages at *@pages - * @get_block: The filesystem's block mapper function. - * - * This function walks the pages and the blocks within each page, building and - * emitting large BIOs. - * - * If anything unusual happens, such as: - * - * - encountering a page which has buffers - * - encountering a page which has a non-hole after a hole - * - encountering a page with non-contiguous blocks - * - * then this code just gives up and calls the buffer_head-based read function. - * It does handle a page which has holes at the end - that is a common case: - * the end-of-file on blocksize < PAGE_SIZE setups. - * - * BH_Boundary explanation: - * - * There is a problem. The mpage read code assembles several pages, gets all - * their disk mappings, and then submits them all. That's fine, but obtaining - * the disk mappings may require I/O. Reads of indirect blocks, for example. - * - * So an mpage read of the first 16 blocks of an ext2 file will cause I/O to be - * submitted in the following order: - * 12 0 1 2 3 4 5 6 7 8 9 10 11 13 14 15 16 - * - * because the indirect block has to be read to get the mappings of blocks - * 13,14,15,16. Obviously, this impacts performance. - * - * So what we do it to allow the filesystem's get_block() function to set - * BH_Boundary when it maps block 11. BH_Boundary says: mapping of the block - * after this one will require I/O against a block which is probably close to - * this one. So you should push what I/O you have currently accumulated. - * - * This all causes the disk requests to be issued in the correct order. - */ -int -mpage_readpages(struct address_space *mapping, struct list_head *pages, - unsigned nr_pages, get_block_t get_block) -{ - struct bio *bio = NULL; - unsigned page_idx; - sector_t last_block_in_bio = 0; - struct buffer_head map_bh; - unsigned long first_logical_block = 0; - gfp_t gfp = readahead_gfp_mask(mapping); - - map_bh.b_state = 0; - map_bh.b_size = 0; - for (page_idx = 0; page_idx < nr_pages; page_idx++) { - struct page *page = lru_to_page(pages); - - prefetchw(&page->flags); - list_del(&page->lru); - if (!add_to_page_cache_lru(page, mapping, - page->index, - gfp)) { - bio = do_mpage_readpage(bio, page, - nr_pages - page_idx, - &last_block_in_bio, &map_bh, - &first_logical_block, - get_block, gfp); - } - put_page(page); - } - BUG_ON(!list_empty(pages)); - if (bio) - mpage_bio_submit(REQ_OP_READ, 0, bio); - return 0; -} -EXPORT_SYMBOL(mpage_readpages); - -/* - * This isn't called much at all - */ -int mpage_readpage(struct page *page, get_block_t get_block) -{ - struct bio *bio = NULL; - sector_t last_block_in_bio = 0; - struct buffer_head map_bh; - unsigned long first_logical_block = 0; - gfp_t gfp = mapping_gfp_constraint(page->mapping, GFP_KERNEL); - - map_bh.b_state = 0; - map_bh.b_size = 0; - bio = do_mpage_readpage(bio, page, 1, &last_block_in_bio, - &map_bh, &first_logical_block, get_block, gfp); - if (bio) - mpage_bio_submit(REQ_OP_READ, 0, bio); - return 0; -} -EXPORT_SYMBOL(mpage_readpage); - -/* - * Writing is not so simple. - * - * If the page has buffers then they will be used for obtaining the disk - * mapping. We only support pages which are fully mapped-and-dirty, with a - * special case for pages which are unmapped at the end: end-of-file. - * - * If the page has no buffers (preferred) then the page is mapped here. - * - * If all blocks are found to be contiguous then the page can go into the - * BIO. Otherwise fall back to the mapping's writepage(). - * - * FIXME: This code wants an estimate of how many pages are still to be - * written, so it can intelligently allocate a suitably-sized BIO. For now, - * just allocate full-size (16-page) BIOs. - */ - -struct mpage_data { - struct bio *bio; - sector_t last_block_in_bio; - get_block_t *get_block; - unsigned use_writepage; -}; - -/* - * We have our BIO, so we can now mark the buffers clean. Make - * sure to only clean buffers which we know we'll be writing. - */ -static void clean_buffers(struct page *page, unsigned first_unmapped) -{ - unsigned buffer_counter = 0; - struct buffer_head *bh, *head; - if (!page_has_buffers(page)) - return; - head = page_buffers(page); - bh = head; - - do { - if (buffer_counter++ == first_unmapped) - break; - clear_buffer_dirty(bh); - bh = bh->b_this_page; - } while (bh != head); - - /* - * we cannot drop the bh if the page is not uptodate or a concurrent - * readpage would fail to serialize with the bh and it would read from - * disk before we reach the platter. - */ - if (buffer_heads_over_limit && PageUptodate(page)) - try_to_free_buffers(page); -} - -static int __mpage_writepage(struct page *page, struct writeback_control *wbc, - void *data) -{ - struct mpage_data *mpd = data; - struct bio *bio = mpd->bio; - struct address_space *mapping = page->mapping; - struct inode *inode = page->mapping->host; - const unsigned blkbits = inode->i_blkbits; - unsigned long end_index; - const unsigned blocks_per_page = PAGE_SIZE >> blkbits; - sector_t last_block; - sector_t block_in_file; - sector_t blocks[MAX_BUF_PER_PAGE]; - unsigned page_block; - unsigned first_unmapped = blocks_per_page; - struct block_device *bdev = NULL; - int boundary = 0; - sector_t boundary_block = 0; - struct block_device *boundary_bdev = NULL; - int length; - struct buffer_head map_bh; - loff_t i_size = i_size_read(inode); - int ret = 0; - int op_flags = (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC : 0); - - if (page_has_buffers(page)) { - struct buffer_head *head = page_buffers(page); - struct buffer_head *bh = head; - - /* If they're all mapped and dirty, do it */ - page_block = 0; - do { - BUG_ON(buffer_locked(bh)); - if (!buffer_mapped(bh)) { - /* - * unmapped dirty buffers are created by - * __set_page_dirty_buffers -> mmapped data - */ - if (buffer_dirty(bh)) - goto confused; - if (first_unmapped == blocks_per_page) - first_unmapped = page_block; - continue; - } - - if (first_unmapped != blocks_per_page) - goto confused; /* hole -> non-hole */ - - if (!buffer_dirty(bh) || !buffer_uptodate(bh)) - goto confused; - if (page_block) { - if (bh->b_blocknr != blocks[page_block-1] + 1) - goto confused; - } - blocks[page_block++] = bh->b_blocknr; - boundary = buffer_boundary(bh); - if (boundary) { - boundary_block = bh->b_blocknr; - boundary_bdev = bh->b_bdev; - } - bdev = bh->b_bdev; - } while ((bh = bh->b_this_page) != head); - - if (first_unmapped) - goto page_is_mapped; - - /* - * Page has buffers, but they are all unmapped. The page was - * created by pagein or read over a hole which was handled by - * block_read_full_page(). If this address_space is also - * using mpage_readpages then this can rarely happen. - */ - goto confused; - } - - /* - * The page has no buffers: map it to disk - */ - BUG_ON(!PageUptodate(page)); - block_in_file = (sector_t)page->index << (PAGE_SHIFT - blkbits); - last_block = (i_size - 1) >> blkbits; - map_bh.b_page = page; - for (page_block = 0; page_block < blocks_per_page; ) { - - map_bh.b_state = 0; - map_bh.b_size = 1 << blkbits; - if (mpd->get_block(inode, block_in_file, &map_bh, 1)) - goto confused; - if (buffer_new(&map_bh)) - unmap_underlying_metadata(map_bh.b_bdev, - map_bh.b_blocknr); - if (buffer_boundary(&map_bh)) { - boundary_block = map_bh.b_blocknr; - boundary_bdev = map_bh.b_bdev; - } - if (page_block) { - if (map_bh.b_blocknr != blocks[page_block-1] + 1) - goto confused; - } - blocks[page_block++] = map_bh.b_blocknr; - boundary = buffer_boundary(&map_bh); - bdev = map_bh.b_bdev; - if (block_in_file == last_block) - break; - block_in_file++; - } - BUG_ON(page_block == 0); - - first_unmapped = page_block; - -page_is_mapped: - end_index = i_size >> PAGE_SHIFT; - if (page->index >= end_index) { - /* - * The page straddles i_size. It must be zeroed out on each - * and every writepage invocation because it may be mmapped. - * "A file is mapped in multiples of the page size. For a file - * that is not a multiple of the page size, the remaining memory - * is zeroed when mapped, and writes to that region are not - * written out to the file." - */ - unsigned offset = i_size & (PAGE_SIZE - 1); - - if (page->index > end_index || !offset) - goto confused; - zero_user_segment(page, offset, PAGE_SIZE); - } - - /* - * This page will go to BIO. Do we need to send this BIO off first? - */ - if (bio && mpd->last_block_in_bio != blocks[0] - 1) - bio = mpage_bio_submit(REQ_OP_WRITE, op_flags, bio); - -alloc_new: - if (bio == NULL) { - if (first_unmapped == blocks_per_page) { - if (!bdev_write_page(bdev, blocks[0] << (blkbits - 9), - page, wbc)) { - clean_buffers(page, first_unmapped); - goto out; - } - } - bio = mpage_alloc(bdev, blocks[0] << (blkbits - 9), - BIO_MAX_PAGES, GFP_NOFS|__GFP_HIGH); - if (bio == NULL) - goto confused; - - wbc_init_bio(wbc, bio); - } - - /* - * Must try to add the page before marking the buffer clean or - * the confused fail path above (OOM) will be very confused when - * it finds all bh marked clean (i.e. it will not write anything) - */ - wbc_account_io(wbc, page, PAGE_SIZE); - length = first_unmapped << blkbits; - if (bio_add_page(bio, page, length, 0) < length) { - bio = mpage_bio_submit(REQ_OP_WRITE, op_flags, bio); - goto alloc_new; - } - - clean_buffers(page, first_unmapped); - - BUG_ON(PageWriteback(page)); - set_page_writeback(page); - unlock_page(page); - if (boundary || (first_unmapped != blocks_per_page)) { - bio = mpage_bio_submit(REQ_OP_WRITE, op_flags, bio); - if (boundary_block) { - write_boundary_block(boundary_bdev, - boundary_block, 1 << blkbits); - } - } else { - mpd->last_block_in_bio = blocks[blocks_per_page - 1]; - } - goto out; - -confused: - if (bio) - bio = mpage_bio_submit(REQ_OP_WRITE, op_flags, bio); - - if (mpd->use_writepage) { - ret = mapping->a_ops->writepage(page, wbc); - } else { - ret = -EAGAIN; - goto out; - } - /* - * The caller has a ref on the inode, so *mapping is stable - */ - mapping_set_error(mapping, ret); -out: - mpd->bio = bio; - return ret; -} - -/** - * mpage_writepages - walk the list of dirty pages of the given address space & writepage() all of them - * @mapping: address space structure to write - * @wbc: subtract the number of written pages from *@wbc->nr_to_write - * @get_block: the filesystem's block mapper function. - * If this is NULL then use a_ops->writepage. Otherwise, go - * direct-to-BIO. - * - * This is a library function, which implements the writepages() - * address_space_operation. - * - * If a page is already under I/O, generic_writepages() skips it, even - * if it's dirty. This is desirable behaviour for memory-cleaning writeback, - * but it is INCORRECT for data-integrity system calls such as fsync(). fsync() - * and msync() need to guarantee that all the data which was dirty at the time - * the call was made get new I/O started against them. If wbc->sync_mode is - * WB_SYNC_ALL then we were called for data integrity and we must wait for - * existing IO to complete. - */ -int -mpage_writepages(struct address_space *mapping, - struct writeback_control *wbc, get_block_t get_block) -{ - struct blk_plug plug; - int ret; - - blk_start_plug(&plug); - - if (!get_block) - ret = generic_writepages(mapping, wbc); - else { - struct mpage_data mpd = { - .bio = NULL, - .last_block_in_bio = 0, - .get_block = get_block, - .use_writepage = 1, - }; - - ret = write_cache_pages(mapping, wbc, __mpage_writepage, &mpd); - if (mpd.bio) { - int op_flags = (wbc->sync_mode == WB_SYNC_ALL ? - WRITE_SYNC : 0); - mpage_bio_submit(REQ_OP_WRITE, op_flags, mpd.bio); - } - } - blk_finish_plug(&plug); - return ret; -} -EXPORT_SYMBOL(mpage_writepages); - -int mpage_writepage(struct page *page, get_block_t get_block, - struct writeback_control *wbc) -{ - struct mpage_data mpd = { - .bio = NULL, - .last_block_in_bio = 0, - .get_block = get_block, - .use_writepage = 0, - }; - int ret = __mpage_writepage(page, wbc, &mpd); - if (mpd.bio) { - int op_flags = (wbc->sync_mode == WB_SYNC_ALL ? - WRITE_SYNC : 0); - mpage_bio_submit(REQ_OP_WRITE, op_flags, mpd.bio); - } - return ret; -} -EXPORT_SYMBOL(mpage_writepage); diff --git a/src/linux/fs/namei.c b/src/linux/fs/namei.c deleted file mode 100644 index 5b4eed2..0000000 --- a/src/linux/fs/namei.c +++ /dev/null @@ -1,4789 +0,0 @@ -/* - * linux/fs/namei.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -/* - * Some corrections by tytso. - */ - -/* [Feb 1997 T. Schoebel-Theuer] Complete rewrite of the pathname - * lookup logic. - */ -/* [Feb-Apr 2000, AV] Rewrite to the new namespace architecture. - */ - -#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 "internal.h" -#include "mount.h" - -/* [Feb-1997 T. Schoebel-Theuer] - * Fundamental changes in the pathname lookup mechanisms (namei) - * were necessary because of omirr. The reason is that omirr needs - * to know the _real_ pathname, not the user-supplied one, in case - * of symlinks (and also when transname replacements occur). - * - * The new code replaces the old recursive symlink resolution with - * an iterative one (in case of non-nested symlink chains). It does - * this with calls to _follow_link(). - * As a side effect, dir_namei(), _namei() and follow_link() are now - * replaced with a single function lookup_dentry() that can handle all - * the special cases of the former code. - * - * With the new dcache, the pathname is stored at each inode, at least as - * long as the refcount of the inode is positive. As a side effect, the - * size of the dcache depends on the inode cache and thus is dynamic. - * - * [29-Apr-1998 C. Scott Ananian] Updated above description of symlink - * resolution to correspond with current state of the code. - * - * Note that the symlink resolution is not *completely* iterative. - * There is still a significant amount of tail- and mid- recursion in - * the algorithm. Also, note that _readlink() is not used in - * lookup_dentry(): lookup_dentry() on the result of _readlink() - * may return different results than _follow_link(). Many virtual - * filesystems (including /proc) exhibit this behavior. - */ - -/* [24-Feb-97 T. Schoebel-Theuer] Side effects caused by new implementation: - * New symlink semantics: when open() is called with flags O_CREAT | O_EXCL - * and the name already exists in form of a symlink, try to create the new - * name indicated by the symlink. The old code always complained that the - * name already exists, due to not following the symlink even if its target - * is nonexistent. The new semantics affects also mknod() and link() when - * the name is a symlink pointing to a non-existent name. - * - * I don't know which semantics is the right one, since I have no access - * to standards. But I found by trial that HP-UX 9.0 has the full "new" - * semantics implemented, while SunOS 4.1.1 and Solaris (SunOS 5.4) have the - * "old" one. Personally, I think the new semantics is much more logical. - * Note that "ln old new" where "new" is a symlink pointing to a non-existing - * file does succeed in both HP-UX and SunOs, but not in Solaris - * and in the old Linux semantics. - */ - -/* [16-Dec-97 Kevin Buhr] For security reasons, we change some symlink - * semantics. See the comments in "open_namei" and "do_link" below. - * - * [10-Sep-98 Alan Modra] Another symlink change. - */ - -/* [Feb-Apr 2000 AV] Complete rewrite. Rules for symlinks: - * inside the path - always follow. - * in the last component in creation/removal/renaming - never follow. - * if LOOKUP_FOLLOW passed - follow. - * if the pathname has trailing slashes - follow. - * otherwise - don't follow. - * (applied in that order). - * - * [Jun 2000 AV] Inconsistent behaviour of open() in case if flags==O_CREAT - * restored for 2.4. This is the last surviving part of old 4.2BSD bug. - * During the 2.4 we need to fix the userland stuff depending on it - - * hopefully we will be able to get rid of that wart in 2.5. So far only - * XEmacs seems to be relying on it... - */ -/* - * [Sep 2001 AV] Single-semaphore locking scheme (kudos to David Holland) - * implemented. Let's see if raised priority of ->s_vfs_rename_mutex gives - * any extra contention... - */ - -/* In order to reduce some races, while at the same time doing additional - * checking and hopefully speeding things up, we copy filenames to the - * kernel data space before using them.. - * - * POSIX.1 2.4: an empty pathname is invalid (ENOENT). - * PATH_MAX includes the nul terminator --RR. - */ - -#define EMBEDDED_NAME_MAX (PATH_MAX - offsetof(struct filename, iname)) - -struct filename * -getname_flags(const char __user *filename, int flags, int *empty) -{ - struct filename *result; - char *kname; - int len; - - result = audit_reusename(filename); - if (result) - return result; - - result = __getname(); - if (unlikely(!result)) - return ERR_PTR(-ENOMEM); - - /* - * First, try to embed the struct filename inside the names_cache - * allocation - */ - kname = (char *)result->iname; - result->name = kname; - - len = strncpy_from_user(kname, filename, EMBEDDED_NAME_MAX); - if (unlikely(len < 0)) { - __putname(result); - return ERR_PTR(len); - } - - /* - * Uh-oh. We have a name that's approaching PATH_MAX. Allocate a - * separate struct filename so we can dedicate the entire - * names_cache allocation for the pathname, and re-do the copy from - * userland. - */ - if (unlikely(len == EMBEDDED_NAME_MAX)) { - const size_t size = offsetof(struct filename, iname[1]); - kname = (char *)result; - - /* - * size is chosen that way we to guarantee that - * result->iname[0] is within the same object and that - * kname can't be equal to result->iname, no matter what. - */ - result = kzalloc(size, GFP_KERNEL); - if (unlikely(!result)) { - __putname(kname); - return ERR_PTR(-ENOMEM); - } - result->name = kname; - len = strncpy_from_user(kname, filename, PATH_MAX); - if (unlikely(len < 0)) { - __putname(kname); - kfree(result); - return ERR_PTR(len); - } - if (unlikely(len == PATH_MAX)) { - __putname(kname); - kfree(result); - return ERR_PTR(-ENAMETOOLONG); - } - } - - result->refcnt = 1; - /* The empty path is special. */ - if (unlikely(!len)) { - if (empty) - *empty = 1; - if (!(flags & LOOKUP_EMPTY)) { - putname(result); - return ERR_PTR(-ENOENT); - } - } - - result->uptr = filename; - result->aname = NULL; - audit_getname(result); - return result; -} - -struct filename * -getname(const char __user * filename) -{ - return getname_flags(filename, 0, NULL); -} - -struct filename * -getname_kernel(const char * filename) -{ - struct filename *result; - int len = strlen(filename) + 1; - - result = __getname(); - if (unlikely(!result)) - return ERR_PTR(-ENOMEM); - - if (len <= EMBEDDED_NAME_MAX) { - result->name = (char *)result->iname; - } else if (len <= PATH_MAX) { - struct filename *tmp; - - tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); - if (unlikely(!tmp)) { - __putname(result); - return ERR_PTR(-ENOMEM); - } - tmp->name = (char *)result; - result = tmp; - } else { - __putname(result); - return ERR_PTR(-ENAMETOOLONG); - } - memcpy((char *)result->name, filename, len); - result->uptr = NULL; - result->aname = NULL; - result->refcnt = 1; - audit_getname(result); - - return result; -} - -void putname(struct filename *name) -{ - BUG_ON(name->refcnt <= 0); - - if (--name->refcnt > 0) - return; - - if (name->name != name->iname) { - __putname(name->name); - kfree(name); - } else - __putname(name); -} - -static int check_acl(struct inode *inode, int mask) -{ -#ifdef CONFIG_FS_POSIX_ACL - struct posix_acl *acl; - - if (mask & MAY_NOT_BLOCK) { - acl = get_cached_acl_rcu(inode, ACL_TYPE_ACCESS); - if (!acl) - return -EAGAIN; - /* no ->get_acl() calls in RCU mode... */ - if (is_uncached_acl(acl)) - return -ECHILD; - return posix_acl_permission(inode, acl, mask & ~MAY_NOT_BLOCK); - } - - acl = get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl) { - int error = posix_acl_permission(inode, acl, mask); - posix_acl_release(acl); - return error; - } -#endif - - return -EAGAIN; -} - -/* - * This does the basic permission checking - */ -static int acl_permission_check(struct inode *inode, int mask) -{ - unsigned int mode = inode->i_mode; - - if (likely(uid_eq(current_fsuid(), inode->i_uid))) - mode >>= 6; - else { - if (IS_POSIXACL(inode) && (mode & S_IRWXG)) { - int error = check_acl(inode, mask); - if (error != -EAGAIN) - return error; - } - - if (in_group_p(inode->i_gid)) - mode >>= 3; - } - - /* - * If the DACs are ok we don't need any capability check. - */ - if ((mask & ~mode & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) - return 0; - return -EACCES; -} - -/** - * generic_permission - check for access rights on a Posix-like filesystem - * @inode: inode to check access rights for - * @mask: right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC, ...) - * - * Used to check for read/write/execute permissions on a file. - * We use "fsuid" for this, letting us set arbitrary permissions - * for filesystem access without changing the "normal" uids which - * are used for other things. - * - * generic_permission is rcu-walk aware. It returns -ECHILD in case an rcu-walk - * request cannot be satisfied (eg. requires blocking or too much complexity). - * It would then be called again in ref-walk mode. - */ -int generic_permission(struct inode *inode, int mask) -{ - int ret; - - /* - * Do the basic permission checks. - */ - ret = acl_permission_check(inode, mask); - if (ret != -EACCES) - return ret; - - if (S_ISDIR(inode->i_mode)) { - /* DACs are overridable for directories */ - if (capable_wrt_inode_uidgid(inode, CAP_DAC_OVERRIDE)) - return 0; - if (!(mask & MAY_WRITE)) - if (capable_wrt_inode_uidgid(inode, - CAP_DAC_READ_SEARCH)) - return 0; - return -EACCES; - } - /* - * Read/write DACs are always overridable. - * Executable DACs are overridable when there is - * at least one exec bit set. - */ - if (!(mask & MAY_EXEC) || (inode->i_mode & S_IXUGO)) - if (capable_wrt_inode_uidgid(inode, CAP_DAC_OVERRIDE)) - return 0; - - /* - * Searching includes executable on directories, else just read. - */ - mask &= MAY_READ | MAY_WRITE | MAY_EXEC; - if (mask == MAY_READ) - if (capable_wrt_inode_uidgid(inode, CAP_DAC_READ_SEARCH)) - return 0; - - return -EACCES; -} -EXPORT_SYMBOL(generic_permission); - -/* - * We _really_ want to just do "generic_permission()" without - * even looking at the inode->i_op values. So we keep a cache - * flag in inode->i_opflags, that says "this has not special - * permission function, use the fast case". - */ -static inline int do_inode_permission(struct inode *inode, int mask) -{ - if (unlikely(!(inode->i_opflags & IOP_FASTPERM))) { - if (likely(inode->i_op->permission)) - return inode->i_op->permission(inode, mask); - - /* This gets set once for the inode lifetime */ - spin_lock(&inode->i_lock); - inode->i_opflags |= IOP_FASTPERM; - spin_unlock(&inode->i_lock); - } - return generic_permission(inode, mask); -} - -/** - * __inode_permission - Check for access rights to a given inode - * @inode: Inode to check permission on - * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) - * - * Check for read/write/execute permissions on an inode. - * - * When checking for MAY_APPEND, MAY_WRITE must also be set in @mask. - * - * This does not check for a read-only file system. You probably want - * inode_permission(). - */ -int __inode_permission(struct inode *inode, int mask) -{ - int retval; - - if (unlikely(mask & MAY_WRITE)) { - /* - * Nobody gets write access to an immutable file. - */ - if (IS_IMMUTABLE(inode)) - return -EPERM; - - /* - * Updating mtime will likely cause i_uid and i_gid to be - * written back improperly if their true value is unknown - * to the vfs. - */ - if (HAS_UNMAPPED_ID(inode)) - return -EACCES; - } - - retval = do_inode_permission(inode, mask); - if (retval) - return retval; - - retval = devcgroup_inode_permission(inode, mask); - if (retval) - return retval; - - return security_inode_permission(inode, mask); -} -EXPORT_SYMBOL(__inode_permission); - -/** - * sb_permission - Check superblock-level permissions - * @sb: Superblock of inode to check permission on - * @inode: Inode to check permission on - * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) - * - * Separate out file-system wide checks from inode-specific permission checks. - */ -static int sb_permission(struct super_block *sb, struct inode *inode, int mask) -{ - if (unlikely(mask & MAY_WRITE)) { - umode_t mode = inode->i_mode; - - /* Nobody gets write access to a read-only fs. */ - if ((sb->s_flags & MS_RDONLY) && - (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) - return -EROFS; - } - return 0; -} - -/** - * inode_permission - Check for access rights to a given inode - * @inode: Inode to check permission on - * @mask: Right to check for (%MAY_READ, %MAY_WRITE, %MAY_EXEC) - * - * Check for read/write/execute permissions on an inode. We use fs[ug]id for - * this, letting us set arbitrary permissions for filesystem access without - * changing the "normal" UIDs which are used for other things. - * - * When checking for MAY_APPEND, MAY_WRITE must also be set in @mask. - */ -int inode_permission(struct inode *inode, int mask) -{ - int retval; - - retval = sb_permission(inode->i_sb, inode, mask); - if (retval) - return retval; - return __inode_permission(inode, mask); -} -EXPORT_SYMBOL(inode_permission); - -/** - * path_get - get a reference to a path - * @path: path to get the reference to - * - * Given a path increment the reference count to the dentry and the vfsmount. - */ -void path_get(const struct path *path) -{ - mntget(path->mnt); - dget(path->dentry); -} -EXPORT_SYMBOL(path_get); - -/** - * path_put - put a reference to a path - * @path: path to put the reference to - * - * Given a path decrement the reference count to the dentry and the vfsmount. - */ -void path_put(const struct path *path) -{ - dput(path->dentry); - mntput(path->mnt); -} -EXPORT_SYMBOL(path_put); - -#define EMBEDDED_LEVELS 2 -struct nameidata { - struct path path; - struct qstr last; - struct path root; - struct inode *inode; /* path.dentry.d_inode */ - unsigned int flags; - unsigned seq, m_seq; - int last_type; - unsigned depth; - int total_link_count; - struct saved { - struct path link; - struct delayed_call done; - const char *name; - unsigned seq; - } *stack, internal[EMBEDDED_LEVELS]; - struct filename *name; - struct nameidata *saved; - struct inode *link_inode; - unsigned root_seq; - int dfd; -}; - -static void set_nameidata(struct nameidata *p, int dfd, struct filename *name) -{ - struct nameidata *old = current->nameidata; - p->stack = p->internal; - p->dfd = dfd; - p->name = name; - p->total_link_count = old ? old->total_link_count : 0; - p->saved = old; - current->nameidata = p; -} - -static void restore_nameidata(void) -{ - struct nameidata *now = current->nameidata, *old = now->saved; - - current->nameidata = old; - if (old) - old->total_link_count = now->total_link_count; - if (now->stack != now->internal) - kfree(now->stack); -} - -static int __nd_alloc_stack(struct nameidata *nd) -{ - struct saved *p; - - if (nd->flags & LOOKUP_RCU) { - p= kmalloc(MAXSYMLINKS * sizeof(struct saved), - GFP_ATOMIC); - if (unlikely(!p)) - return -ECHILD; - } else { - p= kmalloc(MAXSYMLINKS * sizeof(struct saved), - GFP_KERNEL); - if (unlikely(!p)) - return -ENOMEM; - } - memcpy(p, nd->internal, sizeof(nd->internal)); - nd->stack = p; - return 0; -} - -/** - * path_connected - Verify that a path->dentry is below path->mnt.mnt_root - * @path: nameidate to verify - * - * Rename can sometimes move a file or directory outside of a bind - * mount, path_connected allows those cases to be detected. - */ -static bool path_connected(const struct path *path) -{ - struct vfsmount *mnt = path->mnt; - - /* Only bind mounts can have disconnected paths */ - if (mnt->mnt_root == mnt->mnt_sb->s_root) - return true; - - return is_subdir(path->dentry, mnt->mnt_root); -} - -static inline int nd_alloc_stack(struct nameidata *nd) -{ - if (likely(nd->depth != EMBEDDED_LEVELS)) - return 0; - if (likely(nd->stack != nd->internal)) - return 0; - return __nd_alloc_stack(nd); -} - -static void drop_links(struct nameidata *nd) -{ - int i = nd->depth; - while (i--) { - struct saved *last = nd->stack + i; - do_delayed_call(&last->done); - clear_delayed_call(&last->done); - } -} - -static void terminate_walk(struct nameidata *nd) -{ - drop_links(nd); - if (!(nd->flags & LOOKUP_RCU)) { - int i; - path_put(&nd->path); - for (i = 0; i < nd->depth; i++) - path_put(&nd->stack[i].link); - if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) { - path_put(&nd->root); - nd->root.mnt = NULL; - } - } else { - nd->flags &= ~LOOKUP_RCU; - if (!(nd->flags & LOOKUP_ROOT)) - nd->root.mnt = NULL; - rcu_read_unlock(); - } - nd->depth = 0; -} - -/* path_put is needed afterwards regardless of success or failure */ -static bool legitimize_path(struct nameidata *nd, - struct path *path, unsigned seq) -{ - int res = __legitimize_mnt(path->mnt, nd->m_seq); - if (unlikely(res)) { - if (res > 0) - path->mnt = NULL; - path->dentry = NULL; - return false; - } - if (unlikely(!lockref_get_not_dead(&path->dentry->d_lockref))) { - path->dentry = NULL; - return false; - } - return !read_seqcount_retry(&path->dentry->d_seq, seq); -} - -static bool legitimize_links(struct nameidata *nd) -{ - int i; - for (i = 0; i < nd->depth; i++) { - struct saved *last = nd->stack + i; - if (unlikely(!legitimize_path(nd, &last->link, last->seq))) { - drop_links(nd); - nd->depth = i + 1; - return false; - } - } - return true; -} - -/* - * Path walking has 2 modes, rcu-walk and ref-walk (see - * Documentation/filesystems/path-lookup.txt). In situations when we can't - * continue in RCU mode, we attempt to drop out of rcu-walk mode and grab - * normal reference counts on dentries and vfsmounts to transition to ref-walk - * mode. Refcounts are grabbed at the last known good point before rcu-walk - * got stuck, so ref-walk may continue from there. If this is not successful - * (eg. a seqcount has changed), then failure is returned and it's up to caller - * to restart the path walk from the beginning in ref-walk mode. - */ - -/** - * unlazy_walk - try to switch to ref-walk mode. - * @nd: nameidata pathwalk data - * @dentry: child of nd->path.dentry or NULL - * @seq: seq number to check dentry against - * Returns: 0 on success, -ECHILD on failure - * - * unlazy_walk attempts to legitimize the current nd->path, nd->root and dentry - * for ref-walk mode. @dentry must be a path found by a do_lookup call on - * @nd or NULL. Must be called from rcu-walk context. - * Nothing should touch nameidata between unlazy_walk() failure and - * terminate_walk(). - */ -static int unlazy_walk(struct nameidata *nd, struct dentry *dentry, unsigned seq) -{ - struct dentry *parent = nd->path.dentry; - - BUG_ON(!(nd->flags & LOOKUP_RCU)); - - nd->flags &= ~LOOKUP_RCU; - if (unlikely(!legitimize_links(nd))) - goto out2; - if (unlikely(!legitimize_mnt(nd->path.mnt, nd->m_seq))) - goto out2; - if (unlikely(!lockref_get_not_dead(&parent->d_lockref))) - goto out1; - - /* - * For a negative lookup, the lookup sequence point is the parents - * sequence point, and it only needs to revalidate the parent dentry. - * - * For a positive lookup, we need to move both the parent and the - * dentry from the RCU domain to be properly refcounted. And the - * sequence number in the dentry validates *both* dentry counters, - * since we checked the sequence number of the parent after we got - * the child sequence number. So we know the parent must still - * be valid if the child sequence number is still valid. - */ - if (!dentry) { - if (read_seqcount_retry(&parent->d_seq, nd->seq)) - goto out; - BUG_ON(nd->inode != parent->d_inode); - } else { - if (!lockref_get_not_dead(&dentry->d_lockref)) - goto out; - if (read_seqcount_retry(&dentry->d_seq, seq)) - goto drop_dentry; - } - - /* - * Sequence counts matched. Now make sure that the root is - * still valid and get it if required. - */ - if (nd->root.mnt && !(nd->flags & LOOKUP_ROOT)) { - if (unlikely(!legitimize_path(nd, &nd->root, nd->root_seq))) { - rcu_read_unlock(); - dput(dentry); - return -ECHILD; - } - } - - rcu_read_unlock(); - return 0; - -drop_dentry: - rcu_read_unlock(); - dput(dentry); - goto drop_root_mnt; -out2: - nd->path.mnt = NULL; -out1: - nd->path.dentry = NULL; -out: - rcu_read_unlock(); -drop_root_mnt: - if (!(nd->flags & LOOKUP_ROOT)) - nd->root.mnt = NULL; - return -ECHILD; -} - -static int unlazy_link(struct nameidata *nd, struct path *link, unsigned seq) -{ - if (unlikely(!legitimize_path(nd, link, seq))) { - drop_links(nd); - nd->depth = 0; - nd->flags &= ~LOOKUP_RCU; - nd->path.mnt = NULL; - nd->path.dentry = NULL; - if (!(nd->flags & LOOKUP_ROOT)) - nd->root.mnt = NULL; - rcu_read_unlock(); - } else if (likely(unlazy_walk(nd, NULL, 0)) == 0) { - return 0; - } - path_put(link); - return -ECHILD; -} - -static inline int d_revalidate(struct dentry *dentry, unsigned int flags) -{ - return dentry->d_op->d_revalidate(dentry, flags); -} - -/** - * complete_walk - successful completion of path walk - * @nd: pointer nameidata - * - * If we had been in RCU mode, drop out of it and legitimize nd->path. - * Revalidate the final result, unless we'd already done that during - * the path walk or the filesystem doesn't ask for it. Return 0 on - * success, -error on failure. In case of failure caller does not - * need to drop nd->path. - */ -static int complete_walk(struct nameidata *nd) -{ - struct dentry *dentry = nd->path.dentry; - int status; - - if (nd->flags & LOOKUP_RCU) { - if (!(nd->flags & LOOKUP_ROOT)) - nd->root.mnt = NULL; - if (unlikely(unlazy_walk(nd, NULL, 0))) - return -ECHILD; - } - - if (likely(!(nd->flags & LOOKUP_JUMPED))) - return 0; - - if (likely(!(dentry->d_flags & DCACHE_OP_WEAK_REVALIDATE))) - return 0; - - status = dentry->d_op->d_weak_revalidate(dentry, nd->flags); - if (status > 0) - return 0; - - if (!status) - status = -ESTALE; - - return status; -} - -static void set_root(struct nameidata *nd) -{ - struct fs_struct *fs = current->fs; - - if (nd->flags & LOOKUP_RCU) { - unsigned seq; - - do { - seq = read_seqcount_begin(&fs->seq); - nd->root = fs->root; - nd->root_seq = __read_seqcount_begin(&nd->root.dentry->d_seq); - } while (read_seqcount_retry(&fs->seq, seq)); - } else { - get_fs_root(fs, &nd->root); - } -} - -static void path_put_conditional(struct path *path, struct nameidata *nd) -{ - dput(path->dentry); - if (path->mnt != nd->path.mnt) - mntput(path->mnt); -} - -static inline void path_to_nameidata(const struct path *path, - struct nameidata *nd) -{ - if (!(nd->flags & LOOKUP_RCU)) { - dput(nd->path.dentry); - if (nd->path.mnt != path->mnt) - mntput(nd->path.mnt); - } - nd->path.mnt = path->mnt; - nd->path.dentry = path->dentry; -} - -static int nd_jump_root(struct nameidata *nd) -{ - if (nd->flags & LOOKUP_RCU) { - struct dentry *d; - nd->path = nd->root; - d = nd->path.dentry; - nd->inode = d->d_inode; - nd->seq = nd->root_seq; - if (unlikely(read_seqcount_retry(&d->d_seq, nd->seq))) - return -ECHILD; - } else { - path_put(&nd->path); - nd->path = nd->root; - path_get(&nd->path); - nd->inode = nd->path.dentry->d_inode; - } - nd->flags |= LOOKUP_JUMPED; - return 0; -} - -/* - * Helper to directly jump to a known parsed path from ->get_link, - * caller must have taken a reference to path beforehand. - */ -void nd_jump_link(struct path *path) -{ - struct nameidata *nd = current->nameidata; - path_put(&nd->path); - - nd->path = *path; - nd->inode = nd->path.dentry->d_inode; - nd->flags |= LOOKUP_JUMPED; -} - -static inline void put_link(struct nameidata *nd) -{ - struct saved *last = nd->stack + --nd->depth; - do_delayed_call(&last->done); - if (!(nd->flags & LOOKUP_RCU)) - path_put(&last->link); -} - -int sysctl_protected_symlinks __read_mostly = 0; -int sysctl_protected_hardlinks __read_mostly = 0; - -/** - * may_follow_link - Check symlink following for unsafe situations - * @nd: nameidata pathwalk data - * - * In the case of the sysctl_protected_symlinks sysctl being enabled, - * CAP_DAC_OVERRIDE needs to be specifically ignored if the symlink is - * in a sticky world-writable directory. This is to protect privileged - * processes from failing races against path names that may change out - * from under them by way of other users creating malicious symlinks. - * It will permit symlinks to be followed only when outside a sticky - * world-writable directory, or when the uid of the symlink and follower - * match, or when the directory owner matches the symlink's owner. - * - * Returns 0 if following the symlink is allowed, -ve on error. - */ -static inline int may_follow_link(struct nameidata *nd) -{ - const struct inode *inode; - const struct inode *parent; - kuid_t puid; - - if (!sysctl_protected_symlinks) - return 0; - - /* Allowed if owner and follower match. */ - inode = nd->link_inode; - if (uid_eq(current_cred()->fsuid, inode->i_uid)) - return 0; - - /* Allowed if parent directory not sticky and world-writable. */ - parent = nd->inode; - if ((parent->i_mode & (S_ISVTX|S_IWOTH)) != (S_ISVTX|S_IWOTH)) - return 0; - - /* Allowed if parent directory and link owner match. */ - puid = parent->i_uid; - if (uid_valid(puid) && uid_eq(puid, inode->i_uid)) - return 0; - - if (nd->flags & LOOKUP_RCU) - return -ECHILD; - - audit_log_link_denied("follow_link", &nd->stack[0].link); - return -EACCES; -} - -/** - * safe_hardlink_source - Check for safe hardlink conditions - * @inode: the source inode to hardlink from - * - * Return false if at least one of the following conditions: - * - inode is not a regular file - * - inode is setuid - * - inode is setgid and group-exec - * - access failure for read and write - * - * Otherwise returns true. - */ -static bool safe_hardlink_source(struct inode *inode) -{ - umode_t mode = inode->i_mode; - - /* Special files should not get pinned to the filesystem. */ - if (!S_ISREG(mode)) - return false; - - /* Setuid files should not get pinned to the filesystem. */ - if (mode & S_ISUID) - return false; - - /* Executable setgid files should not get pinned to the filesystem. */ - if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) - return false; - - /* Hardlinking to unreadable or unwritable sources is dangerous. */ - if (inode_permission(inode, MAY_READ | MAY_WRITE)) - return false; - - return true; -} - -/** - * may_linkat - Check permissions for creating a hardlink - * @link: the source to hardlink from - * - * Block hardlink when all of: - * - sysctl_protected_hardlinks enabled - * - fsuid does not match inode - * - hardlink source is unsafe (see safe_hardlink_source() above) - * - not CAP_FOWNER in a namespace with the inode owner uid mapped - * - * Returns 0 if successful, -ve on error. - */ -static int may_linkat(struct path *link) -{ - struct inode *inode; - - if (!sysctl_protected_hardlinks) - return 0; - - inode = link->dentry->d_inode; - - /* Source inode owner (or CAP_FOWNER) can hardlink all they like, - * otherwise, it must be a safe source. - */ - if (inode_owner_or_capable(inode) || safe_hardlink_source(inode)) - return 0; - - audit_log_link_denied("linkat", link); - return -EPERM; -} - -static __always_inline -const char *get_link(struct nameidata *nd) -{ - struct saved *last = nd->stack + nd->depth - 1; - struct dentry *dentry = last->link.dentry; - struct inode *inode = nd->link_inode; - int error; - const char *res; - - if (!(nd->flags & LOOKUP_RCU)) { - touch_atime(&last->link); - cond_resched(); - } else if (atime_needs_update_rcu(&last->link, inode)) { - if (unlikely(unlazy_walk(nd, NULL, 0))) - return ERR_PTR(-ECHILD); - touch_atime(&last->link); - } - - error = security_inode_follow_link(dentry, inode, - nd->flags & LOOKUP_RCU); - if (unlikely(error)) - return ERR_PTR(error); - - nd->last_type = LAST_BIND; - res = inode->i_link; - if (!res) { - const char * (*get)(struct dentry *, struct inode *, - struct delayed_call *); - get = inode->i_op->get_link; - if (nd->flags & LOOKUP_RCU) { - res = get(NULL, inode, &last->done); - if (res == ERR_PTR(-ECHILD)) { - if (unlikely(unlazy_walk(nd, NULL, 0))) - return ERR_PTR(-ECHILD); - res = get(dentry, inode, &last->done); - } - } else { - res = get(dentry, inode, &last->done); - } - if (IS_ERR_OR_NULL(res)) - return res; - } - if (*res == '/') { - if (!nd->root.mnt) - set_root(nd); - if (unlikely(nd_jump_root(nd))) - return ERR_PTR(-ECHILD); - while (unlikely(*++res == '/')) - ; - } - if (!*res) - res = NULL; - return res; -} - -/* - * follow_up - Find the mountpoint of path's vfsmount - * - * Given a path, find the mountpoint of its source file system. - * Replace @path with the path of the mountpoint in the parent mount. - * Up is towards /. - * - * Return 1 if we went up a level and 0 if we were already at the - * root. - */ -int follow_up(struct path *path) -{ - struct mount *mnt = real_mount(path->mnt); - struct mount *parent; - struct dentry *mountpoint; - - read_seqlock_excl(&mount_lock); - parent = mnt->mnt_parent; - if (parent == mnt) { - read_sequnlock_excl(&mount_lock); - return 0; - } - mntget(&parent->mnt); - mountpoint = dget(mnt->mnt_mountpoint); - read_sequnlock_excl(&mount_lock); - dput(path->dentry); - path->dentry = mountpoint; - mntput(path->mnt); - path->mnt = &parent->mnt; - return 1; -} -EXPORT_SYMBOL(follow_up); - -/* - * Perform an automount - * - return -EISDIR to tell follow_managed() to stop and return the path we - * were called with. - */ -static int follow_automount(struct path *path, struct nameidata *nd, - bool *need_mntput) -{ - struct vfsmount *mnt; - const struct cred *old_cred; - int err; - - if (!path->dentry->d_op || !path->dentry->d_op->d_automount) - return -EREMOTE; - - /* We don't want to mount if someone's just doing a stat - - * unless they're stat'ing a directory and appended a '/' to - * the name. - * - * We do, however, want to mount if someone wants to open or - * create a file of any type under the mountpoint, wants to - * traverse through the mountpoint or wants to open the - * mounted directory. Also, autofs may mark negative dentries - * as being automount points. These will need the attentions - * of the daemon to instantiate them before they can be used. - */ - if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY | - LOOKUP_OPEN | LOOKUP_CREATE | LOOKUP_AUTOMOUNT)) && - path->dentry->d_inode) - return -EISDIR; - - if (path->dentry->d_sb->s_user_ns != &init_user_ns) - return -EACCES; - - nd->total_link_count++; - if (nd->total_link_count >= 40) - return -ELOOP; - - old_cred = override_creds(&init_cred); - mnt = path->dentry->d_op->d_automount(path); - revert_creds(old_cred); - if (IS_ERR(mnt)) { - /* - * The filesystem is allowed to return -EISDIR here to indicate - * it doesn't want to automount. For instance, autofs would do - * this so that its userspace daemon can mount on this dentry. - * - * However, we can only permit this if it's a terminal point in - * the path being looked up; if it wasn't then the remainder of - * the path is inaccessible and we should say so. - */ - if (PTR_ERR(mnt) == -EISDIR && (nd->flags & LOOKUP_PARENT)) - return -EREMOTE; - return PTR_ERR(mnt); - } - - if (!mnt) /* mount collision */ - return 0; - - if (!*need_mntput) { - /* lock_mount() may release path->mnt on error */ - mntget(path->mnt); - *need_mntput = true; - } - err = finish_automount(mnt, path); - - switch (err) { - case -EBUSY: - /* Someone else made a mount here whilst we were busy */ - return 0; - case 0: - path_put(path); - path->mnt = mnt; - path->dentry = dget(mnt->mnt_root); - return 0; - default: - return err; - } - -} - -/* - * Handle a dentry that is managed in some way. - * - Flagged for transit management (autofs) - * - Flagged as mountpoint - * - Flagged as automount point - * - * This may only be called in refwalk mode. - * - * Serialization is taken care of in namespace.c - */ -static int follow_managed(struct path *path, struct nameidata *nd) -{ - struct vfsmount *mnt = path->mnt; /* held by caller, must be left alone */ - unsigned managed; - bool need_mntput = false; - int ret = 0; - - /* Given that we're not holding a lock here, we retain the value in a - * local variable for each dentry as we look at it so that we don't see - * the components of that value change under us */ - while (managed = ACCESS_ONCE(path->dentry->d_flags), - managed &= DCACHE_MANAGED_DENTRY, - unlikely(managed != 0)) { - /* Allow the filesystem to manage the transit without i_mutex - * being held. */ - if (managed & DCACHE_MANAGE_TRANSIT) { - BUG_ON(!path->dentry->d_op); - BUG_ON(!path->dentry->d_op->d_manage); - ret = path->dentry->d_op->d_manage(path->dentry, false); - if (ret < 0) - break; - } - - /* Transit to a mounted filesystem. */ - if (managed & DCACHE_MOUNTED) { - struct vfsmount *mounted = lookup_mnt(path); - if (mounted) { - dput(path->dentry); - if (need_mntput) - mntput(path->mnt); - path->mnt = mounted; - path->dentry = dget(mounted->mnt_root); - need_mntput = true; - continue; - } - - /* Something is mounted on this dentry in another - * namespace and/or whatever was mounted there in this - * namespace got unmounted before lookup_mnt() could - * get it */ - } - - /* Handle an automount point */ - if (managed & DCACHE_NEED_AUTOMOUNT) { - ret = follow_automount(path, nd, &need_mntput); - if (ret < 0) - break; - continue; - } - - /* We didn't change the current path point */ - break; - } - - if (need_mntput && path->mnt == mnt) - mntput(path->mnt); - if (ret == -EISDIR || !ret) - ret = 1; - if (need_mntput) - nd->flags |= LOOKUP_JUMPED; - if (unlikely(ret < 0)) - path_put_conditional(path, nd); - return ret; -} - -int follow_down_one(struct path *path) -{ - struct vfsmount *mounted; - - mounted = lookup_mnt(path); - if (mounted) { - dput(path->dentry); - mntput(path->mnt); - path->mnt = mounted; - path->dentry = dget(mounted->mnt_root); - return 1; - } - return 0; -} -EXPORT_SYMBOL(follow_down_one); - -static inline int managed_dentry_rcu(struct dentry *dentry) -{ - return (dentry->d_flags & DCACHE_MANAGE_TRANSIT) ? - dentry->d_op->d_manage(dentry, true) : 0; -} - -/* - * Try to skip to top of mountpoint pile in rcuwalk mode. Fail if - * we meet a managed dentry that would need blocking. - */ -static bool __follow_mount_rcu(struct nameidata *nd, struct path *path, - struct inode **inode, unsigned *seqp) -{ - for (;;) { - struct mount *mounted; - /* - * Don't forget we might have a non-mountpoint managed dentry - * that wants to block transit. - */ - switch (managed_dentry_rcu(path->dentry)) { - case -ECHILD: - default: - return false; - case -EISDIR: - return true; - case 0: - break; - } - - if (!d_mountpoint(path->dentry)) - return !(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT); - - mounted = __lookup_mnt(path->mnt, path->dentry); - if (!mounted) - break; - path->mnt = &mounted->mnt; - path->dentry = mounted->mnt.mnt_root; - nd->flags |= LOOKUP_JUMPED; - *seqp = read_seqcount_begin(&path->dentry->d_seq); - /* - * Update the inode too. We don't need to re-check the - * dentry sequence number here after this d_inode read, - * because a mount-point is always pinned. - */ - *inode = path->dentry->d_inode; - } - return !read_seqretry(&mount_lock, nd->m_seq) && - !(path->dentry->d_flags & DCACHE_NEED_AUTOMOUNT); -} - -static int follow_dotdot_rcu(struct nameidata *nd) -{ - struct inode *inode = nd->inode; - - while (1) { - if (path_equal(&nd->path, &nd->root)) - break; - if (nd->path.dentry != nd->path.mnt->mnt_root) { - struct dentry *old = nd->path.dentry; - struct dentry *parent = old->d_parent; - unsigned seq; - - inode = parent->d_inode; - seq = read_seqcount_begin(&parent->d_seq); - if (unlikely(read_seqcount_retry(&old->d_seq, nd->seq))) - return -ECHILD; - nd->path.dentry = parent; - nd->seq = seq; - if (unlikely(!path_connected(&nd->path))) - return -ENOENT; - break; - } else { - struct mount *mnt = real_mount(nd->path.mnt); - struct mount *mparent = mnt->mnt_parent; - struct dentry *mountpoint = mnt->mnt_mountpoint; - struct inode *inode2 = mountpoint->d_inode; - unsigned seq = read_seqcount_begin(&mountpoint->d_seq); - if (unlikely(read_seqretry(&mount_lock, nd->m_seq))) - return -ECHILD; - if (&mparent->mnt == nd->path.mnt) - break; - /* we know that mountpoint was pinned */ - nd->path.dentry = mountpoint; - nd->path.mnt = &mparent->mnt; - inode = inode2; - nd->seq = seq; - } - } - while (unlikely(d_mountpoint(nd->path.dentry))) { - struct mount *mounted; - mounted = __lookup_mnt(nd->path.mnt, nd->path.dentry); - if (unlikely(read_seqretry(&mount_lock, nd->m_seq))) - return -ECHILD; - if (!mounted) - break; - nd->path.mnt = &mounted->mnt; - nd->path.dentry = mounted->mnt.mnt_root; - inode = nd->path.dentry->d_inode; - nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); - } - nd->inode = inode; - return 0; -} - -/* - * Follow down to the covering mount currently visible to userspace. At each - * point, the filesystem owning that dentry may be queried as to whether the - * caller is permitted to proceed or not. - */ -int follow_down(struct path *path) -{ - unsigned managed; - int ret; - - while (managed = ACCESS_ONCE(path->dentry->d_flags), - unlikely(managed & DCACHE_MANAGED_DENTRY)) { - /* Allow the filesystem to manage the transit without i_mutex - * being held. - * - * We indicate to the filesystem if someone is trying to mount - * something here. This gives autofs the chance to deny anyone - * other than its daemon the right to mount on its - * superstructure. - * - * The filesystem may sleep at this point. - */ - if (managed & DCACHE_MANAGE_TRANSIT) { - BUG_ON(!path->dentry->d_op); - BUG_ON(!path->dentry->d_op->d_manage); - ret = path->dentry->d_op->d_manage( - path->dentry, false); - if (ret < 0) - return ret == -EISDIR ? 0 : ret; - } - - /* Transit to a mounted filesystem. */ - if (managed & DCACHE_MOUNTED) { - struct vfsmount *mounted = lookup_mnt(path); - if (!mounted) - break; - dput(path->dentry); - mntput(path->mnt); - path->mnt = mounted; - path->dentry = dget(mounted->mnt_root); - continue; - } - - /* Don't handle automount points here */ - break; - } - return 0; -} -EXPORT_SYMBOL(follow_down); - -/* - * Skip to top of mountpoint pile in refwalk mode for follow_dotdot() - */ -static void follow_mount(struct path *path) -{ - while (d_mountpoint(path->dentry)) { - struct vfsmount *mounted = lookup_mnt(path); - if (!mounted) - break; - dput(path->dentry); - mntput(path->mnt); - path->mnt = mounted; - path->dentry = dget(mounted->mnt_root); - } -} - -static int path_parent_directory(struct path *path) -{ - struct dentry *old = path->dentry; - /* rare case of legitimate dget_parent()... */ - path->dentry = dget_parent(path->dentry); - dput(old); - if (unlikely(!path_connected(path))) - return -ENOENT; - return 0; -} - -static int follow_dotdot(struct nameidata *nd) -{ - while(1) { - if (nd->path.dentry == nd->root.dentry && - nd->path.mnt == nd->root.mnt) { - break; - } - if (nd->path.dentry != nd->path.mnt->mnt_root) { - int ret = path_parent_directory(&nd->path); - if (ret) - return ret; - break; - } - if (!follow_up(&nd->path)) - break; - } - follow_mount(&nd->path); - nd->inode = nd->path.dentry->d_inode; - return 0; -} - -/* - * This looks up the name in dcache and possibly revalidates the found dentry. - * NULL is returned if the dentry does not exist in the cache. - */ -static struct dentry *lookup_dcache(const struct qstr *name, - struct dentry *dir, - unsigned int flags) -{ - struct dentry *dentry; - int error; - - dentry = d_lookup(dir, name); - if (dentry) { - if (dentry->d_flags & DCACHE_OP_REVALIDATE) { - error = d_revalidate(dentry, flags); - if (unlikely(error <= 0)) { - if (!error) - d_invalidate(dentry); - dput(dentry); - return ERR_PTR(error); - } - } - } - return dentry; -} - -/* - * Call i_op->lookup on the dentry. The dentry must be negative and - * unhashed. - * - * dir->d_inode->i_mutex must be held - */ -static struct dentry *lookup_real(struct inode *dir, struct dentry *dentry, - unsigned int flags) -{ - struct dentry *old; - - /* Don't create child dentry for a dead directory. */ - if (unlikely(IS_DEADDIR(dir))) { - dput(dentry); - return ERR_PTR(-ENOENT); - } - - old = dir->i_op->lookup(dir, dentry, flags); - if (unlikely(old)) { - dput(dentry); - dentry = old; - } - return dentry; -} - -static struct dentry *__lookup_hash(const struct qstr *name, - struct dentry *base, unsigned int flags) -{ - struct dentry *dentry = lookup_dcache(name, base, flags); - - if (dentry) - return dentry; - - dentry = d_alloc(base, name); - if (unlikely(!dentry)) - return ERR_PTR(-ENOMEM); - - return lookup_real(base->d_inode, dentry, flags); -} - -static int lookup_fast(struct nameidata *nd, - struct path *path, struct inode **inode, - unsigned *seqp) -{ - struct vfsmount *mnt = nd->path.mnt; - struct dentry *dentry, *parent = nd->path.dentry; - int status = 1; - int err; - - /* - * Rename seqlock is not required here because in the off chance - * of a false negative due to a concurrent rename, the caller is - * going to fall back to non-racy lookup. - */ - if (nd->flags & LOOKUP_RCU) { - unsigned seq; - bool negative; - dentry = __d_lookup_rcu(parent, &nd->last, &seq); - if (unlikely(!dentry)) { - if (unlazy_walk(nd, NULL, 0)) - return -ECHILD; - return 0; - } - - /* - * This sequence count validates that the inode matches - * the dentry name information from lookup. - */ - *inode = d_backing_inode(dentry); - negative = d_is_negative(dentry); - if (unlikely(read_seqcount_retry(&dentry->d_seq, seq))) - return -ECHILD; - - /* - * This sequence count validates that the parent had no - * changes while we did the lookup of the dentry above. - * - * The memory barrier in read_seqcount_begin of child is - * enough, we can use __read_seqcount_retry here. - */ - if (unlikely(__read_seqcount_retry(&parent->d_seq, nd->seq))) - return -ECHILD; - - *seqp = seq; - if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) - status = d_revalidate(dentry, nd->flags); - if (unlikely(status <= 0)) { - if (unlazy_walk(nd, dentry, seq)) - return -ECHILD; - if (status == -ECHILD) - status = d_revalidate(dentry, nd->flags); - } else { - /* - * Note: do negative dentry check after revalidation in - * case that drops it. - */ - if (unlikely(negative)) - return -ENOENT; - path->mnt = mnt; - path->dentry = dentry; - if (likely(__follow_mount_rcu(nd, path, inode, seqp))) - return 1; - if (unlazy_walk(nd, dentry, seq)) - return -ECHILD; - } - } else { - dentry = __d_lookup(parent, &nd->last); - if (unlikely(!dentry)) - return 0; - if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE)) - status = d_revalidate(dentry, nd->flags); - } - if (unlikely(status <= 0)) { - if (!status) - d_invalidate(dentry); - dput(dentry); - return status; - } - if (unlikely(d_is_negative(dentry))) { - dput(dentry); - return -ENOENT; - } - - path->mnt = mnt; - path->dentry = dentry; - err = follow_managed(path, nd); - if (likely(err > 0)) - *inode = d_backing_inode(path->dentry); - return err; -} - -/* Fast lookup failed, do it the slow way */ -static struct dentry *lookup_slow(const struct qstr *name, - struct dentry *dir, - unsigned int flags) -{ - struct dentry *dentry = ERR_PTR(-ENOENT), *old; - struct inode *inode = dir->d_inode; - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); - - inode_lock_shared(inode); - /* Don't go there if it's already dead */ - if (unlikely(IS_DEADDIR(inode))) - goto out; -again: - dentry = d_alloc_parallel(dir, name, &wq); - if (IS_ERR(dentry)) - goto out; - if (unlikely(!d_in_lookup(dentry))) { - if ((dentry->d_flags & DCACHE_OP_REVALIDATE) && - !(flags & LOOKUP_NO_REVAL)) { - int error = d_revalidate(dentry, flags); - if (unlikely(error <= 0)) { - if (!error) { - d_invalidate(dentry); - dput(dentry); - goto again; - } - dput(dentry); - dentry = ERR_PTR(error); - } - } - } else { - old = inode->i_op->lookup(inode, dentry, flags); - d_lookup_done(dentry); - if (unlikely(old)) { - dput(dentry); - dentry = old; - } - } -out: - inode_unlock_shared(inode); - return dentry; -} - -static inline int may_lookup(struct nameidata *nd) -{ - if (nd->flags & LOOKUP_RCU) { - int err = inode_permission(nd->inode, MAY_EXEC|MAY_NOT_BLOCK); - if (err != -ECHILD) - return err; - if (unlazy_walk(nd, NULL, 0)) - return -ECHILD; - } - return inode_permission(nd->inode, MAY_EXEC); -} - -static inline int handle_dots(struct nameidata *nd, int type) -{ - if (type == LAST_DOTDOT) { - if (!nd->root.mnt) - set_root(nd); - if (nd->flags & LOOKUP_RCU) { - return follow_dotdot_rcu(nd); - } else - return follow_dotdot(nd); - } - return 0; -} - -static int pick_link(struct nameidata *nd, struct path *link, - struct inode *inode, unsigned seq) -{ - int error; - struct saved *last; - if (unlikely(nd->total_link_count++ >= MAXSYMLINKS)) { - path_to_nameidata(link, nd); - return -ELOOP; - } - if (!(nd->flags & LOOKUP_RCU)) { - if (link->mnt == nd->path.mnt) - mntget(link->mnt); - } - error = nd_alloc_stack(nd); - if (unlikely(error)) { - if (error == -ECHILD) { - if (unlikely(unlazy_link(nd, link, seq))) - return -ECHILD; - error = nd_alloc_stack(nd); - } - if (error) { - path_put(link); - return error; - } - } - - last = nd->stack + nd->depth++; - last->link = *link; - clear_delayed_call(&last->done); - nd->link_inode = inode; - last->seq = seq; - return 1; -} - -/* - * Do we need to follow links? We _really_ want to be able - * to do this check without having to look at inode->i_op, - * so we keep a cache of "no, this doesn't need follow_link" - * for the common case. - */ -static inline int should_follow_link(struct nameidata *nd, struct path *link, - int follow, - struct inode *inode, unsigned seq) -{ - if (likely(!d_is_symlink(link->dentry))) - return 0; - if (!follow) - return 0; - /* make sure that d_is_symlink above matches inode */ - if (nd->flags & LOOKUP_RCU) { - if (read_seqcount_retry(&link->dentry->d_seq, seq)) - return -ECHILD; - } - return pick_link(nd, link, inode, seq); -} - -enum {WALK_GET = 1, WALK_PUT = 2}; - -static int walk_component(struct nameidata *nd, int flags) -{ - struct path path; - struct inode *inode; - unsigned seq; - int err; - /* - * "." and ".." are special - ".." especially so because it has - * to be able to know about the current root directory and - * parent relationships. - */ - if (unlikely(nd->last_type != LAST_NORM)) { - err = handle_dots(nd, nd->last_type); - if (flags & WALK_PUT) - put_link(nd); - return err; - } - err = lookup_fast(nd, &path, &inode, &seq); - if (unlikely(err <= 0)) { - if (err < 0) - return err; - path.dentry = lookup_slow(&nd->last, nd->path.dentry, - nd->flags); - if (IS_ERR(path.dentry)) - return PTR_ERR(path.dentry); - - path.mnt = nd->path.mnt; - err = follow_managed(&path, nd); - if (unlikely(err < 0)) - return err; - - if (unlikely(d_is_negative(path.dentry))) { - path_to_nameidata(&path, nd); - return -ENOENT; - } - - seq = 0; /* we are already out of RCU mode */ - inode = d_backing_inode(path.dentry); - } - - if (flags & WALK_PUT) - put_link(nd); - err = should_follow_link(nd, &path, flags & WALK_GET, inode, seq); - if (unlikely(err)) - return err; - path_to_nameidata(&path, nd); - nd->inode = inode; - nd->seq = seq; - return 0; -} - -/* - * We can do the critical dentry name comparison and hashing - * operations one word at a time, but we are limited to: - * - * - Architectures with fast unaligned word accesses. We could - * do a "get_unaligned()" if this helps and is sufficiently - * fast. - * - * - non-CONFIG_DEBUG_PAGEALLOC configurations (so that we - * do not trap on the (extremely unlikely) case of a page - * crossing operation. - * - * - Furthermore, we need an efficient 64-bit compile for the - * 64-bit case in order to generate the "number of bytes in - * the final mask". Again, that could be replaced with a - * efficient population count instruction or similar. - */ -#ifdef CONFIG_DCACHE_WORD_ACCESS - -#include - -#ifdef HASH_MIX - -/* Architecture provides HASH_MIX and fold_hash() in */ - -#elif defined(CONFIG_64BIT) -/* - * Register pressure in the mixing function is an issue, particularly - * on 32-bit x86, but almost any function requires one state value and - * one temporary. Instead, use a function designed for two state values - * and no temporaries. - * - * This function cannot create a collision in only two iterations, so - * we have two iterations to achieve avalanche. In those two iterations, - * we have six layers of mixing, which is enough to spread one bit's - * influence out to 2^6 = 64 state bits. - * - * Rotate constants are scored by considering either 64 one-bit input - * deltas or 64*63/2 = 2016 two-bit input deltas, and finding the - * probability of that delta causing a change to each of the 128 output - * bits, using a sample of random initial states. - * - * The Shannon entropy of the computed probabilities is then summed - * to produce a score. Ideally, any input change has a 50% chance of - * toggling any given output bit. - * - * Mixing scores (in bits) for (12,45): - * Input delta: 1-bit 2-bit - * 1 round: 713.3 42542.6 - * 2 rounds: 2753.7 140389.8 - * 3 rounds: 5954.1 233458.2 - * 4 rounds: 7862.6 256672.2 - * Perfect: 8192 258048 - * (64*128) (64*63/2 * 128) - */ -#define HASH_MIX(x, y, a) \ - ( x ^= (a), \ - y ^= x, x = rol64(x,12),\ - x += y, y = rol64(y,45),\ - y *= 9 ) - -/* - * Fold two longs into one 32-bit hash value. This must be fast, but - * latency isn't quite as critical, as there is a fair bit of additional - * work done before the hash value is used. - */ -static inline unsigned int fold_hash(unsigned long x, unsigned long y) -{ - y ^= x * GOLDEN_RATIO_64; - y *= GOLDEN_RATIO_64; - return y >> 32; -} - -#else /* 32-bit case */ - -/* - * Mixing scores (in bits) for (7,20): - * Input delta: 1-bit 2-bit - * 1 round: 330.3 9201.6 - * 2 rounds: 1246.4 25475.4 - * 3 rounds: 1907.1 31295.1 - * 4 rounds: 2042.3 31718.6 - * Perfect: 2048 31744 - * (32*64) (32*31/2 * 64) - */ -#define HASH_MIX(x, y, a) \ - ( x ^= (a), \ - y ^= x, x = rol32(x, 7),\ - x += y, y = rol32(y,20),\ - y *= 9 ) - -static inline unsigned int fold_hash(unsigned long x, unsigned long y) -{ - /* Use arch-optimized multiply if one exists */ - return __hash_32(y ^ __hash_32(x)); -} - -#endif - -/* - * Return the hash of a string of known length. This is carfully - * designed to match hash_name(), which is the more critical function. - * In particular, we must end by hashing a final word containing 0..7 - * payload bytes, to match the way that hash_name() iterates until it - * finds the delimiter after the name. - */ -unsigned int full_name_hash(const void *salt, const char *name, unsigned int len) -{ - unsigned long a, x = 0, y = (unsigned long)salt; - - for (;;) { - if (!len) - goto done; - a = load_unaligned_zeropad(name); - if (len < sizeof(unsigned long)) - break; - HASH_MIX(x, y, a); - name += sizeof(unsigned long); - len -= sizeof(unsigned long); - } - x ^= a & bytemask_from_count(len); -done: - return fold_hash(x, y); -} -EXPORT_SYMBOL(full_name_hash); - -/* Return the "hash_len" (hash and length) of a null-terminated string */ -u64 hashlen_string(const void *salt, const char *name) -{ - unsigned long a = 0, x = 0, y = (unsigned long)salt; - unsigned long adata, mask, len; - const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS; - - len = 0; - goto inside; - - do { - HASH_MIX(x, y, a); - len += sizeof(unsigned long); -inside: - a = load_unaligned_zeropad(name+len); - } while (!has_zero(a, &adata, &constants)); - - adata = prep_zero_mask(a, adata, &constants); - mask = create_zero_mask(adata); - x ^= a & zero_bytemask(mask); - - return hashlen_create(fold_hash(x, y), len + find_zero(mask)); -} -EXPORT_SYMBOL(hashlen_string); - -/* - * Calculate the length and hash of the path component, and - * return the "hash_len" as the result. - */ -static inline u64 hash_name(const void *salt, const char *name) -{ - unsigned long a = 0, b, x = 0, y = (unsigned long)salt; - unsigned long adata, bdata, mask, len; - const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS; - - len = 0; - goto inside; - - do { - HASH_MIX(x, y, a); - len += sizeof(unsigned long); -inside: - a = load_unaligned_zeropad(name+len); - b = a ^ REPEAT_BYTE('/'); - } while (!(has_zero(a, &adata, &constants) | has_zero(b, &bdata, &constants))); - - adata = prep_zero_mask(a, adata, &constants); - bdata = prep_zero_mask(b, bdata, &constants); - mask = create_zero_mask(adata | bdata); - x ^= a & zero_bytemask(mask); - - return hashlen_create(fold_hash(x, y), len + find_zero(mask)); -} - -#else /* !CONFIG_DCACHE_WORD_ACCESS: Slow, byte-at-a-time version */ - -/* Return the hash of a string of known length */ -unsigned int full_name_hash(const void *salt, const char *name, unsigned int len) -{ - unsigned long hash = init_name_hash(salt); - while (len--) - hash = partial_name_hash((unsigned char)*name++, hash); - return end_name_hash(hash); -} -EXPORT_SYMBOL(full_name_hash); - -/* Return the "hash_len" (hash and length) of a null-terminated string */ -u64 hashlen_string(const void *salt, const char *name) -{ - unsigned long hash = init_name_hash(salt); - unsigned long len = 0, c; - - c = (unsigned char)*name; - while (c) { - len++; - hash = partial_name_hash(c, hash); - c = (unsigned char)name[len]; - } - return hashlen_create(end_name_hash(hash), len); -} -EXPORT_SYMBOL(hashlen_string); - -/* - * We know there's a real path component here of at least - * one character. - */ -static inline u64 hash_name(const void *salt, const char *name) -{ - unsigned long hash = init_name_hash(salt); - unsigned long len = 0, c; - - c = (unsigned char)*name; - do { - len++; - hash = partial_name_hash(c, hash); - c = (unsigned char)name[len]; - } while (c && c != '/'); - return hashlen_create(end_name_hash(hash), len); -} - -#endif - -/* - * Name resolution. - * This is the basic name resolution function, turning a pathname into - * the final dentry. We expect 'base' to be positive and a directory. - * - * Returns 0 and nd will have valid dentry and mnt on success. - * Returns error and drops reference to input namei data on failure. - */ -static int link_path_walk(const char *name, struct nameidata *nd) -{ - int err; - - while (*name=='/') - name++; - if (!*name) - return 0; - - /* At this point we know we have a real path component. */ - for(;;) { - u64 hash_len; - int type; - - err = may_lookup(nd); - if (err) - return err; - - hash_len = hash_name(nd->path.dentry, name); - - type = LAST_NORM; - if (name[0] == '.') switch (hashlen_len(hash_len)) { - case 2: - if (name[1] == '.') { - type = LAST_DOTDOT; - nd->flags |= LOOKUP_JUMPED; - } - break; - case 1: - type = LAST_DOT; - } - if (likely(type == LAST_NORM)) { - struct dentry *parent = nd->path.dentry; - nd->flags &= ~LOOKUP_JUMPED; - if (unlikely(parent->d_flags & DCACHE_OP_HASH)) { - struct qstr this = { { .hash_len = hash_len }, .name = name }; - err = parent->d_op->d_hash(parent, &this); - if (err < 0) - return err; - hash_len = this.hash_len; - name = this.name; - } - } - - nd->last.hash_len = hash_len; - nd->last.name = name; - nd->last_type = type; - - name += hashlen_len(hash_len); - if (!*name) - goto OK; - /* - * If it wasn't NUL, we know it was '/'. Skip that - * slash, and continue until no more slashes. - */ - do { - name++; - } while (unlikely(*name == '/')); - if (unlikely(!*name)) { -OK: - /* pathname body, done */ - if (!nd->depth) - return 0; - name = nd->stack[nd->depth - 1].name; - /* trailing symlink, done */ - if (!name) - return 0; - /* last component of nested symlink */ - err = walk_component(nd, WALK_GET | WALK_PUT); - } else { - err = walk_component(nd, WALK_GET); - } - if (err < 0) - return err; - - if (err) { - const char *s = get_link(nd); - - if (IS_ERR(s)) - return PTR_ERR(s); - err = 0; - if (unlikely(!s)) { - /* jumped */ - put_link(nd); - } else { - nd->stack[nd->depth - 1].name = name; - name = s; - continue; - } - } - if (unlikely(!d_can_lookup(nd->path.dentry))) { - if (nd->flags & LOOKUP_RCU) { - if (unlazy_walk(nd, NULL, 0)) - return -ECHILD; - } - return -ENOTDIR; - } - } -} - -static const char *path_init(struct nameidata *nd, unsigned flags) -{ - int retval = 0; - const char *s = nd->name->name; - - nd->last_type = LAST_ROOT; /* if there are only slashes... */ - nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT; - nd->depth = 0; - if (flags & LOOKUP_ROOT) { - struct dentry *root = nd->root.dentry; - struct inode *inode = root->d_inode; - if (*s) { - if (!d_can_lookup(root)) - return ERR_PTR(-ENOTDIR); - retval = inode_permission(inode, MAY_EXEC); - if (retval) - return ERR_PTR(retval); - } - nd->path = nd->root; - nd->inode = inode; - if (flags & LOOKUP_RCU) { - rcu_read_lock(); - nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); - nd->root_seq = nd->seq; - nd->m_seq = read_seqbegin(&mount_lock); - } else { - path_get(&nd->path); - } - return s; - } - - nd->root.mnt = NULL; - nd->path.mnt = NULL; - nd->path.dentry = NULL; - - nd->m_seq = read_seqbegin(&mount_lock); - if (*s == '/') { - if (flags & LOOKUP_RCU) - rcu_read_lock(); - set_root(nd); - if (likely(!nd_jump_root(nd))) - return s; - nd->root.mnt = NULL; - rcu_read_unlock(); - return ERR_PTR(-ECHILD); - } else if (nd->dfd == AT_FDCWD) { - if (flags & LOOKUP_RCU) { - struct fs_struct *fs = current->fs; - unsigned seq; - - rcu_read_lock(); - - do { - seq = read_seqcount_begin(&fs->seq); - nd->path = fs->pwd; - nd->inode = nd->path.dentry->d_inode; - nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq); - } while (read_seqcount_retry(&fs->seq, seq)); - } else { - get_fs_pwd(current->fs, &nd->path); - nd->inode = nd->path.dentry->d_inode; - } - return s; - } else { - /* Caller must check execute permissions on the starting path component */ - struct fd f = fdget_raw(nd->dfd); - struct dentry *dentry; - - if (!f.file) - return ERR_PTR(-EBADF); - - dentry = f.file->f_path.dentry; - - if (*s) { - if (!d_can_lookup(dentry)) { - fdput(f); - return ERR_PTR(-ENOTDIR); - } - } - - nd->path = f.file->f_path; - if (flags & LOOKUP_RCU) { - rcu_read_lock(); - nd->inode = nd->path.dentry->d_inode; - nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq); - } else { - path_get(&nd->path); - nd->inode = nd->path.dentry->d_inode; - } - fdput(f); - return s; - } -} - -static const char *trailing_symlink(struct nameidata *nd) -{ - const char *s; - int error = may_follow_link(nd); - if (unlikely(error)) - return ERR_PTR(error); - nd->flags |= LOOKUP_PARENT; - nd->stack[0].name = NULL; - s = get_link(nd); - return s ? s : ""; -} - -static inline int lookup_last(struct nameidata *nd) -{ - if (nd->last_type == LAST_NORM && nd->last.name[nd->last.len]) - nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; - - nd->flags &= ~LOOKUP_PARENT; - return walk_component(nd, - nd->flags & LOOKUP_FOLLOW - ? nd->depth - ? WALK_PUT | WALK_GET - : WALK_GET - : 0); -} - -/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ -static int path_lookupat(struct nameidata *nd, unsigned flags, struct path *path) -{ - const char *s = path_init(nd, flags); - int err; - - if (IS_ERR(s)) - return PTR_ERR(s); - while (!(err = link_path_walk(s, nd)) - && ((err = lookup_last(nd)) > 0)) { - s = trailing_symlink(nd); - if (IS_ERR(s)) { - err = PTR_ERR(s); - break; - } - } - if (!err) - err = complete_walk(nd); - - if (!err && nd->flags & LOOKUP_DIRECTORY) - if (!d_can_lookup(nd->path.dentry)) - err = -ENOTDIR; - if (!err) { - *path = nd->path; - nd->path.mnt = NULL; - nd->path.dentry = NULL; - } - terminate_walk(nd); - return err; -} - -static int filename_lookup(int dfd, struct filename *name, unsigned flags, - struct path *path, struct path *root) -{ - int retval; - struct nameidata nd; - if (IS_ERR(name)) - return PTR_ERR(name); - if (unlikely(root)) { - nd.root = *root; - flags |= LOOKUP_ROOT; - } - set_nameidata(&nd, dfd, name); - retval = path_lookupat(&nd, flags | LOOKUP_RCU, path); - if (unlikely(retval == -ECHILD)) - retval = path_lookupat(&nd, flags, path); - if (unlikely(retval == -ESTALE)) - retval = path_lookupat(&nd, flags | LOOKUP_REVAL, path); - - if (likely(!retval)) - audit_inode(name, path->dentry, flags & LOOKUP_PARENT); - restore_nameidata(); - putname(name); - return retval; -} - -/* Returns 0 and nd will be valid on success; Retuns error, otherwise. */ -static int path_parentat(struct nameidata *nd, unsigned flags, - struct path *parent) -{ - const char *s = path_init(nd, flags); - int err; - if (IS_ERR(s)) - return PTR_ERR(s); - err = link_path_walk(s, nd); - if (!err) - err = complete_walk(nd); - if (!err) { - *parent = nd->path; - nd->path.mnt = NULL; - nd->path.dentry = NULL; - } - terminate_walk(nd); - return err; -} - -static struct filename *filename_parentat(int dfd, struct filename *name, - unsigned int flags, struct path *parent, - struct qstr *last, int *type) -{ - int retval; - struct nameidata nd; - - if (IS_ERR(name)) - return name; - set_nameidata(&nd, dfd, name); - retval = path_parentat(&nd, flags | LOOKUP_RCU, parent); - if (unlikely(retval == -ECHILD)) - retval = path_parentat(&nd, flags, parent); - if (unlikely(retval == -ESTALE)) - retval = path_parentat(&nd, flags | LOOKUP_REVAL, parent); - if (likely(!retval)) { - *last = nd.last; - *type = nd.last_type; - audit_inode(name, parent->dentry, LOOKUP_PARENT); - } else { - putname(name); - name = ERR_PTR(retval); - } - restore_nameidata(); - return name; -} - -/* does lookup, returns the object with parent locked */ -struct dentry *kern_path_locked(const char *name, struct path *path) -{ - struct filename *filename; - struct dentry *d; - struct qstr last; - int type; - - filename = filename_parentat(AT_FDCWD, getname_kernel(name), 0, path, - &last, &type); - if (IS_ERR(filename)) - return ERR_CAST(filename); - if (unlikely(type != LAST_NORM)) { - path_put(path); - putname(filename); - return ERR_PTR(-EINVAL); - } - inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT); - d = __lookup_hash(&last, path->dentry, 0); - if (IS_ERR(d)) { - inode_unlock(path->dentry->d_inode); - path_put(path); - } - putname(filename); - return d; -} - -int kern_path(const char *name, unsigned int flags, struct path *path) -{ - return filename_lookup(AT_FDCWD, getname_kernel(name), - flags, path, NULL); -} -EXPORT_SYMBOL(kern_path); - -/** - * vfs_path_lookup - lookup a file path relative to a dentry-vfsmount pair - * @dentry: pointer to dentry of the base directory - * @mnt: pointer to vfs mount of the base directory - * @name: pointer to file name - * @flags: lookup flags - * @path: pointer to struct path to fill - */ -int vfs_path_lookup(struct dentry *dentry, struct vfsmount *mnt, - const char *name, unsigned int flags, - struct path *path) -{ - struct path root = {.mnt = mnt, .dentry = dentry}; - /* the first argument of filename_lookup() is ignored with root */ - return filename_lookup(AT_FDCWD, getname_kernel(name), - flags , path, &root); -} -EXPORT_SYMBOL(vfs_path_lookup); - -/** - * lookup_one_len - filesystem helper to lookup single pathname component - * @name: pathname component to lookup - * @base: base directory to lookup from - * @len: maximum length @len should be interpreted to - * - * Note that this routine is purely a helper for filesystem usage and should - * not be called by generic code. - * - * The caller must hold base->i_mutex. - */ -struct dentry *lookup_one_len(const char *name, struct dentry *base, int len) -{ - struct qstr this; - unsigned int c; - int err; - - WARN_ON_ONCE(!inode_is_locked(base->d_inode)); - - this.name = name; - this.len = len; - this.hash = full_name_hash(base, name, len); - if (!len) - return ERR_PTR(-EACCES); - - if (unlikely(name[0] == '.')) { - if (len < 2 || (len == 2 && name[1] == '.')) - return ERR_PTR(-EACCES); - } - - while (len--) { - c = *(const unsigned char *)name++; - if (c == '/' || c == '\0') - return ERR_PTR(-EACCES); - } - /* - * See if the low-level filesystem might want - * to use its own hash.. - */ - if (base->d_flags & DCACHE_OP_HASH) { - int err = base->d_op->d_hash(base, &this); - if (err < 0) - return ERR_PTR(err); - } - - err = inode_permission(base->d_inode, MAY_EXEC); - if (err) - return ERR_PTR(err); - - return __lookup_hash(&this, base, 0); -} -EXPORT_SYMBOL(lookup_one_len); - -/** - * lookup_one_len_unlocked - filesystem helper to lookup single pathname component - * @name: pathname component to lookup - * @base: base directory to lookup from - * @len: maximum length @len should be interpreted to - * - * Note that this routine is purely a helper for filesystem usage and should - * not be called by generic code. - * - * Unlike lookup_one_len, it should be called without the parent - * i_mutex held, and will take the i_mutex itself if necessary. - */ -struct dentry *lookup_one_len_unlocked(const char *name, - struct dentry *base, int len) -{ - struct qstr this; - unsigned int c; - int err; - struct dentry *ret; - - this.name = name; - this.len = len; - this.hash = full_name_hash(base, name, len); - if (!len) - return ERR_PTR(-EACCES); - - if (unlikely(name[0] == '.')) { - if (len < 2 || (len == 2 && name[1] == '.')) - return ERR_PTR(-EACCES); - } - - while (len--) { - c = *(const unsigned char *)name++; - if (c == '/' || c == '\0') - return ERR_PTR(-EACCES); - } - /* - * See if the low-level filesystem might want - * to use its own hash.. - */ - if (base->d_flags & DCACHE_OP_HASH) { - int err = base->d_op->d_hash(base, &this); - if (err < 0) - return ERR_PTR(err); - } - - err = inode_permission(base->d_inode, MAY_EXEC); - if (err) - return ERR_PTR(err); - - ret = lookup_dcache(&this, base, 0); - if (!ret) - ret = lookup_slow(&this, base, 0); - return ret; -} -EXPORT_SYMBOL(lookup_one_len_unlocked); - -#ifdef CONFIG_UNIX98_PTYS -int path_pts(struct path *path) -{ - /* Find something mounted on "pts" in the same directory as - * the input path. - */ - struct dentry *child, *parent; - struct qstr this; - int ret; - - ret = path_parent_directory(path); - if (ret) - return ret; - - parent = path->dentry; - this.name = "pts"; - this.len = 3; - child = d_hash_and_lookup(parent, &this); - if (!child) - return -ENOENT; - - path->dentry = child; - dput(parent); - follow_mount(path); - return 0; -} -#endif - -int user_path_at_empty(int dfd, const char __user *name, unsigned flags, - struct path *path, int *empty) -{ - return filename_lookup(dfd, getname_flags(name, flags, empty), - flags, path, NULL); -} -EXPORT_SYMBOL(user_path_at_empty); - -/* - * NB: most callers don't do anything directly with the reference to the - * to struct filename, but the nd->last pointer points into the name string - * allocated by getname. So we must hold the reference to it until all - * path-walking is complete. - */ -static inline struct filename * -user_path_parent(int dfd, const char __user *path, - struct path *parent, - struct qstr *last, - int *type, - unsigned int flags) -{ - /* only LOOKUP_REVAL is allowed in extra flags */ - return filename_parentat(dfd, getname(path), flags & LOOKUP_REVAL, - parent, last, type); -} - -/** - * mountpoint_last - look up last component for umount - * @nd: pathwalk nameidata - currently pointing at parent directory of "last" - * @path: pointer to container for result - * - * This is a special lookup_last function just for umount. In this case, we - * need to resolve the path without doing any revalidation. - * - * The nameidata should be the result of doing a LOOKUP_PARENT pathwalk. Since - * mountpoints are always pinned in the dcache, their ancestors are too. Thus, - * in almost all cases, this lookup will be served out of the dcache. The only - * cases where it won't are if nd->last refers to a symlink or the path is - * bogus and it doesn't exist. - * - * Returns: - * -error: if there was an error during lookup. This includes -ENOENT if the - * lookup found a negative dentry. The nd->path reference will also be - * put in this case. - * - * 0: if we successfully resolved nd->path and found it to not to be a - * symlink that needs to be followed. "path" will also be populated. - * The nd->path reference will also be put. - * - * 1: if we successfully resolved nd->last and found it to be a symlink - * that needs to be followed. "path" will be populated with the path - * to the link, and nd->path will *not* be put. - */ -static int -mountpoint_last(struct nameidata *nd, struct path *path) -{ - int error = 0; - struct dentry *dentry; - struct dentry *dir = nd->path.dentry; - - /* If we're in rcuwalk, drop out of it to handle last component */ - if (nd->flags & LOOKUP_RCU) { - if (unlazy_walk(nd, NULL, 0)) - return -ECHILD; - } - - nd->flags &= ~LOOKUP_PARENT; - - if (unlikely(nd->last_type != LAST_NORM)) { - error = handle_dots(nd, nd->last_type); - if (error) - return error; - dentry = dget(nd->path.dentry); - } else { - dentry = d_lookup(dir, &nd->last); - if (!dentry) { - /* - * No cached dentry. Mounted dentries are pinned in the - * cache, so that means that this dentry is probably - * a symlink or the path doesn't actually point - * to a mounted dentry. - */ - dentry = lookup_slow(&nd->last, dir, - nd->flags | LOOKUP_NO_REVAL); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - } - } - if (d_is_negative(dentry)) { - dput(dentry); - return -ENOENT; - } - if (nd->depth) - put_link(nd); - path->dentry = dentry; - path->mnt = nd->path.mnt; - error = should_follow_link(nd, path, nd->flags & LOOKUP_FOLLOW, - d_backing_inode(dentry), 0); - if (unlikely(error)) - return error; - mntget(path->mnt); - follow_mount(path); - return 0; -} - -/** - * path_mountpoint - look up a path to be umounted - * @nd: lookup context - * @flags: lookup flags - * @path: pointer to container for result - * - * Look up the given name, but don't attempt to revalidate the last component. - * Returns 0 and "path" will be valid on success; Returns error otherwise. - */ -static int -path_mountpoint(struct nameidata *nd, unsigned flags, struct path *path) -{ - const char *s = path_init(nd, flags); - int err; - if (IS_ERR(s)) - return PTR_ERR(s); - while (!(err = link_path_walk(s, nd)) && - (err = mountpoint_last(nd, path)) > 0) { - s = trailing_symlink(nd); - if (IS_ERR(s)) { - err = PTR_ERR(s); - break; - } - } - terminate_walk(nd); - return err; -} - -static int -filename_mountpoint(int dfd, struct filename *name, struct path *path, - unsigned int flags) -{ - struct nameidata nd; - int error; - if (IS_ERR(name)) - return PTR_ERR(name); - set_nameidata(&nd, dfd, name); - error = path_mountpoint(&nd, flags | LOOKUP_RCU, path); - if (unlikely(error == -ECHILD)) - error = path_mountpoint(&nd, flags, path); - if (unlikely(error == -ESTALE)) - error = path_mountpoint(&nd, flags | LOOKUP_REVAL, path); - if (likely(!error)) - audit_inode(name, path->dentry, 0); - restore_nameidata(); - putname(name); - return error; -} - -/** - * user_path_mountpoint_at - lookup a path from userland in order to umount it - * @dfd: directory file descriptor - * @name: pathname from userland - * @flags: lookup flags - * @path: pointer to container to hold result - * - * A umount is a special case for path walking. We're not actually interested - * in the inode in this situation, and ESTALE errors can be a problem. We - * simply want track down the dentry and vfsmount attached at the mountpoint - * and avoid revalidating the last component. - * - * Returns 0 and populates "path" on success. - */ -int -user_path_mountpoint_at(int dfd, const char __user *name, unsigned int flags, - struct path *path) -{ - return filename_mountpoint(dfd, getname(name), path, flags); -} - -int -kern_path_mountpoint(int dfd, const char *name, struct path *path, - unsigned int flags) -{ - return filename_mountpoint(dfd, getname_kernel(name), path, flags); -} -EXPORT_SYMBOL(kern_path_mountpoint); - -int __check_sticky(struct inode *dir, struct inode *inode) -{ - kuid_t fsuid = current_fsuid(); - - if (uid_eq(inode->i_uid, fsuid)) - return 0; - if (uid_eq(dir->i_uid, fsuid)) - return 0; - return !capable_wrt_inode_uidgid(inode, CAP_FOWNER); -} -EXPORT_SYMBOL(__check_sticky); - -/* - * Check whether we can remove a link victim from directory dir, check - * whether the type of victim is right. - * 1. We can't do it if dir is read-only (done in permission()) - * 2. We should have write and exec permissions on dir - * 3. We can't remove anything from append-only dir - * 4. We can't do anything with immutable dir (done in permission()) - * 5. If the sticky bit on dir is set we should either - * a. be owner of dir, or - * b. be owner of victim, or - * c. have CAP_FOWNER capability - * 6. If the victim is append-only or immutable we can't do antyhing with - * links pointing to it. - * 7. If the victim has an unknown uid or gid we can't change the inode. - * 8. If we were asked to remove a directory and victim isn't one - ENOTDIR. - * 9. If we were asked to remove a non-directory and victim isn't one - EISDIR. - * 10. We can't remove a root or mountpoint. - * 11. We don't allow removal of NFS sillyrenamed files; it's handled by - * nfs_async_unlink(). - */ -static int may_delete(struct inode *dir, struct dentry *victim, bool isdir) -{ - struct inode *inode = d_backing_inode(victim); - int error; - - if (d_is_negative(victim)) - return -ENOENT; - BUG_ON(!inode); - - BUG_ON(victim->d_parent->d_inode != dir); - audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE); - - error = inode_permission(dir, MAY_WRITE | MAY_EXEC); - if (error) - return error; - if (IS_APPEND(dir)) - return -EPERM; - - if (check_sticky(dir, inode) || IS_APPEND(inode) || - IS_IMMUTABLE(inode) || IS_SWAPFILE(inode) || HAS_UNMAPPED_ID(inode)) - return -EPERM; - if (isdir) { - if (!d_is_dir(victim)) - return -ENOTDIR; - if (IS_ROOT(victim)) - return -EBUSY; - } else if (d_is_dir(victim)) - return -EISDIR; - if (IS_DEADDIR(dir)) - return -ENOENT; - if (victim->d_flags & DCACHE_NFSFS_RENAMED) - return -EBUSY; - return 0; -} - -/* Check whether we can create an object with dentry child in directory - * dir. - * 1. We can't do it if child already exists (open has special treatment for - * this case, but since we are inlined it's OK) - * 2. We can't do it if dir is read-only (done in permission()) - * 3. We can't do it if the fs can't represent the fsuid or fsgid. - * 4. We should have write and exec permissions on dir - * 5. We can't do it if dir is immutable (done in permission()) - */ -static inline int may_create(struct inode *dir, struct dentry *child) -{ - struct user_namespace *s_user_ns; - audit_inode_child(dir, child, AUDIT_TYPE_CHILD_CREATE); - if (child->d_inode) - return -EEXIST; - if (IS_DEADDIR(dir)) - return -ENOENT; - s_user_ns = dir->i_sb->s_user_ns; - if (!kuid_has_mapping(s_user_ns, current_fsuid()) || - !kgid_has_mapping(s_user_ns, current_fsgid())) - return -EOVERFLOW; - return inode_permission(dir, MAY_WRITE | MAY_EXEC); -} - -/* - * p1 and p2 should be directories on the same fs. - */ -struct dentry *lock_rename(struct dentry *p1, struct dentry *p2) -{ - struct dentry *p; - - if (p1 == p2) { - inode_lock_nested(p1->d_inode, I_MUTEX_PARENT); - return NULL; - } - - mutex_lock(&p1->d_sb->s_vfs_rename_mutex); - - p = d_ancestor(p2, p1); - if (p) { - inode_lock_nested(p2->d_inode, I_MUTEX_PARENT); - inode_lock_nested(p1->d_inode, I_MUTEX_CHILD); - return p; - } - - p = d_ancestor(p1, p2); - if (p) { - inode_lock_nested(p1->d_inode, I_MUTEX_PARENT); - inode_lock_nested(p2->d_inode, I_MUTEX_CHILD); - return p; - } - - inode_lock_nested(p1->d_inode, I_MUTEX_PARENT); - inode_lock_nested(p2->d_inode, I_MUTEX_PARENT2); - return NULL; -} -EXPORT_SYMBOL(lock_rename); - -void unlock_rename(struct dentry *p1, struct dentry *p2) -{ - inode_unlock(p1->d_inode); - if (p1 != p2) { - inode_unlock(p2->d_inode); - mutex_unlock(&p1->d_sb->s_vfs_rename_mutex); - } -} -EXPORT_SYMBOL(unlock_rename); - -int vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, - bool want_excl) -{ - int error = may_create(dir, dentry); - if (error) - return error; - - if (!dir->i_op->create) - return -EACCES; /* shouldn't it be ENOSYS? */ - mode &= S_IALLUGO; - mode |= S_IFREG; - error = security_inode_create(dir, dentry, mode); - if (error) - return error; - error = dir->i_op->create(dir, dentry, mode, want_excl); - if (!error) - fsnotify_create(dir, dentry); - return error; -} -EXPORT_SYMBOL(vfs_create); - -bool may_open_dev(const struct path *path) -{ - return !(path->mnt->mnt_flags & MNT_NODEV) && - !(path->mnt->mnt_sb->s_iflags & SB_I_NODEV); -} - -static int may_open(struct path *path, int acc_mode, int flag) -{ - struct dentry *dentry = path->dentry; - struct inode *inode = dentry->d_inode; - int error; - - if (!inode) - return -ENOENT; - - switch (inode->i_mode & S_IFMT) { - case S_IFLNK: - return -ELOOP; - case S_IFDIR: - if (acc_mode & MAY_WRITE) - return -EISDIR; - break; - case S_IFBLK: - case S_IFCHR: - if (!may_open_dev(path)) - return -EACCES; - /*FALLTHRU*/ - case S_IFIFO: - case S_IFSOCK: - flag &= ~O_TRUNC; - break; - } - - error = inode_permission(inode, MAY_OPEN | acc_mode); - if (error) - return error; - - /* - * An append-only file must be opened in append mode for writing. - */ - if (IS_APPEND(inode)) { - if ((flag & O_ACCMODE) != O_RDONLY && !(flag & O_APPEND)) - return -EPERM; - if (flag & O_TRUNC) - return -EPERM; - } - - /* O_NOATIME can only be set by the owner or superuser */ - if (flag & O_NOATIME && !inode_owner_or_capable(inode)) - return -EPERM; - - return 0; -} - -static int handle_truncate(struct file *filp) -{ - struct path *path = &filp->f_path; - struct inode *inode = path->dentry->d_inode; - int error = get_write_access(inode); - if (error) - return error; - /* - * Refuse to truncate files with mandatory locks held on them. - */ - error = locks_verify_locked(filp); - if (!error) - error = security_path_truncate(path); - if (!error) { - error = do_truncate(path->dentry, 0, - ATTR_MTIME|ATTR_CTIME|ATTR_OPEN, - filp); - } - put_write_access(inode); - return error; -} - -static inline int open_to_namei_flags(int flag) -{ - if ((flag & O_ACCMODE) == 3) - flag--; - return flag; -} - -static int may_o_create(const struct path *dir, struct dentry *dentry, umode_t mode) -{ - int error = security_path_mknod(dir, dentry, mode, 0); - if (error) - return error; - - error = inode_permission(dir->dentry->d_inode, MAY_WRITE | MAY_EXEC); - if (error) - return error; - - return security_inode_create(dir->dentry->d_inode, dentry, mode); -} - -/* - * Attempt to atomically look up, create and open a file from a negative - * dentry. - * - * Returns 0 if successful. The file will have been created and attached to - * @file by the filesystem calling finish_open(). - * - * Returns 1 if the file was looked up only or didn't need creating. The - * caller will need to perform the open themselves. @path will have been - * updated to point to the new dentry. This may be negative. - * - * Returns an error code otherwise. - */ -static int atomic_open(struct nameidata *nd, struct dentry *dentry, - struct path *path, struct file *file, - const struct open_flags *op, - int open_flag, umode_t mode, - int *opened) -{ - struct dentry *const DENTRY_NOT_SET = (void *) -1UL; - struct inode *dir = nd->path.dentry->d_inode; - int error; - - if (!(~open_flag & (O_EXCL | O_CREAT))) /* both O_EXCL and O_CREAT */ - open_flag &= ~O_TRUNC; - - if (nd->flags & LOOKUP_DIRECTORY) - open_flag |= O_DIRECTORY; - - file->f_path.dentry = DENTRY_NOT_SET; - file->f_path.mnt = nd->path.mnt; - error = dir->i_op->atomic_open(dir, dentry, file, - open_to_namei_flags(open_flag), - mode, opened); - d_lookup_done(dentry); - if (!error) { - /* - * We didn't have the inode before the open, so check open - * permission here. - */ - int acc_mode = op->acc_mode; - if (*opened & FILE_CREATED) { - WARN_ON(!(open_flag & O_CREAT)); - fsnotify_create(dir, dentry); - acc_mode = 0; - } - error = may_open(&file->f_path, acc_mode, open_flag); - if (WARN_ON(error > 0)) - error = -EINVAL; - } else if (error > 0) { - if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) { - error = -EIO; - } else { - if (file->f_path.dentry) { - dput(dentry); - dentry = file->f_path.dentry; - } - if (*opened & FILE_CREATED) - fsnotify_create(dir, dentry); - if (unlikely(d_is_negative(dentry))) { - error = -ENOENT; - } else { - path->dentry = dentry; - path->mnt = nd->path.mnt; - return 1; - } - } - } - dput(dentry); - return error; -} - -/* - * Look up and maybe create and open the last component. - * - * Must be called with i_mutex held on parent. - * - * Returns 0 if the file was successfully atomically created (if necessary) and - * opened. In this case the file will be returned attached to @file. - * - * Returns 1 if the file was not completely opened at this time, though lookups - * and creations will have been performed and the dentry returned in @path will - * be positive upon return if O_CREAT was specified. If O_CREAT wasn't - * specified then a negative dentry may be returned. - * - * An error code is returned otherwise. - * - * FILE_CREATE will be set in @*opened if the dentry was created and will be - * cleared otherwise prior to returning. - */ -static int lookup_open(struct nameidata *nd, struct path *path, - struct file *file, - const struct open_flags *op, - bool got_write, int *opened) -{ - struct dentry *dir = nd->path.dentry; - struct inode *dir_inode = dir->d_inode; - int open_flag = op->open_flag; - struct dentry *dentry; - int error, create_error = 0; - umode_t mode = op->mode; - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); - - if (unlikely(IS_DEADDIR(dir_inode))) - return -ENOENT; - - *opened &= ~FILE_CREATED; - dentry = d_lookup(dir, &nd->last); - for (;;) { - if (!dentry) { - dentry = d_alloc_parallel(dir, &nd->last, &wq); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - } - if (d_in_lookup(dentry)) - break; - - if (!(dentry->d_flags & DCACHE_OP_REVALIDATE)) - break; - - error = d_revalidate(dentry, nd->flags); - if (likely(error > 0)) - break; - if (error) - goto out_dput; - d_invalidate(dentry); - dput(dentry); - dentry = NULL; - } - if (dentry->d_inode) { - /* Cached positive dentry: will open in f_op->open */ - goto out_no_open; - } - - /* - * Checking write permission is tricky, bacuse we don't know if we are - * going to actually need it: O_CREAT opens should work as long as the - * file exists. But checking existence breaks atomicity. The trick is - * to check access and if not granted clear O_CREAT from the flags. - * - * Another problem is returing the "right" error value (e.g. for an - * O_EXCL open we want to return EEXIST not EROFS). - */ - if (open_flag & O_CREAT) { - if (!IS_POSIXACL(dir->d_inode)) - mode &= ~current_umask(); - if (unlikely(!got_write)) { - create_error = -EROFS; - open_flag &= ~O_CREAT; - if (open_flag & (O_EXCL | O_TRUNC)) - goto no_open; - /* No side effects, safe to clear O_CREAT */ - } else { - create_error = may_o_create(&nd->path, dentry, mode); - if (create_error) { - open_flag &= ~O_CREAT; - if (open_flag & O_EXCL) - goto no_open; - } - } - } else if ((open_flag & (O_TRUNC|O_WRONLY|O_RDWR)) && - unlikely(!got_write)) { - /* - * No O_CREATE -> atomicity not a requirement -> fall - * back to lookup + open - */ - goto no_open; - } - - if (dir_inode->i_op->atomic_open) { - error = atomic_open(nd, dentry, path, file, op, open_flag, - mode, opened); - if (unlikely(error == -ENOENT) && create_error) - error = create_error; - return error; - } - -no_open: - if (d_in_lookup(dentry)) { - struct dentry *res = dir_inode->i_op->lookup(dir_inode, dentry, - nd->flags); - d_lookup_done(dentry); - if (unlikely(res)) { - if (IS_ERR(res)) { - error = PTR_ERR(res); - goto out_dput; - } - dput(dentry); - dentry = res; - } - } - - /* Negative dentry, just create the file */ - if (!dentry->d_inode && (open_flag & O_CREAT)) { - *opened |= FILE_CREATED; - audit_inode_child(dir_inode, dentry, AUDIT_TYPE_CHILD_CREATE); - if (!dir_inode->i_op->create) { - error = -EACCES; - goto out_dput; - } - error = dir_inode->i_op->create(dir_inode, dentry, mode, - open_flag & O_EXCL); - if (error) - goto out_dput; - fsnotify_create(dir_inode, dentry); - } - if (unlikely(create_error) && !dentry->d_inode) { - error = create_error; - goto out_dput; - } -out_no_open: - path->dentry = dentry; - path->mnt = nd->path.mnt; - return 1; - -out_dput: - dput(dentry); - return error; -} - -/* - * Handle the last step of open() - */ -static int do_last(struct nameidata *nd, - struct file *file, const struct open_flags *op, - int *opened) -{ - struct dentry *dir = nd->path.dentry; - int open_flag = op->open_flag; - bool will_truncate = (open_flag & O_TRUNC) != 0; - bool got_write = false; - int acc_mode = op->acc_mode; - unsigned seq; - struct inode *inode; - struct path path; - int error; - - nd->flags &= ~LOOKUP_PARENT; - nd->flags |= op->intent; - - if (nd->last_type != LAST_NORM) { - error = handle_dots(nd, nd->last_type); - if (unlikely(error)) - return error; - goto finish_open; - } - - if (!(open_flag & O_CREAT)) { - if (nd->last.name[nd->last.len]) - nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY; - /* we _can_ be in RCU mode here */ - error = lookup_fast(nd, &path, &inode, &seq); - if (likely(error > 0)) - goto finish_lookup; - - if (error < 0) - return error; - - BUG_ON(nd->inode != dir->d_inode); - BUG_ON(nd->flags & LOOKUP_RCU); - } else { - /* create side of things */ - /* - * This will *only* deal with leaving RCU mode - LOOKUP_JUMPED - * has been cleared when we got to the last component we are - * about to look up - */ - error = complete_walk(nd); - if (error) - return error; - - audit_inode(nd->name, dir, LOOKUP_PARENT); - /* trailing slashes? */ - if (unlikely(nd->last.name[nd->last.len])) - return -EISDIR; - } - - if (open_flag & (O_CREAT | O_TRUNC | O_WRONLY | O_RDWR)) { - error = mnt_want_write(nd->path.mnt); - if (!error) - got_write = true; - /* - * do _not_ fail yet - we might not need that or fail with - * a different error; let lookup_open() decide; we'll be - * dropping this one anyway. - */ - } - if (open_flag & O_CREAT) - inode_lock(dir->d_inode); - else - inode_lock_shared(dir->d_inode); - error = lookup_open(nd, &path, file, op, got_write, opened); - if (open_flag & O_CREAT) - inode_unlock(dir->d_inode); - else - inode_unlock_shared(dir->d_inode); - - if (error <= 0) { - if (error) - goto out; - - if ((*opened & FILE_CREATED) || - !S_ISREG(file_inode(file)->i_mode)) - will_truncate = false; - - audit_inode(nd->name, file->f_path.dentry, 0); - goto opened; - } - - if (*opened & FILE_CREATED) { - /* Don't check for write permission, don't truncate */ - open_flag &= ~O_TRUNC; - will_truncate = false; - acc_mode = 0; - path_to_nameidata(&path, nd); - goto finish_open_created; - } - - /* - * If atomic_open() acquired write access it is dropped now due to - * possible mount and symlink following (this might be optimized away if - * necessary...) - */ - if (got_write) { - mnt_drop_write(nd->path.mnt); - got_write = false; - } - - error = follow_managed(&path, nd); - if (unlikely(error < 0)) - return error; - - if (unlikely(d_is_negative(path.dentry))) { - path_to_nameidata(&path, nd); - return -ENOENT; - } - - /* - * create/update audit record if it already exists. - */ - audit_inode(nd->name, path.dentry, 0); - - if (unlikely((open_flag & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT))) { - path_to_nameidata(&path, nd); - return -EEXIST; - } - - seq = 0; /* out of RCU mode, so the value doesn't matter */ - inode = d_backing_inode(path.dentry); -finish_lookup: - if (nd->depth) - put_link(nd); - error = should_follow_link(nd, &path, nd->flags & LOOKUP_FOLLOW, - inode, seq); - if (unlikely(error)) - return error; - - path_to_nameidata(&path, nd); - nd->inode = inode; - nd->seq = seq; - /* Why this, you ask? _Now_ we might have grown LOOKUP_JUMPED... */ -finish_open: - error = complete_walk(nd); - if (error) - return error; - audit_inode(nd->name, nd->path.dentry, 0); - error = -EISDIR; - if ((open_flag & O_CREAT) && d_is_dir(nd->path.dentry)) - goto out; - error = -ENOTDIR; - if ((nd->flags & LOOKUP_DIRECTORY) && !d_can_lookup(nd->path.dentry)) - goto out; - if (!d_is_reg(nd->path.dentry)) - will_truncate = false; - - if (will_truncate) { - error = mnt_want_write(nd->path.mnt); - if (error) - goto out; - got_write = true; - } -finish_open_created: - error = may_open(&nd->path, acc_mode, open_flag); - if (error) - goto out; - BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */ - error = vfs_open(&nd->path, file, current_cred()); - if (error) - goto out; - *opened |= FILE_OPENED; -opened: - error = open_check_o_direct(file); - if (!error) - error = ima_file_check(file, op->acc_mode, *opened); - if (!error && will_truncate) - error = handle_truncate(file); -out: - if (unlikely(error) && (*opened & FILE_OPENED)) - fput(file); - if (unlikely(error > 0)) { - WARN_ON(1); - error = -EINVAL; - } - if (got_write) - mnt_drop_write(nd->path.mnt); - return error; -} - -static int do_tmpfile(struct nameidata *nd, unsigned flags, - const struct open_flags *op, - struct file *file, int *opened) -{ - static const struct qstr name = QSTR_INIT("/", 1); - struct dentry *child; - struct inode *dir; - struct path path; - int error = path_lookupat(nd, flags | LOOKUP_DIRECTORY, &path); - if (unlikely(error)) - return error; - error = mnt_want_write(path.mnt); - if (unlikely(error)) - goto out; - dir = path.dentry->d_inode; - /* we want directory to be writable */ - error = inode_permission(dir, MAY_WRITE | MAY_EXEC); - if (error) - goto out2; - if (!dir->i_op->tmpfile) { - error = -EOPNOTSUPP; - goto out2; - } - child = d_alloc(path.dentry, &name); - if (unlikely(!child)) { - error = -ENOMEM; - goto out2; - } - dput(path.dentry); - path.dentry = child; - error = dir->i_op->tmpfile(dir, child, op->mode); - if (error) - goto out2; - audit_inode(nd->name, child, 0); - /* Don't check for other permissions, the inode was just created */ - error = may_open(&path, 0, op->open_flag); - if (error) - goto out2; - file->f_path.mnt = path.mnt; - error = finish_open(file, child, NULL, opened); - if (error) - goto out2; - error = open_check_o_direct(file); - if (error) { - fput(file); - } else if (!(op->open_flag & O_EXCL)) { - struct inode *inode = file_inode(file); - spin_lock(&inode->i_lock); - inode->i_state |= I_LINKABLE; - spin_unlock(&inode->i_lock); - } -out2: - mnt_drop_write(path.mnt); -out: - path_put(&path); - return error; -} - -static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file) -{ - struct path path; - int error = path_lookupat(nd, flags, &path); - if (!error) { - audit_inode(nd->name, path.dentry, 0); - error = vfs_open(&path, file, current_cred()); - path_put(&path); - } - return error; -} - -static struct file *path_openat(struct nameidata *nd, - const struct open_flags *op, unsigned flags) -{ - const char *s; - struct file *file; - int opened = 0; - int error; - - file = get_empty_filp(); - if (IS_ERR(file)) - return file; - - file->f_flags = op->open_flag; - - if (unlikely(file->f_flags & __O_TMPFILE)) { - error = do_tmpfile(nd, flags, op, file, &opened); - goto out2; - } - - if (unlikely(file->f_flags & O_PATH)) { - error = do_o_path(nd, flags, file); - if (!error) - opened |= FILE_OPENED; - goto out2; - } - - s = path_init(nd, flags); - if (IS_ERR(s)) { - put_filp(file); - return ERR_CAST(s); - } - while (!(error = link_path_walk(s, nd)) && - (error = do_last(nd, file, op, &opened)) > 0) { - nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL); - s = trailing_symlink(nd); - if (IS_ERR(s)) { - error = PTR_ERR(s); - break; - } - } - terminate_walk(nd); -out2: - if (!(opened & FILE_OPENED)) { - BUG_ON(!error); - put_filp(file); - } - if (unlikely(error)) { - if (error == -EOPENSTALE) { - if (flags & LOOKUP_RCU) - error = -ECHILD; - else - error = -ESTALE; - } - file = ERR_PTR(error); - } - return file; -} - -struct file *do_filp_open(int dfd, struct filename *pathname, - const struct open_flags *op) -{ - struct nameidata nd; - int flags = op->lookup_flags; - struct file *filp; - - set_nameidata(&nd, dfd, pathname); - filp = path_openat(&nd, op, flags | LOOKUP_RCU); - if (unlikely(filp == ERR_PTR(-ECHILD))) - filp = path_openat(&nd, op, flags); - if (unlikely(filp == ERR_PTR(-ESTALE))) - filp = path_openat(&nd, op, flags | LOOKUP_REVAL); - restore_nameidata(); - return filp; -} - -struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt, - const char *name, const struct open_flags *op) -{ - struct nameidata nd; - struct file *file; - struct filename *filename; - int flags = op->lookup_flags | LOOKUP_ROOT; - - nd.root.mnt = mnt; - nd.root.dentry = dentry; - - if (d_is_symlink(dentry) && op->intent & LOOKUP_OPEN) - return ERR_PTR(-ELOOP); - - filename = getname_kernel(name); - if (IS_ERR(filename)) - return ERR_CAST(filename); - - set_nameidata(&nd, -1, filename); - file = path_openat(&nd, op, flags | LOOKUP_RCU); - if (unlikely(file == ERR_PTR(-ECHILD))) - file = path_openat(&nd, op, flags); - if (unlikely(file == ERR_PTR(-ESTALE))) - file = path_openat(&nd, op, flags | LOOKUP_REVAL); - restore_nameidata(); - putname(filename); - return file; -} - -static struct dentry *filename_create(int dfd, struct filename *name, - struct path *path, unsigned int lookup_flags) -{ - struct dentry *dentry = ERR_PTR(-EEXIST); - struct qstr last; - int type; - int err2; - int error; - bool is_dir = (lookup_flags & LOOKUP_DIRECTORY); - - /* - * Note that only LOOKUP_REVAL and LOOKUP_DIRECTORY matter here. Any - * other flags passed in are ignored! - */ - lookup_flags &= LOOKUP_REVAL; - - name = filename_parentat(dfd, name, lookup_flags, path, &last, &type); - if (IS_ERR(name)) - return ERR_CAST(name); - - /* - * Yucky last component or no last component at all? - * (foo/., foo/.., /////) - */ - if (unlikely(type != LAST_NORM)) - goto out; - - /* don't fail immediately if it's r/o, at least try to report other errors */ - err2 = mnt_want_write(path->mnt); - /* - * Do the final lookup. - */ - lookup_flags |= LOOKUP_CREATE | LOOKUP_EXCL; - inode_lock_nested(path->dentry->d_inode, I_MUTEX_PARENT); - dentry = __lookup_hash(&last, path->dentry, lookup_flags); - if (IS_ERR(dentry)) - goto unlock; - - error = -EEXIST; - if (d_is_positive(dentry)) - goto fail; - - /* - * Special case - lookup gave negative, but... we had foo/bar/ - * From the vfs_mknod() POV we just have a negative dentry - - * all is fine. Let's be bastards - you had / on the end, you've - * been asking for (non-existent) directory. -ENOENT for you. - */ - if (unlikely(!is_dir && last.name[last.len])) { - error = -ENOENT; - goto fail; - } - if (unlikely(err2)) { - error = err2; - goto fail; - } - putname(name); - return dentry; -fail: - dput(dentry); - dentry = ERR_PTR(error); -unlock: - inode_unlock(path->dentry->d_inode); - if (!err2) - mnt_drop_write(path->mnt); -out: - path_put(path); - putname(name); - return dentry; -} - -struct dentry *kern_path_create(int dfd, const char *pathname, - struct path *path, unsigned int lookup_flags) -{ - return filename_create(dfd, getname_kernel(pathname), - path, lookup_flags); -} -EXPORT_SYMBOL(kern_path_create); - -void done_path_create(struct path *path, struct dentry *dentry) -{ - dput(dentry); - inode_unlock(path->dentry->d_inode); - mnt_drop_write(path->mnt); - path_put(path); -} -EXPORT_SYMBOL(done_path_create); - -inline struct dentry *user_path_create(int dfd, const char __user *pathname, - struct path *path, unsigned int lookup_flags) -{ - return filename_create(dfd, getname(pathname), path, lookup_flags); -} -EXPORT_SYMBOL(user_path_create); - -int vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) -{ - int error = may_create(dir, dentry); - - if (error) - return error; - - if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD)) - return -EPERM; - - if (!dir->i_op->mknod) - return -EPERM; - - error = devcgroup_inode_mknod(mode, dev); - if (error) - return error; - - error = security_inode_mknod(dir, dentry, mode, dev); - if (error) - return error; - - error = dir->i_op->mknod(dir, dentry, mode, dev); - if (!error) - fsnotify_create(dir, dentry); - return error; -} -EXPORT_SYMBOL(vfs_mknod); - -static int may_mknod(umode_t mode) -{ - switch (mode & S_IFMT) { - case S_IFREG: - case S_IFCHR: - case S_IFBLK: - case S_IFIFO: - case S_IFSOCK: - case 0: /* zero mode translates to S_IFREG */ - return 0; - case S_IFDIR: - return -EPERM; - default: - return -EINVAL; - } -} - -SYSCALL_DEFINE4(mknodat, int, dfd, const char __user *, filename, umode_t, mode, - unsigned, dev) -{ - struct dentry *dentry; - struct path path; - int error; - unsigned int lookup_flags = 0; - - error = may_mknod(mode); - if (error) - return error; -retry: - dentry = user_path_create(dfd, filename, &path, lookup_flags); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - - if (!IS_POSIXACL(path.dentry->d_inode)) - mode &= ~current_umask(); - error = security_path_mknod(&path, dentry, mode, dev); - if (error) - goto out; - switch (mode & S_IFMT) { - case 0: case S_IFREG: - error = vfs_create(path.dentry->d_inode,dentry,mode,true); - if (!error) - ima_post_path_mknod(dentry); - break; - case S_IFCHR: case S_IFBLK: - error = vfs_mknod(path.dentry->d_inode,dentry,mode, - new_decode_dev(dev)); - break; - case S_IFIFO: case S_IFSOCK: - error = vfs_mknod(path.dentry->d_inode,dentry,mode,0); - break; - } -out: - done_path_create(&path, dentry); - if (retry_estale(error, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - goto retry; - } - return error; -} - -SYSCALL_DEFINE3(mknod, const char __user *, filename, umode_t, mode, unsigned, dev) -{ - return sys_mknodat(AT_FDCWD, filename, mode, dev); -} - -int vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) -{ - int error = may_create(dir, dentry); - unsigned max_links = dir->i_sb->s_max_links; - - if (error) - return error; - - if (!dir->i_op->mkdir) - return -EPERM; - - mode &= (S_IRWXUGO|S_ISVTX); - error = security_inode_mkdir(dir, dentry, mode); - if (error) - return error; - - if (max_links && dir->i_nlink >= max_links) - return -EMLINK; - - error = dir->i_op->mkdir(dir, dentry, mode); - if (!error) - fsnotify_mkdir(dir, dentry); - return error; -} -EXPORT_SYMBOL(vfs_mkdir); - -SYSCALL_DEFINE3(mkdirat, int, dfd, const char __user *, pathname, umode_t, mode) -{ - struct dentry *dentry; - struct path path; - int error; - unsigned int lookup_flags = LOOKUP_DIRECTORY; - -retry: - dentry = user_path_create(dfd, pathname, &path, lookup_flags); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - - if (!IS_POSIXACL(path.dentry->d_inode)) - mode &= ~current_umask(); - error = security_path_mkdir(&path, dentry, mode); - if (!error) - error = vfs_mkdir(path.dentry->d_inode, dentry, mode); - done_path_create(&path, dentry); - if (retry_estale(error, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - goto retry; - } - return error; -} - -SYSCALL_DEFINE2(mkdir, const char __user *, pathname, umode_t, mode) -{ - return sys_mkdirat(AT_FDCWD, pathname, mode); -} - -int vfs_rmdir(struct inode *dir, struct dentry *dentry) -{ - int error = may_delete(dir, dentry, 1); - - if (error) - return error; - - if (!dir->i_op->rmdir) - return -EPERM; - - dget(dentry); - inode_lock(dentry->d_inode); - - error = -EBUSY; - if (is_local_mountpoint(dentry)) - goto out; - - error = security_inode_rmdir(dir, dentry); - if (error) - goto out; - - shrink_dcache_parent(dentry); - error = dir->i_op->rmdir(dir, dentry); - if (error) - goto out; - - dentry->d_inode->i_flags |= S_DEAD; - dont_mount(dentry); - detach_mounts(dentry); - -out: - inode_unlock(dentry->d_inode); - dput(dentry); - if (!error) - d_delete(dentry); - return error; -} -EXPORT_SYMBOL(vfs_rmdir); - -static long do_rmdir(int dfd, const char __user *pathname) -{ - int error = 0; - struct filename *name; - struct dentry *dentry; - struct path path; - struct qstr last; - int type; - unsigned int lookup_flags = 0; -retry: - name = user_path_parent(dfd, pathname, - &path, &last, &type, lookup_flags); - if (IS_ERR(name)) - return PTR_ERR(name); - - switch (type) { - case LAST_DOTDOT: - error = -ENOTEMPTY; - goto exit1; - case LAST_DOT: - error = -EINVAL; - goto exit1; - case LAST_ROOT: - error = -EBUSY; - goto exit1; - } - - error = mnt_want_write(path.mnt); - if (error) - goto exit1; - - inode_lock_nested(path.dentry->d_inode, I_MUTEX_PARENT); - dentry = __lookup_hash(&last, path.dentry, lookup_flags); - error = PTR_ERR(dentry); - if (IS_ERR(dentry)) - goto exit2; - if (!dentry->d_inode) { - error = -ENOENT; - goto exit3; - } - error = security_path_rmdir(&path, dentry); - if (error) - goto exit3; - error = vfs_rmdir(path.dentry->d_inode, dentry); -exit3: - dput(dentry); -exit2: - inode_unlock(path.dentry->d_inode); - mnt_drop_write(path.mnt); -exit1: - path_put(&path); - putname(name); - if (retry_estale(error, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - goto retry; - } - return error; -} - -SYSCALL_DEFINE1(rmdir, const char __user *, pathname) -{ - return do_rmdir(AT_FDCWD, pathname); -} - -/** - * vfs_unlink - unlink a filesystem object - * @dir: parent directory - * @dentry: victim - * @delegated_inode: returns victim inode, if the inode is delegated. - * - * The caller must hold dir->i_mutex. - * - * If vfs_unlink discovers a delegation, it will return -EWOULDBLOCK and - * return a reference to the inode in delegated_inode. The caller - * should then break the delegation on that inode and retry. Because - * breaking a delegation may take a long time, the caller should drop - * dir->i_mutex before doing so. - * - * Alternatively, a caller may pass NULL for delegated_inode. This may - * be appropriate for callers that expect the underlying filesystem not - * to be NFS exported. - */ -int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegated_inode) -{ - struct inode *target = dentry->d_inode; - int error = may_delete(dir, dentry, 0); - - if (error) - return error; - - if (!dir->i_op->unlink) - return -EPERM; - - inode_lock(target); - if (is_local_mountpoint(dentry)) - error = -EBUSY; - else { - error = security_inode_unlink(dir, dentry); - if (!error) { - error = try_break_deleg(target, delegated_inode); - if (error) - goto out; - error = dir->i_op->unlink(dir, dentry); - if (!error) { - dont_mount(dentry); - detach_mounts(dentry); - } - } - } -out: - inode_unlock(target); - - /* We don't d_delete() NFS sillyrenamed files--they still exist. */ - if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) { - fsnotify_link_count(target); - d_delete(dentry); - } - - return error; -} -EXPORT_SYMBOL(vfs_unlink); - -/* - * Make sure that the actual truncation of the file will occur outside its - * directory's i_mutex. Truncate can take a long time if there is a lot of - * writeout happening, and we don't want to prevent access to the directory - * while waiting on the I/O. - */ -static long do_unlinkat(int dfd, const char __user *pathname) -{ - int error; - struct filename *name; - struct dentry *dentry; - struct path path; - struct qstr last; - int type; - struct inode *inode = NULL; - struct inode *delegated_inode = NULL; - unsigned int lookup_flags = 0; -retry: - name = user_path_parent(dfd, pathname, - &path, &last, &type, lookup_flags); - if (IS_ERR(name)) - return PTR_ERR(name); - - error = -EISDIR; - if (type != LAST_NORM) - goto exit1; - - error = mnt_want_write(path.mnt); - if (error) - goto exit1; -retry_deleg: - inode_lock_nested(path.dentry->d_inode, I_MUTEX_PARENT); - dentry = __lookup_hash(&last, path.dentry, lookup_flags); - error = PTR_ERR(dentry); - if (!IS_ERR(dentry)) { - /* Why not before? Because we want correct error value */ - if (last.name[last.len]) - goto slashes; - inode = dentry->d_inode; - if (d_is_negative(dentry)) - goto slashes; - ihold(inode); - error = security_path_unlink(&path, dentry); - if (error) - goto exit2; - error = vfs_unlink(path.dentry->d_inode, dentry, &delegated_inode); -exit2: - dput(dentry); - } - inode_unlock(path.dentry->d_inode); - if (inode) - iput(inode); /* truncate the inode here */ - inode = NULL; - if (delegated_inode) { - error = break_deleg_wait(&delegated_inode); - if (!error) - goto retry_deleg; - } - mnt_drop_write(path.mnt); -exit1: - path_put(&path); - putname(name); - if (retry_estale(error, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - inode = NULL; - goto retry; - } - return error; - -slashes: - if (d_is_negative(dentry)) - error = -ENOENT; - else if (d_is_dir(dentry)) - error = -EISDIR; - else - error = -ENOTDIR; - goto exit2; -} - -SYSCALL_DEFINE3(unlinkat, int, dfd, const char __user *, pathname, int, flag) -{ - if ((flag & ~AT_REMOVEDIR) != 0) - return -EINVAL; - - if (flag & AT_REMOVEDIR) - return do_rmdir(dfd, pathname); - - return do_unlinkat(dfd, pathname); -} - -SYSCALL_DEFINE1(unlink, const char __user *, pathname) -{ - return do_unlinkat(AT_FDCWD, pathname); -} - -int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname) -{ - int error = may_create(dir, dentry); - - if (error) - return error; - - if (!dir->i_op->symlink) - return -EPERM; - - error = security_inode_symlink(dir, dentry, oldname); - if (error) - return error; - - error = dir->i_op->symlink(dir, dentry, oldname); - if (!error) - fsnotify_create(dir, dentry); - return error; -} -EXPORT_SYMBOL(vfs_symlink); - -SYSCALL_DEFINE3(symlinkat, const char __user *, oldname, - int, newdfd, const char __user *, newname) -{ - int error; - struct filename *from; - struct dentry *dentry; - struct path path; - unsigned int lookup_flags = 0; - - from = getname(oldname); - if (IS_ERR(from)) - return PTR_ERR(from); -retry: - dentry = user_path_create(newdfd, newname, &path, lookup_flags); - error = PTR_ERR(dentry); - if (IS_ERR(dentry)) - goto out_putname; - - error = security_path_symlink(&path, dentry, from->name); - if (!error) - error = vfs_symlink(path.dentry->d_inode, dentry, from->name); - done_path_create(&path, dentry); - if (retry_estale(error, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - goto retry; - } -out_putname: - putname(from); - return error; -} - -SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newname) -{ - return sys_symlinkat(oldname, AT_FDCWD, newname); -} - -/** - * vfs_link - create a new link - * @old_dentry: object to be linked - * @dir: new parent - * @new_dentry: where to create the new link - * @delegated_inode: returns inode needing a delegation break - * - * The caller must hold dir->i_mutex - * - * If vfs_link discovers a delegation on the to-be-linked file in need - * of breaking, it will return -EWOULDBLOCK and return a reference to the - * inode in delegated_inode. The caller should then break the delegation - * and retry. Because breaking a delegation may take a long time, the - * caller should drop the i_mutex before doing so. - * - * Alternatively, a caller may pass NULL for delegated_inode. This may - * be appropriate for callers that expect the underlying filesystem not - * to be NFS exported. - */ -int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, struct inode **delegated_inode) -{ - struct inode *inode = old_dentry->d_inode; - unsigned max_links = dir->i_sb->s_max_links; - int error; - - if (!inode) - return -ENOENT; - - error = may_create(dir, new_dentry); - if (error) - return error; - - if (dir->i_sb != inode->i_sb) - return -EXDEV; - - /* - * A link to an append-only or immutable file cannot be created. - */ - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - return -EPERM; - /* - * Updating the link count will likely cause i_uid and i_gid to - * be writen back improperly if their true value is unknown to - * the vfs. - */ - if (HAS_UNMAPPED_ID(inode)) - return -EPERM; - if (!dir->i_op->link) - return -EPERM; - if (S_ISDIR(inode->i_mode)) - return -EPERM; - - error = security_inode_link(old_dentry, dir, new_dentry); - if (error) - return error; - - inode_lock(inode); - /* Make sure we don't allow creating hardlink to an unlinked file */ - if (inode->i_nlink == 0 && !(inode->i_state & I_LINKABLE)) - error = -ENOENT; - else if (max_links && inode->i_nlink >= max_links) - error = -EMLINK; - else { - error = try_break_deleg(inode, delegated_inode); - if (!error) - error = dir->i_op->link(old_dentry, dir, new_dentry); - } - - if (!error && (inode->i_state & I_LINKABLE)) { - spin_lock(&inode->i_lock); - inode->i_state &= ~I_LINKABLE; - spin_unlock(&inode->i_lock); - } - inode_unlock(inode); - if (!error) - fsnotify_link(dir, inode, new_dentry); - return error; -} -EXPORT_SYMBOL(vfs_link); - -/* - * Hardlinks are often used in delicate situations. We avoid - * security-related surprises by not following symlinks on the - * newname. --KAB - * - * We don't follow them on the oldname either to be compatible - * with linux 2.0, and to avoid hard-linking to directories - * and other special files. --ADM - */ -SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname, - int, newdfd, const char __user *, newname, int, flags) -{ - struct dentry *new_dentry; - struct path old_path, new_path; - struct inode *delegated_inode = NULL; - int how = 0; - int error; - - if ((flags & ~(AT_SYMLINK_FOLLOW | AT_EMPTY_PATH)) != 0) - return -EINVAL; - /* - * To use null names we require CAP_DAC_READ_SEARCH - * This ensures that not everyone will be able to create - * handlink using the passed filedescriptor. - */ - if (flags & AT_EMPTY_PATH) { - if (!capable(CAP_DAC_READ_SEARCH)) - return -ENOENT; - how = LOOKUP_EMPTY; - } - - if (flags & AT_SYMLINK_FOLLOW) - how |= LOOKUP_FOLLOW; -retry: - error = user_path_at(olddfd, oldname, how, &old_path); - if (error) - return error; - - new_dentry = user_path_create(newdfd, newname, &new_path, - (how & LOOKUP_REVAL)); - error = PTR_ERR(new_dentry); - if (IS_ERR(new_dentry)) - goto out; - - error = -EXDEV; - if (old_path.mnt != new_path.mnt) - goto out_dput; - error = may_linkat(&old_path); - if (unlikely(error)) - goto out_dput; - error = security_path_link(old_path.dentry, &new_path, new_dentry); - if (error) - goto out_dput; - error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry, &delegated_inode); -out_dput: - done_path_create(&new_path, new_dentry); - if (delegated_inode) { - error = break_deleg_wait(&delegated_inode); - if (!error) { - path_put(&old_path); - goto retry; - } - } - if (retry_estale(error, how)) { - path_put(&old_path); - how |= LOOKUP_REVAL; - goto retry; - } -out: - path_put(&old_path); - - return error; -} - -SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname) -{ - return sys_linkat(AT_FDCWD, oldname, AT_FDCWD, newname, 0); -} - -/** - * vfs_rename - rename a filesystem object - * @old_dir: parent of source - * @old_dentry: source - * @new_dir: parent of destination - * @new_dentry: destination - * @delegated_inode: returns an inode needing a delegation break - * @flags: rename flags - * - * The caller must hold multiple mutexes--see lock_rename()). - * - * If vfs_rename discovers a delegation in need of breaking at either - * the source or destination, it will return -EWOULDBLOCK and return a - * reference to the inode in delegated_inode. The caller should then - * break the delegation and retry. Because breaking a delegation may - * take a long time, the caller should drop all locks before doing - * so. - * - * Alternatively, a caller may pass NULL for delegated_inode. This may - * be appropriate for callers that expect the underlying filesystem not - * to be NFS exported. - * - * The worst of all namespace operations - renaming directory. "Perverted" - * doesn't even start to describe it. Somebody in UCB had a heck of a trip... - * Problems: - * a) we can get into loop creation. - * b) race potential - two innocent renames can create a loop together. - * That's where 4.4 screws up. Current fix: serialization on - * sb->s_vfs_rename_mutex. We might be more accurate, but that's another - * story. - * c) we have to lock _four_ objects - parents and victim (if it exists), - * and source (if it is not a directory). - * And that - after we got ->i_mutex on parents (until then we don't know - * whether the target exists). Solution: try to be smart with locking - * order for inodes. We rely on the fact that tree topology may change - * only under ->s_vfs_rename_mutex _and_ that parent of the object we - * move will be locked. Thus we can rank directories by the tree - * (ancestors first) and rank all non-directories after them. - * That works since everybody except rename does "lock parent, lookup, - * lock child" and rename is under ->s_vfs_rename_mutex. - * HOWEVER, it relies on the assumption that any object with ->lookup() - * has no more than 1 dentry. If "hybrid" objects will ever appear, - * we'd better make sure that there's no link(2) for them. - * d) conversion from fhandle to dentry may come in the wrong moment - when - * we are removing the target. Solution: we will have to grab ->i_mutex - * in the fhandle_to_dentry code. [FIXME - current nfsfh.c relies on - * ->i_mutex on parents, which works but leads to some truly excessive - * locking]. - */ -int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry, - struct inode **delegated_inode, unsigned int flags) -{ - int error; - bool is_dir = d_is_dir(old_dentry); - const unsigned char *old_name; - struct inode *source = old_dentry->d_inode; - struct inode *target = new_dentry->d_inode; - bool new_is_dir = false; - unsigned max_links = new_dir->i_sb->s_max_links; - - /* - * Check source == target. - * On overlayfs need to look at underlying inodes. - */ - if (d_real_inode(old_dentry) == d_real_inode(new_dentry)) - return 0; - - error = may_delete(old_dir, old_dentry, is_dir); - if (error) - return error; - - if (!target) { - error = may_create(new_dir, new_dentry); - } else { - new_is_dir = d_is_dir(new_dentry); - - if (!(flags & RENAME_EXCHANGE)) - error = may_delete(new_dir, new_dentry, is_dir); - else - error = may_delete(new_dir, new_dentry, new_is_dir); - } - if (error) - return error; - - if (!old_dir->i_op->rename) - return -EPERM; - - /* - * If we are going to change the parent - check write permissions, - * we'll need to flip '..'. - */ - if (new_dir != old_dir) { - if (is_dir) { - error = inode_permission(source, MAY_WRITE); - if (error) - return error; - } - if ((flags & RENAME_EXCHANGE) && new_is_dir) { - error = inode_permission(target, MAY_WRITE); - if (error) - return error; - } - } - - error = security_inode_rename(old_dir, old_dentry, new_dir, new_dentry, - flags); - if (error) - return error; - - old_name = fsnotify_oldname_init(old_dentry->d_name.name); - dget(new_dentry); - if (!is_dir || (flags & RENAME_EXCHANGE)) - lock_two_nondirectories(source, target); - else if (target) - inode_lock(target); - - error = -EBUSY; - if (is_local_mountpoint(old_dentry) || is_local_mountpoint(new_dentry)) - goto out; - - if (max_links && new_dir != old_dir) { - error = -EMLINK; - if (is_dir && !new_is_dir && new_dir->i_nlink >= max_links) - goto out; - if ((flags & RENAME_EXCHANGE) && !is_dir && new_is_dir && - old_dir->i_nlink >= max_links) - goto out; - } - if (is_dir && !(flags & RENAME_EXCHANGE) && target) - shrink_dcache_parent(new_dentry); - if (!is_dir) { - error = try_break_deleg(source, delegated_inode); - if (error) - goto out; - } - if (target && !new_is_dir) { - error = try_break_deleg(target, delegated_inode); - if (error) - goto out; - } - error = old_dir->i_op->rename(old_dir, old_dentry, - new_dir, new_dentry, flags); - if (error) - goto out; - - if (!(flags & RENAME_EXCHANGE) && target) { - if (is_dir) - target->i_flags |= S_DEAD; - dont_mount(new_dentry); - detach_mounts(new_dentry); - } - if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE)) { - if (!(flags & RENAME_EXCHANGE)) - d_move(old_dentry, new_dentry); - else - d_exchange(old_dentry, new_dentry); - } -out: - if (!is_dir || (flags & RENAME_EXCHANGE)) - unlock_two_nondirectories(source, target); - else if (target) - inode_unlock(target); - dput(new_dentry); - if (!error) { - fsnotify_move(old_dir, new_dir, old_name, is_dir, - !(flags & RENAME_EXCHANGE) ? target : NULL, old_dentry); - if (flags & RENAME_EXCHANGE) { - fsnotify_move(new_dir, old_dir, old_dentry->d_name.name, - new_is_dir, NULL, new_dentry); - } - } - fsnotify_oldname_free(old_name); - - return error; -} -EXPORT_SYMBOL(vfs_rename); - -SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname, - int, newdfd, const char __user *, newname, unsigned int, flags) -{ - struct dentry *old_dentry, *new_dentry; - struct dentry *trap; - struct path old_path, new_path; - struct qstr old_last, new_last; - int old_type, new_type; - struct inode *delegated_inode = NULL; - struct filename *from; - struct filename *to; - unsigned int lookup_flags = 0, target_flags = LOOKUP_RENAME_TARGET; - bool should_retry = false; - int error; - - if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) - return -EINVAL; - - if ((flags & (RENAME_NOREPLACE | RENAME_WHITEOUT)) && - (flags & RENAME_EXCHANGE)) - return -EINVAL; - - if ((flags & RENAME_WHITEOUT) && !capable(CAP_MKNOD)) - return -EPERM; - - if (flags & RENAME_EXCHANGE) - target_flags = 0; - -retry: - from = user_path_parent(olddfd, oldname, - &old_path, &old_last, &old_type, lookup_flags); - if (IS_ERR(from)) { - error = PTR_ERR(from); - goto exit; - } - - to = user_path_parent(newdfd, newname, - &new_path, &new_last, &new_type, lookup_flags); - if (IS_ERR(to)) { - error = PTR_ERR(to); - goto exit1; - } - - error = -EXDEV; - if (old_path.mnt != new_path.mnt) - goto exit2; - - error = -EBUSY; - if (old_type != LAST_NORM) - goto exit2; - - if (flags & RENAME_NOREPLACE) - error = -EEXIST; - if (new_type != LAST_NORM) - goto exit2; - - error = mnt_want_write(old_path.mnt); - if (error) - goto exit2; - -retry_deleg: - trap = lock_rename(new_path.dentry, old_path.dentry); - - old_dentry = __lookup_hash(&old_last, old_path.dentry, lookup_flags); - error = PTR_ERR(old_dentry); - if (IS_ERR(old_dentry)) - goto exit3; - /* source must exist */ - error = -ENOENT; - if (d_is_negative(old_dentry)) - goto exit4; - new_dentry = __lookup_hash(&new_last, new_path.dentry, lookup_flags | target_flags); - error = PTR_ERR(new_dentry); - if (IS_ERR(new_dentry)) - goto exit4; - error = -EEXIST; - if ((flags & RENAME_NOREPLACE) && d_is_positive(new_dentry)) - goto exit5; - if (flags & RENAME_EXCHANGE) { - error = -ENOENT; - if (d_is_negative(new_dentry)) - goto exit5; - - if (!d_is_dir(new_dentry)) { - error = -ENOTDIR; - if (new_last.name[new_last.len]) - goto exit5; - } - } - /* unless the source is a directory trailing slashes give -ENOTDIR */ - if (!d_is_dir(old_dentry)) { - error = -ENOTDIR; - if (old_last.name[old_last.len]) - goto exit5; - if (!(flags & RENAME_EXCHANGE) && new_last.name[new_last.len]) - goto exit5; - } - /* source should not be ancestor of target */ - error = -EINVAL; - if (old_dentry == trap) - goto exit5; - /* target should not be an ancestor of source */ - if (!(flags & RENAME_EXCHANGE)) - error = -ENOTEMPTY; - if (new_dentry == trap) - goto exit5; - - error = security_path_rename(&old_path, old_dentry, - &new_path, new_dentry, flags); - if (error) - goto exit5; - error = vfs_rename(old_path.dentry->d_inode, old_dentry, - new_path.dentry->d_inode, new_dentry, - &delegated_inode, flags); -exit5: - dput(new_dentry); -exit4: - dput(old_dentry); -exit3: - unlock_rename(new_path.dentry, old_path.dentry); - if (delegated_inode) { - error = break_deleg_wait(&delegated_inode); - if (!error) - goto retry_deleg; - } - mnt_drop_write(old_path.mnt); -exit2: - if (retry_estale(error, lookup_flags)) - should_retry = true; - path_put(&new_path); - putname(to); -exit1: - path_put(&old_path); - putname(from); - if (should_retry) { - should_retry = false; - lookup_flags |= LOOKUP_REVAL; - goto retry; - } -exit: - return error; -} - -SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname, - int, newdfd, const char __user *, newname) -{ - return sys_renameat2(olddfd, oldname, newdfd, newname, 0); -} - -SYSCALL_DEFINE2(rename, const char __user *, oldname, const char __user *, newname) -{ - return sys_renameat2(AT_FDCWD, oldname, AT_FDCWD, newname, 0); -} - -int vfs_whiteout(struct inode *dir, struct dentry *dentry) -{ - int error = may_create(dir, dentry); - if (error) - return error; - - if (!dir->i_op->mknod) - return -EPERM; - - return dir->i_op->mknod(dir, dentry, - S_IFCHR | WHITEOUT_MODE, WHITEOUT_DEV); -} -EXPORT_SYMBOL(vfs_whiteout); - -int readlink_copy(char __user *buffer, int buflen, const char *link) -{ - int len = PTR_ERR(link); - if (IS_ERR(link)) - goto out; - - len = strlen(link); - if (len > (unsigned) buflen) - len = buflen; - if (copy_to_user(buffer, link, len)) - len = -EFAULT; -out: - return len; -} - -/* - * A helper for ->readlink(). This should be used *ONLY* for symlinks that - * have ->get_link() not calling nd_jump_link(). Using (or not using) it - * for any given inode is up to filesystem. - */ -int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) -{ - DEFINE_DELAYED_CALL(done); - struct inode *inode = d_inode(dentry); - const char *link = inode->i_link; - int res; - - if (!link) { - link = inode->i_op->get_link(dentry, inode, &done); - if (IS_ERR(link)) - return PTR_ERR(link); - } - res = readlink_copy(buffer, buflen, link); - do_delayed_call(&done); - return res; -} -EXPORT_SYMBOL(generic_readlink); - -/** - * vfs_get_link - get symlink body - * @dentry: dentry on which to get symbolic link - * @done: caller needs to free returned data with this - * - * Calls security hook and i_op->get_link() on the supplied inode. - * - * It does not touch atime. That's up to the caller if necessary. - * - * Does not work on "special" symlinks like /proc/$$/fd/N - */ -const char *vfs_get_link(struct dentry *dentry, struct delayed_call *done) -{ - const char *res = ERR_PTR(-EINVAL); - struct inode *inode = d_inode(dentry); - - if (d_is_symlink(dentry)) { - res = ERR_PTR(security_inode_readlink(dentry)); - if (!res) - res = inode->i_op->get_link(dentry, inode, done); - } - return res; -} -EXPORT_SYMBOL(vfs_get_link); - -/* get the link contents into pagecache */ -const char *page_get_link(struct dentry *dentry, struct inode *inode, - struct delayed_call *callback) -{ - char *kaddr; - struct page *page; - struct address_space *mapping = inode->i_mapping; - - if (!dentry) { - page = find_get_page(mapping, 0); - if (!page) - return ERR_PTR(-ECHILD); - if (!PageUptodate(page)) { - put_page(page); - return ERR_PTR(-ECHILD); - } - } else { - page = read_mapping_page(mapping, 0, NULL); - if (IS_ERR(page)) - return (char*)page; - } - set_delayed_call(callback, page_put_link, page); - BUG_ON(mapping_gfp_mask(mapping) & __GFP_HIGHMEM); - kaddr = page_address(page); - nd_terminate_link(kaddr, inode->i_size, PAGE_SIZE - 1); - return kaddr; -} - -EXPORT_SYMBOL(page_get_link); - -void page_put_link(void *arg) -{ - put_page(arg); -} -EXPORT_SYMBOL(page_put_link); - -int page_readlink(struct dentry *dentry, char __user *buffer, int buflen) -{ - DEFINE_DELAYED_CALL(done); - int res = readlink_copy(buffer, buflen, - page_get_link(dentry, d_inode(dentry), - &done)); - do_delayed_call(&done); - return res; -} -EXPORT_SYMBOL(page_readlink); - -/* - * The nofs argument instructs pagecache_write_begin to pass AOP_FLAG_NOFS - */ -int __page_symlink(struct inode *inode, const char *symname, int len, int nofs) -{ - struct address_space *mapping = inode->i_mapping; - struct page *page; - void *fsdata; - int err; - unsigned int flags = AOP_FLAG_UNINTERRUPTIBLE; - if (nofs) - flags |= AOP_FLAG_NOFS; - -retry: - err = pagecache_write_begin(NULL, mapping, 0, len-1, - flags, &page, &fsdata); - if (err) - goto fail; - - memcpy(page_address(page), symname, len-1); - - err = pagecache_write_end(NULL, mapping, 0, len-1, len-1, - page, fsdata); - if (err < 0) - goto fail; - if (err < len-1) - goto retry; - - mark_inode_dirty(inode); - return 0; -fail: - return err; -} -EXPORT_SYMBOL(__page_symlink); - -int page_symlink(struct inode *inode, const char *symname, int len) -{ - return __page_symlink(inode, symname, len, - !mapping_gfp_constraint(inode->i_mapping, __GFP_FS)); -} -EXPORT_SYMBOL(page_symlink); - -const struct inode_operations page_symlink_inode_operations = { - .readlink = generic_readlink, - .get_link = page_get_link, -}; -EXPORT_SYMBOL(page_symlink_inode_operations); diff --git a/src/linux/fs/namespace.c b/src/linux/fs/namespace.c deleted file mode 100644 index e6c234b..0000000 --- a/src/linux/fs/namespace.c +++ /dev/null @@ -1,3431 +0,0 @@ -/* - * linux/fs/namespace.c - * - * (C) Copyright Al Viro 2000, 2001 - * Released under GPL v2. - * - * Based on code from fs/super.c, copyright Linus Torvalds and others. - * Heavily rewritten. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include /* init_rootfs */ -#include /* get_fs_root et.al. */ -#include /* fsnotify_vfsmount_delete */ -#include -#include -#include -#include -#include -#include "pnode.h" -#include "internal.h" - -/* Maximum number of mounts in a mount namespace */ -unsigned int sysctl_mount_max __read_mostly = 100000; - -static unsigned int m_hash_mask __read_mostly; -static unsigned int m_hash_shift __read_mostly; -static unsigned int mp_hash_mask __read_mostly; -static unsigned int mp_hash_shift __read_mostly; - -static __initdata unsigned long mhash_entries; -static int __init set_mhash_entries(char *str) -{ - if (!str) - return 0; - mhash_entries = simple_strtoul(str, &str, 0); - return 1; -} -__setup("mhash_entries=", set_mhash_entries); - -static __initdata unsigned long mphash_entries; -static int __init set_mphash_entries(char *str) -{ - if (!str) - return 0; - mphash_entries = simple_strtoul(str, &str, 0); - return 1; -} -__setup("mphash_entries=", set_mphash_entries); - -static u64 event; -static DEFINE_IDA(mnt_id_ida); -static DEFINE_IDA(mnt_group_ida); -static DEFINE_SPINLOCK(mnt_id_lock); -static int mnt_id_start = 0; -static int mnt_group_start = 1; - -static struct hlist_head *mount_hashtable __read_mostly; -static struct hlist_head *mountpoint_hashtable __read_mostly; -static struct kmem_cache *mnt_cache __read_mostly; -static DECLARE_RWSEM(namespace_sem); - -/* /sys/fs */ -struct kobject *fs_kobj; -EXPORT_SYMBOL_GPL(fs_kobj); - -/* - * vfsmount lock may be taken for read to prevent changes to the - * vfsmount hash, ie. during mountpoint lookups or walking back - * up the tree. - * - * It should be taken for write in all cases where the vfsmount - * tree or hash is modified or when a vfsmount structure is modified. - */ -__cacheline_aligned_in_smp DEFINE_SEQLOCK(mount_lock); - -static inline struct hlist_head *m_hash(struct vfsmount *mnt, struct dentry *dentry) -{ - unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES); - tmp += ((unsigned long)dentry / L1_CACHE_BYTES); - tmp = tmp + (tmp >> m_hash_shift); - return &mount_hashtable[tmp & m_hash_mask]; -} - -static inline struct hlist_head *mp_hash(struct dentry *dentry) -{ - unsigned long tmp = ((unsigned long)dentry / L1_CACHE_BYTES); - tmp = tmp + (tmp >> mp_hash_shift); - return &mountpoint_hashtable[tmp & mp_hash_mask]; -} - -/* - * allocation is serialized by namespace_sem, but we need the spinlock to - * serialize with freeing. - */ -static int mnt_alloc_id(struct mount *mnt) -{ - int res; - -retry: - ida_pre_get(&mnt_id_ida, GFP_KERNEL); - spin_lock(&mnt_id_lock); - res = ida_get_new_above(&mnt_id_ida, mnt_id_start, &mnt->mnt_id); - if (!res) - mnt_id_start = mnt->mnt_id + 1; - spin_unlock(&mnt_id_lock); - if (res == -EAGAIN) - goto retry; - - return res; -} - -static void mnt_free_id(struct mount *mnt) -{ - int id = mnt->mnt_id; - spin_lock(&mnt_id_lock); - ida_remove(&mnt_id_ida, id); - if (mnt_id_start > id) - mnt_id_start = id; - spin_unlock(&mnt_id_lock); -} - -/* - * Allocate a new peer group ID - * - * mnt_group_ida is protected by namespace_sem - */ -static int mnt_alloc_group_id(struct mount *mnt) -{ - int res; - - if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL)) - return -ENOMEM; - - res = ida_get_new_above(&mnt_group_ida, - mnt_group_start, - &mnt->mnt_group_id); - if (!res) - mnt_group_start = mnt->mnt_group_id + 1; - - return res; -} - -/* - * Release a peer group ID - */ -void mnt_release_group_id(struct mount *mnt) -{ - int id = mnt->mnt_group_id; - ida_remove(&mnt_group_ida, id); - if (mnt_group_start > id) - mnt_group_start = id; - mnt->mnt_group_id = 0; -} - -/* - * vfsmount lock must be held for read - */ -static inline void mnt_add_count(struct mount *mnt, int n) -{ -#ifdef CONFIG_SMP - this_cpu_add(mnt->mnt_pcp->mnt_count, n); -#else - preempt_disable(); - mnt->mnt_count += n; - preempt_enable(); -#endif -} - -/* - * vfsmount lock must be held for write - */ -unsigned int mnt_get_count(struct mount *mnt) -{ -#ifdef CONFIG_SMP - unsigned int count = 0; - int cpu; - - for_each_possible_cpu(cpu) { - count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_count; - } - - return count; -#else - return mnt->mnt_count; -#endif -} - -static void drop_mountpoint(struct fs_pin *p) -{ - struct mount *m = container_of(p, struct mount, mnt_umount); - dput(m->mnt_ex_mountpoint); - pin_remove(p); - mntput(&m->mnt); -} - -static struct mount *alloc_vfsmnt(const char *name) -{ - struct mount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); - if (mnt) { - int err; - - err = mnt_alloc_id(mnt); - if (err) - goto out_free_cache; - - if (name) { - mnt->mnt_devname = kstrdup_const(name, GFP_KERNEL); - if (!mnt->mnt_devname) - goto out_free_id; - } - -#ifdef CONFIG_SMP - mnt->mnt_pcp = alloc_percpu(struct mnt_pcp); - if (!mnt->mnt_pcp) - goto out_free_devname; - - this_cpu_add(mnt->mnt_pcp->mnt_count, 1); -#else - mnt->mnt_count = 1; - mnt->mnt_writers = 0; -#endif - - INIT_HLIST_NODE(&mnt->mnt_hash); - INIT_LIST_HEAD(&mnt->mnt_child); - INIT_LIST_HEAD(&mnt->mnt_mounts); - INIT_LIST_HEAD(&mnt->mnt_list); - INIT_LIST_HEAD(&mnt->mnt_expire); - INIT_LIST_HEAD(&mnt->mnt_share); - INIT_LIST_HEAD(&mnt->mnt_slave_list); - INIT_LIST_HEAD(&mnt->mnt_slave); - INIT_HLIST_NODE(&mnt->mnt_mp_list); -#ifdef CONFIG_FSNOTIFY - INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks); -#endif - init_fs_pin(&mnt->mnt_umount, drop_mountpoint); - } - return mnt; - -#ifdef CONFIG_SMP -out_free_devname: - kfree_const(mnt->mnt_devname); -#endif -out_free_id: - mnt_free_id(mnt); -out_free_cache: - kmem_cache_free(mnt_cache, mnt); - return NULL; -} - -/* - * Most r/o checks on a fs are for operations that take - * discrete amounts of time, like a write() or unlink(). - * We must keep track of when those operations start - * (for permission checks) and when they end, so that - * we can determine when writes are able to occur to - * a filesystem. - */ -/* - * __mnt_is_readonly: check whether a mount is read-only - * @mnt: the mount to check for its write status - * - * This shouldn't be used directly ouside of the VFS. - * It does not guarantee that the filesystem will stay - * r/w, just that it is right *now*. This can not and - * should not be used in place of IS_RDONLY(inode). - * mnt_want/drop_write() will _keep_ the filesystem - * r/w. - */ -int __mnt_is_readonly(struct vfsmount *mnt) -{ - if (mnt->mnt_flags & MNT_READONLY) - return 1; - if (mnt->mnt_sb->s_flags & MS_RDONLY) - return 1; - return 0; -} -EXPORT_SYMBOL_GPL(__mnt_is_readonly); - -static inline void mnt_inc_writers(struct mount *mnt) -{ -#ifdef CONFIG_SMP - this_cpu_inc(mnt->mnt_pcp->mnt_writers); -#else - mnt->mnt_writers++; -#endif -} - -static inline void mnt_dec_writers(struct mount *mnt) -{ -#ifdef CONFIG_SMP - this_cpu_dec(mnt->mnt_pcp->mnt_writers); -#else - mnt->mnt_writers--; -#endif -} - -static unsigned int mnt_get_writers(struct mount *mnt) -{ -#ifdef CONFIG_SMP - unsigned int count = 0; - int cpu; - - for_each_possible_cpu(cpu) { - count += per_cpu_ptr(mnt->mnt_pcp, cpu)->mnt_writers; - } - - return count; -#else - return mnt->mnt_writers; -#endif -} - -static int mnt_is_readonly(struct vfsmount *mnt) -{ - if (mnt->mnt_sb->s_readonly_remount) - return 1; - /* Order wrt setting s_flags/s_readonly_remount in do_remount() */ - smp_rmb(); - return __mnt_is_readonly(mnt); -} - -/* - * Most r/o & frozen checks on a fs are for operations that take discrete - * amounts of time, like a write() or unlink(). We must keep track of when - * those operations start (for permission checks) and when they end, so that we - * can determine when writes are able to occur to a filesystem. - */ -/** - * __mnt_want_write - get write access to a mount without freeze protection - * @m: the mount on which to take a write - * - * This tells the low-level filesystem that a write is about to be performed to - * it, and makes sure that writes are allowed (mnt it read-write) before - * returning success. This operation does not protect against filesystem being - * frozen. When the write operation is finished, __mnt_drop_write() must be - * called. This is effectively a refcount. - */ -int __mnt_want_write(struct vfsmount *m) -{ - struct mount *mnt = real_mount(m); - int ret = 0; - - preempt_disable(); - mnt_inc_writers(mnt); - /* - * The store to mnt_inc_writers must be visible before we pass - * MNT_WRITE_HOLD loop below, so that the slowpath can see our - * incremented count after it has set MNT_WRITE_HOLD. - */ - smp_mb(); - while (ACCESS_ONCE(mnt->mnt.mnt_flags) & MNT_WRITE_HOLD) - cpu_relax(); - /* - * After the slowpath clears MNT_WRITE_HOLD, mnt_is_readonly will - * be set to match its requirements. So we must not load that until - * MNT_WRITE_HOLD is cleared. - */ - smp_rmb(); - if (mnt_is_readonly(m)) { - mnt_dec_writers(mnt); - ret = -EROFS; - } - preempt_enable(); - - return ret; -} - -/** - * mnt_want_write - get write access to a mount - * @m: the mount on which to take a write - * - * This tells the low-level filesystem that a write is about to be performed to - * it, and makes sure that writes are allowed (mount is read-write, filesystem - * is not frozen) before returning success. When the write operation is - * finished, mnt_drop_write() must be called. This is effectively a refcount. - */ -int mnt_want_write(struct vfsmount *m) -{ - int ret; - - sb_start_write(m->mnt_sb); - ret = __mnt_want_write(m); - if (ret) - sb_end_write(m->mnt_sb); - return ret; -} -EXPORT_SYMBOL_GPL(mnt_want_write); - -/** - * mnt_clone_write - get write access to a mount - * @mnt: the mount on which to take a write - * - * This is effectively like mnt_want_write, except - * it must only be used to take an extra write reference - * on a mountpoint that we already know has a write reference - * on it. This allows some optimisation. - * - * After finished, mnt_drop_write must be called as usual to - * drop the reference. - */ -int mnt_clone_write(struct vfsmount *mnt) -{ - /* superblock may be r/o */ - if (__mnt_is_readonly(mnt)) - return -EROFS; - preempt_disable(); - mnt_inc_writers(real_mount(mnt)); - preempt_enable(); - return 0; -} -EXPORT_SYMBOL_GPL(mnt_clone_write); - -/** - * __mnt_want_write_file - get write access to a file's mount - * @file: the file who's mount on which to take a write - * - * This is like __mnt_want_write, but it takes a file and can - * do some optimisations if the file is open for write already - */ -int __mnt_want_write_file(struct file *file) -{ - if (!(file->f_mode & FMODE_WRITER)) - return __mnt_want_write(file->f_path.mnt); - else - return mnt_clone_write(file->f_path.mnt); -} - -/** - * mnt_want_write_file - get write access to a file's mount - * @file: the file who's mount on which to take a write - * - * This is like mnt_want_write, but it takes a file and can - * do some optimisations if the file is open for write already - */ -int mnt_want_write_file(struct file *file) -{ - int ret; - - sb_start_write(file->f_path.mnt->mnt_sb); - ret = __mnt_want_write_file(file); - if (ret) - sb_end_write(file->f_path.mnt->mnt_sb); - return ret; -} -EXPORT_SYMBOL_GPL(mnt_want_write_file); - -/** - * __mnt_drop_write - give up write access to a mount - * @mnt: the mount on which to give up write access - * - * Tells the low-level filesystem that we are done - * performing writes to it. Must be matched with - * __mnt_want_write() call above. - */ -void __mnt_drop_write(struct vfsmount *mnt) -{ - preempt_disable(); - mnt_dec_writers(real_mount(mnt)); - preempt_enable(); -} - -/** - * mnt_drop_write - give up write access to a mount - * @mnt: the mount on which to give up write access - * - * Tells the low-level filesystem that we are done performing writes to it and - * also allows filesystem to be frozen again. Must be matched with - * mnt_want_write() call above. - */ -void mnt_drop_write(struct vfsmount *mnt) -{ - __mnt_drop_write(mnt); - sb_end_write(mnt->mnt_sb); -} -EXPORT_SYMBOL_GPL(mnt_drop_write); - -void __mnt_drop_write_file(struct file *file) -{ - __mnt_drop_write(file->f_path.mnt); -} - -void mnt_drop_write_file(struct file *file) -{ - mnt_drop_write(file->f_path.mnt); -} -EXPORT_SYMBOL(mnt_drop_write_file); - -static int mnt_make_readonly(struct mount *mnt) -{ - int ret = 0; - - lock_mount_hash(); - mnt->mnt.mnt_flags |= MNT_WRITE_HOLD; - /* - * After storing MNT_WRITE_HOLD, we'll read the counters. This store - * should be visible before we do. - */ - smp_mb(); - - /* - * With writers on hold, if this value is zero, then there are - * definitely no active writers (although held writers may subsequently - * increment the count, they'll have to wait, and decrement it after - * seeing MNT_READONLY). - * - * It is OK to have counter incremented on one CPU and decremented on - * another: the sum will add up correctly. The danger would be when we - * sum up each counter, if we read a counter before it is incremented, - * but then read another CPU's count which it has been subsequently - * decremented from -- we would see more decrements than we should. - * MNT_WRITE_HOLD protects against this scenario, because - * mnt_want_write first increments count, then smp_mb, then spins on - * MNT_WRITE_HOLD, so it can't be decremented by another CPU while - * we're counting up here. - */ - if (mnt_get_writers(mnt) > 0) - ret = -EBUSY; - else - mnt->mnt.mnt_flags |= MNT_READONLY; - /* - * MNT_READONLY must become visible before ~MNT_WRITE_HOLD, so writers - * that become unheld will see MNT_READONLY. - */ - smp_wmb(); - mnt->mnt.mnt_flags &= ~MNT_WRITE_HOLD; - unlock_mount_hash(); - return ret; -} - -static void __mnt_unmake_readonly(struct mount *mnt) -{ - lock_mount_hash(); - mnt->mnt.mnt_flags &= ~MNT_READONLY; - unlock_mount_hash(); -} - -int sb_prepare_remount_readonly(struct super_block *sb) -{ - struct mount *mnt; - int err = 0; - - /* Racy optimization. Recheck the counter under MNT_WRITE_HOLD */ - if (atomic_long_read(&sb->s_remove_count)) - return -EBUSY; - - lock_mount_hash(); - list_for_each_entry(mnt, &sb->s_mounts, mnt_instance) { - if (!(mnt->mnt.mnt_flags & MNT_READONLY)) { - mnt->mnt.mnt_flags |= MNT_WRITE_HOLD; - smp_mb(); - if (mnt_get_writers(mnt) > 0) { - err = -EBUSY; - break; - } - } - } - if (!err && atomic_long_read(&sb->s_remove_count)) - err = -EBUSY; - - if (!err) { - sb->s_readonly_remount = 1; - smp_wmb(); - } - list_for_each_entry(mnt, &sb->s_mounts, mnt_instance) { - if (mnt->mnt.mnt_flags & MNT_WRITE_HOLD) - mnt->mnt.mnt_flags &= ~MNT_WRITE_HOLD; - } - unlock_mount_hash(); - - return err; -} - -static void free_vfsmnt(struct mount *mnt) -{ - kfree_const(mnt->mnt_devname); -#ifdef CONFIG_SMP - free_percpu(mnt->mnt_pcp); -#endif - kmem_cache_free(mnt_cache, mnt); -} - -static void delayed_free_vfsmnt(struct rcu_head *head) -{ - free_vfsmnt(container_of(head, struct mount, mnt_rcu)); -} - -/* call under rcu_read_lock */ -int __legitimize_mnt(struct vfsmount *bastard, unsigned seq) -{ - struct mount *mnt; - if (read_seqretry(&mount_lock, seq)) - return 1; - if (bastard == NULL) - return 0; - mnt = real_mount(bastard); - mnt_add_count(mnt, 1); - if (likely(!read_seqretry(&mount_lock, seq))) - return 0; - if (bastard->mnt_flags & MNT_SYNC_UMOUNT) { - mnt_add_count(mnt, -1); - return 1; - } - return -1; -} - -/* call under rcu_read_lock */ -bool legitimize_mnt(struct vfsmount *bastard, unsigned seq) -{ - int res = __legitimize_mnt(bastard, seq); - if (likely(!res)) - return true; - if (unlikely(res < 0)) { - rcu_read_unlock(); - mntput(bastard); - rcu_read_lock(); - } - return false; -} - -/* - * find the first mount at @dentry on vfsmount @mnt. - * call under rcu_read_lock() - */ -struct mount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) -{ - struct hlist_head *head = m_hash(mnt, dentry); - struct mount *p; - - hlist_for_each_entry_rcu(p, head, mnt_hash) - if (&p->mnt_parent->mnt == mnt && p->mnt_mountpoint == dentry) - return p; - return NULL; -} - -/* - * find the last mount at @dentry on vfsmount @mnt. - * mount_lock must be held. - */ -struct mount *__lookup_mnt_last(struct vfsmount *mnt, struct dentry *dentry) -{ - struct mount *p, *res = NULL; - p = __lookup_mnt(mnt, dentry); - if (!p) - goto out; - if (!(p->mnt.mnt_flags & MNT_UMOUNT)) - res = p; - hlist_for_each_entry_continue(p, mnt_hash) { - if (&p->mnt_parent->mnt != mnt || p->mnt_mountpoint != dentry) - break; - if (!(p->mnt.mnt_flags & MNT_UMOUNT)) - res = p; - } -out: - return res; -} - -/* - * lookup_mnt - Return the first child mount mounted at path - * - * "First" means first mounted chronologically. If you create the - * following mounts: - * - * mount /dev/sda1 /mnt - * mount /dev/sda2 /mnt - * mount /dev/sda3 /mnt - * - * Then lookup_mnt() on the base /mnt dentry in the root mount will - * return successively the root dentry and vfsmount of /dev/sda1, then - * /dev/sda2, then /dev/sda3, then NULL. - * - * lookup_mnt takes a reference to the found vfsmount. - */ -struct vfsmount *lookup_mnt(struct path *path) -{ - struct mount *child_mnt; - struct vfsmount *m; - unsigned seq; - - rcu_read_lock(); - do { - seq = read_seqbegin(&mount_lock); - child_mnt = __lookup_mnt(path->mnt, path->dentry); - m = child_mnt ? &child_mnt->mnt : NULL; - } while (!legitimize_mnt(m, seq)); - rcu_read_unlock(); - return m; -} - -/* - * __is_local_mountpoint - Test to see if dentry is a mountpoint in the - * current mount namespace. - * - * The common case is dentries are not mountpoints at all and that - * test is handled inline. For the slow case when we are actually - * dealing with a mountpoint of some kind, walk through all of the - * mounts in the current mount namespace and test to see if the dentry - * is a mountpoint. - * - * The mount_hashtable is not usable in the context because we - * need to identify all mounts that may be in the current mount - * namespace not just a mount that happens to have some specified - * parent mount. - */ -bool __is_local_mountpoint(struct dentry *dentry) -{ - struct mnt_namespace *ns = current->nsproxy->mnt_ns; - struct mount *mnt; - bool is_covered = false; - - if (!d_mountpoint(dentry)) - goto out; - - down_read(&namespace_sem); - list_for_each_entry(mnt, &ns->list, mnt_list) { - is_covered = (mnt->mnt_mountpoint == dentry); - if (is_covered) - break; - } - up_read(&namespace_sem); -out: - return is_covered; -} - -static struct mountpoint *lookup_mountpoint(struct dentry *dentry) -{ - struct hlist_head *chain = mp_hash(dentry); - struct mountpoint *mp; - - hlist_for_each_entry(mp, chain, m_hash) { - if (mp->m_dentry == dentry) { - /* might be worth a WARN_ON() */ - if (d_unlinked(dentry)) - return ERR_PTR(-ENOENT); - mp->m_count++; - return mp; - } - } - return NULL; -} - -static struct mountpoint *new_mountpoint(struct dentry *dentry) -{ - struct hlist_head *chain = mp_hash(dentry); - struct mountpoint *mp; - int ret; - - mp = kmalloc(sizeof(struct mountpoint), GFP_KERNEL); - if (!mp) - return ERR_PTR(-ENOMEM); - - ret = d_set_mounted(dentry); - if (ret) { - kfree(mp); - return ERR_PTR(ret); - } - - mp->m_dentry = dentry; - mp->m_count = 1; - hlist_add_head(&mp->m_hash, chain); - INIT_HLIST_HEAD(&mp->m_list); - return mp; -} - -static void put_mountpoint(struct mountpoint *mp) -{ - if (!--mp->m_count) { - struct dentry *dentry = mp->m_dentry; - BUG_ON(!hlist_empty(&mp->m_list)); - spin_lock(&dentry->d_lock); - dentry->d_flags &= ~DCACHE_MOUNTED; - spin_unlock(&dentry->d_lock); - hlist_del(&mp->m_hash); - kfree(mp); - } -} - -static inline int check_mnt(struct mount *mnt) -{ - return mnt->mnt_ns == current->nsproxy->mnt_ns; -} - -/* - * vfsmount lock must be held for write - */ -static void touch_mnt_namespace(struct mnt_namespace *ns) -{ - if (ns) { - ns->event = ++event; - wake_up_interruptible(&ns->poll); - } -} - -/* - * vfsmount lock must be held for write - */ -static void __touch_mnt_namespace(struct mnt_namespace *ns) -{ - if (ns && ns->event != event) { - ns->event = event; - wake_up_interruptible(&ns->poll); - } -} - -/* - * vfsmount lock must be held for write - */ -static void unhash_mnt(struct mount *mnt) -{ - mnt->mnt_parent = mnt; - mnt->mnt_mountpoint = mnt->mnt.mnt_root; - list_del_init(&mnt->mnt_child); - hlist_del_init_rcu(&mnt->mnt_hash); - hlist_del_init(&mnt->mnt_mp_list); - put_mountpoint(mnt->mnt_mp); - mnt->mnt_mp = NULL; -} - -/* - * vfsmount lock must be held for write - */ -static void detach_mnt(struct mount *mnt, struct path *old_path) -{ - old_path->dentry = mnt->mnt_mountpoint; - old_path->mnt = &mnt->mnt_parent->mnt; - unhash_mnt(mnt); -} - -/* - * vfsmount lock must be held for write - */ -static void umount_mnt(struct mount *mnt) -{ - /* old mountpoint will be dropped when we can do that */ - mnt->mnt_ex_mountpoint = mnt->mnt_mountpoint; - unhash_mnt(mnt); -} - -/* - * vfsmount lock must be held for write - */ -void mnt_set_mountpoint(struct mount *mnt, - struct mountpoint *mp, - struct mount *child_mnt) -{ - mp->m_count++; - mnt_add_count(mnt, 1); /* essentially, that's mntget */ - child_mnt->mnt_mountpoint = dget(mp->m_dentry); - child_mnt->mnt_parent = mnt; - child_mnt->mnt_mp = mp; - hlist_add_head(&child_mnt->mnt_mp_list, &mp->m_list); -} - -/* - * vfsmount lock must be held for write - */ -static void attach_mnt(struct mount *mnt, - struct mount *parent, - struct mountpoint *mp) -{ - mnt_set_mountpoint(parent, mp, mnt); - hlist_add_head_rcu(&mnt->mnt_hash, m_hash(&parent->mnt, mp->m_dentry)); - list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); -} - -static void attach_shadowed(struct mount *mnt, - struct mount *parent, - struct mount *shadows) -{ - if (shadows) { - hlist_add_behind_rcu(&mnt->mnt_hash, &shadows->mnt_hash); - list_add(&mnt->mnt_child, &shadows->mnt_child); - } else { - hlist_add_head_rcu(&mnt->mnt_hash, - m_hash(&parent->mnt, mnt->mnt_mountpoint)); - list_add_tail(&mnt->mnt_child, &parent->mnt_mounts); - } -} - -/* - * vfsmount lock must be held for write - */ -static void commit_tree(struct mount *mnt, struct mount *shadows) -{ - struct mount *parent = mnt->mnt_parent; - struct mount *m; - LIST_HEAD(head); - struct mnt_namespace *n = parent->mnt_ns; - - BUG_ON(parent == mnt); - - list_add_tail(&head, &mnt->mnt_list); - list_for_each_entry(m, &head, mnt_list) - m->mnt_ns = n; - - list_splice(&head, n->list.prev); - - n->mounts += n->pending_mounts; - n->pending_mounts = 0; - - attach_shadowed(mnt, parent, shadows); - touch_mnt_namespace(n); -} - -static struct mount *next_mnt(struct mount *p, struct mount *root) -{ - struct list_head *next = p->mnt_mounts.next; - if (next == &p->mnt_mounts) { - while (1) { - if (p == root) - return NULL; - next = p->mnt_child.next; - if (next != &p->mnt_parent->mnt_mounts) - break; - p = p->mnt_parent; - } - } - return list_entry(next, struct mount, mnt_child); -} - -static struct mount *skip_mnt_tree(struct mount *p) -{ - struct list_head *prev = p->mnt_mounts.prev; - while (prev != &p->mnt_mounts) { - p = list_entry(prev, struct mount, mnt_child); - prev = p->mnt_mounts.prev; - } - return p; -} - -struct vfsmount * -vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) -{ - struct mount *mnt; - struct dentry *root; - - if (!type) - return ERR_PTR(-ENODEV); - - mnt = alloc_vfsmnt(name); - if (!mnt) - return ERR_PTR(-ENOMEM); - - if (flags & MS_KERNMOUNT) - mnt->mnt.mnt_flags = MNT_INTERNAL; - - root = mount_fs(type, flags, name, data); - if (IS_ERR(root)) { - mnt_free_id(mnt); - free_vfsmnt(mnt); - return ERR_CAST(root); - } - - mnt->mnt.mnt_root = root; - mnt->mnt.mnt_sb = root->d_sb; - mnt->mnt_mountpoint = mnt->mnt.mnt_root; - mnt->mnt_parent = mnt; - lock_mount_hash(); - list_add_tail(&mnt->mnt_instance, &root->d_sb->s_mounts); - unlock_mount_hash(); - return &mnt->mnt; -} -EXPORT_SYMBOL_GPL(vfs_kern_mount); - -static struct mount *clone_mnt(struct mount *old, struct dentry *root, - int flag) -{ - struct super_block *sb = old->mnt.mnt_sb; - struct mount *mnt; - int err; - - mnt = alloc_vfsmnt(old->mnt_devname); - if (!mnt) - return ERR_PTR(-ENOMEM); - - if (flag & (CL_SLAVE | CL_PRIVATE | CL_SHARED_TO_SLAVE)) - mnt->mnt_group_id = 0; /* not a peer of original */ - else - mnt->mnt_group_id = old->mnt_group_id; - - if ((flag & CL_MAKE_SHARED) && !mnt->mnt_group_id) { - err = mnt_alloc_group_id(mnt); - if (err) - goto out_free; - } - - mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~(MNT_WRITE_HOLD|MNT_MARKED); - /* Don't allow unprivileged users to change mount flags */ - if (flag & CL_UNPRIVILEGED) { - mnt->mnt.mnt_flags |= MNT_LOCK_ATIME; - - if (mnt->mnt.mnt_flags & MNT_READONLY) - mnt->mnt.mnt_flags |= MNT_LOCK_READONLY; - - if (mnt->mnt.mnt_flags & MNT_NODEV) - mnt->mnt.mnt_flags |= MNT_LOCK_NODEV; - - if (mnt->mnt.mnt_flags & MNT_NOSUID) - mnt->mnt.mnt_flags |= MNT_LOCK_NOSUID; - - if (mnt->mnt.mnt_flags & MNT_NOEXEC) - mnt->mnt.mnt_flags |= MNT_LOCK_NOEXEC; - } - - /* Don't allow unprivileged users to reveal what is under a mount */ - if ((flag & CL_UNPRIVILEGED) && - (!(flag & CL_EXPIRE) || list_empty(&old->mnt_expire))) - mnt->mnt.mnt_flags |= MNT_LOCKED; - - atomic_inc(&sb->s_active); - mnt->mnt.mnt_sb = sb; - mnt->mnt.mnt_root = dget(root); - mnt->mnt_mountpoint = mnt->mnt.mnt_root; - mnt->mnt_parent = mnt; - lock_mount_hash(); - list_add_tail(&mnt->mnt_instance, &sb->s_mounts); - unlock_mount_hash(); - - if ((flag & CL_SLAVE) || - ((flag & CL_SHARED_TO_SLAVE) && IS_MNT_SHARED(old))) { - list_add(&mnt->mnt_slave, &old->mnt_slave_list); - mnt->mnt_master = old; - CLEAR_MNT_SHARED(mnt); - } else if (!(flag & CL_PRIVATE)) { - if ((flag & CL_MAKE_SHARED) || IS_MNT_SHARED(old)) - list_add(&mnt->mnt_share, &old->mnt_share); - if (IS_MNT_SLAVE(old)) - list_add(&mnt->mnt_slave, &old->mnt_slave); - mnt->mnt_master = old->mnt_master; - } - if (flag & CL_MAKE_SHARED) - set_mnt_shared(mnt); - - /* stick the duplicate mount on the same expiry list - * as the original if that was on one */ - if (flag & CL_EXPIRE) { - if (!list_empty(&old->mnt_expire)) - list_add(&mnt->mnt_expire, &old->mnt_expire); - } - - return mnt; - - out_free: - mnt_free_id(mnt); - free_vfsmnt(mnt); - return ERR_PTR(err); -} - -static void cleanup_mnt(struct mount *mnt) -{ - /* - * This probably indicates that somebody messed - * up a mnt_want/drop_write() pair. If this - * happens, the filesystem was probably unable - * to make r/w->r/o transitions. - */ - /* - * The locking used to deal with mnt_count decrement provides barriers, - * so mnt_get_writers() below is safe. - */ - WARN_ON(mnt_get_writers(mnt)); - if (unlikely(mnt->mnt_pins.first)) - mnt_pin_kill(mnt); - fsnotify_vfsmount_delete(&mnt->mnt); - dput(mnt->mnt.mnt_root); - deactivate_super(mnt->mnt.mnt_sb); - mnt_free_id(mnt); - call_rcu(&mnt->mnt_rcu, delayed_free_vfsmnt); -} - -static void __cleanup_mnt(struct rcu_head *head) -{ - cleanup_mnt(container_of(head, struct mount, mnt_rcu)); -} - -static LLIST_HEAD(delayed_mntput_list); -static void delayed_mntput(struct work_struct *unused) -{ - struct llist_node *node = llist_del_all(&delayed_mntput_list); - struct llist_node *next; - - for (; node; node = next) { - next = llist_next(node); - cleanup_mnt(llist_entry(node, struct mount, mnt_llist)); - } -} -static DECLARE_DELAYED_WORK(delayed_mntput_work, delayed_mntput); - -static void mntput_no_expire(struct mount *mnt) -{ - rcu_read_lock(); - mnt_add_count(mnt, -1); - if (likely(mnt->mnt_ns)) { /* shouldn't be the last one */ - rcu_read_unlock(); - return; - } - lock_mount_hash(); - if (mnt_get_count(mnt)) { - rcu_read_unlock(); - unlock_mount_hash(); - return; - } - if (unlikely(mnt->mnt.mnt_flags & MNT_DOOMED)) { - rcu_read_unlock(); - unlock_mount_hash(); - return; - } - mnt->mnt.mnt_flags |= MNT_DOOMED; - rcu_read_unlock(); - - list_del(&mnt->mnt_instance); - - if (unlikely(!list_empty(&mnt->mnt_mounts))) { - struct mount *p, *tmp; - list_for_each_entry_safe(p, tmp, &mnt->mnt_mounts, mnt_child) { - umount_mnt(p); - } - } - unlock_mount_hash(); - - if (likely(!(mnt->mnt.mnt_flags & MNT_INTERNAL))) { - struct task_struct *task = current; - if (likely(!(task->flags & PF_KTHREAD))) { - init_task_work(&mnt->mnt_rcu, __cleanup_mnt); - if (!task_work_add(task, &mnt->mnt_rcu, true)) - return; - } - if (llist_add(&mnt->mnt_llist, &delayed_mntput_list)) - schedule_delayed_work(&delayed_mntput_work, 1); - return; - } - cleanup_mnt(mnt); -} - -void mntput(struct vfsmount *mnt) -{ - if (mnt) { - struct mount *m = real_mount(mnt); - /* avoid cacheline pingpong, hope gcc doesn't get "smart" */ - if (unlikely(m->mnt_expiry_mark)) - m->mnt_expiry_mark = 0; - mntput_no_expire(m); - } -} -EXPORT_SYMBOL(mntput); - -struct vfsmount *mntget(struct vfsmount *mnt) -{ - if (mnt) - mnt_add_count(real_mount(mnt), 1); - return mnt; -} -EXPORT_SYMBOL(mntget); - -struct vfsmount *mnt_clone_internal(struct path *path) -{ - struct mount *p; - p = clone_mnt(real_mount(path->mnt), path->dentry, CL_PRIVATE); - if (IS_ERR(p)) - return ERR_CAST(p); - p->mnt.mnt_flags |= MNT_INTERNAL; - return &p->mnt; -} - -static inline void mangle(struct seq_file *m, const char *s) -{ - seq_escape(m, s, " \t\n\\"); -} - -/* - * Simple .show_options callback for filesystems which don't want to - * implement more complex mount option showing. - * - * See also save_mount_options(). - */ -int generic_show_options(struct seq_file *m, struct dentry *root) -{ - const char *options; - - rcu_read_lock(); - options = rcu_dereference(root->d_sb->s_options); - - if (options != NULL && options[0]) { - seq_putc(m, ','); - mangle(m, options); - } - rcu_read_unlock(); - - return 0; -} -EXPORT_SYMBOL(generic_show_options); - -/* - * If filesystem uses generic_show_options(), this function should be - * called from the fill_super() callback. - * - * The .remount_fs callback usually needs to be handled in a special - * way, to make sure, that previous options are not overwritten if the - * remount fails. - * - * Also note, that if the filesystem's .remount_fs function doesn't - * reset all options to their default value, but changes only newly - * given options, then the displayed options will not reflect reality - * any more. - */ -void save_mount_options(struct super_block *sb, char *options) -{ - BUG_ON(sb->s_options); - rcu_assign_pointer(sb->s_options, kstrdup(options, GFP_KERNEL)); -} -EXPORT_SYMBOL(save_mount_options); - -void replace_mount_options(struct super_block *sb, char *options) -{ - char *old = sb->s_options; - rcu_assign_pointer(sb->s_options, options); - if (old) { - synchronize_rcu(); - kfree(old); - } -} -EXPORT_SYMBOL(replace_mount_options); - -#ifdef CONFIG_PROC_FS -/* iterator; we want it to have access to namespace_sem, thus here... */ -static void *m_start(struct seq_file *m, loff_t *pos) -{ - struct proc_mounts *p = m->private; - - down_read(&namespace_sem); - if (p->cached_event == p->ns->event) { - void *v = p->cached_mount; - if (*pos == p->cached_index) - return v; - if (*pos == p->cached_index + 1) { - v = seq_list_next(v, &p->ns->list, &p->cached_index); - return p->cached_mount = v; - } - } - - p->cached_event = p->ns->event; - p->cached_mount = seq_list_start(&p->ns->list, *pos); - p->cached_index = *pos; - return p->cached_mount; -} - -static void *m_next(struct seq_file *m, void *v, loff_t *pos) -{ - struct proc_mounts *p = m->private; - - p->cached_mount = seq_list_next(v, &p->ns->list, pos); - p->cached_index = *pos; - return p->cached_mount; -} - -static void m_stop(struct seq_file *m, void *v) -{ - up_read(&namespace_sem); -} - -static int m_show(struct seq_file *m, void *v) -{ - struct proc_mounts *p = m->private; - struct mount *r = list_entry(v, struct mount, mnt_list); - return p->show(m, &r->mnt); -} - -const struct seq_operations mounts_op = { - .start = m_start, - .next = m_next, - .stop = m_stop, - .show = m_show, -}; -#endif /* CONFIG_PROC_FS */ - -/** - * may_umount_tree - check if a mount tree is busy - * @mnt: root of mount tree - * - * This is called to check if a tree of mounts has any - * open files, pwds, chroots or sub mounts that are - * busy. - */ -int may_umount_tree(struct vfsmount *m) -{ - struct mount *mnt = real_mount(m); - int actual_refs = 0; - int minimum_refs = 0; - struct mount *p; - BUG_ON(!m); - - /* write lock needed for mnt_get_count */ - lock_mount_hash(); - for (p = mnt; p; p = next_mnt(p, mnt)) { - actual_refs += mnt_get_count(p); - minimum_refs += 2; - } - unlock_mount_hash(); - - if (actual_refs > minimum_refs) - return 0; - - return 1; -} - -EXPORT_SYMBOL(may_umount_tree); - -/** - * may_umount - check if a mount point is busy - * @mnt: root of mount - * - * This is called to check if a mount point has any - * open files, pwds, chroots or sub mounts. If the - * mount has sub mounts this will return busy - * regardless of whether the sub mounts are busy. - * - * Doesn't take quota and stuff into account. IOW, in some cases it will - * give false negatives. The main reason why it's here is that we need - * a non-destructive way to look for easily umountable filesystems. - */ -int may_umount(struct vfsmount *mnt) -{ - int ret = 1; - down_read(&namespace_sem); - lock_mount_hash(); - if (propagate_mount_busy(real_mount(mnt), 2)) - ret = 0; - unlock_mount_hash(); - up_read(&namespace_sem); - return ret; -} - -EXPORT_SYMBOL(may_umount); - -static HLIST_HEAD(unmounted); /* protected by namespace_sem */ - -static void namespace_unlock(void) -{ - struct hlist_head head; - - hlist_move_list(&unmounted, &head); - - up_write(&namespace_sem); - - if (likely(hlist_empty(&head))) - return; - - synchronize_rcu(); - - group_pin_kill(&head); -} - -static inline void namespace_lock(void) -{ - down_write(&namespace_sem); -} - -enum umount_tree_flags { - UMOUNT_SYNC = 1, - UMOUNT_PROPAGATE = 2, - UMOUNT_CONNECTED = 4, -}; - -static bool disconnect_mount(struct mount *mnt, enum umount_tree_flags how) -{ - /* Leaving mounts connected is only valid for lazy umounts */ - if (how & UMOUNT_SYNC) - return true; - - /* A mount without a parent has nothing to be connected to */ - if (!mnt_has_parent(mnt)) - return true; - - /* Because the reference counting rules change when mounts are - * unmounted and connected, umounted mounts may not be - * connected to mounted mounts. - */ - if (!(mnt->mnt_parent->mnt.mnt_flags & MNT_UMOUNT)) - return true; - - /* Has it been requested that the mount remain connected? */ - if (how & UMOUNT_CONNECTED) - return false; - - /* Is the mount locked such that it needs to remain connected? */ - if (IS_MNT_LOCKED(mnt)) - return false; - - /* By default disconnect the mount */ - return true; -} - -/* - * mount_lock must be held - * namespace_sem must be held for write - */ -static void umount_tree(struct mount *mnt, enum umount_tree_flags how) -{ - LIST_HEAD(tmp_list); - struct mount *p; - - if (how & UMOUNT_PROPAGATE) - propagate_mount_unlock(mnt); - - /* Gather the mounts to umount */ - for (p = mnt; p; p = next_mnt(p, mnt)) { - p->mnt.mnt_flags |= MNT_UMOUNT; - list_move(&p->mnt_list, &tmp_list); - } - - /* Hide the mounts from mnt_mounts */ - list_for_each_entry(p, &tmp_list, mnt_list) { - list_del_init(&p->mnt_child); - } - - /* Add propogated mounts to the tmp_list */ - if (how & UMOUNT_PROPAGATE) - propagate_umount(&tmp_list); - - while (!list_empty(&tmp_list)) { - struct mnt_namespace *ns; - bool disconnect; - p = list_first_entry(&tmp_list, struct mount, mnt_list); - list_del_init(&p->mnt_expire); - list_del_init(&p->mnt_list); - ns = p->mnt_ns; - if (ns) { - ns->mounts--; - __touch_mnt_namespace(ns); - } - p->mnt_ns = NULL; - if (how & UMOUNT_SYNC) - p->mnt.mnt_flags |= MNT_SYNC_UMOUNT; - - disconnect = disconnect_mount(p, how); - - pin_insert_group(&p->mnt_umount, &p->mnt_parent->mnt, - disconnect ? &unmounted : NULL); - if (mnt_has_parent(p)) { - mnt_add_count(p->mnt_parent, -1); - if (!disconnect) { - /* Don't forget about p */ - list_add_tail(&p->mnt_child, &p->mnt_parent->mnt_mounts); - } else { - umount_mnt(p); - } - } - change_mnt_propagation(p, MS_PRIVATE); - } -} - -static void shrink_submounts(struct mount *mnt); - -static int do_umount(struct mount *mnt, int flags) -{ - struct super_block *sb = mnt->mnt.mnt_sb; - int retval; - - retval = security_sb_umount(&mnt->mnt, flags); - if (retval) - return retval; - - /* - * Allow userspace to request a mountpoint be expired rather than - * unmounting unconditionally. Unmount only happens if: - * (1) the mark is already set (the mark is cleared by mntput()) - * (2) the usage count == 1 [parent vfsmount] + 1 [sys_umount] - */ - if (flags & MNT_EXPIRE) { - if (&mnt->mnt == current->fs->root.mnt || - flags & (MNT_FORCE | MNT_DETACH)) - return -EINVAL; - - /* - * probably don't strictly need the lock here if we examined - * all race cases, but it's a slowpath. - */ - lock_mount_hash(); - if (mnt_get_count(mnt) != 2) { - unlock_mount_hash(); - return -EBUSY; - } - unlock_mount_hash(); - - if (!xchg(&mnt->mnt_expiry_mark, 1)) - return -EAGAIN; - } - - /* - * If we may have to abort operations to get out of this - * mount, and they will themselves hold resources we must - * allow the fs to do things. In the Unix tradition of - * 'Gee thats tricky lets do it in userspace' the umount_begin - * might fail to complete on the first run through as other tasks - * must return, and the like. Thats for the mount program to worry - * about for the moment. - */ - - if (flags & MNT_FORCE && sb->s_op->umount_begin) { - sb->s_op->umount_begin(sb); - } - - /* - * No sense to grab the lock for this test, but test itself looks - * somewhat bogus. Suggestions for better replacement? - * Ho-hum... In principle, we might treat that as umount + switch - * to rootfs. GC would eventually take care of the old vfsmount. - * Actually it makes sense, especially if rootfs would contain a - * /reboot - static binary that would close all descriptors and - * call reboot(9). Then init(8) could umount root and exec /reboot. - */ - if (&mnt->mnt == current->fs->root.mnt && !(flags & MNT_DETACH)) { - /* - * Special case for "unmounting" root ... - * we just try to remount it readonly. - */ - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - down_write(&sb->s_umount); - if (!(sb->s_flags & MS_RDONLY)) - retval = do_remount_sb(sb, MS_RDONLY, NULL, 0); - up_write(&sb->s_umount); - return retval; - } - - namespace_lock(); - lock_mount_hash(); - event++; - - if (flags & MNT_DETACH) { - if (!list_empty(&mnt->mnt_list)) - umount_tree(mnt, UMOUNT_PROPAGATE); - retval = 0; - } else { - shrink_submounts(mnt); - retval = -EBUSY; - if (!propagate_mount_busy(mnt, 2)) { - if (!list_empty(&mnt->mnt_list)) - umount_tree(mnt, UMOUNT_PROPAGATE|UMOUNT_SYNC); - retval = 0; - } - } - unlock_mount_hash(); - namespace_unlock(); - return retval; -} - -/* - * __detach_mounts - lazily unmount all mounts on the specified dentry - * - * During unlink, rmdir, and d_drop it is possible to loose the path - * to an existing mountpoint, and wind up leaking the mount. - * detach_mounts allows lazily unmounting those mounts instead of - * leaking them. - * - * The caller may hold dentry->d_inode->i_mutex. - */ -void __detach_mounts(struct dentry *dentry) -{ - struct mountpoint *mp; - struct mount *mnt; - - namespace_lock(); - mp = lookup_mountpoint(dentry); - if (IS_ERR_OR_NULL(mp)) - goto out_unlock; - - lock_mount_hash(); - event++; - while (!hlist_empty(&mp->m_list)) { - mnt = hlist_entry(mp->m_list.first, struct mount, mnt_mp_list); - if (mnt->mnt.mnt_flags & MNT_UMOUNT) { - hlist_add_head(&mnt->mnt_umount.s_list, &unmounted); - umount_mnt(mnt); - } - else umount_tree(mnt, UMOUNT_CONNECTED); - } - unlock_mount_hash(); - put_mountpoint(mp); -out_unlock: - namespace_unlock(); -} - -/* - * Is the caller allowed to modify his namespace? - */ -static inline bool may_mount(void) -{ - return ns_capable(current->nsproxy->mnt_ns->user_ns, CAP_SYS_ADMIN); -} - -static inline bool may_mandlock(void) -{ -#ifndef CONFIG_MANDATORY_FILE_LOCKING - return false; -#endif - return capable(CAP_SYS_ADMIN); -} - -/* - * Now umount can handle mount points as well as block devices. - * This is important for filesystems which use unnamed block devices. - * - * We now support a flag for forced unmount like the other 'big iron' - * unixes. Our API is identical to OSF/1 to avoid making a mess of AMD - */ - -SYSCALL_DEFINE2(umount, char __user *, name, int, flags) -{ - struct path path; - struct mount *mnt; - int retval; - int lookup_flags = 0; - - if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW)) - return -EINVAL; - - if (!may_mount()) - return -EPERM; - - if (!(flags & UMOUNT_NOFOLLOW)) - lookup_flags |= LOOKUP_FOLLOW; - - retval = user_path_mountpoint_at(AT_FDCWD, name, lookup_flags, &path); - if (retval) - goto out; - mnt = real_mount(path.mnt); - retval = -EINVAL; - if (path.dentry != path.mnt->mnt_root) - goto dput_and_out; - if (!check_mnt(mnt)) - goto dput_and_out; - if (mnt->mnt.mnt_flags & MNT_LOCKED) - goto dput_and_out; - retval = -EPERM; - if (flags & MNT_FORCE && !capable(CAP_SYS_ADMIN)) - goto dput_and_out; - - retval = do_umount(mnt, flags); -dput_and_out: - /* we mustn't call path_put() as that would clear mnt_expiry_mark */ - dput(path.dentry); - mntput_no_expire(mnt); -out: - return retval; -} - -#ifdef __ARCH_WANT_SYS_OLDUMOUNT - -/* - * The 2.0 compatible umount. No flags. - */ -SYSCALL_DEFINE1(oldumount, char __user *, name) -{ - return sys_umount(name, 0); -} - -#endif - -static bool is_mnt_ns_file(struct dentry *dentry) -{ - /* Is this a proxy for a mount namespace? */ - return dentry->d_op == &ns_dentry_operations && - dentry->d_fsdata == &mntns_operations; -} - -struct mnt_namespace *to_mnt_ns(struct ns_common *ns) -{ - return container_of(ns, struct mnt_namespace, ns); -} - -static bool mnt_ns_loop(struct dentry *dentry) -{ - /* Could bind mounting the mount namespace inode cause a - * mount namespace loop? - */ - struct mnt_namespace *mnt_ns; - if (!is_mnt_ns_file(dentry)) - return false; - - mnt_ns = to_mnt_ns(get_proc_ns(dentry->d_inode)); - return current->nsproxy->mnt_ns->seq >= mnt_ns->seq; -} - -struct mount *copy_tree(struct mount *mnt, struct dentry *dentry, - int flag) -{ - struct mount *res, *p, *q, *r, *parent; - - if (!(flag & CL_COPY_UNBINDABLE) && IS_MNT_UNBINDABLE(mnt)) - return ERR_PTR(-EINVAL); - - if (!(flag & CL_COPY_MNT_NS_FILE) && is_mnt_ns_file(dentry)) - return ERR_PTR(-EINVAL); - - res = q = clone_mnt(mnt, dentry, flag); - if (IS_ERR(q)) - return q; - - q->mnt_mountpoint = mnt->mnt_mountpoint; - - p = mnt; - list_for_each_entry(r, &mnt->mnt_mounts, mnt_child) { - struct mount *s; - if (!is_subdir(r->mnt_mountpoint, dentry)) - continue; - - for (s = r; s; s = next_mnt(s, r)) { - struct mount *t = NULL; - if (!(flag & CL_COPY_UNBINDABLE) && - IS_MNT_UNBINDABLE(s)) { - s = skip_mnt_tree(s); - continue; - } - if (!(flag & CL_COPY_MNT_NS_FILE) && - is_mnt_ns_file(s->mnt.mnt_root)) { - s = skip_mnt_tree(s); - continue; - } - while (p != s->mnt_parent) { - p = p->mnt_parent; - q = q->mnt_parent; - } - p = s; - parent = q; - q = clone_mnt(p, p->mnt.mnt_root, flag); - if (IS_ERR(q)) - goto out; - lock_mount_hash(); - list_add_tail(&q->mnt_list, &res->mnt_list); - mnt_set_mountpoint(parent, p->mnt_mp, q); - if (!list_empty(&parent->mnt_mounts)) { - t = list_last_entry(&parent->mnt_mounts, - struct mount, mnt_child); - if (t->mnt_mp != p->mnt_mp) - t = NULL; - } - attach_shadowed(q, parent, t); - unlock_mount_hash(); - } - } - return res; -out: - if (res) { - lock_mount_hash(); - umount_tree(res, UMOUNT_SYNC); - unlock_mount_hash(); - } - return q; -} - -/* Caller should check returned pointer for errors */ - -struct vfsmount *collect_mounts(struct path *path) -{ - struct mount *tree; - namespace_lock(); - if (!check_mnt(real_mount(path->mnt))) - tree = ERR_PTR(-EINVAL); - else - tree = copy_tree(real_mount(path->mnt), path->dentry, - CL_COPY_ALL | CL_PRIVATE); - namespace_unlock(); - if (IS_ERR(tree)) - return ERR_CAST(tree); - return &tree->mnt; -} - -void drop_collected_mounts(struct vfsmount *mnt) -{ - namespace_lock(); - lock_mount_hash(); - umount_tree(real_mount(mnt), UMOUNT_SYNC); - unlock_mount_hash(); - namespace_unlock(); -} - -/** - * clone_private_mount - create a private clone of a path - * - * This creates a new vfsmount, which will be the clone of @path. The new will - * not be attached anywhere in the namespace and will be private (i.e. changes - * to the originating mount won't be propagated into this). - * - * Release with mntput(). - */ -struct vfsmount *clone_private_mount(struct path *path) -{ - struct mount *old_mnt = real_mount(path->mnt); - struct mount *new_mnt; - - if (IS_MNT_UNBINDABLE(old_mnt)) - return ERR_PTR(-EINVAL); - - down_read(&namespace_sem); - new_mnt = clone_mnt(old_mnt, path->dentry, CL_PRIVATE); - up_read(&namespace_sem); - if (IS_ERR(new_mnt)) - return ERR_CAST(new_mnt); - - return &new_mnt->mnt; -} -EXPORT_SYMBOL_GPL(clone_private_mount); - -int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg, - struct vfsmount *root) -{ - struct mount *mnt; - int res = f(root, arg); - if (res) - return res; - list_for_each_entry(mnt, &real_mount(root)->mnt_list, mnt_list) { - res = f(&mnt->mnt, arg); - if (res) - return res; - } - return 0; -} - -static void cleanup_group_ids(struct mount *mnt, struct mount *end) -{ - struct mount *p; - - for (p = mnt; p != end; p = next_mnt(p, mnt)) { - if (p->mnt_group_id && !IS_MNT_SHARED(p)) - mnt_release_group_id(p); - } -} - -static int invent_group_ids(struct mount *mnt, bool recurse) -{ - struct mount *p; - - for (p = mnt; p; p = recurse ? next_mnt(p, mnt) : NULL) { - if (!p->mnt_group_id && !IS_MNT_SHARED(p)) { - int err = mnt_alloc_group_id(p); - if (err) { - cleanup_group_ids(mnt, p); - return err; - } - } - } - - return 0; -} - -int count_mounts(struct mnt_namespace *ns, struct mount *mnt) -{ - unsigned int max = READ_ONCE(sysctl_mount_max); - unsigned int mounts = 0, old, pending, sum; - struct mount *p; - - for (p = mnt; p; p = next_mnt(p, mnt)) - mounts++; - - old = ns->mounts; - pending = ns->pending_mounts; - sum = old + pending; - if ((old > sum) || - (pending > sum) || - (max < sum) || - (mounts > (max - sum))) - return -ENOSPC; - - ns->pending_mounts = pending + mounts; - return 0; -} - -/* - * @source_mnt : mount tree to be attached - * @nd : place the mount tree @source_mnt is attached - * @parent_nd : if non-null, detach the source_mnt from its parent and - * store the parent mount and mountpoint dentry. - * (done when source_mnt is moved) - * - * NOTE: in the table below explains the semantics when a source mount - * of a given type is attached to a destination mount of a given type. - * --------------------------------------------------------------------------- - * | BIND MOUNT OPERATION | - * |************************************************************************** - * | source-->| shared | private | slave | unbindable | - * | dest | | | | | - * | | | | | | | - * | v | | | | | - * |************************************************************************** - * | shared | shared (++) | shared (+) | shared(+++)| invalid | - * | | | | | | - * |non-shared| shared (+) | private | slave (*) | invalid | - * *************************************************************************** - * A bind operation clones the source mount and mounts the clone on the - * destination mount. - * - * (++) the cloned mount is propagated to all the mounts in the propagation - * tree of the destination mount and the cloned mount is added to - * the peer group of the source mount. - * (+) the cloned mount is created under the destination mount and is marked - * as shared. The cloned mount is added to the peer group of the source - * mount. - * (+++) the mount is propagated to all the mounts in the propagation tree - * of the destination mount and the cloned mount is made slave - * of the same master as that of the source mount. The cloned mount - * is marked as 'shared and slave'. - * (*) the cloned mount is made a slave of the same master as that of the - * source mount. - * - * --------------------------------------------------------------------------- - * | MOVE MOUNT OPERATION | - * |************************************************************************** - * | source-->| shared | private | slave | unbindable | - * | dest | | | | | - * | | | | | | | - * | v | | | | | - * |************************************************************************** - * | shared | shared (+) | shared (+) | shared(+++) | invalid | - * | | | | | | - * |non-shared| shared (+*) | private | slave (*) | unbindable | - * *************************************************************************** - * - * (+) the mount is moved to the destination. And is then propagated to - * all the mounts in the propagation tree of the destination mount. - * (+*) the mount is moved to the destination. - * (+++) the mount is moved to the destination and is then propagated to - * all the mounts belonging to the destination mount's propagation tree. - * the mount is marked as 'shared and slave'. - * (*) the mount continues to be a slave at the new location. - * - * if the source mount is a tree, the operations explained above is - * applied to each mount in the tree. - * Must be called without spinlocks held, since this function can sleep - * in allocations. - */ -static int attach_recursive_mnt(struct mount *source_mnt, - struct mount *dest_mnt, - struct mountpoint *dest_mp, - struct path *parent_path) -{ - HLIST_HEAD(tree_list); - struct mnt_namespace *ns = dest_mnt->mnt_ns; - struct mount *child, *p; - struct hlist_node *n; - int err; - - /* Is there space to add these mounts to the mount namespace? */ - if (!parent_path) { - err = count_mounts(ns, source_mnt); - if (err) - goto out; - } - - if (IS_MNT_SHARED(dest_mnt)) { - err = invent_group_ids(source_mnt, true); - if (err) - goto out; - err = propagate_mnt(dest_mnt, dest_mp, source_mnt, &tree_list); - lock_mount_hash(); - if (err) - goto out_cleanup_ids; - for (p = source_mnt; p; p = next_mnt(p, source_mnt)) - set_mnt_shared(p); - } else { - lock_mount_hash(); - } - if (parent_path) { - detach_mnt(source_mnt, parent_path); - attach_mnt(source_mnt, dest_mnt, dest_mp); - touch_mnt_namespace(source_mnt->mnt_ns); - } else { - mnt_set_mountpoint(dest_mnt, dest_mp, source_mnt); - commit_tree(source_mnt, NULL); - } - - hlist_for_each_entry_safe(child, n, &tree_list, mnt_hash) { - struct mount *q; - hlist_del_init(&child->mnt_hash); - q = __lookup_mnt_last(&child->mnt_parent->mnt, - child->mnt_mountpoint); - commit_tree(child, q); - } - unlock_mount_hash(); - - return 0; - - out_cleanup_ids: - while (!hlist_empty(&tree_list)) { - child = hlist_entry(tree_list.first, struct mount, mnt_hash); - child->mnt_parent->mnt_ns->pending_mounts = 0; - umount_tree(child, UMOUNT_SYNC); - } - unlock_mount_hash(); - cleanup_group_ids(source_mnt, NULL); - out: - ns->pending_mounts = 0; - return err; -} - -static struct mountpoint *lock_mount(struct path *path) -{ - struct vfsmount *mnt; - struct dentry *dentry = path->dentry; -retry: - inode_lock(dentry->d_inode); - if (unlikely(cant_mount(dentry))) { - inode_unlock(dentry->d_inode); - return ERR_PTR(-ENOENT); - } - namespace_lock(); - mnt = lookup_mnt(path); - if (likely(!mnt)) { - struct mountpoint *mp = lookup_mountpoint(dentry); - if (!mp) - mp = new_mountpoint(dentry); - if (IS_ERR(mp)) { - namespace_unlock(); - inode_unlock(dentry->d_inode); - return mp; - } - return mp; - } - namespace_unlock(); - inode_unlock(path->dentry->d_inode); - path_put(path); - path->mnt = mnt; - dentry = path->dentry = dget(mnt->mnt_root); - goto retry; -} - -static void unlock_mount(struct mountpoint *where) -{ - struct dentry *dentry = where->m_dentry; - put_mountpoint(where); - namespace_unlock(); - inode_unlock(dentry->d_inode); -} - -static int graft_tree(struct mount *mnt, struct mount *p, struct mountpoint *mp) -{ - if (mnt->mnt.mnt_sb->s_flags & MS_NOUSER) - return -EINVAL; - - if (d_is_dir(mp->m_dentry) != - d_is_dir(mnt->mnt.mnt_root)) - return -ENOTDIR; - - return attach_recursive_mnt(mnt, p, mp, NULL); -} - -/* - * Sanity check the flags to change_mnt_propagation. - */ - -static int flags_to_propagation_type(int flags) -{ - int type = flags & ~(MS_REC | MS_SILENT); - - /* Fail if any non-propagation flags are set */ - if (type & ~(MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) - return 0; - /* Only one propagation flag should be set */ - if (!is_power_of_2(type)) - return 0; - return type; -} - -/* - * recursively change the type of the mountpoint. - */ -static int do_change_type(struct path *path, int flag) -{ - struct mount *m; - struct mount *mnt = real_mount(path->mnt); - int recurse = flag & MS_REC; - int type; - int err = 0; - - if (path->dentry != path->mnt->mnt_root) - return -EINVAL; - - type = flags_to_propagation_type(flag); - if (!type) - return -EINVAL; - - namespace_lock(); - if (type == MS_SHARED) { - err = invent_group_ids(mnt, recurse); - if (err) - goto out_unlock; - } - - lock_mount_hash(); - for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL)) - change_mnt_propagation(m, type); - unlock_mount_hash(); - - out_unlock: - namespace_unlock(); - return err; -} - -static bool has_locked_children(struct mount *mnt, struct dentry *dentry) -{ - struct mount *child; - list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) { - if (!is_subdir(child->mnt_mountpoint, dentry)) - continue; - - if (child->mnt.mnt_flags & MNT_LOCKED) - return true; - } - return false; -} - -/* - * do loopback mount. - */ -static int do_loopback(struct path *path, const char *old_name, - int recurse) -{ - struct path old_path; - struct mount *mnt = NULL, *old, *parent; - struct mountpoint *mp; - int err; - if (!old_name || !*old_name) - return -EINVAL; - err = kern_path(old_name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &old_path); - if (err) - return err; - - err = -EINVAL; - if (mnt_ns_loop(old_path.dentry)) - goto out; - - mp = lock_mount(path); - err = PTR_ERR(mp); - if (IS_ERR(mp)) - goto out; - - old = real_mount(old_path.mnt); - parent = real_mount(path->mnt); - - err = -EINVAL; - if (IS_MNT_UNBINDABLE(old)) - goto out2; - - if (!check_mnt(parent)) - goto out2; - - if (!check_mnt(old) && old_path.dentry->d_op != &ns_dentry_operations) - goto out2; - - if (!recurse && has_locked_children(old, old_path.dentry)) - goto out2; - - if (recurse) - mnt = copy_tree(old, old_path.dentry, CL_COPY_MNT_NS_FILE); - else - mnt = clone_mnt(old, old_path.dentry, 0); - - if (IS_ERR(mnt)) { - err = PTR_ERR(mnt); - goto out2; - } - - mnt->mnt.mnt_flags &= ~MNT_LOCKED; - - err = graft_tree(mnt, parent, mp); - if (err) { - lock_mount_hash(); - umount_tree(mnt, UMOUNT_SYNC); - unlock_mount_hash(); - } -out2: - unlock_mount(mp); -out: - path_put(&old_path); - return err; -} - -static int change_mount_flags(struct vfsmount *mnt, int ms_flags) -{ - int error = 0; - int readonly_request = 0; - - if (ms_flags & MS_RDONLY) - readonly_request = 1; - if (readonly_request == __mnt_is_readonly(mnt)) - return 0; - - if (readonly_request) - error = mnt_make_readonly(real_mount(mnt)); - else - __mnt_unmake_readonly(real_mount(mnt)); - return error; -} - -/* - * change filesystem flags. dir should be a physical root of filesystem. - * If you've mounted a non-root directory somewhere and want to do remount - * on it - tough luck. - */ -static int do_remount(struct path *path, int flags, int mnt_flags, - void *data) -{ - int err; - struct super_block *sb = path->mnt->mnt_sb; - struct mount *mnt = real_mount(path->mnt); - - if (!check_mnt(mnt)) - return -EINVAL; - - if (path->dentry != path->mnt->mnt_root) - return -EINVAL; - - /* Don't allow changing of locked mnt flags. - * - * No locks need to be held here while testing the various - * MNT_LOCK flags because those flags can never be cleared - * once they are set. - */ - if ((mnt->mnt.mnt_flags & MNT_LOCK_READONLY) && - !(mnt_flags & MNT_READONLY)) { - return -EPERM; - } - if ((mnt->mnt.mnt_flags & MNT_LOCK_NODEV) && - !(mnt_flags & MNT_NODEV)) { - return -EPERM; - } - if ((mnt->mnt.mnt_flags & MNT_LOCK_NOSUID) && - !(mnt_flags & MNT_NOSUID)) { - return -EPERM; - } - if ((mnt->mnt.mnt_flags & MNT_LOCK_NOEXEC) && - !(mnt_flags & MNT_NOEXEC)) { - return -EPERM; - } - if ((mnt->mnt.mnt_flags & MNT_LOCK_ATIME) && - ((mnt->mnt.mnt_flags & MNT_ATIME_MASK) != (mnt_flags & MNT_ATIME_MASK))) { - return -EPERM; - } - - err = security_sb_remount(sb, data); - if (err) - return err; - - down_write(&sb->s_umount); - if (flags & MS_BIND) - err = change_mount_flags(path->mnt, flags); - else if (!capable(CAP_SYS_ADMIN)) - err = -EPERM; - else - err = do_remount_sb(sb, flags, data, 0); - if (!err) { - lock_mount_hash(); - mnt_flags |= mnt->mnt.mnt_flags & ~MNT_USER_SETTABLE_MASK; - mnt->mnt.mnt_flags = mnt_flags; - touch_mnt_namespace(mnt->mnt_ns); - unlock_mount_hash(); - } - up_write(&sb->s_umount); - return err; -} - -static inline int tree_contains_unbindable(struct mount *mnt) -{ - struct mount *p; - for (p = mnt; p; p = next_mnt(p, mnt)) { - if (IS_MNT_UNBINDABLE(p)) - return 1; - } - return 0; -} - -static int do_move_mount(struct path *path, const char *old_name) -{ - struct path old_path, parent_path; - struct mount *p; - struct mount *old; - struct mountpoint *mp; - int err; - if (!old_name || !*old_name) - return -EINVAL; - err = kern_path(old_name, LOOKUP_FOLLOW, &old_path); - if (err) - return err; - - mp = lock_mount(path); - err = PTR_ERR(mp); - if (IS_ERR(mp)) - goto out; - - old = real_mount(old_path.mnt); - p = real_mount(path->mnt); - - err = -EINVAL; - if (!check_mnt(p) || !check_mnt(old)) - goto out1; - - if (old->mnt.mnt_flags & MNT_LOCKED) - goto out1; - - err = -EINVAL; - if (old_path.dentry != old_path.mnt->mnt_root) - goto out1; - - if (!mnt_has_parent(old)) - goto out1; - - if (d_is_dir(path->dentry) != - d_is_dir(old_path.dentry)) - goto out1; - /* - * Don't move a mount residing in a shared parent. - */ - if (IS_MNT_SHARED(old->mnt_parent)) - goto out1; - /* - * Don't move a mount tree containing unbindable mounts to a destination - * mount which is shared. - */ - if (IS_MNT_SHARED(p) && tree_contains_unbindable(old)) - goto out1; - err = -ELOOP; - for (; mnt_has_parent(p); p = p->mnt_parent) - if (p == old) - goto out1; - - err = attach_recursive_mnt(old, real_mount(path->mnt), mp, &parent_path); - if (err) - goto out1; - - /* if the mount is moved, it should no longer be expire - * automatically */ - list_del_init(&old->mnt_expire); -out1: - unlock_mount(mp); -out: - if (!err) - path_put(&parent_path); - path_put(&old_path); - return err; -} - -static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype) -{ - int err; - const char *subtype = strchr(fstype, '.'); - if (subtype) { - subtype++; - err = -EINVAL; - if (!subtype[0]) - goto err; - } else - subtype = ""; - - mnt->mnt_sb->s_subtype = kstrdup(subtype, GFP_KERNEL); - err = -ENOMEM; - if (!mnt->mnt_sb->s_subtype) - goto err; - return mnt; - - err: - mntput(mnt); - return ERR_PTR(err); -} - -/* - * add a mount into a namespace's mount tree - */ -static int do_add_mount(struct mount *newmnt, struct path *path, int mnt_flags) -{ - struct mountpoint *mp; - struct mount *parent; - int err; - - mnt_flags &= ~MNT_INTERNAL_FLAGS; - - mp = lock_mount(path); - if (IS_ERR(mp)) - return PTR_ERR(mp); - - parent = real_mount(path->mnt); - err = -EINVAL; - if (unlikely(!check_mnt(parent))) { - /* that's acceptable only for automounts done in private ns */ - if (!(mnt_flags & MNT_SHRINKABLE)) - goto unlock; - /* ... and for those we'd better have mountpoint still alive */ - if (!parent->mnt_ns) - goto unlock; - } - - /* Refuse the same filesystem on the same mount point */ - err = -EBUSY; - if (path->mnt->mnt_sb == newmnt->mnt.mnt_sb && - path->mnt->mnt_root == path->dentry) - goto unlock; - - err = -EINVAL; - if (d_is_symlink(newmnt->mnt.mnt_root)) - goto unlock; - - newmnt->mnt.mnt_flags = mnt_flags; - err = graft_tree(newmnt, parent, mp); - -unlock: - unlock_mount(mp); - return err; -} - -static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags); - -/* - * create a new mount for userspace and request it to be added into the - * namespace's tree - */ -static int do_new_mount(struct path *path, const char *fstype, int flags, - int mnt_flags, const char *name, void *data) -{ - struct file_system_type *type; - struct vfsmount *mnt; - int err; - - if (!fstype) - return -EINVAL; - - type = get_fs_type(fstype); - if (!type) - return -ENODEV; - - mnt = vfs_kern_mount(type, flags, name, data); - if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) && - !mnt->mnt_sb->s_subtype) - mnt = fs_set_subtype(mnt, fstype); - - put_filesystem(type); - if (IS_ERR(mnt)) - return PTR_ERR(mnt); - - if (mount_too_revealing(mnt, &mnt_flags)) { - mntput(mnt); - return -EPERM; - } - - err = do_add_mount(real_mount(mnt), path, mnt_flags); - if (err) - mntput(mnt); - return err; -} - -int finish_automount(struct vfsmount *m, struct path *path) -{ - struct mount *mnt = real_mount(m); - int err; - /* The new mount record should have at least 2 refs to prevent it being - * expired before we get a chance to add it - */ - BUG_ON(mnt_get_count(mnt) < 2); - - if (m->mnt_sb == path->mnt->mnt_sb && - m->mnt_root == path->dentry) { - err = -ELOOP; - goto fail; - } - - err = do_add_mount(mnt, path, path->mnt->mnt_flags | MNT_SHRINKABLE); - if (!err) - return 0; -fail: - /* remove m from any expiration list it may be on */ - if (!list_empty(&mnt->mnt_expire)) { - namespace_lock(); - list_del_init(&mnt->mnt_expire); - namespace_unlock(); - } - mntput(m); - mntput(m); - return err; -} - -/** - * mnt_set_expiry - Put a mount on an expiration list - * @mnt: The mount to list. - * @expiry_list: The list to add the mount to. - */ -void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list) -{ - namespace_lock(); - - list_add_tail(&real_mount(mnt)->mnt_expire, expiry_list); - - namespace_unlock(); -} -EXPORT_SYMBOL(mnt_set_expiry); - -/* - * process a list of expirable mountpoints with the intent of discarding any - * mountpoints that aren't in use and haven't been touched since last we came - * here - */ -void mark_mounts_for_expiry(struct list_head *mounts) -{ - struct mount *mnt, *next; - LIST_HEAD(graveyard); - - if (list_empty(mounts)) - return; - - namespace_lock(); - lock_mount_hash(); - - /* extract from the expiration list every vfsmount that matches the - * following criteria: - * - only referenced by its parent vfsmount - * - still marked for expiry (marked on the last call here; marks are - * cleared by mntput()) - */ - list_for_each_entry_safe(mnt, next, mounts, mnt_expire) { - if (!xchg(&mnt->mnt_expiry_mark, 1) || - propagate_mount_busy(mnt, 1)) - continue; - list_move(&mnt->mnt_expire, &graveyard); - } - while (!list_empty(&graveyard)) { - mnt = list_first_entry(&graveyard, struct mount, mnt_expire); - touch_mnt_namespace(mnt->mnt_ns); - umount_tree(mnt, UMOUNT_PROPAGATE|UMOUNT_SYNC); - } - unlock_mount_hash(); - namespace_unlock(); -} - -EXPORT_SYMBOL_GPL(mark_mounts_for_expiry); - -/* - * Ripoff of 'select_parent()' - * - * search the list of submounts for a given mountpoint, and move any - * shrinkable submounts to the 'graveyard' list. - */ -static int select_submounts(struct mount *parent, struct list_head *graveyard) -{ - struct mount *this_parent = parent; - struct list_head *next; - int found = 0; - -repeat: - next = this_parent->mnt_mounts.next; -resume: - while (next != &this_parent->mnt_mounts) { - struct list_head *tmp = next; - struct mount *mnt = list_entry(tmp, struct mount, mnt_child); - - next = tmp->next; - if (!(mnt->mnt.mnt_flags & MNT_SHRINKABLE)) - continue; - /* - * Descend a level if the d_mounts list is non-empty. - */ - if (!list_empty(&mnt->mnt_mounts)) { - this_parent = mnt; - goto repeat; - } - - if (!propagate_mount_busy(mnt, 1)) { - list_move_tail(&mnt->mnt_expire, graveyard); - found++; - } - } - /* - * All done at this level ... ascend and resume the search - */ - if (this_parent != parent) { - next = this_parent->mnt_child.next; - this_parent = this_parent->mnt_parent; - goto resume; - } - return found; -} - -/* - * process a list of expirable mountpoints with the intent of discarding any - * submounts of a specific parent mountpoint - * - * mount_lock must be held for write - */ -static void shrink_submounts(struct mount *mnt) -{ - LIST_HEAD(graveyard); - struct mount *m; - - /* extract submounts of 'mountpoint' from the expiration list */ - while (select_submounts(mnt, &graveyard)) { - while (!list_empty(&graveyard)) { - m = list_first_entry(&graveyard, struct mount, - mnt_expire); - touch_mnt_namespace(m->mnt_ns); - umount_tree(m, UMOUNT_PROPAGATE|UMOUNT_SYNC); - } - } -} - -/* - * Some copy_from_user() implementations do not return the exact number of - * bytes remaining to copy on a fault. But copy_mount_options() requires that. - * Note that this function differs from copy_from_user() in that it will oops - * on bad values of `to', rather than returning a short copy. - */ -static long exact_copy_from_user(void *to, const void __user * from, - unsigned long n) -{ - char *t = to; - const char __user *f = from; - char c; - - if (!access_ok(VERIFY_READ, from, n)) - return n; - - while (n) { - if (__get_user(c, f)) { - memset(t, 0, n); - break; - } - *t++ = c; - f++; - n--; - } - return n; -} - -void *copy_mount_options(const void __user * data) -{ - int i; - unsigned long size; - char *copy; - - if (!data) - return NULL; - - copy = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (!copy) - return ERR_PTR(-ENOMEM); - - /* We only care that *some* data at the address the user - * gave us is valid. Just in case, we'll zero - * the remainder of the page. - */ - /* copy_from_user cannot cross TASK_SIZE ! */ - size = TASK_SIZE - (unsigned long)data; - if (size > PAGE_SIZE) - size = PAGE_SIZE; - - i = size - exact_copy_from_user(copy, data, size); - if (!i) { - kfree(copy); - return ERR_PTR(-EFAULT); - } - if (i != PAGE_SIZE) - memset(copy + i, 0, PAGE_SIZE - i); - return copy; -} - -char *copy_mount_string(const void __user *data) -{ - return data ? strndup_user(data, PAGE_SIZE) : NULL; -} - -/* - * Flags is a 32-bit value that allows up to 31 non-fs dependent flags to - * be given to the mount() call (ie: read-only, no-dev, no-suid etc). - * - * data is a (void *) that can point to any structure up to - * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent - * information (or be NULL). - * - * Pre-0.97 versions of mount() didn't have a flags word. - * When the flags word was introduced its top half was required - * to have the magic value 0xC0ED, and this remained so until 2.4.0-test9. - * Therefore, if this magic number is present, it carries no information - * and must be discarded. - */ -long do_mount(const char *dev_name, const char __user *dir_name, - const char *type_page, unsigned long flags, void *data_page) -{ - struct path path; - int retval = 0; - int mnt_flags = 0; - - /* Discard magic */ - if ((flags & MS_MGC_MSK) == MS_MGC_VAL) - flags &= ~MS_MGC_MSK; - - /* Basic sanity checks */ - if (data_page) - ((char *)data_page)[PAGE_SIZE - 1] = 0; - - /* ... and get the mountpoint */ - retval = user_path(dir_name, &path); - if (retval) - return retval; - - retval = security_sb_mount(dev_name, &path, - type_page, flags, data_page); - if (!retval && !may_mount()) - retval = -EPERM; - if (!retval && (flags & MS_MANDLOCK) && !may_mandlock()) - retval = -EPERM; - if (retval) - goto dput_out; - - /* Default to relatime unless overriden */ - if (!(flags & MS_NOATIME)) - mnt_flags |= MNT_RELATIME; - - /* Separate the per-mountpoint flags */ - if (flags & MS_NOSUID) - mnt_flags |= MNT_NOSUID; - if (flags & MS_NODEV) - mnt_flags |= MNT_NODEV; - if (flags & MS_NOEXEC) - mnt_flags |= MNT_NOEXEC; - if (flags & MS_NOATIME) - mnt_flags |= MNT_NOATIME; - if (flags & MS_NODIRATIME) - mnt_flags |= MNT_NODIRATIME; - if (flags & MS_STRICTATIME) - mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME); - if (flags & MS_RDONLY) - mnt_flags |= MNT_READONLY; - - /* The default atime for remount is preservation */ - if ((flags & MS_REMOUNT) && - ((flags & (MS_NOATIME | MS_NODIRATIME | MS_RELATIME | - MS_STRICTATIME)) == 0)) { - mnt_flags &= ~MNT_ATIME_MASK; - mnt_flags |= path.mnt->mnt_flags & MNT_ATIME_MASK; - } - - flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN | - MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT | - MS_STRICTATIME | MS_NOREMOTELOCK); - - if (flags & MS_REMOUNT) - retval = do_remount(&path, flags & ~MS_REMOUNT, mnt_flags, - data_page); - else if (flags & MS_BIND) - retval = do_loopback(&path, dev_name, flags & MS_REC); - else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) - retval = do_change_type(&path, flags); - else if (flags & MS_MOVE) - retval = do_move_mount(&path, dev_name); - else - retval = do_new_mount(&path, type_page, flags, mnt_flags, - dev_name, data_page); -dput_out: - path_put(&path); - return retval; -} - -static struct ucounts *inc_mnt_namespaces(struct user_namespace *ns) -{ - return inc_ucount(ns, current_euid(), UCOUNT_MNT_NAMESPACES); -} - -static void dec_mnt_namespaces(struct ucounts *ucounts) -{ - dec_ucount(ucounts, UCOUNT_MNT_NAMESPACES); -} - -static void free_mnt_ns(struct mnt_namespace *ns) -{ - ns_free_inum(&ns->ns); - dec_mnt_namespaces(ns->ucounts); - put_user_ns(ns->user_ns); - kfree(ns); -} - -/* - * Assign a sequence number so we can detect when we attempt to bind - * mount a reference to an older mount namespace into the current - * mount namespace, preventing reference counting loops. A 64bit - * number incrementing at 10Ghz will take 12,427 years to wrap which - * is effectively never, so we can ignore the possibility. - */ -static atomic64_t mnt_ns_seq = ATOMIC64_INIT(1); - -static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) -{ - struct mnt_namespace *new_ns; - struct ucounts *ucounts; - int ret; - - ucounts = inc_mnt_namespaces(user_ns); - if (!ucounts) - return ERR_PTR(-ENOSPC); - - new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); - if (!new_ns) { - dec_mnt_namespaces(ucounts); - return ERR_PTR(-ENOMEM); - } - ret = ns_alloc_inum(&new_ns->ns); - if (ret) { - kfree(new_ns); - dec_mnt_namespaces(ucounts); - return ERR_PTR(ret); - } - new_ns->ns.ops = &mntns_operations; - new_ns->seq = atomic64_add_return(1, &mnt_ns_seq); - atomic_set(&new_ns->count, 1); - new_ns->root = NULL; - INIT_LIST_HEAD(&new_ns->list); - init_waitqueue_head(&new_ns->poll); - new_ns->event = 0; - new_ns->user_ns = get_user_ns(user_ns); - new_ns->ucounts = ucounts; - new_ns->mounts = 0; - new_ns->pending_mounts = 0; - return new_ns; -} - -__latent_entropy -struct mnt_namespace *copy_mnt_ns(unsigned long flags, struct mnt_namespace *ns, - struct user_namespace *user_ns, struct fs_struct *new_fs) -{ - struct mnt_namespace *new_ns; - struct vfsmount *rootmnt = NULL, *pwdmnt = NULL; - struct mount *p, *q; - struct mount *old; - struct mount *new; - int copy_flags; - - BUG_ON(!ns); - - if (likely(!(flags & CLONE_NEWNS))) { - get_mnt_ns(ns); - return ns; - } - - old = ns->root; - - new_ns = alloc_mnt_ns(user_ns); - if (IS_ERR(new_ns)) - return new_ns; - - namespace_lock(); - /* First pass: copy the tree topology */ - copy_flags = CL_COPY_UNBINDABLE | CL_EXPIRE; - if (user_ns != ns->user_ns) - copy_flags |= CL_SHARED_TO_SLAVE | CL_UNPRIVILEGED; - new = copy_tree(old, old->mnt.mnt_root, copy_flags); - if (IS_ERR(new)) { - namespace_unlock(); - free_mnt_ns(new_ns); - return ERR_CAST(new); - } - new_ns->root = new; - list_add_tail(&new_ns->list, &new->mnt_list); - - /* - * Second pass: switch the tsk->fs->* elements and mark new vfsmounts - * as belonging to new namespace. We have already acquired a private - * fs_struct, so tsk->fs->lock is not needed. - */ - p = old; - q = new; - while (p) { - q->mnt_ns = new_ns; - new_ns->mounts++; - if (new_fs) { - if (&p->mnt == new_fs->root.mnt) { - new_fs->root.mnt = mntget(&q->mnt); - rootmnt = &p->mnt; - } - if (&p->mnt == new_fs->pwd.mnt) { - new_fs->pwd.mnt = mntget(&q->mnt); - pwdmnt = &p->mnt; - } - } - p = next_mnt(p, old); - q = next_mnt(q, new); - if (!q) - break; - while (p->mnt.mnt_root != q->mnt.mnt_root) - p = next_mnt(p, old); - } - namespace_unlock(); - - if (rootmnt) - mntput(rootmnt); - if (pwdmnt) - mntput(pwdmnt); - - return new_ns; -} - -/** - * create_mnt_ns - creates a private namespace and adds a root filesystem - * @mnt: pointer to the new root filesystem mountpoint - */ -static struct mnt_namespace *create_mnt_ns(struct vfsmount *m) -{ - struct mnt_namespace *new_ns = alloc_mnt_ns(&init_user_ns); - if (!IS_ERR(new_ns)) { - struct mount *mnt = real_mount(m); - mnt->mnt_ns = new_ns; - new_ns->root = mnt; - new_ns->mounts++; - list_add(&mnt->mnt_list, &new_ns->list); - } else { - mntput(m); - } - return new_ns; -} - -struct dentry *mount_subtree(struct vfsmount *mnt, const char *name) -{ - struct mnt_namespace *ns; - struct super_block *s; - struct path path; - int err; - - ns = create_mnt_ns(mnt); - if (IS_ERR(ns)) - return ERR_CAST(ns); - - err = vfs_path_lookup(mnt->mnt_root, mnt, - name, LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT, &path); - - put_mnt_ns(ns); - - if (err) - return ERR_PTR(err); - - /* trade a vfsmount reference for active sb one */ - s = path.mnt->mnt_sb; - atomic_inc(&s->s_active); - mntput(path.mnt); - /* lock the sucker */ - down_write(&s->s_umount); - /* ... and return the root of (sub)tree on it */ - return path.dentry; -} -EXPORT_SYMBOL(mount_subtree); - -SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name, - char __user *, type, unsigned long, flags, void __user *, data) -{ - int ret; - char *kernel_type; - char *kernel_dev; - void *options; - - kernel_type = copy_mount_string(type); - ret = PTR_ERR(kernel_type); - if (IS_ERR(kernel_type)) - goto out_type; - - kernel_dev = copy_mount_string(dev_name); - ret = PTR_ERR(kernel_dev); - if (IS_ERR(kernel_dev)) - goto out_dev; - - options = copy_mount_options(data); - ret = PTR_ERR(options); - if (IS_ERR(options)) - goto out_data; - - ret = do_mount(kernel_dev, dir_name, kernel_type, flags, options); - - kfree(options); -out_data: - kfree(kernel_dev); -out_dev: - kfree(kernel_type); -out_type: - return ret; -} - -/* - * Return true if path is reachable from root - * - * namespace_sem or mount_lock is held - */ -bool is_path_reachable(struct mount *mnt, struct dentry *dentry, - const struct path *root) -{ - while (&mnt->mnt != root->mnt && mnt_has_parent(mnt)) { - dentry = mnt->mnt_mountpoint; - mnt = mnt->mnt_parent; - } - return &mnt->mnt == root->mnt && is_subdir(dentry, root->dentry); -} - -bool path_is_under(struct path *path1, struct path *path2) -{ - bool res; - read_seqlock_excl(&mount_lock); - res = is_path_reachable(real_mount(path1->mnt), path1->dentry, path2); - read_sequnlock_excl(&mount_lock); - return res; -} -EXPORT_SYMBOL(path_is_under); - -/* - * pivot_root Semantics: - * Moves the root file system of the current process to the directory put_old, - * makes new_root as the new root file system of the current process, and sets - * root/cwd of all processes which had them on the current root to new_root. - * - * Restrictions: - * The new_root and put_old must be directories, and must not be on the - * same file system as the current process root. The put_old must be - * underneath new_root, i.e. adding a non-zero number of /.. to the string - * pointed to by put_old must yield the same directory as new_root. No other - * file system may be mounted on put_old. After all, new_root is a mountpoint. - * - * Also, the current root cannot be on the 'rootfs' (initial ramfs) filesystem. - * See Documentation/filesystems/ramfs-rootfs-initramfs.txt for alternatives - * in this situation. - * - * Notes: - * - we don't move root/cwd if they are not at the root (reason: if something - * cared enough to change them, it's probably wrong to force them elsewhere) - * - it's okay to pick a root that isn't the root of a file system, e.g. - * /nfs/my_root where /nfs is the mount point. It must be a mountpoint, - * though, so you may need to say mount --bind /nfs/my_root /nfs/my_root - * first. - */ -SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, - const char __user *, put_old) -{ - struct path new, old, parent_path, root_parent, root; - struct mount *new_mnt, *root_mnt, *old_mnt; - struct mountpoint *old_mp, *root_mp; - int error; - - if (!may_mount()) - return -EPERM; - - error = user_path_dir(new_root, &new); - if (error) - goto out0; - - error = user_path_dir(put_old, &old); - if (error) - goto out1; - - error = security_sb_pivotroot(&old, &new); - if (error) - goto out2; - - get_fs_root(current->fs, &root); - old_mp = lock_mount(&old); - error = PTR_ERR(old_mp); - if (IS_ERR(old_mp)) - goto out3; - - error = -EINVAL; - new_mnt = real_mount(new.mnt); - root_mnt = real_mount(root.mnt); - old_mnt = real_mount(old.mnt); - if (IS_MNT_SHARED(old_mnt) || - IS_MNT_SHARED(new_mnt->mnt_parent) || - IS_MNT_SHARED(root_mnt->mnt_parent)) - goto out4; - if (!check_mnt(root_mnt) || !check_mnt(new_mnt)) - goto out4; - if (new_mnt->mnt.mnt_flags & MNT_LOCKED) - goto out4; - error = -ENOENT; - if (d_unlinked(new.dentry)) - goto out4; - error = -EBUSY; - if (new_mnt == root_mnt || old_mnt == root_mnt) - goto out4; /* loop, on the same file system */ - error = -EINVAL; - if (root.mnt->mnt_root != root.dentry) - goto out4; /* not a mountpoint */ - if (!mnt_has_parent(root_mnt)) - goto out4; /* not attached */ - root_mp = root_mnt->mnt_mp; - if (new.mnt->mnt_root != new.dentry) - goto out4; /* not a mountpoint */ - if (!mnt_has_parent(new_mnt)) - goto out4; /* not attached */ - /* make sure we can reach put_old from new_root */ - if (!is_path_reachable(old_mnt, old.dentry, &new)) - goto out4; - /* make certain new is below the root */ - if (!is_path_reachable(new_mnt, new.dentry, &root)) - goto out4; - root_mp->m_count++; /* pin it so it won't go away */ - lock_mount_hash(); - detach_mnt(new_mnt, &parent_path); - detach_mnt(root_mnt, &root_parent); - if (root_mnt->mnt.mnt_flags & MNT_LOCKED) { - new_mnt->mnt.mnt_flags |= MNT_LOCKED; - root_mnt->mnt.mnt_flags &= ~MNT_LOCKED; - } - /* mount old root on put_old */ - attach_mnt(root_mnt, old_mnt, old_mp); - /* mount new_root on / */ - attach_mnt(new_mnt, real_mount(root_parent.mnt), root_mp); - touch_mnt_namespace(current->nsproxy->mnt_ns); - /* A moved mount should not expire automatically */ - list_del_init(&new_mnt->mnt_expire); - unlock_mount_hash(); - chroot_fs_refs(&root, &new); - put_mountpoint(root_mp); - error = 0; -out4: - unlock_mount(old_mp); - if (!error) { - path_put(&root_parent); - path_put(&parent_path); - } -out3: - path_put(&root); -out2: - path_put(&old); -out1: - path_put(&new); -out0: - return error; -} - -static void __init init_mount_tree(void) -{ - struct vfsmount *mnt; - struct mnt_namespace *ns; - struct path root; - struct file_system_type *type; - - type = get_fs_type("rootfs"); - if (!type) - panic("Can't find rootfs type"); - mnt = vfs_kern_mount(type, 0, "rootfs", NULL); - put_filesystem(type); - if (IS_ERR(mnt)) - panic("Can't create rootfs"); - - ns = create_mnt_ns(mnt); - if (IS_ERR(ns)) - panic("Can't allocate initial namespace"); - - init_task.nsproxy->mnt_ns = ns; - get_mnt_ns(ns); - - root.mnt = mnt; - root.dentry = mnt->mnt_root; - mnt->mnt_flags |= MNT_LOCKED; - - set_fs_pwd(current->fs, &root); - set_fs_root(current->fs, &root); -} - -void __init mnt_init(void) -{ - unsigned u; - int err; - - mnt_cache = kmem_cache_create("mnt_cache", sizeof(struct mount), - 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL); - - mount_hashtable = alloc_large_system_hash("Mount-cache", - sizeof(struct hlist_head), - mhash_entries, 19, - 0, - &m_hash_shift, &m_hash_mask, 0, 0); - mountpoint_hashtable = alloc_large_system_hash("Mountpoint-cache", - sizeof(struct hlist_head), - mphash_entries, 19, - 0, - &mp_hash_shift, &mp_hash_mask, 0, 0); - - if (!mount_hashtable || !mountpoint_hashtable) - panic("Failed to allocate mount hash table\n"); - - for (u = 0; u <= m_hash_mask; u++) - INIT_HLIST_HEAD(&mount_hashtable[u]); - for (u = 0; u <= mp_hash_mask; u++) - INIT_HLIST_HEAD(&mountpoint_hashtable[u]); - - kernfs_init(); - - err = sysfs_init(); - if (err) - printk(KERN_WARNING "%s: sysfs_init error: %d\n", - __func__, err); - fs_kobj = kobject_create_and_add("fs", NULL); - if (!fs_kobj) - printk(KERN_WARNING "%s: kobj create error\n", __func__); - init_rootfs(); - init_mount_tree(); -} - -void put_mnt_ns(struct mnt_namespace *ns) -{ - if (!atomic_dec_and_test(&ns->count)) - return; - drop_collected_mounts(&ns->root->mnt); - free_mnt_ns(ns); -} - -struct vfsmount *kern_mount_data(struct file_system_type *type, void *data) -{ - struct vfsmount *mnt; - mnt = vfs_kern_mount(type, MS_KERNMOUNT, type->name, data); - if (!IS_ERR(mnt)) { - /* - * it is a longterm mount, don't release mnt until - * we unmount before file sys is unregistered - */ - real_mount(mnt)->mnt_ns = MNT_NS_INTERNAL; - } - return mnt; -} -EXPORT_SYMBOL_GPL(kern_mount_data); - -void kern_unmount(struct vfsmount *mnt) -{ - /* release long term mount so mount point can be released */ - if (!IS_ERR_OR_NULL(mnt)) { - real_mount(mnt)->mnt_ns = NULL; - synchronize_rcu(); /* yecchhh... */ - mntput(mnt); - } -} -EXPORT_SYMBOL(kern_unmount); - -bool our_mnt(struct vfsmount *mnt) -{ - return check_mnt(real_mount(mnt)); -} - -bool current_chrooted(void) -{ - /* Does the current process have a non-standard root */ - struct path ns_root; - struct path fs_root; - bool chrooted; - - /* Find the namespace root */ - ns_root.mnt = ¤t->nsproxy->mnt_ns->root->mnt; - ns_root.dentry = ns_root.mnt->mnt_root; - path_get(&ns_root); - while (d_mountpoint(ns_root.dentry) && follow_down_one(&ns_root)) - ; - - get_fs_root(current->fs, &fs_root); - - chrooted = !path_equal(&fs_root, &ns_root); - - path_put(&fs_root); - path_put(&ns_root); - - return chrooted; -} - -static bool mnt_already_visible(struct mnt_namespace *ns, struct vfsmount *new, - int *new_mnt_flags) -{ - int new_flags = *new_mnt_flags; - struct mount *mnt; - bool visible = false; - - down_read(&namespace_sem); - list_for_each_entry(mnt, &ns->list, mnt_list) { - struct mount *child; - int mnt_flags; - - if (mnt->mnt.mnt_sb->s_type != new->mnt_sb->s_type) - continue; - - /* This mount is not fully visible if it's root directory - * is not the root directory of the filesystem. - */ - if (mnt->mnt.mnt_root != mnt->mnt.mnt_sb->s_root) - continue; - - /* A local view of the mount flags */ - mnt_flags = mnt->mnt.mnt_flags; - - /* Don't miss readonly hidden in the superblock flags */ - if (mnt->mnt.mnt_sb->s_flags & MS_RDONLY) - mnt_flags |= MNT_LOCK_READONLY; - - /* Verify the mount flags are equal to or more permissive - * than the proposed new mount. - */ - if ((mnt_flags & MNT_LOCK_READONLY) && - !(new_flags & MNT_READONLY)) - continue; - if ((mnt_flags & MNT_LOCK_ATIME) && - ((mnt_flags & MNT_ATIME_MASK) != (new_flags & MNT_ATIME_MASK))) - continue; - - /* This mount is not fully visible if there are any - * locked child mounts that cover anything except for - * empty directories. - */ - list_for_each_entry(child, &mnt->mnt_mounts, mnt_child) { - struct inode *inode = child->mnt_mountpoint->d_inode; - /* Only worry about locked mounts */ - if (!(child->mnt.mnt_flags & MNT_LOCKED)) - continue; - /* Is the directory permanetly empty? */ - if (!is_empty_dir_inode(inode)) - goto next; - } - /* Preserve the locked attributes */ - *new_mnt_flags |= mnt_flags & (MNT_LOCK_READONLY | \ - MNT_LOCK_ATIME); - visible = true; - goto found; - next: ; - } -found: - up_read(&namespace_sem); - return visible; -} - -static bool mount_too_revealing(struct vfsmount *mnt, int *new_mnt_flags) -{ - const unsigned long required_iflags = SB_I_NOEXEC | SB_I_NODEV; - struct mnt_namespace *ns = current->nsproxy->mnt_ns; - unsigned long s_iflags; - - if (ns->user_ns == &init_user_ns) - return false; - - /* Can this filesystem be too revealing? */ - s_iflags = mnt->mnt_sb->s_iflags; - if (!(s_iflags & SB_I_USERNS_VISIBLE)) - return false; - - if ((s_iflags & required_iflags) != required_iflags) { - WARN_ONCE(1, "Expected s_iflags to contain 0x%lx\n", - required_iflags); - return true; - } - - return !mnt_already_visible(ns, mnt, new_mnt_flags); -} - -bool mnt_may_suid(struct vfsmount *mnt) -{ - /* - * Foreign mounts (accessed via fchdir or through /proc - * symlinks) are always treated as if they are nosuid. This - * prevents namespaces from trusting potentially unsafe - * suid/sgid bits, file caps, or security labels that originate - * in other namespaces. - */ - return !(mnt->mnt_flags & MNT_NOSUID) && check_mnt(real_mount(mnt)) && - current_in_userns(mnt->mnt_sb->s_user_ns); -} - -static struct ns_common *mntns_get(struct task_struct *task) -{ - struct ns_common *ns = NULL; - struct nsproxy *nsproxy; - - task_lock(task); - nsproxy = task->nsproxy; - if (nsproxy) { - ns = &nsproxy->mnt_ns->ns; - get_mnt_ns(to_mnt_ns(ns)); - } - task_unlock(task); - - return ns; -} - -static void mntns_put(struct ns_common *ns) -{ - put_mnt_ns(to_mnt_ns(ns)); -} - -static int mntns_install(struct nsproxy *nsproxy, struct ns_common *ns) -{ - struct fs_struct *fs = current->fs; - struct mnt_namespace *mnt_ns = to_mnt_ns(ns); - struct path root; - - if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) || - !ns_capable(current_user_ns(), CAP_SYS_CHROOT) || - !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) - return -EPERM; - - if (fs->users != 1) - return -EINVAL; - - get_mnt_ns(mnt_ns); - put_mnt_ns(nsproxy->mnt_ns); - nsproxy->mnt_ns = mnt_ns; - - /* Find the root */ - root.mnt = &mnt_ns->root->mnt; - root.dentry = mnt_ns->root->mnt.mnt_root; - path_get(&root); - while(d_mountpoint(root.dentry) && follow_down_one(&root)) - ; - - /* Update the pwd and root */ - set_fs_pwd(fs, &root); - set_fs_root(fs, &root); - - path_put(&root); - return 0; -} - -static struct user_namespace *mntns_owner(struct ns_common *ns) -{ - return to_mnt_ns(ns)->user_ns; -} - -const struct proc_ns_operations mntns_operations = { - .name = "mnt", - .type = CLONE_NEWNS, - .get = mntns_get, - .put = mntns_put, - .install = mntns_install, - .owner = mntns_owner, -}; diff --git a/src/linux/fs/ncpfs/Kconfig b/src/linux/fs/ncpfs/Kconfig deleted file mode 100644 index c931cf2..0000000 --- a/src/linux/fs/ncpfs/Kconfig +++ /dev/null @@ -1,108 +0,0 @@ -# -# NCP Filesystem configuration -# -config NCP_FS - tristate "NCP file system support (to mount NetWare volumes)" - depends on IPX!=n || INET - help - NCP (NetWare Core Protocol) is a protocol that runs over IPX and is - used by Novell NetWare clients to talk to file servers. It is to - IPX what NFS is to TCP/IP, if that helps. Saying Y here allows you - to mount NetWare file server volumes and to access them just like - any other Unix directory. For details, please read the file - in the kernel source and - the IPX-HOWTO from . - - You do not have to say Y here if you want your Linux box to act as a - file *server* for Novell NetWare clients. - - General information about how to connect Linux, Windows machines and - Macs is on the WWW at . - - To compile this as a module, choose M here: the module will be called - ncpfs. Say N unless you are connected to a Novell network. - -config NCPFS_PACKET_SIGNING - bool "Packet signatures" - depends on NCP_FS - help - NCP allows packets to be signed for stronger security. If you want - security, say Y. Normal users can leave it off. To be able to use - packet signing you must use ncpfs > 2.0.12. - -config NCPFS_IOCTL_LOCKING - bool "Proprietary file locking" - depends on NCP_FS - help - Allows locking of records on remote volumes. Say N unless you have - special applications which are able to utilize this locking scheme. - -config NCPFS_STRONG - bool "Clear remove/delete inhibit when needed" - depends on NCP_FS - help - Allows manipulation of files flagged as Delete or Rename Inhibit. - To use this feature you must mount volumes with the ncpmount - parameter "-s" (ncpfs-2.0.12 and newer). Say Y unless you are not - mounting volumes with -f 444. - -config NCPFS_NFS_NS - bool "Use NFS namespace if available" - depends on NCP_FS - help - Allows you to utilize NFS namespace on NetWare servers. It brings - you case sensitive filenames. Say Y. You can disable it at - mount-time with the `-N nfs' parameter of ncpmount. - -config NCPFS_OS2_NS - bool "Use LONG (OS/2) namespace if available" - depends on NCP_FS - help - Allows you to utilize OS2/LONG namespace on NetWare servers. - Filenames in this namespace are limited to 255 characters, they are - case insensitive, and case in names is preserved. Say Y. You can - disable it at mount time with the -N os2 parameter of ncpmount. - -config NCPFS_SMALLDOS - bool "Lowercase DOS filenames" - depends on NCP_FS - ---help--- - If you say Y here, every filename on a NetWare server volume using - the OS2/LONG namespace and created under DOS or on a volume using - DOS namespace will be converted to lowercase characters. - Saying N here will give you these filenames in uppercase. - - This is only a cosmetic option since the OS2/LONG namespace is case - insensitive. The only major reason for this option is backward - compatibility when moving from DOS to OS2/LONG namespace support. - Long filenames (created by Win95) will not be affected. - - This option does not solve the problem that filenames appear - differently under Linux and under Windows, since Windows does an - additional conversions on the client side. You can achieve similar - effects by saying Y to "Allow using of Native Language Support" - below. - -config NCPFS_NLS - bool "Use Native Language Support" - depends on NCP_FS - select NLS - help - Allows you to use codepages and I/O charsets for file name - translation between the server file system and input/output. This - may be useful, if you want to access the server with other operating - systems, e.g. Windows 95. See also NLS for more Information. - - To select codepages and I/O charsets use ncpfs-2.2.0.13 or newer. - -config NCPFS_EXTRAS - bool "Enable symbolic links and execute flags" - depends on NCP_FS - help - This enables the use of symbolic links and an execute permission - bit on NCPFS. The file server need not have long name space or NFS - name space loaded for these to work. - - To use the new attributes, it is recommended to use the flags - '-f 600 -d 755' on the ncpmount command line. - diff --git a/src/linux/fs/nfs/Kconfig b/src/linux/fs/nfs/Kconfig deleted file mode 100644 index f31fd0d..0000000 --- a/src/linux/fs/nfs/Kconfig +++ /dev/null @@ -1,202 +0,0 @@ -config NFS_FS - tristate "NFS client support" - depends on INET && FILE_LOCKING && MULTIUSER - select LOCKD - select SUNRPC - select NFS_ACL_SUPPORT if NFS_V3_ACL - help - Choose Y here if you want to access files residing on other - computers using Sun's Network File System protocol. To compile - this file system support as a module, choose M here: the module - will be called nfs. - - To mount file systems exported by NFS servers, you also need to - install the user space mount.nfs command which can be found in - the Linux nfs-utils package, available from http://linux-nfs.org/. - Information about using the mount command is available in the - mount(8) man page. More detail about the Linux NFS client - implementation is available via the nfs(5) man page. - - Below you can choose which versions of the NFS protocol are - available in the kernel to mount NFS servers. Support for NFS - version 2 (RFC 1094) is always available when NFS_FS is selected. - - To configure a system which mounts its root file system via NFS - at boot time, say Y here, select "Kernel level IP - autoconfiguration" in the NETWORK menu, and select "Root file - system on NFS" below. You cannot compile this file system as a - module in this case. - - If unsure, say N. - -config NFS_V2 - tristate "NFS client support for NFS version 2" - depends on NFS_FS - default y - help - This option enables support for version 2 of the NFS protocol - (RFC 1094) in the kernel's NFS client. - - If unsure, say Y. - -config NFS_V3 - tristate "NFS client support for NFS version 3" - depends on NFS_FS - default y - help - This option enables support for version 3 of the NFS protocol - (RFC 1813) in the kernel's NFS client. - - If unsure, say Y. - -config NFS_V3_ACL - bool "NFS client support for the NFSv3 ACL protocol extension" - depends on NFS_V3 - help - Some NFS servers support an auxiliary NFSv3 ACL protocol that - Sun added to Solaris but never became an official part of the - NFS version 3 protocol. This protocol extension allows - applications on NFS clients to manipulate POSIX Access Control - Lists on files residing on NFS servers. NFS servers enforce - ACLs on local files whether this protocol is available or not. - - Choose Y here if your NFS server supports the Solaris NFSv3 ACL - protocol extension and you want your NFS client to allow - applications to access and modify ACLs on files on the server. - - Most NFS servers don't support the Solaris NFSv3 ACL protocol - extension. You can choose N here or specify the "noacl" mount - option to prevent your NFS client from trying to use the NFSv3 - ACL protocol. - - If unsure, say N. - -config NFS_V4 - tristate "NFS client support for NFS version 4" - depends on NFS_FS - select SUNRPC_GSS - select KEYS - help - This option enables support for version 4 of the NFS protocol - (RFC 3530) in the kernel's NFS client. - - To mount NFS servers using NFSv4, you also need to install user - space programs which can be found in the Linux nfs-utils package, - available from http://linux-nfs.org/. - - If unsure, say Y. - -config NFS_SWAP - bool "Provide swap over NFS support" - default n - depends on NFS_FS - select SUNRPC_SWAP - help - This option enables swapon to work on files located on NFS mounts. - -config NFS_V4_1 - bool "NFS client support for NFSv4.1" - depends on NFS_V4 - select SUNRPC_BACKCHANNEL - help - This option enables support for minor version 1 of the NFSv4 protocol - (RFC 5661) in the kernel's NFS client. - - If unsure, say N. - -config NFS_V4_2 - bool "NFS client support for NFSv4.2" - depends on NFS_V4_1 - help - This option enables support for minor version 2 of the NFSv4 protocol - in the kernel's NFS client. - - If unsure, say N. - -config PNFS_FILE_LAYOUT - tristate - depends on NFS_V4_1 - default NFS_V4 - -config PNFS_BLOCK - tristate - depends on NFS_V4_1 && BLK_DEV_DM - default NFS_V4 - -config PNFS_OBJLAYOUT - tristate - depends on NFS_V4_1 && SCSI_OSD_ULD - default NFS_V4 - -config PNFS_FLEXFILE_LAYOUT - tristate - depends on NFS_V4_1 && NFS_V3 - default m - -config NFS_V4_1_IMPLEMENTATION_ID_DOMAIN - string "NFSv4.1 Implementation ID Domain" - depends on NFS_V4_1 - default "kernel.org" - help - This option defines the domain portion of the implementation ID that - may be sent in the NFS exchange_id operation. The value must be in - the format of a DNS domain name and should be set to the DNS domain - name of the distribution. - If the NFS client is unchanged from the upstream kernel, this - option should be set to the default "kernel.org". - -config NFS_V4_1_MIGRATION - bool "NFSv4.1 client support for migration" - depends on NFS_V4_1 - default n - help - This option makes the NFS client advertise to NFSv4.1 servers that - it can support NFSv4 migration. - - The NFSv4.1 pieces of the Linux NFSv4 migration implementation are - still experimental. If you are not an NFSv4 developer, say N here. - -config NFS_V4_SECURITY_LABEL - bool - depends on NFS_V4_2 && SECURITY - default y - -config ROOT_NFS - bool "Root file system on NFS" - depends on NFS_FS=y && IP_PNP - help - If you want your system to mount its root file system via NFS, - choose Y here. This is common practice for managing systems - without local permanent storage. For details, read - . - - Most people say N here. - -config NFS_FSCACHE - bool "Provide NFS client caching support" - depends on NFS_FS=m && FSCACHE || NFS_FS=y && FSCACHE=y - help - Say Y here if you want NFS data to be cached locally on disc through - the general filesystem cache manager - -config NFS_USE_LEGACY_DNS - bool "Use the legacy NFS DNS resolver" - depends on NFS_V4 - help - The kernel now provides a method for translating a host name into an - IP address. Select Y here if you would rather use your own DNS - resolver script. - - If unsure, say N - -config NFS_USE_KERNEL_DNS - bool - depends on NFS_V4 && !NFS_USE_LEGACY_DNS - select DNS_RESOLVER - default y - -config NFS_DEBUG - bool - depends on NFS_FS && SUNRPC_DEBUG - select CRC32 - default y diff --git a/src/linux/fs/nfsd/Kconfig b/src/linux/fs/nfsd/Kconfig deleted file mode 100644 index 47febcf..0000000 --- a/src/linux/fs/nfsd/Kconfig +++ /dev/null @@ -1,154 +0,0 @@ -config NFSD - tristate "NFS server support" - depends on INET - depends on FILE_LOCKING - select LOCKD - select SUNRPC - select EXPORTFS - select NFS_ACL_SUPPORT if NFSD_V2_ACL - depends on MULTIUSER - help - Choose Y here if you want to allow other computers to access - files residing on this system using Sun's Network File System - protocol. To compile the NFS server support as a module, - choose M here: the module will be called nfsd. - - You may choose to use a user-space NFS server instead, in which - case you can choose N here. - - To export local file systems using NFS, you also need to install - user space programs which can be found in the Linux nfs-utils - package, available from http://linux-nfs.org/. More detail about - the Linux NFS server implementation is available via the - exports(5) man page. - - Below you can choose which versions of the NFS protocol are - available to clients mounting the NFS server on this system. - Support for NFS version 2 (RFC 1094) is always available when - CONFIG_NFSD is selected. - - If unsure, say N. - -config NFSD_V2_ACL - bool - depends on NFSD - -config NFSD_V3 - bool "NFS server support for NFS version 3" - depends on NFSD - help - This option enables support in your system's NFS server for - version 3 of the NFS protocol (RFC 1813). - - If unsure, say Y. - -config NFSD_V3_ACL - bool "NFS server support for the NFSv3 ACL protocol extension" - depends on NFSD_V3 - select NFSD_V2_ACL - help - Solaris NFS servers support an auxiliary NFSv3 ACL protocol that - never became an official part of the NFS version 3 protocol. - This protocol extension allows applications on NFS clients to - manipulate POSIX Access Control Lists on files residing on NFS - servers. NFS servers enforce POSIX ACLs on local files whether - this protocol is available or not. - - This option enables support in your system's NFS server for the - NFSv3 ACL protocol extension allowing NFS clients to manipulate - POSIX ACLs on files exported by your system's NFS server. NFS - clients which support the Solaris NFSv3 ACL protocol can then - access and modify ACLs on your NFS server. - - To store ACLs on your NFS server, you also need to enable ACL- - related CONFIG options for your local file systems of choice. - - If unsure, say N. - -config NFSD_V4 - bool "NFS server support for NFS version 4" - depends on NFSD && PROC_FS - select NFSD_V3 - select FS_POSIX_ACL - select SUNRPC_GSS - select CRYPTO - select GRACE_PERIOD - help - This option enables support in your system's NFS server for - version 4 of the NFS protocol (RFC 3530). - - To export files using NFSv4, you need to install additional user - space programs which can be found in the Linux nfs-utils package, - available from http://linux-nfs.org/. - - If unsure, say N. - -config NFSD_PNFS - bool - -config NFSD_BLOCKLAYOUT - bool "NFSv4.1 server support for pNFS block layouts" - depends on NFSD_V4 && BLOCK - select NFSD_PNFS - select EXPORTFS_BLOCK_OPS - help - This option enables support for the exporting pNFS block layouts - in the kernel's NFS server. The pNFS block layout enables NFS - clients to directly perform I/O to block devices accesible to both - the server and the clients. See RFC 5663 for more details. - - If unsure, say N. - -config NFSD_SCSILAYOUT - bool "NFSv4.1 server support for pNFS SCSI layouts" - depends on NFSD_V4 && BLOCK - select NFSD_PNFS - select EXPORTFS_BLOCK_OPS - help - This option enables support for the exporting pNFS SCSI layouts - in the kernel's NFS server. The pNFS SCSI layout enables NFS - clients to directly perform I/O to SCSI devices accesible to both - the server and the clients. See draft-ietf-nfsv4-scsi-layout for - more details. - - If unsure, say N. - -config NFSD_FLEXFILELAYOUT - bool "NFSv4.1 server support for pNFS Flex File layouts" - depends on NFSD_V4 - select NFSD_PNFS - help - This option enables support for the exporting pNFS Flex File - layouts in the kernel's NFS server. The pNFS Flex File layout - enables NFS clients to directly perform I/O to NFSv3 devices - accesible to both the server and the clients. See - draft-ietf-nfsv4-flex-files for more details. - - Warning, this server implements the bare minimum functionality - to be a flex file server - it is for testing the client, - not for use in production. - - If unsure, say N. - -config NFSD_V4_SECURITY_LABEL - bool "Provide Security Label support for NFSv4 server" - depends on NFSD_V4 && SECURITY - help - - Say Y here if you want enable fine-grained security label attribute - support for NFS version 4. Security labels allow security modules like - SELinux and Smack to label files to facilitate enforcement of their policies. - Without this an NFSv4 mount will have the same label on each file. - - If you do not wish to enable fine-grained security labels SELinux or - Smack policies on NFSv4 files, say N. - -config NFSD_FAULT_INJECTION - bool "NFS server manual fault injection" - depends on NFSD_V4 && DEBUG_KERNEL && DEBUG_FS - help - This option enables support for manually injecting faults - into the NFS server. This is intended to be used for - testing error recovery on the NFS client. - - If unsure, say N. diff --git a/src/linux/fs/nilfs2/Kconfig b/src/linux/fs/nilfs2/Kconfig deleted file mode 100644 index 80da8eb..0000000 --- a/src/linux/fs/nilfs2/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -config NILFS2_FS - tristate "NILFS2 file system support" - select CRC32 - help - NILFS2 is a log-structured file system (LFS) supporting continuous - snapshotting. In addition to versioning capability of the entire - file system, users can even restore files mistakenly overwritten or - destroyed just a few seconds ago. Since this file system can keep - consistency like conventional LFS, it achieves quick recovery after - system crashes. - - NILFS2 creates a number of checkpoints every few seconds or per - synchronous write basis (unless there is no change). Users can - select significant versions among continuously created checkpoints, - and can change them into snapshots which will be preserved for long - periods until they are changed back to checkpoints. Each - snapshot is mountable as a read-only file system concurrently with - its writable mount, and this feature is convenient for online backup. - - Some features including atime, extended attributes, and POSIX ACLs, - are not supported yet. - - To compile this file system support as a module, choose M here: the - module will be called nilfs2. If unsure, say N. diff --git a/src/linux/fs/nls/Kconfig b/src/linux/fs/nls/Kconfig deleted file mode 100644 index e2ce79e..0000000 --- a/src/linux/fs/nls/Kconfig +++ /dev/null @@ -1,619 +0,0 @@ -# -# Native language support configuration -# - -menuconfig NLS - tristate "Native language support" - ---help--- - The base Native Language Support. A number of filesystems - depend on it (e.g. FAT, JOLIET, NT, BEOS filesystems), as well - as the ability of some filesystems to use native languages - (NCP, SMB). - - If unsure, say Y. - - To compile this code as a module, choose M here: the module - will be called nls_base. - -if NLS - -config NLS_DEFAULT - string "Default NLS Option" - default "iso8859-1" - ---help--- - The default NLS used when mounting file system. Note, that this is - the NLS used by your console, not the NLS used by a specific file - system (if different) to store data (filenames) on a disk. - Currently, the valid values are: - big5, cp437, cp737, cp775, cp850, cp852, cp855, cp857, cp860, cp861, - cp862, cp863, cp864, cp865, cp866, cp869, cp874, cp932, cp936, - cp949, cp950, cp1251, cp1255, euc-jp, euc-kr, gb2312, iso8859-1, - iso8859-2, iso8859-3, iso8859-4, iso8859-5, iso8859-6, iso8859-7, - iso8859-8, iso8859-9, iso8859-13, iso8859-14, iso8859-15, - koi8-r, koi8-ru, koi8-u, sjis, tis-620, macroman, utf8. - If you specify a wrong value, it will use the built-in NLS; - compatible with iso8859-1. - - If unsure, specify it as "iso8859-1". - -config NLS_CODEPAGE_437 - tristate "Codepage 437 (United States, Canada)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored - in so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage that is used in - the United States and parts of Canada. This is recommended. - -config NLS_CODEPAGE_737 - tristate "Codepage 737 (Greek)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored - in so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage that is used for - Greek. If unsure, say N. - -config NLS_CODEPAGE_775 - tristate "Codepage 775 (Baltic Rim)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored - in so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage that is used - for the Baltic Rim Languages (Latvian and Lithuanian). If unsure, - say N. - -config NLS_CODEPAGE_850 - tristate "Codepage 850 (Europe)" - ---help--- - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage that is used for - much of Europe -- United Kingdom, Germany, Spain, Italy, and [add - more countries here]. It has some characters useful to many European - languages that are not part of the US codepage 437. - - If unsure, say Y. - -config NLS_CODEPAGE_852 - tristate "Codepage 852 (Central/Eastern Europe)" - ---help--- - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the Latin 2 codepage used by DOS - for much of Central and Eastern Europe. It has all the required - characters for these languages: Albanian, Croatian, Czech, English, - Finnish, Hungarian, Irish, German, Polish, Romanian, Serbian (Latin - transcription), Slovak, Slovenian, and Sorbian. - -config NLS_CODEPAGE_855 - tristate "Codepage 855 (Cyrillic)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage for Cyrillic. - -config NLS_CODEPAGE_857 - tristate "Codepage 857 (Turkish)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage for Turkish. - -config NLS_CODEPAGE_860 - tristate "Codepage 860 (Portuguese)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage for Portuguese. - -config NLS_CODEPAGE_861 - tristate "Codepage 861 (Icelandic)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage for Icelandic. - -config NLS_CODEPAGE_862 - tristate "Codepage 862 (Hebrew)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage for Hebrew. - -config NLS_CODEPAGE_863 - tristate "Codepage 863 (Canadian French)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage for Canadian - French. - -config NLS_CODEPAGE_864 - tristate "Codepage 864 (Arabic)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage for Arabic. - -config NLS_CODEPAGE_865 - tristate "Codepage 865 (Norwegian, Danish)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage for the Nordic - European countries. - -config NLS_CODEPAGE_866 - tristate "Codepage 866 (Cyrillic/Russian)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage for - Cyrillic/Russian. - -config NLS_CODEPAGE_869 - tristate "Codepage 869 (Greek)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage for Greek. - -config NLS_CODEPAGE_936 - tristate "Simplified Chinese charset (CP936, GB2312)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage for Simplified - Chinese(GBK). - -config NLS_CODEPAGE_950 - tristate "Traditional Chinese charset (Big5)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage for Traditional - Chinese(Big5). - -config NLS_CODEPAGE_932 - tristate "Japanese charsets (Shift-JIS, EUC-JP)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage for Shift-JIS - or EUC-JP. To use EUC-JP, you can use 'euc-jp' as mount option or - NLS Default value during kernel configuration, instead of 'cp932'. - -config NLS_CODEPAGE_949 - tristate "Korean charset (CP949, EUC-KR)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage for UHC. - -config NLS_CODEPAGE_874 - tristate "Thai charset (CP874, TIS-620)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage for Thai. - -config NLS_ISO8859_8 - tristate "Hebrew charsets (ISO-8859-8, CP1255)" - help - If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CD-ROMs - correctly on the screen, you need to include the appropriate - input/output character sets. Say Y here for ISO8859-8, the Hebrew - character set. - -config NLS_CODEPAGE_1250 - tristate "Windows CP1250 (Slavic/Central European Languages)" - help - If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CDROMs - correctly on the screen, you need to include the appropriate - input/output character sets. Say Y here for the Windows CP-1250 - character set, which works for most Latin-written Slavic and Central - European languages: Czech, German, Hungarian, Polish, Rumanian, Croatian, - Slovak, Slovene. - -config NLS_CODEPAGE_1251 - tristate "Windows CP1251 (Bulgarian, Belarusian)" - help - The Microsoft FAT file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called DOS codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - DOS/Windows partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the DOS codepage for Russian and - Bulgarian and Belarusian. - -config NLS_ASCII - tristate "ASCII (United States)" - help - An ASCII NLS module is needed if you want to override the - DEFAULT NLS with this very basic charset and don't want any - non-ASCII characters to be translated. - -config NLS_ISO8859_1 - tristate "NLS ISO 8859-1 (Latin 1; Western European Languages)" - help - If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CD-ROMs - correctly on the screen, you need to include the appropriate - input/output character sets. Say Y here for the Latin 1 character - set, which covers most West European languages such as Albanian, - Catalan, Danish, Dutch, English, Faeroese, Finnish, French, German, - Galician, Irish, Icelandic, Italian, Norwegian, Portuguese, Spanish, - and Swedish. It is also the default for the US. If unsure, say Y. - -config NLS_ISO8859_2 - tristate "NLS ISO 8859-2 (Latin 2; Slavic/Central European Languages)" - help - If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CD-ROMs - correctly on the screen, you need to include the appropriate - input/output character sets. Say Y here for the Latin 2 character - set, which works for most Latin-written Slavic and Central European - languages: Czech, German, Hungarian, Polish, Rumanian, Croatian, - Slovak, Slovene. - -config NLS_ISO8859_3 - tristate "NLS ISO 8859-3 (Latin 3; Esperanto, Galician, Maltese, Turkish)" - help - If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CD-ROMs - correctly on the screen, you need to include the appropriate - input/output character sets. Say Y here for the Latin 3 character - set, which is popular with authors of Esperanto, Galician, Maltese, - and Turkish. - -config NLS_ISO8859_4 - tristate "NLS ISO 8859-4 (Latin 4; old Baltic charset)" - help - If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CD-ROMs - correctly on the screen, you need to include the appropriate - input/output character sets. Say Y here for the Latin 4 character - set which introduces letters for Estonian, Latvian, and - Lithuanian. It is an incomplete predecessor of Latin 7. - -config NLS_ISO8859_5 - tristate "NLS ISO 8859-5 (Cyrillic)" - help - If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CD-ROMs - correctly on the screen, you need to include the appropriate - input/output character sets. Say Y here for ISO8859-5, a Cyrillic - character set with which you can type Bulgarian, Belarusian, - Macedonian, Russian, Serbian, and Ukrainian. Note that the charset - KOI8-R is preferred in Russia. - -config NLS_ISO8859_6 - tristate "NLS ISO 8859-6 (Arabic)" - help - If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CD-ROMs - correctly on the screen, you need to include the appropriate - input/output character sets. Say Y here for ISO8859-6, the Arabic - character set. - -config NLS_ISO8859_7 - tristate "NLS ISO 8859-7 (Modern Greek)" - help - If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CD-ROMs - correctly on the screen, you need to include the appropriate - input/output character sets. Say Y here for ISO8859-7, the Modern - Greek character set. - -config NLS_ISO8859_9 - tristate "NLS ISO 8859-9 (Latin 5; Turkish)" - help - If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CD-ROMs - correctly on the screen, you need to include the appropriate - input/output character sets. Say Y here for the Latin 5 character - set, and it replaces the rarely needed Icelandic letters in Latin 1 - with the Turkish ones. Useful in Turkey. - -config NLS_ISO8859_13 - tristate "NLS ISO 8859-13 (Latin 7; Baltic)" - help - If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CD-ROMs - correctly on the screen, you need to include the appropriate - input/output character sets. Say Y here for the Latin 7 character - set, which supports modern Baltic languages including Latvian - and Lithuanian. - -config NLS_ISO8859_14 - tristate "NLS ISO 8859-14 (Latin 8; Celtic)" - help - If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CD-ROMs - correctly on the screen, you need to include the appropriate - input/output character sets. Say Y here for the Latin 8 character - set, which adds the last accented vowels for Welsh (aka Cymraeg) - (and Manx Gaelic) that were missing in Latin 1. - has further information. - -config NLS_ISO8859_15 - tristate "NLS ISO 8859-15 (Latin 9; Western European Languages with Euro)" - ---help--- - If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CD-ROMs - correctly on the screen, you need to include the appropriate - input/output character sets. Say Y here for the Latin 9 character - set, which covers most West European languages such as Albanian, - Catalan, Danish, Dutch, English, Estonian, Faeroese, Finnish, - French, German, Galician, Irish, Icelandic, Italian, Norwegian, - Portuguese, Spanish, and Swedish. Latin 9 is an update to - Latin 1 (ISO 8859-1) that removes a handful of rarely used - characters and instead adds support for Estonian, corrects the - support for French and Finnish, and adds the new Euro character. - If unsure, say Y. - -config NLS_KOI8_R - tristate "NLS KOI8-R (Russian)" - help - If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CD-ROMs - correctly on the screen, you need to include the appropriate - input/output character sets. Say Y here for the preferred Russian - character set. - -config NLS_KOI8_U - tristate "NLS KOI8-U/RU (Ukrainian, Belarusian)" - help - If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CD-ROMs - correctly on the screen, you need to include the appropriate - input/output character sets. Say Y here for the preferred Ukrainian - (koi8-u) and Belarusian (koi8-ru) character sets. - -config NLS_MAC_ROMAN - tristate "Codepage macroman" - ---help--- - The Apple HFS file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called MAC codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - Mac partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the Mac codepage that is used for - much of Europe -- United Kingdom, Germany, Spain, Italy, and [add - more countries here]. - - If unsure, say Y. - -config NLS_MAC_CELTIC - tristate "Codepage macceltic" - ---help--- - The Apple HFS file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called MAC codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - Mac partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the Mac codepage that is used for - Celtic. - - If unsure, say Y. - -config NLS_MAC_CENTEURO - tristate "Codepage maccenteuro" - ---help--- - The Apple HFS file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called MAC codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - Mac partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the Mac codepage that is used for - Central Europe. - - If unsure, say Y. - -config NLS_MAC_CROATIAN - tristate "Codepage maccroatian" - ---help--- - The Apple HFS file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called MAC codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - Mac partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the Mac codepage that is used for - Croatian. - - If unsure, say Y. - -config NLS_MAC_CYRILLIC - tristate "Codepage maccyrillic" - ---help--- - The Apple HFS file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called MAC codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - Mac partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the Mac codepage that is used for - Cyrillic. - - If unsure, say Y. - -config NLS_MAC_GAELIC - tristate "Codepage macgaelic" - ---help--- - The Apple HFS file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called MAC codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - Mac partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the Mac codepage that is used for - Gaelic. - - If unsure, say Y. - -config NLS_MAC_GREEK - tristate "Codepage macgreek" - ---help--- - The Apple HFS file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called MAC codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - Mac partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the Mac codepage that is used for - Greek. - - If unsure, say Y. - -config NLS_MAC_ICELAND - tristate "Codepage maciceland" - ---help--- - The Apple HFS file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called MAC codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - Mac partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the Mac codepage that is used for - Iceland. - - If unsure, say Y. - -config NLS_MAC_INUIT - tristate "Codepage macinuit" - ---help--- - The Apple HFS file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called MAC codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - Mac partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the Mac codepage that is used for - Inuit. - - If unsure, say Y. - -config NLS_MAC_ROMANIAN - tristate "Codepage macromanian" - ---help--- - The Apple HFS file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called MAC codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - Mac partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the Mac codepage that is used for - Romanian. - - If unsure, say Y. - -config NLS_MAC_TURKISH - tristate "Codepage macturkish" - ---help--- - The Apple HFS file system family can deal with filenames in - native language character sets. These character sets are stored in - so-called MAC codepages. You need to include the appropriate - codepage if you want to be able to read/write these filenames on - Mac partitions correctly. This does apply to the filenames - only, not to the file contents. You can include several codepages; - say Y here if you want to include the Mac codepage that is used for - Turkish. - - If unsure, say Y. - -config NLS_UTF8 - tristate "NLS UTF-8" - help - If you want to display filenames with native language characters - from the Microsoft FAT file system family or from JOLIET CD-ROMs - correctly on the screen, you need to include the appropriate - input/output character sets. Say Y here for the UTF-8 encoding of - the Unicode/ISO9646 universal character set. - -endif # NLS diff --git a/src/linux/fs/nls/Makefile b/src/linux/fs/nls/Makefile deleted file mode 100644 index 8ae37c1..0000000 --- a/src/linux/fs/nls/Makefile +++ /dev/null @@ -1,55 +0,0 @@ -# -# Makefile for native language support -# - -obj-$(CONFIG_NLS) += nls_base.o - -obj-$(CONFIG_NLS_CODEPAGE_437) += nls_cp437.o -obj-$(CONFIG_NLS_CODEPAGE_737) += nls_cp737.o -obj-$(CONFIG_NLS_CODEPAGE_775) += nls_cp775.o -obj-$(CONFIG_NLS_CODEPAGE_850) += nls_cp850.o -obj-$(CONFIG_NLS_CODEPAGE_852) += nls_cp852.o -obj-$(CONFIG_NLS_CODEPAGE_855) += nls_cp855.o -obj-$(CONFIG_NLS_CODEPAGE_857) += nls_cp857.o -obj-$(CONFIG_NLS_CODEPAGE_860) += nls_cp860.o -obj-$(CONFIG_NLS_CODEPAGE_861) += nls_cp861.o -obj-$(CONFIG_NLS_CODEPAGE_862) += nls_cp862.o -obj-$(CONFIG_NLS_CODEPAGE_863) += nls_cp863.o -obj-$(CONFIG_NLS_CODEPAGE_864) += nls_cp864.o -obj-$(CONFIG_NLS_CODEPAGE_865) += nls_cp865.o -obj-$(CONFIG_NLS_CODEPAGE_866) += nls_cp866.o -obj-$(CONFIG_NLS_CODEPAGE_869) += nls_cp869.o -obj-$(CONFIG_NLS_CODEPAGE_874) += nls_cp874.o -obj-$(CONFIG_NLS_CODEPAGE_932) += nls_cp932.o nls_euc-jp.o -obj-$(CONFIG_NLS_CODEPAGE_936) += nls_cp936.o -obj-$(CONFIG_NLS_CODEPAGE_949) += nls_cp949.o -obj-$(CONFIG_NLS_CODEPAGE_950) += nls_cp950.o -obj-$(CONFIG_NLS_CODEPAGE_1250) += nls_cp1250.o -obj-$(CONFIG_NLS_CODEPAGE_1251) += nls_cp1251.o -obj-$(CONFIG_NLS_ASCII) += nls_ascii.o -obj-$(CONFIG_NLS_ISO8859_1) += nls_iso8859-1.o -obj-$(CONFIG_NLS_ISO8859_2) += nls_iso8859-2.o -obj-$(CONFIG_NLS_ISO8859_3) += nls_iso8859-3.o -obj-$(CONFIG_NLS_ISO8859_4) += nls_iso8859-4.o -obj-$(CONFIG_NLS_ISO8859_5) += nls_iso8859-5.o -obj-$(CONFIG_NLS_ISO8859_6) += nls_iso8859-6.o -obj-$(CONFIG_NLS_ISO8859_7) += nls_iso8859-7.o -obj-$(CONFIG_NLS_ISO8859_8) += nls_cp1255.o -obj-$(CONFIG_NLS_ISO8859_9) += nls_iso8859-9.o -obj-$(CONFIG_NLS_ISO8859_13) += nls_iso8859-13.o -obj-$(CONFIG_NLS_ISO8859_14) += nls_iso8859-14.o -obj-$(CONFIG_NLS_ISO8859_15) += nls_iso8859-15.o -obj-$(CONFIG_NLS_KOI8_R) += nls_koi8-r.o -obj-$(CONFIG_NLS_KOI8_U) += nls_koi8-u.o nls_koi8-ru.o -obj-$(CONFIG_NLS_UTF8) += nls_utf8.o -obj-$(CONFIG_NLS_MAC_CELTIC) += mac-celtic.o -obj-$(CONFIG_NLS_MAC_CENTEURO) += mac-centeuro.o -obj-$(CONFIG_NLS_MAC_CROATIAN) += mac-croatian.o -obj-$(CONFIG_NLS_MAC_CYRILLIC) += mac-cyrillic.o -obj-$(CONFIG_NLS_MAC_GAELIC) += mac-gaelic.o -obj-$(CONFIG_NLS_MAC_GREEK) += mac-greek.o -obj-$(CONFIG_NLS_MAC_ICELAND) += mac-iceland.o -obj-$(CONFIG_NLS_MAC_INUIT) += mac-inuit.o -obj-$(CONFIG_NLS_MAC_ROMANIAN) += mac-romanian.o -obj-$(CONFIG_NLS_MAC_ROMAN) += mac-roman.o -obj-$(CONFIG_NLS_MAC_TURKISH) += mac-turkish.o diff --git a/src/linux/fs/nls/mac-celtic.c b/src/linux/fs/nls/mac-celtic.c deleted file mode 100644 index 266c2d7..0000000 --- a/src/linux/fs/nls/mac-celtic.c +++ /dev/null @@ -1,601 +0,0 @@ -/* - * linux/fs/nls/mac-celtic.c - * - * Charset macceltic translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -/* - * COPYRIGHT AND PERMISSION NOTICE - * - * Copyright 1991-2012 Unicode, Inc. All rights reserved. Distributed under - * the Terms of Use in http://www.unicode.org/copyright.html. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of the Unicode data files and any associated documentation (the "Data - * Files") or Unicode software and any associated documentation (the - * "Software") to deal in the Data Files or Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, and/or sell copies of the Data Files or Software, and - * to permit persons to whom the Data Files or Software are furnished to do - * so, provided that (a) the above copyright notice(s) and this permission - * notice appear with all copies of the Data Files or Software, (b) both the - * above copyright notice(s) and this permission notice appear in associated - * documentation, and (c) there is clear notice in each modified Data File or - * in the Software as well as in the documentation associated with the Data - * File(s) or Software that the data or software has been modified. - * - * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THE DATA FILES OR SOFTWARE. - * - * Except as contained in this notice, the name of a copyright holder shall - * not be used in advertising or otherwise to promote the sale, use or other - * dealings in these Data Files or Software without prior written - * authorization of the copyright holder. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00 */ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10 */ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20 */ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30 */ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40 */ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50 */ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60 */ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70 */ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80 */ - 0x00c4, 0x00c5, 0x00c7, 0x00c9, - 0x00d1, 0x00d6, 0x00dc, 0x00e1, - 0x00e0, 0x00e2, 0x00e4, 0x00e3, - 0x00e5, 0x00e7, 0x00e9, 0x00e8, - /* 0x90 */ - 0x00ea, 0x00eb, 0x00ed, 0x00ec, - 0x00ee, 0x00ef, 0x00f1, 0x00f3, - 0x00f2, 0x00f4, 0x00f6, 0x00f5, - 0x00fa, 0x00f9, 0x00fb, 0x00fc, - /* 0xa0 */ - 0x2020, 0x00b0, 0x00a2, 0x00a3, - 0x00a7, 0x2022, 0x00b6, 0x00df, - 0x00ae, 0x00a9, 0x2122, 0x00b4, - 0x00a8, 0x2260, 0x00c6, 0x00d8, - /* 0xb0 */ - 0x221e, 0x00b1, 0x2264, 0x2265, - 0x00a5, 0x00b5, 0x2202, 0x2211, - 0x220f, 0x03c0, 0x222b, 0x00aa, - 0x00ba, 0x03a9, 0x00e6, 0x00f8, - /* 0xc0 */ - 0x00bf, 0x00a1, 0x00ac, 0x221a, - 0x0192, 0x2248, 0x2206, 0x00ab, - 0x00bb, 0x2026, 0x00a0, 0x00c0, - 0x00c3, 0x00d5, 0x0152, 0x0153, - /* 0xd0 */ - 0x2013, 0x2014, 0x201c, 0x201d, - 0x2018, 0x2019, 0x00f7, 0x25ca, - 0x00ff, 0x0178, 0x2044, 0x20ac, - 0x2039, 0x203a, 0x0176, 0x0177, - /* 0xe0 */ - 0x2021, 0x00b7, 0x1ef2, 0x1ef3, - 0x2030, 0x00c2, 0x00ca, 0x00c1, - 0x00cb, 0x00c8, 0x00cd, 0x00ce, - 0x00cf, 0x00cc, 0x00d3, 0x00d4, - /* 0xf0 */ - 0x2663, 0x00d2, 0x00da, 0x00db, - 0x00d9, 0x0131, 0x00dd, 0x00fd, - 0x0174, 0x0175, 0x1e84, 0x1e85, - 0x1e80, 0x1e81, 0x1e82, 0x1e83, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xca, 0xc1, 0xa2, 0xa3, 0x00, 0xb4, 0x00, 0xa4, /* 0xa0-0xa7 */ - 0xac, 0xa9, 0xbb, 0xc7, 0xc2, 0x00, 0xa8, 0x00, /* 0xa8-0xaf */ - 0xa1, 0xb1, 0x00, 0x00, 0xab, 0xb5, 0xa6, 0xe1, /* 0xb0-0xb7 */ - 0x00, 0x00, 0xbc, 0xc8, 0x00, 0x00, 0x00, 0xc0, /* 0xb8-0xbf */ - 0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xae, 0x82, /* 0xc0-0xc7 */ - 0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec, /* 0xc8-0xcf */ - 0x00, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0x00, /* 0xd0-0xd7 */ - 0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0xf6, 0x00, 0xa7, /* 0xd8-0xdf */ - 0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xbe, 0x8d, /* 0xe0-0xe7 */ - 0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, /* 0xe8-0xef */ - 0x00, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6, /* 0xf0-0xf7 */ - 0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0xf7, 0x00, 0xd8, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0xce, 0xcf, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0xf8, 0xf9, 0xde, 0xdf, /* 0x70-0x77 */ - 0xd9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page03[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page1e[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0xfc, 0xfd, 0xfe, 0xff, 0xfa, 0xfb, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0xe2, 0xe3, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0xd0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd4, 0xd5, 0x00, 0x00, 0xd2, 0xd3, 0x00, 0x00, /* 0x18-0x1f */ - 0xa0, 0xe0, 0xa5, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0xdc, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page21[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xc6, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, /* 0x08-0x0f */ - 0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xb0, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xad, 0x00, 0x00, 0x00, 0xb2, 0xb3, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page25[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page26[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, NULL, page03, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, page1e, NULL, - page20, page21, page22, NULL, NULL, page25, page26, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x00-0x07 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x08-0x0f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x10-0x17 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x18-0x1f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x20-0x27 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x28-0x2f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x30-0x37 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x38-0x3f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x40-0x47 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x48-0x4f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x50-0x57 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x58-0x5f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x60-0x67 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x68-0x6f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x70-0x77 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x78-0x7f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x80-0x87 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x88-0x8f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x90-0x97 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x98-0x9f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xa0-0xa7 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xa8-0xaf */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xb0-0xb7 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xb8-0xbf */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xc0-0xc7 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xc8-0xcf */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xd0-0xd7 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xd8-0xdf */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xe0-0xe7 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xe8-0xef */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xf0-0xf7 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "macceltic", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_macceltic(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_macceltic(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_macceltic) -module_exit(exit_nls_macceltic) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/mac-centeuro.c b/src/linux/fs/nls/mac-centeuro.c deleted file mode 100644 index 9789c60..0000000 --- a/src/linux/fs/nls/mac-centeuro.c +++ /dev/null @@ -1,531 +0,0 @@ -/* - * linux/fs/nls/mac-centeuro.c - * - * Charset maccenteuro translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -/* - * COPYRIGHT AND PERMISSION NOTICE - * - * Copyright 1991-2012 Unicode, Inc. All rights reserved. Distributed under - * the Terms of Use in http://www.unicode.org/copyright.html. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of the Unicode data files and any associated documentation (the "Data - * Files") or Unicode software and any associated documentation (the - * "Software") to deal in the Data Files or Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, and/or sell copies of the Data Files or Software, and - * to permit persons to whom the Data Files or Software are furnished to do - * so, provided that (a) the above copyright notice(s) and this permission - * notice appear with all copies of the Data Files or Software, (b) both the - * above copyright notice(s) and this permission notice appear in associated - * documentation, and (c) there is clear notice in each modified Data File or - * in the Software as well as in the documentation associated with the Data - * File(s) or Software that the data or software has been modified. - * - * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THE DATA FILES OR SOFTWARE. - * - * Except as contained in this notice, the name of a copyright holder shall - * not be used in advertising or otherwise to promote the sale, use or other - * dealings in these Data Files or Software without prior written - * authorization of the copyright holder. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00 */ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10 */ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20 */ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30 */ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40 */ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50 */ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60 */ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70 */ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80 */ - 0x00c4, 0x0100, 0x0101, 0x00c9, - 0x0104, 0x00d6, 0x00dc, 0x00e1, - 0x0105, 0x010c, 0x00e4, 0x010d, - 0x0106, 0x0107, 0x00e9, 0x0179, - /* 0x90 */ - 0x017a, 0x010e, 0x00ed, 0x010f, - 0x0112, 0x0113, 0x0116, 0x00f3, - 0x0117, 0x00f4, 0x00f6, 0x00f5, - 0x00fa, 0x011a, 0x011b, 0x00fc, - /* 0xa0 */ - 0x2020, 0x00b0, 0x0118, 0x00a3, - 0x00a7, 0x2022, 0x00b6, 0x00df, - 0x00ae, 0x00a9, 0x2122, 0x0119, - 0x00a8, 0x2260, 0x0123, 0x012e, - /* 0xb0 */ - 0x012f, 0x012a, 0x2264, 0x2265, - 0x012b, 0x0136, 0x2202, 0x2211, - 0x0142, 0x013b, 0x013c, 0x013d, - 0x013e, 0x0139, 0x013a, 0x0145, - /* 0xc0 */ - 0x0146, 0x0143, 0x00ac, 0x221a, - 0x0144, 0x0147, 0x2206, 0x00ab, - 0x00bb, 0x2026, 0x00a0, 0x0148, - 0x0150, 0x00d5, 0x0151, 0x014c, - /* 0xd0 */ - 0x2013, 0x2014, 0x201c, 0x201d, - 0x2018, 0x2019, 0x00f7, 0x25ca, - 0x014d, 0x0154, 0x0155, 0x0158, - 0x2039, 0x203a, 0x0159, 0x0156, - /* 0xe0 */ - 0x0157, 0x0160, 0x201a, 0x201e, - 0x0161, 0x015a, 0x015b, 0x00c1, - 0x0164, 0x0165, 0x00cd, 0x017d, - 0x017e, 0x016a, 0x00d3, 0x00d4, - /* 0xf0 */ - 0x016b, 0x016e, 0x00da, 0x016f, - 0x0170, 0x0171, 0x0172, 0x0173, - 0x00dd, 0x00fd, 0x0137, 0x017b, - 0x0141, 0x017c, 0x0122, 0x02c7, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xca, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0xa4, /* 0xa0-0xa7 */ - 0xac, 0xa9, 0x00, 0xc7, 0xc2, 0x00, 0xa8, 0x00, /* 0xa8-0xaf */ - 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0xe7, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x83, 0x00, 0x00, 0x00, 0xea, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0xee, 0xef, 0xcd, 0x85, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0xf2, 0x00, 0x86, 0xf8, 0x00, 0xa7, /* 0xd8-0xdf */ - 0x00, 0x87, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x8e, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x97, 0x99, 0x9b, 0x9a, 0xd6, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x9c, 0x00, 0x9f, 0xf9, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x81, 0x82, 0x00, 0x00, 0x84, 0x88, 0x8c, 0x8d, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0x8b, 0x91, 0x93, /* 0x08-0x0f */ - 0x00, 0x00, 0x94, 0x95, 0x00, 0x00, 0x96, 0x98, /* 0x10-0x17 */ - 0xa2, 0xab, 0x9d, 0x9e, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0xfe, 0xae, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0xb1, 0xb4, 0x00, 0x00, 0xaf, 0xb0, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb5, 0xfa, /* 0x30-0x37 */ - 0x00, 0xbd, 0xbe, 0xb9, 0xba, 0xbb, 0xbc, 0x00, /* 0x38-0x3f */ - 0x00, 0xfc, 0xb8, 0xc1, 0xc4, 0xbf, 0xc0, 0xc5, /* 0x40-0x47 */ - 0xcb, 0x00, 0x00, 0x00, 0xcf, 0xd8, 0x00, 0x00, /* 0x48-0x4f */ - 0xcc, 0xce, 0x00, 0x00, 0xd9, 0xda, 0xdf, 0xe0, /* 0x50-0x57 */ - 0xdb, 0xde, 0xe5, 0xe6, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xe1, 0xe4, 0x00, 0x00, 0xe8, 0xe9, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0xed, 0xf0, 0x00, 0x00, 0xf1, 0xf3, /* 0x68-0x6f */ - 0xf4, 0xf5, 0xf6, 0xf7, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x8f, 0x90, 0xfb, 0xfd, 0xeb, 0xec, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page02[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0xd0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd4, 0xd5, 0xe2, 0x00, 0xd2, 0xd3, 0xe3, 0x00, /* 0x18-0x1f */ - 0xa0, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0xdc, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page21[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xc6, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xad, 0x00, 0x00, 0x00, 0xb2, 0xb3, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page25[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, page02, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, page21, page22, NULL, NULL, page25, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "maccenteuro", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_maccenteuro(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_maccenteuro(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_maccenteuro) -module_exit(exit_nls_maccenteuro) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/mac-croatian.c b/src/linux/fs/nls/mac-croatian.c deleted file mode 100644 index bb19e7a..0000000 --- a/src/linux/fs/nls/mac-croatian.c +++ /dev/null @@ -1,601 +0,0 @@ -/* - * linux/fs/nls/mac-croatian.c - * - * Charset maccroatian translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -/* - * COPYRIGHT AND PERMISSION NOTICE - * - * Copyright 1991-2012 Unicode, Inc. All rights reserved. Distributed under - * the Terms of Use in http://www.unicode.org/copyright.html. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of the Unicode data files and any associated documentation (the "Data - * Files") or Unicode software and any associated documentation (the - * "Software") to deal in the Data Files or Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, and/or sell copies of the Data Files or Software, and - * to permit persons to whom the Data Files or Software are furnished to do - * so, provided that (a) the above copyright notice(s) and this permission - * notice appear with all copies of the Data Files or Software, (b) both the - * above copyright notice(s) and this permission notice appear in associated - * documentation, and (c) there is clear notice in each modified Data File or - * in the Software as well as in the documentation associated with the Data - * File(s) or Software that the data or software has been modified. - * - * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THE DATA FILES OR SOFTWARE. - * - * Except as contained in this notice, the name of a copyright holder shall - * not be used in advertising or otherwise to promote the sale, use or other - * dealings in these Data Files or Software without prior written - * authorization of the copyright holder. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00 */ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10 */ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20 */ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30 */ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40 */ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50 */ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60 */ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70 */ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80 */ - 0x00c4, 0x00c5, 0x00c7, 0x00c9, - 0x00d1, 0x00d6, 0x00dc, 0x00e1, - 0x00e0, 0x00e2, 0x00e4, 0x00e3, - 0x00e5, 0x00e7, 0x00e9, 0x00e8, - /* 0x90 */ - 0x00ea, 0x00eb, 0x00ed, 0x00ec, - 0x00ee, 0x00ef, 0x00f1, 0x00f3, - 0x00f2, 0x00f4, 0x00f6, 0x00f5, - 0x00fa, 0x00f9, 0x00fb, 0x00fc, - /* 0xa0 */ - 0x2020, 0x00b0, 0x00a2, 0x00a3, - 0x00a7, 0x2022, 0x00b6, 0x00df, - 0x00ae, 0x0160, 0x2122, 0x00b4, - 0x00a8, 0x2260, 0x017d, 0x00d8, - /* 0xb0 */ - 0x221e, 0x00b1, 0x2264, 0x2265, - 0x2206, 0x00b5, 0x2202, 0x2211, - 0x220f, 0x0161, 0x222b, 0x00aa, - 0x00ba, 0x03a9, 0x017e, 0x00f8, - /* 0xc0 */ - 0x00bf, 0x00a1, 0x00ac, 0x221a, - 0x0192, 0x2248, 0x0106, 0x00ab, - 0x010c, 0x2026, 0x00a0, 0x00c0, - 0x00c3, 0x00d5, 0x0152, 0x0153, - /* 0xd0 */ - 0x0110, 0x2014, 0x201c, 0x201d, - 0x2018, 0x2019, 0x00f7, 0x25ca, - 0xf8ff, 0x00a9, 0x2044, 0x20ac, - 0x2039, 0x203a, 0x00c6, 0x00bb, - /* 0xe0 */ - 0x2013, 0x00b7, 0x201a, 0x201e, - 0x2030, 0x00c2, 0x0107, 0x00c1, - 0x010d, 0x00c8, 0x00cd, 0x00ce, - 0x00cf, 0x00cc, 0x00d3, 0x00d4, - /* 0xf0 */ - 0x0111, 0x00d2, 0x00da, 0x00db, - 0x00d9, 0x0131, 0x02c6, 0x02dc, - 0x00af, 0x03c0, 0x00cb, 0x02da, - 0x00b8, 0x00ca, 0x00e6, 0x02c7, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xca, 0xc1, 0xa2, 0xa3, 0x00, 0x00, 0x00, 0xa4, /* 0xa0-0xa7 */ - 0xac, 0xd9, 0xbb, 0xc7, 0xc2, 0x00, 0xa8, 0xf8, /* 0xa8-0xaf */ - 0xa1, 0xb1, 0x00, 0x00, 0xab, 0xb5, 0xa6, 0xe1, /* 0xb0-0xb7 */ - 0xfc, 0x00, 0xbc, 0xdf, 0x00, 0x00, 0x00, 0xc0, /* 0xb8-0xbf */ - 0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xde, 0x82, /* 0xc0-0xc7 */ - 0xe9, 0x83, 0xfd, 0xfa, 0xed, 0xea, 0xeb, 0xec, /* 0xc8-0xcf */ - 0x00, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0x00, /* 0xd0-0xd7 */ - 0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0x00, 0x00, 0xa7, /* 0xd8-0xdf */ - 0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xfe, 0x8d, /* 0xe0-0xe7 */ - 0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, /* 0xe8-0xef */ - 0x00, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6, /* 0xf0-0xf7 */ - 0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0xe6, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0x00, 0x00, /* 0x08-0x0f */ - 0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0xce, 0xcf, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xa9, 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0xbe, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page02[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xff, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0xfb, 0x00, 0xf7, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page03[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0xe0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd4, 0xd5, 0xe2, 0x00, 0xd2, 0xd3, 0xe3, 0x00, /* 0x18-0x1f */ - 0xa0, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0xdc, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page21[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xb4, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, /* 0x08-0x0f */ - 0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xb0, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xad, 0x00, 0x00, 0x00, 0xb2, 0xb3, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page25[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char pagef8[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd8, /* 0xf8-0xff */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, page02, page03, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, page21, page22, NULL, NULL, page25, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - pagef8, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "maccroatian", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_maccroatian(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_maccroatian(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_maccroatian) -module_exit(exit_nls_maccroatian) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/mac-cyrillic.c b/src/linux/fs/nls/mac-cyrillic.c deleted file mode 100644 index 2a7dea3..0000000 --- a/src/linux/fs/nls/mac-cyrillic.c +++ /dev/null @@ -1,496 +0,0 @@ -/* - * linux/fs/nls/mac-cyrillic.c - * - * Charset maccyrillic translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -/* - * COPYRIGHT AND PERMISSION NOTICE - * - * Copyright 1991-2012 Unicode, Inc. All rights reserved. Distributed under - * the Terms of Use in http://www.unicode.org/copyright.html. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of the Unicode data files and any associated documentation (the "Data - * Files") or Unicode software and any associated documentation (the - * "Software") to deal in the Data Files or Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, and/or sell copies of the Data Files or Software, and - * to permit persons to whom the Data Files or Software are furnished to do - * so, provided that (a) the above copyright notice(s) and this permission - * notice appear with all copies of the Data Files or Software, (b) both the - * above copyright notice(s) and this permission notice appear in associated - * documentation, and (c) there is clear notice in each modified Data File or - * in the Software as well as in the documentation associated with the Data - * File(s) or Software that the data or software has been modified. - * - * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THE DATA FILES OR SOFTWARE. - * - * Except as contained in this notice, the name of a copyright holder shall - * not be used in advertising or otherwise to promote the sale, use or other - * dealings in these Data Files or Software without prior written - * authorization of the copyright holder. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00 */ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10 */ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20 */ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30 */ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40 */ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50 */ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60 */ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70 */ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80 */ - 0x0410, 0x0411, 0x0412, 0x0413, - 0x0414, 0x0415, 0x0416, 0x0417, - 0x0418, 0x0419, 0x041a, 0x041b, - 0x041c, 0x041d, 0x041e, 0x041f, - /* 0x90 */ - 0x0420, 0x0421, 0x0422, 0x0423, - 0x0424, 0x0425, 0x0426, 0x0427, - 0x0428, 0x0429, 0x042a, 0x042b, - 0x042c, 0x042d, 0x042e, 0x042f, - /* 0xa0 */ - 0x2020, 0x00b0, 0x0490, 0x00a3, - 0x00a7, 0x2022, 0x00b6, 0x0406, - 0x00ae, 0x00a9, 0x2122, 0x0402, - 0x0452, 0x2260, 0x0403, 0x0453, - /* 0xb0 */ - 0x221e, 0x00b1, 0x2264, 0x2265, - 0x0456, 0x00b5, 0x0491, 0x0408, - 0x0404, 0x0454, 0x0407, 0x0457, - 0x0409, 0x0459, 0x040a, 0x045a, - /* 0xc0 */ - 0x0458, 0x0405, 0x00ac, 0x221a, - 0x0192, 0x2248, 0x2206, 0x00ab, - 0x00bb, 0x2026, 0x00a0, 0x040b, - 0x045b, 0x040c, 0x045c, 0x0455, - /* 0xd0 */ - 0x2013, 0x2014, 0x201c, 0x201d, - 0x2018, 0x2019, 0x00f7, 0x201e, - 0x040e, 0x045e, 0x040f, 0x045f, - 0x2116, 0x0401, 0x0451, 0x044f, - /* 0xe0 */ - 0x0430, 0x0431, 0x0432, 0x0433, - 0x0434, 0x0435, 0x0436, 0x0437, - 0x0438, 0x0439, 0x043a, 0x043b, - 0x043c, 0x043d, 0x043e, 0x043f, - /* 0xf0 */ - 0x0440, 0x0441, 0x0442, 0x0443, - 0x0444, 0x0445, 0x0446, 0x0447, - 0x0448, 0x0449, 0x044a, 0x044b, - 0x044c, 0x044d, 0x044e, 0x20ac, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xca, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0xa4, /* 0xa0-0xa7 */ - 0x00, 0xa9, 0x00, 0xc7, 0xc2, 0x00, 0xa8, 0x00, /* 0xa8-0xaf */ - 0xa1, 0xb1, 0x00, 0x00, 0x00, 0xb5, 0xa6, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page04[256] = { - 0x00, 0xdd, 0xab, 0xae, 0xb8, 0xc1, 0xa7, 0xba, /* 0x00-0x07 */ - 0xb7, 0xbc, 0xbe, 0xcb, 0xcd, 0x00, 0xd8, 0xda, /* 0x08-0x0f */ - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x10-0x17 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x18-0x1f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x20-0x27 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x28-0x2f */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x30-0x37 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x38-0x3f */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0x40-0x47 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* 0x48-0x4f */ - 0x00, 0xde, 0xac, 0xaf, 0xb9, 0xcf, 0xb4, 0xbb, /* 0x50-0x57 */ - 0xc0, 0xbd, 0xbf, 0xcc, 0xce, 0x00, 0xd9, 0xdb, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0xa2, 0xb6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0xd0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd4, 0xd5, 0x00, 0x00, 0xd2, 0xd3, 0xd7, 0x00, /* 0x18-0x1f */ - 0xa0, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page21[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc6, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xb0, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xad, 0x00, 0x00, 0x00, 0xb2, 0xb3, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, NULL, NULL, page04, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, page21, page22, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "maccyrillic", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_maccyrillic(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_maccyrillic(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_maccyrillic) -module_exit(exit_nls_maccyrillic) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/mac-gaelic.c b/src/linux/fs/nls/mac-gaelic.c deleted file mode 100644 index 77b0016..0000000 --- a/src/linux/fs/nls/mac-gaelic.c +++ /dev/null @@ -1,566 +0,0 @@ -/* - * linux/fs/nls/mac-gaelic.c - * - * Charset macgaelic translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -/* - * COPYRIGHT AND PERMISSION NOTICE - * - * Copyright 1991-2012 Unicode, Inc. All rights reserved. Distributed under - * the Terms of Use in http://www.unicode.org/copyright.html. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of the Unicode data files and any associated documentation (the "Data - * Files") or Unicode software and any associated documentation (the - * "Software") to deal in the Data Files or Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, and/or sell copies of the Data Files or Software, and - * to permit persons to whom the Data Files or Software are furnished to do - * so, provided that (a) the above copyright notice(s) and this permission - * notice appear with all copies of the Data Files or Software, (b) both the - * above copyright notice(s) and this permission notice appear in associated - * documentation, and (c) there is clear notice in each modified Data File or - * in the Software as well as in the documentation associated with the Data - * File(s) or Software that the data or software has been modified. - * - * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THE DATA FILES OR SOFTWARE. - * - * Except as contained in this notice, the name of a copyright holder shall - * not be used in advertising or otherwise to promote the sale, use or other - * dealings in these Data Files or Software without prior written - * authorization of the copyright holder. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00 */ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10 */ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20 */ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30 */ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40 */ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50 */ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60 */ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70 */ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80 */ - 0x00c4, 0x00c5, 0x00c7, 0x00c9, - 0x00d1, 0x00d6, 0x00dc, 0x00e1, - 0x00e0, 0x00e2, 0x00e4, 0x00e3, - 0x00e5, 0x00e7, 0x00e9, 0x00e8, - /* 0x90 */ - 0x00ea, 0x00eb, 0x00ed, 0x00ec, - 0x00ee, 0x00ef, 0x00f1, 0x00f3, - 0x00f2, 0x00f4, 0x00f6, 0x00f5, - 0x00fa, 0x00f9, 0x00fb, 0x00fc, - /* 0xa0 */ - 0x2020, 0x00b0, 0x00a2, 0x00a3, - 0x00a7, 0x2022, 0x00b6, 0x00df, - 0x00ae, 0x00a9, 0x2122, 0x00b4, - 0x00a8, 0x2260, 0x00c6, 0x00d8, - /* 0xb0 */ - 0x1e02, 0x00b1, 0x2264, 0x2265, - 0x1e03, 0x010a, 0x010b, 0x1e0a, - 0x1e0b, 0x1e1e, 0x1e1f, 0x0120, - 0x0121, 0x1e40, 0x00e6, 0x00f8, - /* 0xc0 */ - 0x1e41, 0x1e56, 0x1e57, 0x027c, - 0x0192, 0x017f, 0x1e60, 0x00ab, - 0x00bb, 0x2026, 0x00a0, 0x00c0, - 0x00c3, 0x00d5, 0x0152, 0x0153, - /* 0xd0 */ - 0x2013, 0x2014, 0x201c, 0x201d, - 0x2018, 0x2019, 0x1e61, 0x1e9b, - 0x00ff, 0x0178, 0x1e6a, 0x20ac, - 0x2039, 0x203a, 0x0176, 0x0177, - /* 0xe0 */ - 0x1e6b, 0x00b7, 0x1ef2, 0x1ef3, - 0x204a, 0x00c2, 0x00ca, 0x00c1, - 0x00cb, 0x00c8, 0x00cd, 0x00ce, - 0x00cf, 0x00cc, 0x00d3, 0x00d4, - /* 0xf0 */ - 0x2663, 0x00d2, 0x00da, 0x00db, - 0x00d9, 0x0131, 0x00dd, 0x00fd, - 0x0174, 0x0175, 0x1e84, 0x1e85, - 0x1e80, 0x1e81, 0x1e82, 0x1e83, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xca, 0x00, 0xa2, 0xa3, 0x00, 0x00, 0x00, 0xa4, /* 0xa0-0xa7 */ - 0xac, 0xa9, 0x00, 0xc7, 0x00, 0x00, 0xa8, 0x00, /* 0xa8-0xaf */ - 0xa1, 0xb1, 0x00, 0x00, 0xab, 0x00, 0xa6, 0xe1, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xae, 0x82, /* 0xc0-0xc7 */ - 0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec, /* 0xc8-0xcf */ - 0x00, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0x00, /* 0xd0-0xd7 */ - 0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0xf6, 0x00, 0xa7, /* 0xd8-0xdf */ - 0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xbe, 0x8d, /* 0xe0-0xe7 */ - 0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, /* 0xe8-0xef */ - 0x00, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0x00, /* 0xf0-0xf7 */ - 0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0xf7, 0x00, 0xd8, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0xb5, 0xb6, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0xbb, 0xbc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0xce, 0xcf, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0xf8, 0xf9, 0xde, 0xdf, /* 0x70-0x77 */ - 0xd9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page02[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page1e[256] = { - 0x00, 0x00, 0xb0, 0xb4, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0xb7, 0xb8, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0xba, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0xbd, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0xc2, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xc6, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0xda, 0xe0, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0xfc, 0xfd, 0xfe, 0xff, 0xfa, 0xfb, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0xe2, 0xe3, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0xd0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd4, 0xd5, 0x00, 0x00, 0xd2, 0xd3, 0x00, 0x00, /* 0x18-0x1f */ - 0xa0, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0xdc, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page21[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xad, 0x00, 0x00, 0x00, 0xb2, 0xb3, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page26[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, page02, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, page1e, NULL, - page20, page21, page22, NULL, NULL, NULL, page26, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x00-0x07 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x08-0x0f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x10-0x17 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x18-0x1f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x20-0x27 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x28-0x2f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x30-0x37 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x38-0x3f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x40-0x47 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x48-0x4f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x50-0x57 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x58-0x5f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x60-0x67 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x68-0x6f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x70-0x77 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x78-0x7f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x80-0x87 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x88-0x8f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x90-0x97 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x98-0x9f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xa0-0xa7 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xa8-0xaf */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xb0-0xb7 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xb8-0xbf */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xc0-0xc7 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xc8-0xcf */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xd0-0xd7 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xd8-0xdf */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xe0-0xe7 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xe8-0xef */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xf0-0xf7 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "macgaelic", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_macgaelic(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_macgaelic(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_macgaelic) -module_exit(exit_nls_macgaelic) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/mac-greek.c b/src/linux/fs/nls/mac-greek.c deleted file mode 100644 index 1eccf49..0000000 --- a/src/linux/fs/nls/mac-greek.c +++ /dev/null @@ -1,496 +0,0 @@ -/* - * linux/fs/nls/mac-greek.c - * - * Charset macgreek translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -/* - * COPYRIGHT AND PERMISSION NOTICE - * - * Copyright 1991-2012 Unicode, Inc. All rights reserved. Distributed under - * the Terms of Use in http://www.unicode.org/copyright.html. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of the Unicode data files and any associated documentation (the "Data - * Files") or Unicode software and any associated documentation (the - * "Software") to deal in the Data Files or Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, and/or sell copies of the Data Files or Software, and - * to permit persons to whom the Data Files or Software are furnished to do - * so, provided that (a) the above copyright notice(s) and this permission - * notice appear with all copies of the Data Files or Software, (b) both the - * above copyright notice(s) and this permission notice appear in associated - * documentation, and (c) there is clear notice in each modified Data File or - * in the Software as well as in the documentation associated with the Data - * File(s) or Software that the data or software has been modified. - * - * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THE DATA FILES OR SOFTWARE. - * - * Except as contained in this notice, the name of a copyright holder shall - * not be used in advertising or otherwise to promote the sale, use or other - * dealings in these Data Files or Software without prior written - * authorization of the copyright holder. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00 */ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10 */ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20 */ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30 */ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40 */ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50 */ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60 */ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70 */ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80 */ - 0x00c4, 0x00b9, 0x00b2, 0x00c9, - 0x00b3, 0x00d6, 0x00dc, 0x0385, - 0x00e0, 0x00e2, 0x00e4, 0x0384, - 0x00a8, 0x00e7, 0x00e9, 0x00e8, - /* 0x90 */ - 0x00ea, 0x00eb, 0x00a3, 0x2122, - 0x00ee, 0x00ef, 0x2022, 0x00bd, - 0x2030, 0x00f4, 0x00f6, 0x00a6, - 0x20ac, 0x00f9, 0x00fb, 0x00fc, - /* 0xa0 */ - 0x2020, 0x0393, 0x0394, 0x0398, - 0x039b, 0x039e, 0x03a0, 0x00df, - 0x00ae, 0x00a9, 0x03a3, 0x03aa, - 0x00a7, 0x2260, 0x00b0, 0x00b7, - /* 0xb0 */ - 0x0391, 0x00b1, 0x2264, 0x2265, - 0x00a5, 0x0392, 0x0395, 0x0396, - 0x0397, 0x0399, 0x039a, 0x039c, - 0x03a6, 0x03ab, 0x03a8, 0x03a9, - /* 0xc0 */ - 0x03ac, 0x039d, 0x00ac, 0x039f, - 0x03a1, 0x2248, 0x03a4, 0x00ab, - 0x00bb, 0x2026, 0x00a0, 0x03a5, - 0x03a7, 0x0386, 0x0388, 0x0153, - /* 0xd0 */ - 0x2013, 0x2015, 0x201c, 0x201d, - 0x2018, 0x2019, 0x00f7, 0x0389, - 0x038a, 0x038c, 0x038e, 0x03ad, - 0x03ae, 0x03af, 0x03cc, 0x038f, - /* 0xe0 */ - 0x03cd, 0x03b1, 0x03b2, 0x03c8, - 0x03b4, 0x03b5, 0x03c6, 0x03b3, - 0x03b7, 0x03b9, 0x03be, 0x03ba, - 0x03bb, 0x03bc, 0x03bd, 0x03bf, - /* 0xf0 */ - 0x03c0, 0x03ce, 0x03c1, 0x03c3, - 0x03c4, 0x03b8, 0x03c9, 0x03c2, - 0x03c7, 0x03c5, 0x03b6, 0x03ca, - 0x03cb, 0x0390, 0x03b0, 0x00ad, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xca, 0x00, 0x00, 0x92, 0x00, 0xb4, 0x9b, 0xac, /* 0xa0-0xa7 */ - 0x8c, 0xa9, 0x00, 0xc7, 0xc2, 0xff, 0xa8, 0x00, /* 0xa8-0xaf */ - 0xae, 0xb1, 0x82, 0x84, 0x00, 0x00, 0x00, 0xaf, /* 0xb0-0xb7 */ - 0x00, 0x81, 0x00, 0xc8, 0x00, 0x97, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0xa7, /* 0xd8-0xdf */ - 0x88, 0x00, 0x89, 0x00, 0x8a, 0x00, 0x00, 0x8d, /* 0xe0-0xe7 */ - 0x8f, 0x8e, 0x90, 0x91, 0x00, 0x00, 0x94, 0x95, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x9a, 0xd6, /* 0xf0-0xf7 */ - 0x00, 0x9d, 0x00, 0x9e, 0x9f, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page03[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x8b, 0x87, 0xcd, 0x00, /* 0x80-0x87 */ - 0xce, 0xd7, 0xd8, 0x00, 0xd9, 0x00, 0xda, 0xdf, /* 0x88-0x8f */ - 0xfd, 0xb0, 0xb5, 0xa1, 0xa2, 0xb6, 0xb7, 0xb8, /* 0x90-0x97 */ - 0xa3, 0xb9, 0xba, 0xa4, 0xbb, 0xc1, 0xa5, 0xc3, /* 0x98-0x9f */ - 0xa6, 0xc4, 0x00, 0xaa, 0xc6, 0xcb, 0xbc, 0xcc, /* 0xa0-0xa7 */ - 0xbe, 0xbf, 0xab, 0xbd, 0xc0, 0xdb, 0xdc, 0xdd, /* 0xa8-0xaf */ - 0xfe, 0xe1, 0xe2, 0xe7, 0xe4, 0xe5, 0xfa, 0xe8, /* 0xb0-0xb7 */ - 0xf5, 0xe9, 0xeb, 0xec, 0xed, 0xee, 0xea, 0xef, /* 0xb8-0xbf */ - 0xf0, 0xf2, 0xf7, 0xf3, 0xf4, 0xf9, 0xe6, 0xf8, /* 0xc0-0xc7 */ - 0xe3, 0xf6, 0xfb, 0xfc, 0xde, 0xe0, 0xf1, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0x00, /* 0x10-0x17 */ - 0xd4, 0xd5, 0x00, 0x00, 0xd2, 0xd3, 0x00, 0x00, /* 0x18-0x1f */ - 0xa0, 0x00, 0x96, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page21[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xad, 0x00, 0x00, 0x00, 0xb2, 0xb3, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, NULL, page03, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, page21, page22, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "macgreek", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_macgreek(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_macgreek(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_macgreek) -module_exit(exit_nls_macgreek) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/mac-iceland.c b/src/linux/fs/nls/mac-iceland.c deleted file mode 100644 index cbd0875..0000000 --- a/src/linux/fs/nls/mac-iceland.c +++ /dev/null @@ -1,601 +0,0 @@ -/* - * linux/fs/nls/mac-iceland.c - * - * Charset maciceland translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -/* - * COPYRIGHT AND PERMISSION NOTICE - * - * Copyright 1991-2012 Unicode, Inc. All rights reserved. Distributed under - * the Terms of Use in http://www.unicode.org/copyright.html. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of the Unicode data files and any associated documentation (the "Data - * Files") or Unicode software and any associated documentation (the - * "Software") to deal in the Data Files or Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, and/or sell copies of the Data Files or Software, and - * to permit persons to whom the Data Files or Software are furnished to do - * so, provided that (a) the above copyright notice(s) and this permission - * notice appear with all copies of the Data Files or Software, (b) both the - * above copyright notice(s) and this permission notice appear in associated - * documentation, and (c) there is clear notice in each modified Data File or - * in the Software as well as in the documentation associated with the Data - * File(s) or Software that the data or software has been modified. - * - * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THE DATA FILES OR SOFTWARE. - * - * Except as contained in this notice, the name of a copyright holder shall - * not be used in advertising or otherwise to promote the sale, use or other - * dealings in these Data Files or Software without prior written - * authorization of the copyright holder. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00 */ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10 */ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20 */ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30 */ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40 */ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50 */ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60 */ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70 */ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80 */ - 0x00c4, 0x00c5, 0x00c7, 0x00c9, - 0x00d1, 0x00d6, 0x00dc, 0x00e1, - 0x00e0, 0x00e2, 0x00e4, 0x00e3, - 0x00e5, 0x00e7, 0x00e9, 0x00e8, - /* 0x90 */ - 0x00ea, 0x00eb, 0x00ed, 0x00ec, - 0x00ee, 0x00ef, 0x00f1, 0x00f3, - 0x00f2, 0x00f4, 0x00f6, 0x00f5, - 0x00fa, 0x00f9, 0x00fb, 0x00fc, - /* 0xa0 */ - 0x00dd, 0x00b0, 0x00a2, 0x00a3, - 0x00a7, 0x2022, 0x00b6, 0x00df, - 0x00ae, 0x00a9, 0x2122, 0x00b4, - 0x00a8, 0x2260, 0x00c6, 0x00d8, - /* 0xb0 */ - 0x221e, 0x00b1, 0x2264, 0x2265, - 0x00a5, 0x00b5, 0x2202, 0x2211, - 0x220f, 0x03c0, 0x222b, 0x00aa, - 0x00ba, 0x03a9, 0x00e6, 0x00f8, - /* 0xc0 */ - 0x00bf, 0x00a1, 0x00ac, 0x221a, - 0x0192, 0x2248, 0x2206, 0x00ab, - 0x00bb, 0x2026, 0x00a0, 0x00c0, - 0x00c3, 0x00d5, 0x0152, 0x0153, - /* 0xd0 */ - 0x2013, 0x2014, 0x201c, 0x201d, - 0x2018, 0x2019, 0x00f7, 0x25ca, - 0x00ff, 0x0178, 0x2044, 0x20ac, - 0x00d0, 0x00f0, 0x00de, 0x00fe, - /* 0xe0 */ - 0x00fd, 0x00b7, 0x201a, 0x201e, - 0x2030, 0x00c2, 0x00ca, 0x00c1, - 0x00cb, 0x00c8, 0x00cd, 0x00ce, - 0x00cf, 0x00cc, 0x00d3, 0x00d4, - /* 0xf0 */ - 0xf8ff, 0x00d2, 0x00da, 0x00db, - 0x00d9, 0x0131, 0x02c6, 0x02dc, - 0x00af, 0x02d8, 0x02d9, 0x02da, - 0x00b8, 0x02dd, 0x02db, 0x02c7, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xca, 0xc1, 0xa2, 0xa3, 0x00, 0xb4, 0x00, 0xa4, /* 0xa0-0xa7 */ - 0xac, 0xa9, 0xbb, 0xc7, 0xc2, 0x00, 0xa8, 0xf8, /* 0xa8-0xaf */ - 0xa1, 0xb1, 0x00, 0x00, 0xab, 0xb5, 0xa6, 0xe1, /* 0xb0-0xb7 */ - 0xfc, 0x00, 0xbc, 0xc8, 0x00, 0x00, 0x00, 0xc0, /* 0xb8-0xbf */ - 0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xae, 0x82, /* 0xc0-0xc7 */ - 0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec, /* 0xc8-0xcf */ - 0xdc, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0x00, /* 0xd0-0xd7 */ - 0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0xa0, 0xde, 0xa7, /* 0xd8-0xdf */ - 0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xbe, 0x8d, /* 0xe0-0xe7 */ - 0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, /* 0xe8-0xef */ - 0xdd, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6, /* 0xf0-0xf7 */ - 0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0xe0, 0xdf, 0xd8, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0xce, 0xcf, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0xd9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page02[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xff, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0xf9, 0xfa, 0xfb, 0xfe, 0xf7, 0xfd, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page03[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0xd0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd4, 0xd5, 0xe2, 0x00, 0xd2, 0xd3, 0xe3, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page21[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xc6, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, /* 0x08-0x0f */ - 0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xb0, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xad, 0x00, 0x00, 0x00, 0xb2, 0xb3, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page25[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char pagef8[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, /* 0xf8-0xff */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, page02, page03, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, page21, page22, NULL, NULL, page25, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - pagef8, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "maciceland", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_maciceland(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_maciceland(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_maciceland) -module_exit(exit_nls_maciceland) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/mac-inuit.c b/src/linux/fs/nls/mac-inuit.c deleted file mode 100644 index fba8357..0000000 --- a/src/linux/fs/nls/mac-inuit.c +++ /dev/null @@ -1,531 +0,0 @@ -/* - * linux/fs/nls/mac-inuit.c - * - * Charset macinuit translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -/* - * COPYRIGHT AND PERMISSION NOTICE - * - * Copyright 1991-2012 Unicode, Inc. All rights reserved. Distributed under - * the Terms of Use in http://www.unicode.org/copyright.html. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of the Unicode data files and any associated documentation (the "Data - * Files") or Unicode software and any associated documentation (the - * "Software") to deal in the Data Files or Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, and/or sell copies of the Data Files or Software, and - * to permit persons to whom the Data Files or Software are furnished to do - * so, provided that (a) the above copyright notice(s) and this permission - * notice appear with all copies of the Data Files or Software, (b) both the - * above copyright notice(s) and this permission notice appear in associated - * documentation, and (c) there is clear notice in each modified Data File or - * in the Software as well as in the documentation associated with the Data - * File(s) or Software that the data or software has been modified. - * - * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THE DATA FILES OR SOFTWARE. - * - * Except as contained in this notice, the name of a copyright holder shall - * not be used in advertising or otherwise to promote the sale, use or other - * dealings in these Data Files or Software without prior written - * authorization of the copyright holder. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00 */ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10 */ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20 */ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30 */ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40 */ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50 */ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60 */ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70 */ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80 */ - 0x1403, 0x1404, 0x1405, 0x1406, - 0x140a, 0x140b, 0x1431, 0x1432, - 0x1433, 0x1434, 0x1438, 0x1439, - 0x1449, 0x144e, 0x144f, 0x1450, - /* 0x90 */ - 0x1451, 0x1455, 0x1456, 0x1466, - 0x146d, 0x146e, 0x146f, 0x1470, - 0x1472, 0x1473, 0x1483, 0x148b, - 0x148c, 0x148d, 0x148e, 0x1490, - /* 0xa0 */ - 0x1491, 0x00b0, 0x14a1, 0x14a5, - 0x14a6, 0x2022, 0x00b6, 0x14a7, - 0x00ae, 0x00a9, 0x2122, 0x14a8, - 0x14aa, 0x14ab, 0x14bb, 0x14c2, - /* 0xb0 */ - 0x14c3, 0x14c4, 0x14c5, 0x14c7, - 0x14c8, 0x14d0, 0x14ef, 0x14f0, - 0x14f1, 0x14f2, 0x14f4, 0x14f5, - 0x1505, 0x14d5, 0x14d6, 0x14d7, - /* 0xc0 */ - 0x14d8, 0x14da, 0x14db, 0x14ea, - 0x1528, 0x1529, 0x152a, 0x152b, - 0x152d, 0x2026, 0x00a0, 0x152e, - 0x153e, 0x1555, 0x1556, 0x1557, - /* 0xd0 */ - 0x2013, 0x2014, 0x201c, 0x201d, - 0x2018, 0x2019, 0x1558, 0x1559, - 0x155a, 0x155d, 0x1546, 0x1547, - 0x1548, 0x1549, 0x154b, 0x154c, - /* 0xe0 */ - 0x1550, 0x157f, 0x1580, 0x1581, - 0x1582, 0x1583, 0x1584, 0x1585, - 0x158f, 0x1590, 0x1591, 0x1592, - 0x1593, 0x1594, 0x1595, 0x1671, - /* 0xf0 */ - 0x1672, 0x1673, 0x1674, 0x1675, - 0x1676, 0x1596, 0x15a0, 0x15a1, - 0x15a2, 0x15a3, 0x15a4, 0x15a5, - 0x15a6, 0x157c, 0x0141, 0x0142, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xca, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0xa9, 0x00, 0x00, 0x00, 0x00, 0xa8, 0x00, /* 0xa8-0xaf */ - 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page14[256] = { - 0x00, 0x00, 0x00, 0x80, 0x81, 0x82, 0x83, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x84, 0x85, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x86, 0x87, 0x88, 0x89, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x8a, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x8d, 0x8e, /* 0x48-0x4f */ - 0x8f, 0x90, 0x00, 0x00, 0x00, 0x91, 0x92, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x95, 0x96, /* 0x68-0x6f */ - 0x97, 0x00, 0x98, 0x99, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x9b, 0x9c, 0x9d, 0x9e, 0x00, /* 0x88-0x8f */ - 0x9f, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0xa2, 0x00, 0x00, 0x00, 0xa3, 0xa4, 0xa7, /* 0xa0-0xa7 */ - 0xab, 0x00, 0xac, 0xad, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0xae, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0xaf, 0xb0, 0xb1, 0xb2, 0x00, 0xb3, /* 0xc0-0xc7 */ - 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0xb5, 0x00, 0x00, 0x00, 0x00, 0xbd, 0xbe, 0xbf, /* 0xd0-0xd7 */ - 0xc0, 0x00, 0xc1, 0xc2, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0x00, 0xb6, /* 0xe8-0xef */ - 0xb7, 0xb8, 0xb9, 0x00, 0xba, 0xbb, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page15[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0xc4, 0xc5, 0xc6, 0xc7, 0x00, 0xc8, 0xcb, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcc, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0xdb, /* 0x40-0x47 */ - 0xdc, 0xdd, 0x00, 0xde, 0xdf, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xe0, 0x00, 0x00, 0x00, 0x00, 0xcd, 0xce, 0xcf, /* 0x50-0x57 */ - 0xd6, 0xd7, 0xd8, 0x00, 0x00, 0xd9, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0xe1, /* 0x78-0x7f */ - 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, /* 0x88-0x8f */ - 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xf5, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page16[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0xd0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd4, 0xd5, 0x00, 0x00, 0xd2, 0xd3, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page21[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, page14, page15, page16, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, page21, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x00-0x07 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x08-0x0f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x10-0x17 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x18-0x1f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x20-0x27 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x28-0x2f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x30-0x37 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x38-0x3f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x40-0x47 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x48-0x4f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x50-0x57 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x58-0x5f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x60-0x67 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x68-0x6f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x70-0x77 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x78-0x7f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x80-0x87 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x88-0x8f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x90-0x97 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0x98-0x9f */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xa0-0xa7 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xa8-0xaf */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xb0-0xb7 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xb8-0xbf */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xc0-0xc7 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xc8-0xcf */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xd0-0xd7 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xd8-0xdf */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xe0-0xe7 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xe8-0xef */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xf0-0xf7 */ - 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "macinuit", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_macinuit(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_macinuit(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_macinuit) -module_exit(exit_nls_macinuit) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/mac-roman.c b/src/linux/fs/nls/mac-roman.c deleted file mode 100644 index b6a98a5..0000000 --- a/src/linux/fs/nls/mac-roman.c +++ /dev/null @@ -1,636 +0,0 @@ -/* - * linux/fs/nls/mac-roman.c - * - * Charset macroman translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -/* - * COPYRIGHT AND PERMISSION NOTICE - * - * Copyright 1991-2012 Unicode, Inc. All rights reserved. Distributed under - * the Terms of Use in http://www.unicode.org/copyright.html. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of the Unicode data files and any associated documentation (the "Data - * Files") or Unicode software and any associated documentation (the - * "Software") to deal in the Data Files or Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, and/or sell copies of the Data Files or Software, and - * to permit persons to whom the Data Files or Software are furnished to do - * so, provided that (a) the above copyright notice(s) and this permission - * notice appear with all copies of the Data Files or Software, (b) both the - * above copyright notice(s) and this permission notice appear in associated - * documentation, and (c) there is clear notice in each modified Data File or - * in the Software as well as in the documentation associated with the Data - * File(s) or Software that the data or software has been modified. - * - * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THE DATA FILES OR SOFTWARE. - * - * Except as contained in this notice, the name of a copyright holder shall - * not be used in advertising or otherwise to promote the sale, use or other - * dealings in these Data Files or Software without prior written - * authorization of the copyright holder. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00 */ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10 */ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20 */ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30 */ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40 */ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50 */ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60 */ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70 */ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80 */ - 0x00c4, 0x00c5, 0x00c7, 0x00c9, - 0x00d1, 0x00d6, 0x00dc, 0x00e1, - 0x00e0, 0x00e2, 0x00e4, 0x00e3, - 0x00e5, 0x00e7, 0x00e9, 0x00e8, - /* 0x90 */ - 0x00ea, 0x00eb, 0x00ed, 0x00ec, - 0x00ee, 0x00ef, 0x00f1, 0x00f3, - 0x00f2, 0x00f4, 0x00f6, 0x00f5, - 0x00fa, 0x00f9, 0x00fb, 0x00fc, - /* 0xa0 */ - 0x2020, 0x00b0, 0x00a2, 0x00a3, - 0x00a7, 0x2022, 0x00b6, 0x00df, - 0x00ae, 0x00a9, 0x2122, 0x00b4, - 0x00a8, 0x2260, 0x00c6, 0x00d8, - /* 0xb0 */ - 0x221e, 0x00b1, 0x2264, 0x2265, - 0x00a5, 0x00b5, 0x2202, 0x2211, - 0x220f, 0x03c0, 0x222b, 0x00aa, - 0x00ba, 0x03a9, 0x00e6, 0x00f8, - /* 0xc0 */ - 0x00bf, 0x00a1, 0x00ac, 0x221a, - 0x0192, 0x2248, 0x2206, 0x00ab, - 0x00bb, 0x2026, 0x00a0, 0x00c0, - 0x00c3, 0x00d5, 0x0152, 0x0153, - /* 0xd0 */ - 0x2013, 0x2014, 0x201c, 0x201d, - 0x2018, 0x2019, 0x00f7, 0x25ca, - 0x00ff, 0x0178, 0x2044, 0x20ac, - 0x2039, 0x203a, 0xfb01, 0xfb02, - /* 0xe0 */ - 0x2021, 0x00b7, 0x201a, 0x201e, - 0x2030, 0x00c2, 0x00ca, 0x00c1, - 0x00cb, 0x00c8, 0x00cd, 0x00ce, - 0x00cf, 0x00cc, 0x00d3, 0x00d4, - /* 0xf0 */ - 0xf8ff, 0x00d2, 0x00da, 0x00db, - 0x00d9, 0x0131, 0x02c6, 0x02dc, - 0x00af, 0x02d8, 0x02d9, 0x02da, - 0x00b8, 0x02dd, 0x02db, 0x02c7, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xca, 0xc1, 0xa2, 0xa3, 0x00, 0xb4, 0x00, 0xa4, /* 0xa0-0xa7 */ - 0xac, 0xa9, 0xbb, 0xc7, 0xc2, 0x00, 0xa8, 0xf8, /* 0xa8-0xaf */ - 0xa1, 0xb1, 0x00, 0x00, 0xab, 0xb5, 0xa6, 0xe1, /* 0xb0-0xb7 */ - 0xfc, 0x00, 0xbc, 0xc8, 0x00, 0x00, 0x00, 0xc0, /* 0xb8-0xbf */ - 0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xae, 0x82, /* 0xc0-0xc7 */ - 0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec, /* 0xc8-0xcf */ - 0x00, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0x00, /* 0xd0-0xd7 */ - 0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0x00, 0x00, 0xa7, /* 0xd8-0xdf */ - 0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xbe, 0x8d, /* 0xe0-0xe7 */ - 0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, /* 0xe8-0xef */ - 0x00, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6, /* 0xf0-0xf7 */ - 0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0x00, 0x00, 0xd8, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0xce, 0xcf, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0xd9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page02[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xff, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0xf9, 0xfa, 0xfb, 0xfe, 0xf7, 0xfd, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page03[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0xd0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd4, 0xd5, 0xe2, 0x00, 0xd2, 0xd3, 0xe3, 0x00, /* 0x18-0x1f */ - 0xa0, 0xe0, 0xa5, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0xdc, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page21[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xc6, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, /* 0x08-0x0f */ - 0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xb0, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xad, 0x00, 0x00, 0x00, 0xb2, 0xb3, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page25[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char pagef8[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, /* 0xf8-0xff */ -}; - -static const unsigned char pagefb[256] = { - 0x00, 0xde, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, page02, page03, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, page21, page22, NULL, NULL, page25, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - pagef8, NULL, NULL, pagefb, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "macroman", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_macroman(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_macroman(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_macroman) -module_exit(exit_nls_macroman) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/mac-romanian.c b/src/linux/fs/nls/mac-romanian.c deleted file mode 100644 index 25547f0..0000000 --- a/src/linux/fs/nls/mac-romanian.c +++ /dev/null @@ -1,601 +0,0 @@ -/* - * linux/fs/nls/mac-romanian.c - * - * Charset macromanian translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -/* - * COPYRIGHT AND PERMISSION NOTICE - * - * Copyright 1991-2012 Unicode, Inc. All rights reserved. Distributed under - * the Terms of Use in http://www.unicode.org/copyright.html. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of the Unicode data files and any associated documentation (the "Data - * Files") or Unicode software and any associated documentation (the - * "Software") to deal in the Data Files or Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, and/or sell copies of the Data Files or Software, and - * to permit persons to whom the Data Files or Software are furnished to do - * so, provided that (a) the above copyright notice(s) and this permission - * notice appear with all copies of the Data Files or Software, (b) both the - * above copyright notice(s) and this permission notice appear in associated - * documentation, and (c) there is clear notice in each modified Data File or - * in the Software as well as in the documentation associated with the Data - * File(s) or Software that the data or software has been modified. - * - * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THE DATA FILES OR SOFTWARE. - * - * Except as contained in this notice, the name of a copyright holder shall - * not be used in advertising or otherwise to promote the sale, use or other - * dealings in these Data Files or Software without prior written - * authorization of the copyright holder. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00 */ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10 */ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20 */ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30 */ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40 */ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50 */ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60 */ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70 */ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80 */ - 0x00c4, 0x00c5, 0x00c7, 0x00c9, - 0x00d1, 0x00d6, 0x00dc, 0x00e1, - 0x00e0, 0x00e2, 0x00e4, 0x00e3, - 0x00e5, 0x00e7, 0x00e9, 0x00e8, - /* 0x90 */ - 0x00ea, 0x00eb, 0x00ed, 0x00ec, - 0x00ee, 0x00ef, 0x00f1, 0x00f3, - 0x00f2, 0x00f4, 0x00f6, 0x00f5, - 0x00fa, 0x00f9, 0x00fb, 0x00fc, - /* 0xa0 */ - 0x2020, 0x00b0, 0x00a2, 0x00a3, - 0x00a7, 0x2022, 0x00b6, 0x00df, - 0x00ae, 0x00a9, 0x2122, 0x00b4, - 0x00a8, 0x2260, 0x0102, 0x0218, - /* 0xb0 */ - 0x221e, 0x00b1, 0x2264, 0x2265, - 0x00a5, 0x00b5, 0x2202, 0x2211, - 0x220f, 0x03c0, 0x222b, 0x00aa, - 0x00ba, 0x03a9, 0x0103, 0x0219, - /* 0xc0 */ - 0x00bf, 0x00a1, 0x00ac, 0x221a, - 0x0192, 0x2248, 0x2206, 0x00ab, - 0x00bb, 0x2026, 0x00a0, 0x00c0, - 0x00c3, 0x00d5, 0x0152, 0x0153, - /* 0xd0 */ - 0x2013, 0x2014, 0x201c, 0x201d, - 0x2018, 0x2019, 0x00f7, 0x25ca, - 0x00ff, 0x0178, 0x2044, 0x20ac, - 0x2039, 0x203a, 0x021a, 0x021b, - /* 0xe0 */ - 0x2021, 0x00b7, 0x201a, 0x201e, - 0x2030, 0x00c2, 0x00ca, 0x00c1, - 0x00cb, 0x00c8, 0x00cd, 0x00ce, - 0x00cf, 0x00cc, 0x00d3, 0x00d4, - /* 0xf0 */ - 0xf8ff, 0x00d2, 0x00da, 0x00db, - 0x00d9, 0x0131, 0x02c6, 0x02dc, - 0x00af, 0x02d8, 0x02d9, 0x02da, - 0x00b8, 0x02dd, 0x02db, 0x02c7, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xca, 0xc1, 0xa2, 0xa3, 0x00, 0xb4, 0x00, 0xa4, /* 0xa0-0xa7 */ - 0xac, 0xa9, 0xbb, 0xc7, 0xc2, 0x00, 0xa8, 0xf8, /* 0xa8-0xaf */ - 0xa1, 0xb1, 0x00, 0x00, 0xab, 0xb5, 0xa6, 0xe1, /* 0xb0-0xb7 */ - 0xfc, 0x00, 0xbc, 0xc8, 0x00, 0x00, 0x00, 0xc0, /* 0xb8-0xbf */ - 0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0x00, 0x82, /* 0xc0-0xc7 */ - 0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec, /* 0xc8-0xcf */ - 0x00, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0x00, /* 0xd0-0xd7 */ - 0x00, 0xf4, 0xf2, 0xf3, 0x86, 0x00, 0x00, 0xa7, /* 0xd8-0xdf */ - 0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0x00, 0x8d, /* 0xe0-0xe7 */ - 0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, /* 0xe8-0xef */ - 0x00, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6, /* 0xf0-0xf7 */ - 0x00, 0x9d, 0x9c, 0x9e, 0x9f, 0x00, 0x00, 0xd8, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0xae, 0xbe, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0xce, 0xcf, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0xd9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page02[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xaf, 0xbf, 0xde, 0xdf, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xff, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0xf9, 0xfa, 0xfb, 0xfe, 0xf7, 0xfd, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page03[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0xd0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd4, 0xd5, 0xe2, 0x00, 0xd2, 0xd3, 0xe3, 0x00, /* 0x18-0x1f */ - 0xa0, 0xe0, 0xa5, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0xdc, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0xdb, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page21[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xc6, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, /* 0x08-0x0f */ - 0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xb0, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xad, 0x00, 0x00, 0x00, 0xb2, 0xb3, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page25[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char pagef8[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, /* 0xf8-0xff */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, page02, page03, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, page21, page22, NULL, NULL, page25, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - pagef8, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "macromanian", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_macromanian(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_macromanian(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_macromanian) -module_exit(exit_nls_macromanian) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/mac-turkish.c b/src/linux/fs/nls/mac-turkish.c deleted file mode 100644 index b5454bc..0000000 --- a/src/linux/fs/nls/mac-turkish.c +++ /dev/null @@ -1,601 +0,0 @@ -/* - * linux/fs/nls/mac-turkish.c - * - * Charset macturkish translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -/* - * COPYRIGHT AND PERMISSION NOTICE - * - * Copyright 1991-2012 Unicode, Inc. All rights reserved. Distributed under - * the Terms of Use in http://www.unicode.org/copyright.html. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of the Unicode data files and any associated documentation (the "Data - * Files") or Unicode software and any associated documentation (the - * "Software") to deal in the Data Files or Software without restriction, - * including without limitation the rights to use, copy, modify, merge, - * publish, distribute, and/or sell copies of the Data Files or Software, and - * to permit persons to whom the Data Files or Software are furnished to do - * so, provided that (a) the above copyright notice(s) and this permission - * notice appear with all copies of the Data Files or Software, (b) both the - * above copyright notice(s) and this permission notice appear in associated - * documentation, and (c) there is clear notice in each modified Data File or - * in the Software as well as in the documentation associated with the Data - * File(s) or Software that the data or software has been modified. - * - * THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY - * KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF - * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS - * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT - * OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF - * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR - * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR - * PERFORMANCE OF THE DATA FILES OR SOFTWARE. - * - * Except as contained in this notice, the name of a copyright holder shall - * not be used in advertising or otherwise to promote the sale, use or other - * dealings in these Data Files or Software without prior written - * authorization of the copyright holder. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00 */ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10 */ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20 */ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30 */ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40 */ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50 */ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60 */ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70 */ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80 */ - 0x00c4, 0x00c5, 0x00c7, 0x00c9, - 0x00d1, 0x00d6, 0x00dc, 0x00e1, - 0x00e0, 0x00e2, 0x00e4, 0x00e3, - 0x00e5, 0x00e7, 0x00e9, 0x00e8, - /* 0x90 */ - 0x00ea, 0x00eb, 0x00ed, 0x00ec, - 0x00ee, 0x00ef, 0x00f1, 0x00f3, - 0x00f2, 0x00f4, 0x00f6, 0x00f5, - 0x00fa, 0x00f9, 0x00fb, 0x00fc, - /* 0xa0 */ - 0x2020, 0x00b0, 0x00a2, 0x00a3, - 0x00a7, 0x2022, 0x00b6, 0x00df, - 0x00ae, 0x00a9, 0x2122, 0x00b4, - 0x00a8, 0x2260, 0x00c6, 0x00d8, - /* 0xb0 */ - 0x221e, 0x00b1, 0x2264, 0x2265, - 0x00a5, 0x00b5, 0x2202, 0x2211, - 0x220f, 0x03c0, 0x222b, 0x00aa, - 0x00ba, 0x03a9, 0x00e6, 0x00f8, - /* 0xc0 */ - 0x00bf, 0x00a1, 0x00ac, 0x221a, - 0x0192, 0x2248, 0x2206, 0x00ab, - 0x00bb, 0x2026, 0x00a0, 0x00c0, - 0x00c3, 0x00d5, 0x0152, 0x0153, - /* 0xd0 */ - 0x2013, 0x2014, 0x201c, 0x201d, - 0x2018, 0x2019, 0x00f7, 0x25ca, - 0x00ff, 0x0178, 0x011e, 0x011f, - 0x0130, 0x0131, 0x015e, 0x015f, - /* 0xe0 */ - 0x2021, 0x00b7, 0x201a, 0x201e, - 0x2030, 0x00c2, 0x00ca, 0x00c1, - 0x00cb, 0x00c8, 0x00cd, 0x00ce, - 0x00cf, 0x00cc, 0x00d3, 0x00d4, - /* 0xf0 */ - 0xf8ff, 0x00d2, 0x00da, 0x00db, - 0x00d9, 0xf8a0, 0x02c6, 0x02dc, - 0x00af, 0x02d8, 0x02d9, 0x02da, - 0x00b8, 0x02dd, 0x02db, 0x02c7, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xca, 0xc1, 0xa2, 0xa3, 0x00, 0xb4, 0x00, 0xa4, /* 0xa0-0xa7 */ - 0xac, 0xa9, 0xbb, 0xc7, 0xc2, 0x00, 0xa8, 0xf8, /* 0xa8-0xaf */ - 0xa1, 0xb1, 0x00, 0x00, 0xab, 0xb5, 0xa6, 0xe1, /* 0xb0-0xb7 */ - 0xfc, 0x00, 0xbc, 0xc8, 0x00, 0x00, 0x00, 0xc0, /* 0xb8-0xbf */ - 0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xae, 0x82, /* 0xc0-0xc7 */ - 0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec, /* 0xc8-0xcf */ - 0x00, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0x00, /* 0xd0-0xd7 */ - 0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0x00, 0x00, 0xa7, /* 0xd8-0xdf */ - 0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xbe, 0x8d, /* 0xe0-0xe7 */ - 0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, /* 0xe8-0xef */ - 0x00, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6, /* 0xf0-0xf7 */ - 0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0x00, 0x00, 0xd8, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0xdb, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0xdc, 0xdd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0xce, 0xcf, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xdf, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0xd9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page02[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xff, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0xf9, 0xfa, 0xfb, 0xfe, 0xf7, 0xfd, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page03[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0xb9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0xd0, 0xd1, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd4, 0xd5, 0xe2, 0x00, 0xd2, 0xd3, 0xe3, 0x00, /* 0x18-0x1f */ - 0xa0, 0xe0, 0xa5, 0x00, 0x00, 0x00, 0xc9, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page21[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, 0xc6, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, /* 0x08-0x0f */ - 0x00, 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, 0xb0, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0xba, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0xc5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xad, 0x00, 0x00, 0x00, 0xb2, 0xb3, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page25[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char pagef8[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, /* 0xf8-0xff */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, page02, page03, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, page21, page22, NULL, NULL, page25, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - pagef8, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x00-0x07 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x08-0x0f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x10-0x17 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x18-0x1f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x20-0x27 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x28-0x2f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30-0x37 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x38-0x3f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x40-0x47 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x48-0x4f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x50-0x57 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x58-0x5f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60-0x67 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x68-0x6f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70-0x77 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x78-0x7f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x80-0x87 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x88-0x8f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90-0x97 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x98-0x9f */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa0-0xa7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xa8-0xaf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0-0xb7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb8-0xbf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc0-0xc7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xc8-0xcf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0-0xd7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd8-0xdf */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe0-0xe7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xe8-0xef */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf0-0xf7 */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "macturkish", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_macturkish(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_macturkish(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_macturkish) -module_exit(exit_nls_macturkish) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_ascii.c b/src/linux/fs/nls/nls_ascii.c deleted file mode 100644 index a262065..0000000 --- a/src/linux/fs/nls/nls_ascii.c +++ /dev/null @@ -1,166 +0,0 @@ -/* - * linux/fs/nls/nls_ascii.c - * - * Charset ascii translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "ascii", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_ascii(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_ascii(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_ascii) -module_exit(exit_nls_ascii) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_base.c b/src/linux/fs/nls/nls_base.c deleted file mode 100644 index 52ccd34..0000000 --- a/src/linux/fs/nls/nls_base.c +++ /dev/null @@ -1,548 +0,0 @@ -/* - * linux/fs/nls/nls_base.c - * - * Native language support--charsets and unicode translations. - * By Gordon Chaffee 1996, 1997 - * - * Unicode based case conversion 1999 by Wolfram Pienkoss - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static struct nls_table default_table; -static struct nls_table *tables = &default_table; -static DEFINE_SPINLOCK(nls_lock); - -/* - * Sample implementation from Unicode home page. - * http://www.stonehand.com/unicode/standard/fss-utf.html - */ -struct utf8_table { - int cmask; - int cval; - int shift; - long lmask; - long lval; -}; - -static const struct utf8_table utf8_table[] = -{ - {0x80, 0x00, 0*6, 0x7F, 0, /* 1 byte sequence */}, - {0xE0, 0xC0, 1*6, 0x7FF, 0x80, /* 2 byte sequence */}, - {0xF0, 0xE0, 2*6, 0xFFFF, 0x800, /* 3 byte sequence */}, - {0xF8, 0xF0, 3*6, 0x1FFFFF, 0x10000, /* 4 byte sequence */}, - {0xFC, 0xF8, 4*6, 0x3FFFFFF, 0x200000, /* 5 byte sequence */}, - {0xFE, 0xFC, 5*6, 0x7FFFFFFF, 0x4000000, /* 6 byte sequence */}, - {0, /* end of table */} -}; - -#define UNICODE_MAX 0x0010ffff -#define PLANE_SIZE 0x00010000 - -#define SURROGATE_MASK 0xfffff800 -#define SURROGATE_PAIR 0x0000d800 -#define SURROGATE_LOW 0x00000400 -#define SURROGATE_BITS 0x000003ff - -int utf8_to_utf32(const u8 *s, int inlen, unicode_t *pu) -{ - unsigned long l; - int c0, c, nc; - const struct utf8_table *t; - - nc = 0; - c0 = *s; - l = c0; - for (t = utf8_table; t->cmask; t++) { - nc++; - if ((c0 & t->cmask) == t->cval) { - l &= t->lmask; - if (l < t->lval || l > UNICODE_MAX || - (l & SURROGATE_MASK) == SURROGATE_PAIR) - return -1; - *pu = (unicode_t) l; - return nc; - } - if (inlen <= nc) - return -1; - s++; - c = (*s ^ 0x80) & 0xFF; - if (c & 0xC0) - return -1; - l = (l << 6) | c; - } - return -1; -} -EXPORT_SYMBOL(utf8_to_utf32); - -int utf32_to_utf8(unicode_t u, u8 *s, int maxout) -{ - unsigned long l; - int c, nc; - const struct utf8_table *t; - - if (!s) - return 0; - - l = u; - if (l > UNICODE_MAX || (l & SURROGATE_MASK) == SURROGATE_PAIR) - return -1; - - nc = 0; - for (t = utf8_table; t->cmask && maxout; t++, maxout--) { - nc++; - if (l <= t->lmask) { - c = t->shift; - *s = (u8) (t->cval | (l >> c)); - while (c > 0) { - c -= 6; - s++; - *s = (u8) (0x80 | ((l >> c) & 0x3F)); - } - return nc; - } - } - return -1; -} -EXPORT_SYMBOL(utf32_to_utf8); - -static inline void put_utf16(wchar_t *s, unsigned c, enum utf16_endian endian) -{ - switch (endian) { - default: - *s = (wchar_t) c; - break; - case UTF16_LITTLE_ENDIAN: - *s = __cpu_to_le16(c); - break; - case UTF16_BIG_ENDIAN: - *s = __cpu_to_be16(c); - break; - } -} - -int utf8s_to_utf16s(const u8 *s, int inlen, enum utf16_endian endian, - wchar_t *pwcs, int maxout) -{ - u16 *op; - int size; - unicode_t u; - - op = pwcs; - while (inlen > 0 && maxout > 0 && *s) { - if (*s & 0x80) { - size = utf8_to_utf32(s, inlen, &u); - if (size < 0) - return -EINVAL; - s += size; - inlen -= size; - - if (u >= PLANE_SIZE) { - if (maxout < 2) - break; - u -= PLANE_SIZE; - put_utf16(op++, SURROGATE_PAIR | - ((u >> 10) & SURROGATE_BITS), - endian); - put_utf16(op++, SURROGATE_PAIR | - SURROGATE_LOW | - (u & SURROGATE_BITS), - endian); - maxout -= 2; - } else { - put_utf16(op++, u, endian); - maxout--; - } - } else { - put_utf16(op++, *s++, endian); - inlen--; - maxout--; - } - } - return op - pwcs; -} -EXPORT_SYMBOL(utf8s_to_utf16s); - -static inline unsigned long get_utf16(unsigned c, enum utf16_endian endian) -{ - switch (endian) { - default: - return c; - case UTF16_LITTLE_ENDIAN: - return __le16_to_cpu(c); - case UTF16_BIG_ENDIAN: - return __be16_to_cpu(c); - } -} - -int utf16s_to_utf8s(const wchar_t *pwcs, int inlen, enum utf16_endian endian, - u8 *s, int maxout) -{ - u8 *op; - int size; - unsigned long u, v; - - op = s; - while (inlen > 0 && maxout > 0) { - u = get_utf16(*pwcs, endian); - if (!u) - break; - pwcs++; - inlen--; - if (u > 0x7f) { - if ((u & SURROGATE_MASK) == SURROGATE_PAIR) { - if (u & SURROGATE_LOW) { - /* Ignore character and move on */ - continue; - } - if (inlen <= 0) - break; - v = get_utf16(*pwcs, endian); - if ((v & SURROGATE_MASK) != SURROGATE_PAIR || - !(v & SURROGATE_LOW)) { - /* Ignore character and move on */ - continue; - } - u = PLANE_SIZE + ((u & SURROGATE_BITS) << 10) - + (v & SURROGATE_BITS); - pwcs++; - inlen--; - } - size = utf32_to_utf8(u, op, maxout); - if (size == -1) { - /* Ignore character and move on */ - } else { - op += size; - maxout -= size; - } - } else { - *op++ = (u8) u; - maxout--; - } - } - return op - s; -} -EXPORT_SYMBOL(utf16s_to_utf8s); - -int __register_nls(struct nls_table *nls, struct module *owner) -{ - struct nls_table ** tmp = &tables; - - if (nls->next) - return -EBUSY; - - nls->owner = owner; - spin_lock(&nls_lock); - while (*tmp) { - if (nls == *tmp) { - spin_unlock(&nls_lock); - return -EBUSY; - } - tmp = &(*tmp)->next; - } - nls->next = tables; - tables = nls; - spin_unlock(&nls_lock); - return 0; -} -EXPORT_SYMBOL(__register_nls); - -int unregister_nls(struct nls_table * nls) -{ - struct nls_table ** tmp = &tables; - - spin_lock(&nls_lock); - while (*tmp) { - if (nls == *tmp) { - *tmp = nls->next; - spin_unlock(&nls_lock); - return 0; - } - tmp = &(*tmp)->next; - } - spin_unlock(&nls_lock); - return -EINVAL; -} - -static struct nls_table *find_nls(char *charset) -{ - struct nls_table *nls; - spin_lock(&nls_lock); - for (nls = tables; nls; nls = nls->next) { - if (!strcmp(nls->charset, charset)) - break; - if (nls->alias && !strcmp(nls->alias, charset)) - break; - } - if (nls && !try_module_get(nls->owner)) - nls = NULL; - spin_unlock(&nls_lock); - return nls; -} - -struct nls_table *load_nls(char *charset) -{ - return try_then_request_module(find_nls(charset), "nls_%s", charset); -} - -void unload_nls(struct nls_table *nls) -{ - if (nls) - module_put(nls->owner); -} - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0080, 0x0081, 0x0082, 0x0083, - 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008a, 0x008b, - 0x008c, 0x008d, 0x008e, 0x008f, - /* 0x90*/ - 0x0090, 0x0091, 0x0092, 0x0093, - 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009a, 0x009b, - 0x009c, 0x009d, 0x009e, 0x009f, - /* 0xa0*/ - 0x00a0, 0x00a1, 0x00a2, 0x00a3, - 0x00a4, 0x00a5, 0x00a6, 0x00a7, - 0x00a8, 0x00a9, 0x00aa, 0x00ab, - 0x00ac, 0x00ad, 0x00ae, 0x00af, - /* 0xb0*/ - 0x00b0, 0x00b1, 0x00b2, 0x00b3, - 0x00b4, 0x00b5, 0x00b6, 0x00b7, - 0x00b8, 0x00b9, 0x00ba, 0x00bb, - 0x00bc, 0x00bd, 0x00be, 0x00bf, - /* 0xc0*/ - 0x00c0, 0x00c1, 0x00c2, 0x00c3, - 0x00c4, 0x00c5, 0x00c6, 0x00c7, - 0x00c8, 0x00c9, 0x00ca, 0x00cb, - 0x00cc, 0x00cd, 0x00ce, 0x00cf, - /* 0xd0*/ - 0x00d0, 0x00d1, 0x00d2, 0x00d3, - 0x00d4, 0x00d5, 0x00d6, 0x00d7, - 0x00d8, 0x00d9, 0x00da, 0x00db, - 0x00dc, 0x00dd, 0x00de, 0x00df, - /* 0xe0*/ - 0x00e0, 0x00e1, 0x00e2, 0x00e3, - 0x00e4, 0x00e5, 0x00e6, 0x00e7, - 0x00e8, 0x00e9, 0x00ea, 0x00eb, - 0x00ec, 0x00ed, 0x00ee, 0x00ef, - /* 0xf0*/ - 0x00f0, 0x00f1, 0x00f2, 0x00f3, - 0x00f4, 0x00f5, 0x00f6, 0x00f7, - 0x00f8, 0x00f9, 0x00fa, 0x00fb, - 0x00fc, 0x00fd, 0x00fe, 0x00ff, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00 -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table default_table = { - .charset = "default", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -/* Returns a simple default translation table */ -struct nls_table *load_nls_default(void) -{ - struct nls_table *default_nls; - - default_nls = load_nls(CONFIG_NLS_DEFAULT); - if (default_nls != NULL) - return default_nls; - else - return &default_table; -} - -EXPORT_SYMBOL(unregister_nls); -EXPORT_SYMBOL(unload_nls); -EXPORT_SYMBOL(load_nls); -EXPORT_SYMBOL(load_nls_default); - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_cp1250.c b/src/linux/fs/nls/nls_cp1250.c deleted file mode 100644 index ace3e19..0000000 --- a/src/linux/fs/nls/nls_cp1250.c +++ /dev/null @@ -1,346 +0,0 @@ -/* - * linux/fs/nls/nls_cp1250.c - * - * Charset cp1250 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x20ac, 0x0000, 0x201a, 0x0000, - 0x201e, 0x2026, 0x2020, 0x2021, - 0x0000, 0x2030, 0x0160, 0x2039, - 0x015a, 0x0164, 0x017d, 0x0179, - /* 0x90*/ - 0x0000, 0x2018, 0x2019, 0x201c, - 0x201d, 0x2022, 0x2013, 0x2014, - 0x0000, 0x2122, 0x0161, 0x203a, - 0x015b, 0x0165, 0x017e, 0x017a, - /* 0xa0*/ - 0x00a0, 0x02c7, 0x02d8, 0x0141, - 0x00a4, 0x0104, 0x00a6, 0x00a7, - 0x00a8, 0x00a9, 0x015e, 0x00ab, - 0x00ac, 0x00ad, 0x00ae, 0x017b, - /* 0xb0*/ - 0x00b0, 0x00b1, 0x02db, 0x0142, - 0x00b4, 0x00b5, 0x00b6, 0x00b7, - 0x00b8, 0x0105, 0x015f, 0x00bb, - 0x013d, 0x02dd, 0x013e, 0x017c, - /* 0xc0*/ - 0x0154, 0x00c1, 0x00c2, 0x0102, - 0x00c4, 0x0139, 0x0106, 0x00c7, - 0x010c, 0x00c9, 0x0118, 0x00cb, - 0x011a, 0x00cd, 0x00ce, 0x010e, - /* 0xd0*/ - 0x0110, 0x0143, 0x0147, 0x00d3, - 0x00d4, 0x0150, 0x00d6, 0x00d7, - 0x0158, 0x016e, 0x00da, 0x0170, - 0x00dc, 0x00dd, 0x0162, 0x00df, - /* 0xe0*/ - 0x0155, 0x00e1, 0x00e2, 0x0103, - 0x00e4, 0x013a, 0x0107, 0x00e7, - 0x010d, 0x00e9, 0x0119, 0x00eb, - 0x011b, 0x00ed, 0x00ee, 0x010f, - /* 0xf0*/ - 0x0111, 0x0144, 0x0148, 0x00f3, - 0x00f4, 0x0151, 0x00f6, 0x00f7, - 0x0159, 0x016f, 0x00fa, 0x0171, - 0x00fc, 0x00fd, 0x0163, 0x02d9, - }; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0x00, 0x00, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0xc1, 0xc2, 0x00, 0xc4, 0x00, 0x00, 0xc7, /* 0xc0-0xc7 */ - 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcd, 0xce, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0xd3, 0xd4, 0x00, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0x00, 0x00, 0xda, 0x00, 0xdc, 0xdd, 0x00, 0xdf, /* 0xd8-0xdf */ - 0x00, 0xe1, 0xe2, 0x00, 0xe4, 0x00, 0x00, 0xe7, /* 0xe0-0xe7 */ - 0x00, 0xe9, 0x00, 0xeb, 0x00, 0xed, 0xee, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0xf3, 0xf4, 0x00, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0x00, 0x00, 0xfa, 0x00, 0xfc, 0xfd, 0x00, 0x00, /* 0xf8-0xff */ - }; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0xc3, 0xe3, 0xa5, 0xb9, 0xc6, 0xe6, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0xcf, 0xef, /* 0x08-0x0f */ - 0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xca, 0xea, 0xcc, 0xec, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0xc5, 0xe5, 0x00, 0x00, 0xbc, 0xbe, 0x00, /* 0x38-0x3f */ - 0x00, 0xa3, 0xb3, 0xd1, 0xf1, 0x00, 0x00, 0xd2, /* 0x40-0x47 */ - 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xd5, 0xf5, 0x00, 0x00, 0xc0, 0xe0, 0x00, 0x00, /* 0x50-0x57 */ - 0xd8, 0xf8, 0x8c, 0x9c, 0x00, 0x00, 0xaa, 0xba, /* 0x58-0x5f */ - 0x8a, 0x9a, 0xde, 0xfe, 0x8d, 0x9d, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0xf9, /* 0x68-0x6f */ - 0xdb, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x8f, 0x9f, 0xaf, 0xbf, 0x8e, 0x9e, 0x00, /* 0x78-0x7f */ - - }; - -static const unsigned char page02[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa1, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0xa2, 0xff, 0x00, 0xb2, 0x00, 0xbd, 0x00, 0x00, /* 0xd8-0xdf */ - }; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x91, 0x92, 0x82, 0x00, 0x93, 0x94, 0x84, 0x00, /* 0x18-0x1f */ - 0x86, 0x87, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x8b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - }; - -static const unsigned char page21[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - }; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, page02, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, page21, NULL, NULL, NULL, NULL, NULL, NULL, - }; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x00, 0x82, 0x00, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x00, 0x89, 0x9a, 0x8b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x88-0x8f */ - 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x00, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xb3, 0xa4, 0xb9, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xba, 0xab, 0xac, 0xad, 0xae, 0xbf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbe, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* 0xd0-0xd7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ - }; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x00, 0x82, 0x00, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x00, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x00, 0x99, 0x8a, 0x9b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xa3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xa5, 0xaa, 0xbb, 0xbc, 0xbd, 0xbc, 0xaf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, /* 0xd8-0xdf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xf7, /* 0xf0-0xf7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xff, /* 0xf8-0xff */ - }; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp1250", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp1250(void) -{ - return register_nls(&table); -} -static void __exit exit_nls_cp1250(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp1250) -module_exit(exit_nls_cp1250) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_cp1251.c b/src/linux/fs/nls/nls_cp1251.c deleted file mode 100644 index 9273ddf..0000000 --- a/src/linux/fs/nls/nls_cp1251.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * linux/fs/nls/nls_cp1251.c - * - * Charset cp1251 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0402, 0x0403, 0x201a, 0x0453, - 0x201e, 0x2026, 0x2020, 0x2021, - 0x20ac, 0x2030, 0x0409, 0x2039, - 0x040a, 0x040c, 0x040b, 0x040f, - /* 0x90*/ - 0x0452, 0x2018, 0x2019, 0x201c, - 0x201d, 0x2022, 0x2013, 0x2014, - 0x0000, 0x2122, 0x0459, 0x203a, - 0x045a, 0x045c, 0x045b, 0x045f, - /* 0xa0*/ - 0x00a0, 0x040e, 0x045e, 0x0408, - 0x00a4, 0x0490, 0x00a6, 0x00a7, - 0x0401, 0x00a9, 0x0404, 0x00ab, - 0x00ac, 0x00ad, 0x00ae, 0x0407, - /* 0xb0*/ - 0x00b0, 0x00b1, 0x0406, 0x0456, - 0x0491, 0x00b5, 0x00b6, 0x00b7, - 0x0451, 0x2116, 0x0454, 0x00bb, - 0x0458, 0x0405, 0x0455, 0x0457, - /* 0xc0*/ - 0x0410, 0x0411, 0x0412, 0x0413, - 0x0414, 0x0415, 0x0416, 0x0417, - 0x0418, 0x0419, 0x041a, 0x041b, - 0x041c, 0x041d, 0x041e, 0x041f, - /* 0xd0*/ - 0x0420, 0x0421, 0x0422, 0x0423, - 0x0424, 0x0425, 0x0426, 0x0427, - 0x0428, 0x0429, 0x042a, 0x042b, - 0x042c, 0x042d, 0x042e, 0x042f, - /* 0xe0*/ - 0x0430, 0x0431, 0x0432, 0x0433, - 0x0434, 0x0435, 0x0436, 0x0437, - 0x0438, 0x0439, 0x043a, 0x043b, - 0x043c, 0x043d, 0x043e, 0x043f, - /* 0xf0*/ - 0x0440, 0x0441, 0x0442, 0x0443, - 0x0444, 0x0445, 0x0446, 0x0447, - 0x0448, 0x0449, 0x044a, 0x044b, - 0x044c, 0x044d, 0x044e, 0x044f, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0x00, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0x00, 0x00, 0x00, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page04[256] = { - 0x00, 0xa8, 0x80, 0x81, 0xaa, 0xbd, 0xb2, 0xaf, /* 0x00-0x07 */ - 0xa3, 0x8a, 0x8c, 0x8e, 0x8d, 0x00, 0xa1, 0x8f, /* 0x08-0x0f */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x10-0x17 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0x18-0x1f */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0x20-0x27 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0x28-0x2f */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x30-0x37 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x38-0x3f */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0x40-0x47 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0x48-0x4f */ - 0x00, 0xb8, 0x90, 0x83, 0xba, 0xbe, 0xb3, 0xbf, /* 0x50-0x57 */ - 0xbc, 0x9a, 0x9c, 0x9e, 0x9d, 0x00, 0xa2, 0x9f, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0xa5, 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x91, 0x92, 0x82, 0x00, 0x93, 0x94, 0x84, 0x00, /* 0x18-0x1f */ - 0x86, 0x87, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x8b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ -}; - -static const unsigned char page21[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, NULL, NULL, NULL, page04, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, page21, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - 0x90, 0x83, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x9a, 0x8b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa2, 0xa2, 0xbc, 0xa4, 0xb4, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xb8, 0xa9, 0xba, 0xab, 0xac, 0xad, 0xae, 0xbf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb3, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbe, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xd0-0xd7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - 0x80, 0x81, 0x82, 0x81, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x80, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x8a, 0x9b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa1, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb2, 0xa5, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xa8, 0xb9, 0xaa, 0xbb, 0xa3, 0xbd, 0xbd, 0xaf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xf0-0xf7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp1251", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp1251(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp1251(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp1251) -module_exit(exit_nls_cp1251) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_cp1255.c b/src/linux/fs/nls/nls_cp1255.c deleted file mode 100644 index 1caf5df..0000000 --- a/src/linux/fs/nls/nls_cp1255.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * linux/fs/nls/nls_cp1255.c - * - * Charset cp1255 translation tables. - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x20ac, 0x0000, 0x201a, 0x0192, - 0x201e, 0x2026, 0x2020, 0x2021, - 0x02c6, 0x2030, 0x0000, 0x2039, - 0x0000, 0x0000, 0x0000, 0x0000, - /* 0x90*/ - 0x0000, 0x2018, 0x2019, 0x201c, - 0x201d, 0x2022, 0x2013, 0x2014, - 0x02dc, 0x2122, 0x0000, 0x203a, - 0x0000, 0x0000, 0x0000, 0x0000, - /* 0xa0*/ - 0x00a0, 0x00a1, 0x00a2, 0x00a3, - 0x20aa, 0x00a5, 0x00a6, 0x00a7, - 0x00a8, 0x00a9, 0x00d7, 0x00ab, - 0x00ac, 0x00ad, 0x00ae, 0x203e, - /* 0xb0*/ - 0x00b0, 0x00b1, 0x00b2, 0x00b3, - 0x00b4, 0x00b5, 0x00b6, 0x00b7, - 0x00b8, 0x00b9, 0x00f7, 0x00bb, - 0x00bc, 0x00bd, 0x00be, 0x00bf, - /* 0xc0*/ - 0x05b0, 0x05b1, 0x05b2, 0x05b3, - 0x05b4, 0x05b5, 0x05b6, 0x05b7, - 0x05b8, 0x05b9, 0x0000, 0x05bb, - 0x05bc, 0x05bd, 0x05be, 0x05bf, - /* 0xd0*/ - 0x05c0, 0x05c1, 0x05c2, 0x05c3, - 0x05f0, 0x05f1, 0x05f2, 0x05f3, - 0x05f4, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x2017, - /* 0xe0*/ - 0x05d0, 0x05d1, 0x05d2, 0x05d3, - 0x05d4, 0x05d5, 0x05d6, 0x05d7, - 0x05d8, 0x05d9, 0x05da, 0x05db, - 0x05dc, 0x05dd, 0x05de, 0x05df, - /* 0xf0*/ - 0x05e0, 0x05e1, 0x05e2, 0x05e3, - 0x05e4, 0x05e5, 0x05e6, 0x05e7, - 0x05e8, 0x05e9, 0x05ea, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xa0, 0x00, 0xa2, 0xa3, 0x00, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0x00, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xba, /* 0xf0-0xf7 */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ -}; - -static const unsigned char page02[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ -}; - -static const unsigned char page05[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xb0-0xb7 */ - 0xc8, 0xc9, 0x00, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xb8-0xbf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xd0-0xd7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xd8-0xdf */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xe0-0xe7 */ - 0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0xfe, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x91, 0x92, 0x82, 0x00, 0x93, 0x94, 0x84, 0x00, /* 0x18-0x1f */ - 0x86, 0x87, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x8b, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0xa4, 0x00, 0x80, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ -}; - -static const unsigned char page21[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, page02, NULL, NULL, page05, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, page21, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0x00, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp1255", - .alias = "iso8859-8", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp1255(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp1255(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp1255) -module_exit(exit_nls_cp1255) - -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_ALIAS_NLS(iso8859-8); diff --git a/src/linux/fs/nls/nls_cp437.c b/src/linux/fs/nls/nls_cp437.c deleted file mode 100644 index 7ddb830..0000000 --- a/src/linux/fs/nls/nls_cp437.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - * linux/fs/nls/nls_cp437.c - * - * Charset cp437 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x00c7, 0x00fc, 0x00e9, 0x00e2, - 0x00e4, 0x00e0, 0x00e5, 0x00e7, - 0x00ea, 0x00eb, 0x00e8, 0x00ef, - 0x00ee, 0x00ec, 0x00c4, 0x00c5, - /* 0x90*/ - 0x00c9, 0x00e6, 0x00c6, 0x00f4, - 0x00f6, 0x00f2, 0x00fb, 0x00f9, - 0x00ff, 0x00d6, 0x00dc, 0x00a2, - 0x00a3, 0x00a5, 0x20a7, 0x0192, - /* 0xa0*/ - 0x00e1, 0x00ed, 0x00f3, 0x00fa, - 0x00f1, 0x00d1, 0x00aa, 0x00ba, - 0x00bf, 0x2310, 0x00ac, 0x00bd, - 0x00bc, 0x00a1, 0x00ab, 0x00bb, - /* 0xb0*/ - 0x2591, 0x2592, 0x2593, 0x2502, - 0x2524, 0x2561, 0x2562, 0x2556, - 0x2555, 0x2563, 0x2551, 0x2557, - 0x255d, 0x255c, 0x255b, 0x2510, - /* 0xc0*/ - 0x2514, 0x2534, 0x252c, 0x251c, - 0x2500, 0x253c, 0x255e, 0x255f, - 0x255a, 0x2554, 0x2569, 0x2566, - 0x2560, 0x2550, 0x256c, 0x2567, - /* 0xd0*/ - 0x2568, 0x2564, 0x2565, 0x2559, - 0x2558, 0x2552, 0x2553, 0x256b, - 0x256a, 0x2518, 0x250c, 0x2588, - 0x2584, 0x258c, 0x2590, 0x2580, - /* 0xe0*/ - 0x03b1, 0x00df, 0x0393, 0x03c0, - 0x03a3, 0x03c3, 0x00b5, 0x03c4, - 0x03a6, 0x0398, 0x03a9, 0x03b4, - 0x221e, 0x03c6, 0x03b5, 0x2229, - /* 0xf0*/ - 0x2261, 0x00b1, 0x2265, 0x2264, - 0x2320, 0x2321, 0x00f7, 0x2248, - 0x00b0, 0x2219, 0x00b7, 0x221a, - 0x207f, 0x00b2, 0x25a0, 0x00a0, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xff, 0xad, 0x9b, 0x9c, 0x00, 0x9d, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */ - 0x00, 0x00, 0xa7, 0xaf, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */ - 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */ - 0x85, 0xa0, 0x83, 0x00, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */ - 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, /* 0xe8-0xef */ - 0x00, 0xa4, 0x95, 0xa2, 0x93, 0x00, 0x94, 0xf6, /* 0xf0-0xf7 */ - 0x00, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0x98, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ -}; - -static const unsigned char page03[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */ - 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */ -}; - -static const unsigned char page23[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ -}; - -static const unsigned char page25[256] = { - 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */ - 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */ - 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */ - 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, NULL, page03, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, NULL, page22, page23, NULL, page25, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x87, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x84, 0x86, /* 0x88-0x8f */ - 0x82, 0x91, 0x91, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x94, 0x81, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0x00, 0xe3, 0xe5, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xed, 0x00, 0x00, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x9a, 0x90, 0x00, 0x8e, 0x00, 0x8f, 0x80, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x92, 0x92, 0x00, 0x99, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0x00, 0xe1, 0xe2, 0x00, 0xe4, 0xe4, 0x00, 0x00, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0x00, 0xec, 0xe8, 0x00, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp437", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp437(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp437(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp437) -module_exit(exit_nls_cp437) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_cp737.c b/src/linux/fs/nls/nls_cp737.c deleted file mode 100644 index c593f68..0000000 --- a/src/linux/fs/nls/nls_cp737.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * linux/fs/nls/nls_cp737.c - * - * Charset cp737 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0391, 0x0392, 0x0393, 0x0394, - 0x0395, 0x0396, 0x0397, 0x0398, - 0x0399, 0x039a, 0x039b, 0x039c, - 0x039d, 0x039e, 0x039f, 0x03a0, - /* 0x90*/ - 0x03a1, 0x03a3, 0x03a4, 0x03a5, - 0x03a6, 0x03a7, 0x03a8, 0x03a9, - 0x03b1, 0x03b2, 0x03b3, 0x03b4, - 0x03b5, 0x03b6, 0x03b7, 0x03b8, - /* 0xa0*/ - 0x03b9, 0x03ba, 0x03bb, 0x03bc, - 0x03bd, 0x03be, 0x03bf, 0x03c0, - 0x03c1, 0x03c3, 0x03c2, 0x03c4, - 0x03c5, 0x03c6, 0x03c7, 0x03c8, - /* 0xb0*/ - 0x2591, 0x2592, 0x2593, 0x2502, - 0x2524, 0x2561, 0x2562, 0x2556, - 0x2555, 0x2563, 0x2551, 0x2557, - 0x255d, 0x255c, 0x255b, 0x2510, - /* 0xc0*/ - 0x2514, 0x2534, 0x252c, 0x251c, - 0x2500, 0x253c, 0x255e, 0x255f, - 0x255a, 0x2554, 0x2569, 0x2566, - 0x2560, 0x2550, 0x256c, 0x2567, - /* 0xd0*/ - 0x2568, 0x2564, 0x2565, 0x2559, - 0x2558, 0x2552, 0x2553, 0x256b, - 0x256a, 0x2518, 0x250c, 0x2588, - 0x2584, 0x258c, 0x2590, 0x2580, - /* 0xe0*/ - 0x03c9, 0x03ac, 0x03ad, 0x03ae, - 0x03ca, 0x03af, 0x03cc, 0x03cd, - 0x03cb, 0x03ce, 0x0386, 0x0388, - 0x0389, 0x038a, 0x038c, 0x038e, - /* 0xf0*/ - 0x038f, 0x00b1, 0x2265, 0x2264, - 0x03aa, 0x03ab, 0x00f7, 0x2248, - 0x00b0, 0x2219, 0x00b7, 0x221a, - 0x207f, 0x00b2, 0x25a0, 0x00a0, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0xf8, 0xf1, 0xfd, 0x00, 0x00, 0x00, 0x00, 0xfa, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, /* 0xf0-0xf7 */ -}; - -static const unsigned char page03[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xea, 0x00, /* 0x80-0x87 */ - 0xeb, 0xec, 0xed, 0x00, 0xee, 0x00, 0xef, 0xf0, /* 0x88-0x8f */ - 0x00, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, /* 0x90-0x97 */ - 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, /* 0x98-0x9f */ - 0x8f, 0x90, 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, /* 0xa0-0xa7 */ - 0x96, 0x97, 0xf4, 0xf5, 0xe1, 0xe2, 0xe3, 0xe5, /* 0xa8-0xaf */ - 0x00, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, /* 0xb0-0xb7 */ - 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, /* 0xb8-0xbf */ - 0xa7, 0xa8, 0xaa, 0xa9, 0xab, 0xac, 0xad, 0xae, /* 0xc0-0xc7 */ - 0xaf, 0xe0, 0xe4, 0xe8, 0xe6, 0xe7, 0xe9, 0x00, /* 0xc8-0xcf */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */ -}; - -static const unsigned char page25[256] = { - 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */ - 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */ - 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */ - 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, NULL, NULL, page03, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, NULL, page22, NULL, NULL, page25, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x80-0x87 */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0x88-0x8f */ - 0xa8, 0xa9, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xe0, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xe1, 0xe2, 0xe3, 0xe5, 0xe6, 0xe7, /* 0xe8-0xef */ - 0xe9, 0xf1, 0xf2, 0xf3, 0xe4, 0xe8, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x98-0x9f */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0xa0-0xa7 */ - 0x90, 0x91, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0x97, 0xea, 0xeb, 0xec, 0xf4, 0xed, 0xee, 0xef, /* 0xe0-0xe7 */ - 0xf5, 0xf0, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp737", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp737(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp737(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp737) -module_exit(exit_nls_cp737) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_cp775.c b/src/linux/fs/nls/nls_cp775.c deleted file mode 100644 index 554c863..0000000 --- a/src/linux/fs/nls/nls_cp775.c +++ /dev/null @@ -1,319 +0,0 @@ -/* - * linux/fs/nls/nls_cp775.c - * - * Charset cp775 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0106, 0x00fc, 0x00e9, 0x0101, - 0x00e4, 0x0123, 0x00e5, 0x0107, - 0x0142, 0x0113, 0x0156, 0x0157, - 0x012b, 0x0179, 0x00c4, 0x00c5, - /* 0x90*/ - 0x00c9, 0x00e6, 0x00c6, 0x014d, - 0x00f6, 0x0122, 0x00a2, 0x015a, - 0x015b, 0x00d6, 0x00dc, 0x00f8, - 0x00a3, 0x00d8, 0x00d7, 0x00a4, - /* 0xa0*/ - 0x0100, 0x012a, 0x00f3, 0x017b, - 0x017c, 0x017a, 0x201d, 0x00a6, - 0x00a9, 0x00ae, 0x00ac, 0x00bd, - 0x00bc, 0x0141, 0x00ab, 0x00bb, - /* 0xb0*/ - 0x2591, 0x2592, 0x2593, 0x2502, - 0x2524, 0x0104, 0x010c, 0x0118, - 0x0116, 0x2563, 0x2551, 0x2557, - 0x255d, 0x012e, 0x0160, 0x2510, - /* 0xc0*/ - 0x2514, 0x2534, 0x252c, 0x251c, - 0x2500, 0x253c, 0x0172, 0x016a, - 0x255a, 0x2554, 0x2569, 0x2566, - 0x2560, 0x2550, 0x256c, 0x017d, - /* 0xd0*/ - 0x0105, 0x010d, 0x0119, 0x0117, - 0x012f, 0x0161, 0x0173, 0x016b, - 0x017e, 0x2518, 0x250c, 0x2588, - 0x2584, 0x258c, 0x2590, 0x2580, - /* 0xe0*/ - 0x00d3, 0x00df, 0x014c, 0x0143, - 0x00f5, 0x00d5, 0x00b5, 0x0144, - 0x0136, 0x0137, 0x013b, 0x013c, - 0x0146, 0x0112, 0x0145, 0x2019, - /* 0xf0*/ - 0x00ad, 0x00b1, 0x201c, 0x00be, - 0x00b6, 0x00a7, 0x00f7, 0x201e, - 0x00b0, 0x2219, 0x00b7, 0x00b9, - 0x00b3, 0x00b2, 0x25a0, 0x00a0, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xff, 0x00, 0x96, 0x9c, 0x9f, 0x00, 0xa7, 0xf5, /* 0xa0-0xa7 */ - 0x00, 0xa8, 0x00, 0xae, 0xaa, 0xf0, 0xa9, 0x00, /* 0xa8-0xaf */ - 0xf8, 0xf1, 0xfd, 0xfc, 0x00, 0xe6, 0xf4, 0xfa, /* 0xb0-0xb7 */ - 0x00, 0xfb, 0x00, 0xaf, 0xac, 0xab, 0xf3, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0xe0, 0x00, 0xe5, 0x99, 0x9e, /* 0xd0-0xd7 */ - 0x9d, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x84, 0x86, 0x91, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0xa2, 0x00, 0xe4, 0x94, 0xf6, /* 0xf0-0xf7 */ - 0x9b, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0xa0, 0x83, 0x00, 0x00, 0xb5, 0xd0, 0x80, 0x87, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xb6, 0xd1, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0xed, 0x89, 0x00, 0x00, 0xb8, 0xd3, /* 0x10-0x17 */ - 0xb7, 0xd2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x95, 0x85, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0xa1, 0x8c, 0x00, 0x00, 0xbd, 0xd4, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0xe9, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0xea, 0xeb, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0xad, 0x88, 0xe3, 0xe7, 0xee, 0xec, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xe2, 0x93, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8a, 0x8b, /* 0x50-0x57 */ - 0x00, 0x00, 0x97, 0x98, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xbe, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0xc7, 0xd7, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0xc6, 0xd6, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x8d, 0xa5, 0xa3, 0xa4, 0xcf, 0xd8, 0x00, /* 0x78-0x7f */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0xef, 0x00, 0x00, 0xf2, 0xa6, 0xf7, 0x00, /* 0x18-0x1f */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ -}; - -static const unsigned char page25[256] = { - 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xcd, 0xba, 0x00, 0x00, 0xc9, 0x00, 0x00, 0xbb, /* 0x50-0x57 */ - 0x00, 0x00, 0xc8, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x58-0x5f */ - 0xcc, 0x00, 0x00, 0xb9, 0x00, 0x00, 0xcb, 0x00, /* 0x60-0x67 */ - 0x00, 0xca, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, NULL, page22, NULL, NULL, page25, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x87, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8b, 0x8b, 0x8c, 0xa5, 0x84, 0x86, /* 0x88-0x8f */ - 0x82, 0x91, 0x91, 0x93, 0x94, 0x85, 0x96, 0x98, /* 0x90-0x97 */ - 0x98, 0x94, 0x81, 0x9b, 0x9c, 0x9b, 0x9e, 0x9f, /* 0x98-0x9f */ - 0x83, 0x8c, 0xa2, 0xa4, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0x88, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xd0, 0xd1, 0xd2, /* 0xb0-0xb7 */ - 0xd3, 0xb9, 0xba, 0xbb, 0xbc, 0xd4, 0xd5, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xd6, 0xd7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xd8, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xa2, 0xe1, 0x93, 0xe7, 0xe4, 0xe4, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe9, 0xe9, 0xeb, 0xeb, 0xec, 0x89, 0xec, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x9a, 0x90, 0xa0, 0x8e, 0x95, 0x8f, 0x80, /* 0x80-0x87 */ - 0xad, 0xed, 0x8a, 0x8a, 0xa1, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x92, 0x92, 0xe2, 0x99, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x97, 0x99, 0x9a, 0x9d, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xe0, 0xa3, 0xa3, 0x8d, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xb5, 0xb6, 0xb7, 0xb8, 0xbd, 0xbe, 0xc6, 0xc7, /* 0xd0-0xd7 */ - 0xcf, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe5, 0xe5, 0x00, 0xe3, /* 0xe0-0xe7 */ - 0xe8, 0xe8, 0xea, 0xea, 0xee, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp775", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp775(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp775(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp775) -module_exit(exit_nls_cp775) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_cp850.c b/src/linux/fs/nls/nls_cp850.c deleted file mode 100644 index 56cccd1..0000000 --- a/src/linux/fs/nls/nls_cp850.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * linux/fs/nls/nls_cp850.c - * - * Charset cp850 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x00c7, 0x00fc, 0x00e9, 0x00e2, - 0x00e4, 0x00e0, 0x00e5, 0x00e7, - 0x00ea, 0x00eb, 0x00e8, 0x00ef, - 0x00ee, 0x00ec, 0x00c4, 0x00c5, - /* 0x90*/ - 0x00c9, 0x00e6, 0x00c6, 0x00f4, - 0x00f6, 0x00f2, 0x00fb, 0x00f9, - 0x00ff, 0x00d6, 0x00dc, 0x00f8, - 0x00a3, 0x00d8, 0x00d7, 0x0192, - /* 0xa0*/ - 0x00e1, 0x00ed, 0x00f3, 0x00fa, - 0x00f1, 0x00d1, 0x00aa, 0x00ba, - 0x00bf, 0x00ae, 0x00ac, 0x00bd, - 0x00bc, 0x00a1, 0x00ab, 0x00bb, - /* 0xb0*/ - 0x2591, 0x2592, 0x2593, 0x2502, - 0x2524, 0x00c1, 0x00c2, 0x00c0, - 0x00a9, 0x2563, 0x2551, 0x2557, - 0x255d, 0x00a2, 0x00a5, 0x2510, - /* 0xc0*/ - 0x2514, 0x2534, 0x252c, 0x251c, - 0x2500, 0x253c, 0x00e3, 0x00c3, - 0x255a, 0x2554, 0x2569, 0x2566, - 0x2560, 0x2550, 0x256c, 0x00a4, - /* 0xd0*/ - 0x00f0, 0x00d0, 0x00ca, 0x00cb, - 0x00c8, 0x0131, 0x00cd, 0x00ce, - 0x00cf, 0x2518, 0x250c, 0x2588, - 0x2584, 0x00a6, 0x00cc, 0x2580, - /* 0xe0*/ - 0x00d3, 0x00df, 0x00d4, 0x00d2, - 0x00f5, 0x00d5, 0x00b5, 0x00fe, - 0x00de, 0x00da, 0x00db, 0x00d9, - 0x00fd, 0x00dd, 0x00af, 0x00b4, - /* 0xf0*/ - 0x00ad, 0x00b1, 0x2017, 0x00be, - 0x00b6, 0x00a7, 0x00f7, 0x00b8, - 0x00b0, 0x00a8, 0x00b7, 0x00b9, - 0x00b3, 0x00b2, 0x25a0, 0x00a0, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xff, 0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5, /* 0xa0-0xa7 */ - 0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee, /* 0xa8-0xaf */ - 0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa, /* 0xb0-0xb7 */ - 0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8, /* 0xb8-0xbf */ - 0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */ - 0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* 0xc8-0xcf */ - 0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e, /* 0xd0-0xd7 */ - 0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1, /* 0xd8-0xdf */ - 0x85, 0xa0, 0x83, 0xc6, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */ - 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, /* 0xe8-0xef */ - 0xd0, 0xa4, 0x95, 0xa2, 0x93, 0xe4, 0x94, 0xf6, /* 0xf0-0xf7 */ - 0x9b, 0x97, 0xa3, 0x96, 0x81, 0xec, 0xe7, 0x98, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, /* 0x10-0x17 */ -}; - -static const unsigned char page25[256] = { - 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xcd, 0xba, 0x00, 0x00, 0xc9, 0x00, 0x00, 0xbb, /* 0x50-0x57 */ - 0x00, 0x00, 0xc8, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x58-0x5f */ - 0xcc, 0x00, 0x00, 0xb9, 0x00, 0x00, 0xcb, 0x00, /* 0x60-0x67 */ - 0x00, 0xca, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, NULL, NULL, NULL, NULL, page25, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x87, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x84, 0x86, /* 0x88-0x8f */ - 0x82, 0x91, 0x91, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x94, 0x81, 0x9b, 0x9c, 0x9b, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xa0, 0x83, 0x85, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc6, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd0, 0x88, 0x89, 0x8a, 0xd5, 0xa1, 0x8c, /* 0xd0-0xd7 */ - 0x8b, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0x8d, 0xdf, /* 0xd8-0xdf */ - 0xa2, 0xe1, 0x93, 0x95, 0xe4, 0xe4, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe7, 0xa3, 0x96, 0x97, 0xec, 0xec, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x9a, 0x90, 0xb6, 0x8e, 0xb7, 0x8f, 0x80, /* 0x80-0x87 */ - 0xd2, 0xd3, 0xd4, 0xd8, 0xd7, 0xde, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x92, 0x92, 0xe2, 0x99, 0xe3, 0xea, 0xeb, /* 0x90-0x97 */ - 0x00, 0x99, 0x9a, 0x9d, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */ - 0xb5, 0xd6, 0xe0, 0xe9, 0xa5, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc7, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd1, 0xd1, 0xd2, 0xd3, 0xd4, 0x49, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe5, 0xe5, 0x00, 0xe8, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xed, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp850", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp850(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp850(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp850) -module_exit(exit_nls_cp850) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_cp852.c b/src/linux/fs/nls/nls_cp852.c deleted file mode 100644 index 7cdc05a..0000000 --- a/src/linux/fs/nls/nls_cp852.c +++ /dev/null @@ -1,337 +0,0 @@ -/* - * linux/fs/nls/nls_cp852.c - * - * Charset cp852 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x00c7, 0x00fc, 0x00e9, 0x00e2, - 0x00e4, 0x016f, 0x0107, 0x00e7, - 0x0142, 0x00eb, 0x0150, 0x0151, - 0x00ee, 0x0179, 0x00c4, 0x0106, - /* 0x90*/ - 0x00c9, 0x0139, 0x013a, 0x00f4, - 0x00f6, 0x013d, 0x013e, 0x015a, - 0x015b, 0x00d6, 0x00dc, 0x0164, - 0x0165, 0x0141, 0x00d7, 0x010d, - /* 0xa0*/ - 0x00e1, 0x00ed, 0x00f3, 0x00fa, - 0x0104, 0x0105, 0x017d, 0x017e, - 0x0118, 0x0119, 0x00ac, 0x017a, - 0x010c, 0x015f, 0x00ab, 0x00bb, - /* 0xb0*/ - 0x2591, 0x2592, 0x2593, 0x2502, - 0x2524, 0x00c1, 0x00c2, 0x011a, - 0x015e, 0x2563, 0x2551, 0x2557, - 0x255d, 0x017b, 0x017c, 0x2510, - /* 0xc0*/ - 0x2514, 0x2534, 0x252c, 0x251c, - 0x2500, 0x253c, 0x0102, 0x0103, - 0x255a, 0x2554, 0x2569, 0x2566, - 0x2560, 0x2550, 0x256c, 0x00a4, - /* 0xd0*/ - 0x0111, 0x0110, 0x010e, 0x00cb, - 0x010f, 0x0147, 0x00cd, 0x00ce, - 0x011b, 0x2518, 0x250c, 0x2588, - 0x2584, 0x0162, 0x016e, 0x2580, - /* 0xe0*/ - 0x00d3, 0x00df, 0x00d4, 0x0143, - 0x0144, 0x0148, 0x0160, 0x0161, - 0x0154, 0x00da, 0x0155, 0x0170, - 0x00fd, 0x00dd, 0x0163, 0x00b4, - /* 0xf0*/ - 0x00ad, 0x02dd, 0x02db, 0x02c7, - 0x02d8, 0x00a7, 0x00f7, 0x00b8, - 0x00b0, 0x00a8, 0x02d9, 0x0171, - 0x0158, 0x0159, 0x25a0, 0x00a0, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xff, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0xf5, /* 0xa0-0xa7 */ - 0xf9, 0x00, 0x00, 0xae, 0xaa, 0xf0, 0x00, 0x00, /* 0xa8-0xaf */ - 0xf8, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0xf7, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0xb5, 0xb6, 0x00, 0x8e, 0x00, 0x00, 0x80, /* 0xc0-0xc7 */ - 0x00, 0x90, 0x00, 0xd3, 0x00, 0xd6, 0xd7, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0xe0, 0xe2, 0x00, 0x99, 0x9e, /* 0xd0-0xd7 */ - 0x00, 0x00, 0xe9, 0x00, 0x9a, 0xed, 0x00, 0xe1, /* 0xd8-0xdf */ - 0x00, 0xa0, 0x83, 0x00, 0x84, 0x00, 0x00, 0x87, /* 0xe0-0xe7 */ - 0x00, 0x82, 0x00, 0x89, 0x00, 0xa1, 0x8c, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0xa2, 0x93, 0x00, 0x94, 0xf6, /* 0xf0-0xf7 */ - 0x00, 0x00, 0xa3, 0x00, 0x81, 0xec, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0xc6, 0xc7, 0xa4, 0xa5, 0x8f, 0x86, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xac, 0x9f, 0xd2, 0xd4, /* 0x08-0x0f */ - 0xd1, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xa8, 0xa9, 0xb7, 0xd8, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x91, 0x92, 0x00, 0x00, 0x95, 0x96, 0x00, /* 0x38-0x3f */ - 0x00, 0x9d, 0x88, 0xe3, 0xe4, 0x00, 0x00, 0xd5, /* 0x40-0x47 */ - 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x8a, 0x8b, 0x00, 0x00, 0xe8, 0xea, 0x00, 0x00, /* 0x50-0x57 */ - 0xfc, 0xfd, 0x97, 0x98, 0x00, 0x00, 0xb8, 0xad, /* 0x58-0x5f */ - 0xe6, 0xe7, 0xdd, 0xee, 0x9b, 0x9c, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0x85, /* 0x68-0x6f */ - 0xeb, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x8d, 0xab, 0xbd, 0xbe, 0xa6, 0xa7, 0x00, /* 0x78-0x7f */ -}; - -static const unsigned char page02[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf3, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0xf4, 0xfa, 0x00, 0xf2, 0x00, 0xf1, 0x00, 0x00, /* 0xd8-0xdf */ -}; - -static const unsigned char page25[256] = { - 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xcd, 0xba, 0x00, 0x00, 0xc9, 0x00, 0x00, 0xbb, /* 0x50-0x57 */ - 0x00, 0x00, 0xc8, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x58-0x5f */ - 0xcc, 0x00, 0x00, 0xb9, 0x00, 0x00, 0xcb, 0x00, /* 0x60-0x67 */ - 0x00, 0xca, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, page02, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, page25, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x87, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8b, 0x8b, 0x8c, 0xab, 0x84, 0x86, /* 0x88-0x8f */ - 0x82, 0x92, 0x92, 0x93, 0x94, 0x96, 0x96, 0x98, /* 0x90-0x97 */ - 0x98, 0x94, 0x81, 0x9c, 0x9c, 0x88, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa5, 0xa5, 0xa7, 0xa7, /* 0xa0-0xa7 */ - 0xa9, 0xa9, 0xaa, 0xab, 0x9f, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xa0, 0x83, 0xd8, /* 0xb0-0xb7 */ - 0xad, 0xb9, 0xba, 0xbb, 0xbc, 0xbe, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc7, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd0, 0xd4, 0x89, 0xd4, 0xe5, 0xa1, 0x8c, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xee, 0x85, 0xdf, /* 0xd8-0xdf */ - 0xa2, 0xe1, 0x93, 0xe4, 0xe4, 0xe5, 0xe7, 0xe7, /* 0xe0-0xe7 */ - 0xea, 0xa3, 0xea, 0xfb, 0xec, 0xec, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfd, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x9a, 0x90, 0xb6, 0x8e, 0xde, 0x8f, 0x80, /* 0x80-0x87 */ - 0x9d, 0xd3, 0x8a, 0x8a, 0xd7, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x91, 0xe2, 0x99, 0x95, 0x95, 0x97, /* 0x90-0x97 */ - 0x97, 0x99, 0x9a, 0x9b, 0x9b, 0x9d, 0x9e, 0xac, /* 0x98-0x9f */ - 0xb5, 0xd6, 0xe0, 0xe9, 0xa4, 0xa4, 0xa6, 0xa6, /* 0xa0-0xa7 */ - 0xa8, 0xa8, 0xaa, 0x8d, 0xac, 0xb8, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbd, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc6, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd1, 0xd1, 0xd2, 0xd3, 0xd2, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xb7, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe3, 0xd5, 0xe6, 0xe6, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xe8, 0xeb, 0xed, 0xed, 0xdd, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xeb, 0xfc, 0xfc, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp852", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp852(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp852(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp852) -module_exit(exit_nls_cp852) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_cp855.c b/src/linux/fs/nls/nls_cp855.c deleted file mode 100644 index 7426eea..0000000 --- a/src/linux/fs/nls/nls_cp855.c +++ /dev/null @@ -1,299 +0,0 @@ -/* - * linux/fs/nls/nls_cp855.c - * - * Charset cp855 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0452, 0x0402, 0x0453, 0x0403, - 0x0451, 0x0401, 0x0454, 0x0404, - 0x0455, 0x0405, 0x0456, 0x0406, - 0x0457, 0x0407, 0x0458, 0x0408, - /* 0x90*/ - 0x0459, 0x0409, 0x045a, 0x040a, - 0x045b, 0x040b, 0x045c, 0x040c, - 0x045e, 0x040e, 0x045f, 0x040f, - 0x044e, 0x042e, 0x044a, 0x042a, - /* 0xa0*/ - 0x0430, 0x0410, 0x0431, 0x0411, - 0x0446, 0x0426, 0x0434, 0x0414, - 0x0435, 0x0415, 0x0444, 0x0424, - 0x0433, 0x0413, 0x00ab, 0x00bb, - /* 0xb0*/ - 0x2591, 0x2592, 0x2593, 0x2502, - 0x2524, 0x0445, 0x0425, 0x0438, - 0x0418, 0x2563, 0x2551, 0x2557, - 0x255d, 0x0439, 0x0419, 0x2510, - /* 0xc0*/ - 0x2514, 0x2534, 0x252c, 0x251c, - 0x2500, 0x253c, 0x043a, 0x041a, - 0x255a, 0x2554, 0x2569, 0x2566, - 0x2560, 0x2550, 0x256c, 0x00a4, - /* 0xd0*/ - 0x043b, 0x041b, 0x043c, 0x041c, - 0x043d, 0x041d, 0x043e, 0x041e, - 0x043f, 0x2518, 0x250c, 0x2588, - 0x2584, 0x041f, 0x044f, 0x2580, - /* 0xe0*/ - 0x042f, 0x0440, 0x0420, 0x0441, - 0x0421, 0x0442, 0x0422, 0x0443, - 0x0423, 0x0436, 0x0416, 0x0432, - 0x0412, 0x044c, 0x042c, 0x2116, - /* 0xf0*/ - 0x00ad, 0x044b, 0x042b, 0x0437, - 0x0417, 0x0448, 0x0428, 0x044d, - 0x042d, 0x0449, 0x0429, 0x0447, - 0x0427, 0x00a7, 0x25a0, 0x00a0, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xff, 0x00, 0x00, 0x00, 0xcf, 0x00, 0x00, 0xfd, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0xae, 0x00, 0xf0, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ -}; - -static const unsigned char page04[256] = { - 0x00, 0x85, 0x81, 0x83, 0x87, 0x89, 0x8b, 0x8d, /* 0x00-0x07 */ - 0x8f, 0x91, 0x93, 0x95, 0x97, 0x00, 0x99, 0x9b, /* 0x08-0x0f */ - 0xa1, 0xa3, 0xec, 0xad, 0xa7, 0xa9, 0xea, 0xf4, /* 0x10-0x17 */ - 0xb8, 0xbe, 0xc7, 0xd1, 0xd3, 0xd5, 0xd7, 0xdd, /* 0x18-0x1f */ - 0xe2, 0xe4, 0xe6, 0xe8, 0xab, 0xb6, 0xa5, 0xfc, /* 0x20-0x27 */ - 0xf6, 0xfa, 0x9f, 0xf2, 0xee, 0xf8, 0x9d, 0xe0, /* 0x28-0x2f */ - 0xa0, 0xa2, 0xeb, 0xac, 0xa6, 0xa8, 0xe9, 0xf3, /* 0x30-0x37 */ - 0xb7, 0xbd, 0xc6, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, /* 0x38-0x3f */ - 0xe1, 0xe3, 0xe5, 0xe7, 0xaa, 0xb5, 0xa4, 0xfb, /* 0x40-0x47 */ - 0xf5, 0xf9, 0x9e, 0xf1, 0xed, 0xf7, 0x9c, 0xde, /* 0x48-0x4f */ - 0x00, 0x84, 0x80, 0x82, 0x86, 0x88, 0x8a, 0x8c, /* 0x50-0x57 */ - 0x8e, 0x90, 0x92, 0x94, 0x96, 0x00, 0x98, 0x9a, /* 0x58-0x5f */ -}; - -static const unsigned char page21[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0x00, /* 0x10-0x17 */ -}; - -static const unsigned char page25[256] = { - 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xcd, 0xba, 0x00, 0x00, 0xc9, 0x00, 0x00, 0xbb, /* 0x50-0x57 */ - 0x00, 0x00, 0xc8, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x58-0x5f */ - 0xcc, 0x00, 0x00, 0xb9, 0x00, 0x00, 0xcb, 0x00, /* 0x60-0x67 */ - 0x00, 0xca, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, NULL, NULL, NULL, page04, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, page21, NULL, NULL, NULL, page25, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x80, 0x82, 0x82, 0x84, 0x84, 0x86, 0x86, /* 0x80-0x87 */ - 0x88, 0x88, 0x8a, 0x8a, 0x8c, 0x8c, 0x8e, 0x8e, /* 0x88-0x8f */ - 0x90, 0x90, 0x92, 0x92, 0x94, 0x94, 0x96, 0x96, /* 0x90-0x97 */ - 0x98, 0x98, 0x9a, 0x9a, 0x9c, 0x9c, 0x9e, 0x9e, /* 0x98-0x9f */ - 0xa0, 0xa0, 0xa2, 0xa2, 0xa4, 0xa4, 0xa6, 0xa6, /* 0xa0-0xa7 */ - 0xa8, 0xa8, 0xaa, 0xaa, 0xac, 0xac, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb5, 0xb7, /* 0xb0-0xb7 */ - 0xb7, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbd, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc6, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd0, 0xd2, 0xd2, 0xd4, 0xd4, 0xd6, 0xd6, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xd8, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xde, 0xe1, 0xe1, 0xe3, 0xe3, 0xe5, 0xe5, 0xe7, /* 0xe0-0xe7 */ - 0xe7, 0xe9, 0xe9, 0xeb, 0xeb, 0xed, 0xed, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf1, 0xf3, 0xf3, 0xf5, 0xf5, 0xf7, /* 0xf0-0xf7 */ - 0xf7, 0xf9, 0xf9, 0xfb, 0xfb, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x81, 0x81, 0x83, 0x83, 0x85, 0x85, 0x87, 0x87, /* 0x80-0x87 */ - 0x89, 0x89, 0x8b, 0x8b, 0x8d, 0x8d, 0x8f, 0x8f, /* 0x88-0x8f */ - 0x91, 0x91, 0x93, 0x93, 0x95, 0x95, 0x97, 0x97, /* 0x90-0x97 */ - 0x99, 0x99, 0x9b, 0x9b, 0x9d, 0x9d, 0x9f, 0x9f, /* 0x98-0x9f */ - 0xa1, 0xa1, 0xa3, 0xa3, 0xa5, 0xa5, 0xa7, 0xa7, /* 0xa0-0xa7 */ - 0xa9, 0xa9, 0xab, 0xab, 0xad, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb6, 0xb6, 0xb8, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbe, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc7, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd1, 0xd1, 0xd3, 0xd3, 0xd5, 0xd5, 0xd7, 0xd7, /* 0xd0-0xd7 */ - 0xdd, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xe0, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe2, 0xe2, 0xe4, 0xe4, 0xe6, 0xe6, 0xe8, /* 0xe0-0xe7 */ - 0xe8, 0xea, 0xea, 0xec, 0xec, 0xee, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf2, 0xf2, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, /* 0xf0-0xf7 */ - 0xf8, 0xfa, 0xfa, 0xfc, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp855", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp855(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp855(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp855) -module_exit(exit_nls_cp855) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_cp857.c b/src/linux/fs/nls/nls_cp857.c deleted file mode 100644 index 0983097..0000000 --- a/src/linux/fs/nls/nls_cp857.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * linux/fs/nls/nls_cp857.c - * - * Charset cp857 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x00c7, 0x00fc, 0x00e9, 0x00e2, - 0x00e4, 0x00e0, 0x00e5, 0x00e7, - 0x00ea, 0x00eb, 0x00e8, 0x00ef, - 0x00ee, 0x0131, 0x00c4, 0x00c5, - /* 0x90*/ - 0x00c9, 0x00e6, 0x00c6, 0x00f4, - 0x00f6, 0x00f2, 0x00fb, 0x00f9, - 0x0130, 0x00d6, 0x00dc, 0x00f8, - 0x00a3, 0x00d8, 0x015e, 0x015f, - /* 0xa0*/ - 0x00e1, 0x00ed, 0x00f3, 0x00fa, - 0x00f1, 0x00d1, 0x011e, 0x011f, - 0x00bf, 0x00ae, 0x00ac, 0x00bd, - 0x00bc, 0x00a1, 0x00ab, 0x00bb, - /* 0xb0*/ - 0x2591, 0x2592, 0x2593, 0x2502, - 0x2524, 0x00c1, 0x00c2, 0x00c0, - 0x00a9, 0x2563, 0x2551, 0x2557, - 0x255d, 0x00a2, 0x00a5, 0x2510, - /* 0xc0*/ - 0x2514, 0x2534, 0x252c, 0x251c, - 0x2500, 0x253c, 0x00e3, 0x00c3, - 0x255a, 0x2554, 0x2569, 0x2566, - 0x2560, 0x2550, 0x256c, 0x00a4, - /* 0xd0*/ - 0x00ba, 0x00aa, 0x00ca, 0x00cb, - 0x00c8, 0x0000, 0x00cd, 0x00ce, - 0x00cf, 0x2518, 0x250c, 0x2588, - 0x2584, 0x00a6, 0x00cc, 0x2580, - /* 0xe0*/ - 0x00d3, 0x00df, 0x00d4, 0x00d2, - 0x00f5, 0x00d5, 0x00b5, 0x0000, - 0x00d7, 0x00da, 0x00db, 0x00d9, - 0x00ec, 0x00ff, 0x00af, 0x00b4, - /* 0xf0*/ - 0x00ad, 0x00b1, 0x0000, 0x00be, - 0x00b6, 0x00a7, 0x00f7, 0x00b8, - 0x00b0, 0x00a8, 0x00b7, 0x00b9, - 0x00b3, 0x00b2, 0x25a0, 0x00a0, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xff, 0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5, /* 0xa0-0xa7 */ - 0xf9, 0xb8, 0xd1, 0xae, 0xaa, 0xf0, 0xa9, 0xee, /* 0xa8-0xaf */ - 0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa, /* 0xb0-0xb7 */ - 0xf7, 0xfb, 0xd0, 0xaf, 0xac, 0xab, 0xf3, 0xa8, /* 0xb8-0xbf */ - 0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */ - 0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* 0xc8-0xcf */ - 0x00, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0xe8, /* 0xd0-0xd7 */ - 0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */ - 0x85, 0xa0, 0x83, 0xc6, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */ - 0x8a, 0x82, 0x88, 0x89, 0xec, 0xa1, 0x8c, 0x8b, /* 0xe8-0xef */ - 0x00, 0xa4, 0x95, 0xa2, 0x93, 0xe4, 0x94, 0xf6, /* 0xf0-0xf7 */ - 0x9b, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0xed, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0xa7, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x98, 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x9f, /* 0x58-0x5f */ -}; - -static const unsigned char page25[256] = { - 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xcd, 0xba, 0x00, 0x00, 0xc9, 0x00, 0x00, 0xbb, /* 0x50-0x57 */ - 0x00, 0x00, 0xc8, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x58-0x5f */ - 0xcc, 0x00, 0x00, 0xb9, 0x00, 0x00, 0xcb, 0x00, /* 0x60-0x67 */ - 0x00, 0xca, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, page25, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x87, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x84, 0x86, /* 0x88-0x8f */ - 0x82, 0x91, 0x91, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x69, 0x94, 0x81, 0x9b, 0x9c, 0x9b, 0x9f, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa7, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xa0, 0x83, 0x85, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc6, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0x88, 0x89, 0x8a, 0x00, 0xa1, 0x8c, /* 0xd0-0xd7 */ - 0x8b, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xec, 0xdf, /* 0xd8-0xdf */ - 0xa2, 0xe1, 0x93, 0x95, 0xe4, 0xe4, 0xe6, 0x00, /* 0xe0-0xe7 */ - 0xe8, 0xa3, 0x96, 0x97, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0x00, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x9a, 0x90, 0xb6, 0x8e, 0xb7, 0x8f, 0x80, /* 0x80-0x87 */ - 0xd2, 0xd3, 0xd4, 0xd8, 0xd7, 0x49, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x92, 0x92, 0xe2, 0x99, 0xe3, 0xea, 0xeb, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9d, 0x9c, 0x9d, 0x9e, 0x9e, /* 0x98-0x9f */ - 0xb5, 0xd6, 0xe0, 0xe9, 0xa5, 0xa5, 0xa6, 0xa6, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc7, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0x00, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe5, 0xe5, 0x00, 0x00, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xde, 0x00, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0x00, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp857", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp857(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp857(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp857) -module_exit(exit_nls_cp857) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_cp860.c b/src/linux/fs/nls/nls_cp860.c deleted file mode 100644 index 8422447..0000000 --- a/src/linux/fs/nls/nls_cp860.c +++ /dev/null @@ -1,364 +0,0 @@ -/* - * linux/fs/nls/nls_cp860.c - * - * Charset cp860 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x00c7, 0x00fc, 0x00e9, 0x00e2, - 0x00e3, 0x00e0, 0x00c1, 0x00e7, - 0x00ea, 0x00ca, 0x00e8, 0x00cd, - 0x00d4, 0x00ec, 0x00c3, 0x00c2, - /* 0x90*/ - 0x00c9, 0x00c0, 0x00c8, 0x00f4, - 0x00f5, 0x00f2, 0x00da, 0x00f9, - 0x00cc, 0x00d5, 0x00dc, 0x00a2, - 0x00a3, 0x00d9, 0x20a7, 0x00d3, - /* 0xa0*/ - 0x00e1, 0x00ed, 0x00f3, 0x00fa, - 0x00f1, 0x00d1, 0x00aa, 0x00ba, - 0x00bf, 0x00d2, 0x00ac, 0x00bd, - 0x00bc, 0x00a1, 0x00ab, 0x00bb, - /* 0xb0*/ - 0x2591, 0x2592, 0x2593, 0x2502, - 0x2524, 0x2561, 0x2562, 0x2556, - 0x2555, 0x2563, 0x2551, 0x2557, - 0x255d, 0x255c, 0x255b, 0x2510, - /* 0xc0*/ - 0x2514, 0x2534, 0x252c, 0x251c, - 0x2500, 0x253c, 0x255e, 0x255f, - 0x255a, 0x2554, 0x2569, 0x2566, - 0x2560, 0x2550, 0x256c, 0x2567, - /* 0xd0*/ - 0x2568, 0x2564, 0x2565, 0x2559, - 0x2558, 0x2552, 0x2553, 0x256b, - 0x256a, 0x2518, 0x250c, 0x2588, - 0x2584, 0x258c, 0x2590, 0x2580, - /* 0xe0*/ - 0x03b1, 0x00df, 0x0393, 0x03c0, - 0x03a3, 0x03c3, 0x00b5, 0x03c4, - 0x03a6, 0x0398, 0x03a9, 0x03b4, - 0x221e, 0x03c6, 0x03b5, 0x2229, - /* 0xf0*/ - 0x2261, 0x00b1, 0x2265, 0x2264, - 0x2320, 0x2321, 0x00f7, 0x2248, - 0x00b0, 0x2219, 0x00b7, 0x221a, - 0x207f, 0x00b2, 0x25a0, 0x00a0, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xff, 0xad, 0x9b, 0x9c, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */ - 0x00, 0x00, 0xa7, 0xaf, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */ - 0x91, 0x86, 0x8f, 0x8e, 0x00, 0x00, 0x00, 0x80, /* 0xc0-0xc7 */ - 0x92, 0x90, 0x89, 0x00, 0x98, 0x8b, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0xa5, 0xa9, 0x9f, 0x8c, 0x99, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x9d, 0x96, 0x00, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */ - 0x85, 0xa0, 0x83, 0x84, 0x00, 0x00, 0x00, 0x87, /* 0xe0-0xe7 */ - 0x8a, 0x82, 0x88, 0x00, 0x8d, 0xa1, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0xa4, 0x95, 0xa2, 0x93, 0x94, 0x00, 0xf6, /* 0xf0-0xf7 */ - 0x00, 0x97, 0xa3, 0x00, 0x81, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page03[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */ - 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */ -}; - -static const unsigned char page23[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ -}; - -static const unsigned char page25[256] = { - 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */ - 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */ - 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */ - 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, NULL, NULL, page03, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, NULL, page22, page23, NULL, page25, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x87, 0x81, 0x82, 0x83, 0x84, 0x85, 0xa0, 0x87, /* 0x80-0x87 */ - 0x88, 0x88, 0x8a, 0xa1, 0x93, 0x8d, 0x84, 0x83, /* 0x88-0x8f */ - 0x82, 0x85, 0x8a, 0x93, 0x94, 0x95, 0xa3, 0x97, /* 0x90-0x97 */ - 0x8d, 0x94, 0x81, 0x9b, 0x9c, 0x97, 0x9e, 0xa2, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0x95, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0x00, 0xe3, 0xe5, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xed, 0x00, 0x00, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x9a, 0x90, 0x8f, 0x8e, 0x91, 0x86, 0x80, /* 0x80-0x87 */ - 0x89, 0x89, 0x92, 0x8b, 0x8c, 0x98, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x8c, 0x99, 0xa9, 0x96, 0x9d, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0x86, 0x8b, 0x9f, 0x96, 0xa5, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0x00, 0xe1, 0xe2, 0x00, 0xe4, 0xe4, 0x00, 0x00, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0x00, 0xec, 0xe8, 0x00, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp860", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp860(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp860(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp860) -module_exit(exit_nls_cp860) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_cp861.c b/src/linux/fs/nls/nls_cp861.c deleted file mode 100644 index dc873e4..0000000 --- a/src/linux/fs/nls/nls_cp861.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - * linux/fs/nls/nls_cp861.c - * - * Charset cp861 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x00c7, 0x00fc, 0x00e9, 0x00e2, - 0x00e4, 0x00e0, 0x00e5, 0x00e7, - 0x00ea, 0x00eb, 0x00e8, 0x00d0, - 0x00f0, 0x00de, 0x00c4, 0x00c5, - /* 0x90*/ - 0x00c9, 0x00e6, 0x00c6, 0x00f4, - 0x00f6, 0x00fe, 0x00fb, 0x00dd, - 0x00fd, 0x00d6, 0x00dc, 0x00f8, - 0x00a3, 0x00d8, 0x20a7, 0x0192, - /* 0xa0*/ - 0x00e1, 0x00ed, 0x00f3, 0x00fa, - 0x00c1, 0x00cd, 0x00d3, 0x00da, - 0x00bf, 0x2310, 0x00ac, 0x00bd, - 0x00bc, 0x00a1, 0x00ab, 0x00bb, - /* 0xb0*/ - 0x2591, 0x2592, 0x2593, 0x2502, - 0x2524, 0x2561, 0x2562, 0x2556, - 0x2555, 0x2563, 0x2551, 0x2557, - 0x255d, 0x255c, 0x255b, 0x2510, - /* 0xc0*/ - 0x2514, 0x2534, 0x252c, 0x251c, - 0x2500, 0x253c, 0x255e, 0x255f, - 0x255a, 0x2554, 0x2569, 0x2566, - 0x2560, 0x2550, 0x256c, 0x2567, - /* 0xd0*/ - 0x2568, 0x2564, 0x2565, 0x2559, - 0x2558, 0x2552, 0x2553, 0x256b, - 0x256a, 0x2518, 0x250c, 0x2588, - 0x2584, 0x258c, 0x2590, 0x2580, - /* 0xe0*/ - 0x03b1, 0x00df, 0x0393, 0x03c0, - 0x03a3, 0x03c3, 0x00b5, 0x03c4, - 0x03a6, 0x0398, 0x03a9, 0x03b4, - 0x221e, 0x03c6, 0x03b5, 0x2229, - /* 0xf0*/ - 0x2261, 0x00b1, 0x2265, 0x2264, - 0x2320, 0x2321, 0x00f7, 0x2248, - 0x00b0, 0x2219, 0x00b7, 0x221a, - 0x207f, 0x00b2, 0x25a0, 0x00a0, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xff, 0xad, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0xaf, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */ - 0x00, 0xa4, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */ - 0x00, 0x90, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, /* 0xc8-0xcf */ - 0x8b, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x99, 0x00, /* 0xd0-0xd7 */ - 0x9d, 0x00, 0xa7, 0x00, 0x9a, 0x97, 0x8d, 0xe1, /* 0xd8-0xdf */ - 0x85, 0xa0, 0x83, 0x00, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */ - 0x8a, 0x82, 0x88, 0x89, 0x00, 0xa1, 0x00, 0x00, /* 0xe8-0xef */ - 0x8c, 0x00, 0x00, 0xa2, 0x93, 0x00, 0x94, 0xf6, /* 0xf0-0xf7 */ - 0x9b, 0x00, 0xa3, 0x96, 0x81, 0x98, 0x95, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ -}; - -static const unsigned char page03[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */ - 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */ -}; - -static const unsigned char page23[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ -}; - -static const unsigned char page25[256] = { - 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */ - 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */ - 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */ - 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, NULL, page03, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, NULL, page22, page23, NULL, page25, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x87, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8c, 0x8c, 0x95, 0x84, 0x86, /* 0x88-0x8f */ - 0x82, 0x91, 0x91, 0x93, 0x94, 0x95, 0x96, 0x98, /* 0x90-0x97 */ - 0x98, 0x94, 0x81, 0x9b, 0x9c, 0x9b, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa0, 0xa1, 0xa2, 0xa3, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0x00, 0xe3, 0xe5, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xed, 0x00, 0x00, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x9a, 0x90, 0x00, 0x8e, 0x00, 0x8f, 0x80, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x8b, 0x8b, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x92, 0x92, 0x00, 0x99, 0x8d, 0x00, 0x97, /* 0x90-0x97 */ - 0x97, 0x99, 0x9a, 0x9d, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */ - 0xa4, 0xa5, 0xa6, 0xa7, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0x00, 0xe1, 0xe2, 0x00, 0xe4, 0xe4, 0x00, 0x00, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0x00, 0xec, 0xe8, 0x00, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp861", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp861(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp861(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp861) -module_exit(exit_nls_cp861) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_cp862.c b/src/linux/fs/nls/nls_cp862.c deleted file mode 100644 index d5263e3..0000000 --- a/src/linux/fs/nls/nls_cp862.c +++ /dev/null @@ -1,421 +0,0 @@ -/* - * linux/fs/nls/nls_cp862.c - * - * Charset cp862 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x05d0, 0x05d1, 0x05d2, 0x05d3, - 0x05d4, 0x05d5, 0x05d6, 0x05d7, - 0x05d8, 0x05d9, 0x05da, 0x05db, - 0x05dc, 0x05dd, 0x05de, 0x05df, - /* 0x90*/ - 0x05e0, 0x05e1, 0x05e2, 0x05e3, - 0x05e4, 0x05e5, 0x05e6, 0x05e7, - 0x05e8, 0x05e9, 0x05ea, 0x00a2, - 0x00a3, 0x00a5, 0x20a7, 0x0192, - /* 0xa0*/ - 0x00e1, 0x00ed, 0x00f3, 0x00fa, - 0x00f1, 0x00d1, 0x00aa, 0x00ba, - 0x00bf, 0x2310, 0x00ac, 0x00bd, - 0x00bc, 0x00a1, 0x00ab, 0x00bb, - /* 0xb0*/ - 0x2591, 0x2592, 0x2593, 0x2502, - 0x2524, 0x2561, 0x2562, 0x2556, - 0x2555, 0x2563, 0x2551, 0x2557, - 0x255d, 0x255c, 0x255b, 0x2510, - /* 0xc0*/ - 0x2514, 0x2534, 0x252c, 0x251c, - 0x2500, 0x253c, 0x255e, 0x255f, - 0x255a, 0x2554, 0x2569, 0x2566, - 0x2560, 0x2550, 0x256c, 0x2567, - /* 0xd0*/ - 0x2568, 0x2564, 0x2565, 0x2559, - 0x2558, 0x2552, 0x2553, 0x256b, - 0x256a, 0x2518, 0x250c, 0x2588, - 0x2584, 0x258c, 0x2590, 0x2580, - /* 0xe0*/ - 0x03b1, 0x00df, 0x0393, 0x03c0, - 0x03a3, 0x03c3, 0x00b5, 0x03c4, - 0x03a6, 0x0398, 0x03a9, 0x03b4, - 0x221e, 0x03c6, 0x03b5, 0x2229, - /* 0xf0*/ - 0x2261, 0x00b1, 0x2265, 0x2264, - 0x2320, 0x2321, 0x00f7, 0x2248, - 0x00b0, 0x2219, 0x00b7, 0x221a, - 0x207f, 0x00b2, 0x25a0, 0x00a0, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xff, 0xad, 0x9b, 0x9c, 0x00, 0x9d, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */ - 0x00, 0x00, 0xa7, 0xaf, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */ - 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0xa4, 0x00, 0xa2, 0x00, 0x00, 0x00, 0xf6, /* 0xf0-0xf7 */ - 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ -}; - -static const unsigned char page03[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */ - 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */ -}; - -static const unsigned char page05[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0xd0-0xd7 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0xd8-0xdf */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0xe0-0xe7 */ - 0x98, 0x99, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */ -}; - -static const unsigned char page23[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ -}; - -static const unsigned char page25[256] = { - 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */ - 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */ - 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */ - 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, NULL, page03, NULL, page05, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, NULL, page22, page23, NULL, page25, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0x00, 0xe3, 0xe5, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xed, 0x00, 0x00, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0x00, 0xe1, 0xe2, 0x00, 0xe4, 0xe4, 0x00, 0x00, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0x00, 0xec, 0xe8, 0x00, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp862", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp862(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp862(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp862) -module_exit(exit_nls_cp862) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_cp863.c b/src/linux/fs/nls/nls_cp863.c deleted file mode 100644 index 051c983..0000000 --- a/src/linux/fs/nls/nls_cp863.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * linux/fs/nls/nls_cp863.c - * - * Charset cp863 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x00c7, 0x00fc, 0x00e9, 0x00e2, - 0x00c2, 0x00e0, 0x00b6, 0x00e7, - 0x00ea, 0x00eb, 0x00e8, 0x00ef, - 0x00ee, 0x2017, 0x00c0, 0x00a7, - /* 0x90*/ - 0x00c9, 0x00c8, 0x00ca, 0x00f4, - 0x00cb, 0x00cf, 0x00fb, 0x00f9, - 0x00a4, 0x00d4, 0x00dc, 0x00a2, - 0x00a3, 0x00d9, 0x00db, 0x0192, - /* 0xa0*/ - 0x00a6, 0x00b4, 0x00f3, 0x00fa, - 0x00a8, 0x00b8, 0x00b3, 0x00af, - 0x00ce, 0x2310, 0x00ac, 0x00bd, - 0x00bc, 0x00be, 0x00ab, 0x00bb, - /* 0xb0*/ - 0x2591, 0x2592, 0x2593, 0x2502, - 0x2524, 0x2561, 0x2562, 0x2556, - 0x2555, 0x2563, 0x2551, 0x2557, - 0x255d, 0x255c, 0x255b, 0x2510, - /* 0xc0*/ - 0x2514, 0x2534, 0x252c, 0x251c, - 0x2500, 0x253c, 0x255e, 0x255f, - 0x255a, 0x2554, 0x2569, 0x2566, - 0x2560, 0x2550, 0x256c, 0x2567, - /* 0xd0*/ - 0x2568, 0x2564, 0x2565, 0x2559, - 0x2558, 0x2552, 0x2553, 0x256b, - 0x256a, 0x2518, 0x250c, 0x2588, - 0x2584, 0x258c, 0x2590, 0x2580, - /* 0xe0*/ - 0x03b1, 0x00df, 0x0393, 0x03c0, - 0x03a3, 0x03c3, 0x00b5, 0x03c4, - 0x03a6, 0x0398, 0x03a9, 0x03b4, - 0x221e, 0x03c6, 0x03b5, 0x2229, - /* 0xf0*/ - 0x2261, 0x00b1, 0x2265, 0x2264, - 0x2320, 0x2321, 0x00f7, 0x2248, - 0x00b0, 0x2219, 0x00b7, 0x221a, - 0x207f, 0x00b2, 0x25a0, 0x00a0, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xff, 0x00, 0x9b, 0x9c, 0x98, 0x00, 0xa0, 0x8f, /* 0xa0-0xa7 */ - 0xa4, 0x00, 0x00, 0xae, 0xaa, 0x00, 0x00, 0xa7, /* 0xa8-0xaf */ - 0xf8, 0xf1, 0xfd, 0xa6, 0xa1, 0xe6, 0x86, 0xfa, /* 0xb0-0xb7 */ - 0xa5, 0x00, 0x00, 0xaf, 0xac, 0xab, 0xad, 0x00, /* 0xb8-0xbf */ - 0x8e, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x80, /* 0xc0-0xc7 */ - 0x91, 0x90, 0x92, 0x94, 0x00, 0x00, 0xa8, 0x95, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x9d, 0x00, 0x9e, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */ - 0x85, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x87, /* 0xe0-0xe7 */ - 0x8a, 0x82, 0x88, 0x89, 0x00, 0x00, 0x8c, 0x8b, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0xa2, 0x93, 0x00, 0x00, 0xf6, /* 0xf0-0xf7 */ - 0x00, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ -}; - -static const unsigned char page03[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */ - 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8d, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */ -}; - -static const unsigned char page23[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ -}; - -static const unsigned char page25[256] = { - 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */ - 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */ - 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */ - 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, NULL, page03, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, NULL, page22, page23, NULL, page25, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x87, 0x81, 0x82, 0x83, 0x83, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x85, 0x8f, /* 0x88-0x8f */ - 0x82, 0x8a, 0x88, 0x93, 0x89, 0x8b, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x93, 0x81, 0x9b, 0x9c, 0x97, 0x96, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0x8c, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0x00, 0xe3, 0xe5, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xed, 0x00, 0x00, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x9a, 0x90, 0x84, 0x84, 0x8e, 0x86, 0x80, /* 0x80-0x87 */ - 0x92, 0x94, 0x91, 0x95, 0xa8, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x99, 0x94, 0x95, 0x9e, 0x9d, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */ - 0xa0, 0xa1, 0x00, 0x00, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0x00, 0xe1, 0xe2, 0x00, 0xe4, 0xe4, 0x00, 0x00, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0x00, 0xec, 0xe8, 0x00, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp863", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp863(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp863(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp863) -module_exit(exit_nls_cp863) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_cp864.c b/src/linux/fs/nls/nls_cp864.c deleted file mode 100644 index 97eb127..0000000 --- a/src/linux/fs/nls/nls_cp864.c +++ /dev/null @@ -1,407 +0,0 @@ -/* - * linux/fs/nls/nls_cp864.c - * - * Charset cp864 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x066a, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x00b0, 0x00b7, 0x2219, 0x221a, - 0x2592, 0x2500, 0x2502, 0x253c, - 0x2524, 0x252c, 0x251c, 0x2534, - 0x2510, 0x250c, 0x2514, 0x2518, - /* 0x90*/ - 0x03b2, 0x221e, 0x03c6, 0x00b1, - 0x00bd, 0x00bc, 0x2248, 0x00ab, - 0x00bb, 0xfef7, 0xfef8, 0x0000, - 0x0000, 0xfefb, 0xfefc, 0x0000, - /* 0xa0*/ - 0x00a0, 0x00ad, 0xfe82, 0x00a3, - 0x00a4, 0xfe84, 0x0000, 0x0000, - 0xfe8e, 0xfe8f, 0xfe95, 0xfe99, - 0x060c, 0xfe9d, 0xfea1, 0xfea5, - /* 0xb0*/ - 0x0660, 0x0661, 0x0662, 0x0663, - 0x0664, 0x0665, 0x0666, 0x0667, - 0x0668, 0x0669, 0xfed1, 0x061b, - 0xfeb1, 0xfeb5, 0xfeb9, 0x061f, - /* 0xc0*/ - 0x00a2, 0xfe80, 0xfe81, 0xfe83, - 0xfe85, 0xfeca, 0xfe8b, 0xfe8d, - 0xfe91, 0xfe93, 0xfe97, 0xfe9b, - 0xfe9f, 0xfea3, 0xfea7, 0xfea9, - /* 0xd0*/ - 0xfeab, 0xfead, 0xfeaf, 0xfeb3, - 0xfeb7, 0xfebb, 0xfebf, 0xfec1, - 0xfec5, 0xfecb, 0xfecf, 0x00a6, - 0x00ac, 0x00f7, 0x00d7, 0xfec9, - /* 0xe0*/ - 0x0640, 0xfed3, 0xfed7, 0xfedb, - 0xfedf, 0xfee3, 0xfee7, 0xfeeb, - 0xfeed, 0xfeef, 0xfef3, 0xfebd, - 0xfecc, 0xfece, 0xfecd, 0xfee1, - /* 0xf0*/ - 0xfe7d, 0x0651, 0xfee5, 0xfee9, - 0xfeec, 0xfef0, 0xfef2, 0xfed0, - 0xfed5, 0xfef5, 0xfef6, 0xfedd, - 0xfed9, 0xfef1, 0x25a0, 0x0000, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x00, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xa0, 0x00, 0xc0, 0xa3, 0xa4, 0x00, 0xdb, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x97, 0xdc, 0xa1, 0x00, 0x00, /* 0xa8-0xaf */ - 0x80, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x98, 0x95, 0x94, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, /* 0xf0-0xf7 */ -}; - -static const unsigned char page03[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, /* 0xc0-0xc7 */ -}; - -static const unsigned char page06[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xbf, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0xf1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0x60-0x67 */ - 0xb8, 0xb9, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x82, 0x83, 0x00, 0x00, 0x00, 0x91, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ -}; - -static const unsigned char page25[256] = { - 0x85, 0x00, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x8d, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x8c, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x8f, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ -}; - -static const unsigned char pagefe[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, 0x00, /* 0x78-0x7f */ - - 0xc1, 0xc2, 0xa2, 0xc3, 0xa5, 0xc4, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0xc6, 0x00, 0xc7, 0xa8, 0xa9, /* 0x88-0x8f */ - 0x00, 0xc8, 0x00, 0xc9, 0x00, 0xaa, 0x00, 0xca, /* 0x90-0x97 */ - 0x00, 0xab, 0x00, 0xcb, 0x00, 0xad, 0x00, 0xcc, /* 0x98-0x9f */ - 0x00, 0xae, 0x00, 0xcd, 0x00, 0xaf, 0x00, 0xce, /* 0xa0-0xa7 */ - 0x00, 0xcf, 0x00, 0xd0, 0x00, 0xd1, 0x00, 0xd2, /* 0xa8-0xaf */ - 0x00, 0xbc, 0x00, 0xd3, 0x00, 0xbd, 0x00, 0xd4, /* 0xb0-0xb7 */ - 0x00, 0xbe, 0x00, 0xd5, 0x00, 0xeb, 0x00, 0xd6, /* 0xb8-0xbf */ - 0x00, 0xd7, 0x00, 0x00, 0x00, 0xd8, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0xdf, 0xc5, 0xd9, 0xec, 0xee, 0xed, 0xda, /* 0xc8-0xcf */ - 0xf7, 0xba, 0x00, 0xe1, 0x00, 0xf8, 0x00, 0xe2, /* 0xd0-0xd7 */ - 0x00, 0xfc, 0x00, 0xe3, 0x00, 0xfb, 0x00, 0xe4, /* 0xd8-0xdf */ - 0x00, 0xef, 0x00, 0xe5, 0x00, 0xf2, 0x00, 0xe6, /* 0xe0-0xe7 */ - 0x00, 0xf3, 0x00, 0xe7, 0xf4, 0xe8, 0x00, 0xe9, /* 0xe8-0xef */ - 0xf5, 0xfd, 0xf6, 0xea, 0x00, 0xf9, 0xfa, 0x99, /* 0xf0-0xf7 */ - 0x9a, 0x00, 0x00, 0x9d, 0x9e, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, NULL, NULL, page03, NULL, NULL, page06, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, page22, NULL, NULL, page25, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, pagefe, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x00, 0x00, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x00, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x00, 0x91, 0x00, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x00, 0x00, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0x00, 0x00, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0x00, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp864", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp864(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp864(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp864) -module_exit(exit_nls_cp864) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_cp865.c b/src/linux/fs/nls/nls_cp865.c deleted file mode 100644 index 1112142..0000000 --- a/src/linux/fs/nls/nls_cp865.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - * linux/fs/nls/nls_cp865.c - * - * Charset cp865 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x00c7, 0x00fc, 0x00e9, 0x00e2, - 0x00e4, 0x00e0, 0x00e5, 0x00e7, - 0x00ea, 0x00eb, 0x00e8, 0x00ef, - 0x00ee, 0x00ec, 0x00c4, 0x00c5, - /* 0x90*/ - 0x00c9, 0x00e6, 0x00c6, 0x00f4, - 0x00f6, 0x00f2, 0x00fb, 0x00f9, - 0x00ff, 0x00d6, 0x00dc, 0x00f8, - 0x00a3, 0x00d8, 0x20a7, 0x0192, - /* 0xa0*/ - 0x00e1, 0x00ed, 0x00f3, 0x00fa, - 0x00f1, 0x00d1, 0x00aa, 0x00ba, - 0x00bf, 0x2310, 0x00ac, 0x00bd, - 0x00bc, 0x00a1, 0x00ab, 0x00a4, - /* 0xb0*/ - 0x2591, 0x2592, 0x2593, 0x2502, - 0x2524, 0x2561, 0x2562, 0x2556, - 0x2555, 0x2563, 0x2551, 0x2557, - 0x255d, 0x255c, 0x255b, 0x2510, - /* 0xc0*/ - 0x2514, 0x2534, 0x252c, 0x251c, - 0x2500, 0x253c, 0x255e, 0x255f, - 0x255a, 0x2554, 0x2569, 0x2566, - 0x2560, 0x2550, 0x256c, 0x2567, - /* 0xd0*/ - 0x2568, 0x2564, 0x2565, 0x2559, - 0x2558, 0x2552, 0x2553, 0x256b, - 0x256a, 0x2518, 0x250c, 0x2588, - 0x2584, 0x258c, 0x2590, 0x2580, - /* 0xe0*/ - 0x03b1, 0x00df, 0x0393, 0x03c0, - 0x03a3, 0x03c3, 0x00b5, 0x03c4, - 0x03a6, 0x0398, 0x03a9, 0x03b4, - 0x221e, 0x03c6, 0x03b5, 0x2229, - /* 0xf0*/ - 0x2261, 0x00b1, 0x2265, 0x2264, - 0x2320, 0x2321, 0x00f7, 0x2248, - 0x00b0, 0x2219, 0x00b7, 0x221a, - 0x207f, 0x00b2, 0x25a0, 0x00a0, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xff, 0xad, 0x00, 0x9c, 0xaf, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0xa6, 0xae, 0xaa, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0xf8, 0xf1, 0xfd, 0x00, 0x00, 0xe6, 0x00, 0xfa, /* 0xb0-0xb7 */ - 0x00, 0x00, 0xa7, 0x00, 0xac, 0xab, 0x00, 0xa8, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, 0x92, 0x80, /* 0xc0-0xc7 */ - 0x00, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0xa5, 0x00, 0x00, 0x00, 0x00, 0x99, 0x00, /* 0xd0-0xd7 */ - 0x9d, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0xe1, /* 0xd8-0xdf */ - 0x85, 0xa0, 0x83, 0x00, 0x84, 0x86, 0x91, 0x87, /* 0xe0-0xe7 */ - 0x8a, 0x82, 0x88, 0x89, 0x8d, 0xa1, 0x8c, 0x8b, /* 0xe8-0xef */ - 0x00, 0xa4, 0x95, 0xa2, 0x93, 0x00, 0x94, 0xf6, /* 0xf0-0xf7 */ - 0x9b, 0x97, 0xa3, 0x96, 0x81, 0x00, 0x00, 0x98, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ -}; - -static const unsigned char page03[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0xe4, 0x00, 0x00, 0xe8, 0x00, /* 0xa0-0xa7 */ - 0x00, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0xe0, 0x00, 0x00, 0xeb, 0xee, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0xe3, 0x00, 0x00, 0xe5, 0xe7, 0x00, 0xed, 0x00, /* 0xc0-0xc7 */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xa0-0xa7 */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0xec, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0xef, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0xf0, 0x00, 0x00, 0xf3, 0xf2, 0x00, 0x00, /* 0x60-0x67 */ -}; - -static const unsigned char page23[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0xf4, 0xf5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ -}; - -static const unsigned char page25[256] = { - 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */ - 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */ - 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */ - 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, NULL, page03, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, NULL, page22, page23, NULL, page25, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x87, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x84, 0x86, /* 0x88-0x8f */ - 0x82, 0x91, 0x91, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x94, 0x81, 0x9b, 0x9c, 0x9b, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa4, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0x00, 0xe3, 0xe5, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xed, 0x00, 0x00, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x9a, 0x90, 0x00, 0x8e, 0x00, 0x8f, 0x80, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x92, 0x92, 0x00, 0x99, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x99, 0x9a, 0x9d, 0x9c, 0x9d, 0x9e, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0xa5, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0x00, 0xe1, 0xe2, 0x00, 0xe4, 0xe4, 0x00, 0x00, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0x00, 0xec, 0xe8, 0x00, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp865", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp865(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp865(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp865) -module_exit(exit_nls_cp865) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_cp866.c b/src/linux/fs/nls/nls_cp866.c deleted file mode 100644 index ffdcbc3..0000000 --- a/src/linux/fs/nls/nls_cp866.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * linux/fs/nls/nls_cp866.c - * - * Charset cp866 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0410, 0x0411, 0x0412, 0x0413, - 0x0414, 0x0415, 0x0416, 0x0417, - 0x0418, 0x0419, 0x041a, 0x041b, - 0x041c, 0x041d, 0x041e, 0x041f, - /* 0x90*/ - 0x0420, 0x0421, 0x0422, 0x0423, - 0x0424, 0x0425, 0x0426, 0x0427, - 0x0428, 0x0429, 0x042a, 0x042b, - 0x042c, 0x042d, 0x042e, 0x042f, - /* 0xa0*/ - 0x0430, 0x0431, 0x0432, 0x0433, - 0x0434, 0x0435, 0x0436, 0x0437, - 0x0438, 0x0439, 0x043a, 0x043b, - 0x043c, 0x043d, 0x043e, 0x043f, - /* 0xb0*/ - 0x2591, 0x2592, 0x2593, 0x2502, - 0x2524, 0x2561, 0x2562, 0x2556, - 0x2555, 0x2563, 0x2551, 0x2557, - 0x255d, 0x255c, 0x255b, 0x2510, - /* 0xc0*/ - 0x2514, 0x2534, 0x252c, 0x251c, - 0x2500, 0x253c, 0x255e, 0x255f, - 0x255a, 0x2554, 0x2569, 0x2566, - 0x2560, 0x2550, 0x256c, 0x2567, - /* 0xd0*/ - 0x2568, 0x2564, 0x2565, 0x2559, - 0x2558, 0x2552, 0x2553, 0x256b, - 0x256a, 0x2518, 0x250c, 0x2588, - 0x2584, 0x258c, 0x2590, 0x2580, - /* 0xe0*/ - 0x0440, 0x0441, 0x0442, 0x0443, - 0x0444, 0x0445, 0x0446, 0x0447, - 0x0448, 0x0449, 0x044a, 0x044b, - 0x044c, 0x044d, 0x044e, 0x044f, - /* 0xf0*/ - 0x0401, 0x0451, 0x0404, 0x0454, - 0x0407, 0x0457, 0x040e, 0x045e, - 0x00b0, 0x2219, 0x00b7, 0x221a, - 0x2116, 0x00a4, 0x25a0, 0x00a0, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xff, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, /* 0xb0-0xb7 */ -}; - -static const unsigned char page04[256] = { - 0x00, 0xf0, 0x00, 0x00, 0xf2, 0x00, 0x00, 0xf4, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0x00, /* 0x08-0x0f */ - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x10-0x17 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x18-0x1f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x20-0x27 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x28-0x2f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0x30-0x37 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0x38-0x3f */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x40-0x47 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x48-0x4f */ - 0x00, 0xf1, 0x00, 0x00, 0xf3, 0x00, 0x00, 0xf5, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x00, /* 0x58-0x5f */ -}; - -static const unsigned char page21[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, /* 0x10-0x17 */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0xf9, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ -}; - -static const unsigned char page25[256] = { - 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xcd, 0xba, 0xd5, 0xd6, 0xc9, 0xb8, 0xb7, 0xbb, /* 0x50-0x57 */ - 0xd4, 0xd3, 0xc8, 0xbe, 0xbd, 0xbc, 0xc6, 0xc7, /* 0x58-0x5f */ - 0xcc, 0xb5, 0xb6, 0xb9, 0xd1, 0xd2, 0xcb, 0xcf, /* 0x60-0x67 */ - 0xd0, 0xca, 0xd8, 0xd7, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0xdb, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0xde, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, NULL, NULL, NULL, page04, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, page21, page22, NULL, NULL, page25, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0x80-0x87 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0x88-0x8f */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x90-0x97 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf1, 0xf1, 0xf3, 0xf3, 0xf5, 0xf5, 0xf7, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0xa0-0xa7 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0xe0-0xe7 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0xe8-0xef */ - 0xf0, 0xf0, 0xf2, 0xf2, 0xf4, 0xf4, 0xf6, 0xf6, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp866", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp866(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp866(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp866) -module_exit(exit_nls_cp866) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_cp869.c b/src/linux/fs/nls/nls_cp869.c deleted file mode 100644 index 3b5a345..0000000 --- a/src/linux/fs/nls/nls_cp869.c +++ /dev/null @@ -1,315 +0,0 @@ -/* - * linux/fs/nls/nls_cp869.c - * - * Charset cp869 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0386, 0x0000, - 0x00b7, 0x00ac, 0x00a6, 0x2018, - 0x2019, 0x0388, 0x2015, 0x0389, - /* 0x90*/ - 0x038a, 0x03aa, 0x038c, 0x0000, - 0x0000, 0x038e, 0x03ab, 0x00a9, - 0x038f, 0x00b2, 0x00b3, 0x03ac, - 0x00a3, 0x03ad, 0x03ae, 0x03af, - /* 0xa0*/ - 0x03ca, 0x0390, 0x03cc, 0x03cd, - 0x0391, 0x0392, 0x0393, 0x0394, - 0x0395, 0x0396, 0x0397, 0x00bd, - 0x0398, 0x0399, 0x00ab, 0x00bb, - /* 0xb0*/ - 0x2591, 0x2592, 0x2593, 0x2502, - 0x2524, 0x039a, 0x039b, 0x039c, - 0x039d, 0x2563, 0x2551, 0x2557, - 0x255d, 0x039e, 0x039f, 0x2510, - /* 0xc0*/ - 0x2514, 0x2534, 0x252c, 0x251c, - 0x2500, 0x253c, 0x03a0, 0x03a1, - 0x255a, 0x2554, 0x2569, 0x2566, - 0x2560, 0x2550, 0x256c, 0x03a3, - /* 0xd0*/ - 0x03a4, 0x03a5, 0x03a6, 0x03a7, - 0x03a8, 0x03a9, 0x03b1, 0x03b2, - 0x03b3, 0x2518, 0x250c, 0x2588, - 0x2584, 0x03b4, 0x03b5, 0x2580, - /* 0xe0*/ - 0x03b6, 0x03b7, 0x03b8, 0x03b9, - 0x03ba, 0x03bb, 0x03bc, 0x03bd, - 0x03be, 0x03bf, 0x03c0, 0x03c1, - 0x03c3, 0x03c2, 0x03c4, 0x0384, - /* 0xf0*/ - 0x00ad, 0x00b1, 0x03c5, 0x03c6, - 0x03c7, 0x00a7, 0x03c8, 0x0385, - 0x00b0, 0x00a8, 0x03c9, 0x03cb, - 0x03b0, 0x03ce, 0x25a0, 0x00a0, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xff, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x8a, 0xf5, /* 0xa0-0xa7 */ - 0xf9, 0x97, 0x00, 0xae, 0x89, 0xf0, 0x00, 0x00, /* 0xa8-0xaf */ - 0xf8, 0xf1, 0x99, 0x9a, 0x00, 0x00, 0x00, 0x88, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0xaf, 0x00, 0xab, 0x00, 0x00, /* 0xb8-0xbf */ -}; - -static const unsigned char page03[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0xef, 0xf7, 0x86, 0x00, /* 0x80-0x87 */ - 0x8d, 0x8f, 0x90, 0x00, 0x92, 0x00, 0x95, 0x98, /* 0x88-0x8f */ - 0xa1, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, /* 0x90-0x97 */ - 0xac, 0xad, 0xb5, 0xb6, 0xb7, 0xb8, 0xbd, 0xbe, /* 0x98-0x9f */ - 0xc6, 0xc7, 0x00, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, /* 0xa0-0xa7 */ - 0xd4, 0xd5, 0x91, 0x96, 0x9b, 0x9d, 0x9e, 0x9f, /* 0xa8-0xaf */ - 0xfc, 0xd6, 0xd7, 0xd8, 0xdd, 0xde, 0xe0, 0xe1, /* 0xb0-0xb7 */ - 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, /* 0xb8-0xbf */ - 0xea, 0xeb, 0xed, 0xec, 0xee, 0xf2, 0xf3, 0xf4, /* 0xc0-0xc7 */ - 0xf6, 0xfa, 0xa0, 0xfb, 0xa2, 0xa3, 0xfd, 0x00, /* 0xc8-0xcf */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, /* 0x10-0x17 */ - 0x8b, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ -}; - -static const unsigned char page25[256] = { - 0xc4, 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xbf, 0x00, 0x00, 0x00, 0xc0, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xd9, 0x00, 0x00, 0x00, 0xc3, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xcd, 0xba, 0x00, 0x00, 0xc9, 0x00, 0x00, 0xbb, /* 0x50-0x57 */ - 0x00, 0x00, 0xc8, 0x00, 0x00, 0xbc, 0x00, 0x00, /* 0x58-0x5f */ - 0xcc, 0x00, 0x00, 0xb9, 0x00, 0x00, 0xcb, 0x00, /* 0x60-0x67 */ - 0x00, 0xca, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0xdf, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0xb0, 0xb1, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, NULL, NULL, page03, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, NULL, NULL, NULL, NULL, page25, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x00, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x9d, 0x8e, 0x9e, /* 0x88-0x8f */ - 0x9f, 0xa0, 0xa2, 0x00, 0x00, 0xa3, 0xfb, 0x97, /* 0x90-0x97 */ - 0xfd, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xd6, 0xd7, 0xd8, 0xdd, /* 0xa0-0xa7 */ - 0xde, 0xe0, 0xe1, 0xab, 0xe2, 0xe3, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xe4, 0xe5, 0xe6, /* 0xb0-0xb7 */ - 0xe7, 0xb9, 0xba, 0xbb, 0xbc, 0xe8, 0xe9, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xea, 0xeb, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xec, /* 0xc8-0xcf */ - 0xee, 0xf2, 0xf3, 0xf4, 0xf6, 0xfa, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x00, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x00, 0x00, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x86, 0x9c, 0x8d, 0x8f, 0x90, /* 0x98-0x9f */ - 0x91, 0xa1, 0x92, 0x95, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xa4, 0xa5, /* 0xd0-0xd7 */ - 0xa6, 0xd9, 0xda, 0xdb, 0xdc, 0xa7, 0xa8, 0xdf, /* 0xd8-0xdf */ - 0xa9, 0xaa, 0xac, 0xad, 0xb5, 0xb6, 0xb7, 0xb8, /* 0xe0-0xe7 */ - 0xbd, 0xbe, 0xc6, 0xc7, 0xcf, 0xcf, 0xd0, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xd1, 0xd2, 0xd3, 0xf5, 0xd4, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xd5, 0x96, 0xfc, 0x98, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp869", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp869(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp869(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp869) -module_exit(exit_nls_cp869) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_cp874.c b/src/linux/fs/nls/nls_cp874.c deleted file mode 100644 index 8dfaa10..0000000 --- a/src/linux/fs/nls/nls_cp874.c +++ /dev/null @@ -1,275 +0,0 @@ -/* - * linux/fs/nls/nls_cp874.c - * - * Charset cp874 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x2026, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - /* 0x90*/ - 0x0000, 0x2018, 0x2019, 0x201c, - 0x201d, 0x2022, 0x2013, 0x2014, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - /* 0xa0*/ - 0x00a0, 0x0e01, 0x0e02, 0x0e03, - 0x0e04, 0x0e05, 0x0e06, 0x0e07, - 0x0e08, 0x0e09, 0x0e0a, 0x0e0b, - 0x0e0c, 0x0e0d, 0x0e0e, 0x0e0f, - /* 0xb0*/ - 0x0e10, 0x0e11, 0x0e12, 0x0e13, - 0x0e14, 0x0e15, 0x0e16, 0x0e17, - 0x0e18, 0x0e19, 0x0e1a, 0x0e1b, - 0x0e1c, 0x0e1d, 0x0e1e, 0x0e1f, - /* 0xc0*/ - 0x0e20, 0x0e21, 0x0e22, 0x0e23, - 0x0e24, 0x0e25, 0x0e26, 0x0e27, - 0x0e28, 0x0e29, 0x0e2a, 0x0e2b, - 0x0e2c, 0x0e2d, 0x0e2e, 0x0e2f, - /* 0xd0*/ - 0x0e30, 0x0e31, 0x0e32, 0x0e33, - 0x0e34, 0x0e35, 0x0e36, 0x0e37, - 0x0e38, 0x0e39, 0x0e3a, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0e3f, - /* 0xe0*/ - 0x0e40, 0x0e41, 0x0e42, 0x0e43, - 0x0e44, 0x0e45, 0x0e46, 0x0e47, - 0x0e48, 0x0e49, 0x0e4a, 0x0e4b, - 0x0e4c, 0x0e4d, 0x0e4e, 0x0e4f, - /* 0xf0*/ - 0x0e50, 0x0e51, 0x0e52, 0x0e53, - 0x0e54, 0x0e55, 0x0e56, 0x0e57, - 0x0e58, 0x0e59, 0x0e5a, 0x0e5b, - 0x0000, 0x0000, 0x0000, 0x0000, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ -}; - -static const unsigned char page0e[256] = { - 0x00, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0x00-0x07 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0x08-0x0f */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0x10-0x17 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0x18-0x1f */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x20-0x27 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0x28-0x2f */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0x30-0x37 */ - 0xd8, 0xd9, 0xda, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0x38-0x3f */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x40-0x47 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x48-0x4f */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0x50-0x57 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x96, 0x97, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x91, 0x92, 0x00, 0x00, 0x93, 0x94, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, 0x85, 0x00, /* 0x20-0x27 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, page0e, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0x00, 0x00, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "cp874", - .alias = "tis-620", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp874(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp874(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp874) -module_exit(exit_nls_cp874) - -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_ALIAS_NLS(tis-620); diff --git a/src/linux/fs/nls/nls_cp932.c b/src/linux/fs/nls/nls_cp932.c deleted file mode 100644 index 67b7398..0000000 --- a/src/linux/fs/nls/nls_cp932.c +++ /dev/null @@ -1,7933 +0,0 @@ -/* - * linux/fs/nls/nls_cp932.c - * - * Charset cp932 translation tables. - * This translation table was generated automatically, the - * original table can be download from the Microsoft website. - * (http://www.microsoft.com/typography/unicode/unicodecp.htm) - */ - -#include -#include -#include -#include -#include - -static const wchar_t c2u_81[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x3000,0x3001,0x3002,0xFF0C,0xFF0E,0x30FB,0xFF1A,0xFF1B,/* 0x40-0x47 */ - 0xFF1F,0xFF01,0x309B,0x309C,0x00B4,0xFF40,0x00A8,0xFF3E,/* 0x48-0x4F */ - 0xFFE3,0xFF3F,0x30FD,0x30FE,0x309D,0x309E,0x3003,0x4EDD,/* 0x50-0x57 */ - 0x3005,0x3006,0x3007,0x30FC,0x2015,0x2010,0xFF0F,0xFF3C,/* 0x58-0x5F */ - 0xFF5E,0x2225,0xFF5C,0x2026,0x2025,0x2018,0x2019,0x201C,/* 0x60-0x67 */ - 0x201D,0xFF08,0xFF09,0x3014,0x3015,0xFF3B,0xFF3D,0xFF5B,/* 0x68-0x6F */ - 0xFF5D,0x3008,0x3009,0x300A,0x300B,0x300C,0x300D,0x300E,/* 0x70-0x77 */ - 0x300F,0x3010,0x3011,0xFF0B,0xFF0D,0x00B1,0x00D7,0x0000,/* 0x78-0x7F */ - - 0x00F7,0xFF1D,0x2260,0xFF1C,0xFF1E,0x2266,0x2267,0x221E,/* 0x80-0x87 */ - 0x2234,0x2642,0x2640,0x00B0,0x2032,0x2033,0x2103,0xFFE5,/* 0x88-0x8F */ - 0xFF04,0xFFE0,0xFFE1,0xFF05,0xFF03,0xFF06,0xFF0A,0xFF20,/* 0x90-0x97 */ - 0x00A7,0x2606,0x2605,0x25CB,0x25CF,0x25CE,0x25C7,0x25C6,/* 0x98-0x9F */ - 0x25A1,0x25A0,0x25B3,0x25B2,0x25BD,0x25BC,0x203B,0x3012,/* 0xA0-0xA7 */ - 0x2192,0x2190,0x2191,0x2193,0x3013,0x0000,0x0000,0x0000,/* 0xA8-0xAF */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xB0-0xB7 */ - 0x2208,0x220B,0x2286,0x2287,0x2282,0x2283,0x222A,0x2229,/* 0xB8-0xBF */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xC0-0xC7 */ - 0x2227,0x2228,0xFFE2,0x21D2,0x21D4,0x2200,0x2203,0x0000,/* 0xC8-0xCF */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xD0-0xD7 */ - 0x0000,0x0000,0x2220,0x22A5,0x2312,0x2202,0x2207,0x2261,/* 0xD8-0xDF */ - 0x2252,0x226A,0x226B,0x221A,0x223D,0x221D,0x2235,0x222B,/* 0xE0-0xE7 */ - 0x222C,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xE8-0xEF */ - 0x212B,0x2030,0x266F,0x266D,0x266A,0x2020,0x2021,0x00B6,/* 0xF0-0xF7 */ - 0x0000,0x0000,0x0000,0x0000,0x25EF,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_82[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xFF10,/* 0x48-0x4F */ - 0xFF11,0xFF12,0xFF13,0xFF14,0xFF15,0xFF16,0xFF17,0xFF18,/* 0x50-0x57 */ - 0xFF19,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0xFF21,0xFF22,0xFF23,0xFF24,0xFF25,0xFF26,0xFF27,0xFF28,/* 0x60-0x67 */ - 0xFF29,0xFF2A,0xFF2B,0xFF2C,0xFF2D,0xFF2E,0xFF2F,0xFF30,/* 0x68-0x6F */ - 0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,0xFF38,/* 0x70-0x77 */ - 0xFF39,0xFF3A,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xFF41,0xFF42,0xFF43,0xFF44,0xFF45,0xFF46,0xFF47,/* 0x80-0x87 */ - 0xFF48,0xFF49,0xFF4A,0xFF4B,0xFF4C,0xFF4D,0xFF4E,0xFF4F,/* 0x88-0x8F */ - 0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0xFF57,/* 0x90-0x97 */ - 0xFF58,0xFF59,0xFF5A,0x0000,0x0000,0x0000,0x0000,0x3041,/* 0x98-0x9F */ - 0x3042,0x3043,0x3044,0x3045,0x3046,0x3047,0x3048,0x3049,/* 0xA0-0xA7 */ - 0x304A,0x304B,0x304C,0x304D,0x304E,0x304F,0x3050,0x3051,/* 0xA8-0xAF */ - 0x3052,0x3053,0x3054,0x3055,0x3056,0x3057,0x3058,0x3059,/* 0xB0-0xB7 */ - 0x305A,0x305B,0x305C,0x305D,0x305E,0x305F,0x3060,0x3061,/* 0xB8-0xBF */ - 0x3062,0x3063,0x3064,0x3065,0x3066,0x3067,0x3068,0x3069,/* 0xC0-0xC7 */ - 0x306A,0x306B,0x306C,0x306D,0x306E,0x306F,0x3070,0x3071,/* 0xC8-0xCF */ - 0x3072,0x3073,0x3074,0x3075,0x3076,0x3077,0x3078,0x3079,/* 0xD0-0xD7 */ - 0x307A,0x307B,0x307C,0x307D,0x307E,0x307F,0x3080,0x3081,/* 0xD8-0xDF */ - 0x3082,0x3083,0x3084,0x3085,0x3086,0x3087,0x3088,0x3089,/* 0xE0-0xE7 */ - 0x308A,0x308B,0x308C,0x308D,0x308E,0x308F,0x3090,0x3091,/* 0xE8-0xEF */ - 0x3092,0x3093,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xF0-0xF7 */ -}; - -static const wchar_t c2u_83[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x30A1,0x30A2,0x30A3,0x30A4,0x30A5,0x30A6,0x30A7,0x30A8,/* 0x40-0x47 */ - 0x30A9,0x30AA,0x30AB,0x30AC,0x30AD,0x30AE,0x30AF,0x30B0,/* 0x48-0x4F */ - 0x30B1,0x30B2,0x30B3,0x30B4,0x30B5,0x30B6,0x30B7,0x30B8,/* 0x50-0x57 */ - 0x30B9,0x30BA,0x30BB,0x30BC,0x30BD,0x30BE,0x30BF,0x30C0,/* 0x58-0x5F */ - 0x30C1,0x30C2,0x30C3,0x30C4,0x30C5,0x30C6,0x30C7,0x30C8,/* 0x60-0x67 */ - 0x30C9,0x30CA,0x30CB,0x30CC,0x30CD,0x30CE,0x30CF,0x30D0,/* 0x68-0x6F */ - 0x30D1,0x30D2,0x30D3,0x30D4,0x30D5,0x30D6,0x30D7,0x30D8,/* 0x70-0x77 */ - 0x30D9,0x30DA,0x30DB,0x30DC,0x30DD,0x30DE,0x30DF,0x0000,/* 0x78-0x7F */ - - 0x30E0,0x30E1,0x30E2,0x30E3,0x30E4,0x30E5,0x30E6,0x30E7,/* 0x80-0x87 */ - 0x30E8,0x30E9,0x30EA,0x30EB,0x30EC,0x30ED,0x30EE,0x30EF,/* 0x88-0x8F */ - 0x30F0,0x30F1,0x30F2,0x30F3,0x30F4,0x30F5,0x30F6,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0391,/* 0x98-0x9F */ - 0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,0x0398,0x0399,/* 0xA0-0xA7 */ - 0x039A,0x039B,0x039C,0x039D,0x039E,0x039F,0x03A0,0x03A1,/* 0xA8-0xAF */ - 0x03A3,0x03A4,0x03A5,0x03A6,0x03A7,0x03A8,0x03A9,0x0000,/* 0xB0-0xB7 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x03B1,/* 0xB8-0xBF */ - 0x03B2,0x03B3,0x03B4,0x03B5,0x03B6,0x03B7,0x03B8,0x03B9,/* 0xC0-0xC7 */ - 0x03BA,0x03BB,0x03BC,0x03BD,0x03BE,0x03BF,0x03C0,0x03C1,/* 0xC8-0xCF */ - 0x03C3,0x03C4,0x03C5,0x03C6,0x03C7,0x03C8,0x03C9,0x0000,/* 0xD0-0xD7 */ -}; - -static const wchar_t c2u_84[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0401,0x0416,/* 0x40-0x47 */ - 0x0417,0x0418,0x0419,0x041A,0x041B,0x041C,0x041D,0x041E,/* 0x48-0x4F */ - 0x041F,0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,0x0426,/* 0x50-0x57 */ - 0x0427,0x0428,0x0429,0x042A,0x042B,0x042C,0x042D,0x042E,/* 0x58-0x5F */ - 0x042F,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0451,0x0436,/* 0x70-0x77 */ - 0x0437,0x0438,0x0439,0x043A,0x043B,0x043C,0x043D,0x0000,/* 0x78-0x7F */ - - 0x043E,0x043F,0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,/* 0x80-0x87 */ - 0x0446,0x0447,0x0448,0x0449,0x044A,0x044B,0x044C,0x044D,/* 0x88-0x8F */ - 0x044E,0x044F,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x2500,/* 0x98-0x9F */ - 0x2502,0x250C,0x2510,0x2518,0x2514,0x251C,0x252C,0x2524,/* 0xA0-0xA7 */ - 0x2534,0x253C,0x2501,0x2503,0x250F,0x2513,0x251B,0x2517,/* 0xA8-0xAF */ - 0x2523,0x2533,0x252B,0x253B,0x254B,0x2520,0x252F,0x2528,/* 0xB0-0xB7 */ - 0x2537,0x253F,0x251D,0x2530,0x2525,0x2538,0x2542,0x0000,/* 0xB8-0xBF */ -}; - -static const wchar_t c2u_87[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,/* 0x40-0x47 */ - 0x2468,0x2469,0x246A,0x246B,0x246C,0x246D,0x246E,0x246F,/* 0x48-0x4F */ - 0x2470,0x2471,0x2472,0x2473,0x2160,0x2161,0x2162,0x2163,/* 0x50-0x57 */ - 0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,0x0000,0x3349,/* 0x58-0x5F */ - 0x3314,0x3322,0x334D,0x3318,0x3327,0x3303,0x3336,0x3351,/* 0x60-0x67 */ - 0x3357,0x330D,0x3326,0x3323,0x332B,0x334A,0x333B,0x339C,/* 0x68-0x6F */ - 0x339D,0x339E,0x338E,0x338F,0x33C4,0x33A1,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x337B,0x0000,/* 0x78-0x7F */ - - 0x301D,0x301F,0x2116,0x33CD,0x2121,0x32A4,0x32A5,0x32A6,/* 0x80-0x87 */ - 0x32A7,0x32A8,0x3231,0x3232,0x3239,0x337E,0x337D,0x337C,/* 0x88-0x8F */ - 0x2252,0x2261,0x222B,0x222E,0x2211,0x221A,0x22A5,0x2220,/* 0x90-0x97 */ - 0x221F,0x22BF,0x2235,0x2229,0x222A,0x0000,0x0000,0x0000,/* 0x98-0x9F */ -}; - -static const wchar_t c2u_88[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x4E9C,/* 0x98-0x9F */ - 0x5516,0x5A03,0x963F,0x54C0,0x611B,0x6328,0x59F6,0x9022,/* 0xA0-0xA7 */ - 0x8475,0x831C,0x7A50,0x60AA,0x63E1,0x6E25,0x65ED,0x8466,/* 0xA8-0xAF */ - 0x82A6,0x9BF5,0x6893,0x5727,0x65A1,0x6271,0x5B9B,0x59D0,/* 0xB0-0xB7 */ - 0x867B,0x98F4,0x7D62,0x7DBE,0x9B8E,0x6216,0x7C9F,0x88B7,/* 0xB8-0xBF */ - 0x5B89,0x5EB5,0x6309,0x6697,0x6848,0x95C7,0x978D,0x674F,/* 0xC0-0xC7 */ - 0x4EE5,0x4F0A,0x4F4D,0x4F9D,0x5049,0x56F2,0x5937,0x59D4,/* 0xC8-0xCF */ - 0x5A01,0x5C09,0x60DF,0x610F,0x6170,0x6613,0x6905,0x70BA,/* 0xD0-0xD7 */ - 0x754F,0x7570,0x79FB,0x7DAD,0x7DEF,0x80C3,0x840E,0x8863,/* 0xD8-0xDF */ - 0x8B02,0x9055,0x907A,0x533B,0x4E95,0x4EA5,0x57DF,0x80B2,/* 0xE0-0xE7 */ - 0x90C1,0x78EF,0x4E00,0x58F1,0x6EA2,0x9038,0x7A32,0x8328,/* 0xE8-0xEF */ - 0x828B,0x9C2F,0x5141,0x5370,0x54BD,0x54E1,0x56E0,0x59FB,/* 0xF0-0xF7 */ - 0x5F15,0x98F2,0x6DEB,0x80E4,0x852D,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_89[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9662,0x9670,0x96A0,0x97FB,0x540B,0x53F3,0x5B87,0x70CF,/* 0x40-0x47 */ - 0x7FBD,0x8FC2,0x96E8,0x536F,0x9D5C,0x7ABA,0x4E11,0x7893,/* 0x48-0x4F */ - 0x81FC,0x6E26,0x5618,0x5504,0x6B1D,0x851A,0x9C3B,0x59E5,/* 0x50-0x57 */ - 0x53A9,0x6D66,0x74DC,0x958F,0x5642,0x4E91,0x904B,0x96F2,/* 0x58-0x5F */ - 0x834F,0x990C,0x53E1,0x55B6,0x5B30,0x5F71,0x6620,0x66F3,/* 0x60-0x67 */ - 0x6804,0x6C38,0x6CF3,0x6D29,0x745B,0x76C8,0x7A4E,0x9834,/* 0x68-0x6F */ - 0x82F1,0x885B,0x8A60,0x92ED,0x6DB2,0x75AB,0x76CA,0x99C5,/* 0x70-0x77 */ - 0x60A6,0x8B01,0x8D8A,0x95B2,0x698E,0x53AD,0x5186,0x0000,/* 0x78-0x7F */ - - 0x5712,0x5830,0x5944,0x5BB4,0x5EF6,0x6028,0x63A9,0x63F4,/* 0x80-0x87 */ - 0x6CBF,0x6F14,0x708E,0x7114,0x7159,0x71D5,0x733F,0x7E01,/* 0x88-0x8F */ - 0x8276,0x82D1,0x8597,0x9060,0x925B,0x9D1B,0x5869,0x65BC,/* 0x90-0x97 */ - 0x6C5A,0x7525,0x51F9,0x592E,0x5965,0x5F80,0x5FDC,0x62BC,/* 0x98-0x9F */ - 0x65FA,0x6A2A,0x6B27,0x6BB4,0x738B,0x7FC1,0x8956,0x9D2C,/* 0xA0-0xA7 */ - 0x9D0E,0x9EC4,0x5CA1,0x6C96,0x837B,0x5104,0x5C4B,0x61B6,/* 0xA8-0xAF */ - 0x81C6,0x6876,0x7261,0x4E59,0x4FFA,0x5378,0x6069,0x6E29,/* 0xB0-0xB7 */ - 0x7A4F,0x97F3,0x4E0B,0x5316,0x4EEE,0x4F55,0x4F3D,0x4FA1,/* 0xB8-0xBF */ - 0x4F73,0x52A0,0x53EF,0x5609,0x590F,0x5AC1,0x5BB6,0x5BE1,/* 0xC0-0xC7 */ - 0x79D1,0x6687,0x679C,0x67B6,0x6B4C,0x6CB3,0x706B,0x73C2,/* 0xC8-0xCF */ - 0x798D,0x79BE,0x7A3C,0x7B87,0x82B1,0x82DB,0x8304,0x8377,/* 0xD0-0xD7 */ - 0x83EF,0x83D3,0x8766,0x8AB2,0x5629,0x8CA8,0x8FE6,0x904E,/* 0xD8-0xDF */ - 0x971E,0x868A,0x4FC4,0x5CE8,0x6211,0x7259,0x753B,0x81E5,/* 0xE0-0xE7 */ - 0x82BD,0x86FE,0x8CC0,0x96C5,0x9913,0x99D5,0x4ECB,0x4F1A,/* 0xE8-0xEF */ - 0x89E3,0x56DE,0x584A,0x58CA,0x5EFB,0x5FEB,0x602A,0x6094,/* 0xF0-0xF7 */ - 0x6062,0x61D0,0x6212,0x62D0,0x6539,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_8A[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9B41,0x6666,0x68B0,0x6D77,0x7070,0x754C,0x7686,0x7D75,/* 0x40-0x47 */ - 0x82A5,0x87F9,0x958B,0x968E,0x8C9D,0x51F1,0x52BE,0x5916,/* 0x48-0x4F */ - 0x54B3,0x5BB3,0x5D16,0x6168,0x6982,0x6DAF,0x788D,0x84CB,/* 0x50-0x57 */ - 0x8857,0x8A72,0x93A7,0x9AB8,0x6D6C,0x99A8,0x86D9,0x57A3,/* 0x58-0x5F */ - 0x67FF,0x86CE,0x920E,0x5283,0x5687,0x5404,0x5ED3,0x62E1,/* 0x60-0x67 */ - 0x64B9,0x683C,0x6838,0x6BBB,0x7372,0x78BA,0x7A6B,0x899A,/* 0x68-0x6F */ - 0x89D2,0x8D6B,0x8F03,0x90ED,0x95A3,0x9694,0x9769,0x5B66,/* 0x70-0x77 */ - 0x5CB3,0x697D,0x984D,0x984E,0x639B,0x7B20,0x6A2B,0x0000,/* 0x78-0x7F */ - - 0x6A7F,0x68B6,0x9C0D,0x6F5F,0x5272,0x559D,0x6070,0x62EC,/* 0x80-0x87 */ - 0x6D3B,0x6E07,0x6ED1,0x845B,0x8910,0x8F44,0x4E14,0x9C39,/* 0x88-0x8F */ - 0x53F6,0x691B,0x6A3A,0x9784,0x682A,0x515C,0x7AC3,0x84B2,/* 0x90-0x97 */ - 0x91DC,0x938C,0x565B,0x9D28,0x6822,0x8305,0x8431,0x7CA5,/* 0x98-0x9F */ - 0x5208,0x82C5,0x74E6,0x4E7E,0x4F83,0x51A0,0x5BD2,0x520A,/* 0xA0-0xA7 */ - 0x52D8,0x52E7,0x5DFB,0x559A,0x582A,0x59E6,0x5B8C,0x5B98,/* 0xA8-0xAF */ - 0x5BDB,0x5E72,0x5E79,0x60A3,0x611F,0x6163,0x61BE,0x63DB,/* 0xB0-0xB7 */ - 0x6562,0x67D1,0x6853,0x68FA,0x6B3E,0x6B53,0x6C57,0x6F22,/* 0xB8-0xBF */ - 0x6F97,0x6F45,0x74B0,0x7518,0x76E3,0x770B,0x7AFF,0x7BA1,/* 0xC0-0xC7 */ - 0x7C21,0x7DE9,0x7F36,0x7FF0,0x809D,0x8266,0x839E,0x89B3,/* 0xC8-0xCF */ - 0x8ACC,0x8CAB,0x9084,0x9451,0x9593,0x9591,0x95A2,0x9665,/* 0xD0-0xD7 */ - 0x97D3,0x9928,0x8218,0x4E38,0x542B,0x5CB8,0x5DCC,0x73A9,/* 0xD8-0xDF */ - 0x764C,0x773C,0x5CA9,0x7FEB,0x8D0B,0x96C1,0x9811,0x9854,/* 0xE0-0xE7 */ - 0x9858,0x4F01,0x4F0E,0x5371,0x559C,0x5668,0x57FA,0x5947,/* 0xE8-0xEF */ - 0x5B09,0x5BC4,0x5C90,0x5E0C,0x5E7E,0x5FCC,0x63EE,0x673A,/* 0xF0-0xF7 */ - 0x65D7,0x65E2,0x671F,0x68CB,0x68C4,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_8B[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6A5F,0x5E30,0x6BC5,0x6C17,0x6C7D,0x757F,0x7948,0x5B63,/* 0x40-0x47 */ - 0x7A00,0x7D00,0x5FBD,0x898F,0x8A18,0x8CB4,0x8D77,0x8ECC,/* 0x48-0x4F */ - 0x8F1D,0x98E2,0x9A0E,0x9B3C,0x4E80,0x507D,0x5100,0x5993,/* 0x50-0x57 */ - 0x5B9C,0x622F,0x6280,0x64EC,0x6B3A,0x72A0,0x7591,0x7947,/* 0x58-0x5F */ - 0x7FA9,0x87FB,0x8ABC,0x8B70,0x63AC,0x83CA,0x97A0,0x5409,/* 0x60-0x67 */ - 0x5403,0x55AB,0x6854,0x6A58,0x8A70,0x7827,0x6775,0x9ECD,/* 0x68-0x6F */ - 0x5374,0x5BA2,0x811A,0x8650,0x9006,0x4E18,0x4E45,0x4EC7,/* 0x70-0x77 */ - 0x4F11,0x53CA,0x5438,0x5BAE,0x5F13,0x6025,0x6551,0x0000,/* 0x78-0x7F */ - - 0x673D,0x6C42,0x6C72,0x6CE3,0x7078,0x7403,0x7A76,0x7AAE,/* 0x80-0x87 */ - 0x7B08,0x7D1A,0x7CFE,0x7D66,0x65E7,0x725B,0x53BB,0x5C45,/* 0x88-0x8F */ - 0x5DE8,0x62D2,0x62E0,0x6319,0x6E20,0x865A,0x8A31,0x8DDD,/* 0x90-0x97 */ - 0x92F8,0x6F01,0x79A6,0x9B5A,0x4EA8,0x4EAB,0x4EAC,0x4F9B,/* 0x98-0x9F */ - 0x4FA0,0x50D1,0x5147,0x7AF6,0x5171,0x51F6,0x5354,0x5321,/* 0xA0-0xA7 */ - 0x537F,0x53EB,0x55AC,0x5883,0x5CE1,0x5F37,0x5F4A,0x602F,/* 0xA8-0xAF */ - 0x6050,0x606D,0x631F,0x6559,0x6A4B,0x6CC1,0x72C2,0x72ED,/* 0xB0-0xB7 */ - 0x77EF,0x80F8,0x8105,0x8208,0x854E,0x90F7,0x93E1,0x97FF,/* 0xB8-0xBF */ - 0x9957,0x9A5A,0x4EF0,0x51DD,0x5C2D,0x6681,0x696D,0x5C40,/* 0xC0-0xC7 */ - 0x66F2,0x6975,0x7389,0x6850,0x7C81,0x50C5,0x52E4,0x5747,/* 0xC8-0xCF */ - 0x5DFE,0x9326,0x65A4,0x6B23,0x6B3D,0x7434,0x7981,0x79BD,/* 0xD0-0xD7 */ - 0x7B4B,0x7DCA,0x82B9,0x83CC,0x887F,0x895F,0x8B39,0x8FD1,/* 0xD8-0xDF */ - 0x91D1,0x541F,0x9280,0x4E5D,0x5036,0x53E5,0x533A,0x72D7,/* 0xE0-0xE7 */ - 0x7396,0x77E9,0x82E6,0x8EAF,0x99C6,0x99C8,0x99D2,0x5177,/* 0xE8-0xEF */ - 0x611A,0x865E,0x55B0,0x7A7A,0x5076,0x5BD3,0x9047,0x9685,/* 0xF0-0xF7 */ - 0x4E32,0x6ADB,0x91E7,0x5C51,0x5C48,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_8C[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6398,0x7A9F,0x6C93,0x9774,0x8F61,0x7AAA,0x718A,0x9688,/* 0x40-0x47 */ - 0x7C82,0x6817,0x7E70,0x6851,0x936C,0x52F2,0x541B,0x85AB,/* 0x48-0x4F */ - 0x8A13,0x7FA4,0x8ECD,0x90E1,0x5366,0x8888,0x7941,0x4FC2,/* 0x50-0x57 */ - 0x50BE,0x5211,0x5144,0x5553,0x572D,0x73EA,0x578B,0x5951,/* 0x58-0x5F */ - 0x5F62,0x5F84,0x6075,0x6176,0x6167,0x61A9,0x63B2,0x643A,/* 0x60-0x67 */ - 0x656C,0x666F,0x6842,0x6E13,0x7566,0x7A3D,0x7CFB,0x7D4C,/* 0x68-0x6F */ - 0x7D99,0x7E4B,0x7F6B,0x830E,0x834A,0x86CD,0x8A08,0x8A63,/* 0x70-0x77 */ - 0x8B66,0x8EFD,0x981A,0x9D8F,0x82B8,0x8FCE,0x9BE8,0x0000,/* 0x78-0x7F */ - - 0x5287,0x621F,0x6483,0x6FC0,0x9699,0x6841,0x5091,0x6B20,/* 0x80-0x87 */ - 0x6C7A,0x6F54,0x7A74,0x7D50,0x8840,0x8A23,0x6708,0x4EF6,/* 0x88-0x8F */ - 0x5039,0x5026,0x5065,0x517C,0x5238,0x5263,0x55A7,0x570F,/* 0x90-0x97 */ - 0x5805,0x5ACC,0x5EFA,0x61B2,0x61F8,0x62F3,0x6372,0x691C,/* 0x98-0x9F */ - 0x6A29,0x727D,0x72AC,0x732E,0x7814,0x786F,0x7D79,0x770C,/* 0xA0-0xA7 */ - 0x80A9,0x898B,0x8B19,0x8CE2,0x8ED2,0x9063,0x9375,0x967A,/* 0xA8-0xAF */ - 0x9855,0x9A13,0x9E78,0x5143,0x539F,0x53B3,0x5E7B,0x5F26,/* 0xB0-0xB7 */ - 0x6E1B,0x6E90,0x7384,0x73FE,0x7D43,0x8237,0x8A00,0x8AFA,/* 0xB8-0xBF */ - 0x9650,0x4E4E,0x500B,0x53E4,0x547C,0x56FA,0x59D1,0x5B64,/* 0xC0-0xC7 */ - 0x5DF1,0x5EAB,0x5F27,0x6238,0x6545,0x67AF,0x6E56,0x72D0,/* 0xC8-0xCF */ - 0x7CCA,0x88B4,0x80A1,0x80E1,0x83F0,0x864E,0x8A87,0x8DE8,/* 0xD0-0xD7 */ - 0x9237,0x96C7,0x9867,0x9F13,0x4E94,0x4E92,0x4F0D,0x5348,/* 0xD8-0xDF */ - 0x5449,0x543E,0x5A2F,0x5F8C,0x5FA1,0x609F,0x68A7,0x6A8E,/* 0xE0-0xE7 */ - 0x745A,0x7881,0x8A9E,0x8AA4,0x8B77,0x9190,0x4E5E,0x9BC9,/* 0xE8-0xEF */ - 0x4EA4,0x4F7C,0x4FAF,0x5019,0x5016,0x5149,0x516C,0x529F,/* 0xF0-0xF7 */ - 0x52B9,0x52FE,0x539A,0x53E3,0x5411,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_8D[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x540E,0x5589,0x5751,0x57A2,0x597D,0x5B54,0x5B5D,0x5B8F,/* 0x40-0x47 */ - 0x5DE5,0x5DE7,0x5DF7,0x5E78,0x5E83,0x5E9A,0x5EB7,0x5F18,/* 0x48-0x4F */ - 0x6052,0x614C,0x6297,0x62D8,0x63A7,0x653B,0x6602,0x6643,/* 0x50-0x57 */ - 0x66F4,0x676D,0x6821,0x6897,0x69CB,0x6C5F,0x6D2A,0x6D69,/* 0x58-0x5F */ - 0x6E2F,0x6E9D,0x7532,0x7687,0x786C,0x7A3F,0x7CE0,0x7D05,/* 0x60-0x67 */ - 0x7D18,0x7D5E,0x7DB1,0x8015,0x8003,0x80AF,0x80B1,0x8154,/* 0x68-0x6F */ - 0x818F,0x822A,0x8352,0x884C,0x8861,0x8B1B,0x8CA2,0x8CFC,/* 0x70-0x77 */ - 0x90CA,0x9175,0x9271,0x783F,0x92FC,0x95A4,0x964D,0x0000,/* 0x78-0x7F */ - - 0x9805,0x9999,0x9AD8,0x9D3B,0x525B,0x52AB,0x53F7,0x5408,/* 0x80-0x87 */ - 0x58D5,0x62F7,0x6FE0,0x8C6A,0x8F5F,0x9EB9,0x514B,0x523B,/* 0x88-0x8F */ - 0x544A,0x56FD,0x7A40,0x9177,0x9D60,0x9ED2,0x7344,0x6F09,/* 0x90-0x97 */ - 0x8170,0x7511,0x5FFD,0x60DA,0x9AA8,0x72DB,0x8FBC,0x6B64,/* 0x98-0x9F */ - 0x9803,0x4ECA,0x56F0,0x5764,0x58BE,0x5A5A,0x6068,0x61C7,/* 0xA0-0xA7 */ - 0x660F,0x6606,0x6839,0x68B1,0x6DF7,0x75D5,0x7D3A,0x826E,/* 0xA8-0xAF */ - 0x9B42,0x4E9B,0x4F50,0x53C9,0x5506,0x5D6F,0x5DE6,0x5DEE,/* 0xB0-0xB7 */ - 0x67FB,0x6C99,0x7473,0x7802,0x8A50,0x9396,0x88DF,0x5750,/* 0xB8-0xBF */ - 0x5EA7,0x632B,0x50B5,0x50AC,0x518D,0x6700,0x54C9,0x585E,/* 0xC0-0xC7 */ - 0x59BB,0x5BB0,0x5F69,0x624D,0x63A1,0x683D,0x6B73,0x6E08,/* 0xC8-0xCF */ - 0x707D,0x91C7,0x7280,0x7815,0x7826,0x796D,0x658E,0x7D30,/* 0xD0-0xD7 */ - 0x83DC,0x88C1,0x8F09,0x969B,0x5264,0x5728,0x6750,0x7F6A,/* 0xD8-0xDF */ - 0x8CA1,0x51B4,0x5742,0x962A,0x583A,0x698A,0x80B4,0x54B2,/* 0xE0-0xE7 */ - 0x5D0E,0x57FC,0x7895,0x9DFA,0x4F5C,0x524A,0x548B,0x643E,/* 0xE8-0xEF */ - 0x6628,0x6714,0x67F5,0x7A84,0x7B56,0x7D22,0x932F,0x685C,/* 0xF0-0xF7 */ - 0x9BAD,0x7B39,0x5319,0x518A,0x5237,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_8E[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5BDF,0x62F6,0x64AE,0x64E6,0x672D,0x6BBA,0x85A9,0x96D1,/* 0x40-0x47 */ - 0x7690,0x9BD6,0x634C,0x9306,0x9BAB,0x76BF,0x6652,0x4E09,/* 0x48-0x4F */ - 0x5098,0x53C2,0x5C71,0x60E8,0x6492,0x6563,0x685F,0x71E6,/* 0x50-0x57 */ - 0x73CA,0x7523,0x7B97,0x7E82,0x8695,0x8B83,0x8CDB,0x9178,/* 0x58-0x5F */ - 0x9910,0x65AC,0x66AB,0x6B8B,0x4ED5,0x4ED4,0x4F3A,0x4F7F,/* 0x60-0x67 */ - 0x523A,0x53F8,0x53F2,0x55E3,0x56DB,0x58EB,0x59CB,0x59C9,/* 0x68-0x6F */ - 0x59FF,0x5B50,0x5C4D,0x5E02,0x5E2B,0x5FD7,0x601D,0x6307,/* 0x70-0x77 */ - 0x652F,0x5B5C,0x65AF,0x65BD,0x65E8,0x679D,0x6B62,0x0000,/* 0x78-0x7F */ - - 0x6B7B,0x6C0F,0x7345,0x7949,0x79C1,0x7CF8,0x7D19,0x7D2B,/* 0x80-0x87 */ - 0x80A2,0x8102,0x81F3,0x8996,0x8A5E,0x8A69,0x8A66,0x8A8C,/* 0x88-0x8F */ - 0x8AEE,0x8CC7,0x8CDC,0x96CC,0x98FC,0x6B6F,0x4E8B,0x4F3C,/* 0x90-0x97 */ - 0x4F8D,0x5150,0x5B57,0x5BFA,0x6148,0x6301,0x6642,0x6B21,/* 0x98-0x9F */ - 0x6ECB,0x6CBB,0x723E,0x74BD,0x75D4,0x78C1,0x793A,0x800C,/* 0xA0-0xA7 */ - 0x8033,0x81EA,0x8494,0x8F9E,0x6C50,0x9E7F,0x5F0F,0x8B58,/* 0xA8-0xAF */ - 0x9D2B,0x7AFA,0x8EF8,0x5B8D,0x96EB,0x4E03,0x53F1,0x57F7,/* 0xB0-0xB7 */ - 0x5931,0x5AC9,0x5BA4,0x6089,0x6E7F,0x6F06,0x75BE,0x8CEA,/* 0xB8-0xBF */ - 0x5B9F,0x8500,0x7BE0,0x5072,0x67F4,0x829D,0x5C61,0x854A,/* 0xC0-0xC7 */ - 0x7E1E,0x820E,0x5199,0x5C04,0x6368,0x8D66,0x659C,0x716E,/* 0xC8-0xCF */ - 0x793E,0x7D17,0x8005,0x8B1D,0x8ECA,0x906E,0x86C7,0x90AA,/* 0xD0-0xD7 */ - 0x501F,0x52FA,0x5C3A,0x6753,0x707C,0x7235,0x914C,0x91C8,/* 0xD8-0xDF */ - 0x932B,0x82E5,0x5BC2,0x5F31,0x60F9,0x4E3B,0x53D6,0x5B88,/* 0xE0-0xE7 */ - 0x624B,0x6731,0x6B8A,0x72E9,0x73E0,0x7A2E,0x816B,0x8DA3,/* 0xE8-0xEF */ - 0x9152,0x9996,0x5112,0x53D7,0x546A,0x5BFF,0x6388,0x6A39,/* 0xF0-0xF7 */ - 0x7DAC,0x9700,0x56DA,0x53CE,0x5468,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_8F[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5B97,0x5C31,0x5DDE,0x4FEE,0x6101,0x62FE,0x6D32,0x79C0,/* 0x40-0x47 */ - 0x79CB,0x7D42,0x7E4D,0x7FD2,0x81ED,0x821F,0x8490,0x8846,/* 0x48-0x4F */ - 0x8972,0x8B90,0x8E74,0x8F2F,0x9031,0x914B,0x916C,0x96C6,/* 0x50-0x57 */ - 0x919C,0x4EC0,0x4F4F,0x5145,0x5341,0x5F93,0x620E,0x67D4,/* 0x58-0x5F */ - 0x6C41,0x6E0B,0x7363,0x7E26,0x91CD,0x9283,0x53D4,0x5919,/* 0x60-0x67 */ - 0x5BBF,0x6DD1,0x795D,0x7E2E,0x7C9B,0x587E,0x719F,0x51FA,/* 0x68-0x6F */ - 0x8853,0x8FF0,0x4FCA,0x5CFB,0x6625,0x77AC,0x7AE3,0x821C,/* 0x70-0x77 */ - 0x99FF,0x51C6,0x5FAA,0x65EC,0x696F,0x6B89,0x6DF3,0x0000,/* 0x78-0x7F */ - - 0x6E96,0x6F64,0x76FE,0x7D14,0x5DE1,0x9075,0x9187,0x9806,/* 0x80-0x87 */ - 0x51E6,0x521D,0x6240,0x6691,0x66D9,0x6E1A,0x5EB6,0x7DD2,/* 0x88-0x8F */ - 0x7F72,0x66F8,0x85AF,0x85F7,0x8AF8,0x52A9,0x53D9,0x5973,/* 0x90-0x97 */ - 0x5E8F,0x5F90,0x6055,0x92E4,0x9664,0x50B7,0x511F,0x52DD,/* 0x98-0x9F */ - 0x5320,0x5347,0x53EC,0x54E8,0x5546,0x5531,0x5617,0x5968,/* 0xA0-0xA7 */ - 0x59BE,0x5A3C,0x5BB5,0x5C06,0x5C0F,0x5C11,0x5C1A,0x5E84,/* 0xA8-0xAF */ - 0x5E8A,0x5EE0,0x5F70,0x627F,0x6284,0x62DB,0x638C,0x6377,/* 0xB0-0xB7 */ - 0x6607,0x660C,0x662D,0x6676,0x677E,0x68A2,0x6A1F,0x6A35,/* 0xB8-0xBF */ - 0x6CBC,0x6D88,0x6E09,0x6E58,0x713C,0x7126,0x7167,0x75C7,/* 0xC0-0xC7 */ - 0x7701,0x785D,0x7901,0x7965,0x79F0,0x7AE0,0x7B11,0x7CA7,/* 0xC8-0xCF */ - 0x7D39,0x8096,0x83D6,0x848B,0x8549,0x885D,0x88F3,0x8A1F,/* 0xD0-0xD7 */ - 0x8A3C,0x8A54,0x8A73,0x8C61,0x8CDE,0x91A4,0x9266,0x937E,/* 0xD8-0xDF */ - 0x9418,0x969C,0x9798,0x4E0A,0x4E08,0x4E1E,0x4E57,0x5197,/* 0xE0-0xE7 */ - 0x5270,0x57CE,0x5834,0x58CC,0x5B22,0x5E38,0x60C5,0x64FE,/* 0xE8-0xEF */ - 0x6761,0x6756,0x6D44,0x72B6,0x7573,0x7A63,0x84B8,0x8B72,/* 0xF0-0xF7 */ - 0x91B8,0x9320,0x5631,0x57F4,0x98FE,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_90[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x62ED,0x690D,0x6B96,0x71ED,0x7E54,0x8077,0x8272,0x89E6,/* 0x40-0x47 */ - 0x98DF,0x8755,0x8FB1,0x5C3B,0x4F38,0x4FE1,0x4FB5,0x5507,/* 0x48-0x4F */ - 0x5A20,0x5BDD,0x5BE9,0x5FC3,0x614E,0x632F,0x65B0,0x664B,/* 0x50-0x57 */ - 0x68EE,0x699B,0x6D78,0x6DF1,0x7533,0x75B9,0x771F,0x795E,/* 0x58-0x5F */ - 0x79E6,0x7D33,0x81E3,0x82AF,0x85AA,0x89AA,0x8A3A,0x8EAB,/* 0x60-0x67 */ - 0x8F9B,0x9032,0x91DD,0x9707,0x4EBA,0x4EC1,0x5203,0x5875,/* 0x68-0x6F */ - 0x58EC,0x5C0B,0x751A,0x5C3D,0x814E,0x8A0A,0x8FC5,0x9663,/* 0x70-0x77 */ - 0x976D,0x7B25,0x8ACF,0x9808,0x9162,0x56F3,0x53A8,0x0000,/* 0x78-0x7F */ - - 0x9017,0x5439,0x5782,0x5E25,0x63A8,0x6C34,0x708A,0x7761,/* 0x80-0x87 */ - 0x7C8B,0x7FE0,0x8870,0x9042,0x9154,0x9310,0x9318,0x968F,/* 0x88-0x8F */ - 0x745E,0x9AC4,0x5D07,0x5D69,0x6570,0x67A2,0x8DA8,0x96DB,/* 0x90-0x97 */ - 0x636E,0x6749,0x6919,0x83C5,0x9817,0x96C0,0x88FE,0x6F84,/* 0x98-0x9F */ - 0x647A,0x5BF8,0x4E16,0x702C,0x755D,0x662F,0x51C4,0x5236,/* 0xA0-0xA7 */ - 0x52E2,0x59D3,0x5F81,0x6027,0x6210,0x653F,0x6574,0x661F,/* 0xA8-0xAF */ - 0x6674,0x68F2,0x6816,0x6B63,0x6E05,0x7272,0x751F,0x76DB,/* 0xB0-0xB7 */ - 0x7CBE,0x8056,0x58F0,0x88FD,0x897F,0x8AA0,0x8A93,0x8ACB,/* 0xB8-0xBF */ - 0x901D,0x9192,0x9752,0x9759,0x6589,0x7A0E,0x8106,0x96BB,/* 0xC0-0xC7 */ - 0x5E2D,0x60DC,0x621A,0x65A5,0x6614,0x6790,0x77F3,0x7A4D,/* 0xC8-0xCF */ - 0x7C4D,0x7E3E,0x810A,0x8CAC,0x8D64,0x8DE1,0x8E5F,0x78A9,/* 0xD0-0xD7 */ - 0x5207,0x62D9,0x63A5,0x6442,0x6298,0x8A2D,0x7A83,0x7BC0,/* 0xD8-0xDF */ - 0x8AAC,0x96EA,0x7D76,0x820C,0x8749,0x4ED9,0x5148,0x5343,/* 0xE0-0xE7 */ - 0x5360,0x5BA3,0x5C02,0x5C16,0x5DDD,0x6226,0x6247,0x64B0,/* 0xE8-0xEF */ - 0x6813,0x6834,0x6CC9,0x6D45,0x6D17,0x67D3,0x6F5C,0x714E,/* 0xF0-0xF7 */ - 0x717D,0x65CB,0x7A7F,0x7BAD,0x7DDA,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_91[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7E4A,0x7FA8,0x817A,0x821B,0x8239,0x85A6,0x8A6E,0x8CCE,/* 0x40-0x47 */ - 0x8DF5,0x9078,0x9077,0x92AD,0x9291,0x9583,0x9BAE,0x524D,/* 0x48-0x4F */ - 0x5584,0x6F38,0x7136,0x5168,0x7985,0x7E55,0x81B3,0x7CCE,/* 0x50-0x57 */ - 0x564C,0x5851,0x5CA8,0x63AA,0x66FE,0x66FD,0x695A,0x72D9,/* 0x58-0x5F */ - 0x758F,0x758E,0x790E,0x7956,0x79DF,0x7C97,0x7D20,0x7D44,/* 0x60-0x67 */ - 0x8607,0x8A34,0x963B,0x9061,0x9F20,0x50E7,0x5275,0x53CC,/* 0x68-0x6F */ - 0x53E2,0x5009,0x55AA,0x58EE,0x594F,0x723D,0x5B8B,0x5C64,/* 0x70-0x77 */ - 0x531D,0x60E3,0x60F3,0x635C,0x6383,0x633F,0x63BB,0x0000,/* 0x78-0x7F */ - - 0x64CD,0x65E9,0x66F9,0x5DE3,0x69CD,0x69FD,0x6F15,0x71E5,/* 0x80-0x87 */ - 0x4E89,0x75E9,0x76F8,0x7A93,0x7CDF,0x7DCF,0x7D9C,0x8061,/* 0x88-0x8F */ - 0x8349,0x8358,0x846C,0x84BC,0x85FB,0x88C5,0x8D70,0x9001,/* 0x90-0x97 */ - 0x906D,0x9397,0x971C,0x9A12,0x50CF,0x5897,0x618E,0x81D3,/* 0x98-0x9F */ - 0x8535,0x8D08,0x9020,0x4FC3,0x5074,0x5247,0x5373,0x606F,/* 0xA0-0xA7 */ - 0x6349,0x675F,0x6E2C,0x8DB3,0x901F,0x4FD7,0x5C5E,0x8CCA,/* 0xA8-0xAF */ - 0x65CF,0x7D9A,0x5352,0x8896,0x5176,0x63C3,0x5B58,0x5B6B,/* 0xB0-0xB7 */ - 0x5C0A,0x640D,0x6751,0x905C,0x4ED6,0x591A,0x592A,0x6C70,/* 0xB8-0xBF */ - 0x8A51,0x553E,0x5815,0x59A5,0x60F0,0x6253,0x67C1,0x8235,/* 0xC0-0xC7 */ - 0x6955,0x9640,0x99C4,0x9A28,0x4F53,0x5806,0x5BFE,0x8010,/* 0xC8-0xCF */ - 0x5CB1,0x5E2F,0x5F85,0x6020,0x614B,0x6234,0x66FF,0x6CF0,/* 0xD0-0xD7 */ - 0x6EDE,0x80CE,0x817F,0x82D4,0x888B,0x8CB8,0x9000,0x902E,/* 0xD8-0xDF */ - 0x968A,0x9EDB,0x9BDB,0x4EE3,0x53F0,0x5927,0x7B2C,0x918D,/* 0xE0-0xE7 */ - 0x984C,0x9DF9,0x6EDD,0x7027,0x5353,0x5544,0x5B85,0x6258,/* 0xE8-0xEF */ - 0x629E,0x62D3,0x6CA2,0x6FEF,0x7422,0x8A17,0x9438,0x6FC1,/* 0xF0-0xF7 */ - 0x8AFE,0x8338,0x51E7,0x86F8,0x53EA,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_92[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x53E9,0x4F46,0x9054,0x8FB0,0x596A,0x8131,0x5DFD,0x7AEA,/* 0x40-0x47 */ - 0x8FBF,0x68DA,0x8C37,0x72F8,0x9C48,0x6A3D,0x8AB0,0x4E39,/* 0x48-0x4F */ - 0x5358,0x5606,0x5766,0x62C5,0x63A2,0x65E6,0x6B4E,0x6DE1,/* 0x50-0x57 */ - 0x6E5B,0x70AD,0x77ED,0x7AEF,0x7BAA,0x7DBB,0x803D,0x80C6,/* 0x58-0x5F */ - 0x86CB,0x8A95,0x935B,0x56E3,0x58C7,0x5F3E,0x65AD,0x6696,/* 0x60-0x67 */ - 0x6A80,0x6BB5,0x7537,0x8AC7,0x5024,0x77E5,0x5730,0x5F1B,/* 0x68-0x6F */ - 0x6065,0x667A,0x6C60,0x75F4,0x7A1A,0x7F6E,0x81F4,0x8718,/* 0x70-0x77 */ - 0x9045,0x99B3,0x7BC9,0x755C,0x7AF9,0x7B51,0x84C4,0x0000,/* 0x78-0x7F */ - - 0x9010,0x79E9,0x7A92,0x8336,0x5AE1,0x7740,0x4E2D,0x4EF2,/* 0x80-0x87 */ - 0x5B99,0x5FE0,0x62BD,0x663C,0x67F1,0x6CE8,0x866B,0x8877,/* 0x88-0x8F */ - 0x8A3B,0x914E,0x92F3,0x99D0,0x6A17,0x7026,0x732A,0x82E7,/* 0x90-0x97 */ - 0x8457,0x8CAF,0x4E01,0x5146,0x51CB,0x558B,0x5BF5,0x5E16,/* 0x98-0x9F */ - 0x5E33,0x5E81,0x5F14,0x5F35,0x5F6B,0x5FB4,0x61F2,0x6311,/* 0xA0-0xA7 */ - 0x66A2,0x671D,0x6F6E,0x7252,0x753A,0x773A,0x8074,0x8139,/* 0xA8-0xAF */ - 0x8178,0x8776,0x8ABF,0x8ADC,0x8D85,0x8DF3,0x929A,0x9577,/* 0xB0-0xB7 */ - 0x9802,0x9CE5,0x52C5,0x6357,0x76F4,0x6715,0x6C88,0x73CD,/* 0xB8-0xBF */ - 0x8CC3,0x93AE,0x9673,0x6D25,0x589C,0x690E,0x69CC,0x8FFD,/* 0xC0-0xC7 */ - 0x939A,0x75DB,0x901A,0x585A,0x6802,0x63B4,0x69FB,0x4F43,/* 0xC8-0xCF */ - 0x6F2C,0x67D8,0x8FBB,0x8526,0x7DB4,0x9354,0x693F,0x6F70,/* 0xD0-0xD7 */ - 0x576A,0x58F7,0x5B2C,0x7D2C,0x722A,0x540A,0x91E3,0x9DB4,/* 0xD8-0xDF */ - 0x4EAD,0x4F4E,0x505C,0x5075,0x5243,0x8C9E,0x5448,0x5824,/* 0xE0-0xE7 */ - 0x5B9A,0x5E1D,0x5E95,0x5EAD,0x5EF7,0x5F1F,0x608C,0x62B5,/* 0xE8-0xEF */ - 0x633A,0x63D0,0x68AF,0x6C40,0x7887,0x798E,0x7A0B,0x7DE0,/* 0xF0-0xF7 */ - 0x8247,0x8A02,0x8AE6,0x8E44,0x9013,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_93[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x90B8,0x912D,0x91D8,0x9F0E,0x6CE5,0x6458,0x64E2,0x6575,/* 0x40-0x47 */ - 0x6EF4,0x7684,0x7B1B,0x9069,0x93D1,0x6EBA,0x54F2,0x5FB9,/* 0x48-0x4F */ - 0x64A4,0x8F4D,0x8FED,0x9244,0x5178,0x586B,0x5929,0x5C55,/* 0x50-0x57 */ - 0x5E97,0x6DFB,0x7E8F,0x751C,0x8CBC,0x8EE2,0x985B,0x70B9,/* 0x58-0x5F */ - 0x4F1D,0x6BBF,0x6FB1,0x7530,0x96FB,0x514E,0x5410,0x5835,/* 0x60-0x67 */ - 0x5857,0x59AC,0x5C60,0x5F92,0x6597,0x675C,0x6E21,0x767B,/* 0x68-0x6F */ - 0x83DF,0x8CED,0x9014,0x90FD,0x934D,0x7825,0x783A,0x52AA,/* 0x70-0x77 */ - 0x5EA6,0x571F,0x5974,0x6012,0x5012,0x515A,0x51AC,0x0000,/* 0x78-0x7F */ - - 0x51CD,0x5200,0x5510,0x5854,0x5858,0x5957,0x5B95,0x5CF6,/* 0x80-0x87 */ - 0x5D8B,0x60BC,0x6295,0x642D,0x6771,0x6843,0x68BC,0x68DF,/* 0x88-0x8F */ - 0x76D7,0x6DD8,0x6E6F,0x6D9B,0x706F,0x71C8,0x5F53,0x75D8,/* 0x90-0x97 */ - 0x7977,0x7B49,0x7B54,0x7B52,0x7CD6,0x7D71,0x5230,0x8463,/* 0x98-0x9F */ - 0x8569,0x85E4,0x8A0E,0x8B04,0x8C46,0x8E0F,0x9003,0x900F,/* 0xA0-0xA7 */ - 0x9419,0x9676,0x982D,0x9A30,0x95D8,0x50CD,0x52D5,0x540C,/* 0xA8-0xAF */ - 0x5802,0x5C0E,0x61A7,0x649E,0x6D1E,0x77B3,0x7AE5,0x80F4,/* 0xB0-0xB7 */ - 0x8404,0x9053,0x9285,0x5CE0,0x9D07,0x533F,0x5F97,0x5FB3,/* 0xB8-0xBF */ - 0x6D9C,0x7279,0x7763,0x79BF,0x7BE4,0x6BD2,0x72EC,0x8AAD,/* 0xC0-0xC7 */ - 0x6803,0x6A61,0x51F8,0x7A81,0x6934,0x5C4A,0x9CF6,0x82EB,/* 0xC8-0xCF */ - 0x5BC5,0x9149,0x701E,0x5678,0x5C6F,0x60C7,0x6566,0x6C8C,/* 0xD0-0xD7 */ - 0x8C5A,0x9041,0x9813,0x5451,0x66C7,0x920D,0x5948,0x90A3,/* 0xD8-0xDF */ - 0x5185,0x4E4D,0x51EA,0x8599,0x8B0E,0x7058,0x637A,0x934B,/* 0xE0-0xE7 */ - 0x6962,0x99B4,0x7E04,0x7577,0x5357,0x6960,0x8EDF,0x96E3,/* 0xE8-0xEF */ - 0x6C5D,0x4E8C,0x5C3C,0x5F10,0x8FE9,0x5302,0x8CD1,0x8089,/* 0xF0-0xF7 */ - 0x8679,0x5EFF,0x65E5,0x4E73,0x5165,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_94[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5982,0x5C3F,0x97EE,0x4EFB,0x598A,0x5FCD,0x8A8D,0x6FE1,/* 0x40-0x47 */ - 0x79B0,0x7962,0x5BE7,0x8471,0x732B,0x71B1,0x5E74,0x5FF5,/* 0x48-0x4F */ - 0x637B,0x649A,0x71C3,0x7C98,0x4E43,0x5EFC,0x4E4B,0x57DC,/* 0x50-0x57 */ - 0x56A2,0x60A9,0x6FC3,0x7D0D,0x80FD,0x8133,0x81BF,0x8FB2,/* 0x58-0x5F */ - 0x8997,0x86A4,0x5DF4,0x628A,0x64AD,0x8987,0x6777,0x6CE2,/* 0x60-0x67 */ - 0x6D3E,0x7436,0x7834,0x5A46,0x7F75,0x82AD,0x99AC,0x4FF3,/* 0x68-0x6F */ - 0x5EC3,0x62DD,0x6392,0x6557,0x676F,0x76C3,0x724C,0x80CC,/* 0x70-0x77 */ - 0x80BA,0x8F29,0x914D,0x500D,0x57F9,0x5A92,0x6885,0x0000,/* 0x78-0x7F */ - - 0x6973,0x7164,0x72FD,0x8CB7,0x58F2,0x8CE0,0x966A,0x9019,/* 0x80-0x87 */ - 0x877F,0x79E4,0x77E7,0x8429,0x4F2F,0x5265,0x535A,0x62CD,/* 0x88-0x8F */ - 0x67CF,0x6CCA,0x767D,0x7B94,0x7C95,0x8236,0x8584,0x8FEB,/* 0x90-0x97 */ - 0x66DD,0x6F20,0x7206,0x7E1B,0x83AB,0x99C1,0x9EA6,0x51FD,/* 0x98-0x9F */ - 0x7BB1,0x7872,0x7BB8,0x8087,0x7B48,0x6AE8,0x5E61,0x808C,/* 0xA0-0xA7 */ - 0x7551,0x7560,0x516B,0x9262,0x6E8C,0x767A,0x9197,0x9AEA,/* 0xA8-0xAF */ - 0x4F10,0x7F70,0x629C,0x7B4F,0x95A5,0x9CE9,0x567A,0x5859,/* 0xB0-0xB7 */ - 0x86E4,0x96BC,0x4F34,0x5224,0x534A,0x53CD,0x53DB,0x5E06,/* 0xB8-0xBF */ - 0x642C,0x6591,0x677F,0x6C3E,0x6C4E,0x7248,0x72AF,0x73ED,/* 0xC0-0xC7 */ - 0x7554,0x7E41,0x822C,0x85E9,0x8CA9,0x7BC4,0x91C6,0x7169,/* 0xC8-0xCF */ - 0x9812,0x98EF,0x633D,0x6669,0x756A,0x76E4,0x78D0,0x8543,/* 0xD0-0xD7 */ - 0x86EE,0x532A,0x5351,0x5426,0x5983,0x5E87,0x5F7C,0x60B2,/* 0xD8-0xDF */ - 0x6249,0x6279,0x62AB,0x6590,0x6BD4,0x6CCC,0x75B2,0x76AE,/* 0xE0-0xE7 */ - 0x7891,0x79D8,0x7DCB,0x7F77,0x80A5,0x88AB,0x8AB9,0x8CBB,/* 0xE8-0xEF */ - 0x907F,0x975E,0x98DB,0x6A0B,0x7C38,0x5099,0x5C3E,0x5FAE,/* 0xF0-0xF7 */ - 0x6787,0x6BD8,0x7435,0x7709,0x7F8E,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_95[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9F3B,0x67CA,0x7A17,0x5339,0x758B,0x9AED,0x5F66,0x819D,/* 0x40-0x47 */ - 0x83F1,0x8098,0x5F3C,0x5FC5,0x7562,0x7B46,0x903C,0x6867,/* 0x48-0x4F */ - 0x59EB,0x5A9B,0x7D10,0x767E,0x8B2C,0x4FF5,0x5F6A,0x6A19,/* 0x50-0x57 */ - 0x6C37,0x6F02,0x74E2,0x7968,0x8868,0x8A55,0x8C79,0x5EDF,/* 0x58-0x5F */ - 0x63CF,0x75C5,0x79D2,0x82D7,0x9328,0x92F2,0x849C,0x86ED,/* 0x60-0x67 */ - 0x9C2D,0x54C1,0x5F6C,0x658C,0x6D5C,0x7015,0x8CA7,0x8CD3,/* 0x68-0x6F */ - 0x983B,0x654F,0x74F6,0x4E0D,0x4ED8,0x57E0,0x592B,0x5A66,/* 0x70-0x77 */ - 0x5BCC,0x51A8,0x5E03,0x5E9C,0x6016,0x6276,0x6577,0x0000,/* 0x78-0x7F */ - - 0x65A7,0x666E,0x6D6E,0x7236,0x7B26,0x8150,0x819A,0x8299,/* 0x80-0x87 */ - 0x8B5C,0x8CA0,0x8CE6,0x8D74,0x961C,0x9644,0x4FAE,0x64AB,/* 0x88-0x8F */ - 0x6B66,0x821E,0x8461,0x856A,0x90E8,0x5C01,0x6953,0x98A8,/* 0x90-0x97 */ - 0x847A,0x8557,0x4F0F,0x526F,0x5FA9,0x5E45,0x670D,0x798F,/* 0x98-0x9F */ - 0x8179,0x8907,0x8986,0x6DF5,0x5F17,0x6255,0x6CB8,0x4ECF,/* 0xA0-0xA7 */ - 0x7269,0x9B92,0x5206,0x543B,0x5674,0x58B3,0x61A4,0x626E,/* 0xA8-0xAF */ - 0x711A,0x596E,0x7C89,0x7CDE,0x7D1B,0x96F0,0x6587,0x805E,/* 0xB0-0xB7 */ - 0x4E19,0x4F75,0x5175,0x5840,0x5E63,0x5E73,0x5F0A,0x67C4,/* 0xB8-0xBF */ - 0x4E26,0x853D,0x9589,0x965B,0x7C73,0x9801,0x50FB,0x58C1,/* 0xC0-0xC7 */ - 0x7656,0x78A7,0x5225,0x77A5,0x8511,0x7B86,0x504F,0x5909,/* 0xC8-0xCF */ - 0x7247,0x7BC7,0x7DE8,0x8FBA,0x8FD4,0x904D,0x4FBF,0x52C9,/* 0xD0-0xD7 */ - 0x5A29,0x5F01,0x97AD,0x4FDD,0x8217,0x92EA,0x5703,0x6355,/* 0xD8-0xDF */ - 0x6B69,0x752B,0x88DC,0x8F14,0x7A42,0x52DF,0x5893,0x6155,/* 0xE0-0xE7 */ - 0x620A,0x66AE,0x6BCD,0x7C3F,0x83E9,0x5023,0x4FF8,0x5305,/* 0xE8-0xEF */ - 0x5446,0x5831,0x5949,0x5B9D,0x5CF0,0x5CEF,0x5D29,0x5E96,/* 0xF0-0xF7 */ - 0x62B1,0x6367,0x653E,0x65B9,0x670B,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_96[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6CD5,0x6CE1,0x70F9,0x7832,0x7E2B,0x80DE,0x82B3,0x840C,/* 0x40-0x47 */ - 0x84EC,0x8702,0x8912,0x8A2A,0x8C4A,0x90A6,0x92D2,0x98FD,/* 0x48-0x4F */ - 0x9CF3,0x9D6C,0x4E4F,0x4EA1,0x508D,0x5256,0x574A,0x59A8,/* 0x50-0x57 */ - 0x5E3D,0x5FD8,0x5FD9,0x623F,0x66B4,0x671B,0x67D0,0x68D2,/* 0x58-0x5F */ - 0x5192,0x7D21,0x80AA,0x81A8,0x8B00,0x8C8C,0x8CBF,0x927E,/* 0x60-0x67 */ - 0x9632,0x5420,0x982C,0x5317,0x50D5,0x535C,0x58A8,0x64B2,/* 0x68-0x6F */ - 0x6734,0x7267,0x7766,0x7A46,0x91E6,0x52C3,0x6CA1,0x6B86,/* 0x70-0x77 */ - 0x5800,0x5E4C,0x5954,0x672C,0x7FFB,0x51E1,0x76C6,0x0000,/* 0x78-0x7F */ - - 0x6469,0x78E8,0x9B54,0x9EBB,0x57CB,0x59B9,0x6627,0x679A,/* 0x80-0x87 */ - 0x6BCE,0x54E9,0x69D9,0x5E55,0x819C,0x6795,0x9BAA,0x67FE,/* 0x88-0x8F */ - 0x9C52,0x685D,0x4EA6,0x4FE3,0x53C8,0x62B9,0x672B,0x6CAB,/* 0x90-0x97 */ - 0x8FC4,0x4FAD,0x7E6D,0x9EBF,0x4E07,0x6162,0x6E80,0x6F2B,/* 0x98-0x9F */ - 0x8513,0x5473,0x672A,0x9B45,0x5DF3,0x7B95,0x5CAC,0x5BC6,/* 0xA0-0xA7 */ - 0x871C,0x6E4A,0x84D1,0x7A14,0x8108,0x5999,0x7C8D,0x6C11,/* 0xA8-0xAF */ - 0x7720,0x52D9,0x5922,0x7121,0x725F,0x77DB,0x9727,0x9D61,/* 0xB0-0xB7 */ - 0x690B,0x5A7F,0x5A18,0x51A5,0x540D,0x547D,0x660E,0x76DF,/* 0xB8-0xBF */ - 0x8FF7,0x9298,0x9CF4,0x59EA,0x725D,0x6EC5,0x514D,0x68C9,/* 0xC0-0xC7 */ - 0x7DBF,0x7DEC,0x9762,0x9EBA,0x6478,0x6A21,0x8302,0x5984,/* 0xC8-0xCF */ - 0x5B5F,0x6BDB,0x731B,0x76F2,0x7DB2,0x8017,0x8499,0x5132,/* 0xD0-0xD7 */ - 0x6728,0x9ED9,0x76EE,0x6762,0x52FF,0x9905,0x5C24,0x623B,/* 0xD8-0xDF */ - 0x7C7E,0x8CB0,0x554F,0x60B6,0x7D0B,0x9580,0x5301,0x4E5F,/* 0xE0-0xE7 */ - 0x51B6,0x591C,0x723A,0x8036,0x91CE,0x5F25,0x77E2,0x5384,/* 0xE8-0xEF */ - 0x5F79,0x7D04,0x85AC,0x8A33,0x8E8D,0x9756,0x67F3,0x85AE,/* 0xF0-0xF7 */ - 0x9453,0x6109,0x6108,0x6CB9,0x7652,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_97[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8AED,0x8F38,0x552F,0x4F51,0x512A,0x52C7,0x53CB,0x5BA5,/* 0x40-0x47 */ - 0x5E7D,0x60A0,0x6182,0x63D6,0x6709,0x67DA,0x6E67,0x6D8C,/* 0x48-0x4F */ - 0x7336,0x7337,0x7531,0x7950,0x88D5,0x8A98,0x904A,0x9091,/* 0x50-0x57 */ - 0x90F5,0x96C4,0x878D,0x5915,0x4E88,0x4F59,0x4E0E,0x8A89,/* 0x58-0x5F */ - 0x8F3F,0x9810,0x50AD,0x5E7C,0x5996,0x5BB9,0x5EB8,0x63DA,/* 0x60-0x67 */ - 0x63FA,0x64C1,0x66DC,0x694A,0x69D8,0x6D0B,0x6EB6,0x7194,/* 0x68-0x6F */ - 0x7528,0x7AAF,0x7F8A,0x8000,0x8449,0x84C9,0x8981,0x8B21,/* 0x70-0x77 */ - 0x8E0A,0x9065,0x967D,0x990A,0x617E,0x6291,0x6B32,0x0000,/* 0x78-0x7F */ - - 0x6C83,0x6D74,0x7FCC,0x7FFC,0x6DC0,0x7F85,0x87BA,0x88F8,/* 0x80-0x87 */ - 0x6765,0x83B1,0x983C,0x96F7,0x6D1B,0x7D61,0x843D,0x916A,/* 0x88-0x8F */ - 0x4E71,0x5375,0x5D50,0x6B04,0x6FEB,0x85CD,0x862D,0x89A7,/* 0x90-0x97 */ - 0x5229,0x540F,0x5C65,0x674E,0x68A8,0x7406,0x7483,0x75E2,/* 0x98-0x9F */ - 0x88CF,0x88E1,0x91CC,0x96E2,0x9678,0x5F8B,0x7387,0x7ACB,/* 0xA0-0xA7 */ - 0x844E,0x63A0,0x7565,0x5289,0x6D41,0x6E9C,0x7409,0x7559,/* 0xA8-0xAF */ - 0x786B,0x7C92,0x9686,0x7ADC,0x9F8D,0x4FB6,0x616E,0x65C5,/* 0xB0-0xB7 */ - 0x865C,0x4E86,0x4EAE,0x50DA,0x4E21,0x51CC,0x5BEE,0x6599,/* 0xB8-0xBF */ - 0x6881,0x6DBC,0x731F,0x7642,0x77AD,0x7A1C,0x7CE7,0x826F,/* 0xC0-0xC7 */ - 0x8AD2,0x907C,0x91CF,0x9675,0x9818,0x529B,0x7DD1,0x502B,/* 0xC8-0xCF */ - 0x5398,0x6797,0x6DCB,0x71D0,0x7433,0x81E8,0x8F2A,0x96A3,/* 0xD0-0xD7 */ - 0x9C57,0x9E9F,0x7460,0x5841,0x6D99,0x7D2F,0x985E,0x4EE4,/* 0xD8-0xDF */ - 0x4F36,0x4F8B,0x51B7,0x52B1,0x5DBA,0x601C,0x73B2,0x793C,/* 0xE0-0xE7 */ - 0x82D3,0x9234,0x96B7,0x96F6,0x970A,0x9E97,0x9F62,0x66A6,/* 0xE8-0xEF */ - 0x6B74,0x5217,0x52A3,0x70C8,0x88C2,0x5EC9,0x604B,0x6190,/* 0xF0-0xF7 */ - 0x6F23,0x7149,0x7C3E,0x7DF4,0x806F,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_98[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x84EE,0x9023,0x932C,0x5442,0x9B6F,0x6AD3,0x7089,0x8CC2,/* 0x40-0x47 */ - 0x8DEF,0x9732,0x52B4,0x5A41,0x5ECA,0x5F04,0x6717,0x697C,/* 0x48-0x4F */ - 0x6994,0x6D6A,0x6F0F,0x7262,0x72FC,0x7BED,0x8001,0x807E,/* 0x50-0x57 */ - 0x874B,0x90CE,0x516D,0x9E93,0x7984,0x808B,0x9332,0x8AD6,/* 0x58-0x5F */ - 0x502D,0x548C,0x8A71,0x6B6A,0x8CC4,0x8107,0x60D1,0x67A0,/* 0x60-0x67 */ - 0x9DF2,0x4E99,0x4E98,0x9C10,0x8A6B,0x85C1,0x8568,0x6900,/* 0x68-0x6F */ - 0x6E7E,0x7897,0x8155,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x5F0C,/* 0x98-0x9F */ - 0x4E10,0x4E15,0x4E2A,0x4E31,0x4E36,0x4E3C,0x4E3F,0x4E42,/* 0xA0-0xA7 */ - 0x4E56,0x4E58,0x4E82,0x4E85,0x8C6B,0x4E8A,0x8212,0x5F0D,/* 0xA8-0xAF */ - 0x4E8E,0x4E9E,0x4E9F,0x4EA0,0x4EA2,0x4EB0,0x4EB3,0x4EB6,/* 0xB0-0xB7 */ - 0x4ECE,0x4ECD,0x4EC4,0x4EC6,0x4EC2,0x4ED7,0x4EDE,0x4EED,/* 0xB8-0xBF */ - 0x4EDF,0x4EF7,0x4F09,0x4F5A,0x4F30,0x4F5B,0x4F5D,0x4F57,/* 0xC0-0xC7 */ - 0x4F47,0x4F76,0x4F88,0x4F8F,0x4F98,0x4F7B,0x4F69,0x4F70,/* 0xC8-0xCF */ - 0x4F91,0x4F6F,0x4F86,0x4F96,0x5118,0x4FD4,0x4FDF,0x4FCE,/* 0xD0-0xD7 */ - 0x4FD8,0x4FDB,0x4FD1,0x4FDA,0x4FD0,0x4FE4,0x4FE5,0x501A,/* 0xD8-0xDF */ - 0x5028,0x5014,0x502A,0x5025,0x5005,0x4F1C,0x4FF6,0x5021,/* 0xE0-0xE7 */ - 0x5029,0x502C,0x4FFE,0x4FEF,0x5011,0x5006,0x5043,0x5047,/* 0xE8-0xEF */ - 0x6703,0x5055,0x5050,0x5048,0x505A,0x5056,0x506C,0x5078,/* 0xF0-0xF7 */ - 0x5080,0x509A,0x5085,0x50B4,0x50B2,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_99[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x50C9,0x50CA,0x50B3,0x50C2,0x50D6,0x50DE,0x50E5,0x50ED,/* 0x40-0x47 */ - 0x50E3,0x50EE,0x50F9,0x50F5,0x5109,0x5101,0x5102,0x5116,/* 0x48-0x4F */ - 0x5115,0x5114,0x511A,0x5121,0x513A,0x5137,0x513C,0x513B,/* 0x50-0x57 */ - 0x513F,0x5140,0x5152,0x514C,0x5154,0x5162,0x7AF8,0x5169,/* 0x58-0x5F */ - 0x516A,0x516E,0x5180,0x5182,0x56D8,0x518C,0x5189,0x518F,/* 0x60-0x67 */ - 0x5191,0x5193,0x5195,0x5196,0x51A4,0x51A6,0x51A2,0x51A9,/* 0x68-0x6F */ - 0x51AA,0x51AB,0x51B3,0x51B1,0x51B2,0x51B0,0x51B5,0x51BD,/* 0x70-0x77 */ - 0x51C5,0x51C9,0x51DB,0x51E0,0x8655,0x51E9,0x51ED,0x0000,/* 0x78-0x7F */ - - 0x51F0,0x51F5,0x51FE,0x5204,0x520B,0x5214,0x520E,0x5227,/* 0x80-0x87 */ - 0x522A,0x522E,0x5233,0x5239,0x524F,0x5244,0x524B,0x524C,/* 0x88-0x8F */ - 0x525E,0x5254,0x526A,0x5274,0x5269,0x5273,0x527F,0x527D,/* 0x90-0x97 */ - 0x528D,0x5294,0x5292,0x5271,0x5288,0x5291,0x8FA8,0x8FA7,/* 0x98-0x9F */ - 0x52AC,0x52AD,0x52BC,0x52B5,0x52C1,0x52CD,0x52D7,0x52DE,/* 0xA0-0xA7 */ - 0x52E3,0x52E6,0x98ED,0x52E0,0x52F3,0x52F5,0x52F8,0x52F9,/* 0xA8-0xAF */ - 0x5306,0x5308,0x7538,0x530D,0x5310,0x530F,0x5315,0x531A,/* 0xB0-0xB7 */ - 0x5323,0x532F,0x5331,0x5333,0x5338,0x5340,0x5346,0x5345,/* 0xB8-0xBF */ - 0x4E17,0x5349,0x534D,0x51D6,0x535E,0x5369,0x536E,0x5918,/* 0xC0-0xC7 */ - 0x537B,0x5377,0x5382,0x5396,0x53A0,0x53A6,0x53A5,0x53AE,/* 0xC8-0xCF */ - 0x53B0,0x53B6,0x53C3,0x7C12,0x96D9,0x53DF,0x66FC,0x71EE,/* 0xD0-0xD7 */ - 0x53EE,0x53E8,0x53ED,0x53FA,0x5401,0x543D,0x5440,0x542C,/* 0xD8-0xDF */ - 0x542D,0x543C,0x542E,0x5436,0x5429,0x541D,0x544E,0x548F,/* 0xE0-0xE7 */ - 0x5475,0x548E,0x545F,0x5471,0x5477,0x5470,0x5492,0x547B,/* 0xE8-0xEF */ - 0x5480,0x5476,0x5484,0x5490,0x5486,0x54C7,0x54A2,0x54B8,/* 0xF0-0xF7 */ - 0x54A5,0x54AC,0x54C4,0x54C8,0x54A8,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_9A[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x54AB,0x54C2,0x54A4,0x54BE,0x54BC,0x54D8,0x54E5,0x54E6,/* 0x40-0x47 */ - 0x550F,0x5514,0x54FD,0x54EE,0x54ED,0x54FA,0x54E2,0x5539,/* 0x48-0x4F */ - 0x5540,0x5563,0x554C,0x552E,0x555C,0x5545,0x5556,0x5557,/* 0x50-0x57 */ - 0x5538,0x5533,0x555D,0x5599,0x5580,0x54AF,0x558A,0x559F,/* 0x58-0x5F */ - 0x557B,0x557E,0x5598,0x559E,0x55AE,0x557C,0x5583,0x55A9,/* 0x60-0x67 */ - 0x5587,0x55A8,0x55DA,0x55C5,0x55DF,0x55C4,0x55DC,0x55E4,/* 0x68-0x6F */ - 0x55D4,0x5614,0x55F7,0x5616,0x55FE,0x55FD,0x561B,0x55F9,/* 0x70-0x77 */ - 0x564E,0x5650,0x71DF,0x5634,0x5636,0x5632,0x5638,0x0000,/* 0x78-0x7F */ - - 0x566B,0x5664,0x562F,0x566C,0x566A,0x5686,0x5680,0x568A,/* 0x80-0x87 */ - 0x56A0,0x5694,0x568F,0x56A5,0x56AE,0x56B6,0x56B4,0x56C2,/* 0x88-0x8F */ - 0x56BC,0x56C1,0x56C3,0x56C0,0x56C8,0x56CE,0x56D1,0x56D3,/* 0x90-0x97 */ - 0x56D7,0x56EE,0x56F9,0x5700,0x56FF,0x5704,0x5709,0x5708,/* 0x98-0x9F */ - 0x570B,0x570D,0x5713,0x5718,0x5716,0x55C7,0x571C,0x5726,/* 0xA0-0xA7 */ - 0x5737,0x5738,0x574E,0x573B,0x5740,0x574F,0x5769,0x57C0,/* 0xA8-0xAF */ - 0x5788,0x5761,0x577F,0x5789,0x5793,0x57A0,0x57B3,0x57A4,/* 0xB0-0xB7 */ - 0x57AA,0x57B0,0x57C3,0x57C6,0x57D4,0x57D2,0x57D3,0x580A,/* 0xB8-0xBF */ - 0x57D6,0x57E3,0x580B,0x5819,0x581D,0x5872,0x5821,0x5862,/* 0xC0-0xC7 */ - 0x584B,0x5870,0x6BC0,0x5852,0x583D,0x5879,0x5885,0x58B9,/* 0xC8-0xCF */ - 0x589F,0x58AB,0x58BA,0x58DE,0x58BB,0x58B8,0x58AE,0x58C5,/* 0xD0-0xD7 */ - 0x58D3,0x58D1,0x58D7,0x58D9,0x58D8,0x58E5,0x58DC,0x58E4,/* 0xD8-0xDF */ - 0x58DF,0x58EF,0x58FA,0x58F9,0x58FB,0x58FC,0x58FD,0x5902,/* 0xE0-0xE7 */ - 0x590A,0x5910,0x591B,0x68A6,0x5925,0x592C,0x592D,0x5932,/* 0xE8-0xEF */ - 0x5938,0x593E,0x7AD2,0x5955,0x5950,0x594E,0x595A,0x5958,/* 0xF0-0xF7 */ - 0x5962,0x5960,0x5967,0x596C,0x5969,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_9B[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5978,0x5981,0x599D,0x4F5E,0x4FAB,0x59A3,0x59B2,0x59C6,/* 0x40-0x47 */ - 0x59E8,0x59DC,0x598D,0x59D9,0x59DA,0x5A25,0x5A1F,0x5A11,/* 0x48-0x4F */ - 0x5A1C,0x5A09,0x5A1A,0x5A40,0x5A6C,0x5A49,0x5A35,0x5A36,/* 0x50-0x57 */ - 0x5A62,0x5A6A,0x5A9A,0x5ABC,0x5ABE,0x5ACB,0x5AC2,0x5ABD,/* 0x58-0x5F */ - 0x5AE3,0x5AD7,0x5AE6,0x5AE9,0x5AD6,0x5AFA,0x5AFB,0x5B0C,/* 0x60-0x67 */ - 0x5B0B,0x5B16,0x5B32,0x5AD0,0x5B2A,0x5B36,0x5B3E,0x5B43,/* 0x68-0x6F */ - 0x5B45,0x5B40,0x5B51,0x5B55,0x5B5A,0x5B5B,0x5B65,0x5B69,/* 0x70-0x77 */ - 0x5B70,0x5B73,0x5B75,0x5B78,0x6588,0x5B7A,0x5B80,0x0000,/* 0x78-0x7F */ - - 0x5B83,0x5BA6,0x5BB8,0x5BC3,0x5BC7,0x5BC9,0x5BD4,0x5BD0,/* 0x80-0x87 */ - 0x5BE4,0x5BE6,0x5BE2,0x5BDE,0x5BE5,0x5BEB,0x5BF0,0x5BF6,/* 0x88-0x8F */ - 0x5BF3,0x5C05,0x5C07,0x5C08,0x5C0D,0x5C13,0x5C20,0x5C22,/* 0x90-0x97 */ - 0x5C28,0x5C38,0x5C39,0x5C41,0x5C46,0x5C4E,0x5C53,0x5C50,/* 0x98-0x9F */ - 0x5C4F,0x5B71,0x5C6C,0x5C6E,0x4E62,0x5C76,0x5C79,0x5C8C,/* 0xA0-0xA7 */ - 0x5C91,0x5C94,0x599B,0x5CAB,0x5CBB,0x5CB6,0x5CBC,0x5CB7,/* 0xA8-0xAF */ - 0x5CC5,0x5CBE,0x5CC7,0x5CD9,0x5CE9,0x5CFD,0x5CFA,0x5CED,/* 0xB0-0xB7 */ - 0x5D8C,0x5CEA,0x5D0B,0x5D15,0x5D17,0x5D5C,0x5D1F,0x5D1B,/* 0xB8-0xBF */ - 0x5D11,0x5D14,0x5D22,0x5D1A,0x5D19,0x5D18,0x5D4C,0x5D52,/* 0xC0-0xC7 */ - 0x5D4E,0x5D4B,0x5D6C,0x5D73,0x5D76,0x5D87,0x5D84,0x5D82,/* 0xC8-0xCF */ - 0x5DA2,0x5D9D,0x5DAC,0x5DAE,0x5DBD,0x5D90,0x5DB7,0x5DBC,/* 0xD0-0xD7 */ - 0x5DC9,0x5DCD,0x5DD3,0x5DD2,0x5DD6,0x5DDB,0x5DEB,0x5DF2,/* 0xD8-0xDF */ - 0x5DF5,0x5E0B,0x5E1A,0x5E19,0x5E11,0x5E1B,0x5E36,0x5E37,/* 0xE0-0xE7 */ - 0x5E44,0x5E43,0x5E40,0x5E4E,0x5E57,0x5E54,0x5E5F,0x5E62,/* 0xE8-0xEF */ - 0x5E64,0x5E47,0x5E75,0x5E76,0x5E7A,0x9EBC,0x5E7F,0x5EA0,/* 0xF0-0xF7 */ - 0x5EC1,0x5EC2,0x5EC8,0x5ED0,0x5ECF,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_9C[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5ED6,0x5EE3,0x5EDD,0x5EDA,0x5EDB,0x5EE2,0x5EE1,0x5EE8,/* 0x40-0x47 */ - 0x5EE9,0x5EEC,0x5EF1,0x5EF3,0x5EF0,0x5EF4,0x5EF8,0x5EFE,/* 0x48-0x4F */ - 0x5F03,0x5F09,0x5F5D,0x5F5C,0x5F0B,0x5F11,0x5F16,0x5F29,/* 0x50-0x57 */ - 0x5F2D,0x5F38,0x5F41,0x5F48,0x5F4C,0x5F4E,0x5F2F,0x5F51,/* 0x58-0x5F */ - 0x5F56,0x5F57,0x5F59,0x5F61,0x5F6D,0x5F73,0x5F77,0x5F83,/* 0x60-0x67 */ - 0x5F82,0x5F7F,0x5F8A,0x5F88,0x5F91,0x5F87,0x5F9E,0x5F99,/* 0x68-0x6F */ - 0x5F98,0x5FA0,0x5FA8,0x5FAD,0x5FBC,0x5FD6,0x5FFB,0x5FE4,/* 0x70-0x77 */ - 0x5FF8,0x5FF1,0x5FDD,0x60B3,0x5FFF,0x6021,0x6060,0x0000,/* 0x78-0x7F */ - - 0x6019,0x6010,0x6029,0x600E,0x6031,0x601B,0x6015,0x602B,/* 0x80-0x87 */ - 0x6026,0x600F,0x603A,0x605A,0x6041,0x606A,0x6077,0x605F,/* 0x88-0x8F */ - 0x604A,0x6046,0x604D,0x6063,0x6043,0x6064,0x6042,0x606C,/* 0x90-0x97 */ - 0x606B,0x6059,0x6081,0x608D,0x60E7,0x6083,0x609A,0x6084,/* 0x98-0x9F */ - 0x609B,0x6096,0x6097,0x6092,0x60A7,0x608B,0x60E1,0x60B8,/* 0xA0-0xA7 */ - 0x60E0,0x60D3,0x60B4,0x5FF0,0x60BD,0x60C6,0x60B5,0x60D8,/* 0xA8-0xAF */ - 0x614D,0x6115,0x6106,0x60F6,0x60F7,0x6100,0x60F4,0x60FA,/* 0xB0-0xB7 */ - 0x6103,0x6121,0x60FB,0x60F1,0x610D,0x610E,0x6147,0x613E,/* 0xB8-0xBF */ - 0x6128,0x6127,0x614A,0x613F,0x613C,0x612C,0x6134,0x613D,/* 0xC0-0xC7 */ - 0x6142,0x6144,0x6173,0x6177,0x6158,0x6159,0x615A,0x616B,/* 0xC8-0xCF */ - 0x6174,0x616F,0x6165,0x6171,0x615F,0x615D,0x6153,0x6175,/* 0xD0-0xD7 */ - 0x6199,0x6196,0x6187,0x61AC,0x6194,0x619A,0x618A,0x6191,/* 0xD8-0xDF */ - 0x61AB,0x61AE,0x61CC,0x61CA,0x61C9,0x61F7,0x61C8,0x61C3,/* 0xE0-0xE7 */ - 0x61C6,0x61BA,0x61CB,0x7F79,0x61CD,0x61E6,0x61E3,0x61F6,/* 0xE8-0xEF */ - 0x61FA,0x61F4,0x61FF,0x61FD,0x61FC,0x61FE,0x6200,0x6208,/* 0xF0-0xF7 */ - 0x6209,0x620D,0x620C,0x6214,0x621B,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_9D[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x621E,0x6221,0x622A,0x622E,0x6230,0x6232,0x6233,0x6241,/* 0x40-0x47 */ - 0x624E,0x625E,0x6263,0x625B,0x6260,0x6268,0x627C,0x6282,/* 0x48-0x4F */ - 0x6289,0x627E,0x6292,0x6293,0x6296,0x62D4,0x6283,0x6294,/* 0x50-0x57 */ - 0x62D7,0x62D1,0x62BB,0x62CF,0x62FF,0x62C6,0x64D4,0x62C8,/* 0x58-0x5F */ - 0x62DC,0x62CC,0x62CA,0x62C2,0x62C7,0x629B,0x62C9,0x630C,/* 0x60-0x67 */ - 0x62EE,0x62F1,0x6327,0x6302,0x6308,0x62EF,0x62F5,0x6350,/* 0x68-0x6F */ - 0x633E,0x634D,0x641C,0x634F,0x6396,0x638E,0x6380,0x63AB,/* 0x70-0x77 */ - 0x6376,0x63A3,0x638F,0x6389,0x639F,0x63B5,0x636B,0x0000,/* 0x78-0x7F */ - - 0x6369,0x63BE,0x63E9,0x63C0,0x63C6,0x63E3,0x63C9,0x63D2,/* 0x80-0x87 */ - 0x63F6,0x63C4,0x6416,0x6434,0x6406,0x6413,0x6426,0x6436,/* 0x88-0x8F */ - 0x651D,0x6417,0x6428,0x640F,0x6467,0x646F,0x6476,0x644E,/* 0x90-0x97 */ - 0x652A,0x6495,0x6493,0x64A5,0x64A9,0x6488,0x64BC,0x64DA,/* 0x98-0x9F */ - 0x64D2,0x64C5,0x64C7,0x64BB,0x64D8,0x64C2,0x64F1,0x64E7,/* 0xA0-0xA7 */ - 0x8209,0x64E0,0x64E1,0x62AC,0x64E3,0x64EF,0x652C,0x64F6,/* 0xA8-0xAF */ - 0x64F4,0x64F2,0x64FA,0x6500,0x64FD,0x6518,0x651C,0x6505,/* 0xB0-0xB7 */ - 0x6524,0x6523,0x652B,0x6534,0x6535,0x6537,0x6536,0x6538,/* 0xB8-0xBF */ - 0x754B,0x6548,0x6556,0x6555,0x654D,0x6558,0x655E,0x655D,/* 0xC0-0xC7 */ - 0x6572,0x6578,0x6582,0x6583,0x8B8A,0x659B,0x659F,0x65AB,/* 0xC8-0xCF */ - 0x65B7,0x65C3,0x65C6,0x65C1,0x65C4,0x65CC,0x65D2,0x65DB,/* 0xD0-0xD7 */ - 0x65D9,0x65E0,0x65E1,0x65F1,0x6772,0x660A,0x6603,0x65FB,/* 0xD8-0xDF */ - 0x6773,0x6635,0x6636,0x6634,0x661C,0x664F,0x6644,0x6649,/* 0xE0-0xE7 */ - 0x6641,0x665E,0x665D,0x6664,0x6667,0x6668,0x665F,0x6662,/* 0xE8-0xEF */ - 0x6670,0x6683,0x6688,0x668E,0x6689,0x6684,0x6698,0x669D,/* 0xF0-0xF7 */ - 0x66C1,0x66B9,0x66C9,0x66BE,0x66BC,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_9E[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x66C4,0x66B8,0x66D6,0x66DA,0x66E0,0x663F,0x66E6,0x66E9,/* 0x40-0x47 */ - 0x66F0,0x66F5,0x66F7,0x670F,0x6716,0x671E,0x6726,0x6727,/* 0x48-0x4F */ - 0x9738,0x672E,0x673F,0x6736,0x6741,0x6738,0x6737,0x6746,/* 0x50-0x57 */ - 0x675E,0x6760,0x6759,0x6763,0x6764,0x6789,0x6770,0x67A9,/* 0x58-0x5F */ - 0x677C,0x676A,0x678C,0x678B,0x67A6,0x67A1,0x6785,0x67B7,/* 0x60-0x67 */ - 0x67EF,0x67B4,0x67EC,0x67B3,0x67E9,0x67B8,0x67E4,0x67DE,/* 0x68-0x6F */ - 0x67DD,0x67E2,0x67EE,0x67B9,0x67CE,0x67C6,0x67E7,0x6A9C,/* 0x70-0x77 */ - 0x681E,0x6846,0x6829,0x6840,0x684D,0x6832,0x684E,0x0000,/* 0x78-0x7F */ - - 0x68B3,0x682B,0x6859,0x6863,0x6877,0x687F,0x689F,0x688F,/* 0x80-0x87 */ - 0x68AD,0x6894,0x689D,0x689B,0x6883,0x6AAE,0x68B9,0x6874,/* 0x88-0x8F */ - 0x68B5,0x68A0,0x68BA,0x690F,0x688D,0x687E,0x6901,0x68CA,/* 0x90-0x97 */ - 0x6908,0x68D8,0x6922,0x6926,0x68E1,0x690C,0x68CD,0x68D4,/* 0x98-0x9F */ - 0x68E7,0x68D5,0x6936,0x6912,0x6904,0x68D7,0x68E3,0x6925,/* 0xA0-0xA7 */ - 0x68F9,0x68E0,0x68EF,0x6928,0x692A,0x691A,0x6923,0x6921,/* 0xA8-0xAF */ - 0x68C6,0x6979,0x6977,0x695C,0x6978,0x696B,0x6954,0x697E,/* 0xB0-0xB7 */ - 0x696E,0x6939,0x6974,0x693D,0x6959,0x6930,0x6961,0x695E,/* 0xB8-0xBF */ - 0x695D,0x6981,0x696A,0x69B2,0x69AE,0x69D0,0x69BF,0x69C1,/* 0xC0-0xC7 */ - 0x69D3,0x69BE,0x69CE,0x5BE8,0x69CA,0x69DD,0x69BB,0x69C3,/* 0xC8-0xCF */ - 0x69A7,0x6A2E,0x6991,0x69A0,0x699C,0x6995,0x69B4,0x69DE,/* 0xD0-0xD7 */ - 0x69E8,0x6A02,0x6A1B,0x69FF,0x6B0A,0x69F9,0x69F2,0x69E7,/* 0xD8-0xDF */ - 0x6A05,0x69B1,0x6A1E,0x69ED,0x6A14,0x69EB,0x6A0A,0x6A12,/* 0xE0-0xE7 */ - 0x6AC1,0x6A23,0x6A13,0x6A44,0x6A0C,0x6A72,0x6A36,0x6A78,/* 0xE8-0xEF */ - 0x6A47,0x6A62,0x6A59,0x6A66,0x6A48,0x6A38,0x6A22,0x6A90,/* 0xF0-0xF7 */ - 0x6A8D,0x6AA0,0x6A84,0x6AA2,0x6AA3,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_9F[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6A97,0x8617,0x6ABB,0x6AC3,0x6AC2,0x6AB8,0x6AB3,0x6AAC,/* 0x40-0x47 */ - 0x6ADE,0x6AD1,0x6ADF,0x6AAA,0x6ADA,0x6AEA,0x6AFB,0x6B05,/* 0x48-0x4F */ - 0x8616,0x6AFA,0x6B12,0x6B16,0x9B31,0x6B1F,0x6B38,0x6B37,/* 0x50-0x57 */ - 0x76DC,0x6B39,0x98EE,0x6B47,0x6B43,0x6B49,0x6B50,0x6B59,/* 0x58-0x5F */ - 0x6B54,0x6B5B,0x6B5F,0x6B61,0x6B78,0x6B79,0x6B7F,0x6B80,/* 0x60-0x67 */ - 0x6B84,0x6B83,0x6B8D,0x6B98,0x6B95,0x6B9E,0x6BA4,0x6BAA,/* 0x68-0x6F */ - 0x6BAB,0x6BAF,0x6BB2,0x6BB1,0x6BB3,0x6BB7,0x6BBC,0x6BC6,/* 0x70-0x77 */ - 0x6BCB,0x6BD3,0x6BDF,0x6BEC,0x6BEB,0x6BF3,0x6BEF,0x0000,/* 0x78-0x7F */ - - 0x9EBE,0x6C08,0x6C13,0x6C14,0x6C1B,0x6C24,0x6C23,0x6C5E,/* 0x80-0x87 */ - 0x6C55,0x6C62,0x6C6A,0x6C82,0x6C8D,0x6C9A,0x6C81,0x6C9B,/* 0x88-0x8F */ - 0x6C7E,0x6C68,0x6C73,0x6C92,0x6C90,0x6CC4,0x6CF1,0x6CD3,/* 0x90-0x97 */ - 0x6CBD,0x6CD7,0x6CC5,0x6CDD,0x6CAE,0x6CB1,0x6CBE,0x6CBA,/* 0x98-0x9F */ - 0x6CDB,0x6CEF,0x6CD9,0x6CEA,0x6D1F,0x884D,0x6D36,0x6D2B,/* 0xA0-0xA7 */ - 0x6D3D,0x6D38,0x6D19,0x6D35,0x6D33,0x6D12,0x6D0C,0x6D63,/* 0xA8-0xAF */ - 0x6D93,0x6D64,0x6D5A,0x6D79,0x6D59,0x6D8E,0x6D95,0x6FE4,/* 0xB0-0xB7 */ - 0x6D85,0x6DF9,0x6E15,0x6E0A,0x6DB5,0x6DC7,0x6DE6,0x6DB8,/* 0xB8-0xBF */ - 0x6DC6,0x6DEC,0x6DDE,0x6DCC,0x6DE8,0x6DD2,0x6DC5,0x6DFA,/* 0xC0-0xC7 */ - 0x6DD9,0x6DE4,0x6DD5,0x6DEA,0x6DEE,0x6E2D,0x6E6E,0x6E2E,/* 0xC8-0xCF */ - 0x6E19,0x6E72,0x6E5F,0x6E3E,0x6E23,0x6E6B,0x6E2B,0x6E76,/* 0xD0-0xD7 */ - 0x6E4D,0x6E1F,0x6E43,0x6E3A,0x6E4E,0x6E24,0x6EFF,0x6E1D,/* 0xD8-0xDF */ - 0x6E38,0x6E82,0x6EAA,0x6E98,0x6EC9,0x6EB7,0x6ED3,0x6EBD,/* 0xE0-0xE7 */ - 0x6EAF,0x6EC4,0x6EB2,0x6ED4,0x6ED5,0x6E8F,0x6EA5,0x6EC2,/* 0xE8-0xEF */ - 0x6E9F,0x6F41,0x6F11,0x704C,0x6EEC,0x6EF8,0x6EFE,0x6F3F,/* 0xF0-0xF7 */ - 0x6EF2,0x6F31,0x6EEF,0x6F32,0x6ECC,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E0[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6F3E,0x6F13,0x6EF7,0x6F86,0x6F7A,0x6F78,0x6F81,0x6F80,/* 0x40-0x47 */ - 0x6F6F,0x6F5B,0x6FF3,0x6F6D,0x6F82,0x6F7C,0x6F58,0x6F8E,/* 0x48-0x4F */ - 0x6F91,0x6FC2,0x6F66,0x6FB3,0x6FA3,0x6FA1,0x6FA4,0x6FB9,/* 0x50-0x57 */ - 0x6FC6,0x6FAA,0x6FDF,0x6FD5,0x6FEC,0x6FD4,0x6FD8,0x6FF1,/* 0x58-0x5F */ - 0x6FEE,0x6FDB,0x7009,0x700B,0x6FFA,0x7011,0x7001,0x700F,/* 0x60-0x67 */ - 0x6FFE,0x701B,0x701A,0x6F74,0x701D,0x7018,0x701F,0x7030,/* 0x68-0x6F */ - 0x703E,0x7032,0x7051,0x7063,0x7099,0x7092,0x70AF,0x70F1,/* 0x70-0x77 */ - 0x70AC,0x70B8,0x70B3,0x70AE,0x70DF,0x70CB,0x70DD,0x0000,/* 0x78-0x7F */ - - 0x70D9,0x7109,0x70FD,0x711C,0x7119,0x7165,0x7155,0x7188,/* 0x80-0x87 */ - 0x7166,0x7162,0x714C,0x7156,0x716C,0x718F,0x71FB,0x7184,/* 0x88-0x8F */ - 0x7195,0x71A8,0x71AC,0x71D7,0x71B9,0x71BE,0x71D2,0x71C9,/* 0x90-0x97 */ - 0x71D4,0x71CE,0x71E0,0x71EC,0x71E7,0x71F5,0x71FC,0x71F9,/* 0x98-0x9F */ - 0x71FF,0x720D,0x7210,0x721B,0x7228,0x722D,0x722C,0x7230,/* 0xA0-0xA7 */ - 0x7232,0x723B,0x723C,0x723F,0x7240,0x7246,0x724B,0x7258,/* 0xA8-0xAF */ - 0x7274,0x727E,0x7282,0x7281,0x7287,0x7292,0x7296,0x72A2,/* 0xB0-0xB7 */ - 0x72A7,0x72B9,0x72B2,0x72C3,0x72C6,0x72C4,0x72CE,0x72D2,/* 0xB8-0xBF */ - 0x72E2,0x72E0,0x72E1,0x72F9,0x72F7,0x500F,0x7317,0x730A,/* 0xC0-0xC7 */ - 0x731C,0x7316,0x731D,0x7334,0x732F,0x7329,0x7325,0x733E,/* 0xC8-0xCF */ - 0x734E,0x734F,0x9ED8,0x7357,0x736A,0x7368,0x7370,0x7378,/* 0xD0-0xD7 */ - 0x7375,0x737B,0x737A,0x73C8,0x73B3,0x73CE,0x73BB,0x73C0,/* 0xD8-0xDF */ - 0x73E5,0x73EE,0x73DE,0x74A2,0x7405,0x746F,0x7425,0x73F8,/* 0xE0-0xE7 */ - 0x7432,0x743A,0x7455,0x743F,0x745F,0x7459,0x7441,0x745C,/* 0xE8-0xEF */ - 0x7469,0x7470,0x7463,0x746A,0x7476,0x747E,0x748B,0x749E,/* 0xF0-0xF7 */ - 0x74A7,0x74CA,0x74CF,0x74D4,0x73F1,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x74E0,0x74E3,0x74E7,0x74E9,0x74EE,0x74F2,0x74F0,0x74F1,/* 0x40-0x47 */ - 0x74F8,0x74F7,0x7504,0x7503,0x7505,0x750C,0x750E,0x750D,/* 0x48-0x4F */ - 0x7515,0x7513,0x751E,0x7526,0x752C,0x753C,0x7544,0x754D,/* 0x50-0x57 */ - 0x754A,0x7549,0x755B,0x7546,0x755A,0x7569,0x7564,0x7567,/* 0x58-0x5F */ - 0x756B,0x756D,0x7578,0x7576,0x7586,0x7587,0x7574,0x758A,/* 0x60-0x67 */ - 0x7589,0x7582,0x7594,0x759A,0x759D,0x75A5,0x75A3,0x75C2,/* 0x68-0x6F */ - 0x75B3,0x75C3,0x75B5,0x75BD,0x75B8,0x75BC,0x75B1,0x75CD,/* 0x70-0x77 */ - 0x75CA,0x75D2,0x75D9,0x75E3,0x75DE,0x75FE,0x75FF,0x0000,/* 0x78-0x7F */ - - 0x75FC,0x7601,0x75F0,0x75FA,0x75F2,0x75F3,0x760B,0x760D,/* 0x80-0x87 */ - 0x7609,0x761F,0x7627,0x7620,0x7621,0x7622,0x7624,0x7634,/* 0x88-0x8F */ - 0x7630,0x763B,0x7647,0x7648,0x7646,0x765C,0x7658,0x7661,/* 0x90-0x97 */ - 0x7662,0x7668,0x7669,0x766A,0x7667,0x766C,0x7670,0x7672,/* 0x98-0x9F */ - 0x7676,0x7678,0x767C,0x7680,0x7683,0x7688,0x768B,0x768E,/* 0xA0-0xA7 */ - 0x7696,0x7693,0x7699,0x769A,0x76B0,0x76B4,0x76B8,0x76B9,/* 0xA8-0xAF */ - 0x76BA,0x76C2,0x76CD,0x76D6,0x76D2,0x76DE,0x76E1,0x76E5,/* 0xB0-0xB7 */ - 0x76E7,0x76EA,0x862F,0x76FB,0x7708,0x7707,0x7704,0x7729,/* 0xB8-0xBF */ - 0x7724,0x771E,0x7725,0x7726,0x771B,0x7737,0x7738,0x7747,/* 0xC0-0xC7 */ - 0x775A,0x7768,0x776B,0x775B,0x7765,0x777F,0x777E,0x7779,/* 0xC8-0xCF */ - 0x778E,0x778B,0x7791,0x77A0,0x779E,0x77B0,0x77B6,0x77B9,/* 0xD0-0xD7 */ - 0x77BF,0x77BC,0x77BD,0x77BB,0x77C7,0x77CD,0x77D7,0x77DA,/* 0xD8-0xDF */ - 0x77DC,0x77E3,0x77EE,0x77FC,0x780C,0x7812,0x7926,0x7820,/* 0xE0-0xE7 */ - 0x792A,0x7845,0x788E,0x7874,0x7886,0x787C,0x789A,0x788C,/* 0xE8-0xEF */ - 0x78A3,0x78B5,0x78AA,0x78AF,0x78D1,0x78C6,0x78CB,0x78D4,/* 0xF0-0xF7 */ - 0x78BE,0x78BC,0x78C5,0x78CA,0x78EC,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x78E7,0x78DA,0x78FD,0x78F4,0x7907,0x7912,0x7911,0x7919,/* 0x40-0x47 */ - 0x792C,0x792B,0x7940,0x7960,0x7957,0x795F,0x795A,0x7955,/* 0x48-0x4F */ - 0x7953,0x797A,0x797F,0x798A,0x799D,0x79A7,0x9F4B,0x79AA,/* 0x50-0x57 */ - 0x79AE,0x79B3,0x79B9,0x79BA,0x79C9,0x79D5,0x79E7,0x79EC,/* 0x58-0x5F */ - 0x79E1,0x79E3,0x7A08,0x7A0D,0x7A18,0x7A19,0x7A20,0x7A1F,/* 0x60-0x67 */ - 0x7980,0x7A31,0x7A3B,0x7A3E,0x7A37,0x7A43,0x7A57,0x7A49,/* 0x68-0x6F */ - 0x7A61,0x7A62,0x7A69,0x9F9D,0x7A70,0x7A79,0x7A7D,0x7A88,/* 0x70-0x77 */ - 0x7A97,0x7A95,0x7A98,0x7A96,0x7AA9,0x7AC8,0x7AB0,0x0000,/* 0x78-0x7F */ - - 0x7AB6,0x7AC5,0x7AC4,0x7ABF,0x9083,0x7AC7,0x7ACA,0x7ACD,/* 0x80-0x87 */ - 0x7ACF,0x7AD5,0x7AD3,0x7AD9,0x7ADA,0x7ADD,0x7AE1,0x7AE2,/* 0x88-0x8F */ - 0x7AE6,0x7AED,0x7AF0,0x7B02,0x7B0F,0x7B0A,0x7B06,0x7B33,/* 0x90-0x97 */ - 0x7B18,0x7B19,0x7B1E,0x7B35,0x7B28,0x7B36,0x7B50,0x7B7A,/* 0x98-0x9F */ - 0x7B04,0x7B4D,0x7B0B,0x7B4C,0x7B45,0x7B75,0x7B65,0x7B74,/* 0xA0-0xA7 */ - 0x7B67,0x7B70,0x7B71,0x7B6C,0x7B6E,0x7B9D,0x7B98,0x7B9F,/* 0xA8-0xAF */ - 0x7B8D,0x7B9C,0x7B9A,0x7B8B,0x7B92,0x7B8F,0x7B5D,0x7B99,/* 0xB0-0xB7 */ - 0x7BCB,0x7BC1,0x7BCC,0x7BCF,0x7BB4,0x7BC6,0x7BDD,0x7BE9,/* 0xB8-0xBF */ - 0x7C11,0x7C14,0x7BE6,0x7BE5,0x7C60,0x7C00,0x7C07,0x7C13,/* 0xC0-0xC7 */ - 0x7BF3,0x7BF7,0x7C17,0x7C0D,0x7BF6,0x7C23,0x7C27,0x7C2A,/* 0xC8-0xCF */ - 0x7C1F,0x7C37,0x7C2B,0x7C3D,0x7C4C,0x7C43,0x7C54,0x7C4F,/* 0xD0-0xD7 */ - 0x7C40,0x7C50,0x7C58,0x7C5F,0x7C64,0x7C56,0x7C65,0x7C6C,/* 0xD8-0xDF */ - 0x7C75,0x7C83,0x7C90,0x7CA4,0x7CAD,0x7CA2,0x7CAB,0x7CA1,/* 0xE0-0xE7 */ - 0x7CA8,0x7CB3,0x7CB2,0x7CB1,0x7CAE,0x7CB9,0x7CBD,0x7CC0,/* 0xE8-0xEF */ - 0x7CC5,0x7CC2,0x7CD8,0x7CD2,0x7CDC,0x7CE2,0x9B3B,0x7CEF,/* 0xF0-0xF7 */ - 0x7CF2,0x7CF4,0x7CF6,0x7CFA,0x7D06,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7D02,0x7D1C,0x7D15,0x7D0A,0x7D45,0x7D4B,0x7D2E,0x7D32,/* 0x40-0x47 */ - 0x7D3F,0x7D35,0x7D46,0x7D73,0x7D56,0x7D4E,0x7D72,0x7D68,/* 0x48-0x4F */ - 0x7D6E,0x7D4F,0x7D63,0x7D93,0x7D89,0x7D5B,0x7D8F,0x7D7D,/* 0x50-0x57 */ - 0x7D9B,0x7DBA,0x7DAE,0x7DA3,0x7DB5,0x7DC7,0x7DBD,0x7DAB,/* 0x58-0x5F */ - 0x7E3D,0x7DA2,0x7DAF,0x7DDC,0x7DB8,0x7D9F,0x7DB0,0x7DD8,/* 0x60-0x67 */ - 0x7DDD,0x7DE4,0x7DDE,0x7DFB,0x7DF2,0x7DE1,0x7E05,0x7E0A,/* 0x68-0x6F */ - 0x7E23,0x7E21,0x7E12,0x7E31,0x7E1F,0x7E09,0x7E0B,0x7E22,/* 0x70-0x77 */ - 0x7E46,0x7E66,0x7E3B,0x7E35,0x7E39,0x7E43,0x7E37,0x0000,/* 0x78-0x7F */ - - 0x7E32,0x7E3A,0x7E67,0x7E5D,0x7E56,0x7E5E,0x7E59,0x7E5A,/* 0x80-0x87 */ - 0x7E79,0x7E6A,0x7E69,0x7E7C,0x7E7B,0x7E83,0x7DD5,0x7E7D,/* 0x88-0x8F */ - 0x8FAE,0x7E7F,0x7E88,0x7E89,0x7E8C,0x7E92,0x7E90,0x7E93,/* 0x90-0x97 */ - 0x7E94,0x7E96,0x7E8E,0x7E9B,0x7E9C,0x7F38,0x7F3A,0x7F45,/* 0x98-0x9F */ - 0x7F4C,0x7F4D,0x7F4E,0x7F50,0x7F51,0x7F55,0x7F54,0x7F58,/* 0xA0-0xA7 */ - 0x7F5F,0x7F60,0x7F68,0x7F69,0x7F67,0x7F78,0x7F82,0x7F86,/* 0xA8-0xAF */ - 0x7F83,0x7F88,0x7F87,0x7F8C,0x7F94,0x7F9E,0x7F9D,0x7F9A,/* 0xB0-0xB7 */ - 0x7FA3,0x7FAF,0x7FB2,0x7FB9,0x7FAE,0x7FB6,0x7FB8,0x8B71,/* 0xB8-0xBF */ - 0x7FC5,0x7FC6,0x7FCA,0x7FD5,0x7FD4,0x7FE1,0x7FE6,0x7FE9,/* 0xC0-0xC7 */ - 0x7FF3,0x7FF9,0x98DC,0x8006,0x8004,0x800B,0x8012,0x8018,/* 0xC8-0xCF */ - 0x8019,0x801C,0x8021,0x8028,0x803F,0x803B,0x804A,0x8046,/* 0xD0-0xD7 */ - 0x8052,0x8058,0x805A,0x805F,0x8062,0x8068,0x8073,0x8072,/* 0xD8-0xDF */ - 0x8070,0x8076,0x8079,0x807D,0x807F,0x8084,0x8086,0x8085,/* 0xE0-0xE7 */ - 0x809B,0x8093,0x809A,0x80AD,0x5190,0x80AC,0x80DB,0x80E5,/* 0xE8-0xEF */ - 0x80D9,0x80DD,0x80C4,0x80DA,0x80D6,0x8109,0x80EF,0x80F1,/* 0xF0-0xF7 */ - 0x811B,0x8129,0x8123,0x812F,0x814B,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x968B,0x8146,0x813E,0x8153,0x8151,0x80FC,0x8171,0x816E,/* 0x40-0x47 */ - 0x8165,0x8166,0x8174,0x8183,0x8188,0x818A,0x8180,0x8182,/* 0x48-0x4F */ - 0x81A0,0x8195,0x81A4,0x81A3,0x815F,0x8193,0x81A9,0x81B0,/* 0x50-0x57 */ - 0x81B5,0x81BE,0x81B8,0x81BD,0x81C0,0x81C2,0x81BA,0x81C9,/* 0x58-0x5F */ - 0x81CD,0x81D1,0x81D9,0x81D8,0x81C8,0x81DA,0x81DF,0x81E0,/* 0x60-0x67 */ - 0x81E7,0x81FA,0x81FB,0x81FE,0x8201,0x8202,0x8205,0x8207,/* 0x68-0x6F */ - 0x820A,0x820D,0x8210,0x8216,0x8229,0x822B,0x8238,0x8233,/* 0x70-0x77 */ - 0x8240,0x8259,0x8258,0x825D,0x825A,0x825F,0x8264,0x0000,/* 0x78-0x7F */ - - 0x8262,0x8268,0x826A,0x826B,0x822E,0x8271,0x8277,0x8278,/* 0x80-0x87 */ - 0x827E,0x828D,0x8292,0x82AB,0x829F,0x82BB,0x82AC,0x82E1,/* 0x88-0x8F */ - 0x82E3,0x82DF,0x82D2,0x82F4,0x82F3,0x82FA,0x8393,0x8303,/* 0x90-0x97 */ - 0x82FB,0x82F9,0x82DE,0x8306,0x82DC,0x8309,0x82D9,0x8335,/* 0x98-0x9F */ - 0x8334,0x8316,0x8332,0x8331,0x8340,0x8339,0x8350,0x8345,/* 0xA0-0xA7 */ - 0x832F,0x832B,0x8317,0x8318,0x8385,0x839A,0x83AA,0x839F,/* 0xA8-0xAF */ - 0x83A2,0x8396,0x8323,0x838E,0x8387,0x838A,0x837C,0x83B5,/* 0xB0-0xB7 */ - 0x8373,0x8375,0x83A0,0x8389,0x83A8,0x83F4,0x8413,0x83EB,/* 0xB8-0xBF */ - 0x83CE,0x83FD,0x8403,0x83D8,0x840B,0x83C1,0x83F7,0x8407,/* 0xC0-0xC7 */ - 0x83E0,0x83F2,0x840D,0x8422,0x8420,0x83BD,0x8438,0x8506,/* 0xC8-0xCF */ - 0x83FB,0x846D,0x842A,0x843C,0x855A,0x8484,0x8477,0x846B,/* 0xD0-0xD7 */ - 0x84AD,0x846E,0x8482,0x8469,0x8446,0x842C,0x846F,0x8479,/* 0xD8-0xDF */ - 0x8435,0x84CA,0x8462,0x84B9,0x84BF,0x849F,0x84D9,0x84CD,/* 0xE0-0xE7 */ - 0x84BB,0x84DA,0x84D0,0x84C1,0x84C6,0x84D6,0x84A1,0x8521,/* 0xE8-0xEF */ - 0x84FF,0x84F4,0x8517,0x8518,0x852C,0x851F,0x8515,0x8514,/* 0xF0-0xF7 */ - 0x84FC,0x8540,0x8563,0x8558,0x8548,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8541,0x8602,0x854B,0x8555,0x8580,0x85A4,0x8588,0x8591,/* 0x40-0x47 */ - 0x858A,0x85A8,0x856D,0x8594,0x859B,0x85EA,0x8587,0x859C,/* 0x48-0x4F */ - 0x8577,0x857E,0x8590,0x85C9,0x85BA,0x85CF,0x85B9,0x85D0,/* 0x50-0x57 */ - 0x85D5,0x85DD,0x85E5,0x85DC,0x85F9,0x860A,0x8613,0x860B,/* 0x58-0x5F */ - 0x85FE,0x85FA,0x8606,0x8622,0x861A,0x8630,0x863F,0x864D,/* 0x60-0x67 */ - 0x4E55,0x8654,0x865F,0x8667,0x8671,0x8693,0x86A3,0x86A9,/* 0x68-0x6F */ - 0x86AA,0x868B,0x868C,0x86B6,0x86AF,0x86C4,0x86C6,0x86B0,/* 0x70-0x77 */ - 0x86C9,0x8823,0x86AB,0x86D4,0x86DE,0x86E9,0x86EC,0x0000,/* 0x78-0x7F */ - - 0x86DF,0x86DB,0x86EF,0x8712,0x8706,0x8708,0x8700,0x8703,/* 0x80-0x87 */ - 0x86FB,0x8711,0x8709,0x870D,0x86F9,0x870A,0x8734,0x873F,/* 0x88-0x8F */ - 0x8737,0x873B,0x8725,0x8729,0x871A,0x8760,0x875F,0x8778,/* 0x90-0x97 */ - 0x874C,0x874E,0x8774,0x8757,0x8768,0x876E,0x8759,0x8753,/* 0x98-0x9F */ - 0x8763,0x876A,0x8805,0x87A2,0x879F,0x8782,0x87AF,0x87CB,/* 0xA0-0xA7 */ - 0x87BD,0x87C0,0x87D0,0x96D6,0x87AB,0x87C4,0x87B3,0x87C7,/* 0xA8-0xAF */ - 0x87C6,0x87BB,0x87EF,0x87F2,0x87E0,0x880F,0x880D,0x87FE,/* 0xB0-0xB7 */ - 0x87F6,0x87F7,0x880E,0x87D2,0x8811,0x8816,0x8815,0x8822,/* 0xB8-0xBF */ - 0x8821,0x8831,0x8836,0x8839,0x8827,0x883B,0x8844,0x8842,/* 0xC0-0xC7 */ - 0x8852,0x8859,0x885E,0x8862,0x886B,0x8881,0x887E,0x889E,/* 0xC8-0xCF */ - 0x8875,0x887D,0x88B5,0x8872,0x8882,0x8897,0x8892,0x88AE,/* 0xD0-0xD7 */ - 0x8899,0x88A2,0x888D,0x88A4,0x88B0,0x88BF,0x88B1,0x88C3,/* 0xD8-0xDF */ - 0x88C4,0x88D4,0x88D8,0x88D9,0x88DD,0x88F9,0x8902,0x88FC,/* 0xE0-0xE7 */ - 0x88F4,0x88E8,0x88F2,0x8904,0x890C,0x890A,0x8913,0x8943,/* 0xE8-0xEF */ - 0x891E,0x8925,0x892A,0x892B,0x8941,0x8944,0x893B,0x8936,/* 0xF0-0xF7 */ - 0x8938,0x894C,0x891D,0x8960,0x895E,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8966,0x8964,0x896D,0x896A,0x896F,0x8974,0x8977,0x897E,/* 0x40-0x47 */ - 0x8983,0x8988,0x898A,0x8993,0x8998,0x89A1,0x89A9,0x89A6,/* 0x48-0x4F */ - 0x89AC,0x89AF,0x89B2,0x89BA,0x89BD,0x89BF,0x89C0,0x89DA,/* 0x50-0x57 */ - 0x89DC,0x89DD,0x89E7,0x89F4,0x89F8,0x8A03,0x8A16,0x8A10,/* 0x58-0x5F */ - 0x8A0C,0x8A1B,0x8A1D,0x8A25,0x8A36,0x8A41,0x8A5B,0x8A52,/* 0x60-0x67 */ - 0x8A46,0x8A48,0x8A7C,0x8A6D,0x8A6C,0x8A62,0x8A85,0x8A82,/* 0x68-0x6F */ - 0x8A84,0x8AA8,0x8AA1,0x8A91,0x8AA5,0x8AA6,0x8A9A,0x8AA3,/* 0x70-0x77 */ - 0x8AC4,0x8ACD,0x8AC2,0x8ADA,0x8AEB,0x8AF3,0x8AE7,0x0000,/* 0x78-0x7F */ - - 0x8AE4,0x8AF1,0x8B14,0x8AE0,0x8AE2,0x8AF7,0x8ADE,0x8ADB,/* 0x80-0x87 */ - 0x8B0C,0x8B07,0x8B1A,0x8AE1,0x8B16,0x8B10,0x8B17,0x8B20,/* 0x88-0x8F */ - 0x8B33,0x97AB,0x8B26,0x8B2B,0x8B3E,0x8B28,0x8B41,0x8B4C,/* 0x90-0x97 */ - 0x8B4F,0x8B4E,0x8B49,0x8B56,0x8B5B,0x8B5A,0x8B6B,0x8B5F,/* 0x98-0x9F */ - 0x8B6C,0x8B6F,0x8B74,0x8B7D,0x8B80,0x8B8C,0x8B8E,0x8B92,/* 0xA0-0xA7 */ - 0x8B93,0x8B96,0x8B99,0x8B9A,0x8C3A,0x8C41,0x8C3F,0x8C48,/* 0xA8-0xAF */ - 0x8C4C,0x8C4E,0x8C50,0x8C55,0x8C62,0x8C6C,0x8C78,0x8C7A,/* 0xB0-0xB7 */ - 0x8C82,0x8C89,0x8C85,0x8C8A,0x8C8D,0x8C8E,0x8C94,0x8C7C,/* 0xB8-0xBF */ - 0x8C98,0x621D,0x8CAD,0x8CAA,0x8CBD,0x8CB2,0x8CB3,0x8CAE,/* 0xC0-0xC7 */ - 0x8CB6,0x8CC8,0x8CC1,0x8CE4,0x8CE3,0x8CDA,0x8CFD,0x8CFA,/* 0xC8-0xCF */ - 0x8CFB,0x8D04,0x8D05,0x8D0A,0x8D07,0x8D0F,0x8D0D,0x8D10,/* 0xD0-0xD7 */ - 0x9F4E,0x8D13,0x8CCD,0x8D14,0x8D16,0x8D67,0x8D6D,0x8D71,/* 0xD8-0xDF */ - 0x8D73,0x8D81,0x8D99,0x8DC2,0x8DBE,0x8DBA,0x8DCF,0x8DDA,/* 0xE0-0xE7 */ - 0x8DD6,0x8DCC,0x8DDB,0x8DCB,0x8DEA,0x8DEB,0x8DDF,0x8DE3,/* 0xE8-0xEF */ - 0x8DFC,0x8E08,0x8E09,0x8DFF,0x8E1D,0x8E1E,0x8E10,0x8E1F,/* 0xF0-0xF7 */ - 0x8E42,0x8E35,0x8E30,0x8E34,0x8E4A,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E7[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8E47,0x8E49,0x8E4C,0x8E50,0x8E48,0x8E59,0x8E64,0x8E60,/* 0x40-0x47 */ - 0x8E2A,0x8E63,0x8E55,0x8E76,0x8E72,0x8E7C,0x8E81,0x8E87,/* 0x48-0x4F */ - 0x8E85,0x8E84,0x8E8B,0x8E8A,0x8E93,0x8E91,0x8E94,0x8E99,/* 0x50-0x57 */ - 0x8EAA,0x8EA1,0x8EAC,0x8EB0,0x8EC6,0x8EB1,0x8EBE,0x8EC5,/* 0x58-0x5F */ - 0x8EC8,0x8ECB,0x8EDB,0x8EE3,0x8EFC,0x8EFB,0x8EEB,0x8EFE,/* 0x60-0x67 */ - 0x8F0A,0x8F05,0x8F15,0x8F12,0x8F19,0x8F13,0x8F1C,0x8F1F,/* 0x68-0x6F */ - 0x8F1B,0x8F0C,0x8F26,0x8F33,0x8F3B,0x8F39,0x8F45,0x8F42,/* 0x70-0x77 */ - 0x8F3E,0x8F4C,0x8F49,0x8F46,0x8F4E,0x8F57,0x8F5C,0x0000,/* 0x78-0x7F */ - - 0x8F62,0x8F63,0x8F64,0x8F9C,0x8F9F,0x8FA3,0x8FAD,0x8FAF,/* 0x80-0x87 */ - 0x8FB7,0x8FDA,0x8FE5,0x8FE2,0x8FEA,0x8FEF,0x9087,0x8FF4,/* 0x88-0x8F */ - 0x9005,0x8FF9,0x8FFA,0x9011,0x9015,0x9021,0x900D,0x901E,/* 0x90-0x97 */ - 0x9016,0x900B,0x9027,0x9036,0x9035,0x9039,0x8FF8,0x904F,/* 0x98-0x9F */ - 0x9050,0x9051,0x9052,0x900E,0x9049,0x903E,0x9056,0x9058,/* 0xA0-0xA7 */ - 0x905E,0x9068,0x906F,0x9076,0x96A8,0x9072,0x9082,0x907D,/* 0xA8-0xAF */ - 0x9081,0x9080,0x908A,0x9089,0x908F,0x90A8,0x90AF,0x90B1,/* 0xB0-0xB7 */ - 0x90B5,0x90E2,0x90E4,0x6248,0x90DB,0x9102,0x9112,0x9119,/* 0xB8-0xBF */ - 0x9132,0x9130,0x914A,0x9156,0x9158,0x9163,0x9165,0x9169,/* 0xC0-0xC7 */ - 0x9173,0x9172,0x918B,0x9189,0x9182,0x91A2,0x91AB,0x91AF,/* 0xC8-0xCF */ - 0x91AA,0x91B5,0x91B4,0x91BA,0x91C0,0x91C1,0x91C9,0x91CB,/* 0xD0-0xD7 */ - 0x91D0,0x91D6,0x91DF,0x91E1,0x91DB,0x91FC,0x91F5,0x91F6,/* 0xD8-0xDF */ - 0x921E,0x91FF,0x9214,0x922C,0x9215,0x9211,0x925E,0x9257,/* 0xE0-0xE7 */ - 0x9245,0x9249,0x9264,0x9248,0x9295,0x923F,0x924B,0x9250,/* 0xE8-0xEF */ - 0x929C,0x9296,0x9293,0x929B,0x925A,0x92CF,0x92B9,0x92B7,/* 0xF0-0xF7 */ - 0x92E9,0x930F,0x92FA,0x9344,0x932E,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E8[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9319,0x9322,0x931A,0x9323,0x933A,0x9335,0x933B,0x935C,/* 0x40-0x47 */ - 0x9360,0x937C,0x936E,0x9356,0x93B0,0x93AC,0x93AD,0x9394,/* 0x48-0x4F */ - 0x93B9,0x93D6,0x93D7,0x93E8,0x93E5,0x93D8,0x93C3,0x93DD,/* 0x50-0x57 */ - 0x93D0,0x93C8,0x93E4,0x941A,0x9414,0x9413,0x9403,0x9407,/* 0x58-0x5F */ - 0x9410,0x9436,0x942B,0x9435,0x9421,0x943A,0x9441,0x9452,/* 0x60-0x67 */ - 0x9444,0x945B,0x9460,0x9462,0x945E,0x946A,0x9229,0x9470,/* 0x68-0x6F */ - 0x9475,0x9477,0x947D,0x945A,0x947C,0x947E,0x9481,0x947F,/* 0x70-0x77 */ - 0x9582,0x9587,0x958A,0x9594,0x9596,0x9598,0x9599,0x0000,/* 0x78-0x7F */ - - 0x95A0,0x95A8,0x95A7,0x95AD,0x95BC,0x95BB,0x95B9,0x95BE,/* 0x80-0x87 */ - 0x95CA,0x6FF6,0x95C3,0x95CD,0x95CC,0x95D5,0x95D4,0x95D6,/* 0x88-0x8F */ - 0x95DC,0x95E1,0x95E5,0x95E2,0x9621,0x9628,0x962E,0x962F,/* 0x90-0x97 */ - 0x9642,0x964C,0x964F,0x964B,0x9677,0x965C,0x965E,0x965D,/* 0x98-0x9F */ - 0x965F,0x9666,0x9672,0x966C,0x968D,0x9698,0x9695,0x9697,/* 0xA0-0xA7 */ - 0x96AA,0x96A7,0x96B1,0x96B2,0x96B0,0x96B4,0x96B6,0x96B8,/* 0xA8-0xAF */ - 0x96B9,0x96CE,0x96CB,0x96C9,0x96CD,0x894D,0x96DC,0x970D,/* 0xB0-0xB7 */ - 0x96D5,0x96F9,0x9704,0x9706,0x9708,0x9713,0x970E,0x9711,/* 0xB8-0xBF */ - 0x970F,0x9716,0x9719,0x9724,0x972A,0x9730,0x9739,0x973D,/* 0xC0-0xC7 */ - 0x973E,0x9744,0x9746,0x9748,0x9742,0x9749,0x975C,0x9760,/* 0xC8-0xCF */ - 0x9764,0x9766,0x9768,0x52D2,0x976B,0x9771,0x9779,0x9785,/* 0xD0-0xD7 */ - 0x977C,0x9781,0x977A,0x9786,0x978B,0x978F,0x9790,0x979C,/* 0xD8-0xDF */ - 0x97A8,0x97A6,0x97A3,0x97B3,0x97B4,0x97C3,0x97C6,0x97C8,/* 0xE0-0xE7 */ - 0x97CB,0x97DC,0x97ED,0x9F4F,0x97F2,0x7ADF,0x97F6,0x97F5,/* 0xE8-0xEF */ - 0x980F,0x980C,0x9838,0x9824,0x9821,0x9837,0x983D,0x9846,/* 0xF0-0xF7 */ - 0x984F,0x984B,0x986B,0x986F,0x9870,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E9[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9871,0x9874,0x9873,0x98AA,0x98AF,0x98B1,0x98B6,0x98C4,/* 0x40-0x47 */ - 0x98C3,0x98C6,0x98E9,0x98EB,0x9903,0x9909,0x9912,0x9914,/* 0x48-0x4F */ - 0x9918,0x9921,0x991D,0x991E,0x9924,0x9920,0x992C,0x992E,/* 0x50-0x57 */ - 0x993D,0x993E,0x9942,0x9949,0x9945,0x9950,0x994B,0x9951,/* 0x58-0x5F */ - 0x9952,0x994C,0x9955,0x9997,0x9998,0x99A5,0x99AD,0x99AE,/* 0x60-0x67 */ - 0x99BC,0x99DF,0x99DB,0x99DD,0x99D8,0x99D1,0x99ED,0x99EE,/* 0x68-0x6F */ - 0x99F1,0x99F2,0x99FB,0x99F8,0x9A01,0x9A0F,0x9A05,0x99E2,/* 0x70-0x77 */ - 0x9A19,0x9A2B,0x9A37,0x9A45,0x9A42,0x9A40,0x9A43,0x0000,/* 0x78-0x7F */ - - 0x9A3E,0x9A55,0x9A4D,0x9A5B,0x9A57,0x9A5F,0x9A62,0x9A65,/* 0x80-0x87 */ - 0x9A64,0x9A69,0x9A6B,0x9A6A,0x9AAD,0x9AB0,0x9ABC,0x9AC0,/* 0x88-0x8F */ - 0x9ACF,0x9AD1,0x9AD3,0x9AD4,0x9ADE,0x9ADF,0x9AE2,0x9AE3,/* 0x90-0x97 */ - 0x9AE6,0x9AEF,0x9AEB,0x9AEE,0x9AF4,0x9AF1,0x9AF7,0x9AFB,/* 0x98-0x9F */ - 0x9B06,0x9B18,0x9B1A,0x9B1F,0x9B22,0x9B23,0x9B25,0x9B27,/* 0xA0-0xA7 */ - 0x9B28,0x9B29,0x9B2A,0x9B2E,0x9B2F,0x9B32,0x9B44,0x9B43,/* 0xA8-0xAF */ - 0x9B4F,0x9B4D,0x9B4E,0x9B51,0x9B58,0x9B74,0x9B93,0x9B83,/* 0xB0-0xB7 */ - 0x9B91,0x9B96,0x9B97,0x9B9F,0x9BA0,0x9BA8,0x9BB4,0x9BC0,/* 0xB8-0xBF */ - 0x9BCA,0x9BB9,0x9BC6,0x9BCF,0x9BD1,0x9BD2,0x9BE3,0x9BE2,/* 0xC0-0xC7 */ - 0x9BE4,0x9BD4,0x9BE1,0x9C3A,0x9BF2,0x9BF1,0x9BF0,0x9C15,/* 0xC8-0xCF */ - 0x9C14,0x9C09,0x9C13,0x9C0C,0x9C06,0x9C08,0x9C12,0x9C0A,/* 0xD0-0xD7 */ - 0x9C04,0x9C2E,0x9C1B,0x9C25,0x9C24,0x9C21,0x9C30,0x9C47,/* 0xD8-0xDF */ - 0x9C32,0x9C46,0x9C3E,0x9C5A,0x9C60,0x9C67,0x9C76,0x9C78,/* 0xE0-0xE7 */ - 0x9CE7,0x9CEC,0x9CF0,0x9D09,0x9D08,0x9CEB,0x9D03,0x9D06,/* 0xE8-0xEF */ - 0x9D2A,0x9D26,0x9DAF,0x9D23,0x9D1F,0x9D44,0x9D15,0x9D12,/* 0xF0-0xF7 */ - 0x9D41,0x9D3F,0x9D3E,0x9D46,0x9D48,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_EA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9D5D,0x9D5E,0x9D64,0x9D51,0x9D50,0x9D59,0x9D72,0x9D89,/* 0x40-0x47 */ - 0x9D87,0x9DAB,0x9D6F,0x9D7A,0x9D9A,0x9DA4,0x9DA9,0x9DB2,/* 0x48-0x4F */ - 0x9DC4,0x9DC1,0x9DBB,0x9DB8,0x9DBA,0x9DC6,0x9DCF,0x9DC2,/* 0x50-0x57 */ - 0x9DD9,0x9DD3,0x9DF8,0x9DE6,0x9DED,0x9DEF,0x9DFD,0x9E1A,/* 0x58-0x5F */ - 0x9E1B,0x9E1E,0x9E75,0x9E79,0x9E7D,0x9E81,0x9E88,0x9E8B,/* 0x60-0x67 */ - 0x9E8C,0x9E92,0x9E95,0x9E91,0x9E9D,0x9EA5,0x9EA9,0x9EB8,/* 0x68-0x6F */ - 0x9EAA,0x9EAD,0x9761,0x9ECC,0x9ECE,0x9ECF,0x9ED0,0x9ED4,/* 0x70-0x77 */ - 0x9EDC,0x9EDE,0x9EDD,0x9EE0,0x9EE5,0x9EE8,0x9EEF,0x0000,/* 0x78-0x7F */ - - 0x9EF4,0x9EF6,0x9EF7,0x9EF9,0x9EFB,0x9EFC,0x9EFD,0x9F07,/* 0x80-0x87 */ - 0x9F08,0x76B7,0x9F15,0x9F21,0x9F2C,0x9F3E,0x9F4A,0x9F52,/* 0x88-0x8F */ - 0x9F54,0x9F63,0x9F5F,0x9F60,0x9F61,0x9F66,0x9F67,0x9F6C,/* 0x90-0x97 */ - 0x9F6A,0x9F77,0x9F72,0x9F76,0x9F95,0x9F9C,0x9FA0,0x582F,/* 0x98-0x9F */ - 0x69C7,0x9059,0x7464,0x51DC,0x7199,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ -}; - -static const wchar_t c2u_ED[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7E8A,0x891C,0x9348,0x9288,0x84DC,0x4FC9,0x70BB,0x6631,/* 0x40-0x47 */ - 0x68C8,0x92F9,0x66FB,0x5F45,0x4E28,0x4EE1,0x4EFC,0x4F00,/* 0x48-0x4F */ - 0x4F03,0x4F39,0x4F56,0x4F92,0x4F8A,0x4F9A,0x4F94,0x4FCD,/* 0x50-0x57 */ - 0x5040,0x5022,0x4FFF,0x501E,0x5046,0x5070,0x5042,0x5094,/* 0x58-0x5F */ - 0x50F4,0x50D8,0x514A,0x5164,0x519D,0x51BE,0x51EC,0x5215,/* 0x60-0x67 */ - 0x529C,0x52A6,0x52C0,0x52DB,0x5300,0x5307,0x5324,0x5372,/* 0x68-0x6F */ - 0x5393,0x53B2,0x53DD,0xFA0E,0x549C,0x548A,0x54A9,0x54FF,/* 0x70-0x77 */ - 0x5586,0x5759,0x5765,0x57AC,0x57C8,0x57C7,0xFA0F,0x0000,/* 0x78-0x7F */ - - 0xFA10,0x589E,0x58B2,0x590B,0x5953,0x595B,0x595D,0x5963,/* 0x80-0x87 */ - 0x59A4,0x59BA,0x5B56,0x5BC0,0x752F,0x5BD8,0x5BEC,0x5C1E,/* 0x88-0x8F */ - 0x5CA6,0x5CBA,0x5CF5,0x5D27,0x5D53,0xFA11,0x5D42,0x5D6D,/* 0x90-0x97 */ - 0x5DB8,0x5DB9,0x5DD0,0x5F21,0x5F34,0x5F67,0x5FB7,0x5FDE,/* 0x98-0x9F */ - 0x605D,0x6085,0x608A,0x60DE,0x60D5,0x6120,0x60F2,0x6111,/* 0xA0-0xA7 */ - 0x6137,0x6130,0x6198,0x6213,0x62A6,0x63F5,0x6460,0x649D,/* 0xA8-0xAF */ - 0x64CE,0x654E,0x6600,0x6615,0x663B,0x6609,0x662E,0x661E,/* 0xB0-0xB7 */ - 0x6624,0x6665,0x6657,0x6659,0xFA12,0x6673,0x6699,0x66A0,/* 0xB8-0xBF */ - 0x66B2,0x66BF,0x66FA,0x670E,0xF929,0x6766,0x67BB,0x6852,/* 0xC0-0xC7 */ - 0x67C0,0x6801,0x6844,0x68CF,0xFA13,0x6968,0xFA14,0x6998,/* 0xC8-0xCF */ - 0x69E2,0x6A30,0x6A6B,0x6A46,0x6A73,0x6A7E,0x6AE2,0x6AE4,/* 0xD0-0xD7 */ - 0x6BD6,0x6C3F,0x6C5C,0x6C86,0x6C6F,0x6CDA,0x6D04,0x6D87,/* 0xD8-0xDF */ - 0x6D6F,0x6D96,0x6DAC,0x6DCF,0x6DF8,0x6DF2,0x6DFC,0x6E39,/* 0xE0-0xE7 */ - 0x6E5C,0x6E27,0x6E3C,0x6EBF,0x6F88,0x6FB5,0x6FF5,0x7005,/* 0xE8-0xEF */ - 0x7007,0x7028,0x7085,0x70AB,0x710F,0x7104,0x715C,0x7146,/* 0xF0-0xF7 */ - 0x7147,0xFA15,0x71C1,0x71FE,0x72B1,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_EE[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x72BE,0x7324,0xFA16,0x7377,0x73BD,0x73C9,0x73D6,0x73E3,/* 0x40-0x47 */ - 0x73D2,0x7407,0x73F5,0x7426,0x742A,0x7429,0x742E,0x7462,/* 0x48-0x4F */ - 0x7489,0x749F,0x7501,0x756F,0x7682,0x769C,0x769E,0x769B,/* 0x50-0x57 */ - 0x76A6,0xFA17,0x7746,0x52AF,0x7821,0x784E,0x7864,0x787A,/* 0x58-0x5F */ - 0x7930,0xFA18,0xFA19,0xFA1A,0x7994,0xFA1B,0x799B,0x7AD1,/* 0x60-0x67 */ - 0x7AE7,0xFA1C,0x7AEB,0x7B9E,0xFA1D,0x7D48,0x7D5C,0x7DB7,/* 0x68-0x6F */ - 0x7DA0,0x7DD6,0x7E52,0x7F47,0x7FA1,0xFA1E,0x8301,0x8362,/* 0x70-0x77 */ - 0x837F,0x83C7,0x83F6,0x8448,0x84B4,0x8553,0x8559,0x0000,/* 0x78-0x7F */ - - 0x856B,0xFA1F,0x85B0,0xFA20,0xFA21,0x8807,0x88F5,0x8A12,/* 0x80-0x87 */ - 0x8A37,0x8A79,0x8AA7,0x8ABE,0x8ADF,0xFA22,0x8AF6,0x8B53,/* 0x88-0x8F */ - 0x8B7F,0x8CF0,0x8CF4,0x8D12,0x8D76,0xFA23,0x8ECF,0xFA24,/* 0x90-0x97 */ - 0xFA25,0x9067,0x90DE,0xFA26,0x9115,0x9127,0x91DA,0x91D7,/* 0x98-0x9F */ - 0x91DE,0x91ED,0x91EE,0x91E4,0x91E5,0x9206,0x9210,0x920A,/* 0xA0-0xA7 */ - 0x923A,0x9240,0x923C,0x924E,0x9259,0x9251,0x9239,0x9267,/* 0xA8-0xAF */ - 0x92A7,0x9277,0x9278,0x92E7,0x92D7,0x92D9,0x92D0,0xFA27,/* 0xB0-0xB7 */ - 0x92D5,0x92E0,0x92D3,0x9325,0x9321,0x92FB,0xFA28,0x931E,/* 0xB8-0xBF */ - 0x92FF,0x931D,0x9302,0x9370,0x9357,0x93A4,0x93C6,0x93DE,/* 0xC0-0xC7 */ - 0x93F8,0x9431,0x9445,0x9448,0x9592,0xF9DC,0xFA29,0x969D,/* 0xC8-0xCF */ - 0x96AF,0x9733,0x973B,0x9743,0x974D,0x974F,0x9751,0x9755,/* 0xD0-0xD7 */ - 0x9857,0x9865,0xFA2A,0xFA2B,0x9927,0xFA2C,0x999E,0x9A4E,/* 0xD8-0xDF */ - 0x9AD9,0x9ADC,0x9B75,0x9B72,0x9B8F,0x9BB1,0x9BBB,0x9C00,/* 0xE0-0xE7 */ - 0x9D70,0x9D6B,0xFA2D,0x9E19,0x9ED1,0x0000,0x0000,0x2170,/* 0xE8-0xEF */ - 0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,/* 0xF0-0xF7 */ - 0x2179,0xFFE2,0xFFE4,0xFF07,0xFF02,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_FA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,/* 0x40-0x47 */ - 0x2178,0x2179,0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,/* 0x48-0x4F */ - 0x2166,0x2167,0x2168,0x2169,0xFFE2,0xFFE4,0xFF07,0xFF02,/* 0x50-0x57 */ - 0x3231,0x2116,0x2121,0x2235,0x7E8A,0x891C,0x9348,0x9288,/* 0x58-0x5F */ - 0x84DC,0x4FC9,0x70BB,0x6631,0x68C8,0x92F9,0x66FB,0x5F45,/* 0x60-0x67 */ - 0x4E28,0x4EE1,0x4EFC,0x4F00,0x4F03,0x4F39,0x4F56,0x4F92,/* 0x68-0x6F */ - 0x4F8A,0x4F9A,0x4F94,0x4FCD,0x5040,0x5022,0x4FFF,0x501E,/* 0x70-0x77 */ - 0x5046,0x5070,0x5042,0x5094,0x50F4,0x50D8,0x514A,0x0000,/* 0x78-0x7F */ - - 0x5164,0x519D,0x51BE,0x51EC,0x5215,0x529C,0x52A6,0x52C0,/* 0x80-0x87 */ - 0x52DB,0x5300,0x5307,0x5324,0x5372,0x5393,0x53B2,0x53DD,/* 0x88-0x8F */ - 0xFA0E,0x549C,0x548A,0x54A9,0x54FF,0x5586,0x5759,0x5765,/* 0x90-0x97 */ - 0x57AC,0x57C8,0x57C7,0xFA0F,0xFA10,0x589E,0x58B2,0x590B,/* 0x98-0x9F */ - 0x5953,0x595B,0x595D,0x5963,0x59A4,0x59BA,0x5B56,0x5BC0,/* 0xA0-0xA7 */ - 0x752F,0x5BD8,0x5BEC,0x5C1E,0x5CA6,0x5CBA,0x5CF5,0x5D27,/* 0xA8-0xAF */ - 0x5D53,0xFA11,0x5D42,0x5D6D,0x5DB8,0x5DB9,0x5DD0,0x5F21,/* 0xB0-0xB7 */ - 0x5F34,0x5F67,0x5FB7,0x5FDE,0x605D,0x6085,0x608A,0x60DE,/* 0xB8-0xBF */ - 0x60D5,0x6120,0x60F2,0x6111,0x6137,0x6130,0x6198,0x6213,/* 0xC0-0xC7 */ - 0x62A6,0x63F5,0x6460,0x649D,0x64CE,0x654E,0x6600,0x6615,/* 0xC8-0xCF */ - 0x663B,0x6609,0x662E,0x661E,0x6624,0x6665,0x6657,0x6659,/* 0xD0-0xD7 */ - 0xFA12,0x6673,0x6699,0x66A0,0x66B2,0x66BF,0x66FA,0x670E,/* 0xD8-0xDF */ - 0xF929,0x6766,0x67BB,0x6852,0x67C0,0x6801,0x6844,0x68CF,/* 0xE0-0xE7 */ - 0xFA13,0x6968,0xFA14,0x6998,0x69E2,0x6A30,0x6A6B,0x6A46,/* 0xE8-0xEF */ - 0x6A73,0x6A7E,0x6AE2,0x6AE4,0x6BD6,0x6C3F,0x6C5C,0x6C86,/* 0xF0-0xF7 */ - 0x6C6F,0x6CDA,0x6D04,0x6D87,0x6D6F,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_FB[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6D96,0x6DAC,0x6DCF,0x6DF8,0x6DF2,0x6DFC,0x6E39,0x6E5C,/* 0x40-0x47 */ - 0x6E27,0x6E3C,0x6EBF,0x6F88,0x6FB5,0x6FF5,0x7005,0x7007,/* 0x48-0x4F */ - 0x7028,0x7085,0x70AB,0x710F,0x7104,0x715C,0x7146,0x7147,/* 0x50-0x57 */ - 0xFA15,0x71C1,0x71FE,0x72B1,0x72BE,0x7324,0xFA16,0x7377,/* 0x58-0x5F */ - 0x73BD,0x73C9,0x73D6,0x73E3,0x73D2,0x7407,0x73F5,0x7426,/* 0x60-0x67 */ - 0x742A,0x7429,0x742E,0x7462,0x7489,0x749F,0x7501,0x756F,/* 0x68-0x6F */ - 0x7682,0x769C,0x769E,0x769B,0x76A6,0xFA17,0x7746,0x52AF,/* 0x70-0x77 */ - 0x7821,0x784E,0x7864,0x787A,0x7930,0xFA18,0xFA19,0x0000,/* 0x78-0x7F */ - - 0xFA1A,0x7994,0xFA1B,0x799B,0x7AD1,0x7AE7,0xFA1C,0x7AEB,/* 0x80-0x87 */ - 0x7B9E,0xFA1D,0x7D48,0x7D5C,0x7DB7,0x7DA0,0x7DD6,0x7E52,/* 0x88-0x8F */ - 0x7F47,0x7FA1,0xFA1E,0x8301,0x8362,0x837F,0x83C7,0x83F6,/* 0x90-0x97 */ - 0x8448,0x84B4,0x8553,0x8559,0x856B,0xFA1F,0x85B0,0xFA20,/* 0x98-0x9F */ - 0xFA21,0x8807,0x88F5,0x8A12,0x8A37,0x8A79,0x8AA7,0x8ABE,/* 0xA0-0xA7 */ - 0x8ADF,0xFA22,0x8AF6,0x8B53,0x8B7F,0x8CF0,0x8CF4,0x8D12,/* 0xA8-0xAF */ - 0x8D76,0xFA23,0x8ECF,0xFA24,0xFA25,0x9067,0x90DE,0xFA26,/* 0xB0-0xB7 */ - 0x9115,0x9127,0x91DA,0x91D7,0x91DE,0x91ED,0x91EE,0x91E4,/* 0xB8-0xBF */ - 0x91E5,0x9206,0x9210,0x920A,0x923A,0x9240,0x923C,0x924E,/* 0xC0-0xC7 */ - 0x9259,0x9251,0x9239,0x9267,0x92A7,0x9277,0x9278,0x92E7,/* 0xC8-0xCF */ - 0x92D7,0x92D9,0x92D0,0xFA27,0x92D5,0x92E0,0x92D3,0x9325,/* 0xD0-0xD7 */ - 0x9321,0x92FB,0xFA28,0x931E,0x92FF,0x931D,0x9302,0x9370,/* 0xD8-0xDF */ - 0x9357,0x93A4,0x93C6,0x93DE,0x93F8,0x9431,0x9445,0x9448,/* 0xE0-0xE7 */ - 0x9592,0xF9DC,0xFA29,0x969D,0x96AF,0x9733,0x973B,0x9743,/* 0xE8-0xEF */ - 0x974D,0x974F,0x9751,0x9755,0x9857,0x9865,0xFA2A,0xFA2B,/* 0xF0-0xF7 */ - 0x9927,0xFA2C,0x999E,0x9A4E,0x9AD9,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_FC[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9ADC,0x9B75,0x9B72,0x9B8F,0x9BB1,0x9BBB,0x9C00,0x9D70,/* 0x40-0x47 */ - 0x9D6B,0xFA2D,0x9E19,0x9ED1,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ -}; - -static const wchar_t *page_charset2uni[256] = { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, c2u_81, c2u_82, c2u_83, c2u_84, NULL, NULL, c2u_87, - c2u_88, c2u_89, c2u_8A, c2u_8B, c2u_8C, c2u_8D, c2u_8E, c2u_8F, - c2u_90, c2u_91, c2u_92, c2u_93, c2u_94, c2u_95, c2u_96, c2u_97, - c2u_98, c2u_99, c2u_9A, c2u_9B, c2u_9C, c2u_9D, c2u_9E, c2u_9F, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - c2u_E0, c2u_E1, c2u_E2, c2u_E3, c2u_E4, c2u_E5, c2u_E6, c2u_E7, - c2u_E8, c2u_E9, c2u_EA, NULL, NULL, c2u_ED, c2u_EE, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, c2u_FA, c2u_FB, c2u_FC, NULL, NULL, NULL, -}; - -static const unsigned char u2c_00hi[256 - 0xA0][2] = { - {0x00, 0x00}, {0x00, 0x00}, {0x81, 0x91}, {0x81, 0x92},/* 0xA0-0xA3 */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x81, 0x98},/* 0xA4-0xA7 */ - {0x81, 0x4E}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xA8-0xAB */ - {0x81, 0xCA}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xAC-0xAF */ - {0x81, 0x8B}, {0x81, 0x7D}, {0x00, 0x00}, {0x00, 0x00},/* 0xB0-0xB3 */ - {0x81, 0x4C}, {0x00, 0x00}, {0x81, 0xF7}, {0x00, 0x00},/* 0xB4-0xB7 */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xB8-0xBB */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xBC-0xBF */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xC0-0xC3 */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xC4-0xC7 */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xC8-0xCB */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xCC-0xCF */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xD0-0xD3 */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x81, 0x7E},/* 0xD4-0xD7 */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xD8-0xDB */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xDC-0xDF */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xE0-0xE3 */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xE4-0xE7 */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xE8-0xEB */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xEC-0xEF */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xF0-0xF3 */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x81, 0x80},/* 0xF4-0xF7 */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xF8-0xFB */ - {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00}, {0x00, 0x00},/* 0xFC-0xFF */ -}; - -static const unsigned char u2c_03[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x83, 0x9F, 0x83, 0xA0, 0x83, 0xA1, /* 0x90-0x93 */ - 0x83, 0xA2, 0x83, 0xA3, 0x83, 0xA4, 0x83, 0xA5, /* 0x94-0x97 */ - 0x83, 0xA6, 0x83, 0xA7, 0x83, 0xA8, 0x83, 0xA9, /* 0x98-0x9B */ - 0x83, 0xAA, 0x83, 0xAB, 0x83, 0xAC, 0x83, 0xAD, /* 0x9C-0x9F */ - 0x83, 0xAE, 0x83, 0xAF, 0x00, 0x00, 0x83, 0xB0, /* 0xA0-0xA3 */ - 0x83, 0xB1, 0x83, 0xB2, 0x83, 0xB3, 0x83, 0xB4, /* 0xA4-0xA7 */ - 0x83, 0xB5, 0x83, 0xB6, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x83, 0xBF, 0x83, 0xC0, 0x83, 0xC1, /* 0xB0-0xB3 */ - 0x83, 0xC2, 0x83, 0xC3, 0x83, 0xC4, 0x83, 0xC5, /* 0xB4-0xB7 */ - 0x83, 0xC6, 0x83, 0xC7, 0x83, 0xC8, 0x83, 0xC9, /* 0xB8-0xBB */ - 0x83, 0xCA, 0x83, 0xCB, 0x83, 0xCC, 0x83, 0xCD, /* 0xBC-0xBF */ - 0x83, 0xCE, 0x83, 0xCF, 0x00, 0x00, 0x83, 0xD0, /* 0xC0-0xC3 */ - 0x83, 0xD1, 0x83, 0xD2, 0x83, 0xD3, 0x83, 0xD4, /* 0xC4-0xC7 */ - 0x83, 0xD5, 0x83, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ -}; - -static const unsigned char u2c_04[512] = { - 0x00, 0x00, 0x84, 0x46, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x84, 0x40, 0x84, 0x41, 0x84, 0x42, 0x84, 0x43, /* 0x10-0x13 */ - 0x84, 0x44, 0x84, 0x45, 0x84, 0x47, 0x84, 0x48, /* 0x14-0x17 */ - 0x84, 0x49, 0x84, 0x4A, 0x84, 0x4B, 0x84, 0x4C, /* 0x18-0x1B */ - 0x84, 0x4D, 0x84, 0x4E, 0x84, 0x4F, 0x84, 0x50, /* 0x1C-0x1F */ - 0x84, 0x51, 0x84, 0x52, 0x84, 0x53, 0x84, 0x54, /* 0x20-0x23 */ - 0x84, 0x55, 0x84, 0x56, 0x84, 0x57, 0x84, 0x58, /* 0x24-0x27 */ - 0x84, 0x59, 0x84, 0x5A, 0x84, 0x5B, 0x84, 0x5C, /* 0x28-0x2B */ - 0x84, 0x5D, 0x84, 0x5E, 0x84, 0x5F, 0x84, 0x60, /* 0x2C-0x2F */ - 0x84, 0x70, 0x84, 0x71, 0x84, 0x72, 0x84, 0x73, /* 0x30-0x33 */ - 0x84, 0x74, 0x84, 0x75, 0x84, 0x77, 0x84, 0x78, /* 0x34-0x37 */ - 0x84, 0x79, 0x84, 0x7A, 0x84, 0x7B, 0x84, 0x7C, /* 0x38-0x3B */ - 0x84, 0x7D, 0x84, 0x7E, 0x84, 0x80, 0x84, 0x81, /* 0x3C-0x3F */ - 0x84, 0x82, 0x84, 0x83, 0x84, 0x84, 0x84, 0x85, /* 0x40-0x43 */ - 0x84, 0x86, 0x84, 0x87, 0x84, 0x88, 0x84, 0x89, /* 0x44-0x47 */ - 0x84, 0x8A, 0x84, 0x8B, 0x84, 0x8C, 0x84, 0x8D, /* 0x48-0x4B */ - 0x84, 0x8E, 0x84, 0x8F, 0x84, 0x90, 0x84, 0x91, /* 0x4C-0x4F */ - 0x00, 0x00, 0x84, 0x76, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ -}; - -static const unsigned char u2c_20[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x81, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x81, 0x5C, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x81, 0x65, 0x81, 0x66, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x81, 0x67, 0x81, 0x68, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x81, 0xF5, 0x81, 0xF6, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x81, 0x64, 0x81, 0x63, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x81, 0xF1, 0x00, 0x00, 0x81, 0x8C, 0x81, 0x8D, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xA6, /* 0x38-0x3B */ -}; - -static const unsigned char u2c_21[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x8E, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xFA, 0x59, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xFA, 0x5A, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xF0, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xFA, 0x4A, 0xFA, 0x4B, 0xFA, 0x4C, 0xFA, 0x4D, /* 0x60-0x63 */ - 0xFA, 0x4E, 0xFA, 0x4F, 0xFA, 0x50, 0xFA, 0x51, /* 0x64-0x67 */ - 0xFA, 0x52, 0xFA, 0x53, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xEE, 0xEF, 0xEE, 0xF0, 0xEE, 0xF1, 0xEE, 0xF2, /* 0x70-0x73 */ - 0xEE, 0xF3, 0xEE, 0xF4, 0xEE, 0xF5, 0xEE, 0xF6, /* 0x74-0x77 */ - 0xEE, 0xF7, 0xEE, 0xF8, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x81, 0xA9, 0x81, 0xAA, 0x81, 0xA8, 0x81, 0xAB, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x81, 0xCB, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x81, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ -}; - -static const unsigned char u2c_22[512] = { - 0x81, 0xCD, 0x00, 0x00, 0x81, 0xDD, 0x81, 0xCE, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xDE, /* 0x04-0x07 */ - 0x81, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x81, 0xB9, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x87, 0x94, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x87, 0x95, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x81, 0xE5, 0x81, 0x87, 0x87, 0x98, /* 0x1C-0x1F */ - 0x87, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x81, 0x61, 0x00, 0x00, 0x81, 0xC8, /* 0x24-0x27 */ - 0x81, 0xC9, 0x87, 0x9B, 0x87, 0x9C, 0x87, 0x92, /* 0x28-0x2B */ - 0x81, 0xE8, 0x00, 0x00, 0x87, 0x93, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x81, 0x88, 0xFA, 0x5B, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x81, 0xE4, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x87, 0x90, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x81, 0x82, 0x87, 0x91, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x81, 0x85, 0x81, 0x86, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x81, 0xE1, 0x81, 0xE2, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x81, 0xBC, 0x81, 0xBD, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x81, 0xBA, 0x81, 0xBB, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x87, 0x96, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x99, /* 0xBC-0xBF */ -}; - -static const unsigned char u2c_23[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x81, 0xDC, 0x00, 0x00, /* 0x10-0x13 */ -}; - -static const unsigned char u2c_24[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x87, 0x40, 0x87, 0x41, 0x87, 0x42, 0x87, 0x43, /* 0x60-0x63 */ - 0x87, 0x44, 0x87, 0x45, 0x87, 0x46, 0x87, 0x47, /* 0x64-0x67 */ - 0x87, 0x48, 0x87, 0x49, 0x87, 0x4A, 0x87, 0x4B, /* 0x68-0x6B */ - 0x87, 0x4C, 0x87, 0x4D, 0x87, 0x4E, 0x87, 0x4F, /* 0x6C-0x6F */ - 0x87, 0x50, 0x87, 0x51, 0x87, 0x52, 0x87, 0x53, /* 0x70-0x73 */ -}; - -static const unsigned char u2c_25[512] = { - 0x84, 0x9F, 0x84, 0xAA, 0x84, 0xA0, 0x84, 0xAB, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x84, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x84, 0xAC, /* 0x0C-0x0F */ - 0x84, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x84, 0xAD, /* 0x10-0x13 */ - 0x84, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x84, 0xAF, /* 0x14-0x17 */ - 0x84, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x84, 0xAE, /* 0x18-0x1B */ - 0x84, 0xA5, 0x84, 0xBA, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x84, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x84, 0xB0, /* 0x20-0x23 */ - 0x84, 0xA7, 0x84, 0xBC, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x84, 0xB7, 0x00, 0x00, 0x00, 0x00, 0x84, 0xB2, /* 0x28-0x2B */ - 0x84, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x84, 0xB6, /* 0x2C-0x2F */ - 0x84, 0xBB, 0x00, 0x00, 0x00, 0x00, 0x84, 0xB1, /* 0x30-0x33 */ - 0x84, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x84, 0xB8, /* 0x34-0x37 */ - 0x84, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x84, 0xB3, /* 0x38-0x3B */ - 0x84, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x84, 0xB9, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x84, 0xBE, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x84, 0xB4, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x81, 0xA1, 0x81, 0xA0, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x81, 0xA3, 0x81, 0xA2, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x81, 0xA5, 0x81, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x81, 0x9F, 0x81, 0x9E, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x9B, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x81, 0x9D, 0x81, 0x9C, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xFC, /* 0xEC-0xEF */ -}; - -static const unsigned char u2c_26[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x81, 0x9A, 0x81, 0x99, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x81, 0x8A, 0x00, 0x00, 0x81, 0x89, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x81, 0xF4, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x81, 0xF3, 0x00, 0x00, 0x81, 0xF2, /* 0x6C-0x6F */ -}; - -static const unsigned char u2c_30[512] = { - 0x81, 0x40, 0x81, 0x41, 0x81, 0x42, 0x81, 0x56, /* 0x00-0x03 */ - 0x00, 0x00, 0x81, 0x58, 0x81, 0x59, 0x81, 0x5A, /* 0x04-0x07 */ - 0x81, 0x71, 0x81, 0x72, 0x81, 0x73, 0x81, 0x74, /* 0x08-0x0B */ - 0x81, 0x75, 0x81, 0x76, 0x81, 0x77, 0x81, 0x78, /* 0x0C-0x0F */ - 0x81, 0x79, 0x81, 0x7A, 0x81, 0xA7, 0x81, 0xAC, /* 0x10-0x13 */ - 0x81, 0x6B, 0x81, 0x6C, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x87, 0x80, 0x00, 0x00, 0x87, 0x81, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x82, 0x9F, 0x82, 0xA0, 0x82, 0xA1, /* 0x40-0x43 */ - 0x82, 0xA2, 0x82, 0xA3, 0x82, 0xA4, 0x82, 0xA5, /* 0x44-0x47 */ - 0x82, 0xA6, 0x82, 0xA7, 0x82, 0xA8, 0x82, 0xA9, /* 0x48-0x4B */ - 0x82, 0xAA, 0x82, 0xAB, 0x82, 0xAC, 0x82, 0xAD, /* 0x4C-0x4F */ - 0x82, 0xAE, 0x82, 0xAF, 0x82, 0xB0, 0x82, 0xB1, /* 0x50-0x53 */ - 0x82, 0xB2, 0x82, 0xB3, 0x82, 0xB4, 0x82, 0xB5, /* 0x54-0x57 */ - 0x82, 0xB6, 0x82, 0xB7, 0x82, 0xB8, 0x82, 0xB9, /* 0x58-0x5B */ - 0x82, 0xBA, 0x82, 0xBB, 0x82, 0xBC, 0x82, 0xBD, /* 0x5C-0x5F */ - 0x82, 0xBE, 0x82, 0xBF, 0x82, 0xC0, 0x82, 0xC1, /* 0x60-0x63 */ - 0x82, 0xC2, 0x82, 0xC3, 0x82, 0xC4, 0x82, 0xC5, /* 0x64-0x67 */ - 0x82, 0xC6, 0x82, 0xC7, 0x82, 0xC8, 0x82, 0xC9, /* 0x68-0x6B */ - 0x82, 0xCA, 0x82, 0xCB, 0x82, 0xCC, 0x82, 0xCD, /* 0x6C-0x6F */ - 0x82, 0xCE, 0x82, 0xCF, 0x82, 0xD0, 0x82, 0xD1, /* 0x70-0x73 */ - 0x82, 0xD2, 0x82, 0xD3, 0x82, 0xD4, 0x82, 0xD5, /* 0x74-0x77 */ - 0x82, 0xD6, 0x82, 0xD7, 0x82, 0xD8, 0x82, 0xD9, /* 0x78-0x7B */ - 0x82, 0xDA, 0x82, 0xDB, 0x82, 0xDC, 0x82, 0xDD, /* 0x7C-0x7F */ - - 0x82, 0xDE, 0x82, 0xDF, 0x82, 0xE0, 0x82, 0xE1, /* 0x80-0x83 */ - 0x82, 0xE2, 0x82, 0xE3, 0x82, 0xE4, 0x82, 0xE5, /* 0x84-0x87 */ - 0x82, 0xE6, 0x82, 0xE7, 0x82, 0xE8, 0x82, 0xE9, /* 0x88-0x8B */ - 0x82, 0xEA, 0x82, 0xEB, 0x82, 0xEC, 0x82, 0xED, /* 0x8C-0x8F */ - 0x82, 0xEE, 0x82, 0xEF, 0x82, 0xF0, 0x82, 0xF1, /* 0x90-0x93 */ - 0x83, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x4A, /* 0x98-0x9B */ - 0x81, 0x4B, 0x81, 0x54, 0x81, 0x55, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x83, 0x40, 0x83, 0x41, 0x83, 0x42, /* 0xA0-0xA3 */ - 0x83, 0x43, 0x83, 0x44, 0x83, 0x45, 0x83, 0x46, /* 0xA4-0xA7 */ - 0x83, 0x47, 0x83, 0x48, 0x83, 0x49, 0x83, 0x4A, /* 0xA8-0xAB */ - 0x83, 0x4B, 0x83, 0x4C, 0x83, 0x4D, 0x83, 0x4E, /* 0xAC-0xAF */ - 0x83, 0x4F, 0x83, 0x50, 0x83, 0x51, 0x83, 0x52, /* 0xB0-0xB3 */ - 0x83, 0x53, 0x83, 0x54, 0x83, 0x55, 0x83, 0x56, /* 0xB4-0xB7 */ - 0x83, 0x57, 0x83, 0x58, 0x83, 0x59, 0x83, 0x5A, /* 0xB8-0xBB */ - 0x83, 0x5B, 0x83, 0x5C, 0x83, 0x5D, 0x83, 0x5E, /* 0xBC-0xBF */ - 0x83, 0x5F, 0x83, 0x60, 0x83, 0x61, 0x83, 0x62, /* 0xC0-0xC3 */ - 0x83, 0x63, 0x83, 0x64, 0x83, 0x65, 0x83, 0x66, /* 0xC4-0xC7 */ - 0x83, 0x67, 0x83, 0x68, 0x83, 0x69, 0x83, 0x6A, /* 0xC8-0xCB */ - 0x83, 0x6B, 0x83, 0x6C, 0x83, 0x6D, 0x83, 0x6E, /* 0xCC-0xCF */ - 0x83, 0x6F, 0x83, 0x70, 0x83, 0x71, 0x83, 0x72, /* 0xD0-0xD3 */ - 0x83, 0x73, 0x83, 0x74, 0x83, 0x75, 0x83, 0x76, /* 0xD4-0xD7 */ - 0x83, 0x77, 0x83, 0x78, 0x83, 0x79, 0x83, 0x7A, /* 0xD8-0xDB */ - 0x83, 0x7B, 0x83, 0x7C, 0x83, 0x7D, 0x83, 0x7E, /* 0xDC-0xDF */ - 0x83, 0x80, 0x83, 0x81, 0x83, 0x82, 0x83, 0x83, /* 0xE0-0xE3 */ - 0x83, 0x84, 0x83, 0x85, 0x83, 0x86, 0x83, 0x87, /* 0xE4-0xE7 */ - 0x83, 0x88, 0x83, 0x89, 0x83, 0x8A, 0x83, 0x8B, /* 0xE8-0xEB */ - 0x83, 0x8C, 0x83, 0x8D, 0x83, 0x8E, 0x83, 0x8F, /* 0xEC-0xEF */ - 0x83, 0x90, 0x83, 0x91, 0x83, 0x92, 0x83, 0x93, /* 0xF0-0xF3 */ - 0x83, 0x94, 0x83, 0x95, 0x83, 0x96, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x45, /* 0xF8-0xFB */ - 0x81, 0x5B, 0x81, 0x52, 0x81, 0x53, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_32[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xFA, 0x58, 0x87, 0x8B, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x87, 0x8C, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x87, 0x85, 0x87, 0x86, 0x87, 0x87, 0x87, 0x88, /* 0xA4-0xA7 */ - 0x87, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ -}; - -static const unsigned char u2c_33[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x65, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x87, 0x69, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x87, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x87, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x87, 0x61, 0x87, 0x6B, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x87, 0x6A, 0x87, 0x64, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x6C, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x87, 0x66, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x6E, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x87, 0x5F, 0x87, 0x6D, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x87, 0x62, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x87, 0x67, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x68, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, 0x7E, /* 0x78-0x7B */ - 0x87, 0x8F, 0x87, 0x8E, 0x87, 0x8D, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x87, 0x72, 0x87, 0x73, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x87, 0x6F, 0x87, 0x70, 0x87, 0x71, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x87, 0x75, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x87, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x87, 0x83, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ -}; - -static const unsigned char u2c_4E[512] = { - 0x88, 0xEA, 0x92, 0x9A, 0x00, 0x00, 0x8E, 0xB5, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x9C, /* 0x04-0x07 */ - 0x8F, 0xE4, 0x8E, 0x4F, 0x8F, 0xE3, 0x89, 0xBA, /* 0x08-0x0B */ - 0x00, 0x00, 0x95, 0x73, 0x97, 0x5E, 0x00, 0x00, /* 0x0C-0x0F */ - 0x98, 0xA0, 0x89, 0x4E, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x8A, 0x8E, 0x98, 0xA1, 0x90, 0xA2, 0x99, 0xC0, /* 0x14-0x17 */ - 0x8B, 0x75, 0x95, 0xB8, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0xE5, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x97, 0xBC, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x95, 0xC0, 0x00, 0x00, /* 0x24-0x27 */ - 0xED, 0x4C, 0x00, 0x00, 0x98, 0xA2, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x92, 0x86, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x98, 0xA3, 0x8B, 0xF8, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x98, 0xA4, 0x00, 0x00, /* 0x34-0x37 */ - 0x8A, 0xDB, 0x92, 0x4F, 0x00, 0x00, 0x8E, 0xE5, /* 0x38-0x3B */ - 0x98, 0xA5, 0x00, 0x00, 0x00, 0x00, 0x98, 0xA6, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x98, 0xA7, 0x94, 0x54, /* 0x40-0x43 */ - 0x00, 0x00, 0x8B, 0x76, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x56, /* 0x48-0x4B */ - 0x00, 0x00, 0x93, 0xE1, 0x8C, 0xC1, 0x96, 0x52, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xE5, 0x68, 0x98, 0xA8, 0x8F, 0xE6, /* 0x54-0x57 */ - 0x98, 0xA9, 0x89, 0xB3, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x8B, 0xE3, 0x8C, 0xEE, 0x96, 0xE7, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0xA4, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x97, 0x90, 0x00, 0x00, 0x93, 0xFB, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x8A, 0xA3, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x8B, 0x54, 0x00, 0x00, 0x98, 0xAA, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x98, 0xAB, 0x97, 0xB9, 0x00, 0x00, /* 0x84-0x87 */ - 0x97, 0x5C, 0x91, 0x88, 0x98, 0xAD, 0x8E, 0x96, /* 0x88-0x8B */ - 0x93, 0xF1, 0x00, 0x00, 0x98, 0xB0, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x89, 0x5D, 0x8C, 0xDD, 0x00, 0x00, /* 0x90-0x93 */ - 0x8C, 0xDC, 0x88, 0xE4, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x98, 0x6A, 0x98, 0x69, 0x00, 0x00, 0x8D, 0xB1, /* 0x98-0x9B */ - 0x88, 0x9F, 0x00, 0x00, 0x98, 0xB1, 0x98, 0xB2, /* 0x9C-0x9F */ - 0x98, 0xB3, 0x96, 0x53, 0x98, 0xB4, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x8C, 0xF0, 0x88, 0xE5, 0x96, 0x92, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x8B, 0x9C, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x9D, /* 0xA8-0xAB */ - 0x8B, 0x9E, 0x92, 0xE0, 0x97, 0xBA, 0x00, 0x00, /* 0xAC-0xAF */ - 0x98, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x98, 0xB6, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x98, 0xB7, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x90, 0x6C, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x8F, 0x59, 0x90, 0x6D, 0x98, 0xBC, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x98, 0xBA, 0x00, 0x00, 0x98, 0xBB, 0x8B, 0x77, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x8D, 0xA1, 0x89, 0xEE, /* 0xC8-0xCB */ - 0x00, 0x00, 0x98, 0xB9, 0x98, 0xB8, 0x95, 0xA7, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x8E, 0x65, 0x8E, 0x64, 0x91, 0xBC, 0x98, 0xBD, /* 0xD4-0xD7 */ - 0x95, 0x74, 0x90, 0xE5, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x81, 0x57, 0x98, 0xBE, 0x98, 0xC0, /* 0xDC-0xDF */ - 0x00, 0x00, 0xED, 0x4D, 0x00, 0x00, 0x91, 0xE3, /* 0xE0-0xE3 */ - 0x97, 0xDF, 0x88, 0xC8, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x98, 0xBF, 0x89, 0xBC, 0x00, 0x00, /* 0xEC-0xEF */ - 0x8B, 0xC2, 0x00, 0x00, 0x92, 0x87, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0x8F, 0x98, 0xC1, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x43, /* 0xF8-0xFB */ - 0xED, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_4F[512] = { - 0xED, 0x4F, 0x8A, 0xE9, 0x00, 0x00, 0xED, 0x50, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x98, 0xC2, 0x88, 0xC9, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x8C, 0xDE, 0x8A, 0xEA, 0x95, 0x9A, /* 0x0C-0x0F */ - 0x94, 0xB0, 0x8B, 0x78, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0xEF, 0x00, 0x00, /* 0x18-0x1B */ - 0x98, 0xE5, 0x93, 0x60, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x8C, /* 0x2C-0x2F */ - 0x98, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x94, 0xBA, 0x00, 0x00, 0x97, 0xE0, 0x00, 0x00, /* 0x34-0x37 */ - 0x90, 0x4C, 0xED, 0x51, 0x8E, 0x66, 0x00, 0x00, /* 0x38-0x3B */ - 0x8E, 0x97, 0x89, 0xBE, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0xCF, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x92, 0x41, 0x98, 0xC8, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x88, 0xCA, 0x92, 0xE1, 0x8F, 0x5A, /* 0x4C-0x4F */ - 0x8D, 0xB2, 0x97, 0x43, 0x00, 0x00, 0x91, 0xCC, /* 0x50-0x53 */ - 0x00, 0x00, 0x89, 0xBD, 0xED, 0x52, 0x98, 0xC7, /* 0x54-0x57 */ - 0x00, 0x00, 0x97, 0x5D, 0x98, 0xC3, 0x98, 0xC5, /* 0x58-0x5B */ - 0x8D, 0xEC, 0x98, 0xC6, 0x9B, 0x43, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x98, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0xD1, /* 0x6C-0x6F */ - 0x98, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x89, 0xC0, /* 0x70-0x73 */ - 0x00, 0x00, 0x95, 0xB9, 0x98, 0xC9, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0xCD, /* 0x78-0x7B */ - 0x8C, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x67, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xA4, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x98, 0xD2, 0x00, 0x00, /* 0x84-0x87 */ - 0x98, 0xCA, 0x00, 0x00, 0xED, 0x54, 0x97, 0xE1, /* 0x88-0x8B */ - 0x00, 0x00, 0x8E, 0x98, 0x00, 0x00, 0x98, 0xCB, /* 0x8C-0x8F */ - 0x00, 0x00, 0x98, 0xD0, 0xED, 0x53, 0x00, 0x00, /* 0x90-0x93 */ - 0xED, 0x56, 0x00, 0x00, 0x98, 0xD3, 0x00, 0x00, /* 0x94-0x97 */ - 0x98, 0xCC, 0x00, 0x00, 0xED, 0x55, 0x8B, 0x9F, /* 0x98-0x9B */ - 0x00, 0x00, 0x88, 0xCB, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x8B, 0xA0, 0x89, 0xBF, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x44, /* 0xA8-0xAB */ - 0x00, 0x00, 0x96, 0x99, 0x95, 0x8E, 0x8C, 0xF2, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x90, 0x4E, 0x97, 0xB5, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0xD6, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0x57, 0x91, 0xA3, /* 0xC0-0xC3 */ - 0x89, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xED, 0x45, 0x8F, 0x72, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0xED, 0x57, 0x98, 0xD7, 0x00, 0x00, /* 0xCC-0xCF */ - 0x98, 0xDC, 0x98, 0xDA, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x98, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x91, 0xAD, /* 0xD4-0xD7 */ - 0x98, 0xD8, 0x00, 0x00, 0x98, 0xDB, 0x98, 0xD9, /* 0xD8-0xDB */ - 0x00, 0x00, 0x95, 0xDB, 0x00, 0x00, 0x98, 0xD6, /* 0xDC-0xDF */ - 0x00, 0x00, 0x90, 0x4D, 0x00, 0x00, 0x96, 0x93, /* 0xE0-0xE3 */ - 0x98, 0xDD, 0x98, 0xDE, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0x43, 0x98, 0xEB, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x6F, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x95, 0x55, 0x98, 0xE6, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x95, 0xEE, 0x00, 0x00, 0x89, 0xB4, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x98, 0xEA, 0xED, 0x5A, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_50[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x98, 0xE4, 0x98, 0xED, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x91, 0x71, 0x00, 0x00, 0x8C, 0xC2, /* 0x08-0x0B */ - 0x00, 0x00, 0x94, 0x7B, 0x00, 0x00, 0xE0, 0xC5, /* 0x0C-0x0F */ - 0x00, 0x00, 0x98, 0xEC, 0x93, 0x7C, 0x00, 0x00, /* 0x10-0x13 */ - 0x98, 0xE1, 0x00, 0x00, 0x8C, 0xF4, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x8C, 0xF3, 0x98, 0xDF, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0x5B, 0x8E, 0xD8, /* 0x1C-0x1F */ - 0x00, 0x00, 0x98, 0xE7, 0xED, 0x59, 0x95, 0xED, /* 0x20-0x23 */ - 0x92, 0x6C, 0x98, 0xE3, 0x8C, 0x91, 0x00, 0x00, /* 0x24-0x27 */ - 0x98, 0xE0, 0x98, 0xE8, 0x98, 0xE2, 0x97, 0xCF, /* 0x28-0x2B */ - 0x98, 0xE9, 0x98, 0x60, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0xE4, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x8C, 0x90, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xED, 0x58, 0x00, 0x00, 0xED, 0x5E, 0x98, 0xEE, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0x5C, 0x98, 0xEF, /* 0x44-0x47 */ - 0x98, 0xF3, 0x88, 0xCC, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0xCE, /* 0x4C-0x4F */ - 0x98, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x98, 0xF1, 0x98, 0xF5, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x98, 0xF4, 0x00, 0x00, /* 0x58-0x5B */ - 0x92, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x8C, 0x92, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x98, 0xF6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xED, 0x5D, 0x00, 0x00, 0x8E, 0xC3, 0x00, 0x00, /* 0x70-0x73 */ - 0x91, 0xA4, 0x92, 0xE3, 0x8B, 0xF4, 0x00, 0x00, /* 0x74-0x77 */ - 0x98, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x8B, 0x55, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x98, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x98, 0xFA, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x96, 0x54, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x8C, 0x86, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xED, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x8E, 0x50, 0x94, 0xF5, 0x98, 0xF9, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x8D, 0xC3, 0x97, 0x62, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x98, 0xFC, 0x99, 0x42, /* 0xB0-0xB3 */ - 0x98, 0xFB, 0x8D, 0xC2, 0x00, 0x00, 0x8F, 0x9D, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0x58, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x99, 0x43, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x8B, 0xCD, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x99, 0x40, 0x99, 0x41, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x93, 0xAD, 0x00, 0x00, 0x91, 0x9C, /* 0xCC-0xCF */ - 0x00, 0x00, 0x8B, 0xA1, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x96, 0x6C, 0x99, 0x44, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xED, 0x61, 0x00, 0x00, 0x97, 0xBB, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x99, 0x45, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x48, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x99, 0x46, 0x00, 0x00, 0x91, 0x6D, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x99, 0x47, 0x99, 0x49, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xED, 0x60, 0x99, 0x4B, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x99, 0x4A, 0x00, 0x00, 0x95, 0xC6, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_51[512] = { - 0x8B, 0x56, 0x99, 0x4D, 0x99, 0x4E, 0x00, 0x00, /* 0x00-0x03 */ - 0x89, 0xAD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x99, 0x4C, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x8E, 0xF2, 0x00, 0x00, /* 0x10-0x13 */ - 0x99, 0x51, 0x99, 0x50, 0x99, 0x4F, 0x00, 0x00, /* 0x14-0x17 */ - 0x98, 0xD4, 0x00, 0x00, 0x99, 0x52, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x9E, /* 0x1C-0x1F */ - 0x00, 0x00, 0x99, 0x53, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0x44, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0xD7, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x55, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x99, 0x54, 0x99, 0x57, /* 0x38-0x3B */ - 0x99, 0x56, 0x00, 0x00, 0x00, 0x00, 0x99, 0x58, /* 0x3C-0x3F */ - 0x99, 0x59, 0x88, 0xF2, 0x00, 0x00, 0x8C, 0xB3, /* 0x40-0x43 */ - 0x8C, 0x5A, 0x8F, 0x5B, 0x92, 0x9B, 0x8B, 0xA2, /* 0x44-0x47 */ - 0x90, 0xE6, 0x8C, 0xF5, 0xED, 0x62, 0x8D, 0x8E, /* 0x48-0x4B */ - 0x99, 0x5B, 0x96, 0xC6, 0x93, 0x65, 0x00, 0x00, /* 0x4C-0x4F */ - 0x8E, 0x99, 0x00, 0x00, 0x99, 0x5A, 0x00, 0x00, /* 0x50-0x53 */ - 0x99, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x93, 0x7D, 0x00, 0x00, /* 0x58-0x5B */ - 0x8A, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x99, 0x5D, 0x00, 0x00, /* 0x60-0x63 */ - 0xED, 0x63, 0x93, 0xFC, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x91, 0x53, 0x99, 0x5F, 0x99, 0x60, 0x94, 0xAA, /* 0x68-0x6B */ - 0x8C, 0xF6, 0x98, 0x5A, 0x99, 0x61, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x8B, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x95, 0xBA, 0x91, 0xB4, 0x8B, 0xEF, /* 0x74-0x77 */ - 0x93, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x8C, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x99, 0x62, 0x00, 0x00, 0x99, 0x63, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x93, 0xE0, 0x89, 0x7E, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x99, 0x66, 0x8D, 0xFB, 0x00, 0x00, /* 0x88-0x8B */ - 0x99, 0x65, 0x8D, 0xC4, 0x00, 0x00, 0x99, 0x67, /* 0x8C-0x8F */ - 0xE3, 0xEC, 0x99, 0x68, 0x96, 0x60, 0x99, 0x69, /* 0x90-0x93 */ - 0x00, 0x00, 0x99, 0x6A, 0x99, 0x6B, 0x8F, 0xE7, /* 0x94-0x97 */ - 0x00, 0x00, 0x8E, 0xCA, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xED, 0x64, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x8A, 0xA5, 0x00, 0x00, 0x99, 0x6E, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x99, 0x6C, 0x96, 0xBB, 0x99, 0x6D, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x95, 0x79, 0x99, 0x6F, 0x99, 0x70, 0x99, 0x71, /* 0xA8-0xAB */ - 0x93, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x99, 0x75, 0x99, 0x73, 0x99, 0x74, 0x99, 0x72, /* 0xB0-0xB3 */ - 0x8D, 0xE1, 0x99, 0x76, 0x96, 0xE8, 0x97, 0xE2, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x99, 0x77, 0xED, 0x65, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x90, 0xA6, 0x99, 0x78, 0x8F, 0x79, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x99, 0x79, 0x00, 0x00, 0x92, 0x9C, /* 0xC8-0xCB */ - 0x97, 0xBD, 0x93, 0x80, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x99, 0xC3, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x7A, /* 0xD8-0xDB */ - 0xEA, 0xA3, 0x8B, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x99, 0x7B, 0x96, 0x7D, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0x88, 0x91, 0xFA, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x99, 0x7D, 0x93, 0xE2, 0x00, 0x00, /* 0xE8-0xEB */ - 0xED, 0x66, 0x99, 0x7E, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x99, 0x80, 0x8A, 0x4D, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x99, 0x81, 0x8B, 0xA5, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x93, 0xCA, 0x89, 0x9A, 0x8F, 0x6F, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x94, 0x9F, 0x99, 0x82, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_52[512] = { - 0x93, 0x81, 0x00, 0x00, 0x00, 0x00, 0x90, 0x6E, /* 0x00-0x03 */ - 0x99, 0x83, 0x00, 0x00, 0x95, 0xAA, 0x90, 0xD8, /* 0x04-0x07 */ - 0x8A, 0xA0, 0x00, 0x00, 0x8A, 0xA7, 0x99, 0x84, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x99, 0x86, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x8C, 0x59, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x99, 0x85, 0xED, 0x67, 0x00, 0x00, 0x97, 0xF1, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x8F, 0x89, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x94, 0xBB, 0x95, 0xCA, 0x00, 0x00, 0x99, 0x87, /* 0x24-0x27 */ - 0x00, 0x00, 0x97, 0x98, 0x99, 0x88, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x99, 0x89, 0x00, 0x00, /* 0x2C-0x2F */ - 0x93, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x99, 0x8A, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x90, 0xA7, 0x8D, 0xFC, /* 0x34-0x37 */ - 0x8C, 0x94, 0x99, 0x8B, 0x8E, 0x68, 0x8D, 0x8F, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0xE4, /* 0x40-0x43 */ - 0x99, 0x8D, 0x00, 0x00, 0x00, 0x00, 0x91, 0xA5, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x8D, 0xED, 0x99, 0x8E, /* 0x48-0x4B */ - 0x99, 0x8F, 0x91, 0x4F, 0x00, 0x00, 0x99, 0x8C, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x99, 0x91, 0x00, 0x00, 0x96, 0x55, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8D, 0x84, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x99, 0x90, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x95, /* 0x60-0x63 */ - 0x8D, 0xDC, 0x94, 0x8D, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x99, 0x94, 0x99, 0x92, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x9B, /* 0x6C-0x6F */ - 0x8F, 0xE8, 0x99, 0x9B, 0x8A, 0x84, 0x99, 0x95, /* 0x70-0x73 */ - 0x99, 0x93, 0x91, 0x6E, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x99, 0x97, 0x00, 0x00, 0x99, 0x96, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x63, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x80, /* 0x84-0x87 */ - 0x99, 0x9C, 0x97, 0xAB, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x99, 0x98, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x99, 0x9D, 0x99, 0x9A, 0x00, 0x00, /* 0x90-0x93 */ - 0x99, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0xCD, /* 0x98-0x9B */ - 0xED, 0x68, 0x00, 0x00, 0x00, 0x00, 0x8C, 0xF7, /* 0x9C-0x9F */ - 0x89, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x97, 0xF2, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0x69, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x8F, 0x95, 0x93, 0x77, 0x8D, 0x85, /* 0xA8-0xAB */ - 0x99, 0xA0, 0x99, 0xA1, 0x00, 0x00, 0xEE, 0x5B, /* 0xAC-0xAF */ - 0x00, 0x00, 0x97, 0xE3, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x98, 0x4A, 0x99, 0xA3, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x8C, 0xF8, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x99, 0xA2, 0x00, 0x00, 0x8A, 0x4E, 0x00, 0x00, /* 0xBC-0xBF */ - 0xED, 0x6A, 0x99, 0xA4, 0x00, 0x00, 0x96, 0x75, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x92, 0xBA, 0x00, 0x00, 0x97, 0x45, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x95, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x99, 0xA5, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xD3, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x93, 0xAE, 0x00, 0x00, 0x99, 0xA6, /* 0xD4-0xD7 */ - 0x8A, 0xA8, 0x96, 0xB1, 0x00, 0x00, 0xED, 0x6B, /* 0xD8-0xDB */ - 0x00, 0x00, 0x8F, 0x9F, 0x99, 0xA7, 0x95, 0xE5, /* 0xDC-0xDF */ - 0x99, 0xAB, 0x00, 0x00, 0x90, 0xA8, 0x99, 0xA8, /* 0xE0-0xE3 */ - 0x8B, 0xCE, 0x00, 0x00, 0x99, 0xA9, 0x8A, 0xA9, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0x4D, 0x99, 0xAC, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x99, 0xAD, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x99, 0xAE, 0x99, 0xAF, 0x8E, 0xD9, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0xF9, 0x96, 0xDC, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_53[512] = { - 0xED, 0x6C, 0x96, 0xE6, 0x93, 0xF5, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x95, 0xEF, 0x99, 0xB0, 0xED, 0x6D, /* 0x04-0x07 */ - 0x99, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x99, 0xB3, 0x00, 0x00, 0x99, 0xB5, /* 0x0C-0x0F */ - 0x99, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x99, 0xB6, 0x89, 0xBB, 0x96, 0x6B, /* 0x14-0x17 */ - 0x00, 0x00, 0x8D, 0xFA, 0x99, 0xB7, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x91, 0x78, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x8F, 0xA0, 0x8B, 0xA7, 0x00, 0x00, 0x99, 0xB8, /* 0x20-0x23 */ - 0xED, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0xD9, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xB9, /* 0x2C-0x2F */ - 0x00, 0x00, 0x99, 0xBA, 0x00, 0x00, 0x99, 0xBB, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x99, 0xBC, 0x95, 0x43, 0x8B, 0xE6, 0x88, 0xE3, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0xBD, /* 0x3C-0x3F */ - 0x99, 0xBD, 0x8F, 0x5C, 0x00, 0x00, 0x90, 0xE7, /* 0x40-0x43 */ - 0x00, 0x00, 0x99, 0xBF, 0x99, 0xBE, 0x8F, 0xA1, /* 0x44-0x47 */ - 0x8C, 0xDF, 0x99, 0xC1, 0x94, 0xBC, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x99, 0xC2, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x94, 0xDA, 0x91, 0xB2, 0x91, 0xEC, /* 0x50-0x53 */ - 0x8B, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x93, 0xEC, /* 0x54-0x57 */ - 0x92, 0x50, 0x00, 0x00, 0x94, 0x8E, 0x00, 0x00, /* 0x58-0x5B */ - 0x96, 0x6D, 0x00, 0x00, 0x99, 0xC4, 0x00, 0x00, /* 0x5C-0x5F */ - 0x90, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0x54, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x99, 0xC5, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x99, 0xC6, 0x89, 0x4B, /* 0x6C-0x6F */ - 0x88, 0xF3, 0x8A, 0xEB, 0xED, 0x6F, 0x91, 0xA6, /* 0x70-0x73 */ - 0x8B, 0x70, 0x97, 0x91, 0x00, 0x00, 0x99, 0xC9, /* 0x74-0x77 */ - 0x89, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x99, 0xC8, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xA8, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x99, 0xCA, 0x00, 0x00, /* 0x80-0x83 */ - 0x96, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0x70, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x99, 0xCB, 0x00, 0x00, /* 0x94-0x97 */ - 0x97, 0xD0, 0x00, 0x00, 0x8C, 0xFA, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0xB4, /* 0x9C-0x9F */ - 0x99, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x99, 0xCE, 0x99, 0xCD, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x90, 0x7E, 0x89, 0x58, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x89, 0x7D, 0x99, 0xCF, 0x00, 0x00, /* 0xAC-0xAF */ - 0x99, 0xD0, 0x00, 0x00, 0xED, 0x71, 0x8C, 0xB5, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x99, 0xD1, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x8E, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x8E, 0x51, 0x99, 0xD2, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x96, 0x94, 0x8D, 0xB3, 0x8B, 0x79, 0x97, 0x46, /* 0xC8-0xCB */ - 0x91, 0x6F, 0x94, 0xBD, 0x8E, 0xFB, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x8F, 0x66, 0x00, 0x00, 0x8E, 0xE6, 0x8E, 0xF3, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x8F, 0x96, 0x00, 0x00, 0x94, 0xBE, /* 0xD8-0xDB */ - 0x00, 0x00, 0xED, 0x72, 0x00, 0x00, 0x99, 0xD5, /* 0xDC-0xDF */ - 0x00, 0x00, 0x89, 0x62, 0x91, 0x70, 0x8C, 0xFB, /* 0xE0-0xE3 */ - 0x8C, 0xC3, 0x8B, 0xE5, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x99, 0xD9, 0x92, 0x40, 0x91, 0xFC, 0x8B, 0xA9, /* 0xE8-0xEB */ - 0x8F, 0xA2, 0x99, 0xDA, 0x99, 0xD8, 0x89, 0xC2, /* 0xEC-0xEF */ - 0x91, 0xE4, 0x8E, 0xB6, 0x8E, 0x6A, 0x89, 0x45, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x8A, 0x90, 0x8D, 0x86, /* 0xF4-0xF7 */ - 0x8E, 0x69, 0x00, 0x00, 0x99, 0xDB, 0x00, 0x00, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_54[512] = { - 0x00, 0x00, 0x99, 0xDC, 0x00, 0x00, 0x8B, 0x68, /* 0x00-0x03 */ - 0x8A, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x8D, 0x87, 0x8B, 0x67, 0x92, 0xDD, 0x89, 0x44, /* 0x08-0x0B */ - 0x93, 0xAF, 0x96, 0xBC, 0x8D, 0x40, 0x97, 0x99, /* 0x0C-0x0F */ - 0x93, 0x66, 0x8C, 0xFC, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x4E, /* 0x18-0x1B */ - 0x00, 0x00, 0x99, 0xE5, 0x00, 0x00, 0x8B, 0xE1, /* 0x1C-0x1F */ - 0x96, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0xDB, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x99, 0xE4, 0x00, 0x00, 0x8A, 0xDC, /* 0x28-0x2B */ - 0x99, 0xDF, 0x99, 0xE0, 0x99, 0xE2, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x99, 0xE3, 0x00, 0x00, /* 0x34-0x37 */ - 0x8B, 0x7A, 0x90, 0x81, 0x00, 0x00, 0x95, 0xAB, /* 0x38-0x3B */ - 0x99, 0xE1, 0x99, 0xDD, 0x8C, 0xE1, 0x00, 0x00, /* 0x3C-0x3F */ - 0x99, 0xDE, 0x00, 0x00, 0x98, 0x43, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x95, 0xF0, 0x00, 0x00, /* 0x44-0x47 */ - 0x92, 0xE6, 0x8C, 0xE0, 0x8D, 0x90, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x99, 0xE6, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x93, 0xDB, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xEA, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x8E, 0xFC, 0x00, 0x00, 0x8E, 0xF4, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x99, 0xED, 0x99, 0xEB, 0x00, 0x00, 0x96, 0xA1, /* 0x70-0x73 */ - 0x00, 0x00, 0x99, 0xE8, 0x99, 0xF1, 0x99, 0xEC, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0xEF, /* 0x78-0x7B */ - 0x8C, 0xC4, 0x96, 0xBD, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x99, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x99, 0xF2, 0x00, 0x00, 0x99, 0xF4, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0x75, 0x8D, 0xEE, /* 0x88-0x8B */ - 0x98, 0x61, 0x00, 0x00, 0x99, 0xE9, 0x99, 0xE7, /* 0x8C-0x8F */ - 0x99, 0xF3, 0x00, 0x00, 0x99, 0xEE, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xED, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x99, 0xF6, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x9A, 0x42, 0x99, 0xF8, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x99, 0xFC, 0xED, 0x76, 0x00, 0x00, 0x9A, 0x40, /* 0xA8-0xAB */ - 0x99, 0xF9, 0x00, 0x00, 0x00, 0x00, 0x9A, 0x5D, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x8D, 0xE7, 0x8A, 0x50, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x99, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x9A, 0x44, 0x88, 0xF4, 0x9A, 0x43, 0x00, 0x00, /* 0xBC-0xBF */ - 0x88, 0xA3, 0x95, 0x69, 0x9A, 0x41, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x99, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x99, 0xF5, /* 0xC4-0xC7 */ - 0x99, 0xFB, 0x8D, 0xC6, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x9A, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x88, 0xF5, 0x9A, 0x4E, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x9A, 0x46, 0x9A, 0x47, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x8F, 0xA3, 0x96, 0x89, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x9A, 0x4C, 0x9A, 0x4B, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x93, 0x4E, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0x4D, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x9A, 0x4A, 0x00, 0x00, 0xED, 0x77, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_55[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x89, 0x53, 0x00, 0x00, 0x8D, 0xB4, 0x90, 0x4F, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 0x48, /* 0x0C-0x0F */ - 0x93, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x9A, 0x49, 0x00, 0x00, 0x88, 0xA0, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0x53, 0x97, 0x42, /* 0x2C-0x2F */ - 0x00, 0x00, 0x8F, 0xA5, 0x00, 0x00, 0x9A, 0x59, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x9A, 0x58, 0x9A, 0x4F, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x91, 0xC1, 0x00, 0x00, /* 0x3C-0x3F */ - 0x9A, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x91, 0xED, 0x9A, 0x55, 0x8F, 0xA4, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x9A, 0x52, 0x00, 0x00, 0x00, 0x00, 0x96, 0xE2, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x5B, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0x56, 0x9A, 0x57, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x9A, 0x54, 0x9A, 0x5A, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 0x51, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 0x60, /* 0x78-0x7B */ - 0x9A, 0x65, 0x00, 0x00, 0x9A, 0x61, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x9A, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x9A, 0x66, /* 0x80-0x83 */ - 0x91, 0x50, 0x00, 0x00, 0xED, 0x78, 0x9A, 0x68, /* 0x84-0x87 */ - 0x00, 0x00, 0x8D, 0x41, 0x9A, 0x5E, 0x92, 0x9D, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x9A, 0x62, 0x9A, 0x5B, 0x8A, 0xAB, 0x00, 0x00, /* 0x98-0x9B */ - 0x8A, 0xEC, 0x8A, 0x85, 0x9A, 0x63, 0x9A, 0x5F, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x96, /* 0xA4-0xA7 */ - 0x9A, 0x69, 0x9A, 0x67, 0x91, 0x72, 0x8B, 0x69, /* 0xA8-0xAB */ - 0x8B, 0xAA, 0x00, 0x00, 0x9A, 0x64, 0x00, 0x00, /* 0xAC-0xAF */ - 0x8B, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0x63, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x9A, 0x6D, 0x9A, 0x6B, 0x00, 0x00, 0x9A, 0xA5, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x9A, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0x6A, 0x00, 0x00, /* 0xD8-0xDB */ - 0x9A, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x9A, 0x6C, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x6B, /* 0xE0-0xE3 */ - 0x9A, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 0x72, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x9A, 0x77, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x9A, 0x75, 0x9A, 0x74, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_56[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x92, 0x51, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x89, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x9A, 0x71, 0x00, 0x00, 0x9A, 0x73, 0x8F, 0xA6, /* 0x14-0x17 */ - 0x89, 0x52, 0x00, 0x00, 0x00, 0x00, 0x9A, 0x76, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x89, 0xDC, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 0x82, /* 0x2C-0x2F */ - 0x00, 0x00, 0x8F, 0xFA, 0x9A, 0x7D, 0x00, 0x00, /* 0x30-0x33 */ - 0x9A, 0x7B, 0x00, 0x00, 0x9A, 0x7C, 0x00, 0x00, /* 0x34-0x37 */ - 0x9A, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0x5C, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x91, 0x58, 0x00, 0x00, 0x9A, 0x78, 0x00, 0x00, /* 0x4C-0x4F */ - 0x9A, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x9A, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x9A, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x8A, 0xED, 0x00, 0x00, 0x9A, 0x84, 0x9A, 0x80, /* 0x68-0x6B */ - 0x9A, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x95, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x93, 0xD3, 0x00, 0x00, 0x94, 0xB6, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x9A, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0x85, 0x8A, 0x64, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0x87, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 0x8A, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x9A, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x9A, 0x88, 0x00, 0x00, 0x94, 0x58, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x9A, 0x8B, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0x8C, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x9A, 0x8E, 0x00, 0x00, 0x9A, 0x8D, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x9A, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x9A, 0x93, 0x9A, 0x91, 0x9A, 0x8F, 0x9A, 0x92, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x9A, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0x95, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x9A, 0x96, 0x00, 0x00, 0x9A, 0x97, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 0x98, /* 0xD4-0xD7 */ - 0x99, 0x64, 0x00, 0x00, 0x8E, 0xFA, 0x8E, 0x6C, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0xF1, 0x00, 0x00, /* 0xDC-0xDF */ - 0x88, 0xF6, 0x00, 0x00, 0x00, 0x00, 0x92, 0x63, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0x99, 0x00, 0x00, /* 0xEC-0xEF */ - 0x8D, 0xA2, 0x00, 0x00, 0x88, 0xCD, 0x90, 0x7D, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x9A, 0x9A, 0x8C, 0xC5, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x8D, 0x91, 0x00, 0x00, 0x9A, 0x9C, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_57[512] = { - 0x9A, 0x9B, 0x00, 0x00, 0x00, 0x00, 0x95, 0xDE, /* 0x00-0x03 */ - 0x9A, 0x9D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x9A, 0x9F, 0x9A, 0x9E, 0x00, 0x00, 0x9A, 0xA0, /* 0x08-0x0B */ - 0x00, 0x00, 0x9A, 0xA1, 0x00, 0x00, 0x8C, 0x97, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0x80, 0x9A, 0xA2, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0xA4, 0x00, 0x00, /* 0x14-0x17 */ - 0x9A, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x9A, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x93, 0x79, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0xA7, 0x88, 0xB3, /* 0x24-0x27 */ - 0x8D, 0xDD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x8C, 0x5C, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x92, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xA8, /* 0x34-0x37 */ - 0x9A, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xAB, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x9A, 0xAC, 0x00, 0x00, 0x8D, 0xE2, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xCF, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0x56, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0xAA, 0x9A, 0xAD, /* 0x4C-0x4F */ - 0x8D, 0xBF, 0x8D, 0x42, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xED, 0x79, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x9A, 0xB1, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x8D, 0xA3, 0xED, 0x7A, 0x92, 0x52, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x9A, 0xAE, 0x92, 0xD8, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xB2, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x90, 0x82, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x9A, 0xB0, 0x9A, 0xB3, 0x00, 0x00, 0x8C, 0x5E, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xB4, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x9A, 0xB5, 0x00, 0x00, 0x8D, 0x43, 0x8A, 0x5F, /* 0xA0-0xA3 */ - 0x9A, 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0xB8, 0x00, 0x00, /* 0xA8-0xAB */ - 0xED, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x9A, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xB6, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x9A, 0xAF, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xBA, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0xBB, 0xED, 0x7D, /* 0xC4-0xC7 */ - 0xED, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x96, 0x84, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0xE9, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0xBD, 0x9A, 0xBE, /* 0xD0-0xD3 */ - 0x9A, 0xBC, 0x00, 0x00, 0x9A, 0xC0, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x94, 0x57, 0x00, 0x00, 0x00, 0x00, 0x88, 0xE6, /* 0xDC-0xDF */ - 0x95, 0x75, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xC1, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x8F, 0xFB, 0x00, 0x00, 0x00, 0x00, 0x8E, 0xB7, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x94, 0x7C, 0x8A, 0xEE, 0x00, 0x00, /* 0xF8-0xFB */ - 0x8D, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_58[512] = { - 0x96, 0x78, 0x00, 0x00, 0x93, 0xB0, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x8C, 0x98, 0x91, 0xCD, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0xBF, 0x9A, 0xC2, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x91, 0xC2, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x9A, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x9A, 0xC4, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x9A, 0xC6, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x92, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x8A, 0xAC, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x9F, /* 0x2C-0x2F */ - 0x89, 0x81, 0x95, 0xF1, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x8F, 0xEA, 0x93, 0x67, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x8D, 0xE4, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x9A, 0xCC, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x95, 0xBB, 0x97, 0xDB, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0xF2, 0x9A, 0xC8, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x91, 0x59, 0x9A, 0xCB, 0x00, 0x00, /* 0x50-0x53 */ - 0x93, 0x83, 0x00, 0x00, 0x00, 0x00, 0x93, 0x68, /* 0x54-0x57 */ - 0x93, 0x84, 0x94, 0xB7, 0x92, 0xCB, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x8D, 0xC7, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0xC7, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x89, 0x96, 0x00, 0x00, 0x93, 0x55, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x9A, 0xC9, 0x00, 0x00, 0x9A, 0xC5, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x90, 0x6F, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x9A, 0xCD, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0x6D, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xAB, /* 0x80-0x83 */ - 0x00, 0x00, 0x9A, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0xE6, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x9D, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x92, 0xC4, 0x00, 0x00, 0xED, 0x81, 0x9A, 0xD0, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x96, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x9A, 0xD1, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0xD6, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0x82, 0x95, 0xAD, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x9A, 0xD5, 0x9A, 0xCF, 0x9A, 0xD2, 0x9A, 0xD4, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x8D, 0xA4, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x95, 0xC7, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x9A, 0xD7, 0x00, 0x00, 0x92, 0x64, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0xF3, 0x00, 0x00, /* 0xC8-0xCB */ - 0x8F, 0xEB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x9A, 0xD9, 0x00, 0x00, 0x9A, 0xD8, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x8D, 0x88, 0x00, 0x00, 0x9A, 0xDA, /* 0xD4-0xD7 */ - 0x9A, 0xDC, 0x9A, 0xDB, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x9A, 0xDE, 0x00, 0x00, 0x9A, 0xD3, 0x9A, 0xE0, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x9A, 0xDF, 0x9A, 0xDD, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x6D, /* 0xE8-0xEB */ - 0x90, 0x70, 0x00, 0x00, 0x91, 0x73, 0x9A, 0xE1, /* 0xEC-0xEF */ - 0x90, 0xBA, 0x88, 0xEB, 0x94, 0x84, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0xD9, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x9A, 0xE3, 0x9A, 0xE2, 0x9A, 0xE4, /* 0xF8-0xFB */ - 0x9A, 0xE5, 0x9A, 0xE6, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_59[512] = { - 0x00, 0x00, 0x00, 0x00, 0x9A, 0xE7, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x95, 0xCF, 0x9A, 0xE8, 0xED, 0x83, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0xC4, /* 0x0C-0x0F */ - 0x9A, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x97, 0x5B, 0x8A, 0x4F, 0x00, 0x00, /* 0x14-0x17 */ - 0x99, 0xC7, 0x8F, 0x67, 0x91, 0xBD, 0x9A, 0xEA, /* 0x18-0x1B */ - 0x96, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0xB2, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x9A, 0xEC, 0x00, 0x00, 0x91, 0xE5, /* 0x24-0x27 */ - 0x00, 0x00, 0x93, 0x56, 0x91, 0xBE, 0x95, 0x76, /* 0x28-0x2B */ - 0x9A, 0xED, 0x9A, 0xEE, 0x89, 0x9B, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x8E, 0xB8, 0x9A, 0xEF, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xCE, /* 0x34-0x37 */ - 0x9A, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0xF1, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x89, 0x82, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xEF, /* 0x44-0x47 */ - 0x93, 0xDE, 0x95, 0xF2, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0xF5, 0x91, 0x74, /* 0x4C-0x4F */ - 0x9A, 0xF4, 0x8C, 0x5F, 0x00, 0x00, 0xED, 0x84, /* 0x50-0x53 */ - 0x96, 0x7A, 0x9A, 0xF3, 0x00, 0x00, 0x93, 0x85, /* 0x54-0x57 */ - 0x9A, 0xF7, 0x00, 0x00, 0x9A, 0xF6, 0xED, 0x85, /* 0x58-0x5B */ - 0x00, 0x00, 0xED, 0x86, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x9A, 0xF9, 0x00, 0x00, 0x9A, 0xF8, 0xED, 0x87, /* 0x60-0x63 */ - 0x00, 0x00, 0x89, 0x9C, 0x00, 0x00, 0x9A, 0xFA, /* 0x64-0x67 */ - 0x8F, 0xA7, 0x9A, 0xFC, 0x92, 0x44, 0x00, 0x00, /* 0x68-0x6B */ - 0x9A, 0xFB, 0x00, 0x00, 0x95, 0xB1, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x97, /* 0x70-0x73 */ - 0x93, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x9B, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x8D, 0x44, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x9B, 0x41, 0x94, 0x40, 0x94, 0xDC, /* 0x80-0x83 */ - 0x96, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0x44, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x9B, 0x4A, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x57, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0x64, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x96, 0xAD, 0x00, 0x00, 0x9B, 0xAA, /* 0x98-0x9B */ - 0x00, 0x00, 0x9B, 0x42, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x45, /* 0xA0-0xA3 */ - 0xED, 0x88, 0x91, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x96, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x93, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0x46, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x96, 0x85, 0xED, 0x89, 0x8D, 0xC8, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0xA8, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0x47, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x8E, 0x6F, 0x00, 0x00, 0x8E, 0x6E, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x88, 0xB7, 0x8C, 0xC6, 0x00, 0x00, 0x90, 0xA9, /* 0xD0-0xD3 */ - 0x88, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x9B, 0x4B, 0x9B, 0x4C, 0x00, 0x00, /* 0xD8-0xDB */ - 0x9B, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x89, 0x57, 0x8A, 0xAD, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x9B, 0x48, 0x00, 0x00, 0x96, 0xC3, 0x95, 0x50, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x88, 0xA6, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xF7, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x70, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5A[512] = { - 0x00, 0x00, 0x88, 0xD0, 0x00, 0x00, 0x88, 0xA1, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x9B, 0x51, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x9B, 0x4F, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x96, 0xBA, 0x00, 0x00, 0x9B, 0x52, 0x00, 0x00, /* 0x18-0x1B */ - 0x9B, 0x50, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x4E, /* 0x1C-0x1F */ - 0x90, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x9B, 0x4D, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x95, 0xD8, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0xE2, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x9B, 0x56, 0x9B, 0x57, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x8F, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x9B, 0x53, 0x98, 0x4B, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0x6B, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x9B, 0x55, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x8D, 0xA5, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0x58, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x95, 0x77, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0x59, 0x00, 0x00, /* 0x68-0x6B */ - 0x9B, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0xB9, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0x7D, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0x5A, 0x95, 0x51, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x9B, 0x5B, 0x9B, 0x5F, 0x9B, 0x5C, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x89, 0xC5, 0x9B, 0x5E, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x8E, 0xB9, 0x00, 0x00, 0x9B, 0x5D, /* 0xC8-0xCB */ - 0x8C, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x9B, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0x64, 0x9B, 0x61, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x92, 0x84, 0x00, 0x00, 0x9B, 0x60, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0x62, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x9B, 0x63, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0x65, 0x9B, 0x66, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_5B[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x8A, 0xF0, 0x00, 0x00, 0x9B, 0x68, /* 0x08-0x0B */ - 0x9B, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0x69, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0xEC, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0x6C, 0x00, 0x00, /* 0x28-0x2B */ - 0x92, 0xDA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x89, 0x64, 0x00, 0x00, 0x9B, 0x6A, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0x6D, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0x6E, 0x00, 0x00, /* 0x3C-0x3F */ - 0x9B, 0x71, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x6F, /* 0x40-0x43 */ - 0x00, 0x00, 0x9B, 0x70, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x8E, 0x71, 0x9B, 0x72, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x8D, 0x45, 0x9B, 0x73, 0xED, 0x8A, 0x8E, 0x9A, /* 0x54-0x57 */ - 0x91, 0xB6, 0x00, 0x00, 0x9B, 0x74, 0x9B, 0x75, /* 0x58-0x5B */ - 0x8E, 0x79, 0x8D, 0x46, 0x00, 0x00, 0x96, 0xD0, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x47, /* 0x60-0x63 */ - 0x8C, 0xC7, 0x9B, 0x76, 0x8A, 0x77, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x9B, 0x77, 0x00, 0x00, 0x91, 0xB7, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x9B, 0x78, 0x9B, 0xA1, 0x00, 0x00, 0x9B, 0x79, /* 0x70-0x73 */ - 0x00, 0x00, 0x9B, 0x7A, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x9B, 0x7B, 0x00, 0x00, 0x9B, 0x7D, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x9B, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x80, /* 0x80-0x83 */ - 0x00, 0x00, 0x91, 0xEE, 0x00, 0x00, 0x89, 0x46, /* 0x84-0x87 */ - 0x8E, 0xE7, 0x88, 0xC0, 0x00, 0x00, 0x91, 0x76, /* 0x88-0x8B */ - 0x8A, 0xAE, 0x8E, 0xB3, 0x00, 0x00, 0x8D, 0x47, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x93, 0x86, 0x00, 0x00, 0x8F, 0x40, /* 0x94-0x97 */ - 0x8A, 0xAF, 0x92, 0x88, 0x92, 0xE8, 0x88, 0xB6, /* 0x98-0x9B */ - 0x8B, 0x58, 0x95, 0xF3, 0x00, 0x00, 0x8E, 0xC0, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0x71, 0x90, 0xE9, /* 0xA0-0xA3 */ - 0x8E, 0xBA, 0x97, 0x47, 0x9B, 0x81, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0x7B, 0x00, 0x00, /* 0xAC-0xAF */ - 0x8D, 0xC9, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x51, /* 0xB0-0xB3 */ - 0x89, 0x83, 0x8F, 0xAA, 0x89, 0xC6, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x9B, 0x82, 0x97, 0x65, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x68, /* 0xBC-0xBF */ - 0xED, 0x8B, 0x00, 0x00, 0x8E, 0xE2, 0x9B, 0x83, /* 0xC0-0xC3 */ - 0x8A, 0xF1, 0x93, 0xD0, 0x96, 0xA7, 0x9B, 0x84, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x9B, 0x85, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x95, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x9B, 0x87, 0x00, 0x00, 0x8A, 0xA6, 0x8B, 0xF5, /* 0xD0-0xD3 */ - 0x9B, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xED, 0x8D, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xB0, /* 0xD8-0xDB */ - 0x00, 0x00, 0x90, 0x51, 0x9B, 0x8B, 0x8E, 0x40, /* 0xDC-0xDF */ - 0x00, 0x00, 0x89, 0xC7, 0x9B, 0x8A, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x9B, 0x88, 0x9B, 0x8C, 0x9B, 0x89, 0x94, 0x4A, /* 0xE4-0xE7 */ - 0x9E, 0xCB, 0x90, 0x52, 0x00, 0x00, 0x9B, 0x8D, /* 0xE8-0xEB */ - 0xED, 0x8E, 0x00, 0x00, 0x97, 0xBE, 0x00, 0x00, /* 0xEC-0xEF */ - 0x9B, 0x8E, 0x00, 0x00, 0x00, 0x00, 0x9B, 0x90, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x92, 0x9E, 0x9B, 0x8F, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x90, 0xA1, 0x00, 0x00, 0x8E, 0x9B, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x91, 0xCE, 0x8E, 0xF5, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5C[512] = { - 0x00, 0x00, 0x95, 0x95, 0x90, 0xEA, 0x00, 0x00, /* 0x00-0x03 */ - 0x8E, 0xCB, 0x9B, 0x91, 0x8F, 0xAB, 0x9B, 0x92, /* 0x04-0x07 */ - 0x9B, 0x93, 0x88, 0xD1, 0x91, 0xB8, 0x90, 0x71, /* 0x08-0x0B */ - 0x00, 0x00, 0x9B, 0x94, 0x93, 0xB1, 0x8F, 0xAC, /* 0x0C-0x0F */ - 0x00, 0x00, 0x8F, 0xAD, 0x00, 0x00, 0x9B, 0x95, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x90, 0xEB, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0xAE, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0x8F, 0x00, 0x00, /* 0x1C-0x1F */ - 0x9B, 0x96, 0x00, 0x00, 0x9B, 0x97, 0x00, 0x00, /* 0x20-0x23 */ - 0x96, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x9B, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x8B, 0xC4, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x8F, 0x41, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x9B, 0x99, 0x9B, 0x9A, 0x8E, 0xDA, 0x90, 0x4B, /* 0x38-0x3B */ - 0x93, 0xF2, 0x90, 0x73, 0x94, 0xF6, 0x94, 0x41, /* 0x3C-0x3F */ - 0x8B, 0xC7, 0x9B, 0x9B, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x8B, 0x8F, 0x9B, 0x9C, 0x00, 0x00, /* 0x44-0x47 */ - 0x8B, 0xFC, 0x00, 0x00, 0x93, 0xCD, 0x89, 0xAE, /* 0x48-0x4B */ - 0x00, 0x00, 0x8E, 0x72, 0x9B, 0x9D, 0x9B, 0xA0, /* 0x4C-0x4F */ - 0x9B, 0x9F, 0x8B, 0xFB, 0x00, 0x00, 0x9B, 0x9E, /* 0x50-0x53 */ - 0x00, 0x00, 0x93, 0x57, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x91, 0xAE, 0x00, 0x00, /* 0x5C-0x5F */ - 0x93, 0x6A, 0x8E, 0xC6, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x91, 0x77, 0x97, 0x9A, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x9B, 0xA2, 0x00, 0x00, 0x9B, 0xA3, 0x93, 0xD4, /* 0x6C-0x6F */ - 0x00, 0x00, 0x8E, 0x52, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0xA5, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x9B, 0xA6, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x9B, 0xA7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x8A, 0xF2, 0x9B, 0xA8, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x9B, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x89, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0x90, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x91, 0x5A, 0x8A, 0xE2, 0x00, 0x00, 0x9B, 0xAB, /* 0xA8-0xAB */ - 0x96, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x91, 0xD0, 0x00, 0x00, 0x8A, 0x78, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0xAD, 0x9B, 0xAF, /* 0xB4-0xB7 */ - 0x8A, 0xDD, 0x00, 0x00, 0xED, 0x91, 0x9B, 0xAC, /* 0xB8-0xBB */ - 0x9B, 0xAE, 0x00, 0x00, 0x9B, 0xB1, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x9B, 0xB0, 0x00, 0x00, 0x9B, 0xB2, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x9B, 0xB3, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x93, 0xBB, 0x8B, 0xAC, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x89, 0xE3, 0x9B, 0xB4, 0x9B, 0xB9, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x9B, 0xB7, 0x00, 0x00, 0x95, 0xF5, /* 0xEC-0xEF */ - 0x95, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xED, 0x92, 0x93, 0x87, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0xB6, 0x8F, 0x73, /* 0xF8-0xFB */ - 0x00, 0x00, 0x9B, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5D[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x92, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0xBA, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x8D, 0xE8, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x9B, 0xC0, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x9B, 0xC1, 0x9B, 0xBB, 0x8A, 0x52, 0x9B, 0xBC, /* 0x14-0x17 */ - 0x9B, 0xC5, 0x9B, 0xC4, 0x9B, 0xC3, 0x9B, 0xBF, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0xBE, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0xC2, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0x93, /* 0x24-0x27 */ - 0x00, 0x00, 0x95, 0xF6, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0x96, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0xC9, /* 0x48-0x4B */ - 0x9B, 0xC6, 0x00, 0x00, 0x9B, 0xC8, 0x00, 0x00, /* 0x4C-0x4F */ - 0x97, 0x92, 0x00, 0x00, 0x9B, 0xC7, 0xED, 0x94, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x9B, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x90, 0x93, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x9B, 0xCA, 0xED, 0x97, 0x00, 0x00, 0x8D, 0xB5, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0xCB, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0xCC, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x9B, 0xCF, 0x00, 0x00, /* 0x80-0x83 */ - 0x9B, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x9B, 0xCD, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x88, /* 0x88-0x8B */ - 0x9B, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x9B, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x9B, 0xD1, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0xD0, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x9B, 0xD2, 0x00, 0x00, 0x9B, 0xD3, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0xD6, /* 0xB4-0xB7 */ - 0xED, 0x98, 0xED, 0x99, 0x97, 0xE4, 0x00, 0x00, /* 0xB8-0xBB */ - 0x9B, 0xD7, 0x9B, 0xD4, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x9B, 0xD8, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x8A, 0xDE, 0x9B, 0xD9, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0xED, 0x9A, 0x00, 0x00, 0x9B, 0xDB, 0x9B, 0xDA, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0xDC, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0xDD, /* 0xD8-0xDB */ - 0x00, 0x00, 0x90, 0xEC, 0x8F, 0x42, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x8F, 0x84, 0x00, 0x00, 0x91, 0x83, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x8D, 0x48, 0x8D, 0xB6, 0x8D, 0x49, /* 0xE4-0xE7 */ - 0x8B, 0x90, 0x00, 0x00, 0x00, 0x00, 0x9B, 0xDE, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x8D, 0xB7, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x8C, 0xC8, 0x9B, 0xDF, 0x96, 0xA4, /* 0xF0-0xF3 */ - 0x94, 0x62, 0x9B, 0xE0, 0x00, 0x00, 0x8D, 0x4A, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xAA, /* 0xF8-0xFB */ - 0x00, 0x00, 0x92, 0x46, 0x8B, 0xD0, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5E[512] = { - 0x00, 0x00, 0x00, 0x00, 0x8E, 0x73, 0x95, 0x7A, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0xBF, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0xE1, /* 0x08-0x0B */ - 0x8A, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x9B, 0xE4, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x92, 0x9F, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x9B, 0xE3, 0x9B, 0xE2, 0x9B, 0xE5, /* 0x18-0x1B */ - 0x00, 0x00, 0x92, 0xE9, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x90, 0x83, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x74, /* 0x28-0x2B */ - 0x00, 0x00, 0x90, 0xC8, 0x00, 0x00, 0x91, 0xD1, /* 0x2C-0x2F */ - 0x8B, 0x41, 0x00, 0x00, 0x00, 0x00, 0x92, 0xA0, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x9B, 0xE6, 0x9B, 0xE7, /* 0x34-0x37 */ - 0x8F, 0xED, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x96, 0x58, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x9B, 0xEA, 0x00, 0x00, 0x00, 0x00, 0x9B, 0xE9, /* 0x40-0x43 */ - 0x9B, 0xE8, 0x95, 0x9D, 0x00, 0x00, 0x9B, 0xF1, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x96, 0x79, 0x00, 0x00, 0x9B, 0xEB, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x9B, 0xED, 0x96, 0x8B, 0x00, 0x00, 0x9B, 0xEC, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0xEE, /* 0x5C-0x5F */ - 0x00, 0x00, 0x94, 0xA6, 0x9B, 0xEF, 0x95, 0xBC, /* 0x60-0x63 */ - 0x9B, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x8A, 0xB1, 0x95, 0xBD, /* 0x70-0x73 */ - 0x94, 0x4E, 0x9B, 0xF2, 0x9B, 0xF3, 0x00, 0x00, /* 0x74-0x77 */ - 0x8D, 0x4B, 0x8A, 0xB2, 0x9B, 0xF4, 0x8C, 0xB6, /* 0x78-0x7B */ - 0x97, 0x63, 0x97, 0x48, 0x8A, 0xF4, 0x9B, 0xF6, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x92, 0xA1, 0x00, 0x00, 0x8D, 0x4C, /* 0x80-0x83 */ - 0x8F, 0xAF, 0x00, 0x00, 0x00, 0x00, 0x94, 0xDD, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0xB0, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x98, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x92, 0xEA, 0x95, 0xF7, 0x93, 0x58, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x8D, 0x4D, 0x00, 0x00, /* 0x98-0x9B */ - 0x95, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x9B, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x93, 0x78, 0x8D, 0xC0, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0xC9, /* 0xA8-0xAB */ - 0x00, 0x00, 0x92, 0xEB, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x88, 0xC1, 0x8F, 0x8E, 0x8D, 0x4E, /* 0xB4-0xB7 */ - 0x97, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x9B, 0xF8, 0x9B, 0xF9, 0x94, 0x70, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x9B, 0xFA, 0x97, 0xF5, 0x98, 0x4C, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9B, 0xFC, /* 0xCC-0xCF */ - 0x9B, 0xFB, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x66, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x9C, 0x40, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x9C, 0x43, 0x9C, 0x44, /* 0xD8-0xDB */ - 0x00, 0x00, 0x9C, 0x42, 0x00, 0x00, 0x95, 0x5F, /* 0xDC-0xDF */ - 0x8F, 0xB1, 0x9C, 0x46, 0x9C, 0x45, 0x9C, 0x41, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x9C, 0x47, 0x9C, 0x48, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x9C, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x9C, 0x4C, 0x9C, 0x4A, 0x00, 0x00, 0x9C, 0x4B, /* 0xF0-0xF3 */ - 0x9C, 0x4D, 0x00, 0x00, 0x89, 0x84, 0x92, 0xEC, /* 0xF4-0xF7 */ - 0x9C, 0x4E, 0x00, 0x00, 0x8C, 0x9A, 0x89, 0xF4, /* 0xF8-0xFB */ - 0x94, 0x55, 0x00, 0x00, 0x9C, 0x4F, 0x93, 0xF9, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5F[512] = { - 0x00, 0x00, 0x95, 0xD9, 0x00, 0x00, 0x9C, 0x50, /* 0x00-0x03 */ - 0x98, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x9C, 0x51, 0x95, 0xBE, 0x9C, 0x54, /* 0x08-0x0B */ - 0x98, 0x9F, 0x98, 0xAF, 0x00, 0x00, 0x8E, 0xAE, /* 0x0C-0x0F */ - 0x93, 0xF3, 0x9C, 0x55, 0x00, 0x00, 0x8B, 0x7C, /* 0x10-0x13 */ - 0x92, 0xA2, 0x88, 0xF8, 0x9C, 0x56, 0x95, 0xA4, /* 0x14-0x17 */ - 0x8D, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x92, 0x6F, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0xED, /* 0x1C-0x1F */ - 0x00, 0x00, 0xED, 0x9B, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x96, 0xED, 0x8C, 0xB7, 0x8C, 0xCA, /* 0x24-0x27 */ - 0x00, 0x00, 0x9C, 0x57, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x9C, 0x58, 0x00, 0x00, 0x9C, 0x5E, /* 0x2C-0x2F */ - 0x00, 0x00, 0x8E, 0xE3, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xED, 0x9C, 0x92, 0xA3, 0x00, 0x00, 0x8B, 0xAD, /* 0x34-0x37 */ - 0x9C, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x95, 0x4A, 0x00, 0x00, 0x92, 0x65, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x9C, 0x5A, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0xED, 0x4B, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x9C, 0x5B, 0x00, 0x00, 0x8B, 0xAE, 0x00, 0x00, /* 0x48-0x4B */ - 0x9C, 0x5C, 0x00, 0x00, 0x9C, 0x5D, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x9C, 0x5F, 0x00, 0x00, 0x93, 0x96, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x9C, 0x60, 0x9C, 0x61, /* 0x54-0x57 */ - 0x00, 0x00, 0x9C, 0x62, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x9C, 0x53, 0x9C, 0x52, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x9C, 0x63, 0x8C, 0x60, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x95, 0x46, 0xED, 0x9D, /* 0x64-0x67 */ - 0x00, 0x00, 0x8D, 0xCA, 0x95, 0x56, 0x92, 0xA4, /* 0x68-0x6B */ - 0x95, 0x6A, 0x9C, 0x64, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x8F, 0xB2, 0x89, 0x65, 0x00, 0x00, 0x9C, 0x65, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x66, /* 0x74-0x77 */ - 0x00, 0x00, 0x96, 0xF0, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x94, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x69, /* 0x7C-0x7F */ - - 0x89, 0x9D, 0x90, 0xAA, 0x9C, 0x68, 0x9C, 0x67, /* 0x80-0x83 */ - 0x8C, 0x61, 0x91, 0xD2, 0x00, 0x00, 0x9C, 0x6D, /* 0x84-0x87 */ - 0x9C, 0x6B, 0x00, 0x00, 0x9C, 0x6A, 0x97, 0xA5, /* 0x88-0x8B */ - 0x8C, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x8F, 0x99, 0x9C, 0x6C, 0x93, 0x6B, 0x8F, 0x5D, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0xBE, /* 0x94-0x97 */ - 0x9C, 0x70, 0x9C, 0x6F, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x9C, 0x6E, 0x00, 0x00, /* 0x9C-0x9F */ - 0x9C, 0x71, 0x8C, 0xE4, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x9C, 0x72, 0x95, 0x9C, 0x8F, 0x7A, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x9C, 0x73, 0x94, 0xF7, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0xBF, /* 0xB0-0xB3 */ - 0x92, 0xA5, 0x00, 0x00, 0x00, 0x00, 0xED, 0x9E, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x93, 0x4F, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x9C, 0x74, 0x8B, 0x4A, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x53, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x95, 0x4B, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x8A, 0xF5, 0x94, 0x45, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x9C, 0x75, 0x8E, 0x75, /* 0xD4-0xD7 */ - 0x96, 0x59, 0x96, 0x5A, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x89, 0x9E, 0x9C, 0x7A, 0xED, 0x9F, 0x00, 0x00, /* 0xDC-0xDF */ - 0x92, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x9C, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0xF5, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x9C, 0xAB, 0x9C, 0x79, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x94, 0x4F, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x9C, 0x78, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x76, /* 0xF8-0xFB */ - 0x00, 0x00, 0x8D, 0x9A, 0x00, 0x00, 0x9C, 0x7C, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_60[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x9C, 0x83, 0x9C, 0x89, /* 0x0C-0x0F */ - 0x9C, 0x81, 0x00, 0x00, 0x93, 0x7B, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x9C, 0x86, 0x95, 0x7C, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x9C, 0x80, 0x00, 0x00, 0x9C, 0x85, /* 0x18-0x1B */ - 0x97, 0xE5, 0x8E, 0x76, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x91, 0xD3, 0x9C, 0x7D, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x8B, 0x7D, 0x9C, 0x88, 0x90, 0xAB, /* 0x24-0x27 */ - 0x89, 0x85, 0x9C, 0x82, 0x89, 0xF6, 0x9C, 0x87, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xAF, /* 0x2C-0x2F */ - 0x00, 0x00, 0x9C, 0x84, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x9C, 0x8A, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x9C, 0x8C, 0x9C, 0x96, 0x9C, 0x94, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x9C, 0x91, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x9C, 0x90, 0x97, 0xF6, /* 0x48-0x4B */ - 0x00, 0x00, 0x9C, 0x92, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x8B, 0xB0, 0x00, 0x00, 0x8D, 0x50, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x8F, 0x9A, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x9C, 0x99, 0x9C, 0x8B, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0xED, 0xA0, 0x00, 0x00, 0x9C, 0x8F, /* 0x5C-0x5F */ - 0x9C, 0x7E, 0x00, 0x00, 0x89, 0xF8, 0x9C, 0x93, /* 0x60-0x63 */ - 0x9C, 0x95, 0x92, 0x70, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x8D, 0xA6, 0x89, 0xB6, 0x9C, 0x8D, 0x9C, 0x98, /* 0x68-0x6B */ - 0x9C, 0x97, 0x8B, 0xB1, 0x00, 0x00, 0x91, 0xA7, /* 0x6C-0x6F */ - 0x8A, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x8C, 0x62, 0x00, 0x00, 0x9C, 0x8E, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x9C, 0x9A, 0x00, 0x00, 0x9C, 0x9D, /* 0x80-0x83 */ - 0x9C, 0x9F, 0xED, 0xA1, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x8E, 0xBB, 0xED, 0xA2, 0x9C, 0xA5, /* 0x88-0x8B */ - 0x92, 0xEE, 0x9C, 0x9B, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x9C, 0xA3, 0x00, 0x00, /* 0x90-0x93 */ - 0x89, 0xF7, 0x00, 0x00, 0x9C, 0xA1, 0x9C, 0xA2, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x9C, 0x9E, 0x9C, 0xA0, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0xE5, /* 0x9C-0x9F */ - 0x97, 0x49, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xB3, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0x78, 0x9C, 0xA4, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x94, 0x59, 0x88, 0xAB, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0xDF, 0x9C, 0x7B, /* 0xB0-0xB3 */ - 0x9C, 0xAA, 0x9C, 0xAE, 0x96, 0xE3, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x9C, 0xA7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x93, 0x89, 0x9C, 0xAC, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x8F, 0xEE, 0x9C, 0xAD, 0x93, 0xD5, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x98, 0x66, 0x00, 0x00, 0x9C, 0xA9, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xED, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x9C, 0xAF, 0x00, 0x00, 0x8D, 0x9B, 0x00, 0x00, /* 0xD8-0xDB */ - 0x90, 0xC9, 0x00, 0x00, 0xED, 0xA3, 0x88, 0xD2, /* 0xDC-0xDF */ - 0x9C, 0xA8, 0x9C, 0xA6, 0x00, 0x00, 0x91, 0x79, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0x9C, /* 0xE4-0xE7 */ - 0x8E, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x91, 0xC4, 0x9C, 0xBB, 0xED, 0xA6, 0x91, 0x7A, /* 0xF0-0xF3 */ - 0x9C, 0xB6, 0x00, 0x00, 0x9C, 0xB3, 0x9C, 0xB4, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x8E, 0xE4, 0x9C, 0xB7, 0x9C, 0xBA, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_61[512] = { - 0x9C, 0xB5, 0x8F, 0x44, 0x00, 0x00, 0x9C, 0xB8, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x9C, 0xB2, 0x00, 0x00, /* 0x04-0x07 */ - 0x96, 0xFA, 0x96, 0xF9, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x9C, 0xBC, 0x9C, 0xBD, 0x88, 0xD3, /* 0x0C-0x0F */ - 0x00, 0x00, 0xED, 0xA7, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x9C, 0xB1, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0xF0, 0x88, 0xA4, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xB4, /* 0x1C-0x1F */ - 0xED, 0xA5, 0x9C, 0xB9, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xC1, /* 0x24-0x27 */ - 0x9C, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x9C, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xED, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x9C, 0xC6, 0x00, 0x00, 0x00, 0x00, 0xED, 0xA8, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x9C, 0xC4, 0x9C, 0xC7, 0x9C, 0xBF, 0x9C, 0xC3, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x9C, 0xC8, 0x00, 0x00, /* 0x40-0x43 */ - 0x9C, 0xC9, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xBE, /* 0x44-0x47 */ - 0x8E, 0x9C, 0x00, 0x00, 0x9C, 0xC2, 0x91, 0xD4, /* 0x48-0x4B */ - 0x8D, 0x51, 0x9C, 0xB0, 0x90, 0x54, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xD6, /* 0x50-0x53 */ - 0x00, 0x00, 0x95, 0xE7, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x9C, 0xCC, 0x9C, 0xCD, 0x9C, 0xCE, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x9C, 0xD5, 0x00, 0x00, 0x9C, 0xD4, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0x9D, 0x8A, 0xB5, /* 0x60-0x63 */ - 0x00, 0x00, 0x9C, 0xD2, 0x00, 0x00, 0x8C, 0x64, /* 0x64-0x67 */ - 0x8A, 0x53, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xCF, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0xB6, 0x9C, 0xD1, /* 0x6C-0x6F */ - 0x88, 0xD4, 0x9C, 0xD3, 0x00, 0x00, 0x9C, 0xCA, /* 0x70-0x73 */ - 0x9C, 0xD0, 0x9C, 0xD7, 0x8C, 0x63, 0x9C, 0xCB, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0x7C, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x97, 0x4A, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xDA, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x9C, 0xDE, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x91, 0x9E, 0x00, 0x00, /* 0x8C-0x8F */ - 0x97, 0xF7, 0x9C, 0xDF, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x9C, 0xDC, 0x00, 0x00, 0x9C, 0xD9, 0x00, 0x00, /* 0x94-0x97 */ - 0xED, 0xAA, 0x9C, 0xD8, 0x9C, 0xDD, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x95, 0xAE, 0x00, 0x00, 0x00, 0x00, 0x93, 0xB2, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x8C, 0x65, 0x00, 0x00, 0x9C, 0xE0, /* 0xA8-0xAB */ - 0x9C, 0xDB, 0x00, 0x00, 0x9C, 0xE1, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0x9B, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0xAF, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x9C, 0xE9, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x8A, 0xB6, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xE7, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x9C, 0xE8, 0x8D, 0xA7, /* 0xC4-0xC7 */ - 0x9C, 0xE6, 0x9C, 0xE4, 0x9C, 0xE3, 0x9C, 0xEA, /* 0xC8-0xCB */ - 0x9C, 0xE2, 0x9C, 0xEC, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x89, 0xF9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9C, 0xEE, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x9C, 0xED, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x92, 0xA6, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x9C, 0xF1, 0x00, 0x00, 0x9C, 0xEF, 0x9C, 0xE5, /* 0xF4-0xF7 */ - 0x8C, 0x9C, 0x00, 0x00, 0x9C, 0xF0, 0x00, 0x00, /* 0xF8-0xFB */ - 0x9C, 0xF4, 0x9C, 0xF3, 0x9C, 0xF5, 0x9C, 0xF2, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_62[512] = { - 0x9C, 0xF6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x9C, 0xF7, 0x9C, 0xF8, 0x95, 0xE8, 0x00, 0x00, /* 0x08-0x0B */ - 0x9C, 0xFA, 0x9C, 0xF9, 0x8F, 0x5E, 0x00, 0x00, /* 0x0C-0x0F */ - 0x90, 0xAC, 0x89, 0xE4, 0x89, 0xFA, 0xED, 0xAB, /* 0x10-0x13 */ - 0x9C, 0xFB, 0x00, 0x00, 0x88, 0xBD, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x90, 0xCA, 0x9C, 0xFC, /* 0x18-0x1B */ - 0x00, 0x00, 0xE6, 0xC1, 0x9D, 0x40, 0x8C, 0x81, /* 0x1C-0x1F */ - 0x00, 0x00, 0x9D, 0x41, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x90, 0xED, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0x42, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0x43, 0x8B, 0x59, /* 0x2C-0x2F */ - 0x9D, 0x44, 0x00, 0x00, 0x9D, 0x45, 0x9D, 0x46, /* 0x30-0x33 */ - 0x91, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x8C, 0xCB, 0x00, 0x00, 0x00, 0x00, 0x96, 0xDF, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x5B, /* 0x3C-0x3F */ - 0x8F, 0x8A, 0x9D, 0x47, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xEE, /* 0x44-0x47 */ - 0xE7, 0xBB, 0x94, 0xE0, 0x00, 0x00, 0x8E, 0xE8, /* 0x48-0x4B */ - 0x00, 0x00, 0x8D, 0xCB, 0x9D, 0x48, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0xC5, /* 0x50-0x53 */ - 0x00, 0x00, 0x95, 0xA5, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x91, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x9D, 0x4B, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0x49, 0x00, 0x00, /* 0x5C-0x5F */ - 0x9D, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x9D, 0x4A, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x9D, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x95, 0xAF, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x88, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x95, 0x7D, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x94, 0xE1, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x9D, 0x4E, 0x00, 0x00, 0x9D, 0x51, 0x8F, 0xB3, /* 0x7C-0x7F */ - - 0x8B, 0x5A, 0x00, 0x00, 0x9D, 0x4F, 0x9D, 0x56, /* 0x80-0x83 */ - 0x8F, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x9D, 0x50, 0x94, 0x63, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x97, 0x7D, 0x9D, 0x52, 0x9D, 0x53, /* 0x90-0x93 */ - 0x9D, 0x57, 0x93, 0x8A, 0x9D, 0x54, 0x8D, 0x52, /* 0x94-0x97 */ - 0x90, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x9D, 0x65, /* 0x98-0x9B */ - 0x94, 0xB2, 0x00, 0x00, 0x91, 0xF0, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0xAC, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0xE2, /* 0xA8-0xAB */ - 0x9D, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x95, 0xF8, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x92, 0xEF, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x96, 0x95, 0x00, 0x00, 0x9D, 0x5A, /* 0xB8-0xBB */ - 0x89, 0x9F, 0x92, 0x8A, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0x63, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x92, 0x53, 0x9D, 0x5D, 0x9D, 0x64, /* 0xC4-0xC7 */ - 0x9D, 0x5F, 0x9D, 0x66, 0x9D, 0x62, 0x00, 0x00, /* 0xC8-0xCB */ - 0x9D, 0x61, 0x94, 0x8F, 0x00, 0x00, 0x9D, 0x5B, /* 0xCC-0xCF */ - 0x89, 0xFB, 0x9D, 0x59, 0x8B, 0x91, 0x91, 0xF1, /* 0xD0-0xD3 */ - 0x9D, 0x55, 0x00, 0x00, 0x00, 0x00, 0x9D, 0x58, /* 0xD4-0xD7 */ - 0x8D, 0x53, 0x90, 0xD9, 0x00, 0x00, 0x8F, 0xB5, /* 0xD8-0xDB */ - 0x9D, 0x60, 0x94, 0x71, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x8B, 0x92, 0x8A, 0x67, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x8A, 0x87, 0x90, 0x40, 0x9D, 0x68, 0x9D, 0x6D, /* 0xEC-0xEF */ - 0x00, 0x00, 0x9D, 0x69, 0x00, 0x00, 0x8C, 0x9D, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x9D, 0x6E, 0x8E, 0x41, 0x8D, 0x89, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0x45, 0x9D, 0x5C, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_63[512] = { - 0x00, 0x00, 0x8E, 0x9D, 0x9D, 0x6B, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x77, /* 0x04-0x07 */ - 0x9D, 0x6C, 0x88, 0xC2, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x9D, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x92, 0xA7, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x8B, 0x93, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xB2, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9D, 0x6A, /* 0x24-0x27 */ - 0x88, 0xA5, 0x00, 0x00, 0x00, 0x00, 0x8D, 0xC1, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x55, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x92, 0xF0, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x94, 0xD2, 0x9D, 0x70, 0x91, 0x7D, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x91, 0xA8, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x8E, 0x4A, 0x9D, 0x71, 0x00, 0x00, 0x9D, 0x73, /* 0x4C-0x4F */ - 0x9D, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x95, 0xDF, 0x00, 0x00, 0x92, 0xBB, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x91, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0xF9, /* 0x64-0x67 */ - 0x8E, 0xCC, 0x9D, 0x80, 0x00, 0x00, 0x9D, 0x7E, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x90, 0x98, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0x9E, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0x78, 0x8F, 0xB7, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x93, 0xE6, 0x94, 0x50, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x9D, 0x76, 0x00, 0x00, 0x00, 0x00, 0x91, 0x7C, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x8E, 0xF6, 0x9D, 0x7B, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x8F, 0xB6, 0x00, 0x00, 0x9D, 0x75, 0x9D, 0x7A, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0x72, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0x74, 0x00, 0x00, /* 0x94-0x97 */ - 0x8C, 0x40, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x7C, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9D, 0x7C, /* 0x9C-0x9F */ - 0x97, 0xA9, 0x8D, 0xCC, 0x92, 0x54, 0x9D, 0x79, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x90, 0xDA, 0x00, 0x00, 0x8D, 0x54, /* 0xA4-0xA7 */ - 0x90, 0x84, 0x89, 0x86, 0x91, 0x5B, 0x9D, 0x77, /* 0xA8-0xAB */ - 0x8B, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0x66, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x92, 0xCD, 0x9D, 0x7D, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x7E, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0x81, 0x00, 0x00, /* 0xBC-0xBF */ - 0x9D, 0x83, 0x00, 0x00, 0x00, 0x00, 0x91, 0xB5, /* 0xC0-0xC3 */ - 0x9D, 0x89, 0x00, 0x00, 0x9D, 0x84, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x9D, 0x86, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x60, /* 0xCC-0xCF */ - 0x92, 0xF1, 0x00, 0x00, 0x9D, 0x87, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0x4B, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0x67, 0x8A, 0xB7, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x88, 0xAC, 0x00, 0x00, 0x9D, 0x85, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x9D, 0x82, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x8A, 0xF6, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x89, 0x87, 0xED, 0xAD, 0x9D, 0x88, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0x68, 0x00, 0x00, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_64[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0x8C, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x91, 0xB9, 0x00, 0x00, 0x9D, 0x93, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9D, 0x8D, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0x8A, 0x9D, 0x91, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x9D, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0x8E, 0x00, 0x00, /* 0x24-0x27 */ - 0x9D, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x94, 0xC0, 0x93, 0x8B, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x9D, 0x8B, 0x00, 0x00, 0x9D, 0x8F, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0x67, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x8D, 0xEF, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x90, 0xDB, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0x97, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x93, 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xED, 0xAE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9D, 0x94, /* 0x64-0x67 */ - 0x00, 0x00, 0x96, 0x80, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9D, 0x95, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0x96, 0x00, 0x00, /* 0x74-0x77 */ - 0x96, 0xCC, 0x00, 0x00, 0x90, 0xA0, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x82, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x9D, 0x9D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x8E, 0x54, 0x9D, 0x9A, /* 0x90-0x93 */ - 0x00, 0x00, 0x9D, 0x99, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0x51, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xED, 0xAF, 0x93, 0xB3, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x93, 0x50, 0x9D, 0x9B, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x9D, 0x9C, 0x00, 0x00, 0x95, 0x8F, /* 0xA8-0xAB */ - 0x00, 0x00, 0x94, 0x64, 0x8E, 0x42, 0x00, 0x00, /* 0xAC-0xAF */ - 0x90, 0xEF, 0x00, 0x00, 0x96, 0x6F, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x8A, 0x68, 0x00, 0x00, 0x9D, 0xA3, /* 0xB8-0xBB */ - 0x9D, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x97, 0x69, 0x9D, 0xA5, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x9D, 0xA1, 0x00, 0x00, 0x9D, 0xA2, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x91, 0x80, 0xED, 0xB0, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0xA0, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x9D, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x9D, 0xA4, 0x00, 0x00, 0x9D, 0x9F, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x9D, 0xA9, 0x9D, 0xAA, 0x93, 0x46, 0x9D, 0xAC, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x8E, 0x43, 0x9D, 0xA7, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x8B, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x9D, 0xAD, /* 0xEC-0xEF */ - 0x00, 0x00, 0x9D, 0xA6, 0x9D, 0xB1, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x9D, 0xB0, 0x00, 0x00, 0x9D, 0xAF, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0xB2, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x9D, 0xB4, 0x8F, 0xEF, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_65[512] = { - 0x9D, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x9D, 0xB7, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x9D, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x9D, 0xB6, 0x9D, 0x90, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9D, 0xB9, /* 0x20-0x23 */ - 0x9D, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0x98, 0x9D, 0xBA, /* 0x28-0x2B */ - 0x9D, 0xAE, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x78, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x9D, 0xBB, 0x9D, 0xBC, 0x9D, 0xBE, 0x9D, 0xBD, /* 0x34-0x37 */ - 0x9D, 0xBF, 0x89, 0xFC, 0x00, 0x00, 0x8D, 0x55, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x95, 0xFA, 0x90, 0xAD, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x8C, 0xCC, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x9D, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x9D, 0xC4, 0xED, 0xB1, 0x95, 0x71, /* 0x4C-0x4F */ - 0x00, 0x00, 0x8B, 0x7E, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x9D, 0xC3, 0x9D, 0xC2, 0x94, 0x73, /* 0x54-0x57 */ - 0x9D, 0xC5, 0x8B, 0xB3, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x9D, 0xC7, 0x9D, 0xC6, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x8A, 0xB8, 0x8E, 0x55, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x93, 0xD6, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x8C, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x90, 0x94, 0x00, 0x00, 0x9D, 0xC8, 0x00, 0x00, /* 0x70-0x73 */ - 0x90, 0xAE, 0x93, 0x47, 0x00, 0x00, 0x95, 0x7E, /* 0x74-0x77 */ - 0x9D, 0xC9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x9D, 0xCA, 0x9D, 0xCB, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0xB6, /* 0x84-0x87 */ - 0x9B, 0x7C, 0x90, 0xC4, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x95, 0x6B, 0x00, 0x00, 0x8D, 0xD6, 0x00, 0x00, /* 0x8C-0x8F */ - 0x94, 0xE3, 0x94, 0xC1, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x6C, /* 0x94-0x97 */ - 0x00, 0x00, 0x97, 0xBF, 0x00, 0x00, 0x9D, 0xCD, /* 0x98-0x9B */ - 0x8E, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x9D, 0xCE, /* 0x9C-0x9F */ - 0x00, 0x00, 0x88, 0xB4, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x8B, 0xD2, 0x90, 0xCB, 0x00, 0x00, 0x95, 0x80, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9D, 0xCF, /* 0xA8-0xAB */ - 0x8E, 0x61, 0x92, 0x66, 0x00, 0x00, 0x8E, 0x7A, /* 0xAC-0xAF */ - 0x90, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9D, 0xD0, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x95, 0xFB, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x89, 0x97, 0x8E, 0x7B, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x9D, 0xD3, 0x00, 0x00, 0x9D, 0xD1, /* 0xC0-0xC3 */ - 0x9D, 0xD4, 0x97, 0xB7, 0x9D, 0xD2, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xF9, /* 0xC8-0xCB */ - 0x9D, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x91, 0xB0, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0xD6, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xF8, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x9D, 0xD8, 0x00, 0x00, 0x9D, 0xD7, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x9D, 0xD9, 0x9D, 0xDA, 0x8A, 0xF9, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x93, 0xFA, 0x92, 0x55, 0x8B, 0x8C, /* 0xE4-0xE7 */ - 0x8E, 0x7C, 0x91, 0x81, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x8F, 0x7B, 0x88, 0xAE, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x9D, 0xDB, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0xA0, 0x9D, 0xDF, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_66[512] = { - 0xED, 0xB2, 0x00, 0x00, 0x8D, 0x56, 0x9D, 0xDE, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x8D, 0xA9, 0x8F, 0xB8, /* 0x04-0x07 */ - 0x00, 0x00, 0xED, 0xB5, 0x9D, 0xDD, 0x00, 0x00, /* 0x08-0x0B */ - 0x8F, 0xB9, 0x00, 0x00, 0x96, 0xBE, 0x8D, 0xA8, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xD5, /* 0x10-0x13 */ - 0x90, 0xCC, 0xED, 0xB3, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x9D, 0xE4, 0x00, 0x00, 0xED, 0xB7, 0x90, 0xAF, /* 0x1C-0x1F */ - 0x89, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0xED, 0xB8, 0x8F, 0x74, 0x00, 0x00, 0x96, 0x86, /* 0x24-0x27 */ - 0x8D, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x8F, 0xBA, 0xED, 0xB6, 0x90, 0xA5, /* 0x2C-0x2F */ - 0x00, 0x00, 0xED, 0x47, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x9D, 0xE3, 0x9D, 0xE1, 0x9D, 0xE2, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xB4, /* 0x38-0x3B */ - 0x92, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x45, /* 0x3C-0x3F */ - 0x00, 0x00, 0x9D, 0xE8, 0x8E, 0x9E, 0x8D, 0x57, /* 0x40-0x43 */ - 0x9D, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x9D, 0xE7, 0x00, 0x00, 0x90, 0x57, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9D, 0xE5, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x8E, 0x4E, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xBA, /* 0x54-0x57 */ - 0x00, 0x00, 0xED, 0xBB, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x9D, 0xEA, 0x9D, 0xE9, 0x9D, 0xEE, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0xEF, 0x00, 0x00, /* 0x60-0x63 */ - 0x9D, 0xEB, 0xED, 0xB9, 0x8A, 0x41, 0x9D, 0xEC, /* 0x64-0x67 */ - 0x9D, 0xED, 0x94, 0xD3, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x95, 0x81, 0x8C, 0x69, /* 0x6C-0x6F */ - 0x9D, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xED, 0xBD, /* 0x70-0x73 */ - 0x90, 0xB0, 0x00, 0x00, 0x8F, 0xBB, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x92, 0x71, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x8B, 0xC5, 0x00, 0x00, 0x9D, 0xF1, /* 0x80-0x83 */ - 0x9D, 0xF5, 0x00, 0x00, 0x00, 0x00, 0x89, 0xC9, /* 0x84-0x87 */ - 0x9D, 0xF2, 0x9D, 0xF4, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0xF3, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x8F, 0x8B, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x92, 0x67, 0x88, 0xC3, /* 0x94-0x97 */ - 0x9D, 0xF6, 0xED, 0xBE, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x9D, 0xF7, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xED, 0xBF, 0x00, 0x00, 0x92, 0xA8, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0xEF, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x62, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x95, 0xE9, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0xC0, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x96, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x9E, 0x41, 0x9D, 0xF9, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x9D, 0xFC, 0x00, 0x00, 0x9D, 0xFB, 0xED, 0xC1, /* 0xBC-0xBF */ - 0x00, 0x00, 0x9D, 0xF8, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x9E, 0x40, 0x00, 0x00, 0x00, 0x00, 0x93, 0xDC, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x9D, 0xFA, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0x42, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x8F, 0x8C, 0x9E, 0x43, 0x00, 0x00, /* 0xD8-0xDB */ - 0x97, 0x6A, 0x94, 0x98, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x9E, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0x46, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x9E, 0x47, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x9E, 0x48, 0x00, 0x00, 0x8B, 0xC8, 0x89, 0x67, /* 0xF0-0xF3 */ - 0x8D, 0x58, 0x9E, 0x49, 0x00, 0x00, 0x9E, 0x4A, /* 0xF4-0xF7 */ - 0x8F, 0x91, 0x91, 0x82, 0xED, 0xC2, 0xED, 0x4A, /* 0xF8-0xFB */ - 0x99, 0xD6, 0x91, 0x5D, 0x91, 0x5C, 0x91, 0xD6, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_67[512] = { - 0x8D, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x98, 0xF0, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x8C, 0x8E, 0x97, 0x4C, 0x00, 0x00, 0x95, 0xFC, /* 0x08-0x0B */ - 0x00, 0x00, 0x95, 0x9E, 0xED, 0xC3, 0x9E, 0x4B, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x8D, 0xF1, 0x92, 0xBD, 0x9E, 0x4C, 0x98, 0x4E, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x5D, /* 0x18-0x1B */ - 0x00, 0x00, 0x92, 0xA9, 0x9E, 0x4D, 0x8A, 0xFA, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0x4E, 0x9E, 0x4F, /* 0x24-0x27 */ - 0x96, 0xD8, 0x00, 0x00, 0x96, 0xA2, 0x96, 0x96, /* 0x28-0x2B */ - 0x96, 0x7B, 0x8E, 0x44, 0x9E, 0x51, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x8E, 0xE9, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x96, 0x70, 0x00, 0x00, 0x9E, 0x53, 0x9E, 0x56, /* 0x34-0x37 */ - 0x9E, 0x55, 0x00, 0x00, 0x8A, 0xF7, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x8B, 0x80, 0x00, 0x00, 0x9E, 0x52, /* 0x3C-0x3F */ - 0x00, 0x00, 0x9E, 0x54, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0x57, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x90, 0x99, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0x9B, 0x88, 0xC7, /* 0x4C-0x4F */ - 0x8D, 0xDE, 0x91, 0xBA, 0x00, 0x00, 0x8E, 0xDB, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0xF1, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x9E, 0x5A, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x93, 0x6D, 0x00, 0x00, 0x9E, 0x58, 0x91, 0xA9, /* 0x5C-0x5F */ - 0x9E, 0x59, 0x8F, 0xF0, 0x96, 0xDB, 0x9E, 0x5B, /* 0x60-0x63 */ - 0x9E, 0x5C, 0x97, 0x88, 0xED, 0xC5, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0x61, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x8D, 0x59, 0x00, 0x00, 0x94, 0x74, /* 0x6C-0x6F */ - 0x9E, 0x5E, 0x93, 0x8C, 0x9D, 0xDC, 0x9D, 0xE0, /* 0x70-0x73 */ - 0x00, 0x00, 0x8B, 0x6E, 0x00, 0x00, 0x94, 0x66, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x9E, 0x60, 0x00, 0x00, 0x8F, 0xBC, 0x94, 0xC2, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x9E, 0x66, 0x00, 0x00, 0x94, 0xF8, /* 0x84-0x87 */ - 0x00, 0x00, 0x9E, 0x5D, 0x00, 0x00, 0x9E, 0x63, /* 0x88-0x8B */ - 0x9E, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x90, 0xCD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x96, 0x8D, 0x00, 0x00, 0x97, 0xD1, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0x87, 0x00, 0x00, /* 0x98-0x9B */ - 0x89, 0xCA, 0x8E, 0x7D, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x98, 0x67, 0x9E, 0x65, 0x90, 0x95, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0x64, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x9E, 0x5F, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0xCD, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x6B, /* 0xB0-0xB3 */ - 0x9E, 0x69, 0x00, 0x00, 0x89, 0xCB, 0x9E, 0x67, /* 0xB4-0xB7 */ - 0x9E, 0x6D, 0x9E, 0x73, 0x00, 0x00, 0xED, 0xC6, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xED, 0xC8, 0x91, 0xC6, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x95, 0xBF, 0x00, 0x00, 0x9E, 0x75, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x95, 0x41, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0x74, 0x94, 0x90, /* 0xCC-0xCF */ - 0x96, 0x5E, 0x8A, 0xB9, 0x00, 0x00, 0x90, 0xF5, /* 0xD0-0xD3 */ - 0x8F, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x92, 0xD1, 0x00, 0x00, 0x97, 0x4D, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x9E, 0x70, 0x9E, 0x6F, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0x71, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x9E, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x76, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x9E, 0x6C, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x9E, 0x6A, 0x00, 0x00, 0x9E, 0x72, 0x9E, 0x68, /* 0xEC-0xEF */ - 0x00, 0x00, 0x92, 0x8C, 0x00, 0x00, 0x96, 0xF6, /* 0xF0-0xF3 */ - 0x8E, 0xC4, 0x8D, 0xF2, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8D, 0xB8, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0x8F, 0x8A, 0x60, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_68[512] = { - 0x00, 0x00, 0xED, 0xC9, 0x92, 0xCC, 0x93, 0xC8, /* 0x00-0x03 */ - 0x89, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xF0, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x90, 0xB2, 0x8C, 0x49, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0x78, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x8D, 0x5A, 0x8A, 0x9C, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x9E, 0x7A, 0x8A, 0x94, 0x9E, 0x81, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0x7D, 0x00, 0x00, /* 0x30-0x33 */ - 0x90, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x8A, 0x6A, 0x8D, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x8A, 0x69, 0x8D, 0xCD, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x9E, 0x7B, 0x8C, 0x85, 0x8C, 0x6A, 0x93, 0x8D, /* 0x40-0x43 */ - 0xED, 0xCA, 0x00, 0x00, 0x9E, 0x79, 0x00, 0x00, /* 0x44-0x47 */ - 0x88, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x9E, 0x7C, 0x9E, 0x7E, 0x00, 0x00, /* 0x4C-0x4F */ - 0x8B, 0xCB, 0x8C, 0x4B, 0xED, 0xC7, 0x8A, 0xBA, /* 0x50-0x53 */ - 0x8B, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x9E, 0x82, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x8D, 0xF7, 0x96, 0x91, 0x00, 0x00, 0x8E, 0x56, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x83, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x4F, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x9E, 0x8F, 0x00, 0x00, 0x89, 0xB1, 0x9E, 0x84, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0x95, 0x9E, 0x85, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x97, 0xC0, 0x00, 0x00, 0x9E, 0x8C, /* 0x80-0x83 */ - 0x00, 0x00, 0x94, 0x7E, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x9E, 0x94, 0x00, 0x00, 0x9E, 0x87, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xB2, /* 0x90-0x93 */ - 0x9E, 0x89, 0x00, 0x00, 0x00, 0x00, 0x8D, 0x5B, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, 0x8B, /* 0x98-0x9B */ - 0x00, 0x00, 0x9E, 0x8A, 0x00, 0x00, 0x9E, 0x86, /* 0x9C-0x9F */ - 0x9E, 0x91, 0x00, 0x00, 0x8F, 0xBD, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x9A, 0xEB, 0x8C, 0xE6, /* 0xA4-0xA7 */ - 0x97, 0x9C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x9E, 0x88, 0x00, 0x00, 0x92, 0xF2, /* 0xAC-0xAF */ - 0x8A, 0x42, 0x8D, 0xAB, 0x00, 0x00, 0x9E, 0x80, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x9E, 0x90, 0x8A, 0x81, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x9E, 0x8E, 0x9E, 0x92, 0x00, 0x00, /* 0xB8-0xBB */ - 0x93, 0x8E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x8A, 0xFC, 0x00, 0x00, 0x9E, 0xB0, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xED, 0x48, 0x96, 0xC7, 0x9E, 0x97, 0x8A, 0xFB, /* 0xC8-0xCB */ - 0x00, 0x00, 0x9E, 0x9E, 0x00, 0x00, 0xED, 0xCB, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0x5F, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x9E, 0x9F, 0x9E, 0xA1, 0x00, 0x00, 0x9E, 0xA5, /* 0xD4-0xD7 */ - 0x9E, 0x99, 0x00, 0x00, 0x92, 0x49, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x8F, /* 0xDC-0xDF */ - 0x9E, 0xA9, 0x9E, 0x9C, 0x00, 0x00, 0x9E, 0xA6, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, 0xA0, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x90, 0x58, 0x9E, 0xAA, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x90, 0xB1, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x9E, 0xA8, 0x8A, 0xBB, 0x00, 0x00, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_69[512] = { - 0x98, 0x6F, 0x9E, 0x96, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x9E, 0xA4, 0x88, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x9E, 0x98, 0x00, 0x00, 0x00, 0x00, 0x96, 0xB8, /* 0x08-0x0B */ - 0x9E, 0x9D, 0x90, 0x41, 0x92, 0xC5, 0x9E, 0x93, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0xA3, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x90, 0x9A, 0x9E, 0xAD, 0x8A, 0x91, /* 0x18-0x1B */ - 0x8C, 0x9F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x9E, 0xAF, 0x9E, 0x9A, 0x9E, 0xAE, /* 0x20-0x23 */ - 0x00, 0x00, 0x9E, 0xA7, 0x9E, 0x9B, 0x00, 0x00, /* 0x24-0x27 */ - 0x9E, 0xAB, 0x00, 0x00, 0x9E, 0xAC, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x9E, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x93, 0xCC, 0x00, 0x00, 0x9E, 0xA2, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x9E, 0xB9, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x9E, 0xBB, 0x00, 0x00, 0x92, 0xD6, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0x6B, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x96, /* 0x50-0x53 */ - 0x9E, 0xB6, 0x91, 0xC8, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x9E, 0xBC, 0x91, 0x5E, 0x00, 0x00, /* 0x58-0x5B */ - 0x9E, 0xB3, 0x9E, 0xC0, 0x9E, 0xBF, 0x00, 0x00, /* 0x5C-0x5F */ - 0x93, 0xED, 0x9E, 0xBE, 0x93, 0xE8, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xED, 0xCD, 0x00, 0x00, 0x9E, 0xC2, 0x9E, 0xB5, /* 0x68-0x6B */ - 0x00, 0x00, 0x8B, 0xC6, 0x9E, 0xB8, 0x8F, 0x7C, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x80, /* 0x70-0x73 */ - 0x9E, 0xBA, 0x8B, 0xC9, 0x00, 0x00, 0x9E, 0xB2, /* 0x74-0x77 */ - 0x9E, 0xB4, 0x9E, 0xB1, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x98, 0x4F, 0x8A, 0x79, 0x9E, 0xB7, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x9E, 0xC1, 0x8A, 0x54, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x8D, 0xE5, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0x7C, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x9E, 0xD2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x98, 0x50, 0x9E, 0xD5, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xED, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x90, 0x59, /* 0x98-0x9B */ - 0x9E, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x9E, 0xD3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, 0xD0, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0xC4, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x9E, 0xE1, 0x9E, 0xC3, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x9E, 0xD6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, 0xCE, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0xC9, 0x9E, 0xC6, /* 0xBC-0xBF */ - 0x00, 0x00, 0x9E, 0xC7, 0x00, 0x00, 0x9E, 0xCF, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0xA0, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0xCC, 0x8D, 0x5C, /* 0xC8-0xCB */ - 0x92, 0xC6, 0x91, 0x84, 0x9E, 0xCA, 0x00, 0x00, /* 0xCC-0xCF */ - 0x9E, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x9E, 0xC8, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x97, 0x6C, 0x96, 0x8A, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x9E, 0xCD, 0x9E, 0xD7, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0xD0, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9E, 0xDF, /* 0xE4-0xE7 */ - 0x9E, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x9E, 0xE5, /* 0xE8-0xEB */ - 0x00, 0x00, 0x9E, 0xE3, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0xDE, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x9E, 0xDD, 0x00, 0x00, 0x92, 0xCE, /* 0xF8-0xFB */ - 0x00, 0x00, 0x91, 0x85, 0x00, 0x00, 0x9E, 0xDB, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_6A[512] = { - 0x00, 0x00, 0x00, 0x00, 0x9E, 0xD9, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x9E, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0xE6, 0x94, 0xF3, /* 0x08-0x0B */ - 0x9E, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0xE7, 0x9E, 0xEA, /* 0x10-0x13 */ - 0x9E, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x92, 0x94, /* 0x14-0x17 */ - 0x00, 0x00, 0x95, 0x57, 0x00, 0x00, 0x9E, 0xDA, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0xE2, 0x8F, 0xBE, /* 0x1C-0x1F */ - 0x00, 0x00, 0x96, 0xCD, 0x9E, 0xF6, 0x9E, 0xE9, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x8C, 0xA0, 0x89, 0xA1, 0x8A, 0x7E, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0xD1, 0x00, 0x00, /* 0x2C-0x2F */ - 0xED, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x8F, 0xBF, 0x9E, 0xEE, 0x00, 0x00, /* 0x34-0x37 */ - 0x9E, 0xF5, 0x8E, 0xF7, 0x8A, 0x92, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x92, 0x4D, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x9E, 0xEB, 0x00, 0x00, 0xED, 0xD3, 0x9E, 0xF0, /* 0x44-0x47 */ - 0x9E, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xB4, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x8B, 0x6B, 0x9E, 0xF2, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x40, /* 0x5C-0x5F */ - 0x00, 0x00, 0x93, 0xC9, 0x9E, 0xF1, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0xF3, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xD2, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0xED, 0xED, 0xD4, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x9E, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0xD5, 0x8A, 0x80, /* 0x7C-0x7F */ - - 0x92, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x9E, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x9E, 0xF8, 0x8C, 0xE7, 0x00, 0x00, /* 0x8C-0x8F */ - 0x9E, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x40, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x9E, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x9E, 0xF9, 0x00, 0x00, 0x9E, 0xFB, 0x9E, 0xFC, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0x4B, 0x00, 0x00, /* 0xA8-0xAB */ - 0x9F, 0x47, 0x00, 0x00, 0x9E, 0x8D, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x46, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x9F, 0x45, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x42, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x9E, 0xE8, 0x9F, 0x44, 0x9F, 0x43, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x9F, 0x49, 0x00, 0x00, 0x98, 0x45, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0x4C, 0x8B, 0xF9, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0x48, 0x9F, 0x4A, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0xD6, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xED, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x94, 0xA5, 0x00, 0x00, 0x9F, 0x4D, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0x51, 0x9F, 0x4E, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_6B[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x97, 0x93, 0x9F, 0x4F, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x9E, 0xDC, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0x52, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0x53, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x89, 0x54, 0x00, 0x00, 0x9F, 0x55, /* 0x1C-0x1F */ - 0x8C, 0x87, 0x8E, 0x9F, 0x00, 0x00, 0x8B, 0xD3, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0xA2, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0x7E, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x57, /* 0x34-0x37 */ - 0x9F, 0x56, 0x9F, 0x59, 0x8B, 0x5C, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x8B, 0xD4, 0x8A, 0xBC, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x5C, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x5B, /* 0x44-0x47 */ - 0x00, 0x00, 0x9F, 0x5D, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x89, 0xCC, 0x00, 0x00, 0x92, 0x56, 0x00, 0x00, /* 0x4C-0x4F */ - 0x9F, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xBD, /* 0x50-0x53 */ - 0x9F, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x9F, 0x5F, 0x00, 0x00, 0x9F, 0x61, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x62, /* 0x5C-0x5F */ - 0x00, 0x00, 0x9F, 0x63, 0x8E, 0x7E, 0x90, 0xB3, /* 0x60-0x63 */ - 0x8D, 0x9F, 0x00, 0x00, 0x95, 0x90, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x95, 0xE0, 0x98, 0x63, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x95, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8D, 0xCE, /* 0x70-0x73 */ - 0x97, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x9F, 0x64, 0x9F, 0x65, 0x00, 0x00, 0x8E, 0x80, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x66, /* 0x7C-0x7F */ - - 0x9F, 0x67, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x69, /* 0x80-0x83 */ - 0x9F, 0x68, 0x00, 0x00, 0x96, 0x77, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x8F, 0x7D, 0x8E, 0xEA, 0x8E, 0x63, /* 0x88-0x8B */ - 0x00, 0x00, 0x9F, 0x6A, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x9F, 0x6C, 0x90, 0x42, 0x00, 0x00, /* 0x94-0x97 */ - 0x9F, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0x6D, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x9F, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0x6F, 0x9F, 0x70, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x71, /* 0xAC-0xAF */ - 0x00, 0x00, 0x9F, 0x73, 0x9F, 0x72, 0x9F, 0x74, /* 0xB0-0xB3 */ - 0x89, 0xA3, 0x92, 0x69, 0x00, 0x00, 0x9F, 0x75, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x8E, 0x45, 0x8A, 0x6B, /* 0xB8-0xBB */ - 0x9F, 0x76, 0x00, 0x00, 0x00, 0x00, 0x93, 0x61, /* 0xBC-0xBF */ - 0x9A, 0xCA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x8B, 0x42, 0x9F, 0x77, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x78, /* 0xC8-0xCB */ - 0x00, 0x00, 0x95, 0xEA, 0x96, 0x88, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x93, 0xC5, 0x9F, 0x79, /* 0xD0-0xD3 */ - 0x94, 0xE4, 0x00, 0x00, 0xED, 0xD8, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x94, 0xF9, 0x00, 0x00, 0x00, 0x00, 0x96, 0xD1, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x7A, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x7C, /* 0xE8-0xEB */ - 0x9F, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x7E, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x7D, /* 0xF0-0xF3 */ -}; - -static const unsigned char u2c_6C[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x9F, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x81, /* 0x0C-0x0F */ - 0x00, 0x00, 0x96, 0xAF, 0x00, 0x00, 0x9F, 0x82, /* 0x10-0x13 */ - 0x9F, 0x83, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x43, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x84, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x86, /* 0x20-0x23 */ - 0x9F, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x90, 0x85, 0x00, 0x00, 0x00, 0x00, 0x95, 0x58, /* 0x34-0x37 */ - 0x89, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0xC3, 0xED, 0xD9, /* 0x3C-0x3F */ - 0x92, 0xF3, 0x8F, 0x60, 0x8B, 0x81, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0xC4, 0x00, 0x00, /* 0x4C-0x4F */ - 0x8E, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x9F, 0x88, 0x00, 0x00, 0x8A, 0xBE, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0x98, 0x00, 0x00, /* 0x58-0x5B */ - 0xED, 0xDA, 0x93, 0xF0, 0x9F, 0x87, 0x8D, 0x5D, /* 0x5C-0x5F */ - 0x92, 0x72, 0x00, 0x00, 0x9F, 0x89, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x9F, 0x91, 0x00, 0x00, 0x9F, 0x8A, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xDC, /* 0x6C-0x6F */ - 0x91, 0xBF, 0x00, 0x00, 0x8B, 0x82, 0x9F, 0x92, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0x88, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x8B, 0x44, 0x9F, 0x90, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x9F, 0x8E, 0x9F, 0x8B, 0x97, 0x80, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0xDB, 0x00, 0x00, /* 0x84-0x87 */ - 0x92, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x93, 0xD7, 0x9F, 0x8C, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x9F, 0x94, 0x00, 0x00, 0x9F, 0x93, 0x8C, 0x42, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0xAB, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x8D, 0xB9, 0x9F, 0x8D, 0x9F, 0x8F, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x96, 0x76, 0x91, 0xF2, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x97, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0x9C, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x9F, 0x9D, 0x00, 0x00, 0x89, 0xCD, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x95, 0xA6, 0x96, 0xFB, 0x9F, 0x9F, 0x8E, 0xA1, /* 0xB8-0xBB */ - 0x8F, 0xC0, 0x9F, 0x98, 0x9F, 0x9E, 0x89, 0x88, /* 0xBC-0xBF */ - 0x00, 0x00, 0x8B, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x9F, 0x95, 0x9F, 0x9A, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x90, 0xF2, 0x94, 0x91, 0x00, 0x00, /* 0xC8-0xCB */ - 0x94, 0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0x97, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x96, 0x40, 0x00, 0x00, 0x9F, 0x99, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x9F, 0xA2, 0xED, 0xDD, 0x9F, 0xA0, /* 0xD8-0xDB */ - 0x00, 0x00, 0x9F, 0x9B, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x96, 0x41, 0x94, 0x67, 0x8B, 0x83, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x93, 0x44, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x92, 0x8D, 0x00, 0x00, 0x9F, 0xA3, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0xA1, /* 0xEC-0xEF */ - 0x91, 0xD7, 0x9F, 0x96, 0x00, 0x00, 0x89, 0x6A, /* 0xF0-0xF3 */ -}; - -static const unsigned char u2c_6D[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xED, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x6D, /* 0x08-0x0B */ - 0x9F, 0xAE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0xAD, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xF4, /* 0x14-0x17 */ - 0x00, 0x00, 0x9F, 0xAA, 0x00, 0x00, 0x97, 0x8C, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x93, 0xB4, 0x9F, 0xA4, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x92, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x89, 0x6B, 0x8D, 0x5E, 0x9F, 0xA7, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0x46, 0x9F, 0xAC, /* 0x30-0x33 */ - 0x00, 0x00, 0x9F, 0xAB, 0x9F, 0xA6, 0x00, 0x00, /* 0x34-0x37 */ - 0x9F, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x88, /* 0x38-0x3B */ - 0x00, 0x00, 0x9F, 0xA8, 0x94, 0x68, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x97, 0xAC, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x8F, 0xF2, 0x90, 0xF3, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x9F, 0xB4, 0x9F, 0xB2, 0x00, 0x00, /* 0x58-0x5B */ - 0x95, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0xAF, /* 0x60-0x63 */ - 0x9F, 0xB1, 0x00, 0x00, 0x89, 0x59, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x8D, 0x5F, 0x98, 0x51, 0x00, 0x00, /* 0x68-0x6B */ - 0x8A, 0x5C, 0x00, 0x00, 0x95, 0x82, 0xED, 0xE0, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x97, 0x81, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x43, /* 0x74-0x77 */ - 0x90, 0x5A, 0x9F, 0xB3, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x9F, 0xB8, 0x00, 0x00, 0xED, 0xDF, /* 0x84-0x87 */ - 0x8F, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x97, 0x4F, 0x00, 0x00, 0x9F, 0xB5, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0xB0, /* 0x90-0x93 */ - 0x00, 0x00, 0x9F, 0xB6, 0xED, 0xE1, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x97, 0xDC, 0x00, 0x00, 0x93, 0x93, /* 0x98-0x9B */ - 0x93, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xED, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x55, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0x74, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x9F, 0xBC, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x9F, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x97, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x97, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x9F, 0xC6, 0x9F, 0xC0, 0x9F, 0xBD, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0xD2, /* 0xC8-0xCB */ - 0x9F, 0xC3, 0x00, 0x00, 0x00, 0x00, 0xED, 0xE3, /* 0xCC-0xCF */ - 0x00, 0x00, 0x8F, 0x69, 0x9F, 0xC5, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x9F, 0xCA, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x93, 0x91, 0x9F, 0xC8, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0xC2, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x92, 0x57, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x9F, 0xC9, 0x00, 0x00, 0x9F, 0xBE, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x9F, 0xC4, 0x00, 0x00, 0x9F, 0xCB, 0x88, 0xFA, /* 0xE8-0xEB */ - 0x9F, 0xC1, 0x00, 0x00, 0x9F, 0xCC, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x90, 0x5B, 0xED, 0xE5, 0x8F, 0x7E, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x95, 0xA3, 0x00, 0x00, 0x8D, 0xAC, /* 0xF4-0xF7 */ - 0xED, 0xE4, 0x9F, 0xB9, 0x9F, 0xC7, 0x93, 0x59, /* 0xF8-0xFB */ - 0xED, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_6E[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x90, 0xB4, 0x00, 0x00, 0x8A, 0x89, /* 0x04-0x07 */ - 0x8D, 0xCF, 0x8F, 0xC2, 0x9F, 0xBB, 0x8F, 0x61, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x6B, /* 0x10-0x13 */ - 0x00, 0x00, 0x9F, 0xBA, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x9F, 0xD0, 0x8F, 0x8D, 0x8C, 0xB8, /* 0x18-0x1B */ - 0x00, 0x00, 0x9F, 0xDF, 0x00, 0x00, 0x9F, 0xD9, /* 0x1C-0x1F */ - 0x8B, 0x94, 0x93, 0x6E, 0x00, 0x00, 0x9F, 0xD4, /* 0x20-0x23 */ - 0x9F, 0xDD, 0x88, 0xAD, 0x89, 0x51, 0xED, 0xE9, /* 0x24-0x27 */ - 0x00, 0x00, 0x89, 0xB7, 0x00, 0x00, 0x9F, 0xD6, /* 0x28-0x2B */ - 0x91, 0xAA, 0x9F, 0xCD, 0x9F, 0xCF, 0x8D, 0x60, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x9F, 0xE0, 0xED, 0xE7, 0x9F, 0xDB, 0x00, 0x00, /* 0x38-0x3B */ - 0xED, 0xEA, 0x00, 0x00, 0x9F, 0xD3, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0xDA, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0xA9, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x9F, 0xD8, 0x9F, 0xDC, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0xCE, 0x00, 0x00, /* 0x54-0x57 */ - 0x8F, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x92, 0x58, /* 0x58-0x5B */ - 0xED, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x9F, 0xD2, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x4E, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0xD5, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0xCE, 0x93, 0x92, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0xD1, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0xD7, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x98, 0x70, 0x8E, 0xBC, /* 0x7C-0x7F */ - - 0x96, 0x9E, 0x00, 0x00, 0x9F, 0xE1, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x94, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x9F, 0xED, /* 0x8C-0x8F */ - 0x8C, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0x80, 0x00, 0x00, /* 0x94-0x97 */ - 0x9F, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x97, 0xAD, 0x8D, 0x61, 0x00, 0x00, 0x9F, 0xF0, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x88, 0xEC, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x9F, 0xEE, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0xE2, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9F, 0xE8, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0xEA, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0x6E, 0x9F, 0xE5, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x93, 0x4D, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x9F, 0xE7, 0x00, 0x00, 0xED, 0xEB, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0xEF, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x9F, 0xE9, 0x96, 0xC5, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x9F, 0xE4, 0x00, 0x00, 0x8E, 0xA0, /* 0xC8-0xCB */ - 0x9F, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x8A, 0x8A, 0x00, 0x00, 0x9F, 0xE6, /* 0xD0-0xD3 */ - 0x9F, 0xEB, 0x9F, 0xEC, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x91, 0xEA, 0x91, 0xD8, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x9F, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x9F, 0xFA, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0xF8, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x93, 0x48, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x42, /* 0xF4-0xF7 */ - 0x9F, 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0xF6, 0x9F, 0xDE, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_6F[512] = { - 0x00, 0x00, 0x8B, 0x99, 0x95, 0x59, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x8E, 0xBD, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x8D, 0x97, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x52, /* 0x0C-0x0F */ - 0x00, 0x00, 0x9F, 0xF2, 0x00, 0x00, 0xE0, 0x41, /* 0x10-0x13 */ - 0x89, 0x89, 0x91, 0x86, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x94, 0x99, 0x00, 0x00, 0x8A, 0xBF, 0x97, 0xF8, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x9F, /* 0x28-0x2B */ - 0x92, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x9F, 0xF9, 0x9F, 0xFB, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x91, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0x40, 0x9F, 0xF7, /* 0x3C-0x3F */ - 0x00, 0x00, 0x9F, 0xF1, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x8A, 0xC1, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x8C, 0x89, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xE0, 0x4E, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x49, /* 0x58-0x5B */ - 0x90, 0xF6, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x83, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x8F, 0x81, 0x00, 0x00, 0xE0, 0x52, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0xE0, 0x4B, 0x92, 0xAA, 0xE0, 0x48, /* 0x6C-0x6F */ - 0x92, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xE0, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0xE0, 0x45, 0x00, 0x00, 0xE0, 0x44, 0x00, 0x00, /* 0x78-0x7B */ - 0xE0, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xE0, 0x47, 0xE0, 0x46, 0xE0, 0x4C, 0x00, 0x00, /* 0x80-0x83 */ - 0x90, 0x9F, 0x00, 0x00, 0xE0, 0x43, 0x00, 0x00, /* 0x84-0x87 */ - 0xED, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0x4F, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xE0, 0x50, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xC0, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xE0, 0x55, 0x00, 0x00, 0xE0, 0x54, /* 0xA0-0xA3 */ - 0xE0, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0x59, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x93, 0x62, 0x00, 0x00, 0xE0, 0x53, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xED, 0xED, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xE0, 0x57, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x8C, 0x83, 0x91, 0xF7, 0xE0, 0x51, 0x94, 0x5A, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0x58, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xE0, 0x5D, 0xE0, 0x5B, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xE0, 0x5E, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x61, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x5A, /* 0xDC-0xDF */ - 0x8D, 0x8A, 0x94, 0x47, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x9F, 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x94, /* 0xE8-0xEB */ - 0xE0, 0x5C, 0x00, 0x00, 0xE0, 0x60, 0x91, 0xF3, /* 0xEC-0xEF */ - 0x00, 0x00, 0xE0, 0x5F, 0x00, 0x00, 0xE0, 0x4A, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xED, 0xEE, 0xE8, 0x89, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0x64, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0x68, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_70[512] = { - 0x00, 0x00, 0xE0, 0x66, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xED, 0xEF, 0x00, 0x00, 0xED, 0xF0, /* 0x04-0x07 */ - 0x00, 0x00, 0xE0, 0x62, 0x00, 0x00, 0xE0, 0x63, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x67, /* 0x0C-0x0F */ - 0x00, 0x00, 0xE0, 0x65, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x95, 0x6D, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xE0, 0x6D, 0x00, 0x00, 0xE0, 0x6A, 0xE0, 0x69, /* 0x18-0x1B */ - 0x00, 0x00, 0xE0, 0x6C, 0x93, 0xD2, 0xE0, 0x6E, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x92, 0x95, 0x91, 0xEB, /* 0x24-0x27 */ - 0xED, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x90, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xE0, 0x6F, 0x00, 0x00, 0xE0, 0x71, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0x70, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x9F, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0xE0, 0x72, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x93, 0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x73, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0xCE, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x94, /* 0x6C-0x6F */ - 0x8A, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x8B, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x8E, 0xDC, 0x8D, 0xD0, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0xED, 0xF2, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x98, 0x46, 0x90, 0x86, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0x8A, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0x75, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xE0, 0x74, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xF3, /* 0xA8-0xAB */ - 0xE0, 0x78, 0x92, 0x59, 0xE0, 0x7B, 0xE0, 0x76, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x7A, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xE0, 0x79, 0x93, 0x5F, 0x88, 0xD7, 0xED, 0x46, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x97, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x7D, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x47, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xE0, 0x80, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0xE0, 0x7E, 0x00, 0x00, 0xE0, 0x7C, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0xE0, 0x77, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x96, 0x42, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xE0, 0x82, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_71[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xED, 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xE0, 0x81, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xF4, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x89, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xE0, 0x84, 0x95, 0xB0, 0x00, 0x00, /* 0x18-0x1B */ - 0xE0, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x96, 0xB3, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0xC5, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x91, 0x52, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x8F, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0xF7, 0xED, 0xF8, /* 0x44-0x47 */ - 0x00, 0x00, 0x97, 0xF9, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xE0, 0x8A, 0x00, 0x00, 0x90, 0xF7, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xE0, 0x86, 0xE0, 0x8B, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x89, 0x8C, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0xED, 0xF6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0x89, 0x00, 0x00, /* 0x60-0x63 */ - 0x94, 0x81, 0xE0, 0x85, 0xE0, 0x88, 0x8F, 0xC6, /* 0x64-0x67 */ - 0x00, 0x00, 0x94, 0xCF, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0xE0, 0x8C, 0x00, 0x00, 0x8E, 0xCF, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x90, 0xF8, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xE0, 0x8F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xE0, 0x87, 0x00, 0x00, 0x8C, 0x46, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x8D, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x97, 0x6F, 0xE0, 0x90, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xEA, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x6E, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xE0, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xE0, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x94, 0x4D, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xE0, 0x94, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0x95, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xED, 0xFA, 0x00, 0x00, 0x94, 0x52, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x93, 0x95, 0xE0, 0x97, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0x99, 0x00, 0x00, /* 0xCC-0xCF */ - 0x97, 0xD3, 0x00, 0x00, 0xE0, 0x96, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xE0, 0x98, 0x89, 0x8D, 0x00, 0x00, 0xE0, 0x93, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9A, 0x7A, /* 0xDC-0xDF */ - 0xE0, 0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x91, 0x87, 0x8E, 0x57, 0xE0, 0x9C, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xE0, 0x9B, 0x90, 0x43, 0x99, 0xD7, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xE0, 0x9D, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xE0, 0x9F, 0x00, 0x00, 0xE0, 0x8E, /* 0xF8-0xFB */ - 0xE0, 0x9E, 0x00, 0x00, 0xED, 0xFB, 0xE0, 0xA0, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_72[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0x9A, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0xE0, 0xA1, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xE0, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xA3, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xE0, 0xA4, 0x00, 0x00, 0x92, 0xDC, 0x00, 0x00, /* 0x28-0x2B */ - 0xE0, 0xA6, 0xE0, 0xA5, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xE0, 0xA7, 0x00, 0x00, 0xE0, 0xA8, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x8E, 0xDD, 0x95, 0x83, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0xEA, 0xE0, 0xA9, /* 0x38-0x3B */ - 0xE0, 0xAA, 0x91, 0x75, 0x8E, 0xA2, 0xE0, 0xAB, /* 0x3C-0x3F */ - 0xE0, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xAD, 0x95, 0xD0, /* 0x44-0x47 */ - 0x94, 0xC5, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xAE, /* 0x48-0x4B */ - 0x94, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x92, 0xAB, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xE0, 0xAF, 0x89, 0xE5, 0x00, 0x00, 0x8B, 0x8D, /* 0x58-0x5B */ - 0x00, 0x00, 0x96, 0xC4, 0x00, 0x00, 0x96, 0xB4, /* 0x5C-0x5F */ - 0x00, 0x00, 0x89, 0xB2, 0x98, 0x53, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x71, /* 0x64-0x67 */ - 0x00, 0x00, 0x95, 0xA8, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x90, 0xB5, 0x00, 0x00, /* 0x70-0x73 */ - 0xE0, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x93, 0xC1, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x8C, 0xA1, 0xE0, 0xB1, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x8D, 0xD2, 0xE0, 0xB3, 0xE0, 0xB2, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xB4, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xB5, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xB6, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x8B, 0x5D, 0x00, 0x00, 0xE0, 0xB7, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xB8, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x8C, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x94, 0xC6, /* 0xAC-0xAF */ - 0x00, 0x00, 0xED, 0xFC, 0xE0, 0xBA, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0xF3, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xE0, 0xB9, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0x40, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0xB6, 0xE0, 0xBB, /* 0xC0-0xC3 */ - 0xE0, 0xBD, 0x00, 0x00, 0xE0, 0xBC, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xBE, 0x00, 0x00, /* 0xCC-0xCF */ - 0x8C, 0xCF, 0x00, 0x00, 0xE0, 0xBF, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xE7, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x91, 0x5F, 0x00, 0x00, 0x8D, 0x9D, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0xE0, 0xC1, 0xE0, 0xC2, 0xE0, 0xC0, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x8E, 0xEB, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x93, 0xC6, 0x8B, 0xB7, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC4, /* 0xF4-0xF7 */ - 0x92, 0x4B, 0xE0, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x98, 0x54, 0x94, 0x82, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_73[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC7, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC9, 0xE0, 0xC6, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0xD2, /* 0x18-0x1B */ - 0xE0, 0xC8, 0xE0, 0xCA, 0x00, 0x00, 0x97, 0xC2, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0xEE, 0x41, 0xE0, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xE0, 0xCD, 0x92, 0x96, 0x94, 0x4C, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0xA3, 0xE0, 0xCC, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xE0, 0xCB, 0x00, 0x00, 0x97, 0x50, 0x97, 0x51, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xCF, 0x89, 0x8E, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x8D, 0x96, 0x8E, 0x82, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xD0, 0xE0, 0xD1, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xD3, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x62, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xE0, 0xD5, 0x00, 0x00, 0xE0, 0xD4, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xE0, 0xD6, 0x00, 0x00, 0x8A, 0x6C, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xE0, 0xD8, 0x00, 0x00, 0xEE, 0x43, /* 0x74-0x77 */ - 0xE0, 0xD7, 0x00, 0x00, 0xE0, 0xDA, 0xE0, 0xD9, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x8C, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x97, 0xA6, /* 0x84-0x87 */ - 0x00, 0x00, 0x8B, 0xCA, 0x00, 0x00, 0x89, 0xA4, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0xE8, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x8A, 0xDF, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0xE6, 0xE0, 0xDC, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xDE, /* 0xB8-0xBB */ - 0x00, 0x00, 0xEE, 0x44, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xE0, 0xDF, 0x00, 0x00, 0x89, 0xCF, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xE0, 0xDB, 0xEE, 0x45, 0x8E, 0x58, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x92, 0xBF, 0xE0, 0xDD, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0x48, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0x46, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE2, 0x00, 0x00, /* 0xDC-0xDF */ - 0x8E, 0xEC, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x47, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xE0, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0x5D, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x94, 0xC7, 0xE0, 0xE1, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0xE0, 0xFC, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xEE, 0x4A, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xE0, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0xBB, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_74[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x85, /* 0x00-0x03 */ - 0x00, 0x00, 0xE0, 0xE4, 0x97, 0x9D, 0xEE, 0x49, /* 0x04-0x07 */ - 0x00, 0x00, 0x97, 0xAE, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x91, 0xF4, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xE0, 0xE6, 0xEE, 0x4B, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xEE, 0x4D, 0xEE, 0x4C, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0x4E, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE8, 0x97, 0xD4, /* 0x30-0x33 */ - 0x8B, 0xD5, 0x94, 0xFA, 0x94, 0x69, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE9, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xEB, /* 0x3C-0x3F */ - 0x00, 0x00, 0xE0, 0xEE, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xE0, 0xEA, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xE0, 0xED, 0x8C, 0xE8, 0x89, 0x6C, /* 0x58-0x5B */ - 0xE0, 0xEF, 0x00, 0x00, 0x90, 0x90, 0xE0, 0xEC, /* 0x5C-0x5F */ - 0x97, 0xDA, 0x00, 0x00, 0xEE, 0x4F, 0xE0, 0xF2, /* 0x60-0x63 */ - 0xEA, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xE0, 0xF0, 0xE0, 0xF3, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE5, /* 0x6C-0x6F */ - 0xE0, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x8D, 0xBA, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF4, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF5, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x9E, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0xEE, 0x50, 0x00, 0x00, 0xE0, 0xF6, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF7, 0xEE, 0x51, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE3, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF8, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x8A, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x8E, 0xA3, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF9, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFA, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xE0, 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x89, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0xE1, 0x40, 0x00, 0x00, 0x95, 0x5A, 0xE1, 0x41, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x8A, 0xA2, 0xE1, 0x42, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xE1, 0x43, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0x44, 0x00, 0x00, /* 0xEC-0xEF */ - 0xE1, 0x46, 0xE1, 0x47, 0xE1, 0x45, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x95, 0x72, 0xE1, 0x49, /* 0xF4-0xF7 */ - 0xE1, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_75[512] = { - 0x00, 0x00, 0xEE, 0x52, 0x00, 0x00, 0xE1, 0x4B, /* 0x00-0x03 */ - 0xE1, 0x4A, 0xE1, 0x4C, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0xE1, 0x4D, 0xE1, 0x4F, 0xE1, 0x4E, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x8D, 0x99, 0x00, 0x00, 0xE1, 0x51, /* 0x10-0x13 */ - 0x00, 0x00, 0xE1, 0x50, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x8A, 0xC3, 0x00, 0x00, 0x90, 0x72, 0x00, 0x00, /* 0x18-0x1B */ - 0x93, 0x5B, 0x00, 0x00, 0xE1, 0x52, 0x90, 0xB6, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x59, /* 0x20-0x23 */ - 0x00, 0x00, 0x89, 0x99, 0xE1, 0x53, 0x00, 0x00, /* 0x24-0x27 */ - 0x97, 0x70, 0x00, 0x00, 0x00, 0x00, 0x95, 0xE1, /* 0x28-0x2B */ - 0xE1, 0x54, 0x00, 0x00, 0x00, 0x00, 0xED, 0x8C, /* 0x2C-0x2F */ - 0x93, 0x63, 0x97, 0x52, 0x8D, 0x62, 0x90, 0x5C, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x6A, /* 0x34-0x37 */ - 0x99, 0xB2, 0x00, 0x00, 0x92, 0xAC, 0x89, 0xE6, /* 0x38-0x3B */ - 0xE1, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xE1, 0x56, 0x00, 0x00, 0xE1, 0x5B, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xE1, 0x59, 0xE1, 0x58, 0x9D, 0xC0, /* 0x48-0x4B */ - 0x8A, 0x45, 0xE1, 0x57, 0x00, 0x00, 0x88, 0xD8, /* 0x4C-0x4F */ - 0x00, 0x00, 0x94, 0xA8, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x94, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x97, 0xAF, 0xE1, 0x5C, 0xE1, 0x5A, /* 0x58-0x5B */ - 0x92, 0x7B, 0x90, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x94, 0xA9, 0x00, 0x00, 0x95, 0x4C, 0x00, 0x00, /* 0x60-0x63 */ - 0xE1, 0x5E, 0x97, 0xAA, 0x8C, 0x6C, 0xE1, 0x5F, /* 0x64-0x67 */ - 0x00, 0x00, 0xE1, 0x5D, 0x94, 0xD4, 0xE1, 0x60, /* 0x68-0x6B */ - 0x00, 0x00, 0xE1, 0x61, 0x00, 0x00, 0xEE, 0x53, /* 0x6C-0x6F */ - 0x88, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x8F, 0xF4, /* 0x70-0x73 */ - 0xE1, 0x66, 0x00, 0x00, 0xE1, 0x63, 0x93, 0xEB, /* 0x74-0x77 */ - 0xE1, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x45, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xE1, 0x69, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0x64, 0xE1, 0x65, /* 0x84-0x87 */ - 0x00, 0x00, 0xE1, 0x68, 0xE1, 0x67, 0x95, 0x44, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x91, 0x61, 0x91, 0x60, /* 0x8C-0x8F */ - 0x00, 0x00, 0x8B, 0x5E, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xE1, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0x6B, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xE1, 0x6C, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0x6E, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xE1, 0x6D, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x75, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xE1, 0x76, 0x94, 0xE6, 0xE1, 0x70, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xE1, 0x72, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xE1, 0x74, 0x90, 0x5D, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0xE1, 0x75, 0xE1, 0x73, 0x8E, 0xBE, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0x6F, 0xE1, 0x71, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x95, 0x61, 0x00, 0x00, 0x8F, 0xC7, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0x78, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0xE1, 0x77, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0x79, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x8E, 0xA4, 0x8D, 0xAD, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x93, 0x97, 0xE1, 0x7A, 0x00, 0x00, 0x92, 0xC9, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0x7C, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0x9F, 0xE1, 0x7B, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x91, 0x89, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xE1, 0x82, 0x00, 0x00, 0xE1, 0x84, 0xE1, 0x85, /* 0xF0-0xF3 */ - 0x92, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0x83, 0x00, 0x00, /* 0xF8-0xFB */ - 0xE1, 0x80, 0x00, 0x00, 0xE1, 0x7D, 0xE1, 0x7E, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_76[512] = { - 0x00, 0x00, 0xE1, 0x81, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xE1, 0x88, 0x00, 0x00, 0xE1, 0x86, /* 0x08-0x0B */ - 0x00, 0x00, 0xE1, 0x87, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0x89, /* 0x1C-0x1F */ - 0xE1, 0x8B, 0xE1, 0x8C, 0xE1, 0x8D, 0x00, 0x00, /* 0x20-0x23 */ - 0xE1, 0x8E, 0x00, 0x00, 0x00, 0x00, 0xE1, 0x8A, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xE1, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xE1, 0x8F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0x91, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0xC3, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0x94, 0xE1, 0x92, /* 0x44-0x47 */ - 0xE1, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x8A, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0xFC, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x95, 0xC8, 0x00, 0x00, /* 0x54-0x57 */ - 0xE1, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0xE1, 0x95, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0xE1, 0x97, 0xE1, 0x98, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0x9C, /* 0x64-0x67 */ - 0xE1, 0x99, 0xE1, 0x9A, 0xE1, 0x9B, 0x00, 0x00, /* 0x68-0x6B */ - 0xE1, 0x9D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xE1, 0x9E, 0x00, 0x00, 0xE1, 0x9F, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xA0, 0x00, 0x00, /* 0x74-0x77 */ - 0xE1, 0xA1, 0x00, 0x00, 0x94, 0xAD, 0x93, 0x6F, /* 0x78-0x7B */ - 0xE1, 0xA2, 0x94, 0x92, 0x95, 0x53, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xE1, 0xA3, 0x00, 0x00, 0xEE, 0x54, 0xE1, 0xA4, /* 0x80-0x83 */ - 0x93, 0x49, 0x00, 0x00, 0x8A, 0x46, 0x8D, 0x63, /* 0x84-0x87 */ - 0xE1, 0xA5, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xA6, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xA7, 0x00, 0x00, /* 0x8C-0x8F */ - 0x8E, 0x48, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xA9, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xA8, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xE1, 0xAA, 0xE1, 0xAB, 0xEE, 0x57, /* 0x98-0x9B */ - 0xEE, 0x55, 0x00, 0x00, 0xEE, 0x56, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0x58, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0xE7, 0x00, 0x00, /* 0xAC-0xAF */ - 0xE1, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xE1, 0xAD, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x89, /* 0xB4-0xB7 */ - 0xE1, 0xAE, 0xE1, 0xAF, 0xE1, 0xB0, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x4D, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xB1, 0x94, 0x75, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0x7E, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x89, 0x6D, 0x00, 0x00, 0x89, 0x76, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0xE1, 0xB2, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xB4, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xB3, 0x93, 0x90, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xB7, /* 0xD8-0xDB */ - 0x9F, 0x58, 0x00, 0x00, 0xE1, 0xB5, 0x96, 0xBF, /* 0xDC-0xDF */ - 0x00, 0x00, 0xE1, 0xB6, 0x00, 0x00, 0x8A, 0xC4, /* 0xE0-0xE3 */ - 0x94, 0xD5, 0xE1, 0xB7, 0x00, 0x00, 0xE1, 0xB8, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xB9, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0xDA, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0xD3, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x92, 0xBC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x91, 0x8A, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xBB, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0x82, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_77[512] = { - 0x00, 0x00, 0x8F, 0xC8, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xE1, 0xBE, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xBD, /* 0x04-0x07 */ - 0xE1, 0xBC, 0x94, 0xFB, 0x00, 0x00, 0x8A, 0xC5, /* 0x08-0x0B */ - 0x8C, 0xA7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xC4, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xC1, 0x90, 0x5E, /* 0x1C-0x1F */ - 0x96, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0xE1, 0xC0, 0xE1, 0xC2, 0xE1, 0xC3, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xE1, 0xBF, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xC5, /* 0x34-0x37 */ - 0xE1, 0xC6, 0x00, 0x00, 0x92, 0xAD, 0x00, 0x00, /* 0x38-0x3B */ - 0x8A, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x92, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0x5A, 0xE1, 0xC7, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xC8, 0xE1, 0xCB, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x90, 0x87, 0x00, 0x00, 0x93, 0xC2, /* 0x60-0x63 */ - 0x00, 0x00, 0xE1, 0xCC, 0x96, 0x72, 0x00, 0x00, /* 0x64-0x67 */ - 0xE1, 0xC9, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xCA, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xE1, 0xCF, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xCE, 0xE1, 0xCD, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xD1, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xD0, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xE1, 0xD2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xD4, 0x00, 0x00, /* 0x9C-0x9F */ - 0xE1, 0xD3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x95, 0xCB, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x8F, 0x75, 0x97, 0xC4, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0xE1, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x93, 0xB5, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xD6, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xE1, 0xD7, 0x00, 0x00, 0xE1, 0xDB, /* 0xB8-0xBB */ - 0xE1, 0xD9, 0xE1, 0xDA, 0x00, 0x00, 0xE1, 0xD8, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xDC, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0xE1, 0xDD, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xDE, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xDF, 0x96, 0xB5, /* 0xD8-0xDB */ - 0xE1, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0xEE, 0xE1, 0xE1, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x92, 0x6D, 0x00, 0x00, 0x94, 0x8A, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x8B, 0xE9, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x92, 0x5A, 0xE1, 0xE2, 0x8B, 0xB8, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xCE, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0xE1, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_78[512] = { - 0x00, 0x00, 0x00, 0x00, 0x8D, 0xBB, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0xE1, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xE5, 0x00, 0x00, /* 0x10-0x13 */ - 0x8C, 0xA4, 0x8D, 0xD3, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xE1, 0xE7, 0xEE, 0x5C, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x93, 0x75, 0x8D, 0xD4, 0x8B, 0x6D, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0x43, 0x00, 0x00, /* 0x30-0x33 */ - 0x94, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x93, 0x76, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8D, 0x7B, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0xE1, 0xE9, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0x5D, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x8F, 0xC9, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0xEE, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0xB0, /* 0x68-0x6B */ - 0x8D, 0x64, 0x00, 0x00, 0x00, 0x00, 0x8C, 0xA5, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0xA1, 0x00, 0x00, /* 0x70-0x73 */ - 0xE1, 0xEB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0x5F, 0x00, 0x00, /* 0x78-0x7B */ - 0xE1, 0xED, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x8C, 0xE9, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xEC, 0x92, 0xF4, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0xE1, 0xEF, 0x8A, 0x56, 0xE1, 0xEA, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x94, 0xE8, 0x00, 0x00, 0x89, 0x4F, /* 0x90-0x93 */ - 0x00, 0x00, 0x8D, 0xEA, 0x00, 0x00, 0x98, 0x71, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xEE, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xF0, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0xC9, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x90, 0xD7, 0xE1, 0xF2, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xF3, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xE1, 0xF1, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x8A, 0x6D, 0x00, 0x00, /* 0xB8-0xBB */ - 0xE1, 0xF9, 0x00, 0x00, 0xE1, 0xF8, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x8E, 0xA5, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xE1, 0xFA, 0xE1, 0xF5, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xFB, 0xE1, 0xF6, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x94, 0xD6, 0xE1, 0xF4, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xE1, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0x41, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x40, /* 0xE4-0xE7 */ - 0x96, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xE1, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x88, 0xE9, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xE2, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xE2, 0x42, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_79[512] = { - 0x00, 0x00, 0x8F, 0xCA, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x44, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x91, 0x62, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0xE2, 0x46, 0xE2, 0x45, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xE2, 0x47, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xE6, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xE8, 0xE2, 0x49, /* 0x28-0x2B */ - 0xE2, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xEE, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x8E, 0xA6, 0x00, 0x00, /* 0x38-0x3B */ - 0x97, 0xE7, 0x00, 0x00, 0x8E, 0xD0, 0x00, 0x00, /* 0x3C-0x3F */ - 0xE2, 0x4A, 0x8C, 0x56, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x5F, /* 0x44-0x47 */ - 0x8B, 0x46, 0x8E, 0x83, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x97, 0x53, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x50, /* 0x50-0x53 */ - 0x00, 0x00, 0xE2, 0x4F, 0x91, 0x63, 0xE2, 0x4C, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0x4E, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x8F, 0x6A, 0x90, 0x5F, 0xE2, 0x4D, /* 0x5C-0x5F */ - 0xE2, 0x4B, 0x00, 0x00, 0x94, 0x49, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x8F, 0xCB, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x95, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x8D, 0xD5, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0x98, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0x51, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x52, /* 0x7C-0x7F */ - - 0xE2, 0x68, 0x8B, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x98, 0x5C, 0x91, 0x54, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0x53, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x89, 0xD0, 0x92, 0xF5, 0x95, 0x9F, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xEE, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x66, /* 0x98-0x9B */ - 0x00, 0x00, 0xE2, 0x54, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0x9A, 0xE2, 0x55, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0x57, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0x58, 0x00, 0x00, /* 0xAC-0xAF */ - 0x94, 0x48, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x59, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xE2, 0x5A, 0xE2, 0x5B, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x8B, 0xD7, 0x89, 0xD1, 0x93, 0xC3, /* 0xBC-0xBF */ - 0x8F, 0x47, 0x8E, 0x84, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xE2, 0x5C, 0x00, 0x00, 0x8F, 0x48, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x89, 0xC8, 0x95, 0x62, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xE2, 0x5D, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x94, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x64, /* 0xDC-0xDF */ - 0x00, 0x00, 0xE2, 0x60, 0x00, 0x00, 0xE2, 0x61, /* 0xE0-0xE3 */ - 0x94, 0x89, 0x00, 0x00, 0x90, 0x60, 0xE2, 0x5E, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x92, 0x81, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xE2, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x8F, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xDA, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_7A[512] = { - 0x8B, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xE2, 0x62, 0x00, 0x00, 0x00, 0x00, 0x92, 0xF6, /* 0x08-0x0B */ - 0x00, 0x00, 0xE2, 0x63, 0x90, 0xC5, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x96, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x95, 0x42, /* 0x14-0x17 */ - 0xE2, 0x64, 0xE2, 0x65, 0x92, 0x74, 0x00, 0x00, /* 0x18-0x1B */ - 0x97, 0xC5, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x67, /* 0x1C-0x1F */ - 0xE2, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x8E, 0xED, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xE2, 0x69, 0x88, 0xEE, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x6C, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x6A, /* 0x38-0x3B */ - 0x89, 0xD2, 0x8C, 0x6D, 0xE2, 0x6B, 0x8D, 0x65, /* 0x3C-0x3F */ - 0x8D, 0x92, 0x00, 0x00, 0x95, 0xE4, 0xE2, 0x6D, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0x73, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xE2, 0x6F, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x90, 0xCF, 0x89, 0x6E, 0x89, 0xB8, /* 0x4C-0x4F */ - 0x88, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x6E, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0xE2, 0x70, 0xE2, 0x71, 0x8F, 0xF5, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xE2, 0x72, 0x00, 0x00, 0x8A, 0x6E, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xE2, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x8C, 0x8A, 0x00, 0x00, 0x8B, 0x86, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xE2, 0x75, 0x8B, 0xF3, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xE2, 0x76, 0x00, 0x00, 0x90, 0xFA, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x93, 0xCB, 0x00, 0x00, 0x90, 0xDE, /* 0x80-0x83 */ - 0x8D, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xE2, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x92, 0x82, 0x91, 0x8B, /* 0x90-0x93 */ - 0x00, 0x00, 0xE2, 0x79, 0xE2, 0x7B, 0xE2, 0x78, /* 0x94-0x97 */ - 0xE2, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x41, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xE2, 0x7C, 0x8C, 0x45, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0x87, 0x97, 0x71, /* 0xAC-0xAF */ - 0xE2, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0x80, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0x4D, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x83, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x96, /* 0xC0-0xC3 */ - 0xE2, 0x82, 0xE2, 0x81, 0x00, 0x00, 0xE2, 0x85, /* 0xC4-0xC7 */ - 0xE2, 0x7D, 0x00, 0x00, 0xE2, 0x86, 0x97, 0xA7, /* 0xC8-0xCB */ - 0x00, 0x00, 0xE2, 0x87, 0x00, 0x00, 0xE2, 0x88, /* 0xCC-0xCF */ - 0x00, 0x00, 0xEE, 0x67, 0x9A, 0xF2, 0xE2, 0x8A, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xE2, 0x89, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xE2, 0x8B, 0xE2, 0x8C, 0x00, 0x00, /* 0xD8-0xDB */ - 0x97, 0xB3, 0xE2, 0x8D, 0x00, 0x00, 0xE8, 0xED, /* 0xDC-0xDF */ - 0x8F, 0xCD, 0xE2, 0x8E, 0xE2, 0x8F, 0x8F, 0x76, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x93, 0xB6, 0xE2, 0x90, 0xEE, 0x68, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x92, 0x47, 0xEE, 0x6A, /* 0xE8-0xEB */ - 0x00, 0x00, 0xE2, 0x91, 0x00, 0x00, 0x92, 0x5B, /* 0xEC-0xEF */ - 0xE2, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0xA3, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x99, 0x5E, 0x92, 0x7C, 0x8E, 0xB1, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xC6, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_7B[512] = { - 0x00, 0x00, 0x00, 0x00, 0xE2, 0x93, 0x00, 0x00, /* 0x00-0x03 */ - 0xE2, 0xA0, 0x00, 0x00, 0xE2, 0x96, 0x00, 0x00, /* 0x04-0x07 */ - 0x8B, 0x88, 0x00, 0x00, 0xE2, 0x95, 0xE2, 0xA2, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x94, /* 0x0C-0x0F */ - 0x00, 0x00, 0x8F, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xE2, 0x98, 0xE2, 0x99, 0x00, 0x00, 0x93, 0x4A, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0x9A, 0x00, 0x00, /* 0x1C-0x1F */ - 0x8A, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x90, 0x79, 0x95, 0x84, 0x00, 0x00, /* 0x24-0x27 */ - 0xE2, 0x9C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x91, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x97, /* 0x30-0x33 */ - 0x00, 0x00, 0xE2, 0x9B, 0xE2, 0x9D, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x8D, 0xF9, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0xE2, 0xA4, 0x95, 0x4D, 0x00, 0x00, /* 0x44-0x47 */ - 0x94, 0xA4, 0x93, 0x99, 0x00, 0x00, 0x8B, 0xD8, /* 0x48-0x4B */ - 0xE2, 0xA3, 0xE2, 0xA1, 0x00, 0x00, 0x94, 0xB3, /* 0x4C-0x4F */ - 0xE2, 0x9E, 0x92, 0x7D, 0x93, 0x9B, 0x00, 0x00, /* 0x50-0x53 */ - 0x93, 0x9A, 0x00, 0x00, 0x8D, 0xF4, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0xE2, 0xB6, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0xE2, 0xA6, 0x00, 0x00, 0xE2, 0xA8, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0xE2, 0xAB, 0x00, 0x00, 0xE2, 0xAC, 0x00, 0x00, /* 0x6C-0x6F */ - 0xE2, 0xA9, 0xE2, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xE2, 0xA7, 0xE2, 0xA5, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0x9F, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x95, 0xCD, 0x89, 0xD3, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xB3, /* 0x88-0x8B */ - 0x00, 0x00, 0xE2, 0xB0, 0x00, 0x00, 0xE2, 0xB5, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0xB4, 0x00, 0x00, /* 0x90-0x93 */ - 0x94, 0x93, 0x96, 0xA5, 0x00, 0x00, 0x8E, 0x5A, /* 0x94-0x97 */ - 0xE2, 0xAE, 0xE2, 0xB7, 0xE2, 0xB2, 0x00, 0x00, /* 0x98-0x9B */ - 0xE2, 0xB1, 0xE2, 0xAD, 0xEE, 0x6B, 0xE2, 0xAF, /* 0x9C-0x9F */ - 0x00, 0x00, 0x8A, 0xC7, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x92, 0x5C, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x90, 0xFB, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x94, 0xA0, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xE2, 0xBC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x94, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x90, 0xDF, 0xE2, 0xB9, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x94, 0xCD, 0x00, 0x00, 0xE2, 0xBD, 0x95, 0xD1, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x92, 0x7A, 0x00, 0x00, 0xE2, 0xB8, /* 0xC8-0xCB */ - 0xE2, 0xBA, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xBB, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0xE2, 0xBE, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x8E, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x93, 0xC4, 0xE2, 0xC3, 0xE2, 0xC2, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xE2, 0xBF, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x98, 0x55, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xC8, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0xCC, 0xE2, 0xC9, /* 0xF4-0xF7 */ -}; - -static const unsigned char u2c_7C[512] = { - 0xE2, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xC6, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0xE2, 0xCB, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0xE2, 0xC0, 0x99, 0xD3, 0xE2, 0xC7, /* 0x10-0x13 */ - 0xE2, 0xC1, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xCA, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xD0, /* 0x1C-0x1F */ - 0x00, 0x00, 0x8A, 0xC8, 0x00, 0x00, 0xE2, 0xCD, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xCE, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0xCF, 0xE2, 0xD2, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xD1, /* 0x34-0x37 */ - 0x94, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xE2, 0xD3, 0x97, 0xFA, 0x95, 0xEB, /* 0x3C-0x3F */ - 0xE2, 0xD8, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xD5, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xE2, 0xD4, 0x90, 0xD0, 0x00, 0x00, 0xE2, 0xD7, /* 0x4C-0x4F */ - 0xE2, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xE2, 0xD6, 0x00, 0x00, 0xE2, 0xDD, 0x00, 0x00, /* 0x54-0x57 */ - 0xE2, 0xDA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xDB, /* 0x5C-0x5F */ - 0xE2, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0xE2, 0xDC, 0xE2, 0xDE, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0xE2, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0xC4, /* 0x70-0x73 */ - 0x00, 0x00, 0xE2, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0xE0, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x8B, 0xCC, 0x8C, 0x48, 0xE2, 0xE1, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x95, 0xB2, 0x00, 0x00, 0x90, 0x88, /* 0x88-0x8B */ - 0x00, 0x00, 0x96, 0xAE, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xE2, 0xE2, 0x00, 0x00, 0x97, 0xB1, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x94, 0x94, 0x00, 0x00, 0x91, 0x65, /* 0x94-0x97 */ - 0x94, 0x53, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x6C, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xBE, /* 0x9C-0x9F */ - 0x00, 0x00, 0xE2, 0xE7, 0xE2, 0xE5, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xE2, 0xE3, 0x8A, 0x9F, 0x00, 0x00, 0x8F, 0xCF, /* 0xA4-0xA7 */ - 0xE2, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xE6, /* 0xA8-0xAB */ - 0x00, 0x00, 0xE2, 0xE4, 0xE2, 0xEC, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xE2, 0xEB, 0xE2, 0xEA, 0xE2, 0xE9, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xE2, 0xED, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xE2, 0xEE, 0x90, 0xB8, 0x00, 0x00, /* 0xBC-0xBF */ - 0xE2, 0xEF, 0x00, 0x00, 0xE2, 0xF1, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xE2, 0xF0, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0xD0, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x91, 0x57, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0xF3, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x93, 0x9C, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xE2, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xE2, 0xF4, 0x00, 0x00, 0x95, 0xB3, 0x91, 0x8C, /* 0xDC-0xDF */ - 0x8D, 0x66, 0x00, 0x00, 0xE2, 0xF5, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0xC6, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xF7, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0xF8, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xE2, 0xF9, 0x00, 0x00, 0xE2, 0xFA, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x8E, 0x85, 0x00, 0x00, 0xE2, 0xFB, 0x8C, 0x6E, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0x8A, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_7D[512] = { - 0x8B, 0x49, 0x00, 0x00, 0xE3, 0x40, 0x00, 0x00, /* 0x00-0x03 */ - 0x96, 0xF1, 0x8D, 0x67, 0xE2, 0xFC, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0x43, 0x96, 0xE4, /* 0x08-0x0B */ - 0x00, 0x00, 0x94, 0x5B, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x95, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x8F, 0x83, 0xE3, 0x42, 0x00, 0x00, 0x8E, 0xD1, /* 0x14-0x17 */ - 0x8D, 0x68, 0x8E, 0x86, 0x8B, 0x89, 0x95, 0xB4, /* 0x18-0x1B */ - 0xE3, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x91, 0x66, 0x96, 0x61, 0x8D, 0xF5, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x87, /* 0x28-0x2B */ - 0x92, 0xDB, 0x00, 0x00, 0xE3, 0x46, 0x97, 0xDD, /* 0x2C-0x2F */ - 0x8D, 0xD7, 0x00, 0x00, 0xE3, 0x47, 0x90, 0x61, /* 0x30-0x33 */ - 0x00, 0x00, 0xE3, 0x49, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x8F, 0xD0, 0x8D, 0xAE, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0x48, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0x49, 0x8C, 0xBC, /* 0x40-0x43 */ - 0x91, 0x67, 0xE3, 0x44, 0xE3, 0x4A, 0x00, 0x00, /* 0x44-0x47 */ - 0xEE, 0x6D, 0x00, 0x00, 0x00, 0x00, 0xE3, 0x45, /* 0x48-0x4B */ - 0x8C, 0x6F, 0x00, 0x00, 0xE3, 0x4D, 0xE3, 0x51, /* 0x4C-0x4F */ - 0x8C, 0x8B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0x4C, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0x55, /* 0x58-0x5B */ - 0xEE, 0x6E, 0x00, 0x00, 0x8D, 0x69, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x97, 0x8D, 0x88, 0xBA, 0xE3, 0x52, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0x8B, 0x00, 0x00, /* 0x64-0x67 */ - 0xE3, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0x50, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x93, 0x9D, 0xE3, 0x4E, 0xE3, 0x4B, /* 0x70-0x73 */ - 0x00, 0x00, 0x8A, 0x47, 0x90, 0xE2, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x8C, 0xA6, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xE3, 0x57, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0xE3, 0x54, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0x56, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0x53, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x8C, 0x70, 0x91, 0xB1, 0xE3, 0x58, /* 0x98-0x9B */ - 0x91, 0x8E, 0x00, 0x00, 0x00, 0x00, 0xE3, 0x65, /* 0x9C-0x9F */ - 0xEE, 0x70, 0x00, 0x00, 0xE3, 0x61, 0xE3, 0x5B, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0x5F, /* 0xA8-0xAB */ - 0x8E, 0xF8, 0x88, 0xDB, 0xE3, 0x5A, 0xE3, 0x62, /* 0xAC-0xAF */ - 0xE3, 0x66, 0x8D, 0x6A, 0x96, 0xD4, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x92, 0xD4, 0xE3, 0x5C, 0x00, 0x00, 0xEE, 0x6F, /* 0xB4-0xB7 */ - 0xE3, 0x64, 0x00, 0x00, 0xE3, 0x59, 0x92, 0x5D, /* 0xB8-0xBB */ - 0x00, 0x00, 0xE3, 0x5E, 0x88, 0xBB, 0x96, 0xC8, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0x5D, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0xD9, 0x94, 0xEA, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x8D, /* 0xCC-0xCF */ - 0x00, 0x00, 0x97, 0xCE, 0x8F, 0x8F, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xE3, 0x8E, 0xEE, 0x71, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xE3, 0x67, 0x00, 0x00, 0x90, 0xFC, 0x00, 0x00, /* 0xD8-0xDB */ - 0xE3, 0x63, 0xE3, 0x68, 0xE3, 0x6A, 0x00, 0x00, /* 0xDC-0xDF */ - 0x92, 0xF7, 0xE3, 0x6D, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xE3, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x95, 0xD2, 0x8A, 0xC9, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x96, 0xC9, 0x00, 0x00, 0x00, 0x00, 0x88, 0xDC, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0x6C, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x97, 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0x6B, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_7E[512] = { - 0x00, 0x00, 0x89, 0x8F, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x93, 0xEA, 0xE3, 0x6E, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xE3, 0x75, 0xE3, 0x6F, 0xE3, 0x76, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0x72, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x9B, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x8E, 0xC8, 0xE3, 0x74, /* 0x1C-0x1F */ - 0x00, 0x00, 0xE3, 0x71, 0xE3, 0x77, 0xE3, 0x70, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0x63, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x44, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0x6B, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xE3, 0x73, 0xE3, 0x80, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0xE3, 0x7B, 0x00, 0x00, 0xE3, 0x7E, /* 0x34-0x37 */ - 0x00, 0x00, 0xE3, 0x7C, 0xE3, 0x81, 0xE3, 0x7A, /* 0x38-0x3B */ - 0x00, 0x00, 0xE3, 0x60, 0x90, 0xD1, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x94, 0xC9, 0x00, 0x00, 0xE3, 0x7D, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0x78, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x91, 0x40, 0x8C, 0x71, /* 0x48-0x4B */ - 0x00, 0x00, 0x8F, 0x4A, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0x72, 0x00, 0x00, /* 0x50-0x53 */ - 0x90, 0x44, 0x91, 0x55, 0xE3, 0x84, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xE3, 0x86, 0xE3, 0x87, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0xE3, 0x83, 0xE3, 0x85, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0x79, 0xE3, 0x82, /* 0x64-0x67 */ - 0x00, 0x00, 0xE3, 0x8A, 0xE3, 0x89, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x96, 0x9A, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x8C, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xE3, 0x88, 0x00, 0x00, 0xE3, 0x8C, /* 0x78-0x7B */ - 0xE3, 0x8B, 0xE3, 0x8F, 0x00, 0x00, 0xE3, 0x91, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x8E, 0x5B, 0xE3, 0x8D, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xE3, 0x92, 0xE3, 0x93, 0xED, 0x40, 0x00, 0x00, /* 0x88-0x8B */ - 0xE3, 0x94, 0x00, 0x00, 0xE3, 0x9A, 0x93, 0x5A, /* 0x8C-0x8F */ - 0xE3, 0x96, 0x00, 0x00, 0xE3, 0x95, 0xE3, 0x97, /* 0x90-0x93 */ - 0xE3, 0x98, 0x00, 0x00, 0xE3, 0x99, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0x9B, /* 0x98-0x9B */ - 0xE3, 0x9C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ -}; - -static const unsigned char u2c_7F[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x8A, 0xCA, 0x00, 0x00, /* 0x34-0x37 */ - 0xE3, 0x9D, 0x00, 0x00, 0xE3, 0x9E, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0xE3, 0x9F, 0x00, 0x00, 0xEE, 0x73, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xE3, 0xA0, 0xE3, 0xA1, 0xE3, 0xA2, 0x00, 0x00, /* 0x4C-0x4F */ - 0xE3, 0xA3, 0xE3, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xE3, 0xA6, 0xE3, 0xA5, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xE3, 0xA7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xA8, /* 0x5C-0x5F */ - 0xE3, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xAC, /* 0x64-0x67 */ - 0xE3, 0xAA, 0xE3, 0xAB, 0x8D, 0xDF, 0x8C, 0x72, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x92, 0x75, 0x00, 0x00, /* 0x6C-0x6F */ - 0x94, 0xB1, 0x00, 0x00, 0x8F, 0x90, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x94, 0x6C, 0x00, 0x00, 0x94, 0xEB, /* 0x74-0x77 */ - 0xE3, 0xAD, 0x9C, 0xEB, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xAE, 0xE3, 0xB0, /* 0x80-0x83 */ - 0x00, 0x00, 0x97, 0x85, 0xE3, 0xAF, 0xE3, 0xB2, /* 0x84-0x87 */ - 0xE3, 0xB1, 0x00, 0x00, 0x97, 0x72, 0x00, 0x00, /* 0x88-0x8B */ - 0xE3, 0xB3, 0x00, 0x00, 0x94, 0xFC, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xE3, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xB7, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xE3, 0xB6, 0xE3, 0xB5, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xEE, 0x74, 0x00, 0x00, 0xE3, 0xB8, /* 0xA0-0xA3 */ - 0x8C, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x91, 0x41, 0x8B, 0x60, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xBC, 0xE3, 0xB9, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xBA, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xBD, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xE3, 0xBE, 0xE3, 0xBB, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x89, 0x48, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x89, 0xA5, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xE3, 0xC0, 0xE3, 0xC1, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xC2, 0x00, 0x00, /* 0xC8-0xCB */ - 0x97, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0x4B, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xE3, 0xC4, 0xE3, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x90, 0x89, 0xE3, 0xC5, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xC6, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xE3, 0xC7, 0x00, 0x00, 0x8A, 0xE3, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x8A, 0xCB, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xC8, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xE3, 0xC9, 0x00, 0x00, 0x96, 0x7C, /* 0xF8-0xFB */ - 0x97, 0x83, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_80[512] = { - 0x97, 0x73, 0x98, 0x56, 0x00, 0x00, 0x8D, 0x6C, /* 0x00-0x03 */ - 0xE3, 0xCC, 0x8E, 0xD2, 0xE3, 0xCB, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xCD, /* 0x08-0x0B */ - 0x8E, 0xA7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x91, 0xCF, 0x00, 0x00, 0xE3, 0xCE, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x8D, 0x6B, 0x00, 0x00, 0x96, 0xD5, /* 0x14-0x17 */ - 0xE3, 0xCF, 0xE3, 0xD0, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xE3, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xE3, 0xD2, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xE3, 0xD3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0xA8, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0xEB, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xD5, /* 0x38-0x3B */ - 0x00, 0x00, 0x92, 0x5E, 0x00, 0x00, 0xE3, 0xD4, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xD7, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xD6, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xD8, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x90, 0xB9, 0x00, 0x00, /* 0x54-0x57 */ - 0xE3, 0xD9, 0x00, 0x00, 0xE3, 0xDA, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x95, 0xB7, 0xE3, 0xDB, /* 0x5C-0x5F */ - 0x00, 0x00, 0x91, 0x8F, 0xE3, 0xDC, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xE3, 0xDD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0xFC, /* 0x6C-0x6F */ - 0xE3, 0xE0, 0x00, 0x00, 0xE3, 0xDF, 0xE3, 0xDE, /* 0x70-0x73 */ - 0x92, 0xAE, 0x00, 0x00, 0xE3, 0xE1, 0x90, 0x45, /* 0x74-0x77 */ - 0x00, 0x00, 0xE3, 0xE2, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xE3, 0xE3, 0x98, 0x57, 0xE3, 0xE4, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xE3, 0xE5, 0xE3, 0xE7, 0xE3, 0xE6, 0x94, 0xA3, /* 0x84-0x87 */ - 0x00, 0x00, 0x93, 0xF7, 0x00, 0x00, 0x98, 0x5D, /* 0x88-0x8B */ - 0x94, 0xA7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xE9, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0xD1, 0x00, 0x00, /* 0x94-0x97 */ - 0x95, 0x49, 0x00, 0x00, 0xE3, 0xEA, 0xE3, 0xE8, /* 0x98-0x9B */ - 0x00, 0x00, 0x8A, 0xCC, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x8C, 0xD2, 0x8E, 0x88, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x94, 0xEC, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x8C, 0xA8, 0x96, 0x62, 0x00, 0x00, /* 0xA8-0xAB */ - 0xE3, 0xED, 0xE3, 0xEB, 0x00, 0x00, 0x8D, 0x6D, /* 0xAC-0xAF */ - 0x00, 0x00, 0x8D, 0x6E, 0x88, 0xE7, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x8D, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0x78, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xDD, /* 0xC0-0xC3 */ - 0xE3, 0xF2, 0x00, 0x00, 0x92, 0x5F, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x94, 0x77, 0x00, 0x00, 0x91, 0xD9, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xF4, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xE3, 0xF0, 0xE3, 0xF3, 0xE3, 0xEE, /* 0xD8-0xDB */ - 0x00, 0x00, 0xE3, 0xF1, 0x96, 0x45, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x8C, 0xD3, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x88, 0xFB, 0xE3, 0xEF, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xF6, /* 0xEC-0xEF */ - 0x00, 0x00, 0xE3, 0xF7, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x93, 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x8B, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0xE4, 0x45, 0x94, 0x5C, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_81[512] = { - 0x00, 0x00, 0x00, 0x00, 0x8E, 0x89, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x8B, 0xBA, 0x90, 0xC6, 0x98, 0x65, /* 0x04-0x07 */ - 0x96, 0xAC, 0xE3, 0xF5, 0x90, 0xD2, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0x72, 0xE3, 0xF8, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xFA, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xE3, 0xF9, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xFB, /* 0x2C-0x2F */ - 0x00, 0x00, 0x92, 0x45, 0x00, 0x00, 0x94, 0x5D, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x92, 0xAF, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0x42, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0x41, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xFC, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x90, 0x74, 0x00, 0x00, /* 0x4C-0x4F */ - 0x95, 0x85, 0xE4, 0x44, 0x00, 0x00, 0xE4, 0x43, /* 0x50-0x53 */ - 0x8D, 0x6F, 0x98, 0x72, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x54, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0xE4, 0x48, 0xE4, 0x49, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0xEE, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0x47, 0x00, 0x00, /* 0x6C-0x6F */ - 0x8D, 0x98, 0xE4, 0x46, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xE4, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x92, 0xB0, 0x95, 0xA0, 0x91, 0x42, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0xDA, /* 0x7C-0x7F */ - - 0xE4, 0x4E, 0x00, 0x00, 0xE4, 0x4F, 0xE4, 0x4B, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xE4, 0x4C, 0x00, 0x00, 0xE4, 0x4D, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8D, 0x70, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x55, /* 0x90-0x93 */ - 0x00, 0x00, 0xE4, 0x51, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x95, 0x86, 0x00, 0x00, /* 0x98-0x9B */ - 0x96, 0x8C, 0x95, 0x47, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xE4, 0x50, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x53, /* 0xA0-0xA3 */ - 0xE4, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x96, 0x63, 0xE4, 0x56, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0xE4, 0x57, 0x00, 0x00, 0x00, 0x00, 0x91, 0x56, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xE4, 0x58, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xE4, 0x5A, 0x00, 0x00, 0xE4, 0x5E, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xE4, 0x5B, 0xE4, 0x59, 0x94, 0x5E, /* 0xBC-0xBF */ - 0xE4, 0x5C, 0x00, 0x00, 0xE4, 0x5D, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0xB0, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xE4, 0x64, 0xE4, 0x5F, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0xE4, 0x60, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xE4, 0x61, 0x00, 0x00, 0x91, 0x9F, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xE4, 0x63, 0xE4, 0x62, 0xE4, 0x65, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x66, /* 0xDC-0xDF */ - 0xE4, 0x67, 0x00, 0x00, 0x00, 0x00, 0x90, 0x62, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x89, 0xE7, 0x00, 0x00, 0xE4, 0x68, /* 0xE4-0xE7 */ - 0x97, 0xD5, 0x00, 0x00, 0x8E, 0xA9, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x8F, 0x4C, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x8A, /* 0xF0-0xF3 */ - 0x92, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0x69, 0xE4, 0x6A, /* 0xF8-0xFB */ - 0x89, 0x50, 0x00, 0x00, 0xE4, 0x6B, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_82[512] = { - 0x00, 0x00, 0xE4, 0x6C, 0xE4, 0x6D, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xE4, 0x6E, 0x00, 0x00, 0xE4, 0x6F, /* 0x04-0x07 */ - 0x8B, 0xBB, 0x9D, 0xA8, 0xE4, 0x70, 0x00, 0x00, /* 0x08-0x0B */ - 0x90, 0xE3, 0xE4, 0x71, 0x8E, 0xC9, 0x00, 0x00, /* 0x0C-0x0F */ - 0xE4, 0x72, 0x00, 0x00, 0x98, 0xAE, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0x73, 0x95, 0xDC, /* 0x14-0x17 */ - 0x8A, 0xDA, 0x00, 0x00, 0x00, 0x00, 0x91, 0x43, /* 0x18-0x1B */ - 0x8F, 0x77, 0x00, 0x00, 0x95, 0x91, 0x8F, 0x4D, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xE4, 0x74, 0x8D, 0x71, 0xE4, 0x75, /* 0x28-0x2B */ - 0x94, 0xCA, 0x00, 0x00, 0xE4, 0x84, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x77, /* 0x30-0x33 */ - 0x00, 0x00, 0x91, 0xC7, 0x94, 0x95, 0x8C, 0xBD, /* 0x34-0x37 */ - 0xE4, 0x76, 0x91, 0x44, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xE4, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0xF8, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xE4, 0x7A, 0xE4, 0x79, 0xE4, 0x7C, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0xE4, 0x7B, 0x00, 0x00, 0xE4, 0x7D, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0x80, 0x00, 0x00, /* 0x60-0x63 */ - 0xE4, 0x7E, 0x00, 0x00, 0x8A, 0xCD, 0x00, 0x00, /* 0x64-0x67 */ - 0xE4, 0x81, 0x00, 0x00, 0xE4, 0x82, 0xE4, 0x83, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x8D, 0xAF, 0x97, 0xC7, /* 0x6C-0x6F */ - 0x00, 0x00, 0xE4, 0x85, 0x90, 0x46, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0x90, 0xE4, 0x86, /* 0x74-0x77 */ - 0xE4, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0x88, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xF0, /* 0x88-0x8B */ - 0x00, 0x00, 0xE4, 0x89, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0x8A, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x95, 0x87, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x8E, 0xC5, 0x00, 0x00, 0xE4, 0x8C, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x8A, 0x48, 0x88, 0xB0, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x8B, /* 0xA8-0xAB */ - 0xE4, 0x8E, 0x94, 0x6D, 0x00, 0x00, 0x90, 0x63, /* 0xAC-0xAF */ - 0x00, 0x00, 0x89, 0xD4, 0x00, 0x00, 0x96, 0x46, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x8C, 0x7C, 0x8B, 0xDA, 0x00, 0x00, 0xE4, 0x8D, /* 0xB8-0xBB */ - 0x00, 0x00, 0x89, 0xE8, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x8A, 0xA1, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x89, 0x91, 0xE4, 0x92, 0x97, 0xE8, /* 0xD0-0xD3 */ - 0x91, 0xDB, 0x00, 0x00, 0x00, 0x00, 0x95, 0x63, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xE4, 0x9E, 0x00, 0x00, 0x89, 0xD5, /* 0xD8-0xDB */ - 0xE4, 0x9C, 0x00, 0x00, 0xE4, 0x9A, 0xE4, 0x91, /* 0xDC-0xDF */ - 0x00, 0x00, 0xE4, 0x8F, 0x00, 0x00, 0xE4, 0x90, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x8E, 0xE1, 0x8B, 0xEA, 0x92, 0x97, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0xCF, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x89, 0x70, 0x00, 0x00, 0xE4, 0x94, /* 0xF0-0xF3 */ - 0xE4, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xE4, 0x99, 0xE4, 0x95, 0xE4, 0x98, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_83[512] = { - 0x00, 0x00, 0xEE, 0x76, 0x96, 0xCE, 0xE4, 0x97, /* 0x00-0x03 */ - 0x89, 0xD6, 0x8A, 0x9D, 0xE4, 0x9B, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xE4, 0x9D, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0x73, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xA1, 0xE4, 0xAA, /* 0x14-0x17 */ - 0xE4, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x88, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xB2, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x88, 0xEF, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xA9, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xA8, /* 0x2C-0x2F */ - 0x00, 0x00, 0xE4, 0xA3, 0xE4, 0xA2, 0x00, 0x00, /* 0x30-0x33 */ - 0xE4, 0xA0, 0xE4, 0x9F, 0x92, 0x83, 0x00, 0x00, /* 0x34-0x37 */ - 0x91, 0xF9, 0xE4, 0xA5, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xE4, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0xE4, 0xA7, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x91, 0x90, 0x8C, 0x74, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x60, /* 0x4C-0x4F */ - 0xE4, 0xA6, 0x00, 0x00, 0x8D, 0x72, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x91, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0x77, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xB8, /* 0x70-0x73 */ - 0x00, 0x00, 0xE4, 0xB9, 0x00, 0x00, 0x89, 0xD7, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0xAC, /* 0x78-0x7B */ - 0xE4, 0xB6, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x78, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0xE4, 0xAC, 0x00, 0x00, 0xE4, 0xB4, /* 0x84-0x87 */ - 0x00, 0x00, 0xE4, 0xBB, 0xE4, 0xB5, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xB3, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x96, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xB1, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xAD, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x8A, 0xCE, 0xE4, 0xAF, /* 0x9C-0x9F */ - 0xE4, 0xBA, 0x00, 0x00, 0xE4, 0xB0, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xE4, 0xBC, 0x00, 0x00, 0xE4, 0xAE, 0x94, 0x9C, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x97, 0x89, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xE4, 0xB7, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xE4, 0xCD, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xE4, 0xC5, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x90, 0x9B, 0x00, 0x00, 0xEE, 0x79, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0x65, 0x00, 0x00, /* 0xC8-0xCB */ - 0x8B, 0xDB, 0x00, 0x00, 0xE4, 0xC0, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0xD9, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0xD2, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xE4, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x8D, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x93, 0x70, /* 0xDC-0xDF */ - 0xE4, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x95, 0xEC, 0x00, 0x00, 0xE4, 0xBF, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0xD8, /* 0xEC-0xEF */ - 0x8C, 0xD4, 0x95, 0x48, 0xE4, 0xC9, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xE4, 0xBD, 0x00, 0x00, 0xEE, 0x7A, 0xE4, 0xC6, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xD0, /* 0xF8-0xFB */ - 0x00, 0x00, 0xE4, 0xC1, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_84[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xC2, /* 0x00-0x03 */ - 0x93, 0xB8, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xC7, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xC4, /* 0x08-0x0B */ - 0x96, 0x47, 0xE4, 0xCA, 0x88, 0xDE, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xBE, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xE4, 0xCC, 0x00, 0x00, 0xE4, 0xCB, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x94, 0x8B, 0xE4, 0xD2, 0x00, 0x00, /* 0x28-0x2B */ - 0xE4, 0xDD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x8A, 0x9E, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0xE4, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xE4, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xE4, 0xD3, 0x97, 0x8E, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xDC, 0x00, 0x00, /* 0x44-0x47 */ - 0xEE, 0x7B, 0x97, 0x74, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0xA8, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x98, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x8B, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x95, 0x92, 0xE4, 0xE2, 0x93, 0x9F, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x88, 0xAF, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xE4, 0xDB, 0x00, 0x00, 0xE4, 0xD7, /* 0x68-0x6B */ - 0x91, 0x92, 0xE4, 0xD1, 0xE4, 0xD9, 0xE4, 0xDE, /* 0x6C-0x6F */ - 0x00, 0x00, 0x94, 0x4B, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x88, 0xA8, 0x00, 0x00, 0xE4, 0xD6, /* 0x74-0x77 */ - 0x00, 0x00, 0xE4, 0xDF, 0x95, 0x98, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xDA, 0x00, 0x00, /* 0x80-0x83 */ - 0xE4, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8F, 0xD3, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x8F, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x8E, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x96, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x95, 0x66, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xE5, /* 0x9C-0x9F */ - 0x00, 0x00, 0xE4, 0xEE, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0xE4, 0xD8, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x8A, 0x97, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xEE, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x8F, 0xF6, 0xE4, 0xE3, 0x00, 0x00, 0xE4, 0xE8, /* 0xB8-0xBB */ - 0x91, 0x93, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xE4, /* 0xBC-0xBF */ - 0x00, 0x00, 0xE4, 0xEB, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x92, 0x7E, 0x00, 0x00, 0xE4, 0xEC, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x97, 0x75, 0xE4, 0xE1, 0x8A, 0x57, /* 0xC8-0xCB */ - 0x00, 0x00, 0xE4, 0xE7, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0xE4, 0xEA, 0x96, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xED, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xE4, 0xE6, 0xE4, 0xE9, 0x00, 0x00, /* 0xD8-0xDB */ - 0xED, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x96, 0x48, 0x00, 0x00, 0x98, 0x40, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xE4, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0xE4, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xF0, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_85[512] = { - 0x8E, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xCF, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x95, 0xCC, 0x00, 0x00, 0x96, 0xA0, /* 0x10-0x13 */ - 0xE4, 0xF7, 0xE4, 0xF6, 0x00, 0x00, 0xE4, 0xF2, /* 0x14-0x17 */ - 0xE4, 0xF3, 0x00, 0x00, 0x89, 0x55, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xF5, /* 0x1C-0x1F */ - 0x00, 0x00, 0xE4, 0xEF, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x92, 0xD3, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0xE4, 0xF4, 0x88, 0xFC, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x91, 0xA0, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x95, 0xC1, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xE4, 0xF9, 0xE5, 0x40, 0x00, 0x00, 0x94, 0xD7, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0xE4, 0xFC, 0x8F, 0xD4, 0x8E, 0xC7, 0xE5, 0x42, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0xBC, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x7D, /* 0x50-0x53 */ - 0x00, 0x00, 0xE5, 0x43, 0x00, 0x00, 0x95, 0x99, /* 0x54-0x57 */ - 0xE4, 0xFB, 0xEE, 0x7E, 0xE4, 0xD4, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xFA, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x98, 0x6E, 0x93, 0xA0, 0x95, 0x93, 0xEE, 0x80, /* 0x68-0x6B */ - 0x00, 0x00, 0xE5, 0x4A, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0x50, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0x51, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xE5, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x94, 0x96, 0x00, 0x00, 0x00, 0x00, 0xE5, 0x4E, /* 0x84-0x87 */ - 0xE5, 0x46, 0x00, 0x00, 0xE5, 0x48, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xE5, 0x52, 0xE5, 0x47, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xE5, 0x4B, 0x00, 0x00, 0x00, 0x00, 0x89, 0x92, /* 0x94-0x97 */ - 0x00, 0x00, 0x93, 0xE3, 0x00, 0x00, 0xE5, 0x4C, /* 0x98-0x9B */ - 0xE5, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xE5, 0x45, 0x00, 0x00, 0x91, 0x45, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xE5, 0x49, 0x8E, 0x46, 0x90, 0x64, 0x8C, 0x4F, /* 0xA8-0xAB */ - 0x96, 0xF2, 0x00, 0x00, 0x96, 0xF7, 0x8F, 0x92, /* 0xAC-0xAF */ - 0xEE, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xE5, 0x56, 0xE5, 0x54, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x98, 0x6D, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xE5, 0x53, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x97, 0x95, 0x00, 0x00, 0xE5, 0x55, /* 0xCC-0xCF */ - 0xE5, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xE5, 0x58, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xE5, 0x5B, 0xE5, 0x59, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x93, 0xA1, 0xE5, 0x5A, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x94, 0xCB, 0xE5, 0x4D, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x93, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xE5, 0x5C, 0xE5, 0x61, 0x91, 0x94, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0x60, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_86[512] = { - 0x00, 0x00, 0x00, 0x00, 0xE5, 0x41, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0x62, 0x91, 0x68, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0x5D, 0xE5, 0x5F, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0x5E, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x9F, 0x50, 0x9F, 0x41, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0x64, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0x63, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x97, 0x96, 0x00, 0x00, 0xE1, 0xBA, /* 0x2C-0x2F */ - 0xE5, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0x66, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0xE5, 0x67, 0x8C, 0xD5, 0x00, 0x00, /* 0x4C-0x4F */ - 0x8B, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xE5, 0x69, 0x99, 0x7C, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0x95, 0x00, 0x00, /* 0x58-0x5B */ - 0x97, 0xB8, 0x00, 0x00, 0x8B, 0xF1, 0xE5, 0x6A, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0x6B, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x8E, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0xE5, 0x6C, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x93, 0xF8, 0x00, 0x00, 0x88, 0xB8, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0xE1, 0xE5, 0x71, /* 0x88-0x8B */ - 0xE5, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0x6D, /* 0x90-0x93 */ - 0x00, 0x00, 0x8E, 0x5C, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0x6E, /* 0xA0-0xA3 */ - 0x94, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xE5, 0x6F, 0xE5, 0x70, 0xE5, 0x7A, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0x74, /* 0xAC-0xAF */ - 0xE5, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0x73, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xE5, 0x75, 0x00, 0x00, 0xE5, 0x76, 0x8E, 0xD6, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xE5, 0x78, 0x00, 0x00, 0x92, 0x60, /* 0xC8-0xCB */ - 0x00, 0x00, 0x8C, 0x75, 0x8A, 0x61, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xE5, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x8A, 0x5E, 0x00, 0x00, 0xE5, 0x81, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0x7C, 0xE5, 0x80, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x94, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xE5, 0x7D, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xE5, 0x7E, 0x95, 0x67, 0x94, 0xD8, 0xE5, 0x82, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x91, 0xFB, 0xE5, 0x8C, 0x00, 0x00, 0xE5, 0x88, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0xE9, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_87[512] = { - 0xE5, 0x86, 0x00, 0x00, 0x96, 0x49, 0xE5, 0x87, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0x84, 0x00, 0x00, /* 0x04-0x07 */ - 0xE5, 0x85, 0xE5, 0x8A, 0xE5, 0x8D, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0xE5, 0x8B, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0xE5, 0x89, 0xE5, 0x83, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x92, 0x77, 0x00, 0x00, 0xE5, 0x94, 0x00, 0x00, /* 0x18-0x1B */ - 0x96, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xE5, 0x92, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xE5, 0x93, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xE5, 0x8E, 0x00, 0x00, 0x00, 0x00, 0xE5, 0x90, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0x91, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0x8F, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x90, 0xE4, 0x00, 0x00, 0x98, 0x58, /* 0x48-0x4B */ - 0xE5, 0x98, 0x00, 0x00, 0xE5, 0x99, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0x9F, /* 0x50-0x53 */ - 0x00, 0x00, 0x90, 0x49, 0x00, 0x00, 0xE5, 0x9B, /* 0x54-0x57 */ - 0x00, 0x00, 0xE5, 0x9E, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0x96, /* 0x5C-0x5F */ - 0xE5, 0x95, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xA0, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0xDA, 0x00, 0x00, /* 0x64-0x67 */ - 0xE5, 0x9C, 0x00, 0x00, 0xE5, 0xA1, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0x9D, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xE5, 0x9A, 0x00, 0x00, 0x92, 0xB1, 0x00, 0x00, /* 0x74-0x77 */ - 0xE5, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x88, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xA5, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x97, 0x5A, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xA4, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xA3, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xAC, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xA6, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xAE, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0x86, 0xE5, 0xB1, /* 0xB8-0xBB */ - 0x00, 0x00, 0xE5, 0xA8, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xE5, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xE5, 0xAD, 0x00, 0x00, 0xE5, 0xB0, 0xE5, 0xAF, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xA7, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0xE5, 0xAA, 0x00, 0x00, 0xE5, 0xBB, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0xE5, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xB2, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xB3, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xB8, 0xE5, 0xB9, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x8A, 0x49, 0x00, 0x00, 0x8B, 0x61, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xB7, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_88[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xE5, 0xA2, 0x00, 0x00, 0xEE, 0x85, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0xE5, 0xB6, 0xE5, 0xBA, 0xE5, 0xB5, /* 0x0C-0x0F */ - 0x00, 0x00, 0xE5, 0xBC, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xE5, 0xBE, 0xE5, 0xBD, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xE5, 0xC0, 0xE5, 0xBF, 0xE5, 0x79, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xC4, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xE5, 0xC1, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xC2, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0xE5, 0xC3, 0x00, 0x00, 0xE5, 0xC5, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x8C, 0x8C, 0x00, 0x00, 0xE5, 0xC7, 0x00, 0x00, /* 0x40-0x43 */ - 0xE5, 0xC6, 0x00, 0x00, 0x8F, 0x4F, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x8D, 0x73, 0x9F, 0xA5, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xC8, 0x8F, 0x70, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x58, /* 0x54-0x57 */ - 0x00, 0x00, 0xE5, 0xC9, 0x00, 0x00, 0x89, 0x71, /* 0x58-0x5B */ - 0x00, 0x00, 0x8F, 0xD5, 0xE5, 0xCA, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x8D, 0x74, 0xE5, 0xCB, 0x88, 0xDF, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x95, 0x5C, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xCC, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x90, 0x8A, 0x00, 0x00, 0xE5, 0xD3, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xE5, 0xD0, 0x00, 0x00, 0x92, 0x8F, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xE5, 0xD1, 0xE5, 0xCE, 0x8B, 0xDC, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xE5, 0xCD, 0xE5, 0xD4, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x8C, 0x55, 0x00, 0x00, 0x00, 0x00, 0x91, 0xDC, /* 0x88-0x8B */ - 0x00, 0x00, 0xE5, 0xDA, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xD6, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x91, 0xB3, 0xE5, 0xD5, /* 0x94-0x97 */ - 0x00, 0x00, 0xE5, 0xD8, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xCF, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xD9, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xE5, 0xDB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0xED, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xD7, 0x00, 0x00, /* 0xAC-0xAF */ - 0xE5, 0xDC, 0xE5, 0xDE, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x8C, 0xD1, 0xE5, 0xD2, 0x00, 0x00, 0x88, 0xBF, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xDD, /* 0xBC-0xBF */ - 0x00, 0x00, 0x8D, 0xD9, 0x97, 0xF4, 0xE5, 0xDF, /* 0xC0-0xC3 */ - 0xE5, 0xE0, 0x91, 0x95, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0xA0, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xE5, 0xE1, 0x97, 0x54, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xE5, 0xE2, 0xE5, 0xE3, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x95, 0xE2, 0xE5, 0xE4, 0x00, 0x00, 0x8D, 0xBE, /* 0xDC-0xDF */ - 0x00, 0x00, 0x97, 0xA1, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xE5, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xEA, 0x8F, 0xD6, /* 0xF0-0xF3 */ - 0xE5, 0xE8, 0xEE, 0x86, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x97, 0x87, 0xE5, 0xE5, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0xE5, 0xE7, 0x90, 0xBB, 0x90, 0x9E, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_89[512] = { - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xE6, 0x00, 0x00, /* 0x00-0x03 */ - 0xE5, 0xEB, 0x00, 0x00, 0x00, 0x00, 0x95, 0xA1, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xED, 0x00, 0x00, /* 0x08-0x0B */ - 0xE5, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x8A, 0x8C, 0x00, 0x00, 0x96, 0x4A, 0xE5, 0xEE, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xED, 0x41, 0xE5, 0xFA, 0xE5, 0xF0, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xE5, 0xF1, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xF2, 0xE5, 0xF3, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xF7, 0x00, 0x00, /* 0x34-0x37 */ - 0xE5, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xF6, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xE5, 0xF4, 0x00, 0x00, 0xE5, 0xEF, /* 0x40-0x43 */ - 0xE5, 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xE5, 0xF9, 0xE8, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0xA6, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xFC, 0x8B, 0xDD, /* 0x5C-0x5F */ - 0xE5, 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0xE6, 0x41, 0x00, 0x00, 0xE6, 0x40, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0x43, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0xE6, 0x42, 0x00, 0x00, 0xE6, 0x44, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x8F, 0x50, 0x00, 0x00, /* 0x70-0x73 */ - 0xE6, 0x45, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x46, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0x47, 0x90, 0xBC, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x97, 0x76, 0x00, 0x00, 0xE6, 0x48, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x95, 0xA2, 0x94, 0x65, /* 0x84-0x87 */ - 0xE6, 0x49, 0x00, 0x00, 0xE6, 0x4A, 0x8C, 0xA9, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0x4B, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x4B, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x8E, 0x8B, 0x94, 0x60, /* 0x94-0x97 */ - 0xE6, 0x4C, 0x00, 0x00, 0x8A, 0x6F, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xE6, 0x4D, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0x4F, 0x97, 0x97, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xE6, 0x4E, 0x90, 0x65, 0x00, 0x00, /* 0xA8-0xAB */ - 0xE6, 0x50, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x51, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0x52, 0x8A, 0xCF, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0x53, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xE6, 0x54, 0x00, 0x00, 0xE6, 0x55, /* 0xBC-0xBF */ - 0xE6, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x8A, 0x70, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0x57, 0x00, 0x00, /* 0xD8-0xDB */ - 0xE6, 0x58, 0xE6, 0x59, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0xF0, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x90, 0x47, 0xE6, 0x5A, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xE6, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xE6, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_8A[512] = { - 0x8C, 0xBE, 0x00, 0x00, 0x92, 0xF9, 0xE6, 0x5D, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x8C, 0x76, 0x00, 0x00, 0x90, 0x75, 0x00, 0x00, /* 0x08-0x0B */ - 0xE6, 0x60, 0x00, 0x00, 0x93, 0xA2, 0x00, 0x00, /* 0x0C-0x0F */ - 0xE6, 0x5F, 0x00, 0x00, 0xEE, 0x87, 0x8C, 0x50, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0x5E, 0x91, 0xF5, /* 0x14-0x17 */ - 0x8B, 0x4C, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x61, /* 0x18-0x1B */ - 0x00, 0x00, 0xE6, 0x62, 0x00, 0x00, 0x8F, 0xD7, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x8D, /* 0x20-0x23 */ - 0x00, 0x00, 0xE6, 0x63, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0x4B, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x90, 0xDD, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x8B, 0x96, 0x00, 0x00, 0x96, 0xF3, /* 0x30-0x33 */ - 0x91, 0x69, 0x00, 0x00, 0xE6, 0x64, 0xEE, 0x88, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x90, 0x66, 0x92, 0x90, /* 0x38-0x3B */ - 0x8F, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xE6, 0x65, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0x68, 0x00, 0x00, /* 0x44-0x47 */ - 0xE6, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x8D, 0xBC, 0x91, 0xC0, 0xE6, 0x67, 0x00, 0x00, /* 0x50-0x53 */ - 0x8F, 0xD9, 0x95, 0x5D, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x66, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x8E, 0x8C, 0x00, 0x00, /* 0x5C-0x5F */ - 0x89, 0x72, 0x00, 0x00, 0xE6, 0x6D, 0x8C, 0x77, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x8E, 0x8E, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x8E, 0x8D, 0x00, 0x00, 0x98, 0x6C, /* 0x68-0x6B */ - 0xE6, 0x6C, 0xE6, 0x6B, 0x91, 0x46, 0x00, 0x00, /* 0x6C-0x6F */ - 0x8B, 0x6C, 0x98, 0x62, 0x8A, 0x59, 0x8F, 0xDA, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xEE, 0x89, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xE6, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xE6, 0x6F, 0x00, 0x00, /* 0x80-0x83 */ - 0xE6, 0x70, 0xE6, 0x6E, 0x00, 0x00, 0x8C, 0xD6, /* 0x84-0x87 */ - 0x00, 0x00, 0x97, 0x5F, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x8E, 0x8F, 0x94, 0x46, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xE6, 0x73, 0x00, 0x00, 0x90, 0xBE, /* 0x90-0x93 */ - 0x00, 0x00, 0x92, 0x61, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x97, 0x55, 0x00, 0x00, 0xE6, 0x76, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0xEA, 0x00, 0x00, /* 0x9C-0x9F */ - 0x90, 0xBD, 0xE6, 0x72, 0x00, 0x00, 0xE6, 0x77, /* 0xA0-0xA3 */ - 0x8C, 0xEB, 0xE6, 0x74, 0xE6, 0x75, 0xEE, 0x8A, /* 0xA4-0xA7 */ - 0xE6, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x90, 0xE0, 0x93, 0xC7, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x92, 0x4E, 0x00, 0x00, 0x89, 0xDB, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x94, 0xEE, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x8B, 0x62, 0x00, 0x00, 0xEE, 0x8B, 0x92, 0xB2, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0x7A, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xE6, 0x78, 0x00, 0x00, 0x00, 0x00, 0x92, 0x6B, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xBF, /* 0xC8-0xCB */ - 0x8A, 0xD0, 0xE6, 0x79, 0x00, 0x00, 0x90, 0x7A, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0xC8, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x98, 0x5F, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0x7B, 0xE6, 0x87, /* 0xD8-0xDB */ - 0x92, 0xB3, 0x00, 0x00, 0xE6, 0x86, 0xEE, 0x8C, /* 0xDC-0xDF */ - 0xE6, 0x83, 0xE6, 0x8B, 0xE6, 0x84, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xE6, 0x80, 0x00, 0x00, 0x92, 0xFA, 0xE6, 0x7E, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x7C, /* 0xE8-0xEB */ - 0x00, 0x00, 0x97, 0x40, 0x8E, 0x90, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0xE6, 0x81, 0x00, 0x00, 0xE6, 0x7D, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0x8E, 0xE6, 0x85, /* 0xF4-0xF7 */ - 0x8F, 0x94, 0x00, 0x00, 0x8C, 0xBF, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x91, 0xF8, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_8B[512] = { - 0x96, 0x64, 0x89, 0x79, 0x88, 0xE0, 0x00, 0x00, /* 0x00-0x03 */ - 0x93, 0xA3, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x89, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0xE6, 0x88, 0x00, 0x00, 0x93, 0xE4, 0x00, 0x00, /* 0x0C-0x0F */ - 0xE6, 0x8D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xE6, 0x82, 0x00, 0x00, 0xE6, 0x8C, 0xE6, 0x8E, /* 0x14-0x17 */ - 0x00, 0x00, 0x8C, 0xAA, 0xE6, 0x8A, 0x8D, 0x75, /* 0x18-0x1B */ - 0x00, 0x00, 0x8E, 0xD3, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xE6, 0x8F, 0x97, 0x77, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0x92, 0x00, 0x00, /* 0x24-0x27 */ - 0xE6, 0x95, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x93, /* 0x28-0x2B */ - 0x95, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x90, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x8B, 0xDE, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0x94, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xE6, 0x96, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xE6, 0x9A, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xE6, 0x97, 0x00, 0x00, 0xE6, 0x99, 0xE6, 0x98, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x8F, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0x9B, 0x00, 0x00, /* 0x54-0x57 */ - 0x8E, 0xAF, 0x00, 0x00, 0xE6, 0x9D, 0xE6, 0x9C, /* 0x58-0x5B */ - 0x95, 0x88, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x9F, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0x78, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x9E, /* 0x68-0x6B */ - 0xE6, 0xA0, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xA1, /* 0x6C-0x6F */ - 0x8B, 0x63, 0xE3, 0xBF, 0x8F, 0xF7, 0x00, 0x00, /* 0x70-0x73 */ - 0xE6, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x8C, 0xEC, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xE6, 0xA3, 0x00, 0x00, 0xEE, 0x90, /* 0x7C-0x7F */ - - 0xE6, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x5D, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x9D, 0xCC, 0x00, 0x00, /* 0x88-0x8B */ - 0xE6, 0xA5, 0x00, 0x00, 0xE6, 0xA6, 0x00, 0x00, /* 0x8C-0x8F */ - 0x8F, 0x51, 0x00, 0x00, 0xE6, 0xA7, 0xE6, 0xA8, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xA9, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xE6, 0xAA, 0xE6, 0xAB, 0x00, 0x00, /* 0x98-0x9B */ -}; - -static const unsigned char u2c_8C[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x4A, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xAC, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xAE, /* 0x3C-0x3F */ - 0x00, 0x00, 0xE6, 0xAD, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x93, 0xA4, 0x00, 0x00, /* 0x44-0x47 */ - 0xE6, 0xAF, 0x00, 0x00, 0x96, 0x4C, 0x00, 0x00, /* 0x48-0x4B */ - 0xE6, 0xB0, 0x00, 0x00, 0xE6, 0xB1, 0x00, 0x00, /* 0x4C-0x4F */ - 0xE6, 0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xE6, 0xB3, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x93, 0xD8, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x8F, 0xDB, 0xE6, 0xB4, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x8D, 0x8B, 0x98, 0xAC, /* 0x68-0x6B */ - 0xE6, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0xE6, 0xB6, 0x95, 0x5E, 0xE6, 0xB7, 0x00, 0x00, /* 0x78-0x7B */ - 0xE6, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xB8, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0xE6, 0xBA, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0xE6, 0xB9, 0xE6, 0xBB, 0x00, 0x00, /* 0x88-0x8B */ - 0x96, 0x65, 0xE6, 0xBC, 0xE6, 0xBD, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xE6, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xE6, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x8A, 0x4C, 0x92, 0xE5, 0x00, 0x00, /* 0x9C-0x9F */ - 0x95, 0x89, 0x8D, 0xE0, 0x8D, 0x76, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x6E, /* 0xA4-0xA7 */ - 0x89, 0xDD, 0x94, 0xCC, 0xE6, 0xC3, 0x8A, 0xD1, /* 0xA8-0xAB */ - 0x90, 0xD3, 0xE6, 0xC2, 0xE6, 0xC7, 0x92, 0x99, /* 0xAC-0xAF */ - 0x96, 0xE1, 0x00, 0x00, 0xE6, 0xC5, 0xE6, 0xC6, /* 0xB0-0xB3 */ - 0x8B, 0x4D, 0x00, 0x00, 0xE6, 0xC8, 0x94, 0x83, /* 0xB4-0xB7 */ - 0x91, 0xDD, 0x00, 0x00, 0x00, 0x00, 0x94, 0xEF, /* 0xB8-0xBB */ - 0x93, 0x5C, 0xE6, 0xC4, 0x00, 0x00, 0x96, 0x66, /* 0xBC-0xBF */ - 0x89, 0xEA, 0xE6, 0xCA, 0x98, 0x47, 0x92, 0xC0, /* 0xC0-0xC3 */ - 0x98, 0x64, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x91, /* 0xC4-0xC7 */ - 0xE6, 0xC9, 0x00, 0x00, 0x91, 0xAF, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0xE6, 0xDA, 0x91, 0x47, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x93, 0xF6, 0x00, 0x00, 0x95, 0x6F, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xCD, 0x8E, 0x5E, /* 0xD8-0xDB */ - 0x8E, 0x92, 0x00, 0x00, 0x8F, 0xDC, 0x00, 0x00, /* 0xDC-0xDF */ - 0x94, 0x85, 0x00, 0x00, 0x8C, 0xAB, 0xE6, 0xCC, /* 0xE0-0xE3 */ - 0xE6, 0xCB, 0x00, 0x00, 0x95, 0x8A, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x8E, 0xBF, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x93, 0x71, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xEE, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xEE, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xCF, 0xE6, 0xD0, /* 0xF8-0xFB */ - 0x8D, 0x77, 0xE6, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_8D[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xE6, 0xD1, 0xE6, 0xD2, 0x00, 0x00, 0xE6, 0xD4, /* 0x04-0x07 */ - 0x91, 0xA1, 0x00, 0x00, 0xE6, 0xD3, 0x8A, 0xE4, /* 0x08-0x0B */ - 0x00, 0x00, 0xE6, 0xD6, 0x00, 0x00, 0xE6, 0xD5, /* 0x0C-0x0F */ - 0xE6, 0xD7, 0x00, 0x00, 0xEE, 0x93, 0xE6, 0xD9, /* 0x10-0x13 */ - 0xE6, 0xDB, 0x00, 0x00, 0xE6, 0xDC, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x90, 0xD4, 0x00, 0x00, 0x8E, 0xCD, 0xE6, 0xDD, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x71, /* 0x68-0x6B */ - 0x00, 0x00, 0xE6, 0xDE, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x91, 0x96, 0xE6, 0xDF, 0x00, 0x00, 0xE6, 0xE0, /* 0x70-0x73 */ - 0x95, 0x8B, 0x00, 0x00, 0xEE, 0x94, 0x8B, 0x4E, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xE6, 0xE1, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x92, 0xB4, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0x7A, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xE6, 0xE2, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8E, 0xEF, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x90, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0xAB, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE5, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE4, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE3, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xEB, /* 0xC8-0xCB */ - 0xE6, 0xE9, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE6, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE8, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE7, 0xE6, 0xEA, /* 0xD8-0xDB */ - 0x00, 0x00, 0x8B, 0x97, 0x00, 0x00, 0xE6, 0xEE, /* 0xDC-0xDF */ - 0x00, 0x00, 0x90, 0xD5, 0x00, 0x00, 0xE6, 0xEF, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x8C, 0xD7, 0x00, 0x00, 0xE6, 0xEC, 0xE6, 0xED, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x48, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0xB5, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x91, 0x48, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0xE6, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xF3, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_8E[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xE6, 0xF1, 0xE6, 0xF2, 0x97, 0x78, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0xA5, /* 0x0C-0x0F */ - 0xE6, 0xF6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0xE6, 0xF4, 0xE6, 0xF5, 0xE6, 0xF7, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0x48, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xE6, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xE6, 0xFB, 0xE6, 0xF9, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xF8, 0x00, 0x00, /* 0x40-0x43 */ - 0x92, 0xFB, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x40, /* 0x44-0x47 */ - 0xE7, 0x44, 0xE7, 0x41, 0xE6, 0xFC, 0x00, 0x00, /* 0x48-0x4B */ - 0xE7, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xE7, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xE7, 0x4A, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xE7, 0x45, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0xD6, /* 0x5C-0x5F */ - 0xE7, 0x47, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x49, /* 0x60-0x63 */ - 0xE7, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0x4C, 0x00, 0x00, /* 0x70-0x73 */ - 0x8F, 0x52, 0x00, 0x00, 0xE7, 0x4B, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xE7, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xE7, 0x4E, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xE7, 0x51, 0xE7, 0x50, 0x00, 0x00, 0xE7, 0x4F, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0x53, 0xE7, 0x52, /* 0x88-0x8B */ - 0x00, 0x00, 0x96, 0xF4, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xE7, 0x55, 0x00, 0x00, 0xE7, 0x54, /* 0x90-0x93 */ - 0xE7, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xE7, 0x57, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xE7, 0x59, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0x58, 0x90, 0x67, /* 0xA8-0xAB */ - 0xE7, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xEB, /* 0xAC-0xAF */ - 0xE7, 0x5B, 0xE7, 0x5D, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0x5E, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xE7, 0x5F, 0xE7, 0x5C, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xE7, 0x60, 0x00, 0x00, 0x8E, 0xD4, 0xE7, 0x61, /* 0xC8-0xCB */ - 0x8B, 0x4F, 0x8C, 0x52, 0x00, 0x00, 0xEE, 0x96, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0xAC, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x62, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0xEE, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x93, 0x5D, 0xE7, 0x63, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x66, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x8E, 0xB2, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x65, /* 0xF8-0xFB */ - 0xE7, 0x64, 0x8C, 0x79, 0xE7, 0x67, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_8F[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x72, /* 0x00-0x03 */ - 0x00, 0x00, 0xE7, 0x69, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x8D, 0xDA, 0xE7, 0x68, 0x00, 0x00, /* 0x08-0x0B */ - 0xE7, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0x6B, 0xE7, 0x6D, /* 0x10-0x13 */ - 0x95, 0xE3, 0xE7, 0x6A, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xE7, 0x6C, 0x00, 0x00, 0xE7, 0x70, /* 0x18-0x1B */ - 0xE7, 0x6E, 0x8B, 0x50, 0x00, 0x00, 0xE7, 0x6F, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0x72, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x94, 0x79, 0x97, 0xD6, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x53, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x73, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x97, 0x41, 0xE7, 0x75, 0x00, 0x00, 0xE7, 0x74, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0x78, 0x97, 0x60, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0x77, 0x00, 0x00, /* 0x40-0x43 */ - 0x8A, 0x8D, 0xE7, 0x76, 0xE7, 0x7B, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xE7, 0x7A, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xE7, 0x79, 0x93, 0x51, 0xE7, 0x7C, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x7D, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0xE7, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x8D, 0x8C, /* 0x5C-0x5F */ - 0x00, 0x00, 0x8C, 0x44, 0xE7, 0x80, 0xE7, 0x81, /* 0x60-0x63 */ - 0xE7, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x68, /* 0x98-0x9B */ - 0xE7, 0x83, 0x00, 0x00, 0x8E, 0xAB, 0xE7, 0x84, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x85, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x9F, /* 0xA4-0xA7 */ - 0x99, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0xE7, 0x86, 0xE3, 0x90, 0xE7, 0x87, /* 0xAC-0xAF */ - 0x92, 0x43, 0x90, 0x4A, 0x94, 0x5F, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x88, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x95, 0xD3, 0x92, 0xD2, /* 0xB8-0xBB */ - 0x8D, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x92, 0x48, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0x49, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x96, 0x98, 0x90, 0x76, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x8C, 0x7D, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x8B, 0xDF, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x95, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0x89, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0x8B, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xE7, 0x8A, 0x89, 0xDE, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x93, 0xF4, 0xE7, 0x8C, 0x94, 0x97, /* 0xE8-0xEB */ - 0x00, 0x00, 0x93, 0x52, 0x00, 0x00, 0xE7, 0x8D, /* 0xEC-0xEF */ - 0x8F, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xE7, 0x8F, 0x00, 0x00, 0x00, 0x00, 0x96, 0xC0, /* 0xF4-0xF7 */ - 0xE7, 0x9E, 0xE7, 0x91, 0xE7, 0x92, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x92, 0xC7, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_90[512] = { - 0x91, 0xDE, 0x91, 0x97, 0x00, 0x00, 0x93, 0xA6, /* 0x00-0x03 */ - 0x00, 0x00, 0xE7, 0x90, 0x8B, 0x74, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x99, /* 0x08-0x0B */ - 0x00, 0x00, 0xE7, 0x96, 0xE7, 0xA3, 0x93, 0xA7, /* 0x0C-0x0F */ - 0x92, 0x80, 0xE7, 0x93, 0x00, 0x00, 0x92, 0xFC, /* 0x10-0x13 */ - 0x93, 0x72, 0xE7, 0x94, 0xE7, 0x98, 0x90, 0x80, /* 0x14-0x17 */ - 0x00, 0x00, 0x94, 0x87, 0x92, 0xCA, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x90, 0xC0, 0xE7, 0x97, 0x91, 0xAC, /* 0x1C-0x1F */ - 0x91, 0xA2, 0xE7, 0x95, 0x88, 0xA7, 0x98, 0x41, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x9A, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x91, 0xDF, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x8F, 0x54, 0x90, 0x69, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0xE7, 0x9C, 0xE7, 0x9B, 0x00, 0x00, /* 0x34-0x37 */ - 0x88, 0xED, 0xE7, 0x9D, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x95, 0x4E, 0x00, 0x00, 0xE7, 0xA5, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x93, 0xD9, 0x90, 0x8B, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x92, 0x78, 0x00, 0x00, 0x8B, 0xF6, /* 0x44-0x47 */ - 0x00, 0x00, 0xE7, 0xA4, 0x97, 0x56, 0x89, 0x5E, /* 0x48-0x4B */ - 0x00, 0x00, 0x95, 0xD5, 0x89, 0xDF, 0xE7, 0x9F, /* 0x4C-0x4F */ - 0xE7, 0xA0, 0xE7, 0xA1, 0xE7, 0xA2, 0x93, 0xB9, /* 0x50-0x53 */ - 0x92, 0x42, 0x88, 0xE1, 0xE7, 0xA6, 0x00, 0x00, /* 0x54-0x57 */ - 0xE7, 0xA7, 0xEA, 0xA1, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x91, 0xBB, 0x00, 0x00, 0xE7, 0xA8, 0x00, 0x00, /* 0x5C-0x5F */ - 0x89, 0x93, 0x91, 0x6B, 0x00, 0x00, 0x8C, 0xAD, /* 0x60-0x63 */ - 0x00, 0x00, 0x97, 0x79, 0x00, 0x00, 0xEE, 0x99, /* 0x64-0x67 */ - 0xE7, 0xA9, 0x93, 0x4B, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x91, 0x98, 0x8E, 0xD5, 0xE7, 0xAA, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xAD, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x8F, 0x85, 0xE7, 0xAB, 0x91, 0x4A, /* 0x74-0x77 */ - 0x91, 0x49, 0x00, 0x00, 0x88, 0xE2, 0x00, 0x00, /* 0x78-0x7B */ - 0x97, 0xC9, 0xE7, 0xAF, 0x00, 0x00, 0x94, 0xF0, /* 0x7C-0x7F */ - - 0xE7, 0xB1, 0xE7, 0xB0, 0xE7, 0xAE, 0xE2, 0x84, /* 0x80-0x83 */ - 0x8A, 0xD2, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x8E, /* 0x84-0x87 */ - 0x00, 0x00, 0xE7, 0xB3, 0xE7, 0xB2, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xB4, /* 0x8C-0x8F */ - 0x00, 0x00, 0x97, 0x57, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x93, 0xDF, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0x4D, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xE7, 0xB5, 0x00, 0x00, 0x8E, 0xD7, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xB6, /* 0xAC-0xAF */ - 0x00, 0x00, 0xE7, 0xB7, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xE7, 0xB8, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x93, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x88, 0xE8, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x8D, 0x78, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x98, 0x59, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xBC, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0x9A, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x8C, 0x53, 0xE7, 0xB9, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xE7, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x95, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x8A, 0x73, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x97, 0x58, 0x00, 0x00, 0x8B, 0xBD, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x93, 0x73, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_91[512] = { - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xBD, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xBE, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xEE, 0x9C, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xE7, 0xBF, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x9D, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x93, 0x41, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xE7, 0xC1, 0x00, 0x00, 0xE7, 0xC0, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x93, 0xD1, 0xE7, 0xC2, 0x8F, 0x55, /* 0x48-0x4B */ - 0x8E, 0xDE, 0x94, 0x7A, 0x92, 0x91, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x8E, 0xF0, 0x00, 0x00, /* 0x50-0x53 */ - 0x90, 0x8C, 0x00, 0x00, 0xE7, 0xC3, 0x00, 0x00, /* 0x54-0x57 */ - 0xE7, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x90, 0x7C, 0xE7, 0xC5, /* 0x60-0x63 */ - 0x00, 0x00, 0xE7, 0xC6, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xE7, 0xC7, 0x97, 0x8F, 0x00, 0x00, /* 0x68-0x6B */ - 0x8F, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xC9, 0xE7, 0xC8, /* 0x70-0x73 */ - 0x00, 0x00, 0x8D, 0x79, 0x00, 0x00, 0x8D, 0x93, /* 0x74-0x77 */ - 0x8E, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xCC, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x86, /* 0x84-0x87 */ - 0x00, 0x00, 0xE7, 0xCB, 0x00, 0x00, 0xE7, 0xCA, /* 0x88-0x8B */ - 0x00, 0x00, 0x91, 0xE7, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x8C, 0xED, 0x00, 0x00, 0x90, 0xC1, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0xAE, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x8F, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xCD, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x8F, 0xDD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xD0, 0xE7, 0xCE, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xCF, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xE7, 0xD2, 0xE7, 0xD1, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x8F, 0xF8, 0x00, 0x00, 0xE7, 0xD3, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xE7, 0xD4, 0xE7, 0xD5, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0xCE, 0x8D, 0xD1, /* 0xC4-0xC7 */ - 0x8E, 0xDF, 0xE7, 0xD6, 0x00, 0x00, 0xE7, 0xD7, /* 0xC8-0xCB */ - 0x97, 0xA2, 0x8F, 0x64, 0x96, 0xEC, 0x97, 0xCA, /* 0xCC-0xCF */ - 0xE7, 0xD8, 0x8B, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xD9, 0xEE, 0x9F, /* 0xD4-0xD7 */ - 0x93, 0x42, 0x00, 0x00, 0xEE, 0x9E, 0xE7, 0xDC, /* 0xD8-0xDB */ - 0x8A, 0x98, 0x90, 0x6A, 0xEE, 0xA0, 0xE7, 0xDA, /* 0xDC-0xDF */ - 0x00, 0x00, 0xE7, 0xDB, 0x00, 0x00, 0x92, 0xDE, /* 0xE0-0xE3 */ - 0xEE, 0xA3, 0xEE, 0xA4, 0x96, 0x74, 0x8B, 0xFA, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xEE, 0xA1, 0xEE, 0xA2, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xE7, 0xDE, 0xE7, 0xDF, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0xE7, 0xDD, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xE1, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_92[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0xA5, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0xA7, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x93, 0xDD, 0x8A, 0x62, 0x00, 0x00, /* 0x0C-0x0F */ - 0xEE, 0xA6, 0xE7, 0xE5, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xE7, 0xE2, 0xE7, 0xE4, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xE0, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xE8, 0x6E, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0xE7, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x97, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x8C, 0xD8, /* 0x34-0x37 */ - 0x00, 0x00, 0xEE, 0xAE, 0xEE, 0xA8, 0x00, 0x00, /* 0x38-0x3B */ - 0xEE, 0xAA, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xED, /* 0x3C-0x3F */ - 0xEE, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x93, 0x53, 0xE7, 0xE8, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0xE7, 0xEB, 0xE7, 0xE9, 0x00, 0x00, 0xE7, 0xEE, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0xAB, 0x00, 0x00, /* 0x4C-0x4F */ - 0xE7, 0xEF, 0xEE, 0xAD, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xE7, /* 0x54-0x57 */ - 0x00, 0x00, 0xEE, 0xAC, 0xE7, 0xF4, 0x89, 0x94, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xE6, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0xAB, 0x00, 0x00, /* 0x60-0x63 */ - 0xE7, 0xEA, 0x00, 0x00, 0x8F, 0xDE, 0xEE, 0xAF, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x8D, 0x7A, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xB1, /* 0x74-0x77 */ - 0xEE, 0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0x67, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x8B, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x65, /* 0x80-0x83 */ - 0x00, 0x00, 0x93, 0xBA, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xED, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x91, 0x4C, 0x00, 0x00, 0xE7, 0xF2, /* 0x90-0x93 */ - 0x00, 0x00, 0xE7, 0xEC, 0xE7, 0xF1, 0x00, 0x00, /* 0x94-0x97 */ - 0x96, 0xC1, 0x00, 0x00, 0x92, 0xB6, 0xE7, 0xF3, /* 0x98-0x9B */ - 0xE7, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xB0, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x91, 0x4B, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xF7, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xE7, 0xF6, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xF5, /* 0xCC-0xCF */ - 0xEE, 0xB6, 0x00, 0x00, 0x96, 0x4E, 0xEE, 0xBA, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xEE, 0xB8, 0x00, 0x00, 0xEE, 0xB4, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xEE, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0xEE, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x8F, 0x9B, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xB3, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xE7, 0xF8, 0x95, 0xDD, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x89, 0x73, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x95, 0x65, 0x92, 0x92, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x8B, 0x98, 0xED, 0x49, 0xE7, 0xFA, 0xEE, 0xBD, /* 0xF8-0xFB */ - 0x8D, 0x7C, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xC0, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_93[512] = { - 0x00, 0x00, 0x00, 0x00, 0xEE, 0xC2, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x8E, 0x4B, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xF9, /* 0x0C-0x0F */ - 0x90, 0x8D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x90, 0x8E, 0xE8, 0x40, 0xE8, 0x42, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0xEE, 0xC1, 0xEE, 0xBF, 0x00, 0x00, /* 0x1C-0x1F */ - 0x8F, 0xF9, 0xEE, 0xBC, 0xE8, 0x41, 0xE8, 0x43, /* 0x20-0x23 */ - 0x00, 0x00, 0xEE, 0xBB, 0x8B, 0xD1, 0x00, 0x00, /* 0x24-0x27 */ - 0x95, 0x64, 0x00, 0x00, 0x00, 0x00, 0x8E, 0xE0, /* 0x28-0x2B */ - 0x98, 0x42, 0x00, 0x00, 0xE7, 0xFC, 0x8D, 0xF6, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x98, 0x5E, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0xE8, 0x45, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0x44, 0xE8, 0x46, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xE7, 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0xED, 0x42, 0x00, 0x00, 0x00, 0x00, 0x93, 0xE7, /* 0x48-0x4B */ - 0x00, 0x00, 0x93, 0x74, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x92, 0xD5, 0x00, 0x00, 0xE8, 0x4B, 0xEE, 0xC4, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x62, /* 0x58-0x5B */ - 0xE8, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xE8, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x8C, 0x4C, 0x00, 0x00, 0xE8, 0x4A, 0x00, 0x00, /* 0x6C-0x6F */ - 0xEE, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x8C, 0xAE, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xE8, 0x49, 0x00, 0x00, 0x8F, 0xDF, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x8A, 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xE8, 0x4F, 0x00, 0x00, 0x8D, 0xBD, 0x91, 0x99, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x92, 0xC8, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xEE, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x8A, 0x5A, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xE8, 0x4D, 0xE8, 0x4E, 0x92, 0xC1, 0x00, 0x00, /* 0xAC-0xAF */ - 0xE8, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xE8, 0x50, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x56, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0xC6, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xE8, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0xE8, 0x58, 0x93, 0x4C, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0x51, 0xE8, 0x52, /* 0xD4-0xD7 */ - 0xE8, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0xE8, 0x57, 0xEE, 0xC7, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x8B, 0xBE, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xE8, 0x5A, 0xE8, 0x54, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xE8, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xEE, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_94[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x5E, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x5F, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xE8, 0x60, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x5D, /* 0x10-0x13 */ - 0xE8, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x8F, 0xE0, 0x93, 0xA8, 0xE8, 0x5B, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xE8, 0x64, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x62, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xEE, 0xC9, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0xE8, 0x63, 0xE8, 0x61, 0x00, 0x00, /* 0x34-0x37 */ - 0x91, 0xF6, 0x00, 0x00, 0xE8, 0x65, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xE8, 0x66, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xE8, 0x68, 0xEE, 0xCA, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0xEE, 0xCB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x8A, 0xD3, 0xE8, 0x67, 0x96, 0xF8, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0x73, 0xE8, 0x69, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0x6C, 0x00, 0x00, /* 0x5C-0x5F */ - 0xE8, 0x6A, 0x00, 0x00, 0xE8, 0x6B, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0x6D, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xE8, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xE8, 0x70, 0x00, 0x00, 0xE8, 0x71, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xE8, 0x74, 0xE8, 0x72, 0xE8, 0x75, 0xE8, 0x77, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xE8, 0x76, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ -}; - -static const unsigned char u2c_95[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0xB7, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x96, 0xE5, 0x00, 0x00, 0xE8, 0x78, 0x91, 0x4D, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x79, /* 0x84-0x87 */ - 0x00, 0x00, 0x95, 0xC2, 0xE8, 0x7A, 0x8A, 0x4A, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x5B, /* 0x8C-0x8F */ - 0x00, 0x00, 0x8A, 0xD5, 0xEE, 0xCC, 0x8A, 0xD4, /* 0x90-0x93 */ - 0xE8, 0x7B, 0x00, 0x00, 0xE8, 0x7C, 0x00, 0x00, /* 0x94-0x97 */ - 0xE8, 0x7D, 0xE8, 0x7E, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xE8, 0x80, 0x00, 0x00, 0x8A, 0xD6, 0x8A, 0x74, /* 0xA0-0xA3 */ - 0x8D, 0x7D, 0x94, 0xB4, 0x00, 0x00, 0xE8, 0x82, /* 0xA4-0xA7 */ - 0xE8, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0xE8, 0x83, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0x7B, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xE8, 0x86, 0x00, 0x00, 0xE8, 0x85, /* 0xB8-0xBB */ - 0xE8, 0x84, 0x00, 0x00, 0xE8, 0x87, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x8A, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xC5, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0x88, 0x00, 0x00, /* 0xC8-0xCB */ - 0xE8, 0x8C, 0xE8, 0x8B, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xE8, 0x8E, 0xE8, 0x8D, 0xE8, 0x8F, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x93, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xE8, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0xE8, 0x91, 0xE8, 0x93, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xE8, 0x92, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ -}; - -static const unsigned char u2c_96[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x95, 0x8C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xE8, 0x94, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xE8, 0x95, 0x00, 0x00, 0x8D, 0xE3, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0x96, 0xE8, 0x97, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0x68, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x6A, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0xA2, /* 0x3C-0x3F */ - 0x91, 0xC9, 0x00, 0x00, 0xE8, 0x98, 0x00, 0x00, /* 0x40-0x43 */ - 0x95, 0x8D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x9B, /* 0x48-0x4B */ - 0xE8, 0x99, 0x8D, 0x7E, 0x00, 0x00, 0xE8, 0x9A, /* 0x4C-0x4F */ - 0x8C, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0xC3, /* 0x58-0x5B */ - 0xE8, 0x9D, 0xE8, 0x9F, 0xE8, 0x9E, 0xE8, 0xA0, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0x40, 0x90, 0x77, /* 0x60-0x63 */ - 0x8F, 0x9C, 0x8A, 0xD7, 0xE8, 0xA1, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0x86, 0x00, 0x00, /* 0x68-0x6B */ - 0xE8, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x89, 0x41, 0x00, 0x00, 0xE8, 0xA2, 0x92, 0xC2, /* 0x70-0x73 */ - 0x00, 0x00, 0x97, 0xCB, 0x93, 0xA9, 0xE8, 0x9C, /* 0x74-0x77 */ - 0x97, 0xA4, 0x00, 0x00, 0x8C, 0xAF, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x97, 0x7A, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x8B, 0xF7, 0x97, 0xB2, 0x00, 0x00, /* 0x84-0x87 */ - 0x8C, 0x47, 0x00, 0x00, 0x91, 0xE0, 0xE4, 0x40, /* 0x88-0x8B */ - 0x00, 0x00, 0xE8, 0xA4, 0x8A, 0x4B, 0x90, 0x8F, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x8A, 0x75, 0xE8, 0xA6, 0x00, 0x00, 0xE8, 0xA7, /* 0x94-0x97 */ - 0xE8, 0xA5, 0x8C, 0x84, 0x00, 0x00, 0x8D, 0xDB, /* 0x98-0x9B */ - 0x8F, 0xE1, 0xEE, 0xCF, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x89, 0x42, 0x00, 0x00, 0x00, 0x00, 0x97, 0xD7, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xA9, /* 0xA4-0xA7 */ - 0xE7, 0xAC, 0x00, 0x00, 0xE8, 0xA8, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xD0, /* 0xAC-0xAF */ - 0xE8, 0xAC, 0xE8, 0xAA, 0xE8, 0xAB, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xE8, 0xAD, 0x00, 0x00, 0xE8, 0xAE, 0x97, 0xEA, /* 0xB4-0xB7 */ - 0xE8, 0xAF, 0xE8, 0xB0, 0x00, 0x00, 0x90, 0xC7, /* 0xB8-0xBB */ - 0x94, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x90, 0x9D, 0x8A, 0xE5, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x97, 0x59, 0x89, 0xEB, 0x8F, 0x57, 0x8C, 0xD9, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xE8, 0xB3, 0x00, 0x00, 0xE8, 0xB2, /* 0xC8-0xCB */ - 0x8E, 0x93, 0xE8, 0xB4, 0xE8, 0xB1, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x8E, 0x47, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xE8, 0xB8, 0xE5, 0xAB, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x99, 0xD4, 0x00, 0x00, 0x90, 0x97, /* 0xD8-0xDB */ - 0xE8, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0xA3, 0x93, 0xEF, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x89, 0x4A, 0x00, 0x00, 0x90, 0xE1, 0x8E, 0xB4, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x95, 0xB5, 0x00, 0x00, 0x89, 0x5F, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0xEB, 0x97, 0x8B, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xE8, 0xB9, 0x00, 0x00, 0x93, 0x64, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_97[512] = { - 0x8E, 0xF9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xE8, 0xBA, 0x00, 0x00, 0xE8, 0xBB, 0x90, 0x6B, /* 0x04-0x07 */ - 0xE8, 0xBC, 0x00, 0x00, 0x97, 0xEC, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0xE8, 0xB7, 0xE8, 0xBE, 0xE8, 0xC0, /* 0x0C-0x0F */ - 0x00, 0x00, 0xE8, 0xBF, 0x00, 0x00, 0xE8, 0xBD, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xC1, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xE8, 0xC2, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x91, 0x9A, 0x00, 0x00, 0x89, 0xE0, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0xE8, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x96, 0xB6, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xC4, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xE8, 0xC5, 0x00, 0x00, 0x98, 0x49, 0xEE, 0xD1, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x9E, 0x50, 0xE8, 0xC6, 0x00, 0x00, 0xEE, 0xD2, /* 0x38-0x3B */ - 0x00, 0x00, 0xE8, 0xC7, 0xE8, 0xC8, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xCC, 0xEE, 0xD3, /* 0x40-0x43 */ - 0xE8, 0xC9, 0x00, 0x00, 0xE8, 0xCA, 0x00, 0x00, /* 0x44-0x47 */ - 0xE8, 0xCB, 0xE8, 0xCD, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0xEE, 0xD4, 0x00, 0x00, 0xEE, 0xD5, /* 0x4C-0x4F */ - 0x00, 0x00, 0xEE, 0xD6, 0x90, 0xC2, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xEE, 0xD7, 0x96, 0xF5, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x90, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0xE8, 0xCE, 0x00, 0x00, 0x94, 0xF1, 0x00, 0x00, /* 0x5C-0x5F */ - 0xE8, 0xCF, 0xEA, 0x72, 0x96, 0xCA, 0x00, 0x00, /* 0x60-0x63 */ - 0xE8, 0xD0, 0x00, 0x00, 0xE8, 0xD1, 0x00, 0x00, /* 0x64-0x67 */ - 0xE8, 0xD2, 0x8A, 0x76, 0x00, 0x00, 0xE8, 0xD4, /* 0x68-0x6B */ - 0x00, 0x00, 0x90, 0x78, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0xE8, 0xD5, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x8C, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xE8, 0xD6, 0xE8, 0xDA, 0x00, 0x00, /* 0x78-0x7B */ - 0xE8, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xE8, 0xD9, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x8A, 0x93, 0xE8, 0xD7, 0xE8, 0xDB, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xDC, /* 0x88-0x8B */ - 0x00, 0x00, 0x88, 0xC6, 0x00, 0x00, 0xE8, 0xDD, /* 0x8C-0x8F */ - 0xE8, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x8F, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xE8, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x8B, 0x66, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xE2, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xE1, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xE8, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x91, /* 0xA8-0xAB */ - 0x00, 0x00, 0x95, 0xDA, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xE3, /* 0xB0-0xB3 */ - 0xE8, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xE5, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xE6, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xE8, 0xE7, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xE8, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8A, 0xD8, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xE8, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xE8, 0xEA, 0x94, 0x42, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xEC, 0x89, 0xB9, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xE8, 0xEF, 0xE8, 0xEE, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x43, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8B, 0xBF, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_98[512] = { - 0x00, 0x00, 0x95, 0xC5, 0x92, 0xB8, 0x8D, 0xA0, /* 0x00-0x03 */ - 0x00, 0x00, 0x8D, 0x80, 0x8F, 0x87, 0x00, 0x00, /* 0x04-0x07 */ - 0x90, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0xE8, 0xF1, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xF0, /* 0x0C-0x0F */ - 0x97, 0x61, 0x8A, 0xE6, 0x94, 0xD0, 0x93, 0xDA, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x9C, /* 0x14-0x17 */ - 0x97, 0xCC, 0x00, 0x00, 0x8C, 0x7A, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xE8, 0xF4, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0xE8, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x96, 0x6A, 0x93, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x89, 0x6F, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xF5, /* 0x34-0x37 */ - 0xE8, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x95, 0x70, /* 0x38-0x3B */ - 0x97, 0x8A, 0xE8, 0xF6, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xF7, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xF9, /* 0x48-0x4B */ - 0x91, 0xE8, 0x8A, 0x7A, 0x8A, 0x7B, 0xE8, 0xF8, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x8A, 0xE7, 0x8C, 0xB0, 0x00, 0x00, 0xEE, 0xD8, /* 0x54-0x57 */ - 0x8A, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x93, 0x5E, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x97, 0xDE, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0xEE, 0xD9, 0x00, 0x00, 0x8C, 0xDA, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xFA, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xFB, /* 0x6C-0x6F */ - 0xE8, 0xFC, 0xE9, 0x40, 0x00, 0x00, 0xE9, 0x42, /* 0x70-0x73 */ - 0xE9, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x95, 0x97, 0x00, 0x00, 0xE9, 0x43, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x44, /* 0xAC-0xAF */ - 0x00, 0x00, 0xE9, 0x45, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0x46, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x48, /* 0xC0-0xC3 */ - 0xE9, 0x47, 0x00, 0x00, 0xE9, 0x49, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0xF2, /* 0xD8-0xDB */ - 0xE3, 0xCA, 0x00, 0x00, 0x00, 0x00, 0x90, 0x48, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0x51, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xE9, 0x4A, 0x00, 0x00, 0xE9, 0x4B, /* 0xE8-0xEB */ - 0x00, 0x00, 0x99, 0xAA, 0x9F, 0x5A, 0x94, 0xD1, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x88, 0xF9, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x88, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x8E, 0x94, 0x96, 0x4F, 0x8F, 0xFC, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_99[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x4C, /* 0x00-0x03 */ - 0x00, 0x00, 0x96, 0xDD, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xE9, 0x4D, 0x97, 0x7B, 0x00, 0x00, /* 0x08-0x0B */ - 0x89, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x8E, 0x60, 0x00, 0x00, 0xE9, 0x4E, 0x89, 0xEC, /* 0x10-0x13 */ - 0xE9, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xE9, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0xE9, 0x52, 0xE9, 0x53, 0x00, 0x00, /* 0x1C-0x1F */ - 0xE9, 0x55, 0xE9, 0x51, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0xE9, 0x54, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xDC, /* 0x24-0x27 */ - 0x8A, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0xE9, 0x56, 0x00, 0x00, 0xE9, 0x57, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xE9, 0x58, 0xE9, 0x59, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0x5A, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0xE9, 0x5C, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xE9, 0x5B, 0x00, 0x00, 0xE9, 0x5E, /* 0x48-0x4B */ - 0xE9, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xE9, 0x5D, 0xE9, 0x5F, 0xE9, 0x60, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xE9, 0x62, 0x00, 0x00, 0x8B, 0xC0, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x8E, 0xF1, 0xE9, 0x63, /* 0x94-0x97 */ - 0xE9, 0x64, 0x8D, 0x81, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0xDE, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xE9, 0x65, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x8A, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x94, 0x6E, 0xE9, 0x66, 0xE9, 0x67, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x79, /* 0xB0-0xB3 */ - 0x93, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0xE9, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x94, 0x9D, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x91, 0xCA, 0x89, 0x77, 0x8B, 0xEC, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x8B, 0xED, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x92, 0x93, 0xE9, 0x6D, 0x8B, 0xEE, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x89, 0xED, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xE9, 0x6C, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x6A, /* 0xD8-0xDB */ - 0x00, 0x00, 0xE9, 0x6B, 0x00, 0x00, 0xE9, 0x69, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0x77, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xE9, 0x6E, 0xE9, 0x6F, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0xE9, 0x70, 0xE9, 0x71, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xE9, 0x73, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x72, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x78, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_9A[512] = { - 0x00, 0x00, 0xE9, 0x74, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xE9, 0x76, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0x52, 0xE9, 0x75, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x91, 0x9B, 0x8C, 0xB1, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xE9, 0x78, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x91, 0xCB, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x79, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x93, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x7A, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0x80, 0x00, 0x00, /* 0x3C-0x3F */ - 0xE9, 0x7D, 0x00, 0x00, 0xE9, 0x7C, 0xE9, 0x7E, /* 0x40-0x43 */ - 0x00, 0x00, 0xE9, 0x7B, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0xE9, 0x82, 0xEE, 0xDF, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xE9, 0x81, 0x00, 0x00, 0xE9, 0x84, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x8B, 0xC1, 0xE9, 0x83, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x85, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0x86, 0x00, 0x00, /* 0x60-0x63 */ - 0xE9, 0x88, 0xE9, 0x87, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xE9, 0x89, 0xE9, 0x8B, 0xE9, 0x8A, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x8D, 0x9C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0xE9, 0x8C, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0xE9, 0x8D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x8A, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0xE9, 0x8E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xE9, 0x8F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x90, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x90, /* 0xCC-0xCF */ - 0x00, 0x00, 0xE9, 0x91, 0x00, 0x00, 0xE9, 0x92, /* 0xD0-0xD3 */ - 0xE9, 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x8D, 0x82, 0xEE, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xEE, 0xE1, 0x00, 0x00, 0xE9, 0x94, 0xE9, 0x95, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0x96, 0xE9, 0x97, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0x98, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x94, 0xAF, 0xE9, 0x9A, /* 0xE8-0xEB */ - 0x00, 0x00, 0x95, 0x45, 0xE9, 0x9B, 0xE9, 0x99, /* 0xEC-0xEF */ - 0x00, 0x00, 0xE9, 0x9D, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xE9, 0x9C, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x9E, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x9F, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_9B[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xA0, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xE9, 0xA1, 0x00, 0x00, 0xE9, 0xA2, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xA3, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xA4, 0xE9, 0xA5, /* 0x20-0x23 */ - 0x00, 0x00, 0xE9, 0xA6, 0x00, 0x00, 0xE9, 0xA7, /* 0x24-0x27 */ - 0xE9, 0xA8, 0xE9, 0xA9, 0xE9, 0xAA, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xAB, 0xE9, 0xAC, /* 0x2C-0x2F */ - 0x00, 0x00, 0x9F, 0x54, 0xE9, 0xAD, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xF6, /* 0x38-0x3B */ - 0x8B, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x8A, 0x40, 0x8D, 0xB0, 0xE9, 0xAF, /* 0x40-0x43 */ - 0xE9, 0xAE, 0x96, 0xA3, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0xE9, 0xB1, 0xE9, 0xB2, 0xE9, 0xB0, /* 0x4C-0x4F */ - 0x00, 0x00, 0xE9, 0xB3, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x96, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xE9, 0xB4, 0x00, 0x00, 0x8B, 0x9B, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x44, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0xE3, 0x00, 0x00, /* 0x70-0x73 */ - 0xE9, 0xB5, 0xEE, 0xE2, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xB7, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x88, 0xBC, 0xEE, 0xE4, /* 0x8C-0x8F */ - 0x00, 0x00, 0xE9, 0xB8, 0x95, 0xA9, 0xE9, 0xB6, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xB9, 0xE9, 0xBA, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xBB, /* 0x9C-0x9F */ - 0xE9, 0xBC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xE9, 0xBD, 0x00, 0x00, 0x96, 0x8E, 0x8E, 0x4C, /* 0xA8-0xAB */ - 0x00, 0x00, 0x8D, 0xF8, 0x91, 0x4E, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xEE, 0xE5, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xE9, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xE9, 0xC1, 0x00, 0x00, 0xEE, 0xE6, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xE9, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xC2, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x8C, 0xEF, 0xE9, 0xC0, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xC3, /* 0xCC-0xCF */ - 0x00, 0x00, 0xE9, 0xC4, 0xE9, 0xC5, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xE9, 0xC9, 0x00, 0x00, 0x8E, 0x49, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0xE2, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0xE9, 0xCA, 0xE9, 0xC7, 0xE9, 0xC6, /* 0xE0-0xE3 */ - 0xE9, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x8C, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xE9, 0xCE, 0xE9, 0xCD, 0xE9, 0xCC, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x88, 0xB1, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ -}; - -static const unsigned char u2c_9C[512] = { - 0xEE, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xE9, 0xD8, 0x00, 0x00, 0xE9, 0xD4, 0x00, 0x00, /* 0x04-0x07 */ - 0xE9, 0xD5, 0xE9, 0xD1, 0xE9, 0xD7, 0x00, 0x00, /* 0x08-0x0B */ - 0xE9, 0xD3, 0x8A, 0x82, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x98, 0x6B, 0x00, 0x00, 0xE9, 0xD6, 0xE9, 0xD2, /* 0x10-0x13 */ - 0xE9, 0xD0, 0xE9, 0xCF, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xDA, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xE9, 0xDD, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0xE9, 0xDC, 0xE9, 0xDB, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x95, 0x68, 0xE9, 0xD9, 0x88, 0xF1, /* 0x2C-0x2F */ - 0xE9, 0xDE, 0x00, 0x00, 0xE9, 0xE0, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x8A, 0x8F, 0xE9, 0xCB, 0x89, 0x56, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xE2, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xE1, 0xE9, 0xDF, /* 0x44-0x47 */ - 0x92, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x96, 0x90, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0xD8, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xE3, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xE9, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xE5, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xE6, 0x00, 0x00, /* 0x74-0x77 */ - 0xE9, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x92, 0xB9, 0x00, 0x00, 0xE9, 0xE8, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x94, 0xB5, 0x00, 0x00, 0xE9, 0xED, /* 0xE8-0xEB */ - 0xE9, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xE9, 0xEA, 0x00, 0x00, 0x00, 0x00, 0x96, 0x50, /* 0xF0-0xF3 */ - 0x96, 0xC2, 0x00, 0x00, 0x93, 0xCE, 0x00, 0x00, /* 0xF4-0xF7 */ -}; - -static const unsigned char u2c_9D[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xEE, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xEF, 0x93, 0xBC, /* 0x04-0x07 */ - 0xE9, 0xEC, 0xE9, 0xEB, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0xA8, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xF7, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xE9, 0xF6, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x95, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xF4, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xF3, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xF1, 0x00, 0x00, /* 0x24-0x27 */ - 0x8A, 0x9B, 0x00, 0x00, 0xE9, 0xF0, 0x8E, 0xB0, /* 0x28-0x2B */ - 0x89, 0xA7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8D, 0x83, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xFA, 0xE9, 0xF9, /* 0x3C-0x3F */ - 0x00, 0x00, 0xE9, 0xF8, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xE9, 0xF5, 0x00, 0x00, 0xE9, 0xFB, 0x00, 0x00, /* 0x44-0x47 */ - 0xE9, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xEA, 0x44, 0xEA, 0x43, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xEA, 0x45, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x89, 0x4C, 0xEA, 0x40, 0xEA, 0x41, 0x00, 0x00, /* 0x5C-0x5F */ - 0x8D, 0x94, 0x96, 0xB7, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0xEA, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xE9, /* 0x68-0x6B */ - 0x96, 0x51, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x4A, /* 0x6C-0x6F */ - 0xEE, 0xE8, 0x00, 0x00, 0xEA, 0x46, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0x4B, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x48, /* 0x84-0x87 */ - 0x00, 0x00, 0xEA, 0x47, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0x7B, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0x4C, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xEA, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xEA, 0x4E, 0x00, 0x00, 0xEA, 0x49, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xF2, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0x4F, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x92, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xEA, 0x53, 0x00, 0x00, 0xEA, 0x54, 0xEA, 0x52, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xEA, 0x51, 0xEA, 0x57, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xEA, 0x50, 0x00, 0x00, 0xEA, 0x55, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x56, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x59, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xEA, 0x58, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0x5B, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xEA, 0x5C, 0x00, 0x00, 0xEA, 0x5D, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x98, 0x68, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xEA, 0x5A, 0x91, 0xE9, 0x8D, 0xEB, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xEA, 0x5E, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_9E[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xEE, 0xEB, 0xEA, 0x5F, 0xEA, 0x60, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0x61, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xEA, 0x62, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x8C, 0xB2, 0xEA, 0x63, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xEA, 0x64, 0x00, 0x00, 0x8E, 0xAD, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xEA, 0x65, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xEA, 0x66, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x67, /* 0x88-0x8B */ - 0xEA, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xEA, 0x6B, 0xEA, 0x69, 0x98, 0x5B, /* 0x90-0x93 */ - 0x00, 0x00, 0xEA, 0x6A, 0x00, 0x00, 0x97, 0xED, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xEA, 0x6C, 0x00, 0x00, 0x97, 0xD9, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xEA, 0x6D, 0x94, 0x9E, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xEA, 0x6E, 0xEA, 0x70, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0xEA, 0x71, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xEA, 0x6F, 0x8D, 0x8D, 0x96, 0xCB, 0x96, 0x83, /* 0xB8-0xBB */ - 0x9B, 0xF5, 0x00, 0x00, 0x9F, 0x80, 0x96, 0x9B, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x89, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0xEA, 0x73, 0x8B, 0x6F, 0xEA, 0x74, 0xEA, 0x75, /* 0xCC-0xCF */ - 0xEA, 0x76, 0xEE, 0xEC, 0x8D, 0x95, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xEA, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xE0, 0xD2, 0x96, 0xD9, 0x00, 0x00, 0x91, 0xE1, /* 0xD8-0xDB */ - 0xEA, 0x78, 0xEA, 0x7A, 0xEA, 0x79, 0x00, 0x00, /* 0xDC-0xDF */ - 0xEA, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xEA, 0x7C, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xEA, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x7E, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xEA, 0x80, 0x00, 0x00, 0xEA, 0x81, 0xEA, 0x82, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xEA, 0x83, 0x00, 0x00, 0xEA, 0x84, /* 0xF8-0xFB */ - 0xEA, 0x85, 0xEA, 0x86, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_9F[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x87, /* 0x04-0x07 */ - 0xEA, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x93, 0x43, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8C, 0xDB, /* 0x10-0x13 */ - 0x00, 0x00, 0xEA, 0x8A, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x91, 0x6C, 0xEA, 0x8B, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0xEA, 0x8C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x40, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0x8D, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0x8E, 0xE2, 0x56, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xD8, 0xE8, 0xEB, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0x8F, 0x00, 0x00, /* 0x50-0x53 */ - 0xEA, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x92, /* 0x5C-0x5F */ - 0xEA, 0x93, 0xEA, 0x94, 0x97, 0xEE, 0xEA, 0x91, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0x95, 0xEA, 0x96, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0x98, 0x00, 0x00, /* 0x68-0x6B */ - 0xEA, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0x9A, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0x9B, 0xEA, 0x99, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x97, 0xB4, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0xEA, 0x9C, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xEA, 0x9D, 0xE2, 0x73, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xEA, 0x9E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ -}; - -static const unsigned char u2c_DC[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ -}; - -static const unsigned char u2c_F9[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xED, 0xC4, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xEE, 0xCD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ -}; - -static const unsigned char u2c_FA[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0x73, 0xED, 0x7E, /* 0x0C-0x0F */ - 0xED, 0x80, 0xED, 0x95, 0xED, 0xBC, 0xED, 0xCC, /* 0x10-0x13 */ - 0xED, 0xCE, 0xED, 0xF9, 0xEE, 0x42, 0xEE, 0x59, /* 0x14-0x17 */ - 0xEE, 0x61, 0xEE, 0x62, 0xEE, 0x63, 0xEE, 0x65, /* 0x18-0x1B */ - 0xEE, 0x69, 0xEE, 0x6C, 0xEE, 0x75, 0xEE, 0x81, /* 0x1C-0x1F */ - 0xEE, 0x83, 0xEE, 0x84, 0xEE, 0x8D, 0xEE, 0x95, /* 0x20-0x23 */ - 0xEE, 0x97, 0xEE, 0x98, 0xEE, 0x9B, 0xEE, 0xB7, /* 0x24-0x27 */ - 0xEE, 0xBE, 0xEE, 0xCE, 0xEE, 0xDA, 0xEE, 0xDB, /* 0x28-0x2B */ - 0xEE, 0xDD, 0xEE, 0xEA, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ -}; - -static const unsigned char u2c_FF[512] = { - 0x00, 0x00, 0x81, 0x49, 0xEE, 0xFC, 0x81, 0x94, /* 0x00-0x03 */ - 0x81, 0x90, 0x81, 0x93, 0x81, 0x95, 0xEE, 0xFB, /* 0x04-0x07 */ - 0x81, 0x69, 0x81, 0x6A, 0x81, 0x96, 0x81, 0x7B, /* 0x08-0x0B */ - 0x81, 0x43, 0x81, 0x7C, 0x81, 0x44, 0x81, 0x5E, /* 0x0C-0x0F */ - 0x82, 0x4F, 0x82, 0x50, 0x82, 0x51, 0x82, 0x52, /* 0x10-0x13 */ - 0x82, 0x53, 0x82, 0x54, 0x82, 0x55, 0x82, 0x56, /* 0x14-0x17 */ - 0x82, 0x57, 0x82, 0x58, 0x81, 0x46, 0x81, 0x47, /* 0x18-0x1B */ - 0x81, 0x83, 0x81, 0x81, 0x81, 0x84, 0x81, 0x48, /* 0x1C-0x1F */ - 0x81, 0x97, 0x82, 0x60, 0x82, 0x61, 0x82, 0x62, /* 0x20-0x23 */ - 0x82, 0x63, 0x82, 0x64, 0x82, 0x65, 0x82, 0x66, /* 0x24-0x27 */ - 0x82, 0x67, 0x82, 0x68, 0x82, 0x69, 0x82, 0x6A, /* 0x28-0x2B */ - 0x82, 0x6B, 0x82, 0x6C, 0x82, 0x6D, 0x82, 0x6E, /* 0x2C-0x2F */ - 0x82, 0x6F, 0x82, 0x70, 0x82, 0x71, 0x82, 0x72, /* 0x30-0x33 */ - 0x82, 0x73, 0x82, 0x74, 0x82, 0x75, 0x82, 0x76, /* 0x34-0x37 */ - 0x82, 0x77, 0x82, 0x78, 0x82, 0x79, 0x81, 0x6D, /* 0x38-0x3B */ - 0x81, 0x5F, 0x81, 0x6E, 0x81, 0x4F, 0x81, 0x51, /* 0x3C-0x3F */ - 0x81, 0x4D, 0x82, 0x81, 0x82, 0x82, 0x82, 0x83, /* 0x40-0x43 */ - 0x82, 0x84, 0x82, 0x85, 0x82, 0x86, 0x82, 0x87, /* 0x44-0x47 */ - 0x82, 0x88, 0x82, 0x89, 0x82, 0x8A, 0x82, 0x8B, /* 0x48-0x4B */ - 0x82, 0x8C, 0x82, 0x8D, 0x82, 0x8E, 0x82, 0x8F, /* 0x4C-0x4F */ - 0x82, 0x90, 0x82, 0x91, 0x82, 0x92, 0x82, 0x93, /* 0x50-0x53 */ - 0x82, 0x94, 0x82, 0x95, 0x82, 0x96, 0x82, 0x97, /* 0x54-0x57 */ - 0x82, 0x98, 0x82, 0x99, 0x82, 0x9A, 0x81, 0x6F, /* 0x58-0x5B */ - 0x81, 0x62, 0x81, 0x70, 0x81, 0x60, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0xA1, 0x00, 0xA2, 0x00, 0xA3, /* 0x60-0x63 */ - 0x00, 0xA4, 0x00, 0xA5, 0x00, 0xA6, 0x00, 0xA7, /* 0x64-0x67 */ - 0x00, 0xA8, 0x00, 0xA9, 0x00, 0xAA, 0x00, 0xAB, /* 0x68-0x6B */ - 0x00, 0xAC, 0x00, 0xAD, 0x00, 0xAE, 0x00, 0xAF, /* 0x6C-0x6F */ - 0x00, 0xB0, 0x00, 0xB1, 0x00, 0xB2, 0x00, 0xB3, /* 0x70-0x73 */ - 0x00, 0xB4, 0x00, 0xB5, 0x00, 0xB6, 0x00, 0xB7, /* 0x74-0x77 */ - 0x00, 0xB8, 0x00, 0xB9, 0x00, 0xBA, 0x00, 0xBB, /* 0x78-0x7B */ - 0x00, 0xBC, 0x00, 0xBD, 0x00, 0xBE, 0x00, 0xBF, /* 0x7C-0x7F */ - - 0x00, 0xC0, 0x00, 0xC1, 0x00, 0xC2, 0x00, 0xC3, /* 0x80-0x83 */ - 0x00, 0xC4, 0x00, 0xC5, 0x00, 0xC6, 0x00, 0xC7, /* 0x84-0x87 */ - 0x00, 0xC8, 0x00, 0xC9, 0x00, 0xCA, 0x00, 0xCB, /* 0x88-0x8B */ - 0x00, 0xCC, 0x00, 0xCD, 0x00, 0xCE, 0x00, 0xCF, /* 0x8C-0x8F */ - 0x00, 0xD0, 0x00, 0xD1, 0x00, 0xD2, 0x00, 0xD3, /* 0x90-0x93 */ - 0x00, 0xD4, 0x00, 0xD5, 0x00, 0xD6, 0x00, 0xD7, /* 0x94-0x97 */ - 0x00, 0xD8, 0x00, 0xD9, 0x00, 0xDA, 0x00, 0xDB, /* 0x98-0x9B */ - 0x00, 0xDC, 0x00, 0xDD, 0x00, 0xDE, 0x00, 0xDF, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x81, 0x91, 0x81, 0x92, 0x81, 0xCA, 0x81, 0x50, /* 0xE0-0xE3 */ - 0xEE, 0xFA, 0x81, 0x8F, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - NULL, NULL, NULL, u2c_03, u2c_04, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - u2c_20, u2c_21, u2c_22, u2c_23, u2c_24, u2c_25, u2c_26, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - u2c_30, NULL, u2c_32, u2c_33, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, u2c_4E, u2c_4F, - u2c_50, u2c_51, u2c_52, u2c_53, u2c_54, u2c_55, u2c_56, u2c_57, - u2c_58, u2c_59, u2c_5A, u2c_5B, u2c_5C, u2c_5D, u2c_5E, u2c_5F, - u2c_60, u2c_61, u2c_62, u2c_63, u2c_64, u2c_65, u2c_66, u2c_67, - u2c_68, u2c_69, u2c_6A, u2c_6B, u2c_6C, u2c_6D, u2c_6E, u2c_6F, - u2c_70, u2c_71, u2c_72, u2c_73, u2c_74, u2c_75, u2c_76, u2c_77, - u2c_78, u2c_79, u2c_7A, u2c_7B, u2c_7C, u2c_7D, u2c_7E, u2c_7F, - u2c_80, u2c_81, u2c_82, u2c_83, u2c_84, u2c_85, u2c_86, u2c_87, - u2c_88, u2c_89, u2c_8A, u2c_8B, u2c_8C, u2c_8D, u2c_8E, u2c_8F, - u2c_90, u2c_91, u2c_92, u2c_93, u2c_94, u2c_95, u2c_96, u2c_97, - u2c_98, u2c_99, u2c_9A, u2c_9B, u2c_9C, u2c_9D, u2c_9E, u2c_9F, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, u2c_DC, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, u2c_F9, u2c_FA, NULL, NULL, NULL, NULL, u2c_FF, }; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(const wchar_t uni, - unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni&0xFF; - unsigned char ch = (uni>>8)&0xFF; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - if (ch == 0xFF && 0x61 <= cl && cl <= 0x9F) { - out[0] = cl + 0x40; - return 1; - } - uni2charset = page_uni2charset[ch]; - if (uni2charset) { - if (boundlen < 2) - return -ENAMETOOLONG; - - out[0] = uni2charset[cl*2]; - out[1] = uni2charset[cl*2+1]; - if (out[0] == 0x00 && out[1] == 0x00) - return -EINVAL; - return 2; - } else if (ch == 0) { - if (cl <= 0x7F) { - out[0] = cl; - return 1; - } else if (0xA0 <= cl) { - out[0] = u2c_00hi[cl - 0xA0][0]; - out[1] = u2c_00hi[cl - 0xA0][1]; - if (out[0] && out[1]) - return 2; - } - return -EINVAL; - } - else - return -EINVAL; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, - wchar_t *uni) -{ - unsigned char ch, cl; - const wchar_t *charset2uni; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - if (rawstring[0] <= 0x7F) { - *uni = rawstring[0]; - return 1; - } - if (0xA1 <= rawstring[0] && rawstring[0] <= 0xDF) { - *uni = 0xFF00 | (rawstring[0] - 0x40); - return 1; - } - - if (boundlen < 2) - return -ENAMETOOLONG; - ch = rawstring[0]; - cl = rawstring[1]; - charset2uni = page_charset2uni[ch]; - if (charset2uni && cl) { - *uni = charset2uni[cl]; - if (*uni == 0x0000) - return -EINVAL; - return 2; - } - else - return -EINVAL; -} - -static struct nls_table table = { - .charset = "cp932", - .alias = "sjis", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp932(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp932(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp932) -module_exit(exit_nls_cp932) - -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_ALIAS_NLS(sjis); diff --git a/src/linux/fs/nls/nls_cp936.c b/src/linux/fs/nls/nls_cp936.c deleted file mode 100644 index c96546c..0000000 --- a/src/linux/fs/nls/nls_cp936.c +++ /dev/null @@ -1,11111 +0,0 @@ -/* - * linux/fs/nls/nls_cp936.c - * - * Charset cp936 translation tables. - * This translation table was generated automatically, the - * original table can be download from the Microsoft website. - * (http://www.microsoft.com/typography/unicode/unicodecp.htm) - */ - -#include -#include -#include -#include -#include - -static const wchar_t c2u_81[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x4E02,0x4E04,0x4E05,0x4E06,0x4E0F,0x4E12,0x4E17,0x4E1F,/* 0x40-0x47 */ - 0x4E20,0x4E21,0x4E23,0x4E26,0x4E29,0x4E2E,0x4E2F,0x4E31,/* 0x48-0x4F */ - 0x4E33,0x4E35,0x4E37,0x4E3C,0x4E40,0x4E41,0x4E42,0x4E44,/* 0x50-0x57 */ - 0x4E46,0x4E4A,0x4E51,0x4E55,0x4E57,0x4E5A,0x4E5B,0x4E62,/* 0x58-0x5F */ - 0x4E63,0x4E64,0x4E65,0x4E67,0x4E68,0x4E6A,0x4E6B,0x4E6C,/* 0x60-0x67 */ - 0x4E6D,0x4E6E,0x4E6F,0x4E72,0x4E74,0x4E75,0x4E76,0x4E77,/* 0x68-0x6F */ - 0x4E78,0x4E79,0x4E7A,0x4E7B,0x4E7C,0x4E7D,0x4E7F,0x4E80,/* 0x70-0x77 */ - 0x4E81,0x4E82,0x4E83,0x4E84,0x4E85,0x4E87,0x4E8A,0x0000,/* 0x78-0x7F */ - - 0x4E90,0x4E96,0x4E97,0x4E99,0x4E9C,0x4E9D,0x4E9E,0x4EA3,/* 0x80-0x87 */ - 0x4EAA,0x4EAF,0x4EB0,0x4EB1,0x4EB4,0x4EB6,0x4EB7,0x4EB8,/* 0x88-0x8F */ - 0x4EB9,0x4EBC,0x4EBD,0x4EBE,0x4EC8,0x4ECC,0x4ECF,0x4ED0,/* 0x90-0x97 */ - 0x4ED2,0x4EDA,0x4EDB,0x4EDC,0x4EE0,0x4EE2,0x4EE6,0x4EE7,/* 0x98-0x9F */ - 0x4EE9,0x4EED,0x4EEE,0x4EEF,0x4EF1,0x4EF4,0x4EF8,0x4EF9,/* 0xA0-0xA7 */ - 0x4EFA,0x4EFC,0x4EFE,0x4F00,0x4F02,0x4F03,0x4F04,0x4F05,/* 0xA8-0xAF */ - 0x4F06,0x4F07,0x4F08,0x4F0B,0x4F0C,0x4F12,0x4F13,0x4F14,/* 0xB0-0xB7 */ - 0x4F15,0x4F16,0x4F1C,0x4F1D,0x4F21,0x4F23,0x4F28,0x4F29,/* 0xB8-0xBF */ - 0x4F2C,0x4F2D,0x4F2E,0x4F31,0x4F33,0x4F35,0x4F37,0x4F39,/* 0xC0-0xC7 */ - 0x4F3B,0x4F3E,0x4F3F,0x4F40,0x4F41,0x4F42,0x4F44,0x4F45,/* 0xC8-0xCF */ - 0x4F47,0x4F48,0x4F49,0x4F4A,0x4F4B,0x4F4C,0x4F52,0x4F54,/* 0xD0-0xD7 */ - 0x4F56,0x4F61,0x4F62,0x4F66,0x4F68,0x4F6A,0x4F6B,0x4F6D,/* 0xD8-0xDF */ - 0x4F6E,0x4F71,0x4F72,0x4F75,0x4F77,0x4F78,0x4F79,0x4F7A,/* 0xE0-0xE7 */ - 0x4F7D,0x4F80,0x4F81,0x4F82,0x4F85,0x4F86,0x4F87,0x4F8A,/* 0xE8-0xEF */ - 0x4F8C,0x4F8E,0x4F90,0x4F92,0x4F93,0x4F95,0x4F96,0x4F98,/* 0xF0-0xF7 */ - 0x4F99,0x4F9A,0x4F9C,0x4F9E,0x4F9F,0x4FA1,0x4FA2,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_82[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x4FA4,0x4FAB,0x4FAD,0x4FB0,0x4FB1,0x4FB2,0x4FB3,0x4FB4,/* 0x40-0x47 */ - 0x4FB6,0x4FB7,0x4FB8,0x4FB9,0x4FBA,0x4FBB,0x4FBC,0x4FBD,/* 0x48-0x4F */ - 0x4FBE,0x4FC0,0x4FC1,0x4FC2,0x4FC6,0x4FC7,0x4FC8,0x4FC9,/* 0x50-0x57 */ - 0x4FCB,0x4FCC,0x4FCD,0x4FD2,0x4FD3,0x4FD4,0x4FD5,0x4FD6,/* 0x58-0x5F */ - 0x4FD9,0x4FDB,0x4FE0,0x4FE2,0x4FE4,0x4FE5,0x4FE7,0x4FEB,/* 0x60-0x67 */ - 0x4FEC,0x4FF0,0x4FF2,0x4FF4,0x4FF5,0x4FF6,0x4FF7,0x4FF9,/* 0x68-0x6F */ - 0x4FFB,0x4FFC,0x4FFD,0x4FFF,0x5000,0x5001,0x5002,0x5003,/* 0x70-0x77 */ - 0x5004,0x5005,0x5006,0x5007,0x5008,0x5009,0x500A,0x0000,/* 0x78-0x7F */ - - 0x500B,0x500E,0x5010,0x5011,0x5013,0x5015,0x5016,0x5017,/* 0x80-0x87 */ - 0x501B,0x501D,0x501E,0x5020,0x5022,0x5023,0x5024,0x5027,/* 0x88-0x8F */ - 0x502B,0x502F,0x5030,0x5031,0x5032,0x5033,0x5034,0x5035,/* 0x90-0x97 */ - 0x5036,0x5037,0x5038,0x5039,0x503B,0x503D,0x503F,0x5040,/* 0x98-0x9F */ - 0x5041,0x5042,0x5044,0x5045,0x5046,0x5049,0x504A,0x504B,/* 0xA0-0xA7 */ - 0x504D,0x5050,0x5051,0x5052,0x5053,0x5054,0x5056,0x5057,/* 0xA8-0xAF */ - 0x5058,0x5059,0x505B,0x505D,0x505E,0x505F,0x5060,0x5061,/* 0xB0-0xB7 */ - 0x5062,0x5063,0x5064,0x5066,0x5067,0x5068,0x5069,0x506A,/* 0xB8-0xBF */ - 0x506B,0x506D,0x506E,0x506F,0x5070,0x5071,0x5072,0x5073,/* 0xC0-0xC7 */ - 0x5074,0x5075,0x5078,0x5079,0x507A,0x507C,0x507D,0x5081,/* 0xC8-0xCF */ - 0x5082,0x5083,0x5084,0x5086,0x5087,0x5089,0x508A,0x508B,/* 0xD0-0xD7 */ - 0x508C,0x508E,0x508F,0x5090,0x5091,0x5092,0x5093,0x5094,/* 0xD8-0xDF */ - 0x5095,0x5096,0x5097,0x5098,0x5099,0x509A,0x509B,0x509C,/* 0xE0-0xE7 */ - 0x509D,0x509E,0x509F,0x50A0,0x50A1,0x50A2,0x50A4,0x50A6,/* 0xE8-0xEF */ - 0x50AA,0x50AB,0x50AD,0x50AE,0x50AF,0x50B0,0x50B1,0x50B3,/* 0xF0-0xF7 */ - 0x50B4,0x50B5,0x50B6,0x50B7,0x50B8,0x50B9,0x50BC,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_83[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x50BD,0x50BE,0x50BF,0x50C0,0x50C1,0x50C2,0x50C3,0x50C4,/* 0x40-0x47 */ - 0x50C5,0x50C6,0x50C7,0x50C8,0x50C9,0x50CA,0x50CB,0x50CC,/* 0x48-0x4F */ - 0x50CD,0x50CE,0x50D0,0x50D1,0x50D2,0x50D3,0x50D4,0x50D5,/* 0x50-0x57 */ - 0x50D7,0x50D8,0x50D9,0x50DB,0x50DC,0x50DD,0x50DE,0x50DF,/* 0x58-0x5F */ - 0x50E0,0x50E1,0x50E2,0x50E3,0x50E4,0x50E5,0x50E8,0x50E9,/* 0x60-0x67 */ - 0x50EA,0x50EB,0x50EF,0x50F0,0x50F1,0x50F2,0x50F4,0x50F6,/* 0x68-0x6F */ - 0x50F7,0x50F8,0x50F9,0x50FA,0x50FC,0x50FD,0x50FE,0x50FF,/* 0x70-0x77 */ - 0x5100,0x5101,0x5102,0x5103,0x5104,0x5105,0x5108,0x0000,/* 0x78-0x7F */ - - 0x5109,0x510A,0x510C,0x510D,0x510E,0x510F,0x5110,0x5111,/* 0x80-0x87 */ - 0x5113,0x5114,0x5115,0x5116,0x5117,0x5118,0x5119,0x511A,/* 0x88-0x8F */ - 0x511B,0x511C,0x511D,0x511E,0x511F,0x5120,0x5122,0x5123,/* 0x90-0x97 */ - 0x5124,0x5125,0x5126,0x5127,0x5128,0x5129,0x512A,0x512B,/* 0x98-0x9F */ - 0x512C,0x512D,0x512E,0x512F,0x5130,0x5131,0x5132,0x5133,/* 0xA0-0xA7 */ - 0x5134,0x5135,0x5136,0x5137,0x5138,0x5139,0x513A,0x513B,/* 0xA8-0xAF */ - 0x513C,0x513D,0x513E,0x5142,0x5147,0x514A,0x514C,0x514E,/* 0xB0-0xB7 */ - 0x514F,0x5150,0x5152,0x5153,0x5157,0x5158,0x5159,0x515B,/* 0xB8-0xBF */ - 0x515D,0x515E,0x515F,0x5160,0x5161,0x5163,0x5164,0x5166,/* 0xC0-0xC7 */ - 0x5167,0x5169,0x516A,0x516F,0x5172,0x517A,0x517E,0x517F,/* 0xC8-0xCF */ - 0x5183,0x5184,0x5186,0x5187,0x518A,0x518B,0x518E,0x518F,/* 0xD0-0xD7 */ - 0x5190,0x5191,0x5193,0x5194,0x5198,0x519A,0x519D,0x519E,/* 0xD8-0xDF */ - 0x519F,0x51A1,0x51A3,0x51A6,0x51A7,0x51A8,0x51A9,0x51AA,/* 0xE0-0xE7 */ - 0x51AD,0x51AE,0x51B4,0x51B8,0x51B9,0x51BA,0x51BE,0x51BF,/* 0xE8-0xEF */ - 0x51C1,0x51C2,0x51C3,0x51C5,0x51C8,0x51CA,0x51CD,0x51CE,/* 0xF0-0xF7 */ - 0x51D0,0x51D2,0x51D3,0x51D4,0x51D5,0x51D6,0x51D7,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_84[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x51D8,0x51D9,0x51DA,0x51DC,0x51DE,0x51DF,0x51E2,0x51E3,/* 0x40-0x47 */ - 0x51E5,0x51E6,0x51E7,0x51E8,0x51E9,0x51EA,0x51EC,0x51EE,/* 0x48-0x4F */ - 0x51F1,0x51F2,0x51F4,0x51F7,0x51FE,0x5204,0x5205,0x5209,/* 0x50-0x57 */ - 0x520B,0x520C,0x520F,0x5210,0x5213,0x5214,0x5215,0x521C,/* 0x58-0x5F */ - 0x521E,0x521F,0x5221,0x5222,0x5223,0x5225,0x5226,0x5227,/* 0x60-0x67 */ - 0x522A,0x522C,0x522F,0x5231,0x5232,0x5234,0x5235,0x523C,/* 0x68-0x6F */ - 0x523E,0x5244,0x5245,0x5246,0x5247,0x5248,0x5249,0x524B,/* 0x70-0x77 */ - 0x524E,0x524F,0x5252,0x5253,0x5255,0x5257,0x5258,0x0000,/* 0x78-0x7F */ - - 0x5259,0x525A,0x525B,0x525D,0x525F,0x5260,0x5262,0x5263,/* 0x80-0x87 */ - 0x5264,0x5266,0x5268,0x526B,0x526C,0x526D,0x526E,0x5270,/* 0x88-0x8F */ - 0x5271,0x5273,0x5274,0x5275,0x5276,0x5277,0x5278,0x5279,/* 0x90-0x97 */ - 0x527A,0x527B,0x527C,0x527E,0x5280,0x5283,0x5284,0x5285,/* 0x98-0x9F */ - 0x5286,0x5287,0x5289,0x528A,0x528B,0x528C,0x528D,0x528E,/* 0xA0-0xA7 */ - 0x528F,0x5291,0x5292,0x5294,0x5295,0x5296,0x5297,0x5298,/* 0xA8-0xAF */ - 0x5299,0x529A,0x529C,0x52A4,0x52A5,0x52A6,0x52A7,0x52AE,/* 0xB0-0xB7 */ - 0x52AF,0x52B0,0x52B4,0x52B5,0x52B6,0x52B7,0x52B8,0x52B9,/* 0xB8-0xBF */ - 0x52BA,0x52BB,0x52BC,0x52BD,0x52C0,0x52C1,0x52C2,0x52C4,/* 0xC0-0xC7 */ - 0x52C5,0x52C6,0x52C8,0x52CA,0x52CC,0x52CD,0x52CE,0x52CF,/* 0xC8-0xCF */ - 0x52D1,0x52D3,0x52D4,0x52D5,0x52D7,0x52D9,0x52DA,0x52DB,/* 0xD0-0xD7 */ - 0x52DC,0x52DD,0x52DE,0x52E0,0x52E1,0x52E2,0x52E3,0x52E5,/* 0xD8-0xDF */ - 0x52E6,0x52E7,0x52E8,0x52E9,0x52EA,0x52EB,0x52EC,0x52ED,/* 0xE0-0xE7 */ - 0x52EE,0x52EF,0x52F1,0x52F2,0x52F3,0x52F4,0x52F5,0x52F6,/* 0xE8-0xEF */ - 0x52F7,0x52F8,0x52FB,0x52FC,0x52FD,0x5301,0x5302,0x5303,/* 0xF0-0xF7 */ - 0x5304,0x5307,0x5309,0x530A,0x530B,0x530C,0x530E,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_85[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5311,0x5312,0x5313,0x5314,0x5318,0x531B,0x531C,0x531E,/* 0x40-0x47 */ - 0x531F,0x5322,0x5324,0x5325,0x5327,0x5328,0x5329,0x532B,/* 0x48-0x4F */ - 0x532C,0x532D,0x532F,0x5330,0x5331,0x5332,0x5333,0x5334,/* 0x50-0x57 */ - 0x5335,0x5336,0x5337,0x5338,0x533C,0x533D,0x5340,0x5342,/* 0x58-0x5F */ - 0x5344,0x5346,0x534B,0x534C,0x534D,0x5350,0x5354,0x5358,/* 0x60-0x67 */ - 0x5359,0x535B,0x535D,0x5365,0x5368,0x536A,0x536C,0x536D,/* 0x68-0x6F */ - 0x5372,0x5376,0x5379,0x537B,0x537C,0x537D,0x537E,0x5380,/* 0x70-0x77 */ - 0x5381,0x5383,0x5387,0x5388,0x538A,0x538E,0x538F,0x0000,/* 0x78-0x7F */ - - 0x5390,0x5391,0x5392,0x5393,0x5394,0x5396,0x5397,0x5399,/* 0x80-0x87 */ - 0x539B,0x539C,0x539E,0x53A0,0x53A1,0x53A4,0x53A7,0x53AA,/* 0x88-0x8F */ - 0x53AB,0x53AC,0x53AD,0x53AF,0x53B0,0x53B1,0x53B2,0x53B3,/* 0x90-0x97 */ - 0x53B4,0x53B5,0x53B7,0x53B8,0x53B9,0x53BA,0x53BC,0x53BD,/* 0x98-0x9F */ - 0x53BE,0x53C0,0x53C3,0x53C4,0x53C5,0x53C6,0x53C7,0x53CE,/* 0xA0-0xA7 */ - 0x53CF,0x53D0,0x53D2,0x53D3,0x53D5,0x53DA,0x53DC,0x53DD,/* 0xA8-0xAF */ - 0x53DE,0x53E1,0x53E2,0x53E7,0x53F4,0x53FA,0x53FE,0x53FF,/* 0xB0-0xB7 */ - 0x5400,0x5402,0x5405,0x5407,0x540B,0x5414,0x5418,0x5419,/* 0xB8-0xBF */ - 0x541A,0x541C,0x5422,0x5424,0x5425,0x542A,0x5430,0x5433,/* 0xC0-0xC7 */ - 0x5436,0x5437,0x543A,0x543D,0x543F,0x5441,0x5442,0x5444,/* 0xC8-0xCF */ - 0x5445,0x5447,0x5449,0x544C,0x544D,0x544E,0x544F,0x5451,/* 0xD0-0xD7 */ - 0x545A,0x545D,0x545E,0x545F,0x5460,0x5461,0x5463,0x5465,/* 0xD8-0xDF */ - 0x5467,0x5469,0x546A,0x546B,0x546C,0x546D,0x546E,0x546F,/* 0xE0-0xE7 */ - 0x5470,0x5474,0x5479,0x547A,0x547E,0x547F,0x5481,0x5483,/* 0xE8-0xEF */ - 0x5485,0x5487,0x5488,0x5489,0x548A,0x548D,0x5491,0x5493,/* 0xF0-0xF7 */ - 0x5497,0x5498,0x549C,0x549E,0x549F,0x54A0,0x54A1,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_86[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x54A2,0x54A5,0x54AE,0x54B0,0x54B2,0x54B5,0x54B6,0x54B7,/* 0x40-0x47 */ - 0x54B9,0x54BA,0x54BC,0x54BE,0x54C3,0x54C5,0x54CA,0x54CB,/* 0x48-0x4F */ - 0x54D6,0x54D8,0x54DB,0x54E0,0x54E1,0x54E2,0x54E3,0x54E4,/* 0x50-0x57 */ - 0x54EB,0x54EC,0x54EF,0x54F0,0x54F1,0x54F4,0x54F5,0x54F6,/* 0x58-0x5F */ - 0x54F7,0x54F8,0x54F9,0x54FB,0x54FE,0x5500,0x5502,0x5503,/* 0x60-0x67 */ - 0x5504,0x5505,0x5508,0x550A,0x550B,0x550C,0x550D,0x550E,/* 0x68-0x6F */ - 0x5512,0x5513,0x5515,0x5516,0x5517,0x5518,0x5519,0x551A,/* 0x70-0x77 */ - 0x551C,0x551D,0x551E,0x551F,0x5521,0x5525,0x5526,0x0000,/* 0x78-0x7F */ - - 0x5528,0x5529,0x552B,0x552D,0x5532,0x5534,0x5535,0x5536,/* 0x80-0x87 */ - 0x5538,0x5539,0x553A,0x553B,0x553D,0x5540,0x5542,0x5545,/* 0x88-0x8F */ - 0x5547,0x5548,0x554B,0x554C,0x554D,0x554E,0x554F,0x5551,/* 0x90-0x97 */ - 0x5552,0x5553,0x5554,0x5557,0x5558,0x5559,0x555A,0x555B,/* 0x98-0x9F */ - 0x555D,0x555E,0x555F,0x5560,0x5562,0x5563,0x5568,0x5569,/* 0xA0-0xA7 */ - 0x556B,0x556F,0x5570,0x5571,0x5572,0x5573,0x5574,0x5579,/* 0xA8-0xAF */ - 0x557A,0x557D,0x557F,0x5585,0x5586,0x558C,0x558D,0x558E,/* 0xB0-0xB7 */ - 0x5590,0x5592,0x5593,0x5595,0x5596,0x5597,0x559A,0x559B,/* 0xB8-0xBF */ - 0x559E,0x55A0,0x55A1,0x55A2,0x55A3,0x55A4,0x55A5,0x55A6,/* 0xC0-0xC7 */ - 0x55A8,0x55A9,0x55AA,0x55AB,0x55AC,0x55AD,0x55AE,0x55AF,/* 0xC8-0xCF */ - 0x55B0,0x55B2,0x55B4,0x55B6,0x55B8,0x55BA,0x55BC,0x55BF,/* 0xD0-0xD7 */ - 0x55C0,0x55C1,0x55C2,0x55C3,0x55C6,0x55C7,0x55C8,0x55CA,/* 0xD8-0xDF */ - 0x55CB,0x55CE,0x55CF,0x55D0,0x55D5,0x55D7,0x55D8,0x55D9,/* 0xE0-0xE7 */ - 0x55DA,0x55DB,0x55DE,0x55E0,0x55E2,0x55E7,0x55E9,0x55ED,/* 0xE8-0xEF */ - 0x55EE,0x55F0,0x55F1,0x55F4,0x55F6,0x55F8,0x55F9,0x55FA,/* 0xF0-0xF7 */ - 0x55FB,0x55FC,0x55FF,0x5602,0x5603,0x5604,0x5605,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_87[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5606,0x5607,0x560A,0x560B,0x560D,0x5610,0x5611,0x5612,/* 0x40-0x47 */ - 0x5613,0x5614,0x5615,0x5616,0x5617,0x5619,0x561A,0x561C,/* 0x48-0x4F */ - 0x561D,0x5620,0x5621,0x5622,0x5625,0x5626,0x5628,0x5629,/* 0x50-0x57 */ - 0x562A,0x562B,0x562E,0x562F,0x5630,0x5633,0x5635,0x5637,/* 0x58-0x5F */ - 0x5638,0x563A,0x563C,0x563D,0x563E,0x5640,0x5641,0x5642,/* 0x60-0x67 */ - 0x5643,0x5644,0x5645,0x5646,0x5647,0x5648,0x5649,0x564A,/* 0x68-0x6F */ - 0x564B,0x564F,0x5650,0x5651,0x5652,0x5653,0x5655,0x5656,/* 0x70-0x77 */ - 0x565A,0x565B,0x565D,0x565E,0x565F,0x5660,0x5661,0x0000,/* 0x78-0x7F */ - - 0x5663,0x5665,0x5666,0x5667,0x566D,0x566E,0x566F,0x5670,/* 0x80-0x87 */ - 0x5672,0x5673,0x5674,0x5675,0x5677,0x5678,0x5679,0x567A,/* 0x88-0x8F */ - 0x567D,0x567E,0x567F,0x5680,0x5681,0x5682,0x5683,0x5684,/* 0x90-0x97 */ - 0x5687,0x5688,0x5689,0x568A,0x568B,0x568C,0x568D,0x5690,/* 0x98-0x9F */ - 0x5691,0x5692,0x5694,0x5695,0x5696,0x5697,0x5698,0x5699,/* 0xA0-0xA7 */ - 0x569A,0x569B,0x569C,0x569D,0x569E,0x569F,0x56A0,0x56A1,/* 0xA8-0xAF */ - 0x56A2,0x56A4,0x56A5,0x56A6,0x56A7,0x56A8,0x56A9,0x56AA,/* 0xB0-0xB7 */ - 0x56AB,0x56AC,0x56AD,0x56AE,0x56B0,0x56B1,0x56B2,0x56B3,/* 0xB8-0xBF */ - 0x56B4,0x56B5,0x56B6,0x56B8,0x56B9,0x56BA,0x56BB,0x56BD,/* 0xC0-0xC7 */ - 0x56BE,0x56BF,0x56C0,0x56C1,0x56C2,0x56C3,0x56C4,0x56C5,/* 0xC8-0xCF */ - 0x56C6,0x56C7,0x56C8,0x56C9,0x56CB,0x56CC,0x56CD,0x56CE,/* 0xD0-0xD7 */ - 0x56CF,0x56D0,0x56D1,0x56D2,0x56D3,0x56D5,0x56D6,0x56D8,/* 0xD8-0xDF */ - 0x56D9,0x56DC,0x56E3,0x56E5,0x56E6,0x56E7,0x56E8,0x56E9,/* 0xE0-0xE7 */ - 0x56EA,0x56EC,0x56EE,0x56EF,0x56F2,0x56F3,0x56F6,0x56F7,/* 0xE8-0xEF */ - 0x56F8,0x56FB,0x56FC,0x5700,0x5701,0x5702,0x5705,0x5707,/* 0xF0-0xF7 */ - 0x570B,0x570C,0x570D,0x570E,0x570F,0x5710,0x5711,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_88[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5712,0x5713,0x5714,0x5715,0x5716,0x5717,0x5718,0x5719,/* 0x40-0x47 */ - 0x571A,0x571B,0x571D,0x571E,0x5720,0x5721,0x5722,0x5724,/* 0x48-0x4F */ - 0x5725,0x5726,0x5727,0x572B,0x5731,0x5732,0x5734,0x5735,/* 0x50-0x57 */ - 0x5736,0x5737,0x5738,0x573C,0x573D,0x573F,0x5741,0x5743,/* 0x58-0x5F */ - 0x5744,0x5745,0x5746,0x5748,0x5749,0x574B,0x5752,0x5753,/* 0x60-0x67 */ - 0x5754,0x5755,0x5756,0x5758,0x5759,0x5762,0x5763,0x5765,/* 0x68-0x6F */ - 0x5767,0x576C,0x576E,0x5770,0x5771,0x5772,0x5774,0x5775,/* 0x70-0x77 */ - 0x5778,0x5779,0x577A,0x577D,0x577E,0x577F,0x5780,0x0000,/* 0x78-0x7F */ - - 0x5781,0x5787,0x5788,0x5789,0x578A,0x578D,0x578E,0x578F,/* 0x80-0x87 */ - 0x5790,0x5791,0x5794,0x5795,0x5796,0x5797,0x5798,0x5799,/* 0x88-0x8F */ - 0x579A,0x579C,0x579D,0x579E,0x579F,0x57A5,0x57A8,0x57AA,/* 0x90-0x97 */ - 0x57AC,0x57AF,0x57B0,0x57B1,0x57B3,0x57B5,0x57B6,0x57B7,/* 0x98-0x9F */ - 0x57B9,0x57BA,0x57BB,0x57BC,0x57BD,0x57BE,0x57BF,0x57C0,/* 0xA0-0xA7 */ - 0x57C1,0x57C4,0x57C5,0x57C6,0x57C7,0x57C8,0x57C9,0x57CA,/* 0xA8-0xAF */ - 0x57CC,0x57CD,0x57D0,0x57D1,0x57D3,0x57D6,0x57D7,0x57DB,/* 0xB0-0xB7 */ - 0x57DC,0x57DE,0x57E1,0x57E2,0x57E3,0x57E5,0x57E6,0x57E7,/* 0xB8-0xBF */ - 0x57E8,0x57E9,0x57EA,0x57EB,0x57EC,0x57EE,0x57F0,0x57F1,/* 0xC0-0xC7 */ - 0x57F2,0x57F3,0x57F5,0x57F6,0x57F7,0x57FB,0x57FC,0x57FE,/* 0xC8-0xCF */ - 0x57FF,0x5801,0x5803,0x5804,0x5805,0x5808,0x5809,0x580A,/* 0xD0-0xD7 */ - 0x580C,0x580E,0x580F,0x5810,0x5812,0x5813,0x5814,0x5816,/* 0xD8-0xDF */ - 0x5817,0x5818,0x581A,0x581B,0x581C,0x581D,0x581F,0x5822,/* 0xE0-0xE7 */ - 0x5823,0x5825,0x5826,0x5827,0x5828,0x5829,0x582B,0x582C,/* 0xE8-0xEF */ - 0x582D,0x582E,0x582F,0x5831,0x5832,0x5833,0x5834,0x5836,/* 0xF0-0xF7 */ - 0x5837,0x5838,0x5839,0x583A,0x583B,0x583C,0x583D,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_89[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x583E,0x583F,0x5840,0x5841,0x5842,0x5843,0x5845,0x5846,/* 0x40-0x47 */ - 0x5847,0x5848,0x5849,0x584A,0x584B,0x584E,0x584F,0x5850,/* 0x48-0x4F */ - 0x5852,0x5853,0x5855,0x5856,0x5857,0x5859,0x585A,0x585B,/* 0x50-0x57 */ - 0x585C,0x585D,0x585F,0x5860,0x5861,0x5862,0x5863,0x5864,/* 0x58-0x5F */ - 0x5866,0x5867,0x5868,0x5869,0x586A,0x586D,0x586E,0x586F,/* 0x60-0x67 */ - 0x5870,0x5871,0x5872,0x5873,0x5874,0x5875,0x5876,0x5877,/* 0x68-0x6F */ - 0x5878,0x5879,0x587A,0x587B,0x587C,0x587D,0x587F,0x5882,/* 0x70-0x77 */ - 0x5884,0x5886,0x5887,0x5888,0x588A,0x588B,0x588C,0x0000,/* 0x78-0x7F */ - - 0x588D,0x588E,0x588F,0x5890,0x5891,0x5894,0x5895,0x5896,/* 0x80-0x87 */ - 0x5897,0x5898,0x589B,0x589C,0x589D,0x58A0,0x58A1,0x58A2,/* 0x88-0x8F */ - 0x58A3,0x58A4,0x58A5,0x58A6,0x58A7,0x58AA,0x58AB,0x58AC,/* 0x90-0x97 */ - 0x58AD,0x58AE,0x58AF,0x58B0,0x58B1,0x58B2,0x58B3,0x58B4,/* 0x98-0x9F */ - 0x58B5,0x58B6,0x58B7,0x58B8,0x58B9,0x58BA,0x58BB,0x58BD,/* 0xA0-0xA7 */ - 0x58BE,0x58BF,0x58C0,0x58C2,0x58C3,0x58C4,0x58C6,0x58C7,/* 0xA8-0xAF */ - 0x58C8,0x58C9,0x58CA,0x58CB,0x58CC,0x58CD,0x58CE,0x58CF,/* 0xB0-0xB7 */ - 0x58D0,0x58D2,0x58D3,0x58D4,0x58D6,0x58D7,0x58D8,0x58D9,/* 0xB8-0xBF */ - 0x58DA,0x58DB,0x58DC,0x58DD,0x58DE,0x58DF,0x58E0,0x58E1,/* 0xC0-0xC7 */ - 0x58E2,0x58E3,0x58E5,0x58E6,0x58E7,0x58E8,0x58E9,0x58EA,/* 0xC8-0xCF */ - 0x58ED,0x58EF,0x58F1,0x58F2,0x58F4,0x58F5,0x58F7,0x58F8,/* 0xD0-0xD7 */ - 0x58FA,0x58FB,0x58FC,0x58FD,0x58FE,0x58FF,0x5900,0x5901,/* 0xD8-0xDF */ - 0x5903,0x5905,0x5906,0x5908,0x5909,0x590A,0x590B,0x590C,/* 0xE0-0xE7 */ - 0x590E,0x5910,0x5911,0x5912,0x5913,0x5917,0x5918,0x591B,/* 0xE8-0xEF */ - 0x591D,0x591E,0x5920,0x5921,0x5922,0x5923,0x5926,0x5928,/* 0xF0-0xF7 */ - 0x592C,0x5930,0x5932,0x5933,0x5935,0x5936,0x593B,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_8A[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x593D,0x593E,0x593F,0x5940,0x5943,0x5945,0x5946,0x594A,/* 0x40-0x47 */ - 0x594C,0x594D,0x5950,0x5952,0x5953,0x5959,0x595B,0x595C,/* 0x48-0x4F */ - 0x595D,0x595E,0x595F,0x5961,0x5963,0x5964,0x5966,0x5967,/* 0x50-0x57 */ - 0x5968,0x5969,0x596A,0x596B,0x596C,0x596D,0x596E,0x596F,/* 0x58-0x5F */ - 0x5970,0x5971,0x5972,0x5975,0x5977,0x597A,0x597B,0x597C,/* 0x60-0x67 */ - 0x597E,0x597F,0x5980,0x5985,0x5989,0x598B,0x598C,0x598E,/* 0x68-0x6F */ - 0x598F,0x5990,0x5991,0x5994,0x5995,0x5998,0x599A,0x599B,/* 0x70-0x77 */ - 0x599C,0x599D,0x599F,0x59A0,0x59A1,0x59A2,0x59A6,0x0000,/* 0x78-0x7F */ - - 0x59A7,0x59AC,0x59AD,0x59B0,0x59B1,0x59B3,0x59B4,0x59B5,/* 0x80-0x87 */ - 0x59B6,0x59B7,0x59B8,0x59BA,0x59BC,0x59BD,0x59BF,0x59C0,/* 0x88-0x8F */ - 0x59C1,0x59C2,0x59C3,0x59C4,0x59C5,0x59C7,0x59C8,0x59C9,/* 0x90-0x97 */ - 0x59CC,0x59CD,0x59CE,0x59CF,0x59D5,0x59D6,0x59D9,0x59DB,/* 0x98-0x9F */ - 0x59DE,0x59DF,0x59E0,0x59E1,0x59E2,0x59E4,0x59E6,0x59E7,/* 0xA0-0xA7 */ - 0x59E9,0x59EA,0x59EB,0x59ED,0x59EE,0x59EF,0x59F0,0x59F1,/* 0xA8-0xAF */ - 0x59F2,0x59F3,0x59F4,0x59F5,0x59F6,0x59F7,0x59F8,0x59FA,/* 0xB0-0xB7 */ - 0x59FC,0x59FD,0x59FE,0x5A00,0x5A02,0x5A0A,0x5A0B,0x5A0D,/* 0xB8-0xBF */ - 0x5A0E,0x5A0F,0x5A10,0x5A12,0x5A14,0x5A15,0x5A16,0x5A17,/* 0xC0-0xC7 */ - 0x5A19,0x5A1A,0x5A1B,0x5A1D,0x5A1E,0x5A21,0x5A22,0x5A24,/* 0xC8-0xCF */ - 0x5A26,0x5A27,0x5A28,0x5A2A,0x5A2B,0x5A2C,0x5A2D,0x5A2E,/* 0xD0-0xD7 */ - 0x5A2F,0x5A30,0x5A33,0x5A35,0x5A37,0x5A38,0x5A39,0x5A3A,/* 0xD8-0xDF */ - 0x5A3B,0x5A3D,0x5A3E,0x5A3F,0x5A41,0x5A42,0x5A43,0x5A44,/* 0xE0-0xE7 */ - 0x5A45,0x5A47,0x5A48,0x5A4B,0x5A4C,0x5A4D,0x5A4E,0x5A4F,/* 0xE8-0xEF */ - 0x5A50,0x5A51,0x5A52,0x5A53,0x5A54,0x5A56,0x5A57,0x5A58,/* 0xF0-0xF7 */ - 0x5A59,0x5A5B,0x5A5C,0x5A5D,0x5A5E,0x5A5F,0x5A60,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_8B[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5A61,0x5A63,0x5A64,0x5A65,0x5A66,0x5A68,0x5A69,0x5A6B,/* 0x40-0x47 */ - 0x5A6C,0x5A6D,0x5A6E,0x5A6F,0x5A70,0x5A71,0x5A72,0x5A73,/* 0x48-0x4F */ - 0x5A78,0x5A79,0x5A7B,0x5A7C,0x5A7D,0x5A7E,0x5A80,0x5A81,/* 0x50-0x57 */ - 0x5A82,0x5A83,0x5A84,0x5A85,0x5A86,0x5A87,0x5A88,0x5A89,/* 0x58-0x5F */ - 0x5A8A,0x5A8B,0x5A8C,0x5A8D,0x5A8E,0x5A8F,0x5A90,0x5A91,/* 0x60-0x67 */ - 0x5A93,0x5A94,0x5A95,0x5A96,0x5A97,0x5A98,0x5A99,0x5A9C,/* 0x68-0x6F */ - 0x5A9D,0x5A9E,0x5A9F,0x5AA0,0x5AA1,0x5AA2,0x5AA3,0x5AA4,/* 0x70-0x77 */ - 0x5AA5,0x5AA6,0x5AA7,0x5AA8,0x5AA9,0x5AAB,0x5AAC,0x0000,/* 0x78-0x7F */ - - 0x5AAD,0x5AAE,0x5AAF,0x5AB0,0x5AB1,0x5AB4,0x5AB6,0x5AB7,/* 0x80-0x87 */ - 0x5AB9,0x5ABA,0x5ABB,0x5ABC,0x5ABD,0x5ABF,0x5AC0,0x5AC3,/* 0x88-0x8F */ - 0x5AC4,0x5AC5,0x5AC6,0x5AC7,0x5AC8,0x5ACA,0x5ACB,0x5ACD,/* 0x90-0x97 */ - 0x5ACE,0x5ACF,0x5AD0,0x5AD1,0x5AD3,0x5AD5,0x5AD7,0x5AD9,/* 0x98-0x9F */ - 0x5ADA,0x5ADB,0x5ADD,0x5ADE,0x5ADF,0x5AE2,0x5AE4,0x5AE5,/* 0xA0-0xA7 */ - 0x5AE7,0x5AE8,0x5AEA,0x5AEC,0x5AED,0x5AEE,0x5AEF,0x5AF0,/* 0xA8-0xAF */ - 0x5AF2,0x5AF3,0x5AF4,0x5AF5,0x5AF6,0x5AF7,0x5AF8,0x5AF9,/* 0xB0-0xB7 */ - 0x5AFA,0x5AFB,0x5AFC,0x5AFD,0x5AFE,0x5AFF,0x5B00,0x5B01,/* 0xB8-0xBF */ - 0x5B02,0x5B03,0x5B04,0x5B05,0x5B06,0x5B07,0x5B08,0x5B0A,/* 0xC0-0xC7 */ - 0x5B0B,0x5B0C,0x5B0D,0x5B0E,0x5B0F,0x5B10,0x5B11,0x5B12,/* 0xC8-0xCF */ - 0x5B13,0x5B14,0x5B15,0x5B18,0x5B19,0x5B1A,0x5B1B,0x5B1C,/* 0xD0-0xD7 */ - 0x5B1D,0x5B1E,0x5B1F,0x5B20,0x5B21,0x5B22,0x5B23,0x5B24,/* 0xD8-0xDF */ - 0x5B25,0x5B26,0x5B27,0x5B28,0x5B29,0x5B2A,0x5B2B,0x5B2C,/* 0xE0-0xE7 */ - 0x5B2D,0x5B2E,0x5B2F,0x5B30,0x5B31,0x5B33,0x5B35,0x5B36,/* 0xE8-0xEF */ - 0x5B38,0x5B39,0x5B3A,0x5B3B,0x5B3C,0x5B3D,0x5B3E,0x5B3F,/* 0xF0-0xF7 */ - 0x5B41,0x5B42,0x5B43,0x5B44,0x5B45,0x5B46,0x5B47,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_8C[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5B48,0x5B49,0x5B4A,0x5B4B,0x5B4C,0x5B4D,0x5B4E,0x5B4F,/* 0x40-0x47 */ - 0x5B52,0x5B56,0x5B5E,0x5B60,0x5B61,0x5B67,0x5B68,0x5B6B,/* 0x48-0x4F */ - 0x5B6D,0x5B6E,0x5B6F,0x5B72,0x5B74,0x5B76,0x5B77,0x5B78,/* 0x50-0x57 */ - 0x5B79,0x5B7B,0x5B7C,0x5B7E,0x5B7F,0x5B82,0x5B86,0x5B8A,/* 0x58-0x5F */ - 0x5B8D,0x5B8E,0x5B90,0x5B91,0x5B92,0x5B94,0x5B96,0x5B9F,/* 0x60-0x67 */ - 0x5BA7,0x5BA8,0x5BA9,0x5BAC,0x5BAD,0x5BAE,0x5BAF,0x5BB1,/* 0x68-0x6F */ - 0x5BB2,0x5BB7,0x5BBA,0x5BBB,0x5BBC,0x5BC0,0x5BC1,0x5BC3,/* 0x70-0x77 */ - 0x5BC8,0x5BC9,0x5BCA,0x5BCB,0x5BCD,0x5BCE,0x5BCF,0x0000,/* 0x78-0x7F */ - - 0x5BD1,0x5BD4,0x5BD5,0x5BD6,0x5BD7,0x5BD8,0x5BD9,0x5BDA,/* 0x80-0x87 */ - 0x5BDB,0x5BDC,0x5BE0,0x5BE2,0x5BE3,0x5BE6,0x5BE7,0x5BE9,/* 0x88-0x8F */ - 0x5BEA,0x5BEB,0x5BEC,0x5BED,0x5BEF,0x5BF1,0x5BF2,0x5BF3,/* 0x90-0x97 */ - 0x5BF4,0x5BF5,0x5BF6,0x5BF7,0x5BFD,0x5BFE,0x5C00,0x5C02,/* 0x98-0x9F */ - 0x5C03,0x5C05,0x5C07,0x5C08,0x5C0B,0x5C0C,0x5C0D,0x5C0E,/* 0xA0-0xA7 */ - 0x5C10,0x5C12,0x5C13,0x5C17,0x5C19,0x5C1B,0x5C1E,0x5C1F,/* 0xA8-0xAF */ - 0x5C20,0x5C21,0x5C23,0x5C26,0x5C28,0x5C29,0x5C2A,0x5C2B,/* 0xB0-0xB7 */ - 0x5C2D,0x5C2E,0x5C2F,0x5C30,0x5C32,0x5C33,0x5C35,0x5C36,/* 0xB8-0xBF */ - 0x5C37,0x5C43,0x5C44,0x5C46,0x5C47,0x5C4C,0x5C4D,0x5C52,/* 0xC0-0xC7 */ - 0x5C53,0x5C54,0x5C56,0x5C57,0x5C58,0x5C5A,0x5C5B,0x5C5C,/* 0xC8-0xCF */ - 0x5C5D,0x5C5F,0x5C62,0x5C64,0x5C67,0x5C68,0x5C69,0x5C6A,/* 0xD0-0xD7 */ - 0x5C6B,0x5C6C,0x5C6D,0x5C70,0x5C72,0x5C73,0x5C74,0x5C75,/* 0xD8-0xDF */ - 0x5C76,0x5C77,0x5C78,0x5C7B,0x5C7C,0x5C7D,0x5C7E,0x5C80,/* 0xE0-0xE7 */ - 0x5C83,0x5C84,0x5C85,0x5C86,0x5C87,0x5C89,0x5C8A,0x5C8B,/* 0xE8-0xEF */ - 0x5C8E,0x5C8F,0x5C92,0x5C93,0x5C95,0x5C9D,0x5C9E,0x5C9F,/* 0xF0-0xF7 */ - 0x5CA0,0x5CA1,0x5CA4,0x5CA5,0x5CA6,0x5CA7,0x5CA8,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_8D[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5CAA,0x5CAE,0x5CAF,0x5CB0,0x5CB2,0x5CB4,0x5CB6,0x5CB9,/* 0x40-0x47 */ - 0x5CBA,0x5CBB,0x5CBC,0x5CBE,0x5CC0,0x5CC2,0x5CC3,0x5CC5,/* 0x48-0x4F */ - 0x5CC6,0x5CC7,0x5CC8,0x5CC9,0x5CCA,0x5CCC,0x5CCD,0x5CCE,/* 0x50-0x57 */ - 0x5CCF,0x5CD0,0x5CD1,0x5CD3,0x5CD4,0x5CD5,0x5CD6,0x5CD7,/* 0x58-0x5F */ - 0x5CD8,0x5CDA,0x5CDB,0x5CDC,0x5CDD,0x5CDE,0x5CDF,0x5CE0,/* 0x60-0x67 */ - 0x5CE2,0x5CE3,0x5CE7,0x5CE9,0x5CEB,0x5CEC,0x5CEE,0x5CEF,/* 0x68-0x6F */ - 0x5CF1,0x5CF2,0x5CF3,0x5CF4,0x5CF5,0x5CF6,0x5CF7,0x5CF8,/* 0x70-0x77 */ - 0x5CF9,0x5CFA,0x5CFC,0x5CFD,0x5CFE,0x5CFF,0x5D00,0x0000,/* 0x78-0x7F */ - - 0x5D01,0x5D04,0x5D05,0x5D08,0x5D09,0x5D0A,0x5D0B,0x5D0C,/* 0x80-0x87 */ - 0x5D0D,0x5D0F,0x5D10,0x5D11,0x5D12,0x5D13,0x5D15,0x5D17,/* 0x88-0x8F */ - 0x5D18,0x5D19,0x5D1A,0x5D1C,0x5D1D,0x5D1F,0x5D20,0x5D21,/* 0x90-0x97 */ - 0x5D22,0x5D23,0x5D25,0x5D28,0x5D2A,0x5D2B,0x5D2C,0x5D2F,/* 0x98-0x9F */ - 0x5D30,0x5D31,0x5D32,0x5D33,0x5D35,0x5D36,0x5D37,0x5D38,/* 0xA0-0xA7 */ - 0x5D39,0x5D3A,0x5D3B,0x5D3C,0x5D3F,0x5D40,0x5D41,0x5D42,/* 0xA8-0xAF */ - 0x5D43,0x5D44,0x5D45,0x5D46,0x5D48,0x5D49,0x5D4D,0x5D4E,/* 0xB0-0xB7 */ - 0x5D4F,0x5D50,0x5D51,0x5D52,0x5D53,0x5D54,0x5D55,0x5D56,/* 0xB8-0xBF */ - 0x5D57,0x5D59,0x5D5A,0x5D5C,0x5D5E,0x5D5F,0x5D60,0x5D61,/* 0xC0-0xC7 */ - 0x5D62,0x5D63,0x5D64,0x5D65,0x5D66,0x5D67,0x5D68,0x5D6A,/* 0xC8-0xCF */ - 0x5D6D,0x5D6E,0x5D70,0x5D71,0x5D72,0x5D73,0x5D75,0x5D76,/* 0xD0-0xD7 */ - 0x5D77,0x5D78,0x5D79,0x5D7A,0x5D7B,0x5D7C,0x5D7D,0x5D7E,/* 0xD8-0xDF */ - 0x5D7F,0x5D80,0x5D81,0x5D83,0x5D84,0x5D85,0x5D86,0x5D87,/* 0xE0-0xE7 */ - 0x5D88,0x5D89,0x5D8A,0x5D8B,0x5D8C,0x5D8D,0x5D8E,0x5D8F,/* 0xE8-0xEF */ - 0x5D90,0x5D91,0x5D92,0x5D93,0x5D94,0x5D95,0x5D96,0x5D97,/* 0xF0-0xF7 */ - 0x5D98,0x5D9A,0x5D9B,0x5D9C,0x5D9E,0x5D9F,0x5DA0,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_8E[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5DA1,0x5DA2,0x5DA3,0x5DA4,0x5DA5,0x5DA6,0x5DA7,0x5DA8,/* 0x40-0x47 */ - 0x5DA9,0x5DAA,0x5DAB,0x5DAC,0x5DAD,0x5DAE,0x5DAF,0x5DB0,/* 0x48-0x4F */ - 0x5DB1,0x5DB2,0x5DB3,0x5DB4,0x5DB5,0x5DB6,0x5DB8,0x5DB9,/* 0x50-0x57 */ - 0x5DBA,0x5DBB,0x5DBC,0x5DBD,0x5DBE,0x5DBF,0x5DC0,0x5DC1,/* 0x58-0x5F */ - 0x5DC2,0x5DC3,0x5DC4,0x5DC6,0x5DC7,0x5DC8,0x5DC9,0x5DCA,/* 0x60-0x67 */ - 0x5DCB,0x5DCC,0x5DCE,0x5DCF,0x5DD0,0x5DD1,0x5DD2,0x5DD3,/* 0x68-0x6F */ - 0x5DD4,0x5DD5,0x5DD6,0x5DD7,0x5DD8,0x5DD9,0x5DDA,0x5DDC,/* 0x70-0x77 */ - 0x5DDF,0x5DE0,0x5DE3,0x5DE4,0x5DEA,0x5DEC,0x5DED,0x0000,/* 0x78-0x7F */ - - 0x5DF0,0x5DF5,0x5DF6,0x5DF8,0x5DF9,0x5DFA,0x5DFB,0x5DFC,/* 0x80-0x87 */ - 0x5DFF,0x5E00,0x5E04,0x5E07,0x5E09,0x5E0A,0x5E0B,0x5E0D,/* 0x88-0x8F */ - 0x5E0E,0x5E12,0x5E13,0x5E17,0x5E1E,0x5E1F,0x5E20,0x5E21,/* 0x90-0x97 */ - 0x5E22,0x5E23,0x5E24,0x5E25,0x5E28,0x5E29,0x5E2A,0x5E2B,/* 0x98-0x9F */ - 0x5E2C,0x5E2F,0x5E30,0x5E32,0x5E33,0x5E34,0x5E35,0x5E36,/* 0xA0-0xA7 */ - 0x5E39,0x5E3A,0x5E3E,0x5E3F,0x5E40,0x5E41,0x5E43,0x5E46,/* 0xA8-0xAF */ - 0x5E47,0x5E48,0x5E49,0x5E4A,0x5E4B,0x5E4D,0x5E4E,0x5E4F,/* 0xB0-0xB7 */ - 0x5E50,0x5E51,0x5E52,0x5E53,0x5E56,0x5E57,0x5E58,0x5E59,/* 0xB8-0xBF */ - 0x5E5A,0x5E5C,0x5E5D,0x5E5F,0x5E60,0x5E63,0x5E64,0x5E65,/* 0xC0-0xC7 */ - 0x5E66,0x5E67,0x5E68,0x5E69,0x5E6A,0x5E6B,0x5E6C,0x5E6D,/* 0xC8-0xCF */ - 0x5E6E,0x5E6F,0x5E70,0x5E71,0x5E75,0x5E77,0x5E79,0x5E7E,/* 0xD0-0xD7 */ - 0x5E81,0x5E82,0x5E83,0x5E85,0x5E88,0x5E89,0x5E8C,0x5E8D,/* 0xD8-0xDF */ - 0x5E8E,0x5E92,0x5E98,0x5E9B,0x5E9D,0x5EA1,0x5EA2,0x5EA3,/* 0xE0-0xE7 */ - 0x5EA4,0x5EA8,0x5EA9,0x5EAA,0x5EAB,0x5EAC,0x5EAE,0x5EAF,/* 0xE8-0xEF */ - 0x5EB0,0x5EB1,0x5EB2,0x5EB4,0x5EBA,0x5EBB,0x5EBC,0x5EBD,/* 0xF0-0xF7 */ - 0x5EBF,0x5EC0,0x5EC1,0x5EC2,0x5EC3,0x5EC4,0x5EC5,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_8F[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5EC6,0x5EC7,0x5EC8,0x5ECB,0x5ECC,0x5ECD,0x5ECE,0x5ECF,/* 0x40-0x47 */ - 0x5ED0,0x5ED4,0x5ED5,0x5ED7,0x5ED8,0x5ED9,0x5EDA,0x5EDC,/* 0x48-0x4F */ - 0x5EDD,0x5EDE,0x5EDF,0x5EE0,0x5EE1,0x5EE2,0x5EE3,0x5EE4,/* 0x50-0x57 */ - 0x5EE5,0x5EE6,0x5EE7,0x5EE9,0x5EEB,0x5EEC,0x5EED,0x5EEE,/* 0x58-0x5F */ - 0x5EEF,0x5EF0,0x5EF1,0x5EF2,0x5EF3,0x5EF5,0x5EF8,0x5EF9,/* 0x60-0x67 */ - 0x5EFB,0x5EFC,0x5EFD,0x5F05,0x5F06,0x5F07,0x5F09,0x5F0C,/* 0x68-0x6F */ - 0x5F0D,0x5F0E,0x5F10,0x5F12,0x5F14,0x5F16,0x5F19,0x5F1A,/* 0x70-0x77 */ - 0x5F1C,0x5F1D,0x5F1E,0x5F21,0x5F22,0x5F23,0x5F24,0x0000,/* 0x78-0x7F */ - - 0x5F28,0x5F2B,0x5F2C,0x5F2E,0x5F30,0x5F32,0x5F33,0x5F34,/* 0x80-0x87 */ - 0x5F35,0x5F36,0x5F37,0x5F38,0x5F3B,0x5F3D,0x5F3E,0x5F3F,/* 0x88-0x8F */ - 0x5F41,0x5F42,0x5F43,0x5F44,0x5F45,0x5F46,0x5F47,0x5F48,/* 0x90-0x97 */ - 0x5F49,0x5F4A,0x5F4B,0x5F4C,0x5F4D,0x5F4E,0x5F4F,0x5F51,/* 0x98-0x9F */ - 0x5F54,0x5F59,0x5F5A,0x5F5B,0x5F5C,0x5F5E,0x5F5F,0x5F60,/* 0xA0-0xA7 */ - 0x5F63,0x5F65,0x5F67,0x5F68,0x5F6B,0x5F6E,0x5F6F,0x5F72,/* 0xA8-0xAF */ - 0x5F74,0x5F75,0x5F76,0x5F78,0x5F7A,0x5F7D,0x5F7E,0x5F7F,/* 0xB0-0xB7 */ - 0x5F83,0x5F86,0x5F8D,0x5F8E,0x5F8F,0x5F91,0x5F93,0x5F94,/* 0xB8-0xBF */ - 0x5F96,0x5F9A,0x5F9B,0x5F9D,0x5F9E,0x5F9F,0x5FA0,0x5FA2,/* 0xC0-0xC7 */ - 0x5FA3,0x5FA4,0x5FA5,0x5FA6,0x5FA7,0x5FA9,0x5FAB,0x5FAC,/* 0xC8-0xCF */ - 0x5FAF,0x5FB0,0x5FB1,0x5FB2,0x5FB3,0x5FB4,0x5FB6,0x5FB8,/* 0xD0-0xD7 */ - 0x5FB9,0x5FBA,0x5FBB,0x5FBE,0x5FBF,0x5FC0,0x5FC1,0x5FC2,/* 0xD8-0xDF */ - 0x5FC7,0x5FC8,0x5FCA,0x5FCB,0x5FCE,0x5FD3,0x5FD4,0x5FD5,/* 0xE0-0xE7 */ - 0x5FDA,0x5FDB,0x5FDC,0x5FDE,0x5FDF,0x5FE2,0x5FE3,0x5FE5,/* 0xE8-0xEF */ - 0x5FE6,0x5FE8,0x5FE9,0x5FEC,0x5FEF,0x5FF0,0x5FF2,0x5FF3,/* 0xF0-0xF7 */ - 0x5FF4,0x5FF6,0x5FF7,0x5FF9,0x5FFA,0x5FFC,0x6007,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_90[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6008,0x6009,0x600B,0x600C,0x6010,0x6011,0x6013,0x6017,/* 0x40-0x47 */ - 0x6018,0x601A,0x601E,0x601F,0x6022,0x6023,0x6024,0x602C,/* 0x48-0x4F */ - 0x602D,0x602E,0x6030,0x6031,0x6032,0x6033,0x6034,0x6036,/* 0x50-0x57 */ - 0x6037,0x6038,0x6039,0x603A,0x603D,0x603E,0x6040,0x6044,/* 0x58-0x5F */ - 0x6045,0x6046,0x6047,0x6048,0x6049,0x604A,0x604C,0x604E,/* 0x60-0x67 */ - 0x604F,0x6051,0x6053,0x6054,0x6056,0x6057,0x6058,0x605B,/* 0x68-0x6F */ - 0x605C,0x605E,0x605F,0x6060,0x6061,0x6065,0x6066,0x606E,/* 0x70-0x77 */ - 0x6071,0x6072,0x6074,0x6075,0x6077,0x607E,0x6080,0x0000,/* 0x78-0x7F */ - - 0x6081,0x6082,0x6085,0x6086,0x6087,0x6088,0x608A,0x608B,/* 0x80-0x87 */ - 0x608E,0x608F,0x6090,0x6091,0x6093,0x6095,0x6097,0x6098,/* 0x88-0x8F */ - 0x6099,0x609C,0x609E,0x60A1,0x60A2,0x60A4,0x60A5,0x60A7,/* 0x90-0x97 */ - 0x60A9,0x60AA,0x60AE,0x60B0,0x60B3,0x60B5,0x60B6,0x60B7,/* 0x98-0x9F */ - 0x60B9,0x60BA,0x60BD,0x60BE,0x60BF,0x60C0,0x60C1,0x60C2,/* 0xA0-0xA7 */ - 0x60C3,0x60C4,0x60C7,0x60C8,0x60C9,0x60CC,0x60CD,0x60CE,/* 0xA8-0xAF */ - 0x60CF,0x60D0,0x60D2,0x60D3,0x60D4,0x60D6,0x60D7,0x60D9,/* 0xB0-0xB7 */ - 0x60DB,0x60DE,0x60E1,0x60E2,0x60E3,0x60E4,0x60E5,0x60EA,/* 0xB8-0xBF */ - 0x60F1,0x60F2,0x60F5,0x60F7,0x60F8,0x60FB,0x60FC,0x60FD,/* 0xC0-0xC7 */ - 0x60FE,0x60FF,0x6102,0x6103,0x6104,0x6105,0x6107,0x610A,/* 0xC8-0xCF */ - 0x610B,0x610C,0x6110,0x6111,0x6112,0x6113,0x6114,0x6116,/* 0xD0-0xD7 */ - 0x6117,0x6118,0x6119,0x611B,0x611C,0x611D,0x611E,0x6121,/* 0xD8-0xDF */ - 0x6122,0x6125,0x6128,0x6129,0x612A,0x612C,0x612D,0x612E,/* 0xE0-0xE7 */ - 0x612F,0x6130,0x6131,0x6132,0x6133,0x6134,0x6135,0x6136,/* 0xE8-0xEF */ - 0x6137,0x6138,0x6139,0x613A,0x613B,0x613C,0x613D,0x613E,/* 0xF0-0xF7 */ - 0x6140,0x6141,0x6142,0x6143,0x6144,0x6145,0x6146,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_91[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6147,0x6149,0x614B,0x614D,0x614F,0x6150,0x6152,0x6153,/* 0x40-0x47 */ - 0x6154,0x6156,0x6157,0x6158,0x6159,0x615A,0x615B,0x615C,/* 0x48-0x4F */ - 0x615E,0x615F,0x6160,0x6161,0x6163,0x6164,0x6165,0x6166,/* 0x50-0x57 */ - 0x6169,0x616A,0x616B,0x616C,0x616D,0x616E,0x616F,0x6171,/* 0x58-0x5F */ - 0x6172,0x6173,0x6174,0x6176,0x6178,0x6179,0x617A,0x617B,/* 0x60-0x67 */ - 0x617C,0x617D,0x617E,0x617F,0x6180,0x6181,0x6182,0x6183,/* 0x68-0x6F */ - 0x6184,0x6185,0x6186,0x6187,0x6188,0x6189,0x618A,0x618C,/* 0x70-0x77 */ - 0x618D,0x618F,0x6190,0x6191,0x6192,0x6193,0x6195,0x0000,/* 0x78-0x7F */ - - 0x6196,0x6197,0x6198,0x6199,0x619A,0x619B,0x619C,0x619E,/* 0x80-0x87 */ - 0x619F,0x61A0,0x61A1,0x61A2,0x61A3,0x61A4,0x61A5,0x61A6,/* 0x88-0x8F */ - 0x61AA,0x61AB,0x61AD,0x61AE,0x61AF,0x61B0,0x61B1,0x61B2,/* 0x90-0x97 */ - 0x61B3,0x61B4,0x61B5,0x61B6,0x61B8,0x61B9,0x61BA,0x61BB,/* 0x98-0x9F */ - 0x61BC,0x61BD,0x61BF,0x61C0,0x61C1,0x61C3,0x61C4,0x61C5,/* 0xA0-0xA7 */ - 0x61C6,0x61C7,0x61C9,0x61CC,0x61CD,0x61CE,0x61CF,0x61D0,/* 0xA8-0xAF */ - 0x61D3,0x61D5,0x61D6,0x61D7,0x61D8,0x61D9,0x61DA,0x61DB,/* 0xB0-0xB7 */ - 0x61DC,0x61DD,0x61DE,0x61DF,0x61E0,0x61E1,0x61E2,0x61E3,/* 0xB8-0xBF */ - 0x61E4,0x61E5,0x61E7,0x61E8,0x61E9,0x61EA,0x61EB,0x61EC,/* 0xC0-0xC7 */ - 0x61ED,0x61EE,0x61EF,0x61F0,0x61F1,0x61F2,0x61F3,0x61F4,/* 0xC8-0xCF */ - 0x61F6,0x61F7,0x61F8,0x61F9,0x61FA,0x61FB,0x61FC,0x61FD,/* 0xD0-0xD7 */ - 0x61FE,0x6200,0x6201,0x6202,0x6203,0x6204,0x6205,0x6207,/* 0xD8-0xDF */ - 0x6209,0x6213,0x6214,0x6219,0x621C,0x621D,0x621E,0x6220,/* 0xE0-0xE7 */ - 0x6223,0x6226,0x6227,0x6228,0x6229,0x622B,0x622D,0x622F,/* 0xE8-0xEF */ - 0x6230,0x6231,0x6232,0x6235,0x6236,0x6238,0x6239,0x623A,/* 0xF0-0xF7 */ - 0x623B,0x623C,0x6242,0x6244,0x6245,0x6246,0x624A,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_92[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x624F,0x6250,0x6255,0x6256,0x6257,0x6259,0x625A,0x625C,/* 0x40-0x47 */ - 0x625D,0x625E,0x625F,0x6260,0x6261,0x6262,0x6264,0x6265,/* 0x48-0x4F */ - 0x6268,0x6271,0x6272,0x6274,0x6275,0x6277,0x6278,0x627A,/* 0x50-0x57 */ - 0x627B,0x627D,0x6281,0x6282,0x6283,0x6285,0x6286,0x6287,/* 0x58-0x5F */ - 0x6288,0x628B,0x628C,0x628D,0x628E,0x628F,0x6290,0x6294,/* 0x60-0x67 */ - 0x6299,0x629C,0x629D,0x629E,0x62A3,0x62A6,0x62A7,0x62A9,/* 0x68-0x6F */ - 0x62AA,0x62AD,0x62AE,0x62AF,0x62B0,0x62B2,0x62B3,0x62B4,/* 0x70-0x77 */ - 0x62B6,0x62B7,0x62B8,0x62BA,0x62BE,0x62C0,0x62C1,0x0000,/* 0x78-0x7F */ - - 0x62C3,0x62CB,0x62CF,0x62D1,0x62D5,0x62DD,0x62DE,0x62E0,/* 0x80-0x87 */ - 0x62E1,0x62E4,0x62EA,0x62EB,0x62F0,0x62F2,0x62F5,0x62F8,/* 0x88-0x8F */ - 0x62F9,0x62FA,0x62FB,0x6300,0x6303,0x6304,0x6305,0x6306,/* 0x90-0x97 */ - 0x630A,0x630B,0x630C,0x630D,0x630F,0x6310,0x6312,0x6313,/* 0x98-0x9F */ - 0x6314,0x6315,0x6317,0x6318,0x6319,0x631C,0x6326,0x6327,/* 0xA0-0xA7 */ - 0x6329,0x632C,0x632D,0x632E,0x6330,0x6331,0x6333,0x6334,/* 0xA8-0xAF */ - 0x6335,0x6336,0x6337,0x6338,0x633B,0x633C,0x633E,0x633F,/* 0xB0-0xB7 */ - 0x6340,0x6341,0x6344,0x6347,0x6348,0x634A,0x6351,0x6352,/* 0xB8-0xBF */ - 0x6353,0x6354,0x6356,0x6357,0x6358,0x6359,0x635A,0x635B,/* 0xC0-0xC7 */ - 0x635C,0x635D,0x6360,0x6364,0x6365,0x6366,0x6368,0x636A,/* 0xC8-0xCF */ - 0x636B,0x636C,0x636F,0x6370,0x6372,0x6373,0x6374,0x6375,/* 0xD0-0xD7 */ - 0x6378,0x6379,0x637C,0x637D,0x637E,0x637F,0x6381,0x6383,/* 0xD8-0xDF */ - 0x6384,0x6385,0x6386,0x638B,0x638D,0x6391,0x6393,0x6394,/* 0xE0-0xE7 */ - 0x6395,0x6397,0x6399,0x639A,0x639B,0x639C,0x639D,0x639E,/* 0xE8-0xEF */ - 0x639F,0x63A1,0x63A4,0x63A6,0x63AB,0x63AF,0x63B1,0x63B2,/* 0xF0-0xF7 */ - 0x63B5,0x63B6,0x63B9,0x63BB,0x63BD,0x63BF,0x63C0,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_93[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x63C1,0x63C2,0x63C3,0x63C5,0x63C7,0x63C8,0x63CA,0x63CB,/* 0x40-0x47 */ - 0x63CC,0x63D1,0x63D3,0x63D4,0x63D5,0x63D7,0x63D8,0x63D9,/* 0x48-0x4F */ - 0x63DA,0x63DB,0x63DC,0x63DD,0x63DF,0x63E2,0x63E4,0x63E5,/* 0x50-0x57 */ - 0x63E6,0x63E7,0x63E8,0x63EB,0x63EC,0x63EE,0x63EF,0x63F0,/* 0x58-0x5F */ - 0x63F1,0x63F3,0x63F5,0x63F7,0x63F9,0x63FA,0x63FB,0x63FC,/* 0x60-0x67 */ - 0x63FE,0x6403,0x6404,0x6406,0x6407,0x6408,0x6409,0x640A,/* 0x68-0x6F */ - 0x640D,0x640E,0x6411,0x6412,0x6415,0x6416,0x6417,0x6418,/* 0x70-0x77 */ - 0x6419,0x641A,0x641D,0x641F,0x6422,0x6423,0x6424,0x0000,/* 0x78-0x7F */ - - 0x6425,0x6427,0x6428,0x6429,0x642B,0x642E,0x642F,0x6430,/* 0x80-0x87 */ - 0x6431,0x6432,0x6433,0x6435,0x6436,0x6437,0x6438,0x6439,/* 0x88-0x8F */ - 0x643B,0x643C,0x643E,0x6440,0x6442,0x6443,0x6449,0x644B,/* 0x90-0x97 */ - 0x644C,0x644D,0x644E,0x644F,0x6450,0x6451,0x6453,0x6455,/* 0x98-0x9F */ - 0x6456,0x6457,0x6459,0x645A,0x645B,0x645C,0x645D,0x645F,/* 0xA0-0xA7 */ - 0x6460,0x6461,0x6462,0x6463,0x6464,0x6465,0x6466,0x6468,/* 0xA8-0xAF */ - 0x646A,0x646B,0x646C,0x646E,0x646F,0x6470,0x6471,0x6472,/* 0xB0-0xB7 */ - 0x6473,0x6474,0x6475,0x6476,0x6477,0x647B,0x647C,0x647D,/* 0xB8-0xBF */ - 0x647E,0x647F,0x6480,0x6481,0x6483,0x6486,0x6488,0x6489,/* 0xC0-0xC7 */ - 0x648A,0x648B,0x648C,0x648D,0x648E,0x648F,0x6490,0x6493,/* 0xC8-0xCF */ - 0x6494,0x6497,0x6498,0x649A,0x649B,0x649C,0x649D,0x649F,/* 0xD0-0xD7 */ - 0x64A0,0x64A1,0x64A2,0x64A3,0x64A5,0x64A6,0x64A7,0x64A8,/* 0xD8-0xDF */ - 0x64AA,0x64AB,0x64AF,0x64B1,0x64B2,0x64B3,0x64B4,0x64B6,/* 0xE0-0xE7 */ - 0x64B9,0x64BB,0x64BD,0x64BE,0x64BF,0x64C1,0x64C3,0x64C4,/* 0xE8-0xEF */ - 0x64C6,0x64C7,0x64C8,0x64C9,0x64CA,0x64CB,0x64CC,0x64CF,/* 0xF0-0xF7 */ - 0x64D1,0x64D3,0x64D4,0x64D5,0x64D6,0x64D9,0x64DA,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_94[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x64DB,0x64DC,0x64DD,0x64DF,0x64E0,0x64E1,0x64E3,0x64E5,/* 0x40-0x47 */ - 0x64E7,0x64E8,0x64E9,0x64EA,0x64EB,0x64EC,0x64ED,0x64EE,/* 0x48-0x4F */ - 0x64EF,0x64F0,0x64F1,0x64F2,0x64F3,0x64F4,0x64F5,0x64F6,/* 0x50-0x57 */ - 0x64F7,0x64F8,0x64F9,0x64FA,0x64FB,0x64FC,0x64FD,0x64FE,/* 0x58-0x5F */ - 0x64FF,0x6501,0x6502,0x6503,0x6504,0x6505,0x6506,0x6507,/* 0x60-0x67 */ - 0x6508,0x650A,0x650B,0x650C,0x650D,0x650E,0x650F,0x6510,/* 0x68-0x6F */ - 0x6511,0x6513,0x6514,0x6515,0x6516,0x6517,0x6519,0x651A,/* 0x70-0x77 */ - 0x651B,0x651C,0x651D,0x651E,0x651F,0x6520,0x6521,0x0000,/* 0x78-0x7F */ - - 0x6522,0x6523,0x6524,0x6526,0x6527,0x6528,0x6529,0x652A,/* 0x80-0x87 */ - 0x652C,0x652D,0x6530,0x6531,0x6532,0x6533,0x6537,0x653A,/* 0x88-0x8F */ - 0x653C,0x653D,0x6540,0x6541,0x6542,0x6543,0x6544,0x6546,/* 0x90-0x97 */ - 0x6547,0x654A,0x654B,0x654D,0x654E,0x6550,0x6552,0x6553,/* 0x98-0x9F */ - 0x6554,0x6557,0x6558,0x655A,0x655C,0x655F,0x6560,0x6561,/* 0xA0-0xA7 */ - 0x6564,0x6565,0x6567,0x6568,0x6569,0x656A,0x656D,0x656E,/* 0xA8-0xAF */ - 0x656F,0x6571,0x6573,0x6575,0x6576,0x6578,0x6579,0x657A,/* 0xB0-0xB7 */ - 0x657B,0x657C,0x657D,0x657E,0x657F,0x6580,0x6581,0x6582,/* 0xB8-0xBF */ - 0x6583,0x6584,0x6585,0x6586,0x6588,0x6589,0x658A,0x658D,/* 0xC0-0xC7 */ - 0x658E,0x658F,0x6592,0x6594,0x6595,0x6596,0x6598,0x659A,/* 0xC8-0xCF */ - 0x659D,0x659E,0x65A0,0x65A2,0x65A3,0x65A6,0x65A8,0x65AA,/* 0xD0-0xD7 */ - 0x65AC,0x65AE,0x65B1,0x65B2,0x65B3,0x65B4,0x65B5,0x65B6,/* 0xD8-0xDF */ - 0x65B7,0x65B8,0x65BA,0x65BB,0x65BE,0x65BF,0x65C0,0x65C2,/* 0xE0-0xE7 */ - 0x65C7,0x65C8,0x65C9,0x65CA,0x65CD,0x65D0,0x65D1,0x65D3,/* 0xE8-0xEF */ - 0x65D4,0x65D5,0x65D8,0x65D9,0x65DA,0x65DB,0x65DC,0x65DD,/* 0xF0-0xF7 */ - 0x65DE,0x65DF,0x65E1,0x65E3,0x65E4,0x65EA,0x65EB,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_95[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x65F2,0x65F3,0x65F4,0x65F5,0x65F8,0x65F9,0x65FB,0x65FC,/* 0x40-0x47 */ - 0x65FD,0x65FE,0x65FF,0x6601,0x6604,0x6605,0x6607,0x6608,/* 0x48-0x4F */ - 0x6609,0x660B,0x660D,0x6610,0x6611,0x6612,0x6616,0x6617,/* 0x50-0x57 */ - 0x6618,0x661A,0x661B,0x661C,0x661E,0x6621,0x6622,0x6623,/* 0x58-0x5F */ - 0x6624,0x6626,0x6629,0x662A,0x662B,0x662C,0x662E,0x6630,/* 0x60-0x67 */ - 0x6632,0x6633,0x6637,0x6638,0x6639,0x663A,0x663B,0x663D,/* 0x68-0x6F */ - 0x663F,0x6640,0x6642,0x6644,0x6645,0x6646,0x6647,0x6648,/* 0x70-0x77 */ - 0x6649,0x664A,0x664D,0x664E,0x6650,0x6651,0x6658,0x0000,/* 0x78-0x7F */ - - 0x6659,0x665B,0x665C,0x665D,0x665E,0x6660,0x6662,0x6663,/* 0x80-0x87 */ - 0x6665,0x6667,0x6669,0x666A,0x666B,0x666C,0x666D,0x6671,/* 0x88-0x8F */ - 0x6672,0x6673,0x6675,0x6678,0x6679,0x667B,0x667C,0x667D,/* 0x90-0x97 */ - 0x667F,0x6680,0x6681,0x6683,0x6685,0x6686,0x6688,0x6689,/* 0x98-0x9F */ - 0x668A,0x668B,0x668D,0x668E,0x668F,0x6690,0x6692,0x6693,/* 0xA0-0xA7 */ - 0x6694,0x6695,0x6698,0x6699,0x669A,0x669B,0x669C,0x669E,/* 0xA8-0xAF */ - 0x669F,0x66A0,0x66A1,0x66A2,0x66A3,0x66A4,0x66A5,0x66A6,/* 0xB0-0xB7 */ - 0x66A9,0x66AA,0x66AB,0x66AC,0x66AD,0x66AF,0x66B0,0x66B1,/* 0xB8-0xBF */ - 0x66B2,0x66B3,0x66B5,0x66B6,0x66B7,0x66B8,0x66BA,0x66BB,/* 0xC0-0xC7 */ - 0x66BC,0x66BD,0x66BF,0x66C0,0x66C1,0x66C2,0x66C3,0x66C4,/* 0xC8-0xCF */ - 0x66C5,0x66C6,0x66C7,0x66C8,0x66C9,0x66CA,0x66CB,0x66CC,/* 0xD0-0xD7 */ - 0x66CD,0x66CE,0x66CF,0x66D0,0x66D1,0x66D2,0x66D3,0x66D4,/* 0xD8-0xDF */ - 0x66D5,0x66D6,0x66D7,0x66D8,0x66DA,0x66DE,0x66DF,0x66E0,/* 0xE0-0xE7 */ - 0x66E1,0x66E2,0x66E3,0x66E4,0x66E5,0x66E7,0x66E8,0x66EA,/* 0xE8-0xEF */ - 0x66EB,0x66EC,0x66ED,0x66EE,0x66EF,0x66F1,0x66F5,0x66F6,/* 0xF0-0xF7 */ - 0x66F8,0x66FA,0x66FB,0x66FD,0x6701,0x6702,0x6703,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_96[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6704,0x6705,0x6706,0x6707,0x670C,0x670E,0x670F,0x6711,/* 0x40-0x47 */ - 0x6712,0x6713,0x6716,0x6718,0x6719,0x671A,0x671C,0x671E,/* 0x48-0x4F */ - 0x6720,0x6721,0x6722,0x6723,0x6724,0x6725,0x6727,0x6729,/* 0x50-0x57 */ - 0x672E,0x6730,0x6732,0x6733,0x6736,0x6737,0x6738,0x6739,/* 0x58-0x5F */ - 0x673B,0x673C,0x673E,0x673F,0x6741,0x6744,0x6745,0x6747,/* 0x60-0x67 */ - 0x674A,0x674B,0x674D,0x6752,0x6754,0x6755,0x6757,0x6758,/* 0x68-0x6F */ - 0x6759,0x675A,0x675B,0x675D,0x6762,0x6763,0x6764,0x6766,/* 0x70-0x77 */ - 0x6767,0x676B,0x676C,0x676E,0x6771,0x6774,0x6776,0x0000,/* 0x78-0x7F */ - - 0x6778,0x6779,0x677A,0x677B,0x677D,0x6780,0x6782,0x6783,/* 0x80-0x87 */ - 0x6785,0x6786,0x6788,0x678A,0x678C,0x678D,0x678E,0x678F,/* 0x88-0x8F */ - 0x6791,0x6792,0x6793,0x6794,0x6796,0x6799,0x679B,0x679F,/* 0x90-0x97 */ - 0x67A0,0x67A1,0x67A4,0x67A6,0x67A9,0x67AC,0x67AE,0x67B1,/* 0x98-0x9F */ - 0x67B2,0x67B4,0x67B9,0x67BA,0x67BB,0x67BC,0x67BD,0x67BE,/* 0xA0-0xA7 */ - 0x67BF,0x67C0,0x67C2,0x67C5,0x67C6,0x67C7,0x67C8,0x67C9,/* 0xA8-0xAF */ - 0x67CA,0x67CB,0x67CC,0x67CD,0x67CE,0x67D5,0x67D6,0x67D7,/* 0xB0-0xB7 */ - 0x67DB,0x67DF,0x67E1,0x67E3,0x67E4,0x67E6,0x67E7,0x67E8,/* 0xB8-0xBF */ - 0x67EA,0x67EB,0x67ED,0x67EE,0x67F2,0x67F5,0x67F6,0x67F7,/* 0xC0-0xC7 */ - 0x67F8,0x67F9,0x67FA,0x67FB,0x67FC,0x67FE,0x6801,0x6802,/* 0xC8-0xCF */ - 0x6803,0x6804,0x6806,0x680D,0x6810,0x6812,0x6814,0x6815,/* 0xD0-0xD7 */ - 0x6818,0x6819,0x681A,0x681B,0x681C,0x681E,0x681F,0x6820,/* 0xD8-0xDF */ - 0x6822,0x6823,0x6824,0x6825,0x6826,0x6827,0x6828,0x682B,/* 0xE0-0xE7 */ - 0x682C,0x682D,0x682E,0x682F,0x6830,0x6831,0x6834,0x6835,/* 0xE8-0xEF */ - 0x6836,0x683A,0x683B,0x683F,0x6847,0x684B,0x684D,0x684F,/* 0xF0-0xF7 */ - 0x6852,0x6856,0x6857,0x6858,0x6859,0x685A,0x685B,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_97[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x685C,0x685D,0x685E,0x685F,0x686A,0x686C,0x686D,0x686E,/* 0x40-0x47 */ - 0x686F,0x6870,0x6871,0x6872,0x6873,0x6875,0x6878,0x6879,/* 0x48-0x4F */ - 0x687A,0x687B,0x687C,0x687D,0x687E,0x687F,0x6880,0x6882,/* 0x50-0x57 */ - 0x6884,0x6887,0x6888,0x6889,0x688A,0x688B,0x688C,0x688D,/* 0x58-0x5F */ - 0x688E,0x6890,0x6891,0x6892,0x6894,0x6895,0x6896,0x6898,/* 0x60-0x67 */ - 0x6899,0x689A,0x689B,0x689C,0x689D,0x689E,0x689F,0x68A0,/* 0x68-0x6F */ - 0x68A1,0x68A3,0x68A4,0x68A5,0x68A9,0x68AA,0x68AB,0x68AC,/* 0x70-0x77 */ - 0x68AE,0x68B1,0x68B2,0x68B4,0x68B6,0x68B7,0x68B8,0x0000,/* 0x78-0x7F */ - - 0x68B9,0x68BA,0x68BB,0x68BC,0x68BD,0x68BE,0x68BF,0x68C1,/* 0x80-0x87 */ - 0x68C3,0x68C4,0x68C5,0x68C6,0x68C7,0x68C8,0x68CA,0x68CC,/* 0x88-0x8F */ - 0x68CE,0x68CF,0x68D0,0x68D1,0x68D3,0x68D4,0x68D6,0x68D7,/* 0x90-0x97 */ - 0x68D9,0x68DB,0x68DC,0x68DD,0x68DE,0x68DF,0x68E1,0x68E2,/* 0x98-0x9F */ - 0x68E4,0x68E5,0x68E6,0x68E7,0x68E8,0x68E9,0x68EA,0x68EB,/* 0xA0-0xA7 */ - 0x68EC,0x68ED,0x68EF,0x68F2,0x68F3,0x68F4,0x68F6,0x68F7,/* 0xA8-0xAF */ - 0x68F8,0x68FB,0x68FD,0x68FE,0x68FF,0x6900,0x6902,0x6903,/* 0xB0-0xB7 */ - 0x6904,0x6906,0x6907,0x6908,0x6909,0x690A,0x690C,0x690F,/* 0xB8-0xBF */ - 0x6911,0x6913,0x6914,0x6915,0x6916,0x6917,0x6918,0x6919,/* 0xC0-0xC7 */ - 0x691A,0x691B,0x691C,0x691D,0x691E,0x6921,0x6922,0x6923,/* 0xC8-0xCF */ - 0x6925,0x6926,0x6927,0x6928,0x6929,0x692A,0x692B,0x692C,/* 0xD0-0xD7 */ - 0x692E,0x692F,0x6931,0x6932,0x6933,0x6935,0x6936,0x6937,/* 0xD8-0xDF */ - 0x6938,0x693A,0x693B,0x693C,0x693E,0x6940,0x6941,0x6943,/* 0xE0-0xE7 */ - 0x6944,0x6945,0x6946,0x6947,0x6948,0x6949,0x694A,0x694B,/* 0xE8-0xEF */ - 0x694C,0x694D,0x694E,0x694F,0x6950,0x6951,0x6952,0x6953,/* 0xF0-0xF7 */ - 0x6955,0x6956,0x6958,0x6959,0x695B,0x695C,0x695F,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_98[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6961,0x6962,0x6964,0x6965,0x6967,0x6968,0x6969,0x696A,/* 0x40-0x47 */ - 0x696C,0x696D,0x696F,0x6970,0x6972,0x6973,0x6974,0x6975,/* 0x48-0x4F */ - 0x6976,0x697A,0x697B,0x697D,0x697E,0x697F,0x6981,0x6983,/* 0x50-0x57 */ - 0x6985,0x698A,0x698B,0x698C,0x698E,0x698F,0x6990,0x6991,/* 0x58-0x5F */ - 0x6992,0x6993,0x6996,0x6997,0x6999,0x699A,0x699D,0x699E,/* 0x60-0x67 */ - 0x699F,0x69A0,0x69A1,0x69A2,0x69A3,0x69A4,0x69A5,0x69A6,/* 0x68-0x6F */ - 0x69A9,0x69AA,0x69AC,0x69AE,0x69AF,0x69B0,0x69B2,0x69B3,/* 0x70-0x77 */ - 0x69B5,0x69B6,0x69B8,0x69B9,0x69BA,0x69BC,0x69BD,0x0000,/* 0x78-0x7F */ - - 0x69BE,0x69BF,0x69C0,0x69C2,0x69C3,0x69C4,0x69C5,0x69C6,/* 0x80-0x87 */ - 0x69C7,0x69C8,0x69C9,0x69CB,0x69CD,0x69CF,0x69D1,0x69D2,/* 0x88-0x8F */ - 0x69D3,0x69D5,0x69D6,0x69D7,0x69D8,0x69D9,0x69DA,0x69DC,/* 0x90-0x97 */ - 0x69DD,0x69DE,0x69E1,0x69E2,0x69E3,0x69E4,0x69E5,0x69E6,/* 0x98-0x9F */ - 0x69E7,0x69E8,0x69E9,0x69EA,0x69EB,0x69EC,0x69EE,0x69EF,/* 0xA0-0xA7 */ - 0x69F0,0x69F1,0x69F3,0x69F4,0x69F5,0x69F6,0x69F7,0x69F8,/* 0xA8-0xAF */ - 0x69F9,0x69FA,0x69FB,0x69FC,0x69FE,0x6A00,0x6A01,0x6A02,/* 0xB0-0xB7 */ - 0x6A03,0x6A04,0x6A05,0x6A06,0x6A07,0x6A08,0x6A09,0x6A0B,/* 0xB8-0xBF */ - 0x6A0C,0x6A0D,0x6A0E,0x6A0F,0x6A10,0x6A11,0x6A12,0x6A13,/* 0xC0-0xC7 */ - 0x6A14,0x6A15,0x6A16,0x6A19,0x6A1A,0x6A1B,0x6A1C,0x6A1D,/* 0xC8-0xCF */ - 0x6A1E,0x6A20,0x6A22,0x6A23,0x6A24,0x6A25,0x6A26,0x6A27,/* 0xD0-0xD7 */ - 0x6A29,0x6A2B,0x6A2C,0x6A2D,0x6A2E,0x6A30,0x6A32,0x6A33,/* 0xD8-0xDF */ - 0x6A34,0x6A36,0x6A37,0x6A38,0x6A39,0x6A3A,0x6A3B,0x6A3C,/* 0xE0-0xE7 */ - 0x6A3F,0x6A40,0x6A41,0x6A42,0x6A43,0x6A45,0x6A46,0x6A48,/* 0xE8-0xEF */ - 0x6A49,0x6A4A,0x6A4B,0x6A4C,0x6A4D,0x6A4E,0x6A4F,0x6A51,/* 0xF0-0xF7 */ - 0x6A52,0x6A53,0x6A54,0x6A55,0x6A56,0x6A57,0x6A5A,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_99[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6A5C,0x6A5D,0x6A5E,0x6A5F,0x6A60,0x6A62,0x6A63,0x6A64,/* 0x40-0x47 */ - 0x6A66,0x6A67,0x6A68,0x6A69,0x6A6A,0x6A6B,0x6A6C,0x6A6D,/* 0x48-0x4F */ - 0x6A6E,0x6A6F,0x6A70,0x6A72,0x6A73,0x6A74,0x6A75,0x6A76,/* 0x50-0x57 */ - 0x6A77,0x6A78,0x6A7A,0x6A7B,0x6A7D,0x6A7E,0x6A7F,0x6A81,/* 0x58-0x5F */ - 0x6A82,0x6A83,0x6A85,0x6A86,0x6A87,0x6A88,0x6A89,0x6A8A,/* 0x60-0x67 */ - 0x6A8B,0x6A8C,0x6A8D,0x6A8F,0x6A92,0x6A93,0x6A94,0x6A95,/* 0x68-0x6F */ - 0x6A96,0x6A98,0x6A99,0x6A9A,0x6A9B,0x6A9C,0x6A9D,0x6A9E,/* 0x70-0x77 */ - 0x6A9F,0x6AA1,0x6AA2,0x6AA3,0x6AA4,0x6AA5,0x6AA6,0x0000,/* 0x78-0x7F */ - - 0x6AA7,0x6AA8,0x6AAA,0x6AAD,0x6AAE,0x6AAF,0x6AB0,0x6AB1,/* 0x80-0x87 */ - 0x6AB2,0x6AB3,0x6AB4,0x6AB5,0x6AB6,0x6AB7,0x6AB8,0x6AB9,/* 0x88-0x8F */ - 0x6ABA,0x6ABB,0x6ABC,0x6ABD,0x6ABE,0x6ABF,0x6AC0,0x6AC1,/* 0x90-0x97 */ - 0x6AC2,0x6AC3,0x6AC4,0x6AC5,0x6AC6,0x6AC7,0x6AC8,0x6AC9,/* 0x98-0x9F */ - 0x6ACA,0x6ACB,0x6ACC,0x6ACD,0x6ACE,0x6ACF,0x6AD0,0x6AD1,/* 0xA0-0xA7 */ - 0x6AD2,0x6AD3,0x6AD4,0x6AD5,0x6AD6,0x6AD7,0x6AD8,0x6AD9,/* 0xA8-0xAF */ - 0x6ADA,0x6ADB,0x6ADC,0x6ADD,0x6ADE,0x6ADF,0x6AE0,0x6AE1,/* 0xB0-0xB7 */ - 0x6AE2,0x6AE3,0x6AE4,0x6AE5,0x6AE6,0x6AE7,0x6AE8,0x6AE9,/* 0xB8-0xBF */ - 0x6AEA,0x6AEB,0x6AEC,0x6AED,0x6AEE,0x6AEF,0x6AF0,0x6AF1,/* 0xC0-0xC7 */ - 0x6AF2,0x6AF3,0x6AF4,0x6AF5,0x6AF6,0x6AF7,0x6AF8,0x6AF9,/* 0xC8-0xCF */ - 0x6AFA,0x6AFB,0x6AFC,0x6AFD,0x6AFE,0x6AFF,0x6B00,0x6B01,/* 0xD0-0xD7 */ - 0x6B02,0x6B03,0x6B04,0x6B05,0x6B06,0x6B07,0x6B08,0x6B09,/* 0xD8-0xDF */ - 0x6B0A,0x6B0B,0x6B0C,0x6B0D,0x6B0E,0x6B0F,0x6B10,0x6B11,/* 0xE0-0xE7 */ - 0x6B12,0x6B13,0x6B14,0x6B15,0x6B16,0x6B17,0x6B18,0x6B19,/* 0xE8-0xEF */ - 0x6B1A,0x6B1B,0x6B1C,0x6B1D,0x6B1E,0x6B1F,0x6B25,0x6B26,/* 0xF0-0xF7 */ - 0x6B28,0x6B29,0x6B2A,0x6B2B,0x6B2C,0x6B2D,0x6B2E,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_9A[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6B2F,0x6B30,0x6B31,0x6B33,0x6B34,0x6B35,0x6B36,0x6B38,/* 0x40-0x47 */ - 0x6B3B,0x6B3C,0x6B3D,0x6B3F,0x6B40,0x6B41,0x6B42,0x6B44,/* 0x48-0x4F */ - 0x6B45,0x6B48,0x6B4A,0x6B4B,0x6B4D,0x6B4E,0x6B4F,0x6B50,/* 0x50-0x57 */ - 0x6B51,0x6B52,0x6B53,0x6B54,0x6B55,0x6B56,0x6B57,0x6B58,/* 0x58-0x5F */ - 0x6B5A,0x6B5B,0x6B5C,0x6B5D,0x6B5E,0x6B5F,0x6B60,0x6B61,/* 0x60-0x67 */ - 0x6B68,0x6B69,0x6B6B,0x6B6C,0x6B6D,0x6B6E,0x6B6F,0x6B70,/* 0x68-0x6F */ - 0x6B71,0x6B72,0x6B73,0x6B74,0x6B75,0x6B76,0x6B77,0x6B78,/* 0x70-0x77 */ - 0x6B7A,0x6B7D,0x6B7E,0x6B7F,0x6B80,0x6B85,0x6B88,0x0000,/* 0x78-0x7F */ - - 0x6B8C,0x6B8E,0x6B8F,0x6B90,0x6B91,0x6B94,0x6B95,0x6B97,/* 0x80-0x87 */ - 0x6B98,0x6B99,0x6B9C,0x6B9D,0x6B9E,0x6B9F,0x6BA0,0x6BA2,/* 0x88-0x8F */ - 0x6BA3,0x6BA4,0x6BA5,0x6BA6,0x6BA7,0x6BA8,0x6BA9,0x6BAB,/* 0x90-0x97 */ - 0x6BAC,0x6BAD,0x6BAE,0x6BAF,0x6BB0,0x6BB1,0x6BB2,0x6BB6,/* 0x98-0x9F */ - 0x6BB8,0x6BB9,0x6BBA,0x6BBB,0x6BBC,0x6BBD,0x6BBE,0x6BC0,/* 0xA0-0xA7 */ - 0x6BC3,0x6BC4,0x6BC6,0x6BC7,0x6BC8,0x6BC9,0x6BCA,0x6BCC,/* 0xA8-0xAF */ - 0x6BCE,0x6BD0,0x6BD1,0x6BD8,0x6BDA,0x6BDC,0x6BDD,0x6BDE,/* 0xB0-0xB7 */ - 0x6BDF,0x6BE0,0x6BE2,0x6BE3,0x6BE4,0x6BE5,0x6BE6,0x6BE7,/* 0xB8-0xBF */ - 0x6BE8,0x6BE9,0x6BEC,0x6BED,0x6BEE,0x6BF0,0x6BF1,0x6BF2,/* 0xC0-0xC7 */ - 0x6BF4,0x6BF6,0x6BF7,0x6BF8,0x6BFA,0x6BFB,0x6BFC,0x6BFE,/* 0xC8-0xCF */ - 0x6BFF,0x6C00,0x6C01,0x6C02,0x6C03,0x6C04,0x6C08,0x6C09,/* 0xD0-0xD7 */ - 0x6C0A,0x6C0B,0x6C0C,0x6C0E,0x6C12,0x6C17,0x6C1C,0x6C1D,/* 0xD8-0xDF */ - 0x6C1E,0x6C20,0x6C23,0x6C25,0x6C2B,0x6C2C,0x6C2D,0x6C31,/* 0xE0-0xE7 */ - 0x6C33,0x6C36,0x6C37,0x6C39,0x6C3A,0x6C3B,0x6C3C,0x6C3E,/* 0xE8-0xEF */ - 0x6C3F,0x6C43,0x6C44,0x6C45,0x6C48,0x6C4B,0x6C4C,0x6C4D,/* 0xF0-0xF7 */ - 0x6C4E,0x6C4F,0x6C51,0x6C52,0x6C53,0x6C56,0x6C58,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_9B[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6C59,0x6C5A,0x6C62,0x6C63,0x6C65,0x6C66,0x6C67,0x6C6B,/* 0x40-0x47 */ - 0x6C6C,0x6C6D,0x6C6E,0x6C6F,0x6C71,0x6C73,0x6C75,0x6C77,/* 0x48-0x4F */ - 0x6C78,0x6C7A,0x6C7B,0x6C7C,0x6C7F,0x6C80,0x6C84,0x6C87,/* 0x50-0x57 */ - 0x6C8A,0x6C8B,0x6C8D,0x6C8E,0x6C91,0x6C92,0x6C95,0x6C96,/* 0x58-0x5F */ - 0x6C97,0x6C98,0x6C9A,0x6C9C,0x6C9D,0x6C9E,0x6CA0,0x6CA2,/* 0x60-0x67 */ - 0x6CA8,0x6CAC,0x6CAF,0x6CB0,0x6CB4,0x6CB5,0x6CB6,0x6CB7,/* 0x68-0x6F */ - 0x6CBA,0x6CC0,0x6CC1,0x6CC2,0x6CC3,0x6CC6,0x6CC7,0x6CC8,/* 0x70-0x77 */ - 0x6CCB,0x6CCD,0x6CCE,0x6CCF,0x6CD1,0x6CD2,0x6CD8,0x0000,/* 0x78-0x7F */ - - 0x6CD9,0x6CDA,0x6CDC,0x6CDD,0x6CDF,0x6CE4,0x6CE6,0x6CE7,/* 0x80-0x87 */ - 0x6CE9,0x6CEC,0x6CED,0x6CF2,0x6CF4,0x6CF9,0x6CFF,0x6D00,/* 0x88-0x8F */ - 0x6D02,0x6D03,0x6D05,0x6D06,0x6D08,0x6D09,0x6D0A,0x6D0D,/* 0x90-0x97 */ - 0x6D0F,0x6D10,0x6D11,0x6D13,0x6D14,0x6D15,0x6D16,0x6D18,/* 0x98-0x9F */ - 0x6D1C,0x6D1D,0x6D1F,0x6D20,0x6D21,0x6D22,0x6D23,0x6D24,/* 0xA0-0xA7 */ - 0x6D26,0x6D28,0x6D29,0x6D2C,0x6D2D,0x6D2F,0x6D30,0x6D34,/* 0xA8-0xAF */ - 0x6D36,0x6D37,0x6D38,0x6D3A,0x6D3F,0x6D40,0x6D42,0x6D44,/* 0xB0-0xB7 */ - 0x6D49,0x6D4C,0x6D50,0x6D55,0x6D56,0x6D57,0x6D58,0x6D5B,/* 0xB8-0xBF */ - 0x6D5D,0x6D5F,0x6D61,0x6D62,0x6D64,0x6D65,0x6D67,0x6D68,/* 0xC0-0xC7 */ - 0x6D6B,0x6D6C,0x6D6D,0x6D70,0x6D71,0x6D72,0x6D73,0x6D75,/* 0xC8-0xCF */ - 0x6D76,0x6D79,0x6D7A,0x6D7B,0x6D7D,0x6D7E,0x6D7F,0x6D80,/* 0xD0-0xD7 */ - 0x6D81,0x6D83,0x6D84,0x6D86,0x6D87,0x6D8A,0x6D8B,0x6D8D,/* 0xD8-0xDF */ - 0x6D8F,0x6D90,0x6D92,0x6D96,0x6D97,0x6D98,0x6D99,0x6D9A,/* 0xE0-0xE7 */ - 0x6D9C,0x6DA2,0x6DA5,0x6DAC,0x6DAD,0x6DB0,0x6DB1,0x6DB3,/* 0xE8-0xEF */ - 0x6DB4,0x6DB6,0x6DB7,0x6DB9,0x6DBA,0x6DBB,0x6DBC,0x6DBD,/* 0xF0-0xF7 */ - 0x6DBE,0x6DC1,0x6DC2,0x6DC3,0x6DC8,0x6DC9,0x6DCA,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_9C[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6DCD,0x6DCE,0x6DCF,0x6DD0,0x6DD2,0x6DD3,0x6DD4,0x6DD5,/* 0x40-0x47 */ - 0x6DD7,0x6DDA,0x6DDB,0x6DDC,0x6DDF,0x6DE2,0x6DE3,0x6DE5,/* 0x48-0x4F */ - 0x6DE7,0x6DE8,0x6DE9,0x6DEA,0x6DED,0x6DEF,0x6DF0,0x6DF2,/* 0x50-0x57 */ - 0x6DF4,0x6DF5,0x6DF6,0x6DF8,0x6DFA,0x6DFD,0x6DFE,0x6DFF,/* 0x58-0x5F */ - 0x6E00,0x6E01,0x6E02,0x6E03,0x6E04,0x6E06,0x6E07,0x6E08,/* 0x60-0x67 */ - 0x6E09,0x6E0B,0x6E0F,0x6E12,0x6E13,0x6E15,0x6E18,0x6E19,/* 0x68-0x6F */ - 0x6E1B,0x6E1C,0x6E1E,0x6E1F,0x6E22,0x6E26,0x6E27,0x6E28,/* 0x70-0x77 */ - 0x6E2A,0x6E2C,0x6E2E,0x6E30,0x6E31,0x6E33,0x6E35,0x0000,/* 0x78-0x7F */ - - 0x6E36,0x6E37,0x6E39,0x6E3B,0x6E3C,0x6E3D,0x6E3E,0x6E3F,/* 0x80-0x87 */ - 0x6E40,0x6E41,0x6E42,0x6E45,0x6E46,0x6E47,0x6E48,0x6E49,/* 0x88-0x8F */ - 0x6E4A,0x6E4B,0x6E4C,0x6E4F,0x6E50,0x6E51,0x6E52,0x6E55,/* 0x90-0x97 */ - 0x6E57,0x6E59,0x6E5A,0x6E5C,0x6E5D,0x6E5E,0x6E60,0x6E61,/* 0x98-0x9F */ - 0x6E62,0x6E63,0x6E64,0x6E65,0x6E66,0x6E67,0x6E68,0x6E69,/* 0xA0-0xA7 */ - 0x6E6A,0x6E6C,0x6E6D,0x6E6F,0x6E70,0x6E71,0x6E72,0x6E73,/* 0xA8-0xAF */ - 0x6E74,0x6E75,0x6E76,0x6E77,0x6E78,0x6E79,0x6E7A,0x6E7B,/* 0xB0-0xB7 */ - 0x6E7C,0x6E7D,0x6E80,0x6E81,0x6E82,0x6E84,0x6E87,0x6E88,/* 0xB8-0xBF */ - 0x6E8A,0x6E8B,0x6E8C,0x6E8D,0x6E8E,0x6E91,0x6E92,0x6E93,/* 0xC0-0xC7 */ - 0x6E94,0x6E95,0x6E96,0x6E97,0x6E99,0x6E9A,0x6E9B,0x6E9D,/* 0xC8-0xCF */ - 0x6E9E,0x6EA0,0x6EA1,0x6EA3,0x6EA4,0x6EA6,0x6EA8,0x6EA9,/* 0xD0-0xD7 */ - 0x6EAB,0x6EAC,0x6EAD,0x6EAE,0x6EB0,0x6EB3,0x6EB5,0x6EB8,/* 0xD8-0xDF */ - 0x6EB9,0x6EBC,0x6EBE,0x6EBF,0x6EC0,0x6EC3,0x6EC4,0x6EC5,/* 0xE0-0xE7 */ - 0x6EC6,0x6EC8,0x6EC9,0x6ECA,0x6ECC,0x6ECD,0x6ECE,0x6ED0,/* 0xE8-0xEF */ - 0x6ED2,0x6ED6,0x6ED8,0x6ED9,0x6EDB,0x6EDC,0x6EDD,0x6EE3,/* 0xF0-0xF7 */ - 0x6EE7,0x6EEA,0x6EEB,0x6EEC,0x6EED,0x6EEE,0x6EEF,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_9D[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6EF0,0x6EF1,0x6EF2,0x6EF3,0x6EF5,0x6EF6,0x6EF7,0x6EF8,/* 0x40-0x47 */ - 0x6EFA,0x6EFB,0x6EFC,0x6EFD,0x6EFE,0x6EFF,0x6F00,0x6F01,/* 0x48-0x4F */ - 0x6F03,0x6F04,0x6F05,0x6F07,0x6F08,0x6F0A,0x6F0B,0x6F0C,/* 0x50-0x57 */ - 0x6F0D,0x6F0E,0x6F10,0x6F11,0x6F12,0x6F16,0x6F17,0x6F18,/* 0x58-0x5F */ - 0x6F19,0x6F1A,0x6F1B,0x6F1C,0x6F1D,0x6F1E,0x6F1F,0x6F21,/* 0x60-0x67 */ - 0x6F22,0x6F23,0x6F25,0x6F26,0x6F27,0x6F28,0x6F2C,0x6F2E,/* 0x68-0x6F */ - 0x6F30,0x6F32,0x6F34,0x6F35,0x6F37,0x6F38,0x6F39,0x6F3A,/* 0x70-0x77 */ - 0x6F3B,0x6F3C,0x6F3D,0x6F3F,0x6F40,0x6F41,0x6F42,0x0000,/* 0x78-0x7F */ - - 0x6F43,0x6F44,0x6F45,0x6F48,0x6F49,0x6F4A,0x6F4C,0x6F4E,/* 0x80-0x87 */ - 0x6F4F,0x6F50,0x6F51,0x6F52,0x6F53,0x6F54,0x6F55,0x6F56,/* 0x88-0x8F */ - 0x6F57,0x6F59,0x6F5A,0x6F5B,0x6F5D,0x6F5F,0x6F60,0x6F61,/* 0x90-0x97 */ - 0x6F63,0x6F64,0x6F65,0x6F67,0x6F68,0x6F69,0x6F6A,0x6F6B,/* 0x98-0x9F */ - 0x6F6C,0x6F6F,0x6F70,0x6F71,0x6F73,0x6F75,0x6F76,0x6F77,/* 0xA0-0xA7 */ - 0x6F79,0x6F7B,0x6F7D,0x6F7E,0x6F7F,0x6F80,0x6F81,0x6F82,/* 0xA8-0xAF */ - 0x6F83,0x6F85,0x6F86,0x6F87,0x6F8A,0x6F8B,0x6F8F,0x6F90,/* 0xB0-0xB7 */ - 0x6F91,0x6F92,0x6F93,0x6F94,0x6F95,0x6F96,0x6F97,0x6F98,/* 0xB8-0xBF */ - 0x6F99,0x6F9A,0x6F9B,0x6F9D,0x6F9E,0x6F9F,0x6FA0,0x6FA2,/* 0xC0-0xC7 */ - 0x6FA3,0x6FA4,0x6FA5,0x6FA6,0x6FA8,0x6FA9,0x6FAA,0x6FAB,/* 0xC8-0xCF */ - 0x6FAC,0x6FAD,0x6FAE,0x6FAF,0x6FB0,0x6FB1,0x6FB2,0x6FB4,/* 0xD0-0xD7 */ - 0x6FB5,0x6FB7,0x6FB8,0x6FBA,0x6FBB,0x6FBC,0x6FBD,0x6FBE,/* 0xD8-0xDF */ - 0x6FBF,0x6FC1,0x6FC3,0x6FC4,0x6FC5,0x6FC6,0x6FC7,0x6FC8,/* 0xE0-0xE7 */ - 0x6FCA,0x6FCB,0x6FCC,0x6FCD,0x6FCE,0x6FCF,0x6FD0,0x6FD3,/* 0xE8-0xEF */ - 0x6FD4,0x6FD5,0x6FD6,0x6FD7,0x6FD8,0x6FD9,0x6FDA,0x6FDB,/* 0xF0-0xF7 */ - 0x6FDC,0x6FDD,0x6FDF,0x6FE2,0x6FE3,0x6FE4,0x6FE5,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_9E[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6FE6,0x6FE7,0x6FE8,0x6FE9,0x6FEA,0x6FEB,0x6FEC,0x6FED,/* 0x40-0x47 */ - 0x6FF0,0x6FF1,0x6FF2,0x6FF3,0x6FF4,0x6FF5,0x6FF6,0x6FF7,/* 0x48-0x4F */ - 0x6FF8,0x6FF9,0x6FFA,0x6FFB,0x6FFC,0x6FFD,0x6FFE,0x6FFF,/* 0x50-0x57 */ - 0x7000,0x7001,0x7002,0x7003,0x7004,0x7005,0x7006,0x7007,/* 0x58-0x5F */ - 0x7008,0x7009,0x700A,0x700B,0x700C,0x700D,0x700E,0x700F,/* 0x60-0x67 */ - 0x7010,0x7012,0x7013,0x7014,0x7015,0x7016,0x7017,0x7018,/* 0x68-0x6F */ - 0x7019,0x701C,0x701D,0x701E,0x701F,0x7020,0x7021,0x7022,/* 0x70-0x77 */ - 0x7024,0x7025,0x7026,0x7027,0x7028,0x7029,0x702A,0x0000,/* 0x78-0x7F */ - - 0x702B,0x702C,0x702D,0x702E,0x702F,0x7030,0x7031,0x7032,/* 0x80-0x87 */ - 0x7033,0x7034,0x7036,0x7037,0x7038,0x703A,0x703B,0x703C,/* 0x88-0x8F */ - 0x703D,0x703E,0x703F,0x7040,0x7041,0x7042,0x7043,0x7044,/* 0x90-0x97 */ - 0x7045,0x7046,0x7047,0x7048,0x7049,0x704A,0x704B,0x704D,/* 0x98-0x9F */ - 0x704E,0x7050,0x7051,0x7052,0x7053,0x7054,0x7055,0x7056,/* 0xA0-0xA7 */ - 0x7057,0x7058,0x7059,0x705A,0x705B,0x705C,0x705D,0x705F,/* 0xA8-0xAF */ - 0x7060,0x7061,0x7062,0x7063,0x7064,0x7065,0x7066,0x7067,/* 0xB0-0xB7 */ - 0x7068,0x7069,0x706A,0x706E,0x7071,0x7072,0x7073,0x7074,/* 0xB8-0xBF */ - 0x7077,0x7079,0x707A,0x707B,0x707D,0x7081,0x7082,0x7083,/* 0xC0-0xC7 */ - 0x7084,0x7086,0x7087,0x7088,0x708B,0x708C,0x708D,0x708F,/* 0xC8-0xCF */ - 0x7090,0x7091,0x7093,0x7097,0x7098,0x709A,0x709B,0x709E,/* 0xD0-0xD7 */ - 0x709F,0x70A0,0x70A1,0x70A2,0x70A3,0x70A4,0x70A5,0x70A6,/* 0xD8-0xDF */ - 0x70A7,0x70A8,0x70A9,0x70AA,0x70B0,0x70B2,0x70B4,0x70B5,/* 0xE0-0xE7 */ - 0x70B6,0x70BA,0x70BE,0x70BF,0x70C4,0x70C5,0x70C6,0x70C7,/* 0xE8-0xEF */ - 0x70C9,0x70CB,0x70CC,0x70CD,0x70CE,0x70CF,0x70D0,0x70D1,/* 0xF0-0xF7 */ - 0x70D2,0x70D3,0x70D4,0x70D5,0x70D6,0x70D7,0x70DA,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_9F[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x70DC,0x70DD,0x70DE,0x70E0,0x70E1,0x70E2,0x70E3,0x70E5,/* 0x40-0x47 */ - 0x70EA,0x70EE,0x70F0,0x70F1,0x70F2,0x70F3,0x70F4,0x70F5,/* 0x48-0x4F */ - 0x70F6,0x70F8,0x70FA,0x70FB,0x70FC,0x70FE,0x70FF,0x7100,/* 0x50-0x57 */ - 0x7101,0x7102,0x7103,0x7104,0x7105,0x7106,0x7107,0x7108,/* 0x58-0x5F */ - 0x710B,0x710C,0x710D,0x710E,0x710F,0x7111,0x7112,0x7114,/* 0x60-0x67 */ - 0x7117,0x711B,0x711C,0x711D,0x711E,0x711F,0x7120,0x7121,/* 0x68-0x6F */ - 0x7122,0x7123,0x7124,0x7125,0x7127,0x7128,0x7129,0x712A,/* 0x70-0x77 */ - 0x712B,0x712C,0x712D,0x712E,0x7132,0x7133,0x7134,0x0000,/* 0x78-0x7F */ - - 0x7135,0x7137,0x7138,0x7139,0x713A,0x713B,0x713C,0x713D,/* 0x80-0x87 */ - 0x713E,0x713F,0x7140,0x7141,0x7142,0x7143,0x7144,0x7146,/* 0x88-0x8F */ - 0x7147,0x7148,0x7149,0x714B,0x714D,0x714F,0x7150,0x7151,/* 0x90-0x97 */ - 0x7152,0x7153,0x7154,0x7155,0x7156,0x7157,0x7158,0x7159,/* 0x98-0x9F */ - 0x715A,0x715B,0x715D,0x715F,0x7160,0x7161,0x7162,0x7163,/* 0xA0-0xA7 */ - 0x7165,0x7169,0x716A,0x716B,0x716C,0x716D,0x716F,0x7170,/* 0xA8-0xAF */ - 0x7171,0x7174,0x7175,0x7176,0x7177,0x7179,0x717B,0x717C,/* 0xB0-0xB7 */ - 0x717E,0x717F,0x7180,0x7181,0x7182,0x7183,0x7185,0x7186,/* 0xB8-0xBF */ - 0x7187,0x7188,0x7189,0x718B,0x718C,0x718D,0x718E,0x7190,/* 0xC0-0xC7 */ - 0x7191,0x7192,0x7193,0x7195,0x7196,0x7197,0x719A,0x719B,/* 0xC8-0xCF */ - 0x719C,0x719D,0x719E,0x71A1,0x71A2,0x71A3,0x71A4,0x71A5,/* 0xD0-0xD7 */ - 0x71A6,0x71A7,0x71A9,0x71AA,0x71AB,0x71AD,0x71AE,0x71AF,/* 0xD8-0xDF */ - 0x71B0,0x71B1,0x71B2,0x71B4,0x71B6,0x71B7,0x71B8,0x71BA,/* 0xE0-0xE7 */ - 0x71BB,0x71BC,0x71BD,0x71BE,0x71BF,0x71C0,0x71C1,0x71C2,/* 0xE8-0xEF */ - 0x71C4,0x71C5,0x71C6,0x71C7,0x71C8,0x71C9,0x71CA,0x71CB,/* 0xF0-0xF7 */ - 0x71CC,0x71CD,0x71CF,0x71D0,0x71D1,0x71D2,0x71D3,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A0[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x71D6,0x71D7,0x71D8,0x71D9,0x71DA,0x71DB,0x71DC,0x71DD,/* 0x40-0x47 */ - 0x71DE,0x71DF,0x71E1,0x71E2,0x71E3,0x71E4,0x71E6,0x71E8,/* 0x48-0x4F */ - 0x71E9,0x71EA,0x71EB,0x71EC,0x71ED,0x71EF,0x71F0,0x71F1,/* 0x50-0x57 */ - 0x71F2,0x71F3,0x71F4,0x71F5,0x71F6,0x71F7,0x71F8,0x71FA,/* 0x58-0x5F */ - 0x71FB,0x71FC,0x71FD,0x71FE,0x71FF,0x7200,0x7201,0x7202,/* 0x60-0x67 */ - 0x7203,0x7204,0x7205,0x7207,0x7208,0x7209,0x720A,0x720B,/* 0x68-0x6F */ - 0x720C,0x720D,0x720E,0x720F,0x7210,0x7211,0x7212,0x7213,/* 0x70-0x77 */ - 0x7214,0x7215,0x7216,0x7217,0x7218,0x7219,0x721A,0x0000,/* 0x78-0x7F */ - - 0x721B,0x721C,0x721E,0x721F,0x7220,0x7221,0x7222,0x7223,/* 0x80-0x87 */ - 0x7224,0x7225,0x7226,0x7227,0x7229,0x722B,0x722D,0x722E,/* 0x88-0x8F */ - 0x722F,0x7232,0x7233,0x7234,0x723A,0x723C,0x723E,0x7240,/* 0x90-0x97 */ - 0x7241,0x7242,0x7243,0x7244,0x7245,0x7246,0x7249,0x724A,/* 0x98-0x9F */ - 0x724B,0x724E,0x724F,0x7250,0x7251,0x7253,0x7254,0x7255,/* 0xA0-0xA7 */ - 0x7257,0x7258,0x725A,0x725C,0x725E,0x7260,0x7263,0x7264,/* 0xA8-0xAF */ - 0x7265,0x7268,0x726A,0x726B,0x726C,0x726D,0x7270,0x7271,/* 0xB0-0xB7 */ - 0x7273,0x7274,0x7276,0x7277,0x7278,0x727B,0x727C,0x727D,/* 0xB8-0xBF */ - 0x7282,0x7283,0x7285,0x7286,0x7287,0x7288,0x7289,0x728C,/* 0xC0-0xC7 */ - 0x728E,0x7290,0x7291,0x7293,0x7294,0x7295,0x7296,0x7297,/* 0xC8-0xCF */ - 0x7298,0x7299,0x729A,0x729B,0x729C,0x729D,0x729E,0x72A0,/* 0xD0-0xD7 */ - 0x72A1,0x72A2,0x72A3,0x72A4,0x72A5,0x72A6,0x72A7,0x72A8,/* 0xD8-0xDF */ - 0x72A9,0x72AA,0x72AB,0x72AE,0x72B1,0x72B2,0x72B3,0x72B5,/* 0xE0-0xE7 */ - 0x72BA,0x72BB,0x72BC,0x72BD,0x72BE,0x72BF,0x72C0,0x72C5,/* 0xE8-0xEF */ - 0x72C6,0x72C7,0x72C9,0x72CA,0x72CB,0x72CC,0x72CF,0x72D1,/* 0xF0-0xF7 */ - 0x72D3,0x72D4,0x72D5,0x72D6,0x72D8,0x72DA,0x72DB,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x3000,0x3001,0x3002,0x00B7,0x02C9,0x02C7,0x00A8,/* 0xA0-0xA7 */ - 0x3003,0x3005,0x2014,0xFF5E,0x2016,0x2026,0x2018,0x2019,/* 0xA8-0xAF */ - 0x201C,0x201D,0x3014,0x3015,0x3008,0x3009,0x300A,0x300B,/* 0xB0-0xB7 */ - 0x300C,0x300D,0x300E,0x300F,0x3016,0x3017,0x3010,0x3011,/* 0xB8-0xBF */ - 0x00B1,0x00D7,0x00F7,0x2236,0x2227,0x2228,0x2211,0x220F,/* 0xC0-0xC7 */ - 0x222A,0x2229,0x2208,0x2237,0x221A,0x22A5,0x2225,0x2220,/* 0xC8-0xCF */ - 0x2312,0x2299,0x222B,0x222E,0x2261,0x224C,0x2248,0x223D,/* 0xD0-0xD7 */ - 0x221D,0x2260,0x226E,0x226F,0x2264,0x2265,0x221E,0x2235,/* 0xD8-0xDF */ - 0x2234,0x2642,0x2640,0x00B0,0x2032,0x2033,0x2103,0xFF04,/* 0xE0-0xE7 */ - 0x00A4,0xFFE0,0xFFE1,0x2030,0x00A7,0x2116,0x2606,0x2605,/* 0xE8-0xEF */ - 0x25CB,0x25CF,0x25CE,0x25C7,0x25C6,0x25A1,0x25A0,0x25B3,/* 0xF0-0xF7 */ - 0x25B2,0x203B,0x2192,0x2190,0x2191,0x2193,0x3013,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,/* 0xA0-0xA7 */ - 0x2177,0x2178,0x2179,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA8-0xAF */ - 0x0000,0x2488,0x2489,0x248A,0x248B,0x248C,0x248D,0x248E,/* 0xB0-0xB7 */ - 0x248F,0x2490,0x2491,0x2492,0x2493,0x2494,0x2495,0x2496,/* 0xB8-0xBF */ - 0x2497,0x2498,0x2499,0x249A,0x249B,0x2474,0x2475,0x2476,/* 0xC0-0xC7 */ - 0x2477,0x2478,0x2479,0x247A,0x247B,0x247C,0x247D,0x247E,/* 0xC8-0xCF */ - 0x247F,0x2480,0x2481,0x2482,0x2483,0x2484,0x2485,0x2486,/* 0xD0-0xD7 */ - 0x2487,0x2460,0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,/* 0xD8-0xDF */ - 0x2467,0x2468,0x2469,0x0000,0x0000,0x3220,0x3221,0x3222,/* 0xE0-0xE7 */ - 0x3223,0x3224,0x3225,0x3226,0x3227,0x3228,0x3229,0x0000,/* 0xE8-0xEF */ - 0x0000,0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,/* 0xF0-0xF7 */ - 0x2167,0x2168,0x2169,0x216A,0x216B,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0xFF01,0xFF02,0xFF03,0xFFE5,0xFF05,0xFF06,0xFF07,/* 0xA0-0xA7 */ - 0xFF08,0xFF09,0xFF0A,0xFF0B,0xFF0C,0xFF0D,0xFF0E,0xFF0F,/* 0xA8-0xAF */ - 0xFF10,0xFF11,0xFF12,0xFF13,0xFF14,0xFF15,0xFF16,0xFF17,/* 0xB0-0xB7 */ - 0xFF18,0xFF19,0xFF1A,0xFF1B,0xFF1C,0xFF1D,0xFF1E,0xFF1F,/* 0xB8-0xBF */ - 0xFF20,0xFF21,0xFF22,0xFF23,0xFF24,0xFF25,0xFF26,0xFF27,/* 0xC0-0xC7 */ - 0xFF28,0xFF29,0xFF2A,0xFF2B,0xFF2C,0xFF2D,0xFF2E,0xFF2F,/* 0xC8-0xCF */ - 0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,/* 0xD0-0xD7 */ - 0xFF38,0xFF39,0xFF3A,0xFF3B,0xFF3C,0xFF3D,0xFF3E,0xFF3F,/* 0xD8-0xDF */ - 0xFF40,0xFF41,0xFF42,0xFF43,0xFF44,0xFF45,0xFF46,0xFF47,/* 0xE0-0xE7 */ - 0xFF48,0xFF49,0xFF4A,0xFF4B,0xFF4C,0xFF4D,0xFF4E,0xFF4F,/* 0xE8-0xEF */ - 0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0xFF57,/* 0xF0-0xF7 */ - 0xFF58,0xFF59,0xFF5A,0xFF5B,0xFF5C,0xFF5D,0xFFE3,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x3041,0x3042,0x3043,0x3044,0x3045,0x3046,0x3047,/* 0xA0-0xA7 */ - 0x3048,0x3049,0x304A,0x304B,0x304C,0x304D,0x304E,0x304F,/* 0xA8-0xAF */ - 0x3050,0x3051,0x3052,0x3053,0x3054,0x3055,0x3056,0x3057,/* 0xB0-0xB7 */ - 0x3058,0x3059,0x305A,0x305B,0x305C,0x305D,0x305E,0x305F,/* 0xB8-0xBF */ - 0x3060,0x3061,0x3062,0x3063,0x3064,0x3065,0x3066,0x3067,/* 0xC0-0xC7 */ - 0x3068,0x3069,0x306A,0x306B,0x306C,0x306D,0x306E,0x306F,/* 0xC8-0xCF */ - 0x3070,0x3071,0x3072,0x3073,0x3074,0x3075,0x3076,0x3077,/* 0xD0-0xD7 */ - 0x3078,0x3079,0x307A,0x307B,0x307C,0x307D,0x307E,0x307F,/* 0xD8-0xDF */ - 0x3080,0x3081,0x3082,0x3083,0x3084,0x3085,0x3086,0x3087,/* 0xE0-0xE7 */ - 0x3088,0x3089,0x308A,0x308B,0x308C,0x308D,0x308E,0x308F,/* 0xE8-0xEF */ - 0x3090,0x3091,0x3092,0x3093,0x0000,0x0000,0x0000,0x0000,/* 0xF0-0xF7 */ -}; - -static const wchar_t c2u_A5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x30A1,0x30A2,0x30A3,0x30A4,0x30A5,0x30A6,0x30A7,/* 0xA0-0xA7 */ - 0x30A8,0x30A9,0x30AA,0x30AB,0x30AC,0x30AD,0x30AE,0x30AF,/* 0xA8-0xAF */ - 0x30B0,0x30B1,0x30B2,0x30B3,0x30B4,0x30B5,0x30B6,0x30B7,/* 0xB0-0xB7 */ - 0x30B8,0x30B9,0x30BA,0x30BB,0x30BC,0x30BD,0x30BE,0x30BF,/* 0xB8-0xBF */ - 0x30C0,0x30C1,0x30C2,0x30C3,0x30C4,0x30C5,0x30C6,0x30C7,/* 0xC0-0xC7 */ - 0x30C8,0x30C9,0x30CA,0x30CB,0x30CC,0x30CD,0x30CE,0x30CF,/* 0xC8-0xCF */ - 0x30D0,0x30D1,0x30D2,0x30D3,0x30D4,0x30D5,0x30D6,0x30D7,/* 0xD0-0xD7 */ - 0x30D8,0x30D9,0x30DA,0x30DB,0x30DC,0x30DD,0x30DE,0x30DF,/* 0xD8-0xDF */ - 0x30E0,0x30E1,0x30E2,0x30E3,0x30E4,0x30E5,0x30E6,0x30E7,/* 0xE0-0xE7 */ - 0x30E8,0x30E9,0x30EA,0x30EB,0x30EC,0x30ED,0x30EE,0x30EF,/* 0xE8-0xEF */ - 0x30F0,0x30F1,0x30F2,0x30F3,0x30F4,0x30F5,0x30F6,0x0000,/* 0xF0-0xF7 */ -}; - -static const wchar_t c2u_A6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,/* 0xA0-0xA7 */ - 0x0398,0x0399,0x039A,0x039B,0x039C,0x039D,0x039E,0x039F,/* 0xA8-0xAF */ - 0x03A0,0x03A1,0x03A3,0x03A4,0x03A5,0x03A6,0x03A7,0x03A8,/* 0xB0-0xB7 */ - 0x03A9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xB8-0xBF */ - 0x0000,0x03B1,0x03B2,0x03B3,0x03B4,0x03B5,0x03B6,0x03B7,/* 0xC0-0xC7 */ - 0x03B8,0x03B9,0x03BA,0x03BB,0x03BC,0x03BD,0x03BE,0x03BF,/* 0xC8-0xCF */ - 0x03C0,0x03C1,0x03C3,0x03C4,0x03C5,0x03C6,0x03C7,0x03C8,/* 0xD0-0xD7 */ - 0x03C9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xD8-0xDF */ - 0xFE35,0xFE36,0xFE39,0xFE3A,0xFE3F,0xFE40,0xFE3D,0xFE3E,/* 0xE0-0xE7 */ - 0xFE41,0xFE42,0xFE43,0xFE44,0x0000,0x0000,0xFE3B,0xFE3C,/* 0xE8-0xEF */ - 0xFE37,0xFE38,0xFE31,0x0000,0xFE33,0xFE34,0x0000,0x0000,/* 0xF0-0xF7 */ -}; - -static const wchar_t c2u_A7[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0401,/* 0xA0-0xA7 */ - 0x0416,0x0417,0x0418,0x0419,0x041A,0x041B,0x041C,0x041D,/* 0xA8-0xAF */ - 0x041E,0x041F,0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,/* 0xB0-0xB7 */ - 0x0426,0x0427,0x0428,0x0429,0x042A,0x042B,0x042C,0x042D,/* 0xB8-0xBF */ - 0x042E,0x042F,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xC0-0xC7 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xC8-0xCF */ - 0x0000,0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0451,/* 0xD0-0xD7 */ - 0x0436,0x0437,0x0438,0x0439,0x043A,0x043B,0x043C,0x043D,/* 0xD8-0xDF */ - 0x043E,0x043F,0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,/* 0xE0-0xE7 */ - 0x0446,0x0447,0x0448,0x0449,0x044A,0x044B,0x044C,0x044D,/* 0xE8-0xEF */ - 0x044E,0x044F,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xF0-0xF7 */ -}; - -static const wchar_t c2u_A8[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x02CA,0x02CB,0x02D9,0x2013,0x2015,0x2025,0x2035,0x2105,/* 0x40-0x47 */ - 0x2109,0x2196,0x2197,0x2198,0x2199,0x2215,0x221F,0x2223,/* 0x48-0x4F */ - 0x2252,0x2266,0x2267,0x22BF,0x2550,0x2551,0x2552,0x2553,/* 0x50-0x57 */ - 0x2554,0x2555,0x2556,0x2557,0x2558,0x2559,0x255A,0x255B,/* 0x58-0x5F */ - 0x255C,0x255D,0x255E,0x255F,0x2560,0x2561,0x2562,0x2563,/* 0x60-0x67 */ - 0x2564,0x2565,0x2566,0x2567,0x2568,0x2569,0x256A,0x256B,/* 0x68-0x6F */ - 0x256C,0x256D,0x256E,0x256F,0x2570,0x2571,0x2572,0x2573,/* 0x70-0x77 */ - 0x2581,0x2582,0x2583,0x2584,0x2585,0x2586,0x2587,0x0000,/* 0x78-0x7F */ - - 0x2588,0x2589,0x258A,0x258B,0x258C,0x258D,0x258E,0x258F,/* 0x80-0x87 */ - 0x2593,0x2594,0x2595,0x25BC,0x25BD,0x25E2,0x25E3,0x25E4,/* 0x88-0x8F */ - 0x25E5,0x2609,0x2295,0x3012,0x301D,0x301E,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x0101,0x00E1,0x01CE,0x00E0,0x0113,0x00E9,0x011B,/* 0xA0-0xA7 */ - 0x00E8,0x012B,0x00ED,0x01D0,0x00EC,0x014D,0x00F3,0x01D2,/* 0xA8-0xAF */ - 0x00F2,0x016B,0x00FA,0x01D4,0x00F9,0x01D6,0x01D8,0x01DA,/* 0xB0-0xB7 */ - 0x01DC,0x00FC,0x00EA,0x0251,0x0000,0x0144,0x0148,0x0000,/* 0xB8-0xBF */ - 0x0261,0x0000,0x0000,0x0000,0x0000,0x3105,0x3106,0x3107,/* 0xC0-0xC7 */ - 0x3108,0x3109,0x310A,0x310B,0x310C,0x310D,0x310E,0x310F,/* 0xC8-0xCF */ - 0x3110,0x3111,0x3112,0x3113,0x3114,0x3115,0x3116,0x3117,/* 0xD0-0xD7 */ - 0x3118,0x3119,0x311A,0x311B,0x311C,0x311D,0x311E,0x311F,/* 0xD8-0xDF */ - 0x3120,0x3121,0x3122,0x3123,0x3124,0x3125,0x3126,0x3127,/* 0xE0-0xE7 */ - 0x3128,0x3129,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xE8-0xEF */ -}; - -static const wchar_t c2u_A9[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x3021,0x3022,0x3023,0x3024,0x3025,0x3026,0x3027,0x3028,/* 0x40-0x47 */ - 0x3029,0x32A3,0x338E,0x338F,0x339C,0x339D,0x339E,0x33A1,/* 0x48-0x4F */ - 0x33C4,0x33CE,0x33D1,0x33D2,0x33D5,0xFE30,0xFFE2,0xFFE4,/* 0x50-0x57 */ - 0x0000,0x2121,0x3231,0x0000,0x2010,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x30FC,0x309B,0x309C,0x30FD,0x30FE,0x3006,0x309D,0x309E,/* 0x60-0x67 */ - 0xFE49,0xFE4A,0xFE4B,0xFE4C,0xFE4D,0xFE4E,0xFE4F,0xFE50,/* 0x68-0x6F */ - 0xFE51,0xFE52,0xFE54,0xFE55,0xFE56,0xFE57,0xFE59,0xFE5A,/* 0x70-0x77 */ - 0xFE5B,0xFE5C,0xFE5D,0xFE5E,0xFE5F,0xFE60,0xFE61,0x0000,/* 0x78-0x7F */ - - 0xFE62,0xFE63,0xFE64,0xFE65,0xFE66,0xFE68,0xFE69,0xFE6A,/* 0x80-0x87 */ - 0xFE6B,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x3007,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x0000,0x0000,0x0000,0x2500,0x2501,0x2502,0x2503,/* 0xA0-0xA7 */ - 0x2504,0x2505,0x2506,0x2507,0x2508,0x2509,0x250A,0x250B,/* 0xA8-0xAF */ - 0x250C,0x250D,0x250E,0x250F,0x2510,0x2511,0x2512,0x2513,/* 0xB0-0xB7 */ - 0x2514,0x2515,0x2516,0x2517,0x2518,0x2519,0x251A,0x251B,/* 0xB8-0xBF */ - 0x251C,0x251D,0x251E,0x251F,0x2520,0x2521,0x2522,0x2523,/* 0xC0-0xC7 */ - 0x2524,0x2525,0x2526,0x2527,0x2528,0x2529,0x252A,0x252B,/* 0xC8-0xCF */ - 0x252C,0x252D,0x252E,0x252F,0x2530,0x2531,0x2532,0x2533,/* 0xD0-0xD7 */ - 0x2534,0x2535,0x2536,0x2537,0x2538,0x2539,0x253A,0x253B,/* 0xD8-0xDF */ - 0x253C,0x253D,0x253E,0x253F,0x2540,0x2541,0x2542,0x2543,/* 0xE0-0xE7 */ - 0x2544,0x2545,0x2546,0x2547,0x2548,0x2549,0x254A,0x254B,/* 0xE8-0xEF */ -}; - -static const wchar_t c2u_AA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x72DC,0x72DD,0x72DF,0x72E2,0x72E3,0x72E4,0x72E5,0x72E6,/* 0x40-0x47 */ - 0x72E7,0x72EA,0x72EB,0x72F5,0x72F6,0x72F9,0x72FD,0x72FE,/* 0x48-0x4F */ - 0x72FF,0x7300,0x7302,0x7304,0x7305,0x7306,0x7307,0x7308,/* 0x50-0x57 */ - 0x7309,0x730B,0x730C,0x730D,0x730F,0x7310,0x7311,0x7312,/* 0x58-0x5F */ - 0x7314,0x7318,0x7319,0x731A,0x731F,0x7320,0x7323,0x7324,/* 0x60-0x67 */ - 0x7326,0x7327,0x7328,0x732D,0x732F,0x7330,0x7332,0x7333,/* 0x68-0x6F */ - 0x7335,0x7336,0x733A,0x733B,0x733C,0x733D,0x7340,0x7341,/* 0x70-0x77 */ - 0x7342,0x7343,0x7344,0x7345,0x7346,0x7347,0x7348,0x0000,/* 0x78-0x7F */ - - 0x7349,0x734A,0x734B,0x734C,0x734E,0x734F,0x7351,0x7353,/* 0x80-0x87 */ - 0x7354,0x7355,0x7356,0x7358,0x7359,0x735A,0x735B,0x735C,/* 0x88-0x8F */ - 0x735D,0x735E,0x735F,0x7361,0x7362,0x7363,0x7364,0x7365,/* 0x90-0x97 */ - 0x7366,0x7367,0x7368,0x7369,0x736A,0x736B,0x736E,0x7370,/* 0x98-0x9F */ - 0x7371,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ -}; - -static const wchar_t c2u_AB[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7372,0x7373,0x7374,0x7375,0x7376,0x7377,0x7378,0x7379,/* 0x40-0x47 */ - 0x737A,0x737B,0x737C,0x737D,0x737F,0x7380,0x7381,0x7382,/* 0x48-0x4F */ - 0x7383,0x7385,0x7386,0x7388,0x738A,0x738C,0x738D,0x738F,/* 0x50-0x57 */ - 0x7390,0x7392,0x7393,0x7394,0x7395,0x7397,0x7398,0x7399,/* 0x58-0x5F */ - 0x739A,0x739C,0x739D,0x739E,0x73A0,0x73A1,0x73A3,0x73A4,/* 0x60-0x67 */ - 0x73A5,0x73A6,0x73A7,0x73A8,0x73AA,0x73AC,0x73AD,0x73B1,/* 0x68-0x6F */ - 0x73B4,0x73B5,0x73B6,0x73B8,0x73B9,0x73BC,0x73BD,0x73BE,/* 0x70-0x77 */ - 0x73BF,0x73C1,0x73C3,0x73C4,0x73C5,0x73C6,0x73C7,0x0000,/* 0x78-0x7F */ - - 0x73CB,0x73CC,0x73CE,0x73D2,0x73D3,0x73D4,0x73D5,0x73D6,/* 0x80-0x87 */ - 0x73D7,0x73D8,0x73DA,0x73DB,0x73DC,0x73DD,0x73DF,0x73E1,/* 0x88-0x8F */ - 0x73E2,0x73E3,0x73E4,0x73E6,0x73E8,0x73EA,0x73EB,0x73EC,/* 0x90-0x97 */ - 0x73EE,0x73EF,0x73F0,0x73F1,0x73F3,0x73F4,0x73F5,0x73F6,/* 0x98-0x9F */ - 0x73F7,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ -}; - -static const wchar_t c2u_AC[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x73F8,0x73F9,0x73FA,0x73FB,0x73FC,0x73FD,0x73FE,0x73FF,/* 0x40-0x47 */ - 0x7400,0x7401,0x7402,0x7404,0x7407,0x7408,0x740B,0x740C,/* 0x48-0x4F */ - 0x740D,0x740E,0x7411,0x7412,0x7413,0x7414,0x7415,0x7416,/* 0x50-0x57 */ - 0x7417,0x7418,0x7419,0x741C,0x741D,0x741E,0x741F,0x7420,/* 0x58-0x5F */ - 0x7421,0x7423,0x7424,0x7427,0x7429,0x742B,0x742D,0x742F,/* 0x60-0x67 */ - 0x7431,0x7432,0x7437,0x7438,0x7439,0x743A,0x743B,0x743D,/* 0x68-0x6F */ - 0x743E,0x743F,0x7440,0x7442,0x7443,0x7444,0x7445,0x7446,/* 0x70-0x77 */ - 0x7447,0x7448,0x7449,0x744A,0x744B,0x744C,0x744D,0x0000,/* 0x78-0x7F */ - - 0x744E,0x744F,0x7450,0x7451,0x7452,0x7453,0x7454,0x7456,/* 0x80-0x87 */ - 0x7458,0x745D,0x7460,0x7461,0x7462,0x7463,0x7464,0x7465,/* 0x88-0x8F */ - 0x7466,0x7467,0x7468,0x7469,0x746A,0x746B,0x746C,0x746E,/* 0x90-0x97 */ - 0x746F,0x7471,0x7472,0x7473,0x7474,0x7475,0x7478,0x7479,/* 0x98-0x9F */ - 0x747A,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ -}; - -static const wchar_t c2u_AD[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x747B,0x747C,0x747D,0x747F,0x7482,0x7484,0x7485,0x7486,/* 0x40-0x47 */ - 0x7488,0x7489,0x748A,0x748C,0x748D,0x748F,0x7491,0x7492,/* 0x48-0x4F */ - 0x7493,0x7494,0x7495,0x7496,0x7497,0x7498,0x7499,0x749A,/* 0x50-0x57 */ - 0x749B,0x749D,0x749F,0x74A0,0x74A1,0x74A2,0x74A3,0x74A4,/* 0x58-0x5F */ - 0x74A5,0x74A6,0x74AA,0x74AB,0x74AC,0x74AD,0x74AE,0x74AF,/* 0x60-0x67 */ - 0x74B0,0x74B1,0x74B2,0x74B3,0x74B4,0x74B5,0x74B6,0x74B7,/* 0x68-0x6F */ - 0x74B8,0x74B9,0x74BB,0x74BC,0x74BD,0x74BE,0x74BF,0x74C0,/* 0x70-0x77 */ - 0x74C1,0x74C2,0x74C3,0x74C4,0x74C5,0x74C6,0x74C7,0x0000,/* 0x78-0x7F */ - - 0x74C8,0x74C9,0x74CA,0x74CB,0x74CC,0x74CD,0x74CE,0x74CF,/* 0x80-0x87 */ - 0x74D0,0x74D1,0x74D3,0x74D4,0x74D5,0x74D6,0x74D7,0x74D8,/* 0x88-0x8F */ - 0x74D9,0x74DA,0x74DB,0x74DD,0x74DF,0x74E1,0x74E5,0x74E7,/* 0x90-0x97 */ - 0x74E8,0x74E9,0x74EA,0x74EB,0x74EC,0x74ED,0x74F0,0x74F1,/* 0x98-0x9F */ - 0x74F2,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ -}; - -static const wchar_t c2u_AE[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x74F3,0x74F5,0x74F8,0x74F9,0x74FA,0x74FB,0x74FC,0x74FD,/* 0x40-0x47 */ - 0x74FE,0x7500,0x7501,0x7502,0x7503,0x7505,0x7506,0x7507,/* 0x48-0x4F */ - 0x7508,0x7509,0x750A,0x750B,0x750C,0x750E,0x7510,0x7512,/* 0x50-0x57 */ - 0x7514,0x7515,0x7516,0x7517,0x751B,0x751D,0x751E,0x7520,/* 0x58-0x5F */ - 0x7521,0x7522,0x7523,0x7524,0x7526,0x7527,0x752A,0x752E,/* 0x60-0x67 */ - 0x7534,0x7536,0x7539,0x753C,0x753D,0x753F,0x7541,0x7542,/* 0x68-0x6F */ - 0x7543,0x7544,0x7546,0x7547,0x7549,0x754A,0x754D,0x7550,/* 0x70-0x77 */ - 0x7551,0x7552,0x7553,0x7555,0x7556,0x7557,0x7558,0x0000,/* 0x78-0x7F */ - - 0x755D,0x755E,0x755F,0x7560,0x7561,0x7562,0x7563,0x7564,/* 0x80-0x87 */ - 0x7567,0x7568,0x7569,0x756B,0x756C,0x756D,0x756E,0x756F,/* 0x88-0x8F */ - 0x7570,0x7571,0x7573,0x7575,0x7576,0x7577,0x757A,0x757B,/* 0x90-0x97 */ - 0x757C,0x757D,0x757E,0x7580,0x7581,0x7582,0x7584,0x7585,/* 0x98-0x9F */ - 0x7587,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ -}; - -static const wchar_t c2u_AF[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7588,0x7589,0x758A,0x758C,0x758D,0x758E,0x7590,0x7593,/* 0x40-0x47 */ - 0x7595,0x7598,0x759B,0x759C,0x759E,0x75A2,0x75A6,0x75A7,/* 0x48-0x4F */ - 0x75A8,0x75A9,0x75AA,0x75AD,0x75B6,0x75B7,0x75BA,0x75BB,/* 0x50-0x57 */ - 0x75BF,0x75C0,0x75C1,0x75C6,0x75CB,0x75CC,0x75CE,0x75CF,/* 0x58-0x5F */ - 0x75D0,0x75D1,0x75D3,0x75D7,0x75D9,0x75DA,0x75DC,0x75DD,/* 0x60-0x67 */ - 0x75DF,0x75E0,0x75E1,0x75E5,0x75E9,0x75EC,0x75ED,0x75EE,/* 0x68-0x6F */ - 0x75EF,0x75F2,0x75F3,0x75F5,0x75F6,0x75F7,0x75F8,0x75FA,/* 0x70-0x77 */ - 0x75FB,0x75FD,0x75FE,0x7602,0x7604,0x7606,0x7607,0x0000,/* 0x78-0x7F */ - - 0x7608,0x7609,0x760B,0x760D,0x760E,0x760F,0x7611,0x7612,/* 0x80-0x87 */ - 0x7613,0x7614,0x7616,0x761A,0x761C,0x761D,0x761E,0x7621,/* 0x88-0x8F */ - 0x7623,0x7627,0x7628,0x762C,0x762E,0x762F,0x7631,0x7632,/* 0x90-0x97 */ - 0x7636,0x7637,0x7639,0x763A,0x763B,0x763D,0x7641,0x7642,/* 0x98-0x9F */ - 0x7644,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ -}; - -static const wchar_t c2u_B0[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7645,0x7646,0x7647,0x7648,0x7649,0x764A,0x764B,0x764E,/* 0x40-0x47 */ - 0x764F,0x7650,0x7651,0x7652,0x7653,0x7655,0x7657,0x7658,/* 0x48-0x4F */ - 0x7659,0x765A,0x765B,0x765D,0x765F,0x7660,0x7661,0x7662,/* 0x50-0x57 */ - 0x7664,0x7665,0x7666,0x7667,0x7668,0x7669,0x766A,0x766C,/* 0x58-0x5F */ - 0x766D,0x766E,0x7670,0x7671,0x7672,0x7673,0x7674,0x7675,/* 0x60-0x67 */ - 0x7676,0x7677,0x7679,0x767A,0x767C,0x767F,0x7680,0x7681,/* 0x68-0x6F */ - 0x7683,0x7685,0x7689,0x768A,0x768C,0x768D,0x768F,0x7690,/* 0x70-0x77 */ - 0x7692,0x7694,0x7695,0x7697,0x7698,0x769A,0x769B,0x0000,/* 0x78-0x7F */ - - 0x769C,0x769D,0x769E,0x769F,0x76A0,0x76A1,0x76A2,0x76A3,/* 0x80-0x87 */ - 0x76A5,0x76A6,0x76A7,0x76A8,0x76A9,0x76AA,0x76AB,0x76AC,/* 0x88-0x8F */ - 0x76AD,0x76AF,0x76B0,0x76B3,0x76B5,0x76B6,0x76B7,0x76B8,/* 0x90-0x97 */ - 0x76B9,0x76BA,0x76BB,0x76BC,0x76BD,0x76BE,0x76C0,0x76C1,/* 0x98-0x9F */ - 0x76C3,0x554A,0x963F,0x57C3,0x6328,0x54CE,0x5509,0x54C0,/* 0xA0-0xA7 */ - 0x7691,0x764C,0x853C,0x77EE,0x827E,0x788D,0x7231,0x9698,/* 0xA8-0xAF */ - 0x978D,0x6C28,0x5B89,0x4FFA,0x6309,0x6697,0x5CB8,0x80FA,/* 0xB0-0xB7 */ - 0x6848,0x80AE,0x6602,0x76CE,0x51F9,0x6556,0x71AC,0x7FF1,/* 0xB8-0xBF */ - 0x8884,0x50B2,0x5965,0x61CA,0x6FB3,0x82AD,0x634C,0x6252,/* 0xC0-0xC7 */ - 0x53ED,0x5427,0x7B06,0x516B,0x75A4,0x5DF4,0x62D4,0x8DCB,/* 0xC8-0xCF */ - 0x9776,0x628A,0x8019,0x575D,0x9738,0x7F62,0x7238,0x767D,/* 0xD0-0xD7 */ - 0x67CF,0x767E,0x6446,0x4F70,0x8D25,0x62DC,0x7A17,0x6591,/* 0xD8-0xDF */ - 0x73ED,0x642C,0x6273,0x822C,0x9881,0x677F,0x7248,0x626E,/* 0xE0-0xE7 */ - 0x62CC,0x4F34,0x74E3,0x534A,0x529E,0x7ECA,0x90A6,0x5E2E,/* 0xE8-0xEF */ - 0x6886,0x699C,0x8180,0x7ED1,0x68D2,0x78C5,0x868C,0x9551,/* 0xF0-0xF7 */ - 0x508D,0x8C24,0x82DE,0x80DE,0x5305,0x8912,0x5265,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x76C4,0x76C7,0x76C9,0x76CB,0x76CC,0x76D3,0x76D5,0x76D9,/* 0x40-0x47 */ - 0x76DA,0x76DC,0x76DD,0x76DE,0x76E0,0x76E1,0x76E2,0x76E3,/* 0x48-0x4F */ - 0x76E4,0x76E6,0x76E7,0x76E8,0x76E9,0x76EA,0x76EB,0x76EC,/* 0x50-0x57 */ - 0x76ED,0x76F0,0x76F3,0x76F5,0x76F6,0x76F7,0x76FA,0x76FB,/* 0x58-0x5F */ - 0x76FD,0x76FF,0x7700,0x7702,0x7703,0x7705,0x7706,0x770A,/* 0x60-0x67 */ - 0x770C,0x770E,0x770F,0x7710,0x7711,0x7712,0x7713,0x7714,/* 0x68-0x6F */ - 0x7715,0x7716,0x7717,0x7718,0x771B,0x771C,0x771D,0x771E,/* 0x70-0x77 */ - 0x7721,0x7723,0x7724,0x7725,0x7727,0x772A,0x772B,0x0000,/* 0x78-0x7F */ - - 0x772C,0x772E,0x7730,0x7731,0x7732,0x7733,0x7734,0x7739,/* 0x80-0x87 */ - 0x773B,0x773D,0x773E,0x773F,0x7742,0x7744,0x7745,0x7746,/* 0x88-0x8F */ - 0x7748,0x7749,0x774A,0x774B,0x774C,0x774D,0x774E,0x774F,/* 0x90-0x97 */ - 0x7752,0x7753,0x7754,0x7755,0x7756,0x7757,0x7758,0x7759,/* 0x98-0x9F */ - 0x775C,0x8584,0x96F9,0x4FDD,0x5821,0x9971,0x5B9D,0x62B1,/* 0xA0-0xA7 */ - 0x62A5,0x66B4,0x8C79,0x9C8D,0x7206,0x676F,0x7891,0x60B2,/* 0xA8-0xAF */ - 0x5351,0x5317,0x8F88,0x80CC,0x8D1D,0x94A1,0x500D,0x72C8,/* 0xB0-0xB7 */ - 0x5907,0x60EB,0x7119,0x88AB,0x5954,0x82EF,0x672C,0x7B28,/* 0xB8-0xBF */ - 0x5D29,0x7EF7,0x752D,0x6CF5,0x8E66,0x8FF8,0x903C,0x9F3B,/* 0xC0-0xC7 */ - 0x6BD4,0x9119,0x7B14,0x5F7C,0x78A7,0x84D6,0x853D,0x6BD5,/* 0xC8-0xCF */ - 0x6BD9,0x6BD6,0x5E01,0x5E87,0x75F9,0x95ED,0x655D,0x5F0A,/* 0xD0-0xD7 */ - 0x5FC5,0x8F9F,0x58C1,0x81C2,0x907F,0x965B,0x97AD,0x8FB9,/* 0xD8-0xDF */ - 0x7F16,0x8D2C,0x6241,0x4FBF,0x53D8,0x535E,0x8FA8,0x8FA9,/* 0xE0-0xE7 */ - 0x8FAB,0x904D,0x6807,0x5F6A,0x8198,0x8868,0x9CD6,0x618B,/* 0xE8-0xEF */ - 0x522B,0x762A,0x5F6C,0x658C,0x6FD2,0x6EE8,0x5BBE,0x6448,/* 0xF0-0xF7 */ - 0x5175,0x51B0,0x67C4,0x4E19,0x79C9,0x997C,0x70B3,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x775D,0x775E,0x775F,0x7760,0x7764,0x7767,0x7769,0x776A,/* 0x40-0x47 */ - 0x776D,0x776E,0x776F,0x7770,0x7771,0x7772,0x7773,0x7774,/* 0x48-0x4F */ - 0x7775,0x7776,0x7777,0x7778,0x777A,0x777B,0x777C,0x7781,/* 0x50-0x57 */ - 0x7782,0x7783,0x7786,0x7787,0x7788,0x7789,0x778A,0x778B,/* 0x58-0x5F */ - 0x778F,0x7790,0x7793,0x7794,0x7795,0x7796,0x7797,0x7798,/* 0x60-0x67 */ - 0x7799,0x779A,0x779B,0x779C,0x779D,0x779E,0x77A1,0x77A3,/* 0x68-0x6F */ - 0x77A4,0x77A6,0x77A8,0x77AB,0x77AD,0x77AE,0x77AF,0x77B1,/* 0x70-0x77 */ - 0x77B2,0x77B4,0x77B6,0x77B7,0x77B8,0x77B9,0x77BA,0x0000,/* 0x78-0x7F */ - - 0x77BC,0x77BE,0x77C0,0x77C1,0x77C2,0x77C3,0x77C4,0x77C5,/* 0x80-0x87 */ - 0x77C6,0x77C7,0x77C8,0x77C9,0x77CA,0x77CB,0x77CC,0x77CE,/* 0x88-0x8F */ - 0x77CF,0x77D0,0x77D1,0x77D2,0x77D3,0x77D4,0x77D5,0x77D6,/* 0x90-0x97 */ - 0x77D8,0x77D9,0x77DA,0x77DD,0x77DE,0x77DF,0x77E0,0x77E1,/* 0x98-0x9F */ - 0x77E4,0x75C5,0x5E76,0x73BB,0x83E0,0x64AD,0x62E8,0x94B5,/* 0xA0-0xA7 */ - 0x6CE2,0x535A,0x52C3,0x640F,0x94C2,0x7B94,0x4F2F,0x5E1B,/* 0xA8-0xAF */ - 0x8236,0x8116,0x818A,0x6E24,0x6CCA,0x9A73,0x6355,0x535C,/* 0xB0-0xB7 */ - 0x54FA,0x8865,0x57E0,0x4E0D,0x5E03,0x6B65,0x7C3F,0x90E8,/* 0xB8-0xBF */ - 0x6016,0x64E6,0x731C,0x88C1,0x6750,0x624D,0x8D22,0x776C,/* 0xC0-0xC7 */ - 0x8E29,0x91C7,0x5F69,0x83DC,0x8521,0x9910,0x53C2,0x8695,/* 0xC8-0xCF */ - 0x6B8B,0x60ED,0x60E8,0x707F,0x82CD,0x8231,0x4ED3,0x6CA7,/* 0xD0-0xD7 */ - 0x85CF,0x64CD,0x7CD9,0x69FD,0x66F9,0x8349,0x5395,0x7B56,/* 0xD8-0xDF */ - 0x4FA7,0x518C,0x6D4B,0x5C42,0x8E6D,0x63D2,0x53C9,0x832C,/* 0xE0-0xE7 */ - 0x8336,0x67E5,0x78B4,0x643D,0x5BDF,0x5C94,0x5DEE,0x8BE7,/* 0xE8-0xEF */ - 0x62C6,0x67F4,0x8C7A,0x6400,0x63BA,0x8749,0x998B,0x8C17,/* 0xF0-0xF7 */ - 0x7F20,0x94F2,0x4EA7,0x9610,0x98A4,0x660C,0x7316,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x77E6,0x77E8,0x77EA,0x77EF,0x77F0,0x77F1,0x77F2,0x77F4,/* 0x40-0x47 */ - 0x77F5,0x77F7,0x77F9,0x77FA,0x77FB,0x77FC,0x7803,0x7804,/* 0x48-0x4F */ - 0x7805,0x7806,0x7807,0x7808,0x780A,0x780B,0x780E,0x780F,/* 0x50-0x57 */ - 0x7810,0x7813,0x7815,0x7819,0x781B,0x781E,0x7820,0x7821,/* 0x58-0x5F */ - 0x7822,0x7824,0x7828,0x782A,0x782B,0x782E,0x782F,0x7831,/* 0x60-0x67 */ - 0x7832,0x7833,0x7835,0x7836,0x783D,0x783F,0x7841,0x7842,/* 0x68-0x6F */ - 0x7843,0x7844,0x7846,0x7848,0x7849,0x784A,0x784B,0x784D,/* 0x70-0x77 */ - 0x784F,0x7851,0x7853,0x7854,0x7858,0x7859,0x785A,0x0000,/* 0x78-0x7F */ - - 0x785B,0x785C,0x785E,0x785F,0x7860,0x7861,0x7862,0x7863,/* 0x80-0x87 */ - 0x7864,0x7865,0x7866,0x7867,0x7868,0x7869,0x786F,0x7870,/* 0x88-0x8F */ - 0x7871,0x7872,0x7873,0x7874,0x7875,0x7876,0x7878,0x7879,/* 0x90-0x97 */ - 0x787A,0x787B,0x787D,0x787E,0x787F,0x7880,0x7881,0x7882,/* 0x98-0x9F */ - 0x7883,0x573A,0x5C1D,0x5E38,0x957F,0x507F,0x80A0,0x5382,/* 0xA0-0xA7 */ - 0x655E,0x7545,0x5531,0x5021,0x8D85,0x6284,0x949E,0x671D,/* 0xA8-0xAF */ - 0x5632,0x6F6E,0x5DE2,0x5435,0x7092,0x8F66,0x626F,0x64A4,/* 0xB0-0xB7 */ - 0x63A3,0x5F7B,0x6F88,0x90F4,0x81E3,0x8FB0,0x5C18,0x6668,/* 0xB8-0xBF */ - 0x5FF1,0x6C89,0x9648,0x8D81,0x886C,0x6491,0x79F0,0x57CE,/* 0xC0-0xC7 */ - 0x6A59,0x6210,0x5448,0x4E58,0x7A0B,0x60E9,0x6F84,0x8BDA,/* 0xC8-0xCF */ - 0x627F,0x901E,0x9A8B,0x79E4,0x5403,0x75F4,0x6301,0x5319,/* 0xD0-0xD7 */ - 0x6C60,0x8FDF,0x5F1B,0x9A70,0x803B,0x9F7F,0x4F88,0x5C3A,/* 0xD8-0xDF */ - 0x8D64,0x7FC5,0x65A5,0x70BD,0x5145,0x51B2,0x866B,0x5D07,/* 0xE0-0xE7 */ - 0x5BA0,0x62BD,0x916C,0x7574,0x8E0C,0x7A20,0x6101,0x7B79,/* 0xE8-0xEF */ - 0x4EC7,0x7EF8,0x7785,0x4E11,0x81ED,0x521D,0x51FA,0x6A71,/* 0xF0-0xF7 */ - 0x53A8,0x8E87,0x9504,0x96CF,0x6EC1,0x9664,0x695A,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7884,0x7885,0x7886,0x7888,0x788A,0x788B,0x788F,0x7890,/* 0x40-0x47 */ - 0x7892,0x7894,0x7895,0x7896,0x7899,0x789D,0x789E,0x78A0,/* 0x48-0x4F */ - 0x78A2,0x78A4,0x78A6,0x78A8,0x78A9,0x78AA,0x78AB,0x78AC,/* 0x50-0x57 */ - 0x78AD,0x78AE,0x78AF,0x78B5,0x78B6,0x78B7,0x78B8,0x78BA,/* 0x58-0x5F */ - 0x78BB,0x78BC,0x78BD,0x78BF,0x78C0,0x78C2,0x78C3,0x78C4,/* 0x60-0x67 */ - 0x78C6,0x78C7,0x78C8,0x78CC,0x78CD,0x78CE,0x78CF,0x78D1,/* 0x68-0x6F */ - 0x78D2,0x78D3,0x78D6,0x78D7,0x78D8,0x78DA,0x78DB,0x78DC,/* 0x70-0x77 */ - 0x78DD,0x78DE,0x78DF,0x78E0,0x78E1,0x78E2,0x78E3,0x0000,/* 0x78-0x7F */ - - 0x78E4,0x78E5,0x78E6,0x78E7,0x78E9,0x78EA,0x78EB,0x78ED,/* 0x80-0x87 */ - 0x78EE,0x78EF,0x78F0,0x78F1,0x78F3,0x78F5,0x78F6,0x78F8,/* 0x88-0x8F */ - 0x78F9,0x78FB,0x78FC,0x78FD,0x78FE,0x78FF,0x7900,0x7902,/* 0x90-0x97 */ - 0x7903,0x7904,0x7906,0x7907,0x7908,0x7909,0x790A,0x790B,/* 0x98-0x9F */ - 0x790C,0x7840,0x50A8,0x77D7,0x6410,0x89E6,0x5904,0x63E3,/* 0xA0-0xA7 */ - 0x5DDD,0x7A7F,0x693D,0x4F20,0x8239,0x5598,0x4E32,0x75AE,/* 0xA8-0xAF */ - 0x7A97,0x5E62,0x5E8A,0x95EF,0x521B,0x5439,0x708A,0x6376,/* 0xB0-0xB7 */ - 0x9524,0x5782,0x6625,0x693F,0x9187,0x5507,0x6DF3,0x7EAF,/* 0xB8-0xBF */ - 0x8822,0x6233,0x7EF0,0x75B5,0x8328,0x78C1,0x96CC,0x8F9E,/* 0xC0-0xC7 */ - 0x6148,0x74F7,0x8BCD,0x6B64,0x523A,0x8D50,0x6B21,0x806A,/* 0xC8-0xCF */ - 0x8471,0x56F1,0x5306,0x4ECE,0x4E1B,0x51D1,0x7C97,0x918B,/* 0xD0-0xD7 */ - 0x7C07,0x4FC3,0x8E7F,0x7BE1,0x7A9C,0x6467,0x5D14,0x50AC,/* 0xD8-0xDF */ - 0x8106,0x7601,0x7CB9,0x6DEC,0x7FE0,0x6751,0x5B58,0x5BF8,/* 0xE0-0xE7 */ - 0x78CB,0x64AE,0x6413,0x63AA,0x632B,0x9519,0x642D,0x8FBE,/* 0xE8-0xEF */ - 0x7B54,0x7629,0x6253,0x5927,0x5446,0x6B79,0x50A3,0x6234,/* 0xF0-0xF7 */ - 0x5E26,0x6B86,0x4EE3,0x8D37,0x888B,0x5F85,0x902E,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x790D,0x790E,0x790F,0x7910,0x7911,0x7912,0x7914,0x7915,/* 0x40-0x47 */ - 0x7916,0x7917,0x7918,0x7919,0x791A,0x791B,0x791C,0x791D,/* 0x48-0x4F */ - 0x791F,0x7920,0x7921,0x7922,0x7923,0x7925,0x7926,0x7927,/* 0x50-0x57 */ - 0x7928,0x7929,0x792A,0x792B,0x792C,0x792D,0x792E,0x792F,/* 0x58-0x5F */ - 0x7930,0x7931,0x7932,0x7933,0x7935,0x7936,0x7937,0x7938,/* 0x60-0x67 */ - 0x7939,0x793D,0x793F,0x7942,0x7943,0x7944,0x7945,0x7947,/* 0x68-0x6F */ - 0x794A,0x794B,0x794C,0x794D,0x794E,0x794F,0x7950,0x7951,/* 0x70-0x77 */ - 0x7952,0x7954,0x7955,0x7958,0x7959,0x7961,0x7963,0x0000,/* 0x78-0x7F */ - - 0x7964,0x7966,0x7969,0x796A,0x796B,0x796C,0x796E,0x7970,/* 0x80-0x87 */ - 0x7971,0x7972,0x7973,0x7974,0x7975,0x7976,0x7979,0x797B,/* 0x88-0x8F */ - 0x797C,0x797D,0x797E,0x797F,0x7982,0x7983,0x7986,0x7987,/* 0x90-0x97 */ - 0x7988,0x7989,0x798B,0x798C,0x798D,0x798E,0x7990,0x7991,/* 0x98-0x9F */ - 0x7992,0x6020,0x803D,0x62C5,0x4E39,0x5355,0x90F8,0x63B8,/* 0xA0-0xA7 */ - 0x80C6,0x65E6,0x6C2E,0x4F46,0x60EE,0x6DE1,0x8BDE,0x5F39,/* 0xA8-0xAF */ - 0x86CB,0x5F53,0x6321,0x515A,0x8361,0x6863,0x5200,0x6363,/* 0xB0-0xB7 */ - 0x8E48,0x5012,0x5C9B,0x7977,0x5BFC,0x5230,0x7A3B,0x60BC,/* 0xB8-0xBF */ - 0x9053,0x76D7,0x5FB7,0x5F97,0x7684,0x8E6C,0x706F,0x767B,/* 0xC0-0xC7 */ - 0x7B49,0x77AA,0x51F3,0x9093,0x5824,0x4F4E,0x6EF4,0x8FEA,/* 0xC8-0xCF */ - 0x654C,0x7B1B,0x72C4,0x6DA4,0x7FDF,0x5AE1,0x62B5,0x5E95,/* 0xD0-0xD7 */ - 0x5730,0x8482,0x7B2C,0x5E1D,0x5F1F,0x9012,0x7F14,0x98A0,/* 0xD8-0xDF */ - 0x6382,0x6EC7,0x7898,0x70B9,0x5178,0x975B,0x57AB,0x7535,/* 0xE0-0xE7 */ - 0x4F43,0x7538,0x5E97,0x60E6,0x5960,0x6DC0,0x6BBF,0x7889,/* 0xE8-0xEF */ - 0x53FC,0x96D5,0x51CB,0x5201,0x6389,0x540A,0x9493,0x8C03,/* 0xF0-0xF7 */ - 0x8DCC,0x7239,0x789F,0x8776,0x8FED,0x8C0D,0x53E0,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7993,0x7994,0x7995,0x7996,0x7997,0x7998,0x7999,0x799B,/* 0x40-0x47 */ - 0x799C,0x799D,0x799E,0x799F,0x79A0,0x79A1,0x79A2,0x79A3,/* 0x48-0x4F */ - 0x79A4,0x79A5,0x79A6,0x79A8,0x79A9,0x79AA,0x79AB,0x79AC,/* 0x50-0x57 */ - 0x79AD,0x79AE,0x79AF,0x79B0,0x79B1,0x79B2,0x79B4,0x79B5,/* 0x58-0x5F */ - 0x79B6,0x79B7,0x79B8,0x79BC,0x79BF,0x79C2,0x79C4,0x79C5,/* 0x60-0x67 */ - 0x79C7,0x79C8,0x79CA,0x79CC,0x79CE,0x79CF,0x79D0,0x79D3,/* 0x68-0x6F */ - 0x79D4,0x79D6,0x79D7,0x79D9,0x79DA,0x79DB,0x79DC,0x79DD,/* 0x70-0x77 */ - 0x79DE,0x79E0,0x79E1,0x79E2,0x79E5,0x79E8,0x79EA,0x0000,/* 0x78-0x7F */ - - 0x79EC,0x79EE,0x79F1,0x79F2,0x79F3,0x79F4,0x79F5,0x79F6,/* 0x80-0x87 */ - 0x79F7,0x79F9,0x79FA,0x79FC,0x79FE,0x79FF,0x7A01,0x7A04,/* 0x88-0x8F */ - 0x7A05,0x7A07,0x7A08,0x7A09,0x7A0A,0x7A0C,0x7A0F,0x7A10,/* 0x90-0x97 */ - 0x7A11,0x7A12,0x7A13,0x7A15,0x7A16,0x7A18,0x7A19,0x7A1B,/* 0x98-0x9F */ - 0x7A1C,0x4E01,0x76EF,0x53EE,0x9489,0x9876,0x9F0E,0x952D,/* 0xA0-0xA7 */ - 0x5B9A,0x8BA2,0x4E22,0x4E1C,0x51AC,0x8463,0x61C2,0x52A8,/* 0xA8-0xAF */ - 0x680B,0x4F97,0x606B,0x51BB,0x6D1E,0x515C,0x6296,0x6597,/* 0xB0-0xB7 */ - 0x9661,0x8C46,0x9017,0x75D8,0x90FD,0x7763,0x6BD2,0x728A,/* 0xB8-0xBF */ - 0x72EC,0x8BFB,0x5835,0x7779,0x8D4C,0x675C,0x9540,0x809A,/* 0xC0-0xC7 */ - 0x5EA6,0x6E21,0x5992,0x7AEF,0x77ED,0x953B,0x6BB5,0x65AD,/* 0xC8-0xCF */ - 0x7F0E,0x5806,0x5151,0x961F,0x5BF9,0x58A9,0x5428,0x8E72,/* 0xD0-0xD7 */ - 0x6566,0x987F,0x56E4,0x949D,0x76FE,0x9041,0x6387,0x54C6,/* 0xD8-0xDF */ - 0x591A,0x593A,0x579B,0x8EB2,0x6735,0x8DFA,0x8235,0x5241,/* 0xE0-0xE7 */ - 0x60F0,0x5815,0x86FE,0x5CE8,0x9E45,0x4FC4,0x989D,0x8BB9,/* 0xE8-0xEF */ - 0x5A25,0x6076,0x5384,0x627C,0x904F,0x9102,0x997F,0x6069,/* 0xF0-0xF7 */ - 0x800C,0x513F,0x8033,0x5C14,0x9975,0x6D31,0x4E8C,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B7[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7A1D,0x7A1F,0x7A21,0x7A22,0x7A24,0x7A25,0x7A26,0x7A27,/* 0x40-0x47 */ - 0x7A28,0x7A29,0x7A2A,0x7A2B,0x7A2C,0x7A2D,0x7A2E,0x7A2F,/* 0x48-0x4F */ - 0x7A30,0x7A31,0x7A32,0x7A34,0x7A35,0x7A36,0x7A38,0x7A3A,/* 0x50-0x57 */ - 0x7A3E,0x7A40,0x7A41,0x7A42,0x7A43,0x7A44,0x7A45,0x7A47,/* 0x58-0x5F */ - 0x7A48,0x7A49,0x7A4A,0x7A4B,0x7A4C,0x7A4D,0x7A4E,0x7A4F,/* 0x60-0x67 */ - 0x7A50,0x7A52,0x7A53,0x7A54,0x7A55,0x7A56,0x7A58,0x7A59,/* 0x68-0x6F */ - 0x7A5A,0x7A5B,0x7A5C,0x7A5D,0x7A5E,0x7A5F,0x7A60,0x7A61,/* 0x70-0x77 */ - 0x7A62,0x7A63,0x7A64,0x7A65,0x7A66,0x7A67,0x7A68,0x0000,/* 0x78-0x7F */ - - 0x7A69,0x7A6A,0x7A6B,0x7A6C,0x7A6D,0x7A6E,0x7A6F,0x7A71,/* 0x80-0x87 */ - 0x7A72,0x7A73,0x7A75,0x7A7B,0x7A7C,0x7A7D,0x7A7E,0x7A82,/* 0x88-0x8F */ - 0x7A85,0x7A87,0x7A89,0x7A8A,0x7A8B,0x7A8C,0x7A8E,0x7A8F,/* 0x90-0x97 */ - 0x7A90,0x7A93,0x7A94,0x7A99,0x7A9A,0x7A9B,0x7A9E,0x7AA1,/* 0x98-0x9F */ - 0x7AA2,0x8D30,0x53D1,0x7F5A,0x7B4F,0x4F10,0x4E4F,0x9600,/* 0xA0-0xA7 */ - 0x6CD5,0x73D0,0x85E9,0x5E06,0x756A,0x7FFB,0x6A0A,0x77FE,/* 0xA8-0xAF */ - 0x9492,0x7E41,0x51E1,0x70E6,0x53CD,0x8FD4,0x8303,0x8D29,/* 0xB0-0xB7 */ - 0x72AF,0x996D,0x6CDB,0x574A,0x82B3,0x65B9,0x80AA,0x623F,/* 0xB8-0xBF */ - 0x9632,0x59A8,0x4EFF,0x8BBF,0x7EBA,0x653E,0x83F2,0x975E,/* 0xC0-0xC7 */ - 0x5561,0x98DE,0x80A5,0x532A,0x8BFD,0x5420,0x80BA,0x5E9F,/* 0xC8-0xCF */ - 0x6CB8,0x8D39,0x82AC,0x915A,0x5429,0x6C1B,0x5206,0x7EB7,/* 0xD0-0xD7 */ - 0x575F,0x711A,0x6C7E,0x7C89,0x594B,0x4EFD,0x5FFF,0x6124,/* 0xD8-0xDF */ - 0x7CAA,0x4E30,0x5C01,0x67AB,0x8702,0x5CF0,0x950B,0x98CE,/* 0xE0-0xE7 */ - 0x75AF,0x70FD,0x9022,0x51AF,0x7F1D,0x8BBD,0x5949,0x51E4,/* 0xE8-0xEF */ - 0x4F5B,0x5426,0x592B,0x6577,0x80A4,0x5B75,0x6276,0x62C2,/* 0xF0-0xF7 */ - 0x8F90,0x5E45,0x6C1F,0x7B26,0x4F0F,0x4FD8,0x670D,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B8[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7AA3,0x7AA4,0x7AA7,0x7AA9,0x7AAA,0x7AAB,0x7AAE,0x7AAF,/* 0x40-0x47 */ - 0x7AB0,0x7AB1,0x7AB2,0x7AB4,0x7AB5,0x7AB6,0x7AB7,0x7AB8,/* 0x48-0x4F */ - 0x7AB9,0x7ABA,0x7ABB,0x7ABC,0x7ABD,0x7ABE,0x7AC0,0x7AC1,/* 0x50-0x57 */ - 0x7AC2,0x7AC3,0x7AC4,0x7AC5,0x7AC6,0x7AC7,0x7AC8,0x7AC9,/* 0x58-0x5F */ - 0x7ACA,0x7ACC,0x7ACD,0x7ACE,0x7ACF,0x7AD0,0x7AD1,0x7AD2,/* 0x60-0x67 */ - 0x7AD3,0x7AD4,0x7AD5,0x7AD7,0x7AD8,0x7ADA,0x7ADB,0x7ADC,/* 0x68-0x6F */ - 0x7ADD,0x7AE1,0x7AE2,0x7AE4,0x7AE7,0x7AE8,0x7AE9,0x7AEA,/* 0x70-0x77 */ - 0x7AEB,0x7AEC,0x7AEE,0x7AF0,0x7AF1,0x7AF2,0x7AF3,0x0000,/* 0x78-0x7F */ - - 0x7AF4,0x7AF5,0x7AF6,0x7AF7,0x7AF8,0x7AFB,0x7AFC,0x7AFE,/* 0x80-0x87 */ - 0x7B00,0x7B01,0x7B02,0x7B05,0x7B07,0x7B09,0x7B0C,0x7B0D,/* 0x88-0x8F */ - 0x7B0E,0x7B10,0x7B12,0x7B13,0x7B16,0x7B17,0x7B18,0x7B1A,/* 0x90-0x97 */ - 0x7B1C,0x7B1D,0x7B1F,0x7B21,0x7B22,0x7B23,0x7B27,0x7B29,/* 0x98-0x9F */ - 0x7B2D,0x6D6E,0x6DAA,0x798F,0x88B1,0x5F17,0x752B,0x629A,/* 0xA0-0xA7 */ - 0x8F85,0x4FEF,0x91DC,0x65A7,0x812F,0x8151,0x5E9C,0x8150,/* 0xA8-0xAF */ - 0x8D74,0x526F,0x8986,0x8D4B,0x590D,0x5085,0x4ED8,0x961C,/* 0xB0-0xB7 */ - 0x7236,0x8179,0x8D1F,0x5BCC,0x8BA3,0x9644,0x5987,0x7F1A,/* 0xB8-0xBF */ - 0x5490,0x5676,0x560E,0x8BE5,0x6539,0x6982,0x9499,0x76D6,/* 0xC0-0xC7 */ - 0x6E89,0x5E72,0x7518,0x6746,0x67D1,0x7AFF,0x809D,0x8D76,/* 0xC8-0xCF */ - 0x611F,0x79C6,0x6562,0x8D63,0x5188,0x521A,0x94A2,0x7F38,/* 0xD0-0xD7 */ - 0x809B,0x7EB2,0x5C97,0x6E2F,0x6760,0x7BD9,0x768B,0x9AD8,/* 0xD8-0xDF */ - 0x818F,0x7F94,0x7CD5,0x641E,0x9550,0x7A3F,0x544A,0x54E5,/* 0xE0-0xE7 */ - 0x6B4C,0x6401,0x6208,0x9E3D,0x80F3,0x7599,0x5272,0x9769,/* 0xE8-0xEF */ - 0x845B,0x683C,0x86E4,0x9601,0x9694,0x94EC,0x4E2A,0x5404,/* 0xF0-0xF7 */ - 0x7ED9,0x6839,0x8DDF,0x8015,0x66F4,0x5E9A,0x7FB9,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B9[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7B2F,0x7B30,0x7B32,0x7B34,0x7B35,0x7B36,0x7B37,0x7B39,/* 0x40-0x47 */ - 0x7B3B,0x7B3D,0x7B3F,0x7B40,0x7B41,0x7B42,0x7B43,0x7B44,/* 0x48-0x4F */ - 0x7B46,0x7B48,0x7B4A,0x7B4D,0x7B4E,0x7B53,0x7B55,0x7B57,/* 0x50-0x57 */ - 0x7B59,0x7B5C,0x7B5E,0x7B5F,0x7B61,0x7B63,0x7B64,0x7B65,/* 0x58-0x5F */ - 0x7B66,0x7B67,0x7B68,0x7B69,0x7B6A,0x7B6B,0x7B6C,0x7B6D,/* 0x60-0x67 */ - 0x7B6F,0x7B70,0x7B73,0x7B74,0x7B76,0x7B78,0x7B7A,0x7B7C,/* 0x68-0x6F */ - 0x7B7D,0x7B7F,0x7B81,0x7B82,0x7B83,0x7B84,0x7B86,0x7B87,/* 0x70-0x77 */ - 0x7B88,0x7B89,0x7B8A,0x7B8B,0x7B8C,0x7B8E,0x7B8F,0x0000,/* 0x78-0x7F */ - - 0x7B91,0x7B92,0x7B93,0x7B96,0x7B98,0x7B99,0x7B9A,0x7B9B,/* 0x80-0x87 */ - 0x7B9E,0x7B9F,0x7BA0,0x7BA3,0x7BA4,0x7BA5,0x7BAE,0x7BAF,/* 0x88-0x8F */ - 0x7BB0,0x7BB2,0x7BB3,0x7BB5,0x7BB6,0x7BB7,0x7BB9,0x7BBA,/* 0x90-0x97 */ - 0x7BBB,0x7BBC,0x7BBD,0x7BBE,0x7BBF,0x7BC0,0x7BC2,0x7BC3,/* 0x98-0x9F */ - 0x7BC4,0x57C2,0x803F,0x6897,0x5DE5,0x653B,0x529F,0x606D,/* 0xA0-0xA7 */ - 0x9F9A,0x4F9B,0x8EAC,0x516C,0x5BAB,0x5F13,0x5DE9,0x6C5E,/* 0xA8-0xAF */ - 0x62F1,0x8D21,0x5171,0x94A9,0x52FE,0x6C9F,0x82DF,0x72D7,/* 0xB0-0xB7 */ - 0x57A2,0x6784,0x8D2D,0x591F,0x8F9C,0x83C7,0x5495,0x7B8D,/* 0xB8-0xBF */ - 0x4F30,0x6CBD,0x5B64,0x59D1,0x9F13,0x53E4,0x86CA,0x9AA8,/* 0xC0-0xC7 */ - 0x8C37,0x80A1,0x6545,0x987E,0x56FA,0x96C7,0x522E,0x74DC,/* 0xC8-0xCF */ - 0x5250,0x5BE1,0x6302,0x8902,0x4E56,0x62D0,0x602A,0x68FA,/* 0xD0-0xD7 */ - 0x5173,0x5B98,0x51A0,0x89C2,0x7BA1,0x9986,0x7F50,0x60EF,/* 0xD8-0xDF */ - 0x704C,0x8D2F,0x5149,0x5E7F,0x901B,0x7470,0x89C4,0x572D,/* 0xE0-0xE7 */ - 0x7845,0x5F52,0x9F9F,0x95FA,0x8F68,0x9B3C,0x8BE1,0x7678,/* 0xE8-0xEF */ - 0x6842,0x67DC,0x8DEA,0x8D35,0x523D,0x8F8A,0x6EDA,0x68CD,/* 0xF0-0xF7 */ - 0x9505,0x90ED,0x56FD,0x679C,0x88F9,0x8FC7,0x54C8,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_BA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7BC5,0x7BC8,0x7BC9,0x7BCA,0x7BCB,0x7BCD,0x7BCE,0x7BCF,/* 0x40-0x47 */ - 0x7BD0,0x7BD2,0x7BD4,0x7BD5,0x7BD6,0x7BD7,0x7BD8,0x7BDB,/* 0x48-0x4F */ - 0x7BDC,0x7BDE,0x7BDF,0x7BE0,0x7BE2,0x7BE3,0x7BE4,0x7BE7,/* 0x50-0x57 */ - 0x7BE8,0x7BE9,0x7BEB,0x7BEC,0x7BED,0x7BEF,0x7BF0,0x7BF2,/* 0x58-0x5F */ - 0x7BF3,0x7BF4,0x7BF5,0x7BF6,0x7BF8,0x7BF9,0x7BFA,0x7BFB,/* 0x60-0x67 */ - 0x7BFD,0x7BFF,0x7C00,0x7C01,0x7C02,0x7C03,0x7C04,0x7C05,/* 0x68-0x6F */ - 0x7C06,0x7C08,0x7C09,0x7C0A,0x7C0D,0x7C0E,0x7C10,0x7C11,/* 0x70-0x77 */ - 0x7C12,0x7C13,0x7C14,0x7C15,0x7C17,0x7C18,0x7C19,0x0000,/* 0x78-0x7F */ - - 0x7C1A,0x7C1B,0x7C1C,0x7C1D,0x7C1E,0x7C20,0x7C21,0x7C22,/* 0x80-0x87 */ - 0x7C23,0x7C24,0x7C25,0x7C28,0x7C29,0x7C2B,0x7C2C,0x7C2D,/* 0x88-0x8F */ - 0x7C2E,0x7C2F,0x7C30,0x7C31,0x7C32,0x7C33,0x7C34,0x7C35,/* 0x90-0x97 */ - 0x7C36,0x7C37,0x7C39,0x7C3A,0x7C3B,0x7C3C,0x7C3D,0x7C3E,/* 0x98-0x9F */ - 0x7C42,0x9AB8,0x5B69,0x6D77,0x6C26,0x4EA5,0x5BB3,0x9A87,/* 0xA0-0xA7 */ - 0x9163,0x61A8,0x90AF,0x97E9,0x542B,0x6DB5,0x5BD2,0x51FD,/* 0xA8-0xAF */ - 0x558A,0x7F55,0x7FF0,0x64BC,0x634D,0x65F1,0x61BE,0x608D,/* 0xB0-0xB7 */ - 0x710A,0x6C57,0x6C49,0x592F,0x676D,0x822A,0x58D5,0x568E,/* 0xB8-0xBF */ - 0x8C6A,0x6BEB,0x90DD,0x597D,0x8017,0x53F7,0x6D69,0x5475,/* 0xC0-0xC7 */ - 0x559D,0x8377,0x83CF,0x6838,0x79BE,0x548C,0x4F55,0x5408,/* 0xC8-0xCF */ - 0x76D2,0x8C89,0x9602,0x6CB3,0x6DB8,0x8D6B,0x8910,0x9E64,/* 0xD0-0xD7 */ - 0x8D3A,0x563F,0x9ED1,0x75D5,0x5F88,0x72E0,0x6068,0x54FC,/* 0xD8-0xDF */ - 0x4EA8,0x6A2A,0x8861,0x6052,0x8F70,0x54C4,0x70D8,0x8679,/* 0xE0-0xE7 */ - 0x9E3F,0x6D2A,0x5B8F,0x5F18,0x7EA2,0x5589,0x4FAF,0x7334,/* 0xE8-0xEF */ - 0x543C,0x539A,0x5019,0x540E,0x547C,0x4E4E,0x5FFD,0x745A,/* 0xF0-0xF7 */ - 0x58F6,0x846B,0x80E1,0x8774,0x72D0,0x7CCA,0x6E56,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_BB[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7C43,0x7C44,0x7C45,0x7C46,0x7C47,0x7C48,0x7C49,0x7C4A,/* 0x40-0x47 */ - 0x7C4B,0x7C4C,0x7C4E,0x7C4F,0x7C50,0x7C51,0x7C52,0x7C53,/* 0x48-0x4F */ - 0x7C54,0x7C55,0x7C56,0x7C57,0x7C58,0x7C59,0x7C5A,0x7C5B,/* 0x50-0x57 */ - 0x7C5C,0x7C5D,0x7C5E,0x7C5F,0x7C60,0x7C61,0x7C62,0x7C63,/* 0x58-0x5F */ - 0x7C64,0x7C65,0x7C66,0x7C67,0x7C68,0x7C69,0x7C6A,0x7C6B,/* 0x60-0x67 */ - 0x7C6C,0x7C6D,0x7C6E,0x7C6F,0x7C70,0x7C71,0x7C72,0x7C75,/* 0x68-0x6F */ - 0x7C76,0x7C77,0x7C78,0x7C79,0x7C7A,0x7C7E,0x7C7F,0x7C80,/* 0x70-0x77 */ - 0x7C81,0x7C82,0x7C83,0x7C84,0x7C85,0x7C86,0x7C87,0x0000,/* 0x78-0x7F */ - - 0x7C88,0x7C8A,0x7C8B,0x7C8C,0x7C8D,0x7C8E,0x7C8F,0x7C90,/* 0x80-0x87 */ - 0x7C93,0x7C94,0x7C96,0x7C99,0x7C9A,0x7C9B,0x7CA0,0x7CA1,/* 0x88-0x8F */ - 0x7CA3,0x7CA6,0x7CA7,0x7CA8,0x7CA9,0x7CAB,0x7CAC,0x7CAD,/* 0x90-0x97 */ - 0x7CAF,0x7CB0,0x7CB4,0x7CB5,0x7CB6,0x7CB7,0x7CB8,0x7CBA,/* 0x98-0x9F */ - 0x7CBB,0x5F27,0x864E,0x552C,0x62A4,0x4E92,0x6CAA,0x6237,/* 0xA0-0xA7 */ - 0x82B1,0x54D7,0x534E,0x733E,0x6ED1,0x753B,0x5212,0x5316,/* 0xA8-0xAF */ - 0x8BDD,0x69D0,0x5F8A,0x6000,0x6DEE,0x574F,0x6B22,0x73AF,/* 0xB0-0xB7 */ - 0x6853,0x8FD8,0x7F13,0x6362,0x60A3,0x5524,0x75EA,0x8C62,/* 0xB8-0xBF */ - 0x7115,0x6DA3,0x5BA6,0x5E7B,0x8352,0x614C,0x9EC4,0x78FA,/* 0xC0-0xC7 */ - 0x8757,0x7C27,0x7687,0x51F0,0x60F6,0x714C,0x6643,0x5E4C,/* 0xC8-0xCF */ - 0x604D,0x8C0E,0x7070,0x6325,0x8F89,0x5FBD,0x6062,0x86D4,/* 0xD0-0xD7 */ - 0x56DE,0x6BC1,0x6094,0x6167,0x5349,0x60E0,0x6666,0x8D3F,/* 0xD8-0xDF */ - 0x79FD,0x4F1A,0x70E9,0x6C47,0x8BB3,0x8BF2,0x7ED8,0x8364,/* 0xE0-0xE7 */ - 0x660F,0x5A5A,0x9B42,0x6D51,0x6DF7,0x8C41,0x6D3B,0x4F19,/* 0xE8-0xEF */ - 0x706B,0x83B7,0x6216,0x60D1,0x970D,0x8D27,0x7978,0x51FB,/* 0xF0-0xF7 */ - 0x573E,0x57FA,0x673A,0x7578,0x7A3D,0x79EF,0x7B95,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_BC[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7CBF,0x7CC0,0x7CC2,0x7CC3,0x7CC4,0x7CC6,0x7CC9,0x7CCB,/* 0x40-0x47 */ - 0x7CCE,0x7CCF,0x7CD0,0x7CD1,0x7CD2,0x7CD3,0x7CD4,0x7CD8,/* 0x48-0x4F */ - 0x7CDA,0x7CDB,0x7CDD,0x7CDE,0x7CE1,0x7CE2,0x7CE3,0x7CE4,/* 0x50-0x57 */ - 0x7CE5,0x7CE6,0x7CE7,0x7CE9,0x7CEA,0x7CEB,0x7CEC,0x7CED,/* 0x58-0x5F */ - 0x7CEE,0x7CF0,0x7CF1,0x7CF2,0x7CF3,0x7CF4,0x7CF5,0x7CF6,/* 0x60-0x67 */ - 0x7CF7,0x7CF9,0x7CFA,0x7CFC,0x7CFD,0x7CFE,0x7CFF,0x7D00,/* 0x68-0x6F */ - 0x7D01,0x7D02,0x7D03,0x7D04,0x7D05,0x7D06,0x7D07,0x7D08,/* 0x70-0x77 */ - 0x7D09,0x7D0B,0x7D0C,0x7D0D,0x7D0E,0x7D0F,0x7D10,0x0000,/* 0x78-0x7F */ - - 0x7D11,0x7D12,0x7D13,0x7D14,0x7D15,0x7D16,0x7D17,0x7D18,/* 0x80-0x87 */ - 0x7D19,0x7D1A,0x7D1B,0x7D1C,0x7D1D,0x7D1E,0x7D1F,0x7D21,/* 0x88-0x8F */ - 0x7D23,0x7D24,0x7D25,0x7D26,0x7D28,0x7D29,0x7D2A,0x7D2C,/* 0x90-0x97 */ - 0x7D2D,0x7D2E,0x7D30,0x7D31,0x7D32,0x7D33,0x7D34,0x7D35,/* 0x98-0x9F */ - 0x7D36,0x808C,0x9965,0x8FF9,0x6FC0,0x8BA5,0x9E21,0x59EC,/* 0xA0-0xA7 */ - 0x7EE9,0x7F09,0x5409,0x6781,0x68D8,0x8F91,0x7C4D,0x96C6,/* 0xA8-0xAF */ - 0x53CA,0x6025,0x75BE,0x6C72,0x5373,0x5AC9,0x7EA7,0x6324,/* 0xB0-0xB7 */ - 0x51E0,0x810A,0x5DF1,0x84DF,0x6280,0x5180,0x5B63,0x4F0E,/* 0xB8-0xBF */ - 0x796D,0x5242,0x60B8,0x6D4E,0x5BC4,0x5BC2,0x8BA1,0x8BB0,/* 0xC0-0xC7 */ - 0x65E2,0x5FCC,0x9645,0x5993,0x7EE7,0x7EAA,0x5609,0x67B7,/* 0xC8-0xCF */ - 0x5939,0x4F73,0x5BB6,0x52A0,0x835A,0x988A,0x8D3E,0x7532,/* 0xD0-0xD7 */ - 0x94BE,0x5047,0x7A3C,0x4EF7,0x67B6,0x9A7E,0x5AC1,0x6B7C,/* 0xD8-0xDF */ - 0x76D1,0x575A,0x5C16,0x7B3A,0x95F4,0x714E,0x517C,0x80A9,/* 0xE0-0xE7 */ - 0x8270,0x5978,0x7F04,0x8327,0x68C0,0x67EC,0x78B1,0x7877,/* 0xE8-0xEF */ - 0x62E3,0x6361,0x7B80,0x4FED,0x526A,0x51CF,0x8350,0x69DB,/* 0xF0-0xF7 */ - 0x9274,0x8DF5,0x8D31,0x89C1,0x952E,0x7BAD,0x4EF6,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_BD[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7D37,0x7D38,0x7D39,0x7D3A,0x7D3B,0x7D3C,0x7D3D,0x7D3E,/* 0x40-0x47 */ - 0x7D3F,0x7D40,0x7D41,0x7D42,0x7D43,0x7D44,0x7D45,0x7D46,/* 0x48-0x4F */ - 0x7D47,0x7D48,0x7D49,0x7D4A,0x7D4B,0x7D4C,0x7D4D,0x7D4E,/* 0x50-0x57 */ - 0x7D4F,0x7D50,0x7D51,0x7D52,0x7D53,0x7D54,0x7D55,0x7D56,/* 0x58-0x5F */ - 0x7D57,0x7D58,0x7D59,0x7D5A,0x7D5B,0x7D5C,0x7D5D,0x7D5E,/* 0x60-0x67 */ - 0x7D5F,0x7D60,0x7D61,0x7D62,0x7D63,0x7D64,0x7D65,0x7D66,/* 0x68-0x6F */ - 0x7D67,0x7D68,0x7D69,0x7D6A,0x7D6B,0x7D6C,0x7D6D,0x7D6F,/* 0x70-0x77 */ - 0x7D70,0x7D71,0x7D72,0x7D73,0x7D74,0x7D75,0x7D76,0x0000,/* 0x78-0x7F */ - - 0x7D78,0x7D79,0x7D7A,0x7D7B,0x7D7C,0x7D7D,0x7D7E,0x7D7F,/* 0x80-0x87 */ - 0x7D80,0x7D81,0x7D82,0x7D83,0x7D84,0x7D85,0x7D86,0x7D87,/* 0x88-0x8F */ - 0x7D88,0x7D89,0x7D8A,0x7D8B,0x7D8C,0x7D8D,0x7D8E,0x7D8F,/* 0x90-0x97 */ - 0x7D90,0x7D91,0x7D92,0x7D93,0x7D94,0x7D95,0x7D96,0x7D97,/* 0x98-0x9F */ - 0x7D98,0x5065,0x8230,0x5251,0x996F,0x6E10,0x6E85,0x6DA7,/* 0xA0-0xA7 */ - 0x5EFA,0x50F5,0x59DC,0x5C06,0x6D46,0x6C5F,0x7586,0x848B,/* 0xA8-0xAF */ - 0x6868,0x5956,0x8BB2,0x5320,0x9171,0x964D,0x8549,0x6912,/* 0xB0-0xB7 */ - 0x7901,0x7126,0x80F6,0x4EA4,0x90CA,0x6D47,0x9A84,0x5A07,/* 0xB8-0xBF */ - 0x56BC,0x6405,0x94F0,0x77EB,0x4FA5,0x811A,0x72E1,0x89D2,/* 0xC0-0xC7 */ - 0x997A,0x7F34,0x7EDE,0x527F,0x6559,0x9175,0x8F7F,0x8F83,/* 0xC8-0xCF */ - 0x53EB,0x7A96,0x63ED,0x63A5,0x7686,0x79F8,0x8857,0x9636,/* 0xD0-0xD7 */ - 0x622A,0x52AB,0x8282,0x6854,0x6770,0x6377,0x776B,0x7AED,/* 0xD8-0xDF */ - 0x6D01,0x7ED3,0x89E3,0x59D0,0x6212,0x85C9,0x82A5,0x754C,/* 0xE0-0xE7 */ - 0x501F,0x4ECB,0x75A5,0x8BEB,0x5C4A,0x5DFE,0x7B4B,0x65A4,/* 0xE8-0xEF */ - 0x91D1,0x4ECA,0x6D25,0x895F,0x7D27,0x9526,0x4EC5,0x8C28,/* 0xF0-0xF7 */ - 0x8FDB,0x9773,0x664B,0x7981,0x8FD1,0x70EC,0x6D78,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_BE[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7D99,0x7D9A,0x7D9B,0x7D9C,0x7D9D,0x7D9E,0x7D9F,0x7DA0,/* 0x40-0x47 */ - 0x7DA1,0x7DA2,0x7DA3,0x7DA4,0x7DA5,0x7DA7,0x7DA8,0x7DA9,/* 0x48-0x4F */ - 0x7DAA,0x7DAB,0x7DAC,0x7DAD,0x7DAF,0x7DB0,0x7DB1,0x7DB2,/* 0x50-0x57 */ - 0x7DB3,0x7DB4,0x7DB5,0x7DB6,0x7DB7,0x7DB8,0x7DB9,0x7DBA,/* 0x58-0x5F */ - 0x7DBB,0x7DBC,0x7DBD,0x7DBE,0x7DBF,0x7DC0,0x7DC1,0x7DC2,/* 0x60-0x67 */ - 0x7DC3,0x7DC4,0x7DC5,0x7DC6,0x7DC7,0x7DC8,0x7DC9,0x7DCA,/* 0x68-0x6F */ - 0x7DCB,0x7DCC,0x7DCD,0x7DCE,0x7DCF,0x7DD0,0x7DD1,0x7DD2,/* 0x70-0x77 */ - 0x7DD3,0x7DD4,0x7DD5,0x7DD6,0x7DD7,0x7DD8,0x7DD9,0x0000,/* 0x78-0x7F */ - - 0x7DDA,0x7DDB,0x7DDC,0x7DDD,0x7DDE,0x7DDF,0x7DE0,0x7DE1,/* 0x80-0x87 */ - 0x7DE2,0x7DE3,0x7DE4,0x7DE5,0x7DE6,0x7DE7,0x7DE8,0x7DE9,/* 0x88-0x8F */ - 0x7DEA,0x7DEB,0x7DEC,0x7DED,0x7DEE,0x7DEF,0x7DF0,0x7DF1,/* 0x90-0x97 */ - 0x7DF2,0x7DF3,0x7DF4,0x7DF5,0x7DF6,0x7DF7,0x7DF8,0x7DF9,/* 0x98-0x9F */ - 0x7DFA,0x5C3D,0x52B2,0x8346,0x5162,0x830E,0x775B,0x6676,/* 0xA0-0xA7 */ - 0x9CB8,0x4EAC,0x60CA,0x7CBE,0x7CB3,0x7ECF,0x4E95,0x8B66,/* 0xA8-0xAF */ - 0x666F,0x9888,0x9759,0x5883,0x656C,0x955C,0x5F84,0x75C9,/* 0xB0-0xB7 */ - 0x9756,0x7ADF,0x7ADE,0x51C0,0x70AF,0x7A98,0x63EA,0x7A76,/* 0xB8-0xBF */ - 0x7EA0,0x7396,0x97ED,0x4E45,0x7078,0x4E5D,0x9152,0x53A9,/* 0xC0-0xC7 */ - 0x6551,0x65E7,0x81FC,0x8205,0x548E,0x5C31,0x759A,0x97A0,/* 0xC8-0xCF */ - 0x62D8,0x72D9,0x75BD,0x5C45,0x9A79,0x83CA,0x5C40,0x5480,/* 0xD0-0xD7 */ - 0x77E9,0x4E3E,0x6CAE,0x805A,0x62D2,0x636E,0x5DE8,0x5177,/* 0xD8-0xDF */ - 0x8DDD,0x8E1E,0x952F,0x4FF1,0x53E5,0x60E7,0x70AC,0x5267,/* 0xE0-0xE7 */ - 0x6350,0x9E43,0x5A1F,0x5026,0x7737,0x5377,0x7EE2,0x6485,/* 0xE8-0xEF */ - 0x652B,0x6289,0x6398,0x5014,0x7235,0x89C9,0x51B3,0x8BC0,/* 0xF0-0xF7 */ - 0x7EDD,0x5747,0x83CC,0x94A7,0x519B,0x541B,0x5CFB,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_BF[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7DFB,0x7DFC,0x7DFD,0x7DFE,0x7DFF,0x7E00,0x7E01,0x7E02,/* 0x40-0x47 */ - 0x7E03,0x7E04,0x7E05,0x7E06,0x7E07,0x7E08,0x7E09,0x7E0A,/* 0x48-0x4F */ - 0x7E0B,0x7E0C,0x7E0D,0x7E0E,0x7E0F,0x7E10,0x7E11,0x7E12,/* 0x50-0x57 */ - 0x7E13,0x7E14,0x7E15,0x7E16,0x7E17,0x7E18,0x7E19,0x7E1A,/* 0x58-0x5F */ - 0x7E1B,0x7E1C,0x7E1D,0x7E1E,0x7E1F,0x7E20,0x7E21,0x7E22,/* 0x60-0x67 */ - 0x7E23,0x7E24,0x7E25,0x7E26,0x7E27,0x7E28,0x7E29,0x7E2A,/* 0x68-0x6F */ - 0x7E2B,0x7E2C,0x7E2D,0x7E2E,0x7E2F,0x7E30,0x7E31,0x7E32,/* 0x70-0x77 */ - 0x7E33,0x7E34,0x7E35,0x7E36,0x7E37,0x7E38,0x7E39,0x0000,/* 0x78-0x7F */ - - 0x7E3A,0x7E3C,0x7E3D,0x7E3E,0x7E3F,0x7E40,0x7E42,0x7E43,/* 0x80-0x87 */ - 0x7E44,0x7E45,0x7E46,0x7E48,0x7E49,0x7E4A,0x7E4B,0x7E4C,/* 0x88-0x8F */ - 0x7E4D,0x7E4E,0x7E4F,0x7E50,0x7E51,0x7E52,0x7E53,0x7E54,/* 0x90-0x97 */ - 0x7E55,0x7E56,0x7E57,0x7E58,0x7E59,0x7E5A,0x7E5B,0x7E5C,/* 0x98-0x9F */ - 0x7E5D,0x4FCA,0x7AE3,0x6D5A,0x90E1,0x9A8F,0x5580,0x5496,/* 0xA0-0xA7 */ - 0x5361,0x54AF,0x5F00,0x63E9,0x6977,0x51EF,0x6168,0x520A,/* 0xA8-0xAF */ - 0x582A,0x52D8,0x574E,0x780D,0x770B,0x5EB7,0x6177,0x7CE0,/* 0xB0-0xB7 */ - 0x625B,0x6297,0x4EA2,0x7095,0x8003,0x62F7,0x70E4,0x9760,/* 0xB8-0xBF */ - 0x5777,0x82DB,0x67EF,0x68F5,0x78D5,0x9897,0x79D1,0x58F3,/* 0xC0-0xC7 */ - 0x54B3,0x53EF,0x6E34,0x514B,0x523B,0x5BA2,0x8BFE,0x80AF,/* 0xC8-0xCF */ - 0x5543,0x57A6,0x6073,0x5751,0x542D,0x7A7A,0x6050,0x5B54,/* 0xD0-0xD7 */ - 0x63A7,0x62A0,0x53E3,0x6263,0x5BC7,0x67AF,0x54ED,0x7A9F,/* 0xD8-0xDF */ - 0x82E6,0x9177,0x5E93,0x88E4,0x5938,0x57AE,0x630E,0x8DE8,/* 0xE0-0xE7 */ - 0x80EF,0x5757,0x7B77,0x4FA9,0x5FEB,0x5BBD,0x6B3E,0x5321,/* 0xE8-0xEF */ - 0x7B50,0x72C2,0x6846,0x77FF,0x7736,0x65F7,0x51B5,0x4E8F,/* 0xF0-0xF7 */ - 0x76D4,0x5CBF,0x7AA5,0x8475,0x594E,0x9B41,0x5080,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C0[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7E5E,0x7E5F,0x7E60,0x7E61,0x7E62,0x7E63,0x7E64,0x7E65,/* 0x40-0x47 */ - 0x7E66,0x7E67,0x7E68,0x7E69,0x7E6A,0x7E6B,0x7E6C,0x7E6D,/* 0x48-0x4F */ - 0x7E6E,0x7E6F,0x7E70,0x7E71,0x7E72,0x7E73,0x7E74,0x7E75,/* 0x50-0x57 */ - 0x7E76,0x7E77,0x7E78,0x7E79,0x7E7A,0x7E7B,0x7E7C,0x7E7D,/* 0x58-0x5F */ - 0x7E7E,0x7E7F,0x7E80,0x7E81,0x7E83,0x7E84,0x7E85,0x7E86,/* 0x60-0x67 */ - 0x7E87,0x7E88,0x7E89,0x7E8A,0x7E8B,0x7E8C,0x7E8D,0x7E8E,/* 0x68-0x6F */ - 0x7E8F,0x7E90,0x7E91,0x7E92,0x7E93,0x7E94,0x7E95,0x7E96,/* 0x70-0x77 */ - 0x7E97,0x7E98,0x7E99,0x7E9A,0x7E9C,0x7E9D,0x7E9E,0x0000,/* 0x78-0x7F */ - - 0x7EAE,0x7EB4,0x7EBB,0x7EBC,0x7ED6,0x7EE4,0x7EEC,0x7EF9,/* 0x80-0x87 */ - 0x7F0A,0x7F10,0x7F1E,0x7F37,0x7F39,0x7F3B,0x7F3C,0x7F3D,/* 0x88-0x8F */ - 0x7F3E,0x7F3F,0x7F40,0x7F41,0x7F43,0x7F46,0x7F47,0x7F48,/* 0x90-0x97 */ - 0x7F49,0x7F4A,0x7F4B,0x7F4C,0x7F4D,0x7F4E,0x7F4F,0x7F52,/* 0x98-0x9F */ - 0x7F53,0x9988,0x6127,0x6E83,0x5764,0x6606,0x6346,0x56F0,/* 0xA0-0xA7 */ - 0x62EC,0x6269,0x5ED3,0x9614,0x5783,0x62C9,0x5587,0x8721,/* 0xA8-0xAF */ - 0x814A,0x8FA3,0x5566,0x83B1,0x6765,0x8D56,0x84DD,0x5A6A,/* 0xB0-0xB7 */ - 0x680F,0x62E6,0x7BEE,0x9611,0x5170,0x6F9C,0x8C30,0x63FD,/* 0xB8-0xBF */ - 0x89C8,0x61D2,0x7F06,0x70C2,0x6EE5,0x7405,0x6994,0x72FC,/* 0xC0-0xC7 */ - 0x5ECA,0x90CE,0x6717,0x6D6A,0x635E,0x52B3,0x7262,0x8001,/* 0xC8-0xCF */ - 0x4F6C,0x59E5,0x916A,0x70D9,0x6D9D,0x52D2,0x4E50,0x96F7,/* 0xD0-0xD7 */ - 0x956D,0x857E,0x78CA,0x7D2F,0x5121,0x5792,0x64C2,0x808B,/* 0xD8-0xDF */ - 0x7C7B,0x6CEA,0x68F1,0x695E,0x51B7,0x5398,0x68A8,0x7281,/* 0xE0-0xE7 */ - 0x9ECE,0x7BF1,0x72F8,0x79BB,0x6F13,0x7406,0x674E,0x91CC,/* 0xE8-0xEF */ - 0x9CA4,0x793C,0x8389,0x8354,0x540F,0x6817,0x4E3D,0x5389,/* 0xF0-0xF7 */ - 0x52B1,0x783E,0x5386,0x5229,0x5088,0x4F8B,0x4FD0,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7F56,0x7F59,0x7F5B,0x7F5C,0x7F5D,0x7F5E,0x7F60,0x7F63,/* 0x40-0x47 */ - 0x7F64,0x7F65,0x7F66,0x7F67,0x7F6B,0x7F6C,0x7F6D,0x7F6F,/* 0x48-0x4F */ - 0x7F70,0x7F73,0x7F75,0x7F76,0x7F77,0x7F78,0x7F7A,0x7F7B,/* 0x50-0x57 */ - 0x7F7C,0x7F7D,0x7F7F,0x7F80,0x7F82,0x7F83,0x7F84,0x7F85,/* 0x58-0x5F */ - 0x7F86,0x7F87,0x7F88,0x7F89,0x7F8B,0x7F8D,0x7F8F,0x7F90,/* 0x60-0x67 */ - 0x7F91,0x7F92,0x7F93,0x7F95,0x7F96,0x7F97,0x7F98,0x7F99,/* 0x68-0x6F */ - 0x7F9B,0x7F9C,0x7FA0,0x7FA2,0x7FA3,0x7FA5,0x7FA6,0x7FA8,/* 0x70-0x77 */ - 0x7FA9,0x7FAA,0x7FAB,0x7FAC,0x7FAD,0x7FAE,0x7FB1,0x0000,/* 0x78-0x7F */ - - 0x7FB3,0x7FB4,0x7FB5,0x7FB6,0x7FB7,0x7FBA,0x7FBB,0x7FBE,/* 0x80-0x87 */ - 0x7FC0,0x7FC2,0x7FC3,0x7FC4,0x7FC6,0x7FC7,0x7FC8,0x7FC9,/* 0x88-0x8F */ - 0x7FCB,0x7FCD,0x7FCF,0x7FD0,0x7FD1,0x7FD2,0x7FD3,0x7FD6,/* 0x90-0x97 */ - 0x7FD7,0x7FD9,0x7FDA,0x7FDB,0x7FDC,0x7FDD,0x7FDE,0x7FE2,/* 0x98-0x9F */ - 0x7FE3,0x75E2,0x7ACB,0x7C92,0x6CA5,0x96B6,0x529B,0x7483,/* 0xA0-0xA7 */ - 0x54E9,0x4FE9,0x8054,0x83B2,0x8FDE,0x9570,0x5EC9,0x601C,/* 0xA8-0xAF */ - 0x6D9F,0x5E18,0x655B,0x8138,0x94FE,0x604B,0x70BC,0x7EC3,/* 0xB0-0xB7 */ - 0x7CAE,0x51C9,0x6881,0x7CB1,0x826F,0x4E24,0x8F86,0x91CF,/* 0xB8-0xBF */ - 0x667E,0x4EAE,0x8C05,0x64A9,0x804A,0x50DA,0x7597,0x71CE,/* 0xC0-0xC7 */ - 0x5BE5,0x8FBD,0x6F66,0x4E86,0x6482,0x9563,0x5ED6,0x6599,/* 0xC8-0xCF */ - 0x5217,0x88C2,0x70C8,0x52A3,0x730E,0x7433,0x6797,0x78F7,/* 0xD0-0xD7 */ - 0x9716,0x4E34,0x90BB,0x9CDE,0x6DCB,0x51DB,0x8D41,0x541D,/* 0xD8-0xDF */ - 0x62CE,0x73B2,0x83F1,0x96F6,0x9F84,0x94C3,0x4F36,0x7F9A,/* 0xE0-0xE7 */ - 0x51CC,0x7075,0x9675,0x5CAD,0x9886,0x53E6,0x4EE4,0x6E9C,/* 0xE8-0xEF */ - 0x7409,0x69B4,0x786B,0x998F,0x7559,0x5218,0x7624,0x6D41,/* 0xF0-0xF7 */ - 0x67F3,0x516D,0x9F99,0x804B,0x5499,0x7B3C,0x7ABF,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7FE4,0x7FE7,0x7FE8,0x7FEA,0x7FEB,0x7FEC,0x7FED,0x7FEF,/* 0x40-0x47 */ - 0x7FF2,0x7FF4,0x7FF5,0x7FF6,0x7FF7,0x7FF8,0x7FF9,0x7FFA,/* 0x48-0x4F */ - 0x7FFD,0x7FFE,0x7FFF,0x8002,0x8007,0x8008,0x8009,0x800A,/* 0x50-0x57 */ - 0x800E,0x800F,0x8011,0x8013,0x801A,0x801B,0x801D,0x801E,/* 0x58-0x5F */ - 0x801F,0x8021,0x8023,0x8024,0x802B,0x802C,0x802D,0x802E,/* 0x60-0x67 */ - 0x802F,0x8030,0x8032,0x8034,0x8039,0x803A,0x803C,0x803E,/* 0x68-0x6F */ - 0x8040,0x8041,0x8044,0x8045,0x8047,0x8048,0x8049,0x804E,/* 0x70-0x77 */ - 0x804F,0x8050,0x8051,0x8053,0x8055,0x8056,0x8057,0x0000,/* 0x78-0x7F */ - - 0x8059,0x805B,0x805C,0x805D,0x805E,0x805F,0x8060,0x8061,/* 0x80-0x87 */ - 0x8062,0x8063,0x8064,0x8065,0x8066,0x8067,0x8068,0x806B,/* 0x88-0x8F */ - 0x806C,0x806D,0x806E,0x806F,0x8070,0x8072,0x8073,0x8074,/* 0x90-0x97 */ - 0x8075,0x8076,0x8077,0x8078,0x8079,0x807A,0x807B,0x807C,/* 0x98-0x9F */ - 0x807D,0x9686,0x5784,0x62E2,0x9647,0x697C,0x5A04,0x6402,/* 0xA0-0xA7 */ - 0x7BD3,0x6F0F,0x964B,0x82A6,0x5362,0x9885,0x5E90,0x7089,/* 0xA8-0xAF */ - 0x63B3,0x5364,0x864F,0x9C81,0x9E93,0x788C,0x9732,0x8DEF,/* 0xB0-0xB7 */ - 0x8D42,0x9E7F,0x6F5E,0x7984,0x5F55,0x9646,0x622E,0x9A74,/* 0xB8-0xBF */ - 0x5415,0x94DD,0x4FA3,0x65C5,0x5C65,0x5C61,0x7F15,0x8651,/* 0xC0-0xC7 */ - 0x6C2F,0x5F8B,0x7387,0x6EE4,0x7EFF,0x5CE6,0x631B,0x5B6A,/* 0xC8-0xCF */ - 0x6EE6,0x5375,0x4E71,0x63A0,0x7565,0x62A1,0x8F6E,0x4F26,/* 0xD0-0xD7 */ - 0x4ED1,0x6CA6,0x7EB6,0x8BBA,0x841D,0x87BA,0x7F57,0x903B,/* 0xD8-0xDF */ - 0x9523,0x7BA9,0x9AA1,0x88F8,0x843D,0x6D1B,0x9A86,0x7EDC,/* 0xE0-0xE7 */ - 0x5988,0x9EBB,0x739B,0x7801,0x8682,0x9A6C,0x9A82,0x561B,/* 0xE8-0xEF */ - 0x5417,0x57CB,0x4E70,0x9EA6,0x5356,0x8FC8,0x8109,0x7792,/* 0xF0-0xF7 */ - 0x9992,0x86EE,0x6EE1,0x8513,0x66FC,0x6162,0x6F2B,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x807E,0x8081,0x8082,0x8085,0x8088,0x808A,0x808D,0x808E,/* 0x40-0x47 */ - 0x808F,0x8090,0x8091,0x8092,0x8094,0x8095,0x8097,0x8099,/* 0x48-0x4F */ - 0x809E,0x80A3,0x80A6,0x80A7,0x80A8,0x80AC,0x80B0,0x80B3,/* 0x50-0x57 */ - 0x80B5,0x80B6,0x80B8,0x80B9,0x80BB,0x80C5,0x80C7,0x80C8,/* 0x58-0x5F */ - 0x80C9,0x80CA,0x80CB,0x80CF,0x80D0,0x80D1,0x80D2,0x80D3,/* 0x60-0x67 */ - 0x80D4,0x80D5,0x80D8,0x80DF,0x80E0,0x80E2,0x80E3,0x80E6,/* 0x68-0x6F */ - 0x80EE,0x80F5,0x80F7,0x80F9,0x80FB,0x80FE,0x80FF,0x8100,/* 0x70-0x77 */ - 0x8101,0x8103,0x8104,0x8105,0x8107,0x8108,0x810B,0x0000,/* 0x78-0x7F */ - - 0x810C,0x8115,0x8117,0x8119,0x811B,0x811C,0x811D,0x811F,/* 0x80-0x87 */ - 0x8120,0x8121,0x8122,0x8123,0x8124,0x8125,0x8126,0x8127,/* 0x88-0x8F */ - 0x8128,0x8129,0x812A,0x812B,0x812D,0x812E,0x8130,0x8133,/* 0x90-0x97 */ - 0x8134,0x8135,0x8137,0x8139,0x813A,0x813B,0x813C,0x813D,/* 0x98-0x9F */ - 0x813F,0x8C29,0x8292,0x832B,0x76F2,0x6C13,0x5FD9,0x83BD,/* 0xA0-0xA7 */ - 0x732B,0x8305,0x951A,0x6BDB,0x77DB,0x94C6,0x536F,0x8302,/* 0xA8-0xAF */ - 0x5192,0x5E3D,0x8C8C,0x8D38,0x4E48,0x73AB,0x679A,0x6885,/* 0xB0-0xB7 */ - 0x9176,0x9709,0x7164,0x6CA1,0x7709,0x5A92,0x9541,0x6BCF,/* 0xB8-0xBF */ - 0x7F8E,0x6627,0x5BD0,0x59B9,0x5A9A,0x95E8,0x95F7,0x4EEC,/* 0xC0-0xC7 */ - 0x840C,0x8499,0x6AAC,0x76DF,0x9530,0x731B,0x68A6,0x5B5F,/* 0xC8-0xCF */ - 0x772F,0x919A,0x9761,0x7CDC,0x8FF7,0x8C1C,0x5F25,0x7C73,/* 0xD0-0xD7 */ - 0x79D8,0x89C5,0x6CCC,0x871C,0x5BC6,0x5E42,0x68C9,0x7720,/* 0xD8-0xDF */ - 0x7EF5,0x5195,0x514D,0x52C9,0x5A29,0x7F05,0x9762,0x82D7,/* 0xE0-0xE7 */ - 0x63CF,0x7784,0x85D0,0x79D2,0x6E3A,0x5E99,0x5999,0x8511,/* 0xE8-0xEF */ - 0x706D,0x6C11,0x62BF,0x76BF,0x654F,0x60AF,0x95FD,0x660E,/* 0xF0-0xF7 */ - 0x879F,0x9E23,0x94ED,0x540D,0x547D,0x8C2C,0x6478,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8140,0x8141,0x8142,0x8143,0x8144,0x8145,0x8147,0x8149,/* 0x40-0x47 */ - 0x814D,0x814E,0x814F,0x8152,0x8156,0x8157,0x8158,0x815B,/* 0x48-0x4F */ - 0x815C,0x815D,0x815E,0x815F,0x8161,0x8162,0x8163,0x8164,/* 0x50-0x57 */ - 0x8166,0x8168,0x816A,0x816B,0x816C,0x816F,0x8172,0x8173,/* 0x58-0x5F */ - 0x8175,0x8176,0x8177,0x8178,0x8181,0x8183,0x8184,0x8185,/* 0x60-0x67 */ - 0x8186,0x8187,0x8189,0x818B,0x818C,0x818D,0x818E,0x8190,/* 0x68-0x6F */ - 0x8192,0x8193,0x8194,0x8195,0x8196,0x8197,0x8199,0x819A,/* 0x70-0x77 */ - 0x819E,0x819F,0x81A0,0x81A1,0x81A2,0x81A4,0x81A5,0x0000,/* 0x78-0x7F */ - - 0x81A7,0x81A9,0x81AB,0x81AC,0x81AD,0x81AE,0x81AF,0x81B0,/* 0x80-0x87 */ - 0x81B1,0x81B2,0x81B4,0x81B5,0x81B6,0x81B7,0x81B8,0x81B9,/* 0x88-0x8F */ - 0x81BC,0x81BD,0x81BE,0x81BF,0x81C4,0x81C5,0x81C7,0x81C8,/* 0x90-0x97 */ - 0x81C9,0x81CB,0x81CD,0x81CE,0x81CF,0x81D0,0x81D1,0x81D2,/* 0x98-0x9F */ - 0x81D3,0x6479,0x8611,0x6A21,0x819C,0x78E8,0x6469,0x9B54,/* 0xA0-0xA7 */ - 0x62B9,0x672B,0x83AB,0x58A8,0x9ED8,0x6CAB,0x6F20,0x5BDE,/* 0xA8-0xAF */ - 0x964C,0x8C0B,0x725F,0x67D0,0x62C7,0x7261,0x4EA9,0x59C6,/* 0xB0-0xB7 */ - 0x6BCD,0x5893,0x66AE,0x5E55,0x52DF,0x6155,0x6728,0x76EE,/* 0xB8-0xBF */ - 0x7766,0x7267,0x7A46,0x62FF,0x54EA,0x5450,0x94A0,0x90A3,/* 0xC0-0xC7 */ - 0x5A1C,0x7EB3,0x6C16,0x4E43,0x5976,0x8010,0x5948,0x5357,/* 0xC8-0xCF */ - 0x7537,0x96BE,0x56CA,0x6320,0x8111,0x607C,0x95F9,0x6DD6,/* 0xD0-0xD7 */ - 0x5462,0x9981,0x5185,0x5AE9,0x80FD,0x59AE,0x9713,0x502A,/* 0xD8-0xDF */ - 0x6CE5,0x5C3C,0x62DF,0x4F60,0x533F,0x817B,0x9006,0x6EBA,/* 0xE0-0xE7 */ - 0x852B,0x62C8,0x5E74,0x78BE,0x64B5,0x637B,0x5FF5,0x5A18,/* 0xE8-0xEF */ - 0x917F,0x9E1F,0x5C3F,0x634F,0x8042,0x5B7D,0x556E,0x954A,/* 0xF0-0xF7 */ - 0x954D,0x6D85,0x60A8,0x67E0,0x72DE,0x51DD,0x5B81,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x81D4,0x81D5,0x81D6,0x81D7,0x81D8,0x81D9,0x81DA,0x81DB,/* 0x40-0x47 */ - 0x81DC,0x81DD,0x81DE,0x81DF,0x81E0,0x81E1,0x81E2,0x81E4,/* 0x48-0x4F */ - 0x81E5,0x81E6,0x81E8,0x81E9,0x81EB,0x81EE,0x81EF,0x81F0,/* 0x50-0x57 */ - 0x81F1,0x81F2,0x81F5,0x81F6,0x81F7,0x81F8,0x81F9,0x81FA,/* 0x58-0x5F */ - 0x81FD,0x81FF,0x8203,0x8207,0x8208,0x8209,0x820A,0x820B,/* 0x60-0x67 */ - 0x820E,0x820F,0x8211,0x8213,0x8215,0x8216,0x8217,0x8218,/* 0x68-0x6F */ - 0x8219,0x821A,0x821D,0x8220,0x8224,0x8225,0x8226,0x8227,/* 0x70-0x77 */ - 0x8229,0x822E,0x8232,0x823A,0x823C,0x823D,0x823F,0x0000,/* 0x78-0x7F */ - - 0x8240,0x8241,0x8242,0x8243,0x8245,0x8246,0x8248,0x824A,/* 0x80-0x87 */ - 0x824C,0x824D,0x824E,0x8250,0x8251,0x8252,0x8253,0x8254,/* 0x88-0x8F */ - 0x8255,0x8256,0x8257,0x8259,0x825B,0x825C,0x825D,0x825E,/* 0x90-0x97 */ - 0x8260,0x8261,0x8262,0x8263,0x8264,0x8265,0x8266,0x8267,/* 0x98-0x9F */ - 0x8269,0x62E7,0x6CDE,0x725B,0x626D,0x94AE,0x7EBD,0x8113,/* 0xA0-0xA7 */ - 0x6D53,0x519C,0x5F04,0x5974,0x52AA,0x6012,0x5973,0x6696,/* 0xA8-0xAF */ - 0x8650,0x759F,0x632A,0x61E6,0x7CEF,0x8BFA,0x54E6,0x6B27,/* 0xB0-0xB7 */ - 0x9E25,0x6BB4,0x85D5,0x5455,0x5076,0x6CA4,0x556A,0x8DB4,/* 0xB8-0xBF */ - 0x722C,0x5E15,0x6015,0x7436,0x62CD,0x6392,0x724C,0x5F98,/* 0xC0-0xC7 */ - 0x6E43,0x6D3E,0x6500,0x6F58,0x76D8,0x78D0,0x76FC,0x7554,/* 0xC8-0xCF */ - 0x5224,0x53DB,0x4E53,0x5E9E,0x65C1,0x802A,0x80D6,0x629B,/* 0xD0-0xD7 */ - 0x5486,0x5228,0x70AE,0x888D,0x8DD1,0x6CE1,0x5478,0x80DA,/* 0xD8-0xDF */ - 0x57F9,0x88F4,0x8D54,0x966A,0x914D,0x4F69,0x6C9B,0x55B7,/* 0xE0-0xE7 */ - 0x76C6,0x7830,0x62A8,0x70F9,0x6F8E,0x5F6D,0x84EC,0x68DA,/* 0xE8-0xEF */ - 0x787C,0x7BF7,0x81A8,0x670B,0x9E4F,0x6367,0x78B0,0x576F,/* 0xF0-0xF7 */ - 0x7812,0x9739,0x6279,0x62AB,0x5288,0x7435,0x6BD7,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x826A,0x826B,0x826C,0x826D,0x8271,0x8275,0x8276,0x8277,/* 0x40-0x47 */ - 0x8278,0x827B,0x827C,0x8280,0x8281,0x8283,0x8285,0x8286,/* 0x48-0x4F */ - 0x8287,0x8289,0x828C,0x8290,0x8293,0x8294,0x8295,0x8296,/* 0x50-0x57 */ - 0x829A,0x829B,0x829E,0x82A0,0x82A2,0x82A3,0x82A7,0x82B2,/* 0x58-0x5F */ - 0x82B5,0x82B6,0x82BA,0x82BB,0x82BC,0x82BF,0x82C0,0x82C2,/* 0x60-0x67 */ - 0x82C3,0x82C5,0x82C6,0x82C9,0x82D0,0x82D6,0x82D9,0x82DA,/* 0x68-0x6F */ - 0x82DD,0x82E2,0x82E7,0x82E8,0x82E9,0x82EA,0x82EC,0x82ED,/* 0x70-0x77 */ - 0x82EE,0x82F0,0x82F2,0x82F3,0x82F5,0x82F6,0x82F8,0x0000,/* 0x78-0x7F */ - - 0x82FA,0x82FC,0x82FD,0x82FE,0x82FF,0x8300,0x830A,0x830B,/* 0x80-0x87 */ - 0x830D,0x8310,0x8312,0x8313,0x8316,0x8318,0x8319,0x831D,/* 0x88-0x8F */ - 0x831E,0x831F,0x8320,0x8321,0x8322,0x8323,0x8324,0x8325,/* 0x90-0x97 */ - 0x8326,0x8329,0x832A,0x832E,0x8330,0x8332,0x8337,0x833B,/* 0x98-0x9F */ - 0x833D,0x5564,0x813E,0x75B2,0x76AE,0x5339,0x75DE,0x50FB,/* 0xA0-0xA7 */ - 0x5C41,0x8B6C,0x7BC7,0x504F,0x7247,0x9A97,0x98D8,0x6F02,/* 0xA8-0xAF */ - 0x74E2,0x7968,0x6487,0x77A5,0x62FC,0x9891,0x8D2B,0x54C1,/* 0xB0-0xB7 */ - 0x8058,0x4E52,0x576A,0x82F9,0x840D,0x5E73,0x51ED,0x74F6,/* 0xB8-0xBF */ - 0x8BC4,0x5C4F,0x5761,0x6CFC,0x9887,0x5A46,0x7834,0x9B44,/* 0xC0-0xC7 */ - 0x8FEB,0x7C95,0x5256,0x6251,0x94FA,0x4EC6,0x8386,0x8461,/* 0xC8-0xCF */ - 0x83E9,0x84B2,0x57D4,0x6734,0x5703,0x666E,0x6D66,0x8C31,/* 0xD0-0xD7 */ - 0x66DD,0x7011,0x671F,0x6B3A,0x6816,0x621A,0x59BB,0x4E03,/* 0xD8-0xDF */ - 0x51C4,0x6F06,0x67D2,0x6C8F,0x5176,0x68CB,0x5947,0x6B67,/* 0xE0-0xE7 */ - 0x7566,0x5D0E,0x8110,0x9F50,0x65D7,0x7948,0x7941,0x9A91,/* 0xE8-0xEF */ - 0x8D77,0x5C82,0x4E5E,0x4F01,0x542F,0x5951,0x780C,0x5668,/* 0xF0-0xF7 */ - 0x6C14,0x8FC4,0x5F03,0x6C7D,0x6CE3,0x8BAB,0x6390,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C7[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x833E,0x833F,0x8341,0x8342,0x8344,0x8345,0x8348,0x834A,/* 0x40-0x47 */ - 0x834B,0x834C,0x834D,0x834E,0x8353,0x8355,0x8356,0x8357,/* 0x48-0x4F */ - 0x8358,0x8359,0x835D,0x8362,0x8370,0x8371,0x8372,0x8373,/* 0x50-0x57 */ - 0x8374,0x8375,0x8376,0x8379,0x837A,0x837E,0x837F,0x8380,/* 0x58-0x5F */ - 0x8381,0x8382,0x8383,0x8384,0x8387,0x8388,0x838A,0x838B,/* 0x60-0x67 */ - 0x838C,0x838D,0x838F,0x8390,0x8391,0x8394,0x8395,0x8396,/* 0x68-0x6F */ - 0x8397,0x8399,0x839A,0x839D,0x839F,0x83A1,0x83A2,0x83A3,/* 0x70-0x77 */ - 0x83A4,0x83A5,0x83A6,0x83A7,0x83AC,0x83AD,0x83AE,0x0000,/* 0x78-0x7F */ - - 0x83AF,0x83B5,0x83BB,0x83BE,0x83BF,0x83C2,0x83C3,0x83C4,/* 0x80-0x87 */ - 0x83C6,0x83C8,0x83C9,0x83CB,0x83CD,0x83CE,0x83D0,0x83D1,/* 0x88-0x8F */ - 0x83D2,0x83D3,0x83D5,0x83D7,0x83D9,0x83DA,0x83DB,0x83DE,/* 0x90-0x97 */ - 0x83E2,0x83E3,0x83E4,0x83E6,0x83E7,0x83E8,0x83EB,0x83EC,/* 0x98-0x9F */ - 0x83ED,0x6070,0x6D3D,0x7275,0x6266,0x948E,0x94C5,0x5343,/* 0xA0-0xA7 */ - 0x8FC1,0x7B7E,0x4EDF,0x8C26,0x4E7E,0x9ED4,0x94B1,0x94B3,/* 0xA8-0xAF */ - 0x524D,0x6F5C,0x9063,0x6D45,0x8C34,0x5811,0x5D4C,0x6B20,/* 0xB0-0xB7 */ - 0x6B49,0x67AA,0x545B,0x8154,0x7F8C,0x5899,0x8537,0x5F3A,/* 0xB8-0xBF */ - 0x62A2,0x6A47,0x9539,0x6572,0x6084,0x6865,0x77A7,0x4E54,/* 0xC0-0xC7 */ - 0x4FA8,0x5DE7,0x9798,0x64AC,0x7FD8,0x5CED,0x4FCF,0x7A8D,/* 0xC8-0xCF */ - 0x5207,0x8304,0x4E14,0x602F,0x7A83,0x94A6,0x4FB5,0x4EB2,/* 0xD0-0xD7 */ - 0x79E6,0x7434,0x52E4,0x82B9,0x64D2,0x79BD,0x5BDD,0x6C81,/* 0xD8-0xDF */ - 0x9752,0x8F7B,0x6C22,0x503E,0x537F,0x6E05,0x64CE,0x6674,/* 0xE0-0xE7 */ - 0x6C30,0x60C5,0x9877,0x8BF7,0x5E86,0x743C,0x7A77,0x79CB,/* 0xE8-0xEF */ - 0x4E18,0x90B1,0x7403,0x6C42,0x56DA,0x914B,0x6CC5,0x8D8B,/* 0xF0-0xF7 */ - 0x533A,0x86C6,0x66F2,0x8EAF,0x5C48,0x9A71,0x6E20,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C8[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x83EE,0x83EF,0x83F3,0x83F4,0x83F5,0x83F6,0x83F7,0x83FA,/* 0x40-0x47 */ - 0x83FB,0x83FC,0x83FE,0x83FF,0x8400,0x8402,0x8405,0x8407,/* 0x48-0x4F */ - 0x8408,0x8409,0x840A,0x8410,0x8412,0x8413,0x8414,0x8415,/* 0x50-0x57 */ - 0x8416,0x8417,0x8419,0x841A,0x841B,0x841E,0x841F,0x8420,/* 0x58-0x5F */ - 0x8421,0x8422,0x8423,0x8429,0x842A,0x842B,0x842C,0x842D,/* 0x60-0x67 */ - 0x842E,0x842F,0x8430,0x8432,0x8433,0x8434,0x8435,0x8436,/* 0x68-0x6F */ - 0x8437,0x8439,0x843A,0x843B,0x843E,0x843F,0x8440,0x8441,/* 0x70-0x77 */ - 0x8442,0x8443,0x8444,0x8445,0x8447,0x8448,0x8449,0x0000,/* 0x78-0x7F */ - - 0x844A,0x844B,0x844C,0x844D,0x844E,0x844F,0x8450,0x8452,/* 0x80-0x87 */ - 0x8453,0x8454,0x8455,0x8456,0x8458,0x845D,0x845E,0x845F,/* 0x88-0x8F */ - 0x8460,0x8462,0x8464,0x8465,0x8466,0x8467,0x8468,0x846A,/* 0x90-0x97 */ - 0x846E,0x846F,0x8470,0x8472,0x8474,0x8477,0x8479,0x847B,/* 0x98-0x9F */ - 0x847C,0x53D6,0x5A36,0x9F8B,0x8DA3,0x53BB,0x5708,0x98A7,/* 0xA0-0xA7 */ - 0x6743,0x919B,0x6CC9,0x5168,0x75CA,0x62F3,0x72AC,0x5238,/* 0xA8-0xAF */ - 0x529D,0x7F3A,0x7094,0x7638,0x5374,0x9E4A,0x69B7,0x786E,/* 0xB0-0xB7 */ - 0x96C0,0x88D9,0x7FA4,0x7136,0x71C3,0x5189,0x67D3,0x74E4,/* 0xB8-0xBF */ - 0x58E4,0x6518,0x56B7,0x8BA9,0x9976,0x6270,0x7ED5,0x60F9,/* 0xC0-0xC7 */ - 0x70ED,0x58EC,0x4EC1,0x4EBA,0x5FCD,0x97E7,0x4EFB,0x8BA4,/* 0xC8-0xCF */ - 0x5203,0x598A,0x7EAB,0x6254,0x4ECD,0x65E5,0x620E,0x8338,/* 0xD0-0xD7 */ - 0x84C9,0x8363,0x878D,0x7194,0x6EB6,0x5BB9,0x7ED2,0x5197,/* 0xD8-0xDF */ - 0x63C9,0x67D4,0x8089,0x8339,0x8815,0x5112,0x5B7A,0x5982,/* 0xE0-0xE7 */ - 0x8FB1,0x4E73,0x6C5D,0x5165,0x8925,0x8F6F,0x962E,0x854A,/* 0xE8-0xEF */ - 0x745E,0x9510,0x95F0,0x6DA6,0x82E5,0x5F31,0x6492,0x6D12,/* 0xF0-0xF7 */ - 0x8428,0x816E,0x9CC3,0x585E,0x8D5B,0x4E09,0x53C1,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C9[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x847D,0x847E,0x847F,0x8480,0x8481,0x8483,0x8484,0x8485,/* 0x40-0x47 */ - 0x8486,0x848A,0x848D,0x848F,0x8490,0x8491,0x8492,0x8493,/* 0x48-0x4F */ - 0x8494,0x8495,0x8496,0x8498,0x849A,0x849B,0x849D,0x849E,/* 0x50-0x57 */ - 0x849F,0x84A0,0x84A2,0x84A3,0x84A4,0x84A5,0x84A6,0x84A7,/* 0x58-0x5F */ - 0x84A8,0x84A9,0x84AA,0x84AB,0x84AC,0x84AD,0x84AE,0x84B0,/* 0x60-0x67 */ - 0x84B1,0x84B3,0x84B5,0x84B6,0x84B7,0x84BB,0x84BC,0x84BE,/* 0x68-0x6F */ - 0x84C0,0x84C2,0x84C3,0x84C5,0x84C6,0x84C7,0x84C8,0x84CB,/* 0x70-0x77 */ - 0x84CC,0x84CE,0x84CF,0x84D2,0x84D4,0x84D5,0x84D7,0x0000,/* 0x78-0x7F */ - - 0x84D8,0x84D9,0x84DA,0x84DB,0x84DC,0x84DE,0x84E1,0x84E2,/* 0x80-0x87 */ - 0x84E4,0x84E7,0x84E8,0x84E9,0x84EA,0x84EB,0x84ED,0x84EE,/* 0x88-0x8F */ - 0x84EF,0x84F1,0x84F2,0x84F3,0x84F4,0x84F5,0x84F6,0x84F7,/* 0x90-0x97 */ - 0x84F8,0x84F9,0x84FA,0x84FB,0x84FD,0x84FE,0x8500,0x8501,/* 0x98-0x9F */ - 0x8502,0x4F1E,0x6563,0x6851,0x55D3,0x4E27,0x6414,0x9A9A,/* 0xA0-0xA7 */ - 0x626B,0x5AC2,0x745F,0x8272,0x6DA9,0x68EE,0x50E7,0x838E,/* 0xA8-0xAF */ - 0x7802,0x6740,0x5239,0x6C99,0x7EB1,0x50BB,0x5565,0x715E,/* 0xB0-0xB7 */ - 0x7B5B,0x6652,0x73CA,0x82EB,0x6749,0x5C71,0x5220,0x717D,/* 0xB8-0xBF */ - 0x886B,0x95EA,0x9655,0x64C5,0x8D61,0x81B3,0x5584,0x6C55,/* 0xC0-0xC7 */ - 0x6247,0x7F2E,0x5892,0x4F24,0x5546,0x8D4F,0x664C,0x4E0A,/* 0xC8-0xCF */ - 0x5C1A,0x88F3,0x68A2,0x634E,0x7A0D,0x70E7,0x828D,0x52FA,/* 0xD0-0xD7 */ - 0x97F6,0x5C11,0x54E8,0x90B5,0x7ECD,0x5962,0x8D4A,0x86C7,/* 0xD8-0xDF */ - 0x820C,0x820D,0x8D66,0x6444,0x5C04,0x6151,0x6D89,0x793E,/* 0xE0-0xE7 */ - 0x8BBE,0x7837,0x7533,0x547B,0x4F38,0x8EAB,0x6DF1,0x5A20,/* 0xE8-0xEF */ - 0x7EC5,0x795E,0x6C88,0x5BA1,0x5A76,0x751A,0x80BE,0x614E,/* 0xF0-0xF7 */ - 0x6E17,0x58F0,0x751F,0x7525,0x7272,0x5347,0x7EF3,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_CA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8503,0x8504,0x8505,0x8506,0x8507,0x8508,0x8509,0x850A,/* 0x40-0x47 */ - 0x850B,0x850D,0x850E,0x850F,0x8510,0x8512,0x8514,0x8515,/* 0x48-0x4F */ - 0x8516,0x8518,0x8519,0x851B,0x851C,0x851D,0x851E,0x8520,/* 0x50-0x57 */ - 0x8522,0x8523,0x8524,0x8525,0x8526,0x8527,0x8528,0x8529,/* 0x58-0x5F */ - 0x852A,0x852D,0x852E,0x852F,0x8530,0x8531,0x8532,0x8533,/* 0x60-0x67 */ - 0x8534,0x8535,0x8536,0x853E,0x853F,0x8540,0x8541,0x8542,/* 0x68-0x6F */ - 0x8544,0x8545,0x8546,0x8547,0x854B,0x854C,0x854D,0x854E,/* 0x70-0x77 */ - 0x854F,0x8550,0x8551,0x8552,0x8553,0x8554,0x8555,0x0000,/* 0x78-0x7F */ - - 0x8557,0x8558,0x855A,0x855B,0x855C,0x855D,0x855F,0x8560,/* 0x80-0x87 */ - 0x8561,0x8562,0x8563,0x8565,0x8566,0x8567,0x8569,0x856A,/* 0x88-0x8F */ - 0x856B,0x856C,0x856D,0x856E,0x856F,0x8570,0x8571,0x8573,/* 0x90-0x97 */ - 0x8575,0x8576,0x8577,0x8578,0x857C,0x857D,0x857F,0x8580,/* 0x98-0x9F */ - 0x8581,0x7701,0x76DB,0x5269,0x80DC,0x5723,0x5E08,0x5931,/* 0xA0-0xA7 */ - 0x72EE,0x65BD,0x6E7F,0x8BD7,0x5C38,0x8671,0x5341,0x77F3,/* 0xA8-0xAF */ - 0x62FE,0x65F6,0x4EC0,0x98DF,0x8680,0x5B9E,0x8BC6,0x53F2,/* 0xB0-0xB7 */ - 0x77E2,0x4F7F,0x5C4E,0x9A76,0x59CB,0x5F0F,0x793A,0x58EB,/* 0xB8-0xBF */ - 0x4E16,0x67FF,0x4E8B,0x62ED,0x8A93,0x901D,0x52BF,0x662F,/* 0xC0-0xC7 */ - 0x55DC,0x566C,0x9002,0x4ED5,0x4F8D,0x91CA,0x9970,0x6C0F,/* 0xC8-0xCF */ - 0x5E02,0x6043,0x5BA4,0x89C6,0x8BD5,0x6536,0x624B,0x9996,/* 0xD0-0xD7 */ - 0x5B88,0x5BFF,0x6388,0x552E,0x53D7,0x7626,0x517D,0x852C,/* 0xD8-0xDF */ - 0x67A2,0x68B3,0x6B8A,0x6292,0x8F93,0x53D4,0x8212,0x6DD1,/* 0xE0-0xE7 */ - 0x758F,0x4E66,0x8D4E,0x5B70,0x719F,0x85AF,0x6691,0x66D9,/* 0xE8-0xEF */ - 0x7F72,0x8700,0x9ECD,0x9F20,0x5C5E,0x672F,0x8FF0,0x6811,/* 0xF0-0xF7 */ - 0x675F,0x620D,0x7AD6,0x5885,0x5EB6,0x6570,0x6F31,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_CB[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8582,0x8583,0x8586,0x8588,0x8589,0x858A,0x858B,0x858C,/* 0x40-0x47 */ - 0x858D,0x858E,0x8590,0x8591,0x8592,0x8593,0x8594,0x8595,/* 0x48-0x4F */ - 0x8596,0x8597,0x8598,0x8599,0x859A,0x859D,0x859E,0x859F,/* 0x50-0x57 */ - 0x85A0,0x85A1,0x85A2,0x85A3,0x85A5,0x85A6,0x85A7,0x85A9,/* 0x58-0x5F */ - 0x85AB,0x85AC,0x85AD,0x85B1,0x85B2,0x85B3,0x85B4,0x85B5,/* 0x60-0x67 */ - 0x85B6,0x85B8,0x85BA,0x85BB,0x85BC,0x85BD,0x85BE,0x85BF,/* 0x68-0x6F */ - 0x85C0,0x85C2,0x85C3,0x85C4,0x85C5,0x85C6,0x85C7,0x85C8,/* 0x70-0x77 */ - 0x85CA,0x85CB,0x85CC,0x85CD,0x85CE,0x85D1,0x85D2,0x0000,/* 0x78-0x7F */ - - 0x85D4,0x85D6,0x85D7,0x85D8,0x85D9,0x85DA,0x85DB,0x85DD,/* 0x80-0x87 */ - 0x85DE,0x85DF,0x85E0,0x85E1,0x85E2,0x85E3,0x85E5,0x85E6,/* 0x88-0x8F */ - 0x85E7,0x85E8,0x85EA,0x85EB,0x85EC,0x85ED,0x85EE,0x85EF,/* 0x90-0x97 */ - 0x85F0,0x85F1,0x85F2,0x85F3,0x85F4,0x85F5,0x85F6,0x85F7,/* 0x98-0x9F */ - 0x85F8,0x6055,0x5237,0x800D,0x6454,0x8870,0x7529,0x5E05,/* 0xA0-0xA7 */ - 0x6813,0x62F4,0x971C,0x53CC,0x723D,0x8C01,0x6C34,0x7761,/* 0xA8-0xAF */ - 0x7A0E,0x542E,0x77AC,0x987A,0x821C,0x8BF4,0x7855,0x6714,/* 0xB0-0xB7 */ - 0x70C1,0x65AF,0x6495,0x5636,0x601D,0x79C1,0x53F8,0x4E1D,/* 0xB8-0xBF */ - 0x6B7B,0x8086,0x5BFA,0x55E3,0x56DB,0x4F3A,0x4F3C,0x9972,/* 0xC0-0xC7 */ - 0x5DF3,0x677E,0x8038,0x6002,0x9882,0x9001,0x5B8B,0x8BBC,/* 0xC8-0xCF */ - 0x8BF5,0x641C,0x8258,0x64DE,0x55FD,0x82CF,0x9165,0x4FD7,/* 0xD0-0xD7 */ - 0x7D20,0x901F,0x7C9F,0x50F3,0x5851,0x6EAF,0x5BBF,0x8BC9,/* 0xD8-0xDF */ - 0x8083,0x9178,0x849C,0x7B97,0x867D,0x968B,0x968F,0x7EE5,/* 0xE0-0xE7 */ - 0x9AD3,0x788E,0x5C81,0x7A57,0x9042,0x96A7,0x795F,0x5B59,/* 0xE8-0xEF */ - 0x635F,0x7B0B,0x84D1,0x68AD,0x5506,0x7F29,0x7410,0x7D22,/* 0xF0-0xF7 */ - 0x9501,0x6240,0x584C,0x4ED6,0x5B83,0x5979,0x5854,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_CC[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x85F9,0x85FA,0x85FC,0x85FD,0x85FE,0x8600,0x8601,0x8602,/* 0x40-0x47 */ - 0x8603,0x8604,0x8606,0x8607,0x8608,0x8609,0x860A,0x860B,/* 0x48-0x4F */ - 0x860C,0x860D,0x860E,0x860F,0x8610,0x8612,0x8613,0x8614,/* 0x50-0x57 */ - 0x8615,0x8617,0x8618,0x8619,0x861A,0x861B,0x861C,0x861D,/* 0x58-0x5F */ - 0x861E,0x861F,0x8620,0x8621,0x8622,0x8623,0x8624,0x8625,/* 0x60-0x67 */ - 0x8626,0x8628,0x862A,0x862B,0x862C,0x862D,0x862E,0x862F,/* 0x68-0x6F */ - 0x8630,0x8631,0x8632,0x8633,0x8634,0x8635,0x8636,0x8637,/* 0x70-0x77 */ - 0x8639,0x863A,0x863B,0x863D,0x863E,0x863F,0x8640,0x0000,/* 0x78-0x7F */ - - 0x8641,0x8642,0x8643,0x8644,0x8645,0x8646,0x8647,0x8648,/* 0x80-0x87 */ - 0x8649,0x864A,0x864B,0x864C,0x8652,0x8653,0x8655,0x8656,/* 0x88-0x8F */ - 0x8657,0x8658,0x8659,0x865B,0x865C,0x865D,0x865F,0x8660,/* 0x90-0x97 */ - 0x8661,0x8663,0x8664,0x8665,0x8666,0x8667,0x8668,0x8669,/* 0x98-0x9F */ - 0x866A,0x736D,0x631E,0x8E4B,0x8E0F,0x80CE,0x82D4,0x62AC,/* 0xA0-0xA7 */ - 0x53F0,0x6CF0,0x915E,0x592A,0x6001,0x6C70,0x574D,0x644A,/* 0xA8-0xAF */ - 0x8D2A,0x762B,0x6EE9,0x575B,0x6A80,0x75F0,0x6F6D,0x8C2D,/* 0xB0-0xB7 */ - 0x8C08,0x5766,0x6BEF,0x8892,0x78B3,0x63A2,0x53F9,0x70AD,/* 0xB8-0xBF */ - 0x6C64,0x5858,0x642A,0x5802,0x68E0,0x819B,0x5510,0x7CD6,/* 0xC0-0xC7 */ - 0x5018,0x8EBA,0x6DCC,0x8D9F,0x70EB,0x638F,0x6D9B,0x6ED4,/* 0xC8-0xCF */ - 0x7EE6,0x8404,0x6843,0x9003,0x6DD8,0x9676,0x8BA8,0x5957,/* 0xD0-0xD7 */ - 0x7279,0x85E4,0x817E,0x75BC,0x8A8A,0x68AF,0x5254,0x8E22,/* 0xD8-0xDF */ - 0x9511,0x63D0,0x9898,0x8E44,0x557C,0x4F53,0x66FF,0x568F,/* 0xE0-0xE7 */ - 0x60D5,0x6D95,0x5243,0x5C49,0x5929,0x6DFB,0x586B,0x7530,/* 0xE8-0xEF */ - 0x751C,0x606C,0x8214,0x8146,0x6311,0x6761,0x8FE2,0x773A,/* 0xF0-0xF7 */ - 0x8DF3,0x8D34,0x94C1,0x5E16,0x5385,0x542C,0x70C3,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_CD[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x866D,0x866F,0x8670,0x8672,0x8673,0x8674,0x8675,0x8676,/* 0x40-0x47 */ - 0x8677,0x8678,0x8683,0x8684,0x8685,0x8686,0x8687,0x8688,/* 0x48-0x4F */ - 0x8689,0x868E,0x868F,0x8690,0x8691,0x8692,0x8694,0x8696,/* 0x50-0x57 */ - 0x8697,0x8698,0x8699,0x869A,0x869B,0x869E,0x869F,0x86A0,/* 0x58-0x5F */ - 0x86A1,0x86A2,0x86A5,0x86A6,0x86AB,0x86AD,0x86AE,0x86B2,/* 0x60-0x67 */ - 0x86B3,0x86B7,0x86B8,0x86B9,0x86BB,0x86BC,0x86BD,0x86BE,/* 0x68-0x6F */ - 0x86BF,0x86C1,0x86C2,0x86C3,0x86C5,0x86C8,0x86CC,0x86CD,/* 0x70-0x77 */ - 0x86D2,0x86D3,0x86D5,0x86D6,0x86D7,0x86DA,0x86DC,0x0000,/* 0x78-0x7F */ - - 0x86DD,0x86E0,0x86E1,0x86E2,0x86E3,0x86E5,0x86E6,0x86E7,/* 0x80-0x87 */ - 0x86E8,0x86EA,0x86EB,0x86EC,0x86EF,0x86F5,0x86F6,0x86F7,/* 0x88-0x8F */ - 0x86FA,0x86FB,0x86FC,0x86FD,0x86FF,0x8701,0x8704,0x8705,/* 0x90-0x97 */ - 0x8706,0x870B,0x870C,0x870E,0x870F,0x8710,0x8711,0x8714,/* 0x98-0x9F */ - 0x8716,0x6C40,0x5EF7,0x505C,0x4EAD,0x5EAD,0x633A,0x8247,/* 0xA0-0xA7 */ - 0x901A,0x6850,0x916E,0x77B3,0x540C,0x94DC,0x5F64,0x7AE5,/* 0xA8-0xAF */ - 0x6876,0x6345,0x7B52,0x7EDF,0x75DB,0x5077,0x6295,0x5934,/* 0xB0-0xB7 */ - 0x900F,0x51F8,0x79C3,0x7A81,0x56FE,0x5F92,0x9014,0x6D82,/* 0xB8-0xBF */ - 0x5C60,0x571F,0x5410,0x5154,0x6E4D,0x56E2,0x63A8,0x9893,/* 0xC0-0xC7 */ - 0x817F,0x8715,0x892A,0x9000,0x541E,0x5C6F,0x81C0,0x62D6,/* 0xC8-0xCF */ - 0x6258,0x8131,0x9E35,0x9640,0x9A6E,0x9A7C,0x692D,0x59A5,/* 0xD0-0xD7 */ - 0x62D3,0x553E,0x6316,0x54C7,0x86D9,0x6D3C,0x5A03,0x74E6,/* 0xD8-0xDF */ - 0x889C,0x6B6A,0x5916,0x8C4C,0x5F2F,0x6E7E,0x73A9,0x987D,/* 0xE0-0xE7 */ - 0x4E38,0x70F7,0x5B8C,0x7897,0x633D,0x665A,0x7696,0x60CB,/* 0xE8-0xEF */ - 0x5B9B,0x5A49,0x4E07,0x8155,0x6C6A,0x738B,0x4EA1,0x6789,/* 0xF0-0xF7 */ - 0x7F51,0x5F80,0x65FA,0x671B,0x5FD8,0x5984,0x5A01,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_CE[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8719,0x871B,0x871D,0x871F,0x8720,0x8724,0x8726,0x8727,/* 0x40-0x47 */ - 0x8728,0x872A,0x872B,0x872C,0x872D,0x872F,0x8730,0x8732,/* 0x48-0x4F */ - 0x8733,0x8735,0x8736,0x8738,0x8739,0x873A,0x873C,0x873D,/* 0x50-0x57 */ - 0x8740,0x8741,0x8742,0x8743,0x8744,0x8745,0x8746,0x874A,/* 0x58-0x5F */ - 0x874B,0x874D,0x874F,0x8750,0x8751,0x8752,0x8754,0x8755,/* 0x60-0x67 */ - 0x8756,0x8758,0x875A,0x875B,0x875C,0x875D,0x875E,0x875F,/* 0x68-0x6F */ - 0x8761,0x8762,0x8766,0x8767,0x8768,0x8769,0x876A,0x876B,/* 0x70-0x77 */ - 0x876C,0x876D,0x876F,0x8771,0x8772,0x8773,0x8775,0x0000,/* 0x78-0x7F */ - - 0x8777,0x8778,0x8779,0x877A,0x877F,0x8780,0x8781,0x8784,/* 0x80-0x87 */ - 0x8786,0x8787,0x8789,0x878A,0x878C,0x878E,0x878F,0x8790,/* 0x88-0x8F */ - 0x8791,0x8792,0x8794,0x8795,0x8796,0x8798,0x8799,0x879A,/* 0x90-0x97 */ - 0x879B,0x879C,0x879D,0x879E,0x87A0,0x87A1,0x87A2,0x87A3,/* 0x98-0x9F */ - 0x87A4,0x5DCD,0x5FAE,0x5371,0x97E6,0x8FDD,0x6845,0x56F4,/* 0xA0-0xA7 */ - 0x552F,0x60DF,0x4E3A,0x6F4D,0x7EF4,0x82C7,0x840E,0x59D4,/* 0xA8-0xAF */ - 0x4F1F,0x4F2A,0x5C3E,0x7EAC,0x672A,0x851A,0x5473,0x754F,/* 0xB0-0xB7 */ - 0x80C3,0x5582,0x9B4F,0x4F4D,0x6E2D,0x8C13,0x5C09,0x6170,/* 0xB8-0xBF */ - 0x536B,0x761F,0x6E29,0x868A,0x6587,0x95FB,0x7EB9,0x543B,/* 0xC0-0xC7 */ - 0x7A33,0x7D0A,0x95EE,0x55E1,0x7FC1,0x74EE,0x631D,0x8717,/* 0xC8-0xCF */ - 0x6DA1,0x7A9D,0x6211,0x65A1,0x5367,0x63E1,0x6C83,0x5DEB,/* 0xD0-0xD7 */ - 0x545C,0x94A8,0x4E4C,0x6C61,0x8BEC,0x5C4B,0x65E0,0x829C,/* 0xD8-0xDF */ - 0x68A7,0x543E,0x5434,0x6BCB,0x6B66,0x4E94,0x6342,0x5348,/* 0xE0-0xE7 */ - 0x821E,0x4F0D,0x4FAE,0x575E,0x620A,0x96FE,0x6664,0x7269,/* 0xE8-0xEF */ - 0x52FF,0x52A1,0x609F,0x8BEF,0x6614,0x7199,0x6790,0x897F,/* 0xF0-0xF7 */ - 0x7852,0x77FD,0x6670,0x563B,0x5438,0x9521,0x727A,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_CF[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x87A5,0x87A6,0x87A7,0x87A9,0x87AA,0x87AE,0x87B0,0x87B1,/* 0x40-0x47 */ - 0x87B2,0x87B4,0x87B6,0x87B7,0x87B8,0x87B9,0x87BB,0x87BC,/* 0x48-0x4F */ - 0x87BE,0x87BF,0x87C1,0x87C2,0x87C3,0x87C4,0x87C5,0x87C7,/* 0x50-0x57 */ - 0x87C8,0x87C9,0x87CC,0x87CD,0x87CE,0x87CF,0x87D0,0x87D4,/* 0x58-0x5F */ - 0x87D5,0x87D6,0x87D7,0x87D8,0x87D9,0x87DA,0x87DC,0x87DD,/* 0x60-0x67 */ - 0x87DE,0x87DF,0x87E1,0x87E2,0x87E3,0x87E4,0x87E6,0x87E7,/* 0x68-0x6F */ - 0x87E8,0x87E9,0x87EB,0x87EC,0x87ED,0x87EF,0x87F0,0x87F1,/* 0x70-0x77 */ - 0x87F2,0x87F3,0x87F4,0x87F5,0x87F6,0x87F7,0x87F8,0x0000,/* 0x78-0x7F */ - - 0x87FA,0x87FB,0x87FC,0x87FD,0x87FF,0x8800,0x8801,0x8802,/* 0x80-0x87 */ - 0x8804,0x8805,0x8806,0x8807,0x8808,0x8809,0x880B,0x880C,/* 0x88-0x8F */ - 0x880D,0x880E,0x880F,0x8810,0x8811,0x8812,0x8814,0x8817,/* 0x90-0x97 */ - 0x8818,0x8819,0x881A,0x881C,0x881D,0x881E,0x881F,0x8820,/* 0x98-0x9F */ - 0x8823,0x7A00,0x606F,0x5E0C,0x6089,0x819D,0x5915,0x60DC,/* 0xA0-0xA7 */ - 0x7184,0x70EF,0x6EAA,0x6C50,0x7280,0x6A84,0x88AD,0x5E2D,/* 0xA8-0xAF */ - 0x4E60,0x5AB3,0x559C,0x94E3,0x6D17,0x7CFB,0x9699,0x620F,/* 0xB0-0xB7 */ - 0x7EC6,0x778E,0x867E,0x5323,0x971E,0x8F96,0x6687,0x5CE1,/* 0xB8-0xBF */ - 0x4FA0,0x72ED,0x4E0B,0x53A6,0x590F,0x5413,0x6380,0x9528,/* 0xC0-0xC7 */ - 0x5148,0x4ED9,0x9C9C,0x7EA4,0x54B8,0x8D24,0x8854,0x8237,/* 0xC8-0xCF */ - 0x95F2,0x6D8E,0x5F26,0x5ACC,0x663E,0x9669,0x73B0,0x732E,/* 0xD0-0xD7 */ - 0x53BF,0x817A,0x9985,0x7FA1,0x5BAA,0x9677,0x9650,0x7EBF,/* 0xD8-0xDF */ - 0x76F8,0x53A2,0x9576,0x9999,0x7BB1,0x8944,0x6E58,0x4E61,/* 0xE0-0xE7 */ - 0x7FD4,0x7965,0x8BE6,0x60F3,0x54CD,0x4EAB,0x9879,0x5DF7,/* 0xE8-0xEF */ - 0x6A61,0x50CF,0x5411,0x8C61,0x8427,0x785D,0x9704,0x524A,/* 0xF0-0xF7 */ - 0x54EE,0x56A3,0x9500,0x6D88,0x5BB5,0x6DC6,0x6653,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D0[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8824,0x8825,0x8826,0x8827,0x8828,0x8829,0x882A,0x882B,/* 0x40-0x47 */ - 0x882C,0x882D,0x882E,0x882F,0x8830,0x8831,0x8833,0x8834,/* 0x48-0x4F */ - 0x8835,0x8836,0x8837,0x8838,0x883A,0x883B,0x883D,0x883E,/* 0x50-0x57 */ - 0x883F,0x8841,0x8842,0x8843,0x8846,0x8847,0x8848,0x8849,/* 0x58-0x5F */ - 0x884A,0x884B,0x884E,0x884F,0x8850,0x8851,0x8852,0x8853,/* 0x60-0x67 */ - 0x8855,0x8856,0x8858,0x885A,0x885B,0x885C,0x885D,0x885E,/* 0x68-0x6F */ - 0x885F,0x8860,0x8866,0x8867,0x886A,0x886D,0x886F,0x8871,/* 0x70-0x77 */ - 0x8873,0x8874,0x8875,0x8876,0x8878,0x8879,0x887A,0x0000,/* 0x78-0x7F */ - - 0x887B,0x887C,0x8880,0x8883,0x8886,0x8887,0x8889,0x888A,/* 0x80-0x87 */ - 0x888C,0x888E,0x888F,0x8890,0x8891,0x8893,0x8894,0x8895,/* 0x88-0x8F */ - 0x8897,0x8898,0x8899,0x889A,0x889B,0x889D,0x889E,0x889F,/* 0x90-0x97 */ - 0x88A0,0x88A1,0x88A3,0x88A5,0x88A6,0x88A7,0x88A8,0x88A9,/* 0x98-0x9F */ - 0x88AA,0x5C0F,0x5B5D,0x6821,0x8096,0x5578,0x7B11,0x6548,/* 0xA0-0xA7 */ - 0x6954,0x4E9B,0x6B47,0x874E,0x978B,0x534F,0x631F,0x643A,/* 0xA8-0xAF */ - 0x90AA,0x659C,0x80C1,0x8C10,0x5199,0x68B0,0x5378,0x87F9,/* 0xB0-0xB7 */ - 0x61C8,0x6CC4,0x6CFB,0x8C22,0x5C51,0x85AA,0x82AF,0x950C,/* 0xB8-0xBF */ - 0x6B23,0x8F9B,0x65B0,0x5FFB,0x5FC3,0x4FE1,0x8845,0x661F,/* 0xC0-0xC7 */ - 0x8165,0x7329,0x60FA,0x5174,0x5211,0x578B,0x5F62,0x90A2,/* 0xC8-0xCF */ - 0x884C,0x9192,0x5E78,0x674F,0x6027,0x59D3,0x5144,0x51F6,/* 0xD0-0xD7 */ - 0x80F8,0x5308,0x6C79,0x96C4,0x718A,0x4F11,0x4FEE,0x7F9E,/* 0xD8-0xDF */ - 0x673D,0x55C5,0x9508,0x79C0,0x8896,0x7EE3,0x589F,0x620C,/* 0xE0-0xE7 */ - 0x9700,0x865A,0x5618,0x987B,0x5F90,0x8BB8,0x84C4,0x9157,/* 0xE8-0xEF */ - 0x53D9,0x65ED,0x5E8F,0x755C,0x6064,0x7D6E,0x5A7F,0x7EEA,/* 0xF0-0xF7 */ - 0x7EED,0x8F69,0x55A7,0x5BA3,0x60AC,0x65CB,0x7384,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x88AC,0x88AE,0x88AF,0x88B0,0x88B2,0x88B3,0x88B4,0x88B5,/* 0x40-0x47 */ - 0x88B6,0x88B8,0x88B9,0x88BA,0x88BB,0x88BD,0x88BE,0x88BF,/* 0x48-0x4F */ - 0x88C0,0x88C3,0x88C4,0x88C7,0x88C8,0x88CA,0x88CB,0x88CC,/* 0x50-0x57 */ - 0x88CD,0x88CF,0x88D0,0x88D1,0x88D3,0x88D6,0x88D7,0x88DA,/* 0x58-0x5F */ - 0x88DB,0x88DC,0x88DD,0x88DE,0x88E0,0x88E1,0x88E6,0x88E7,/* 0x60-0x67 */ - 0x88E9,0x88EA,0x88EB,0x88EC,0x88ED,0x88EE,0x88EF,0x88F2,/* 0x68-0x6F */ - 0x88F5,0x88F6,0x88F7,0x88FA,0x88FB,0x88FD,0x88FF,0x8900,/* 0x70-0x77 */ - 0x8901,0x8903,0x8904,0x8905,0x8906,0x8907,0x8908,0x0000,/* 0x78-0x7F */ - - 0x8909,0x890B,0x890C,0x890D,0x890E,0x890F,0x8911,0x8914,/* 0x80-0x87 */ - 0x8915,0x8916,0x8917,0x8918,0x891C,0x891D,0x891E,0x891F,/* 0x88-0x8F */ - 0x8920,0x8922,0x8923,0x8924,0x8926,0x8927,0x8928,0x8929,/* 0x90-0x97 */ - 0x892C,0x892D,0x892E,0x892F,0x8931,0x8932,0x8933,0x8935,/* 0x98-0x9F */ - 0x8937,0x9009,0x7663,0x7729,0x7EDA,0x9774,0x859B,0x5B66,/* 0xA0-0xA7 */ - 0x7A74,0x96EA,0x8840,0x52CB,0x718F,0x5FAA,0x65EC,0x8BE2,/* 0xA8-0xAF */ - 0x5BFB,0x9A6F,0x5DE1,0x6B89,0x6C5B,0x8BAD,0x8BAF,0x900A,/* 0xB0-0xB7 */ - 0x8FC5,0x538B,0x62BC,0x9E26,0x9E2D,0x5440,0x4E2B,0x82BD,/* 0xB8-0xBF */ - 0x7259,0x869C,0x5D16,0x8859,0x6DAF,0x96C5,0x54D1,0x4E9A,/* 0xC0-0xC7 */ - 0x8BB6,0x7109,0x54BD,0x9609,0x70DF,0x6DF9,0x76D0,0x4E25,/* 0xC8-0xCF */ - 0x7814,0x8712,0x5CA9,0x5EF6,0x8A00,0x989C,0x960E,0x708E,/* 0xD0-0xD7 */ - 0x6CBF,0x5944,0x63A9,0x773C,0x884D,0x6F14,0x8273,0x5830,/* 0xD8-0xDF */ - 0x71D5,0x538C,0x781A,0x96C1,0x5501,0x5F66,0x7130,0x5BB4,/* 0xE0-0xE7 */ - 0x8C1A,0x9A8C,0x6B83,0x592E,0x9E2F,0x79E7,0x6768,0x626C,/* 0xE8-0xEF */ - 0x4F6F,0x75A1,0x7F8A,0x6D0B,0x9633,0x6C27,0x4EF0,0x75D2,/* 0xF0-0xF7 */ - 0x517B,0x6837,0x6F3E,0x9080,0x8170,0x5996,0x7476,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8938,0x8939,0x893A,0x893B,0x893C,0x893D,0x893E,0x893F,/* 0x40-0x47 */ - 0x8940,0x8942,0x8943,0x8945,0x8946,0x8947,0x8948,0x8949,/* 0x48-0x4F */ - 0x894A,0x894B,0x894C,0x894D,0x894E,0x894F,0x8950,0x8951,/* 0x50-0x57 */ - 0x8952,0x8953,0x8954,0x8955,0x8956,0x8957,0x8958,0x8959,/* 0x58-0x5F */ - 0x895A,0x895B,0x895C,0x895D,0x8960,0x8961,0x8962,0x8963,/* 0x60-0x67 */ - 0x8964,0x8965,0x8967,0x8968,0x8969,0x896A,0x896B,0x896C,/* 0x68-0x6F */ - 0x896D,0x896E,0x896F,0x8970,0x8971,0x8972,0x8973,0x8974,/* 0x70-0x77 */ - 0x8975,0x8976,0x8977,0x8978,0x8979,0x897A,0x897C,0x0000,/* 0x78-0x7F */ - - 0x897D,0x897E,0x8980,0x8982,0x8984,0x8985,0x8987,0x8988,/* 0x80-0x87 */ - 0x8989,0x898A,0x898B,0x898C,0x898D,0x898E,0x898F,0x8990,/* 0x88-0x8F */ - 0x8991,0x8992,0x8993,0x8994,0x8995,0x8996,0x8997,0x8998,/* 0x90-0x97 */ - 0x8999,0x899A,0x899B,0x899C,0x899D,0x899E,0x899F,0x89A0,/* 0x98-0x9F */ - 0x89A1,0x6447,0x5C27,0x9065,0x7A91,0x8C23,0x59DA,0x54AC,/* 0xA0-0xA7 */ - 0x8200,0x836F,0x8981,0x8000,0x6930,0x564E,0x8036,0x7237,/* 0xA8-0xAF */ - 0x91CE,0x51B6,0x4E5F,0x9875,0x6396,0x4E1A,0x53F6,0x66F3,/* 0xB0-0xB7 */ - 0x814B,0x591C,0x6DB2,0x4E00,0x58F9,0x533B,0x63D6,0x94F1,/* 0xB8-0xBF */ - 0x4F9D,0x4F0A,0x8863,0x9890,0x5937,0x9057,0x79FB,0x4EEA,/* 0xC0-0xC7 */ - 0x80F0,0x7591,0x6C82,0x5B9C,0x59E8,0x5F5D,0x6905,0x8681,/* 0xC8-0xCF */ - 0x501A,0x5DF2,0x4E59,0x77E3,0x4EE5,0x827A,0x6291,0x6613,/* 0xD0-0xD7 */ - 0x9091,0x5C79,0x4EBF,0x5F79,0x81C6,0x9038,0x8084,0x75AB,/* 0xD8-0xDF */ - 0x4EA6,0x88D4,0x610F,0x6BC5,0x5FC6,0x4E49,0x76CA,0x6EA2,/* 0xE0-0xE7 */ - 0x8BE3,0x8BAE,0x8C0A,0x8BD1,0x5F02,0x7FFC,0x7FCC,0x7ECE,/* 0xE8-0xEF */ - 0x8335,0x836B,0x56E0,0x6BB7,0x97F3,0x9634,0x59FB,0x541F,/* 0xF0-0xF7 */ - 0x94F6,0x6DEB,0x5BC5,0x996E,0x5C39,0x5F15,0x9690,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x89A2,0x89A3,0x89A4,0x89A5,0x89A6,0x89A7,0x89A8,0x89A9,/* 0x40-0x47 */ - 0x89AA,0x89AB,0x89AC,0x89AD,0x89AE,0x89AF,0x89B0,0x89B1,/* 0x48-0x4F */ - 0x89B2,0x89B3,0x89B4,0x89B5,0x89B6,0x89B7,0x89B8,0x89B9,/* 0x50-0x57 */ - 0x89BA,0x89BB,0x89BC,0x89BD,0x89BE,0x89BF,0x89C0,0x89C3,/* 0x58-0x5F */ - 0x89CD,0x89D3,0x89D4,0x89D5,0x89D7,0x89D8,0x89D9,0x89DB,/* 0x60-0x67 */ - 0x89DD,0x89DF,0x89E0,0x89E1,0x89E2,0x89E4,0x89E7,0x89E8,/* 0x68-0x6F */ - 0x89E9,0x89EA,0x89EC,0x89ED,0x89EE,0x89F0,0x89F1,0x89F2,/* 0x70-0x77 */ - 0x89F4,0x89F5,0x89F6,0x89F7,0x89F8,0x89F9,0x89FA,0x0000,/* 0x78-0x7F */ - - 0x89FB,0x89FC,0x89FD,0x89FE,0x89FF,0x8A01,0x8A02,0x8A03,/* 0x80-0x87 */ - 0x8A04,0x8A05,0x8A06,0x8A08,0x8A09,0x8A0A,0x8A0B,0x8A0C,/* 0x88-0x8F */ - 0x8A0D,0x8A0E,0x8A0F,0x8A10,0x8A11,0x8A12,0x8A13,0x8A14,/* 0x90-0x97 */ - 0x8A15,0x8A16,0x8A17,0x8A18,0x8A19,0x8A1A,0x8A1B,0x8A1C,/* 0x98-0x9F */ - 0x8A1D,0x5370,0x82F1,0x6A31,0x5A74,0x9E70,0x5E94,0x7F28,/* 0xA0-0xA7 */ - 0x83B9,0x8424,0x8425,0x8367,0x8747,0x8FCE,0x8D62,0x76C8,/* 0xA8-0xAF */ - 0x5F71,0x9896,0x786C,0x6620,0x54DF,0x62E5,0x4F63,0x81C3,/* 0xB0-0xB7 */ - 0x75C8,0x5EB8,0x96CD,0x8E0A,0x86F9,0x548F,0x6CF3,0x6D8C,/* 0xB8-0xBF */ - 0x6C38,0x607F,0x52C7,0x7528,0x5E7D,0x4F18,0x60A0,0x5FE7,/* 0xC0-0xC7 */ - 0x5C24,0x7531,0x90AE,0x94C0,0x72B9,0x6CB9,0x6E38,0x9149,/* 0xC8-0xCF */ - 0x6709,0x53CB,0x53F3,0x4F51,0x91C9,0x8BF1,0x53C8,0x5E7C,/* 0xD0-0xD7 */ - 0x8FC2,0x6DE4,0x4E8E,0x76C2,0x6986,0x865E,0x611A,0x8206,/* 0xD8-0xDF */ - 0x4F59,0x4FDE,0x903E,0x9C7C,0x6109,0x6E1D,0x6E14,0x9685,/* 0xE0-0xE7 */ - 0x4E88,0x5A31,0x96E8,0x4E0E,0x5C7F,0x79B9,0x5B87,0x8BED,/* 0xE8-0xEF */ - 0x7FBD,0x7389,0x57DF,0x828B,0x90C1,0x5401,0x9047,0x55BB,/* 0xF0-0xF7 */ - 0x5CEA,0x5FA1,0x6108,0x6B32,0x72F1,0x80B2,0x8A89,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8A1E,0x8A1F,0x8A20,0x8A21,0x8A22,0x8A23,0x8A24,0x8A25,/* 0x40-0x47 */ - 0x8A26,0x8A27,0x8A28,0x8A29,0x8A2A,0x8A2B,0x8A2C,0x8A2D,/* 0x48-0x4F */ - 0x8A2E,0x8A2F,0x8A30,0x8A31,0x8A32,0x8A33,0x8A34,0x8A35,/* 0x50-0x57 */ - 0x8A36,0x8A37,0x8A38,0x8A39,0x8A3A,0x8A3B,0x8A3C,0x8A3D,/* 0x58-0x5F */ - 0x8A3F,0x8A40,0x8A41,0x8A42,0x8A43,0x8A44,0x8A45,0x8A46,/* 0x60-0x67 */ - 0x8A47,0x8A49,0x8A4A,0x8A4B,0x8A4C,0x8A4D,0x8A4E,0x8A4F,/* 0x68-0x6F */ - 0x8A50,0x8A51,0x8A52,0x8A53,0x8A54,0x8A55,0x8A56,0x8A57,/* 0x70-0x77 */ - 0x8A58,0x8A59,0x8A5A,0x8A5B,0x8A5C,0x8A5D,0x8A5E,0x0000,/* 0x78-0x7F */ - - 0x8A5F,0x8A60,0x8A61,0x8A62,0x8A63,0x8A64,0x8A65,0x8A66,/* 0x80-0x87 */ - 0x8A67,0x8A68,0x8A69,0x8A6A,0x8A6B,0x8A6C,0x8A6D,0x8A6E,/* 0x88-0x8F */ - 0x8A6F,0x8A70,0x8A71,0x8A72,0x8A73,0x8A74,0x8A75,0x8A76,/* 0x90-0x97 */ - 0x8A77,0x8A78,0x8A7A,0x8A7B,0x8A7C,0x8A7D,0x8A7E,0x8A7F,/* 0x98-0x9F */ - 0x8A80,0x6D74,0x5BD3,0x88D5,0x9884,0x8C6B,0x9A6D,0x9E33,/* 0xA0-0xA7 */ - 0x6E0A,0x51A4,0x5143,0x57A3,0x8881,0x539F,0x63F4,0x8F95,/* 0xA8-0xAF */ - 0x56ED,0x5458,0x5706,0x733F,0x6E90,0x7F18,0x8FDC,0x82D1,/* 0xB0-0xB7 */ - 0x613F,0x6028,0x9662,0x66F0,0x7EA6,0x8D8A,0x8DC3,0x94A5,/* 0xB8-0xBF */ - 0x5CB3,0x7CA4,0x6708,0x60A6,0x9605,0x8018,0x4E91,0x90E7,/* 0xC0-0xC7 */ - 0x5300,0x9668,0x5141,0x8FD0,0x8574,0x915D,0x6655,0x97F5,/* 0xC8-0xCF */ - 0x5B55,0x531D,0x7838,0x6742,0x683D,0x54C9,0x707E,0x5BB0,/* 0xD0-0xD7 */ - 0x8F7D,0x518D,0x5728,0x54B1,0x6512,0x6682,0x8D5E,0x8D43,/* 0xD8-0xDF */ - 0x810F,0x846C,0x906D,0x7CDF,0x51FF,0x85FB,0x67A3,0x65E9,/* 0xE0-0xE7 */ - 0x6FA1,0x86A4,0x8E81,0x566A,0x9020,0x7682,0x7076,0x71E5,/* 0xE8-0xEF */ - 0x8D23,0x62E9,0x5219,0x6CFD,0x8D3C,0x600E,0x589E,0x618E,/* 0xF0-0xF7 */ - 0x66FE,0x8D60,0x624E,0x55B3,0x6E23,0x672D,0x8F67,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8A81,0x8A82,0x8A83,0x8A84,0x8A85,0x8A86,0x8A87,0x8A88,/* 0x40-0x47 */ - 0x8A8B,0x8A8C,0x8A8D,0x8A8E,0x8A8F,0x8A90,0x8A91,0x8A92,/* 0x48-0x4F */ - 0x8A94,0x8A95,0x8A96,0x8A97,0x8A98,0x8A99,0x8A9A,0x8A9B,/* 0x50-0x57 */ - 0x8A9C,0x8A9D,0x8A9E,0x8A9F,0x8AA0,0x8AA1,0x8AA2,0x8AA3,/* 0x58-0x5F */ - 0x8AA4,0x8AA5,0x8AA6,0x8AA7,0x8AA8,0x8AA9,0x8AAA,0x8AAB,/* 0x60-0x67 */ - 0x8AAC,0x8AAD,0x8AAE,0x8AAF,0x8AB0,0x8AB1,0x8AB2,0x8AB3,/* 0x68-0x6F */ - 0x8AB4,0x8AB5,0x8AB6,0x8AB7,0x8AB8,0x8AB9,0x8ABA,0x8ABB,/* 0x70-0x77 */ - 0x8ABC,0x8ABD,0x8ABE,0x8ABF,0x8AC0,0x8AC1,0x8AC2,0x0000,/* 0x78-0x7F */ - - 0x8AC3,0x8AC4,0x8AC5,0x8AC6,0x8AC7,0x8AC8,0x8AC9,0x8ACA,/* 0x80-0x87 */ - 0x8ACB,0x8ACC,0x8ACD,0x8ACE,0x8ACF,0x8AD0,0x8AD1,0x8AD2,/* 0x88-0x8F */ - 0x8AD3,0x8AD4,0x8AD5,0x8AD6,0x8AD7,0x8AD8,0x8AD9,0x8ADA,/* 0x90-0x97 */ - 0x8ADB,0x8ADC,0x8ADD,0x8ADE,0x8ADF,0x8AE0,0x8AE1,0x8AE2,/* 0x98-0x9F */ - 0x8AE3,0x94E1,0x95F8,0x7728,0x6805,0x69A8,0x548B,0x4E4D,/* 0xA0-0xA7 */ - 0x70B8,0x8BC8,0x6458,0x658B,0x5B85,0x7A84,0x503A,0x5BE8,/* 0xA8-0xAF */ - 0x77BB,0x6BE1,0x8A79,0x7C98,0x6CBE,0x76CF,0x65A9,0x8F97,/* 0xB0-0xB7 */ - 0x5D2D,0x5C55,0x8638,0x6808,0x5360,0x6218,0x7AD9,0x6E5B,/* 0xB8-0xBF */ - 0x7EFD,0x6A1F,0x7AE0,0x5F70,0x6F33,0x5F20,0x638C,0x6DA8,/* 0xC0-0xC7 */ - 0x6756,0x4E08,0x5E10,0x8D26,0x4ED7,0x80C0,0x7634,0x969C,/* 0xC8-0xCF */ - 0x62DB,0x662D,0x627E,0x6CBC,0x8D75,0x7167,0x7F69,0x5146,/* 0xD0-0xD7 */ - 0x8087,0x53EC,0x906E,0x6298,0x54F2,0x86F0,0x8F99,0x8005,/* 0xD8-0xDF */ - 0x9517,0x8517,0x8FD9,0x6D59,0x73CD,0x659F,0x771F,0x7504,/* 0xE0-0xE7 */ - 0x7827,0x81FB,0x8D1E,0x9488,0x4FA6,0x6795,0x75B9,0x8BCA,/* 0xE8-0xEF */ - 0x9707,0x632F,0x9547,0x9635,0x84B8,0x6323,0x7741,0x5F81,/* 0xF0-0xF7 */ - 0x72F0,0x4E89,0x6014,0x6574,0x62EF,0x6B63,0x653F,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8AE4,0x8AE5,0x8AE6,0x8AE7,0x8AE8,0x8AE9,0x8AEA,0x8AEB,/* 0x40-0x47 */ - 0x8AEC,0x8AED,0x8AEE,0x8AEF,0x8AF0,0x8AF1,0x8AF2,0x8AF3,/* 0x48-0x4F */ - 0x8AF4,0x8AF5,0x8AF6,0x8AF7,0x8AF8,0x8AF9,0x8AFA,0x8AFB,/* 0x50-0x57 */ - 0x8AFC,0x8AFD,0x8AFE,0x8AFF,0x8B00,0x8B01,0x8B02,0x8B03,/* 0x58-0x5F */ - 0x8B04,0x8B05,0x8B06,0x8B08,0x8B09,0x8B0A,0x8B0B,0x8B0C,/* 0x60-0x67 */ - 0x8B0D,0x8B0E,0x8B0F,0x8B10,0x8B11,0x8B12,0x8B13,0x8B14,/* 0x68-0x6F */ - 0x8B15,0x8B16,0x8B17,0x8B18,0x8B19,0x8B1A,0x8B1B,0x8B1C,/* 0x70-0x77 */ - 0x8B1D,0x8B1E,0x8B1F,0x8B20,0x8B21,0x8B22,0x8B23,0x0000,/* 0x78-0x7F */ - - 0x8B24,0x8B25,0x8B27,0x8B28,0x8B29,0x8B2A,0x8B2B,0x8B2C,/* 0x80-0x87 */ - 0x8B2D,0x8B2E,0x8B2F,0x8B30,0x8B31,0x8B32,0x8B33,0x8B34,/* 0x88-0x8F */ - 0x8B35,0x8B36,0x8B37,0x8B38,0x8B39,0x8B3A,0x8B3B,0x8B3C,/* 0x90-0x97 */ - 0x8B3D,0x8B3E,0x8B3F,0x8B40,0x8B41,0x8B42,0x8B43,0x8B44,/* 0x98-0x9F */ - 0x8B45,0x5E27,0x75C7,0x90D1,0x8BC1,0x829D,0x679D,0x652F,/* 0xA0-0xA7 */ - 0x5431,0x8718,0x77E5,0x80A2,0x8102,0x6C41,0x4E4B,0x7EC7,/* 0xA8-0xAF */ - 0x804C,0x76F4,0x690D,0x6B96,0x6267,0x503C,0x4F84,0x5740,/* 0xB0-0xB7 */ - 0x6307,0x6B62,0x8DBE,0x53EA,0x65E8,0x7EB8,0x5FD7,0x631A,/* 0xB8-0xBF */ - 0x63B7,0x81F3,0x81F4,0x7F6E,0x5E1C,0x5CD9,0x5236,0x667A,/* 0xC0-0xC7 */ - 0x79E9,0x7A1A,0x8D28,0x7099,0x75D4,0x6EDE,0x6CBB,0x7A92,/* 0xC8-0xCF */ - 0x4E2D,0x76C5,0x5FE0,0x949F,0x8877,0x7EC8,0x79CD,0x80BF,/* 0xD0-0xD7 */ - 0x91CD,0x4EF2,0x4F17,0x821F,0x5468,0x5DDE,0x6D32,0x8BCC,/* 0xD8-0xDF */ - 0x7CA5,0x8F74,0x8098,0x5E1A,0x5492,0x76B1,0x5B99,0x663C,/* 0xE0-0xE7 */ - 0x9AA4,0x73E0,0x682A,0x86DB,0x6731,0x732A,0x8BF8,0x8BDB,/* 0xE8-0xEF */ - 0x9010,0x7AF9,0x70DB,0x716E,0x62C4,0x77A9,0x5631,0x4E3B,/* 0xF0-0xF7 */ - 0x8457,0x67F1,0x52A9,0x86C0,0x8D2E,0x94F8,0x7B51,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D7[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8B46,0x8B47,0x8B48,0x8B49,0x8B4A,0x8B4B,0x8B4C,0x8B4D,/* 0x40-0x47 */ - 0x8B4E,0x8B4F,0x8B50,0x8B51,0x8B52,0x8B53,0x8B54,0x8B55,/* 0x48-0x4F */ - 0x8B56,0x8B57,0x8B58,0x8B59,0x8B5A,0x8B5B,0x8B5C,0x8B5D,/* 0x50-0x57 */ - 0x8B5E,0x8B5F,0x8B60,0x8B61,0x8B62,0x8B63,0x8B64,0x8B65,/* 0x58-0x5F */ - 0x8B67,0x8B68,0x8B69,0x8B6A,0x8B6B,0x8B6D,0x8B6E,0x8B6F,/* 0x60-0x67 */ - 0x8B70,0x8B71,0x8B72,0x8B73,0x8B74,0x8B75,0x8B76,0x8B77,/* 0x68-0x6F */ - 0x8B78,0x8B79,0x8B7A,0x8B7B,0x8B7C,0x8B7D,0x8B7E,0x8B7F,/* 0x70-0x77 */ - 0x8B80,0x8B81,0x8B82,0x8B83,0x8B84,0x8B85,0x8B86,0x0000,/* 0x78-0x7F */ - - 0x8B87,0x8B88,0x8B89,0x8B8A,0x8B8B,0x8B8C,0x8B8D,0x8B8E,/* 0x80-0x87 */ - 0x8B8F,0x8B90,0x8B91,0x8B92,0x8B93,0x8B94,0x8B95,0x8B96,/* 0x88-0x8F */ - 0x8B97,0x8B98,0x8B99,0x8B9A,0x8B9B,0x8B9C,0x8B9D,0x8B9E,/* 0x90-0x97 */ - 0x8B9F,0x8BAC,0x8BB1,0x8BBB,0x8BC7,0x8BD0,0x8BEA,0x8C09,/* 0x98-0x9F */ - 0x8C1E,0x4F4F,0x6CE8,0x795D,0x9A7B,0x6293,0x722A,0x62FD,/* 0xA0-0xA7 */ - 0x4E13,0x7816,0x8F6C,0x64B0,0x8D5A,0x7BC6,0x6869,0x5E84,/* 0xA8-0xAF */ - 0x88C5,0x5986,0x649E,0x58EE,0x72B6,0x690E,0x9525,0x8FFD,/* 0xB0-0xB7 */ - 0x8D58,0x5760,0x7F00,0x8C06,0x51C6,0x6349,0x62D9,0x5353,/* 0xB8-0xBF */ - 0x684C,0x7422,0x8301,0x914C,0x5544,0x7740,0x707C,0x6D4A,/* 0xC0-0xC7 */ - 0x5179,0x54A8,0x8D44,0x59FF,0x6ECB,0x6DC4,0x5B5C,0x7D2B,/* 0xC8-0xCF */ - 0x4ED4,0x7C7D,0x6ED3,0x5B50,0x81EA,0x6E0D,0x5B57,0x9B03,/* 0xD0-0xD7 */ - 0x68D5,0x8E2A,0x5B97,0x7EFC,0x603B,0x7EB5,0x90B9,0x8D70,/* 0xD8-0xDF */ - 0x594F,0x63CD,0x79DF,0x8DB3,0x5352,0x65CF,0x7956,0x8BC5,/* 0xE0-0xE7 */ - 0x963B,0x7EC4,0x94BB,0x7E82,0x5634,0x9189,0x6700,0x7F6A,/* 0xE8-0xEF */ - 0x5C0A,0x9075,0x6628,0x5DE6,0x4F50,0x67DE,0x505A,0x4F5C,/* 0xF0-0xF7 */ - 0x5750,0x5EA7,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D8[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8C38,0x8C39,0x8C3A,0x8C3B,0x8C3C,0x8C3D,0x8C3E,0x8C3F,/* 0x40-0x47 */ - 0x8C40,0x8C42,0x8C43,0x8C44,0x8C45,0x8C48,0x8C4A,0x8C4B,/* 0x48-0x4F */ - 0x8C4D,0x8C4E,0x8C4F,0x8C50,0x8C51,0x8C52,0x8C53,0x8C54,/* 0x50-0x57 */ - 0x8C56,0x8C57,0x8C58,0x8C59,0x8C5B,0x8C5C,0x8C5D,0x8C5E,/* 0x58-0x5F */ - 0x8C5F,0x8C60,0x8C63,0x8C64,0x8C65,0x8C66,0x8C67,0x8C68,/* 0x60-0x67 */ - 0x8C69,0x8C6C,0x8C6D,0x8C6E,0x8C6F,0x8C70,0x8C71,0x8C72,/* 0x68-0x6F */ - 0x8C74,0x8C75,0x8C76,0x8C77,0x8C7B,0x8C7C,0x8C7D,0x8C7E,/* 0x70-0x77 */ - 0x8C7F,0x8C80,0x8C81,0x8C83,0x8C84,0x8C86,0x8C87,0x0000,/* 0x78-0x7F */ - - 0x8C88,0x8C8B,0x8C8D,0x8C8E,0x8C8F,0x8C90,0x8C91,0x8C92,/* 0x80-0x87 */ - 0x8C93,0x8C95,0x8C96,0x8C97,0x8C99,0x8C9A,0x8C9B,0x8C9C,/* 0x88-0x8F */ - 0x8C9D,0x8C9E,0x8C9F,0x8CA0,0x8CA1,0x8CA2,0x8CA3,0x8CA4,/* 0x90-0x97 */ - 0x8CA5,0x8CA6,0x8CA7,0x8CA8,0x8CA9,0x8CAA,0x8CAB,0x8CAC,/* 0x98-0x9F */ - 0x8CAD,0x4E8D,0x4E0C,0x5140,0x4E10,0x5EFF,0x5345,0x4E15,/* 0xA0-0xA7 */ - 0x4E98,0x4E1E,0x9B32,0x5B6C,0x5669,0x4E28,0x79BA,0x4E3F,/* 0xA8-0xAF */ - 0x5315,0x4E47,0x592D,0x723B,0x536E,0x6C10,0x56DF,0x80E4,/* 0xB0-0xB7 */ - 0x9997,0x6BD3,0x777E,0x9F17,0x4E36,0x4E9F,0x9F10,0x4E5C,/* 0xB8-0xBF */ - 0x4E69,0x4E93,0x8288,0x5B5B,0x556C,0x560F,0x4EC4,0x538D,/* 0xC0-0xC7 */ - 0x539D,0x53A3,0x53A5,0x53AE,0x9765,0x8D5D,0x531A,0x53F5,/* 0xC8-0xCF */ - 0x5326,0x532E,0x533E,0x8D5C,0x5366,0x5363,0x5202,0x5208,/* 0xD0-0xD7 */ - 0x520E,0x522D,0x5233,0x523F,0x5240,0x524C,0x525E,0x5261,/* 0xD8-0xDF */ - 0x525C,0x84AF,0x527D,0x5282,0x5281,0x5290,0x5293,0x5182,/* 0xE0-0xE7 */ - 0x7F54,0x4EBB,0x4EC3,0x4EC9,0x4EC2,0x4EE8,0x4EE1,0x4EEB,/* 0xE8-0xEF */ - 0x4EDE,0x4F1B,0x4EF3,0x4F22,0x4F64,0x4EF5,0x4F25,0x4F27,/* 0xF0-0xF7 */ - 0x4F09,0x4F2B,0x4F5E,0x4F67,0x6538,0x4F5A,0x4F5D,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D9[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8CAE,0x8CAF,0x8CB0,0x8CB1,0x8CB2,0x8CB3,0x8CB4,0x8CB5,/* 0x40-0x47 */ - 0x8CB6,0x8CB7,0x8CB8,0x8CB9,0x8CBA,0x8CBB,0x8CBC,0x8CBD,/* 0x48-0x4F */ - 0x8CBE,0x8CBF,0x8CC0,0x8CC1,0x8CC2,0x8CC3,0x8CC4,0x8CC5,/* 0x50-0x57 */ - 0x8CC6,0x8CC7,0x8CC8,0x8CC9,0x8CCA,0x8CCB,0x8CCC,0x8CCD,/* 0x58-0x5F */ - 0x8CCE,0x8CCF,0x8CD0,0x8CD1,0x8CD2,0x8CD3,0x8CD4,0x8CD5,/* 0x60-0x67 */ - 0x8CD6,0x8CD7,0x8CD8,0x8CD9,0x8CDA,0x8CDB,0x8CDC,0x8CDD,/* 0x68-0x6F */ - 0x8CDE,0x8CDF,0x8CE0,0x8CE1,0x8CE2,0x8CE3,0x8CE4,0x8CE5,/* 0x70-0x77 */ - 0x8CE6,0x8CE7,0x8CE8,0x8CE9,0x8CEA,0x8CEB,0x8CEC,0x0000,/* 0x78-0x7F */ - - 0x8CED,0x8CEE,0x8CEF,0x8CF0,0x8CF1,0x8CF2,0x8CF3,0x8CF4,/* 0x80-0x87 */ - 0x8CF5,0x8CF6,0x8CF7,0x8CF8,0x8CF9,0x8CFA,0x8CFB,0x8CFC,/* 0x88-0x8F */ - 0x8CFD,0x8CFE,0x8CFF,0x8D00,0x8D01,0x8D02,0x8D03,0x8D04,/* 0x90-0x97 */ - 0x8D05,0x8D06,0x8D07,0x8D08,0x8D09,0x8D0A,0x8D0B,0x8D0C,/* 0x98-0x9F */ - 0x8D0D,0x4F5F,0x4F57,0x4F32,0x4F3D,0x4F76,0x4F74,0x4F91,/* 0xA0-0xA7 */ - 0x4F89,0x4F83,0x4F8F,0x4F7E,0x4F7B,0x4FAA,0x4F7C,0x4FAC,/* 0xA8-0xAF */ - 0x4F94,0x4FE6,0x4FE8,0x4FEA,0x4FC5,0x4FDA,0x4FE3,0x4FDC,/* 0xB0-0xB7 */ - 0x4FD1,0x4FDF,0x4FF8,0x5029,0x504C,0x4FF3,0x502C,0x500F,/* 0xB8-0xBF */ - 0x502E,0x502D,0x4FFE,0x501C,0x500C,0x5025,0x5028,0x507E,/* 0xC0-0xC7 */ - 0x5043,0x5055,0x5048,0x504E,0x506C,0x507B,0x50A5,0x50A7,/* 0xC8-0xCF */ - 0x50A9,0x50BA,0x50D6,0x5106,0x50ED,0x50EC,0x50E6,0x50EE,/* 0xD0-0xD7 */ - 0x5107,0x510B,0x4EDD,0x6C3D,0x4F58,0x4F65,0x4FCE,0x9FA0,/* 0xD8-0xDF */ - 0x6C46,0x7C74,0x516E,0x5DFD,0x9EC9,0x9998,0x5181,0x5914,/* 0xE0-0xE7 */ - 0x52F9,0x530D,0x8A07,0x5310,0x51EB,0x5919,0x5155,0x4EA0,/* 0xE8-0xEF */ - 0x5156,0x4EB3,0x886E,0x88A4,0x4EB5,0x8114,0x88D2,0x7980,/* 0xF0-0xF7 */ - 0x5B34,0x8803,0x7FB8,0x51AB,0x51B1,0x51BD,0x51BC,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_DA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8D0E,0x8D0F,0x8D10,0x8D11,0x8D12,0x8D13,0x8D14,0x8D15,/* 0x40-0x47 */ - 0x8D16,0x8D17,0x8D18,0x8D19,0x8D1A,0x8D1B,0x8D1C,0x8D20,/* 0x48-0x4F */ - 0x8D51,0x8D52,0x8D57,0x8D5F,0x8D65,0x8D68,0x8D69,0x8D6A,/* 0x50-0x57 */ - 0x8D6C,0x8D6E,0x8D6F,0x8D71,0x8D72,0x8D78,0x8D79,0x8D7A,/* 0x58-0x5F */ - 0x8D7B,0x8D7C,0x8D7D,0x8D7E,0x8D7F,0x8D80,0x8D82,0x8D83,/* 0x60-0x67 */ - 0x8D86,0x8D87,0x8D88,0x8D89,0x8D8C,0x8D8D,0x8D8E,0x8D8F,/* 0x68-0x6F */ - 0x8D90,0x8D92,0x8D93,0x8D95,0x8D96,0x8D97,0x8D98,0x8D99,/* 0x70-0x77 */ - 0x8D9A,0x8D9B,0x8D9C,0x8D9D,0x8D9E,0x8DA0,0x8DA1,0x0000,/* 0x78-0x7F */ - - 0x8DA2,0x8DA4,0x8DA5,0x8DA6,0x8DA7,0x8DA8,0x8DA9,0x8DAA,/* 0x80-0x87 */ - 0x8DAB,0x8DAC,0x8DAD,0x8DAE,0x8DAF,0x8DB0,0x8DB2,0x8DB6,/* 0x88-0x8F */ - 0x8DB7,0x8DB9,0x8DBB,0x8DBD,0x8DC0,0x8DC1,0x8DC2,0x8DC5,/* 0x90-0x97 */ - 0x8DC7,0x8DC8,0x8DC9,0x8DCA,0x8DCD,0x8DD0,0x8DD2,0x8DD3,/* 0x98-0x9F */ - 0x8DD4,0x51C7,0x5196,0x51A2,0x51A5,0x8BA0,0x8BA6,0x8BA7,/* 0xA0-0xA7 */ - 0x8BAA,0x8BB4,0x8BB5,0x8BB7,0x8BC2,0x8BC3,0x8BCB,0x8BCF,/* 0xA8-0xAF */ - 0x8BCE,0x8BD2,0x8BD3,0x8BD4,0x8BD6,0x8BD8,0x8BD9,0x8BDC,/* 0xB0-0xB7 */ - 0x8BDF,0x8BE0,0x8BE4,0x8BE8,0x8BE9,0x8BEE,0x8BF0,0x8BF3,/* 0xB8-0xBF */ - 0x8BF6,0x8BF9,0x8BFC,0x8BFF,0x8C00,0x8C02,0x8C04,0x8C07,/* 0xC0-0xC7 */ - 0x8C0C,0x8C0F,0x8C11,0x8C12,0x8C14,0x8C15,0x8C16,0x8C19,/* 0xC8-0xCF */ - 0x8C1B,0x8C18,0x8C1D,0x8C1F,0x8C20,0x8C21,0x8C25,0x8C27,/* 0xD0-0xD7 */ - 0x8C2A,0x8C2B,0x8C2E,0x8C2F,0x8C32,0x8C33,0x8C35,0x8C36,/* 0xD8-0xDF */ - 0x5369,0x537A,0x961D,0x9622,0x9621,0x9631,0x962A,0x963D,/* 0xE0-0xE7 */ - 0x963C,0x9642,0x9649,0x9654,0x965F,0x9667,0x966C,0x9672,/* 0xE8-0xEF */ - 0x9674,0x9688,0x968D,0x9697,0x96B0,0x9097,0x909B,0x909D,/* 0xF0-0xF7 */ - 0x9099,0x90AC,0x90A1,0x90B4,0x90B3,0x90B6,0x90BA,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_DB[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8DD5,0x8DD8,0x8DD9,0x8DDC,0x8DE0,0x8DE1,0x8DE2,0x8DE5,/* 0x40-0x47 */ - 0x8DE6,0x8DE7,0x8DE9,0x8DED,0x8DEE,0x8DF0,0x8DF1,0x8DF2,/* 0x48-0x4F */ - 0x8DF4,0x8DF6,0x8DFC,0x8DFE,0x8DFF,0x8E00,0x8E01,0x8E02,/* 0x50-0x57 */ - 0x8E03,0x8E04,0x8E06,0x8E07,0x8E08,0x8E0B,0x8E0D,0x8E0E,/* 0x58-0x5F */ - 0x8E10,0x8E11,0x8E12,0x8E13,0x8E15,0x8E16,0x8E17,0x8E18,/* 0x60-0x67 */ - 0x8E19,0x8E1A,0x8E1B,0x8E1C,0x8E20,0x8E21,0x8E24,0x8E25,/* 0x68-0x6F */ - 0x8E26,0x8E27,0x8E28,0x8E2B,0x8E2D,0x8E30,0x8E32,0x8E33,/* 0x70-0x77 */ - 0x8E34,0x8E36,0x8E37,0x8E38,0x8E3B,0x8E3C,0x8E3E,0x0000,/* 0x78-0x7F */ - - 0x8E3F,0x8E43,0x8E45,0x8E46,0x8E4C,0x8E4D,0x8E4E,0x8E4F,/* 0x80-0x87 */ - 0x8E50,0x8E53,0x8E54,0x8E55,0x8E56,0x8E57,0x8E58,0x8E5A,/* 0x88-0x8F */ - 0x8E5B,0x8E5C,0x8E5D,0x8E5E,0x8E5F,0x8E60,0x8E61,0x8E62,/* 0x90-0x97 */ - 0x8E63,0x8E64,0x8E65,0x8E67,0x8E68,0x8E6A,0x8E6B,0x8E6E,/* 0x98-0x9F */ - 0x8E71,0x90B8,0x90B0,0x90CF,0x90C5,0x90BE,0x90D0,0x90C4,/* 0xA0-0xA7 */ - 0x90C7,0x90D3,0x90E6,0x90E2,0x90DC,0x90D7,0x90DB,0x90EB,/* 0xA8-0xAF */ - 0x90EF,0x90FE,0x9104,0x9122,0x911E,0x9123,0x9131,0x912F,/* 0xB0-0xB7 */ - 0x9139,0x9143,0x9146,0x520D,0x5942,0x52A2,0x52AC,0x52AD,/* 0xB8-0xBF */ - 0x52BE,0x54FF,0x52D0,0x52D6,0x52F0,0x53DF,0x71EE,0x77CD,/* 0xC0-0xC7 */ - 0x5EF4,0x51F5,0x51FC,0x9B2F,0x53B6,0x5F01,0x755A,0x5DEF,/* 0xC8-0xCF */ - 0x574C,0x57A9,0x57A1,0x587E,0x58BC,0x58C5,0x58D1,0x5729,/* 0xD0-0xD7 */ - 0x572C,0x572A,0x5733,0x5739,0x572E,0x572F,0x575C,0x573B,/* 0xD8-0xDF */ - 0x5742,0x5769,0x5785,0x576B,0x5786,0x577C,0x577B,0x5768,/* 0xE0-0xE7 */ - 0x576D,0x5776,0x5773,0x57AD,0x57A4,0x578C,0x57B2,0x57CF,/* 0xE8-0xEF */ - 0x57A7,0x57B4,0x5793,0x57A0,0x57D5,0x57D8,0x57DA,0x57D9,/* 0xF0-0xF7 */ - 0x57D2,0x57B8,0x57F4,0x57EF,0x57F8,0x57E4,0x57DD,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_DC[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8E73,0x8E75,0x8E77,0x8E78,0x8E79,0x8E7A,0x8E7B,0x8E7D,/* 0x40-0x47 */ - 0x8E7E,0x8E80,0x8E82,0x8E83,0x8E84,0x8E86,0x8E88,0x8E89,/* 0x48-0x4F */ - 0x8E8A,0x8E8B,0x8E8C,0x8E8D,0x8E8E,0x8E91,0x8E92,0x8E93,/* 0x50-0x57 */ - 0x8E95,0x8E96,0x8E97,0x8E98,0x8E99,0x8E9A,0x8E9B,0x8E9D,/* 0x58-0x5F */ - 0x8E9F,0x8EA0,0x8EA1,0x8EA2,0x8EA3,0x8EA4,0x8EA5,0x8EA6,/* 0x60-0x67 */ - 0x8EA7,0x8EA8,0x8EA9,0x8EAA,0x8EAD,0x8EAE,0x8EB0,0x8EB1,/* 0x68-0x6F */ - 0x8EB3,0x8EB4,0x8EB5,0x8EB6,0x8EB7,0x8EB8,0x8EB9,0x8EBB,/* 0x70-0x77 */ - 0x8EBC,0x8EBD,0x8EBE,0x8EBF,0x8EC0,0x8EC1,0x8EC2,0x0000,/* 0x78-0x7F */ - - 0x8EC3,0x8EC4,0x8EC5,0x8EC6,0x8EC7,0x8EC8,0x8EC9,0x8ECA,/* 0x80-0x87 */ - 0x8ECB,0x8ECC,0x8ECD,0x8ECF,0x8ED0,0x8ED1,0x8ED2,0x8ED3,/* 0x88-0x8F */ - 0x8ED4,0x8ED5,0x8ED6,0x8ED7,0x8ED8,0x8ED9,0x8EDA,0x8EDB,/* 0x90-0x97 */ - 0x8EDC,0x8EDD,0x8EDE,0x8EDF,0x8EE0,0x8EE1,0x8EE2,0x8EE3,/* 0x98-0x9F */ - 0x8EE4,0x580B,0x580D,0x57FD,0x57ED,0x5800,0x581E,0x5819,/* 0xA0-0xA7 */ - 0x5844,0x5820,0x5865,0x586C,0x5881,0x5889,0x589A,0x5880,/* 0xA8-0xAF */ - 0x99A8,0x9F19,0x61FF,0x8279,0x827D,0x827F,0x828F,0x828A,/* 0xB0-0xB7 */ - 0x82A8,0x8284,0x828E,0x8291,0x8297,0x8299,0x82AB,0x82B8,/* 0xB8-0xBF */ - 0x82BE,0x82B0,0x82C8,0x82CA,0x82E3,0x8298,0x82B7,0x82AE,/* 0xC0-0xC7 */ - 0x82CB,0x82CC,0x82C1,0x82A9,0x82B4,0x82A1,0x82AA,0x829F,/* 0xC8-0xCF */ - 0x82C4,0x82CE,0x82A4,0x82E1,0x8309,0x82F7,0x82E4,0x830F,/* 0xD0-0xD7 */ - 0x8307,0x82DC,0x82F4,0x82D2,0x82D8,0x830C,0x82FB,0x82D3,/* 0xD8-0xDF */ - 0x8311,0x831A,0x8306,0x8314,0x8315,0x82E0,0x82D5,0x831C,/* 0xE0-0xE7 */ - 0x8351,0x835B,0x835C,0x8308,0x8392,0x833C,0x8334,0x8331,/* 0xE8-0xEF */ - 0x839B,0x835E,0x832F,0x834F,0x8347,0x8343,0x835F,0x8340,/* 0xF0-0xF7 */ - 0x8317,0x8360,0x832D,0x833A,0x8333,0x8366,0x8365,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_DD[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8EE5,0x8EE6,0x8EE7,0x8EE8,0x8EE9,0x8EEA,0x8EEB,0x8EEC,/* 0x40-0x47 */ - 0x8EED,0x8EEE,0x8EEF,0x8EF0,0x8EF1,0x8EF2,0x8EF3,0x8EF4,/* 0x48-0x4F */ - 0x8EF5,0x8EF6,0x8EF7,0x8EF8,0x8EF9,0x8EFA,0x8EFB,0x8EFC,/* 0x50-0x57 */ - 0x8EFD,0x8EFE,0x8EFF,0x8F00,0x8F01,0x8F02,0x8F03,0x8F04,/* 0x58-0x5F */ - 0x8F05,0x8F06,0x8F07,0x8F08,0x8F09,0x8F0A,0x8F0B,0x8F0C,/* 0x60-0x67 */ - 0x8F0D,0x8F0E,0x8F0F,0x8F10,0x8F11,0x8F12,0x8F13,0x8F14,/* 0x68-0x6F */ - 0x8F15,0x8F16,0x8F17,0x8F18,0x8F19,0x8F1A,0x8F1B,0x8F1C,/* 0x70-0x77 */ - 0x8F1D,0x8F1E,0x8F1F,0x8F20,0x8F21,0x8F22,0x8F23,0x0000,/* 0x78-0x7F */ - - 0x8F24,0x8F25,0x8F26,0x8F27,0x8F28,0x8F29,0x8F2A,0x8F2B,/* 0x80-0x87 */ - 0x8F2C,0x8F2D,0x8F2E,0x8F2F,0x8F30,0x8F31,0x8F32,0x8F33,/* 0x88-0x8F */ - 0x8F34,0x8F35,0x8F36,0x8F37,0x8F38,0x8F39,0x8F3A,0x8F3B,/* 0x90-0x97 */ - 0x8F3C,0x8F3D,0x8F3E,0x8F3F,0x8F40,0x8F41,0x8F42,0x8F43,/* 0x98-0x9F */ - 0x8F44,0x8368,0x831B,0x8369,0x836C,0x836A,0x836D,0x836E,/* 0xA0-0xA7 */ - 0x83B0,0x8378,0x83B3,0x83B4,0x83A0,0x83AA,0x8393,0x839C,/* 0xA8-0xAF */ - 0x8385,0x837C,0x83B6,0x83A9,0x837D,0x83B8,0x837B,0x8398,/* 0xB0-0xB7 */ - 0x839E,0x83A8,0x83BA,0x83BC,0x83C1,0x8401,0x83E5,0x83D8,/* 0xB8-0xBF */ - 0x5807,0x8418,0x840B,0x83DD,0x83FD,0x83D6,0x841C,0x8438,/* 0xC0-0xC7 */ - 0x8411,0x8406,0x83D4,0x83DF,0x840F,0x8403,0x83F8,0x83F9,/* 0xC8-0xCF */ - 0x83EA,0x83C5,0x83C0,0x8426,0x83F0,0x83E1,0x845C,0x8451,/* 0xD0-0xD7 */ - 0x845A,0x8459,0x8473,0x8487,0x8488,0x847A,0x8489,0x8478,/* 0xD8-0xDF */ - 0x843C,0x8446,0x8469,0x8476,0x848C,0x848E,0x8431,0x846D,/* 0xE0-0xE7 */ - 0x84C1,0x84CD,0x84D0,0x84E6,0x84BD,0x84D3,0x84CA,0x84BF,/* 0xE8-0xEF */ - 0x84BA,0x84E0,0x84A1,0x84B9,0x84B4,0x8497,0x84E5,0x84E3,/* 0xF0-0xF7 */ - 0x850C,0x750D,0x8538,0x84F0,0x8539,0x851F,0x853A,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_DE[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8F45,0x8F46,0x8F47,0x8F48,0x8F49,0x8F4A,0x8F4B,0x8F4C,/* 0x40-0x47 */ - 0x8F4D,0x8F4E,0x8F4F,0x8F50,0x8F51,0x8F52,0x8F53,0x8F54,/* 0x48-0x4F */ - 0x8F55,0x8F56,0x8F57,0x8F58,0x8F59,0x8F5A,0x8F5B,0x8F5C,/* 0x50-0x57 */ - 0x8F5D,0x8F5E,0x8F5F,0x8F60,0x8F61,0x8F62,0x8F63,0x8F64,/* 0x58-0x5F */ - 0x8F65,0x8F6A,0x8F80,0x8F8C,0x8F92,0x8F9D,0x8FA0,0x8FA1,/* 0x60-0x67 */ - 0x8FA2,0x8FA4,0x8FA5,0x8FA6,0x8FA7,0x8FAA,0x8FAC,0x8FAD,/* 0x68-0x6F */ - 0x8FAE,0x8FAF,0x8FB2,0x8FB3,0x8FB4,0x8FB5,0x8FB7,0x8FB8,/* 0x70-0x77 */ - 0x8FBA,0x8FBB,0x8FBC,0x8FBF,0x8FC0,0x8FC3,0x8FC6,0x0000,/* 0x78-0x7F */ - - 0x8FC9,0x8FCA,0x8FCB,0x8FCC,0x8FCD,0x8FCF,0x8FD2,0x8FD6,/* 0x80-0x87 */ - 0x8FD7,0x8FDA,0x8FE0,0x8FE1,0x8FE3,0x8FE7,0x8FEC,0x8FEF,/* 0x88-0x8F */ - 0x8FF1,0x8FF2,0x8FF4,0x8FF5,0x8FF6,0x8FFA,0x8FFB,0x8FFC,/* 0x90-0x97 */ - 0x8FFE,0x8FFF,0x9007,0x9008,0x900C,0x900E,0x9013,0x9015,/* 0x98-0x9F */ - 0x9018,0x8556,0x853B,0x84FF,0x84FC,0x8559,0x8548,0x8568,/* 0xA0-0xA7 */ - 0x8564,0x855E,0x857A,0x77A2,0x8543,0x8572,0x857B,0x85A4,/* 0xA8-0xAF */ - 0x85A8,0x8587,0x858F,0x8579,0x85AE,0x859C,0x8585,0x85B9,/* 0xB0-0xB7 */ - 0x85B7,0x85B0,0x85D3,0x85C1,0x85DC,0x85FF,0x8627,0x8605,/* 0xB8-0xBF */ - 0x8629,0x8616,0x863C,0x5EFE,0x5F08,0x593C,0x5941,0x8037,/* 0xC0-0xC7 */ - 0x5955,0x595A,0x5958,0x530F,0x5C22,0x5C25,0x5C2C,0x5C34,/* 0xC8-0xCF */ - 0x624C,0x626A,0x629F,0x62BB,0x62CA,0x62DA,0x62D7,0x62EE,/* 0xD0-0xD7 */ - 0x6322,0x62F6,0x6339,0x634B,0x6343,0x63AD,0x63F6,0x6371,/* 0xD8-0xDF */ - 0x637A,0x638E,0x63B4,0x636D,0x63AC,0x638A,0x6369,0x63AE,/* 0xE0-0xE7 */ - 0x63BC,0x63F2,0x63F8,0x63E0,0x63FF,0x63C4,0x63DE,0x63CE,/* 0xE8-0xEF */ - 0x6452,0x63C6,0x63BE,0x6445,0x6441,0x640B,0x641B,0x6420,/* 0xF0-0xF7 */ - 0x640C,0x6426,0x6421,0x645E,0x6484,0x646D,0x6496,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_DF[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9019,0x901C,0x9023,0x9024,0x9025,0x9027,0x9028,0x9029,/* 0x40-0x47 */ - 0x902A,0x902B,0x902C,0x9030,0x9031,0x9032,0x9033,0x9034,/* 0x48-0x4F */ - 0x9037,0x9039,0x903A,0x903D,0x903F,0x9040,0x9043,0x9045,/* 0x50-0x57 */ - 0x9046,0x9048,0x9049,0x904A,0x904B,0x904C,0x904E,0x9054,/* 0x58-0x5F */ - 0x9055,0x9056,0x9059,0x905A,0x905C,0x905D,0x905E,0x905F,/* 0x60-0x67 */ - 0x9060,0x9061,0x9064,0x9066,0x9067,0x9069,0x906A,0x906B,/* 0x68-0x6F */ - 0x906C,0x906F,0x9070,0x9071,0x9072,0x9073,0x9076,0x9077,/* 0x70-0x77 */ - 0x9078,0x9079,0x907A,0x907B,0x907C,0x907E,0x9081,0x0000,/* 0x78-0x7F */ - - 0x9084,0x9085,0x9086,0x9087,0x9089,0x908A,0x908C,0x908D,/* 0x80-0x87 */ - 0x908E,0x908F,0x9090,0x9092,0x9094,0x9096,0x9098,0x909A,/* 0x88-0x8F */ - 0x909C,0x909E,0x909F,0x90A0,0x90A4,0x90A5,0x90A7,0x90A8,/* 0x90-0x97 */ - 0x90A9,0x90AB,0x90AD,0x90B2,0x90B7,0x90BC,0x90BD,0x90BF,/* 0x98-0x9F */ - 0x90C0,0x647A,0x64B7,0x64B8,0x6499,0x64BA,0x64C0,0x64D0,/* 0xA0-0xA7 */ - 0x64D7,0x64E4,0x64E2,0x6509,0x6525,0x652E,0x5F0B,0x5FD2,/* 0xA8-0xAF */ - 0x7519,0x5F11,0x535F,0x53F1,0x53FD,0x53E9,0x53E8,0x53FB,/* 0xB0-0xB7 */ - 0x5412,0x5416,0x5406,0x544B,0x5452,0x5453,0x5454,0x5456,/* 0xB8-0xBF */ - 0x5443,0x5421,0x5457,0x5459,0x5423,0x5432,0x5482,0x5494,/* 0xC0-0xC7 */ - 0x5477,0x5471,0x5464,0x549A,0x549B,0x5484,0x5476,0x5466,/* 0xC8-0xCF */ - 0x549D,0x54D0,0x54AD,0x54C2,0x54B4,0x54D2,0x54A7,0x54A6,/* 0xD0-0xD7 */ - 0x54D3,0x54D4,0x5472,0x54A3,0x54D5,0x54BB,0x54BF,0x54CC,/* 0xD8-0xDF */ - 0x54D9,0x54DA,0x54DC,0x54A9,0x54AA,0x54A4,0x54DD,0x54CF,/* 0xE0-0xE7 */ - 0x54DE,0x551B,0x54E7,0x5520,0x54FD,0x5514,0x54F3,0x5522,/* 0xE8-0xEF */ - 0x5523,0x550F,0x5511,0x5527,0x552A,0x5567,0x558F,0x55B5,/* 0xF0-0xF7 */ - 0x5549,0x556D,0x5541,0x5555,0x553F,0x5550,0x553C,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E0[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x90C2,0x90C3,0x90C6,0x90C8,0x90C9,0x90CB,0x90CC,0x90CD,/* 0x40-0x47 */ - 0x90D2,0x90D4,0x90D5,0x90D6,0x90D8,0x90D9,0x90DA,0x90DE,/* 0x48-0x4F */ - 0x90DF,0x90E0,0x90E3,0x90E4,0x90E5,0x90E9,0x90EA,0x90EC,/* 0x50-0x57 */ - 0x90EE,0x90F0,0x90F1,0x90F2,0x90F3,0x90F5,0x90F6,0x90F7,/* 0x58-0x5F */ - 0x90F9,0x90FA,0x90FB,0x90FC,0x90FF,0x9100,0x9101,0x9103,/* 0x60-0x67 */ - 0x9105,0x9106,0x9107,0x9108,0x9109,0x910A,0x910B,0x910C,/* 0x68-0x6F */ - 0x910D,0x910E,0x910F,0x9110,0x9111,0x9112,0x9113,0x9114,/* 0x70-0x77 */ - 0x9115,0x9116,0x9117,0x9118,0x911A,0x911B,0x911C,0x0000,/* 0x78-0x7F */ - - 0x911D,0x911F,0x9120,0x9121,0x9124,0x9125,0x9126,0x9127,/* 0x80-0x87 */ - 0x9128,0x9129,0x912A,0x912B,0x912C,0x912D,0x912E,0x9130,/* 0x88-0x8F */ - 0x9132,0x9133,0x9134,0x9135,0x9136,0x9137,0x9138,0x913A,/* 0x90-0x97 */ - 0x913B,0x913C,0x913D,0x913E,0x913F,0x9140,0x9141,0x9142,/* 0x98-0x9F */ - 0x9144,0x5537,0x5556,0x5575,0x5576,0x5577,0x5533,0x5530,/* 0xA0-0xA7 */ - 0x555C,0x558B,0x55D2,0x5583,0x55B1,0x55B9,0x5588,0x5581,/* 0xA8-0xAF */ - 0x559F,0x557E,0x55D6,0x5591,0x557B,0x55DF,0x55BD,0x55BE,/* 0xB0-0xB7 */ - 0x5594,0x5599,0x55EA,0x55F7,0x55C9,0x561F,0x55D1,0x55EB,/* 0xB8-0xBF */ - 0x55EC,0x55D4,0x55E6,0x55DD,0x55C4,0x55EF,0x55E5,0x55F2,/* 0xC0-0xC7 */ - 0x55F3,0x55CC,0x55CD,0x55E8,0x55F5,0x55E4,0x8F94,0x561E,/* 0xC8-0xCF */ - 0x5608,0x560C,0x5601,0x5624,0x5623,0x55FE,0x5600,0x5627,/* 0xD0-0xD7 */ - 0x562D,0x5658,0x5639,0x5657,0x562C,0x564D,0x5662,0x5659,/* 0xD8-0xDF */ - 0x565C,0x564C,0x5654,0x5686,0x5664,0x5671,0x566B,0x567B,/* 0xE0-0xE7 */ - 0x567C,0x5685,0x5693,0x56AF,0x56D4,0x56D7,0x56DD,0x56E1,/* 0xE8-0xEF */ - 0x56F5,0x56EB,0x56F9,0x56FF,0x5704,0x570A,0x5709,0x571C,/* 0xF0-0xF7 */ - 0x5E0F,0x5E19,0x5E14,0x5E11,0x5E31,0x5E3B,0x5E3C,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9145,0x9147,0x9148,0x9151,0x9153,0x9154,0x9155,0x9156,/* 0x40-0x47 */ - 0x9158,0x9159,0x915B,0x915C,0x915F,0x9160,0x9166,0x9167,/* 0x48-0x4F */ - 0x9168,0x916B,0x916D,0x9173,0x917A,0x917B,0x917C,0x9180,/* 0x50-0x57 */ - 0x9181,0x9182,0x9183,0x9184,0x9186,0x9188,0x918A,0x918E,/* 0x58-0x5F */ - 0x918F,0x9193,0x9194,0x9195,0x9196,0x9197,0x9198,0x9199,/* 0x60-0x67 */ - 0x919C,0x919D,0x919E,0x919F,0x91A0,0x91A1,0x91A4,0x91A5,/* 0x68-0x6F */ - 0x91A6,0x91A7,0x91A8,0x91A9,0x91AB,0x91AC,0x91B0,0x91B1,/* 0x70-0x77 */ - 0x91B2,0x91B3,0x91B6,0x91B7,0x91B8,0x91B9,0x91BB,0x0000,/* 0x78-0x7F */ - - 0x91BC,0x91BD,0x91BE,0x91BF,0x91C0,0x91C1,0x91C2,0x91C3,/* 0x80-0x87 */ - 0x91C4,0x91C5,0x91C6,0x91C8,0x91CB,0x91D0,0x91D2,0x91D3,/* 0x88-0x8F */ - 0x91D4,0x91D5,0x91D6,0x91D7,0x91D8,0x91D9,0x91DA,0x91DB,/* 0x90-0x97 */ - 0x91DD,0x91DE,0x91DF,0x91E0,0x91E1,0x91E2,0x91E3,0x91E4,/* 0x98-0x9F */ - 0x91E5,0x5E37,0x5E44,0x5E54,0x5E5B,0x5E5E,0x5E61,0x5C8C,/* 0xA0-0xA7 */ - 0x5C7A,0x5C8D,0x5C90,0x5C96,0x5C88,0x5C98,0x5C99,0x5C91,/* 0xA8-0xAF */ - 0x5C9A,0x5C9C,0x5CB5,0x5CA2,0x5CBD,0x5CAC,0x5CAB,0x5CB1,/* 0xB0-0xB7 */ - 0x5CA3,0x5CC1,0x5CB7,0x5CC4,0x5CD2,0x5CE4,0x5CCB,0x5CE5,/* 0xB8-0xBF */ - 0x5D02,0x5D03,0x5D27,0x5D26,0x5D2E,0x5D24,0x5D1E,0x5D06,/* 0xC0-0xC7 */ - 0x5D1B,0x5D58,0x5D3E,0x5D34,0x5D3D,0x5D6C,0x5D5B,0x5D6F,/* 0xC8-0xCF */ - 0x5D5D,0x5D6B,0x5D4B,0x5D4A,0x5D69,0x5D74,0x5D82,0x5D99,/* 0xD0-0xD7 */ - 0x5D9D,0x8C73,0x5DB7,0x5DC5,0x5F73,0x5F77,0x5F82,0x5F87,/* 0xD8-0xDF */ - 0x5F89,0x5F8C,0x5F95,0x5F99,0x5F9C,0x5FA8,0x5FAD,0x5FB5,/* 0xE0-0xE7 */ - 0x5FBC,0x8862,0x5F61,0x72AD,0x72B0,0x72B4,0x72B7,0x72B8,/* 0xE8-0xEF */ - 0x72C3,0x72C1,0x72CE,0x72CD,0x72D2,0x72E8,0x72EF,0x72E9,/* 0xF0-0xF7 */ - 0x72F2,0x72F4,0x72F7,0x7301,0x72F3,0x7303,0x72FA,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x91E6,0x91E7,0x91E8,0x91E9,0x91EA,0x91EB,0x91EC,0x91ED,/* 0x40-0x47 */ - 0x91EE,0x91EF,0x91F0,0x91F1,0x91F2,0x91F3,0x91F4,0x91F5,/* 0x48-0x4F */ - 0x91F6,0x91F7,0x91F8,0x91F9,0x91FA,0x91FB,0x91FC,0x91FD,/* 0x50-0x57 */ - 0x91FE,0x91FF,0x9200,0x9201,0x9202,0x9203,0x9204,0x9205,/* 0x58-0x5F */ - 0x9206,0x9207,0x9208,0x9209,0x920A,0x920B,0x920C,0x920D,/* 0x60-0x67 */ - 0x920E,0x920F,0x9210,0x9211,0x9212,0x9213,0x9214,0x9215,/* 0x68-0x6F */ - 0x9216,0x9217,0x9218,0x9219,0x921A,0x921B,0x921C,0x921D,/* 0x70-0x77 */ - 0x921E,0x921F,0x9220,0x9221,0x9222,0x9223,0x9224,0x0000,/* 0x78-0x7F */ - - 0x9225,0x9226,0x9227,0x9228,0x9229,0x922A,0x922B,0x922C,/* 0x80-0x87 */ - 0x922D,0x922E,0x922F,0x9230,0x9231,0x9232,0x9233,0x9234,/* 0x88-0x8F */ - 0x9235,0x9236,0x9237,0x9238,0x9239,0x923A,0x923B,0x923C,/* 0x90-0x97 */ - 0x923D,0x923E,0x923F,0x9240,0x9241,0x9242,0x9243,0x9244,/* 0x98-0x9F */ - 0x9245,0x72FB,0x7317,0x7313,0x7321,0x730A,0x731E,0x731D,/* 0xA0-0xA7 */ - 0x7315,0x7322,0x7339,0x7325,0x732C,0x7338,0x7331,0x7350,/* 0xA8-0xAF */ - 0x734D,0x7357,0x7360,0x736C,0x736F,0x737E,0x821B,0x5925,/* 0xB0-0xB7 */ - 0x98E7,0x5924,0x5902,0x9963,0x9967,0x9968,0x9969,0x996A,/* 0xB8-0xBF */ - 0x996B,0x996C,0x9974,0x9977,0x997D,0x9980,0x9984,0x9987,/* 0xC0-0xC7 */ - 0x998A,0x998D,0x9990,0x9991,0x9993,0x9994,0x9995,0x5E80,/* 0xC8-0xCF */ - 0x5E91,0x5E8B,0x5E96,0x5EA5,0x5EA0,0x5EB9,0x5EB5,0x5EBE,/* 0xD0-0xD7 */ - 0x5EB3,0x8D53,0x5ED2,0x5ED1,0x5EDB,0x5EE8,0x5EEA,0x81BA,/* 0xD8-0xDF */ - 0x5FC4,0x5FC9,0x5FD6,0x5FCF,0x6003,0x5FEE,0x6004,0x5FE1,/* 0xE0-0xE7 */ - 0x5FE4,0x5FFE,0x6005,0x6006,0x5FEA,0x5FED,0x5FF8,0x6019,/* 0xE8-0xEF */ - 0x6035,0x6026,0x601B,0x600F,0x600D,0x6029,0x602B,0x600A,/* 0xF0-0xF7 */ - 0x603F,0x6021,0x6078,0x6079,0x607B,0x607A,0x6042,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9246,0x9247,0x9248,0x9249,0x924A,0x924B,0x924C,0x924D,/* 0x40-0x47 */ - 0x924E,0x924F,0x9250,0x9251,0x9252,0x9253,0x9254,0x9255,/* 0x48-0x4F */ - 0x9256,0x9257,0x9258,0x9259,0x925A,0x925B,0x925C,0x925D,/* 0x50-0x57 */ - 0x925E,0x925F,0x9260,0x9261,0x9262,0x9263,0x9264,0x9265,/* 0x58-0x5F */ - 0x9266,0x9267,0x9268,0x9269,0x926A,0x926B,0x926C,0x926D,/* 0x60-0x67 */ - 0x926E,0x926F,0x9270,0x9271,0x9272,0x9273,0x9275,0x9276,/* 0x68-0x6F */ - 0x9277,0x9278,0x9279,0x927A,0x927B,0x927C,0x927D,0x927E,/* 0x70-0x77 */ - 0x927F,0x9280,0x9281,0x9282,0x9283,0x9284,0x9285,0x0000,/* 0x78-0x7F */ - - 0x9286,0x9287,0x9288,0x9289,0x928A,0x928B,0x928C,0x928D,/* 0x80-0x87 */ - 0x928F,0x9290,0x9291,0x9292,0x9293,0x9294,0x9295,0x9296,/* 0x88-0x8F */ - 0x9297,0x9298,0x9299,0x929A,0x929B,0x929C,0x929D,0x929E,/* 0x90-0x97 */ - 0x929F,0x92A0,0x92A1,0x92A2,0x92A3,0x92A4,0x92A5,0x92A6,/* 0x98-0x9F */ - 0x92A7,0x606A,0x607D,0x6096,0x609A,0x60AD,0x609D,0x6083,/* 0xA0-0xA7 */ - 0x6092,0x608C,0x609B,0x60EC,0x60BB,0x60B1,0x60DD,0x60D8,/* 0xA8-0xAF */ - 0x60C6,0x60DA,0x60B4,0x6120,0x6126,0x6115,0x6123,0x60F4,/* 0xB0-0xB7 */ - 0x6100,0x610E,0x612B,0x614A,0x6175,0x61AC,0x6194,0x61A7,/* 0xB8-0xBF */ - 0x61B7,0x61D4,0x61F5,0x5FDD,0x96B3,0x95E9,0x95EB,0x95F1,/* 0xC0-0xC7 */ - 0x95F3,0x95F5,0x95F6,0x95FC,0x95FE,0x9603,0x9604,0x9606,/* 0xC8-0xCF */ - 0x9608,0x960A,0x960B,0x960C,0x960D,0x960F,0x9612,0x9615,/* 0xD0-0xD7 */ - 0x9616,0x9617,0x9619,0x961A,0x4E2C,0x723F,0x6215,0x6C35,/* 0xD8-0xDF */ - 0x6C54,0x6C5C,0x6C4A,0x6CA3,0x6C85,0x6C90,0x6C94,0x6C8C,/* 0xE0-0xE7 */ - 0x6C68,0x6C69,0x6C74,0x6C76,0x6C86,0x6CA9,0x6CD0,0x6CD4,/* 0xE8-0xEF */ - 0x6CAD,0x6CF7,0x6CF8,0x6CF1,0x6CD7,0x6CB2,0x6CE0,0x6CD6,/* 0xF0-0xF7 */ - 0x6CFA,0x6CEB,0x6CEE,0x6CB1,0x6CD3,0x6CEF,0x6CFE,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x92A8,0x92A9,0x92AA,0x92AB,0x92AC,0x92AD,0x92AF,0x92B0,/* 0x40-0x47 */ - 0x92B1,0x92B2,0x92B3,0x92B4,0x92B5,0x92B6,0x92B7,0x92B8,/* 0x48-0x4F */ - 0x92B9,0x92BA,0x92BB,0x92BC,0x92BD,0x92BE,0x92BF,0x92C0,/* 0x50-0x57 */ - 0x92C1,0x92C2,0x92C3,0x92C4,0x92C5,0x92C6,0x92C7,0x92C9,/* 0x58-0x5F */ - 0x92CA,0x92CB,0x92CC,0x92CD,0x92CE,0x92CF,0x92D0,0x92D1,/* 0x60-0x67 */ - 0x92D2,0x92D3,0x92D4,0x92D5,0x92D6,0x92D7,0x92D8,0x92D9,/* 0x68-0x6F */ - 0x92DA,0x92DB,0x92DC,0x92DD,0x92DE,0x92DF,0x92E0,0x92E1,/* 0x70-0x77 */ - 0x92E2,0x92E3,0x92E4,0x92E5,0x92E6,0x92E7,0x92E8,0x0000,/* 0x78-0x7F */ - - 0x92E9,0x92EA,0x92EB,0x92EC,0x92ED,0x92EE,0x92EF,0x92F0,/* 0x80-0x87 */ - 0x92F1,0x92F2,0x92F3,0x92F4,0x92F5,0x92F6,0x92F7,0x92F8,/* 0x88-0x8F */ - 0x92F9,0x92FA,0x92FB,0x92FC,0x92FD,0x92FE,0x92FF,0x9300,/* 0x90-0x97 */ - 0x9301,0x9302,0x9303,0x9304,0x9305,0x9306,0x9307,0x9308,/* 0x98-0x9F */ - 0x9309,0x6D39,0x6D27,0x6D0C,0x6D43,0x6D48,0x6D07,0x6D04,/* 0xA0-0xA7 */ - 0x6D19,0x6D0E,0x6D2B,0x6D4D,0x6D2E,0x6D35,0x6D1A,0x6D4F,/* 0xA8-0xAF */ - 0x6D52,0x6D54,0x6D33,0x6D91,0x6D6F,0x6D9E,0x6DA0,0x6D5E,/* 0xB0-0xB7 */ - 0x6D93,0x6D94,0x6D5C,0x6D60,0x6D7C,0x6D63,0x6E1A,0x6DC7,/* 0xB8-0xBF */ - 0x6DC5,0x6DDE,0x6E0E,0x6DBF,0x6DE0,0x6E11,0x6DE6,0x6DDD,/* 0xC0-0xC7 */ - 0x6DD9,0x6E16,0x6DAB,0x6E0C,0x6DAE,0x6E2B,0x6E6E,0x6E4E,/* 0xC8-0xCF */ - 0x6E6B,0x6EB2,0x6E5F,0x6E86,0x6E53,0x6E54,0x6E32,0x6E25,/* 0xD0-0xD7 */ - 0x6E44,0x6EDF,0x6EB1,0x6E98,0x6EE0,0x6F2D,0x6EE2,0x6EA5,/* 0xD8-0xDF */ - 0x6EA7,0x6EBD,0x6EBB,0x6EB7,0x6ED7,0x6EB4,0x6ECF,0x6E8F,/* 0xE0-0xE7 */ - 0x6EC2,0x6E9F,0x6F62,0x6F46,0x6F47,0x6F24,0x6F15,0x6EF9,/* 0xE8-0xEF */ - 0x6F2F,0x6F36,0x6F4B,0x6F74,0x6F2A,0x6F09,0x6F29,0x6F89,/* 0xF0-0xF7 */ - 0x6F8D,0x6F8C,0x6F78,0x6F72,0x6F7C,0x6F7A,0x6FD1,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x930A,0x930B,0x930C,0x930D,0x930E,0x930F,0x9310,0x9311,/* 0x40-0x47 */ - 0x9312,0x9313,0x9314,0x9315,0x9316,0x9317,0x9318,0x9319,/* 0x48-0x4F */ - 0x931A,0x931B,0x931C,0x931D,0x931E,0x931F,0x9320,0x9321,/* 0x50-0x57 */ - 0x9322,0x9323,0x9324,0x9325,0x9326,0x9327,0x9328,0x9329,/* 0x58-0x5F */ - 0x932A,0x932B,0x932C,0x932D,0x932E,0x932F,0x9330,0x9331,/* 0x60-0x67 */ - 0x9332,0x9333,0x9334,0x9335,0x9336,0x9337,0x9338,0x9339,/* 0x68-0x6F */ - 0x933A,0x933B,0x933C,0x933D,0x933F,0x9340,0x9341,0x9342,/* 0x70-0x77 */ - 0x9343,0x9344,0x9345,0x9346,0x9347,0x9348,0x9349,0x0000,/* 0x78-0x7F */ - - 0x934A,0x934B,0x934C,0x934D,0x934E,0x934F,0x9350,0x9351,/* 0x80-0x87 */ - 0x9352,0x9353,0x9354,0x9355,0x9356,0x9357,0x9358,0x9359,/* 0x88-0x8F */ - 0x935A,0x935B,0x935C,0x935D,0x935E,0x935F,0x9360,0x9361,/* 0x90-0x97 */ - 0x9362,0x9363,0x9364,0x9365,0x9366,0x9367,0x9368,0x9369,/* 0x98-0x9F */ - 0x936B,0x6FC9,0x6FA7,0x6FB9,0x6FB6,0x6FC2,0x6FE1,0x6FEE,/* 0xA0-0xA7 */ - 0x6FDE,0x6FE0,0x6FEF,0x701A,0x7023,0x701B,0x7039,0x7035,/* 0xA8-0xAF */ - 0x704F,0x705E,0x5B80,0x5B84,0x5B95,0x5B93,0x5BA5,0x5BB8,/* 0xB0-0xB7 */ - 0x752F,0x9A9E,0x6434,0x5BE4,0x5BEE,0x8930,0x5BF0,0x8E47,/* 0xB8-0xBF */ - 0x8B07,0x8FB6,0x8FD3,0x8FD5,0x8FE5,0x8FEE,0x8FE4,0x8FE9,/* 0xC0-0xC7 */ - 0x8FE6,0x8FF3,0x8FE8,0x9005,0x9004,0x900B,0x9026,0x9011,/* 0xC8-0xCF */ - 0x900D,0x9016,0x9021,0x9035,0x9036,0x902D,0x902F,0x9044,/* 0xD0-0xD7 */ - 0x9051,0x9052,0x9050,0x9068,0x9058,0x9062,0x905B,0x66B9,/* 0xD8-0xDF */ - 0x9074,0x907D,0x9082,0x9088,0x9083,0x908B,0x5F50,0x5F57,/* 0xE0-0xE7 */ - 0x5F56,0x5F58,0x5C3B,0x54AB,0x5C50,0x5C59,0x5B71,0x5C63,/* 0xE8-0xEF */ - 0x5C66,0x7FBC,0x5F2A,0x5F29,0x5F2D,0x8274,0x5F3C,0x9B3B,/* 0xF0-0xF7 */ - 0x5C6E,0x5981,0x5983,0x598D,0x59A9,0x59AA,0x59A3,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x936C,0x936D,0x936E,0x936F,0x9370,0x9371,0x9372,0x9373,/* 0x40-0x47 */ - 0x9374,0x9375,0x9376,0x9377,0x9378,0x9379,0x937A,0x937B,/* 0x48-0x4F */ - 0x937C,0x937D,0x937E,0x937F,0x9380,0x9381,0x9382,0x9383,/* 0x50-0x57 */ - 0x9384,0x9385,0x9386,0x9387,0x9388,0x9389,0x938A,0x938B,/* 0x58-0x5F */ - 0x938C,0x938D,0x938E,0x9390,0x9391,0x9392,0x9393,0x9394,/* 0x60-0x67 */ - 0x9395,0x9396,0x9397,0x9398,0x9399,0x939A,0x939B,0x939C,/* 0x68-0x6F */ - 0x939D,0x939E,0x939F,0x93A0,0x93A1,0x93A2,0x93A3,0x93A4,/* 0x70-0x77 */ - 0x93A5,0x93A6,0x93A7,0x93A8,0x93A9,0x93AA,0x93AB,0x0000,/* 0x78-0x7F */ - - 0x93AC,0x93AD,0x93AE,0x93AF,0x93B0,0x93B1,0x93B2,0x93B3,/* 0x80-0x87 */ - 0x93B4,0x93B5,0x93B6,0x93B7,0x93B8,0x93B9,0x93BA,0x93BB,/* 0x88-0x8F */ - 0x93BC,0x93BD,0x93BE,0x93BF,0x93C0,0x93C1,0x93C2,0x93C3,/* 0x90-0x97 */ - 0x93C4,0x93C5,0x93C6,0x93C7,0x93C8,0x93C9,0x93CB,0x93CC,/* 0x98-0x9F */ - 0x93CD,0x5997,0x59CA,0x59AB,0x599E,0x59A4,0x59D2,0x59B2,/* 0xA0-0xA7 */ - 0x59AF,0x59D7,0x59BE,0x5A05,0x5A06,0x59DD,0x5A08,0x59E3,/* 0xA8-0xAF */ - 0x59D8,0x59F9,0x5A0C,0x5A09,0x5A32,0x5A34,0x5A11,0x5A23,/* 0xB0-0xB7 */ - 0x5A13,0x5A40,0x5A67,0x5A4A,0x5A55,0x5A3C,0x5A62,0x5A75,/* 0xB8-0xBF */ - 0x80EC,0x5AAA,0x5A9B,0x5A77,0x5A7A,0x5ABE,0x5AEB,0x5AB2,/* 0xC0-0xC7 */ - 0x5AD2,0x5AD4,0x5AB8,0x5AE0,0x5AE3,0x5AF1,0x5AD6,0x5AE6,/* 0xC8-0xCF */ - 0x5AD8,0x5ADC,0x5B09,0x5B17,0x5B16,0x5B32,0x5B37,0x5B40,/* 0xD0-0xD7 */ - 0x5C15,0x5C1C,0x5B5A,0x5B65,0x5B73,0x5B51,0x5B53,0x5B62,/* 0xD8-0xDF */ - 0x9A75,0x9A77,0x9A78,0x9A7A,0x9A7F,0x9A7D,0x9A80,0x9A81,/* 0xE0-0xE7 */ - 0x9A85,0x9A88,0x9A8A,0x9A90,0x9A92,0x9A93,0x9A96,0x9A98,/* 0xE8-0xEF */ - 0x9A9B,0x9A9C,0x9A9D,0x9A9F,0x9AA0,0x9AA2,0x9AA3,0x9AA5,/* 0xF0-0xF7 */ - 0x9AA7,0x7E9F,0x7EA1,0x7EA3,0x7EA5,0x7EA8,0x7EA9,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E7[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x93CE,0x93CF,0x93D0,0x93D1,0x93D2,0x93D3,0x93D4,0x93D5,/* 0x40-0x47 */ - 0x93D7,0x93D8,0x93D9,0x93DA,0x93DB,0x93DC,0x93DD,0x93DE,/* 0x48-0x4F */ - 0x93DF,0x93E0,0x93E1,0x93E2,0x93E3,0x93E4,0x93E5,0x93E6,/* 0x50-0x57 */ - 0x93E7,0x93E8,0x93E9,0x93EA,0x93EB,0x93EC,0x93ED,0x93EE,/* 0x58-0x5F */ - 0x93EF,0x93F0,0x93F1,0x93F2,0x93F3,0x93F4,0x93F5,0x93F6,/* 0x60-0x67 */ - 0x93F7,0x93F8,0x93F9,0x93FA,0x93FB,0x93FC,0x93FD,0x93FE,/* 0x68-0x6F */ - 0x93FF,0x9400,0x9401,0x9402,0x9403,0x9404,0x9405,0x9406,/* 0x70-0x77 */ - 0x9407,0x9408,0x9409,0x940A,0x940B,0x940C,0x940D,0x0000,/* 0x78-0x7F */ - - 0x940E,0x940F,0x9410,0x9411,0x9412,0x9413,0x9414,0x9415,/* 0x80-0x87 */ - 0x9416,0x9417,0x9418,0x9419,0x941A,0x941B,0x941C,0x941D,/* 0x88-0x8F */ - 0x941E,0x941F,0x9420,0x9421,0x9422,0x9423,0x9424,0x9425,/* 0x90-0x97 */ - 0x9426,0x9427,0x9428,0x9429,0x942A,0x942B,0x942C,0x942D,/* 0x98-0x9F */ - 0x942E,0x7EAD,0x7EB0,0x7EBE,0x7EC0,0x7EC1,0x7EC2,0x7EC9,/* 0xA0-0xA7 */ - 0x7ECB,0x7ECC,0x7ED0,0x7ED4,0x7ED7,0x7EDB,0x7EE0,0x7EE1,/* 0xA8-0xAF */ - 0x7EE8,0x7EEB,0x7EEE,0x7EEF,0x7EF1,0x7EF2,0x7F0D,0x7EF6,/* 0xB0-0xB7 */ - 0x7EFA,0x7EFB,0x7EFE,0x7F01,0x7F02,0x7F03,0x7F07,0x7F08,/* 0xB8-0xBF */ - 0x7F0B,0x7F0C,0x7F0F,0x7F11,0x7F12,0x7F17,0x7F19,0x7F1C,/* 0xC0-0xC7 */ - 0x7F1B,0x7F1F,0x7F21,0x7F22,0x7F23,0x7F24,0x7F25,0x7F26,/* 0xC8-0xCF */ - 0x7F27,0x7F2A,0x7F2B,0x7F2C,0x7F2D,0x7F2F,0x7F30,0x7F31,/* 0xD0-0xD7 */ - 0x7F32,0x7F33,0x7F35,0x5E7A,0x757F,0x5DDB,0x753E,0x9095,/* 0xD8-0xDF */ - 0x738E,0x7391,0x73AE,0x73A2,0x739F,0x73CF,0x73C2,0x73D1,/* 0xE0-0xE7 */ - 0x73B7,0x73B3,0x73C0,0x73C9,0x73C8,0x73E5,0x73D9,0x987C,/* 0xE8-0xEF */ - 0x740A,0x73E9,0x73E7,0x73DE,0x73BA,0x73F2,0x740F,0x742A,/* 0xF0-0xF7 */ - 0x745B,0x7426,0x7425,0x7428,0x7430,0x742E,0x742C,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E8[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x942F,0x9430,0x9431,0x9432,0x9433,0x9434,0x9435,0x9436,/* 0x40-0x47 */ - 0x9437,0x9438,0x9439,0x943A,0x943B,0x943C,0x943D,0x943F,/* 0x48-0x4F */ - 0x9440,0x9441,0x9442,0x9443,0x9444,0x9445,0x9446,0x9447,/* 0x50-0x57 */ - 0x9448,0x9449,0x944A,0x944B,0x944C,0x944D,0x944E,0x944F,/* 0x58-0x5F */ - 0x9450,0x9451,0x9452,0x9453,0x9454,0x9455,0x9456,0x9457,/* 0x60-0x67 */ - 0x9458,0x9459,0x945A,0x945B,0x945C,0x945D,0x945E,0x945F,/* 0x68-0x6F */ - 0x9460,0x9461,0x9462,0x9463,0x9464,0x9465,0x9466,0x9467,/* 0x70-0x77 */ - 0x9468,0x9469,0x946A,0x946C,0x946D,0x946E,0x946F,0x0000,/* 0x78-0x7F */ - - 0x9470,0x9471,0x9472,0x9473,0x9474,0x9475,0x9476,0x9477,/* 0x80-0x87 */ - 0x9478,0x9479,0x947A,0x947B,0x947C,0x947D,0x947E,0x947F,/* 0x88-0x8F */ - 0x9480,0x9481,0x9482,0x9483,0x9484,0x9491,0x9496,0x9498,/* 0x90-0x97 */ - 0x94C7,0x94CF,0x94D3,0x94D4,0x94DA,0x94E6,0x94FB,0x951C,/* 0x98-0x9F */ - 0x9520,0x741B,0x741A,0x7441,0x745C,0x7457,0x7455,0x7459,/* 0xA0-0xA7 */ - 0x7477,0x746D,0x747E,0x749C,0x748E,0x7480,0x7481,0x7487,/* 0xA8-0xAF */ - 0x748B,0x749E,0x74A8,0x74A9,0x7490,0x74A7,0x74D2,0x74BA,/* 0xB0-0xB7 */ - 0x97EA,0x97EB,0x97EC,0x674C,0x6753,0x675E,0x6748,0x6769,/* 0xB8-0xBF */ - 0x67A5,0x6787,0x676A,0x6773,0x6798,0x67A7,0x6775,0x67A8,/* 0xC0-0xC7 */ - 0x679E,0x67AD,0x678B,0x6777,0x677C,0x67F0,0x6809,0x67D8,/* 0xC8-0xCF */ - 0x680A,0x67E9,0x67B0,0x680C,0x67D9,0x67B5,0x67DA,0x67B3,/* 0xD0-0xD7 */ - 0x67DD,0x6800,0x67C3,0x67B8,0x67E2,0x680E,0x67C1,0x67FD,/* 0xD8-0xDF */ - 0x6832,0x6833,0x6860,0x6861,0x684E,0x6862,0x6844,0x6864,/* 0xE0-0xE7 */ - 0x6883,0x681D,0x6855,0x6866,0x6841,0x6867,0x6840,0x683E,/* 0xE8-0xEF */ - 0x684A,0x6849,0x6829,0x68B5,0x688F,0x6874,0x6877,0x6893,/* 0xF0-0xF7 */ - 0x686B,0x68C2,0x696E,0x68FC,0x691F,0x6920,0x68F9,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E9[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9527,0x9533,0x953D,0x9543,0x9548,0x954B,0x9555,0x955A,/* 0x40-0x47 */ - 0x9560,0x956E,0x9574,0x9575,0x9577,0x9578,0x9579,0x957A,/* 0x48-0x4F */ - 0x957B,0x957C,0x957D,0x957E,0x9580,0x9581,0x9582,0x9583,/* 0x50-0x57 */ - 0x9584,0x9585,0x9586,0x9587,0x9588,0x9589,0x958A,0x958B,/* 0x58-0x5F */ - 0x958C,0x958D,0x958E,0x958F,0x9590,0x9591,0x9592,0x9593,/* 0x60-0x67 */ - 0x9594,0x9595,0x9596,0x9597,0x9598,0x9599,0x959A,0x959B,/* 0x68-0x6F */ - 0x959C,0x959D,0x959E,0x959F,0x95A0,0x95A1,0x95A2,0x95A3,/* 0x70-0x77 */ - 0x95A4,0x95A5,0x95A6,0x95A7,0x95A8,0x95A9,0x95AA,0x0000,/* 0x78-0x7F */ - - 0x95AB,0x95AC,0x95AD,0x95AE,0x95AF,0x95B0,0x95B1,0x95B2,/* 0x80-0x87 */ - 0x95B3,0x95B4,0x95B5,0x95B6,0x95B7,0x95B8,0x95B9,0x95BA,/* 0x88-0x8F */ - 0x95BB,0x95BC,0x95BD,0x95BE,0x95BF,0x95C0,0x95C1,0x95C2,/* 0x90-0x97 */ - 0x95C3,0x95C4,0x95C5,0x95C6,0x95C7,0x95C8,0x95C9,0x95CA,/* 0x98-0x9F */ - 0x95CB,0x6924,0x68F0,0x690B,0x6901,0x6957,0x68E3,0x6910,/* 0xA0-0xA7 */ - 0x6971,0x6939,0x6960,0x6942,0x695D,0x6984,0x696B,0x6980,/* 0xA8-0xAF */ - 0x6998,0x6978,0x6934,0x69CC,0x6987,0x6988,0x69CE,0x6989,/* 0xB0-0xB7 */ - 0x6966,0x6963,0x6979,0x699B,0x69A7,0x69BB,0x69AB,0x69AD,/* 0xB8-0xBF */ - 0x69D4,0x69B1,0x69C1,0x69CA,0x69DF,0x6995,0x69E0,0x698D,/* 0xC0-0xC7 */ - 0x69FF,0x6A2F,0x69ED,0x6A17,0x6A18,0x6A65,0x69F2,0x6A44,/* 0xC8-0xCF */ - 0x6A3E,0x6AA0,0x6A50,0x6A5B,0x6A35,0x6A8E,0x6A79,0x6A3D,/* 0xD0-0xD7 */ - 0x6A28,0x6A58,0x6A7C,0x6A91,0x6A90,0x6AA9,0x6A97,0x6AAB,/* 0xD8-0xDF */ - 0x7337,0x7352,0x6B81,0x6B82,0x6B87,0x6B84,0x6B92,0x6B93,/* 0xE0-0xE7 */ - 0x6B8D,0x6B9A,0x6B9B,0x6BA1,0x6BAA,0x8F6B,0x8F6D,0x8F71,/* 0xE8-0xEF */ - 0x8F72,0x8F73,0x8F75,0x8F76,0x8F78,0x8F77,0x8F79,0x8F7A,/* 0xF0-0xF7 */ - 0x8F7C,0x8F7E,0x8F81,0x8F82,0x8F84,0x8F87,0x8F8B,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_EA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x95CC,0x95CD,0x95CE,0x95CF,0x95D0,0x95D1,0x95D2,0x95D3,/* 0x40-0x47 */ - 0x95D4,0x95D5,0x95D6,0x95D7,0x95D8,0x95D9,0x95DA,0x95DB,/* 0x48-0x4F */ - 0x95DC,0x95DD,0x95DE,0x95DF,0x95E0,0x95E1,0x95E2,0x95E3,/* 0x50-0x57 */ - 0x95E4,0x95E5,0x95E6,0x95E7,0x95EC,0x95FF,0x9607,0x9613,/* 0x58-0x5F */ - 0x9618,0x961B,0x961E,0x9620,0x9623,0x9624,0x9625,0x9626,/* 0x60-0x67 */ - 0x9627,0x9628,0x9629,0x962B,0x962C,0x962D,0x962F,0x9630,/* 0x68-0x6F */ - 0x9637,0x9638,0x9639,0x963A,0x963E,0x9641,0x9643,0x964A,/* 0x70-0x77 */ - 0x964E,0x964F,0x9651,0x9652,0x9653,0x9656,0x9657,0x0000,/* 0x78-0x7F */ - - 0x9658,0x9659,0x965A,0x965C,0x965D,0x965E,0x9660,0x9663,/* 0x80-0x87 */ - 0x9665,0x9666,0x966B,0x966D,0x966E,0x966F,0x9670,0x9671,/* 0x88-0x8F */ - 0x9673,0x9678,0x9679,0x967A,0x967B,0x967C,0x967D,0x967E,/* 0x90-0x97 */ - 0x967F,0x9680,0x9681,0x9682,0x9683,0x9684,0x9687,0x9689,/* 0x98-0x9F */ - 0x968A,0x8F8D,0x8F8E,0x8F8F,0x8F98,0x8F9A,0x8ECE,0x620B,/* 0xA0-0xA7 */ - 0x6217,0x621B,0x621F,0x6222,0x6221,0x6225,0x6224,0x622C,/* 0xA8-0xAF */ - 0x81E7,0x74EF,0x74F4,0x74FF,0x750F,0x7511,0x7513,0x6534,/* 0xB0-0xB7 */ - 0x65EE,0x65EF,0x65F0,0x660A,0x6619,0x6772,0x6603,0x6615,/* 0xB8-0xBF */ - 0x6600,0x7085,0x66F7,0x661D,0x6634,0x6631,0x6636,0x6635,/* 0xC0-0xC7 */ - 0x8006,0x665F,0x6654,0x6641,0x664F,0x6656,0x6661,0x6657,/* 0xC8-0xCF */ - 0x6677,0x6684,0x668C,0x66A7,0x669D,0x66BE,0x66DB,0x66DC,/* 0xD0-0xD7 */ - 0x66E6,0x66E9,0x8D32,0x8D33,0x8D36,0x8D3B,0x8D3D,0x8D40,/* 0xD8-0xDF */ - 0x8D45,0x8D46,0x8D48,0x8D49,0x8D47,0x8D4D,0x8D55,0x8D59,/* 0xE0-0xE7 */ - 0x89C7,0x89CA,0x89CB,0x89CC,0x89CE,0x89CF,0x89D0,0x89D1,/* 0xE8-0xEF */ - 0x726E,0x729F,0x725D,0x7266,0x726F,0x727E,0x727F,0x7284,/* 0xF0-0xF7 */ - 0x728B,0x728D,0x728F,0x7292,0x6308,0x6332,0x63B0,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_EB[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x968C,0x968E,0x9691,0x9692,0x9693,0x9695,0x9696,0x969A,/* 0x40-0x47 */ - 0x969B,0x969D,0x969E,0x969F,0x96A0,0x96A1,0x96A2,0x96A3,/* 0x48-0x4F */ - 0x96A4,0x96A5,0x96A6,0x96A8,0x96A9,0x96AA,0x96AB,0x96AC,/* 0x50-0x57 */ - 0x96AD,0x96AE,0x96AF,0x96B1,0x96B2,0x96B4,0x96B5,0x96B7,/* 0x58-0x5F */ - 0x96B8,0x96BA,0x96BB,0x96BF,0x96C2,0x96C3,0x96C8,0x96CA,/* 0x60-0x67 */ - 0x96CB,0x96D0,0x96D1,0x96D3,0x96D4,0x96D6,0x96D7,0x96D8,/* 0x68-0x6F */ - 0x96D9,0x96DA,0x96DB,0x96DC,0x96DD,0x96DE,0x96DF,0x96E1,/* 0x70-0x77 */ - 0x96E2,0x96E3,0x96E4,0x96E5,0x96E6,0x96E7,0x96EB,0x0000,/* 0x78-0x7F */ - - 0x96EC,0x96ED,0x96EE,0x96F0,0x96F1,0x96F2,0x96F4,0x96F5,/* 0x80-0x87 */ - 0x96F8,0x96FA,0x96FB,0x96FC,0x96FD,0x96FF,0x9702,0x9703,/* 0x88-0x8F */ - 0x9705,0x970A,0x970B,0x970C,0x9710,0x9711,0x9712,0x9714,/* 0x90-0x97 */ - 0x9715,0x9717,0x9718,0x9719,0x971A,0x971B,0x971D,0x971F,/* 0x98-0x9F */ - 0x9720,0x643F,0x64D8,0x8004,0x6BEA,0x6BF3,0x6BFD,0x6BF5,/* 0xA0-0xA7 */ - 0x6BF9,0x6C05,0x6C07,0x6C06,0x6C0D,0x6C15,0x6C18,0x6C19,/* 0xA8-0xAF */ - 0x6C1A,0x6C21,0x6C29,0x6C24,0x6C2A,0x6C32,0x6535,0x6555,/* 0xB0-0xB7 */ - 0x656B,0x724D,0x7252,0x7256,0x7230,0x8662,0x5216,0x809F,/* 0xB8-0xBF */ - 0x809C,0x8093,0x80BC,0x670A,0x80BD,0x80B1,0x80AB,0x80AD,/* 0xC0-0xC7 */ - 0x80B4,0x80B7,0x80E7,0x80E8,0x80E9,0x80EA,0x80DB,0x80C2,/* 0xC8-0xCF */ - 0x80C4,0x80D9,0x80CD,0x80D7,0x6710,0x80DD,0x80EB,0x80F1,/* 0xD0-0xD7 */ - 0x80F4,0x80ED,0x810D,0x810E,0x80F2,0x80FC,0x6715,0x8112,/* 0xD8-0xDF */ - 0x8C5A,0x8136,0x811E,0x812C,0x8118,0x8132,0x8148,0x814C,/* 0xE0-0xE7 */ - 0x8153,0x8174,0x8159,0x815A,0x8171,0x8160,0x8169,0x817C,/* 0xE8-0xEF */ - 0x817D,0x816D,0x8167,0x584D,0x5AB5,0x8188,0x8182,0x8191,/* 0xF0-0xF7 */ - 0x6ED5,0x81A3,0x81AA,0x81CC,0x6726,0x81CA,0x81BB,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_EC[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9721,0x9722,0x9723,0x9724,0x9725,0x9726,0x9727,0x9728,/* 0x40-0x47 */ - 0x9729,0x972B,0x972C,0x972E,0x972F,0x9731,0x9733,0x9734,/* 0x48-0x4F */ - 0x9735,0x9736,0x9737,0x973A,0x973B,0x973C,0x973D,0x973F,/* 0x50-0x57 */ - 0x9740,0x9741,0x9742,0x9743,0x9744,0x9745,0x9746,0x9747,/* 0x58-0x5F */ - 0x9748,0x9749,0x974A,0x974B,0x974C,0x974D,0x974E,0x974F,/* 0x60-0x67 */ - 0x9750,0x9751,0x9754,0x9755,0x9757,0x9758,0x975A,0x975C,/* 0x68-0x6F */ - 0x975D,0x975F,0x9763,0x9764,0x9766,0x9767,0x9768,0x976A,/* 0x70-0x77 */ - 0x976B,0x976C,0x976D,0x976E,0x976F,0x9770,0x9771,0x0000,/* 0x78-0x7F */ - - 0x9772,0x9775,0x9777,0x9778,0x9779,0x977A,0x977B,0x977D,/* 0x80-0x87 */ - 0x977E,0x977F,0x9780,0x9781,0x9782,0x9783,0x9784,0x9786,/* 0x88-0x8F */ - 0x9787,0x9788,0x9789,0x978A,0x978C,0x978E,0x978F,0x9790,/* 0x90-0x97 */ - 0x9793,0x9795,0x9796,0x9797,0x9799,0x979A,0x979B,0x979C,/* 0x98-0x9F */ - 0x979D,0x81C1,0x81A6,0x6B24,0x6B37,0x6B39,0x6B43,0x6B46,/* 0xA0-0xA7 */ - 0x6B59,0x98D1,0x98D2,0x98D3,0x98D5,0x98D9,0x98DA,0x6BB3,/* 0xA8-0xAF */ - 0x5F40,0x6BC2,0x89F3,0x6590,0x9F51,0x6593,0x65BC,0x65C6,/* 0xB0-0xB7 */ - 0x65C4,0x65C3,0x65CC,0x65CE,0x65D2,0x65D6,0x7080,0x709C,/* 0xB8-0xBF */ - 0x7096,0x709D,0x70BB,0x70C0,0x70B7,0x70AB,0x70B1,0x70E8,/* 0xC0-0xC7 */ - 0x70CA,0x7110,0x7113,0x7116,0x712F,0x7131,0x7173,0x715C,/* 0xC8-0xCF */ - 0x7168,0x7145,0x7172,0x714A,0x7178,0x717A,0x7198,0x71B3,/* 0xD0-0xD7 */ - 0x71B5,0x71A8,0x71A0,0x71E0,0x71D4,0x71E7,0x71F9,0x721D,/* 0xD8-0xDF */ - 0x7228,0x706C,0x7118,0x7166,0x71B9,0x623E,0x623D,0x6243,/* 0xE0-0xE7 */ - 0x6248,0x6249,0x793B,0x7940,0x7946,0x7949,0x795B,0x795C,/* 0xE8-0xEF */ - 0x7953,0x795A,0x7962,0x7957,0x7960,0x796F,0x7967,0x797A,/* 0xF0-0xF7 */ - 0x7985,0x798A,0x799A,0x79A7,0x79B3,0x5FD1,0x5FD0,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_ED[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x979E,0x979F,0x97A1,0x97A2,0x97A4,0x97A5,0x97A6,0x97A7,/* 0x40-0x47 */ - 0x97A8,0x97A9,0x97AA,0x97AC,0x97AE,0x97B0,0x97B1,0x97B3,/* 0x48-0x4F */ - 0x97B5,0x97B6,0x97B7,0x97B8,0x97B9,0x97BA,0x97BB,0x97BC,/* 0x50-0x57 */ - 0x97BD,0x97BE,0x97BF,0x97C0,0x97C1,0x97C2,0x97C3,0x97C4,/* 0x58-0x5F */ - 0x97C5,0x97C6,0x97C7,0x97C8,0x97C9,0x97CA,0x97CB,0x97CC,/* 0x60-0x67 */ - 0x97CD,0x97CE,0x97CF,0x97D0,0x97D1,0x97D2,0x97D3,0x97D4,/* 0x68-0x6F */ - 0x97D5,0x97D6,0x97D7,0x97D8,0x97D9,0x97DA,0x97DB,0x97DC,/* 0x70-0x77 */ - 0x97DD,0x97DE,0x97DF,0x97E0,0x97E1,0x97E2,0x97E3,0x0000,/* 0x78-0x7F */ - - 0x97E4,0x97E5,0x97E8,0x97EE,0x97EF,0x97F0,0x97F1,0x97F2,/* 0x80-0x87 */ - 0x97F4,0x97F7,0x97F8,0x97F9,0x97FA,0x97FB,0x97FC,0x97FD,/* 0x88-0x8F */ - 0x97FE,0x97FF,0x9800,0x9801,0x9802,0x9803,0x9804,0x9805,/* 0x90-0x97 */ - 0x9806,0x9807,0x9808,0x9809,0x980A,0x980B,0x980C,0x980D,/* 0x98-0x9F */ - 0x980E,0x603C,0x605D,0x605A,0x6067,0x6041,0x6059,0x6063,/* 0xA0-0xA7 */ - 0x60AB,0x6106,0x610D,0x615D,0x61A9,0x619D,0x61CB,0x61D1,/* 0xA8-0xAF */ - 0x6206,0x8080,0x807F,0x6C93,0x6CF6,0x6DFC,0x77F6,0x77F8,/* 0xB0-0xB7 */ - 0x7800,0x7809,0x7817,0x7818,0x7811,0x65AB,0x782D,0x781C,/* 0xB8-0xBF */ - 0x781D,0x7839,0x783A,0x783B,0x781F,0x783C,0x7825,0x782C,/* 0xC0-0xC7 */ - 0x7823,0x7829,0x784E,0x786D,0x7856,0x7857,0x7826,0x7850,/* 0xC8-0xCF */ - 0x7847,0x784C,0x786A,0x789B,0x7893,0x789A,0x7887,0x789C,/* 0xD0-0xD7 */ - 0x78A1,0x78A3,0x78B2,0x78B9,0x78A5,0x78D4,0x78D9,0x78C9,/* 0xD8-0xDF */ - 0x78EC,0x78F2,0x7905,0x78F4,0x7913,0x7924,0x791E,0x7934,/* 0xE0-0xE7 */ - 0x9F9B,0x9EF9,0x9EFB,0x9EFC,0x76F1,0x7704,0x770D,0x76F9,/* 0xE8-0xEF */ - 0x7707,0x7708,0x771A,0x7722,0x7719,0x772D,0x7726,0x7735,/* 0xF0-0xF7 */ - 0x7738,0x7750,0x7751,0x7747,0x7743,0x775A,0x7768,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_EE[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x980F,0x9810,0x9811,0x9812,0x9813,0x9814,0x9815,0x9816,/* 0x40-0x47 */ - 0x9817,0x9818,0x9819,0x981A,0x981B,0x981C,0x981D,0x981E,/* 0x48-0x4F */ - 0x981F,0x9820,0x9821,0x9822,0x9823,0x9824,0x9825,0x9826,/* 0x50-0x57 */ - 0x9827,0x9828,0x9829,0x982A,0x982B,0x982C,0x982D,0x982E,/* 0x58-0x5F */ - 0x982F,0x9830,0x9831,0x9832,0x9833,0x9834,0x9835,0x9836,/* 0x60-0x67 */ - 0x9837,0x9838,0x9839,0x983A,0x983B,0x983C,0x983D,0x983E,/* 0x68-0x6F */ - 0x983F,0x9840,0x9841,0x9842,0x9843,0x9844,0x9845,0x9846,/* 0x70-0x77 */ - 0x9847,0x9848,0x9849,0x984A,0x984B,0x984C,0x984D,0x0000,/* 0x78-0x7F */ - - 0x984E,0x984F,0x9850,0x9851,0x9852,0x9853,0x9854,0x9855,/* 0x80-0x87 */ - 0x9856,0x9857,0x9858,0x9859,0x985A,0x985B,0x985C,0x985D,/* 0x88-0x8F */ - 0x985E,0x985F,0x9860,0x9861,0x9862,0x9863,0x9864,0x9865,/* 0x90-0x97 */ - 0x9866,0x9867,0x9868,0x9869,0x986A,0x986B,0x986C,0x986D,/* 0x98-0x9F */ - 0x986E,0x7762,0x7765,0x777F,0x778D,0x777D,0x7780,0x778C,/* 0xA0-0xA7 */ - 0x7791,0x779F,0x77A0,0x77B0,0x77B5,0x77BD,0x753A,0x7540,/* 0xA8-0xAF */ - 0x754E,0x754B,0x7548,0x755B,0x7572,0x7579,0x7583,0x7F58,/* 0xB0-0xB7 */ - 0x7F61,0x7F5F,0x8A48,0x7F68,0x7F74,0x7F71,0x7F79,0x7F81,/* 0xB8-0xBF */ - 0x7F7E,0x76CD,0x76E5,0x8832,0x9485,0x9486,0x9487,0x948B,/* 0xC0-0xC7 */ - 0x948A,0x948C,0x948D,0x948F,0x9490,0x9494,0x9497,0x9495,/* 0xC8-0xCF */ - 0x949A,0x949B,0x949C,0x94A3,0x94A4,0x94AB,0x94AA,0x94AD,/* 0xD0-0xD7 */ - 0x94AC,0x94AF,0x94B0,0x94B2,0x94B4,0x94B6,0x94B7,0x94B8,/* 0xD8-0xDF */ - 0x94B9,0x94BA,0x94BC,0x94BD,0x94BF,0x94C4,0x94C8,0x94C9,/* 0xE0-0xE7 */ - 0x94CA,0x94CB,0x94CC,0x94CD,0x94CE,0x94D0,0x94D1,0x94D2,/* 0xE8-0xEF */ - 0x94D5,0x94D6,0x94D7,0x94D9,0x94D8,0x94DB,0x94DE,0x94DF,/* 0xF0-0xF7 */ - 0x94E0,0x94E2,0x94E4,0x94E5,0x94E7,0x94E8,0x94EA,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_EF[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x986F,0x9870,0x9871,0x9872,0x9873,0x9874,0x988B,0x988E,/* 0x40-0x47 */ - 0x9892,0x9895,0x9899,0x98A3,0x98A8,0x98A9,0x98AA,0x98AB,/* 0x48-0x4F */ - 0x98AC,0x98AD,0x98AE,0x98AF,0x98B0,0x98B1,0x98B2,0x98B3,/* 0x50-0x57 */ - 0x98B4,0x98B5,0x98B6,0x98B7,0x98B8,0x98B9,0x98BA,0x98BB,/* 0x58-0x5F */ - 0x98BC,0x98BD,0x98BE,0x98BF,0x98C0,0x98C1,0x98C2,0x98C3,/* 0x60-0x67 */ - 0x98C4,0x98C5,0x98C6,0x98C7,0x98C8,0x98C9,0x98CA,0x98CB,/* 0x68-0x6F */ - 0x98CC,0x98CD,0x98CF,0x98D0,0x98D4,0x98D6,0x98D7,0x98DB,/* 0x70-0x77 */ - 0x98DC,0x98DD,0x98E0,0x98E1,0x98E2,0x98E3,0x98E4,0x0000,/* 0x78-0x7F */ - - 0x98E5,0x98E6,0x98E9,0x98EA,0x98EB,0x98EC,0x98ED,0x98EE,/* 0x80-0x87 */ - 0x98EF,0x98F0,0x98F1,0x98F2,0x98F3,0x98F4,0x98F5,0x98F6,/* 0x88-0x8F */ - 0x98F7,0x98F8,0x98F9,0x98FA,0x98FB,0x98FC,0x98FD,0x98FE,/* 0x90-0x97 */ - 0x98FF,0x9900,0x9901,0x9902,0x9903,0x9904,0x9905,0x9906,/* 0x98-0x9F */ - 0x9907,0x94E9,0x94EB,0x94EE,0x94EF,0x94F3,0x94F4,0x94F5,/* 0xA0-0xA7 */ - 0x94F7,0x94F9,0x94FC,0x94FD,0x94FF,0x9503,0x9502,0x9506,/* 0xA8-0xAF */ - 0x9507,0x9509,0x950A,0x950D,0x950E,0x950F,0x9512,0x9513,/* 0xB0-0xB7 */ - 0x9514,0x9515,0x9516,0x9518,0x951B,0x951D,0x951E,0x951F,/* 0xB8-0xBF */ - 0x9522,0x952A,0x952B,0x9529,0x952C,0x9531,0x9532,0x9534,/* 0xC0-0xC7 */ - 0x9536,0x9537,0x9538,0x953C,0x953E,0x953F,0x9542,0x9535,/* 0xC8-0xCF */ - 0x9544,0x9545,0x9546,0x9549,0x954C,0x954E,0x954F,0x9552,/* 0xD0-0xD7 */ - 0x9553,0x9554,0x9556,0x9557,0x9558,0x9559,0x955B,0x955E,/* 0xD8-0xDF */ - 0x955F,0x955D,0x9561,0x9562,0x9564,0x9565,0x9566,0x9567,/* 0xE0-0xE7 */ - 0x9568,0x9569,0x956A,0x956B,0x956C,0x956F,0x9571,0x9572,/* 0xE8-0xEF */ - 0x9573,0x953A,0x77E7,0x77EC,0x96C9,0x79D5,0x79ED,0x79E3,/* 0xF0-0xF7 */ - 0x79EB,0x7A06,0x5D47,0x7A03,0x7A02,0x7A1E,0x7A14,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F0[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9908,0x9909,0x990A,0x990B,0x990C,0x990E,0x990F,0x9911,/* 0x40-0x47 */ - 0x9912,0x9913,0x9914,0x9915,0x9916,0x9917,0x9918,0x9919,/* 0x48-0x4F */ - 0x991A,0x991B,0x991C,0x991D,0x991E,0x991F,0x9920,0x9921,/* 0x50-0x57 */ - 0x9922,0x9923,0x9924,0x9925,0x9926,0x9927,0x9928,0x9929,/* 0x58-0x5F */ - 0x992A,0x992B,0x992C,0x992D,0x992F,0x9930,0x9931,0x9932,/* 0x60-0x67 */ - 0x9933,0x9934,0x9935,0x9936,0x9937,0x9938,0x9939,0x993A,/* 0x68-0x6F */ - 0x993B,0x993C,0x993D,0x993E,0x993F,0x9940,0x9941,0x9942,/* 0x70-0x77 */ - 0x9943,0x9944,0x9945,0x9946,0x9947,0x9948,0x9949,0x0000,/* 0x78-0x7F */ - - 0x994A,0x994B,0x994C,0x994D,0x994E,0x994F,0x9950,0x9951,/* 0x80-0x87 */ - 0x9952,0x9953,0x9956,0x9957,0x9958,0x9959,0x995A,0x995B,/* 0x88-0x8F */ - 0x995C,0x995D,0x995E,0x995F,0x9960,0x9961,0x9962,0x9964,/* 0x90-0x97 */ - 0x9966,0x9973,0x9978,0x9979,0x997B,0x997E,0x9982,0x9983,/* 0x98-0x9F */ - 0x9989,0x7A39,0x7A37,0x7A51,0x9ECF,0x99A5,0x7A70,0x7688,/* 0xA0-0xA7 */ - 0x768E,0x7693,0x7699,0x76A4,0x74DE,0x74E0,0x752C,0x9E20,/* 0xA8-0xAF */ - 0x9E22,0x9E28,0x9E29,0x9E2A,0x9E2B,0x9E2C,0x9E32,0x9E31,/* 0xB0-0xB7 */ - 0x9E36,0x9E38,0x9E37,0x9E39,0x9E3A,0x9E3E,0x9E41,0x9E42,/* 0xB8-0xBF */ - 0x9E44,0x9E46,0x9E47,0x9E48,0x9E49,0x9E4B,0x9E4C,0x9E4E,/* 0xC0-0xC7 */ - 0x9E51,0x9E55,0x9E57,0x9E5A,0x9E5B,0x9E5C,0x9E5E,0x9E63,/* 0xC8-0xCF */ - 0x9E66,0x9E67,0x9E68,0x9E69,0x9E6A,0x9E6B,0x9E6C,0x9E71,/* 0xD0-0xD7 */ - 0x9E6D,0x9E73,0x7592,0x7594,0x7596,0x75A0,0x759D,0x75AC,/* 0xD8-0xDF */ - 0x75A3,0x75B3,0x75B4,0x75B8,0x75C4,0x75B1,0x75B0,0x75C3,/* 0xE0-0xE7 */ - 0x75C2,0x75D6,0x75CD,0x75E3,0x75E8,0x75E6,0x75E4,0x75EB,/* 0xE8-0xEF */ - 0x75E7,0x7603,0x75F1,0x75FC,0x75FF,0x7610,0x7600,0x7605,/* 0xF0-0xF7 */ - 0x760C,0x7617,0x760A,0x7625,0x7618,0x7615,0x7619,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x998C,0x998E,0x999A,0x999B,0x999C,0x999D,0x999E,0x999F,/* 0x40-0x47 */ - 0x99A0,0x99A1,0x99A2,0x99A3,0x99A4,0x99A6,0x99A7,0x99A9,/* 0x48-0x4F */ - 0x99AA,0x99AB,0x99AC,0x99AD,0x99AE,0x99AF,0x99B0,0x99B1,/* 0x50-0x57 */ - 0x99B2,0x99B3,0x99B4,0x99B5,0x99B6,0x99B7,0x99B8,0x99B9,/* 0x58-0x5F */ - 0x99BA,0x99BB,0x99BC,0x99BD,0x99BE,0x99BF,0x99C0,0x99C1,/* 0x60-0x67 */ - 0x99C2,0x99C3,0x99C4,0x99C5,0x99C6,0x99C7,0x99C8,0x99C9,/* 0x68-0x6F */ - 0x99CA,0x99CB,0x99CC,0x99CD,0x99CE,0x99CF,0x99D0,0x99D1,/* 0x70-0x77 */ - 0x99D2,0x99D3,0x99D4,0x99D5,0x99D6,0x99D7,0x99D8,0x0000,/* 0x78-0x7F */ - - 0x99D9,0x99DA,0x99DB,0x99DC,0x99DD,0x99DE,0x99DF,0x99E0,/* 0x80-0x87 */ - 0x99E1,0x99E2,0x99E3,0x99E4,0x99E5,0x99E6,0x99E7,0x99E8,/* 0x88-0x8F */ - 0x99E9,0x99EA,0x99EB,0x99EC,0x99ED,0x99EE,0x99EF,0x99F0,/* 0x90-0x97 */ - 0x99F1,0x99F2,0x99F3,0x99F4,0x99F5,0x99F6,0x99F7,0x99F8,/* 0x98-0x9F */ - 0x99F9,0x761B,0x763C,0x7622,0x7620,0x7640,0x762D,0x7630,/* 0xA0-0xA7 */ - 0x763F,0x7635,0x7643,0x763E,0x7633,0x764D,0x765E,0x7654,/* 0xA8-0xAF */ - 0x765C,0x7656,0x766B,0x766F,0x7FCA,0x7AE6,0x7A78,0x7A79,/* 0xB0-0xB7 */ - 0x7A80,0x7A86,0x7A88,0x7A95,0x7AA6,0x7AA0,0x7AAC,0x7AA8,/* 0xB8-0xBF */ - 0x7AAD,0x7AB3,0x8864,0x8869,0x8872,0x887D,0x887F,0x8882,/* 0xC0-0xC7 */ - 0x88A2,0x88C6,0x88B7,0x88BC,0x88C9,0x88E2,0x88CE,0x88E3,/* 0xC8-0xCF */ - 0x88E5,0x88F1,0x891A,0x88FC,0x88E8,0x88FE,0x88F0,0x8921,/* 0xD0-0xD7 */ - 0x8919,0x8913,0x891B,0x890A,0x8934,0x892B,0x8936,0x8941,/* 0xD8-0xDF */ - 0x8966,0x897B,0x758B,0x80E5,0x76B2,0x76B4,0x77DC,0x8012,/* 0xE0-0xE7 */ - 0x8014,0x8016,0x801C,0x8020,0x8022,0x8025,0x8026,0x8027,/* 0xE8-0xEF */ - 0x8029,0x8028,0x8031,0x800B,0x8035,0x8043,0x8046,0x804D,/* 0xF0-0xF7 */ - 0x8052,0x8069,0x8071,0x8983,0x9878,0x9880,0x9883,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x99FA,0x99FB,0x99FC,0x99FD,0x99FE,0x99FF,0x9A00,0x9A01,/* 0x40-0x47 */ - 0x9A02,0x9A03,0x9A04,0x9A05,0x9A06,0x9A07,0x9A08,0x9A09,/* 0x48-0x4F */ - 0x9A0A,0x9A0B,0x9A0C,0x9A0D,0x9A0E,0x9A0F,0x9A10,0x9A11,/* 0x50-0x57 */ - 0x9A12,0x9A13,0x9A14,0x9A15,0x9A16,0x9A17,0x9A18,0x9A19,/* 0x58-0x5F */ - 0x9A1A,0x9A1B,0x9A1C,0x9A1D,0x9A1E,0x9A1F,0x9A20,0x9A21,/* 0x60-0x67 */ - 0x9A22,0x9A23,0x9A24,0x9A25,0x9A26,0x9A27,0x9A28,0x9A29,/* 0x68-0x6F */ - 0x9A2A,0x9A2B,0x9A2C,0x9A2D,0x9A2E,0x9A2F,0x9A30,0x9A31,/* 0x70-0x77 */ - 0x9A32,0x9A33,0x9A34,0x9A35,0x9A36,0x9A37,0x9A38,0x0000,/* 0x78-0x7F */ - - 0x9A39,0x9A3A,0x9A3B,0x9A3C,0x9A3D,0x9A3E,0x9A3F,0x9A40,/* 0x80-0x87 */ - 0x9A41,0x9A42,0x9A43,0x9A44,0x9A45,0x9A46,0x9A47,0x9A48,/* 0x88-0x8F */ - 0x9A49,0x9A4A,0x9A4B,0x9A4C,0x9A4D,0x9A4E,0x9A4F,0x9A50,/* 0x90-0x97 */ - 0x9A51,0x9A52,0x9A53,0x9A54,0x9A55,0x9A56,0x9A57,0x9A58,/* 0x98-0x9F */ - 0x9A59,0x9889,0x988C,0x988D,0x988F,0x9894,0x989A,0x989B,/* 0xA0-0xA7 */ - 0x989E,0x989F,0x98A1,0x98A2,0x98A5,0x98A6,0x864D,0x8654,/* 0xA8-0xAF */ - 0x866C,0x866E,0x867F,0x867A,0x867C,0x867B,0x86A8,0x868D,/* 0xB0-0xB7 */ - 0x868B,0x86AC,0x869D,0x86A7,0x86A3,0x86AA,0x8693,0x86A9,/* 0xB8-0xBF */ - 0x86B6,0x86C4,0x86B5,0x86CE,0x86B0,0x86BA,0x86B1,0x86AF,/* 0xC0-0xC7 */ - 0x86C9,0x86CF,0x86B4,0x86E9,0x86F1,0x86F2,0x86ED,0x86F3,/* 0xC8-0xCF */ - 0x86D0,0x8713,0x86DE,0x86F4,0x86DF,0x86D8,0x86D1,0x8703,/* 0xD0-0xD7 */ - 0x8707,0x86F8,0x8708,0x870A,0x870D,0x8709,0x8723,0x873B,/* 0xD8-0xDF */ - 0x871E,0x8725,0x872E,0x871A,0x873E,0x8748,0x8734,0x8731,/* 0xE0-0xE7 */ - 0x8729,0x8737,0x873F,0x8782,0x8722,0x877D,0x877E,0x877B,/* 0xE8-0xEF */ - 0x8760,0x8770,0x874C,0x876E,0x878B,0x8753,0x8763,0x877C,/* 0xF0-0xF7 */ - 0x8764,0x8759,0x8765,0x8793,0x87AF,0x87A8,0x87D2,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9A5A,0x9A5B,0x9A5C,0x9A5D,0x9A5E,0x9A5F,0x9A60,0x9A61,/* 0x40-0x47 */ - 0x9A62,0x9A63,0x9A64,0x9A65,0x9A66,0x9A67,0x9A68,0x9A69,/* 0x48-0x4F */ - 0x9A6A,0x9A6B,0x9A72,0x9A83,0x9A89,0x9A8D,0x9A8E,0x9A94,/* 0x50-0x57 */ - 0x9A95,0x9A99,0x9AA6,0x9AA9,0x9AAA,0x9AAB,0x9AAC,0x9AAD,/* 0x58-0x5F */ - 0x9AAE,0x9AAF,0x9AB2,0x9AB3,0x9AB4,0x9AB5,0x9AB9,0x9ABB,/* 0x60-0x67 */ - 0x9ABD,0x9ABE,0x9ABF,0x9AC3,0x9AC4,0x9AC6,0x9AC7,0x9AC8,/* 0x68-0x6F */ - 0x9AC9,0x9ACA,0x9ACD,0x9ACE,0x9ACF,0x9AD0,0x9AD2,0x9AD4,/* 0x70-0x77 */ - 0x9AD5,0x9AD6,0x9AD7,0x9AD9,0x9ADA,0x9ADB,0x9ADC,0x0000,/* 0x78-0x7F */ - - 0x9ADD,0x9ADE,0x9AE0,0x9AE2,0x9AE3,0x9AE4,0x9AE5,0x9AE7,/* 0x80-0x87 */ - 0x9AE8,0x9AE9,0x9AEA,0x9AEC,0x9AEE,0x9AF0,0x9AF1,0x9AF2,/* 0x88-0x8F */ - 0x9AF3,0x9AF4,0x9AF5,0x9AF6,0x9AF7,0x9AF8,0x9AFA,0x9AFC,/* 0x90-0x97 */ - 0x9AFD,0x9AFE,0x9AFF,0x9B00,0x9B01,0x9B02,0x9B04,0x9B05,/* 0x98-0x9F */ - 0x9B06,0x87C6,0x8788,0x8785,0x87AD,0x8797,0x8783,0x87AB,/* 0xA0-0xA7 */ - 0x87E5,0x87AC,0x87B5,0x87B3,0x87CB,0x87D3,0x87BD,0x87D1,/* 0xA8-0xAF */ - 0x87C0,0x87CA,0x87DB,0x87EA,0x87E0,0x87EE,0x8816,0x8813,/* 0xB0-0xB7 */ - 0x87FE,0x880A,0x881B,0x8821,0x8839,0x883C,0x7F36,0x7F42,/* 0xB8-0xBF */ - 0x7F44,0x7F45,0x8210,0x7AFA,0x7AFD,0x7B08,0x7B03,0x7B04,/* 0xC0-0xC7 */ - 0x7B15,0x7B0A,0x7B2B,0x7B0F,0x7B47,0x7B38,0x7B2A,0x7B19,/* 0xC8-0xCF */ - 0x7B2E,0x7B31,0x7B20,0x7B25,0x7B24,0x7B33,0x7B3E,0x7B1E,/* 0xD0-0xD7 */ - 0x7B58,0x7B5A,0x7B45,0x7B75,0x7B4C,0x7B5D,0x7B60,0x7B6E,/* 0xD8-0xDF */ - 0x7B7B,0x7B62,0x7B72,0x7B71,0x7B90,0x7BA6,0x7BA7,0x7BB8,/* 0xE0-0xE7 */ - 0x7BAC,0x7B9D,0x7BA8,0x7B85,0x7BAA,0x7B9C,0x7BA2,0x7BAB,/* 0xE8-0xEF */ - 0x7BB4,0x7BD1,0x7BC1,0x7BCC,0x7BDD,0x7BDA,0x7BE5,0x7BE6,/* 0xF0-0xF7 */ - 0x7BEA,0x7C0C,0x7BFE,0x7BFC,0x7C0F,0x7C16,0x7C0B,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9B07,0x9B09,0x9B0A,0x9B0B,0x9B0C,0x9B0D,0x9B0E,0x9B10,/* 0x40-0x47 */ - 0x9B11,0x9B12,0x9B14,0x9B15,0x9B16,0x9B17,0x9B18,0x9B19,/* 0x48-0x4F */ - 0x9B1A,0x9B1B,0x9B1C,0x9B1D,0x9B1E,0x9B20,0x9B21,0x9B22,/* 0x50-0x57 */ - 0x9B24,0x9B25,0x9B26,0x9B27,0x9B28,0x9B29,0x9B2A,0x9B2B,/* 0x58-0x5F */ - 0x9B2C,0x9B2D,0x9B2E,0x9B30,0x9B31,0x9B33,0x9B34,0x9B35,/* 0x60-0x67 */ - 0x9B36,0x9B37,0x9B38,0x9B39,0x9B3A,0x9B3D,0x9B3E,0x9B3F,/* 0x68-0x6F */ - 0x9B40,0x9B46,0x9B4A,0x9B4B,0x9B4C,0x9B4E,0x9B50,0x9B52,/* 0x70-0x77 */ - 0x9B53,0x9B55,0x9B56,0x9B57,0x9B58,0x9B59,0x9B5A,0x0000,/* 0x78-0x7F */ - - 0x9B5B,0x9B5C,0x9B5D,0x9B5E,0x9B5F,0x9B60,0x9B61,0x9B62,/* 0x80-0x87 */ - 0x9B63,0x9B64,0x9B65,0x9B66,0x9B67,0x9B68,0x9B69,0x9B6A,/* 0x88-0x8F */ - 0x9B6B,0x9B6C,0x9B6D,0x9B6E,0x9B6F,0x9B70,0x9B71,0x9B72,/* 0x90-0x97 */ - 0x9B73,0x9B74,0x9B75,0x9B76,0x9B77,0x9B78,0x9B79,0x9B7A,/* 0x98-0x9F */ - 0x9B7B,0x7C1F,0x7C2A,0x7C26,0x7C38,0x7C41,0x7C40,0x81FE,/* 0xA0-0xA7 */ - 0x8201,0x8202,0x8204,0x81EC,0x8844,0x8221,0x8222,0x8223,/* 0xA8-0xAF */ - 0x822D,0x822F,0x8228,0x822B,0x8238,0x823B,0x8233,0x8234,/* 0xB0-0xB7 */ - 0x823E,0x8244,0x8249,0x824B,0x824F,0x825A,0x825F,0x8268,/* 0xB8-0xBF */ - 0x887E,0x8885,0x8888,0x88D8,0x88DF,0x895E,0x7F9D,0x7F9F,/* 0xC0-0xC7 */ - 0x7FA7,0x7FAF,0x7FB0,0x7FB2,0x7C7C,0x6549,0x7C91,0x7C9D,/* 0xC8-0xCF */ - 0x7C9C,0x7C9E,0x7CA2,0x7CB2,0x7CBC,0x7CBD,0x7CC1,0x7CC7,/* 0xD0-0xD7 */ - 0x7CCC,0x7CCD,0x7CC8,0x7CC5,0x7CD7,0x7CE8,0x826E,0x66A8,/* 0xD8-0xDF */ - 0x7FBF,0x7FCE,0x7FD5,0x7FE5,0x7FE1,0x7FE6,0x7FE9,0x7FEE,/* 0xE0-0xE7 */ - 0x7FF3,0x7CF8,0x7D77,0x7DA6,0x7DAE,0x7E47,0x7E9B,0x9EB8,/* 0xE8-0xEF */ - 0x9EB4,0x8D73,0x8D84,0x8D94,0x8D91,0x8DB1,0x8D67,0x8D6D,/* 0xF0-0xF7 */ - 0x8C47,0x8C49,0x914A,0x9150,0x914E,0x914F,0x9164,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9B7C,0x9B7D,0x9B7E,0x9B7F,0x9B80,0x9B81,0x9B82,0x9B83,/* 0x40-0x47 */ - 0x9B84,0x9B85,0x9B86,0x9B87,0x9B88,0x9B89,0x9B8A,0x9B8B,/* 0x48-0x4F */ - 0x9B8C,0x9B8D,0x9B8E,0x9B8F,0x9B90,0x9B91,0x9B92,0x9B93,/* 0x50-0x57 */ - 0x9B94,0x9B95,0x9B96,0x9B97,0x9B98,0x9B99,0x9B9A,0x9B9B,/* 0x58-0x5F */ - 0x9B9C,0x9B9D,0x9B9E,0x9B9F,0x9BA0,0x9BA1,0x9BA2,0x9BA3,/* 0x60-0x67 */ - 0x9BA4,0x9BA5,0x9BA6,0x9BA7,0x9BA8,0x9BA9,0x9BAA,0x9BAB,/* 0x68-0x6F */ - 0x9BAC,0x9BAD,0x9BAE,0x9BAF,0x9BB0,0x9BB1,0x9BB2,0x9BB3,/* 0x70-0x77 */ - 0x9BB4,0x9BB5,0x9BB6,0x9BB7,0x9BB8,0x9BB9,0x9BBA,0x0000,/* 0x78-0x7F */ - - 0x9BBB,0x9BBC,0x9BBD,0x9BBE,0x9BBF,0x9BC0,0x9BC1,0x9BC2,/* 0x80-0x87 */ - 0x9BC3,0x9BC4,0x9BC5,0x9BC6,0x9BC7,0x9BC8,0x9BC9,0x9BCA,/* 0x88-0x8F */ - 0x9BCB,0x9BCC,0x9BCD,0x9BCE,0x9BCF,0x9BD0,0x9BD1,0x9BD2,/* 0x90-0x97 */ - 0x9BD3,0x9BD4,0x9BD5,0x9BD6,0x9BD7,0x9BD8,0x9BD9,0x9BDA,/* 0x98-0x9F */ - 0x9BDB,0x9162,0x9161,0x9170,0x9169,0x916F,0x917D,0x917E,/* 0xA0-0xA7 */ - 0x9172,0x9174,0x9179,0x918C,0x9185,0x9190,0x918D,0x9191,/* 0xA8-0xAF */ - 0x91A2,0x91A3,0x91AA,0x91AD,0x91AE,0x91AF,0x91B5,0x91B4,/* 0xB0-0xB7 */ - 0x91BA,0x8C55,0x9E7E,0x8DB8,0x8DEB,0x8E05,0x8E59,0x8E69,/* 0xB8-0xBF */ - 0x8DB5,0x8DBF,0x8DBC,0x8DBA,0x8DC4,0x8DD6,0x8DD7,0x8DDA,/* 0xC0-0xC7 */ - 0x8DDE,0x8DCE,0x8DCF,0x8DDB,0x8DC6,0x8DEC,0x8DF7,0x8DF8,/* 0xC8-0xCF */ - 0x8DE3,0x8DF9,0x8DFB,0x8DE4,0x8E09,0x8DFD,0x8E14,0x8E1D,/* 0xD0-0xD7 */ - 0x8E1F,0x8E2C,0x8E2E,0x8E23,0x8E2F,0x8E3A,0x8E40,0x8E39,/* 0xD8-0xDF */ - 0x8E35,0x8E3D,0x8E31,0x8E49,0x8E41,0x8E42,0x8E51,0x8E52,/* 0xE0-0xE7 */ - 0x8E4A,0x8E70,0x8E76,0x8E7C,0x8E6F,0x8E74,0x8E85,0x8E8F,/* 0xE8-0xEF */ - 0x8E94,0x8E90,0x8E9C,0x8E9E,0x8C78,0x8C82,0x8C8A,0x8C85,/* 0xF0-0xF7 */ - 0x8C98,0x8C94,0x659B,0x89D6,0x89DE,0x89DA,0x89DC,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9BDC,0x9BDD,0x9BDE,0x9BDF,0x9BE0,0x9BE1,0x9BE2,0x9BE3,/* 0x40-0x47 */ - 0x9BE4,0x9BE5,0x9BE6,0x9BE7,0x9BE8,0x9BE9,0x9BEA,0x9BEB,/* 0x48-0x4F */ - 0x9BEC,0x9BED,0x9BEE,0x9BEF,0x9BF0,0x9BF1,0x9BF2,0x9BF3,/* 0x50-0x57 */ - 0x9BF4,0x9BF5,0x9BF6,0x9BF7,0x9BF8,0x9BF9,0x9BFA,0x9BFB,/* 0x58-0x5F */ - 0x9BFC,0x9BFD,0x9BFE,0x9BFF,0x9C00,0x9C01,0x9C02,0x9C03,/* 0x60-0x67 */ - 0x9C04,0x9C05,0x9C06,0x9C07,0x9C08,0x9C09,0x9C0A,0x9C0B,/* 0x68-0x6F */ - 0x9C0C,0x9C0D,0x9C0E,0x9C0F,0x9C10,0x9C11,0x9C12,0x9C13,/* 0x70-0x77 */ - 0x9C14,0x9C15,0x9C16,0x9C17,0x9C18,0x9C19,0x9C1A,0x0000,/* 0x78-0x7F */ - - 0x9C1B,0x9C1C,0x9C1D,0x9C1E,0x9C1F,0x9C20,0x9C21,0x9C22,/* 0x80-0x87 */ - 0x9C23,0x9C24,0x9C25,0x9C26,0x9C27,0x9C28,0x9C29,0x9C2A,/* 0x88-0x8F */ - 0x9C2B,0x9C2C,0x9C2D,0x9C2E,0x9C2F,0x9C30,0x9C31,0x9C32,/* 0x90-0x97 */ - 0x9C33,0x9C34,0x9C35,0x9C36,0x9C37,0x9C38,0x9C39,0x9C3A,/* 0x98-0x9F */ - 0x9C3B,0x89E5,0x89EB,0x89EF,0x8A3E,0x8B26,0x9753,0x96E9,/* 0xA0-0xA7 */ - 0x96F3,0x96EF,0x9706,0x9701,0x9708,0x970F,0x970E,0x972A,/* 0xA8-0xAF */ - 0x972D,0x9730,0x973E,0x9F80,0x9F83,0x9F85,0x9F86,0x9F87,/* 0xB0-0xB7 */ - 0x9F88,0x9F89,0x9F8A,0x9F8C,0x9EFE,0x9F0B,0x9F0D,0x96B9,/* 0xB8-0xBF */ - 0x96BC,0x96BD,0x96CE,0x96D2,0x77BF,0x96E0,0x928E,0x92AE,/* 0xC0-0xC7 */ - 0x92C8,0x933E,0x936A,0x93CA,0x938F,0x943E,0x946B,0x9C7F,/* 0xC8-0xCF */ - 0x9C82,0x9C85,0x9C86,0x9C87,0x9C88,0x7A23,0x9C8B,0x9C8E,/* 0xD0-0xD7 */ - 0x9C90,0x9C91,0x9C92,0x9C94,0x9C95,0x9C9A,0x9C9B,0x9C9E,/* 0xD8-0xDF */ - 0x9C9F,0x9CA0,0x9CA1,0x9CA2,0x9CA3,0x9CA5,0x9CA6,0x9CA7,/* 0xE0-0xE7 */ - 0x9CA8,0x9CA9,0x9CAB,0x9CAD,0x9CAE,0x9CB0,0x9CB1,0x9CB2,/* 0xE8-0xEF */ - 0x9CB3,0x9CB4,0x9CB5,0x9CB6,0x9CB7,0x9CBA,0x9CBB,0x9CBC,/* 0xF0-0xF7 */ - 0x9CBD,0x9CC4,0x9CC5,0x9CC6,0x9CC7,0x9CCA,0x9CCB,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F7[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9C3C,0x9C3D,0x9C3E,0x9C3F,0x9C40,0x9C41,0x9C42,0x9C43,/* 0x40-0x47 */ - 0x9C44,0x9C45,0x9C46,0x9C47,0x9C48,0x9C49,0x9C4A,0x9C4B,/* 0x48-0x4F */ - 0x9C4C,0x9C4D,0x9C4E,0x9C4F,0x9C50,0x9C51,0x9C52,0x9C53,/* 0x50-0x57 */ - 0x9C54,0x9C55,0x9C56,0x9C57,0x9C58,0x9C59,0x9C5A,0x9C5B,/* 0x58-0x5F */ - 0x9C5C,0x9C5D,0x9C5E,0x9C5F,0x9C60,0x9C61,0x9C62,0x9C63,/* 0x60-0x67 */ - 0x9C64,0x9C65,0x9C66,0x9C67,0x9C68,0x9C69,0x9C6A,0x9C6B,/* 0x68-0x6F */ - 0x9C6C,0x9C6D,0x9C6E,0x9C6F,0x9C70,0x9C71,0x9C72,0x9C73,/* 0x70-0x77 */ - 0x9C74,0x9C75,0x9C76,0x9C77,0x9C78,0x9C79,0x9C7A,0x0000,/* 0x78-0x7F */ - - 0x9C7B,0x9C7D,0x9C7E,0x9C80,0x9C83,0x9C84,0x9C89,0x9C8A,/* 0x80-0x87 */ - 0x9C8C,0x9C8F,0x9C93,0x9C96,0x9C97,0x9C98,0x9C99,0x9C9D,/* 0x88-0x8F */ - 0x9CAA,0x9CAC,0x9CAF,0x9CB9,0x9CBE,0x9CBF,0x9CC0,0x9CC1,/* 0x90-0x97 */ - 0x9CC2,0x9CC8,0x9CC9,0x9CD1,0x9CD2,0x9CDA,0x9CDB,0x9CE0,/* 0x98-0x9F */ - 0x9CE1,0x9CCC,0x9CCD,0x9CCE,0x9CCF,0x9CD0,0x9CD3,0x9CD4,/* 0xA0-0xA7 */ - 0x9CD5,0x9CD7,0x9CD8,0x9CD9,0x9CDC,0x9CDD,0x9CDF,0x9CE2,/* 0xA8-0xAF */ - 0x977C,0x9785,0x9791,0x9792,0x9794,0x97AF,0x97AB,0x97A3,/* 0xB0-0xB7 */ - 0x97B2,0x97B4,0x9AB1,0x9AB0,0x9AB7,0x9E58,0x9AB6,0x9ABA,/* 0xB8-0xBF */ - 0x9ABC,0x9AC1,0x9AC0,0x9AC5,0x9AC2,0x9ACB,0x9ACC,0x9AD1,/* 0xC0-0xC7 */ - 0x9B45,0x9B43,0x9B47,0x9B49,0x9B48,0x9B4D,0x9B51,0x98E8,/* 0xC8-0xCF */ - 0x990D,0x992E,0x9955,0x9954,0x9ADF,0x9AE1,0x9AE6,0x9AEF,/* 0xD0-0xD7 */ - 0x9AEB,0x9AFB,0x9AED,0x9AF9,0x9B08,0x9B0F,0x9B13,0x9B1F,/* 0xD8-0xDF */ - 0x9B23,0x9EBD,0x9EBE,0x7E3B,0x9E82,0x9E87,0x9E88,0x9E8B,/* 0xE0-0xE7 */ - 0x9E92,0x93D6,0x9E9D,0x9E9F,0x9EDB,0x9EDC,0x9EDD,0x9EE0,/* 0xE8-0xEF */ - 0x9EDF,0x9EE2,0x9EE9,0x9EE7,0x9EE5,0x9EEA,0x9EEF,0x9F22,/* 0xF0-0xF7 */ - 0x9F2C,0x9F2F,0x9F39,0x9F37,0x9F3D,0x9F3E,0x9F44,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F8[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9CE3,0x9CE4,0x9CE5,0x9CE6,0x9CE7,0x9CE8,0x9CE9,0x9CEA,/* 0x40-0x47 */ - 0x9CEB,0x9CEC,0x9CED,0x9CEE,0x9CEF,0x9CF0,0x9CF1,0x9CF2,/* 0x48-0x4F */ - 0x9CF3,0x9CF4,0x9CF5,0x9CF6,0x9CF7,0x9CF8,0x9CF9,0x9CFA,/* 0x50-0x57 */ - 0x9CFB,0x9CFC,0x9CFD,0x9CFE,0x9CFF,0x9D00,0x9D01,0x9D02,/* 0x58-0x5F */ - 0x9D03,0x9D04,0x9D05,0x9D06,0x9D07,0x9D08,0x9D09,0x9D0A,/* 0x60-0x67 */ - 0x9D0B,0x9D0C,0x9D0D,0x9D0E,0x9D0F,0x9D10,0x9D11,0x9D12,/* 0x68-0x6F */ - 0x9D13,0x9D14,0x9D15,0x9D16,0x9D17,0x9D18,0x9D19,0x9D1A,/* 0x70-0x77 */ - 0x9D1B,0x9D1C,0x9D1D,0x9D1E,0x9D1F,0x9D20,0x9D21,0x0000,/* 0x78-0x7F */ - - 0x9D22,0x9D23,0x9D24,0x9D25,0x9D26,0x9D27,0x9D28,0x9D29,/* 0x80-0x87 */ - 0x9D2A,0x9D2B,0x9D2C,0x9D2D,0x9D2E,0x9D2F,0x9D30,0x9D31,/* 0x88-0x8F */ - 0x9D32,0x9D33,0x9D34,0x9D35,0x9D36,0x9D37,0x9D38,0x9D39,/* 0x90-0x97 */ - 0x9D3A,0x9D3B,0x9D3C,0x9D3D,0x9D3E,0x9D3F,0x9D40,0x9D41,/* 0x98-0x9F */ - 0x9D42,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ -}; - -static const wchar_t c2u_F9[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9D43,0x9D44,0x9D45,0x9D46,0x9D47,0x9D48,0x9D49,0x9D4A,/* 0x40-0x47 */ - 0x9D4B,0x9D4C,0x9D4D,0x9D4E,0x9D4F,0x9D50,0x9D51,0x9D52,/* 0x48-0x4F */ - 0x9D53,0x9D54,0x9D55,0x9D56,0x9D57,0x9D58,0x9D59,0x9D5A,/* 0x50-0x57 */ - 0x9D5B,0x9D5C,0x9D5D,0x9D5E,0x9D5F,0x9D60,0x9D61,0x9D62,/* 0x58-0x5F */ - 0x9D63,0x9D64,0x9D65,0x9D66,0x9D67,0x9D68,0x9D69,0x9D6A,/* 0x60-0x67 */ - 0x9D6B,0x9D6C,0x9D6D,0x9D6E,0x9D6F,0x9D70,0x9D71,0x9D72,/* 0x68-0x6F */ - 0x9D73,0x9D74,0x9D75,0x9D76,0x9D77,0x9D78,0x9D79,0x9D7A,/* 0x70-0x77 */ - 0x9D7B,0x9D7C,0x9D7D,0x9D7E,0x9D7F,0x9D80,0x9D81,0x0000,/* 0x78-0x7F */ - - 0x9D82,0x9D83,0x9D84,0x9D85,0x9D86,0x9D87,0x9D88,0x9D89,/* 0x80-0x87 */ - 0x9D8A,0x9D8B,0x9D8C,0x9D8D,0x9D8E,0x9D8F,0x9D90,0x9D91,/* 0x88-0x8F */ - 0x9D92,0x9D93,0x9D94,0x9D95,0x9D96,0x9D97,0x9D98,0x9D99,/* 0x90-0x97 */ - 0x9D9A,0x9D9B,0x9D9C,0x9D9D,0x9D9E,0x9D9F,0x9DA0,0x9DA1,/* 0x98-0x9F */ - 0x9DA2,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ -}; - -static const wchar_t c2u_FA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9DA3,0x9DA4,0x9DA5,0x9DA6,0x9DA7,0x9DA8,0x9DA9,0x9DAA,/* 0x40-0x47 */ - 0x9DAB,0x9DAC,0x9DAD,0x9DAE,0x9DAF,0x9DB0,0x9DB1,0x9DB2,/* 0x48-0x4F */ - 0x9DB3,0x9DB4,0x9DB5,0x9DB6,0x9DB7,0x9DB8,0x9DB9,0x9DBA,/* 0x50-0x57 */ - 0x9DBB,0x9DBC,0x9DBD,0x9DBE,0x9DBF,0x9DC0,0x9DC1,0x9DC2,/* 0x58-0x5F */ - 0x9DC3,0x9DC4,0x9DC5,0x9DC6,0x9DC7,0x9DC8,0x9DC9,0x9DCA,/* 0x60-0x67 */ - 0x9DCB,0x9DCC,0x9DCD,0x9DCE,0x9DCF,0x9DD0,0x9DD1,0x9DD2,/* 0x68-0x6F */ - 0x9DD3,0x9DD4,0x9DD5,0x9DD6,0x9DD7,0x9DD8,0x9DD9,0x9DDA,/* 0x70-0x77 */ - 0x9DDB,0x9DDC,0x9DDD,0x9DDE,0x9DDF,0x9DE0,0x9DE1,0x0000,/* 0x78-0x7F */ - - 0x9DE2,0x9DE3,0x9DE4,0x9DE5,0x9DE6,0x9DE7,0x9DE8,0x9DE9,/* 0x80-0x87 */ - 0x9DEA,0x9DEB,0x9DEC,0x9DED,0x9DEE,0x9DEF,0x9DF0,0x9DF1,/* 0x88-0x8F */ - 0x9DF2,0x9DF3,0x9DF4,0x9DF5,0x9DF6,0x9DF7,0x9DF8,0x9DF9,/* 0x90-0x97 */ - 0x9DFA,0x9DFB,0x9DFC,0x9DFD,0x9DFE,0x9DFF,0x9E00,0x9E01,/* 0x98-0x9F */ - 0x9E02,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ -}; - -static const wchar_t c2u_FB[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9E03,0x9E04,0x9E05,0x9E06,0x9E07,0x9E08,0x9E09,0x9E0A,/* 0x40-0x47 */ - 0x9E0B,0x9E0C,0x9E0D,0x9E0E,0x9E0F,0x9E10,0x9E11,0x9E12,/* 0x48-0x4F */ - 0x9E13,0x9E14,0x9E15,0x9E16,0x9E17,0x9E18,0x9E19,0x9E1A,/* 0x50-0x57 */ - 0x9E1B,0x9E1C,0x9E1D,0x9E1E,0x9E24,0x9E27,0x9E2E,0x9E30,/* 0x58-0x5F */ - 0x9E34,0x9E3B,0x9E3C,0x9E40,0x9E4D,0x9E50,0x9E52,0x9E53,/* 0x60-0x67 */ - 0x9E54,0x9E56,0x9E59,0x9E5D,0x9E5F,0x9E60,0x9E61,0x9E62,/* 0x68-0x6F */ - 0x9E65,0x9E6E,0x9E6F,0x9E72,0x9E74,0x9E75,0x9E76,0x9E77,/* 0x70-0x77 */ - 0x9E78,0x9E79,0x9E7A,0x9E7B,0x9E7C,0x9E7D,0x9E80,0x0000,/* 0x78-0x7F */ - - 0x9E81,0x9E83,0x9E84,0x9E85,0x9E86,0x9E89,0x9E8A,0x9E8C,/* 0x80-0x87 */ - 0x9E8D,0x9E8E,0x9E8F,0x9E90,0x9E91,0x9E94,0x9E95,0x9E96,/* 0x88-0x8F */ - 0x9E97,0x9E98,0x9E99,0x9E9A,0x9E9B,0x9E9C,0x9E9E,0x9EA0,/* 0x90-0x97 */ - 0x9EA1,0x9EA2,0x9EA3,0x9EA4,0x9EA5,0x9EA7,0x9EA8,0x9EA9,/* 0x98-0x9F */ - 0x9EAA,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ -}; - -static const wchar_t c2u_FC[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9EAB,0x9EAC,0x9EAD,0x9EAE,0x9EAF,0x9EB0,0x9EB1,0x9EB2,/* 0x40-0x47 */ - 0x9EB3,0x9EB5,0x9EB6,0x9EB7,0x9EB9,0x9EBA,0x9EBC,0x9EBF,/* 0x48-0x4F */ - 0x9EC0,0x9EC1,0x9EC2,0x9EC3,0x9EC5,0x9EC6,0x9EC7,0x9EC8,/* 0x50-0x57 */ - 0x9ECA,0x9ECB,0x9ECC,0x9ED0,0x9ED2,0x9ED3,0x9ED5,0x9ED6,/* 0x58-0x5F */ - 0x9ED7,0x9ED9,0x9EDA,0x9EDE,0x9EE1,0x9EE3,0x9EE4,0x9EE6,/* 0x60-0x67 */ - 0x9EE8,0x9EEB,0x9EEC,0x9EED,0x9EEE,0x9EF0,0x9EF1,0x9EF2,/* 0x68-0x6F */ - 0x9EF3,0x9EF4,0x9EF5,0x9EF6,0x9EF7,0x9EF8,0x9EFA,0x9EFD,/* 0x70-0x77 */ - 0x9EFF,0x9F00,0x9F01,0x9F02,0x9F03,0x9F04,0x9F05,0x0000,/* 0x78-0x7F */ - - 0x9F06,0x9F07,0x9F08,0x9F09,0x9F0A,0x9F0C,0x9F0F,0x9F11,/* 0x80-0x87 */ - 0x9F12,0x9F14,0x9F15,0x9F16,0x9F18,0x9F1A,0x9F1B,0x9F1C,/* 0x88-0x8F */ - 0x9F1D,0x9F1E,0x9F1F,0x9F21,0x9F23,0x9F24,0x9F25,0x9F26,/* 0x90-0x97 */ - 0x9F27,0x9F28,0x9F29,0x9F2A,0x9F2B,0x9F2D,0x9F2E,0x9F30,/* 0x98-0x9F */ - 0x9F31,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ -}; - -static const wchar_t c2u_FD[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9F32,0x9F33,0x9F34,0x9F35,0x9F36,0x9F38,0x9F3A,0x9F3C,/* 0x40-0x47 */ - 0x9F3F,0x9F40,0x9F41,0x9F42,0x9F43,0x9F45,0x9F46,0x9F47,/* 0x48-0x4F */ - 0x9F48,0x9F49,0x9F4A,0x9F4B,0x9F4C,0x9F4D,0x9F4E,0x9F4F,/* 0x50-0x57 */ - 0x9F52,0x9F53,0x9F54,0x9F55,0x9F56,0x9F57,0x9F58,0x9F59,/* 0x58-0x5F */ - 0x9F5A,0x9F5B,0x9F5C,0x9F5D,0x9F5E,0x9F5F,0x9F60,0x9F61,/* 0x60-0x67 */ - 0x9F62,0x9F63,0x9F64,0x9F65,0x9F66,0x9F67,0x9F68,0x9F69,/* 0x68-0x6F */ - 0x9F6A,0x9F6B,0x9F6C,0x9F6D,0x9F6E,0x9F6F,0x9F70,0x9F71,/* 0x70-0x77 */ - 0x9F72,0x9F73,0x9F74,0x9F75,0x9F76,0x9F77,0x9F78,0x0000,/* 0x78-0x7F */ - - 0x9F79,0x9F7A,0x9F7B,0x9F7C,0x9F7D,0x9F7E,0x9F81,0x9F82,/* 0x80-0x87 */ - 0x9F8D,0x9F8E,0x9F8F,0x9F90,0x9F91,0x9F92,0x9F93,0x9F94,/* 0x88-0x8F */ - 0x9F95,0x9F96,0x9F97,0x9F98,0x9F9C,0x9F9D,0x9F9E,0x9FA1,/* 0x90-0x97 */ - 0x9FA2,0x9FA3,0x9FA4,0x9FA5,0xF92C,0xF979,0xF995,0xF9E7,/* 0x98-0x9F */ - 0xF9F1,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ -}; - -static const wchar_t c2u_FE[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0xFA0C,0xFA0D,0xFA0E,0xFA0F,0xFA11,0xFA13,0xFA14,0xFA18,/* 0x40-0x47 */ - 0xFA1F,0xFA20,0xFA21,0xFA23,0xFA24,0xFA27,0xFA28,0xFA29,/* 0x48-0x4F */ -}; - -static const wchar_t *page_charset2uni[256] = { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, c2u_81, c2u_82, c2u_83, c2u_84, c2u_85, c2u_86, c2u_87, - c2u_88, c2u_89, c2u_8A, c2u_8B, c2u_8C, c2u_8D, c2u_8E, c2u_8F, - c2u_90, c2u_91, c2u_92, c2u_93, c2u_94, c2u_95, c2u_96, c2u_97, - c2u_98, c2u_99, c2u_9A, c2u_9B, c2u_9C, c2u_9D, c2u_9E, c2u_9F, - c2u_A0, c2u_A1, c2u_A2, c2u_A3, c2u_A4, c2u_A5, c2u_A6, c2u_A7, - c2u_A8, c2u_A9, c2u_AA, c2u_AB, c2u_AC, c2u_AD, c2u_AE, c2u_AF, - c2u_B0, c2u_B1, c2u_B2, c2u_B3, c2u_B4, c2u_B5, c2u_B6, c2u_B7, - c2u_B8, c2u_B9, c2u_BA, c2u_BB, c2u_BC, c2u_BD, c2u_BE, c2u_BF, - c2u_C0, c2u_C1, c2u_C2, c2u_C3, c2u_C4, c2u_C5, c2u_C6, c2u_C7, - c2u_C8, c2u_C9, c2u_CA, c2u_CB, c2u_CC, c2u_CD, c2u_CE, c2u_CF, - c2u_D0, c2u_D1, c2u_D2, c2u_D3, c2u_D4, c2u_D5, c2u_D6, c2u_D7, - c2u_D8, c2u_D9, c2u_DA, c2u_DB, c2u_DC, c2u_DD, c2u_DE, c2u_DF, - c2u_E0, c2u_E1, c2u_E2, c2u_E3, c2u_E4, c2u_E5, c2u_E6, c2u_E7, - c2u_E8, c2u_E9, c2u_EA, c2u_EB, c2u_EC, c2u_ED, c2u_EE, c2u_EF, - c2u_F0, c2u_F1, c2u_F2, c2u_F3, c2u_F4, c2u_F5, c2u_F6, c2u_F7, - c2u_F8, c2u_F9, c2u_FA, c2u_FB, c2u_FC, c2u_FD, c2u_FE, NULL, -}; - -static const unsigned char u2c_00[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xA1, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xEC, /* 0xA4-0xA7 */ - 0xA1, 0xA7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0xA1, 0xE3, 0xA1, 0xC0, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xA4, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xC1, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0xA8, 0xA4, 0xA8, 0xA2, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xA8, 0xA8, 0xA8, 0xA6, 0xA8, 0xBA, 0x00, 0x00, /* 0xE8-0xEB */ - 0xA8, 0xAC, 0xA8, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0xB0, 0xA8, 0xAE, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xC2, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xA8, 0xB4, 0xA8, 0xB2, 0x00, 0x00, /* 0xF8-0xFB */ - 0xA8, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_01[512] = { - 0xA8, 0xA1, 0xA8, 0xA1, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0xA5, 0xA8, 0xA5, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0xA7, 0xA8, 0xA7, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0xA9, 0xA8, 0xA9, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xA8, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0xA8, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xA8, 0xAD, 0xA8, 0xAD, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0xB1, 0xA8, 0xB1, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xA1, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0xA8, 0xA3, 0xA8, 0xA3, 0xA8, 0xAB, /* 0xCC-0xCF */ - 0xA8, 0xAB, 0xA8, 0xAF, 0xA8, 0xAF, 0xA8, 0xB3, /* 0xD0-0xD3 */ - 0xA8, 0xB3, 0xA8, 0xB5, 0xA8, 0xB5, 0xA8, 0xB6, /* 0xD4-0xD7 */ - 0xA8, 0xB6, 0xA8, 0xB7, 0xA8, 0xB7, 0xA8, 0xB8, /* 0xD8-0xDB */ - 0xA8, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ -}; - -static const unsigned char u2c_02[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0xA8, 0xBB, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0xA8, 0xC0, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xA6, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xA1, 0xA5, 0xA8, 0x40, 0xA8, 0x41, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xA8, 0x42, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ -}; - -static const unsigned char u2c_03[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xA6, 0xA1, 0xA6, 0xA2, 0xA6, 0xA3, /* 0x90-0x93 */ - 0xA6, 0xA4, 0xA6, 0xA5, 0xA6, 0xA6, 0xA6, 0xA7, /* 0x94-0x97 */ - 0xA6, 0xA8, 0xA6, 0xA9, 0xA6, 0xAA, 0xA6, 0xAB, /* 0x98-0x9B */ - 0xA6, 0xAC, 0xA6, 0xAD, 0xA6, 0xAE, 0xA6, 0xAF, /* 0x9C-0x9F */ - 0xA6, 0xB0, 0xA6, 0xB1, 0x00, 0x00, 0xA6, 0xB2, /* 0xA0-0xA3 */ - 0xA6, 0xB3, 0xA6, 0xB4, 0xA6, 0xB5, 0xA6, 0xB6, /* 0xA4-0xA7 */ - 0xA6, 0xB7, 0xA6, 0xB8, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xA6, 0xC1, 0xA6, 0xC2, 0xA6, 0xC3, /* 0xB0-0xB3 */ - 0xA6, 0xC4, 0xA6, 0xC5, 0xA6, 0xC6, 0xA6, 0xC7, /* 0xB4-0xB7 */ - 0xA6, 0xC8, 0xA6, 0xC9, 0xA6, 0xCA, 0xA6, 0xCB, /* 0xB8-0xBB */ - 0xA6, 0xCC, 0xA6, 0xCD, 0xA6, 0xCE, 0xA6, 0xCF, /* 0xBC-0xBF */ - 0xA6, 0xD0, 0xA6, 0xD1, 0x00, 0x00, 0xA6, 0xD2, /* 0xC0-0xC3 */ - 0xA6, 0xD3, 0xA6, 0xD4, 0xA6, 0xD5, 0xA6, 0xD6, /* 0xC4-0xC7 */ - 0xA6, 0xD7, 0xA6, 0xD8, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ -}; - -static const unsigned char u2c_04[512] = { - 0x00, 0x00, 0xA7, 0xA7, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xA7, 0xA1, 0xA7, 0xA2, 0xA7, 0xA3, 0xA7, 0xA4, /* 0x10-0x13 */ - 0xA7, 0xA5, 0xA7, 0xA6, 0xA7, 0xA8, 0xA7, 0xA9, /* 0x14-0x17 */ - 0xA7, 0xAA, 0xA7, 0xAB, 0xA7, 0xAC, 0xA7, 0xAD, /* 0x18-0x1B */ - 0xA7, 0xAE, 0xA7, 0xAF, 0xA7, 0xB0, 0xA7, 0xB1, /* 0x1C-0x1F */ - 0xA7, 0xB2, 0xA7, 0xB3, 0xA7, 0xB4, 0xA7, 0xB5, /* 0x20-0x23 */ - 0xA7, 0xB6, 0xA7, 0xB7, 0xA7, 0xB8, 0xA7, 0xB9, /* 0x24-0x27 */ - 0xA7, 0xBA, 0xA7, 0xBB, 0xA7, 0xBC, 0xA7, 0xBD, /* 0x28-0x2B */ - 0xA7, 0xBE, 0xA7, 0xBF, 0xA7, 0xC0, 0xA7, 0xC1, /* 0x2C-0x2F */ - 0xA7, 0xD1, 0xA7, 0xD2, 0xA7, 0xD3, 0xA7, 0xD4, /* 0x30-0x33 */ - 0xA7, 0xD5, 0xA7, 0xD6, 0xA7, 0xD8, 0xA7, 0xD9, /* 0x34-0x37 */ - 0xA7, 0xDA, 0xA7, 0xDB, 0xA7, 0xDC, 0xA7, 0xDD, /* 0x38-0x3B */ - 0xA7, 0xDE, 0xA7, 0xDF, 0xA7, 0xE0, 0xA7, 0xE1, /* 0x3C-0x3F */ - 0xA7, 0xE2, 0xA7, 0xE3, 0xA7, 0xE4, 0xA7, 0xE5, /* 0x40-0x43 */ - 0xA7, 0xE6, 0xA7, 0xE7, 0xA7, 0xE8, 0xA7, 0xE9, /* 0x44-0x47 */ - 0xA7, 0xEA, 0xA7, 0xEB, 0xA7, 0xEC, 0xA7, 0xED, /* 0x48-0x4B */ - 0xA7, 0xEE, 0xA7, 0xEF, 0xA7, 0xF0, 0xA7, 0xF1, /* 0x4C-0x4F */ - 0x00, 0x00, 0xA7, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ -}; - -static const unsigned char u2c_20[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xA9, 0x5C, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x43, /* 0x10-0x13 */ - 0xA1, 0xAA, 0xA8, 0x44, 0xA1, 0xAC, 0x00, 0x00, /* 0x14-0x17 */ - 0xA1, 0xAE, 0xA1, 0xAF, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xA1, 0xB0, 0xA1, 0xB1, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xA8, 0x45, 0xA1, 0xAD, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xA1, 0xEB, 0x00, 0x00, 0xA1, 0xE4, 0xA1, 0xE5, /* 0x30-0x33 */ - 0x00, 0x00, 0xA8, 0x46, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xF9, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xA3, 0xFE, 0x00, 0x00, /* 0x3C-0x3F */ -}; - -static const unsigned char u2c_21[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xE6, /* 0x00-0x03 */ - 0x00, 0x00, 0xA8, 0x47, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xA8, 0x48, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xED, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xA9, 0x59, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xA2, 0xF1, 0xA2, 0xF2, 0xA2, 0xF3, 0xA2, 0xF4, /* 0x60-0x63 */ - 0xA2, 0xF5, 0xA2, 0xF6, 0xA2, 0xF7, 0xA2, 0xF8, /* 0x64-0x67 */ - 0xA2, 0xF9, 0xA2, 0xFA, 0xA2, 0xFB, 0xA2, 0xFC, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xA2, 0xA1, 0xA2, 0xA2, 0xA2, 0xA3, 0xA2, 0xA4, /* 0x70-0x73 */ - 0xA2, 0xA5, 0xA2, 0xA6, 0xA2, 0xA7, 0xA2, 0xA8, /* 0x74-0x77 */ - 0xA2, 0xA9, 0xA2, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xA1, 0xFB, 0xA1, 0xFC, 0xA1, 0xFA, 0xA1, 0xFD, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0x49, 0xA8, 0x4A, /* 0x94-0x97 */ - 0xA8, 0x4B, 0xA8, 0x4C, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ -}; - -static const unsigned char u2c_22[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xA1, 0xCA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xC7, /* 0x0C-0x0F */ - 0x00, 0x00, 0xA1, 0xC6, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xA8, 0x4D, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xA1, 0xE3, 0x00, 0x00, 0xA1, 0xCC, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0xA1, 0xD8, 0xA1, 0xDE, 0xA8, 0x4E, /* 0x1C-0x1F */ - 0xA1, 0xCF, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x4F, /* 0x20-0x23 */ - 0x00, 0x00, 0xA1, 0xCE, 0x00, 0x00, 0xA1, 0xC4, /* 0x24-0x27 */ - 0xA1, 0xC5, 0xA1, 0xC9, 0xA1, 0xC8, 0xA1, 0xD2, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xD3, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xA1, 0xE0, 0xA1, 0xDF, 0xA1, 0xC3, 0xA1, 0xCB, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xA1, 0xAB, 0xA1, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0xA1, 0xD6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xA1, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0x50, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xA1, 0xD9, 0xA1, 0xD4, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0xA1, 0xDC, 0xA1, 0xDD, 0xA8, 0x51, 0xA8, 0x52, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xDA, 0xA1, 0xDB, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0xA8, 0x92, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xA1, 0xD1, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xA1, 0xCD, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x53, /* 0xBC-0xBF */ -}; - -static const unsigned char u2c_23[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xD0, 0x00, 0x00, /* 0x10-0x13 */ -}; - -static const unsigned char u2c_24[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xA2, 0xD9, 0xA2, 0xDA, 0xA2, 0xDB, 0xA2, 0xDC, /* 0x60-0x63 */ - 0xA2, 0xDD, 0xA2, 0xDE, 0xA2, 0xDF, 0xA2, 0xE0, /* 0x64-0x67 */ - 0xA2, 0xE1, 0xA2, 0xE2, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xA2, 0xC5, 0xA2, 0xC6, 0xA2, 0xC7, 0xA2, 0xC8, /* 0x74-0x77 */ - 0xA2, 0xC9, 0xA2, 0xCA, 0xA2, 0xCB, 0xA2, 0xCC, /* 0x78-0x7B */ - 0xA2, 0xCD, 0xA2, 0xCE, 0xA2, 0xCF, 0xA2, 0xD0, /* 0x7C-0x7F */ - - 0xA2, 0xD1, 0xA2, 0xD2, 0xA2, 0xD3, 0xA2, 0xD4, /* 0x80-0x83 */ - 0xA2, 0xD5, 0xA2, 0xD6, 0xA2, 0xD7, 0xA2, 0xD8, /* 0x84-0x87 */ - 0xA2, 0xB1, 0xA2, 0xB2, 0xA2, 0xB3, 0xA2, 0xB4, /* 0x88-0x8B */ - 0xA2, 0xB5, 0xA2, 0xB6, 0xA2, 0xB7, 0xA2, 0xB8, /* 0x8C-0x8F */ - 0xA2, 0xB9, 0xA2, 0xBA, 0xA2, 0xBB, 0xA2, 0xBC, /* 0x90-0x93 */ - 0xA2, 0xBD, 0xA2, 0xBE, 0xA2, 0xBF, 0xA2, 0xC0, /* 0x94-0x97 */ - 0xA2, 0xC1, 0xA2, 0xC2, 0xA2, 0xC3, 0xA2, 0xC4, /* 0x98-0x9B */ -}; - -static const unsigned char u2c_25[512] = { - 0xA9, 0xA4, 0xA9, 0xA5, 0xA9, 0xA6, 0xA9, 0xA7, /* 0x00-0x03 */ - 0xA9, 0xA8, 0xA9, 0xA9, 0xA9, 0xAA, 0xA9, 0xAB, /* 0x04-0x07 */ - 0xA9, 0xAC, 0xA9, 0xAD, 0xA9, 0xAE, 0xA9, 0xAF, /* 0x08-0x0B */ - 0xA9, 0xB0, 0xA9, 0xB1, 0xA9, 0xB2, 0xA9, 0xB3, /* 0x0C-0x0F */ - 0xA9, 0xB4, 0xA9, 0xB5, 0xA9, 0xB6, 0xA9, 0xB7, /* 0x10-0x13 */ - 0xA9, 0xB8, 0xA9, 0xB9, 0xA9, 0xBA, 0xA9, 0xBB, /* 0x14-0x17 */ - 0xA9, 0xBC, 0xA9, 0xBD, 0xA9, 0xBE, 0xA9, 0xBF, /* 0x18-0x1B */ - 0xA9, 0xC0, 0xA9, 0xC1, 0xA9, 0xC2, 0xA9, 0xC3, /* 0x1C-0x1F */ - 0xA9, 0xC4, 0xA9, 0xC5, 0xA9, 0xC6, 0xA9, 0xC7, /* 0x20-0x23 */ - 0xA9, 0xC8, 0xA9, 0xC9, 0xA9, 0xCA, 0xA9, 0xCB, /* 0x24-0x27 */ - 0xA9, 0xCC, 0xA9, 0xCD, 0xA9, 0xCE, 0xA9, 0xCF, /* 0x28-0x2B */ - 0xA9, 0xD0, 0xA9, 0xD1, 0xA9, 0xD2, 0xA9, 0xD3, /* 0x2C-0x2F */ - 0xA9, 0xD4, 0xA9, 0xD5, 0xA9, 0xD6, 0xA9, 0xD7, /* 0x30-0x33 */ - 0xA9, 0xD8, 0xA9, 0xD9, 0xA9, 0xDA, 0xA9, 0xDB, /* 0x34-0x37 */ - 0xA9, 0xDC, 0xA9, 0xDD, 0xA9, 0xDE, 0xA9, 0xDF, /* 0x38-0x3B */ - 0xA9, 0xE0, 0xA9, 0xE1, 0xA9, 0xE2, 0xA9, 0xE3, /* 0x3C-0x3F */ - 0xA9, 0xE4, 0xA9, 0xE5, 0xA9, 0xE6, 0xA9, 0xE7, /* 0x40-0x43 */ - 0xA9, 0xE8, 0xA9, 0xE9, 0xA9, 0xEA, 0xA9, 0xEB, /* 0x44-0x47 */ - 0xA9, 0xEC, 0xA9, 0xED, 0xA9, 0xEE, 0xA9, 0xEF, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xA8, 0x54, 0xA8, 0x55, 0xA8, 0x56, 0xA8, 0x57, /* 0x50-0x53 */ - 0xA8, 0x58, 0xA8, 0x59, 0xA8, 0x5A, 0xA8, 0x5B, /* 0x54-0x57 */ - 0xA8, 0x5C, 0xA8, 0x5D, 0xA8, 0x5E, 0xA8, 0x5F, /* 0x58-0x5B */ - 0xA8, 0x60, 0xA8, 0x61, 0xA8, 0x62, 0xA8, 0x63, /* 0x5C-0x5F */ - 0xA8, 0x64, 0xA8, 0x65, 0xA8, 0x66, 0xA8, 0x67, /* 0x60-0x63 */ - 0xA8, 0x68, 0xA8, 0x69, 0xA8, 0x6A, 0xA8, 0x6B, /* 0x64-0x67 */ - 0xA8, 0x6C, 0xA8, 0x6D, 0xA8, 0x6E, 0xA8, 0x6F, /* 0x68-0x6B */ - 0xA8, 0x70, 0xA8, 0x71, 0xA8, 0x72, 0xA8, 0x73, /* 0x6C-0x6F */ - 0xA8, 0x74, 0xA8, 0x75, 0xA8, 0x76, 0xA8, 0x77, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xA8, 0x78, 0xA8, 0x79, 0xA8, 0x7A, /* 0x80-0x83 */ - 0xA8, 0x7B, 0xA8, 0x7C, 0xA8, 0x7D, 0xA8, 0x7E, /* 0x84-0x87 */ - 0xA8, 0x80, 0xA8, 0x81, 0xA8, 0x82, 0xA8, 0x83, /* 0x88-0x8B */ - 0xA8, 0x84, 0xA8, 0x85, 0xA8, 0x86, 0xA8, 0x87, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x88, /* 0x90-0x93 */ - 0xA8, 0x89, 0xA8, 0x8A, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xA1, 0xF6, 0xA1, 0xF5, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xF8, 0xA1, 0xF7, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0xA8, 0x8B, 0xA8, 0x8C, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xF4, 0xA1, 0xF3, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xF0, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xF2, 0xA1, 0xF1, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0x8D, 0xA8, 0x8E, /* 0xE0-0xE3 */ - 0xA8, 0x8F, 0xA8, 0x90, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_26[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xA1, 0xEF, 0xA1, 0xEE, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xA8, 0x91, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xA1, 0xE2, 0x00, 0x00, 0xA1, 0xE1, 0x00, 0x00, /* 0x40-0x43 */ -}; - -static const unsigned char u2c_30[512] = { - 0xA1, 0xA1, 0xA1, 0xA2, 0xA1, 0xA3, 0xA1, 0xA8, /* 0x00-0x03 */ - 0x00, 0x00, 0xA1, 0xA9, 0xA9, 0x65, 0xA9, 0x96, /* 0x04-0x07 */ - 0xA1, 0xB4, 0xA1, 0xB5, 0xA1, 0xB6, 0xA1, 0xB7, /* 0x08-0x0B */ - 0xA1, 0xB8, 0xA1, 0xB9, 0xA1, 0xBA, 0xA1, 0xBB, /* 0x0C-0x0F */ - 0xA1, 0xBE, 0xA1, 0xBF, 0xA8, 0x93, 0xA1, 0xFE, /* 0x10-0x13 */ - 0xA1, 0xB2, 0xA1, 0xB3, 0xA1, 0xBC, 0xA1, 0xBD, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0xA8, 0x94, 0xA8, 0x95, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xA9, 0x40, 0xA9, 0x41, 0xA9, 0x42, /* 0x20-0x23 */ - 0xA9, 0x43, 0xA9, 0x44, 0xA9, 0x45, 0xA9, 0x46, /* 0x24-0x27 */ - 0xA9, 0x47, 0xA9, 0x48, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xA4, 0xA1, 0xA4, 0xA2, 0xA4, 0xA3, /* 0x40-0x43 */ - 0xA4, 0xA4, 0xA4, 0xA5, 0xA4, 0xA6, 0xA4, 0xA7, /* 0x44-0x47 */ - 0xA4, 0xA8, 0xA4, 0xA9, 0xA4, 0xAA, 0xA4, 0xAB, /* 0x48-0x4B */ - 0xA4, 0xAC, 0xA4, 0xAD, 0xA4, 0xAE, 0xA4, 0xAF, /* 0x4C-0x4F */ - 0xA4, 0xB0, 0xA4, 0xB1, 0xA4, 0xB2, 0xA4, 0xB3, /* 0x50-0x53 */ - 0xA4, 0xB4, 0xA4, 0xB5, 0xA4, 0xB6, 0xA4, 0xB7, /* 0x54-0x57 */ - 0xA4, 0xB8, 0xA4, 0xB9, 0xA4, 0xBA, 0xA4, 0xBB, /* 0x58-0x5B */ - 0xA4, 0xBC, 0xA4, 0xBD, 0xA4, 0xBE, 0xA4, 0xBF, /* 0x5C-0x5F */ - 0xA4, 0xC0, 0xA4, 0xC1, 0xA4, 0xC2, 0xA4, 0xC3, /* 0x60-0x63 */ - 0xA4, 0xC4, 0xA4, 0xC5, 0xA4, 0xC6, 0xA4, 0xC7, /* 0x64-0x67 */ - 0xA4, 0xC8, 0xA4, 0xC9, 0xA4, 0xCA, 0xA4, 0xCB, /* 0x68-0x6B */ - 0xA4, 0xCC, 0xA4, 0xCD, 0xA4, 0xCE, 0xA4, 0xCF, /* 0x6C-0x6F */ - 0xA4, 0xD0, 0xA4, 0xD1, 0xA4, 0xD2, 0xA4, 0xD3, /* 0x70-0x73 */ - 0xA4, 0xD4, 0xA4, 0xD5, 0xA4, 0xD6, 0xA4, 0xD7, /* 0x74-0x77 */ - 0xA4, 0xD8, 0xA4, 0xD9, 0xA4, 0xDA, 0xA4, 0xDB, /* 0x78-0x7B */ - 0xA4, 0xDC, 0xA4, 0xDD, 0xA4, 0xDE, 0xA4, 0xDF, /* 0x7C-0x7F */ - - 0xA4, 0xE0, 0xA4, 0xE1, 0xA4, 0xE2, 0xA4, 0xE3, /* 0x80-0x83 */ - 0xA4, 0xE4, 0xA4, 0xE5, 0xA4, 0xE6, 0xA4, 0xE7, /* 0x84-0x87 */ - 0xA4, 0xE8, 0xA4, 0xE9, 0xA4, 0xEA, 0xA4, 0xEB, /* 0x88-0x8B */ - 0xA4, 0xEC, 0xA4, 0xED, 0xA4, 0xEE, 0xA4, 0xEF, /* 0x8C-0x8F */ - 0xA4, 0xF0, 0xA4, 0xF1, 0xA4, 0xF2, 0xA4, 0xF3, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA9, 0x61, /* 0x98-0x9B */ - 0xA9, 0x62, 0xA9, 0x66, 0xA9, 0x67, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xA5, 0xA1, 0xA5, 0xA2, 0xA5, 0xA3, /* 0xA0-0xA3 */ - 0xA5, 0xA4, 0xA5, 0xA5, 0xA5, 0xA6, 0xA5, 0xA7, /* 0xA4-0xA7 */ - 0xA5, 0xA8, 0xA5, 0xA9, 0xA5, 0xAA, 0xA5, 0xAB, /* 0xA8-0xAB */ - 0xA5, 0xAC, 0xA5, 0xAD, 0xA5, 0xAE, 0xA5, 0xAF, /* 0xAC-0xAF */ - 0xA5, 0xB0, 0xA5, 0xB1, 0xA5, 0xB2, 0xA5, 0xB3, /* 0xB0-0xB3 */ - 0xA5, 0xB4, 0xA5, 0xB5, 0xA5, 0xB6, 0xA5, 0xB7, /* 0xB4-0xB7 */ - 0xA5, 0xB8, 0xA5, 0xB9, 0xA5, 0xBA, 0xA5, 0xBB, /* 0xB8-0xBB */ - 0xA5, 0xBC, 0xA5, 0xBD, 0xA5, 0xBE, 0xA5, 0xBF, /* 0xBC-0xBF */ - 0xA5, 0xC0, 0xA5, 0xC1, 0xA5, 0xC2, 0xA5, 0xC3, /* 0xC0-0xC3 */ - 0xA5, 0xC4, 0xA5, 0xC5, 0xA5, 0xC6, 0xA5, 0xC7, /* 0xC4-0xC7 */ - 0xA5, 0xC8, 0xA5, 0xC9, 0xA5, 0xCA, 0xA5, 0xCB, /* 0xC8-0xCB */ - 0xA5, 0xCC, 0xA5, 0xCD, 0xA5, 0xCE, 0xA5, 0xCF, /* 0xCC-0xCF */ - 0xA5, 0xD0, 0xA5, 0xD1, 0xA5, 0xD2, 0xA5, 0xD3, /* 0xD0-0xD3 */ - 0xA5, 0xD4, 0xA5, 0xD5, 0xA5, 0xD6, 0xA5, 0xD7, /* 0xD4-0xD7 */ - 0xA5, 0xD8, 0xA5, 0xD9, 0xA5, 0xDA, 0xA5, 0xDB, /* 0xD8-0xDB */ - 0xA5, 0xDC, 0xA5, 0xDD, 0xA5, 0xDE, 0xA5, 0xDF, /* 0xDC-0xDF */ - 0xA5, 0xE0, 0xA5, 0xE1, 0xA5, 0xE2, 0xA5, 0xE3, /* 0xE0-0xE3 */ - 0xA5, 0xE4, 0xA5, 0xE5, 0xA5, 0xE6, 0xA5, 0xE7, /* 0xE4-0xE7 */ - 0xA5, 0xE8, 0xA5, 0xE9, 0xA5, 0xEA, 0xA5, 0xEB, /* 0xE8-0xEB */ - 0xA5, 0xEC, 0xA5, 0xED, 0xA5, 0xEE, 0xA5, 0xEF, /* 0xEC-0xEF */ - 0xA5, 0xF0, 0xA5, 0xF1, 0xA5, 0xF2, 0xA5, 0xF3, /* 0xF0-0xF3 */ - 0xA5, 0xF4, 0xA5, 0xF5, 0xA5, 0xF6, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0xA9, 0x60, 0xA9, 0x63, 0xA9, 0x64, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_31[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xA8, 0xC5, 0xA8, 0xC6, 0xA8, 0xC7, /* 0x04-0x07 */ - 0xA8, 0xC8, 0xA8, 0xC9, 0xA8, 0xCA, 0xA8, 0xCB, /* 0x08-0x0B */ - 0xA8, 0xCC, 0xA8, 0xCD, 0xA8, 0xCE, 0xA8, 0xCF, /* 0x0C-0x0F */ - 0xA8, 0xD0, 0xA8, 0xD1, 0xA8, 0xD2, 0xA8, 0xD3, /* 0x10-0x13 */ - 0xA8, 0xD4, 0xA8, 0xD5, 0xA8, 0xD6, 0xA8, 0xD7, /* 0x14-0x17 */ - 0xA8, 0xD8, 0xA8, 0xD9, 0xA8, 0xDA, 0xA8, 0xDB, /* 0x18-0x1B */ - 0xA8, 0xDC, 0xA8, 0xDD, 0xA8, 0xDE, 0xA8, 0xDF, /* 0x1C-0x1F */ - 0xA8, 0xE0, 0xA8, 0xE1, 0xA8, 0xE2, 0xA8, 0xE3, /* 0x20-0x23 */ - 0xA8, 0xE4, 0xA8, 0xE5, 0xA8, 0xE6, 0xA8, 0xE7, /* 0x24-0x27 */ - 0xA8, 0xE8, 0xA8, 0xE9, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xD2, 0xBB, 0xB6, 0xFE, /* 0x90-0x93 */ - 0xC8, 0xFD, 0xCB, 0xC4, 0xC9, 0xCF, 0xD6, 0xD0, /* 0x94-0x97 */ - 0xCF, 0xC2, 0xBC, 0xD7, 0xD2, 0xD2, 0xB1, 0xFB, /* 0x98-0x9B */ - 0xB6, 0xA1, 0xCC, 0xEC, 0xB5, 0xD8, 0xC8, 0xCB, /* 0x9C-0x9F */ -}; - -static const unsigned char u2c_32[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xA2, 0xE5, 0xA2, 0xE6, 0xA2, 0xE7, 0xA2, 0xE8, /* 0x20-0x23 */ - 0xA2, 0xE9, 0xA2, 0xEA, 0xA2, 0xEB, 0xA2, 0xEC, /* 0x24-0x27 */ - 0xA2, 0xED, 0xA2, 0xEE, 0xD4, 0xC2, 0xBB, 0xF0, /* 0x28-0x2B */ - 0xCB, 0xAE, 0xC4, 0xBE, 0xBD, 0xF0, 0xCD, 0xC1, /* 0x2C-0x2F */ - 0xC8, 0xD5, 0xA9, 0x5A, 0xD3, 0xD0, 0xC9, 0xE7, /* 0x30-0x33 */ - 0xC3, 0xFB, 0xCC, 0xD8, 0xB2, 0xC6, 0xD7, 0xA3, /* 0x34-0x37 */ - 0xC0, 0xCD, 0xB4, 0xFA, 0xBA, 0xF4, 0xD1, 0xA7, /* 0x38-0x3B */ - 0xBC, 0xE0, 0xC6, 0xF3, 0xD7, 0xCA, 0xD0, 0xAD, /* 0x3C-0x3F */ - 0xBC, 0xC0, 0xD0, 0xDD, 0xD7, 0xD4, 0xD6, 0xC1, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xD2, 0xBB, 0xB6, 0xFE, 0xC8, 0xFD, 0xCB, 0xC4, /* 0x80-0x83 */ - 0xCE, 0xE5, 0xC1, 0xF9, 0xC6, 0xDF, 0xB0, 0xCB, /* 0x84-0x87 */ - 0xBE, 0xC5, 0xCA, 0xAE, 0xD4, 0xC2, 0xBB, 0xF0, /* 0x88-0x8B */ - 0xCB, 0xAE, 0xC4, 0xBE, 0xBD, 0xF0, 0xCD, 0xC1, /* 0x8C-0x8F */ - 0xC8, 0xD5, 0xD6, 0xEA, 0xD3, 0xD0, 0xC9, 0xE7, /* 0x90-0x93 */ - 0xC3, 0xFB, 0xCC, 0xD8, 0xB2, 0xC6, 0xD7, 0xA3, /* 0x94-0x97 */ - 0xC0, 0xCD, 0xC3, 0xD8, 0xC4, 0xD0, 0xC5, 0xAE, /* 0x98-0x9B */ - 0xCA, 0xCA, 0xD3, 0xC5, 0x00, 0x00, 0xD7, 0xA2, /* 0x9C-0x9F */ - 0xCF, 0xEE, 0xD0, 0xDD, 0xD0, 0xB4, 0xA9, 0x49, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xD2, 0xBD, 0xD7, 0xDA, 0xD1, 0xA7, /* 0xA8-0xAB */ - 0xBC, 0xE0, 0xC6, 0xF3, 0xD7, 0xCA, 0xD0, 0xAD, /* 0xAC-0xAF */ - 0xD2, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ -}; - -static const unsigned char u2c_33[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xA9, 0x4A, 0xA9, 0x4B, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xA9, 0x4C, 0xA9, 0x4D, 0xA9, 0x4E, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xA9, 0x4F, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xA9, 0x50, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xA9, 0x51, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xA9, 0x52, 0xA9, 0x53, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xA9, 0x54, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ -}; - -static const unsigned char u2c_4E[512] = { - 0xD2, 0xBB, 0xB6, 0xA1, 0x81, 0x40, 0xC6, 0xDF, /* 0x00-0x03 */ - 0x81, 0x41, 0x81, 0x42, 0x81, 0x43, 0xCD, 0xF2, /* 0x04-0x07 */ - 0xD5, 0xC9, 0xC8, 0xFD, 0xC9, 0xCF, 0xCF, 0xC2, /* 0x08-0x0B */ - 0xD8, 0xA2, 0xB2, 0xBB, 0xD3, 0xEB, 0x81, 0x44, /* 0x0C-0x0F */ - 0xD8, 0xA4, 0xB3, 0xF3, 0x81, 0x45, 0xD7, 0xA8, /* 0x10-0x13 */ - 0xC7, 0xD2, 0xD8, 0xA7, 0xCA, 0xC0, 0x81, 0x46, /* 0x14-0x17 */ - 0xC7, 0xF0, 0xB1, 0xFB, 0xD2, 0xB5, 0xB4, 0xD4, /* 0x18-0x1B */ - 0xB6, 0xAB, 0xCB, 0xBF, 0xD8, 0xA9, 0x81, 0x47, /* 0x1C-0x1F */ - 0x81, 0x48, 0x81, 0x49, 0xB6, 0xAA, 0x81, 0x4A, /* 0x20-0x23 */ - 0xC1, 0xBD, 0xD1, 0xCF, 0x81, 0x4B, 0xC9, 0xA5, /* 0x24-0x27 */ - 0xD8, 0xAD, 0x81, 0x4C, 0xB8, 0xF6, 0xD1, 0xBE, /* 0x28-0x2B */ - 0xE3, 0xDC, 0xD6, 0xD0, 0x81, 0x4D, 0x81, 0x4E, /* 0x2C-0x2F */ - 0xB7, 0xE1, 0x81, 0x4F, 0xB4, 0xAE, 0x81, 0x50, /* 0x30-0x33 */ - 0xC1, 0xD9, 0x81, 0x51, 0xD8, 0xBC, 0x81, 0x52, /* 0x34-0x37 */ - 0xCD, 0xE8, 0xB5, 0xA4, 0xCE, 0xAA, 0xD6, 0xF7, /* 0x38-0x3B */ - 0x81, 0x53, 0xC0, 0xF6, 0xBE, 0xD9, 0xD8, 0xAF, /* 0x3C-0x3F */ - 0x81, 0x54, 0x81, 0x55, 0x81, 0x56, 0xC4, 0xCB, /* 0x40-0x43 */ - 0x81, 0x57, 0xBE, 0xC3, 0x81, 0x58, 0xD8, 0xB1, /* 0x44-0x47 */ - 0xC3, 0xB4, 0xD2, 0xE5, 0x81, 0x59, 0xD6, 0xAE, /* 0x48-0x4B */ - 0xCE, 0xDA, 0xD5, 0xA7, 0xBA, 0xF5, 0xB7, 0xA6, /* 0x4C-0x4F */ - 0xC0, 0xD6, 0x81, 0x5A, 0xC6, 0xB9, 0xC5, 0xD2, /* 0x50-0x53 */ - 0xC7, 0xC7, 0x81, 0x5B, 0xB9, 0xD4, 0x81, 0x5C, /* 0x54-0x57 */ - 0xB3, 0xCB, 0xD2, 0xD2, 0x81, 0x5D, 0x81, 0x5E, /* 0x58-0x5B */ - 0xD8, 0xBF, 0xBE, 0xC5, 0xC6, 0xF2, 0xD2, 0xB2, /* 0x5C-0x5F */ - 0xCF, 0xB0, 0xCF, 0xE7, 0x81, 0x5F, 0x81, 0x60, /* 0x60-0x63 */ - 0x81, 0x61, 0x81, 0x62, 0xCA, 0xE9, 0x81, 0x63, /* 0x64-0x67 */ - 0x81, 0x64, 0xD8, 0xC0, 0x81, 0x65, 0x81, 0x66, /* 0x68-0x6B */ - 0x81, 0x67, 0x81, 0x68, 0x81, 0x69, 0x81, 0x6A, /* 0x6C-0x6F */ - 0xC2, 0xF2, 0xC2, 0xD2, 0x81, 0x6B, 0xC8, 0xE9, /* 0x70-0x73 */ - 0x81, 0x6C, 0x81, 0x6D, 0x81, 0x6E, 0x81, 0x6F, /* 0x74-0x77 */ - 0x81, 0x70, 0x81, 0x71, 0x81, 0x72, 0x81, 0x73, /* 0x78-0x7B */ - 0x81, 0x74, 0x81, 0x75, 0xC7, 0xAC, 0x81, 0x76, /* 0x7C-0x7F */ - - 0x81, 0x77, 0x81, 0x78, 0x81, 0x79, 0x81, 0x7A, /* 0x80-0x83 */ - 0x81, 0x7B, 0x81, 0x7C, 0xC1, 0xCB, 0x81, 0x7D, /* 0x84-0x87 */ - 0xD3, 0xE8, 0xD5, 0xF9, 0x81, 0x7E, 0xCA, 0xC2, /* 0x88-0x8B */ - 0xB6, 0xFE, 0xD8, 0xA1, 0xD3, 0xDA, 0xBF, 0xF7, /* 0x8C-0x8F */ - 0x81, 0x80, 0xD4, 0xC6, 0xBB, 0xA5, 0xD8, 0xC1, /* 0x90-0x93 */ - 0xCE, 0xE5, 0xBE, 0xAE, 0x81, 0x81, 0x81, 0x82, /* 0x94-0x97 */ - 0xD8, 0xA8, 0x81, 0x83, 0xD1, 0xC7, 0xD0, 0xA9, /* 0x98-0x9B */ - 0x81, 0x84, 0x81, 0x85, 0x81, 0x86, 0xD8, 0xBD, /* 0x9C-0x9F */ - 0xD9, 0xEF, 0xCD, 0xF6, 0xBF, 0xBA, 0x81, 0x87, /* 0xA0-0xA3 */ - 0xBD, 0xBB, 0xBA, 0xA5, 0xD2, 0xE0, 0xB2, 0xFA, /* 0xA4-0xA7 */ - 0xBA, 0xE0, 0xC4, 0xB6, 0x81, 0x88, 0xCF, 0xED, /* 0xA8-0xAB */ - 0xBE, 0xA9, 0xCD, 0xA4, 0xC1, 0xC1, 0x81, 0x89, /* 0xAC-0xAF */ - 0x81, 0x8A, 0x81, 0x8B, 0xC7, 0xD7, 0xD9, 0xF1, /* 0xB0-0xB3 */ - 0x81, 0x8C, 0xD9, 0xF4, 0x81, 0x8D, 0x81, 0x8E, /* 0xB4-0xB7 */ - 0x81, 0x8F, 0x81, 0x90, 0xC8, 0xCB, 0xD8, 0xE9, /* 0xB8-0xBB */ - 0x81, 0x91, 0x81, 0x92, 0x81, 0x93, 0xD2, 0xDA, /* 0xBC-0xBF */ - 0xCA, 0xB2, 0xC8, 0xCA, 0xD8, 0xEC, 0xD8, 0xEA, /* 0xC0-0xC3 */ - 0xD8, 0xC6, 0xBD, 0xF6, 0xC6, 0xCD, 0xB3, 0xF0, /* 0xC4-0xC7 */ - 0x81, 0x94, 0xD8, 0xEB, 0xBD, 0xF1, 0xBD, 0xE9, /* 0xC8-0xCB */ - 0x81, 0x95, 0xC8, 0xD4, 0xB4, 0xD3, 0x81, 0x96, /* 0xCC-0xCF */ - 0x81, 0x97, 0xC2, 0xD8, 0x81, 0x98, 0xB2, 0xD6, /* 0xD0-0xD3 */ - 0xD7, 0xD0, 0xCA, 0xCB, 0xCB, 0xFB, 0xD5, 0xCC, /* 0xD4-0xD7 */ - 0xB8, 0xB6, 0xCF, 0xC9, 0x81, 0x99, 0x81, 0x9A, /* 0xD8-0xDB */ - 0x81, 0x9B, 0xD9, 0xDA, 0xD8, 0xF0, 0xC7, 0xAA, /* 0xDC-0xDF */ - 0x81, 0x9C, 0xD8, 0xEE, 0x81, 0x9D, 0xB4, 0xFA, /* 0xE0-0xE3 */ - 0xC1, 0xEE, 0xD2, 0xD4, 0x81, 0x9E, 0x81, 0x9F, /* 0xE4-0xE7 */ - 0xD8, 0xED, 0x81, 0xA0, 0xD2, 0xC7, 0xD8, 0xEF, /* 0xE8-0xEB */ - 0xC3, 0xC7, 0x81, 0xA1, 0x81, 0xA2, 0x81, 0xA3, /* 0xEC-0xEF */ - 0xD1, 0xF6, 0x81, 0xA4, 0xD6, 0xD9, 0xD8, 0xF2, /* 0xF0-0xF3 */ - 0x81, 0xA5, 0xD8, 0xF5, 0xBC, 0xFE, 0xBC, 0xDB, /* 0xF4-0xF7 */ - 0x81, 0xA6, 0x81, 0xA7, 0x81, 0xA8, 0xC8, 0xCE, /* 0xF8-0xFB */ - 0x81, 0xA9, 0xB7, 0xDD, 0x81, 0xAA, 0xB7, 0xC2, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_4F[512] = { - 0x81, 0xAB, 0xC6, 0xF3, 0x81, 0xAC, 0x81, 0xAD, /* 0x00-0x03 */ - 0x81, 0xAE, 0x81, 0xAF, 0x81, 0xB0, 0x81, 0xB1, /* 0x04-0x07 */ - 0x81, 0xB2, 0xD8, 0xF8, 0xD2, 0xC1, 0x81, 0xB3, /* 0x08-0x0B */ - 0x81, 0xB4, 0xCE, 0xE9, 0xBC, 0xBF, 0xB7, 0xFC, /* 0x0C-0x0F */ - 0xB7, 0xA5, 0xD0, 0xDD, 0x81, 0xB5, 0x81, 0xB6, /* 0x10-0x13 */ - 0x81, 0xB7, 0x81, 0xB8, 0x81, 0xB9, 0xD6, 0xDA, /* 0x14-0x17 */ - 0xD3, 0xC5, 0xBB, 0xEF, 0xBB, 0xE1, 0xD8, 0xF1, /* 0x18-0x1B */ - 0x81, 0xBA, 0x81, 0xBB, 0xC9, 0xA1, 0xCE, 0xB0, /* 0x1C-0x1F */ - 0xB4, 0xAB, 0x81, 0xBC, 0xD8, 0xF3, 0x81, 0xBD, /* 0x20-0x23 */ - 0xC9, 0xCB, 0xD8, 0xF6, 0xC2, 0xD7, 0xD8, 0xF7, /* 0x24-0x27 */ - 0x81, 0xBE, 0x81, 0xBF, 0xCE, 0xB1, 0xD8, 0xF9, /* 0x28-0x2B */ - 0x81, 0xC0, 0x81, 0xC1, 0x81, 0xC2, 0xB2, 0xAE, /* 0x2C-0x2F */ - 0xB9, 0xC0, 0x81, 0xC3, 0xD9, 0xA3, 0x81, 0xC4, /* 0x30-0x33 */ - 0xB0, 0xE9, 0x81, 0xC5, 0xC1, 0xE6, 0x81, 0xC6, /* 0x34-0x37 */ - 0xC9, 0xEC, 0x81, 0xC7, 0xCB, 0xC5, 0x81, 0xC8, /* 0x38-0x3B */ - 0xCB, 0xC6, 0xD9, 0xA4, 0x81, 0xC9, 0x81, 0xCA, /* 0x3C-0x3F */ - 0x81, 0xCB, 0x81, 0xCC, 0x81, 0xCD, 0xB5, 0xE8, /* 0x40-0x43 */ - 0x81, 0xCE, 0x81, 0xCF, 0xB5, 0xAB, 0x81, 0xD0, /* 0x44-0x47 */ - 0x81, 0xD1, 0x81, 0xD2, 0x81, 0xD3, 0x81, 0xD4, /* 0x48-0x4B */ - 0x81, 0xD5, 0xCE, 0xBB, 0xB5, 0xCD, 0xD7, 0xA1, /* 0x4C-0x4F */ - 0xD7, 0xF4, 0xD3, 0xD3, 0x81, 0xD6, 0xCC, 0xE5, /* 0x50-0x53 */ - 0x81, 0xD7, 0xBA, 0xCE, 0x81, 0xD8, 0xD9, 0xA2, /* 0x54-0x57 */ - 0xD9, 0xDC, 0xD3, 0xE0, 0xD8, 0xFD, 0xB7, 0xF0, /* 0x58-0x5B */ - 0xD7, 0xF7, 0xD8, 0xFE, 0xD8, 0xFA, 0xD9, 0xA1, /* 0x5C-0x5F */ - 0xC4, 0xE3, 0x81, 0xD9, 0x81, 0xDA, 0xD3, 0xB6, /* 0x60-0x63 */ - 0xD8, 0xF4, 0xD9, 0xDD, 0x81, 0xDB, 0xD8, 0xFB, /* 0x64-0x67 */ - 0x81, 0xDC, 0xC5, 0xE5, 0x81, 0xDD, 0x81, 0xDE, /* 0x68-0x6B */ - 0xC0, 0xD0, 0x81, 0xDF, 0x81, 0xE0, 0xD1, 0xF0, /* 0x6C-0x6F */ - 0xB0, 0xDB, 0x81, 0xE1, 0x81, 0xE2, 0xBC, 0xD1, /* 0x70-0x73 */ - 0xD9, 0xA6, 0x81, 0xE3, 0xD9, 0xA5, 0x81, 0xE4, /* 0x74-0x77 */ - 0x81, 0xE5, 0x81, 0xE6, 0x81, 0xE7, 0xD9, 0xAC, /* 0x78-0x7B */ - 0xD9, 0xAE, 0x81, 0xE8, 0xD9, 0xAB, 0xCA, 0xB9, /* 0x7C-0x7F */ - - 0x81, 0xE9, 0x81, 0xEA, 0x81, 0xEB, 0xD9, 0xA9, /* 0x80-0x83 */ - 0xD6, 0xB6, 0x81, 0xEC, 0x81, 0xED, 0x81, 0xEE, /* 0x84-0x87 */ - 0xB3, 0xDE, 0xD9, 0xA8, 0x81, 0xEF, 0xC0, 0xFD, /* 0x88-0x8B */ - 0x81, 0xF0, 0xCA, 0xCC, 0x81, 0xF1, 0xD9, 0xAA, /* 0x8C-0x8F */ - 0x81, 0xF2, 0xD9, 0xA7, 0x81, 0xF3, 0x81, 0xF4, /* 0x90-0x93 */ - 0xD9, 0xB0, 0x81, 0xF5, 0x81, 0xF6, 0xB6, 0xB1, /* 0x94-0x97 */ - 0x81, 0xF7, 0x81, 0xF8, 0x81, 0xF9, 0xB9, 0xA9, /* 0x98-0x9B */ - 0x81, 0xFA, 0xD2, 0xC0, 0x81, 0xFB, 0x81, 0xFC, /* 0x9C-0x9F */ - 0xCF, 0xC0, 0x81, 0xFD, 0x81, 0xFE, 0xC2, 0xC2, /* 0xA0-0xA3 */ - 0x82, 0x40, 0xBD, 0xC4, 0xD5, 0xEC, 0xB2, 0xE0, /* 0xA4-0xA7 */ - 0xC7, 0xC8, 0xBF, 0xEB, 0xD9, 0xAD, 0x82, 0x41, /* 0xA8-0xAB */ - 0xD9, 0xAF, 0x82, 0x42, 0xCE, 0xEA, 0xBA, 0xEE, /* 0xAC-0xAF */ - 0x82, 0x43, 0x82, 0x44, 0x82, 0x45, 0x82, 0x46, /* 0xB0-0xB3 */ - 0x82, 0x47, 0xC7, 0xD6, 0x82, 0x48, 0x82, 0x49, /* 0xB4-0xB7 */ - 0x82, 0x4A, 0x82, 0x4B, 0x82, 0x4C, 0x82, 0x4D, /* 0xB8-0xBB */ - 0x82, 0x4E, 0x82, 0x4F, 0x82, 0x50, 0xB1, 0xE3, /* 0xBC-0xBF */ - 0x82, 0x51, 0x82, 0x52, 0x82, 0x53, 0xB4, 0xD9, /* 0xC0-0xC3 */ - 0xB6, 0xED, 0xD9, 0xB4, 0x82, 0x54, 0x82, 0x55, /* 0xC4-0xC7 */ - 0x82, 0x56, 0x82, 0x57, 0xBF, 0xA1, 0x82, 0x58, /* 0xC8-0xCB */ - 0x82, 0x59, 0x82, 0x5A, 0xD9, 0xDE, 0xC7, 0xCE, /* 0xCC-0xCF */ - 0xC0, 0xFE, 0xD9, 0xB8, 0x82, 0x5B, 0x82, 0x5C, /* 0xD0-0xD3 */ - 0x82, 0x5D, 0x82, 0x5E, 0x82, 0x5F, 0xCB, 0xD7, /* 0xD4-0xD7 */ - 0xB7, 0xFD, 0x82, 0x60, 0xD9, 0xB5, 0x82, 0x61, /* 0xD8-0xDB */ - 0xD9, 0xB7, 0xB1, 0xA3, 0xD3, 0xE1, 0xD9, 0xB9, /* 0xDC-0xDF */ - 0x82, 0x62, 0xD0, 0xC5, 0x82, 0x63, 0xD9, 0xB6, /* 0xE0-0xE3 */ - 0x82, 0x64, 0x82, 0x65, 0xD9, 0xB1, 0x82, 0x66, /* 0xE4-0xE7 */ - 0xD9, 0xB2, 0xC1, 0xA9, 0xD9, 0xB3, 0x82, 0x67, /* 0xE8-0xEB */ - 0x82, 0x68, 0xBC, 0xF3, 0xD0, 0xDE, 0xB8, 0xA9, /* 0xEC-0xEF */ - 0x82, 0x69, 0xBE, 0xE3, 0x82, 0x6A, 0xD9, 0xBD, /* 0xF0-0xF3 */ - 0x82, 0x6B, 0x82, 0x6C, 0x82, 0x6D, 0x82, 0x6E, /* 0xF4-0xF7 */ - 0xD9, 0xBA, 0x82, 0x6F, 0xB0, 0xB3, 0x82, 0x70, /* 0xF8-0xFB */ - 0x82, 0x71, 0x82, 0x72, 0xD9, 0xC2, 0x82, 0x73, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_50[512] = { - 0x82, 0x74, 0x82, 0x75, 0x82, 0x76, 0x82, 0x77, /* 0x00-0x03 */ - 0x82, 0x78, 0x82, 0x79, 0x82, 0x7A, 0x82, 0x7B, /* 0x04-0x07 */ - 0x82, 0x7C, 0x82, 0x7D, 0x82, 0x7E, 0x82, 0x80, /* 0x08-0x0B */ - 0xD9, 0xC4, 0xB1, 0xB6, 0x82, 0x81, 0xD9, 0xBF, /* 0x0C-0x0F */ - 0x82, 0x82, 0x82, 0x83, 0xB5, 0xB9, 0x82, 0x84, /* 0x10-0x13 */ - 0xBE, 0xF3, 0x82, 0x85, 0x82, 0x86, 0x82, 0x87, /* 0x14-0x17 */ - 0xCC, 0xC8, 0xBA, 0xF2, 0xD2, 0xD0, 0x82, 0x88, /* 0x18-0x1B */ - 0xD9, 0xC3, 0x82, 0x89, 0x82, 0x8A, 0xBD, 0xE8, /* 0x1C-0x1F */ - 0x82, 0x8B, 0xB3, 0xAB, 0x82, 0x8C, 0x82, 0x8D, /* 0x20-0x23 */ - 0x82, 0x8E, 0xD9, 0xC5, 0xBE, 0xEB, 0x82, 0x8F, /* 0x24-0x27 */ - 0xD9, 0xC6, 0xD9, 0xBB, 0xC4, 0xDF, 0x82, 0x90, /* 0x28-0x2B */ - 0xD9, 0xBE, 0xD9, 0xC1, 0xD9, 0xC0, 0x82, 0x91, /* 0x2C-0x2F */ - 0x82, 0x92, 0x82, 0x93, 0x82, 0x94, 0x82, 0x95, /* 0x30-0x33 */ - 0x82, 0x96, 0x82, 0x97, 0x82, 0x98, 0x82, 0x99, /* 0x34-0x37 */ - 0x82, 0x9A, 0x82, 0x9B, 0xD5, 0xAE, 0x82, 0x9C, /* 0x38-0x3B */ - 0xD6, 0xB5, 0x82, 0x9D, 0xC7, 0xE3, 0x82, 0x9E, /* 0x3C-0x3F */ - 0x82, 0x9F, 0x82, 0xA0, 0x82, 0xA1, 0xD9, 0xC8, /* 0x40-0x43 */ - 0x82, 0xA2, 0x82, 0xA3, 0x82, 0xA4, 0xBC, 0xD9, /* 0x44-0x47 */ - 0xD9, 0xCA, 0x82, 0xA5, 0x82, 0xA6, 0x82, 0xA7, /* 0x48-0x4B */ - 0xD9, 0xBC, 0x82, 0xA8, 0xD9, 0xCB, 0xC6, 0xAB, /* 0x4C-0x4F */ - 0x82, 0xA9, 0x82, 0xAA, 0x82, 0xAB, 0x82, 0xAC, /* 0x50-0x53 */ - 0x82, 0xAD, 0xD9, 0xC9, 0x82, 0xAE, 0x82, 0xAF, /* 0x54-0x57 */ - 0x82, 0xB0, 0x82, 0xB1, 0xD7, 0xF6, 0x82, 0xB2, /* 0x58-0x5B */ - 0xCD, 0xA3, 0x82, 0xB3, 0x82, 0xB4, 0x82, 0xB5, /* 0x5C-0x5F */ - 0x82, 0xB6, 0x82, 0xB7, 0x82, 0xB8, 0x82, 0xB9, /* 0x60-0x63 */ - 0x82, 0xBA, 0xBD, 0xA1, 0x82, 0xBB, 0x82, 0xBC, /* 0x64-0x67 */ - 0x82, 0xBD, 0x82, 0xBE, 0x82, 0xBF, 0x82, 0xC0, /* 0x68-0x6B */ - 0xD9, 0xCC, 0x82, 0xC1, 0x82, 0xC2, 0x82, 0xC3, /* 0x6C-0x6F */ - 0x82, 0xC4, 0x82, 0xC5, 0x82, 0xC6, 0x82, 0xC7, /* 0x70-0x73 */ - 0x82, 0xC8, 0x82, 0xC9, 0xC5, 0xBC, 0xCD, 0xB5, /* 0x74-0x77 */ - 0x82, 0xCA, 0x82, 0xCB, 0x82, 0xCC, 0xD9, 0xCD, /* 0x78-0x7B */ - 0x82, 0xCD, 0x82, 0xCE, 0xD9, 0xC7, 0xB3, 0xA5, /* 0x7C-0x7F */ - - 0xBF, 0xFE, 0x82, 0xCF, 0x82, 0xD0, 0x82, 0xD1, /* 0x80-0x83 */ - 0x82, 0xD2, 0xB8, 0xB5, 0x82, 0xD3, 0x82, 0xD4, /* 0x84-0x87 */ - 0xC0, 0xFC, 0x82, 0xD5, 0x82, 0xD6, 0x82, 0xD7, /* 0x88-0x8B */ - 0x82, 0xD8, 0xB0, 0xF8, 0x82, 0xD9, 0x82, 0xDA, /* 0x8C-0x8F */ - 0x82, 0xDB, 0x82, 0xDC, 0x82, 0xDD, 0x82, 0xDE, /* 0x90-0x93 */ - 0x82, 0xDF, 0x82, 0xE0, 0x82, 0xE1, 0x82, 0xE2, /* 0x94-0x97 */ - 0x82, 0xE3, 0x82, 0xE4, 0x82, 0xE5, 0x82, 0xE6, /* 0x98-0x9B */ - 0x82, 0xE7, 0x82, 0xE8, 0x82, 0xE9, 0x82, 0xEA, /* 0x9C-0x9F */ - 0x82, 0xEB, 0x82, 0xEC, 0x82, 0xED, 0xB4, 0xF6, /* 0xA0-0xA3 */ - 0x82, 0xEE, 0xD9, 0xCE, 0x82, 0xEF, 0xD9, 0xCF, /* 0xA4-0xA7 */ - 0xB4, 0xA2, 0xD9, 0xD0, 0x82, 0xF0, 0x82, 0xF1, /* 0xA8-0xAB */ - 0xB4, 0xDF, 0x82, 0xF2, 0x82, 0xF3, 0x82, 0xF4, /* 0xAC-0xAF */ - 0x82, 0xF5, 0x82, 0xF6, 0xB0, 0xC1, 0x82, 0xF7, /* 0xB0-0xB3 */ - 0x82, 0xF8, 0x82, 0xF9, 0x82, 0xFA, 0x82, 0xFB, /* 0xB4-0xB7 */ - 0x82, 0xFC, 0x82, 0xFD, 0xD9, 0xD1, 0xC9, 0xB5, /* 0xB8-0xBB */ - 0x82, 0xFE, 0x83, 0x40, 0x83, 0x41, 0x83, 0x42, /* 0xBC-0xBF */ - 0x83, 0x43, 0x83, 0x44, 0x83, 0x45, 0x83, 0x46, /* 0xC0-0xC3 */ - 0x83, 0x47, 0x83, 0x48, 0x83, 0x49, 0x83, 0x4A, /* 0xC4-0xC7 */ - 0x83, 0x4B, 0x83, 0x4C, 0x83, 0x4D, 0x83, 0x4E, /* 0xC8-0xCB */ - 0x83, 0x4F, 0x83, 0x50, 0x83, 0x51, 0xCF, 0xF1, /* 0xCC-0xCF */ - 0x83, 0x52, 0x83, 0x53, 0x83, 0x54, 0x83, 0x55, /* 0xD0-0xD3 */ - 0x83, 0x56, 0x83, 0x57, 0xD9, 0xD2, 0x83, 0x58, /* 0xD4-0xD7 */ - 0x83, 0x59, 0x83, 0x5A, 0xC1, 0xC5, 0x83, 0x5B, /* 0xD8-0xDB */ - 0x83, 0x5C, 0x83, 0x5D, 0x83, 0x5E, 0x83, 0x5F, /* 0xDC-0xDF */ - 0x83, 0x60, 0x83, 0x61, 0x83, 0x62, 0x83, 0x63, /* 0xE0-0xE3 */ - 0x83, 0x64, 0x83, 0x65, 0xD9, 0xD6, 0xC9, 0xAE, /* 0xE4-0xE7 */ - 0x83, 0x66, 0x83, 0x67, 0x83, 0x68, 0x83, 0x69, /* 0xE8-0xEB */ - 0xD9, 0xD5, 0xD9, 0xD4, 0xD9, 0xD7, 0x83, 0x6A, /* 0xEC-0xEF */ - 0x83, 0x6B, 0x83, 0x6C, 0x83, 0x6D, 0xCB, 0xDB, /* 0xF0-0xF3 */ - 0x83, 0x6E, 0xBD, 0xA9, 0x83, 0x6F, 0x83, 0x70, /* 0xF4-0xF7 */ - 0x83, 0x71, 0x83, 0x72, 0x83, 0x73, 0xC6, 0xA7, /* 0xF8-0xFB */ - 0x83, 0x74, 0x83, 0x75, 0x83, 0x76, 0x83, 0x77, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_51[512] = { - 0x83, 0x78, 0x83, 0x79, 0x83, 0x7A, 0x83, 0x7B, /* 0x00-0x03 */ - 0x83, 0x7C, 0x83, 0x7D, 0xD9, 0xD3, 0xD9, 0xD8, /* 0x04-0x07 */ - 0x83, 0x7E, 0x83, 0x80, 0x83, 0x81, 0xD9, 0xD9, /* 0x08-0x0B */ - 0x83, 0x82, 0x83, 0x83, 0x83, 0x84, 0x83, 0x85, /* 0x0C-0x0F */ - 0x83, 0x86, 0x83, 0x87, 0xC8, 0xE5, 0x83, 0x88, /* 0x10-0x13 */ - 0x83, 0x89, 0x83, 0x8A, 0x83, 0x8B, 0x83, 0x8C, /* 0x14-0x17 */ - 0x83, 0x8D, 0x83, 0x8E, 0x83, 0x8F, 0x83, 0x90, /* 0x18-0x1B */ - 0x83, 0x91, 0x83, 0x92, 0x83, 0x93, 0x83, 0x94, /* 0x1C-0x1F */ - 0x83, 0x95, 0xC0, 0xDC, 0x83, 0x96, 0x83, 0x97, /* 0x20-0x23 */ - 0x83, 0x98, 0x83, 0x99, 0x83, 0x9A, 0x83, 0x9B, /* 0x24-0x27 */ - 0x83, 0x9C, 0x83, 0x9D, 0x83, 0x9E, 0x83, 0x9F, /* 0x28-0x2B */ - 0x83, 0xA0, 0x83, 0xA1, 0x83, 0xA2, 0x83, 0xA3, /* 0x2C-0x2F */ - 0x83, 0xA4, 0x83, 0xA5, 0x83, 0xA6, 0x83, 0xA7, /* 0x30-0x33 */ - 0x83, 0xA8, 0x83, 0xA9, 0x83, 0xAA, 0x83, 0xAB, /* 0x34-0x37 */ - 0x83, 0xAC, 0x83, 0xAD, 0x83, 0xAE, 0x83, 0xAF, /* 0x38-0x3B */ - 0x83, 0xB0, 0x83, 0xB1, 0x83, 0xB2, 0xB6, 0xF9, /* 0x3C-0x3F */ - 0xD8, 0xA3, 0xD4, 0xCA, 0x83, 0xB3, 0xD4, 0xAA, /* 0x40-0x43 */ - 0xD0, 0xD6, 0xB3, 0xE4, 0xD5, 0xD7, 0x83, 0xB4, /* 0x44-0x47 */ - 0xCF, 0xC8, 0xB9, 0xE2, 0x83, 0xB5, 0xBF, 0xCB, /* 0x48-0x4B */ - 0x83, 0xB6, 0xC3, 0xE2, 0x83, 0xB7, 0x83, 0xB8, /* 0x4C-0x4F */ - 0x83, 0xB9, 0xB6, 0xD2, 0x83, 0xBA, 0x83, 0xBB, /* 0x50-0x53 */ - 0xCD, 0xC3, 0xD9, 0xEE, 0xD9, 0xF0, 0x83, 0xBC, /* 0x54-0x57 */ - 0x83, 0xBD, 0x83, 0xBE, 0xB5, 0xB3, 0x83, 0xBF, /* 0x58-0x5B */ - 0xB6, 0xB5, 0x83, 0xC0, 0x83, 0xC1, 0x83, 0xC2, /* 0x5C-0x5F */ - 0x83, 0xC3, 0x83, 0xC4, 0xBE, 0xA4, 0x83, 0xC5, /* 0x60-0x63 */ - 0x83, 0xC6, 0xC8, 0xEB, 0x83, 0xC7, 0x83, 0xC8, /* 0x64-0x67 */ - 0xC8, 0xAB, 0x83, 0xC9, 0x83, 0xCA, 0xB0, 0xCB, /* 0x68-0x6B */ - 0xB9, 0xAB, 0xC1, 0xF9, 0xD9, 0xE2, 0x83, 0xCB, /* 0x6C-0x6F */ - 0xC0, 0xBC, 0xB9, 0xB2, 0x83, 0xCC, 0xB9, 0xD8, /* 0x70-0x73 */ - 0xD0, 0xCB, 0xB1, 0xF8, 0xC6, 0xE4, 0xBE, 0xDF, /* 0x74-0x77 */ - 0xB5, 0xE4, 0xD7, 0xC8, 0x83, 0xCD, 0xD1, 0xF8, /* 0x78-0x7B */ - 0xBC, 0xE6, 0xCA, 0xDE, 0x83, 0xCE, 0x83, 0xCF, /* 0x7C-0x7F */ - - 0xBC, 0xBD, 0xD9, 0xE6, 0xD8, 0xE7, 0x83, 0xD0, /* 0x80-0x83 */ - 0x83, 0xD1, 0xC4, 0xDA, 0x83, 0xD2, 0x83, 0xD3, /* 0x84-0x87 */ - 0xB8, 0xD4, 0xC8, 0xBD, 0x83, 0xD4, 0x83, 0xD5, /* 0x88-0x8B */ - 0xB2, 0xE1, 0xD4, 0xD9, 0x83, 0xD6, 0x83, 0xD7, /* 0x8C-0x8F */ - 0x83, 0xD8, 0x83, 0xD9, 0xC3, 0xB0, 0x83, 0xDA, /* 0x90-0x93 */ - 0x83, 0xDB, 0xC3, 0xE1, 0xDA, 0xA2, 0xC8, 0xDF, /* 0x94-0x97 */ - 0x83, 0xDC, 0xD0, 0xB4, 0x83, 0xDD, 0xBE, 0xFC, /* 0x98-0x9B */ - 0xC5, 0xA9, 0x83, 0xDE, 0x83, 0xDF, 0x83, 0xE0, /* 0x9C-0x9F */ - 0xB9, 0xDA, 0x83, 0xE1, 0xDA, 0xA3, 0x83, 0xE2, /* 0xA0-0xA3 */ - 0xD4, 0xA9, 0xDA, 0xA4, 0x83, 0xE3, 0x83, 0xE4, /* 0xA4-0xA7 */ - 0x83, 0xE5, 0x83, 0xE6, 0x83, 0xE7, 0xD9, 0xFB, /* 0xA8-0xAB */ - 0xB6, 0xAC, 0x83, 0xE8, 0x83, 0xE9, 0xB7, 0xEB, /* 0xAC-0xAF */ - 0xB1, 0xF9, 0xD9, 0xFC, 0xB3, 0xE5, 0xBE, 0xF6, /* 0xB0-0xB3 */ - 0x83, 0xEA, 0xBF, 0xF6, 0xD2, 0xB1, 0xC0, 0xE4, /* 0xB4-0xB7 */ - 0x83, 0xEB, 0x83, 0xEC, 0x83, 0xED, 0xB6, 0xB3, /* 0xB8-0xBB */ - 0xD9, 0xFE, 0xD9, 0xFD, 0x83, 0xEE, 0x83, 0xEF, /* 0xBC-0xBF */ - 0xBE, 0xBB, 0x83, 0xF0, 0x83, 0xF1, 0x83, 0xF2, /* 0xC0-0xC3 */ - 0xC6, 0xE0, 0x83, 0xF3, 0xD7, 0xBC, 0xDA, 0xA1, /* 0xC4-0xC7 */ - 0x83, 0xF4, 0xC1, 0xB9, 0x83, 0xF5, 0xB5, 0xF2, /* 0xC8-0xCB */ - 0xC1, 0xE8, 0x83, 0xF6, 0x83, 0xF7, 0xBC, 0xF5, /* 0xCC-0xCF */ - 0x83, 0xF8, 0xB4, 0xD5, 0x83, 0xF9, 0x83, 0xFA, /* 0xD0-0xD3 */ - 0x83, 0xFB, 0x83, 0xFC, 0x83, 0xFD, 0x83, 0xFE, /* 0xD4-0xD7 */ - 0x84, 0x40, 0x84, 0x41, 0x84, 0x42, 0xC1, 0xDD, /* 0xD8-0xDB */ - 0x84, 0x43, 0xC4, 0xFD, 0x84, 0x44, 0x84, 0x45, /* 0xDC-0xDF */ - 0xBC, 0xB8, 0xB7, 0xB2, 0x84, 0x46, 0x84, 0x47, /* 0xE0-0xE3 */ - 0xB7, 0xEF, 0x84, 0x48, 0x84, 0x49, 0x84, 0x4A, /* 0xE4-0xE7 */ - 0x84, 0x4B, 0x84, 0x4C, 0x84, 0x4D, 0xD9, 0xEC, /* 0xE8-0xEB */ - 0x84, 0x4E, 0xC6, 0xBE, 0x84, 0x4F, 0xBF, 0xAD, /* 0xEC-0xEF */ - 0xBB, 0xCB, 0x84, 0x50, 0x84, 0x51, 0xB5, 0xCA, /* 0xF0-0xF3 */ - 0x84, 0x52, 0xDB, 0xC9, 0xD0, 0xD7, 0x84, 0x53, /* 0xF4-0xF7 */ - 0xCD, 0xB9, 0xB0, 0xBC, 0xB3, 0xF6, 0xBB, 0xF7, /* 0xF8-0xFB */ - 0xDB, 0xCA, 0xBA, 0xAF, 0x84, 0x54, 0xD4, 0xE4, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_52[512] = { - 0xB5, 0xB6, 0xB5, 0xF3, 0xD8, 0xD6, 0xC8, 0xD0, /* 0x00-0x03 */ - 0x84, 0x55, 0x84, 0x56, 0xB7, 0xD6, 0xC7, 0xD0, /* 0x04-0x07 */ - 0xD8, 0xD7, 0x84, 0x57, 0xBF, 0xAF, 0x84, 0x58, /* 0x08-0x0B */ - 0x84, 0x59, 0xDB, 0xBB, 0xD8, 0xD8, 0x84, 0x5A, /* 0x0C-0x0F */ - 0x84, 0x5B, 0xD0, 0xCC, 0xBB, 0xAE, 0x84, 0x5C, /* 0x10-0x13 */ - 0x84, 0x5D, 0x84, 0x5E, 0xEB, 0xBE, 0xC1, 0xD0, /* 0x14-0x17 */ - 0xC1, 0xF5, 0xD4, 0xF2, 0xB8, 0xD5, 0xB4, 0xB4, /* 0x18-0x1B */ - 0x84, 0x5F, 0xB3, 0xF5, 0x84, 0x60, 0x84, 0x61, /* 0x1C-0x1F */ - 0xC9, 0xBE, 0x84, 0x62, 0x84, 0x63, 0x84, 0x64, /* 0x20-0x23 */ - 0xC5, 0xD0, 0x84, 0x65, 0x84, 0x66, 0x84, 0x67, /* 0x24-0x27 */ - 0xC5, 0xD9, 0xC0, 0xFB, 0x84, 0x68, 0xB1, 0xF0, /* 0x28-0x2B */ - 0x84, 0x69, 0xD8, 0xD9, 0xB9, 0xCE, 0x84, 0x6A, /* 0x2C-0x2F */ - 0xB5, 0xBD, 0x84, 0x6B, 0x84, 0x6C, 0xD8, 0xDA, /* 0x30-0x33 */ - 0x84, 0x6D, 0x84, 0x6E, 0xD6, 0xC6, 0xCB, 0xA2, /* 0x34-0x37 */ - 0xC8, 0xAF, 0xC9, 0xB2, 0xB4, 0xCC, 0xBF, 0xCC, /* 0x38-0x3B */ - 0x84, 0x6F, 0xB9, 0xF4, 0x84, 0x70, 0xD8, 0xDB, /* 0x3C-0x3F */ - 0xD8, 0xDC, 0xB6, 0xE7, 0xBC, 0xC1, 0xCC, 0xEA, /* 0x40-0x43 */ - 0x84, 0x71, 0x84, 0x72, 0x84, 0x73, 0x84, 0x74, /* 0x44-0x47 */ - 0x84, 0x75, 0x84, 0x76, 0xCF, 0xF7, 0x84, 0x77, /* 0x48-0x4B */ - 0xD8, 0xDD, 0xC7, 0xB0, 0x84, 0x78, 0x84, 0x79, /* 0x4C-0x4F */ - 0xB9, 0xD0, 0xBD, 0xA3, 0x84, 0x7A, 0x84, 0x7B, /* 0x50-0x53 */ - 0xCC, 0xDE, 0x84, 0x7C, 0xC6, 0xCA, 0x84, 0x7D, /* 0x54-0x57 */ - 0x84, 0x7E, 0x84, 0x80, 0x84, 0x81, 0x84, 0x82, /* 0x58-0x5B */ - 0xD8, 0xE0, 0x84, 0x83, 0xD8, 0xDE, 0x84, 0x84, /* 0x5C-0x5F */ - 0x84, 0x85, 0xD8, 0xDF, 0x84, 0x86, 0x84, 0x87, /* 0x60-0x63 */ - 0x84, 0x88, 0xB0, 0xFE, 0x84, 0x89, 0xBE, 0xE7, /* 0x64-0x67 */ - 0x84, 0x8A, 0xCA, 0xA3, 0xBC, 0xF4, 0x84, 0x8B, /* 0x68-0x6B */ - 0x84, 0x8C, 0x84, 0x8D, 0x84, 0x8E, 0xB8, 0xB1, /* 0x6C-0x6F */ - 0x84, 0x8F, 0x84, 0x90, 0xB8, 0xEE, 0x84, 0x91, /* 0x70-0x73 */ - 0x84, 0x92, 0x84, 0x93, 0x84, 0x94, 0x84, 0x95, /* 0x74-0x77 */ - 0x84, 0x96, 0x84, 0x97, 0x84, 0x98, 0x84, 0x99, /* 0x78-0x7B */ - 0x84, 0x9A, 0xD8, 0xE2, 0x84, 0x9B, 0xBD, 0xCB, /* 0x7C-0x7F */ - - 0x84, 0x9C, 0xD8, 0xE4, 0xD8, 0xE3, 0x84, 0x9D, /* 0x80-0x83 */ - 0x84, 0x9E, 0x84, 0x9F, 0x84, 0xA0, 0x84, 0xA1, /* 0x84-0x87 */ - 0xC5, 0xFC, 0x84, 0xA2, 0x84, 0xA3, 0x84, 0xA4, /* 0x88-0x8B */ - 0x84, 0xA5, 0x84, 0xA6, 0x84, 0xA7, 0x84, 0xA8, /* 0x8C-0x8F */ - 0xD8, 0xE5, 0x84, 0xA9, 0x84, 0xAA, 0xD8, 0xE6, /* 0x90-0x93 */ - 0x84, 0xAB, 0x84, 0xAC, 0x84, 0xAD, 0x84, 0xAE, /* 0x94-0x97 */ - 0x84, 0xAF, 0x84, 0xB0, 0x84, 0xB1, 0xC1, 0xA6, /* 0x98-0x9B */ - 0x84, 0xB2, 0xC8, 0xB0, 0xB0, 0xEC, 0xB9, 0xA6, /* 0x9C-0x9F */ - 0xBC, 0xD3, 0xCE, 0xF1, 0xDB, 0xBD, 0xC1, 0xD3, /* 0xA0-0xA3 */ - 0x84, 0xB3, 0x84, 0xB4, 0x84, 0xB5, 0x84, 0xB6, /* 0xA4-0xA7 */ - 0xB6, 0xAF, 0xD6, 0xFA, 0xC5, 0xAC, 0xBD, 0xD9, /* 0xA8-0xAB */ - 0xDB, 0xBE, 0xDB, 0xBF, 0x84, 0xB7, 0x84, 0xB8, /* 0xAC-0xAF */ - 0x84, 0xB9, 0xC0, 0xF8, 0xBE, 0xA2, 0xC0, 0xCD, /* 0xB0-0xB3 */ - 0x84, 0xBA, 0x84, 0xBB, 0x84, 0xBC, 0x84, 0xBD, /* 0xB4-0xB7 */ - 0x84, 0xBE, 0x84, 0xBF, 0x84, 0xC0, 0x84, 0xC1, /* 0xB8-0xBB */ - 0x84, 0xC2, 0x84, 0xC3, 0xDB, 0xC0, 0xCA, 0xC6, /* 0xBC-0xBF */ - 0x84, 0xC4, 0x84, 0xC5, 0x84, 0xC6, 0xB2, 0xAA, /* 0xC0-0xC3 */ - 0x84, 0xC7, 0x84, 0xC8, 0x84, 0xC9, 0xD3, 0xC2, /* 0xC4-0xC7 */ - 0x84, 0xCA, 0xC3, 0xE3, 0x84, 0xCB, 0xD1, 0xAB, /* 0xC8-0xCB */ - 0x84, 0xCC, 0x84, 0xCD, 0x84, 0xCE, 0x84, 0xCF, /* 0xCC-0xCF */ - 0xDB, 0xC2, 0x84, 0xD0, 0xC0, 0xD5, 0x84, 0xD1, /* 0xD0-0xD3 */ - 0x84, 0xD2, 0x84, 0xD3, 0xDB, 0xC3, 0x84, 0xD4, /* 0xD4-0xD7 */ - 0xBF, 0xB1, 0x84, 0xD5, 0x84, 0xD6, 0x84, 0xD7, /* 0xD8-0xDB */ - 0x84, 0xD8, 0x84, 0xD9, 0x84, 0xDA, 0xC4, 0xBC, /* 0xDC-0xDF */ - 0x84, 0xDB, 0x84, 0xDC, 0x84, 0xDD, 0x84, 0xDE, /* 0xE0-0xE3 */ - 0xC7, 0xDA, 0x84, 0xDF, 0x84, 0xE0, 0x84, 0xE1, /* 0xE4-0xE7 */ - 0x84, 0xE2, 0x84, 0xE3, 0x84, 0xE4, 0x84, 0xE5, /* 0xE8-0xEB */ - 0x84, 0xE6, 0x84, 0xE7, 0x84, 0xE8, 0x84, 0xE9, /* 0xEC-0xEF */ - 0xDB, 0xC4, 0x84, 0xEA, 0x84, 0xEB, 0x84, 0xEC, /* 0xF0-0xF3 */ - 0x84, 0xED, 0x84, 0xEE, 0x84, 0xEF, 0x84, 0xF0, /* 0xF4-0xF7 */ - 0x84, 0xF1, 0xD9, 0xE8, 0xC9, 0xD7, 0x84, 0xF2, /* 0xF8-0xFB */ - 0x84, 0xF3, 0x84, 0xF4, 0xB9, 0xB4, 0xCE, 0xF0, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_53[512] = { - 0xD4, 0xC8, 0x84, 0xF5, 0x84, 0xF6, 0x84, 0xF7, /* 0x00-0x03 */ - 0x84, 0xF8, 0xB0, 0xFC, 0xB4, 0xD2, 0x84, 0xF9, /* 0x04-0x07 */ - 0xD0, 0xD9, 0x84, 0xFA, 0x84, 0xFB, 0x84, 0xFC, /* 0x08-0x0B */ - 0x84, 0xFD, 0xD9, 0xE9, 0x84, 0xFE, 0xDE, 0xCB, /* 0x0C-0x0F */ - 0xD9, 0xEB, 0x85, 0x40, 0x85, 0x41, 0x85, 0x42, /* 0x10-0x13 */ - 0x85, 0x43, 0xD8, 0xB0, 0xBB, 0xAF, 0xB1, 0xB1, /* 0x14-0x17 */ - 0x85, 0x44, 0xB3, 0xD7, 0xD8, 0xCE, 0x85, 0x45, /* 0x18-0x1B */ - 0x85, 0x46, 0xD4, 0xD1, 0x85, 0x47, 0x85, 0x48, /* 0x1C-0x1F */ - 0xBD, 0xB3, 0xBF, 0xEF, 0x85, 0x49, 0xCF, 0xBB, /* 0x20-0x23 */ - 0x85, 0x4A, 0x85, 0x4B, 0xD8, 0xD0, 0x85, 0x4C, /* 0x24-0x27 */ - 0x85, 0x4D, 0x85, 0x4E, 0xB7, 0xCB, 0x85, 0x4F, /* 0x28-0x2B */ - 0x85, 0x50, 0x85, 0x51, 0xD8, 0xD1, 0x85, 0x52, /* 0x2C-0x2F */ - 0x85, 0x53, 0x85, 0x54, 0x85, 0x55, 0x85, 0x56, /* 0x30-0x33 */ - 0x85, 0x57, 0x85, 0x58, 0x85, 0x59, 0x85, 0x5A, /* 0x34-0x37 */ - 0x85, 0x5B, 0xC6, 0xA5, 0xC7, 0xF8, 0xD2, 0xBD, /* 0x38-0x3B */ - 0x85, 0x5C, 0x85, 0x5D, 0xD8, 0xD2, 0xC4, 0xE4, /* 0x3C-0x3F */ - 0x85, 0x5E, 0xCA, 0xAE, 0x85, 0x5F, 0xC7, 0xA7, /* 0x40-0x43 */ - 0x85, 0x60, 0xD8, 0xA6, 0x85, 0x61, 0xC9, 0xFD, /* 0x44-0x47 */ - 0xCE, 0xE7, 0xBB, 0xDC, 0xB0, 0xEB, 0x85, 0x62, /* 0x48-0x4B */ - 0x85, 0x63, 0x85, 0x64, 0xBB, 0xAA, 0xD0, 0xAD, /* 0x4C-0x4F */ - 0x85, 0x65, 0xB1, 0xB0, 0xD7, 0xE4, 0xD7, 0xBF, /* 0x50-0x53 */ - 0x85, 0x66, 0xB5, 0xA5, 0xC2, 0xF4, 0xC4, 0xCF, /* 0x54-0x57 */ - 0x85, 0x67, 0x85, 0x68, 0xB2, 0xA9, 0x85, 0x69, /* 0x58-0x5B */ - 0xB2, 0xB7, 0x85, 0x6A, 0xB1, 0xE5, 0xDF, 0xB2, /* 0x5C-0x5F */ - 0xD5, 0xBC, 0xBF, 0xA8, 0xC2, 0xAC, 0xD8, 0xD5, /* 0x60-0x63 */ - 0xC2, 0xB1, 0x85, 0x6B, 0xD8, 0xD4, 0xCE, 0xD4, /* 0x64-0x67 */ - 0x85, 0x6C, 0xDA, 0xE0, 0x85, 0x6D, 0xCE, 0xC0, /* 0x68-0x6B */ - 0x85, 0x6E, 0x85, 0x6F, 0xD8, 0xB4, 0xC3, 0xAE, /* 0x6C-0x6F */ - 0xD3, 0xA1, 0xCE, 0xA3, 0x85, 0x70, 0xBC, 0xB4, /* 0x70-0x73 */ - 0xC8, 0xB4, 0xC2, 0xD1, 0x85, 0x71, 0xBE, 0xED, /* 0x74-0x77 */ - 0xD0, 0xB6, 0x85, 0x72, 0xDA, 0xE1, 0x85, 0x73, /* 0x78-0x7B */ - 0x85, 0x74, 0x85, 0x75, 0x85, 0x76, 0xC7, 0xE4, /* 0x7C-0x7F */ - - 0x85, 0x77, 0x85, 0x78, 0xB3, 0xA7, 0x85, 0x79, /* 0x80-0x83 */ - 0xB6, 0xF2, 0xCC, 0xFC, 0xC0, 0xFA, 0x85, 0x7A, /* 0x84-0x87 */ - 0x85, 0x7B, 0xC0, 0xF7, 0x85, 0x7C, 0xD1, 0xB9, /* 0x88-0x8B */ - 0xD1, 0xE1, 0xD8, 0xC7, 0x85, 0x7D, 0x85, 0x7E, /* 0x8C-0x8F */ - 0x85, 0x80, 0x85, 0x81, 0x85, 0x82, 0x85, 0x83, /* 0x90-0x93 */ - 0x85, 0x84, 0xB2, 0xDE, 0x85, 0x85, 0x85, 0x86, /* 0x94-0x97 */ - 0xC0, 0xE5, 0x85, 0x87, 0xBA, 0xF1, 0x85, 0x88, /* 0x98-0x9B */ - 0x85, 0x89, 0xD8, 0xC8, 0x85, 0x8A, 0xD4, 0xAD, /* 0x9C-0x9F */ - 0x85, 0x8B, 0x85, 0x8C, 0xCF, 0xE1, 0xD8, 0xC9, /* 0xA0-0xA3 */ - 0x85, 0x8D, 0xD8, 0xCA, 0xCF, 0xC3, 0x85, 0x8E, /* 0xA4-0xA7 */ - 0xB3, 0xF8, 0xBE, 0xC7, 0x85, 0x8F, 0x85, 0x90, /* 0xA8-0xAB */ - 0x85, 0x91, 0x85, 0x92, 0xD8, 0xCB, 0x85, 0x93, /* 0xAC-0xAF */ - 0x85, 0x94, 0x85, 0x95, 0x85, 0x96, 0x85, 0x97, /* 0xB0-0xB3 */ - 0x85, 0x98, 0x85, 0x99, 0xDB, 0xCC, 0x85, 0x9A, /* 0xB4-0xB7 */ - 0x85, 0x9B, 0x85, 0x9C, 0x85, 0x9D, 0xC8, 0xA5, /* 0xB8-0xBB */ - 0x85, 0x9E, 0x85, 0x9F, 0x85, 0xA0, 0xCF, 0xD8, /* 0xBC-0xBF */ - 0x85, 0xA1, 0xC8, 0xFE, 0xB2, 0xCE, 0x85, 0xA2, /* 0xC0-0xC3 */ - 0x85, 0xA3, 0x85, 0xA4, 0x85, 0xA5, 0x85, 0xA6, /* 0xC4-0xC7 */ - 0xD3, 0xD6, 0xB2, 0xE6, 0xBC, 0xB0, 0xD3, 0xD1, /* 0xC8-0xCB */ - 0xCB, 0xAB, 0xB7, 0xB4, 0x85, 0xA7, 0x85, 0xA8, /* 0xCC-0xCF */ - 0x85, 0xA9, 0xB7, 0xA2, 0x85, 0xAA, 0x85, 0xAB, /* 0xD0-0xD3 */ - 0xCA, 0xE5, 0x85, 0xAC, 0xC8, 0xA1, 0xCA, 0xDC, /* 0xD4-0xD7 */ - 0xB1, 0xE4, 0xD0, 0xF0, 0x85, 0xAD, 0xC5, 0xD1, /* 0xD8-0xDB */ - 0x85, 0xAE, 0x85, 0xAF, 0x85, 0xB0, 0xDB, 0xC5, /* 0xDC-0xDF */ - 0xB5, 0xFE, 0x85, 0xB1, 0x85, 0xB2, 0xBF, 0xDA, /* 0xE0-0xE3 */ - 0xB9, 0xC5, 0xBE, 0xE4, 0xC1, 0xED, 0x85, 0xB3, /* 0xE4-0xE7 */ - 0xDF, 0xB6, 0xDF, 0xB5, 0xD6, 0xBB, 0xBD, 0xD0, /* 0xE8-0xEB */ - 0xD5, 0xD9, 0xB0, 0xC8, 0xB6, 0xA3, 0xBF, 0xC9, /* 0xEC-0xEF */ - 0xCC, 0xA8, 0xDF, 0xB3, 0xCA, 0xB7, 0xD3, 0xD2, /* 0xF0-0xF3 */ - 0x85, 0xB4, 0xD8, 0xCF, 0xD2, 0xB6, 0xBA, 0xC5, /* 0xF4-0xF7 */ - 0xCB, 0xBE, 0xCC, 0xBE, 0x85, 0xB5, 0xDF, 0xB7, /* 0xF8-0xFB */ - 0xB5, 0xF0, 0xDF, 0xB4, 0x85, 0xB6, 0x85, 0xB7, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_54[512] = { - 0x85, 0xB8, 0xD3, 0xF5, 0x85, 0xB9, 0xB3, 0xD4, /* 0x00-0x03 */ - 0xB8, 0xF7, 0x85, 0xBA, 0xDF, 0xBA, 0x85, 0xBB, /* 0x04-0x07 */ - 0xBA, 0xCF, 0xBC, 0xAA, 0xB5, 0xF5, 0x85, 0xBC, /* 0x08-0x0B */ - 0xCD, 0xAC, 0xC3, 0xFB, 0xBA, 0xF3, 0xC0, 0xF4, /* 0x0C-0x0F */ - 0xCD, 0xC2, 0xCF, 0xF2, 0xDF, 0xB8, 0xCF, 0xC5, /* 0x10-0x13 */ - 0x85, 0xBD, 0xC2, 0xC0, 0xDF, 0xB9, 0xC2, 0xF0, /* 0x14-0x17 */ - 0x85, 0xBE, 0x85, 0xBF, 0x85, 0xC0, 0xBE, 0xFD, /* 0x18-0x1B */ - 0x85, 0xC1, 0xC1, 0xDF, 0xCD, 0xCC, 0xD2, 0xF7, /* 0x1C-0x1F */ - 0xB7, 0xCD, 0xDF, 0xC1, 0x85, 0xC2, 0xDF, 0xC4, /* 0x20-0x23 */ - 0x85, 0xC3, 0x85, 0xC4, 0xB7, 0xF1, 0xB0, 0xC9, /* 0x24-0x27 */ - 0xB6, 0xD6, 0xB7, 0xD4, 0x85, 0xC5, 0xBA, 0xAC, /* 0x28-0x2B */ - 0xCC, 0xFD, 0xBF, 0xD4, 0xCB, 0xB1, 0xC6, 0xF4, /* 0x2C-0x2F */ - 0x85, 0xC6, 0xD6, 0xA8, 0xDF, 0xC5, 0x85, 0xC7, /* 0x30-0x33 */ - 0xCE, 0xE2, 0xB3, 0xB3, 0x85, 0xC8, 0x85, 0xC9, /* 0x34-0x37 */ - 0xCE, 0xFC, 0xB4, 0xB5, 0x85, 0xCA, 0xCE, 0xC7, /* 0x38-0x3B */ - 0xBA, 0xF0, 0x85, 0xCB, 0xCE, 0xE1, 0x85, 0xCC, /* 0x3C-0x3F */ - 0xD1, 0xBD, 0x85, 0xCD, 0x85, 0xCE, 0xDF, 0xC0, /* 0x40-0x43 */ - 0x85, 0xCF, 0x85, 0xD0, 0xB4, 0xF4, 0x85, 0xD1, /* 0x44-0x47 */ - 0xB3, 0xCA, 0x85, 0xD2, 0xB8, 0xE6, 0xDF, 0xBB, /* 0x48-0x4B */ - 0x85, 0xD3, 0x85, 0xD4, 0x85, 0xD5, 0x85, 0xD6, /* 0x4C-0x4F */ - 0xC4, 0xC5, 0x85, 0xD7, 0xDF, 0xBC, 0xDF, 0xBD, /* 0x50-0x53 */ - 0xDF, 0xBE, 0xC5, 0xBB, 0xDF, 0xBF, 0xDF, 0xC2, /* 0x54-0x57 */ - 0xD4, 0xB1, 0xDF, 0xC3, 0x85, 0xD8, 0xC7, 0xBA, /* 0x58-0x5B */ - 0xCE, 0xD8, 0x85, 0xD9, 0x85, 0xDA, 0x85, 0xDB, /* 0x5C-0x5F */ - 0x85, 0xDC, 0x85, 0xDD, 0xC4, 0xD8, 0x85, 0xDE, /* 0x60-0x63 */ - 0xDF, 0xCA, 0x85, 0xDF, 0xDF, 0xCF, 0x85, 0xE0, /* 0x64-0x67 */ - 0xD6, 0xDC, 0x85, 0xE1, 0x85, 0xE2, 0x85, 0xE3, /* 0x68-0x6B */ - 0x85, 0xE4, 0x85, 0xE5, 0x85, 0xE6, 0x85, 0xE7, /* 0x6C-0x6F */ - 0x85, 0xE8, 0xDF, 0xC9, 0xDF, 0xDA, 0xCE, 0xB6, /* 0x70-0x73 */ - 0x85, 0xE9, 0xBA, 0xC7, 0xDF, 0xCE, 0xDF, 0xC8, /* 0x74-0x77 */ - 0xC5, 0xDE, 0x85, 0xEA, 0x85, 0xEB, 0xC9, 0xEB, /* 0x78-0x7B */ - 0xBA, 0xF4, 0xC3, 0xFC, 0x85, 0xEC, 0x85, 0xED, /* 0x7C-0x7F */ - - 0xBE, 0xD7, 0x85, 0xEE, 0xDF, 0xC6, 0x85, 0xEF, /* 0x80-0x83 */ - 0xDF, 0xCD, 0x85, 0xF0, 0xC5, 0xD8, 0x85, 0xF1, /* 0x84-0x87 */ - 0x85, 0xF2, 0x85, 0xF3, 0x85, 0xF4, 0xD5, 0xA6, /* 0x88-0x8B */ - 0xBA, 0xCD, 0x85, 0xF5, 0xBE, 0xCC, 0xD3, 0xBD, /* 0x8C-0x8F */ - 0xB8, 0xC0, 0x85, 0xF6, 0xD6, 0xE4, 0x85, 0xF7, /* 0x90-0x93 */ - 0xDF, 0xC7, 0xB9, 0xBE, 0xBF, 0xA7, 0x85, 0xF8, /* 0x94-0x97 */ - 0x85, 0xF9, 0xC1, 0xFC, 0xDF, 0xCB, 0xDF, 0xCC, /* 0x98-0x9B */ - 0x85, 0xFA, 0xDF, 0xD0, 0x85, 0xFB, 0x85, 0xFC, /* 0x9C-0x9F */ - 0x85, 0xFD, 0x85, 0xFE, 0x86, 0x40, 0xDF, 0xDB, /* 0xA0-0xA3 */ - 0xDF, 0xE5, 0x86, 0x41, 0xDF, 0xD7, 0xDF, 0xD6, /* 0xA4-0xA7 */ - 0xD7, 0xC9, 0xDF, 0xE3, 0xDF, 0xE4, 0xE5, 0xEB, /* 0xA8-0xAB */ - 0xD2, 0xA7, 0xDF, 0xD2, 0x86, 0x42, 0xBF, 0xA9, /* 0xAC-0xAF */ - 0x86, 0x43, 0xD4, 0xDB, 0x86, 0x44, 0xBF, 0xC8, /* 0xB0-0xB3 */ - 0xDF, 0xD4, 0x86, 0x45, 0x86, 0x46, 0x86, 0x47, /* 0xB4-0xB7 */ - 0xCF, 0xCC, 0x86, 0x48, 0x86, 0x49, 0xDF, 0xDD, /* 0xB8-0xBB */ - 0x86, 0x4A, 0xD1, 0xCA, 0x86, 0x4B, 0xDF, 0xDE, /* 0xBC-0xBF */ - 0xB0, 0xA7, 0xC6, 0xB7, 0xDF, 0xD3, 0x86, 0x4C, /* 0xC0-0xC3 */ - 0xBA, 0xE5, 0x86, 0x4D, 0xB6, 0xDF, 0xCD, 0xDB, /* 0xC4-0xC7 */ - 0xB9, 0xFE, 0xD4, 0xD5, 0x86, 0x4E, 0x86, 0x4F, /* 0xC8-0xCB */ - 0xDF, 0xDF, 0xCF, 0xEC, 0xB0, 0xA5, 0xDF, 0xE7, /* 0xCC-0xCF */ - 0xDF, 0xD1, 0xD1, 0xC6, 0xDF, 0xD5, 0xDF, 0xD8, /* 0xD0-0xD3 */ - 0xDF, 0xD9, 0xDF, 0xDC, 0x86, 0x50, 0xBB, 0xA9, /* 0xD4-0xD7 */ - 0x86, 0x51, 0xDF, 0xE0, 0xDF, 0xE1, 0x86, 0x52, /* 0xD8-0xDB */ - 0xDF, 0xE2, 0xDF, 0xE6, 0xDF, 0xE8, 0xD3, 0xB4, /* 0xDC-0xDF */ - 0x86, 0x53, 0x86, 0x54, 0x86, 0x55, 0x86, 0x56, /* 0xE0-0xE3 */ - 0x86, 0x57, 0xB8, 0xE7, 0xC5, 0xB6, 0xDF, 0xEA, /* 0xE4-0xE7 */ - 0xC9, 0xDA, 0xC1, 0xA8, 0xC4, 0xC4, 0x86, 0x58, /* 0xE8-0xEB */ - 0x86, 0x59, 0xBF, 0xDE, 0xCF, 0xF8, 0x86, 0x5A, /* 0xEC-0xEF */ - 0x86, 0x5B, 0x86, 0x5C, 0xD5, 0xDC, 0xDF, 0xEE, /* 0xF0-0xF3 */ - 0x86, 0x5D, 0x86, 0x5E, 0x86, 0x5F, 0x86, 0x60, /* 0xF4-0xF7 */ - 0x86, 0x61, 0x86, 0x62, 0xB2, 0xB8, 0x86, 0x63, /* 0xF8-0xFB */ - 0xBA, 0xDF, 0xDF, 0xEC, 0x86, 0x64, 0xDB, 0xC1, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_55[512] = { - 0x86, 0x65, 0xD1, 0xE4, 0x86, 0x66, 0x86, 0x67, /* 0x00-0x03 */ - 0x86, 0x68, 0x86, 0x69, 0xCB, 0xF4, 0xB4, 0xBD, /* 0x04-0x07 */ - 0x86, 0x6A, 0xB0, 0xA6, 0x86, 0x6B, 0x86, 0x6C, /* 0x08-0x0B */ - 0x86, 0x6D, 0x86, 0x6E, 0x86, 0x6F, 0xDF, 0xF1, /* 0x0C-0x0F */ - 0xCC, 0xC6, 0xDF, 0xF2, 0x86, 0x70, 0x86, 0x71, /* 0x10-0x13 */ - 0xDF, 0xED, 0x86, 0x72, 0x86, 0x73, 0x86, 0x74, /* 0x14-0x17 */ - 0x86, 0x75, 0x86, 0x76, 0x86, 0x77, 0xDF, 0xE9, /* 0x18-0x1B */ - 0x86, 0x78, 0x86, 0x79, 0x86, 0x7A, 0x86, 0x7B, /* 0x1C-0x1F */ - 0xDF, 0xEB, 0x86, 0x7C, 0xDF, 0xEF, 0xDF, 0xF0, /* 0x20-0x23 */ - 0xBB, 0xBD, 0x86, 0x7D, 0x86, 0x7E, 0xDF, 0xF3, /* 0x24-0x27 */ - 0x86, 0x80, 0x86, 0x81, 0xDF, 0xF4, 0x86, 0x82, /* 0x28-0x2B */ - 0xBB, 0xA3, 0x86, 0x83, 0xCA, 0xDB, 0xCE, 0xA8, /* 0x2C-0x2F */ - 0xE0, 0xA7, 0xB3, 0xAA, 0x86, 0x84, 0xE0, 0xA6, /* 0x30-0x33 */ - 0x86, 0x85, 0x86, 0x86, 0x86, 0x87, 0xE0, 0xA1, /* 0x34-0x37 */ - 0x86, 0x88, 0x86, 0x89, 0x86, 0x8A, 0x86, 0x8B, /* 0x38-0x3B */ - 0xDF, 0xFE, 0x86, 0x8C, 0xCD, 0xD9, 0xDF, 0xFC, /* 0x3C-0x3F */ - 0x86, 0x8D, 0xDF, 0xFA, 0x86, 0x8E, 0xBF, 0xD0, /* 0x40-0x43 */ - 0xD7, 0xC4, 0x86, 0x8F, 0xC9, 0xCC, 0x86, 0x90, /* 0x44-0x47 */ - 0x86, 0x91, 0xDF, 0xF8, 0xB0, 0xA1, 0x86, 0x92, /* 0x48-0x4B */ - 0x86, 0x93, 0x86, 0x94, 0x86, 0x95, 0x86, 0x96, /* 0x4C-0x4F */ - 0xDF, 0xFD, 0x86, 0x97, 0x86, 0x98, 0x86, 0x99, /* 0x50-0x53 */ - 0x86, 0x9A, 0xDF, 0xFB, 0xE0, 0xA2, 0x86, 0x9B, /* 0x54-0x57 */ - 0x86, 0x9C, 0x86, 0x9D, 0x86, 0x9E, 0x86, 0x9F, /* 0x58-0x5B */ - 0xE0, 0xA8, 0x86, 0xA0, 0x86, 0xA1, 0x86, 0xA2, /* 0x5C-0x5F */ - 0x86, 0xA3, 0xB7, 0xC8, 0x86, 0xA4, 0x86, 0xA5, /* 0x60-0x63 */ - 0xC6, 0xA1, 0xC9, 0xB6, 0xC0, 0xB2, 0xDF, 0xF5, /* 0x64-0x67 */ - 0x86, 0xA6, 0x86, 0xA7, 0xC5, 0xBE, 0x86, 0xA8, /* 0x68-0x6B */ - 0xD8, 0xC4, 0xDF, 0xF9, 0xC4, 0xF6, 0x86, 0xA9, /* 0x6C-0x6F */ - 0x86, 0xAA, 0x86, 0xAB, 0x86, 0xAC, 0x86, 0xAD, /* 0x70-0x73 */ - 0x86, 0xAE, 0xE0, 0xA3, 0xE0, 0xA4, 0xE0, 0xA5, /* 0x74-0x77 */ - 0xD0, 0xA5, 0x86, 0xAF, 0x86, 0xB0, 0xE0, 0xB4, /* 0x78-0x7B */ - 0xCC, 0xE4, 0x86, 0xB1, 0xE0, 0xB1, 0x86, 0xB2, /* 0x7C-0x7F */ - - 0xBF, 0xA6, 0xE0, 0xAF, 0xCE, 0xB9, 0xE0, 0xAB, /* 0x80-0x83 */ - 0xC9, 0xC6, 0x86, 0xB3, 0x86, 0xB4, 0xC0, 0xAE, /* 0x84-0x87 */ - 0xE0, 0xAE, 0xBA, 0xED, 0xBA, 0xB0, 0xE0, 0xA9, /* 0x88-0x8B */ - 0x86, 0xB5, 0x86, 0xB6, 0x86, 0xB7, 0xDF, 0xF6, /* 0x8C-0x8F */ - 0x86, 0xB8, 0xE0, 0xB3, 0x86, 0xB9, 0x86, 0xBA, /* 0x90-0x93 */ - 0xE0, 0xB8, 0x86, 0xBB, 0x86, 0xBC, 0x86, 0xBD, /* 0x94-0x97 */ - 0xB4, 0xAD, 0xE0, 0xB9, 0x86, 0xBE, 0x86, 0xBF, /* 0x98-0x9B */ - 0xCF, 0xB2, 0xBA, 0xC8, 0x86, 0xC0, 0xE0, 0xB0, /* 0x9C-0x9F */ - 0x86, 0xC1, 0x86, 0xC2, 0x86, 0xC3, 0x86, 0xC4, /* 0xA0-0xA3 */ - 0x86, 0xC5, 0x86, 0xC6, 0x86, 0xC7, 0xD0, 0xFA, /* 0xA4-0xA7 */ - 0x86, 0xC8, 0x86, 0xC9, 0x86, 0xCA, 0x86, 0xCB, /* 0xA8-0xAB */ - 0x86, 0xCC, 0x86, 0xCD, 0x86, 0xCE, 0x86, 0xCF, /* 0xAC-0xAF */ - 0x86, 0xD0, 0xE0, 0xAC, 0x86, 0xD1, 0xD4, 0xFB, /* 0xB0-0xB3 */ - 0x86, 0xD2, 0xDF, 0xF7, 0x86, 0xD3, 0xC5, 0xE7, /* 0xB4-0xB7 */ - 0x86, 0xD4, 0xE0, 0xAD, 0x86, 0xD5, 0xD3, 0xF7, /* 0xB8-0xBB */ - 0x86, 0xD6, 0xE0, 0xB6, 0xE0, 0xB7, 0x86, 0xD7, /* 0xBC-0xBF */ - 0x86, 0xD8, 0x86, 0xD9, 0x86, 0xDA, 0x86, 0xDB, /* 0xC0-0xC3 */ - 0xE0, 0xC4, 0xD0, 0xE1, 0x86, 0xDC, 0x86, 0xDD, /* 0xC4-0xC7 */ - 0x86, 0xDE, 0xE0, 0xBC, 0x86, 0xDF, 0x86, 0xE0, /* 0xC8-0xCB */ - 0xE0, 0xC9, 0xE0, 0xCA, 0x86, 0xE1, 0x86, 0xE2, /* 0xCC-0xCF */ - 0x86, 0xE3, 0xE0, 0xBE, 0xE0, 0xAA, 0xC9, 0xA4, /* 0xD0-0xD3 */ - 0xE0, 0xC1, 0x86, 0xE4, 0xE0, 0xB2, 0x86, 0xE5, /* 0xD4-0xD7 */ - 0x86, 0xE6, 0x86, 0xE7, 0x86, 0xE8, 0x86, 0xE9, /* 0xD8-0xDB */ - 0xCA, 0xC8, 0xE0, 0xC3, 0x86, 0xEA, 0xE0, 0xB5, /* 0xDC-0xDF */ - 0x86, 0xEB, 0xCE, 0xCB, 0x86, 0xEC, 0xCB, 0xC3, /* 0xE0-0xE3 */ - 0xE0, 0xCD, 0xE0, 0xC6, 0xE0, 0xC2, 0x86, 0xED, /* 0xE4-0xE7 */ - 0xE0, 0xCB, 0x86, 0xEE, 0xE0, 0xBA, 0xE0, 0xBF, /* 0xE8-0xEB */ - 0xE0, 0xC0, 0x86, 0xEF, 0x86, 0xF0, 0xE0, 0xC5, /* 0xEC-0xEF */ - 0x86, 0xF1, 0x86, 0xF2, 0xE0, 0xC7, 0xE0, 0xC8, /* 0xF0-0xF3 */ - 0x86, 0xF3, 0xE0, 0xCC, 0x86, 0xF4, 0xE0, 0xBB, /* 0xF4-0xF7 */ - 0x86, 0xF5, 0x86, 0xF6, 0x86, 0xF7, 0x86, 0xF8, /* 0xF8-0xFB */ - 0x86, 0xF9, 0xCB, 0xD4, 0xE0, 0xD5, 0x86, 0xFA, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_56[512] = { - 0xE0, 0xD6, 0xE0, 0xD2, 0x86, 0xFB, 0x86, 0xFC, /* 0x00-0x03 */ - 0x86, 0xFD, 0x86, 0xFE, 0x87, 0x40, 0x87, 0x41, /* 0x04-0x07 */ - 0xE0, 0xD0, 0xBC, 0xCE, 0x87, 0x42, 0x87, 0x43, /* 0x08-0x0B */ - 0xE0, 0xD1, 0x87, 0x44, 0xB8, 0xC2, 0xD8, 0xC5, /* 0x0C-0x0F */ - 0x87, 0x45, 0x87, 0x46, 0x87, 0x47, 0x87, 0x48, /* 0x10-0x13 */ - 0x87, 0x49, 0x87, 0x4A, 0x87, 0x4B, 0x87, 0x4C, /* 0x14-0x17 */ - 0xD0, 0xEA, 0x87, 0x4D, 0x87, 0x4E, 0xC2, 0xEF, /* 0x18-0x1B */ - 0x87, 0x4F, 0x87, 0x50, 0xE0, 0xCF, 0xE0, 0xBD, /* 0x1C-0x1F */ - 0x87, 0x51, 0x87, 0x52, 0x87, 0x53, 0xE0, 0xD4, /* 0x20-0x23 */ - 0xE0, 0xD3, 0x87, 0x54, 0x87, 0x55, 0xE0, 0xD7, /* 0x24-0x27 */ - 0x87, 0x56, 0x87, 0x57, 0x87, 0x58, 0x87, 0x59, /* 0x28-0x2B */ - 0xE0, 0xDC, 0xE0, 0xD8, 0x87, 0x5A, 0x87, 0x5B, /* 0x2C-0x2F */ - 0x87, 0x5C, 0xD6, 0xF6, 0xB3, 0xB0, 0x87, 0x5D, /* 0x30-0x33 */ - 0xD7, 0xEC, 0x87, 0x5E, 0xCB, 0xBB, 0x87, 0x5F, /* 0x34-0x37 */ - 0x87, 0x60, 0xE0, 0xDA, 0x87, 0x61, 0xCE, 0xFB, /* 0x38-0x3B */ - 0x87, 0x62, 0x87, 0x63, 0x87, 0x64, 0xBA, 0xD9, /* 0x3C-0x3F */ - 0x87, 0x65, 0x87, 0x66, 0x87, 0x67, 0x87, 0x68, /* 0x40-0x43 */ - 0x87, 0x69, 0x87, 0x6A, 0x87, 0x6B, 0x87, 0x6C, /* 0x44-0x47 */ - 0x87, 0x6D, 0x87, 0x6E, 0x87, 0x6F, 0x87, 0x70, /* 0x48-0x4B */ - 0xE0, 0xE1, 0xE0, 0xDD, 0xD2, 0xAD, 0x87, 0x71, /* 0x4C-0x4F */ - 0x87, 0x72, 0x87, 0x73, 0x87, 0x74, 0x87, 0x75, /* 0x50-0x53 */ - 0xE0, 0xE2, 0x87, 0x76, 0x87, 0x77, 0xE0, 0xDB, /* 0x54-0x57 */ - 0xE0, 0xD9, 0xE0, 0xDF, 0x87, 0x78, 0x87, 0x79, /* 0x58-0x5B */ - 0xE0, 0xE0, 0x87, 0x7A, 0x87, 0x7B, 0x87, 0x7C, /* 0x5C-0x5F */ - 0x87, 0x7D, 0x87, 0x7E, 0xE0, 0xDE, 0x87, 0x80, /* 0x60-0x63 */ - 0xE0, 0xE4, 0x87, 0x81, 0x87, 0x82, 0x87, 0x83, /* 0x64-0x67 */ - 0xC6, 0xF7, 0xD8, 0xAC, 0xD4, 0xEB, 0xE0, 0xE6, /* 0x68-0x6B */ - 0xCA, 0xC9, 0x87, 0x84, 0x87, 0x85, 0x87, 0x86, /* 0x6C-0x6F */ - 0x87, 0x87, 0xE0, 0xE5, 0x87, 0x88, 0x87, 0x89, /* 0x70-0x73 */ - 0x87, 0x8A, 0x87, 0x8B, 0xB8, 0xC1, 0x87, 0x8C, /* 0x74-0x77 */ - 0x87, 0x8D, 0x87, 0x8E, 0x87, 0x8F, 0xE0, 0xE7, /* 0x78-0x7B */ - 0xE0, 0xE8, 0x87, 0x90, 0x87, 0x91, 0x87, 0x92, /* 0x7C-0x7F */ - - 0x87, 0x93, 0x87, 0x94, 0x87, 0x95, 0x87, 0x96, /* 0x80-0x83 */ - 0x87, 0x97, 0xE0, 0xE9, 0xE0, 0xE3, 0x87, 0x98, /* 0x84-0x87 */ - 0x87, 0x99, 0x87, 0x9A, 0x87, 0x9B, 0x87, 0x9C, /* 0x88-0x8B */ - 0x87, 0x9D, 0x87, 0x9E, 0xBA, 0xBF, 0xCC, 0xE7, /* 0x8C-0x8F */ - 0x87, 0x9F, 0x87, 0xA0, 0x87, 0xA1, 0xE0, 0xEA, /* 0x90-0x93 */ - 0x87, 0xA2, 0x87, 0xA3, 0x87, 0xA4, 0x87, 0xA5, /* 0x94-0x97 */ - 0x87, 0xA6, 0x87, 0xA7, 0x87, 0xA8, 0x87, 0xA9, /* 0x98-0x9B */ - 0x87, 0xAA, 0x87, 0xAB, 0x87, 0xAC, 0x87, 0xAD, /* 0x9C-0x9F */ - 0x87, 0xAE, 0x87, 0xAF, 0x87, 0xB0, 0xCF, 0xF9, /* 0xA0-0xA3 */ - 0x87, 0xB1, 0x87, 0xB2, 0x87, 0xB3, 0x87, 0xB4, /* 0xA4-0xA7 */ - 0x87, 0xB5, 0x87, 0xB6, 0x87, 0xB7, 0x87, 0xB8, /* 0xA8-0xAB */ - 0x87, 0xB9, 0x87, 0xBA, 0x87, 0xBB, 0xE0, 0xEB, /* 0xAC-0xAF */ - 0x87, 0xBC, 0x87, 0xBD, 0x87, 0xBE, 0x87, 0xBF, /* 0xB0-0xB3 */ - 0x87, 0xC0, 0x87, 0xC1, 0x87, 0xC2, 0xC8, 0xC2, /* 0xB4-0xB7 */ - 0x87, 0xC3, 0x87, 0xC4, 0x87, 0xC5, 0x87, 0xC6, /* 0xB8-0xBB */ - 0xBD, 0xC0, 0x87, 0xC7, 0x87, 0xC8, 0x87, 0xC9, /* 0xBC-0xBF */ - 0x87, 0xCA, 0x87, 0xCB, 0x87, 0xCC, 0x87, 0xCD, /* 0xC0-0xC3 */ - 0x87, 0xCE, 0x87, 0xCF, 0x87, 0xD0, 0x87, 0xD1, /* 0xC4-0xC7 */ - 0x87, 0xD2, 0x87, 0xD3, 0xC4, 0xD2, 0x87, 0xD4, /* 0xC8-0xCB */ - 0x87, 0xD5, 0x87, 0xD6, 0x87, 0xD7, 0x87, 0xD8, /* 0xCC-0xCF */ - 0x87, 0xD9, 0x87, 0xDA, 0x87, 0xDB, 0x87, 0xDC, /* 0xD0-0xD3 */ - 0xE0, 0xEC, 0x87, 0xDD, 0x87, 0xDE, 0xE0, 0xED, /* 0xD4-0xD7 */ - 0x87, 0xDF, 0x87, 0xE0, 0xC7, 0xF4, 0xCB, 0xC4, /* 0xD8-0xDB */ - 0x87, 0xE1, 0xE0, 0xEE, 0xBB, 0xD8, 0xD8, 0xB6, /* 0xDC-0xDF */ - 0xD2, 0xF2, 0xE0, 0xEF, 0xCD, 0xC5, 0x87, 0xE2, /* 0xE0-0xE3 */ - 0xB6, 0xDA, 0x87, 0xE3, 0x87, 0xE4, 0x87, 0xE5, /* 0xE4-0xE7 */ - 0x87, 0xE6, 0x87, 0xE7, 0x87, 0xE8, 0xE0, 0xF1, /* 0xE8-0xEB */ - 0x87, 0xE9, 0xD4, 0xB0, 0x87, 0xEA, 0x87, 0xEB, /* 0xEC-0xEF */ - 0xC0, 0xA7, 0xB4, 0xD1, 0x87, 0xEC, 0x87, 0xED, /* 0xF0-0xF3 */ - 0xCE, 0xA7, 0xE0, 0xF0, 0x87, 0xEE, 0x87, 0xEF, /* 0xF4-0xF7 */ - 0x87, 0xF0, 0xE0, 0xF2, 0xB9, 0xCC, 0x87, 0xF1, /* 0xF8-0xFB */ - 0x87, 0xF2, 0xB9, 0xFA, 0xCD, 0xBC, 0xE0, 0xF3, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_57[512] = { - 0x87, 0xF3, 0x87, 0xF4, 0x87, 0xF5, 0xC6, 0xD4, /* 0x00-0x03 */ - 0xE0, 0xF4, 0x87, 0xF6, 0xD4, 0xB2, 0x87, 0xF7, /* 0x04-0x07 */ - 0xC8, 0xA6, 0xE0, 0xF6, 0xE0, 0xF5, 0x87, 0xF8, /* 0x08-0x0B */ - 0x87, 0xF9, 0x87, 0xFA, 0x87, 0xFB, 0x87, 0xFC, /* 0x0C-0x0F */ - 0x87, 0xFD, 0x87, 0xFE, 0x88, 0x40, 0x88, 0x41, /* 0x10-0x13 */ - 0x88, 0x42, 0x88, 0x43, 0x88, 0x44, 0x88, 0x45, /* 0x14-0x17 */ - 0x88, 0x46, 0x88, 0x47, 0x88, 0x48, 0x88, 0x49, /* 0x18-0x1B */ - 0xE0, 0xF7, 0x88, 0x4A, 0x88, 0x4B, 0xCD, 0xC1, /* 0x1C-0x1F */ - 0x88, 0x4C, 0x88, 0x4D, 0x88, 0x4E, 0xCA, 0xA5, /* 0x20-0x23 */ - 0x88, 0x4F, 0x88, 0x50, 0x88, 0x51, 0x88, 0x52, /* 0x24-0x27 */ - 0xD4, 0xDA, 0xDB, 0xD7, 0xDB, 0xD9, 0x88, 0x53, /* 0x28-0x2B */ - 0xDB, 0xD8, 0xB9, 0xE7, 0xDB, 0xDC, 0xDB, 0xDD, /* 0x2C-0x2F */ - 0xB5, 0xD8, 0x88, 0x54, 0x88, 0x55, 0xDB, 0xDA, /* 0x30-0x33 */ - 0x88, 0x56, 0x88, 0x57, 0x88, 0x58, 0x88, 0x59, /* 0x34-0x37 */ - 0x88, 0x5A, 0xDB, 0xDB, 0xB3, 0xA1, 0xDB, 0xDF, /* 0x38-0x3B */ - 0x88, 0x5B, 0x88, 0x5C, 0xBB, 0xF8, 0x88, 0x5D, /* 0x3C-0x3F */ - 0xD6, 0xB7, 0x88, 0x5E, 0xDB, 0xE0, 0x88, 0x5F, /* 0x40-0x43 */ - 0x88, 0x60, 0x88, 0x61, 0x88, 0x62, 0xBE, 0xF9, /* 0x44-0x47 */ - 0x88, 0x63, 0x88, 0x64, 0xB7, 0xBB, 0x88, 0x65, /* 0x48-0x4B */ - 0xDB, 0xD0, 0xCC, 0xAE, 0xBF, 0xB2, 0xBB, 0xB5, /* 0x4C-0x4F */ - 0xD7, 0xF8, 0xBF, 0xD3, 0x88, 0x66, 0x88, 0x67, /* 0x50-0x53 */ - 0x88, 0x68, 0x88, 0x69, 0x88, 0x6A, 0xBF, 0xE9, /* 0x54-0x57 */ - 0x88, 0x6B, 0x88, 0x6C, 0xBC, 0xE1, 0xCC, 0xB3, /* 0x58-0x5B */ - 0xDB, 0xDE, 0xB0, 0xD3, 0xCE, 0xEB, 0xB7, 0xD8, /* 0x5C-0x5F */ - 0xD7, 0xB9, 0xC6, 0xC2, 0x88, 0x6D, 0x88, 0x6E, /* 0x60-0x63 */ - 0xC0, 0xA4, 0x88, 0x6F, 0xCC, 0xB9, 0x88, 0x70, /* 0x64-0x67 */ - 0xDB, 0xE7, 0xDB, 0xE1, 0xC6, 0xBA, 0xDB, 0xE3, /* 0x68-0x6B */ - 0x88, 0x71, 0xDB, 0xE8, 0x88, 0x72, 0xC5, 0xF7, /* 0x6C-0x6F */ - 0x88, 0x73, 0x88, 0x74, 0x88, 0x75, 0xDB, 0xEA, /* 0x70-0x73 */ - 0x88, 0x76, 0x88, 0x77, 0xDB, 0xE9, 0xBF, 0xC0, /* 0x74-0x77 */ - 0x88, 0x78, 0x88, 0x79, 0x88, 0x7A, 0xDB, 0xE6, /* 0x78-0x7B */ - 0xDB, 0xE5, 0x88, 0x7B, 0x88, 0x7C, 0x88, 0x7D, /* 0x7C-0x7F */ - - 0x88, 0x7E, 0x88, 0x80, 0xB4, 0xB9, 0xC0, 0xAC, /* 0x80-0x83 */ - 0xC2, 0xA2, 0xDB, 0xE2, 0xDB, 0xE4, 0x88, 0x81, /* 0x84-0x87 */ - 0x88, 0x82, 0x88, 0x83, 0x88, 0x84, 0xD0, 0xCD, /* 0x88-0x8B */ - 0xDB, 0xED, 0x88, 0x85, 0x88, 0x86, 0x88, 0x87, /* 0x8C-0x8F */ - 0x88, 0x88, 0x88, 0x89, 0xC0, 0xDD, 0xDB, 0xF2, /* 0x90-0x93 */ - 0x88, 0x8A, 0x88, 0x8B, 0x88, 0x8C, 0x88, 0x8D, /* 0x94-0x97 */ - 0x88, 0x8E, 0x88, 0x8F, 0x88, 0x90, 0xB6, 0xE2, /* 0x98-0x9B */ - 0x88, 0x91, 0x88, 0x92, 0x88, 0x93, 0x88, 0x94, /* 0x9C-0x9F */ - 0xDB, 0xF3, 0xDB, 0xD2, 0xB9, 0xB8, 0xD4, 0xAB, /* 0xA0-0xA3 */ - 0xDB, 0xEC, 0x88, 0x95, 0xBF, 0xD1, 0xDB, 0xF0, /* 0xA4-0xA7 */ - 0x88, 0x96, 0xDB, 0xD1, 0x88, 0x97, 0xB5, 0xE6, /* 0xA8-0xAB */ - 0x88, 0x98, 0xDB, 0xEB, 0xBF, 0xE5, 0x88, 0x99, /* 0xAC-0xAF */ - 0x88, 0x9A, 0x88, 0x9B, 0xDB, 0xEE, 0x88, 0x9C, /* 0xB0-0xB3 */ - 0xDB, 0xF1, 0x88, 0x9D, 0x88, 0x9E, 0x88, 0x9F, /* 0xB4-0xB7 */ - 0xDB, 0xF9, 0x88, 0xA0, 0x88, 0xA1, 0x88, 0xA2, /* 0xB8-0xBB */ - 0x88, 0xA3, 0x88, 0xA4, 0x88, 0xA5, 0x88, 0xA6, /* 0xBC-0xBF */ - 0x88, 0xA7, 0x88, 0xA8, 0xB9, 0xA1, 0xB0, 0xA3, /* 0xC0-0xC3 */ - 0x88, 0xA9, 0x88, 0xAA, 0x88, 0xAB, 0x88, 0xAC, /* 0xC4-0xC7 */ - 0x88, 0xAD, 0x88, 0xAE, 0x88, 0xAF, 0xC2, 0xF1, /* 0xC8-0xCB */ - 0x88, 0xB0, 0x88, 0xB1, 0xB3, 0xC7, 0xDB, 0xEF, /* 0xCC-0xCF */ - 0x88, 0xB2, 0x88, 0xB3, 0xDB, 0xF8, 0x88, 0xB4, /* 0xD0-0xD3 */ - 0xC6, 0xD2, 0xDB, 0xF4, 0x88, 0xB5, 0x88, 0xB6, /* 0xD4-0xD7 */ - 0xDB, 0xF5, 0xDB, 0xF7, 0xDB, 0xF6, 0x88, 0xB7, /* 0xD8-0xDB */ - 0x88, 0xB8, 0xDB, 0xFE, 0x88, 0xB9, 0xD3, 0xF2, /* 0xDC-0xDF */ - 0xB2, 0xBA, 0x88, 0xBA, 0x88, 0xBB, 0x88, 0xBC, /* 0xE0-0xE3 */ - 0xDB, 0xFD, 0x88, 0xBD, 0x88, 0xBE, 0x88, 0xBF, /* 0xE4-0xE7 */ - 0x88, 0xC0, 0x88, 0xC1, 0x88, 0xC2, 0x88, 0xC3, /* 0xE8-0xEB */ - 0x88, 0xC4, 0xDC, 0xA4, 0x88, 0xC5, 0xDB, 0xFB, /* 0xEC-0xEF */ - 0x88, 0xC6, 0x88, 0xC7, 0x88, 0xC8, 0x88, 0xC9, /* 0xF0-0xF3 */ - 0xDB, 0xFA, 0x88, 0xCA, 0x88, 0xCB, 0x88, 0xCC, /* 0xF4-0xF7 */ - 0xDB, 0xFC, 0xC5, 0xE0, 0xBB, 0xF9, 0x88, 0xCD, /* 0xF8-0xFB */ - 0x88, 0xCE, 0xDC, 0xA3, 0x88, 0xCF, 0x88, 0xD0, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_58[512] = { - 0xDC, 0xA5, 0x88, 0xD1, 0xCC, 0xC3, 0x88, 0xD2, /* 0x00-0x03 */ - 0x88, 0xD3, 0x88, 0xD4, 0xB6, 0xD1, 0xDD, 0xC0, /* 0x04-0x07 */ - 0x88, 0xD5, 0x88, 0xD6, 0x88, 0xD7, 0xDC, 0xA1, /* 0x08-0x0B */ - 0x88, 0xD8, 0xDC, 0xA2, 0x88, 0xD9, 0x88, 0xDA, /* 0x0C-0x0F */ - 0x88, 0xDB, 0xC7, 0xB5, 0x88, 0xDC, 0x88, 0xDD, /* 0x10-0x13 */ - 0x88, 0xDE, 0xB6, 0xE9, 0x88, 0xDF, 0x88, 0xE0, /* 0x14-0x17 */ - 0x88, 0xE1, 0xDC, 0xA7, 0x88, 0xE2, 0x88, 0xE3, /* 0x18-0x1B */ - 0x88, 0xE4, 0x88, 0xE5, 0xDC, 0xA6, 0x88, 0xE6, /* 0x1C-0x1F */ - 0xDC, 0xA9, 0xB1, 0xA4, 0x88, 0xE7, 0x88, 0xE8, /* 0x20-0x23 */ - 0xB5, 0xCC, 0x88, 0xE9, 0x88, 0xEA, 0x88, 0xEB, /* 0x24-0x27 */ - 0x88, 0xEC, 0x88, 0xED, 0xBF, 0xB0, 0x88, 0xEE, /* 0x28-0x2B */ - 0x88, 0xEF, 0x88, 0xF0, 0x88, 0xF1, 0x88, 0xF2, /* 0x2C-0x2F */ - 0xD1, 0xDF, 0x88, 0xF3, 0x88, 0xF4, 0x88, 0xF5, /* 0x30-0x33 */ - 0x88, 0xF6, 0xB6, 0xC2, 0x88, 0xF7, 0x88, 0xF8, /* 0x34-0x37 */ - 0x88, 0xF9, 0x88, 0xFA, 0x88, 0xFB, 0x88, 0xFC, /* 0x38-0x3B */ - 0x88, 0xFD, 0x88, 0xFE, 0x89, 0x40, 0x89, 0x41, /* 0x3C-0x3F */ - 0x89, 0x42, 0x89, 0x43, 0x89, 0x44, 0x89, 0x45, /* 0x40-0x43 */ - 0xDC, 0xA8, 0x89, 0x46, 0x89, 0x47, 0x89, 0x48, /* 0x44-0x47 */ - 0x89, 0x49, 0x89, 0x4A, 0x89, 0x4B, 0x89, 0x4C, /* 0x48-0x4B */ - 0xCB, 0xFA, 0xEB, 0xF3, 0x89, 0x4D, 0x89, 0x4E, /* 0x4C-0x4F */ - 0x89, 0x4F, 0xCB, 0xDC, 0x89, 0x50, 0x89, 0x51, /* 0x50-0x53 */ - 0xCB, 0xFE, 0x89, 0x52, 0x89, 0x53, 0x89, 0x54, /* 0x54-0x57 */ - 0xCC, 0xC1, 0x89, 0x55, 0x89, 0x56, 0x89, 0x57, /* 0x58-0x5B */ - 0x89, 0x58, 0x89, 0x59, 0xC8, 0xFB, 0x89, 0x5A, /* 0x5C-0x5F */ - 0x89, 0x5B, 0x89, 0x5C, 0x89, 0x5D, 0x89, 0x5E, /* 0x60-0x63 */ - 0x89, 0x5F, 0xDC, 0xAA, 0x89, 0x60, 0x89, 0x61, /* 0x64-0x67 */ - 0x89, 0x62, 0x89, 0x63, 0x89, 0x64, 0xCC, 0xEE, /* 0x68-0x6B */ - 0xDC, 0xAB, 0x89, 0x65, 0x89, 0x66, 0x89, 0x67, /* 0x6C-0x6F */ - 0x89, 0x68, 0x89, 0x69, 0x89, 0x6A, 0x89, 0x6B, /* 0x70-0x73 */ - 0x89, 0x6C, 0x89, 0x6D, 0x89, 0x6E, 0x89, 0x6F, /* 0x74-0x77 */ - 0x89, 0x70, 0x89, 0x71, 0x89, 0x72, 0x89, 0x73, /* 0x78-0x7B */ - 0x89, 0x74, 0x89, 0x75, 0xDB, 0xD3, 0x89, 0x76, /* 0x7C-0x7F */ - - 0xDC, 0xAF, 0xDC, 0xAC, 0x89, 0x77, 0xBE, 0xB3, /* 0x80-0x83 */ - 0x89, 0x78, 0xCA, 0xFB, 0x89, 0x79, 0x89, 0x7A, /* 0x84-0x87 */ - 0x89, 0x7B, 0xDC, 0xAD, 0x89, 0x7C, 0x89, 0x7D, /* 0x88-0x8B */ - 0x89, 0x7E, 0x89, 0x80, 0x89, 0x81, 0x89, 0x82, /* 0x8C-0x8F */ - 0x89, 0x83, 0x89, 0x84, 0xC9, 0xCA, 0xC4, 0xB9, /* 0x90-0x93 */ - 0x89, 0x85, 0x89, 0x86, 0x89, 0x87, 0x89, 0x88, /* 0x94-0x97 */ - 0x89, 0x89, 0xC7, 0xBD, 0xDC, 0xAE, 0x89, 0x8A, /* 0x98-0x9B */ - 0x89, 0x8B, 0x89, 0x8C, 0xD4, 0xF6, 0xD0, 0xE6, /* 0x9C-0x9F */ - 0x89, 0x8D, 0x89, 0x8E, 0x89, 0x8F, 0x89, 0x90, /* 0xA0-0xA3 */ - 0x89, 0x91, 0x89, 0x92, 0x89, 0x93, 0x89, 0x94, /* 0xA4-0xA7 */ - 0xC4, 0xAB, 0xB6, 0xD5, 0x89, 0x95, 0x89, 0x96, /* 0xA8-0xAB */ - 0x89, 0x97, 0x89, 0x98, 0x89, 0x99, 0x89, 0x9A, /* 0xAC-0xAF */ - 0x89, 0x9B, 0x89, 0x9C, 0x89, 0x9D, 0x89, 0x9E, /* 0xB0-0xB3 */ - 0x89, 0x9F, 0x89, 0xA0, 0x89, 0xA1, 0x89, 0xA2, /* 0xB4-0xB7 */ - 0x89, 0xA3, 0x89, 0xA4, 0x89, 0xA5, 0x89, 0xA6, /* 0xB8-0xBB */ - 0xDB, 0xD4, 0x89, 0xA7, 0x89, 0xA8, 0x89, 0xA9, /* 0xBC-0xBF */ - 0x89, 0xAA, 0xB1, 0xDA, 0x89, 0xAB, 0x89, 0xAC, /* 0xC0-0xC3 */ - 0x89, 0xAD, 0xDB, 0xD5, 0x89, 0xAE, 0x89, 0xAF, /* 0xC4-0xC7 */ - 0x89, 0xB0, 0x89, 0xB1, 0x89, 0xB2, 0x89, 0xB3, /* 0xC8-0xCB */ - 0x89, 0xB4, 0x89, 0xB5, 0x89, 0xB6, 0x89, 0xB7, /* 0xCC-0xCF */ - 0x89, 0xB8, 0xDB, 0xD6, 0x89, 0xB9, 0x89, 0xBA, /* 0xD0-0xD3 */ - 0x89, 0xBB, 0xBA, 0xBE, 0x89, 0xBC, 0x89, 0xBD, /* 0xD4-0xD7 */ - 0x89, 0xBE, 0x89, 0xBF, 0x89, 0xC0, 0x89, 0xC1, /* 0xD8-0xDB */ - 0x89, 0xC2, 0x89, 0xC3, 0x89, 0xC4, 0x89, 0xC5, /* 0xDC-0xDF */ - 0x89, 0xC6, 0x89, 0xC7, 0x89, 0xC8, 0x89, 0xC9, /* 0xE0-0xE3 */ - 0xC8, 0xC0, 0x89, 0xCA, 0x89, 0xCB, 0x89, 0xCC, /* 0xE4-0xE7 */ - 0x89, 0xCD, 0x89, 0xCE, 0x89, 0xCF, 0xCA, 0xBF, /* 0xE8-0xEB */ - 0xC8, 0xC9, 0x89, 0xD0, 0xD7, 0xB3, 0x89, 0xD1, /* 0xEC-0xEF */ - 0xC9, 0xF9, 0x89, 0xD2, 0x89, 0xD3, 0xBF, 0xC7, /* 0xF0-0xF3 */ - 0x89, 0xD4, 0x89, 0xD5, 0xBA, 0xF8, 0x89, 0xD6, /* 0xF4-0xF7 */ - 0x89, 0xD7, 0xD2, 0xBC, 0x89, 0xD8, 0x89, 0xD9, /* 0xF8-0xFB */ - 0x89, 0xDA, 0x89, 0xDB, 0x89, 0xDC, 0x89, 0xDD, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_59[512] = { - 0x89, 0xDE, 0x89, 0xDF, 0xE2, 0xBA, 0x89, 0xE0, /* 0x00-0x03 */ - 0xB4, 0xA6, 0x89, 0xE1, 0x89, 0xE2, 0xB1, 0xB8, /* 0x04-0x07 */ - 0x89, 0xE3, 0x89, 0xE4, 0x89, 0xE5, 0x89, 0xE6, /* 0x08-0x0B */ - 0x89, 0xE7, 0xB8, 0xB4, 0x89, 0xE8, 0xCF, 0xC4, /* 0x0C-0x0F */ - 0x89, 0xE9, 0x89, 0xEA, 0x89, 0xEB, 0x89, 0xEC, /* 0x10-0x13 */ - 0xD9, 0xE7, 0xCF, 0xA6, 0xCD, 0xE2, 0x89, 0xED, /* 0x14-0x17 */ - 0x89, 0xEE, 0xD9, 0xED, 0xB6, 0xE0, 0x89, 0xEF, /* 0x18-0x1B */ - 0xD2, 0xB9, 0x89, 0xF0, 0x89, 0xF1, 0xB9, 0xBB, /* 0x1C-0x1F */ - 0x89, 0xF2, 0x89, 0xF3, 0x89, 0xF4, 0x89, 0xF5, /* 0x20-0x23 */ - 0xE2, 0xB9, 0xE2, 0xB7, 0x89, 0xF6, 0xB4, 0xF3, /* 0x24-0x27 */ - 0x89, 0xF7, 0xCC, 0xEC, 0xCC, 0xAB, 0xB7, 0xF2, /* 0x28-0x2B */ - 0x89, 0xF8, 0xD8, 0xB2, 0xD1, 0xEB, 0xBA, 0xBB, /* 0x2C-0x2F */ - 0x89, 0xF9, 0xCA, 0xA7, 0x89, 0xFA, 0x89, 0xFB, /* 0x30-0x33 */ - 0xCD, 0xB7, 0x89, 0xFC, 0x89, 0xFD, 0xD2, 0xC4, /* 0x34-0x37 */ - 0xBF, 0xE4, 0xBC, 0xD0, 0xB6, 0xE1, 0x89, 0xFE, /* 0x38-0x3B */ - 0xDE, 0xC5, 0x8A, 0x40, 0x8A, 0x41, 0x8A, 0x42, /* 0x3C-0x3F */ - 0x8A, 0x43, 0xDE, 0xC6, 0xDB, 0xBC, 0x8A, 0x44, /* 0x40-0x43 */ - 0xD1, 0xD9, 0x8A, 0x45, 0x8A, 0x46, 0xC6, 0xE6, /* 0x44-0x47 */ - 0xC4, 0xCE, 0xB7, 0xEE, 0x8A, 0x47, 0xB7, 0xDC, /* 0x48-0x4B */ - 0x8A, 0x48, 0x8A, 0x49, 0xBF, 0xFC, 0xD7, 0xE0, /* 0x4C-0x4F */ - 0x8A, 0x4A, 0xC6, 0xF5, 0x8A, 0x4B, 0x8A, 0x4C, /* 0x50-0x53 */ - 0xB1, 0xBC, 0xDE, 0xC8, 0xBD, 0xB1, 0xCC, 0xD7, /* 0x54-0x57 */ - 0xDE, 0xCA, 0x8A, 0x4D, 0xDE, 0xC9, 0x8A, 0x4E, /* 0x58-0x5B */ - 0x8A, 0x4F, 0x8A, 0x50, 0x8A, 0x51, 0x8A, 0x52, /* 0x5C-0x5F */ - 0xB5, 0xEC, 0x8A, 0x53, 0xC9, 0xDD, 0x8A, 0x54, /* 0x60-0x63 */ - 0x8A, 0x55, 0xB0, 0xC2, 0x8A, 0x56, 0x8A, 0x57, /* 0x64-0x67 */ - 0x8A, 0x58, 0x8A, 0x59, 0x8A, 0x5A, 0x8A, 0x5B, /* 0x68-0x6B */ - 0x8A, 0x5C, 0x8A, 0x5D, 0x8A, 0x5E, 0x8A, 0x5F, /* 0x6C-0x6F */ - 0x8A, 0x60, 0x8A, 0x61, 0x8A, 0x62, 0xC5, 0xAE, /* 0x70-0x73 */ - 0xC5, 0xAB, 0x8A, 0x63, 0xC4, 0xCC, 0x8A, 0x64, /* 0x74-0x77 */ - 0xBC, 0xE9, 0xCB, 0xFD, 0x8A, 0x65, 0x8A, 0x66, /* 0x78-0x7B */ - 0x8A, 0x67, 0xBA, 0xC3, 0x8A, 0x68, 0x8A, 0x69, /* 0x7C-0x7F */ - - 0x8A, 0x6A, 0xE5, 0xF9, 0xC8, 0xE7, 0xE5, 0xFA, /* 0x80-0x83 */ - 0xCD, 0xFD, 0x8A, 0x6B, 0xD7, 0xB1, 0xB8, 0xBE, /* 0x84-0x87 */ - 0xC2, 0xE8, 0x8A, 0x6C, 0xC8, 0xD1, 0x8A, 0x6D, /* 0x88-0x8B */ - 0x8A, 0x6E, 0xE5, 0xFB, 0x8A, 0x6F, 0x8A, 0x70, /* 0x8C-0x8F */ - 0x8A, 0x71, 0x8A, 0x72, 0xB6, 0xCA, 0xBC, 0xCB, /* 0x90-0x93 */ - 0x8A, 0x73, 0x8A, 0x74, 0xD1, 0xFD, 0xE6, 0xA1, /* 0x94-0x97 */ - 0x8A, 0x75, 0xC3, 0xEE, 0x8A, 0x76, 0x8A, 0x77, /* 0x98-0x9B */ - 0x8A, 0x78, 0x8A, 0x79, 0xE6, 0xA4, 0x8A, 0x7A, /* 0x9C-0x9F */ - 0x8A, 0x7B, 0x8A, 0x7C, 0x8A, 0x7D, 0xE5, 0xFE, /* 0xA0-0xA3 */ - 0xE6, 0xA5, 0xCD, 0xD7, 0x8A, 0x7E, 0x8A, 0x80, /* 0xA4-0xA7 */ - 0xB7, 0xC1, 0xE5, 0xFC, 0xE5, 0xFD, 0xE6, 0xA3, /* 0xA8-0xAB */ - 0x8A, 0x81, 0x8A, 0x82, 0xC4, 0xDD, 0xE6, 0xA8, /* 0xAC-0xAF */ - 0x8A, 0x83, 0x8A, 0x84, 0xE6, 0xA7, 0x8A, 0x85, /* 0xB0-0xB3 */ - 0x8A, 0x86, 0x8A, 0x87, 0x8A, 0x88, 0x8A, 0x89, /* 0xB4-0xB7 */ - 0x8A, 0x8A, 0xC3, 0xC3, 0x8A, 0x8B, 0xC6, 0xDE, /* 0xB8-0xBB */ - 0x8A, 0x8C, 0x8A, 0x8D, 0xE6, 0xAA, 0x8A, 0x8E, /* 0xBC-0xBF */ - 0x8A, 0x8F, 0x8A, 0x90, 0x8A, 0x91, 0x8A, 0x92, /* 0xC0-0xC3 */ - 0x8A, 0x93, 0x8A, 0x94, 0xC4, 0xB7, 0x8A, 0x95, /* 0xC4-0xC7 */ - 0x8A, 0x96, 0x8A, 0x97, 0xE6, 0xA2, 0xCA, 0xBC, /* 0xC8-0xCB */ - 0x8A, 0x98, 0x8A, 0x99, 0x8A, 0x9A, 0x8A, 0x9B, /* 0xCC-0xCF */ - 0xBD, 0xE3, 0xB9, 0xC3, 0xE6, 0xA6, 0xD0, 0xD5, /* 0xD0-0xD3 */ - 0xCE, 0xAF, 0x8A, 0x9C, 0x8A, 0x9D, 0xE6, 0xA9, /* 0xD4-0xD7 */ - 0xE6, 0xB0, 0x8A, 0x9E, 0xD2, 0xA6, 0x8A, 0x9F, /* 0xD8-0xDB */ - 0xBD, 0xAA, 0xE6, 0xAD, 0x8A, 0xA0, 0x8A, 0xA1, /* 0xDC-0xDF */ - 0x8A, 0xA2, 0x8A, 0xA3, 0x8A, 0xA4, 0xE6, 0xAF, /* 0xE0-0xE3 */ - 0x8A, 0xA5, 0xC0, 0xD1, 0x8A, 0xA6, 0x8A, 0xA7, /* 0xE4-0xE7 */ - 0xD2, 0xCC, 0x8A, 0xA8, 0x8A, 0xA9, 0x8A, 0xAA, /* 0xE8-0xEB */ - 0xBC, 0xA7, 0x8A, 0xAB, 0x8A, 0xAC, 0x8A, 0xAD, /* 0xEC-0xEF */ - 0x8A, 0xAE, 0x8A, 0xAF, 0x8A, 0xB0, 0x8A, 0xB1, /* 0xF0-0xF3 */ - 0x8A, 0xB2, 0x8A, 0xB3, 0x8A, 0xB4, 0x8A, 0xB5, /* 0xF4-0xF7 */ - 0x8A, 0xB6, 0xE6, 0xB1, 0x8A, 0xB7, 0xD2, 0xF6, /* 0xF8-0xFB */ - 0x8A, 0xB8, 0x8A, 0xB9, 0x8A, 0xBA, 0xD7, 0xCB, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5A[512] = { - 0x8A, 0xBB, 0xCD, 0xFE, 0x8A, 0xBC, 0xCD, 0xDE, /* 0x00-0x03 */ - 0xC2, 0xA6, 0xE6, 0xAB, 0xE6, 0xAC, 0xBD, 0xBF, /* 0x04-0x07 */ - 0xE6, 0xAE, 0xE6, 0xB3, 0x8A, 0xBD, 0x8A, 0xBE, /* 0x08-0x0B */ - 0xE6, 0xB2, 0x8A, 0xBF, 0x8A, 0xC0, 0x8A, 0xC1, /* 0x0C-0x0F */ - 0x8A, 0xC2, 0xE6, 0xB6, 0x8A, 0xC3, 0xE6, 0xB8, /* 0x10-0x13 */ - 0x8A, 0xC4, 0x8A, 0xC5, 0x8A, 0xC6, 0x8A, 0xC7, /* 0x14-0x17 */ - 0xC4, 0xEF, 0x8A, 0xC8, 0x8A, 0xC9, 0x8A, 0xCA, /* 0x18-0x1B */ - 0xC4, 0xC8, 0x8A, 0xCB, 0x8A, 0xCC, 0xBE, 0xEA, /* 0x1C-0x1F */ - 0xC9, 0xEF, 0x8A, 0xCD, 0x8A, 0xCE, 0xE6, 0xB7, /* 0x20-0x23 */ - 0x8A, 0xCF, 0xB6, 0xF0, 0x8A, 0xD0, 0x8A, 0xD1, /* 0x24-0x27 */ - 0x8A, 0xD2, 0xC3, 0xE4, 0x8A, 0xD3, 0x8A, 0xD4, /* 0x28-0x2B */ - 0x8A, 0xD5, 0x8A, 0xD6, 0x8A, 0xD7, 0x8A, 0xD8, /* 0x2C-0x2F */ - 0x8A, 0xD9, 0xD3, 0xE9, 0xE6, 0xB4, 0x8A, 0xDA, /* 0x30-0x33 */ - 0xE6, 0xB5, 0x8A, 0xDB, 0xC8, 0xA2, 0x8A, 0xDC, /* 0x34-0x37 */ - 0x8A, 0xDD, 0x8A, 0xDE, 0x8A, 0xDF, 0x8A, 0xE0, /* 0x38-0x3B */ - 0xE6, 0xBD, 0x8A, 0xE1, 0x8A, 0xE2, 0x8A, 0xE3, /* 0x3C-0x3F */ - 0xE6, 0xB9, 0x8A, 0xE4, 0x8A, 0xE5, 0x8A, 0xE6, /* 0x40-0x43 */ - 0x8A, 0xE7, 0x8A, 0xE8, 0xC6, 0xC5, 0x8A, 0xE9, /* 0x44-0x47 */ - 0x8A, 0xEA, 0xCD, 0xF1, 0xE6, 0xBB, 0x8A, 0xEB, /* 0x48-0x4B */ - 0x8A, 0xEC, 0x8A, 0xED, 0x8A, 0xEE, 0x8A, 0xEF, /* 0x4C-0x4F */ - 0x8A, 0xF0, 0x8A, 0xF1, 0x8A, 0xF2, 0x8A, 0xF3, /* 0x50-0x53 */ - 0x8A, 0xF4, 0xE6, 0xBC, 0x8A, 0xF5, 0x8A, 0xF6, /* 0x54-0x57 */ - 0x8A, 0xF7, 0x8A, 0xF8, 0xBB, 0xE9, 0x8A, 0xF9, /* 0x58-0x5B */ - 0x8A, 0xFA, 0x8A, 0xFB, 0x8A, 0xFC, 0x8A, 0xFD, /* 0x5C-0x5F */ - 0x8A, 0xFE, 0x8B, 0x40, 0xE6, 0xBE, 0x8B, 0x41, /* 0x60-0x63 */ - 0x8B, 0x42, 0x8B, 0x43, 0x8B, 0x44, 0xE6, 0xBA, /* 0x64-0x67 */ - 0x8B, 0x45, 0x8B, 0x46, 0xC0, 0xB7, 0x8B, 0x47, /* 0x68-0x6B */ - 0x8B, 0x48, 0x8B, 0x49, 0x8B, 0x4A, 0x8B, 0x4B, /* 0x6C-0x6F */ - 0x8B, 0x4C, 0x8B, 0x4D, 0x8B, 0x4E, 0x8B, 0x4F, /* 0x70-0x73 */ - 0xD3, 0xA4, 0xE6, 0xBF, 0xC9, 0xF4, 0xE6, 0xC3, /* 0x74-0x77 */ - 0x8B, 0x50, 0x8B, 0x51, 0xE6, 0xC4, 0x8B, 0x52, /* 0x78-0x7B */ - 0x8B, 0x53, 0x8B, 0x54, 0x8B, 0x55, 0xD0, 0xF6, /* 0x7C-0x7F */ - - 0x8B, 0x56, 0x8B, 0x57, 0x8B, 0x58, 0x8B, 0x59, /* 0x80-0x83 */ - 0x8B, 0x5A, 0x8B, 0x5B, 0x8B, 0x5C, 0x8B, 0x5D, /* 0x84-0x87 */ - 0x8B, 0x5E, 0x8B, 0x5F, 0x8B, 0x60, 0x8B, 0x61, /* 0x88-0x8B */ - 0x8B, 0x62, 0x8B, 0x63, 0x8B, 0x64, 0x8B, 0x65, /* 0x8C-0x8F */ - 0x8B, 0x66, 0x8B, 0x67, 0xC3, 0xBD, 0x8B, 0x68, /* 0x90-0x93 */ - 0x8B, 0x69, 0x8B, 0x6A, 0x8B, 0x6B, 0x8B, 0x6C, /* 0x94-0x97 */ - 0x8B, 0x6D, 0x8B, 0x6E, 0xC3, 0xC4, 0xE6, 0xC2, /* 0x98-0x9B */ - 0x8B, 0x6F, 0x8B, 0x70, 0x8B, 0x71, 0x8B, 0x72, /* 0x9C-0x9F */ - 0x8B, 0x73, 0x8B, 0x74, 0x8B, 0x75, 0x8B, 0x76, /* 0xA0-0xA3 */ - 0x8B, 0x77, 0x8B, 0x78, 0x8B, 0x79, 0x8B, 0x7A, /* 0xA4-0xA7 */ - 0x8B, 0x7B, 0x8B, 0x7C, 0xE6, 0xC1, 0x8B, 0x7D, /* 0xA8-0xAB */ - 0x8B, 0x7E, 0x8B, 0x80, 0x8B, 0x81, 0x8B, 0x82, /* 0xAC-0xAF */ - 0x8B, 0x83, 0x8B, 0x84, 0xE6, 0xC7, 0xCF, 0xB1, /* 0xB0-0xB3 */ - 0x8B, 0x85, 0xEB, 0xF4, 0x8B, 0x86, 0x8B, 0x87, /* 0xB4-0xB7 */ - 0xE6, 0xCA, 0x8B, 0x88, 0x8B, 0x89, 0x8B, 0x8A, /* 0xB8-0xBB */ - 0x8B, 0x8B, 0x8B, 0x8C, 0xE6, 0xC5, 0x8B, 0x8D, /* 0xBC-0xBF */ - 0x8B, 0x8E, 0xBC, 0xDE, 0xC9, 0xA9, 0x8B, 0x8F, /* 0xC0-0xC3 */ - 0x8B, 0x90, 0x8B, 0x91, 0x8B, 0x92, 0x8B, 0x93, /* 0xC4-0xC7 */ - 0x8B, 0x94, 0xBC, 0xB5, 0x8B, 0x95, 0x8B, 0x96, /* 0xC8-0xCB */ - 0xCF, 0xD3, 0x8B, 0x97, 0x8B, 0x98, 0x8B, 0x99, /* 0xCC-0xCF */ - 0x8B, 0x9A, 0x8B, 0x9B, 0xE6, 0xC8, 0x8B, 0x9C, /* 0xD0-0xD3 */ - 0xE6, 0xC9, 0x8B, 0x9D, 0xE6, 0xCE, 0x8B, 0x9E, /* 0xD4-0xD7 */ - 0xE6, 0xD0, 0x8B, 0x9F, 0x8B, 0xA0, 0x8B, 0xA1, /* 0xD8-0xDB */ - 0xE6, 0xD1, 0x8B, 0xA2, 0x8B, 0xA3, 0x8B, 0xA4, /* 0xDC-0xDF */ - 0xE6, 0xCB, 0xB5, 0xD5, 0x8B, 0xA5, 0xE6, 0xCC, /* 0xE0-0xE3 */ - 0x8B, 0xA6, 0x8B, 0xA7, 0xE6, 0xCF, 0x8B, 0xA8, /* 0xE4-0xE7 */ - 0x8B, 0xA9, 0xC4, 0xDB, 0x8B, 0xAA, 0xE6, 0xC6, /* 0xE8-0xEB */ - 0x8B, 0xAB, 0x8B, 0xAC, 0x8B, 0xAD, 0x8B, 0xAE, /* 0xEC-0xEF */ - 0x8B, 0xAF, 0xE6, 0xCD, 0x8B, 0xB0, 0x8B, 0xB1, /* 0xF0-0xF3 */ - 0x8B, 0xB2, 0x8B, 0xB3, 0x8B, 0xB4, 0x8B, 0xB5, /* 0xF4-0xF7 */ - 0x8B, 0xB6, 0x8B, 0xB7, 0x8B, 0xB8, 0x8B, 0xB9, /* 0xF8-0xFB */ - 0x8B, 0xBA, 0x8B, 0xBB, 0x8B, 0xBC, 0x8B, 0xBD, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5B[512] = { - 0x8B, 0xBE, 0x8B, 0xBF, 0x8B, 0xC0, 0x8B, 0xC1, /* 0x00-0x03 */ - 0x8B, 0xC2, 0x8B, 0xC3, 0x8B, 0xC4, 0x8B, 0xC5, /* 0x04-0x07 */ - 0x8B, 0xC6, 0xE6, 0xD2, 0x8B, 0xC7, 0x8B, 0xC8, /* 0x08-0x0B */ - 0x8B, 0xC9, 0x8B, 0xCA, 0x8B, 0xCB, 0x8B, 0xCC, /* 0x0C-0x0F */ - 0x8B, 0xCD, 0x8B, 0xCE, 0x8B, 0xCF, 0x8B, 0xD0, /* 0x10-0x13 */ - 0x8B, 0xD1, 0x8B, 0xD2, 0xE6, 0xD4, 0xE6, 0xD3, /* 0x14-0x17 */ - 0x8B, 0xD3, 0x8B, 0xD4, 0x8B, 0xD5, 0x8B, 0xD6, /* 0x18-0x1B */ - 0x8B, 0xD7, 0x8B, 0xD8, 0x8B, 0xD9, 0x8B, 0xDA, /* 0x1C-0x1F */ - 0x8B, 0xDB, 0x8B, 0xDC, 0x8B, 0xDD, 0x8B, 0xDE, /* 0x20-0x23 */ - 0x8B, 0xDF, 0x8B, 0xE0, 0x8B, 0xE1, 0x8B, 0xE2, /* 0x24-0x27 */ - 0x8B, 0xE3, 0x8B, 0xE4, 0x8B, 0xE5, 0x8B, 0xE6, /* 0x28-0x2B */ - 0x8B, 0xE7, 0x8B, 0xE8, 0x8B, 0xE9, 0x8B, 0xEA, /* 0x2C-0x2F */ - 0x8B, 0xEB, 0x8B, 0xEC, 0xE6, 0xD5, 0x8B, 0xED, /* 0x30-0x33 */ - 0xD9, 0xF8, 0x8B, 0xEE, 0x8B, 0xEF, 0xE6, 0xD6, /* 0x34-0x37 */ - 0x8B, 0xF0, 0x8B, 0xF1, 0x8B, 0xF2, 0x8B, 0xF3, /* 0x38-0x3B */ - 0x8B, 0xF4, 0x8B, 0xF5, 0x8B, 0xF6, 0x8B, 0xF7, /* 0x3C-0x3F */ - 0xE6, 0xD7, 0x8B, 0xF8, 0x8B, 0xF9, 0x8B, 0xFA, /* 0x40-0x43 */ - 0x8B, 0xFB, 0x8B, 0xFC, 0x8B, 0xFD, 0x8B, 0xFE, /* 0x44-0x47 */ - 0x8C, 0x40, 0x8C, 0x41, 0x8C, 0x42, 0x8C, 0x43, /* 0x48-0x4B */ - 0x8C, 0x44, 0x8C, 0x45, 0x8C, 0x46, 0x8C, 0x47, /* 0x4C-0x4F */ - 0xD7, 0xD3, 0xE6, 0xDD, 0x8C, 0x48, 0xE6, 0xDE, /* 0x50-0x53 */ - 0xBF, 0xD7, 0xD4, 0xD0, 0x8C, 0x49, 0xD7, 0xD6, /* 0x54-0x57 */ - 0xB4, 0xE6, 0xCB, 0xEF, 0xE6, 0xDA, 0xD8, 0xC3, /* 0x58-0x5B */ - 0xD7, 0xCE, 0xD0, 0xA2, 0x8C, 0x4A, 0xC3, 0xCF, /* 0x5C-0x5F */ - 0x8C, 0x4B, 0x8C, 0x4C, 0xE6, 0xDF, 0xBC, 0xBE, /* 0x60-0x63 */ - 0xB9, 0xC2, 0xE6, 0xDB, 0xD1, 0xA7, 0x8C, 0x4D, /* 0x64-0x67 */ - 0x8C, 0x4E, 0xBA, 0xA2, 0xC2, 0xCF, 0x8C, 0x4F, /* 0x68-0x6B */ - 0xD8, 0xAB, 0x8C, 0x50, 0x8C, 0x51, 0x8C, 0x52, /* 0x6C-0x6F */ - 0xCA, 0xEB, 0xE5, 0xEE, 0x8C, 0x53, 0xE6, 0xDC, /* 0x70-0x73 */ - 0x8C, 0x54, 0xB7, 0xF5, 0x8C, 0x55, 0x8C, 0x56, /* 0x74-0x77 */ - 0x8C, 0x57, 0x8C, 0x58, 0xC8, 0xE6, 0x8C, 0x59, /* 0x78-0x7B */ - 0x8C, 0x5A, 0xC4, 0xF5, 0x8C, 0x5B, 0x8C, 0x5C, /* 0x7C-0x7F */ - - 0xE5, 0xB2, 0xC4, 0xFE, 0x8C, 0x5D, 0xCB, 0xFC, /* 0x80-0x83 */ - 0xE5, 0xB3, 0xD5, 0xAC, 0x8C, 0x5E, 0xD3, 0xEE, /* 0x84-0x87 */ - 0xCA, 0xD8, 0xB0, 0xB2, 0x8C, 0x5F, 0xCB, 0xCE, /* 0x88-0x8B */ - 0xCD, 0xEA, 0x8C, 0x60, 0x8C, 0x61, 0xBA, 0xEA, /* 0x8C-0x8F */ - 0x8C, 0x62, 0x8C, 0x63, 0x8C, 0x64, 0xE5, 0xB5, /* 0x90-0x93 */ - 0x8C, 0x65, 0xE5, 0xB4, 0x8C, 0x66, 0xD7, 0xDA, /* 0x94-0x97 */ - 0xB9, 0xD9, 0xD6, 0xE6, 0xB6, 0xA8, 0xCD, 0xF0, /* 0x98-0x9B */ - 0xD2, 0xCB, 0xB1, 0xA6, 0xCA, 0xB5, 0x8C, 0x67, /* 0x9C-0x9F */ - 0xB3, 0xE8, 0xC9, 0xF3, 0xBF, 0xCD, 0xD0, 0xFB, /* 0xA0-0xA3 */ - 0xCA, 0xD2, 0xE5, 0xB6, 0xBB, 0xC2, 0x8C, 0x68, /* 0xA4-0xA7 */ - 0x8C, 0x69, 0x8C, 0x6A, 0xCF, 0xDC, 0xB9, 0xAC, /* 0xA8-0xAB */ - 0x8C, 0x6B, 0x8C, 0x6C, 0x8C, 0x6D, 0x8C, 0x6E, /* 0xAC-0xAF */ - 0xD4, 0xD7, 0x8C, 0x6F, 0x8C, 0x70, 0xBA, 0xA6, /* 0xB0-0xB3 */ - 0xD1, 0xE7, 0xCF, 0xFC, 0xBC, 0xD2, 0x8C, 0x71, /* 0xB4-0xB7 */ - 0xE5, 0xB7, 0xC8, 0xDD, 0x8C, 0x72, 0x8C, 0x73, /* 0xB8-0xBB */ - 0x8C, 0x74, 0xBF, 0xED, 0xB1, 0xF6, 0xCB, 0xDE, /* 0xBC-0xBF */ - 0x8C, 0x75, 0x8C, 0x76, 0xBC, 0xC5, 0x8C, 0x77, /* 0xC0-0xC3 */ - 0xBC, 0xC4, 0xD2, 0xFA, 0xC3, 0xDC, 0xBF, 0xDC, /* 0xC4-0xC7 */ - 0x8C, 0x78, 0x8C, 0x79, 0x8C, 0x7A, 0x8C, 0x7B, /* 0xC8-0xCB */ - 0xB8, 0xBB, 0x8C, 0x7C, 0x8C, 0x7D, 0x8C, 0x7E, /* 0xCC-0xCF */ - 0xC3, 0xC2, 0x8C, 0x80, 0xBA, 0xAE, 0xD4, 0xA2, /* 0xD0-0xD3 */ - 0x8C, 0x81, 0x8C, 0x82, 0x8C, 0x83, 0x8C, 0x84, /* 0xD4-0xD7 */ - 0x8C, 0x85, 0x8C, 0x86, 0x8C, 0x87, 0x8C, 0x88, /* 0xD8-0xDB */ - 0x8C, 0x89, 0xC7, 0xDE, 0xC4, 0xAF, 0xB2, 0xEC, /* 0xDC-0xDF */ - 0x8C, 0x8A, 0xB9, 0xD1, 0x8C, 0x8B, 0x8C, 0x8C, /* 0xE0-0xE3 */ - 0xE5, 0xBB, 0xC1, 0xC8, 0x8C, 0x8D, 0x8C, 0x8E, /* 0xE4-0xE7 */ - 0xD5, 0xAF, 0x8C, 0x8F, 0x8C, 0x90, 0x8C, 0x91, /* 0xE8-0xEB */ - 0x8C, 0x92, 0x8C, 0x93, 0xE5, 0xBC, 0x8C, 0x94, /* 0xEC-0xEF */ - 0xE5, 0xBE, 0x8C, 0x95, 0x8C, 0x96, 0x8C, 0x97, /* 0xF0-0xF3 */ - 0x8C, 0x98, 0x8C, 0x99, 0x8C, 0x9A, 0x8C, 0x9B, /* 0xF4-0xF7 */ - 0xB4, 0xE7, 0xB6, 0xD4, 0xCB, 0xC2, 0xD1, 0xB0, /* 0xF8-0xFB */ - 0xB5, 0xBC, 0x8C, 0x9C, 0x8C, 0x9D, 0xCA, 0xD9, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5C[512] = { - 0x8C, 0x9E, 0xB7, 0xE2, 0x8C, 0x9F, 0x8C, 0xA0, /* 0x00-0x03 */ - 0xC9, 0xE4, 0x8C, 0xA1, 0xBD, 0xAB, 0x8C, 0xA2, /* 0x04-0x07 */ - 0x8C, 0xA3, 0xCE, 0xBE, 0xD7, 0xF0, 0x8C, 0xA4, /* 0x08-0x0B */ - 0x8C, 0xA5, 0x8C, 0xA6, 0x8C, 0xA7, 0xD0, 0xA1, /* 0x0C-0x0F */ - 0x8C, 0xA8, 0xC9, 0xD9, 0x8C, 0xA9, 0x8C, 0xAA, /* 0x10-0x13 */ - 0xB6, 0xFB, 0xE6, 0xD8, 0xBC, 0xE2, 0x8C, 0xAB, /* 0x14-0x17 */ - 0xB3, 0xBE, 0x8C, 0xAC, 0xC9, 0xD0, 0x8C, 0xAD, /* 0x18-0x1B */ - 0xE6, 0xD9, 0xB3, 0xA2, 0x8C, 0xAE, 0x8C, 0xAF, /* 0x1C-0x1F */ - 0x8C, 0xB0, 0x8C, 0xB1, 0xDE, 0xCC, 0x8C, 0xB2, /* 0x20-0x23 */ - 0xD3, 0xC8, 0xDE, 0xCD, 0x8C, 0xB3, 0xD2, 0xA2, /* 0x24-0x27 */ - 0x8C, 0xB4, 0x8C, 0xB5, 0x8C, 0xB6, 0x8C, 0xB7, /* 0x28-0x2B */ - 0xDE, 0xCE, 0x8C, 0xB8, 0x8C, 0xB9, 0x8C, 0xBA, /* 0x2C-0x2F */ - 0x8C, 0xBB, 0xBE, 0xCD, 0x8C, 0xBC, 0x8C, 0xBD, /* 0x30-0x33 */ - 0xDE, 0xCF, 0x8C, 0xBE, 0x8C, 0xBF, 0x8C, 0xC0, /* 0x34-0x37 */ - 0xCA, 0xAC, 0xD2, 0xFC, 0xB3, 0xDF, 0xE5, 0xEA, /* 0x38-0x3B */ - 0xC4, 0xE1, 0xBE, 0xA1, 0xCE, 0xB2, 0xC4, 0xF2, /* 0x3C-0x3F */ - 0xBE, 0xD6, 0xC6, 0xA8, 0xB2, 0xE3, 0x8C, 0xC1, /* 0x40-0x43 */ - 0x8C, 0xC2, 0xBE, 0xD3, 0x8C, 0xC3, 0x8C, 0xC4, /* 0x44-0x47 */ - 0xC7, 0xFC, 0xCC, 0xEB, 0xBD, 0xEC, 0xCE, 0xDD, /* 0x48-0x4B */ - 0x8C, 0xC5, 0x8C, 0xC6, 0xCA, 0xBA, 0xC6, 0xC1, /* 0x4C-0x4F */ - 0xE5, 0xEC, 0xD0, 0xBC, 0x8C, 0xC7, 0x8C, 0xC8, /* 0x50-0x53 */ - 0x8C, 0xC9, 0xD5, 0xB9, 0x8C, 0xCA, 0x8C, 0xCB, /* 0x54-0x57 */ - 0x8C, 0xCC, 0xE5, 0xED, 0x8C, 0xCD, 0x8C, 0xCE, /* 0x58-0x5B */ - 0x8C, 0xCF, 0x8C, 0xD0, 0xCA, 0xF4, 0x8C, 0xD1, /* 0x5C-0x5F */ - 0xCD, 0xC0, 0xC2, 0xC5, 0x8C, 0xD2, 0xE5, 0xEF, /* 0x60-0x63 */ - 0x8C, 0xD3, 0xC2, 0xC4, 0xE5, 0xF0, 0x8C, 0xD4, /* 0x64-0x67 */ - 0x8C, 0xD5, 0x8C, 0xD6, 0x8C, 0xD7, 0x8C, 0xD8, /* 0x68-0x6B */ - 0x8C, 0xD9, 0x8C, 0xDA, 0xE5, 0xF8, 0xCD, 0xCD, /* 0x6C-0x6F */ - 0x8C, 0xDB, 0xC9, 0xBD, 0x8C, 0xDC, 0x8C, 0xDD, /* 0x70-0x73 */ - 0x8C, 0xDE, 0x8C, 0xDF, 0x8C, 0xE0, 0x8C, 0xE1, /* 0x74-0x77 */ - 0x8C, 0xE2, 0xD2, 0xD9, 0xE1, 0xA8, 0x8C, 0xE3, /* 0x78-0x7B */ - 0x8C, 0xE4, 0x8C, 0xE5, 0x8C, 0xE6, 0xD3, 0xEC, /* 0x7C-0x7F */ - - 0x8C, 0xE7, 0xCB, 0xEA, 0xC6, 0xF1, 0x8C, 0xE8, /* 0x80-0x83 */ - 0x8C, 0xE9, 0x8C, 0xEA, 0x8C, 0xEB, 0x8C, 0xEC, /* 0x84-0x87 */ - 0xE1, 0xAC, 0x8C, 0xED, 0x8C, 0xEE, 0x8C, 0xEF, /* 0x88-0x8B */ - 0xE1, 0xA7, 0xE1, 0xA9, 0x8C, 0xF0, 0x8C, 0xF1, /* 0x8C-0x8F */ - 0xE1, 0xAA, 0xE1, 0xAF, 0x8C, 0xF2, 0x8C, 0xF3, /* 0x90-0x93 */ - 0xB2, 0xED, 0x8C, 0xF4, 0xE1, 0xAB, 0xB8, 0xDA, /* 0x94-0x97 */ - 0xE1, 0xAD, 0xE1, 0xAE, 0xE1, 0xB0, 0xB5, 0xBA, /* 0x98-0x9B */ - 0xE1, 0xB1, 0x8C, 0xF5, 0x8C, 0xF6, 0x8C, 0xF7, /* 0x9C-0x9F */ - 0x8C, 0xF8, 0x8C, 0xF9, 0xE1, 0xB3, 0xE1, 0xB8, /* 0xA0-0xA3 */ - 0x8C, 0xFA, 0x8C, 0xFB, 0x8C, 0xFC, 0x8C, 0xFD, /* 0xA4-0xA7 */ - 0x8C, 0xFE, 0xD1, 0xD2, 0x8D, 0x40, 0xE1, 0xB6, /* 0xA8-0xAB */ - 0xE1, 0xB5, 0xC1, 0xEB, 0x8D, 0x41, 0x8D, 0x42, /* 0xAC-0xAF */ - 0x8D, 0x43, 0xE1, 0xB7, 0x8D, 0x44, 0xD4, 0xC0, /* 0xB0-0xB3 */ - 0x8D, 0x45, 0xE1, 0xB2, 0x8D, 0x46, 0xE1, 0xBA, /* 0xB4-0xB7 */ - 0xB0, 0xB6, 0x8D, 0x47, 0x8D, 0x48, 0x8D, 0x49, /* 0xB8-0xBB */ - 0x8D, 0x4A, 0xE1, 0xB4, 0x8D, 0x4B, 0xBF, 0xF9, /* 0xBC-0xBF */ - 0x8D, 0x4C, 0xE1, 0xB9, 0x8D, 0x4D, 0x8D, 0x4E, /* 0xC0-0xC3 */ - 0xE1, 0xBB, 0x8D, 0x4F, 0x8D, 0x50, 0x8D, 0x51, /* 0xC4-0xC7 */ - 0x8D, 0x52, 0x8D, 0x53, 0x8D, 0x54, 0xE1, 0xBE, /* 0xC8-0xCB */ - 0x8D, 0x55, 0x8D, 0x56, 0x8D, 0x57, 0x8D, 0x58, /* 0xCC-0xCF */ - 0x8D, 0x59, 0x8D, 0x5A, 0xE1, 0xBC, 0x8D, 0x5B, /* 0xD0-0xD3 */ - 0x8D, 0x5C, 0x8D, 0x5D, 0x8D, 0x5E, 0x8D, 0x5F, /* 0xD4-0xD7 */ - 0x8D, 0x60, 0xD6, 0xC5, 0x8D, 0x61, 0x8D, 0x62, /* 0xD8-0xDB */ - 0x8D, 0x63, 0x8D, 0x64, 0x8D, 0x65, 0x8D, 0x66, /* 0xDC-0xDF */ - 0x8D, 0x67, 0xCF, 0xBF, 0x8D, 0x68, 0x8D, 0x69, /* 0xE0-0xE3 */ - 0xE1, 0xBD, 0xE1, 0xBF, 0xC2, 0xCD, 0x8D, 0x6A, /* 0xE4-0xE7 */ - 0xB6, 0xEB, 0x8D, 0x6B, 0xD3, 0xF8, 0x8D, 0x6C, /* 0xE8-0xEB */ - 0x8D, 0x6D, 0xC7, 0xCD, 0x8D, 0x6E, 0x8D, 0x6F, /* 0xEC-0xEF */ - 0xB7, 0xE5, 0x8D, 0x70, 0x8D, 0x71, 0x8D, 0x72, /* 0xF0-0xF3 */ - 0x8D, 0x73, 0x8D, 0x74, 0x8D, 0x75, 0x8D, 0x76, /* 0xF4-0xF7 */ - 0x8D, 0x77, 0x8D, 0x78, 0x8D, 0x79, 0xBE, 0xFE, /* 0xF8-0xFB */ - 0x8D, 0x7A, 0x8D, 0x7B, 0x8D, 0x7C, 0x8D, 0x7D, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5D[512] = { - 0x8D, 0x7E, 0x8D, 0x80, 0xE1, 0xC0, 0xE1, 0xC1, /* 0x00-0x03 */ - 0x8D, 0x81, 0x8D, 0x82, 0xE1, 0xC7, 0xB3, 0xE7, /* 0x04-0x07 */ - 0x8D, 0x83, 0x8D, 0x84, 0x8D, 0x85, 0x8D, 0x86, /* 0x08-0x0B */ - 0x8D, 0x87, 0x8D, 0x88, 0xC6, 0xE9, 0x8D, 0x89, /* 0x0C-0x0F */ - 0x8D, 0x8A, 0x8D, 0x8B, 0x8D, 0x8C, 0x8D, 0x8D, /* 0x10-0x13 */ - 0xB4, 0xDE, 0x8D, 0x8E, 0xD1, 0xC2, 0x8D, 0x8F, /* 0x14-0x17 */ - 0x8D, 0x90, 0x8D, 0x91, 0x8D, 0x92, 0xE1, 0xC8, /* 0x18-0x1B */ - 0x8D, 0x93, 0x8D, 0x94, 0xE1, 0xC6, 0x8D, 0x95, /* 0x1C-0x1F */ - 0x8D, 0x96, 0x8D, 0x97, 0x8D, 0x98, 0x8D, 0x99, /* 0x20-0x23 */ - 0xE1, 0xC5, 0x8D, 0x9A, 0xE1, 0xC3, 0xE1, 0xC2, /* 0x24-0x27 */ - 0x8D, 0x9B, 0xB1, 0xC0, 0x8D, 0x9C, 0x8D, 0x9D, /* 0x28-0x2B */ - 0x8D, 0x9E, 0xD5, 0xB8, 0xE1, 0xC4, 0x8D, 0x9F, /* 0x2C-0x2F */ - 0x8D, 0xA0, 0x8D, 0xA1, 0x8D, 0xA2, 0x8D, 0xA3, /* 0x30-0x33 */ - 0xE1, 0xCB, 0x8D, 0xA4, 0x8D, 0xA5, 0x8D, 0xA6, /* 0x34-0x37 */ - 0x8D, 0xA7, 0x8D, 0xA8, 0x8D, 0xA9, 0x8D, 0xAA, /* 0x38-0x3B */ - 0x8D, 0xAB, 0xE1, 0xCC, 0xE1, 0xCA, 0x8D, 0xAC, /* 0x3C-0x3F */ - 0x8D, 0xAD, 0x8D, 0xAE, 0x8D, 0xAF, 0x8D, 0xB0, /* 0x40-0x43 */ - 0x8D, 0xB1, 0x8D, 0xB2, 0x8D, 0xB3, 0xEF, 0xFA, /* 0x44-0x47 */ - 0x8D, 0xB4, 0x8D, 0xB5, 0xE1, 0xD3, 0xE1, 0xD2, /* 0x48-0x4B */ - 0xC7, 0xB6, 0x8D, 0xB6, 0x8D, 0xB7, 0x8D, 0xB8, /* 0x4C-0x4F */ - 0x8D, 0xB9, 0x8D, 0xBA, 0x8D, 0xBB, 0x8D, 0xBC, /* 0x50-0x53 */ - 0x8D, 0xBD, 0x8D, 0xBE, 0x8D, 0xBF, 0x8D, 0xC0, /* 0x54-0x57 */ - 0xE1, 0xC9, 0x8D, 0xC1, 0x8D, 0xC2, 0xE1, 0xCE, /* 0x58-0x5B */ - 0x8D, 0xC3, 0xE1, 0xD0, 0x8D, 0xC4, 0x8D, 0xC5, /* 0x5C-0x5F */ - 0x8D, 0xC6, 0x8D, 0xC7, 0x8D, 0xC8, 0x8D, 0xC9, /* 0x60-0x63 */ - 0x8D, 0xCA, 0x8D, 0xCB, 0x8D, 0xCC, 0x8D, 0xCD, /* 0x64-0x67 */ - 0x8D, 0xCE, 0xE1, 0xD4, 0x8D, 0xCF, 0xE1, 0xD1, /* 0x68-0x6B */ - 0xE1, 0xCD, 0x8D, 0xD0, 0x8D, 0xD1, 0xE1, 0xCF, /* 0x6C-0x6F */ - 0x8D, 0xD2, 0x8D, 0xD3, 0x8D, 0xD4, 0x8D, 0xD5, /* 0x70-0x73 */ - 0xE1, 0xD5, 0x8D, 0xD6, 0x8D, 0xD7, 0x8D, 0xD8, /* 0x74-0x77 */ - 0x8D, 0xD9, 0x8D, 0xDA, 0x8D, 0xDB, 0x8D, 0xDC, /* 0x78-0x7B */ - 0x8D, 0xDD, 0x8D, 0xDE, 0x8D, 0xDF, 0x8D, 0xE0, /* 0x7C-0x7F */ - - 0x8D, 0xE1, 0x8D, 0xE2, 0xE1, 0xD6, 0x8D, 0xE3, /* 0x80-0x83 */ - 0x8D, 0xE4, 0x8D, 0xE5, 0x8D, 0xE6, 0x8D, 0xE7, /* 0x84-0x87 */ - 0x8D, 0xE8, 0x8D, 0xE9, 0x8D, 0xEA, 0x8D, 0xEB, /* 0x88-0x8B */ - 0x8D, 0xEC, 0x8D, 0xED, 0x8D, 0xEE, 0x8D, 0xEF, /* 0x8C-0x8F */ - 0x8D, 0xF0, 0x8D, 0xF1, 0x8D, 0xF2, 0x8D, 0xF3, /* 0x90-0x93 */ - 0x8D, 0xF4, 0x8D, 0xF5, 0x8D, 0xF6, 0x8D, 0xF7, /* 0x94-0x97 */ - 0x8D, 0xF8, 0xE1, 0xD7, 0x8D, 0xF9, 0x8D, 0xFA, /* 0x98-0x9B */ - 0x8D, 0xFB, 0xE1, 0xD8, 0x8D, 0xFC, 0x8D, 0xFD, /* 0x9C-0x9F */ - 0x8D, 0xFE, 0x8E, 0x40, 0x8E, 0x41, 0x8E, 0x42, /* 0xA0-0xA3 */ - 0x8E, 0x43, 0x8E, 0x44, 0x8E, 0x45, 0x8E, 0x46, /* 0xA4-0xA7 */ - 0x8E, 0x47, 0x8E, 0x48, 0x8E, 0x49, 0x8E, 0x4A, /* 0xA8-0xAB */ - 0x8E, 0x4B, 0x8E, 0x4C, 0x8E, 0x4D, 0x8E, 0x4E, /* 0xAC-0xAF */ - 0x8E, 0x4F, 0x8E, 0x50, 0x8E, 0x51, 0x8E, 0x52, /* 0xB0-0xB3 */ - 0x8E, 0x53, 0x8E, 0x54, 0x8E, 0x55, 0xE1, 0xDA, /* 0xB4-0xB7 */ - 0x8E, 0x56, 0x8E, 0x57, 0x8E, 0x58, 0x8E, 0x59, /* 0xB8-0xBB */ - 0x8E, 0x5A, 0x8E, 0x5B, 0x8E, 0x5C, 0x8E, 0x5D, /* 0xBC-0xBF */ - 0x8E, 0x5E, 0x8E, 0x5F, 0x8E, 0x60, 0x8E, 0x61, /* 0xC0-0xC3 */ - 0x8E, 0x62, 0xE1, 0xDB, 0x8E, 0x63, 0x8E, 0x64, /* 0xC4-0xC7 */ - 0x8E, 0x65, 0x8E, 0x66, 0x8E, 0x67, 0x8E, 0x68, /* 0xC8-0xCB */ - 0x8E, 0x69, 0xCE, 0xA1, 0x8E, 0x6A, 0x8E, 0x6B, /* 0xCC-0xCF */ - 0x8E, 0x6C, 0x8E, 0x6D, 0x8E, 0x6E, 0x8E, 0x6F, /* 0xD0-0xD3 */ - 0x8E, 0x70, 0x8E, 0x71, 0x8E, 0x72, 0x8E, 0x73, /* 0xD4-0xD7 */ - 0x8E, 0x74, 0x8E, 0x75, 0x8E, 0x76, 0xE7, 0xDD, /* 0xD8-0xDB */ - 0x8E, 0x77, 0xB4, 0xA8, 0xD6, 0xDD, 0x8E, 0x78, /* 0xDC-0xDF */ - 0x8E, 0x79, 0xD1, 0xB2, 0xB3, 0xB2, 0x8E, 0x7A, /* 0xE0-0xE3 */ - 0x8E, 0x7B, 0xB9, 0xA4, 0xD7, 0xF3, 0xC7, 0xC9, /* 0xE4-0xE7 */ - 0xBE, 0xDE, 0xB9, 0xAE, 0x8E, 0x7C, 0xCE, 0xD7, /* 0xE8-0xEB */ - 0x8E, 0x7D, 0x8E, 0x7E, 0xB2, 0xEE, 0xDB, 0xCF, /* 0xEC-0xEF */ - 0x8E, 0x80, 0xBC, 0xBA, 0xD2, 0xD1, 0xCB, 0xC8, /* 0xF0-0xF3 */ - 0xB0, 0xCD, 0x8E, 0x81, 0x8E, 0x82, 0xCF, 0xEF, /* 0xF4-0xF7 */ - 0x8E, 0x83, 0x8E, 0x84, 0x8E, 0x85, 0x8E, 0x86, /* 0xF8-0xFB */ - 0x8E, 0x87, 0xD9, 0xE3, 0xBD, 0xED, 0x8E, 0x88, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5E[512] = { - 0x8E, 0x89, 0xB1, 0xD2, 0xCA, 0xD0, 0xB2, 0xBC, /* 0x00-0x03 */ - 0x8E, 0x8A, 0xCB, 0xA7, 0xB7, 0xAB, 0x8E, 0x8B, /* 0x04-0x07 */ - 0xCA, 0xA6, 0x8E, 0x8C, 0x8E, 0x8D, 0x8E, 0x8E, /* 0x08-0x0B */ - 0xCF, 0xA3, 0x8E, 0x8F, 0x8E, 0x90, 0xE0, 0xF8, /* 0x0C-0x0F */ - 0xD5, 0xCA, 0xE0, 0xFB, 0x8E, 0x91, 0x8E, 0x92, /* 0x10-0x13 */ - 0xE0, 0xFA, 0xC5, 0xC1, 0xCC, 0xFB, 0x8E, 0x93, /* 0x14-0x17 */ - 0xC1, 0xB1, 0xE0, 0xF9, 0xD6, 0xE3, 0xB2, 0xAF, /* 0x18-0x1B */ - 0xD6, 0xC4, 0xB5, 0xDB, 0x8E, 0x94, 0x8E, 0x95, /* 0x1C-0x1F */ - 0x8E, 0x96, 0x8E, 0x97, 0x8E, 0x98, 0x8E, 0x99, /* 0x20-0x23 */ - 0x8E, 0x9A, 0x8E, 0x9B, 0xB4, 0xF8, 0xD6, 0xA1, /* 0x24-0x27 */ - 0x8E, 0x9C, 0x8E, 0x9D, 0x8E, 0x9E, 0x8E, 0x9F, /* 0x28-0x2B */ - 0x8E, 0xA0, 0xCF, 0xAF, 0xB0, 0xEF, 0x8E, 0xA1, /* 0x2C-0x2F */ - 0x8E, 0xA2, 0xE0, 0xFC, 0x8E, 0xA3, 0x8E, 0xA4, /* 0x30-0x33 */ - 0x8E, 0xA5, 0x8E, 0xA6, 0x8E, 0xA7, 0xE1, 0xA1, /* 0x34-0x37 */ - 0xB3, 0xA3, 0x8E, 0xA8, 0x8E, 0xA9, 0xE0, 0xFD, /* 0x38-0x3B */ - 0xE0, 0xFE, 0xC3, 0xB1, 0x8E, 0xAA, 0x8E, 0xAB, /* 0x3C-0x3F */ - 0x8E, 0xAC, 0x8E, 0xAD, 0xC3, 0xDD, 0x8E, 0xAE, /* 0x40-0x43 */ - 0xE1, 0xA2, 0xB7, 0xF9, 0x8E, 0xAF, 0x8E, 0xB0, /* 0x44-0x47 */ - 0x8E, 0xB1, 0x8E, 0xB2, 0x8E, 0xB3, 0x8E, 0xB4, /* 0x48-0x4B */ - 0xBB, 0xCF, 0x8E, 0xB5, 0x8E, 0xB6, 0x8E, 0xB7, /* 0x4C-0x4F */ - 0x8E, 0xB8, 0x8E, 0xB9, 0x8E, 0xBA, 0x8E, 0xBB, /* 0x50-0x53 */ - 0xE1, 0xA3, 0xC4, 0xBB, 0x8E, 0xBC, 0x8E, 0xBD, /* 0x54-0x57 */ - 0x8E, 0xBE, 0x8E, 0xBF, 0x8E, 0xC0, 0xE1, 0xA4, /* 0x58-0x5B */ - 0x8E, 0xC1, 0x8E, 0xC2, 0xE1, 0xA5, 0x8E, 0xC3, /* 0x5C-0x5F */ - 0x8E, 0xC4, 0xE1, 0xA6, 0xB4, 0xB1, 0x8E, 0xC5, /* 0x60-0x63 */ - 0x8E, 0xC6, 0x8E, 0xC7, 0x8E, 0xC8, 0x8E, 0xC9, /* 0x64-0x67 */ - 0x8E, 0xCA, 0x8E, 0xCB, 0x8E, 0xCC, 0x8E, 0xCD, /* 0x68-0x6B */ - 0x8E, 0xCE, 0x8E, 0xCF, 0x8E, 0xD0, 0x8E, 0xD1, /* 0x6C-0x6F */ - 0x8E, 0xD2, 0x8E, 0xD3, 0xB8, 0xC9, 0xC6, 0xBD, /* 0x70-0x73 */ - 0xC4, 0xEA, 0x8E, 0xD4, 0xB2, 0xA2, 0x8E, 0xD5, /* 0x74-0x77 */ - 0xD0, 0xD2, 0x8E, 0xD6, 0xE7, 0xDB, 0xBB, 0xC3, /* 0x78-0x7B */ - 0xD3, 0xD7, 0xD3, 0xC4, 0x8E, 0xD7, 0xB9, 0xE3, /* 0x7C-0x7F */ - - 0xE2, 0xCF, 0x8E, 0xD8, 0x8E, 0xD9, 0x8E, 0xDA, /* 0x80-0x83 */ - 0xD7, 0xAF, 0x8E, 0xDB, 0xC7, 0xEC, 0xB1, 0xD3, /* 0x84-0x87 */ - 0x8E, 0xDC, 0x8E, 0xDD, 0xB4, 0xB2, 0xE2, 0xD1, /* 0x88-0x8B */ - 0x8E, 0xDE, 0x8E, 0xDF, 0x8E, 0xE0, 0xD0, 0xF2, /* 0x8C-0x8F */ - 0xC2, 0xAE, 0xE2, 0xD0, 0x8E, 0xE1, 0xBF, 0xE2, /* 0x90-0x93 */ - 0xD3, 0xA6, 0xB5, 0xD7, 0xE2, 0xD2, 0xB5, 0xEA, /* 0x94-0x97 */ - 0x8E, 0xE2, 0xC3, 0xED, 0xB8, 0xFD, 0x8E, 0xE3, /* 0x98-0x9B */ - 0xB8, 0xAE, 0x8E, 0xE4, 0xC5, 0xD3, 0xB7, 0xCF, /* 0x9C-0x9F */ - 0xE2, 0xD4, 0x8E, 0xE5, 0x8E, 0xE6, 0x8E, 0xE7, /* 0xA0-0xA3 */ - 0x8E, 0xE8, 0xE2, 0xD3, 0xB6, 0xC8, 0xD7, 0xF9, /* 0xA4-0xA7 */ - 0x8E, 0xE9, 0x8E, 0xEA, 0x8E, 0xEB, 0x8E, 0xEC, /* 0xA8-0xAB */ - 0x8E, 0xED, 0xCD, 0xA5, 0x8E, 0xEE, 0x8E, 0xEF, /* 0xAC-0xAF */ - 0x8E, 0xF0, 0x8E, 0xF1, 0x8E, 0xF2, 0xE2, 0xD8, /* 0xB0-0xB3 */ - 0x8E, 0xF3, 0xE2, 0xD6, 0xCA, 0xFC, 0xBF, 0xB5, /* 0xB4-0xB7 */ - 0xD3, 0xB9, 0xE2, 0xD5, 0x8E, 0xF4, 0x8E, 0xF5, /* 0xB8-0xBB */ - 0x8E, 0xF6, 0x8E, 0xF7, 0xE2, 0xD7, 0x8E, 0xF8, /* 0xBC-0xBF */ - 0x8E, 0xF9, 0x8E, 0xFA, 0x8E, 0xFB, 0x8E, 0xFC, /* 0xC0-0xC3 */ - 0x8E, 0xFD, 0x8E, 0xFE, 0x8F, 0x40, 0x8F, 0x41, /* 0xC4-0xC7 */ - 0x8F, 0x42, 0xC1, 0xAE, 0xC0, 0xC8, 0x8F, 0x43, /* 0xC8-0xCB */ - 0x8F, 0x44, 0x8F, 0x45, 0x8F, 0x46, 0x8F, 0x47, /* 0xCC-0xCF */ - 0x8F, 0x48, 0xE2, 0xDB, 0xE2, 0xDA, 0xC0, 0xAA, /* 0xD0-0xD3 */ - 0x8F, 0x49, 0x8F, 0x4A, 0xC1, 0xCE, 0x8F, 0x4B, /* 0xD4-0xD7 */ - 0x8F, 0x4C, 0x8F, 0x4D, 0x8F, 0x4E, 0xE2, 0xDC, /* 0xD8-0xDB */ - 0x8F, 0x4F, 0x8F, 0x50, 0x8F, 0x51, 0x8F, 0x52, /* 0xDC-0xDF */ - 0x8F, 0x53, 0x8F, 0x54, 0x8F, 0x55, 0x8F, 0x56, /* 0xE0-0xE3 */ - 0x8F, 0x57, 0x8F, 0x58, 0x8F, 0x59, 0x8F, 0x5A, /* 0xE4-0xE7 */ - 0xE2, 0xDD, 0x8F, 0x5B, 0xE2, 0xDE, 0x8F, 0x5C, /* 0xE8-0xEB */ - 0x8F, 0x5D, 0x8F, 0x5E, 0x8F, 0x5F, 0x8F, 0x60, /* 0xEC-0xEF */ - 0x8F, 0x61, 0x8F, 0x62, 0x8F, 0x63, 0x8F, 0x64, /* 0xF0-0xF3 */ - 0xDB, 0xC8, 0x8F, 0x65, 0xD1, 0xD3, 0xCD, 0xA2, /* 0xF4-0xF7 */ - 0x8F, 0x66, 0x8F, 0x67, 0xBD, 0xA8, 0x8F, 0x68, /* 0xF8-0xFB */ - 0x8F, 0x69, 0x8F, 0x6A, 0xDE, 0xC3, 0xD8, 0xA5, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5F[512] = { - 0xBF, 0xAA, 0xDB, 0xCD, 0xD2, 0xEC, 0xC6, 0xFA, /* 0x00-0x03 */ - 0xC5, 0xAA, 0x8F, 0x6B, 0x8F, 0x6C, 0x8F, 0x6D, /* 0x04-0x07 */ - 0xDE, 0xC4, 0x8F, 0x6E, 0xB1, 0xD7, 0xDF, 0xAE, /* 0x08-0x0B */ - 0x8F, 0x6F, 0x8F, 0x70, 0x8F, 0x71, 0xCA, 0xBD, /* 0x0C-0x0F */ - 0x8F, 0x72, 0xDF, 0xB1, 0x8F, 0x73, 0xB9, 0xAD, /* 0x10-0x13 */ - 0x8F, 0x74, 0xD2, 0xFD, 0x8F, 0x75, 0xB8, 0xA5, /* 0x14-0x17 */ - 0xBA, 0xEB, 0x8F, 0x76, 0x8F, 0x77, 0xB3, 0xDA, /* 0x18-0x1B */ - 0x8F, 0x78, 0x8F, 0x79, 0x8F, 0x7A, 0xB5, 0xDC, /* 0x1C-0x1F */ - 0xD5, 0xC5, 0x8F, 0x7B, 0x8F, 0x7C, 0x8F, 0x7D, /* 0x20-0x23 */ - 0x8F, 0x7E, 0xC3, 0xD6, 0xCF, 0xD2, 0xBB, 0xA1, /* 0x24-0x27 */ - 0x8F, 0x80, 0xE5, 0xF3, 0xE5, 0xF2, 0x8F, 0x81, /* 0x28-0x2B */ - 0x8F, 0x82, 0xE5, 0xF4, 0x8F, 0x83, 0xCD, 0xE4, /* 0x2C-0x2F */ - 0x8F, 0x84, 0xC8, 0xF5, 0x8F, 0x85, 0x8F, 0x86, /* 0x30-0x33 */ - 0x8F, 0x87, 0x8F, 0x88, 0x8F, 0x89, 0x8F, 0x8A, /* 0x34-0x37 */ - 0x8F, 0x8B, 0xB5, 0xAF, 0xC7, 0xBF, 0x8F, 0x8C, /* 0x38-0x3B */ - 0xE5, 0xF6, 0x8F, 0x8D, 0x8F, 0x8E, 0x8F, 0x8F, /* 0x3C-0x3F */ - 0xEC, 0xB0, 0x8F, 0x90, 0x8F, 0x91, 0x8F, 0x92, /* 0x40-0x43 */ - 0x8F, 0x93, 0x8F, 0x94, 0x8F, 0x95, 0x8F, 0x96, /* 0x44-0x47 */ - 0x8F, 0x97, 0x8F, 0x98, 0x8F, 0x99, 0x8F, 0x9A, /* 0x48-0x4B */ - 0x8F, 0x9B, 0x8F, 0x9C, 0x8F, 0x9D, 0x8F, 0x9E, /* 0x4C-0x4F */ - 0xE5, 0xE6, 0x8F, 0x9F, 0xB9, 0xE9, 0xB5, 0xB1, /* 0x50-0x53 */ - 0x8F, 0xA0, 0xC2, 0xBC, 0xE5, 0xE8, 0xE5, 0xE7, /* 0x54-0x57 */ - 0xE5, 0xE9, 0x8F, 0xA1, 0x8F, 0xA2, 0x8F, 0xA3, /* 0x58-0x5B */ - 0x8F, 0xA4, 0xD2, 0xCD, 0x8F, 0xA5, 0x8F, 0xA6, /* 0x5C-0x5F */ - 0x8F, 0xA7, 0xE1, 0xEA, 0xD0, 0xCE, 0x8F, 0xA8, /* 0x60-0x63 */ - 0xCD, 0xAE, 0x8F, 0xA9, 0xD1, 0xE5, 0x8F, 0xAA, /* 0x64-0x67 */ - 0x8F, 0xAB, 0xB2, 0xCA, 0xB1, 0xEB, 0x8F, 0xAC, /* 0x68-0x6B */ - 0xB1, 0xF2, 0xC5, 0xED, 0x8F, 0xAD, 0x8F, 0xAE, /* 0x6C-0x6F */ - 0xD5, 0xC3, 0xD3, 0xB0, 0x8F, 0xAF, 0xE1, 0xDC, /* 0x70-0x73 */ - 0x8F, 0xB0, 0x8F, 0xB1, 0x8F, 0xB2, 0xE1, 0xDD, /* 0x74-0x77 */ - 0x8F, 0xB3, 0xD2, 0xDB, 0x8F, 0xB4, 0xB3, 0xB9, /* 0x78-0x7B */ - 0xB1, 0xCB, 0x8F, 0xB5, 0x8F, 0xB6, 0x8F, 0xB7, /* 0x7C-0x7F */ - - 0xCD, 0xF9, 0xD5, 0xF7, 0xE1, 0xDE, 0x8F, 0xB8, /* 0x80-0x83 */ - 0xBE, 0xB6, 0xB4, 0xFD, 0x8F, 0xB9, 0xE1, 0xDF, /* 0x84-0x87 */ - 0xBA, 0xDC, 0xE1, 0xE0, 0xBB, 0xB2, 0xC2, 0xC9, /* 0x88-0x8B */ - 0xE1, 0xE1, 0x8F, 0xBA, 0x8F, 0xBB, 0x8F, 0xBC, /* 0x8C-0x8F */ - 0xD0, 0xEC, 0x8F, 0xBD, 0xCD, 0xBD, 0x8F, 0xBE, /* 0x90-0x93 */ - 0x8F, 0xBF, 0xE1, 0xE2, 0x8F, 0xC0, 0xB5, 0xC3, /* 0x94-0x97 */ - 0xC5, 0xC7, 0xE1, 0xE3, 0x8F, 0xC1, 0x8F, 0xC2, /* 0x98-0x9B */ - 0xE1, 0xE4, 0x8F, 0xC3, 0x8F, 0xC4, 0x8F, 0xC5, /* 0x9C-0x9F */ - 0x8F, 0xC6, 0xD3, 0xF9, 0x8F, 0xC7, 0x8F, 0xC8, /* 0xA0-0xA3 */ - 0x8F, 0xC9, 0x8F, 0xCA, 0x8F, 0xCB, 0x8F, 0xCC, /* 0xA4-0xA7 */ - 0xE1, 0xE5, 0x8F, 0xCD, 0xD1, 0xAD, 0x8F, 0xCE, /* 0xA8-0xAB */ - 0x8F, 0xCF, 0xE1, 0xE6, 0xCE, 0xA2, 0x8F, 0xD0, /* 0xAC-0xAF */ - 0x8F, 0xD1, 0x8F, 0xD2, 0x8F, 0xD3, 0x8F, 0xD4, /* 0xB0-0xB3 */ - 0x8F, 0xD5, 0xE1, 0xE7, 0x8F, 0xD6, 0xB5, 0xC2, /* 0xB4-0xB7 */ - 0x8F, 0xD7, 0x8F, 0xD8, 0x8F, 0xD9, 0x8F, 0xDA, /* 0xB8-0xBB */ - 0xE1, 0xE8, 0xBB, 0xD5, 0x8F, 0xDB, 0x8F, 0xDC, /* 0xBC-0xBF */ - 0x8F, 0xDD, 0x8F, 0xDE, 0x8F, 0xDF, 0xD0, 0xC4, /* 0xC0-0xC3 */ - 0xE2, 0xE0, 0xB1, 0xD8, 0xD2, 0xE4, 0x8F, 0xE0, /* 0xC4-0xC7 */ - 0x8F, 0xE1, 0xE2, 0xE1, 0x8F, 0xE2, 0x8F, 0xE3, /* 0xC8-0xCB */ - 0xBC, 0xC9, 0xC8, 0xCC, 0x8F, 0xE4, 0xE2, 0xE3, /* 0xCC-0xCF */ - 0xEC, 0xFE, 0xEC, 0xFD, 0xDF, 0xAF, 0x8F, 0xE5, /* 0xD0-0xD3 */ - 0x8F, 0xE6, 0x8F, 0xE7, 0xE2, 0xE2, 0xD6, 0xBE, /* 0xD4-0xD7 */ - 0xCD, 0xFC, 0xC3, 0xA6, 0x8F, 0xE8, 0x8F, 0xE9, /* 0xD8-0xDB */ - 0x8F, 0xEA, 0xE3, 0xC3, 0x8F, 0xEB, 0x8F, 0xEC, /* 0xDC-0xDF */ - 0xD6, 0xD2, 0xE2, 0xE7, 0x8F, 0xED, 0x8F, 0xEE, /* 0xE0-0xE3 */ - 0xE2, 0xE8, 0x8F, 0xEF, 0x8F, 0xF0, 0xD3, 0xC7, /* 0xE4-0xE7 */ - 0x8F, 0xF1, 0x8F, 0xF2, 0xE2, 0xEC, 0xBF, 0xEC, /* 0xE8-0xEB */ - 0x8F, 0xF3, 0xE2, 0xED, 0xE2, 0xE5, 0x8F, 0xF4, /* 0xEC-0xEF */ - 0x8F, 0xF5, 0xB3, 0xC0, 0x8F, 0xF6, 0x8F, 0xF7, /* 0xF0-0xF3 */ - 0x8F, 0xF8, 0xC4, 0xEE, 0x8F, 0xF9, 0x8F, 0xFA, /* 0xF4-0xF7 */ - 0xE2, 0xEE, 0x8F, 0xFB, 0x8F, 0xFC, 0xD0, 0xC3, /* 0xF8-0xFB */ - 0x8F, 0xFD, 0xBA, 0xF6, 0xE2, 0xE9, 0xB7, 0xDE, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_60[512] = { - 0xBB, 0xB3, 0xCC, 0xAC, 0xCB, 0xCB, 0xE2, 0xE4, /* 0x00-0x03 */ - 0xE2, 0xE6, 0xE2, 0xEA, 0xE2, 0xEB, 0x8F, 0xFE, /* 0x04-0x07 */ - 0x90, 0x40, 0x90, 0x41, 0xE2, 0xF7, 0x90, 0x42, /* 0x08-0x0B */ - 0x90, 0x43, 0xE2, 0xF4, 0xD4, 0xF5, 0xE2, 0xF3, /* 0x0C-0x0F */ - 0x90, 0x44, 0x90, 0x45, 0xC5, 0xAD, 0x90, 0x46, /* 0x10-0x13 */ - 0xD5, 0xFA, 0xC5, 0xC2, 0xB2, 0xC0, 0x90, 0x47, /* 0x14-0x17 */ - 0x90, 0x48, 0xE2, 0xEF, 0x90, 0x49, 0xE2, 0xF2, /* 0x18-0x1B */ - 0xC1, 0xAF, 0xCB, 0xBC, 0x90, 0x4A, 0x90, 0x4B, /* 0x1C-0x1F */ - 0xB5, 0xA1, 0xE2, 0xF9, 0x90, 0x4C, 0x90, 0x4D, /* 0x20-0x23 */ - 0x90, 0x4E, 0xBC, 0xB1, 0xE2, 0xF1, 0xD0, 0xD4, /* 0x24-0x27 */ - 0xD4, 0xB9, 0xE2, 0xF5, 0xB9, 0xD6, 0xE2, 0xF6, /* 0x28-0x2B */ - 0x90, 0x4F, 0x90, 0x50, 0x90, 0x51, 0xC7, 0xD3, /* 0x2C-0x2F */ - 0x90, 0x52, 0x90, 0x53, 0x90, 0x54, 0x90, 0x55, /* 0x30-0x33 */ - 0x90, 0x56, 0xE2, 0xF0, 0x90, 0x57, 0x90, 0x58, /* 0x34-0x37 */ - 0x90, 0x59, 0x90, 0x5A, 0x90, 0x5B, 0xD7, 0xDC, /* 0x38-0x3B */ - 0xED, 0xA1, 0x90, 0x5C, 0x90, 0x5D, 0xE2, 0xF8, /* 0x3C-0x3F */ - 0x90, 0x5E, 0xED, 0xA5, 0xE2, 0xFE, 0xCA, 0xD1, /* 0x40-0x43 */ - 0x90, 0x5F, 0x90, 0x60, 0x90, 0x61, 0x90, 0x62, /* 0x44-0x47 */ - 0x90, 0x63, 0x90, 0x64, 0x90, 0x65, 0xC1, 0xB5, /* 0x48-0x4B */ - 0x90, 0x66, 0xBB, 0xD0, 0x90, 0x67, 0x90, 0x68, /* 0x4C-0x4F */ - 0xBF, 0xD6, 0x90, 0x69, 0xBA, 0xE3, 0x90, 0x6A, /* 0x50-0x53 */ - 0x90, 0x6B, 0xCB, 0xA1, 0x90, 0x6C, 0x90, 0x6D, /* 0x54-0x57 */ - 0x90, 0x6E, 0xED, 0xA6, 0xED, 0xA3, 0x90, 0x6F, /* 0x58-0x5B */ - 0x90, 0x70, 0xED, 0xA2, 0x90, 0x71, 0x90, 0x72, /* 0x5C-0x5F */ - 0x90, 0x73, 0x90, 0x74, 0xBB, 0xD6, 0xED, 0xA7, /* 0x60-0x63 */ - 0xD0, 0xF4, 0x90, 0x75, 0x90, 0x76, 0xED, 0xA4, /* 0x64-0x67 */ - 0xBA, 0xDE, 0xB6, 0xF7, 0xE3, 0xA1, 0xB6, 0xB2, /* 0x68-0x6B */ - 0xCC, 0xF1, 0xB9, 0xA7, 0x90, 0x77, 0xCF, 0xA2, /* 0x6C-0x6F */ - 0xC7, 0xA1, 0x90, 0x78, 0x90, 0x79, 0xBF, 0xD2, /* 0x70-0x73 */ - 0x90, 0x7A, 0x90, 0x7B, 0xB6, 0xF1, 0x90, 0x7C, /* 0x74-0x77 */ - 0xE2, 0xFA, 0xE2, 0xFB, 0xE2, 0xFD, 0xE2, 0xFC, /* 0x78-0x7B */ - 0xC4, 0xD5, 0xE3, 0xA2, 0x90, 0x7D, 0xD3, 0xC1, /* 0x7C-0x7F */ - - 0x90, 0x7E, 0x90, 0x80, 0x90, 0x81, 0xE3, 0xA7, /* 0x80-0x83 */ - 0xC7, 0xC4, 0x90, 0x82, 0x90, 0x83, 0x90, 0x84, /* 0x84-0x87 */ - 0x90, 0x85, 0xCF, 0xA4, 0x90, 0x86, 0x90, 0x87, /* 0x88-0x8B */ - 0xE3, 0xA9, 0xBA, 0xB7, 0x90, 0x88, 0x90, 0x89, /* 0x8C-0x8F */ - 0x90, 0x8A, 0x90, 0x8B, 0xE3, 0xA8, 0x90, 0x8C, /* 0x90-0x93 */ - 0xBB, 0xDA, 0x90, 0x8D, 0xE3, 0xA3, 0x90, 0x8E, /* 0x94-0x97 */ - 0x90, 0x8F, 0x90, 0x90, 0xE3, 0xA4, 0xE3, 0xAA, /* 0x98-0x9B */ - 0x90, 0x91, 0xE3, 0xA6, 0x90, 0x92, 0xCE, 0xF2, /* 0x9C-0x9F */ - 0xD3, 0xC6, 0x90, 0x93, 0x90, 0x94, 0xBB, 0xBC, /* 0xA0-0xA3 */ - 0x90, 0x95, 0x90, 0x96, 0xD4, 0xC3, 0x90, 0x97, /* 0xA4-0xA7 */ - 0xC4, 0xFA, 0x90, 0x98, 0x90, 0x99, 0xED, 0xA8, /* 0xA8-0xAB */ - 0xD0, 0xFC, 0xE3, 0xA5, 0x90, 0x9A, 0xC3, 0xF5, /* 0xAC-0xAF */ - 0x90, 0x9B, 0xE3, 0xAD, 0xB1, 0xAF, 0x90, 0x9C, /* 0xB0-0xB3 */ - 0xE3, 0xB2, 0x90, 0x9D, 0x90, 0x9E, 0x90, 0x9F, /* 0xB4-0xB7 */ - 0xBC, 0xC2, 0x90, 0xA0, 0x90, 0xA1, 0xE3, 0xAC, /* 0xB8-0xBB */ - 0xB5, 0xBF, 0x90, 0xA2, 0x90, 0xA3, 0x90, 0xA4, /* 0xBC-0xBF */ - 0x90, 0xA5, 0x90, 0xA6, 0x90, 0xA7, 0x90, 0xA8, /* 0xC0-0xC3 */ - 0x90, 0xA9, 0xC7, 0xE9, 0xE3, 0xB0, 0x90, 0xAA, /* 0xC4-0xC7 */ - 0x90, 0xAB, 0x90, 0xAC, 0xBE, 0xAA, 0xCD, 0xEF, /* 0xC8-0xCB */ - 0x90, 0xAD, 0x90, 0xAE, 0x90, 0xAF, 0x90, 0xB0, /* 0xCC-0xCF */ - 0x90, 0xB1, 0xBB, 0xF3, 0x90, 0xB2, 0x90, 0xB3, /* 0xD0-0xD3 */ - 0x90, 0xB4, 0xCC, 0xE8, 0x90, 0xB5, 0x90, 0xB6, /* 0xD4-0xD7 */ - 0xE3, 0xAF, 0x90, 0xB7, 0xE3, 0xB1, 0x90, 0xB8, /* 0xD8-0xDB */ - 0xCF, 0xA7, 0xE3, 0xAE, 0x90, 0xB9, 0xCE, 0xA9, /* 0xDC-0xDF */ - 0xBB, 0xDD, 0x90, 0xBA, 0x90, 0xBB, 0x90, 0xBC, /* 0xE0-0xE3 */ - 0x90, 0xBD, 0x90, 0xBE, 0xB5, 0xEB, 0xBE, 0xE5, /* 0xE4-0xE7 */ - 0xB2, 0xD2, 0xB3, 0xCD, 0x90, 0xBF, 0xB1, 0xB9, /* 0xE8-0xEB */ - 0xE3, 0xAB, 0xB2, 0xD1, 0xB5, 0xAC, 0xB9, 0xDF, /* 0xEC-0xEF */ - 0xB6, 0xE8, 0x90, 0xC0, 0x90, 0xC1, 0xCF, 0xEB, /* 0xF0-0xF3 */ - 0xE3, 0xB7, 0x90, 0xC2, 0xBB, 0xCC, 0x90, 0xC3, /* 0xF4-0xF7 */ - 0x90, 0xC4, 0xC8, 0xC7, 0xD0, 0xCA, 0x90, 0xC5, /* 0xF8-0xFB */ - 0x90, 0xC6, 0x90, 0xC7, 0x90, 0xC8, 0x90, 0xC9, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_61[512] = { - 0xE3, 0xB8, 0xB3, 0xEE, 0x90, 0xCA, 0x90, 0xCB, /* 0x00-0x03 */ - 0x90, 0xCC, 0x90, 0xCD, 0xED, 0xA9, 0x90, 0xCE, /* 0x04-0x07 */ - 0xD3, 0xFA, 0xD3, 0xE4, 0x90, 0xCF, 0x90, 0xD0, /* 0x08-0x0B */ - 0x90, 0xD1, 0xED, 0xAA, 0xE3, 0xB9, 0xD2, 0xE2, /* 0x0C-0x0F */ - 0x90, 0xD2, 0x90, 0xD3, 0x90, 0xD4, 0x90, 0xD5, /* 0x10-0x13 */ - 0x90, 0xD6, 0xE3, 0xB5, 0x90, 0xD7, 0x90, 0xD8, /* 0x14-0x17 */ - 0x90, 0xD9, 0x90, 0xDA, 0xD3, 0xDE, 0x90, 0xDB, /* 0x18-0x1B */ - 0x90, 0xDC, 0x90, 0xDD, 0x90, 0xDE, 0xB8, 0xD0, /* 0x1C-0x1F */ - 0xE3, 0xB3, 0x90, 0xDF, 0x90, 0xE0, 0xE3, 0xB6, /* 0x20-0x23 */ - 0xB7, 0xDF, 0x90, 0xE1, 0xE3, 0xB4, 0xC0, 0xA2, /* 0x24-0x27 */ - 0x90, 0xE2, 0x90, 0xE3, 0x90, 0xE4, 0xE3, 0xBA, /* 0x28-0x2B */ - 0x90, 0xE5, 0x90, 0xE6, 0x90, 0xE7, 0x90, 0xE8, /* 0x2C-0x2F */ - 0x90, 0xE9, 0x90, 0xEA, 0x90, 0xEB, 0x90, 0xEC, /* 0x30-0x33 */ - 0x90, 0xED, 0x90, 0xEE, 0x90, 0xEF, 0x90, 0xF0, /* 0x34-0x37 */ - 0x90, 0xF1, 0x90, 0xF2, 0x90, 0xF3, 0x90, 0xF4, /* 0x38-0x3B */ - 0x90, 0xF5, 0x90, 0xF6, 0x90, 0xF7, 0xD4, 0xB8, /* 0x3C-0x3F */ - 0x90, 0xF8, 0x90, 0xF9, 0x90, 0xFA, 0x90, 0xFB, /* 0x40-0x43 */ - 0x90, 0xFC, 0x90, 0xFD, 0x90, 0xFE, 0x91, 0x40, /* 0x44-0x47 */ - 0xB4, 0xC8, 0x91, 0x41, 0xE3, 0xBB, 0x91, 0x42, /* 0x48-0x4B */ - 0xBB, 0xC5, 0x91, 0x43, 0xC9, 0xF7, 0x91, 0x44, /* 0x4C-0x4F */ - 0x91, 0x45, 0xC9, 0xE5, 0x91, 0x46, 0x91, 0x47, /* 0x50-0x53 */ - 0x91, 0x48, 0xC4, 0xBD, 0x91, 0x49, 0x91, 0x4A, /* 0x54-0x57 */ - 0x91, 0x4B, 0x91, 0x4C, 0x91, 0x4D, 0x91, 0x4E, /* 0x58-0x5B */ - 0x91, 0x4F, 0xED, 0xAB, 0x91, 0x50, 0x91, 0x51, /* 0x5C-0x5F */ - 0x91, 0x52, 0x91, 0x53, 0xC2, 0xFD, 0x91, 0x54, /* 0x60-0x63 */ - 0x91, 0x55, 0x91, 0x56, 0x91, 0x57, 0xBB, 0xDB, /* 0x64-0x67 */ - 0xBF, 0xAE, 0x91, 0x58, 0x91, 0x59, 0x91, 0x5A, /* 0x68-0x6B */ - 0x91, 0x5B, 0x91, 0x5C, 0x91, 0x5D, 0x91, 0x5E, /* 0x6C-0x6F */ - 0xCE, 0xBF, 0x91, 0x5F, 0x91, 0x60, 0x91, 0x61, /* 0x70-0x73 */ - 0x91, 0x62, 0xE3, 0xBC, 0x91, 0x63, 0xBF, 0xB6, /* 0x74-0x77 */ - 0x91, 0x64, 0x91, 0x65, 0x91, 0x66, 0x91, 0x67, /* 0x78-0x7B */ - 0x91, 0x68, 0x91, 0x69, 0x91, 0x6A, 0x91, 0x6B, /* 0x7C-0x7F */ - - 0x91, 0x6C, 0x91, 0x6D, 0x91, 0x6E, 0x91, 0x6F, /* 0x80-0x83 */ - 0x91, 0x70, 0x91, 0x71, 0x91, 0x72, 0x91, 0x73, /* 0x84-0x87 */ - 0x91, 0x74, 0x91, 0x75, 0x91, 0x76, 0xB1, 0xEF, /* 0x88-0x8B */ - 0x91, 0x77, 0x91, 0x78, 0xD4, 0xF7, 0x91, 0x79, /* 0x8C-0x8F */ - 0x91, 0x7A, 0x91, 0x7B, 0x91, 0x7C, 0x91, 0x7D, /* 0x90-0x93 */ - 0xE3, 0xBE, 0x91, 0x7E, 0x91, 0x80, 0x91, 0x81, /* 0x94-0x97 */ - 0x91, 0x82, 0x91, 0x83, 0x91, 0x84, 0x91, 0x85, /* 0x98-0x9B */ - 0x91, 0x86, 0xED, 0xAD, 0x91, 0x87, 0x91, 0x88, /* 0x9C-0x9F */ - 0x91, 0x89, 0x91, 0x8A, 0x91, 0x8B, 0x91, 0x8C, /* 0xA0-0xA3 */ - 0x91, 0x8D, 0x91, 0x8E, 0x91, 0x8F, 0xE3, 0xBF, /* 0xA4-0xA7 */ - 0xBA, 0xA9, 0xED, 0xAC, 0x91, 0x90, 0x91, 0x91, /* 0xA8-0xAB */ - 0xE3, 0xBD, 0x91, 0x92, 0x91, 0x93, 0x91, 0x94, /* 0xAC-0xAF */ - 0x91, 0x95, 0x91, 0x96, 0x91, 0x97, 0x91, 0x98, /* 0xB0-0xB3 */ - 0x91, 0x99, 0x91, 0x9A, 0x91, 0x9B, 0xE3, 0xC0, /* 0xB4-0xB7 */ - 0x91, 0x9C, 0x91, 0x9D, 0x91, 0x9E, 0x91, 0x9F, /* 0xB8-0xBB */ - 0x91, 0xA0, 0x91, 0xA1, 0xBA, 0xB6, 0x91, 0xA2, /* 0xBC-0xBF */ - 0x91, 0xA3, 0x91, 0xA4, 0xB6, 0xAE, 0x91, 0xA5, /* 0xC0-0xC3 */ - 0x91, 0xA6, 0x91, 0xA7, 0x91, 0xA8, 0x91, 0xA9, /* 0xC4-0xC7 */ - 0xD0, 0xB8, 0x91, 0xAA, 0xB0, 0xC3, 0xED, 0xAE, /* 0xC8-0xCB */ - 0x91, 0xAB, 0x91, 0xAC, 0x91, 0xAD, 0x91, 0xAE, /* 0xCC-0xCF */ - 0x91, 0xAF, 0xED, 0xAF, 0xC0, 0xC1, 0x91, 0xB0, /* 0xD0-0xD3 */ - 0xE3, 0xC1, 0x91, 0xB1, 0x91, 0xB2, 0x91, 0xB3, /* 0xD4-0xD7 */ - 0x91, 0xB4, 0x91, 0xB5, 0x91, 0xB6, 0x91, 0xB7, /* 0xD8-0xDB */ - 0x91, 0xB8, 0x91, 0xB9, 0x91, 0xBA, 0x91, 0xBB, /* 0xDC-0xDF */ - 0x91, 0xBC, 0x91, 0xBD, 0x91, 0xBE, 0x91, 0xBF, /* 0xE0-0xE3 */ - 0x91, 0xC0, 0x91, 0xC1, 0xC5, 0xB3, 0x91, 0xC2, /* 0xE4-0xE7 */ - 0x91, 0xC3, 0x91, 0xC4, 0x91, 0xC5, 0x91, 0xC6, /* 0xE8-0xEB */ - 0x91, 0xC7, 0x91, 0xC8, 0x91, 0xC9, 0x91, 0xCA, /* 0xEC-0xEF */ - 0x91, 0xCB, 0x91, 0xCC, 0x91, 0xCD, 0x91, 0xCE, /* 0xF0-0xF3 */ - 0x91, 0xCF, 0xE3, 0xC2, 0x91, 0xD0, 0x91, 0xD1, /* 0xF4-0xF7 */ - 0x91, 0xD2, 0x91, 0xD3, 0x91, 0xD4, 0x91, 0xD5, /* 0xF8-0xFB */ - 0x91, 0xD6, 0x91, 0xD7, 0x91, 0xD8, 0xDC, 0xB2, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_62[512] = { - 0x91, 0xD9, 0x91, 0xDA, 0x91, 0xDB, 0x91, 0xDC, /* 0x00-0x03 */ - 0x91, 0xDD, 0x91, 0xDE, 0xED, 0xB0, 0x91, 0xDF, /* 0x04-0x07 */ - 0xB8, 0xEA, 0x91, 0xE0, 0xCE, 0xEC, 0xEA, 0xA7, /* 0x08-0x0B */ - 0xD0, 0xE7, 0xCA, 0xF9, 0xC8, 0xD6, 0xCF, 0xB7, /* 0x0C-0x0F */ - 0xB3, 0xC9, 0xCE, 0xD2, 0xBD, 0xE4, 0x91, 0xE1, /* 0x10-0x13 */ - 0x91, 0xE2, 0xE3, 0xDE, 0xBB, 0xF2, 0xEA, 0xA8, /* 0x14-0x17 */ - 0xD5, 0xBD, 0x91, 0xE3, 0xC6, 0xDD, 0xEA, 0xA9, /* 0x18-0x1B */ - 0x91, 0xE4, 0x91, 0xE5, 0x91, 0xE6, 0xEA, 0xAA, /* 0x1C-0x1F */ - 0x91, 0xE7, 0xEA, 0xAC, 0xEA, 0xAB, 0x91, 0xE8, /* 0x20-0x23 */ - 0xEA, 0xAE, 0xEA, 0xAD, 0x91, 0xE9, 0x91, 0xEA, /* 0x24-0x27 */ - 0x91, 0xEB, 0x91, 0xEC, 0xBD, 0xD8, 0x91, 0xED, /* 0x28-0x2B */ - 0xEA, 0xAF, 0x91, 0xEE, 0xC2, 0xBE, 0x91, 0xEF, /* 0x2C-0x2F */ - 0x91, 0xF0, 0x91, 0xF1, 0x91, 0xF2, 0xB4, 0xC1, /* 0x30-0x33 */ - 0xB4, 0xF7, 0x91, 0xF3, 0x91, 0xF4, 0xBB, 0xA7, /* 0x34-0x37 */ - 0x91, 0xF5, 0x91, 0xF6, 0x91, 0xF7, 0x91, 0xF8, /* 0x38-0x3B */ - 0x91, 0xF9, 0xEC, 0xE6, 0xEC, 0xE5, 0xB7, 0xBF, /* 0x3C-0x3F */ - 0xCB, 0xF9, 0xB1, 0xE2, 0x91, 0xFA, 0xEC, 0xE7, /* 0x40-0x43 */ - 0x91, 0xFB, 0x91, 0xFC, 0x91, 0xFD, 0xC9, 0xC8, /* 0x44-0x47 */ - 0xEC, 0xE8, 0xEC, 0xE9, 0x91, 0xFE, 0xCA, 0xD6, /* 0x48-0x4B */ - 0xDE, 0xD0, 0xB2, 0xC5, 0xD4, 0xFA, 0x92, 0x40, /* 0x4C-0x4F */ - 0x92, 0x41, 0xC6, 0xCB, 0xB0, 0xC7, 0xB4, 0xF2, /* 0x50-0x53 */ - 0xC8, 0xD3, 0x92, 0x42, 0x92, 0x43, 0x92, 0x44, /* 0x54-0x57 */ - 0xCD, 0xD0, 0x92, 0x45, 0x92, 0x46, 0xBF, 0xB8, /* 0x58-0x5B */ - 0x92, 0x47, 0x92, 0x48, 0x92, 0x49, 0x92, 0x4A, /* 0x5C-0x5F */ - 0x92, 0x4B, 0x92, 0x4C, 0x92, 0x4D, 0xBF, 0xDB, /* 0x60-0x63 */ - 0x92, 0x4E, 0x92, 0x4F, 0xC7, 0xA4, 0xD6, 0xB4, /* 0x64-0x67 */ - 0x92, 0x50, 0xC0, 0xA9, 0xDE, 0xD1, 0xC9, 0xA8, /* 0x68-0x6B */ - 0xD1, 0xEF, 0xC5, 0xA4, 0xB0, 0xE7, 0xB3, 0xB6, /* 0x6C-0x6F */ - 0xC8, 0xC5, 0x92, 0x51, 0x92, 0x52, 0xB0, 0xE2, /* 0x70-0x73 */ - 0x92, 0x53, 0x92, 0x54, 0xB7, 0xF6, 0x92, 0x55, /* 0x74-0x77 */ - 0x92, 0x56, 0xC5, 0xFA, 0x92, 0x57, 0x92, 0x58, /* 0x78-0x7B */ - 0xB6, 0xF3, 0x92, 0x59, 0xD5, 0xD2, 0xB3, 0xD0, /* 0x7C-0x7F */ - - 0xBC, 0xBC, 0x92, 0x5A, 0x92, 0x5B, 0x92, 0x5C, /* 0x80-0x83 */ - 0xB3, 0xAD, 0x92, 0x5D, 0x92, 0x5E, 0x92, 0x5F, /* 0x84-0x87 */ - 0x92, 0x60, 0xBE, 0xF1, 0xB0, 0xD1, 0x92, 0x61, /* 0x88-0x8B */ - 0x92, 0x62, 0x92, 0x63, 0x92, 0x64, 0x92, 0x65, /* 0x8C-0x8F */ - 0x92, 0x66, 0xD2, 0xD6, 0xCA, 0xE3, 0xD7, 0xA5, /* 0x90-0x93 */ - 0x92, 0x67, 0xCD, 0xB6, 0xB6, 0xB6, 0xBF, 0xB9, /* 0x94-0x97 */ - 0xD5, 0xDB, 0x92, 0x68, 0xB8, 0xA7, 0xC5, 0xD7, /* 0x98-0x9B */ - 0x92, 0x69, 0x92, 0x6A, 0x92, 0x6B, 0xDE, 0xD2, /* 0x9C-0x9F */ - 0xBF, 0xD9, 0xC2, 0xD5, 0xC7, 0xC0, 0x92, 0x6C, /* 0xA0-0xA3 */ - 0xBB, 0xA4, 0xB1, 0xA8, 0x92, 0x6D, 0x92, 0x6E, /* 0xA4-0xA7 */ - 0xC5, 0xEA, 0x92, 0x6F, 0x92, 0x70, 0xC5, 0xFB, /* 0xA8-0xAB */ - 0xCC, 0xA7, 0x92, 0x71, 0x92, 0x72, 0x92, 0x73, /* 0xAC-0xAF */ - 0x92, 0x74, 0xB1, 0xA7, 0x92, 0x75, 0x92, 0x76, /* 0xB0-0xB3 */ - 0x92, 0x77, 0xB5, 0xD6, 0x92, 0x78, 0x92, 0x79, /* 0xB4-0xB7 */ - 0x92, 0x7A, 0xC4, 0xA8, 0x92, 0x7B, 0xDE, 0xD3, /* 0xB8-0xBB */ - 0xD1, 0xBA, 0xB3, 0xE9, 0x92, 0x7C, 0xC3, 0xF2, /* 0xBC-0xBF */ - 0x92, 0x7D, 0x92, 0x7E, 0xB7, 0xF7, 0x92, 0x80, /* 0xC0-0xC3 */ - 0xD6, 0xF4, 0xB5, 0xA3, 0xB2, 0xF0, 0xC4, 0xB4, /* 0xC4-0xC7 */ - 0xC4, 0xE9, 0xC0, 0xAD, 0xDE, 0xD4, 0x92, 0x81, /* 0xC8-0xCB */ - 0xB0, 0xE8, 0xC5, 0xC4, 0xC1, 0xE0, 0x92, 0x82, /* 0xCC-0xCF */ - 0xB9, 0xD5, 0x92, 0x83, 0xBE, 0xDC, 0xCD, 0xD8, /* 0xD0-0xD3 */ - 0xB0, 0xCE, 0x92, 0x84, 0xCD, 0xCF, 0xDE, 0xD6, /* 0xD4-0xD7 */ - 0xBE, 0xD0, 0xD7, 0xBE, 0xDE, 0xD5, 0xD5, 0xD0, /* 0xD8-0xDB */ - 0xB0, 0xDD, 0x92, 0x85, 0x92, 0x86, 0xC4, 0xE2, /* 0xDC-0xDF */ - 0x92, 0x87, 0x92, 0x88, 0xC2, 0xA3, 0xBC, 0xF0, /* 0xE0-0xE3 */ - 0x92, 0x89, 0xD3, 0xB5, 0xC0, 0xB9, 0xC5, 0xA1, /* 0xE4-0xE7 */ - 0xB2, 0xA6, 0xD4, 0xF1, 0x92, 0x8A, 0x92, 0x8B, /* 0xE8-0xEB */ - 0xC0, 0xA8, 0xCA, 0xC3, 0xDE, 0xD7, 0xD5, 0xFC, /* 0xEC-0xEF */ - 0x92, 0x8C, 0xB9, 0xB0, 0x92, 0x8D, 0xC8, 0xAD, /* 0xF0-0xF3 */ - 0xCB, 0xA9, 0x92, 0x8E, 0xDE, 0xD9, 0xBF, 0xBD, /* 0xF4-0xF7 */ - 0x92, 0x8F, 0x92, 0x90, 0x92, 0x91, 0x92, 0x92, /* 0xF8-0xFB */ - 0xC6, 0xB4, 0xD7, 0xA7, 0xCA, 0xB0, 0xC4, 0xC3, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_63[512] = { - 0x92, 0x93, 0xB3, 0xD6, 0xB9, 0xD2, 0x92, 0x94, /* 0x00-0x03 */ - 0x92, 0x95, 0x92, 0x96, 0x92, 0x97, 0xD6, 0xB8, /* 0x04-0x07 */ - 0xEA, 0xFC, 0xB0, 0xB4, 0x92, 0x98, 0x92, 0x99, /* 0x08-0x0B */ - 0x92, 0x9A, 0x92, 0x9B, 0xBF, 0xE6, 0x92, 0x9C, /* 0x0C-0x0F */ - 0x92, 0x9D, 0xCC, 0xF4, 0x92, 0x9E, 0x92, 0x9F, /* 0x10-0x13 */ - 0x92, 0xA0, 0x92, 0xA1, 0xCD, 0xDA, 0x92, 0xA2, /* 0x14-0x17 */ - 0x92, 0xA3, 0x92, 0xA4, 0xD6, 0xBF, 0xC2, 0xCE, /* 0x18-0x1B */ - 0x92, 0xA5, 0xCE, 0xCE, 0xCC, 0xA2, 0xD0, 0xAE, /* 0x1C-0x1F */ - 0xC4, 0xD3, 0xB5, 0xB2, 0xDE, 0xD8, 0xD5, 0xF5, /* 0x20-0x23 */ - 0xBC, 0xB7, 0xBB, 0xD3, 0x92, 0xA6, 0x92, 0xA7, /* 0x24-0x27 */ - 0xB0, 0xA4, 0x92, 0xA8, 0xC5, 0xB2, 0xB4, 0xEC, /* 0x28-0x2B */ - 0x92, 0xA9, 0x92, 0xAA, 0x92, 0xAB, 0xD5, 0xF1, /* 0x2C-0x2F */ - 0x92, 0xAC, 0x92, 0xAD, 0xEA, 0xFD, 0x92, 0xAE, /* 0x30-0x33 */ - 0x92, 0xAF, 0x92, 0xB0, 0x92, 0xB1, 0x92, 0xB2, /* 0x34-0x37 */ - 0x92, 0xB3, 0xDE, 0xDA, 0xCD, 0xA6, 0x92, 0xB4, /* 0x38-0x3B */ - 0x92, 0xB5, 0xCD, 0xEC, 0x92, 0xB6, 0x92, 0xB7, /* 0x3C-0x3F */ - 0x92, 0xB8, 0x92, 0xB9, 0xCE, 0xE6, 0xDE, 0xDC, /* 0x40-0x43 */ - 0x92, 0xBA, 0xCD, 0xB1, 0xC0, 0xA6, 0x92, 0xBB, /* 0x44-0x47 */ - 0x92, 0xBC, 0xD7, 0xBD, 0x92, 0xBD, 0xDE, 0xDB, /* 0x48-0x4B */ - 0xB0, 0xC6, 0xBA, 0xB4, 0xC9, 0xD3, 0xC4, 0xF3, /* 0x4C-0x4F */ - 0xBE, 0xE8, 0x92, 0xBE, 0x92, 0xBF, 0x92, 0xC0, /* 0x50-0x53 */ - 0x92, 0xC1, 0xB2, 0xB6, 0x92, 0xC2, 0x92, 0xC3, /* 0x54-0x57 */ - 0x92, 0xC4, 0x92, 0xC5, 0x92, 0xC6, 0x92, 0xC7, /* 0x58-0x5B */ - 0x92, 0xC8, 0x92, 0xC9, 0xC0, 0xCC, 0xCB, 0xF0, /* 0x5C-0x5F */ - 0x92, 0xCA, 0xBC, 0xF1, 0xBB, 0xBB, 0xB5, 0xB7, /* 0x60-0x63 */ - 0x92, 0xCB, 0x92, 0xCC, 0x92, 0xCD, 0xC5, 0xF5, /* 0x64-0x67 */ - 0x92, 0xCE, 0xDE, 0xE6, 0x92, 0xCF, 0x92, 0xD0, /* 0x68-0x6B */ - 0x92, 0xD1, 0xDE, 0xE3, 0xBE, 0xDD, 0x92, 0xD2, /* 0x6C-0x6F */ - 0x92, 0xD3, 0xDE, 0xDF, 0x92, 0xD4, 0x92, 0xD5, /* 0x70-0x73 */ - 0x92, 0xD6, 0x92, 0xD7, 0xB4, 0xB7, 0xBD, 0xDD, /* 0x74-0x77 */ - 0x92, 0xD8, 0x92, 0xD9, 0xDE, 0xE0, 0xC4, 0xED, /* 0x78-0x7B */ - 0x92, 0xDA, 0x92, 0xDB, 0x92, 0xDC, 0x92, 0xDD, /* 0x7C-0x7F */ - - 0xCF, 0xC6, 0x92, 0xDE, 0xB5, 0xE0, 0x92, 0xDF, /* 0x80-0x83 */ - 0x92, 0xE0, 0x92, 0xE1, 0x92, 0xE2, 0xB6, 0xDE, /* 0x84-0x87 */ - 0xCA, 0xDA, 0xB5, 0xF4, 0xDE, 0xE5, 0x92, 0xE3, /* 0x88-0x8B */ - 0xD5, 0xC6, 0x92, 0xE4, 0xDE, 0xE1, 0xCC, 0xCD, /* 0x8C-0x8F */ - 0xC6, 0xFE, 0x92, 0xE5, 0xC5, 0xC5, 0x92, 0xE6, /* 0x90-0x93 */ - 0x92, 0xE7, 0x92, 0xE8, 0xD2, 0xB4, 0x92, 0xE9, /* 0x94-0x97 */ - 0xBE, 0xF2, 0x92, 0xEA, 0x92, 0xEB, 0x92, 0xEC, /* 0x98-0x9B */ - 0x92, 0xED, 0x92, 0xEE, 0x92, 0xEF, 0x92, 0xF0, /* 0x9C-0x9F */ - 0xC2, 0xD3, 0x92, 0xF1, 0xCC, 0xBD, 0xB3, 0xB8, /* 0xA0-0xA3 */ - 0x92, 0xF2, 0xBD, 0xD3, 0x92, 0xF3, 0xBF, 0xD8, /* 0xA4-0xA7 */ - 0xCD, 0xC6, 0xD1, 0xDA, 0xB4, 0xEB, 0x92, 0xF4, /* 0xA8-0xAB */ - 0xDE, 0xE4, 0xDE, 0xDD, 0xDE, 0xE7, 0x92, 0xF5, /* 0xAC-0xAF */ - 0xEA, 0xFE, 0x92, 0xF6, 0x92, 0xF7, 0xC2, 0xB0, /* 0xB0-0xB3 */ - 0xDE, 0xE2, 0x92, 0xF8, 0x92, 0xF9, 0xD6, 0xC0, /* 0xB4-0xB7 */ - 0xB5, 0xA7, 0x92, 0xFA, 0xB2, 0xF4, 0x92, 0xFB, /* 0xB8-0xBB */ - 0xDE, 0xE8, 0x92, 0xFC, 0xDE, 0xF2, 0x92, 0xFD, /* 0xBC-0xBF */ - 0x92, 0xFE, 0x93, 0x40, 0x93, 0x41, 0x93, 0x42, /* 0xC0-0xC3 */ - 0xDE, 0xED, 0x93, 0x43, 0xDE, 0xF1, 0x93, 0x44, /* 0xC4-0xC7 */ - 0x93, 0x45, 0xC8, 0xE0, 0x93, 0x46, 0x93, 0x47, /* 0xC8-0xCB */ - 0x93, 0x48, 0xD7, 0xE1, 0xDE, 0xEF, 0xC3, 0xE8, /* 0xCC-0xCF */ - 0xCC, 0xE1, 0x93, 0x49, 0xB2, 0xE5, 0x93, 0x4A, /* 0xD0-0xD3 */ - 0x93, 0x4B, 0x93, 0x4C, 0xD2, 0xBE, 0x93, 0x4D, /* 0xD4-0xD7 */ - 0x93, 0x4E, 0x93, 0x4F, 0x93, 0x50, 0x93, 0x51, /* 0xD8-0xDB */ - 0x93, 0x52, 0x93, 0x53, 0xDE, 0xEE, 0x93, 0x54, /* 0xDC-0xDF */ - 0xDE, 0xEB, 0xCE, 0xD5, 0x93, 0x55, 0xB4, 0xA7, /* 0xE0-0xE3 */ - 0x93, 0x56, 0x93, 0x57, 0x93, 0x58, 0x93, 0x59, /* 0xE4-0xE7 */ - 0x93, 0x5A, 0xBF, 0xAB, 0xBE, 0xBE, 0x93, 0x5B, /* 0xE8-0xEB */ - 0x93, 0x5C, 0xBD, 0xD2, 0x93, 0x5D, 0x93, 0x5E, /* 0xEC-0xEF */ - 0x93, 0x5F, 0x93, 0x60, 0xDE, 0xE9, 0x93, 0x61, /* 0xF0-0xF3 */ - 0xD4, 0xAE, 0x93, 0x62, 0xDE, 0xDE, 0x93, 0x63, /* 0xF4-0xF7 */ - 0xDE, 0xEA, 0x93, 0x64, 0x93, 0x65, 0x93, 0x66, /* 0xF8-0xFB */ - 0x93, 0x67, 0xC0, 0xBF, 0x93, 0x68, 0xDE, 0xEC, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_64[512] = { - 0xB2, 0xF3, 0xB8, 0xE9, 0xC2, 0xA7, 0x93, 0x69, /* 0x00-0x03 */ - 0x93, 0x6A, 0xBD, 0xC1, 0x93, 0x6B, 0x93, 0x6C, /* 0x04-0x07 */ - 0x93, 0x6D, 0x93, 0x6E, 0x93, 0x6F, 0xDE, 0xF5, /* 0x08-0x0B */ - 0xDE, 0xF8, 0x93, 0x70, 0x93, 0x71, 0xB2, 0xAB, /* 0x0C-0x0F */ - 0xB4, 0xA4, 0x93, 0x72, 0x93, 0x73, 0xB4, 0xEA, /* 0x10-0x13 */ - 0xC9, 0xA6, 0x93, 0x74, 0x93, 0x75, 0x93, 0x76, /* 0x14-0x17 */ - 0x93, 0x77, 0x93, 0x78, 0x93, 0x79, 0xDE, 0xF6, /* 0x18-0x1B */ - 0xCB, 0xD1, 0x93, 0x7A, 0xB8, 0xE3, 0x93, 0x7B, /* 0x1C-0x1F */ - 0xDE, 0xF7, 0xDE, 0xFA, 0x93, 0x7C, 0x93, 0x7D, /* 0x20-0x23 */ - 0x93, 0x7E, 0x93, 0x80, 0xDE, 0xF9, 0x93, 0x81, /* 0x24-0x27 */ - 0x93, 0x82, 0x93, 0x83, 0xCC, 0xC2, 0x93, 0x84, /* 0x28-0x2B */ - 0xB0, 0xE1, 0xB4, 0xEE, 0x93, 0x85, 0x93, 0x86, /* 0x2C-0x2F */ - 0x93, 0x87, 0x93, 0x88, 0x93, 0x89, 0x93, 0x8A, /* 0x30-0x33 */ - 0xE5, 0xBA, 0x93, 0x8B, 0x93, 0x8C, 0x93, 0x8D, /* 0x34-0x37 */ - 0x93, 0x8E, 0x93, 0x8F, 0xD0, 0xAF, 0x93, 0x90, /* 0x38-0x3B */ - 0x93, 0x91, 0xB2, 0xEB, 0x93, 0x92, 0xEB, 0xA1, /* 0x3C-0x3F */ - 0x93, 0x93, 0xDE, 0xF4, 0x93, 0x94, 0x93, 0x95, /* 0x40-0x43 */ - 0xC9, 0xE3, 0xDE, 0xF3, 0xB0, 0xDA, 0xD2, 0xA1, /* 0x44-0x47 */ - 0xB1, 0xF7, 0x93, 0x96, 0xCC, 0xAF, 0x93, 0x97, /* 0x48-0x4B */ - 0x93, 0x98, 0x93, 0x99, 0x93, 0x9A, 0x93, 0x9B, /* 0x4C-0x4F */ - 0x93, 0x9C, 0x93, 0x9D, 0xDE, 0xF0, 0x93, 0x9E, /* 0x50-0x53 */ - 0xCB, 0xA4, 0x93, 0x9F, 0x93, 0xA0, 0x93, 0xA1, /* 0x54-0x57 */ - 0xD5, 0xAA, 0x93, 0xA2, 0x93, 0xA3, 0x93, 0xA4, /* 0x58-0x5B */ - 0x93, 0xA5, 0x93, 0xA6, 0xDE, 0xFB, 0x93, 0xA7, /* 0x5C-0x5F */ - 0x93, 0xA8, 0x93, 0xA9, 0x93, 0xAA, 0x93, 0xAB, /* 0x60-0x63 */ - 0x93, 0xAC, 0x93, 0xAD, 0x93, 0xAE, 0xB4, 0xDD, /* 0x64-0x67 */ - 0x93, 0xAF, 0xC4, 0xA6, 0x93, 0xB0, 0x93, 0xB1, /* 0x68-0x6B */ - 0x93, 0xB2, 0xDE, 0xFD, 0x93, 0xB3, 0x93, 0xB4, /* 0x6C-0x6F */ - 0x93, 0xB5, 0x93, 0xB6, 0x93, 0xB7, 0x93, 0xB8, /* 0x70-0x73 */ - 0x93, 0xB9, 0x93, 0xBA, 0x93, 0xBB, 0x93, 0xBC, /* 0x74-0x77 */ - 0xC3, 0xFE, 0xC4, 0xA1, 0xDF, 0xA1, 0x93, 0xBD, /* 0x78-0x7B */ - 0x93, 0xBE, 0x93, 0xBF, 0x93, 0xC0, 0x93, 0xC1, /* 0x7C-0x7F */ - - 0x93, 0xC2, 0x93, 0xC3, 0xC1, 0xCC, 0x93, 0xC4, /* 0x80-0x83 */ - 0xDE, 0xFC, 0xBE, 0xEF, 0x93, 0xC5, 0xC6, 0xB2, /* 0x84-0x87 */ - 0x93, 0xC6, 0x93, 0xC7, 0x93, 0xC8, 0x93, 0xC9, /* 0x88-0x8B */ - 0x93, 0xCA, 0x93, 0xCB, 0x93, 0xCC, 0x93, 0xCD, /* 0x8C-0x8F */ - 0x93, 0xCE, 0xB3, 0xC5, 0xC8, 0xF6, 0x93, 0xCF, /* 0x90-0x93 */ - 0x93, 0xD0, 0xCB, 0xBA, 0xDE, 0xFE, 0x93, 0xD1, /* 0x94-0x97 */ - 0x93, 0xD2, 0xDF, 0xA4, 0x93, 0xD3, 0x93, 0xD4, /* 0x98-0x9B */ - 0x93, 0xD5, 0x93, 0xD6, 0xD7, 0xB2, 0x93, 0xD7, /* 0x9C-0x9F */ - 0x93, 0xD8, 0x93, 0xD9, 0x93, 0xDA, 0x93, 0xDB, /* 0xA0-0xA3 */ - 0xB3, 0xB7, 0x93, 0xDC, 0x93, 0xDD, 0x93, 0xDE, /* 0xA4-0xA7 */ - 0x93, 0xDF, 0xC1, 0xC3, 0x93, 0xE0, 0x93, 0xE1, /* 0xA8-0xAB */ - 0xC7, 0xCB, 0xB2, 0xA5, 0xB4, 0xE9, 0x93, 0xE2, /* 0xAC-0xAF */ - 0xD7, 0xAB, 0x93, 0xE3, 0x93, 0xE4, 0x93, 0xE5, /* 0xB0-0xB3 */ - 0x93, 0xE6, 0xC4, 0xEC, 0x93, 0xE7, 0xDF, 0xA2, /* 0xB4-0xB7 */ - 0xDF, 0xA3, 0x93, 0xE8, 0xDF, 0xA5, 0x93, 0xE9, /* 0xB8-0xBB */ - 0xBA, 0xB3, 0x93, 0xEA, 0x93, 0xEB, 0x93, 0xEC, /* 0xBC-0xBF */ - 0xDF, 0xA6, 0x93, 0xED, 0xC0, 0xDE, 0x93, 0xEE, /* 0xC0-0xC3 */ - 0x93, 0xEF, 0xC9, 0xC3, 0x93, 0xF0, 0x93, 0xF1, /* 0xC4-0xC7 */ - 0x93, 0xF2, 0x93, 0xF3, 0x93, 0xF4, 0x93, 0xF5, /* 0xC8-0xCB */ - 0x93, 0xF6, 0xB2, 0xD9, 0xC7, 0xE6, 0x93, 0xF7, /* 0xCC-0xCF */ - 0xDF, 0xA7, 0x93, 0xF8, 0xC7, 0xDC, 0x93, 0xF9, /* 0xD0-0xD3 */ - 0x93, 0xFA, 0x93, 0xFB, 0x93, 0xFC, 0xDF, 0xA8, /* 0xD4-0xD7 */ - 0xEB, 0xA2, 0x93, 0xFD, 0x93, 0xFE, 0x94, 0x40, /* 0xD8-0xDB */ - 0x94, 0x41, 0x94, 0x42, 0xCB, 0xD3, 0x94, 0x43, /* 0xDC-0xDF */ - 0x94, 0x44, 0x94, 0x45, 0xDF, 0xAA, 0x94, 0x46, /* 0xE0-0xE3 */ - 0xDF, 0xA9, 0x94, 0x47, 0xB2, 0xC1, 0x94, 0x48, /* 0xE4-0xE7 */ - 0x94, 0x49, 0x94, 0x4A, 0x94, 0x4B, 0x94, 0x4C, /* 0xE8-0xEB */ - 0x94, 0x4D, 0x94, 0x4E, 0x94, 0x4F, 0x94, 0x50, /* 0xEC-0xEF */ - 0x94, 0x51, 0x94, 0x52, 0x94, 0x53, 0x94, 0x54, /* 0xF0-0xF3 */ - 0x94, 0x55, 0x94, 0x56, 0x94, 0x57, 0x94, 0x58, /* 0xF4-0xF7 */ - 0x94, 0x59, 0x94, 0x5A, 0x94, 0x5B, 0x94, 0x5C, /* 0xF8-0xFB */ - 0x94, 0x5D, 0x94, 0x5E, 0x94, 0x5F, 0x94, 0x60, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_65[512] = { - 0xC5, 0xCA, 0x94, 0x61, 0x94, 0x62, 0x94, 0x63, /* 0x00-0x03 */ - 0x94, 0x64, 0x94, 0x65, 0x94, 0x66, 0x94, 0x67, /* 0x04-0x07 */ - 0x94, 0x68, 0xDF, 0xAB, 0x94, 0x69, 0x94, 0x6A, /* 0x08-0x0B */ - 0x94, 0x6B, 0x94, 0x6C, 0x94, 0x6D, 0x94, 0x6E, /* 0x0C-0x0F */ - 0x94, 0x6F, 0x94, 0x70, 0xD4, 0xDC, 0x94, 0x71, /* 0x10-0x13 */ - 0x94, 0x72, 0x94, 0x73, 0x94, 0x74, 0x94, 0x75, /* 0x14-0x17 */ - 0xC8, 0xC1, 0x94, 0x76, 0x94, 0x77, 0x94, 0x78, /* 0x18-0x1B */ - 0x94, 0x79, 0x94, 0x7A, 0x94, 0x7B, 0x94, 0x7C, /* 0x1C-0x1F */ - 0x94, 0x7D, 0x94, 0x7E, 0x94, 0x80, 0x94, 0x81, /* 0x20-0x23 */ - 0x94, 0x82, 0xDF, 0xAC, 0x94, 0x83, 0x94, 0x84, /* 0x24-0x27 */ - 0x94, 0x85, 0x94, 0x86, 0x94, 0x87, 0xBE, 0xF0, /* 0x28-0x2B */ - 0x94, 0x88, 0x94, 0x89, 0xDF, 0xAD, 0xD6, 0xA7, /* 0x2C-0x2F */ - 0x94, 0x8A, 0x94, 0x8B, 0x94, 0x8C, 0x94, 0x8D, /* 0x30-0x33 */ - 0xEA, 0xB7, 0xEB, 0xB6, 0xCA, 0xD5, 0x94, 0x8E, /* 0x34-0x37 */ - 0xD8, 0xFC, 0xB8, 0xC4, 0x94, 0x8F, 0xB9, 0xA5, /* 0x38-0x3B */ - 0x94, 0x90, 0x94, 0x91, 0xB7, 0xC5, 0xD5, 0xFE, /* 0x3C-0x3F */ - 0x94, 0x92, 0x94, 0x93, 0x94, 0x94, 0x94, 0x95, /* 0x40-0x43 */ - 0x94, 0x96, 0xB9, 0xCA, 0x94, 0x97, 0x94, 0x98, /* 0x44-0x47 */ - 0xD0, 0xA7, 0xF4, 0xCD, 0x94, 0x99, 0x94, 0x9A, /* 0x48-0x4B */ - 0xB5, 0xD0, 0x94, 0x9B, 0x94, 0x9C, 0xC3, 0xF4, /* 0x4C-0x4F */ - 0x94, 0x9D, 0xBE, 0xC8, 0x94, 0x9E, 0x94, 0x9F, /* 0x50-0x53 */ - 0x94, 0xA0, 0xEB, 0xB7, 0xB0, 0xBD, 0x94, 0xA1, /* 0x54-0x57 */ - 0x94, 0xA2, 0xBD, 0xCC, 0x94, 0xA3, 0xC1, 0xB2, /* 0x58-0x5B */ - 0x94, 0xA4, 0xB1, 0xD6, 0xB3, 0xA8, 0x94, 0xA5, /* 0x5C-0x5F */ - 0x94, 0xA6, 0x94, 0xA7, 0xB8, 0xD2, 0xC9, 0xA2, /* 0x60-0x63 */ - 0x94, 0xA8, 0x94, 0xA9, 0xB6, 0xD8, 0x94, 0xAA, /* 0x64-0x67 */ - 0x94, 0xAB, 0x94, 0xAC, 0x94, 0xAD, 0xEB, 0xB8, /* 0x68-0x6B */ - 0xBE, 0xB4, 0x94, 0xAE, 0x94, 0xAF, 0x94, 0xB0, /* 0x6C-0x6F */ - 0xCA, 0xFD, 0x94, 0xB1, 0xC7, 0xC3, 0x94, 0xB2, /* 0x70-0x73 */ - 0xD5, 0xFB, 0x94, 0xB3, 0x94, 0xB4, 0xB7, 0xF3, /* 0x74-0x77 */ - 0x94, 0xB5, 0x94, 0xB6, 0x94, 0xB7, 0x94, 0xB8, /* 0x78-0x7B */ - 0x94, 0xB9, 0x94, 0xBA, 0x94, 0xBB, 0x94, 0xBC, /* 0x7C-0x7F */ - - 0x94, 0xBD, 0x94, 0xBE, 0x94, 0xBF, 0x94, 0xC0, /* 0x80-0x83 */ - 0x94, 0xC1, 0x94, 0xC2, 0x94, 0xC3, 0xCE, 0xC4, /* 0x84-0x87 */ - 0x94, 0xC4, 0x94, 0xC5, 0x94, 0xC6, 0xD5, 0xAB, /* 0x88-0x8B */ - 0xB1, 0xF3, 0x94, 0xC7, 0x94, 0xC8, 0x94, 0xC9, /* 0x8C-0x8F */ - 0xEC, 0xB3, 0xB0, 0xDF, 0x94, 0xCA, 0xEC, 0xB5, /* 0x90-0x93 */ - 0x94, 0xCB, 0x94, 0xCC, 0x94, 0xCD, 0xB6, 0xB7, /* 0x94-0x97 */ - 0x94, 0xCE, 0xC1, 0xCF, 0x94, 0xCF, 0xF5, 0xFA, /* 0x98-0x9B */ - 0xD0, 0xB1, 0x94, 0xD0, 0x94, 0xD1, 0xD5, 0xE5, /* 0x9C-0x9F */ - 0x94, 0xD2, 0xCE, 0xD3, 0x94, 0xD3, 0x94, 0xD4, /* 0xA0-0xA3 */ - 0xBD, 0xEF, 0xB3, 0xE2, 0x94, 0xD5, 0xB8, 0xAB, /* 0xA4-0xA7 */ - 0x94, 0xD6, 0xD5, 0xB6, 0x94, 0xD7, 0xED, 0xBD, /* 0xA8-0xAB */ - 0x94, 0xD8, 0xB6, 0xCF, 0x94, 0xD9, 0xCB, 0xB9, /* 0xAC-0xAF */ - 0xD0, 0xC2, 0x94, 0xDA, 0x94, 0xDB, 0x94, 0xDC, /* 0xB0-0xB3 */ - 0x94, 0xDD, 0x94, 0xDE, 0x94, 0xDF, 0x94, 0xE0, /* 0xB4-0xB7 */ - 0x94, 0xE1, 0xB7, 0xBD, 0x94, 0xE2, 0x94, 0xE3, /* 0xB8-0xBB */ - 0xEC, 0xB6, 0xCA, 0xA9, 0x94, 0xE4, 0x94, 0xE5, /* 0xBC-0xBF */ - 0x94, 0xE6, 0xC5, 0xD4, 0x94, 0xE7, 0xEC, 0xB9, /* 0xC0-0xC3 */ - 0xEC, 0xB8, 0xC2, 0xC3, 0xEC, 0xB7, 0x94, 0xE8, /* 0xC4-0xC7 */ - 0x94, 0xE9, 0x94, 0xEA, 0x94, 0xEB, 0xD0, 0xFD, /* 0xC8-0xCB */ - 0xEC, 0xBA, 0x94, 0xEC, 0xEC, 0xBB, 0xD7, 0xE5, /* 0xCC-0xCF */ - 0x94, 0xED, 0x94, 0xEE, 0xEC, 0xBC, 0x94, 0xEF, /* 0xD0-0xD3 */ - 0x94, 0xF0, 0x94, 0xF1, 0xEC, 0xBD, 0xC6, 0xEC, /* 0xD4-0xD7 */ - 0x94, 0xF2, 0x94, 0xF3, 0x94, 0xF4, 0x94, 0xF5, /* 0xD8-0xDB */ - 0x94, 0xF6, 0x94, 0xF7, 0x94, 0xF8, 0x94, 0xF9, /* 0xDC-0xDF */ - 0xCE, 0xDE, 0x94, 0xFA, 0xBC, 0xC8, 0x94, 0xFB, /* 0xE0-0xE3 */ - 0x94, 0xFC, 0xC8, 0xD5, 0xB5, 0xA9, 0xBE, 0xC9, /* 0xE4-0xE7 */ - 0xD6, 0xBC, 0xD4, 0xE7, 0x94, 0xFD, 0x94, 0xFE, /* 0xE8-0xEB */ - 0xD1, 0xAE, 0xD0, 0xF1, 0xEA, 0xB8, 0xEA, 0xB9, /* 0xEC-0xEF */ - 0xEA, 0xBA, 0xBA, 0xB5, 0x95, 0x40, 0x95, 0x41, /* 0xF0-0xF3 */ - 0x95, 0x42, 0x95, 0x43, 0xCA, 0xB1, 0xBF, 0xF5, /* 0xF4-0xF7 */ - 0x95, 0x44, 0x95, 0x45, 0xCD, 0xFA, 0x95, 0x46, /* 0xF8-0xFB */ - 0x95, 0x47, 0x95, 0x48, 0x95, 0x49, 0x95, 0x4A, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_66[512] = { - 0xEA, 0xC0, 0x95, 0x4B, 0xB0, 0xBA, 0xEA, 0xBE, /* 0x00-0x03 */ - 0x95, 0x4C, 0x95, 0x4D, 0xC0, 0xA5, 0x95, 0x4E, /* 0x04-0x07 */ - 0x95, 0x4F, 0x95, 0x50, 0xEA, 0xBB, 0x95, 0x51, /* 0x08-0x0B */ - 0xB2, 0xFD, 0x95, 0x52, 0xC3, 0xF7, 0xBB, 0xE8, /* 0x0C-0x0F */ - 0x95, 0x53, 0x95, 0x54, 0x95, 0x55, 0xD2, 0xD7, /* 0x10-0x13 */ - 0xCE, 0xF4, 0xEA, 0xBF, 0x95, 0x56, 0x95, 0x57, /* 0x14-0x17 */ - 0x95, 0x58, 0xEA, 0xBC, 0x95, 0x59, 0x95, 0x5A, /* 0x18-0x1B */ - 0x95, 0x5B, 0xEA, 0xC3, 0x95, 0x5C, 0xD0, 0xC7, /* 0x1C-0x1F */ - 0xD3, 0xB3, 0x95, 0x5D, 0x95, 0x5E, 0x95, 0x5F, /* 0x20-0x23 */ - 0x95, 0x60, 0xB4, 0xBA, 0x95, 0x61, 0xC3, 0xC1, /* 0x24-0x27 */ - 0xD7, 0xF2, 0x95, 0x62, 0x95, 0x63, 0x95, 0x64, /* 0x28-0x2B */ - 0x95, 0x65, 0xD5, 0xD1, 0x95, 0x66, 0xCA, 0xC7, /* 0x2C-0x2F */ - 0x95, 0x67, 0xEA, 0xC5, 0x95, 0x68, 0x95, 0x69, /* 0x30-0x33 */ - 0xEA, 0xC4, 0xEA, 0xC7, 0xEA, 0xC6, 0x95, 0x6A, /* 0x34-0x37 */ - 0x95, 0x6B, 0x95, 0x6C, 0x95, 0x6D, 0x95, 0x6E, /* 0x38-0x3B */ - 0xD6, 0xE7, 0x95, 0x6F, 0xCF, 0xD4, 0x95, 0x70, /* 0x3C-0x3F */ - 0x95, 0x71, 0xEA, 0xCB, 0x95, 0x72, 0xBB, 0xCE, /* 0x40-0x43 */ - 0x95, 0x73, 0x95, 0x74, 0x95, 0x75, 0x95, 0x76, /* 0x44-0x47 */ - 0x95, 0x77, 0x95, 0x78, 0x95, 0x79, 0xBD, 0xFA, /* 0x48-0x4B */ - 0xC9, 0xCE, 0x95, 0x7A, 0x95, 0x7B, 0xEA, 0xCC, /* 0x4C-0x4F */ - 0x95, 0x7C, 0x95, 0x7D, 0xC9, 0xB9, 0xCF, 0xFE, /* 0x50-0x53 */ - 0xEA, 0xCA, 0xD4, 0xCE, 0xEA, 0xCD, 0xEA, 0xCF, /* 0x54-0x57 */ - 0x95, 0x7E, 0x95, 0x80, 0xCD, 0xED, 0x95, 0x81, /* 0x58-0x5B */ - 0x95, 0x82, 0x95, 0x83, 0x95, 0x84, 0xEA, 0xC9, /* 0x5C-0x5F */ - 0x95, 0x85, 0xEA, 0xCE, 0x95, 0x86, 0x95, 0x87, /* 0x60-0x63 */ - 0xCE, 0xEE, 0x95, 0x88, 0xBB, 0xDE, 0x95, 0x89, /* 0x64-0x67 */ - 0xB3, 0xBF, 0x95, 0x8A, 0x95, 0x8B, 0x95, 0x8C, /* 0x68-0x6B */ - 0x95, 0x8D, 0x95, 0x8E, 0xC6, 0xD5, 0xBE, 0xB0, /* 0x6C-0x6F */ - 0xCE, 0xFA, 0x95, 0x8F, 0x95, 0x90, 0x95, 0x91, /* 0x70-0x73 */ - 0xC7, 0xE7, 0x95, 0x92, 0xBE, 0xA7, 0xEA, 0xD0, /* 0x74-0x77 */ - 0x95, 0x93, 0x95, 0x94, 0xD6, 0xC7, 0x95, 0x95, /* 0x78-0x7B */ - 0x95, 0x96, 0x95, 0x97, 0xC1, 0xC0, 0x95, 0x98, /* 0x7C-0x7F */ - - 0x95, 0x99, 0x95, 0x9A, 0xD4, 0xDD, 0x95, 0x9B, /* 0x80-0x83 */ - 0xEA, 0xD1, 0x95, 0x9C, 0x95, 0x9D, 0xCF, 0xBE, /* 0x84-0x87 */ - 0x95, 0x9E, 0x95, 0x9F, 0x95, 0xA0, 0x95, 0xA1, /* 0x88-0x8B */ - 0xEA, 0xD2, 0x95, 0xA2, 0x95, 0xA3, 0x95, 0xA4, /* 0x8C-0x8F */ - 0x95, 0xA5, 0xCA, 0xEE, 0x95, 0xA6, 0x95, 0xA7, /* 0x90-0x93 */ - 0x95, 0xA8, 0x95, 0xA9, 0xC5, 0xAF, 0xB0, 0xB5, /* 0x94-0x97 */ - 0x95, 0xAA, 0x95, 0xAB, 0x95, 0xAC, 0x95, 0xAD, /* 0x98-0x9B */ - 0x95, 0xAE, 0xEA, 0xD4, 0x95, 0xAF, 0x95, 0xB0, /* 0x9C-0x9F */ - 0x95, 0xB1, 0x95, 0xB2, 0x95, 0xB3, 0x95, 0xB4, /* 0xA0-0xA3 */ - 0x95, 0xB5, 0x95, 0xB6, 0x95, 0xB7, 0xEA, 0xD3, /* 0xA4-0xA7 */ - 0xF4, 0xDF, 0x95, 0xB8, 0x95, 0xB9, 0x95, 0xBA, /* 0xA8-0xAB */ - 0x95, 0xBB, 0x95, 0xBC, 0xC4, 0xBA, 0x95, 0xBD, /* 0xAC-0xAF */ - 0x95, 0xBE, 0x95, 0xBF, 0x95, 0xC0, 0x95, 0xC1, /* 0xB0-0xB3 */ - 0xB1, 0xA9, 0x95, 0xC2, 0x95, 0xC3, 0x95, 0xC4, /* 0xB4-0xB7 */ - 0x95, 0xC5, 0xE5, 0xDF, 0x95, 0xC6, 0x95, 0xC7, /* 0xB8-0xBB */ - 0x95, 0xC8, 0x95, 0xC9, 0xEA, 0xD5, 0x95, 0xCA, /* 0xBC-0xBF */ - 0x95, 0xCB, 0x95, 0xCC, 0x95, 0xCD, 0x95, 0xCE, /* 0xC0-0xC3 */ - 0x95, 0xCF, 0x95, 0xD0, 0x95, 0xD1, 0x95, 0xD2, /* 0xC4-0xC7 */ - 0x95, 0xD3, 0x95, 0xD4, 0x95, 0xD5, 0x95, 0xD6, /* 0xC8-0xCB */ - 0x95, 0xD7, 0x95, 0xD8, 0x95, 0xD9, 0x95, 0xDA, /* 0xCC-0xCF */ - 0x95, 0xDB, 0x95, 0xDC, 0x95, 0xDD, 0x95, 0xDE, /* 0xD0-0xD3 */ - 0x95, 0xDF, 0x95, 0xE0, 0x95, 0xE1, 0x95, 0xE2, /* 0xD4-0xD7 */ - 0x95, 0xE3, 0xCA, 0xEF, 0x95, 0xE4, 0xEA, 0xD6, /* 0xD8-0xDB */ - 0xEA, 0xD7, 0xC6, 0xD8, 0x95, 0xE5, 0x95, 0xE6, /* 0xDC-0xDF */ - 0x95, 0xE7, 0x95, 0xE8, 0x95, 0xE9, 0x95, 0xEA, /* 0xE0-0xE3 */ - 0x95, 0xEB, 0x95, 0xEC, 0xEA, 0xD8, 0x95, 0xED, /* 0xE4-0xE7 */ - 0x95, 0xEE, 0xEA, 0xD9, 0x95, 0xEF, 0x95, 0xF0, /* 0xE8-0xEB */ - 0x95, 0xF1, 0x95, 0xF2, 0x95, 0xF3, 0x95, 0xF4, /* 0xEC-0xEF */ - 0xD4, 0xBB, 0x95, 0xF5, 0xC7, 0xFA, 0xD2, 0xB7, /* 0xF0-0xF3 */ - 0xB8, 0xFC, 0x95, 0xF6, 0x95, 0xF7, 0xEA, 0xC2, /* 0xF4-0xF7 */ - 0x95, 0xF8, 0xB2, 0xDC, 0x95, 0xF9, 0x95, 0xFA, /* 0xF8-0xFB */ - 0xC2, 0xFC, 0x95, 0xFB, 0xD4, 0xF8, 0xCC, 0xE6, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_67[512] = { - 0xD7, 0xEE, 0x95, 0xFC, 0x95, 0xFD, 0x95, 0xFE, /* 0x00-0x03 */ - 0x96, 0x40, 0x96, 0x41, 0x96, 0x42, 0x96, 0x43, /* 0x04-0x07 */ - 0xD4, 0xC2, 0xD3, 0xD0, 0xEB, 0xC3, 0xC5, 0xF3, /* 0x08-0x0B */ - 0x96, 0x44, 0xB7, 0xFE, 0x96, 0x45, 0x96, 0x46, /* 0x0C-0x0F */ - 0xEB, 0xD4, 0x96, 0x47, 0x96, 0x48, 0x96, 0x49, /* 0x10-0x13 */ - 0xCB, 0xB7, 0xEB, 0xDE, 0x96, 0x4A, 0xC0, 0xCA, /* 0x14-0x17 */ - 0x96, 0x4B, 0x96, 0x4C, 0x96, 0x4D, 0xCD, 0xFB, /* 0x18-0x1B */ - 0x96, 0x4E, 0xB3, 0xAF, 0x96, 0x4F, 0xC6, 0xDA, /* 0x1C-0x1F */ - 0x96, 0x50, 0x96, 0x51, 0x96, 0x52, 0x96, 0x53, /* 0x20-0x23 */ - 0x96, 0x54, 0x96, 0x55, 0xEB, 0xFC, 0x96, 0x56, /* 0x24-0x27 */ - 0xC4, 0xBE, 0x96, 0x57, 0xCE, 0xB4, 0xC4, 0xA9, /* 0x28-0x2B */ - 0xB1, 0xBE, 0xD4, 0xFD, 0x96, 0x58, 0xCA, 0xF5, /* 0x2C-0x2F */ - 0x96, 0x59, 0xD6, 0xEC, 0x96, 0x5A, 0x96, 0x5B, /* 0x30-0x33 */ - 0xC6, 0xD3, 0xB6, 0xE4, 0x96, 0x5C, 0x96, 0x5D, /* 0x34-0x37 */ - 0x96, 0x5E, 0x96, 0x5F, 0xBB, 0xFA, 0x96, 0x60, /* 0x38-0x3B */ - 0x96, 0x61, 0xD0, 0xE0, 0x96, 0x62, 0x96, 0x63, /* 0x3C-0x3F */ - 0xC9, 0xB1, 0x96, 0x64, 0xD4, 0xD3, 0xC8, 0xA8, /* 0x40-0x43 */ - 0x96, 0x65, 0x96, 0x66, 0xB8, 0xCB, 0x96, 0x67, /* 0x44-0x47 */ - 0xE8, 0xBE, 0xC9, 0xBC, 0x96, 0x68, 0x96, 0x69, /* 0x48-0x4B */ - 0xE8, 0xBB, 0x96, 0x6A, 0xC0, 0xEE, 0xD0, 0xD3, /* 0x4C-0x4F */ - 0xB2, 0xC4, 0xB4, 0xE5, 0x96, 0x6B, 0xE8, 0xBC, /* 0x50-0x53 */ - 0x96, 0x6C, 0x96, 0x6D, 0xD5, 0xC8, 0x96, 0x6E, /* 0x54-0x57 */ - 0x96, 0x6F, 0x96, 0x70, 0x96, 0x71, 0x96, 0x72, /* 0x58-0x5B */ - 0xB6, 0xC5, 0x96, 0x73, 0xE8, 0xBD, 0xCA, 0xF8, /* 0x5C-0x5F */ - 0xB8, 0xDC, 0xCC, 0xF5, 0x96, 0x74, 0x96, 0x75, /* 0x60-0x63 */ - 0x96, 0x76, 0xC0, 0xB4, 0x96, 0x77, 0x96, 0x78, /* 0x64-0x67 */ - 0xD1, 0xEE, 0xE8, 0xBF, 0xE8, 0xC2, 0x96, 0x79, /* 0x68-0x6B */ - 0x96, 0x7A, 0xBA, 0xBC, 0x96, 0x7B, 0xB1, 0xAD, /* 0x6C-0x6F */ - 0xBD, 0xDC, 0x96, 0x7C, 0xEA, 0xBD, 0xE8, 0xC3, /* 0x70-0x73 */ - 0x96, 0x7D, 0xE8, 0xC6, 0x96, 0x7E, 0xE8, 0xCB, /* 0x74-0x77 */ - 0x96, 0x80, 0x96, 0x81, 0x96, 0x82, 0x96, 0x83, /* 0x78-0x7B */ - 0xE8, 0xCC, 0x96, 0x84, 0xCB, 0xC9, 0xB0, 0xE5, /* 0x7C-0x7F */ - - 0x96, 0x85, 0xBC, 0xAB, 0x96, 0x86, 0x96, 0x87, /* 0x80-0x83 */ - 0xB9, 0xB9, 0x96, 0x88, 0x96, 0x89, 0xE8, 0xC1, /* 0x84-0x87 */ - 0x96, 0x8A, 0xCD, 0xF7, 0x96, 0x8B, 0xE8, 0xCA, /* 0x88-0x8B */ - 0x96, 0x8C, 0x96, 0x8D, 0x96, 0x8E, 0x96, 0x8F, /* 0x8C-0x8F */ - 0xCE, 0xF6, 0x96, 0x90, 0x96, 0x91, 0x96, 0x92, /* 0x90-0x93 */ - 0x96, 0x93, 0xD5, 0xED, 0x96, 0x94, 0xC1, 0xD6, /* 0x94-0x97 */ - 0xE8, 0xC4, 0x96, 0x95, 0xC3, 0xB6, 0x96, 0x96, /* 0x98-0x9B */ - 0xB9, 0xFB, 0xD6, 0xA6, 0xE8, 0xC8, 0x96, 0x97, /* 0x9C-0x9F */ - 0x96, 0x98, 0x96, 0x99, 0xCA, 0xE0, 0xD4, 0xE6, /* 0xA0-0xA3 */ - 0x96, 0x9A, 0xE8, 0xC0, 0x96, 0x9B, 0xE8, 0xC5, /* 0xA4-0xA7 */ - 0xE8, 0xC7, 0x96, 0x9C, 0xC7, 0xB9, 0xB7, 0xE3, /* 0xA8-0xAB */ - 0x96, 0x9D, 0xE8, 0xC9, 0x96, 0x9E, 0xBF, 0xDD, /* 0xAC-0xAF */ - 0xE8, 0xD2, 0x96, 0x9F, 0x96, 0xA0, 0xE8, 0xD7, /* 0xB0-0xB3 */ - 0x96, 0xA1, 0xE8, 0xD5, 0xBC, 0xDC, 0xBC, 0xCF, /* 0xB4-0xB7 */ - 0xE8, 0xDB, 0x96, 0xA2, 0x96, 0xA3, 0x96, 0xA4, /* 0xB8-0xBB */ - 0x96, 0xA5, 0x96, 0xA6, 0x96, 0xA7, 0x96, 0xA8, /* 0xBC-0xBF */ - 0x96, 0xA9, 0xE8, 0xDE, 0x96, 0xAA, 0xE8, 0xDA, /* 0xC0-0xC3 */ - 0xB1, 0xFA, 0x96, 0xAB, 0x96, 0xAC, 0x96, 0xAD, /* 0xC4-0xC7 */ - 0x96, 0xAE, 0x96, 0xAF, 0x96, 0xB0, 0x96, 0xB1, /* 0xC8-0xCB */ - 0x96, 0xB2, 0x96, 0xB3, 0x96, 0xB4, 0xB0, 0xD8, /* 0xCC-0xCF */ - 0xC4, 0xB3, 0xB8, 0xCC, 0xC6, 0xE2, 0xC8, 0xBE, /* 0xD0-0xD3 */ - 0xC8, 0xE1, 0x96, 0xB5, 0x96, 0xB6, 0x96, 0xB7, /* 0xD4-0xD7 */ - 0xE8, 0xCF, 0xE8, 0xD4, 0xE8, 0xD6, 0x96, 0xB8, /* 0xD8-0xDB */ - 0xB9, 0xF1, 0xE8, 0xD8, 0xD7, 0xF5, 0x96, 0xB9, /* 0xDC-0xDF */ - 0xC4, 0xFB, 0x96, 0xBA, 0xE8, 0xDC, 0x96, 0xBB, /* 0xE0-0xE3 */ - 0x96, 0xBC, 0xB2, 0xE9, 0x96, 0xBD, 0x96, 0xBE, /* 0xE4-0xE7 */ - 0x96, 0xBF, 0xE8, 0xD1, 0x96, 0xC0, 0x96, 0xC1, /* 0xE8-0xEB */ - 0xBC, 0xED, 0x96, 0xC2, 0x96, 0xC3, 0xBF, 0xC2, /* 0xEC-0xEF */ - 0xE8, 0xCD, 0xD6, 0xF9, 0x96, 0xC4, 0xC1, 0xF8, /* 0xF0-0xF3 */ - 0xB2, 0xF1, 0x96, 0xC5, 0x96, 0xC6, 0x96, 0xC7, /* 0xF4-0xF7 */ - 0x96, 0xC8, 0x96, 0xC9, 0x96, 0xCA, 0x96, 0xCB, /* 0xF8-0xFB */ - 0x96, 0xCC, 0xE8, 0xDF, 0x96, 0xCD, 0xCA, 0xC1, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_68[512] = { - 0xE8, 0xD9, 0x96, 0xCE, 0x96, 0xCF, 0x96, 0xD0, /* 0x00-0x03 */ - 0x96, 0xD1, 0xD5, 0xA4, 0x96, 0xD2, 0xB1, 0xEA, /* 0x04-0x07 */ - 0xD5, 0xBB, 0xE8, 0xCE, 0xE8, 0xD0, 0xB6, 0xB0, /* 0x08-0x0B */ - 0xE8, 0xD3, 0x96, 0xD3, 0xE8, 0xDD, 0xC0, 0xB8, /* 0x0C-0x0F */ - 0x96, 0xD4, 0xCA, 0xF7, 0x96, 0xD5, 0xCB, 0xA8, /* 0x10-0x13 */ - 0x96, 0xD6, 0x96, 0xD7, 0xC6, 0xDC, 0xC0, 0xF5, /* 0x14-0x17 */ - 0x96, 0xD8, 0x96, 0xD9, 0x96, 0xDA, 0x96, 0xDB, /* 0x18-0x1B */ - 0x96, 0xDC, 0xE8, 0xE9, 0x96, 0xDD, 0x96, 0xDE, /* 0x1C-0x1F */ - 0x96, 0xDF, 0xD0, 0xA3, 0x96, 0xE0, 0x96, 0xE1, /* 0x20-0x23 */ - 0x96, 0xE2, 0x96, 0xE3, 0x96, 0xE4, 0x96, 0xE5, /* 0x24-0x27 */ - 0x96, 0xE6, 0xE8, 0xF2, 0xD6, 0xEA, 0x96, 0xE7, /* 0x28-0x2B */ - 0x96, 0xE8, 0x96, 0xE9, 0x96, 0xEA, 0x96, 0xEB, /* 0x2C-0x2F */ - 0x96, 0xEC, 0x96, 0xED, 0xE8, 0xE0, 0xE8, 0xE1, /* 0x30-0x33 */ - 0x96, 0xEE, 0x96, 0xEF, 0x96, 0xF0, 0xD1, 0xF9, /* 0x34-0x37 */ - 0xBA, 0xCB, 0xB8, 0xF9, 0x96, 0xF1, 0x96, 0xF2, /* 0x38-0x3B */ - 0xB8, 0xF1, 0xD4, 0xD4, 0xE8, 0xEF, 0x96, 0xF3, /* 0x3C-0x3F */ - 0xE8, 0xEE, 0xE8, 0xEC, 0xB9, 0xF0, 0xCC, 0xD2, /* 0x40-0x43 */ - 0xE8, 0xE6, 0xCE, 0xA6, 0xBF, 0xF2, 0x96, 0xF4, /* 0x44-0x47 */ - 0xB0, 0xB8, 0xE8, 0xF1, 0xE8, 0xF0, 0x96, 0xF5, /* 0x48-0x4B */ - 0xD7, 0xC0, 0x96, 0xF6, 0xE8, 0xE4, 0x96, 0xF7, /* 0x4C-0x4F */ - 0xCD, 0xA9, 0xC9, 0xA3, 0x96, 0xF8, 0xBB, 0xB8, /* 0x50-0x53 */ - 0xBD, 0xDB, 0xE8, 0xEA, 0x96, 0xF9, 0x96, 0xFA, /* 0x54-0x57 */ - 0x96, 0xFB, 0x96, 0xFC, 0x96, 0xFD, 0x96, 0xFE, /* 0x58-0x5B */ - 0x97, 0x40, 0x97, 0x41, 0x97, 0x42, 0x97, 0x43, /* 0x5C-0x5F */ - 0xE8, 0xE2, 0xE8, 0xE3, 0xE8, 0xE5, 0xB5, 0xB5, /* 0x60-0x63 */ - 0xE8, 0xE7, 0xC7, 0xC5, 0xE8, 0xEB, 0xE8, 0xED, /* 0x64-0x67 */ - 0xBD, 0xB0, 0xD7, 0xAE, 0x97, 0x44, 0xE8, 0xF8, /* 0x68-0x6B */ - 0x97, 0x45, 0x97, 0x46, 0x97, 0x47, 0x97, 0x48, /* 0x6C-0x6F */ - 0x97, 0x49, 0x97, 0x4A, 0x97, 0x4B, 0x97, 0x4C, /* 0x70-0x73 */ - 0xE8, 0xF5, 0x97, 0x4D, 0xCD, 0xB0, 0xE8, 0xF6, /* 0x74-0x77 */ - 0x97, 0x4E, 0x97, 0x4F, 0x97, 0x50, 0x97, 0x51, /* 0x78-0x7B */ - 0x97, 0x52, 0x97, 0x53, 0x97, 0x54, 0x97, 0x55, /* 0x7C-0x7F */ - - 0x97, 0x56, 0xC1, 0xBA, 0x97, 0x57, 0xE8, 0xE8, /* 0x80-0x83 */ - 0x97, 0x58, 0xC3, 0xB7, 0xB0, 0xF0, 0x97, 0x59, /* 0x84-0x87 */ - 0x97, 0x5A, 0x97, 0x5B, 0x97, 0x5C, 0x97, 0x5D, /* 0x88-0x8B */ - 0x97, 0x5E, 0x97, 0x5F, 0x97, 0x60, 0xE8, 0xF4, /* 0x8C-0x8F */ - 0x97, 0x61, 0x97, 0x62, 0x97, 0x63, 0xE8, 0xF7, /* 0x90-0x93 */ - 0x97, 0x64, 0x97, 0x65, 0x97, 0x66, 0xB9, 0xA3, /* 0x94-0x97 */ - 0x97, 0x67, 0x97, 0x68, 0x97, 0x69, 0x97, 0x6A, /* 0x98-0x9B */ - 0x97, 0x6B, 0x97, 0x6C, 0x97, 0x6D, 0x97, 0x6E, /* 0x9C-0x9F */ - 0x97, 0x6F, 0x97, 0x70, 0xC9, 0xD2, 0x97, 0x71, /* 0xA0-0xA3 */ - 0x97, 0x72, 0x97, 0x73, 0xC3, 0xCE, 0xCE, 0xE0, /* 0xA4-0xA7 */ - 0xC0, 0xE6, 0x97, 0x74, 0x97, 0x75, 0x97, 0x76, /* 0xA8-0xAB */ - 0x97, 0x77, 0xCB, 0xF3, 0x97, 0x78, 0xCC, 0xDD, /* 0xAC-0xAF */ - 0xD0, 0xB5, 0x97, 0x79, 0x97, 0x7A, 0xCA, 0xE1, /* 0xB0-0xB3 */ - 0x97, 0x7B, 0xE8, 0xF3, 0x97, 0x7C, 0x97, 0x7D, /* 0xB4-0xB7 */ - 0x97, 0x7E, 0x97, 0x80, 0x97, 0x81, 0x97, 0x82, /* 0xB8-0xBB */ - 0x97, 0x83, 0x97, 0x84, 0x97, 0x85, 0x97, 0x86, /* 0xBC-0xBF */ - 0xBC, 0xEC, 0x97, 0x87, 0xE8, 0xF9, 0x97, 0x88, /* 0xC0-0xC3 */ - 0x97, 0x89, 0x97, 0x8A, 0x97, 0x8B, 0x97, 0x8C, /* 0xC4-0xC7 */ - 0x97, 0x8D, 0xC3, 0xDE, 0x97, 0x8E, 0xC6, 0xE5, /* 0xC8-0xCB */ - 0x97, 0x8F, 0xB9, 0xF7, 0x97, 0x90, 0x97, 0x91, /* 0xCC-0xCF */ - 0x97, 0x92, 0x97, 0x93, 0xB0, 0xF4, 0x97, 0x94, /* 0xD0-0xD3 */ - 0x97, 0x95, 0xD7, 0xD8, 0x97, 0x96, 0x97, 0x97, /* 0xD4-0xD7 */ - 0xBC, 0xAC, 0x97, 0x98, 0xC5, 0xEF, 0x97, 0x99, /* 0xD8-0xDB */ - 0x97, 0x9A, 0x97, 0x9B, 0x97, 0x9C, 0x97, 0x9D, /* 0xDC-0xDF */ - 0xCC, 0xC4, 0x97, 0x9E, 0x97, 0x9F, 0xE9, 0xA6, /* 0xE0-0xE3 */ - 0x97, 0xA0, 0x97, 0xA1, 0x97, 0xA2, 0x97, 0xA3, /* 0xE4-0xE7 */ - 0x97, 0xA4, 0x97, 0xA5, 0x97, 0xA6, 0x97, 0xA7, /* 0xE8-0xEB */ - 0x97, 0xA8, 0x97, 0xA9, 0xC9, 0xAD, 0x97, 0xAA, /* 0xEC-0xEF */ - 0xE9, 0xA2, 0xC0, 0xE2, 0x97, 0xAB, 0x97, 0xAC, /* 0xF0-0xF3 */ - 0x97, 0xAD, 0xBF, 0xC3, 0x97, 0xAE, 0x97, 0xAF, /* 0xF4-0xF7 */ - 0x97, 0xB0, 0xE8, 0xFE, 0xB9, 0xD7, 0x97, 0xB1, /* 0xF8-0xFB */ - 0xE8, 0xFB, 0x97, 0xB2, 0x97, 0xB3, 0x97, 0xB4, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_69[512] = { - 0x97, 0xB5, 0xE9, 0xA4, 0x97, 0xB6, 0x97, 0xB7, /* 0x00-0x03 */ - 0x97, 0xB8, 0xD2, 0xCE, 0x97, 0xB9, 0x97, 0xBA, /* 0x04-0x07 */ - 0x97, 0xBB, 0x97, 0xBC, 0x97, 0xBD, 0xE9, 0xA3, /* 0x08-0x0B */ - 0x97, 0xBE, 0xD6, 0xB2, 0xD7, 0xB5, 0x97, 0xBF, /* 0x0C-0x0F */ - 0xE9, 0xA7, 0x97, 0xC0, 0xBD, 0xB7, 0x97, 0xC1, /* 0x10-0x13 */ - 0x97, 0xC2, 0x97, 0xC3, 0x97, 0xC4, 0x97, 0xC5, /* 0x14-0x17 */ - 0x97, 0xC6, 0x97, 0xC7, 0x97, 0xC8, 0x97, 0xC9, /* 0x18-0x1B */ - 0x97, 0xCA, 0x97, 0xCB, 0x97, 0xCC, 0xE8, 0xFC, /* 0x1C-0x1F */ - 0xE8, 0xFD, 0x97, 0xCD, 0x97, 0xCE, 0x97, 0xCF, /* 0x20-0x23 */ - 0xE9, 0xA1, 0x97, 0xD0, 0x97, 0xD1, 0x97, 0xD2, /* 0x24-0x27 */ - 0x97, 0xD3, 0x97, 0xD4, 0x97, 0xD5, 0x97, 0xD6, /* 0x28-0x2B */ - 0x97, 0xD7, 0xCD, 0xD6, 0x97, 0xD8, 0x97, 0xD9, /* 0x2C-0x2F */ - 0xD2, 0xAC, 0x97, 0xDA, 0x97, 0xDB, 0x97, 0xDC, /* 0x30-0x33 */ - 0xE9, 0xB2, 0x97, 0xDD, 0x97, 0xDE, 0x97, 0xDF, /* 0x34-0x37 */ - 0x97, 0xE0, 0xE9, 0xA9, 0x97, 0xE1, 0x97, 0xE2, /* 0x38-0x3B */ - 0x97, 0xE3, 0xB4, 0xAA, 0x97, 0xE4, 0xB4, 0xBB, /* 0x3C-0x3F */ - 0x97, 0xE5, 0x97, 0xE6, 0xE9, 0xAB, 0x97, 0xE7, /* 0x40-0x43 */ - 0x97, 0xE8, 0x97, 0xE9, 0x97, 0xEA, 0x97, 0xEB, /* 0x44-0x47 */ - 0x97, 0xEC, 0x97, 0xED, 0x97, 0xEE, 0x97, 0xEF, /* 0x48-0x4B */ - 0x97, 0xF0, 0x97, 0xF1, 0x97, 0xF2, 0x97, 0xF3, /* 0x4C-0x4F */ - 0x97, 0xF4, 0x97, 0xF5, 0x97, 0xF6, 0x97, 0xF7, /* 0x50-0x53 */ - 0xD0, 0xA8, 0x97, 0xF8, 0x97, 0xF9, 0xE9, 0xA5, /* 0x54-0x57 */ - 0x97, 0xFA, 0x97, 0xFB, 0xB3, 0xFE, 0x97, 0xFC, /* 0x58-0x5B */ - 0x97, 0xFD, 0xE9, 0xAC, 0xC0, 0xE3, 0x97, 0xFE, /* 0x5C-0x5F */ - 0xE9, 0xAA, 0x98, 0x40, 0x98, 0x41, 0xE9, 0xB9, /* 0x60-0x63 */ - 0x98, 0x42, 0x98, 0x43, 0xE9, 0xB8, 0x98, 0x44, /* 0x64-0x67 */ - 0x98, 0x45, 0x98, 0x46, 0x98, 0x47, 0xE9, 0xAE, /* 0x68-0x6B */ - 0x98, 0x48, 0x98, 0x49, 0xE8, 0xFA, 0x98, 0x4A, /* 0x6C-0x6F */ - 0x98, 0x4B, 0xE9, 0xA8, 0x98, 0x4C, 0x98, 0x4D, /* 0x70-0x73 */ - 0x98, 0x4E, 0x98, 0x4F, 0x98, 0x50, 0xBF, 0xAC, /* 0x74-0x77 */ - 0xE9, 0xB1, 0xE9, 0xBA, 0x98, 0x51, 0x98, 0x52, /* 0x78-0x7B */ - 0xC2, 0xA5, 0x98, 0x53, 0x98, 0x54, 0x98, 0x55, /* 0x7C-0x7F */ - - 0xE9, 0xAF, 0x98, 0x56, 0xB8, 0xC5, 0x98, 0x57, /* 0x80-0x83 */ - 0xE9, 0xAD, 0x98, 0x58, 0xD3, 0xDC, 0xE9, 0xB4, /* 0x84-0x87 */ - 0xE9, 0xB5, 0xE9, 0xB7, 0x98, 0x59, 0x98, 0x5A, /* 0x88-0x8B */ - 0x98, 0x5B, 0xE9, 0xC7, 0x98, 0x5C, 0x98, 0x5D, /* 0x8C-0x8F */ - 0x98, 0x5E, 0x98, 0x5F, 0x98, 0x60, 0x98, 0x61, /* 0x90-0x93 */ - 0xC0, 0xC6, 0xE9, 0xC5, 0x98, 0x62, 0x98, 0x63, /* 0x94-0x97 */ - 0xE9, 0xB0, 0x98, 0x64, 0x98, 0x65, 0xE9, 0xBB, /* 0x98-0x9B */ - 0xB0, 0xF1, 0x98, 0x66, 0x98, 0x67, 0x98, 0x68, /* 0x9C-0x9F */ - 0x98, 0x69, 0x98, 0x6A, 0x98, 0x6B, 0x98, 0x6C, /* 0xA0-0xA3 */ - 0x98, 0x6D, 0x98, 0x6E, 0x98, 0x6F, 0xE9, 0xBC, /* 0xA4-0xA7 */ - 0xD5, 0xA5, 0x98, 0x70, 0x98, 0x71, 0xE9, 0xBE, /* 0xA8-0xAB */ - 0x98, 0x72, 0xE9, 0xBF, 0x98, 0x73, 0x98, 0x74, /* 0xAC-0xAF */ - 0x98, 0x75, 0xE9, 0xC1, 0x98, 0x76, 0x98, 0x77, /* 0xB0-0xB3 */ - 0xC1, 0xF1, 0x98, 0x78, 0x98, 0x79, 0xC8, 0xB6, /* 0xB4-0xB7 */ - 0x98, 0x7A, 0x98, 0x7B, 0x98, 0x7C, 0xE9, 0xBD, /* 0xB8-0xBB */ - 0x98, 0x7D, 0x98, 0x7E, 0x98, 0x80, 0x98, 0x81, /* 0xBC-0xBF */ - 0x98, 0x82, 0xE9, 0xC2, 0x98, 0x83, 0x98, 0x84, /* 0xC0-0xC3 */ - 0x98, 0x85, 0x98, 0x86, 0x98, 0x87, 0x98, 0x88, /* 0xC4-0xC7 */ - 0x98, 0x89, 0x98, 0x8A, 0xE9, 0xC3, 0x98, 0x8B, /* 0xC8-0xCB */ - 0xE9, 0xB3, 0x98, 0x8C, 0xE9, 0xB6, 0x98, 0x8D, /* 0xCC-0xCF */ - 0xBB, 0xB1, 0x98, 0x8E, 0x98, 0x8F, 0x98, 0x90, /* 0xD0-0xD3 */ - 0xE9, 0xC0, 0x98, 0x91, 0x98, 0x92, 0x98, 0x93, /* 0xD4-0xD7 */ - 0x98, 0x94, 0x98, 0x95, 0x98, 0x96, 0xBC, 0xF7, /* 0xD8-0xDB */ - 0x98, 0x97, 0x98, 0x98, 0x98, 0x99, 0xE9, 0xC4, /* 0xDC-0xDF */ - 0xE9, 0xC6, 0x98, 0x9A, 0x98, 0x9B, 0x98, 0x9C, /* 0xE0-0xE3 */ - 0x98, 0x9D, 0x98, 0x9E, 0x98, 0x9F, 0x98, 0xA0, /* 0xE4-0xE7 */ - 0x98, 0xA1, 0x98, 0xA2, 0x98, 0xA3, 0x98, 0xA4, /* 0xE8-0xEB */ - 0x98, 0xA5, 0xE9, 0xCA, 0x98, 0xA6, 0x98, 0xA7, /* 0xEC-0xEF */ - 0x98, 0xA8, 0x98, 0xA9, 0xE9, 0xCE, 0x98, 0xAA, /* 0xF0-0xF3 */ - 0x98, 0xAB, 0x98, 0xAC, 0x98, 0xAD, 0x98, 0xAE, /* 0xF4-0xF7 */ - 0x98, 0xAF, 0x98, 0xB0, 0x98, 0xB1, 0x98, 0xB2, /* 0xF8-0xFB */ - 0x98, 0xB3, 0xB2, 0xDB, 0x98, 0xB4, 0xE9, 0xC8, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_6A[512] = { - 0x98, 0xB5, 0x98, 0xB6, 0x98, 0xB7, 0x98, 0xB8, /* 0x00-0x03 */ - 0x98, 0xB9, 0x98, 0xBA, 0x98, 0xBB, 0x98, 0xBC, /* 0x04-0x07 */ - 0x98, 0xBD, 0x98, 0xBE, 0xB7, 0xAE, 0x98, 0xBF, /* 0x08-0x0B */ - 0x98, 0xC0, 0x98, 0xC1, 0x98, 0xC2, 0x98, 0xC3, /* 0x0C-0x0F */ - 0x98, 0xC4, 0x98, 0xC5, 0x98, 0xC6, 0x98, 0xC7, /* 0x10-0x13 */ - 0x98, 0xC8, 0x98, 0xC9, 0x98, 0xCA, 0xE9, 0xCB, /* 0x14-0x17 */ - 0xE9, 0xCC, 0x98, 0xCB, 0x98, 0xCC, 0x98, 0xCD, /* 0x18-0x1B */ - 0x98, 0xCE, 0x98, 0xCF, 0x98, 0xD0, 0xD5, 0xC1, /* 0x1C-0x1F */ - 0x98, 0xD1, 0xC4, 0xA3, 0x98, 0xD2, 0x98, 0xD3, /* 0x20-0x23 */ - 0x98, 0xD4, 0x98, 0xD5, 0x98, 0xD6, 0x98, 0xD7, /* 0x24-0x27 */ - 0xE9, 0xD8, 0x98, 0xD8, 0xBA, 0xE1, 0x98, 0xD9, /* 0x28-0x2B */ - 0x98, 0xDA, 0x98, 0xDB, 0x98, 0xDC, 0xE9, 0xC9, /* 0x2C-0x2F */ - 0x98, 0xDD, 0xD3, 0xA3, 0x98, 0xDE, 0x98, 0xDF, /* 0x30-0x33 */ - 0x98, 0xE0, 0xE9, 0xD4, 0x98, 0xE1, 0x98, 0xE2, /* 0x34-0x37 */ - 0x98, 0xE3, 0x98, 0xE4, 0x98, 0xE5, 0x98, 0xE6, /* 0x38-0x3B */ - 0x98, 0xE7, 0xE9, 0xD7, 0xE9, 0xD0, 0x98, 0xE8, /* 0x3C-0x3F */ - 0x98, 0xE9, 0x98, 0xEA, 0x98, 0xEB, 0x98, 0xEC, /* 0x40-0x43 */ - 0xE9, 0xCF, 0x98, 0xED, 0x98, 0xEE, 0xC7, 0xC1, /* 0x44-0x47 */ - 0x98, 0xEF, 0x98, 0xF0, 0x98, 0xF1, 0x98, 0xF2, /* 0x48-0x4B */ - 0x98, 0xF3, 0x98, 0xF4, 0x98, 0xF5, 0x98, 0xF6, /* 0x4C-0x4F */ - 0xE9, 0xD2, 0x98, 0xF7, 0x98, 0xF8, 0x98, 0xF9, /* 0x50-0x53 */ - 0x98, 0xFA, 0x98, 0xFB, 0x98, 0xFC, 0x98, 0xFD, /* 0x54-0x57 */ - 0xE9, 0xD9, 0xB3, 0xC8, 0x98, 0xFE, 0xE9, 0xD3, /* 0x58-0x5B */ - 0x99, 0x40, 0x99, 0x41, 0x99, 0x42, 0x99, 0x43, /* 0x5C-0x5F */ - 0x99, 0x44, 0xCF, 0xF0, 0x99, 0x45, 0x99, 0x46, /* 0x60-0x63 */ - 0x99, 0x47, 0xE9, 0xCD, 0x99, 0x48, 0x99, 0x49, /* 0x64-0x67 */ - 0x99, 0x4A, 0x99, 0x4B, 0x99, 0x4C, 0x99, 0x4D, /* 0x68-0x6B */ - 0x99, 0x4E, 0x99, 0x4F, 0x99, 0x50, 0x99, 0x51, /* 0x6C-0x6F */ - 0x99, 0x52, 0xB3, 0xF7, 0x99, 0x53, 0x99, 0x54, /* 0x70-0x73 */ - 0x99, 0x55, 0x99, 0x56, 0x99, 0x57, 0x99, 0x58, /* 0x74-0x77 */ - 0x99, 0x59, 0xE9, 0xD6, 0x99, 0x5A, 0x99, 0x5B, /* 0x78-0x7B */ - 0xE9, 0xDA, 0x99, 0x5C, 0x99, 0x5D, 0x99, 0x5E, /* 0x7C-0x7F */ - - 0xCC, 0xB4, 0x99, 0x5F, 0x99, 0x60, 0x99, 0x61, /* 0x80-0x83 */ - 0xCF, 0xAD, 0x99, 0x62, 0x99, 0x63, 0x99, 0x64, /* 0x84-0x87 */ - 0x99, 0x65, 0x99, 0x66, 0x99, 0x67, 0x99, 0x68, /* 0x88-0x8B */ - 0x99, 0x69, 0x99, 0x6A, 0xE9, 0xD5, 0x99, 0x6B, /* 0x8C-0x8F */ - 0xE9, 0xDC, 0xE9, 0xDB, 0x99, 0x6C, 0x99, 0x6D, /* 0x90-0x93 */ - 0x99, 0x6E, 0x99, 0x6F, 0x99, 0x70, 0xE9, 0xDE, /* 0x94-0x97 */ - 0x99, 0x71, 0x99, 0x72, 0x99, 0x73, 0x99, 0x74, /* 0x98-0x9B */ - 0x99, 0x75, 0x99, 0x76, 0x99, 0x77, 0x99, 0x78, /* 0x9C-0x9F */ - 0xE9, 0xD1, 0x99, 0x79, 0x99, 0x7A, 0x99, 0x7B, /* 0xA0-0xA3 */ - 0x99, 0x7C, 0x99, 0x7D, 0x99, 0x7E, 0x99, 0x80, /* 0xA4-0xA7 */ - 0x99, 0x81, 0xE9, 0xDD, 0x99, 0x82, 0xE9, 0xDF, /* 0xA8-0xAB */ - 0xC3, 0xCA, 0x99, 0x83, 0x99, 0x84, 0x99, 0x85, /* 0xAC-0xAF */ - 0x99, 0x86, 0x99, 0x87, 0x99, 0x88, 0x99, 0x89, /* 0xB0-0xB3 */ - 0x99, 0x8A, 0x99, 0x8B, 0x99, 0x8C, 0x99, 0x8D, /* 0xB4-0xB7 */ - 0x99, 0x8E, 0x99, 0x8F, 0x99, 0x90, 0x99, 0x91, /* 0xB8-0xBB */ - 0x99, 0x92, 0x99, 0x93, 0x99, 0x94, 0x99, 0x95, /* 0xBC-0xBF */ - 0x99, 0x96, 0x99, 0x97, 0x99, 0x98, 0x99, 0x99, /* 0xC0-0xC3 */ - 0x99, 0x9A, 0x99, 0x9B, 0x99, 0x9C, 0x99, 0x9D, /* 0xC4-0xC7 */ - 0x99, 0x9E, 0x99, 0x9F, 0x99, 0xA0, 0x99, 0xA1, /* 0xC8-0xCB */ - 0x99, 0xA2, 0x99, 0xA3, 0x99, 0xA4, 0x99, 0xA5, /* 0xCC-0xCF */ - 0x99, 0xA6, 0x99, 0xA7, 0x99, 0xA8, 0x99, 0xA9, /* 0xD0-0xD3 */ - 0x99, 0xAA, 0x99, 0xAB, 0x99, 0xAC, 0x99, 0xAD, /* 0xD4-0xD7 */ - 0x99, 0xAE, 0x99, 0xAF, 0x99, 0xB0, 0x99, 0xB1, /* 0xD8-0xDB */ - 0x99, 0xB2, 0x99, 0xB3, 0x99, 0xB4, 0x99, 0xB5, /* 0xDC-0xDF */ - 0x99, 0xB6, 0x99, 0xB7, 0x99, 0xB8, 0x99, 0xB9, /* 0xE0-0xE3 */ - 0x99, 0xBA, 0x99, 0xBB, 0x99, 0xBC, 0x99, 0xBD, /* 0xE4-0xE7 */ - 0x99, 0xBE, 0x99, 0xBF, 0x99, 0xC0, 0x99, 0xC1, /* 0xE8-0xEB */ - 0x99, 0xC2, 0x99, 0xC3, 0x99, 0xC4, 0x99, 0xC5, /* 0xEC-0xEF */ - 0x99, 0xC6, 0x99, 0xC7, 0x99, 0xC8, 0x99, 0xC9, /* 0xF0-0xF3 */ - 0x99, 0xCA, 0x99, 0xCB, 0x99, 0xCC, 0x99, 0xCD, /* 0xF4-0xF7 */ - 0x99, 0xCE, 0x99, 0xCF, 0x99, 0xD0, 0x99, 0xD1, /* 0xF8-0xFB */ - 0x99, 0xD2, 0x99, 0xD3, 0x99, 0xD4, 0x99, 0xD5, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_6B[512] = { - 0x99, 0xD6, 0x99, 0xD7, 0x99, 0xD8, 0x99, 0xD9, /* 0x00-0x03 */ - 0x99, 0xDA, 0x99, 0xDB, 0x99, 0xDC, 0x99, 0xDD, /* 0x04-0x07 */ - 0x99, 0xDE, 0x99, 0xDF, 0x99, 0xE0, 0x99, 0xE1, /* 0x08-0x0B */ - 0x99, 0xE2, 0x99, 0xE3, 0x99, 0xE4, 0x99, 0xE5, /* 0x0C-0x0F */ - 0x99, 0xE6, 0x99, 0xE7, 0x99, 0xE8, 0x99, 0xE9, /* 0x10-0x13 */ - 0x99, 0xEA, 0x99, 0xEB, 0x99, 0xEC, 0x99, 0xED, /* 0x14-0x17 */ - 0x99, 0xEE, 0x99, 0xEF, 0x99, 0xF0, 0x99, 0xF1, /* 0x18-0x1B */ - 0x99, 0xF2, 0x99, 0xF3, 0x99, 0xF4, 0x99, 0xF5, /* 0x1C-0x1F */ - 0xC7, 0xB7, 0xB4, 0xCE, 0xBB, 0xB6, 0xD0, 0xC0, /* 0x20-0x23 */ - 0xEC, 0xA3, 0x99, 0xF6, 0x99, 0xF7, 0xC5, 0xB7, /* 0x24-0x27 */ - 0x99, 0xF8, 0x99, 0xF9, 0x99, 0xFA, 0x99, 0xFB, /* 0x28-0x2B */ - 0x99, 0xFC, 0x99, 0xFD, 0x99, 0xFE, 0x9A, 0x40, /* 0x2C-0x2F */ - 0x9A, 0x41, 0x9A, 0x42, 0xD3, 0xFB, 0x9A, 0x43, /* 0x30-0x33 */ - 0x9A, 0x44, 0x9A, 0x45, 0x9A, 0x46, 0xEC, 0xA4, /* 0x34-0x37 */ - 0x9A, 0x47, 0xEC, 0xA5, 0xC6, 0xDB, 0x9A, 0x48, /* 0x38-0x3B */ - 0x9A, 0x49, 0x9A, 0x4A, 0xBF, 0xEE, 0x9A, 0x4B, /* 0x3C-0x3F */ - 0x9A, 0x4C, 0x9A, 0x4D, 0x9A, 0x4E, 0xEC, 0xA6, /* 0x40-0x43 */ - 0x9A, 0x4F, 0x9A, 0x50, 0xEC, 0xA7, 0xD0, 0xAA, /* 0x44-0x47 */ - 0x9A, 0x51, 0xC7, 0xB8, 0x9A, 0x52, 0x9A, 0x53, /* 0x48-0x4B */ - 0xB8, 0xE8, 0x9A, 0x54, 0x9A, 0x55, 0x9A, 0x56, /* 0x4C-0x4F */ - 0x9A, 0x57, 0x9A, 0x58, 0x9A, 0x59, 0x9A, 0x5A, /* 0x50-0x53 */ - 0x9A, 0x5B, 0x9A, 0x5C, 0x9A, 0x5D, 0x9A, 0x5E, /* 0x54-0x57 */ - 0x9A, 0x5F, 0xEC, 0xA8, 0x9A, 0x60, 0x9A, 0x61, /* 0x58-0x5B */ - 0x9A, 0x62, 0x9A, 0x63, 0x9A, 0x64, 0x9A, 0x65, /* 0x5C-0x5F */ - 0x9A, 0x66, 0x9A, 0x67, 0xD6, 0xB9, 0xD5, 0xFD, /* 0x60-0x63 */ - 0xB4, 0xCB, 0xB2, 0xBD, 0xCE, 0xE4, 0xC6, 0xE7, /* 0x64-0x67 */ - 0x9A, 0x68, 0x9A, 0x69, 0xCD, 0xE1, 0x9A, 0x6A, /* 0x68-0x6B */ - 0x9A, 0x6B, 0x9A, 0x6C, 0x9A, 0x6D, 0x9A, 0x6E, /* 0x6C-0x6F */ - 0x9A, 0x6F, 0x9A, 0x70, 0x9A, 0x71, 0x9A, 0x72, /* 0x70-0x73 */ - 0x9A, 0x73, 0x9A, 0x74, 0x9A, 0x75, 0x9A, 0x76, /* 0x74-0x77 */ - 0x9A, 0x77, 0xB4, 0xF5, 0x9A, 0x78, 0xCB, 0xC0, /* 0x78-0x7B */ - 0xBC, 0xDF, 0x9A, 0x79, 0x9A, 0x7A, 0x9A, 0x7B, /* 0x7C-0x7F */ - - 0x9A, 0x7C, 0xE9, 0xE2, 0xE9, 0xE3, 0xD1, 0xEA, /* 0x80-0x83 */ - 0xE9, 0xE5, 0x9A, 0x7D, 0xB4, 0xF9, 0xE9, 0xE4, /* 0x84-0x87 */ - 0x9A, 0x7E, 0xD1, 0xB3, 0xCA, 0xE2, 0xB2, 0xD0, /* 0x88-0x8B */ - 0x9A, 0x80, 0xE9, 0xE8, 0x9A, 0x81, 0x9A, 0x82, /* 0x8C-0x8F */ - 0x9A, 0x83, 0x9A, 0x84, 0xE9, 0xE6, 0xE9, 0xE7, /* 0x90-0x93 */ - 0x9A, 0x85, 0x9A, 0x86, 0xD6, 0xB3, 0x9A, 0x87, /* 0x94-0x97 */ - 0x9A, 0x88, 0x9A, 0x89, 0xE9, 0xE9, 0xE9, 0xEA, /* 0x98-0x9B */ - 0x9A, 0x8A, 0x9A, 0x8B, 0x9A, 0x8C, 0x9A, 0x8D, /* 0x9C-0x9F */ - 0x9A, 0x8E, 0xE9, 0xEB, 0x9A, 0x8F, 0x9A, 0x90, /* 0xA0-0xA3 */ - 0x9A, 0x91, 0x9A, 0x92, 0x9A, 0x93, 0x9A, 0x94, /* 0xA4-0xA7 */ - 0x9A, 0x95, 0x9A, 0x96, 0xE9, 0xEC, 0x9A, 0x97, /* 0xA8-0xAB */ - 0x9A, 0x98, 0x9A, 0x99, 0x9A, 0x9A, 0x9A, 0x9B, /* 0xAC-0xAF */ - 0x9A, 0x9C, 0x9A, 0x9D, 0x9A, 0x9E, 0xEC, 0xAF, /* 0xB0-0xB3 */ - 0xC5, 0xB9, 0xB6, 0xCE, 0x9A, 0x9F, 0xD2, 0xF3, /* 0xB4-0xB7 */ - 0x9A, 0xA0, 0x9A, 0xA1, 0x9A, 0xA2, 0x9A, 0xA3, /* 0xB8-0xBB */ - 0x9A, 0xA4, 0x9A, 0xA5, 0x9A, 0xA6, 0xB5, 0xEE, /* 0xBC-0xBF */ - 0x9A, 0xA7, 0xBB, 0xD9, 0xEC, 0xB1, 0x9A, 0xA8, /* 0xC0-0xC3 */ - 0x9A, 0xA9, 0xD2, 0xE3, 0x9A, 0xAA, 0x9A, 0xAB, /* 0xC4-0xC7 */ - 0x9A, 0xAC, 0x9A, 0xAD, 0x9A, 0xAE, 0xCE, 0xE3, /* 0xC8-0xCB */ - 0x9A, 0xAF, 0xC4, 0xB8, 0x9A, 0xB0, 0xC3, 0xBF, /* 0xCC-0xCF */ - 0x9A, 0xB1, 0x9A, 0xB2, 0xB6, 0xBE, 0xD8, 0xB9, /* 0xD0-0xD3 */ - 0xB1, 0xC8, 0xB1, 0xCF, 0xB1, 0xD1, 0xC5, 0xFE, /* 0xD4-0xD7 */ - 0x9A, 0xB3, 0xB1, 0xD0, 0x9A, 0xB4, 0xC3, 0xAB, /* 0xD8-0xDB */ - 0x9A, 0xB5, 0x9A, 0xB6, 0x9A, 0xB7, 0x9A, 0xB8, /* 0xDC-0xDF */ - 0x9A, 0xB9, 0xD5, 0xB1, 0x9A, 0xBA, 0x9A, 0xBB, /* 0xE0-0xE3 */ - 0x9A, 0xBC, 0x9A, 0xBD, 0x9A, 0xBE, 0x9A, 0xBF, /* 0xE4-0xE7 */ - 0x9A, 0xC0, 0x9A, 0xC1, 0xEB, 0xA4, 0xBA, 0xC1, /* 0xE8-0xEB */ - 0x9A, 0xC2, 0x9A, 0xC3, 0x9A, 0xC4, 0xCC, 0xBA, /* 0xEC-0xEF */ - 0x9A, 0xC5, 0x9A, 0xC6, 0x9A, 0xC7, 0xEB, 0xA5, /* 0xF0-0xF3 */ - 0x9A, 0xC8, 0xEB, 0xA7, 0x9A, 0xC9, 0x9A, 0xCA, /* 0xF4-0xF7 */ - 0x9A, 0xCB, 0xEB, 0xA8, 0x9A, 0xCC, 0x9A, 0xCD, /* 0xF8-0xFB */ - 0x9A, 0xCE, 0xEB, 0xA6, 0x9A, 0xCF, 0x9A, 0xD0, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_6C[512] = { - 0x9A, 0xD1, 0x9A, 0xD2, 0x9A, 0xD3, 0x9A, 0xD4, /* 0x00-0x03 */ - 0x9A, 0xD5, 0xEB, 0xA9, 0xEB, 0xAB, 0xEB, 0xAA, /* 0x04-0x07 */ - 0x9A, 0xD6, 0x9A, 0xD7, 0x9A, 0xD8, 0x9A, 0xD9, /* 0x08-0x0B */ - 0x9A, 0xDA, 0xEB, 0xAC, 0x9A, 0xDB, 0xCA, 0xCF, /* 0x0C-0x0F */ - 0xD8, 0xB5, 0xC3, 0xF1, 0x9A, 0xDC, 0xC3, 0xA5, /* 0x10-0x13 */ - 0xC6, 0xF8, 0xEB, 0xAD, 0xC4, 0xCA, 0x9A, 0xDD, /* 0x14-0x17 */ - 0xEB, 0xAE, 0xEB, 0xAF, 0xEB, 0xB0, 0xB7, 0xD5, /* 0x18-0x1B */ - 0x9A, 0xDE, 0x9A, 0xDF, 0x9A, 0xE0, 0xB7, 0xFA, /* 0x1C-0x1F */ - 0x9A, 0xE1, 0xEB, 0xB1, 0xC7, 0xE2, 0x9A, 0xE2, /* 0x20-0x23 */ - 0xEB, 0xB3, 0x9A, 0xE3, 0xBA, 0xA4, 0xD1, 0xF5, /* 0x24-0x27 */ - 0xB0, 0xB1, 0xEB, 0xB2, 0xEB, 0xB4, 0x9A, 0xE4, /* 0x28-0x2B */ - 0x9A, 0xE5, 0x9A, 0xE6, 0xB5, 0xAA, 0xC2, 0xC8, /* 0x2C-0x2F */ - 0xC7, 0xE8, 0x9A, 0xE7, 0xEB, 0xB5, 0x9A, 0xE8, /* 0x30-0x33 */ - 0xCB, 0xAE, 0xE3, 0xDF, 0x9A, 0xE9, 0x9A, 0xEA, /* 0x34-0x37 */ - 0xD3, 0xC0, 0x9A, 0xEB, 0x9A, 0xEC, 0x9A, 0xED, /* 0x38-0x3B */ - 0x9A, 0xEE, 0xD9, 0xDB, 0x9A, 0xEF, 0x9A, 0xF0, /* 0x3C-0x3F */ - 0xCD, 0xA1, 0xD6, 0xAD, 0xC7, 0xF3, 0x9A, 0xF1, /* 0x40-0x43 */ - 0x9A, 0xF2, 0x9A, 0xF3, 0xD9, 0xE0, 0xBB, 0xE3, /* 0x44-0x47 */ - 0x9A, 0xF4, 0xBA, 0xBA, 0xE3, 0xE2, 0x9A, 0xF5, /* 0x48-0x4B */ - 0x9A, 0xF6, 0x9A, 0xF7, 0x9A, 0xF8, 0x9A, 0xF9, /* 0x4C-0x4F */ - 0xCF, 0xAB, 0x9A, 0xFA, 0x9A, 0xFB, 0x9A, 0xFC, /* 0x50-0x53 */ - 0xE3, 0xE0, 0xC9, 0xC7, 0x9A, 0xFD, 0xBA, 0xB9, /* 0x54-0x57 */ - 0x9A, 0xFE, 0x9B, 0x40, 0x9B, 0x41, 0xD1, 0xB4, /* 0x58-0x5B */ - 0xE3, 0xE1, 0xC8, 0xEA, 0xB9, 0xAF, 0xBD, 0xAD, /* 0x5C-0x5F */ - 0xB3, 0xD8, 0xCE, 0xDB, 0x9B, 0x42, 0x9B, 0x43, /* 0x60-0x63 */ - 0xCC, 0xC0, 0x9B, 0x44, 0x9B, 0x45, 0x9B, 0x46, /* 0x64-0x67 */ - 0xE3, 0xE8, 0xE3, 0xE9, 0xCD, 0xF4, 0x9B, 0x47, /* 0x68-0x6B */ - 0x9B, 0x48, 0x9B, 0x49, 0x9B, 0x4A, 0x9B, 0x4B, /* 0x6C-0x6F */ - 0xCC, 0xAD, 0x9B, 0x4C, 0xBC, 0xB3, 0x9B, 0x4D, /* 0x70-0x73 */ - 0xE3, 0xEA, 0x9B, 0x4E, 0xE3, 0xEB, 0x9B, 0x4F, /* 0x74-0x77 */ - 0x9B, 0x50, 0xD0, 0xDA, 0x9B, 0x51, 0x9B, 0x52, /* 0x78-0x7B */ - 0x9B, 0x53, 0xC6, 0xFB, 0xB7, 0xDA, 0x9B, 0x54, /* 0x7C-0x7F */ - - 0x9B, 0x55, 0xC7, 0xDF, 0xD2, 0xCA, 0xCE, 0xD6, /* 0x80-0x83 */ - 0x9B, 0x56, 0xE3, 0xE4, 0xE3, 0xEC, 0x9B, 0x57, /* 0x84-0x87 */ - 0xC9, 0xF2, 0xB3, 0xC1, 0x9B, 0x58, 0x9B, 0x59, /* 0x88-0x8B */ - 0xE3, 0xE7, 0x9B, 0x5A, 0x9B, 0x5B, 0xC6, 0xE3, /* 0x8C-0x8F */ - 0xE3, 0xE5, 0x9B, 0x5C, 0x9B, 0x5D, 0xED, 0xB3, /* 0x90-0x93 */ - 0xE3, 0xE6, 0x9B, 0x5E, 0x9B, 0x5F, 0x9B, 0x60, /* 0x94-0x97 */ - 0x9B, 0x61, 0xC9, 0xB3, 0x9B, 0x62, 0xC5, 0xE6, /* 0x98-0x9B */ - 0x9B, 0x63, 0x9B, 0x64, 0x9B, 0x65, 0xB9, 0xB5, /* 0x9C-0x9F */ - 0x9B, 0x66, 0xC3, 0xBB, 0x9B, 0x67, 0xE3, 0xE3, /* 0xA0-0xA3 */ - 0xC5, 0xBD, 0xC1, 0xA4, 0xC2, 0xD9, 0xB2, 0xD7, /* 0xA4-0xA7 */ - 0x9B, 0x68, 0xE3, 0xED, 0xBB, 0xA6, 0xC4, 0xAD, /* 0xA8-0xAB */ - 0x9B, 0x69, 0xE3, 0xF0, 0xBE, 0xDA, 0x9B, 0x6A, /* 0xAC-0xAF */ - 0x9B, 0x6B, 0xE3, 0xFB, 0xE3, 0xF5, 0xBA, 0xD3, /* 0xB0-0xB3 */ - 0x9B, 0x6C, 0x9B, 0x6D, 0x9B, 0x6E, 0x9B, 0x6F, /* 0xB4-0xB7 */ - 0xB7, 0xD0, 0xD3, 0xCD, 0x9B, 0x70, 0xD6, 0xCE, /* 0xB8-0xBB */ - 0xD5, 0xD3, 0xB9, 0xC1, 0xD5, 0xB4, 0xD1, 0xD8, /* 0xBC-0xBF */ - 0x9B, 0x71, 0x9B, 0x72, 0x9B, 0x73, 0x9B, 0x74, /* 0xC0-0xC3 */ - 0xD0, 0xB9, 0xC7, 0xF6, 0x9B, 0x75, 0x9B, 0x76, /* 0xC4-0xC7 */ - 0x9B, 0x77, 0xC8, 0xAA, 0xB2, 0xB4, 0x9B, 0x78, /* 0xC8-0xCB */ - 0xC3, 0xDA, 0x9B, 0x79, 0x9B, 0x7A, 0x9B, 0x7B, /* 0xCC-0xCF */ - 0xE3, 0xEE, 0x9B, 0x7C, 0x9B, 0x7D, 0xE3, 0xFC, /* 0xD0-0xD3 */ - 0xE3, 0xEF, 0xB7, 0xA8, 0xE3, 0xF7, 0xE3, 0xF4, /* 0xD4-0xD7 */ - 0x9B, 0x7E, 0x9B, 0x80, 0x9B, 0x81, 0xB7, 0xBA, /* 0xD8-0xDB */ - 0x9B, 0x82, 0x9B, 0x83, 0xC5, 0xA2, 0x9B, 0x84, /* 0xDC-0xDF */ - 0xE3, 0xF6, 0xC5, 0xDD, 0xB2, 0xA8, 0xC6, 0xFC, /* 0xE0-0xE3 */ - 0x9B, 0x85, 0xC4, 0xE0, 0x9B, 0x86, 0x9B, 0x87, /* 0xE4-0xE7 */ - 0xD7, 0xA2, 0x9B, 0x88, 0xC0, 0xE1, 0xE3, 0xF9, /* 0xE8-0xEB */ - 0x9B, 0x89, 0x9B, 0x8A, 0xE3, 0xFA, 0xE3, 0xFD, /* 0xEC-0xEF */ - 0xCC, 0xA9, 0xE3, 0xF3, 0x9B, 0x8B, 0xD3, 0xBE, /* 0xF0-0xF3 */ - 0x9B, 0x8C, 0xB1, 0xC3, 0xED, 0xB4, 0xE3, 0xF1, /* 0xF4-0xF7 */ - 0xE3, 0xF2, 0x9B, 0x8D, 0xE3, 0xF8, 0xD0, 0xBA, /* 0xF8-0xFB */ - 0xC6, 0xC3, 0xD4, 0xF3, 0xE3, 0xFE, 0x9B, 0x8E, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_6D[512] = { - 0x9B, 0x8F, 0xBD, 0xE0, 0x9B, 0x90, 0x9B, 0x91, /* 0x00-0x03 */ - 0xE4, 0xA7, 0x9B, 0x92, 0x9B, 0x93, 0xE4, 0xA6, /* 0x04-0x07 */ - 0x9B, 0x94, 0x9B, 0x95, 0x9B, 0x96, 0xD1, 0xF3, /* 0x08-0x0B */ - 0xE4, 0xA3, 0x9B, 0x97, 0xE4, 0xA9, 0x9B, 0x98, /* 0x0C-0x0F */ - 0x9B, 0x99, 0x9B, 0x9A, 0xC8, 0xF7, 0x9B, 0x9B, /* 0x10-0x13 */ - 0x9B, 0x9C, 0x9B, 0x9D, 0x9B, 0x9E, 0xCF, 0xB4, /* 0x14-0x17 */ - 0x9B, 0x9F, 0xE4, 0xA8, 0xE4, 0xAE, 0xC2, 0xE5, /* 0x18-0x1B */ - 0x9B, 0xA0, 0x9B, 0xA1, 0xB6, 0xB4, 0x9B, 0xA2, /* 0x1C-0x1F */ - 0x9B, 0xA3, 0x9B, 0xA4, 0x9B, 0xA5, 0x9B, 0xA6, /* 0x20-0x23 */ - 0x9B, 0xA7, 0xBD, 0xF2, 0x9B, 0xA8, 0xE4, 0xA2, /* 0x24-0x27 */ - 0x9B, 0xA9, 0x9B, 0xAA, 0xBA, 0xE9, 0xE4, 0xAA, /* 0x28-0x2B */ - 0x9B, 0xAB, 0x9B, 0xAC, 0xE4, 0xAC, 0x9B, 0xAD, /* 0x2C-0x2F */ - 0x9B, 0xAE, 0xB6, 0xFD, 0xD6, 0xDE, 0xE4, 0xB2, /* 0x30-0x33 */ - 0x9B, 0xAF, 0xE4, 0xAD, 0x9B, 0xB0, 0x9B, 0xB1, /* 0x34-0x37 */ - 0x9B, 0xB2, 0xE4, 0xA1, 0x9B, 0xB3, 0xBB, 0xEE, /* 0x38-0x3B */ - 0xCD, 0xDD, 0xC7, 0xA2, 0xC5, 0xC9, 0x9B, 0xB4, /* 0x3C-0x3F */ - 0x9B, 0xB5, 0xC1, 0xF7, 0x9B, 0xB6, 0xE4, 0xA4, /* 0x40-0x43 */ - 0x9B, 0xB7, 0xC7, 0xB3, 0xBD, 0xAC, 0xBD, 0xBD, /* 0x44-0x47 */ - 0xE4, 0xA5, 0x9B, 0xB8, 0xD7, 0xC7, 0xB2, 0xE2, /* 0x48-0x4B */ - 0x9B, 0xB9, 0xE4, 0xAB, 0xBC, 0xC3, 0xE4, 0xAF, /* 0x4C-0x4F */ - 0x9B, 0xBA, 0xBB, 0xEB, 0xE4, 0xB0, 0xC5, 0xA8, /* 0x50-0x53 */ - 0xE4, 0xB1, 0x9B, 0xBB, 0x9B, 0xBC, 0x9B, 0xBD, /* 0x54-0x57 */ - 0x9B, 0xBE, 0xD5, 0xE3, 0xBF, 0xA3, 0x9B, 0xBF, /* 0x58-0x5B */ - 0xE4, 0xBA, 0x9B, 0xC0, 0xE4, 0xB7, 0x9B, 0xC1, /* 0x5C-0x5F */ - 0xE4, 0xBB, 0x9B, 0xC2, 0x9B, 0xC3, 0xE4, 0xBD, /* 0x60-0x63 */ - 0x9B, 0xC4, 0x9B, 0xC5, 0xC6, 0xD6, 0x9B, 0xC6, /* 0x64-0x67 */ - 0x9B, 0xC7, 0xBA, 0xC6, 0xC0, 0xCB, 0x9B, 0xC8, /* 0x68-0x6B */ - 0x9B, 0xC9, 0x9B, 0xCA, 0xB8, 0xA1, 0xE4, 0xB4, /* 0x6C-0x6F */ - 0x9B, 0xCB, 0x9B, 0xCC, 0x9B, 0xCD, 0x9B, 0xCE, /* 0x70-0x73 */ - 0xD4, 0xA1, 0x9B, 0xCF, 0x9B, 0xD0, 0xBA, 0xA3, /* 0x74-0x77 */ - 0xBD, 0xFE, 0x9B, 0xD1, 0x9B, 0xD2, 0x9B, 0xD3, /* 0x78-0x7B */ - 0xE4, 0xBC, 0x9B, 0xD4, 0x9B, 0xD5, 0x9B, 0xD6, /* 0x7C-0x7F */ - - 0x9B, 0xD7, 0x9B, 0xD8, 0xCD, 0xBF, 0x9B, 0xD9, /* 0x80-0x83 */ - 0x9B, 0xDA, 0xC4, 0xF9, 0x9B, 0xDB, 0x9B, 0xDC, /* 0x84-0x87 */ - 0xCF, 0xFB, 0xC9, 0xE6, 0x9B, 0xDD, 0x9B, 0xDE, /* 0x88-0x8B */ - 0xD3, 0xBF, 0x9B, 0xDF, 0xCF, 0xD1, 0x9B, 0xE0, /* 0x8C-0x8F */ - 0x9B, 0xE1, 0xE4, 0xB3, 0x9B, 0xE2, 0xE4, 0xB8, /* 0x90-0x93 */ - 0xE4, 0xB9, 0xCC, 0xE9, 0x9B, 0xE3, 0x9B, 0xE4, /* 0x94-0x97 */ - 0x9B, 0xE5, 0x9B, 0xE6, 0x9B, 0xE7, 0xCC, 0xCE, /* 0x98-0x9B */ - 0x9B, 0xE8, 0xC0, 0xD4, 0xE4, 0xB5, 0xC1, 0xB0, /* 0x9C-0x9F */ - 0xE4, 0xB6, 0xCE, 0xD0, 0x9B, 0xE9, 0xBB, 0xC1, /* 0xA0-0xA3 */ - 0xB5, 0xD3, 0x9B, 0xEA, 0xC8, 0xF3, 0xBD, 0xA7, /* 0xA4-0xA7 */ - 0xD5, 0xC7, 0xC9, 0xAC, 0xB8, 0xA2, 0xE4, 0xCA, /* 0xA8-0xAB */ - 0x9B, 0xEB, 0x9B, 0xEC, 0xE4, 0xCC, 0xD1, 0xC4, /* 0xAC-0xAF */ - 0x9B, 0xED, 0x9B, 0xEE, 0xD2, 0xBA, 0x9B, 0xEF, /* 0xB0-0xB3 */ - 0x9B, 0xF0, 0xBA, 0xAD, 0x9B, 0xF1, 0x9B, 0xF2, /* 0xB4-0xB7 */ - 0xBA, 0xD4, 0x9B, 0xF3, 0x9B, 0xF4, 0x9B, 0xF5, /* 0xB8-0xBB */ - 0x9B, 0xF6, 0x9B, 0xF7, 0x9B, 0xF8, 0xE4, 0xC3, /* 0xBC-0xBF */ - 0xB5, 0xED, 0x9B, 0xF9, 0x9B, 0xFA, 0x9B, 0xFB, /* 0xC0-0xC3 */ - 0xD7, 0xCD, 0xE4, 0xC0, 0xCF, 0xFD, 0xE4, 0xBF, /* 0xC4-0xC7 */ - 0x9B, 0xFC, 0x9B, 0xFD, 0x9B, 0xFE, 0xC1, 0xDC, /* 0xC8-0xCB */ - 0xCC, 0xCA, 0x9C, 0x40, 0x9C, 0x41, 0x9C, 0x42, /* 0xCC-0xCF */ - 0x9C, 0x43, 0xCA, 0xE7, 0x9C, 0x44, 0x9C, 0x45, /* 0xD0-0xD3 */ - 0x9C, 0x46, 0x9C, 0x47, 0xC4, 0xD7, 0x9C, 0x48, /* 0xD4-0xD7 */ - 0xCC, 0xD4, 0xE4, 0xC8, 0x9C, 0x49, 0x9C, 0x4A, /* 0xD8-0xDB */ - 0x9C, 0x4B, 0xE4, 0xC7, 0xE4, 0xC1, 0x9C, 0x4C, /* 0xDC-0xDF */ - 0xE4, 0xC4, 0xB5, 0xAD, 0x9C, 0x4D, 0x9C, 0x4E, /* 0xE0-0xE3 */ - 0xD3, 0xD9, 0x9C, 0x4F, 0xE4, 0xC6, 0x9C, 0x50, /* 0xE4-0xE7 */ - 0x9C, 0x51, 0x9C, 0x52, 0x9C, 0x53, 0xD2, 0xF9, /* 0xE8-0xEB */ - 0xB4, 0xE3, 0x9C, 0x54, 0xBB, 0xB4, 0x9C, 0x55, /* 0xEC-0xEF */ - 0x9C, 0x56, 0xC9, 0xEE, 0x9C, 0x57, 0xB4, 0xBE, /* 0xF0-0xF3 */ - 0x9C, 0x58, 0x9C, 0x59, 0x9C, 0x5A, 0xBB, 0xEC, /* 0xF4-0xF7 */ - 0x9C, 0x5B, 0xD1, 0xCD, 0x9C, 0x5C, 0xCC, 0xED, /* 0xF8-0xFB */ - 0xED, 0xB5, 0x9C, 0x5D, 0x9C, 0x5E, 0x9C, 0x5F, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_6E[512] = { - 0x9C, 0x60, 0x9C, 0x61, 0x9C, 0x62, 0x9C, 0x63, /* 0x00-0x03 */ - 0x9C, 0x64, 0xC7, 0xE5, 0x9C, 0x65, 0x9C, 0x66, /* 0x04-0x07 */ - 0x9C, 0x67, 0x9C, 0x68, 0xD4, 0xA8, 0x9C, 0x69, /* 0x08-0x0B */ - 0xE4, 0xCB, 0xD7, 0xD5, 0xE4, 0xC2, 0x9C, 0x6A, /* 0x0C-0x0F */ - 0xBD, 0xA5, 0xE4, 0xC5, 0x9C, 0x6B, 0x9C, 0x6C, /* 0x10-0x13 */ - 0xD3, 0xE6, 0x9C, 0x6D, 0xE4, 0xC9, 0xC9, 0xF8, /* 0x14-0x17 */ - 0x9C, 0x6E, 0x9C, 0x6F, 0xE4, 0xBE, 0x9C, 0x70, /* 0x18-0x1B */ - 0x9C, 0x71, 0xD3, 0xE5, 0x9C, 0x72, 0x9C, 0x73, /* 0x1C-0x1F */ - 0xC7, 0xFE, 0xB6, 0xC9, 0x9C, 0x74, 0xD4, 0xFC, /* 0x20-0x23 */ - 0xB2, 0xB3, 0xE4, 0xD7, 0x9C, 0x75, 0x9C, 0x76, /* 0x24-0x27 */ - 0x9C, 0x77, 0xCE, 0xC2, 0x9C, 0x78, 0xE4, 0xCD, /* 0x28-0x2B */ - 0x9C, 0x79, 0xCE, 0xBC, 0x9C, 0x7A, 0xB8, 0xDB, /* 0x2C-0x2F */ - 0x9C, 0x7B, 0x9C, 0x7C, 0xE4, 0xD6, 0x9C, 0x7D, /* 0x30-0x33 */ - 0xBF, 0xCA, 0x9C, 0x7E, 0x9C, 0x80, 0x9C, 0x81, /* 0x34-0x37 */ - 0xD3, 0xCE, 0x9C, 0x82, 0xC3, 0xEC, 0x9C, 0x83, /* 0x38-0x3B */ - 0x9C, 0x84, 0x9C, 0x85, 0x9C, 0x86, 0x9C, 0x87, /* 0x3C-0x3F */ - 0x9C, 0x88, 0x9C, 0x89, 0x9C, 0x8A, 0xC5, 0xC8, /* 0x40-0x43 */ - 0xE4, 0xD8, 0x9C, 0x8B, 0x9C, 0x8C, 0x9C, 0x8D, /* 0x44-0x47 */ - 0x9C, 0x8E, 0x9C, 0x8F, 0x9C, 0x90, 0x9C, 0x91, /* 0x48-0x4B */ - 0x9C, 0x92, 0xCD, 0xC4, 0xE4, 0xCF, 0x9C, 0x93, /* 0x4C-0x4F */ - 0x9C, 0x94, 0x9C, 0x95, 0x9C, 0x96, 0xE4, 0xD4, /* 0x50-0x53 */ - 0xE4, 0xD5, 0x9C, 0x97, 0xBA, 0xFE, 0x9C, 0x98, /* 0x54-0x57 */ - 0xCF, 0xE6, 0x9C, 0x99, 0x9C, 0x9A, 0xD5, 0xBF, /* 0x58-0x5B */ - 0x9C, 0x9B, 0x9C, 0x9C, 0x9C, 0x9D, 0xE4, 0xD2, /* 0x5C-0x5F */ - 0x9C, 0x9E, 0x9C, 0x9F, 0x9C, 0xA0, 0x9C, 0xA1, /* 0x60-0x63 */ - 0x9C, 0xA2, 0x9C, 0xA3, 0x9C, 0xA4, 0x9C, 0xA5, /* 0x64-0x67 */ - 0x9C, 0xA6, 0x9C, 0xA7, 0x9C, 0xA8, 0xE4, 0xD0, /* 0x68-0x6B */ - 0x9C, 0xA9, 0x9C, 0xAA, 0xE4, 0xCE, 0x9C, 0xAB, /* 0x6C-0x6F */ - 0x9C, 0xAC, 0x9C, 0xAD, 0x9C, 0xAE, 0x9C, 0xAF, /* 0x70-0x73 */ - 0x9C, 0xB0, 0x9C, 0xB1, 0x9C, 0xB2, 0x9C, 0xB3, /* 0x74-0x77 */ - 0x9C, 0xB4, 0x9C, 0xB5, 0x9C, 0xB6, 0x9C, 0xB7, /* 0x78-0x7B */ - 0x9C, 0xB8, 0x9C, 0xB9, 0xCD, 0xE5, 0xCA, 0xAA, /* 0x7C-0x7F */ - - 0x9C, 0xBA, 0x9C, 0xBB, 0x9C, 0xBC, 0xC0, 0xA3, /* 0x80-0x83 */ - 0x9C, 0xBD, 0xBD, 0xA6, 0xE4, 0xD3, 0x9C, 0xBE, /* 0x84-0x87 */ - 0x9C, 0xBF, 0xB8, 0xC8, 0x9C, 0xC0, 0x9C, 0xC1, /* 0x88-0x8B */ - 0x9C, 0xC2, 0x9C, 0xC3, 0x9C, 0xC4, 0xE4, 0xE7, /* 0x8C-0x8F */ - 0xD4, 0xB4, 0x9C, 0xC5, 0x9C, 0xC6, 0x9C, 0xC7, /* 0x90-0x93 */ - 0x9C, 0xC8, 0x9C, 0xC9, 0x9C, 0xCA, 0x9C, 0xCB, /* 0x94-0x97 */ - 0xE4, 0xDB, 0x9C, 0xCC, 0x9C, 0xCD, 0x9C, 0xCE, /* 0x98-0x9B */ - 0xC1, 0xEF, 0x9C, 0xCF, 0x9C, 0xD0, 0xE4, 0xE9, /* 0x9C-0x9F */ - 0x9C, 0xD1, 0x9C, 0xD2, 0xD2, 0xE7, 0x9C, 0xD3, /* 0xA0-0xA3 */ - 0x9C, 0xD4, 0xE4, 0xDF, 0x9C, 0xD5, 0xE4, 0xE0, /* 0xA4-0xA7 */ - 0x9C, 0xD6, 0x9C, 0xD7, 0xCF, 0xAA, 0x9C, 0xD8, /* 0xA8-0xAB */ - 0x9C, 0xD9, 0x9C, 0xDA, 0x9C, 0xDB, 0xCB, 0xDD, /* 0xAC-0xAF */ - 0x9C, 0xDC, 0xE4, 0xDA, 0xE4, 0xD1, 0x9C, 0xDD, /* 0xB0-0xB3 */ - 0xE4, 0xE5, 0x9C, 0xDE, 0xC8, 0xDC, 0xE4, 0xE3, /* 0xB4-0xB7 */ - 0x9C, 0xDF, 0x9C, 0xE0, 0xC4, 0xE7, 0xE4, 0xE2, /* 0xB8-0xBB */ - 0x9C, 0xE1, 0xE4, 0xE1, 0x9C, 0xE2, 0x9C, 0xE3, /* 0xBC-0xBF */ - 0x9C, 0xE4, 0xB3, 0xFC, 0xE4, 0xE8, 0x9C, 0xE5, /* 0xC0-0xC3 */ - 0x9C, 0xE6, 0x9C, 0xE7, 0x9C, 0xE8, 0xB5, 0xE1, /* 0xC4-0xC7 */ - 0x9C, 0xE9, 0x9C, 0xEA, 0x9C, 0xEB, 0xD7, 0xCC, /* 0xC8-0xCB */ - 0x9C, 0xEC, 0x9C, 0xED, 0x9C, 0xEE, 0xE4, 0xE6, /* 0xCC-0xCF */ - 0x9C, 0xEF, 0xBB, 0xAC, 0x9C, 0xF0, 0xD7, 0xD2, /* 0xD0-0xD3 */ - 0xCC, 0xCF, 0xEB, 0xF8, 0x9C, 0xF1, 0xE4, 0xE4, /* 0xD4-0xD7 */ - 0x9C, 0xF2, 0x9C, 0xF3, 0xB9, 0xF6, 0x9C, 0xF4, /* 0xD8-0xDB */ - 0x9C, 0xF5, 0x9C, 0xF6, 0xD6, 0xCD, 0xE4, 0xD9, /* 0xDC-0xDF */ - 0xE4, 0xDC, 0xC2, 0xFA, 0xE4, 0xDE, 0x9C, 0xF7, /* 0xE0-0xE3 */ - 0xC2, 0xCB, 0xC0, 0xC4, 0xC2, 0xD0, 0x9C, 0xF8, /* 0xE4-0xE7 */ - 0xB1, 0xF5, 0xCC, 0xB2, 0x9C, 0xF9, 0x9C, 0xFA, /* 0xE8-0xEB */ - 0x9C, 0xFB, 0x9C, 0xFC, 0x9C, 0xFD, 0x9C, 0xFE, /* 0xEC-0xEF */ - 0x9D, 0x40, 0x9D, 0x41, 0x9D, 0x42, 0x9D, 0x43, /* 0xF0-0xF3 */ - 0xB5, 0xCE, 0x9D, 0x44, 0x9D, 0x45, 0x9D, 0x46, /* 0xF4-0xF7 */ - 0x9D, 0x47, 0xE4, 0xEF, 0x9D, 0x48, 0x9D, 0x49, /* 0xF8-0xFB */ - 0x9D, 0x4A, 0x9D, 0x4B, 0x9D, 0x4C, 0x9D, 0x4D, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_6F[512] = { - 0x9D, 0x4E, 0x9D, 0x4F, 0xC6, 0xAF, 0x9D, 0x50, /* 0x00-0x03 */ - 0x9D, 0x51, 0x9D, 0x52, 0xC6, 0xE1, 0x9D, 0x53, /* 0x04-0x07 */ - 0x9D, 0x54, 0xE4, 0xF5, 0x9D, 0x55, 0x9D, 0x56, /* 0x08-0x0B */ - 0x9D, 0x57, 0x9D, 0x58, 0x9D, 0x59, 0xC2, 0xA9, /* 0x0C-0x0F */ - 0x9D, 0x5A, 0x9D, 0x5B, 0x9D, 0x5C, 0xC0, 0xEC, /* 0x10-0x13 */ - 0xD1, 0xDD, 0xE4, 0xEE, 0x9D, 0x5D, 0x9D, 0x5E, /* 0x14-0x17 */ - 0x9D, 0x5F, 0x9D, 0x60, 0x9D, 0x61, 0x9D, 0x62, /* 0x18-0x1B */ - 0x9D, 0x63, 0x9D, 0x64, 0x9D, 0x65, 0x9D, 0x66, /* 0x1C-0x1F */ - 0xC4, 0xAE, 0x9D, 0x67, 0x9D, 0x68, 0x9D, 0x69, /* 0x20-0x23 */ - 0xE4, 0xED, 0x9D, 0x6A, 0x9D, 0x6B, 0x9D, 0x6C, /* 0x24-0x27 */ - 0x9D, 0x6D, 0xE4, 0xF6, 0xE4, 0xF4, 0xC2, 0xFE, /* 0x28-0x2B */ - 0x9D, 0x6E, 0xE4, 0xDD, 0x9D, 0x6F, 0xE4, 0xF0, /* 0x2C-0x2F */ - 0x9D, 0x70, 0xCA, 0xFE, 0x9D, 0x71, 0xD5, 0xC4, /* 0x30-0x33 */ - 0x9D, 0x72, 0x9D, 0x73, 0xE4, 0xF1, 0x9D, 0x74, /* 0x34-0x37 */ - 0x9D, 0x75, 0x9D, 0x76, 0x9D, 0x77, 0x9D, 0x78, /* 0x38-0x3B */ - 0x9D, 0x79, 0x9D, 0x7A, 0xD1, 0xFA, 0x9D, 0x7B, /* 0x3C-0x3F */ - 0x9D, 0x7C, 0x9D, 0x7D, 0x9D, 0x7E, 0x9D, 0x80, /* 0x40-0x43 */ - 0x9D, 0x81, 0x9D, 0x82, 0xE4, 0xEB, 0xE4, 0xEC, /* 0x44-0x47 */ - 0x9D, 0x83, 0x9D, 0x84, 0x9D, 0x85, 0xE4, 0xF2, /* 0x48-0x4B */ - 0x9D, 0x86, 0xCE, 0xAB, 0x9D, 0x87, 0x9D, 0x88, /* 0x4C-0x4F */ - 0x9D, 0x89, 0x9D, 0x8A, 0x9D, 0x8B, 0x9D, 0x8C, /* 0x50-0x53 */ - 0x9D, 0x8D, 0x9D, 0x8E, 0x9D, 0x8F, 0x9D, 0x90, /* 0x54-0x57 */ - 0xC5, 0xCB, 0x9D, 0x91, 0x9D, 0x92, 0x9D, 0x93, /* 0x58-0x5B */ - 0xC7, 0xB1, 0x9D, 0x94, 0xC2, 0xBA, 0x9D, 0x95, /* 0x5C-0x5F */ - 0x9D, 0x96, 0x9D, 0x97, 0xE4, 0xEA, 0x9D, 0x98, /* 0x60-0x63 */ - 0x9D, 0x99, 0x9D, 0x9A, 0xC1, 0xCA, 0x9D, 0x9B, /* 0x64-0x67 */ - 0x9D, 0x9C, 0x9D, 0x9D, 0x9D, 0x9E, 0x9D, 0x9F, /* 0x68-0x6B */ - 0x9D, 0xA0, 0xCC, 0xB6, 0xB3, 0xB1, 0x9D, 0xA1, /* 0x6C-0x6F */ - 0x9D, 0xA2, 0x9D, 0xA3, 0xE4, 0xFB, 0x9D, 0xA4, /* 0x70-0x73 */ - 0xE4, 0xF3, 0x9D, 0xA5, 0x9D, 0xA6, 0x9D, 0xA7, /* 0x74-0x77 */ - 0xE4, 0xFA, 0x9D, 0xA8, 0xE4, 0xFD, 0x9D, 0xA9, /* 0x78-0x7B */ - 0xE4, 0xFC, 0x9D, 0xAA, 0x9D, 0xAB, 0x9D, 0xAC, /* 0x7C-0x7F */ - - 0x9D, 0xAD, 0x9D, 0xAE, 0x9D, 0xAF, 0x9D, 0xB0, /* 0x80-0x83 */ - 0xB3, 0xCE, 0x9D, 0xB1, 0x9D, 0xB2, 0x9D, 0xB3, /* 0x84-0x87 */ - 0xB3, 0xBA, 0xE4, 0xF7, 0x9D, 0xB4, 0x9D, 0xB5, /* 0x88-0x8B */ - 0xE4, 0xF9, 0xE4, 0xF8, 0xC5, 0xEC, 0x9D, 0xB6, /* 0x8C-0x8F */ - 0x9D, 0xB7, 0x9D, 0xB8, 0x9D, 0xB9, 0x9D, 0xBA, /* 0x90-0x93 */ - 0x9D, 0xBB, 0x9D, 0xBC, 0x9D, 0xBD, 0x9D, 0xBE, /* 0x94-0x97 */ - 0x9D, 0xBF, 0x9D, 0xC0, 0x9D, 0xC1, 0x9D, 0xC2, /* 0x98-0x9B */ - 0xC0, 0xBD, 0x9D, 0xC3, 0x9D, 0xC4, 0x9D, 0xC5, /* 0x9C-0x9F */ - 0x9D, 0xC6, 0xD4, 0xE8, 0x9D, 0xC7, 0x9D, 0xC8, /* 0xA0-0xA3 */ - 0x9D, 0xC9, 0x9D, 0xCA, 0x9D, 0xCB, 0xE5, 0xA2, /* 0xA4-0xA7 */ - 0x9D, 0xCC, 0x9D, 0xCD, 0x9D, 0xCE, 0x9D, 0xCF, /* 0xA8-0xAB */ - 0x9D, 0xD0, 0x9D, 0xD1, 0x9D, 0xD2, 0x9D, 0xD3, /* 0xAC-0xAF */ - 0x9D, 0xD4, 0x9D, 0xD5, 0x9D, 0xD6, 0xB0, 0xC4, /* 0xB0-0xB3 */ - 0x9D, 0xD7, 0x9D, 0xD8, 0xE5, 0xA4, 0x9D, 0xD9, /* 0xB4-0xB7 */ - 0x9D, 0xDA, 0xE5, 0xA3, 0x9D, 0xDB, 0x9D, 0xDC, /* 0xB8-0xBB */ - 0x9D, 0xDD, 0x9D, 0xDE, 0x9D, 0xDF, 0x9D, 0xE0, /* 0xBC-0xBF */ - 0xBC, 0xA4, 0x9D, 0xE1, 0xE5, 0xA5, 0x9D, 0xE2, /* 0xC0-0xC3 */ - 0x9D, 0xE3, 0x9D, 0xE4, 0x9D, 0xE5, 0x9D, 0xE6, /* 0xC4-0xC7 */ - 0x9D, 0xE7, 0xE5, 0xA1, 0x9D, 0xE8, 0x9D, 0xE9, /* 0xC8-0xCB */ - 0x9D, 0xEA, 0x9D, 0xEB, 0x9D, 0xEC, 0x9D, 0xED, /* 0xCC-0xCF */ - 0x9D, 0xEE, 0xE4, 0xFE, 0xB1, 0xF4, 0x9D, 0xEF, /* 0xD0-0xD3 */ - 0x9D, 0xF0, 0x9D, 0xF1, 0x9D, 0xF2, 0x9D, 0xF3, /* 0xD4-0xD7 */ - 0x9D, 0xF4, 0x9D, 0xF5, 0x9D, 0xF6, 0x9D, 0xF7, /* 0xD8-0xDB */ - 0x9D, 0xF8, 0x9D, 0xF9, 0xE5, 0xA8, 0x9D, 0xFA, /* 0xDC-0xDF */ - 0xE5, 0xA9, 0xE5, 0xA6, 0x9D, 0xFB, 0x9D, 0xFC, /* 0xE0-0xE3 */ - 0x9D, 0xFD, 0x9D, 0xFE, 0x9E, 0x40, 0x9E, 0x41, /* 0xE4-0xE7 */ - 0x9E, 0x42, 0x9E, 0x43, 0x9E, 0x44, 0x9E, 0x45, /* 0xE8-0xEB */ - 0x9E, 0x46, 0x9E, 0x47, 0xE5, 0xA7, 0xE5, 0xAA, /* 0xEC-0xEF */ - 0x9E, 0x48, 0x9E, 0x49, 0x9E, 0x4A, 0x9E, 0x4B, /* 0xF0-0xF3 */ - 0x9E, 0x4C, 0x9E, 0x4D, 0x9E, 0x4E, 0x9E, 0x4F, /* 0xF4-0xF7 */ - 0x9E, 0x50, 0x9E, 0x51, 0x9E, 0x52, 0x9E, 0x53, /* 0xF8-0xFB */ - 0x9E, 0x54, 0x9E, 0x55, 0x9E, 0x56, 0x9E, 0x57, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_70[512] = { - 0x9E, 0x58, 0x9E, 0x59, 0x9E, 0x5A, 0x9E, 0x5B, /* 0x00-0x03 */ - 0x9E, 0x5C, 0x9E, 0x5D, 0x9E, 0x5E, 0x9E, 0x5F, /* 0x04-0x07 */ - 0x9E, 0x60, 0x9E, 0x61, 0x9E, 0x62, 0x9E, 0x63, /* 0x08-0x0B */ - 0x9E, 0x64, 0x9E, 0x65, 0x9E, 0x66, 0x9E, 0x67, /* 0x0C-0x0F */ - 0x9E, 0x68, 0xC6, 0xD9, 0x9E, 0x69, 0x9E, 0x6A, /* 0x10-0x13 */ - 0x9E, 0x6B, 0x9E, 0x6C, 0x9E, 0x6D, 0x9E, 0x6E, /* 0x14-0x17 */ - 0x9E, 0x6F, 0x9E, 0x70, 0xE5, 0xAB, 0xE5, 0xAD, /* 0x18-0x1B */ - 0x9E, 0x71, 0x9E, 0x72, 0x9E, 0x73, 0x9E, 0x74, /* 0x1C-0x1F */ - 0x9E, 0x75, 0x9E, 0x76, 0x9E, 0x77, 0xE5, 0xAC, /* 0x20-0x23 */ - 0x9E, 0x78, 0x9E, 0x79, 0x9E, 0x7A, 0x9E, 0x7B, /* 0x24-0x27 */ - 0x9E, 0x7C, 0x9E, 0x7D, 0x9E, 0x7E, 0x9E, 0x80, /* 0x28-0x2B */ - 0x9E, 0x81, 0x9E, 0x82, 0x9E, 0x83, 0x9E, 0x84, /* 0x2C-0x2F */ - 0x9E, 0x85, 0x9E, 0x86, 0x9E, 0x87, 0x9E, 0x88, /* 0x30-0x33 */ - 0x9E, 0x89, 0xE5, 0xAF, 0x9E, 0x8A, 0x9E, 0x8B, /* 0x34-0x37 */ - 0x9E, 0x8C, 0xE5, 0xAE, 0x9E, 0x8D, 0x9E, 0x8E, /* 0x38-0x3B */ - 0x9E, 0x8F, 0x9E, 0x90, 0x9E, 0x91, 0x9E, 0x92, /* 0x3C-0x3F */ - 0x9E, 0x93, 0x9E, 0x94, 0x9E, 0x95, 0x9E, 0x96, /* 0x40-0x43 */ - 0x9E, 0x97, 0x9E, 0x98, 0x9E, 0x99, 0x9E, 0x9A, /* 0x44-0x47 */ - 0x9E, 0x9B, 0x9E, 0x9C, 0x9E, 0x9D, 0x9E, 0x9E, /* 0x48-0x4B */ - 0xB9, 0xE0, 0x9E, 0x9F, 0x9E, 0xA0, 0xE5, 0xB0, /* 0x4C-0x4F */ - 0x9E, 0xA1, 0x9E, 0xA2, 0x9E, 0xA3, 0x9E, 0xA4, /* 0x50-0x53 */ - 0x9E, 0xA5, 0x9E, 0xA6, 0x9E, 0xA7, 0x9E, 0xA8, /* 0x54-0x57 */ - 0x9E, 0xA9, 0x9E, 0xAA, 0x9E, 0xAB, 0x9E, 0xAC, /* 0x58-0x5B */ - 0x9E, 0xAD, 0x9E, 0xAE, 0xE5, 0xB1, 0x9E, 0xAF, /* 0x5C-0x5F */ - 0x9E, 0xB0, 0x9E, 0xB1, 0x9E, 0xB2, 0x9E, 0xB3, /* 0x60-0x63 */ - 0x9E, 0xB4, 0x9E, 0xB5, 0x9E, 0xB6, 0x9E, 0xB7, /* 0x64-0x67 */ - 0x9E, 0xB8, 0x9E, 0xB9, 0x9E, 0xBA, 0xBB, 0xF0, /* 0x68-0x6B */ - 0xEC, 0xE1, 0xC3, 0xF0, 0x9E, 0xBB, 0xB5, 0xC6, /* 0x6C-0x6F */ - 0xBB, 0xD2, 0x9E, 0xBC, 0x9E, 0xBD, 0x9E, 0xBE, /* 0x70-0x73 */ - 0x9E, 0xBF, 0xC1, 0xE9, 0xD4, 0xEE, 0x9E, 0xC0, /* 0x74-0x77 */ - 0xBE, 0xC4, 0x9E, 0xC1, 0x9E, 0xC2, 0x9E, 0xC3, /* 0x78-0x7B */ - 0xD7, 0xC6, 0x9E, 0xC4, 0xD4, 0xD6, 0xB2, 0xD3, /* 0x7C-0x7F */ - - 0xEC, 0xBE, 0x9E, 0xC5, 0x9E, 0xC6, 0x9E, 0xC7, /* 0x80-0x83 */ - 0x9E, 0xC8, 0xEA, 0xC1, 0x9E, 0xC9, 0x9E, 0xCA, /* 0x84-0x87 */ - 0x9E, 0xCB, 0xC2, 0xAF, 0xB4, 0xB6, 0x9E, 0xCC, /* 0x88-0x8B */ - 0x9E, 0xCD, 0x9E, 0xCE, 0xD1, 0xD7, 0x9E, 0xCF, /* 0x8C-0x8F */ - 0x9E, 0xD0, 0x9E, 0xD1, 0xB3, 0xB4, 0x9E, 0xD2, /* 0x90-0x93 */ - 0xC8, 0xB2, 0xBF, 0xBB, 0xEC, 0xC0, 0x9E, 0xD3, /* 0x94-0x97 */ - 0x9E, 0xD4, 0xD6, 0xCB, 0x9E, 0xD5, 0x9E, 0xD6, /* 0x98-0x9B */ - 0xEC, 0xBF, 0xEC, 0xC1, 0x9E, 0xD7, 0x9E, 0xD8, /* 0x9C-0x9F */ - 0x9E, 0xD9, 0x9E, 0xDA, 0x9E, 0xDB, 0x9E, 0xDC, /* 0xA0-0xA3 */ - 0x9E, 0xDD, 0x9E, 0xDE, 0x9E, 0xDF, 0x9E, 0xE0, /* 0xA4-0xA7 */ - 0x9E, 0xE1, 0x9E, 0xE2, 0x9E, 0xE3, 0xEC, 0xC5, /* 0xA8-0xAB */ - 0xBE, 0xE6, 0xCC, 0xBF, 0xC5, 0xDA, 0xBE, 0xBC, /* 0xAC-0xAF */ - 0x9E, 0xE4, 0xEC, 0xC6, 0x9E, 0xE5, 0xB1, 0xFE, /* 0xB0-0xB3 */ - 0x9E, 0xE6, 0x9E, 0xE7, 0x9E, 0xE8, 0xEC, 0xC4, /* 0xB4-0xB7 */ - 0xD5, 0xA8, 0xB5, 0xE3, 0x9E, 0xE9, 0xEC, 0xC2, /* 0xB8-0xBB */ - 0xC1, 0xB6, 0xB3, 0xE3, 0x9E, 0xEA, 0x9E, 0xEB, /* 0xBC-0xBF */ - 0xEC, 0xC3, 0xCB, 0xB8, 0xC0, 0xC3, 0xCC, 0xFE, /* 0xC0-0xC3 */ - 0x9E, 0xEC, 0x9E, 0xED, 0x9E, 0xEE, 0x9E, 0xEF, /* 0xC4-0xC7 */ - 0xC1, 0xD2, 0x9E, 0xF0, 0xEC, 0xC8, 0x9E, 0xF1, /* 0xC8-0xCB */ - 0x9E, 0xF2, 0x9E, 0xF3, 0x9E, 0xF4, 0x9E, 0xF5, /* 0xCC-0xCF */ - 0x9E, 0xF6, 0x9E, 0xF7, 0x9E, 0xF8, 0x9E, 0xF9, /* 0xD0-0xD3 */ - 0x9E, 0xFA, 0x9E, 0xFB, 0x9E, 0xFC, 0x9E, 0xFD, /* 0xD4-0xD7 */ - 0xBA, 0xE6, 0xC0, 0xD3, 0x9E, 0xFE, 0xD6, 0xF2, /* 0xD8-0xDB */ - 0x9F, 0x40, 0x9F, 0x41, 0x9F, 0x42, 0xD1, 0xCC, /* 0xDC-0xDF */ - 0x9F, 0x43, 0x9F, 0x44, 0x9F, 0x45, 0x9F, 0x46, /* 0xE0-0xE3 */ - 0xBF, 0xBE, 0x9F, 0x47, 0xB7, 0xB3, 0xC9, 0xD5, /* 0xE4-0xE7 */ - 0xEC, 0xC7, 0xBB, 0xE2, 0x9F, 0x48, 0xCC, 0xCC, /* 0xE8-0xEB */ - 0xBD, 0xFD, 0xC8, 0xC8, 0x9F, 0x49, 0xCF, 0xA9, /* 0xEC-0xEF */ - 0x9F, 0x4A, 0x9F, 0x4B, 0x9F, 0x4C, 0x9F, 0x4D, /* 0xF0-0xF3 */ - 0x9F, 0x4E, 0x9F, 0x4F, 0x9F, 0x50, 0xCD, 0xE9, /* 0xF4-0xF7 */ - 0x9F, 0x51, 0xC5, 0xEB, 0x9F, 0x52, 0x9F, 0x53, /* 0xF8-0xFB */ - 0x9F, 0x54, 0xB7, 0xE9, 0x9F, 0x55, 0x9F, 0x56, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_71[512] = { - 0x9F, 0x57, 0x9F, 0x58, 0x9F, 0x59, 0x9F, 0x5A, /* 0x00-0x03 */ - 0x9F, 0x5B, 0x9F, 0x5C, 0x9F, 0x5D, 0x9F, 0x5E, /* 0x04-0x07 */ - 0x9F, 0x5F, 0xD1, 0xC9, 0xBA, 0xB8, 0x9F, 0x60, /* 0x08-0x0B */ - 0x9F, 0x61, 0x9F, 0x62, 0x9F, 0x63, 0x9F, 0x64, /* 0x0C-0x0F */ - 0xEC, 0xC9, 0x9F, 0x65, 0x9F, 0x66, 0xEC, 0xCA, /* 0x10-0x13 */ - 0x9F, 0x67, 0xBB, 0xC0, 0xEC, 0xCB, 0x9F, 0x68, /* 0x14-0x17 */ - 0xEC, 0xE2, 0xB1, 0xBA, 0xB7, 0xD9, 0x9F, 0x69, /* 0x18-0x1B */ - 0x9F, 0x6A, 0x9F, 0x6B, 0x9F, 0x6C, 0x9F, 0x6D, /* 0x1C-0x1F */ - 0x9F, 0x6E, 0x9F, 0x6F, 0x9F, 0x70, 0x9F, 0x71, /* 0x20-0x23 */ - 0x9F, 0x72, 0x9F, 0x73, 0xBD, 0xB9, 0x9F, 0x74, /* 0x24-0x27 */ - 0x9F, 0x75, 0x9F, 0x76, 0x9F, 0x77, 0x9F, 0x78, /* 0x28-0x2B */ - 0x9F, 0x79, 0x9F, 0x7A, 0x9F, 0x7B, 0xEC, 0xCC, /* 0x2C-0x2F */ - 0xD1, 0xE6, 0xEC, 0xCD, 0x9F, 0x7C, 0x9F, 0x7D, /* 0x30-0x33 */ - 0x9F, 0x7E, 0x9F, 0x80, 0xC8, 0xBB, 0x9F, 0x81, /* 0x34-0x37 */ - 0x9F, 0x82, 0x9F, 0x83, 0x9F, 0x84, 0x9F, 0x85, /* 0x38-0x3B */ - 0x9F, 0x86, 0x9F, 0x87, 0x9F, 0x88, 0x9F, 0x89, /* 0x3C-0x3F */ - 0x9F, 0x8A, 0x9F, 0x8B, 0x9F, 0x8C, 0x9F, 0x8D, /* 0x40-0x43 */ - 0x9F, 0x8E, 0xEC, 0xD1, 0x9F, 0x8F, 0x9F, 0x90, /* 0x44-0x47 */ - 0x9F, 0x91, 0x9F, 0x92, 0xEC, 0xD3, 0x9F, 0x93, /* 0x48-0x4B */ - 0xBB, 0xCD, 0x9F, 0x94, 0xBC, 0xE5, 0x9F, 0x95, /* 0x4C-0x4F */ - 0x9F, 0x96, 0x9F, 0x97, 0x9F, 0x98, 0x9F, 0x99, /* 0x50-0x53 */ - 0x9F, 0x9A, 0x9F, 0x9B, 0x9F, 0x9C, 0x9F, 0x9D, /* 0x54-0x57 */ - 0x9F, 0x9E, 0x9F, 0x9F, 0x9F, 0xA0, 0x9F, 0xA1, /* 0x58-0x5B */ - 0xEC, 0xCF, 0x9F, 0xA2, 0xC9, 0xB7, 0x9F, 0xA3, /* 0x5C-0x5F */ - 0x9F, 0xA4, 0x9F, 0xA5, 0x9F, 0xA6, 0x9F, 0xA7, /* 0x60-0x63 */ - 0xC3, 0xBA, 0x9F, 0xA8, 0xEC, 0xE3, 0xD5, 0xD5, /* 0x64-0x67 */ - 0xEC, 0xD0, 0x9F, 0xA9, 0x9F, 0xAA, 0x9F, 0xAB, /* 0x68-0x6B */ - 0x9F, 0xAC, 0x9F, 0xAD, 0xD6, 0xF3, 0x9F, 0xAE, /* 0x6C-0x6F */ - 0x9F, 0xAF, 0x9F, 0xB0, 0xEC, 0xD2, 0xEC, 0xCE, /* 0x70-0x73 */ - 0x9F, 0xB1, 0x9F, 0xB2, 0x9F, 0xB3, 0x9F, 0xB4, /* 0x74-0x77 */ - 0xEC, 0xD4, 0x9F, 0xB5, 0xEC, 0xD5, 0x9F, 0xB6, /* 0x78-0x7B */ - 0x9F, 0xB7, 0xC9, 0xBF, 0x9F, 0xB8, 0x9F, 0xB9, /* 0x7C-0x7F */ - - 0x9F, 0xBA, 0x9F, 0xBB, 0x9F, 0xBC, 0x9F, 0xBD, /* 0x80-0x83 */ - 0xCF, 0xA8, 0x9F, 0xBE, 0x9F, 0xBF, 0x9F, 0xC0, /* 0x84-0x87 */ - 0x9F, 0xC1, 0x9F, 0xC2, 0xD0, 0xDC, 0x9F, 0xC3, /* 0x88-0x8B */ - 0x9F, 0xC4, 0x9F, 0xC5, 0x9F, 0xC6, 0xD1, 0xAC, /* 0x8C-0x8F */ - 0x9F, 0xC7, 0x9F, 0xC8, 0x9F, 0xC9, 0x9F, 0xCA, /* 0x90-0x93 */ - 0xC8, 0xDB, 0x9F, 0xCB, 0x9F, 0xCC, 0x9F, 0xCD, /* 0x94-0x97 */ - 0xEC, 0xD6, 0xCE, 0xF5, 0x9F, 0xCE, 0x9F, 0xCF, /* 0x98-0x9B */ - 0x9F, 0xD0, 0x9F, 0xD1, 0x9F, 0xD2, 0xCA, 0xEC, /* 0x9C-0x9F */ - 0xEC, 0xDA, 0x9F, 0xD3, 0x9F, 0xD4, 0x9F, 0xD5, /* 0xA0-0xA3 */ - 0x9F, 0xD6, 0x9F, 0xD7, 0x9F, 0xD8, 0x9F, 0xD9, /* 0xA4-0xA7 */ - 0xEC, 0xD9, 0x9F, 0xDA, 0x9F, 0xDB, 0x9F, 0xDC, /* 0xA8-0xAB */ - 0xB0, 0xBE, 0x9F, 0xDD, 0x9F, 0xDE, 0x9F, 0xDF, /* 0xAC-0xAF */ - 0x9F, 0xE0, 0x9F, 0xE1, 0x9F, 0xE2, 0xEC, 0xD7, /* 0xB0-0xB3 */ - 0x9F, 0xE3, 0xEC, 0xD8, 0x9F, 0xE4, 0x9F, 0xE5, /* 0xB4-0xB7 */ - 0x9F, 0xE6, 0xEC, 0xE4, 0x9F, 0xE7, 0x9F, 0xE8, /* 0xB8-0xBB */ - 0x9F, 0xE9, 0x9F, 0xEA, 0x9F, 0xEB, 0x9F, 0xEC, /* 0xBC-0xBF */ - 0x9F, 0xED, 0x9F, 0xEE, 0x9F, 0xEF, 0xC8, 0xBC, /* 0xC0-0xC3 */ - 0x9F, 0xF0, 0x9F, 0xF1, 0x9F, 0xF2, 0x9F, 0xF3, /* 0xC4-0xC7 */ - 0x9F, 0xF4, 0x9F, 0xF5, 0x9F, 0xF6, 0x9F, 0xF7, /* 0xC8-0xCB */ - 0x9F, 0xF8, 0x9F, 0xF9, 0xC1, 0xC7, 0x9F, 0xFA, /* 0xCC-0xCF */ - 0x9F, 0xFB, 0x9F, 0xFC, 0x9F, 0xFD, 0x9F, 0xFE, /* 0xD0-0xD3 */ - 0xEC, 0xDC, 0xD1, 0xE0, 0xA0, 0x40, 0xA0, 0x41, /* 0xD4-0xD7 */ - 0xA0, 0x42, 0xA0, 0x43, 0xA0, 0x44, 0xA0, 0x45, /* 0xD8-0xDB */ - 0xA0, 0x46, 0xA0, 0x47, 0xA0, 0x48, 0xA0, 0x49, /* 0xDC-0xDF */ - 0xEC, 0xDB, 0xA0, 0x4A, 0xA0, 0x4B, 0xA0, 0x4C, /* 0xE0-0xE3 */ - 0xA0, 0x4D, 0xD4, 0xEF, 0xA0, 0x4E, 0xEC, 0xDD, /* 0xE4-0xE7 */ - 0xA0, 0x4F, 0xA0, 0x50, 0xA0, 0x51, 0xA0, 0x52, /* 0xE8-0xEB */ - 0xA0, 0x53, 0xA0, 0x54, 0xDB, 0xC6, 0xA0, 0x55, /* 0xEC-0xEF */ - 0xA0, 0x56, 0xA0, 0x57, 0xA0, 0x58, 0xA0, 0x59, /* 0xF0-0xF3 */ - 0xA0, 0x5A, 0xA0, 0x5B, 0xA0, 0x5C, 0xA0, 0x5D, /* 0xF4-0xF7 */ - 0xA0, 0x5E, 0xEC, 0xDE, 0xA0, 0x5F, 0xA0, 0x60, /* 0xF8-0xFB */ - 0xA0, 0x61, 0xA0, 0x62, 0xA0, 0x63, 0xA0, 0x64, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_72[512] = { - 0xA0, 0x65, 0xA0, 0x66, 0xA0, 0x67, 0xA0, 0x68, /* 0x00-0x03 */ - 0xA0, 0x69, 0xA0, 0x6A, 0xB1, 0xAC, 0xA0, 0x6B, /* 0x04-0x07 */ - 0xA0, 0x6C, 0xA0, 0x6D, 0xA0, 0x6E, 0xA0, 0x6F, /* 0x08-0x0B */ - 0xA0, 0x70, 0xA0, 0x71, 0xA0, 0x72, 0xA0, 0x73, /* 0x0C-0x0F */ - 0xA0, 0x74, 0xA0, 0x75, 0xA0, 0x76, 0xA0, 0x77, /* 0x10-0x13 */ - 0xA0, 0x78, 0xA0, 0x79, 0xA0, 0x7A, 0xA0, 0x7B, /* 0x14-0x17 */ - 0xA0, 0x7C, 0xA0, 0x7D, 0xA0, 0x7E, 0xA0, 0x80, /* 0x18-0x1B */ - 0xA0, 0x81, 0xEC, 0xDF, 0xA0, 0x82, 0xA0, 0x83, /* 0x1C-0x1F */ - 0xA0, 0x84, 0xA0, 0x85, 0xA0, 0x86, 0xA0, 0x87, /* 0x20-0x23 */ - 0xA0, 0x88, 0xA0, 0x89, 0xA0, 0x8A, 0xA0, 0x8B, /* 0x24-0x27 */ - 0xEC, 0xE0, 0xA0, 0x8C, 0xD7, 0xA6, 0xA0, 0x8D, /* 0x28-0x2B */ - 0xC5, 0xC0, 0xA0, 0x8E, 0xA0, 0x8F, 0xA0, 0x90, /* 0x2C-0x2F */ - 0xEB, 0xBC, 0xB0, 0xAE, 0xA0, 0x91, 0xA0, 0x92, /* 0x30-0x33 */ - 0xA0, 0x93, 0xBE, 0xF4, 0xB8, 0xB8, 0xD2, 0xAF, /* 0x34-0x37 */ - 0xB0, 0xD6, 0xB5, 0xF9, 0xA0, 0x94, 0xD8, 0xB3, /* 0x38-0x3B */ - 0xA0, 0x95, 0xCB, 0xAC, 0xA0, 0x96, 0xE3, 0xDD, /* 0x3C-0x3F */ - 0xA0, 0x97, 0xA0, 0x98, 0xA0, 0x99, 0xA0, 0x9A, /* 0x40-0x43 */ - 0xA0, 0x9B, 0xA0, 0x9C, 0xA0, 0x9D, 0xC6, 0xAC, /* 0x44-0x47 */ - 0xB0, 0xE6, 0xA0, 0x9E, 0xA0, 0x9F, 0xA0, 0xA0, /* 0x48-0x4B */ - 0xC5, 0xC6, 0xEB, 0xB9, 0xA0, 0xA1, 0xA0, 0xA2, /* 0x4C-0x4F */ - 0xA0, 0xA3, 0xA0, 0xA4, 0xEB, 0xBA, 0xA0, 0xA5, /* 0x50-0x53 */ - 0xA0, 0xA6, 0xA0, 0xA7, 0xEB, 0xBB, 0xA0, 0xA8, /* 0x54-0x57 */ - 0xA0, 0xA9, 0xD1, 0xC0, 0xA0, 0xAA, 0xC5, 0xA3, /* 0x58-0x5B */ - 0xA0, 0xAB, 0xEA, 0xF2, 0xA0, 0xAC, 0xC4, 0xB2, /* 0x5C-0x5F */ - 0xA0, 0xAD, 0xC4, 0xB5, 0xC0, 0xCE, 0xA0, 0xAE, /* 0x60-0x63 */ - 0xA0, 0xAF, 0xA0, 0xB0, 0xEA, 0xF3, 0xC4, 0xC1, /* 0x64-0x67 */ - 0xA0, 0xB1, 0xCE, 0xEF, 0xA0, 0xB2, 0xA0, 0xB3, /* 0x68-0x6B */ - 0xA0, 0xB4, 0xA0, 0xB5, 0xEA, 0xF0, 0xEA, 0xF4, /* 0x6C-0x6F */ - 0xA0, 0xB6, 0xA0, 0xB7, 0xC9, 0xFC, 0xA0, 0xB8, /* 0x70-0x73 */ - 0xA0, 0xB9, 0xC7, 0xA3, 0xA0, 0xBA, 0xA0, 0xBB, /* 0x74-0x77 */ - 0xA0, 0xBC, 0xCC, 0xD8, 0xCE, 0xFE, 0xA0, 0xBD, /* 0x78-0x7B */ - 0xA0, 0xBE, 0xA0, 0xBF, 0xEA, 0xF5, 0xEA, 0xF6, /* 0x7C-0x7F */ - - 0xCF, 0xAC, 0xC0, 0xE7, 0xA0, 0xC0, 0xA0, 0xC1, /* 0x80-0x83 */ - 0xEA, 0xF7, 0xA0, 0xC2, 0xA0, 0xC3, 0xA0, 0xC4, /* 0x84-0x87 */ - 0xA0, 0xC5, 0xA0, 0xC6, 0xB6, 0xBF, 0xEA, 0xF8, /* 0x88-0x8B */ - 0xA0, 0xC7, 0xEA, 0xF9, 0xA0, 0xC8, 0xEA, 0xFA, /* 0x8C-0x8F */ - 0xA0, 0xC9, 0xA0, 0xCA, 0xEA, 0xFB, 0xA0, 0xCB, /* 0x90-0x93 */ - 0xA0, 0xCC, 0xA0, 0xCD, 0xA0, 0xCE, 0xA0, 0xCF, /* 0x94-0x97 */ - 0xA0, 0xD0, 0xA0, 0xD1, 0xA0, 0xD2, 0xA0, 0xD3, /* 0x98-0x9B */ - 0xA0, 0xD4, 0xA0, 0xD5, 0xA0, 0xD6, 0xEA, 0xF1, /* 0x9C-0x9F */ - 0xA0, 0xD7, 0xA0, 0xD8, 0xA0, 0xD9, 0xA0, 0xDA, /* 0xA0-0xA3 */ - 0xA0, 0xDB, 0xA0, 0xDC, 0xA0, 0xDD, 0xA0, 0xDE, /* 0xA4-0xA7 */ - 0xA0, 0xDF, 0xA0, 0xE0, 0xA0, 0xE1, 0xA0, 0xE2, /* 0xA8-0xAB */ - 0xC8, 0xAE, 0xE1, 0xEB, 0xA0, 0xE3, 0xB7, 0xB8, /* 0xAC-0xAF */ - 0xE1, 0xEC, 0xA0, 0xE4, 0xA0, 0xE5, 0xA0, 0xE6, /* 0xB0-0xB3 */ - 0xE1, 0xED, 0xA0, 0xE7, 0xD7, 0xB4, 0xE1, 0xEE, /* 0xB4-0xB7 */ - 0xE1, 0xEF, 0xD3, 0xCC, 0xA0, 0xE8, 0xA0, 0xE9, /* 0xB8-0xBB */ - 0xA0, 0xEA, 0xA0, 0xEB, 0xA0, 0xEC, 0xA0, 0xED, /* 0xBC-0xBF */ - 0xA0, 0xEE, 0xE1, 0xF1, 0xBF, 0xF1, 0xE1, 0xF0, /* 0xC0-0xC3 */ - 0xB5, 0xD2, 0xA0, 0xEF, 0xA0, 0xF0, 0xA0, 0xF1, /* 0xC4-0xC7 */ - 0xB1, 0xB7, 0xA0, 0xF2, 0xA0, 0xF3, 0xA0, 0xF4, /* 0xC8-0xCB */ - 0xA0, 0xF5, 0xE1, 0xF3, 0xE1, 0xF2, 0xA0, 0xF6, /* 0xCC-0xCF */ - 0xBA, 0xFC, 0xA0, 0xF7, 0xE1, 0xF4, 0xA0, 0xF8, /* 0xD0-0xD3 */ - 0xA0, 0xF9, 0xA0, 0xFA, 0xA0, 0xFB, 0xB9, 0xB7, /* 0xD4-0xD7 */ - 0xA0, 0xFC, 0xBE, 0xD1, 0xA0, 0xFD, 0xA0, 0xFE, /* 0xD8-0xDB */ - 0xAA, 0x40, 0xAA, 0x41, 0xC4, 0xFC, 0xAA, 0x42, /* 0xDC-0xDF */ - 0xBA, 0xDD, 0xBD, 0xC6, 0xAA, 0x43, 0xAA, 0x44, /* 0xE0-0xE3 */ - 0xAA, 0x45, 0xAA, 0x46, 0xAA, 0x47, 0xAA, 0x48, /* 0xE4-0xE7 */ - 0xE1, 0xF5, 0xE1, 0xF7, 0xAA, 0x49, 0xAA, 0x4A, /* 0xE8-0xEB */ - 0xB6, 0xC0, 0xCF, 0xC1, 0xCA, 0xA8, 0xE1, 0xF6, /* 0xEC-0xEF */ - 0xD5, 0xF8, 0xD3, 0xFC, 0xE1, 0xF8, 0xE1, 0xFC, /* 0xF0-0xF3 */ - 0xE1, 0xF9, 0xAA, 0x4B, 0xAA, 0x4C, 0xE1, 0xFA, /* 0xF4-0xF7 */ - 0xC0, 0xEA, 0xAA, 0x4D, 0xE1, 0xFE, 0xE2, 0xA1, /* 0xF8-0xFB */ - 0xC0, 0xC7, 0xAA, 0x4E, 0xAA, 0x4F, 0xAA, 0x50, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_73[512] = { - 0xAA, 0x51, 0xE1, 0xFB, 0xAA, 0x52, 0xE1, 0xFD, /* 0x00-0x03 */ - 0xAA, 0x53, 0xAA, 0x54, 0xAA, 0x55, 0xAA, 0x56, /* 0x04-0x07 */ - 0xAA, 0x57, 0xAA, 0x58, 0xE2, 0xA5, 0xAA, 0x59, /* 0x08-0x0B */ - 0xAA, 0x5A, 0xAA, 0x5B, 0xC1, 0xD4, 0xAA, 0x5C, /* 0x0C-0x0F */ - 0xAA, 0x5D, 0xAA, 0x5E, 0xAA, 0x5F, 0xE2, 0xA3, /* 0x10-0x13 */ - 0xAA, 0x60, 0xE2, 0xA8, 0xB2, 0xFE, 0xE2, 0xA2, /* 0x14-0x17 */ - 0xAA, 0x61, 0xAA, 0x62, 0xAA, 0x63, 0xC3, 0xCD, /* 0x18-0x1B */ - 0xB2, 0xC2, 0xE2, 0xA7, 0xE2, 0xA6, 0xAA, 0x64, /* 0x1C-0x1F */ - 0xAA, 0x65, 0xE2, 0xA4, 0xE2, 0xA9, 0xAA, 0x66, /* 0x20-0x23 */ - 0xAA, 0x67, 0xE2, 0xAB, 0xAA, 0x68, 0xAA, 0x69, /* 0x24-0x27 */ - 0xAA, 0x6A, 0xD0, 0xC9, 0xD6, 0xED, 0xC3, 0xA8, /* 0x28-0x2B */ - 0xE2, 0xAC, 0xAA, 0x6B, 0xCF, 0xD7, 0xAA, 0x6C, /* 0x2C-0x2F */ - 0xAA, 0x6D, 0xE2, 0xAE, 0xAA, 0x6E, 0xAA, 0x6F, /* 0x30-0x33 */ - 0xBA, 0xEF, 0xAA, 0x70, 0xAA, 0x71, 0xE9, 0xE0, /* 0x34-0x37 */ - 0xE2, 0xAD, 0xE2, 0xAA, 0xAA, 0x72, 0xAA, 0x73, /* 0x38-0x3B */ - 0xAA, 0x74, 0xAA, 0x75, 0xBB, 0xAB, 0xD4, 0xB3, /* 0x3C-0x3F */ - 0xAA, 0x76, 0xAA, 0x77, 0xAA, 0x78, 0xAA, 0x79, /* 0x40-0x43 */ - 0xAA, 0x7A, 0xAA, 0x7B, 0xAA, 0x7C, 0xAA, 0x7D, /* 0x44-0x47 */ - 0xAA, 0x7E, 0xAA, 0x80, 0xAA, 0x81, 0xAA, 0x82, /* 0x48-0x4B */ - 0xAA, 0x83, 0xE2, 0xB0, 0xAA, 0x84, 0xAA, 0x85, /* 0x4C-0x4F */ - 0xE2, 0xAF, 0xAA, 0x86, 0xE9, 0xE1, 0xAA, 0x87, /* 0x50-0x53 */ - 0xAA, 0x88, 0xAA, 0x89, 0xAA, 0x8A, 0xE2, 0xB1, /* 0x54-0x57 */ - 0xAA, 0x8B, 0xAA, 0x8C, 0xAA, 0x8D, 0xAA, 0x8E, /* 0x58-0x5B */ - 0xAA, 0x8F, 0xAA, 0x90, 0xAA, 0x91, 0xAA, 0x92, /* 0x5C-0x5F */ - 0xE2, 0xB2, 0xAA, 0x93, 0xAA, 0x94, 0xAA, 0x95, /* 0x60-0x63 */ - 0xAA, 0x96, 0xAA, 0x97, 0xAA, 0x98, 0xAA, 0x99, /* 0x64-0x67 */ - 0xAA, 0x9A, 0xAA, 0x9B, 0xAA, 0x9C, 0xAA, 0x9D, /* 0x68-0x6B */ - 0xE2, 0xB3, 0xCC, 0xA1, 0xAA, 0x9E, 0xE2, 0xB4, /* 0x6C-0x6F */ - 0xAA, 0x9F, 0xAA, 0xA0, 0xAB, 0x40, 0xAB, 0x41, /* 0x70-0x73 */ - 0xAB, 0x42, 0xAB, 0x43, 0xAB, 0x44, 0xAB, 0x45, /* 0x74-0x77 */ - 0xAB, 0x46, 0xAB, 0x47, 0xAB, 0x48, 0xAB, 0x49, /* 0x78-0x7B */ - 0xAB, 0x4A, 0xAB, 0x4B, 0xE2, 0xB5, 0xAB, 0x4C, /* 0x7C-0x7F */ - - 0xAB, 0x4D, 0xAB, 0x4E, 0xAB, 0x4F, 0xAB, 0x50, /* 0x80-0x83 */ - 0xD0, 0xFE, 0xAB, 0x51, 0xAB, 0x52, 0xC2, 0xCA, /* 0x84-0x87 */ - 0xAB, 0x53, 0xD3, 0xF1, 0xAB, 0x54, 0xCD, 0xF5, /* 0x88-0x8B */ - 0xAB, 0x55, 0xAB, 0x56, 0xE7, 0xE0, 0xAB, 0x57, /* 0x8C-0x8F */ - 0xAB, 0x58, 0xE7, 0xE1, 0xAB, 0x59, 0xAB, 0x5A, /* 0x90-0x93 */ - 0xAB, 0x5B, 0xAB, 0x5C, 0xBE, 0xC1, 0xAB, 0x5D, /* 0x94-0x97 */ - 0xAB, 0x5E, 0xAB, 0x5F, 0xAB, 0x60, 0xC2, 0xEA, /* 0x98-0x9B */ - 0xAB, 0x61, 0xAB, 0x62, 0xAB, 0x63, 0xE7, 0xE4, /* 0x9C-0x9F */ - 0xAB, 0x64, 0xAB, 0x65, 0xE7, 0xE3, 0xAB, 0x66, /* 0xA0-0xA3 */ - 0xAB, 0x67, 0xAB, 0x68, 0xAB, 0x69, 0xAB, 0x6A, /* 0xA4-0xA7 */ - 0xAB, 0x6B, 0xCD, 0xE6, 0xAB, 0x6C, 0xC3, 0xB5, /* 0xA8-0xAB */ - 0xAB, 0x6D, 0xAB, 0x6E, 0xE7, 0xE2, 0xBB, 0xB7, /* 0xAC-0xAF */ - 0xCF, 0xD6, 0xAB, 0x6F, 0xC1, 0xE1, 0xE7, 0xE9, /* 0xB0-0xB3 */ - 0xAB, 0x70, 0xAB, 0x71, 0xAB, 0x72, 0xE7, 0xE8, /* 0xB4-0xB7 */ - 0xAB, 0x73, 0xAB, 0x74, 0xE7, 0xF4, 0xB2, 0xA3, /* 0xB8-0xBB */ - 0xAB, 0x75, 0xAB, 0x76, 0xAB, 0x77, 0xAB, 0x78, /* 0xBC-0xBF */ - 0xE7, 0xEA, 0xAB, 0x79, 0xE7, 0xE6, 0xAB, 0x7A, /* 0xC0-0xC3 */ - 0xAB, 0x7B, 0xAB, 0x7C, 0xAB, 0x7D, 0xAB, 0x7E, /* 0xC4-0xC7 */ - 0xE7, 0xEC, 0xE7, 0xEB, 0xC9, 0xBA, 0xAB, 0x80, /* 0xC8-0xCB */ - 0xAB, 0x81, 0xD5, 0xE4, 0xAB, 0x82, 0xE7, 0xE5, /* 0xCC-0xCF */ - 0xB7, 0xA9, 0xE7, 0xE7, 0xAB, 0x83, 0xAB, 0x84, /* 0xD0-0xD3 */ - 0xAB, 0x85, 0xAB, 0x86, 0xAB, 0x87, 0xAB, 0x88, /* 0xD4-0xD7 */ - 0xAB, 0x89, 0xE7, 0xEE, 0xAB, 0x8A, 0xAB, 0x8B, /* 0xD8-0xDB */ - 0xAB, 0x8C, 0xAB, 0x8D, 0xE7, 0xF3, 0xAB, 0x8E, /* 0xDC-0xDF */ - 0xD6, 0xE9, 0xAB, 0x8F, 0xAB, 0x90, 0xAB, 0x91, /* 0xE0-0xE3 */ - 0xAB, 0x92, 0xE7, 0xED, 0xAB, 0x93, 0xE7, 0xF2, /* 0xE4-0xE7 */ - 0xAB, 0x94, 0xE7, 0xF1, 0xAB, 0x95, 0xAB, 0x96, /* 0xE8-0xEB */ - 0xAB, 0x97, 0xB0, 0xE0, 0xAB, 0x98, 0xAB, 0x99, /* 0xEC-0xEF */ - 0xAB, 0x9A, 0xAB, 0x9B, 0xE7, 0xF5, 0xAB, 0x9C, /* 0xF0-0xF3 */ - 0xAB, 0x9D, 0xAB, 0x9E, 0xAB, 0x9F, 0xAB, 0xA0, /* 0xF4-0xF7 */ - 0xAC, 0x40, 0xAC, 0x41, 0xAC, 0x42, 0xAC, 0x43, /* 0xF8-0xFB */ - 0xAC, 0x44, 0xAC, 0x45, 0xAC, 0x46, 0xAC, 0x47, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_74[512] = { - 0xAC, 0x48, 0xAC, 0x49, 0xAC, 0x4A, 0xC7, 0xF2, /* 0x00-0x03 */ - 0xAC, 0x4B, 0xC0, 0xC5, 0xC0, 0xED, 0xAC, 0x4C, /* 0x04-0x07 */ - 0xAC, 0x4D, 0xC1, 0xF0, 0xE7, 0xF0, 0xAC, 0x4E, /* 0x08-0x0B */ - 0xAC, 0x4F, 0xAC, 0x50, 0xAC, 0x51, 0xE7, 0xF6, /* 0x0C-0x0F */ - 0xCB, 0xF6, 0xAC, 0x52, 0xAC, 0x53, 0xAC, 0x54, /* 0x10-0x13 */ - 0xAC, 0x55, 0xAC, 0x56, 0xAC, 0x57, 0xAC, 0x58, /* 0x14-0x17 */ - 0xAC, 0x59, 0xAC, 0x5A, 0xE8, 0xA2, 0xE8, 0xA1, /* 0x18-0x1B */ - 0xAC, 0x5B, 0xAC, 0x5C, 0xAC, 0x5D, 0xAC, 0x5E, /* 0x1C-0x1F */ - 0xAC, 0x5F, 0xAC, 0x60, 0xD7, 0xC1, 0xAC, 0x61, /* 0x20-0x23 */ - 0xAC, 0x62, 0xE7, 0xFA, 0xE7, 0xF9, 0xAC, 0x63, /* 0x24-0x27 */ - 0xE7, 0xFB, 0xAC, 0x64, 0xE7, 0xF7, 0xAC, 0x65, /* 0x28-0x2B */ - 0xE7, 0xFE, 0xAC, 0x66, 0xE7, 0xFD, 0xAC, 0x67, /* 0x2C-0x2F */ - 0xE7, 0xFC, 0xAC, 0x68, 0xAC, 0x69, 0xC1, 0xD5, /* 0x30-0x33 */ - 0xC7, 0xD9, 0xC5, 0xFD, 0xC5, 0xC3, 0xAC, 0x6A, /* 0x34-0x37 */ - 0xAC, 0x6B, 0xAC, 0x6C, 0xAC, 0x6D, 0xAC, 0x6E, /* 0x38-0x3B */ - 0xC7, 0xED, 0xAC, 0x6F, 0xAC, 0x70, 0xAC, 0x71, /* 0x3C-0x3F */ - 0xAC, 0x72, 0xE8, 0xA3, 0xAC, 0x73, 0xAC, 0x74, /* 0x40-0x43 */ - 0xAC, 0x75, 0xAC, 0x76, 0xAC, 0x77, 0xAC, 0x78, /* 0x44-0x47 */ - 0xAC, 0x79, 0xAC, 0x7A, 0xAC, 0x7B, 0xAC, 0x7C, /* 0x48-0x4B */ - 0xAC, 0x7D, 0xAC, 0x7E, 0xAC, 0x80, 0xAC, 0x81, /* 0x4C-0x4F */ - 0xAC, 0x82, 0xAC, 0x83, 0xAC, 0x84, 0xAC, 0x85, /* 0x50-0x53 */ - 0xAC, 0x86, 0xE8, 0xA6, 0xAC, 0x87, 0xE8, 0xA5, /* 0x54-0x57 */ - 0xAC, 0x88, 0xE8, 0xA7, 0xBA, 0xF7, 0xE7, 0xF8, /* 0x58-0x5B */ - 0xE8, 0xA4, 0xAC, 0x89, 0xC8, 0xF0, 0xC9, 0xAA, /* 0x5C-0x5F */ - 0xAC, 0x8A, 0xAC, 0x8B, 0xAC, 0x8C, 0xAC, 0x8D, /* 0x60-0x63 */ - 0xAC, 0x8E, 0xAC, 0x8F, 0xAC, 0x90, 0xAC, 0x91, /* 0x64-0x67 */ - 0xAC, 0x92, 0xAC, 0x93, 0xAC, 0x94, 0xAC, 0x95, /* 0x68-0x6B */ - 0xAC, 0x96, 0xE8, 0xA9, 0xAC, 0x97, 0xAC, 0x98, /* 0x6C-0x6F */ - 0xB9, 0xE5, 0xAC, 0x99, 0xAC, 0x9A, 0xAC, 0x9B, /* 0x70-0x73 */ - 0xAC, 0x9C, 0xAC, 0x9D, 0xD1, 0xFE, 0xE8, 0xA8, /* 0x74-0x77 */ - 0xAC, 0x9E, 0xAC, 0x9F, 0xAC, 0xA0, 0xAD, 0x40, /* 0x78-0x7B */ - 0xAD, 0x41, 0xAD, 0x42, 0xE8, 0xAA, 0xAD, 0x43, /* 0x7C-0x7F */ - - 0xE8, 0xAD, 0xE8, 0xAE, 0xAD, 0x44, 0xC1, 0xA7, /* 0x80-0x83 */ - 0xAD, 0x45, 0xAD, 0x46, 0xAD, 0x47, 0xE8, 0xAF, /* 0x84-0x87 */ - 0xAD, 0x48, 0xAD, 0x49, 0xAD, 0x4A, 0xE8, 0xB0, /* 0x88-0x8B */ - 0xAD, 0x4B, 0xAD, 0x4C, 0xE8, 0xAC, 0xAD, 0x4D, /* 0x8C-0x8F */ - 0xE8, 0xB4, 0xAD, 0x4E, 0xAD, 0x4F, 0xAD, 0x50, /* 0x90-0x93 */ - 0xAD, 0x51, 0xAD, 0x52, 0xAD, 0x53, 0xAD, 0x54, /* 0x94-0x97 */ - 0xAD, 0x55, 0xAD, 0x56, 0xAD, 0x57, 0xAD, 0x58, /* 0x98-0x9B */ - 0xE8, 0xAB, 0xAD, 0x59, 0xE8, 0xB1, 0xAD, 0x5A, /* 0x9C-0x9F */ - 0xAD, 0x5B, 0xAD, 0x5C, 0xAD, 0x5D, 0xAD, 0x5E, /* 0xA0-0xA3 */ - 0xAD, 0x5F, 0xAD, 0x60, 0xAD, 0x61, 0xE8, 0xB5, /* 0xA4-0xA7 */ - 0xE8, 0xB2, 0xE8, 0xB3, 0xAD, 0x62, 0xAD, 0x63, /* 0xA8-0xAB */ - 0xAD, 0x64, 0xAD, 0x65, 0xAD, 0x66, 0xAD, 0x67, /* 0xAC-0xAF */ - 0xAD, 0x68, 0xAD, 0x69, 0xAD, 0x6A, 0xAD, 0x6B, /* 0xB0-0xB3 */ - 0xAD, 0x6C, 0xAD, 0x6D, 0xAD, 0x6E, 0xAD, 0x6F, /* 0xB4-0xB7 */ - 0xAD, 0x70, 0xAD, 0x71, 0xE8, 0xB7, 0xAD, 0x72, /* 0xB8-0xBB */ - 0xAD, 0x73, 0xAD, 0x74, 0xAD, 0x75, 0xAD, 0x76, /* 0xBC-0xBF */ - 0xAD, 0x77, 0xAD, 0x78, 0xAD, 0x79, 0xAD, 0x7A, /* 0xC0-0xC3 */ - 0xAD, 0x7B, 0xAD, 0x7C, 0xAD, 0x7D, 0xAD, 0x7E, /* 0xC4-0xC7 */ - 0xAD, 0x80, 0xAD, 0x81, 0xAD, 0x82, 0xAD, 0x83, /* 0xC8-0xCB */ - 0xAD, 0x84, 0xAD, 0x85, 0xAD, 0x86, 0xAD, 0x87, /* 0xCC-0xCF */ - 0xAD, 0x88, 0xAD, 0x89, 0xE8, 0xB6, 0xAD, 0x8A, /* 0xD0-0xD3 */ - 0xAD, 0x8B, 0xAD, 0x8C, 0xAD, 0x8D, 0xAD, 0x8E, /* 0xD4-0xD7 */ - 0xAD, 0x8F, 0xAD, 0x90, 0xAD, 0x91, 0xAD, 0x92, /* 0xD8-0xDB */ - 0xB9, 0xCF, 0xAD, 0x93, 0xF0, 0xAC, 0xAD, 0x94, /* 0xDC-0xDF */ - 0xF0, 0xAD, 0xAD, 0x95, 0xC6, 0xB0, 0xB0, 0xEA, /* 0xE0-0xE3 */ - 0xC8, 0xBF, 0xAD, 0x96, 0xCD, 0xDF, 0xAD, 0x97, /* 0xE4-0xE7 */ - 0xAD, 0x98, 0xAD, 0x99, 0xAD, 0x9A, 0xAD, 0x9B, /* 0xE8-0xEB */ - 0xAD, 0x9C, 0xAD, 0x9D, 0xCE, 0xCD, 0xEA, 0xB1, /* 0xEC-0xEF */ - 0xAD, 0x9E, 0xAD, 0x9F, 0xAD, 0xA0, 0xAE, 0x40, /* 0xF0-0xF3 */ - 0xEA, 0xB2, 0xAE, 0x41, 0xC6, 0xBF, 0xB4, 0xC9, /* 0xF4-0xF7 */ - 0xAE, 0x42, 0xAE, 0x43, 0xAE, 0x44, 0xAE, 0x45, /* 0xF8-0xFB */ - 0xAE, 0x46, 0xAE, 0x47, 0xAE, 0x48, 0xEA, 0xB3, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_75[512] = { - 0xAE, 0x49, 0xAE, 0x4A, 0xAE, 0x4B, 0xAE, 0x4C, /* 0x00-0x03 */ - 0xD5, 0xE7, 0xAE, 0x4D, 0xAE, 0x4E, 0xAE, 0x4F, /* 0x04-0x07 */ - 0xAE, 0x50, 0xAE, 0x51, 0xAE, 0x52, 0xAE, 0x53, /* 0x08-0x0B */ - 0xAE, 0x54, 0xDD, 0xF9, 0xAE, 0x55, 0xEA, 0xB4, /* 0x0C-0x0F */ - 0xAE, 0x56, 0xEA, 0xB5, 0xAE, 0x57, 0xEA, 0xB6, /* 0x10-0x13 */ - 0xAE, 0x58, 0xAE, 0x59, 0xAE, 0x5A, 0xAE, 0x5B, /* 0x14-0x17 */ - 0xB8, 0xCA, 0xDF, 0xB0, 0xC9, 0xF5, 0xAE, 0x5C, /* 0x18-0x1B */ - 0xCC, 0xF0, 0xAE, 0x5D, 0xAE, 0x5E, 0xC9, 0xFA, /* 0x1C-0x1F */ - 0xAE, 0x5F, 0xAE, 0x60, 0xAE, 0x61, 0xAE, 0x62, /* 0x20-0x23 */ - 0xAE, 0x63, 0xC9, 0xFB, 0xAE, 0x64, 0xAE, 0x65, /* 0x24-0x27 */ - 0xD3, 0xC3, 0xCB, 0xA6, 0xAE, 0x66, 0xB8, 0xA6, /* 0x28-0x2B */ - 0xF0, 0xAE, 0xB1, 0xC2, 0xAE, 0x67, 0xE5, 0xB8, /* 0x2C-0x2F */ - 0xCC, 0xEF, 0xD3, 0xC9, 0xBC, 0xD7, 0xC9, 0xEA, /* 0x30-0x33 */ - 0xAE, 0x68, 0xB5, 0xE7, 0xAE, 0x69, 0xC4, 0xD0, /* 0x34-0x37 */ - 0xB5, 0xE9, 0xAE, 0x6A, 0xEE, 0xAE, 0xBB, 0xAD, /* 0x38-0x3B */ - 0xAE, 0x6B, 0xAE, 0x6C, 0xE7, 0xDE, 0xAE, 0x6D, /* 0x3C-0x3F */ - 0xEE, 0xAF, 0xAE, 0x6E, 0xAE, 0x6F, 0xAE, 0x70, /* 0x40-0x43 */ - 0xAE, 0x71, 0xB3, 0xA9, 0xAE, 0x72, 0xAE, 0x73, /* 0x44-0x47 */ - 0xEE, 0xB2, 0xAE, 0x74, 0xAE, 0x75, 0xEE, 0xB1, /* 0x48-0x4B */ - 0xBD, 0xE7, 0xAE, 0x76, 0xEE, 0xB0, 0xCE, 0xB7, /* 0x4C-0x4F */ - 0xAE, 0x77, 0xAE, 0x78, 0xAE, 0x79, 0xAE, 0x7A, /* 0x50-0x53 */ - 0xC5, 0xCF, 0xAE, 0x7B, 0xAE, 0x7C, 0xAE, 0x7D, /* 0x54-0x57 */ - 0xAE, 0x7E, 0xC1, 0xF4, 0xDB, 0xCE, 0xEE, 0xB3, /* 0x58-0x5B */ - 0xD0, 0xF3, 0xAE, 0x80, 0xAE, 0x81, 0xAE, 0x82, /* 0x5C-0x5F */ - 0xAE, 0x83, 0xAE, 0x84, 0xAE, 0x85, 0xAE, 0x86, /* 0x60-0x63 */ - 0xAE, 0x87, 0xC2, 0xD4, 0xC6, 0xE8, 0xAE, 0x88, /* 0x64-0x67 */ - 0xAE, 0x89, 0xAE, 0x8A, 0xB7, 0xAC, 0xAE, 0x8B, /* 0x68-0x6B */ - 0xAE, 0x8C, 0xAE, 0x8D, 0xAE, 0x8E, 0xAE, 0x8F, /* 0x6C-0x6F */ - 0xAE, 0x90, 0xAE, 0x91, 0xEE, 0xB4, 0xAE, 0x92, /* 0x70-0x73 */ - 0xB3, 0xEB, 0xAE, 0x93, 0xAE, 0x94, 0xAE, 0x95, /* 0x74-0x77 */ - 0xBB, 0xFB, 0xEE, 0xB5, 0xAE, 0x96, 0xAE, 0x97, /* 0x78-0x7B */ - 0xAE, 0x98, 0xAE, 0x99, 0xAE, 0x9A, 0xE7, 0xDC, /* 0x7C-0x7F */ - - 0xAE, 0x9B, 0xAE, 0x9C, 0xAE, 0x9D, 0xEE, 0xB6, /* 0x80-0x83 */ - 0xAE, 0x9E, 0xAE, 0x9F, 0xBD, 0xAE, 0xAE, 0xA0, /* 0x84-0x87 */ - 0xAF, 0x40, 0xAF, 0x41, 0xAF, 0x42, 0xF1, 0xE2, /* 0x88-0x8B */ - 0xAF, 0x43, 0xAF, 0x44, 0xAF, 0x45, 0xCA, 0xE8, /* 0x8C-0x8F */ - 0xAF, 0x46, 0xD2, 0xC9, 0xF0, 0xDA, 0xAF, 0x47, /* 0x90-0x93 */ - 0xF0, 0xDB, 0xAF, 0x48, 0xF0, 0xDC, 0xC1, 0xC6, /* 0x94-0x97 */ - 0xAF, 0x49, 0xB8, 0xED, 0xBE, 0xCE, 0xAF, 0x4A, /* 0x98-0x9B */ - 0xAF, 0x4B, 0xF0, 0xDE, 0xAF, 0x4C, 0xC5, 0xB1, /* 0x9C-0x9F */ - 0xF0, 0xDD, 0xD1, 0xF1, 0xAF, 0x4D, 0xF0, 0xE0, /* 0xA0-0xA3 */ - 0xB0, 0xCC, 0xBD, 0xEA, 0xAF, 0x4E, 0xAF, 0x4F, /* 0xA4-0xA7 */ - 0xAF, 0x50, 0xAF, 0x51, 0xAF, 0x52, 0xD2, 0xDF, /* 0xA8-0xAB */ - 0xF0, 0xDF, 0xAF, 0x53, 0xB4, 0xAF, 0xB7, 0xE8, /* 0xAC-0xAF */ - 0xF0, 0xE6, 0xF0, 0xE5, 0xC6, 0xA3, 0xF0, 0xE1, /* 0xB0-0xB3 */ - 0xF0, 0xE2, 0xB4, 0xC3, 0xAF, 0x54, 0xAF, 0x55, /* 0xB4-0xB7 */ - 0xF0, 0xE3, 0xD5, 0xEE, 0xAF, 0x56, 0xAF, 0x57, /* 0xB8-0xBB */ - 0xCC, 0xDB, 0xBE, 0xD2, 0xBC, 0xB2, 0xAF, 0x58, /* 0xBC-0xBF */ - 0xAF, 0x59, 0xAF, 0x5A, 0xF0, 0xE8, 0xF0, 0xE7, /* 0xC0-0xC3 */ - 0xF0, 0xE4, 0xB2, 0xA1, 0xAF, 0x5B, 0xD6, 0xA2, /* 0xC4-0xC7 */ - 0xD3, 0xB8, 0xBE, 0xB7, 0xC8, 0xAC, 0xAF, 0x5C, /* 0xC8-0xCB */ - 0xAF, 0x5D, 0xF0, 0xEA, 0xAF, 0x5E, 0xAF, 0x5F, /* 0xCC-0xCF */ - 0xAF, 0x60, 0xAF, 0x61, 0xD1, 0xF7, 0xAF, 0x62, /* 0xD0-0xD3 */ - 0xD6, 0xCC, 0xBA, 0xDB, 0xF0, 0xE9, 0xAF, 0x63, /* 0xD4-0xD7 */ - 0xB6, 0xBB, 0xAF, 0x64, 0xAF, 0x65, 0xCD, 0xB4, /* 0xD8-0xDB */ - 0xAF, 0x66, 0xAF, 0x67, 0xC6, 0xA6, 0xAF, 0x68, /* 0xDC-0xDF */ - 0xAF, 0x69, 0xAF, 0x6A, 0xC1, 0xA1, 0xF0, 0xEB, /* 0xE0-0xE3 */ - 0xF0, 0xEE, 0xAF, 0x6B, 0xF0, 0xED, 0xF0, 0xF0, /* 0xE4-0xE7 */ - 0xF0, 0xEC, 0xAF, 0x6C, 0xBB, 0xBE, 0xF0, 0xEF, /* 0xE8-0xEB */ - 0xAF, 0x6D, 0xAF, 0x6E, 0xAF, 0x6F, 0xAF, 0x70, /* 0xEC-0xEF */ - 0xCC, 0xB5, 0xF0, 0xF2, 0xAF, 0x71, 0xAF, 0x72, /* 0xF0-0xF3 */ - 0xB3, 0xD5, 0xAF, 0x73, 0xAF, 0x74, 0xAF, 0x75, /* 0xF4-0xF7 */ - 0xAF, 0x76, 0xB1, 0xD4, 0xAF, 0x77, 0xAF, 0x78, /* 0xF8-0xFB */ - 0xF0, 0xF3, 0xAF, 0x79, 0xAF, 0x7A, 0xF0, 0xF4, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_76[512] = { - 0xF0, 0xF6, 0xB4, 0xE1, 0xAF, 0x7B, 0xF0, 0xF1, /* 0x00-0x03 */ - 0xAF, 0x7C, 0xF0, 0xF7, 0xAF, 0x7D, 0xAF, 0x7E, /* 0x04-0x07 */ - 0xAF, 0x80, 0xAF, 0x81, 0xF0, 0xFA, 0xAF, 0x82, /* 0x08-0x0B */ - 0xF0, 0xF8, 0xAF, 0x83, 0xAF, 0x84, 0xAF, 0x85, /* 0x0C-0x0F */ - 0xF0, 0xF5, 0xAF, 0x86, 0xAF, 0x87, 0xAF, 0x88, /* 0x10-0x13 */ - 0xAF, 0x89, 0xF0, 0xFD, 0xAF, 0x8A, 0xF0, 0xF9, /* 0x14-0x17 */ - 0xF0, 0xFC, 0xF0, 0xFE, 0xAF, 0x8B, 0xF1, 0xA1, /* 0x18-0x1B */ - 0xAF, 0x8C, 0xAF, 0x8D, 0xAF, 0x8E, 0xCE, 0xC1, /* 0x1C-0x1F */ - 0xF1, 0xA4, 0xAF, 0x8F, 0xF1, 0xA3, 0xAF, 0x90, /* 0x20-0x23 */ - 0xC1, 0xF6, 0xF0, 0xFB, 0xCA, 0xDD, 0xAF, 0x91, /* 0x24-0x27 */ - 0xAF, 0x92, 0xB4, 0xF1, 0xB1, 0xF1, 0xCC, 0xB1, /* 0x28-0x2B */ - 0xAF, 0x93, 0xF1, 0xA6, 0xAF, 0x94, 0xAF, 0x95, /* 0x2C-0x2F */ - 0xF1, 0xA7, 0xAF, 0x96, 0xAF, 0x97, 0xF1, 0xAC, /* 0x30-0x33 */ - 0xD5, 0xCE, 0xF1, 0xA9, 0xAF, 0x98, 0xAF, 0x99, /* 0x34-0x37 */ - 0xC8, 0xB3, 0xAF, 0x9A, 0xAF, 0x9B, 0xAF, 0x9C, /* 0x38-0x3B */ - 0xF1, 0xA2, 0xAF, 0x9D, 0xF1, 0xAB, 0xF1, 0xA8, /* 0x3C-0x3F */ - 0xF1, 0xA5, 0xAF, 0x9E, 0xAF, 0x9F, 0xF1, 0xAA, /* 0x40-0x43 */ - 0xAF, 0xA0, 0xB0, 0x40, 0xB0, 0x41, 0xB0, 0x42, /* 0x44-0x47 */ - 0xB0, 0x43, 0xB0, 0x44, 0xB0, 0x45, 0xB0, 0x46, /* 0x48-0x4B */ - 0xB0, 0xA9, 0xF1, 0xAD, 0xB0, 0x47, 0xB0, 0x48, /* 0x4C-0x4F */ - 0xB0, 0x49, 0xB0, 0x4A, 0xB0, 0x4B, 0xB0, 0x4C, /* 0x50-0x53 */ - 0xF1, 0xAF, 0xB0, 0x4D, 0xF1, 0xB1, 0xB0, 0x4E, /* 0x54-0x57 */ - 0xB0, 0x4F, 0xB0, 0x50, 0xB0, 0x51, 0xB0, 0x52, /* 0x58-0x5B */ - 0xF1, 0xB0, 0xB0, 0x53, 0xF1, 0xAE, 0xB0, 0x54, /* 0x5C-0x5F */ - 0xB0, 0x55, 0xB0, 0x56, 0xB0, 0x57, 0xD1, 0xA2, /* 0x60-0x63 */ - 0xB0, 0x58, 0xB0, 0x59, 0xB0, 0x5A, 0xB0, 0x5B, /* 0x64-0x67 */ - 0xB0, 0x5C, 0xB0, 0x5D, 0xB0, 0x5E, 0xF1, 0xB2, /* 0x68-0x6B */ - 0xB0, 0x5F, 0xB0, 0x60, 0xB0, 0x61, 0xF1, 0xB3, /* 0x6C-0x6F */ - 0xB0, 0x62, 0xB0, 0x63, 0xB0, 0x64, 0xB0, 0x65, /* 0x70-0x73 */ - 0xB0, 0x66, 0xB0, 0x67, 0xB0, 0x68, 0xB0, 0x69, /* 0x74-0x77 */ - 0xB9, 0xEF, 0xB0, 0x6A, 0xB0, 0x6B, 0xB5, 0xC7, /* 0x78-0x7B */ - 0xB0, 0x6C, 0xB0, 0xD7, 0xB0, 0xD9, 0xB0, 0x6D, /* 0x7C-0x7F */ - - 0xB0, 0x6E, 0xB0, 0x6F, 0xD4, 0xED, 0xB0, 0x70, /* 0x80-0x83 */ - 0xB5, 0xC4, 0xB0, 0x71, 0xBD, 0xD4, 0xBB, 0xCA, /* 0x84-0x87 */ - 0xF0, 0xA7, 0xB0, 0x72, 0xB0, 0x73, 0xB8, 0xDE, /* 0x88-0x8B */ - 0xB0, 0x74, 0xB0, 0x75, 0xF0, 0xA8, 0xB0, 0x76, /* 0x8C-0x8F */ - 0xB0, 0x77, 0xB0, 0xA8, 0xB0, 0x78, 0xF0, 0xA9, /* 0x90-0x93 */ - 0xB0, 0x79, 0xB0, 0x7A, 0xCD, 0xEE, 0xB0, 0x7B, /* 0x94-0x97 */ - 0xB0, 0x7C, 0xF0, 0xAA, 0xB0, 0x7D, 0xB0, 0x7E, /* 0x98-0x9B */ - 0xB0, 0x80, 0xB0, 0x81, 0xB0, 0x82, 0xB0, 0x83, /* 0x9C-0x9F */ - 0xB0, 0x84, 0xB0, 0x85, 0xB0, 0x86, 0xB0, 0x87, /* 0xA0-0xA3 */ - 0xF0, 0xAB, 0xB0, 0x88, 0xB0, 0x89, 0xB0, 0x8A, /* 0xA4-0xA7 */ - 0xB0, 0x8B, 0xB0, 0x8C, 0xB0, 0x8D, 0xB0, 0x8E, /* 0xA8-0xAB */ - 0xB0, 0x8F, 0xB0, 0x90, 0xC6, 0xA4, 0xB0, 0x91, /* 0xAC-0xAF */ - 0xB0, 0x92, 0xD6, 0xE5, 0xF1, 0xE4, 0xB0, 0x93, /* 0xB0-0xB3 */ - 0xF1, 0xE5, 0xB0, 0x94, 0xB0, 0x95, 0xB0, 0x96, /* 0xB4-0xB7 */ - 0xB0, 0x97, 0xB0, 0x98, 0xB0, 0x99, 0xB0, 0x9A, /* 0xB8-0xBB */ - 0xB0, 0x9B, 0xB0, 0x9C, 0xB0, 0x9D, 0xC3, 0xF3, /* 0xBC-0xBF */ - 0xB0, 0x9E, 0xB0, 0x9F, 0xD3, 0xDB, 0xB0, 0xA0, /* 0xC0-0xC3 */ - 0xB1, 0x40, 0xD6, 0xD1, 0xC5, 0xE8, 0xB1, 0x41, /* 0xC4-0xC7 */ - 0xD3, 0xAF, 0xB1, 0x42, 0xD2, 0xE6, 0xB1, 0x43, /* 0xC8-0xCB */ - 0xB1, 0x44, 0xEE, 0xC1, 0xB0, 0xBB, 0xD5, 0xB5, /* 0xCC-0xCF */ - 0xD1, 0xCE, 0xBC, 0xE0, 0xBA, 0xD0, 0xB1, 0x45, /* 0xD0-0xD3 */ - 0xBF, 0xF8, 0xB1, 0x46, 0xB8, 0xC7, 0xB5, 0xC1, /* 0xD4-0xD7 */ - 0xC5, 0xCC, 0xB1, 0x47, 0xB1, 0x48, 0xCA, 0xA2, /* 0xD8-0xDB */ - 0xB1, 0x49, 0xB1, 0x4A, 0xB1, 0x4B, 0xC3, 0xCB, /* 0xDC-0xDF */ - 0xB1, 0x4C, 0xB1, 0x4D, 0xB1, 0x4E, 0xB1, 0x4F, /* 0xE0-0xE3 */ - 0xB1, 0x50, 0xEE, 0xC2, 0xB1, 0x51, 0xB1, 0x52, /* 0xE4-0xE7 */ - 0xB1, 0x53, 0xB1, 0x54, 0xB1, 0x55, 0xB1, 0x56, /* 0xE8-0xEB */ - 0xB1, 0x57, 0xB1, 0x58, 0xC4, 0xBF, 0xB6, 0xA2, /* 0xEC-0xEF */ - 0xB1, 0x59, 0xED, 0xEC, 0xC3, 0xA4, 0xB1, 0x5A, /* 0xF0-0xF3 */ - 0xD6, 0xB1, 0xB1, 0x5B, 0xB1, 0x5C, 0xB1, 0x5D, /* 0xF4-0xF7 */ - 0xCF, 0xE0, 0xED, 0xEF, 0xB1, 0x5E, 0xB1, 0x5F, /* 0xF8-0xFB */ - 0xC5, 0xCE, 0xB1, 0x60, 0xB6, 0xDC, 0xB1, 0x61, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_77[512] = { - 0xB1, 0x62, 0xCA, 0xA1, 0xB1, 0x63, 0xB1, 0x64, /* 0x00-0x03 */ - 0xED, 0xED, 0xB1, 0x65, 0xB1, 0x66, 0xED, 0xF0, /* 0x04-0x07 */ - 0xED, 0xF1, 0xC3, 0xBC, 0xB1, 0x67, 0xBF, 0xB4, /* 0x08-0x0B */ - 0xB1, 0x68, 0xED, 0xEE, 0xB1, 0x69, 0xB1, 0x6A, /* 0x0C-0x0F */ - 0xB1, 0x6B, 0xB1, 0x6C, 0xB1, 0x6D, 0xB1, 0x6E, /* 0x10-0x13 */ - 0xB1, 0x6F, 0xB1, 0x70, 0xB1, 0x71, 0xB1, 0x72, /* 0x14-0x17 */ - 0xB1, 0x73, 0xED, 0xF4, 0xED, 0xF2, 0xB1, 0x74, /* 0x18-0x1B */ - 0xB1, 0x75, 0xB1, 0x76, 0xB1, 0x77, 0xD5, 0xE6, /* 0x1C-0x1F */ - 0xC3, 0xDF, 0xB1, 0x78, 0xED, 0xF3, 0xB1, 0x79, /* 0x20-0x23 */ - 0xB1, 0x7A, 0xB1, 0x7B, 0xED, 0xF6, 0xB1, 0x7C, /* 0x24-0x27 */ - 0xD5, 0xA3, 0xD1, 0xA3, 0xB1, 0x7D, 0xB1, 0x7E, /* 0x28-0x2B */ - 0xB1, 0x80, 0xED, 0xF5, 0xB1, 0x81, 0xC3, 0xD0, /* 0x2C-0x2F */ - 0xB1, 0x82, 0xB1, 0x83, 0xB1, 0x84, 0xB1, 0x85, /* 0x30-0x33 */ - 0xB1, 0x86, 0xED, 0xF7, 0xBF, 0xF4, 0xBE, 0xEC, /* 0x34-0x37 */ - 0xED, 0xF8, 0xB1, 0x87, 0xCC, 0xF7, 0xB1, 0x88, /* 0x38-0x3B */ - 0xD1, 0xDB, 0xB1, 0x89, 0xB1, 0x8A, 0xB1, 0x8B, /* 0x3C-0x3F */ - 0xD7, 0xC5, 0xD5, 0xF6, 0xB1, 0x8C, 0xED, 0xFC, /* 0x40-0x43 */ - 0xB1, 0x8D, 0xB1, 0x8E, 0xB1, 0x8F, 0xED, 0xFB, /* 0x44-0x47 */ - 0xB1, 0x90, 0xB1, 0x91, 0xB1, 0x92, 0xB1, 0x93, /* 0x48-0x4B */ - 0xB1, 0x94, 0xB1, 0x95, 0xB1, 0x96, 0xB1, 0x97, /* 0x4C-0x4F */ - 0xED, 0xF9, 0xED, 0xFA, 0xB1, 0x98, 0xB1, 0x99, /* 0x50-0x53 */ - 0xB1, 0x9A, 0xB1, 0x9B, 0xB1, 0x9C, 0xB1, 0x9D, /* 0x54-0x57 */ - 0xB1, 0x9E, 0xB1, 0x9F, 0xED, 0xFD, 0xBE, 0xA6, /* 0x58-0x5B */ - 0xB1, 0xA0, 0xB2, 0x40, 0xB2, 0x41, 0xB2, 0x42, /* 0x5C-0x5F */ - 0xB2, 0x43, 0xCB, 0xAF, 0xEE, 0xA1, 0xB6, 0xBD, /* 0x60-0x63 */ - 0xB2, 0x44, 0xEE, 0xA2, 0xC4, 0xC0, 0xB2, 0x45, /* 0x64-0x67 */ - 0xED, 0xFE, 0xB2, 0x46, 0xB2, 0x47, 0xBD, 0xDE, /* 0x68-0x6B */ - 0xB2, 0xC7, 0xB2, 0x48, 0xB2, 0x49, 0xB2, 0x4A, /* 0x6C-0x6F */ - 0xB2, 0x4B, 0xB2, 0x4C, 0xB2, 0x4D, 0xB2, 0x4E, /* 0x70-0x73 */ - 0xB2, 0x4F, 0xB2, 0x50, 0xB2, 0x51, 0xB2, 0x52, /* 0x74-0x77 */ - 0xB2, 0x53, 0xB6, 0xC3, 0xB2, 0x54, 0xB2, 0x55, /* 0x78-0x7B */ - 0xB2, 0x56, 0xEE, 0xA5, 0xD8, 0xBA, 0xEE, 0xA3, /* 0x7C-0x7F */ - - 0xEE, 0xA6, 0xB2, 0x57, 0xB2, 0x58, 0xB2, 0x59, /* 0x80-0x83 */ - 0xC3, 0xE9, 0xB3, 0xF2, 0xB2, 0x5A, 0xB2, 0x5B, /* 0x84-0x87 */ - 0xB2, 0x5C, 0xB2, 0x5D, 0xB2, 0x5E, 0xB2, 0x5F, /* 0x88-0x8B */ - 0xEE, 0xA7, 0xEE, 0xA4, 0xCF, 0xB9, 0xB2, 0x60, /* 0x8C-0x8F */ - 0xB2, 0x61, 0xEE, 0xA8, 0xC2, 0xF7, 0xB2, 0x62, /* 0x90-0x93 */ - 0xB2, 0x63, 0xB2, 0x64, 0xB2, 0x65, 0xB2, 0x66, /* 0x94-0x97 */ - 0xB2, 0x67, 0xB2, 0x68, 0xB2, 0x69, 0xB2, 0x6A, /* 0x98-0x9B */ - 0xB2, 0x6B, 0xB2, 0x6C, 0xB2, 0x6D, 0xEE, 0xA9, /* 0x9C-0x9F */ - 0xEE, 0xAA, 0xB2, 0x6E, 0xDE, 0xAB, 0xB2, 0x6F, /* 0xA0-0xA3 */ - 0xB2, 0x70, 0xC6, 0xB3, 0xB2, 0x71, 0xC7, 0xC6, /* 0xA4-0xA7 */ - 0xB2, 0x72, 0xD6, 0xF5, 0xB5, 0xC9, 0xB2, 0x73, /* 0xA8-0xAB */ - 0xCB, 0xB2, 0xB2, 0x74, 0xB2, 0x75, 0xB2, 0x76, /* 0xAC-0xAF */ - 0xEE, 0xAB, 0xB2, 0x77, 0xB2, 0x78, 0xCD, 0xAB, /* 0xB0-0xB3 */ - 0xB2, 0x79, 0xEE, 0xAC, 0xB2, 0x7A, 0xB2, 0x7B, /* 0xB4-0xB7 */ - 0xB2, 0x7C, 0xB2, 0x7D, 0xB2, 0x7E, 0xD5, 0xB0, /* 0xB8-0xBB */ - 0xB2, 0x80, 0xEE, 0xAD, 0xB2, 0x81, 0xF6, 0xC4, /* 0xBC-0xBF */ - 0xB2, 0x82, 0xB2, 0x83, 0xB2, 0x84, 0xB2, 0x85, /* 0xC0-0xC3 */ - 0xB2, 0x86, 0xB2, 0x87, 0xB2, 0x88, 0xB2, 0x89, /* 0xC4-0xC7 */ - 0xB2, 0x8A, 0xB2, 0x8B, 0xB2, 0x8C, 0xB2, 0x8D, /* 0xC8-0xCB */ - 0xB2, 0x8E, 0xDB, 0xC7, 0xB2, 0x8F, 0xB2, 0x90, /* 0xCC-0xCF */ - 0xB2, 0x91, 0xB2, 0x92, 0xB2, 0x93, 0xB2, 0x94, /* 0xD0-0xD3 */ - 0xB2, 0x95, 0xB2, 0x96, 0xB2, 0x97, 0xB4, 0xA3, /* 0xD4-0xD7 */ - 0xB2, 0x98, 0xB2, 0x99, 0xB2, 0x9A, 0xC3, 0xAC, /* 0xD8-0xDB */ - 0xF1, 0xE6, 0xB2, 0x9B, 0xB2, 0x9C, 0xB2, 0x9D, /* 0xDC-0xDF */ - 0xB2, 0x9E, 0xB2, 0x9F, 0xCA, 0xB8, 0xD2, 0xD3, /* 0xE0-0xE3 */ - 0xB2, 0xA0, 0xD6, 0xAA, 0xB3, 0x40, 0xEF, 0xF2, /* 0xE4-0xE7 */ - 0xB3, 0x41, 0xBE, 0xD8, 0xB3, 0x42, 0xBD, 0xC3, /* 0xE8-0xEB */ - 0xEF, 0xF3, 0xB6, 0xCC, 0xB0, 0xAB, 0xB3, 0x43, /* 0xEC-0xEF */ - 0xB3, 0x44, 0xB3, 0x45, 0xB3, 0x46, 0xCA, 0xAF, /* 0xF0-0xF3 */ - 0xB3, 0x47, 0xB3, 0x48, 0xED, 0xB6, 0xB3, 0x49, /* 0xF4-0xF7 */ - 0xED, 0xB7, 0xB3, 0x4A, 0xB3, 0x4B, 0xB3, 0x4C, /* 0xF8-0xFB */ - 0xB3, 0x4D, 0xCE, 0xF9, 0xB7, 0xAF, 0xBF, 0xF3, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_78[512] = { - 0xED, 0xB8, 0xC2, 0xEB, 0xC9, 0xB0, 0xB3, 0x4E, /* 0x00-0x03 */ - 0xB3, 0x4F, 0xB3, 0x50, 0xB3, 0x51, 0xB3, 0x52, /* 0x04-0x07 */ - 0xB3, 0x53, 0xED, 0xB9, 0xB3, 0x54, 0xB3, 0x55, /* 0x08-0x0B */ - 0xC6, 0xF6, 0xBF, 0xB3, 0xB3, 0x56, 0xB3, 0x57, /* 0x0C-0x0F */ - 0xB3, 0x58, 0xED, 0xBC, 0xC5, 0xF8, 0xB3, 0x59, /* 0x10-0x13 */ - 0xD1, 0xD0, 0xB3, 0x5A, 0xD7, 0xA9, 0xED, 0xBA, /* 0x14-0x17 */ - 0xED, 0xBB, 0xB3, 0x5B, 0xD1, 0xE2, 0xB3, 0x5C, /* 0x18-0x1B */ - 0xED, 0xBF, 0xED, 0xC0, 0xB3, 0x5D, 0xED, 0xC4, /* 0x1C-0x1F */ - 0xB3, 0x5E, 0xB3, 0x5F, 0xB3, 0x60, 0xED, 0xC8, /* 0x20-0x23 */ - 0xB3, 0x61, 0xED, 0xC6, 0xED, 0xCE, 0xD5, 0xE8, /* 0x24-0x27 */ - 0xB3, 0x62, 0xED, 0xC9, 0xB3, 0x63, 0xB3, 0x64, /* 0x28-0x2B */ - 0xED, 0xC7, 0xED, 0xBE, 0xB3, 0x65, 0xB3, 0x66, /* 0x2C-0x2F */ - 0xC5, 0xE9, 0xB3, 0x67, 0xB3, 0x68, 0xB3, 0x69, /* 0x30-0x33 */ - 0xC6, 0xC6, 0xB3, 0x6A, 0xB3, 0x6B, 0xC9, 0xE9, /* 0x34-0x37 */ - 0xD4, 0xD2, 0xED, 0xC1, 0xED, 0xC2, 0xED, 0xC3, /* 0x38-0x3B */ - 0xED, 0xC5, 0xB3, 0x6C, 0xC0, 0xF9, 0xB3, 0x6D, /* 0x3C-0x3F */ - 0xB4, 0xA1, 0xB3, 0x6E, 0xB3, 0x6F, 0xB3, 0x70, /* 0x40-0x43 */ - 0xB3, 0x71, 0xB9, 0xE8, 0xB3, 0x72, 0xED, 0xD0, /* 0x44-0x47 */ - 0xB3, 0x73, 0xB3, 0x74, 0xB3, 0x75, 0xB3, 0x76, /* 0x48-0x4B */ - 0xED, 0xD1, 0xB3, 0x77, 0xED, 0xCA, 0xB3, 0x78, /* 0x4C-0x4F */ - 0xED, 0xCF, 0xB3, 0x79, 0xCE, 0xF8, 0xB3, 0x7A, /* 0x50-0x53 */ - 0xB3, 0x7B, 0xCB, 0xB6, 0xED, 0xCC, 0xED, 0xCD, /* 0x54-0x57 */ - 0xB3, 0x7C, 0xB3, 0x7D, 0xB3, 0x7E, 0xB3, 0x80, /* 0x58-0x5B */ - 0xB3, 0x81, 0xCF, 0xF5, 0xB3, 0x82, 0xB3, 0x83, /* 0x5C-0x5F */ - 0xB3, 0x84, 0xB3, 0x85, 0xB3, 0x86, 0xB3, 0x87, /* 0x60-0x63 */ - 0xB3, 0x88, 0xB3, 0x89, 0xB3, 0x8A, 0xB3, 0x8B, /* 0x64-0x67 */ - 0xB3, 0x8C, 0xB3, 0x8D, 0xED, 0xD2, 0xC1, 0xF2, /* 0x68-0x6B */ - 0xD3, 0xB2, 0xED, 0xCB, 0xC8, 0xB7, 0xB3, 0x8E, /* 0x6C-0x6F */ - 0xB3, 0x8F, 0xB3, 0x90, 0xB3, 0x91, 0xB3, 0x92, /* 0x70-0x73 */ - 0xB3, 0x93, 0xB3, 0x94, 0xB3, 0x95, 0xBC, 0xEF, /* 0x74-0x77 */ - 0xB3, 0x96, 0xB3, 0x97, 0xB3, 0x98, 0xB3, 0x99, /* 0x78-0x7B */ - 0xC5, 0xF0, 0xB3, 0x9A, 0xB3, 0x9B, 0xB3, 0x9C, /* 0x7C-0x7F */ - - 0xB3, 0x9D, 0xB3, 0x9E, 0xB3, 0x9F, 0xB3, 0xA0, /* 0x80-0x83 */ - 0xB4, 0x40, 0xB4, 0x41, 0xB4, 0x42, 0xED, 0xD6, /* 0x84-0x87 */ - 0xB4, 0x43, 0xB5, 0xEF, 0xB4, 0x44, 0xB4, 0x45, /* 0x88-0x8B */ - 0xC2, 0xB5, 0xB0, 0xAD, 0xCB, 0xE9, 0xB4, 0x46, /* 0x8C-0x8F */ - 0xB4, 0x47, 0xB1, 0xAE, 0xB4, 0x48, 0xED, 0xD4, /* 0x90-0x93 */ - 0xB4, 0x49, 0xB4, 0x4A, 0xB4, 0x4B, 0xCD, 0xEB, /* 0x94-0x97 */ - 0xB5, 0xE2, 0xB4, 0x4C, 0xED, 0xD5, 0xED, 0xD3, /* 0x98-0x9B */ - 0xED, 0xD7, 0xB4, 0x4D, 0xB4, 0x4E, 0xB5, 0xFA, /* 0x9C-0x9F */ - 0xB4, 0x4F, 0xED, 0xD8, 0xB4, 0x50, 0xED, 0xD9, /* 0xA0-0xA3 */ - 0xB4, 0x51, 0xED, 0xDC, 0xB4, 0x52, 0xB1, 0xCC, /* 0xA4-0xA7 */ - 0xB4, 0x53, 0xB4, 0x54, 0xB4, 0x55, 0xB4, 0x56, /* 0xA8-0xAB */ - 0xB4, 0x57, 0xB4, 0x58, 0xB4, 0x59, 0xB4, 0x5A, /* 0xAC-0xAF */ - 0xC5, 0xF6, 0xBC, 0xEE, 0xED, 0xDA, 0xCC, 0xBC, /* 0xB0-0xB3 */ - 0xB2, 0xEA, 0xB4, 0x5B, 0xB4, 0x5C, 0xB4, 0x5D, /* 0xB4-0xB7 */ - 0xB4, 0x5E, 0xED, 0xDB, 0xB4, 0x5F, 0xB4, 0x60, /* 0xB8-0xBB */ - 0xB4, 0x61, 0xB4, 0x62, 0xC4, 0xEB, 0xB4, 0x63, /* 0xBC-0xBF */ - 0xB4, 0x64, 0xB4, 0xC5, 0xB4, 0x65, 0xB4, 0x66, /* 0xC0-0xC3 */ - 0xB4, 0x67, 0xB0, 0xF5, 0xB4, 0x68, 0xB4, 0x69, /* 0xC4-0xC7 */ - 0xB4, 0x6A, 0xED, 0xDF, 0xC0, 0xDA, 0xB4, 0xE8, /* 0xC8-0xCB */ - 0xB4, 0x6B, 0xB4, 0x6C, 0xB4, 0x6D, 0xB4, 0x6E, /* 0xCC-0xCF */ - 0xC5, 0xCD, 0xB4, 0x6F, 0xB4, 0x70, 0xB4, 0x71, /* 0xD0-0xD3 */ - 0xED, 0xDD, 0xBF, 0xC4, 0xB4, 0x72, 0xB4, 0x73, /* 0xD4-0xD7 */ - 0xB4, 0x74, 0xED, 0xDE, 0xB4, 0x75, 0xB4, 0x76, /* 0xD8-0xDB */ - 0xB4, 0x77, 0xB4, 0x78, 0xB4, 0x79, 0xB4, 0x7A, /* 0xDC-0xDF */ - 0xB4, 0x7B, 0xB4, 0x7C, 0xB4, 0x7D, 0xB4, 0x7E, /* 0xE0-0xE3 */ - 0xB4, 0x80, 0xB4, 0x81, 0xB4, 0x82, 0xB4, 0x83, /* 0xE4-0xE7 */ - 0xC4, 0xA5, 0xB4, 0x84, 0xB4, 0x85, 0xB4, 0x86, /* 0xE8-0xEB */ - 0xED, 0xE0, 0xB4, 0x87, 0xB4, 0x88, 0xB4, 0x89, /* 0xEC-0xEF */ - 0xB4, 0x8A, 0xB4, 0x8B, 0xED, 0xE1, 0xB4, 0x8C, /* 0xF0-0xF3 */ - 0xED, 0xE3, 0xB4, 0x8D, 0xB4, 0x8E, 0xC1, 0xD7, /* 0xF4-0xF7 */ - 0xB4, 0x8F, 0xB4, 0x90, 0xBB, 0xC7, 0xB4, 0x91, /* 0xF8-0xFB */ - 0xB4, 0x92, 0xB4, 0x93, 0xB4, 0x94, 0xB4, 0x95, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_79[512] = { - 0xB4, 0x96, 0xBD, 0xB8, 0xB4, 0x97, 0xB4, 0x98, /* 0x00-0x03 */ - 0xB4, 0x99, 0xED, 0xE2, 0xB4, 0x9A, 0xB4, 0x9B, /* 0x04-0x07 */ - 0xB4, 0x9C, 0xB4, 0x9D, 0xB4, 0x9E, 0xB4, 0x9F, /* 0x08-0x0B */ - 0xB4, 0xA0, 0xB5, 0x40, 0xB5, 0x41, 0xB5, 0x42, /* 0x0C-0x0F */ - 0xB5, 0x43, 0xB5, 0x44, 0xB5, 0x45, 0xED, 0xE4, /* 0x10-0x13 */ - 0xB5, 0x46, 0xB5, 0x47, 0xB5, 0x48, 0xB5, 0x49, /* 0x14-0x17 */ - 0xB5, 0x4A, 0xB5, 0x4B, 0xB5, 0x4C, 0xB5, 0x4D, /* 0x18-0x1B */ - 0xB5, 0x4E, 0xB5, 0x4F, 0xED, 0xE6, 0xB5, 0x50, /* 0x1C-0x1F */ - 0xB5, 0x51, 0xB5, 0x52, 0xB5, 0x53, 0xB5, 0x54, /* 0x20-0x23 */ - 0xED, 0xE5, 0xB5, 0x55, 0xB5, 0x56, 0xB5, 0x57, /* 0x24-0x27 */ - 0xB5, 0x58, 0xB5, 0x59, 0xB5, 0x5A, 0xB5, 0x5B, /* 0x28-0x2B */ - 0xB5, 0x5C, 0xB5, 0x5D, 0xB5, 0x5E, 0xB5, 0x5F, /* 0x2C-0x2F */ - 0xB5, 0x60, 0xB5, 0x61, 0xB5, 0x62, 0xB5, 0x63, /* 0x30-0x33 */ - 0xED, 0xE7, 0xB5, 0x64, 0xB5, 0x65, 0xB5, 0x66, /* 0x34-0x37 */ - 0xB5, 0x67, 0xB5, 0x68, 0xCA, 0xBE, 0xEC, 0xEA, /* 0x38-0x3B */ - 0xC0, 0xF1, 0xB5, 0x69, 0xC9, 0xE7, 0xB5, 0x6A, /* 0x3C-0x3F */ - 0xEC, 0xEB, 0xC6, 0xEE, 0xB5, 0x6B, 0xB5, 0x6C, /* 0x40-0x43 */ - 0xB5, 0x6D, 0xB5, 0x6E, 0xEC, 0xEC, 0xB5, 0x6F, /* 0x44-0x47 */ - 0xC6, 0xED, 0xEC, 0xED, 0xB5, 0x70, 0xB5, 0x71, /* 0x48-0x4B */ - 0xB5, 0x72, 0xB5, 0x73, 0xB5, 0x74, 0xB5, 0x75, /* 0x4C-0x4F */ - 0xB5, 0x76, 0xB5, 0x77, 0xB5, 0x78, 0xEC, 0xF0, /* 0x50-0x53 */ - 0xB5, 0x79, 0xB5, 0x7A, 0xD7, 0xE6, 0xEC, 0xF3, /* 0x54-0x57 */ - 0xB5, 0x7B, 0xB5, 0x7C, 0xEC, 0xF1, 0xEC, 0xEE, /* 0x58-0x5B */ - 0xEC, 0xEF, 0xD7, 0xA3, 0xC9, 0xF1, 0xCB, 0xEE, /* 0x5C-0x5F */ - 0xEC, 0xF4, 0xB5, 0x7D, 0xEC, 0xF2, 0xB5, 0x7E, /* 0x60-0x63 */ - 0xB5, 0x80, 0xCF, 0xE9, 0xB5, 0x81, 0xEC, 0xF6, /* 0x64-0x67 */ - 0xC6, 0xB1, 0xB5, 0x82, 0xB5, 0x83, 0xB5, 0x84, /* 0x68-0x6B */ - 0xB5, 0x85, 0xBC, 0xC0, 0xB5, 0x86, 0xEC, 0xF5, /* 0x6C-0x6F */ - 0xB5, 0x87, 0xB5, 0x88, 0xB5, 0x89, 0xB5, 0x8A, /* 0x70-0x73 */ - 0xB5, 0x8B, 0xB5, 0x8C, 0xB5, 0x8D, 0xB5, 0xBB, /* 0x74-0x77 */ - 0xBB, 0xF6, 0xB5, 0x8E, 0xEC, 0xF7, 0xB5, 0x8F, /* 0x78-0x7B */ - 0xB5, 0x90, 0xB5, 0x91, 0xB5, 0x92, 0xB5, 0x93, /* 0x7C-0x7F */ - - 0xD9, 0xF7, 0xBD, 0xFB, 0xB5, 0x94, 0xB5, 0x95, /* 0x80-0x83 */ - 0xC2, 0xBB, 0xEC, 0xF8, 0xB5, 0x96, 0xB5, 0x97, /* 0x84-0x87 */ - 0xB5, 0x98, 0xB5, 0x99, 0xEC, 0xF9, 0xB5, 0x9A, /* 0x88-0x8B */ - 0xB5, 0x9B, 0xB5, 0x9C, 0xB5, 0x9D, 0xB8, 0xA3, /* 0x8C-0x8F */ - 0xB5, 0x9E, 0xB5, 0x9F, 0xB5, 0xA0, 0xB6, 0x40, /* 0x90-0x93 */ - 0xB6, 0x41, 0xB6, 0x42, 0xB6, 0x43, 0xB6, 0x44, /* 0x94-0x97 */ - 0xB6, 0x45, 0xB6, 0x46, 0xEC, 0xFA, 0xB6, 0x47, /* 0x98-0x9B */ - 0xB6, 0x48, 0xB6, 0x49, 0xB6, 0x4A, 0xB6, 0x4B, /* 0x9C-0x9F */ - 0xB6, 0x4C, 0xB6, 0x4D, 0xB6, 0x4E, 0xB6, 0x4F, /* 0xA0-0xA3 */ - 0xB6, 0x50, 0xB6, 0x51, 0xB6, 0x52, 0xEC, 0xFB, /* 0xA4-0xA7 */ - 0xB6, 0x53, 0xB6, 0x54, 0xB6, 0x55, 0xB6, 0x56, /* 0xA8-0xAB */ - 0xB6, 0x57, 0xB6, 0x58, 0xB6, 0x59, 0xB6, 0x5A, /* 0xAC-0xAF */ - 0xB6, 0x5B, 0xB6, 0x5C, 0xB6, 0x5D, 0xEC, 0xFC, /* 0xB0-0xB3 */ - 0xB6, 0x5E, 0xB6, 0x5F, 0xB6, 0x60, 0xB6, 0x61, /* 0xB4-0xB7 */ - 0xB6, 0x62, 0xD3, 0xED, 0xD8, 0xAE, 0xC0, 0xEB, /* 0xB8-0xBB */ - 0xB6, 0x63, 0xC7, 0xDD, 0xBA, 0xCC, 0xB6, 0x64, /* 0xBC-0xBF */ - 0xD0, 0xE3, 0xCB, 0xBD, 0xB6, 0x65, 0xCD, 0xBA, /* 0xC0-0xC3 */ - 0xB6, 0x66, 0xB6, 0x67, 0xB8, 0xD1, 0xB6, 0x68, /* 0xC4-0xC7 */ - 0xB6, 0x69, 0xB1, 0xFC, 0xB6, 0x6A, 0xC7, 0xEF, /* 0xC8-0xCB */ - 0xB6, 0x6B, 0xD6, 0xD6, 0xB6, 0x6C, 0xB6, 0x6D, /* 0xCC-0xCF */ - 0xB6, 0x6E, 0xBF, 0xC6, 0xC3, 0xEB, 0xB6, 0x6F, /* 0xD0-0xD3 */ - 0xB6, 0x70, 0xEF, 0xF5, 0xB6, 0x71, 0xB6, 0x72, /* 0xD4-0xD7 */ - 0xC3, 0xD8, 0xB6, 0x73, 0xB6, 0x74, 0xB6, 0x75, /* 0xD8-0xDB */ - 0xB6, 0x76, 0xB6, 0x77, 0xB6, 0x78, 0xD7, 0xE2, /* 0xDC-0xDF */ - 0xB6, 0x79, 0xB6, 0x7A, 0xB6, 0x7B, 0xEF, 0xF7, /* 0xE0-0xE3 */ - 0xB3, 0xD3, 0xB6, 0x7C, 0xC7, 0xD8, 0xD1, 0xED, /* 0xE4-0xE7 */ - 0xB6, 0x7D, 0xD6, 0xC8, 0xB6, 0x7E, 0xEF, 0xF8, /* 0xE8-0xEB */ - 0xB6, 0x80, 0xEF, 0xF6, 0xB6, 0x81, 0xBB, 0xFD, /* 0xEC-0xEF */ - 0xB3, 0xC6, 0xB6, 0x82, 0xB6, 0x83, 0xB6, 0x84, /* 0xF0-0xF3 */ - 0xB6, 0x85, 0xB6, 0x86, 0xB6, 0x87, 0xB6, 0x88, /* 0xF4-0xF7 */ - 0xBD, 0xD5, 0xB6, 0x89, 0xB6, 0x8A, 0xD2, 0xC6, /* 0xF8-0xFB */ - 0xB6, 0x8B, 0xBB, 0xE0, 0xB6, 0x8C, 0xB6, 0x8D, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_7A[512] = { - 0xCF, 0xA1, 0xB6, 0x8E, 0xEF, 0xFC, 0xEF, 0xFB, /* 0x00-0x03 */ - 0xB6, 0x8F, 0xB6, 0x90, 0xEF, 0xF9, 0xB6, 0x91, /* 0x04-0x07 */ - 0xB6, 0x92, 0xB6, 0x93, 0xB6, 0x94, 0xB3, 0xCC, /* 0x08-0x0B */ - 0xB6, 0x95, 0xC9, 0xD4, 0xCB, 0xB0, 0xB6, 0x96, /* 0x0C-0x0F */ - 0xB6, 0x97, 0xB6, 0x98, 0xB6, 0x99, 0xB6, 0x9A, /* 0x10-0x13 */ - 0xEF, 0xFE, 0xB6, 0x9B, 0xB6, 0x9C, 0xB0, 0xDE, /* 0x14-0x17 */ - 0xB6, 0x9D, 0xB6, 0x9E, 0xD6, 0xC9, 0xB6, 0x9F, /* 0x18-0x1B */ - 0xB6, 0xA0, 0xB7, 0x40, 0xEF, 0xFD, 0xB7, 0x41, /* 0x1C-0x1F */ - 0xB3, 0xED, 0xB7, 0x42, 0xB7, 0x43, 0xF6, 0xD5, /* 0x20-0x23 */ - 0xB7, 0x44, 0xB7, 0x45, 0xB7, 0x46, 0xB7, 0x47, /* 0x24-0x27 */ - 0xB7, 0x48, 0xB7, 0x49, 0xB7, 0x4A, 0xB7, 0x4B, /* 0x28-0x2B */ - 0xB7, 0x4C, 0xB7, 0x4D, 0xB7, 0x4E, 0xB7, 0x4F, /* 0x2C-0x2F */ - 0xB7, 0x50, 0xB7, 0x51, 0xB7, 0x52, 0xCE, 0xC8, /* 0x30-0x33 */ - 0xB7, 0x53, 0xB7, 0x54, 0xB7, 0x55, 0xF0, 0xA2, /* 0x34-0x37 */ - 0xB7, 0x56, 0xF0, 0xA1, 0xB7, 0x57, 0xB5, 0xBE, /* 0x38-0x3B */ - 0xBC, 0xDA, 0xBB, 0xFC, 0xB7, 0x58, 0xB8, 0xE5, /* 0x3C-0x3F */ - 0xB7, 0x59, 0xB7, 0x5A, 0xB7, 0x5B, 0xB7, 0x5C, /* 0x40-0x43 */ - 0xB7, 0x5D, 0xB7, 0x5E, 0xC4, 0xC2, 0xB7, 0x5F, /* 0x44-0x47 */ - 0xB7, 0x60, 0xB7, 0x61, 0xB7, 0x62, 0xB7, 0x63, /* 0x48-0x4B */ - 0xB7, 0x64, 0xB7, 0x65, 0xB7, 0x66, 0xB7, 0x67, /* 0x4C-0x4F */ - 0xB7, 0x68, 0xF0, 0xA3, 0xB7, 0x69, 0xB7, 0x6A, /* 0x50-0x53 */ - 0xB7, 0x6B, 0xB7, 0x6C, 0xB7, 0x6D, 0xCB, 0xEB, /* 0x54-0x57 */ - 0xB7, 0x6E, 0xB7, 0x6F, 0xB7, 0x70, 0xB7, 0x71, /* 0x58-0x5B */ - 0xB7, 0x72, 0xB7, 0x73, 0xB7, 0x74, 0xB7, 0x75, /* 0x5C-0x5F */ - 0xB7, 0x76, 0xB7, 0x77, 0xB7, 0x78, 0xB7, 0x79, /* 0x60-0x63 */ - 0xB7, 0x7A, 0xB7, 0x7B, 0xB7, 0x7C, 0xB7, 0x7D, /* 0x64-0x67 */ - 0xB7, 0x7E, 0xB7, 0x80, 0xB7, 0x81, 0xB7, 0x82, /* 0x68-0x6B */ - 0xB7, 0x83, 0xB7, 0x84, 0xB7, 0x85, 0xB7, 0x86, /* 0x6C-0x6F */ - 0xF0, 0xA6, 0xB7, 0x87, 0xB7, 0x88, 0xB7, 0x89, /* 0x70-0x73 */ - 0xD1, 0xA8, 0xB7, 0x8A, 0xBE, 0xBF, 0xC7, 0xEE, /* 0x74-0x77 */ - 0xF1, 0xB6, 0xF1, 0xB7, 0xBF, 0xD5, 0xB7, 0x8B, /* 0x78-0x7B */ - 0xB7, 0x8C, 0xB7, 0x8D, 0xB7, 0x8E, 0xB4, 0xA9, /* 0x7C-0x7F */ - - 0xF1, 0xB8, 0xCD, 0xBB, 0xB7, 0x8F, 0xC7, 0xD4, /* 0x80-0x83 */ - 0xD5, 0xAD, 0xB7, 0x90, 0xF1, 0xB9, 0xB7, 0x91, /* 0x84-0x87 */ - 0xF1, 0xBA, 0xB7, 0x92, 0xB7, 0x93, 0xB7, 0x94, /* 0x88-0x8B */ - 0xB7, 0x95, 0xC7, 0xCF, 0xB7, 0x96, 0xB7, 0x97, /* 0x8C-0x8F */ - 0xB7, 0x98, 0xD2, 0xA4, 0xD6, 0xCF, 0xB7, 0x99, /* 0x90-0x93 */ - 0xB7, 0x9A, 0xF1, 0xBB, 0xBD, 0xD1, 0xB4, 0xB0, /* 0x94-0x97 */ - 0xBE, 0xBD, 0xB7, 0x9B, 0xB7, 0x9C, 0xB7, 0x9D, /* 0x98-0x9B */ - 0xB4, 0xDC, 0xCE, 0xD1, 0xB7, 0x9E, 0xBF, 0xDF, /* 0x9C-0x9F */ - 0xF1, 0xBD, 0xB7, 0x9F, 0xB7, 0xA0, 0xB8, 0x40, /* 0xA0-0xA3 */ - 0xB8, 0x41, 0xBF, 0xFA, 0xF1, 0xBC, 0xB8, 0x42, /* 0xA4-0xA7 */ - 0xF1, 0xBF, 0xB8, 0x43, 0xB8, 0x44, 0xB8, 0x45, /* 0xA8-0xAB */ - 0xF1, 0xBE, 0xF1, 0xC0, 0xB8, 0x46, 0xB8, 0x47, /* 0xAC-0xAF */ - 0xB8, 0x48, 0xB8, 0x49, 0xB8, 0x4A, 0xF1, 0xC1, /* 0xB0-0xB3 */ - 0xB8, 0x4B, 0xB8, 0x4C, 0xB8, 0x4D, 0xB8, 0x4E, /* 0xB4-0xB7 */ - 0xB8, 0x4F, 0xB8, 0x50, 0xB8, 0x51, 0xB8, 0x52, /* 0xB8-0xBB */ - 0xB8, 0x53, 0xB8, 0x54, 0xB8, 0x55, 0xC1, 0xFE, /* 0xBC-0xBF */ - 0xB8, 0x56, 0xB8, 0x57, 0xB8, 0x58, 0xB8, 0x59, /* 0xC0-0xC3 */ - 0xB8, 0x5A, 0xB8, 0x5B, 0xB8, 0x5C, 0xB8, 0x5D, /* 0xC4-0xC7 */ - 0xB8, 0x5E, 0xB8, 0x5F, 0xB8, 0x60, 0xC1, 0xA2, /* 0xC8-0xCB */ - 0xB8, 0x61, 0xB8, 0x62, 0xB8, 0x63, 0xB8, 0x64, /* 0xCC-0xCF */ - 0xB8, 0x65, 0xB8, 0x66, 0xB8, 0x67, 0xB8, 0x68, /* 0xD0-0xD3 */ - 0xB8, 0x69, 0xB8, 0x6A, 0xCA, 0xFA, 0xB8, 0x6B, /* 0xD4-0xD7 */ - 0xB8, 0x6C, 0xD5, 0xBE, 0xB8, 0x6D, 0xB8, 0x6E, /* 0xD8-0xDB */ - 0xB8, 0x6F, 0xB8, 0x70, 0xBE, 0xBA, 0xBE, 0xB9, /* 0xDC-0xDF */ - 0xD5, 0xC2, 0xB8, 0x71, 0xB8, 0x72, 0xBF, 0xA2, /* 0xE0-0xE3 */ - 0xB8, 0x73, 0xCD, 0xAF, 0xF1, 0xB5, 0xB8, 0x74, /* 0xE4-0xE7 */ - 0xB8, 0x75, 0xB8, 0x76, 0xB8, 0x77, 0xB8, 0x78, /* 0xE8-0xEB */ - 0xB8, 0x79, 0xBD, 0xDF, 0xB8, 0x7A, 0xB6, 0xCB, /* 0xEC-0xEF */ - 0xB8, 0x7B, 0xB8, 0x7C, 0xB8, 0x7D, 0xB8, 0x7E, /* 0xF0-0xF3 */ - 0xB8, 0x80, 0xB8, 0x81, 0xB8, 0x82, 0xB8, 0x83, /* 0xF4-0xF7 */ - 0xB8, 0x84, 0xD6, 0xF1, 0xF3, 0xC3, 0xB8, 0x85, /* 0xF8-0xFB */ - 0xB8, 0x86, 0xF3, 0xC4, 0xB8, 0x87, 0xB8, 0xCD, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_7B[512] = { - 0xB8, 0x88, 0xB8, 0x89, 0xB8, 0x8A, 0xF3, 0xC6, /* 0x00-0x03 */ - 0xF3, 0xC7, 0xB8, 0x8B, 0xB0, 0xCA, 0xB8, 0x8C, /* 0x04-0x07 */ - 0xF3, 0xC5, 0xB8, 0x8D, 0xF3, 0xC9, 0xCB, 0xF1, /* 0x08-0x0B */ - 0xB8, 0x8E, 0xB8, 0x8F, 0xB8, 0x90, 0xF3, 0xCB, /* 0x0C-0x0F */ - 0xB8, 0x91, 0xD0, 0xA6, 0xB8, 0x92, 0xB8, 0x93, /* 0x10-0x13 */ - 0xB1, 0xCA, 0xF3, 0xC8, 0xB8, 0x94, 0xB8, 0x95, /* 0x14-0x17 */ - 0xB8, 0x96, 0xF3, 0xCF, 0xB8, 0x97, 0xB5, 0xD1, /* 0x18-0x1B */ - 0xB8, 0x98, 0xB8, 0x99, 0xF3, 0xD7, 0xB8, 0x9A, /* 0x1C-0x1F */ - 0xF3, 0xD2, 0xB8, 0x9B, 0xB8, 0x9C, 0xB8, 0x9D, /* 0x20-0x23 */ - 0xF3, 0xD4, 0xF3, 0xD3, 0xB7, 0xFB, 0xB8, 0x9E, /* 0x24-0x27 */ - 0xB1, 0xBF, 0xB8, 0x9F, 0xF3, 0xCE, 0xF3, 0xCA, /* 0x28-0x2B */ - 0xB5, 0xDA, 0xB8, 0xA0, 0xF3, 0xD0, 0xB9, 0x40, /* 0x2C-0x2F */ - 0xB9, 0x41, 0xF3, 0xD1, 0xB9, 0x42, 0xF3, 0xD5, /* 0x30-0x33 */ - 0xB9, 0x43, 0xB9, 0x44, 0xB9, 0x45, 0xB9, 0x46, /* 0x34-0x37 */ - 0xF3, 0xCD, 0xB9, 0x47, 0xBC, 0xE3, 0xB9, 0x48, /* 0x38-0x3B */ - 0xC1, 0xFD, 0xB9, 0x49, 0xF3, 0xD6, 0xB9, 0x4A, /* 0x3C-0x3F */ - 0xB9, 0x4B, 0xB9, 0x4C, 0xB9, 0x4D, 0xB9, 0x4E, /* 0x40-0x43 */ - 0xB9, 0x4F, 0xF3, 0xDA, 0xB9, 0x50, 0xF3, 0xCC, /* 0x44-0x47 */ - 0xB9, 0x51, 0xB5, 0xC8, 0xB9, 0x52, 0xBD, 0xEE, /* 0x48-0x4B */ - 0xF3, 0xDC, 0xB9, 0x53, 0xB9, 0x54, 0xB7, 0xA4, /* 0x4C-0x4F */ - 0xBF, 0xF0, 0xD6, 0xFE, 0xCD, 0xB2, 0xB9, 0x55, /* 0x50-0x53 */ - 0xB4, 0xF0, 0xB9, 0x56, 0xB2, 0xDF, 0xB9, 0x57, /* 0x54-0x57 */ - 0xF3, 0xD8, 0xB9, 0x58, 0xF3, 0xD9, 0xC9, 0xB8, /* 0x58-0x5B */ - 0xB9, 0x59, 0xF3, 0xDD, 0xB9, 0x5A, 0xB9, 0x5B, /* 0x5C-0x5F */ - 0xF3, 0xDE, 0xB9, 0x5C, 0xF3, 0xE1, 0xB9, 0x5D, /* 0x60-0x63 */ - 0xB9, 0x5E, 0xB9, 0x5F, 0xB9, 0x60, 0xB9, 0x61, /* 0x64-0x67 */ - 0xB9, 0x62, 0xB9, 0x63, 0xB9, 0x64, 0xB9, 0x65, /* 0x68-0x6B */ - 0xB9, 0x66, 0xB9, 0x67, 0xF3, 0xDF, 0xB9, 0x68, /* 0x6C-0x6F */ - 0xB9, 0x69, 0xF3, 0xE3, 0xF3, 0xE2, 0xB9, 0x6A, /* 0x70-0x73 */ - 0xB9, 0x6B, 0xF3, 0xDB, 0xB9, 0x6C, 0xBF, 0xEA, /* 0x74-0x77 */ - 0xB9, 0x6D, 0xB3, 0xEF, 0xB9, 0x6E, 0xF3, 0xE0, /* 0x78-0x7B */ - 0xB9, 0x6F, 0xB9, 0x70, 0xC7, 0xA9, 0xB9, 0x71, /* 0x7C-0x7F */ - - 0xBC, 0xF2, 0xB9, 0x72, 0xB9, 0x73, 0xB9, 0x74, /* 0x80-0x83 */ - 0xB9, 0x75, 0xF3, 0xEB, 0xB9, 0x76, 0xB9, 0x77, /* 0x84-0x87 */ - 0xB9, 0x78, 0xB9, 0x79, 0xB9, 0x7A, 0xB9, 0x7B, /* 0x88-0x8B */ - 0xB9, 0x7C, 0xB9, 0xBF, 0xB9, 0x7D, 0xB9, 0x7E, /* 0x8C-0x8F */ - 0xF3, 0xE4, 0xB9, 0x80, 0xB9, 0x81, 0xB9, 0x82, /* 0x90-0x93 */ - 0xB2, 0xAD, 0xBB, 0xFE, 0xB9, 0x83, 0xCB, 0xE3, /* 0x94-0x97 */ - 0xB9, 0x84, 0xB9, 0x85, 0xB9, 0x86, 0xB9, 0x87, /* 0x98-0x9B */ - 0xF3, 0xED, 0xF3, 0xE9, 0xB9, 0x88, 0xB9, 0x89, /* 0x9C-0x9F */ - 0xB9, 0x8A, 0xB9, 0xDC, 0xF3, 0xEE, 0xB9, 0x8B, /* 0xA0-0xA3 */ - 0xB9, 0x8C, 0xB9, 0x8D, 0xF3, 0xE5, 0xF3, 0xE6, /* 0xA4-0xA7 */ - 0xF3, 0xEA, 0xC2, 0xE1, 0xF3, 0xEC, 0xF3, 0xEF, /* 0xA8-0xAB */ - 0xF3, 0xE8, 0xBC, 0xFD, 0xB9, 0x8E, 0xB9, 0x8F, /* 0xAC-0xAF */ - 0xB9, 0x90, 0xCF, 0xE4, 0xB9, 0x91, 0xB9, 0x92, /* 0xB0-0xB3 */ - 0xF3, 0xF0, 0xB9, 0x93, 0xB9, 0x94, 0xB9, 0x95, /* 0xB4-0xB7 */ - 0xF3, 0xE7, 0xB9, 0x96, 0xB9, 0x97, 0xB9, 0x98, /* 0xB8-0xBB */ - 0xB9, 0x99, 0xB9, 0x9A, 0xB9, 0x9B, 0xB9, 0x9C, /* 0xBC-0xBF */ - 0xB9, 0x9D, 0xF3, 0xF2, 0xB9, 0x9E, 0xB9, 0x9F, /* 0xC0-0xC3 */ - 0xB9, 0xA0, 0xBA, 0x40, 0xD7, 0xAD, 0xC6, 0xAA, /* 0xC4-0xC7 */ - 0xBA, 0x41, 0xBA, 0x42, 0xBA, 0x43, 0xBA, 0x44, /* 0xC8-0xCB */ - 0xF3, 0xF3, 0xBA, 0x45, 0xBA, 0x46, 0xBA, 0x47, /* 0xCC-0xCF */ - 0xBA, 0x48, 0xF3, 0xF1, 0xBA, 0x49, 0xC2, 0xA8, /* 0xD0-0xD3 */ - 0xBA, 0x4A, 0xBA, 0x4B, 0xBA, 0x4C, 0xBA, 0x4D, /* 0xD4-0xD7 */ - 0xBA, 0x4E, 0xB8, 0xDD, 0xF3, 0xF5, 0xBA, 0x4F, /* 0xD8-0xDB */ - 0xBA, 0x50, 0xF3, 0xF4, 0xBA, 0x51, 0xBA, 0x52, /* 0xDC-0xDF */ - 0xBA, 0x53, 0xB4, 0xDB, 0xBA, 0x54, 0xBA, 0x55, /* 0xE0-0xE3 */ - 0xBA, 0x56, 0xF3, 0xF6, 0xF3, 0xF7, 0xBA, 0x57, /* 0xE4-0xE7 */ - 0xBA, 0x58, 0xBA, 0x59, 0xF3, 0xF8, 0xBA, 0x5A, /* 0xE8-0xEB */ - 0xBA, 0x5B, 0xBA, 0x5C, 0xC0, 0xBA, 0xBA, 0x5D, /* 0xEC-0xEF */ - 0xBA, 0x5E, 0xC0, 0xE9, 0xBA, 0x5F, 0xBA, 0x60, /* 0xF0-0xF3 */ - 0xBA, 0x61, 0xBA, 0x62, 0xBA, 0x63, 0xC5, 0xF1, /* 0xF4-0xF7 */ - 0xBA, 0x64, 0xBA, 0x65, 0xBA, 0x66, 0xBA, 0x67, /* 0xF8-0xFB */ - 0xF3, 0xFB, 0xBA, 0x68, 0xF3, 0xFA, 0xBA, 0x69, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_7C[512] = { - 0xBA, 0x6A, 0xBA, 0x6B, 0xBA, 0x6C, 0xBA, 0x6D, /* 0x00-0x03 */ - 0xBA, 0x6E, 0xBA, 0x6F, 0xBA, 0x70, 0xB4, 0xD8, /* 0x04-0x07 */ - 0xBA, 0x71, 0xBA, 0x72, 0xBA, 0x73, 0xF3, 0xFE, /* 0x08-0x0B */ - 0xF3, 0xF9, 0xBA, 0x74, 0xBA, 0x75, 0xF3, 0xFC, /* 0x0C-0x0F */ - 0xBA, 0x76, 0xBA, 0x77, 0xBA, 0x78, 0xBA, 0x79, /* 0x10-0x13 */ - 0xBA, 0x7A, 0xBA, 0x7B, 0xF3, 0xFD, 0xBA, 0x7C, /* 0x14-0x17 */ - 0xBA, 0x7D, 0xBA, 0x7E, 0xBA, 0x80, 0xBA, 0x81, /* 0x18-0x1B */ - 0xBA, 0x82, 0xBA, 0x83, 0xBA, 0x84, 0xF4, 0xA1, /* 0x1C-0x1F */ - 0xBA, 0x85, 0xBA, 0x86, 0xBA, 0x87, 0xBA, 0x88, /* 0x20-0x23 */ - 0xBA, 0x89, 0xBA, 0x8A, 0xF4, 0xA3, 0xBB, 0xC9, /* 0x24-0x27 */ - 0xBA, 0x8B, 0xBA, 0x8C, 0xF4, 0xA2, 0xBA, 0x8D, /* 0x28-0x2B */ - 0xBA, 0x8E, 0xBA, 0x8F, 0xBA, 0x90, 0xBA, 0x91, /* 0x2C-0x2F */ - 0xBA, 0x92, 0xBA, 0x93, 0xBA, 0x94, 0xBA, 0x95, /* 0x30-0x33 */ - 0xBA, 0x96, 0xBA, 0x97, 0xBA, 0x98, 0xBA, 0x99, /* 0x34-0x37 */ - 0xF4, 0xA4, 0xBA, 0x9A, 0xBA, 0x9B, 0xBA, 0x9C, /* 0x38-0x3B */ - 0xBA, 0x9D, 0xBA, 0x9E, 0xBA, 0x9F, 0xB2, 0xBE, /* 0x3C-0x3F */ - 0xF4, 0xA6, 0xF4, 0xA5, 0xBA, 0xA0, 0xBB, 0x40, /* 0x40-0x43 */ - 0xBB, 0x41, 0xBB, 0x42, 0xBB, 0x43, 0xBB, 0x44, /* 0x44-0x47 */ - 0xBB, 0x45, 0xBB, 0x46, 0xBB, 0x47, 0xBB, 0x48, /* 0x48-0x4B */ - 0xBB, 0x49, 0xBC, 0xAE, 0xBB, 0x4A, 0xBB, 0x4B, /* 0x4C-0x4F */ - 0xBB, 0x4C, 0xBB, 0x4D, 0xBB, 0x4E, 0xBB, 0x4F, /* 0x50-0x53 */ - 0xBB, 0x50, 0xBB, 0x51, 0xBB, 0x52, 0xBB, 0x53, /* 0x54-0x57 */ - 0xBB, 0x54, 0xBB, 0x55, 0xBB, 0x56, 0xBB, 0x57, /* 0x58-0x5B */ - 0xBB, 0x58, 0xBB, 0x59, 0xBB, 0x5A, 0xBB, 0x5B, /* 0x5C-0x5F */ - 0xBB, 0x5C, 0xBB, 0x5D, 0xBB, 0x5E, 0xBB, 0x5F, /* 0x60-0x63 */ - 0xBB, 0x60, 0xBB, 0x61, 0xBB, 0x62, 0xBB, 0x63, /* 0x64-0x67 */ - 0xBB, 0x64, 0xBB, 0x65, 0xBB, 0x66, 0xBB, 0x67, /* 0x68-0x6B */ - 0xBB, 0x68, 0xBB, 0x69, 0xBB, 0x6A, 0xBB, 0x6B, /* 0x6C-0x6F */ - 0xBB, 0x6C, 0xBB, 0x6D, 0xBB, 0x6E, 0xC3, 0xD7, /* 0x70-0x73 */ - 0xD9, 0xE1, 0xBB, 0x6F, 0xBB, 0x70, 0xBB, 0x71, /* 0x74-0x77 */ - 0xBB, 0x72, 0xBB, 0x73, 0xBB, 0x74, 0xC0, 0xE0, /* 0x78-0x7B */ - 0xF4, 0xCC, 0xD7, 0xD1, 0xBB, 0x75, 0xBB, 0x76, /* 0x7C-0x7F */ - - 0xBB, 0x77, 0xBB, 0x78, 0xBB, 0x79, 0xBB, 0x7A, /* 0x80-0x83 */ - 0xBB, 0x7B, 0xBB, 0x7C, 0xBB, 0x7D, 0xBB, 0x7E, /* 0x84-0x87 */ - 0xBB, 0x80, 0xB7, 0xDB, 0xBB, 0x81, 0xBB, 0x82, /* 0x88-0x8B */ - 0xBB, 0x83, 0xBB, 0x84, 0xBB, 0x85, 0xBB, 0x86, /* 0x8C-0x8F */ - 0xBB, 0x87, 0xF4, 0xCE, 0xC1, 0xA3, 0xBB, 0x88, /* 0x90-0x93 */ - 0xBB, 0x89, 0xC6, 0xC9, 0xBB, 0x8A, 0xB4, 0xD6, /* 0x94-0x97 */ - 0xD5, 0xB3, 0xBB, 0x8B, 0xBB, 0x8C, 0xBB, 0x8D, /* 0x98-0x9B */ - 0xF4, 0xD0, 0xF4, 0xCF, 0xF4, 0xD1, 0xCB, 0xDA, /* 0x9C-0x9F */ - 0xBB, 0x8E, 0xBB, 0x8F, 0xF4, 0xD2, 0xBB, 0x90, /* 0xA0-0xA3 */ - 0xD4, 0xC1, 0xD6, 0xE0, 0xBB, 0x91, 0xBB, 0x92, /* 0xA4-0xA7 */ - 0xBB, 0x93, 0xBB, 0x94, 0xB7, 0xE0, 0xBB, 0x95, /* 0xA8-0xAB */ - 0xBB, 0x96, 0xBB, 0x97, 0xC1, 0xB8, 0xBB, 0x98, /* 0xAC-0xAF */ - 0xBB, 0x99, 0xC1, 0xBB, 0xF4, 0xD3, 0xBE, 0xAC, /* 0xB0-0xB3 */ - 0xBB, 0x9A, 0xBB, 0x9B, 0xBB, 0x9C, 0xBB, 0x9D, /* 0xB4-0xB7 */ - 0xBB, 0x9E, 0xB4, 0xE2, 0xBB, 0x9F, 0xBB, 0xA0, /* 0xB8-0xBB */ - 0xF4, 0xD4, 0xF4, 0xD5, 0xBE, 0xAB, 0xBC, 0x40, /* 0xBC-0xBF */ - 0xBC, 0x41, 0xF4, 0xD6, 0xBC, 0x42, 0xBC, 0x43, /* 0xC0-0xC3 */ - 0xBC, 0x44, 0xF4, 0xDB, 0xBC, 0x45, 0xF4, 0xD7, /* 0xC4-0xC7 */ - 0xF4, 0xDA, 0xBC, 0x46, 0xBA, 0xFD, 0xBC, 0x47, /* 0xC8-0xCB */ - 0xF4, 0xD8, 0xF4, 0xD9, 0xBC, 0x48, 0xBC, 0x49, /* 0xCC-0xCF */ - 0xBC, 0x4A, 0xBC, 0x4B, 0xBC, 0x4C, 0xBC, 0x4D, /* 0xD0-0xD3 */ - 0xBC, 0x4E, 0xB8, 0xE2, 0xCC, 0xC7, 0xF4, 0xDC, /* 0xD4-0xD7 */ - 0xBC, 0x4F, 0xB2, 0xDA, 0xBC, 0x50, 0xBC, 0x51, /* 0xD8-0xDB */ - 0xC3, 0xD3, 0xBC, 0x52, 0xBC, 0x53, 0xD4, 0xE3, /* 0xDC-0xDF */ - 0xBF, 0xB7, 0xBC, 0x54, 0xBC, 0x55, 0xBC, 0x56, /* 0xE0-0xE3 */ - 0xBC, 0x57, 0xBC, 0x58, 0xBC, 0x59, 0xBC, 0x5A, /* 0xE4-0xE7 */ - 0xF4, 0xDD, 0xBC, 0x5B, 0xBC, 0x5C, 0xBC, 0x5D, /* 0xE8-0xEB */ - 0xBC, 0x5E, 0xBC, 0x5F, 0xBC, 0x60, 0xC5, 0xB4, /* 0xEC-0xEF */ - 0xBC, 0x61, 0xBC, 0x62, 0xBC, 0x63, 0xBC, 0x64, /* 0xF0-0xF3 */ - 0xBC, 0x65, 0xBC, 0x66, 0xBC, 0x67, 0xBC, 0x68, /* 0xF4-0xF7 */ - 0xF4, 0xE9, 0xBC, 0x69, 0xBC, 0x6A, 0xCF, 0xB5, /* 0xF8-0xFB */ - 0xBC, 0x6B, 0xBC, 0x6C, 0xBC, 0x6D, 0xBC, 0x6E, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_7D[512] = { - 0xBC, 0x6F, 0xBC, 0x70, 0xBC, 0x71, 0xBC, 0x72, /* 0x00-0x03 */ - 0xBC, 0x73, 0xBC, 0x74, 0xBC, 0x75, 0xBC, 0x76, /* 0x04-0x07 */ - 0xBC, 0x77, 0xBC, 0x78, 0xCE, 0xC9, 0xBC, 0x79, /* 0x08-0x0B */ - 0xBC, 0x7A, 0xBC, 0x7B, 0xBC, 0x7C, 0xBC, 0x7D, /* 0x0C-0x0F */ - 0xBC, 0x7E, 0xBC, 0x80, 0xBC, 0x81, 0xBC, 0x82, /* 0x10-0x13 */ - 0xBC, 0x83, 0xBC, 0x84, 0xBC, 0x85, 0xBC, 0x86, /* 0x14-0x17 */ - 0xBC, 0x87, 0xBC, 0x88, 0xBC, 0x89, 0xBC, 0x8A, /* 0x18-0x1B */ - 0xBC, 0x8B, 0xBC, 0x8C, 0xBC, 0x8D, 0xBC, 0x8E, /* 0x1C-0x1F */ - 0xCB, 0xD8, 0xBC, 0x8F, 0xCB, 0xF7, 0xBC, 0x90, /* 0x20-0x23 */ - 0xBC, 0x91, 0xBC, 0x92, 0xBC, 0x93, 0xBD, 0xF4, /* 0x24-0x27 */ - 0xBC, 0x94, 0xBC, 0x95, 0xBC, 0x96, 0xD7, 0xCF, /* 0x28-0x2B */ - 0xBC, 0x97, 0xBC, 0x98, 0xBC, 0x99, 0xC0, 0xDB, /* 0x2C-0x2F */ - 0xBC, 0x9A, 0xBC, 0x9B, 0xBC, 0x9C, 0xBC, 0x9D, /* 0x30-0x33 */ - 0xBC, 0x9E, 0xBC, 0x9F, 0xBC, 0xA0, 0xBD, 0x40, /* 0x34-0x37 */ - 0xBD, 0x41, 0xBD, 0x42, 0xBD, 0x43, 0xBD, 0x44, /* 0x38-0x3B */ - 0xBD, 0x45, 0xBD, 0x46, 0xBD, 0x47, 0xBD, 0x48, /* 0x3C-0x3F */ - 0xBD, 0x49, 0xBD, 0x4A, 0xBD, 0x4B, 0xBD, 0x4C, /* 0x40-0x43 */ - 0xBD, 0x4D, 0xBD, 0x4E, 0xBD, 0x4F, 0xBD, 0x50, /* 0x44-0x47 */ - 0xBD, 0x51, 0xBD, 0x52, 0xBD, 0x53, 0xBD, 0x54, /* 0x48-0x4B */ - 0xBD, 0x55, 0xBD, 0x56, 0xBD, 0x57, 0xBD, 0x58, /* 0x4C-0x4F */ - 0xBD, 0x59, 0xBD, 0x5A, 0xBD, 0x5B, 0xBD, 0x5C, /* 0x50-0x53 */ - 0xBD, 0x5D, 0xBD, 0x5E, 0xBD, 0x5F, 0xBD, 0x60, /* 0x54-0x57 */ - 0xBD, 0x61, 0xBD, 0x62, 0xBD, 0x63, 0xBD, 0x64, /* 0x58-0x5B */ - 0xBD, 0x65, 0xBD, 0x66, 0xBD, 0x67, 0xBD, 0x68, /* 0x5C-0x5F */ - 0xBD, 0x69, 0xBD, 0x6A, 0xBD, 0x6B, 0xBD, 0x6C, /* 0x60-0x63 */ - 0xBD, 0x6D, 0xBD, 0x6E, 0xBD, 0x6F, 0xBD, 0x70, /* 0x64-0x67 */ - 0xBD, 0x71, 0xBD, 0x72, 0xBD, 0x73, 0xBD, 0x74, /* 0x68-0x6B */ - 0xBD, 0x75, 0xBD, 0x76, 0xD0, 0xF5, 0xBD, 0x77, /* 0x6C-0x6F */ - 0xBD, 0x78, 0xBD, 0x79, 0xBD, 0x7A, 0xBD, 0x7B, /* 0x70-0x73 */ - 0xBD, 0x7C, 0xBD, 0x7D, 0xBD, 0x7E, 0xF4, 0xEA, /* 0x74-0x77 */ - 0xBD, 0x80, 0xBD, 0x81, 0xBD, 0x82, 0xBD, 0x83, /* 0x78-0x7B */ - 0xBD, 0x84, 0xBD, 0x85, 0xBD, 0x86, 0xBD, 0x87, /* 0x7C-0x7F */ - - 0xBD, 0x88, 0xBD, 0x89, 0xBD, 0x8A, 0xBD, 0x8B, /* 0x80-0x83 */ - 0xBD, 0x8C, 0xBD, 0x8D, 0xBD, 0x8E, 0xBD, 0x8F, /* 0x84-0x87 */ - 0xBD, 0x90, 0xBD, 0x91, 0xBD, 0x92, 0xBD, 0x93, /* 0x88-0x8B */ - 0xBD, 0x94, 0xBD, 0x95, 0xBD, 0x96, 0xBD, 0x97, /* 0x8C-0x8F */ - 0xBD, 0x98, 0xBD, 0x99, 0xBD, 0x9A, 0xBD, 0x9B, /* 0x90-0x93 */ - 0xBD, 0x9C, 0xBD, 0x9D, 0xBD, 0x9E, 0xBD, 0x9F, /* 0x94-0x97 */ - 0xBD, 0xA0, 0xBE, 0x40, 0xBE, 0x41, 0xBE, 0x42, /* 0x98-0x9B */ - 0xBE, 0x43, 0xBE, 0x44, 0xBE, 0x45, 0xBE, 0x46, /* 0x9C-0x9F */ - 0xBE, 0x47, 0xBE, 0x48, 0xBE, 0x49, 0xBE, 0x4A, /* 0xA0-0xA3 */ - 0xBE, 0x4B, 0xBE, 0x4C, 0xF4, 0xEB, 0xBE, 0x4D, /* 0xA4-0xA7 */ - 0xBE, 0x4E, 0xBE, 0x4F, 0xBE, 0x50, 0xBE, 0x51, /* 0xA8-0xAB */ - 0xBE, 0x52, 0xBE, 0x53, 0xF4, 0xEC, 0xBE, 0x54, /* 0xAC-0xAF */ - 0xBE, 0x55, 0xBE, 0x56, 0xBE, 0x57, 0xBE, 0x58, /* 0xB0-0xB3 */ - 0xBE, 0x59, 0xBE, 0x5A, 0xBE, 0x5B, 0xBE, 0x5C, /* 0xB4-0xB7 */ - 0xBE, 0x5D, 0xBE, 0x5E, 0xBE, 0x5F, 0xBE, 0x60, /* 0xB8-0xBB */ - 0xBE, 0x61, 0xBE, 0x62, 0xBE, 0x63, 0xBE, 0x64, /* 0xBC-0xBF */ - 0xBE, 0x65, 0xBE, 0x66, 0xBE, 0x67, 0xBE, 0x68, /* 0xC0-0xC3 */ - 0xBE, 0x69, 0xBE, 0x6A, 0xBE, 0x6B, 0xBE, 0x6C, /* 0xC4-0xC7 */ - 0xBE, 0x6D, 0xBE, 0x6E, 0xBE, 0x6F, 0xBE, 0x70, /* 0xC8-0xCB */ - 0xBE, 0x71, 0xBE, 0x72, 0xBE, 0x73, 0xBE, 0x74, /* 0xCC-0xCF */ - 0xBE, 0x75, 0xBE, 0x76, 0xBE, 0x77, 0xBE, 0x78, /* 0xD0-0xD3 */ - 0xBE, 0x79, 0xBE, 0x7A, 0xBE, 0x7B, 0xBE, 0x7C, /* 0xD4-0xD7 */ - 0xBE, 0x7D, 0xBE, 0x7E, 0xBE, 0x80, 0xBE, 0x81, /* 0xD8-0xDB */ - 0xBE, 0x82, 0xBE, 0x83, 0xBE, 0x84, 0xBE, 0x85, /* 0xDC-0xDF */ - 0xBE, 0x86, 0xBE, 0x87, 0xBE, 0x88, 0xBE, 0x89, /* 0xE0-0xE3 */ - 0xBE, 0x8A, 0xBE, 0x8B, 0xBE, 0x8C, 0xBE, 0x8D, /* 0xE4-0xE7 */ - 0xBE, 0x8E, 0xBE, 0x8F, 0xBE, 0x90, 0xBE, 0x91, /* 0xE8-0xEB */ - 0xBE, 0x92, 0xBE, 0x93, 0xBE, 0x94, 0xBE, 0x95, /* 0xEC-0xEF */ - 0xBE, 0x96, 0xBE, 0x97, 0xBE, 0x98, 0xBE, 0x99, /* 0xF0-0xF3 */ - 0xBE, 0x9A, 0xBE, 0x9B, 0xBE, 0x9C, 0xBE, 0x9D, /* 0xF4-0xF7 */ - 0xBE, 0x9E, 0xBE, 0x9F, 0xBE, 0xA0, 0xBF, 0x40, /* 0xF8-0xFB */ - 0xBF, 0x41, 0xBF, 0x42, 0xBF, 0x43, 0xBF, 0x44, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_7E[512] = { - 0xBF, 0x45, 0xBF, 0x46, 0xBF, 0x47, 0xBF, 0x48, /* 0x00-0x03 */ - 0xBF, 0x49, 0xBF, 0x4A, 0xBF, 0x4B, 0xBF, 0x4C, /* 0x04-0x07 */ - 0xBF, 0x4D, 0xBF, 0x4E, 0xBF, 0x4F, 0xBF, 0x50, /* 0x08-0x0B */ - 0xBF, 0x51, 0xBF, 0x52, 0xBF, 0x53, 0xBF, 0x54, /* 0x0C-0x0F */ - 0xBF, 0x55, 0xBF, 0x56, 0xBF, 0x57, 0xBF, 0x58, /* 0x10-0x13 */ - 0xBF, 0x59, 0xBF, 0x5A, 0xBF, 0x5B, 0xBF, 0x5C, /* 0x14-0x17 */ - 0xBF, 0x5D, 0xBF, 0x5E, 0xBF, 0x5F, 0xBF, 0x60, /* 0x18-0x1B */ - 0xBF, 0x61, 0xBF, 0x62, 0xBF, 0x63, 0xBF, 0x64, /* 0x1C-0x1F */ - 0xBF, 0x65, 0xBF, 0x66, 0xBF, 0x67, 0xBF, 0x68, /* 0x20-0x23 */ - 0xBF, 0x69, 0xBF, 0x6A, 0xBF, 0x6B, 0xBF, 0x6C, /* 0x24-0x27 */ - 0xBF, 0x6D, 0xBF, 0x6E, 0xBF, 0x6F, 0xBF, 0x70, /* 0x28-0x2B */ - 0xBF, 0x71, 0xBF, 0x72, 0xBF, 0x73, 0xBF, 0x74, /* 0x2C-0x2F */ - 0xBF, 0x75, 0xBF, 0x76, 0xBF, 0x77, 0xBF, 0x78, /* 0x30-0x33 */ - 0xBF, 0x79, 0xBF, 0x7A, 0xBF, 0x7B, 0xBF, 0x7C, /* 0x34-0x37 */ - 0xBF, 0x7D, 0xBF, 0x7E, 0xBF, 0x80, 0xF7, 0xE3, /* 0x38-0x3B */ - 0xBF, 0x81, 0xBF, 0x82, 0xBF, 0x83, 0xBF, 0x84, /* 0x3C-0x3F */ - 0xBF, 0x85, 0xB7, 0xB1, 0xBF, 0x86, 0xBF, 0x87, /* 0x40-0x43 */ - 0xBF, 0x88, 0xBF, 0x89, 0xBF, 0x8A, 0xF4, 0xED, /* 0x44-0x47 */ - 0xBF, 0x8B, 0xBF, 0x8C, 0xBF, 0x8D, 0xBF, 0x8E, /* 0x48-0x4B */ - 0xBF, 0x8F, 0xBF, 0x90, 0xBF, 0x91, 0xBF, 0x92, /* 0x4C-0x4F */ - 0xBF, 0x93, 0xBF, 0x94, 0xBF, 0x95, 0xBF, 0x96, /* 0x50-0x53 */ - 0xBF, 0x97, 0xBF, 0x98, 0xBF, 0x99, 0xBF, 0x9A, /* 0x54-0x57 */ - 0xBF, 0x9B, 0xBF, 0x9C, 0xBF, 0x9D, 0xBF, 0x9E, /* 0x58-0x5B */ - 0xBF, 0x9F, 0xBF, 0xA0, 0xC0, 0x40, 0xC0, 0x41, /* 0x5C-0x5F */ - 0xC0, 0x42, 0xC0, 0x43, 0xC0, 0x44, 0xC0, 0x45, /* 0x60-0x63 */ - 0xC0, 0x46, 0xC0, 0x47, 0xC0, 0x48, 0xC0, 0x49, /* 0x64-0x67 */ - 0xC0, 0x4A, 0xC0, 0x4B, 0xC0, 0x4C, 0xC0, 0x4D, /* 0x68-0x6B */ - 0xC0, 0x4E, 0xC0, 0x4F, 0xC0, 0x50, 0xC0, 0x51, /* 0x6C-0x6F */ - 0xC0, 0x52, 0xC0, 0x53, 0xC0, 0x54, 0xC0, 0x55, /* 0x70-0x73 */ - 0xC0, 0x56, 0xC0, 0x57, 0xC0, 0x58, 0xC0, 0x59, /* 0x74-0x77 */ - 0xC0, 0x5A, 0xC0, 0x5B, 0xC0, 0x5C, 0xC0, 0x5D, /* 0x78-0x7B */ - 0xC0, 0x5E, 0xC0, 0x5F, 0xC0, 0x60, 0xC0, 0x61, /* 0x7C-0x7F */ - - 0xC0, 0x62, 0xC0, 0x63, 0xD7, 0xEB, 0xC0, 0x64, /* 0x80-0x83 */ - 0xC0, 0x65, 0xC0, 0x66, 0xC0, 0x67, 0xC0, 0x68, /* 0x84-0x87 */ - 0xC0, 0x69, 0xC0, 0x6A, 0xC0, 0x6B, 0xC0, 0x6C, /* 0x88-0x8B */ - 0xC0, 0x6D, 0xC0, 0x6E, 0xC0, 0x6F, 0xC0, 0x70, /* 0x8C-0x8F */ - 0xC0, 0x71, 0xC0, 0x72, 0xC0, 0x73, 0xC0, 0x74, /* 0x90-0x93 */ - 0xC0, 0x75, 0xC0, 0x76, 0xC0, 0x77, 0xC0, 0x78, /* 0x94-0x97 */ - 0xC0, 0x79, 0xC0, 0x7A, 0xC0, 0x7B, 0xF4, 0xEE, /* 0x98-0x9B */ - 0xC0, 0x7C, 0xC0, 0x7D, 0xC0, 0x7E, 0xE6, 0xF9, /* 0x9C-0x9F */ - 0xBE, 0xC0, 0xE6, 0xFA, 0xBA, 0xEC, 0xE6, 0xFB, /* 0xA0-0xA3 */ - 0xCF, 0xCB, 0xE6, 0xFC, 0xD4, 0xBC, 0xBC, 0xB6, /* 0xA4-0xA7 */ - 0xE6, 0xFD, 0xE6, 0xFE, 0xBC, 0xCD, 0xC8, 0xD2, /* 0xA8-0xAB */ - 0xCE, 0xB3, 0xE7, 0xA1, 0xC0, 0x80, 0xB4, 0xBF, /* 0xAC-0xAF */ - 0xE7, 0xA2, 0xC9, 0xB4, 0xB8, 0xD9, 0xC4, 0xC9, /* 0xB0-0xB3 */ - 0xC0, 0x81, 0xD7, 0xDD, 0xC2, 0xDA, 0xB7, 0xD7, /* 0xB4-0xB7 */ - 0xD6, 0xBD, 0xCE, 0xC6, 0xB7, 0xC4, 0xC0, 0x82, /* 0xB8-0xBB */ - 0xC0, 0x83, 0xC5, 0xA6, 0xE7, 0xA3, 0xCF, 0xDF, /* 0xBC-0xBF */ - 0xE7, 0xA4, 0xE7, 0xA5, 0xE7, 0xA6, 0xC1, 0xB7, /* 0xC0-0xC3 */ - 0xD7, 0xE9, 0xC9, 0xF0, 0xCF, 0xB8, 0xD6, 0xAF, /* 0xC4-0xC7 */ - 0xD6, 0xD5, 0xE7, 0xA7, 0xB0, 0xED, 0xE7, 0xA8, /* 0xC8-0xCB */ - 0xE7, 0xA9, 0xC9, 0xDC, 0xD2, 0xEF, 0xBE, 0xAD, /* 0xCC-0xCF */ - 0xE7, 0xAA, 0xB0, 0xF3, 0xC8, 0xDE, 0xBD, 0xE1, /* 0xD0-0xD3 */ - 0xE7, 0xAB, 0xC8, 0xC6, 0xC0, 0x84, 0xE7, 0xAC, /* 0xD4-0xD7 */ - 0xBB, 0xE6, 0xB8, 0xF8, 0xD1, 0xA4, 0xE7, 0xAD, /* 0xD8-0xDB */ - 0xC2, 0xE7, 0xBE, 0xF8, 0xBD, 0xCA, 0xCD, 0xB3, /* 0xDC-0xDF */ - 0xE7, 0xAE, 0xE7, 0xAF, 0xBE, 0xEE, 0xD0, 0xE5, /* 0xE0-0xE3 */ - 0xC0, 0x85, 0xCB, 0xE7, 0xCC, 0xD0, 0xBC, 0xCC, /* 0xE4-0xE7 */ - 0xE7, 0xB0, 0xBC, 0xA8, 0xD0, 0xF7, 0xE7, 0xB1, /* 0xE8-0xEB */ - 0xC0, 0x86, 0xD0, 0xF8, 0xE7, 0xB2, 0xE7, 0xB3, /* 0xEC-0xEF */ - 0xB4, 0xC2, 0xE7, 0xB4, 0xE7, 0xB5, 0xC9, 0xFE, /* 0xF0-0xF3 */ - 0xCE, 0xAC, 0xC3, 0xE0, 0xE7, 0xB7, 0xB1, 0xC1, /* 0xF4-0xF7 */ - 0xB3, 0xF1, 0xC0, 0x87, 0xE7, 0xB8, 0xE7, 0xB9, /* 0xF8-0xFB */ - 0xD7, 0xDB, 0xD5, 0xC0, 0xE7, 0xBA, 0xC2, 0xCC, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_7F[512] = { - 0xD7, 0xBA, 0xE7, 0xBB, 0xE7, 0xBC, 0xE7, 0xBD, /* 0x00-0x03 */ - 0xBC, 0xEA, 0xC3, 0xE5, 0xC0, 0xC2, 0xE7, 0xBE, /* 0x04-0x07 */ - 0xE7, 0xBF, 0xBC, 0xA9, 0xC0, 0x88, 0xE7, 0xC0, /* 0x08-0x0B */ - 0xE7, 0xC1, 0xE7, 0xB6, 0xB6, 0xD0, 0xE7, 0xC2, /* 0x0C-0x0F */ - 0xC0, 0x89, 0xE7, 0xC3, 0xE7, 0xC4, 0xBB, 0xBA, /* 0x10-0x13 */ - 0xB5, 0xDE, 0xC2, 0xC6, 0xB1, 0xE0, 0xE7, 0xC5, /* 0x14-0x17 */ - 0xD4, 0xB5, 0xE7, 0xC6, 0xB8, 0xBF, 0xE7, 0xC8, /* 0x18-0x1B */ - 0xE7, 0xC7, 0xB7, 0xEC, 0xC0, 0x8A, 0xE7, 0xC9, /* 0x1C-0x1F */ - 0xB2, 0xF8, 0xE7, 0xCA, 0xE7, 0xCB, 0xE7, 0xCC, /* 0x20-0x23 */ - 0xE7, 0xCD, 0xE7, 0xCE, 0xE7, 0xCF, 0xE7, 0xD0, /* 0x24-0x27 */ - 0xD3, 0xA7, 0xCB, 0xF5, 0xE7, 0xD1, 0xE7, 0xD2, /* 0x28-0x2B */ - 0xE7, 0xD3, 0xE7, 0xD4, 0xC9, 0xC9, 0xE7, 0xD5, /* 0x2C-0x2F */ - 0xE7, 0xD6, 0xE7, 0xD7, 0xE7, 0xD8, 0xE7, 0xD9, /* 0x30-0x33 */ - 0xBD, 0xC9, 0xE7, 0xDA, 0xF3, 0xBE, 0xC0, 0x8B, /* 0x34-0x37 */ - 0xB8, 0xD7, 0xC0, 0x8C, 0xC8, 0xB1, 0xC0, 0x8D, /* 0x38-0x3B */ - 0xC0, 0x8E, 0xC0, 0x8F, 0xC0, 0x90, 0xC0, 0x91, /* 0x3C-0x3F */ - 0xC0, 0x92, 0xC0, 0x93, 0xF3, 0xBF, 0xC0, 0x94, /* 0x40-0x43 */ - 0xF3, 0xC0, 0xF3, 0xC1, 0xC0, 0x95, 0xC0, 0x96, /* 0x44-0x47 */ - 0xC0, 0x97, 0xC0, 0x98, 0xC0, 0x99, 0xC0, 0x9A, /* 0x48-0x4B */ - 0xC0, 0x9B, 0xC0, 0x9C, 0xC0, 0x9D, 0xC0, 0x9E, /* 0x4C-0x4F */ - 0xB9, 0xDE, 0xCD, 0xF8, 0xC0, 0x9F, 0xC0, 0xA0, /* 0x50-0x53 */ - 0xD8, 0xE8, 0xBA, 0xB1, 0xC1, 0x40, 0xC2, 0xDE, /* 0x54-0x57 */ - 0xEE, 0xB7, 0xC1, 0x41, 0xB7, 0xA3, 0xC1, 0x42, /* 0x58-0x5B */ - 0xC1, 0x43, 0xC1, 0x44, 0xC1, 0x45, 0xEE, 0xB9, /* 0x5C-0x5F */ - 0xC1, 0x46, 0xEE, 0xB8, 0xB0, 0xD5, 0xC1, 0x47, /* 0x60-0x63 */ - 0xC1, 0x48, 0xC1, 0x49, 0xC1, 0x4A, 0xC1, 0x4B, /* 0x64-0x67 */ - 0xEE, 0xBB, 0xD5, 0xD6, 0xD7, 0xEF, 0xC1, 0x4C, /* 0x68-0x6B */ - 0xC1, 0x4D, 0xC1, 0x4E, 0xD6, 0xC3, 0xC1, 0x4F, /* 0x6C-0x6F */ - 0xC1, 0x50, 0xEE, 0xBD, 0xCA, 0xF0, 0xC1, 0x51, /* 0x70-0x73 */ - 0xEE, 0xBC, 0xC1, 0x52, 0xC1, 0x53, 0xC1, 0x54, /* 0x74-0x77 */ - 0xC1, 0x55, 0xEE, 0xBE, 0xC1, 0x56, 0xC1, 0x57, /* 0x78-0x7B */ - 0xC1, 0x58, 0xC1, 0x59, 0xEE, 0xC0, 0xC1, 0x5A, /* 0x7C-0x7F */ - - 0xC1, 0x5B, 0xEE, 0xBF, 0xC1, 0x5C, 0xC1, 0x5D, /* 0x80-0x83 */ - 0xC1, 0x5E, 0xC1, 0x5F, 0xC1, 0x60, 0xC1, 0x61, /* 0x84-0x87 */ - 0xC1, 0x62, 0xC1, 0x63, 0xD1, 0xF2, 0xC1, 0x64, /* 0x88-0x8B */ - 0xC7, 0xBC, 0xC1, 0x65, 0xC3, 0xC0, 0xC1, 0x66, /* 0x8C-0x8F */ - 0xC1, 0x67, 0xC1, 0x68, 0xC1, 0x69, 0xC1, 0x6A, /* 0x90-0x93 */ - 0xB8, 0xE1, 0xC1, 0x6B, 0xC1, 0x6C, 0xC1, 0x6D, /* 0x94-0x97 */ - 0xC1, 0x6E, 0xC1, 0x6F, 0xC1, 0xE7, 0xC1, 0x70, /* 0x98-0x9B */ - 0xC1, 0x71, 0xF4, 0xC6, 0xD0, 0xDF, 0xF4, 0xC7, /* 0x9C-0x9F */ - 0xC1, 0x72, 0xCF, 0xDB, 0xC1, 0x73, 0xC1, 0x74, /* 0xA0-0xA3 */ - 0xC8, 0xBA, 0xC1, 0x75, 0xC1, 0x76, 0xF4, 0xC8, /* 0xA4-0xA7 */ - 0xC1, 0x77, 0xC1, 0x78, 0xC1, 0x79, 0xC1, 0x7A, /* 0xA8-0xAB */ - 0xC1, 0x7B, 0xC1, 0x7C, 0xC1, 0x7D, 0xF4, 0xC9, /* 0xAC-0xAF */ - 0xF4, 0xCA, 0xC1, 0x7E, 0xF4, 0xCB, 0xC1, 0x80, /* 0xB0-0xB3 */ - 0xC1, 0x81, 0xC1, 0x82, 0xC1, 0x83, 0xC1, 0x84, /* 0xB4-0xB7 */ - 0xD9, 0xFA, 0xB8, 0xFE, 0xC1, 0x85, 0xC1, 0x86, /* 0xB8-0xBB */ - 0xE5, 0xF1, 0xD3, 0xF0, 0xC1, 0x87, 0xF4, 0xE0, /* 0xBC-0xBF */ - 0xC1, 0x88, 0xCE, 0xCC, 0xC1, 0x89, 0xC1, 0x8A, /* 0xC0-0xC3 */ - 0xC1, 0x8B, 0xB3, 0xE1, 0xC1, 0x8C, 0xC1, 0x8D, /* 0xC4-0xC7 */ - 0xC1, 0x8E, 0xC1, 0x8F, 0xF1, 0xB4, 0xC1, 0x90, /* 0xC8-0xCB */ - 0xD2, 0xEE, 0xC1, 0x91, 0xF4, 0xE1, 0xC1, 0x92, /* 0xCC-0xCF */ - 0xC1, 0x93, 0xC1, 0x94, 0xC1, 0x95, 0xC1, 0x96, /* 0xD0-0xD3 */ - 0xCF, 0xE8, 0xF4, 0xE2, 0xC1, 0x97, 0xC1, 0x98, /* 0xD4-0xD7 */ - 0xC7, 0xCC, 0xC1, 0x99, 0xC1, 0x9A, 0xC1, 0x9B, /* 0xD8-0xDB */ - 0xC1, 0x9C, 0xC1, 0x9D, 0xC1, 0x9E, 0xB5, 0xD4, /* 0xDC-0xDF */ - 0xB4, 0xE4, 0xF4, 0xE4, 0xC1, 0x9F, 0xC1, 0xA0, /* 0xE0-0xE3 */ - 0xC2, 0x40, 0xF4, 0xE3, 0xF4, 0xE5, 0xC2, 0x41, /* 0xE4-0xE7 */ - 0xC2, 0x42, 0xF4, 0xE6, 0xC2, 0x43, 0xC2, 0x44, /* 0xE8-0xEB */ - 0xC2, 0x45, 0xC2, 0x46, 0xF4, 0xE7, 0xC2, 0x47, /* 0xEC-0xEF */ - 0xBA, 0xB2, 0xB0, 0xBF, 0xC2, 0x48, 0xF4, 0xE8, /* 0xF0-0xF3 */ - 0xC2, 0x49, 0xC2, 0x4A, 0xC2, 0x4B, 0xC2, 0x4C, /* 0xF4-0xF7 */ - 0xC2, 0x4D, 0xC2, 0x4E, 0xC2, 0x4F, 0xB7, 0xAD, /* 0xF8-0xFB */ - 0xD2, 0xED, 0xC2, 0x50, 0xC2, 0x51, 0xC2, 0x52, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_80[512] = { - 0xD2, 0xAB, 0xC0, 0xCF, 0xC2, 0x53, 0xBF, 0xBC, /* 0x00-0x03 */ - 0xEB, 0xA3, 0xD5, 0xDF, 0xEA, 0xC8, 0xC2, 0x54, /* 0x04-0x07 */ - 0xC2, 0x55, 0xC2, 0x56, 0xC2, 0x57, 0xF1, 0xF3, /* 0x08-0x0B */ - 0xB6, 0xF8, 0xCB, 0xA3, 0xC2, 0x58, 0xC2, 0x59, /* 0x0C-0x0F */ - 0xC4, 0xCD, 0xC2, 0x5A, 0xF1, 0xE7, 0xC2, 0x5B, /* 0x10-0x13 */ - 0xF1, 0xE8, 0xB8, 0xFB, 0xF1, 0xE9, 0xBA, 0xC4, /* 0x14-0x17 */ - 0xD4, 0xC5, 0xB0, 0xD2, 0xC2, 0x5C, 0xC2, 0x5D, /* 0x18-0x1B */ - 0xF1, 0xEA, 0xC2, 0x5E, 0xC2, 0x5F, 0xC2, 0x60, /* 0x1C-0x1F */ - 0xF1, 0xEB, 0xC2, 0x61, 0xF1, 0xEC, 0xC2, 0x62, /* 0x20-0x23 */ - 0xC2, 0x63, 0xF1, 0xED, 0xF1, 0xEE, 0xF1, 0xEF, /* 0x24-0x27 */ - 0xF1, 0xF1, 0xF1, 0xF0, 0xC5, 0xD5, 0xC2, 0x64, /* 0x28-0x2B */ - 0xC2, 0x65, 0xC2, 0x66, 0xC2, 0x67, 0xC2, 0x68, /* 0x2C-0x2F */ - 0xC2, 0x69, 0xF1, 0xF2, 0xC2, 0x6A, 0xB6, 0xFA, /* 0x30-0x33 */ - 0xC2, 0x6B, 0xF1, 0xF4, 0xD2, 0xAE, 0xDE, 0xC7, /* 0x34-0x37 */ - 0xCB, 0xCA, 0xC2, 0x6C, 0xC2, 0x6D, 0xB3, 0xDC, /* 0x38-0x3B */ - 0xC2, 0x6E, 0xB5, 0xA2, 0xC2, 0x6F, 0xB9, 0xA2, /* 0x3C-0x3F */ - 0xC2, 0x70, 0xC2, 0x71, 0xC4, 0xF4, 0xF1, 0xF5, /* 0x40-0x43 */ - 0xC2, 0x72, 0xC2, 0x73, 0xF1, 0xF6, 0xC2, 0x74, /* 0x44-0x47 */ - 0xC2, 0x75, 0xC2, 0x76, 0xC1, 0xC4, 0xC1, 0xFB, /* 0x48-0x4B */ - 0xD6, 0xB0, 0xF1, 0xF7, 0xC2, 0x77, 0xC2, 0x78, /* 0x4C-0x4F */ - 0xC2, 0x79, 0xC2, 0x7A, 0xF1, 0xF8, 0xC2, 0x7B, /* 0x50-0x53 */ - 0xC1, 0xAA, 0xC2, 0x7C, 0xC2, 0x7D, 0xC2, 0x7E, /* 0x54-0x57 */ - 0xC6, 0xB8, 0xC2, 0x80, 0xBE, 0xDB, 0xC2, 0x81, /* 0x58-0x5B */ - 0xC2, 0x82, 0xC2, 0x83, 0xC2, 0x84, 0xC2, 0x85, /* 0x5C-0x5F */ - 0xC2, 0x86, 0xC2, 0x87, 0xC2, 0x88, 0xC2, 0x89, /* 0x60-0x63 */ - 0xC2, 0x8A, 0xC2, 0x8B, 0xC2, 0x8C, 0xC2, 0x8D, /* 0x64-0x67 */ - 0xC2, 0x8E, 0xF1, 0xF9, 0xB4, 0xCF, 0xC2, 0x8F, /* 0x68-0x6B */ - 0xC2, 0x90, 0xC2, 0x91, 0xC2, 0x92, 0xC2, 0x93, /* 0x6C-0x6F */ - 0xC2, 0x94, 0xF1, 0xFA, 0xC2, 0x95, 0xC2, 0x96, /* 0x70-0x73 */ - 0xC2, 0x97, 0xC2, 0x98, 0xC2, 0x99, 0xC2, 0x9A, /* 0x74-0x77 */ - 0xC2, 0x9B, 0xC2, 0x9C, 0xC2, 0x9D, 0xC2, 0x9E, /* 0x78-0x7B */ - 0xC2, 0x9F, 0xC2, 0xA0, 0xC3, 0x40, 0xED, 0xB2, /* 0x7C-0x7F */ - - 0xED, 0xB1, 0xC3, 0x41, 0xC3, 0x42, 0xCB, 0xE0, /* 0x80-0x83 */ - 0xD2, 0xDE, 0xC3, 0x43, 0xCB, 0xC1, 0xD5, 0xD8, /* 0x84-0x87 */ - 0xC3, 0x44, 0xC8, 0xE2, 0xC3, 0x45, 0xC0, 0xDF, /* 0x88-0x8B */ - 0xBC, 0xA1, 0xC3, 0x46, 0xC3, 0x47, 0xC3, 0x48, /* 0x8C-0x8F */ - 0xC3, 0x49, 0xC3, 0x4A, 0xC3, 0x4B, 0xEB, 0xC1, /* 0x90-0x93 */ - 0xC3, 0x4C, 0xC3, 0x4D, 0xD0, 0xA4, 0xC3, 0x4E, /* 0x94-0x97 */ - 0xD6, 0xE2, 0xC3, 0x4F, 0xB6, 0xC7, 0xB8, 0xD8, /* 0x98-0x9B */ - 0xEB, 0xC0, 0xB8, 0xCE, 0xC3, 0x50, 0xEB, 0xBF, /* 0x9C-0x9F */ - 0xB3, 0xA6, 0xB9, 0xC9, 0xD6, 0xAB, 0xC3, 0x51, /* 0xA0-0xA3 */ - 0xB7, 0xF4, 0xB7, 0xCA, 0xC3, 0x52, 0xC3, 0x53, /* 0xA4-0xA7 */ - 0xC3, 0x54, 0xBC, 0xE7, 0xB7, 0xBE, 0xEB, 0xC6, /* 0xA8-0xAB */ - 0xC3, 0x55, 0xEB, 0xC7, 0xB0, 0xB9, 0xBF, 0xCF, /* 0xAC-0xAF */ - 0xC3, 0x56, 0xEB, 0xC5, 0xD3, 0xFD, 0xC3, 0x57, /* 0xB0-0xB3 */ - 0xEB, 0xC8, 0xC3, 0x58, 0xC3, 0x59, 0xEB, 0xC9, /* 0xB4-0xB7 */ - 0xC3, 0x5A, 0xC3, 0x5B, 0xB7, 0xCE, 0xC3, 0x5C, /* 0xB8-0xBB */ - 0xEB, 0xC2, 0xEB, 0xC4, 0xC9, 0xF6, 0xD6, 0xD7, /* 0xBC-0xBF */ - 0xD5, 0xCD, 0xD0, 0xB2, 0xEB, 0xCF, 0xCE, 0xB8, /* 0xC0-0xC3 */ - 0xEB, 0xD0, 0xC3, 0x5D, 0xB5, 0xA8, 0xC3, 0x5E, /* 0xC4-0xC7 */ - 0xC3, 0x5F, 0xC3, 0x60, 0xC3, 0x61, 0xC3, 0x62, /* 0xC8-0xCB */ - 0xB1, 0xB3, 0xEB, 0xD2, 0xCC, 0xA5, 0xC3, 0x63, /* 0xCC-0xCF */ - 0xC3, 0x64, 0xC3, 0x65, 0xC3, 0x66, 0xC3, 0x67, /* 0xD0-0xD3 */ - 0xC3, 0x68, 0xC3, 0x69, 0xC5, 0xD6, 0xEB, 0xD3, /* 0xD4-0xD7 */ - 0xC3, 0x6A, 0xEB, 0xD1, 0xC5, 0xDF, 0xEB, 0xCE, /* 0xD8-0xDB */ - 0xCA, 0xA4, 0xEB, 0xD5, 0xB0, 0xFB, 0xC3, 0x6B, /* 0xDC-0xDF */ - 0xC3, 0x6C, 0xBA, 0xFA, 0xC3, 0x6D, 0xC3, 0x6E, /* 0xE0-0xE3 */ - 0xD8, 0xB7, 0xF1, 0xE3, 0xC3, 0x6F, 0xEB, 0xCA, /* 0xE4-0xE7 */ - 0xEB, 0xCB, 0xEB, 0xCC, 0xEB, 0xCD, 0xEB, 0xD6, /* 0xE8-0xEB */ - 0xE6, 0xC0, 0xEB, 0xD9, 0xC3, 0x70, 0xBF, 0xE8, /* 0xEC-0xEF */ - 0xD2, 0xC8, 0xEB, 0xD7, 0xEB, 0xDC, 0xB8, 0xEC, /* 0xF0-0xF3 */ - 0xEB, 0xD8, 0xC3, 0x71, 0xBD, 0xBA, 0xC3, 0x72, /* 0xF4-0xF7 */ - 0xD0, 0xD8, 0xC3, 0x73, 0xB0, 0xB7, 0xC3, 0x74, /* 0xF8-0xFB */ - 0xEB, 0xDD, 0xC4, 0xDC, 0xC3, 0x75, 0xC3, 0x76, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_81[512] = { - 0xC3, 0x77, 0xC3, 0x78, 0xD6, 0xAC, 0xC3, 0x79, /* 0x00-0x03 */ - 0xC3, 0x7A, 0xC3, 0x7B, 0xB4, 0xE0, 0xC3, 0x7C, /* 0x04-0x07 */ - 0xC3, 0x7D, 0xC2, 0xF6, 0xBC, 0xB9, 0xC3, 0x7E, /* 0x08-0x0B */ - 0xC3, 0x80, 0xEB, 0xDA, 0xEB, 0xDB, 0xD4, 0xE0, /* 0x0C-0x0F */ - 0xC6, 0xEA, 0xC4, 0xD4, 0xEB, 0xDF, 0xC5, 0xA7, /* 0x10-0x13 */ - 0xD9, 0xF5, 0xC3, 0x81, 0xB2, 0xB1, 0xC3, 0x82, /* 0x14-0x17 */ - 0xEB, 0xE4, 0xC3, 0x83, 0xBD, 0xC5, 0xC3, 0x84, /* 0x18-0x1B */ - 0xC3, 0x85, 0xC3, 0x86, 0xEB, 0xE2, 0xC3, 0x87, /* 0x1C-0x1F */ - 0xC3, 0x88, 0xC3, 0x89, 0xC3, 0x8A, 0xC3, 0x8B, /* 0x20-0x23 */ - 0xC3, 0x8C, 0xC3, 0x8D, 0xC3, 0x8E, 0xC3, 0x8F, /* 0x24-0x27 */ - 0xC3, 0x90, 0xC3, 0x91, 0xC3, 0x92, 0xC3, 0x93, /* 0x28-0x2B */ - 0xEB, 0xE3, 0xC3, 0x94, 0xC3, 0x95, 0xB8, 0xAC, /* 0x2C-0x2F */ - 0xC3, 0x96, 0xCD, 0xD1, 0xEB, 0xE5, 0xC3, 0x97, /* 0x30-0x33 */ - 0xC3, 0x98, 0xC3, 0x99, 0xEB, 0xE1, 0xC3, 0x9A, /* 0x34-0x37 */ - 0xC1, 0xB3, 0xC3, 0x9B, 0xC3, 0x9C, 0xC3, 0x9D, /* 0x38-0x3B */ - 0xC3, 0x9E, 0xC3, 0x9F, 0xC6, 0xA2, 0xC3, 0xA0, /* 0x3C-0x3F */ - 0xC4, 0x40, 0xC4, 0x41, 0xC4, 0x42, 0xC4, 0x43, /* 0x40-0x43 */ - 0xC4, 0x44, 0xC4, 0x45, 0xCC, 0xF3, 0xC4, 0x46, /* 0x44-0x47 */ - 0xEB, 0xE6, 0xC4, 0x47, 0xC0, 0xB0, 0xD2, 0xB8, /* 0x48-0x4B */ - 0xEB, 0xE7, 0xC4, 0x48, 0xC4, 0x49, 0xC4, 0x4A, /* 0x4C-0x4F */ - 0xB8, 0xAF, 0xB8, 0xAD, 0xC4, 0x4B, 0xEB, 0xE8, /* 0x50-0x53 */ - 0xC7, 0xBB, 0xCD, 0xF3, 0xC4, 0x4C, 0xC4, 0x4D, /* 0x54-0x57 */ - 0xC4, 0x4E, 0xEB, 0xEA, 0xEB, 0xEB, 0xC4, 0x4F, /* 0x58-0x5B */ - 0xC4, 0x50, 0xC4, 0x51, 0xC4, 0x52, 0xC4, 0x53, /* 0x5C-0x5F */ - 0xEB, 0xED, 0xC4, 0x54, 0xC4, 0x55, 0xC4, 0x56, /* 0x60-0x63 */ - 0xC4, 0x57, 0xD0, 0xC8, 0xC4, 0x58, 0xEB, 0xF2, /* 0x64-0x67 */ - 0xC4, 0x59, 0xEB, 0xEE, 0xC4, 0x5A, 0xC4, 0x5B, /* 0x68-0x6B */ - 0xC4, 0x5C, 0xEB, 0xF1, 0xC8, 0xF9, 0xC4, 0x5D, /* 0x6C-0x6F */ - 0xD1, 0xFC, 0xEB, 0xEC, 0xC4, 0x5E, 0xC4, 0x5F, /* 0x70-0x73 */ - 0xEB, 0xE9, 0xC4, 0x60, 0xC4, 0x61, 0xC4, 0x62, /* 0x74-0x77 */ - 0xC4, 0x63, 0xB8, 0xB9, 0xCF, 0xD9, 0xC4, 0xE5, /* 0x78-0x7B */ - 0xEB, 0xEF, 0xEB, 0xF0, 0xCC, 0xDA, 0xCD, 0xC8, /* 0x7C-0x7F */ - - 0xB0, 0xF2, 0xC4, 0x64, 0xEB, 0xF6, 0xC4, 0x65, /* 0x80-0x83 */ - 0xC4, 0x66, 0xC4, 0x67, 0xC4, 0x68, 0xC4, 0x69, /* 0x84-0x87 */ - 0xEB, 0xF5, 0xC4, 0x6A, 0xB2, 0xB2, 0xC4, 0x6B, /* 0x88-0x8B */ - 0xC4, 0x6C, 0xC4, 0x6D, 0xC4, 0x6E, 0xB8, 0xE0, /* 0x8C-0x8F */ - 0xC4, 0x6F, 0xEB, 0xF7, 0xC4, 0x70, 0xC4, 0x71, /* 0x90-0x93 */ - 0xC4, 0x72, 0xC4, 0x73, 0xC4, 0x74, 0xC4, 0x75, /* 0x94-0x97 */ - 0xB1, 0xEC, 0xC4, 0x76, 0xC4, 0x77, 0xCC, 0xC5, /* 0x98-0x9B */ - 0xC4, 0xA4, 0xCF, 0xA5, 0xC4, 0x78, 0xC4, 0x79, /* 0x9C-0x9F */ - 0xC4, 0x7A, 0xC4, 0x7B, 0xC4, 0x7C, 0xEB, 0xF9, /* 0xA0-0xA3 */ - 0xC4, 0x7D, 0xC4, 0x7E, 0xEC, 0xA2, 0xC4, 0x80, /* 0xA4-0xA7 */ - 0xC5, 0xF2, 0xC4, 0x81, 0xEB, 0xFA, 0xC4, 0x82, /* 0xA8-0xAB */ - 0xC4, 0x83, 0xC4, 0x84, 0xC4, 0x85, 0xC4, 0x86, /* 0xAC-0xAF */ - 0xC4, 0x87, 0xC4, 0x88, 0xC4, 0x89, 0xC9, 0xC5, /* 0xB0-0xB3 */ - 0xC4, 0x8A, 0xC4, 0x8B, 0xC4, 0x8C, 0xC4, 0x8D, /* 0xB4-0xB7 */ - 0xC4, 0x8E, 0xC4, 0x8F, 0xE2, 0xDF, 0xEB, 0xFE, /* 0xB8-0xBB */ - 0xC4, 0x90, 0xC4, 0x91, 0xC4, 0x92, 0xC4, 0x93, /* 0xBC-0xBF */ - 0xCD, 0xCE, 0xEC, 0xA1, 0xB1, 0xDB, 0xD3, 0xB7, /* 0xC0-0xC3 */ - 0xC4, 0x94, 0xC4, 0x95, 0xD2, 0xDC, 0xC4, 0x96, /* 0xC4-0xC7 */ - 0xC4, 0x97, 0xC4, 0x98, 0xEB, 0xFD, 0xC4, 0x99, /* 0xC8-0xCB */ - 0xEB, 0xFB, 0xC4, 0x9A, 0xC4, 0x9B, 0xC4, 0x9C, /* 0xCC-0xCF */ - 0xC4, 0x9D, 0xC4, 0x9E, 0xC4, 0x9F, 0xC4, 0xA0, /* 0xD0-0xD3 */ - 0xC5, 0x40, 0xC5, 0x41, 0xC5, 0x42, 0xC5, 0x43, /* 0xD4-0xD7 */ - 0xC5, 0x44, 0xC5, 0x45, 0xC5, 0x46, 0xC5, 0x47, /* 0xD8-0xDB */ - 0xC5, 0x48, 0xC5, 0x49, 0xC5, 0x4A, 0xC5, 0x4B, /* 0xDC-0xDF */ - 0xC5, 0x4C, 0xC5, 0x4D, 0xC5, 0x4E, 0xB3, 0xBC, /* 0xE0-0xE3 */ - 0xC5, 0x4F, 0xC5, 0x50, 0xC5, 0x51, 0xEA, 0xB0, /* 0xE4-0xE7 */ - 0xC5, 0x52, 0xC5, 0x53, 0xD7, 0xD4, 0xC5, 0x54, /* 0xE8-0xEB */ - 0xF4, 0xAB, 0xB3, 0xF4, 0xC5, 0x55, 0xC5, 0x56, /* 0xEC-0xEF */ - 0xC5, 0x57, 0xC5, 0x58, 0xC5, 0x59, 0xD6, 0xC1, /* 0xF0-0xF3 */ - 0xD6, 0xC2, 0xC5, 0x5A, 0xC5, 0x5B, 0xC5, 0x5C, /* 0xF4-0xF7 */ - 0xC5, 0x5D, 0xC5, 0x5E, 0xC5, 0x5F, 0xD5, 0xE9, /* 0xF8-0xFB */ - 0xBE, 0xCA, 0xC5, 0x60, 0xF4, 0xA7, 0xC5, 0x61, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_82[512] = { - 0xD2, 0xA8, 0xF4, 0xA8, 0xF4, 0xA9, 0xC5, 0x62, /* 0x00-0x03 */ - 0xF4, 0xAA, 0xBE, 0xCB, 0xD3, 0xDF, 0xC5, 0x63, /* 0x04-0x07 */ - 0xC5, 0x64, 0xC5, 0x65, 0xC5, 0x66, 0xC5, 0x67, /* 0x08-0x0B */ - 0xC9, 0xE0, 0xC9, 0xE1, 0xC5, 0x68, 0xC5, 0x69, /* 0x0C-0x0F */ - 0xF3, 0xC2, 0xC5, 0x6A, 0xCA, 0xE6, 0xC5, 0x6B, /* 0x10-0x13 */ - 0xCC, 0xF2, 0xC5, 0x6C, 0xC5, 0x6D, 0xC5, 0x6E, /* 0x14-0x17 */ - 0xC5, 0x6F, 0xC5, 0x70, 0xC5, 0x71, 0xE2, 0xB6, /* 0x18-0x1B */ - 0xCB, 0xB4, 0xC5, 0x72, 0xCE, 0xE8, 0xD6, 0xDB, /* 0x1C-0x1F */ - 0xC5, 0x73, 0xF4, 0xAD, 0xF4, 0xAE, 0xF4, 0xAF, /* 0x20-0x23 */ - 0xC5, 0x74, 0xC5, 0x75, 0xC5, 0x76, 0xC5, 0x77, /* 0x24-0x27 */ - 0xF4, 0xB2, 0xC5, 0x78, 0xBA, 0xBD, 0xF4, 0xB3, /* 0x28-0x2B */ - 0xB0, 0xE3, 0xF4, 0xB0, 0xC5, 0x79, 0xF4, 0xB1, /* 0x2C-0x2F */ - 0xBD, 0xA2, 0xB2, 0xD5, 0xC5, 0x7A, 0xF4, 0xB6, /* 0x30-0x33 */ - 0xF4, 0xB7, 0xB6, 0xE6, 0xB2, 0xB0, 0xCF, 0xCF, /* 0x34-0x37 */ - 0xF4, 0xB4, 0xB4, 0xAC, 0xC5, 0x7B, 0xF4, 0xB5, /* 0x38-0x3B */ - 0xC5, 0x7C, 0xC5, 0x7D, 0xF4, 0xB8, 0xC5, 0x7E, /* 0x3C-0x3F */ - 0xC5, 0x80, 0xC5, 0x81, 0xC5, 0x82, 0xC5, 0x83, /* 0x40-0x43 */ - 0xF4, 0xB9, 0xC5, 0x84, 0xC5, 0x85, 0xCD, 0xA7, /* 0x44-0x47 */ - 0xC5, 0x86, 0xF4, 0xBA, 0xC5, 0x87, 0xF4, 0xBB, /* 0x48-0x4B */ - 0xC5, 0x88, 0xC5, 0x89, 0xC5, 0x8A, 0xF4, 0xBC, /* 0x4C-0x4F */ - 0xC5, 0x8B, 0xC5, 0x8C, 0xC5, 0x8D, 0xC5, 0x8E, /* 0x50-0x53 */ - 0xC5, 0x8F, 0xC5, 0x90, 0xC5, 0x91, 0xC5, 0x92, /* 0x54-0x57 */ - 0xCB, 0xD2, 0xC5, 0x93, 0xF4, 0xBD, 0xC5, 0x94, /* 0x58-0x5B */ - 0xC5, 0x95, 0xC5, 0x96, 0xC5, 0x97, 0xF4, 0xBE, /* 0x5C-0x5F */ - 0xC5, 0x98, 0xC5, 0x99, 0xC5, 0x9A, 0xC5, 0x9B, /* 0x60-0x63 */ - 0xC5, 0x9C, 0xC5, 0x9D, 0xC5, 0x9E, 0xC5, 0x9F, /* 0x64-0x67 */ - 0xF4, 0xBF, 0xC5, 0xA0, 0xC6, 0x40, 0xC6, 0x41, /* 0x68-0x6B */ - 0xC6, 0x42, 0xC6, 0x43, 0xF4, 0xDE, 0xC1, 0xBC, /* 0x6C-0x6F */ - 0xBC, 0xE8, 0xC6, 0x44, 0xC9, 0xAB, 0xD1, 0xDE, /* 0x70-0x73 */ - 0xE5, 0xF5, 0xC6, 0x45, 0xC6, 0x46, 0xC6, 0x47, /* 0x74-0x77 */ - 0xC6, 0x48, 0xDC, 0xB3, 0xD2, 0xD5, 0xC6, 0x49, /* 0x78-0x7B */ - 0xC6, 0x4A, 0xDC, 0xB4, 0xB0, 0xAC, 0xDC, 0xB5, /* 0x7C-0x7F */ - - 0xC6, 0x4B, 0xC6, 0x4C, 0xBD, 0xDA, 0xC6, 0x4D, /* 0x80-0x83 */ - 0xDC, 0xB9, 0xC6, 0x4E, 0xC6, 0x4F, 0xC6, 0x50, /* 0x84-0x87 */ - 0xD8, 0xC2, 0xC6, 0x51, 0xDC, 0xB7, 0xD3, 0xF3, /* 0x88-0x8B */ - 0xC6, 0x52, 0xC9, 0xD6, 0xDC, 0xBA, 0xDC, 0xB6, /* 0x8C-0x8F */ - 0xC6, 0x53, 0xDC, 0xBB, 0xC3, 0xA2, 0xC6, 0x54, /* 0x90-0x93 */ - 0xC6, 0x55, 0xC6, 0x56, 0xC6, 0x57, 0xDC, 0xBC, /* 0x94-0x97 */ - 0xDC, 0xC5, 0xDC, 0xBD, 0xC6, 0x58, 0xC6, 0x59, /* 0x98-0x9B */ - 0xCE, 0xDF, 0xD6, 0xA5, 0xC6, 0x5A, 0xDC, 0xCF, /* 0x9C-0x9F */ - 0xC6, 0x5B, 0xDC, 0xCD, 0xC6, 0x5C, 0xC6, 0x5D, /* 0xA0-0xA3 */ - 0xDC, 0xD2, 0xBD, 0xE6, 0xC2, 0xAB, 0xC6, 0x5E, /* 0xA4-0xA7 */ - 0xDC, 0xB8, 0xDC, 0xCB, 0xDC, 0xCE, 0xDC, 0xBE, /* 0xA8-0xAB */ - 0xB7, 0xD2, 0xB0, 0xC5, 0xDC, 0xC7, 0xD0, 0xBE, /* 0xAC-0xAF */ - 0xDC, 0xC1, 0xBB, 0xA8, 0xC6, 0x5F, 0xB7, 0xBC, /* 0xB0-0xB3 */ - 0xDC, 0xCC, 0xC6, 0x60, 0xC6, 0x61, 0xDC, 0xC6, /* 0xB4-0xB7 */ - 0xDC, 0xBF, 0xC7, 0xDB, 0xC6, 0x62, 0xC6, 0x63, /* 0xB8-0xBB */ - 0xC6, 0x64, 0xD1, 0xBF, 0xDC, 0xC0, 0xC6, 0x65, /* 0xBC-0xBF */ - 0xC6, 0x66, 0xDC, 0xCA, 0xC6, 0x67, 0xC6, 0x68, /* 0xC0-0xC3 */ - 0xDC, 0xD0, 0xC6, 0x69, 0xC6, 0x6A, 0xCE, 0xAD, /* 0xC4-0xC7 */ - 0xDC, 0xC2, 0xC6, 0x6B, 0xDC, 0xC3, 0xDC, 0xC8, /* 0xC8-0xCB */ - 0xDC, 0xC9, 0xB2, 0xD4, 0xDC, 0xD1, 0xCB, 0xD5, /* 0xCC-0xCF */ - 0xC6, 0x6C, 0xD4, 0xB7, 0xDC, 0xDB, 0xDC, 0xDF, /* 0xD0-0xD3 */ - 0xCC, 0xA6, 0xDC, 0xE6, 0xC6, 0x6D, 0xC3, 0xE7, /* 0xD4-0xD7 */ - 0xDC, 0xDC, 0xC6, 0x6E, 0xC6, 0x6F, 0xBF, 0xC1, /* 0xD8-0xDB */ - 0xDC, 0xD9, 0xC6, 0x70, 0xB0, 0xFA, 0xB9, 0xB6, /* 0xDC-0xDF */ - 0xDC, 0xE5, 0xDC, 0xD3, 0xC6, 0x71, 0xDC, 0xC4, /* 0xE0-0xE3 */ - 0xDC, 0xD6, 0xC8, 0xF4, 0xBF, 0xE0, 0xC6, 0x72, /* 0xE4-0xE7 */ - 0xC6, 0x73, 0xC6, 0x74, 0xC6, 0x75, 0xC9, 0xBB, /* 0xE8-0xEB */ - 0xC6, 0x76, 0xC6, 0x77, 0xC6, 0x78, 0xB1, 0xBD, /* 0xEC-0xEF */ - 0xC6, 0x79, 0xD3, 0xA2, 0xC6, 0x7A, 0xC6, 0x7B, /* 0xF0-0xF3 */ - 0xDC, 0xDA, 0xC6, 0x7C, 0xC6, 0x7D, 0xDC, 0xD5, /* 0xF4-0xF7 */ - 0xC6, 0x7E, 0xC6, 0xBB, 0xC6, 0x80, 0xDC, 0xDE, /* 0xF8-0xFB */ - 0xC6, 0x81, 0xC6, 0x82, 0xC6, 0x83, 0xC6, 0x84, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_83[512] = { - 0xC6, 0x85, 0xD7, 0xC2, 0xC3, 0xAF, 0xB7, 0xB6, /* 0x00-0x03 */ - 0xC7, 0xD1, 0xC3, 0xA9, 0xDC, 0xE2, 0xDC, 0xD8, /* 0x04-0x07 */ - 0xDC, 0xEB, 0xDC, 0xD4, 0xC6, 0x86, 0xC6, 0x87, /* 0x08-0x0B */ - 0xDC, 0xDD, 0xC6, 0x88, 0xBE, 0xA5, 0xDC, 0xD7, /* 0x0C-0x0F */ - 0xC6, 0x89, 0xDC, 0xE0, 0xC6, 0x8A, 0xC6, 0x8B, /* 0x10-0x13 */ - 0xDC, 0xE3, 0xDC, 0xE4, 0xC6, 0x8C, 0xDC, 0xF8, /* 0x14-0x17 */ - 0xC6, 0x8D, 0xC6, 0x8E, 0xDC, 0xE1, 0xDD, 0xA2, /* 0x18-0x1B */ - 0xDC, 0xE7, 0xC6, 0x8F, 0xC6, 0x90, 0xC6, 0x91, /* 0x1C-0x1F */ - 0xC6, 0x92, 0xC6, 0x93, 0xC6, 0x94, 0xC6, 0x95, /* 0x20-0x23 */ - 0xC6, 0x96, 0xC6, 0x97, 0xC6, 0x98, 0xBC, 0xEB, /* 0x24-0x27 */ - 0xB4, 0xC4, 0xC6, 0x99, 0xC6, 0x9A, 0xC3, 0xA3, /* 0x28-0x2B */ - 0xB2, 0xE7, 0xDC, 0xFA, 0xC6, 0x9B, 0xDC, 0xF2, /* 0x2C-0x2F */ - 0xC6, 0x9C, 0xDC, 0xEF, 0xC6, 0x9D, 0xDC, 0xFC, /* 0x30-0x33 */ - 0xDC, 0xEE, 0xD2, 0xF0, 0xB2, 0xE8, 0xC6, 0x9E, /* 0x34-0x37 */ - 0xC8, 0xD7, 0xC8, 0xE3, 0xDC, 0xFB, 0xC6, 0x9F, /* 0x38-0x3B */ - 0xDC, 0xED, 0xC6, 0xA0, 0xC7, 0x40, 0xC7, 0x41, /* 0x3C-0x3F */ - 0xDC, 0xF7, 0xC7, 0x42, 0xC7, 0x43, 0xDC, 0xF5, /* 0x40-0x43 */ - 0xC7, 0x44, 0xC7, 0x45, 0xBE, 0xA3, 0xDC, 0xF4, /* 0x44-0x47 */ - 0xC7, 0x46, 0xB2, 0xDD, 0xC7, 0x47, 0xC7, 0x48, /* 0x48-0x4B */ - 0xC7, 0x49, 0xC7, 0x4A, 0xC7, 0x4B, 0xDC, 0xF3, /* 0x4C-0x4F */ - 0xBC, 0xF6, 0xDC, 0xE8, 0xBB, 0xC4, 0xC7, 0x4C, /* 0x50-0x53 */ - 0xC0, 0xF3, 0xC7, 0x4D, 0xC7, 0x4E, 0xC7, 0x4F, /* 0x54-0x57 */ - 0xC7, 0x50, 0xC7, 0x51, 0xBC, 0xD4, 0xDC, 0xE9, /* 0x58-0x5B */ - 0xDC, 0xEA, 0xC7, 0x52, 0xDC, 0xF1, 0xDC, 0xF6, /* 0x5C-0x5F */ - 0xDC, 0xF9, 0xB5, 0xB4, 0xC7, 0x53, 0xC8, 0xD9, /* 0x60-0x63 */ - 0xBB, 0xE7, 0xDC, 0xFE, 0xDC, 0xFD, 0xD3, 0xAB, /* 0x64-0x67 */ - 0xDD, 0xA1, 0xDD, 0xA3, 0xDD, 0xA5, 0xD2, 0xF1, /* 0x68-0x6B */ - 0xDD, 0xA4, 0xDD, 0xA6, 0xDD, 0xA7, 0xD2, 0xA9, /* 0x6C-0x6F */ - 0xC7, 0x54, 0xC7, 0x55, 0xC7, 0x56, 0xC7, 0x57, /* 0x70-0x73 */ - 0xC7, 0x58, 0xC7, 0x59, 0xC7, 0x5A, 0xBA, 0xC9, /* 0x74-0x77 */ - 0xDD, 0xA9, 0xC7, 0x5B, 0xC7, 0x5C, 0xDD, 0xB6, /* 0x78-0x7B */ - 0xDD, 0xB1, 0xDD, 0xB4, 0xC7, 0x5D, 0xC7, 0x5E, /* 0x7C-0x7F */ - - 0xC7, 0x5F, 0xC7, 0x60, 0xC7, 0x61, 0xC7, 0x62, /* 0x80-0x83 */ - 0xC7, 0x63, 0xDD, 0xB0, 0xC6, 0xCE, 0xC7, 0x64, /* 0x84-0x87 */ - 0xC7, 0x65, 0xC0, 0xF2, 0xC7, 0x66, 0xC7, 0x67, /* 0x88-0x8B */ - 0xC7, 0x68, 0xC7, 0x69, 0xC9, 0xAF, 0xC7, 0x6A, /* 0x8C-0x8F */ - 0xC7, 0x6B, 0xC7, 0x6C, 0xDC, 0xEC, 0xDD, 0xAE, /* 0x90-0x93 */ - 0xC7, 0x6D, 0xC7, 0x6E, 0xC7, 0x6F, 0xC7, 0x70, /* 0x94-0x97 */ - 0xDD, 0xB7, 0xC7, 0x71, 0xC7, 0x72, 0xDC, 0xF0, /* 0x98-0x9B */ - 0xDD, 0xAF, 0xC7, 0x73, 0xDD, 0xB8, 0xC7, 0x74, /* 0x9C-0x9F */ - 0xDD, 0xAC, 0xC7, 0x75, 0xC7, 0x76, 0xC7, 0x77, /* 0xA0-0xA3 */ - 0xC7, 0x78, 0xC7, 0x79, 0xC7, 0x7A, 0xC7, 0x7B, /* 0xA4-0xA7 */ - 0xDD, 0xB9, 0xDD, 0xB3, 0xDD, 0xAD, 0xC4, 0xAA, /* 0xA8-0xAB */ - 0xC7, 0x7C, 0xC7, 0x7D, 0xC7, 0x7E, 0xC7, 0x80, /* 0xAC-0xAF */ - 0xDD, 0xA8, 0xC0, 0xB3, 0xC1, 0xAB, 0xDD, 0xAA, /* 0xB0-0xB3 */ - 0xDD, 0xAB, 0xC7, 0x81, 0xDD, 0xB2, 0xBB, 0xF1, /* 0xB4-0xB7 */ - 0xDD, 0xB5, 0xD3, 0xA8, 0xDD, 0xBA, 0xC7, 0x82, /* 0xB8-0xBB */ - 0xDD, 0xBB, 0xC3, 0xA7, 0xC7, 0x83, 0xC7, 0x84, /* 0xBC-0xBF */ - 0xDD, 0xD2, 0xDD, 0xBC, 0xC7, 0x85, 0xC7, 0x86, /* 0xC0-0xC3 */ - 0xC7, 0x87, 0xDD, 0xD1, 0xC7, 0x88, 0xB9, 0xBD, /* 0xC4-0xC7 */ - 0xC7, 0x89, 0xC7, 0x8A, 0xBE, 0xD5, 0xC7, 0x8B, /* 0xC8-0xCB */ - 0xBE, 0xFA, 0xC7, 0x8C, 0xC7, 0x8D, 0xBA, 0xCA, /* 0xCC-0xCF */ - 0xC7, 0x8E, 0xC7, 0x8F, 0xC7, 0x90, 0xC7, 0x91, /* 0xD0-0xD3 */ - 0xDD, 0xCA, 0xC7, 0x92, 0xDD, 0xC5, 0xC7, 0x93, /* 0xD4-0xD7 */ - 0xDD, 0xBF, 0xC7, 0x94, 0xC7, 0x95, 0xC7, 0x96, /* 0xD8-0xDB */ - 0xB2, 0xCB, 0xDD, 0xC3, 0xC7, 0x97, 0xDD, 0xCB, /* 0xDC-0xDF */ - 0xB2, 0xA4, 0xDD, 0xD5, 0xC7, 0x98, 0xC7, 0x99, /* 0xE0-0xE3 */ - 0xC7, 0x9A, 0xDD, 0xBE, 0xC7, 0x9B, 0xC7, 0x9C, /* 0xE4-0xE7 */ - 0xC7, 0x9D, 0xC6, 0xD0, 0xDD, 0xD0, 0xC7, 0x9E, /* 0xE8-0xEB */ - 0xC7, 0x9F, 0xC7, 0xA0, 0xC8, 0x40, 0xC8, 0x41, /* 0xEC-0xEF */ - 0xDD, 0xD4, 0xC1, 0xE2, 0xB7, 0xC6, 0xC8, 0x42, /* 0xF0-0xF3 */ - 0xC8, 0x43, 0xC8, 0x44, 0xC8, 0x45, 0xC8, 0x46, /* 0xF4-0xF7 */ - 0xDD, 0xCE, 0xDD, 0xCF, 0xC8, 0x47, 0xC8, 0x48, /* 0xF8-0xFB */ - 0xC8, 0x49, 0xDD, 0xC4, 0xC8, 0x4A, 0xC8, 0x4B, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_84[512] = { - 0xC8, 0x4C, 0xDD, 0xBD, 0xC8, 0x4D, 0xDD, 0xCD, /* 0x00-0x03 */ - 0xCC, 0xD1, 0xC8, 0x4E, 0xDD, 0xC9, 0xC8, 0x4F, /* 0x04-0x07 */ - 0xC8, 0x50, 0xC8, 0x51, 0xC8, 0x52, 0xDD, 0xC2, /* 0x08-0x0B */ - 0xC3, 0xC8, 0xC6, 0xBC, 0xCE, 0xAE, 0xDD, 0xCC, /* 0x0C-0x0F */ - 0xC8, 0x53, 0xDD, 0xC8, 0xC8, 0x54, 0xC8, 0x55, /* 0x10-0x13 */ - 0xC8, 0x56, 0xC8, 0x57, 0xC8, 0x58, 0xC8, 0x59, /* 0x14-0x17 */ - 0xDD, 0xC1, 0xC8, 0x5A, 0xC8, 0x5B, 0xC8, 0x5C, /* 0x18-0x1B */ - 0xDD, 0xC6, 0xC2, 0xDC, 0xC8, 0x5D, 0xC8, 0x5E, /* 0x1C-0x1F */ - 0xC8, 0x5F, 0xC8, 0x60, 0xC8, 0x61, 0xC8, 0x62, /* 0x20-0x23 */ - 0xD3, 0xA9, 0xD3, 0xAA, 0xDD, 0xD3, 0xCF, 0xF4, /* 0x24-0x27 */ - 0xC8, 0xF8, 0xC8, 0x63, 0xC8, 0x64, 0xC8, 0x65, /* 0x28-0x2B */ - 0xC8, 0x66, 0xC8, 0x67, 0xC8, 0x68, 0xC8, 0x69, /* 0x2C-0x2F */ - 0xC8, 0x6A, 0xDD, 0xE6, 0xC8, 0x6B, 0xC8, 0x6C, /* 0x30-0x33 */ - 0xC8, 0x6D, 0xC8, 0x6E, 0xC8, 0x6F, 0xC8, 0x70, /* 0x34-0x37 */ - 0xDD, 0xC7, 0xC8, 0x71, 0xC8, 0x72, 0xC8, 0x73, /* 0x38-0x3B */ - 0xDD, 0xE0, 0xC2, 0xE4, 0xC8, 0x74, 0xC8, 0x75, /* 0x3C-0x3F */ - 0xC8, 0x76, 0xC8, 0x77, 0xC8, 0x78, 0xC8, 0x79, /* 0x40-0x43 */ - 0xC8, 0x7A, 0xC8, 0x7B, 0xDD, 0xE1, 0xC8, 0x7C, /* 0x44-0x47 */ - 0xC8, 0x7D, 0xC8, 0x7E, 0xC8, 0x80, 0xC8, 0x81, /* 0x48-0x4B */ - 0xC8, 0x82, 0xC8, 0x83, 0xC8, 0x84, 0xC8, 0x85, /* 0x4C-0x4F */ - 0xC8, 0x86, 0xDD, 0xD7, 0xC8, 0x87, 0xC8, 0x88, /* 0x50-0x53 */ - 0xC8, 0x89, 0xC8, 0x8A, 0xC8, 0x8B, 0xD6, 0xF8, /* 0x54-0x57 */ - 0xC8, 0x8C, 0xDD, 0xD9, 0xDD, 0xD8, 0xB8, 0xF0, /* 0x58-0x5B */ - 0xDD, 0xD6, 0xC8, 0x8D, 0xC8, 0x8E, 0xC8, 0x8F, /* 0x5C-0x5F */ - 0xC8, 0x90, 0xC6, 0xCF, 0xC8, 0x91, 0xB6, 0xAD, /* 0x60-0x63 */ - 0xC8, 0x92, 0xC8, 0x93, 0xC8, 0x94, 0xC8, 0x95, /* 0x64-0x67 */ - 0xC8, 0x96, 0xDD, 0xE2, 0xC8, 0x97, 0xBA, 0xF9, /* 0x68-0x6B */ - 0xD4, 0xE1, 0xDD, 0xE7, 0xC8, 0x98, 0xC8, 0x99, /* 0x6C-0x6F */ - 0xC8, 0x9A, 0xB4, 0xD0, 0xC8, 0x9B, 0xDD, 0xDA, /* 0x70-0x73 */ - 0xC8, 0x9C, 0xBF, 0xFB, 0xDD, 0xE3, 0xC8, 0x9D, /* 0x74-0x77 */ - 0xDD, 0xDF, 0xC8, 0x9E, 0xDD, 0xDD, 0xC8, 0x9F, /* 0x78-0x7B */ - 0xC8, 0xA0, 0xC9, 0x40, 0xC9, 0x41, 0xC9, 0x42, /* 0x7C-0x7F */ - - 0xC9, 0x43, 0xC9, 0x44, 0xB5, 0xD9, 0xC9, 0x45, /* 0x80-0x83 */ - 0xC9, 0x46, 0xC9, 0x47, 0xC9, 0x48, 0xDD, 0xDB, /* 0x84-0x87 */ - 0xDD, 0xDC, 0xDD, 0xDE, 0xC9, 0x49, 0xBD, 0xAF, /* 0x88-0x8B */ - 0xDD, 0xE4, 0xC9, 0x4A, 0xDD, 0xE5, 0xC9, 0x4B, /* 0x8C-0x8F */ - 0xC9, 0x4C, 0xC9, 0x4D, 0xC9, 0x4E, 0xC9, 0x4F, /* 0x90-0x93 */ - 0xC9, 0x50, 0xC9, 0x51, 0xC9, 0x52, 0xDD, 0xF5, /* 0x94-0x97 */ - 0xC9, 0x53, 0xC3, 0xC9, 0xC9, 0x54, 0xC9, 0x55, /* 0x98-0x9B */ - 0xCB, 0xE2, 0xC9, 0x56, 0xC9, 0x57, 0xC9, 0x58, /* 0x9C-0x9F */ - 0xC9, 0x59, 0xDD, 0xF2, 0xC9, 0x5A, 0xC9, 0x5B, /* 0xA0-0xA3 */ - 0xC9, 0x5C, 0xC9, 0x5D, 0xC9, 0x5E, 0xC9, 0x5F, /* 0xA4-0xA7 */ - 0xC9, 0x60, 0xC9, 0x61, 0xC9, 0x62, 0xC9, 0x63, /* 0xA8-0xAB */ - 0xC9, 0x64, 0xC9, 0x65, 0xC9, 0x66, 0xD8, 0xE1, /* 0xAC-0xAF */ - 0xC9, 0x67, 0xC9, 0x68, 0xC6, 0xD1, 0xC9, 0x69, /* 0xB0-0xB3 */ - 0xDD, 0xF4, 0xC9, 0x6A, 0xC9, 0x6B, 0xC9, 0x6C, /* 0xB4-0xB7 */ - 0xD5, 0xF4, 0xDD, 0xF3, 0xDD, 0xF0, 0xC9, 0x6D, /* 0xB8-0xBB */ - 0xC9, 0x6E, 0xDD, 0xEC, 0xC9, 0x6F, 0xDD, 0xEF, /* 0xBC-0xBF */ - 0xC9, 0x70, 0xDD, 0xE8, 0xC9, 0x71, 0xC9, 0x72, /* 0xC0-0xC3 */ - 0xD0, 0xEE, 0xC9, 0x73, 0xC9, 0x74, 0xC9, 0x75, /* 0xC4-0xC7 */ - 0xC9, 0x76, 0xC8, 0xD8, 0xDD, 0xEE, 0xC9, 0x77, /* 0xC8-0xCB */ - 0xC9, 0x78, 0xDD, 0xE9, 0xC9, 0x79, 0xC9, 0x7A, /* 0xCC-0xCF */ - 0xDD, 0xEA, 0xCB, 0xF2, 0xC9, 0x7B, 0xDD, 0xED, /* 0xD0-0xD3 */ - 0xC9, 0x7C, 0xC9, 0x7D, 0xB1, 0xCD, 0xC9, 0x7E, /* 0xD4-0xD7 */ - 0xC9, 0x80, 0xC9, 0x81, 0xC9, 0x82, 0xC9, 0x83, /* 0xD8-0xDB */ - 0xC9, 0x84, 0xC0, 0xB6, 0xC9, 0x85, 0xBC, 0xBB, /* 0xDC-0xDF */ - 0xDD, 0xF1, 0xC9, 0x86, 0xC9, 0x87, 0xDD, 0xF7, /* 0xE0-0xE3 */ - 0xC9, 0x88, 0xDD, 0xF6, 0xDD, 0xEB, 0xC9, 0x89, /* 0xE4-0xE7 */ - 0xC9, 0x8A, 0xC9, 0x8B, 0xC9, 0x8C, 0xC9, 0x8D, /* 0xE8-0xEB */ - 0xC5, 0xEE, 0xC9, 0x8E, 0xC9, 0x8F, 0xC9, 0x90, /* 0xEC-0xEF */ - 0xDD, 0xFB, 0xC9, 0x91, 0xC9, 0x92, 0xC9, 0x93, /* 0xF0-0xF3 */ - 0xC9, 0x94, 0xC9, 0x95, 0xC9, 0x96, 0xC9, 0x97, /* 0xF4-0xF7 */ - 0xC9, 0x98, 0xC9, 0x99, 0xC9, 0x9A, 0xC9, 0x9B, /* 0xF8-0xFB */ - 0xDE, 0xA4, 0xC9, 0x9C, 0xC9, 0x9D, 0xDE, 0xA3, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_85[512] = { - 0xC9, 0x9E, 0xC9, 0x9F, 0xC9, 0xA0, 0xCA, 0x40, /* 0x00-0x03 */ - 0xCA, 0x41, 0xCA, 0x42, 0xCA, 0x43, 0xCA, 0x44, /* 0x04-0x07 */ - 0xCA, 0x45, 0xCA, 0x46, 0xCA, 0x47, 0xCA, 0x48, /* 0x08-0x0B */ - 0xDD, 0xF8, 0xCA, 0x49, 0xCA, 0x4A, 0xCA, 0x4B, /* 0x0C-0x0F */ - 0xCA, 0x4C, 0xC3, 0xEF, 0xCA, 0x4D, 0xC2, 0xFB, /* 0x10-0x13 */ - 0xCA, 0x4E, 0xCA, 0x4F, 0xCA, 0x50, 0xD5, 0xE1, /* 0x14-0x17 */ - 0xCA, 0x51, 0xCA, 0x52, 0xCE, 0xB5, 0xCA, 0x53, /* 0x18-0x1B */ - 0xCA, 0x54, 0xCA, 0x55, 0xCA, 0x56, 0xDD, 0xFD, /* 0x1C-0x1F */ - 0xCA, 0x57, 0xB2, 0xCC, 0xCA, 0x58, 0xCA, 0x59, /* 0x20-0x23 */ - 0xCA, 0x5A, 0xCA, 0x5B, 0xCA, 0x5C, 0xCA, 0x5D, /* 0x24-0x27 */ - 0xCA, 0x5E, 0xCA, 0x5F, 0xCA, 0x60, 0xC4, 0xE8, /* 0x28-0x2B */ - 0xCA, 0xDF, 0xCA, 0x61, 0xCA, 0x62, 0xCA, 0x63, /* 0x2C-0x2F */ - 0xCA, 0x64, 0xCA, 0x65, 0xCA, 0x66, 0xCA, 0x67, /* 0x30-0x33 */ - 0xCA, 0x68, 0xCA, 0x69, 0xCA, 0x6A, 0xC7, 0xBE, /* 0x34-0x37 */ - 0xDD, 0xFA, 0xDD, 0xFC, 0xDD, 0xFE, 0xDE, 0xA2, /* 0x38-0x3B */ - 0xB0, 0xAA, 0xB1, 0xCE, 0xCA, 0x6B, 0xCA, 0x6C, /* 0x3C-0x3F */ - 0xCA, 0x6D, 0xCA, 0x6E, 0xCA, 0x6F, 0xDE, 0xAC, /* 0x40-0x43 */ - 0xCA, 0x70, 0xCA, 0x71, 0xCA, 0x72, 0xCA, 0x73, /* 0x44-0x47 */ - 0xDE, 0xA6, 0xBD, 0xB6, 0xC8, 0xEF, 0xCA, 0x74, /* 0x48-0x4B */ - 0xCA, 0x75, 0xCA, 0x76, 0xCA, 0x77, 0xCA, 0x78, /* 0x4C-0x4F */ - 0xCA, 0x79, 0xCA, 0x7A, 0xCA, 0x7B, 0xCA, 0x7C, /* 0x50-0x53 */ - 0xCA, 0x7D, 0xCA, 0x7E, 0xDE, 0xA1, 0xCA, 0x80, /* 0x54-0x57 */ - 0xCA, 0x81, 0xDE, 0xA5, 0xCA, 0x82, 0xCA, 0x83, /* 0x58-0x5B */ - 0xCA, 0x84, 0xCA, 0x85, 0xDE, 0xA9, 0xCA, 0x86, /* 0x5C-0x5F */ - 0xCA, 0x87, 0xCA, 0x88, 0xCA, 0x89, 0xCA, 0x8A, /* 0x60-0x63 */ - 0xDE, 0xA8, 0xCA, 0x8B, 0xCA, 0x8C, 0xCA, 0x8D, /* 0x64-0x67 */ - 0xDE, 0xA7, 0xCA, 0x8E, 0xCA, 0x8F, 0xCA, 0x90, /* 0x68-0x6B */ - 0xCA, 0x91, 0xCA, 0x92, 0xCA, 0x93, 0xCA, 0x94, /* 0x6C-0x6F */ - 0xCA, 0x95, 0xCA, 0x96, 0xDE, 0xAD, 0xCA, 0x97, /* 0x70-0x73 */ - 0xD4, 0xCC, 0xCA, 0x98, 0xCA, 0x99, 0xCA, 0x9A, /* 0x74-0x77 */ - 0xCA, 0x9B, 0xDE, 0xB3, 0xDE, 0xAA, 0xDE, 0xAE, /* 0x78-0x7B */ - 0xCA, 0x9C, 0xCA, 0x9D, 0xC0, 0xD9, 0xCA, 0x9E, /* 0x7C-0x7F */ - - 0xCA, 0x9F, 0xCA, 0xA0, 0xCB, 0x40, 0xCB, 0x41, /* 0x80-0x83 */ - 0xB1, 0xA1, 0xDE, 0xB6, 0xCB, 0x42, 0xDE, 0xB1, /* 0x84-0x87 */ - 0xCB, 0x43, 0xCB, 0x44, 0xCB, 0x45, 0xCB, 0x46, /* 0x88-0x8B */ - 0xCB, 0x47, 0xCB, 0x48, 0xCB, 0x49, 0xDE, 0xB2, /* 0x8C-0x8F */ - 0xCB, 0x4A, 0xCB, 0x4B, 0xCB, 0x4C, 0xCB, 0x4D, /* 0x90-0x93 */ - 0xCB, 0x4E, 0xCB, 0x4F, 0xCB, 0x50, 0xCB, 0x51, /* 0x94-0x97 */ - 0xCB, 0x52, 0xCB, 0x53, 0xCB, 0x54, 0xD1, 0xA6, /* 0x98-0x9B */ - 0xDE, 0xB5, 0xCB, 0x55, 0xCB, 0x56, 0xCB, 0x57, /* 0x9C-0x9F */ - 0xCB, 0x58, 0xCB, 0x59, 0xCB, 0x5A, 0xCB, 0x5B, /* 0xA0-0xA3 */ - 0xDE, 0xAF, 0xCB, 0x5C, 0xCB, 0x5D, 0xCB, 0x5E, /* 0xA4-0xA7 */ - 0xDE, 0xB0, 0xCB, 0x5F, 0xD0, 0xBD, 0xCB, 0x60, /* 0xA8-0xAB */ - 0xCB, 0x61, 0xCB, 0x62, 0xDE, 0xB4, 0xCA, 0xED, /* 0xAC-0xAF */ - 0xDE, 0xB9, 0xCB, 0x63, 0xCB, 0x64, 0xCB, 0x65, /* 0xB0-0xB3 */ - 0xCB, 0x66, 0xCB, 0x67, 0xCB, 0x68, 0xDE, 0xB8, /* 0xB4-0xB7 */ - 0xCB, 0x69, 0xDE, 0xB7, 0xCB, 0x6A, 0xCB, 0x6B, /* 0xB8-0xBB */ - 0xCB, 0x6C, 0xCB, 0x6D, 0xCB, 0x6E, 0xCB, 0x6F, /* 0xBC-0xBF */ - 0xCB, 0x70, 0xDE, 0xBB, 0xCB, 0x71, 0xCB, 0x72, /* 0xC0-0xC3 */ - 0xCB, 0x73, 0xCB, 0x74, 0xCB, 0x75, 0xCB, 0x76, /* 0xC4-0xC7 */ - 0xCB, 0x77, 0xBD, 0xE5, 0xCB, 0x78, 0xCB, 0x79, /* 0xC8-0xCB */ - 0xCB, 0x7A, 0xCB, 0x7B, 0xCB, 0x7C, 0xB2, 0xD8, /* 0xCC-0xCF */ - 0xC3, 0xEA, 0xCB, 0x7D, 0xCB, 0x7E, 0xDE, 0xBA, /* 0xD0-0xD3 */ - 0xCB, 0x80, 0xC5, 0xBA, 0xCB, 0x81, 0xCB, 0x82, /* 0xD4-0xD7 */ - 0xCB, 0x83, 0xCB, 0x84, 0xCB, 0x85, 0xCB, 0x86, /* 0xD8-0xDB */ - 0xDE, 0xBC, 0xCB, 0x87, 0xCB, 0x88, 0xCB, 0x89, /* 0xDC-0xDF */ - 0xCB, 0x8A, 0xCB, 0x8B, 0xCB, 0x8C, 0xCB, 0x8D, /* 0xE0-0xE3 */ - 0xCC, 0xD9, 0xCB, 0x8E, 0xCB, 0x8F, 0xCB, 0x90, /* 0xE4-0xE7 */ - 0xCB, 0x91, 0xB7, 0xAA, 0xCB, 0x92, 0xCB, 0x93, /* 0xE8-0xEB */ - 0xCB, 0x94, 0xCB, 0x95, 0xCB, 0x96, 0xCB, 0x97, /* 0xEC-0xEF */ - 0xCB, 0x98, 0xCB, 0x99, 0xCB, 0x9A, 0xCB, 0x9B, /* 0xF0-0xF3 */ - 0xCB, 0x9C, 0xCB, 0x9D, 0xCB, 0x9E, 0xCB, 0x9F, /* 0xF4-0xF7 */ - 0xCB, 0xA0, 0xCC, 0x40, 0xCC, 0x41, 0xD4, 0xE5, /* 0xF8-0xFB */ - 0xCC, 0x42, 0xCC, 0x43, 0xCC, 0x44, 0xDE, 0xBD, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_86[512] = { - 0xCC, 0x45, 0xCC, 0x46, 0xCC, 0x47, 0xCC, 0x48, /* 0x00-0x03 */ - 0xCC, 0x49, 0xDE, 0xBF, 0xCC, 0x4A, 0xCC, 0x4B, /* 0x04-0x07 */ - 0xCC, 0x4C, 0xCC, 0x4D, 0xCC, 0x4E, 0xCC, 0x4F, /* 0x08-0x0B */ - 0xCC, 0x50, 0xCC, 0x51, 0xCC, 0x52, 0xCC, 0x53, /* 0x0C-0x0F */ - 0xCC, 0x54, 0xC4, 0xA2, 0xCC, 0x55, 0xCC, 0x56, /* 0x10-0x13 */ - 0xCC, 0x57, 0xCC, 0x58, 0xDE, 0xC1, 0xCC, 0x59, /* 0x14-0x17 */ - 0xCC, 0x5A, 0xCC, 0x5B, 0xCC, 0x5C, 0xCC, 0x5D, /* 0x18-0x1B */ - 0xCC, 0x5E, 0xCC, 0x5F, 0xCC, 0x60, 0xCC, 0x61, /* 0x1C-0x1F */ - 0xCC, 0x62, 0xCC, 0x63, 0xCC, 0x64, 0xCC, 0x65, /* 0x20-0x23 */ - 0xCC, 0x66, 0xCC, 0x67, 0xCC, 0x68, 0xDE, 0xBE, /* 0x24-0x27 */ - 0xCC, 0x69, 0xDE, 0xC0, 0xCC, 0x6A, 0xCC, 0x6B, /* 0x28-0x2B */ - 0xCC, 0x6C, 0xCC, 0x6D, 0xCC, 0x6E, 0xCC, 0x6F, /* 0x2C-0x2F */ - 0xCC, 0x70, 0xCC, 0x71, 0xCC, 0x72, 0xCC, 0x73, /* 0x30-0x33 */ - 0xCC, 0x74, 0xCC, 0x75, 0xCC, 0x76, 0xCC, 0x77, /* 0x34-0x37 */ - 0xD5, 0xBA, 0xCC, 0x78, 0xCC, 0x79, 0xCC, 0x7A, /* 0x38-0x3B */ - 0xDE, 0xC2, 0xCC, 0x7B, 0xCC, 0x7C, 0xCC, 0x7D, /* 0x3C-0x3F */ - 0xCC, 0x7E, 0xCC, 0x80, 0xCC, 0x81, 0xCC, 0x82, /* 0x40-0x43 */ - 0xCC, 0x83, 0xCC, 0x84, 0xCC, 0x85, 0xCC, 0x86, /* 0x44-0x47 */ - 0xCC, 0x87, 0xCC, 0x88, 0xCC, 0x89, 0xCC, 0x8A, /* 0x48-0x4B */ - 0xCC, 0x8B, 0xF2, 0xAE, 0xBB, 0xA2, 0xC2, 0xB2, /* 0x4C-0x4F */ - 0xC5, 0xB0, 0xC2, 0xC7, 0xCC, 0x8C, 0xCC, 0x8D, /* 0x50-0x53 */ - 0xF2, 0xAF, 0xCC, 0x8E, 0xCC, 0x8F, 0xCC, 0x90, /* 0x54-0x57 */ - 0xCC, 0x91, 0xCC, 0x92, 0xD0, 0xE9, 0xCC, 0x93, /* 0x58-0x5B */ - 0xCC, 0x94, 0xCC, 0x95, 0xD3, 0xDD, 0xCC, 0x96, /* 0x5C-0x5F */ - 0xCC, 0x97, 0xCC, 0x98, 0xEB, 0xBD, 0xCC, 0x99, /* 0x60-0x63 */ - 0xCC, 0x9A, 0xCC, 0x9B, 0xCC, 0x9C, 0xCC, 0x9D, /* 0x64-0x67 */ - 0xCC, 0x9E, 0xCC, 0x9F, 0xCC, 0xA0, 0xB3, 0xE6, /* 0x68-0x6B */ - 0xF2, 0xB0, 0xCD, 0x40, 0xF2, 0xB1, 0xCD, 0x41, /* 0x6C-0x6F */ - 0xCD, 0x42, 0xCA, 0xAD, 0xCD, 0x43, 0xCD, 0x44, /* 0x70-0x73 */ - 0xCD, 0x45, 0xCD, 0x46, 0xCD, 0x47, 0xCD, 0x48, /* 0x74-0x77 */ - 0xCD, 0x49, 0xBA, 0xE7, 0xF2, 0xB3, 0xF2, 0xB5, /* 0x78-0x7B */ - 0xF2, 0xB4, 0xCB, 0xE4, 0xCF, 0xBA, 0xF2, 0xB2, /* 0x7C-0x7F */ - - 0xCA, 0xB4, 0xD2, 0xCF, 0xC2, 0xEC, 0xCD, 0x4A, /* 0x80-0x83 */ - 0xCD, 0x4B, 0xCD, 0x4C, 0xCD, 0x4D, 0xCD, 0x4E, /* 0x84-0x87 */ - 0xCD, 0x4F, 0xCD, 0x50, 0xCE, 0xC3, 0xF2, 0xB8, /* 0x88-0x8B */ - 0xB0, 0xF6, 0xF2, 0xB7, 0xCD, 0x51, 0xCD, 0x52, /* 0x8C-0x8F */ - 0xCD, 0x53, 0xCD, 0x54, 0xCD, 0x55, 0xF2, 0xBE, /* 0x90-0x93 */ - 0xCD, 0x56, 0xB2, 0xCF, 0xCD, 0x57, 0xCD, 0x58, /* 0x94-0x97 */ - 0xCD, 0x59, 0xCD, 0x5A, 0xCD, 0x5B, 0xCD, 0x5C, /* 0x98-0x9B */ - 0xD1, 0xC1, 0xF2, 0xBA, 0xCD, 0x5D, 0xCD, 0x5E, /* 0x9C-0x9F */ - 0xCD, 0x5F, 0xCD, 0x60, 0xCD, 0x61, 0xF2, 0xBC, /* 0xA0-0xA3 */ - 0xD4, 0xE9, 0xCD, 0x62, 0xCD, 0x63, 0xF2, 0xBB, /* 0xA4-0xA7 */ - 0xF2, 0xB6, 0xF2, 0xBF, 0xF2, 0xBD, 0xCD, 0x64, /* 0xA8-0xAB */ - 0xF2, 0xB9, 0xCD, 0x65, 0xCD, 0x66, 0xF2, 0xC7, /* 0xAC-0xAF */ - 0xF2, 0xC4, 0xF2, 0xC6, 0xCD, 0x67, 0xCD, 0x68, /* 0xB0-0xB3 */ - 0xF2, 0xCA, 0xF2, 0xC2, 0xF2, 0xC0, 0xCD, 0x69, /* 0xB4-0xB7 */ - 0xCD, 0x6A, 0xCD, 0x6B, 0xF2, 0xC5, 0xCD, 0x6C, /* 0xB8-0xBB */ - 0xCD, 0x6D, 0xCD, 0x6E, 0xCD, 0x6F, 0xCD, 0x70, /* 0xBC-0xBF */ - 0xD6, 0xFB, 0xCD, 0x71, 0xCD, 0x72, 0xCD, 0x73, /* 0xC0-0xC3 */ - 0xF2, 0xC1, 0xCD, 0x74, 0xC7, 0xF9, 0xC9, 0xDF, /* 0xC4-0xC7 */ - 0xCD, 0x75, 0xF2, 0xC8, 0xB9, 0xC6, 0xB5, 0xB0, /* 0xC8-0xCB */ - 0xCD, 0x76, 0xCD, 0x77, 0xF2, 0xC3, 0xF2, 0xC9, /* 0xCC-0xCF */ - 0xF2, 0xD0, 0xF2, 0xD6, 0xCD, 0x78, 0xCD, 0x79, /* 0xD0-0xD3 */ - 0xBB, 0xD7, 0xCD, 0x7A, 0xCD, 0x7B, 0xCD, 0x7C, /* 0xD4-0xD7 */ - 0xF2, 0xD5, 0xCD, 0xDC, 0xCD, 0x7D, 0xD6, 0xEB, /* 0xD8-0xDB */ - 0xCD, 0x7E, 0xCD, 0x80, 0xF2, 0xD2, 0xF2, 0xD4, /* 0xDC-0xDF */ - 0xCD, 0x81, 0xCD, 0x82, 0xCD, 0x83, 0xCD, 0x84, /* 0xE0-0xE3 */ - 0xB8, 0xF2, 0xCD, 0x85, 0xCD, 0x86, 0xCD, 0x87, /* 0xE4-0xE7 */ - 0xCD, 0x88, 0xF2, 0xCB, 0xCD, 0x89, 0xCD, 0x8A, /* 0xE8-0xEB */ - 0xCD, 0x8B, 0xF2, 0xCE, 0xC2, 0xF9, 0xCD, 0x8C, /* 0xEC-0xEF */ - 0xD5, 0xDD, 0xF2, 0xCC, 0xF2, 0xCD, 0xF2, 0xCF, /* 0xF0-0xF3 */ - 0xF2, 0xD3, 0xCD, 0x8D, 0xCD, 0x8E, 0xCD, 0x8F, /* 0xF4-0xF7 */ - 0xF2, 0xD9, 0xD3, 0xBC, 0xCD, 0x90, 0xCD, 0x91, /* 0xF8-0xFB */ - 0xCD, 0x92, 0xCD, 0x93, 0xB6, 0xEA, 0xCD, 0x94, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_87[512] = { - 0xCA, 0xF1, 0xCD, 0x95, 0xB7, 0xE4, 0xF2, 0xD7, /* 0x00-0x03 */ - 0xCD, 0x96, 0xCD, 0x97, 0xCD, 0x98, 0xF2, 0xD8, /* 0x04-0x07 */ - 0xF2, 0xDA, 0xF2, 0xDD, 0xF2, 0xDB, 0xCD, 0x99, /* 0x08-0x0B */ - 0xCD, 0x9A, 0xF2, 0xDC, 0xCD, 0x9B, 0xCD, 0x9C, /* 0x0C-0x0F */ - 0xCD, 0x9D, 0xCD, 0x9E, 0xD1, 0xD1, 0xF2, 0xD1, /* 0x10-0x13 */ - 0xCD, 0x9F, 0xCD, 0xC9, 0xCD, 0xA0, 0xCE, 0xCF, /* 0x14-0x17 */ - 0xD6, 0xA9, 0xCE, 0x40, 0xF2, 0xE3, 0xCE, 0x41, /* 0x18-0x1B */ - 0xC3, 0xDB, 0xCE, 0x42, 0xF2, 0xE0, 0xCE, 0x43, /* 0x1C-0x1F */ - 0xCE, 0x44, 0xC0, 0xAF, 0xF2, 0xEC, 0xF2, 0xDE, /* 0x20-0x23 */ - 0xCE, 0x45, 0xF2, 0xE1, 0xCE, 0x46, 0xCE, 0x47, /* 0x24-0x27 */ - 0xCE, 0x48, 0xF2, 0xE8, 0xCE, 0x49, 0xCE, 0x4A, /* 0x28-0x2B */ - 0xCE, 0x4B, 0xCE, 0x4C, 0xF2, 0xE2, 0xCE, 0x4D, /* 0x2C-0x2F */ - 0xCE, 0x4E, 0xF2, 0xE7, 0xCE, 0x4F, 0xCE, 0x50, /* 0x30-0x33 */ - 0xF2, 0xE6, 0xCE, 0x51, 0xCE, 0x52, 0xF2, 0xE9, /* 0x34-0x37 */ - 0xCE, 0x53, 0xCE, 0x54, 0xCE, 0x55, 0xF2, 0xDF, /* 0x38-0x3B */ - 0xCE, 0x56, 0xCE, 0x57, 0xF2, 0xE4, 0xF2, 0xEA, /* 0x3C-0x3F */ - 0xCE, 0x58, 0xCE, 0x59, 0xCE, 0x5A, 0xCE, 0x5B, /* 0x40-0x43 */ - 0xCE, 0x5C, 0xCE, 0x5D, 0xCE, 0x5E, 0xD3, 0xAC, /* 0x44-0x47 */ - 0xF2, 0xE5, 0xB2, 0xF5, 0xCE, 0x5F, 0xCE, 0x60, /* 0x48-0x4B */ - 0xF2, 0xF2, 0xCE, 0x61, 0xD0, 0xAB, 0xCE, 0x62, /* 0x4C-0x4F */ - 0xCE, 0x63, 0xCE, 0x64, 0xCE, 0x65, 0xF2, 0xF5, /* 0x50-0x53 */ - 0xCE, 0x66, 0xCE, 0x67, 0xCE, 0x68, 0xBB, 0xC8, /* 0x54-0x57 */ - 0xCE, 0x69, 0xF2, 0xF9, 0xCE, 0x6A, 0xCE, 0x6B, /* 0x58-0x5B */ - 0xCE, 0x6C, 0xCE, 0x6D, 0xCE, 0x6E, 0xCE, 0x6F, /* 0x5C-0x5F */ - 0xF2, 0xF0, 0xCE, 0x70, 0xCE, 0x71, 0xF2, 0xF6, /* 0x60-0x63 */ - 0xF2, 0xF8, 0xF2, 0xFA, 0xCE, 0x72, 0xCE, 0x73, /* 0x64-0x67 */ - 0xCE, 0x74, 0xCE, 0x75, 0xCE, 0x76, 0xCE, 0x77, /* 0x68-0x6B */ - 0xCE, 0x78, 0xCE, 0x79, 0xF2, 0xF3, 0xCE, 0x7A, /* 0x6C-0x6F */ - 0xF2, 0xF1, 0xCE, 0x7B, 0xCE, 0x7C, 0xCE, 0x7D, /* 0x70-0x73 */ - 0xBA, 0xFB, 0xCE, 0x7E, 0xB5, 0xFB, 0xCE, 0x80, /* 0x74-0x77 */ - 0xCE, 0x81, 0xCE, 0x82, 0xCE, 0x83, 0xF2, 0xEF, /* 0x78-0x7B */ - 0xF2, 0xF7, 0xF2, 0xED, 0xF2, 0xEE, 0xCE, 0x84, /* 0x7C-0x7F */ - - 0xCE, 0x85, 0xCE, 0x86, 0xF2, 0xEB, 0xF3, 0xA6, /* 0x80-0x83 */ - 0xCE, 0x87, 0xF3, 0xA3, 0xCE, 0x88, 0xCE, 0x89, /* 0x84-0x87 */ - 0xF3, 0xA2, 0xCE, 0x8A, 0xCE, 0x8B, 0xF2, 0xF4, /* 0x88-0x8B */ - 0xCE, 0x8C, 0xC8, 0xDA, 0xCE, 0x8D, 0xCE, 0x8E, /* 0x8C-0x8F */ - 0xCE, 0x8F, 0xCE, 0x90, 0xCE, 0x91, 0xF2, 0xFB, /* 0x90-0x93 */ - 0xCE, 0x92, 0xCE, 0x93, 0xCE, 0x94, 0xF3, 0xA5, /* 0x94-0x97 */ - 0xCE, 0x95, 0xCE, 0x96, 0xCE, 0x97, 0xCE, 0x98, /* 0x98-0x9B */ - 0xCE, 0x99, 0xCE, 0x9A, 0xCE, 0x9B, 0xC3, 0xF8, /* 0x9C-0x9F */ - 0xCE, 0x9C, 0xCE, 0x9D, 0xCE, 0x9E, 0xCE, 0x9F, /* 0xA0-0xA3 */ - 0xCE, 0xA0, 0xCF, 0x40, 0xCF, 0x41, 0xCF, 0x42, /* 0xA4-0xA7 */ - 0xF2, 0xFD, 0xCF, 0x43, 0xCF, 0x44, 0xF3, 0xA7, /* 0xA8-0xAB */ - 0xF3, 0xA9, 0xF3, 0xA4, 0xCF, 0x45, 0xF2, 0xFC, /* 0xAC-0xAF */ - 0xCF, 0x46, 0xCF, 0x47, 0xCF, 0x48, 0xF3, 0xAB, /* 0xB0-0xB3 */ - 0xCF, 0x49, 0xF3, 0xAA, 0xCF, 0x4A, 0xCF, 0x4B, /* 0xB4-0xB7 */ - 0xCF, 0x4C, 0xCF, 0x4D, 0xC2, 0xDD, 0xCF, 0x4E, /* 0xB8-0xBB */ - 0xCF, 0x4F, 0xF3, 0xAE, 0xCF, 0x50, 0xCF, 0x51, /* 0xBC-0xBF */ - 0xF3, 0xB0, 0xCF, 0x52, 0xCF, 0x53, 0xCF, 0x54, /* 0xC0-0xC3 */ - 0xCF, 0x55, 0xCF, 0x56, 0xF3, 0xA1, 0xCF, 0x57, /* 0xC4-0xC7 */ - 0xCF, 0x58, 0xCF, 0x59, 0xF3, 0xB1, 0xF3, 0xAC, /* 0xC8-0xCB */ - 0xCF, 0x5A, 0xCF, 0x5B, 0xCF, 0x5C, 0xCF, 0x5D, /* 0xCC-0xCF */ - 0xCF, 0x5E, 0xF3, 0xAF, 0xF2, 0xFE, 0xF3, 0xAD, /* 0xD0-0xD3 */ - 0xCF, 0x5F, 0xCF, 0x60, 0xCF, 0x61, 0xCF, 0x62, /* 0xD4-0xD7 */ - 0xCF, 0x63, 0xCF, 0x64, 0xCF, 0x65, 0xF3, 0xB2, /* 0xD8-0xDB */ - 0xCF, 0x66, 0xCF, 0x67, 0xCF, 0x68, 0xCF, 0x69, /* 0xDC-0xDF */ - 0xF3, 0xB4, 0xCF, 0x6A, 0xCF, 0x6B, 0xCF, 0x6C, /* 0xE0-0xE3 */ - 0xCF, 0x6D, 0xF3, 0xA8, 0xCF, 0x6E, 0xCF, 0x6F, /* 0xE4-0xE7 */ - 0xCF, 0x70, 0xCF, 0x71, 0xF3, 0xB3, 0xCF, 0x72, /* 0xE8-0xEB */ - 0xCF, 0x73, 0xCF, 0x74, 0xF3, 0xB5, 0xCF, 0x75, /* 0xEC-0xEF */ - 0xCF, 0x76, 0xCF, 0x77, 0xCF, 0x78, 0xCF, 0x79, /* 0xF0-0xF3 */ - 0xCF, 0x7A, 0xCF, 0x7B, 0xCF, 0x7C, 0xCF, 0x7D, /* 0xF4-0xF7 */ - 0xCF, 0x7E, 0xD0, 0xB7, 0xCF, 0x80, 0xCF, 0x81, /* 0xF8-0xFB */ - 0xCF, 0x82, 0xCF, 0x83, 0xF3, 0xB8, 0xCF, 0x84, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_88[512] = { - 0xCF, 0x85, 0xCF, 0x86, 0xCF, 0x87, 0xD9, 0xF9, /* 0x00-0x03 */ - 0xCF, 0x88, 0xCF, 0x89, 0xCF, 0x8A, 0xCF, 0x8B, /* 0x04-0x07 */ - 0xCF, 0x8C, 0xCF, 0x8D, 0xF3, 0xB9, 0xCF, 0x8E, /* 0x08-0x0B */ - 0xCF, 0x8F, 0xCF, 0x90, 0xCF, 0x91, 0xCF, 0x92, /* 0x0C-0x0F */ - 0xCF, 0x93, 0xCF, 0x94, 0xCF, 0x95, 0xF3, 0xB7, /* 0x10-0x13 */ - 0xCF, 0x96, 0xC8, 0xE4, 0xF3, 0xB6, 0xCF, 0x97, /* 0x14-0x17 */ - 0xCF, 0x98, 0xCF, 0x99, 0xCF, 0x9A, 0xF3, 0xBA, /* 0x18-0x1B */ - 0xCF, 0x9B, 0xCF, 0x9C, 0xCF, 0x9D, 0xCF, 0x9E, /* 0x1C-0x1F */ - 0xCF, 0x9F, 0xF3, 0xBB, 0xB4, 0xC0, 0xCF, 0xA0, /* 0x20-0x23 */ - 0xD0, 0x40, 0xD0, 0x41, 0xD0, 0x42, 0xD0, 0x43, /* 0x24-0x27 */ - 0xD0, 0x44, 0xD0, 0x45, 0xD0, 0x46, 0xD0, 0x47, /* 0x28-0x2B */ - 0xD0, 0x48, 0xD0, 0x49, 0xD0, 0x4A, 0xD0, 0x4B, /* 0x2C-0x2F */ - 0xD0, 0x4C, 0xD0, 0x4D, 0xEE, 0xC3, 0xD0, 0x4E, /* 0x30-0x33 */ - 0xD0, 0x4F, 0xD0, 0x50, 0xD0, 0x51, 0xD0, 0x52, /* 0x34-0x37 */ - 0xD0, 0x53, 0xF3, 0xBC, 0xD0, 0x54, 0xD0, 0x55, /* 0x38-0x3B */ - 0xF3, 0xBD, 0xD0, 0x56, 0xD0, 0x57, 0xD0, 0x58, /* 0x3C-0x3F */ - 0xD1, 0xAA, 0xD0, 0x59, 0xD0, 0x5A, 0xD0, 0x5B, /* 0x40-0x43 */ - 0xF4, 0xAC, 0xD0, 0xC6, 0xD0, 0x5C, 0xD0, 0x5D, /* 0x44-0x47 */ - 0xD0, 0x5E, 0xD0, 0x5F, 0xD0, 0x60, 0xD0, 0x61, /* 0x48-0x4B */ - 0xD0, 0xD0, 0xD1, 0xDC, 0xD0, 0x62, 0xD0, 0x63, /* 0x4C-0x4F */ - 0xD0, 0x64, 0xD0, 0x65, 0xD0, 0x66, 0xD0, 0x67, /* 0x50-0x53 */ - 0xCF, 0xCE, 0xD0, 0x68, 0xD0, 0x69, 0xBD, 0xD6, /* 0x54-0x57 */ - 0xD0, 0x6A, 0xD1, 0xC3, 0xD0, 0x6B, 0xD0, 0x6C, /* 0x58-0x5B */ - 0xD0, 0x6D, 0xD0, 0x6E, 0xD0, 0x6F, 0xD0, 0x70, /* 0x5C-0x5F */ - 0xD0, 0x71, 0xBA, 0xE2, 0xE1, 0xE9, 0xD2, 0xC2, /* 0x60-0x63 */ - 0xF1, 0xC2, 0xB2, 0xB9, 0xD0, 0x72, 0xD0, 0x73, /* 0x64-0x67 */ - 0xB1, 0xED, 0xF1, 0xC3, 0xD0, 0x74, 0xC9, 0xC0, /* 0x68-0x6B */ - 0xB3, 0xC4, 0xD0, 0x75, 0xD9, 0xF2, 0xD0, 0x76, /* 0x6C-0x6F */ - 0xCB, 0xA5, 0xD0, 0x77, 0xF1, 0xC4, 0xD0, 0x78, /* 0x70-0x73 */ - 0xD0, 0x79, 0xD0, 0x7A, 0xD0, 0x7B, 0xD6, 0xD4, /* 0x74-0x77 */ - 0xD0, 0x7C, 0xD0, 0x7D, 0xD0, 0x7E, 0xD0, 0x80, /* 0x78-0x7B */ - 0xD0, 0x81, 0xF1, 0xC5, 0xF4, 0xC0, 0xF1, 0xC6, /* 0x7C-0x7F */ - - 0xD0, 0x82, 0xD4, 0xAC, 0xF1, 0xC7, 0xD0, 0x83, /* 0x80-0x83 */ - 0xB0, 0xC0, 0xF4, 0xC1, 0xD0, 0x84, 0xD0, 0x85, /* 0x84-0x87 */ - 0xF4, 0xC2, 0xD0, 0x86, 0xD0, 0x87, 0xB4, 0xFC, /* 0x88-0x8B */ - 0xD0, 0x88, 0xC5, 0xDB, 0xD0, 0x89, 0xD0, 0x8A, /* 0x8C-0x8F */ - 0xD0, 0x8B, 0xD0, 0x8C, 0xCC, 0xBB, 0xD0, 0x8D, /* 0x90-0x93 */ - 0xD0, 0x8E, 0xD0, 0x8F, 0xD0, 0xE4, 0xD0, 0x90, /* 0x94-0x97 */ - 0xD0, 0x91, 0xD0, 0x92, 0xD0, 0x93, 0xD0, 0x94, /* 0x98-0x9B */ - 0xCD, 0xE0, 0xD0, 0x95, 0xD0, 0x96, 0xD0, 0x97, /* 0x9C-0x9F */ - 0xD0, 0x98, 0xD0, 0x99, 0xF1, 0xC8, 0xD0, 0x9A, /* 0xA0-0xA3 */ - 0xD9, 0xF3, 0xD0, 0x9B, 0xD0, 0x9C, 0xD0, 0x9D, /* 0xA4-0xA7 */ - 0xD0, 0x9E, 0xD0, 0x9F, 0xD0, 0xA0, 0xB1, 0xBB, /* 0xA8-0xAB */ - 0xD1, 0x40, 0xCF, 0xAE, 0xD1, 0x41, 0xD1, 0x42, /* 0xAC-0xAF */ - 0xD1, 0x43, 0xB8, 0xA4, 0xD1, 0x44, 0xD1, 0x45, /* 0xB0-0xB3 */ - 0xD1, 0x46, 0xD1, 0x47, 0xD1, 0x48, 0xF1, 0xCA, /* 0xB4-0xB7 */ - 0xD1, 0x49, 0xD1, 0x4A, 0xD1, 0x4B, 0xD1, 0x4C, /* 0xB8-0xBB */ - 0xF1, 0xCB, 0xD1, 0x4D, 0xD1, 0x4E, 0xD1, 0x4F, /* 0xBC-0xBF */ - 0xD1, 0x50, 0xB2, 0xC3, 0xC1, 0xD1, 0xD1, 0x51, /* 0xC0-0xC3 */ - 0xD1, 0x52, 0xD7, 0xB0, 0xF1, 0xC9, 0xD1, 0x53, /* 0xC4-0xC7 */ - 0xD1, 0x54, 0xF1, 0xCC, 0xD1, 0x55, 0xD1, 0x56, /* 0xC8-0xCB */ - 0xD1, 0x57, 0xD1, 0x58, 0xF1, 0xCE, 0xD1, 0x59, /* 0xCC-0xCF */ - 0xD1, 0x5A, 0xD1, 0x5B, 0xD9, 0xF6, 0xD1, 0x5C, /* 0xD0-0xD3 */ - 0xD2, 0xE1, 0xD4, 0xA3, 0xD1, 0x5D, 0xD1, 0x5E, /* 0xD4-0xD7 */ - 0xF4, 0xC3, 0xC8, 0xB9, 0xD1, 0x5F, 0xD1, 0x60, /* 0xD8-0xDB */ - 0xD1, 0x61, 0xD1, 0x62, 0xD1, 0x63, 0xF4, 0xC4, /* 0xDC-0xDF */ - 0xD1, 0x64, 0xD1, 0x65, 0xF1, 0xCD, 0xF1, 0xCF, /* 0xE0-0xE3 */ - 0xBF, 0xE3, 0xF1, 0xD0, 0xD1, 0x66, 0xD1, 0x67, /* 0xE4-0xE7 */ - 0xF1, 0xD4, 0xD1, 0x68, 0xD1, 0x69, 0xD1, 0x6A, /* 0xE8-0xEB */ - 0xD1, 0x6B, 0xD1, 0x6C, 0xD1, 0x6D, 0xD1, 0x6E, /* 0xEC-0xEF */ - 0xF1, 0xD6, 0xF1, 0xD1, 0xD1, 0x6F, 0xC9, 0xD1, /* 0xF0-0xF3 */ - 0xC5, 0xE1, 0xD1, 0x70, 0xD1, 0x71, 0xD1, 0x72, /* 0xF4-0xF7 */ - 0xC2, 0xE3, 0xB9, 0xFC, 0xD1, 0x73, 0xD1, 0x74, /* 0xF8-0xFB */ - 0xF1, 0xD3, 0xD1, 0x75, 0xF1, 0xD5, 0xD1, 0x76, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_89[512] = { - 0xD1, 0x77, 0xD1, 0x78, 0xB9, 0xD3, 0xD1, 0x79, /* 0x00-0x03 */ - 0xD1, 0x7A, 0xD1, 0x7B, 0xD1, 0x7C, 0xD1, 0x7D, /* 0x04-0x07 */ - 0xD1, 0x7E, 0xD1, 0x80, 0xF1, 0xDB, 0xD1, 0x81, /* 0x08-0x0B */ - 0xD1, 0x82, 0xD1, 0x83, 0xD1, 0x84, 0xD1, 0x85, /* 0x0C-0x0F */ - 0xBA, 0xD6, 0xD1, 0x86, 0xB0, 0xFD, 0xF1, 0xD9, /* 0x10-0x13 */ - 0xD1, 0x87, 0xD1, 0x88, 0xD1, 0x89, 0xD1, 0x8A, /* 0x14-0x17 */ - 0xD1, 0x8B, 0xF1, 0xD8, 0xF1, 0xD2, 0xF1, 0xDA, /* 0x18-0x1B */ - 0xD1, 0x8C, 0xD1, 0x8D, 0xD1, 0x8E, 0xD1, 0x8F, /* 0x1C-0x1F */ - 0xD1, 0x90, 0xF1, 0xD7, 0xD1, 0x91, 0xD1, 0x92, /* 0x20-0x23 */ - 0xD1, 0x93, 0xC8, 0xEC, 0xD1, 0x94, 0xD1, 0x95, /* 0x24-0x27 */ - 0xD1, 0x96, 0xD1, 0x97, 0xCD, 0xCA, 0xF1, 0xDD, /* 0x28-0x2B */ - 0xD1, 0x98, 0xD1, 0x99, 0xD1, 0x9A, 0xD1, 0x9B, /* 0x2C-0x2F */ - 0xE5, 0xBD, 0xD1, 0x9C, 0xD1, 0x9D, 0xD1, 0x9E, /* 0x30-0x33 */ - 0xF1, 0xDC, 0xD1, 0x9F, 0xF1, 0xDE, 0xD1, 0xA0, /* 0x34-0x37 */ - 0xD2, 0x40, 0xD2, 0x41, 0xD2, 0x42, 0xD2, 0x43, /* 0x38-0x3B */ - 0xD2, 0x44, 0xD2, 0x45, 0xD2, 0x46, 0xD2, 0x47, /* 0x3C-0x3F */ - 0xD2, 0x48, 0xF1, 0xDF, 0xD2, 0x49, 0xD2, 0x4A, /* 0x40-0x43 */ - 0xCF, 0xE5, 0xD2, 0x4B, 0xD2, 0x4C, 0xD2, 0x4D, /* 0x44-0x47 */ - 0xD2, 0x4E, 0xD2, 0x4F, 0xD2, 0x50, 0xD2, 0x51, /* 0x48-0x4B */ - 0xD2, 0x52, 0xD2, 0x53, 0xD2, 0x54, 0xD2, 0x55, /* 0x4C-0x4F */ - 0xD2, 0x56, 0xD2, 0x57, 0xD2, 0x58, 0xD2, 0x59, /* 0x50-0x53 */ - 0xD2, 0x5A, 0xD2, 0x5B, 0xD2, 0x5C, 0xD2, 0x5D, /* 0x54-0x57 */ - 0xD2, 0x5E, 0xD2, 0x5F, 0xD2, 0x60, 0xD2, 0x61, /* 0x58-0x5B */ - 0xD2, 0x62, 0xD2, 0x63, 0xF4, 0xC5, 0xBD, 0xF3, /* 0x5C-0x5F */ - 0xD2, 0x64, 0xD2, 0x65, 0xD2, 0x66, 0xD2, 0x67, /* 0x60-0x63 */ - 0xD2, 0x68, 0xD2, 0x69, 0xF1, 0xE0, 0xD2, 0x6A, /* 0x64-0x67 */ - 0xD2, 0x6B, 0xD2, 0x6C, 0xD2, 0x6D, 0xD2, 0x6E, /* 0x68-0x6B */ - 0xD2, 0x6F, 0xD2, 0x70, 0xD2, 0x71, 0xD2, 0x72, /* 0x6C-0x6F */ - 0xD2, 0x73, 0xD2, 0x74, 0xD2, 0x75, 0xD2, 0x76, /* 0x70-0x73 */ - 0xD2, 0x77, 0xD2, 0x78, 0xD2, 0x79, 0xD2, 0x7A, /* 0x74-0x77 */ - 0xD2, 0x7B, 0xD2, 0x7C, 0xD2, 0x7D, 0xF1, 0xE1, /* 0x78-0x7B */ - 0xD2, 0x7E, 0xD2, 0x80, 0xD2, 0x81, 0xCE, 0xF7, /* 0x7C-0x7F */ - - 0xD2, 0x82, 0xD2, 0xAA, 0xD2, 0x83, 0xF1, 0xFB, /* 0x80-0x83 */ - 0xD2, 0x84, 0xD2, 0x85, 0xB8, 0xB2, 0xD2, 0x86, /* 0x84-0x87 */ - 0xD2, 0x87, 0xD2, 0x88, 0xD2, 0x89, 0xD2, 0x8A, /* 0x88-0x8B */ - 0xD2, 0x8B, 0xD2, 0x8C, 0xD2, 0x8D, 0xD2, 0x8E, /* 0x8C-0x8F */ - 0xD2, 0x8F, 0xD2, 0x90, 0xD2, 0x91, 0xD2, 0x92, /* 0x90-0x93 */ - 0xD2, 0x93, 0xD2, 0x94, 0xD2, 0x95, 0xD2, 0x96, /* 0x94-0x97 */ - 0xD2, 0x97, 0xD2, 0x98, 0xD2, 0x99, 0xD2, 0x9A, /* 0x98-0x9B */ - 0xD2, 0x9B, 0xD2, 0x9C, 0xD2, 0x9D, 0xD2, 0x9E, /* 0x9C-0x9F */ - 0xD2, 0x9F, 0xD2, 0xA0, 0xD3, 0x40, 0xD3, 0x41, /* 0xA0-0xA3 */ - 0xD3, 0x42, 0xD3, 0x43, 0xD3, 0x44, 0xD3, 0x45, /* 0xA4-0xA7 */ - 0xD3, 0x46, 0xD3, 0x47, 0xD3, 0x48, 0xD3, 0x49, /* 0xA8-0xAB */ - 0xD3, 0x4A, 0xD3, 0x4B, 0xD3, 0x4C, 0xD3, 0x4D, /* 0xAC-0xAF */ - 0xD3, 0x4E, 0xD3, 0x4F, 0xD3, 0x50, 0xD3, 0x51, /* 0xB0-0xB3 */ - 0xD3, 0x52, 0xD3, 0x53, 0xD3, 0x54, 0xD3, 0x55, /* 0xB4-0xB7 */ - 0xD3, 0x56, 0xD3, 0x57, 0xD3, 0x58, 0xD3, 0x59, /* 0xB8-0xBB */ - 0xD3, 0x5A, 0xD3, 0x5B, 0xD3, 0x5C, 0xD3, 0x5D, /* 0xBC-0xBF */ - 0xD3, 0x5E, 0xBC, 0xFB, 0xB9, 0xDB, 0xD3, 0x5F, /* 0xC0-0xC3 */ - 0xB9, 0xE6, 0xC3, 0xD9, 0xCA, 0xD3, 0xEA, 0xE8, /* 0xC4-0xC7 */ - 0xC0, 0xC0, 0xBE, 0xF5, 0xEA, 0xE9, 0xEA, 0xEA, /* 0xC8-0xCB */ - 0xEA, 0xEB, 0xD3, 0x60, 0xEA, 0xEC, 0xEA, 0xED, /* 0xCC-0xCF */ - 0xEA, 0xEE, 0xEA, 0xEF, 0xBD, 0xC7, 0xD3, 0x61, /* 0xD0-0xD3 */ - 0xD3, 0x62, 0xD3, 0x63, 0xF5, 0xFB, 0xD3, 0x64, /* 0xD4-0xD7 */ - 0xD3, 0x65, 0xD3, 0x66, 0xF5, 0xFD, 0xD3, 0x67, /* 0xD8-0xDB */ - 0xF5, 0xFE, 0xD3, 0x68, 0xF5, 0xFC, 0xD3, 0x69, /* 0xDC-0xDF */ - 0xD3, 0x6A, 0xD3, 0x6B, 0xD3, 0x6C, 0xBD, 0xE2, /* 0xE0-0xE3 */ - 0xD3, 0x6D, 0xF6, 0xA1, 0xB4, 0xA5, 0xD3, 0x6E, /* 0xE4-0xE7 */ - 0xD3, 0x6F, 0xD3, 0x70, 0xD3, 0x71, 0xF6, 0xA2, /* 0xE8-0xEB */ - 0xD3, 0x72, 0xD3, 0x73, 0xD3, 0x74, 0xF6, 0xA3, /* 0xEC-0xEF */ - 0xD3, 0x75, 0xD3, 0x76, 0xD3, 0x77, 0xEC, 0xB2, /* 0xF0-0xF3 */ - 0xD3, 0x78, 0xD3, 0x79, 0xD3, 0x7A, 0xD3, 0x7B, /* 0xF4-0xF7 */ - 0xD3, 0x7C, 0xD3, 0x7D, 0xD3, 0x7E, 0xD3, 0x80, /* 0xF8-0xFB */ - 0xD3, 0x81, 0xD3, 0x82, 0xD3, 0x83, 0xD3, 0x84, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_8A[512] = { - 0xD1, 0xD4, 0xD3, 0x85, 0xD3, 0x86, 0xD3, 0x87, /* 0x00-0x03 */ - 0xD3, 0x88, 0xD3, 0x89, 0xD3, 0x8A, 0xD9, 0xEA, /* 0x04-0x07 */ - 0xD3, 0x8B, 0xD3, 0x8C, 0xD3, 0x8D, 0xD3, 0x8E, /* 0x08-0x0B */ - 0xD3, 0x8F, 0xD3, 0x90, 0xD3, 0x91, 0xD3, 0x92, /* 0x0C-0x0F */ - 0xD3, 0x93, 0xD3, 0x94, 0xD3, 0x95, 0xD3, 0x96, /* 0x10-0x13 */ - 0xD3, 0x97, 0xD3, 0x98, 0xD3, 0x99, 0xD3, 0x9A, /* 0x14-0x17 */ - 0xD3, 0x9B, 0xD3, 0x9C, 0xD3, 0x9D, 0xD3, 0x9E, /* 0x18-0x1B */ - 0xD3, 0x9F, 0xD3, 0xA0, 0xD4, 0x40, 0xD4, 0x41, /* 0x1C-0x1F */ - 0xD4, 0x42, 0xD4, 0x43, 0xD4, 0x44, 0xD4, 0x45, /* 0x20-0x23 */ - 0xD4, 0x46, 0xD4, 0x47, 0xD4, 0x48, 0xD4, 0x49, /* 0x24-0x27 */ - 0xD4, 0x4A, 0xD4, 0x4B, 0xD4, 0x4C, 0xD4, 0x4D, /* 0x28-0x2B */ - 0xD4, 0x4E, 0xD4, 0x4F, 0xD4, 0x50, 0xD4, 0x51, /* 0x2C-0x2F */ - 0xD4, 0x52, 0xD4, 0x53, 0xD4, 0x54, 0xD4, 0x55, /* 0x30-0x33 */ - 0xD4, 0x56, 0xD4, 0x57, 0xD4, 0x58, 0xD4, 0x59, /* 0x34-0x37 */ - 0xD4, 0x5A, 0xD4, 0x5B, 0xD4, 0x5C, 0xD4, 0x5D, /* 0x38-0x3B */ - 0xD4, 0x5E, 0xD4, 0x5F, 0xF6, 0xA4, 0xD4, 0x60, /* 0x3C-0x3F */ - 0xD4, 0x61, 0xD4, 0x62, 0xD4, 0x63, 0xD4, 0x64, /* 0x40-0x43 */ - 0xD4, 0x65, 0xD4, 0x66, 0xD4, 0x67, 0xD4, 0x68, /* 0x44-0x47 */ - 0xEE, 0xBA, 0xD4, 0x69, 0xD4, 0x6A, 0xD4, 0x6B, /* 0x48-0x4B */ - 0xD4, 0x6C, 0xD4, 0x6D, 0xD4, 0x6E, 0xD4, 0x6F, /* 0x4C-0x4F */ - 0xD4, 0x70, 0xD4, 0x71, 0xD4, 0x72, 0xD4, 0x73, /* 0x50-0x53 */ - 0xD4, 0x74, 0xD4, 0x75, 0xD4, 0x76, 0xD4, 0x77, /* 0x54-0x57 */ - 0xD4, 0x78, 0xD4, 0x79, 0xD4, 0x7A, 0xD4, 0x7B, /* 0x58-0x5B */ - 0xD4, 0x7C, 0xD4, 0x7D, 0xD4, 0x7E, 0xD4, 0x80, /* 0x5C-0x5F */ - 0xD4, 0x81, 0xD4, 0x82, 0xD4, 0x83, 0xD4, 0x84, /* 0x60-0x63 */ - 0xD4, 0x85, 0xD4, 0x86, 0xD4, 0x87, 0xD4, 0x88, /* 0x64-0x67 */ - 0xD4, 0x89, 0xD4, 0x8A, 0xD4, 0x8B, 0xD4, 0x8C, /* 0x68-0x6B */ - 0xD4, 0x8D, 0xD4, 0x8E, 0xD4, 0x8F, 0xD4, 0x90, /* 0x6C-0x6F */ - 0xD4, 0x91, 0xD4, 0x92, 0xD4, 0x93, 0xD4, 0x94, /* 0x70-0x73 */ - 0xD4, 0x95, 0xD4, 0x96, 0xD4, 0x97, 0xD4, 0x98, /* 0x74-0x77 */ - 0xD4, 0x99, 0xD5, 0xB2, 0xD4, 0x9A, 0xD4, 0x9B, /* 0x78-0x7B */ - 0xD4, 0x9C, 0xD4, 0x9D, 0xD4, 0x9E, 0xD4, 0x9F, /* 0x7C-0x7F */ - - 0xD4, 0xA0, 0xD5, 0x40, 0xD5, 0x41, 0xD5, 0x42, /* 0x80-0x83 */ - 0xD5, 0x43, 0xD5, 0x44, 0xD5, 0x45, 0xD5, 0x46, /* 0x84-0x87 */ - 0xD5, 0x47, 0xD3, 0xFE, 0xCC, 0xDC, 0xD5, 0x48, /* 0x88-0x8B */ - 0xD5, 0x49, 0xD5, 0x4A, 0xD5, 0x4B, 0xD5, 0x4C, /* 0x8C-0x8F */ - 0xD5, 0x4D, 0xD5, 0x4E, 0xD5, 0x4F, 0xCA, 0xC4, /* 0x90-0x93 */ - 0xD5, 0x50, 0xD5, 0x51, 0xD5, 0x52, 0xD5, 0x53, /* 0x94-0x97 */ - 0xD5, 0x54, 0xD5, 0x55, 0xD5, 0x56, 0xD5, 0x57, /* 0x98-0x9B */ - 0xD5, 0x58, 0xD5, 0x59, 0xD5, 0x5A, 0xD5, 0x5B, /* 0x9C-0x9F */ - 0xD5, 0x5C, 0xD5, 0x5D, 0xD5, 0x5E, 0xD5, 0x5F, /* 0xA0-0xA3 */ - 0xD5, 0x60, 0xD5, 0x61, 0xD5, 0x62, 0xD5, 0x63, /* 0xA4-0xA7 */ - 0xD5, 0x64, 0xD5, 0x65, 0xD5, 0x66, 0xD5, 0x67, /* 0xA8-0xAB */ - 0xD5, 0x68, 0xD5, 0x69, 0xD5, 0x6A, 0xD5, 0x6B, /* 0xAC-0xAF */ - 0xD5, 0x6C, 0xD5, 0x6D, 0xD5, 0x6E, 0xD5, 0x6F, /* 0xB0-0xB3 */ - 0xD5, 0x70, 0xD5, 0x71, 0xD5, 0x72, 0xD5, 0x73, /* 0xB4-0xB7 */ - 0xD5, 0x74, 0xD5, 0x75, 0xD5, 0x76, 0xD5, 0x77, /* 0xB8-0xBB */ - 0xD5, 0x78, 0xD5, 0x79, 0xD5, 0x7A, 0xD5, 0x7B, /* 0xBC-0xBF */ - 0xD5, 0x7C, 0xD5, 0x7D, 0xD5, 0x7E, 0xD5, 0x80, /* 0xC0-0xC3 */ - 0xD5, 0x81, 0xD5, 0x82, 0xD5, 0x83, 0xD5, 0x84, /* 0xC4-0xC7 */ - 0xD5, 0x85, 0xD5, 0x86, 0xD5, 0x87, 0xD5, 0x88, /* 0xC8-0xCB */ - 0xD5, 0x89, 0xD5, 0x8A, 0xD5, 0x8B, 0xD5, 0x8C, /* 0xCC-0xCF */ - 0xD5, 0x8D, 0xD5, 0x8E, 0xD5, 0x8F, 0xD5, 0x90, /* 0xD0-0xD3 */ - 0xD5, 0x91, 0xD5, 0x92, 0xD5, 0x93, 0xD5, 0x94, /* 0xD4-0xD7 */ - 0xD5, 0x95, 0xD5, 0x96, 0xD5, 0x97, 0xD5, 0x98, /* 0xD8-0xDB */ - 0xD5, 0x99, 0xD5, 0x9A, 0xD5, 0x9B, 0xD5, 0x9C, /* 0xDC-0xDF */ - 0xD5, 0x9D, 0xD5, 0x9E, 0xD5, 0x9F, 0xD5, 0xA0, /* 0xE0-0xE3 */ - 0xD6, 0x40, 0xD6, 0x41, 0xD6, 0x42, 0xD6, 0x43, /* 0xE4-0xE7 */ - 0xD6, 0x44, 0xD6, 0x45, 0xD6, 0x46, 0xD6, 0x47, /* 0xE8-0xEB */ - 0xD6, 0x48, 0xD6, 0x49, 0xD6, 0x4A, 0xD6, 0x4B, /* 0xEC-0xEF */ - 0xD6, 0x4C, 0xD6, 0x4D, 0xD6, 0x4E, 0xD6, 0x4F, /* 0xF0-0xF3 */ - 0xD6, 0x50, 0xD6, 0x51, 0xD6, 0x52, 0xD6, 0x53, /* 0xF4-0xF7 */ - 0xD6, 0x54, 0xD6, 0x55, 0xD6, 0x56, 0xD6, 0x57, /* 0xF8-0xFB */ - 0xD6, 0x58, 0xD6, 0x59, 0xD6, 0x5A, 0xD6, 0x5B, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_8B[512] = { - 0xD6, 0x5C, 0xD6, 0x5D, 0xD6, 0x5E, 0xD6, 0x5F, /* 0x00-0x03 */ - 0xD6, 0x60, 0xD6, 0x61, 0xD6, 0x62, 0xE5, 0xC0, /* 0x04-0x07 */ - 0xD6, 0x63, 0xD6, 0x64, 0xD6, 0x65, 0xD6, 0x66, /* 0x08-0x0B */ - 0xD6, 0x67, 0xD6, 0x68, 0xD6, 0x69, 0xD6, 0x6A, /* 0x0C-0x0F */ - 0xD6, 0x6B, 0xD6, 0x6C, 0xD6, 0x6D, 0xD6, 0x6E, /* 0x10-0x13 */ - 0xD6, 0x6F, 0xD6, 0x70, 0xD6, 0x71, 0xD6, 0x72, /* 0x14-0x17 */ - 0xD6, 0x73, 0xD6, 0x74, 0xD6, 0x75, 0xD6, 0x76, /* 0x18-0x1B */ - 0xD6, 0x77, 0xD6, 0x78, 0xD6, 0x79, 0xD6, 0x7A, /* 0x1C-0x1F */ - 0xD6, 0x7B, 0xD6, 0x7C, 0xD6, 0x7D, 0xD6, 0x7E, /* 0x20-0x23 */ - 0xD6, 0x80, 0xD6, 0x81, 0xF6, 0xA5, 0xD6, 0x82, /* 0x24-0x27 */ - 0xD6, 0x83, 0xD6, 0x84, 0xD6, 0x85, 0xD6, 0x86, /* 0x28-0x2B */ - 0xD6, 0x87, 0xD6, 0x88, 0xD6, 0x89, 0xD6, 0x8A, /* 0x2C-0x2F */ - 0xD6, 0x8B, 0xD6, 0x8C, 0xD6, 0x8D, 0xD6, 0x8E, /* 0x30-0x33 */ - 0xD6, 0x8F, 0xD6, 0x90, 0xD6, 0x91, 0xD6, 0x92, /* 0x34-0x37 */ - 0xD6, 0x93, 0xD6, 0x94, 0xD6, 0x95, 0xD6, 0x96, /* 0x38-0x3B */ - 0xD6, 0x97, 0xD6, 0x98, 0xD6, 0x99, 0xD6, 0x9A, /* 0x3C-0x3F */ - 0xD6, 0x9B, 0xD6, 0x9C, 0xD6, 0x9D, 0xD6, 0x9E, /* 0x40-0x43 */ - 0xD6, 0x9F, 0xD6, 0xA0, 0xD7, 0x40, 0xD7, 0x41, /* 0x44-0x47 */ - 0xD7, 0x42, 0xD7, 0x43, 0xD7, 0x44, 0xD7, 0x45, /* 0x48-0x4B */ - 0xD7, 0x46, 0xD7, 0x47, 0xD7, 0x48, 0xD7, 0x49, /* 0x4C-0x4F */ - 0xD7, 0x4A, 0xD7, 0x4B, 0xD7, 0x4C, 0xD7, 0x4D, /* 0x50-0x53 */ - 0xD7, 0x4E, 0xD7, 0x4F, 0xD7, 0x50, 0xD7, 0x51, /* 0x54-0x57 */ - 0xD7, 0x52, 0xD7, 0x53, 0xD7, 0x54, 0xD7, 0x55, /* 0x58-0x5B */ - 0xD7, 0x56, 0xD7, 0x57, 0xD7, 0x58, 0xD7, 0x59, /* 0x5C-0x5F */ - 0xD7, 0x5A, 0xD7, 0x5B, 0xD7, 0x5C, 0xD7, 0x5D, /* 0x60-0x63 */ - 0xD7, 0x5E, 0xD7, 0x5F, 0xBE, 0xAF, 0xD7, 0x60, /* 0x64-0x67 */ - 0xD7, 0x61, 0xD7, 0x62, 0xD7, 0x63, 0xD7, 0x64, /* 0x68-0x6B */ - 0xC6, 0xA9, 0xD7, 0x65, 0xD7, 0x66, 0xD7, 0x67, /* 0x6C-0x6F */ - 0xD7, 0x68, 0xD7, 0x69, 0xD7, 0x6A, 0xD7, 0x6B, /* 0x70-0x73 */ - 0xD7, 0x6C, 0xD7, 0x6D, 0xD7, 0x6E, 0xD7, 0x6F, /* 0x74-0x77 */ - 0xD7, 0x70, 0xD7, 0x71, 0xD7, 0x72, 0xD7, 0x73, /* 0x78-0x7B */ - 0xD7, 0x74, 0xD7, 0x75, 0xD7, 0x76, 0xD7, 0x77, /* 0x7C-0x7F */ - - 0xD7, 0x78, 0xD7, 0x79, 0xD7, 0x7A, 0xD7, 0x7B, /* 0x80-0x83 */ - 0xD7, 0x7C, 0xD7, 0x7D, 0xD7, 0x7E, 0xD7, 0x80, /* 0x84-0x87 */ - 0xD7, 0x81, 0xD7, 0x82, 0xD7, 0x83, 0xD7, 0x84, /* 0x88-0x8B */ - 0xD7, 0x85, 0xD7, 0x86, 0xD7, 0x87, 0xD7, 0x88, /* 0x8C-0x8F */ - 0xD7, 0x89, 0xD7, 0x8A, 0xD7, 0x8B, 0xD7, 0x8C, /* 0x90-0x93 */ - 0xD7, 0x8D, 0xD7, 0x8E, 0xD7, 0x8F, 0xD7, 0x90, /* 0x94-0x97 */ - 0xD7, 0x91, 0xD7, 0x92, 0xD7, 0x93, 0xD7, 0x94, /* 0x98-0x9B */ - 0xD7, 0x95, 0xD7, 0x96, 0xD7, 0x97, 0xD7, 0x98, /* 0x9C-0x9F */ - 0xDA, 0xA5, 0xBC, 0xC6, 0xB6, 0xA9, 0xB8, 0xBC, /* 0xA0-0xA3 */ - 0xC8, 0xCF, 0xBC, 0xA5, 0xDA, 0xA6, 0xDA, 0xA7, /* 0xA4-0xA7 */ - 0xCC, 0xD6, 0xC8, 0xC3, 0xDA, 0xA8, 0xC6, 0xFD, /* 0xA8-0xAB */ - 0xD7, 0x99, 0xD1, 0xB5, 0xD2, 0xE9, 0xD1, 0xB6, /* 0xAC-0xAF */ - 0xBC, 0xC7, 0xD7, 0x9A, 0xBD, 0xB2, 0xBB, 0xE4, /* 0xB0-0xB3 */ - 0xDA, 0xA9, 0xDA, 0xAA, 0xD1, 0xC8, 0xDA, 0xAB, /* 0xB4-0xB7 */ - 0xD0, 0xED, 0xB6, 0xEF, 0xC2, 0xDB, 0xD7, 0x9B, /* 0xB8-0xBB */ - 0xCB, 0xCF, 0xB7, 0xED, 0xC9, 0xE8, 0xB7, 0xC3, /* 0xBC-0xBF */ - 0xBE, 0xF7, 0xD6, 0xA4, 0xDA, 0xAC, 0xDA, 0xAD, /* 0xC0-0xC3 */ - 0xC6, 0xC0, 0xD7, 0xE7, 0xCA, 0xB6, 0xD7, 0x9C, /* 0xC4-0xC7 */ - 0xD5, 0xA9, 0xCB, 0xDF, 0xD5, 0xEF, 0xDA, 0xAE, /* 0xC8-0xCB */ - 0xD6, 0xDF, 0xB4, 0xCA, 0xDA, 0xB0, 0xDA, 0xAF, /* 0xCC-0xCF */ - 0xD7, 0x9D, 0xD2, 0xEB, 0xDA, 0xB1, 0xDA, 0xB2, /* 0xD0-0xD3 */ - 0xDA, 0xB3, 0xCA, 0xD4, 0xDA, 0xB4, 0xCA, 0xAB, /* 0xD4-0xD7 */ - 0xDA, 0xB5, 0xDA, 0xB6, 0xB3, 0xCF, 0xD6, 0xEF, /* 0xD8-0xDB */ - 0xDA, 0xB7, 0xBB, 0xB0, 0xB5, 0xAE, 0xDA, 0xB8, /* 0xDC-0xDF */ - 0xDA, 0xB9, 0xB9, 0xEE, 0xD1, 0xAF, 0xD2, 0xE8, /* 0xE0-0xE3 */ - 0xDA, 0xBA, 0xB8, 0xC3, 0xCF, 0xEA, 0xB2, 0xEF, /* 0xE4-0xE7 */ - 0xDA, 0xBB, 0xDA, 0xBC, 0xD7, 0x9E, 0xBD, 0xEB, /* 0xE8-0xEB */ - 0xCE, 0xDC, 0xD3, 0xEF, 0xDA, 0xBD, 0xCE, 0xF3, /* 0xEC-0xEF */ - 0xDA, 0xBE, 0xD3, 0xD5, 0xBB, 0xE5, 0xDA, 0xBF, /* 0xF0-0xF3 */ - 0xCB, 0xB5, 0xCB, 0xD0, 0xDA, 0xC0, 0xC7, 0xEB, /* 0xF4-0xF7 */ - 0xD6, 0xEE, 0xDA, 0xC1, 0xC5, 0xB5, 0xB6, 0xC1, /* 0xF8-0xFB */ - 0xDA, 0xC2, 0xB7, 0xCC, 0xBF, 0xCE, 0xDA, 0xC3, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_8C[512] = { - 0xDA, 0xC4, 0xCB, 0xAD, 0xDA, 0xC5, 0xB5, 0xF7, /* 0x00-0x03 */ - 0xDA, 0xC6, 0xC1, 0xC2, 0xD7, 0xBB, 0xDA, 0xC7, /* 0x04-0x07 */ - 0xCC, 0xB8, 0xD7, 0x9F, 0xD2, 0xEA, 0xC4, 0xB1, /* 0x08-0x0B */ - 0xDA, 0xC8, 0xB5, 0xFD, 0xBB, 0xD1, 0xDA, 0xC9, /* 0x0C-0x0F */ - 0xD0, 0xB3, 0xDA, 0xCA, 0xDA, 0xCB, 0xCE, 0xBD, /* 0x10-0x13 */ - 0xDA, 0xCC, 0xDA, 0xCD, 0xDA, 0xCE, 0xB2, 0xF7, /* 0x14-0x17 */ - 0xDA, 0xD1, 0xDA, 0xCF, 0xD1, 0xE8, 0xDA, 0xD0, /* 0x18-0x1B */ - 0xC3, 0xD5, 0xDA, 0xD2, 0xD7, 0xA0, 0xDA, 0xD3, /* 0x1C-0x1F */ - 0xDA, 0xD4, 0xDA, 0xD5, 0xD0, 0xBB, 0xD2, 0xA5, /* 0x20-0x23 */ - 0xB0, 0xF9, 0xDA, 0xD6, 0xC7, 0xAB, 0xDA, 0xD7, /* 0x24-0x27 */ - 0xBD, 0xF7, 0xC3, 0xA1, 0xDA, 0xD8, 0xDA, 0xD9, /* 0x28-0x2B */ - 0xC3, 0xFD, 0xCC, 0xB7, 0xDA, 0xDA, 0xDA, 0xDB, /* 0x2C-0x2F */ - 0xC0, 0xBE, 0xC6, 0xD7, 0xDA, 0xDC, 0xDA, 0xDD, /* 0x30-0x33 */ - 0xC7, 0xB4, 0xDA, 0xDE, 0xDA, 0xDF, 0xB9, 0xC8, /* 0x34-0x37 */ - 0xD8, 0x40, 0xD8, 0x41, 0xD8, 0x42, 0xD8, 0x43, /* 0x38-0x3B */ - 0xD8, 0x44, 0xD8, 0x45, 0xD8, 0x46, 0xD8, 0x47, /* 0x3C-0x3F */ - 0xD8, 0x48, 0xBB, 0xED, 0xD8, 0x49, 0xD8, 0x4A, /* 0x40-0x43 */ - 0xD8, 0x4B, 0xD8, 0x4C, 0xB6, 0xB9, 0xF4, 0xF8, /* 0x44-0x47 */ - 0xD8, 0x4D, 0xF4, 0xF9, 0xD8, 0x4E, 0xD8, 0x4F, /* 0x48-0x4B */ - 0xCD, 0xE3, 0xD8, 0x50, 0xD8, 0x51, 0xD8, 0x52, /* 0x4C-0x4F */ - 0xD8, 0x53, 0xD8, 0x54, 0xD8, 0x55, 0xD8, 0x56, /* 0x50-0x53 */ - 0xD8, 0x57, 0xF5, 0xB9, 0xD8, 0x58, 0xD8, 0x59, /* 0x54-0x57 */ - 0xD8, 0x5A, 0xD8, 0x5B, 0xEB, 0xE0, 0xD8, 0x5C, /* 0x58-0x5B */ - 0xD8, 0x5D, 0xD8, 0x5E, 0xD8, 0x5F, 0xD8, 0x60, /* 0x5C-0x5F */ - 0xD8, 0x61, 0xCF, 0xF3, 0xBB, 0xBF, 0xD8, 0x62, /* 0x60-0x63 */ - 0xD8, 0x63, 0xD8, 0x64, 0xD8, 0x65, 0xD8, 0x66, /* 0x64-0x67 */ - 0xD8, 0x67, 0xD8, 0x68, 0xBA, 0xC0, 0xD4, 0xA5, /* 0x68-0x6B */ - 0xD8, 0x69, 0xD8, 0x6A, 0xD8, 0x6B, 0xD8, 0x6C, /* 0x6C-0x6F */ - 0xD8, 0x6D, 0xD8, 0x6E, 0xD8, 0x6F, 0xE1, 0xD9, /* 0x70-0x73 */ - 0xD8, 0x70, 0xD8, 0x71, 0xD8, 0x72, 0xD8, 0x73, /* 0x74-0x77 */ - 0xF5, 0xF4, 0xB1, 0xAA, 0xB2, 0xF2, 0xD8, 0x74, /* 0x78-0x7B */ - 0xD8, 0x75, 0xD8, 0x76, 0xD8, 0x77, 0xD8, 0x78, /* 0x7C-0x7F */ - - 0xD8, 0x79, 0xD8, 0x7A, 0xF5, 0xF5, 0xD8, 0x7B, /* 0x80-0x83 */ - 0xD8, 0x7C, 0xF5, 0xF7, 0xD8, 0x7D, 0xD8, 0x7E, /* 0x84-0x87 */ - 0xD8, 0x80, 0xBA, 0xD1, 0xF5, 0xF6, 0xD8, 0x81, /* 0x88-0x8B */ - 0xC3, 0xB2, 0xD8, 0x82, 0xD8, 0x83, 0xD8, 0x84, /* 0x8C-0x8F */ - 0xD8, 0x85, 0xD8, 0x86, 0xD8, 0x87, 0xD8, 0x88, /* 0x90-0x93 */ - 0xF5, 0xF9, 0xD8, 0x89, 0xD8, 0x8A, 0xD8, 0x8B, /* 0x94-0x97 */ - 0xF5, 0xF8, 0xD8, 0x8C, 0xD8, 0x8D, 0xD8, 0x8E, /* 0x98-0x9B */ - 0xD8, 0x8F, 0xD8, 0x90, 0xD8, 0x91, 0xD8, 0x92, /* 0x9C-0x9F */ - 0xD8, 0x93, 0xD8, 0x94, 0xD8, 0x95, 0xD8, 0x96, /* 0xA0-0xA3 */ - 0xD8, 0x97, 0xD8, 0x98, 0xD8, 0x99, 0xD8, 0x9A, /* 0xA4-0xA7 */ - 0xD8, 0x9B, 0xD8, 0x9C, 0xD8, 0x9D, 0xD8, 0x9E, /* 0xA8-0xAB */ - 0xD8, 0x9F, 0xD8, 0xA0, 0xD9, 0x40, 0xD9, 0x41, /* 0xAC-0xAF */ - 0xD9, 0x42, 0xD9, 0x43, 0xD9, 0x44, 0xD9, 0x45, /* 0xB0-0xB3 */ - 0xD9, 0x46, 0xD9, 0x47, 0xD9, 0x48, 0xD9, 0x49, /* 0xB4-0xB7 */ - 0xD9, 0x4A, 0xD9, 0x4B, 0xD9, 0x4C, 0xD9, 0x4D, /* 0xB8-0xBB */ - 0xD9, 0x4E, 0xD9, 0x4F, 0xD9, 0x50, 0xD9, 0x51, /* 0xBC-0xBF */ - 0xD9, 0x52, 0xD9, 0x53, 0xD9, 0x54, 0xD9, 0x55, /* 0xC0-0xC3 */ - 0xD9, 0x56, 0xD9, 0x57, 0xD9, 0x58, 0xD9, 0x59, /* 0xC4-0xC7 */ - 0xD9, 0x5A, 0xD9, 0x5B, 0xD9, 0x5C, 0xD9, 0x5D, /* 0xC8-0xCB */ - 0xD9, 0x5E, 0xD9, 0x5F, 0xD9, 0x60, 0xD9, 0x61, /* 0xCC-0xCF */ - 0xD9, 0x62, 0xD9, 0x63, 0xD9, 0x64, 0xD9, 0x65, /* 0xD0-0xD3 */ - 0xD9, 0x66, 0xD9, 0x67, 0xD9, 0x68, 0xD9, 0x69, /* 0xD4-0xD7 */ - 0xD9, 0x6A, 0xD9, 0x6B, 0xD9, 0x6C, 0xD9, 0x6D, /* 0xD8-0xDB */ - 0xD9, 0x6E, 0xD9, 0x6F, 0xD9, 0x70, 0xD9, 0x71, /* 0xDC-0xDF */ - 0xD9, 0x72, 0xD9, 0x73, 0xD9, 0x74, 0xD9, 0x75, /* 0xE0-0xE3 */ - 0xD9, 0x76, 0xD9, 0x77, 0xD9, 0x78, 0xD9, 0x79, /* 0xE4-0xE7 */ - 0xD9, 0x7A, 0xD9, 0x7B, 0xD9, 0x7C, 0xD9, 0x7D, /* 0xE8-0xEB */ - 0xD9, 0x7E, 0xD9, 0x80, 0xD9, 0x81, 0xD9, 0x82, /* 0xEC-0xEF */ - 0xD9, 0x83, 0xD9, 0x84, 0xD9, 0x85, 0xD9, 0x86, /* 0xF0-0xF3 */ - 0xD9, 0x87, 0xD9, 0x88, 0xD9, 0x89, 0xD9, 0x8A, /* 0xF4-0xF7 */ - 0xD9, 0x8B, 0xD9, 0x8C, 0xD9, 0x8D, 0xD9, 0x8E, /* 0xF8-0xFB */ - 0xD9, 0x8F, 0xD9, 0x90, 0xD9, 0x91, 0xD9, 0x92, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_8D[512] = { - 0xD9, 0x93, 0xD9, 0x94, 0xD9, 0x95, 0xD9, 0x96, /* 0x00-0x03 */ - 0xD9, 0x97, 0xD9, 0x98, 0xD9, 0x99, 0xD9, 0x9A, /* 0x04-0x07 */ - 0xD9, 0x9B, 0xD9, 0x9C, 0xD9, 0x9D, 0xD9, 0x9E, /* 0x08-0x0B */ - 0xD9, 0x9F, 0xD9, 0xA0, 0xDA, 0x40, 0xDA, 0x41, /* 0x0C-0x0F */ - 0xDA, 0x42, 0xDA, 0x43, 0xDA, 0x44, 0xDA, 0x45, /* 0x10-0x13 */ - 0xDA, 0x46, 0xDA, 0x47, 0xDA, 0x48, 0xDA, 0x49, /* 0x14-0x17 */ - 0xDA, 0x4A, 0xDA, 0x4B, 0xDA, 0x4C, 0xDA, 0x4D, /* 0x18-0x1B */ - 0xDA, 0x4E, 0xB1, 0xB4, 0xD5, 0xEA, 0xB8, 0xBA, /* 0x1C-0x1F */ - 0xDA, 0x4F, 0xB9, 0xB1, 0xB2, 0xC6, 0xD4, 0xF0, /* 0x20-0x23 */ - 0xCF, 0xCD, 0xB0, 0xDC, 0xD5, 0xCB, 0xBB, 0xF5, /* 0x24-0x27 */ - 0xD6, 0xCA, 0xB7, 0xB7, 0xCC, 0xB0, 0xC6, 0xB6, /* 0x28-0x2B */ - 0xB1, 0xE1, 0xB9, 0xBA, 0xD6, 0xFC, 0xB9, 0xE1, /* 0x2C-0x2F */ - 0xB7, 0xA1, 0xBC, 0xFA, 0xEA, 0xDA, 0xEA, 0xDB, /* 0x30-0x33 */ - 0xCC, 0xF9, 0xB9, 0xF3, 0xEA, 0xDC, 0xB4, 0xFB, /* 0x34-0x37 */ - 0xC3, 0xB3, 0xB7, 0xD1, 0xBA, 0xD8, 0xEA, 0xDD, /* 0x38-0x3B */ - 0xD4, 0xF4, 0xEA, 0xDE, 0xBC, 0xD6, 0xBB, 0xDF, /* 0x3C-0x3F */ - 0xEA, 0xDF, 0xC1, 0xDE, 0xC2, 0xB8, 0xD4, 0xDF, /* 0x40-0x43 */ - 0xD7, 0xCA, 0xEA, 0xE0, 0xEA, 0xE1, 0xEA, 0xE4, /* 0x44-0x47 */ - 0xEA, 0xE2, 0xEA, 0xE3, 0xC9, 0xDE, 0xB8, 0xB3, /* 0x48-0x4B */ - 0xB6, 0xC4, 0xEA, 0xE5, 0xCA, 0xEA, 0xC9, 0xCD, /* 0x4C-0x4F */ - 0xB4, 0xCD, 0xDA, 0x50, 0xDA, 0x51, 0xE2, 0xD9, /* 0x50-0x53 */ - 0xC5, 0xE2, 0xEA, 0xE6, 0xC0, 0xB5, 0xDA, 0x52, /* 0x54-0x57 */ - 0xD7, 0xB8, 0xEA, 0xE7, 0xD7, 0xAC, 0xC8, 0xFC, /* 0x58-0x5B */ - 0xD8, 0xD3, 0xD8, 0xCD, 0xD4, 0xDE, 0xDA, 0x53, /* 0x5C-0x5F */ - 0xD4, 0xF9, 0xC9, 0xC4, 0xD3, 0xAE, 0xB8, 0xD3, /* 0x60-0x63 */ - 0xB3, 0xE0, 0xDA, 0x54, 0xC9, 0xE2, 0xF4, 0xF6, /* 0x64-0x67 */ - 0xDA, 0x55, 0xDA, 0x56, 0xDA, 0x57, 0xBA, 0xD5, /* 0x68-0x6B */ - 0xDA, 0x58, 0xF4, 0xF7, 0xDA, 0x59, 0xDA, 0x5A, /* 0x6C-0x6F */ - 0xD7, 0xDF, 0xDA, 0x5B, 0xDA, 0x5C, 0xF4, 0xF1, /* 0x70-0x73 */ - 0xB8, 0xB0, 0xD5, 0xD4, 0xB8, 0xCF, 0xC6, 0xF0, /* 0x74-0x77 */ - 0xDA, 0x5D, 0xDA, 0x5E, 0xDA, 0x5F, 0xDA, 0x60, /* 0x78-0x7B */ - 0xDA, 0x61, 0xDA, 0x62, 0xDA, 0x63, 0xDA, 0x64, /* 0x7C-0x7F */ - - 0xDA, 0x65, 0xB3, 0xC3, 0xDA, 0x66, 0xDA, 0x67, /* 0x80-0x83 */ - 0xF4, 0xF2, 0xB3, 0xAC, 0xDA, 0x68, 0xDA, 0x69, /* 0x84-0x87 */ - 0xDA, 0x6A, 0xDA, 0x6B, 0xD4, 0xBD, 0xC7, 0xF7, /* 0x88-0x8B */ - 0xDA, 0x6C, 0xDA, 0x6D, 0xDA, 0x6E, 0xDA, 0x6F, /* 0x8C-0x8F */ - 0xDA, 0x70, 0xF4, 0xF4, 0xDA, 0x71, 0xDA, 0x72, /* 0x90-0x93 */ - 0xF4, 0xF3, 0xDA, 0x73, 0xDA, 0x74, 0xDA, 0x75, /* 0x94-0x97 */ - 0xDA, 0x76, 0xDA, 0x77, 0xDA, 0x78, 0xDA, 0x79, /* 0x98-0x9B */ - 0xDA, 0x7A, 0xDA, 0x7B, 0xDA, 0x7C, 0xCC, 0xCB, /* 0x9C-0x9F */ - 0xDA, 0x7D, 0xDA, 0x7E, 0xDA, 0x80, 0xC8, 0xA4, /* 0xA0-0xA3 */ - 0xDA, 0x81, 0xDA, 0x82, 0xDA, 0x83, 0xDA, 0x84, /* 0xA4-0xA7 */ - 0xDA, 0x85, 0xDA, 0x86, 0xDA, 0x87, 0xDA, 0x88, /* 0xA8-0xAB */ - 0xDA, 0x89, 0xDA, 0x8A, 0xDA, 0x8B, 0xDA, 0x8C, /* 0xAC-0xAF */ - 0xDA, 0x8D, 0xF4, 0xF5, 0xDA, 0x8E, 0xD7, 0xE3, /* 0xB0-0xB3 */ - 0xC5, 0xBF, 0xF5, 0xC0, 0xDA, 0x8F, 0xDA, 0x90, /* 0xB4-0xB7 */ - 0xF5, 0xBB, 0xDA, 0x91, 0xF5, 0xC3, 0xDA, 0x92, /* 0xB8-0xBB */ - 0xF5, 0xC2, 0xDA, 0x93, 0xD6, 0xBA, 0xF5, 0xC1, /* 0xBC-0xBF */ - 0xDA, 0x94, 0xDA, 0x95, 0xDA, 0x96, 0xD4, 0xBE, /* 0xC0-0xC3 */ - 0xF5, 0xC4, 0xDA, 0x97, 0xF5, 0xCC, 0xDA, 0x98, /* 0xC4-0xC7 */ - 0xDA, 0x99, 0xDA, 0x9A, 0xDA, 0x9B, 0xB0, 0xCF, /* 0xC8-0xCB */ - 0xB5, 0xF8, 0xDA, 0x9C, 0xF5, 0xC9, 0xF5, 0xCA, /* 0xCC-0xCF */ - 0xDA, 0x9D, 0xC5, 0xDC, 0xDA, 0x9E, 0xDA, 0x9F, /* 0xD0-0xD3 */ - 0xDA, 0xA0, 0xDB, 0x40, 0xF5, 0xC5, 0xF5, 0xC6, /* 0xD4-0xD7 */ - 0xDB, 0x41, 0xDB, 0x42, 0xF5, 0xC7, 0xF5, 0xCB, /* 0xD8-0xDB */ - 0xDB, 0x43, 0xBE, 0xE0, 0xF5, 0xC8, 0xB8, 0xFA, /* 0xDC-0xDF */ - 0xDB, 0x44, 0xDB, 0x45, 0xDB, 0x46, 0xF5, 0xD0, /* 0xE0-0xE3 */ - 0xF5, 0xD3, 0xDB, 0x47, 0xDB, 0x48, 0xDB, 0x49, /* 0xE4-0xE7 */ - 0xBF, 0xE7, 0xDB, 0x4A, 0xB9, 0xF2, 0xF5, 0xBC, /* 0xE8-0xEB */ - 0xF5, 0xCD, 0xDB, 0x4B, 0xDB, 0x4C, 0xC2, 0xB7, /* 0xEC-0xEF */ - 0xDB, 0x4D, 0xDB, 0x4E, 0xDB, 0x4F, 0xCC, 0xF8, /* 0xF0-0xF3 */ - 0xDB, 0x50, 0xBC, 0xF9, 0xDB, 0x51, 0xF5, 0xCE, /* 0xF4-0xF7 */ - 0xF5, 0xCF, 0xF5, 0xD1, 0xB6, 0xE5, 0xF5, 0xD2, /* 0xF8-0xFB */ - 0xDB, 0x52, 0xF5, 0xD5, 0xDB, 0x53, 0xDB, 0x54, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_8E[512] = { - 0xDB, 0x55, 0xDB, 0x56, 0xDB, 0x57, 0xDB, 0x58, /* 0x00-0x03 */ - 0xDB, 0x59, 0xF5, 0xBD, 0xDB, 0x5A, 0xDB, 0x5B, /* 0x04-0x07 */ - 0xDB, 0x5C, 0xF5, 0xD4, 0xD3, 0xBB, 0xDB, 0x5D, /* 0x08-0x0B */ - 0xB3, 0xEC, 0xDB, 0x5E, 0xDB, 0x5F, 0xCC, 0xA4, /* 0x0C-0x0F */ - 0xDB, 0x60, 0xDB, 0x61, 0xDB, 0x62, 0xDB, 0x63, /* 0x10-0x13 */ - 0xF5, 0xD6, 0xDB, 0x64, 0xDB, 0x65, 0xDB, 0x66, /* 0x14-0x17 */ - 0xDB, 0x67, 0xDB, 0x68, 0xDB, 0x69, 0xDB, 0x6A, /* 0x18-0x1B */ - 0xDB, 0x6B, 0xF5, 0xD7, 0xBE, 0xE1, 0xF5, 0xD8, /* 0x1C-0x1F */ - 0xDB, 0x6C, 0xDB, 0x6D, 0xCC, 0xDF, 0xF5, 0xDB, /* 0x20-0x23 */ - 0xDB, 0x6E, 0xDB, 0x6F, 0xDB, 0x70, 0xDB, 0x71, /* 0x24-0x27 */ - 0xDB, 0x72, 0xB2, 0xC8, 0xD7, 0xD9, 0xDB, 0x73, /* 0x28-0x2B */ - 0xF5, 0xD9, 0xDB, 0x74, 0xF5, 0xDA, 0xF5, 0xDC, /* 0x2C-0x2F */ - 0xDB, 0x75, 0xF5, 0xE2, 0xDB, 0x76, 0xDB, 0x77, /* 0x30-0x33 */ - 0xDB, 0x78, 0xF5, 0xE0, 0xDB, 0x79, 0xDB, 0x7A, /* 0x34-0x37 */ - 0xDB, 0x7B, 0xF5, 0xDF, 0xF5, 0xDD, 0xDB, 0x7C, /* 0x38-0x3B */ - 0xDB, 0x7D, 0xF5, 0xE1, 0xDB, 0x7E, 0xDB, 0x80, /* 0x3C-0x3F */ - 0xF5, 0xDE, 0xF5, 0xE4, 0xF5, 0xE5, 0xDB, 0x81, /* 0x40-0x43 */ - 0xCC, 0xE3, 0xDB, 0x82, 0xDB, 0x83, 0xE5, 0xBF, /* 0x44-0x47 */ - 0xB5, 0xB8, 0xF5, 0xE3, 0xF5, 0xE8, 0xCC, 0xA3, /* 0x48-0x4B */ - 0xDB, 0x84, 0xDB, 0x85, 0xDB, 0x86, 0xDB, 0x87, /* 0x4C-0x4F */ - 0xDB, 0x88, 0xF5, 0xE6, 0xF5, 0xE7, 0xDB, 0x89, /* 0x50-0x53 */ - 0xDB, 0x8A, 0xDB, 0x8B, 0xDB, 0x8C, 0xDB, 0x8D, /* 0x54-0x57 */ - 0xDB, 0x8E, 0xF5, 0xBE, 0xDB, 0x8F, 0xDB, 0x90, /* 0x58-0x5B */ - 0xDB, 0x91, 0xDB, 0x92, 0xDB, 0x93, 0xDB, 0x94, /* 0x5C-0x5F */ - 0xDB, 0x95, 0xDB, 0x96, 0xDB, 0x97, 0xDB, 0x98, /* 0x60-0x63 */ - 0xDB, 0x99, 0xDB, 0x9A, 0xB1, 0xC4, 0xDB, 0x9B, /* 0x64-0x67 */ - 0xDB, 0x9C, 0xF5, 0xBF, 0xDB, 0x9D, 0xDB, 0x9E, /* 0x68-0x6B */ - 0xB5, 0xC5, 0xB2, 0xE4, 0xDB, 0x9F, 0xF5, 0xEC, /* 0x6C-0x6F */ - 0xF5, 0xE9, 0xDB, 0xA0, 0xB6, 0xD7, 0xDC, 0x40, /* 0x70-0x73 */ - 0xF5, 0xED, 0xDC, 0x41, 0xF5, 0xEA, 0xDC, 0x42, /* 0x74-0x77 */ - 0xDC, 0x43, 0xDC, 0x44, 0xDC, 0x45, 0xDC, 0x46, /* 0x78-0x7B */ - 0xF5, 0xEB, 0xDC, 0x47, 0xDC, 0x48, 0xB4, 0xDA, /* 0x7C-0x7F */ - - 0xDC, 0x49, 0xD4, 0xEA, 0xDC, 0x4A, 0xDC, 0x4B, /* 0x80-0x83 */ - 0xDC, 0x4C, 0xF5, 0xEE, 0xDC, 0x4D, 0xB3, 0xF9, /* 0x84-0x87 */ - 0xDC, 0x4E, 0xDC, 0x4F, 0xDC, 0x50, 0xDC, 0x51, /* 0x88-0x8B */ - 0xDC, 0x52, 0xDC, 0x53, 0xDC, 0x54, 0xF5, 0xEF, /* 0x8C-0x8F */ - 0xF5, 0xF1, 0xDC, 0x55, 0xDC, 0x56, 0xDC, 0x57, /* 0x90-0x93 */ - 0xF5, 0xF0, 0xDC, 0x58, 0xDC, 0x59, 0xDC, 0x5A, /* 0x94-0x97 */ - 0xDC, 0x5B, 0xDC, 0x5C, 0xDC, 0x5D, 0xDC, 0x5E, /* 0x98-0x9B */ - 0xF5, 0xF2, 0xDC, 0x5F, 0xF5, 0xF3, 0xDC, 0x60, /* 0x9C-0x9F */ - 0xDC, 0x61, 0xDC, 0x62, 0xDC, 0x63, 0xDC, 0x64, /* 0xA0-0xA3 */ - 0xDC, 0x65, 0xDC, 0x66, 0xDC, 0x67, 0xDC, 0x68, /* 0xA4-0xA7 */ - 0xDC, 0x69, 0xDC, 0x6A, 0xDC, 0x6B, 0xC9, 0xED, /* 0xA8-0xAB */ - 0xB9, 0xAA, 0xDC, 0x6C, 0xDC, 0x6D, 0xC7, 0xFB, /* 0xAC-0xAF */ - 0xDC, 0x6E, 0xDC, 0x6F, 0xB6, 0xE3, 0xDC, 0x70, /* 0xB0-0xB3 */ - 0xDC, 0x71, 0xDC, 0x72, 0xDC, 0x73, 0xDC, 0x74, /* 0xB4-0xB7 */ - 0xDC, 0x75, 0xDC, 0x76, 0xCC, 0xC9, 0xDC, 0x77, /* 0xB8-0xBB */ - 0xDC, 0x78, 0xDC, 0x79, 0xDC, 0x7A, 0xDC, 0x7B, /* 0xBC-0xBF */ - 0xDC, 0x7C, 0xDC, 0x7D, 0xDC, 0x7E, 0xDC, 0x80, /* 0xC0-0xC3 */ - 0xDC, 0x81, 0xDC, 0x82, 0xDC, 0x83, 0xDC, 0x84, /* 0xC4-0xC7 */ - 0xDC, 0x85, 0xDC, 0x86, 0xDC, 0x87, 0xDC, 0x88, /* 0xC8-0xCB */ - 0xDC, 0x89, 0xDC, 0x8A, 0xEA, 0xA6, 0xDC, 0x8B, /* 0xCC-0xCF */ - 0xDC, 0x8C, 0xDC, 0x8D, 0xDC, 0x8E, 0xDC, 0x8F, /* 0xD0-0xD3 */ - 0xDC, 0x90, 0xDC, 0x91, 0xDC, 0x92, 0xDC, 0x93, /* 0xD4-0xD7 */ - 0xDC, 0x94, 0xDC, 0x95, 0xDC, 0x96, 0xDC, 0x97, /* 0xD8-0xDB */ - 0xDC, 0x98, 0xDC, 0x99, 0xDC, 0x9A, 0xDC, 0x9B, /* 0xDC-0xDF */ - 0xDC, 0x9C, 0xDC, 0x9D, 0xDC, 0x9E, 0xDC, 0x9F, /* 0xE0-0xE3 */ - 0xDC, 0xA0, 0xDD, 0x40, 0xDD, 0x41, 0xDD, 0x42, /* 0xE4-0xE7 */ - 0xDD, 0x43, 0xDD, 0x44, 0xDD, 0x45, 0xDD, 0x46, /* 0xE8-0xEB */ - 0xDD, 0x47, 0xDD, 0x48, 0xDD, 0x49, 0xDD, 0x4A, /* 0xEC-0xEF */ - 0xDD, 0x4B, 0xDD, 0x4C, 0xDD, 0x4D, 0xDD, 0x4E, /* 0xF0-0xF3 */ - 0xDD, 0x4F, 0xDD, 0x50, 0xDD, 0x51, 0xDD, 0x52, /* 0xF4-0xF7 */ - 0xDD, 0x53, 0xDD, 0x54, 0xDD, 0x55, 0xDD, 0x56, /* 0xF8-0xFB */ - 0xDD, 0x57, 0xDD, 0x58, 0xDD, 0x59, 0xDD, 0x5A, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_8F[512] = { - 0xDD, 0x5B, 0xDD, 0x5C, 0xDD, 0x5D, 0xDD, 0x5E, /* 0x00-0x03 */ - 0xDD, 0x5F, 0xDD, 0x60, 0xDD, 0x61, 0xDD, 0x62, /* 0x04-0x07 */ - 0xDD, 0x63, 0xDD, 0x64, 0xDD, 0x65, 0xDD, 0x66, /* 0x08-0x0B */ - 0xDD, 0x67, 0xDD, 0x68, 0xDD, 0x69, 0xDD, 0x6A, /* 0x0C-0x0F */ - 0xDD, 0x6B, 0xDD, 0x6C, 0xDD, 0x6D, 0xDD, 0x6E, /* 0x10-0x13 */ - 0xDD, 0x6F, 0xDD, 0x70, 0xDD, 0x71, 0xDD, 0x72, /* 0x14-0x17 */ - 0xDD, 0x73, 0xDD, 0x74, 0xDD, 0x75, 0xDD, 0x76, /* 0x18-0x1B */ - 0xDD, 0x77, 0xDD, 0x78, 0xDD, 0x79, 0xDD, 0x7A, /* 0x1C-0x1F */ - 0xDD, 0x7B, 0xDD, 0x7C, 0xDD, 0x7D, 0xDD, 0x7E, /* 0x20-0x23 */ - 0xDD, 0x80, 0xDD, 0x81, 0xDD, 0x82, 0xDD, 0x83, /* 0x24-0x27 */ - 0xDD, 0x84, 0xDD, 0x85, 0xDD, 0x86, 0xDD, 0x87, /* 0x28-0x2B */ - 0xDD, 0x88, 0xDD, 0x89, 0xDD, 0x8A, 0xDD, 0x8B, /* 0x2C-0x2F */ - 0xDD, 0x8C, 0xDD, 0x8D, 0xDD, 0x8E, 0xDD, 0x8F, /* 0x30-0x33 */ - 0xDD, 0x90, 0xDD, 0x91, 0xDD, 0x92, 0xDD, 0x93, /* 0x34-0x37 */ - 0xDD, 0x94, 0xDD, 0x95, 0xDD, 0x96, 0xDD, 0x97, /* 0x38-0x3B */ - 0xDD, 0x98, 0xDD, 0x99, 0xDD, 0x9A, 0xDD, 0x9B, /* 0x3C-0x3F */ - 0xDD, 0x9C, 0xDD, 0x9D, 0xDD, 0x9E, 0xDD, 0x9F, /* 0x40-0x43 */ - 0xDD, 0xA0, 0xDE, 0x40, 0xDE, 0x41, 0xDE, 0x42, /* 0x44-0x47 */ - 0xDE, 0x43, 0xDE, 0x44, 0xDE, 0x45, 0xDE, 0x46, /* 0x48-0x4B */ - 0xDE, 0x47, 0xDE, 0x48, 0xDE, 0x49, 0xDE, 0x4A, /* 0x4C-0x4F */ - 0xDE, 0x4B, 0xDE, 0x4C, 0xDE, 0x4D, 0xDE, 0x4E, /* 0x50-0x53 */ - 0xDE, 0x4F, 0xDE, 0x50, 0xDE, 0x51, 0xDE, 0x52, /* 0x54-0x57 */ - 0xDE, 0x53, 0xDE, 0x54, 0xDE, 0x55, 0xDE, 0x56, /* 0x58-0x5B */ - 0xDE, 0x57, 0xDE, 0x58, 0xDE, 0x59, 0xDE, 0x5A, /* 0x5C-0x5F */ - 0xDE, 0x5B, 0xDE, 0x5C, 0xDE, 0x5D, 0xDE, 0x5E, /* 0x60-0x63 */ - 0xDE, 0x5F, 0xDE, 0x60, 0xB3, 0xB5, 0xD4, 0xFE, /* 0x64-0x67 */ - 0xB9, 0xEC, 0xD0, 0xF9, 0xDE, 0x61, 0xE9, 0xED, /* 0x68-0x6B */ - 0xD7, 0xAA, 0xE9, 0xEE, 0xC2, 0xD6, 0xC8, 0xED, /* 0x6C-0x6F */ - 0xBA, 0xE4, 0xE9, 0xEF, 0xE9, 0xF0, 0xE9, 0xF1, /* 0x70-0x73 */ - 0xD6, 0xE1, 0xE9, 0xF2, 0xE9, 0xF3, 0xE9, 0xF5, /* 0x74-0x77 */ - 0xE9, 0xF4, 0xE9, 0xF6, 0xE9, 0xF7, 0xC7, 0xE1, /* 0x78-0x7B */ - 0xE9, 0xF8, 0xD4, 0xD8, 0xE9, 0xF9, 0xBD, 0xCE, /* 0x7C-0x7F */ - - 0xDE, 0x62, 0xE9, 0xFA, 0xE9, 0xFB, 0xBD, 0xCF, /* 0x80-0x83 */ - 0xE9, 0xFC, 0xB8, 0xA8, 0xC1, 0xBE, 0xE9, 0xFD, /* 0x84-0x87 */ - 0xB1, 0xB2, 0xBB, 0xD4, 0xB9, 0xF5, 0xE9, 0xFE, /* 0x88-0x8B */ - 0xDE, 0x63, 0xEA, 0xA1, 0xEA, 0xA2, 0xEA, 0xA3, /* 0x8C-0x8F */ - 0xB7, 0xF8, 0xBC, 0xAD, 0xDE, 0x64, 0xCA, 0xE4, /* 0x90-0x93 */ - 0xE0, 0xCE, 0xD4, 0xAF, 0xCF, 0xBD, 0xD5, 0xB7, /* 0x94-0x97 */ - 0xEA, 0xA4, 0xD5, 0xDE, 0xEA, 0xA5, 0xD0, 0xC1, /* 0x98-0x9B */ - 0xB9, 0xBC, 0xDE, 0x65, 0xB4, 0xC7, 0xB1, 0xD9, /* 0x9C-0x9F */ - 0xDE, 0x66, 0xDE, 0x67, 0xDE, 0x68, 0xC0, 0xB1, /* 0xA0-0xA3 */ - 0xDE, 0x69, 0xDE, 0x6A, 0xDE, 0x6B, 0xDE, 0x6C, /* 0xA4-0xA7 */ - 0xB1, 0xE6, 0xB1, 0xE7, 0xDE, 0x6D, 0xB1, 0xE8, /* 0xA8-0xAB */ - 0xDE, 0x6E, 0xDE, 0x6F, 0xDE, 0x70, 0xDE, 0x71, /* 0xAC-0xAF */ - 0xB3, 0xBD, 0xC8, 0xE8, 0xDE, 0x72, 0xDE, 0x73, /* 0xB0-0xB3 */ - 0xDE, 0x74, 0xDE, 0x75, 0xE5, 0xC1, 0xDE, 0x76, /* 0xB4-0xB7 */ - 0xDE, 0x77, 0xB1, 0xDF, 0xDE, 0x78, 0xDE, 0x79, /* 0xB8-0xBB */ - 0xDE, 0x7A, 0xC1, 0xC9, 0xB4, 0xEF, 0xDE, 0x7B, /* 0xBC-0xBF */ - 0xDE, 0x7C, 0xC7, 0xA8, 0xD3, 0xD8, 0xDE, 0x7D, /* 0xC0-0xC3 */ - 0xC6, 0xF9, 0xD1, 0xB8, 0xDE, 0x7E, 0xB9, 0xFD, /* 0xC4-0xC7 */ - 0xC2, 0xF5, 0xDE, 0x80, 0xDE, 0x81, 0xDE, 0x82, /* 0xC8-0xCB */ - 0xDE, 0x83, 0xDE, 0x84, 0xD3, 0xAD, 0xDE, 0x85, /* 0xCC-0xCF */ - 0xD4, 0xCB, 0xBD, 0xFC, 0xDE, 0x86, 0xE5, 0xC2, /* 0xD0-0xD3 */ - 0xB7, 0xB5, 0xE5, 0xC3, 0xDE, 0x87, 0xDE, 0x88, /* 0xD4-0xD7 */ - 0xBB, 0xB9, 0xD5, 0xE2, 0xDE, 0x89, 0xBD, 0xF8, /* 0xD8-0xDB */ - 0xD4, 0xB6, 0xCE, 0xA5, 0xC1, 0xAC, 0xB3, 0xD9, /* 0xDC-0xDF */ - 0xDE, 0x8A, 0xDE, 0x8B, 0xCC, 0xF6, 0xDE, 0x8C, /* 0xE0-0xE3 */ - 0xE5, 0xC6, 0xE5, 0xC4, 0xE5, 0xC8, 0xDE, 0x8D, /* 0xE4-0xE7 */ - 0xE5, 0xCA, 0xE5, 0xC7, 0xB5, 0xCF, 0xC6, 0xC8, /* 0xE8-0xEB */ - 0xDE, 0x8E, 0xB5, 0xFC, 0xE5, 0xC5, 0xDE, 0x8F, /* 0xEC-0xEF */ - 0xCA, 0xF6, 0xDE, 0x90, 0xDE, 0x91, 0xE5, 0xC9, /* 0xF0-0xF3 */ - 0xDE, 0x92, 0xDE, 0x93, 0xDE, 0x94, 0xC3, 0xD4, /* 0xF4-0xF7 */ - 0xB1, 0xC5, 0xBC, 0xA3, 0xDE, 0x95, 0xDE, 0x96, /* 0xF8-0xFB */ - 0xDE, 0x97, 0xD7, 0xB7, 0xDE, 0x98, 0xDE, 0x99, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_90[512] = { - 0xCD, 0xCB, 0xCB, 0xCD, 0xCA, 0xCA, 0xCC, 0xD3, /* 0x00-0x03 */ - 0xE5, 0xCC, 0xE5, 0xCB, 0xC4, 0xE6, 0xDE, 0x9A, /* 0x04-0x07 */ - 0xDE, 0x9B, 0xD1, 0xA1, 0xD1, 0xB7, 0xE5, 0xCD, /* 0x08-0x0B */ - 0xDE, 0x9C, 0xE5, 0xD0, 0xDE, 0x9D, 0xCD, 0xB8, /* 0x0C-0x0F */ - 0xD6, 0xF0, 0xE5, 0xCF, 0xB5, 0xDD, 0xDE, 0x9E, /* 0x10-0x13 */ - 0xCD, 0xBE, 0xDE, 0x9F, 0xE5, 0xD1, 0xB6, 0xBA, /* 0x14-0x17 */ - 0xDE, 0xA0, 0xDF, 0x40, 0xCD, 0xA8, 0xB9, 0xE4, /* 0x18-0x1B */ - 0xDF, 0x41, 0xCA, 0xC5, 0xB3, 0xD1, 0xCB, 0xD9, /* 0x1C-0x1F */ - 0xD4, 0xEC, 0xE5, 0xD2, 0xB7, 0xEA, 0xDF, 0x42, /* 0x20-0x23 */ - 0xDF, 0x43, 0xDF, 0x44, 0xE5, 0xCE, 0xDF, 0x45, /* 0x24-0x27 */ - 0xDF, 0x46, 0xDF, 0x47, 0xDF, 0x48, 0xDF, 0x49, /* 0x28-0x2B */ - 0xDF, 0x4A, 0xE5, 0xD5, 0xB4, 0xFE, 0xE5, 0xD6, /* 0x2C-0x2F */ - 0xDF, 0x4B, 0xDF, 0x4C, 0xDF, 0x4D, 0xDF, 0x4E, /* 0x30-0x33 */ - 0xDF, 0x4F, 0xE5, 0xD3, 0xE5, 0xD4, 0xDF, 0x50, /* 0x34-0x37 */ - 0xD2, 0xDD, 0xDF, 0x51, 0xDF, 0x52, 0xC2, 0xDF, /* 0x38-0x3B */ - 0xB1, 0xC6, 0xDF, 0x53, 0xD3, 0xE2, 0xDF, 0x54, /* 0x3C-0x3F */ - 0xDF, 0x55, 0xB6, 0xDD, 0xCB, 0xEC, 0xDF, 0x56, /* 0x40-0x43 */ - 0xE5, 0xD7, 0xDF, 0x57, 0xDF, 0x58, 0xD3, 0xF6, /* 0x44-0x47 */ - 0xDF, 0x59, 0xDF, 0x5A, 0xDF, 0x5B, 0xDF, 0x5C, /* 0x48-0x4B */ - 0xDF, 0x5D, 0xB1, 0xE9, 0xDF, 0x5E, 0xB6, 0xF4, /* 0x4C-0x4F */ - 0xE5, 0xDA, 0xE5, 0xD8, 0xE5, 0xD9, 0xB5, 0xC0, /* 0x50-0x53 */ - 0xDF, 0x5F, 0xDF, 0x60, 0xDF, 0x61, 0xD2, 0xC5, /* 0x54-0x57 */ - 0xE5, 0xDC, 0xDF, 0x62, 0xDF, 0x63, 0xE5, 0xDE, /* 0x58-0x5B */ - 0xDF, 0x64, 0xDF, 0x65, 0xDF, 0x66, 0xDF, 0x67, /* 0x5C-0x5F */ - 0xDF, 0x68, 0xDF, 0x69, 0xE5, 0xDD, 0xC7, 0xB2, /* 0x60-0x63 */ - 0xDF, 0x6A, 0xD2, 0xA3, 0xDF, 0x6B, 0xDF, 0x6C, /* 0x64-0x67 */ - 0xE5, 0xDB, 0xDF, 0x6D, 0xDF, 0x6E, 0xDF, 0x6F, /* 0x68-0x6B */ - 0xDF, 0x70, 0xD4, 0xE2, 0xD5, 0xDA, 0xDF, 0x71, /* 0x6C-0x6F */ - 0xDF, 0x72, 0xDF, 0x73, 0xDF, 0x74, 0xDF, 0x75, /* 0x70-0x73 */ - 0xE5, 0xE0, 0xD7, 0xF1, 0xDF, 0x76, 0xDF, 0x77, /* 0x74-0x77 */ - 0xDF, 0x78, 0xDF, 0x79, 0xDF, 0x7A, 0xDF, 0x7B, /* 0x78-0x7B */ - 0xDF, 0x7C, 0xE5, 0xE1, 0xDF, 0x7D, 0xB1, 0xDC, /* 0x7C-0x7F */ - - 0xD1, 0xFB, 0xDF, 0x7E, 0xE5, 0xE2, 0xE5, 0xE4, /* 0x80-0x83 */ - 0xDF, 0x80, 0xDF, 0x81, 0xDF, 0x82, 0xDF, 0x83, /* 0x84-0x87 */ - 0xE5, 0xE3, 0xDF, 0x84, 0xDF, 0x85, 0xE5, 0xE5, /* 0x88-0x8B */ - 0xDF, 0x86, 0xDF, 0x87, 0xDF, 0x88, 0xDF, 0x89, /* 0x8C-0x8F */ - 0xDF, 0x8A, 0xD2, 0xD8, 0xDF, 0x8B, 0xB5, 0xCB, /* 0x90-0x93 */ - 0xDF, 0x8C, 0xE7, 0xDF, 0xDF, 0x8D, 0xDA, 0xF5, /* 0x94-0x97 */ - 0xDF, 0x8E, 0xDA, 0xF8, 0xDF, 0x8F, 0xDA, 0xF6, /* 0x98-0x9B */ - 0xDF, 0x90, 0xDA, 0xF7, 0xDF, 0x91, 0xDF, 0x92, /* 0x9C-0x9F */ - 0xDF, 0x93, 0xDA, 0xFA, 0xD0, 0xCF, 0xC4, 0xC7, /* 0xA0-0xA3 */ - 0xDF, 0x94, 0xDF, 0x95, 0xB0, 0xEE, 0xDF, 0x96, /* 0xA4-0xA7 */ - 0xDF, 0x97, 0xDF, 0x98, 0xD0, 0xB0, 0xDF, 0x99, /* 0xA8-0xAB */ - 0xDA, 0xF9, 0xDF, 0x9A, 0xD3, 0xCA, 0xBA, 0xAA, /* 0xAC-0xAF */ - 0xDB, 0xA2, 0xC7, 0xF1, 0xDF, 0x9B, 0xDA, 0xFC, /* 0xB0-0xB3 */ - 0xDA, 0xFB, 0xC9, 0xDB, 0xDA, 0xFD, 0xDF, 0x9C, /* 0xB4-0xB7 */ - 0xDB, 0xA1, 0xD7, 0xDE, 0xDA, 0xFE, 0xC1, 0xDA, /* 0xB8-0xBB */ - 0xDF, 0x9D, 0xDF, 0x9E, 0xDB, 0xA5, 0xDF, 0x9F, /* 0xBC-0xBF */ - 0xDF, 0xA0, 0xD3, 0xF4, 0xE0, 0x40, 0xE0, 0x41, /* 0xC0-0xC3 */ - 0xDB, 0xA7, 0xDB, 0xA4, 0xE0, 0x42, 0xDB, 0xA8, /* 0xC4-0xC7 */ - 0xE0, 0x43, 0xE0, 0x44, 0xBD, 0xBC, 0xE0, 0x45, /* 0xC8-0xCB */ - 0xE0, 0x46, 0xE0, 0x47, 0xC0, 0xC9, 0xDB, 0xA3, /* 0xCC-0xCF */ - 0xDB, 0xA6, 0xD6, 0xA3, 0xE0, 0x48, 0xDB, 0xA9, /* 0xD0-0xD3 */ - 0xE0, 0x49, 0xE0, 0x4A, 0xE0, 0x4B, 0xDB, 0xAD, /* 0xD4-0xD7 */ - 0xE0, 0x4C, 0xE0, 0x4D, 0xE0, 0x4E, 0xDB, 0xAE, /* 0xD8-0xDB */ - 0xDB, 0xAC, 0xBA, 0xC2, 0xE0, 0x4F, 0xE0, 0x50, /* 0xDC-0xDF */ - 0xE0, 0x51, 0xBF, 0xA4, 0xDB, 0xAB, 0xE0, 0x52, /* 0xE0-0xE3 */ - 0xE0, 0x53, 0xE0, 0x54, 0xDB, 0xAA, 0xD4, 0xC7, /* 0xE4-0xE7 */ - 0xB2, 0xBF, 0xE0, 0x55, 0xE0, 0x56, 0xDB, 0xAF, /* 0xE8-0xEB */ - 0xE0, 0x57, 0xB9, 0xF9, 0xE0, 0x58, 0xDB, 0xB0, /* 0xEC-0xEF */ - 0xE0, 0x59, 0xE0, 0x5A, 0xE0, 0x5B, 0xE0, 0x5C, /* 0xF0-0xF3 */ - 0xB3, 0xBB, 0xE0, 0x5D, 0xE0, 0x5E, 0xE0, 0x5F, /* 0xF4-0xF7 */ - 0xB5, 0xA6, 0xE0, 0x60, 0xE0, 0x61, 0xE0, 0x62, /* 0xF8-0xFB */ - 0xE0, 0x63, 0xB6, 0xBC, 0xDB, 0xB1, 0xE0, 0x64, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_91[512] = { - 0xE0, 0x65, 0xE0, 0x66, 0xB6, 0xF5, 0xE0, 0x67, /* 0x00-0x03 */ - 0xDB, 0xB2, 0xE0, 0x68, 0xE0, 0x69, 0xE0, 0x6A, /* 0x04-0x07 */ - 0xE0, 0x6B, 0xE0, 0x6C, 0xE0, 0x6D, 0xE0, 0x6E, /* 0x08-0x0B */ - 0xE0, 0x6F, 0xE0, 0x70, 0xE0, 0x71, 0xE0, 0x72, /* 0x0C-0x0F */ - 0xE0, 0x73, 0xE0, 0x74, 0xE0, 0x75, 0xE0, 0x76, /* 0x10-0x13 */ - 0xE0, 0x77, 0xE0, 0x78, 0xE0, 0x79, 0xE0, 0x7A, /* 0x14-0x17 */ - 0xE0, 0x7B, 0xB1, 0xC9, 0xE0, 0x7C, 0xE0, 0x7D, /* 0x18-0x1B */ - 0xE0, 0x7E, 0xE0, 0x80, 0xDB, 0xB4, 0xE0, 0x81, /* 0x1C-0x1F */ - 0xE0, 0x82, 0xE0, 0x83, 0xDB, 0xB3, 0xDB, 0xB5, /* 0x20-0x23 */ - 0xE0, 0x84, 0xE0, 0x85, 0xE0, 0x86, 0xE0, 0x87, /* 0x24-0x27 */ - 0xE0, 0x88, 0xE0, 0x89, 0xE0, 0x8A, 0xE0, 0x8B, /* 0x28-0x2B */ - 0xE0, 0x8C, 0xE0, 0x8D, 0xE0, 0x8E, 0xDB, 0xB7, /* 0x2C-0x2F */ - 0xE0, 0x8F, 0xDB, 0xB6, 0xE0, 0x90, 0xE0, 0x91, /* 0x30-0x33 */ - 0xE0, 0x92, 0xE0, 0x93, 0xE0, 0x94, 0xE0, 0x95, /* 0x34-0x37 */ - 0xE0, 0x96, 0xDB, 0xB8, 0xE0, 0x97, 0xE0, 0x98, /* 0x38-0x3B */ - 0xE0, 0x99, 0xE0, 0x9A, 0xE0, 0x9B, 0xE0, 0x9C, /* 0x3C-0x3F */ - 0xE0, 0x9D, 0xE0, 0x9E, 0xE0, 0x9F, 0xDB, 0xB9, /* 0x40-0x43 */ - 0xE0, 0xA0, 0xE1, 0x40, 0xDB, 0xBA, 0xE1, 0x41, /* 0x44-0x47 */ - 0xE1, 0x42, 0xD3, 0xCF, 0xF4, 0xFA, 0xC7, 0xF5, /* 0x48-0x4B */ - 0xD7, 0xC3, 0xC5, 0xE4, 0xF4, 0xFC, 0xF4, 0xFD, /* 0x4C-0x4F */ - 0xF4, 0xFB, 0xE1, 0x43, 0xBE, 0xC6, 0xE1, 0x44, /* 0x50-0x53 */ - 0xE1, 0x45, 0xE1, 0x46, 0xE1, 0x47, 0xD0, 0xEF, /* 0x54-0x57 */ - 0xE1, 0x48, 0xE1, 0x49, 0xB7, 0xD3, 0xE1, 0x4A, /* 0x58-0x5B */ - 0xE1, 0x4B, 0xD4, 0xCD, 0xCC, 0xAA, 0xE1, 0x4C, /* 0x5C-0x5F */ - 0xE1, 0x4D, 0xF5, 0xA2, 0xF5, 0xA1, 0xBA, 0xA8, /* 0x60-0x63 */ - 0xF4, 0xFE, 0xCB, 0xD6, 0xE1, 0x4E, 0xE1, 0x4F, /* 0x64-0x67 */ - 0xE1, 0x50, 0xF5, 0xA4, 0xC0, 0xD2, 0xE1, 0x51, /* 0x68-0x6B */ - 0xB3, 0xEA, 0xE1, 0x52, 0xCD, 0xAA, 0xF5, 0xA5, /* 0x6C-0x6F */ - 0xF5, 0xA3, 0xBD, 0xB4, 0xF5, 0xA8, 0xE1, 0x53, /* 0x70-0x73 */ - 0xF5, 0xA9, 0xBD, 0xCD, 0xC3, 0xB8, 0xBF, 0xE1, /* 0x74-0x77 */ - 0xCB, 0xE1, 0xF5, 0xAA, 0xE1, 0x54, 0xE1, 0x55, /* 0x78-0x7B */ - 0xE1, 0x56, 0xF5, 0xA6, 0xF5, 0xA7, 0xC4, 0xF0, /* 0x7C-0x7F */ - - 0xE1, 0x57, 0xE1, 0x58, 0xE1, 0x59, 0xE1, 0x5A, /* 0x80-0x83 */ - 0xE1, 0x5B, 0xF5, 0xAC, 0xE1, 0x5C, 0xB4, 0xBC, /* 0x84-0x87 */ - 0xE1, 0x5D, 0xD7, 0xED, 0xE1, 0x5E, 0xB4, 0xD7, /* 0x88-0x8B */ - 0xF5, 0xAB, 0xF5, 0xAE, 0xE1, 0x5F, 0xE1, 0x60, /* 0x8C-0x8F */ - 0xF5, 0xAD, 0xF5, 0xAF, 0xD0, 0xD1, 0xE1, 0x61, /* 0x90-0x93 */ - 0xE1, 0x62, 0xE1, 0x63, 0xE1, 0x64, 0xE1, 0x65, /* 0x94-0x97 */ - 0xE1, 0x66, 0xE1, 0x67, 0xC3, 0xD1, 0xC8, 0xA9, /* 0x98-0x9B */ - 0xE1, 0x68, 0xE1, 0x69, 0xE1, 0x6A, 0xE1, 0x6B, /* 0x9C-0x9F */ - 0xE1, 0x6C, 0xE1, 0x6D, 0xF5, 0xB0, 0xF5, 0xB1, /* 0xA0-0xA3 */ - 0xE1, 0x6E, 0xE1, 0x6F, 0xE1, 0x70, 0xE1, 0x71, /* 0xA4-0xA7 */ - 0xE1, 0x72, 0xE1, 0x73, 0xF5, 0xB2, 0xE1, 0x74, /* 0xA8-0xAB */ - 0xE1, 0x75, 0xF5, 0xB3, 0xF5, 0xB4, 0xF5, 0xB5, /* 0xAC-0xAF */ - 0xE1, 0x76, 0xE1, 0x77, 0xE1, 0x78, 0xE1, 0x79, /* 0xB0-0xB3 */ - 0xF5, 0xB7, 0xF5, 0xB6, 0xE1, 0x7A, 0xE1, 0x7B, /* 0xB4-0xB7 */ - 0xE1, 0x7C, 0xE1, 0x7D, 0xF5, 0xB8, 0xE1, 0x7E, /* 0xB8-0xBB */ - 0xE1, 0x80, 0xE1, 0x81, 0xE1, 0x82, 0xE1, 0x83, /* 0xBC-0xBF */ - 0xE1, 0x84, 0xE1, 0x85, 0xE1, 0x86, 0xE1, 0x87, /* 0xC0-0xC3 */ - 0xE1, 0x88, 0xE1, 0x89, 0xE1, 0x8A, 0xB2, 0xC9, /* 0xC4-0xC7 */ - 0xE1, 0x8B, 0xD3, 0xD4, 0xCA, 0xCD, 0xE1, 0x8C, /* 0xC8-0xCB */ - 0xC0, 0xEF, 0xD6, 0xD8, 0xD2, 0xB0, 0xC1, 0xBF, /* 0xCC-0xCF */ - 0xE1, 0x8D, 0xBD, 0xF0, 0xE1, 0x8E, 0xE1, 0x8F, /* 0xD0-0xD3 */ - 0xE1, 0x90, 0xE1, 0x91, 0xE1, 0x92, 0xE1, 0x93, /* 0xD4-0xD7 */ - 0xE1, 0x94, 0xE1, 0x95, 0xE1, 0x96, 0xE1, 0x97, /* 0xD8-0xDB */ - 0xB8, 0xAA, 0xE1, 0x98, 0xE1, 0x99, 0xE1, 0x9A, /* 0xDC-0xDF */ - 0xE1, 0x9B, 0xE1, 0x9C, 0xE1, 0x9D, 0xE1, 0x9E, /* 0xE0-0xE3 */ - 0xE1, 0x9F, 0xE1, 0xA0, 0xE2, 0x40, 0xE2, 0x41, /* 0xE4-0xE7 */ - 0xE2, 0x42, 0xE2, 0x43, 0xE2, 0x44, 0xE2, 0x45, /* 0xE8-0xEB */ - 0xE2, 0x46, 0xE2, 0x47, 0xE2, 0x48, 0xE2, 0x49, /* 0xEC-0xEF */ - 0xE2, 0x4A, 0xE2, 0x4B, 0xE2, 0x4C, 0xE2, 0x4D, /* 0xF0-0xF3 */ - 0xE2, 0x4E, 0xE2, 0x4F, 0xE2, 0x50, 0xE2, 0x51, /* 0xF4-0xF7 */ - 0xE2, 0x52, 0xE2, 0x53, 0xE2, 0x54, 0xE2, 0x55, /* 0xF8-0xFB */ - 0xE2, 0x56, 0xE2, 0x57, 0xE2, 0x58, 0xE2, 0x59, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_92[512] = { - 0xE2, 0x5A, 0xE2, 0x5B, 0xE2, 0x5C, 0xE2, 0x5D, /* 0x00-0x03 */ - 0xE2, 0x5E, 0xE2, 0x5F, 0xE2, 0x60, 0xE2, 0x61, /* 0x04-0x07 */ - 0xE2, 0x62, 0xE2, 0x63, 0xE2, 0x64, 0xE2, 0x65, /* 0x08-0x0B */ - 0xE2, 0x66, 0xE2, 0x67, 0xE2, 0x68, 0xE2, 0x69, /* 0x0C-0x0F */ - 0xE2, 0x6A, 0xE2, 0x6B, 0xE2, 0x6C, 0xE2, 0x6D, /* 0x10-0x13 */ - 0xE2, 0x6E, 0xE2, 0x6F, 0xE2, 0x70, 0xE2, 0x71, /* 0x14-0x17 */ - 0xE2, 0x72, 0xE2, 0x73, 0xE2, 0x74, 0xE2, 0x75, /* 0x18-0x1B */ - 0xE2, 0x76, 0xE2, 0x77, 0xE2, 0x78, 0xE2, 0x79, /* 0x1C-0x1F */ - 0xE2, 0x7A, 0xE2, 0x7B, 0xE2, 0x7C, 0xE2, 0x7D, /* 0x20-0x23 */ - 0xE2, 0x7E, 0xE2, 0x80, 0xE2, 0x81, 0xE2, 0x82, /* 0x24-0x27 */ - 0xE2, 0x83, 0xE2, 0x84, 0xE2, 0x85, 0xE2, 0x86, /* 0x28-0x2B */ - 0xE2, 0x87, 0xE2, 0x88, 0xE2, 0x89, 0xE2, 0x8A, /* 0x2C-0x2F */ - 0xE2, 0x8B, 0xE2, 0x8C, 0xE2, 0x8D, 0xE2, 0x8E, /* 0x30-0x33 */ - 0xE2, 0x8F, 0xE2, 0x90, 0xE2, 0x91, 0xE2, 0x92, /* 0x34-0x37 */ - 0xE2, 0x93, 0xE2, 0x94, 0xE2, 0x95, 0xE2, 0x96, /* 0x38-0x3B */ - 0xE2, 0x97, 0xE2, 0x98, 0xE2, 0x99, 0xE2, 0x9A, /* 0x3C-0x3F */ - 0xE2, 0x9B, 0xE2, 0x9C, 0xE2, 0x9D, 0xE2, 0x9E, /* 0x40-0x43 */ - 0xE2, 0x9F, 0xE2, 0xA0, 0xE3, 0x40, 0xE3, 0x41, /* 0x44-0x47 */ - 0xE3, 0x42, 0xE3, 0x43, 0xE3, 0x44, 0xE3, 0x45, /* 0x48-0x4B */ - 0xE3, 0x46, 0xE3, 0x47, 0xE3, 0x48, 0xE3, 0x49, /* 0x4C-0x4F */ - 0xE3, 0x4A, 0xE3, 0x4B, 0xE3, 0x4C, 0xE3, 0x4D, /* 0x50-0x53 */ - 0xE3, 0x4E, 0xE3, 0x4F, 0xE3, 0x50, 0xE3, 0x51, /* 0x54-0x57 */ - 0xE3, 0x52, 0xE3, 0x53, 0xE3, 0x54, 0xE3, 0x55, /* 0x58-0x5B */ - 0xE3, 0x56, 0xE3, 0x57, 0xE3, 0x58, 0xE3, 0x59, /* 0x5C-0x5F */ - 0xE3, 0x5A, 0xE3, 0x5B, 0xE3, 0x5C, 0xE3, 0x5D, /* 0x60-0x63 */ - 0xE3, 0x5E, 0xE3, 0x5F, 0xE3, 0x60, 0xE3, 0x61, /* 0x64-0x67 */ - 0xE3, 0x62, 0xE3, 0x63, 0xE3, 0x64, 0xE3, 0x65, /* 0x68-0x6B */ - 0xE3, 0x66, 0xE3, 0x67, 0xE3, 0x68, 0xE3, 0x69, /* 0x6C-0x6F */ - 0xE3, 0x6A, 0xE3, 0x6B, 0xE3, 0x6C, 0xE3, 0x6D, /* 0x70-0x73 */ - 0xBC, 0xF8, 0xE3, 0x6E, 0xE3, 0x6F, 0xE3, 0x70, /* 0x74-0x77 */ - 0xE3, 0x71, 0xE3, 0x72, 0xE3, 0x73, 0xE3, 0x74, /* 0x78-0x7B */ - 0xE3, 0x75, 0xE3, 0x76, 0xE3, 0x77, 0xE3, 0x78, /* 0x7C-0x7F */ - - 0xE3, 0x79, 0xE3, 0x7A, 0xE3, 0x7B, 0xE3, 0x7C, /* 0x80-0x83 */ - 0xE3, 0x7D, 0xE3, 0x7E, 0xE3, 0x80, 0xE3, 0x81, /* 0x84-0x87 */ - 0xE3, 0x82, 0xE3, 0x83, 0xE3, 0x84, 0xE3, 0x85, /* 0x88-0x8B */ - 0xE3, 0x86, 0xE3, 0x87, 0xF6, 0xC6, 0xE3, 0x88, /* 0x8C-0x8F */ - 0xE3, 0x89, 0xE3, 0x8A, 0xE3, 0x8B, 0xE3, 0x8C, /* 0x90-0x93 */ - 0xE3, 0x8D, 0xE3, 0x8E, 0xE3, 0x8F, 0xE3, 0x90, /* 0x94-0x97 */ - 0xE3, 0x91, 0xE3, 0x92, 0xE3, 0x93, 0xE3, 0x94, /* 0x98-0x9B */ - 0xE3, 0x95, 0xE3, 0x96, 0xE3, 0x97, 0xE3, 0x98, /* 0x9C-0x9F */ - 0xE3, 0x99, 0xE3, 0x9A, 0xE3, 0x9B, 0xE3, 0x9C, /* 0xA0-0xA3 */ - 0xE3, 0x9D, 0xE3, 0x9E, 0xE3, 0x9F, 0xE3, 0xA0, /* 0xA4-0xA7 */ - 0xE4, 0x40, 0xE4, 0x41, 0xE4, 0x42, 0xE4, 0x43, /* 0xA8-0xAB */ - 0xE4, 0x44, 0xE4, 0x45, 0xF6, 0xC7, 0xE4, 0x46, /* 0xAC-0xAF */ - 0xE4, 0x47, 0xE4, 0x48, 0xE4, 0x49, 0xE4, 0x4A, /* 0xB0-0xB3 */ - 0xE4, 0x4B, 0xE4, 0x4C, 0xE4, 0x4D, 0xE4, 0x4E, /* 0xB4-0xB7 */ - 0xE4, 0x4F, 0xE4, 0x50, 0xE4, 0x51, 0xE4, 0x52, /* 0xB8-0xBB */ - 0xE4, 0x53, 0xE4, 0x54, 0xE4, 0x55, 0xE4, 0x56, /* 0xBC-0xBF */ - 0xE4, 0x57, 0xE4, 0x58, 0xE4, 0x59, 0xE4, 0x5A, /* 0xC0-0xC3 */ - 0xE4, 0x5B, 0xE4, 0x5C, 0xE4, 0x5D, 0xE4, 0x5E, /* 0xC4-0xC7 */ - 0xF6, 0xC8, 0xE4, 0x5F, 0xE4, 0x60, 0xE4, 0x61, /* 0xC8-0xCB */ - 0xE4, 0x62, 0xE4, 0x63, 0xE4, 0x64, 0xE4, 0x65, /* 0xCC-0xCF */ - 0xE4, 0x66, 0xE4, 0x67, 0xE4, 0x68, 0xE4, 0x69, /* 0xD0-0xD3 */ - 0xE4, 0x6A, 0xE4, 0x6B, 0xE4, 0x6C, 0xE4, 0x6D, /* 0xD4-0xD7 */ - 0xE4, 0x6E, 0xE4, 0x6F, 0xE4, 0x70, 0xE4, 0x71, /* 0xD8-0xDB */ - 0xE4, 0x72, 0xE4, 0x73, 0xE4, 0x74, 0xE4, 0x75, /* 0xDC-0xDF */ - 0xE4, 0x76, 0xE4, 0x77, 0xE4, 0x78, 0xE4, 0x79, /* 0xE0-0xE3 */ - 0xE4, 0x7A, 0xE4, 0x7B, 0xE4, 0x7C, 0xE4, 0x7D, /* 0xE4-0xE7 */ - 0xE4, 0x7E, 0xE4, 0x80, 0xE4, 0x81, 0xE4, 0x82, /* 0xE8-0xEB */ - 0xE4, 0x83, 0xE4, 0x84, 0xE4, 0x85, 0xE4, 0x86, /* 0xEC-0xEF */ - 0xE4, 0x87, 0xE4, 0x88, 0xE4, 0x89, 0xE4, 0x8A, /* 0xF0-0xF3 */ - 0xE4, 0x8B, 0xE4, 0x8C, 0xE4, 0x8D, 0xE4, 0x8E, /* 0xF4-0xF7 */ - 0xE4, 0x8F, 0xE4, 0x90, 0xE4, 0x91, 0xE4, 0x92, /* 0xF8-0xFB */ - 0xE4, 0x93, 0xE4, 0x94, 0xE4, 0x95, 0xE4, 0x96, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_93[512] = { - 0xE4, 0x97, 0xE4, 0x98, 0xE4, 0x99, 0xE4, 0x9A, /* 0x00-0x03 */ - 0xE4, 0x9B, 0xE4, 0x9C, 0xE4, 0x9D, 0xE4, 0x9E, /* 0x04-0x07 */ - 0xE4, 0x9F, 0xE4, 0xA0, 0xE5, 0x40, 0xE5, 0x41, /* 0x08-0x0B */ - 0xE5, 0x42, 0xE5, 0x43, 0xE5, 0x44, 0xE5, 0x45, /* 0x0C-0x0F */ - 0xE5, 0x46, 0xE5, 0x47, 0xE5, 0x48, 0xE5, 0x49, /* 0x10-0x13 */ - 0xE5, 0x4A, 0xE5, 0x4B, 0xE5, 0x4C, 0xE5, 0x4D, /* 0x14-0x17 */ - 0xE5, 0x4E, 0xE5, 0x4F, 0xE5, 0x50, 0xE5, 0x51, /* 0x18-0x1B */ - 0xE5, 0x52, 0xE5, 0x53, 0xE5, 0x54, 0xE5, 0x55, /* 0x1C-0x1F */ - 0xE5, 0x56, 0xE5, 0x57, 0xE5, 0x58, 0xE5, 0x59, /* 0x20-0x23 */ - 0xE5, 0x5A, 0xE5, 0x5B, 0xE5, 0x5C, 0xE5, 0x5D, /* 0x24-0x27 */ - 0xE5, 0x5E, 0xE5, 0x5F, 0xE5, 0x60, 0xE5, 0x61, /* 0x28-0x2B */ - 0xE5, 0x62, 0xE5, 0x63, 0xE5, 0x64, 0xE5, 0x65, /* 0x2C-0x2F */ - 0xE5, 0x66, 0xE5, 0x67, 0xE5, 0x68, 0xE5, 0x69, /* 0x30-0x33 */ - 0xE5, 0x6A, 0xE5, 0x6B, 0xE5, 0x6C, 0xE5, 0x6D, /* 0x34-0x37 */ - 0xE5, 0x6E, 0xE5, 0x6F, 0xE5, 0x70, 0xE5, 0x71, /* 0x38-0x3B */ - 0xE5, 0x72, 0xE5, 0x73, 0xF6, 0xC9, 0xE5, 0x74, /* 0x3C-0x3F */ - 0xE5, 0x75, 0xE5, 0x76, 0xE5, 0x77, 0xE5, 0x78, /* 0x40-0x43 */ - 0xE5, 0x79, 0xE5, 0x7A, 0xE5, 0x7B, 0xE5, 0x7C, /* 0x44-0x47 */ - 0xE5, 0x7D, 0xE5, 0x7E, 0xE5, 0x80, 0xE5, 0x81, /* 0x48-0x4B */ - 0xE5, 0x82, 0xE5, 0x83, 0xE5, 0x84, 0xE5, 0x85, /* 0x4C-0x4F */ - 0xE5, 0x86, 0xE5, 0x87, 0xE5, 0x88, 0xE5, 0x89, /* 0x50-0x53 */ - 0xE5, 0x8A, 0xE5, 0x8B, 0xE5, 0x8C, 0xE5, 0x8D, /* 0x54-0x57 */ - 0xE5, 0x8E, 0xE5, 0x8F, 0xE5, 0x90, 0xE5, 0x91, /* 0x58-0x5B */ - 0xE5, 0x92, 0xE5, 0x93, 0xE5, 0x94, 0xE5, 0x95, /* 0x5C-0x5F */ - 0xE5, 0x96, 0xE5, 0x97, 0xE5, 0x98, 0xE5, 0x99, /* 0x60-0x63 */ - 0xE5, 0x9A, 0xE5, 0x9B, 0xE5, 0x9C, 0xE5, 0x9D, /* 0x64-0x67 */ - 0xE5, 0x9E, 0xE5, 0x9F, 0xF6, 0xCA, 0xE5, 0xA0, /* 0x68-0x6B */ - 0xE6, 0x40, 0xE6, 0x41, 0xE6, 0x42, 0xE6, 0x43, /* 0x6C-0x6F */ - 0xE6, 0x44, 0xE6, 0x45, 0xE6, 0x46, 0xE6, 0x47, /* 0x70-0x73 */ - 0xE6, 0x48, 0xE6, 0x49, 0xE6, 0x4A, 0xE6, 0x4B, /* 0x74-0x77 */ - 0xE6, 0x4C, 0xE6, 0x4D, 0xE6, 0x4E, 0xE6, 0x4F, /* 0x78-0x7B */ - 0xE6, 0x50, 0xE6, 0x51, 0xE6, 0x52, 0xE6, 0x53, /* 0x7C-0x7F */ - - 0xE6, 0x54, 0xE6, 0x55, 0xE6, 0x56, 0xE6, 0x57, /* 0x80-0x83 */ - 0xE6, 0x58, 0xE6, 0x59, 0xE6, 0x5A, 0xE6, 0x5B, /* 0x84-0x87 */ - 0xE6, 0x5C, 0xE6, 0x5D, 0xE6, 0x5E, 0xE6, 0x5F, /* 0x88-0x8B */ - 0xE6, 0x60, 0xE6, 0x61, 0xE6, 0x62, 0xF6, 0xCC, /* 0x8C-0x8F */ - 0xE6, 0x63, 0xE6, 0x64, 0xE6, 0x65, 0xE6, 0x66, /* 0x90-0x93 */ - 0xE6, 0x67, 0xE6, 0x68, 0xE6, 0x69, 0xE6, 0x6A, /* 0x94-0x97 */ - 0xE6, 0x6B, 0xE6, 0x6C, 0xE6, 0x6D, 0xE6, 0x6E, /* 0x98-0x9B */ - 0xE6, 0x6F, 0xE6, 0x70, 0xE6, 0x71, 0xE6, 0x72, /* 0x9C-0x9F */ - 0xE6, 0x73, 0xE6, 0x74, 0xE6, 0x75, 0xE6, 0x76, /* 0xA0-0xA3 */ - 0xE6, 0x77, 0xE6, 0x78, 0xE6, 0x79, 0xE6, 0x7A, /* 0xA4-0xA7 */ - 0xE6, 0x7B, 0xE6, 0x7C, 0xE6, 0x7D, 0xE6, 0x7E, /* 0xA8-0xAB */ - 0xE6, 0x80, 0xE6, 0x81, 0xE6, 0x82, 0xE6, 0x83, /* 0xAC-0xAF */ - 0xE6, 0x84, 0xE6, 0x85, 0xE6, 0x86, 0xE6, 0x87, /* 0xB0-0xB3 */ - 0xE6, 0x88, 0xE6, 0x89, 0xE6, 0x8A, 0xE6, 0x8B, /* 0xB4-0xB7 */ - 0xE6, 0x8C, 0xE6, 0x8D, 0xE6, 0x8E, 0xE6, 0x8F, /* 0xB8-0xBB */ - 0xE6, 0x90, 0xE6, 0x91, 0xE6, 0x92, 0xE6, 0x93, /* 0xBC-0xBF */ - 0xE6, 0x94, 0xE6, 0x95, 0xE6, 0x96, 0xE6, 0x97, /* 0xC0-0xC3 */ - 0xE6, 0x98, 0xE6, 0x99, 0xE6, 0x9A, 0xE6, 0x9B, /* 0xC4-0xC7 */ - 0xE6, 0x9C, 0xE6, 0x9D, 0xF6, 0xCB, 0xE6, 0x9E, /* 0xC8-0xCB */ - 0xE6, 0x9F, 0xE6, 0xA0, 0xE7, 0x40, 0xE7, 0x41, /* 0xCC-0xCF */ - 0xE7, 0x42, 0xE7, 0x43, 0xE7, 0x44, 0xE7, 0x45, /* 0xD0-0xD3 */ - 0xE7, 0x46, 0xE7, 0x47, 0xF7, 0xE9, 0xE7, 0x48, /* 0xD4-0xD7 */ - 0xE7, 0x49, 0xE7, 0x4A, 0xE7, 0x4B, 0xE7, 0x4C, /* 0xD8-0xDB */ - 0xE7, 0x4D, 0xE7, 0x4E, 0xE7, 0x4F, 0xE7, 0x50, /* 0xDC-0xDF */ - 0xE7, 0x51, 0xE7, 0x52, 0xE7, 0x53, 0xE7, 0x54, /* 0xE0-0xE3 */ - 0xE7, 0x55, 0xE7, 0x56, 0xE7, 0x57, 0xE7, 0x58, /* 0xE4-0xE7 */ - 0xE7, 0x59, 0xE7, 0x5A, 0xE7, 0x5B, 0xE7, 0x5C, /* 0xE8-0xEB */ - 0xE7, 0x5D, 0xE7, 0x5E, 0xE7, 0x5F, 0xE7, 0x60, /* 0xEC-0xEF */ - 0xE7, 0x61, 0xE7, 0x62, 0xE7, 0x63, 0xE7, 0x64, /* 0xF0-0xF3 */ - 0xE7, 0x65, 0xE7, 0x66, 0xE7, 0x67, 0xE7, 0x68, /* 0xF4-0xF7 */ - 0xE7, 0x69, 0xE7, 0x6A, 0xE7, 0x6B, 0xE7, 0x6C, /* 0xF8-0xFB */ - 0xE7, 0x6D, 0xE7, 0x6E, 0xE7, 0x6F, 0xE7, 0x70, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_94[512] = { - 0xE7, 0x71, 0xE7, 0x72, 0xE7, 0x73, 0xE7, 0x74, /* 0x00-0x03 */ - 0xE7, 0x75, 0xE7, 0x76, 0xE7, 0x77, 0xE7, 0x78, /* 0x04-0x07 */ - 0xE7, 0x79, 0xE7, 0x7A, 0xE7, 0x7B, 0xE7, 0x7C, /* 0x08-0x0B */ - 0xE7, 0x7D, 0xE7, 0x7E, 0xE7, 0x80, 0xE7, 0x81, /* 0x0C-0x0F */ - 0xE7, 0x82, 0xE7, 0x83, 0xE7, 0x84, 0xE7, 0x85, /* 0x10-0x13 */ - 0xE7, 0x86, 0xE7, 0x87, 0xE7, 0x88, 0xE7, 0x89, /* 0x14-0x17 */ - 0xE7, 0x8A, 0xE7, 0x8B, 0xE7, 0x8C, 0xE7, 0x8D, /* 0x18-0x1B */ - 0xE7, 0x8E, 0xE7, 0x8F, 0xE7, 0x90, 0xE7, 0x91, /* 0x1C-0x1F */ - 0xE7, 0x92, 0xE7, 0x93, 0xE7, 0x94, 0xE7, 0x95, /* 0x20-0x23 */ - 0xE7, 0x96, 0xE7, 0x97, 0xE7, 0x98, 0xE7, 0x99, /* 0x24-0x27 */ - 0xE7, 0x9A, 0xE7, 0x9B, 0xE7, 0x9C, 0xE7, 0x9D, /* 0x28-0x2B */ - 0xE7, 0x9E, 0xE7, 0x9F, 0xE7, 0xA0, 0xE8, 0x40, /* 0x2C-0x2F */ - 0xE8, 0x41, 0xE8, 0x42, 0xE8, 0x43, 0xE8, 0x44, /* 0x30-0x33 */ - 0xE8, 0x45, 0xE8, 0x46, 0xE8, 0x47, 0xE8, 0x48, /* 0x34-0x37 */ - 0xE8, 0x49, 0xE8, 0x4A, 0xE8, 0x4B, 0xE8, 0x4C, /* 0x38-0x3B */ - 0xE8, 0x4D, 0xE8, 0x4E, 0xF6, 0xCD, 0xE8, 0x4F, /* 0x3C-0x3F */ - 0xE8, 0x50, 0xE8, 0x51, 0xE8, 0x52, 0xE8, 0x53, /* 0x40-0x43 */ - 0xE8, 0x54, 0xE8, 0x55, 0xE8, 0x56, 0xE8, 0x57, /* 0x44-0x47 */ - 0xE8, 0x58, 0xE8, 0x59, 0xE8, 0x5A, 0xE8, 0x5B, /* 0x48-0x4B */ - 0xE8, 0x5C, 0xE8, 0x5D, 0xE8, 0x5E, 0xE8, 0x5F, /* 0x4C-0x4F */ - 0xE8, 0x60, 0xE8, 0x61, 0xE8, 0x62, 0xE8, 0x63, /* 0x50-0x53 */ - 0xE8, 0x64, 0xE8, 0x65, 0xE8, 0x66, 0xE8, 0x67, /* 0x54-0x57 */ - 0xE8, 0x68, 0xE8, 0x69, 0xE8, 0x6A, 0xE8, 0x6B, /* 0x58-0x5B */ - 0xE8, 0x6C, 0xE8, 0x6D, 0xE8, 0x6E, 0xE8, 0x6F, /* 0x5C-0x5F */ - 0xE8, 0x70, 0xE8, 0x71, 0xE8, 0x72, 0xE8, 0x73, /* 0x60-0x63 */ - 0xE8, 0x74, 0xE8, 0x75, 0xE8, 0x76, 0xE8, 0x77, /* 0x64-0x67 */ - 0xE8, 0x78, 0xE8, 0x79, 0xE8, 0x7A, 0xF6, 0xCE, /* 0x68-0x6B */ - 0xE8, 0x7B, 0xE8, 0x7C, 0xE8, 0x7D, 0xE8, 0x7E, /* 0x6C-0x6F */ - 0xE8, 0x80, 0xE8, 0x81, 0xE8, 0x82, 0xE8, 0x83, /* 0x70-0x73 */ - 0xE8, 0x84, 0xE8, 0x85, 0xE8, 0x86, 0xE8, 0x87, /* 0x74-0x77 */ - 0xE8, 0x88, 0xE8, 0x89, 0xE8, 0x8A, 0xE8, 0x8B, /* 0x78-0x7B */ - 0xE8, 0x8C, 0xE8, 0x8D, 0xE8, 0x8E, 0xE8, 0x8F, /* 0x7C-0x7F */ - - 0xE8, 0x90, 0xE8, 0x91, 0xE8, 0x92, 0xE8, 0x93, /* 0x80-0x83 */ - 0xE8, 0x94, 0xEE, 0xC4, 0xEE, 0xC5, 0xEE, 0xC6, /* 0x84-0x87 */ - 0xD5, 0xEB, 0xB6, 0xA4, 0xEE, 0xC8, 0xEE, 0xC7, /* 0x88-0x8B */ - 0xEE, 0xC9, 0xEE, 0xCA, 0xC7, 0xA5, 0xEE, 0xCB, /* 0x8C-0x8F */ - 0xEE, 0xCC, 0xE8, 0x95, 0xB7, 0xB0, 0xB5, 0xF6, /* 0x90-0x93 */ - 0xEE, 0xCD, 0xEE, 0xCF, 0xE8, 0x96, 0xEE, 0xCE, /* 0x94-0x97 */ - 0xE8, 0x97, 0xB8, 0xC6, 0xEE, 0xD0, 0xEE, 0xD1, /* 0x98-0x9B */ - 0xEE, 0xD2, 0xB6, 0xDB, 0xB3, 0xAE, 0xD6, 0xD3, /* 0x9C-0x9F */ - 0xC4, 0xC6, 0xB1, 0xB5, 0xB8, 0xD6, 0xEE, 0xD3, /* 0xA0-0xA3 */ - 0xEE, 0xD4, 0xD4, 0xBF, 0xC7, 0xD5, 0xBE, 0xFB, /* 0xA4-0xA7 */ - 0xCE, 0xD9, 0xB9, 0xB3, 0xEE, 0xD6, 0xEE, 0xD5, /* 0xA8-0xAB */ - 0xEE, 0xD8, 0xEE, 0xD7, 0xC5, 0xA5, 0xEE, 0xD9, /* 0xAC-0xAF */ - 0xEE, 0xDA, 0xC7, 0xAE, 0xEE, 0xDB, 0xC7, 0xAF, /* 0xB0-0xB3 */ - 0xEE, 0xDC, 0xB2, 0xA7, 0xEE, 0xDD, 0xEE, 0xDE, /* 0xB4-0xB7 */ - 0xEE, 0xDF, 0xEE, 0xE0, 0xEE, 0xE1, 0xD7, 0xEA, /* 0xB8-0xBB */ - 0xEE, 0xE2, 0xEE, 0xE3, 0xBC, 0xD8, 0xEE, 0xE4, /* 0xBC-0xBF */ - 0xD3, 0xCB, 0xCC, 0xFA, 0xB2, 0xAC, 0xC1, 0xE5, /* 0xC0-0xC3 */ - 0xEE, 0xE5, 0xC7, 0xA6, 0xC3, 0xAD, 0xE8, 0x98, /* 0xC4-0xC7 */ - 0xEE, 0xE6, 0xEE, 0xE7, 0xEE, 0xE8, 0xEE, 0xE9, /* 0xC8-0xCB */ - 0xEE, 0xEA, 0xEE, 0xEB, 0xEE, 0xEC, 0xE8, 0x99, /* 0xCC-0xCF */ - 0xEE, 0xED, 0xEE, 0xEE, 0xEE, 0xEF, 0xE8, 0x9A, /* 0xD0-0xD3 */ - 0xE8, 0x9B, 0xEE, 0xF0, 0xEE, 0xF1, 0xEE, 0xF2, /* 0xD4-0xD7 */ - 0xEE, 0xF4, 0xEE, 0xF3, 0xE8, 0x9C, 0xEE, 0xF5, /* 0xD8-0xDB */ - 0xCD, 0xAD, 0xC2, 0xC1, 0xEE, 0xF6, 0xEE, 0xF7, /* 0xDC-0xDF */ - 0xEE, 0xF8, 0xD5, 0xA1, 0xEE, 0xF9, 0xCF, 0xB3, /* 0xE0-0xE3 */ - 0xEE, 0xFA, 0xEE, 0xFB, 0xE8, 0x9D, 0xEE, 0xFC, /* 0xE4-0xE7 */ - 0xEE, 0xFD, 0xEF, 0xA1, 0xEE, 0xFE, 0xEF, 0xA2, /* 0xE8-0xEB */ - 0xB8, 0xF5, 0xC3, 0xFA, 0xEF, 0xA3, 0xEF, 0xA4, /* 0xEC-0xEF */ - 0xBD, 0xC2, 0xD2, 0xBF, 0xB2, 0xF9, 0xEF, 0xA5, /* 0xF0-0xF3 */ - 0xEF, 0xA6, 0xEF, 0xA7, 0xD2, 0xF8, 0xEF, 0xA8, /* 0xF4-0xF7 */ - 0xD6, 0xFD, 0xEF, 0xA9, 0xC6, 0xCC, 0xE8, 0x9E, /* 0xF8-0xFB */ - 0xEF, 0xAA, 0xEF, 0xAB, 0xC1, 0xB4, 0xEF, 0xAC, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_95[512] = { - 0xCF, 0xFA, 0xCB, 0xF8, 0xEF, 0xAE, 0xEF, 0xAD, /* 0x00-0x03 */ - 0xB3, 0xFA, 0xB9, 0xF8, 0xEF, 0xAF, 0xEF, 0xB0, /* 0x04-0x07 */ - 0xD0, 0xE2, 0xEF, 0xB1, 0xEF, 0xB2, 0xB7, 0xE6, /* 0x08-0x0B */ - 0xD0, 0xBF, 0xEF, 0xB3, 0xEF, 0xB4, 0xEF, 0xB5, /* 0x0C-0x0F */ - 0xC8, 0xF1, 0xCC, 0xE0, 0xEF, 0xB6, 0xEF, 0xB7, /* 0x10-0x13 */ - 0xEF, 0xB8, 0xEF, 0xB9, 0xEF, 0xBA, 0xD5, 0xE0, /* 0x14-0x17 */ - 0xEF, 0xBB, 0xB4, 0xED, 0xC3, 0xAA, 0xEF, 0xBC, /* 0x18-0x1B */ - 0xE8, 0x9F, 0xEF, 0xBD, 0xEF, 0xBE, 0xEF, 0xBF, /* 0x1C-0x1F */ - 0xE8, 0xA0, 0xCE, 0xFD, 0xEF, 0xC0, 0xC2, 0xE0, /* 0x20-0x23 */ - 0xB4, 0xB8, 0xD7, 0xB6, 0xBD, 0xF5, 0xE9, 0x40, /* 0x24-0x27 */ - 0xCF, 0xC7, 0xEF, 0xC3, 0xEF, 0xC1, 0xEF, 0xC2, /* 0x28-0x2B */ - 0xEF, 0xC4, 0xB6, 0xA7, 0xBC, 0xFC, 0xBE, 0xE2, /* 0x2C-0x2F */ - 0xC3, 0xCC, 0xEF, 0xC5, 0xEF, 0xC6, 0xE9, 0x41, /* 0x30-0x33 */ - 0xEF, 0xC7, 0xEF, 0xCF, 0xEF, 0xC8, 0xEF, 0xC9, /* 0x34-0x37 */ - 0xEF, 0xCA, 0xC7, 0xC2, 0xEF, 0xF1, 0xB6, 0xCD, /* 0x38-0x3B */ - 0xEF, 0xCB, 0xE9, 0x42, 0xEF, 0xCC, 0xEF, 0xCD, /* 0x3C-0x3F */ - 0xB6, 0xC6, 0xC3, 0xBE, 0xEF, 0xCE, 0xE9, 0x43, /* 0x40-0x43 */ - 0xEF, 0xD0, 0xEF, 0xD1, 0xEF, 0xD2, 0xD5, 0xF2, /* 0x44-0x47 */ - 0xE9, 0x44, 0xEF, 0xD3, 0xC4, 0xF7, 0xE9, 0x45, /* 0x48-0x4B */ - 0xEF, 0xD4, 0xC4, 0xF8, 0xEF, 0xD5, 0xEF, 0xD6, /* 0x4C-0x4F */ - 0xB8, 0xE4, 0xB0, 0xF7, 0xEF, 0xD7, 0xEF, 0xD8, /* 0x50-0x53 */ - 0xEF, 0xD9, 0xE9, 0x46, 0xEF, 0xDA, 0xEF, 0xDB, /* 0x54-0x57 */ - 0xEF, 0xDC, 0xEF, 0xDD, 0xE9, 0x47, 0xEF, 0xDE, /* 0x58-0x5B */ - 0xBE, 0xB5, 0xEF, 0xE1, 0xEF, 0xDF, 0xEF, 0xE0, /* 0x5C-0x5F */ - 0xE9, 0x48, 0xEF, 0xE2, 0xEF, 0xE3, 0xC1, 0xCD, /* 0x60-0x63 */ - 0xEF, 0xE4, 0xEF, 0xE5, 0xEF, 0xE6, 0xEF, 0xE7, /* 0x64-0x67 */ - 0xEF, 0xE8, 0xEF, 0xE9, 0xEF, 0xEA, 0xEF, 0xEB, /* 0x68-0x6B */ - 0xEF, 0xEC, 0xC0, 0xD8, 0xE9, 0x49, 0xEF, 0xED, /* 0x6C-0x6F */ - 0xC1, 0xAD, 0xEF, 0xEE, 0xEF, 0xEF, 0xEF, 0xF0, /* 0x70-0x73 */ - 0xE9, 0x4A, 0xE9, 0x4B, 0xCF, 0xE2, 0xE9, 0x4C, /* 0x74-0x77 */ - 0xE9, 0x4D, 0xE9, 0x4E, 0xE9, 0x4F, 0xE9, 0x50, /* 0x78-0x7B */ - 0xE9, 0x51, 0xE9, 0x52, 0xE9, 0x53, 0xB3, 0xA4, /* 0x7C-0x7F */ - - 0xE9, 0x54, 0xE9, 0x55, 0xE9, 0x56, 0xE9, 0x57, /* 0x80-0x83 */ - 0xE9, 0x58, 0xE9, 0x59, 0xE9, 0x5A, 0xE9, 0x5B, /* 0x84-0x87 */ - 0xE9, 0x5C, 0xE9, 0x5D, 0xE9, 0x5E, 0xE9, 0x5F, /* 0x88-0x8B */ - 0xE9, 0x60, 0xE9, 0x61, 0xE9, 0x62, 0xE9, 0x63, /* 0x8C-0x8F */ - 0xE9, 0x64, 0xE9, 0x65, 0xE9, 0x66, 0xE9, 0x67, /* 0x90-0x93 */ - 0xE9, 0x68, 0xE9, 0x69, 0xE9, 0x6A, 0xE9, 0x6B, /* 0x94-0x97 */ - 0xE9, 0x6C, 0xE9, 0x6D, 0xE9, 0x6E, 0xE9, 0x6F, /* 0x98-0x9B */ - 0xE9, 0x70, 0xE9, 0x71, 0xE9, 0x72, 0xE9, 0x73, /* 0x9C-0x9F */ - 0xE9, 0x74, 0xE9, 0x75, 0xE9, 0x76, 0xE9, 0x77, /* 0xA0-0xA3 */ - 0xE9, 0x78, 0xE9, 0x79, 0xE9, 0x7A, 0xE9, 0x7B, /* 0xA4-0xA7 */ - 0xE9, 0x7C, 0xE9, 0x7D, 0xE9, 0x7E, 0xE9, 0x80, /* 0xA8-0xAB */ - 0xE9, 0x81, 0xE9, 0x82, 0xE9, 0x83, 0xE9, 0x84, /* 0xAC-0xAF */ - 0xE9, 0x85, 0xE9, 0x86, 0xE9, 0x87, 0xE9, 0x88, /* 0xB0-0xB3 */ - 0xE9, 0x89, 0xE9, 0x8A, 0xE9, 0x8B, 0xE9, 0x8C, /* 0xB4-0xB7 */ - 0xE9, 0x8D, 0xE9, 0x8E, 0xE9, 0x8F, 0xE9, 0x90, /* 0xB8-0xBB */ - 0xE9, 0x91, 0xE9, 0x92, 0xE9, 0x93, 0xE9, 0x94, /* 0xBC-0xBF */ - 0xE9, 0x95, 0xE9, 0x96, 0xE9, 0x97, 0xE9, 0x98, /* 0xC0-0xC3 */ - 0xE9, 0x99, 0xE9, 0x9A, 0xE9, 0x9B, 0xE9, 0x9C, /* 0xC4-0xC7 */ - 0xE9, 0x9D, 0xE9, 0x9E, 0xE9, 0x9F, 0xE9, 0xA0, /* 0xC8-0xCB */ - 0xEA, 0x40, 0xEA, 0x41, 0xEA, 0x42, 0xEA, 0x43, /* 0xCC-0xCF */ - 0xEA, 0x44, 0xEA, 0x45, 0xEA, 0x46, 0xEA, 0x47, /* 0xD0-0xD3 */ - 0xEA, 0x48, 0xEA, 0x49, 0xEA, 0x4A, 0xEA, 0x4B, /* 0xD4-0xD7 */ - 0xEA, 0x4C, 0xEA, 0x4D, 0xEA, 0x4E, 0xEA, 0x4F, /* 0xD8-0xDB */ - 0xEA, 0x50, 0xEA, 0x51, 0xEA, 0x52, 0xEA, 0x53, /* 0xDC-0xDF */ - 0xEA, 0x54, 0xEA, 0x55, 0xEA, 0x56, 0xEA, 0x57, /* 0xE0-0xE3 */ - 0xEA, 0x58, 0xEA, 0x59, 0xEA, 0x5A, 0xEA, 0x5B, /* 0xE4-0xE7 */ - 0xC3, 0xC5, 0xE3, 0xC5, 0xC9, 0xC1, 0xE3, 0xC6, /* 0xE8-0xEB */ - 0xEA, 0x5C, 0xB1, 0xD5, 0xCE, 0xCA, 0xB4, 0xB3, /* 0xEC-0xEF */ - 0xC8, 0xF2, 0xE3, 0xC7, 0xCF, 0xD0, 0xE3, 0xC8, /* 0xF0-0xF3 */ - 0xBC, 0xE4, 0xE3, 0xC9, 0xE3, 0xCA, 0xC3, 0xC6, /* 0xF4-0xF7 */ - 0xD5, 0xA2, 0xC4, 0xD6, 0xB9, 0xEB, 0xCE, 0xC5, /* 0xF8-0xFB */ - 0xE3, 0xCB, 0xC3, 0xF6, 0xE3, 0xCC, 0xEA, 0x5D, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_96[512] = { - 0xB7, 0xA7, 0xB8, 0xF3, 0xBA, 0xD2, 0xE3, 0xCD, /* 0x00-0x03 */ - 0xE3, 0xCE, 0xD4, 0xC4, 0xE3, 0xCF, 0xEA, 0x5E, /* 0x04-0x07 */ - 0xE3, 0xD0, 0xD1, 0xCB, 0xE3, 0xD1, 0xE3, 0xD2, /* 0x08-0x0B */ - 0xE3, 0xD3, 0xE3, 0xD4, 0xD1, 0xD6, 0xE3, 0xD5, /* 0x0C-0x0F */ - 0xB2, 0xFB, 0xC0, 0xBB, 0xE3, 0xD6, 0xEA, 0x5F, /* 0x10-0x13 */ - 0xC0, 0xAB, 0xE3, 0xD7, 0xE3, 0xD8, 0xE3, 0xD9, /* 0x14-0x17 */ - 0xEA, 0x60, 0xE3, 0xDA, 0xE3, 0xDB, 0xEA, 0x61, /* 0x18-0x1B */ - 0xB8, 0xB7, 0xDA, 0xE2, 0xEA, 0x62, 0xB6, 0xD3, /* 0x1C-0x1F */ - 0xEA, 0x63, 0xDA, 0xE4, 0xDA, 0xE3, 0xEA, 0x64, /* 0x20-0x23 */ - 0xEA, 0x65, 0xEA, 0x66, 0xEA, 0x67, 0xEA, 0x68, /* 0x24-0x27 */ - 0xEA, 0x69, 0xEA, 0x6A, 0xDA, 0xE6, 0xEA, 0x6B, /* 0x28-0x2B */ - 0xEA, 0x6C, 0xEA, 0x6D, 0xC8, 0xEE, 0xEA, 0x6E, /* 0x2C-0x2F */ - 0xEA, 0x6F, 0xDA, 0xE5, 0xB7, 0xC0, 0xD1, 0xF4, /* 0x30-0x33 */ - 0xD2, 0xF5, 0xD5, 0xF3, 0xBD, 0xD7, 0xEA, 0x70, /* 0x34-0x37 */ - 0xEA, 0x71, 0xEA, 0x72, 0xEA, 0x73, 0xD7, 0xE8, /* 0x38-0x3B */ - 0xDA, 0xE8, 0xDA, 0xE7, 0xEA, 0x74, 0xB0, 0xA2, /* 0x3C-0x3F */ - 0xCD, 0xD3, 0xEA, 0x75, 0xDA, 0xE9, 0xEA, 0x76, /* 0x40-0x43 */ - 0xB8, 0xBD, 0xBC, 0xCA, 0xC2, 0xBD, 0xC2, 0xA4, /* 0x44-0x47 */ - 0xB3, 0xC2, 0xDA, 0xEA, 0xEA, 0x77, 0xC2, 0xAA, /* 0x48-0x4B */ - 0xC4, 0xB0, 0xBD, 0xB5, 0xEA, 0x78, 0xEA, 0x79, /* 0x4C-0x4F */ - 0xCF, 0xDE, 0xEA, 0x7A, 0xEA, 0x7B, 0xEA, 0x7C, /* 0x50-0x53 */ - 0xDA, 0xEB, 0xC9, 0xC2, 0xEA, 0x7D, 0xEA, 0x7E, /* 0x54-0x57 */ - 0xEA, 0x80, 0xEA, 0x81, 0xEA, 0x82, 0xB1, 0xDD, /* 0x58-0x5B */ - 0xEA, 0x83, 0xEA, 0x84, 0xEA, 0x85, 0xDA, 0xEC, /* 0x5C-0x5F */ - 0xEA, 0x86, 0xB6, 0xB8, 0xD4, 0xBA, 0xEA, 0x87, /* 0x60-0x63 */ - 0xB3, 0xFD, 0xEA, 0x88, 0xEA, 0x89, 0xDA, 0xED, /* 0x64-0x67 */ - 0xD4, 0xC9, 0xCF, 0xD5, 0xC5, 0xE3, 0xEA, 0x8A, /* 0x68-0x6B */ - 0xDA, 0xEE, 0xEA, 0x8B, 0xEA, 0x8C, 0xEA, 0x8D, /* 0x6C-0x6F */ - 0xEA, 0x8E, 0xEA, 0x8F, 0xDA, 0xEF, 0xEA, 0x90, /* 0x70-0x73 */ - 0xDA, 0xF0, 0xC1, 0xEA, 0xCC, 0xD5, 0xCF, 0xDD, /* 0x74-0x77 */ - 0xEA, 0x91, 0xEA, 0x92, 0xEA, 0x93, 0xEA, 0x94, /* 0x78-0x7B */ - 0xEA, 0x95, 0xEA, 0x96, 0xEA, 0x97, 0xEA, 0x98, /* 0x7C-0x7F */ - - 0xEA, 0x99, 0xEA, 0x9A, 0xEA, 0x9B, 0xEA, 0x9C, /* 0x80-0x83 */ - 0xEA, 0x9D, 0xD3, 0xE7, 0xC2, 0xA1, 0xEA, 0x9E, /* 0x84-0x87 */ - 0xDA, 0xF1, 0xEA, 0x9F, 0xEA, 0xA0, 0xCB, 0xE5, /* 0x88-0x8B */ - 0xEB, 0x40, 0xDA, 0xF2, 0xEB, 0x41, 0xCB, 0xE6, /* 0x8C-0x8F */ - 0xD2, 0xFE, 0xEB, 0x42, 0xEB, 0x43, 0xEB, 0x44, /* 0x90-0x93 */ - 0xB8, 0xF4, 0xEB, 0x45, 0xEB, 0x46, 0xDA, 0xF3, /* 0x94-0x97 */ - 0xB0, 0xAF, 0xCF, 0xB6, 0xEB, 0x47, 0xEB, 0x48, /* 0x98-0x9B */ - 0xD5, 0xCF, 0xEB, 0x49, 0xEB, 0x4A, 0xEB, 0x4B, /* 0x9C-0x9F */ - 0xEB, 0x4C, 0xEB, 0x4D, 0xEB, 0x4E, 0xEB, 0x4F, /* 0xA0-0xA3 */ - 0xEB, 0x50, 0xEB, 0x51, 0xEB, 0x52, 0xCB, 0xED, /* 0xA4-0xA7 */ - 0xEB, 0x53, 0xEB, 0x54, 0xEB, 0x55, 0xEB, 0x56, /* 0xA8-0xAB */ - 0xEB, 0x57, 0xEB, 0x58, 0xEB, 0x59, 0xEB, 0x5A, /* 0xAC-0xAF */ - 0xDA, 0xF4, 0xEB, 0x5B, 0xEB, 0x5C, 0xE3, 0xC4, /* 0xB0-0xB3 */ - 0xEB, 0x5D, 0xEB, 0x5E, 0xC1, 0xA5, 0xEB, 0x5F, /* 0xB4-0xB7 */ - 0xEB, 0x60, 0xF6, 0xBF, 0xEB, 0x61, 0xEB, 0x62, /* 0xB8-0xBB */ - 0xF6, 0xC0, 0xF6, 0xC1, 0xC4, 0xD1, 0xEB, 0x63, /* 0xBC-0xBF */ - 0xC8, 0xB8, 0xD1, 0xE3, 0xEB, 0x64, 0xEB, 0x65, /* 0xC0-0xC3 */ - 0xD0, 0xDB, 0xD1, 0xC5, 0xBC, 0xAF, 0xB9, 0xCD, /* 0xC4-0xC7 */ - 0xEB, 0x66, 0xEF, 0xF4, 0xEB, 0x67, 0xEB, 0x68, /* 0xC8-0xCB */ - 0xB4, 0xC6, 0xD3, 0xBA, 0xF6, 0xC2, 0xB3, 0xFB, /* 0xCC-0xCF */ - 0xEB, 0x69, 0xEB, 0x6A, 0xF6, 0xC3, 0xEB, 0x6B, /* 0xD0-0xD3 */ - 0xEB, 0x6C, 0xB5, 0xF1, 0xEB, 0x6D, 0xEB, 0x6E, /* 0xD4-0xD7 */ - 0xEB, 0x6F, 0xEB, 0x70, 0xEB, 0x71, 0xEB, 0x72, /* 0xD8-0xDB */ - 0xEB, 0x73, 0xEB, 0x74, 0xEB, 0x75, 0xEB, 0x76, /* 0xDC-0xDF */ - 0xF6, 0xC5, 0xEB, 0x77, 0xEB, 0x78, 0xEB, 0x79, /* 0xE0-0xE3 */ - 0xEB, 0x7A, 0xEB, 0x7B, 0xEB, 0x7C, 0xEB, 0x7D, /* 0xE4-0xE7 */ - 0xD3, 0xEA, 0xF6, 0xA7, 0xD1, 0xA9, 0xEB, 0x7E, /* 0xE8-0xEB */ - 0xEB, 0x80, 0xEB, 0x81, 0xEB, 0x82, 0xF6, 0xA9, /* 0xEC-0xEF */ - 0xEB, 0x83, 0xEB, 0x84, 0xEB, 0x85, 0xF6, 0xA8, /* 0xF0-0xF3 */ - 0xEB, 0x86, 0xEB, 0x87, 0xC1, 0xE3, 0xC0, 0xD7, /* 0xF4-0xF7 */ - 0xEB, 0x88, 0xB1, 0xA2, 0xEB, 0x89, 0xEB, 0x8A, /* 0xF8-0xFB */ - 0xEB, 0x8B, 0xEB, 0x8C, 0xCE, 0xED, 0xEB, 0x8D, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_97[512] = { - 0xD0, 0xE8, 0xF6, 0xAB, 0xEB, 0x8E, 0xEB, 0x8F, /* 0x00-0x03 */ - 0xCF, 0xF6, 0xEB, 0x90, 0xF6, 0xAA, 0xD5, 0xF0, /* 0x04-0x07 */ - 0xF6, 0xAC, 0xC3, 0xB9, 0xEB, 0x91, 0xEB, 0x92, /* 0x08-0x0B */ - 0xEB, 0x93, 0xBB, 0xF4, 0xF6, 0xAE, 0xF6, 0xAD, /* 0x0C-0x0F */ - 0xEB, 0x94, 0xEB, 0x95, 0xEB, 0x96, 0xC4, 0xDE, /* 0x10-0x13 */ - 0xEB, 0x97, 0xEB, 0x98, 0xC1, 0xD8, 0xEB, 0x99, /* 0x14-0x17 */ - 0xEB, 0x9A, 0xEB, 0x9B, 0xEB, 0x9C, 0xEB, 0x9D, /* 0x18-0x1B */ - 0xCB, 0xAA, 0xEB, 0x9E, 0xCF, 0xBC, 0xEB, 0x9F, /* 0x1C-0x1F */ - 0xEB, 0xA0, 0xEC, 0x40, 0xEC, 0x41, 0xEC, 0x42, /* 0x20-0x23 */ - 0xEC, 0x43, 0xEC, 0x44, 0xEC, 0x45, 0xEC, 0x46, /* 0x24-0x27 */ - 0xEC, 0x47, 0xEC, 0x48, 0xF6, 0xAF, 0xEC, 0x49, /* 0x28-0x2B */ - 0xEC, 0x4A, 0xF6, 0xB0, 0xEC, 0x4B, 0xEC, 0x4C, /* 0x2C-0x2F */ - 0xF6, 0xB1, 0xEC, 0x4D, 0xC2, 0xB6, 0xEC, 0x4E, /* 0x30-0x33 */ - 0xEC, 0x4F, 0xEC, 0x50, 0xEC, 0x51, 0xEC, 0x52, /* 0x34-0x37 */ - 0xB0, 0xD4, 0xC5, 0xF9, 0xEC, 0x53, 0xEC, 0x54, /* 0x38-0x3B */ - 0xEC, 0x55, 0xEC, 0x56, 0xF6, 0xB2, 0xEC, 0x57, /* 0x3C-0x3F */ - 0xEC, 0x58, 0xEC, 0x59, 0xEC, 0x5A, 0xEC, 0x5B, /* 0x40-0x43 */ - 0xEC, 0x5C, 0xEC, 0x5D, 0xEC, 0x5E, 0xEC, 0x5F, /* 0x44-0x47 */ - 0xEC, 0x60, 0xEC, 0x61, 0xEC, 0x62, 0xEC, 0x63, /* 0x48-0x4B */ - 0xEC, 0x64, 0xEC, 0x65, 0xEC, 0x66, 0xEC, 0x67, /* 0x4C-0x4F */ - 0xEC, 0x68, 0xEC, 0x69, 0xC7, 0xE0, 0xF6, 0xA6, /* 0x50-0x53 */ - 0xEC, 0x6A, 0xEC, 0x6B, 0xBE, 0xB8, 0xEC, 0x6C, /* 0x54-0x57 */ - 0xEC, 0x6D, 0xBE, 0xB2, 0xEC, 0x6E, 0xB5, 0xE5, /* 0x58-0x5B */ - 0xEC, 0x6F, 0xEC, 0x70, 0xB7, 0xC7, 0xEC, 0x71, /* 0x5C-0x5F */ - 0xBF, 0xBF, 0xC3, 0xD2, 0xC3, 0xE6, 0xEC, 0x72, /* 0x60-0x63 */ - 0xEC, 0x73, 0xD8, 0xCC, 0xEC, 0x74, 0xEC, 0x75, /* 0x64-0x67 */ - 0xEC, 0x76, 0xB8, 0xEF, 0xEC, 0x77, 0xEC, 0x78, /* 0x68-0x6B */ - 0xEC, 0x79, 0xEC, 0x7A, 0xEC, 0x7B, 0xEC, 0x7C, /* 0x6C-0x6F */ - 0xEC, 0x7D, 0xEC, 0x7E, 0xEC, 0x80, 0xBD, 0xF9, /* 0x70-0x73 */ - 0xD1, 0xA5, 0xEC, 0x81, 0xB0, 0xD0, 0xEC, 0x82, /* 0x74-0x77 */ - 0xEC, 0x83, 0xEC, 0x84, 0xEC, 0x85, 0xEC, 0x86, /* 0x78-0x7B */ - 0xF7, 0xB0, 0xEC, 0x87, 0xEC, 0x88, 0xEC, 0x89, /* 0x7C-0x7F */ - - 0xEC, 0x8A, 0xEC, 0x8B, 0xEC, 0x8C, 0xEC, 0x8D, /* 0x80-0x83 */ - 0xEC, 0x8E, 0xF7, 0xB1, 0xEC, 0x8F, 0xEC, 0x90, /* 0x84-0x87 */ - 0xEC, 0x91, 0xEC, 0x92, 0xEC, 0x93, 0xD0, 0xAC, /* 0x88-0x8B */ - 0xEC, 0x94, 0xB0, 0xB0, 0xEC, 0x95, 0xEC, 0x96, /* 0x8C-0x8F */ - 0xEC, 0x97, 0xF7, 0xB2, 0xF7, 0xB3, 0xEC, 0x98, /* 0x90-0x93 */ - 0xF7, 0xB4, 0xEC, 0x99, 0xEC, 0x9A, 0xEC, 0x9B, /* 0x94-0x97 */ - 0xC7, 0xCA, 0xEC, 0x9C, 0xEC, 0x9D, 0xEC, 0x9E, /* 0x98-0x9B */ - 0xEC, 0x9F, 0xEC, 0xA0, 0xED, 0x40, 0xED, 0x41, /* 0x9C-0x9F */ - 0xBE, 0xCF, 0xED, 0x42, 0xED, 0x43, 0xF7, 0xB7, /* 0xA0-0xA3 */ - 0xED, 0x44, 0xED, 0x45, 0xED, 0x46, 0xED, 0x47, /* 0xA4-0xA7 */ - 0xED, 0x48, 0xED, 0x49, 0xED, 0x4A, 0xF7, 0xB6, /* 0xA8-0xAB */ - 0xED, 0x4B, 0xB1, 0xDE, 0xED, 0x4C, 0xF7, 0xB5, /* 0xAC-0xAF */ - 0xED, 0x4D, 0xED, 0x4E, 0xF7, 0xB8, 0xED, 0x4F, /* 0xB0-0xB3 */ - 0xF7, 0xB9, 0xED, 0x50, 0xED, 0x51, 0xED, 0x52, /* 0xB4-0xB7 */ - 0xED, 0x53, 0xED, 0x54, 0xED, 0x55, 0xED, 0x56, /* 0xB8-0xBB */ - 0xED, 0x57, 0xED, 0x58, 0xED, 0x59, 0xED, 0x5A, /* 0xBC-0xBF */ - 0xED, 0x5B, 0xED, 0x5C, 0xED, 0x5D, 0xED, 0x5E, /* 0xC0-0xC3 */ - 0xED, 0x5F, 0xED, 0x60, 0xED, 0x61, 0xED, 0x62, /* 0xC4-0xC7 */ - 0xED, 0x63, 0xED, 0x64, 0xED, 0x65, 0xED, 0x66, /* 0xC8-0xCB */ - 0xED, 0x67, 0xED, 0x68, 0xED, 0x69, 0xED, 0x6A, /* 0xCC-0xCF */ - 0xED, 0x6B, 0xED, 0x6C, 0xED, 0x6D, 0xED, 0x6E, /* 0xD0-0xD3 */ - 0xED, 0x6F, 0xED, 0x70, 0xED, 0x71, 0xED, 0x72, /* 0xD4-0xD7 */ - 0xED, 0x73, 0xED, 0x74, 0xED, 0x75, 0xED, 0x76, /* 0xD8-0xDB */ - 0xED, 0x77, 0xED, 0x78, 0xED, 0x79, 0xED, 0x7A, /* 0xDC-0xDF */ - 0xED, 0x7B, 0xED, 0x7C, 0xED, 0x7D, 0xED, 0x7E, /* 0xE0-0xE3 */ - 0xED, 0x80, 0xED, 0x81, 0xCE, 0xA4, 0xC8, 0xCD, /* 0xE4-0xE7 */ - 0xED, 0x82, 0xBA, 0xAB, 0xE8, 0xB8, 0xE8, 0xB9, /* 0xE8-0xEB */ - 0xE8, 0xBA, 0xBE, 0xC2, 0xED, 0x83, 0xED, 0x84, /* 0xEC-0xEF */ - 0xED, 0x85, 0xED, 0x86, 0xED, 0x87, 0xD2, 0xF4, /* 0xF0-0xF3 */ - 0xED, 0x88, 0xD4, 0xCF, 0xC9, 0xD8, 0xED, 0x89, /* 0xF4-0xF7 */ - 0xED, 0x8A, 0xED, 0x8B, 0xED, 0x8C, 0xED, 0x8D, /* 0xF8-0xFB */ - 0xED, 0x8E, 0xED, 0x8F, 0xED, 0x90, 0xED, 0x91, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_98[512] = { - 0xED, 0x92, 0xED, 0x93, 0xED, 0x94, 0xED, 0x95, /* 0x00-0x03 */ - 0xED, 0x96, 0xED, 0x97, 0xED, 0x98, 0xED, 0x99, /* 0x04-0x07 */ - 0xED, 0x9A, 0xED, 0x9B, 0xED, 0x9C, 0xED, 0x9D, /* 0x08-0x0B */ - 0xED, 0x9E, 0xED, 0x9F, 0xED, 0xA0, 0xEE, 0x40, /* 0x0C-0x0F */ - 0xEE, 0x41, 0xEE, 0x42, 0xEE, 0x43, 0xEE, 0x44, /* 0x10-0x13 */ - 0xEE, 0x45, 0xEE, 0x46, 0xEE, 0x47, 0xEE, 0x48, /* 0x14-0x17 */ - 0xEE, 0x49, 0xEE, 0x4A, 0xEE, 0x4B, 0xEE, 0x4C, /* 0x18-0x1B */ - 0xEE, 0x4D, 0xEE, 0x4E, 0xEE, 0x4F, 0xEE, 0x50, /* 0x1C-0x1F */ - 0xEE, 0x51, 0xEE, 0x52, 0xEE, 0x53, 0xEE, 0x54, /* 0x20-0x23 */ - 0xEE, 0x55, 0xEE, 0x56, 0xEE, 0x57, 0xEE, 0x58, /* 0x24-0x27 */ - 0xEE, 0x59, 0xEE, 0x5A, 0xEE, 0x5B, 0xEE, 0x5C, /* 0x28-0x2B */ - 0xEE, 0x5D, 0xEE, 0x5E, 0xEE, 0x5F, 0xEE, 0x60, /* 0x2C-0x2F */ - 0xEE, 0x61, 0xEE, 0x62, 0xEE, 0x63, 0xEE, 0x64, /* 0x30-0x33 */ - 0xEE, 0x65, 0xEE, 0x66, 0xEE, 0x67, 0xEE, 0x68, /* 0x34-0x37 */ - 0xEE, 0x69, 0xEE, 0x6A, 0xEE, 0x6B, 0xEE, 0x6C, /* 0x38-0x3B */ - 0xEE, 0x6D, 0xEE, 0x6E, 0xEE, 0x6F, 0xEE, 0x70, /* 0x3C-0x3F */ - 0xEE, 0x71, 0xEE, 0x72, 0xEE, 0x73, 0xEE, 0x74, /* 0x40-0x43 */ - 0xEE, 0x75, 0xEE, 0x76, 0xEE, 0x77, 0xEE, 0x78, /* 0x44-0x47 */ - 0xEE, 0x79, 0xEE, 0x7A, 0xEE, 0x7B, 0xEE, 0x7C, /* 0x48-0x4B */ - 0xEE, 0x7D, 0xEE, 0x7E, 0xEE, 0x80, 0xEE, 0x81, /* 0x4C-0x4F */ - 0xEE, 0x82, 0xEE, 0x83, 0xEE, 0x84, 0xEE, 0x85, /* 0x50-0x53 */ - 0xEE, 0x86, 0xEE, 0x87, 0xEE, 0x88, 0xEE, 0x89, /* 0x54-0x57 */ - 0xEE, 0x8A, 0xEE, 0x8B, 0xEE, 0x8C, 0xEE, 0x8D, /* 0x58-0x5B */ - 0xEE, 0x8E, 0xEE, 0x8F, 0xEE, 0x90, 0xEE, 0x91, /* 0x5C-0x5F */ - 0xEE, 0x92, 0xEE, 0x93, 0xEE, 0x94, 0xEE, 0x95, /* 0x60-0x63 */ - 0xEE, 0x96, 0xEE, 0x97, 0xEE, 0x98, 0xEE, 0x99, /* 0x64-0x67 */ - 0xEE, 0x9A, 0xEE, 0x9B, 0xEE, 0x9C, 0xEE, 0x9D, /* 0x68-0x6B */ - 0xEE, 0x9E, 0xEE, 0x9F, 0xEE, 0xA0, 0xEF, 0x40, /* 0x6C-0x6F */ - 0xEF, 0x41, 0xEF, 0x42, 0xEF, 0x43, 0xEF, 0x44, /* 0x70-0x73 */ - 0xEF, 0x45, 0xD2, 0xB3, 0xB6, 0xA5, 0xC7, 0xEA, /* 0x74-0x77 */ - 0xF1, 0xFC, 0xCF, 0xEE, 0xCB, 0xB3, 0xD0, 0xEB, /* 0x78-0x7B */ - 0xE7, 0xEF, 0xCD, 0xE7, 0xB9, 0xCB, 0xB6, 0xD9, /* 0x7C-0x7F */ - - 0xF1, 0xFD, 0xB0, 0xE4, 0xCB, 0xCC, 0xF1, 0xFE, /* 0x80-0x83 */ - 0xD4, 0xA4, 0xC2, 0xAD, 0xC1, 0xEC, 0xC6, 0xC4, /* 0x84-0x87 */ - 0xBE, 0xB1, 0xF2, 0xA1, 0xBC, 0xD5, 0xEF, 0x46, /* 0x88-0x8B */ - 0xF2, 0xA2, 0xF2, 0xA3, 0xEF, 0x47, 0xF2, 0xA4, /* 0x8C-0x8F */ - 0xD2, 0xC3, 0xC6, 0xB5, 0xEF, 0x48, 0xCD, 0xC7, /* 0x90-0x93 */ - 0xF2, 0xA5, 0xEF, 0x49, 0xD3, 0xB1, 0xBF, 0xC5, /* 0x94-0x97 */ - 0xCC, 0xE2, 0xEF, 0x4A, 0xF2, 0xA6, 0xF2, 0xA7, /* 0x98-0x9B */ - 0xD1, 0xD5, 0xB6, 0xEE, 0xF2, 0xA8, 0xF2, 0xA9, /* 0x9C-0x9F */ - 0xB5, 0xDF, 0xF2, 0xAA, 0xF2, 0xAB, 0xEF, 0x4B, /* 0xA0-0xA3 */ - 0xB2, 0xFC, 0xF2, 0xAC, 0xF2, 0xAD, 0xC8, 0xA7, /* 0xA4-0xA7 */ - 0xEF, 0x4C, 0xEF, 0x4D, 0xEF, 0x4E, 0xEF, 0x4F, /* 0xA8-0xAB */ - 0xEF, 0x50, 0xEF, 0x51, 0xEF, 0x52, 0xEF, 0x53, /* 0xAC-0xAF */ - 0xEF, 0x54, 0xEF, 0x55, 0xEF, 0x56, 0xEF, 0x57, /* 0xB0-0xB3 */ - 0xEF, 0x58, 0xEF, 0x59, 0xEF, 0x5A, 0xEF, 0x5B, /* 0xB4-0xB7 */ - 0xEF, 0x5C, 0xEF, 0x5D, 0xEF, 0x5E, 0xEF, 0x5F, /* 0xB8-0xBB */ - 0xEF, 0x60, 0xEF, 0x61, 0xEF, 0x62, 0xEF, 0x63, /* 0xBC-0xBF */ - 0xEF, 0x64, 0xEF, 0x65, 0xEF, 0x66, 0xEF, 0x67, /* 0xC0-0xC3 */ - 0xEF, 0x68, 0xEF, 0x69, 0xEF, 0x6A, 0xEF, 0x6B, /* 0xC4-0xC7 */ - 0xEF, 0x6C, 0xEF, 0x6D, 0xEF, 0x6E, 0xEF, 0x6F, /* 0xC8-0xCB */ - 0xEF, 0x70, 0xEF, 0x71, 0xB7, 0xE7, 0xEF, 0x72, /* 0xCC-0xCF */ - 0xEF, 0x73, 0xEC, 0xA9, 0xEC, 0xAA, 0xEC, 0xAB, /* 0xD0-0xD3 */ - 0xEF, 0x74, 0xEC, 0xAC, 0xEF, 0x75, 0xEF, 0x76, /* 0xD4-0xD7 */ - 0xC6, 0xAE, 0xEC, 0xAD, 0xEC, 0xAE, 0xEF, 0x77, /* 0xD8-0xDB */ - 0xEF, 0x78, 0xEF, 0x79, 0xB7, 0xC9, 0xCA, 0xB3, /* 0xDC-0xDF */ - 0xEF, 0x7A, 0xEF, 0x7B, 0xEF, 0x7C, 0xEF, 0x7D, /* 0xE0-0xE3 */ - 0xEF, 0x7E, 0xEF, 0x80, 0xEF, 0x81, 0xE2, 0xB8, /* 0xE4-0xE7 */ - 0xF7, 0xCF, 0xEF, 0x82, 0xEF, 0x83, 0xEF, 0x84, /* 0xE8-0xEB */ - 0xEF, 0x85, 0xEF, 0x86, 0xEF, 0x87, 0xEF, 0x88, /* 0xEC-0xEF */ - 0xEF, 0x89, 0xEF, 0x8A, 0xEF, 0x8B, 0xEF, 0x8C, /* 0xF0-0xF3 */ - 0xEF, 0x8D, 0xEF, 0x8E, 0xEF, 0x8F, 0xEF, 0x90, /* 0xF4-0xF7 */ - 0xEF, 0x91, 0xEF, 0x92, 0xEF, 0x93, 0xEF, 0x94, /* 0xF8-0xFB */ - 0xEF, 0x95, 0xEF, 0x96, 0xEF, 0x97, 0xEF, 0x98, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_99[512] = { - 0xEF, 0x99, 0xEF, 0x9A, 0xEF, 0x9B, 0xEF, 0x9C, /* 0x00-0x03 */ - 0xEF, 0x9D, 0xEF, 0x9E, 0xEF, 0x9F, 0xEF, 0xA0, /* 0x04-0x07 */ - 0xF0, 0x40, 0xF0, 0x41, 0xF0, 0x42, 0xF0, 0x43, /* 0x08-0x0B */ - 0xF0, 0x44, 0xF7, 0xD0, 0xF0, 0x45, 0xF0, 0x46, /* 0x0C-0x0F */ - 0xB2, 0xCD, 0xF0, 0x47, 0xF0, 0x48, 0xF0, 0x49, /* 0x10-0x13 */ - 0xF0, 0x4A, 0xF0, 0x4B, 0xF0, 0x4C, 0xF0, 0x4D, /* 0x14-0x17 */ - 0xF0, 0x4E, 0xF0, 0x4F, 0xF0, 0x50, 0xF0, 0x51, /* 0x18-0x1B */ - 0xF0, 0x52, 0xF0, 0x53, 0xF0, 0x54, 0xF0, 0x55, /* 0x1C-0x1F */ - 0xF0, 0x56, 0xF0, 0x57, 0xF0, 0x58, 0xF0, 0x59, /* 0x20-0x23 */ - 0xF0, 0x5A, 0xF0, 0x5B, 0xF0, 0x5C, 0xF0, 0x5D, /* 0x24-0x27 */ - 0xF0, 0x5E, 0xF0, 0x5F, 0xF0, 0x60, 0xF0, 0x61, /* 0x28-0x2B */ - 0xF0, 0x62, 0xF0, 0x63, 0xF7, 0xD1, 0xF0, 0x64, /* 0x2C-0x2F */ - 0xF0, 0x65, 0xF0, 0x66, 0xF0, 0x67, 0xF0, 0x68, /* 0x30-0x33 */ - 0xF0, 0x69, 0xF0, 0x6A, 0xF0, 0x6B, 0xF0, 0x6C, /* 0x34-0x37 */ - 0xF0, 0x6D, 0xF0, 0x6E, 0xF0, 0x6F, 0xF0, 0x70, /* 0x38-0x3B */ - 0xF0, 0x71, 0xF0, 0x72, 0xF0, 0x73, 0xF0, 0x74, /* 0x3C-0x3F */ - 0xF0, 0x75, 0xF0, 0x76, 0xF0, 0x77, 0xF0, 0x78, /* 0x40-0x43 */ - 0xF0, 0x79, 0xF0, 0x7A, 0xF0, 0x7B, 0xF0, 0x7C, /* 0x44-0x47 */ - 0xF0, 0x7D, 0xF0, 0x7E, 0xF0, 0x80, 0xF0, 0x81, /* 0x48-0x4B */ - 0xF0, 0x82, 0xF0, 0x83, 0xF0, 0x84, 0xF0, 0x85, /* 0x4C-0x4F */ - 0xF0, 0x86, 0xF0, 0x87, 0xF0, 0x88, 0xF0, 0x89, /* 0x50-0x53 */ - 0xF7, 0xD3, 0xF7, 0xD2, 0xF0, 0x8A, 0xF0, 0x8B, /* 0x54-0x57 */ - 0xF0, 0x8C, 0xF0, 0x8D, 0xF0, 0x8E, 0xF0, 0x8F, /* 0x58-0x5B */ - 0xF0, 0x90, 0xF0, 0x91, 0xF0, 0x92, 0xF0, 0x93, /* 0x5C-0x5F */ - 0xF0, 0x94, 0xF0, 0x95, 0xF0, 0x96, 0xE2, 0xBB, /* 0x60-0x63 */ - 0xF0, 0x97, 0xBC, 0xA2, 0xF0, 0x98, 0xE2, 0xBC, /* 0x64-0x67 */ - 0xE2, 0xBD, 0xE2, 0xBE, 0xE2, 0xBF, 0xE2, 0xC0, /* 0x68-0x6B */ - 0xE2, 0xC1, 0xB7, 0xB9, 0xD2, 0xFB, 0xBD, 0xA4, /* 0x6C-0x6F */ - 0xCA, 0xCE, 0xB1, 0xA5, 0xCB, 0xC7, 0xF0, 0x99, /* 0x70-0x73 */ - 0xE2, 0xC2, 0xB6, 0xFC, 0xC8, 0xC4, 0xE2, 0xC3, /* 0x74-0x77 */ - 0xF0, 0x9A, 0xF0, 0x9B, 0xBD, 0xC8, 0xF0, 0x9C, /* 0x78-0x7B */ - 0xB1, 0xFD, 0xE2, 0xC4, 0xF0, 0x9D, 0xB6, 0xF6, /* 0x7C-0x7F */ - - 0xE2, 0xC5, 0xC4, 0xD9, 0xF0, 0x9E, 0xF0, 0x9F, /* 0x80-0x83 */ - 0xE2, 0xC6, 0xCF, 0xDA, 0xB9, 0xDD, 0xE2, 0xC7, /* 0x84-0x87 */ - 0xC0, 0xA1, 0xF0, 0xA0, 0xE2, 0xC8, 0xB2, 0xF6, /* 0x88-0x8B */ - 0xF1, 0x40, 0xE2, 0xC9, 0xF1, 0x41, 0xC1, 0xF3, /* 0x8C-0x8F */ - 0xE2, 0xCA, 0xE2, 0xCB, 0xC2, 0xF8, 0xE2, 0xCC, /* 0x90-0x93 */ - 0xE2, 0xCD, 0xE2, 0xCE, 0xCA, 0xD7, 0xD8, 0xB8, /* 0x94-0x97 */ - 0xD9, 0xE5, 0xCF, 0xE3, 0xF1, 0x42, 0xF1, 0x43, /* 0x98-0x9B */ - 0xF1, 0x44, 0xF1, 0x45, 0xF1, 0x46, 0xF1, 0x47, /* 0x9C-0x9F */ - 0xF1, 0x48, 0xF1, 0x49, 0xF1, 0x4A, 0xF1, 0x4B, /* 0xA0-0xA3 */ - 0xF1, 0x4C, 0xF0, 0xA5, 0xF1, 0x4D, 0xF1, 0x4E, /* 0xA4-0xA7 */ - 0xDC, 0xB0, 0xF1, 0x4F, 0xF1, 0x50, 0xF1, 0x51, /* 0xA8-0xAB */ - 0xF1, 0x52, 0xF1, 0x53, 0xF1, 0x54, 0xF1, 0x55, /* 0xAC-0xAF */ - 0xF1, 0x56, 0xF1, 0x57, 0xF1, 0x58, 0xF1, 0x59, /* 0xB0-0xB3 */ - 0xF1, 0x5A, 0xF1, 0x5B, 0xF1, 0x5C, 0xF1, 0x5D, /* 0xB4-0xB7 */ - 0xF1, 0x5E, 0xF1, 0x5F, 0xF1, 0x60, 0xF1, 0x61, /* 0xB8-0xBB */ - 0xF1, 0x62, 0xF1, 0x63, 0xF1, 0x64, 0xF1, 0x65, /* 0xBC-0xBF */ - 0xF1, 0x66, 0xF1, 0x67, 0xF1, 0x68, 0xF1, 0x69, /* 0xC0-0xC3 */ - 0xF1, 0x6A, 0xF1, 0x6B, 0xF1, 0x6C, 0xF1, 0x6D, /* 0xC4-0xC7 */ - 0xF1, 0x6E, 0xF1, 0x6F, 0xF1, 0x70, 0xF1, 0x71, /* 0xC8-0xCB */ - 0xF1, 0x72, 0xF1, 0x73, 0xF1, 0x74, 0xF1, 0x75, /* 0xCC-0xCF */ - 0xF1, 0x76, 0xF1, 0x77, 0xF1, 0x78, 0xF1, 0x79, /* 0xD0-0xD3 */ - 0xF1, 0x7A, 0xF1, 0x7B, 0xF1, 0x7C, 0xF1, 0x7D, /* 0xD4-0xD7 */ - 0xF1, 0x7E, 0xF1, 0x80, 0xF1, 0x81, 0xF1, 0x82, /* 0xD8-0xDB */ - 0xF1, 0x83, 0xF1, 0x84, 0xF1, 0x85, 0xF1, 0x86, /* 0xDC-0xDF */ - 0xF1, 0x87, 0xF1, 0x88, 0xF1, 0x89, 0xF1, 0x8A, /* 0xE0-0xE3 */ - 0xF1, 0x8B, 0xF1, 0x8C, 0xF1, 0x8D, 0xF1, 0x8E, /* 0xE4-0xE7 */ - 0xF1, 0x8F, 0xF1, 0x90, 0xF1, 0x91, 0xF1, 0x92, /* 0xE8-0xEB */ - 0xF1, 0x93, 0xF1, 0x94, 0xF1, 0x95, 0xF1, 0x96, /* 0xEC-0xEF */ - 0xF1, 0x97, 0xF1, 0x98, 0xF1, 0x99, 0xF1, 0x9A, /* 0xF0-0xF3 */ - 0xF1, 0x9B, 0xF1, 0x9C, 0xF1, 0x9D, 0xF1, 0x9E, /* 0xF4-0xF7 */ - 0xF1, 0x9F, 0xF1, 0xA0, 0xF2, 0x40, 0xF2, 0x41, /* 0xF8-0xFB */ - 0xF2, 0x42, 0xF2, 0x43, 0xF2, 0x44, 0xF2, 0x45, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_9A[512] = { - 0xF2, 0x46, 0xF2, 0x47, 0xF2, 0x48, 0xF2, 0x49, /* 0x00-0x03 */ - 0xF2, 0x4A, 0xF2, 0x4B, 0xF2, 0x4C, 0xF2, 0x4D, /* 0x04-0x07 */ - 0xF2, 0x4E, 0xF2, 0x4F, 0xF2, 0x50, 0xF2, 0x51, /* 0x08-0x0B */ - 0xF2, 0x52, 0xF2, 0x53, 0xF2, 0x54, 0xF2, 0x55, /* 0x0C-0x0F */ - 0xF2, 0x56, 0xF2, 0x57, 0xF2, 0x58, 0xF2, 0x59, /* 0x10-0x13 */ - 0xF2, 0x5A, 0xF2, 0x5B, 0xF2, 0x5C, 0xF2, 0x5D, /* 0x14-0x17 */ - 0xF2, 0x5E, 0xF2, 0x5F, 0xF2, 0x60, 0xF2, 0x61, /* 0x18-0x1B */ - 0xF2, 0x62, 0xF2, 0x63, 0xF2, 0x64, 0xF2, 0x65, /* 0x1C-0x1F */ - 0xF2, 0x66, 0xF2, 0x67, 0xF2, 0x68, 0xF2, 0x69, /* 0x20-0x23 */ - 0xF2, 0x6A, 0xF2, 0x6B, 0xF2, 0x6C, 0xF2, 0x6D, /* 0x24-0x27 */ - 0xF2, 0x6E, 0xF2, 0x6F, 0xF2, 0x70, 0xF2, 0x71, /* 0x28-0x2B */ - 0xF2, 0x72, 0xF2, 0x73, 0xF2, 0x74, 0xF2, 0x75, /* 0x2C-0x2F */ - 0xF2, 0x76, 0xF2, 0x77, 0xF2, 0x78, 0xF2, 0x79, /* 0x30-0x33 */ - 0xF2, 0x7A, 0xF2, 0x7B, 0xF2, 0x7C, 0xF2, 0x7D, /* 0x34-0x37 */ - 0xF2, 0x7E, 0xF2, 0x80, 0xF2, 0x81, 0xF2, 0x82, /* 0x38-0x3B */ - 0xF2, 0x83, 0xF2, 0x84, 0xF2, 0x85, 0xF2, 0x86, /* 0x3C-0x3F */ - 0xF2, 0x87, 0xF2, 0x88, 0xF2, 0x89, 0xF2, 0x8A, /* 0x40-0x43 */ - 0xF2, 0x8B, 0xF2, 0x8C, 0xF2, 0x8D, 0xF2, 0x8E, /* 0x44-0x47 */ - 0xF2, 0x8F, 0xF2, 0x90, 0xF2, 0x91, 0xF2, 0x92, /* 0x48-0x4B */ - 0xF2, 0x93, 0xF2, 0x94, 0xF2, 0x95, 0xF2, 0x96, /* 0x4C-0x4F */ - 0xF2, 0x97, 0xF2, 0x98, 0xF2, 0x99, 0xF2, 0x9A, /* 0x50-0x53 */ - 0xF2, 0x9B, 0xF2, 0x9C, 0xF2, 0x9D, 0xF2, 0x9E, /* 0x54-0x57 */ - 0xF2, 0x9F, 0xF2, 0xA0, 0xF3, 0x40, 0xF3, 0x41, /* 0x58-0x5B */ - 0xF3, 0x42, 0xF3, 0x43, 0xF3, 0x44, 0xF3, 0x45, /* 0x5C-0x5F */ - 0xF3, 0x46, 0xF3, 0x47, 0xF3, 0x48, 0xF3, 0x49, /* 0x60-0x63 */ - 0xF3, 0x4A, 0xF3, 0x4B, 0xF3, 0x4C, 0xF3, 0x4D, /* 0x64-0x67 */ - 0xF3, 0x4E, 0xF3, 0x4F, 0xF3, 0x50, 0xF3, 0x51, /* 0x68-0x6B */ - 0xC2, 0xED, 0xD4, 0xA6, 0xCD, 0xD4, 0xD1, 0xB1, /* 0x6C-0x6F */ - 0xB3, 0xDB, 0xC7, 0xFD, 0xF3, 0x52, 0xB2, 0xB5, /* 0x70-0x73 */ - 0xC2, 0xBF, 0xE6, 0xE0, 0xCA, 0xBB, 0xE6, 0xE1, /* 0x74-0x77 */ - 0xE6, 0xE2, 0xBE, 0xD4, 0xE6, 0xE3, 0xD7, 0xA4, /* 0x78-0x7B */ - 0xCD, 0xD5, 0xE6, 0xE5, 0xBC, 0xDD, 0xE6, 0xE4, /* 0x7C-0x7F */ - - 0xE6, 0xE6, 0xE6, 0xE7, 0xC2, 0xEE, 0xF3, 0x53, /* 0x80-0x83 */ - 0xBD, 0xBE, 0xE6, 0xE8, 0xC2, 0xE6, 0xBA, 0xA7, /* 0x84-0x87 */ - 0xE6, 0xE9, 0xF3, 0x54, 0xE6, 0xEA, 0xB3, 0xD2, /* 0x88-0x8B */ - 0xD1, 0xE9, 0xF3, 0x55, 0xF3, 0x56, 0xBF, 0xA5, /* 0x8C-0x8F */ - 0xE6, 0xEB, 0xC6, 0xEF, 0xE6, 0xEC, 0xE6, 0xED, /* 0x90-0x93 */ - 0xF3, 0x57, 0xF3, 0x58, 0xE6, 0xEE, 0xC6, 0xAD, /* 0x94-0x97 */ - 0xE6, 0xEF, 0xF3, 0x59, 0xC9, 0xA7, 0xE6, 0xF0, /* 0x98-0x9B */ - 0xE6, 0xF1, 0xE6, 0xF2, 0xE5, 0xB9, 0xE6, 0xF3, /* 0x9C-0x9F */ - 0xE6, 0xF4, 0xC2, 0xE2, 0xE6, 0xF5, 0xE6, 0xF6, /* 0xA0-0xA3 */ - 0xD6, 0xE8, 0xE6, 0xF7, 0xF3, 0x5A, 0xE6, 0xF8, /* 0xA4-0xA7 */ - 0xB9, 0xC7, 0xF3, 0x5B, 0xF3, 0x5C, 0xF3, 0x5D, /* 0xA8-0xAB */ - 0xF3, 0x5E, 0xF3, 0x5F, 0xF3, 0x60, 0xF3, 0x61, /* 0xAC-0xAF */ - 0xF7, 0xBB, 0xF7, 0xBA, 0xF3, 0x62, 0xF3, 0x63, /* 0xB0-0xB3 */ - 0xF3, 0x64, 0xF3, 0x65, 0xF7, 0xBE, 0xF7, 0xBC, /* 0xB4-0xB7 */ - 0xBA, 0xA1, 0xF3, 0x66, 0xF7, 0xBF, 0xF3, 0x67, /* 0xB8-0xBB */ - 0xF7, 0xC0, 0xF3, 0x68, 0xF3, 0x69, 0xF3, 0x6A, /* 0xBC-0xBF */ - 0xF7, 0xC2, 0xF7, 0xC1, 0xF7, 0xC4, 0xF3, 0x6B, /* 0xC0-0xC3 */ - 0xF3, 0x6C, 0xF7, 0xC3, 0xF3, 0x6D, 0xF3, 0x6E, /* 0xC4-0xC7 */ - 0xF3, 0x6F, 0xF3, 0x70, 0xF3, 0x71, 0xF7, 0xC5, /* 0xC8-0xCB */ - 0xF7, 0xC6, 0xF3, 0x72, 0xF3, 0x73, 0xF3, 0x74, /* 0xCC-0xCF */ - 0xF3, 0x75, 0xF7, 0xC7, 0xF3, 0x76, 0xCB, 0xE8, /* 0xD0-0xD3 */ - 0xF3, 0x77, 0xF3, 0x78, 0xF3, 0x79, 0xF3, 0x7A, /* 0xD4-0xD7 */ - 0xB8, 0xDF, 0xF3, 0x7B, 0xF3, 0x7C, 0xF3, 0x7D, /* 0xD8-0xDB */ - 0xF3, 0x7E, 0xF3, 0x80, 0xF3, 0x81, 0xF7, 0xD4, /* 0xDC-0xDF */ - 0xF3, 0x82, 0xF7, 0xD5, 0xF3, 0x83, 0xF3, 0x84, /* 0xE0-0xE3 */ - 0xF3, 0x85, 0xF3, 0x86, 0xF7, 0xD6, 0xF3, 0x87, /* 0xE4-0xE7 */ - 0xF3, 0x88, 0xF3, 0x89, 0xF3, 0x8A, 0xF7, 0xD8, /* 0xE8-0xEB */ - 0xF3, 0x8B, 0xF7, 0xDA, 0xF3, 0x8C, 0xF7, 0xD7, /* 0xEC-0xEF */ - 0xF3, 0x8D, 0xF3, 0x8E, 0xF3, 0x8F, 0xF3, 0x90, /* 0xF0-0xF3 */ - 0xF3, 0x91, 0xF3, 0x92, 0xF3, 0x93, 0xF3, 0x94, /* 0xF4-0xF7 */ - 0xF3, 0x95, 0xF7, 0xDB, 0xF3, 0x96, 0xF7, 0xD9, /* 0xF8-0xFB */ - 0xF3, 0x97, 0xF3, 0x98, 0xF3, 0x99, 0xF3, 0x9A, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_9B[512] = { - 0xF3, 0x9B, 0xF3, 0x9C, 0xF3, 0x9D, 0xD7, 0xD7, /* 0x00-0x03 */ - 0xF3, 0x9E, 0xF3, 0x9F, 0xF3, 0xA0, 0xF4, 0x40, /* 0x04-0x07 */ - 0xF7, 0xDC, 0xF4, 0x41, 0xF4, 0x42, 0xF4, 0x43, /* 0x08-0x0B */ - 0xF4, 0x44, 0xF4, 0x45, 0xF4, 0x46, 0xF7, 0xDD, /* 0x0C-0x0F */ - 0xF4, 0x47, 0xF4, 0x48, 0xF4, 0x49, 0xF7, 0xDE, /* 0x10-0x13 */ - 0xF4, 0x4A, 0xF4, 0x4B, 0xF4, 0x4C, 0xF4, 0x4D, /* 0x14-0x17 */ - 0xF4, 0x4E, 0xF4, 0x4F, 0xF4, 0x50, 0xF4, 0x51, /* 0x18-0x1B */ - 0xF4, 0x52, 0xF4, 0x53, 0xF4, 0x54, 0xF7, 0xDF, /* 0x1C-0x1F */ - 0xF4, 0x55, 0xF4, 0x56, 0xF4, 0x57, 0xF7, 0xE0, /* 0x20-0x23 */ - 0xF4, 0x58, 0xF4, 0x59, 0xF4, 0x5A, 0xF4, 0x5B, /* 0x24-0x27 */ - 0xF4, 0x5C, 0xF4, 0x5D, 0xF4, 0x5E, 0xF4, 0x5F, /* 0x28-0x2B */ - 0xF4, 0x60, 0xF4, 0x61, 0xF4, 0x62, 0xDB, 0xCB, /* 0x2C-0x2F */ - 0xF4, 0x63, 0xF4, 0x64, 0xD8, 0xAA, 0xF4, 0x65, /* 0x30-0x33 */ - 0xF4, 0x66, 0xF4, 0x67, 0xF4, 0x68, 0xF4, 0x69, /* 0x34-0x37 */ - 0xF4, 0x6A, 0xF4, 0x6B, 0xF4, 0x6C, 0xE5, 0xF7, /* 0x38-0x3B */ - 0xB9, 0xED, 0xF4, 0x6D, 0xF4, 0x6E, 0xF4, 0x6F, /* 0x3C-0x3F */ - 0xF4, 0x70, 0xBF, 0xFD, 0xBB, 0xEA, 0xF7, 0xC9, /* 0x40-0x43 */ - 0xC6, 0xC7, 0xF7, 0xC8, 0xF4, 0x71, 0xF7, 0xCA, /* 0x44-0x47 */ - 0xF7, 0xCC, 0xF7, 0xCB, 0xF4, 0x72, 0xF4, 0x73, /* 0x48-0x4B */ - 0xF4, 0x74, 0xF7, 0xCD, 0xF4, 0x75, 0xCE, 0xBA, /* 0x4C-0x4F */ - 0xF4, 0x76, 0xF7, 0xCE, 0xF4, 0x77, 0xF4, 0x78, /* 0x50-0x53 */ - 0xC4, 0xA7, 0xF4, 0x79, 0xF4, 0x7A, 0xF4, 0x7B, /* 0x54-0x57 */ - 0xF4, 0x7C, 0xF4, 0x7D, 0xF4, 0x7E, 0xF4, 0x80, /* 0x58-0x5B */ - 0xF4, 0x81, 0xF4, 0x82, 0xF4, 0x83, 0xF4, 0x84, /* 0x5C-0x5F */ - 0xF4, 0x85, 0xF4, 0x86, 0xF4, 0x87, 0xF4, 0x88, /* 0x60-0x63 */ - 0xF4, 0x89, 0xF4, 0x8A, 0xF4, 0x8B, 0xF4, 0x8C, /* 0x64-0x67 */ - 0xF4, 0x8D, 0xF4, 0x8E, 0xF4, 0x8F, 0xF4, 0x90, /* 0x68-0x6B */ - 0xF4, 0x91, 0xF4, 0x92, 0xF4, 0x93, 0xF4, 0x94, /* 0x6C-0x6F */ - 0xF4, 0x95, 0xF4, 0x96, 0xF4, 0x97, 0xF4, 0x98, /* 0x70-0x73 */ - 0xF4, 0x99, 0xF4, 0x9A, 0xF4, 0x9B, 0xF4, 0x9C, /* 0x74-0x77 */ - 0xF4, 0x9D, 0xF4, 0x9E, 0xF4, 0x9F, 0xF4, 0xA0, /* 0x78-0x7B */ - 0xF5, 0x40, 0xF5, 0x41, 0xF5, 0x42, 0xF5, 0x43, /* 0x7C-0x7F */ - - 0xF5, 0x44, 0xF5, 0x45, 0xF5, 0x46, 0xF5, 0x47, /* 0x80-0x83 */ - 0xF5, 0x48, 0xF5, 0x49, 0xF5, 0x4A, 0xF5, 0x4B, /* 0x84-0x87 */ - 0xF5, 0x4C, 0xF5, 0x4D, 0xF5, 0x4E, 0xF5, 0x4F, /* 0x88-0x8B */ - 0xF5, 0x50, 0xF5, 0x51, 0xF5, 0x52, 0xF5, 0x53, /* 0x8C-0x8F */ - 0xF5, 0x54, 0xF5, 0x55, 0xF5, 0x56, 0xF5, 0x57, /* 0x90-0x93 */ - 0xF5, 0x58, 0xF5, 0x59, 0xF5, 0x5A, 0xF5, 0x5B, /* 0x94-0x97 */ - 0xF5, 0x5C, 0xF5, 0x5D, 0xF5, 0x5E, 0xF5, 0x5F, /* 0x98-0x9B */ - 0xF5, 0x60, 0xF5, 0x61, 0xF5, 0x62, 0xF5, 0x63, /* 0x9C-0x9F */ - 0xF5, 0x64, 0xF5, 0x65, 0xF5, 0x66, 0xF5, 0x67, /* 0xA0-0xA3 */ - 0xF5, 0x68, 0xF5, 0x69, 0xF5, 0x6A, 0xF5, 0x6B, /* 0xA4-0xA7 */ - 0xF5, 0x6C, 0xF5, 0x6D, 0xF5, 0x6E, 0xF5, 0x6F, /* 0xA8-0xAB */ - 0xF5, 0x70, 0xF5, 0x71, 0xF5, 0x72, 0xF5, 0x73, /* 0xAC-0xAF */ - 0xF5, 0x74, 0xF5, 0x75, 0xF5, 0x76, 0xF5, 0x77, /* 0xB0-0xB3 */ - 0xF5, 0x78, 0xF5, 0x79, 0xF5, 0x7A, 0xF5, 0x7B, /* 0xB4-0xB7 */ - 0xF5, 0x7C, 0xF5, 0x7D, 0xF5, 0x7E, 0xF5, 0x80, /* 0xB8-0xBB */ - 0xF5, 0x81, 0xF5, 0x82, 0xF5, 0x83, 0xF5, 0x84, /* 0xBC-0xBF */ - 0xF5, 0x85, 0xF5, 0x86, 0xF5, 0x87, 0xF5, 0x88, /* 0xC0-0xC3 */ - 0xF5, 0x89, 0xF5, 0x8A, 0xF5, 0x8B, 0xF5, 0x8C, /* 0xC4-0xC7 */ - 0xF5, 0x8D, 0xF5, 0x8E, 0xF5, 0x8F, 0xF5, 0x90, /* 0xC8-0xCB */ - 0xF5, 0x91, 0xF5, 0x92, 0xF5, 0x93, 0xF5, 0x94, /* 0xCC-0xCF */ - 0xF5, 0x95, 0xF5, 0x96, 0xF5, 0x97, 0xF5, 0x98, /* 0xD0-0xD3 */ - 0xF5, 0x99, 0xF5, 0x9A, 0xF5, 0x9B, 0xF5, 0x9C, /* 0xD4-0xD7 */ - 0xF5, 0x9D, 0xF5, 0x9E, 0xF5, 0x9F, 0xF5, 0xA0, /* 0xD8-0xDB */ - 0xF6, 0x40, 0xF6, 0x41, 0xF6, 0x42, 0xF6, 0x43, /* 0xDC-0xDF */ - 0xF6, 0x44, 0xF6, 0x45, 0xF6, 0x46, 0xF6, 0x47, /* 0xE0-0xE3 */ - 0xF6, 0x48, 0xF6, 0x49, 0xF6, 0x4A, 0xF6, 0x4B, /* 0xE4-0xE7 */ - 0xF6, 0x4C, 0xF6, 0x4D, 0xF6, 0x4E, 0xF6, 0x4F, /* 0xE8-0xEB */ - 0xF6, 0x50, 0xF6, 0x51, 0xF6, 0x52, 0xF6, 0x53, /* 0xEC-0xEF */ - 0xF6, 0x54, 0xF6, 0x55, 0xF6, 0x56, 0xF6, 0x57, /* 0xF0-0xF3 */ - 0xF6, 0x58, 0xF6, 0x59, 0xF6, 0x5A, 0xF6, 0x5B, /* 0xF4-0xF7 */ - 0xF6, 0x5C, 0xF6, 0x5D, 0xF6, 0x5E, 0xF6, 0x5F, /* 0xF8-0xFB */ - 0xF6, 0x60, 0xF6, 0x61, 0xF6, 0x62, 0xF6, 0x63, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_9C[512] = { - 0xF6, 0x64, 0xF6, 0x65, 0xF6, 0x66, 0xF6, 0x67, /* 0x00-0x03 */ - 0xF6, 0x68, 0xF6, 0x69, 0xF6, 0x6A, 0xF6, 0x6B, /* 0x04-0x07 */ - 0xF6, 0x6C, 0xF6, 0x6D, 0xF6, 0x6E, 0xF6, 0x6F, /* 0x08-0x0B */ - 0xF6, 0x70, 0xF6, 0x71, 0xF6, 0x72, 0xF6, 0x73, /* 0x0C-0x0F */ - 0xF6, 0x74, 0xF6, 0x75, 0xF6, 0x76, 0xF6, 0x77, /* 0x10-0x13 */ - 0xF6, 0x78, 0xF6, 0x79, 0xF6, 0x7A, 0xF6, 0x7B, /* 0x14-0x17 */ - 0xF6, 0x7C, 0xF6, 0x7D, 0xF6, 0x7E, 0xF6, 0x80, /* 0x18-0x1B */ - 0xF6, 0x81, 0xF6, 0x82, 0xF6, 0x83, 0xF6, 0x84, /* 0x1C-0x1F */ - 0xF6, 0x85, 0xF6, 0x86, 0xF6, 0x87, 0xF6, 0x88, /* 0x20-0x23 */ - 0xF6, 0x89, 0xF6, 0x8A, 0xF6, 0x8B, 0xF6, 0x8C, /* 0x24-0x27 */ - 0xF6, 0x8D, 0xF6, 0x8E, 0xF6, 0x8F, 0xF6, 0x90, /* 0x28-0x2B */ - 0xF6, 0x91, 0xF6, 0x92, 0xF6, 0x93, 0xF6, 0x94, /* 0x2C-0x2F */ - 0xF6, 0x95, 0xF6, 0x96, 0xF6, 0x97, 0xF6, 0x98, /* 0x30-0x33 */ - 0xF6, 0x99, 0xF6, 0x9A, 0xF6, 0x9B, 0xF6, 0x9C, /* 0x34-0x37 */ - 0xF6, 0x9D, 0xF6, 0x9E, 0xF6, 0x9F, 0xF6, 0xA0, /* 0x38-0x3B */ - 0xF7, 0x40, 0xF7, 0x41, 0xF7, 0x42, 0xF7, 0x43, /* 0x3C-0x3F */ - 0xF7, 0x44, 0xF7, 0x45, 0xF7, 0x46, 0xF7, 0x47, /* 0x40-0x43 */ - 0xF7, 0x48, 0xF7, 0x49, 0xF7, 0x4A, 0xF7, 0x4B, /* 0x44-0x47 */ - 0xF7, 0x4C, 0xF7, 0x4D, 0xF7, 0x4E, 0xF7, 0x4F, /* 0x48-0x4B */ - 0xF7, 0x50, 0xF7, 0x51, 0xF7, 0x52, 0xF7, 0x53, /* 0x4C-0x4F */ - 0xF7, 0x54, 0xF7, 0x55, 0xF7, 0x56, 0xF7, 0x57, /* 0x50-0x53 */ - 0xF7, 0x58, 0xF7, 0x59, 0xF7, 0x5A, 0xF7, 0x5B, /* 0x54-0x57 */ - 0xF7, 0x5C, 0xF7, 0x5D, 0xF7, 0x5E, 0xF7, 0x5F, /* 0x58-0x5B */ - 0xF7, 0x60, 0xF7, 0x61, 0xF7, 0x62, 0xF7, 0x63, /* 0x5C-0x5F */ - 0xF7, 0x64, 0xF7, 0x65, 0xF7, 0x66, 0xF7, 0x67, /* 0x60-0x63 */ - 0xF7, 0x68, 0xF7, 0x69, 0xF7, 0x6A, 0xF7, 0x6B, /* 0x64-0x67 */ - 0xF7, 0x6C, 0xF7, 0x6D, 0xF7, 0x6E, 0xF7, 0x6F, /* 0x68-0x6B */ - 0xF7, 0x70, 0xF7, 0x71, 0xF7, 0x72, 0xF7, 0x73, /* 0x6C-0x6F */ - 0xF7, 0x74, 0xF7, 0x75, 0xF7, 0x76, 0xF7, 0x77, /* 0x70-0x73 */ - 0xF7, 0x78, 0xF7, 0x79, 0xF7, 0x7A, 0xF7, 0x7B, /* 0x74-0x77 */ - 0xF7, 0x7C, 0xF7, 0x7D, 0xF7, 0x7E, 0xF7, 0x80, /* 0x78-0x7B */ - 0xD3, 0xE3, 0xF7, 0x81, 0xF7, 0x82, 0xF6, 0xCF, /* 0x7C-0x7F */ - - 0xF7, 0x83, 0xC2, 0xB3, 0xF6, 0xD0, 0xF7, 0x84, /* 0x80-0x83 */ - 0xF7, 0x85, 0xF6, 0xD1, 0xF6, 0xD2, 0xF6, 0xD3, /* 0x84-0x87 */ - 0xF6, 0xD4, 0xF7, 0x86, 0xF7, 0x87, 0xF6, 0xD6, /* 0x88-0x8B */ - 0xF7, 0x88, 0xB1, 0xAB, 0xF6, 0xD7, 0xF7, 0x89, /* 0x8C-0x8F */ - 0xF6, 0xD8, 0xF6, 0xD9, 0xF6, 0xDA, 0xF7, 0x8A, /* 0x90-0x93 */ - 0xF6, 0xDB, 0xF6, 0xDC, 0xF7, 0x8B, 0xF7, 0x8C, /* 0x94-0x97 */ - 0xF7, 0x8D, 0xF7, 0x8E, 0xF6, 0xDD, 0xF6, 0xDE, /* 0x98-0x9B */ - 0xCF, 0xCA, 0xF7, 0x8F, 0xF6, 0xDF, 0xF6, 0xE0, /* 0x9C-0x9F */ - 0xF6, 0xE1, 0xF6, 0xE2, 0xF6, 0xE3, 0xF6, 0xE4, /* 0xA0-0xA3 */ - 0xC0, 0xF0, 0xF6, 0xE5, 0xF6, 0xE6, 0xF6, 0xE7, /* 0xA4-0xA7 */ - 0xF6, 0xE8, 0xF6, 0xE9, 0xF7, 0x90, 0xF6, 0xEA, /* 0xA8-0xAB */ - 0xF7, 0x91, 0xF6, 0xEB, 0xF6, 0xEC, 0xF7, 0x92, /* 0xAC-0xAF */ - 0xF6, 0xED, 0xF6, 0xEE, 0xF6, 0xEF, 0xF6, 0xF0, /* 0xB0-0xB3 */ - 0xF6, 0xF1, 0xF6, 0xF2, 0xF6, 0xF3, 0xF6, 0xF4, /* 0xB4-0xB7 */ - 0xBE, 0xA8, 0xF7, 0x93, 0xF6, 0xF5, 0xF6, 0xF6, /* 0xB8-0xBB */ - 0xF6, 0xF7, 0xF6, 0xF8, 0xF7, 0x94, 0xF7, 0x95, /* 0xBC-0xBF */ - 0xF7, 0x96, 0xF7, 0x97, 0xF7, 0x98, 0xC8, 0xFA, /* 0xC0-0xC3 */ - 0xF6, 0xF9, 0xF6, 0xFA, 0xF6, 0xFB, 0xF6, 0xFC, /* 0xC4-0xC7 */ - 0xF7, 0x99, 0xF7, 0x9A, 0xF6, 0xFD, 0xF6, 0xFE, /* 0xC8-0xCB */ - 0xF7, 0xA1, 0xF7, 0xA2, 0xF7, 0xA3, 0xF7, 0xA4, /* 0xCC-0xCF */ - 0xF7, 0xA5, 0xF7, 0x9B, 0xF7, 0x9C, 0xF7, 0xA6, /* 0xD0-0xD3 */ - 0xF7, 0xA7, 0xF7, 0xA8, 0xB1, 0xEE, 0xF7, 0xA9, /* 0xD4-0xD7 */ - 0xF7, 0xAA, 0xF7, 0xAB, 0xF7, 0x9D, 0xF7, 0x9E, /* 0xD8-0xDB */ - 0xF7, 0xAC, 0xF7, 0xAD, 0xC1, 0xDB, 0xF7, 0xAE, /* 0xDC-0xDF */ - 0xF7, 0x9F, 0xF7, 0xA0, 0xF7, 0xAF, 0xF8, 0x40, /* 0xE0-0xE3 */ - 0xF8, 0x41, 0xF8, 0x42, 0xF8, 0x43, 0xF8, 0x44, /* 0xE4-0xE7 */ - 0xF8, 0x45, 0xF8, 0x46, 0xF8, 0x47, 0xF8, 0x48, /* 0xE8-0xEB */ - 0xF8, 0x49, 0xF8, 0x4A, 0xF8, 0x4B, 0xF8, 0x4C, /* 0xEC-0xEF */ - 0xF8, 0x4D, 0xF8, 0x4E, 0xF8, 0x4F, 0xF8, 0x50, /* 0xF0-0xF3 */ - 0xF8, 0x51, 0xF8, 0x52, 0xF8, 0x53, 0xF8, 0x54, /* 0xF4-0xF7 */ - 0xF8, 0x55, 0xF8, 0x56, 0xF8, 0x57, 0xF8, 0x58, /* 0xF8-0xFB */ - 0xF8, 0x59, 0xF8, 0x5A, 0xF8, 0x5B, 0xF8, 0x5C, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_9D[512] = { - 0xF8, 0x5D, 0xF8, 0x5E, 0xF8, 0x5F, 0xF8, 0x60, /* 0x00-0x03 */ - 0xF8, 0x61, 0xF8, 0x62, 0xF8, 0x63, 0xF8, 0x64, /* 0x04-0x07 */ - 0xF8, 0x65, 0xF8, 0x66, 0xF8, 0x67, 0xF8, 0x68, /* 0x08-0x0B */ - 0xF8, 0x69, 0xF8, 0x6A, 0xF8, 0x6B, 0xF8, 0x6C, /* 0x0C-0x0F */ - 0xF8, 0x6D, 0xF8, 0x6E, 0xF8, 0x6F, 0xF8, 0x70, /* 0x10-0x13 */ - 0xF8, 0x71, 0xF8, 0x72, 0xF8, 0x73, 0xF8, 0x74, /* 0x14-0x17 */ - 0xF8, 0x75, 0xF8, 0x76, 0xF8, 0x77, 0xF8, 0x78, /* 0x18-0x1B */ - 0xF8, 0x79, 0xF8, 0x7A, 0xF8, 0x7B, 0xF8, 0x7C, /* 0x1C-0x1F */ - 0xF8, 0x7D, 0xF8, 0x7E, 0xF8, 0x80, 0xF8, 0x81, /* 0x20-0x23 */ - 0xF8, 0x82, 0xF8, 0x83, 0xF8, 0x84, 0xF8, 0x85, /* 0x24-0x27 */ - 0xF8, 0x86, 0xF8, 0x87, 0xF8, 0x88, 0xF8, 0x89, /* 0x28-0x2B */ - 0xF8, 0x8A, 0xF8, 0x8B, 0xF8, 0x8C, 0xF8, 0x8D, /* 0x2C-0x2F */ - 0xF8, 0x8E, 0xF8, 0x8F, 0xF8, 0x90, 0xF8, 0x91, /* 0x30-0x33 */ - 0xF8, 0x92, 0xF8, 0x93, 0xF8, 0x94, 0xF8, 0x95, /* 0x34-0x37 */ - 0xF8, 0x96, 0xF8, 0x97, 0xF8, 0x98, 0xF8, 0x99, /* 0x38-0x3B */ - 0xF8, 0x9A, 0xF8, 0x9B, 0xF8, 0x9C, 0xF8, 0x9D, /* 0x3C-0x3F */ - 0xF8, 0x9E, 0xF8, 0x9F, 0xF8, 0xA0, 0xF9, 0x40, /* 0x40-0x43 */ - 0xF9, 0x41, 0xF9, 0x42, 0xF9, 0x43, 0xF9, 0x44, /* 0x44-0x47 */ - 0xF9, 0x45, 0xF9, 0x46, 0xF9, 0x47, 0xF9, 0x48, /* 0x48-0x4B */ - 0xF9, 0x49, 0xF9, 0x4A, 0xF9, 0x4B, 0xF9, 0x4C, /* 0x4C-0x4F */ - 0xF9, 0x4D, 0xF9, 0x4E, 0xF9, 0x4F, 0xF9, 0x50, /* 0x50-0x53 */ - 0xF9, 0x51, 0xF9, 0x52, 0xF9, 0x53, 0xF9, 0x54, /* 0x54-0x57 */ - 0xF9, 0x55, 0xF9, 0x56, 0xF9, 0x57, 0xF9, 0x58, /* 0x58-0x5B */ - 0xF9, 0x59, 0xF9, 0x5A, 0xF9, 0x5B, 0xF9, 0x5C, /* 0x5C-0x5F */ - 0xF9, 0x5D, 0xF9, 0x5E, 0xF9, 0x5F, 0xF9, 0x60, /* 0x60-0x63 */ - 0xF9, 0x61, 0xF9, 0x62, 0xF9, 0x63, 0xF9, 0x64, /* 0x64-0x67 */ - 0xF9, 0x65, 0xF9, 0x66, 0xF9, 0x67, 0xF9, 0x68, /* 0x68-0x6B */ - 0xF9, 0x69, 0xF9, 0x6A, 0xF9, 0x6B, 0xF9, 0x6C, /* 0x6C-0x6F */ - 0xF9, 0x6D, 0xF9, 0x6E, 0xF9, 0x6F, 0xF9, 0x70, /* 0x70-0x73 */ - 0xF9, 0x71, 0xF9, 0x72, 0xF9, 0x73, 0xF9, 0x74, /* 0x74-0x77 */ - 0xF9, 0x75, 0xF9, 0x76, 0xF9, 0x77, 0xF9, 0x78, /* 0x78-0x7B */ - 0xF9, 0x79, 0xF9, 0x7A, 0xF9, 0x7B, 0xF9, 0x7C, /* 0x7C-0x7F */ - - 0xF9, 0x7D, 0xF9, 0x7E, 0xF9, 0x80, 0xF9, 0x81, /* 0x80-0x83 */ - 0xF9, 0x82, 0xF9, 0x83, 0xF9, 0x84, 0xF9, 0x85, /* 0x84-0x87 */ - 0xF9, 0x86, 0xF9, 0x87, 0xF9, 0x88, 0xF9, 0x89, /* 0x88-0x8B */ - 0xF9, 0x8A, 0xF9, 0x8B, 0xF9, 0x8C, 0xF9, 0x8D, /* 0x8C-0x8F */ - 0xF9, 0x8E, 0xF9, 0x8F, 0xF9, 0x90, 0xF9, 0x91, /* 0x90-0x93 */ - 0xF9, 0x92, 0xF9, 0x93, 0xF9, 0x94, 0xF9, 0x95, /* 0x94-0x97 */ - 0xF9, 0x96, 0xF9, 0x97, 0xF9, 0x98, 0xF9, 0x99, /* 0x98-0x9B */ - 0xF9, 0x9A, 0xF9, 0x9B, 0xF9, 0x9C, 0xF9, 0x9D, /* 0x9C-0x9F */ - 0xF9, 0x9E, 0xF9, 0x9F, 0xF9, 0xA0, 0xFA, 0x40, /* 0xA0-0xA3 */ - 0xFA, 0x41, 0xFA, 0x42, 0xFA, 0x43, 0xFA, 0x44, /* 0xA4-0xA7 */ - 0xFA, 0x45, 0xFA, 0x46, 0xFA, 0x47, 0xFA, 0x48, /* 0xA8-0xAB */ - 0xFA, 0x49, 0xFA, 0x4A, 0xFA, 0x4B, 0xFA, 0x4C, /* 0xAC-0xAF */ - 0xFA, 0x4D, 0xFA, 0x4E, 0xFA, 0x4F, 0xFA, 0x50, /* 0xB0-0xB3 */ - 0xFA, 0x51, 0xFA, 0x52, 0xFA, 0x53, 0xFA, 0x54, /* 0xB4-0xB7 */ - 0xFA, 0x55, 0xFA, 0x56, 0xFA, 0x57, 0xFA, 0x58, /* 0xB8-0xBB */ - 0xFA, 0x59, 0xFA, 0x5A, 0xFA, 0x5B, 0xFA, 0x5C, /* 0xBC-0xBF */ - 0xFA, 0x5D, 0xFA, 0x5E, 0xFA, 0x5F, 0xFA, 0x60, /* 0xC0-0xC3 */ - 0xFA, 0x61, 0xFA, 0x62, 0xFA, 0x63, 0xFA, 0x64, /* 0xC4-0xC7 */ - 0xFA, 0x65, 0xFA, 0x66, 0xFA, 0x67, 0xFA, 0x68, /* 0xC8-0xCB */ - 0xFA, 0x69, 0xFA, 0x6A, 0xFA, 0x6B, 0xFA, 0x6C, /* 0xCC-0xCF */ - 0xFA, 0x6D, 0xFA, 0x6E, 0xFA, 0x6F, 0xFA, 0x70, /* 0xD0-0xD3 */ - 0xFA, 0x71, 0xFA, 0x72, 0xFA, 0x73, 0xFA, 0x74, /* 0xD4-0xD7 */ - 0xFA, 0x75, 0xFA, 0x76, 0xFA, 0x77, 0xFA, 0x78, /* 0xD8-0xDB */ - 0xFA, 0x79, 0xFA, 0x7A, 0xFA, 0x7B, 0xFA, 0x7C, /* 0xDC-0xDF */ - 0xFA, 0x7D, 0xFA, 0x7E, 0xFA, 0x80, 0xFA, 0x81, /* 0xE0-0xE3 */ - 0xFA, 0x82, 0xFA, 0x83, 0xFA, 0x84, 0xFA, 0x85, /* 0xE4-0xE7 */ - 0xFA, 0x86, 0xFA, 0x87, 0xFA, 0x88, 0xFA, 0x89, /* 0xE8-0xEB */ - 0xFA, 0x8A, 0xFA, 0x8B, 0xFA, 0x8C, 0xFA, 0x8D, /* 0xEC-0xEF */ - 0xFA, 0x8E, 0xFA, 0x8F, 0xFA, 0x90, 0xFA, 0x91, /* 0xF0-0xF3 */ - 0xFA, 0x92, 0xFA, 0x93, 0xFA, 0x94, 0xFA, 0x95, /* 0xF4-0xF7 */ - 0xFA, 0x96, 0xFA, 0x97, 0xFA, 0x98, 0xFA, 0x99, /* 0xF8-0xFB */ - 0xFA, 0x9A, 0xFA, 0x9B, 0xFA, 0x9C, 0xFA, 0x9D, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_9E[512] = { - 0xFA, 0x9E, 0xFA, 0x9F, 0xFA, 0xA0, 0xFB, 0x40, /* 0x00-0x03 */ - 0xFB, 0x41, 0xFB, 0x42, 0xFB, 0x43, 0xFB, 0x44, /* 0x04-0x07 */ - 0xFB, 0x45, 0xFB, 0x46, 0xFB, 0x47, 0xFB, 0x48, /* 0x08-0x0B */ - 0xFB, 0x49, 0xFB, 0x4A, 0xFB, 0x4B, 0xFB, 0x4C, /* 0x0C-0x0F */ - 0xFB, 0x4D, 0xFB, 0x4E, 0xFB, 0x4F, 0xFB, 0x50, /* 0x10-0x13 */ - 0xFB, 0x51, 0xFB, 0x52, 0xFB, 0x53, 0xFB, 0x54, /* 0x14-0x17 */ - 0xFB, 0x55, 0xFB, 0x56, 0xFB, 0x57, 0xFB, 0x58, /* 0x18-0x1B */ - 0xFB, 0x59, 0xFB, 0x5A, 0xFB, 0x5B, 0xC4, 0xF1, /* 0x1C-0x1F */ - 0xF0, 0xAF, 0xBC, 0xA6, 0xF0, 0xB0, 0xC3, 0xF9, /* 0x20-0x23 */ - 0xFB, 0x5C, 0xC5, 0xB8, 0xD1, 0xBB, 0xFB, 0x5D, /* 0x24-0x27 */ - 0xF0, 0xB1, 0xF0, 0xB2, 0xF0, 0xB3, 0xF0, 0xB4, /* 0x28-0x2B */ - 0xF0, 0xB5, 0xD1, 0xBC, 0xFB, 0x5E, 0xD1, 0xEC, /* 0x2C-0x2F */ - 0xFB, 0x5F, 0xF0, 0xB7, 0xF0, 0xB6, 0xD4, 0xA7, /* 0x30-0x33 */ - 0xFB, 0x60, 0xCD, 0xD2, 0xF0, 0xB8, 0xF0, 0xBA, /* 0x34-0x37 */ - 0xF0, 0xB9, 0xF0, 0xBB, 0xF0, 0xBC, 0xFB, 0x61, /* 0x38-0x3B */ - 0xFB, 0x62, 0xB8, 0xEB, 0xF0, 0xBD, 0xBA, 0xE8, /* 0x3C-0x3F */ - 0xFB, 0x63, 0xF0, 0xBE, 0xF0, 0xBF, 0xBE, 0xE9, /* 0x40-0x43 */ - 0xF0, 0xC0, 0xB6, 0xEC, 0xF0, 0xC1, 0xF0, 0xC2, /* 0x44-0x47 */ - 0xF0, 0xC3, 0xF0, 0xC4, 0xC8, 0xB5, 0xF0, 0xC5, /* 0x48-0x4B */ - 0xF0, 0xC6, 0xFB, 0x64, 0xF0, 0xC7, 0xC5, 0xF4, /* 0x4C-0x4F */ - 0xFB, 0x65, 0xF0, 0xC8, 0xFB, 0x66, 0xFB, 0x67, /* 0x50-0x53 */ - 0xFB, 0x68, 0xF0, 0xC9, 0xFB, 0x69, 0xF0, 0xCA, /* 0x54-0x57 */ - 0xF7, 0xBD, 0xFB, 0x6A, 0xF0, 0xCB, 0xF0, 0xCC, /* 0x58-0x5B */ - 0xF0, 0xCD, 0xFB, 0x6B, 0xF0, 0xCE, 0xFB, 0x6C, /* 0x5C-0x5F */ - 0xFB, 0x6D, 0xFB, 0x6E, 0xFB, 0x6F, 0xF0, 0xCF, /* 0x60-0x63 */ - 0xBA, 0xD7, 0xFB, 0x70, 0xF0, 0xD0, 0xF0, 0xD1, /* 0x64-0x67 */ - 0xF0, 0xD2, 0xF0, 0xD3, 0xF0, 0xD4, 0xF0, 0xD5, /* 0x68-0x6B */ - 0xF0, 0xD6, 0xF0, 0xD8, 0xFB, 0x71, 0xFB, 0x72, /* 0x6C-0x6F */ - 0xD3, 0xA5, 0xF0, 0xD7, 0xFB, 0x73, 0xF0, 0xD9, /* 0x70-0x73 */ - 0xFB, 0x74, 0xFB, 0x75, 0xFB, 0x76, 0xFB, 0x77, /* 0x74-0x77 */ - 0xFB, 0x78, 0xFB, 0x79, 0xFB, 0x7A, 0xFB, 0x7B, /* 0x78-0x7B */ - 0xFB, 0x7C, 0xFB, 0x7D, 0xF5, 0xBA, 0xC2, 0xB9, /* 0x7C-0x7F */ - - 0xFB, 0x7E, 0xFB, 0x80, 0xF7, 0xE4, 0xFB, 0x81, /* 0x80-0x83 */ - 0xFB, 0x82, 0xFB, 0x83, 0xFB, 0x84, 0xF7, 0xE5, /* 0x84-0x87 */ - 0xF7, 0xE6, 0xFB, 0x85, 0xFB, 0x86, 0xF7, 0xE7, /* 0x88-0x8B */ - 0xFB, 0x87, 0xFB, 0x88, 0xFB, 0x89, 0xFB, 0x8A, /* 0x8C-0x8F */ - 0xFB, 0x8B, 0xFB, 0x8C, 0xF7, 0xE8, 0xC2, 0xB4, /* 0x90-0x93 */ - 0xFB, 0x8D, 0xFB, 0x8E, 0xFB, 0x8F, 0xFB, 0x90, /* 0x94-0x97 */ - 0xFB, 0x91, 0xFB, 0x92, 0xFB, 0x93, 0xFB, 0x94, /* 0x98-0x9B */ - 0xFB, 0x95, 0xF7, 0xEA, 0xFB, 0x96, 0xF7, 0xEB, /* 0x9C-0x9F */ - 0xFB, 0x97, 0xFB, 0x98, 0xFB, 0x99, 0xFB, 0x9A, /* 0xA0-0xA3 */ - 0xFB, 0x9B, 0xFB, 0x9C, 0xC2, 0xF3, 0xFB, 0x9D, /* 0xA4-0xA7 */ - 0xFB, 0x9E, 0xFB, 0x9F, 0xFB, 0xA0, 0xFC, 0x40, /* 0xA8-0xAB */ - 0xFC, 0x41, 0xFC, 0x42, 0xFC, 0x43, 0xFC, 0x44, /* 0xAC-0xAF */ - 0xFC, 0x45, 0xFC, 0x46, 0xFC, 0x47, 0xFC, 0x48, /* 0xB0-0xB3 */ - 0xF4, 0xF0, 0xFC, 0x49, 0xFC, 0x4A, 0xFC, 0x4B, /* 0xB4-0xB7 */ - 0xF4, 0xEF, 0xFC, 0x4C, 0xFC, 0x4D, 0xC2, 0xE9, /* 0xB8-0xBB */ - 0xFC, 0x4E, 0xF7, 0xE1, 0xF7, 0xE2, 0xFC, 0x4F, /* 0xBC-0xBF */ - 0xFC, 0x50, 0xFC, 0x51, 0xFC, 0x52, 0xFC, 0x53, /* 0xC0-0xC3 */ - 0xBB, 0xC6, 0xFC, 0x54, 0xFC, 0x55, 0xFC, 0x56, /* 0xC4-0xC7 */ - 0xFC, 0x57, 0xD9, 0xE4, 0xFC, 0x58, 0xFC, 0x59, /* 0xC8-0xCB */ - 0xFC, 0x5A, 0xCA, 0xF2, 0xC0, 0xE8, 0xF0, 0xA4, /* 0xCC-0xCF */ - 0xFC, 0x5B, 0xBA, 0xDA, 0xFC, 0x5C, 0xFC, 0x5D, /* 0xD0-0xD3 */ - 0xC7, 0xAD, 0xFC, 0x5E, 0xFC, 0x5F, 0xFC, 0x60, /* 0xD4-0xD7 */ - 0xC4, 0xAC, 0xFC, 0x61, 0xFC, 0x62, 0xF7, 0xEC, /* 0xD8-0xDB */ - 0xF7, 0xED, 0xF7, 0xEE, 0xFC, 0x63, 0xF7, 0xF0, /* 0xDC-0xDF */ - 0xF7, 0xEF, 0xFC, 0x64, 0xF7, 0xF1, 0xFC, 0x65, /* 0xE0-0xE3 */ - 0xFC, 0x66, 0xF7, 0xF4, 0xFC, 0x67, 0xF7, 0xF3, /* 0xE4-0xE7 */ - 0xFC, 0x68, 0xF7, 0xF2, 0xF7, 0xF5, 0xFC, 0x69, /* 0xE8-0xEB */ - 0xFC, 0x6A, 0xFC, 0x6B, 0xFC, 0x6C, 0xF7, 0xF6, /* 0xEC-0xEF */ - 0xFC, 0x6D, 0xFC, 0x6E, 0xFC, 0x6F, 0xFC, 0x70, /* 0xF0-0xF3 */ - 0xFC, 0x71, 0xFC, 0x72, 0xFC, 0x73, 0xFC, 0x74, /* 0xF4-0xF7 */ - 0xFC, 0x75, 0xED, 0xE9, 0xFC, 0x76, 0xED, 0xEA, /* 0xF8-0xFB */ - 0xED, 0xEB, 0xFC, 0x77, 0xF6, 0xBC, 0xFC, 0x78, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_9F[512] = { - 0xFC, 0x79, 0xFC, 0x7A, 0xFC, 0x7B, 0xFC, 0x7C, /* 0x00-0x03 */ - 0xFC, 0x7D, 0xFC, 0x7E, 0xFC, 0x80, 0xFC, 0x81, /* 0x04-0x07 */ - 0xFC, 0x82, 0xFC, 0x83, 0xFC, 0x84, 0xF6, 0xBD, /* 0x08-0x0B */ - 0xFC, 0x85, 0xF6, 0xBE, 0xB6, 0xA6, 0xFC, 0x86, /* 0x0C-0x0F */ - 0xD8, 0xBE, 0xFC, 0x87, 0xFC, 0x88, 0xB9, 0xC4, /* 0x10-0x13 */ - 0xFC, 0x89, 0xFC, 0x8A, 0xFC, 0x8B, 0xD8, 0xBB, /* 0x14-0x17 */ - 0xFC, 0x8C, 0xDC, 0xB1, 0xFC, 0x8D, 0xFC, 0x8E, /* 0x18-0x1B */ - 0xFC, 0x8F, 0xFC, 0x90, 0xFC, 0x91, 0xFC, 0x92, /* 0x1C-0x1F */ - 0xCA, 0xF3, 0xFC, 0x93, 0xF7, 0xF7, 0xFC, 0x94, /* 0x20-0x23 */ - 0xFC, 0x95, 0xFC, 0x96, 0xFC, 0x97, 0xFC, 0x98, /* 0x24-0x27 */ - 0xFC, 0x99, 0xFC, 0x9A, 0xFC, 0x9B, 0xFC, 0x9C, /* 0x28-0x2B */ - 0xF7, 0xF8, 0xFC, 0x9D, 0xFC, 0x9E, 0xF7, 0xF9, /* 0x2C-0x2F */ - 0xFC, 0x9F, 0xFC, 0xA0, 0xFD, 0x40, 0xFD, 0x41, /* 0x30-0x33 */ - 0xFD, 0x42, 0xFD, 0x43, 0xFD, 0x44, 0xF7, 0xFB, /* 0x34-0x37 */ - 0xFD, 0x45, 0xF7, 0xFA, 0xFD, 0x46, 0xB1, 0xC7, /* 0x38-0x3B */ - 0xFD, 0x47, 0xF7, 0xFC, 0xF7, 0xFD, 0xFD, 0x48, /* 0x3C-0x3F */ - 0xFD, 0x49, 0xFD, 0x4A, 0xFD, 0x4B, 0xFD, 0x4C, /* 0x40-0x43 */ - 0xF7, 0xFE, 0xFD, 0x4D, 0xFD, 0x4E, 0xFD, 0x4F, /* 0x44-0x47 */ - 0xFD, 0x50, 0xFD, 0x51, 0xFD, 0x52, 0xFD, 0x53, /* 0x48-0x4B */ - 0xFD, 0x54, 0xFD, 0x55, 0xFD, 0x56, 0xFD, 0x57, /* 0x4C-0x4F */ - 0xC6, 0xEB, 0xEC, 0xB4, 0xFD, 0x58, 0xFD, 0x59, /* 0x50-0x53 */ - 0xFD, 0x5A, 0xFD, 0x5B, 0xFD, 0x5C, 0xFD, 0x5D, /* 0x54-0x57 */ - 0xFD, 0x5E, 0xFD, 0x5F, 0xFD, 0x60, 0xFD, 0x61, /* 0x58-0x5B */ - 0xFD, 0x62, 0xFD, 0x63, 0xFD, 0x64, 0xFD, 0x65, /* 0x5C-0x5F */ - 0xFD, 0x66, 0xFD, 0x67, 0xFD, 0x68, 0xFD, 0x69, /* 0x60-0x63 */ - 0xFD, 0x6A, 0xFD, 0x6B, 0xFD, 0x6C, 0xFD, 0x6D, /* 0x64-0x67 */ - 0xFD, 0x6E, 0xFD, 0x6F, 0xFD, 0x70, 0xFD, 0x71, /* 0x68-0x6B */ - 0xFD, 0x72, 0xFD, 0x73, 0xFD, 0x74, 0xFD, 0x75, /* 0x6C-0x6F */ - 0xFD, 0x76, 0xFD, 0x77, 0xFD, 0x78, 0xFD, 0x79, /* 0x70-0x73 */ - 0xFD, 0x7A, 0xFD, 0x7B, 0xFD, 0x7C, 0xFD, 0x7D, /* 0x74-0x77 */ - 0xFD, 0x7E, 0xFD, 0x80, 0xFD, 0x81, 0xFD, 0x82, /* 0x78-0x7B */ - 0xFD, 0x83, 0xFD, 0x84, 0xFD, 0x85, 0xB3, 0xDD, /* 0x7C-0x7F */ - - 0xF6, 0xB3, 0xFD, 0x86, 0xFD, 0x87, 0xF6, 0xB4, /* 0x80-0x83 */ - 0xC1, 0xE4, 0xF6, 0xB5, 0xF6, 0xB6, 0xF6, 0xB7, /* 0x84-0x87 */ - 0xF6, 0xB8, 0xF6, 0xB9, 0xF6, 0xBA, 0xC8, 0xA3, /* 0x88-0x8B */ - 0xF6, 0xBB, 0xFD, 0x88, 0xFD, 0x89, 0xFD, 0x8A, /* 0x8C-0x8F */ - 0xFD, 0x8B, 0xFD, 0x8C, 0xFD, 0x8D, 0xFD, 0x8E, /* 0x90-0x93 */ - 0xFD, 0x8F, 0xFD, 0x90, 0xFD, 0x91, 0xFD, 0x92, /* 0x94-0x97 */ - 0xFD, 0x93, 0xC1, 0xFA, 0xB9, 0xA8, 0xED, 0xE8, /* 0x98-0x9B */ - 0xFD, 0x94, 0xFD, 0x95, 0xFD, 0x96, 0xB9, 0xEA, /* 0x9C-0x9F */ - 0xD9, 0xDF, 0xFD, 0x97, 0xFD, 0x98, 0xFD, 0x99, /* 0xA0-0xA3 */ - 0xFD, 0x9A, 0xFD, 0x9B, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ -}; - -static const unsigned char u2c_DC[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ -}; - -static const unsigned char u2c_F9[512] = { - 0xD8, 0x4D, 0xB8, 0xFC, 0xDC, 0x87, 0xD9, 0x5A, /* 0x00-0x03 */ - 0xBB, 0xAC, 0xB4, 0xAE, 0xBE, 0xE4, 0xFD, 0x94, /* 0x04-0x07 */ - 0xFD, 0x94, 0xC6, 0xF5, 0xBD, 0xF0, 0xC0, 0xAE, /* 0x08-0x0B */ - 0xC4, 0xCE, 0x91, 0xD0, 0xB0, 0x5D, 0xC1, 0x5F, /* 0x0C-0x0F */ - 0xCC, 0x7D, 0xC2, 0xDD, 0xC2, 0xE3, 0xDF, 0x89, /* 0x10-0x13 */ - 0x98, 0xB7, 0xC2, 0xE5, 0xC0, 0xD3, 0xE7, 0xF3, /* 0x14-0x17 */ - 0xC2, 0xE4, 0xC0, 0xD2, 0xF1, 0x98, 0x81, 0x79, /* 0x18-0x1B */ - 0xC2, 0xD1, 0x99, 0xDA, 0xA0, 0x80, 0xCC, 0x6D, /* 0x1C-0x1F */ - 0xFB, 0x5B, 0x8D, 0xB9, 0x9E, 0x45, 0xCB, 0x7B, /* 0x20-0x23 */ - 0xD2, 0x68, 0xC0, 0xAD, 0xC5, 0x44, 0xCF, 0x9E, /* 0x24-0x27 */ - 0xC0, 0xC8, 0xC0, 0xCA, 0xC0, 0xCB, 0xC0, 0xC7, /* 0x28-0x2B */ - 0xFD, 0x9C, 0x81, 0xED, 0xC0, 0xE4, 0x84, 0xDA, /* 0x2C-0x2F */ - 0x93, 0xEF, 0x99, 0xA9, 0xA0, 0x74, 0xB1, 0x52, /* 0x30-0x33 */ - 0xC0, 0xCF, 0xCC, 0x4A, 0xCC, 0x94, 0xC2, 0xB7, /* 0x34-0x37 */ - 0xC2, 0xB6, 0xF4, 0x94, 0xFA, 0x98, 0xC2, 0xB5, /* 0x38-0x3B */ - 0xB5, 0x93, 0xBE, 0x47, 0xC7, 0x8A, 0xE4, 0x9B, /* 0x3C-0x3F */ - 0xC2, 0xB9, 0xD5, 0x93, 0x89, 0xC5, 0xC5, 0xAA, /* 0x40-0x43 */ - 0xBB, 0x5C, 0xC3, 0x40, 0xC0, 0xCE, 0xC0, 0xDA, /* 0x44-0x47 */ - 0xD9, 0x54, 0xC0, 0xD7, 0x89, 0xBE, 0x8C, 0xD2, /* 0x48-0x4B */ - 0x98, 0xC7, 0x9C, 0x49, 0xC2, 0xA9, 0xC0, 0xDB, /* 0x4C-0x4F */ - 0xBF, 0x7C, 0xC2, 0xAA, 0xC0, 0xD5, 0xC0, 0xDF, /* 0x50-0x53 */ - 0x84, 0x43, 0xC1, 0xE8, 0xB6, 0xA0, 0xBE, 0x63, /* 0x54-0x57 */ - 0xC1, 0xE2, 0xC1, 0xEA, 0xD7, 0x78, 0x92, 0x82, /* 0x58-0x5B */ - 0x98, 0xB7, 0xD6, 0x5A, 0xB5, 0xA4, 0x8C, 0x8E, /* 0x5C-0x5F */ - 0xC5, 0xAD, 0xC2, 0xCA, 0xAE, 0x90, 0xB1, 0xB1, /* 0x60-0x63 */ - 0xB4, 0x91, 0xB1, 0xE3, 0x8F, 0xCD, 0xB2, 0xBB, /* 0x64-0x67 */ - 0xC3, 0xDA, 0x94, 0xB5, 0xCB, 0xF7, 0x85, 0xA2, /* 0x68-0x6B */ - 0xC8, 0xFB, 0xCA, 0xA1, 0xC8, 0x7E, 0xD5, 0x66, /* 0x6C-0x6F */ - 0x9A, 0xA2, 0xB3, 0xBD, 0xC9, 0xF2, 0xCA, 0xB0, /* 0x70-0x73 */ - 0xC8, 0xF4, 0xC2, 0xD3, 0xC2, 0xD4, 0xC1, 0xC1, /* 0x74-0x77 */ - 0x83, 0xC9, 0xFD, 0x9D, 0xC1, 0xBA, 0xBC, 0x5A, /* 0x78-0x7B */ - 0xC1, 0xBC, 0xD5, 0x8F, 0xC1, 0xBF, 0x84, 0xEE, /* 0x7C-0x7F */ - - 0x85, 0xCE, 0xC5, 0xAE, 0x8F, 0x5D, 0xC2, 0xC3, /* 0x80-0x83 */ - 0x9E, 0x56, 0xB5, 0x5A, 0xE9, 0x82, 0xF3, 0x50, /* 0x84-0x87 */ - 0xFB, 0x90, 0xC0, 0xE8, 0xC1, 0xA6, 0x95, 0xD1, /* 0x88-0x8B */ - 0x9A, 0x76, 0xDE, 0x5D, 0xC4, 0xEA, 0x91, 0x7A, /* 0x8C-0x8F */ - 0x91, 0xD9, 0x93, 0xD3, 0x9D, 0x69, 0x9F, 0x92, /* 0x90-0x93 */ - 0xAD, 0x49, 0xFD, 0x9E, 0xBE, 0x9A, 0xC2, 0x93, /* 0x94-0x97 */ - 0xDD, 0x82, 0xC9, 0x8F, 0xDF, 0x42, 0xE5, 0x80, /* 0x98-0x9B */ - 0xC1, 0xD0, 0xC1, 0xD3, 0xD1, 0xCA, 0xC1, 0xD2, /* 0x9C-0x9F */ - 0xC1, 0xD1, 0xD5, 0x66, 0xC1, 0xAE, 0xC4, 0xEE, /* 0xA0-0xA3 */ - 0xC4, 0xED, 0x9A, 0x9A, 0xBA, 0x9F, 0xAB, 0x43, /* 0xA4-0xA7 */ - 0xC1, 0xEE, 0xE0, 0xF2, 0x8C, 0x8E, 0x8E, 0x58, /* 0xA8-0xAB */ - 0xC1, 0xAF, 0xC1, 0xE1, 0xAC, 0x93, 0xC1, 0xE7, /* 0xAC-0xAF */ - 0xF1, 0xF6, 0xE2, 0x8F, 0xC1, 0xE3, 0xEC, 0x60, /* 0xB0-0xB3 */ - 0xEE, 0x49, 0xC0, 0xFD, 0xB6, 0x59, 0xF5, 0xB7, /* 0xB4-0xB7 */ - 0xEB, 0x60, 0x90, 0xBA, 0xC1, 0xCB, 0xC1, 0xC5, /* 0xB8-0xBB */ - 0xE5, 0xBC, 0xC4, 0xF2, 0xC1, 0xCF, 0x98, 0xB7, /* 0xBC-0xBF */ - 0xC1, 0xC7, 0xAF, 0x9F, 0xDE, 0xA4, 0xDF, 0x7C, /* 0xC0-0xC3 */ - 0xFD, 0x88, 0x95, 0x9E, 0xC8, 0xEE, 0x84, 0xA2, /* 0xC4-0xC7 */ - 0x96, 0x83, 0xC1, 0xF8, 0xC1, 0xF7, 0xC1, 0xEF, /* 0xC8-0xCB */ - 0xC1, 0xF0, 0xC1, 0xF4, 0xC1, 0xF2, 0xBC, 0x7E, /* 0xCC-0xCF */ - 0xEE, 0x90, 0xC1, 0xF9, 0xC2, 0xBE, 0xEA, 0x91, /* 0xD0-0xD3 */ - 0x82, 0x90, 0x8D, 0x91, 0x9C, 0x53, 0xDD, 0x86, /* 0xD4-0xD7 */ - 0xC2, 0xC9, 0x90, 0xFC, 0xC0, 0xF5, 0xC2, 0xCA, /* 0xD8-0xDB */ - 0xC2, 0xA1, 0xC0, 0xFB, 0xC0, 0xF4, 0xC2, 0xC4, /* 0xDC-0xDF */ - 0xD2, 0xD7, 0xC0, 0xEE, 0xC0, 0xE6, 0xC4, 0xE0, /* 0xE0-0xE3 */ - 0xC0, 0xED, 0xC1, 0xA1, 0xEE, 0xBE, 0xFD, 0x9F, /* 0xE4-0xE7 */ - 0xD1, 0x65, 0xC0, 0xEF, 0xEB, 0x78, 0xC4, 0xE4, /* 0xE8-0xEB */ - 0xC4, 0xE7, 0xC1, 0xDF, 0x9F, 0xFB, 0xAD, 0x55, /* 0xEC-0xEF */ - 0xCC, 0x41, 0xFD, 0xA0, 0xF7, 0x5B, 0xF7, 0xEB, /* 0xF0-0xF3 */ - 0xC1, 0xD6, 0xC1, 0xDC, 0xC5, 0x52, 0xC1, 0xA2, /* 0xF4-0xF7 */ - 0xF3, 0xD2, 0xC1, 0xA3, 0xA0, 0xEE, 0xD6, 0xCB, /* 0xF8-0xFB */ - 0xD7, 0x52, 0xCA, 0xB2, 0xB2, 0xE8, 0xB4, 0xCC, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_FA[512] = { - 0xC7, 0xD0, 0xB6, 0xC8, 0xCD, 0xD8, 0xCC, 0xC7, /* 0x00-0x03 */ - 0xD5, 0xAC, 0xB6, 0xB4, 0xB1, 0xA9, 0xDD, 0x97, /* 0x04-0x07 */ - 0xD0, 0xD0, 0xBD, 0xB5, 0xD2, 0x8A, 0xC0, 0xAA, /* 0x08-0x0B */ - 0xFE, 0x40, 0xFE, 0x41, 0xFE, 0x42, 0xFE, 0x43, /* 0x0C-0x0F */ - 0x89, 0x56, 0xFE, 0x44, 0xC7, 0xE7, 0xFE, 0x45, /* 0x10-0x13 */ - 0xFE, 0x46, 0x84, 0x44, 0xD8, 0x69, 0xD2, 0xE6, /* 0x14-0x17 */ - 0xFE, 0x47, 0xC9, 0xF1, 0xCF, 0xE9, 0xB8, 0xA3, /* 0x18-0x1B */ - 0xBE, 0xB8, 0xBE, 0xAB, 0xD3, 0xF0, 0xFE, 0x48, /* 0x1C-0x1F */ - 0xFE, 0x49, 0xFE, 0x4A, 0xD6, 0x54, 0xFE, 0x4B, /* 0x20-0x23 */ - 0xFE, 0x4C, 0xD2, 0xDD, 0xB6, 0xBC, 0xFE, 0x4D, /* 0x24-0x27 */ - 0xFE, 0x4E, 0xFE, 0x4F, 0xEF, 0x88, 0xEF, 0x95, /* 0x28-0x2B */ - 0xF0, 0x5E, 0xFA, 0x51, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ -}; - -static const unsigned char u2c_FE[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xA9, 0x55, 0xA6, 0xF2, 0x00, 0x00, 0xA6, 0xF4, /* 0x30-0x33 */ - 0xA6, 0xF5, 0xA6, 0xE0, 0xA6, 0xE1, 0xA6, 0xF0, /* 0x34-0x37 */ - 0xA6, 0xF1, 0xA6, 0xE2, 0xA6, 0xE3, 0xA6, 0xEE, /* 0x38-0x3B */ - 0xA6, 0xEF, 0xA6, 0xE6, 0xA6, 0xE7, 0xA6, 0xE4, /* 0x3C-0x3F */ - 0xA6, 0xE5, 0xA6, 0xE8, 0xA6, 0xE9, 0xA6, 0xEA, /* 0x40-0x43 */ - 0xA6, 0xEB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xA9, 0x68, 0xA9, 0x69, 0xA9, 0x6A, /* 0x48-0x4B */ - 0xA9, 0x6B, 0xA9, 0x6C, 0xA9, 0x6D, 0xA9, 0x6E, /* 0x4C-0x4F */ - 0xA9, 0x6F, 0xA9, 0x70, 0xA9, 0x71, 0x00, 0x00, /* 0x50-0x53 */ - 0xA9, 0x72, 0xA9, 0x73, 0xA9, 0x74, 0xA9, 0x75, /* 0x54-0x57 */ - 0x00, 0x00, 0xA9, 0x76, 0xA9, 0x77, 0xA9, 0x78, /* 0x58-0x5B */ - 0xA9, 0x79, 0xA9, 0x7A, 0xA9, 0x7B, 0xA9, 0x7C, /* 0x5C-0x5F */ - 0xA9, 0x7D, 0xA9, 0x7E, 0xA9, 0x80, 0xA9, 0x81, /* 0x60-0x63 */ - 0xA9, 0x82, 0xA9, 0x83, 0xA9, 0x84, 0x00, 0x00, /* 0x64-0x67 */ - 0xA9, 0x85, 0xA9, 0x86, 0xA9, 0x87, 0xA9, 0x88, /* 0x68-0x6B */ -}; - -static const unsigned char u2c_FF[512] = { - 0x00, 0x00, 0xA3, 0xA1, 0xA3, 0xA2, 0xA3, 0xA3, /* 0x00-0x03 */ - 0xA1, 0xE7, 0xA3, 0xA5, 0xA3, 0xA6, 0xA3, 0xA7, /* 0x04-0x07 */ - 0xA3, 0xA8, 0xA3, 0xA9, 0xA3, 0xAA, 0xA3, 0xAB, /* 0x08-0x0B */ - 0xA3, 0xAC, 0xA3, 0xAD, 0xA3, 0xAE, 0xA3, 0xAF, /* 0x0C-0x0F */ - 0xA3, 0xB0, 0xA3, 0xB1, 0xA3, 0xB2, 0xA3, 0xB3, /* 0x10-0x13 */ - 0xA3, 0xB4, 0xA3, 0xB5, 0xA3, 0xB6, 0xA3, 0xB7, /* 0x14-0x17 */ - 0xA3, 0xB8, 0xA3, 0xB9, 0xA3, 0xBA, 0xA3, 0xBB, /* 0x18-0x1B */ - 0xA3, 0xBC, 0xA3, 0xBD, 0xA3, 0xBE, 0xA3, 0xBF, /* 0x1C-0x1F */ - 0xA3, 0xC0, 0xA3, 0xC1, 0xA3, 0xC2, 0xA3, 0xC3, /* 0x20-0x23 */ - 0xA3, 0xC4, 0xA3, 0xC5, 0xA3, 0xC6, 0xA3, 0xC7, /* 0x24-0x27 */ - 0xA3, 0xC8, 0xA3, 0xC9, 0xA3, 0xCA, 0xA3, 0xCB, /* 0x28-0x2B */ - 0xA3, 0xCC, 0xA3, 0xCD, 0xA3, 0xCE, 0xA3, 0xCF, /* 0x2C-0x2F */ - 0xA3, 0xD0, 0xA3, 0xD1, 0xA3, 0xD2, 0xA3, 0xD3, /* 0x30-0x33 */ - 0xA3, 0xD4, 0xA3, 0xD5, 0xA3, 0xD6, 0xA3, 0xD7, /* 0x34-0x37 */ - 0xA3, 0xD8, 0xA3, 0xD9, 0xA3, 0xDA, 0xA3, 0xDB, /* 0x38-0x3B */ - 0xA3, 0xDC, 0xA3, 0xDD, 0xA3, 0xDE, 0xA3, 0xDF, /* 0x3C-0x3F */ - 0xA3, 0xE0, 0xA3, 0xE1, 0xA3, 0xE2, 0xA3, 0xE3, /* 0x40-0x43 */ - 0xA3, 0xE4, 0xA3, 0xE5, 0xA3, 0xE6, 0xA3, 0xE7, /* 0x44-0x47 */ - 0xA3, 0xE8, 0xA3, 0xE9, 0xA3, 0xEA, 0xA3, 0xEB, /* 0x48-0x4B */ - 0xA3, 0xEC, 0xA3, 0xED, 0xA3, 0xEE, 0xA3, 0xEF, /* 0x4C-0x4F */ - 0xA3, 0xF0, 0xA3, 0xF1, 0xA3, 0xF2, 0xA3, 0xF3, /* 0x50-0x53 */ - 0xA3, 0xF4, 0xA3, 0xF5, 0xA3, 0xF6, 0xA3, 0xF7, /* 0x54-0x57 */ - 0xA3, 0xF8, 0xA3, 0xF9, 0xA3, 0xFA, 0xA3, 0xFB, /* 0x58-0x5B */ - 0xA3, 0xFC, 0xA3, 0xFD, 0xA1, 0xAB, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0xA1, 0xE9, 0xA1, 0xEA, 0xA9, 0x56, 0xA3, 0xFE, /* 0xE0-0xE3 */ - 0xA9, 0x57, 0xA3, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - u2c_00, u2c_01, u2c_02, u2c_03, u2c_04, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - u2c_20, u2c_21, u2c_22, u2c_23, u2c_24, u2c_25, u2c_26, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - u2c_30, u2c_31, u2c_32, u2c_33, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, u2c_4E, u2c_4F, - u2c_50, u2c_51, u2c_52, u2c_53, u2c_54, u2c_55, u2c_56, u2c_57, - u2c_58, u2c_59, u2c_5A, u2c_5B, u2c_5C, u2c_5D, u2c_5E, u2c_5F, - u2c_60, u2c_61, u2c_62, u2c_63, u2c_64, u2c_65, u2c_66, u2c_67, - u2c_68, u2c_69, u2c_6A, u2c_6B, u2c_6C, u2c_6D, u2c_6E, u2c_6F, - u2c_70, u2c_71, u2c_72, u2c_73, u2c_74, u2c_75, u2c_76, u2c_77, - u2c_78, u2c_79, u2c_7A, u2c_7B, u2c_7C, u2c_7D, u2c_7E, u2c_7F, - u2c_80, u2c_81, u2c_82, u2c_83, u2c_84, u2c_85, u2c_86, u2c_87, - u2c_88, u2c_89, u2c_8A, u2c_8B, u2c_8C, u2c_8D, u2c_8E, u2c_8F, - u2c_90, u2c_91, u2c_92, u2c_93, u2c_94, u2c_95, u2c_96, u2c_97, - u2c_98, u2c_99, u2c_9A, u2c_9B, u2c_9C, u2c_9D, u2c_9E, u2c_9F, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, u2c_DC, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, u2c_F9, u2c_FA, NULL, NULL, NULL, u2c_FE, u2c_FF, }; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(const wchar_t uni, - unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni&0xFF; - unsigned char ch = (uni>>8)&0xFF; - unsigned char out0,out1; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - if (uni == 0x20ac) {/* Euro symbol.The only exception with a non-ascii unicode */ - out[0] = 0x80; - return 1; - } - - if (ch == 0) { /* handle the U00 plane*/ - /* if (cl == 0) return -EINVAL;*/ /*U0000 is legal in cp936*/ - out0 = u2c_00[cl*2]; - out1 = u2c_00[cl*2+1]; - if (out0 == 0x00 && out1 == 0x00) { - if (cl<0x80) { - out[0] = cl; - return 1; - } - return -EINVAL; - } else { - if (boundlen <= 1) - return -ENAMETOOLONG; - out[0] = out0; - out[1] = out1; - return 2; - } - } - - uni2charset = page_uni2charset[ch]; - if (uni2charset) { - if (boundlen <= 1) - return -ENAMETOOLONG; - out[0] = uni2charset[cl*2]; - out[1] = uni2charset[cl*2+1]; - if (out[0] == 0x00 && out[1] == 0x00) - return -EINVAL; - return 2; - } - else - return -EINVAL; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, - wchar_t *uni) -{ - unsigned char ch, cl; - const wchar_t *charset2uni; - int n; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - if (boundlen == 1) { - if (rawstring[0]==0x80) { /* Euro symbol.The only exception with a non-ascii unicode */ - *uni = 0x20ac; - } else { - *uni = rawstring[0]; - } - return 1; - } - - ch = rawstring[0]; - cl = rawstring[1]; - - charset2uni = page_charset2uni[ch]; - if (charset2uni && cl) { - *uni = charset2uni[cl]; - if (*uni == 0x0000) - return -EINVAL; - n = 2; - } else{ - if (ch==0x80) {/* Euro symbol.The only exception with a non-ascii unicode */ - *uni = 0x20ac; - } else { - *uni = ch; - } - n = 1; - } - return n; -} - -static struct nls_table table = { - .charset = "cp936", - .alias = "gb2312", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp936(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp936(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp936) -module_exit(exit_nls_cp936) - -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_ALIAS_NLS(gb2312); diff --git a/src/linux/fs/nls/nls_cp949.c b/src/linux/fs/nls/nls_cp949.c deleted file mode 100644 index 199171e..0000000 --- a/src/linux/fs/nls/nls_cp949.c +++ /dev/null @@ -1,13946 +0,0 @@ -/* - * linux/fs/nls/nls_cp949.c - * - * Charset cp949 translation tables. - * This translation table was generated automatically, the - * original table can be download from the Microsoft website. - * (http://www.microsoft.com/typography/unicode/unicodecp.htm) - */ - -#include -#include -#include -#include -#include - -static const wchar_t c2u_81[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xAC02,0xAC03,0xAC05,0xAC06,0xAC0B,0xAC0C,0xAC0D,/* 0x40-0x47 */ - 0xAC0E,0xAC0F,0xAC18,0xAC1E,0xAC1F,0xAC21,0xAC22,0xAC23,/* 0x48-0x4F */ - 0xAC25,0xAC26,0xAC27,0xAC28,0xAC29,0xAC2A,0xAC2B,0xAC2E,/* 0x50-0x57 */ - 0xAC32,0xAC33,0xAC34,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xAC35,0xAC36,0xAC37,0xAC3A,0xAC3B,0xAC3D,0xAC3E,/* 0x60-0x67 */ - 0xAC3F,0xAC41,0xAC42,0xAC43,0xAC44,0xAC45,0xAC46,0xAC47,/* 0x68-0x6F */ - 0xAC48,0xAC49,0xAC4A,0xAC4C,0xAC4E,0xAC4F,0xAC50,0xAC51,/* 0x70-0x77 */ - 0xAC52,0xAC53,0xAC55,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xAC56,0xAC57,0xAC59,0xAC5A,0xAC5B,0xAC5D,0xAC5E,/* 0x80-0x87 */ - 0xAC5F,0xAC60,0xAC61,0xAC62,0xAC63,0xAC64,0xAC65,0xAC66,/* 0x88-0x8F */ - 0xAC67,0xAC68,0xAC69,0xAC6A,0xAC6B,0xAC6C,0xAC6D,0xAC6E,/* 0x90-0x97 */ - 0xAC6F,0xAC72,0xAC73,0xAC75,0xAC76,0xAC79,0xAC7B,0xAC7C,/* 0x98-0x9F */ - 0xAC7D,0xAC7E,0xAC7F,0xAC82,0xAC87,0xAC88,0xAC8D,0xAC8E,/* 0xA0-0xA7 */ - 0xAC8F,0xAC91,0xAC92,0xAC93,0xAC95,0xAC96,0xAC97,0xAC98,/* 0xA8-0xAF */ - 0xAC99,0xAC9A,0xAC9B,0xAC9E,0xACA2,0xACA3,0xACA4,0xACA5,/* 0xB0-0xB7 */ - 0xACA6,0xACA7,0xACAB,0xACAD,0xACAE,0xACB1,0xACB2,0xACB3,/* 0xB8-0xBF */ - 0xACB4,0xACB5,0xACB6,0xACB7,0xACBA,0xACBE,0xACBF,0xACC0,/* 0xC0-0xC7 */ - 0xACC2,0xACC3,0xACC5,0xACC6,0xACC7,0xACC9,0xACCA,0xACCB,/* 0xC8-0xCF */ - 0xACCD,0xACCE,0xACCF,0xACD0,0xACD1,0xACD2,0xACD3,0xACD4,/* 0xD0-0xD7 */ - 0xACD6,0xACD8,0xACD9,0xACDA,0xACDB,0xACDC,0xACDD,0xACDE,/* 0xD8-0xDF */ - 0xACDF,0xACE2,0xACE3,0xACE5,0xACE6,0xACE9,0xACEB,0xACED,/* 0xE0-0xE7 */ - 0xACEE,0xACF2,0xACF4,0xACF7,0xACF8,0xACF9,0xACFA,0xACFB,/* 0xE8-0xEF */ - 0xACFE,0xACFF,0xAD01,0xAD02,0xAD03,0xAD05,0xAD07,0xAD08,/* 0xF0-0xF7 */ - 0xAD09,0xAD0A,0xAD0B,0xAD0E,0xAD10,0xAD12,0xAD13,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_82[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xAD14,0xAD15,0xAD16,0xAD17,0xAD19,0xAD1A,0xAD1B,/* 0x40-0x47 */ - 0xAD1D,0xAD1E,0xAD1F,0xAD21,0xAD22,0xAD23,0xAD24,0xAD25,/* 0x48-0x4F */ - 0xAD26,0xAD27,0xAD28,0xAD2A,0xAD2B,0xAD2E,0xAD2F,0xAD30,/* 0x50-0x57 */ - 0xAD31,0xAD32,0xAD33,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xAD36,0xAD37,0xAD39,0xAD3A,0xAD3B,0xAD3D,0xAD3E,/* 0x60-0x67 */ - 0xAD3F,0xAD40,0xAD41,0xAD42,0xAD43,0xAD46,0xAD48,0xAD4A,/* 0x68-0x6F */ - 0xAD4B,0xAD4C,0xAD4D,0xAD4E,0xAD4F,0xAD51,0xAD52,0xAD53,/* 0x70-0x77 */ - 0xAD55,0xAD56,0xAD57,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xAD59,0xAD5A,0xAD5B,0xAD5C,0xAD5D,0xAD5E,0xAD5F,/* 0x80-0x87 */ - 0xAD60,0xAD62,0xAD64,0xAD65,0xAD66,0xAD67,0xAD68,0xAD69,/* 0x88-0x8F */ - 0xAD6A,0xAD6B,0xAD6E,0xAD6F,0xAD71,0xAD72,0xAD77,0xAD78,/* 0x90-0x97 */ - 0xAD79,0xAD7A,0xAD7E,0xAD80,0xAD83,0xAD84,0xAD85,0xAD86,/* 0x98-0x9F */ - 0xAD87,0xAD8A,0xAD8B,0xAD8D,0xAD8E,0xAD8F,0xAD91,0xAD92,/* 0xA0-0xA7 */ - 0xAD93,0xAD94,0xAD95,0xAD96,0xAD97,0xAD98,0xAD99,0xAD9A,/* 0xA8-0xAF */ - 0xAD9B,0xAD9E,0xAD9F,0xADA0,0xADA1,0xADA2,0xADA3,0xADA5,/* 0xB0-0xB7 */ - 0xADA6,0xADA7,0xADA8,0xADA9,0xADAA,0xADAB,0xADAC,0xADAD,/* 0xB8-0xBF */ - 0xADAE,0xADAF,0xADB0,0xADB1,0xADB2,0xADB3,0xADB4,0xADB5,/* 0xC0-0xC7 */ - 0xADB6,0xADB8,0xADB9,0xADBA,0xADBB,0xADBC,0xADBD,0xADBE,/* 0xC8-0xCF */ - 0xADBF,0xADC2,0xADC3,0xADC5,0xADC6,0xADC7,0xADC9,0xADCA,/* 0xD0-0xD7 */ - 0xADCB,0xADCC,0xADCD,0xADCE,0xADCF,0xADD2,0xADD4,0xADD5,/* 0xD8-0xDF */ - 0xADD6,0xADD7,0xADD8,0xADD9,0xADDA,0xADDB,0xADDD,0xADDE,/* 0xE0-0xE7 */ - 0xADDF,0xADE1,0xADE2,0xADE3,0xADE5,0xADE6,0xADE7,0xADE8,/* 0xE8-0xEF */ - 0xADE9,0xADEA,0xADEB,0xADEC,0xADED,0xADEE,0xADEF,0xADF0,/* 0xF0-0xF7 */ - 0xADF1,0xADF2,0xADF3,0xADF4,0xADF5,0xADF6,0xADF7,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_83[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xADFA,0xADFB,0xADFD,0xADFE,0xAE02,0xAE03,0xAE04,/* 0x40-0x47 */ - 0xAE05,0xAE06,0xAE07,0xAE0A,0xAE0C,0xAE0E,0xAE0F,0xAE10,/* 0x48-0x4F */ - 0xAE11,0xAE12,0xAE13,0xAE15,0xAE16,0xAE17,0xAE18,0xAE19,/* 0x50-0x57 */ - 0xAE1A,0xAE1B,0xAE1C,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xAE1D,0xAE1E,0xAE1F,0xAE20,0xAE21,0xAE22,0xAE23,/* 0x60-0x67 */ - 0xAE24,0xAE25,0xAE26,0xAE27,0xAE28,0xAE29,0xAE2A,0xAE2B,/* 0x68-0x6F */ - 0xAE2C,0xAE2D,0xAE2E,0xAE2F,0xAE32,0xAE33,0xAE35,0xAE36,/* 0x70-0x77 */ - 0xAE39,0xAE3B,0xAE3C,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xAE3D,0xAE3E,0xAE3F,0xAE42,0xAE44,0xAE47,0xAE48,/* 0x80-0x87 */ - 0xAE49,0xAE4B,0xAE4F,0xAE51,0xAE52,0xAE53,0xAE55,0xAE57,/* 0x88-0x8F */ - 0xAE58,0xAE59,0xAE5A,0xAE5B,0xAE5E,0xAE62,0xAE63,0xAE64,/* 0x90-0x97 */ - 0xAE66,0xAE67,0xAE6A,0xAE6B,0xAE6D,0xAE6E,0xAE6F,0xAE71,/* 0x98-0x9F */ - 0xAE72,0xAE73,0xAE74,0xAE75,0xAE76,0xAE77,0xAE7A,0xAE7E,/* 0xA0-0xA7 */ - 0xAE7F,0xAE80,0xAE81,0xAE82,0xAE83,0xAE86,0xAE87,0xAE88,/* 0xA8-0xAF */ - 0xAE89,0xAE8A,0xAE8B,0xAE8D,0xAE8E,0xAE8F,0xAE90,0xAE91,/* 0xB0-0xB7 */ - 0xAE92,0xAE93,0xAE94,0xAE95,0xAE96,0xAE97,0xAE98,0xAE99,/* 0xB8-0xBF */ - 0xAE9A,0xAE9B,0xAE9C,0xAE9D,0xAE9E,0xAE9F,0xAEA0,0xAEA1,/* 0xC0-0xC7 */ - 0xAEA2,0xAEA3,0xAEA4,0xAEA5,0xAEA6,0xAEA7,0xAEA8,0xAEA9,/* 0xC8-0xCF */ - 0xAEAA,0xAEAB,0xAEAC,0xAEAD,0xAEAE,0xAEAF,0xAEB0,0xAEB1,/* 0xD0-0xD7 */ - 0xAEB2,0xAEB3,0xAEB4,0xAEB5,0xAEB6,0xAEB7,0xAEB8,0xAEB9,/* 0xD8-0xDF */ - 0xAEBA,0xAEBB,0xAEBF,0xAEC1,0xAEC2,0xAEC3,0xAEC5,0xAEC6,/* 0xE0-0xE7 */ - 0xAEC7,0xAEC8,0xAEC9,0xAECA,0xAECB,0xAECE,0xAED2,0xAED3,/* 0xE8-0xEF */ - 0xAED4,0xAED5,0xAED6,0xAED7,0xAEDA,0xAEDB,0xAEDD,0xAEDE,/* 0xF0-0xF7 */ - 0xAEDF,0xAEE0,0xAEE1,0xAEE2,0xAEE3,0xAEE4,0xAEE5,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_84[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xAEE6,0xAEE7,0xAEE9,0xAEEA,0xAEEC,0xAEEE,0xAEEF,/* 0x40-0x47 */ - 0xAEF0,0xAEF1,0xAEF2,0xAEF3,0xAEF5,0xAEF6,0xAEF7,0xAEF9,/* 0x48-0x4F */ - 0xAEFA,0xAEFB,0xAEFD,0xAEFE,0xAEFF,0xAF00,0xAF01,0xAF02,/* 0x50-0x57 */ - 0xAF03,0xAF04,0xAF05,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xAF06,0xAF09,0xAF0A,0xAF0B,0xAF0C,0xAF0E,0xAF0F,/* 0x60-0x67 */ - 0xAF11,0xAF12,0xAF13,0xAF14,0xAF15,0xAF16,0xAF17,0xAF18,/* 0x68-0x6F */ - 0xAF19,0xAF1A,0xAF1B,0xAF1C,0xAF1D,0xAF1E,0xAF1F,0xAF20,/* 0x70-0x77 */ - 0xAF21,0xAF22,0xAF23,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xAF24,0xAF25,0xAF26,0xAF27,0xAF28,0xAF29,0xAF2A,/* 0x80-0x87 */ - 0xAF2B,0xAF2E,0xAF2F,0xAF31,0xAF33,0xAF35,0xAF36,0xAF37,/* 0x88-0x8F */ - 0xAF38,0xAF39,0xAF3A,0xAF3B,0xAF3E,0xAF40,0xAF44,0xAF45,/* 0x90-0x97 */ - 0xAF46,0xAF47,0xAF4A,0xAF4B,0xAF4C,0xAF4D,0xAF4E,0xAF4F,/* 0x98-0x9F */ - 0xAF51,0xAF52,0xAF53,0xAF54,0xAF55,0xAF56,0xAF57,0xAF58,/* 0xA0-0xA7 */ - 0xAF59,0xAF5A,0xAF5B,0xAF5E,0xAF5F,0xAF60,0xAF61,0xAF62,/* 0xA8-0xAF */ - 0xAF63,0xAF66,0xAF67,0xAF68,0xAF69,0xAF6A,0xAF6B,0xAF6C,/* 0xB0-0xB7 */ - 0xAF6D,0xAF6E,0xAF6F,0xAF70,0xAF71,0xAF72,0xAF73,0xAF74,/* 0xB8-0xBF */ - 0xAF75,0xAF76,0xAF77,0xAF78,0xAF7A,0xAF7B,0xAF7C,0xAF7D,/* 0xC0-0xC7 */ - 0xAF7E,0xAF7F,0xAF81,0xAF82,0xAF83,0xAF85,0xAF86,0xAF87,/* 0xC8-0xCF */ - 0xAF89,0xAF8A,0xAF8B,0xAF8C,0xAF8D,0xAF8E,0xAF8F,0xAF92,/* 0xD0-0xD7 */ - 0xAF93,0xAF94,0xAF96,0xAF97,0xAF98,0xAF99,0xAF9A,0xAF9B,/* 0xD8-0xDF */ - 0xAF9D,0xAF9E,0xAF9F,0xAFA0,0xAFA1,0xAFA2,0xAFA3,0xAFA4,/* 0xE0-0xE7 */ - 0xAFA5,0xAFA6,0xAFA7,0xAFA8,0xAFA9,0xAFAA,0xAFAB,0xAFAC,/* 0xE8-0xEF */ - 0xAFAD,0xAFAE,0xAFAF,0xAFB0,0xAFB1,0xAFB2,0xAFB3,0xAFB4,/* 0xF0-0xF7 */ - 0xAFB5,0xAFB6,0xAFB7,0xAFBA,0xAFBB,0xAFBD,0xAFBE,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_85[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xAFBF,0xAFC1,0xAFC2,0xAFC3,0xAFC4,0xAFC5,0xAFC6,/* 0x40-0x47 */ - 0xAFCA,0xAFCC,0xAFCF,0xAFD0,0xAFD1,0xAFD2,0xAFD3,0xAFD5,/* 0x48-0x4F */ - 0xAFD6,0xAFD7,0xAFD8,0xAFD9,0xAFDA,0xAFDB,0xAFDD,0xAFDE,/* 0x50-0x57 */ - 0xAFDF,0xAFE0,0xAFE1,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xAFE2,0xAFE3,0xAFE4,0xAFE5,0xAFE6,0xAFE7,0xAFEA,/* 0x60-0x67 */ - 0xAFEB,0xAFEC,0xAFED,0xAFEE,0xAFEF,0xAFF2,0xAFF3,0xAFF5,/* 0x68-0x6F */ - 0xAFF6,0xAFF7,0xAFF9,0xAFFA,0xAFFB,0xAFFC,0xAFFD,0xAFFE,/* 0x70-0x77 */ - 0xAFFF,0xB002,0xB003,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xB005,0xB006,0xB007,0xB008,0xB009,0xB00A,0xB00B,/* 0x80-0x87 */ - 0xB00D,0xB00E,0xB00F,0xB011,0xB012,0xB013,0xB015,0xB016,/* 0x88-0x8F */ - 0xB017,0xB018,0xB019,0xB01A,0xB01B,0xB01E,0xB01F,0xB020,/* 0x90-0x97 */ - 0xB021,0xB022,0xB023,0xB024,0xB025,0xB026,0xB027,0xB029,/* 0x98-0x9F */ - 0xB02A,0xB02B,0xB02C,0xB02D,0xB02E,0xB02F,0xB030,0xB031,/* 0xA0-0xA7 */ - 0xB032,0xB033,0xB034,0xB035,0xB036,0xB037,0xB038,0xB039,/* 0xA8-0xAF */ - 0xB03A,0xB03B,0xB03C,0xB03D,0xB03E,0xB03F,0xB040,0xB041,/* 0xB0-0xB7 */ - 0xB042,0xB043,0xB046,0xB047,0xB049,0xB04B,0xB04D,0xB04F,/* 0xB8-0xBF */ - 0xB050,0xB051,0xB052,0xB056,0xB058,0xB05A,0xB05B,0xB05C,/* 0xC0-0xC7 */ - 0xB05E,0xB05F,0xB060,0xB061,0xB062,0xB063,0xB064,0xB065,/* 0xC8-0xCF */ - 0xB066,0xB067,0xB068,0xB069,0xB06A,0xB06B,0xB06C,0xB06D,/* 0xD0-0xD7 */ - 0xB06E,0xB06F,0xB070,0xB071,0xB072,0xB073,0xB074,0xB075,/* 0xD8-0xDF */ - 0xB076,0xB077,0xB078,0xB079,0xB07A,0xB07B,0xB07E,0xB07F,/* 0xE0-0xE7 */ - 0xB081,0xB082,0xB083,0xB085,0xB086,0xB087,0xB088,0xB089,/* 0xE8-0xEF */ - 0xB08A,0xB08B,0xB08E,0xB090,0xB092,0xB093,0xB094,0xB095,/* 0xF0-0xF7 */ - 0xB096,0xB097,0xB09B,0xB09D,0xB09E,0xB0A3,0xB0A4,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_86[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xB0A5,0xB0A6,0xB0A7,0xB0AA,0xB0B0,0xB0B2,0xB0B6,/* 0x40-0x47 */ - 0xB0B7,0xB0B9,0xB0BA,0xB0BB,0xB0BD,0xB0BE,0xB0BF,0xB0C0,/* 0x48-0x4F */ - 0xB0C1,0xB0C2,0xB0C3,0xB0C6,0xB0CA,0xB0CB,0xB0CC,0xB0CD,/* 0x50-0x57 */ - 0xB0CE,0xB0CF,0xB0D2,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xB0D3,0xB0D5,0xB0D6,0xB0D7,0xB0D9,0xB0DA,0xB0DB,/* 0x60-0x67 */ - 0xB0DC,0xB0DD,0xB0DE,0xB0DF,0xB0E1,0xB0E2,0xB0E3,0xB0E4,/* 0x68-0x6F */ - 0xB0E6,0xB0E7,0xB0E8,0xB0E9,0xB0EA,0xB0EB,0xB0EC,0xB0ED,/* 0x70-0x77 */ - 0xB0EE,0xB0EF,0xB0F0,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xB0F1,0xB0F2,0xB0F3,0xB0F4,0xB0F5,0xB0F6,0xB0F7,/* 0x80-0x87 */ - 0xB0F8,0xB0F9,0xB0FA,0xB0FB,0xB0FC,0xB0FD,0xB0FE,0xB0FF,/* 0x88-0x8F */ - 0xB100,0xB101,0xB102,0xB103,0xB104,0xB105,0xB106,0xB107,/* 0x90-0x97 */ - 0xB10A,0xB10D,0xB10E,0xB10F,0xB111,0xB114,0xB115,0xB116,/* 0x98-0x9F */ - 0xB117,0xB11A,0xB11E,0xB11F,0xB120,0xB121,0xB122,0xB126,/* 0xA0-0xA7 */ - 0xB127,0xB129,0xB12A,0xB12B,0xB12D,0xB12E,0xB12F,0xB130,/* 0xA8-0xAF */ - 0xB131,0xB132,0xB133,0xB136,0xB13A,0xB13B,0xB13C,0xB13D,/* 0xB0-0xB7 */ - 0xB13E,0xB13F,0xB142,0xB143,0xB145,0xB146,0xB147,0xB149,/* 0xB8-0xBF */ - 0xB14A,0xB14B,0xB14C,0xB14D,0xB14E,0xB14F,0xB152,0xB153,/* 0xC0-0xC7 */ - 0xB156,0xB157,0xB159,0xB15A,0xB15B,0xB15D,0xB15E,0xB15F,/* 0xC8-0xCF */ - 0xB161,0xB162,0xB163,0xB164,0xB165,0xB166,0xB167,0xB168,/* 0xD0-0xD7 */ - 0xB169,0xB16A,0xB16B,0xB16C,0xB16D,0xB16E,0xB16F,0xB170,/* 0xD8-0xDF */ - 0xB171,0xB172,0xB173,0xB174,0xB175,0xB176,0xB177,0xB17A,/* 0xE0-0xE7 */ - 0xB17B,0xB17D,0xB17E,0xB17F,0xB181,0xB183,0xB184,0xB185,/* 0xE8-0xEF */ - 0xB186,0xB187,0xB18A,0xB18C,0xB18E,0xB18F,0xB190,0xB191,/* 0xF0-0xF7 */ - 0xB195,0xB196,0xB197,0xB199,0xB19A,0xB19B,0xB19D,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_87[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xB19E,0xB19F,0xB1A0,0xB1A1,0xB1A2,0xB1A3,0xB1A4,/* 0x40-0x47 */ - 0xB1A5,0xB1A6,0xB1A7,0xB1A9,0xB1AA,0xB1AB,0xB1AC,0xB1AD,/* 0x48-0x4F */ - 0xB1AE,0xB1AF,0xB1B0,0xB1B1,0xB1B2,0xB1B3,0xB1B4,0xB1B5,/* 0x50-0x57 */ - 0xB1B6,0xB1B7,0xB1B8,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xB1B9,0xB1BA,0xB1BB,0xB1BC,0xB1BD,0xB1BE,0xB1BF,/* 0x60-0x67 */ - 0xB1C0,0xB1C1,0xB1C2,0xB1C3,0xB1C4,0xB1C5,0xB1C6,0xB1C7,/* 0x68-0x6F */ - 0xB1C8,0xB1C9,0xB1CA,0xB1CB,0xB1CD,0xB1CE,0xB1CF,0xB1D1,/* 0x70-0x77 */ - 0xB1D2,0xB1D3,0xB1D5,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xB1D6,0xB1D7,0xB1D8,0xB1D9,0xB1DA,0xB1DB,0xB1DE,/* 0x80-0x87 */ - 0xB1E0,0xB1E1,0xB1E2,0xB1E3,0xB1E4,0xB1E5,0xB1E6,0xB1E7,/* 0x88-0x8F */ - 0xB1EA,0xB1EB,0xB1ED,0xB1EE,0xB1EF,0xB1F1,0xB1F2,0xB1F3,/* 0x90-0x97 */ - 0xB1F4,0xB1F5,0xB1F6,0xB1F7,0xB1F8,0xB1FA,0xB1FC,0xB1FE,/* 0x98-0x9F */ - 0xB1FF,0xB200,0xB201,0xB202,0xB203,0xB206,0xB207,0xB209,/* 0xA0-0xA7 */ - 0xB20A,0xB20D,0xB20E,0xB20F,0xB210,0xB211,0xB212,0xB213,/* 0xA8-0xAF */ - 0xB216,0xB218,0xB21A,0xB21B,0xB21C,0xB21D,0xB21E,0xB21F,/* 0xB0-0xB7 */ - 0xB221,0xB222,0xB223,0xB224,0xB225,0xB226,0xB227,0xB228,/* 0xB8-0xBF */ - 0xB229,0xB22A,0xB22B,0xB22C,0xB22D,0xB22E,0xB22F,0xB230,/* 0xC0-0xC7 */ - 0xB231,0xB232,0xB233,0xB235,0xB236,0xB237,0xB238,0xB239,/* 0xC8-0xCF */ - 0xB23A,0xB23B,0xB23D,0xB23E,0xB23F,0xB240,0xB241,0xB242,/* 0xD0-0xD7 */ - 0xB243,0xB244,0xB245,0xB246,0xB247,0xB248,0xB249,0xB24A,/* 0xD8-0xDF */ - 0xB24B,0xB24C,0xB24D,0xB24E,0xB24F,0xB250,0xB251,0xB252,/* 0xE0-0xE7 */ - 0xB253,0xB254,0xB255,0xB256,0xB257,0xB259,0xB25A,0xB25B,/* 0xE8-0xEF */ - 0xB25D,0xB25E,0xB25F,0xB261,0xB262,0xB263,0xB264,0xB265,/* 0xF0-0xF7 */ - 0xB266,0xB267,0xB26A,0xB26B,0xB26C,0xB26D,0xB26E,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_88[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xB26F,0xB270,0xB271,0xB272,0xB273,0xB276,0xB277,/* 0x40-0x47 */ - 0xB278,0xB279,0xB27A,0xB27B,0xB27D,0xB27E,0xB27F,0xB280,/* 0x48-0x4F */ - 0xB281,0xB282,0xB283,0xB286,0xB287,0xB288,0xB28A,0xB28B,/* 0x50-0x57 */ - 0xB28C,0xB28D,0xB28E,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xB28F,0xB292,0xB293,0xB295,0xB296,0xB297,0xB29B,/* 0x60-0x67 */ - 0xB29C,0xB29D,0xB29E,0xB29F,0xB2A2,0xB2A4,0xB2A7,0xB2A8,/* 0x68-0x6F */ - 0xB2A9,0xB2AB,0xB2AD,0xB2AE,0xB2AF,0xB2B1,0xB2B2,0xB2B3,/* 0x70-0x77 */ - 0xB2B5,0xB2B6,0xB2B7,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xB2B8,0xB2B9,0xB2BA,0xB2BB,0xB2BC,0xB2BD,0xB2BE,/* 0x80-0x87 */ - 0xB2BF,0xB2C0,0xB2C1,0xB2C2,0xB2C3,0xB2C4,0xB2C5,0xB2C6,/* 0x88-0x8F */ - 0xB2C7,0xB2CA,0xB2CB,0xB2CD,0xB2CE,0xB2CF,0xB2D1,0xB2D3,/* 0x90-0x97 */ - 0xB2D4,0xB2D5,0xB2D6,0xB2D7,0xB2DA,0xB2DC,0xB2DE,0xB2DF,/* 0x98-0x9F */ - 0xB2E0,0xB2E1,0xB2E3,0xB2E7,0xB2E9,0xB2EA,0xB2F0,0xB2F1,/* 0xA0-0xA7 */ - 0xB2F2,0xB2F6,0xB2FC,0xB2FD,0xB2FE,0xB302,0xB303,0xB305,/* 0xA8-0xAF */ - 0xB306,0xB307,0xB309,0xB30A,0xB30B,0xB30C,0xB30D,0xB30E,/* 0xB0-0xB7 */ - 0xB30F,0xB312,0xB316,0xB317,0xB318,0xB319,0xB31A,0xB31B,/* 0xB8-0xBF */ - 0xB31D,0xB31E,0xB31F,0xB320,0xB321,0xB322,0xB323,0xB324,/* 0xC0-0xC7 */ - 0xB325,0xB326,0xB327,0xB328,0xB329,0xB32A,0xB32B,0xB32C,/* 0xC8-0xCF */ - 0xB32D,0xB32E,0xB32F,0xB330,0xB331,0xB332,0xB333,0xB334,/* 0xD0-0xD7 */ - 0xB335,0xB336,0xB337,0xB338,0xB339,0xB33A,0xB33B,0xB33C,/* 0xD8-0xDF */ - 0xB33D,0xB33E,0xB33F,0xB340,0xB341,0xB342,0xB343,0xB344,/* 0xE0-0xE7 */ - 0xB345,0xB346,0xB347,0xB348,0xB349,0xB34A,0xB34B,0xB34C,/* 0xE8-0xEF */ - 0xB34D,0xB34E,0xB34F,0xB350,0xB351,0xB352,0xB353,0xB357,/* 0xF0-0xF7 */ - 0xB359,0xB35A,0xB35D,0xB360,0xB361,0xB362,0xB363,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_89[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xB366,0xB368,0xB36A,0xB36C,0xB36D,0xB36F,0xB372,/* 0x40-0x47 */ - 0xB373,0xB375,0xB376,0xB377,0xB379,0xB37A,0xB37B,0xB37C,/* 0x48-0x4F */ - 0xB37D,0xB37E,0xB37F,0xB382,0xB386,0xB387,0xB388,0xB389,/* 0x50-0x57 */ - 0xB38A,0xB38B,0xB38D,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xB38E,0xB38F,0xB391,0xB392,0xB393,0xB395,0xB396,/* 0x60-0x67 */ - 0xB397,0xB398,0xB399,0xB39A,0xB39B,0xB39C,0xB39D,0xB39E,/* 0x68-0x6F */ - 0xB39F,0xB3A2,0xB3A3,0xB3A4,0xB3A5,0xB3A6,0xB3A7,0xB3A9,/* 0x70-0x77 */ - 0xB3AA,0xB3AB,0xB3AD,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xB3AE,0xB3AF,0xB3B0,0xB3B1,0xB3B2,0xB3B3,0xB3B4,/* 0x80-0x87 */ - 0xB3B5,0xB3B6,0xB3B7,0xB3B8,0xB3B9,0xB3BA,0xB3BB,0xB3BC,/* 0x88-0x8F */ - 0xB3BD,0xB3BE,0xB3BF,0xB3C0,0xB3C1,0xB3C2,0xB3C3,0xB3C6,/* 0x90-0x97 */ - 0xB3C7,0xB3C9,0xB3CA,0xB3CD,0xB3CF,0xB3D1,0xB3D2,0xB3D3,/* 0x98-0x9F */ - 0xB3D6,0xB3D8,0xB3DA,0xB3DC,0xB3DE,0xB3DF,0xB3E1,0xB3E2,/* 0xA0-0xA7 */ - 0xB3E3,0xB3E5,0xB3E6,0xB3E7,0xB3E9,0xB3EA,0xB3EB,0xB3EC,/* 0xA8-0xAF */ - 0xB3ED,0xB3EE,0xB3EF,0xB3F0,0xB3F1,0xB3F2,0xB3F3,0xB3F4,/* 0xB0-0xB7 */ - 0xB3F5,0xB3F6,0xB3F7,0xB3F8,0xB3F9,0xB3FA,0xB3FB,0xB3FD,/* 0xB8-0xBF */ - 0xB3FE,0xB3FF,0xB400,0xB401,0xB402,0xB403,0xB404,0xB405,/* 0xC0-0xC7 */ - 0xB406,0xB407,0xB408,0xB409,0xB40A,0xB40B,0xB40C,0xB40D,/* 0xC8-0xCF */ - 0xB40E,0xB40F,0xB411,0xB412,0xB413,0xB414,0xB415,0xB416,/* 0xD0-0xD7 */ - 0xB417,0xB419,0xB41A,0xB41B,0xB41D,0xB41E,0xB41F,0xB421,/* 0xD8-0xDF */ - 0xB422,0xB423,0xB424,0xB425,0xB426,0xB427,0xB42A,0xB42C,/* 0xE0-0xE7 */ - 0xB42D,0xB42E,0xB42F,0xB430,0xB431,0xB432,0xB433,0xB435,/* 0xE8-0xEF */ - 0xB436,0xB437,0xB438,0xB439,0xB43A,0xB43B,0xB43C,0xB43D,/* 0xF0-0xF7 */ - 0xB43E,0xB43F,0xB440,0xB441,0xB442,0xB443,0xB444,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_8A[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xB445,0xB446,0xB447,0xB448,0xB449,0xB44A,0xB44B,/* 0x40-0x47 */ - 0xB44C,0xB44D,0xB44E,0xB44F,0xB452,0xB453,0xB455,0xB456,/* 0x48-0x4F */ - 0xB457,0xB459,0xB45A,0xB45B,0xB45C,0xB45D,0xB45E,0xB45F,/* 0x50-0x57 */ - 0xB462,0xB464,0xB466,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xB467,0xB468,0xB469,0xB46A,0xB46B,0xB46D,0xB46E,/* 0x60-0x67 */ - 0xB46F,0xB470,0xB471,0xB472,0xB473,0xB474,0xB475,0xB476,/* 0x68-0x6F */ - 0xB477,0xB478,0xB479,0xB47A,0xB47B,0xB47C,0xB47D,0xB47E,/* 0x70-0x77 */ - 0xB47F,0xB481,0xB482,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xB483,0xB484,0xB485,0xB486,0xB487,0xB489,0xB48A,/* 0x80-0x87 */ - 0xB48B,0xB48C,0xB48D,0xB48E,0xB48F,0xB490,0xB491,0xB492,/* 0x88-0x8F */ - 0xB493,0xB494,0xB495,0xB496,0xB497,0xB498,0xB499,0xB49A,/* 0x90-0x97 */ - 0xB49B,0xB49C,0xB49E,0xB49F,0xB4A0,0xB4A1,0xB4A2,0xB4A3,/* 0x98-0x9F */ - 0xB4A5,0xB4A6,0xB4A7,0xB4A9,0xB4AA,0xB4AB,0xB4AD,0xB4AE,/* 0xA0-0xA7 */ - 0xB4AF,0xB4B0,0xB4B1,0xB4B2,0xB4B3,0xB4B4,0xB4B6,0xB4B8,/* 0xA8-0xAF */ - 0xB4BA,0xB4BB,0xB4BC,0xB4BD,0xB4BE,0xB4BF,0xB4C1,0xB4C2,/* 0xB0-0xB7 */ - 0xB4C3,0xB4C5,0xB4C6,0xB4C7,0xB4C9,0xB4CA,0xB4CB,0xB4CC,/* 0xB8-0xBF */ - 0xB4CD,0xB4CE,0xB4CF,0xB4D1,0xB4D2,0xB4D3,0xB4D4,0xB4D6,/* 0xC0-0xC7 */ - 0xB4D7,0xB4D8,0xB4D9,0xB4DA,0xB4DB,0xB4DE,0xB4DF,0xB4E1,/* 0xC8-0xCF */ - 0xB4E2,0xB4E5,0xB4E7,0xB4E8,0xB4E9,0xB4EA,0xB4EB,0xB4EE,/* 0xD0-0xD7 */ - 0xB4F0,0xB4F2,0xB4F3,0xB4F4,0xB4F5,0xB4F6,0xB4F7,0xB4F9,/* 0xD8-0xDF */ - 0xB4FA,0xB4FB,0xB4FC,0xB4FD,0xB4FE,0xB4FF,0xB500,0xB501,/* 0xE0-0xE7 */ - 0xB502,0xB503,0xB504,0xB505,0xB506,0xB507,0xB508,0xB509,/* 0xE8-0xEF */ - 0xB50A,0xB50B,0xB50C,0xB50D,0xB50E,0xB50F,0xB510,0xB511,/* 0xF0-0xF7 */ - 0xB512,0xB513,0xB516,0xB517,0xB519,0xB51A,0xB51D,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_8B[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xB51E,0xB51F,0xB520,0xB521,0xB522,0xB523,0xB526,/* 0x40-0x47 */ - 0xB52B,0xB52C,0xB52D,0xB52E,0xB52F,0xB532,0xB533,0xB535,/* 0x48-0x4F */ - 0xB536,0xB537,0xB539,0xB53A,0xB53B,0xB53C,0xB53D,0xB53E,/* 0x50-0x57 */ - 0xB53F,0xB542,0xB546,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xB547,0xB548,0xB549,0xB54A,0xB54E,0xB54F,0xB551,/* 0x60-0x67 */ - 0xB552,0xB553,0xB555,0xB556,0xB557,0xB558,0xB559,0xB55A,/* 0x68-0x6F */ - 0xB55B,0xB55E,0xB562,0xB563,0xB564,0xB565,0xB566,0xB567,/* 0x70-0x77 */ - 0xB568,0xB569,0xB56A,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xB56B,0xB56C,0xB56D,0xB56E,0xB56F,0xB570,0xB571,/* 0x80-0x87 */ - 0xB572,0xB573,0xB574,0xB575,0xB576,0xB577,0xB578,0xB579,/* 0x88-0x8F */ - 0xB57A,0xB57B,0xB57C,0xB57D,0xB57E,0xB57F,0xB580,0xB581,/* 0x90-0x97 */ - 0xB582,0xB583,0xB584,0xB585,0xB586,0xB587,0xB588,0xB589,/* 0x98-0x9F */ - 0xB58A,0xB58B,0xB58C,0xB58D,0xB58E,0xB58F,0xB590,0xB591,/* 0xA0-0xA7 */ - 0xB592,0xB593,0xB594,0xB595,0xB596,0xB597,0xB598,0xB599,/* 0xA8-0xAF */ - 0xB59A,0xB59B,0xB59C,0xB59D,0xB59E,0xB59F,0xB5A2,0xB5A3,/* 0xB0-0xB7 */ - 0xB5A5,0xB5A6,0xB5A7,0xB5A9,0xB5AC,0xB5AD,0xB5AE,0xB5AF,/* 0xB8-0xBF */ - 0xB5B2,0xB5B6,0xB5B7,0xB5B8,0xB5B9,0xB5BA,0xB5BE,0xB5BF,/* 0xC0-0xC7 */ - 0xB5C1,0xB5C2,0xB5C3,0xB5C5,0xB5C6,0xB5C7,0xB5C8,0xB5C9,/* 0xC8-0xCF */ - 0xB5CA,0xB5CB,0xB5CE,0xB5D2,0xB5D3,0xB5D4,0xB5D5,0xB5D6,/* 0xD0-0xD7 */ - 0xB5D7,0xB5D9,0xB5DA,0xB5DB,0xB5DC,0xB5DD,0xB5DE,0xB5DF,/* 0xD8-0xDF */ - 0xB5E0,0xB5E1,0xB5E2,0xB5E3,0xB5E4,0xB5E5,0xB5E6,0xB5E7,/* 0xE0-0xE7 */ - 0xB5E8,0xB5E9,0xB5EA,0xB5EB,0xB5ED,0xB5EE,0xB5EF,0xB5F0,/* 0xE8-0xEF */ - 0xB5F1,0xB5F2,0xB5F3,0xB5F4,0xB5F5,0xB5F6,0xB5F7,0xB5F8,/* 0xF0-0xF7 */ - 0xB5F9,0xB5FA,0xB5FB,0xB5FC,0xB5FD,0xB5FE,0xB5FF,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_8C[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xB600,0xB601,0xB602,0xB603,0xB604,0xB605,0xB606,/* 0x40-0x47 */ - 0xB607,0xB608,0xB609,0xB60A,0xB60B,0xB60C,0xB60D,0xB60E,/* 0x48-0x4F */ - 0xB60F,0xB612,0xB613,0xB615,0xB616,0xB617,0xB619,0xB61A,/* 0x50-0x57 */ - 0xB61B,0xB61C,0xB61D,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xB61E,0xB61F,0xB620,0xB621,0xB622,0xB623,0xB624,/* 0x60-0x67 */ - 0xB626,0xB627,0xB628,0xB629,0xB62A,0xB62B,0xB62D,0xB62E,/* 0x68-0x6F */ - 0xB62F,0xB630,0xB631,0xB632,0xB633,0xB635,0xB636,0xB637,/* 0x70-0x77 */ - 0xB638,0xB639,0xB63A,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xB63B,0xB63C,0xB63D,0xB63E,0xB63F,0xB640,0xB641,/* 0x80-0x87 */ - 0xB642,0xB643,0xB644,0xB645,0xB646,0xB647,0xB649,0xB64A,/* 0x88-0x8F */ - 0xB64B,0xB64C,0xB64D,0xB64E,0xB64F,0xB650,0xB651,0xB652,/* 0x90-0x97 */ - 0xB653,0xB654,0xB655,0xB656,0xB657,0xB658,0xB659,0xB65A,/* 0x98-0x9F */ - 0xB65B,0xB65C,0xB65D,0xB65E,0xB65F,0xB660,0xB661,0xB662,/* 0xA0-0xA7 */ - 0xB663,0xB665,0xB666,0xB667,0xB669,0xB66A,0xB66B,0xB66C,/* 0xA8-0xAF */ - 0xB66D,0xB66E,0xB66F,0xB670,0xB671,0xB672,0xB673,0xB674,/* 0xB0-0xB7 */ - 0xB675,0xB676,0xB677,0xB678,0xB679,0xB67A,0xB67B,0xB67C,/* 0xB8-0xBF */ - 0xB67D,0xB67E,0xB67F,0xB680,0xB681,0xB682,0xB683,0xB684,/* 0xC0-0xC7 */ - 0xB685,0xB686,0xB687,0xB688,0xB689,0xB68A,0xB68B,0xB68C,/* 0xC8-0xCF */ - 0xB68D,0xB68E,0xB68F,0xB690,0xB691,0xB692,0xB693,0xB694,/* 0xD0-0xD7 */ - 0xB695,0xB696,0xB697,0xB698,0xB699,0xB69A,0xB69B,0xB69E,/* 0xD8-0xDF */ - 0xB69F,0xB6A1,0xB6A2,0xB6A3,0xB6A5,0xB6A6,0xB6A7,0xB6A8,/* 0xE0-0xE7 */ - 0xB6A9,0xB6AA,0xB6AD,0xB6AE,0xB6AF,0xB6B0,0xB6B2,0xB6B3,/* 0xE8-0xEF */ - 0xB6B4,0xB6B5,0xB6B6,0xB6B7,0xB6B8,0xB6B9,0xB6BA,0xB6BB,/* 0xF0-0xF7 */ - 0xB6BC,0xB6BD,0xB6BE,0xB6BF,0xB6C0,0xB6C1,0xB6C2,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_8D[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xB6C3,0xB6C4,0xB6C5,0xB6C6,0xB6C7,0xB6C8,0xB6C9,/* 0x40-0x47 */ - 0xB6CA,0xB6CB,0xB6CC,0xB6CD,0xB6CE,0xB6CF,0xB6D0,0xB6D1,/* 0x48-0x4F */ - 0xB6D2,0xB6D3,0xB6D5,0xB6D6,0xB6D7,0xB6D8,0xB6D9,0xB6DA,/* 0x50-0x57 */ - 0xB6DB,0xB6DC,0xB6DD,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xB6DE,0xB6DF,0xB6E0,0xB6E1,0xB6E2,0xB6E3,0xB6E4,/* 0x60-0x67 */ - 0xB6E5,0xB6E6,0xB6E7,0xB6E8,0xB6E9,0xB6EA,0xB6EB,0xB6EC,/* 0x68-0x6F */ - 0xB6ED,0xB6EE,0xB6EF,0xB6F1,0xB6F2,0xB6F3,0xB6F5,0xB6F6,/* 0x70-0x77 */ - 0xB6F7,0xB6F9,0xB6FA,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xB6FB,0xB6FC,0xB6FD,0xB6FE,0xB6FF,0xB702,0xB703,/* 0x80-0x87 */ - 0xB704,0xB706,0xB707,0xB708,0xB709,0xB70A,0xB70B,0xB70C,/* 0x88-0x8F */ - 0xB70D,0xB70E,0xB70F,0xB710,0xB711,0xB712,0xB713,0xB714,/* 0x90-0x97 */ - 0xB715,0xB716,0xB717,0xB718,0xB719,0xB71A,0xB71B,0xB71C,/* 0x98-0x9F */ - 0xB71D,0xB71E,0xB71F,0xB720,0xB721,0xB722,0xB723,0xB724,/* 0xA0-0xA7 */ - 0xB725,0xB726,0xB727,0xB72A,0xB72B,0xB72D,0xB72E,0xB731,/* 0xA8-0xAF */ - 0xB732,0xB733,0xB734,0xB735,0xB736,0xB737,0xB73A,0xB73C,/* 0xB0-0xB7 */ - 0xB73D,0xB73E,0xB73F,0xB740,0xB741,0xB742,0xB743,0xB745,/* 0xB8-0xBF */ - 0xB746,0xB747,0xB749,0xB74A,0xB74B,0xB74D,0xB74E,0xB74F,/* 0xC0-0xC7 */ - 0xB750,0xB751,0xB752,0xB753,0xB756,0xB757,0xB758,0xB759,/* 0xC8-0xCF */ - 0xB75A,0xB75B,0xB75C,0xB75D,0xB75E,0xB75F,0xB761,0xB762,/* 0xD0-0xD7 */ - 0xB763,0xB765,0xB766,0xB767,0xB769,0xB76A,0xB76B,0xB76C,/* 0xD8-0xDF */ - 0xB76D,0xB76E,0xB76F,0xB772,0xB774,0xB776,0xB777,0xB778,/* 0xE0-0xE7 */ - 0xB779,0xB77A,0xB77B,0xB77E,0xB77F,0xB781,0xB782,0xB783,/* 0xE8-0xEF */ - 0xB785,0xB786,0xB787,0xB788,0xB789,0xB78A,0xB78B,0xB78E,/* 0xF0-0xF7 */ - 0xB793,0xB794,0xB795,0xB79A,0xB79B,0xB79D,0xB79E,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_8E[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xB79F,0xB7A1,0xB7A2,0xB7A3,0xB7A4,0xB7A5,0xB7A6,/* 0x40-0x47 */ - 0xB7A7,0xB7AA,0xB7AE,0xB7AF,0xB7B0,0xB7B1,0xB7B2,0xB7B3,/* 0x48-0x4F */ - 0xB7B6,0xB7B7,0xB7B9,0xB7BA,0xB7BB,0xB7BC,0xB7BD,0xB7BE,/* 0x50-0x57 */ - 0xB7BF,0xB7C0,0xB7C1,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xB7C2,0xB7C3,0xB7C4,0xB7C5,0xB7C6,0xB7C8,0xB7CA,/* 0x60-0x67 */ - 0xB7CB,0xB7CC,0xB7CD,0xB7CE,0xB7CF,0xB7D0,0xB7D1,0xB7D2,/* 0x68-0x6F */ - 0xB7D3,0xB7D4,0xB7D5,0xB7D6,0xB7D7,0xB7D8,0xB7D9,0xB7DA,/* 0x70-0x77 */ - 0xB7DB,0xB7DC,0xB7DD,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xB7DE,0xB7DF,0xB7E0,0xB7E1,0xB7E2,0xB7E3,0xB7E4,/* 0x80-0x87 */ - 0xB7E5,0xB7E6,0xB7E7,0xB7E8,0xB7E9,0xB7EA,0xB7EB,0xB7EE,/* 0x88-0x8F */ - 0xB7EF,0xB7F1,0xB7F2,0xB7F3,0xB7F5,0xB7F6,0xB7F7,0xB7F8,/* 0x90-0x97 */ - 0xB7F9,0xB7FA,0xB7FB,0xB7FE,0xB802,0xB803,0xB804,0xB805,/* 0x98-0x9F */ - 0xB806,0xB80A,0xB80B,0xB80D,0xB80E,0xB80F,0xB811,0xB812,/* 0xA0-0xA7 */ - 0xB813,0xB814,0xB815,0xB816,0xB817,0xB81A,0xB81C,0xB81E,/* 0xA8-0xAF */ - 0xB81F,0xB820,0xB821,0xB822,0xB823,0xB826,0xB827,0xB829,/* 0xB0-0xB7 */ - 0xB82A,0xB82B,0xB82D,0xB82E,0xB82F,0xB830,0xB831,0xB832,/* 0xB8-0xBF */ - 0xB833,0xB836,0xB83A,0xB83B,0xB83C,0xB83D,0xB83E,0xB83F,/* 0xC0-0xC7 */ - 0xB841,0xB842,0xB843,0xB845,0xB846,0xB847,0xB848,0xB849,/* 0xC8-0xCF */ - 0xB84A,0xB84B,0xB84C,0xB84D,0xB84E,0xB84F,0xB850,0xB852,/* 0xD0-0xD7 */ - 0xB854,0xB855,0xB856,0xB857,0xB858,0xB859,0xB85A,0xB85B,/* 0xD8-0xDF */ - 0xB85E,0xB85F,0xB861,0xB862,0xB863,0xB865,0xB866,0xB867,/* 0xE0-0xE7 */ - 0xB868,0xB869,0xB86A,0xB86B,0xB86E,0xB870,0xB872,0xB873,/* 0xE8-0xEF */ - 0xB874,0xB875,0xB876,0xB877,0xB879,0xB87A,0xB87B,0xB87D,/* 0xF0-0xF7 */ - 0xB87E,0xB87F,0xB880,0xB881,0xB882,0xB883,0xB884,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_8F[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xB885,0xB886,0xB887,0xB888,0xB889,0xB88A,0xB88B,/* 0x40-0x47 */ - 0xB88C,0xB88E,0xB88F,0xB890,0xB891,0xB892,0xB893,0xB894,/* 0x48-0x4F */ - 0xB895,0xB896,0xB897,0xB898,0xB899,0xB89A,0xB89B,0xB89C,/* 0x50-0x57 */ - 0xB89D,0xB89E,0xB89F,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xB8A0,0xB8A1,0xB8A2,0xB8A3,0xB8A4,0xB8A5,0xB8A6,/* 0x60-0x67 */ - 0xB8A7,0xB8A9,0xB8AA,0xB8AB,0xB8AC,0xB8AD,0xB8AE,0xB8AF,/* 0x68-0x6F */ - 0xB8B1,0xB8B2,0xB8B3,0xB8B5,0xB8B6,0xB8B7,0xB8B9,0xB8BA,/* 0x70-0x77 */ - 0xB8BB,0xB8BC,0xB8BD,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xB8BE,0xB8BF,0xB8C2,0xB8C4,0xB8C6,0xB8C7,0xB8C8,/* 0x80-0x87 */ - 0xB8C9,0xB8CA,0xB8CB,0xB8CD,0xB8CE,0xB8CF,0xB8D1,0xB8D2,/* 0x88-0x8F */ - 0xB8D3,0xB8D5,0xB8D6,0xB8D7,0xB8D8,0xB8D9,0xB8DA,0xB8DB,/* 0x90-0x97 */ - 0xB8DC,0xB8DE,0xB8E0,0xB8E2,0xB8E3,0xB8E4,0xB8E5,0xB8E6,/* 0x98-0x9F */ - 0xB8E7,0xB8EA,0xB8EB,0xB8ED,0xB8EE,0xB8EF,0xB8F1,0xB8F2,/* 0xA0-0xA7 */ - 0xB8F3,0xB8F4,0xB8F5,0xB8F6,0xB8F7,0xB8FA,0xB8FC,0xB8FE,/* 0xA8-0xAF */ - 0xB8FF,0xB900,0xB901,0xB902,0xB903,0xB905,0xB906,0xB907,/* 0xB0-0xB7 */ - 0xB908,0xB909,0xB90A,0xB90B,0xB90C,0xB90D,0xB90E,0xB90F,/* 0xB8-0xBF */ - 0xB910,0xB911,0xB912,0xB913,0xB914,0xB915,0xB916,0xB917,/* 0xC0-0xC7 */ - 0xB919,0xB91A,0xB91B,0xB91C,0xB91D,0xB91E,0xB91F,0xB921,/* 0xC8-0xCF */ - 0xB922,0xB923,0xB924,0xB925,0xB926,0xB927,0xB928,0xB929,/* 0xD0-0xD7 */ - 0xB92A,0xB92B,0xB92C,0xB92D,0xB92E,0xB92F,0xB930,0xB931,/* 0xD8-0xDF */ - 0xB932,0xB933,0xB934,0xB935,0xB936,0xB937,0xB938,0xB939,/* 0xE0-0xE7 */ - 0xB93A,0xB93B,0xB93E,0xB93F,0xB941,0xB942,0xB943,0xB945,/* 0xE8-0xEF */ - 0xB946,0xB947,0xB948,0xB949,0xB94A,0xB94B,0xB94D,0xB94E,/* 0xF0-0xF7 */ - 0xB950,0xB952,0xB953,0xB954,0xB955,0xB956,0xB957,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_90[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xB95A,0xB95B,0xB95D,0xB95E,0xB95F,0xB961,0xB962,/* 0x40-0x47 */ - 0xB963,0xB964,0xB965,0xB966,0xB967,0xB96A,0xB96C,0xB96E,/* 0x48-0x4F */ - 0xB96F,0xB970,0xB971,0xB972,0xB973,0xB976,0xB977,0xB979,/* 0x50-0x57 */ - 0xB97A,0xB97B,0xB97D,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xB97E,0xB97F,0xB980,0xB981,0xB982,0xB983,0xB986,/* 0x60-0x67 */ - 0xB988,0xB98B,0xB98C,0xB98F,0xB990,0xB991,0xB992,0xB993,/* 0x68-0x6F */ - 0xB994,0xB995,0xB996,0xB997,0xB998,0xB999,0xB99A,0xB99B,/* 0x70-0x77 */ - 0xB99C,0xB99D,0xB99E,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xB99F,0xB9A0,0xB9A1,0xB9A2,0xB9A3,0xB9A4,0xB9A5,/* 0x80-0x87 */ - 0xB9A6,0xB9A7,0xB9A8,0xB9A9,0xB9AA,0xB9AB,0xB9AE,0xB9AF,/* 0x88-0x8F */ - 0xB9B1,0xB9B2,0xB9B3,0xB9B5,0xB9B6,0xB9B7,0xB9B8,0xB9B9,/* 0x90-0x97 */ - 0xB9BA,0xB9BB,0xB9BE,0xB9C0,0xB9C2,0xB9C3,0xB9C4,0xB9C5,/* 0x98-0x9F */ - 0xB9C6,0xB9C7,0xB9CA,0xB9CB,0xB9CD,0xB9D3,0xB9D4,0xB9D5,/* 0xA0-0xA7 */ - 0xB9D6,0xB9D7,0xB9DA,0xB9DC,0xB9DF,0xB9E0,0xB9E2,0xB9E6,/* 0xA8-0xAF */ - 0xB9E7,0xB9E9,0xB9EA,0xB9EB,0xB9ED,0xB9EE,0xB9EF,0xB9F0,/* 0xB0-0xB7 */ - 0xB9F1,0xB9F2,0xB9F3,0xB9F6,0xB9FB,0xB9FC,0xB9FD,0xB9FE,/* 0xB8-0xBF */ - 0xB9FF,0xBA02,0xBA03,0xBA04,0xBA05,0xBA06,0xBA07,0xBA09,/* 0xC0-0xC7 */ - 0xBA0A,0xBA0B,0xBA0C,0xBA0D,0xBA0E,0xBA0F,0xBA10,0xBA11,/* 0xC8-0xCF */ - 0xBA12,0xBA13,0xBA14,0xBA16,0xBA17,0xBA18,0xBA19,0xBA1A,/* 0xD0-0xD7 */ - 0xBA1B,0xBA1C,0xBA1D,0xBA1E,0xBA1F,0xBA20,0xBA21,0xBA22,/* 0xD8-0xDF */ - 0xBA23,0xBA24,0xBA25,0xBA26,0xBA27,0xBA28,0xBA29,0xBA2A,/* 0xE0-0xE7 */ - 0xBA2B,0xBA2C,0xBA2D,0xBA2E,0xBA2F,0xBA30,0xBA31,0xBA32,/* 0xE8-0xEF */ - 0xBA33,0xBA34,0xBA35,0xBA36,0xBA37,0xBA3A,0xBA3B,0xBA3D,/* 0xF0-0xF7 */ - 0xBA3E,0xBA3F,0xBA41,0xBA43,0xBA44,0xBA45,0xBA46,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_91[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xBA47,0xBA4A,0xBA4C,0xBA4F,0xBA50,0xBA51,0xBA52,/* 0x40-0x47 */ - 0xBA56,0xBA57,0xBA59,0xBA5A,0xBA5B,0xBA5D,0xBA5E,0xBA5F,/* 0x48-0x4F */ - 0xBA60,0xBA61,0xBA62,0xBA63,0xBA66,0xBA6A,0xBA6B,0xBA6C,/* 0x50-0x57 */ - 0xBA6D,0xBA6E,0xBA6F,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xBA72,0xBA73,0xBA75,0xBA76,0xBA77,0xBA79,0xBA7A,/* 0x60-0x67 */ - 0xBA7B,0xBA7C,0xBA7D,0xBA7E,0xBA7F,0xBA80,0xBA81,0xBA82,/* 0x68-0x6F */ - 0xBA86,0xBA88,0xBA89,0xBA8A,0xBA8B,0xBA8D,0xBA8E,0xBA8F,/* 0x70-0x77 */ - 0xBA90,0xBA91,0xBA92,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xBA93,0xBA94,0xBA95,0xBA96,0xBA97,0xBA98,0xBA99,/* 0x80-0x87 */ - 0xBA9A,0xBA9B,0xBA9C,0xBA9D,0xBA9E,0xBA9F,0xBAA0,0xBAA1,/* 0x88-0x8F */ - 0xBAA2,0xBAA3,0xBAA4,0xBAA5,0xBAA6,0xBAA7,0xBAAA,0xBAAD,/* 0x90-0x97 */ - 0xBAAE,0xBAAF,0xBAB1,0xBAB3,0xBAB4,0xBAB5,0xBAB6,0xBAB7,/* 0x98-0x9F */ - 0xBABA,0xBABC,0xBABE,0xBABF,0xBAC0,0xBAC1,0xBAC2,0xBAC3,/* 0xA0-0xA7 */ - 0xBAC5,0xBAC6,0xBAC7,0xBAC9,0xBACA,0xBACB,0xBACC,0xBACD,/* 0xA8-0xAF */ - 0xBACE,0xBACF,0xBAD0,0xBAD1,0xBAD2,0xBAD3,0xBAD4,0xBAD5,/* 0xB0-0xB7 */ - 0xBAD6,0xBAD7,0xBADA,0xBADB,0xBADC,0xBADD,0xBADE,0xBADF,/* 0xB8-0xBF */ - 0xBAE0,0xBAE1,0xBAE2,0xBAE3,0xBAE4,0xBAE5,0xBAE6,0xBAE7,/* 0xC0-0xC7 */ - 0xBAE8,0xBAE9,0xBAEA,0xBAEB,0xBAEC,0xBAED,0xBAEE,0xBAEF,/* 0xC8-0xCF */ - 0xBAF0,0xBAF1,0xBAF2,0xBAF3,0xBAF4,0xBAF5,0xBAF6,0xBAF7,/* 0xD0-0xD7 */ - 0xBAF8,0xBAF9,0xBAFA,0xBAFB,0xBAFD,0xBAFE,0xBAFF,0xBB01,/* 0xD8-0xDF */ - 0xBB02,0xBB03,0xBB05,0xBB06,0xBB07,0xBB08,0xBB09,0xBB0A,/* 0xE0-0xE7 */ - 0xBB0B,0xBB0C,0xBB0E,0xBB10,0xBB12,0xBB13,0xBB14,0xBB15,/* 0xE8-0xEF */ - 0xBB16,0xBB17,0xBB19,0xBB1A,0xBB1B,0xBB1D,0xBB1E,0xBB1F,/* 0xF0-0xF7 */ - 0xBB21,0xBB22,0xBB23,0xBB24,0xBB25,0xBB26,0xBB27,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_92[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xBB28,0xBB2A,0xBB2C,0xBB2D,0xBB2E,0xBB2F,0xBB30,/* 0x40-0x47 */ - 0xBB31,0xBB32,0xBB33,0xBB37,0xBB39,0xBB3A,0xBB3F,0xBB40,/* 0x48-0x4F */ - 0xBB41,0xBB42,0xBB43,0xBB46,0xBB48,0xBB4A,0xBB4B,0xBB4C,/* 0x50-0x57 */ - 0xBB4E,0xBB51,0xBB52,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xBB53,0xBB55,0xBB56,0xBB57,0xBB59,0xBB5A,0xBB5B,/* 0x60-0x67 */ - 0xBB5C,0xBB5D,0xBB5E,0xBB5F,0xBB60,0xBB62,0xBB64,0xBB65,/* 0x68-0x6F */ - 0xBB66,0xBB67,0xBB68,0xBB69,0xBB6A,0xBB6B,0xBB6D,0xBB6E,/* 0x70-0x77 */ - 0xBB6F,0xBB70,0xBB71,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xBB72,0xBB73,0xBB74,0xBB75,0xBB76,0xBB77,0xBB78,/* 0x80-0x87 */ - 0xBB79,0xBB7A,0xBB7B,0xBB7C,0xBB7D,0xBB7E,0xBB7F,0xBB80,/* 0x88-0x8F */ - 0xBB81,0xBB82,0xBB83,0xBB84,0xBB85,0xBB86,0xBB87,0xBB89,/* 0x90-0x97 */ - 0xBB8A,0xBB8B,0xBB8D,0xBB8E,0xBB8F,0xBB91,0xBB92,0xBB93,/* 0x98-0x9F */ - 0xBB94,0xBB95,0xBB96,0xBB97,0xBB98,0xBB99,0xBB9A,0xBB9B,/* 0xA0-0xA7 */ - 0xBB9C,0xBB9D,0xBB9E,0xBB9F,0xBBA0,0xBBA1,0xBBA2,0xBBA3,/* 0xA8-0xAF */ - 0xBBA5,0xBBA6,0xBBA7,0xBBA9,0xBBAA,0xBBAB,0xBBAD,0xBBAE,/* 0xB0-0xB7 */ - 0xBBAF,0xBBB0,0xBBB1,0xBBB2,0xBBB3,0xBBB5,0xBBB6,0xBBB8,/* 0xB8-0xBF */ - 0xBBB9,0xBBBA,0xBBBB,0xBBBC,0xBBBD,0xBBBE,0xBBBF,0xBBC1,/* 0xC0-0xC7 */ - 0xBBC2,0xBBC3,0xBBC5,0xBBC6,0xBBC7,0xBBC9,0xBBCA,0xBBCB,/* 0xC8-0xCF */ - 0xBBCC,0xBBCD,0xBBCE,0xBBCF,0xBBD1,0xBBD2,0xBBD4,0xBBD5,/* 0xD0-0xD7 */ - 0xBBD6,0xBBD7,0xBBD8,0xBBD9,0xBBDA,0xBBDB,0xBBDC,0xBBDD,/* 0xD8-0xDF */ - 0xBBDE,0xBBDF,0xBBE0,0xBBE1,0xBBE2,0xBBE3,0xBBE4,0xBBE5,/* 0xE0-0xE7 */ - 0xBBE6,0xBBE7,0xBBE8,0xBBE9,0xBBEA,0xBBEB,0xBBEC,0xBBED,/* 0xE8-0xEF */ - 0xBBEE,0xBBEF,0xBBF0,0xBBF1,0xBBF2,0xBBF3,0xBBF4,0xBBF5,/* 0xF0-0xF7 */ - 0xBBF6,0xBBF7,0xBBFA,0xBBFB,0xBBFD,0xBBFE,0xBC01,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_93[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xBC03,0xBC04,0xBC05,0xBC06,0xBC07,0xBC0A,0xBC0E,/* 0x40-0x47 */ - 0xBC10,0xBC12,0xBC13,0xBC19,0xBC1A,0xBC20,0xBC21,0xBC22,/* 0x48-0x4F */ - 0xBC23,0xBC26,0xBC28,0xBC2A,0xBC2B,0xBC2C,0xBC2E,0xBC2F,/* 0x50-0x57 */ - 0xBC32,0xBC33,0xBC35,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xBC36,0xBC37,0xBC39,0xBC3A,0xBC3B,0xBC3C,0xBC3D,/* 0x60-0x67 */ - 0xBC3E,0xBC3F,0xBC42,0xBC46,0xBC47,0xBC48,0xBC4A,0xBC4B,/* 0x68-0x6F */ - 0xBC4E,0xBC4F,0xBC51,0xBC52,0xBC53,0xBC54,0xBC55,0xBC56,/* 0x70-0x77 */ - 0xBC57,0xBC58,0xBC59,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xBC5A,0xBC5B,0xBC5C,0xBC5E,0xBC5F,0xBC60,0xBC61,/* 0x80-0x87 */ - 0xBC62,0xBC63,0xBC64,0xBC65,0xBC66,0xBC67,0xBC68,0xBC69,/* 0x88-0x8F */ - 0xBC6A,0xBC6B,0xBC6C,0xBC6D,0xBC6E,0xBC6F,0xBC70,0xBC71,/* 0x90-0x97 */ - 0xBC72,0xBC73,0xBC74,0xBC75,0xBC76,0xBC77,0xBC78,0xBC79,/* 0x98-0x9F */ - 0xBC7A,0xBC7B,0xBC7C,0xBC7D,0xBC7E,0xBC7F,0xBC80,0xBC81,/* 0xA0-0xA7 */ - 0xBC82,0xBC83,0xBC86,0xBC87,0xBC89,0xBC8A,0xBC8D,0xBC8F,/* 0xA8-0xAF */ - 0xBC90,0xBC91,0xBC92,0xBC93,0xBC96,0xBC98,0xBC9B,0xBC9C,/* 0xB0-0xB7 */ - 0xBC9D,0xBC9E,0xBC9F,0xBCA2,0xBCA3,0xBCA5,0xBCA6,0xBCA9,/* 0xB8-0xBF */ - 0xBCAA,0xBCAB,0xBCAC,0xBCAD,0xBCAE,0xBCAF,0xBCB2,0xBCB6,/* 0xC0-0xC7 */ - 0xBCB7,0xBCB8,0xBCB9,0xBCBA,0xBCBB,0xBCBE,0xBCBF,0xBCC1,/* 0xC8-0xCF */ - 0xBCC2,0xBCC3,0xBCC5,0xBCC6,0xBCC7,0xBCC8,0xBCC9,0xBCCA,/* 0xD0-0xD7 */ - 0xBCCB,0xBCCC,0xBCCE,0xBCD2,0xBCD3,0xBCD4,0xBCD6,0xBCD7,/* 0xD8-0xDF */ - 0xBCD9,0xBCDA,0xBCDB,0xBCDD,0xBCDE,0xBCDF,0xBCE0,0xBCE1,/* 0xE0-0xE7 */ - 0xBCE2,0xBCE3,0xBCE4,0xBCE5,0xBCE6,0xBCE7,0xBCE8,0xBCE9,/* 0xE8-0xEF */ - 0xBCEA,0xBCEB,0xBCEC,0xBCED,0xBCEE,0xBCEF,0xBCF0,0xBCF1,/* 0xF0-0xF7 */ - 0xBCF2,0xBCF3,0xBCF7,0xBCF9,0xBCFA,0xBCFB,0xBCFD,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_94[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xBCFE,0xBCFF,0xBD00,0xBD01,0xBD02,0xBD03,0xBD06,/* 0x40-0x47 */ - 0xBD08,0xBD0A,0xBD0B,0xBD0C,0xBD0D,0xBD0E,0xBD0F,0xBD11,/* 0x48-0x4F */ - 0xBD12,0xBD13,0xBD15,0xBD16,0xBD17,0xBD18,0xBD19,0xBD1A,/* 0x50-0x57 */ - 0xBD1B,0xBD1C,0xBD1D,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xBD1E,0xBD1F,0xBD20,0xBD21,0xBD22,0xBD23,0xBD25,/* 0x60-0x67 */ - 0xBD26,0xBD27,0xBD28,0xBD29,0xBD2A,0xBD2B,0xBD2D,0xBD2E,/* 0x68-0x6F */ - 0xBD2F,0xBD30,0xBD31,0xBD32,0xBD33,0xBD34,0xBD35,0xBD36,/* 0x70-0x77 */ - 0xBD37,0xBD38,0xBD39,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xBD3A,0xBD3B,0xBD3C,0xBD3D,0xBD3E,0xBD3F,0xBD41,/* 0x80-0x87 */ - 0xBD42,0xBD43,0xBD44,0xBD45,0xBD46,0xBD47,0xBD4A,0xBD4B,/* 0x88-0x8F */ - 0xBD4D,0xBD4E,0xBD4F,0xBD51,0xBD52,0xBD53,0xBD54,0xBD55,/* 0x90-0x97 */ - 0xBD56,0xBD57,0xBD5A,0xBD5B,0xBD5C,0xBD5D,0xBD5E,0xBD5F,/* 0x98-0x9F */ - 0xBD60,0xBD61,0xBD62,0xBD63,0xBD65,0xBD66,0xBD67,0xBD69,/* 0xA0-0xA7 */ - 0xBD6A,0xBD6B,0xBD6C,0xBD6D,0xBD6E,0xBD6F,0xBD70,0xBD71,/* 0xA8-0xAF */ - 0xBD72,0xBD73,0xBD74,0xBD75,0xBD76,0xBD77,0xBD78,0xBD79,/* 0xB0-0xB7 */ - 0xBD7A,0xBD7B,0xBD7C,0xBD7D,0xBD7E,0xBD7F,0xBD82,0xBD83,/* 0xB8-0xBF */ - 0xBD85,0xBD86,0xBD8B,0xBD8C,0xBD8D,0xBD8E,0xBD8F,0xBD92,/* 0xC0-0xC7 */ - 0xBD94,0xBD96,0xBD97,0xBD98,0xBD9B,0xBD9D,0xBD9E,0xBD9F,/* 0xC8-0xCF */ - 0xBDA0,0xBDA1,0xBDA2,0xBDA3,0xBDA5,0xBDA6,0xBDA7,0xBDA8,/* 0xD0-0xD7 */ - 0xBDA9,0xBDAA,0xBDAB,0xBDAC,0xBDAD,0xBDAE,0xBDAF,0xBDB1,/* 0xD8-0xDF */ - 0xBDB2,0xBDB3,0xBDB4,0xBDB5,0xBDB6,0xBDB7,0xBDB9,0xBDBA,/* 0xE0-0xE7 */ - 0xBDBB,0xBDBC,0xBDBD,0xBDBE,0xBDBF,0xBDC0,0xBDC1,0xBDC2,/* 0xE8-0xEF */ - 0xBDC3,0xBDC4,0xBDC5,0xBDC6,0xBDC7,0xBDC8,0xBDC9,0xBDCA,/* 0xF0-0xF7 */ - 0xBDCB,0xBDCC,0xBDCD,0xBDCE,0xBDCF,0xBDD0,0xBDD1,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_95[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xBDD2,0xBDD3,0xBDD6,0xBDD7,0xBDD9,0xBDDA,0xBDDB,/* 0x40-0x47 */ - 0xBDDD,0xBDDE,0xBDDF,0xBDE0,0xBDE1,0xBDE2,0xBDE3,0xBDE4,/* 0x48-0x4F */ - 0xBDE5,0xBDE6,0xBDE7,0xBDE8,0xBDEA,0xBDEB,0xBDEC,0xBDED,/* 0x50-0x57 */ - 0xBDEE,0xBDEF,0xBDF1,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xBDF2,0xBDF3,0xBDF5,0xBDF6,0xBDF7,0xBDF9,0xBDFA,/* 0x60-0x67 */ - 0xBDFB,0xBDFC,0xBDFD,0xBDFE,0xBDFF,0xBE01,0xBE02,0xBE04,/* 0x68-0x6F */ - 0xBE06,0xBE07,0xBE08,0xBE09,0xBE0A,0xBE0B,0xBE0E,0xBE0F,/* 0x70-0x77 */ - 0xBE11,0xBE12,0xBE13,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xBE15,0xBE16,0xBE17,0xBE18,0xBE19,0xBE1A,0xBE1B,/* 0x80-0x87 */ - 0xBE1E,0xBE20,0xBE21,0xBE22,0xBE23,0xBE24,0xBE25,0xBE26,/* 0x88-0x8F */ - 0xBE27,0xBE28,0xBE29,0xBE2A,0xBE2B,0xBE2C,0xBE2D,0xBE2E,/* 0x90-0x97 */ - 0xBE2F,0xBE30,0xBE31,0xBE32,0xBE33,0xBE34,0xBE35,0xBE36,/* 0x98-0x9F */ - 0xBE37,0xBE38,0xBE39,0xBE3A,0xBE3B,0xBE3C,0xBE3D,0xBE3E,/* 0xA0-0xA7 */ - 0xBE3F,0xBE40,0xBE41,0xBE42,0xBE43,0xBE46,0xBE47,0xBE49,/* 0xA8-0xAF */ - 0xBE4A,0xBE4B,0xBE4D,0xBE4F,0xBE50,0xBE51,0xBE52,0xBE53,/* 0xB0-0xB7 */ - 0xBE56,0xBE58,0xBE5C,0xBE5D,0xBE5E,0xBE5F,0xBE62,0xBE63,/* 0xB8-0xBF */ - 0xBE65,0xBE66,0xBE67,0xBE69,0xBE6B,0xBE6C,0xBE6D,0xBE6E,/* 0xC0-0xC7 */ - 0xBE6F,0xBE72,0xBE76,0xBE77,0xBE78,0xBE79,0xBE7A,0xBE7E,/* 0xC8-0xCF */ - 0xBE7F,0xBE81,0xBE82,0xBE83,0xBE85,0xBE86,0xBE87,0xBE88,/* 0xD0-0xD7 */ - 0xBE89,0xBE8A,0xBE8B,0xBE8E,0xBE92,0xBE93,0xBE94,0xBE95,/* 0xD8-0xDF */ - 0xBE96,0xBE97,0xBE9A,0xBE9B,0xBE9C,0xBE9D,0xBE9E,0xBE9F,/* 0xE0-0xE7 */ - 0xBEA0,0xBEA1,0xBEA2,0xBEA3,0xBEA4,0xBEA5,0xBEA6,0xBEA7,/* 0xE8-0xEF */ - 0xBEA9,0xBEAA,0xBEAB,0xBEAC,0xBEAD,0xBEAE,0xBEAF,0xBEB0,/* 0xF0-0xF7 */ - 0xBEB1,0xBEB2,0xBEB3,0xBEB4,0xBEB5,0xBEB6,0xBEB7,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_96[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xBEB8,0xBEB9,0xBEBA,0xBEBB,0xBEBC,0xBEBD,0xBEBE,/* 0x40-0x47 */ - 0xBEBF,0xBEC0,0xBEC1,0xBEC2,0xBEC3,0xBEC4,0xBEC5,0xBEC6,/* 0x48-0x4F */ - 0xBEC7,0xBEC8,0xBEC9,0xBECA,0xBECB,0xBECC,0xBECD,0xBECE,/* 0x50-0x57 */ - 0xBECF,0xBED2,0xBED3,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xBED5,0xBED6,0xBED9,0xBEDA,0xBEDB,0xBEDC,0xBEDD,/* 0x60-0x67 */ - 0xBEDE,0xBEDF,0xBEE1,0xBEE2,0xBEE6,0xBEE7,0xBEE8,0xBEE9,/* 0x68-0x6F */ - 0xBEEA,0xBEEB,0xBEED,0xBEEE,0xBEEF,0xBEF0,0xBEF1,0xBEF2,/* 0x70-0x77 */ - 0xBEF3,0xBEF4,0xBEF5,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xBEF6,0xBEF7,0xBEF8,0xBEF9,0xBEFA,0xBEFB,0xBEFC,/* 0x80-0x87 */ - 0xBEFD,0xBEFE,0xBEFF,0xBF00,0xBF02,0xBF03,0xBF04,0xBF05,/* 0x88-0x8F */ - 0xBF06,0xBF07,0xBF0A,0xBF0B,0xBF0C,0xBF0D,0xBF0E,0xBF0F,/* 0x90-0x97 */ - 0xBF10,0xBF11,0xBF12,0xBF13,0xBF14,0xBF15,0xBF16,0xBF17,/* 0x98-0x9F */ - 0xBF1A,0xBF1E,0xBF1F,0xBF20,0xBF21,0xBF22,0xBF23,0xBF24,/* 0xA0-0xA7 */ - 0xBF25,0xBF26,0xBF27,0xBF28,0xBF29,0xBF2A,0xBF2B,0xBF2C,/* 0xA8-0xAF */ - 0xBF2D,0xBF2E,0xBF2F,0xBF30,0xBF31,0xBF32,0xBF33,0xBF34,/* 0xB0-0xB7 */ - 0xBF35,0xBF36,0xBF37,0xBF38,0xBF39,0xBF3A,0xBF3B,0xBF3C,/* 0xB8-0xBF */ - 0xBF3D,0xBF3E,0xBF3F,0xBF42,0xBF43,0xBF45,0xBF46,0xBF47,/* 0xC0-0xC7 */ - 0xBF49,0xBF4A,0xBF4B,0xBF4C,0xBF4D,0xBF4E,0xBF4F,0xBF52,/* 0xC8-0xCF */ - 0xBF53,0xBF54,0xBF56,0xBF57,0xBF58,0xBF59,0xBF5A,0xBF5B,/* 0xD0-0xD7 */ - 0xBF5C,0xBF5D,0xBF5E,0xBF5F,0xBF60,0xBF61,0xBF62,0xBF63,/* 0xD8-0xDF */ - 0xBF64,0xBF65,0xBF66,0xBF67,0xBF68,0xBF69,0xBF6A,0xBF6B,/* 0xE0-0xE7 */ - 0xBF6C,0xBF6D,0xBF6E,0xBF6F,0xBF70,0xBF71,0xBF72,0xBF73,/* 0xE8-0xEF */ - 0xBF74,0xBF75,0xBF76,0xBF77,0xBF78,0xBF79,0xBF7A,0xBF7B,/* 0xF0-0xF7 */ - 0xBF7C,0xBF7D,0xBF7E,0xBF7F,0xBF80,0xBF81,0xBF82,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_97[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xBF83,0xBF84,0xBF85,0xBF86,0xBF87,0xBF88,0xBF89,/* 0x40-0x47 */ - 0xBF8A,0xBF8B,0xBF8C,0xBF8D,0xBF8E,0xBF8F,0xBF90,0xBF91,/* 0x48-0x4F */ - 0xBF92,0xBF93,0xBF95,0xBF96,0xBF97,0xBF98,0xBF99,0xBF9A,/* 0x50-0x57 */ - 0xBF9B,0xBF9C,0xBF9D,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xBF9E,0xBF9F,0xBFA0,0xBFA1,0xBFA2,0xBFA3,0xBFA4,/* 0x60-0x67 */ - 0xBFA5,0xBFA6,0xBFA7,0xBFA8,0xBFA9,0xBFAA,0xBFAB,0xBFAC,/* 0x68-0x6F */ - 0xBFAD,0xBFAE,0xBFAF,0xBFB1,0xBFB2,0xBFB3,0xBFB4,0xBFB5,/* 0x70-0x77 */ - 0xBFB6,0xBFB7,0xBFB8,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xBFB9,0xBFBA,0xBFBB,0xBFBC,0xBFBD,0xBFBE,0xBFBF,/* 0x80-0x87 */ - 0xBFC0,0xBFC1,0xBFC2,0xBFC3,0xBFC4,0xBFC6,0xBFC7,0xBFC8,/* 0x88-0x8F */ - 0xBFC9,0xBFCA,0xBFCB,0xBFCE,0xBFCF,0xBFD1,0xBFD2,0xBFD3,/* 0x90-0x97 */ - 0xBFD5,0xBFD6,0xBFD7,0xBFD8,0xBFD9,0xBFDA,0xBFDB,0xBFDD,/* 0x98-0x9F */ - 0xBFDE,0xBFE0,0xBFE2,0xBFE3,0xBFE4,0xBFE5,0xBFE6,0xBFE7,/* 0xA0-0xA7 */ - 0xBFE8,0xBFE9,0xBFEA,0xBFEB,0xBFEC,0xBFED,0xBFEE,0xBFEF,/* 0xA8-0xAF */ - 0xBFF0,0xBFF1,0xBFF2,0xBFF3,0xBFF4,0xBFF5,0xBFF6,0xBFF7,/* 0xB0-0xB7 */ - 0xBFF8,0xBFF9,0xBFFA,0xBFFB,0xBFFC,0xBFFD,0xBFFE,0xBFFF,/* 0xB8-0xBF */ - 0xC000,0xC001,0xC002,0xC003,0xC004,0xC005,0xC006,0xC007,/* 0xC0-0xC7 */ - 0xC008,0xC009,0xC00A,0xC00B,0xC00C,0xC00D,0xC00E,0xC00F,/* 0xC8-0xCF */ - 0xC010,0xC011,0xC012,0xC013,0xC014,0xC015,0xC016,0xC017,/* 0xD0-0xD7 */ - 0xC018,0xC019,0xC01A,0xC01B,0xC01C,0xC01D,0xC01E,0xC01F,/* 0xD8-0xDF */ - 0xC020,0xC021,0xC022,0xC023,0xC024,0xC025,0xC026,0xC027,/* 0xE0-0xE7 */ - 0xC028,0xC029,0xC02A,0xC02B,0xC02C,0xC02D,0xC02E,0xC02F,/* 0xE8-0xEF */ - 0xC030,0xC031,0xC032,0xC033,0xC034,0xC035,0xC036,0xC037,/* 0xF0-0xF7 */ - 0xC038,0xC039,0xC03A,0xC03B,0xC03D,0xC03E,0xC03F,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_98[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xC040,0xC041,0xC042,0xC043,0xC044,0xC045,0xC046,/* 0x40-0x47 */ - 0xC047,0xC048,0xC049,0xC04A,0xC04B,0xC04C,0xC04D,0xC04E,/* 0x48-0x4F */ - 0xC04F,0xC050,0xC052,0xC053,0xC054,0xC055,0xC056,0xC057,/* 0x50-0x57 */ - 0xC059,0xC05A,0xC05B,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xC05D,0xC05E,0xC05F,0xC061,0xC062,0xC063,0xC064,/* 0x60-0x67 */ - 0xC065,0xC066,0xC067,0xC06A,0xC06B,0xC06C,0xC06D,0xC06E,/* 0x68-0x6F */ - 0xC06F,0xC070,0xC071,0xC072,0xC073,0xC074,0xC075,0xC076,/* 0x70-0x77 */ - 0xC077,0xC078,0xC079,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xC07A,0xC07B,0xC07C,0xC07D,0xC07E,0xC07F,0xC080,/* 0x80-0x87 */ - 0xC081,0xC082,0xC083,0xC084,0xC085,0xC086,0xC087,0xC088,/* 0x88-0x8F */ - 0xC089,0xC08A,0xC08B,0xC08C,0xC08D,0xC08E,0xC08F,0xC092,/* 0x90-0x97 */ - 0xC093,0xC095,0xC096,0xC097,0xC099,0xC09A,0xC09B,0xC09C,/* 0x98-0x9F */ - 0xC09D,0xC09E,0xC09F,0xC0A2,0xC0A4,0xC0A6,0xC0A7,0xC0A8,/* 0xA0-0xA7 */ - 0xC0A9,0xC0AA,0xC0AB,0xC0AE,0xC0B1,0xC0B2,0xC0B7,0xC0B8,/* 0xA8-0xAF */ - 0xC0B9,0xC0BA,0xC0BB,0xC0BE,0xC0C2,0xC0C3,0xC0C4,0xC0C6,/* 0xB0-0xB7 */ - 0xC0C7,0xC0CA,0xC0CB,0xC0CD,0xC0CE,0xC0CF,0xC0D1,0xC0D2,/* 0xB8-0xBF */ - 0xC0D3,0xC0D4,0xC0D5,0xC0D6,0xC0D7,0xC0DA,0xC0DE,0xC0DF,/* 0xC0-0xC7 */ - 0xC0E0,0xC0E1,0xC0E2,0xC0E3,0xC0E6,0xC0E7,0xC0E9,0xC0EA,/* 0xC8-0xCF */ - 0xC0EB,0xC0ED,0xC0EE,0xC0EF,0xC0F0,0xC0F1,0xC0F2,0xC0F3,/* 0xD0-0xD7 */ - 0xC0F6,0xC0F8,0xC0FA,0xC0FB,0xC0FC,0xC0FD,0xC0FE,0xC0FF,/* 0xD8-0xDF */ - 0xC101,0xC102,0xC103,0xC105,0xC106,0xC107,0xC109,0xC10A,/* 0xE0-0xE7 */ - 0xC10B,0xC10C,0xC10D,0xC10E,0xC10F,0xC111,0xC112,0xC113,/* 0xE8-0xEF */ - 0xC114,0xC116,0xC117,0xC118,0xC119,0xC11A,0xC11B,0xC121,/* 0xF0-0xF7 */ - 0xC122,0xC125,0xC128,0xC129,0xC12A,0xC12B,0xC12E,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_99[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xC132,0xC133,0xC134,0xC135,0xC137,0xC13A,0xC13B,/* 0x40-0x47 */ - 0xC13D,0xC13E,0xC13F,0xC141,0xC142,0xC143,0xC144,0xC145,/* 0x48-0x4F */ - 0xC146,0xC147,0xC14A,0xC14E,0xC14F,0xC150,0xC151,0xC152,/* 0x50-0x57 */ - 0xC153,0xC156,0xC157,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xC159,0xC15A,0xC15B,0xC15D,0xC15E,0xC15F,0xC160,/* 0x60-0x67 */ - 0xC161,0xC162,0xC163,0xC166,0xC16A,0xC16B,0xC16C,0xC16D,/* 0x68-0x6F */ - 0xC16E,0xC16F,0xC171,0xC172,0xC173,0xC175,0xC176,0xC177,/* 0x70-0x77 */ - 0xC179,0xC17A,0xC17B,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xC17C,0xC17D,0xC17E,0xC17F,0xC180,0xC181,0xC182,/* 0x80-0x87 */ - 0xC183,0xC184,0xC186,0xC187,0xC188,0xC189,0xC18A,0xC18B,/* 0x88-0x8F */ - 0xC18F,0xC191,0xC192,0xC193,0xC195,0xC197,0xC198,0xC199,/* 0x90-0x97 */ - 0xC19A,0xC19B,0xC19E,0xC1A0,0xC1A2,0xC1A3,0xC1A4,0xC1A6,/* 0x98-0x9F */ - 0xC1A7,0xC1AA,0xC1AB,0xC1AD,0xC1AE,0xC1AF,0xC1B1,0xC1B2,/* 0xA0-0xA7 */ - 0xC1B3,0xC1B4,0xC1B5,0xC1B6,0xC1B7,0xC1B8,0xC1B9,0xC1BA,/* 0xA8-0xAF */ - 0xC1BB,0xC1BC,0xC1BE,0xC1BF,0xC1C0,0xC1C1,0xC1C2,0xC1C3,/* 0xB0-0xB7 */ - 0xC1C5,0xC1C6,0xC1C7,0xC1C9,0xC1CA,0xC1CB,0xC1CD,0xC1CE,/* 0xB8-0xBF */ - 0xC1CF,0xC1D0,0xC1D1,0xC1D2,0xC1D3,0xC1D5,0xC1D6,0xC1D9,/* 0xC0-0xC7 */ - 0xC1DA,0xC1DB,0xC1DC,0xC1DD,0xC1DE,0xC1DF,0xC1E1,0xC1E2,/* 0xC8-0xCF */ - 0xC1E3,0xC1E5,0xC1E6,0xC1E7,0xC1E9,0xC1EA,0xC1EB,0xC1EC,/* 0xD0-0xD7 */ - 0xC1ED,0xC1EE,0xC1EF,0xC1F2,0xC1F4,0xC1F5,0xC1F6,0xC1F7,/* 0xD8-0xDF */ - 0xC1F8,0xC1F9,0xC1FA,0xC1FB,0xC1FE,0xC1FF,0xC201,0xC202,/* 0xE0-0xE7 */ - 0xC203,0xC205,0xC206,0xC207,0xC208,0xC209,0xC20A,0xC20B,/* 0xE8-0xEF */ - 0xC20E,0xC210,0xC212,0xC213,0xC214,0xC215,0xC216,0xC217,/* 0xF0-0xF7 */ - 0xC21A,0xC21B,0xC21D,0xC21E,0xC221,0xC222,0xC223,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_9A[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xC224,0xC225,0xC226,0xC227,0xC22A,0xC22C,0xC22E,/* 0x40-0x47 */ - 0xC230,0xC233,0xC235,0xC236,0xC237,0xC238,0xC239,0xC23A,/* 0x48-0x4F */ - 0xC23B,0xC23C,0xC23D,0xC23E,0xC23F,0xC240,0xC241,0xC242,/* 0x50-0x57 */ - 0xC243,0xC244,0xC245,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xC246,0xC247,0xC249,0xC24A,0xC24B,0xC24C,0xC24D,/* 0x60-0x67 */ - 0xC24E,0xC24F,0xC252,0xC253,0xC255,0xC256,0xC257,0xC259,/* 0x68-0x6F */ - 0xC25A,0xC25B,0xC25C,0xC25D,0xC25E,0xC25F,0xC261,0xC262,/* 0x70-0x77 */ - 0xC263,0xC264,0xC266,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xC267,0xC268,0xC269,0xC26A,0xC26B,0xC26E,0xC26F,/* 0x80-0x87 */ - 0xC271,0xC272,0xC273,0xC275,0xC276,0xC277,0xC278,0xC279,/* 0x88-0x8F */ - 0xC27A,0xC27B,0xC27E,0xC280,0xC282,0xC283,0xC284,0xC285,/* 0x90-0x97 */ - 0xC286,0xC287,0xC28A,0xC28B,0xC28C,0xC28D,0xC28E,0xC28F,/* 0x98-0x9F */ - 0xC291,0xC292,0xC293,0xC294,0xC295,0xC296,0xC297,0xC299,/* 0xA0-0xA7 */ - 0xC29A,0xC29C,0xC29E,0xC29F,0xC2A0,0xC2A1,0xC2A2,0xC2A3,/* 0xA8-0xAF */ - 0xC2A6,0xC2A7,0xC2A9,0xC2AA,0xC2AB,0xC2AE,0xC2AF,0xC2B0,/* 0xB0-0xB7 */ - 0xC2B1,0xC2B2,0xC2B3,0xC2B6,0xC2B8,0xC2BA,0xC2BB,0xC2BC,/* 0xB8-0xBF */ - 0xC2BD,0xC2BE,0xC2BF,0xC2C0,0xC2C1,0xC2C2,0xC2C3,0xC2C4,/* 0xC0-0xC7 */ - 0xC2C5,0xC2C6,0xC2C7,0xC2C8,0xC2C9,0xC2CA,0xC2CB,0xC2CC,/* 0xC8-0xCF */ - 0xC2CD,0xC2CE,0xC2CF,0xC2D0,0xC2D1,0xC2D2,0xC2D3,0xC2D4,/* 0xD0-0xD7 */ - 0xC2D5,0xC2D6,0xC2D7,0xC2D8,0xC2D9,0xC2DA,0xC2DB,0xC2DE,/* 0xD8-0xDF */ - 0xC2DF,0xC2E1,0xC2E2,0xC2E5,0xC2E6,0xC2E7,0xC2E8,0xC2E9,/* 0xE0-0xE7 */ - 0xC2EA,0xC2EE,0xC2F0,0xC2F2,0xC2F3,0xC2F4,0xC2F5,0xC2F7,/* 0xE8-0xEF */ - 0xC2FA,0xC2FD,0xC2FE,0xC2FF,0xC301,0xC302,0xC303,0xC304,/* 0xF0-0xF7 */ - 0xC305,0xC306,0xC307,0xC30A,0xC30B,0xC30E,0xC30F,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_9B[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xC310,0xC311,0xC312,0xC316,0xC317,0xC319,0xC31A,/* 0x40-0x47 */ - 0xC31B,0xC31D,0xC31E,0xC31F,0xC320,0xC321,0xC322,0xC323,/* 0x48-0x4F */ - 0xC326,0xC327,0xC32A,0xC32B,0xC32C,0xC32D,0xC32E,0xC32F,/* 0x50-0x57 */ - 0xC330,0xC331,0xC332,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xC333,0xC334,0xC335,0xC336,0xC337,0xC338,0xC339,/* 0x60-0x67 */ - 0xC33A,0xC33B,0xC33C,0xC33D,0xC33E,0xC33F,0xC340,0xC341,/* 0x68-0x6F */ - 0xC342,0xC343,0xC344,0xC346,0xC347,0xC348,0xC349,0xC34A,/* 0x70-0x77 */ - 0xC34B,0xC34C,0xC34D,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xC34E,0xC34F,0xC350,0xC351,0xC352,0xC353,0xC354,/* 0x80-0x87 */ - 0xC355,0xC356,0xC357,0xC358,0xC359,0xC35A,0xC35B,0xC35C,/* 0x88-0x8F */ - 0xC35D,0xC35E,0xC35F,0xC360,0xC361,0xC362,0xC363,0xC364,/* 0x90-0x97 */ - 0xC365,0xC366,0xC367,0xC36A,0xC36B,0xC36D,0xC36E,0xC36F,/* 0x98-0x9F */ - 0xC371,0xC373,0xC374,0xC375,0xC376,0xC377,0xC37A,0xC37B,/* 0xA0-0xA7 */ - 0xC37E,0xC37F,0xC380,0xC381,0xC382,0xC383,0xC385,0xC386,/* 0xA8-0xAF */ - 0xC387,0xC389,0xC38A,0xC38B,0xC38D,0xC38E,0xC38F,0xC390,/* 0xB0-0xB7 */ - 0xC391,0xC392,0xC393,0xC394,0xC395,0xC396,0xC397,0xC398,/* 0xB8-0xBF */ - 0xC399,0xC39A,0xC39B,0xC39C,0xC39D,0xC39E,0xC39F,0xC3A0,/* 0xC0-0xC7 */ - 0xC3A1,0xC3A2,0xC3A3,0xC3A4,0xC3A5,0xC3A6,0xC3A7,0xC3A8,/* 0xC8-0xCF */ - 0xC3A9,0xC3AA,0xC3AB,0xC3AC,0xC3AD,0xC3AE,0xC3AF,0xC3B0,/* 0xD0-0xD7 */ - 0xC3B1,0xC3B2,0xC3B3,0xC3B4,0xC3B5,0xC3B6,0xC3B7,0xC3B8,/* 0xD8-0xDF */ - 0xC3B9,0xC3BA,0xC3BB,0xC3BC,0xC3BD,0xC3BE,0xC3BF,0xC3C1,/* 0xE0-0xE7 */ - 0xC3C2,0xC3C3,0xC3C4,0xC3C5,0xC3C6,0xC3C7,0xC3C8,0xC3C9,/* 0xE8-0xEF */ - 0xC3CA,0xC3CB,0xC3CC,0xC3CD,0xC3CE,0xC3CF,0xC3D0,0xC3D1,/* 0xF0-0xF7 */ - 0xC3D2,0xC3D3,0xC3D4,0xC3D5,0xC3D6,0xC3D7,0xC3DA,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_9C[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xC3DB,0xC3DD,0xC3DE,0xC3E1,0xC3E3,0xC3E4,0xC3E5,/* 0x40-0x47 */ - 0xC3E6,0xC3E7,0xC3EA,0xC3EB,0xC3EC,0xC3EE,0xC3EF,0xC3F0,/* 0x48-0x4F */ - 0xC3F1,0xC3F2,0xC3F3,0xC3F6,0xC3F7,0xC3F9,0xC3FA,0xC3FB,/* 0x50-0x57 */ - 0xC3FC,0xC3FD,0xC3FE,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xC3FF,0xC400,0xC401,0xC402,0xC403,0xC404,0xC405,/* 0x60-0x67 */ - 0xC406,0xC407,0xC409,0xC40A,0xC40B,0xC40C,0xC40D,0xC40E,/* 0x68-0x6F */ - 0xC40F,0xC411,0xC412,0xC413,0xC414,0xC415,0xC416,0xC417,/* 0x70-0x77 */ - 0xC418,0xC419,0xC41A,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xC41B,0xC41C,0xC41D,0xC41E,0xC41F,0xC420,0xC421,/* 0x80-0x87 */ - 0xC422,0xC423,0xC425,0xC426,0xC427,0xC428,0xC429,0xC42A,/* 0x88-0x8F */ - 0xC42B,0xC42D,0xC42E,0xC42F,0xC431,0xC432,0xC433,0xC435,/* 0x90-0x97 */ - 0xC436,0xC437,0xC438,0xC439,0xC43A,0xC43B,0xC43E,0xC43F,/* 0x98-0x9F */ - 0xC440,0xC441,0xC442,0xC443,0xC444,0xC445,0xC446,0xC447,/* 0xA0-0xA7 */ - 0xC449,0xC44A,0xC44B,0xC44C,0xC44D,0xC44E,0xC44F,0xC450,/* 0xA8-0xAF */ - 0xC451,0xC452,0xC453,0xC454,0xC455,0xC456,0xC457,0xC458,/* 0xB0-0xB7 */ - 0xC459,0xC45A,0xC45B,0xC45C,0xC45D,0xC45E,0xC45F,0xC460,/* 0xB8-0xBF */ - 0xC461,0xC462,0xC463,0xC466,0xC467,0xC469,0xC46A,0xC46B,/* 0xC0-0xC7 */ - 0xC46D,0xC46E,0xC46F,0xC470,0xC471,0xC472,0xC473,0xC476,/* 0xC8-0xCF */ - 0xC477,0xC478,0xC47A,0xC47B,0xC47C,0xC47D,0xC47E,0xC47F,/* 0xD0-0xD7 */ - 0xC481,0xC482,0xC483,0xC484,0xC485,0xC486,0xC487,0xC488,/* 0xD8-0xDF */ - 0xC489,0xC48A,0xC48B,0xC48C,0xC48D,0xC48E,0xC48F,0xC490,/* 0xE0-0xE7 */ - 0xC491,0xC492,0xC493,0xC495,0xC496,0xC497,0xC498,0xC499,/* 0xE8-0xEF */ - 0xC49A,0xC49B,0xC49D,0xC49E,0xC49F,0xC4A0,0xC4A1,0xC4A2,/* 0xF0-0xF7 */ - 0xC4A3,0xC4A4,0xC4A5,0xC4A6,0xC4A7,0xC4A8,0xC4A9,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_9D[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xC4AA,0xC4AB,0xC4AC,0xC4AD,0xC4AE,0xC4AF,0xC4B0,/* 0x40-0x47 */ - 0xC4B1,0xC4B2,0xC4B3,0xC4B4,0xC4B5,0xC4B6,0xC4B7,0xC4B9,/* 0x48-0x4F */ - 0xC4BA,0xC4BB,0xC4BD,0xC4BE,0xC4BF,0xC4C0,0xC4C1,0xC4C2,/* 0x50-0x57 */ - 0xC4C3,0xC4C4,0xC4C5,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xC4C6,0xC4C7,0xC4C8,0xC4C9,0xC4CA,0xC4CB,0xC4CC,/* 0x60-0x67 */ - 0xC4CD,0xC4CE,0xC4CF,0xC4D0,0xC4D1,0xC4D2,0xC4D3,0xC4D4,/* 0x68-0x6F */ - 0xC4D5,0xC4D6,0xC4D7,0xC4D8,0xC4D9,0xC4DA,0xC4DB,0xC4DC,/* 0x70-0x77 */ - 0xC4DD,0xC4DE,0xC4DF,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xC4E0,0xC4E1,0xC4E2,0xC4E3,0xC4E4,0xC4E5,0xC4E6,/* 0x80-0x87 */ - 0xC4E7,0xC4E8,0xC4EA,0xC4EB,0xC4EC,0xC4ED,0xC4EE,0xC4EF,/* 0x88-0x8F */ - 0xC4F2,0xC4F3,0xC4F5,0xC4F6,0xC4F7,0xC4F9,0xC4FB,0xC4FC,/* 0x90-0x97 */ - 0xC4FD,0xC4FE,0xC502,0xC503,0xC504,0xC505,0xC506,0xC507,/* 0x98-0x9F */ - 0xC508,0xC509,0xC50A,0xC50B,0xC50D,0xC50E,0xC50F,0xC511,/* 0xA0-0xA7 */ - 0xC512,0xC513,0xC515,0xC516,0xC517,0xC518,0xC519,0xC51A,/* 0xA8-0xAF */ - 0xC51B,0xC51D,0xC51E,0xC51F,0xC520,0xC521,0xC522,0xC523,/* 0xB0-0xB7 */ - 0xC524,0xC525,0xC526,0xC527,0xC52A,0xC52B,0xC52D,0xC52E,/* 0xB8-0xBF */ - 0xC52F,0xC531,0xC532,0xC533,0xC534,0xC535,0xC536,0xC537,/* 0xC0-0xC7 */ - 0xC53A,0xC53C,0xC53E,0xC53F,0xC540,0xC541,0xC542,0xC543,/* 0xC8-0xCF */ - 0xC546,0xC547,0xC54B,0xC54F,0xC550,0xC551,0xC552,0xC556,/* 0xD0-0xD7 */ - 0xC55A,0xC55B,0xC55C,0xC55F,0xC562,0xC563,0xC565,0xC566,/* 0xD8-0xDF */ - 0xC567,0xC569,0xC56A,0xC56B,0xC56C,0xC56D,0xC56E,0xC56F,/* 0xE0-0xE7 */ - 0xC572,0xC576,0xC577,0xC578,0xC579,0xC57A,0xC57B,0xC57E,/* 0xE8-0xEF */ - 0xC57F,0xC581,0xC582,0xC583,0xC585,0xC586,0xC588,0xC589,/* 0xF0-0xF7 */ - 0xC58A,0xC58B,0xC58E,0xC590,0xC592,0xC593,0xC594,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_9E[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xC596,0xC599,0xC59A,0xC59B,0xC59D,0xC59E,0xC59F,/* 0x40-0x47 */ - 0xC5A1,0xC5A2,0xC5A3,0xC5A4,0xC5A5,0xC5A6,0xC5A7,0xC5A8,/* 0x48-0x4F */ - 0xC5AA,0xC5AB,0xC5AC,0xC5AD,0xC5AE,0xC5AF,0xC5B0,0xC5B1,/* 0x50-0x57 */ - 0xC5B2,0xC5B3,0xC5B6,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xC5B7,0xC5BA,0xC5BF,0xC5C0,0xC5C1,0xC5C2,0xC5C3,/* 0x60-0x67 */ - 0xC5CB,0xC5CD,0xC5CF,0xC5D2,0xC5D3,0xC5D5,0xC5D6,0xC5D7,/* 0x68-0x6F */ - 0xC5D9,0xC5DA,0xC5DB,0xC5DC,0xC5DD,0xC5DE,0xC5DF,0xC5E2,/* 0x70-0x77 */ - 0xC5E4,0xC5E6,0xC5E7,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xC5E8,0xC5E9,0xC5EA,0xC5EB,0xC5EF,0xC5F1,0xC5F2,/* 0x80-0x87 */ - 0xC5F3,0xC5F5,0xC5F8,0xC5F9,0xC5FA,0xC5FB,0xC602,0xC603,/* 0x88-0x8F */ - 0xC604,0xC609,0xC60A,0xC60B,0xC60D,0xC60E,0xC60F,0xC611,/* 0x90-0x97 */ - 0xC612,0xC613,0xC614,0xC615,0xC616,0xC617,0xC61A,0xC61D,/* 0x98-0x9F */ - 0xC61E,0xC61F,0xC620,0xC621,0xC622,0xC623,0xC626,0xC627,/* 0xA0-0xA7 */ - 0xC629,0xC62A,0xC62B,0xC62F,0xC631,0xC632,0xC636,0xC638,/* 0xA8-0xAF */ - 0xC63A,0xC63C,0xC63D,0xC63E,0xC63F,0xC642,0xC643,0xC645,/* 0xB0-0xB7 */ - 0xC646,0xC647,0xC649,0xC64A,0xC64B,0xC64C,0xC64D,0xC64E,/* 0xB8-0xBF */ - 0xC64F,0xC652,0xC656,0xC657,0xC658,0xC659,0xC65A,0xC65B,/* 0xC0-0xC7 */ - 0xC65E,0xC65F,0xC661,0xC662,0xC663,0xC664,0xC665,0xC666,/* 0xC8-0xCF */ - 0xC667,0xC668,0xC669,0xC66A,0xC66B,0xC66D,0xC66E,0xC670,/* 0xD0-0xD7 */ - 0xC672,0xC673,0xC674,0xC675,0xC676,0xC677,0xC67A,0xC67B,/* 0xD8-0xDF */ - 0xC67D,0xC67E,0xC67F,0xC681,0xC682,0xC683,0xC684,0xC685,/* 0xE0-0xE7 */ - 0xC686,0xC687,0xC68A,0xC68C,0xC68E,0xC68F,0xC690,0xC691,/* 0xE8-0xEF */ - 0xC692,0xC693,0xC696,0xC697,0xC699,0xC69A,0xC69B,0xC69D,/* 0xF0-0xF7 */ - 0xC69E,0xC69F,0xC6A0,0xC6A1,0xC6A2,0xC6A3,0xC6A6,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_9F[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xC6A8,0xC6AA,0xC6AB,0xC6AC,0xC6AD,0xC6AE,0xC6AF,/* 0x40-0x47 */ - 0xC6B2,0xC6B3,0xC6B5,0xC6B6,0xC6B7,0xC6BB,0xC6BC,0xC6BD,/* 0x48-0x4F */ - 0xC6BE,0xC6BF,0xC6C2,0xC6C4,0xC6C6,0xC6C7,0xC6C8,0xC6C9,/* 0x50-0x57 */ - 0xC6CA,0xC6CB,0xC6CE,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xC6CF,0xC6D1,0xC6D2,0xC6D3,0xC6D5,0xC6D6,0xC6D7,/* 0x60-0x67 */ - 0xC6D8,0xC6D9,0xC6DA,0xC6DB,0xC6DE,0xC6DF,0xC6E2,0xC6E3,/* 0x68-0x6F */ - 0xC6E4,0xC6E5,0xC6E6,0xC6E7,0xC6EA,0xC6EB,0xC6ED,0xC6EE,/* 0x70-0x77 */ - 0xC6EF,0xC6F1,0xC6F2,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xC6F3,0xC6F4,0xC6F5,0xC6F6,0xC6F7,0xC6FA,0xC6FB,/* 0x80-0x87 */ - 0xC6FC,0xC6FE,0xC6FF,0xC700,0xC701,0xC702,0xC703,0xC706,/* 0x88-0x8F */ - 0xC707,0xC709,0xC70A,0xC70B,0xC70D,0xC70E,0xC70F,0xC710,/* 0x90-0x97 */ - 0xC711,0xC712,0xC713,0xC716,0xC718,0xC71A,0xC71B,0xC71C,/* 0x98-0x9F */ - 0xC71D,0xC71E,0xC71F,0xC722,0xC723,0xC725,0xC726,0xC727,/* 0xA0-0xA7 */ - 0xC729,0xC72A,0xC72B,0xC72C,0xC72D,0xC72E,0xC72F,0xC732,/* 0xA8-0xAF */ - 0xC734,0xC736,0xC738,0xC739,0xC73A,0xC73B,0xC73E,0xC73F,/* 0xB0-0xB7 */ - 0xC741,0xC742,0xC743,0xC745,0xC746,0xC747,0xC748,0xC749,/* 0xB8-0xBF */ - 0xC74B,0xC74E,0xC750,0xC759,0xC75A,0xC75B,0xC75D,0xC75E,/* 0xC0-0xC7 */ - 0xC75F,0xC761,0xC762,0xC763,0xC764,0xC765,0xC766,0xC767,/* 0xC8-0xCF */ - 0xC769,0xC76A,0xC76C,0xC76D,0xC76E,0xC76F,0xC770,0xC771,/* 0xD0-0xD7 */ - 0xC772,0xC773,0xC776,0xC777,0xC779,0xC77A,0xC77B,0xC77F,/* 0xD8-0xDF */ - 0xC780,0xC781,0xC782,0xC786,0xC78B,0xC78C,0xC78D,0xC78F,/* 0xE0-0xE7 */ - 0xC792,0xC793,0xC795,0xC799,0xC79B,0xC79C,0xC79D,0xC79E,/* 0xE8-0xEF */ - 0xC79F,0xC7A2,0xC7A7,0xC7A8,0xC7A9,0xC7AA,0xC7AB,0xC7AE,/* 0xF0-0xF7 */ - 0xC7AF,0xC7B1,0xC7B2,0xC7B3,0xC7B5,0xC7B6,0xC7B7,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A0[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xC7B8,0xC7B9,0xC7BA,0xC7BB,0xC7BE,0xC7C2,0xC7C3,/* 0x40-0x47 */ - 0xC7C4,0xC7C5,0xC7C6,0xC7C7,0xC7CA,0xC7CB,0xC7CD,0xC7CF,/* 0x48-0x4F */ - 0xC7D1,0xC7D2,0xC7D3,0xC7D4,0xC7D5,0xC7D6,0xC7D7,0xC7D9,/* 0x50-0x57 */ - 0xC7DA,0xC7DB,0xC7DC,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xC7DE,0xC7DF,0xC7E0,0xC7E1,0xC7E2,0xC7E3,0xC7E5,/* 0x60-0x67 */ - 0xC7E6,0xC7E7,0xC7E9,0xC7EA,0xC7EB,0xC7ED,0xC7EE,0xC7EF,/* 0x68-0x6F */ - 0xC7F0,0xC7F1,0xC7F2,0xC7F3,0xC7F4,0xC7F5,0xC7F6,0xC7F7,/* 0x70-0x77 */ - 0xC7F8,0xC7F9,0xC7FA,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xC7FB,0xC7FC,0xC7FD,0xC7FE,0xC7FF,0xC802,0xC803,/* 0x80-0x87 */ - 0xC805,0xC806,0xC807,0xC809,0xC80B,0xC80C,0xC80D,0xC80E,/* 0x88-0x8F */ - 0xC80F,0xC812,0xC814,0xC817,0xC818,0xC819,0xC81A,0xC81B,/* 0x90-0x97 */ - 0xC81E,0xC81F,0xC821,0xC822,0xC823,0xC825,0xC826,0xC827,/* 0x98-0x9F */ - 0xC828,0xC829,0xC82A,0xC82B,0xC82E,0xC830,0xC832,0xC833,/* 0xA0-0xA7 */ - 0xC834,0xC835,0xC836,0xC837,0xC839,0xC83A,0xC83B,0xC83D,/* 0xA8-0xAF */ - 0xC83E,0xC83F,0xC841,0xC842,0xC843,0xC844,0xC845,0xC846,/* 0xB0-0xB7 */ - 0xC847,0xC84A,0xC84B,0xC84E,0xC84F,0xC850,0xC851,0xC852,/* 0xB8-0xBF */ - 0xC853,0xC855,0xC856,0xC857,0xC858,0xC859,0xC85A,0xC85B,/* 0xC0-0xC7 */ - 0xC85C,0xC85D,0xC85E,0xC85F,0xC860,0xC861,0xC862,0xC863,/* 0xC8-0xCF */ - 0xC864,0xC865,0xC866,0xC867,0xC868,0xC869,0xC86A,0xC86B,/* 0xD0-0xD7 */ - 0xC86C,0xC86D,0xC86E,0xC86F,0xC872,0xC873,0xC875,0xC876,/* 0xD8-0xDF */ - 0xC877,0xC879,0xC87B,0xC87C,0xC87D,0xC87E,0xC87F,0xC882,/* 0xE0-0xE7 */ - 0xC884,0xC888,0xC889,0xC88A,0xC88E,0xC88F,0xC890,0xC891,/* 0xE8-0xEF */ - 0xC892,0xC893,0xC895,0xC896,0xC897,0xC898,0xC899,0xC89A,/* 0xF0-0xF7 */ - 0xC89B,0xC89C,0xC89E,0xC8A0,0xC8A2,0xC8A3,0xC8A4,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xC8A5,0xC8A6,0xC8A7,0xC8A9,0xC8AA,0xC8AB,0xC8AC,/* 0x40-0x47 */ - 0xC8AD,0xC8AE,0xC8AF,0xC8B0,0xC8B1,0xC8B2,0xC8B3,0xC8B4,/* 0x48-0x4F */ - 0xC8B5,0xC8B6,0xC8B7,0xC8B8,0xC8B9,0xC8BA,0xC8BB,0xC8BE,/* 0x50-0x57 */ - 0xC8BF,0xC8C0,0xC8C1,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xC8C2,0xC8C3,0xC8C5,0xC8C6,0xC8C7,0xC8C9,0xC8CA,/* 0x60-0x67 */ - 0xC8CB,0xC8CD,0xC8CE,0xC8CF,0xC8D0,0xC8D1,0xC8D2,0xC8D3,/* 0x68-0x6F */ - 0xC8D6,0xC8D8,0xC8DA,0xC8DB,0xC8DC,0xC8DD,0xC8DE,0xC8DF,/* 0x70-0x77 */ - 0xC8E2,0xC8E3,0xC8E5,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xC8E6,0xC8E7,0xC8E8,0xC8E9,0xC8EA,0xC8EB,0xC8EC,/* 0x80-0x87 */ - 0xC8ED,0xC8EE,0xC8EF,0xC8F0,0xC8F1,0xC8F2,0xC8F3,0xC8F4,/* 0x88-0x8F */ - 0xC8F6,0xC8F7,0xC8F8,0xC8F9,0xC8FA,0xC8FB,0xC8FE,0xC8FF,/* 0x90-0x97 */ - 0xC901,0xC902,0xC903,0xC907,0xC908,0xC909,0xC90A,0xC90B,/* 0x98-0x9F */ - 0xC90E,0x3000,0x3001,0x3002,0x00B7,0x2025,0x2026,0x00A8,/* 0xA0-0xA7 */ - 0x3003,0x00AD,0x2015,0x2225,0xFF3C,0x223C,0x2018,0x2019,/* 0xA8-0xAF */ - 0x201C,0x201D,0x3014,0x3015,0x3008,0x3009,0x300A,0x300B,/* 0xB0-0xB7 */ - 0x300C,0x300D,0x300E,0x300F,0x3010,0x3011,0x00B1,0x00D7,/* 0xB8-0xBF */ - 0x00F7,0x2260,0x2264,0x2265,0x221E,0x2234,0x00B0,0x2032,/* 0xC0-0xC7 */ - 0x2033,0x2103,0x212B,0xFFE0,0xFFE1,0xFFE5,0x2642,0x2640,/* 0xC8-0xCF */ - 0x2220,0x22A5,0x2312,0x2202,0x2207,0x2261,0x2252,0x00A7,/* 0xD0-0xD7 */ - 0x203B,0x2606,0x2605,0x25CB,0x25CF,0x25CE,0x25C7,0x25C6,/* 0xD8-0xDF */ - 0x25A1,0x25A0,0x25B3,0x25B2,0x25BD,0x25BC,0x2192,0x2190,/* 0xE0-0xE7 */ - 0x2191,0x2193,0x2194,0x3013,0x226A,0x226B,0x221A,0x223D,/* 0xE8-0xEF */ - 0x221D,0x2235,0x222B,0x222C,0x2208,0x220B,0x2286,0x2287,/* 0xF0-0xF7 */ - 0x2282,0x2283,0x222A,0x2229,0x2227,0x2228,0xFFE2,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xC910,0xC912,0xC913,0xC914,0xC915,0xC916,0xC917,/* 0x40-0x47 */ - 0xC919,0xC91A,0xC91B,0xC91C,0xC91D,0xC91E,0xC91F,0xC920,/* 0x48-0x4F */ - 0xC921,0xC922,0xC923,0xC924,0xC925,0xC926,0xC927,0xC928,/* 0x50-0x57 */ - 0xC929,0xC92A,0xC92B,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xC92D,0xC92E,0xC92F,0xC930,0xC931,0xC932,0xC933,/* 0x60-0x67 */ - 0xC935,0xC936,0xC937,0xC938,0xC939,0xC93A,0xC93B,0xC93C,/* 0x68-0x6F */ - 0xC93D,0xC93E,0xC93F,0xC940,0xC941,0xC942,0xC943,0xC944,/* 0x70-0x77 */ - 0xC945,0xC946,0xC947,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xC948,0xC949,0xC94A,0xC94B,0xC94C,0xC94D,0xC94E,/* 0x80-0x87 */ - 0xC94F,0xC952,0xC953,0xC955,0xC956,0xC957,0xC959,0xC95A,/* 0x88-0x8F */ - 0xC95B,0xC95C,0xC95D,0xC95E,0xC95F,0xC962,0xC964,0xC965,/* 0x90-0x97 */ - 0xC966,0xC967,0xC968,0xC969,0xC96A,0xC96B,0xC96D,0xC96E,/* 0x98-0x9F */ - 0xC96F,0x21D2,0x21D4,0x2200,0x2203,0x00B4,0xFF5E,0x02C7,/* 0xA0-0xA7 */ - 0x02D8,0x02DD,0x02DA,0x02D9,0x00B8,0x02DB,0x00A1,0x00BF,/* 0xA8-0xAF */ - 0x02D0,0x222E,0x2211,0x220F,0x00A4,0x2109,0x2030,0x25C1,/* 0xB0-0xB7 */ - 0x25C0,0x25B7,0x25B6,0x2664,0x2660,0x2661,0x2665,0x2667,/* 0xB8-0xBF */ - 0x2663,0x2299,0x25C8,0x25A3,0x25D0,0x25D1,0x2592,0x25A4,/* 0xC0-0xC7 */ - 0x25A5,0x25A8,0x25A7,0x25A6,0x25A9,0x2668,0x260F,0x260E,/* 0xC8-0xCF */ - 0x261C,0x261E,0x00B6,0x2020,0x2021,0x2195,0x2197,0x2199,/* 0xD0-0xD7 */ - 0x2196,0x2198,0x266D,0x2669,0x266A,0x266C,0x327F,0x321C,/* 0xD8-0xDF */ - 0x2116,0x33C7,0x2122,0x33C2,0x33D8,0x2121,0x20AC,0x00AE,/* 0xE0-0xE7 */ -}; - -static const wchar_t c2u_A3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xC971,0xC972,0xC973,0xC975,0xC976,0xC977,0xC978,/* 0x40-0x47 */ - 0xC979,0xC97A,0xC97B,0xC97D,0xC97E,0xC97F,0xC980,0xC981,/* 0x48-0x4F */ - 0xC982,0xC983,0xC984,0xC985,0xC986,0xC987,0xC98A,0xC98B,/* 0x50-0x57 */ - 0xC98D,0xC98E,0xC98F,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xC991,0xC992,0xC993,0xC994,0xC995,0xC996,0xC997,/* 0x60-0x67 */ - 0xC99A,0xC99C,0xC99E,0xC99F,0xC9A0,0xC9A1,0xC9A2,0xC9A3,/* 0x68-0x6F */ - 0xC9A4,0xC9A5,0xC9A6,0xC9A7,0xC9A8,0xC9A9,0xC9AA,0xC9AB,/* 0x70-0x77 */ - 0xC9AC,0xC9AD,0xC9AE,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xC9AF,0xC9B0,0xC9B1,0xC9B2,0xC9B3,0xC9B4,0xC9B5,/* 0x80-0x87 */ - 0xC9B6,0xC9B7,0xC9B8,0xC9B9,0xC9BA,0xC9BB,0xC9BC,0xC9BD,/* 0x88-0x8F */ - 0xC9BE,0xC9BF,0xC9C2,0xC9C3,0xC9C5,0xC9C6,0xC9C9,0xC9CB,/* 0x90-0x97 */ - 0xC9CC,0xC9CD,0xC9CE,0xC9CF,0xC9D2,0xC9D4,0xC9D7,0xC9D8,/* 0x98-0x9F */ - 0xC9DB,0xFF01,0xFF02,0xFF03,0xFF04,0xFF05,0xFF06,0xFF07,/* 0xA0-0xA7 */ - 0xFF08,0xFF09,0xFF0A,0xFF0B,0xFF0C,0xFF0D,0xFF0E,0xFF0F,/* 0xA8-0xAF */ - 0xFF10,0xFF11,0xFF12,0xFF13,0xFF14,0xFF15,0xFF16,0xFF17,/* 0xB0-0xB7 */ - 0xFF18,0xFF19,0xFF1A,0xFF1B,0xFF1C,0xFF1D,0xFF1E,0xFF1F,/* 0xB8-0xBF */ - 0xFF20,0xFF21,0xFF22,0xFF23,0xFF24,0xFF25,0xFF26,0xFF27,/* 0xC0-0xC7 */ - 0xFF28,0xFF29,0xFF2A,0xFF2B,0xFF2C,0xFF2D,0xFF2E,0xFF2F,/* 0xC8-0xCF */ - 0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,/* 0xD0-0xD7 */ - 0xFF38,0xFF39,0xFF3A,0xFF3B,0xFFE6,0xFF3D,0xFF3E,0xFF3F,/* 0xD8-0xDF */ - 0xFF40,0xFF41,0xFF42,0xFF43,0xFF44,0xFF45,0xFF46,0xFF47,/* 0xE0-0xE7 */ - 0xFF48,0xFF49,0xFF4A,0xFF4B,0xFF4C,0xFF4D,0xFF4E,0xFF4F,/* 0xE8-0xEF */ - 0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0xFF57,/* 0xF0-0xF7 */ - 0xFF58,0xFF59,0xFF5A,0xFF5B,0xFF5C,0xFF5D,0xFFE3,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xC9DE,0xC9DF,0xC9E1,0xC9E3,0xC9E5,0xC9E6,0xC9E8,/* 0x40-0x47 */ - 0xC9E9,0xC9EA,0xC9EB,0xC9EE,0xC9F2,0xC9F3,0xC9F4,0xC9F5,/* 0x48-0x4F */ - 0xC9F6,0xC9F7,0xC9FA,0xC9FB,0xC9FD,0xC9FE,0xC9FF,0xCA01,/* 0x50-0x57 */ - 0xCA02,0xCA03,0xCA04,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xCA05,0xCA06,0xCA07,0xCA0A,0xCA0E,0xCA0F,0xCA10,/* 0x60-0x67 */ - 0xCA11,0xCA12,0xCA13,0xCA15,0xCA16,0xCA17,0xCA19,0xCA1A,/* 0x68-0x6F */ - 0xCA1B,0xCA1C,0xCA1D,0xCA1E,0xCA1F,0xCA20,0xCA21,0xCA22,/* 0x70-0x77 */ - 0xCA23,0xCA24,0xCA25,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xCA26,0xCA27,0xCA28,0xCA2A,0xCA2B,0xCA2C,0xCA2D,/* 0x80-0x87 */ - 0xCA2E,0xCA2F,0xCA30,0xCA31,0xCA32,0xCA33,0xCA34,0xCA35,/* 0x88-0x8F */ - 0xCA36,0xCA37,0xCA38,0xCA39,0xCA3A,0xCA3B,0xCA3C,0xCA3D,/* 0x90-0x97 */ - 0xCA3E,0xCA3F,0xCA40,0xCA41,0xCA42,0xCA43,0xCA44,0xCA45,/* 0x98-0x9F */ - 0xCA46,0x3131,0x3132,0x3133,0x3134,0x3135,0x3136,0x3137,/* 0xA0-0xA7 */ - 0x3138,0x3139,0x313A,0x313B,0x313C,0x313D,0x313E,0x313F,/* 0xA8-0xAF */ - 0x3140,0x3141,0x3142,0x3143,0x3144,0x3145,0x3146,0x3147,/* 0xB0-0xB7 */ - 0x3148,0x3149,0x314A,0x314B,0x314C,0x314D,0x314E,0x314F,/* 0xB8-0xBF */ - 0x3150,0x3151,0x3152,0x3153,0x3154,0x3155,0x3156,0x3157,/* 0xC0-0xC7 */ - 0x3158,0x3159,0x315A,0x315B,0x315C,0x315D,0x315E,0x315F,/* 0xC8-0xCF */ - 0x3160,0x3161,0x3162,0x3163,0x3164,0x3165,0x3166,0x3167,/* 0xD0-0xD7 */ - 0x3168,0x3169,0x316A,0x316B,0x316C,0x316D,0x316E,0x316F,/* 0xD8-0xDF */ - 0x3170,0x3171,0x3172,0x3173,0x3174,0x3175,0x3176,0x3177,/* 0xE0-0xE7 */ - 0x3178,0x3179,0x317A,0x317B,0x317C,0x317D,0x317E,0x317F,/* 0xE8-0xEF */ - 0x3180,0x3181,0x3182,0x3183,0x3184,0x3185,0x3186,0x3187,/* 0xF0-0xF7 */ - 0x3188,0x3189,0x318A,0x318B,0x318C,0x318D,0x318E,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xCA47,0xCA48,0xCA49,0xCA4A,0xCA4B,0xCA4E,0xCA4F,/* 0x40-0x47 */ - 0xCA51,0xCA52,0xCA53,0xCA55,0xCA56,0xCA57,0xCA58,0xCA59,/* 0x48-0x4F */ - 0xCA5A,0xCA5B,0xCA5E,0xCA62,0xCA63,0xCA64,0xCA65,0xCA66,/* 0x50-0x57 */ - 0xCA67,0xCA69,0xCA6A,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xCA6B,0xCA6C,0xCA6D,0xCA6E,0xCA6F,0xCA70,0xCA71,/* 0x60-0x67 */ - 0xCA72,0xCA73,0xCA74,0xCA75,0xCA76,0xCA77,0xCA78,0xCA79,/* 0x68-0x6F */ - 0xCA7A,0xCA7B,0xCA7C,0xCA7E,0xCA7F,0xCA80,0xCA81,0xCA82,/* 0x70-0x77 */ - 0xCA83,0xCA85,0xCA86,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xCA87,0xCA88,0xCA89,0xCA8A,0xCA8B,0xCA8C,0xCA8D,/* 0x80-0x87 */ - 0xCA8E,0xCA8F,0xCA90,0xCA91,0xCA92,0xCA93,0xCA94,0xCA95,/* 0x88-0x8F */ - 0xCA96,0xCA97,0xCA99,0xCA9A,0xCA9B,0xCA9C,0xCA9D,0xCA9E,/* 0x90-0x97 */ - 0xCA9F,0xCAA0,0xCAA1,0xCAA2,0xCAA3,0xCAA4,0xCAA5,0xCAA6,/* 0x98-0x9F */ - 0xCAA7,0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,/* 0xA0-0xA7 */ - 0x2177,0x2178,0x2179,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA8-0xAF */ - 0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,/* 0xB0-0xB7 */ - 0x2168,0x2169,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xB8-0xBF */ - 0x0000,0x0391,0x0392,0x0393,0x0394,0x0395,0x0396,0x0397,/* 0xC0-0xC7 */ - 0x0398,0x0399,0x039A,0x039B,0x039C,0x039D,0x039E,0x039F,/* 0xC8-0xCF */ - 0x03A0,0x03A1,0x03A3,0x03A4,0x03A5,0x03A6,0x03A7,0x03A8,/* 0xD0-0xD7 */ - 0x03A9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xD8-0xDF */ - 0x0000,0x03B1,0x03B2,0x03B3,0x03B4,0x03B5,0x03B6,0x03B7,/* 0xE0-0xE7 */ - 0x03B8,0x03B9,0x03BA,0x03BB,0x03BC,0x03BD,0x03BE,0x03BF,/* 0xE8-0xEF */ - 0x03C0,0x03C1,0x03C3,0x03C4,0x03C5,0x03C6,0x03C7,0x03C8,/* 0xF0-0xF7 */ - 0x03C9,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xCAA8,0xCAA9,0xCAAA,0xCAAB,0xCAAC,0xCAAD,0xCAAE,/* 0x40-0x47 */ - 0xCAAF,0xCAB0,0xCAB1,0xCAB2,0xCAB3,0xCAB4,0xCAB5,0xCAB6,/* 0x48-0x4F */ - 0xCAB7,0xCAB8,0xCAB9,0xCABA,0xCABB,0xCABE,0xCABF,0xCAC1,/* 0x50-0x57 */ - 0xCAC2,0xCAC3,0xCAC5,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xCAC6,0xCAC7,0xCAC8,0xCAC9,0xCACA,0xCACB,0xCACE,/* 0x60-0x67 */ - 0xCAD0,0xCAD2,0xCAD4,0xCAD5,0xCAD6,0xCAD7,0xCADA,0xCADB,/* 0x68-0x6F */ - 0xCADC,0xCADD,0xCADE,0xCADF,0xCAE1,0xCAE2,0xCAE3,0xCAE4,/* 0x70-0x77 */ - 0xCAE5,0xCAE6,0xCAE7,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xCAE8,0xCAE9,0xCAEA,0xCAEB,0xCAED,0xCAEE,0xCAEF,/* 0x80-0x87 */ - 0xCAF0,0xCAF1,0xCAF2,0xCAF3,0xCAF5,0xCAF6,0xCAF7,0xCAF8,/* 0x88-0x8F */ - 0xCAF9,0xCAFA,0xCAFB,0xCAFC,0xCAFD,0xCAFE,0xCAFF,0xCB00,/* 0x90-0x97 */ - 0xCB01,0xCB02,0xCB03,0xCB04,0xCB05,0xCB06,0xCB07,0xCB09,/* 0x98-0x9F */ - 0xCB0A,0x2500,0x2502,0x250C,0x2510,0x2518,0x2514,0x251C,/* 0xA0-0xA7 */ - 0x252C,0x2524,0x2534,0x253C,0x2501,0x2503,0x250F,0x2513,/* 0xA8-0xAF */ - 0x251B,0x2517,0x2523,0x2533,0x252B,0x253B,0x254B,0x2520,/* 0xB0-0xB7 */ - 0x252F,0x2528,0x2537,0x253F,0x251D,0x2530,0x2525,0x2538,/* 0xB8-0xBF */ - 0x2542,0x2512,0x2511,0x251A,0x2519,0x2516,0x2515,0x250E,/* 0xC0-0xC7 */ - 0x250D,0x251E,0x251F,0x2521,0x2522,0x2526,0x2527,0x2529,/* 0xC8-0xCF */ - 0x252A,0x252D,0x252E,0x2531,0x2532,0x2535,0x2536,0x2539,/* 0xD0-0xD7 */ - 0x253A,0x253D,0x253E,0x2540,0x2541,0x2543,0x2544,0x2545,/* 0xD8-0xDF */ - 0x2546,0x2547,0x2548,0x2549,0x254A,0x0000,0x0000,0x0000,/* 0xE0-0xE7 */ -}; - -static const wchar_t c2u_A7[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xCB0B,0xCB0C,0xCB0D,0xCB0E,0xCB0F,0xCB11,0xCB12,/* 0x40-0x47 */ - 0xCB13,0xCB15,0xCB16,0xCB17,0xCB19,0xCB1A,0xCB1B,0xCB1C,/* 0x48-0x4F */ - 0xCB1D,0xCB1E,0xCB1F,0xCB22,0xCB23,0xCB24,0xCB25,0xCB26,/* 0x50-0x57 */ - 0xCB27,0xCB28,0xCB29,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xCB2A,0xCB2B,0xCB2C,0xCB2D,0xCB2E,0xCB2F,0xCB30,/* 0x60-0x67 */ - 0xCB31,0xCB32,0xCB33,0xCB34,0xCB35,0xCB36,0xCB37,0xCB38,/* 0x68-0x6F */ - 0xCB39,0xCB3A,0xCB3B,0xCB3C,0xCB3D,0xCB3E,0xCB3F,0xCB40,/* 0x70-0x77 */ - 0xCB42,0xCB43,0xCB44,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xCB45,0xCB46,0xCB47,0xCB4A,0xCB4B,0xCB4D,0xCB4E,/* 0x80-0x87 */ - 0xCB4F,0xCB51,0xCB52,0xCB53,0xCB54,0xCB55,0xCB56,0xCB57,/* 0x88-0x8F */ - 0xCB5A,0xCB5B,0xCB5C,0xCB5E,0xCB5F,0xCB60,0xCB61,0xCB62,/* 0x90-0x97 */ - 0xCB63,0xCB65,0xCB66,0xCB67,0xCB68,0xCB69,0xCB6A,0xCB6B,/* 0x98-0x9F */ - 0xCB6C,0x3395,0x3396,0x3397,0x2113,0x3398,0x33C4,0x33A3,/* 0xA0-0xA7 */ - 0x33A4,0x33A5,0x33A6,0x3399,0x339A,0x339B,0x339C,0x339D,/* 0xA8-0xAF */ - 0x339E,0x339F,0x33A0,0x33A1,0x33A2,0x33CA,0x338D,0x338E,/* 0xB0-0xB7 */ - 0x338F,0x33CF,0x3388,0x3389,0x33C8,0x33A7,0x33A8,0x33B0,/* 0xB8-0xBF */ - 0x33B1,0x33B2,0x33B3,0x33B4,0x33B5,0x33B6,0x33B7,0x33B8,/* 0xC0-0xC7 */ - 0x33B9,0x3380,0x3381,0x3382,0x3383,0x3384,0x33BA,0x33BB,/* 0xC8-0xCF */ - 0x33BC,0x33BD,0x33BE,0x33BF,0x3390,0x3391,0x3392,0x3393,/* 0xD0-0xD7 */ - 0x3394,0x2126,0x33C0,0x33C1,0x338A,0x338B,0x338C,0x33D6,/* 0xD8-0xDF */ - 0x33C5,0x33AD,0x33AE,0x33AF,0x33DB,0x33A9,0x33AA,0x33AB,/* 0xE0-0xE7 */ - 0x33AC,0x33DD,0x33D0,0x33D3,0x33C3,0x33C9,0x33DC,0x33C6,/* 0xE8-0xEF */ -}; - -static const wchar_t c2u_A8[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xCB6D,0xCB6E,0xCB6F,0xCB70,0xCB71,0xCB72,0xCB73,/* 0x40-0x47 */ - 0xCB74,0xCB75,0xCB76,0xCB77,0xCB7A,0xCB7B,0xCB7C,0xCB7D,/* 0x48-0x4F */ - 0xCB7E,0xCB7F,0xCB80,0xCB81,0xCB82,0xCB83,0xCB84,0xCB85,/* 0x50-0x57 */ - 0xCB86,0xCB87,0xCB88,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xCB89,0xCB8A,0xCB8B,0xCB8C,0xCB8D,0xCB8E,0xCB8F,/* 0x60-0x67 */ - 0xCB90,0xCB91,0xCB92,0xCB93,0xCB94,0xCB95,0xCB96,0xCB97,/* 0x68-0x6F */ - 0xCB98,0xCB99,0xCB9A,0xCB9B,0xCB9D,0xCB9E,0xCB9F,0xCBA0,/* 0x70-0x77 */ - 0xCBA1,0xCBA2,0xCBA3,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xCBA4,0xCBA5,0xCBA6,0xCBA7,0xCBA8,0xCBA9,0xCBAA,/* 0x80-0x87 */ - 0xCBAB,0xCBAC,0xCBAD,0xCBAE,0xCBAF,0xCBB0,0xCBB1,0xCBB2,/* 0x88-0x8F */ - 0xCBB3,0xCBB4,0xCBB5,0xCBB6,0xCBB7,0xCBB9,0xCBBA,0xCBBB,/* 0x90-0x97 */ - 0xCBBC,0xCBBD,0xCBBE,0xCBBF,0xCBC0,0xCBC1,0xCBC2,0xCBC3,/* 0x98-0x9F */ - 0xCBC4,0x00C6,0x00D0,0x00AA,0x0126,0x0000,0x0132,0x0000,/* 0xA0-0xA7 */ - 0x013F,0x0141,0x00D8,0x0152,0x00BA,0x00DE,0x0166,0x014A,/* 0xA8-0xAF */ - 0x0000,0x3260,0x3261,0x3262,0x3263,0x3264,0x3265,0x3266,/* 0xB0-0xB7 */ - 0x3267,0x3268,0x3269,0x326A,0x326B,0x326C,0x326D,0x326E,/* 0xB8-0xBF */ - 0x326F,0x3270,0x3271,0x3272,0x3273,0x3274,0x3275,0x3276,/* 0xC0-0xC7 */ - 0x3277,0x3278,0x3279,0x327A,0x327B,0x24D0,0x24D1,0x24D2,/* 0xC8-0xCF */ - 0x24D3,0x24D4,0x24D5,0x24D6,0x24D7,0x24D8,0x24D9,0x24DA,/* 0xD0-0xD7 */ - 0x24DB,0x24DC,0x24DD,0x24DE,0x24DF,0x24E0,0x24E1,0x24E2,/* 0xD8-0xDF */ - 0x24E3,0x24E4,0x24E5,0x24E6,0x24E7,0x24E8,0x24E9,0x2460,/* 0xE0-0xE7 */ - 0x2461,0x2462,0x2463,0x2464,0x2465,0x2466,0x2467,0x2468,/* 0xE8-0xEF */ - 0x2469,0x246A,0x246B,0x246C,0x246D,0x246E,0x00BD,0x2153,/* 0xF0-0xF7 */ - 0x2154,0x00BC,0x00BE,0x215B,0x215C,0x215D,0x215E,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A9[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xCBC5,0xCBC6,0xCBC7,0xCBC8,0xCBC9,0xCBCA,0xCBCB,/* 0x40-0x47 */ - 0xCBCC,0xCBCD,0xCBCE,0xCBCF,0xCBD0,0xCBD1,0xCBD2,0xCBD3,/* 0x48-0x4F */ - 0xCBD5,0xCBD6,0xCBD7,0xCBD8,0xCBD9,0xCBDA,0xCBDB,0xCBDC,/* 0x50-0x57 */ - 0xCBDD,0xCBDE,0xCBDF,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xCBE0,0xCBE1,0xCBE2,0xCBE3,0xCBE5,0xCBE6,0xCBE8,/* 0x60-0x67 */ - 0xCBEA,0xCBEB,0xCBEC,0xCBED,0xCBEE,0xCBEF,0xCBF0,0xCBF1,/* 0x68-0x6F */ - 0xCBF2,0xCBF3,0xCBF4,0xCBF5,0xCBF6,0xCBF7,0xCBF8,0xCBF9,/* 0x70-0x77 */ - 0xCBFA,0xCBFB,0xCBFC,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xCBFD,0xCBFE,0xCBFF,0xCC00,0xCC01,0xCC02,0xCC03,/* 0x80-0x87 */ - 0xCC04,0xCC05,0xCC06,0xCC07,0xCC08,0xCC09,0xCC0A,0xCC0B,/* 0x88-0x8F */ - 0xCC0E,0xCC0F,0xCC11,0xCC12,0xCC13,0xCC15,0xCC16,0xCC17,/* 0x90-0x97 */ - 0xCC18,0xCC19,0xCC1A,0xCC1B,0xCC1E,0xCC1F,0xCC20,0xCC23,/* 0x98-0x9F */ - 0xCC24,0x00E6,0x0111,0x00F0,0x0127,0x0131,0x0133,0x0138,/* 0xA0-0xA7 */ - 0x0140,0x0142,0x00F8,0x0153,0x00DF,0x00FE,0x0167,0x014B,/* 0xA8-0xAF */ - 0x0149,0x3200,0x3201,0x3202,0x3203,0x3204,0x3205,0x3206,/* 0xB0-0xB7 */ - 0x3207,0x3208,0x3209,0x320A,0x320B,0x320C,0x320D,0x320E,/* 0xB8-0xBF */ - 0x320F,0x3210,0x3211,0x3212,0x3213,0x3214,0x3215,0x3216,/* 0xC0-0xC7 */ - 0x3217,0x3218,0x3219,0x321A,0x321B,0x249C,0x249D,0x249E,/* 0xC8-0xCF */ - 0x249F,0x24A0,0x24A1,0x24A2,0x24A3,0x24A4,0x24A5,0x24A6,/* 0xD0-0xD7 */ - 0x24A7,0x24A8,0x24A9,0x24AA,0x24AB,0x24AC,0x24AD,0x24AE,/* 0xD8-0xDF */ - 0x24AF,0x24B0,0x24B1,0x24B2,0x24B3,0x24B4,0x24B5,0x2474,/* 0xE0-0xE7 */ - 0x2475,0x2476,0x2477,0x2478,0x2479,0x247A,0x247B,0x247C,/* 0xE8-0xEF */ - 0x247D,0x247E,0x247F,0x2480,0x2481,0x2482,0x00B9,0x00B2,/* 0xF0-0xF7 */ - 0x00B3,0x2074,0x207F,0x2081,0x2082,0x2083,0x2084,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_AA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xCC25,0xCC26,0xCC2A,0xCC2B,0xCC2D,0xCC2F,0xCC31,/* 0x40-0x47 */ - 0xCC32,0xCC33,0xCC34,0xCC35,0xCC36,0xCC37,0xCC3A,0xCC3F,/* 0x48-0x4F */ - 0xCC40,0xCC41,0xCC42,0xCC43,0xCC46,0xCC47,0xCC49,0xCC4A,/* 0x50-0x57 */ - 0xCC4B,0xCC4D,0xCC4E,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xCC4F,0xCC50,0xCC51,0xCC52,0xCC53,0xCC56,0xCC5A,/* 0x60-0x67 */ - 0xCC5B,0xCC5C,0xCC5D,0xCC5E,0xCC5F,0xCC61,0xCC62,0xCC63,/* 0x68-0x6F */ - 0xCC65,0xCC67,0xCC69,0xCC6A,0xCC6B,0xCC6C,0xCC6D,0xCC6E,/* 0x70-0x77 */ - 0xCC6F,0xCC71,0xCC72,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xCC73,0xCC74,0xCC76,0xCC77,0xCC78,0xCC79,0xCC7A,/* 0x80-0x87 */ - 0xCC7B,0xCC7C,0xCC7D,0xCC7E,0xCC7F,0xCC80,0xCC81,0xCC82,/* 0x88-0x8F */ - 0xCC83,0xCC84,0xCC85,0xCC86,0xCC87,0xCC88,0xCC89,0xCC8A,/* 0x90-0x97 */ - 0xCC8B,0xCC8C,0xCC8D,0xCC8E,0xCC8F,0xCC90,0xCC91,0xCC92,/* 0x98-0x9F */ - 0xCC93,0x3041,0x3042,0x3043,0x3044,0x3045,0x3046,0x3047,/* 0xA0-0xA7 */ - 0x3048,0x3049,0x304A,0x304B,0x304C,0x304D,0x304E,0x304F,/* 0xA8-0xAF */ - 0x3050,0x3051,0x3052,0x3053,0x3054,0x3055,0x3056,0x3057,/* 0xB0-0xB7 */ - 0x3058,0x3059,0x305A,0x305B,0x305C,0x305D,0x305E,0x305F,/* 0xB8-0xBF */ - 0x3060,0x3061,0x3062,0x3063,0x3064,0x3065,0x3066,0x3067,/* 0xC0-0xC7 */ - 0x3068,0x3069,0x306A,0x306B,0x306C,0x306D,0x306E,0x306F,/* 0xC8-0xCF */ - 0x3070,0x3071,0x3072,0x3073,0x3074,0x3075,0x3076,0x3077,/* 0xD0-0xD7 */ - 0x3078,0x3079,0x307A,0x307B,0x307C,0x307D,0x307E,0x307F,/* 0xD8-0xDF */ - 0x3080,0x3081,0x3082,0x3083,0x3084,0x3085,0x3086,0x3087,/* 0xE0-0xE7 */ - 0x3088,0x3089,0x308A,0x308B,0x308C,0x308D,0x308E,0x308F,/* 0xE8-0xEF */ - 0x3090,0x3091,0x3092,0x3093,0x0000,0x0000,0x0000,0x0000,/* 0xF0-0xF7 */ -}; - -static const wchar_t c2u_AB[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xCC94,0xCC95,0xCC96,0xCC97,0xCC9A,0xCC9B,0xCC9D,/* 0x40-0x47 */ - 0xCC9E,0xCC9F,0xCCA1,0xCCA2,0xCCA3,0xCCA4,0xCCA5,0xCCA6,/* 0x48-0x4F */ - 0xCCA7,0xCCAA,0xCCAE,0xCCAF,0xCCB0,0xCCB1,0xCCB2,0xCCB3,/* 0x50-0x57 */ - 0xCCB6,0xCCB7,0xCCB9,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xCCBA,0xCCBB,0xCCBD,0xCCBE,0xCCBF,0xCCC0,0xCCC1,/* 0x60-0x67 */ - 0xCCC2,0xCCC3,0xCCC6,0xCCC8,0xCCCA,0xCCCB,0xCCCC,0xCCCD,/* 0x68-0x6F */ - 0xCCCE,0xCCCF,0xCCD1,0xCCD2,0xCCD3,0xCCD5,0xCCD6,0xCCD7,/* 0x70-0x77 */ - 0xCCD8,0xCCD9,0xCCDA,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xCCDB,0xCCDC,0xCCDD,0xCCDE,0xCCDF,0xCCE0,0xCCE1,/* 0x80-0x87 */ - 0xCCE2,0xCCE3,0xCCE5,0xCCE6,0xCCE7,0xCCE8,0xCCE9,0xCCEA,/* 0x88-0x8F */ - 0xCCEB,0xCCED,0xCCEE,0xCCEF,0xCCF1,0xCCF2,0xCCF3,0xCCF4,/* 0x90-0x97 */ - 0xCCF5,0xCCF6,0xCCF7,0xCCF8,0xCCF9,0xCCFA,0xCCFB,0xCCFC,/* 0x98-0x9F */ - 0xCCFD,0x30A1,0x30A2,0x30A3,0x30A4,0x30A5,0x30A6,0x30A7,/* 0xA0-0xA7 */ - 0x30A8,0x30A9,0x30AA,0x30AB,0x30AC,0x30AD,0x30AE,0x30AF,/* 0xA8-0xAF */ - 0x30B0,0x30B1,0x30B2,0x30B3,0x30B4,0x30B5,0x30B6,0x30B7,/* 0xB0-0xB7 */ - 0x30B8,0x30B9,0x30BA,0x30BB,0x30BC,0x30BD,0x30BE,0x30BF,/* 0xB8-0xBF */ - 0x30C0,0x30C1,0x30C2,0x30C3,0x30C4,0x30C5,0x30C6,0x30C7,/* 0xC0-0xC7 */ - 0x30C8,0x30C9,0x30CA,0x30CB,0x30CC,0x30CD,0x30CE,0x30CF,/* 0xC8-0xCF */ - 0x30D0,0x30D1,0x30D2,0x30D3,0x30D4,0x30D5,0x30D6,0x30D7,/* 0xD0-0xD7 */ - 0x30D8,0x30D9,0x30DA,0x30DB,0x30DC,0x30DD,0x30DE,0x30DF,/* 0xD8-0xDF */ - 0x30E0,0x30E1,0x30E2,0x30E3,0x30E4,0x30E5,0x30E6,0x30E7,/* 0xE0-0xE7 */ - 0x30E8,0x30E9,0x30EA,0x30EB,0x30EC,0x30ED,0x30EE,0x30EF,/* 0xE8-0xEF */ - 0x30F0,0x30F1,0x30F2,0x30F3,0x30F4,0x30F5,0x30F6,0x0000,/* 0xF0-0xF7 */ -}; - -static const wchar_t c2u_AC[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xCCFE,0xCCFF,0xCD00,0xCD02,0xCD03,0xCD04,0xCD05,/* 0x40-0x47 */ - 0xCD06,0xCD07,0xCD0A,0xCD0B,0xCD0D,0xCD0E,0xCD0F,0xCD11,/* 0x48-0x4F */ - 0xCD12,0xCD13,0xCD14,0xCD15,0xCD16,0xCD17,0xCD1A,0xCD1C,/* 0x50-0x57 */ - 0xCD1E,0xCD1F,0xCD20,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xCD21,0xCD22,0xCD23,0xCD25,0xCD26,0xCD27,0xCD29,/* 0x60-0x67 */ - 0xCD2A,0xCD2B,0xCD2D,0xCD2E,0xCD2F,0xCD30,0xCD31,0xCD32,/* 0x68-0x6F */ - 0xCD33,0xCD34,0xCD35,0xCD36,0xCD37,0xCD38,0xCD3A,0xCD3B,/* 0x70-0x77 */ - 0xCD3C,0xCD3D,0xCD3E,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xCD3F,0xCD40,0xCD41,0xCD42,0xCD43,0xCD44,0xCD45,/* 0x80-0x87 */ - 0xCD46,0xCD47,0xCD48,0xCD49,0xCD4A,0xCD4B,0xCD4C,0xCD4D,/* 0x88-0x8F */ - 0xCD4E,0xCD4F,0xCD50,0xCD51,0xCD52,0xCD53,0xCD54,0xCD55,/* 0x90-0x97 */ - 0xCD56,0xCD57,0xCD58,0xCD59,0xCD5A,0xCD5B,0xCD5D,0xCD5E,/* 0x98-0x9F */ - 0xCD5F,0x0410,0x0411,0x0412,0x0413,0x0414,0x0415,0x0401,/* 0xA0-0xA7 */ - 0x0416,0x0417,0x0418,0x0419,0x041A,0x041B,0x041C,0x041D,/* 0xA8-0xAF */ - 0x041E,0x041F,0x0420,0x0421,0x0422,0x0423,0x0424,0x0425,/* 0xB0-0xB7 */ - 0x0426,0x0427,0x0428,0x0429,0x042A,0x042B,0x042C,0x042D,/* 0xB8-0xBF */ - 0x042E,0x042F,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xC0-0xC7 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xC8-0xCF */ - 0x0000,0x0430,0x0431,0x0432,0x0433,0x0434,0x0435,0x0451,/* 0xD0-0xD7 */ - 0x0436,0x0437,0x0438,0x0439,0x043A,0x043B,0x043C,0x043D,/* 0xD8-0xDF */ - 0x043E,0x043F,0x0440,0x0441,0x0442,0x0443,0x0444,0x0445,/* 0xE0-0xE7 */ - 0x0446,0x0447,0x0448,0x0449,0x044A,0x044B,0x044C,0x044D,/* 0xE8-0xEF */ - 0x044E,0x044F,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xF0-0xF7 */ -}; - -static const wchar_t c2u_AD[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xCD61,0xCD62,0xCD63,0xCD65,0xCD66,0xCD67,0xCD68,/* 0x40-0x47 */ - 0xCD69,0xCD6A,0xCD6B,0xCD6E,0xCD70,0xCD72,0xCD73,0xCD74,/* 0x48-0x4F */ - 0xCD75,0xCD76,0xCD77,0xCD79,0xCD7A,0xCD7B,0xCD7C,0xCD7D,/* 0x50-0x57 */ - 0xCD7E,0xCD7F,0xCD80,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xCD81,0xCD82,0xCD83,0xCD84,0xCD85,0xCD86,0xCD87,/* 0x60-0x67 */ - 0xCD89,0xCD8A,0xCD8B,0xCD8C,0xCD8D,0xCD8E,0xCD8F,0xCD90,/* 0x68-0x6F */ - 0xCD91,0xCD92,0xCD93,0xCD96,0xCD97,0xCD99,0xCD9A,0xCD9B,/* 0x70-0x77 */ - 0xCD9D,0xCD9E,0xCD9F,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xCDA0,0xCDA1,0xCDA2,0xCDA3,0xCDA6,0xCDA8,0xCDAA,/* 0x80-0x87 */ - 0xCDAB,0xCDAC,0xCDAD,0xCDAE,0xCDAF,0xCDB1,0xCDB2,0xCDB3,/* 0x88-0x8F */ - 0xCDB4,0xCDB5,0xCDB6,0xCDB7,0xCDB8,0xCDB9,0xCDBA,0xCDBB,/* 0x90-0x97 */ - 0xCDBC,0xCDBD,0xCDBE,0xCDBF,0xCDC0,0xCDC1,0xCDC2,0xCDC3,/* 0x98-0x9F */ - 0xCDC5,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ -}; - -static const wchar_t c2u_AE[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xCDC6,0xCDC7,0xCDC8,0xCDC9,0xCDCA,0xCDCB,0xCDCD,/* 0x40-0x47 */ - 0xCDCE,0xCDCF,0xCDD1,0xCDD2,0xCDD3,0xCDD4,0xCDD5,0xCDD6,/* 0x48-0x4F */ - 0xCDD7,0xCDD8,0xCDD9,0xCDDA,0xCDDB,0xCDDC,0xCDDD,0xCDDE,/* 0x50-0x57 */ - 0xCDDF,0xCDE0,0xCDE1,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xCDE2,0xCDE3,0xCDE4,0xCDE5,0xCDE6,0xCDE7,0xCDE9,/* 0x60-0x67 */ - 0xCDEA,0xCDEB,0xCDED,0xCDEE,0xCDEF,0xCDF1,0xCDF2,0xCDF3,/* 0x68-0x6F */ - 0xCDF4,0xCDF5,0xCDF6,0xCDF7,0xCDFA,0xCDFC,0xCDFE,0xCDFF,/* 0x70-0x77 */ - 0xCE00,0xCE01,0xCE02,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xCE03,0xCE05,0xCE06,0xCE07,0xCE09,0xCE0A,0xCE0B,/* 0x80-0x87 */ - 0xCE0D,0xCE0E,0xCE0F,0xCE10,0xCE11,0xCE12,0xCE13,0xCE15,/* 0x88-0x8F */ - 0xCE16,0xCE17,0xCE18,0xCE1A,0xCE1B,0xCE1C,0xCE1D,0xCE1E,/* 0x90-0x97 */ - 0xCE1F,0xCE22,0xCE23,0xCE25,0xCE26,0xCE27,0xCE29,0xCE2A,/* 0x98-0x9F */ - 0xCE2B,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ -}; - -static const wchar_t c2u_AF[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xCE2C,0xCE2D,0xCE2E,0xCE2F,0xCE32,0xCE34,0xCE36,/* 0x40-0x47 */ - 0xCE37,0xCE38,0xCE39,0xCE3A,0xCE3B,0xCE3C,0xCE3D,0xCE3E,/* 0x48-0x4F */ - 0xCE3F,0xCE40,0xCE41,0xCE42,0xCE43,0xCE44,0xCE45,0xCE46,/* 0x50-0x57 */ - 0xCE47,0xCE48,0xCE49,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xCE4A,0xCE4B,0xCE4C,0xCE4D,0xCE4E,0xCE4F,0xCE50,/* 0x60-0x67 */ - 0xCE51,0xCE52,0xCE53,0xCE54,0xCE55,0xCE56,0xCE57,0xCE5A,/* 0x68-0x6F */ - 0xCE5B,0xCE5D,0xCE5E,0xCE62,0xCE63,0xCE64,0xCE65,0xCE66,/* 0x70-0x77 */ - 0xCE67,0xCE6A,0xCE6C,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xCE6E,0xCE6F,0xCE70,0xCE71,0xCE72,0xCE73,0xCE76,/* 0x80-0x87 */ - 0xCE77,0xCE79,0xCE7A,0xCE7B,0xCE7D,0xCE7E,0xCE7F,0xCE80,/* 0x88-0x8F */ - 0xCE81,0xCE82,0xCE83,0xCE86,0xCE88,0xCE8A,0xCE8B,0xCE8C,/* 0x90-0x97 */ - 0xCE8D,0xCE8E,0xCE8F,0xCE92,0xCE93,0xCE95,0xCE96,0xCE97,/* 0x98-0x9F */ - 0xCE99,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xA0-0xA7 */ -}; - -static const wchar_t c2u_B0[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xCE9A,0xCE9B,0xCE9C,0xCE9D,0xCE9E,0xCE9F,0xCEA2,/* 0x40-0x47 */ - 0xCEA6,0xCEA7,0xCEA8,0xCEA9,0xCEAA,0xCEAB,0xCEAE,0xCEAF,/* 0x48-0x4F */ - 0xCEB0,0xCEB1,0xCEB2,0xCEB3,0xCEB4,0xCEB5,0xCEB6,0xCEB7,/* 0x50-0x57 */ - 0xCEB8,0xCEB9,0xCEBA,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xCEBB,0xCEBC,0xCEBD,0xCEBE,0xCEBF,0xCEC0,0xCEC2,/* 0x60-0x67 */ - 0xCEC3,0xCEC4,0xCEC5,0xCEC6,0xCEC7,0xCEC8,0xCEC9,0xCECA,/* 0x68-0x6F */ - 0xCECB,0xCECC,0xCECD,0xCECE,0xCECF,0xCED0,0xCED1,0xCED2,/* 0x70-0x77 */ - 0xCED3,0xCED4,0xCED5,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xCED6,0xCED7,0xCED8,0xCED9,0xCEDA,0xCEDB,0xCEDC,/* 0x80-0x87 */ - 0xCEDD,0xCEDE,0xCEDF,0xCEE0,0xCEE1,0xCEE2,0xCEE3,0xCEE6,/* 0x88-0x8F */ - 0xCEE7,0xCEE9,0xCEEA,0xCEED,0xCEEE,0xCEEF,0xCEF0,0xCEF1,/* 0x90-0x97 */ - 0xCEF2,0xCEF3,0xCEF6,0xCEFA,0xCEFB,0xCEFC,0xCEFD,0xCEFE,/* 0x98-0x9F */ - 0xCEFF,0xAC00,0xAC01,0xAC04,0xAC07,0xAC08,0xAC09,0xAC0A,/* 0xA0-0xA7 */ - 0xAC10,0xAC11,0xAC12,0xAC13,0xAC14,0xAC15,0xAC16,0xAC17,/* 0xA8-0xAF */ - 0xAC19,0xAC1A,0xAC1B,0xAC1C,0xAC1D,0xAC20,0xAC24,0xAC2C,/* 0xB0-0xB7 */ - 0xAC2D,0xAC2F,0xAC30,0xAC31,0xAC38,0xAC39,0xAC3C,0xAC40,/* 0xB8-0xBF */ - 0xAC4B,0xAC4D,0xAC54,0xAC58,0xAC5C,0xAC70,0xAC71,0xAC74,/* 0xC0-0xC7 */ - 0xAC77,0xAC78,0xAC7A,0xAC80,0xAC81,0xAC83,0xAC84,0xAC85,/* 0xC8-0xCF */ - 0xAC86,0xAC89,0xAC8A,0xAC8B,0xAC8C,0xAC90,0xAC94,0xAC9C,/* 0xD0-0xD7 */ - 0xAC9D,0xAC9F,0xACA0,0xACA1,0xACA8,0xACA9,0xACAA,0xACAC,/* 0xD8-0xDF */ - 0xACAF,0xACB0,0xACB8,0xACB9,0xACBB,0xACBC,0xACBD,0xACC1,/* 0xE0-0xE7 */ - 0xACC4,0xACC8,0xACCC,0xACD5,0xACD7,0xACE0,0xACE1,0xACE4,/* 0xE8-0xEF */ - 0xACE7,0xACE8,0xACEA,0xACEC,0xACEF,0xACF0,0xACF1,0xACF3,/* 0xF0-0xF7 */ - 0xACF5,0xACF6,0xACFC,0xACFD,0xAD00,0xAD04,0xAD06,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xCF02,0xCF03,0xCF05,0xCF06,0xCF07,0xCF09,0xCF0A,/* 0x40-0x47 */ - 0xCF0B,0xCF0C,0xCF0D,0xCF0E,0xCF0F,0xCF12,0xCF14,0xCF16,/* 0x48-0x4F */ - 0xCF17,0xCF18,0xCF19,0xCF1A,0xCF1B,0xCF1D,0xCF1E,0xCF1F,/* 0x50-0x57 */ - 0xCF21,0xCF22,0xCF23,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xCF25,0xCF26,0xCF27,0xCF28,0xCF29,0xCF2A,0xCF2B,/* 0x60-0x67 */ - 0xCF2E,0xCF32,0xCF33,0xCF34,0xCF35,0xCF36,0xCF37,0xCF39,/* 0x68-0x6F */ - 0xCF3A,0xCF3B,0xCF3C,0xCF3D,0xCF3E,0xCF3F,0xCF40,0xCF41,/* 0x70-0x77 */ - 0xCF42,0xCF43,0xCF44,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xCF45,0xCF46,0xCF47,0xCF48,0xCF49,0xCF4A,0xCF4B,/* 0x80-0x87 */ - 0xCF4C,0xCF4D,0xCF4E,0xCF4F,0xCF50,0xCF51,0xCF52,0xCF53,/* 0x88-0x8F */ - 0xCF56,0xCF57,0xCF59,0xCF5A,0xCF5B,0xCF5D,0xCF5E,0xCF5F,/* 0x90-0x97 */ - 0xCF60,0xCF61,0xCF62,0xCF63,0xCF66,0xCF68,0xCF6A,0xCF6B,/* 0x98-0x9F */ - 0xCF6C,0xAD0C,0xAD0D,0xAD0F,0xAD11,0xAD18,0xAD1C,0xAD20,/* 0xA0-0xA7 */ - 0xAD29,0xAD2C,0xAD2D,0xAD34,0xAD35,0xAD38,0xAD3C,0xAD44,/* 0xA8-0xAF */ - 0xAD45,0xAD47,0xAD49,0xAD50,0xAD54,0xAD58,0xAD61,0xAD63,/* 0xB0-0xB7 */ - 0xAD6C,0xAD6D,0xAD70,0xAD73,0xAD74,0xAD75,0xAD76,0xAD7B,/* 0xB8-0xBF */ - 0xAD7C,0xAD7D,0xAD7F,0xAD81,0xAD82,0xAD88,0xAD89,0xAD8C,/* 0xC0-0xC7 */ - 0xAD90,0xAD9C,0xAD9D,0xADA4,0xADB7,0xADC0,0xADC1,0xADC4,/* 0xC8-0xCF */ - 0xADC8,0xADD0,0xADD1,0xADD3,0xADDC,0xADE0,0xADE4,0xADF8,/* 0xD0-0xD7 */ - 0xADF9,0xADFC,0xADFF,0xAE00,0xAE01,0xAE08,0xAE09,0xAE0B,/* 0xD8-0xDF */ - 0xAE0D,0xAE14,0xAE30,0xAE31,0xAE34,0xAE37,0xAE38,0xAE3A,/* 0xE0-0xE7 */ - 0xAE40,0xAE41,0xAE43,0xAE45,0xAE46,0xAE4A,0xAE4C,0xAE4D,/* 0xE8-0xEF */ - 0xAE4E,0xAE50,0xAE54,0xAE56,0xAE5C,0xAE5D,0xAE5F,0xAE60,/* 0xF0-0xF7 */ - 0xAE61,0xAE65,0xAE68,0xAE69,0xAE6C,0xAE70,0xAE78,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xCF6D,0xCF6E,0xCF6F,0xCF72,0xCF73,0xCF75,0xCF76,/* 0x40-0x47 */ - 0xCF77,0xCF79,0xCF7A,0xCF7B,0xCF7C,0xCF7D,0xCF7E,0xCF7F,/* 0x48-0x4F */ - 0xCF81,0xCF82,0xCF83,0xCF84,0xCF86,0xCF87,0xCF88,0xCF89,/* 0x50-0x57 */ - 0xCF8A,0xCF8B,0xCF8D,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xCF8E,0xCF8F,0xCF90,0xCF91,0xCF92,0xCF93,0xCF94,/* 0x60-0x67 */ - 0xCF95,0xCF96,0xCF97,0xCF98,0xCF99,0xCF9A,0xCF9B,0xCF9C,/* 0x68-0x6F */ - 0xCF9D,0xCF9E,0xCF9F,0xCFA0,0xCFA2,0xCFA3,0xCFA4,0xCFA5,/* 0x70-0x77 */ - 0xCFA6,0xCFA7,0xCFA9,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xCFAA,0xCFAB,0xCFAC,0xCFAD,0xCFAE,0xCFAF,0xCFB1,/* 0x80-0x87 */ - 0xCFB2,0xCFB3,0xCFB4,0xCFB5,0xCFB6,0xCFB7,0xCFB8,0xCFB9,/* 0x88-0x8F */ - 0xCFBA,0xCFBB,0xCFBC,0xCFBD,0xCFBE,0xCFBF,0xCFC0,0xCFC1,/* 0x90-0x97 */ - 0xCFC2,0xCFC3,0xCFC5,0xCFC6,0xCFC7,0xCFC8,0xCFC9,0xCFCA,/* 0x98-0x9F */ - 0xCFCB,0xAE79,0xAE7B,0xAE7C,0xAE7D,0xAE84,0xAE85,0xAE8C,/* 0xA0-0xA7 */ - 0xAEBC,0xAEBD,0xAEBE,0xAEC0,0xAEC4,0xAECC,0xAECD,0xAECF,/* 0xA8-0xAF */ - 0xAED0,0xAED1,0xAED8,0xAED9,0xAEDC,0xAEE8,0xAEEB,0xAEED,/* 0xB0-0xB7 */ - 0xAEF4,0xAEF8,0xAEFC,0xAF07,0xAF08,0xAF0D,0xAF10,0xAF2C,/* 0xB8-0xBF */ - 0xAF2D,0xAF30,0xAF32,0xAF34,0xAF3C,0xAF3D,0xAF3F,0xAF41,/* 0xC0-0xC7 */ - 0xAF42,0xAF43,0xAF48,0xAF49,0xAF50,0xAF5C,0xAF5D,0xAF64,/* 0xC8-0xCF */ - 0xAF65,0xAF79,0xAF80,0xAF84,0xAF88,0xAF90,0xAF91,0xAF95,/* 0xD0-0xD7 */ - 0xAF9C,0xAFB8,0xAFB9,0xAFBC,0xAFC0,0xAFC7,0xAFC8,0xAFC9,/* 0xD8-0xDF */ - 0xAFCB,0xAFCD,0xAFCE,0xAFD4,0xAFDC,0xAFE8,0xAFE9,0xAFF0,/* 0xE0-0xE7 */ - 0xAFF1,0xAFF4,0xAFF8,0xB000,0xB001,0xB004,0xB00C,0xB010,/* 0xE8-0xEF */ - 0xB014,0xB01C,0xB01D,0xB028,0xB044,0xB045,0xB048,0xB04A,/* 0xF0-0xF7 */ - 0xB04C,0xB04E,0xB053,0xB054,0xB055,0xB057,0xB059,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xCFCC,0xCFCD,0xCFCE,0xCFCF,0xCFD0,0xCFD1,0xCFD2,/* 0x40-0x47 */ - 0xCFD3,0xCFD4,0xCFD5,0xCFD6,0xCFD7,0xCFD8,0xCFD9,0xCFDA,/* 0x48-0x4F */ - 0xCFDB,0xCFDC,0xCFDD,0xCFDE,0xCFDF,0xCFE2,0xCFE3,0xCFE5,/* 0x50-0x57 */ - 0xCFE6,0xCFE7,0xCFE9,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xCFEA,0xCFEB,0xCFEC,0xCFED,0xCFEE,0xCFEF,0xCFF2,/* 0x60-0x67 */ - 0xCFF4,0xCFF6,0xCFF7,0xCFF8,0xCFF9,0xCFFA,0xCFFB,0xCFFD,/* 0x68-0x6F */ - 0xCFFE,0xCFFF,0xD001,0xD002,0xD003,0xD005,0xD006,0xD007,/* 0x70-0x77 */ - 0xD008,0xD009,0xD00A,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD00B,0xD00C,0xD00D,0xD00E,0xD00F,0xD010,0xD012,/* 0x80-0x87 */ - 0xD013,0xD014,0xD015,0xD016,0xD017,0xD019,0xD01A,0xD01B,/* 0x88-0x8F */ - 0xD01C,0xD01D,0xD01E,0xD01F,0xD020,0xD021,0xD022,0xD023,/* 0x90-0x97 */ - 0xD024,0xD025,0xD026,0xD027,0xD028,0xD029,0xD02A,0xD02B,/* 0x98-0x9F */ - 0xD02C,0xB05D,0xB07C,0xB07D,0xB080,0xB084,0xB08C,0xB08D,/* 0xA0-0xA7 */ - 0xB08F,0xB091,0xB098,0xB099,0xB09A,0xB09C,0xB09F,0xB0A0,/* 0xA8-0xAF */ - 0xB0A1,0xB0A2,0xB0A8,0xB0A9,0xB0AB,0xB0AC,0xB0AD,0xB0AE,/* 0xB0-0xB7 */ - 0xB0AF,0xB0B1,0xB0B3,0xB0B4,0xB0B5,0xB0B8,0xB0BC,0xB0C4,/* 0xB8-0xBF */ - 0xB0C5,0xB0C7,0xB0C8,0xB0C9,0xB0D0,0xB0D1,0xB0D4,0xB0D8,/* 0xC0-0xC7 */ - 0xB0E0,0xB0E5,0xB108,0xB109,0xB10B,0xB10C,0xB110,0xB112,/* 0xC8-0xCF */ - 0xB113,0xB118,0xB119,0xB11B,0xB11C,0xB11D,0xB123,0xB124,/* 0xD0-0xD7 */ - 0xB125,0xB128,0xB12C,0xB134,0xB135,0xB137,0xB138,0xB139,/* 0xD8-0xDF */ - 0xB140,0xB141,0xB144,0xB148,0xB150,0xB151,0xB154,0xB155,/* 0xE0-0xE7 */ - 0xB158,0xB15C,0xB160,0xB178,0xB179,0xB17C,0xB180,0xB182,/* 0xE8-0xEF */ - 0xB188,0xB189,0xB18B,0xB18D,0xB192,0xB193,0xB194,0xB198,/* 0xF0-0xF7 */ - 0xB19C,0xB1A8,0xB1CC,0xB1D0,0xB1D4,0xB1DC,0xB1DD,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD02E,0xD02F,0xD030,0xD031,0xD032,0xD033,0xD036,/* 0x40-0x47 */ - 0xD037,0xD039,0xD03A,0xD03B,0xD03D,0xD03E,0xD03F,0xD040,/* 0x48-0x4F */ - 0xD041,0xD042,0xD043,0xD046,0xD048,0xD04A,0xD04B,0xD04C,/* 0x50-0x57 */ - 0xD04D,0xD04E,0xD04F,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xD051,0xD052,0xD053,0xD055,0xD056,0xD057,0xD059,/* 0x60-0x67 */ - 0xD05A,0xD05B,0xD05C,0xD05D,0xD05E,0xD05F,0xD061,0xD062,/* 0x68-0x6F */ - 0xD063,0xD064,0xD065,0xD066,0xD067,0xD068,0xD069,0xD06A,/* 0x70-0x77 */ - 0xD06B,0xD06E,0xD06F,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD071,0xD072,0xD073,0xD075,0xD076,0xD077,0xD078,/* 0x80-0x87 */ - 0xD079,0xD07A,0xD07B,0xD07E,0xD07F,0xD080,0xD082,0xD083,/* 0x88-0x8F */ - 0xD084,0xD085,0xD086,0xD087,0xD088,0xD089,0xD08A,0xD08B,/* 0x90-0x97 */ - 0xD08C,0xD08D,0xD08E,0xD08F,0xD090,0xD091,0xD092,0xD093,/* 0x98-0x9F */ - 0xD094,0xB1DF,0xB1E8,0xB1E9,0xB1EC,0xB1F0,0xB1F9,0xB1FB,/* 0xA0-0xA7 */ - 0xB1FD,0xB204,0xB205,0xB208,0xB20B,0xB20C,0xB214,0xB215,/* 0xA8-0xAF */ - 0xB217,0xB219,0xB220,0xB234,0xB23C,0xB258,0xB25C,0xB260,/* 0xB0-0xB7 */ - 0xB268,0xB269,0xB274,0xB275,0xB27C,0xB284,0xB285,0xB289,/* 0xB8-0xBF */ - 0xB290,0xB291,0xB294,0xB298,0xB299,0xB29A,0xB2A0,0xB2A1,/* 0xC0-0xC7 */ - 0xB2A3,0xB2A5,0xB2A6,0xB2AA,0xB2AC,0xB2B0,0xB2B4,0xB2C8,/* 0xC8-0xCF */ - 0xB2C9,0xB2CC,0xB2D0,0xB2D2,0xB2D8,0xB2D9,0xB2DB,0xB2DD,/* 0xD0-0xD7 */ - 0xB2E2,0xB2E4,0xB2E5,0xB2E6,0xB2E8,0xB2EB,0xB2EC,0xB2ED,/* 0xD8-0xDF */ - 0xB2EE,0xB2EF,0xB2F3,0xB2F4,0xB2F5,0xB2F7,0xB2F8,0xB2F9,/* 0xE0-0xE7 */ - 0xB2FA,0xB2FB,0xB2FF,0xB300,0xB301,0xB304,0xB308,0xB310,/* 0xE8-0xEF */ - 0xB311,0xB313,0xB314,0xB315,0xB31C,0xB354,0xB355,0xB356,/* 0xF0-0xF7 */ - 0xB358,0xB35B,0xB35C,0xB35E,0xB35F,0xB364,0xB365,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD095,0xD096,0xD097,0xD098,0xD099,0xD09A,0xD09B,/* 0x40-0x47 */ - 0xD09C,0xD09D,0xD09E,0xD09F,0xD0A0,0xD0A1,0xD0A2,0xD0A3,/* 0x48-0x4F */ - 0xD0A6,0xD0A7,0xD0A9,0xD0AA,0xD0AB,0xD0AD,0xD0AE,0xD0AF,/* 0x50-0x57 */ - 0xD0B0,0xD0B1,0xD0B2,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xD0B3,0xD0B6,0xD0B8,0xD0BA,0xD0BB,0xD0BC,0xD0BD,/* 0x60-0x67 */ - 0xD0BE,0xD0BF,0xD0C2,0xD0C3,0xD0C5,0xD0C6,0xD0C7,0xD0CA,/* 0x68-0x6F */ - 0xD0CB,0xD0CC,0xD0CD,0xD0CE,0xD0CF,0xD0D2,0xD0D6,0xD0D7,/* 0x70-0x77 */ - 0xD0D8,0xD0D9,0xD0DA,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD0DB,0xD0DE,0xD0DF,0xD0E1,0xD0E2,0xD0E3,0xD0E5,/* 0x80-0x87 */ - 0xD0E6,0xD0E7,0xD0E8,0xD0E9,0xD0EA,0xD0EB,0xD0EE,0xD0F2,/* 0x88-0x8F */ - 0xD0F3,0xD0F4,0xD0F5,0xD0F6,0xD0F7,0xD0F9,0xD0FA,0xD0FB,/* 0x90-0x97 */ - 0xD0FC,0xD0FD,0xD0FE,0xD0FF,0xD100,0xD101,0xD102,0xD103,/* 0x98-0x9F */ - 0xD104,0xB367,0xB369,0xB36B,0xB36E,0xB370,0xB371,0xB374,/* 0xA0-0xA7 */ - 0xB378,0xB380,0xB381,0xB383,0xB384,0xB385,0xB38C,0xB390,/* 0xA8-0xAF */ - 0xB394,0xB3A0,0xB3A1,0xB3A8,0xB3AC,0xB3C4,0xB3C5,0xB3C8,/* 0xB0-0xB7 */ - 0xB3CB,0xB3CC,0xB3CE,0xB3D0,0xB3D4,0xB3D5,0xB3D7,0xB3D9,/* 0xB8-0xBF */ - 0xB3DB,0xB3DD,0xB3E0,0xB3E4,0xB3E8,0xB3FC,0xB410,0xB418,/* 0xC0-0xC7 */ - 0xB41C,0xB420,0xB428,0xB429,0xB42B,0xB434,0xB450,0xB451,/* 0xC8-0xCF */ - 0xB454,0xB458,0xB460,0xB461,0xB463,0xB465,0xB46C,0xB480,/* 0xD0-0xD7 */ - 0xB488,0xB49D,0xB4A4,0xB4A8,0xB4AC,0xB4B5,0xB4B7,0xB4B9,/* 0xD8-0xDF */ - 0xB4C0,0xB4C4,0xB4C8,0xB4D0,0xB4D5,0xB4DC,0xB4DD,0xB4E0,/* 0xE0-0xE7 */ - 0xB4E3,0xB4E4,0xB4E6,0xB4EC,0xB4ED,0xB4EF,0xB4F1,0xB4F8,/* 0xE8-0xEF */ - 0xB514,0xB515,0xB518,0xB51B,0xB51C,0xB524,0xB525,0xB527,/* 0xF0-0xF7 */ - 0xB528,0xB529,0xB52A,0xB530,0xB531,0xB534,0xB538,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD105,0xD106,0xD107,0xD108,0xD109,0xD10A,0xD10B,/* 0x40-0x47 */ - 0xD10C,0xD10E,0xD10F,0xD110,0xD111,0xD112,0xD113,0xD114,/* 0x48-0x4F */ - 0xD115,0xD116,0xD117,0xD118,0xD119,0xD11A,0xD11B,0xD11C,/* 0x50-0x57 */ - 0xD11D,0xD11E,0xD11F,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xD120,0xD121,0xD122,0xD123,0xD124,0xD125,0xD126,/* 0x60-0x67 */ - 0xD127,0xD128,0xD129,0xD12A,0xD12B,0xD12C,0xD12D,0xD12E,/* 0x68-0x6F */ - 0xD12F,0xD132,0xD133,0xD135,0xD136,0xD137,0xD139,0xD13B,/* 0x70-0x77 */ - 0xD13C,0xD13D,0xD13E,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD13F,0xD142,0xD146,0xD147,0xD148,0xD149,0xD14A,/* 0x80-0x87 */ - 0xD14B,0xD14E,0xD14F,0xD151,0xD152,0xD153,0xD155,0xD156,/* 0x88-0x8F */ - 0xD157,0xD158,0xD159,0xD15A,0xD15B,0xD15E,0xD160,0xD162,/* 0x90-0x97 */ - 0xD163,0xD164,0xD165,0xD166,0xD167,0xD169,0xD16A,0xD16B,/* 0x98-0x9F */ - 0xD16D,0xB540,0xB541,0xB543,0xB544,0xB545,0xB54B,0xB54C,/* 0xA0-0xA7 */ - 0xB54D,0xB550,0xB554,0xB55C,0xB55D,0xB55F,0xB560,0xB561,/* 0xA8-0xAF */ - 0xB5A0,0xB5A1,0xB5A4,0xB5A8,0xB5AA,0xB5AB,0xB5B0,0xB5B1,/* 0xB0-0xB7 */ - 0xB5B3,0xB5B4,0xB5B5,0xB5BB,0xB5BC,0xB5BD,0xB5C0,0xB5C4,/* 0xB8-0xBF */ - 0xB5CC,0xB5CD,0xB5CF,0xB5D0,0xB5D1,0xB5D8,0xB5EC,0xB610,/* 0xC0-0xC7 */ - 0xB611,0xB614,0xB618,0xB625,0xB62C,0xB634,0xB648,0xB664,/* 0xC8-0xCF */ - 0xB668,0xB69C,0xB69D,0xB6A0,0xB6A4,0xB6AB,0xB6AC,0xB6B1,/* 0xD0-0xD7 */ - 0xB6D4,0xB6F0,0xB6F4,0xB6F8,0xB700,0xB701,0xB705,0xB728,/* 0xD8-0xDF */ - 0xB729,0xB72C,0xB72F,0xB730,0xB738,0xB739,0xB73B,0xB744,/* 0xE0-0xE7 */ - 0xB748,0xB74C,0xB754,0xB755,0xB760,0xB764,0xB768,0xB770,/* 0xE8-0xEF */ - 0xB771,0xB773,0xB775,0xB77C,0xB77D,0xB780,0xB784,0xB78C,/* 0xF0-0xF7 */ - 0xB78D,0xB78F,0xB790,0xB791,0xB792,0xB796,0xB797,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B7[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD16E,0xD16F,0xD170,0xD171,0xD172,0xD173,0xD174,/* 0x40-0x47 */ - 0xD175,0xD176,0xD177,0xD178,0xD179,0xD17A,0xD17B,0xD17D,/* 0x48-0x4F */ - 0xD17E,0xD17F,0xD180,0xD181,0xD182,0xD183,0xD185,0xD186,/* 0x50-0x57 */ - 0xD187,0xD189,0xD18A,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xD18B,0xD18C,0xD18D,0xD18E,0xD18F,0xD190,0xD191,/* 0x60-0x67 */ - 0xD192,0xD193,0xD194,0xD195,0xD196,0xD197,0xD198,0xD199,/* 0x68-0x6F */ - 0xD19A,0xD19B,0xD19C,0xD19D,0xD19E,0xD19F,0xD1A2,0xD1A3,/* 0x70-0x77 */ - 0xD1A5,0xD1A6,0xD1A7,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD1A9,0xD1AA,0xD1AB,0xD1AC,0xD1AD,0xD1AE,0xD1AF,/* 0x80-0x87 */ - 0xD1B2,0xD1B4,0xD1B6,0xD1B7,0xD1B8,0xD1B9,0xD1BB,0xD1BD,/* 0x88-0x8F */ - 0xD1BE,0xD1BF,0xD1C1,0xD1C2,0xD1C3,0xD1C4,0xD1C5,0xD1C6,/* 0x90-0x97 */ - 0xD1C7,0xD1C8,0xD1C9,0xD1CA,0xD1CB,0xD1CC,0xD1CD,0xD1CE,/* 0x98-0x9F */ - 0xD1CF,0xB798,0xB799,0xB79C,0xB7A0,0xB7A8,0xB7A9,0xB7AB,/* 0xA0-0xA7 */ - 0xB7AC,0xB7AD,0xB7B4,0xB7B5,0xB7B8,0xB7C7,0xB7C9,0xB7EC,/* 0xA8-0xAF */ - 0xB7ED,0xB7F0,0xB7F4,0xB7FC,0xB7FD,0xB7FF,0xB800,0xB801,/* 0xB0-0xB7 */ - 0xB807,0xB808,0xB809,0xB80C,0xB810,0xB818,0xB819,0xB81B,/* 0xB8-0xBF */ - 0xB81D,0xB824,0xB825,0xB828,0xB82C,0xB834,0xB835,0xB837,/* 0xC0-0xC7 */ - 0xB838,0xB839,0xB840,0xB844,0xB851,0xB853,0xB85C,0xB85D,/* 0xC8-0xCF */ - 0xB860,0xB864,0xB86C,0xB86D,0xB86F,0xB871,0xB878,0xB87C,/* 0xD0-0xD7 */ - 0xB88D,0xB8A8,0xB8B0,0xB8B4,0xB8B8,0xB8C0,0xB8C1,0xB8C3,/* 0xD8-0xDF */ - 0xB8C5,0xB8CC,0xB8D0,0xB8D4,0xB8DD,0xB8DF,0xB8E1,0xB8E8,/* 0xE0-0xE7 */ - 0xB8E9,0xB8EC,0xB8F0,0xB8F8,0xB8F9,0xB8FB,0xB8FD,0xB904,/* 0xE8-0xEF */ - 0xB918,0xB920,0xB93C,0xB93D,0xB940,0xB944,0xB94C,0xB94F,/* 0xF0-0xF7 */ - 0xB951,0xB958,0xB959,0xB95C,0xB960,0xB968,0xB969,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B8[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD1D0,0xD1D1,0xD1D2,0xD1D3,0xD1D4,0xD1D5,0xD1D6,/* 0x40-0x47 */ - 0xD1D7,0xD1D9,0xD1DA,0xD1DB,0xD1DC,0xD1DD,0xD1DE,0xD1DF,/* 0x48-0x4F */ - 0xD1E0,0xD1E1,0xD1E2,0xD1E3,0xD1E4,0xD1E5,0xD1E6,0xD1E7,/* 0x50-0x57 */ - 0xD1E8,0xD1E9,0xD1EA,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xD1EB,0xD1EC,0xD1ED,0xD1EE,0xD1EF,0xD1F0,0xD1F1,/* 0x60-0x67 */ - 0xD1F2,0xD1F3,0xD1F5,0xD1F6,0xD1F7,0xD1F9,0xD1FA,0xD1FB,/* 0x68-0x6F */ - 0xD1FC,0xD1FD,0xD1FE,0xD1FF,0xD200,0xD201,0xD202,0xD203,/* 0x70-0x77 */ - 0xD204,0xD205,0xD206,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD208,0xD20A,0xD20B,0xD20C,0xD20D,0xD20E,0xD20F,/* 0x80-0x87 */ - 0xD211,0xD212,0xD213,0xD214,0xD215,0xD216,0xD217,0xD218,/* 0x88-0x8F */ - 0xD219,0xD21A,0xD21B,0xD21C,0xD21D,0xD21E,0xD21F,0xD220,/* 0x90-0x97 */ - 0xD221,0xD222,0xD223,0xD224,0xD225,0xD226,0xD227,0xD228,/* 0x98-0x9F */ - 0xD229,0xB96B,0xB96D,0xB974,0xB975,0xB978,0xB97C,0xB984,/* 0xA0-0xA7 */ - 0xB985,0xB987,0xB989,0xB98A,0xB98D,0xB98E,0xB9AC,0xB9AD,/* 0xA8-0xAF */ - 0xB9B0,0xB9B4,0xB9BC,0xB9BD,0xB9BF,0xB9C1,0xB9C8,0xB9C9,/* 0xB0-0xB7 */ - 0xB9CC,0xB9CE,0xB9CF,0xB9D0,0xB9D1,0xB9D2,0xB9D8,0xB9D9,/* 0xB8-0xBF */ - 0xB9DB,0xB9DD,0xB9DE,0xB9E1,0xB9E3,0xB9E4,0xB9E5,0xB9E8,/* 0xC0-0xC7 */ - 0xB9EC,0xB9F4,0xB9F5,0xB9F7,0xB9F8,0xB9F9,0xB9FA,0xBA00,/* 0xC8-0xCF */ - 0xBA01,0xBA08,0xBA15,0xBA38,0xBA39,0xBA3C,0xBA40,0xBA42,/* 0xD0-0xD7 */ - 0xBA48,0xBA49,0xBA4B,0xBA4D,0xBA4E,0xBA53,0xBA54,0xBA55,/* 0xD8-0xDF */ - 0xBA58,0xBA5C,0xBA64,0xBA65,0xBA67,0xBA68,0xBA69,0xBA70,/* 0xE0-0xE7 */ - 0xBA71,0xBA74,0xBA78,0xBA83,0xBA84,0xBA85,0xBA87,0xBA8C,/* 0xE8-0xEF */ - 0xBAA8,0xBAA9,0xBAAB,0xBAAC,0xBAB0,0xBAB2,0xBAB8,0xBAB9,/* 0xF0-0xF7 */ - 0xBABB,0xBABD,0xBAC4,0xBAC8,0xBAD8,0xBAD9,0xBAFC,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B9[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD22A,0xD22B,0xD22E,0xD22F,0xD231,0xD232,0xD233,/* 0x40-0x47 */ - 0xD235,0xD236,0xD237,0xD238,0xD239,0xD23A,0xD23B,0xD23E,/* 0x48-0x4F */ - 0xD240,0xD242,0xD243,0xD244,0xD245,0xD246,0xD247,0xD249,/* 0x50-0x57 */ - 0xD24A,0xD24B,0xD24C,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xD24D,0xD24E,0xD24F,0xD250,0xD251,0xD252,0xD253,/* 0x60-0x67 */ - 0xD254,0xD255,0xD256,0xD257,0xD258,0xD259,0xD25A,0xD25B,/* 0x68-0x6F */ - 0xD25D,0xD25E,0xD25F,0xD260,0xD261,0xD262,0xD263,0xD265,/* 0x70-0x77 */ - 0xD266,0xD267,0xD268,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD269,0xD26A,0xD26B,0xD26C,0xD26D,0xD26E,0xD26F,/* 0x80-0x87 */ - 0xD270,0xD271,0xD272,0xD273,0xD274,0xD275,0xD276,0xD277,/* 0x88-0x8F */ - 0xD278,0xD279,0xD27A,0xD27B,0xD27C,0xD27D,0xD27E,0xD27F,/* 0x90-0x97 */ - 0xD282,0xD283,0xD285,0xD286,0xD287,0xD289,0xD28A,0xD28B,/* 0x98-0x9F */ - 0xD28C,0xBB00,0xBB04,0xBB0D,0xBB0F,0xBB11,0xBB18,0xBB1C,/* 0xA0-0xA7 */ - 0xBB20,0xBB29,0xBB2B,0xBB34,0xBB35,0xBB36,0xBB38,0xBB3B,/* 0xA8-0xAF */ - 0xBB3C,0xBB3D,0xBB3E,0xBB44,0xBB45,0xBB47,0xBB49,0xBB4D,/* 0xB0-0xB7 */ - 0xBB4F,0xBB50,0xBB54,0xBB58,0xBB61,0xBB63,0xBB6C,0xBB88,/* 0xB8-0xBF */ - 0xBB8C,0xBB90,0xBBA4,0xBBA8,0xBBAC,0xBBB4,0xBBB7,0xBBC0,/* 0xC0-0xC7 */ - 0xBBC4,0xBBC8,0xBBD0,0xBBD3,0xBBF8,0xBBF9,0xBBFC,0xBBFF,/* 0xC8-0xCF */ - 0xBC00,0xBC02,0xBC08,0xBC09,0xBC0B,0xBC0C,0xBC0D,0xBC0F,/* 0xD0-0xD7 */ - 0xBC11,0xBC14,0xBC15,0xBC16,0xBC17,0xBC18,0xBC1B,0xBC1C,/* 0xD8-0xDF */ - 0xBC1D,0xBC1E,0xBC1F,0xBC24,0xBC25,0xBC27,0xBC29,0xBC2D,/* 0xE0-0xE7 */ - 0xBC30,0xBC31,0xBC34,0xBC38,0xBC40,0xBC41,0xBC43,0xBC44,/* 0xE8-0xEF */ - 0xBC45,0xBC49,0xBC4C,0xBC4D,0xBC50,0xBC5D,0xBC84,0xBC85,/* 0xF0-0xF7 */ - 0xBC88,0xBC8B,0xBC8C,0xBC8E,0xBC94,0xBC95,0xBC97,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_BA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD28D,0xD28E,0xD28F,0xD292,0xD293,0xD294,0xD296,/* 0x40-0x47 */ - 0xD297,0xD298,0xD299,0xD29A,0xD29B,0xD29D,0xD29E,0xD29F,/* 0x48-0x4F */ - 0xD2A1,0xD2A2,0xD2A3,0xD2A5,0xD2A6,0xD2A7,0xD2A8,0xD2A9,/* 0x50-0x57 */ - 0xD2AA,0xD2AB,0xD2AD,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xD2AE,0xD2AF,0xD2B0,0xD2B2,0xD2B3,0xD2B4,0xD2B5,/* 0x60-0x67 */ - 0xD2B6,0xD2B7,0xD2BA,0xD2BB,0xD2BD,0xD2BE,0xD2C1,0xD2C3,/* 0x68-0x6F */ - 0xD2C4,0xD2C5,0xD2C6,0xD2C7,0xD2CA,0xD2CC,0xD2CD,0xD2CE,/* 0x70-0x77 */ - 0xD2CF,0xD2D0,0xD2D1,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD2D2,0xD2D3,0xD2D5,0xD2D6,0xD2D7,0xD2D9,0xD2DA,/* 0x80-0x87 */ - 0xD2DB,0xD2DD,0xD2DE,0xD2DF,0xD2E0,0xD2E1,0xD2E2,0xD2E3,/* 0x88-0x8F */ - 0xD2E6,0xD2E7,0xD2E8,0xD2E9,0xD2EA,0xD2EB,0xD2EC,0xD2ED,/* 0x90-0x97 */ - 0xD2EE,0xD2EF,0xD2F2,0xD2F3,0xD2F5,0xD2F6,0xD2F7,0xD2F9,/* 0x98-0x9F */ - 0xD2FA,0xBC99,0xBC9A,0xBCA0,0xBCA1,0xBCA4,0xBCA7,0xBCA8,/* 0xA0-0xA7 */ - 0xBCB0,0xBCB1,0xBCB3,0xBCB4,0xBCB5,0xBCBC,0xBCBD,0xBCC0,/* 0xA8-0xAF */ - 0xBCC4,0xBCCD,0xBCCF,0xBCD0,0xBCD1,0xBCD5,0xBCD8,0xBCDC,/* 0xB0-0xB7 */ - 0xBCF4,0xBCF5,0xBCF6,0xBCF8,0xBCFC,0xBD04,0xBD05,0xBD07,/* 0xB8-0xBF */ - 0xBD09,0xBD10,0xBD14,0xBD24,0xBD2C,0xBD40,0xBD48,0xBD49,/* 0xC0-0xC7 */ - 0xBD4C,0xBD50,0xBD58,0xBD59,0xBD64,0xBD68,0xBD80,0xBD81,/* 0xC8-0xCF */ - 0xBD84,0xBD87,0xBD88,0xBD89,0xBD8A,0xBD90,0xBD91,0xBD93,/* 0xD0-0xD7 */ - 0xBD95,0xBD99,0xBD9A,0xBD9C,0xBDA4,0xBDB0,0xBDB8,0xBDD4,/* 0xD8-0xDF */ - 0xBDD5,0xBDD8,0xBDDC,0xBDE9,0xBDF0,0xBDF4,0xBDF8,0xBE00,/* 0xE0-0xE7 */ - 0xBE03,0xBE05,0xBE0C,0xBE0D,0xBE10,0xBE14,0xBE1C,0xBE1D,/* 0xE8-0xEF */ - 0xBE1F,0xBE44,0xBE45,0xBE48,0xBE4C,0xBE4E,0xBE54,0xBE55,/* 0xF0-0xF7 */ - 0xBE57,0xBE59,0xBE5A,0xBE5B,0xBE60,0xBE61,0xBE64,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_BB[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD2FB,0xD2FC,0xD2FD,0xD2FE,0xD2FF,0xD302,0xD304,/* 0x40-0x47 */ - 0xD306,0xD307,0xD308,0xD309,0xD30A,0xD30B,0xD30F,0xD311,/* 0x48-0x4F */ - 0xD312,0xD313,0xD315,0xD317,0xD318,0xD319,0xD31A,0xD31B,/* 0x50-0x57 */ - 0xD31E,0xD322,0xD323,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xD324,0xD326,0xD327,0xD32A,0xD32B,0xD32D,0xD32E,/* 0x60-0x67 */ - 0xD32F,0xD331,0xD332,0xD333,0xD334,0xD335,0xD336,0xD337,/* 0x68-0x6F */ - 0xD33A,0xD33E,0xD33F,0xD340,0xD341,0xD342,0xD343,0xD346,/* 0x70-0x77 */ - 0xD347,0xD348,0xD349,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD34A,0xD34B,0xD34C,0xD34D,0xD34E,0xD34F,0xD350,/* 0x80-0x87 */ - 0xD351,0xD352,0xD353,0xD354,0xD355,0xD356,0xD357,0xD358,/* 0x88-0x8F */ - 0xD359,0xD35A,0xD35B,0xD35C,0xD35D,0xD35E,0xD35F,0xD360,/* 0x90-0x97 */ - 0xD361,0xD362,0xD363,0xD364,0xD365,0xD366,0xD367,0xD368,/* 0x98-0x9F */ - 0xD369,0xBE68,0xBE6A,0xBE70,0xBE71,0xBE73,0xBE74,0xBE75,/* 0xA0-0xA7 */ - 0xBE7B,0xBE7C,0xBE7D,0xBE80,0xBE84,0xBE8C,0xBE8D,0xBE8F,/* 0xA8-0xAF */ - 0xBE90,0xBE91,0xBE98,0xBE99,0xBEA8,0xBED0,0xBED1,0xBED4,/* 0xB0-0xB7 */ - 0xBED7,0xBED8,0xBEE0,0xBEE3,0xBEE4,0xBEE5,0xBEEC,0xBF01,/* 0xB8-0xBF */ - 0xBF08,0xBF09,0xBF18,0xBF19,0xBF1B,0xBF1C,0xBF1D,0xBF40,/* 0xC0-0xC7 */ - 0xBF41,0xBF44,0xBF48,0xBF50,0xBF51,0xBF55,0xBF94,0xBFB0,/* 0xC8-0xCF */ - 0xBFC5,0xBFCC,0xBFCD,0xBFD0,0xBFD4,0xBFDC,0xBFDF,0xBFE1,/* 0xD0-0xD7 */ - 0xC03C,0xC051,0xC058,0xC05C,0xC060,0xC068,0xC069,0xC090,/* 0xD8-0xDF */ - 0xC091,0xC094,0xC098,0xC0A0,0xC0A1,0xC0A3,0xC0A5,0xC0AC,/* 0xE0-0xE7 */ - 0xC0AD,0xC0AF,0xC0B0,0xC0B3,0xC0B4,0xC0B5,0xC0B6,0xC0BC,/* 0xE8-0xEF */ - 0xC0BD,0xC0BF,0xC0C0,0xC0C1,0xC0C5,0xC0C8,0xC0C9,0xC0CC,/* 0xF0-0xF7 */ - 0xC0D0,0xC0D8,0xC0D9,0xC0DB,0xC0DC,0xC0DD,0xC0E4,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_BC[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD36A,0xD36B,0xD36C,0xD36D,0xD36E,0xD36F,0xD370,/* 0x40-0x47 */ - 0xD371,0xD372,0xD373,0xD374,0xD375,0xD376,0xD377,0xD378,/* 0x48-0x4F */ - 0xD379,0xD37A,0xD37B,0xD37E,0xD37F,0xD381,0xD382,0xD383,/* 0x50-0x57 */ - 0xD385,0xD386,0xD387,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xD388,0xD389,0xD38A,0xD38B,0xD38E,0xD392,0xD393,/* 0x60-0x67 */ - 0xD394,0xD395,0xD396,0xD397,0xD39A,0xD39B,0xD39D,0xD39E,/* 0x68-0x6F */ - 0xD39F,0xD3A1,0xD3A2,0xD3A3,0xD3A4,0xD3A5,0xD3A6,0xD3A7,/* 0x70-0x77 */ - 0xD3AA,0xD3AC,0xD3AE,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD3AF,0xD3B0,0xD3B1,0xD3B2,0xD3B3,0xD3B5,0xD3B6,/* 0x80-0x87 */ - 0xD3B7,0xD3B9,0xD3BA,0xD3BB,0xD3BD,0xD3BE,0xD3BF,0xD3C0,/* 0x88-0x8F */ - 0xD3C1,0xD3C2,0xD3C3,0xD3C6,0xD3C7,0xD3CA,0xD3CB,0xD3CC,/* 0x90-0x97 */ - 0xD3CD,0xD3CE,0xD3CF,0xD3D1,0xD3D2,0xD3D3,0xD3D4,0xD3D5,/* 0x98-0x9F */ - 0xD3D6,0xC0E5,0xC0E8,0xC0EC,0xC0F4,0xC0F5,0xC0F7,0xC0F9,/* 0xA0-0xA7 */ - 0xC100,0xC104,0xC108,0xC110,0xC115,0xC11C,0xC11D,0xC11E,/* 0xA8-0xAF */ - 0xC11F,0xC120,0xC123,0xC124,0xC126,0xC127,0xC12C,0xC12D,/* 0xB0-0xB7 */ - 0xC12F,0xC130,0xC131,0xC136,0xC138,0xC139,0xC13C,0xC140,/* 0xB8-0xBF */ - 0xC148,0xC149,0xC14B,0xC14C,0xC14D,0xC154,0xC155,0xC158,/* 0xC0-0xC7 */ - 0xC15C,0xC164,0xC165,0xC167,0xC168,0xC169,0xC170,0xC174,/* 0xC8-0xCF */ - 0xC178,0xC185,0xC18C,0xC18D,0xC18E,0xC190,0xC194,0xC196,/* 0xD0-0xD7 */ - 0xC19C,0xC19D,0xC19F,0xC1A1,0xC1A5,0xC1A8,0xC1A9,0xC1AC,/* 0xD8-0xDF */ - 0xC1B0,0xC1BD,0xC1C4,0xC1C8,0xC1CC,0xC1D4,0xC1D7,0xC1D8,/* 0xE0-0xE7 */ - 0xC1E0,0xC1E4,0xC1E8,0xC1F0,0xC1F1,0xC1F3,0xC1FC,0xC1FD,/* 0xE8-0xEF */ - 0xC200,0xC204,0xC20C,0xC20D,0xC20F,0xC211,0xC218,0xC219,/* 0xF0-0xF7 */ - 0xC21C,0xC21F,0xC220,0xC228,0xC229,0xC22B,0xC22D,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_BD[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD3D7,0xD3D9,0xD3DA,0xD3DB,0xD3DC,0xD3DD,0xD3DE,/* 0x40-0x47 */ - 0xD3DF,0xD3E0,0xD3E2,0xD3E4,0xD3E5,0xD3E6,0xD3E7,0xD3E8,/* 0x48-0x4F */ - 0xD3E9,0xD3EA,0xD3EB,0xD3EE,0xD3EF,0xD3F1,0xD3F2,0xD3F3,/* 0x50-0x57 */ - 0xD3F5,0xD3F6,0xD3F7,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xD3F8,0xD3F9,0xD3FA,0xD3FB,0xD3FE,0xD400,0xD402,/* 0x60-0x67 */ - 0xD403,0xD404,0xD405,0xD406,0xD407,0xD409,0xD40A,0xD40B,/* 0x68-0x6F */ - 0xD40C,0xD40D,0xD40E,0xD40F,0xD410,0xD411,0xD412,0xD413,/* 0x70-0x77 */ - 0xD414,0xD415,0xD416,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD417,0xD418,0xD419,0xD41A,0xD41B,0xD41C,0xD41E,/* 0x80-0x87 */ - 0xD41F,0xD420,0xD421,0xD422,0xD423,0xD424,0xD425,0xD426,/* 0x88-0x8F */ - 0xD427,0xD428,0xD429,0xD42A,0xD42B,0xD42C,0xD42D,0xD42E,/* 0x90-0x97 */ - 0xD42F,0xD430,0xD431,0xD432,0xD433,0xD434,0xD435,0xD436,/* 0x98-0x9F */ - 0xD437,0xC22F,0xC231,0xC232,0xC234,0xC248,0xC250,0xC251,/* 0xA0-0xA7 */ - 0xC254,0xC258,0xC260,0xC265,0xC26C,0xC26D,0xC270,0xC274,/* 0xA8-0xAF */ - 0xC27C,0xC27D,0xC27F,0xC281,0xC288,0xC289,0xC290,0xC298,/* 0xB0-0xB7 */ - 0xC29B,0xC29D,0xC2A4,0xC2A5,0xC2A8,0xC2AC,0xC2AD,0xC2B4,/* 0xB8-0xBF */ - 0xC2B5,0xC2B7,0xC2B9,0xC2DC,0xC2DD,0xC2E0,0xC2E3,0xC2E4,/* 0xC0-0xC7 */ - 0xC2EB,0xC2EC,0xC2ED,0xC2EF,0xC2F1,0xC2F6,0xC2F8,0xC2F9,/* 0xC8-0xCF */ - 0xC2FB,0xC2FC,0xC300,0xC308,0xC309,0xC30C,0xC30D,0xC313,/* 0xD0-0xD7 */ - 0xC314,0xC315,0xC318,0xC31C,0xC324,0xC325,0xC328,0xC329,/* 0xD8-0xDF */ - 0xC345,0xC368,0xC369,0xC36C,0xC370,0xC372,0xC378,0xC379,/* 0xE0-0xE7 */ - 0xC37C,0xC37D,0xC384,0xC388,0xC38C,0xC3C0,0xC3D8,0xC3D9,/* 0xE8-0xEF */ - 0xC3DC,0xC3DF,0xC3E0,0xC3E2,0xC3E8,0xC3E9,0xC3ED,0xC3F4,/* 0xF0-0xF7 */ - 0xC3F5,0xC3F8,0xC408,0xC410,0xC424,0xC42C,0xC430,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_BE[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD438,0xD439,0xD43A,0xD43B,0xD43C,0xD43D,0xD43E,/* 0x40-0x47 */ - 0xD43F,0xD441,0xD442,0xD443,0xD445,0xD446,0xD447,0xD448,/* 0x48-0x4F */ - 0xD449,0xD44A,0xD44B,0xD44C,0xD44D,0xD44E,0xD44F,0xD450,/* 0x50-0x57 */ - 0xD451,0xD452,0xD453,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xD454,0xD455,0xD456,0xD457,0xD458,0xD459,0xD45A,/* 0x60-0x67 */ - 0xD45B,0xD45D,0xD45E,0xD45F,0xD461,0xD462,0xD463,0xD465,/* 0x68-0x6F */ - 0xD466,0xD467,0xD468,0xD469,0xD46A,0xD46B,0xD46C,0xD46E,/* 0x70-0x77 */ - 0xD470,0xD471,0xD472,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD473,0xD474,0xD475,0xD476,0xD477,0xD47A,0xD47B,/* 0x80-0x87 */ - 0xD47D,0xD47E,0xD481,0xD483,0xD484,0xD485,0xD486,0xD487,/* 0x88-0x8F */ - 0xD48A,0xD48C,0xD48E,0xD48F,0xD490,0xD491,0xD492,0xD493,/* 0x90-0x97 */ - 0xD495,0xD496,0xD497,0xD498,0xD499,0xD49A,0xD49B,0xD49C,/* 0x98-0x9F */ - 0xD49D,0xC434,0xC43C,0xC43D,0xC448,0xC464,0xC465,0xC468,/* 0xA0-0xA7 */ - 0xC46C,0xC474,0xC475,0xC479,0xC480,0xC494,0xC49C,0xC4B8,/* 0xA8-0xAF */ - 0xC4BC,0xC4E9,0xC4F0,0xC4F1,0xC4F4,0xC4F8,0xC4FA,0xC4FF,/* 0xB0-0xB7 */ - 0xC500,0xC501,0xC50C,0xC510,0xC514,0xC51C,0xC528,0xC529,/* 0xB8-0xBF */ - 0xC52C,0xC530,0xC538,0xC539,0xC53B,0xC53D,0xC544,0xC545,/* 0xC0-0xC7 */ - 0xC548,0xC549,0xC54A,0xC54C,0xC54D,0xC54E,0xC553,0xC554,/* 0xC8-0xCF */ - 0xC555,0xC557,0xC558,0xC559,0xC55D,0xC55E,0xC560,0xC561,/* 0xD0-0xD7 */ - 0xC564,0xC568,0xC570,0xC571,0xC573,0xC574,0xC575,0xC57C,/* 0xD8-0xDF */ - 0xC57D,0xC580,0xC584,0xC587,0xC58C,0xC58D,0xC58F,0xC591,/* 0xE0-0xE7 */ - 0xC595,0xC597,0xC598,0xC59C,0xC5A0,0xC5A9,0xC5B4,0xC5B5,/* 0xE8-0xEF */ - 0xC5B8,0xC5B9,0xC5BB,0xC5BC,0xC5BD,0xC5BE,0xC5C4,0xC5C5,/* 0xF0-0xF7 */ - 0xC5C6,0xC5C7,0xC5C8,0xC5C9,0xC5CA,0xC5CC,0xC5CE,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_BF[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD49E,0xD49F,0xD4A0,0xD4A1,0xD4A2,0xD4A3,0xD4A4,/* 0x40-0x47 */ - 0xD4A5,0xD4A6,0xD4A7,0xD4A8,0xD4AA,0xD4AB,0xD4AC,0xD4AD,/* 0x48-0x4F */ - 0xD4AE,0xD4AF,0xD4B0,0xD4B1,0xD4B2,0xD4B3,0xD4B4,0xD4B5,/* 0x50-0x57 */ - 0xD4B6,0xD4B7,0xD4B8,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xD4B9,0xD4BA,0xD4BB,0xD4BC,0xD4BD,0xD4BE,0xD4BF,/* 0x60-0x67 */ - 0xD4C0,0xD4C1,0xD4C2,0xD4C3,0xD4C4,0xD4C5,0xD4C6,0xD4C7,/* 0x68-0x6F */ - 0xD4C8,0xD4C9,0xD4CA,0xD4CB,0xD4CD,0xD4CE,0xD4CF,0xD4D1,/* 0x70-0x77 */ - 0xD4D2,0xD4D3,0xD4D5,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD4D6,0xD4D7,0xD4D8,0xD4D9,0xD4DA,0xD4DB,0xD4DD,/* 0x80-0x87 */ - 0xD4DE,0xD4E0,0xD4E1,0xD4E2,0xD4E3,0xD4E4,0xD4E5,0xD4E6,/* 0x88-0x8F */ - 0xD4E7,0xD4E9,0xD4EA,0xD4EB,0xD4ED,0xD4EE,0xD4EF,0xD4F1,/* 0x90-0x97 */ - 0xD4F2,0xD4F3,0xD4F4,0xD4F5,0xD4F6,0xD4F7,0xD4F9,0xD4FA,/* 0x98-0x9F */ - 0xD4FC,0xC5D0,0xC5D1,0xC5D4,0xC5D8,0xC5E0,0xC5E1,0xC5E3,/* 0xA0-0xA7 */ - 0xC5E5,0xC5EC,0xC5ED,0xC5EE,0xC5F0,0xC5F4,0xC5F6,0xC5F7,/* 0xA8-0xAF */ - 0xC5FC,0xC5FD,0xC5FE,0xC5FF,0xC600,0xC601,0xC605,0xC606,/* 0xB0-0xB7 */ - 0xC607,0xC608,0xC60C,0xC610,0xC618,0xC619,0xC61B,0xC61C,/* 0xB8-0xBF */ - 0xC624,0xC625,0xC628,0xC62C,0xC62D,0xC62E,0xC630,0xC633,/* 0xC0-0xC7 */ - 0xC634,0xC635,0xC637,0xC639,0xC63B,0xC640,0xC641,0xC644,/* 0xC8-0xCF */ - 0xC648,0xC650,0xC651,0xC653,0xC654,0xC655,0xC65C,0xC65D,/* 0xD0-0xD7 */ - 0xC660,0xC66C,0xC66F,0xC671,0xC678,0xC679,0xC67C,0xC680,/* 0xD8-0xDF */ - 0xC688,0xC689,0xC68B,0xC68D,0xC694,0xC695,0xC698,0xC69C,/* 0xE0-0xE7 */ - 0xC6A4,0xC6A5,0xC6A7,0xC6A9,0xC6B0,0xC6B1,0xC6B4,0xC6B8,/* 0xE8-0xEF */ - 0xC6B9,0xC6BA,0xC6C0,0xC6C1,0xC6C3,0xC6C5,0xC6CC,0xC6CD,/* 0xF0-0xF7 */ - 0xC6D0,0xC6D4,0xC6DC,0xC6DD,0xC6E0,0xC6E1,0xC6E8,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C0[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD4FE,0xD4FF,0xD500,0xD501,0xD502,0xD503,0xD505,/* 0x40-0x47 */ - 0xD506,0xD507,0xD509,0xD50A,0xD50B,0xD50D,0xD50E,0xD50F,/* 0x48-0x4F */ - 0xD510,0xD511,0xD512,0xD513,0xD516,0xD518,0xD519,0xD51A,/* 0x50-0x57 */ - 0xD51B,0xD51C,0xD51D,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xD51E,0xD51F,0xD520,0xD521,0xD522,0xD523,0xD524,/* 0x60-0x67 */ - 0xD525,0xD526,0xD527,0xD528,0xD529,0xD52A,0xD52B,0xD52C,/* 0x68-0x6F */ - 0xD52D,0xD52E,0xD52F,0xD530,0xD531,0xD532,0xD533,0xD534,/* 0x70-0x77 */ - 0xD535,0xD536,0xD537,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD538,0xD539,0xD53A,0xD53B,0xD53E,0xD53F,0xD541,/* 0x80-0x87 */ - 0xD542,0xD543,0xD545,0xD546,0xD547,0xD548,0xD549,0xD54A,/* 0x88-0x8F */ - 0xD54B,0xD54E,0xD550,0xD552,0xD553,0xD554,0xD555,0xD556,/* 0x90-0x97 */ - 0xD557,0xD55A,0xD55B,0xD55D,0xD55E,0xD55F,0xD561,0xD562,/* 0x98-0x9F */ - 0xD563,0xC6E9,0xC6EC,0xC6F0,0xC6F8,0xC6F9,0xC6FD,0xC704,/* 0xA0-0xA7 */ - 0xC705,0xC708,0xC70C,0xC714,0xC715,0xC717,0xC719,0xC720,/* 0xA8-0xAF */ - 0xC721,0xC724,0xC728,0xC730,0xC731,0xC733,0xC735,0xC737,/* 0xB0-0xB7 */ - 0xC73C,0xC73D,0xC740,0xC744,0xC74A,0xC74C,0xC74D,0xC74F,/* 0xB8-0xBF */ - 0xC751,0xC752,0xC753,0xC754,0xC755,0xC756,0xC757,0xC758,/* 0xC0-0xC7 */ - 0xC75C,0xC760,0xC768,0xC76B,0xC774,0xC775,0xC778,0xC77C,/* 0xC8-0xCF */ - 0xC77D,0xC77E,0xC783,0xC784,0xC785,0xC787,0xC788,0xC789,/* 0xD0-0xD7 */ - 0xC78A,0xC78E,0xC790,0xC791,0xC794,0xC796,0xC797,0xC798,/* 0xD8-0xDF */ - 0xC79A,0xC7A0,0xC7A1,0xC7A3,0xC7A4,0xC7A5,0xC7A6,0xC7AC,/* 0xE0-0xE7 */ - 0xC7AD,0xC7B0,0xC7B4,0xC7BC,0xC7BD,0xC7BF,0xC7C0,0xC7C1,/* 0xE8-0xEF */ - 0xC7C8,0xC7C9,0xC7CC,0xC7CE,0xC7D0,0xC7D8,0xC7DD,0xC7E4,/* 0xF0-0xF7 */ - 0xC7E8,0xC7EC,0xC800,0xC801,0xC804,0xC808,0xC80A,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD564,0xD566,0xD567,0xD56A,0xD56C,0xD56E,0xD56F,/* 0x40-0x47 */ - 0xD570,0xD571,0xD572,0xD573,0xD576,0xD577,0xD579,0xD57A,/* 0x48-0x4F */ - 0xD57B,0xD57D,0xD57E,0xD57F,0xD580,0xD581,0xD582,0xD583,/* 0x50-0x57 */ - 0xD586,0xD58A,0xD58B,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xD58C,0xD58D,0xD58E,0xD58F,0xD591,0xD592,0xD593,/* 0x60-0x67 */ - 0xD594,0xD595,0xD596,0xD597,0xD598,0xD599,0xD59A,0xD59B,/* 0x68-0x6F */ - 0xD59C,0xD59D,0xD59E,0xD59F,0xD5A0,0xD5A1,0xD5A2,0xD5A3,/* 0x70-0x77 */ - 0xD5A4,0xD5A6,0xD5A7,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD5A8,0xD5A9,0xD5AA,0xD5AB,0xD5AC,0xD5AD,0xD5AE,/* 0x80-0x87 */ - 0xD5AF,0xD5B0,0xD5B1,0xD5B2,0xD5B3,0xD5B4,0xD5B5,0xD5B6,/* 0x88-0x8F */ - 0xD5B7,0xD5B8,0xD5B9,0xD5BA,0xD5BB,0xD5BC,0xD5BD,0xD5BE,/* 0x90-0x97 */ - 0xD5BF,0xD5C0,0xD5C1,0xD5C2,0xD5C3,0xD5C4,0xD5C5,0xD5C6,/* 0x98-0x9F */ - 0xD5C7,0xC810,0xC811,0xC813,0xC815,0xC816,0xC81C,0xC81D,/* 0xA0-0xA7 */ - 0xC820,0xC824,0xC82C,0xC82D,0xC82F,0xC831,0xC838,0xC83C,/* 0xA8-0xAF */ - 0xC840,0xC848,0xC849,0xC84C,0xC84D,0xC854,0xC870,0xC871,/* 0xB0-0xB7 */ - 0xC874,0xC878,0xC87A,0xC880,0xC881,0xC883,0xC885,0xC886,/* 0xB8-0xBF */ - 0xC887,0xC88B,0xC88C,0xC88D,0xC894,0xC89D,0xC89F,0xC8A1,/* 0xC0-0xC7 */ - 0xC8A8,0xC8BC,0xC8BD,0xC8C4,0xC8C8,0xC8CC,0xC8D4,0xC8D5,/* 0xC8-0xCF */ - 0xC8D7,0xC8D9,0xC8E0,0xC8E1,0xC8E4,0xC8F5,0xC8FC,0xC8FD,/* 0xD0-0xD7 */ - 0xC900,0xC904,0xC905,0xC906,0xC90C,0xC90D,0xC90F,0xC911,/* 0xD8-0xDF */ - 0xC918,0xC92C,0xC934,0xC950,0xC951,0xC954,0xC958,0xC960,/* 0xE0-0xE7 */ - 0xC961,0xC963,0xC96C,0xC970,0xC974,0xC97C,0xC988,0xC989,/* 0xE8-0xEF */ - 0xC98C,0xC990,0xC998,0xC999,0xC99B,0xC99D,0xC9C0,0xC9C1,/* 0xF0-0xF7 */ - 0xC9C4,0xC9C7,0xC9C8,0xC9CA,0xC9D0,0xC9D1,0xC9D3,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD5CA,0xD5CB,0xD5CD,0xD5CE,0xD5CF,0xD5D1,0xD5D3,/* 0x40-0x47 */ - 0xD5D4,0xD5D5,0xD5D6,0xD5D7,0xD5DA,0xD5DC,0xD5DE,0xD5DF,/* 0x48-0x4F */ - 0xD5E0,0xD5E1,0xD5E2,0xD5E3,0xD5E6,0xD5E7,0xD5E9,0xD5EA,/* 0x50-0x57 */ - 0xD5EB,0xD5ED,0xD5EE,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xD5EF,0xD5F0,0xD5F1,0xD5F2,0xD5F3,0xD5F6,0xD5F8,/* 0x60-0x67 */ - 0xD5FA,0xD5FB,0xD5FC,0xD5FD,0xD5FE,0xD5FF,0xD602,0xD603,/* 0x68-0x6F */ - 0xD605,0xD606,0xD607,0xD609,0xD60A,0xD60B,0xD60C,0xD60D,/* 0x70-0x77 */ - 0xD60E,0xD60F,0xD612,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD616,0xD617,0xD618,0xD619,0xD61A,0xD61B,0xD61D,/* 0x80-0x87 */ - 0xD61E,0xD61F,0xD621,0xD622,0xD623,0xD625,0xD626,0xD627,/* 0x88-0x8F */ - 0xD628,0xD629,0xD62A,0xD62B,0xD62C,0xD62E,0xD62F,0xD630,/* 0x90-0x97 */ - 0xD631,0xD632,0xD633,0xD634,0xD635,0xD636,0xD637,0xD63A,/* 0x98-0x9F */ - 0xD63B,0xC9D5,0xC9D6,0xC9D9,0xC9DA,0xC9DC,0xC9DD,0xC9E0,/* 0xA0-0xA7 */ - 0xC9E2,0xC9E4,0xC9E7,0xC9EC,0xC9ED,0xC9EF,0xC9F0,0xC9F1,/* 0xA8-0xAF */ - 0xC9F8,0xC9F9,0xC9FC,0xCA00,0xCA08,0xCA09,0xCA0B,0xCA0C,/* 0xB0-0xB7 */ - 0xCA0D,0xCA14,0xCA18,0xCA29,0xCA4C,0xCA4D,0xCA50,0xCA54,/* 0xB8-0xBF */ - 0xCA5C,0xCA5D,0xCA5F,0xCA60,0xCA61,0xCA68,0xCA7D,0xCA84,/* 0xC0-0xC7 */ - 0xCA98,0xCABC,0xCABD,0xCAC0,0xCAC4,0xCACC,0xCACD,0xCACF,/* 0xC8-0xCF */ - 0xCAD1,0xCAD3,0xCAD8,0xCAD9,0xCAE0,0xCAEC,0xCAF4,0xCB08,/* 0xD0-0xD7 */ - 0xCB10,0xCB14,0xCB18,0xCB20,0xCB21,0xCB41,0xCB48,0xCB49,/* 0xD8-0xDF */ - 0xCB4C,0xCB50,0xCB58,0xCB59,0xCB5D,0xCB64,0xCB78,0xCB79,/* 0xE0-0xE7 */ - 0xCB9C,0xCBB8,0xCBD4,0xCBE4,0xCBE7,0xCBE9,0xCC0C,0xCC0D,/* 0xE8-0xEF */ - 0xCC10,0xCC14,0xCC1C,0xCC1D,0xCC21,0xCC22,0xCC27,0xCC28,/* 0xF0-0xF7 */ - 0xCC29,0xCC2C,0xCC2E,0xCC30,0xCC38,0xCC39,0xCC3B,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD63D,0xD63E,0xD63F,0xD641,0xD642,0xD643,0xD644,/* 0x40-0x47 */ - 0xD646,0xD647,0xD64A,0xD64C,0xD64E,0xD64F,0xD650,0xD652,/* 0x48-0x4F */ - 0xD653,0xD656,0xD657,0xD659,0xD65A,0xD65B,0xD65D,0xD65E,/* 0x50-0x57 */ - 0xD65F,0xD660,0xD661,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xD662,0xD663,0xD664,0xD665,0xD666,0xD668,0xD66A,/* 0x60-0x67 */ - 0xD66B,0xD66C,0xD66D,0xD66E,0xD66F,0xD672,0xD673,0xD675,/* 0x68-0x6F */ - 0xD676,0xD677,0xD678,0xD679,0xD67A,0xD67B,0xD67C,0xD67D,/* 0x70-0x77 */ - 0xD67E,0xD67F,0xD680,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD681,0xD682,0xD684,0xD686,0xD687,0xD688,0xD689,/* 0x80-0x87 */ - 0xD68A,0xD68B,0xD68E,0xD68F,0xD691,0xD692,0xD693,0xD695,/* 0x88-0x8F */ - 0xD696,0xD697,0xD698,0xD699,0xD69A,0xD69B,0xD69C,0xD69E,/* 0x90-0x97 */ - 0xD6A0,0xD6A2,0xD6A3,0xD6A4,0xD6A5,0xD6A6,0xD6A7,0xD6A9,/* 0x98-0x9F */ - 0xD6AA,0xCC3C,0xCC3D,0xCC3E,0xCC44,0xCC45,0xCC48,0xCC4C,/* 0xA0-0xA7 */ - 0xCC54,0xCC55,0xCC57,0xCC58,0xCC59,0xCC60,0xCC64,0xCC66,/* 0xA8-0xAF */ - 0xCC68,0xCC70,0xCC75,0xCC98,0xCC99,0xCC9C,0xCCA0,0xCCA8,/* 0xB0-0xB7 */ - 0xCCA9,0xCCAB,0xCCAC,0xCCAD,0xCCB4,0xCCB5,0xCCB8,0xCCBC,/* 0xB8-0xBF */ - 0xCCC4,0xCCC5,0xCCC7,0xCCC9,0xCCD0,0xCCD4,0xCCE4,0xCCEC,/* 0xC0-0xC7 */ - 0xCCF0,0xCD01,0xCD08,0xCD09,0xCD0C,0xCD10,0xCD18,0xCD19,/* 0xC8-0xCF */ - 0xCD1B,0xCD1D,0xCD24,0xCD28,0xCD2C,0xCD39,0xCD5C,0xCD60,/* 0xD0-0xD7 */ - 0xCD64,0xCD6C,0xCD6D,0xCD6F,0xCD71,0xCD78,0xCD88,0xCD94,/* 0xD8-0xDF */ - 0xCD95,0xCD98,0xCD9C,0xCDA4,0xCDA5,0xCDA7,0xCDA9,0xCDB0,/* 0xE0-0xE7 */ - 0xCDC4,0xCDCC,0xCDD0,0xCDE8,0xCDEC,0xCDF0,0xCDF8,0xCDF9,/* 0xE8-0xEF */ - 0xCDFB,0xCDFD,0xCE04,0xCE08,0xCE0C,0xCE14,0xCE19,0xCE20,/* 0xF0-0xF7 */ - 0xCE21,0xCE24,0xCE28,0xCE30,0xCE31,0xCE33,0xCE35,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD6AB,0xD6AD,0xD6AE,0xD6AF,0xD6B1,0xD6B2,0xD6B3,/* 0x40-0x47 */ - 0xD6B4,0xD6B5,0xD6B6,0xD6B7,0xD6B8,0xD6BA,0xD6BC,0xD6BD,/* 0x48-0x4F */ - 0xD6BE,0xD6BF,0xD6C0,0xD6C1,0xD6C2,0xD6C3,0xD6C6,0xD6C7,/* 0x50-0x57 */ - 0xD6C9,0xD6CA,0xD6CB,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xD6CD,0xD6CE,0xD6CF,0xD6D0,0xD6D2,0xD6D3,0xD6D5,/* 0x60-0x67 */ - 0xD6D6,0xD6D8,0xD6DA,0xD6DB,0xD6DC,0xD6DD,0xD6DE,0xD6DF,/* 0x68-0x6F */ - 0xD6E1,0xD6E2,0xD6E3,0xD6E5,0xD6E6,0xD6E7,0xD6E9,0xD6EA,/* 0x70-0x77 */ - 0xD6EB,0xD6EC,0xD6ED,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD6EE,0xD6EF,0xD6F1,0xD6F2,0xD6F3,0xD6F4,0xD6F6,/* 0x80-0x87 */ - 0xD6F7,0xD6F8,0xD6F9,0xD6FA,0xD6FB,0xD6FE,0xD6FF,0xD701,/* 0x88-0x8F */ - 0xD702,0xD703,0xD705,0xD706,0xD707,0xD708,0xD709,0xD70A,/* 0x90-0x97 */ - 0xD70B,0xD70C,0xD70D,0xD70E,0xD70F,0xD710,0xD712,0xD713,/* 0x98-0x9F */ - 0xD714,0xCE58,0xCE59,0xCE5C,0xCE5F,0xCE60,0xCE61,0xCE68,/* 0xA0-0xA7 */ - 0xCE69,0xCE6B,0xCE6D,0xCE74,0xCE75,0xCE78,0xCE7C,0xCE84,/* 0xA8-0xAF */ - 0xCE85,0xCE87,0xCE89,0xCE90,0xCE91,0xCE94,0xCE98,0xCEA0,/* 0xB0-0xB7 */ - 0xCEA1,0xCEA3,0xCEA4,0xCEA5,0xCEAC,0xCEAD,0xCEC1,0xCEE4,/* 0xB8-0xBF */ - 0xCEE5,0xCEE8,0xCEEB,0xCEEC,0xCEF4,0xCEF5,0xCEF7,0xCEF8,/* 0xC0-0xC7 */ - 0xCEF9,0xCF00,0xCF01,0xCF04,0xCF08,0xCF10,0xCF11,0xCF13,/* 0xC8-0xCF */ - 0xCF15,0xCF1C,0xCF20,0xCF24,0xCF2C,0xCF2D,0xCF2F,0xCF30,/* 0xD0-0xD7 */ - 0xCF31,0xCF38,0xCF54,0xCF55,0xCF58,0xCF5C,0xCF64,0xCF65,/* 0xD8-0xDF */ - 0xCF67,0xCF69,0xCF70,0xCF71,0xCF74,0xCF78,0xCF80,0xCF85,/* 0xE0-0xE7 */ - 0xCF8C,0xCFA1,0xCFA8,0xCFB0,0xCFC4,0xCFE0,0xCFE1,0xCFE4,/* 0xE8-0xEF */ - 0xCFE8,0xCFF0,0xCFF1,0xCFF3,0xCFF5,0xCFFC,0xD000,0xD004,/* 0xF0-0xF7 */ - 0xD011,0xD018,0xD02D,0xD034,0xD035,0xD038,0xD03C,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD715,0xD716,0xD717,0xD71A,0xD71B,0xD71D,0xD71E,/* 0x40-0x47 */ - 0xD71F,0xD721,0xD722,0xD723,0xD724,0xD725,0xD726,0xD727,/* 0x48-0x4F */ - 0xD72A,0xD72C,0xD72E,0xD72F,0xD730,0xD731,0xD732,0xD733,/* 0x50-0x57 */ - 0xD736,0xD737,0xD739,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0xD73A,0xD73B,0xD73D,0xD73E,0xD73F,0xD740,0xD741,/* 0x60-0x67 */ - 0xD742,0xD743,0xD745,0xD746,0xD748,0xD74A,0xD74B,0xD74C,/* 0x68-0x6F */ - 0xD74D,0xD74E,0xD74F,0xD752,0xD753,0xD755,0xD75A,0xD75B,/* 0x70-0x77 */ - 0xD75C,0xD75D,0xD75E,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0xD75F,0xD762,0xD764,0xD766,0xD767,0xD768,0xD76A,/* 0x80-0x87 */ - 0xD76B,0xD76D,0xD76E,0xD76F,0xD771,0xD772,0xD773,0xD775,/* 0x88-0x8F */ - 0xD776,0xD777,0xD778,0xD779,0xD77A,0xD77B,0xD77E,0xD77F,/* 0x90-0x97 */ - 0xD780,0xD782,0xD783,0xD784,0xD785,0xD786,0xD787,0xD78A,/* 0x98-0x9F */ - 0xD78B,0xD044,0xD045,0xD047,0xD049,0xD050,0xD054,0xD058,/* 0xA0-0xA7 */ - 0xD060,0xD06C,0xD06D,0xD070,0xD074,0xD07C,0xD07D,0xD081,/* 0xA8-0xAF */ - 0xD0A4,0xD0A5,0xD0A8,0xD0AC,0xD0B4,0xD0B5,0xD0B7,0xD0B9,/* 0xB0-0xB7 */ - 0xD0C0,0xD0C1,0xD0C4,0xD0C8,0xD0C9,0xD0D0,0xD0D1,0xD0D3,/* 0xB8-0xBF */ - 0xD0D4,0xD0D5,0xD0DC,0xD0DD,0xD0E0,0xD0E4,0xD0EC,0xD0ED,/* 0xC0-0xC7 */ - 0xD0EF,0xD0F0,0xD0F1,0xD0F8,0xD10D,0xD130,0xD131,0xD134,/* 0xC8-0xCF */ - 0xD138,0xD13A,0xD140,0xD141,0xD143,0xD144,0xD145,0xD14C,/* 0xD0-0xD7 */ - 0xD14D,0xD150,0xD154,0xD15C,0xD15D,0xD15F,0xD161,0xD168,/* 0xD8-0xDF */ - 0xD16C,0xD17C,0xD184,0xD188,0xD1A0,0xD1A1,0xD1A4,0xD1A8,/* 0xE0-0xE7 */ - 0xD1B0,0xD1B1,0xD1B3,0xD1B5,0xD1BA,0xD1BC,0xD1C0,0xD1D8,/* 0xE8-0xEF */ - 0xD1F4,0xD1F8,0xD207,0xD209,0xD210,0xD22C,0xD22D,0xD230,/* 0xF0-0xF7 */ - 0xD234,0xD23C,0xD23D,0xD23F,0xD241,0xD248,0xD25C,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0xD78D,0xD78E,0xD78F,0xD791,0xD792,0xD793,0xD794,/* 0x40-0x47 */ - 0xD795,0xD796,0xD797,0xD79A,0xD79C,0xD79E,0xD79F,0xD7A0,/* 0x48-0x4F */ - 0xD7A1,0xD7A2,0xD7A3,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0xD264,0xD280,0xD281,0xD284,0xD288,0xD290,0xD291,/* 0xA0-0xA7 */ - 0xD295,0xD29C,0xD2A0,0xD2A4,0xD2AC,0xD2B1,0xD2B8,0xD2B9,/* 0xA8-0xAF */ - 0xD2BC,0xD2BF,0xD2C0,0xD2C2,0xD2C8,0xD2C9,0xD2CB,0xD2D4,/* 0xB0-0xB7 */ - 0xD2D8,0xD2DC,0xD2E4,0xD2E5,0xD2F0,0xD2F1,0xD2F4,0xD2F8,/* 0xB8-0xBF */ - 0xD300,0xD301,0xD303,0xD305,0xD30C,0xD30D,0xD30E,0xD310,/* 0xC0-0xC7 */ - 0xD314,0xD316,0xD31C,0xD31D,0xD31F,0xD320,0xD321,0xD325,/* 0xC8-0xCF */ - 0xD328,0xD329,0xD32C,0xD330,0xD338,0xD339,0xD33B,0xD33C,/* 0xD0-0xD7 */ - 0xD33D,0xD344,0xD345,0xD37C,0xD37D,0xD380,0xD384,0xD38C,/* 0xD8-0xDF */ - 0xD38D,0xD38F,0xD390,0xD391,0xD398,0xD399,0xD39C,0xD3A0,/* 0xE0-0xE7 */ - 0xD3A8,0xD3A9,0xD3AB,0xD3AD,0xD3B4,0xD3B8,0xD3BC,0xD3C4,/* 0xE8-0xEF */ - 0xD3C5,0xD3C8,0xD3C9,0xD3D0,0xD3D8,0xD3E1,0xD3E3,0xD3EC,/* 0xF0-0xF7 */ - 0xD3ED,0xD3F0,0xD3F4,0xD3FC,0xD3FD,0xD3FF,0xD401,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C7[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0xD408,0xD41D,0xD440,0xD444,0xD45C,0xD460,0xD464,/* 0xA0-0xA7 */ - 0xD46D,0xD46F,0xD478,0xD479,0xD47C,0xD47F,0xD480,0xD482,/* 0xA8-0xAF */ - 0xD488,0xD489,0xD48B,0xD48D,0xD494,0xD4A9,0xD4CC,0xD4D0,/* 0xB0-0xB7 */ - 0xD4D4,0xD4DC,0xD4DF,0xD4E8,0xD4EC,0xD4F0,0xD4F8,0xD4FB,/* 0xB8-0xBF */ - 0xD4FD,0xD504,0xD508,0xD50C,0xD514,0xD515,0xD517,0xD53C,/* 0xC0-0xC7 */ - 0xD53D,0xD540,0xD544,0xD54C,0xD54D,0xD54F,0xD551,0xD558,/* 0xC8-0xCF */ - 0xD559,0xD55C,0xD560,0xD565,0xD568,0xD569,0xD56B,0xD56D,/* 0xD0-0xD7 */ - 0xD574,0xD575,0xD578,0xD57C,0xD584,0xD585,0xD587,0xD588,/* 0xD8-0xDF */ - 0xD589,0xD590,0xD5A5,0xD5C8,0xD5C9,0xD5CC,0xD5D0,0xD5D2,/* 0xE0-0xE7 */ - 0xD5D8,0xD5D9,0xD5DB,0xD5DD,0xD5E4,0xD5E5,0xD5E8,0xD5EC,/* 0xE8-0xEF */ - 0xD5F4,0xD5F5,0xD5F7,0xD5F9,0xD600,0xD601,0xD604,0xD608,/* 0xF0-0xF7 */ - 0xD610,0xD611,0xD613,0xD614,0xD615,0xD61C,0xD620,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C8[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0xD624,0xD62D,0xD638,0xD639,0xD63C,0xD640,0xD645,/* 0xA0-0xA7 */ - 0xD648,0xD649,0xD64B,0xD64D,0xD651,0xD654,0xD655,0xD658,/* 0xA8-0xAF */ - 0xD65C,0xD667,0xD669,0xD670,0xD671,0xD674,0xD683,0xD685,/* 0xB0-0xB7 */ - 0xD68C,0xD68D,0xD690,0xD694,0xD69D,0xD69F,0xD6A1,0xD6A8,/* 0xB8-0xBF */ - 0xD6AC,0xD6B0,0xD6B9,0xD6BB,0xD6C4,0xD6C5,0xD6C8,0xD6CC,/* 0xC0-0xC7 */ - 0xD6D1,0xD6D4,0xD6D7,0xD6D9,0xD6E0,0xD6E4,0xD6E8,0xD6F0,/* 0xC8-0xCF */ - 0xD6F5,0xD6FC,0xD6FD,0xD700,0xD704,0xD711,0xD718,0xD719,/* 0xD0-0xD7 */ - 0xD71C,0xD720,0xD728,0xD729,0xD72B,0xD72D,0xD734,0xD735,/* 0xD8-0xDF */ - 0xD738,0xD73C,0xD744,0xD747,0xD749,0xD750,0xD751,0xD754,/* 0xE0-0xE7 */ - 0xD756,0xD757,0xD758,0xD759,0xD760,0xD761,0xD763,0xD765,/* 0xE8-0xEF */ - 0xD769,0xD76C,0xD770,0xD774,0xD77C,0xD77D,0xD781,0xD788,/* 0xF0-0xF7 */ - 0xD789,0xD78C,0xD790,0xD798,0xD799,0xD79B,0xD79D,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_CA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x4F3D,0x4F73,0x5047,0x50F9,0x52A0,0x53EF,0x5475,/* 0xA0-0xA7 */ - 0x54E5,0x5609,0x5AC1,0x5BB6,0x6687,0x67B6,0x67B7,0x67EF,/* 0xA8-0xAF */ - 0x6B4C,0x73C2,0x75C2,0x7A3C,0x82DB,0x8304,0x8857,0x8888,/* 0xB0-0xB7 */ - 0x8A36,0x8CC8,0x8DCF,0x8EFB,0x8FE6,0x99D5,0x523B,0x5374,/* 0xB8-0xBF */ - 0x5404,0x606A,0x6164,0x6BBC,0x73CF,0x811A,0x89BA,0x89D2,/* 0xC0-0xC7 */ - 0x95A3,0x4F83,0x520A,0x58BE,0x5978,0x59E6,0x5E72,0x5E79,/* 0xC8-0xCF */ - 0x61C7,0x63C0,0x6746,0x67EC,0x687F,0x6F97,0x764E,0x770B,/* 0xD0-0xD7 */ - 0x78F5,0x7A08,0x7AFF,0x7C21,0x809D,0x826E,0x8271,0x8AEB,/* 0xD8-0xDF */ - 0x9593,0x4E6B,0x559D,0x66F7,0x6E34,0x78A3,0x7AED,0x845B,/* 0xE0-0xE7 */ - 0x8910,0x874E,0x97A8,0x52D8,0x574E,0x582A,0x5D4C,0x611F,/* 0xE8-0xEF */ - 0x61BE,0x6221,0x6562,0x67D1,0x6A44,0x6E1B,0x7518,0x75B3,/* 0xF0-0xF7 */ - 0x76E3,0x77B0,0x7D3A,0x90AF,0x9451,0x9452,0x9F95,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_CB[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x5323,0x5CAC,0x7532,0x80DB,0x9240,0x9598,0x525B,/* 0xA0-0xA7 */ - 0x5808,0x59DC,0x5CA1,0x5D17,0x5EB7,0x5F3A,0x5F4A,0x6177,/* 0xA8-0xAF */ - 0x6C5F,0x757A,0x7586,0x7CE0,0x7D73,0x7DB1,0x7F8C,0x8154,/* 0xB0-0xB7 */ - 0x8221,0x8591,0x8941,0x8B1B,0x92FC,0x964D,0x9C47,0x4ECB,/* 0xB8-0xBF */ - 0x4EF7,0x500B,0x51F1,0x584F,0x6137,0x613E,0x6168,0x6539,/* 0xC0-0xC7 */ - 0x69EA,0x6F11,0x75A5,0x7686,0x76D6,0x7B87,0x82A5,0x84CB,/* 0xC8-0xCF */ - 0xF900,0x93A7,0x958B,0x5580,0x5BA2,0x5751,0xF901,0x7CB3,/* 0xD0-0xD7 */ - 0x7FB9,0x91B5,0x5028,0x53BB,0x5C45,0x5DE8,0x62D2,0x636E,/* 0xD8-0xDF */ - 0x64DA,0x64E7,0x6E20,0x70AC,0x795B,0x8DDD,0x8E1E,0xF902,/* 0xE0-0xE7 */ - 0x907D,0x9245,0x92F8,0x4E7E,0x4EF6,0x5065,0x5DFE,0x5EFA,/* 0xE8-0xEF */ - 0x6106,0x6957,0x8171,0x8654,0x8E47,0x9375,0x9A2B,0x4E5E,/* 0xF0-0xF7 */ - 0x5091,0x6770,0x6840,0x5109,0x528D,0x5292,0x6AA2,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_CC[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x77BC,0x9210,0x9ED4,0x52AB,0x602F,0x8FF2,0x5048,/* 0xA0-0xA7 */ - 0x61A9,0x63ED,0x64CA,0x683C,0x6A84,0x6FC0,0x8188,0x89A1,/* 0xA8-0xAF */ - 0x9694,0x5805,0x727D,0x72AC,0x7504,0x7D79,0x7E6D,0x80A9,/* 0xB0-0xB7 */ - 0x898B,0x8B74,0x9063,0x9D51,0x6289,0x6C7A,0x6F54,0x7D50,/* 0xB8-0xBF */ - 0x7F3A,0x8A23,0x517C,0x614A,0x7B9D,0x8B19,0x9257,0x938C,/* 0xC0-0xC7 */ - 0x4EAC,0x4FD3,0x501E,0x50BE,0x5106,0x52C1,0x52CD,0x537F,/* 0xC8-0xCF */ - 0x5770,0x5883,0x5E9A,0x5F91,0x6176,0x61AC,0x64CE,0x656C,/* 0xD0-0xD7 */ - 0x666F,0x66BB,0x66F4,0x6897,0x6D87,0x7085,0x70F1,0x749F,/* 0xD8-0xDF */ - 0x74A5,0x74CA,0x75D9,0x786C,0x78EC,0x7ADF,0x7AF6,0x7D45,/* 0xE0-0xE7 */ - 0x7D93,0x8015,0x803F,0x811B,0x8396,0x8B66,0x8F15,0x9015,/* 0xE8-0xEF */ - 0x93E1,0x9803,0x9838,0x9A5A,0x9BE8,0x4FC2,0x5553,0x583A,/* 0xF0-0xF7 */ - 0x5951,0x5B63,0x5C46,0x60B8,0x6212,0x6842,0x68B0,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_CD[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x68E8,0x6EAA,0x754C,0x7678,0x78CE,0x7A3D,0x7CFB,/* 0xA0-0xA7 */ - 0x7E6B,0x7E7C,0x8A08,0x8AA1,0x8C3F,0x968E,0x9DC4,0x53E4,/* 0xA8-0xAF */ - 0x53E9,0x544A,0x5471,0x56FA,0x59D1,0x5B64,0x5C3B,0x5EAB,/* 0xB0-0xB7 */ - 0x62F7,0x6537,0x6545,0x6572,0x66A0,0x67AF,0x69C1,0x6CBD,/* 0xB8-0xBF */ - 0x75FC,0x7690,0x777E,0x7A3F,0x7F94,0x8003,0x80A1,0x818F,/* 0xC0-0xC7 */ - 0x82E6,0x82FD,0x83F0,0x85C1,0x8831,0x88B4,0x8AA5,0xF903,/* 0xC8-0xCF */ - 0x8F9C,0x932E,0x96C7,0x9867,0x9AD8,0x9F13,0x54ED,0x659B,/* 0xD0-0xD7 */ - 0x66F2,0x688F,0x7A40,0x8C37,0x9D60,0x56F0,0x5764,0x5D11,/* 0xD8-0xDF */ - 0x6606,0x68B1,0x68CD,0x6EFE,0x7428,0x889E,0x9BE4,0x6C68,/* 0xE0-0xE7 */ - 0xF904,0x9AA8,0x4F9B,0x516C,0x5171,0x529F,0x5B54,0x5DE5,/* 0xE8-0xEF */ - 0x6050,0x606D,0x62F1,0x63A7,0x653B,0x73D9,0x7A7A,0x86A3,/* 0xF0-0xF7 */ - 0x8CA2,0x978F,0x4E32,0x5BE1,0x6208,0x679C,0x74DC,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_CE[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x79D1,0x83D3,0x8A87,0x8AB2,0x8DE8,0x904E,0x934B,/* 0xA0-0xA7 */ - 0x9846,0x5ED3,0x69E8,0x85FF,0x90ED,0xF905,0x51A0,0x5B98,/* 0xA8-0xAF */ - 0x5BEC,0x6163,0x68FA,0x6B3E,0x704C,0x742F,0x74D8,0x7BA1,/* 0xB0-0xB7 */ - 0x7F50,0x83C5,0x89C0,0x8CAB,0x95DC,0x9928,0x522E,0x605D,/* 0xB8-0xBF */ - 0x62EC,0x9002,0x4F8A,0x5149,0x5321,0x58D9,0x5EE3,0x66E0,/* 0xC0-0xC7 */ - 0x6D38,0x709A,0x72C2,0x73D6,0x7B50,0x80F1,0x945B,0x5366,/* 0xC8-0xCF */ - 0x639B,0x7F6B,0x4E56,0x5080,0x584A,0x58DE,0x602A,0x6127,/* 0xD0-0xD7 */ - 0x62D0,0x69D0,0x9B41,0x5B8F,0x7D18,0x80B1,0x8F5F,0x4EA4,/* 0xD8-0xDF */ - 0x50D1,0x54AC,0x55AC,0x5B0C,0x5DA0,0x5DE7,0x652A,0x654E,/* 0xE0-0xE7 */ - 0x6821,0x6A4B,0x72E1,0x768E,0x77EF,0x7D5E,0x7FF9,0x81A0,/* 0xE8-0xEF */ - 0x854E,0x86DF,0x8F03,0x8F4E,0x90CA,0x9903,0x9A55,0x9BAB,/* 0xF0-0xF7 */ - 0x4E18,0x4E45,0x4E5D,0x4EC7,0x4FF1,0x5177,0x52FE,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_CF[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x5340,0x53E3,0x53E5,0x548E,0x5614,0x5775,0x57A2,/* 0xA0-0xA7 */ - 0x5BC7,0x5D87,0x5ED0,0x61FC,0x62D8,0x6551,0x67B8,0x67E9,/* 0xA8-0xAF */ - 0x69CB,0x6B50,0x6BC6,0x6BEC,0x6C42,0x6E9D,0x7078,0x72D7,/* 0xB0-0xB7 */ - 0x7396,0x7403,0x77BF,0x77E9,0x7A76,0x7D7F,0x8009,0x81FC,/* 0xB8-0xBF */ - 0x8205,0x820A,0x82DF,0x8862,0x8B33,0x8CFC,0x8EC0,0x9011,/* 0xC0-0xC7 */ - 0x90B1,0x9264,0x92B6,0x99D2,0x9A45,0x9CE9,0x9DD7,0x9F9C,/* 0xC8-0xCF */ - 0x570B,0x5C40,0x83CA,0x97A0,0x97AB,0x9EB4,0x541B,0x7A98,/* 0xD0-0xD7 */ - 0x7FA4,0x88D9,0x8ECD,0x90E1,0x5800,0x5C48,0x6398,0x7A9F,/* 0xD8-0xDF */ - 0x5BAE,0x5F13,0x7A79,0x7AAE,0x828E,0x8EAC,0x5026,0x5238,/* 0xE0-0xE7 */ - 0x52F8,0x5377,0x5708,0x62F3,0x6372,0x6B0A,0x6DC3,0x7737,/* 0xE8-0xEF */ - 0x53A5,0x7357,0x8568,0x8E76,0x95D5,0x673A,0x6AC3,0x6F70,/* 0xF0-0xF7 */ - 0x8A6D,0x8ECC,0x994B,0xF906,0x6677,0x6B78,0x8CB4,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D0[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x9B3C,0xF907,0x53EB,0x572D,0x594E,0x63C6,0x69FB,/* 0xA0-0xA7 */ - 0x73EA,0x7845,0x7ABA,0x7AC5,0x7CFE,0x8475,0x898F,0x8D73,/* 0xA8-0xAF */ - 0x9035,0x95A8,0x52FB,0x5747,0x7547,0x7B60,0x83CC,0x921E,/* 0xB0-0xB7 */ - 0xF908,0x6A58,0x514B,0x524B,0x5287,0x621F,0x68D8,0x6975,/* 0xB8-0xBF */ - 0x9699,0x50C5,0x52A4,0x52E4,0x61C3,0x65A4,0x6839,0x69FF,/* 0xC0-0xC7 */ - 0x747E,0x7B4B,0x82B9,0x83EB,0x89B2,0x8B39,0x8FD1,0x9949,/* 0xC8-0xCF */ - 0xF909,0x4ECA,0x5997,0x64D2,0x6611,0x6A8E,0x7434,0x7981,/* 0xD0-0xD7 */ - 0x79BD,0x82A9,0x887E,0x887F,0x895F,0xF90A,0x9326,0x4F0B,/* 0xD8-0xDF */ - 0x53CA,0x6025,0x6271,0x6C72,0x7D1A,0x7D66,0x4E98,0x5162,/* 0xE0-0xE7 */ - 0x77DC,0x80AF,0x4F01,0x4F0E,0x5176,0x5180,0x55DC,0x5668,/* 0xE8-0xEF */ - 0x573B,0x57FA,0x57FC,0x5914,0x5947,0x5993,0x5BC4,0x5C90,/* 0xF0-0xF7 */ - 0x5D0E,0x5DF1,0x5E7E,0x5FCC,0x6280,0x65D7,0x65E3,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x671E,0x671F,0x675E,0x68CB,0x68C4,0x6A5F,0x6B3A,/* 0xA0-0xA7 */ - 0x6C23,0x6C7D,0x6C82,0x6DC7,0x7398,0x7426,0x742A,0x7482,/* 0xA8-0xAF */ - 0x74A3,0x7578,0x757F,0x7881,0x78EF,0x7941,0x7947,0x7948,/* 0xB0-0xB7 */ - 0x797A,0x7B95,0x7D00,0x7DBA,0x7F88,0x8006,0x802D,0x808C,/* 0xB8-0xBF */ - 0x8A18,0x8B4F,0x8C48,0x8D77,0x9321,0x9324,0x98E2,0x9951,/* 0xC0-0xC7 */ - 0x9A0E,0x9A0F,0x9A65,0x9E92,0x7DCA,0x4F76,0x5409,0x62EE,/* 0xC8-0xCF */ - 0x6854,0x91D1,0x55AB,0x513A,0xF90B,0xF90C,0x5A1C,0x61E6,/* 0xD0-0xD7 */ - 0xF90D,0x62CF,0x62FF,0xF90E,0xF90F,0xF910,0xF911,0xF912,/* 0xD8-0xDF */ - 0xF913,0x90A3,0xF914,0xF915,0xF916,0xF917,0xF918,0x8AFE,/* 0xE0-0xE7 */ - 0xF919,0xF91A,0xF91B,0xF91C,0x6696,0xF91D,0x7156,0xF91E,/* 0xE8-0xEF */ - 0xF91F,0x96E3,0xF920,0x634F,0x637A,0x5357,0xF921,0x678F,/* 0xF0-0xF7 */ - 0x6960,0x6E73,0xF922,0x7537,0xF923,0xF924,0xF925,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x7D0D,0xF926,0xF927,0x8872,0x56CA,0x5A18,0xF928,/* 0xA0-0xA7 */ - 0xF929,0xF92A,0xF92B,0xF92C,0x4E43,0xF92D,0x5167,0x5948,/* 0xA8-0xAF */ - 0x67F0,0x8010,0xF92E,0x5973,0x5E74,0x649A,0x79CA,0x5FF5,/* 0xB0-0xB7 */ - 0x606C,0x62C8,0x637B,0x5BE7,0x5BD7,0x52AA,0xF92F,0x5974,/* 0xB8-0xBF */ - 0x5F29,0x6012,0xF930,0xF931,0xF932,0x7459,0xF933,0xF934,/* 0xC0-0xC7 */ - 0xF935,0xF936,0xF937,0xF938,0x99D1,0xF939,0xF93A,0xF93B,/* 0xC8-0xCF */ - 0xF93C,0xF93D,0xF93E,0xF93F,0xF940,0xF941,0xF942,0xF943,/* 0xD0-0xD7 */ - 0x6FC3,0xF944,0xF945,0x81BF,0x8FB2,0x60F1,0xF946,0xF947,/* 0xD8-0xDF */ - 0x8166,0xF948,0xF949,0x5C3F,0xF94A,0xF94B,0xF94C,0xF94D,/* 0xE0-0xE7 */ - 0xF94E,0xF94F,0xF950,0xF951,0x5AE9,0x8A25,0x677B,0x7D10,/* 0xE8-0xEF */ - 0xF952,0xF953,0xF954,0xF955,0xF956,0xF957,0x80FD,0xF958,/* 0xF0-0xF7 */ - 0xF959,0x5C3C,0x6CE5,0x533F,0x6EBA,0x591A,0x8336,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x4E39,0x4EB6,0x4F46,0x55AE,0x5718,0x58C7,0x5F56,/* 0xA0-0xA7 */ - 0x65B7,0x65E6,0x6A80,0x6BB5,0x6E4D,0x77ED,0x7AEF,0x7C1E,/* 0xA8-0xAF */ - 0x7DDE,0x86CB,0x8892,0x9132,0x935B,0x64BB,0x6FBE,0x737A,/* 0xB0-0xB7 */ - 0x75B8,0x9054,0x5556,0x574D,0x61BA,0x64D4,0x66C7,0x6DE1,/* 0xB8-0xBF */ - 0x6E5B,0x6F6D,0x6FB9,0x75F0,0x8043,0x81BD,0x8541,0x8983,/* 0xC0-0xC7 */ - 0x8AC7,0x8B5A,0x931F,0x6C93,0x7553,0x7B54,0x8E0F,0x905D,/* 0xC8-0xCF */ - 0x5510,0x5802,0x5858,0x5E62,0x6207,0x649E,0x68E0,0x7576,/* 0xD0-0xD7 */ - 0x7CD6,0x87B3,0x9EE8,0x4EE3,0x5788,0x576E,0x5927,0x5C0D,/* 0xD8-0xDF */ - 0x5CB1,0x5E36,0x5F85,0x6234,0x64E1,0x73B3,0x81FA,0x888B,/* 0xE0-0xE7 */ - 0x8CB8,0x968A,0x9EDB,0x5B85,0x5FB7,0x60B3,0x5012,0x5200,/* 0xE8-0xEF */ - 0x5230,0x5716,0x5835,0x5857,0x5C0E,0x5C60,0x5CF6,0x5D8B,/* 0xF0-0xF7 */ - 0x5EA6,0x5F92,0x60BC,0x6311,0x6389,0x6417,0x6843,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x68F9,0x6AC2,0x6DD8,0x6E21,0x6ED4,0x6FE4,0x71FE,/* 0xA0-0xA7 */ - 0x76DC,0x7779,0x79B1,0x7A3B,0x8404,0x89A9,0x8CED,0x8DF3,/* 0xA8-0xAF */ - 0x8E48,0x9003,0x9014,0x9053,0x90FD,0x934D,0x9676,0x97DC,/* 0xB0-0xB7 */ - 0x6BD2,0x7006,0x7258,0x72A2,0x7368,0x7763,0x79BF,0x7BE4,/* 0xB8-0xBF */ - 0x7E9B,0x8B80,0x58A9,0x60C7,0x6566,0x65FD,0x66BE,0x6C8C,/* 0xC0-0xC7 */ - 0x711E,0x71C9,0x8C5A,0x9813,0x4E6D,0x7A81,0x4EDD,0x51AC,/* 0xC8-0xCF */ - 0x51CD,0x52D5,0x540C,0x61A7,0x6771,0x6850,0x68DF,0x6D1E,/* 0xD0-0xD7 */ - 0x6F7C,0x75BC,0x77B3,0x7AE5,0x80F4,0x8463,0x9285,0x515C,/* 0xD8-0xDF */ - 0x6597,0x675C,0x6793,0x75D8,0x7AC7,0x8373,0xF95A,0x8C46,/* 0xE0-0xE7 */ - 0x9017,0x982D,0x5C6F,0x81C0,0x829A,0x9041,0x906F,0x920D,/* 0xE8-0xEF */ - 0x5F97,0x5D9D,0x6A59,0x71C8,0x767B,0x7B49,0x85E4,0x8B04,/* 0xF0-0xF7 */ - 0x9127,0x9A30,0x5587,0x61F6,0xF95B,0x7669,0x7F85,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x863F,0x87BA,0x88F8,0x908F,0xF95C,0x6D1B,0x70D9,/* 0xA0-0xA7 */ - 0x73DE,0x7D61,0x843D,0xF95D,0x916A,0x99F1,0xF95E,0x4E82,/* 0xA8-0xAF */ - 0x5375,0x6B04,0x6B12,0x703E,0x721B,0x862D,0x9E1E,0x524C,/* 0xB0-0xB7 */ - 0x8FA3,0x5D50,0x64E5,0x652C,0x6B16,0x6FEB,0x7C43,0x7E9C,/* 0xB8-0xBF */ - 0x85CD,0x8964,0x89BD,0x62C9,0x81D8,0x881F,0x5ECA,0x6717,/* 0xC0-0xC7 */ - 0x6D6A,0x72FC,0x7405,0x746F,0x8782,0x90DE,0x4F86,0x5D0D,/* 0xC8-0xCF */ - 0x5FA0,0x840A,0x51B7,0x63A0,0x7565,0x4EAE,0x5006,0x5169,/* 0xD0-0xD7 */ - 0x51C9,0x6881,0x6A11,0x7CAE,0x7CB1,0x7CE7,0x826F,0x8AD2,/* 0xD8-0xDF */ - 0x8F1B,0x91CF,0x4FB6,0x5137,0x52F5,0x5442,0x5EEC,0x616E,/* 0xE0-0xE7 */ - 0x623E,0x65C5,0x6ADA,0x6FFE,0x792A,0x85DC,0x8823,0x95AD,/* 0xE8-0xEF */ - 0x9A62,0x9A6A,0x9E97,0x9ECE,0x529B,0x66C6,0x6B77,0x701D,/* 0xF0-0xF7 */ - 0x792B,0x8F62,0x9742,0x6190,0x6200,0x6523,0x6F23,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x7149,0x7489,0x7DF4,0x806F,0x84EE,0x8F26,0x9023,/* 0xA0-0xA7 */ - 0x934A,0x51BD,0x5217,0x52A3,0x6D0C,0x70C8,0x88C2,0x5EC9,/* 0xA8-0xAF */ - 0x6582,0x6BAE,0x6FC2,0x7C3E,0x7375,0x4EE4,0x4F36,0x56F9,/* 0xB0-0xB7 */ - 0xF95F,0x5CBA,0x5DBA,0x601C,0x73B2,0x7B2D,0x7F9A,0x7FCE,/* 0xB8-0xBF */ - 0x8046,0x901E,0x9234,0x96F6,0x9748,0x9818,0x9F61,0x4F8B,/* 0xC0-0xC7 */ - 0x6FA7,0x79AE,0x91B4,0x96B7,0x52DE,0xF960,0x6488,0x64C4,/* 0xC8-0xCF */ - 0x6AD3,0x6F5E,0x7018,0x7210,0x76E7,0x8001,0x8606,0x865C,/* 0xD0-0xD7 */ - 0x8DEF,0x8F05,0x9732,0x9B6F,0x9DFA,0x9E75,0x788C,0x797F,/* 0xD8-0xDF */ - 0x7DA0,0x83C9,0x9304,0x9E7F,0x9E93,0x8AD6,0x58DF,0x5F04,/* 0xE0-0xE7 */ - 0x6727,0x7027,0x74CF,0x7C60,0x807E,0x5121,0x7028,0x7262,/* 0xE8-0xEF */ - 0x78CA,0x8CC2,0x8CDA,0x8CF4,0x96F7,0x4E86,0x50DA,0x5BEE,/* 0xF0-0xF7 */ - 0x5ED6,0x6599,0x71CE,0x7642,0x77AD,0x804A,0x84FC,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D7[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x907C,0x9B27,0x9F8D,0x58D8,0x5A41,0x5C62,0x6A13,/* 0xA0-0xA7 */ - 0x6DDA,0x6F0F,0x763B,0x7D2F,0x7E37,0x851E,0x8938,0x93E4,/* 0xA8-0xAF */ - 0x964B,0x5289,0x65D2,0x67F3,0x69B4,0x6D41,0x6E9C,0x700F,/* 0xB0-0xB7 */ - 0x7409,0x7460,0x7559,0x7624,0x786B,0x8B2C,0x985E,0x516D,/* 0xB8-0xBF */ - 0x622E,0x9678,0x4F96,0x502B,0x5D19,0x6DEA,0x7DB8,0x8F2A,/* 0xC0-0xC7 */ - 0x5F8B,0x6144,0x6817,0xF961,0x9686,0x52D2,0x808B,0x51DC,/* 0xC8-0xCF */ - 0x51CC,0x695E,0x7A1C,0x7DBE,0x83F1,0x9675,0x4FDA,0x5229,/* 0xD0-0xD7 */ - 0x5398,0x540F,0x550E,0x5C65,0x60A7,0x674E,0x68A8,0x6D6C,/* 0xD8-0xDF */ - 0x7281,0x72F8,0x7406,0x7483,0xF962,0x75E2,0x7C6C,0x7F79,/* 0xE0-0xE7 */ - 0x7FB8,0x8389,0x88CF,0x88E1,0x91CC,0x91D0,0x96E2,0x9BC9,/* 0xE8-0xEF */ - 0x541D,0x6F7E,0x71D0,0x7498,0x85FA,0x8EAA,0x96A3,0x9C57,/* 0xF0-0xF7 */ - 0x9E9F,0x6797,0x6DCB,0x7433,0x81E8,0x9716,0x782C,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D8[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x7ACB,0x7B20,0x7C92,0x6469,0x746A,0x75F2,0x78BC,/* 0xA0-0xA7 */ - 0x78E8,0x99AC,0x9B54,0x9EBB,0x5BDE,0x5E55,0x6F20,0x819C,/* 0xA8-0xAF */ - 0x83AB,0x9088,0x4E07,0x534D,0x5A29,0x5DD2,0x5F4E,0x6162,/* 0xB0-0xB7 */ - 0x633D,0x6669,0x66FC,0x6EFF,0x6F2B,0x7063,0x779E,0x842C,/* 0xB8-0xBF */ - 0x8513,0x883B,0x8F13,0x9945,0x9C3B,0x551C,0x62B9,0x672B,/* 0xC0-0xC7 */ - 0x6CAB,0x8309,0x896A,0x977A,0x4EA1,0x5984,0x5FD8,0x5FD9,/* 0xC8-0xCF */ - 0x671B,0x7DB2,0x7F54,0x8292,0x832B,0x83BD,0x8F1E,0x9099,/* 0xD0-0xD7 */ - 0x57CB,0x59B9,0x5A92,0x5BD0,0x6627,0x679A,0x6885,0x6BCF,/* 0xD8-0xDF */ - 0x7164,0x7F75,0x8CB7,0x8CE3,0x9081,0x9B45,0x8108,0x8C8A,/* 0xE0-0xE7 */ - 0x964C,0x9A40,0x9EA5,0x5B5F,0x6C13,0x731B,0x76F2,0x76DF,/* 0xE8-0xEF */ - 0x840C,0x51AA,0x8993,0x514D,0x5195,0x52C9,0x68C9,0x6C94,/* 0xF0-0xF7 */ - 0x7704,0x7720,0x7DBF,0x7DEC,0x9762,0x9EB5,0x6EC5,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D9[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x8511,0x51A5,0x540D,0x547D,0x660E,0x669D,0x6927,/* 0xA0-0xA7 */ - 0x6E9F,0x76BF,0x7791,0x8317,0x84C2,0x879F,0x9169,0x9298,/* 0xA8-0xAF */ - 0x9CF4,0x8882,0x4FAE,0x5192,0x52DF,0x59C6,0x5E3D,0x6155,/* 0xB0-0xB7 */ - 0x6478,0x6479,0x66AE,0x67D0,0x6A21,0x6BCD,0x6BDB,0x725F,/* 0xB8-0xBF */ - 0x7261,0x7441,0x7738,0x77DB,0x8017,0x82BC,0x8305,0x8B00,/* 0xC0-0xC7 */ - 0x8B28,0x8C8C,0x6728,0x6C90,0x7267,0x76EE,0x7766,0x7A46,/* 0xC8-0xCF */ - 0x9DA9,0x6B7F,0x6C92,0x5922,0x6726,0x8499,0x536F,0x5893,/* 0xD0-0xD7 */ - 0x5999,0x5EDF,0x63CF,0x6634,0x6773,0x6E3A,0x732B,0x7AD7,/* 0xD8-0xDF */ - 0x82D7,0x9328,0x52D9,0x5DEB,0x61AE,0x61CB,0x620A,0x62C7,/* 0xE0-0xE7 */ - 0x64AB,0x65E0,0x6959,0x6B66,0x6BCB,0x7121,0x73F7,0x755D,/* 0xE8-0xEF */ - 0x7E46,0x821E,0x8302,0x856A,0x8AA3,0x8CBF,0x9727,0x9D61,/* 0xF0-0xF7 */ - 0x58A8,0x9ED8,0x5011,0x520E,0x543B,0x554F,0x6587,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_DA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x6C76,0x7D0A,0x7D0B,0x805E,0x868A,0x9580,0x96EF,/* 0xA0-0xA7 */ - 0x52FF,0x6C95,0x7269,0x5473,0x5A9A,0x5C3E,0x5D4B,0x5F4C,/* 0xA8-0xAF */ - 0x5FAE,0x672A,0x68B6,0x6963,0x6E3C,0x6E44,0x7709,0x7C73,/* 0xB0-0xB7 */ - 0x7F8E,0x8587,0x8B0E,0x8FF7,0x9761,0x9EF4,0x5CB7,0x60B6,/* 0xB8-0xBF */ - 0x610D,0x61AB,0x654F,0x65FB,0x65FC,0x6C11,0x6CEF,0x739F,/* 0xC0-0xC7 */ - 0x73C9,0x7DE1,0x9594,0x5BC6,0x871C,0x8B10,0x525D,0x535A,/* 0xC8-0xCF */ - 0x62CD,0x640F,0x64B2,0x6734,0x6A38,0x6CCA,0x73C0,0x749E,/* 0xD0-0xD7 */ - 0x7B94,0x7C95,0x7E1B,0x818A,0x8236,0x8584,0x8FEB,0x96F9,/* 0xD8-0xDF */ - 0x99C1,0x4F34,0x534A,0x53CD,0x53DB,0x62CC,0x642C,0x6500,/* 0xE0-0xE7 */ - 0x6591,0x69C3,0x6CEE,0x6F58,0x73ED,0x7554,0x7622,0x76E4,/* 0xE8-0xEF */ - 0x76FC,0x78D0,0x78FB,0x792C,0x7D46,0x822C,0x87E0,0x8FD4,/* 0xF0-0xF7 */ - 0x9812,0x98EF,0x52C3,0x62D4,0x64A5,0x6E24,0x6F51,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_DB[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x767C,0x8DCB,0x91B1,0x9262,0x9AEE,0x9B43,0x5023,/* 0xA0-0xA7 */ - 0x508D,0x574A,0x59A8,0x5C28,0x5E47,0x5F77,0x623F,0x653E,/* 0xA8-0xAF */ - 0x65B9,0x65C1,0x6609,0x678B,0x699C,0x6EC2,0x78C5,0x7D21,/* 0xB0-0xB7 */ - 0x80AA,0x8180,0x822B,0x82B3,0x84A1,0x868C,0x8A2A,0x8B17,/* 0xB8-0xBF */ - 0x90A6,0x9632,0x9F90,0x500D,0x4FF3,0xF963,0x57F9,0x5F98,/* 0xC0-0xC7 */ - 0x62DC,0x6392,0x676F,0x6E43,0x7119,0x76C3,0x80CC,0x80DA,/* 0xC8-0xCF */ - 0x88F4,0x88F5,0x8919,0x8CE0,0x8F29,0x914D,0x966A,0x4F2F,/* 0xD0-0xD7 */ - 0x4F70,0x5E1B,0x67CF,0x6822,0x767D,0x767E,0x9B44,0x5E61,/* 0xD8-0xDF */ - 0x6A0A,0x7169,0x71D4,0x756A,0xF964,0x7E41,0x8543,0x85E9,/* 0xE0-0xE7 */ - 0x98DC,0x4F10,0x7B4F,0x7F70,0x95A5,0x51E1,0x5E06,0x68B5,/* 0xE8-0xEF */ - 0x6C3E,0x6C4E,0x6CDB,0x72AF,0x7BC4,0x8303,0x6CD5,0x743A,/* 0xF0-0xF7 */ - 0x50FB,0x5288,0x58C1,0x64D8,0x6A97,0x74A7,0x7656,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_DC[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x78A7,0x8617,0x95E2,0x9739,0xF965,0x535E,0x5F01,/* 0xA0-0xA7 */ - 0x8B8A,0x8FA8,0x8FAF,0x908A,0x5225,0x77A5,0x9C49,0x9F08,/* 0xA8-0xAF */ - 0x4E19,0x5002,0x5175,0x5C5B,0x5E77,0x661E,0x663A,0x67C4,/* 0xB0-0xB7 */ - 0x68C5,0x70B3,0x7501,0x75C5,0x79C9,0x7ADD,0x8F27,0x9920,/* 0xB8-0xBF */ - 0x9A08,0x4FDD,0x5821,0x5831,0x5BF6,0x666E,0x6B65,0x6D11,/* 0xC0-0xC7 */ - 0x6E7A,0x6F7D,0x73E4,0x752B,0x83E9,0x88DC,0x8913,0x8B5C,/* 0xC8-0xCF */ - 0x8F14,0x4F0F,0x50D5,0x5310,0x535C,0x5B93,0x5FA9,0x670D,/* 0xD0-0xD7 */ - 0x798F,0x8179,0x832F,0x8514,0x8907,0x8986,0x8F39,0x8F3B,/* 0xD8-0xDF */ - 0x99A5,0x9C12,0x672C,0x4E76,0x4FF8,0x5949,0x5C01,0x5CEF,/* 0xE0-0xE7 */ - 0x5CF0,0x6367,0x68D2,0x70FD,0x71A2,0x742B,0x7E2B,0x84EC,/* 0xE8-0xEF */ - 0x8702,0x9022,0x92D2,0x9CF3,0x4E0D,0x4ED8,0x4FEF,0x5085,/* 0xF0-0xF7 */ - 0x5256,0x526F,0x5426,0x5490,0x57E0,0x592B,0x5A66,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_DD[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x5B5A,0x5B75,0x5BCC,0x5E9C,0xF966,0x6276,0x6577,/* 0xA0-0xA7 */ - 0x65A7,0x6D6E,0x6EA5,0x7236,0x7B26,0x7C3F,0x7F36,0x8150,/* 0xA8-0xAF */ - 0x8151,0x819A,0x8240,0x8299,0x83A9,0x8A03,0x8CA0,0x8CE6,/* 0xB0-0xB7 */ - 0x8CFB,0x8D74,0x8DBA,0x90E8,0x91DC,0x961C,0x9644,0x99D9,/* 0xB8-0xBF */ - 0x9CE7,0x5317,0x5206,0x5429,0x5674,0x58B3,0x5954,0x596E,/* 0xC0-0xC7 */ - 0x5FFF,0x61A4,0x626E,0x6610,0x6C7E,0x711A,0x76C6,0x7C89,/* 0xC8-0xCF */ - 0x7CDE,0x7D1B,0x82AC,0x8CC1,0x96F0,0xF967,0x4F5B,0x5F17,/* 0xD0-0xD7 */ - 0x5F7F,0x62C2,0x5D29,0x670B,0x68DA,0x787C,0x7E43,0x9D6C,/* 0xD8-0xDF */ - 0x4E15,0x5099,0x5315,0x532A,0x5351,0x5983,0x5A62,0x5E87,/* 0xE0-0xE7 */ - 0x60B2,0x618A,0x6249,0x6279,0x6590,0x6787,0x69A7,0x6BD4,/* 0xE8-0xEF */ - 0x6BD6,0x6BD7,0x6BD8,0x6CB8,0xF968,0x7435,0x75FA,0x7812,/* 0xF0-0xF7 */ - 0x7891,0x79D5,0x79D8,0x7C83,0x7DCB,0x7FE1,0x80A5,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_DE[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x813E,0x81C2,0x83F2,0x871A,0x88E8,0x8AB9,0x8B6C,/* 0xA0-0xA7 */ - 0x8CBB,0x9119,0x975E,0x98DB,0x9F3B,0x56AC,0x5B2A,0x5F6C,/* 0xA8-0xAF */ - 0x658C,0x6AB3,0x6BAF,0x6D5C,0x6FF1,0x7015,0x725D,0x73AD,/* 0xB0-0xB7 */ - 0x8CA7,0x8CD3,0x983B,0x6191,0x6C37,0x8058,0x9A01,0x4E4D,/* 0xB8-0xBF */ - 0x4E8B,0x4E9B,0x4ED5,0x4F3A,0x4F3C,0x4F7F,0x4FDF,0x50FF,/* 0xC0-0xC7 */ - 0x53F2,0x53F8,0x5506,0x55E3,0x56DB,0x58EB,0x5962,0x5A11,/* 0xC8-0xCF */ - 0x5BEB,0x5BFA,0x5C04,0x5DF3,0x5E2B,0x5F99,0x601D,0x6368,/* 0xD0-0xD7 */ - 0x659C,0x65AF,0x67F6,0x67FB,0x68AD,0x6B7B,0x6C99,0x6CD7,/* 0xD8-0xDF */ - 0x6E23,0x7009,0x7345,0x7802,0x793E,0x7940,0x7960,0x79C1,/* 0xE0-0xE7 */ - 0x7BE9,0x7D17,0x7D72,0x8086,0x820D,0x838E,0x84D1,0x86C7,/* 0xE8-0xEF */ - 0x88DF,0x8A50,0x8A5E,0x8B1D,0x8CDC,0x8D66,0x8FAD,0x90AA,/* 0xF0-0xF7 */ - 0x98FC,0x99DF,0x9E9D,0x524A,0xF969,0x6714,0xF96A,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_DF[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x5098,0x522A,0x5C71,0x6563,0x6C55,0x73CA,0x7523,/* 0xA0-0xA7 */ - 0x759D,0x7B97,0x849C,0x9178,0x9730,0x4E77,0x6492,0x6BBA,/* 0xA8-0xAF */ - 0x715E,0x85A9,0x4E09,0xF96B,0x6749,0x68EE,0x6E17,0x829F,/* 0xB0-0xB7 */ - 0x8518,0x886B,0x63F7,0x6F81,0x9212,0x98AF,0x4E0A,0x50B7,/* 0xB8-0xBF */ - 0x50CF,0x511F,0x5546,0x55AA,0x5617,0x5B40,0x5C19,0x5CE0,/* 0xC0-0xC7 */ - 0x5E38,0x5E8A,0x5EA0,0x5EC2,0x60F3,0x6851,0x6A61,0x6E58,/* 0xC8-0xCF */ - 0x723D,0x7240,0x72C0,0x76F8,0x7965,0x7BB1,0x7FD4,0x88F3,/* 0xD0-0xD7 */ - 0x89F4,0x8A73,0x8C61,0x8CDE,0x971C,0x585E,0x74BD,0x8CFD,/* 0xD8-0xDF */ - 0x55C7,0xF96C,0x7A61,0x7D22,0x8272,0x7272,0x751F,0x7525,/* 0xE0-0xE7 */ - 0xF96D,0x7B19,0x5885,0x58FB,0x5DBC,0x5E8F,0x5EB6,0x5F90,/* 0xE8-0xEF */ - 0x6055,0x6292,0x637F,0x654D,0x6691,0x66D9,0x66F8,0x6816,/* 0xF0-0xF7 */ - 0x68F2,0x7280,0x745E,0x7B6E,0x7D6E,0x7DD6,0x7F72,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E0[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x80E5,0x8212,0x85AF,0x897F,0x8A93,0x901D,0x92E4,/* 0xA0-0xA7 */ - 0x9ECD,0x9F20,0x5915,0x596D,0x5E2D,0x60DC,0x6614,0x6673,/* 0xA8-0xAF */ - 0x6790,0x6C50,0x6DC5,0x6F5F,0x77F3,0x78A9,0x84C6,0x91CB,/* 0xB0-0xB7 */ - 0x932B,0x4ED9,0x50CA,0x5148,0x5584,0x5B0B,0x5BA3,0x6247,/* 0xB8-0xBF */ - 0x657E,0x65CB,0x6E32,0x717D,0x7401,0x7444,0x7487,0x74BF,/* 0xC0-0xC7 */ - 0x766C,0x79AA,0x7DDA,0x7E55,0x7FA8,0x817A,0x81B3,0x8239,/* 0xC8-0xCF */ - 0x861A,0x87EC,0x8A75,0x8DE3,0x9078,0x9291,0x9425,0x994D,/* 0xD0-0xD7 */ - 0x9BAE,0x5368,0x5C51,0x6954,0x6CC4,0x6D29,0x6E2B,0x820C,/* 0xD8-0xDF */ - 0x859B,0x893B,0x8A2D,0x8AAA,0x96EA,0x9F67,0x5261,0x66B9,/* 0xE0-0xE7 */ - 0x6BB2,0x7E96,0x87FE,0x8D0D,0x9583,0x965D,0x651D,0x6D89,/* 0xE8-0xEF */ - 0x71EE,0xF96E,0x57CE,0x59D3,0x5BAC,0x6027,0x60FA,0x6210,/* 0xF0-0xF7 */ - 0x661F,0x665F,0x7329,0x73F9,0x76DB,0x7701,0x7B6C,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x8056,0x8072,0x8165,0x8AA0,0x9192,0x4E16,0x52E2,/* 0xA0-0xA7 */ - 0x6B72,0x6D17,0x7A05,0x7B39,0x7D30,0xF96F,0x8CB0,0x53EC,/* 0xA8-0xAF */ - 0x562F,0x5851,0x5BB5,0x5C0F,0x5C11,0x5DE2,0x6240,0x6383,/* 0xB0-0xB7 */ - 0x6414,0x662D,0x68B3,0x6CBC,0x6D88,0x6EAF,0x701F,0x70A4,/* 0xB8-0xBF */ - 0x71D2,0x7526,0x758F,0x758E,0x7619,0x7B11,0x7BE0,0x7C2B,/* 0xC0-0xC7 */ - 0x7D20,0x7D39,0x852C,0x856D,0x8607,0x8A34,0x900D,0x9061,/* 0xC8-0xCF */ - 0x90B5,0x92B7,0x97F6,0x9A37,0x4FD7,0x5C6C,0x675F,0x6D91,/* 0xD0-0xD7 */ - 0x7C9F,0x7E8C,0x8B16,0x8D16,0x901F,0x5B6B,0x5DFD,0x640D,/* 0xD8-0xDF */ - 0x84C0,0x905C,0x98E1,0x7387,0x5B8B,0x609A,0x677E,0x6DDE,/* 0xE0-0xE7 */ - 0x8A1F,0x8AA6,0x9001,0x980C,0x5237,0xF970,0x7051,0x788E,/* 0xE8-0xEF */ - 0x9396,0x8870,0x91D7,0x4FEE,0x53D7,0x55FD,0x56DA,0x5782,/* 0xF0-0xF7 */ - 0x58FD,0x5AC2,0x5B88,0x5CAB,0x5CC0,0x5E25,0x6101,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x620D,0x624B,0x6388,0x641C,0x6536,0x6578,0x6A39,/* 0xA0-0xA7 */ - 0x6B8A,0x6C34,0x6D19,0x6F31,0x71E7,0x72E9,0x7378,0x7407,/* 0xA8-0xAF */ - 0x74B2,0x7626,0x7761,0x79C0,0x7A57,0x7AEA,0x7CB9,0x7D8F,/* 0xB0-0xB7 */ - 0x7DAC,0x7E61,0x7F9E,0x8129,0x8331,0x8490,0x84DA,0x85EA,/* 0xB8-0xBF */ - 0x8896,0x8AB0,0x8B90,0x8F38,0x9042,0x9083,0x916C,0x9296,/* 0xC0-0xC7 */ - 0x92B9,0x968B,0x96A7,0x96A8,0x96D6,0x9700,0x9808,0x9996,/* 0xC8-0xCF */ - 0x9AD3,0x9B1A,0x53D4,0x587E,0x5919,0x5B70,0x5BBF,0x6DD1,/* 0xD0-0xD7 */ - 0x6F5A,0x719F,0x7421,0x74B9,0x8085,0x83FD,0x5DE1,0x5F87,/* 0xD8-0xDF */ - 0x5FAA,0x6042,0x65EC,0x6812,0x696F,0x6A53,0x6B89,0x6D35,/* 0xE0-0xE7 */ - 0x6DF3,0x73E3,0x76FE,0x77AC,0x7B4D,0x7D14,0x8123,0x821C,/* 0xE8-0xEF */ - 0x8340,0x84F4,0x8563,0x8A62,0x8AC4,0x9187,0x931E,0x9806,/* 0xF0-0xF7 */ - 0x99B4,0x620C,0x8853,0x8FF0,0x9265,0x5D07,0x5D27,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x5D69,0x745F,0x819D,0x8768,0x6FD5,0x62FE,0x7FD2,/* 0xA0-0xA7 */ - 0x8936,0x8972,0x4E1E,0x4E58,0x50E7,0x52DD,0x5347,0x627F,/* 0xA8-0xAF */ - 0x6607,0x7E69,0x8805,0x965E,0x4F8D,0x5319,0x5636,0x59CB,/* 0xB0-0xB7 */ - 0x5AA4,0x5C38,0x5C4E,0x5C4D,0x5E02,0x5F11,0x6043,0x65BD,/* 0xB8-0xBF */ - 0x662F,0x6642,0x67BE,0x67F4,0x731C,0x77E2,0x793A,0x7FC5,/* 0xC0-0xC7 */ - 0x8494,0x84CD,0x8996,0x8A66,0x8A69,0x8AE1,0x8C55,0x8C7A,/* 0xC8-0xCF */ - 0x57F4,0x5BD4,0x5F0F,0x606F,0x62ED,0x690D,0x6B96,0x6E5C,/* 0xD0-0xD7 */ - 0x7184,0x7BD2,0x8755,0x8B58,0x8EFE,0x98DF,0x98FE,0x4F38,/* 0xD8-0xDF */ - 0x4F81,0x4FE1,0x547B,0x5A20,0x5BB8,0x613C,0x65B0,0x6668,/* 0xE0-0xE7 */ - 0x71FC,0x7533,0x795E,0x7D33,0x814E,0x81E3,0x8398,0x85AA,/* 0xE8-0xEF */ - 0x85CE,0x8703,0x8A0A,0x8EAB,0x8F9B,0xF971,0x8FC5,0x5931,/* 0xF0-0xF7 */ - 0x5BA4,0x5BE6,0x6089,0x5BE9,0x5C0B,0x5FC3,0x6C81,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0xF972,0x6DF1,0x700B,0x751A,0x82AF,0x8AF6,0x4EC0,/* 0xA0-0xA7 */ - 0x5341,0xF973,0x96D9,0x6C0F,0x4E9E,0x4FC4,0x5152,0x555E,/* 0xA8-0xAF */ - 0x5A25,0x5CE8,0x6211,0x7259,0x82BD,0x83AA,0x86FE,0x8859,/* 0xB0-0xB7 */ - 0x8A1D,0x963F,0x96C5,0x9913,0x9D09,0x9D5D,0x580A,0x5CB3,/* 0xB8-0xBF */ - 0x5DBD,0x5E44,0x60E1,0x6115,0x63E1,0x6A02,0x6E25,0x9102,/* 0xC0-0xC7 */ - 0x9354,0x984E,0x9C10,0x9F77,0x5B89,0x5CB8,0x6309,0x664F,/* 0xC8-0xCF */ - 0x6848,0x773C,0x96C1,0x978D,0x9854,0x9B9F,0x65A1,0x8B01,/* 0xD0-0xD7 */ - 0x8ECB,0x95BC,0x5535,0x5CA9,0x5DD6,0x5EB5,0x6697,0x764C,/* 0xD8-0xDF */ - 0x83F4,0x95C7,0x58D3,0x62BC,0x72CE,0x9D28,0x4EF0,0x592E,/* 0xE0-0xE7 */ - 0x600F,0x663B,0x6B83,0x79E7,0x9D26,0x5393,0x54C0,0x57C3,/* 0xE8-0xEF */ - 0x5D16,0x611B,0x66D6,0x6DAF,0x788D,0x827E,0x9698,0x9744,/* 0xF0-0xF7 */ - 0x5384,0x627C,0x6396,0x6DB2,0x7E0A,0x814B,0x984D,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x6AFB,0x7F4C,0x9DAF,0x9E1A,0x4E5F,0x503B,0x51B6,/* 0xA0-0xA7 */ - 0x591C,0x60F9,0x63F6,0x6930,0x723A,0x8036,0xF974,0x91CE,/* 0xA8-0xAF */ - 0x5F31,0xF975,0xF976,0x7D04,0x82E5,0x846F,0x84BB,0x85E5,/* 0xB0-0xB7 */ - 0x8E8D,0xF977,0x4F6F,0xF978,0xF979,0x58E4,0x5B43,0x6059,/* 0xB8-0xBF */ - 0x63DA,0x6518,0x656D,0x6698,0xF97A,0x694A,0x6A23,0x6D0B,/* 0xC0-0xC7 */ - 0x7001,0x716C,0x75D2,0x760D,0x79B3,0x7A70,0xF97B,0x7F8A,/* 0xC8-0xCF */ - 0xF97C,0x8944,0xF97D,0x8B93,0x91C0,0x967D,0xF97E,0x990A,/* 0xD0-0xD7 */ - 0x5704,0x5FA1,0x65BC,0x6F01,0x7600,0x79A6,0x8A9E,0x99AD,/* 0xD8-0xDF */ - 0x9B5A,0x9F6C,0x5104,0x61B6,0x6291,0x6A8D,0x81C6,0x5043,/* 0xE0-0xE7 */ - 0x5830,0x5F66,0x7109,0x8A00,0x8AFA,0x5B7C,0x8616,0x4FFA,/* 0xE8-0xEF */ - 0x513C,0x56B4,0x5944,0x63A9,0x6DF9,0x5DAA,0x696D,0x5186,/* 0xF0-0xF7 */ - 0x4E88,0x4F59,0xF97F,0xF980,0xF981,0x5982,0xF982,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0xF983,0x6B5F,0x6C5D,0xF984,0x74B5,0x7916,0xF985,/* 0xA0-0xA7 */ - 0x8207,0x8245,0x8339,0x8F3F,0x8F5D,0xF986,0x9918,0xF987,/* 0xA8-0xAF */ - 0xF988,0xF989,0x4EA6,0xF98A,0x57DF,0x5F79,0x6613,0xF98B,/* 0xB0-0xB7 */ - 0xF98C,0x75AB,0x7E79,0x8B6F,0xF98D,0x9006,0x9A5B,0x56A5,/* 0xB8-0xBF */ - 0x5827,0x59F8,0x5A1F,0x5BB4,0xF98E,0x5EF6,0xF98F,0xF990,/* 0xC0-0xC7 */ - 0x6350,0x633B,0xF991,0x693D,0x6C87,0x6CBF,0x6D8E,0x6D93,/* 0xC8-0xCF */ - 0x6DF5,0x6F14,0xF992,0x70DF,0x7136,0x7159,0xF993,0x71C3,/* 0xD0-0xD7 */ - 0x71D5,0xF994,0x784F,0x786F,0xF995,0x7B75,0x7DE3,0xF996,/* 0xD8-0xDF */ - 0x7E2F,0xF997,0x884D,0x8EDF,0xF998,0xF999,0xF99A,0x925B,/* 0xE0-0xE7 */ - 0xF99B,0x9CF6,0xF99C,0xF99D,0xF99E,0x6085,0x6D85,0xF99F,/* 0xE8-0xEF */ - 0x71B1,0xF9A0,0xF9A1,0x95B1,0x53AD,0xF9A2,0xF9A3,0xF9A4,/* 0xF0-0xF7 */ - 0x67D3,0xF9A5,0x708E,0x7130,0x7430,0x8276,0x82D2,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E7[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0xF9A6,0x95BB,0x9AE5,0x9E7D,0x66C4,0xF9A7,0x71C1,/* 0xA0-0xA7 */ - 0x8449,0xF9A8,0xF9A9,0x584B,0xF9AA,0xF9AB,0x5DB8,0x5F71,/* 0xA8-0xAF */ - 0xF9AC,0x6620,0x668E,0x6979,0x69AE,0x6C38,0x6CF3,0x6E36,/* 0xB0-0xB7 */ - 0x6F41,0x6FDA,0x701B,0x702F,0x7150,0x71DF,0x7370,0xF9AD,/* 0xB8-0xBF */ - 0x745B,0xF9AE,0x74D4,0x76C8,0x7A4E,0x7E93,0xF9AF,0xF9B0,/* 0xC0-0xC7 */ - 0x82F1,0x8A60,0x8FCE,0xF9B1,0x9348,0xF9B2,0x9719,0xF9B3,/* 0xC8-0xCF */ - 0xF9B4,0x4E42,0x502A,0xF9B5,0x5208,0x53E1,0x66F3,0x6C6D,/* 0xD0-0xD7 */ - 0x6FCA,0x730A,0x777F,0x7A62,0x82AE,0x85DD,0x8602,0xF9B6,/* 0xD8-0xDF */ - 0x88D4,0x8A63,0x8B7D,0x8C6B,0xF9B7,0x92B3,0xF9B8,0x9713,/* 0xE0-0xE7 */ - 0x9810,0x4E94,0x4F0D,0x4FC9,0x50B2,0x5348,0x543E,0x5433,/* 0xE8-0xEF */ - 0x55DA,0x5862,0x58BA,0x5967,0x5A1B,0x5BE4,0x609F,0xF9B9,/* 0xF0-0xF7 */ - 0x61CA,0x6556,0x65FF,0x6664,0x68A7,0x6C5A,0x6FB3,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E8[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x70CF,0x71AC,0x7352,0x7B7D,0x8708,0x8AA4,0x9C32,/* 0xA0-0xA7 */ - 0x9F07,0x5C4B,0x6C83,0x7344,0x7389,0x923A,0x6EAB,0x7465,/* 0xA8-0xAF */ - 0x761F,0x7A69,0x7E15,0x860A,0x5140,0x58C5,0x64C1,0x74EE,/* 0xB0-0xB7 */ - 0x7515,0x7670,0x7FC1,0x9095,0x96CD,0x9954,0x6E26,0x74E6,/* 0xB8-0xBF */ - 0x7AA9,0x7AAA,0x81E5,0x86D9,0x8778,0x8A1B,0x5A49,0x5B8C,/* 0xC0-0xC7 */ - 0x5B9B,0x68A1,0x6900,0x6D63,0x73A9,0x7413,0x742C,0x7897,/* 0xC8-0xCF */ - 0x7DE9,0x7FEB,0x8118,0x8155,0x839E,0x8C4C,0x962E,0x9811,/* 0xD0-0xD7 */ - 0x66F0,0x5F80,0x65FA,0x6789,0x6C6A,0x738B,0x502D,0x5A03,/* 0xD8-0xDF */ - 0x6B6A,0x77EE,0x5916,0x5D6C,0x5DCD,0x7325,0x754F,0xF9BA,/* 0xE0-0xE7 */ - 0xF9BB,0x50E5,0x51F9,0x582F,0x592D,0x5996,0x59DA,0x5BE5,/* 0xE8-0xEF */ - 0xF9BC,0xF9BD,0x5DA2,0x62D7,0x6416,0x6493,0x64FE,0xF9BE,/* 0xF0-0xF7 */ - 0x66DC,0xF9BF,0x6A48,0xF9C0,0x71FF,0x7464,0xF9C1,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E9[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x7A88,0x7AAF,0x7E47,0x7E5E,0x8000,0x8170,0xF9C2,/* 0xA0-0xA7 */ - 0x87EF,0x8981,0x8B20,0x9059,0xF9C3,0x9080,0x9952,0x617E,/* 0xA8-0xAF */ - 0x6B32,0x6D74,0x7E1F,0x8925,0x8FB1,0x4FD1,0x50AD,0x5197,/* 0xB0-0xB7 */ - 0x52C7,0x57C7,0x5889,0x5BB9,0x5EB8,0x6142,0x6995,0x6D8C,/* 0xB8-0xBF */ - 0x6E67,0x6EB6,0x7194,0x7462,0x7528,0x752C,0x8073,0x8338,/* 0xC0-0xC7 */ - 0x84C9,0x8E0A,0x9394,0x93DE,0xF9C4,0x4E8E,0x4F51,0x5076,/* 0xC8-0xCF */ - 0x512A,0x53C8,0x53CB,0x53F3,0x5B87,0x5BD3,0x5C24,0x611A,/* 0xD0-0xD7 */ - 0x6182,0x65F4,0x725B,0x7397,0x7440,0x76C2,0x7950,0x7991,/* 0xD8-0xDF */ - 0x79B9,0x7D06,0x7FBD,0x828B,0x85D5,0x865E,0x8FC2,0x9047,/* 0xE0-0xE7 */ - 0x90F5,0x91EA,0x9685,0x96E8,0x96E9,0x52D6,0x5F67,0x65ED,/* 0xE8-0xEF */ - 0x6631,0x682F,0x715C,0x7A36,0x90C1,0x980A,0x4E91,0xF9C5,/* 0xF0-0xF7 */ - 0x6A52,0x6B9E,0x6F90,0x7189,0x8018,0x82B8,0x8553,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_EA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x904B,0x9695,0x96F2,0x97FB,0x851A,0x9B31,0x4E90,/* 0xA0-0xA7 */ - 0x718A,0x96C4,0x5143,0x539F,0x54E1,0x5713,0x5712,0x57A3,/* 0xA8-0xAF */ - 0x5A9B,0x5AC4,0x5BC3,0x6028,0x613F,0x63F4,0x6C85,0x6D39,/* 0xB0-0xB7 */ - 0x6E72,0x6E90,0x7230,0x733F,0x7457,0x82D1,0x8881,0x8F45,/* 0xB8-0xBF */ - 0x9060,0xF9C6,0x9662,0x9858,0x9D1B,0x6708,0x8D8A,0x925E,/* 0xC0-0xC7 */ - 0x4F4D,0x5049,0x50DE,0x5371,0x570D,0x59D4,0x5A01,0x5C09,/* 0xC8-0xCF */ - 0x6170,0x6690,0x6E2D,0x7232,0x744B,0x7DEF,0x80C3,0x840E,/* 0xD0-0xD7 */ - 0x8466,0x853F,0x875F,0x885B,0x8918,0x8B02,0x9055,0x97CB,/* 0xD8-0xDF */ - 0x9B4F,0x4E73,0x4F91,0x5112,0x516A,0xF9C7,0x552F,0x55A9,/* 0xE0-0xE7 */ - 0x5B7A,0x5BA5,0x5E7C,0x5E7D,0x5EBE,0x60A0,0x60DF,0x6108,/* 0xE8-0xEF */ - 0x6109,0x63C4,0x6538,0x6709,0xF9C8,0x67D4,0x67DA,0xF9C9,/* 0xF0-0xF7 */ - 0x6961,0x6962,0x6CB9,0x6D27,0xF9CA,0x6E38,0xF9CB,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_EB[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x6FE1,0x7336,0x7337,0xF9CC,0x745C,0x7531,0xF9CD,/* 0xA0-0xA7 */ - 0x7652,0xF9CE,0xF9CF,0x7DAD,0x81FE,0x8438,0x88D5,0x8A98,/* 0xA8-0xAF */ - 0x8ADB,0x8AED,0x8E30,0x8E42,0x904A,0x903E,0x907A,0x9149,/* 0xB0-0xB7 */ - 0x91C9,0x936E,0xF9D0,0xF9D1,0x5809,0xF9D2,0x6BD3,0x8089,/* 0xB8-0xBF */ - 0x80B2,0xF9D3,0xF9D4,0x5141,0x596B,0x5C39,0xF9D5,0xF9D6,/* 0xC0-0xC7 */ - 0x6F64,0x73A7,0x80E4,0x8D07,0xF9D7,0x9217,0x958F,0xF9D8,/* 0xC8-0xCF */ - 0xF9D9,0xF9DA,0xF9DB,0x807F,0x620E,0x701C,0x7D68,0x878D,/* 0xD0-0xD7 */ - 0xF9DC,0x57A0,0x6069,0x6147,0x6BB7,0x8ABE,0x9280,0x96B1,/* 0xD8-0xDF */ - 0x4E59,0x541F,0x6DEB,0x852D,0x9670,0x97F3,0x98EE,0x63D6,/* 0xE0-0xE7 */ - 0x6CE3,0x9091,0x51DD,0x61C9,0x81BA,0x9DF9,0x4F9D,0x501A,/* 0xE8-0xEF */ - 0x5100,0x5B9C,0x610F,0x61FF,0x64EC,0x6905,0x6BC5,0x7591,/* 0xF0-0xF7 */ - 0x77E3,0x7FA9,0x8264,0x858F,0x87FB,0x8863,0x8ABC,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_EC[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x8B70,0x91AB,0x4E8C,0x4EE5,0x4F0A,0xF9DD,0xF9DE,/* 0xA0-0xA7 */ - 0x5937,0x59E8,0xF9DF,0x5DF2,0x5F1B,0x5F5B,0x6021,0xF9E0,/* 0xA8-0xAF */ - 0xF9E1,0xF9E2,0xF9E3,0x723E,0x73E5,0xF9E4,0x7570,0x75CD,/* 0xB0-0xB7 */ - 0xF9E5,0x79FB,0xF9E6,0x800C,0x8033,0x8084,0x82E1,0x8351,/* 0xB8-0xBF */ - 0xF9E7,0xF9E8,0x8CBD,0x8CB3,0x9087,0xF9E9,0xF9EA,0x98F4,/* 0xC0-0xC7 */ - 0x990C,0xF9EB,0xF9EC,0x7037,0x76CA,0x7FCA,0x7FCC,0x7FFC,/* 0xC8-0xCF */ - 0x8B1A,0x4EBA,0x4EC1,0x5203,0x5370,0xF9ED,0x54BD,0x56E0,/* 0xD0-0xD7 */ - 0x59FB,0x5BC5,0x5F15,0x5FCD,0x6E6E,0xF9EE,0xF9EF,0x7D6A,/* 0xD8-0xDF */ - 0x8335,0xF9F0,0x8693,0x8A8D,0xF9F1,0x976D,0x9777,0xF9F2,/* 0xE0-0xE7 */ - 0xF9F3,0x4E00,0x4F5A,0x4F7E,0x58F9,0x65E5,0x6EA2,0x9038,/* 0xE8-0xEF */ - 0x93B0,0x99B9,0x4EFB,0x58EC,0x598A,0x59D9,0x6041,0xF9F4,/* 0xF0-0xF7 */ - 0xF9F5,0x7A14,0xF9F6,0x834F,0x8CC3,0x5165,0x5344,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_ED[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0xF9F7,0xF9F8,0xF9F9,0x4ECD,0x5269,0x5B55,0x82BF,/* 0xA0-0xA7 */ - 0x4ED4,0x523A,0x54A8,0x59C9,0x59FF,0x5B50,0x5B57,0x5B5C,/* 0xA8-0xAF */ - 0x6063,0x6148,0x6ECB,0x7099,0x716E,0x7386,0x74F7,0x75B5,/* 0xB0-0xB7 */ - 0x78C1,0x7D2B,0x8005,0x81EA,0x8328,0x8517,0x85C9,0x8AEE,/* 0xB8-0xBF */ - 0x8CC7,0x96CC,0x4F5C,0x52FA,0x56BC,0x65AB,0x6628,0x707C,/* 0xC0-0xC7 */ - 0x70B8,0x7235,0x7DBD,0x828D,0x914C,0x96C0,0x9D72,0x5B71,/* 0xC8-0xCF */ - 0x68E7,0x6B98,0x6F7A,0x76DE,0x5C91,0x66AB,0x6F5B,0x7BB4,/* 0xD0-0xD7 */ - 0x7C2A,0x8836,0x96DC,0x4E08,0x4ED7,0x5320,0x5834,0x58BB,/* 0xD8-0xDF */ - 0x58EF,0x596C,0x5C07,0x5E33,0x5E84,0x5F35,0x638C,0x66B2,/* 0xE0-0xE7 */ - 0x6756,0x6A1F,0x6AA3,0x6B0C,0x6F3F,0x7246,0xF9FA,0x7350,/* 0xE8-0xEF */ - 0x748B,0x7AE0,0x7CA7,0x8178,0x81DF,0x81E7,0x838A,0x846C,/* 0xF0-0xF7 */ - 0x8523,0x8594,0x85CF,0x88DD,0x8D13,0x91AC,0x9577,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_EE[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x969C,0x518D,0x54C9,0x5728,0x5BB0,0x624D,0x6750,/* 0xA0-0xA7 */ - 0x683D,0x6893,0x6E3D,0x6ED3,0x707D,0x7E21,0x88C1,0x8CA1,/* 0xA8-0xAF */ - 0x8F09,0x9F4B,0x9F4E,0x722D,0x7B8F,0x8ACD,0x931A,0x4F47,/* 0xB0-0xB7 */ - 0x4F4E,0x5132,0x5480,0x59D0,0x5E95,0x62B5,0x6775,0x696E,/* 0xB8-0xBF */ - 0x6A17,0x6CAE,0x6E1A,0x72D9,0x732A,0x75BD,0x7BB8,0x7D35,/* 0xC0-0xC7 */ - 0x82E7,0x83F9,0x8457,0x85F7,0x8A5B,0x8CAF,0x8E87,0x9019,/* 0xC8-0xCF */ - 0x90B8,0x96CE,0x9F5F,0x52E3,0x540A,0x5AE1,0x5BC2,0x6458,/* 0xD0-0xD7 */ - 0x6575,0x6EF4,0x72C4,0xF9FB,0x7684,0x7A4D,0x7B1B,0x7C4D,/* 0xD8-0xDF */ - 0x7E3E,0x7FDF,0x837B,0x8B2B,0x8CCA,0x8D64,0x8DE1,0x8E5F,/* 0xE0-0xE7 */ - 0x8FEA,0x8FF9,0x9069,0x93D1,0x4F43,0x4F7A,0x50B3,0x5168,/* 0xE8-0xEF */ - 0x5178,0x524D,0x526A,0x5861,0x587C,0x5960,0x5C08,0x5C55,/* 0xF0-0xF7 */ - 0x5EDB,0x609B,0x6230,0x6813,0x6BBF,0x6C08,0x6FB1,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_EF[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x714E,0x7420,0x7530,0x7538,0x7551,0x7672,0x7B4C,/* 0xA0-0xA7 */ - 0x7B8B,0x7BAD,0x7BC6,0x7E8F,0x8A6E,0x8F3E,0x8F49,0x923F,/* 0xA8-0xAF */ - 0x9293,0x9322,0x942B,0x96FB,0x985A,0x986B,0x991E,0x5207,/* 0xB0-0xB7 */ - 0x622A,0x6298,0x6D59,0x7664,0x7ACA,0x7BC0,0x7D76,0x5360,/* 0xB8-0xBF */ - 0x5CBE,0x5E97,0x6F38,0x70B9,0x7C98,0x9711,0x9B8E,0x9EDE,/* 0xC0-0xC7 */ - 0x63A5,0x647A,0x8776,0x4E01,0x4E95,0x4EAD,0x505C,0x5075,/* 0xC8-0xCF */ - 0x5448,0x59C3,0x5B9A,0x5E40,0x5EAD,0x5EF7,0x5F81,0x60C5,/* 0xD0-0xD7 */ - 0x633A,0x653F,0x6574,0x65CC,0x6676,0x6678,0x67FE,0x6968,/* 0xD8-0xDF */ - 0x6A89,0x6B63,0x6C40,0x6DC0,0x6DE8,0x6E1F,0x6E5E,0x701E,/* 0xE0-0xE7 */ - 0x70A1,0x738E,0x73FD,0x753A,0x775B,0x7887,0x798E,0x7A0B,/* 0xE8-0xEF */ - 0x7A7D,0x7CBE,0x7D8E,0x8247,0x8A02,0x8AEA,0x8C9E,0x912D,/* 0xF0-0xF7 */ - 0x914A,0x91D8,0x9266,0x92CC,0x9320,0x9706,0x9756,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F0[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x975C,0x9802,0x9F0E,0x5236,0x5291,0x557C,0x5824,/* 0xA0-0xA7 */ - 0x5E1D,0x5F1F,0x608C,0x63D0,0x68AF,0x6FDF,0x796D,0x7B2C,/* 0xA8-0xAF */ - 0x81CD,0x85BA,0x88FD,0x8AF8,0x8E44,0x918D,0x9664,0x969B,/* 0xB0-0xB7 */ - 0x973D,0x984C,0x9F4A,0x4FCE,0x5146,0x51CB,0x52A9,0x5632,/* 0xB8-0xBF */ - 0x5F14,0x5F6B,0x63AA,0x64CD,0x65E9,0x6641,0x66FA,0x66F9,/* 0xC0-0xC7 */ - 0x671D,0x689D,0x68D7,0x69FD,0x6F15,0x6F6E,0x7167,0x71E5,/* 0xC8-0xCF */ - 0x722A,0x74AA,0x773A,0x7956,0x795A,0x79DF,0x7A20,0x7A95,/* 0xD0-0xD7 */ - 0x7C97,0x7CDF,0x7D44,0x7E70,0x8087,0x85FB,0x86A4,0x8A54,/* 0xD8-0xDF */ - 0x8ABF,0x8D99,0x8E81,0x9020,0x906D,0x91E3,0x963B,0x96D5,/* 0xE0-0xE7 */ - 0x9CE5,0x65CF,0x7C07,0x8DB3,0x93C3,0x5B58,0x5C0A,0x5352,/* 0xE8-0xEF */ - 0x62D9,0x731D,0x5027,0x5B97,0x5F9E,0x60B0,0x616B,0x68D5,/* 0xF0-0xF7 */ - 0x6DD9,0x742E,0x7A2E,0x7D42,0x7D9C,0x7E31,0x816B,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x8E2A,0x8E35,0x937E,0x9418,0x4F50,0x5750,0x5DE6,/* 0xA0-0xA7 */ - 0x5EA7,0x632B,0x7F6A,0x4E3B,0x4F4F,0x4F8F,0x505A,0x59DD,/* 0xA8-0xAF */ - 0x80C4,0x546A,0x5468,0x55FE,0x594F,0x5B99,0x5DDE,0x5EDA,/* 0xB0-0xB7 */ - 0x665D,0x6731,0x67F1,0x682A,0x6CE8,0x6D32,0x6E4A,0x6F8D,/* 0xB8-0xBF */ - 0x70B7,0x73E0,0x7587,0x7C4C,0x7D02,0x7D2C,0x7DA2,0x821F,/* 0xC0-0xC7 */ - 0x86DB,0x8A3B,0x8A85,0x8D70,0x8E8A,0x8F33,0x9031,0x914E,/* 0xC8-0xCF */ - 0x9152,0x9444,0x99D0,0x7AF9,0x7CA5,0x4FCA,0x5101,0x51C6,/* 0xD0-0xD7 */ - 0x57C8,0x5BEF,0x5CFB,0x6659,0x6A3D,0x6D5A,0x6E96,0x6FEC,/* 0xD8-0xDF */ - 0x710C,0x756F,0x7AE3,0x8822,0x9021,0x9075,0x96CB,0x99FF,/* 0xE0-0xE7 */ - 0x8301,0x4E2D,0x4EF2,0x8846,0x91CD,0x537D,0x6ADB,0x696B,/* 0xE8-0xEF */ - 0x6C41,0x847A,0x589E,0x618E,0x66FE,0x62EF,0x70DD,0x7511,/* 0xF0-0xF7 */ - 0x75C7,0x7E52,0x84B8,0x8B49,0x8D08,0x4E4B,0x53EA,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x54AB,0x5730,0x5740,0x5FD7,0x6301,0x6307,0x646F,/* 0xA0-0xA7 */ - 0x652F,0x65E8,0x667A,0x679D,0x67B3,0x6B62,0x6C60,0x6C9A,/* 0xA8-0xAF */ - 0x6F2C,0x77E5,0x7825,0x7949,0x7957,0x7D19,0x80A2,0x8102,/* 0xB0-0xB7 */ - 0x81F3,0x829D,0x82B7,0x8718,0x8A8C,0xF9FC,0x8D04,0x8DBE,/* 0xB8-0xBF */ - 0x9072,0x76F4,0x7A19,0x7A37,0x7E54,0x8077,0x5507,0x55D4,/* 0xC0-0xC7 */ - 0x5875,0x632F,0x6422,0x6649,0x664B,0x686D,0x699B,0x6B84,/* 0xC8-0xCF */ - 0x6D25,0x6EB1,0x73CD,0x7468,0x74A1,0x755B,0x75B9,0x76E1,/* 0xD0-0xD7 */ - 0x771E,0x778B,0x79E6,0x7E09,0x7E1D,0x81FB,0x852F,0x8897,/* 0xD8-0xDF */ - 0x8A3A,0x8CD1,0x8EEB,0x8FB0,0x9032,0x93AD,0x9663,0x9673,/* 0xE0-0xE7 */ - 0x9707,0x4F84,0x53F1,0x59EA,0x5AC9,0x5E19,0x684E,0x74C6,/* 0xE8-0xEF */ - 0x75BE,0x79E9,0x7A92,0x81A3,0x86ED,0x8CEA,0x8DCC,0x8FED,/* 0xF0-0xF7 */ - 0x659F,0x6715,0xF9FD,0x57F7,0x6F57,0x7DDD,0x8F2F,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x93F6,0x96C6,0x5FB5,0x61F2,0x6F84,0x4E14,0x4F98,/* 0xA0-0xA7 */ - 0x501F,0x53C9,0x55DF,0x5D6F,0x5DEE,0x6B21,0x6B64,0x78CB,/* 0xA8-0xAF */ - 0x7B9A,0xF9FE,0x8E49,0x8ECA,0x906E,0x6349,0x643E,0x7740,/* 0xB0-0xB7 */ - 0x7A84,0x932F,0x947F,0x9F6A,0x64B0,0x6FAF,0x71E6,0x74A8,/* 0xB8-0xBF */ - 0x74DA,0x7AC4,0x7C12,0x7E82,0x7CB2,0x7E98,0x8B9A,0x8D0A,/* 0xC0-0xC7 */ - 0x947D,0x9910,0x994C,0x5239,0x5BDF,0x64E6,0x672D,0x7D2E,/* 0xC8-0xCF */ - 0x50ED,0x53C3,0x5879,0x6158,0x6159,0x61FA,0x65AC,0x7AD9,/* 0xD0-0xD7 */ - 0x8B92,0x8B96,0x5009,0x5021,0x5275,0x5531,0x5A3C,0x5EE0,/* 0xD8-0xDF */ - 0x5F70,0x6134,0x655E,0x660C,0x6636,0x66A2,0x69CD,0x6EC4,/* 0xE0-0xE7 */ - 0x6F32,0x7316,0x7621,0x7A93,0x8139,0x8259,0x83D6,0x84BC,/* 0xE8-0xEF */ - 0x50B5,0x57F0,0x5BC0,0x5BE8,0x5F69,0x63A1,0x7826,0x7DB5,/* 0xF0-0xF7 */ - 0x83DC,0x8521,0x91C7,0x91F5,0x518A,0x67F5,0x7B56,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x8CAC,0x51C4,0x59BB,0x60BD,0x8655,0x501C,0xF9FF,/* 0xA0-0xA7 */ - 0x5254,0x5C3A,0x617D,0x621A,0x62D3,0x64F2,0x65A5,0x6ECC,/* 0xA8-0xAF */ - 0x7620,0x810A,0x8E60,0x965F,0x96BB,0x4EDF,0x5343,0x5598,/* 0xB0-0xB7 */ - 0x5929,0x5DDD,0x64C5,0x6CC9,0x6DFA,0x7394,0x7A7F,0x821B,/* 0xB8-0xBF */ - 0x85A6,0x8CE4,0x8E10,0x9077,0x91E7,0x95E1,0x9621,0x97C6,/* 0xC0-0xC7 */ - 0x51F8,0x54F2,0x5586,0x5FB9,0x64A4,0x6F88,0x7DB4,0x8F1F,/* 0xC8-0xCF */ - 0x8F4D,0x9435,0x50C9,0x5C16,0x6CBE,0x6DFB,0x751B,0x77BB,/* 0xD0-0xD7 */ - 0x7C3D,0x7C64,0x8A79,0x8AC2,0x581E,0x59BE,0x5E16,0x6377,/* 0xD8-0xDF */ - 0x7252,0x758A,0x776B,0x8ADC,0x8CBC,0x8F12,0x5EF3,0x6674,/* 0xE0-0xE7 */ - 0x6DF8,0x807D,0x83C1,0x8ACB,0x9751,0x9BD6,0xFA00,0x5243,/* 0xE8-0xEF */ - 0x66FF,0x6D95,0x6EEF,0x7DE0,0x8AE6,0x902E,0x905E,0x9AD4,/* 0xF0-0xF7 */ - 0x521D,0x527F,0x54E8,0x6194,0x6284,0x62DB,0x68A2,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x6912,0x695A,0x6A35,0x7092,0x7126,0x785D,0x7901,/* 0xA0-0xA7 */ - 0x790E,0x79D2,0x7A0D,0x8096,0x8278,0x82D5,0x8349,0x8549,/* 0xA8-0xAF */ - 0x8C82,0x8D85,0x9162,0x918B,0x91AE,0x4FC3,0x56D1,0x71ED,/* 0xB0-0xB7 */ - 0x77D7,0x8700,0x89F8,0x5BF8,0x5FD6,0x6751,0x90A8,0x53E2,/* 0xB8-0xBF */ - 0x585A,0x5BF5,0x60A4,0x6181,0x6460,0x7E3D,0x8070,0x8525,/* 0xC0-0xC7 */ - 0x9283,0x64AE,0x50AC,0x5D14,0x6700,0x589C,0x62BD,0x63A8,/* 0xC8-0xCF */ - 0x690E,0x6978,0x6A1E,0x6E6B,0x76BA,0x79CB,0x82BB,0x8429,/* 0xD0-0xD7 */ - 0x8ACF,0x8DA8,0x8FFD,0x9112,0x914B,0x919C,0x9310,0x9318,/* 0xD8-0xDF */ - 0x939A,0x96DB,0x9A36,0x9C0D,0x4E11,0x755C,0x795D,0x7AFA,/* 0xE0-0xE7 */ - 0x7B51,0x7BC9,0x7E2E,0x84C4,0x8E59,0x8E74,0x8EF8,0x9010,/* 0xE8-0xEF */ - 0x6625,0x693F,0x7443,0x51FA,0x672E,0x9EDC,0x5145,0x5FE0,/* 0xF0-0xF7 */ - 0x6C96,0x87F2,0x885D,0x8877,0x60B4,0x81B5,0x8403,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x8D05,0x53D6,0x5439,0x5634,0x5A36,0x5C31,0x708A,/* 0xA0-0xA7 */ - 0x7FE0,0x805A,0x8106,0x81ED,0x8DA3,0x9189,0x9A5F,0x9DF2,/* 0xA8-0xAF */ - 0x5074,0x4EC4,0x53A0,0x60FB,0x6E2C,0x5C64,0x4F88,0x5024,/* 0xB0-0xB7 */ - 0x55E4,0x5CD9,0x5E5F,0x6065,0x6894,0x6CBB,0x6DC4,0x71BE,/* 0xB8-0xBF */ - 0x75D4,0x75F4,0x7661,0x7A1A,0x7A49,0x7DC7,0x7DFB,0x7F6E,/* 0xC0-0xC7 */ - 0x81F4,0x86A9,0x8F1C,0x96C9,0x99B3,0x9F52,0x5247,0x52C5,/* 0xC8-0xCF */ - 0x98ED,0x89AA,0x4E03,0x67D2,0x6F06,0x4FB5,0x5BE2,0x6795,/* 0xD0-0xD7 */ - 0x6C88,0x6D78,0x741B,0x7827,0x91DD,0x937C,0x87C4,0x79E4,/* 0xD8-0xDF */ - 0x7A31,0x5FEB,0x4ED6,0x54A4,0x553E,0x58AE,0x59A5,0x60F0,/* 0xE0-0xE7 */ - 0x6253,0x62D6,0x6736,0x6955,0x8235,0x9640,0x99B1,0x99DD,/* 0xE8-0xEF */ - 0x502C,0x5353,0x5544,0x577C,0xFA01,0x6258,0xFA02,0x64E2,/* 0xF0-0xF7 */ - 0x666B,0x67DD,0x6FC1,0x6FEF,0x7422,0x7438,0x8A17,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F7[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x9438,0x5451,0x5606,0x5766,0x5F48,0x619A,0x6B4E,/* 0xA0-0xA7 */ - 0x7058,0x70AD,0x7DBB,0x8A95,0x596A,0x812B,0x63A2,0x7708,/* 0xA8-0xAF */ - 0x803D,0x8CAA,0x5854,0x642D,0x69BB,0x5B95,0x5E11,0x6E6F,/* 0xB0-0xB7 */ - 0xFA03,0x8569,0x514C,0x53F0,0x592A,0x6020,0x614B,0x6B86,/* 0xB8-0xBF */ - 0x6C70,0x6CF0,0x7B1E,0x80CE,0x82D4,0x8DC6,0x90B0,0x98B1,/* 0xC0-0xC7 */ - 0xFA04,0x64C7,0x6FA4,0x6491,0x6504,0x514E,0x5410,0x571F,/* 0xC8-0xCF */ - 0x8A0E,0x615F,0x6876,0xFA05,0x75DB,0x7B52,0x7D71,0x901A,/* 0xD0-0xD7 */ - 0x5806,0x69CC,0x817F,0x892A,0x9000,0x9839,0x5078,0x5957,/* 0xD8-0xDF */ - 0x59AC,0x6295,0x900F,0x9B2A,0x615D,0x7279,0x95D6,0x5761,/* 0xE0-0xE7 */ - 0x5A46,0x5DF4,0x628A,0x64AD,0x64FA,0x6777,0x6CE2,0x6D3E,/* 0xE8-0xEF */ - 0x722C,0x7436,0x7834,0x7F77,0x82AD,0x8DDB,0x9817,0x5224,/* 0xF0-0xF7 */ - 0x5742,0x677F,0x7248,0x74E3,0x8CA9,0x8FA6,0x9211,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F8[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x962A,0x516B,0x53ED,0x634C,0x4F69,0x5504,0x6096,/* 0xA0-0xA7 */ - 0x6557,0x6C9B,0x6D7F,0x724C,0x72FD,0x7A17,0x8987,0x8C9D,/* 0xA8-0xAF */ - 0x5F6D,0x6F8E,0x70F9,0x81A8,0x610E,0x4FBF,0x504F,0x6241,/* 0xB0-0xB7 */ - 0x7247,0x7BC7,0x7DE8,0x7FE9,0x904D,0x97AD,0x9A19,0x8CB6,/* 0xB8-0xBF */ - 0x576A,0x5E73,0x67B0,0x840D,0x8A55,0x5420,0x5B16,0x5E63,/* 0xC0-0xC7 */ - 0x5EE2,0x5F0A,0x6583,0x80BA,0x853D,0x9589,0x965B,0x4F48,/* 0xC8-0xCF */ - 0x5305,0x530D,0x530F,0x5486,0x54FA,0x5703,0x5E03,0x6016,/* 0xD0-0xD7 */ - 0x629B,0x62B1,0x6355,0xFA06,0x6CE1,0x6D66,0x75B1,0x7832,/* 0xD8-0xDF */ - 0x80DE,0x812F,0x82DE,0x8461,0x84B2,0x888D,0x8912,0x900B,/* 0xE0-0xE7 */ - 0x92EA,0x98FD,0x9B91,0x5E45,0x66B4,0x66DD,0x7011,0x7206,/* 0xE8-0xEF */ - 0xFA07,0x4FF5,0x527D,0x5F6A,0x6153,0x6753,0x6A19,0x6F02,/* 0xF0-0xF7 */ - 0x74E2,0x7968,0x8868,0x8C79,0x98C7,0x98C4,0x9A43,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F9[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x54C1,0x7A1F,0x6953,0x8AF7,0x8C4A,0x98A8,0x99AE,/* 0xA0-0xA7 */ - 0x5F7C,0x62AB,0x75B2,0x76AE,0x88AB,0x907F,0x9642,0x5339,/* 0xA8-0xAF */ - 0x5F3C,0x5FC5,0x6CCC,0x73CC,0x7562,0x758B,0x7B46,0x82FE,/* 0xB0-0xB7 */ - 0x999D,0x4E4F,0x903C,0x4E0B,0x4F55,0x53A6,0x590F,0x5EC8,/* 0xB8-0xBF */ - 0x6630,0x6CB3,0x7455,0x8377,0x8766,0x8CC0,0x9050,0x971E,/* 0xC0-0xC7 */ - 0x9C15,0x58D1,0x5B78,0x8650,0x8B14,0x9DB4,0x5BD2,0x6068,/* 0xC8-0xCF */ - 0x608D,0x65F1,0x6C57,0x6F22,0x6FA3,0x701A,0x7F55,0x7FF0,/* 0xD0-0xD7 */ - 0x9591,0x9592,0x9650,0x97D3,0x5272,0x8F44,0x51FD,0x542B,/* 0xD8-0xDF */ - 0x54B8,0x5563,0x558A,0x6ABB,0x6DB5,0x7DD8,0x8266,0x929C,/* 0xE0-0xE7 */ - 0x9677,0x9E79,0x5408,0x54C8,0x76D2,0x86E4,0x95A4,0x95D4,/* 0xE8-0xEF */ - 0x965C,0x4EA2,0x4F09,0x59EE,0x5AE6,0x5DF7,0x6052,0x6297,/* 0xF0-0xF7 */ - 0x676D,0x6841,0x6C86,0x6E2F,0x7F38,0x809B,0x822A,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_FA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0xFA08,0xFA09,0x9805,0x4EA5,0x5055,0x54B3,0x5793,/* 0xA0-0xA7 */ - 0x595A,0x5B69,0x5BB3,0x61C8,0x6977,0x6D77,0x7023,0x87F9,/* 0xA8-0xAF */ - 0x89E3,0x8A72,0x8AE7,0x9082,0x99ED,0x9AB8,0x52BE,0x6838,/* 0xB0-0xB7 */ - 0x5016,0x5E78,0x674F,0x8347,0x884C,0x4EAB,0x5411,0x56AE,/* 0xB8-0xBF */ - 0x73E6,0x9115,0x97FF,0x9909,0x9957,0x9999,0x5653,0x589F,/* 0xC0-0xC7 */ - 0x865B,0x8A31,0x61B2,0x6AF6,0x737B,0x8ED2,0x6B47,0x96AA,/* 0xC8-0xCF */ - 0x9A57,0x5955,0x7200,0x8D6B,0x9769,0x4FD4,0x5CF4,0x5F26,/* 0xD0-0xD7 */ - 0x61F8,0x665B,0x6CEB,0x70AB,0x7384,0x73B9,0x73FE,0x7729,/* 0xD8-0xDF */ - 0x774D,0x7D43,0x7D62,0x7E23,0x8237,0x8852,0xFA0A,0x8CE2,/* 0xE0-0xE7 */ - 0x9249,0x986F,0x5B51,0x7A74,0x8840,0x9801,0x5ACC,0x4FE0,/* 0xE8-0xEF */ - 0x5354,0x593E,0x5CFD,0x633E,0x6D79,0x72F9,0x8105,0x8107,/* 0xF0-0xF7 */ - 0x83A2,0x92CF,0x9830,0x4EA8,0x5144,0x5211,0x578B,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_FB[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x5F62,0x6CC2,0x6ECE,0x7005,0x7050,0x70AF,0x7192,/* 0xA0-0xA7 */ - 0x73E9,0x7469,0x834A,0x87A2,0x8861,0x9008,0x90A2,0x93A3,/* 0xA8-0xAF */ - 0x99A8,0x516E,0x5F57,0x60E0,0x6167,0x66B3,0x8559,0x8E4A,/* 0xB0-0xB7 */ - 0x91AF,0x978B,0x4E4E,0x4E92,0x547C,0x58D5,0x58FA,0x597D,/* 0xB8-0xBF */ - 0x5CB5,0x5F27,0x6236,0x6248,0x660A,0x6667,0x6BEB,0x6D69,/* 0xC0-0xC7 */ - 0x6DCF,0x6E56,0x6EF8,0x6F94,0x6FE0,0x6FE9,0x705D,0x72D0,/* 0xC8-0xCF */ - 0x7425,0x745A,0x74E0,0x7693,0x795C,0x7CCA,0x7E1E,0x80E1,/* 0xD0-0xD7 */ - 0x82A6,0x846B,0x84BF,0x864E,0x865F,0x8774,0x8B77,0x8C6A,/* 0xD8-0xDF */ - 0x93AC,0x9800,0x9865,0x60D1,0x6216,0x9177,0x5A5A,0x660F,/* 0xE0-0xE7 */ - 0x6DF7,0x6E3E,0x743F,0x9B42,0x5FFD,0x60DA,0x7B0F,0x54C4,/* 0xE8-0xEF */ - 0x5F18,0x6C5E,0x6CD3,0x6D2A,0x70D8,0x7D05,0x8679,0x8A0C,/* 0xF0-0xF7 */ - 0x9D3B,0x5316,0x548C,0x5B05,0x6A3A,0x706B,0x7575,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_FC[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x798D,0x79BE,0x82B1,0x83EF,0x8A71,0x8B41,0x8CA8,/* 0xA0-0xA7 */ - 0x9774,0xFA0B,0x64F4,0x652B,0x78BA,0x78BB,0x7A6B,0x4E38,/* 0xA8-0xAF */ - 0x559A,0x5950,0x5BA6,0x5E7B,0x60A3,0x63DB,0x6B61,0x6665,/* 0xB0-0xB7 */ - 0x6853,0x6E19,0x7165,0x74B0,0x7D08,0x9084,0x9A69,0x9C25,/* 0xB8-0xBF */ - 0x6D3B,0x6ED1,0x733E,0x8C41,0x95CA,0x51F0,0x5E4C,0x5FA8,/* 0xC0-0xC7 */ - 0x604D,0x60F6,0x6130,0x614C,0x6643,0x6644,0x69A5,0x6CC1,/* 0xC8-0xCF */ - 0x6E5F,0x6EC9,0x6F62,0x714C,0x749C,0x7687,0x7BC1,0x7C27,/* 0xD0-0xD7 */ - 0x8352,0x8757,0x9051,0x968D,0x9EC3,0x532F,0x56DE,0x5EFB,/* 0xD8-0xDF */ - 0x5F8A,0x6062,0x6094,0x61F7,0x6666,0x6703,0x6A9C,0x6DEE,/* 0xE0-0xE7 */ - 0x6FAE,0x7070,0x736A,0x7E6A,0x81BE,0x8334,0x86D4,0x8AA8,/* 0xE8-0xEF */ - 0x8CC4,0x5283,0x7372,0x5B96,0x6A6B,0x9404,0x54EE,0x5686,/* 0xF0-0xF7 */ - 0x5B5D,0x6548,0x6585,0x66C9,0x689F,0x6D8D,0x6DC6,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_FD[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x40-0x47 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x48-0x4F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x50-0x57 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x58-0x5F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x60-0x67 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x68-0x6F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x70-0x77 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x723B,0x80B4,0x9175,0x9A4D,0x4FAF,0x5019,0x539A,/* 0xA0-0xA7 */ - 0x540E,0x543C,0x5589,0x55C5,0x5E3F,0x5F8C,0x673D,0x7166,/* 0xA8-0xAF */ - 0x73DD,0x9005,0x52DB,0x52F3,0x5864,0x58CE,0x7104,0x718F,/* 0xB0-0xB7 */ - 0x71FB,0x85B0,0x8A13,0x6688,0x85A8,0x55A7,0x6684,0x714A,/* 0xB8-0xBF */ - 0x8431,0x5349,0x5599,0x6BC1,0x5F59,0x5FBD,0x63EE,0x6689,/* 0xC0-0xC7 */ - 0x7147,0x8AF1,0x8F1D,0x9EBE,0x4F11,0x643A,0x70CB,0x7566,/* 0xC8-0xCF */ - 0x8667,0x6064,0x8B4E,0x9DF8,0x5147,0x51F6,0x5308,0x6D36,/* 0xD0-0xD7 */ - 0x80F8,0x9ED1,0x6615,0x6B23,0x7098,0x75D5,0x5403,0x5C79,/* 0xD8-0xDF */ - 0x7D07,0x8A16,0x6B20,0x6B3D,0x6B46,0x5438,0x6070,0x6D3D,/* 0xE0-0xE7 */ - 0x7FD5,0x8208,0x50D6,0x51DE,0x559C,0x566B,0x56CD,0x59EC,/* 0xE8-0xEF */ - 0x5B09,0x5E0C,0x6199,0x6198,0x6231,0x665E,0x66E6,0x7199,/* 0xF0-0xF7 */ - 0x71B9,0x71BA,0x72A7,0x79A7,0x7A00,0x7FB2,0x8A70,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t *page_charset2uni[256] = { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, c2u_81, c2u_82, c2u_83, c2u_84, c2u_85, c2u_86, c2u_87, - c2u_88, c2u_89, c2u_8A, c2u_8B, c2u_8C, c2u_8D, c2u_8E, c2u_8F, - c2u_90, c2u_91, c2u_92, c2u_93, c2u_94, c2u_95, c2u_96, c2u_97, - c2u_98, c2u_99, c2u_9A, c2u_9B, c2u_9C, c2u_9D, c2u_9E, c2u_9F, - c2u_A0, c2u_A1, c2u_A2, c2u_A3, c2u_A4, c2u_A5, c2u_A6, c2u_A7, - c2u_A8, c2u_A9, c2u_AA, c2u_AB, c2u_AC, c2u_AD, c2u_AE, c2u_AF, - c2u_B0, c2u_B1, c2u_B2, c2u_B3, c2u_B4, c2u_B5, c2u_B6, c2u_B7, - c2u_B8, c2u_B9, c2u_BA, c2u_BB, c2u_BC, c2u_BD, c2u_BE, c2u_BF, - c2u_C0, c2u_C1, c2u_C2, c2u_C3, c2u_C4, c2u_C5, c2u_C6, c2u_C7, - c2u_C8, NULL, c2u_CA, c2u_CB, c2u_CC, c2u_CD, c2u_CE, c2u_CF, - c2u_D0, c2u_D1, c2u_D2, c2u_D3, c2u_D4, c2u_D5, c2u_D6, c2u_D7, - c2u_D8, c2u_D9, c2u_DA, c2u_DB, c2u_DC, c2u_DD, c2u_DE, c2u_DF, - c2u_E0, c2u_E1, c2u_E2, c2u_E3, c2u_E4, c2u_E5, c2u_E6, c2u_E7, - c2u_E8, c2u_E9, c2u_EA, c2u_EB, c2u_EC, c2u_ED, c2u_EE, c2u_EF, - c2u_F0, c2u_F1, c2u_F2, c2u_F3, c2u_F4, c2u_F5, c2u_F6, c2u_F7, - c2u_F8, c2u_F9, c2u_FA, c2u_FB, c2u_FC, c2u_FD, NULL, NULL, -}; - -static const unsigned char u2c_01[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xA9, 0xA2, 0xA9, 0xA2, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0xA4, 0xA9, 0xA4, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xA9, 0xA5, 0xA8, 0xA6, 0xA9, 0xA6, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xA9, 0xA7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xA8, /* 0x3C-0x3F */ - 0xA9, 0xA8, 0xA8, 0xA9, 0xA9, 0xA9, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xA9, 0xB0, 0xA8, 0xAF, 0xA9, 0xAF, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0xAB, 0xA9, 0xAB, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0xAE, 0xA9, 0xAE, /* 0x64-0x67 */ -}; - -static const unsigned char u2c_02[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0xA7, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0xA2, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xA2, 0xA8, 0xA2, 0xAB, 0xA2, 0xAA, 0xA2, 0xAD, /* 0xD8-0xDB */ - 0x00, 0x00, 0xA2, 0xA9, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ -}; - -static const unsigned char u2c_03[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xA5, 0xC1, 0xA5, 0xC2, 0xA5, 0xC3, /* 0x90-0x93 */ - 0xA5, 0xC4, 0xA5, 0xC5, 0xA5, 0xC6, 0xA5, 0xC7, /* 0x94-0x97 */ - 0xA5, 0xC8, 0xA5, 0xC9, 0xA5, 0xCA, 0xA5, 0xCB, /* 0x98-0x9B */ - 0xA5, 0xCC, 0xA5, 0xCD, 0xA5, 0xCE, 0xA5, 0xCF, /* 0x9C-0x9F */ - 0xA5, 0xD0, 0xA5, 0xD1, 0x00, 0x00, 0xA5, 0xD2, /* 0xA0-0xA3 */ - 0xA5, 0xD3, 0xA5, 0xD4, 0xA5, 0xD5, 0xA5, 0xD6, /* 0xA4-0xA7 */ - 0xA5, 0xD7, 0xA5, 0xD8, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xA5, 0xE1, 0xA5, 0xE2, 0xA5, 0xE3, /* 0xB0-0xB3 */ - 0xA5, 0xE4, 0xA5, 0xE5, 0xA5, 0xE6, 0xA5, 0xE7, /* 0xB4-0xB7 */ - 0xA5, 0xE8, 0xA5, 0xE9, 0xA5, 0xEA, 0xA5, 0xEB, /* 0xB8-0xBB */ - 0xA5, 0xEC, 0xA5, 0xED, 0xA5, 0xEE, 0xA5, 0xEF, /* 0xBC-0xBF */ - 0xA5, 0xF0, 0xA5, 0xF1, 0x00, 0x00, 0xA5, 0xF2, /* 0xC0-0xC3 */ - 0xA5, 0xF3, 0xA5, 0xF4, 0xA5, 0xF5, 0xA5, 0xF6, /* 0xC4-0xC7 */ - 0xA5, 0xF7, 0xA5, 0xF8, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ -}; - -static const unsigned char u2c_04[512] = { - 0x00, 0x00, 0xAC, 0xA7, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xAC, 0xA1, 0xAC, 0xA2, 0xAC, 0xA3, 0xAC, 0xA4, /* 0x10-0x13 */ - 0xAC, 0xA5, 0xAC, 0xA6, 0xAC, 0xA8, 0xAC, 0xA9, /* 0x14-0x17 */ - 0xAC, 0xAA, 0xAC, 0xAB, 0xAC, 0xAC, 0xAC, 0xAD, /* 0x18-0x1B */ - 0xAC, 0xAE, 0xAC, 0xAF, 0xAC, 0xB0, 0xAC, 0xB1, /* 0x1C-0x1F */ - 0xAC, 0xB2, 0xAC, 0xB3, 0xAC, 0xB4, 0xAC, 0xB5, /* 0x20-0x23 */ - 0xAC, 0xB6, 0xAC, 0xB7, 0xAC, 0xB8, 0xAC, 0xB9, /* 0x24-0x27 */ - 0xAC, 0xBA, 0xAC, 0xBB, 0xAC, 0xBC, 0xAC, 0xBD, /* 0x28-0x2B */ - 0xAC, 0xBE, 0xAC, 0xBF, 0xAC, 0xC0, 0xAC, 0xC1, /* 0x2C-0x2F */ - 0xAC, 0xD1, 0xAC, 0xD2, 0xAC, 0xD3, 0xAC, 0xD4, /* 0x30-0x33 */ - 0xAC, 0xD5, 0xAC, 0xD6, 0xAC, 0xD8, 0xAC, 0xD9, /* 0x34-0x37 */ - 0xAC, 0xDA, 0xAC, 0xDB, 0xAC, 0xDC, 0xAC, 0xDD, /* 0x38-0x3B */ - 0xAC, 0xDE, 0xAC, 0xDF, 0xAC, 0xE0, 0xAC, 0xE1, /* 0x3C-0x3F */ - 0xAC, 0xE2, 0xAC, 0xE3, 0xAC, 0xE4, 0xAC, 0xE5, /* 0x40-0x43 */ - 0xAC, 0xE6, 0xAC, 0xE7, 0xAC, 0xE8, 0xAC, 0xE9, /* 0x44-0x47 */ - 0xAC, 0xEA, 0xAC, 0xEB, 0xAC, 0xEC, 0xAC, 0xED, /* 0x48-0x4B */ - 0xAC, 0xEE, 0xAC, 0xEF, 0xAC, 0xF0, 0xAC, 0xF1, /* 0x4C-0x4F */ - 0x00, 0x00, 0xAC, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ -}; - -static const unsigned char u2c_11[512] = { - 0xA4, 0xA1, 0xA4, 0xA2, 0xA4, 0xA4, 0xA4, 0xA7, /* 0x00-0x03 */ - 0xA4, 0xA8, 0xA4, 0xA9, 0xA4, 0xB1, 0xA4, 0xB2, /* 0x04-0x07 */ - 0xA4, 0xB3, 0xA4, 0xB5, 0xA4, 0xB6, 0xA4, 0xB7, /* 0x08-0x0B */ - 0xA4, 0xB8, 0xA4, 0xB9, 0xA4, 0xBA, 0xA4, 0xBB, /* 0x0C-0x0F */ - 0xA4, 0xBC, 0xA4, 0xBD, 0xA4, 0xBE, 0x00, 0x00, /* 0x10-0x13 */ - 0xA4, 0xD5, 0xA4, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0xA4, 0xDD, 0x00, 0x00, /* 0x18-0x1B */ - 0xA4, 0xDE, 0xA4, 0xE1, 0xA4, 0xE2, 0x00, 0x00, /* 0x1C-0x1F */ - 0xA4, 0xE3, 0xA4, 0xB4, 0xA4, 0xE4, 0xA4, 0xE5, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0xE6, /* 0x24-0x27 */ - 0x00, 0x00, 0xA4, 0xE7, 0x00, 0x00, 0xA4, 0xE8, /* 0x28-0x2B */ - 0xA4, 0xE9, 0xA4, 0xEA, 0xA4, 0xEB, 0xA4, 0xEC, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xA4, 0xED, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xA4, 0xEE, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xA4, 0xB5, 0xA4, 0xB6, 0xA4, 0xB5, 0xA4, 0xB6, /* 0x3C-0x3F */ - 0xA4, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0xA4, 0xF2, 0xA4, 0xF3, 0xA4, 0xF0, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xA4, 0xB7, 0x00, 0x00, 0xA4, 0xB8, 0xA4, 0xB9, /* 0x4C-0x4F */ - 0xA4, 0xB8, 0xA4, 0xB9, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xA4, 0xBA, 0xA4, 0xBA, 0x00, 0x00, 0xA4, 0xF4, /* 0x54-0x57 */ - 0xA4, 0xF5, 0xA4, 0xF6, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0xD4, /* 0x5C-0x5F */ - 0x00, 0x00, 0xA4, 0xBF, 0xA4, 0xC0, 0xA4, 0xC1, /* 0x60-0x63 */ - 0xA4, 0xC2, 0xA4, 0xC3, 0xA4, 0xC4, 0xA4, 0xC5, /* 0x64-0x67 */ - 0xA4, 0xC6, 0xA4, 0xC7, 0xA4, 0xC8, 0xA4, 0xC9, /* 0x68-0x6B */ - 0xA4, 0xCA, 0xA4, 0xCB, 0xA4, 0xCC, 0xA4, 0xCD, /* 0x6C-0x6F */ - 0xA4, 0xCE, 0xA4, 0xCF, 0xA4, 0xD0, 0xA4, 0xD1, /* 0x70-0x73 */ - 0xA4, 0xD2, 0xA4, 0xD3, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xA4, 0xF7, 0xA4, 0xF8, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xA4, 0xF9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xA4, 0xFA, 0xA4, 0xFB, 0x00, 0x00, /* 0x90-0x93 */ - 0xA4, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xA4, 0xFD, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xA4, 0xFE, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xA4, 0xA1, 0xA4, 0xA2, 0xA4, 0xA3, 0xA4, 0xA4, /* 0xA8-0xAB */ - 0xA4, 0xA5, 0xA4, 0xA6, 0xA4, 0xA7, 0xA4, 0xA9, /* 0xAC-0xAF */ - 0xA4, 0xAA, 0xA4, 0xAB, 0xA4, 0xAC, 0xA4, 0xAD, /* 0xB0-0xB3 */ - 0xA4, 0xAE, 0xA4, 0xAF, 0xA4, 0xB0, 0xA4, 0xB1, /* 0xB4-0xB7 */ - 0xA4, 0xB2, 0xA4, 0xB4, 0xA4, 0xB5, 0xA4, 0xB6, /* 0xB8-0xBB */ - 0xA4, 0xB7, 0xA4, 0xB8, 0xA4, 0xBA, 0xA4, 0xBB, /* 0xBC-0xBF */ - 0xA4, 0xBC, 0xA4, 0xBD, 0xA4, 0xBE, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0xA4, 0xD6, 0xA4, 0xD7, /* 0xC4-0xC7 */ - 0xA4, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0xA4, 0xD9, 0x00, 0x00, 0xA4, 0xDA, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0xDB, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0xDC, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xA4, 0xDD, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xA4, 0xDE, 0xA4, 0xDF, 0x00, 0x00, 0xA4, 0xE0, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0xA4, 0xE8, 0xA4, 0xEA, /* 0xE4-0xE7 */ - 0xA4, 0xEC, 0x00, 0x00, 0xA4, 0xED, 0xA4, 0xEF, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0xA4, 0xF0, 0x00, 0x00, /* 0xEC-0xEF */ - 0xA4, 0xB7, 0xA4, 0xF2, 0xA4, 0xF3, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xA4, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xA4, 0xF6, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_20[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xA1, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xA1, 0xAE, 0xA1, 0xAF, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xA1, 0xB0, 0xA1, 0xB1, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xA2, 0xD3, 0xA2, 0xD4, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xA1, 0xA5, 0xA1, 0xA6, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xA2, 0xB6, 0x00, 0x00, 0xA1, 0xC7, 0xA1, 0xC8, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xD8, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xA9, 0xF9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA9, 0xFA, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xA9, 0xFB, 0xA9, 0xFC, 0xA9, 0xFD, /* 0x80-0x83 */ - 0xA9, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x5C, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ -}; - -static const unsigned char u2c_21[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xC9, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xA2, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA7, 0xA4, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xA2, 0xE0, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xA2, 0xE5, 0xA2, 0xE2, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0xA7, 0xD9, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xCA, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xF7, /* 0x50-0x53 */ - 0xA8, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xFB, /* 0x58-0x5B */ - 0xA8, 0xFC, 0xA8, 0xFD, 0xA8, 0xFE, 0x00, 0x00, /* 0x5C-0x5F */ - 0xA5, 0xB0, 0xA5, 0xB1, 0xA5, 0xB2, 0xA5, 0xB3, /* 0x60-0x63 */ - 0xA5, 0xB4, 0xA5, 0xB5, 0xA5, 0xB6, 0xA5, 0xB7, /* 0x64-0x67 */ - 0xA5, 0xB8, 0xA5, 0xB9, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xA5, 0xA1, 0xA5, 0xA2, 0xA5, 0xA3, 0xA5, 0xA4, /* 0x70-0x73 */ - 0xA5, 0xA5, 0xA5, 0xA6, 0xA5, 0xA7, 0xA5, 0xA8, /* 0x74-0x77 */ - 0xA5, 0xA9, 0xA5, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xA1, 0xE7, 0xA1, 0xE8, 0xA1, 0xE6, 0xA1, 0xE9, /* 0x90-0x93 */ - 0xA1, 0xEA, 0xA2, 0xD5, 0xA2, 0xD8, 0xA2, 0xD6, /* 0x94-0x97 */ - 0xA2, 0xD9, 0xA2, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xA2, 0xA1, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xA2, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ -}; - -static const unsigned char u2c_22[512] = { - 0xA2, 0xA3, 0x00, 0x00, 0xA1, 0xD3, 0xA2, 0xA4, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xD4, /* 0x04-0x07 */ - 0xA1, 0xF4, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xF5, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0xB3, /* 0x0C-0x0F */ - 0x00, 0x00, 0xA2, 0xB2, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xEE, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0xA1, 0xF0, 0xA1, 0xC4, 0x00, 0x00, /* 0x1C-0x1F */ - 0xA1, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xA1, 0xAB, 0x00, 0x00, 0xA1, 0xFC, /* 0x24-0x27 */ - 0xA1, 0xFD, 0xA1, 0xFB, 0xA1, 0xFA, 0xA1, 0xF2, /* 0x28-0x2B */ - 0xA1, 0xF3, 0x00, 0x00, 0xA2, 0xB1, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xA1, 0xC5, 0xA1, 0xF1, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xA1, 0xAD, 0xA1, 0xEF, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xD6, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xA1, 0xC1, 0xA1, 0xD5, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0xA1, 0xC2, 0xA1, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xEC, 0xA1, 0xED, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xF8, 0xA1, 0xF9, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xF6, 0xA1, 0xF7, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xA2, 0xC1, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xA1, 0xD1, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ -}; - -static const unsigned char u2c_23[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xD2, 0x00, 0x00, /* 0x10-0x13 */ -}; - -static const unsigned char u2c_24[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xA8, 0xE7, 0xA8, 0xE8, 0xA8, 0xE9, 0xA8, 0xEA, /* 0x60-0x63 */ - 0xA8, 0xEB, 0xA8, 0xEC, 0xA8, 0xED, 0xA8, 0xEE, /* 0x64-0x67 */ - 0xA8, 0xEF, 0xA8, 0xF0, 0xA8, 0xF1, 0xA8, 0xF2, /* 0x68-0x6B */ - 0xA8, 0xF3, 0xA8, 0xF4, 0xA8, 0xF5, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xA9, 0xE7, 0xA9, 0xE8, 0xA9, 0xE9, 0xA9, 0xEA, /* 0x74-0x77 */ - 0xA9, 0xEB, 0xA9, 0xEC, 0xA9, 0xED, 0xA9, 0xEE, /* 0x78-0x7B */ - 0xA9, 0xEF, 0xA9, 0xF0, 0xA9, 0xF1, 0xA9, 0xF2, /* 0x7C-0x7F */ - - 0xA9, 0xF3, 0xA9, 0xF4, 0xA9, 0xF5, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xA9, 0xCD, 0xA9, 0xCE, 0xA9, 0xCF, 0xA9, 0xD0, /* 0x9C-0x9F */ - 0xA9, 0xD1, 0xA9, 0xD2, 0xA9, 0xD3, 0xA9, 0xD4, /* 0xA0-0xA3 */ - 0xA9, 0xD5, 0xA9, 0xD6, 0xA9, 0xD7, 0xA9, 0xD8, /* 0xA4-0xA7 */ - 0xA9, 0xD9, 0xA9, 0xDA, 0xA9, 0xDB, 0xA9, 0xDC, /* 0xA8-0xAB */ - 0xA9, 0xDD, 0xA9, 0xDE, 0xA9, 0xDF, 0xA9, 0xE0, /* 0xAC-0xAF */ - 0xA9, 0xE1, 0xA9, 0xE2, 0xA9, 0xE3, 0xA9, 0xE4, /* 0xB0-0xB3 */ - 0xA9, 0xE5, 0xA9, 0xE6, 0xA8, 0xCD, 0xA8, 0xCE, /* 0xB4-0xB7 */ - 0xA8, 0xCF, 0xA8, 0xD0, 0xA8, 0xD1, 0xA8, 0xD2, /* 0xB8-0xBB */ - 0xA8, 0xD3, 0xA8, 0xD4, 0xA8, 0xD5, 0xA8, 0xD6, /* 0xBC-0xBF */ - 0xA8, 0xD7, 0xA8, 0xD8, 0xA8, 0xD9, 0xA8, 0xDA, /* 0xC0-0xC3 */ - 0xA8, 0xDB, 0xA8, 0xDC, 0xA8, 0xDD, 0xA8, 0xDE, /* 0xC4-0xC7 */ - 0xA8, 0xDF, 0xA8, 0xE0, 0xA8, 0xE1, 0xA8, 0xE2, /* 0xC8-0xCB */ - 0xA8, 0xE3, 0xA8, 0xE4, 0xA8, 0xE5, 0xA8, 0xE6, /* 0xCC-0xCF */ - 0xA8, 0xCD, 0xA8, 0xCE, 0xA8, 0xCF, 0xA8, 0xD0, /* 0xD0-0xD3 */ - 0xA8, 0xD1, 0xA8, 0xD2, 0xA8, 0xD3, 0xA8, 0xD4, /* 0xD4-0xD7 */ - 0xA8, 0xD5, 0xA8, 0xD6, 0xA8, 0xD7, 0xA8, 0xD8, /* 0xD8-0xDB */ - 0xA8, 0xD9, 0xA8, 0xDA, 0xA8, 0xDB, 0xA8, 0xDC, /* 0xDC-0xDF */ - 0xA8, 0xDD, 0xA8, 0xDE, 0xA8, 0xDF, 0xA8, 0xE0, /* 0xE0-0xE3 */ - 0xA8, 0xE1, 0xA8, 0xE2, 0xA8, 0xE3, 0xA8, 0xE4, /* 0xE4-0xE7 */ - 0xA8, 0xE5, 0xA8, 0xE6, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ -}; - -static const unsigned char u2c_25[512] = { - 0xA6, 0xA1, 0xA6, 0xAC, 0xA6, 0xA2, 0xA6, 0xAD, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0xA6, 0xA3, 0xA6, 0xC8, 0xA6, 0xC7, 0xA6, 0xAE, /* 0x0C-0x0F */ - 0xA6, 0xA4, 0xA6, 0xC2, 0xA6, 0xC1, 0xA6, 0xAF, /* 0x10-0x13 */ - 0xA6, 0xA6, 0xA6, 0xC6, 0xA6, 0xC5, 0xA6, 0xB1, /* 0x14-0x17 */ - 0xA6, 0xA5, 0xA6, 0xC4, 0xA6, 0xC3, 0xA6, 0xB0, /* 0x18-0x1B */ - 0xA6, 0xA7, 0xA6, 0xBC, 0xA6, 0xC9, 0xA6, 0xCA, /* 0x1C-0x1F */ - 0xA6, 0xB7, 0xA6, 0xCB, 0xA6, 0xCC, 0xA6, 0xB2, /* 0x20-0x23 */ - 0xA6, 0xA9, 0xA6, 0xBE, 0xA6, 0xCD, 0xA6, 0xCE, /* 0x24-0x27 */ - 0xA6, 0xB9, 0xA6, 0xCF, 0xA6, 0xD0, 0xA6, 0xB4, /* 0x28-0x2B */ - 0xA6, 0xA8, 0xA6, 0xD1, 0xA6, 0xD2, 0xA6, 0xB8, /* 0x2C-0x2F */ - 0xA6, 0xBD, 0xA6, 0xD3, 0xA6, 0xD4, 0xA6, 0xB3, /* 0x30-0x33 */ - 0xA6, 0xAA, 0xA6, 0xD5, 0xA6, 0xD6, 0xA6, 0xBA, /* 0x34-0x37 */ - 0xA6, 0xBF, 0xA6, 0xD7, 0xA6, 0xD8, 0xA6, 0xB5, /* 0x38-0x3B */ - 0xA6, 0xAB, 0xA6, 0xD9, 0xA6, 0xDA, 0xA6, 0xBB, /* 0x3C-0x3F */ - 0xA6, 0xDB, 0xA6, 0xDC, 0xA6, 0xC0, 0xA6, 0xDD, /* 0x40-0x43 */ - 0xA6, 0xDE, 0xA6, 0xDF, 0xA6, 0xE0, 0xA6, 0xE1, /* 0x44-0x47 */ - 0xA6, 0xE2, 0xA6, 0xE3, 0xA6, 0xE4, 0xA6, 0xB6, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xA2, 0xC6, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xA1, 0xE1, 0xA1, 0xE0, 0x00, 0x00, 0xA2, 0xC3, /* 0xA0-0xA3 */ - 0xA2, 0xC7, 0xA2, 0xC8, 0xA2, 0xCB, 0xA2, 0xCA, /* 0xA4-0xA7 */ - 0xA2, 0xC9, 0xA2, 0xCC, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xE3, 0xA1, 0xE2, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xA2, 0xBA, 0xA2, 0xB9, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0xA1, 0xE5, 0xA1, 0xE4, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xA2, 0xB8, 0xA2, 0xB7, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xDF, 0xA1, 0xDE, /* 0xC4-0xC7 */ - 0xA2, 0xC2, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xDB, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xDD, 0xA1, 0xDC, /* 0xCC-0xCF */ - 0xA2, 0xC4, 0xA2, 0xC5, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ -}; - -static const unsigned char u2c_26[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xA1, 0xDA, 0xA1, 0xD9, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0xA2, 0xCF, 0xA2, 0xCE, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xA2, 0xD0, 0x00, 0x00, 0xA2, 0xD1, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xA1, 0xCF, 0x00, 0x00, 0xA1, 0xCE, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xA2, 0xBC, 0xA2, 0xBD, 0x00, 0x00, 0xA2, 0xC0, /* 0x60-0x63 */ - 0xA2, 0xBB, 0xA2, 0xBE, 0x00, 0x00, 0xA2, 0xBF, /* 0x64-0x67 */ - 0xA2, 0xCD, 0xA2, 0xDB, 0xA2, 0xDC, 0x00, 0x00, /* 0x68-0x6B */ - 0xA2, 0xDD, 0xA2, 0xDA, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ -}; - -static const unsigned char u2c_30[512] = { - 0xA1, 0xA1, 0xA1, 0xA2, 0xA1, 0xA3, 0xA1, 0xA8, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xA1, 0xB4, 0xA1, 0xB5, 0xA1, 0xB6, 0xA1, 0xB7, /* 0x08-0x0B */ - 0xA1, 0xB8, 0xA1, 0xB9, 0xA1, 0xBA, 0xA1, 0xBB, /* 0x0C-0x0F */ - 0xA1, 0xBC, 0xA1, 0xBD, 0x00, 0x00, 0xA1, 0xEB, /* 0x10-0x13 */ - 0xA1, 0xB2, 0xA1, 0xB3, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xAA, 0xA1, 0xAA, 0xA2, 0xAA, 0xA3, /* 0x40-0x43 */ - 0xAA, 0xA4, 0xAA, 0xA5, 0xAA, 0xA6, 0xAA, 0xA7, /* 0x44-0x47 */ - 0xAA, 0xA8, 0xAA, 0xA9, 0xAA, 0xAA, 0xAA, 0xAB, /* 0x48-0x4B */ - 0xAA, 0xAC, 0xAA, 0xAD, 0xAA, 0xAE, 0xAA, 0xAF, /* 0x4C-0x4F */ - 0xAA, 0xB0, 0xAA, 0xB1, 0xAA, 0xB2, 0xAA, 0xB3, /* 0x50-0x53 */ - 0xAA, 0xB4, 0xAA, 0xB5, 0xAA, 0xB6, 0xAA, 0xB7, /* 0x54-0x57 */ - 0xAA, 0xB8, 0xAA, 0xB9, 0xAA, 0xBA, 0xAA, 0xBB, /* 0x58-0x5B */ - 0xAA, 0xBC, 0xAA, 0xBD, 0xAA, 0xBE, 0xAA, 0xBF, /* 0x5C-0x5F */ - 0xAA, 0xC0, 0xAA, 0xC1, 0xAA, 0xC2, 0xAA, 0xC3, /* 0x60-0x63 */ - 0xAA, 0xC4, 0xAA, 0xC5, 0xAA, 0xC6, 0xAA, 0xC7, /* 0x64-0x67 */ - 0xAA, 0xC8, 0xAA, 0xC9, 0xAA, 0xCA, 0xAA, 0xCB, /* 0x68-0x6B */ - 0xAA, 0xCC, 0xAA, 0xCD, 0xAA, 0xCE, 0xAA, 0xCF, /* 0x6C-0x6F */ - 0xAA, 0xD0, 0xAA, 0xD1, 0xAA, 0xD2, 0xAA, 0xD3, /* 0x70-0x73 */ - 0xAA, 0xD4, 0xAA, 0xD5, 0xAA, 0xD6, 0xAA, 0xD7, /* 0x74-0x77 */ - 0xAA, 0xD8, 0xAA, 0xD9, 0xAA, 0xDA, 0xAA, 0xDB, /* 0x78-0x7B */ - 0xAA, 0xDC, 0xAA, 0xDD, 0xAA, 0xDE, 0xAA, 0xDF, /* 0x7C-0x7F */ - - 0xAA, 0xE0, 0xAA, 0xE1, 0xAA, 0xE2, 0xAA, 0xE3, /* 0x80-0x83 */ - 0xAA, 0xE4, 0xAA, 0xE5, 0xAA, 0xE6, 0xAA, 0xE7, /* 0x84-0x87 */ - 0xAA, 0xE8, 0xAA, 0xE9, 0xAA, 0xEA, 0xAA, 0xEB, /* 0x88-0x8B */ - 0xAA, 0xEC, 0xAA, 0xED, 0xAA, 0xEE, 0xAA, 0xEF, /* 0x8C-0x8F */ - 0xAA, 0xF0, 0xAA, 0xF1, 0xAA, 0xF2, 0xAA, 0xF3, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xAB, 0xA1, 0xAB, 0xA2, 0xAB, 0xA3, /* 0xA0-0xA3 */ - 0xAB, 0xA4, 0xAB, 0xA5, 0xAB, 0xA6, 0xAB, 0xA7, /* 0xA4-0xA7 */ - 0xAB, 0xA8, 0xAB, 0xA9, 0xAB, 0xAA, 0xAB, 0xAB, /* 0xA8-0xAB */ - 0xAB, 0xAC, 0xAB, 0xAD, 0xAB, 0xAE, 0xAB, 0xAF, /* 0xAC-0xAF */ - 0xAB, 0xB0, 0xAB, 0xB1, 0xAB, 0xB2, 0xAB, 0xB3, /* 0xB0-0xB3 */ - 0xAB, 0xB4, 0xAB, 0xB5, 0xAB, 0xB6, 0xAB, 0xB7, /* 0xB4-0xB7 */ - 0xAB, 0xB8, 0xAB, 0xB9, 0xAB, 0xBA, 0xAB, 0xBB, /* 0xB8-0xBB */ - 0xAB, 0xBC, 0xAB, 0xBD, 0xAB, 0xBE, 0xAB, 0xBF, /* 0xBC-0xBF */ - 0xAB, 0xC0, 0xAB, 0xC1, 0xAB, 0xC2, 0xAB, 0xC3, /* 0xC0-0xC3 */ - 0xAB, 0xC4, 0xAB, 0xC5, 0xAB, 0xC6, 0xAB, 0xC7, /* 0xC4-0xC7 */ - 0xAB, 0xC8, 0xAB, 0xC9, 0xAB, 0xCA, 0xAB, 0xCB, /* 0xC8-0xCB */ - 0xAB, 0xCC, 0xAB, 0xCD, 0xAB, 0xCE, 0xAB, 0xCF, /* 0xCC-0xCF */ - 0xAB, 0xD0, 0xAB, 0xD1, 0xAB, 0xD2, 0xAB, 0xD3, /* 0xD0-0xD3 */ - 0xAB, 0xD4, 0xAB, 0xD5, 0xAB, 0xD6, 0xAB, 0xD7, /* 0xD4-0xD7 */ - 0xAB, 0xD8, 0xAB, 0xD9, 0xAB, 0xDA, 0xAB, 0xDB, /* 0xD8-0xDB */ - 0xAB, 0xDC, 0xAB, 0xDD, 0xAB, 0xDE, 0xAB, 0xDF, /* 0xDC-0xDF */ - 0xAB, 0xE0, 0xAB, 0xE1, 0xAB, 0xE2, 0xAB, 0xE3, /* 0xE0-0xE3 */ - 0xAB, 0xE4, 0xAB, 0xE5, 0xAB, 0xE6, 0xAB, 0xE7, /* 0xE4-0xE7 */ - 0xAB, 0xE8, 0xAB, 0xE9, 0xAB, 0xEA, 0xAB, 0xEB, /* 0xE8-0xEB */ - 0xAB, 0xEC, 0xAB, 0xED, 0xAB, 0xEE, 0xAB, 0xEF, /* 0xEC-0xEF */ - 0xAB, 0xF0, 0xAB, 0xF1, 0xAB, 0xF2, 0xAB, 0xF3, /* 0xF0-0xF3 */ - 0xAB, 0xF4, 0xAB, 0xF5, 0xAB, 0xF6, 0x00, 0x00, /* 0xF4-0xF7 */ -}; - -static const unsigned char u2c_31[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xA4, 0xA1, 0xA4, 0xA2, 0xA4, 0xA3, /* 0x30-0x33 */ - 0xA4, 0xA4, 0xA4, 0xA5, 0xA4, 0xA6, 0xA4, 0xA7, /* 0x34-0x37 */ - 0xA4, 0xA8, 0xA4, 0xA9, 0xA4, 0xAA, 0xA4, 0xAB, /* 0x38-0x3B */ - 0xA4, 0xAC, 0xA4, 0xAD, 0xA4, 0xAE, 0xA4, 0xAF, /* 0x3C-0x3F */ - 0xA4, 0xB0, 0xA4, 0xB1, 0xA4, 0xB2, 0xA4, 0xB3, /* 0x40-0x43 */ - 0xA4, 0xB4, 0xA4, 0xB5, 0xA4, 0xB6, 0xA4, 0xB7, /* 0x44-0x47 */ - 0xA4, 0xB8, 0xA4, 0xB9, 0xA4, 0xBA, 0xA4, 0xBB, /* 0x48-0x4B */ - 0xA4, 0xBC, 0xA4, 0xBD, 0xA4, 0xBE, 0xA4, 0xBF, /* 0x4C-0x4F */ - 0xA4, 0xC0, 0xA4, 0xC1, 0xA4, 0xC2, 0xA4, 0xC3, /* 0x50-0x53 */ - 0xA4, 0xC4, 0xA4, 0xC5, 0xA4, 0xC6, 0xA4, 0xC7, /* 0x54-0x57 */ - 0xA4, 0xC8, 0xA4, 0xC9, 0xA4, 0xCA, 0xA4, 0xCB, /* 0x58-0x5B */ - 0xA4, 0xCC, 0xA4, 0xCD, 0xA4, 0xCE, 0xA4, 0xCF, /* 0x5C-0x5F */ - 0xA4, 0xD0, 0xA4, 0xD1, 0xA4, 0xD2, 0xA4, 0xD3, /* 0x60-0x63 */ - 0xA4, 0xD4, 0xA4, 0xD5, 0xA4, 0xD6, 0xA4, 0xD7, /* 0x64-0x67 */ - 0xA4, 0xD8, 0xA4, 0xD9, 0xA4, 0xDA, 0xA4, 0xDB, /* 0x68-0x6B */ - 0xA4, 0xDC, 0xA4, 0xDD, 0xA4, 0xDE, 0xA4, 0xDF, /* 0x6C-0x6F */ - 0xA4, 0xE0, 0xA4, 0xE1, 0xA4, 0xE2, 0xA4, 0xE3, /* 0x70-0x73 */ - 0xA4, 0xE4, 0xA4, 0xE5, 0xA4, 0xE6, 0xA4, 0xE7, /* 0x74-0x77 */ - 0xA4, 0xE8, 0xA4, 0xE9, 0xA4, 0xEA, 0xA4, 0xEB, /* 0x78-0x7B */ - 0xA4, 0xEC, 0xA4, 0xED, 0xA4, 0xEE, 0xA4, 0xEF, /* 0x7C-0x7F */ - - 0xA4, 0xF0, 0xA4, 0xF1, 0xA4, 0xF2, 0xA4, 0xF3, /* 0x80-0x83 */ - 0xA4, 0xF4, 0xA4, 0xF5, 0xA4, 0xF6, 0xA4, 0xF7, /* 0x84-0x87 */ - 0xA4, 0xF8, 0xA4, 0xF9, 0xA4, 0xFA, 0xA4, 0xFB, /* 0x88-0x8B */ - 0xA4, 0xFC, 0xA4, 0xFD, 0xA4, 0xFE, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xEC, 0xE9, 0xEC, 0xA3, /* 0x90-0x93 */ - 0xDF, 0xB2, 0xDE, 0xCC, 0xDF, 0xBE, 0xF1, 0xE9, /* 0x94-0x97 */ - 0xF9, 0xBB, 0xCB, 0xA3, 0xEB, 0xE0, 0xDC, 0xB0, /* 0x98-0x9B */ - 0xEF, 0xCB, 0xF4, 0xB8, 0xF2, 0xA2, 0xEC, 0xD1, /* 0x9C-0x9F */ -}; - -static const unsigned char u2c_32[512] = { - 0xA9, 0xB1, 0xA9, 0xB2, 0xA9, 0xB3, 0xA9, 0xB4, /* 0x00-0x03 */ - 0xA9, 0xB5, 0xA9, 0xB6, 0xA9, 0xB7, 0xA9, 0xB8, /* 0x04-0x07 */ - 0xA9, 0xB9, 0xA9, 0xBA, 0xA9, 0xBB, 0xA9, 0xBC, /* 0x08-0x0B */ - 0xA9, 0xBD, 0xA9, 0xBE, 0xA9, 0xBF, 0xA9, 0xC0, /* 0x0C-0x0F */ - 0xA9, 0xC1, 0xA9, 0xC2, 0xA9, 0xC3, 0xA9, 0xC4, /* 0x10-0x13 */ - 0xA9, 0xC5, 0xA9, 0xC6, 0xA9, 0xC7, 0xA9, 0xC8, /* 0x14-0x17 */ - 0xA9, 0xC9, 0xA9, 0xCA, 0xA9, 0xCB, 0xA9, 0xCC, /* 0x18-0x1B */ - 0xA2, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xEC, 0xE9, 0xEC, 0xA3, 0xDF, 0xB2, 0xDE, 0xCC, /* 0x20-0x23 */ - 0xE7, 0xE9, 0xD7, 0xBF, 0xF6, 0xD2, 0xF8, 0xA2, /* 0x24-0x27 */ - 0xCE, 0xFA, 0xE4, 0xA8, 0xEA, 0xC5, 0xFB, 0xFD, /* 0x28-0x2B */ - 0xE2, 0xA9, 0xD9, 0xCA, 0xD1, 0xD1, 0xF7, 0xCF, /* 0x2C-0x2F */ - 0xEC, 0xED, 0xF1, 0xBB, 0xEA, 0xF3, 0xDE, 0xE4, /* 0x30-0x33 */ - 0xD9, 0xA3, 0xF7, 0xE5, 0xEE, 0xAF, 0xF5, 0xE6, /* 0x34-0x37 */ - 0xD6, 0xCC, 0xD3, 0xDB, 0xFB, 0xBC, 0xF9, 0xCA, /* 0x38-0x3B */ - 0xCA, 0xF8, 0xD0, 0xEA, 0xED, 0xC0, 0xFA, 0xF0, /* 0x3C-0x3F */ - 0xF0, 0xAE, 0xFD, 0xCC, 0xED, 0xBB, 0xF2, 0xB8, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xA8, 0xB1, 0xA8, 0xB2, 0xA8, 0xB3, 0xA8, 0xB4, /* 0x60-0x63 */ - 0xA8, 0xB5, 0xA8, 0xB6, 0xA8, 0xB7, 0xA8, 0xB8, /* 0x64-0x67 */ - 0xA8, 0xB9, 0xA8, 0xBA, 0xA8, 0xBB, 0xA8, 0xBC, /* 0x68-0x6B */ - 0xA8, 0xBD, 0xA8, 0xBE, 0xA8, 0xBF, 0xA8, 0xC0, /* 0x6C-0x6F */ - 0xA8, 0xC1, 0xA8, 0xC2, 0xA8, 0xC3, 0xA8, 0xC4, /* 0x70-0x73 */ - 0xA8, 0xC5, 0xA8, 0xC6, 0xA8, 0xC7, 0xA8, 0xC8, /* 0x74-0x77 */ - 0xA8, 0xC9, 0xA8, 0xCA, 0xA8, 0xCB, 0xA8, 0xCC, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0xDE, /* 0x7C-0x7F */ - - 0xEC, 0xE9, 0xEC, 0xA3, 0xDF, 0xB2, 0xDE, 0xCC, /* 0x80-0x83 */ - 0xE7, 0xE9, 0xD7, 0xBF, 0xF6, 0xD2, 0xF8, 0xA2, /* 0x84-0x87 */ - 0xCE, 0xFA, 0xE4, 0xA8, 0xEA, 0xC5, 0xFB, 0xFD, /* 0x88-0x8B */ - 0xE2, 0xA9, 0xD9, 0xCA, 0xD1, 0xD1, 0xF7, 0xCF, /* 0x8C-0x8F */ - 0xEC, 0xED, 0xF1, 0xBB, 0xEA, 0xF3, 0xDE, 0xE4, /* 0x90-0x93 */ - 0xD9, 0xA3, 0xF7, 0xE5, 0xEE, 0xAF, 0xF5, 0xE6, /* 0x94-0x97 */ - 0xD6, 0xCC, 0xDD, 0xFA, 0xD1, 0xFB, 0xD2, 0xB3, /* 0x98-0x9B */ - 0xEE, 0xEA, 0xE9, 0xD0, 0xEC, 0xD4, 0xF1, 0xBC, /* 0x9C-0x9F */ - 0xFA, 0xA3, 0xFD, 0xCC, 0xDE, 0xD0, 0xEF, 0xE1, /* 0xA0-0xA3 */ - 0xDF, 0xBE, 0xF1, 0xE9, 0xF9, 0xBB, 0xF1, 0xA7, /* 0xA4-0xA7 */ - 0xE9, 0xD3, 0xEC, 0xA2, 0xF0, 0xF3, 0xF9, 0xCA, /* 0xA8-0xAB */ - 0xCA, 0xF8, 0xD0, 0xEA, 0xED, 0xC0, 0xFA, 0xF0, /* 0xAC-0xAF */ - 0xE5, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ -}; - -static const unsigned char u2c_33[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xA7, 0xC9, 0xA7, 0xCA, 0xA7, 0xCB, 0xA7, 0xCC, /* 0x80-0x83 */ - 0xA7, 0xCD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xA7, 0xBA, 0xA7, 0xBB, 0xA7, 0xDC, 0xA7, 0xDD, /* 0x88-0x8B */ - 0xA7, 0xDE, 0xA7, 0xB6, 0xA7, 0xB7, 0xA7, 0xB8, /* 0x8C-0x8F */ - 0xA7, 0xD4, 0xA7, 0xD5, 0xA7, 0xD6, 0xA7, 0xD7, /* 0x90-0x93 */ - 0xA7, 0xD8, 0xA7, 0xA1, 0xA7, 0xA2, 0xA7, 0xA3, /* 0x94-0x97 */ - 0xA7, 0xA5, 0xA7, 0xAB, 0xA7, 0xAC, 0xA7, 0xAD, /* 0x98-0x9B */ - 0xA7, 0xAE, 0xA7, 0xAF, 0xA7, 0xB0, 0xA7, 0xB1, /* 0x9C-0x9F */ - 0xA7, 0xB2, 0xA7, 0xB3, 0xA7, 0xB4, 0xA7, 0xA7, /* 0xA0-0xA3 */ - 0xA7, 0xA8, 0xA7, 0xA9, 0xA7, 0xAA, 0xA7, 0xBD, /* 0xA4-0xA7 */ - 0xA7, 0xBE, 0xA7, 0xE5, 0xA7, 0xE6, 0xA7, 0xE7, /* 0xA8-0xAB */ - 0xA7, 0xE8, 0xA7, 0xE1, 0xA7, 0xE2, 0xA7, 0xE3, /* 0xAC-0xAF */ - 0xA7, 0xBF, 0xA7, 0xC0, 0xA7, 0xC1, 0xA7, 0xC2, /* 0xB0-0xB3 */ - 0xA7, 0xC3, 0xA7, 0xC4, 0xA7, 0xC5, 0xA7, 0xC6, /* 0xB4-0xB7 */ - 0xA7, 0xC7, 0xA7, 0xC8, 0xA7, 0xCE, 0xA7, 0xCF, /* 0xB8-0xBB */ - 0xA7, 0xD0, 0xA7, 0xD1, 0xA7, 0xD2, 0xA7, 0xD3, /* 0xBC-0xBF */ - 0xA7, 0xDA, 0xA7, 0xDB, 0xA2, 0xE3, 0xA7, 0xEC, /* 0xC0-0xC3 */ - 0xA7, 0xA6, 0xA7, 0xE0, 0xA7, 0xEF, 0xA2, 0xE1, /* 0xC4-0xC7 */ - 0xA7, 0xBC, 0xA7, 0xED, 0xA7, 0xB5, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA7, 0xB9, /* 0xCC-0xCF */ - 0xA7, 0xEA, 0x00, 0x00, 0x00, 0x00, 0xA7, 0xEB, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xA7, 0xDF, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xA2, 0xE4, 0x00, 0x00, 0x00, 0x00, 0xA7, 0xE4, /* 0xD8-0xDB */ - 0xA7, 0xEE, 0xA7, 0xE9, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ -}; - -static const unsigned char u2c_4E[512] = { - 0xEC, 0xE9, 0xEF, 0xCB, 0x00, 0x00, 0xF6, 0xD2, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xB2, /* 0x04-0x07 */ - 0xED, 0xDB, 0xDF, 0xB2, 0xDF, 0xBE, 0xF9, 0xBB, /* 0x08-0x0B */ - 0x00, 0x00, 0xDC, 0xF4, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0xF5, 0xE4, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xF3, 0xA6, 0xDD, 0xE0, 0xE1, 0xA6, 0x00, 0x00, /* 0x14-0x17 */ - 0xCE, 0xF8, 0xDC, 0xB0, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xAA, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0xF1, 0xE9, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xCD, 0xFA, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xFC, 0xAF, 0xD3, 0xA1, 0x00, 0x00, 0xF1, 0xAB, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xD1, 0xD2, 0xAC, /* 0x40-0x43 */ - 0x00, 0x00, 0xCE, 0xF9, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xFD, /* 0x48-0x4B */ - 0x00, 0x00, 0xDE, 0xBF, 0xFB, 0xBA, 0xF9, 0xB9, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0xD2, 0x00, 0x00, /* 0x54-0x57 */ - 0xE3, 0xAB, 0xEB, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0xCE, 0xFA, 0xCB, 0xF7, 0xE5, 0xA5, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xE1, /* 0x68-0x6B */ - 0x00, 0x00, 0xD4, 0xCC, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0xE1, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0xDC, 0xE3, 0xDF, 0xAD, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xCB, 0xEB, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xAF, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xF5, 0x00, 0x00, /* 0x84-0x87 */ - 0xE5, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xC0, /* 0x88-0x8B */ - 0xEC, 0xA3, 0x00, 0x00, 0xE9, 0xCD, 0x00, 0x00, /* 0x8C-0x8F */ - 0xEA, 0xA7, 0xE9, 0xF6, 0xFB, 0xBB, 0x00, 0x00, /* 0x90-0x93 */ - 0xE7, 0xE9, 0xEF, 0xCC, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xD0, 0xE6, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xC1, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xAC, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xD8, 0xCC, 0xF9, 0xF1, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xCE, 0xDF, 0xFA, 0xA4, 0xE6, 0xB2, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xFA, 0xFB, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xBD, /* 0xA8-0xAB */ - 0xCC, 0xC8, 0xEF, 0xCD, 0xD5, 0xD5, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0xA2, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xEC, 0xD1, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xE4, 0xA7, 0xEC, 0xD2, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xF6, 0xB1, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xFB, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0xD1, 0xCB, 0xBF, /* 0xC8-0xCB */ - 0x00, 0x00, 0xED, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xED, 0xA8, 0xDE, 0xC2, 0xF6, 0xE2, 0xED, 0xDC, /* 0xD4-0xD7 */ - 0xDC, 0xF5, 0xE0, 0xB9, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0xD4, 0xCE, 0x00, 0x00, 0xF4, 0xB5, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD3, 0xDB, /* 0xE0-0xE3 */ - 0xD6, 0xB5, 0xEC, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xE4, 0xE6, 0x00, 0x00, 0xF1, 0xEA, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xCB, 0xEC, 0xCB, 0xC0, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xF2, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_4F[512] = { - 0x00, 0x00, 0xD0, 0xEA, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xF9, 0xF2, 0xEC, 0xA5, 0xD0, 0xDF, /* 0x08-0x0B */ - 0x00, 0x00, 0xE7, 0xEA, 0xD0, 0xEB, 0xDC, 0xD1, /* 0x0C-0x0F */ - 0xDB, 0xE9, 0xFD, 0xCC, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0xD7, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xDA, 0xE1, 0x00, 0x00, 0xD6, 0xB6, 0x00, 0x00, /* 0x34-0x37 */ - 0xE3, 0xDF, 0x00, 0x00, 0xDE, 0xC3, 0x00, 0x00, /* 0x38-0x3B */ - 0xDE, 0xC4, 0xCA, 0xA1, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xEC, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0xA3, 0xEE, 0xB7, /* 0x44-0x47 */ - 0xF8, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0xEA, 0xC8, 0xEE, 0xB8, 0xF1, 0xAC, /* 0x4C-0x4F */ - 0xF1, 0xA5, 0xE9, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xF9, 0xBC, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xE5, 0xF9, 0xEC, 0xEA, 0xDD, 0xD6, /* 0x58-0x5B */ - 0xED, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xF8, 0xA5, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xBA, /* 0x6C-0x6F */ - 0xDB, 0xD8, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xA2, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0xD1, 0xCD, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0xED, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xEC, 0xEB, 0xDE, 0xC5, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xE3, 0xE0, 0x00, 0x00, 0xCA, 0xC9, /* 0x80-0x83 */ - 0xF2, 0xE9, 0x00, 0x00, 0xD5, 0xCE, 0x00, 0x00, /* 0x84-0x87 */ - 0xF6, 0xB6, 0x00, 0x00, 0xCE, 0xC2, 0xD6, 0xC7, /* 0x88-0x8B */ - 0x00, 0x00, 0xE3, 0xB4, 0x00, 0x00, 0xF1, 0xAD, /* 0x8C-0x8F */ - 0x00, 0x00, 0xEA, 0xE2, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xD7, 0xC2, 0x00, 0x00, /* 0x94-0x97 */ - 0xF3, 0xA7, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xEA, /* 0x98-0x9B */ - 0x00, 0x00, 0xEB, 0xEE, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xD9, 0xB2, 0xFD, 0xA5, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xF6, 0xD5, 0xD5, 0xE2, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB5, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xCC, 0xF5, 0xF5, 0xB5, /* 0xC0-0xC3 */ - 0xE4, 0xAD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xE7, 0xEB, 0xF1, 0xD5, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xBB, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xE9, 0xB5, 0x00, 0x00, 0xCC, 0xC9, /* 0xD0-0xD3 */ - 0xFA, 0xD5, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xD4, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xD7, 0xD6, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0xDC, 0xC1, 0x00, 0x00, 0xDE, 0xC6, /* 0xDC-0xDF */ - 0xFA, 0xEF, 0xE3, 0xE1, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xF3, 0xDC, 0xF6, /* 0xEC-0xEF */ - 0x00, 0x00, 0xCE, 0xFC, 0x00, 0x00, 0xDB, 0xC4, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xF8, 0xF1, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xDC, 0xE4, 0x00, 0x00, 0xE5, 0xEF, 0x00, 0x00, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_50[512] = { - 0x00, 0x00, 0x00, 0x00, 0xDC, 0xB1, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xD6, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xF3, 0xDA, 0x00, 0x00, 0xCB, 0xC1, /* 0x08-0x0B */ - 0x00, 0x00, 0xDB, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0xD9, 0xFA, 0xD3, 0xEE, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xFA, 0xB8, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xFD, 0xA6, 0xEB, 0xEF, 0x00, 0x00, /* 0x18-0x1B */ - 0xF4, 0xA6, 0x00, 0x00, 0xCC, 0xCA, 0xF3, 0xA8, /* 0x1C-0x1F */ - 0x00, 0x00, 0xF3, 0xDB, 0x00, 0x00, 0xDB, 0xA7, /* 0x20-0x23 */ - 0xF6, 0xB7, 0x00, 0x00, 0xCF, 0xE6, 0xF0, 0xF2, /* 0x24-0x27 */ - 0xCB, 0xDA, 0x00, 0x00, 0xE7, 0xD2, 0xD7, 0xC3, /* 0x28-0x2B */ - 0xF6, 0xF0, 0xE8, 0xDE, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xA6, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xE7, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xA3, /* 0x44-0x47 */ - 0xCC, 0xA7, 0xEA, 0xC9, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xB6, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xFA, 0xA5, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xAE, 0x00, 0x00, /* 0x58-0x5B */ - 0xEF, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0xCB, 0xED, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xF6, 0xB0, 0xEF, 0xCF, 0xE9, 0xCF, 0x00, 0x00, /* 0x74-0x77 */ - 0xF7, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xCE, 0xD3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0xDC, 0xF7, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0xDB, 0xA8, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xCB, 0xF8, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xDF, 0xA1, 0xDD, 0xE1, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xF5, 0xCA, 0xE9, 0xB6, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xEC, 0xEE, 0xEE, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xF3, 0xF0, 0x00, 0x00, 0xDF, 0xBF, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xCC, 0xCB, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xD0, 0xC1, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xF4, 0xD2, 0xE0, 0xBA, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xC0, /* 0xCC-0xCF */ - 0x00, 0x00, 0xCE, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xDC, 0xD2, 0xFD, 0xEA, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xF6, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0xCA, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xE8, 0xE9, 0x00, 0x00, 0xE3, 0xAC, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xF3, 0xD0, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xCA, 0xA4, 0x00, 0x00, 0xDB, 0xF8, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xC7, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_51[512] = { - 0xEB, 0xF0, 0xF1, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xE5, 0xE2, 0x00, 0x00, 0xCC, 0xCC, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xCB, 0xFB, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0xE3, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xC1, /* 0x1C-0x1F */ - 0x00, 0x00, 0xD6, 0xED, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xD0, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0xB9, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xE3, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xD1, 0xD3, 0x00, 0x00, /* 0x38-0x3B */ - 0xE5, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xE8, 0xB4, 0xEB, 0xC3, 0x00, 0x00, 0xEA, 0xAA, /* 0x40-0x43 */ - 0xFA, 0xFC, 0xF5, 0xF6, 0xF0, 0xBC, 0xFD, 0xD4, /* 0x44-0x47 */ - 0xE0, 0xBB, 0xCE, 0xC3, 0x00, 0x00, 0xD0, 0xBA, /* 0x48-0x4B */ - 0xF7, 0xBA, 0xD8, 0xF3, 0xF7, 0xCD, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xAE, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0xD4, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0xE7, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0xEC, 0xFD, 0x00, 0x00, 0xD2, 0xAE, /* 0x64-0x67 */ - 0xEE, 0xEF, 0xD5, 0xD7, 0xEA, 0xE4, 0xF8, 0xA2, /* 0x68-0x6B */ - 0xCD, 0xEB, 0xD7, 0xBF, 0xFB, 0xB1, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0xCD, 0xEC, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xDC, 0xB2, 0xD0, 0xEC, 0xCE, 0xFD, /* 0x74-0x77 */ - 0xEE, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xCC, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xD0, 0xED, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xF7, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xF3, 0xFC, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0xEE, 0xA2, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xD9, 0xB3, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0xD8, 0xF4, 0x00, 0x00, 0xE9, 0xB7, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xCE, 0xAE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xD9, 0xA2, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0xD8, 0xF1, 0x00, 0x00, /* 0xA8-0xAB */ - 0xD4, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xA7, 0xD5, 0xD2, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xD6, 0xA9, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xF4, 0xA2, 0x00, 0x00, 0xF1, 0xD7, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xD5, 0xD8, 0x00, 0x00, 0xF0, 0xBD, /* 0xC8-0xCB */ - 0xD7, 0xD0, 0xD4, 0xD0, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xD7, 0xCF, 0xEB, 0xEA, 0xFD, 0xEB, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0xDB, 0xED, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xFC, 0xC5, 0xCB, 0xC2, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xFD, 0xD5, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xF4, 0xC8, 0xE8, 0xEA, 0xF5, 0xF3, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xF9, 0xDE, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_52[512] = { - 0xD3, 0xEF, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xD3, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0xC2, 0xEF, 0xB7, /* 0x04-0x07 */ - 0xE7, 0xD4, 0x00, 0x00, 0xCA, 0xCA, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0xD9, 0xFB, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0xFA, 0xFD, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xAA, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0xF4, 0xF8, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0xF7, 0xF7, 0xDC, 0xAC, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xD7, 0xD7, 0xDF, 0xA2, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0xBE, 0x00, 0x00, /* 0x2C-0x2F */ - 0xD3, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xA4, 0xE1, 0xEC, /* 0x34-0x37 */ - 0xCF, 0xE7, 0xF3, 0xCB, 0xED, 0xA9, 0xCA, 0xBE, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0xEF, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xCE, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xDE, 0xFB, 0xD0, 0xBB, /* 0x48-0x4B */ - 0xD5, 0xB7, 0xEE, 0xF1, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xF4, 0xA8, 0x00, 0x00, 0xDC, 0xF8, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCB, 0xA7, /* 0x58-0x5B */ - 0x00, 0x00, 0xDA, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0xE0, 0xE6, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xED, 0xA5, 0xEE, 0xF2, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xF9, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xF9, 0xDC, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xF3, 0xDC, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xF8, 0xF2, 0x00, 0x00, 0xF4, 0xF9, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xF1, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xBC, /* 0x84-0x87 */ - 0xDB, 0xF9, 0xD7, 0xB1, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0xCB, 0xFC, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xF0, 0xA5, 0xCB, 0xFD, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xF4, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xED, /* 0x9C-0x9F */ - 0xCA, 0xA5, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xAB, /* 0xA0-0xA3 */ - 0xD0, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xF0, 0xBE, 0xD2, 0xBD, 0xCC, 0xA4, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xFA, 0xB6, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xCC, 0xCD, 0x00, 0x00, 0xDA, 0xFA, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xF6, 0xCF, 0x00, 0x00, 0xE9, 0xB8, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xD8, 0xF5, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0xCC, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xD7, 0xCD, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xD4, 0xD1, 0xE9, 0xED, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xCA, 0xEB, 0xD9, 0xE2, 0x00, 0x00, 0xFD, 0xB2, /* 0xD8-0xDB */ - 0x00, 0x00, 0xE3, 0xAD, 0xD6, 0xCC, 0xD9, 0xB4, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xA7, 0xEE, 0xD3, /* 0xE0-0xE3 */ - 0xD0, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xB3, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xD5, 0xE4, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xCF, 0xE8, 0x00, 0x00, 0xED, 0xC3, 0xD0, 0xB2, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0xFE, 0xDA, 0xA8, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_53[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xF8, 0xD0, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xFD, 0xD6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0xF8, 0xD1, 0x00, 0x00, 0xF8, 0xD2, /* 0x0C-0x0F */ - 0xDC, 0xD3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xDD, 0xE2, 0xFB, 0xF9, 0xDD, 0xC1, /* 0x14-0x17 */ - 0x00, 0x00, 0xE3, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xED, 0xDD, 0xCE, 0xC4, 0x00, 0x00, 0xCB, 0xA1, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0xE3, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xDD, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0xF9, 0xAF, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD2, 0xFB, /* 0x3C-0x3F */ - 0xCF, 0xA1, 0xE4, 0xA8, 0x00, 0x00, 0xF4, 0xB6, /* 0x40-0x43 */ - 0xEC, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xAE, /* 0x44-0x47 */ - 0xE7, 0xED, 0xFD, 0xC1, 0xDA, 0xE2, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0xD8, 0xB3, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0xDD, 0xE4, 0xF0, 0xEF, 0xF6, 0xF1, /* 0x50-0x53 */ - 0xFA, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xF5, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0xCF, 0x00, 0x00, /* 0x58-0x5B */ - 0xDC, 0xD4, 0x00, 0x00, 0xDC, 0xA6, 0x00, 0x00, /* 0x5C-0x5F */ - 0xEF, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0xCF, 0x00, 0x00, /* 0x64-0x67 */ - 0xE0, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xD6, /* 0x6C-0x6F */ - 0xEC, 0xD4, 0xEA, 0xCB, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xCA, 0xBF, 0xD5, 0xB0, 0x00, 0x00, 0xCF, 0xE9, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xF1, 0xED, 0x00, 0x00, 0xCC, 0xCF, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xE4, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xED, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xD7, 0xD8, 0x00, 0x00, 0xFD, 0xA7, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0xAB, /* 0x9C-0x9F */ - 0xF6, 0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xCF, 0xF0, 0xF9, 0xBD, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0xE6, 0xF4, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCB, 0xDB, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF3, 0xD1, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xE9, 0xD1, 0xF3, 0xA9, 0xD0, 0xE0, 0xE9, 0xD2, /* 0xC8-0xCB */ - 0x00, 0x00, 0xDA, 0xE3, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xE2, 0xD2, 0x00, 0x00, 0xF6, 0xA2, 0xE1, 0xF4, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xE4, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0xE7, 0xD5, 0xF5, 0xBF, 0xCF, 0xA2, /* 0xE0-0xE3 */ - 0xCD, 0xAF, 0xCF, 0xA3, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xCD, 0xB0, 0xF1, 0xFE, 0xD0, 0xA3, /* 0xE8-0xEB */ - 0xE1, 0xAF, 0xF8, 0xA3, 0x00, 0x00, 0xCA, 0xA6, /* 0xEC-0xEF */ - 0xF7, 0xBB, 0xF2, 0xEA, 0xDE, 0xC8, 0xE9, 0xD3, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xDE, 0xC9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_54[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xDE, /* 0x00-0x03 */ - 0xCA, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xF9, 0xEA, 0xD1, 0xCE, 0xEE, 0xD4, 0x00, 0x00, /* 0x08-0x0B */ - 0xD4, 0xD2, 0xD9, 0xA3, 0xFD, 0xA8, 0xD7, 0xD9, /* 0x0C-0x0F */ - 0xF7, 0xCE, 0xFA, 0xBE, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xD6, /* 0x18-0x1B */ - 0x00, 0x00, 0xD7, 0xF0, 0x00, 0x00, 0xEB, 0xE1, /* 0x1C-0x1F */ - 0xF8, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0xDC, 0xFA, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xDD, 0xC3, 0x00, 0x00, 0xF9, 0xDF, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xEF, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xFD, 0xE5, 0xF6, 0xA3, 0x00, 0x00, 0xD9, 0xFC, /* 0x38-0x3B */ - 0xFD, 0xA9, 0x00, 0x00, 0xE7, 0xEE, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xE5, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0xEF, 0xD0, 0x00, 0x00, 0xCD, 0xB1, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0xF7, 0xA2, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xF1, 0xB2, 0x00, 0x00, 0xF1, 0xB1, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0xCD, 0xB2, 0x00, 0x00, 0xDA, 0xAB, /* 0x70-0x73 */ - 0x00, 0x00, 0xCA, 0xA7, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xE2, /* 0x78-0x7B */ - 0xFB, 0xBC, 0xD9, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xEE, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xD3, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0xFB, 0xFA, 0x00, 0x00, 0xCF, 0xA4, 0x00, 0x00, /* 0x8C-0x8F */ - 0xDC, 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xF6, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xED, 0xAA, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xA1, /* 0xA8-0xAB */ - 0xCE, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xA6, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xF9, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xEC, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xE4, 0xEE, 0xF9, 0xA1, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xFB, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xF9, 0xEB, 0xEE, 0xA3, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0xEA, 0xAC, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xCA, 0xA8, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xF4, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xCD, 0xD6, 0xFC, 0xF6, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0xC9, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xD4, 0x00, 0x00, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_55[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xF8, 0xA6, 0x00, 0x00, 0xDE, 0xCA, 0xF2, 0xC6, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0xD7, 0xDA, 0x00, 0x00, /* 0x0C-0x0F */ - 0xD3, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xD8, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0xE6, /* 0x2C-0x2F */ - 0x00, 0x00, 0xF3, 0xDD, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0xE4, 0xDA, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xF6, 0xE4, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xF6, 0xF2, 0x00, 0x00, 0xDF, 0xC2, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xFD, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xF6, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0xBA, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xAF, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xE1, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xF0, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xCB, 0xD3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xE0, 0xBC, 0x00, 0x00, 0xF4, 0xCA, 0xD4, 0xFA, /* 0x84-0x87 */ - 0x00, 0x00, 0xFD, 0xAA, 0xF9, 0xE2, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xF4, 0xB7, 0xFD, 0xC2, 0xFC, 0xB0, 0x00, 0x00, /* 0x98-0x9B */ - 0xFD, 0xEC, 0xCA, 0xE2, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xBD, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xEA, 0xE7, 0xDF, 0xC3, 0xD1, 0xD2, /* 0xA8-0xAB */ - 0xCE, 0xE2, 0x00, 0x00, 0xD3, 0xA4, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xFD, 0xAB, 0x00, 0x00, 0xDF, 0xE0, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xF2, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xF0, 0x00, 0x00, /* 0xD8-0xDB */ - 0xD0, 0xEE, 0x00, 0x00, 0x00, 0x00, 0xF3, 0xAA, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xCB, /* 0xE0-0xE3 */ - 0xF6, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xE1, 0xF5, 0xF1, 0xB3, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_56[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xF7, 0xA3, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xCA, 0xA9, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xCF, 0xA5, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xC4, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xB0, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xBF, 0x00, 0x00, /* 0x30-0x33 */ - 0xF6, 0xA4, 0x00, 0x00, 0xE3, 0xB6, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xC6, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xD0, 0xEF, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xED, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xDD, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0xFC, 0xF7, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xE6, 0xBF, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xDE, 0xAD, 0x00, 0x00, 0xFA, 0xBF, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xE5, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0xED, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xD2, 0xA5, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0xFD, 0xEE, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xF5, 0xB6, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xF6, 0xDE, 0xCC, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xFC, 0xDE, 0x00, 0x00, /* 0xDC-0xDF */ - 0xEC, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xCD, 0xDD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xD6, 0xB7, 0xCD, 0xB3, 0x00, 0x00, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_57[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xD5, /* 0x00-0x03 */ - 0xE5, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xCF, 0xEA, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xD0, /* 0x08-0x0B */ - 0x00, 0x00, 0xEA, 0xCC, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0xAE, 0xEA, 0xAD, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0xF1, 0x00, 0x00, /* 0x14-0x17 */ - 0xD3, 0xA5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7, 0xCF, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xEE, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0xD0, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xF2, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xF0, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xF2, 0xA3, 0x00, 0x00, 0xF7, 0xF8, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xB3, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xA9, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0xD3, 0xBB, 0xCA, 0xEC, 0x00, 0x00, /* 0x4C-0x4F */ - 0xF1, 0xA6, 0xCB, 0xD5, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0xF7, 0xE7, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0xCD, 0xDE, 0x00, 0x00, 0xF7, 0xA4, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xC0, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0xDD, 0x00, 0x00, /* 0x6C-0x6F */ - 0xCC, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xCF, 0xA6, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xF6, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xF7, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xD3, 0xDC, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xFE, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xA7, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xEB, 0xD9, 0x00, 0x00, 0xCF, 0xA7, 0xEA, 0xAF, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xEF, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xB9, /* 0xC4-0xC7 */ - 0xF1, 0xD8, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xD8, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xF2, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xB4, /* 0xDC-0xDF */ - 0xDC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xF3, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xE3, 0xD0, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xFB, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xDB, 0xC6, 0xD0, 0xF1, 0x00, 0x00, /* 0xF8-0xFB */ - 0xD0, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_58[512] = { - 0xCF, 0xDC, 0x00, 0x00, 0xD3, 0xD1, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xCC, 0xB1, 0xF7, 0xD8, 0x00, 0x00, /* 0x04-0x07 */ - 0xCB, 0xA8, 0xEB, 0xBC, 0xE4, 0xBE, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0xDC, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xDC, 0xC2, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0xF0, 0xA7, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xC0, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xED, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xEB, /* 0x2C-0x2F */ - 0xE5, 0xE8, 0xDC, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xED, 0xDE, 0xD3, 0xF2, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xCC, 0xF7, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0xD4, 0xE7, 0xAB, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCB, 0xC3, /* 0x4C-0x4F */ - 0x00, 0x00, 0xE1, 0xB1, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xF7, 0xB2, 0x00, 0x00, 0x00, 0x00, 0xD3, 0xF3, /* 0x54-0x57 */ - 0xD3, 0xD2, 0x00, 0x00, 0xF5, 0xC0, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xDF, 0xDD, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0xEE, 0xF3, 0xE7, 0xF1, 0x00, 0x00, /* 0x60-0x63 */ - 0xFD, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xF2, 0xC8, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xF3, 0xD2, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xEE, 0xF4, 0x00, 0x00, 0xE2, 0xD3, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xD1, /* 0x80-0x83 */ - 0x00, 0x00, 0xDF, 0xEA, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0xE9, 0xBA, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xD7, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xF5, 0xCD, 0x00, 0x00, 0xF1, 0xF2, 0xFA, 0xC7, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xD9, 0xF8, 0xD4, 0xC2, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xF6, 0xE5, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDD, 0xC5, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xF2, 0xED, 0xDF, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xCB, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xDB, 0xFA, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xE8, 0xB5, 0x00, 0x00, 0xD3, 0xA6, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xFD, 0xB5, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xF9, 0xC9, 0x00, 0x00, 0xE4, 0xE2, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xFB, 0xBD, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xD7, 0xA4, 0xCE, 0xC5, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0xD5, 0xD6, 0xE6, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xE5, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xCD, /* 0xE8-0xEB */ - 0xEC, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xED, 0xE0, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xEC, 0xEC, 0xFB, 0xBE, 0xDF, 0xEB, /* 0xF8-0xFB */ - 0x00, 0x00, 0xE1, 0xF8, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_59[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xBE, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xD0, 0xF3, 0xE0, 0xAA, 0xE8, 0xE2, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xE2, 0xD4, 0xD2, 0xFD, 0x00, 0x00, /* 0x18-0x1B */ - 0xE5, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0xD9, 0xD3, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD3, 0xDE, /* 0x24-0x27 */ - 0x00, 0x00, 0xF4, 0xB8, 0xF7, 0xBC, 0xDC, 0xFD, /* 0x28-0x2B */ - 0x00, 0x00, 0xE8, 0xEC, 0xE4, 0xE7, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xE3, 0xF7, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xA8, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xFA, 0xF1, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xE5, 0xF2, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xF4, /* 0x44-0x47 */ - 0xD2, 0xAF, 0xDC, 0xE5, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0xA5, 0xF1, 0xB4, /* 0x4C-0x4F */ - 0xFC, 0xB1, 0xCC, 0xF8, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xDD, 0xC6, 0xFA, 0xD1, 0x00, 0x00, 0xF7, 0xDF, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xFA, 0xA8, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xEE, 0xF5, 0x00, 0x00, 0xDE, 0xCE, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xF3, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xF7, 0xAC, 0xEB, 0xC4, /* 0x68-0x6B */ - 0xED, 0xE1, 0xE0, 0xAB, 0xDD, 0xC7, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD2, 0xB3, /* 0x70-0x73 */ - 0xD2, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0xCA, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xFB, 0xBF, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xFD, 0xDD, 0xE5, /* 0x80-0x83 */ - 0xD8, 0xCD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xEC, 0xF4, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xF5, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xED, 0xD0, 0xD2, /* 0x94-0x97 */ - 0x00, 0x00, 0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xF6, 0xE6, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xDB, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xF7, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xD8, 0xD9, 0x00, 0x00, 0xF4, 0xA3, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0xDD, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xD1, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0xD9, 0xB5, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xED, 0xAB, 0x00, 0x00, 0xE3, 0xB7, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0xEE, 0xBB, 0xCD, 0xB4, 0x00, 0x00, 0xE0, 0xF3, /* 0xD0-0xD3 */ - 0xEA, 0xCD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xEC, 0xF5, 0xE8, 0xEE, 0x00, 0x00, /* 0xD8-0xDB */ - 0xCB, 0xA9, 0xF1, 0xAF, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xCD, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xEC, 0xA9, 0x00, 0x00, 0xF2, 0xEB, 0x00, 0x00, /* 0xE8-0xEB */ - 0xFD, 0xEF, 0x00, 0x00, 0xF9, 0xF3, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xE6, 0xC1, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xD8, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xAC, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5A[512] = { - 0x00, 0x00, 0xEA, 0xCE, 0x00, 0x00, 0xE8, 0xDF, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0xDE, 0xCF, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xD2, 0xA6, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xF4, /* 0x18-0x1B */ - 0xD1, 0xD6, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xC2, /* 0x1C-0x1F */ - 0xE3, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xE4, 0xB0, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xD8, 0xB4, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xF6, 0xA5, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xF3, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xD7, 0xA5, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xF7, 0xE8, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xE8, 0xC6, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xFB, 0xE6, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0xE6, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xDC, 0xFE, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xD8, 0xDA, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0xAC, 0xEA, 0xB0, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xE3, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xCA, 0xAA, 0xE1, 0xF9, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xEA, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xF2, 0xEC, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0xFA, 0xEE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0xEE, 0xD5, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0xF9, 0xF4, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xD2, 0xEC, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ -}; - -static const unsigned char u2c_5B[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xFB, 0xFB, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xFD, 0xF0, 0x00, 0x00, 0xE0, 0xBD, /* 0x08-0x0B */ - 0xCE, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xC6, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAE, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xDF, 0xC5, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xBE, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xED, 0xAD, 0xFA, 0xEA, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xCD, 0xEE, 0xED, 0xA6, 0x00, 0x00, 0xED, 0xAE, /* 0x54-0x57 */ - 0xF0, 0xED, 0x00, 0x00, 0xDD, 0xA1, 0x00, 0x00, /* 0x58-0x5B */ - 0xED, 0xAF, 0xFC, 0xF8, 0x00, 0x00, 0xD8, 0xEB, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xF9, /* 0x60-0x63 */ - 0xCD, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xFA, 0xA9, 0x00, 0x00, 0xE1, 0xDD, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xE2, 0xD5, 0xED, 0xCF, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xDD, 0xA2, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0xF9, 0xCA, 0x00, 0x00, 0xEA, 0xE8, 0x00, 0x00, /* 0x78-0x7B */ - 0xE5, 0xED, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0xD3, 0xEB, 0x00, 0x00, 0xE9, 0xD4, /* 0x84-0x87 */ - 0xE1, 0xFA, 0xE4, 0xCC, 0x00, 0x00, 0xE1, 0xE4, /* 0x88-0x8B */ - 0xE8, 0xC7, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xDB, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xD5, /* 0x90-0x93 */ - 0x00, 0x00, 0xF7, 0xB5, 0xFC, 0xF3, 0xF0, 0xF3, /* 0x94-0x97 */ - 0xCE, 0xAF, 0xF1, 0xB5, 0xEF, 0xD2, 0xE8, 0xC8, /* 0x98-0x9B */ - 0xEB, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0xCB, 0xD4, 0xE0, 0xBE, /* 0xA0-0xA3 */ - 0xE3, 0xF8, 0xEA, 0xE9, 0xFC, 0xB2, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xE0, 0xF4, 0x00, 0x00, 0xCF, 0xE0, 0x00, 0x00, /* 0xAC-0xAF */ - 0xEE, 0xA5, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xAA, /* 0xB0-0xB3 */ - 0xE6, 0xC3, 0xE1, 0xB2, 0xCA, 0xAB, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xE3, 0xE4, 0xE9, 0xBB, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xD6, /* 0xBC-0xBF */ - 0xF3, 0xF2, 0x00, 0x00, 0xEE, 0xD6, 0xEA, 0xB2, /* 0xC0-0xC3 */ - 0xD0, 0xF6, 0xEC, 0xD9, 0xDA, 0xCB, 0xCF, 0xA8, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0xDD, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0xD8, 0xDB, 0x00, 0x00, 0xF9, 0xCE, 0xE9, 0xD5, /* 0xD0-0xD3 */ - 0xE3, 0xD1, 0x00, 0x00, 0x00, 0x00, 0xD2, 0xBC, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xD8, 0xAC, 0xF3, 0xCC, /* 0xDC-0xDF */ - 0x00, 0x00, 0xCD, 0xFB, 0xF6, 0xD6, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xE7, 0xF5, 0xE8, 0xEF, 0xE3, 0xF9, 0xD2, 0xBB, /* 0xE4-0xE7 */ - 0xF3, 0xF3, 0xE3, 0xFB, 0x00, 0x00, 0xDE, 0xD0, /* 0xE8-0xEB */ - 0xCE, 0xB0, 0x00, 0x00, 0xD6, 0xF7, 0xF1, 0xD9, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xF5, 0xC1, 0xDC, 0xC4, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xF5, 0xBB, 0x00, 0x00, 0xDE, 0xD1, 0x00, 0x00, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_5C[512] = { - 0x00, 0x00, 0xDC, 0xE6, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xDE, 0xD2, 0x00, 0x00, 0x00, 0x00, 0xED, 0xE2, /* 0x04-0x07 */ - 0xEE, 0xF6, 0xEA, 0xCF, 0xF0, 0xEE, 0xE3, 0xFC, /* 0x08-0x0B */ - 0x00, 0x00, 0xD3, 0xDF, 0xD3, 0xF4, 0xE1, 0xB3, /* 0x0C-0x0F */ - 0x00, 0x00, 0xE1, 0xB4, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0xD3, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xDF, 0xC6, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0xE9, 0xD6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xDB, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xF6, 0xA6, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xE3, 0xB9, 0xEB, 0xC5, 0xF4, 0xA9, 0xCD, 0xB6, /* 0x38-0x3B */ - 0xD2, 0xF9, 0x00, 0x00, 0xDA, 0xAD, 0xD2, 0xE3, /* 0x3C-0x3F */ - 0xCF, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0xCB, 0xDC, 0xCC, 0xFA, 0x00, 0x00, /* 0x44-0x47 */ - 0xCF, 0xDD, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xA9, /* 0x48-0x4B */ - 0x00, 0x00, 0xE3, 0xBB, 0xE3, 0xBA, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0xE0, 0xDA, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xEE, 0xF7, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xB3, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xD3, 0xF5, 0x00, 0x00, 0xD7, 0xA6, 0x00, 0x00, /* 0x60-0x63 */ - 0xF6, 0xB5, 0xD7, 0xDB, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0xE1, 0xD5, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xEA, /* 0x6C-0x6F */ - 0x00, 0x00, 0xDF, 0xA3, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xFD, 0xDF, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xD0, 0xF7, 0xED, 0xD4, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xCB, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xE4, 0xDB, 0x00, 0x00, 0xE1, 0xFB, /* 0xA8-0xAB */ - 0xCB, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xD3, 0xE0, 0x00, 0x00, 0xE4, 0xBF, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xFB, 0xC0, 0x00, 0x00, 0xDA, 0xBE, /* 0xB4-0xB7 */ - 0xE4, 0xCD, 0x00, 0x00, 0xD6, 0xB9, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0xC0, 0x00, 0x00, /* 0xBC-0xBF */ - 0xE1, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xF6, 0xB9, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0xDF, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xE4, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xE7, /* 0xEC-0xEF */ - 0xDC, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xFA, 0xD6, 0x00, 0x00, 0xD3, 0xF6, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xDA, /* 0xF8-0xFB */ - 0x00, 0x00, 0xFA, 0xF2, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5D[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xFD, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0xD5, 0xCF, 0xD0, 0xF8, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0xCD, 0xDF, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xF5, 0xCB, 0x00, 0x00, 0xE4, 0xF0, 0xCB, 0xAB, /* 0x14-0x17 */ - 0x00, 0x00, 0xD7, 0xC4, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xFE, /* 0x24-0x27 */ - 0x00, 0x00, 0xDD, 0xDA, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xAE, /* 0x48-0x4B */ - 0xCA, 0xEE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xD5, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xE3, 0xA1, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0xE8, 0xE3, 0x00, 0x00, 0x00, 0x00, 0xF3, 0xAB, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xA9, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD3, 0xF7, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xD4, 0xF1, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xCE, 0xE4, 0x00, 0x00, 0xE8, 0xF2, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xF5, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xE7, 0xAE, 0x00, 0x00, 0xD6, 0xBA, 0x00, 0x00, /* 0xB8-0xBB */ - 0xDF, 0xEC, 0xE4, 0xC0, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0xE8, 0xE4, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xD8, 0xB5, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xDC, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0xF4, 0xB9, 0xF1, 0xB6, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0xE2, 0xDE, 0xE1, 0xB5, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xCD, 0xEF, 0xF1, 0xA7, 0xCE, 0xE5, /* 0xE4-0xE7 */ - 0xCB, 0xDD, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xE3, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0xF3, 0xAC, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0xD0, 0xF9, 0xEC, 0xAB, 0xDE, 0xD3, /* 0xF0-0xF3 */ - 0xF7, 0xE9, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xF5, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xE1, 0xDE, 0xCB, 0xEE, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5E[512] = { - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xBC, 0xF8, 0xD6, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xEE, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0xFD, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0xF7, 0xB6, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0xDE, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xF2, 0xED, 0x00, 0x00, 0xDB, 0xD9, /* 0x18-0x1B */ - 0x00, 0x00, 0xF0, 0xA8, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xE1, 0xFD, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xD4, /* 0x28-0x2B */ - 0x00, 0x00, 0xE0, 0xAC, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xE3, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0xE1, 0x00, 0x00, /* 0x34-0x37 */ - 0xDF, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xD9, 0xB6, 0x00, 0x00, 0xFD, 0xAC, /* 0x3C-0x3F */ - 0xEF, 0xD3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xE4, 0xC1, 0xF8, 0xEB, 0x00, 0x00, 0xDB, 0xAC, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xFC, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xD8, 0xAD, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xBA, /* 0x5C-0x5F */ - 0x00, 0x00, 0xDB, 0xDF, 0xD3, 0xD3, 0xF8, 0xC7, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xCE, 0xF8, 0xC1, /* 0x70-0x73 */ - 0xD2, 0xB4, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xB4, /* 0x74-0x77 */ - 0xFA, 0xB9, 0xCA, 0xCF, 0x00, 0x00, 0xFC, 0xB3, /* 0x78-0x7B */ - 0xEA, 0xEA, 0xEA, 0xEB, 0xD0, 0xFA, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xED, 0xE4, 0x00, 0x00, 0x00, 0x00, 0xDD, 0xE7, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xDF, 0xC9, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xED, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0xEE, 0xBC, 0x00, 0x00, 0xEF, 0xC1, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xCC, 0xD2, 0x00, 0x00, /* 0x98-0x9B */ - 0xDD, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xDF, 0xCA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0xF8, 0xF1, 0xA8, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xB7, /* 0xA8-0xAB */ - 0x00, 0x00, 0xEF, 0xD4, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xE4, 0xDD, 0xDF, 0xEE, 0xCB, 0xAC, /* 0xB4-0xB7 */ - 0xE9, 0xBC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0xEC, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xDF, 0xCB, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xF9, 0xBF, 0xD6, 0xAF, 0xD5, 0xC6, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0xCF, 0xAA, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xA9, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xF8, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xB7, 0xEE, 0xF8, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xD9, /* 0xDC-0xDF */ - 0xF3, 0xDF, 0x00, 0x00, 0xF8, 0xC8, 0xCE, 0xC6, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xD5, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0xE6, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xC5, 0xEF, 0xD5, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0xCB, 0xEF, 0xFC, 0xDF, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_5F[512] = { - 0x00, 0x00, 0xDC, 0xA7, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xD6, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xC9, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xD2, /* 0x0C-0x0F */ - 0x00, 0x00, 0xE3, 0xBD, 0x00, 0x00, 0xCF, 0xE1, /* 0x10-0x13 */ - 0xF0, 0xC0, 0xEC, 0xDA, 0x00, 0x00, 0xDD, 0xD7, /* 0x14-0x17 */ - 0xFB, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xAC, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xA9, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0xFA, 0xD7, 0xFB, 0xC1, /* 0x24-0x27 */ - 0x00, 0x00, 0xD2, 0xC0, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xE5, 0xB0, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0xED, 0xE5, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xCB, 0xAD, 0x00, 0x00, /* 0x38-0x3B */ - 0xF9, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0xF7, 0xA5, 0x00, 0x00, 0xCB, 0xAE, 0x00, 0x00, /* 0x48-0x4B */ - 0xDA, 0xAF, 0x00, 0x00, 0xD8, 0xB6, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0xA7, 0xFB, 0xB2, /* 0x54-0x57 */ - 0x00, 0x00, 0xFD, 0xC4, 0x00, 0x00, 0xEC, 0xAD, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xFB, 0xA1, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xE9, 0xE9, 0xEE, /* 0x64-0x67 */ - 0x00, 0x00, 0xF3, 0xF4, 0xF8, 0xF3, 0xF0, 0xC1, /* 0x68-0x6B */ - 0xDE, 0xAF, 0xF8, 0xB0, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xF3, 0xE0, 0xE7, 0xAF, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0xAD, /* 0x74-0x77 */ - 0x00, 0x00, 0xE6, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xF9, 0xA8, 0x00, 0x00, 0x00, 0x00, 0xDD, 0xD8, /* 0x7C-0x7F */ - - 0xE8, 0xD9, 0xEF, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0xD3, 0xE2, 0x00, 0x00, 0xE2, 0xDF, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xFC, 0xE0, 0xD7, 0xC8, /* 0x88-0x8B */ - 0xFD, 0xAD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xDF, 0xEF, 0xCC, 0xD3, 0xD3, 0xF9, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xF0, /* 0x94-0x97 */ - 0xDB, 0xC7, 0xDE, 0xD5, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF4, 0x00, 0x00, /* 0x9C-0x9F */ - 0xD5, 0xD0, 0xE5, 0xD9, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xFC, 0xC7, 0xDC, 0xD6, 0xE2, 0xE0, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0xB0, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xF3, 0xA3, 0x00, 0x00, 0xD3, 0xEC, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xF4, 0xCB, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xFD, 0xC5, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xFD, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xF9, 0xB1, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0xD0, 0xFB, 0xEC, 0xDB, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0xBC, 0xF2, 0xA4, /* 0xD4-0xD7 */ - 0xD8, 0xCE, 0xD8, 0xCF, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0xF5, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xE1, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xD2, 0xB7, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xFB, 0xEC, 0x00, 0x00, 0xDD, 0xC8, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_60[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xE8, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xD2, 0xC1, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xD7, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xD6, 0xBB, 0xDE, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xF7, 0xBD, 0xEC, 0xAE, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xD0, 0xE1, 0x00, 0x00, 0xE0, 0xF5, /* 0x24-0x27 */ - 0xEA, 0xB3, 0x00, 0x00, 0xCE, 0xD6, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xA5, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xEC, 0xF6, 0xE2, 0xE1, 0xE3, 0xBE, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0xFC, 0xC8, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xCD, 0xF0, 0x00, 0x00, 0xF9, 0xF6, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xDF, 0xF0, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xE5, 0xBF, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0xCE, 0xBF, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xFC, 0xE1, 0xED, 0xB0, /* 0x60-0x63 */ - 0xFD, 0xD1, 0xF6, 0xBB, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xF9, 0xCF, 0xEB, 0xDA, 0xCA, 0xC1, 0x00, 0x00, /* 0x68-0x6B */ - 0xD2, 0xB8, 0xCD, 0xF1, 0x00, 0x00, 0xE3, 0xD3, /* 0x6C-0x6F */ - 0xFD, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0xE6, 0xED, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0xE3, 0xFA, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0xF0, 0xAA, 0xF9, 0xD0, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xFC, 0xE2, 0x00, 0x00, 0xF8, 0xA7, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xE5, 0xEE, 0xF9, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xF6, /* 0x9C-0x9F */ - 0xEA, 0xED, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xB4, /* 0xA0-0xA3 */ - 0xF5, 0xC2, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xDC, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0xF0, 0xF5, 0x00, 0x00, 0xDD, 0xE8, 0xD3, 0xED, /* 0xB0-0xB3 */ - 0xF5, 0xFC, 0x00, 0x00, 0xDA, 0xBF, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xCC, 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0xD3, 0xFA, 0xF4, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xEF, 0xD7, 0x00, 0x00, 0xD4, 0xC3, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xFB, 0xE3, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xFB, 0xED, 0x00, 0x00, /* 0xD8-0xDB */ - 0xE0, 0xAD, 0x00, 0x00, 0x00, 0x00, 0xEA, 0xEE, /* 0xDC-0xDF */ - 0xFB, 0xB3, 0xE4, 0xC2, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xF6, 0xE7, 0xD2, 0xDD, 0x00, 0x00, 0xDF, 0xCC, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xFC, 0xC9, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xE5, 0xA9, 0xE0, 0xF6, 0xF6, 0xB3, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_61[512] = { - 0x00, 0x00, 0xE1, 0xFE, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xCB, 0xF0, 0x00, 0x00, /* 0x04-0x07 */ - 0xEA, 0xEF, 0xEA, 0xF0, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0xDA, 0xC0, 0xF8, 0xB4, 0xEB, 0xF2, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xE4, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xD7, 0xE4, 0xF1, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xEF, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xD7, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xFC, 0xCA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xF3, 0xE1, 0x00, 0x00, 0x00, 0x00, 0xCB, 0xC4, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xE3, 0xE5, 0x00, 0x00, 0xCB, 0xC5, 0xEA, 0xB4, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xBD, 0x00, 0x00, /* 0x40-0x43 */ - 0xD7, 0xC9, 0x00, 0x00, 0x00, 0x00, 0xEB, 0xDB, /* 0x44-0x47 */ - 0xED, 0xB1, 0x00, 0x00, 0xCC, 0xC3, 0xF7, 0xBE, /* 0x48-0x4B */ - 0xFC, 0xCB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF4, /* 0x50-0x53 */ - 0x00, 0x00, 0xD9, 0xB7, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xF3, 0xD3, 0xF3, 0xD4, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0xF7, 0xE4, 0x00, 0x00, 0xF7, 0xD1, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xD8, 0xB7, 0xCE, 0xB1, /* 0x60-0x63 */ - 0xCA, 0xC2, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xB4, /* 0x64-0x67 */ - 0xCB, 0xC6, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xF6, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xE7, 0x00, 0x00, /* 0x6C-0x6F */ - 0xEA, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0xCC, 0xD4, 0xCB, 0xAF, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xF4, 0xAA, 0xE9, 0xAF, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xF5, 0xC3, 0xE9, 0xD8, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0xE9, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xF3, 0x00, 0x00, /* 0x8C-0x8F */ - 0xD5, 0xFB, 0xDE, 0xBB, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xF4, 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xFD, 0xF3, 0xFD, 0xF2, 0xF7, 0xA6, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xDD, 0xC9, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xD3, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xCC, 0xA8, 0x00, 0x00, 0xDA, 0xC1, /* 0xA8-0xAB */ - 0xCC, 0xD5, 0x00, 0x00, 0xD9, 0xE4, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xFA, 0xCA, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xE3, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0xBC, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xF0, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xC4, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xD0, /* 0xC4-0xC7 */ - 0xFA, 0xAB, 0xEB, 0xEB, 0xE7, 0xF8, 0xD9, 0xE5, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0xD1, 0xD7, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0xF3, 0xA4, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xD4, 0xFB, 0xFC, 0xE3, /* 0xF4-0xF7 */ - 0xFA, 0xD8, 0x00, 0x00, 0xF3, 0xD5, 0x00, 0x00, /* 0xF8-0xFB */ - 0xCF, 0xAB, 0x00, 0x00, 0x00, 0x00, 0xEB, 0xF3, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_62[512] = { - 0xD5, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD3, 0xD4, /* 0x04-0x07 */ - 0xCD, 0xFC, 0x00, 0x00, 0xD9, 0xE6, 0x00, 0x00, /* 0x08-0x0B */ - 0xE2, 0xF9, 0xE2, 0xA1, 0xEB, 0xD4, 0x00, 0x00, /* 0x0C-0x0F */ - 0xE0, 0xF7, 0xE4, 0xB2, 0xCC, 0xFC, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xFB, 0xE4, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0xAB, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xBD, /* 0x1C-0x1F */ - 0x00, 0x00, 0xCA, 0xF1, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0xB8, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0xD7, 0xC0, 0x00, 0x00, /* 0x2C-0x2F */ - 0xEE, 0xFA, 0xFD, 0xF4, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xD3, 0xE3, 0x00, 0x00, 0xFB, 0xC2, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xE8, 0xDB, 0xAE, /* 0x3C-0x3F */ - 0xE1, 0xB6, 0xF8, 0xB7, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xBF, /* 0x44-0x47 */ - 0xFB, 0xC3, 0xDD, 0xEA, 0x00, 0x00, 0xE2, 0xA2, /* 0x48-0x4B */ - 0x00, 0x00, 0xEE, 0xA6, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xE8, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xF6, 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0xCA, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0xD0, 0xE2, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0xA6, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xDD, 0xEB, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xE4, 0xF9, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xAF, /* 0x7C-0x7F */ - - 0xD0, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xF4, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0xCC, 0xBC, 0xF7, 0xEA, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xE5, 0xE4, 0xDF, 0xF1, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0xF7, 0xE1, 0x00, 0x00, 0xF9, 0xF7, /* 0x94-0x97 */ - 0xEF, 0xB9, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xD8, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xA9, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xF8, 0xD9, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xEE, 0xBD, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xD8, 0xC6, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0xE4, 0xE3, 0xF5, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0xD9, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xE7, /* 0xC4-0xC7 */ - 0xD2, 0xB9, 0xD5, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0xDA, 0xE5, 0xDA, 0xD0, 0x00, 0x00, 0xD1, 0xD9, /* 0xCC-0xCF */ - 0xCE, 0xD8, 0x00, 0x00, 0xCB, 0xDE, 0xF4, 0xAC, /* 0xD0-0xD3 */ - 0xDA, 0xFB, 0x00, 0x00, 0xF6, 0xE9, 0xE8, 0xF3, /* 0xD4-0xD7 */ - 0xCF, 0xAC, 0xF0, 0xF0, 0x00, 0x00, 0xF4, 0xFD, /* 0xD8-0xDB */ - 0xDB, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xCE, 0xC0, 0xE3, 0xD4, 0xD1, 0xCF, 0xF1, 0xF5, /* 0xEC-0xEF */ - 0x00, 0x00, 0xCD, 0xF2, 0x00, 0x00, 0xCF, 0xEB, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xB8, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xA6, 0xD1, 0xDA, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_63[512] = { - 0x00, 0x00, 0xF2, 0xA5, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xA6, /* 0x04-0x07 */ - 0x00, 0x00, 0xE4, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0xD3, 0xFB, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xA9, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xC9, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0xD8, 0xE6, 0xC9, /* 0x38-0x3B */ - 0x00, 0x00, 0xD8, 0xB8, 0xFA, 0xF3, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xF3, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xF8, 0xA4, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xF3, /* 0x4C-0x4F */ - 0xE6, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xF8, 0xDA, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xE9, /* 0x64-0x67 */ - 0xDE, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0xCB, 0xDF, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xCF, 0xEC, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0xDF, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0xD1, 0xF4, 0xD2, 0xBA, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xF2, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xB7, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xE2, 0xA3, 0xD3, 0xFC, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0xED, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xC9, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xFA, 0x00, 0x00, /* 0x94-0x97 */ - 0xCF, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xD0, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xD5, 0xD3, 0xF3, 0xF5, 0xF7, 0xAE, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xEF, 0xC8, 0x00, 0x00, 0xCD, 0xF3, /* 0xA4-0xA7 */ - 0xF5, 0xCF, 0xE5, 0xF3, 0xF0, 0xC2, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xCA, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xEA, 0xF1, 0x00, 0x00, 0xD0, 0xA6, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xDA, /* 0xCC-0xCF */ - 0xF0, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xEB, 0xE7, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xC0, 0xFC, 0xB5, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0xE4, 0xC4, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xCC, 0xA9, 0xFD, 0xC6, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xEA, 0xB5, 0x00, 0x00, 0xE5, 0xAA, 0xDF, 0xBA, /* 0xF4-0xF7 */ -}; - -static const unsigned char u2c_64[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0xE1, 0xDF, 0x00, 0x00, 0xDA, 0xD1, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xE1, 0xB8, 0x00, 0x00, 0xE8, 0xF4, 0xD3, 0xFD, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xE2, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0xF2, 0xCA, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0xDA, 0xE6, 0xF7, 0xB3, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xFD, 0xCD, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xF3, 0xB6, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xEE, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xF5, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xD8, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xA7, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0xD9, 0xB8, 0xD9, 0xB9, 0xEF, 0xC9, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xD6, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xF7, 0xCB, 0xDF, 0xAE, 0xE8, 0xF5, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xD2, 0xB5, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0xD5, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xF4, 0xCC, 0xDA, 0xFC, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xE8, /* 0xA8-0xAB */ - 0x00, 0x00, 0xF7, 0xEB, 0xF5, 0xC9, 0x00, 0x00, /* 0xAC-0xAF */ - 0xF3, 0xBC, 0x00, 0x00, 0xDA, 0xD2, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD3, 0xB5, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xE8, 0xB6, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xD6, 0xCF, 0xF4, 0xBA, 0x00, 0x00, 0xF7, 0xC9, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xCC, 0xAA, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0xF0, 0xC3, 0xCC, 0xD6, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0xD3, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xD3, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xDB, 0xFB, 0x00, 0x00, 0xCB, 0xE0, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0xD3, 0xE4, 0xF6, 0xF7, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xD5, 0xBA, 0xF3, 0xCD, 0xCB, 0xE1, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xEB, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0xAD, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xFC, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0xF7, 0xEC, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xF6, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_65[512] = { - 0xDA, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xF7, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xE5, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0xE0, 0xEE, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xFD, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0xE6, 0xFC, 0xAB, /* 0x28-0x2B */ - 0xD5, 0xBB, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xA8, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0xA5, 0xCD, 0xB9, /* 0x34-0x37 */ - 0xEA, 0xF2, 0xCB, 0xC7, 0x00, 0x00, 0xCD, 0xF4, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xAF, 0xEF, 0xD9, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0xCD, 0xBA, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0xFC, 0xF9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0xDF, 0xF3, 0xCE, 0xE7, 0xDA, 0xC2, /* 0x4C-0x4F */ - 0x00, 0x00, 0xCF, 0xAD, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xF9, 0xF8, 0xA8, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xF3, 0xE2, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xF2, 0xDF, 0xA4, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xD4, 0xC4, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0xCC, 0xD7, 0xE5, 0xC2, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xCD, 0xBB, 0x00, 0x00, /* 0x70-0x73 */ - 0xEF, 0xDA, 0xEE, 0xD8, 0x00, 0x00, 0xDD, 0xA7, /* 0x74-0x77 */ - 0xE2, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC0, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xB0, 0xF8, 0xCA, /* 0x80-0x83 */ - 0x00, 0x00, 0xFC, 0xFA, 0x00, 0x00, 0xD9, 0xFE, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0xDE, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xDD, 0xEC, 0xDA, 0xE8, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xE0, /* 0x94-0x97 */ - 0x00, 0x00, 0xD6, 0xF9, 0x00, 0x00, 0xCD, 0xD7, /* 0x98-0x9B */ - 0xDE, 0xD8, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xF8, /* 0x9C-0x9F */ - 0x00, 0x00, 0xE4, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xD0, 0xC5, 0xF4, 0xAE, 0x00, 0x00, 0xDD, 0xA8, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xC5, /* 0xA8-0xAB */ - 0xF3, 0xD6, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xD9, /* 0xAC-0xAF */ - 0xE3, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD3, 0xA8, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xDB, 0xB0, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0xE5, 0xDA, 0xE3, 0xBF, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xDB, 0xB1, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xD5, 0xE9, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC1, /* 0xC8-0xCB */ - 0xEF, 0xDB, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xE9, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xD7, 0xB2, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xFD, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0xD9, 0xE9, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xFE, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xEC, 0xED, 0xD3, 0xA9, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xF2, 0xA9, 0xF0, 0xC4, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xE2, 0xE2, 0xE9, 0xEF, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0xF9, 0xD1, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xE9, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xDA, 0xDA, 0xC3, /* 0xF8-0xFB */ - 0xDA, 0xC4, 0xD4, 0xC5, 0x00, 0x00, 0xE7, 0xFA, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_66[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xCD, 0xE0, 0xE3, 0xB0, /* 0x04-0x07 */ - 0x00, 0x00, 0xDB, 0xB2, 0xFB, 0xC4, 0x00, 0x00, /* 0x08-0x0B */ - 0xF3, 0xE3, 0x00, 0x00, 0xD9, 0xA5, 0xFB, 0xE7, /* 0x0C-0x0F */ - 0xDD, 0xCB, 0xD0, 0xD4, 0x00, 0x00, 0xE6, 0xB6, /* 0x10-0x13 */ - 0xE0, 0xAE, 0xFD, 0xDA, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xDC, 0xB5, 0xE0, 0xF8, /* 0x1C-0x1F */ - 0xE7, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xF5, 0xF0, 0x00, 0x00, 0xD8, 0xDC, /* 0x24-0x27 */ - 0xED, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0xE1, 0xB9, 0x00, 0x00, 0xE3, 0xC0, /* 0x2C-0x2F */ - 0xF9, 0xC0, 0xE9, 0xF0, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xD9, 0xDB, 0x00, 0x00, 0xF3, 0xE4, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xDC, 0xB6, 0xE4, 0xE9, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xF0, 0xC5, 0xE3, 0xC1, 0xFC, 0xCC, /* 0x40-0x43 */ - 0xFC, 0xCD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xF2, 0xCB, 0x00, 0x00, 0xF2, 0xCC, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xCF, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xF1, 0xDB, 0x00, 0x00, 0xFA, 0xD9, /* 0x58-0x5B */ - 0x00, 0x00, 0xF1, 0xB8, 0xFD, 0xF5, 0xE0, 0xF9, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0xE7, 0xFB, 0xFC, 0xB7, 0xFC, 0xE4, 0xFB, 0xC5, /* 0x64-0x67 */ - 0xE3, 0xE7, 0xD8, 0xB9, 0x00, 0x00, 0xF6, 0xF8, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0xDC, 0xC5, 0xCC, 0xD8, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xAF, /* 0x70-0x73 */ - 0xF4, 0xE7, 0x00, 0x00, 0xEF, 0xDC, 0xCF, 0xFC, /* 0x74-0x77 */ - 0xEF, 0xDD, 0x00, 0x00, 0xF2, 0xAA, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xFD, 0xBE, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xAC, /* 0x84-0x87 */ - 0xFD, 0xBB, 0xFD, 0xC7, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xB2, 0x00, 0x00, /* 0x8C-0x8F */ - 0xEA, 0xD1, 0xDF, 0xF4, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xD1, 0xEC, 0xE4, 0xDE, /* 0x94-0x97 */ - 0xE5, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xD9, 0xA6, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xCD, 0xBC, 0x00, 0x00, 0xF3, 0xE5, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xD5, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xD9, 0xBA, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0xE7, 0xFB, 0xB5, /* 0xB0-0xB3 */ - 0xF8, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xE0, 0xE7, 0x00, 0x00, 0xCC, 0xD9, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xD4, 0xC6, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xE7, 0xA5, 0x00, 0x00, 0xD5, 0xF5, 0xD3, 0xBE, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xFC, 0xFB, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xF2, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xDF, 0xF5, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xE8, 0xF8, 0xF8, 0xED, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0xCE, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0xFD, 0xF6, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xE8, 0xD8, 0x00, 0x00, 0xCD, 0xD8, 0xE7, 0xD6, /* 0xF0-0xF3 */ - 0xCC, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xE3, /* 0xF4-0xF7 */ - 0xDF, 0xF6, 0xF0, 0xC7, 0xF0, 0xC6, 0x00, 0x00, /* 0xF8-0xFB */ - 0xD8, 0xBA, 0x00, 0x00, 0xF1, 0xF4, 0xF4, 0xF0, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_67[512] = { - 0xF5, 0xCC, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xE5, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xEA, 0xC5, 0xEA, 0xF3, 0x00, 0x00, 0xDD, 0xDB, /* 0x08-0x0B */ - 0x00, 0x00, 0xDC, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xDE, 0xFD, 0xF2, 0xF9, 0x00, 0x00, 0xD5, 0xC7, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xD0, /* 0x18-0x1B */ - 0x00, 0x00, 0xF0, 0xC8, 0xD1, 0xA1, 0xD1, 0xA2, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0xD9, 0xD4, 0xD6, 0xE8, /* 0x24-0x27 */ - 0xD9, 0xCA, 0x00, 0x00, 0xDA, 0xB1, 0xD8, 0xC7, /* 0x28-0x2B */ - 0xDC, 0xE2, 0xF3, 0xCE, 0xF5, 0xF4, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xF1, 0xB9, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xDA, 0xD3, 0x00, 0x00, 0xF6, 0xEA, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xCF, 0xF5, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xFD, 0xAE, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xD2, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xDF, 0xB4, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xD7, 0xDD, 0xFA, 0xBA, /* 0x4C-0x4F */ - 0xEE, 0xA7, 0xF5, 0xBD, 0x00, 0x00, 0xF8, 0xF5, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0xE8, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0xD4, 0xE1, 0x00, 0x00, 0xD1, 0xA3, 0xE1, 0xD6, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0xF9, 0xF8, 0x00, 0x00, 0xDB, 0xCA, /* 0x6C-0x6F */ - 0xCB, 0xF9, 0xD4, 0xD4, 0x00, 0x00, 0xD9, 0xDC, /* 0x70-0x73 */ - 0x00, 0x00, 0xEE, 0xBE, 0x00, 0x00, 0xF7, 0xED, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD2, 0xEE, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xE6, 0xF7, 0xF9, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDD, 0xED, /* 0x84-0x87 */ - 0x00, 0x00, 0xE8, 0xDB, 0x00, 0x00, 0xDB, 0xB3, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xF7, /* 0x8C-0x8F */ - 0xE0, 0xB0, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xE2, /* 0x90-0x93 */ - 0x00, 0x00, 0xF6, 0xD7, 0x00, 0x00, 0xD7, 0xF9, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xD8, 0xDD, 0x00, 0x00, /* 0x98-0x9B */ - 0xCD, 0xFD, 0xF2, 0xAB, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xBD, /* 0xAC-0xAF */ - 0xF8, 0xC2, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xAC, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xAD, 0xCA, 0xAE, /* 0xB4-0xB7 */ - 0xCF, 0xAE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xC2, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xDC, 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0xDA, /* 0xCC-0xCF */ - 0xD9, 0xBB, 0xCA, 0xF3, 0xF6, 0xD3, 0xE6, 0xF8, /* 0xD0-0xD3 */ - 0xEA, 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0xF6, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0xF6, 0xF9, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xCF, 0xAF, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xCA, 0xD3, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xAF, /* 0xEC-0xEF */ - 0xD2, 0xB0, 0xF1, 0xBA, 0x00, 0x00, 0xD7, 0xB3, /* 0xF0-0xF3 */ - 0xE3, 0xC3, 0xF3, 0xFD, 0xDE, 0xDA, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xDB, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0xDE, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_68[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0xE3, 0xEE, 0xFB, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xDF, 0xF7, 0xD7, 0xCA, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xCE, 0xE8, 0xDB, 0xDB, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xBB, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xF1, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xFA, 0xB7, 0xD0, 0xC6, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xCC, 0xAB, 0xEE, 0xA8, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xCB, 0xFA, 0xF9, 0xF9, 0xCC, 0xFD, 0xD3, 0xFE, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0xE4, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xF2, 0xEE, 0x00, 0x00, /* 0x4C-0x4F */ - 0xD4, 0xD5, 0xDF, 0xCD, 0x00, 0x00, 0xFC, 0xB8, /* 0x50-0x53 */ - 0xD1, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0xF2, 0xCD, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0xF7, 0xD2, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xD4, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xD5, 0xD9, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0xD8, 0xDE, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xD9, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xA9, /* 0x90-0x93 */ - 0xF6, 0xBC, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xDB, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xF0, 0xC9, 0x00, 0x00, 0xFC, 0xFC, /* 0x9C-0x9F */ - 0x00, 0x00, 0xE8, 0xC9, 0xF4, 0xFE, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xFC, /* 0xA4-0xA7 */ - 0xD7, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0xDE, 0xDC, 0x00, 0x00, 0xF0, 0xAC, /* 0xAC-0xAF */ - 0xCC, 0xFE, 0xCD, 0xE1, 0x00, 0x00, 0xE1, 0xBA, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xDB, 0xEF, 0xDA, 0xB2, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xD1, 0xA5, 0xDC, 0xB8, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xD8, 0xF6, 0x00, 0x00, 0xD1, 0xA4, /* 0xC8-0xCB */ - 0x00, 0x00, 0xCD, 0xE2, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xDC, 0xEA, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xF0, 0xF7, 0x00, 0x00, 0xF0, 0xCA, /* 0xD4-0xD7 */ - 0xD0, 0xBE, 0x00, 0x00, 0xDD, 0xDC, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xD6, /* 0xDC-0xDF */ - 0xD3, 0xD6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xD0, /* 0xE4-0xE7 */ - 0xCD, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0xDF, 0xB5, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0xDF, 0xF8, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xD4, 0xA1, 0xCE, 0xB2, 0x00, 0x00, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_69[512] = { - 0xE8, 0xCA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xEB, 0xF5, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0xE3, 0xD5, 0xF5, 0xD0, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0xA1, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xA7, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xE5, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xE6, 0xCB, 0x00, 0x00, 0xF5, 0xF1, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xC5, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xA3, /* 0x50-0x53 */ - 0xE0, 0xDB, 0xF6, 0xEB, 0x00, 0x00, 0xCB, 0xF1, /* 0x54-0x57 */ - 0x00, 0x00, 0xD9, 0xEA, 0xF5, 0xA2, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xD7, 0xD1, 0x00, 0x00, /* 0x5C-0x5F */ - 0xD1, 0xF8, 0xEA, 0xF8, 0xEA, 0xF9, 0xDA, 0xB3, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xEF, 0xDF, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xEF, /* 0x68-0x6B */ - 0x00, 0x00, 0xE5, 0xF6, 0xEE, 0xBF, 0xE2, 0xE4, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xD0, 0xBF, 0x00, 0x00, 0xFA, 0xAC, /* 0x74-0x77 */ - 0xF5, 0xD1, 0xE7, 0xB3, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0xE9, 0xBE, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xCE, /* 0x98-0x9B */ - 0xDB, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xFC, 0xCE, 0x00, 0x00, 0xDD, 0xEE, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xB4, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xD7, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7, 0xB4, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xCD, 0xBE, 0x00, 0x00, 0xDA, 0xE9, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xB0, /* 0xC8-0xCB */ - 0xF7, 0xD9, 0xF3, 0xE6, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0xCE, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xCE, 0xAA, 0x00, 0x00, 0xCB, 0xC8, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xA7, /* 0xF8-0xFB */ - 0x00, 0x00, 0xF0, 0xCB, 0x00, 0x00, 0xD0, 0xC7, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_6A[512] = { - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xC5, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xE0, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0xD5, 0xDA, 0x00, 0x00, 0xD7, 0xA7, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xC0, /* 0x14-0x17 */ - 0x00, 0x00, 0xF8, 0xF6, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0xD2, 0xED, 0xE9, /* 0x1C-0x1F */ - 0x00, 0x00, 0xD9, 0xBC, 0x00, 0x00, 0xE5, 0xC6, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0xF5, 0xA3, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xDA, 0xD4, 0xE2, 0xA7, 0xFB, 0xFC, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xF1, 0xDC, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xCA, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0xE8, 0xFA, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xE9, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xF8, 0xE2, 0xE5, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xD0, 0xB9, 0xD4, 0xF2, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xA6, /* 0x5C-0x5F */ - 0x00, 0x00, 0xDF, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xF4, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xD3, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xCC, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0xEF, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0xE5, 0xE5, 0xD0, 0xD5, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0xFC, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xFC, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0xCB, 0xFE, 0xED, 0xEA, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xB1, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xE3, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xD4, 0xA2, 0xCF, 0xF6, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xD0, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xEA, 0xF1, 0xEE, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xFA, 0xCB, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xA1, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_6B[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xD5, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xCF, 0xED, 0x00, 0x00, /* 0x08-0x0B */ - 0xED, 0xEB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xB2, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xBC, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xFD, 0xE2, 0xF3, 0xAD, 0x00, 0x00, 0xFD, 0xDB, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xB0, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xD1, 0xA7, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xFD, 0xE3, 0xCE, 0xB3, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xFD, 0xE4, 0xFA, 0xCE, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xCA, 0xB0, 0x00, 0x00, 0xF7, 0xA7, 0x00, 0x00, /* 0x4C-0x4F */ - 0xCF, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xA2, /* 0x5C-0x5F */ - 0x00, 0x00, 0xFC, 0xB6, 0xF2, 0xAD, 0xEF, 0xE1, /* 0x60-0x63 */ - 0xF3, 0xAE, 0xDC, 0xC6, 0xD9, 0xEB, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xE0, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xA8, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xF6, /* 0x74-0x77 */ - 0xCF, 0xFD, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xDD, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xD1, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xEA, /* 0x80-0x83 */ - 0xF2, 0xCF, 0x00, 0x00, 0xF7, 0xBF, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0xE2, 0xE6, 0xE2, 0xA8, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xD6, 0x00, 0x00, /* 0x94-0x97 */ - 0xED, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xF9, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xB1, 0xDE, 0xB2, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE8, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xD3, 0xAB, 0x00, 0x00, 0xEB, 0xDC, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xDF, 0xAF, 0x00, 0x00, /* 0xB8-0xBB */ - 0xCA, 0xC3, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xFC, /* 0xBC-0xBF */ - 0x00, 0x00, 0xFD, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xEB, 0xF6, 0xCF, 0xB2, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xEC, /* 0xC8-0xCB */ - 0x00, 0x00, 0xD9, 0xBD, 0x00, 0x00, 0xD8, 0xDF, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xD4, 0xB8, 0xEB, 0xBE, /* 0xD0-0xD3 */ - 0xDD, 0xEF, 0x00, 0x00, 0xDD, 0xF0, 0xDD, 0xF1, /* 0xD4-0xD7 */ - 0xDD, 0xF2, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xBE, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xC6, /* 0xE8-0xEB */ - 0xCF, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ -}; - -static const unsigned char u2c_6C[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xEE, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xAB, /* 0x0C-0x0F */ - 0x00, 0x00, 0xDA, 0xC5, 0x00, 0x00, 0xD8, 0xEC, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xA8, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xE2, 0xA9, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xBC, /* 0x34-0x37 */ - 0xE7, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xF0, 0x00, 0x00, /* 0x3C-0x3F */ - 0xEF, 0xE2, 0xF1, 0xF0, 0xCF, 0xB4, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xF1, 0x00, 0x00, /* 0x4C-0x4F */ - 0xE0, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xDF, 0xA5, 0x00, 0x00, 0xF9, 0xD2, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xFD, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0xE6, 0xA3, 0xFB, 0xF1, 0xCB, 0xB0, /* 0x5C-0x5F */ - 0xF2, 0xAE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xCD, 0xE7, 0x00, 0x00, 0xE8, 0xDC, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0xE7, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xF7, 0xC0, 0x00, 0x00, 0xD0, 0xE3, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0xA1, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0xCC, 0xBD, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xD1, 0xA9, 0xDD, 0xCC, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xE3, 0xFE, 0xD1, 0xAA, 0xE8, 0xAA, /* 0x80-0x83 */ - 0x00, 0x00, 0xEA, 0xB6, 0xF9, 0xFA, 0xE6, 0xCC, /* 0x84-0x87 */ - 0xF6, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0xD4, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xD9, 0xCB, 0x00, 0x00, 0xD9, 0xD2, 0xD3, 0xCB, /* 0x90-0x93 */ - 0xD8, 0xF7, 0xDA, 0xA9, 0xF5, 0xF8, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xDE, 0xDE, 0xF2, 0xAF, 0xF8, 0xA9, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xC8, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0xC1, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xC1, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xDD, 0xF3, 0xEA, 0xFA, 0x00, 0x00, 0xF6, 0xBD, /* 0xB8-0xBB */ - 0xE1, 0xBB, 0xCD, 0xBF, 0xF4, 0xD4, 0xE6, 0xCD, /* 0xBC-0xBF */ - 0x00, 0x00, 0xFC, 0xCF, 0xFB, 0xA2, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xE0, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xF4, 0xBB, 0xDA, 0xD5, 0x00, 0x00, /* 0xC8-0xCB */ - 0xF9, 0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xF2, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xDB, 0xF6, 0x00, 0x00, 0xDE, 0xDF, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0xF2, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0xF8, 0xDC, 0xF7, 0xEE, 0xEB, 0xE8, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xD2, 0xFA, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xF1, 0xBC, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xDA, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0xEA, 0xDA, 0xC6, /* 0xEC-0xEF */ - 0xF7, 0xC1, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xB6, /* 0xF0-0xF3 */ -}; - -static const unsigned char u2c_6D[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xC7, /* 0x08-0x0B */ - 0xD6, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0xDC, 0xC7, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xA9, /* 0x14-0x17 */ - 0x00, 0x00, 0xE2, 0xAA, 0x00, 0x00, 0xD5, 0xA6, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xD4, 0xD7, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xF2, 0xD0, 0x00, 0x00, 0xEA, 0xFB, /* 0x24-0x27 */ - 0x00, 0x00, 0xE0, 0xDD, 0xFB, 0xF3, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xBD, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0xE2, 0xE7, 0xFD, 0xD7, 0x00, 0x00, /* 0x34-0x37 */ - 0xCE, 0xC8, 0xEA, 0xB7, 0x00, 0x00, 0xFC, 0xC0, /* 0x38-0x3B */ - 0x00, 0x00, 0xFD, 0xE7, 0xF7, 0xEF, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xD7, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xEF, 0xBA, 0xF1, 0xDD, 0x00, 0x00, /* 0x58-0x5B */ - 0xDE, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xCB, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xDD, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xFB, 0xC7, 0xD5, 0xC8, 0x00, 0x00, /* 0x68-0x6B */ - 0xD7, 0xDF, 0x00, 0x00, 0xDD, 0xA9, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xE9, 0xB1, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xAD, /* 0x74-0x77 */ - 0xF6, 0xD9, 0xFA, 0xF4, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xAA, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0xE6, 0xEE, 0x00, 0x00, 0xCC, 0xDC, /* 0x84-0x87 */ - 0xE1, 0xBC, 0xE0, 0xEF, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0xE9, 0xBF, 0xFC, 0xFD, 0xE6, 0xCE, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xE1, 0xD7, 0x00, 0x00, 0xE6, 0xCF, /* 0x90-0x93 */ - 0x00, 0x00, 0xF4, 0xF1, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xF3, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xFB, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xF9, 0xE4, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xEF, 0xE3, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xEE, /* 0xC0-0xC3 */ - 0xF6, 0xBE, 0xE0, 0xB2, 0xFC, 0xFE, 0xD1, 0xAB, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xFA, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xC8, /* 0xCC-0xCF */ - 0x00, 0x00, 0xE2, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xD4, 0xA3, 0xF0, 0xF8, 0xD7, 0xA8, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xE7, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0xD3, 0xBF, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xEF, 0xE4, 0x00, 0x00, 0xD7, 0xC5, 0xEB, 0xE2, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0xFC, 0xE7, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0xE4, 0xA2, 0x00, 0x00, 0xE2, 0xE8, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xE6, 0xD0, 0x00, 0x00, 0xFB, 0xE8, /* 0xF4-0xF7 */ - 0xF4, 0xE8, 0xE5, 0xF4, 0xF4, 0xBC, 0xF4, 0xD5, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_6E[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xB6, /* 0x14-0x17 */ - 0x00, 0x00, 0xFC, 0xB9, 0xEE, 0xC2, 0xCA, 0xF5, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xE5, /* 0x1C-0x1F */ - 0xCB, 0xE2, 0xD4, 0xA4, 0x00, 0x00, 0xDE, 0xE0, /* 0x20-0x23 */ - 0xDA, 0xFD, 0xE4, 0xC6, 0xE8, 0xBE, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xDE, /* 0x28-0x2B */ - 0xF6, 0xB4, 0xEA, 0xD2, 0x00, 0x00, 0xF9, 0xFB, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC2, 0x00, 0x00, /* 0x30-0x33 */ - 0xCA, 0xE4, 0x00, 0x00, 0xE7, 0xB7, 0x00, 0x00, /* 0x34-0x37 */ - 0xEA, 0xFD, 0x00, 0x00, 0xD9, 0xDD, 0x00, 0x00, /* 0x38-0x3B */ - 0xDA, 0xB4, 0xEE, 0xAA, 0xFB, 0xE9, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0xCB, /* 0x40-0x43 */ - 0xDA, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xBE, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0xD3, 0xAC, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xFB, 0xC9, 0x00, 0x00, /* 0x54-0x57 */ - 0xDF, 0xCF, 0x00, 0x00, 0x00, 0x00, 0xD3, 0xC0, /* 0x58-0x5B */ - 0xE3, 0xD7, 0x00, 0x00, 0xEF, 0xE6, 0xFC, 0xD0, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xC0, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF5, 0xD3, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0xEC, 0xDC, 0xF7, 0xB7, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0xB8, 0xD1, 0xF9, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0xDC, 0xC8, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xEA, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xDE, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xD7, 0xB6, 0xCF, 0xB5, 0x00, 0x00, 0xD9, 0xA8, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0xEC, 0xEE, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xDD, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0xCD, 0xA2, 0xE8, 0xAE, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xBD, /* 0xAC-0xAF */ - 0x00, 0x00, 0xF2, 0xD1, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xC1, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xD2, 0xFC, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xB5, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xF3, 0xE7, 0xD8, 0xFE, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xFC, 0xD1, 0x00, 0x00, 0xED, 0xB2, /* 0xC8-0xCB */ - 0xF4, 0xAF, 0x00, 0x00, 0xFB, 0xA3, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xFC, 0xC1, 0x00, 0x00, 0xEE, 0xAB, /* 0xD0-0xD3 */ - 0xD4, 0xA5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0xF2, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xEE, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xFB, 0xCA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0xCD, 0xE3, 0xD8, 0xBB, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_6F[512] = { - 0x00, 0x00, 0xE5, 0xDB, 0xF8, 0xF7, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xF6, 0xD4, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xA9, /* 0x0C-0x0F */ - 0x00, 0x00, 0xCB, 0xC9, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xE6, 0xD1, 0xF0, 0xCC, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xD8, 0xAE, 0x00, 0x00, 0xF9, 0xD3, 0xD5, 0xFE, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xBC, /* 0x28-0x2B */ - 0xF2, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xE2, 0xAB, 0xF3, 0xE8, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xEF, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xEC, /* 0x3C-0x3F */ - 0x00, 0x00, 0xE7, 0xB8, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0xDA, 0xFE, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xCC, 0xBE, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xFC, /* 0x54-0x57 */ - 0xDA, 0xEB, 0x00, 0x00, 0xE2, 0xD8, 0xED, 0xD6, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xD1, 0xE0, 0xB3, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xFC, 0xD2, 0x00, 0x00, /* 0x60-0x63 */ - 0xEB, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0xD3, 0xC1, 0xF0, 0xCD, 0x00, 0x00, /* 0x6C-0x6F */ - 0xCF, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0xD2, 0x00, 0x00, /* 0x78-0x7B */ - 0xD4, 0xD8, 0xDC, 0xC9, 0xD7, 0xF1, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xDF, 0xBB, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xF3, 0xA5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xF4, 0xCD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0xF1, 0xBF, 0xF8, 0xB1, 0x00, 0x00, /* 0x8C-0x8F */ - 0xE9, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xFB, 0xCB, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xD5, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xD4, /* 0xA0-0xA3 */ - 0xF7, 0xCA, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xC8, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xFC, 0xE8, 0xF3, 0xBD, /* 0xAC-0xAF */ - 0x00, 0x00, 0xEE, 0xFE, 0x00, 0x00, 0xE7, 0xFE, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xD3, 0xC2, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0xB6, 0x00, 0x00, /* 0xBC-0xBF */ - 0xCC, 0xAD, 0xF6, 0xFA, 0xD6, 0xB2, 0xD2, 0xD8, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xD8, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xE3, 0xA5, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xB9, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xAD, /* 0xDC-0xDF */ - 0xFB, 0xCC, 0xEB, 0xA1, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xD4, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xFB, 0xCD, 0x00, 0x00, 0xD5, 0xBD, /* 0xE8-0xEB */ - 0xF1, 0xDF, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xFB, /* 0xEC-0xEF */ - 0x00, 0x00, 0xDE, 0xB4, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xEB, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_70[512] = { - 0x00, 0x00, 0xE5, 0xC8, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xFB, 0xA4, 0xD4, 0xB9, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xDE, 0xE1, 0x00, 0x00, 0xE4, 0xA3, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xB7, /* 0x0C-0x0F */ - 0x00, 0x00, 0xF8, 0xEE, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xDE, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xD6, 0xD2, 0x00, 0x00, 0xF9, 0xD5, 0xE7, 0xBA, /* 0x18-0x1B */ - 0xEB, 0xD5, 0xD5, 0xF7, 0xEF, 0xE7, 0xE1, 0xBE, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xAE, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xE9, /* 0x24-0x27 */ - 0xD6, 0xEE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xBB, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xCB, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xB3, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xCE, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xFB, 0xA5, 0xE1, 0xEE, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xF7, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0xFB, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xBD, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xFD, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xFC, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0xCF, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xED, 0xC7, 0xEE, 0xAC, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0xCC, 0xDD, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xF6, 0xA7, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xFA, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0xA4, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xFD, 0xDC, 0xED, 0xB3, 0xCE, 0xC9, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xEF, 0xE8, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xE1, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xDB, /* 0xA8-0xAB */ - 0xCB, 0xE3, 0xF7, 0xA9, 0x00, 0x00, 0xFB, 0xA6, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xB9, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xC0, /* 0xB4-0xB7 */ - 0xED, 0xC8, 0xEF, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xD6, 0xAD, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xCE, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xA1, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xFB, 0xF4, 0xD5, 0xA7, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0xF1, 0xF6, 0x00, 0x00, 0xE6, 0xD3, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0xCC, 0xDE, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xF8, 0xB2, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xDC, 0xEB, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_71[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xFD, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xE5, 0xEA, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0xF1, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xDB, 0xCC, 0xDD, 0xCD, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xD4, 0xC8, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xD9, 0xED, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0xA5, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xE6, 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xD4, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xC8, /* 0x44-0x47 */ - 0x00, 0x00, 0xD6, 0xA1, 0xFD, 0xBF, 0x00, 0x00, /* 0x48-0x4B */ - 0xFC, 0xD3, 0x00, 0x00, 0xEF, 0xA1, 0x00, 0x00, /* 0x4C-0x4F */ - 0xE7, 0xBC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xD1, 0xEE, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xE6, 0xD5, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0xE9, 0xF2, 0x00, 0x00, 0xDF, 0xB0, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0xD8, 0xE0, 0xFC, 0xBA, 0xFD, 0xAF, 0xF0, 0xCE, /* 0x64-0x67 */ - 0x00, 0x00, 0xDB, 0xE1, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0xE5, 0xC9, 0x00, 0x00, 0xED, 0xB4, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xE0, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xE3, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0xE9, 0xFB, 0xEA, 0xA8, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xB7, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xFB, 0xA7, 0x00, 0x00, /* 0x90-0x93 */ - 0xE9, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xFD, 0xF7, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xD9, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0xDC, 0xEC, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xE8, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xE6, 0xF0, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xFD, 0xF8, 0xFD, 0xF9, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xF6, 0xBF, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xE7, 0xA7, 0x00, 0x00, 0xE6, 0xD7, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xD4, 0xF3, 0xD4, 0xC9, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xFA, 0x00, 0x00, /* 0xCC-0xCF */ - 0xD7, 0xF2, 0x00, 0x00, 0xE1, 0xC0, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xDB, 0xE2, 0xE6, 0xD8, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xBD, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xF0, 0xCF, 0xF3, 0xBE, 0xE2, 0xAC, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xF5, 0xB7, 0xE0, 0xF0, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xB8, /* 0xF8-0xFB */ - 0xE3, 0xE8, 0x00, 0x00, 0xD4, 0xA7, 0xE8, 0xFC, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_72[512] = { - 0xFA, 0xD2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xEF, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xD6, 0xD3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xB4, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xD0, 0x00, 0x00, /* 0x28-0x2B */ - 0xF7, 0xF0, 0xEE, 0xB3, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xEA, 0xBA, 0x00, 0x00, 0xEA, 0xD3, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0xED, 0xC9, 0xDD, 0xAB, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xAC, 0xFD, 0xA1, /* 0x38-0x3B */ - 0x00, 0x00, 0xDF, 0xD0, 0xEC, 0xB3, 0x00, 0x00, /* 0x3C-0x3F */ - 0xDF, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0xED, 0xF8, 0xB8, /* 0x44-0x47 */ - 0xF7, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xF8, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0xE0, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xD4, 0xBA, 0xE4, 0xB3, 0x00, 0x00, 0xE9, 0xDA, /* 0x58-0x5B */ - 0x00, 0x00, 0xDE, 0xB6, 0x00, 0x00, 0xD9, 0xBF, /* 0x5C-0x5F */ - 0x00, 0x00, 0xD9, 0xC0, 0xD6, 0xEF, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xCC, /* 0x64-0x67 */ - 0x00, 0x00, 0xDA, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xDF, 0xE5, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xF7, 0xE5, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xCC, 0xB2, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xDF, 0xF9, 0xD7, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0xD4, 0xBB, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFA, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xCC, 0xB3, 0x00, 0x00, 0x00, 0x00, 0xDB, 0xF3, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xDF, 0xD2, 0x00, 0x00, 0xCE, 0xCA, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xEE, 0xDA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xE4, 0x00, 0x00, /* 0xCC-0xCF */ - 0xFB, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xB7, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xEE, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0xCE, 0xEA, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xE2, 0xAD, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xD7, 0xE1, 0xFA, 0xF5, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0xD5, 0xC9, 0xF8, 0xAC, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_73[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xD9, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xF3, 0xE9, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xED, /* 0x18-0x1B */ - 0xE3, 0xC4, 0xF0, 0xF1, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xE8, 0xE5, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xE0, 0xFA, 0xEE, 0xC4, 0xD9, 0xDE, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xEB, 0xA2, 0xEB, 0xA3, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xFC, 0xC2, 0xEA, 0xBB, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xE8, 0xAB, 0xDE, 0xE2, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xED, 0xEF, 0x00, 0x00, 0xE8, 0xA3, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xF1, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xD4, 0xBC, 0x00, 0x00, 0xFC, 0xEA, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xE7, 0xBE, 0x00, 0x00, 0xFC, 0xF2, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xD6, 0xB4, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0xE2, 0xAE, 0x00, 0x00, 0xD3, 0xB7, 0xFA, 0xCC, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xFA, 0xDC, 0x00, 0x00, 0xED, 0xB5, 0xE1, 0xE3, /* 0x84-0x87 */ - 0x00, 0x00, 0xE8, 0xAC, 0x00, 0x00, 0xE8, 0xDD, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0xE9, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xF4, 0xBD, 0x00, 0x00, 0xCF, 0xB8, 0xE9, 0xDB, /* 0x94-0x97 */ - 0xD1, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xC7, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEB, 0xC9, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xE8, 0xCC, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0xDE, 0xB7, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xBC, 0xD3, 0xE5, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xFA, 0xDD, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xDA, 0xD6, 0x00, 0x00, 0xCA, 0xB1, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xDA, 0xC8, 0xDF, 0xA6, 0x00, 0x00, /* 0xC8-0xCB */ - 0xF9, 0xB3, 0xF2, 0xD2, 0x00, 0x00, 0xCA, 0xC4, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0xCB, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xCD, 0xF5, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0xFD, 0xB0, 0xD5, 0xA8, 0x00, 0x00, /* 0xDC-0xDF */ - 0xF1, 0xC1, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xE9, /* 0xE0-0xE3 */ - 0xDC, 0xCA, 0xEC, 0xB4, 0xFA, 0xC0, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xFB, 0xA8, 0xD0, 0xA8, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xDA, 0xEC, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xEE, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xE0, 0xFB, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xEF, 0xEA, 0xFA, 0xDE, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_74[512] = { - 0x00, 0x00, 0xE0, 0xC4, 0x00, 0x00, 0xCF, 0xB9, /* 0x00-0x03 */ - 0x00, 0x00, 0xD5, 0xCA, 0xD7, 0xE2, 0xE2, 0xAF, /* 0x04-0x07 */ - 0x00, 0x00, 0xD7, 0xB8, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xCD, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xDA, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xEF, 0xA2, 0xE2, 0xDA, 0xF6, 0xFC, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xFB, 0xD0, 0xD1, 0xAD, 0x00, 0x00, /* 0x24-0x27 */ - 0xCD, 0xE4, 0x00, 0x00, 0xD1, 0xAE, 0xDC, 0xED, /* 0x28-0x2B */ - 0xE8, 0xCE, 0x00, 0x00, 0xF0, 0xF9, 0xCE, 0xB5, /* 0x2C-0x2F */ - 0xE6, 0xFC, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xFB, /* 0x30-0x33 */ - 0xD0, 0xD6, 0xDD, 0xF5, 0xF7, 0xF1, 0x00, 0x00, /* 0x34-0x37 */ - 0xF6, 0xFD, 0x00, 0x00, 0xDB, 0xF7, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xEA, /* 0x3C-0x3F */ - 0xE9, 0xDC, 0xD9, 0xC1, 0x00, 0x00, 0xF5, 0xF2, /* 0x40-0x43 */ - 0xE0, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0xD4, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xF9, 0xC2, 0x00, 0x00, 0xEA, 0xBC, /* 0x54-0x57 */ - 0x00, 0x00, 0xD2, 0xC5, 0xFB, 0xD1, 0xE7, 0xC0, /* 0x58-0x5B */ - 0xEB, 0xA5, 0x00, 0x00, 0xDF, 0xFA, 0xE3, 0xA2, /* 0x5C-0x5F */ - 0xD7, 0xB9, 0x00, 0x00, 0xE9, 0xC3, 0x00, 0x00, /* 0x60-0x63 */ - 0xE8, 0xFD, 0xE8, 0xAF, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xF2, 0xD3, 0xFB, 0xA9, 0xD8, 0xA5, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xCB, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0xC8, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xD1, 0xAF, 0xD7, 0xE3, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC6, /* 0x84-0x87 */ - 0x00, 0x00, 0xD6, 0xA2, 0x00, 0x00, 0xED, 0xF0, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xD7, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xFC, 0xD4, 0x00, 0x00, 0xDA, 0xD7, 0xCC, 0xDF, /* 0x9C-0x9F */ - 0x00, 0x00, 0xF2, 0xD4, 0x00, 0x00, 0xD1, 0xB0, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xCC, 0xE0, 0x00, 0x00, 0xDB, 0xFD, /* 0xA4-0xA7 */ - 0xF3, 0xBF, 0x00, 0x00, 0xF0, 0xD1, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0xFC, 0xBB, 0x00, 0x00, 0xE2, 0xB0, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xE6, 0xA5, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xE2, 0xDB, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xDF, 0xDE, 0x00, 0x00, 0xE0, 0xC7, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0xF2, 0xEF, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xCC, 0xE1, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xEA, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xE7, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xCE, 0xB6, 0x00, 0x00, 0xF3, 0xC0, 0x00, 0x00, /* 0xD8-0xDB */ - 0xCD, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0xFB, 0xD2, 0x00, 0x00, 0xF8, 0xF8, 0xF7, 0xFB, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xBF, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xB7, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xB6, /* 0xF4-0xF7 */ -}; - -static const unsigned char u2c_75[512] = { - 0x00, 0x00, 0xDC, 0xBA, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xCC, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0xF1, 0xF7, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xE8, 0xB8, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xCA, 0xF6, 0x00, 0x00, 0xE4, 0xA4, 0xF4, 0xD6, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xE6, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xA7, /* 0x20-0x23 */ - 0x00, 0x00, 0xDF, 0xE7, 0xE1, 0xC1, 0x00, 0x00, /* 0x24-0x27 */ - 0xE9, 0xC4, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xCB, /* 0x28-0x2B */ - 0xE9, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xEF, 0xA3, 0xEB, 0xA6, 0xCB, 0xA3, 0xE3, 0xE9, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xFB, /* 0x34-0x37 */ - 0xEF, 0xA4, 0x00, 0x00, 0xEF, 0xEB, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xB4, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xCD, 0xA3, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xE6, /* 0x4C-0x4F */ - 0x00, 0x00, 0xEF, 0xA5, 0x00, 0x00, 0xD3, 0xCC, /* 0x50-0x53 */ - 0xDA, 0xED, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xD7, 0xBA, 0x00, 0x00, 0xF2, 0xD5, /* 0x58-0x5B */ - 0xF5, 0xE5, 0xD9, 0xEF, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xF9, 0xB4, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0xD5, 0xD4, 0xFD, 0xCF, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xE3, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xE1, /* 0x6C-0x6F */ - 0xEC, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xFB, 0xFE, 0xD3, 0xD7, 0x00, 0x00, /* 0x74-0x77 */ - 0xD1, 0xB1, 0x00, 0x00, 0xCB, 0xB1, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xB2, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0xCB, 0xB2, 0xF1, 0xC2, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0xE1, 0xF9, 0xB5, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xC3, 0xE1, 0xC2, /* 0x8C-0x8F */ - 0x00, 0x00, 0xEB, 0xF7, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xDF, 0xA8, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xCB, 0xCA, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xB9, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xF8, 0xDE, 0xF9, 0xAA, 0xCA, 0xF7, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xED, 0xB7, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xD3, 0xB8, 0xF2, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0xD4, 0xD9, 0xEE, 0xC5, 0xF2, 0xF0, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xB2, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xDC, 0xBB, 0x00, 0x00, 0xF1, 0xF8, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0xEC, 0xB7, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xCA, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xF6, 0xC0, 0xFD, 0xDD, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xD4, 0xE3, 0xCC, 0xE2, 0x00, 0x00, 0xF7, 0xD4, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xD7, 0xE5, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xD3, 0xC3, 0x00, 0x00, 0xD8, 0xA6, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xF6, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0xF6, 0x00, 0x00, /* 0xF8-0xFB */ - 0xCD, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_76[512] = { - 0xE5, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0xE5, 0xCB, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xE1, 0xC4, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xB0, /* 0x1C-0x1F */ - 0xF4, 0xB0, 0xF3, 0xEA, 0xDA, 0xEE, 0x00, 0x00, /* 0x20-0x23 */ - 0xD7, 0xBB, 0x00, 0x00, 0xE2, 0xB1, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xAA, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xFB, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xE4, 0xDF, 0x00, 0x00, 0xCA, 0xD6, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xEB, 0xA8, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xFE, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0xF6, 0xC2, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0xEF, 0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xD4, 0xFD, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0xE0, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xE8, 0xB9, 0x00, 0x00, 0xEF, 0xA6, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0xCD, 0xA4, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xF4, /* 0x78-0x7B */ - 0xDB, 0xA1, 0xDB, 0xDC, 0xDB, 0xDD, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xEE, 0xDC, 0x00, 0x00, 0xCB, 0xCB, 0xFC, 0xD5, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0xEB, 0x00, 0x00, /* 0x8C-0x8F */ - 0xCD, 0xC1, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xD3, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xF9, 0xAB, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0xD4, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xA9, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xDD, 0xDB, 0xCD, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0xCE, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xE7, 0xC3, 0x00, 0x00, 0xEC, 0xCC, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xF9, 0xEC, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xCB, 0xCC, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFC, /* 0xD8-0xDB */ - 0xD4, 0xA8, 0x00, 0x00, 0xED, 0xD3, 0xD8, 0xEF, /* 0xDC-0xDF */ - 0x00, 0x00, 0xF2, 0xD7, 0x00, 0x00, 0xCA, 0xF8, /* 0xE0-0xE3 */ - 0xDA, 0xEF, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xD4, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0xD9, 0xCD, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0xD8, 0xEE, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xF2, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xDF, 0xD3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0xDA, 0xF0, 0x00, 0x00, 0xE2, 0xEA, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_77[512] = { - 0x00, 0x00, 0xE0, 0xFD, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xD8, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xF7, 0xAF, 0xDA, 0xB6, 0x00, 0x00, 0xCA, 0xD7, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xF2, 0xD8, 0x00, 0x00, /* 0x1C-0x1F */ - 0xD8, 0xF9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xFA, 0xDF, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xEF, /* 0x34-0x37 */ - 0xD9, 0xC2, 0x00, 0x00, 0xF0, 0xD2, 0x00, 0x00, /* 0x38-0x3B */ - 0xE4, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xF3, 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0xFA, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xEC, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0xE2, 0xB2, 0x00, 0x00, 0xD4, 0xBD, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xD9, 0xCE, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0xE2, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xD4, 0xA9, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xCD, 0xC2, 0xE7, 0xDA, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xD9, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xD9, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xD8, 0xBE, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xDC, 0xAD, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xE2, 0xEB, 0xD6, 0xFC, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0xCA, 0xF9, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xDA, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0xD7, /* 0xB8-0xBB */ - 0xCC, 0xA1, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xBA, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF5, 0xB8, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xC3, /* 0xD8-0xDB */ - 0xD0, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xC5, 0xEB, 0xF8, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xF2, 0xB1, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xCF, 0xBB, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xD3, 0xAD, 0xE8, 0xE1, 0xCE, 0xEC, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xB4, /* 0xF0-0xF3 */ -}; - -static const unsigned char u2c_78[512] = { - 0x00, 0x00, 0x00, 0x00, 0xDE, 0xE3, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0xF7, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xF2, 0xB2, 0xF3, 0xF6, 0xF6, 0xDB, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0xD7, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xDF, 0x00, 0x00, /* 0x30-0x33 */ - 0xF7, 0xF2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0xD0, 0xA9, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xDA, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0xF5, 0xA6, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xBC, /* 0x68-0x6B */ - 0xCC, 0xE3, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xDB, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xDD, 0xDD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xD1, 0xB3, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xED, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0xD6, 0xDE, 0xE4, 0xF4, 0xE1, 0xEF, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xDD, 0xF8, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xCF, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xE5, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xA1, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xE0, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xFC, 0xAC, 0xFC, 0xAD, /* 0xB8-0xBB */ - 0xD8, 0xA7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xED, 0xB8, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xDB, 0xB6, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xF0, 0xF3, 0xAF, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xCD, 0xA5, 0x00, 0x00, /* 0xCC-0xCF */ - 0xDA, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xD8, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xCC, 0xE4, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xB4, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xCA, 0xD8, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xF2, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_79[512] = { - 0x00, 0x00, 0xF5, 0xA7, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0xA8, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xA6, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xEC, 0xD5, 0xF8, /* 0x28-0x2B */ - 0xDA, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xC6, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xDE, 0xE4, 0x00, 0x00, /* 0x3C-0x3F */ - 0xDE, 0xE5, 0xD1, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xB6, /* 0x44-0x47 */ - 0xD1, 0xB7, 0xF2, 0xB3, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xE9, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xD3, 0xF2, 0xB4, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xD4, 0xCB, 0xE4, /* 0x58-0x5B */ - 0xFB, 0xD4, 0xF5, 0xE6, 0xE3, 0xEA, 0x00, 0x00, /* 0x5C-0x5F */ - 0xDE, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0xDF, 0xD4, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xF8, 0xF9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0xF0, 0xAE, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0xD1, 0xB8, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xDF, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xD0, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0xFC, 0xA1, 0xEF, 0xEE, 0xDC, 0xD8, /* 0x8C-0x8F */ - 0x00, 0x00, 0xE9, 0xDF, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xDD, 0xFD, 0xFB, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC9, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xC9, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xD4, 0xAA, 0x00, 0x00, 0xE5, 0xCC, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xE9, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xD0, 0xD8, 0xFC, 0xA2, 0xD4, 0xBE, /* 0xBC-0xBF */ - 0xE2, 0xB3, 0xDE, 0xE7, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xDC, 0xBC, 0xD2, 0xB6, 0xF5, 0xD5, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xCE, 0xA1, 0xF5, 0xA9, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xDD, 0xF9, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xDD, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xD5, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xF6, 0xDF, 0x00, 0x00, 0xF2, 0xDA, 0xE4, 0xEB, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xF2, 0xF1, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xB9, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_7A[512] = { - 0xFD, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xE1, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xCA, 0xD9, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xEF, /* 0x08-0x0B */ - 0x00, 0x00, 0xF5, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xEC, 0xF9, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xAD, /* 0x14-0x17 */ - 0x00, 0x00, 0xF2, 0xC2, 0xF6, 0xC3, 0x00, 0x00, /* 0x18-0x1B */ - 0xD7, 0xD2, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xA2, /* 0x1C-0x1F */ - 0xF0, 0xD6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFA, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xF6, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xF3, 0xF2, 0xC3, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xAB, /* 0x38-0x3B */ - 0xCA, 0xB3, 0xCD, 0xA6, 0x00, 0x00, 0xCD, 0xC3, /* 0x3C-0x3F */ - 0xCD, 0xDA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xD9, 0xCF, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xF6, 0xC4, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0xEE, 0xDD, 0xE7, 0xC4, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xB4, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0xDF, 0xE2, 0xE7, 0xDB, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xE8, 0xB1, 0x00, 0x00, 0xFC, 0xAE, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xE5, 0xCD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xFA, 0xEB, 0x00, 0x00, 0xCF, 0xBC, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xCF, 0xE2, 0xCD, 0xF6, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xEF, 0xF0, 0x00, 0x00, 0xF4, 0xBE, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xD4, 0xCD, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xF3, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xE9, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xF2, 0xF2, 0xF3, 0xEB, /* 0x90-0x93 */ - 0x00, 0x00, 0xF0, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xCF, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xDF, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xE8, 0xC0, 0xE8, 0xC1, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xCF, 0xE3, 0xE9, 0xA2, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0xAA, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xF3, 0xC1, 0xD0, 0xAB, 0x00, 0x00, 0xD4, 0xE4, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0xBC, 0xD8, 0xA1, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xDF, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xF3, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0xDC, 0xBD, 0x00, 0x00, 0xCC, 0xE5, /* 0xDC-0xDF */ - 0xED, 0xF1, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xE2, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xD4, 0xDB, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0xB5, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xCA, 0xE6, 0x00, 0x00, 0xD3, 0xAE, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xCC, 0xE6, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xF1, 0xD3, 0xF5, 0xE7, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xDA, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_7B[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xEE, /* 0x0C-0x0F */ - 0x00, 0x00, 0xE1, 0xC5, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xDF, 0xE9, 0x00, 0x00, 0xEE, 0xDE, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xF7, 0xC2, 0x00, 0x00, /* 0x1C-0x1F */ - 0xD8, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0xAC, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0xF0, 0xAF, 0xD6, 0xBD, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0xE1, 0xAB, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xF9, 0xB6, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xD4, 0xF5, 0x00, 0x00, 0xD0, 0xC9, /* 0x48-0x4B */ - 0xEF, 0xA7, 0xE2, 0xEC, 0x00, 0x00, 0xDB, 0xEA, /* 0x4C-0x4F */ - 0xCE, 0xCC, 0xF5, 0xE8, 0xF7, 0xD5, 0x00, 0x00, /* 0x50-0x53 */ - 0xD3, 0xCD, 0x00, 0x00, 0xF3, 0xFE, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xD0, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0xE0, 0xFE, 0x00, 0x00, 0xDF, 0xFB, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xE6, 0xDD, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xE8, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCB, 0xCD, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xA8, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xB4, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xDA, 0xD8, 0xD1, 0xB9, 0x00, 0x00, 0xDF, 0xA9, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xF3, 0xB0, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xCC, 0xC4, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xCE, 0xB7, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0xEF, 0xA9, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xDF, 0xD5, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xED, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xEE, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xEF, 0xBD, 0xFC, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xDB, 0xF4, 0x00, 0x00, 0xEF, 0xAA, 0xF8, 0xB9, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xF5, 0xE9, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xD9, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0xE1, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xD4, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xDE, 0xE8, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ -}; - -static const unsigned char u2c_7C[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xEA, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xF3, 0xC2, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0xAF, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xCA, 0xDB, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xD7, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0xD8, 0xE1, 0xC7, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xF4, 0xD8, 0xD6, 0xB3, 0xDD, 0xAD, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xBE, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xF1, 0xC3, 0xEE, 0xDF, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xD6, 0xEB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0xF4, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0xD7, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xB7, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDD, 0xFB, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0xDD, 0xCF, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xD8, 0xA3, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0xDA, 0xD9, 0x00, 0x00, 0xF0, 0xD8, /* 0x94-0x97 */ - 0xEF, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xD8, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xF1, 0xD4, 0x00, 0x00, 0xED, 0xF2, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xDB, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xD5, 0xDC, 0xF3, 0xC4, 0xCB, 0xD7, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xE2, 0xB6, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0xF1, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xFB, 0xD5, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0xD8, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0xD0, 0xF0, 0xD9, /* 0xDC-0xDF */ - 0xCB, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xDD, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xA7, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0xAC, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_7D[512] = { - 0xD1, 0xBA, 0x00, 0x00, 0xF1, 0xC4, 0x00, 0x00, /* 0x00-0x03 */ - 0xE5, 0xB3, 0xFB, 0xF5, 0xE9, 0xE1, 0xFD, 0xE0, /* 0x04-0x07 */ - 0xFC, 0xBC, 0x00, 0x00, 0xDA, 0xA2, 0xDA, 0xA3, /* 0x08-0x0B */ - 0x00, 0x00, 0xD2, 0xA1, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xD2, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xE2, 0xED, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xE9, /* 0x14-0x17 */ - 0xCE, 0xDC, 0xF2, 0xB5, 0xD0, 0xE4, 0xDD, 0xD1, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xE1, 0xC8, 0xDB, 0xB7, 0xDF, 0xE3, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xB9, /* 0x28-0x2B */ - 0xF1, 0xC5, 0x00, 0x00, 0xF3, 0xCF, 0xD7, 0xAB, /* 0x2C-0x2F */ - 0xE1, 0xAC, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xEB, /* 0x30-0x33 */ - 0x00, 0x00, 0xEE, 0xC7, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0xE1, 0xC9, 0xCA, 0xFA, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFB, 0xFA, 0xE1, /* 0x40-0x43 */ - 0xF0, 0xDA, 0xCC, 0xE7, 0xDA, 0xF4, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xCC, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0xED, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0xD5, 0xA9, 0xFA, 0xE2, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0xE5, 0x00, 0x00, /* 0x64-0x67 */ - 0xEB, 0xD6, 0x00, 0x00, 0xEC, 0xDF, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0xDF, 0xFC, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0xF7, 0xD6, 0xDE, 0xEA, 0xCB, 0xB4, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0xBE, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xCC, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xBD, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0xF2, 0xE2, 0xB7, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xE8, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xF0, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xD6, 0xE0, 0x00, 0x00, 0xF1, 0xC6, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xE2, 0xB8, 0xEB, 0xAB, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xCB, 0xB5, 0xD8, 0xD1, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xF4, 0xCE, 0xF3, 0xF7, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xD7, 0xC6, 0x00, 0x00, 0xD1, 0xBB, 0xF7, 0xAA, /* 0xB8-0xBB */ - 0x00, 0x00, 0xED, 0xCA, 0xD7, 0xD3, 0xD8, 0xFA, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xC5, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xD1, 0xCC, 0xDD, 0xFC, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xDF, 0xFD, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xF9, 0xE5, 0x00, 0x00, 0xE0, 0xCA, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0xF2, 0xFD, 0xD3, 0xB0, 0x00, 0x00, /* 0xDC-0xDF */ - 0xF4, 0xF3, 0xDA, 0xC9, 0x00, 0x00, 0xE6, 0xDE, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xF8, 0xBA, 0xE8, 0xD0, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xD8, 0xFB, 0x00, 0x00, 0x00, 0x00, 0xEA, 0xD5, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xD6, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xC6, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_7E[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xF2, 0xDB, 0xE4, 0xFC, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xE8, 0xB2, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xDA, /* 0x18-0x1B */ - 0x00, 0x00, 0xF2, 0xDC, 0xFB, 0xD6, 0xE9, 0xB2, /* 0x1C-0x1F */ - 0x00, 0x00, 0xEE, 0xAD, 0x00, 0x00, 0xFA, 0xE3, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xEE, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0xEA, 0xE6, 0xE0, /* 0x2C-0x2F */ - 0x00, 0x00, 0xF0, 0xFD, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xAC, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xF5, 0xC5, 0xEE, 0xE0, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xDB, 0xE5, 0x00, 0x00, 0xDD, 0xDE, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xD9, 0xF0, 0xE9, 0xA3, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xF9, 0x00, 0x00, /* 0x50-0x53 */ - 0xF2, 0xC4, 0xE0, 0xCB, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xA4, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0xE2, 0xB9, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xE3, 0xB1, 0xFC, 0xEB, 0xCD, 0xA8, /* 0x68-0x6B */ - 0x00, 0x00, 0xCC, 0xB6, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xF0, 0xDB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xE6, 0xBA, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xCD, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xF3, 0xC3, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0xE1, 0xD9, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xAB, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xC5, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE9, 0x00, 0x00, /* 0x94-0x97 */ - 0xF3, 0xC5, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xC0, /* 0x98-0x9B */ - 0xD5, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ -}; - -static const unsigned char u2c_7F[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0xAE, 0x00, 0x00, /* 0x34-0x37 */ - 0xF9, 0xFC, 0x00, 0x00, 0xCC, 0xC0, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xE5, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xCE, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xD8, 0xD2, 0xF9, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xAA, 0xCE, 0xD1, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0xF6, 0xC7, 0x00, 0x00, /* 0x6C-0x6F */ - 0xDB, 0xEB, 0x00, 0x00, 0xDF, 0xFE, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xD8, 0xE1, 0x00, 0x00, 0xF7, 0xF3, /* 0x74-0x77 */ - 0x00, 0x00, 0xD7, 0xE7, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0xD4, 0xFE, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xD1, 0xBC, 0x00, 0x00, 0xE5, 0xCF, 0x00, 0x00, /* 0x88-0x8B */ - 0xCB, 0xB6, 0x00, 0x00, 0xDA, 0xB8, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xCD, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xBE, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0xBA, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xCF, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xE0, 0xCC, 0xEB, 0xF9, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xFD, 0xFD, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xD7, 0xE8, 0xCB, 0xD8, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xE9, 0xE2, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xE8, 0xBA, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xE3, 0xC7, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xEC, 0xCD, 0x00, 0x00, /* 0xC8-0xCB */ - 0xEC, 0xCE, 0x00, 0x00, 0xD6, 0xBF, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xA7, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xDF, 0xD6, 0xFD, 0xE8, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xE1, /* 0xDC-0xDF */ - 0xF6, 0xA8, 0xDD, 0xFD, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xF8, 0xBB, 0x00, 0x00, 0xE8, 0xD1, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xF9, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xCE, 0xEE, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0xEC, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_80[512] = { - 0xE9, 0xA5, 0xD6, 0xD5, 0x00, 0x00, 0xCD, 0xC5, /* 0x00-0x03 */ - 0x00, 0x00, 0xED, 0xBA, 0xD1, 0xBD, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xCF, 0xBE, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0xEC, 0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xD2, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xCC, 0xE9, 0x00, 0x00, 0xD9, 0xC4, /* 0x14-0x17 */ - 0xE9, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0xD1, 0xBE, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xBC, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xAD, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xF7, 0xB0, 0x00, 0x00, 0xCC, 0xEA, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD3, 0xC4, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xC0, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xFD, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xA1, 0x00, 0x00, /* 0x54-0x57 */ - 0xDE, 0xBD, 0x00, 0x00, 0xF6, 0xA9, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0xA4, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xA4, /* 0x6C-0x6F */ - 0xF5, 0xC6, 0x00, 0x00, 0xE1, 0xA2, 0xE9, 0xC6, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xC5, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xF4, 0xE9, 0xD6, 0xEC, 0xEB, 0xD3, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xEC, 0xBD, 0xE2, 0xDC, 0xDE, 0xEB, 0xF0, 0xDC, /* 0x84-0x87 */ - 0x00, 0x00, 0xEB, 0xBF, 0x00, 0x00, 0xD7, 0xCE, /* 0x88-0x8B */ - 0xD1, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0xAB, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xFD, /* 0x98-0x9B */ - 0x00, 0x00, 0xCA, 0xDC, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xCD, 0xC6, 0xF2, 0xB6, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xDD, 0xFE, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xCC, 0xB7, 0xDB, 0xB8, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xE9, /* 0xAC-0xAF */ - 0x00, 0x00, 0xCE, 0xDD, 0xEB, 0xC0, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xFD, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xCB, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0xD6, /* 0xC0-0xC3 */ - 0xF1, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0xDB, 0xCE, 0x00, 0x00, 0xF7, 0xC3, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xCF, 0xCB, 0xA4, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xE0, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0xFB, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xEB, 0xCA, 0xE0, 0xA1, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0xCE, 0xCD, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xD4, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xFD, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xD2, 0xF6, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_81[512] = { - 0x00, 0x00, 0x00, 0x00, 0xF2, 0xB7, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xFA, 0xF6, 0xF6, 0xAA, 0xFA, 0xF7, /* 0x04-0x07 */ - 0xD8, 0xE6, 0x00, 0x00, 0xF4, 0xB1, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xE8, 0xD2, 0x00, 0x00, 0xCA, 0xC5, 0xCC, 0xEB, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xEE, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xE2, 0xBB, 0x00, 0x00, 0xF7, 0xAD, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xE1, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0xF3, 0xEC, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xDE, 0xA1, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xFD, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xEC, 0x00, 0x00, /* 0x4C-0x4F */ - 0xDD, 0xAF, 0xDD, 0xB0, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xCB, 0xB7, 0xE8, 0xD3, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0xE1, 0xA3, 0xD2, 0xE0, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xFE, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xE9, 0xA6, 0xCB, 0xF2, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0xED, 0xF3, 0xDC, 0xD9, 0xE0, 0xCD, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7, 0xDA, /* 0x7C-0x7F */ - - 0xDB, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xCC, 0xAE, 0x00, 0x00, 0xDA, 0xDB, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xC7, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0xB1, 0x00, 0x00, /* 0x98-0x9B */ - 0xD8, 0xAF, 0xE3, 0xA3, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xCE, 0xEF, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xF3, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xF8, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xCE, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xF5, 0xFD, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xEB, 0xEC, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xD3, 0xC5, 0xFC, 0xEC, 0xD2, 0xDB, /* 0xBC-0xBF */ - 0xD4, 0xEB, 0x00, 0x00, 0xDE, 0xA2, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xE6, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0xF0, 0xB0, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xD5, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xF4, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xED, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xE8, 0xC2, 0x00, 0x00, 0xED, 0xF5, /* 0xE4-0xE7 */ - 0xD7, 0xFC, 0x00, 0x00, 0xED, 0xBB, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xF6, 0xAB, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xB8, /* 0xF0-0xF3 */ - 0xF6, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0xE6, 0xF2, 0xDD, /* 0xF8-0xFB */ - 0xCF, 0xBF, 0x00, 0x00, 0xEB, 0xAC, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_82[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xCF, 0xC0, 0x00, 0x00, 0xE6, 0xA8, /* 0x04-0x07 */ - 0xFD, 0xE9, 0x00, 0x00, 0xCF, 0xC1, 0x00, 0x00, /* 0x08-0x0B */ - 0xE0, 0xDF, 0xDE, 0xEC, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xA2, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0xBF, /* 0x18-0x1B */ - 0xE2, 0xEF, 0x00, 0x00, 0xD9, 0xF1, 0xF1, 0xC7, /* 0x1C-0x1F */ - 0x00, 0x00, 0xCB, 0xB8, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xF9, 0xFE, 0xDB, 0xBA, /* 0x28-0x2B */ - 0xDA, 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0xF6, 0xEC, 0xDA, 0xDC, 0xFA, 0xE4, /* 0x34-0x37 */ - 0x00, 0x00, 0xE0, 0xCF, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xDD, 0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0xE6, 0xA9, 0x00, 0x00, 0xEF, 0xF3, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xF3, 0xED, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0xEB, 0xFA, 0x00, 0x00, 0xF9, 0xE6, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xDD, 0xD5, 0xDE, /* 0x6C-0x6F */ - 0x00, 0x00, 0xCA, 0xDE, 0xDF, 0xE4, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xFD, 0x00, 0x00, /* 0x74-0x77 */ - 0xF5, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xF5, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xE3, /* 0x88-0x8B */ - 0x00, 0x00, 0xED, 0xCB, 0xCF, 0xE4, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xD8, 0xD3, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xDD, 0xB3, 0xD4, 0xEC, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xF2, 0xB9, 0x00, 0x00, 0xDF, 0xB7, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xCB, 0xCE, 0xFB, 0xD8, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xD0, 0xD9, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xDD, 0xD2, 0xF7, 0xF4, 0xE7, 0xDC, 0xE4, 0xA5, /* 0xAC-0xAF */ - 0x00, 0x00, 0xFC, 0xA3, 0x00, 0x00, 0xDB, 0xBB, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xBA, /* 0xB4-0xB7 */ - 0xE9, 0xFD, 0xD0, 0xCA, 0x00, 0x00, 0xF5, 0xD6, /* 0xB8-0xBB */ - 0xD9, 0xC5, 0xE4, 0xB4, 0x00, 0x00, 0xED, 0xA7, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xEA, 0xBD, 0xE6, 0xFE, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xF7, 0xC4, 0xF5, 0xAD, 0x00, 0x00, 0xD9, 0xE0, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xB4, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xE2, 0xCF, 0xC2, /* 0xDC-0xDF */ - 0x00, 0x00, 0xEC, 0xBE, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xE5, 0xB4, 0xCD, 0xC8, 0xEE, 0xC8, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0xE7, 0xC8, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xCD, 0xC9, 0xF9, 0xB7, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_83[512] = { - 0x00, 0x00, 0xF1, 0xE8, 0xD9, 0xF2, 0xDB, 0xF5, /* 0x00-0x03 */ - 0xCA, 0xB5, 0xD9, 0xC6, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xD8, 0xC9, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xAB, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xED, 0xBC, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xD4, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDA, /* 0x2C-0x2F */ - 0x00, 0x00, 0xE2, 0xBC, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xFC, 0xED, 0xEC, 0xE0, 0xD2, 0xFE, 0x00, 0x00, /* 0x34-0x37 */ - 0xE9, 0xC7, 0xE6, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xE2, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xBB, /* 0x44-0x47 */ - 0x00, 0x00, 0xF5, 0xAE, 0xFB, 0xAA, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xFB, /* 0x4C-0x4F */ - 0x00, 0x00, 0xEC, 0xBF, 0xFC, 0xD8, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xE5, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xC3, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xE2, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0xD7, 0xE9, 0xED, 0xF6, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xDE, 0xED, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xCC, 0xEC, 0x00, 0x00, /* 0x94-0x97 */ - 0xE3, 0xEE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xD4, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0xFA, 0xF8, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xDD, 0xB4, 0xE4, 0xB5, 0xD8, 0xB0, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xD8, 0xD5, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xF4, 0xEA, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xCE, 0xB9, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xD6, 0xE1, 0xCF, 0xD2, 0x00, 0x00, /* 0xC8-0xCB */ - 0xD0, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xA2, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xF3, 0xEE, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xF3, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xDC, 0xCC, 0x00, 0x00, 0xD0, 0xCB, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xA4, /* 0xEC-0xEF */ - 0xCD, 0xCA, 0xD7, 0xD4, 0xDE, 0xA3, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xE4, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xEE, 0xC9, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xE2, 0xDD, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_84[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF5, 0xFE, /* 0x00-0x03 */ - 0xD4, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xD1, 0x00, 0x00, /* 0x08-0x0B */ - 0xD8, 0xF0, 0xF8, 0xC3, 0xEA, 0xD7, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xF5, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0xD8, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xFD, 0xC0, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xEB, 0xAD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xD5, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xE7, 0xA8, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xCA, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xE7, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0xF8, 0xE3, 0x00, 0x00, 0xD4, 0xDD, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0xD8, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xD9, /* 0x68-0x6B */ - 0xED, 0xF7, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xB5, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xD0, 0xAD, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xF1, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xE2, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xE3, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xD9, 0xD5, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xDF, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xDB, 0xBC, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xE4, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xF1, 0xFA, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xB6, /* 0xB8-0xBB */ - 0xF3, 0xEF, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xDA, /* 0xBC-0xBF */ - 0xE1, 0xE0, 0x00, 0x00, 0xD9, 0xAC, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xF5, 0xEB, 0x00, 0x00, 0xE0, 0xB6, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xE9, 0xC8, 0x00, 0x00, 0xCB, 0xCF, /* 0xC8-0xCB */ - 0x00, 0x00, 0xE3, 0xC9, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xDE, 0xEE, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0xBE, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xDC, 0xEF, 0x00, 0x00, 0xD6, 0xA5, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xE2, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0xD6, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_85[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0xD9, 0xA1, 0x00, 0x00, 0xD8, 0xC0, /* 0x10-0x13 */ - 0xDC, 0xDB, 0x00, 0x00, 0x00, 0x00, 0xED, 0xBD, /* 0x14-0x17 */ - 0xDF, 0xB8, 0x00, 0x00, 0xEA, 0xA5, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xD7, 0xAD, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xF3, 0xF9, 0x00, 0x00, 0xED, 0xF8, /* 0x20-0x23 */ - 0x00, 0x00, 0xF5, 0xC7, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0xE1, 0xCA, 0xEB, 0xE3, 0x00, 0x00, 0xF2, 0xDE, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xF8, 0xCC, 0x00, 0x00, 0xEA, 0xD9, /* 0x3C-0x3F */ - 0x00, 0x00, 0xD3, 0xC6, 0x00, 0x00, 0xDB, 0xE6, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xF5, 0xAF, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0xF0, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xFE, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xFB, 0xB6, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xF2, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xCF, 0xF2, 0xF7, 0xB9, 0xD9, 0xF3, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0xE1, 0xCB, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xDA, 0xDD, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xB9, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEB, 0xFB, /* 0x8C-0x8F */ - 0x00, 0x00, 0xCB, 0xB9, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xED, 0xF9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE0, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0xC0, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xFD, 0xBC, 0xDF, 0xB1, 0xE3, 0xEF, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xA3, /* 0xAC-0xAF */ - 0xFD, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xB1, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xCD, 0xCB, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xED, 0xBE, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0xD5, 0xC0, 0xE3, 0xF0, 0xED, 0xFA, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xE9, 0xE4, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xD5, 0xED, 0xE7, 0xDD, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xD4, 0xF6, 0xE5, 0xB7, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xDB, 0xE7, 0xE2, 0xBF, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xCB, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0xD7, 0xF4, 0xF0, 0xDD, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xAB, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_86[512] = { - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xDE, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xD6, 0xE1, 0xCC, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xB3, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xEE, 0xDC, 0xA2, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xD0, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0xD5, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xA1, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xFB, 0xDB, 0x00, 0x00, /* 0x4C-0x4F */ - 0xF9, 0xCB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xCB, 0xF3, 0xF4, 0xA5, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xC8, /* 0x58-0x5B */ - 0xD6, 0xD7, 0x00, 0x00, 0xE9, 0xE5, 0xFB, 0xDC, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xD0, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xFB, 0xF6, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0xA5, 0x00, 0x00, /* 0x88-0x8B */ - 0xDB, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xE2, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xF7, /* 0xA0-0xA3 */ - 0xF0, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xF6, 0xC9, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xEF, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD3, 0xB1, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xFC, 0xEE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xE8, 0xC3, 0x00, 0x00, 0xF1, 0xC8, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xF1, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xF9, 0xED, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xF2, 0xF4, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xB6, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_87[512] = { - 0xF5, 0xB9, 0x00, 0x00, 0xDC, 0xF0, 0xE3, 0xF1, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xE8, 0xA5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xF2, 0xBB, 0x00, 0x00, 0xDE, 0xA4, 0x00, 0x00, /* 0x18-0x1B */ - 0xDA, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xE9, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xE3, 0xDA, 0x00, 0x00, 0xFC, 0xD9, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0xDA, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xF9, 0xC4, 0x00, 0x00, /* 0x64-0x67 */ - 0xE3, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xFB, 0xDD, 0x00, 0x00, 0xEF, 0xCA, 0x00, 0x00, /* 0x74-0x77 */ - 0xE8, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xCC, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0xEB, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xAD, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0xFB, 0xAB, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD3, 0xD9, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xA2, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xF6, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0xDA, 0xF6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xE0, 0xD1, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xA8, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0xF9, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xFA, 0xAF, 0x00, 0x00, 0xEB, 0xFC, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xEA, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_88[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xE3, 0xB2, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xC5, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xE3, 0xD5, 0xEE, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xCD, 0xCC, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0xD9, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xC1, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xFA, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xEB, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xFA, 0xBC, 0xE6, 0xE2, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xFA, 0xE5, 0xE2, 0xFA, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xB6, /* 0x54-0x57 */ - 0x00, 0x00, 0xE4, 0xB7, 0x00, 0x00, 0xEA, 0xDB, /* 0x58-0x5B */ - 0x00, 0x00, 0xF5, 0xFA, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0xFB, 0xAC, 0xCF, 0xC3, 0xEB, 0xFD, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xF8, 0xFA, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xB9, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xE1, 0xF1, 0x00, 0x00, 0xD2, 0xA4, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF5, 0xFB, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0xDA, 0xD0, 0xDB, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xEA, 0xBE, 0xD9, 0xB1, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xCA, 0xB7, 0x00, 0x00, 0x00, 0x00, 0xD3, 0xE7, /* 0x88-0x8B */ - 0x00, 0x00, 0xF8, 0xE5, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0xB2, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0xC0, 0xF2, 0xDF, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xCD, 0xE5, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xAC, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xCD, 0xCD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xEE, 0xAE, 0xD6, 0xAE, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xEA, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xE7, 0xE0, 0xEB, 0xAE, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xCF, 0xD9, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xDC, 0xCD, 0xED, 0xFB, 0x00, 0x00, 0xDE, 0xF0, /* 0xDC-0xDF */ - 0x00, 0x00, 0xD7, 0xEB, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xDE, 0xA5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xD7, /* 0xF0-0xF3 */ - 0xDB, 0xD0, 0xDB, 0xD1, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xD5, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xF0, 0xB2, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_89[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDC, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xCA, 0xE8, 0x00, 0x00, 0xF8, 0xE6, 0xDC, 0xCE, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xEA, 0xDC, 0xDB, 0xD2, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xE9, 0xB3, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xF7, 0xDB, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xA8, 0x00, 0x00, /* 0x34-0x37 */ - 0xD7, 0xAE, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE1, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xCB, 0xBA, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xE5, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xDC, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0xD5, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xD8, 0xCA, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xA9, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xA4, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xE9, 0xA9, 0x00, 0x00, 0xD3, 0xC7, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDD, 0xF8, 0xAE, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xB8, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xAE, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xF2, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xCA, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xCC, 0xAF, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xD4, 0xAD, 0xF6, 0xD1, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0xCC, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xC6, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xD5, 0xC2, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xCE, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xC7, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xB0, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xDF, 0xD8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xF5, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_8A[512] = { - 0xE5, 0xEB, 0x00, 0x00, 0xEF, 0xF4, 0xDD, 0xB5, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xCD, 0xAA, 0x00, 0x00, 0xE3, 0xF2, 0x00, 0x00, /* 0x08-0x0B */ - 0xFB, 0xF7, 0x00, 0x00, 0xF7, 0xD0, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xBA, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xFD, 0xE1, 0xF6, 0xFE, /* 0x14-0x17 */ - 0xD1, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xC5, /* 0x18-0x1B */ - 0x00, 0x00, 0xE4, 0xB8, 0x00, 0x00, 0xE1, 0xE8, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xC1, /* 0x20-0x23 */ - 0x00, 0x00, 0xD2, 0xED, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xBE, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0xE0, 0xE2, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xFA, 0xC9, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xE1, 0xCD, 0x00, 0x00, 0xCA, 0xB8, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xF2, 0xE0, 0xF1, 0xC9, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xDE, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xF0, 0xDF, 0xF8, 0xC4, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xCC, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xDE, 0xF2, 0x00, 0x00, /* 0x5C-0x5F */ - 0xE7, 0xC9, 0x00, 0x00, 0xE2, 0xF3, 0xE7, 0xE1, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xCB, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xE3, 0xCC, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0xCF, 0xF8, 0xEF, 0xAC, 0x00, 0x00, /* 0x6C-0x6F */ - 0xFD, 0xFE, 0xFC, 0xA5, 0xFA, 0xB1, 0xDF, 0xD9, /* 0x70-0x73 */ - 0x00, 0x00, 0xE0, 0xD2, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xF4, 0xDA, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0xF1, 0xCA, 0x00, 0x00, 0xCE, 0xA3, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0xF2, 0xBC, 0xEC, 0xE3, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xA5, /* 0x90-0x93 */ - 0x00, 0x00, 0xF7, 0xAB, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xEB, 0xAF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xDE, 0x00, 0x00, /* 0x9C-0x9F */ - 0xE1, 0xA4, 0xCD, 0xAB, 0x00, 0x00, 0xD9, 0xF4, /* 0xA0-0xA3 */ - 0xE8, 0xA6, 0xCD, 0xCE, 0xE1, 0xE9, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xFC, 0xEF, 0x00, 0x00, 0xE0, 0xE3, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0xE2, 0xC1, 0x00, 0x00, 0xCE, 0xA4, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xDE, 0xA6, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0xEB, 0xFE, 0x00, 0x00, 0xEB, 0xDD, 0xF0, 0xE0, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0xDB, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xE2, 0xF4, 0x00, 0x00, 0x00, 0x00, 0xD3, 0xC8, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0xEB, /* 0xC8-0xCB */ - 0x00, 0x00, 0xEE, 0xB5, 0x00, 0x00, 0xF5, 0xD8, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xDF, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xE5, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEB, 0xB0, /* 0xD8-0xDB */ - 0xF4, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0xE3, 0xCD, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0xF4, 0xFA, 0xB2, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0xF5, 0xCA, 0xDF, /* 0xE8-0xEB */ - 0x00, 0x00, 0xEB, 0xB1, 0xED, 0xBF, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0xFD, 0xC9, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xA6, 0xF9, 0xA4, /* 0xF4-0xF7 */ - 0xF0, 0xB3, 0x00, 0x00, 0xE5, 0xEC, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0xD1, 0xE7, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_8B[512] = { - 0xD9, 0xC7, 0xE4, 0xD7, 0xEA, 0xDD, 0x00, 0x00, /* 0x00-0x03 */ - 0xD4, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0xBA, 0x00, 0x00, /* 0x0C-0x0F */ - 0xDA, 0xCD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xF9, 0xCC, 0x00, 0x00, 0xE1, 0xDA, 0xDB, 0xBF, /* 0x14-0x17 */ - 0x00, 0x00, 0xCC, 0xC5, 0xEC, 0xD0, 0xCB, 0xBB, /* 0x18-0x1B */ - 0x00, 0x00, 0xDE, 0xF3, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xE9, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xD9, 0xC8, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xE3, /* 0x28-0x2B */ - 0xD7, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xC4, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0xD0, 0xCD, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xFC, 0xA6, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xF1, 0xFB, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xFD, 0xD2, 0xD1, 0xC1, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xE3, 0xDB, 0x00, 0x00, 0xD3, 0xC9, 0x00, 0x00, /* 0x58-0x5B */ - 0xDC, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xCC, 0xED, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0xDE, 0xA7, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xBB, /* 0x6C-0x6F */ - 0xEC, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xCC, 0xB9, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xDE, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xE7, 0xE2, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xD4, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xDC, 0xA8, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xE2, 0xC2, 0x00, 0x00, 0xF3, 0xD8, 0xE5, 0xD3, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xF3, 0xD9, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xF3, 0xC6, 0x00, 0x00, /* 0x98-0x9B */ -}; - -static const unsigned char u2c_8C[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xDB, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xAC, /* 0x3C-0x3F */ - 0x00, 0x00, 0xFC, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xD4, 0xE7, 0x00, 0x00, /* 0x44-0x47 */ - 0xD1, 0xC2, 0x00, 0x00, 0xF9, 0xA5, 0x00, 0x00, /* 0x48-0x4B */ - 0xE8, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xE3, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xD4, 0xCA, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0xDF, 0xDA, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xFB, 0xDF, 0xE7, 0xE3, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xF8, 0xFB, 0xE3, 0xCF, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xF5, 0xB0, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xD8, 0xE7, 0x00, 0x00, /* 0x88-0x8B */ - 0xD9, 0xC9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xF8, 0xAF, 0xEF, 0xF6, 0x00, 0x00, /* 0x9C-0x9F */ - 0xDD, 0xB6, 0xEE, 0xAF, 0xCD, 0xF8, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xB8, /* 0xA4-0xA7 */ - 0xFC, 0xA7, 0xF7, 0xFC, 0xF7, 0xB1, 0xCE, 0xBB, /* 0xA8-0xAB */ - 0xF4, 0xA1, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xCD, /* 0xAC-0xAF */ - 0xE1, 0xAE, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xC3, /* 0xB0-0xB3 */ - 0xCF, 0xFE, 0x00, 0x00, 0xF8, 0xBF, 0xD8, 0xE2, /* 0xB4-0xB7 */ - 0xD3, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xA8, /* 0xB8-0xBB */ - 0xF4, 0xE4, 0xEC, 0xC2, 0x00, 0x00, 0xD9, 0xF5, /* 0xBC-0xBF */ - 0xF9, 0xC5, 0xDD, 0xD3, 0xD6, 0xF1, 0xEC, 0xFC, /* 0xC0-0xC3 */ - 0xFC, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xED, 0xC0, /* 0xC4-0xC7 */ - 0xCA, 0xB9, 0x00, 0x00, 0xEE, 0xE4, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xF2, 0xE1, 0x00, 0x00, 0xDE, 0xB9, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xF2, 0x00, 0x00, /* 0xD8-0xDB */ - 0xDE, 0xF4, 0x00, 0x00, 0xDF, 0xDB, 0x00, 0x00, /* 0xDC-0xDF */ - 0xDB, 0xD3, 0x00, 0x00, 0xFA, 0xE7, 0xD8, 0xE3, /* 0xE0-0xE3 */ - 0xF4, 0xC1, 0x00, 0x00, 0xDD, 0xB7, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0xF2, 0xF5, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xD4, 0xAE, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xD6, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDD, 0xB8, /* 0xF8-0xFB */ - 0xCF, 0xC5, 0xDF, 0xDF, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_8D[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xF2, 0xBE, 0xF6, 0xA1, 0x00, 0x00, 0xEB, 0xCB, /* 0x04-0x07 */ - 0xF1, 0xFC, 0x00, 0x00, 0xF3, 0xC7, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0xE0, 0xEB, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xFC, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xDB, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0xEE, 0xE5, 0x00, 0x00, 0xDE, 0xF5, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xD3, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xF1, 0xCB, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xAF, /* 0x70-0x73 */ - 0xDD, 0xB9, 0x00, 0x00, 0x00, 0x00, 0xD1, 0xC3, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0xF5, 0xB1, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0xC6, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xF0, 0xE1, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xAC, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xF5, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xEB, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0xBA, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xF2, 0xBF, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0xF7, 0xC5, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0xA2, /* 0xC8-0xCB */ - 0xF2, 0xF6, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xBA, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7, 0xF5, /* 0xD8-0xDB */ - 0x00, 0x00, 0xCB, 0xE5, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0xEE, 0xE6, 0x00, 0x00, 0xE0, 0xD3, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xCE, 0xA5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xD8, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xAF, /* 0xF0-0xF3 */ -}; - -static const unsigned char u2c_8E[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xC9, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD3, 0xCE, /* 0x0C-0x0F */ - 0xF4, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xCB, 0xE6, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xA1, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xEB, 0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0xF1, 0xA2, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0xEB, 0xB3, 0x00, 0x00, /* 0x40-0x43 */ - 0xF0, 0xB4, 0x00, 0x00, 0x00, 0x00, 0xCB, 0xF4, /* 0x44-0x47 */ - 0xD4, 0xB0, 0xF3, 0xB2, 0xFB, 0xB7, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xF5, 0xEC, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xE7, /* 0x5C-0x5F */ - 0xF4, 0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xF5, 0xED, 0x00, 0x00, 0xCF, 0xF3, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xF0, 0xE2, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xCE, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xCC, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0xE5, 0xB8, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0xD7, 0xF5, 0xE3, 0xF3, /* 0xA8-0xAB */ - 0xCF, 0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xCF, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xF3, 0xB3, 0xE4, 0xD8, /* 0xC8-0xCB */ - 0xCF, 0xF9, 0xCF, 0xDA, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xFA, 0xCD, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE3, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xE2, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xF5, 0xEE, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xBB, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xDC, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_8F[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xF2, /* 0x00-0x03 */ - 0x00, 0x00, 0xD6, 0xD9, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xEE, 0xB0, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0xE5, 0xD8, 0xC2, /* 0x10-0x13 */ - 0xDC, 0xD0, 0xCC, 0xEE, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xE0, /* 0x18-0x1B */ - 0xF6, 0xCA, 0xFD, 0xCA, 0xD8, 0xD6, 0xF4, 0xCF, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xA6, 0xDC, 0xBE, /* 0x24-0x27 */ - 0x00, 0x00, 0xDB, 0xD4, 0xD7, 0xC7, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xFE, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xCD, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xE2, 0xC3, 0xDC, 0xDE, 0x00, 0x00, 0xDC, 0xDF, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0xAD, 0xE6, 0xAB, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xF9, 0xDD, 0xEA, 0xBF, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xEF, 0xAE, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0xF4, 0xD0, 0xCE, 0xF3, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0xE6, 0xAC, 0x00, 0x00, 0xCE, 0xDE, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xF9, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xF4, /* 0x98-0x9B */ - 0xCD, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xB8, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0xF7, 0xFD, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xDC, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0xDE, 0xF6, 0x00, 0x00, 0xDC, 0xAA, /* 0xAC-0xAF */ - 0xF2, 0xE3, 0xE9, 0xB4, 0xD2, 0xDC, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xE6, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xE3, 0xF6, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xCA, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xD0, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xDA, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xBC, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0xE8, 0xDA, 0xDE, /* 0xE8-0xEB */ - 0x00, 0x00, 0xF2, 0xF7, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xE2, 0xFB, 0x00, 0x00, 0xCC, 0xA6, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xBB, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xEE, 0xE9, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xF5, 0xDA, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_90[512] = { - 0xF7, 0xDC, 0xE1, 0xEA, 0xCE, 0xC1, 0xD4, 0xB1, /* 0x00-0x03 */ - 0x00, 0x00, 0xFD, 0xB1, 0xE6, 0xBD, 0x00, 0x00, /* 0x04-0x07 */ - 0xFB, 0xAD, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xE7, /* 0x08-0x0B */ - 0x00, 0x00, 0xE1, 0xCE, 0x00, 0x00, 0xF7, 0xE2, /* 0x0C-0x0F */ - 0xF5, 0xEF, 0xCF, 0xC7, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xD4, 0xB2, 0xCC, 0xEF, 0x00, 0x00, 0xD4, 0xE8, /* 0x14-0x17 */ - 0x00, 0x00, 0xEE, 0xCF, 0xF7, 0xD7, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0xE0, 0xA6, 0xD6, 0xC1, 0xE1, 0xDC, /* 0x1C-0x1F */ - 0xF0, 0xE3, 0xF1, 0xE4, 0xDC, 0xF1, 0xD6, 0xA7, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0xF5, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xF1, 0xCE, 0xF2, 0xE4, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0xD0, 0xB0, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xEC, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xF9, 0xBA, 0x00, 0x00, 0xEB, 0xB5, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xD4, 0xED, 0xE2, 0xC4, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xE7, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xEB, 0xB4, 0xEA, 0xA1, /* 0x48-0x4B */ - 0x00, 0x00, 0xF8, 0xBC, 0xCE, 0xA6, 0x00, 0x00, /* 0x4C-0x4F */ - 0xF9, 0xC6, 0xFC, 0xDA, 0x00, 0x00, 0xD4, 0xB3, /* 0x50-0x53 */ - 0xD3, 0xB9, 0xEA, 0xDE, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xE9, 0xAB, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0xE1, 0xE1, 0xD3, 0xCF, 0xF4, 0xF6, 0x00, 0x00, /* 0x5C-0x5F */ - 0xEA, 0xC0, 0xE1, 0xCF, 0x00, 0x00, 0xCC, 0xBA, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xEE, 0xEA, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0xF0, 0xE4, 0xF3, 0xB4, 0xD4, 0xEE, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xF2, 0xC0, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xF1, 0xE5, 0x00, 0x00, 0xF4, 0xC3, /* 0x74-0x77 */ - 0xE0, 0xD4, 0x00, 0x00, 0xEB, 0xB6, 0x00, 0x00, /* 0x78-0x7B */ - 0xD7, 0xA1, 0xCB, 0xE8, 0x00, 0x00, 0xF9, 0xAD, /* 0x7C-0x7F */ - - 0xE9, 0xAD, 0xD8, 0xE4, 0xFA, 0xB3, 0xE2, 0xC5, /* 0x80-0x83 */ - 0xFC, 0xBD, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xC4, /* 0x84-0x87 */ - 0xD8, 0xB1, 0x00, 0x00, 0xDC, 0xAB, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xA4, /* 0x8C-0x8F */ - 0x00, 0x00, 0xEB, 0xE9, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0xE8, 0xBB, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xD8, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0xFB, 0xAE, 0xD1, 0xE1, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xC0, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xF5, 0xBE, 0x00, 0x00, 0xDE, 0xF7, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xFB, /* 0xAC-0xAF */ - 0xF7, 0xC6, 0xCF, 0xC8, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xE1, 0xD0, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xEE, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xE9, 0xF4, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0xF4, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xCD, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0xCF, 0xDB, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xDD, 0xBB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xCE, 0xAC, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xE9, 0xE8, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xD4, 0xB4, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_91[512] = { - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xC7, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0xDB, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xFA, 0xC1, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xDE, 0xA9, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xF8, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0xEF, 0xF7, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0xB3, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xEB, 0xB7, 0xEF, 0xF8, 0xF5, 0xDC, /* 0x48-0x4B */ - 0xED, 0xCC, 0xDB, 0xD5, 0xF1, 0xCF, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xD0, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0xB2, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xD9, 0xAE, 0xD5, 0xAC, 0x00, 0x00, /* 0x68-0x6B */ - 0xE2, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xFD, 0xA3, 0x00, 0x00, 0xFB, 0xE5, /* 0x74-0x77 */ - 0xDF, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xF5, /* 0x84-0x87 */ - 0x00, 0x00, 0xF6, 0xAD, 0x00, 0x00, 0xF5, 0xB3, /* 0x88-0x8B */ - 0x00, 0x00, 0xF0, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xA5, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xF5, 0xDD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xA2, /* 0xA8-0xAB */ - 0xED, 0xFD, 0x00, 0x00, 0xF5, 0xB4, 0xFB, 0xB8, /* 0xAC-0xAF */ - 0x00, 0x00, 0xDB, 0xA3, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xD6, 0xCA, 0xCB, 0xD9, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xE5, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF3, 0xFA, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xEB, 0xB8, 0x00, 0x00, 0xE0, 0xB7, /* 0xC8-0xCB */ - 0xD7, 0xEC, 0xF1, 0xEC, 0xE5, 0xAF, 0xD5, 0xE1, /* 0xCC-0xCF */ - 0xD7, 0xED, 0xD1, 0xD1, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xF2, /* 0xD4-0xD7 */ - 0xEF, 0xF9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xDD, 0xBC, 0xF6, 0xDC, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xE5, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0xC4, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xE9, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xF3, 0xFB, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ -}; - -static const unsigned char u2c_92[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0xD4, 0xEF, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xCC, 0xA2, 0xF7, 0xFE, 0xDF, 0xBC, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEB, 0xCD, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0xB7, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xD6, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xAD, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xAF, /* 0x3C-0x3F */ - 0xCB, 0xA5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0xCB, 0xE9, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xFA, 0xE8, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0xC6, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE7, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0xC7, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xA4, 0x00, 0x00, /* 0x60-0x63 */ - 0xCF, 0xC9, 0xE2, 0xFC, 0xEF, 0xFA, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xEB, 0xDE, 0x00, 0x00, 0x00, 0x00, 0xF5, 0xC8, /* 0x80-0x83 */ - 0x00, 0x00, 0xD4, 0xDE, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xE0, 0xD5, 0x00, 0x00, 0xEF, 0xB0, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0xC7, 0x00, 0x00, /* 0x94-0x97 */ - 0xD9, 0xAF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xF9, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xE5, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xCF, 0xCA, 0xE1, 0xD1, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xE2, 0xC8, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0xEF, 0xFB, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xF9, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xDC, 0xF2, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xE0, 0xA7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xE8, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xCB, 0xEA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0xCB, 0xBC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_93[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xD6, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xF5, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xF5, 0xDF, 0x00, 0x00, 0xEE, 0xB6, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0xF6, 0xD3, 0xCA, /* 0x1C-0x1F */ - 0xEF, 0xFC, 0xD1, 0xC4, 0xEF, 0xB1, 0x00, 0x00, /* 0x20-0x23 */ - 0xD1, 0xC5, 0x00, 0x00, 0xD0, 0xDE, 0x00, 0x00, /* 0x24-0x27 */ - 0xD9, 0xE1, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xB8, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0xCD, 0xD1, 0xF3, 0xB9, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0xE7, 0xCC, 0x00, 0x00, 0xD6, 0xA8, 0xCE, 0xA7, /* 0x48-0x4B */ - 0x00, 0x00, 0xD4, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xE4, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD3, 0xB4, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0xEB, 0xB9, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xCB, 0xF5, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xF6, 0xDD, 0x00, 0x00, 0xF1, 0xA3, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0xCC, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xE9, 0xCA, 0x00, 0x00, 0xE1, 0xF0, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0xE0, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xAF, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCB, 0xD1, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xFB, 0xE0, 0xF2, 0xE5, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0xEC, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xEC, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xEE, 0xEB, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xCB, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0xCC, 0xF0, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xD7, 0xAF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xF3, 0xA1, 0x00, 0x00, /* 0xF4-0xF7 */ -}; - -static const unsigned char u2c_94[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xFC, 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xF1, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xE0, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xB2, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0xF4, 0xD1, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xF7, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xF1, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0xCA, 0xFC, 0xCA, 0xFD, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xCE, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xF3, 0xC8, 0x00, 0x00, 0xF3, 0xBA, /* 0x7C-0x7F */ -}; - -static const unsigned char u2c_95[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xED, 0xFE, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xDA, 0xA6, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xEC, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0xF8, 0xCD, 0x00, 0x00, 0xCB, 0xD2, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEB, 0xCE, /* 0x8C-0x8F */ - 0x00, 0x00, 0xF9, 0xD8, 0xF9, 0xD9, 0xCA, 0xE0, /* 0x90-0x93 */ - 0xDA, 0xCA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xCB, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCA, 0xC8, /* 0xA0-0xA3 */ - 0xF9, 0xEE, 0xDB, 0xEC, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xD0, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0xD5, 0xEF, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xE6, 0xF3, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xA2, /* 0xB8-0xBB */ - 0xE4, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xE1, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xFC, 0xC4, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xF9, 0xEF, 0xCF, 0xF4, 0xF7, 0xE6, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xCE, 0xBC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0xF4, 0xC5, 0xDC, 0xA3, 0x00, 0x00, /* 0xE0-0xE3 */ -}; - -static const unsigned char u2c_96[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xDD, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xF4, 0xC6, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xA1, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xD6, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xC1, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xE6, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xB9, /* 0x3C-0x3F */ - 0xF6, 0xED, 0x00, 0x00, 0xF9, 0xAE, 0x00, 0x00, /* 0x40-0x43 */ - 0xDD, 0xBE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xB0, /* 0x48-0x4B */ - 0xD8, 0xE8, 0xCB, 0xBD, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xF9, 0xDA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xCE, /* 0x58-0x5B */ - 0xF9, 0xF0, 0xE0, 0xED, 0xE3, 0xB3, 0xF4, 0xB3, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0xC2, 0xF2, 0xE6, /* 0x60-0x63 */ - 0xF0, 0xB6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xD6, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xEB, 0xE4, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xE7, /* 0x70-0x73 */ - 0x00, 0x00, 0xD7, 0xD5, 0xD4, 0xB6, 0xF9, 0xE8, /* 0x74-0x77 */ - 0xD7, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xE5, 0xD5, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0xE9, 0xEA, 0xD7, 0xCC, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0xE9, 0xE2, 0xC9, /* 0x88-0x8B */ - 0x00, 0x00, 0xFC, 0xDB, 0xCD, 0xAD, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xCC, 0xB0, 0xEA, 0xA2, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xE4, 0xF6, 0xD0, 0xC0, 0x00, 0x00, 0xF0, 0xB7, /* 0x98-0x9B */ - 0xEE, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xF6, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xCA, /* 0xA4-0xA7 */ - 0xE2, 0xCB, 0x00, 0x00, 0xFA, 0xCF, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xEB, 0xDF, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xCB, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0xB4, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xED, 0xCD, 0xE4, 0xD2, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xEA, 0xA9, 0xE4, 0xBA, 0xF3, 0xA2, 0xCD, 0xD2, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xF6, 0xCB, 0x00, 0x00, 0xF1, 0xE6, /* 0xC8-0xCB */ - 0xED, 0xC1, 0xE8, 0xBC, 0xEE, 0xD1, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xF0, 0xE7, 0xE2, 0xCC, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xE4, 0xAA, 0x00, 0x00, 0xF5, 0xE1, /* 0xD8-0xDB */ - 0xED, 0xDA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xD7, 0xEE, 0xD1, 0xF1, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xE9, 0xEB, 0xE9, 0xEC, 0xE0, 0xE4, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xA7, /* 0xEC-0xEF */ - 0xDD, 0xD4, 0x00, 0x00, 0xEA, 0xA3, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xC3, 0xD6, 0xF4, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xDA, 0xDF, 0x00, 0x00, 0xEF, 0xB3, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_97[512] = { - 0xE2, 0xCD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0xFD, 0xF2, 0xE8, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0xEF, 0xC5, 0x00, 0x00, 0xE7, 0xE7, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xD7, 0xFD, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xE7, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xDF, 0xDC, 0x00, 0x00, 0xF9, 0xC7, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xF6, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xDF, 0xAC, 0x00, 0x00, 0xD6, 0xDA, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0xDC, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xF0, 0xB8, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xFA, 0x00, 0x00, /* 0x40-0x43 */ - 0xE4, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0xD6, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0xF4, 0xEC, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0xFE, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0xF0, 0xA1, 0x00, 0x00, 0xDE, 0xAA, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0xDA, 0xBC, 0xD8, 0xFC, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xFA, 0xD4, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0xEC, 0xE5, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xFC, 0xA8, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xE6, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0xD8, 0xCB, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xB9, /* 0x88-0x8B */ - 0x00, 0x00, 0xE4, 0xD3, 0x00, 0x00, 0xCD, 0xF9, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xCF, 0xD3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xCA, 0xEA, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xD4, /* 0xA8-0xAB */ - 0x00, 0x00, 0xF8, 0xBD, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0xC7, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0xDF, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xDB, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xD4, 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEB, 0xE5, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xD2, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0xA4, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xC2, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_98[512] = { - 0xFB, 0xE1, 0xFA, 0xED, 0xF0, 0xA2, 0xCC, 0xF1, /* 0x00-0x03 */ - 0x00, 0x00, 0xFA, 0xA3, 0xE2, 0xF7, 0x00, 0x00, /* 0x04-0x07 */ - 0xE2, 0xCE, 0x00, 0x00, 0xE9, 0xF5, 0x00, 0x00, /* 0x08-0x0B */ - 0xE1, 0xEB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xE7, 0xE8, 0xE8, 0xD7, 0xDA, 0xF8, 0xD4, 0xCB, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7, 0xF6, /* 0x14-0x17 */ - 0xD6, 0xC5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0xD4, 0xE9, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xFA, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xCC, 0xF2, 0xF7, 0xDD, 0x00, 0x00, 0xDE, 0xBA, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0xA8, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xF0, 0xB9, 0xE4, 0xFE, 0xE4, 0xC9, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xE4, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xEA, 0xC3, 0x00, 0x00, 0xEF, 0xB4, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xD7, 0xBE, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0xFB, 0xE2, 0x00, 0x00, 0xCD, 0xD3, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xB5, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xE9, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xF9, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xBD, /* 0xAC-0xAF */ - 0x00, 0x00, 0xF7, 0xC7, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xF8, 0xFD, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFC, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAB, /* 0xD8-0xDB */ - 0xDB, 0xE8, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xDD, /* 0xDC-0xDF */ - 0x00, 0x00, 0xE1, 0xE2, 0xD1, 0xC6, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xF6, 0xD0, 0xEB, 0xE6, 0xDA, 0xF9, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xEC, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0xDE, 0xF8, 0xF8, 0xE9, 0xE3, 0xDE, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_99[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xF5, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xFA, 0xC3, 0xE5, 0xD7, 0x00, 0x00, /* 0x08-0x0B */ - 0xEC, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xF3, 0xC9, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xBB, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xE6, 0xAE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0xB6, 0x00, 0x00, /* 0x1C-0x1F */ - 0xDC, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xCE, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0xD8, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xD0, 0xCF, 0x00, 0x00, 0xCF, 0xFA, /* 0x48-0x4B */ - 0xF3, 0xCA, 0xE0, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0xD1, 0xC7, 0xE9, 0xAE, 0x00, 0x00, /* 0x50-0x53 */ - 0xE8, 0xBD, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xC4, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0xCF, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xFA, 0xC5, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xF9, 0xB8, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xDC, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xFB, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xD8, 0xA9, 0xE5, 0xDF, 0xF9, 0xA7, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xF6, 0xEE, 0x00, 0x00, 0xF6, 0xCC, /* 0xB0-0xB3 */ - 0xE2, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xEC, 0xF1, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xDA, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0xF1, 0xD2, 0xD2, 0xCC, 0xCF, 0xCB, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xCA, 0xBD, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xDD, 0xBF, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0xF6, 0xEF, 0x00, 0x00, 0xDE, 0xF9, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xFA, 0xB4, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0xD5, 0xAD, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xE7, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_9A[512] = { - 0x00, 0x00, 0xDE, 0xBE, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xDC, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0xD1, 0xC8, 0xD1, 0xC9, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xF8, 0xBE, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCB, 0xF6, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xD4, 0xF9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0xE2, 0xE1, 0xD3, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xD8, 0xE9, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFE, /* 0x40-0x43 */ - 0x00, 0x00, 0xCF, 0xCC, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0xFD, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xCE, 0xF6, 0x00, 0x00, 0xFA, 0xD0, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xCC, 0xF3, 0xE6, 0xBE, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xAE, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xF0, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0xD1, 0xCA, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xFC, 0xBE, 0xD5, 0xF1, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xCD, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xFA, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xD0, /* 0xD0-0xD3 */ - 0xF4, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xCD, 0xD4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xE7, 0xA3, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xA5, 0x00, 0x00, /* 0xEC-0xEF */ -}; - -static const unsigned char u2c_9B[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0xD1, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xA2, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xF7, 0xE3, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xEA, 0xA6, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xD0, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xCE, 0xDA, 0xFB, 0xEB, 0xDB, 0xA6, /* 0x40-0x43 */ - 0xDB, 0xDE, 0xD8, 0xE5, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0xE0, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xD8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xE0, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xDB, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0xC6, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xF8, 0xEA, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xD5, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xF7, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xD8, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xD7, 0xEF, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0xED, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xCD, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xCC, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ -}; - -static const unsigned char u2c_9C[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0xF5, 0xE3, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xE4, 0xCA, 0x00, 0x00, 0xDC, 0xE1, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xF9, 0xC8, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xFC, 0xBF, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xE8, 0xA7, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xC4, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCB, 0xBE, /* 0x44-0x47 */ - 0x00, 0x00, 0xDC, 0xAE, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xF7, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xF0, 0xE8, 0x00, 0x00, 0xDD, 0xC0, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xCF, 0xCD, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xF3, /* 0xF0-0xF3 */ - 0xD9, 0xB0, 0x00, 0x00, 0xE6, 0xE9, 0x00, 0x00, /* 0xF4-0xF7 */ -}; - -static const unsigned char u2c_9D[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xE4, 0xBC, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0xC4, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xEC, 0x00, 0x00, /* 0x24-0x27 */ - 0xE4, 0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0xF8, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0xCC, 0xBB, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0xE4, 0xBD, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xCD, 0xDC, 0xD9, 0xF7, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0xDD, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0xCE, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xD9, 0xD0, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xA3, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xF9, 0xCD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xCD, 0xAE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xCE, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0xF6, 0xAF, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xFD, 0xD3, 0xEB, 0xED, 0xD6, 0xDC, 0x00, 0x00, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_9E[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xA4, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0xB6, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xD6, 0xDD, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xF9, 0xE9, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xE7, 0xA4, 0x00, 0x00, 0xD6, 0xE3, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xD1, 0xCB, 0xD6, 0xE4, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xF2, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xDE, 0xFA, 0x00, 0x00, 0xD7, 0xF8, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xD8, 0xEA, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xCF, 0xD5, 0xD8, 0xFD, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xAB, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xFD, 0xCB, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0xDC, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0xE0, 0xA8, 0xD5, 0xF3, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xFD, 0xD9, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xCC, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xD9, 0xF9, 0x00, 0x00, 0x00, 0x00, 0xD3, 0xEA, /* 0xD8-0xDB */ - 0xF5, 0xF5, 0x00, 0x00, 0xEF, 0xC7, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xD3, 0xDA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xDA, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ -}; - -static const unsigned char u2c_9F[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xA8, /* 0x04-0x07 */ - 0xDC, 0xAF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xA3, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xD5, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xE0, 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAC, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xBA, 0xEE, 0xB1, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0xB2, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xF6, 0xCD, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xD2, /* 0x5C-0x5F */ - 0x00, 0x00, 0xD6, 0xC6, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE5, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xF3, 0xBB, 0x00, 0x00, /* 0x68-0x6B */ - 0xE5, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xCB, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0xD7, 0xA3, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xDB, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0xCA, 0xFE, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xCF, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ -}; - -static const unsigned char u2c_AC[512] = { - 0xB0, 0xA1, 0xB0, 0xA2, 0x81, 0x41, 0x81, 0x42, /* 0x00-0x03 */ - 0xB0, 0xA3, 0x81, 0x43, 0x81, 0x44, 0xB0, 0xA4, /* 0x04-0x07 */ - 0xB0, 0xA5, 0xB0, 0xA6, 0xB0, 0xA7, 0x81, 0x45, /* 0x08-0x0B */ - 0x81, 0x46, 0x81, 0x47, 0x81, 0x48, 0x81, 0x49, /* 0x0C-0x0F */ - 0xB0, 0xA8, 0xB0, 0xA9, 0xB0, 0xAA, 0xB0, 0xAB, /* 0x10-0x13 */ - 0xB0, 0xAC, 0xB0, 0xAD, 0xB0, 0xAE, 0xB0, 0xAF, /* 0x14-0x17 */ - 0x81, 0x4A, 0xB0, 0xB0, 0xB0, 0xB1, 0xB0, 0xB2, /* 0x18-0x1B */ - 0xB0, 0xB3, 0xB0, 0xB4, 0x81, 0x4B, 0x81, 0x4C, /* 0x1C-0x1F */ - 0xB0, 0xB5, 0x81, 0x4D, 0x81, 0x4E, 0x81, 0x4F, /* 0x20-0x23 */ - 0xB0, 0xB6, 0x81, 0x50, 0x81, 0x51, 0x81, 0x52, /* 0x24-0x27 */ - 0x81, 0x53, 0x81, 0x54, 0x81, 0x55, 0x81, 0x56, /* 0x28-0x2B */ - 0xB0, 0xB7, 0xB0, 0xB8, 0x81, 0x57, 0xB0, 0xB9, /* 0x2C-0x2F */ - 0xB0, 0xBA, 0xB0, 0xBB, 0x81, 0x58, 0x81, 0x59, /* 0x30-0x33 */ - 0x81, 0x5A, 0x81, 0x61, 0x81, 0x62, 0x81, 0x63, /* 0x34-0x37 */ - 0xB0, 0xBC, 0xB0, 0xBD, 0x81, 0x64, 0x81, 0x65, /* 0x38-0x3B */ - 0xB0, 0xBE, 0x81, 0x66, 0x81, 0x67, 0x81, 0x68, /* 0x3C-0x3F */ - 0xB0, 0xBF, 0x81, 0x69, 0x81, 0x6A, 0x81, 0x6B, /* 0x40-0x43 */ - 0x81, 0x6C, 0x81, 0x6D, 0x81, 0x6E, 0x81, 0x6F, /* 0x44-0x47 */ - 0x81, 0x70, 0x81, 0x71, 0x81, 0x72, 0xB0, 0xC0, /* 0x48-0x4B */ - 0x81, 0x73, 0xB0, 0xC1, 0x81, 0x74, 0x81, 0x75, /* 0x4C-0x4F */ - 0x81, 0x76, 0x81, 0x77, 0x81, 0x78, 0x81, 0x79, /* 0x50-0x53 */ - 0xB0, 0xC2, 0x81, 0x7A, 0x81, 0x81, 0x81, 0x82, /* 0x54-0x57 */ - 0xB0, 0xC3, 0x81, 0x83, 0x81, 0x84, 0x81, 0x85, /* 0x58-0x5B */ - 0xB0, 0xC4, 0x81, 0x86, 0x81, 0x87, 0x81, 0x88, /* 0x5C-0x5F */ - 0x81, 0x89, 0x81, 0x8A, 0x81, 0x8B, 0x81, 0x8C, /* 0x60-0x63 */ - 0x81, 0x8D, 0x81, 0x8E, 0x81, 0x8F, 0x81, 0x90, /* 0x64-0x67 */ - 0x81, 0x91, 0x81, 0x92, 0x81, 0x93, 0x81, 0x94, /* 0x68-0x6B */ - 0x81, 0x95, 0x81, 0x96, 0x81, 0x97, 0x81, 0x98, /* 0x6C-0x6F */ - 0xB0, 0xC5, 0xB0, 0xC6, 0x81, 0x99, 0x81, 0x9A, /* 0x70-0x73 */ - 0xB0, 0xC7, 0x81, 0x9B, 0x81, 0x9C, 0xB0, 0xC8, /* 0x74-0x77 */ - 0xB0, 0xC9, 0x81, 0x9D, 0xB0, 0xCA, 0x81, 0x9E, /* 0x78-0x7B */ - 0x81, 0x9F, 0x81, 0xA0, 0x81, 0xA1, 0x81, 0xA2, /* 0x7C-0x7F */ - - 0xB0, 0xCB, 0xB0, 0xCC, 0x81, 0xA3, 0xB0, 0xCD, /* 0x80-0x83 */ - 0xB0, 0xCE, 0xB0, 0xCF, 0xB0, 0xD0, 0x81, 0xA4, /* 0x84-0x87 */ - 0x81, 0xA5, 0xB0, 0xD1, 0xB0, 0xD2, 0xB0, 0xD3, /* 0x88-0x8B */ - 0xB0, 0xD4, 0x81, 0xA6, 0x81, 0xA7, 0x81, 0xA8, /* 0x8C-0x8F */ - 0xB0, 0xD5, 0x81, 0xA9, 0x81, 0xAA, 0x81, 0xAB, /* 0x90-0x93 */ - 0xB0, 0xD6, 0x81, 0xAC, 0x81, 0xAD, 0x81, 0xAE, /* 0x94-0x97 */ - 0x81, 0xAF, 0x81, 0xB0, 0x81, 0xB1, 0x81, 0xB2, /* 0x98-0x9B */ - 0xB0, 0xD7, 0xB0, 0xD8, 0x81, 0xB3, 0xB0, 0xD9, /* 0x9C-0x9F */ - 0xB0, 0xDA, 0xB0, 0xDB, 0x81, 0xB4, 0x81, 0xB5, /* 0xA0-0xA3 */ - 0x81, 0xB6, 0x81, 0xB7, 0x81, 0xB8, 0x81, 0xB9, /* 0xA4-0xA7 */ - 0xB0, 0xDC, 0xB0, 0xDD, 0xB0, 0xDE, 0x81, 0xBA, /* 0xA8-0xAB */ - 0xB0, 0xDF, 0x81, 0xBB, 0x81, 0xBC, 0xB0, 0xE0, /* 0xAC-0xAF */ - 0xB0, 0xE1, 0x81, 0xBD, 0x81, 0xBE, 0x81, 0xBF, /* 0xB0-0xB3 */ - 0x81, 0xC0, 0x81, 0xC1, 0x81, 0xC2, 0x81, 0xC3, /* 0xB4-0xB7 */ - 0xB0, 0xE2, 0xB0, 0xE3, 0x81, 0xC4, 0xB0, 0xE4, /* 0xB8-0xBB */ - 0xB0, 0xE5, 0xB0, 0xE6, 0x81, 0xC5, 0x81, 0xC6, /* 0xBC-0xBF */ - 0x81, 0xC7, 0xB0, 0xE7, 0x81, 0xC8, 0x81, 0xC9, /* 0xC0-0xC3 */ - 0xB0, 0xE8, 0x81, 0xCA, 0x81, 0xCB, 0x81, 0xCC, /* 0xC4-0xC7 */ - 0xB0, 0xE9, 0x81, 0xCD, 0x81, 0xCE, 0x81, 0xCF, /* 0xC8-0xCB */ - 0xB0, 0xEA, 0x81, 0xD0, 0x81, 0xD1, 0x81, 0xD2, /* 0xCC-0xCF */ - 0x81, 0xD3, 0x81, 0xD4, 0x81, 0xD5, 0x81, 0xD6, /* 0xD0-0xD3 */ - 0x81, 0xD7, 0xB0, 0xEB, 0x81, 0xD8, 0xB0, 0xEC, /* 0xD4-0xD7 */ - 0x81, 0xD9, 0x81, 0xDA, 0x81, 0xDB, 0x81, 0xDC, /* 0xD8-0xDB */ - 0x81, 0xDD, 0x81, 0xDE, 0x81, 0xDF, 0x81, 0xE0, /* 0xDC-0xDF */ - 0xB0, 0xED, 0xB0, 0xEE, 0x81, 0xE1, 0x81, 0xE2, /* 0xE0-0xE3 */ - 0xB0, 0xEF, 0x81, 0xE3, 0x81, 0xE4, 0xB0, 0xF0, /* 0xE4-0xE7 */ - 0xB0, 0xF1, 0x81, 0xE5, 0xB0, 0xF2, 0x81, 0xE6, /* 0xE8-0xEB */ - 0xB0, 0xF3, 0x81, 0xE7, 0x81, 0xE8, 0xB0, 0xF4, /* 0xEC-0xEF */ - 0xB0, 0xF5, 0xB0, 0xF6, 0x81, 0xE9, 0xB0, 0xF7, /* 0xF0-0xF3 */ - 0x81, 0xEA, 0xB0, 0xF8, 0xB0, 0xF9, 0x81, 0xEB, /* 0xF4-0xF7 */ - 0x81, 0xEC, 0x81, 0xED, 0x81, 0xEE, 0x81, 0xEF, /* 0xF8-0xFB */ - 0xB0, 0xFA, 0xB0, 0xFB, 0x81, 0xF0, 0x81, 0xF1, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_AD[512] = { - 0xB0, 0xFC, 0x81, 0xF2, 0x81, 0xF3, 0x81, 0xF4, /* 0x00-0x03 */ - 0xB0, 0xFD, 0x81, 0xF5, 0xB0, 0xFE, 0x81, 0xF6, /* 0x04-0x07 */ - 0x81, 0xF7, 0x81, 0xF8, 0x81, 0xF9, 0x81, 0xFA, /* 0x08-0x0B */ - 0xB1, 0xA1, 0xB1, 0xA2, 0x81, 0xFB, 0xB1, 0xA3, /* 0x0C-0x0F */ - 0x81, 0xFC, 0xB1, 0xA4, 0x81, 0xFD, 0x81, 0xFE, /* 0x10-0x13 */ - 0x82, 0x41, 0x82, 0x42, 0x82, 0x43, 0x82, 0x44, /* 0x14-0x17 */ - 0xB1, 0xA5, 0x82, 0x45, 0x82, 0x46, 0x82, 0x47, /* 0x18-0x1B */ - 0xB1, 0xA6, 0x82, 0x48, 0x82, 0x49, 0x82, 0x4A, /* 0x1C-0x1F */ - 0xB1, 0xA7, 0x82, 0x4B, 0x82, 0x4C, 0x82, 0x4D, /* 0x20-0x23 */ - 0x82, 0x4E, 0x82, 0x4F, 0x82, 0x50, 0x82, 0x51, /* 0x24-0x27 */ - 0x82, 0x52, 0xB1, 0xA8, 0x82, 0x53, 0x82, 0x54, /* 0x28-0x2B */ - 0xB1, 0xA9, 0xB1, 0xAA, 0x82, 0x55, 0x82, 0x56, /* 0x2C-0x2F */ - 0x82, 0x57, 0x82, 0x58, 0x82, 0x59, 0x82, 0x5A, /* 0x30-0x33 */ - 0xB1, 0xAB, 0xB1, 0xAC, 0x82, 0x61, 0x82, 0x62, /* 0x34-0x37 */ - 0xB1, 0xAD, 0x82, 0x63, 0x82, 0x64, 0x82, 0x65, /* 0x38-0x3B */ - 0xB1, 0xAE, 0x82, 0x66, 0x82, 0x67, 0x82, 0x68, /* 0x3C-0x3F */ - 0x82, 0x69, 0x82, 0x6A, 0x82, 0x6B, 0x82, 0x6C, /* 0x40-0x43 */ - 0xB1, 0xAF, 0xB1, 0xB0, 0x82, 0x6D, 0xB1, 0xB1, /* 0x44-0x47 */ - 0x82, 0x6E, 0xB1, 0xB2, 0x82, 0x6F, 0x82, 0x70, /* 0x48-0x4B */ - 0x82, 0x71, 0x82, 0x72, 0x82, 0x73, 0x82, 0x74, /* 0x4C-0x4F */ - 0xB1, 0xB3, 0x82, 0x75, 0x82, 0x76, 0x82, 0x77, /* 0x50-0x53 */ - 0xB1, 0xB4, 0x82, 0x78, 0x82, 0x79, 0x82, 0x7A, /* 0x54-0x57 */ - 0xB1, 0xB5, 0x82, 0x81, 0x82, 0x82, 0x82, 0x83, /* 0x58-0x5B */ - 0x82, 0x84, 0x82, 0x85, 0x82, 0x86, 0x82, 0x87, /* 0x5C-0x5F */ - 0x82, 0x88, 0xB1, 0xB6, 0x82, 0x89, 0xB1, 0xB7, /* 0x60-0x63 */ - 0x82, 0x8A, 0x82, 0x8B, 0x82, 0x8C, 0x82, 0x8D, /* 0x64-0x67 */ - 0x82, 0x8E, 0x82, 0x8F, 0x82, 0x90, 0x82, 0x91, /* 0x68-0x6B */ - 0xB1, 0xB8, 0xB1, 0xB9, 0x82, 0x92, 0x82, 0x93, /* 0x6C-0x6F */ - 0xB1, 0xBA, 0x82, 0x94, 0x82, 0x95, 0xB1, 0xBB, /* 0x70-0x73 */ - 0xB1, 0xBC, 0xB1, 0xBD, 0xB1, 0xBE, 0x82, 0x96, /* 0x74-0x77 */ - 0x82, 0x97, 0x82, 0x98, 0x82, 0x99, 0xB1, 0xBF, /* 0x78-0x7B */ - 0xB1, 0xC0, 0xB1, 0xC1, 0x82, 0x9A, 0xB1, 0xC2, /* 0x7C-0x7F */ - - 0x82, 0x9B, 0xB1, 0xC3, 0xB1, 0xC4, 0x82, 0x9C, /* 0x80-0x83 */ - 0x82, 0x9D, 0x82, 0x9E, 0x82, 0x9F, 0x82, 0xA0, /* 0x84-0x87 */ - 0xB1, 0xC5, 0xB1, 0xC6, 0x82, 0xA1, 0x82, 0xA2, /* 0x88-0x8B */ - 0xB1, 0xC7, 0x82, 0xA3, 0x82, 0xA4, 0x82, 0xA5, /* 0x8C-0x8F */ - 0xB1, 0xC8, 0x82, 0xA6, 0x82, 0xA7, 0x82, 0xA8, /* 0x90-0x93 */ - 0x82, 0xA9, 0x82, 0xAA, 0x82, 0xAB, 0x82, 0xAC, /* 0x94-0x97 */ - 0x82, 0xAD, 0x82, 0xAE, 0x82, 0xAF, 0x82, 0xB0, /* 0x98-0x9B */ - 0xB1, 0xC9, 0xB1, 0xCA, 0x82, 0xB1, 0x82, 0xB2, /* 0x9C-0x9F */ - 0x82, 0xB3, 0x82, 0xB4, 0x82, 0xB5, 0x82, 0xB6, /* 0xA0-0xA3 */ - 0xB1, 0xCB, 0x82, 0xB7, 0x82, 0xB8, 0x82, 0xB9, /* 0xA4-0xA7 */ - 0x82, 0xBA, 0x82, 0xBB, 0x82, 0xBC, 0x82, 0xBD, /* 0xA8-0xAB */ - 0x82, 0xBE, 0x82, 0xBF, 0x82, 0xC0, 0x82, 0xC1, /* 0xAC-0xAF */ - 0x82, 0xC2, 0x82, 0xC3, 0x82, 0xC4, 0x82, 0xC5, /* 0xB0-0xB3 */ - 0x82, 0xC6, 0x82, 0xC7, 0x82, 0xC8, 0xB1, 0xCC, /* 0xB4-0xB7 */ - 0x82, 0xC9, 0x82, 0xCA, 0x82, 0xCB, 0x82, 0xCC, /* 0xB8-0xBB */ - 0x82, 0xCD, 0x82, 0xCE, 0x82, 0xCF, 0x82, 0xD0, /* 0xBC-0xBF */ - 0xB1, 0xCD, 0xB1, 0xCE, 0x82, 0xD1, 0x82, 0xD2, /* 0xC0-0xC3 */ - 0xB1, 0xCF, 0x82, 0xD3, 0x82, 0xD4, 0x82, 0xD5, /* 0xC4-0xC7 */ - 0xB1, 0xD0, 0x82, 0xD6, 0x82, 0xD7, 0x82, 0xD8, /* 0xC8-0xCB */ - 0x82, 0xD9, 0x82, 0xDA, 0x82, 0xDB, 0x82, 0xDC, /* 0xCC-0xCF */ - 0xB1, 0xD1, 0xB1, 0xD2, 0x82, 0xDD, 0xB1, 0xD3, /* 0xD0-0xD3 */ - 0x82, 0xDE, 0x82, 0xDF, 0x82, 0xE0, 0x82, 0xE1, /* 0xD4-0xD7 */ - 0x82, 0xE2, 0x82, 0xE3, 0x82, 0xE4, 0x82, 0xE5, /* 0xD8-0xDB */ - 0xB1, 0xD4, 0x82, 0xE6, 0x82, 0xE7, 0x82, 0xE8, /* 0xDC-0xDF */ - 0xB1, 0xD5, 0x82, 0xE9, 0x82, 0xEA, 0x82, 0xEB, /* 0xE0-0xE3 */ - 0xB1, 0xD6, 0x82, 0xEC, 0x82, 0xED, 0x82, 0xEE, /* 0xE4-0xE7 */ - 0x82, 0xEF, 0x82, 0xF0, 0x82, 0xF1, 0x82, 0xF2, /* 0xE8-0xEB */ - 0x82, 0xF3, 0x82, 0xF4, 0x82, 0xF5, 0x82, 0xF6, /* 0xEC-0xEF */ - 0x82, 0xF7, 0x82, 0xF8, 0x82, 0xF9, 0x82, 0xFA, /* 0xF0-0xF3 */ - 0x82, 0xFB, 0x82, 0xFC, 0x82, 0xFD, 0x82, 0xFE, /* 0xF4-0xF7 */ - 0xB1, 0xD7, 0xB1, 0xD8, 0x83, 0x41, 0x83, 0x42, /* 0xF8-0xFB */ - 0xB1, 0xD9, 0x83, 0x43, 0x83, 0x44, 0xB1, 0xDA, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_AE[512] = { - 0xB1, 0xDB, 0xB1, 0xDC, 0x83, 0x45, 0x83, 0x46, /* 0x00-0x03 */ - 0x83, 0x47, 0x83, 0x48, 0x83, 0x49, 0x83, 0x4A, /* 0x04-0x07 */ - 0xB1, 0xDD, 0xB1, 0xDE, 0x83, 0x4B, 0xB1, 0xDF, /* 0x08-0x0B */ - 0x83, 0x4C, 0xB1, 0xE0, 0x83, 0x4D, 0x83, 0x4E, /* 0x0C-0x0F */ - 0x83, 0x4F, 0x83, 0x50, 0x83, 0x51, 0x83, 0x52, /* 0x10-0x13 */ - 0xB1, 0xE1, 0x83, 0x53, 0x83, 0x54, 0x83, 0x55, /* 0x14-0x17 */ - 0x83, 0x56, 0x83, 0x57, 0x83, 0x58, 0x83, 0x59, /* 0x18-0x1B */ - 0x83, 0x5A, 0x83, 0x61, 0x83, 0x62, 0x83, 0x63, /* 0x1C-0x1F */ - 0x83, 0x64, 0x83, 0x65, 0x83, 0x66, 0x83, 0x67, /* 0x20-0x23 */ - 0x83, 0x68, 0x83, 0x69, 0x83, 0x6A, 0x83, 0x6B, /* 0x24-0x27 */ - 0x83, 0x6C, 0x83, 0x6D, 0x83, 0x6E, 0x83, 0x6F, /* 0x28-0x2B */ - 0x83, 0x70, 0x83, 0x71, 0x83, 0x72, 0x83, 0x73, /* 0x2C-0x2F */ - 0xB1, 0xE2, 0xB1, 0xE3, 0x83, 0x74, 0x83, 0x75, /* 0x30-0x33 */ - 0xB1, 0xE4, 0x83, 0x76, 0x83, 0x77, 0xB1, 0xE5, /* 0x34-0x37 */ - 0xB1, 0xE6, 0x83, 0x78, 0xB1, 0xE7, 0x83, 0x79, /* 0x38-0x3B */ - 0x83, 0x7A, 0x83, 0x81, 0x83, 0x82, 0x83, 0x83, /* 0x3C-0x3F */ - 0xB1, 0xE8, 0xB1, 0xE9, 0x83, 0x84, 0xB1, 0xEA, /* 0x40-0x43 */ - 0x83, 0x85, 0xB1, 0xEB, 0xB1, 0xEC, 0x83, 0x86, /* 0x44-0x47 */ - 0x83, 0x87, 0x83, 0x88, 0xB1, 0xED, 0x83, 0x89, /* 0x48-0x4B */ - 0xB1, 0xEE, 0xB1, 0xEF, 0xB1, 0xF0, 0x83, 0x8A, /* 0x4C-0x4F */ - 0xB1, 0xF1, 0x83, 0x8B, 0x83, 0x8C, 0x83, 0x8D, /* 0x50-0x53 */ - 0xB1, 0xF2, 0x83, 0x8E, 0xB1, 0xF3, 0x83, 0x8F, /* 0x54-0x57 */ - 0x83, 0x90, 0x83, 0x91, 0x83, 0x92, 0x83, 0x93, /* 0x58-0x5B */ - 0xB1, 0xF4, 0xB1, 0xF5, 0x83, 0x94, 0xB1, 0xF6, /* 0x5C-0x5F */ - 0xB1, 0xF7, 0xB1, 0xF8, 0x83, 0x95, 0x83, 0x96, /* 0x60-0x63 */ - 0x83, 0x97, 0xB1, 0xF9, 0x83, 0x98, 0x83, 0x99, /* 0x64-0x67 */ - 0xB1, 0xFA, 0xB1, 0xFB, 0x83, 0x9A, 0x83, 0x9B, /* 0x68-0x6B */ - 0xB1, 0xFC, 0x83, 0x9C, 0x83, 0x9D, 0x83, 0x9E, /* 0x6C-0x6F */ - 0xB1, 0xFD, 0x83, 0x9F, 0x83, 0xA0, 0x83, 0xA1, /* 0x70-0x73 */ - 0x83, 0xA2, 0x83, 0xA3, 0x83, 0xA4, 0x83, 0xA5, /* 0x74-0x77 */ - 0xB1, 0xFE, 0xB2, 0xA1, 0x83, 0xA6, 0xB2, 0xA2, /* 0x78-0x7B */ - 0xB2, 0xA3, 0xB2, 0xA4, 0x83, 0xA7, 0x83, 0xA8, /* 0x7C-0x7F */ - - 0x83, 0xA9, 0x83, 0xAA, 0x83, 0xAB, 0x83, 0xAC, /* 0x80-0x83 */ - 0xB2, 0xA5, 0xB2, 0xA6, 0x83, 0xAD, 0x83, 0xAE, /* 0x84-0x87 */ - 0x83, 0xAF, 0x83, 0xB0, 0x83, 0xB1, 0x83, 0xB2, /* 0x88-0x8B */ - 0xB2, 0xA7, 0x83, 0xB3, 0x83, 0xB4, 0x83, 0xB5, /* 0x8C-0x8F */ - 0x83, 0xB6, 0x83, 0xB7, 0x83, 0xB8, 0x83, 0xB9, /* 0x90-0x93 */ - 0x83, 0xBA, 0x83, 0xBB, 0x83, 0xBC, 0x83, 0xBD, /* 0x94-0x97 */ - 0x83, 0xBE, 0x83, 0xBF, 0x83, 0xC0, 0x83, 0xC1, /* 0x98-0x9B */ - 0x83, 0xC2, 0x83, 0xC3, 0x83, 0xC4, 0x83, 0xC5, /* 0x9C-0x9F */ - 0x83, 0xC6, 0x83, 0xC7, 0x83, 0xC8, 0x83, 0xC9, /* 0xA0-0xA3 */ - 0x83, 0xCA, 0x83, 0xCB, 0x83, 0xCC, 0x83, 0xCD, /* 0xA4-0xA7 */ - 0x83, 0xCE, 0x83, 0xCF, 0x83, 0xD0, 0x83, 0xD1, /* 0xA8-0xAB */ - 0x83, 0xD2, 0x83, 0xD3, 0x83, 0xD4, 0x83, 0xD5, /* 0xAC-0xAF */ - 0x83, 0xD6, 0x83, 0xD7, 0x83, 0xD8, 0x83, 0xD9, /* 0xB0-0xB3 */ - 0x83, 0xDA, 0x83, 0xDB, 0x83, 0xDC, 0x83, 0xDD, /* 0xB4-0xB7 */ - 0x83, 0xDE, 0x83, 0xDF, 0x83, 0xE0, 0x83, 0xE1, /* 0xB8-0xBB */ - 0xB2, 0xA8, 0xB2, 0xA9, 0xB2, 0xAA, 0x83, 0xE2, /* 0xBC-0xBF */ - 0xB2, 0xAB, 0x83, 0xE3, 0x83, 0xE4, 0x83, 0xE5, /* 0xC0-0xC3 */ - 0xB2, 0xAC, 0x83, 0xE6, 0x83, 0xE7, 0x83, 0xE8, /* 0xC4-0xC7 */ - 0x83, 0xE9, 0x83, 0xEA, 0x83, 0xEB, 0x83, 0xEC, /* 0xC8-0xCB */ - 0xB2, 0xAD, 0xB2, 0xAE, 0x83, 0xED, 0xB2, 0xAF, /* 0xCC-0xCF */ - 0xB2, 0xB0, 0xB2, 0xB1, 0x83, 0xEE, 0x83, 0xEF, /* 0xD0-0xD3 */ - 0x83, 0xF0, 0x83, 0xF1, 0x83, 0xF2, 0x83, 0xF3, /* 0xD4-0xD7 */ - 0xB2, 0xB2, 0xB2, 0xB3, 0x83, 0xF4, 0x83, 0xF5, /* 0xD8-0xDB */ - 0xB2, 0xB4, 0x83, 0xF6, 0x83, 0xF7, 0x83, 0xF8, /* 0xDC-0xDF */ - 0x83, 0xF9, 0x83, 0xFA, 0x83, 0xFB, 0x83, 0xFC, /* 0xE0-0xE3 */ - 0x83, 0xFD, 0x83, 0xFE, 0x84, 0x41, 0x84, 0x42, /* 0xE4-0xE7 */ - 0xB2, 0xB5, 0x84, 0x43, 0x84, 0x44, 0xB2, 0xB6, /* 0xE8-0xEB */ - 0x84, 0x45, 0xB2, 0xB7, 0x84, 0x46, 0x84, 0x47, /* 0xEC-0xEF */ - 0x84, 0x48, 0x84, 0x49, 0x84, 0x4A, 0x84, 0x4B, /* 0xF0-0xF3 */ - 0xB2, 0xB8, 0x84, 0x4C, 0x84, 0x4D, 0x84, 0x4E, /* 0xF4-0xF7 */ - 0xB2, 0xB9, 0x84, 0x4F, 0x84, 0x50, 0x84, 0x51, /* 0xF8-0xFB */ - 0xB2, 0xBA, 0x84, 0x52, 0x84, 0x53, 0x84, 0x54, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_AF[512] = { - 0x84, 0x55, 0x84, 0x56, 0x84, 0x57, 0x84, 0x58, /* 0x00-0x03 */ - 0x84, 0x59, 0x84, 0x5A, 0x84, 0x61, 0xB2, 0xBB, /* 0x04-0x07 */ - 0xB2, 0xBC, 0x84, 0x62, 0x84, 0x63, 0x84, 0x64, /* 0x08-0x0B */ - 0x84, 0x65, 0xB2, 0xBD, 0x84, 0x66, 0x84, 0x67, /* 0x0C-0x0F */ - 0xB2, 0xBE, 0x84, 0x68, 0x84, 0x69, 0x84, 0x6A, /* 0x10-0x13 */ - 0x84, 0x6B, 0x84, 0x6C, 0x84, 0x6D, 0x84, 0x6E, /* 0x14-0x17 */ - 0x84, 0x6F, 0x84, 0x70, 0x84, 0x71, 0x84, 0x72, /* 0x18-0x1B */ - 0x84, 0x73, 0x84, 0x74, 0x84, 0x75, 0x84, 0x76, /* 0x1C-0x1F */ - 0x84, 0x77, 0x84, 0x78, 0x84, 0x79, 0x84, 0x7A, /* 0x20-0x23 */ - 0x84, 0x81, 0x84, 0x82, 0x84, 0x83, 0x84, 0x84, /* 0x24-0x27 */ - 0x84, 0x85, 0x84, 0x86, 0x84, 0x87, 0x84, 0x88, /* 0x28-0x2B */ - 0xB2, 0xBF, 0xB2, 0xC0, 0x84, 0x89, 0x84, 0x8A, /* 0x2C-0x2F */ - 0xB2, 0xC1, 0x84, 0x8B, 0xB2, 0xC2, 0x84, 0x8C, /* 0x30-0x33 */ - 0xB2, 0xC3, 0x84, 0x8D, 0x84, 0x8E, 0x84, 0x8F, /* 0x34-0x37 */ - 0x84, 0x90, 0x84, 0x91, 0x84, 0x92, 0x84, 0x93, /* 0x38-0x3B */ - 0xB2, 0xC4, 0xB2, 0xC5, 0x84, 0x94, 0xB2, 0xC6, /* 0x3C-0x3F */ - 0x84, 0x95, 0xB2, 0xC7, 0xB2, 0xC8, 0xB2, 0xC9, /* 0x40-0x43 */ - 0x84, 0x96, 0x84, 0x97, 0x84, 0x98, 0x84, 0x99, /* 0x44-0x47 */ - 0xB2, 0xCA, 0xB2, 0xCB, 0x84, 0x9A, 0x84, 0x9B, /* 0x48-0x4B */ - 0x84, 0x9C, 0x84, 0x9D, 0x84, 0x9E, 0x84, 0x9F, /* 0x4C-0x4F */ - 0xB2, 0xCC, 0x84, 0xA0, 0x84, 0xA1, 0x84, 0xA2, /* 0x50-0x53 */ - 0x84, 0xA3, 0x84, 0xA4, 0x84, 0xA5, 0x84, 0xA6, /* 0x54-0x57 */ - 0x84, 0xA7, 0x84, 0xA8, 0x84, 0xA9, 0x84, 0xAA, /* 0x58-0x5B */ - 0xB2, 0xCD, 0xB2, 0xCE, 0x84, 0xAB, 0x84, 0xAC, /* 0x5C-0x5F */ - 0x84, 0xAD, 0x84, 0xAE, 0x84, 0xAF, 0x84, 0xB0, /* 0x60-0x63 */ - 0xB2, 0xCF, 0xB2, 0xD0, 0x84, 0xB1, 0x84, 0xB2, /* 0x64-0x67 */ - 0x84, 0xB3, 0x84, 0xB4, 0x84, 0xB5, 0x84, 0xB6, /* 0x68-0x6B */ - 0x84, 0xB7, 0x84, 0xB8, 0x84, 0xB9, 0x84, 0xBA, /* 0x6C-0x6F */ - 0x84, 0xBB, 0x84, 0xBC, 0x84, 0xBD, 0x84, 0xBE, /* 0x70-0x73 */ - 0x84, 0xBF, 0x84, 0xC0, 0x84, 0xC1, 0x84, 0xC2, /* 0x74-0x77 */ - 0x84, 0xC3, 0xB2, 0xD1, 0x84, 0xC4, 0x84, 0xC5, /* 0x78-0x7B */ - 0x84, 0xC6, 0x84, 0xC7, 0x84, 0xC8, 0x84, 0xC9, /* 0x7C-0x7F */ - - 0xB2, 0xD2, 0x84, 0xCA, 0x84, 0xCB, 0x84, 0xCC, /* 0x80-0x83 */ - 0xB2, 0xD3, 0x84, 0xCD, 0x84, 0xCE, 0x84, 0xCF, /* 0x84-0x87 */ - 0xB2, 0xD4, 0x84, 0xD0, 0x84, 0xD1, 0x84, 0xD2, /* 0x88-0x8B */ - 0x84, 0xD3, 0x84, 0xD4, 0x84, 0xD5, 0x84, 0xD6, /* 0x8C-0x8F */ - 0xB2, 0xD5, 0xB2, 0xD6, 0x84, 0xD7, 0x84, 0xD8, /* 0x90-0x93 */ - 0x84, 0xD9, 0xB2, 0xD7, 0x84, 0xDA, 0x84, 0xDB, /* 0x94-0x97 */ - 0x84, 0xDC, 0x84, 0xDD, 0x84, 0xDE, 0x84, 0xDF, /* 0x98-0x9B */ - 0xB2, 0xD8, 0x84, 0xE0, 0x84, 0xE1, 0x84, 0xE2, /* 0x9C-0x9F */ - 0x84, 0xE3, 0x84, 0xE4, 0x84, 0xE5, 0x84, 0xE6, /* 0xA0-0xA3 */ - 0x84, 0xE7, 0x84, 0xE8, 0x84, 0xE9, 0x84, 0xEA, /* 0xA4-0xA7 */ - 0x84, 0xEB, 0x84, 0xEC, 0x84, 0xED, 0x84, 0xEE, /* 0xA8-0xAB */ - 0x84, 0xEF, 0x84, 0xF0, 0x84, 0xF1, 0x84, 0xF2, /* 0xAC-0xAF */ - 0x84, 0xF3, 0x84, 0xF4, 0x84, 0xF5, 0x84, 0xF6, /* 0xB0-0xB3 */ - 0x84, 0xF7, 0x84, 0xF8, 0x84, 0xF9, 0x84, 0xFA, /* 0xB4-0xB7 */ - 0xB2, 0xD9, 0xB2, 0xDA, 0x84, 0xFB, 0x84, 0xFC, /* 0xB8-0xBB */ - 0xB2, 0xDB, 0x84, 0xFD, 0x84, 0xFE, 0x85, 0x41, /* 0xBC-0xBF */ - 0xB2, 0xDC, 0x85, 0x42, 0x85, 0x43, 0x85, 0x44, /* 0xC0-0xC3 */ - 0x85, 0x45, 0x85, 0x46, 0x85, 0x47, 0xB2, 0xDD, /* 0xC4-0xC7 */ - 0xB2, 0xDE, 0xB2, 0xDF, 0x85, 0x48, 0xB2, 0xE0, /* 0xC8-0xCB */ - 0x85, 0x49, 0xB2, 0xE1, 0xB2, 0xE2, 0x85, 0x4A, /* 0xCC-0xCF */ - 0x85, 0x4B, 0x85, 0x4C, 0x85, 0x4D, 0x85, 0x4E, /* 0xD0-0xD3 */ - 0xB2, 0xE3, 0x85, 0x4F, 0x85, 0x50, 0x85, 0x51, /* 0xD4-0xD7 */ - 0x85, 0x52, 0x85, 0x53, 0x85, 0x54, 0x85, 0x55, /* 0xD8-0xDB */ - 0xB2, 0xE4, 0x85, 0x56, 0x85, 0x57, 0x85, 0x58, /* 0xDC-0xDF */ - 0x85, 0x59, 0x85, 0x5A, 0x85, 0x61, 0x85, 0x62, /* 0xE0-0xE3 */ - 0x85, 0x63, 0x85, 0x64, 0x85, 0x65, 0x85, 0x66, /* 0xE4-0xE7 */ - 0xB2, 0xE5, 0xB2, 0xE6, 0x85, 0x67, 0x85, 0x68, /* 0xE8-0xEB */ - 0x85, 0x69, 0x85, 0x6A, 0x85, 0x6B, 0x85, 0x6C, /* 0xEC-0xEF */ - 0xB2, 0xE7, 0xB2, 0xE8, 0x85, 0x6D, 0x85, 0x6E, /* 0xF0-0xF3 */ - 0xB2, 0xE9, 0x85, 0x6F, 0x85, 0x70, 0x85, 0x71, /* 0xF4-0xF7 */ - 0xB2, 0xEA, 0x85, 0x72, 0x85, 0x73, 0x85, 0x74, /* 0xF8-0xFB */ - 0x85, 0x75, 0x85, 0x76, 0x85, 0x77, 0x85, 0x78, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_B0[512] = { - 0xB2, 0xEB, 0xB2, 0xEC, 0x85, 0x79, 0x85, 0x7A, /* 0x00-0x03 */ - 0xB2, 0xED, 0x85, 0x81, 0x85, 0x82, 0x85, 0x83, /* 0x04-0x07 */ - 0x85, 0x84, 0x85, 0x85, 0x85, 0x86, 0x85, 0x87, /* 0x08-0x0B */ - 0xB2, 0xEE, 0x85, 0x88, 0x85, 0x89, 0x85, 0x8A, /* 0x0C-0x0F */ - 0xB2, 0xEF, 0x85, 0x8B, 0x85, 0x8C, 0x85, 0x8D, /* 0x10-0x13 */ - 0xB2, 0xF0, 0x85, 0x8E, 0x85, 0x8F, 0x85, 0x90, /* 0x14-0x17 */ - 0x85, 0x91, 0x85, 0x92, 0x85, 0x93, 0x85, 0x94, /* 0x18-0x1B */ - 0xB2, 0xF1, 0xB2, 0xF2, 0x85, 0x95, 0x85, 0x96, /* 0x1C-0x1F */ - 0x85, 0x97, 0x85, 0x98, 0x85, 0x99, 0x85, 0x9A, /* 0x20-0x23 */ - 0x85, 0x9B, 0x85, 0x9C, 0x85, 0x9D, 0x85, 0x9E, /* 0x24-0x27 */ - 0xB2, 0xF3, 0x85, 0x9F, 0x85, 0xA0, 0x85, 0xA1, /* 0x28-0x2B */ - 0x85, 0xA2, 0x85, 0xA3, 0x85, 0xA4, 0x85, 0xA5, /* 0x2C-0x2F */ - 0x85, 0xA6, 0x85, 0xA7, 0x85, 0xA8, 0x85, 0xA9, /* 0x30-0x33 */ - 0x85, 0xAA, 0x85, 0xAB, 0x85, 0xAC, 0x85, 0xAD, /* 0x34-0x37 */ - 0x85, 0xAE, 0x85, 0xAF, 0x85, 0xB0, 0x85, 0xB1, /* 0x38-0x3B */ - 0x85, 0xB2, 0x85, 0xB3, 0x85, 0xB4, 0x85, 0xB5, /* 0x3C-0x3F */ - 0x85, 0xB6, 0x85, 0xB7, 0x85, 0xB8, 0x85, 0xB9, /* 0x40-0x43 */ - 0xB2, 0xF4, 0xB2, 0xF5, 0x85, 0xBA, 0x85, 0xBB, /* 0x44-0x47 */ - 0xB2, 0xF6, 0x85, 0xBC, 0xB2, 0xF7, 0x85, 0xBD, /* 0x48-0x4B */ - 0xB2, 0xF8, 0x85, 0xBE, 0xB2, 0xF9, 0x85, 0xBF, /* 0x4C-0x4F */ - 0x85, 0xC0, 0x85, 0xC1, 0x85, 0xC2, 0xB2, 0xFA, /* 0x50-0x53 */ - 0xB2, 0xFB, 0xB2, 0xFC, 0x85, 0xC3, 0xB2, 0xFD, /* 0x54-0x57 */ - 0x85, 0xC4, 0xB2, 0xFE, 0x85, 0xC5, 0x85, 0xC6, /* 0x58-0x5B */ - 0x85, 0xC7, 0xB3, 0xA1, 0x85, 0xC8, 0x85, 0xC9, /* 0x5C-0x5F */ - 0x85, 0xCA, 0x85, 0xCB, 0x85, 0xCC, 0x85, 0xCD, /* 0x60-0x63 */ - 0x85, 0xCE, 0x85, 0xCF, 0x85, 0xD0, 0x85, 0xD1, /* 0x64-0x67 */ - 0x85, 0xD2, 0x85, 0xD3, 0x85, 0xD4, 0x85, 0xD5, /* 0x68-0x6B */ - 0x85, 0xD6, 0x85, 0xD7, 0x85, 0xD8, 0x85, 0xD9, /* 0x6C-0x6F */ - 0x85, 0xDA, 0x85, 0xDB, 0x85, 0xDC, 0x85, 0xDD, /* 0x70-0x73 */ - 0x85, 0xDE, 0x85, 0xDF, 0x85, 0xE0, 0x85, 0xE1, /* 0x74-0x77 */ - 0x85, 0xE2, 0x85, 0xE3, 0x85, 0xE4, 0x85, 0xE5, /* 0x78-0x7B */ - 0xB3, 0xA2, 0xB3, 0xA3, 0x85, 0xE6, 0x85, 0xE7, /* 0x7C-0x7F */ - - 0xB3, 0xA4, 0x85, 0xE8, 0x85, 0xE9, 0x85, 0xEA, /* 0x80-0x83 */ - 0xB3, 0xA5, 0x85, 0xEB, 0x85, 0xEC, 0x85, 0xED, /* 0x84-0x87 */ - 0x85, 0xEE, 0x85, 0xEF, 0x85, 0xF0, 0x85, 0xF1, /* 0x88-0x8B */ - 0xB3, 0xA6, 0xB3, 0xA7, 0x85, 0xF2, 0xB3, 0xA8, /* 0x8C-0x8F */ - 0x85, 0xF3, 0xB3, 0xA9, 0x85, 0xF4, 0x85, 0xF5, /* 0x90-0x93 */ - 0x85, 0xF6, 0x85, 0xF7, 0x85, 0xF8, 0x85, 0xF9, /* 0x94-0x97 */ - 0xB3, 0xAA, 0xB3, 0xAB, 0xB3, 0xAC, 0x85, 0xFA, /* 0x98-0x9B */ - 0xB3, 0xAD, 0x85, 0xFB, 0x85, 0xFC, 0xB3, 0xAE, /* 0x9C-0x9F */ - 0xB3, 0xAF, 0xB3, 0xB0, 0xB3, 0xB1, 0x85, 0xFD, /* 0xA0-0xA3 */ - 0x85, 0xFE, 0x86, 0x41, 0x86, 0x42, 0x86, 0x43, /* 0xA4-0xA7 */ - 0xB3, 0xB2, 0xB3, 0xB3, 0x86, 0x44, 0xB3, 0xB4, /* 0xA8-0xAB */ - 0xB3, 0xB5, 0xB3, 0xB6, 0xB3, 0xB7, 0xB3, 0xB8, /* 0xAC-0xAF */ - 0x86, 0x45, 0xB3, 0xB9, 0x86, 0x46, 0xB3, 0xBA, /* 0xB0-0xB3 */ - 0xB3, 0xBB, 0xB3, 0xBC, 0x86, 0x47, 0x86, 0x48, /* 0xB4-0xB7 */ - 0xB3, 0xBD, 0x86, 0x49, 0x86, 0x4A, 0x86, 0x4B, /* 0xB8-0xBB */ - 0xB3, 0xBE, 0x86, 0x4C, 0x86, 0x4D, 0x86, 0x4E, /* 0xBC-0xBF */ - 0x86, 0x4F, 0x86, 0x50, 0x86, 0x51, 0x86, 0x52, /* 0xC0-0xC3 */ - 0xB3, 0xBF, 0xB3, 0xC0, 0x86, 0x53, 0xB3, 0xC1, /* 0xC4-0xC7 */ - 0xB3, 0xC2, 0xB3, 0xC3, 0x86, 0x54, 0x86, 0x55, /* 0xC8-0xCB */ - 0x86, 0x56, 0x86, 0x57, 0x86, 0x58, 0x86, 0x59, /* 0xCC-0xCF */ - 0xB3, 0xC4, 0xB3, 0xC5, 0x86, 0x5A, 0x86, 0x61, /* 0xD0-0xD3 */ - 0xB3, 0xC6, 0x86, 0x62, 0x86, 0x63, 0x86, 0x64, /* 0xD4-0xD7 */ - 0xB3, 0xC7, 0x86, 0x65, 0x86, 0x66, 0x86, 0x67, /* 0xD8-0xDB */ - 0x86, 0x68, 0x86, 0x69, 0x86, 0x6A, 0x86, 0x6B, /* 0xDC-0xDF */ - 0xB3, 0xC8, 0x86, 0x6C, 0x86, 0x6D, 0x86, 0x6E, /* 0xE0-0xE3 */ - 0x86, 0x6F, 0xB3, 0xC9, 0x86, 0x70, 0x86, 0x71, /* 0xE4-0xE7 */ - 0x86, 0x72, 0x86, 0x73, 0x86, 0x74, 0x86, 0x75, /* 0xE8-0xEB */ - 0x86, 0x76, 0x86, 0x77, 0x86, 0x78, 0x86, 0x79, /* 0xEC-0xEF */ - 0x86, 0x7A, 0x86, 0x81, 0x86, 0x82, 0x86, 0x83, /* 0xF0-0xF3 */ - 0x86, 0x84, 0x86, 0x85, 0x86, 0x86, 0x86, 0x87, /* 0xF4-0xF7 */ - 0x86, 0x88, 0x86, 0x89, 0x86, 0x8A, 0x86, 0x8B, /* 0xF8-0xFB */ - 0x86, 0x8C, 0x86, 0x8D, 0x86, 0x8E, 0x86, 0x8F, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_B1[512] = { - 0x86, 0x90, 0x86, 0x91, 0x86, 0x92, 0x86, 0x93, /* 0x00-0x03 */ - 0x86, 0x94, 0x86, 0x95, 0x86, 0x96, 0x86, 0x97, /* 0x04-0x07 */ - 0xB3, 0xCA, 0xB3, 0xCB, 0x86, 0x98, 0xB3, 0xCC, /* 0x08-0x0B */ - 0xB3, 0xCD, 0x86, 0x99, 0x86, 0x9A, 0x86, 0x9B, /* 0x0C-0x0F */ - 0xB3, 0xCE, 0x86, 0x9C, 0xB3, 0xCF, 0xB3, 0xD0, /* 0x10-0x13 */ - 0x86, 0x9D, 0x86, 0x9E, 0x86, 0x9F, 0x86, 0xA0, /* 0x14-0x17 */ - 0xB3, 0xD1, 0xB3, 0xD2, 0x86, 0xA1, 0xB3, 0xD3, /* 0x18-0x1B */ - 0xB3, 0xD4, 0xB3, 0xD5, 0x86, 0xA2, 0x86, 0xA3, /* 0x1C-0x1F */ - 0x86, 0xA4, 0x86, 0xA5, 0x86, 0xA6, 0xB3, 0xD6, /* 0x20-0x23 */ - 0xB3, 0xD7, 0xB3, 0xD8, 0x86, 0xA7, 0x86, 0xA8, /* 0x24-0x27 */ - 0xB3, 0xD9, 0x86, 0xA9, 0x86, 0xAA, 0x86, 0xAB, /* 0x28-0x2B */ - 0xB3, 0xDA, 0x86, 0xAC, 0x86, 0xAD, 0x86, 0xAE, /* 0x2C-0x2F */ - 0x86, 0xAF, 0x86, 0xB0, 0x86, 0xB1, 0x86, 0xB2, /* 0x30-0x33 */ - 0xB3, 0xDB, 0xB3, 0xDC, 0x86, 0xB3, 0xB3, 0xDD, /* 0x34-0x37 */ - 0xB3, 0xDE, 0xB3, 0xDF, 0x86, 0xB4, 0x86, 0xB5, /* 0x38-0x3B */ - 0x86, 0xB6, 0x86, 0xB7, 0x86, 0xB8, 0x86, 0xB9, /* 0x3C-0x3F */ - 0xB3, 0xE0, 0xB3, 0xE1, 0x86, 0xBA, 0x86, 0xBB, /* 0x40-0x43 */ - 0xB3, 0xE2, 0x86, 0xBC, 0x86, 0xBD, 0x86, 0xBE, /* 0x44-0x47 */ - 0xB3, 0xE3, 0x86, 0xBF, 0x86, 0xC0, 0x86, 0xC1, /* 0x48-0x4B */ - 0x86, 0xC2, 0x86, 0xC3, 0x86, 0xC4, 0x86, 0xC5, /* 0x4C-0x4F */ - 0xB3, 0xE4, 0xB3, 0xE5, 0x86, 0xC6, 0x86, 0xC7, /* 0x50-0x53 */ - 0xB3, 0xE6, 0xB3, 0xE7, 0x86, 0xC8, 0x86, 0xC9, /* 0x54-0x57 */ - 0xB3, 0xE8, 0x86, 0xCA, 0x86, 0xCB, 0x86, 0xCC, /* 0x58-0x5B */ - 0xB3, 0xE9, 0x86, 0xCD, 0x86, 0xCE, 0x86, 0xCF, /* 0x5C-0x5F */ - 0xB3, 0xEA, 0x86, 0xD0, 0x86, 0xD1, 0x86, 0xD2, /* 0x60-0x63 */ - 0x86, 0xD3, 0x86, 0xD4, 0x86, 0xD5, 0x86, 0xD6, /* 0x64-0x67 */ - 0x86, 0xD7, 0x86, 0xD8, 0x86, 0xD9, 0x86, 0xDA, /* 0x68-0x6B */ - 0x86, 0xDB, 0x86, 0xDC, 0x86, 0xDD, 0x86, 0xDE, /* 0x6C-0x6F */ - 0x86, 0xDF, 0x86, 0xE0, 0x86, 0xE1, 0x86, 0xE2, /* 0x70-0x73 */ - 0x86, 0xE3, 0x86, 0xE4, 0x86, 0xE5, 0x86, 0xE6, /* 0x74-0x77 */ - 0xB3, 0xEB, 0xB3, 0xEC, 0x86, 0xE7, 0x86, 0xE8, /* 0x78-0x7B */ - 0xB3, 0xED, 0x86, 0xE9, 0x86, 0xEA, 0x86, 0xEB, /* 0x7C-0x7F */ - - 0xB3, 0xEE, 0x86, 0xEC, 0xB3, 0xEF, 0x86, 0xED, /* 0x80-0x83 */ - 0x86, 0xEE, 0x86, 0xEF, 0x86, 0xF0, 0x86, 0xF1, /* 0x84-0x87 */ - 0xB3, 0xF0, 0xB3, 0xF1, 0x86, 0xF2, 0xB3, 0xF2, /* 0x88-0x8B */ - 0x86, 0xF3, 0xB3, 0xF3, 0x86, 0xF4, 0x86, 0xF5, /* 0x8C-0x8F */ - 0x86, 0xF6, 0x86, 0xF7, 0xB3, 0xF4, 0xB3, 0xF5, /* 0x90-0x93 */ - 0xB3, 0xF6, 0x86, 0xF8, 0x86, 0xF9, 0x86, 0xFA, /* 0x94-0x97 */ - 0xB3, 0xF7, 0x86, 0xFB, 0x86, 0xFC, 0x86, 0xFD, /* 0x98-0x9B */ - 0xB3, 0xF8, 0x86, 0xFE, 0x87, 0x41, 0x87, 0x42, /* 0x9C-0x9F */ - 0x87, 0x43, 0x87, 0x44, 0x87, 0x45, 0x87, 0x46, /* 0xA0-0xA3 */ - 0x87, 0x47, 0x87, 0x48, 0x87, 0x49, 0x87, 0x4A, /* 0xA4-0xA7 */ - 0xB3, 0xF9, 0x87, 0x4B, 0x87, 0x4C, 0x87, 0x4D, /* 0xA8-0xAB */ - 0x87, 0x4E, 0x87, 0x4F, 0x87, 0x50, 0x87, 0x51, /* 0xAC-0xAF */ - 0x87, 0x52, 0x87, 0x53, 0x87, 0x54, 0x87, 0x55, /* 0xB0-0xB3 */ - 0x87, 0x56, 0x87, 0x57, 0x87, 0x58, 0x87, 0x59, /* 0xB4-0xB7 */ - 0x87, 0x5A, 0x87, 0x61, 0x87, 0x62, 0x87, 0x63, /* 0xB8-0xBB */ - 0x87, 0x64, 0x87, 0x65, 0x87, 0x66, 0x87, 0x67, /* 0xBC-0xBF */ - 0x87, 0x68, 0x87, 0x69, 0x87, 0x6A, 0x87, 0x6B, /* 0xC0-0xC3 */ - 0x87, 0x6C, 0x87, 0x6D, 0x87, 0x6E, 0x87, 0x6F, /* 0xC4-0xC7 */ - 0x87, 0x70, 0x87, 0x71, 0x87, 0x72, 0x87, 0x73, /* 0xC8-0xCB */ - 0xB3, 0xFA, 0x87, 0x74, 0x87, 0x75, 0x87, 0x76, /* 0xCC-0xCF */ - 0xB3, 0xFB, 0x87, 0x77, 0x87, 0x78, 0x87, 0x79, /* 0xD0-0xD3 */ - 0xB3, 0xFC, 0x87, 0x7A, 0x87, 0x81, 0x87, 0x82, /* 0xD4-0xD7 */ - 0x87, 0x83, 0x87, 0x84, 0x87, 0x85, 0x87, 0x86, /* 0xD8-0xDB */ - 0xB3, 0xFD, 0xB3, 0xFE, 0x87, 0x87, 0xB4, 0xA1, /* 0xDC-0xDF */ - 0x87, 0x88, 0x87, 0x89, 0x87, 0x8A, 0x87, 0x8B, /* 0xE0-0xE3 */ - 0x87, 0x8C, 0x87, 0x8D, 0x87, 0x8E, 0x87, 0x8F, /* 0xE4-0xE7 */ - 0xB4, 0xA2, 0xB4, 0xA3, 0x87, 0x90, 0x87, 0x91, /* 0xE8-0xEB */ - 0xB4, 0xA4, 0x87, 0x92, 0x87, 0x93, 0x87, 0x94, /* 0xEC-0xEF */ - 0xB4, 0xA5, 0x87, 0x95, 0x87, 0x96, 0x87, 0x97, /* 0xF0-0xF3 */ - 0x87, 0x98, 0x87, 0x99, 0x87, 0x9A, 0x87, 0x9B, /* 0xF4-0xF7 */ - 0x87, 0x9C, 0xB4, 0xA6, 0x87, 0x9D, 0xB4, 0xA7, /* 0xF8-0xFB */ - 0x87, 0x9E, 0xB4, 0xA8, 0x87, 0x9F, 0x87, 0xA0, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_B2[512] = { - 0x87, 0xA1, 0x87, 0xA2, 0x87, 0xA3, 0x87, 0xA4, /* 0x00-0x03 */ - 0xB4, 0xA9, 0xB4, 0xAA, 0x87, 0xA5, 0x87, 0xA6, /* 0x04-0x07 */ - 0xB4, 0xAB, 0x87, 0xA7, 0x87, 0xA8, 0xB4, 0xAC, /* 0x08-0x0B */ - 0xB4, 0xAD, 0x87, 0xA9, 0x87, 0xAA, 0x87, 0xAB, /* 0x0C-0x0F */ - 0x87, 0xAC, 0x87, 0xAD, 0x87, 0xAE, 0x87, 0xAF, /* 0x10-0x13 */ - 0xB4, 0xAE, 0xB4, 0xAF, 0x87, 0xB0, 0xB4, 0xB0, /* 0x14-0x17 */ - 0x87, 0xB1, 0xB4, 0xB1, 0x87, 0xB2, 0x87, 0xB3, /* 0x18-0x1B */ - 0x87, 0xB4, 0x87, 0xB5, 0x87, 0xB6, 0x87, 0xB7, /* 0x1C-0x1F */ - 0xB4, 0xB2, 0x87, 0xB8, 0x87, 0xB9, 0x87, 0xBA, /* 0x20-0x23 */ - 0x87, 0xBB, 0x87, 0xBC, 0x87, 0xBD, 0x87, 0xBE, /* 0x24-0x27 */ - 0x87, 0xBF, 0x87, 0xC0, 0x87, 0xC1, 0x87, 0xC2, /* 0x28-0x2B */ - 0x87, 0xC3, 0x87, 0xC4, 0x87, 0xC5, 0x87, 0xC6, /* 0x2C-0x2F */ - 0x87, 0xC7, 0x87, 0xC8, 0x87, 0xC9, 0x87, 0xCA, /* 0x30-0x33 */ - 0xB4, 0xB3, 0x87, 0xCB, 0x87, 0xCC, 0x87, 0xCD, /* 0x34-0x37 */ - 0x87, 0xCE, 0x87, 0xCF, 0x87, 0xD0, 0x87, 0xD1, /* 0x38-0x3B */ - 0xB4, 0xB4, 0x87, 0xD2, 0x87, 0xD3, 0x87, 0xD4, /* 0x3C-0x3F */ - 0x87, 0xD5, 0x87, 0xD6, 0x87, 0xD7, 0x87, 0xD8, /* 0x40-0x43 */ - 0x87, 0xD9, 0x87, 0xDA, 0x87, 0xDB, 0x87, 0xDC, /* 0x44-0x47 */ - 0x87, 0xDD, 0x87, 0xDE, 0x87, 0xDF, 0x87, 0xE0, /* 0x48-0x4B */ - 0x87, 0xE1, 0x87, 0xE2, 0x87, 0xE3, 0x87, 0xE4, /* 0x4C-0x4F */ - 0x87, 0xE5, 0x87, 0xE6, 0x87, 0xE7, 0x87, 0xE8, /* 0x50-0x53 */ - 0x87, 0xE9, 0x87, 0xEA, 0x87, 0xEB, 0x87, 0xEC, /* 0x54-0x57 */ - 0xB4, 0xB5, 0x87, 0xED, 0x87, 0xEE, 0x87, 0xEF, /* 0x58-0x5B */ - 0xB4, 0xB6, 0x87, 0xF0, 0x87, 0xF1, 0x87, 0xF2, /* 0x5C-0x5F */ - 0xB4, 0xB7, 0x87, 0xF3, 0x87, 0xF4, 0x87, 0xF5, /* 0x60-0x63 */ - 0x87, 0xF6, 0x87, 0xF7, 0x87, 0xF8, 0x87, 0xF9, /* 0x64-0x67 */ - 0xB4, 0xB8, 0xB4, 0xB9, 0x87, 0xFA, 0x87, 0xFB, /* 0x68-0x6B */ - 0x87, 0xFC, 0x87, 0xFD, 0x87, 0xFE, 0x88, 0x41, /* 0x6C-0x6F */ - 0x88, 0x42, 0x88, 0x43, 0x88, 0x44, 0x88, 0x45, /* 0x70-0x73 */ - 0xB4, 0xBA, 0xB4, 0xBB, 0x88, 0x46, 0x88, 0x47, /* 0x74-0x77 */ - 0x88, 0x48, 0x88, 0x49, 0x88, 0x4A, 0x88, 0x4B, /* 0x78-0x7B */ - 0xB4, 0xBC, 0x88, 0x4C, 0x88, 0x4D, 0x88, 0x4E, /* 0x7C-0x7F */ - - 0x88, 0x4F, 0x88, 0x50, 0x88, 0x51, 0x88, 0x52, /* 0x80-0x83 */ - 0xB4, 0xBD, 0xB4, 0xBE, 0x88, 0x53, 0x88, 0x54, /* 0x84-0x87 */ - 0x88, 0x55, 0xB4, 0xBF, 0x88, 0x56, 0x88, 0x57, /* 0x88-0x8B */ - 0x88, 0x58, 0x88, 0x59, 0x88, 0x5A, 0x88, 0x61, /* 0x8C-0x8F */ - 0xB4, 0xC0, 0xB4, 0xC1, 0x88, 0x62, 0x88, 0x63, /* 0x90-0x93 */ - 0xB4, 0xC2, 0x88, 0x64, 0x88, 0x65, 0x88, 0x66, /* 0x94-0x97 */ - 0xB4, 0xC3, 0xB4, 0xC4, 0xB4, 0xC5, 0x88, 0x67, /* 0x98-0x9B */ - 0x88, 0x68, 0x88, 0x69, 0x88, 0x6A, 0x88, 0x6B, /* 0x9C-0x9F */ - 0xB4, 0xC6, 0xB4, 0xC7, 0x88, 0x6C, 0xB4, 0xC8, /* 0xA0-0xA3 */ - 0x88, 0x6D, 0xB4, 0xC9, 0xB4, 0xCA, 0x88, 0x6E, /* 0xA4-0xA7 */ - 0x88, 0x6F, 0x88, 0x70, 0xB4, 0xCB, 0x88, 0x71, /* 0xA8-0xAB */ - 0xB4, 0xCC, 0x88, 0x72, 0x88, 0x73, 0x88, 0x74, /* 0xAC-0xAF */ - 0xB4, 0xCD, 0x88, 0x75, 0x88, 0x76, 0x88, 0x77, /* 0xB0-0xB3 */ - 0xB4, 0xCE, 0x88, 0x78, 0x88, 0x79, 0x88, 0x7A, /* 0xB4-0xB7 */ - 0x88, 0x81, 0x88, 0x82, 0x88, 0x83, 0x88, 0x84, /* 0xB8-0xBB */ - 0x88, 0x85, 0x88, 0x86, 0x88, 0x87, 0x88, 0x88, /* 0xBC-0xBF */ - 0x88, 0x89, 0x88, 0x8A, 0x88, 0x8B, 0x88, 0x8C, /* 0xC0-0xC3 */ - 0x88, 0x8D, 0x88, 0x8E, 0x88, 0x8F, 0x88, 0x90, /* 0xC4-0xC7 */ - 0xB4, 0xCF, 0xB4, 0xD0, 0x88, 0x91, 0x88, 0x92, /* 0xC8-0xCB */ - 0xB4, 0xD1, 0x88, 0x93, 0x88, 0x94, 0x88, 0x95, /* 0xCC-0xCF */ - 0xB4, 0xD2, 0x88, 0x96, 0xB4, 0xD3, 0x88, 0x97, /* 0xD0-0xD3 */ - 0x88, 0x98, 0x88, 0x99, 0x88, 0x9A, 0x88, 0x9B, /* 0xD4-0xD7 */ - 0xB4, 0xD4, 0xB4, 0xD5, 0x88, 0x9C, 0xB4, 0xD6, /* 0xD8-0xDB */ - 0x88, 0x9D, 0xB4, 0xD7, 0x88, 0x9E, 0x88, 0x9F, /* 0xDC-0xDF */ - 0x88, 0xA0, 0x88, 0xA1, 0xB4, 0xD8, 0x88, 0xA2, /* 0xE0-0xE3 */ - 0xB4, 0xD9, 0xB4, 0xDA, 0xB4, 0xDB, 0x88, 0xA3, /* 0xE4-0xE7 */ - 0xB4, 0xDC, 0x88, 0xA4, 0x88, 0xA5, 0xB4, 0xDD, /* 0xE8-0xEB */ - 0xB4, 0xDE, 0xB4, 0xDF, 0xB4, 0xE0, 0xB4, 0xE1, /* 0xEC-0xEF */ - 0x88, 0xA6, 0x88, 0xA7, 0x88, 0xA8, 0xB4, 0xE2, /* 0xF0-0xF3 */ - 0xB4, 0xE3, 0xB4, 0xE4, 0x88, 0xA9, 0xB4, 0xE5, /* 0xF4-0xF7 */ - 0xB4, 0xE6, 0xB4, 0xE7, 0xB4, 0xE8, 0xB4, 0xE9, /* 0xF8-0xFB */ - 0x88, 0xAA, 0x88, 0xAB, 0x88, 0xAC, 0xB4, 0xEA, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_B3[512] = { - 0xB4, 0xEB, 0xB4, 0xEC, 0x88, 0xAD, 0x88, 0xAE, /* 0x00-0x03 */ - 0xB4, 0xED, 0x88, 0xAF, 0x88, 0xB0, 0x88, 0xB1, /* 0x04-0x07 */ - 0xB4, 0xEE, 0x88, 0xB2, 0x88, 0xB3, 0x88, 0xB4, /* 0x08-0x0B */ - 0x88, 0xB5, 0x88, 0xB6, 0x88, 0xB7, 0x88, 0xB8, /* 0x0C-0x0F */ - 0xB4, 0xEF, 0xB4, 0xF0, 0x88, 0xB9, 0xB4, 0xF1, /* 0x10-0x13 */ - 0xB4, 0xF2, 0xB4, 0xF3, 0x88, 0xBA, 0x88, 0xBB, /* 0x14-0x17 */ - 0x88, 0xBC, 0x88, 0xBD, 0x88, 0xBE, 0x88, 0xBF, /* 0x18-0x1B */ - 0xB4, 0xF4, 0x88, 0xC0, 0x88, 0xC1, 0x88, 0xC2, /* 0x1C-0x1F */ - 0x88, 0xC3, 0x88, 0xC4, 0x88, 0xC5, 0x88, 0xC6, /* 0x20-0x23 */ - 0x88, 0xC7, 0x88, 0xC8, 0x88, 0xC9, 0x88, 0xCA, /* 0x24-0x27 */ - 0x88, 0xCB, 0x88, 0xCC, 0x88, 0xCD, 0x88, 0xCE, /* 0x28-0x2B */ - 0x88, 0xCF, 0x88, 0xD0, 0x88, 0xD1, 0x88, 0xD2, /* 0x2C-0x2F */ - 0x88, 0xD3, 0x88, 0xD4, 0x88, 0xD5, 0x88, 0xD6, /* 0x30-0x33 */ - 0x88, 0xD7, 0x88, 0xD8, 0x88, 0xD9, 0x88, 0xDA, /* 0x34-0x37 */ - 0x88, 0xDB, 0x88, 0xDC, 0x88, 0xDD, 0x88, 0xDE, /* 0x38-0x3B */ - 0x88, 0xDF, 0x88, 0xE0, 0x88, 0xE1, 0x88, 0xE2, /* 0x3C-0x3F */ - 0x88, 0xE3, 0x88, 0xE4, 0x88, 0xE5, 0x88, 0xE6, /* 0x40-0x43 */ - 0x88, 0xE7, 0x88, 0xE8, 0x88, 0xE9, 0x88, 0xEA, /* 0x44-0x47 */ - 0x88, 0xEB, 0x88, 0xEC, 0x88, 0xED, 0x88, 0xEE, /* 0x48-0x4B */ - 0x88, 0xEF, 0x88, 0xF0, 0x88, 0xF1, 0x88, 0xF2, /* 0x4C-0x4F */ - 0x88, 0xF3, 0x88, 0xF4, 0x88, 0xF5, 0x88, 0xF6, /* 0x50-0x53 */ - 0xB4, 0xF5, 0xB4, 0xF6, 0xB4, 0xF7, 0x88, 0xF7, /* 0x54-0x57 */ - 0xB4, 0xF8, 0x88, 0xF8, 0x88, 0xF9, 0xB4, 0xF9, /* 0x58-0x5B */ - 0xB4, 0xFA, 0x88, 0xFA, 0xB4, 0xFB, 0xB4, 0xFC, /* 0x5C-0x5F */ - 0x88, 0xFB, 0x88, 0xFC, 0x88, 0xFD, 0x88, 0xFE, /* 0x60-0x63 */ - 0xB4, 0xFD, 0xB4, 0xFE, 0x89, 0x41, 0xB5, 0xA1, /* 0x64-0x67 */ - 0x89, 0x42, 0xB5, 0xA2, 0x89, 0x43, 0xB5, 0xA3, /* 0x68-0x6B */ - 0x89, 0x44, 0x89, 0x45, 0xB5, 0xA4, 0x89, 0x46, /* 0x6C-0x6F */ - 0xB5, 0xA5, 0xB5, 0xA6, 0x89, 0x47, 0x89, 0x48, /* 0x70-0x73 */ - 0xB5, 0xA7, 0x89, 0x49, 0x89, 0x4A, 0x89, 0x4B, /* 0x74-0x77 */ - 0xB5, 0xA8, 0x89, 0x4C, 0x89, 0x4D, 0x89, 0x4E, /* 0x78-0x7B */ - 0x89, 0x4F, 0x89, 0x50, 0x89, 0x51, 0x89, 0x52, /* 0x7C-0x7F */ - - 0xB5, 0xA9, 0xB5, 0xAA, 0x89, 0x53, 0xB5, 0xAB, /* 0x80-0x83 */ - 0xB5, 0xAC, 0xB5, 0xAD, 0x89, 0x54, 0x89, 0x55, /* 0x84-0x87 */ - 0x89, 0x56, 0x89, 0x57, 0x89, 0x58, 0x89, 0x59, /* 0x88-0x8B */ - 0xB5, 0xAE, 0x89, 0x5A, 0x89, 0x61, 0x89, 0x62, /* 0x8C-0x8F */ - 0xB5, 0xAF, 0x89, 0x63, 0x89, 0x64, 0x89, 0x65, /* 0x90-0x93 */ - 0xB5, 0xB0, 0x89, 0x66, 0x89, 0x67, 0x89, 0x68, /* 0x94-0x97 */ - 0x89, 0x69, 0x89, 0x6A, 0x89, 0x6B, 0x89, 0x6C, /* 0x98-0x9B */ - 0x89, 0x6D, 0x89, 0x6E, 0x89, 0x6F, 0x89, 0x70, /* 0x9C-0x9F */ - 0xB5, 0xB1, 0xB5, 0xB2, 0x89, 0x71, 0x89, 0x72, /* 0xA0-0xA3 */ - 0x89, 0x73, 0x89, 0x74, 0x89, 0x75, 0x89, 0x76, /* 0xA4-0xA7 */ - 0xB5, 0xB3, 0x89, 0x77, 0x89, 0x78, 0x89, 0x79, /* 0xA8-0xAB */ - 0xB5, 0xB4, 0x89, 0x7A, 0x89, 0x81, 0x89, 0x82, /* 0xAC-0xAF */ - 0x89, 0x83, 0x89, 0x84, 0x89, 0x85, 0x89, 0x86, /* 0xB0-0xB3 */ - 0x89, 0x87, 0x89, 0x88, 0x89, 0x89, 0x89, 0x8A, /* 0xB4-0xB7 */ - 0x89, 0x8B, 0x89, 0x8C, 0x89, 0x8D, 0x89, 0x8E, /* 0xB8-0xBB */ - 0x89, 0x8F, 0x89, 0x90, 0x89, 0x91, 0x89, 0x92, /* 0xBC-0xBF */ - 0x89, 0x93, 0x89, 0x94, 0x89, 0x95, 0x89, 0x96, /* 0xC0-0xC3 */ - 0xB5, 0xB5, 0xB5, 0xB6, 0x89, 0x97, 0x89, 0x98, /* 0xC4-0xC7 */ - 0xB5, 0xB7, 0x89, 0x99, 0x89, 0x9A, 0xB5, 0xB8, /* 0xC8-0xCB */ - 0xB5, 0xB9, 0x89, 0x9B, 0xB5, 0xBA, 0x89, 0x9C, /* 0xCC-0xCF */ - 0xB5, 0xBB, 0x89, 0x9D, 0x89, 0x9E, 0x89, 0x9F, /* 0xD0-0xD3 */ - 0xB5, 0xBC, 0xB5, 0xBD, 0x89, 0xA0, 0xB5, 0xBE, /* 0xD4-0xD7 */ - 0x89, 0xA1, 0xB5, 0xBF, 0x89, 0xA2, 0xB5, 0xC0, /* 0xD8-0xDB */ - 0x89, 0xA3, 0xB5, 0xC1, 0x89, 0xA4, 0x89, 0xA5, /* 0xDC-0xDF */ - 0xB5, 0xC2, 0x89, 0xA6, 0x89, 0xA7, 0x89, 0xA8, /* 0xE0-0xE3 */ - 0xB5, 0xC3, 0x89, 0xA9, 0x89, 0xAA, 0x89, 0xAB, /* 0xE4-0xE7 */ - 0xB5, 0xC4, 0x89, 0xAC, 0x89, 0xAD, 0x89, 0xAE, /* 0xE8-0xEB */ - 0x89, 0xAF, 0x89, 0xB0, 0x89, 0xB1, 0x89, 0xB2, /* 0xEC-0xEF */ - 0x89, 0xB3, 0x89, 0xB4, 0x89, 0xB5, 0x89, 0xB6, /* 0xF0-0xF3 */ - 0x89, 0xB7, 0x89, 0xB8, 0x89, 0xB9, 0x89, 0xBA, /* 0xF4-0xF7 */ - 0x89, 0xBB, 0x89, 0xBC, 0x89, 0xBD, 0x89, 0xBE, /* 0xF8-0xFB */ - 0xB5, 0xC5, 0x89, 0xBF, 0x89, 0xC0, 0x89, 0xC1, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_B4[512] = { - 0x89, 0xC2, 0x89, 0xC3, 0x89, 0xC4, 0x89, 0xC5, /* 0x00-0x03 */ - 0x89, 0xC6, 0x89, 0xC7, 0x89, 0xC8, 0x89, 0xC9, /* 0x04-0x07 */ - 0x89, 0xCA, 0x89, 0xCB, 0x89, 0xCC, 0x89, 0xCD, /* 0x08-0x0B */ - 0x89, 0xCE, 0x89, 0xCF, 0x89, 0xD0, 0x89, 0xD1, /* 0x0C-0x0F */ - 0xB5, 0xC6, 0x89, 0xD2, 0x89, 0xD3, 0x89, 0xD4, /* 0x10-0x13 */ - 0x89, 0xD5, 0x89, 0xD6, 0x89, 0xD7, 0x89, 0xD8, /* 0x14-0x17 */ - 0xB5, 0xC7, 0x89, 0xD9, 0x89, 0xDA, 0x89, 0xDB, /* 0x18-0x1B */ - 0xB5, 0xC8, 0x89, 0xDC, 0x89, 0xDD, 0x89, 0xDE, /* 0x1C-0x1F */ - 0xB5, 0xC9, 0x89, 0xDF, 0x89, 0xE0, 0x89, 0xE1, /* 0x20-0x23 */ - 0x89, 0xE2, 0x89, 0xE3, 0x89, 0xE4, 0x89, 0xE5, /* 0x24-0x27 */ - 0xB5, 0xCA, 0xB5, 0xCB, 0x89, 0xE6, 0xB5, 0xCC, /* 0x28-0x2B */ - 0x89, 0xE7, 0x89, 0xE8, 0x89, 0xE9, 0x89, 0xEA, /* 0x2C-0x2F */ - 0x89, 0xEB, 0x89, 0xEC, 0x89, 0xED, 0x89, 0xEE, /* 0x30-0x33 */ - 0xB5, 0xCD, 0x89, 0xEF, 0x89, 0xF0, 0x89, 0xF1, /* 0x34-0x37 */ - 0x89, 0xF2, 0x89, 0xF3, 0x89, 0xF4, 0x89, 0xF5, /* 0x38-0x3B */ - 0x89, 0xF6, 0x89, 0xF7, 0x89, 0xF8, 0x89, 0xF9, /* 0x3C-0x3F */ - 0x89, 0xFA, 0x89, 0xFB, 0x89, 0xFC, 0x89, 0xFD, /* 0x40-0x43 */ - 0x89, 0xFE, 0x8A, 0x41, 0x8A, 0x42, 0x8A, 0x43, /* 0x44-0x47 */ - 0x8A, 0x44, 0x8A, 0x45, 0x8A, 0x46, 0x8A, 0x47, /* 0x48-0x4B */ - 0x8A, 0x48, 0x8A, 0x49, 0x8A, 0x4A, 0x8A, 0x4B, /* 0x4C-0x4F */ - 0xB5, 0xCE, 0xB5, 0xCF, 0x8A, 0x4C, 0x8A, 0x4D, /* 0x50-0x53 */ - 0xB5, 0xD0, 0x8A, 0x4E, 0x8A, 0x4F, 0x8A, 0x50, /* 0x54-0x57 */ - 0xB5, 0xD1, 0x8A, 0x51, 0x8A, 0x52, 0x8A, 0x53, /* 0x58-0x5B */ - 0x8A, 0x54, 0x8A, 0x55, 0x8A, 0x56, 0x8A, 0x57, /* 0x5C-0x5F */ - 0xB5, 0xD2, 0xB5, 0xD3, 0x8A, 0x58, 0xB5, 0xD4, /* 0x60-0x63 */ - 0x8A, 0x59, 0xB5, 0xD5, 0x8A, 0x5A, 0x8A, 0x61, /* 0x64-0x67 */ - 0x8A, 0x62, 0x8A, 0x63, 0x8A, 0x64, 0x8A, 0x65, /* 0x68-0x6B */ - 0xB5, 0xD6, 0x8A, 0x66, 0x8A, 0x67, 0x8A, 0x68, /* 0x6C-0x6F */ - 0x8A, 0x69, 0x8A, 0x6A, 0x8A, 0x6B, 0x8A, 0x6C, /* 0x70-0x73 */ - 0x8A, 0x6D, 0x8A, 0x6E, 0x8A, 0x6F, 0x8A, 0x70, /* 0x74-0x77 */ - 0x8A, 0x71, 0x8A, 0x72, 0x8A, 0x73, 0x8A, 0x74, /* 0x78-0x7B */ - 0x8A, 0x75, 0x8A, 0x76, 0x8A, 0x77, 0x8A, 0x78, /* 0x7C-0x7F */ - - 0xB5, 0xD7, 0x8A, 0x79, 0x8A, 0x7A, 0x8A, 0x81, /* 0x80-0x83 */ - 0x8A, 0x82, 0x8A, 0x83, 0x8A, 0x84, 0x8A, 0x85, /* 0x84-0x87 */ - 0xB5, 0xD8, 0x8A, 0x86, 0x8A, 0x87, 0x8A, 0x88, /* 0x88-0x8B */ - 0x8A, 0x89, 0x8A, 0x8A, 0x8A, 0x8B, 0x8A, 0x8C, /* 0x8C-0x8F */ - 0x8A, 0x8D, 0x8A, 0x8E, 0x8A, 0x8F, 0x8A, 0x90, /* 0x90-0x93 */ - 0x8A, 0x91, 0x8A, 0x92, 0x8A, 0x93, 0x8A, 0x94, /* 0x94-0x97 */ - 0x8A, 0x95, 0x8A, 0x96, 0x8A, 0x97, 0x8A, 0x98, /* 0x98-0x9B */ - 0x8A, 0x99, 0xB5, 0xD9, 0x8A, 0x9A, 0x8A, 0x9B, /* 0x9C-0x9F */ - 0x8A, 0x9C, 0x8A, 0x9D, 0x8A, 0x9E, 0x8A, 0x9F, /* 0xA0-0xA3 */ - 0xB5, 0xDA, 0x8A, 0xA0, 0x8A, 0xA1, 0x8A, 0xA2, /* 0xA4-0xA7 */ - 0xB5, 0xDB, 0x8A, 0xA3, 0x8A, 0xA4, 0x8A, 0xA5, /* 0xA8-0xAB */ - 0xB5, 0xDC, 0x8A, 0xA6, 0x8A, 0xA7, 0x8A, 0xA8, /* 0xAC-0xAF */ - 0x8A, 0xA9, 0x8A, 0xAA, 0x8A, 0xAB, 0x8A, 0xAC, /* 0xB0-0xB3 */ - 0x8A, 0xAD, 0xB5, 0xDD, 0x8A, 0xAE, 0xB5, 0xDE, /* 0xB4-0xB7 */ - 0x8A, 0xAF, 0xB5, 0xDF, 0x8A, 0xB0, 0x8A, 0xB1, /* 0xB8-0xBB */ - 0x8A, 0xB2, 0x8A, 0xB3, 0x8A, 0xB4, 0x8A, 0xB5, /* 0xBC-0xBF */ - 0xB5, 0xE0, 0x8A, 0xB6, 0x8A, 0xB7, 0x8A, 0xB8, /* 0xC0-0xC3 */ - 0xB5, 0xE1, 0x8A, 0xB9, 0x8A, 0xBA, 0x8A, 0xBB, /* 0xC4-0xC7 */ - 0xB5, 0xE2, 0x8A, 0xBC, 0x8A, 0xBD, 0x8A, 0xBE, /* 0xC8-0xCB */ - 0x8A, 0xBF, 0x8A, 0xC0, 0x8A, 0xC1, 0x8A, 0xC2, /* 0xCC-0xCF */ - 0xB5, 0xE3, 0x8A, 0xC3, 0x8A, 0xC4, 0x8A, 0xC5, /* 0xD0-0xD3 */ - 0x8A, 0xC6, 0xB5, 0xE4, 0x8A, 0xC7, 0x8A, 0xC8, /* 0xD4-0xD7 */ - 0x8A, 0xC9, 0x8A, 0xCA, 0x8A, 0xCB, 0x8A, 0xCC, /* 0xD8-0xDB */ - 0xB5, 0xE5, 0xB5, 0xE6, 0x8A, 0xCD, 0x8A, 0xCE, /* 0xDC-0xDF */ - 0xB5, 0xE7, 0x8A, 0xCF, 0x8A, 0xD0, 0xB5, 0xE8, /* 0xE0-0xE3 */ - 0xB5, 0xE9, 0x8A, 0xD1, 0xB5, 0xEA, 0x8A, 0xD2, /* 0xE4-0xE7 */ - 0x8A, 0xD3, 0x8A, 0xD4, 0x8A, 0xD5, 0x8A, 0xD6, /* 0xE8-0xEB */ - 0xB5, 0xEB, 0xB5, 0xEC, 0x8A, 0xD7, 0xB5, 0xED, /* 0xEC-0xEF */ - 0x8A, 0xD8, 0xB5, 0xEE, 0x8A, 0xD9, 0x8A, 0xDA, /* 0xF0-0xF3 */ - 0x8A, 0xDB, 0x8A, 0xDC, 0x8A, 0xDD, 0x8A, 0xDE, /* 0xF4-0xF7 */ - 0xB5, 0xEF, 0x8A, 0xDF, 0x8A, 0xE0, 0x8A, 0xE1, /* 0xF8-0xFB */ - 0x8A, 0xE2, 0x8A, 0xE3, 0x8A, 0xE4, 0x8A, 0xE5, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_B5[512] = { - 0x8A, 0xE6, 0x8A, 0xE7, 0x8A, 0xE8, 0x8A, 0xE9, /* 0x00-0x03 */ - 0x8A, 0xEA, 0x8A, 0xEB, 0x8A, 0xEC, 0x8A, 0xED, /* 0x04-0x07 */ - 0x8A, 0xEE, 0x8A, 0xEF, 0x8A, 0xF0, 0x8A, 0xF1, /* 0x08-0x0B */ - 0x8A, 0xF2, 0x8A, 0xF3, 0x8A, 0xF4, 0x8A, 0xF5, /* 0x0C-0x0F */ - 0x8A, 0xF6, 0x8A, 0xF7, 0x8A, 0xF8, 0x8A, 0xF9, /* 0x10-0x13 */ - 0xB5, 0xF0, 0xB5, 0xF1, 0x8A, 0xFA, 0x8A, 0xFB, /* 0x14-0x17 */ - 0xB5, 0xF2, 0x8A, 0xFC, 0x8A, 0xFD, 0xB5, 0xF3, /* 0x18-0x1B */ - 0xB5, 0xF4, 0x8A, 0xFE, 0x8B, 0x41, 0x8B, 0x42, /* 0x1C-0x1F */ - 0x8B, 0x43, 0x8B, 0x44, 0x8B, 0x45, 0x8B, 0x46, /* 0x20-0x23 */ - 0xB5, 0xF5, 0xB5, 0xF6, 0x8B, 0x47, 0xB5, 0xF7, /* 0x24-0x27 */ - 0xB5, 0xF8, 0xB5, 0xF9, 0xB5, 0xFA, 0x8B, 0x48, /* 0x28-0x2B */ - 0x8B, 0x49, 0x8B, 0x4A, 0x8B, 0x4B, 0x8B, 0x4C, /* 0x2C-0x2F */ - 0xB5, 0xFB, 0xB5, 0xFC, 0x8B, 0x4D, 0x8B, 0x4E, /* 0x30-0x33 */ - 0xB5, 0xFD, 0x8B, 0x4F, 0x8B, 0x50, 0x8B, 0x51, /* 0x34-0x37 */ - 0xB5, 0xFE, 0x8B, 0x52, 0x8B, 0x53, 0x8B, 0x54, /* 0x38-0x3B */ - 0x8B, 0x55, 0x8B, 0x56, 0x8B, 0x57, 0x8B, 0x58, /* 0x3C-0x3F */ - 0xB6, 0xA1, 0xB6, 0xA2, 0x8B, 0x59, 0xB6, 0xA3, /* 0x40-0x43 */ - 0xB6, 0xA4, 0xB6, 0xA5, 0x8B, 0x5A, 0x8B, 0x61, /* 0x44-0x47 */ - 0x8B, 0x62, 0x8B, 0x63, 0x8B, 0x64, 0xB6, 0xA6, /* 0x48-0x4B */ - 0xB6, 0xA7, 0xB6, 0xA8, 0x8B, 0x65, 0x8B, 0x66, /* 0x4C-0x4F */ - 0xB6, 0xA9, 0x8B, 0x67, 0x8B, 0x68, 0x8B, 0x69, /* 0x50-0x53 */ - 0xB6, 0xAA, 0x8B, 0x6A, 0x8B, 0x6B, 0x8B, 0x6C, /* 0x54-0x57 */ - 0x8B, 0x6D, 0x8B, 0x6E, 0x8B, 0x6F, 0x8B, 0x70, /* 0x58-0x5B */ - 0xB6, 0xAB, 0xB6, 0xAC, 0x8B, 0x71, 0xB6, 0xAD, /* 0x5C-0x5F */ - 0xB6, 0xAE, 0xB6, 0xAF, 0x8B, 0x72, 0x8B, 0x73, /* 0x60-0x63 */ - 0x8B, 0x74, 0x8B, 0x75, 0x8B, 0x76, 0x8B, 0x77, /* 0x64-0x67 */ - 0x8B, 0x78, 0x8B, 0x79, 0x8B, 0x7A, 0x8B, 0x81, /* 0x68-0x6B */ - 0x8B, 0x82, 0x8B, 0x83, 0x8B, 0x84, 0x8B, 0x85, /* 0x6C-0x6F */ - 0x8B, 0x86, 0x8B, 0x87, 0x8B, 0x88, 0x8B, 0x89, /* 0x70-0x73 */ - 0x8B, 0x8A, 0x8B, 0x8B, 0x8B, 0x8C, 0x8B, 0x8D, /* 0x74-0x77 */ - 0x8B, 0x8E, 0x8B, 0x8F, 0x8B, 0x90, 0x8B, 0x91, /* 0x78-0x7B */ - 0x8B, 0x92, 0x8B, 0x93, 0x8B, 0x94, 0x8B, 0x95, /* 0x7C-0x7F */ - - 0x8B, 0x96, 0x8B, 0x97, 0x8B, 0x98, 0x8B, 0x99, /* 0x80-0x83 */ - 0x8B, 0x9A, 0x8B, 0x9B, 0x8B, 0x9C, 0x8B, 0x9D, /* 0x84-0x87 */ - 0x8B, 0x9E, 0x8B, 0x9F, 0x8B, 0xA0, 0x8B, 0xA1, /* 0x88-0x8B */ - 0x8B, 0xA2, 0x8B, 0xA3, 0x8B, 0xA4, 0x8B, 0xA5, /* 0x8C-0x8F */ - 0x8B, 0xA6, 0x8B, 0xA7, 0x8B, 0xA8, 0x8B, 0xA9, /* 0x90-0x93 */ - 0x8B, 0xAA, 0x8B, 0xAB, 0x8B, 0xAC, 0x8B, 0xAD, /* 0x94-0x97 */ - 0x8B, 0xAE, 0x8B, 0xAF, 0x8B, 0xB0, 0x8B, 0xB1, /* 0x98-0x9B */ - 0x8B, 0xB2, 0x8B, 0xB3, 0x8B, 0xB4, 0x8B, 0xB5, /* 0x9C-0x9F */ - 0xB6, 0xB0, 0xB6, 0xB1, 0x8B, 0xB6, 0x8B, 0xB7, /* 0xA0-0xA3 */ - 0xB6, 0xB2, 0x8B, 0xB8, 0x8B, 0xB9, 0x8B, 0xBA, /* 0xA4-0xA7 */ - 0xB6, 0xB3, 0x8B, 0xBB, 0xB6, 0xB4, 0xB6, 0xB5, /* 0xA8-0xAB */ - 0x8B, 0xBC, 0x8B, 0xBD, 0x8B, 0xBE, 0x8B, 0xBF, /* 0xAC-0xAF */ - 0xB6, 0xB6, 0xB6, 0xB7, 0x8B, 0xC0, 0xB6, 0xB8, /* 0xB0-0xB3 */ - 0xB6, 0xB9, 0xB6, 0xBA, 0x8B, 0xC1, 0x8B, 0xC2, /* 0xB4-0xB7 */ - 0x8B, 0xC3, 0x8B, 0xC4, 0x8B, 0xC5, 0xB6, 0xBB, /* 0xB8-0xBB */ - 0xB6, 0xBC, 0xB6, 0xBD, 0x8B, 0xC6, 0x8B, 0xC7, /* 0xBC-0xBF */ - 0xB6, 0xBE, 0x8B, 0xC8, 0x8B, 0xC9, 0x8B, 0xCA, /* 0xC0-0xC3 */ - 0xB6, 0xBF, 0x8B, 0xCB, 0x8B, 0xCC, 0x8B, 0xCD, /* 0xC4-0xC7 */ - 0x8B, 0xCE, 0x8B, 0xCF, 0x8B, 0xD0, 0x8B, 0xD1, /* 0xC8-0xCB */ - 0xB6, 0xC0, 0xB6, 0xC1, 0x8B, 0xD2, 0xB6, 0xC2, /* 0xCC-0xCF */ - 0xB6, 0xC3, 0xB6, 0xC4, 0x8B, 0xD3, 0x8B, 0xD4, /* 0xD0-0xD3 */ - 0x8B, 0xD5, 0x8B, 0xD6, 0x8B, 0xD7, 0x8B, 0xD8, /* 0xD4-0xD7 */ - 0xB6, 0xC5, 0x8B, 0xD9, 0x8B, 0xDA, 0x8B, 0xDB, /* 0xD8-0xDB */ - 0x8B, 0xDC, 0x8B, 0xDD, 0x8B, 0xDE, 0x8B, 0xDF, /* 0xDC-0xDF */ - 0x8B, 0xE0, 0x8B, 0xE1, 0x8B, 0xE2, 0x8B, 0xE3, /* 0xE0-0xE3 */ - 0x8B, 0xE4, 0x8B, 0xE5, 0x8B, 0xE6, 0x8B, 0xE7, /* 0xE4-0xE7 */ - 0x8B, 0xE8, 0x8B, 0xE9, 0x8B, 0xEA, 0x8B, 0xEB, /* 0xE8-0xEB */ - 0xB6, 0xC6, 0x8B, 0xEC, 0x8B, 0xED, 0x8B, 0xEE, /* 0xEC-0xEF */ - 0x8B, 0xEF, 0x8B, 0xF0, 0x8B, 0xF1, 0x8B, 0xF2, /* 0xF0-0xF3 */ - 0x8B, 0xF3, 0x8B, 0xF4, 0x8B, 0xF5, 0x8B, 0xF6, /* 0xF4-0xF7 */ - 0x8B, 0xF7, 0x8B, 0xF8, 0x8B, 0xF9, 0x8B, 0xFA, /* 0xF8-0xFB */ - 0x8B, 0xFB, 0x8B, 0xFC, 0x8B, 0xFD, 0x8B, 0xFE, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_B6[512] = { - 0x8C, 0x41, 0x8C, 0x42, 0x8C, 0x43, 0x8C, 0x44, /* 0x00-0x03 */ - 0x8C, 0x45, 0x8C, 0x46, 0x8C, 0x47, 0x8C, 0x48, /* 0x04-0x07 */ - 0x8C, 0x49, 0x8C, 0x4A, 0x8C, 0x4B, 0x8C, 0x4C, /* 0x08-0x0B */ - 0x8C, 0x4D, 0x8C, 0x4E, 0x8C, 0x4F, 0x8C, 0x50, /* 0x0C-0x0F */ - 0xB6, 0xC7, 0xB6, 0xC8, 0x8C, 0x51, 0x8C, 0x52, /* 0x10-0x13 */ - 0xB6, 0xC9, 0x8C, 0x53, 0x8C, 0x54, 0x8C, 0x55, /* 0x14-0x17 */ - 0xB6, 0xCA, 0x8C, 0x56, 0x8C, 0x57, 0x8C, 0x58, /* 0x18-0x1B */ - 0x8C, 0x59, 0x8C, 0x5A, 0x8C, 0x61, 0x8C, 0x62, /* 0x1C-0x1F */ - 0x8C, 0x63, 0x8C, 0x64, 0x8C, 0x65, 0x8C, 0x66, /* 0x20-0x23 */ - 0x8C, 0x67, 0xB6, 0xCB, 0x8C, 0x68, 0x8C, 0x69, /* 0x24-0x27 */ - 0x8C, 0x6A, 0x8C, 0x6B, 0x8C, 0x6C, 0x8C, 0x6D, /* 0x28-0x2B */ - 0xB6, 0xCC, 0x8C, 0x6E, 0x8C, 0x6F, 0x8C, 0x70, /* 0x2C-0x2F */ - 0x8C, 0x71, 0x8C, 0x72, 0x8C, 0x73, 0x8C, 0x74, /* 0x30-0x33 */ - 0xB6, 0xCD, 0x8C, 0x75, 0x8C, 0x76, 0x8C, 0x77, /* 0x34-0x37 */ - 0x8C, 0x78, 0x8C, 0x79, 0x8C, 0x7A, 0x8C, 0x81, /* 0x38-0x3B */ - 0x8C, 0x82, 0x8C, 0x83, 0x8C, 0x84, 0x8C, 0x85, /* 0x3C-0x3F */ - 0x8C, 0x86, 0x8C, 0x87, 0x8C, 0x88, 0x8C, 0x89, /* 0x40-0x43 */ - 0x8C, 0x8A, 0x8C, 0x8B, 0x8C, 0x8C, 0x8C, 0x8D, /* 0x44-0x47 */ - 0xB6, 0xCE, 0x8C, 0x8E, 0x8C, 0x8F, 0x8C, 0x90, /* 0x48-0x4B */ - 0x8C, 0x91, 0x8C, 0x92, 0x8C, 0x93, 0x8C, 0x94, /* 0x4C-0x4F */ - 0x8C, 0x95, 0x8C, 0x96, 0x8C, 0x97, 0x8C, 0x98, /* 0x50-0x53 */ - 0x8C, 0x99, 0x8C, 0x9A, 0x8C, 0x9B, 0x8C, 0x9C, /* 0x54-0x57 */ - 0x8C, 0x9D, 0x8C, 0x9E, 0x8C, 0x9F, 0x8C, 0xA0, /* 0x58-0x5B */ - 0x8C, 0xA1, 0x8C, 0xA2, 0x8C, 0xA3, 0x8C, 0xA4, /* 0x5C-0x5F */ - 0x8C, 0xA5, 0x8C, 0xA6, 0x8C, 0xA7, 0x8C, 0xA8, /* 0x60-0x63 */ - 0xB6, 0xCF, 0x8C, 0xA9, 0x8C, 0xAA, 0x8C, 0xAB, /* 0x64-0x67 */ - 0xB6, 0xD0, 0x8C, 0xAC, 0x8C, 0xAD, 0x8C, 0xAE, /* 0x68-0x6B */ - 0x8C, 0xAF, 0x8C, 0xB0, 0x8C, 0xB1, 0x8C, 0xB2, /* 0x6C-0x6F */ - 0x8C, 0xB3, 0x8C, 0xB4, 0x8C, 0xB5, 0x8C, 0xB6, /* 0x70-0x73 */ - 0x8C, 0xB7, 0x8C, 0xB8, 0x8C, 0xB9, 0x8C, 0xBA, /* 0x74-0x77 */ - 0x8C, 0xBB, 0x8C, 0xBC, 0x8C, 0xBD, 0x8C, 0xBE, /* 0x78-0x7B */ - 0x8C, 0xBF, 0x8C, 0xC0, 0x8C, 0xC1, 0x8C, 0xC2, /* 0x7C-0x7F */ - - 0x8C, 0xC3, 0x8C, 0xC4, 0x8C, 0xC5, 0x8C, 0xC6, /* 0x80-0x83 */ - 0x8C, 0xC7, 0x8C, 0xC8, 0x8C, 0xC9, 0x8C, 0xCA, /* 0x84-0x87 */ - 0x8C, 0xCB, 0x8C, 0xCC, 0x8C, 0xCD, 0x8C, 0xCE, /* 0x88-0x8B */ - 0x8C, 0xCF, 0x8C, 0xD0, 0x8C, 0xD1, 0x8C, 0xD2, /* 0x8C-0x8F */ - 0x8C, 0xD3, 0x8C, 0xD4, 0x8C, 0xD5, 0x8C, 0xD6, /* 0x90-0x93 */ - 0x8C, 0xD7, 0x8C, 0xD8, 0x8C, 0xD9, 0x8C, 0xDA, /* 0x94-0x97 */ - 0x8C, 0xDB, 0x8C, 0xDC, 0x8C, 0xDD, 0x8C, 0xDE, /* 0x98-0x9B */ - 0xB6, 0xD1, 0xB6, 0xD2, 0x8C, 0xDF, 0x8C, 0xE0, /* 0x9C-0x9F */ - 0xB6, 0xD3, 0x8C, 0xE1, 0x8C, 0xE2, 0x8C, 0xE3, /* 0xA0-0xA3 */ - 0xB6, 0xD4, 0x8C, 0xE4, 0x8C, 0xE5, 0x8C, 0xE6, /* 0xA4-0xA7 */ - 0x8C, 0xE7, 0x8C, 0xE8, 0x8C, 0xE9, 0xB6, 0xD5, /* 0xA8-0xAB */ - 0xB6, 0xD6, 0x8C, 0xEA, 0x8C, 0xEB, 0x8C, 0xEC, /* 0xAC-0xAF */ - 0x8C, 0xED, 0xB6, 0xD7, 0x8C, 0xEE, 0x8C, 0xEF, /* 0xB0-0xB3 */ - 0x8C, 0xF0, 0x8C, 0xF1, 0x8C, 0xF2, 0x8C, 0xF3, /* 0xB4-0xB7 */ - 0x8C, 0xF4, 0x8C, 0xF5, 0x8C, 0xF6, 0x8C, 0xF7, /* 0xB8-0xBB */ - 0x8C, 0xF8, 0x8C, 0xF9, 0x8C, 0xFA, 0x8C, 0xFB, /* 0xBC-0xBF */ - 0x8C, 0xFC, 0x8C, 0xFD, 0x8C, 0xFE, 0x8D, 0x41, /* 0xC0-0xC3 */ - 0x8D, 0x42, 0x8D, 0x43, 0x8D, 0x44, 0x8D, 0x45, /* 0xC4-0xC7 */ - 0x8D, 0x46, 0x8D, 0x47, 0x8D, 0x48, 0x8D, 0x49, /* 0xC8-0xCB */ - 0x8D, 0x4A, 0x8D, 0x4B, 0x8D, 0x4C, 0x8D, 0x4D, /* 0xCC-0xCF */ - 0x8D, 0x4E, 0x8D, 0x4F, 0x8D, 0x50, 0x8D, 0x51, /* 0xD0-0xD3 */ - 0xB6, 0xD8, 0x8D, 0x52, 0x8D, 0x53, 0x8D, 0x54, /* 0xD4-0xD7 */ - 0x8D, 0x55, 0x8D, 0x56, 0x8D, 0x57, 0x8D, 0x58, /* 0xD8-0xDB */ - 0x8D, 0x59, 0x8D, 0x5A, 0x8D, 0x61, 0x8D, 0x62, /* 0xDC-0xDF */ - 0x8D, 0x63, 0x8D, 0x64, 0x8D, 0x65, 0x8D, 0x66, /* 0xE0-0xE3 */ - 0x8D, 0x67, 0x8D, 0x68, 0x8D, 0x69, 0x8D, 0x6A, /* 0xE4-0xE7 */ - 0x8D, 0x6B, 0x8D, 0x6C, 0x8D, 0x6D, 0x8D, 0x6E, /* 0xE8-0xEB */ - 0x8D, 0x6F, 0x8D, 0x70, 0x8D, 0x71, 0x8D, 0x72, /* 0xEC-0xEF */ - 0xB6, 0xD9, 0x8D, 0x73, 0x8D, 0x74, 0x8D, 0x75, /* 0xF0-0xF3 */ - 0xB6, 0xDA, 0x8D, 0x76, 0x8D, 0x77, 0x8D, 0x78, /* 0xF4-0xF7 */ - 0xB6, 0xDB, 0x8D, 0x79, 0x8D, 0x7A, 0x8D, 0x81, /* 0xF8-0xFB */ - 0x8D, 0x82, 0x8D, 0x83, 0x8D, 0x84, 0x8D, 0x85, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_B7[512] = { - 0xB6, 0xDC, 0xB6, 0xDD, 0x8D, 0x86, 0x8D, 0x87, /* 0x00-0x03 */ - 0x8D, 0x88, 0xB6, 0xDE, 0x8D, 0x89, 0x8D, 0x8A, /* 0x04-0x07 */ - 0x8D, 0x8B, 0x8D, 0x8C, 0x8D, 0x8D, 0x8D, 0x8E, /* 0x08-0x0B */ - 0x8D, 0x8F, 0x8D, 0x90, 0x8D, 0x91, 0x8D, 0x92, /* 0x0C-0x0F */ - 0x8D, 0x93, 0x8D, 0x94, 0x8D, 0x95, 0x8D, 0x96, /* 0x10-0x13 */ - 0x8D, 0x97, 0x8D, 0x98, 0x8D, 0x99, 0x8D, 0x9A, /* 0x14-0x17 */ - 0x8D, 0x9B, 0x8D, 0x9C, 0x8D, 0x9D, 0x8D, 0x9E, /* 0x18-0x1B */ - 0x8D, 0x9F, 0x8D, 0xA0, 0x8D, 0xA1, 0x8D, 0xA2, /* 0x1C-0x1F */ - 0x8D, 0xA3, 0x8D, 0xA4, 0x8D, 0xA5, 0x8D, 0xA6, /* 0x20-0x23 */ - 0x8D, 0xA7, 0x8D, 0xA8, 0x8D, 0xA9, 0x8D, 0xAA, /* 0x24-0x27 */ - 0xB6, 0xDF, 0xB6, 0xE0, 0x8D, 0xAB, 0x8D, 0xAC, /* 0x28-0x2B */ - 0xB6, 0xE1, 0x8D, 0xAD, 0x8D, 0xAE, 0xB6, 0xE2, /* 0x2C-0x2F */ - 0xB6, 0xE3, 0x8D, 0xAF, 0x8D, 0xB0, 0x8D, 0xB1, /* 0x30-0x33 */ - 0x8D, 0xB2, 0x8D, 0xB3, 0x8D, 0xB4, 0x8D, 0xB5, /* 0x34-0x37 */ - 0xB6, 0xE4, 0xB6, 0xE5, 0x8D, 0xB6, 0xB6, 0xE6, /* 0x38-0x3B */ - 0x8D, 0xB7, 0x8D, 0xB8, 0x8D, 0xB9, 0x8D, 0xBA, /* 0x3C-0x3F */ - 0x8D, 0xBB, 0x8D, 0xBC, 0x8D, 0xBD, 0x8D, 0xBE, /* 0x40-0x43 */ - 0xB6, 0xE7, 0x8D, 0xBF, 0x8D, 0xC0, 0x8D, 0xC1, /* 0x44-0x47 */ - 0xB6, 0xE8, 0x8D, 0xC2, 0x8D, 0xC3, 0x8D, 0xC4, /* 0x48-0x4B */ - 0xB6, 0xE9, 0x8D, 0xC5, 0x8D, 0xC6, 0x8D, 0xC7, /* 0x4C-0x4F */ - 0x8D, 0xC8, 0x8D, 0xC9, 0x8D, 0xCA, 0x8D, 0xCB, /* 0x50-0x53 */ - 0xB6, 0xEA, 0xB6, 0xEB, 0x8D, 0xCC, 0x8D, 0xCD, /* 0x54-0x57 */ - 0x8D, 0xCE, 0x8D, 0xCF, 0x8D, 0xD0, 0x8D, 0xD1, /* 0x58-0x5B */ - 0x8D, 0xD2, 0x8D, 0xD3, 0x8D, 0xD4, 0x8D, 0xD5, /* 0x5C-0x5F */ - 0xB6, 0xEC, 0x8D, 0xD6, 0x8D, 0xD7, 0x8D, 0xD8, /* 0x60-0x63 */ - 0xB6, 0xED, 0x8D, 0xD9, 0x8D, 0xDA, 0x8D, 0xDB, /* 0x64-0x67 */ - 0xB6, 0xEE, 0x8D, 0xDC, 0x8D, 0xDD, 0x8D, 0xDE, /* 0x68-0x6B */ - 0x8D, 0xDF, 0x8D, 0xE0, 0x8D, 0xE1, 0x8D, 0xE2, /* 0x6C-0x6F */ - 0xB6, 0xEF, 0xB6, 0xF0, 0x8D, 0xE3, 0xB6, 0xF1, /* 0x70-0x73 */ - 0x8D, 0xE4, 0xB6, 0xF2, 0x8D, 0xE5, 0x8D, 0xE6, /* 0x74-0x77 */ - 0x8D, 0xE7, 0x8D, 0xE8, 0x8D, 0xE9, 0x8D, 0xEA, /* 0x78-0x7B */ - 0xB6, 0xF3, 0xB6, 0xF4, 0x8D, 0xEB, 0x8D, 0xEC, /* 0x7C-0x7F */ - - 0xB6, 0xF5, 0x8D, 0xED, 0x8D, 0xEE, 0x8D, 0xEF, /* 0x80-0x83 */ - 0xB6, 0xF6, 0x8D, 0xF0, 0x8D, 0xF1, 0x8D, 0xF2, /* 0x84-0x87 */ - 0x8D, 0xF3, 0x8D, 0xF4, 0x8D, 0xF5, 0x8D, 0xF6, /* 0x88-0x8B */ - 0xB6, 0xF7, 0xB6, 0xF8, 0x8D, 0xF7, 0xB6, 0xF9, /* 0x8C-0x8F */ - 0xB6, 0xFA, 0xB6, 0xFB, 0xB6, 0xFC, 0x8D, 0xF8, /* 0x90-0x93 */ - 0x8D, 0xF9, 0x8D, 0xFA, 0xB6, 0xFD, 0xB6, 0xFE, /* 0x94-0x97 */ - 0xB7, 0xA1, 0xB7, 0xA2, 0x8D, 0xFB, 0x8D, 0xFC, /* 0x98-0x9B */ - 0xB7, 0xA3, 0x8D, 0xFD, 0x8D, 0xFE, 0x8E, 0x41, /* 0x9C-0x9F */ - 0xB7, 0xA4, 0x8E, 0x42, 0x8E, 0x43, 0x8E, 0x44, /* 0xA0-0xA3 */ - 0x8E, 0x45, 0x8E, 0x46, 0x8E, 0x47, 0x8E, 0x48, /* 0xA4-0xA7 */ - 0xB7, 0xA5, 0xB7, 0xA6, 0x8E, 0x49, 0xB7, 0xA7, /* 0xA8-0xAB */ - 0xB7, 0xA8, 0xB7, 0xA9, 0x8E, 0x4A, 0x8E, 0x4B, /* 0xAC-0xAF */ - 0x8E, 0x4C, 0x8E, 0x4D, 0x8E, 0x4E, 0x8E, 0x4F, /* 0xB0-0xB3 */ - 0xB7, 0xAA, 0xB7, 0xAB, 0x8E, 0x50, 0x8E, 0x51, /* 0xB4-0xB7 */ - 0xB7, 0xAC, 0x8E, 0x52, 0x8E, 0x53, 0x8E, 0x54, /* 0xB8-0xBB */ - 0x8E, 0x55, 0x8E, 0x56, 0x8E, 0x57, 0x8E, 0x58, /* 0xBC-0xBF */ - 0x8E, 0x59, 0x8E, 0x5A, 0x8E, 0x61, 0x8E, 0x62, /* 0xC0-0xC3 */ - 0x8E, 0x63, 0x8E, 0x64, 0x8E, 0x65, 0xB7, 0xAD, /* 0xC4-0xC7 */ - 0x8E, 0x66, 0xB7, 0xAE, 0x8E, 0x67, 0x8E, 0x68, /* 0xC8-0xCB */ - 0x8E, 0x69, 0x8E, 0x6A, 0x8E, 0x6B, 0x8E, 0x6C, /* 0xCC-0xCF */ - 0x8E, 0x6D, 0x8E, 0x6E, 0x8E, 0x6F, 0x8E, 0x70, /* 0xD0-0xD3 */ - 0x8E, 0x71, 0x8E, 0x72, 0x8E, 0x73, 0x8E, 0x74, /* 0xD4-0xD7 */ - 0x8E, 0x75, 0x8E, 0x76, 0x8E, 0x77, 0x8E, 0x78, /* 0xD8-0xDB */ - 0x8E, 0x79, 0x8E, 0x7A, 0x8E, 0x81, 0x8E, 0x82, /* 0xDC-0xDF */ - 0x8E, 0x83, 0x8E, 0x84, 0x8E, 0x85, 0x8E, 0x86, /* 0xE0-0xE3 */ - 0x8E, 0x87, 0x8E, 0x88, 0x8E, 0x89, 0x8E, 0x8A, /* 0xE4-0xE7 */ - 0x8E, 0x8B, 0x8E, 0x8C, 0x8E, 0x8D, 0x8E, 0x8E, /* 0xE8-0xEB */ - 0xB7, 0xAF, 0xB7, 0xB0, 0x8E, 0x8F, 0x8E, 0x90, /* 0xEC-0xEF */ - 0xB7, 0xB1, 0x8E, 0x91, 0x8E, 0x92, 0x8E, 0x93, /* 0xF0-0xF3 */ - 0xB7, 0xB2, 0x8E, 0x94, 0x8E, 0x95, 0x8E, 0x96, /* 0xF4-0xF7 */ - 0x8E, 0x97, 0x8E, 0x98, 0x8E, 0x99, 0x8E, 0x9A, /* 0xF8-0xFB */ - 0xB7, 0xB3, 0xB7, 0xB4, 0x8E, 0x9B, 0xB7, 0xB5, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_B8[512] = { - 0xB7, 0xB6, 0xB7, 0xB7, 0x8E, 0x9C, 0x8E, 0x9D, /* 0x00-0x03 */ - 0x8E, 0x9E, 0x8E, 0x9F, 0x8E, 0xA0, 0xB7, 0xB8, /* 0x04-0x07 */ - 0xB7, 0xB9, 0xB7, 0xBA, 0x8E, 0xA1, 0x8E, 0xA2, /* 0x08-0x0B */ - 0xB7, 0xBB, 0x8E, 0xA3, 0x8E, 0xA4, 0x8E, 0xA5, /* 0x0C-0x0F */ - 0xB7, 0xBC, 0x8E, 0xA6, 0x8E, 0xA7, 0x8E, 0xA8, /* 0x10-0x13 */ - 0x8E, 0xA9, 0x8E, 0xAA, 0x8E, 0xAB, 0x8E, 0xAC, /* 0x14-0x17 */ - 0xB7, 0xBD, 0xB7, 0xBE, 0x8E, 0xAD, 0xB7, 0xBF, /* 0x18-0x1B */ - 0x8E, 0xAE, 0xB7, 0xC0, 0x8E, 0xAF, 0x8E, 0xB0, /* 0x1C-0x1F */ - 0x8E, 0xB1, 0x8E, 0xB2, 0x8E, 0xB3, 0x8E, 0xB4, /* 0x20-0x23 */ - 0xB7, 0xC1, 0xB7, 0xC2, 0x8E, 0xB5, 0x8E, 0xB6, /* 0x24-0x27 */ - 0xB7, 0xC3, 0x8E, 0xB7, 0x8E, 0xB8, 0x8E, 0xB9, /* 0x28-0x2B */ - 0xB7, 0xC4, 0x8E, 0xBA, 0x8E, 0xBB, 0x8E, 0xBC, /* 0x2C-0x2F */ - 0x8E, 0xBD, 0x8E, 0xBE, 0x8E, 0xBF, 0x8E, 0xC0, /* 0x30-0x33 */ - 0xB7, 0xC5, 0xB7, 0xC6, 0x8E, 0xC1, 0xB7, 0xC7, /* 0x34-0x37 */ - 0xB7, 0xC8, 0xB7, 0xC9, 0x8E, 0xC2, 0x8E, 0xC3, /* 0x38-0x3B */ - 0x8E, 0xC4, 0x8E, 0xC5, 0x8E, 0xC6, 0x8E, 0xC7, /* 0x3C-0x3F */ - 0xB7, 0xCA, 0x8E, 0xC8, 0x8E, 0xC9, 0x8E, 0xCA, /* 0x40-0x43 */ - 0xB7, 0xCB, 0x8E, 0xCB, 0x8E, 0xCC, 0x8E, 0xCD, /* 0x44-0x47 */ - 0x8E, 0xCE, 0x8E, 0xCF, 0x8E, 0xD0, 0x8E, 0xD1, /* 0x48-0x4B */ - 0x8E, 0xD2, 0x8E, 0xD3, 0x8E, 0xD4, 0x8E, 0xD5, /* 0x4C-0x4F */ - 0x8E, 0xD6, 0xB7, 0xCC, 0x8E, 0xD7, 0xB7, 0xCD, /* 0x50-0x53 */ - 0x8E, 0xD8, 0x8E, 0xD9, 0x8E, 0xDA, 0x8E, 0xDB, /* 0x54-0x57 */ - 0x8E, 0xDC, 0x8E, 0xDD, 0x8E, 0xDE, 0x8E, 0xDF, /* 0x58-0x5B */ - 0xB7, 0xCE, 0xB7, 0xCF, 0x8E, 0xE0, 0x8E, 0xE1, /* 0x5C-0x5F */ - 0xB7, 0xD0, 0x8E, 0xE2, 0x8E, 0xE3, 0x8E, 0xE4, /* 0x60-0x63 */ - 0xB7, 0xD1, 0x8E, 0xE5, 0x8E, 0xE6, 0x8E, 0xE7, /* 0x64-0x67 */ - 0x8E, 0xE8, 0x8E, 0xE9, 0x8E, 0xEA, 0x8E, 0xEB, /* 0x68-0x6B */ - 0xB7, 0xD2, 0xB7, 0xD3, 0x8E, 0xEC, 0xB7, 0xD4, /* 0x6C-0x6F */ - 0x8E, 0xED, 0xB7, 0xD5, 0x8E, 0xEE, 0x8E, 0xEF, /* 0x70-0x73 */ - 0x8E, 0xF0, 0x8E, 0xF1, 0x8E, 0xF2, 0x8E, 0xF3, /* 0x74-0x77 */ - 0xB7, 0xD6, 0x8E, 0xF4, 0x8E, 0xF5, 0x8E, 0xF6, /* 0x78-0x7B */ - 0xB7, 0xD7, 0x8E, 0xF7, 0x8E, 0xF8, 0x8E, 0xF9, /* 0x7C-0x7F */ - - 0x8E, 0xFA, 0x8E, 0xFB, 0x8E, 0xFC, 0x8E, 0xFD, /* 0x80-0x83 */ - 0x8E, 0xFE, 0x8F, 0x41, 0x8F, 0x42, 0x8F, 0x43, /* 0x84-0x87 */ - 0x8F, 0x44, 0x8F, 0x45, 0x8F, 0x46, 0x8F, 0x47, /* 0x88-0x8B */ - 0x8F, 0x48, 0xB7, 0xD8, 0x8F, 0x49, 0x8F, 0x4A, /* 0x8C-0x8F */ - 0x8F, 0x4B, 0x8F, 0x4C, 0x8F, 0x4D, 0x8F, 0x4E, /* 0x90-0x93 */ - 0x8F, 0x4F, 0x8F, 0x50, 0x8F, 0x51, 0x8F, 0x52, /* 0x94-0x97 */ - 0x8F, 0x53, 0x8F, 0x54, 0x8F, 0x55, 0x8F, 0x56, /* 0x98-0x9B */ - 0x8F, 0x57, 0x8F, 0x58, 0x8F, 0x59, 0x8F, 0x5A, /* 0x9C-0x9F */ - 0x8F, 0x61, 0x8F, 0x62, 0x8F, 0x63, 0x8F, 0x64, /* 0xA0-0xA3 */ - 0x8F, 0x65, 0x8F, 0x66, 0x8F, 0x67, 0x8F, 0x68, /* 0xA4-0xA7 */ - 0xB7, 0xD9, 0x8F, 0x69, 0x8F, 0x6A, 0x8F, 0x6B, /* 0xA8-0xAB */ - 0x8F, 0x6C, 0x8F, 0x6D, 0x8F, 0x6E, 0x8F, 0x6F, /* 0xAC-0xAF */ - 0xB7, 0xDA, 0x8F, 0x70, 0x8F, 0x71, 0x8F, 0x72, /* 0xB0-0xB3 */ - 0xB7, 0xDB, 0x8F, 0x73, 0x8F, 0x74, 0x8F, 0x75, /* 0xB4-0xB7 */ - 0xB7, 0xDC, 0x8F, 0x76, 0x8F, 0x77, 0x8F, 0x78, /* 0xB8-0xBB */ - 0x8F, 0x79, 0x8F, 0x7A, 0x8F, 0x81, 0x8F, 0x82, /* 0xBC-0xBF */ - 0xB7, 0xDD, 0xB7, 0xDE, 0x8F, 0x83, 0xB7, 0xDF, /* 0xC0-0xC3 */ - 0x8F, 0x84, 0xB7, 0xE0, 0x8F, 0x85, 0x8F, 0x86, /* 0xC4-0xC7 */ - 0x8F, 0x87, 0x8F, 0x88, 0x8F, 0x89, 0x8F, 0x8A, /* 0xC8-0xCB */ - 0xB7, 0xE1, 0x8F, 0x8B, 0x8F, 0x8C, 0x8F, 0x8D, /* 0xCC-0xCF */ - 0xB7, 0xE2, 0x8F, 0x8E, 0x8F, 0x8F, 0x8F, 0x90, /* 0xD0-0xD3 */ - 0xB7, 0xE3, 0x8F, 0x91, 0x8F, 0x92, 0x8F, 0x93, /* 0xD4-0xD7 */ - 0x8F, 0x94, 0x8F, 0x95, 0x8F, 0x96, 0x8F, 0x97, /* 0xD8-0xDB */ - 0x8F, 0x98, 0xB7, 0xE4, 0x8F, 0x99, 0xB7, 0xE5, /* 0xDC-0xDF */ - 0x8F, 0x9A, 0xB7, 0xE6, 0x8F, 0x9B, 0x8F, 0x9C, /* 0xE0-0xE3 */ - 0x8F, 0x9D, 0x8F, 0x9E, 0x8F, 0x9F, 0x8F, 0xA0, /* 0xE4-0xE7 */ - 0xB7, 0xE7, 0xB7, 0xE8, 0x8F, 0xA1, 0x8F, 0xA2, /* 0xE8-0xEB */ - 0xB7, 0xE9, 0x8F, 0xA3, 0x8F, 0xA4, 0x8F, 0xA5, /* 0xEC-0xEF */ - 0xB7, 0xEA, 0x8F, 0xA6, 0x8F, 0xA7, 0x8F, 0xA8, /* 0xF0-0xF3 */ - 0x8F, 0xA9, 0x8F, 0xAA, 0x8F, 0xAB, 0x8F, 0xAC, /* 0xF4-0xF7 */ - 0xB7, 0xEB, 0xB7, 0xEC, 0x8F, 0xAD, 0xB7, 0xED, /* 0xF8-0xFB */ - 0x8F, 0xAE, 0xB7, 0xEE, 0x8F, 0xAF, 0x8F, 0xB0, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_B9[512] = { - 0x8F, 0xB1, 0x8F, 0xB2, 0x8F, 0xB3, 0x8F, 0xB4, /* 0x00-0x03 */ - 0xB7, 0xEF, 0x8F, 0xB5, 0x8F, 0xB6, 0x8F, 0xB7, /* 0x04-0x07 */ - 0x8F, 0xB8, 0x8F, 0xB9, 0x8F, 0xBA, 0x8F, 0xBB, /* 0x08-0x0B */ - 0x8F, 0xBC, 0x8F, 0xBD, 0x8F, 0xBE, 0x8F, 0xBF, /* 0x0C-0x0F */ - 0x8F, 0xC0, 0x8F, 0xC1, 0x8F, 0xC2, 0x8F, 0xC3, /* 0x10-0x13 */ - 0x8F, 0xC4, 0x8F, 0xC5, 0x8F, 0xC6, 0x8F, 0xC7, /* 0x14-0x17 */ - 0xB7, 0xF0, 0x8F, 0xC8, 0x8F, 0xC9, 0x8F, 0xCA, /* 0x18-0x1B */ - 0x8F, 0xCB, 0x8F, 0xCC, 0x8F, 0xCD, 0x8F, 0xCE, /* 0x1C-0x1F */ - 0xB7, 0xF1, 0x8F, 0xCF, 0x8F, 0xD0, 0x8F, 0xD1, /* 0x20-0x23 */ - 0x8F, 0xD2, 0x8F, 0xD3, 0x8F, 0xD4, 0x8F, 0xD5, /* 0x24-0x27 */ - 0x8F, 0xD6, 0x8F, 0xD7, 0x8F, 0xD8, 0x8F, 0xD9, /* 0x28-0x2B */ - 0x8F, 0xDA, 0x8F, 0xDB, 0x8F, 0xDC, 0x8F, 0xDD, /* 0x2C-0x2F */ - 0x8F, 0xDE, 0x8F, 0xDF, 0x8F, 0xE0, 0x8F, 0xE1, /* 0x30-0x33 */ - 0x8F, 0xE2, 0x8F, 0xE3, 0x8F, 0xE4, 0x8F, 0xE5, /* 0x34-0x37 */ - 0x8F, 0xE6, 0x8F, 0xE7, 0x8F, 0xE8, 0x8F, 0xE9, /* 0x38-0x3B */ - 0xB7, 0xF2, 0xB7, 0xF3, 0x8F, 0xEA, 0x8F, 0xEB, /* 0x3C-0x3F */ - 0xB7, 0xF4, 0x8F, 0xEC, 0x8F, 0xED, 0x8F, 0xEE, /* 0x40-0x43 */ - 0xB7, 0xF5, 0x8F, 0xEF, 0x8F, 0xF0, 0x8F, 0xF1, /* 0x44-0x47 */ - 0x8F, 0xF2, 0x8F, 0xF3, 0x8F, 0xF4, 0x8F, 0xF5, /* 0x48-0x4B */ - 0xB7, 0xF6, 0x8F, 0xF6, 0x8F, 0xF7, 0xB7, 0xF7, /* 0x4C-0x4F */ - 0x8F, 0xF8, 0xB7, 0xF8, 0x8F, 0xF9, 0x8F, 0xFA, /* 0x50-0x53 */ - 0x8F, 0xFB, 0x8F, 0xFC, 0x8F, 0xFD, 0x8F, 0xFE, /* 0x54-0x57 */ - 0xB7, 0xF9, 0xB7, 0xFA, 0x90, 0x41, 0x90, 0x42, /* 0x58-0x5B */ - 0xB7, 0xFB, 0x90, 0x43, 0x90, 0x44, 0x90, 0x45, /* 0x5C-0x5F */ - 0xB7, 0xFC, 0x90, 0x46, 0x90, 0x47, 0x90, 0x48, /* 0x60-0x63 */ - 0x90, 0x49, 0x90, 0x4A, 0x90, 0x4B, 0x90, 0x4C, /* 0x64-0x67 */ - 0xB7, 0xFD, 0xB7, 0xFE, 0x90, 0x4D, 0xB8, 0xA1, /* 0x68-0x6B */ - 0x90, 0x4E, 0xB8, 0xA2, 0x90, 0x4F, 0x90, 0x50, /* 0x6C-0x6F */ - 0x90, 0x51, 0x90, 0x52, 0x90, 0x53, 0x90, 0x54, /* 0x70-0x73 */ - 0xB8, 0xA3, 0xB8, 0xA4, 0x90, 0x55, 0x90, 0x56, /* 0x74-0x77 */ - 0xB8, 0xA5, 0x90, 0x57, 0x90, 0x58, 0x90, 0x59, /* 0x78-0x7B */ - 0xB8, 0xA6, 0x90, 0x5A, 0x90, 0x61, 0x90, 0x62, /* 0x7C-0x7F */ - - 0x90, 0x63, 0x90, 0x64, 0x90, 0x65, 0x90, 0x66, /* 0x80-0x83 */ - 0xB8, 0xA7, 0xB8, 0xA8, 0x90, 0x67, 0xB8, 0xA9, /* 0x84-0x87 */ - 0x90, 0x68, 0xB8, 0xAA, 0xB8, 0xAB, 0x90, 0x69, /* 0x88-0x8B */ - 0x90, 0x6A, 0xB8, 0xAC, 0xB8, 0xAD, 0x90, 0x6B, /* 0x8C-0x8F */ - 0x90, 0x6C, 0x90, 0x6D, 0x90, 0x6E, 0x90, 0x6F, /* 0x90-0x93 */ - 0x90, 0x70, 0x90, 0x71, 0x90, 0x72, 0x90, 0x73, /* 0x94-0x97 */ - 0x90, 0x74, 0x90, 0x75, 0x90, 0x76, 0x90, 0x77, /* 0x98-0x9B */ - 0x90, 0x78, 0x90, 0x79, 0x90, 0x7A, 0x90, 0x81, /* 0x9C-0x9F */ - 0x90, 0x82, 0x90, 0x83, 0x90, 0x84, 0x90, 0x85, /* 0xA0-0xA3 */ - 0x90, 0x86, 0x90, 0x87, 0x90, 0x88, 0x90, 0x89, /* 0xA4-0xA7 */ - 0x90, 0x8A, 0x90, 0x8B, 0x90, 0x8C, 0x90, 0x8D, /* 0xA8-0xAB */ - 0xB8, 0xAE, 0xB8, 0xAF, 0x90, 0x8E, 0x90, 0x8F, /* 0xAC-0xAF */ - 0xB8, 0xB0, 0x90, 0x90, 0x90, 0x91, 0x90, 0x92, /* 0xB0-0xB3 */ - 0xB8, 0xB1, 0x90, 0x93, 0x90, 0x94, 0x90, 0x95, /* 0xB4-0xB7 */ - 0x90, 0x96, 0x90, 0x97, 0x90, 0x98, 0x90, 0x99, /* 0xB8-0xBB */ - 0xB8, 0xB2, 0xB8, 0xB3, 0x90, 0x9A, 0xB8, 0xB4, /* 0xBC-0xBF */ - 0x90, 0x9B, 0xB8, 0xB5, 0x90, 0x9C, 0x90, 0x9D, /* 0xC0-0xC3 */ - 0x90, 0x9E, 0x90, 0x9F, 0x90, 0xA0, 0x90, 0xA1, /* 0xC4-0xC7 */ - 0xB8, 0xB6, 0xB8, 0xB7, 0x90, 0xA2, 0x90, 0xA3, /* 0xC8-0xCB */ - 0xB8, 0xB8, 0x90, 0xA4, 0xB8, 0xB9, 0xB8, 0xBA, /* 0xCC-0xCF */ - 0xB8, 0xBB, 0xB8, 0xBC, 0xB8, 0xBD, 0x90, 0xA5, /* 0xD0-0xD3 */ - 0x90, 0xA6, 0x90, 0xA7, 0x90, 0xA8, 0x90, 0xA9, /* 0xD4-0xD7 */ - 0xB8, 0xBE, 0xB8, 0xBF, 0x90, 0xAA, 0xB8, 0xC0, /* 0xD8-0xDB */ - 0x90, 0xAB, 0xB8, 0xC1, 0xB8, 0xC2, 0x90, 0xAC, /* 0xDC-0xDF */ - 0x90, 0xAD, 0xB8, 0xC3, 0x90, 0xAE, 0xB8, 0xC4, /* 0xE0-0xE3 */ - 0xB8, 0xC5, 0xB8, 0xC6, 0x90, 0xAF, 0x90, 0xB0, /* 0xE4-0xE7 */ - 0xB8, 0xC7, 0x90, 0xB1, 0x90, 0xB2, 0x90, 0xB3, /* 0xE8-0xEB */ - 0xB8, 0xC8, 0x90, 0xB4, 0x90, 0xB5, 0x90, 0xB6, /* 0xEC-0xEF */ - 0x90, 0xB7, 0x90, 0xB8, 0x90, 0xB9, 0x90, 0xBA, /* 0xF0-0xF3 */ - 0xB8, 0xC9, 0xB8, 0xCA, 0x90, 0xBB, 0xB8, 0xCB, /* 0xF4-0xF7 */ - 0xB8, 0xCC, 0xB8, 0xCD, 0xB8, 0xCE, 0x90, 0xBC, /* 0xF8-0xFB */ - 0x90, 0xBD, 0x90, 0xBE, 0x90, 0xBF, 0x90, 0xC0, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_BA[512] = { - 0xB8, 0xCF, 0xB8, 0xD0, 0x90, 0xC1, 0x90, 0xC2, /* 0x00-0x03 */ - 0x90, 0xC3, 0x90, 0xC4, 0x90, 0xC5, 0x90, 0xC6, /* 0x04-0x07 */ - 0xB8, 0xD1, 0x90, 0xC7, 0x90, 0xC8, 0x90, 0xC9, /* 0x08-0x0B */ - 0x90, 0xCA, 0x90, 0xCB, 0x90, 0xCC, 0x90, 0xCD, /* 0x0C-0x0F */ - 0x90, 0xCE, 0x90, 0xCF, 0x90, 0xD0, 0x90, 0xD1, /* 0x10-0x13 */ - 0x90, 0xD2, 0xB8, 0xD2, 0x90, 0xD3, 0x90, 0xD4, /* 0x14-0x17 */ - 0x90, 0xD5, 0x90, 0xD6, 0x90, 0xD7, 0x90, 0xD8, /* 0x18-0x1B */ - 0x90, 0xD9, 0x90, 0xDA, 0x90, 0xDB, 0x90, 0xDC, /* 0x1C-0x1F */ - 0x90, 0xDD, 0x90, 0xDE, 0x90, 0xDF, 0x90, 0xE0, /* 0x20-0x23 */ - 0x90, 0xE1, 0x90, 0xE2, 0x90, 0xE3, 0x90, 0xE4, /* 0x24-0x27 */ - 0x90, 0xE5, 0x90, 0xE6, 0x90, 0xE7, 0x90, 0xE8, /* 0x28-0x2B */ - 0x90, 0xE9, 0x90, 0xEA, 0x90, 0xEB, 0x90, 0xEC, /* 0x2C-0x2F */ - 0x90, 0xED, 0x90, 0xEE, 0x90, 0xEF, 0x90, 0xF0, /* 0x30-0x33 */ - 0x90, 0xF1, 0x90, 0xF2, 0x90, 0xF3, 0x90, 0xF4, /* 0x34-0x37 */ - 0xB8, 0xD3, 0xB8, 0xD4, 0x90, 0xF5, 0x90, 0xF6, /* 0x38-0x3B */ - 0xB8, 0xD5, 0x90, 0xF7, 0x90, 0xF8, 0x90, 0xF9, /* 0x3C-0x3F */ - 0xB8, 0xD6, 0x90, 0xFA, 0xB8, 0xD7, 0x90, 0xFB, /* 0x40-0x43 */ - 0x90, 0xFC, 0x90, 0xFD, 0x90, 0xFE, 0x91, 0x41, /* 0x44-0x47 */ - 0xB8, 0xD8, 0xB8, 0xD9, 0x91, 0x42, 0xB8, 0xDA, /* 0x48-0x4B */ - 0x91, 0x43, 0xB8, 0xDB, 0xB8, 0xDC, 0x91, 0x44, /* 0x4C-0x4F */ - 0x91, 0x45, 0x91, 0x46, 0x91, 0x47, 0xB8, 0xDD, /* 0x50-0x53 */ - 0xB8, 0xDE, 0xB8, 0xDF, 0x91, 0x48, 0x91, 0x49, /* 0x54-0x57 */ - 0xB8, 0xE0, 0x91, 0x4A, 0x91, 0x4B, 0x91, 0x4C, /* 0x58-0x5B */ - 0xB8, 0xE1, 0x91, 0x4D, 0x91, 0x4E, 0x91, 0x4F, /* 0x5C-0x5F */ - 0x91, 0x50, 0x91, 0x51, 0x91, 0x52, 0x91, 0x53, /* 0x60-0x63 */ - 0xB8, 0xE2, 0xB8, 0xE3, 0x91, 0x54, 0xB8, 0xE4, /* 0x64-0x67 */ - 0xB8, 0xE5, 0xB8, 0xE6, 0x91, 0x55, 0x91, 0x56, /* 0x68-0x6B */ - 0x91, 0x57, 0x91, 0x58, 0x91, 0x59, 0x91, 0x5A, /* 0x6C-0x6F */ - 0xB8, 0xE7, 0xB8, 0xE8, 0x91, 0x61, 0x91, 0x62, /* 0x70-0x73 */ - 0xB8, 0xE9, 0x91, 0x63, 0x91, 0x64, 0x91, 0x65, /* 0x74-0x77 */ - 0xB8, 0xEA, 0x91, 0x66, 0x91, 0x67, 0x91, 0x68, /* 0x78-0x7B */ - 0x91, 0x69, 0x91, 0x6A, 0x91, 0x6B, 0x91, 0x6C, /* 0x7C-0x7F */ - - 0x91, 0x6D, 0x91, 0x6E, 0x91, 0x6F, 0xB8, 0xEB, /* 0x80-0x83 */ - 0xB8, 0xEC, 0xB8, 0xED, 0x91, 0x70, 0xB8, 0xEE, /* 0x84-0x87 */ - 0x91, 0x71, 0x91, 0x72, 0x91, 0x73, 0x91, 0x74, /* 0x88-0x8B */ - 0xB8, 0xEF, 0x91, 0x75, 0x91, 0x76, 0x91, 0x77, /* 0x8C-0x8F */ - 0x91, 0x78, 0x91, 0x79, 0x91, 0x7A, 0x91, 0x81, /* 0x90-0x93 */ - 0x91, 0x82, 0x91, 0x83, 0x91, 0x84, 0x91, 0x85, /* 0x94-0x97 */ - 0x91, 0x86, 0x91, 0x87, 0x91, 0x88, 0x91, 0x89, /* 0x98-0x9B */ - 0x91, 0x8A, 0x91, 0x8B, 0x91, 0x8C, 0x91, 0x8D, /* 0x9C-0x9F */ - 0x91, 0x8E, 0x91, 0x8F, 0x91, 0x90, 0x91, 0x91, /* 0xA0-0xA3 */ - 0x91, 0x92, 0x91, 0x93, 0x91, 0x94, 0x91, 0x95, /* 0xA4-0xA7 */ - 0xB8, 0xF0, 0xB8, 0xF1, 0x91, 0x96, 0xB8, 0xF2, /* 0xA8-0xAB */ - 0xB8, 0xF3, 0x91, 0x97, 0x91, 0x98, 0x91, 0x99, /* 0xAC-0xAF */ - 0xB8, 0xF4, 0x91, 0x9A, 0xB8, 0xF5, 0x91, 0x9B, /* 0xB0-0xB3 */ - 0x91, 0x9C, 0x91, 0x9D, 0x91, 0x9E, 0x91, 0x9F, /* 0xB4-0xB7 */ - 0xB8, 0xF6, 0xB8, 0xF7, 0x91, 0xA0, 0xB8, 0xF8, /* 0xB8-0xBB */ - 0x91, 0xA1, 0xB8, 0xF9, 0x91, 0xA2, 0x91, 0xA3, /* 0xBC-0xBF */ - 0x91, 0xA4, 0x91, 0xA5, 0x91, 0xA6, 0x91, 0xA7, /* 0xC0-0xC3 */ - 0xB8, 0xFA, 0x91, 0xA8, 0x91, 0xA9, 0x91, 0xAA, /* 0xC4-0xC7 */ - 0xB8, 0xFB, 0x91, 0xAB, 0x91, 0xAC, 0x91, 0xAD, /* 0xC8-0xCB */ - 0x91, 0xAE, 0x91, 0xAF, 0x91, 0xB0, 0x91, 0xB1, /* 0xCC-0xCF */ - 0x91, 0xB2, 0x91, 0xB3, 0x91, 0xB4, 0x91, 0xB5, /* 0xD0-0xD3 */ - 0x91, 0xB6, 0x91, 0xB7, 0x91, 0xB8, 0x91, 0xB9, /* 0xD4-0xD7 */ - 0xB8, 0xFC, 0xB8, 0xFD, 0x91, 0xBA, 0x91, 0xBB, /* 0xD8-0xDB */ - 0x91, 0xBC, 0x91, 0xBD, 0x91, 0xBE, 0x91, 0xBF, /* 0xDC-0xDF */ - 0x91, 0xC0, 0x91, 0xC1, 0x91, 0xC2, 0x91, 0xC3, /* 0xE0-0xE3 */ - 0x91, 0xC4, 0x91, 0xC5, 0x91, 0xC6, 0x91, 0xC7, /* 0xE4-0xE7 */ - 0x91, 0xC8, 0x91, 0xC9, 0x91, 0xCA, 0x91, 0xCB, /* 0xE8-0xEB */ - 0x91, 0xCC, 0x91, 0xCD, 0x91, 0xCE, 0x91, 0xCF, /* 0xEC-0xEF */ - 0x91, 0xD0, 0x91, 0xD1, 0x91, 0xD2, 0x91, 0xD3, /* 0xF0-0xF3 */ - 0x91, 0xD4, 0x91, 0xD5, 0x91, 0xD6, 0x91, 0xD7, /* 0xF4-0xF7 */ - 0x91, 0xD8, 0x91, 0xD9, 0x91, 0xDA, 0x91, 0xDB, /* 0xF8-0xFB */ - 0xB8, 0xFE, 0x91, 0xDC, 0x91, 0xDD, 0x91, 0xDE, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_BB[512] = { - 0xB9, 0xA1, 0x91, 0xDF, 0x91, 0xE0, 0x91, 0xE1, /* 0x00-0x03 */ - 0xB9, 0xA2, 0x91, 0xE2, 0x91, 0xE3, 0x91, 0xE4, /* 0x04-0x07 */ - 0x91, 0xE5, 0x91, 0xE6, 0x91, 0xE7, 0x91, 0xE8, /* 0x08-0x0B */ - 0x91, 0xE9, 0xB9, 0xA3, 0x91, 0xEA, 0xB9, 0xA4, /* 0x0C-0x0F */ - 0x91, 0xEB, 0xB9, 0xA5, 0x91, 0xEC, 0x91, 0xED, /* 0x10-0x13 */ - 0x91, 0xEE, 0x91, 0xEF, 0x91, 0xF0, 0x91, 0xF1, /* 0x14-0x17 */ - 0xB9, 0xA6, 0x91, 0xF2, 0x91, 0xF3, 0x91, 0xF4, /* 0x18-0x1B */ - 0xB9, 0xA7, 0x91, 0xF5, 0x91, 0xF6, 0x91, 0xF7, /* 0x1C-0x1F */ - 0xB9, 0xA8, 0x91, 0xF8, 0x91, 0xF9, 0x91, 0xFA, /* 0x20-0x23 */ - 0x91, 0xFB, 0x91, 0xFC, 0x91, 0xFD, 0x91, 0xFE, /* 0x24-0x27 */ - 0x92, 0x41, 0xB9, 0xA9, 0x92, 0x42, 0xB9, 0xAA, /* 0x28-0x2B */ - 0x92, 0x43, 0x92, 0x44, 0x92, 0x45, 0x92, 0x46, /* 0x2C-0x2F */ - 0x92, 0x47, 0x92, 0x48, 0x92, 0x49, 0x92, 0x4A, /* 0x30-0x33 */ - 0xB9, 0xAB, 0xB9, 0xAC, 0xB9, 0xAD, 0x92, 0x4B, /* 0x34-0x37 */ - 0xB9, 0xAE, 0x92, 0x4C, 0x92, 0x4D, 0xB9, 0xAF, /* 0x38-0x3B */ - 0xB9, 0xB0, 0xB9, 0xB1, 0xB9, 0xB2, 0x92, 0x4E, /* 0x3C-0x3F */ - 0x92, 0x4F, 0x92, 0x50, 0x92, 0x51, 0x92, 0x52, /* 0x40-0x43 */ - 0xB9, 0xB3, 0xB9, 0xB4, 0x92, 0x53, 0xB9, 0xB5, /* 0x44-0x47 */ - 0x92, 0x54, 0xB9, 0xB6, 0x92, 0x55, 0x92, 0x56, /* 0x48-0x4B */ - 0x92, 0x57, 0xB9, 0xB7, 0x92, 0x58, 0xB9, 0xB8, /* 0x4C-0x4F */ - 0xB9, 0xB9, 0x92, 0x59, 0x92, 0x5A, 0x92, 0x61, /* 0x50-0x53 */ - 0xB9, 0xBA, 0x92, 0x62, 0x92, 0x63, 0x92, 0x64, /* 0x54-0x57 */ - 0xB9, 0xBB, 0x92, 0x65, 0x92, 0x66, 0x92, 0x67, /* 0x58-0x5B */ - 0x92, 0x68, 0x92, 0x69, 0x92, 0x6A, 0x92, 0x6B, /* 0x5C-0x5F */ - 0x92, 0x6C, 0xB9, 0xBC, 0x92, 0x6D, 0xB9, 0xBD, /* 0x60-0x63 */ - 0x92, 0x6E, 0x92, 0x6F, 0x92, 0x70, 0x92, 0x71, /* 0x64-0x67 */ - 0x92, 0x72, 0x92, 0x73, 0x92, 0x74, 0x92, 0x75, /* 0x68-0x6B */ - 0xB9, 0xBE, 0x92, 0x76, 0x92, 0x77, 0x92, 0x78, /* 0x6C-0x6F */ - 0x92, 0x79, 0x92, 0x7A, 0x92, 0x81, 0x92, 0x82, /* 0x70-0x73 */ - 0x92, 0x83, 0x92, 0x84, 0x92, 0x85, 0x92, 0x86, /* 0x74-0x77 */ - 0x92, 0x87, 0x92, 0x88, 0x92, 0x89, 0x92, 0x8A, /* 0x78-0x7B */ - 0x92, 0x8B, 0x92, 0x8C, 0x92, 0x8D, 0x92, 0x8E, /* 0x7C-0x7F */ - - 0x92, 0x8F, 0x92, 0x90, 0x92, 0x91, 0x92, 0x92, /* 0x80-0x83 */ - 0x92, 0x93, 0x92, 0x94, 0x92, 0x95, 0x92, 0x96, /* 0x84-0x87 */ - 0xB9, 0xBF, 0x92, 0x97, 0x92, 0x98, 0x92, 0x99, /* 0x88-0x8B */ - 0xB9, 0xC0, 0x92, 0x9A, 0x92, 0x9B, 0x92, 0x9C, /* 0x8C-0x8F */ - 0xB9, 0xC1, 0x92, 0x9D, 0x92, 0x9E, 0x92, 0x9F, /* 0x90-0x93 */ - 0x92, 0xA0, 0x92, 0xA1, 0x92, 0xA2, 0x92, 0xA3, /* 0x94-0x97 */ - 0x92, 0xA4, 0x92, 0xA5, 0x92, 0xA6, 0x92, 0xA7, /* 0x98-0x9B */ - 0x92, 0xA8, 0x92, 0xA9, 0x92, 0xAA, 0x92, 0xAB, /* 0x9C-0x9F */ - 0x92, 0xAC, 0x92, 0xAD, 0x92, 0xAE, 0x92, 0xAF, /* 0xA0-0xA3 */ - 0xB9, 0xC2, 0x92, 0xB0, 0x92, 0xB1, 0x92, 0xB2, /* 0xA4-0xA7 */ - 0xB9, 0xC3, 0x92, 0xB3, 0x92, 0xB4, 0x92, 0xB5, /* 0xA8-0xAB */ - 0xB9, 0xC4, 0x92, 0xB6, 0x92, 0xB7, 0x92, 0xB8, /* 0xAC-0xAF */ - 0x92, 0xB9, 0x92, 0xBA, 0x92, 0xBB, 0x92, 0xBC, /* 0xB0-0xB3 */ - 0xB9, 0xC5, 0x92, 0xBD, 0x92, 0xBE, 0xB9, 0xC6, /* 0xB4-0xB7 */ - 0x92, 0xBF, 0x92, 0xC0, 0x92, 0xC1, 0x92, 0xC2, /* 0xB8-0xBB */ - 0x92, 0xC3, 0x92, 0xC4, 0x92, 0xC5, 0x92, 0xC6, /* 0xBC-0xBF */ - 0xB9, 0xC7, 0x92, 0xC7, 0x92, 0xC8, 0x92, 0xC9, /* 0xC0-0xC3 */ - 0xB9, 0xC8, 0x92, 0xCA, 0x92, 0xCB, 0x92, 0xCC, /* 0xC4-0xC7 */ - 0xB9, 0xC9, 0x92, 0xCD, 0x92, 0xCE, 0x92, 0xCF, /* 0xC8-0xCB */ - 0x92, 0xD0, 0x92, 0xD1, 0x92, 0xD2, 0x92, 0xD3, /* 0xCC-0xCF */ - 0xB9, 0xCA, 0x92, 0xD4, 0x92, 0xD5, 0xB9, 0xCB, /* 0xD0-0xD3 */ - 0x92, 0xD6, 0x92, 0xD7, 0x92, 0xD8, 0x92, 0xD9, /* 0xD4-0xD7 */ - 0x92, 0xDA, 0x92, 0xDB, 0x92, 0xDC, 0x92, 0xDD, /* 0xD8-0xDB */ - 0x92, 0xDE, 0x92, 0xDF, 0x92, 0xE0, 0x92, 0xE1, /* 0xDC-0xDF */ - 0x92, 0xE2, 0x92, 0xE3, 0x92, 0xE4, 0x92, 0xE5, /* 0xE0-0xE3 */ - 0x92, 0xE6, 0x92, 0xE7, 0x92, 0xE8, 0x92, 0xE9, /* 0xE4-0xE7 */ - 0x92, 0xEA, 0x92, 0xEB, 0x92, 0xEC, 0x92, 0xED, /* 0xE8-0xEB */ - 0x92, 0xEE, 0x92, 0xEF, 0x92, 0xF0, 0x92, 0xF1, /* 0xEC-0xEF */ - 0x92, 0xF2, 0x92, 0xF3, 0x92, 0xF4, 0x92, 0xF5, /* 0xF0-0xF3 */ - 0x92, 0xF6, 0x92, 0xF7, 0x92, 0xF8, 0x92, 0xF9, /* 0xF4-0xF7 */ - 0xB9, 0xCC, 0xB9, 0xCD, 0x92, 0xFA, 0x92, 0xFB, /* 0xF8-0xFB */ - 0xB9, 0xCE, 0x92, 0xFC, 0x92, 0xFD, 0xB9, 0xCF, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_BC[512] = { - 0xB9, 0xD0, 0x92, 0xFE, 0xB9, 0xD1, 0x93, 0x41, /* 0x00-0x03 */ - 0x93, 0x42, 0x93, 0x43, 0x93, 0x44, 0x93, 0x45, /* 0x04-0x07 */ - 0xB9, 0xD2, 0xB9, 0xD3, 0x93, 0x46, 0xB9, 0xD4, /* 0x08-0x0B */ - 0xB9, 0xD5, 0xB9, 0xD6, 0x93, 0x47, 0xB9, 0xD7, /* 0x0C-0x0F */ - 0x93, 0x48, 0xB9, 0xD8, 0x93, 0x49, 0x93, 0x4A, /* 0x10-0x13 */ - 0xB9, 0xD9, 0xB9, 0xDA, 0xB9, 0xDB, 0xB9, 0xDC, /* 0x14-0x17 */ - 0xB9, 0xDD, 0x93, 0x4B, 0x93, 0x4C, 0xB9, 0xDE, /* 0x18-0x1B */ - 0xB9, 0xDF, 0xB9, 0xE0, 0xB9, 0xE1, 0xB9, 0xE2, /* 0x1C-0x1F */ - 0x93, 0x4D, 0x93, 0x4E, 0x93, 0x4F, 0x93, 0x50, /* 0x20-0x23 */ - 0xB9, 0xE3, 0xB9, 0xE4, 0x93, 0x51, 0xB9, 0xE5, /* 0x24-0x27 */ - 0x93, 0x52, 0xB9, 0xE6, 0x93, 0x53, 0x93, 0x54, /* 0x28-0x2B */ - 0x93, 0x55, 0xB9, 0xE7, 0x93, 0x56, 0x93, 0x57, /* 0x2C-0x2F */ - 0xB9, 0xE8, 0xB9, 0xE9, 0x93, 0x58, 0x93, 0x59, /* 0x30-0x33 */ - 0xB9, 0xEA, 0x93, 0x5A, 0x93, 0x61, 0x93, 0x62, /* 0x34-0x37 */ - 0xB9, 0xEB, 0x93, 0x63, 0x93, 0x64, 0x93, 0x65, /* 0x38-0x3B */ - 0x93, 0x66, 0x93, 0x67, 0x93, 0x68, 0x93, 0x69, /* 0x3C-0x3F */ - 0xB9, 0xEC, 0xB9, 0xED, 0x93, 0x6A, 0xB9, 0xEE, /* 0x40-0x43 */ - 0xB9, 0xEF, 0xB9, 0xF0, 0x93, 0x6B, 0x93, 0x6C, /* 0x44-0x47 */ - 0x93, 0x6D, 0xB9, 0xF1, 0x93, 0x6E, 0x93, 0x6F, /* 0x48-0x4B */ - 0xB9, 0xF2, 0xB9, 0xF3, 0x93, 0x70, 0x93, 0x71, /* 0x4C-0x4F */ - 0xB9, 0xF4, 0x93, 0x72, 0x93, 0x73, 0x93, 0x74, /* 0x50-0x53 */ - 0x93, 0x75, 0x93, 0x76, 0x93, 0x77, 0x93, 0x78, /* 0x54-0x57 */ - 0x93, 0x79, 0x93, 0x7A, 0x93, 0x81, 0x93, 0x82, /* 0x58-0x5B */ - 0x93, 0x83, 0xB9, 0xF5, 0x93, 0x84, 0x93, 0x85, /* 0x5C-0x5F */ - 0x93, 0x86, 0x93, 0x87, 0x93, 0x88, 0x93, 0x89, /* 0x60-0x63 */ - 0x93, 0x8A, 0x93, 0x8B, 0x93, 0x8C, 0x93, 0x8D, /* 0x64-0x67 */ - 0x93, 0x8E, 0x93, 0x8F, 0x93, 0x90, 0x93, 0x91, /* 0x68-0x6B */ - 0x93, 0x92, 0x93, 0x93, 0x93, 0x94, 0x93, 0x95, /* 0x6C-0x6F */ - 0x93, 0x96, 0x93, 0x97, 0x93, 0x98, 0x93, 0x99, /* 0x70-0x73 */ - 0x93, 0x9A, 0x93, 0x9B, 0x93, 0x9C, 0x93, 0x9D, /* 0x74-0x77 */ - 0x93, 0x9E, 0x93, 0x9F, 0x93, 0xA0, 0x93, 0xA1, /* 0x78-0x7B */ - 0x93, 0xA2, 0x93, 0xA3, 0x93, 0xA4, 0x93, 0xA5, /* 0x7C-0x7F */ - - 0x93, 0xA6, 0x93, 0xA7, 0x93, 0xA8, 0x93, 0xA9, /* 0x80-0x83 */ - 0xB9, 0xF6, 0xB9, 0xF7, 0x93, 0xAA, 0x93, 0xAB, /* 0x84-0x87 */ - 0xB9, 0xF8, 0x93, 0xAC, 0x93, 0xAD, 0xB9, 0xF9, /* 0x88-0x8B */ - 0xB9, 0xFA, 0x93, 0xAE, 0xB9, 0xFB, 0x93, 0xAF, /* 0x8C-0x8F */ - 0x93, 0xB0, 0x93, 0xB1, 0x93, 0xB2, 0x93, 0xB3, /* 0x90-0x93 */ - 0xB9, 0xFC, 0xB9, 0xFD, 0x93, 0xB4, 0xB9, 0xFE, /* 0x94-0x97 */ - 0x93, 0xB5, 0xBA, 0xA1, 0xBA, 0xA2, 0x93, 0xB6, /* 0x98-0x9B */ - 0x93, 0xB7, 0x93, 0xB8, 0x93, 0xB9, 0x93, 0xBA, /* 0x9C-0x9F */ - 0xBA, 0xA3, 0xBA, 0xA4, 0x93, 0xBB, 0x93, 0xBC, /* 0xA0-0xA3 */ - 0xBA, 0xA5, 0x93, 0xBD, 0x93, 0xBE, 0xBA, 0xA6, /* 0xA4-0xA7 */ - 0xBA, 0xA7, 0x93, 0xBF, 0x93, 0xC0, 0x93, 0xC1, /* 0xA8-0xAB */ - 0x93, 0xC2, 0x93, 0xC3, 0x93, 0xC4, 0x93, 0xC5, /* 0xAC-0xAF */ - 0xBA, 0xA8, 0xBA, 0xA9, 0x93, 0xC6, 0xBA, 0xAA, /* 0xB0-0xB3 */ - 0xBA, 0xAB, 0xBA, 0xAC, 0x93, 0xC7, 0x93, 0xC8, /* 0xB4-0xB7 */ - 0x93, 0xC9, 0x93, 0xCA, 0x93, 0xCB, 0x93, 0xCC, /* 0xB8-0xBB */ - 0xBA, 0xAD, 0xBA, 0xAE, 0x93, 0xCD, 0x93, 0xCE, /* 0xBC-0xBF */ - 0xBA, 0xAF, 0x93, 0xCF, 0x93, 0xD0, 0x93, 0xD1, /* 0xC0-0xC3 */ - 0xBA, 0xB0, 0x93, 0xD2, 0x93, 0xD3, 0x93, 0xD4, /* 0xC4-0xC7 */ - 0x93, 0xD5, 0x93, 0xD6, 0x93, 0xD7, 0x93, 0xD8, /* 0xC8-0xCB */ - 0x93, 0xD9, 0xBA, 0xB1, 0x93, 0xDA, 0xBA, 0xB2, /* 0xCC-0xCF */ - 0xBA, 0xB3, 0xBA, 0xB4, 0x93, 0xDB, 0x93, 0xDC, /* 0xD0-0xD3 */ - 0x93, 0xDD, 0xBA, 0xB5, 0x93, 0xDE, 0x93, 0xDF, /* 0xD4-0xD7 */ - 0xBA, 0xB6, 0x93, 0xE0, 0x93, 0xE1, 0x93, 0xE2, /* 0xD8-0xDB */ - 0xBA, 0xB7, 0x93, 0xE3, 0x93, 0xE4, 0x93, 0xE5, /* 0xDC-0xDF */ - 0x93, 0xE6, 0x93, 0xE7, 0x93, 0xE8, 0x93, 0xE9, /* 0xE0-0xE3 */ - 0x93, 0xEA, 0x93, 0xEB, 0x93, 0xEC, 0x93, 0xED, /* 0xE4-0xE7 */ - 0x93, 0xEE, 0x93, 0xEF, 0x93, 0xF0, 0x93, 0xF1, /* 0xE8-0xEB */ - 0x93, 0xF2, 0x93, 0xF3, 0x93, 0xF4, 0x93, 0xF5, /* 0xEC-0xEF */ - 0x93, 0xF6, 0x93, 0xF7, 0x93, 0xF8, 0x93, 0xF9, /* 0xF0-0xF3 */ - 0xBA, 0xB8, 0xBA, 0xB9, 0xBA, 0xBA, 0x93, 0xFA, /* 0xF4-0xF7 */ - 0xBA, 0xBB, 0x93, 0xFB, 0x93, 0xFC, 0x93, 0xFD, /* 0xF8-0xFB */ - 0xBA, 0xBC, 0x93, 0xFE, 0x94, 0x41, 0x94, 0x42, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_BD[512] = { - 0x94, 0x43, 0x94, 0x44, 0x94, 0x45, 0x94, 0x46, /* 0x00-0x03 */ - 0xBA, 0xBD, 0xBA, 0xBE, 0x94, 0x47, 0xBA, 0xBF, /* 0x04-0x07 */ - 0x94, 0x48, 0xBA, 0xC0, 0x94, 0x49, 0x94, 0x4A, /* 0x08-0x0B */ - 0x94, 0x4B, 0x94, 0x4C, 0x94, 0x4D, 0x94, 0x4E, /* 0x0C-0x0F */ - 0xBA, 0xC1, 0x94, 0x4F, 0x94, 0x50, 0x94, 0x51, /* 0x10-0x13 */ - 0xBA, 0xC2, 0x94, 0x52, 0x94, 0x53, 0x94, 0x54, /* 0x14-0x17 */ - 0x94, 0x55, 0x94, 0x56, 0x94, 0x57, 0x94, 0x58, /* 0x18-0x1B */ - 0x94, 0x59, 0x94, 0x5A, 0x94, 0x61, 0x94, 0x62, /* 0x1C-0x1F */ - 0x94, 0x63, 0x94, 0x64, 0x94, 0x65, 0x94, 0x66, /* 0x20-0x23 */ - 0xBA, 0xC3, 0x94, 0x67, 0x94, 0x68, 0x94, 0x69, /* 0x24-0x27 */ - 0x94, 0x6A, 0x94, 0x6B, 0x94, 0x6C, 0x94, 0x6D, /* 0x28-0x2B */ - 0xBA, 0xC4, 0x94, 0x6E, 0x94, 0x6F, 0x94, 0x70, /* 0x2C-0x2F */ - 0x94, 0x71, 0x94, 0x72, 0x94, 0x73, 0x94, 0x74, /* 0x30-0x33 */ - 0x94, 0x75, 0x94, 0x76, 0x94, 0x77, 0x94, 0x78, /* 0x34-0x37 */ - 0x94, 0x79, 0x94, 0x7A, 0x94, 0x81, 0x94, 0x82, /* 0x38-0x3B */ - 0x94, 0x83, 0x94, 0x84, 0x94, 0x85, 0x94, 0x86, /* 0x3C-0x3F */ - 0xBA, 0xC5, 0x94, 0x87, 0x94, 0x88, 0x94, 0x89, /* 0x40-0x43 */ - 0x94, 0x8A, 0x94, 0x8B, 0x94, 0x8C, 0x94, 0x8D, /* 0x44-0x47 */ - 0xBA, 0xC6, 0xBA, 0xC7, 0x94, 0x8E, 0x94, 0x8F, /* 0x48-0x4B */ - 0xBA, 0xC8, 0x94, 0x90, 0x94, 0x91, 0x94, 0x92, /* 0x4C-0x4F */ - 0xBA, 0xC9, 0x94, 0x93, 0x94, 0x94, 0x94, 0x95, /* 0x50-0x53 */ - 0x94, 0x96, 0x94, 0x97, 0x94, 0x98, 0x94, 0x99, /* 0x54-0x57 */ - 0xBA, 0xCA, 0xBA, 0xCB, 0x94, 0x9A, 0x94, 0x9B, /* 0x58-0x5B */ - 0x94, 0x9C, 0x94, 0x9D, 0x94, 0x9E, 0x94, 0x9F, /* 0x5C-0x5F */ - 0x94, 0xA0, 0x94, 0xA1, 0x94, 0xA2, 0x94, 0xA3, /* 0x60-0x63 */ - 0xBA, 0xCC, 0x94, 0xA4, 0x94, 0xA5, 0x94, 0xA6, /* 0x64-0x67 */ - 0xBA, 0xCD, 0x94, 0xA7, 0x94, 0xA8, 0x94, 0xA9, /* 0x68-0x6B */ - 0x94, 0xAA, 0x94, 0xAB, 0x94, 0xAC, 0x94, 0xAD, /* 0x6C-0x6F */ - 0x94, 0xAE, 0x94, 0xAF, 0x94, 0xB0, 0x94, 0xB1, /* 0x70-0x73 */ - 0x94, 0xB2, 0x94, 0xB3, 0x94, 0xB4, 0x94, 0xB5, /* 0x74-0x77 */ - 0x94, 0xB6, 0x94, 0xB7, 0x94, 0xB8, 0x94, 0xB9, /* 0x78-0x7B */ - 0x94, 0xBA, 0x94, 0xBB, 0x94, 0xBC, 0x94, 0xBD, /* 0x7C-0x7F */ - - 0xBA, 0xCE, 0xBA, 0xCF, 0x94, 0xBE, 0x94, 0xBF, /* 0x80-0x83 */ - 0xBA, 0xD0, 0x94, 0xC0, 0x94, 0xC1, 0xBA, 0xD1, /* 0x84-0x87 */ - 0xBA, 0xD2, 0xBA, 0xD3, 0xBA, 0xD4, 0x94, 0xC2, /* 0x88-0x8B */ - 0x94, 0xC3, 0x94, 0xC4, 0x94, 0xC5, 0x94, 0xC6, /* 0x8C-0x8F */ - 0xBA, 0xD5, 0xBA, 0xD6, 0x94, 0xC7, 0xBA, 0xD7, /* 0x90-0x93 */ - 0x94, 0xC8, 0xBA, 0xD8, 0x94, 0xC9, 0x94, 0xCA, /* 0x94-0x97 */ - 0x94, 0xCB, 0xBA, 0xD9, 0xBA, 0xDA, 0x94, 0xCC, /* 0x98-0x9B */ - 0xBA, 0xDB, 0x94, 0xCD, 0x94, 0xCE, 0x94, 0xCF, /* 0x9C-0x9F */ - 0x94, 0xD0, 0x94, 0xD1, 0x94, 0xD2, 0x94, 0xD3, /* 0xA0-0xA3 */ - 0xBA, 0xDC, 0x94, 0xD4, 0x94, 0xD5, 0x94, 0xD6, /* 0xA4-0xA7 */ - 0x94, 0xD7, 0x94, 0xD8, 0x94, 0xD9, 0x94, 0xDA, /* 0xA8-0xAB */ - 0x94, 0xDB, 0x94, 0xDC, 0x94, 0xDD, 0x94, 0xDE, /* 0xAC-0xAF */ - 0xBA, 0xDD, 0x94, 0xDF, 0x94, 0xE0, 0x94, 0xE1, /* 0xB0-0xB3 */ - 0x94, 0xE2, 0x94, 0xE3, 0x94, 0xE4, 0x94, 0xE5, /* 0xB4-0xB7 */ - 0xBA, 0xDE, 0x94, 0xE6, 0x94, 0xE7, 0x94, 0xE8, /* 0xB8-0xBB */ - 0x94, 0xE9, 0x94, 0xEA, 0x94, 0xEB, 0x94, 0xEC, /* 0xBC-0xBF */ - 0x94, 0xED, 0x94, 0xEE, 0x94, 0xEF, 0x94, 0xF0, /* 0xC0-0xC3 */ - 0x94, 0xF1, 0x94, 0xF2, 0x94, 0xF3, 0x94, 0xF4, /* 0xC4-0xC7 */ - 0x94, 0xF5, 0x94, 0xF6, 0x94, 0xF7, 0x94, 0xF8, /* 0xC8-0xCB */ - 0x94, 0xF9, 0x94, 0xFA, 0x94, 0xFB, 0x94, 0xFC, /* 0xCC-0xCF */ - 0x94, 0xFD, 0x94, 0xFE, 0x95, 0x41, 0x95, 0x42, /* 0xD0-0xD3 */ - 0xBA, 0xDF, 0xBA, 0xE0, 0x95, 0x43, 0x95, 0x44, /* 0xD4-0xD7 */ - 0xBA, 0xE1, 0x95, 0x45, 0x95, 0x46, 0x95, 0x47, /* 0xD8-0xDB */ - 0xBA, 0xE2, 0x95, 0x48, 0x95, 0x49, 0x95, 0x4A, /* 0xDC-0xDF */ - 0x95, 0x4B, 0x95, 0x4C, 0x95, 0x4D, 0x95, 0x4E, /* 0xE0-0xE3 */ - 0x95, 0x4F, 0x95, 0x50, 0x95, 0x51, 0x95, 0x52, /* 0xE4-0xE7 */ - 0x95, 0x53, 0xBA, 0xE3, 0x95, 0x54, 0x95, 0x55, /* 0xE8-0xEB */ - 0x95, 0x56, 0x95, 0x57, 0x95, 0x58, 0x95, 0x59, /* 0xEC-0xEF */ - 0xBA, 0xE4, 0x95, 0x5A, 0x95, 0x61, 0x95, 0x62, /* 0xF0-0xF3 */ - 0xBA, 0xE5, 0x95, 0x63, 0x95, 0x64, 0x95, 0x65, /* 0xF4-0xF7 */ - 0xBA, 0xE6, 0x95, 0x66, 0x95, 0x67, 0x95, 0x68, /* 0xF8-0xFB */ - 0x95, 0x69, 0x95, 0x6A, 0x95, 0x6B, 0x95, 0x6C, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_BE[512] = { - 0xBA, 0xE7, 0x95, 0x6D, 0x95, 0x6E, 0xBA, 0xE8, /* 0x00-0x03 */ - 0x95, 0x6F, 0xBA, 0xE9, 0x95, 0x70, 0x95, 0x71, /* 0x04-0x07 */ - 0x95, 0x72, 0x95, 0x73, 0x95, 0x74, 0x95, 0x75, /* 0x08-0x0B */ - 0xBA, 0xEA, 0xBA, 0xEB, 0x95, 0x76, 0x95, 0x77, /* 0x0C-0x0F */ - 0xBA, 0xEC, 0x95, 0x78, 0x95, 0x79, 0x95, 0x7A, /* 0x10-0x13 */ - 0xBA, 0xED, 0x95, 0x81, 0x95, 0x82, 0x95, 0x83, /* 0x14-0x17 */ - 0x95, 0x84, 0x95, 0x85, 0x95, 0x86, 0x95, 0x87, /* 0x18-0x1B */ - 0xBA, 0xEE, 0xBA, 0xEF, 0x95, 0x88, 0xBA, 0xF0, /* 0x1C-0x1F */ - 0x95, 0x89, 0x95, 0x8A, 0x95, 0x8B, 0x95, 0x8C, /* 0x20-0x23 */ - 0x95, 0x8D, 0x95, 0x8E, 0x95, 0x8F, 0x95, 0x90, /* 0x24-0x27 */ - 0x95, 0x91, 0x95, 0x92, 0x95, 0x93, 0x95, 0x94, /* 0x28-0x2B */ - 0x95, 0x95, 0x95, 0x96, 0x95, 0x97, 0x95, 0x98, /* 0x2C-0x2F */ - 0x95, 0x99, 0x95, 0x9A, 0x95, 0x9B, 0x95, 0x9C, /* 0x30-0x33 */ - 0x95, 0x9D, 0x95, 0x9E, 0x95, 0x9F, 0x95, 0xA0, /* 0x34-0x37 */ - 0x95, 0xA1, 0x95, 0xA2, 0x95, 0xA3, 0x95, 0xA4, /* 0x38-0x3B */ - 0x95, 0xA5, 0x95, 0xA6, 0x95, 0xA7, 0x95, 0xA8, /* 0x3C-0x3F */ - 0x95, 0xA9, 0x95, 0xAA, 0x95, 0xAB, 0x95, 0xAC, /* 0x40-0x43 */ - 0xBA, 0xF1, 0xBA, 0xF2, 0x95, 0xAD, 0x95, 0xAE, /* 0x44-0x47 */ - 0xBA, 0xF3, 0x95, 0xAF, 0x95, 0xB0, 0x95, 0xB1, /* 0x48-0x4B */ - 0xBA, 0xF4, 0x95, 0xB2, 0xBA, 0xF5, 0x95, 0xB3, /* 0x4C-0x4F */ - 0x95, 0xB4, 0x95, 0xB5, 0x95, 0xB6, 0x95, 0xB7, /* 0x50-0x53 */ - 0xBA, 0xF6, 0xBA, 0xF7, 0x95, 0xB8, 0xBA, 0xF8, /* 0x54-0x57 */ - 0x95, 0xB9, 0xBA, 0xF9, 0xBA, 0xFA, 0xBA, 0xFB, /* 0x58-0x5B */ - 0x95, 0xBA, 0x95, 0xBB, 0x95, 0xBC, 0x95, 0xBD, /* 0x5C-0x5F */ - 0xBA, 0xFC, 0xBA, 0xFD, 0x95, 0xBE, 0x95, 0xBF, /* 0x60-0x63 */ - 0xBA, 0xFE, 0x95, 0xC0, 0x95, 0xC1, 0x95, 0xC2, /* 0x64-0x67 */ - 0xBB, 0xA1, 0x95, 0xC3, 0xBB, 0xA2, 0x95, 0xC4, /* 0x68-0x6B */ - 0x95, 0xC5, 0x95, 0xC6, 0x95, 0xC7, 0x95, 0xC8, /* 0x6C-0x6F */ - 0xBB, 0xA3, 0xBB, 0xA4, 0x95, 0xC9, 0xBB, 0xA5, /* 0x70-0x73 */ - 0xBB, 0xA6, 0xBB, 0xA7, 0x95, 0xCA, 0x95, 0xCB, /* 0x74-0x77 */ - 0x95, 0xCC, 0x95, 0xCD, 0x95, 0xCE, 0xBB, 0xA8, /* 0x78-0x7B */ - 0xBB, 0xA9, 0xBB, 0xAA, 0x95, 0xCF, 0x95, 0xD0, /* 0x7C-0x7F */ - - 0xBB, 0xAB, 0x95, 0xD1, 0x95, 0xD2, 0x95, 0xD3, /* 0x80-0x83 */ - 0xBB, 0xAC, 0x95, 0xD4, 0x95, 0xD5, 0x95, 0xD6, /* 0x84-0x87 */ - 0x95, 0xD7, 0x95, 0xD8, 0x95, 0xD9, 0x95, 0xDA, /* 0x88-0x8B */ - 0xBB, 0xAD, 0xBB, 0xAE, 0x95, 0xDB, 0xBB, 0xAF, /* 0x8C-0x8F */ - 0xBB, 0xB0, 0xBB, 0xB1, 0x95, 0xDC, 0x95, 0xDD, /* 0x90-0x93 */ - 0x95, 0xDE, 0x95, 0xDF, 0x95, 0xE0, 0x95, 0xE1, /* 0x94-0x97 */ - 0xBB, 0xB2, 0xBB, 0xB3, 0x95, 0xE2, 0x95, 0xE3, /* 0x98-0x9B */ - 0x95, 0xE4, 0x95, 0xE5, 0x95, 0xE6, 0x95, 0xE7, /* 0x9C-0x9F */ - 0x95, 0xE8, 0x95, 0xE9, 0x95, 0xEA, 0x95, 0xEB, /* 0xA0-0xA3 */ - 0x95, 0xEC, 0x95, 0xED, 0x95, 0xEE, 0x95, 0xEF, /* 0xA4-0xA7 */ - 0xBB, 0xB4, 0x95, 0xF0, 0x95, 0xF1, 0x95, 0xF2, /* 0xA8-0xAB */ - 0x95, 0xF3, 0x95, 0xF4, 0x95, 0xF5, 0x95, 0xF6, /* 0xAC-0xAF */ - 0x95, 0xF7, 0x95, 0xF8, 0x95, 0xF9, 0x95, 0xFA, /* 0xB0-0xB3 */ - 0x95, 0xFB, 0x95, 0xFC, 0x95, 0xFD, 0x95, 0xFE, /* 0xB4-0xB7 */ - 0x96, 0x41, 0x96, 0x42, 0x96, 0x43, 0x96, 0x44, /* 0xB8-0xBB */ - 0x96, 0x45, 0x96, 0x46, 0x96, 0x47, 0x96, 0x48, /* 0xBC-0xBF */ - 0x96, 0x49, 0x96, 0x4A, 0x96, 0x4B, 0x96, 0x4C, /* 0xC0-0xC3 */ - 0x96, 0x4D, 0x96, 0x4E, 0x96, 0x4F, 0x96, 0x50, /* 0xC4-0xC7 */ - 0x96, 0x51, 0x96, 0x52, 0x96, 0x53, 0x96, 0x54, /* 0xC8-0xCB */ - 0x96, 0x55, 0x96, 0x56, 0x96, 0x57, 0x96, 0x58, /* 0xCC-0xCF */ - 0xBB, 0xB5, 0xBB, 0xB6, 0x96, 0x59, 0x96, 0x5A, /* 0xD0-0xD3 */ - 0xBB, 0xB7, 0x96, 0x61, 0x96, 0x62, 0xBB, 0xB8, /* 0xD4-0xD7 */ - 0xBB, 0xB9, 0x96, 0x63, 0x96, 0x64, 0x96, 0x65, /* 0xD8-0xDB */ - 0x96, 0x66, 0x96, 0x67, 0x96, 0x68, 0x96, 0x69, /* 0xDC-0xDF */ - 0xBB, 0xBA, 0x96, 0x6A, 0x96, 0x6B, 0xBB, 0xBB, /* 0xE0-0xE3 */ - 0xBB, 0xBC, 0xBB, 0xBD, 0x96, 0x6C, 0x96, 0x6D, /* 0xE4-0xE7 */ - 0x96, 0x6E, 0x96, 0x6F, 0x96, 0x70, 0x96, 0x71, /* 0xE8-0xEB */ - 0xBB, 0xBE, 0x96, 0x72, 0x96, 0x73, 0x96, 0x74, /* 0xEC-0xEF */ - 0x96, 0x75, 0x96, 0x76, 0x96, 0x77, 0x96, 0x78, /* 0xF0-0xF3 */ - 0x96, 0x79, 0x96, 0x7A, 0x96, 0x81, 0x96, 0x82, /* 0xF4-0xF7 */ - 0x96, 0x83, 0x96, 0x84, 0x96, 0x85, 0x96, 0x86, /* 0xF8-0xFB */ - 0x96, 0x87, 0x96, 0x88, 0x96, 0x89, 0x96, 0x8A, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_BF[512] = { - 0x96, 0x8B, 0xBB, 0xBF, 0x96, 0x8C, 0x96, 0x8D, /* 0x00-0x03 */ - 0x96, 0x8E, 0x96, 0x8F, 0x96, 0x90, 0x96, 0x91, /* 0x04-0x07 */ - 0xBB, 0xC0, 0xBB, 0xC1, 0x96, 0x92, 0x96, 0x93, /* 0x08-0x0B */ - 0x96, 0x94, 0x96, 0x95, 0x96, 0x96, 0x96, 0x97, /* 0x0C-0x0F */ - 0x96, 0x98, 0x96, 0x99, 0x96, 0x9A, 0x96, 0x9B, /* 0x10-0x13 */ - 0x96, 0x9C, 0x96, 0x9D, 0x96, 0x9E, 0x96, 0x9F, /* 0x14-0x17 */ - 0xBB, 0xC2, 0xBB, 0xC3, 0x96, 0xA0, 0xBB, 0xC4, /* 0x18-0x1B */ - 0xBB, 0xC5, 0xBB, 0xC6, 0x96, 0xA1, 0x96, 0xA2, /* 0x1C-0x1F */ - 0x96, 0xA3, 0x96, 0xA4, 0x96, 0xA5, 0x96, 0xA6, /* 0x20-0x23 */ - 0x96, 0xA7, 0x96, 0xA8, 0x96, 0xA9, 0x96, 0xAA, /* 0x24-0x27 */ - 0x96, 0xAB, 0x96, 0xAC, 0x96, 0xAD, 0x96, 0xAE, /* 0x28-0x2B */ - 0x96, 0xAF, 0x96, 0xB0, 0x96, 0xB1, 0x96, 0xB2, /* 0x2C-0x2F */ - 0x96, 0xB3, 0x96, 0xB4, 0x96, 0xB5, 0x96, 0xB6, /* 0x30-0x33 */ - 0x96, 0xB7, 0x96, 0xB8, 0x96, 0xB9, 0x96, 0xBA, /* 0x34-0x37 */ - 0x96, 0xBB, 0x96, 0xBC, 0x96, 0xBD, 0x96, 0xBE, /* 0x38-0x3B */ - 0x96, 0xBF, 0x96, 0xC0, 0x96, 0xC1, 0x96, 0xC2, /* 0x3C-0x3F */ - 0xBB, 0xC7, 0xBB, 0xC8, 0x96, 0xC3, 0x96, 0xC4, /* 0x40-0x43 */ - 0xBB, 0xC9, 0x96, 0xC5, 0x96, 0xC6, 0x96, 0xC7, /* 0x44-0x47 */ - 0xBB, 0xCA, 0x96, 0xC8, 0x96, 0xC9, 0x96, 0xCA, /* 0x48-0x4B */ - 0x96, 0xCB, 0x96, 0xCC, 0x96, 0xCD, 0x96, 0xCE, /* 0x4C-0x4F */ - 0xBB, 0xCB, 0xBB, 0xCC, 0x96, 0xCF, 0x96, 0xD0, /* 0x50-0x53 */ - 0x96, 0xD1, 0xBB, 0xCD, 0x96, 0xD2, 0x96, 0xD3, /* 0x54-0x57 */ - 0x96, 0xD4, 0x96, 0xD5, 0x96, 0xD6, 0x96, 0xD7, /* 0x58-0x5B */ - 0x96, 0xD8, 0x96, 0xD9, 0x96, 0xDA, 0x96, 0xDB, /* 0x5C-0x5F */ - 0x96, 0xDC, 0x96, 0xDD, 0x96, 0xDE, 0x96, 0xDF, /* 0x60-0x63 */ - 0x96, 0xE0, 0x96, 0xE1, 0x96, 0xE2, 0x96, 0xE3, /* 0x64-0x67 */ - 0x96, 0xE4, 0x96, 0xE5, 0x96, 0xE6, 0x96, 0xE7, /* 0x68-0x6B */ - 0x96, 0xE8, 0x96, 0xE9, 0x96, 0xEA, 0x96, 0xEB, /* 0x6C-0x6F */ - 0x96, 0xEC, 0x96, 0xED, 0x96, 0xEE, 0x96, 0xEF, /* 0x70-0x73 */ - 0x96, 0xF0, 0x96, 0xF1, 0x96, 0xF2, 0x96, 0xF3, /* 0x74-0x77 */ - 0x96, 0xF4, 0x96, 0xF5, 0x96, 0xF6, 0x96, 0xF7, /* 0x78-0x7B */ - 0x96, 0xF8, 0x96, 0xF9, 0x96, 0xFA, 0x96, 0xFB, /* 0x7C-0x7F */ - - 0x96, 0xFC, 0x96, 0xFD, 0x96, 0xFE, 0x97, 0x41, /* 0x80-0x83 */ - 0x97, 0x42, 0x97, 0x43, 0x97, 0x44, 0x97, 0x45, /* 0x84-0x87 */ - 0x97, 0x46, 0x97, 0x47, 0x97, 0x48, 0x97, 0x49, /* 0x88-0x8B */ - 0x97, 0x4A, 0x97, 0x4B, 0x97, 0x4C, 0x97, 0x4D, /* 0x8C-0x8F */ - 0x97, 0x4E, 0x97, 0x4F, 0x97, 0x50, 0x97, 0x51, /* 0x90-0x93 */ - 0xBB, 0xCE, 0x97, 0x52, 0x97, 0x53, 0x97, 0x54, /* 0x94-0x97 */ - 0x97, 0x55, 0x97, 0x56, 0x97, 0x57, 0x97, 0x58, /* 0x98-0x9B */ - 0x97, 0x59, 0x97, 0x5A, 0x97, 0x61, 0x97, 0x62, /* 0x9C-0x9F */ - 0x97, 0x63, 0x97, 0x64, 0x97, 0x65, 0x97, 0x66, /* 0xA0-0xA3 */ - 0x97, 0x67, 0x97, 0x68, 0x97, 0x69, 0x97, 0x6A, /* 0xA4-0xA7 */ - 0x97, 0x6B, 0x97, 0x6C, 0x97, 0x6D, 0x97, 0x6E, /* 0xA8-0xAB */ - 0x97, 0x6F, 0x97, 0x70, 0x97, 0x71, 0x97, 0x72, /* 0xAC-0xAF */ - 0xBB, 0xCF, 0x97, 0x73, 0x97, 0x74, 0x97, 0x75, /* 0xB0-0xB3 */ - 0x97, 0x76, 0x97, 0x77, 0x97, 0x78, 0x97, 0x79, /* 0xB4-0xB7 */ - 0x97, 0x7A, 0x97, 0x81, 0x97, 0x82, 0x97, 0x83, /* 0xB8-0xBB */ - 0x97, 0x84, 0x97, 0x85, 0x97, 0x86, 0x97, 0x87, /* 0xBC-0xBF */ - 0x97, 0x88, 0x97, 0x89, 0x97, 0x8A, 0x97, 0x8B, /* 0xC0-0xC3 */ - 0x97, 0x8C, 0xBB, 0xD0, 0x97, 0x8D, 0x97, 0x8E, /* 0xC4-0xC7 */ - 0x97, 0x8F, 0x97, 0x90, 0x97, 0x91, 0x97, 0x92, /* 0xC8-0xCB */ - 0xBB, 0xD1, 0xBB, 0xD2, 0x97, 0x93, 0x97, 0x94, /* 0xCC-0xCF */ - 0xBB, 0xD3, 0x97, 0x95, 0x97, 0x96, 0x97, 0x97, /* 0xD0-0xD3 */ - 0xBB, 0xD4, 0x97, 0x98, 0x97, 0x99, 0x97, 0x9A, /* 0xD4-0xD7 */ - 0x97, 0x9B, 0x97, 0x9C, 0x97, 0x9D, 0x97, 0x9E, /* 0xD8-0xDB */ - 0xBB, 0xD5, 0x97, 0x9F, 0x97, 0xA0, 0xBB, 0xD6, /* 0xDC-0xDF */ - 0x97, 0xA1, 0xBB, 0xD7, 0x97, 0xA2, 0x97, 0xA3, /* 0xE0-0xE3 */ - 0x97, 0xA4, 0x97, 0xA5, 0x97, 0xA6, 0x97, 0xA7, /* 0xE4-0xE7 */ - 0x97, 0xA8, 0x97, 0xA9, 0x97, 0xAA, 0x97, 0xAB, /* 0xE8-0xEB */ - 0x97, 0xAC, 0x97, 0xAD, 0x97, 0xAE, 0x97, 0xAF, /* 0xEC-0xEF */ - 0x97, 0xB0, 0x97, 0xB1, 0x97, 0xB2, 0x97, 0xB3, /* 0xF0-0xF3 */ - 0x97, 0xB4, 0x97, 0xB5, 0x97, 0xB6, 0x97, 0xB7, /* 0xF4-0xF7 */ - 0x97, 0xB8, 0x97, 0xB9, 0x97, 0xBA, 0x97, 0xBB, /* 0xF8-0xFB */ - 0x97, 0xBC, 0x97, 0xBD, 0x97, 0xBE, 0x97, 0xBF, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_C0[512] = { - 0x97, 0xC0, 0x97, 0xC1, 0x97, 0xC2, 0x97, 0xC3, /* 0x00-0x03 */ - 0x97, 0xC4, 0x97, 0xC5, 0x97, 0xC6, 0x97, 0xC7, /* 0x04-0x07 */ - 0x97, 0xC8, 0x97, 0xC9, 0x97, 0xCA, 0x97, 0xCB, /* 0x08-0x0B */ - 0x97, 0xCC, 0x97, 0xCD, 0x97, 0xCE, 0x97, 0xCF, /* 0x0C-0x0F */ - 0x97, 0xD0, 0x97, 0xD1, 0x97, 0xD2, 0x97, 0xD3, /* 0x10-0x13 */ - 0x97, 0xD4, 0x97, 0xD5, 0x97, 0xD6, 0x97, 0xD7, /* 0x14-0x17 */ - 0x97, 0xD8, 0x97, 0xD9, 0x97, 0xDA, 0x97, 0xDB, /* 0x18-0x1B */ - 0x97, 0xDC, 0x97, 0xDD, 0x97, 0xDE, 0x97, 0xDF, /* 0x1C-0x1F */ - 0x97, 0xE0, 0x97, 0xE1, 0x97, 0xE2, 0x97, 0xE3, /* 0x20-0x23 */ - 0x97, 0xE4, 0x97, 0xE5, 0x97, 0xE6, 0x97, 0xE7, /* 0x24-0x27 */ - 0x97, 0xE8, 0x97, 0xE9, 0x97, 0xEA, 0x97, 0xEB, /* 0x28-0x2B */ - 0x97, 0xEC, 0x97, 0xED, 0x97, 0xEE, 0x97, 0xEF, /* 0x2C-0x2F */ - 0x97, 0xF0, 0x97, 0xF1, 0x97, 0xF2, 0x97, 0xF3, /* 0x30-0x33 */ - 0x97, 0xF4, 0x97, 0xF5, 0x97, 0xF6, 0x97, 0xF7, /* 0x34-0x37 */ - 0x97, 0xF8, 0x97, 0xF9, 0x97, 0xFA, 0x97, 0xFB, /* 0x38-0x3B */ - 0xBB, 0xD8, 0x97, 0xFC, 0x97, 0xFD, 0x97, 0xFE, /* 0x3C-0x3F */ - 0x98, 0x41, 0x98, 0x42, 0x98, 0x43, 0x98, 0x44, /* 0x40-0x43 */ - 0x98, 0x45, 0x98, 0x46, 0x98, 0x47, 0x98, 0x48, /* 0x44-0x47 */ - 0x98, 0x49, 0x98, 0x4A, 0x98, 0x4B, 0x98, 0x4C, /* 0x48-0x4B */ - 0x98, 0x4D, 0x98, 0x4E, 0x98, 0x4F, 0x98, 0x50, /* 0x4C-0x4F */ - 0x98, 0x51, 0xBB, 0xD9, 0x98, 0x52, 0x98, 0x53, /* 0x50-0x53 */ - 0x98, 0x54, 0x98, 0x55, 0x98, 0x56, 0x98, 0x57, /* 0x54-0x57 */ - 0xBB, 0xDA, 0x98, 0x58, 0x98, 0x59, 0x98, 0x5A, /* 0x58-0x5B */ - 0xBB, 0xDB, 0x98, 0x61, 0x98, 0x62, 0x98, 0x63, /* 0x5C-0x5F */ - 0xBB, 0xDC, 0x98, 0x64, 0x98, 0x65, 0x98, 0x66, /* 0x60-0x63 */ - 0x98, 0x67, 0x98, 0x68, 0x98, 0x69, 0x98, 0x6A, /* 0x64-0x67 */ - 0xBB, 0xDD, 0xBB, 0xDE, 0x98, 0x6B, 0x98, 0x6C, /* 0x68-0x6B */ - 0x98, 0x6D, 0x98, 0x6E, 0x98, 0x6F, 0x98, 0x70, /* 0x6C-0x6F */ - 0x98, 0x71, 0x98, 0x72, 0x98, 0x73, 0x98, 0x74, /* 0x70-0x73 */ - 0x98, 0x75, 0x98, 0x76, 0x98, 0x77, 0x98, 0x78, /* 0x74-0x77 */ - 0x98, 0x79, 0x98, 0x7A, 0x98, 0x81, 0x98, 0x82, /* 0x78-0x7B */ - 0x98, 0x83, 0x98, 0x84, 0x98, 0x85, 0x98, 0x86, /* 0x7C-0x7F */ - - 0x98, 0x87, 0x98, 0x88, 0x98, 0x89, 0x98, 0x8A, /* 0x80-0x83 */ - 0x98, 0x8B, 0x98, 0x8C, 0x98, 0x8D, 0x98, 0x8E, /* 0x84-0x87 */ - 0x98, 0x8F, 0x98, 0x90, 0x98, 0x91, 0x98, 0x92, /* 0x88-0x8B */ - 0x98, 0x93, 0x98, 0x94, 0x98, 0x95, 0x98, 0x96, /* 0x8C-0x8F */ - 0xBB, 0xDF, 0xBB, 0xE0, 0x98, 0x97, 0x98, 0x98, /* 0x90-0x93 */ - 0xBB, 0xE1, 0x98, 0x99, 0x98, 0x9A, 0x98, 0x9B, /* 0x94-0x97 */ - 0xBB, 0xE2, 0x98, 0x9C, 0x98, 0x9D, 0x98, 0x9E, /* 0x98-0x9B */ - 0x98, 0x9F, 0x98, 0xA0, 0x98, 0xA1, 0x98, 0xA2, /* 0x9C-0x9F */ - 0xBB, 0xE3, 0xBB, 0xE4, 0x98, 0xA3, 0xBB, 0xE5, /* 0xA0-0xA3 */ - 0x98, 0xA4, 0xBB, 0xE6, 0x98, 0xA5, 0x98, 0xA6, /* 0xA4-0xA7 */ - 0x98, 0xA7, 0x98, 0xA8, 0x98, 0xA9, 0x98, 0xAA, /* 0xA8-0xAB */ - 0xBB, 0xE7, 0xBB, 0xE8, 0x98, 0xAB, 0xBB, 0xE9, /* 0xAC-0xAF */ - 0xBB, 0xEA, 0x98, 0xAC, 0x98, 0xAD, 0xBB, 0xEB, /* 0xB0-0xB3 */ - 0xBB, 0xEC, 0xBB, 0xED, 0xBB, 0xEE, 0x98, 0xAE, /* 0xB4-0xB7 */ - 0x98, 0xAF, 0x98, 0xB0, 0x98, 0xB1, 0x98, 0xB2, /* 0xB8-0xBB */ - 0xBB, 0xEF, 0xBB, 0xF0, 0x98, 0xB3, 0xBB, 0xF1, /* 0xBC-0xBF */ - 0xBB, 0xF2, 0xBB, 0xF3, 0x98, 0xB4, 0x98, 0xB5, /* 0xC0-0xC3 */ - 0x98, 0xB6, 0xBB, 0xF4, 0x98, 0xB7, 0x98, 0xB8, /* 0xC4-0xC7 */ - 0xBB, 0xF5, 0xBB, 0xF6, 0x98, 0xB9, 0x98, 0xBA, /* 0xC8-0xCB */ - 0xBB, 0xF7, 0x98, 0xBB, 0x98, 0xBC, 0x98, 0xBD, /* 0xCC-0xCF */ - 0xBB, 0xF8, 0x98, 0xBE, 0x98, 0xBF, 0x98, 0xC0, /* 0xD0-0xD3 */ - 0x98, 0xC1, 0x98, 0xC2, 0x98, 0xC3, 0x98, 0xC4, /* 0xD4-0xD7 */ - 0xBB, 0xF9, 0xBB, 0xFA, 0x98, 0xC5, 0xBB, 0xFB, /* 0xD8-0xDB */ - 0xBB, 0xFC, 0xBB, 0xFD, 0x98, 0xC6, 0x98, 0xC7, /* 0xDC-0xDF */ - 0x98, 0xC8, 0x98, 0xC9, 0x98, 0xCA, 0x98, 0xCB, /* 0xE0-0xE3 */ - 0xBB, 0xFE, 0xBC, 0xA1, 0x98, 0xCC, 0x98, 0xCD, /* 0xE4-0xE7 */ - 0xBC, 0xA2, 0x98, 0xCE, 0x98, 0xCF, 0x98, 0xD0, /* 0xE8-0xEB */ - 0xBC, 0xA3, 0x98, 0xD1, 0x98, 0xD2, 0x98, 0xD3, /* 0xEC-0xEF */ - 0x98, 0xD4, 0x98, 0xD5, 0x98, 0xD6, 0x98, 0xD7, /* 0xF0-0xF3 */ - 0xBC, 0xA4, 0xBC, 0xA5, 0x98, 0xD8, 0xBC, 0xA6, /* 0xF4-0xF7 */ - 0x98, 0xD9, 0xBC, 0xA7, 0x98, 0xDA, 0x98, 0xDB, /* 0xF8-0xFB */ - 0x98, 0xDC, 0x98, 0xDD, 0x98, 0xDE, 0x98, 0xDF, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_C1[512] = { - 0xBC, 0xA8, 0x98, 0xE0, 0x98, 0xE1, 0x98, 0xE2, /* 0x00-0x03 */ - 0xBC, 0xA9, 0x98, 0xE3, 0x98, 0xE4, 0x98, 0xE5, /* 0x04-0x07 */ - 0xBC, 0xAA, 0x98, 0xE6, 0x98, 0xE7, 0x98, 0xE8, /* 0x08-0x0B */ - 0x98, 0xE9, 0x98, 0xEA, 0x98, 0xEB, 0x98, 0xEC, /* 0x0C-0x0F */ - 0xBC, 0xAB, 0x98, 0xED, 0x98, 0xEE, 0x98, 0xEF, /* 0x10-0x13 */ - 0x98, 0xF0, 0xBC, 0xAC, 0x98, 0xF1, 0x98, 0xF2, /* 0x14-0x17 */ - 0x98, 0xF3, 0x98, 0xF4, 0x98, 0xF5, 0x98, 0xF6, /* 0x18-0x1B */ - 0xBC, 0xAD, 0xBC, 0xAE, 0xBC, 0xAF, 0xBC, 0xB0, /* 0x1C-0x1F */ - 0xBC, 0xB1, 0x98, 0xF7, 0x98, 0xF8, 0xBC, 0xB2, /* 0x20-0x23 */ - 0xBC, 0xB3, 0x98, 0xF9, 0xBC, 0xB4, 0xBC, 0xB5, /* 0x24-0x27 */ - 0x98, 0xFA, 0x98, 0xFB, 0x98, 0xFC, 0x98, 0xFD, /* 0x28-0x2B */ - 0xBC, 0xB6, 0xBC, 0xB7, 0x98, 0xFE, 0xBC, 0xB8, /* 0x2C-0x2F */ - 0xBC, 0xB9, 0xBC, 0xBA, 0x99, 0x41, 0x99, 0x42, /* 0x30-0x33 */ - 0x99, 0x43, 0x99, 0x44, 0xBC, 0xBB, 0x99, 0x45, /* 0x34-0x37 */ - 0xBC, 0xBC, 0xBC, 0xBD, 0x99, 0x46, 0x99, 0x47, /* 0x38-0x3B */ - 0xBC, 0xBE, 0x99, 0x48, 0x99, 0x49, 0x99, 0x4A, /* 0x3C-0x3F */ - 0xBC, 0xBF, 0x99, 0x4B, 0x99, 0x4C, 0x99, 0x4D, /* 0x40-0x43 */ - 0x99, 0x4E, 0x99, 0x4F, 0x99, 0x50, 0x99, 0x51, /* 0x44-0x47 */ - 0xBC, 0xC0, 0xBC, 0xC1, 0x99, 0x52, 0xBC, 0xC2, /* 0x48-0x4B */ - 0xBC, 0xC3, 0xBC, 0xC4, 0x99, 0x53, 0x99, 0x54, /* 0x4C-0x4F */ - 0x99, 0x55, 0x99, 0x56, 0x99, 0x57, 0x99, 0x58, /* 0x50-0x53 */ - 0xBC, 0xC5, 0xBC, 0xC6, 0x99, 0x59, 0x99, 0x5A, /* 0x54-0x57 */ - 0xBC, 0xC7, 0x99, 0x61, 0x99, 0x62, 0x99, 0x63, /* 0x58-0x5B */ - 0xBC, 0xC8, 0x99, 0x64, 0x99, 0x65, 0x99, 0x66, /* 0x5C-0x5F */ - 0x99, 0x67, 0x99, 0x68, 0x99, 0x69, 0x99, 0x6A, /* 0x60-0x63 */ - 0xBC, 0xC9, 0xBC, 0xCA, 0x99, 0x6B, 0xBC, 0xCB, /* 0x64-0x67 */ - 0xBC, 0xCC, 0xBC, 0xCD, 0x99, 0x6C, 0x99, 0x6D, /* 0x68-0x6B */ - 0x99, 0x6E, 0x99, 0x6F, 0x99, 0x70, 0x99, 0x71, /* 0x6C-0x6F */ - 0xBC, 0xCE, 0x99, 0x72, 0x99, 0x73, 0x99, 0x74, /* 0x70-0x73 */ - 0xBC, 0xCF, 0x99, 0x75, 0x99, 0x76, 0x99, 0x77, /* 0x74-0x77 */ - 0xBC, 0xD0, 0x99, 0x78, 0x99, 0x79, 0x99, 0x7A, /* 0x78-0x7B */ - 0x99, 0x81, 0x99, 0x82, 0x99, 0x83, 0x99, 0x84, /* 0x7C-0x7F */ - - 0x99, 0x85, 0x99, 0x86, 0x99, 0x87, 0x99, 0x88, /* 0x80-0x83 */ - 0x99, 0x89, 0xBC, 0xD1, 0x99, 0x8A, 0x99, 0x8B, /* 0x84-0x87 */ - 0x99, 0x8C, 0x99, 0x8D, 0x99, 0x8E, 0x99, 0x8F, /* 0x88-0x8B */ - 0xBC, 0xD2, 0xBC, 0xD3, 0xBC, 0xD4, 0x99, 0x90, /* 0x8C-0x8F */ - 0xBC, 0xD5, 0x99, 0x91, 0x99, 0x92, 0x99, 0x93, /* 0x90-0x93 */ - 0xBC, 0xD6, 0x99, 0x94, 0xBC, 0xD7, 0x99, 0x95, /* 0x94-0x97 */ - 0x99, 0x96, 0x99, 0x97, 0x99, 0x98, 0x99, 0x99, /* 0x98-0x9B */ - 0xBC, 0xD8, 0xBC, 0xD9, 0x99, 0x9A, 0xBC, 0xDA, /* 0x9C-0x9F */ - 0x99, 0x9B, 0xBC, 0xDB, 0x99, 0x9C, 0x99, 0x9D, /* 0xA0-0xA3 */ - 0x99, 0x9E, 0xBC, 0xDC, 0x99, 0x9F, 0x99, 0xA0, /* 0xA4-0xA7 */ - 0xBC, 0xDD, 0xBC, 0xDE, 0x99, 0xA1, 0x99, 0xA2, /* 0xA8-0xAB */ - 0xBC, 0xDF, 0x99, 0xA3, 0x99, 0xA4, 0x99, 0xA5, /* 0xAC-0xAF */ - 0xBC, 0xE0, 0x99, 0xA6, 0x99, 0xA7, 0x99, 0xA8, /* 0xB0-0xB3 */ - 0x99, 0xA9, 0x99, 0xAA, 0x99, 0xAB, 0x99, 0xAC, /* 0xB4-0xB7 */ - 0x99, 0xAD, 0x99, 0xAE, 0x99, 0xAF, 0x99, 0xB0, /* 0xB8-0xBB */ - 0x99, 0xB1, 0xBC, 0xE1, 0x99, 0xB2, 0x99, 0xB3, /* 0xBC-0xBF */ - 0x99, 0xB4, 0x99, 0xB5, 0x99, 0xB6, 0x99, 0xB7, /* 0xC0-0xC3 */ - 0xBC, 0xE2, 0x99, 0xB8, 0x99, 0xB9, 0x99, 0xBA, /* 0xC4-0xC7 */ - 0xBC, 0xE3, 0x99, 0xBB, 0x99, 0xBC, 0x99, 0xBD, /* 0xC8-0xCB */ - 0xBC, 0xE4, 0x99, 0xBE, 0x99, 0xBF, 0x99, 0xC0, /* 0xCC-0xCF */ - 0x99, 0xC1, 0x99, 0xC2, 0x99, 0xC3, 0x99, 0xC4, /* 0xD0-0xD3 */ - 0xBC, 0xE5, 0x99, 0xC5, 0x99, 0xC6, 0xBC, 0xE6, /* 0xD4-0xD7 */ - 0xBC, 0xE7, 0x99, 0xC7, 0x99, 0xC8, 0x99, 0xC9, /* 0xD8-0xDB */ - 0x99, 0xCA, 0x99, 0xCB, 0x99, 0xCC, 0x99, 0xCD, /* 0xDC-0xDF */ - 0xBC, 0xE8, 0x99, 0xCE, 0x99, 0xCF, 0x99, 0xD0, /* 0xE0-0xE3 */ - 0xBC, 0xE9, 0x99, 0xD1, 0x99, 0xD2, 0x99, 0xD3, /* 0xE4-0xE7 */ - 0xBC, 0xEA, 0x99, 0xD4, 0x99, 0xD5, 0x99, 0xD6, /* 0xE8-0xEB */ - 0x99, 0xD7, 0x99, 0xD8, 0x99, 0xD9, 0x99, 0xDA, /* 0xEC-0xEF */ - 0xBC, 0xEB, 0xBC, 0xEC, 0x99, 0xDB, 0xBC, 0xED, /* 0xF0-0xF3 */ - 0x99, 0xDC, 0x99, 0xDD, 0x99, 0xDE, 0x99, 0xDF, /* 0xF4-0xF7 */ - 0x99, 0xE0, 0x99, 0xE1, 0x99, 0xE2, 0x99, 0xE3, /* 0xF8-0xFB */ - 0xBC, 0xEE, 0xBC, 0xEF, 0x99, 0xE4, 0x99, 0xE5, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_C2[512] = { - 0xBC, 0xF0, 0x99, 0xE6, 0x99, 0xE7, 0x99, 0xE8, /* 0x00-0x03 */ - 0xBC, 0xF1, 0x99, 0xE9, 0x99, 0xEA, 0x99, 0xEB, /* 0x04-0x07 */ - 0x99, 0xEC, 0x99, 0xED, 0x99, 0xEE, 0x99, 0xEF, /* 0x08-0x0B */ - 0xBC, 0xF2, 0xBC, 0xF3, 0x99, 0xF0, 0xBC, 0xF4, /* 0x0C-0x0F */ - 0x99, 0xF1, 0xBC, 0xF5, 0x99, 0xF2, 0x99, 0xF3, /* 0x10-0x13 */ - 0x99, 0xF4, 0x99, 0xF5, 0x99, 0xF6, 0x99, 0xF7, /* 0x14-0x17 */ - 0xBC, 0xF6, 0xBC, 0xF7, 0x99, 0xF8, 0x99, 0xF9, /* 0x18-0x1B */ - 0xBC, 0xF8, 0x99, 0xFA, 0x99, 0xFB, 0xBC, 0xF9, /* 0x1C-0x1F */ - 0xBC, 0xFA, 0x99, 0xFC, 0x99, 0xFD, 0x99, 0xFE, /* 0x20-0x23 */ - 0x9A, 0x41, 0x9A, 0x42, 0x9A, 0x43, 0x9A, 0x44, /* 0x24-0x27 */ - 0xBC, 0xFB, 0xBC, 0xFC, 0x9A, 0x45, 0xBC, 0xFD, /* 0x28-0x2B */ - 0x9A, 0x46, 0xBC, 0xFE, 0x9A, 0x47, 0xBD, 0xA1, /* 0x2C-0x2F */ - 0x9A, 0x48, 0xBD, 0xA2, 0xBD, 0xA3, 0x9A, 0x49, /* 0x30-0x33 */ - 0xBD, 0xA4, 0x9A, 0x4A, 0x9A, 0x4B, 0x9A, 0x4C, /* 0x34-0x37 */ - 0x9A, 0x4D, 0x9A, 0x4E, 0x9A, 0x4F, 0x9A, 0x50, /* 0x38-0x3B */ - 0x9A, 0x51, 0x9A, 0x52, 0x9A, 0x53, 0x9A, 0x54, /* 0x3C-0x3F */ - 0x9A, 0x55, 0x9A, 0x56, 0x9A, 0x57, 0x9A, 0x58, /* 0x40-0x43 */ - 0x9A, 0x59, 0x9A, 0x5A, 0x9A, 0x61, 0x9A, 0x62, /* 0x44-0x47 */ - 0xBD, 0xA5, 0x9A, 0x63, 0x9A, 0x64, 0x9A, 0x65, /* 0x48-0x4B */ - 0x9A, 0x66, 0x9A, 0x67, 0x9A, 0x68, 0x9A, 0x69, /* 0x4C-0x4F */ - 0xBD, 0xA6, 0xBD, 0xA7, 0x9A, 0x6A, 0x9A, 0x6B, /* 0x50-0x53 */ - 0xBD, 0xA8, 0x9A, 0x6C, 0x9A, 0x6D, 0x9A, 0x6E, /* 0x54-0x57 */ - 0xBD, 0xA9, 0x9A, 0x6F, 0x9A, 0x70, 0x9A, 0x71, /* 0x58-0x5B */ - 0x9A, 0x72, 0x9A, 0x73, 0x9A, 0x74, 0x9A, 0x75, /* 0x5C-0x5F */ - 0xBD, 0xAA, 0x9A, 0x76, 0x9A, 0x77, 0x9A, 0x78, /* 0x60-0x63 */ - 0x9A, 0x79, 0xBD, 0xAB, 0x9A, 0x7A, 0x9A, 0x81, /* 0x64-0x67 */ - 0x9A, 0x82, 0x9A, 0x83, 0x9A, 0x84, 0x9A, 0x85, /* 0x68-0x6B */ - 0xBD, 0xAC, 0xBD, 0xAD, 0x9A, 0x86, 0x9A, 0x87, /* 0x6C-0x6F */ - 0xBD, 0xAE, 0x9A, 0x88, 0x9A, 0x89, 0x9A, 0x8A, /* 0x70-0x73 */ - 0xBD, 0xAF, 0x9A, 0x8B, 0x9A, 0x8C, 0x9A, 0x8D, /* 0x74-0x77 */ - 0x9A, 0x8E, 0x9A, 0x8F, 0x9A, 0x90, 0x9A, 0x91, /* 0x78-0x7B */ - 0xBD, 0xB0, 0xBD, 0xB1, 0x9A, 0x92, 0xBD, 0xB2, /* 0x7C-0x7F */ - - 0x9A, 0x93, 0xBD, 0xB3, 0x9A, 0x94, 0x9A, 0x95, /* 0x80-0x83 */ - 0x9A, 0x96, 0x9A, 0x97, 0x9A, 0x98, 0x9A, 0x99, /* 0x84-0x87 */ - 0xBD, 0xB4, 0xBD, 0xB5, 0x9A, 0x9A, 0x9A, 0x9B, /* 0x88-0x8B */ - 0x9A, 0x9C, 0x9A, 0x9D, 0x9A, 0x9E, 0x9A, 0x9F, /* 0x8C-0x8F */ - 0xBD, 0xB6, 0x9A, 0xA0, 0x9A, 0xA1, 0x9A, 0xA2, /* 0x90-0x93 */ - 0x9A, 0xA3, 0x9A, 0xA4, 0x9A, 0xA5, 0x9A, 0xA6, /* 0x94-0x97 */ - 0xBD, 0xB7, 0x9A, 0xA7, 0x9A, 0xA8, 0xBD, 0xB8, /* 0x98-0x9B */ - 0x9A, 0xA9, 0xBD, 0xB9, 0x9A, 0xAA, 0x9A, 0xAB, /* 0x9C-0x9F */ - 0x9A, 0xAC, 0x9A, 0xAD, 0x9A, 0xAE, 0x9A, 0xAF, /* 0xA0-0xA3 */ - 0xBD, 0xBA, 0xBD, 0xBB, 0x9A, 0xB0, 0x9A, 0xB1, /* 0xA4-0xA7 */ - 0xBD, 0xBC, 0x9A, 0xB2, 0x9A, 0xB3, 0x9A, 0xB4, /* 0xA8-0xAB */ - 0xBD, 0xBD, 0xBD, 0xBE, 0x9A, 0xB5, 0x9A, 0xB6, /* 0xAC-0xAF */ - 0x9A, 0xB7, 0x9A, 0xB8, 0x9A, 0xB9, 0x9A, 0xBA, /* 0xB0-0xB3 */ - 0xBD, 0xBF, 0xBD, 0xC0, 0x9A, 0xBB, 0xBD, 0xC1, /* 0xB4-0xB7 */ - 0x9A, 0xBC, 0xBD, 0xC2, 0x9A, 0xBD, 0x9A, 0xBE, /* 0xB8-0xBB */ - 0x9A, 0xBF, 0x9A, 0xC0, 0x9A, 0xC1, 0x9A, 0xC2, /* 0xBC-0xBF */ - 0x9A, 0xC3, 0x9A, 0xC4, 0x9A, 0xC5, 0x9A, 0xC6, /* 0xC0-0xC3 */ - 0x9A, 0xC7, 0x9A, 0xC8, 0x9A, 0xC9, 0x9A, 0xCA, /* 0xC4-0xC7 */ - 0x9A, 0xCB, 0x9A, 0xCC, 0x9A, 0xCD, 0x9A, 0xCE, /* 0xC8-0xCB */ - 0x9A, 0xCF, 0x9A, 0xD0, 0x9A, 0xD1, 0x9A, 0xD2, /* 0xCC-0xCF */ - 0x9A, 0xD3, 0x9A, 0xD4, 0x9A, 0xD5, 0x9A, 0xD6, /* 0xD0-0xD3 */ - 0x9A, 0xD7, 0x9A, 0xD8, 0x9A, 0xD9, 0x9A, 0xDA, /* 0xD4-0xD7 */ - 0x9A, 0xDB, 0x9A, 0xDC, 0x9A, 0xDD, 0x9A, 0xDE, /* 0xD8-0xDB */ - 0xBD, 0xC3, 0xBD, 0xC4, 0x9A, 0xDF, 0x9A, 0xE0, /* 0xDC-0xDF */ - 0xBD, 0xC5, 0x9A, 0xE1, 0x9A, 0xE2, 0xBD, 0xC6, /* 0xE0-0xE3 */ - 0xBD, 0xC7, 0x9A, 0xE3, 0x9A, 0xE4, 0x9A, 0xE5, /* 0xE4-0xE7 */ - 0x9A, 0xE6, 0x9A, 0xE7, 0x9A, 0xE8, 0xBD, 0xC8, /* 0xE8-0xEB */ - 0xBD, 0xC9, 0xBD, 0xCA, 0x9A, 0xE9, 0xBD, 0xCB, /* 0xEC-0xEF */ - 0x9A, 0xEA, 0xBD, 0xCC, 0x9A, 0xEB, 0x9A, 0xEC, /* 0xF0-0xF3 */ - 0x9A, 0xED, 0x9A, 0xEE, 0xBD, 0xCD, 0x9A, 0xEF, /* 0xF4-0xF7 */ - 0xBD, 0xCE, 0xBD, 0xCF, 0x9A, 0xF0, 0xBD, 0xD0, /* 0xF8-0xFB */ - 0xBD, 0xD1, 0x9A, 0xF1, 0x9A, 0xF2, 0x9A, 0xF3, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_C3[512] = { - 0xBD, 0xD2, 0x9A, 0xF4, 0x9A, 0xF5, 0x9A, 0xF6, /* 0x00-0x03 */ - 0x9A, 0xF7, 0x9A, 0xF8, 0x9A, 0xF9, 0x9A, 0xFA, /* 0x04-0x07 */ - 0xBD, 0xD3, 0xBD, 0xD4, 0x9A, 0xFB, 0x9A, 0xFC, /* 0x08-0x0B */ - 0xBD, 0xD5, 0xBD, 0xD6, 0x9A, 0xFD, 0x9A, 0xFE, /* 0x0C-0x0F */ - 0x9B, 0x41, 0x9B, 0x42, 0x9B, 0x43, 0xBD, 0xD7, /* 0x10-0x13 */ - 0xBD, 0xD8, 0xBD, 0xD9, 0x9B, 0x44, 0x9B, 0x45, /* 0x14-0x17 */ - 0xBD, 0xDA, 0x9B, 0x46, 0x9B, 0x47, 0x9B, 0x48, /* 0x18-0x1B */ - 0xBD, 0xDB, 0x9B, 0x49, 0x9B, 0x4A, 0x9B, 0x4B, /* 0x1C-0x1F */ - 0x9B, 0x4C, 0x9B, 0x4D, 0x9B, 0x4E, 0x9B, 0x4F, /* 0x20-0x23 */ - 0xBD, 0xDC, 0xBD, 0xDD, 0x9B, 0x50, 0x9B, 0x51, /* 0x24-0x27 */ - 0xBD, 0xDE, 0xBD, 0xDF, 0x9B, 0x52, 0x9B, 0x53, /* 0x28-0x2B */ - 0x9B, 0x54, 0x9B, 0x55, 0x9B, 0x56, 0x9B, 0x57, /* 0x2C-0x2F */ - 0x9B, 0x58, 0x9B, 0x59, 0x9B, 0x5A, 0x9B, 0x61, /* 0x30-0x33 */ - 0x9B, 0x62, 0x9B, 0x63, 0x9B, 0x64, 0x9B, 0x65, /* 0x34-0x37 */ - 0x9B, 0x66, 0x9B, 0x67, 0x9B, 0x68, 0x9B, 0x69, /* 0x38-0x3B */ - 0x9B, 0x6A, 0x9B, 0x6B, 0x9B, 0x6C, 0x9B, 0x6D, /* 0x3C-0x3F */ - 0x9B, 0x6E, 0x9B, 0x6F, 0x9B, 0x70, 0x9B, 0x71, /* 0x40-0x43 */ - 0x9B, 0x72, 0xBD, 0xE0, 0x9B, 0x73, 0x9B, 0x74, /* 0x44-0x47 */ - 0x9B, 0x75, 0x9B, 0x76, 0x9B, 0x77, 0x9B, 0x78, /* 0x48-0x4B */ - 0x9B, 0x79, 0x9B, 0x7A, 0x9B, 0x81, 0x9B, 0x82, /* 0x4C-0x4F */ - 0x9B, 0x83, 0x9B, 0x84, 0x9B, 0x85, 0x9B, 0x86, /* 0x50-0x53 */ - 0x9B, 0x87, 0x9B, 0x88, 0x9B, 0x89, 0x9B, 0x8A, /* 0x54-0x57 */ - 0x9B, 0x8B, 0x9B, 0x8C, 0x9B, 0x8D, 0x9B, 0x8E, /* 0x58-0x5B */ - 0x9B, 0x8F, 0x9B, 0x90, 0x9B, 0x91, 0x9B, 0x92, /* 0x5C-0x5F */ - 0x9B, 0x93, 0x9B, 0x94, 0x9B, 0x95, 0x9B, 0x96, /* 0x60-0x63 */ - 0x9B, 0x97, 0x9B, 0x98, 0x9B, 0x99, 0x9B, 0x9A, /* 0x64-0x67 */ - 0xBD, 0xE1, 0xBD, 0xE2, 0x9B, 0x9B, 0x9B, 0x9C, /* 0x68-0x6B */ - 0xBD, 0xE3, 0x9B, 0x9D, 0x9B, 0x9E, 0x9B, 0x9F, /* 0x6C-0x6F */ - 0xBD, 0xE4, 0x9B, 0xA0, 0xBD, 0xE5, 0x9B, 0xA1, /* 0x70-0x73 */ - 0x9B, 0xA2, 0x9B, 0xA3, 0x9B, 0xA4, 0x9B, 0xA5, /* 0x74-0x77 */ - 0xBD, 0xE6, 0xBD, 0xE7, 0x9B, 0xA6, 0x9B, 0xA7, /* 0x78-0x7B */ - 0xBD, 0xE8, 0xBD, 0xE9, 0x9B, 0xA8, 0x9B, 0xA9, /* 0x7C-0x7F */ - - 0x9B, 0xAA, 0x9B, 0xAB, 0x9B, 0xAC, 0x9B, 0xAD, /* 0x80-0x83 */ - 0xBD, 0xEA, 0x9B, 0xAE, 0x9B, 0xAF, 0x9B, 0xB0, /* 0x84-0x87 */ - 0xBD, 0xEB, 0x9B, 0xB1, 0x9B, 0xB2, 0x9B, 0xB3, /* 0x88-0x8B */ - 0xBD, 0xEC, 0x9B, 0xB4, 0x9B, 0xB5, 0x9B, 0xB6, /* 0x8C-0x8F */ - 0x9B, 0xB7, 0x9B, 0xB8, 0x9B, 0xB9, 0x9B, 0xBA, /* 0x90-0x93 */ - 0x9B, 0xBB, 0x9B, 0xBC, 0x9B, 0xBD, 0x9B, 0xBE, /* 0x94-0x97 */ - 0x9B, 0xBF, 0x9B, 0xC0, 0x9B, 0xC1, 0x9B, 0xC2, /* 0x98-0x9B */ - 0x9B, 0xC3, 0x9B, 0xC4, 0x9B, 0xC5, 0x9B, 0xC6, /* 0x9C-0x9F */ - 0x9B, 0xC7, 0x9B, 0xC8, 0x9B, 0xC9, 0x9B, 0xCA, /* 0xA0-0xA3 */ - 0x9B, 0xCB, 0x9B, 0xCC, 0x9B, 0xCD, 0x9B, 0xCE, /* 0xA4-0xA7 */ - 0x9B, 0xCF, 0x9B, 0xD0, 0x9B, 0xD1, 0x9B, 0xD2, /* 0xA8-0xAB */ - 0x9B, 0xD3, 0x9B, 0xD4, 0x9B, 0xD5, 0x9B, 0xD6, /* 0xAC-0xAF */ - 0x9B, 0xD7, 0x9B, 0xD8, 0x9B, 0xD9, 0x9B, 0xDA, /* 0xB0-0xB3 */ - 0x9B, 0xDB, 0x9B, 0xDC, 0x9B, 0xDD, 0x9B, 0xDE, /* 0xB4-0xB7 */ - 0x9B, 0xDF, 0x9B, 0xE0, 0x9B, 0xE1, 0x9B, 0xE2, /* 0xB8-0xBB */ - 0x9B, 0xE3, 0x9B, 0xE4, 0x9B, 0xE5, 0x9B, 0xE6, /* 0xBC-0xBF */ - 0xBD, 0xED, 0x9B, 0xE7, 0x9B, 0xE8, 0x9B, 0xE9, /* 0xC0-0xC3 */ - 0x9B, 0xEA, 0x9B, 0xEB, 0x9B, 0xEC, 0x9B, 0xED, /* 0xC4-0xC7 */ - 0x9B, 0xEE, 0x9B, 0xEF, 0x9B, 0xF0, 0x9B, 0xF1, /* 0xC8-0xCB */ - 0x9B, 0xF2, 0x9B, 0xF3, 0x9B, 0xF4, 0x9B, 0xF5, /* 0xCC-0xCF */ - 0x9B, 0xF6, 0x9B, 0xF7, 0x9B, 0xF8, 0x9B, 0xF9, /* 0xD0-0xD3 */ - 0x9B, 0xFA, 0x9B, 0xFB, 0x9B, 0xFC, 0x9B, 0xFD, /* 0xD4-0xD7 */ - 0xBD, 0xEE, 0xBD, 0xEF, 0x9B, 0xFE, 0x9C, 0x41, /* 0xD8-0xDB */ - 0xBD, 0xF0, 0x9C, 0x42, 0x9C, 0x43, 0xBD, 0xF1, /* 0xDC-0xDF */ - 0xBD, 0xF2, 0x9C, 0x44, 0xBD, 0xF3, 0x9C, 0x45, /* 0xE0-0xE3 */ - 0x9C, 0x46, 0x9C, 0x47, 0x9C, 0x48, 0x9C, 0x49, /* 0xE4-0xE7 */ - 0xBD, 0xF4, 0xBD, 0xF5, 0x9C, 0x4A, 0x9C, 0x4B, /* 0xE8-0xEB */ - 0x9C, 0x4C, 0xBD, 0xF6, 0x9C, 0x4D, 0x9C, 0x4E, /* 0xEC-0xEF */ - 0x9C, 0x4F, 0x9C, 0x50, 0x9C, 0x51, 0x9C, 0x52, /* 0xF0-0xF3 */ - 0xBD, 0xF7, 0xBD, 0xF8, 0x9C, 0x53, 0x9C, 0x54, /* 0xF4-0xF7 */ - 0xBD, 0xF9, 0x9C, 0x55, 0x9C, 0x56, 0x9C, 0x57, /* 0xF8-0xFB */ - 0x9C, 0x58, 0x9C, 0x59, 0x9C, 0x5A, 0x9C, 0x61, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_C4[512] = { - 0x9C, 0x62, 0x9C, 0x63, 0x9C, 0x64, 0x9C, 0x65, /* 0x00-0x03 */ - 0x9C, 0x66, 0x9C, 0x67, 0x9C, 0x68, 0x9C, 0x69, /* 0x04-0x07 */ - 0xBD, 0xFA, 0x9C, 0x6A, 0x9C, 0x6B, 0x9C, 0x6C, /* 0x08-0x0B */ - 0x9C, 0x6D, 0x9C, 0x6E, 0x9C, 0x6F, 0x9C, 0x70, /* 0x0C-0x0F */ - 0xBD, 0xFB, 0x9C, 0x71, 0x9C, 0x72, 0x9C, 0x73, /* 0x10-0x13 */ - 0x9C, 0x74, 0x9C, 0x75, 0x9C, 0x76, 0x9C, 0x77, /* 0x14-0x17 */ - 0x9C, 0x78, 0x9C, 0x79, 0x9C, 0x7A, 0x9C, 0x81, /* 0x18-0x1B */ - 0x9C, 0x82, 0x9C, 0x83, 0x9C, 0x84, 0x9C, 0x85, /* 0x1C-0x1F */ - 0x9C, 0x86, 0x9C, 0x87, 0x9C, 0x88, 0x9C, 0x89, /* 0x20-0x23 */ - 0xBD, 0xFC, 0x9C, 0x8A, 0x9C, 0x8B, 0x9C, 0x8C, /* 0x24-0x27 */ - 0x9C, 0x8D, 0x9C, 0x8E, 0x9C, 0x8F, 0x9C, 0x90, /* 0x28-0x2B */ - 0xBD, 0xFD, 0x9C, 0x91, 0x9C, 0x92, 0x9C, 0x93, /* 0x2C-0x2F */ - 0xBD, 0xFE, 0x9C, 0x94, 0x9C, 0x95, 0x9C, 0x96, /* 0x30-0x33 */ - 0xBE, 0xA1, 0x9C, 0x97, 0x9C, 0x98, 0x9C, 0x99, /* 0x34-0x37 */ - 0x9C, 0x9A, 0x9C, 0x9B, 0x9C, 0x9C, 0x9C, 0x9D, /* 0x38-0x3B */ - 0xBE, 0xA2, 0xBE, 0xA3, 0x9C, 0x9E, 0x9C, 0x9F, /* 0x3C-0x3F */ - 0x9C, 0xA0, 0x9C, 0xA1, 0x9C, 0xA2, 0x9C, 0xA3, /* 0x40-0x43 */ - 0x9C, 0xA4, 0x9C, 0xA5, 0x9C, 0xA6, 0x9C, 0xA7, /* 0x44-0x47 */ - 0xBE, 0xA4, 0x9C, 0xA8, 0x9C, 0xA9, 0x9C, 0xAA, /* 0x48-0x4B */ - 0x9C, 0xAB, 0x9C, 0xAC, 0x9C, 0xAD, 0x9C, 0xAE, /* 0x4C-0x4F */ - 0x9C, 0xAF, 0x9C, 0xB0, 0x9C, 0xB1, 0x9C, 0xB2, /* 0x50-0x53 */ - 0x9C, 0xB3, 0x9C, 0xB4, 0x9C, 0xB5, 0x9C, 0xB6, /* 0x54-0x57 */ - 0x9C, 0xB7, 0x9C, 0xB8, 0x9C, 0xB9, 0x9C, 0xBA, /* 0x58-0x5B */ - 0x9C, 0xBB, 0x9C, 0xBC, 0x9C, 0xBD, 0x9C, 0xBE, /* 0x5C-0x5F */ - 0x9C, 0xBF, 0x9C, 0xC0, 0x9C, 0xC1, 0x9C, 0xC2, /* 0x60-0x63 */ - 0xBE, 0xA5, 0xBE, 0xA6, 0x9C, 0xC3, 0x9C, 0xC4, /* 0x64-0x67 */ - 0xBE, 0xA7, 0x9C, 0xC5, 0x9C, 0xC6, 0x9C, 0xC7, /* 0x68-0x6B */ - 0xBE, 0xA8, 0x9C, 0xC8, 0x9C, 0xC9, 0x9C, 0xCA, /* 0x6C-0x6F */ - 0x9C, 0xCB, 0x9C, 0xCC, 0x9C, 0xCD, 0x9C, 0xCE, /* 0x70-0x73 */ - 0xBE, 0xA9, 0xBE, 0xAA, 0x9C, 0xCF, 0x9C, 0xD0, /* 0x74-0x77 */ - 0x9C, 0xD1, 0xBE, 0xAB, 0x9C, 0xD2, 0x9C, 0xD3, /* 0x78-0x7B */ - 0x9C, 0xD4, 0x9C, 0xD5, 0x9C, 0xD6, 0x9C, 0xD7, /* 0x7C-0x7F */ - - 0xBE, 0xAC, 0x9C, 0xD8, 0x9C, 0xD9, 0x9C, 0xDA, /* 0x80-0x83 */ - 0x9C, 0xDB, 0x9C, 0xDC, 0x9C, 0xDD, 0x9C, 0xDE, /* 0x84-0x87 */ - 0x9C, 0xDF, 0x9C, 0xE0, 0x9C, 0xE1, 0x9C, 0xE2, /* 0x88-0x8B */ - 0x9C, 0xE3, 0x9C, 0xE4, 0x9C, 0xE5, 0x9C, 0xE6, /* 0x8C-0x8F */ - 0x9C, 0xE7, 0x9C, 0xE8, 0x9C, 0xE9, 0x9C, 0xEA, /* 0x90-0x93 */ - 0xBE, 0xAD, 0x9C, 0xEB, 0x9C, 0xEC, 0x9C, 0xED, /* 0x94-0x97 */ - 0x9C, 0xEE, 0x9C, 0xEF, 0x9C, 0xF0, 0x9C, 0xF1, /* 0x98-0x9B */ - 0xBE, 0xAE, 0x9C, 0xF2, 0x9C, 0xF3, 0x9C, 0xF4, /* 0x9C-0x9F */ - 0x9C, 0xF5, 0x9C, 0xF6, 0x9C, 0xF7, 0x9C, 0xF8, /* 0xA0-0xA3 */ - 0x9C, 0xF9, 0x9C, 0xFA, 0x9C, 0xFB, 0x9C, 0xFC, /* 0xA4-0xA7 */ - 0x9C, 0xFD, 0x9C, 0xFE, 0x9D, 0x41, 0x9D, 0x42, /* 0xA8-0xAB */ - 0x9D, 0x43, 0x9D, 0x44, 0x9D, 0x45, 0x9D, 0x46, /* 0xAC-0xAF */ - 0x9D, 0x47, 0x9D, 0x48, 0x9D, 0x49, 0x9D, 0x4A, /* 0xB0-0xB3 */ - 0x9D, 0x4B, 0x9D, 0x4C, 0x9D, 0x4D, 0x9D, 0x4E, /* 0xB4-0xB7 */ - 0xBE, 0xAF, 0x9D, 0x4F, 0x9D, 0x50, 0x9D, 0x51, /* 0xB8-0xBB */ - 0xBE, 0xB0, 0x9D, 0x52, 0x9D, 0x53, 0x9D, 0x54, /* 0xBC-0xBF */ - 0x9D, 0x55, 0x9D, 0x56, 0x9D, 0x57, 0x9D, 0x58, /* 0xC0-0xC3 */ - 0x9D, 0x59, 0x9D, 0x5A, 0x9D, 0x61, 0x9D, 0x62, /* 0xC4-0xC7 */ - 0x9D, 0x63, 0x9D, 0x64, 0x9D, 0x65, 0x9D, 0x66, /* 0xC8-0xCB */ - 0x9D, 0x67, 0x9D, 0x68, 0x9D, 0x69, 0x9D, 0x6A, /* 0xCC-0xCF */ - 0x9D, 0x6B, 0x9D, 0x6C, 0x9D, 0x6D, 0x9D, 0x6E, /* 0xD0-0xD3 */ - 0x9D, 0x6F, 0x9D, 0x70, 0x9D, 0x71, 0x9D, 0x72, /* 0xD4-0xD7 */ - 0x9D, 0x73, 0x9D, 0x74, 0x9D, 0x75, 0x9D, 0x76, /* 0xD8-0xDB */ - 0x9D, 0x77, 0x9D, 0x78, 0x9D, 0x79, 0x9D, 0x7A, /* 0xDC-0xDF */ - 0x9D, 0x81, 0x9D, 0x82, 0x9D, 0x83, 0x9D, 0x84, /* 0xE0-0xE3 */ - 0x9D, 0x85, 0x9D, 0x86, 0x9D, 0x87, 0x9D, 0x88, /* 0xE4-0xE7 */ - 0x9D, 0x89, 0xBE, 0xB1, 0x9D, 0x8A, 0x9D, 0x8B, /* 0xE8-0xEB */ - 0x9D, 0x8C, 0x9D, 0x8D, 0x9D, 0x8E, 0x9D, 0x8F, /* 0xEC-0xEF */ - 0xBE, 0xB2, 0xBE, 0xB3, 0x9D, 0x90, 0x9D, 0x91, /* 0xF0-0xF3 */ - 0xBE, 0xB4, 0x9D, 0x92, 0x9D, 0x93, 0x9D, 0x94, /* 0xF4-0xF7 */ - 0xBE, 0xB5, 0x9D, 0x95, 0xBE, 0xB6, 0x9D, 0x96, /* 0xF8-0xFB */ - 0x9D, 0x97, 0x9D, 0x98, 0x9D, 0x99, 0xBE, 0xB7, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_C5[512] = { - 0xBE, 0xB8, 0xBE, 0xB9, 0x9D, 0x9A, 0x9D, 0x9B, /* 0x00-0x03 */ - 0x9D, 0x9C, 0x9D, 0x9D, 0x9D, 0x9E, 0x9D, 0x9F, /* 0x04-0x07 */ - 0x9D, 0xA0, 0x9D, 0xA1, 0x9D, 0xA2, 0x9D, 0xA3, /* 0x08-0x0B */ - 0xBE, 0xBA, 0x9D, 0xA4, 0x9D, 0xA5, 0x9D, 0xA6, /* 0x0C-0x0F */ - 0xBE, 0xBB, 0x9D, 0xA7, 0x9D, 0xA8, 0x9D, 0xA9, /* 0x10-0x13 */ - 0xBE, 0xBC, 0x9D, 0xAA, 0x9D, 0xAB, 0x9D, 0xAC, /* 0x14-0x17 */ - 0x9D, 0xAD, 0x9D, 0xAE, 0x9D, 0xAF, 0x9D, 0xB0, /* 0x18-0x1B */ - 0xBE, 0xBD, 0x9D, 0xB1, 0x9D, 0xB2, 0x9D, 0xB3, /* 0x1C-0x1F */ - 0x9D, 0xB4, 0x9D, 0xB5, 0x9D, 0xB6, 0x9D, 0xB7, /* 0x20-0x23 */ - 0x9D, 0xB8, 0x9D, 0xB9, 0x9D, 0xBA, 0x9D, 0xBB, /* 0x24-0x27 */ - 0xBE, 0xBE, 0xBE, 0xBF, 0x9D, 0xBC, 0x9D, 0xBD, /* 0x28-0x2B */ - 0xBE, 0xC0, 0x9D, 0xBE, 0x9D, 0xBF, 0x9D, 0xC0, /* 0x2C-0x2F */ - 0xBE, 0xC1, 0x9D, 0xC1, 0x9D, 0xC2, 0x9D, 0xC3, /* 0x30-0x33 */ - 0x9D, 0xC4, 0x9D, 0xC5, 0x9D, 0xC6, 0x9D, 0xC7, /* 0x34-0x37 */ - 0xBE, 0xC2, 0xBE, 0xC3, 0x9D, 0xC8, 0xBE, 0xC4, /* 0x38-0x3B */ - 0x9D, 0xC9, 0xBE, 0xC5, 0x9D, 0xCA, 0x9D, 0xCB, /* 0x3C-0x3F */ - 0x9D, 0xCC, 0x9D, 0xCD, 0x9D, 0xCE, 0x9D, 0xCF, /* 0x40-0x43 */ - 0xBE, 0xC6, 0xBE, 0xC7, 0x9D, 0xD0, 0x9D, 0xD1, /* 0x44-0x47 */ - 0xBE, 0xC8, 0xBE, 0xC9, 0xBE, 0xCA, 0x9D, 0xD2, /* 0x48-0x4B */ - 0xBE, 0xCB, 0xBE, 0xCC, 0xBE, 0xCD, 0x9D, 0xD3, /* 0x4C-0x4F */ - 0x9D, 0xD4, 0x9D, 0xD5, 0x9D, 0xD6, 0xBE, 0xCE, /* 0x50-0x53 */ - 0xBE, 0xCF, 0xBE, 0xD0, 0x9D, 0xD7, 0xBE, 0xD1, /* 0x54-0x57 */ - 0xBE, 0xD2, 0xBE, 0xD3, 0x9D, 0xD8, 0x9D, 0xD9, /* 0x58-0x5B */ - 0x9D, 0xDA, 0xBE, 0xD4, 0xBE, 0xD5, 0x9D, 0xDB, /* 0x5C-0x5F */ - 0xBE, 0xD6, 0xBE, 0xD7, 0x9D, 0xDC, 0x9D, 0xDD, /* 0x60-0x63 */ - 0xBE, 0xD8, 0x9D, 0xDE, 0x9D, 0xDF, 0x9D, 0xE0, /* 0x64-0x67 */ - 0xBE, 0xD9, 0x9D, 0xE1, 0x9D, 0xE2, 0x9D, 0xE3, /* 0x68-0x6B */ - 0x9D, 0xE4, 0x9D, 0xE5, 0x9D, 0xE6, 0x9D, 0xE7, /* 0x6C-0x6F */ - 0xBE, 0xDA, 0xBE, 0xDB, 0x9D, 0xE8, 0xBE, 0xDC, /* 0x70-0x73 */ - 0xBE, 0xDD, 0xBE, 0xDE, 0x9D, 0xE9, 0x9D, 0xEA, /* 0x74-0x77 */ - 0x9D, 0xEB, 0x9D, 0xEC, 0x9D, 0xED, 0x9D, 0xEE, /* 0x78-0x7B */ - 0xBE, 0xDF, 0xBE, 0xE0, 0x9D, 0xEF, 0x9D, 0xF0, /* 0x7C-0x7F */ - - 0xBE, 0xE1, 0x9D, 0xF1, 0x9D, 0xF2, 0x9D, 0xF3, /* 0x80-0x83 */ - 0xBE, 0xE2, 0x9D, 0xF4, 0x9D, 0xF5, 0xBE, 0xE3, /* 0x84-0x87 */ - 0x9D, 0xF6, 0x9D, 0xF7, 0x9D, 0xF8, 0x9D, 0xF9, /* 0x88-0x8B */ - 0xBE, 0xE4, 0xBE, 0xE5, 0x9D, 0xFA, 0xBE, 0xE6, /* 0x8C-0x8F */ - 0x9D, 0xFB, 0xBE, 0xE7, 0x9D, 0xFC, 0x9D, 0xFD, /* 0x90-0x93 */ - 0x9D, 0xFE, 0xBE, 0xE8, 0x9E, 0x41, 0xBE, 0xE9, /* 0x94-0x97 */ - 0xBE, 0xEA, 0x9E, 0x42, 0x9E, 0x43, 0x9E, 0x44, /* 0x98-0x9B */ - 0xBE, 0xEB, 0x9E, 0x45, 0x9E, 0x46, 0x9E, 0x47, /* 0x9C-0x9F */ - 0xBE, 0xEC, 0x9E, 0x48, 0x9E, 0x49, 0x9E, 0x4A, /* 0xA0-0xA3 */ - 0x9E, 0x4B, 0x9E, 0x4C, 0x9E, 0x4D, 0x9E, 0x4E, /* 0xA4-0xA7 */ - 0x9E, 0x4F, 0xBE, 0xED, 0x9E, 0x50, 0x9E, 0x51, /* 0xA8-0xAB */ - 0x9E, 0x52, 0x9E, 0x53, 0x9E, 0x54, 0x9E, 0x55, /* 0xAC-0xAF */ - 0x9E, 0x56, 0x9E, 0x57, 0x9E, 0x58, 0x9E, 0x59, /* 0xB0-0xB3 */ - 0xBE, 0xEE, 0xBE, 0xEF, 0x9E, 0x5A, 0x9E, 0x61, /* 0xB4-0xB7 */ - 0xBE, 0xF0, 0xBE, 0xF1, 0x9E, 0x62, 0xBE, 0xF2, /* 0xB8-0xBB */ - 0xBE, 0xF3, 0xBE, 0xF4, 0xBE, 0xF5, 0x9E, 0x63, /* 0xBC-0xBF */ - 0x9E, 0x64, 0x9E, 0x65, 0x9E, 0x66, 0x9E, 0x67, /* 0xC0-0xC3 */ - 0xBE, 0xF6, 0xBE, 0xF7, 0xBE, 0xF8, 0xBE, 0xF9, /* 0xC4-0xC7 */ - 0xBE, 0xFA, 0xBE, 0xFB, 0xBE, 0xFC, 0x9E, 0x68, /* 0xC8-0xCB */ - 0xBE, 0xFD, 0x9E, 0x69, 0xBE, 0xFE, 0x9E, 0x6A, /* 0xCC-0xCF */ - 0xBF, 0xA1, 0xBF, 0xA2, 0x9E, 0x6B, 0x9E, 0x6C, /* 0xD0-0xD3 */ - 0xBF, 0xA3, 0x9E, 0x6D, 0x9E, 0x6E, 0x9E, 0x6F, /* 0xD4-0xD7 */ - 0xBF, 0xA4, 0x9E, 0x70, 0x9E, 0x71, 0x9E, 0x72, /* 0xD8-0xDB */ - 0x9E, 0x73, 0x9E, 0x74, 0x9E, 0x75, 0x9E, 0x76, /* 0xDC-0xDF */ - 0xBF, 0xA5, 0xBF, 0xA6, 0x9E, 0x77, 0xBF, 0xA7, /* 0xE0-0xE3 */ - 0x9E, 0x78, 0xBF, 0xA8, 0x9E, 0x79, 0x9E, 0x7A, /* 0xE4-0xE7 */ - 0x9E, 0x81, 0x9E, 0x82, 0x9E, 0x83, 0x9E, 0x84, /* 0xE8-0xEB */ - 0xBF, 0xA9, 0xBF, 0xAA, 0xBF, 0xAB, 0x9E, 0x85, /* 0xEC-0xEF */ - 0xBF, 0xAC, 0x9E, 0x86, 0x9E, 0x87, 0x9E, 0x88, /* 0xF0-0xF3 */ - 0xBF, 0xAD, 0x9E, 0x89, 0xBF, 0xAE, 0xBF, 0xAF, /* 0xF4-0xF7 */ - 0x9E, 0x8A, 0x9E, 0x8B, 0x9E, 0x8C, 0x9E, 0x8D, /* 0xF8-0xFB */ - 0xBF, 0xB0, 0xBF, 0xB1, 0xBF, 0xB2, 0xBF, 0xB3, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_C6[512] = { - 0xBF, 0xB4, 0xBF, 0xB5, 0x9E, 0x8E, 0x9E, 0x8F, /* 0x00-0x03 */ - 0x9E, 0x90, 0xBF, 0xB6, 0xBF, 0xB7, 0xBF, 0xB8, /* 0x04-0x07 */ - 0xBF, 0xB9, 0x9E, 0x91, 0x9E, 0x92, 0x9E, 0x93, /* 0x08-0x0B */ - 0xBF, 0xBA, 0x9E, 0x94, 0x9E, 0x95, 0x9E, 0x96, /* 0x0C-0x0F */ - 0xBF, 0xBB, 0x9E, 0x97, 0x9E, 0x98, 0x9E, 0x99, /* 0x10-0x13 */ - 0x9E, 0x9A, 0x9E, 0x9B, 0x9E, 0x9C, 0x9E, 0x9D, /* 0x14-0x17 */ - 0xBF, 0xBC, 0xBF, 0xBD, 0x9E, 0x9E, 0xBF, 0xBE, /* 0x18-0x1B */ - 0xBF, 0xBF, 0x9E, 0x9F, 0x9E, 0xA0, 0x9E, 0xA1, /* 0x1C-0x1F */ - 0x9E, 0xA2, 0x9E, 0xA3, 0x9E, 0xA4, 0x9E, 0xA5, /* 0x20-0x23 */ - 0xBF, 0xC0, 0xBF, 0xC1, 0x9E, 0xA6, 0x9E, 0xA7, /* 0x24-0x27 */ - 0xBF, 0xC2, 0x9E, 0xA8, 0x9E, 0xA9, 0x9E, 0xAA, /* 0x28-0x2B */ - 0xBF, 0xC3, 0xBF, 0xC4, 0xBF, 0xC5, 0x9E, 0xAB, /* 0x2C-0x2F */ - 0xBF, 0xC6, 0x9E, 0xAC, 0x9E, 0xAD, 0xBF, 0xC7, /* 0x30-0x33 */ - 0xBF, 0xC8, 0xBF, 0xC9, 0x9E, 0xAE, 0xBF, 0xCA, /* 0x34-0x37 */ - 0x9E, 0xAF, 0xBF, 0xCB, 0x9E, 0xB0, 0xBF, 0xCC, /* 0x38-0x3B */ - 0x9E, 0xB1, 0x9E, 0xB2, 0x9E, 0xB3, 0x9E, 0xB4, /* 0x3C-0x3F */ - 0xBF, 0xCD, 0xBF, 0xCE, 0x9E, 0xB5, 0x9E, 0xB6, /* 0x40-0x43 */ - 0xBF, 0xCF, 0x9E, 0xB7, 0x9E, 0xB8, 0x9E, 0xB9, /* 0x44-0x47 */ - 0xBF, 0xD0, 0x9E, 0xBA, 0x9E, 0xBB, 0x9E, 0xBC, /* 0x48-0x4B */ - 0x9E, 0xBD, 0x9E, 0xBE, 0x9E, 0xBF, 0x9E, 0xC0, /* 0x4C-0x4F */ - 0xBF, 0xD1, 0xBF, 0xD2, 0x9E, 0xC1, 0xBF, 0xD3, /* 0x50-0x53 */ - 0xBF, 0xD4, 0xBF, 0xD5, 0x9E, 0xC2, 0x9E, 0xC3, /* 0x54-0x57 */ - 0x9E, 0xC4, 0x9E, 0xC5, 0x9E, 0xC6, 0x9E, 0xC7, /* 0x58-0x5B */ - 0xBF, 0xD6, 0xBF, 0xD7, 0x9E, 0xC8, 0x9E, 0xC9, /* 0x5C-0x5F */ - 0xBF, 0xD8, 0x9E, 0xCA, 0x9E, 0xCB, 0x9E, 0xCC, /* 0x60-0x63 */ - 0x9E, 0xCD, 0x9E, 0xCE, 0x9E, 0xCF, 0x9E, 0xD0, /* 0x64-0x67 */ - 0x9E, 0xD1, 0x9E, 0xD2, 0x9E, 0xD3, 0x9E, 0xD4, /* 0x68-0x6B */ - 0xBF, 0xD9, 0x9E, 0xD5, 0x9E, 0xD6, 0xBF, 0xDA, /* 0x6C-0x6F */ - 0x9E, 0xD7, 0xBF, 0xDB, 0x9E, 0xD8, 0x9E, 0xD9, /* 0x70-0x73 */ - 0x9E, 0xDA, 0x9E, 0xDB, 0x9E, 0xDC, 0x9E, 0xDD, /* 0x74-0x77 */ - 0xBF, 0xDC, 0xBF, 0xDD, 0x9E, 0xDE, 0x9E, 0xDF, /* 0x78-0x7B */ - 0xBF, 0xDE, 0x9E, 0xE0, 0x9E, 0xE1, 0x9E, 0xE2, /* 0x7C-0x7F */ - - 0xBF, 0xDF, 0x9E, 0xE3, 0x9E, 0xE4, 0x9E, 0xE5, /* 0x80-0x83 */ - 0x9E, 0xE6, 0x9E, 0xE7, 0x9E, 0xE8, 0x9E, 0xE9, /* 0x84-0x87 */ - 0xBF, 0xE0, 0xBF, 0xE1, 0x9E, 0xEA, 0xBF, 0xE2, /* 0x88-0x8B */ - 0x9E, 0xEB, 0xBF, 0xE3, 0x9E, 0xEC, 0x9E, 0xED, /* 0x8C-0x8F */ - 0x9E, 0xEE, 0x9E, 0xEF, 0x9E, 0xF0, 0x9E, 0xF1, /* 0x90-0x93 */ - 0xBF, 0xE4, 0xBF, 0xE5, 0x9E, 0xF2, 0x9E, 0xF3, /* 0x94-0x97 */ - 0xBF, 0xE6, 0x9E, 0xF4, 0x9E, 0xF5, 0x9E, 0xF6, /* 0x98-0x9B */ - 0xBF, 0xE7, 0x9E, 0xF7, 0x9E, 0xF8, 0x9E, 0xF9, /* 0x9C-0x9F */ - 0x9E, 0xFA, 0x9E, 0xFB, 0x9E, 0xFC, 0x9E, 0xFD, /* 0xA0-0xA3 */ - 0xBF, 0xE8, 0xBF, 0xE9, 0x9E, 0xFE, 0xBF, 0xEA, /* 0xA4-0xA7 */ - 0x9F, 0x41, 0xBF, 0xEB, 0x9F, 0x42, 0x9F, 0x43, /* 0xA8-0xAB */ - 0x9F, 0x44, 0x9F, 0x45, 0x9F, 0x46, 0x9F, 0x47, /* 0xAC-0xAF */ - 0xBF, 0xEC, 0xBF, 0xED, 0x9F, 0x48, 0x9F, 0x49, /* 0xB0-0xB3 */ - 0xBF, 0xEE, 0x9F, 0x4A, 0x9F, 0x4B, 0x9F, 0x4C, /* 0xB4-0xB7 */ - 0xBF, 0xEF, 0xBF, 0xF0, 0xBF, 0xF1, 0x9F, 0x4D, /* 0xB8-0xBB */ - 0x9F, 0x4E, 0x9F, 0x4F, 0x9F, 0x50, 0x9F, 0x51, /* 0xBC-0xBF */ - 0xBF, 0xF2, 0xBF, 0xF3, 0x9F, 0x52, 0xBF, 0xF4, /* 0xC0-0xC3 */ - 0x9F, 0x53, 0xBF, 0xF5, 0x9F, 0x54, 0x9F, 0x55, /* 0xC4-0xC7 */ - 0x9F, 0x56, 0x9F, 0x57, 0x9F, 0x58, 0x9F, 0x59, /* 0xC8-0xCB */ - 0xBF, 0xF6, 0xBF, 0xF7, 0x9F, 0x5A, 0x9F, 0x61, /* 0xCC-0xCF */ - 0xBF, 0xF8, 0x9F, 0x62, 0x9F, 0x63, 0x9F, 0x64, /* 0xD0-0xD3 */ - 0xBF, 0xF9, 0x9F, 0x65, 0x9F, 0x66, 0x9F, 0x67, /* 0xD4-0xD7 */ - 0x9F, 0x68, 0x9F, 0x69, 0x9F, 0x6A, 0x9F, 0x6B, /* 0xD8-0xDB */ - 0xBF, 0xFA, 0xBF, 0xFB, 0x9F, 0x6C, 0x9F, 0x6D, /* 0xDC-0xDF */ - 0xBF, 0xFC, 0xBF, 0xFD, 0x9F, 0x6E, 0x9F, 0x6F, /* 0xE0-0xE3 */ - 0x9F, 0x70, 0x9F, 0x71, 0x9F, 0x72, 0x9F, 0x73, /* 0xE4-0xE7 */ - 0xBF, 0xFE, 0xC0, 0xA1, 0x9F, 0x74, 0x9F, 0x75, /* 0xE8-0xEB */ - 0xC0, 0xA2, 0x9F, 0x76, 0x9F, 0x77, 0x9F, 0x78, /* 0xEC-0xEF */ - 0xC0, 0xA3, 0x9F, 0x79, 0x9F, 0x7A, 0x9F, 0x81, /* 0xF0-0xF3 */ - 0x9F, 0x82, 0x9F, 0x83, 0x9F, 0x84, 0x9F, 0x85, /* 0xF4-0xF7 */ - 0xC0, 0xA4, 0xC0, 0xA5, 0x9F, 0x86, 0x9F, 0x87, /* 0xF8-0xFB */ - 0x9F, 0x88, 0xC0, 0xA6, 0x9F, 0x89, 0x9F, 0x8A, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_C7[512] = { - 0x9F, 0x8B, 0x9F, 0x8C, 0x9F, 0x8D, 0x9F, 0x8E, /* 0x00-0x03 */ - 0xC0, 0xA7, 0xC0, 0xA8, 0x9F, 0x8F, 0x9F, 0x90, /* 0x04-0x07 */ - 0xC0, 0xA9, 0x9F, 0x91, 0x9F, 0x92, 0x9F, 0x93, /* 0x08-0x0B */ - 0xC0, 0xAA, 0x9F, 0x94, 0x9F, 0x95, 0x9F, 0x96, /* 0x0C-0x0F */ - 0x9F, 0x97, 0x9F, 0x98, 0x9F, 0x99, 0x9F, 0x9A, /* 0x10-0x13 */ - 0xC0, 0xAB, 0xC0, 0xAC, 0x9F, 0x9B, 0xC0, 0xAD, /* 0x14-0x17 */ - 0x9F, 0x9C, 0xC0, 0xAE, 0x9F, 0x9D, 0x9F, 0x9E, /* 0x18-0x1B */ - 0x9F, 0x9F, 0x9F, 0xA0, 0x9F, 0xA1, 0x9F, 0xA2, /* 0x1C-0x1F */ - 0xC0, 0xAF, 0xC0, 0xB0, 0x9F, 0xA3, 0x9F, 0xA4, /* 0x20-0x23 */ - 0xC0, 0xB1, 0x9F, 0xA5, 0x9F, 0xA6, 0x9F, 0xA7, /* 0x24-0x27 */ - 0xC0, 0xB2, 0x9F, 0xA8, 0x9F, 0xA9, 0x9F, 0xAA, /* 0x28-0x2B */ - 0x9F, 0xAB, 0x9F, 0xAC, 0x9F, 0xAD, 0x9F, 0xAE, /* 0x2C-0x2F */ - 0xC0, 0xB3, 0xC0, 0xB4, 0x9F, 0xAF, 0xC0, 0xB5, /* 0x30-0x33 */ - 0x9F, 0xB0, 0xC0, 0xB6, 0x9F, 0xB1, 0xC0, 0xB7, /* 0x34-0x37 */ - 0x9F, 0xB2, 0x9F, 0xB3, 0x9F, 0xB4, 0x9F, 0xB5, /* 0x38-0x3B */ - 0xC0, 0xB8, 0xC0, 0xB9, 0x9F, 0xB6, 0x9F, 0xB7, /* 0x3C-0x3F */ - 0xC0, 0xBA, 0x9F, 0xB8, 0x9F, 0xB9, 0x9F, 0xBA, /* 0x40-0x43 */ - 0xC0, 0xBB, 0x9F, 0xBB, 0x9F, 0xBC, 0x9F, 0xBD, /* 0x44-0x47 */ - 0x9F, 0xBE, 0x9F, 0xBF, 0xC0, 0xBC, 0x9F, 0xC0, /* 0x48-0x4B */ - 0xC0, 0xBD, 0xC0, 0xBE, 0x9F, 0xC1, 0xC0, 0xBF, /* 0x4C-0x4F */ - 0x9F, 0xC2, 0xC0, 0xC0, 0xC0, 0xC1, 0xC0, 0xC2, /* 0x50-0x53 */ - 0xC0, 0xC3, 0xC0, 0xC4, 0xC0, 0xC5, 0xC0, 0xC6, /* 0x54-0x57 */ - 0xC0, 0xC7, 0x9F, 0xC3, 0x9F, 0xC4, 0x9F, 0xC5, /* 0x58-0x5B */ - 0xC0, 0xC8, 0x9F, 0xC6, 0x9F, 0xC7, 0x9F, 0xC8, /* 0x5C-0x5F */ - 0xC0, 0xC9, 0x9F, 0xC9, 0x9F, 0xCA, 0x9F, 0xCB, /* 0x60-0x63 */ - 0x9F, 0xCC, 0x9F, 0xCD, 0x9F, 0xCE, 0x9F, 0xCF, /* 0x64-0x67 */ - 0xC0, 0xCA, 0x9F, 0xD0, 0x9F, 0xD1, 0xC0, 0xCB, /* 0x68-0x6B */ - 0x9F, 0xD2, 0x9F, 0xD3, 0x9F, 0xD4, 0x9F, 0xD5, /* 0x6C-0x6F */ - 0x9F, 0xD6, 0x9F, 0xD7, 0x9F, 0xD8, 0x9F, 0xD9, /* 0x70-0x73 */ - 0xC0, 0xCC, 0xC0, 0xCD, 0x9F, 0xDA, 0x9F, 0xDB, /* 0x74-0x77 */ - 0xC0, 0xCE, 0x9F, 0xDC, 0x9F, 0xDD, 0x9F, 0xDE, /* 0x78-0x7B */ - 0xC0, 0xCF, 0xC0, 0xD0, 0xC0, 0xD1, 0x9F, 0xDF, /* 0x7C-0x7F */ - - 0x9F, 0xE0, 0x9F, 0xE1, 0x9F, 0xE2, 0xC0, 0xD2, /* 0x80-0x83 */ - 0xC0, 0xD3, 0xC0, 0xD4, 0x9F, 0xE3, 0xC0, 0xD5, /* 0x84-0x87 */ - 0xC0, 0xD6, 0xC0, 0xD7, 0xC0, 0xD8, 0x9F, 0xE4, /* 0x88-0x8B */ - 0x9F, 0xE5, 0x9F, 0xE6, 0xC0, 0xD9, 0x9F, 0xE7, /* 0x8C-0x8F */ - 0xC0, 0xDA, 0xC0, 0xDB, 0x9F, 0xE8, 0x9F, 0xE9, /* 0x90-0x93 */ - 0xC0, 0xDC, 0x9F, 0xEA, 0xC0, 0xDD, 0xC0, 0xDE, /* 0x94-0x97 */ - 0xC0, 0xDF, 0x9F, 0xEB, 0xC0, 0xE0, 0x9F, 0xEC, /* 0x98-0x9B */ - 0x9F, 0xED, 0x9F, 0xEE, 0x9F, 0xEF, 0x9F, 0xF0, /* 0x9C-0x9F */ - 0xC0, 0xE1, 0xC0, 0xE2, 0x9F, 0xF1, 0xC0, 0xE3, /* 0xA0-0xA3 */ - 0xC0, 0xE4, 0xC0, 0xE5, 0xC0, 0xE6, 0x9F, 0xF2, /* 0xA4-0xA7 */ - 0x9F, 0xF3, 0x9F, 0xF4, 0x9F, 0xF5, 0x9F, 0xF6, /* 0xA8-0xAB */ - 0xC0, 0xE7, 0xC0, 0xE8, 0x9F, 0xF7, 0x9F, 0xF8, /* 0xAC-0xAF */ - 0xC0, 0xE9, 0x9F, 0xF9, 0x9F, 0xFA, 0x9F, 0xFB, /* 0xB0-0xB3 */ - 0xC0, 0xEA, 0x9F, 0xFC, 0x9F, 0xFD, 0x9F, 0xFE, /* 0xB4-0xB7 */ - 0xA0, 0x41, 0xA0, 0x42, 0xA0, 0x43, 0xA0, 0x44, /* 0xB8-0xBB */ - 0xC0, 0xEB, 0xC0, 0xEC, 0xA0, 0x45, 0xC0, 0xED, /* 0xBC-0xBF */ - 0xC0, 0xEE, 0xC0, 0xEF, 0xA0, 0x46, 0xA0, 0x47, /* 0xC0-0xC3 */ - 0xA0, 0x48, 0xA0, 0x49, 0xA0, 0x4A, 0xA0, 0x4B, /* 0xC4-0xC7 */ - 0xC0, 0xF0, 0xC0, 0xF1, 0xA0, 0x4C, 0xA0, 0x4D, /* 0xC8-0xCB */ - 0xC0, 0xF2, 0xA0, 0x4E, 0xC0, 0xF3, 0xA0, 0x4F, /* 0xCC-0xCF */ - 0xC0, 0xF4, 0xA0, 0x50, 0xA0, 0x51, 0xA0, 0x52, /* 0xD0-0xD3 */ - 0xA0, 0x53, 0xA0, 0x54, 0xA0, 0x55, 0xA0, 0x56, /* 0xD4-0xD7 */ - 0xC0, 0xF5, 0xA0, 0x57, 0xA0, 0x58, 0xA0, 0x59, /* 0xD8-0xDB */ - 0xA0, 0x5A, 0xC0, 0xF6, 0xA0, 0x61, 0xA0, 0x62, /* 0xDC-0xDF */ - 0xA0, 0x63, 0xA0, 0x64, 0xA0, 0x65, 0xA0, 0x66, /* 0xE0-0xE3 */ - 0xC0, 0xF7, 0xA0, 0x67, 0xA0, 0x68, 0xA0, 0x69, /* 0xE4-0xE7 */ - 0xC0, 0xF8, 0xA0, 0x6A, 0xA0, 0x6B, 0xA0, 0x6C, /* 0xE8-0xEB */ - 0xC0, 0xF9, 0xA0, 0x6D, 0xA0, 0x6E, 0xA0, 0x6F, /* 0xEC-0xEF */ - 0xA0, 0x70, 0xA0, 0x71, 0xA0, 0x72, 0xA0, 0x73, /* 0xF0-0xF3 */ - 0xA0, 0x74, 0xA0, 0x75, 0xA0, 0x76, 0xA0, 0x77, /* 0xF4-0xF7 */ - 0xA0, 0x78, 0xA0, 0x79, 0xA0, 0x7A, 0xA0, 0x81, /* 0xF8-0xFB */ - 0xA0, 0x82, 0xA0, 0x83, 0xA0, 0x84, 0xA0, 0x85, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_C8[512] = { - 0xC0, 0xFA, 0xC0, 0xFB, 0xA0, 0x86, 0xA0, 0x87, /* 0x00-0x03 */ - 0xC0, 0xFC, 0xA0, 0x88, 0xA0, 0x89, 0xA0, 0x8A, /* 0x04-0x07 */ - 0xC0, 0xFD, 0xA0, 0x8B, 0xC0, 0xFE, 0xA0, 0x8C, /* 0x08-0x0B */ - 0xA0, 0x8D, 0xA0, 0x8E, 0xA0, 0x8F, 0xA0, 0x90, /* 0x0C-0x0F */ - 0xC1, 0xA1, 0xC1, 0xA2, 0xA0, 0x91, 0xC1, 0xA3, /* 0x10-0x13 */ - 0xA0, 0x92, 0xC1, 0xA4, 0xC1, 0xA5, 0xA0, 0x93, /* 0x14-0x17 */ - 0xA0, 0x94, 0xA0, 0x95, 0xA0, 0x96, 0xA0, 0x97, /* 0x18-0x1B */ - 0xC1, 0xA6, 0xC1, 0xA7, 0xA0, 0x98, 0xA0, 0x99, /* 0x1C-0x1F */ - 0xC1, 0xA8, 0xA0, 0x9A, 0xA0, 0x9B, 0xA0, 0x9C, /* 0x20-0x23 */ - 0xC1, 0xA9, 0xA0, 0x9D, 0xA0, 0x9E, 0xA0, 0x9F, /* 0x24-0x27 */ - 0xA0, 0xA0, 0xA0, 0xA1, 0xA0, 0xA2, 0xA0, 0xA3, /* 0x28-0x2B */ - 0xC1, 0xAA, 0xC1, 0xAB, 0xA0, 0xA4, 0xC1, 0xAC, /* 0x2C-0x2F */ - 0xA0, 0xA5, 0xC1, 0xAD, 0xA0, 0xA6, 0xA0, 0xA7, /* 0x30-0x33 */ - 0xA0, 0xA8, 0xA0, 0xA9, 0xA0, 0xAA, 0xA0, 0xAB, /* 0x34-0x37 */ - 0xC1, 0xAE, 0xA0, 0xAC, 0xA0, 0xAD, 0xA0, 0xAE, /* 0x38-0x3B */ - 0xC1, 0xAF, 0xA0, 0xAF, 0xA0, 0xB0, 0xA0, 0xB1, /* 0x3C-0x3F */ - 0xC1, 0xB0, 0xA0, 0xB2, 0xA0, 0xB3, 0xA0, 0xB4, /* 0x40-0x43 */ - 0xA0, 0xB5, 0xA0, 0xB6, 0xA0, 0xB7, 0xA0, 0xB8, /* 0x44-0x47 */ - 0xC1, 0xB1, 0xC1, 0xB2, 0xA0, 0xB9, 0xA0, 0xBA, /* 0x48-0x4B */ - 0xC1, 0xB3, 0xC1, 0xB4, 0xA0, 0xBB, 0xA0, 0xBC, /* 0x4C-0x4F */ - 0xA0, 0xBD, 0xA0, 0xBE, 0xA0, 0xBF, 0xA0, 0xC0, /* 0x50-0x53 */ - 0xC1, 0xB5, 0xA0, 0xC1, 0xA0, 0xC2, 0xA0, 0xC3, /* 0x54-0x57 */ - 0xA0, 0xC4, 0xA0, 0xC5, 0xA0, 0xC6, 0xA0, 0xC7, /* 0x58-0x5B */ - 0xA0, 0xC8, 0xA0, 0xC9, 0xA0, 0xCA, 0xA0, 0xCB, /* 0x5C-0x5F */ - 0xA0, 0xCC, 0xA0, 0xCD, 0xA0, 0xCE, 0xA0, 0xCF, /* 0x60-0x63 */ - 0xA0, 0xD0, 0xA0, 0xD1, 0xA0, 0xD2, 0xA0, 0xD3, /* 0x64-0x67 */ - 0xA0, 0xD4, 0xA0, 0xD5, 0xA0, 0xD6, 0xA0, 0xD7, /* 0x68-0x6B */ - 0xA0, 0xD8, 0xA0, 0xD9, 0xA0, 0xDA, 0xA0, 0xDB, /* 0x6C-0x6F */ - 0xC1, 0xB6, 0xC1, 0xB7, 0xA0, 0xDC, 0xA0, 0xDD, /* 0x70-0x73 */ - 0xC1, 0xB8, 0xA0, 0xDE, 0xA0, 0xDF, 0xA0, 0xE0, /* 0x74-0x77 */ - 0xC1, 0xB9, 0xA0, 0xE1, 0xC1, 0xBA, 0xA0, 0xE2, /* 0x78-0x7B */ - 0xA0, 0xE3, 0xA0, 0xE4, 0xA0, 0xE5, 0xA0, 0xE6, /* 0x7C-0x7F */ - - 0xC1, 0xBB, 0xC1, 0xBC, 0xA0, 0xE7, 0xC1, 0xBD, /* 0x80-0x83 */ - 0xA0, 0xE8, 0xC1, 0xBE, 0xC1, 0xBF, 0xC1, 0xC0, /* 0x84-0x87 */ - 0xA0, 0xE9, 0xA0, 0xEA, 0xA0, 0xEB, 0xC1, 0xC1, /* 0x88-0x8B */ - 0xC1, 0xC2, 0xC1, 0xC3, 0xA0, 0xEC, 0xA0, 0xED, /* 0x8C-0x8F */ - 0xA0, 0xEE, 0xA0, 0xEF, 0xA0, 0xF0, 0xA0, 0xF1, /* 0x90-0x93 */ - 0xC1, 0xC4, 0xA0, 0xF2, 0xA0, 0xF3, 0xA0, 0xF4, /* 0x94-0x97 */ - 0xA0, 0xF5, 0xA0, 0xF6, 0xA0, 0xF7, 0xA0, 0xF8, /* 0x98-0x9B */ - 0xA0, 0xF9, 0xC1, 0xC5, 0xA0, 0xFA, 0xC1, 0xC6, /* 0x9C-0x9F */ - 0xA0, 0xFB, 0xC1, 0xC7, 0xA0, 0xFC, 0xA0, 0xFD, /* 0xA0-0xA3 */ - 0xA0, 0xFE, 0xA1, 0x41, 0xA1, 0x42, 0xA1, 0x43, /* 0xA4-0xA7 */ - 0xC1, 0xC8, 0xA1, 0x44, 0xA1, 0x45, 0xA1, 0x46, /* 0xA8-0xAB */ - 0xA1, 0x47, 0xA1, 0x48, 0xA1, 0x49, 0xA1, 0x4A, /* 0xAC-0xAF */ - 0xA1, 0x4B, 0xA1, 0x4C, 0xA1, 0x4D, 0xA1, 0x4E, /* 0xB0-0xB3 */ - 0xA1, 0x4F, 0xA1, 0x50, 0xA1, 0x51, 0xA1, 0x52, /* 0xB4-0xB7 */ - 0xA1, 0x53, 0xA1, 0x54, 0xA1, 0x55, 0xA1, 0x56, /* 0xB8-0xBB */ - 0xC1, 0xC9, 0xC1, 0xCA, 0xA1, 0x57, 0xA1, 0x58, /* 0xBC-0xBF */ - 0xA1, 0x59, 0xA1, 0x5A, 0xA1, 0x61, 0xA1, 0x62, /* 0xC0-0xC3 */ - 0xC1, 0xCB, 0xA1, 0x63, 0xA1, 0x64, 0xA1, 0x65, /* 0xC4-0xC7 */ - 0xC1, 0xCC, 0xA1, 0x66, 0xA1, 0x67, 0xA1, 0x68, /* 0xC8-0xCB */ - 0xC1, 0xCD, 0xA1, 0x69, 0xA1, 0x6A, 0xA1, 0x6B, /* 0xCC-0xCF */ - 0xA1, 0x6C, 0xA1, 0x6D, 0xA1, 0x6E, 0xA1, 0x6F, /* 0xD0-0xD3 */ - 0xC1, 0xCE, 0xC1, 0xCF, 0xA1, 0x70, 0xC1, 0xD0, /* 0xD4-0xD7 */ - 0xA1, 0x71, 0xC1, 0xD1, 0xA1, 0x72, 0xA1, 0x73, /* 0xD8-0xDB */ - 0xA1, 0x74, 0xA1, 0x75, 0xA1, 0x76, 0xA1, 0x77, /* 0xDC-0xDF */ - 0xC1, 0xD2, 0xC1, 0xD3, 0xA1, 0x78, 0xA1, 0x79, /* 0xE0-0xE3 */ - 0xC1, 0xD4, 0xA1, 0x7A, 0xA1, 0x81, 0xA1, 0x82, /* 0xE4-0xE7 */ - 0xA1, 0x83, 0xA1, 0x84, 0xA1, 0x85, 0xA1, 0x86, /* 0xE8-0xEB */ - 0xA1, 0x87, 0xA1, 0x88, 0xA1, 0x89, 0xA1, 0x8A, /* 0xEC-0xEF */ - 0xA1, 0x8B, 0xA1, 0x8C, 0xA1, 0x8D, 0xA1, 0x8E, /* 0xF0-0xF3 */ - 0xA1, 0x8F, 0xC1, 0xD5, 0xA1, 0x90, 0xA1, 0x91, /* 0xF4-0xF7 */ - 0xA1, 0x92, 0xA1, 0x93, 0xA1, 0x94, 0xA1, 0x95, /* 0xF8-0xFB */ - 0xC1, 0xD6, 0xC1, 0xD7, 0xA1, 0x96, 0xA1, 0x97, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_C9[512] = { - 0xC1, 0xD8, 0xA1, 0x98, 0xA1, 0x99, 0xA1, 0x9A, /* 0x00-0x03 */ - 0xC1, 0xD9, 0xC1, 0xDA, 0xC1, 0xDB, 0xA1, 0x9B, /* 0x04-0x07 */ - 0xA1, 0x9C, 0xA1, 0x9D, 0xA1, 0x9E, 0xA1, 0x9F, /* 0x08-0x0B */ - 0xC1, 0xDC, 0xC1, 0xDD, 0xA1, 0xA0, 0xC1, 0xDE, /* 0x0C-0x0F */ - 0xA2, 0x41, 0xC1, 0xDF, 0xA2, 0x42, 0xA2, 0x43, /* 0x10-0x13 */ - 0xA2, 0x44, 0xA2, 0x45, 0xA2, 0x46, 0xA2, 0x47, /* 0x14-0x17 */ - 0xC1, 0xE0, 0xA2, 0x48, 0xA2, 0x49, 0xA2, 0x4A, /* 0x18-0x1B */ - 0xA2, 0x4B, 0xA2, 0x4C, 0xA2, 0x4D, 0xA2, 0x4E, /* 0x1C-0x1F */ - 0xA2, 0x4F, 0xA2, 0x50, 0xA2, 0x51, 0xA2, 0x52, /* 0x20-0x23 */ - 0xA2, 0x53, 0xA2, 0x54, 0xA2, 0x55, 0xA2, 0x56, /* 0x24-0x27 */ - 0xA2, 0x57, 0xA2, 0x58, 0xA2, 0x59, 0xA2, 0x5A, /* 0x28-0x2B */ - 0xC1, 0xE1, 0xA2, 0x61, 0xA2, 0x62, 0xA2, 0x63, /* 0x2C-0x2F */ - 0xA2, 0x64, 0xA2, 0x65, 0xA2, 0x66, 0xA2, 0x67, /* 0x30-0x33 */ - 0xC1, 0xE2, 0xA2, 0x68, 0xA2, 0x69, 0xA2, 0x6A, /* 0x34-0x37 */ - 0xA2, 0x6B, 0xA2, 0x6C, 0xA2, 0x6D, 0xA2, 0x6E, /* 0x38-0x3B */ - 0xA2, 0x6F, 0xA2, 0x70, 0xA2, 0x71, 0xA2, 0x72, /* 0x3C-0x3F */ - 0xA2, 0x73, 0xA2, 0x74, 0xA2, 0x75, 0xA2, 0x76, /* 0x40-0x43 */ - 0xA2, 0x77, 0xA2, 0x78, 0xA2, 0x79, 0xA2, 0x7A, /* 0x44-0x47 */ - 0xA2, 0x81, 0xA2, 0x82, 0xA2, 0x83, 0xA2, 0x84, /* 0x48-0x4B */ - 0xA2, 0x85, 0xA2, 0x86, 0xA2, 0x87, 0xA2, 0x88, /* 0x4C-0x4F */ - 0xC1, 0xE3, 0xC1, 0xE4, 0xA2, 0x89, 0xA2, 0x8A, /* 0x50-0x53 */ - 0xC1, 0xE5, 0xA2, 0x8B, 0xA2, 0x8C, 0xA2, 0x8D, /* 0x54-0x57 */ - 0xC1, 0xE6, 0xA2, 0x8E, 0xA2, 0x8F, 0xA2, 0x90, /* 0x58-0x5B */ - 0xA2, 0x91, 0xA2, 0x92, 0xA2, 0x93, 0xA2, 0x94, /* 0x5C-0x5F */ - 0xC1, 0xE7, 0xC1, 0xE8, 0xA2, 0x95, 0xC1, 0xE9, /* 0x60-0x63 */ - 0xA2, 0x96, 0xA2, 0x97, 0xA2, 0x98, 0xA2, 0x99, /* 0x64-0x67 */ - 0xA2, 0x9A, 0xA2, 0x9B, 0xA2, 0x9C, 0xA2, 0x9D, /* 0x68-0x6B */ - 0xC1, 0xEA, 0xA2, 0x9E, 0xA2, 0x9F, 0xA2, 0xA0, /* 0x6C-0x6F */ - 0xC1, 0xEB, 0xA3, 0x41, 0xA3, 0x42, 0xA3, 0x43, /* 0x70-0x73 */ - 0xC1, 0xEC, 0xA3, 0x44, 0xA3, 0x45, 0xA3, 0x46, /* 0x74-0x77 */ - 0xA3, 0x47, 0xA3, 0x48, 0xA3, 0x49, 0xA3, 0x4A, /* 0x78-0x7B */ - 0xC1, 0xED, 0xA3, 0x4B, 0xA3, 0x4C, 0xA3, 0x4D, /* 0x7C-0x7F */ - - 0xA3, 0x4E, 0xA3, 0x4F, 0xA3, 0x50, 0xA3, 0x51, /* 0x80-0x83 */ - 0xA3, 0x52, 0xA3, 0x53, 0xA3, 0x54, 0xA3, 0x55, /* 0x84-0x87 */ - 0xC1, 0xEE, 0xC1, 0xEF, 0xA3, 0x56, 0xA3, 0x57, /* 0x88-0x8B */ - 0xC1, 0xF0, 0xA3, 0x58, 0xA3, 0x59, 0xA3, 0x5A, /* 0x8C-0x8F */ - 0xC1, 0xF1, 0xA3, 0x61, 0xA3, 0x62, 0xA3, 0x63, /* 0x90-0x93 */ - 0xA3, 0x64, 0xA3, 0x65, 0xA3, 0x66, 0xA3, 0x67, /* 0x94-0x97 */ - 0xC1, 0xF2, 0xC1, 0xF3, 0xA3, 0x68, 0xC1, 0xF4, /* 0x98-0x9B */ - 0xA3, 0x69, 0xC1, 0xF5, 0xA3, 0x6A, 0xA3, 0x6B, /* 0x9C-0x9F */ - 0xA3, 0x6C, 0xA3, 0x6D, 0xA3, 0x6E, 0xA3, 0x6F, /* 0xA0-0xA3 */ - 0xA3, 0x70, 0xA3, 0x71, 0xA3, 0x72, 0xA3, 0x73, /* 0xA4-0xA7 */ - 0xA3, 0x74, 0xA3, 0x75, 0xA3, 0x76, 0xA3, 0x77, /* 0xA8-0xAB */ - 0xA3, 0x78, 0xA3, 0x79, 0xA3, 0x7A, 0xA3, 0x81, /* 0xAC-0xAF */ - 0xA3, 0x82, 0xA3, 0x83, 0xA3, 0x84, 0xA3, 0x85, /* 0xB0-0xB3 */ - 0xA3, 0x86, 0xA3, 0x87, 0xA3, 0x88, 0xA3, 0x89, /* 0xB4-0xB7 */ - 0xA3, 0x8A, 0xA3, 0x8B, 0xA3, 0x8C, 0xA3, 0x8D, /* 0xB8-0xBB */ - 0xA3, 0x8E, 0xA3, 0x8F, 0xA3, 0x90, 0xA3, 0x91, /* 0xBC-0xBF */ - 0xC1, 0xF6, 0xC1, 0xF7, 0xA3, 0x92, 0xA3, 0x93, /* 0xC0-0xC3 */ - 0xC1, 0xF8, 0xA3, 0x94, 0xA3, 0x95, 0xC1, 0xF9, /* 0xC4-0xC7 */ - 0xC1, 0xFA, 0xA3, 0x96, 0xC1, 0xFB, 0xA3, 0x97, /* 0xC8-0xCB */ - 0xA3, 0x98, 0xA3, 0x99, 0xA3, 0x9A, 0xA3, 0x9B, /* 0xCC-0xCF */ - 0xC1, 0xFC, 0xC1, 0xFD, 0xA3, 0x9C, 0xC1, 0xFE, /* 0xD0-0xD3 */ - 0xA3, 0x9D, 0xC2, 0xA1, 0xC2, 0xA2, 0xA3, 0x9E, /* 0xD4-0xD7 */ - 0xA3, 0x9F, 0xC2, 0xA3, 0xC2, 0xA4, 0xA3, 0xA0, /* 0xD8-0xDB */ - 0xC2, 0xA5, 0xC2, 0xA6, 0xA4, 0x41, 0xA4, 0x42, /* 0xDC-0xDF */ - 0xC2, 0xA7, 0xA4, 0x43, 0xC2, 0xA8, 0xA4, 0x44, /* 0xE0-0xE3 */ - 0xC2, 0xA9, 0xA4, 0x45, 0xA4, 0x46, 0xC2, 0xAA, /* 0xE4-0xE7 */ - 0xA4, 0x47, 0xA4, 0x48, 0xA4, 0x49, 0xA4, 0x4A, /* 0xE8-0xEB */ - 0xC2, 0xAB, 0xC2, 0xAC, 0xA4, 0x4B, 0xC2, 0xAD, /* 0xEC-0xEF */ - 0xC2, 0xAE, 0xC2, 0xAF, 0xA4, 0x4C, 0xA4, 0x4D, /* 0xF0-0xF3 */ - 0xA4, 0x4E, 0xA4, 0x4F, 0xA4, 0x50, 0xA4, 0x51, /* 0xF4-0xF7 */ - 0xC2, 0xB0, 0xC2, 0xB1, 0xA4, 0x52, 0xA4, 0x53, /* 0xF8-0xFB */ - 0xC2, 0xB2, 0xA4, 0x54, 0xA4, 0x55, 0xA4, 0x56, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_CA[512] = { - 0xC2, 0xB3, 0xA4, 0x57, 0xA4, 0x58, 0xA4, 0x59, /* 0x00-0x03 */ - 0xA4, 0x5A, 0xA4, 0x61, 0xA4, 0x62, 0xA4, 0x63, /* 0x04-0x07 */ - 0xC2, 0xB4, 0xC2, 0xB5, 0xA4, 0x64, 0xC2, 0xB6, /* 0x08-0x0B */ - 0xC2, 0xB7, 0xC2, 0xB8, 0xA4, 0x65, 0xA4, 0x66, /* 0x0C-0x0F */ - 0xA4, 0x67, 0xA4, 0x68, 0xA4, 0x69, 0xA4, 0x6A, /* 0x10-0x13 */ - 0xC2, 0xB9, 0xA4, 0x6B, 0xA4, 0x6C, 0xA4, 0x6D, /* 0x14-0x17 */ - 0xC2, 0xBA, 0xA4, 0x6E, 0xA4, 0x6F, 0xA4, 0x70, /* 0x18-0x1B */ - 0xA4, 0x71, 0xA4, 0x72, 0xA4, 0x73, 0xA4, 0x74, /* 0x1C-0x1F */ - 0xA4, 0x75, 0xA4, 0x76, 0xA4, 0x77, 0xA4, 0x78, /* 0x20-0x23 */ - 0xA4, 0x79, 0xA4, 0x7A, 0xA4, 0x81, 0xA4, 0x82, /* 0x24-0x27 */ - 0xA4, 0x83, 0xC2, 0xBB, 0xA4, 0x84, 0xA4, 0x85, /* 0x28-0x2B */ - 0xA4, 0x86, 0xA4, 0x87, 0xA4, 0x88, 0xA4, 0x89, /* 0x2C-0x2F */ - 0xA4, 0x8A, 0xA4, 0x8B, 0xA4, 0x8C, 0xA4, 0x8D, /* 0x30-0x33 */ - 0xA4, 0x8E, 0xA4, 0x8F, 0xA4, 0x90, 0xA4, 0x91, /* 0x34-0x37 */ - 0xA4, 0x92, 0xA4, 0x93, 0xA4, 0x94, 0xA4, 0x95, /* 0x38-0x3B */ - 0xA4, 0x96, 0xA4, 0x97, 0xA4, 0x98, 0xA4, 0x99, /* 0x3C-0x3F */ - 0xA4, 0x9A, 0xA4, 0x9B, 0xA4, 0x9C, 0xA4, 0x9D, /* 0x40-0x43 */ - 0xA4, 0x9E, 0xA4, 0x9F, 0xA4, 0xA0, 0xA5, 0x41, /* 0x44-0x47 */ - 0xA5, 0x42, 0xA5, 0x43, 0xA5, 0x44, 0xA5, 0x45, /* 0x48-0x4B */ - 0xC2, 0xBC, 0xC2, 0xBD, 0xA5, 0x46, 0xA5, 0x47, /* 0x4C-0x4F */ - 0xC2, 0xBE, 0xA5, 0x48, 0xA5, 0x49, 0xA5, 0x4A, /* 0x50-0x53 */ - 0xC2, 0xBF, 0xA5, 0x4B, 0xA5, 0x4C, 0xA5, 0x4D, /* 0x54-0x57 */ - 0xA5, 0x4E, 0xA5, 0x4F, 0xA5, 0x50, 0xA5, 0x51, /* 0x58-0x5B */ - 0xC2, 0xC0, 0xC2, 0xC1, 0xA5, 0x52, 0xC2, 0xC2, /* 0x5C-0x5F */ - 0xC2, 0xC3, 0xC2, 0xC4, 0xA5, 0x53, 0xA5, 0x54, /* 0x60-0x63 */ - 0xA5, 0x55, 0xA5, 0x56, 0xA5, 0x57, 0xA5, 0x58, /* 0x64-0x67 */ - 0xC2, 0xC5, 0xA5, 0x59, 0xA5, 0x5A, 0xA5, 0x61, /* 0x68-0x6B */ - 0xA5, 0x62, 0xA5, 0x63, 0xA5, 0x64, 0xA5, 0x65, /* 0x6C-0x6F */ - 0xA5, 0x66, 0xA5, 0x67, 0xA5, 0x68, 0xA5, 0x69, /* 0x70-0x73 */ - 0xA5, 0x6A, 0xA5, 0x6B, 0xA5, 0x6C, 0xA5, 0x6D, /* 0x74-0x77 */ - 0xA5, 0x6E, 0xA5, 0x6F, 0xA5, 0x70, 0xA5, 0x71, /* 0x78-0x7B */ - 0xA5, 0x72, 0xC2, 0xC6, 0xA5, 0x73, 0xA5, 0x74, /* 0x7C-0x7F */ - - 0xA5, 0x75, 0xA5, 0x76, 0xA5, 0x77, 0xA5, 0x78, /* 0x80-0x83 */ - 0xC2, 0xC7, 0xA5, 0x79, 0xA5, 0x7A, 0xA5, 0x81, /* 0x84-0x87 */ - 0xA5, 0x82, 0xA5, 0x83, 0xA5, 0x84, 0xA5, 0x85, /* 0x88-0x8B */ - 0xA5, 0x86, 0xA5, 0x87, 0xA5, 0x88, 0xA5, 0x89, /* 0x8C-0x8F */ - 0xA5, 0x8A, 0xA5, 0x8B, 0xA5, 0x8C, 0xA5, 0x8D, /* 0x90-0x93 */ - 0xA5, 0x8E, 0xA5, 0x8F, 0xA5, 0x90, 0xA5, 0x91, /* 0x94-0x97 */ - 0xC2, 0xC8, 0xA5, 0x92, 0xA5, 0x93, 0xA5, 0x94, /* 0x98-0x9B */ - 0xA5, 0x95, 0xA5, 0x96, 0xA5, 0x97, 0xA5, 0x98, /* 0x9C-0x9F */ - 0xA5, 0x99, 0xA5, 0x9A, 0xA5, 0x9B, 0xA5, 0x9C, /* 0xA0-0xA3 */ - 0xA5, 0x9D, 0xA5, 0x9E, 0xA5, 0x9F, 0xA5, 0xA0, /* 0xA4-0xA7 */ - 0xA6, 0x41, 0xA6, 0x42, 0xA6, 0x43, 0xA6, 0x44, /* 0xA8-0xAB */ - 0xA6, 0x45, 0xA6, 0x46, 0xA6, 0x47, 0xA6, 0x48, /* 0xAC-0xAF */ - 0xA6, 0x49, 0xA6, 0x4A, 0xA6, 0x4B, 0xA6, 0x4C, /* 0xB0-0xB3 */ - 0xA6, 0x4D, 0xA6, 0x4E, 0xA6, 0x4F, 0xA6, 0x50, /* 0xB4-0xB7 */ - 0xA6, 0x51, 0xA6, 0x52, 0xA6, 0x53, 0xA6, 0x54, /* 0xB8-0xBB */ - 0xC2, 0xC9, 0xC2, 0xCA, 0xA6, 0x55, 0xA6, 0x56, /* 0xBC-0xBF */ - 0xC2, 0xCB, 0xA6, 0x57, 0xA6, 0x58, 0xA6, 0x59, /* 0xC0-0xC3 */ - 0xC2, 0xCC, 0xA6, 0x5A, 0xA6, 0x61, 0xA6, 0x62, /* 0xC4-0xC7 */ - 0xA6, 0x63, 0xA6, 0x64, 0xA6, 0x65, 0xA6, 0x66, /* 0xC8-0xCB */ - 0xC2, 0xCD, 0xC2, 0xCE, 0xA6, 0x67, 0xC2, 0xCF, /* 0xCC-0xCF */ - 0xA6, 0x68, 0xC2, 0xD0, 0xA6, 0x69, 0xC2, 0xD1, /* 0xD0-0xD3 */ - 0xA6, 0x6A, 0xA6, 0x6B, 0xA6, 0x6C, 0xA6, 0x6D, /* 0xD4-0xD7 */ - 0xC2, 0xD2, 0xC2, 0xD3, 0xA6, 0x6E, 0xA6, 0x6F, /* 0xD8-0xDB */ - 0xA6, 0x70, 0xA6, 0x71, 0xA6, 0x72, 0xA6, 0x73, /* 0xDC-0xDF */ - 0xC2, 0xD4, 0xA6, 0x74, 0xA6, 0x75, 0xA6, 0x76, /* 0xE0-0xE3 */ - 0xA6, 0x77, 0xA6, 0x78, 0xA6, 0x79, 0xA6, 0x7A, /* 0xE4-0xE7 */ - 0xA6, 0x81, 0xA6, 0x82, 0xA6, 0x83, 0xA6, 0x84, /* 0xE8-0xEB */ - 0xC2, 0xD5, 0xA6, 0x85, 0xA6, 0x86, 0xA6, 0x87, /* 0xEC-0xEF */ - 0xA6, 0x88, 0xA6, 0x89, 0xA6, 0x8A, 0xA6, 0x8B, /* 0xF0-0xF3 */ - 0xC2, 0xD6, 0xA6, 0x8C, 0xA6, 0x8D, 0xA6, 0x8E, /* 0xF4-0xF7 */ - 0xA6, 0x8F, 0xA6, 0x90, 0xA6, 0x91, 0xA6, 0x92, /* 0xF8-0xFB */ - 0xA6, 0x93, 0xA6, 0x94, 0xA6, 0x95, 0xA6, 0x96, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_CB[512] = { - 0xA6, 0x97, 0xA6, 0x98, 0xA6, 0x99, 0xA6, 0x9A, /* 0x00-0x03 */ - 0xA6, 0x9B, 0xA6, 0x9C, 0xA6, 0x9D, 0xA6, 0x9E, /* 0x04-0x07 */ - 0xC2, 0xD7, 0xA6, 0x9F, 0xA6, 0xA0, 0xA7, 0x41, /* 0x08-0x0B */ - 0xA7, 0x42, 0xA7, 0x43, 0xA7, 0x44, 0xA7, 0x45, /* 0x0C-0x0F */ - 0xC2, 0xD8, 0xA7, 0x46, 0xA7, 0x47, 0xA7, 0x48, /* 0x10-0x13 */ - 0xC2, 0xD9, 0xA7, 0x49, 0xA7, 0x4A, 0xA7, 0x4B, /* 0x14-0x17 */ - 0xC2, 0xDA, 0xA7, 0x4C, 0xA7, 0x4D, 0xA7, 0x4E, /* 0x18-0x1B */ - 0xA7, 0x4F, 0xA7, 0x50, 0xA7, 0x51, 0xA7, 0x52, /* 0x1C-0x1F */ - 0xC2, 0xDB, 0xC2, 0xDC, 0xA7, 0x53, 0xA7, 0x54, /* 0x20-0x23 */ - 0xA7, 0x55, 0xA7, 0x56, 0xA7, 0x57, 0xA7, 0x58, /* 0x24-0x27 */ - 0xA7, 0x59, 0xA7, 0x5A, 0xA7, 0x61, 0xA7, 0x62, /* 0x28-0x2B */ - 0xA7, 0x63, 0xA7, 0x64, 0xA7, 0x65, 0xA7, 0x66, /* 0x2C-0x2F */ - 0xA7, 0x67, 0xA7, 0x68, 0xA7, 0x69, 0xA7, 0x6A, /* 0x30-0x33 */ - 0xA7, 0x6B, 0xA7, 0x6C, 0xA7, 0x6D, 0xA7, 0x6E, /* 0x34-0x37 */ - 0xA7, 0x6F, 0xA7, 0x70, 0xA7, 0x71, 0xA7, 0x72, /* 0x38-0x3B */ - 0xA7, 0x73, 0xA7, 0x74, 0xA7, 0x75, 0xA7, 0x76, /* 0x3C-0x3F */ - 0xA7, 0x77, 0xC2, 0xDD, 0xA7, 0x78, 0xA7, 0x79, /* 0x40-0x43 */ - 0xA7, 0x7A, 0xA7, 0x81, 0xA7, 0x82, 0xA7, 0x83, /* 0x44-0x47 */ - 0xC2, 0xDE, 0xC2, 0xDF, 0xA7, 0x84, 0xA7, 0x85, /* 0x48-0x4B */ - 0xC2, 0xE0, 0xA7, 0x86, 0xA7, 0x87, 0xA7, 0x88, /* 0x4C-0x4F */ - 0xC2, 0xE1, 0xA7, 0x89, 0xA7, 0x8A, 0xA7, 0x8B, /* 0x50-0x53 */ - 0xA7, 0x8C, 0xA7, 0x8D, 0xA7, 0x8E, 0xA7, 0x8F, /* 0x54-0x57 */ - 0xC2, 0xE2, 0xC2, 0xE3, 0xA7, 0x90, 0xA7, 0x91, /* 0x58-0x5B */ - 0xA7, 0x92, 0xC2, 0xE4, 0xA7, 0x93, 0xA7, 0x94, /* 0x5C-0x5F */ - 0xA7, 0x95, 0xA7, 0x96, 0xA7, 0x97, 0xA7, 0x98, /* 0x60-0x63 */ - 0xC2, 0xE5, 0xA7, 0x99, 0xA7, 0x9A, 0xA7, 0x9B, /* 0x64-0x67 */ - 0xA7, 0x9C, 0xA7, 0x9D, 0xA7, 0x9E, 0xA7, 0x9F, /* 0x68-0x6B */ - 0xA7, 0xA0, 0xA8, 0x41, 0xA8, 0x42, 0xA8, 0x43, /* 0x6C-0x6F */ - 0xA8, 0x44, 0xA8, 0x45, 0xA8, 0x46, 0xA8, 0x47, /* 0x70-0x73 */ - 0xA8, 0x48, 0xA8, 0x49, 0xA8, 0x4A, 0xA8, 0x4B, /* 0x74-0x77 */ - 0xC2, 0xE6, 0xC2, 0xE7, 0xA8, 0x4C, 0xA8, 0x4D, /* 0x78-0x7B */ - 0xA8, 0x4E, 0xA8, 0x4F, 0xA8, 0x50, 0xA8, 0x51, /* 0x7C-0x7F */ - - 0xA8, 0x52, 0xA8, 0x53, 0xA8, 0x54, 0xA8, 0x55, /* 0x80-0x83 */ - 0xA8, 0x56, 0xA8, 0x57, 0xA8, 0x58, 0xA8, 0x59, /* 0x84-0x87 */ - 0xA8, 0x5A, 0xA8, 0x61, 0xA8, 0x62, 0xA8, 0x63, /* 0x88-0x8B */ - 0xA8, 0x64, 0xA8, 0x65, 0xA8, 0x66, 0xA8, 0x67, /* 0x8C-0x8F */ - 0xA8, 0x68, 0xA8, 0x69, 0xA8, 0x6A, 0xA8, 0x6B, /* 0x90-0x93 */ - 0xA8, 0x6C, 0xA8, 0x6D, 0xA8, 0x6E, 0xA8, 0x6F, /* 0x94-0x97 */ - 0xA8, 0x70, 0xA8, 0x71, 0xA8, 0x72, 0xA8, 0x73, /* 0x98-0x9B */ - 0xC2, 0xE8, 0xA8, 0x74, 0xA8, 0x75, 0xA8, 0x76, /* 0x9C-0x9F */ - 0xA8, 0x77, 0xA8, 0x78, 0xA8, 0x79, 0xA8, 0x7A, /* 0xA0-0xA3 */ - 0xA8, 0x81, 0xA8, 0x82, 0xA8, 0x83, 0xA8, 0x84, /* 0xA4-0xA7 */ - 0xA8, 0x85, 0xA8, 0x86, 0xA8, 0x87, 0xA8, 0x88, /* 0xA8-0xAB */ - 0xA8, 0x89, 0xA8, 0x8A, 0xA8, 0x8B, 0xA8, 0x8C, /* 0xAC-0xAF */ - 0xA8, 0x8D, 0xA8, 0x8E, 0xA8, 0x8F, 0xA8, 0x90, /* 0xB0-0xB3 */ - 0xA8, 0x91, 0xA8, 0x92, 0xA8, 0x93, 0xA8, 0x94, /* 0xB4-0xB7 */ - 0xC2, 0xE9, 0xA8, 0x95, 0xA8, 0x96, 0xA8, 0x97, /* 0xB8-0xBB */ - 0xA8, 0x98, 0xA8, 0x99, 0xA8, 0x9A, 0xA8, 0x9B, /* 0xBC-0xBF */ - 0xA8, 0x9C, 0xA8, 0x9D, 0xA8, 0x9E, 0xA8, 0x9F, /* 0xC0-0xC3 */ - 0xA8, 0xA0, 0xA9, 0x41, 0xA9, 0x42, 0xA9, 0x43, /* 0xC4-0xC7 */ - 0xA9, 0x44, 0xA9, 0x45, 0xA9, 0x46, 0xA9, 0x47, /* 0xC8-0xCB */ - 0xA9, 0x48, 0xA9, 0x49, 0xA9, 0x4A, 0xA9, 0x4B, /* 0xCC-0xCF */ - 0xA9, 0x4C, 0xA9, 0x4D, 0xA9, 0x4E, 0xA9, 0x4F, /* 0xD0-0xD3 */ - 0xC2, 0xEA, 0xA9, 0x50, 0xA9, 0x51, 0xA9, 0x52, /* 0xD4-0xD7 */ - 0xA9, 0x53, 0xA9, 0x54, 0xA9, 0x55, 0xA9, 0x56, /* 0xD8-0xDB */ - 0xA9, 0x57, 0xA9, 0x58, 0xA9, 0x59, 0xA9, 0x5A, /* 0xDC-0xDF */ - 0xA9, 0x61, 0xA9, 0x62, 0xA9, 0x63, 0xA9, 0x64, /* 0xE0-0xE3 */ - 0xC2, 0xEB, 0xA9, 0x65, 0xA9, 0x66, 0xC2, 0xEC, /* 0xE4-0xE7 */ - 0xA9, 0x67, 0xC2, 0xED, 0xA9, 0x68, 0xA9, 0x69, /* 0xE8-0xEB */ - 0xA9, 0x6A, 0xA9, 0x6B, 0xA9, 0x6C, 0xA9, 0x6D, /* 0xEC-0xEF */ - 0xA9, 0x6E, 0xA9, 0x6F, 0xA9, 0x70, 0xA9, 0x71, /* 0xF0-0xF3 */ - 0xA9, 0x72, 0xA9, 0x73, 0xA9, 0x74, 0xA9, 0x75, /* 0xF4-0xF7 */ - 0xA9, 0x76, 0xA9, 0x77, 0xA9, 0x78, 0xA9, 0x79, /* 0xF8-0xFB */ - 0xA9, 0x7A, 0xA9, 0x81, 0xA9, 0x82, 0xA9, 0x83, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_CC[512] = { - 0xA9, 0x84, 0xA9, 0x85, 0xA9, 0x86, 0xA9, 0x87, /* 0x00-0x03 */ - 0xA9, 0x88, 0xA9, 0x89, 0xA9, 0x8A, 0xA9, 0x8B, /* 0x04-0x07 */ - 0xA9, 0x8C, 0xA9, 0x8D, 0xA9, 0x8E, 0xA9, 0x8F, /* 0x08-0x0B */ - 0xC2, 0xEE, 0xC2, 0xEF, 0xA9, 0x90, 0xA9, 0x91, /* 0x0C-0x0F */ - 0xC2, 0xF0, 0xA9, 0x92, 0xA9, 0x93, 0xA9, 0x94, /* 0x10-0x13 */ - 0xC2, 0xF1, 0xA9, 0x95, 0xA9, 0x96, 0xA9, 0x97, /* 0x14-0x17 */ - 0xA9, 0x98, 0xA9, 0x99, 0xA9, 0x9A, 0xA9, 0x9B, /* 0x18-0x1B */ - 0xC2, 0xF2, 0xC2, 0xF3, 0xA9, 0x9C, 0xA9, 0x9D, /* 0x1C-0x1F */ - 0xA9, 0x9E, 0xC2, 0xF4, 0xC2, 0xF5, 0xA9, 0x9F, /* 0x20-0x23 */ - 0xA9, 0xA0, 0xAA, 0x41, 0xAA, 0x42, 0xC2, 0xF6, /* 0x24-0x27 */ - 0xC2, 0xF7, 0xC2, 0xF8, 0xAA, 0x43, 0xAA, 0x44, /* 0x28-0x2B */ - 0xC2, 0xF9, 0xAA, 0x45, 0xC2, 0xFA, 0xAA, 0x46, /* 0x2C-0x2F */ - 0xC2, 0xFB, 0xAA, 0x47, 0xAA, 0x48, 0xAA, 0x49, /* 0x30-0x33 */ - 0xAA, 0x4A, 0xAA, 0x4B, 0xAA, 0x4C, 0xAA, 0x4D, /* 0x34-0x37 */ - 0xC2, 0xFC, 0xC2, 0xFD, 0xAA, 0x4E, 0xC2, 0xFE, /* 0x38-0x3B */ - 0xC3, 0xA1, 0xC3, 0xA2, 0xC3, 0xA3, 0xAA, 0x4F, /* 0x3C-0x3F */ - 0xAA, 0x50, 0xAA, 0x51, 0xAA, 0x52, 0xAA, 0x53, /* 0x40-0x43 */ - 0xC3, 0xA4, 0xC3, 0xA5, 0xAA, 0x54, 0xAA, 0x55, /* 0x44-0x47 */ - 0xC3, 0xA6, 0xAA, 0x56, 0xAA, 0x57, 0xAA, 0x58, /* 0x48-0x4B */ - 0xC3, 0xA7, 0xAA, 0x59, 0xAA, 0x5A, 0xAA, 0x61, /* 0x4C-0x4F */ - 0xAA, 0x62, 0xAA, 0x63, 0xAA, 0x64, 0xAA, 0x65, /* 0x50-0x53 */ - 0xC3, 0xA8, 0xC3, 0xA9, 0xAA, 0x66, 0xC3, 0xAA, /* 0x54-0x57 */ - 0xC3, 0xAB, 0xC3, 0xAC, 0xAA, 0x67, 0xAA, 0x68, /* 0x58-0x5B */ - 0xAA, 0x69, 0xAA, 0x6A, 0xAA, 0x6B, 0xAA, 0x6C, /* 0x5C-0x5F */ - 0xC3, 0xAD, 0xAA, 0x6D, 0xAA, 0x6E, 0xAA, 0x6F, /* 0x60-0x63 */ - 0xC3, 0xAE, 0xAA, 0x70, 0xC3, 0xAF, 0xAA, 0x71, /* 0x64-0x67 */ - 0xC3, 0xB0, 0xAA, 0x72, 0xAA, 0x73, 0xAA, 0x74, /* 0x68-0x6B */ - 0xAA, 0x75, 0xAA, 0x76, 0xAA, 0x77, 0xAA, 0x78, /* 0x6C-0x6F */ - 0xC3, 0xB1, 0xAA, 0x79, 0xAA, 0x7A, 0xAA, 0x81, /* 0x70-0x73 */ - 0xAA, 0x82, 0xC3, 0xB2, 0xAA, 0x83, 0xAA, 0x84, /* 0x74-0x77 */ - 0xAA, 0x85, 0xAA, 0x86, 0xAA, 0x87, 0xAA, 0x88, /* 0x78-0x7B */ - 0xAA, 0x89, 0xAA, 0x8A, 0xAA, 0x8B, 0xAA, 0x8C, /* 0x7C-0x7F */ - - 0xAA, 0x8D, 0xAA, 0x8E, 0xAA, 0x8F, 0xAA, 0x90, /* 0x80-0x83 */ - 0xAA, 0x91, 0xAA, 0x92, 0xAA, 0x93, 0xAA, 0x94, /* 0x84-0x87 */ - 0xAA, 0x95, 0xAA, 0x96, 0xAA, 0x97, 0xAA, 0x98, /* 0x88-0x8B */ - 0xAA, 0x99, 0xAA, 0x9A, 0xAA, 0x9B, 0xAA, 0x9C, /* 0x8C-0x8F */ - 0xAA, 0x9D, 0xAA, 0x9E, 0xAA, 0x9F, 0xAA, 0xA0, /* 0x90-0x93 */ - 0xAB, 0x41, 0xAB, 0x42, 0xAB, 0x43, 0xAB, 0x44, /* 0x94-0x97 */ - 0xC3, 0xB3, 0xC3, 0xB4, 0xAB, 0x45, 0xAB, 0x46, /* 0x98-0x9B */ - 0xC3, 0xB5, 0xAB, 0x47, 0xAB, 0x48, 0xAB, 0x49, /* 0x9C-0x9F */ - 0xC3, 0xB6, 0xAB, 0x4A, 0xAB, 0x4B, 0xAB, 0x4C, /* 0xA0-0xA3 */ - 0xAB, 0x4D, 0xAB, 0x4E, 0xAB, 0x4F, 0xAB, 0x50, /* 0xA4-0xA7 */ - 0xC3, 0xB7, 0xC3, 0xB8, 0xAB, 0x51, 0xC3, 0xB9, /* 0xA8-0xAB */ - 0xC3, 0xBA, 0xC3, 0xBB, 0xAB, 0x52, 0xAB, 0x53, /* 0xAC-0xAF */ - 0xAB, 0x54, 0xAB, 0x55, 0xAB, 0x56, 0xAB, 0x57, /* 0xB0-0xB3 */ - 0xC3, 0xBC, 0xC3, 0xBD, 0xAB, 0x58, 0xAB, 0x59, /* 0xB4-0xB7 */ - 0xC3, 0xBE, 0xAB, 0x5A, 0xAB, 0x61, 0xAB, 0x62, /* 0xB8-0xBB */ - 0xC3, 0xBF, 0xAB, 0x63, 0xAB, 0x64, 0xAB, 0x65, /* 0xBC-0xBF */ - 0xAB, 0x66, 0xAB, 0x67, 0xAB, 0x68, 0xAB, 0x69, /* 0xC0-0xC3 */ - 0xC3, 0xC0, 0xC3, 0xC1, 0xAB, 0x6A, 0xC3, 0xC2, /* 0xC4-0xC7 */ - 0xAB, 0x6B, 0xC3, 0xC3, 0xAB, 0x6C, 0xAB, 0x6D, /* 0xC8-0xCB */ - 0xAB, 0x6E, 0xAB, 0x6F, 0xAB, 0x70, 0xAB, 0x71, /* 0xCC-0xCF */ - 0xC3, 0xC4, 0xAB, 0x72, 0xAB, 0x73, 0xAB, 0x74, /* 0xD0-0xD3 */ - 0xC3, 0xC5, 0xAB, 0x75, 0xAB, 0x76, 0xAB, 0x77, /* 0xD4-0xD7 */ - 0xAB, 0x78, 0xAB, 0x79, 0xAB, 0x7A, 0xAB, 0x81, /* 0xD8-0xDB */ - 0xAB, 0x82, 0xAB, 0x83, 0xAB, 0x84, 0xAB, 0x85, /* 0xDC-0xDF */ - 0xAB, 0x86, 0xAB, 0x87, 0xAB, 0x88, 0xAB, 0x89, /* 0xE0-0xE3 */ - 0xC3, 0xC6, 0xAB, 0x8A, 0xAB, 0x8B, 0xAB, 0x8C, /* 0xE4-0xE7 */ - 0xAB, 0x8D, 0xAB, 0x8E, 0xAB, 0x8F, 0xAB, 0x90, /* 0xE8-0xEB */ - 0xC3, 0xC7, 0xAB, 0x91, 0xAB, 0x92, 0xAB, 0x93, /* 0xEC-0xEF */ - 0xC3, 0xC8, 0xAB, 0x94, 0xAB, 0x95, 0xAB, 0x96, /* 0xF0-0xF3 */ - 0xAB, 0x97, 0xAB, 0x98, 0xAB, 0x99, 0xAB, 0x9A, /* 0xF4-0xF7 */ - 0xAB, 0x9B, 0xAB, 0x9C, 0xAB, 0x9D, 0xAB, 0x9E, /* 0xF8-0xFB */ - 0xAB, 0x9F, 0xAB, 0xA0, 0xAC, 0x41, 0xAC, 0x42, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_CD[512] = { - 0xAC, 0x43, 0xC3, 0xC9, 0xAC, 0x44, 0xAC, 0x45, /* 0x00-0x03 */ - 0xAC, 0x46, 0xAC, 0x47, 0xAC, 0x48, 0xAC, 0x49, /* 0x04-0x07 */ - 0xC3, 0xCA, 0xC3, 0xCB, 0xAC, 0x4A, 0xAC, 0x4B, /* 0x08-0x0B */ - 0xC3, 0xCC, 0xAC, 0x4C, 0xAC, 0x4D, 0xAC, 0x4E, /* 0x0C-0x0F */ - 0xC3, 0xCD, 0xAC, 0x4F, 0xAC, 0x50, 0xAC, 0x51, /* 0x10-0x13 */ - 0xAC, 0x52, 0xAC, 0x53, 0xAC, 0x54, 0xAC, 0x55, /* 0x14-0x17 */ - 0xC3, 0xCE, 0xC3, 0xCF, 0xAC, 0x56, 0xC3, 0xD0, /* 0x18-0x1B */ - 0xAC, 0x57, 0xC3, 0xD1, 0xAC, 0x58, 0xAC, 0x59, /* 0x1C-0x1F */ - 0xAC, 0x5A, 0xAC, 0x61, 0xAC, 0x62, 0xAC, 0x63, /* 0x20-0x23 */ - 0xC3, 0xD2, 0xAC, 0x64, 0xAC, 0x65, 0xAC, 0x66, /* 0x24-0x27 */ - 0xC3, 0xD3, 0xAC, 0x67, 0xAC, 0x68, 0xAC, 0x69, /* 0x28-0x2B */ - 0xC3, 0xD4, 0xAC, 0x6A, 0xAC, 0x6B, 0xAC, 0x6C, /* 0x2C-0x2F */ - 0xAC, 0x6D, 0xAC, 0x6E, 0xAC, 0x6F, 0xAC, 0x70, /* 0x30-0x33 */ - 0xAC, 0x71, 0xAC, 0x72, 0xAC, 0x73, 0xAC, 0x74, /* 0x34-0x37 */ - 0xAC, 0x75, 0xC3, 0xD5, 0xAC, 0x76, 0xAC, 0x77, /* 0x38-0x3B */ - 0xAC, 0x78, 0xAC, 0x79, 0xAC, 0x7A, 0xAC, 0x81, /* 0x3C-0x3F */ - 0xAC, 0x82, 0xAC, 0x83, 0xAC, 0x84, 0xAC, 0x85, /* 0x40-0x43 */ - 0xAC, 0x86, 0xAC, 0x87, 0xAC, 0x88, 0xAC, 0x89, /* 0x44-0x47 */ - 0xAC, 0x8A, 0xAC, 0x8B, 0xAC, 0x8C, 0xAC, 0x8D, /* 0x48-0x4B */ - 0xAC, 0x8E, 0xAC, 0x8F, 0xAC, 0x90, 0xAC, 0x91, /* 0x4C-0x4F */ - 0xAC, 0x92, 0xAC, 0x93, 0xAC, 0x94, 0xAC, 0x95, /* 0x50-0x53 */ - 0xAC, 0x96, 0xAC, 0x97, 0xAC, 0x98, 0xAC, 0x99, /* 0x54-0x57 */ - 0xAC, 0x9A, 0xAC, 0x9B, 0xAC, 0x9C, 0xAC, 0x9D, /* 0x58-0x5B */ - 0xC3, 0xD6, 0xAC, 0x9E, 0xAC, 0x9F, 0xAC, 0xA0, /* 0x5C-0x5F */ - 0xC3, 0xD7, 0xAD, 0x41, 0xAD, 0x42, 0xAD, 0x43, /* 0x60-0x63 */ - 0xC3, 0xD8, 0xAD, 0x44, 0xAD, 0x45, 0xAD, 0x46, /* 0x64-0x67 */ - 0xAD, 0x47, 0xAD, 0x48, 0xAD, 0x49, 0xAD, 0x4A, /* 0x68-0x6B */ - 0xC3, 0xD9, 0xC3, 0xDA, 0xAD, 0x4B, 0xC3, 0xDB, /* 0x6C-0x6F */ - 0xAD, 0x4C, 0xC3, 0xDC, 0xAD, 0x4D, 0xAD, 0x4E, /* 0x70-0x73 */ - 0xAD, 0x4F, 0xAD, 0x50, 0xAD, 0x51, 0xAD, 0x52, /* 0x74-0x77 */ - 0xC3, 0xDD, 0xAD, 0x53, 0xAD, 0x54, 0xAD, 0x55, /* 0x78-0x7B */ - 0xAD, 0x56, 0xAD, 0x57, 0xAD, 0x58, 0xAD, 0x59, /* 0x7C-0x7F */ - - 0xAD, 0x5A, 0xAD, 0x61, 0xAD, 0x62, 0xAD, 0x63, /* 0x80-0x83 */ - 0xAD, 0x64, 0xAD, 0x65, 0xAD, 0x66, 0xAD, 0x67, /* 0x84-0x87 */ - 0xC3, 0xDE, 0xAD, 0x68, 0xAD, 0x69, 0xAD, 0x6A, /* 0x88-0x8B */ - 0xAD, 0x6B, 0xAD, 0x6C, 0xAD, 0x6D, 0xAD, 0x6E, /* 0x8C-0x8F */ - 0xAD, 0x6F, 0xAD, 0x70, 0xAD, 0x71, 0xAD, 0x72, /* 0x90-0x93 */ - 0xC3, 0xDF, 0xC3, 0xE0, 0xAD, 0x73, 0xAD, 0x74, /* 0x94-0x97 */ - 0xC3, 0xE1, 0xAD, 0x75, 0xAD, 0x76, 0xAD, 0x77, /* 0x98-0x9B */ - 0xC3, 0xE2, 0xAD, 0x78, 0xAD, 0x79, 0xAD, 0x7A, /* 0x9C-0x9F */ - 0xAD, 0x81, 0xAD, 0x82, 0xAD, 0x83, 0xAD, 0x84, /* 0xA0-0xA3 */ - 0xC3, 0xE3, 0xC3, 0xE4, 0xAD, 0x85, 0xC3, 0xE5, /* 0xA4-0xA7 */ - 0xAD, 0x86, 0xC3, 0xE6, 0xAD, 0x87, 0xAD, 0x88, /* 0xA8-0xAB */ - 0xAD, 0x89, 0xAD, 0x8A, 0xAD, 0x8B, 0xAD, 0x8C, /* 0xAC-0xAF */ - 0xC3, 0xE7, 0xAD, 0x8D, 0xAD, 0x8E, 0xAD, 0x8F, /* 0xB0-0xB3 */ - 0xAD, 0x90, 0xAD, 0x91, 0xAD, 0x92, 0xAD, 0x93, /* 0xB4-0xB7 */ - 0xAD, 0x94, 0xAD, 0x95, 0xAD, 0x96, 0xAD, 0x97, /* 0xB8-0xBB */ - 0xAD, 0x98, 0xAD, 0x99, 0xAD, 0x9A, 0xAD, 0x9B, /* 0xBC-0xBF */ - 0xAD, 0x9C, 0xAD, 0x9D, 0xAD, 0x9E, 0xAD, 0x9F, /* 0xC0-0xC3 */ - 0xC3, 0xE8, 0xAD, 0xA0, 0xAE, 0x41, 0xAE, 0x42, /* 0xC4-0xC7 */ - 0xAE, 0x43, 0xAE, 0x44, 0xAE, 0x45, 0xAE, 0x46, /* 0xC8-0xCB */ - 0xC3, 0xE9, 0xAE, 0x47, 0xAE, 0x48, 0xAE, 0x49, /* 0xCC-0xCF */ - 0xC3, 0xEA, 0xAE, 0x4A, 0xAE, 0x4B, 0xAE, 0x4C, /* 0xD0-0xD3 */ - 0xAE, 0x4D, 0xAE, 0x4E, 0xAE, 0x4F, 0xAE, 0x50, /* 0xD4-0xD7 */ - 0xAE, 0x51, 0xAE, 0x52, 0xAE, 0x53, 0xAE, 0x54, /* 0xD8-0xDB */ - 0xAE, 0x55, 0xAE, 0x56, 0xAE, 0x57, 0xAE, 0x58, /* 0xDC-0xDF */ - 0xAE, 0x59, 0xAE, 0x5A, 0xAE, 0x61, 0xAE, 0x62, /* 0xE0-0xE3 */ - 0xAE, 0x63, 0xAE, 0x64, 0xAE, 0x65, 0xAE, 0x66, /* 0xE4-0xE7 */ - 0xC3, 0xEB, 0xAE, 0x67, 0xAE, 0x68, 0xAE, 0x69, /* 0xE8-0xEB */ - 0xC3, 0xEC, 0xAE, 0x6A, 0xAE, 0x6B, 0xAE, 0x6C, /* 0xEC-0xEF */ - 0xC3, 0xED, 0xAE, 0x6D, 0xAE, 0x6E, 0xAE, 0x6F, /* 0xF0-0xF3 */ - 0xAE, 0x70, 0xAE, 0x71, 0xAE, 0x72, 0xAE, 0x73, /* 0xF4-0xF7 */ - 0xC3, 0xEE, 0xC3, 0xEF, 0xAE, 0x74, 0xC3, 0xF0, /* 0xF8-0xFB */ - 0xAE, 0x75, 0xC3, 0xF1, 0xAE, 0x76, 0xAE, 0x77, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_CE[512] = { - 0xAE, 0x78, 0xAE, 0x79, 0xAE, 0x7A, 0xAE, 0x81, /* 0x00-0x03 */ - 0xC3, 0xF2, 0xAE, 0x82, 0xAE, 0x83, 0xAE, 0x84, /* 0x04-0x07 */ - 0xC3, 0xF3, 0xAE, 0x85, 0xAE, 0x86, 0xAE, 0x87, /* 0x08-0x0B */ - 0xC3, 0xF4, 0xAE, 0x88, 0xAE, 0x89, 0xAE, 0x8A, /* 0x0C-0x0F */ - 0xAE, 0x8B, 0xAE, 0x8C, 0xAE, 0x8D, 0xAE, 0x8E, /* 0x10-0x13 */ - 0xC3, 0xF5, 0xAE, 0x8F, 0xAE, 0x90, 0xAE, 0x91, /* 0x14-0x17 */ - 0xAE, 0x92, 0xC3, 0xF6, 0xAE, 0x93, 0xAE, 0x94, /* 0x18-0x1B */ - 0xAE, 0x95, 0xAE, 0x96, 0xAE, 0x97, 0xAE, 0x98, /* 0x1C-0x1F */ - 0xC3, 0xF7, 0xC3, 0xF8, 0xAE, 0x99, 0xAE, 0x9A, /* 0x20-0x23 */ - 0xC3, 0xF9, 0xAE, 0x9B, 0xAE, 0x9C, 0xAE, 0x9D, /* 0x24-0x27 */ - 0xC3, 0xFA, 0xAE, 0x9E, 0xAE, 0x9F, 0xAE, 0xA0, /* 0x28-0x2B */ - 0xAF, 0x41, 0xAF, 0x42, 0xAF, 0x43, 0xAF, 0x44, /* 0x2C-0x2F */ - 0xC3, 0xFB, 0xC3, 0xFC, 0xAF, 0x45, 0xC3, 0xFD, /* 0x30-0x33 */ - 0xAF, 0x46, 0xC3, 0xFE, 0xAF, 0x47, 0xAF, 0x48, /* 0x34-0x37 */ - 0xAF, 0x49, 0xAF, 0x4A, 0xAF, 0x4B, 0xAF, 0x4C, /* 0x38-0x3B */ - 0xAF, 0x4D, 0xAF, 0x4E, 0xAF, 0x4F, 0xAF, 0x50, /* 0x3C-0x3F */ - 0xAF, 0x51, 0xAF, 0x52, 0xAF, 0x53, 0xAF, 0x54, /* 0x40-0x43 */ - 0xAF, 0x55, 0xAF, 0x56, 0xAF, 0x57, 0xAF, 0x58, /* 0x44-0x47 */ - 0xAF, 0x59, 0xAF, 0x5A, 0xAF, 0x61, 0xAF, 0x62, /* 0x48-0x4B */ - 0xAF, 0x63, 0xAF, 0x64, 0xAF, 0x65, 0xAF, 0x66, /* 0x4C-0x4F */ - 0xAF, 0x67, 0xAF, 0x68, 0xAF, 0x69, 0xAF, 0x6A, /* 0x50-0x53 */ - 0xAF, 0x6B, 0xAF, 0x6C, 0xAF, 0x6D, 0xAF, 0x6E, /* 0x54-0x57 */ - 0xC4, 0xA1, 0xC4, 0xA2, 0xAF, 0x6F, 0xAF, 0x70, /* 0x58-0x5B */ - 0xC4, 0xA3, 0xAF, 0x71, 0xAF, 0x72, 0xC4, 0xA4, /* 0x5C-0x5F */ - 0xC4, 0xA5, 0xC4, 0xA6, 0xAF, 0x73, 0xAF, 0x74, /* 0x60-0x63 */ - 0xAF, 0x75, 0xAF, 0x76, 0xAF, 0x77, 0xAF, 0x78, /* 0x64-0x67 */ - 0xC4, 0xA7, 0xC4, 0xA8, 0xAF, 0x79, 0xC4, 0xA9, /* 0x68-0x6B */ - 0xAF, 0x7A, 0xC4, 0xAA, 0xAF, 0x81, 0xAF, 0x82, /* 0x6C-0x6F */ - 0xAF, 0x83, 0xAF, 0x84, 0xAF, 0x85, 0xAF, 0x86, /* 0x70-0x73 */ - 0xC4, 0xAB, 0xC4, 0xAC, 0xAF, 0x87, 0xAF, 0x88, /* 0x74-0x77 */ - 0xC4, 0xAD, 0xAF, 0x89, 0xAF, 0x8A, 0xAF, 0x8B, /* 0x78-0x7B */ - 0xC4, 0xAE, 0xAF, 0x8C, 0xAF, 0x8D, 0xAF, 0x8E, /* 0x7C-0x7F */ - - 0xAF, 0x8F, 0xAF, 0x90, 0xAF, 0x91, 0xAF, 0x92, /* 0x80-0x83 */ - 0xC4, 0xAF, 0xC4, 0xB0, 0xAF, 0x93, 0xC4, 0xB1, /* 0x84-0x87 */ - 0xAF, 0x94, 0xC4, 0xB2, 0xAF, 0x95, 0xAF, 0x96, /* 0x88-0x8B */ - 0xAF, 0x97, 0xAF, 0x98, 0xAF, 0x99, 0xAF, 0x9A, /* 0x8C-0x8F */ - 0xC4, 0xB3, 0xC4, 0xB4, 0xAF, 0x9B, 0xAF, 0x9C, /* 0x90-0x93 */ - 0xC4, 0xB5, 0xAF, 0x9D, 0xAF, 0x9E, 0xAF, 0x9F, /* 0x94-0x97 */ - 0xC4, 0xB6, 0xAF, 0xA0, 0xB0, 0x41, 0xB0, 0x42, /* 0x98-0x9B */ - 0xB0, 0x43, 0xB0, 0x44, 0xB0, 0x45, 0xB0, 0x46, /* 0x9C-0x9F */ - 0xC4, 0xB7, 0xC4, 0xB8, 0xB0, 0x47, 0xC4, 0xB9, /* 0xA0-0xA3 */ - 0xC4, 0xBA, 0xC4, 0xBB, 0xB0, 0x48, 0xB0, 0x49, /* 0xA4-0xA7 */ - 0xB0, 0x4A, 0xB0, 0x4B, 0xB0, 0x4C, 0xB0, 0x4D, /* 0xA8-0xAB */ - 0xC4, 0xBC, 0xC4, 0xBD, 0xB0, 0x4E, 0xB0, 0x4F, /* 0xAC-0xAF */ - 0xB0, 0x50, 0xB0, 0x51, 0xB0, 0x52, 0xB0, 0x53, /* 0xB0-0xB3 */ - 0xB0, 0x54, 0xB0, 0x55, 0xB0, 0x56, 0xB0, 0x57, /* 0xB4-0xB7 */ - 0xB0, 0x58, 0xB0, 0x59, 0xB0, 0x5A, 0xB0, 0x61, /* 0xB8-0xBB */ - 0xB0, 0x62, 0xB0, 0x63, 0xB0, 0x64, 0xB0, 0x65, /* 0xBC-0xBF */ - 0xB0, 0x66, 0xC4, 0xBE, 0xB0, 0x67, 0xB0, 0x68, /* 0xC0-0xC3 */ - 0xB0, 0x69, 0xB0, 0x6A, 0xB0, 0x6B, 0xB0, 0x6C, /* 0xC4-0xC7 */ - 0xB0, 0x6D, 0xB0, 0x6E, 0xB0, 0x6F, 0xB0, 0x70, /* 0xC8-0xCB */ - 0xB0, 0x71, 0xB0, 0x72, 0xB0, 0x73, 0xB0, 0x74, /* 0xCC-0xCF */ - 0xB0, 0x75, 0xB0, 0x76, 0xB0, 0x77, 0xB0, 0x78, /* 0xD0-0xD3 */ - 0xB0, 0x79, 0xB0, 0x7A, 0xB0, 0x81, 0xB0, 0x82, /* 0xD4-0xD7 */ - 0xB0, 0x83, 0xB0, 0x84, 0xB0, 0x85, 0xB0, 0x86, /* 0xD8-0xDB */ - 0xB0, 0x87, 0xB0, 0x88, 0xB0, 0x89, 0xB0, 0x8A, /* 0xDC-0xDF */ - 0xB0, 0x8B, 0xB0, 0x8C, 0xB0, 0x8D, 0xB0, 0x8E, /* 0xE0-0xE3 */ - 0xC4, 0xBF, 0xC4, 0xC0, 0xB0, 0x8F, 0xB0, 0x90, /* 0xE4-0xE7 */ - 0xC4, 0xC1, 0xB0, 0x91, 0xB0, 0x92, 0xC4, 0xC2, /* 0xE8-0xEB */ - 0xC4, 0xC3, 0xB0, 0x93, 0xB0, 0x94, 0xB0, 0x95, /* 0xEC-0xEF */ - 0xB0, 0x96, 0xB0, 0x97, 0xB0, 0x98, 0xB0, 0x99, /* 0xF0-0xF3 */ - 0xC4, 0xC4, 0xC4, 0xC5, 0xB0, 0x9A, 0xC4, 0xC6, /* 0xF4-0xF7 */ - 0xC4, 0xC7, 0xC4, 0xC8, 0xB0, 0x9B, 0xB0, 0x9C, /* 0xF8-0xFB */ - 0xB0, 0x9D, 0xB0, 0x9E, 0xB0, 0x9F, 0xB0, 0xA0, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_CF[512] = { - 0xC4, 0xC9, 0xC4, 0xCA, 0xB1, 0x41, 0xB1, 0x42, /* 0x00-0x03 */ - 0xC4, 0xCB, 0xB1, 0x43, 0xB1, 0x44, 0xB1, 0x45, /* 0x04-0x07 */ - 0xC4, 0xCC, 0xB1, 0x46, 0xB1, 0x47, 0xB1, 0x48, /* 0x08-0x0B */ - 0xB1, 0x49, 0xB1, 0x4A, 0xB1, 0x4B, 0xB1, 0x4C, /* 0x0C-0x0F */ - 0xC4, 0xCD, 0xC4, 0xCE, 0xB1, 0x4D, 0xC4, 0xCF, /* 0x10-0x13 */ - 0xB1, 0x4E, 0xC4, 0xD0, 0xB1, 0x4F, 0xB1, 0x50, /* 0x14-0x17 */ - 0xB1, 0x51, 0xB1, 0x52, 0xB1, 0x53, 0xB1, 0x54, /* 0x18-0x1B */ - 0xC4, 0xD1, 0xB1, 0x55, 0xB1, 0x56, 0xB1, 0x57, /* 0x1C-0x1F */ - 0xC4, 0xD2, 0xB1, 0x58, 0xB1, 0x59, 0xB1, 0x5A, /* 0x20-0x23 */ - 0xC4, 0xD3, 0xB1, 0x61, 0xB1, 0x62, 0xB1, 0x63, /* 0x24-0x27 */ - 0xB1, 0x64, 0xB1, 0x65, 0xB1, 0x66, 0xB1, 0x67, /* 0x28-0x2B */ - 0xC4, 0xD4, 0xC4, 0xD5, 0xB1, 0x68, 0xC4, 0xD6, /* 0x2C-0x2F */ - 0xC4, 0xD7, 0xC4, 0xD8, 0xB1, 0x69, 0xB1, 0x6A, /* 0x30-0x33 */ - 0xB1, 0x6B, 0xB1, 0x6C, 0xB1, 0x6D, 0xB1, 0x6E, /* 0x34-0x37 */ - 0xC4, 0xD9, 0xB1, 0x6F, 0xB1, 0x70, 0xB1, 0x71, /* 0x38-0x3B */ - 0xB1, 0x72, 0xB1, 0x73, 0xB1, 0x74, 0xB1, 0x75, /* 0x3C-0x3F */ - 0xB1, 0x76, 0xB1, 0x77, 0xB1, 0x78, 0xB1, 0x79, /* 0x40-0x43 */ - 0xB1, 0x7A, 0xB1, 0x81, 0xB1, 0x82, 0xB1, 0x83, /* 0x44-0x47 */ - 0xB1, 0x84, 0xB1, 0x85, 0xB1, 0x86, 0xB1, 0x87, /* 0x48-0x4B */ - 0xB1, 0x88, 0xB1, 0x89, 0xB1, 0x8A, 0xB1, 0x8B, /* 0x4C-0x4F */ - 0xB1, 0x8C, 0xB1, 0x8D, 0xB1, 0x8E, 0xB1, 0x8F, /* 0x50-0x53 */ - 0xC4, 0xDA, 0xC4, 0xDB, 0xB1, 0x90, 0xB1, 0x91, /* 0x54-0x57 */ - 0xC4, 0xDC, 0xB1, 0x92, 0xB1, 0x93, 0xB1, 0x94, /* 0x58-0x5B */ - 0xC4, 0xDD, 0xB1, 0x95, 0xB1, 0x96, 0xB1, 0x97, /* 0x5C-0x5F */ - 0xB1, 0x98, 0xB1, 0x99, 0xB1, 0x9A, 0xB1, 0x9B, /* 0x60-0x63 */ - 0xC4, 0xDE, 0xC4, 0xDF, 0xB1, 0x9C, 0xC4, 0xE0, /* 0x64-0x67 */ - 0xB1, 0x9D, 0xC4, 0xE1, 0xB1, 0x9E, 0xB1, 0x9F, /* 0x68-0x6B */ - 0xB1, 0xA0, 0xB2, 0x41, 0xB2, 0x42, 0xB2, 0x43, /* 0x6C-0x6F */ - 0xC4, 0xE2, 0xC4, 0xE3, 0xB2, 0x44, 0xB2, 0x45, /* 0x70-0x73 */ - 0xC4, 0xE4, 0xB2, 0x46, 0xB2, 0x47, 0xB2, 0x48, /* 0x74-0x77 */ - 0xC4, 0xE5, 0xB2, 0x49, 0xB2, 0x4A, 0xB2, 0x4B, /* 0x78-0x7B */ - 0xB2, 0x4C, 0xB2, 0x4D, 0xB2, 0x4E, 0xB2, 0x4F, /* 0x7C-0x7F */ - - 0xC4, 0xE6, 0xB2, 0x50, 0xB2, 0x51, 0xB2, 0x52, /* 0x80-0x83 */ - 0xB2, 0x53, 0xC4, 0xE7, 0xB2, 0x54, 0xB2, 0x55, /* 0x84-0x87 */ - 0xB2, 0x56, 0xB2, 0x57, 0xB2, 0x58, 0xB2, 0x59, /* 0x88-0x8B */ - 0xC4, 0xE8, 0xB2, 0x5A, 0xB2, 0x61, 0xB2, 0x62, /* 0x8C-0x8F */ - 0xB2, 0x63, 0xB2, 0x64, 0xB2, 0x65, 0xB2, 0x66, /* 0x90-0x93 */ - 0xB2, 0x67, 0xB2, 0x68, 0xB2, 0x69, 0xB2, 0x6A, /* 0x94-0x97 */ - 0xB2, 0x6B, 0xB2, 0x6C, 0xB2, 0x6D, 0xB2, 0x6E, /* 0x98-0x9B */ - 0xB2, 0x6F, 0xB2, 0x70, 0xB2, 0x71, 0xB2, 0x72, /* 0x9C-0x9F */ - 0xB2, 0x73, 0xC4, 0xE9, 0xB2, 0x74, 0xB2, 0x75, /* 0xA0-0xA3 */ - 0xB2, 0x76, 0xB2, 0x77, 0xB2, 0x78, 0xB2, 0x79, /* 0xA4-0xA7 */ - 0xC4, 0xEA, 0xB2, 0x7A, 0xB2, 0x81, 0xB2, 0x82, /* 0xA8-0xAB */ - 0xB2, 0x83, 0xB2, 0x84, 0xB2, 0x85, 0xB2, 0x86, /* 0xAC-0xAF */ - 0xC4, 0xEB, 0xB2, 0x87, 0xB2, 0x88, 0xB2, 0x89, /* 0xB0-0xB3 */ - 0xB2, 0x8A, 0xB2, 0x8B, 0xB2, 0x8C, 0xB2, 0x8D, /* 0xB4-0xB7 */ - 0xB2, 0x8E, 0xB2, 0x8F, 0xB2, 0x90, 0xB2, 0x91, /* 0xB8-0xBB */ - 0xB2, 0x92, 0xB2, 0x93, 0xB2, 0x94, 0xB2, 0x95, /* 0xBC-0xBF */ - 0xB2, 0x96, 0xB2, 0x97, 0xB2, 0x98, 0xB2, 0x99, /* 0xC0-0xC3 */ - 0xC4, 0xEC, 0xB2, 0x9A, 0xB2, 0x9B, 0xB2, 0x9C, /* 0xC4-0xC7 */ - 0xB2, 0x9D, 0xB2, 0x9E, 0xB2, 0x9F, 0xB2, 0xA0, /* 0xC8-0xCB */ - 0xB3, 0x41, 0xB3, 0x42, 0xB3, 0x43, 0xB3, 0x44, /* 0xCC-0xCF */ - 0xB3, 0x45, 0xB3, 0x46, 0xB3, 0x47, 0xB3, 0x48, /* 0xD0-0xD3 */ - 0xB3, 0x49, 0xB3, 0x4A, 0xB3, 0x4B, 0xB3, 0x4C, /* 0xD4-0xD7 */ - 0xB3, 0x4D, 0xB3, 0x4E, 0xB3, 0x4F, 0xB3, 0x50, /* 0xD8-0xDB */ - 0xB3, 0x51, 0xB3, 0x52, 0xB3, 0x53, 0xB3, 0x54, /* 0xDC-0xDF */ - 0xC4, 0xED, 0xC4, 0xEE, 0xB3, 0x55, 0xB3, 0x56, /* 0xE0-0xE3 */ - 0xC4, 0xEF, 0xB3, 0x57, 0xB3, 0x58, 0xB3, 0x59, /* 0xE4-0xE7 */ - 0xC4, 0xF0, 0xB3, 0x5A, 0xB3, 0x61, 0xB3, 0x62, /* 0xE8-0xEB */ - 0xB3, 0x63, 0xB3, 0x64, 0xB3, 0x65, 0xB3, 0x66, /* 0xEC-0xEF */ - 0xC4, 0xF1, 0xC4, 0xF2, 0xB3, 0x67, 0xC4, 0xF3, /* 0xF0-0xF3 */ - 0xB3, 0x68, 0xC4, 0xF4, 0xB3, 0x69, 0xB3, 0x6A, /* 0xF4-0xF7 */ - 0xB3, 0x6B, 0xB3, 0x6C, 0xB3, 0x6D, 0xB3, 0x6E, /* 0xF8-0xFB */ - 0xC4, 0xF5, 0xB3, 0x6F, 0xB3, 0x70, 0xB3, 0x71, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_D0[512] = { - 0xC4, 0xF6, 0xB3, 0x72, 0xB3, 0x73, 0xB3, 0x74, /* 0x00-0x03 */ - 0xC4, 0xF7, 0xB3, 0x75, 0xB3, 0x76, 0xB3, 0x77, /* 0x04-0x07 */ - 0xB3, 0x78, 0xB3, 0x79, 0xB3, 0x7A, 0xB3, 0x81, /* 0x08-0x0B */ - 0xB3, 0x82, 0xB3, 0x83, 0xB3, 0x84, 0xB3, 0x85, /* 0x0C-0x0F */ - 0xB3, 0x86, 0xC4, 0xF8, 0xB3, 0x87, 0xB3, 0x88, /* 0x10-0x13 */ - 0xB3, 0x89, 0xB3, 0x8A, 0xB3, 0x8B, 0xB3, 0x8C, /* 0x14-0x17 */ - 0xC4, 0xF9, 0xB3, 0x8D, 0xB3, 0x8E, 0xB3, 0x8F, /* 0x18-0x1B */ - 0xB3, 0x90, 0xB3, 0x91, 0xB3, 0x92, 0xB3, 0x93, /* 0x1C-0x1F */ - 0xB3, 0x94, 0xB3, 0x95, 0xB3, 0x96, 0xB3, 0x97, /* 0x20-0x23 */ - 0xB3, 0x98, 0xB3, 0x99, 0xB3, 0x9A, 0xB3, 0x9B, /* 0x24-0x27 */ - 0xB3, 0x9C, 0xB3, 0x9D, 0xB3, 0x9E, 0xB3, 0x9F, /* 0x28-0x2B */ - 0xB3, 0xA0, 0xC4, 0xFA, 0xB4, 0x41, 0xB4, 0x42, /* 0x2C-0x2F */ - 0xB4, 0x43, 0xB4, 0x44, 0xB4, 0x45, 0xB4, 0x46, /* 0x30-0x33 */ - 0xC4, 0xFB, 0xC4, 0xFC, 0xB4, 0x47, 0xB4, 0x48, /* 0x34-0x37 */ - 0xC4, 0xFD, 0xB4, 0x49, 0xB4, 0x4A, 0xB4, 0x4B, /* 0x38-0x3B */ - 0xC4, 0xFE, 0xB4, 0x4C, 0xB4, 0x4D, 0xB4, 0x4E, /* 0x3C-0x3F */ - 0xB4, 0x4F, 0xB4, 0x50, 0xB4, 0x51, 0xB4, 0x52, /* 0x40-0x43 */ - 0xC5, 0xA1, 0xC5, 0xA2, 0xB4, 0x53, 0xC5, 0xA3, /* 0x44-0x47 */ - 0xB4, 0x54, 0xC5, 0xA4, 0xB4, 0x55, 0xB4, 0x56, /* 0x48-0x4B */ - 0xB4, 0x57, 0xB4, 0x58, 0xB4, 0x59, 0xB4, 0x5A, /* 0x4C-0x4F */ - 0xC5, 0xA5, 0xB4, 0x61, 0xB4, 0x62, 0xB4, 0x63, /* 0x50-0x53 */ - 0xC5, 0xA6, 0xB4, 0x64, 0xB4, 0x65, 0xB4, 0x66, /* 0x54-0x57 */ - 0xC5, 0xA7, 0xB4, 0x67, 0xB4, 0x68, 0xB4, 0x69, /* 0x58-0x5B */ - 0xB4, 0x6A, 0xB4, 0x6B, 0xB4, 0x6C, 0xB4, 0x6D, /* 0x5C-0x5F */ - 0xC5, 0xA8, 0xB4, 0x6E, 0xB4, 0x6F, 0xB4, 0x70, /* 0x60-0x63 */ - 0xB4, 0x71, 0xB4, 0x72, 0xB4, 0x73, 0xB4, 0x74, /* 0x64-0x67 */ - 0xB4, 0x75, 0xB4, 0x76, 0xB4, 0x77, 0xB4, 0x78, /* 0x68-0x6B */ - 0xC5, 0xA9, 0xC5, 0xAA, 0xB4, 0x79, 0xB4, 0x7A, /* 0x6C-0x6F */ - 0xC5, 0xAB, 0xB4, 0x81, 0xB4, 0x82, 0xB4, 0x83, /* 0x70-0x73 */ - 0xC5, 0xAC, 0xB4, 0x84, 0xB4, 0x85, 0xB4, 0x86, /* 0x74-0x77 */ - 0xB4, 0x87, 0xB4, 0x88, 0xB4, 0x89, 0xB4, 0x8A, /* 0x78-0x7B */ - 0xC5, 0xAD, 0xC5, 0xAE, 0xB4, 0x8B, 0xB4, 0x8C, /* 0x7C-0x7F */ - - 0xB4, 0x8D, 0xC5, 0xAF, 0xB4, 0x8E, 0xB4, 0x8F, /* 0x80-0x83 */ - 0xB4, 0x90, 0xB4, 0x91, 0xB4, 0x92, 0xB4, 0x93, /* 0x84-0x87 */ - 0xB4, 0x94, 0xB4, 0x95, 0xB4, 0x96, 0xB4, 0x97, /* 0x88-0x8B */ - 0xB4, 0x98, 0xB4, 0x99, 0xB4, 0x9A, 0xB4, 0x9B, /* 0x8C-0x8F */ - 0xB4, 0x9C, 0xB4, 0x9D, 0xB4, 0x9E, 0xB4, 0x9F, /* 0x90-0x93 */ - 0xB4, 0xA0, 0xB5, 0x41, 0xB5, 0x42, 0xB5, 0x43, /* 0x94-0x97 */ - 0xB5, 0x44, 0xB5, 0x45, 0xB5, 0x46, 0xB5, 0x47, /* 0x98-0x9B */ - 0xB5, 0x48, 0xB5, 0x49, 0xB5, 0x4A, 0xB5, 0x4B, /* 0x9C-0x9F */ - 0xB5, 0x4C, 0xB5, 0x4D, 0xB5, 0x4E, 0xB5, 0x4F, /* 0xA0-0xA3 */ - 0xC5, 0xB0, 0xC5, 0xB1, 0xB5, 0x50, 0xB5, 0x51, /* 0xA4-0xA7 */ - 0xC5, 0xB2, 0xB5, 0x52, 0xB5, 0x53, 0xB5, 0x54, /* 0xA8-0xAB */ - 0xC5, 0xB3, 0xB5, 0x55, 0xB5, 0x56, 0xB5, 0x57, /* 0xAC-0xAF */ - 0xB5, 0x58, 0xB5, 0x59, 0xB5, 0x5A, 0xB5, 0x61, /* 0xB0-0xB3 */ - 0xC5, 0xB4, 0xC5, 0xB5, 0xB5, 0x62, 0xC5, 0xB6, /* 0xB4-0xB7 */ - 0xB5, 0x63, 0xC5, 0xB7, 0xB5, 0x64, 0xB5, 0x65, /* 0xB8-0xBB */ - 0xB5, 0x66, 0xB5, 0x67, 0xB5, 0x68, 0xB5, 0x69, /* 0xBC-0xBF */ - 0xC5, 0xB8, 0xC5, 0xB9, 0xB5, 0x6A, 0xB5, 0x6B, /* 0xC0-0xC3 */ - 0xC5, 0xBA, 0xB5, 0x6C, 0xB5, 0x6D, 0xB5, 0x6E, /* 0xC4-0xC7 */ - 0xC5, 0xBB, 0xC5, 0xBC, 0xB5, 0x6F, 0xB5, 0x70, /* 0xC8-0xCB */ - 0xB5, 0x71, 0xB5, 0x72, 0xB5, 0x73, 0xB5, 0x74, /* 0xCC-0xCF */ - 0xC5, 0xBD, 0xC5, 0xBE, 0xB5, 0x75, 0xC5, 0xBF, /* 0xD0-0xD3 */ - 0xC5, 0xC0, 0xC5, 0xC1, 0xB5, 0x76, 0xB5, 0x77, /* 0xD4-0xD7 */ - 0xB5, 0x78, 0xB5, 0x79, 0xB5, 0x7A, 0xB5, 0x81, /* 0xD8-0xDB */ - 0xC5, 0xC2, 0xC5, 0xC3, 0xB5, 0x82, 0xB5, 0x83, /* 0xDC-0xDF */ - 0xC5, 0xC4, 0xB5, 0x84, 0xB5, 0x85, 0xB5, 0x86, /* 0xE0-0xE3 */ - 0xC5, 0xC5, 0xB5, 0x87, 0xB5, 0x88, 0xB5, 0x89, /* 0xE4-0xE7 */ - 0xB5, 0x8A, 0xB5, 0x8B, 0xB5, 0x8C, 0xB5, 0x8D, /* 0xE8-0xEB */ - 0xC5, 0xC6, 0xC5, 0xC7, 0xB5, 0x8E, 0xC5, 0xC8, /* 0xEC-0xEF */ - 0xC5, 0xC9, 0xC5, 0xCA, 0xB5, 0x8F, 0xB5, 0x90, /* 0xF0-0xF3 */ - 0xB5, 0x91, 0xB5, 0x92, 0xB5, 0x93, 0xB5, 0x94, /* 0xF4-0xF7 */ - 0xC5, 0xCB, 0xB5, 0x95, 0xB5, 0x96, 0xB5, 0x97, /* 0xF8-0xFB */ - 0xB5, 0x98, 0xB5, 0x99, 0xB5, 0x9A, 0xB5, 0x9B, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_D1[512] = { - 0xB5, 0x9C, 0xB5, 0x9D, 0xB5, 0x9E, 0xB5, 0x9F, /* 0x00-0x03 */ - 0xB5, 0xA0, 0xB6, 0x41, 0xB6, 0x42, 0xB6, 0x43, /* 0x04-0x07 */ - 0xB6, 0x44, 0xB6, 0x45, 0xB6, 0x46, 0xB6, 0x47, /* 0x08-0x0B */ - 0xB6, 0x48, 0xC5, 0xCC, 0xB6, 0x49, 0xB6, 0x4A, /* 0x0C-0x0F */ - 0xB6, 0x4B, 0xB6, 0x4C, 0xB6, 0x4D, 0xB6, 0x4E, /* 0x10-0x13 */ - 0xB6, 0x4F, 0xB6, 0x50, 0xB6, 0x51, 0xB6, 0x52, /* 0x14-0x17 */ - 0xB6, 0x53, 0xB6, 0x54, 0xB6, 0x55, 0xB6, 0x56, /* 0x18-0x1B */ - 0xB6, 0x57, 0xB6, 0x58, 0xB6, 0x59, 0xB6, 0x5A, /* 0x1C-0x1F */ - 0xB6, 0x61, 0xB6, 0x62, 0xB6, 0x63, 0xB6, 0x64, /* 0x20-0x23 */ - 0xB6, 0x65, 0xB6, 0x66, 0xB6, 0x67, 0xB6, 0x68, /* 0x24-0x27 */ - 0xB6, 0x69, 0xB6, 0x6A, 0xB6, 0x6B, 0xB6, 0x6C, /* 0x28-0x2B */ - 0xB6, 0x6D, 0xB6, 0x6E, 0xB6, 0x6F, 0xB6, 0x70, /* 0x2C-0x2F */ - 0xC5, 0xCD, 0xC5, 0xCE, 0xB6, 0x71, 0xB6, 0x72, /* 0x30-0x33 */ - 0xC5, 0xCF, 0xB6, 0x73, 0xB6, 0x74, 0xB6, 0x75, /* 0x34-0x37 */ - 0xC5, 0xD0, 0xB6, 0x76, 0xC5, 0xD1, 0xB6, 0x77, /* 0x38-0x3B */ - 0xB6, 0x78, 0xB6, 0x79, 0xB6, 0x7A, 0xB6, 0x81, /* 0x3C-0x3F */ - 0xC5, 0xD2, 0xC5, 0xD3, 0xB6, 0x82, 0xC5, 0xD4, /* 0x40-0x43 */ - 0xC5, 0xD5, 0xC5, 0xD6, 0xB6, 0x83, 0xB6, 0x84, /* 0x44-0x47 */ - 0xB6, 0x85, 0xB6, 0x86, 0xB6, 0x87, 0xB6, 0x88, /* 0x48-0x4B */ - 0xC5, 0xD7, 0xC5, 0xD8, 0xB6, 0x89, 0xB6, 0x8A, /* 0x4C-0x4F */ - 0xC5, 0xD9, 0xB6, 0x8B, 0xB6, 0x8C, 0xB6, 0x8D, /* 0x50-0x53 */ - 0xC5, 0xDA, 0xB6, 0x8E, 0xB6, 0x8F, 0xB6, 0x90, /* 0x54-0x57 */ - 0xB6, 0x91, 0xB6, 0x92, 0xB6, 0x93, 0xB6, 0x94, /* 0x58-0x5B */ - 0xC5, 0xDB, 0xC5, 0xDC, 0xB6, 0x95, 0xC5, 0xDD, /* 0x5C-0x5F */ - 0xB6, 0x96, 0xC5, 0xDE, 0xB6, 0x97, 0xB6, 0x98, /* 0x60-0x63 */ - 0xB6, 0x99, 0xB6, 0x9A, 0xB6, 0x9B, 0xB6, 0x9C, /* 0x64-0x67 */ - 0xC5, 0xDF, 0xB6, 0x9D, 0xB6, 0x9E, 0xB6, 0x9F, /* 0x68-0x6B */ - 0xC5, 0xE0, 0xB6, 0xA0, 0xB7, 0x41, 0xB7, 0x42, /* 0x6C-0x6F */ - 0xB7, 0x43, 0xB7, 0x44, 0xB7, 0x45, 0xB7, 0x46, /* 0x70-0x73 */ - 0xB7, 0x47, 0xB7, 0x48, 0xB7, 0x49, 0xB7, 0x4A, /* 0x74-0x77 */ - 0xB7, 0x4B, 0xB7, 0x4C, 0xB7, 0x4D, 0xB7, 0x4E, /* 0x78-0x7B */ - 0xC5, 0xE1, 0xB7, 0x4F, 0xB7, 0x50, 0xB7, 0x51, /* 0x7C-0x7F */ - - 0xB7, 0x52, 0xB7, 0x53, 0xB7, 0x54, 0xB7, 0x55, /* 0x80-0x83 */ - 0xC5, 0xE2, 0xB7, 0x56, 0xB7, 0x57, 0xB7, 0x58, /* 0x84-0x87 */ - 0xC5, 0xE3, 0xB7, 0x59, 0xB7, 0x5A, 0xB7, 0x61, /* 0x88-0x8B */ - 0xB7, 0x62, 0xB7, 0x63, 0xB7, 0x64, 0xB7, 0x65, /* 0x8C-0x8F */ - 0xB7, 0x66, 0xB7, 0x67, 0xB7, 0x68, 0xB7, 0x69, /* 0x90-0x93 */ - 0xB7, 0x6A, 0xB7, 0x6B, 0xB7, 0x6C, 0xB7, 0x6D, /* 0x94-0x97 */ - 0xB7, 0x6E, 0xB7, 0x6F, 0xB7, 0x70, 0xB7, 0x71, /* 0x98-0x9B */ - 0xB7, 0x72, 0xB7, 0x73, 0xB7, 0x74, 0xB7, 0x75, /* 0x9C-0x9F */ - 0xC5, 0xE4, 0xC5, 0xE5, 0xB7, 0x76, 0xB7, 0x77, /* 0xA0-0xA3 */ - 0xC5, 0xE6, 0xB7, 0x78, 0xB7, 0x79, 0xB7, 0x7A, /* 0xA4-0xA7 */ - 0xC5, 0xE7, 0xB7, 0x81, 0xB7, 0x82, 0xB7, 0x83, /* 0xA8-0xAB */ - 0xB7, 0x84, 0xB7, 0x85, 0xB7, 0x86, 0xB7, 0x87, /* 0xAC-0xAF */ - 0xC5, 0xE8, 0xC5, 0xE9, 0xB7, 0x88, 0xC5, 0xEA, /* 0xB0-0xB3 */ - 0xB7, 0x89, 0xC5, 0xEB, 0xB7, 0x8A, 0xB7, 0x8B, /* 0xB4-0xB7 */ - 0xB7, 0x8C, 0xB7, 0x8D, 0xC5, 0xEC, 0xB7, 0x8E, /* 0xB8-0xBB */ - 0xC5, 0xED, 0xB7, 0x8F, 0xB7, 0x90, 0xB7, 0x91, /* 0xBC-0xBF */ - 0xC5, 0xEE, 0xB7, 0x92, 0xB7, 0x93, 0xB7, 0x94, /* 0xC0-0xC3 */ - 0xB7, 0x95, 0xB7, 0x96, 0xB7, 0x97, 0xB7, 0x98, /* 0xC4-0xC7 */ - 0xB7, 0x99, 0xB7, 0x9A, 0xB7, 0x9B, 0xB7, 0x9C, /* 0xC8-0xCB */ - 0xB7, 0x9D, 0xB7, 0x9E, 0xB7, 0x9F, 0xB7, 0xA0, /* 0xCC-0xCF */ - 0xB8, 0x41, 0xB8, 0x42, 0xB8, 0x43, 0xB8, 0x44, /* 0xD0-0xD3 */ - 0xB8, 0x45, 0xB8, 0x46, 0xB8, 0x47, 0xB8, 0x48, /* 0xD4-0xD7 */ - 0xC5, 0xEF, 0xB8, 0x49, 0xB8, 0x4A, 0xB8, 0x4B, /* 0xD8-0xDB */ - 0xB8, 0x4C, 0xB8, 0x4D, 0xB8, 0x4E, 0xB8, 0x4F, /* 0xDC-0xDF */ - 0xB8, 0x50, 0xB8, 0x51, 0xB8, 0x52, 0xB8, 0x53, /* 0xE0-0xE3 */ - 0xB8, 0x54, 0xB8, 0x55, 0xB8, 0x56, 0xB8, 0x57, /* 0xE4-0xE7 */ - 0xB8, 0x58, 0xB8, 0x59, 0xB8, 0x5A, 0xB8, 0x61, /* 0xE8-0xEB */ - 0xB8, 0x62, 0xB8, 0x63, 0xB8, 0x64, 0xB8, 0x65, /* 0xEC-0xEF */ - 0xB8, 0x66, 0xB8, 0x67, 0xB8, 0x68, 0xB8, 0x69, /* 0xF0-0xF3 */ - 0xC5, 0xF0, 0xB8, 0x6A, 0xB8, 0x6B, 0xB8, 0x6C, /* 0xF4-0xF7 */ - 0xC5, 0xF1, 0xB8, 0x6D, 0xB8, 0x6E, 0xB8, 0x6F, /* 0xF8-0xFB */ - 0xB8, 0x70, 0xB8, 0x71, 0xB8, 0x72, 0xB8, 0x73, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_D2[512] = { - 0xB8, 0x74, 0xB8, 0x75, 0xB8, 0x76, 0xB8, 0x77, /* 0x00-0x03 */ - 0xB8, 0x78, 0xB8, 0x79, 0xB8, 0x7A, 0xC5, 0xF2, /* 0x04-0x07 */ - 0xB8, 0x81, 0xC5, 0xF3, 0xB8, 0x82, 0xB8, 0x83, /* 0x08-0x0B */ - 0xB8, 0x84, 0xB8, 0x85, 0xB8, 0x86, 0xB8, 0x87, /* 0x0C-0x0F */ - 0xC5, 0xF4, 0xB8, 0x88, 0xB8, 0x89, 0xB8, 0x8A, /* 0x10-0x13 */ - 0xB8, 0x8B, 0xB8, 0x8C, 0xB8, 0x8D, 0xB8, 0x8E, /* 0x14-0x17 */ - 0xB8, 0x8F, 0xB8, 0x90, 0xB8, 0x91, 0xB8, 0x92, /* 0x18-0x1B */ - 0xB8, 0x93, 0xB8, 0x94, 0xB8, 0x95, 0xB8, 0x96, /* 0x1C-0x1F */ - 0xB8, 0x97, 0xB8, 0x98, 0xB8, 0x99, 0xB8, 0x9A, /* 0x20-0x23 */ - 0xB8, 0x9B, 0xB8, 0x9C, 0xB8, 0x9D, 0xB8, 0x9E, /* 0x24-0x27 */ - 0xB8, 0x9F, 0xB8, 0xA0, 0xB9, 0x41, 0xB9, 0x42, /* 0x28-0x2B */ - 0xC5, 0xF5, 0xC5, 0xF6, 0xB9, 0x43, 0xB9, 0x44, /* 0x2C-0x2F */ - 0xC5, 0xF7, 0xB9, 0x45, 0xB9, 0x46, 0xB9, 0x47, /* 0x30-0x33 */ - 0xC5, 0xF8, 0xB9, 0x48, 0xB9, 0x49, 0xB9, 0x4A, /* 0x34-0x37 */ - 0xB9, 0x4B, 0xB9, 0x4C, 0xB9, 0x4D, 0xB9, 0x4E, /* 0x38-0x3B */ - 0xC5, 0xF9, 0xC5, 0xFA, 0xB9, 0x4F, 0xC5, 0xFB, /* 0x3C-0x3F */ - 0xB9, 0x50, 0xC5, 0xFC, 0xB9, 0x51, 0xB9, 0x52, /* 0x40-0x43 */ - 0xB9, 0x53, 0xB9, 0x54, 0xB9, 0x55, 0xB9, 0x56, /* 0x44-0x47 */ - 0xC5, 0xFD, 0xB9, 0x57, 0xB9, 0x58, 0xB9, 0x59, /* 0x48-0x4B */ - 0xB9, 0x5A, 0xB9, 0x61, 0xB9, 0x62, 0xB9, 0x63, /* 0x4C-0x4F */ - 0xB9, 0x64, 0xB9, 0x65, 0xB9, 0x66, 0xB9, 0x67, /* 0x50-0x53 */ - 0xB9, 0x68, 0xB9, 0x69, 0xB9, 0x6A, 0xB9, 0x6B, /* 0x54-0x57 */ - 0xB9, 0x6C, 0xB9, 0x6D, 0xB9, 0x6E, 0xB9, 0x6F, /* 0x58-0x5B */ - 0xC5, 0xFE, 0xB9, 0x70, 0xB9, 0x71, 0xB9, 0x72, /* 0x5C-0x5F */ - 0xB9, 0x73, 0xB9, 0x74, 0xB9, 0x75, 0xB9, 0x76, /* 0x60-0x63 */ - 0xC6, 0xA1, 0xB9, 0x77, 0xB9, 0x78, 0xB9, 0x79, /* 0x64-0x67 */ - 0xB9, 0x7A, 0xB9, 0x81, 0xB9, 0x82, 0xB9, 0x83, /* 0x68-0x6B */ - 0xB9, 0x84, 0xB9, 0x85, 0xB9, 0x86, 0xB9, 0x87, /* 0x6C-0x6F */ - 0xB9, 0x88, 0xB9, 0x89, 0xB9, 0x8A, 0xB9, 0x8B, /* 0x70-0x73 */ - 0xB9, 0x8C, 0xB9, 0x8D, 0xB9, 0x8E, 0xB9, 0x8F, /* 0x74-0x77 */ - 0xB9, 0x90, 0xB9, 0x91, 0xB9, 0x92, 0xB9, 0x93, /* 0x78-0x7B */ - 0xB9, 0x94, 0xB9, 0x95, 0xB9, 0x96, 0xB9, 0x97, /* 0x7C-0x7F */ - - 0xC6, 0xA2, 0xC6, 0xA3, 0xB9, 0x98, 0xB9, 0x99, /* 0x80-0x83 */ - 0xC6, 0xA4, 0xB9, 0x9A, 0xB9, 0x9B, 0xB9, 0x9C, /* 0x84-0x87 */ - 0xC6, 0xA5, 0xB9, 0x9D, 0xB9, 0x9E, 0xB9, 0x9F, /* 0x88-0x8B */ - 0xB9, 0xA0, 0xBA, 0x41, 0xBA, 0x42, 0xBA, 0x43, /* 0x8C-0x8F */ - 0xC6, 0xA6, 0xC6, 0xA7, 0xBA, 0x44, 0xBA, 0x45, /* 0x90-0x93 */ - 0xBA, 0x46, 0xC6, 0xA8, 0xBA, 0x47, 0xBA, 0x48, /* 0x94-0x97 */ - 0xBA, 0x49, 0xBA, 0x4A, 0xBA, 0x4B, 0xBA, 0x4C, /* 0x98-0x9B */ - 0xC6, 0xA9, 0xBA, 0x4D, 0xBA, 0x4E, 0xBA, 0x4F, /* 0x9C-0x9F */ - 0xC6, 0xAA, 0xBA, 0x50, 0xBA, 0x51, 0xBA, 0x52, /* 0xA0-0xA3 */ - 0xC6, 0xAB, 0xBA, 0x53, 0xBA, 0x54, 0xBA, 0x55, /* 0xA4-0xA7 */ - 0xBA, 0x56, 0xBA, 0x57, 0xBA, 0x58, 0xBA, 0x59, /* 0xA8-0xAB */ - 0xC6, 0xAC, 0xBA, 0x5A, 0xBA, 0x61, 0xBA, 0x62, /* 0xAC-0xAF */ - 0xBA, 0x63, 0xC6, 0xAD, 0xBA, 0x64, 0xBA, 0x65, /* 0xB0-0xB3 */ - 0xBA, 0x66, 0xBA, 0x67, 0xBA, 0x68, 0xBA, 0x69, /* 0xB4-0xB7 */ - 0xC6, 0xAE, 0xC6, 0xAF, 0xBA, 0x6A, 0xBA, 0x6B, /* 0xB8-0xBB */ - 0xC6, 0xB0, 0xBA, 0x6C, 0xBA, 0x6D, 0xC6, 0xB1, /* 0xBC-0xBF */ - 0xC6, 0xB2, 0xBA, 0x6E, 0xC6, 0xB3, 0xBA, 0x6F, /* 0xC0-0xC3 */ - 0xBA, 0x70, 0xBA, 0x71, 0xBA, 0x72, 0xBA, 0x73, /* 0xC4-0xC7 */ - 0xC6, 0xB4, 0xC6, 0xB5, 0xBA, 0x74, 0xC6, 0xB6, /* 0xC8-0xCB */ - 0xBA, 0x75, 0xBA, 0x76, 0xBA, 0x77, 0xBA, 0x78, /* 0xCC-0xCF */ - 0xBA, 0x79, 0xBA, 0x7A, 0xBA, 0x81, 0xBA, 0x82, /* 0xD0-0xD3 */ - 0xC6, 0xB7, 0xBA, 0x83, 0xBA, 0x84, 0xBA, 0x85, /* 0xD4-0xD7 */ - 0xC6, 0xB8, 0xBA, 0x86, 0xBA, 0x87, 0xBA, 0x88, /* 0xD8-0xDB */ - 0xC6, 0xB9, 0xBA, 0x89, 0xBA, 0x8A, 0xBA, 0x8B, /* 0xDC-0xDF */ - 0xBA, 0x8C, 0xBA, 0x8D, 0xBA, 0x8E, 0xBA, 0x8F, /* 0xE0-0xE3 */ - 0xC6, 0xBA, 0xC6, 0xBB, 0xBA, 0x90, 0xBA, 0x91, /* 0xE4-0xE7 */ - 0xBA, 0x92, 0xBA, 0x93, 0xBA, 0x94, 0xBA, 0x95, /* 0xE8-0xEB */ - 0xBA, 0x96, 0xBA, 0x97, 0xBA, 0x98, 0xBA, 0x99, /* 0xEC-0xEF */ - 0xC6, 0xBC, 0xC6, 0xBD, 0xBA, 0x9A, 0xBA, 0x9B, /* 0xF0-0xF3 */ - 0xC6, 0xBE, 0xBA, 0x9C, 0xBA, 0x9D, 0xBA, 0x9E, /* 0xF4-0xF7 */ - 0xC6, 0xBF, 0xBA, 0x9F, 0xBA, 0xA0, 0xBB, 0x41, /* 0xF8-0xFB */ - 0xBB, 0x42, 0xBB, 0x43, 0xBB, 0x44, 0xBB, 0x45, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_D3[512] = { - 0xC6, 0xC0, 0xC6, 0xC1, 0xBB, 0x46, 0xC6, 0xC2, /* 0x00-0x03 */ - 0xBB, 0x47, 0xC6, 0xC3, 0xBB, 0x48, 0xBB, 0x49, /* 0x04-0x07 */ - 0xBB, 0x4A, 0xBB, 0x4B, 0xBB, 0x4C, 0xBB, 0x4D, /* 0x08-0x0B */ - 0xC6, 0xC4, 0xC6, 0xC5, 0xC6, 0xC6, 0xBB, 0x4E, /* 0x0C-0x0F */ - 0xC6, 0xC7, 0xBB, 0x4F, 0xBB, 0x50, 0xBB, 0x51, /* 0x10-0x13 */ - 0xC6, 0xC8, 0xBB, 0x52, 0xC6, 0xC9, 0xBB, 0x53, /* 0x14-0x17 */ - 0xBB, 0x54, 0xBB, 0x55, 0xBB, 0x56, 0xBB, 0x57, /* 0x18-0x1B */ - 0xC6, 0xCA, 0xC6, 0xCB, 0xBB, 0x58, 0xC6, 0xCC, /* 0x1C-0x1F */ - 0xC6, 0xCD, 0xC6, 0xCE, 0xBB, 0x59, 0xBB, 0x5A, /* 0x20-0x23 */ - 0xBB, 0x61, 0xC6, 0xCF, 0xBB, 0x62, 0xBB, 0x63, /* 0x24-0x27 */ - 0xC6, 0xD0, 0xC6, 0xD1, 0xBB, 0x64, 0xBB, 0x65, /* 0x28-0x2B */ - 0xC6, 0xD2, 0xBB, 0x66, 0xBB, 0x67, 0xBB, 0x68, /* 0x2C-0x2F */ - 0xC6, 0xD3, 0xBB, 0x69, 0xBB, 0x6A, 0xBB, 0x6B, /* 0x30-0x33 */ - 0xBB, 0x6C, 0xBB, 0x6D, 0xBB, 0x6E, 0xBB, 0x6F, /* 0x34-0x37 */ - 0xC6, 0xD4, 0xC6, 0xD5, 0xBB, 0x70, 0xC6, 0xD6, /* 0x38-0x3B */ - 0xC6, 0xD7, 0xC6, 0xD8, 0xBB, 0x71, 0xBB, 0x72, /* 0x3C-0x3F */ - 0xBB, 0x73, 0xBB, 0x74, 0xBB, 0x75, 0xBB, 0x76, /* 0x40-0x43 */ - 0xC6, 0xD9, 0xC6, 0xDA, 0xBB, 0x77, 0xBB, 0x78, /* 0x44-0x47 */ - 0xBB, 0x79, 0xBB, 0x7A, 0xBB, 0x81, 0xBB, 0x82, /* 0x48-0x4B */ - 0xBB, 0x83, 0xBB, 0x84, 0xBB, 0x85, 0xBB, 0x86, /* 0x4C-0x4F */ - 0xBB, 0x87, 0xBB, 0x88, 0xBB, 0x89, 0xBB, 0x8A, /* 0x50-0x53 */ - 0xBB, 0x8B, 0xBB, 0x8C, 0xBB, 0x8D, 0xBB, 0x8E, /* 0x54-0x57 */ - 0xBB, 0x8F, 0xBB, 0x90, 0xBB, 0x91, 0xBB, 0x92, /* 0x58-0x5B */ - 0xBB, 0x93, 0xBB, 0x94, 0xBB, 0x95, 0xBB, 0x96, /* 0x5C-0x5F */ - 0xBB, 0x97, 0xBB, 0x98, 0xBB, 0x99, 0xBB, 0x9A, /* 0x60-0x63 */ - 0xBB, 0x9B, 0xBB, 0x9C, 0xBB, 0x9D, 0xBB, 0x9E, /* 0x64-0x67 */ - 0xBB, 0x9F, 0xBB, 0xA0, 0xBC, 0x41, 0xBC, 0x42, /* 0x68-0x6B */ - 0xBC, 0x43, 0xBC, 0x44, 0xBC, 0x45, 0xBC, 0x46, /* 0x6C-0x6F */ - 0xBC, 0x47, 0xBC, 0x48, 0xBC, 0x49, 0xBC, 0x4A, /* 0x70-0x73 */ - 0xBC, 0x4B, 0xBC, 0x4C, 0xBC, 0x4D, 0xBC, 0x4E, /* 0x74-0x77 */ - 0xBC, 0x4F, 0xBC, 0x50, 0xBC, 0x51, 0xBC, 0x52, /* 0x78-0x7B */ - 0xC6, 0xDB, 0xC6, 0xDC, 0xBC, 0x53, 0xBC, 0x54, /* 0x7C-0x7F */ - - 0xC6, 0xDD, 0xBC, 0x55, 0xBC, 0x56, 0xBC, 0x57, /* 0x80-0x83 */ - 0xC6, 0xDE, 0xBC, 0x58, 0xBC, 0x59, 0xBC, 0x5A, /* 0x84-0x87 */ - 0xBC, 0x61, 0xBC, 0x62, 0xBC, 0x63, 0xBC, 0x64, /* 0x88-0x8B */ - 0xC6, 0xDF, 0xC6, 0xE0, 0xBC, 0x65, 0xC6, 0xE1, /* 0x8C-0x8F */ - 0xC6, 0xE2, 0xC6, 0xE3, 0xBC, 0x66, 0xBC, 0x67, /* 0x90-0x93 */ - 0xBC, 0x68, 0xBC, 0x69, 0xBC, 0x6A, 0xBC, 0x6B, /* 0x94-0x97 */ - 0xC6, 0xE4, 0xC6, 0xE5, 0xBC, 0x6C, 0xBC, 0x6D, /* 0x98-0x9B */ - 0xC6, 0xE6, 0xBC, 0x6E, 0xBC, 0x6F, 0xBC, 0x70, /* 0x9C-0x9F */ - 0xC6, 0xE7, 0xBC, 0x71, 0xBC, 0x72, 0xBC, 0x73, /* 0xA0-0xA3 */ - 0xBC, 0x74, 0xBC, 0x75, 0xBC, 0x76, 0xBC, 0x77, /* 0xA4-0xA7 */ - 0xC6, 0xE8, 0xC6, 0xE9, 0xBC, 0x78, 0xC6, 0xEA, /* 0xA8-0xAB */ - 0xBC, 0x79, 0xC6, 0xEB, 0xBC, 0x7A, 0xBC, 0x81, /* 0xAC-0xAF */ - 0xBC, 0x82, 0xBC, 0x83, 0xBC, 0x84, 0xBC, 0x85, /* 0xB0-0xB3 */ - 0xC6, 0xEC, 0xBC, 0x86, 0xBC, 0x87, 0xBC, 0x88, /* 0xB4-0xB7 */ - 0xC6, 0xED, 0xBC, 0x89, 0xBC, 0x8A, 0xBC, 0x8B, /* 0xB8-0xBB */ - 0xC6, 0xEE, 0xBC, 0x8C, 0xBC, 0x8D, 0xBC, 0x8E, /* 0xBC-0xBF */ - 0xBC, 0x8F, 0xBC, 0x90, 0xBC, 0x91, 0xBC, 0x92, /* 0xC0-0xC3 */ - 0xC6, 0xEF, 0xC6, 0xF0, 0xBC, 0x93, 0xBC, 0x94, /* 0xC4-0xC7 */ - 0xC6, 0xF1, 0xC6, 0xF2, 0xBC, 0x95, 0xBC, 0x96, /* 0xC8-0xCB */ - 0xBC, 0x97, 0xBC, 0x98, 0xBC, 0x99, 0xBC, 0x9A, /* 0xCC-0xCF */ - 0xC6, 0xF3, 0xBC, 0x9B, 0xBC, 0x9C, 0xBC, 0x9D, /* 0xD0-0xD3 */ - 0xBC, 0x9E, 0xBC, 0x9F, 0xBC, 0xA0, 0xBD, 0x41, /* 0xD4-0xD7 */ - 0xC6, 0xF4, 0xBD, 0x42, 0xBD, 0x43, 0xBD, 0x44, /* 0xD8-0xDB */ - 0xBD, 0x45, 0xBD, 0x46, 0xBD, 0x47, 0xBD, 0x48, /* 0xDC-0xDF */ - 0xBD, 0x49, 0xC6, 0xF5, 0xBD, 0x4A, 0xC6, 0xF6, /* 0xE0-0xE3 */ - 0xBD, 0x4B, 0xBD, 0x4C, 0xBD, 0x4D, 0xBD, 0x4E, /* 0xE4-0xE7 */ - 0xBD, 0x4F, 0xBD, 0x50, 0xBD, 0x51, 0xBD, 0x52, /* 0xE8-0xEB */ - 0xC6, 0xF7, 0xC6, 0xF8, 0xBD, 0x53, 0xBD, 0x54, /* 0xEC-0xEF */ - 0xC6, 0xF9, 0xBD, 0x55, 0xBD, 0x56, 0xBD, 0x57, /* 0xF0-0xF3 */ - 0xC6, 0xFA, 0xBD, 0x58, 0xBD, 0x59, 0xBD, 0x5A, /* 0xF4-0xF7 */ - 0xBD, 0x61, 0xBD, 0x62, 0xBD, 0x63, 0xBD, 0x64, /* 0xF8-0xFB */ - 0xC6, 0xFB, 0xC6, 0xFC, 0xBD, 0x65, 0xC6, 0xFD, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_D4[512] = { - 0xBD, 0x66, 0xC6, 0xFE, 0xBD, 0x67, 0xBD, 0x68, /* 0x00-0x03 */ - 0xBD, 0x69, 0xBD, 0x6A, 0xBD, 0x6B, 0xBD, 0x6C, /* 0x04-0x07 */ - 0xC7, 0xA1, 0xBD, 0x6D, 0xBD, 0x6E, 0xBD, 0x6F, /* 0x08-0x0B */ - 0xBD, 0x70, 0xBD, 0x71, 0xBD, 0x72, 0xBD, 0x73, /* 0x0C-0x0F */ - 0xBD, 0x74, 0xBD, 0x75, 0xBD, 0x76, 0xBD, 0x77, /* 0x10-0x13 */ - 0xBD, 0x78, 0xBD, 0x79, 0xBD, 0x7A, 0xBD, 0x81, /* 0x14-0x17 */ - 0xBD, 0x82, 0xBD, 0x83, 0xBD, 0x84, 0xBD, 0x85, /* 0x18-0x1B */ - 0xBD, 0x86, 0xC7, 0xA2, 0xBD, 0x87, 0xBD, 0x88, /* 0x1C-0x1F */ - 0xBD, 0x89, 0xBD, 0x8A, 0xBD, 0x8B, 0xBD, 0x8C, /* 0x20-0x23 */ - 0xBD, 0x8D, 0xBD, 0x8E, 0xBD, 0x8F, 0xBD, 0x90, /* 0x24-0x27 */ - 0xBD, 0x91, 0xBD, 0x92, 0xBD, 0x93, 0xBD, 0x94, /* 0x28-0x2B */ - 0xBD, 0x95, 0xBD, 0x96, 0xBD, 0x97, 0xBD, 0x98, /* 0x2C-0x2F */ - 0xBD, 0x99, 0xBD, 0x9A, 0xBD, 0x9B, 0xBD, 0x9C, /* 0x30-0x33 */ - 0xBD, 0x9D, 0xBD, 0x9E, 0xBD, 0x9F, 0xBD, 0xA0, /* 0x34-0x37 */ - 0xBE, 0x41, 0xBE, 0x42, 0xBE, 0x43, 0xBE, 0x44, /* 0x38-0x3B */ - 0xBE, 0x45, 0xBE, 0x46, 0xBE, 0x47, 0xBE, 0x48, /* 0x3C-0x3F */ - 0xC7, 0xA3, 0xBE, 0x49, 0xBE, 0x4A, 0xBE, 0x4B, /* 0x40-0x43 */ - 0xC7, 0xA4, 0xBE, 0x4C, 0xBE, 0x4D, 0xBE, 0x4E, /* 0x44-0x47 */ - 0xBE, 0x4F, 0xBE, 0x50, 0xBE, 0x51, 0xBE, 0x52, /* 0x48-0x4B */ - 0xBE, 0x53, 0xBE, 0x54, 0xBE, 0x55, 0xBE, 0x56, /* 0x4C-0x4F */ - 0xBE, 0x57, 0xBE, 0x58, 0xBE, 0x59, 0xBE, 0x5A, /* 0x50-0x53 */ - 0xBE, 0x61, 0xBE, 0x62, 0xBE, 0x63, 0xBE, 0x64, /* 0x54-0x57 */ - 0xBE, 0x65, 0xBE, 0x66, 0xBE, 0x67, 0xBE, 0x68, /* 0x58-0x5B */ - 0xC7, 0xA5, 0xBE, 0x69, 0xBE, 0x6A, 0xBE, 0x6B, /* 0x5C-0x5F */ - 0xC7, 0xA6, 0xBE, 0x6C, 0xBE, 0x6D, 0xBE, 0x6E, /* 0x60-0x63 */ - 0xC7, 0xA7, 0xBE, 0x6F, 0xBE, 0x70, 0xBE, 0x71, /* 0x64-0x67 */ - 0xBE, 0x72, 0xBE, 0x73, 0xBE, 0x74, 0xBE, 0x75, /* 0x68-0x6B */ - 0xBE, 0x76, 0xC7, 0xA8, 0xBE, 0x77, 0xC7, 0xA9, /* 0x6C-0x6F */ - 0xBE, 0x78, 0xBE, 0x79, 0xBE, 0x7A, 0xBE, 0x81, /* 0x70-0x73 */ - 0xBE, 0x82, 0xBE, 0x83, 0xBE, 0x84, 0xBE, 0x85, /* 0x74-0x77 */ - 0xC7, 0xAA, 0xC7, 0xAB, 0xBE, 0x86, 0xBE, 0x87, /* 0x78-0x7B */ - 0xC7, 0xAC, 0xBE, 0x88, 0xBE, 0x89, 0xC7, 0xAD, /* 0x7C-0x7F */ - - 0xC7, 0xAE, 0xBE, 0x8A, 0xC7, 0xAF, 0xBE, 0x8B, /* 0x80-0x83 */ - 0xBE, 0x8C, 0xBE, 0x8D, 0xBE, 0x8E, 0xBE, 0x8F, /* 0x84-0x87 */ - 0xC7, 0xB0, 0xC7, 0xB1, 0xBE, 0x90, 0xC7, 0xB2, /* 0x88-0x8B */ - 0xBE, 0x91, 0xC7, 0xB3, 0xBE, 0x92, 0xBE, 0x93, /* 0x8C-0x8F */ - 0xBE, 0x94, 0xBE, 0x95, 0xBE, 0x96, 0xBE, 0x97, /* 0x90-0x93 */ - 0xC7, 0xB4, 0xBE, 0x98, 0xBE, 0x99, 0xBE, 0x9A, /* 0x94-0x97 */ - 0xBE, 0x9B, 0xBE, 0x9C, 0xBE, 0x9D, 0xBE, 0x9E, /* 0x98-0x9B */ - 0xBE, 0x9F, 0xBE, 0xA0, 0xBF, 0x41, 0xBF, 0x42, /* 0x9C-0x9F */ - 0xBF, 0x43, 0xBF, 0x44, 0xBF, 0x45, 0xBF, 0x46, /* 0xA0-0xA3 */ - 0xBF, 0x47, 0xBF, 0x48, 0xBF, 0x49, 0xBF, 0x4A, /* 0xA4-0xA7 */ - 0xBF, 0x4B, 0xC7, 0xB5, 0xBF, 0x4C, 0xBF, 0x4D, /* 0xA8-0xAB */ - 0xBF, 0x4E, 0xBF, 0x4F, 0xBF, 0x50, 0xBF, 0x51, /* 0xAC-0xAF */ - 0xBF, 0x52, 0xBF, 0x53, 0xBF, 0x54, 0xBF, 0x55, /* 0xB0-0xB3 */ - 0xBF, 0x56, 0xBF, 0x57, 0xBF, 0x58, 0xBF, 0x59, /* 0xB4-0xB7 */ - 0xBF, 0x5A, 0xBF, 0x61, 0xBF, 0x62, 0xBF, 0x63, /* 0xB8-0xBB */ - 0xBF, 0x64, 0xBF, 0x65, 0xBF, 0x66, 0xBF, 0x67, /* 0xBC-0xBF */ - 0xBF, 0x68, 0xBF, 0x69, 0xBF, 0x6A, 0xBF, 0x6B, /* 0xC0-0xC3 */ - 0xBF, 0x6C, 0xBF, 0x6D, 0xBF, 0x6E, 0xBF, 0x6F, /* 0xC4-0xC7 */ - 0xBF, 0x70, 0xBF, 0x71, 0xBF, 0x72, 0xBF, 0x73, /* 0xC8-0xCB */ - 0xC7, 0xB6, 0xBF, 0x74, 0xBF, 0x75, 0xBF, 0x76, /* 0xCC-0xCF */ - 0xC7, 0xB7, 0xBF, 0x77, 0xBF, 0x78, 0xBF, 0x79, /* 0xD0-0xD3 */ - 0xC7, 0xB8, 0xBF, 0x7A, 0xBF, 0x81, 0xBF, 0x82, /* 0xD4-0xD7 */ - 0xBF, 0x83, 0xBF, 0x84, 0xBF, 0x85, 0xBF, 0x86, /* 0xD8-0xDB */ - 0xC7, 0xB9, 0xBF, 0x87, 0xBF, 0x88, 0xC7, 0xBA, /* 0xDC-0xDF */ - 0xBF, 0x89, 0xBF, 0x8A, 0xBF, 0x8B, 0xBF, 0x8C, /* 0xE0-0xE3 */ - 0xBF, 0x8D, 0xBF, 0x8E, 0xBF, 0x8F, 0xBF, 0x90, /* 0xE4-0xE7 */ - 0xC7, 0xBB, 0xBF, 0x91, 0xBF, 0x92, 0xBF, 0x93, /* 0xE8-0xEB */ - 0xC7, 0xBC, 0xBF, 0x94, 0xBF, 0x95, 0xBF, 0x96, /* 0xEC-0xEF */ - 0xC7, 0xBD, 0xBF, 0x97, 0xBF, 0x98, 0xBF, 0x99, /* 0xF0-0xF3 */ - 0xBF, 0x9A, 0xBF, 0x9B, 0xBF, 0x9C, 0xBF, 0x9D, /* 0xF4-0xF7 */ - 0xC7, 0xBE, 0xBF, 0x9E, 0xBF, 0x9F, 0xC7, 0xBF, /* 0xF8-0xFB */ - 0xBF, 0xA0, 0xC7, 0xC0, 0xC0, 0x41, 0xC0, 0x42, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_D5[512] = { - 0xC0, 0x43, 0xC0, 0x44, 0xC0, 0x45, 0xC0, 0x46, /* 0x00-0x03 */ - 0xC7, 0xC1, 0xC0, 0x47, 0xC0, 0x48, 0xC0, 0x49, /* 0x04-0x07 */ - 0xC7, 0xC2, 0xC0, 0x4A, 0xC0, 0x4B, 0xC0, 0x4C, /* 0x08-0x0B */ - 0xC7, 0xC3, 0xC0, 0x4D, 0xC0, 0x4E, 0xC0, 0x4F, /* 0x0C-0x0F */ - 0xC0, 0x50, 0xC0, 0x51, 0xC0, 0x52, 0xC0, 0x53, /* 0x10-0x13 */ - 0xC7, 0xC4, 0xC7, 0xC5, 0xC0, 0x54, 0xC7, 0xC6, /* 0x14-0x17 */ - 0xC0, 0x55, 0xC0, 0x56, 0xC0, 0x57, 0xC0, 0x58, /* 0x18-0x1B */ - 0xC0, 0x59, 0xC0, 0x5A, 0xC0, 0x61, 0xC0, 0x62, /* 0x1C-0x1F */ - 0xC0, 0x63, 0xC0, 0x64, 0xC0, 0x65, 0xC0, 0x66, /* 0x20-0x23 */ - 0xC0, 0x67, 0xC0, 0x68, 0xC0, 0x69, 0xC0, 0x6A, /* 0x24-0x27 */ - 0xC0, 0x6B, 0xC0, 0x6C, 0xC0, 0x6D, 0xC0, 0x6E, /* 0x28-0x2B */ - 0xC0, 0x6F, 0xC0, 0x70, 0xC0, 0x71, 0xC0, 0x72, /* 0x2C-0x2F */ - 0xC0, 0x73, 0xC0, 0x74, 0xC0, 0x75, 0xC0, 0x76, /* 0x30-0x33 */ - 0xC0, 0x77, 0xC0, 0x78, 0xC0, 0x79, 0xC0, 0x7A, /* 0x34-0x37 */ - 0xC0, 0x81, 0xC0, 0x82, 0xC0, 0x83, 0xC0, 0x84, /* 0x38-0x3B */ - 0xC7, 0xC7, 0xC7, 0xC8, 0xC0, 0x85, 0xC0, 0x86, /* 0x3C-0x3F */ - 0xC7, 0xC9, 0xC0, 0x87, 0xC0, 0x88, 0xC0, 0x89, /* 0x40-0x43 */ - 0xC7, 0xCA, 0xC0, 0x8A, 0xC0, 0x8B, 0xC0, 0x8C, /* 0x44-0x47 */ - 0xC0, 0x8D, 0xC0, 0x8E, 0xC0, 0x8F, 0xC0, 0x90, /* 0x48-0x4B */ - 0xC7, 0xCB, 0xC7, 0xCC, 0xC0, 0x91, 0xC7, 0xCD, /* 0x4C-0x4F */ - 0xC0, 0x92, 0xC7, 0xCE, 0xC0, 0x93, 0xC0, 0x94, /* 0x50-0x53 */ - 0xC0, 0x95, 0xC0, 0x96, 0xC0, 0x97, 0xC0, 0x98, /* 0x54-0x57 */ - 0xC7, 0xCF, 0xC7, 0xD0, 0xC0, 0x99, 0xC0, 0x9A, /* 0x58-0x5B */ - 0xC7, 0xD1, 0xC0, 0x9B, 0xC0, 0x9C, 0xC0, 0x9D, /* 0x5C-0x5F */ - 0xC7, 0xD2, 0xC0, 0x9E, 0xC0, 0x9F, 0xC0, 0xA0, /* 0x60-0x63 */ - 0xC1, 0x41, 0xC7, 0xD3, 0xC1, 0x42, 0xC1, 0x43, /* 0x64-0x67 */ - 0xC7, 0xD4, 0xC7, 0xD5, 0xC1, 0x44, 0xC7, 0xD6, /* 0x68-0x6B */ - 0xC1, 0x45, 0xC7, 0xD7, 0xC1, 0x46, 0xC1, 0x47, /* 0x6C-0x6F */ - 0xC1, 0x48, 0xC1, 0x49, 0xC1, 0x4A, 0xC1, 0x4B, /* 0x70-0x73 */ - 0xC7, 0xD8, 0xC7, 0xD9, 0xC1, 0x4C, 0xC1, 0x4D, /* 0x74-0x77 */ - 0xC7, 0xDA, 0xC1, 0x4E, 0xC1, 0x4F, 0xC1, 0x50, /* 0x78-0x7B */ - 0xC7, 0xDB, 0xC1, 0x51, 0xC1, 0x52, 0xC1, 0x53, /* 0x7C-0x7F */ - - 0xC1, 0x54, 0xC1, 0x55, 0xC1, 0x56, 0xC1, 0x57, /* 0x80-0x83 */ - 0xC7, 0xDC, 0xC7, 0xDD, 0xC1, 0x58, 0xC7, 0xDE, /* 0x84-0x87 */ - 0xC7, 0xDF, 0xC7, 0xE0, 0xC1, 0x59, 0xC1, 0x5A, /* 0x88-0x8B */ - 0xC1, 0x61, 0xC1, 0x62, 0xC1, 0x63, 0xC1, 0x64, /* 0x8C-0x8F */ - 0xC7, 0xE1, 0xC1, 0x65, 0xC1, 0x66, 0xC1, 0x67, /* 0x90-0x93 */ - 0xC1, 0x68, 0xC1, 0x69, 0xC1, 0x6A, 0xC1, 0x6B, /* 0x94-0x97 */ - 0xC1, 0x6C, 0xC1, 0x6D, 0xC1, 0x6E, 0xC1, 0x6F, /* 0x98-0x9B */ - 0xC1, 0x70, 0xC1, 0x71, 0xC1, 0x72, 0xC1, 0x73, /* 0x9C-0x9F */ - 0xC1, 0x74, 0xC1, 0x75, 0xC1, 0x76, 0xC1, 0x77, /* 0xA0-0xA3 */ - 0xC1, 0x78, 0xC7, 0xE2, 0xC1, 0x79, 0xC1, 0x7A, /* 0xA4-0xA7 */ - 0xC1, 0x81, 0xC1, 0x82, 0xC1, 0x83, 0xC1, 0x84, /* 0xA8-0xAB */ - 0xC1, 0x85, 0xC1, 0x86, 0xC1, 0x87, 0xC1, 0x88, /* 0xAC-0xAF */ - 0xC1, 0x89, 0xC1, 0x8A, 0xC1, 0x8B, 0xC1, 0x8C, /* 0xB0-0xB3 */ - 0xC1, 0x8D, 0xC1, 0x8E, 0xC1, 0x8F, 0xC1, 0x90, /* 0xB4-0xB7 */ - 0xC1, 0x91, 0xC1, 0x92, 0xC1, 0x93, 0xC1, 0x94, /* 0xB8-0xBB */ - 0xC1, 0x95, 0xC1, 0x96, 0xC1, 0x97, 0xC1, 0x98, /* 0xBC-0xBF */ - 0xC1, 0x99, 0xC1, 0x9A, 0xC1, 0x9B, 0xC1, 0x9C, /* 0xC0-0xC3 */ - 0xC1, 0x9D, 0xC1, 0x9E, 0xC1, 0x9F, 0xC1, 0xA0, /* 0xC4-0xC7 */ - 0xC7, 0xE3, 0xC7, 0xE4, 0xC2, 0x41, 0xC2, 0x42, /* 0xC8-0xCB */ - 0xC7, 0xE5, 0xC2, 0x43, 0xC2, 0x44, 0xC2, 0x45, /* 0xCC-0xCF */ - 0xC7, 0xE6, 0xC2, 0x46, 0xC7, 0xE7, 0xC2, 0x47, /* 0xD0-0xD3 */ - 0xC2, 0x48, 0xC2, 0x49, 0xC2, 0x4A, 0xC2, 0x4B, /* 0xD4-0xD7 */ - 0xC7, 0xE8, 0xC7, 0xE9, 0xC2, 0x4C, 0xC7, 0xEA, /* 0xD8-0xDB */ - 0xC2, 0x4D, 0xC7, 0xEB, 0xC2, 0x4E, 0xC2, 0x4F, /* 0xDC-0xDF */ - 0xC2, 0x50, 0xC2, 0x51, 0xC2, 0x52, 0xC2, 0x53, /* 0xE0-0xE3 */ - 0xC7, 0xEC, 0xC7, 0xED, 0xC2, 0x54, 0xC2, 0x55, /* 0xE4-0xE7 */ - 0xC7, 0xEE, 0xC2, 0x56, 0xC2, 0x57, 0xC2, 0x58, /* 0xE8-0xEB */ - 0xC7, 0xEF, 0xC2, 0x59, 0xC2, 0x5A, 0xC2, 0x61, /* 0xEC-0xEF */ - 0xC2, 0x62, 0xC2, 0x63, 0xC2, 0x64, 0xC2, 0x65, /* 0xF0-0xF3 */ - 0xC7, 0xF0, 0xC7, 0xF1, 0xC2, 0x66, 0xC7, 0xF2, /* 0xF4-0xF7 */ - 0xC2, 0x67, 0xC7, 0xF3, 0xC2, 0x68, 0xC2, 0x69, /* 0xF8-0xFB */ - 0xC2, 0x6A, 0xC2, 0x6B, 0xC2, 0x6C, 0xC2, 0x6D, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_D6[512] = { - 0xC7, 0xF4, 0xC7, 0xF5, 0xC2, 0x6E, 0xC2, 0x6F, /* 0x00-0x03 */ - 0xC7, 0xF6, 0xC2, 0x70, 0xC2, 0x71, 0xC2, 0x72, /* 0x04-0x07 */ - 0xC7, 0xF7, 0xC2, 0x73, 0xC2, 0x74, 0xC2, 0x75, /* 0x08-0x0B */ - 0xC2, 0x76, 0xC2, 0x77, 0xC2, 0x78, 0xC2, 0x79, /* 0x0C-0x0F */ - 0xC7, 0xF8, 0xC7, 0xF9, 0xC2, 0x7A, 0xC7, 0xFA, /* 0x10-0x13 */ - 0xC7, 0xFB, 0xC7, 0xFC, 0xC2, 0x81, 0xC2, 0x82, /* 0x14-0x17 */ - 0xC2, 0x83, 0xC2, 0x84, 0xC2, 0x85, 0xC2, 0x86, /* 0x18-0x1B */ - 0xC7, 0xFD, 0xC2, 0x87, 0xC2, 0x88, 0xC2, 0x89, /* 0x1C-0x1F */ - 0xC7, 0xFE, 0xC2, 0x8A, 0xC2, 0x8B, 0xC2, 0x8C, /* 0x20-0x23 */ - 0xC8, 0xA1, 0xC2, 0x8D, 0xC2, 0x8E, 0xC2, 0x8F, /* 0x24-0x27 */ - 0xC2, 0x90, 0xC2, 0x91, 0xC2, 0x92, 0xC2, 0x93, /* 0x28-0x2B */ - 0xC2, 0x94, 0xC8, 0xA2, 0xC2, 0x95, 0xC2, 0x96, /* 0x2C-0x2F */ - 0xC2, 0x97, 0xC2, 0x98, 0xC2, 0x99, 0xC2, 0x9A, /* 0x30-0x33 */ - 0xC2, 0x9B, 0xC2, 0x9C, 0xC2, 0x9D, 0xC2, 0x9E, /* 0x34-0x37 */ - 0xC8, 0xA3, 0xC8, 0xA4, 0xC2, 0x9F, 0xC2, 0xA0, /* 0x38-0x3B */ - 0xC8, 0xA5, 0xC3, 0x41, 0xC3, 0x42, 0xC3, 0x43, /* 0x3C-0x3F */ - 0xC8, 0xA6, 0xC3, 0x44, 0xC3, 0x45, 0xC3, 0x46, /* 0x40-0x43 */ - 0xC3, 0x47, 0xC8, 0xA7, 0xC3, 0x48, 0xC3, 0x49, /* 0x44-0x47 */ - 0xC8, 0xA8, 0xC8, 0xA9, 0xC3, 0x4A, 0xC8, 0xAA, /* 0x48-0x4B */ - 0xC3, 0x4B, 0xC8, 0xAB, 0xC3, 0x4C, 0xC3, 0x4D, /* 0x4C-0x4F */ - 0xC3, 0x4E, 0xC8, 0xAC, 0xC3, 0x4F, 0xC3, 0x50, /* 0x50-0x53 */ - 0xC8, 0xAD, 0xC8, 0xAE, 0xC3, 0x51, 0xC3, 0x52, /* 0x54-0x57 */ - 0xC8, 0xAF, 0xC3, 0x53, 0xC3, 0x54, 0xC3, 0x55, /* 0x58-0x5B */ - 0xC8, 0xB0, 0xC3, 0x56, 0xC3, 0x57, 0xC3, 0x58, /* 0x5C-0x5F */ - 0xC3, 0x59, 0xC3, 0x5A, 0xC3, 0x61, 0xC3, 0x62, /* 0x60-0x63 */ - 0xC3, 0x63, 0xC3, 0x64, 0xC3, 0x65, 0xC8, 0xB1, /* 0x64-0x67 */ - 0xC3, 0x66, 0xC8, 0xB2, 0xC3, 0x67, 0xC3, 0x68, /* 0x68-0x6B */ - 0xC3, 0x69, 0xC3, 0x6A, 0xC3, 0x6B, 0xC3, 0x6C, /* 0x6C-0x6F */ - 0xC8, 0xB3, 0xC8, 0xB4, 0xC3, 0x6D, 0xC3, 0x6E, /* 0x70-0x73 */ - 0xC8, 0xB5, 0xC3, 0x6F, 0xC3, 0x70, 0xC3, 0x71, /* 0x74-0x77 */ - 0xC3, 0x72, 0xC3, 0x73, 0xC3, 0x74, 0xC3, 0x75, /* 0x78-0x7B */ - 0xC3, 0x76, 0xC3, 0x77, 0xC3, 0x78, 0xC3, 0x79, /* 0x7C-0x7F */ - - 0xC3, 0x7A, 0xC3, 0x81, 0xC3, 0x82, 0xC8, 0xB6, /* 0x80-0x83 */ - 0xC3, 0x83, 0xC8, 0xB7, 0xC3, 0x84, 0xC3, 0x85, /* 0x84-0x87 */ - 0xC3, 0x86, 0xC3, 0x87, 0xC3, 0x88, 0xC3, 0x89, /* 0x88-0x8B */ - 0xC8, 0xB8, 0xC8, 0xB9, 0xC3, 0x8A, 0xC3, 0x8B, /* 0x8C-0x8F */ - 0xC8, 0xBA, 0xC3, 0x8C, 0xC3, 0x8D, 0xC3, 0x8E, /* 0x90-0x93 */ - 0xC8, 0xBB, 0xC3, 0x8F, 0xC3, 0x90, 0xC3, 0x91, /* 0x94-0x97 */ - 0xC3, 0x92, 0xC3, 0x93, 0xC3, 0x94, 0xC3, 0x95, /* 0x98-0x9B */ - 0xC3, 0x96, 0xC8, 0xBC, 0xC3, 0x97, 0xC8, 0xBD, /* 0x9C-0x9F */ - 0xC3, 0x98, 0xC8, 0xBE, 0xC3, 0x99, 0xC3, 0x9A, /* 0xA0-0xA3 */ - 0xC3, 0x9B, 0xC3, 0x9C, 0xC3, 0x9D, 0xC3, 0x9E, /* 0xA4-0xA7 */ - 0xC8, 0xBF, 0xC3, 0x9F, 0xC3, 0xA0, 0xC4, 0x41, /* 0xA8-0xAB */ - 0xC8, 0xC0, 0xC4, 0x42, 0xC4, 0x43, 0xC4, 0x44, /* 0xAC-0xAF */ - 0xC8, 0xC1, 0xC4, 0x45, 0xC4, 0x46, 0xC4, 0x47, /* 0xB0-0xB3 */ - 0xC4, 0x48, 0xC4, 0x49, 0xC4, 0x4A, 0xC4, 0x4B, /* 0xB4-0xB7 */ - 0xC4, 0x4C, 0xC8, 0xC2, 0xC4, 0x4D, 0xC8, 0xC3, /* 0xB8-0xBB */ - 0xC4, 0x4E, 0xC4, 0x4F, 0xC4, 0x50, 0xC4, 0x51, /* 0xBC-0xBF */ - 0xC4, 0x52, 0xC4, 0x53, 0xC4, 0x54, 0xC4, 0x55, /* 0xC0-0xC3 */ - 0xC8, 0xC4, 0xC8, 0xC5, 0xC4, 0x56, 0xC4, 0x57, /* 0xC4-0xC7 */ - 0xC8, 0xC6, 0xC4, 0x58, 0xC4, 0x59, 0xC4, 0x5A, /* 0xC8-0xCB */ - 0xC8, 0xC7, 0xC4, 0x61, 0xC4, 0x62, 0xC4, 0x63, /* 0xCC-0xCF */ - 0xC4, 0x64, 0xC8, 0xC8, 0xC4, 0x65, 0xC4, 0x66, /* 0xD0-0xD3 */ - 0xC8, 0xC9, 0xC4, 0x67, 0xC4, 0x68, 0xC8, 0xCA, /* 0xD4-0xD7 */ - 0xC4, 0x69, 0xC8, 0xCB, 0xC4, 0x6A, 0xC4, 0x6B, /* 0xD8-0xDB */ - 0xC4, 0x6C, 0xC4, 0x6D, 0xC4, 0x6E, 0xC4, 0x6F, /* 0xDC-0xDF */ - 0xC8, 0xCC, 0xC4, 0x70, 0xC4, 0x71, 0xC4, 0x72, /* 0xE0-0xE3 */ - 0xC8, 0xCD, 0xC4, 0x73, 0xC4, 0x74, 0xC4, 0x75, /* 0xE4-0xE7 */ - 0xC8, 0xCE, 0xC4, 0x76, 0xC4, 0x77, 0xC4, 0x78, /* 0xE8-0xEB */ - 0xC4, 0x79, 0xC4, 0x7A, 0xC4, 0x81, 0xC4, 0x82, /* 0xEC-0xEF */ - 0xC8, 0xCF, 0xC4, 0x83, 0xC4, 0x84, 0xC4, 0x85, /* 0xF0-0xF3 */ - 0xC4, 0x86, 0xC8, 0xD0, 0xC4, 0x87, 0xC4, 0x88, /* 0xF4-0xF7 */ - 0xC4, 0x89, 0xC4, 0x8A, 0xC4, 0x8B, 0xC4, 0x8C, /* 0xF8-0xFB */ - 0xC8, 0xD1, 0xC8, 0xD2, 0xC4, 0x8D, 0xC4, 0x8E, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_D7[512] = { - 0xC8, 0xD3, 0xC4, 0x8F, 0xC4, 0x90, 0xC4, 0x91, /* 0x00-0x03 */ - 0xC8, 0xD4, 0xC4, 0x92, 0xC4, 0x93, 0xC4, 0x94, /* 0x04-0x07 */ - 0xC4, 0x95, 0xC4, 0x96, 0xC4, 0x97, 0xC4, 0x98, /* 0x08-0x0B */ - 0xC4, 0x99, 0xC4, 0x9A, 0xC4, 0x9B, 0xC4, 0x9C, /* 0x0C-0x0F */ - 0xC4, 0x9D, 0xC8, 0xD5, 0xC4, 0x9E, 0xC4, 0x9F, /* 0x10-0x13 */ - 0xC4, 0xA0, 0xC5, 0x41, 0xC5, 0x42, 0xC5, 0x43, /* 0x14-0x17 */ - 0xC8, 0xD6, 0xC8, 0xD7, 0xC5, 0x44, 0xC5, 0x45, /* 0x18-0x1B */ - 0xC8, 0xD8, 0xC5, 0x46, 0xC5, 0x47, 0xC5, 0x48, /* 0x1C-0x1F */ - 0xC8, 0xD9, 0xC5, 0x49, 0xC5, 0x4A, 0xC5, 0x4B, /* 0x20-0x23 */ - 0xC5, 0x4C, 0xC5, 0x4D, 0xC5, 0x4E, 0xC5, 0x4F, /* 0x24-0x27 */ - 0xC8, 0xDA, 0xC8, 0xDB, 0xC5, 0x50, 0xC8, 0xDC, /* 0x28-0x2B */ - 0xC5, 0x51, 0xC8, 0xDD, 0xC5, 0x52, 0xC5, 0x53, /* 0x2C-0x2F */ - 0xC5, 0x54, 0xC5, 0x55, 0xC5, 0x56, 0xC5, 0x57, /* 0x30-0x33 */ - 0xC8, 0xDE, 0xC8, 0xDF, 0xC5, 0x58, 0xC5, 0x59, /* 0x34-0x37 */ - 0xC8, 0xE0, 0xC5, 0x5A, 0xC5, 0x61, 0xC5, 0x62, /* 0x38-0x3B */ - 0xC8, 0xE1, 0xC5, 0x63, 0xC5, 0x64, 0xC5, 0x65, /* 0x3C-0x3F */ - 0xC5, 0x66, 0xC5, 0x67, 0xC5, 0x68, 0xC5, 0x69, /* 0x40-0x43 */ - 0xC8, 0xE2, 0xC5, 0x6A, 0xC5, 0x6B, 0xC8, 0xE3, /* 0x44-0x47 */ - 0xC5, 0x6C, 0xC8, 0xE4, 0xC5, 0x6D, 0xC5, 0x6E, /* 0x48-0x4B */ - 0xC5, 0x6F, 0xC5, 0x70, 0xC5, 0x71, 0xC5, 0x72, /* 0x4C-0x4F */ - 0xC8, 0xE5, 0xC8, 0xE6, 0xC5, 0x73, 0xC5, 0x74, /* 0x50-0x53 */ - 0xC8, 0xE7, 0xC5, 0x75, 0xC8, 0xE8, 0xC8, 0xE9, /* 0x54-0x57 */ - 0xC8, 0xEA, 0xC8, 0xEB, 0xC5, 0x76, 0xC5, 0x77, /* 0x58-0x5B */ - 0xC5, 0x78, 0xC5, 0x79, 0xC5, 0x7A, 0xC5, 0x81, /* 0x5C-0x5F */ - 0xC8, 0xEC, 0xC8, 0xED, 0xC5, 0x82, 0xC8, 0xEE, /* 0x60-0x63 */ - 0xC5, 0x83, 0xC8, 0xEF, 0xC5, 0x84, 0xC5, 0x85, /* 0x64-0x67 */ - 0xC5, 0x86, 0xC8, 0xF0, 0xC5, 0x87, 0xC5, 0x88, /* 0x68-0x6B */ - 0xC8, 0xF1, 0xC5, 0x89, 0xC5, 0x8A, 0xC5, 0x8B, /* 0x6C-0x6F */ - 0xC8, 0xF2, 0xC5, 0x8C, 0xC5, 0x8D, 0xC5, 0x8E, /* 0x70-0x73 */ - 0xC8, 0xF3, 0xC5, 0x8F, 0xC5, 0x90, 0xC5, 0x91, /* 0x74-0x77 */ - 0xC5, 0x92, 0xC5, 0x93, 0xC5, 0x94, 0xC5, 0x95, /* 0x78-0x7B */ - 0xC8, 0xF4, 0xC8, 0xF5, 0xC5, 0x96, 0xC5, 0x97, /* 0x7C-0x7F */ - - 0xC5, 0x98, 0xC8, 0xF6, 0xC5, 0x99, 0xC5, 0x9A, /* 0x80-0x83 */ - 0xC5, 0x9B, 0xC5, 0x9C, 0xC5, 0x9D, 0xC5, 0x9E, /* 0x84-0x87 */ - 0xC8, 0xF7, 0xC8, 0xF8, 0xC5, 0x9F, 0xC5, 0xA0, /* 0x88-0x8B */ - 0xC8, 0xF9, 0xC6, 0x41, 0xC6, 0x42, 0xC6, 0x43, /* 0x8C-0x8F */ - 0xC8, 0xFA, 0xC6, 0x44, 0xC6, 0x45, 0xC6, 0x46, /* 0x90-0x93 */ - 0xC6, 0x47, 0xC6, 0x48, 0xC6, 0x49, 0xC6, 0x4A, /* 0x94-0x97 */ - 0xC8, 0xFB, 0xC8, 0xFC, 0xC6, 0x4B, 0xC8, 0xFD, /* 0x98-0x9B */ - 0xC6, 0x4C, 0xC8, 0xFE, 0xC6, 0x4D, 0xC6, 0x4E, /* 0x9C-0x9F */ - 0xC6, 0x4F, 0xC6, 0x50, 0xC6, 0x51, 0xC6, 0x52, /* 0xA0-0xA3 */ -}; - -static const unsigned char u2c_DC[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ -}; - -static const unsigned char u2c_F9[512] = { - 0xCB, 0xD0, 0xCB, 0xD6, 0xCB, 0xE7, 0xCD, 0xCF, /* 0x00-0x03 */ - 0xCD, 0xE8, 0xCE, 0xAD, 0xCF, 0xFB, 0xD0, 0xA2, /* 0x04-0x07 */ - 0xD0, 0xB8, 0xD0, 0xD0, 0xD0, 0xDD, 0xD1, 0xD4, /* 0x08-0x0B */ - 0xD1, 0xD5, 0xD1, 0xD8, 0xD1, 0xDB, 0xD1, 0xDC, /* 0x0C-0x0F */ - 0xD1, 0xDD, 0xD1, 0xDE, 0xD1, 0xDF, 0xD1, 0xE0, /* 0x10-0x13 */ - 0xD1, 0xE2, 0xD1, 0xE3, 0xD1, 0xE4, 0xD1, 0xE5, /* 0x14-0x17 */ - 0xD1, 0xE6, 0xD1, 0xE8, 0xD1, 0xE9, 0xD1, 0xEA, /* 0x18-0x1B */ - 0xD1, 0xEB, 0xD1, 0xED, 0xD1, 0xEF, 0xD1, 0xF0, /* 0x1C-0x1F */ - 0xD1, 0xF2, 0xD1, 0xF6, 0xD1, 0xFA, 0xD1, 0xFC, /* 0x20-0x23 */ - 0xD1, 0xFD, 0xD1, 0xFE, 0xD2, 0xA2, 0xD2, 0xA3, /* 0x24-0x27 */ - 0xD2, 0xA7, 0xD2, 0xA8, 0xD2, 0xA9, 0xD2, 0xAA, /* 0x28-0x2B */ - 0xD2, 0xAB, 0xD2, 0xAD, 0xD2, 0xB2, 0xD2, 0xBE, /* 0x2C-0x2F */ - 0xD2, 0xC2, 0xD2, 0xC3, 0xD2, 0xC4, 0xD2, 0xC6, /* 0x30-0x33 */ - 0xD2, 0xC7, 0xD2, 0xC8, 0xD2, 0xC9, 0xD2, 0xCA, /* 0x34-0x37 */ - 0xD2, 0xCB, 0xD2, 0xCD, 0xD2, 0xCE, 0xD2, 0xCF, /* 0x38-0x3B */ - 0xD2, 0xD0, 0xD2, 0xD1, 0xD2, 0xD2, 0xD2, 0xD3, /* 0x3C-0x3F */ - 0xD2, 0xD4, 0xD2, 0xD5, 0xD2, 0xD6, 0xD2, 0xD7, /* 0x40-0x43 */ - 0xD2, 0xD9, 0xD2, 0xDA, 0xD2, 0xDE, 0xD2, 0xDF, /* 0x44-0x47 */ - 0xD2, 0xE1, 0xD2, 0xE2, 0xD2, 0xE4, 0xD2, 0xE5, /* 0x48-0x4B */ - 0xD2, 0xE6, 0xD2, 0xE7, 0xD2, 0xE8, 0xD2, 0xE9, /* 0x4C-0x4F */ - 0xD2, 0xEA, 0xD2, 0xEB, 0xD2, 0xF0, 0xD2, 0xF1, /* 0x50-0x53 */ - 0xD2, 0xF2, 0xD2, 0xF3, 0xD2, 0xF4, 0xD2, 0xF5, /* 0x54-0x57 */ - 0xD2, 0xF7, 0xD2, 0xF8, 0xD4, 0xE6, 0xD4, 0xFC, /* 0x58-0x5B */ - 0xD5, 0xA5, 0xD5, 0xAB, 0xD5, 0xAE, 0xD6, 0xB8, /* 0x5C-0x5F */ - 0xD6, 0xCD, 0xD7, 0xCB, 0xD7, 0xE4, 0xDB, 0xC5, /* 0x60-0x63 */ - 0xDB, 0xE4, 0xDC, 0xA5, 0xDD, 0xA5, 0xDD, 0xD5, /* 0x64-0x67 */ - 0xDD, 0xF4, 0xDE, 0xFC, 0xDE, 0xFE, 0xDF, 0xB3, /* 0x68-0x6B */ - 0xDF, 0xE1, 0xDF, 0xE8, 0xE0, 0xF1, 0xE1, 0xAD, /* 0x6C-0x6F */ - 0xE1, 0xED, 0xE3, 0xF5, 0xE4, 0xA1, 0xE4, 0xA9, /* 0x70-0x73 */ - 0xE5, 0xAE, 0xE5, 0xB1, 0xE5, 0xB2, 0xE5, 0xB9, /* 0x74-0x77 */ - 0xE5, 0xBB, 0xE5, 0xBC, 0xE5, 0xC4, 0xE5, 0xCE, /* 0x78-0x7B */ - 0xE5, 0xD0, 0xE5, 0xD2, 0xE5, 0xD6, 0xE5, 0xFA, /* 0x7C-0x7F */ - - 0xE5, 0xFB, 0xE5, 0xFC, 0xE5, 0xFE, 0xE6, 0xA1, /* 0x80-0x83 */ - 0xE6, 0xA4, 0xE6, 0xA7, 0xE6, 0xAD, 0xE6, 0xAF, /* 0x84-0x87 */ - 0xE6, 0xB0, 0xE6, 0xB1, 0xE6, 0xB3, 0xE6, 0xB7, /* 0x88-0x8B */ - 0xE6, 0xB8, 0xE6, 0xBC, 0xE6, 0xC4, 0xE6, 0xC6, /* 0x8C-0x8F */ - 0xE6, 0xC7, 0xE6, 0xCA, 0xE6, 0xD2, 0xE6, 0xD6, /* 0x90-0x93 */ - 0xE6, 0xD9, 0xE6, 0xDC, 0xE6, 0xDF, 0xE6, 0xE1, /* 0x94-0x97 */ - 0xE6, 0xE4, 0xE6, 0xE5, 0xE6, 0xE6, 0xE6, 0xE8, /* 0x98-0x9B */ - 0xE6, 0xEA, 0xE6, 0xEB, 0xE6, 0xEC, 0xE6, 0xEF, /* 0x9C-0x9F */ - 0xE6, 0xF1, 0xE6, 0xF2, 0xE6, 0xF5, 0xE6, 0xF6, /* 0xA0-0xA3 */ - 0xE6, 0xF7, 0xE6, 0xF9, 0xE7, 0xA1, 0xE7, 0xA6, /* 0xA4-0xA7 */ - 0xE7, 0xA9, 0xE7, 0xAA, 0xE7, 0xAC, 0xE7, 0xAD, /* 0xA8-0xAB */ - 0xE7, 0xB0, 0xE7, 0xBF, 0xE7, 0xC1, 0xE7, 0xC6, /* 0xAC-0xAF */ - 0xE7, 0xC7, 0xE7, 0xCB, 0xE7, 0xCD, 0xE7, 0xCF, /* 0xB0-0xB3 */ - 0xE7, 0xD0, 0xE7, 0xD3, 0xE7, 0xDF, 0xE7, 0xE4, /* 0xB4-0xB7 */ - 0xE7, 0xE6, 0xE7, 0xF7, 0xE8, 0xE7, 0xE8, 0xE8, /* 0xB8-0xBB */ - 0xE8, 0xF0, 0xE8, 0xF1, 0xE8, 0xF7, 0xE8, 0xF9, /* 0xBC-0xBF */ - 0xE8, 0xFB, 0xE8, 0xFE, 0xE9, 0xA7, 0xE9, 0xAC, /* 0xC0-0xC3 */ - 0xE9, 0xCC, 0xE9, 0xF7, 0xEA, 0xC1, 0xEA, 0xE5, /* 0xC4-0xC7 */ - 0xEA, 0xF4, 0xEA, 0xF7, 0xEA, 0xFC, 0xEA, 0xFE, /* 0xC8-0xCB */ - 0xEB, 0xA4, 0xEB, 0xA7, 0xEB, 0xA9, 0xEB, 0xAA, /* 0xCC-0xCF */ - 0xEB, 0xBA, 0xEB, 0xBB, 0xEB, 0xBD, 0xEB, 0xC1, /* 0xD0-0xD3 */ - 0xEB, 0xC2, 0xEB, 0xC6, 0xEB, 0xC7, 0xEB, 0xCC, /* 0xD4-0xD7 */ - 0xEB, 0xCF, 0xEB, 0xD0, 0xEB, 0xD1, 0xEB, 0xD2, /* 0xD8-0xDB */ - 0xEB, 0xD8, 0xEC, 0xA6, 0xEC, 0xA7, 0xEC, 0xAA, /* 0xDC-0xDF */ - 0xEC, 0xAF, 0xEC, 0xB0, 0xEC, 0xB1, 0xEC, 0xB2, /* 0xE0-0xE3 */ - 0xEC, 0xB5, 0xEC, 0xB8, 0xEC, 0xBA, 0xEC, 0xC0, /* 0xE4-0xE7 */ - 0xEC, 0xC1, 0xEC, 0xC5, 0xEC, 0xC6, 0xEC, 0xC9, /* 0xE8-0xEB */ - 0xEC, 0xCA, 0xEC, 0xD5, 0xEC, 0xDD, 0xEC, 0xDE, /* 0xEC-0xEF */ - 0xEC, 0xE1, 0xEC, 0xE4, 0xEC, 0xE7, 0xEC, 0xE8, /* 0xF0-0xF3 */ - 0xEC, 0xF7, 0xEC, 0xF8, 0xEC, 0xFA, 0xED, 0xA1, /* 0xF4-0xF7 */ - 0xED, 0xA2, 0xED, 0xA3, 0xED, 0xEE, 0xEE, 0xDB, /* 0xF8-0xFB */ - 0xF2, 0xBD, 0xF2, 0xFA, 0xF3, 0xB1, 0xF4, 0xA7, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_FA[512] = { - 0xF4, 0xEE, 0xF6, 0xF4, 0xF6, 0xF6, 0xF7, 0xB8, /* 0x00-0x03 */ - 0xF7, 0xC8, 0xF7, 0xD3, 0xF8, 0xDB, 0xF8, 0xF0, /* 0x04-0x07 */ - 0xFA, 0xA1, 0xFA, 0xA2, 0xFA, 0xE6, 0xFC, 0xA9, /* 0x08-0x0B */ - 0xE8, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xF5, 0xC0, 0x00, 0x00, 0xF4, 0xE7, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xFD, 0xEB, 0x00, 0x00, 0xEC, 0xCC, /* 0x14-0x17 */ - 0x00, 0x00, 0xE3, 0xEA, 0xDF, 0xD4, 0xDC, 0xD8, /* 0x18-0x1B */ - 0xEF, 0xFE, 0xEF, 0xF1, 0xE9, 0xE2, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0xF0, 0xB3, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xEC, 0xEF, 0xD4, 0xB4, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0xF9, 0xDE, 0xF8, /* 0x28-0x2B */ - 0xCE, 0xBD, 0xF9, 0xCD, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ -}; - -static const unsigned char u2c_FF[512] = { - 0x00, 0x00, 0xA3, 0xA1, 0xA3, 0xA2, 0xA3, 0xA3, /* 0x00-0x03 */ - 0xA3, 0xA4, 0xA3, 0xA5, 0xA3, 0xA6, 0xA3, 0xA7, /* 0x04-0x07 */ - 0xA3, 0xA8, 0xA3, 0xA9, 0xA3, 0xAA, 0xA3, 0xAB, /* 0x08-0x0B */ - 0xA3, 0xAC, 0xA3, 0xAD, 0xA3, 0xAE, 0xA3, 0xAF, /* 0x0C-0x0F */ - 0xA3, 0xB0, 0xA3, 0xB1, 0xA3, 0xB2, 0xA3, 0xB3, /* 0x10-0x13 */ - 0xA3, 0xB4, 0xA3, 0xB5, 0xA3, 0xB6, 0xA3, 0xB7, /* 0x14-0x17 */ - 0xA3, 0xB8, 0xA3, 0xB9, 0xA3, 0xBA, 0xA3, 0xBB, /* 0x18-0x1B */ - 0xA3, 0xBC, 0xA3, 0xBD, 0xA3, 0xBE, 0xA3, 0xBF, /* 0x1C-0x1F */ - 0xA3, 0xC0, 0xA3, 0xC1, 0xA3, 0xC2, 0xA3, 0xC3, /* 0x20-0x23 */ - 0xA3, 0xC4, 0xA3, 0xC5, 0xA3, 0xC6, 0xA3, 0xC7, /* 0x24-0x27 */ - 0xA3, 0xC8, 0xA3, 0xC9, 0xA3, 0xCA, 0xA3, 0xCB, /* 0x28-0x2B */ - 0xA3, 0xCC, 0xA3, 0xCD, 0xA3, 0xCE, 0xA3, 0xCF, /* 0x2C-0x2F */ - 0xA3, 0xD0, 0xA3, 0xD1, 0xA3, 0xD2, 0xA3, 0xD3, /* 0x30-0x33 */ - 0xA3, 0xD4, 0xA3, 0xD5, 0xA3, 0xD6, 0xA3, 0xD7, /* 0x34-0x37 */ - 0xA3, 0xD8, 0xA3, 0xD9, 0xA3, 0xDA, 0xA3, 0xDB, /* 0x38-0x3B */ - 0xA1, 0xAC, 0xA3, 0xDD, 0xA3, 0xDE, 0xA3, 0xDF, /* 0x3C-0x3F */ - 0xA3, 0xE0, 0xA3, 0xE1, 0xA3, 0xE2, 0xA3, 0xE3, /* 0x40-0x43 */ - 0xA3, 0xE4, 0xA3, 0xE5, 0xA3, 0xE6, 0xA3, 0xE7, /* 0x44-0x47 */ - 0xA3, 0xE8, 0xA3, 0xE9, 0xA3, 0xEA, 0xA3, 0xEB, /* 0x48-0x4B */ - 0xA3, 0xEC, 0xA3, 0xED, 0xA3, 0xEE, 0xA3, 0xEF, /* 0x4C-0x4F */ - 0xA3, 0xF0, 0xA3, 0xF1, 0xA3, 0xF2, 0xA3, 0xF3, /* 0x50-0x53 */ - 0xA3, 0xF4, 0xA3, 0xF5, 0xA3, 0xF6, 0xA3, 0xF7, /* 0x54-0x57 */ - 0xA3, 0xF8, 0xA3, 0xF9, 0xA3, 0xFA, 0xA3, 0xFB, /* 0x58-0x5B */ - 0xA3, 0xFC, 0xA3, 0xFD, 0xA2, 0xA6, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xA4, 0xD4, 0xA4, 0xA1, 0xA4, 0xA2, 0xA4, 0xA3, /* 0xA0-0xA3 */ - 0xA4, 0xA4, 0xA4, 0xA5, 0xA4, 0xA6, 0xA4, 0xA7, /* 0xA4-0xA7 */ - 0xA4, 0xA8, 0xA4, 0xA9, 0xA4, 0xAA, 0xA4, 0xAB, /* 0xA8-0xAB */ - 0xA4, 0xAC, 0xA4, 0xAD, 0xA4, 0xAE, 0xA4, 0xAF, /* 0xAC-0xAF */ - 0xA4, 0xB0, 0xA4, 0xB1, 0xA4, 0xB2, 0xA4, 0xB3, /* 0xB0-0xB3 */ - 0xA4, 0xB4, 0xA4, 0xB5, 0xA4, 0xB6, 0xA4, 0xB7, /* 0xB4-0xB7 */ - 0xA4, 0xB8, 0xA4, 0xB9, 0xA4, 0xBA, 0xA4, 0xBB, /* 0xB8-0xBB */ - 0xA4, 0xBC, 0xA4, 0xBD, 0xA4, 0xBE, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xA4, 0xBF, 0xA4, 0xC0, /* 0xC0-0xC3 */ - 0xA4, 0xC1, 0xA4, 0xC2, 0xA4, 0xC3, 0xA4, 0xC4, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xA4, 0xC5, 0xA4, 0xC6, /* 0xC8-0xCB */ - 0xA4, 0xC7, 0xA4, 0xC8, 0xA4, 0xC9, 0xA4, 0xCA, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xA4, 0xCB, 0xA4, 0xCC, /* 0xD0-0xD3 */ - 0xA4, 0xCD, 0xA4, 0xCE, 0xA4, 0xCF, 0xA4, 0xD0, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xA4, 0xD1, 0xA4, 0xD2, /* 0xD8-0xDB */ - 0xA4, 0xD3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0xA1, 0xCB, 0xA1, 0xCC, 0xA1, 0xFE, 0xA3, 0xFE, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xA1, 0xCD, 0xA3, 0xDC, 0x00, 0x00, /* 0xE4-0xE7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - NULL, u2c_01, u2c_02, u2c_03, u2c_04, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, u2c_11, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - u2c_20, u2c_21, u2c_22, u2c_23, u2c_24, u2c_25, u2c_26, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - u2c_30, u2c_31, u2c_32, u2c_33, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, u2c_4E, u2c_4F, - u2c_50, u2c_51, u2c_52, u2c_53, u2c_54, u2c_55, u2c_56, u2c_57, - u2c_58, u2c_59, u2c_5A, u2c_5B, u2c_5C, u2c_5D, u2c_5E, u2c_5F, - u2c_60, u2c_61, u2c_62, u2c_63, u2c_64, u2c_65, u2c_66, u2c_67, - u2c_68, u2c_69, u2c_6A, u2c_6B, u2c_6C, u2c_6D, u2c_6E, u2c_6F, - u2c_70, u2c_71, u2c_72, u2c_73, u2c_74, u2c_75, u2c_76, u2c_77, - u2c_78, u2c_79, u2c_7A, u2c_7B, u2c_7C, u2c_7D, u2c_7E, u2c_7F, - u2c_80, u2c_81, u2c_82, u2c_83, u2c_84, u2c_85, u2c_86, u2c_87, - u2c_88, u2c_89, u2c_8A, u2c_8B, u2c_8C, u2c_8D, u2c_8E, u2c_8F, - u2c_90, u2c_91, u2c_92, u2c_93, u2c_94, u2c_95, u2c_96, u2c_97, - u2c_98, u2c_99, u2c_9A, u2c_9B, u2c_9C, u2c_9D, u2c_9E, u2c_9F, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, u2c_AC, u2c_AD, u2c_AE, u2c_AF, - u2c_B0, u2c_B1, u2c_B2, u2c_B3, u2c_B4, u2c_B5, u2c_B6, u2c_B7, - u2c_B8, u2c_B9, u2c_BA, u2c_BB, u2c_BC, u2c_BD, u2c_BE, u2c_BF, - u2c_C0, u2c_C1, u2c_C2, u2c_C3, u2c_C4, u2c_C5, u2c_C6, u2c_C7, - u2c_C8, u2c_C9, u2c_CA, u2c_CB, u2c_CC, u2c_CD, u2c_CE, u2c_CF, - u2c_D0, u2c_D1, u2c_D2, u2c_D3, u2c_D4, u2c_D5, u2c_D6, u2c_D7, - NULL, NULL, NULL, NULL, u2c_DC, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, u2c_F9, u2c_FA, NULL, NULL, NULL, NULL, u2c_FF, }; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(const wchar_t uni, - unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni&0xFF; - unsigned char ch = (uni>>8)&0xFF; - int n; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - - uni2charset = page_uni2charset[ch]; - if (uni2charset) { - if (boundlen <= 1) - return -ENAMETOOLONG; - out[0] = uni2charset[cl*2]; - out[1] = uni2charset[cl*2+1]; - if (out[0] == 0x00 && out[1] == 0x00) - return -EINVAL; - n = 2; - } else if (ch==0 && cl) { - out[0] = cl; - n = 1; - } - else - return -EINVAL; - - return n; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, - wchar_t *uni) -{ - unsigned char ch, cl; - const wchar_t *charset2uni; - int n; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - if (boundlen == 1) { - *uni = rawstring[0]; - return 1; - } - - ch = rawstring[0]; - cl = rawstring[1]; - - charset2uni = page_charset2uni[ch]; - if (charset2uni && cl) { - *uni = charset2uni[cl]; - if (*uni == 0x0000) - return -EINVAL; - n = 2; - } else{ - *uni = ch; - n = 1; - } - return n; -} - -static struct nls_table table = { - .charset = "cp949", - .alias = "euc-kr", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp949(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp949(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp949) -module_exit(exit_nls_cp949) - -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_ALIAS_NLS(euc-kr); diff --git a/src/linux/fs/nls/nls_cp950.c b/src/linux/fs/nls/nls_cp950.c deleted file mode 100644 index 8e14187..0000000 --- a/src/linux/fs/nls/nls_cp950.c +++ /dev/null @@ -1,9482 +0,0 @@ -/* - * linux/fs/nls/nls_cp950.c - * - * Charset cp950 translation tables. - * This translation table was generated automatically, the - * original table can be download from the Microsoft website. - * (http://www.microsoft.com/typography/unicode/unicodecp.htm) - */ - -#include -#include -#include -#include -#include - -static const wchar_t c2u_A1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x3000,0xFF0C,0x3001,0x3002,0xFF0E,0x2027,0xFF1B,0xFF1A,/* 0x40-0x47 */ - 0xFF1F,0xFF01,0xFE30,0x2026,0x2025,0xFE50,0xFE51,0xFE52,/* 0x48-0x4F */ - 0x00B7,0xFE54,0xFE55,0xFE56,0xFE57,0xFF5C,0x2013,0xFE31,/* 0x50-0x57 */ - 0x2014,0xFE33,0x2574,0xFE34,0xFE4F,0xFF08,0xFF09,0xFE35,/* 0x58-0x5F */ - 0xFE36,0xFF5B,0xFF5D,0xFE37,0xFE38,0x3014,0x3015,0xFE39,/* 0x60-0x67 */ - 0xFE3A,0x3010,0x3011,0xFE3B,0xFE3C,0x300A,0x300B,0xFE3D,/* 0x68-0x6F */ - 0xFE3E,0x3008,0x3009,0xFE3F,0xFE40,0x300C,0x300D,0xFE41,/* 0x70-0x77 */ - 0xFE42,0x300E,0x300F,0xFE43,0xFE44,0xFE59,0xFE5A,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0xFE5B,0xFE5C,0xFE5D,0xFE5E,0x2018,0x2019,0x201C,/* 0xA0-0xA7 */ - 0x201D,0x301D,0x301E,0x2035,0x2032,0xFF03,0xFF06,0xFF0A,/* 0xA8-0xAF */ - 0x203B,0x00A7,0x3003,0x25CB,0x25CF,0x25B3,0x25B2,0x25CE,/* 0xB0-0xB7 */ - 0x2606,0x2605,0x25C7,0x25C6,0x25A1,0x25A0,0x25BD,0x25BC,/* 0xB8-0xBF */ - 0x32A3,0x2105,0x00AF,0xFFE3,0xFF3F,0x02CD,0xFE49,0xFE4A,/* 0xC0-0xC7 */ - 0xFE4D,0xFE4E,0xFE4B,0xFE4C,0xFE5F,0xFE60,0xFE61,0xFF0B,/* 0xC8-0xCF */ - 0xFF0D,0x00D7,0x00F7,0x00B1,0x221A,0xFF1C,0xFF1E,0xFF1D,/* 0xD0-0xD7 */ - 0x2266,0x2267,0x2260,0x221E,0x2252,0x2261,0xFE62,0xFE63,/* 0xD8-0xDF */ - 0xFE64,0xFE65,0xFE66,0xFF5E,0x2229,0x222A,0x22A5,0x2220,/* 0xE0-0xE7 */ - 0x221F,0x22BF,0x33D2,0x33D1,0x222B,0x222E,0x2235,0x2234,/* 0xE8-0xEF */ - 0x2640,0x2642,0x2295,0x2299,0x2191,0x2193,0x2190,0x2192,/* 0xF0-0xF7 */ - 0x2196,0x2197,0x2199,0x2198,0x2225,0x2223,0xFF0F,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0xFF3C,0x2215,0xFE68,0xFF04,0xFFE5,0x3012,0xFFE0,0xFFE1,/* 0x40-0x47 */ - 0xFF05,0xFF20,0x2103,0x2109,0xFE69,0xFE6A,0xFE6B,0x33D5,/* 0x48-0x4F */ - 0x339C,0x339D,0x339E,0x33CE,0x33A1,0x338E,0x338F,0x33C4,/* 0x50-0x57 */ - 0x00B0,0x5159,0x515B,0x515E,0x515D,0x5161,0x5163,0x55E7,/* 0x58-0x5F */ - 0x74E9,0x7CCE,0x2581,0x2582,0x2583,0x2584,0x2585,0x2586,/* 0x60-0x67 */ - 0x2587,0x2588,0x258F,0x258E,0x258D,0x258C,0x258B,0x258A,/* 0x68-0x6F */ - 0x2589,0x253C,0x2534,0x252C,0x2524,0x251C,0x2594,0x2500,/* 0x70-0x77 */ - 0x2502,0x2595,0x250C,0x2510,0x2514,0x2518,0x256D,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x256E,0x2570,0x256F,0x2550,0x255E,0x256A,0x2561,/* 0xA0-0xA7 */ - 0x25E2,0x25E3,0x25E5,0x25E4,0x2571,0x2572,0x2573,0xFF10,/* 0xA8-0xAF */ - 0xFF11,0xFF12,0xFF13,0xFF14,0xFF15,0xFF16,0xFF17,0xFF18,/* 0xB0-0xB7 */ - 0xFF19,0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,/* 0xB8-0xBF */ - 0x2167,0x2168,0x2169,0x3021,0x3022,0x3023,0x3024,0x3025,/* 0xC0-0xC7 */ - 0x3026,0x3027,0x3028,0x3029,0x5341,0x5344,0x5345,0xFF21,/* 0xC8-0xCF */ - 0xFF22,0xFF23,0xFF24,0xFF25,0xFF26,0xFF27,0xFF28,0xFF29,/* 0xD0-0xD7 */ - 0xFF2A,0xFF2B,0xFF2C,0xFF2D,0xFF2E,0xFF2F,0xFF30,0xFF31,/* 0xD8-0xDF */ - 0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,0xFF38,0xFF39,/* 0xE0-0xE7 */ - 0xFF3A,0xFF41,0xFF42,0xFF43,0xFF44,0xFF45,0xFF46,0xFF47,/* 0xE8-0xEF */ - 0xFF48,0xFF49,0xFF4A,0xFF4B,0xFF4C,0xFF4D,0xFF4E,0xFF4F,/* 0xF0-0xF7 */ - 0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0xFF57,0xFF58,0xFF59,0xFF5A,0x0391,0x0392,0x0393,0x0394,/* 0x40-0x47 */ - 0x0395,0x0396,0x0397,0x0398,0x0399,0x039A,0x039B,0x039C,/* 0x48-0x4F */ - 0x039D,0x039E,0x039F,0x03A0,0x03A1,0x03A3,0x03A4,0x03A5,/* 0x50-0x57 */ - 0x03A6,0x03A7,0x03A8,0x03A9,0x03B1,0x03B2,0x03B3,0x03B4,/* 0x58-0x5F */ - 0x03B5,0x03B6,0x03B7,0x03B8,0x03B9,0x03BA,0x03BB,0x03BC,/* 0x60-0x67 */ - 0x03BD,0x03BE,0x03BF,0x03C0,0x03C1,0x03C3,0x03C4,0x03C5,/* 0x68-0x6F */ - 0x03C6,0x03C7,0x03C8,0x03C9,0x3105,0x3106,0x3107,0x3108,/* 0x70-0x77 */ - 0x3109,0x310A,0x310B,0x310C,0x310D,0x310E,0x310F,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x3110,0x3111,0x3112,0x3113,0x3114,0x3115,0x3116,/* 0xA0-0xA7 */ - 0x3117,0x3118,0x3119,0x311A,0x311B,0x311C,0x311D,0x311E,/* 0xA8-0xAF */ - 0x311F,0x3120,0x3121,0x3122,0x3123,0x3124,0x3125,0x3126,/* 0xB0-0xB7 */ - 0x3127,0x3128,0x3129,0x02D9,0x02C9,0x02CA,0x02C7,0x02CB,/* 0xB8-0xBF */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xC0-0xC7 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xC8-0xCF */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xD0-0xD7 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xD8-0xDF */ - 0x0000,0x20AC,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0xE0-0xE7 */ -}; - -static const wchar_t c2u_A4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x4E00,0x4E59,0x4E01,0x4E03,0x4E43,0x4E5D,0x4E86,0x4E8C,/* 0x40-0x47 */ - 0x4EBA,0x513F,0x5165,0x516B,0x51E0,0x5200,0x5201,0x529B,/* 0x48-0x4F */ - 0x5315,0x5341,0x535C,0x53C8,0x4E09,0x4E0B,0x4E08,0x4E0A,/* 0x50-0x57 */ - 0x4E2B,0x4E38,0x51E1,0x4E45,0x4E48,0x4E5F,0x4E5E,0x4E8E,/* 0x58-0x5F */ - 0x4EA1,0x5140,0x5203,0x52FA,0x5343,0x53C9,0x53E3,0x571F,/* 0x60-0x67 */ - 0x58EB,0x5915,0x5927,0x5973,0x5B50,0x5B51,0x5B53,0x5BF8,/* 0x68-0x6F */ - 0x5C0F,0x5C22,0x5C38,0x5C71,0x5DDD,0x5DE5,0x5DF1,0x5DF2,/* 0x70-0x77 */ - 0x5DF3,0x5DFE,0x5E72,0x5EFE,0x5F0B,0x5F13,0x624D,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x4E11,0x4E10,0x4E0D,0x4E2D,0x4E30,0x4E39,0x4E4B,/* 0xA0-0xA7 */ - 0x5C39,0x4E88,0x4E91,0x4E95,0x4E92,0x4E94,0x4EA2,0x4EC1,/* 0xA8-0xAF */ - 0x4EC0,0x4EC3,0x4EC6,0x4EC7,0x4ECD,0x4ECA,0x4ECB,0x4EC4,/* 0xB0-0xB7 */ - 0x5143,0x5141,0x5167,0x516D,0x516E,0x516C,0x5197,0x51F6,/* 0xB8-0xBF */ - 0x5206,0x5207,0x5208,0x52FB,0x52FE,0x52FF,0x5316,0x5339,/* 0xC0-0xC7 */ - 0x5348,0x5347,0x5345,0x535E,0x5384,0x53CB,0x53CA,0x53CD,/* 0xC8-0xCF */ - 0x58EC,0x5929,0x592B,0x592A,0x592D,0x5B54,0x5C11,0x5C24,/* 0xD0-0xD7 */ - 0x5C3A,0x5C6F,0x5DF4,0x5E7B,0x5EFF,0x5F14,0x5F15,0x5FC3,/* 0xD8-0xDF */ - 0x6208,0x6236,0x624B,0x624E,0x652F,0x6587,0x6597,0x65A4,/* 0xE0-0xE7 */ - 0x65B9,0x65E5,0x66F0,0x6708,0x6728,0x6B20,0x6B62,0x6B79,/* 0xE8-0xEF */ - 0x6BCB,0x6BD4,0x6BDB,0x6C0F,0x6C34,0x706B,0x722A,0x7236,/* 0xF0-0xF7 */ - 0x723B,0x7247,0x7259,0x725B,0x72AC,0x738B,0x4E19,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x4E16,0x4E15,0x4E14,0x4E18,0x4E3B,0x4E4D,0x4E4F,0x4E4E,/* 0x40-0x47 */ - 0x4EE5,0x4ED8,0x4ED4,0x4ED5,0x4ED6,0x4ED7,0x4EE3,0x4EE4,/* 0x48-0x4F */ - 0x4ED9,0x4EDE,0x5145,0x5144,0x5189,0x518A,0x51AC,0x51F9,/* 0x50-0x57 */ - 0x51FA,0x51F8,0x520A,0x52A0,0x529F,0x5305,0x5306,0x5317,/* 0x58-0x5F */ - 0x531D,0x4EDF,0x534A,0x5349,0x5361,0x5360,0x536F,0x536E,/* 0x60-0x67 */ - 0x53BB,0x53EF,0x53E4,0x53F3,0x53EC,0x53EE,0x53E9,0x53E8,/* 0x68-0x6F */ - 0x53FC,0x53F8,0x53F5,0x53EB,0x53E6,0x53EA,0x53F2,0x53F1,/* 0x70-0x77 */ - 0x53F0,0x53E5,0x53ED,0x53FB,0x56DB,0x56DA,0x5916,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x592E,0x5931,0x5974,0x5976,0x5B55,0x5B83,0x5C3C,/* 0xA0-0xA7 */ - 0x5DE8,0x5DE7,0x5DE6,0x5E02,0x5E03,0x5E73,0x5E7C,0x5F01,/* 0xA8-0xAF */ - 0x5F18,0x5F17,0x5FC5,0x620A,0x6253,0x6254,0x6252,0x6251,/* 0xB0-0xB7 */ - 0x65A5,0x65E6,0x672E,0x672C,0x672A,0x672B,0x672D,0x6B63,/* 0xB8-0xBF */ - 0x6BCD,0x6C11,0x6C10,0x6C38,0x6C41,0x6C40,0x6C3E,0x72AF,/* 0xC0-0xC7 */ - 0x7384,0x7389,0x74DC,0x74E6,0x7518,0x751F,0x7528,0x7529,/* 0xC8-0xCF */ - 0x7530,0x7531,0x7532,0x7533,0x758B,0x767D,0x76AE,0x76BF,/* 0xD0-0xD7 */ - 0x76EE,0x77DB,0x77E2,0x77F3,0x793A,0x79BE,0x7A74,0x7ACB,/* 0xD8-0xDF */ - 0x4E1E,0x4E1F,0x4E52,0x4E53,0x4E69,0x4E99,0x4EA4,0x4EA6,/* 0xE0-0xE7 */ - 0x4EA5,0x4EFF,0x4F09,0x4F19,0x4F0A,0x4F15,0x4F0D,0x4F10,/* 0xE8-0xEF */ - 0x4F11,0x4F0F,0x4EF2,0x4EF6,0x4EFB,0x4EF0,0x4EF3,0x4EFD,/* 0xF0-0xF7 */ - 0x4F01,0x4F0B,0x5149,0x5147,0x5146,0x5148,0x5168,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5171,0x518D,0x51B0,0x5217,0x5211,0x5212,0x520E,0x5216,/* 0x40-0x47 */ - 0x52A3,0x5308,0x5321,0x5320,0x5370,0x5371,0x5409,0x540F,/* 0x48-0x4F */ - 0x540C,0x540A,0x5410,0x5401,0x540B,0x5404,0x5411,0x540D,/* 0x50-0x57 */ - 0x5408,0x5403,0x540E,0x5406,0x5412,0x56E0,0x56DE,0x56DD,/* 0x58-0x5F */ - 0x5733,0x5730,0x5728,0x572D,0x572C,0x572F,0x5729,0x5919,/* 0x60-0x67 */ - 0x591A,0x5937,0x5938,0x5984,0x5978,0x5983,0x597D,0x5979,/* 0x68-0x6F */ - 0x5982,0x5981,0x5B57,0x5B58,0x5B87,0x5B88,0x5B85,0x5B89,/* 0x70-0x77 */ - 0x5BFA,0x5C16,0x5C79,0x5DDE,0x5E06,0x5E76,0x5E74,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x5F0F,0x5F1B,0x5FD9,0x5FD6,0x620E,0x620C,0x620D,/* 0xA0-0xA7 */ - 0x6210,0x6263,0x625B,0x6258,0x6536,0x65E9,0x65E8,0x65EC,/* 0xA8-0xAF */ - 0x65ED,0x66F2,0x66F3,0x6709,0x673D,0x6734,0x6731,0x6735,/* 0xB0-0xB7 */ - 0x6B21,0x6B64,0x6B7B,0x6C16,0x6C5D,0x6C57,0x6C59,0x6C5F,/* 0xB8-0xBF */ - 0x6C60,0x6C50,0x6C55,0x6C61,0x6C5B,0x6C4D,0x6C4E,0x7070,/* 0xC0-0xC7 */ - 0x725F,0x725D,0x767E,0x7AF9,0x7C73,0x7CF8,0x7F36,0x7F8A,/* 0xC8-0xCF */ - 0x7FBD,0x8001,0x8003,0x800C,0x8012,0x8033,0x807F,0x8089,/* 0xD0-0xD7 */ - 0x808B,0x808C,0x81E3,0x81EA,0x81F3,0x81FC,0x820C,0x821B,/* 0xD8-0xDF */ - 0x821F,0x826E,0x8272,0x827E,0x866B,0x8840,0x884C,0x8863,/* 0xE0-0xE7 */ - 0x897F,0x9621,0x4E32,0x4EA8,0x4F4D,0x4F4F,0x4F47,0x4F57,/* 0xE8-0xEF */ - 0x4F5E,0x4F34,0x4F5B,0x4F55,0x4F30,0x4F50,0x4F51,0x4F3D,/* 0xF0-0xF7 */ - 0x4F3A,0x4F38,0x4F43,0x4F54,0x4F3C,0x4F46,0x4F63,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A7[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x4F5C,0x4F60,0x4F2F,0x4F4E,0x4F36,0x4F59,0x4F5D,0x4F48,/* 0x40-0x47 */ - 0x4F5A,0x514C,0x514B,0x514D,0x5175,0x51B6,0x51B7,0x5225,/* 0x48-0x4F */ - 0x5224,0x5229,0x522A,0x5228,0x52AB,0x52A9,0x52AA,0x52AC,/* 0x50-0x57 */ - 0x5323,0x5373,0x5375,0x541D,0x542D,0x541E,0x543E,0x5426,/* 0x58-0x5F */ - 0x544E,0x5427,0x5446,0x5443,0x5433,0x5448,0x5442,0x541B,/* 0x60-0x67 */ - 0x5429,0x544A,0x5439,0x543B,0x5438,0x542E,0x5435,0x5436,/* 0x68-0x6F */ - 0x5420,0x543C,0x5440,0x5431,0x542B,0x541F,0x542C,0x56EA,/* 0x70-0x77 */ - 0x56F0,0x56E4,0x56EB,0x574A,0x5751,0x5740,0x574D,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x5747,0x574E,0x573E,0x5750,0x574F,0x573B,0x58EF,/* 0xA0-0xA7 */ - 0x593E,0x599D,0x5992,0x59A8,0x599E,0x59A3,0x5999,0x5996,/* 0xA8-0xAF */ - 0x598D,0x59A4,0x5993,0x598A,0x59A5,0x5B5D,0x5B5C,0x5B5A,/* 0xB0-0xB7 */ - 0x5B5B,0x5B8C,0x5B8B,0x5B8F,0x5C2C,0x5C40,0x5C41,0x5C3F,/* 0xB8-0xBF */ - 0x5C3E,0x5C90,0x5C91,0x5C94,0x5C8C,0x5DEB,0x5E0C,0x5E8F,/* 0xC0-0xC7 */ - 0x5E87,0x5E8A,0x5EF7,0x5F04,0x5F1F,0x5F64,0x5F62,0x5F77,/* 0xC8-0xCF */ - 0x5F79,0x5FD8,0x5FCC,0x5FD7,0x5FCD,0x5FF1,0x5FEB,0x5FF8,/* 0xD0-0xD7 */ - 0x5FEA,0x6212,0x6211,0x6284,0x6297,0x6296,0x6280,0x6276,/* 0xD8-0xDF */ - 0x6289,0x626D,0x628A,0x627C,0x627E,0x6279,0x6273,0x6292,/* 0xE0-0xE7 */ - 0x626F,0x6298,0x626E,0x6295,0x6293,0x6291,0x6286,0x6539,/* 0xE8-0xEF */ - 0x653B,0x6538,0x65F1,0x66F4,0x675F,0x674E,0x674F,0x6750,/* 0xF0-0xF7 */ - 0x6751,0x675C,0x6756,0x675E,0x6749,0x6746,0x6760,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A8[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6753,0x6757,0x6B65,0x6BCF,0x6C42,0x6C5E,0x6C99,0x6C81,/* 0x40-0x47 */ - 0x6C88,0x6C89,0x6C85,0x6C9B,0x6C6A,0x6C7A,0x6C90,0x6C70,/* 0x48-0x4F */ - 0x6C8C,0x6C68,0x6C96,0x6C92,0x6C7D,0x6C83,0x6C72,0x6C7E,/* 0x50-0x57 */ - 0x6C74,0x6C86,0x6C76,0x6C8D,0x6C94,0x6C98,0x6C82,0x7076,/* 0x58-0x5F */ - 0x707C,0x707D,0x7078,0x7262,0x7261,0x7260,0x72C4,0x72C2,/* 0x60-0x67 */ - 0x7396,0x752C,0x752B,0x7537,0x7538,0x7682,0x76EF,0x77E3,/* 0x68-0x6F */ - 0x79C1,0x79C0,0x79BF,0x7A76,0x7CFB,0x7F55,0x8096,0x8093,/* 0x70-0x77 */ - 0x809D,0x8098,0x809B,0x809A,0x80B2,0x826F,0x8292,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x828B,0x828D,0x898B,0x89D2,0x8A00,0x8C37,0x8C46,/* 0xA0-0xA7 */ - 0x8C55,0x8C9D,0x8D64,0x8D70,0x8DB3,0x8EAB,0x8ECA,0x8F9B,/* 0xA8-0xAF */ - 0x8FB0,0x8FC2,0x8FC6,0x8FC5,0x8FC4,0x5DE1,0x9091,0x90A2,/* 0xB0-0xB7 */ - 0x90AA,0x90A6,0x90A3,0x9149,0x91C6,0x91CC,0x9632,0x962E,/* 0xB8-0xBF */ - 0x9631,0x962A,0x962C,0x4E26,0x4E56,0x4E73,0x4E8B,0x4E9B,/* 0xC0-0xC7 */ - 0x4E9E,0x4EAB,0x4EAC,0x4F6F,0x4F9D,0x4F8D,0x4F73,0x4F7F,/* 0xC8-0xCF */ - 0x4F6C,0x4F9B,0x4F8B,0x4F86,0x4F83,0x4F70,0x4F75,0x4F88,/* 0xD0-0xD7 */ - 0x4F69,0x4F7B,0x4F96,0x4F7E,0x4F8F,0x4F91,0x4F7A,0x5154,/* 0xD8-0xDF */ - 0x5152,0x5155,0x5169,0x5177,0x5176,0x5178,0x51BD,0x51FD,/* 0xE0-0xE7 */ - 0x523B,0x5238,0x5237,0x523A,0x5230,0x522E,0x5236,0x5241,/* 0xE8-0xEF */ - 0x52BE,0x52BB,0x5352,0x5354,0x5353,0x5351,0x5366,0x5377,/* 0xF0-0xF7 */ - 0x5378,0x5379,0x53D6,0x53D4,0x53D7,0x5473,0x5475,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_A9[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5496,0x5478,0x5495,0x5480,0x547B,0x5477,0x5484,0x5492,/* 0x40-0x47 */ - 0x5486,0x547C,0x5490,0x5471,0x5476,0x548C,0x549A,0x5462,/* 0x48-0x4F */ - 0x5468,0x548B,0x547D,0x548E,0x56FA,0x5783,0x5777,0x576A,/* 0x50-0x57 */ - 0x5769,0x5761,0x5766,0x5764,0x577C,0x591C,0x5949,0x5947,/* 0x58-0x5F */ - 0x5948,0x5944,0x5954,0x59BE,0x59BB,0x59D4,0x59B9,0x59AE,/* 0x60-0x67 */ - 0x59D1,0x59C6,0x59D0,0x59CD,0x59CB,0x59D3,0x59CA,0x59AF,/* 0x68-0x6F */ - 0x59B3,0x59D2,0x59C5,0x5B5F,0x5B64,0x5B63,0x5B97,0x5B9A,/* 0x70-0x77 */ - 0x5B98,0x5B9C,0x5B99,0x5B9B,0x5C1A,0x5C48,0x5C45,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x5C46,0x5CB7,0x5CA1,0x5CB8,0x5CA9,0x5CAB,0x5CB1,/* 0xA0-0xA7 */ - 0x5CB3,0x5E18,0x5E1A,0x5E16,0x5E15,0x5E1B,0x5E11,0x5E78,/* 0xA8-0xAF */ - 0x5E9A,0x5E97,0x5E9C,0x5E95,0x5E96,0x5EF6,0x5F26,0x5F27,/* 0xB0-0xB7 */ - 0x5F29,0x5F80,0x5F81,0x5F7F,0x5F7C,0x5FDD,0x5FE0,0x5FFD,/* 0xB8-0xBF */ - 0x5FF5,0x5FFF,0x600F,0x6014,0x602F,0x6035,0x6016,0x602A,/* 0xC0-0xC7 */ - 0x6015,0x6021,0x6027,0x6029,0x602B,0x601B,0x6216,0x6215,/* 0xC8-0xCF */ - 0x623F,0x623E,0x6240,0x627F,0x62C9,0x62CC,0x62C4,0x62BF,/* 0xD0-0xD7 */ - 0x62C2,0x62B9,0x62D2,0x62DB,0x62AB,0x62D3,0x62D4,0x62CB,/* 0xD8-0xDF */ - 0x62C8,0x62A8,0x62BD,0x62BC,0x62D0,0x62D9,0x62C7,0x62CD,/* 0xE0-0xE7 */ - 0x62B5,0x62DA,0x62B1,0x62D8,0x62D6,0x62D7,0x62C6,0x62AC,/* 0xE8-0xEF */ - 0x62CE,0x653E,0x65A7,0x65BC,0x65FA,0x6614,0x6613,0x660C,/* 0xF0-0xF7 */ - 0x6606,0x6602,0x660E,0x6600,0x660F,0x6615,0x660A,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_AA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6607,0x670D,0x670B,0x676D,0x678B,0x6795,0x6771,0x679C,/* 0x40-0x47 */ - 0x6773,0x6777,0x6787,0x679D,0x6797,0x676F,0x6770,0x677F,/* 0x48-0x4F */ - 0x6789,0x677E,0x6790,0x6775,0x679A,0x6793,0x677C,0x676A,/* 0x50-0x57 */ - 0x6772,0x6B23,0x6B66,0x6B67,0x6B7F,0x6C13,0x6C1B,0x6CE3,/* 0x58-0x5F */ - 0x6CE8,0x6CF3,0x6CB1,0x6CCC,0x6CE5,0x6CB3,0x6CBD,0x6CBE,/* 0x60-0x67 */ - 0x6CBC,0x6CE2,0x6CAB,0x6CD5,0x6CD3,0x6CB8,0x6CC4,0x6CB9,/* 0x68-0x6F */ - 0x6CC1,0x6CAE,0x6CD7,0x6CC5,0x6CF1,0x6CBF,0x6CBB,0x6CE1,/* 0x70-0x77 */ - 0x6CDB,0x6CCA,0x6CAC,0x6CEF,0x6CDC,0x6CD6,0x6CE0,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x7095,0x708E,0x7092,0x708A,0x7099,0x722C,0x722D,/* 0xA0-0xA7 */ - 0x7238,0x7248,0x7267,0x7269,0x72C0,0x72CE,0x72D9,0x72D7,/* 0xA8-0xAF */ - 0x72D0,0x73A9,0x73A8,0x739F,0x73AB,0x73A5,0x753D,0x759D,/* 0xB0-0xB7 */ - 0x7599,0x759A,0x7684,0x76C2,0x76F2,0x76F4,0x77E5,0x77FD,/* 0xB8-0xBF */ - 0x793E,0x7940,0x7941,0x79C9,0x79C8,0x7A7A,0x7A79,0x7AFA,/* 0xC0-0xC7 */ - 0x7CFE,0x7F54,0x7F8C,0x7F8B,0x8005,0x80BA,0x80A5,0x80A2,/* 0xC8-0xCF */ - 0x80B1,0x80A1,0x80AB,0x80A9,0x80B4,0x80AA,0x80AF,0x81E5,/* 0xD0-0xD7 */ - 0x81FE,0x820D,0x82B3,0x829D,0x8299,0x82AD,0x82BD,0x829F,/* 0xD8-0xDF */ - 0x82B9,0x82B1,0x82AC,0x82A5,0x82AF,0x82B8,0x82A3,0x82B0,/* 0xE0-0xE7 */ - 0x82BE,0x82B7,0x864E,0x8671,0x521D,0x8868,0x8ECB,0x8FCE,/* 0xE8-0xEF */ - 0x8FD4,0x8FD1,0x90B5,0x90B8,0x90B1,0x90B6,0x91C7,0x91D1,/* 0xF0-0xF7 */ - 0x9577,0x9580,0x961C,0x9640,0x963F,0x963B,0x9644,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_AB[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9642,0x96B9,0x96E8,0x9752,0x975E,0x4E9F,0x4EAD,0x4EAE,/* 0x40-0x47 */ - 0x4FE1,0x4FB5,0x4FAF,0x4FBF,0x4FE0,0x4FD1,0x4FCF,0x4FDD,/* 0x48-0x4F */ - 0x4FC3,0x4FB6,0x4FD8,0x4FDF,0x4FCA,0x4FD7,0x4FAE,0x4FD0,/* 0x50-0x57 */ - 0x4FC4,0x4FC2,0x4FDA,0x4FCE,0x4FDE,0x4FB7,0x5157,0x5192,/* 0x58-0x5F */ - 0x5191,0x51A0,0x524E,0x5243,0x524A,0x524D,0x524C,0x524B,/* 0x60-0x67 */ - 0x5247,0x52C7,0x52C9,0x52C3,0x52C1,0x530D,0x5357,0x537B,/* 0x68-0x6F */ - 0x539A,0x53DB,0x54AC,0x54C0,0x54A8,0x54CE,0x54C9,0x54B8,/* 0x70-0x77 */ - 0x54A6,0x54B3,0x54C7,0x54C2,0x54BD,0x54AA,0x54C1,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x54C4,0x54C8,0x54AF,0x54AB,0x54B1,0x54BB,0x54A9,/* 0xA0-0xA7 */ - 0x54A7,0x54BF,0x56FF,0x5782,0x578B,0x57A0,0x57A3,0x57A2,/* 0xA8-0xAF */ - 0x57CE,0x57AE,0x5793,0x5955,0x5951,0x594F,0x594E,0x5950,/* 0xB0-0xB7 */ - 0x59DC,0x59D8,0x59FF,0x59E3,0x59E8,0x5A03,0x59E5,0x59EA,/* 0xB8-0xBF */ - 0x59DA,0x59E6,0x5A01,0x59FB,0x5B69,0x5BA3,0x5BA6,0x5BA4,/* 0xC0-0xC7 */ - 0x5BA2,0x5BA5,0x5C01,0x5C4E,0x5C4F,0x5C4D,0x5C4B,0x5CD9,/* 0xC8-0xCF */ - 0x5CD2,0x5DF7,0x5E1D,0x5E25,0x5E1F,0x5E7D,0x5EA0,0x5EA6,/* 0xD0-0xD7 */ - 0x5EFA,0x5F08,0x5F2D,0x5F65,0x5F88,0x5F85,0x5F8A,0x5F8B,/* 0xD8-0xDF */ - 0x5F87,0x5F8C,0x5F89,0x6012,0x601D,0x6020,0x6025,0x600E,/* 0xE0-0xE7 */ - 0x6028,0x604D,0x6070,0x6068,0x6062,0x6046,0x6043,0x606C,/* 0xE8-0xEF */ - 0x606B,0x606A,0x6064,0x6241,0x62DC,0x6316,0x6309,0x62FC,/* 0xF0-0xF7 */ - 0x62ED,0x6301,0x62EE,0x62FD,0x6307,0x62F1,0x62F7,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_AC[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x62EF,0x62EC,0x62FE,0x62F4,0x6311,0x6302,0x653F,0x6545,/* 0x40-0x47 */ - 0x65AB,0x65BD,0x65E2,0x6625,0x662D,0x6620,0x6627,0x662F,/* 0x48-0x4F */ - 0x661F,0x6628,0x6631,0x6624,0x66F7,0x67FF,0x67D3,0x67F1,/* 0x50-0x57 */ - 0x67D4,0x67D0,0x67EC,0x67B6,0x67AF,0x67F5,0x67E9,0x67EF,/* 0x58-0x5F */ - 0x67C4,0x67D1,0x67B4,0x67DA,0x67E5,0x67B8,0x67CF,0x67DE,/* 0x60-0x67 */ - 0x67F3,0x67B0,0x67D9,0x67E2,0x67DD,0x67D2,0x6B6A,0x6B83,/* 0x68-0x6F */ - 0x6B86,0x6BB5,0x6BD2,0x6BD7,0x6C1F,0x6CC9,0x6D0B,0x6D32,/* 0x70-0x77 */ - 0x6D2A,0x6D41,0x6D25,0x6D0C,0x6D31,0x6D1E,0x6D17,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x6D3B,0x6D3D,0x6D3E,0x6D36,0x6D1B,0x6CF5,0x6D39,/* 0xA0-0xA7 */ - 0x6D27,0x6D38,0x6D29,0x6D2E,0x6D35,0x6D0E,0x6D2B,0x70AB,/* 0xA8-0xAF */ - 0x70BA,0x70B3,0x70AC,0x70AF,0x70AD,0x70B8,0x70AE,0x70A4,/* 0xB0-0xB7 */ - 0x7230,0x7272,0x726F,0x7274,0x72E9,0x72E0,0x72E1,0x73B7,/* 0xB8-0xBF */ - 0x73CA,0x73BB,0x73B2,0x73CD,0x73C0,0x73B3,0x751A,0x752D,/* 0xC0-0xC7 */ - 0x754F,0x754C,0x754E,0x754B,0x75AB,0x75A4,0x75A5,0x75A2,/* 0xC8-0xCF */ - 0x75A3,0x7678,0x7686,0x7687,0x7688,0x76C8,0x76C6,0x76C3,/* 0xD0-0xD7 */ - 0x76C5,0x7701,0x76F9,0x76F8,0x7709,0x770B,0x76FE,0x76FC,/* 0xD8-0xDF */ - 0x7707,0x77DC,0x7802,0x7814,0x780C,0x780D,0x7946,0x7949,/* 0xE0-0xE7 */ - 0x7948,0x7947,0x79B9,0x79BA,0x79D1,0x79D2,0x79CB,0x7A7F,/* 0xE8-0xEF */ - 0x7A81,0x7AFF,0x7AFD,0x7C7D,0x7D02,0x7D05,0x7D00,0x7D09,/* 0xF0-0xF7 */ - 0x7D07,0x7D04,0x7D06,0x7F38,0x7F8E,0x7FBF,0x8004,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_AD[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8010,0x800D,0x8011,0x8036,0x80D6,0x80E5,0x80DA,0x80C3,/* 0x40-0x47 */ - 0x80C4,0x80CC,0x80E1,0x80DB,0x80CE,0x80DE,0x80E4,0x80DD,/* 0x48-0x4F */ - 0x81F4,0x8222,0x82E7,0x8303,0x8305,0x82E3,0x82DB,0x82E6,/* 0x50-0x57 */ - 0x8304,0x82E5,0x8302,0x8309,0x82D2,0x82D7,0x82F1,0x8301,/* 0x58-0x5F */ - 0x82DC,0x82D4,0x82D1,0x82DE,0x82D3,0x82DF,0x82EF,0x8306,/* 0x60-0x67 */ - 0x8650,0x8679,0x867B,0x867A,0x884D,0x886B,0x8981,0x89D4,/* 0x68-0x6F */ - 0x8A08,0x8A02,0x8A03,0x8C9E,0x8CA0,0x8D74,0x8D73,0x8DB4,/* 0x70-0x77 */ - 0x8ECD,0x8ECC,0x8FF0,0x8FE6,0x8FE2,0x8FEA,0x8FE5,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x8FED,0x8FEB,0x8FE4,0x8FE8,0x90CA,0x90CE,0x90C1,/* 0xA0-0xA7 */ - 0x90C3,0x914B,0x914A,0x91CD,0x9582,0x9650,0x964B,0x964C,/* 0xA8-0xAF */ - 0x964D,0x9762,0x9769,0x97CB,0x97ED,0x97F3,0x9801,0x98A8,/* 0xB0-0xB7 */ - 0x98DB,0x98DF,0x9996,0x9999,0x4E58,0x4EB3,0x500C,0x500D,/* 0xB8-0xBF */ - 0x5023,0x4FEF,0x5026,0x5025,0x4FF8,0x5029,0x5016,0x5006,/* 0xC0-0xC7 */ - 0x503C,0x501F,0x501A,0x5012,0x5011,0x4FFA,0x5000,0x5014,/* 0xC8-0xCF */ - 0x5028,0x4FF1,0x5021,0x500B,0x5019,0x5018,0x4FF3,0x4FEE,/* 0xD0-0xD7 */ - 0x502D,0x502A,0x4FFE,0x502B,0x5009,0x517C,0x51A4,0x51A5,/* 0xD8-0xDF */ - 0x51A2,0x51CD,0x51CC,0x51C6,0x51CB,0x5256,0x525C,0x5254,/* 0xE0-0xE7 */ - 0x525B,0x525D,0x532A,0x537F,0x539F,0x539D,0x53DF,0x54E8,/* 0xE8-0xEF */ - 0x5510,0x5501,0x5537,0x54FC,0x54E5,0x54F2,0x5506,0x54FA,/* 0xF0-0xF7 */ - 0x5514,0x54E9,0x54ED,0x54E1,0x5509,0x54EE,0x54EA,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_AE[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x54E6,0x5527,0x5507,0x54FD,0x550F,0x5703,0x5704,0x57C2,/* 0x40-0x47 */ - 0x57D4,0x57CB,0x57C3,0x5809,0x590F,0x5957,0x5958,0x595A,/* 0x48-0x4F */ - 0x5A11,0x5A18,0x5A1C,0x5A1F,0x5A1B,0x5A13,0x59EC,0x5A20,/* 0x50-0x57 */ - 0x5A23,0x5A29,0x5A25,0x5A0C,0x5A09,0x5B6B,0x5C58,0x5BB0,/* 0x58-0x5F */ - 0x5BB3,0x5BB6,0x5BB4,0x5BAE,0x5BB5,0x5BB9,0x5BB8,0x5C04,/* 0x60-0x67 */ - 0x5C51,0x5C55,0x5C50,0x5CED,0x5CFD,0x5CFB,0x5CEA,0x5CE8,/* 0x68-0x6F */ - 0x5CF0,0x5CF6,0x5D01,0x5CF4,0x5DEE,0x5E2D,0x5E2B,0x5EAB,/* 0x70-0x77 */ - 0x5EAD,0x5EA7,0x5F31,0x5F92,0x5F91,0x5F90,0x6059,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x6063,0x6065,0x6050,0x6055,0x606D,0x6069,0x606F,/* 0xA0-0xA7 */ - 0x6084,0x609F,0x609A,0x608D,0x6094,0x608C,0x6085,0x6096,/* 0xA8-0xAF */ - 0x6247,0x62F3,0x6308,0x62FF,0x634E,0x633E,0x632F,0x6355,/* 0xB0-0xB7 */ - 0x6342,0x6346,0x634F,0x6349,0x633A,0x6350,0x633D,0x632A,/* 0xB8-0xBF */ - 0x632B,0x6328,0x634D,0x634C,0x6548,0x6549,0x6599,0x65C1,/* 0xC0-0xC7 */ - 0x65C5,0x6642,0x6649,0x664F,0x6643,0x6652,0x664C,0x6645,/* 0xC8-0xCF */ - 0x6641,0x66F8,0x6714,0x6715,0x6717,0x6821,0x6838,0x6848,/* 0xD0-0xD7 */ - 0x6846,0x6853,0x6839,0x6842,0x6854,0x6829,0x68B3,0x6817,/* 0xD8-0xDF */ - 0x684C,0x6851,0x683D,0x67F4,0x6850,0x6840,0x683C,0x6843,/* 0xE0-0xE7 */ - 0x682A,0x6845,0x6813,0x6818,0x6841,0x6B8A,0x6B89,0x6BB7,/* 0xE8-0xEF */ - 0x6C23,0x6C27,0x6C28,0x6C26,0x6C24,0x6CF0,0x6D6A,0x6D95,/* 0xF0-0xF7 */ - 0x6D88,0x6D87,0x6D66,0x6D78,0x6D77,0x6D59,0x6D93,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_AF[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6D6C,0x6D89,0x6D6E,0x6D5A,0x6D74,0x6D69,0x6D8C,0x6D8A,/* 0x40-0x47 */ - 0x6D79,0x6D85,0x6D65,0x6D94,0x70CA,0x70D8,0x70E4,0x70D9,/* 0x48-0x4F */ - 0x70C8,0x70CF,0x7239,0x7279,0x72FC,0x72F9,0x72FD,0x72F8,/* 0x50-0x57 */ - 0x72F7,0x7386,0x73ED,0x7409,0x73EE,0x73E0,0x73EA,0x73DE,/* 0x58-0x5F */ - 0x7554,0x755D,0x755C,0x755A,0x7559,0x75BE,0x75C5,0x75C7,/* 0x60-0x67 */ - 0x75B2,0x75B3,0x75BD,0x75BC,0x75B9,0x75C2,0x75B8,0x768B,/* 0x68-0x6F */ - 0x76B0,0x76CA,0x76CD,0x76CE,0x7729,0x771F,0x7720,0x7728,/* 0x70-0x77 */ - 0x77E9,0x7830,0x7827,0x7838,0x781D,0x7834,0x7837,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x7825,0x782D,0x7820,0x781F,0x7832,0x7955,0x7950,/* 0xA0-0xA7 */ - 0x7960,0x795F,0x7956,0x795E,0x795D,0x7957,0x795A,0x79E4,/* 0xA8-0xAF */ - 0x79E3,0x79E7,0x79DF,0x79E6,0x79E9,0x79D8,0x7A84,0x7A88,/* 0xB0-0xB7 */ - 0x7AD9,0x7B06,0x7B11,0x7C89,0x7D21,0x7D17,0x7D0B,0x7D0A,/* 0xB8-0xBF */ - 0x7D20,0x7D22,0x7D14,0x7D10,0x7D15,0x7D1A,0x7D1C,0x7D0D,/* 0xC0-0xC7 */ - 0x7D19,0x7D1B,0x7F3A,0x7F5F,0x7F94,0x7FC5,0x7FC1,0x8006,/* 0xC8-0xCF */ - 0x8018,0x8015,0x8019,0x8017,0x803D,0x803F,0x80F1,0x8102,/* 0xD0-0xD7 */ - 0x80F0,0x8105,0x80ED,0x80F4,0x8106,0x80F8,0x80F3,0x8108,/* 0xD8-0xDF */ - 0x80FD,0x810A,0x80FC,0x80EF,0x81ED,0x81EC,0x8200,0x8210,/* 0xE0-0xE7 */ - 0x822A,0x822B,0x8228,0x822C,0x82BB,0x832B,0x8352,0x8354,/* 0xE8-0xEF */ - 0x834A,0x8338,0x8350,0x8349,0x8335,0x8334,0x834F,0x8332,/* 0xF0-0xF7 */ - 0x8339,0x8336,0x8317,0x8340,0x8331,0x8328,0x8343,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B0[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8654,0x868A,0x86AA,0x8693,0x86A4,0x86A9,0x868C,0x86A3,/* 0x40-0x47 */ - 0x869C,0x8870,0x8877,0x8881,0x8882,0x887D,0x8879,0x8A18,/* 0x48-0x4F */ - 0x8A10,0x8A0E,0x8A0C,0x8A15,0x8A0A,0x8A17,0x8A13,0x8A16,/* 0x50-0x57 */ - 0x8A0F,0x8A11,0x8C48,0x8C7A,0x8C79,0x8CA1,0x8CA2,0x8D77,/* 0x58-0x5F */ - 0x8EAC,0x8ED2,0x8ED4,0x8ECF,0x8FB1,0x9001,0x9006,0x8FF7,/* 0x60-0x67 */ - 0x9000,0x8FFA,0x8FF4,0x9003,0x8FFD,0x9005,0x8FF8,0x9095,/* 0x68-0x6F */ - 0x90E1,0x90DD,0x90E2,0x9152,0x914D,0x914C,0x91D8,0x91DD,/* 0x70-0x77 */ - 0x91D7,0x91DC,0x91D9,0x9583,0x9662,0x9663,0x9661,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x965B,0x965D,0x9664,0x9658,0x965E,0x96BB,0x98E2,/* 0xA0-0xA7 */ - 0x99AC,0x9AA8,0x9AD8,0x9B25,0x9B32,0x9B3C,0x4E7E,0x507A,/* 0xA8-0xAF */ - 0x507D,0x505C,0x5047,0x5043,0x504C,0x505A,0x5049,0x5065,/* 0xB0-0xB7 */ - 0x5076,0x504E,0x5055,0x5075,0x5074,0x5077,0x504F,0x500F,/* 0xB8-0xBF */ - 0x506F,0x506D,0x515C,0x5195,0x51F0,0x526A,0x526F,0x52D2,/* 0xC0-0xC7 */ - 0x52D9,0x52D8,0x52D5,0x5310,0x530F,0x5319,0x533F,0x5340,/* 0xC8-0xCF */ - 0x533E,0x53C3,0x66FC,0x5546,0x556A,0x5566,0x5544,0x555E,/* 0xD0-0xD7 */ - 0x5561,0x5543,0x554A,0x5531,0x5556,0x554F,0x5555,0x552F,/* 0xD8-0xDF */ - 0x5564,0x5538,0x552E,0x555C,0x552C,0x5563,0x5533,0x5541,/* 0xE0-0xE7 */ - 0x5557,0x5708,0x570B,0x5709,0x57DF,0x5805,0x580A,0x5806,/* 0xE8-0xEF */ - 0x57E0,0x57E4,0x57FA,0x5802,0x5835,0x57F7,0x57F9,0x5920,/* 0xF0-0xF7 */ - 0x5962,0x5A36,0x5A41,0x5A49,0x5A66,0x5A6A,0x5A40,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5A3C,0x5A62,0x5A5A,0x5A46,0x5A4A,0x5B70,0x5BC7,0x5BC5,/* 0x40-0x47 */ - 0x5BC4,0x5BC2,0x5BBF,0x5BC6,0x5C09,0x5C08,0x5C07,0x5C60,/* 0x48-0x4F */ - 0x5C5C,0x5C5D,0x5D07,0x5D06,0x5D0E,0x5D1B,0x5D16,0x5D22,/* 0x50-0x57 */ - 0x5D11,0x5D29,0x5D14,0x5D19,0x5D24,0x5D27,0x5D17,0x5DE2,/* 0x58-0x5F */ - 0x5E38,0x5E36,0x5E33,0x5E37,0x5EB7,0x5EB8,0x5EB6,0x5EB5,/* 0x60-0x67 */ - 0x5EBE,0x5F35,0x5F37,0x5F57,0x5F6C,0x5F69,0x5F6B,0x5F97,/* 0x68-0x6F */ - 0x5F99,0x5F9E,0x5F98,0x5FA1,0x5FA0,0x5F9C,0x607F,0x60A3,/* 0x70-0x77 */ - 0x6089,0x60A0,0x60A8,0x60CB,0x60B4,0x60E6,0x60BD,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x60C5,0x60BB,0x60B5,0x60DC,0x60BC,0x60D8,0x60D5,/* 0xA0-0xA7 */ - 0x60C6,0x60DF,0x60B8,0x60DA,0x60C7,0x621A,0x621B,0x6248,/* 0xA8-0xAF */ - 0x63A0,0x63A7,0x6372,0x6396,0x63A2,0x63A5,0x6377,0x6367,/* 0xB0-0xB7 */ - 0x6398,0x63AA,0x6371,0x63A9,0x6389,0x6383,0x639B,0x636B,/* 0xB8-0xBF */ - 0x63A8,0x6384,0x6388,0x6399,0x63A1,0x63AC,0x6392,0x638F,/* 0xC0-0xC7 */ - 0x6380,0x637B,0x6369,0x6368,0x637A,0x655D,0x6556,0x6551,/* 0xC8-0xCF */ - 0x6559,0x6557,0x555F,0x654F,0x6558,0x6555,0x6554,0x659C,/* 0xD0-0xD7 */ - 0x659B,0x65AC,0x65CF,0x65CB,0x65CC,0x65CE,0x665D,0x665A,/* 0xD8-0xDF */ - 0x6664,0x6668,0x6666,0x665E,0x66F9,0x52D7,0x671B,0x6881,/* 0xE0-0xE7 */ - 0x68AF,0x68A2,0x6893,0x68B5,0x687F,0x6876,0x68B1,0x68A7,/* 0xE8-0xEF */ - 0x6897,0x68B0,0x6883,0x68C4,0x68AD,0x6886,0x6885,0x6894,/* 0xF0-0xF7 */ - 0x689D,0x68A8,0x689F,0x68A1,0x6882,0x6B32,0x6BBA,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6BEB,0x6BEC,0x6C2B,0x6D8E,0x6DBC,0x6DF3,0x6DD9,0x6DB2,/* 0x40-0x47 */ - 0x6DE1,0x6DCC,0x6DE4,0x6DFB,0x6DFA,0x6E05,0x6DC7,0x6DCB,/* 0x48-0x4F */ - 0x6DAF,0x6DD1,0x6DAE,0x6DDE,0x6DF9,0x6DB8,0x6DF7,0x6DF5,/* 0x50-0x57 */ - 0x6DC5,0x6DD2,0x6E1A,0x6DB5,0x6DDA,0x6DEB,0x6DD8,0x6DEA,/* 0x58-0x5F */ - 0x6DF1,0x6DEE,0x6DE8,0x6DC6,0x6DC4,0x6DAA,0x6DEC,0x6DBF,/* 0x60-0x67 */ - 0x6DE6,0x70F9,0x7109,0x710A,0x70FD,0x70EF,0x723D,0x727D,/* 0x68-0x6F */ - 0x7281,0x731C,0x731B,0x7316,0x7313,0x7319,0x7387,0x7405,/* 0x70-0x77 */ - 0x740A,0x7403,0x7406,0x73FE,0x740D,0x74E0,0x74F6,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x74F7,0x751C,0x7522,0x7565,0x7566,0x7562,0x7570,/* 0xA0-0xA7 */ - 0x758F,0x75D4,0x75D5,0x75B5,0x75CA,0x75CD,0x768E,0x76D4,/* 0xA8-0xAF */ - 0x76D2,0x76DB,0x7737,0x773E,0x773C,0x7736,0x7738,0x773A,/* 0xB0-0xB7 */ - 0x786B,0x7843,0x784E,0x7965,0x7968,0x796D,0x79FB,0x7A92,/* 0xB8-0xBF */ - 0x7A95,0x7B20,0x7B28,0x7B1B,0x7B2C,0x7B26,0x7B19,0x7B1E,/* 0xC0-0xC7 */ - 0x7B2E,0x7C92,0x7C97,0x7C95,0x7D46,0x7D43,0x7D71,0x7D2E,/* 0xC8-0xCF */ - 0x7D39,0x7D3C,0x7D40,0x7D30,0x7D33,0x7D44,0x7D2F,0x7D42,/* 0xD0-0xD7 */ - 0x7D32,0x7D31,0x7F3D,0x7F9E,0x7F9A,0x7FCC,0x7FCE,0x7FD2,/* 0xD8-0xDF */ - 0x801C,0x804A,0x8046,0x812F,0x8116,0x8123,0x812B,0x8129,/* 0xE0-0xE7 */ - 0x8130,0x8124,0x8202,0x8235,0x8237,0x8236,0x8239,0x838E,/* 0xE8-0xEF */ - 0x839E,0x8398,0x8378,0x83A2,0x8396,0x83BD,0x83AB,0x8392,/* 0xF0-0xF7 */ - 0x838A,0x8393,0x8389,0x83A0,0x8377,0x837B,0x837C,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8386,0x83A7,0x8655,0x5F6A,0x86C7,0x86C0,0x86B6,0x86C4,/* 0x40-0x47 */ - 0x86B5,0x86C6,0x86CB,0x86B1,0x86AF,0x86C9,0x8853,0x889E,/* 0x48-0x4F */ - 0x8888,0x88AB,0x8892,0x8896,0x888D,0x888B,0x8993,0x898F,/* 0x50-0x57 */ - 0x8A2A,0x8A1D,0x8A23,0x8A25,0x8A31,0x8A2D,0x8A1F,0x8A1B,/* 0x58-0x5F */ - 0x8A22,0x8C49,0x8C5A,0x8CA9,0x8CAC,0x8CAB,0x8CA8,0x8CAA,/* 0x60-0x67 */ - 0x8CA7,0x8D67,0x8D66,0x8DBE,0x8DBA,0x8EDB,0x8EDF,0x9019,/* 0x68-0x6F */ - 0x900D,0x901A,0x9017,0x9023,0x901F,0x901D,0x9010,0x9015,/* 0x70-0x77 */ - 0x901E,0x9020,0x900F,0x9022,0x9016,0x901B,0x9014,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x90E8,0x90ED,0x90FD,0x9157,0x91CE,0x91F5,0x91E6,/* 0xA0-0xA7 */ - 0x91E3,0x91E7,0x91ED,0x91E9,0x9589,0x966A,0x9675,0x9673,/* 0xA8-0xAF */ - 0x9678,0x9670,0x9674,0x9676,0x9677,0x966C,0x96C0,0x96EA,/* 0xB0-0xB7 */ - 0x96E9,0x7AE0,0x7ADF,0x9802,0x9803,0x9B5A,0x9CE5,0x9E75,/* 0xB8-0xBF */ - 0x9E7F,0x9EA5,0x9EBB,0x50A2,0x508D,0x5085,0x5099,0x5091,/* 0xC0-0xC7 */ - 0x5080,0x5096,0x5098,0x509A,0x6700,0x51F1,0x5272,0x5274,/* 0xC8-0xCF */ - 0x5275,0x5269,0x52DE,0x52DD,0x52DB,0x535A,0x53A5,0x557B,/* 0xD0-0xD7 */ - 0x5580,0x55A7,0x557C,0x558A,0x559D,0x5598,0x5582,0x559C,/* 0xD8-0xDF */ - 0x55AA,0x5594,0x5587,0x558B,0x5583,0x55B3,0x55AE,0x559F,/* 0xE0-0xE7 */ - 0x553E,0x55B2,0x559A,0x55BB,0x55AC,0x55B1,0x557E,0x5589,/* 0xE8-0xEF */ - 0x55AB,0x5599,0x570D,0x582F,0x582A,0x5834,0x5824,0x5830,/* 0xF0-0xF7 */ - 0x5831,0x5821,0x581D,0x5820,0x58F9,0x58FA,0x5960,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5A77,0x5A9A,0x5A7F,0x5A92,0x5A9B,0x5AA7,0x5B73,0x5B71,/* 0x40-0x47 */ - 0x5BD2,0x5BCC,0x5BD3,0x5BD0,0x5C0A,0x5C0B,0x5C31,0x5D4C,/* 0x48-0x4F */ - 0x5D50,0x5D34,0x5D47,0x5DFD,0x5E45,0x5E3D,0x5E40,0x5E43,/* 0x50-0x57 */ - 0x5E7E,0x5ECA,0x5EC1,0x5EC2,0x5EC4,0x5F3C,0x5F6D,0x5FA9,/* 0x58-0x5F */ - 0x5FAA,0x5FA8,0x60D1,0x60E1,0x60B2,0x60B6,0x60E0,0x611C,/* 0x60-0x67 */ - 0x6123,0x60FA,0x6115,0x60F0,0x60FB,0x60F4,0x6168,0x60F1,/* 0x68-0x6F */ - 0x610E,0x60F6,0x6109,0x6100,0x6112,0x621F,0x6249,0x63A3,/* 0x70-0x77 */ - 0x638C,0x63CF,0x63C0,0x63E9,0x63C9,0x63C6,0x63CD,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x63D2,0x63E3,0x63D0,0x63E1,0x63D6,0x63ED,0x63EE,/* 0xA0-0xA7 */ - 0x6376,0x63F4,0x63EA,0x63DB,0x6452,0x63DA,0x63F9,0x655E,/* 0xA8-0xAF */ - 0x6566,0x6562,0x6563,0x6591,0x6590,0x65AF,0x666E,0x6670,/* 0xB0-0xB7 */ - 0x6674,0x6676,0x666F,0x6691,0x667A,0x667E,0x6677,0x66FE,/* 0xB8-0xBF */ - 0x66FF,0x671F,0x671D,0x68FA,0x68D5,0x68E0,0x68D8,0x68D7,/* 0xC0-0xC7 */ - 0x6905,0x68DF,0x68F5,0x68EE,0x68E7,0x68F9,0x68D2,0x68F2,/* 0xC8-0xCF */ - 0x68E3,0x68CB,0x68CD,0x690D,0x6912,0x690E,0x68C9,0x68DA,/* 0xD0-0xD7 */ - 0x696E,0x68FB,0x6B3E,0x6B3A,0x6B3D,0x6B98,0x6B96,0x6BBC,/* 0xD8-0xDF */ - 0x6BEF,0x6C2E,0x6C2F,0x6C2C,0x6E2F,0x6E38,0x6E54,0x6E21,/* 0xE0-0xE7 */ - 0x6E32,0x6E67,0x6E4A,0x6E20,0x6E25,0x6E23,0x6E1B,0x6E5B,/* 0xE8-0xEF */ - 0x6E58,0x6E24,0x6E56,0x6E6E,0x6E2D,0x6E26,0x6E6F,0x6E34,/* 0xF0-0xF7 */ - 0x6E4D,0x6E3A,0x6E2C,0x6E43,0x6E1D,0x6E3E,0x6ECB,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6E89,0x6E19,0x6E4E,0x6E63,0x6E44,0x6E72,0x6E69,0x6E5F,/* 0x40-0x47 */ - 0x7119,0x711A,0x7126,0x7130,0x7121,0x7136,0x716E,0x711C,/* 0x48-0x4F */ - 0x724C,0x7284,0x7280,0x7336,0x7325,0x7334,0x7329,0x743A,/* 0x50-0x57 */ - 0x742A,0x7433,0x7422,0x7425,0x7435,0x7436,0x7434,0x742F,/* 0x58-0x5F */ - 0x741B,0x7426,0x7428,0x7525,0x7526,0x756B,0x756A,0x75E2,/* 0x60-0x67 */ - 0x75DB,0x75E3,0x75D9,0x75D8,0x75DE,0x75E0,0x767B,0x767C,/* 0x68-0x6F */ - 0x7696,0x7693,0x76B4,0x76DC,0x774F,0x77ED,0x785D,0x786C,/* 0x70-0x77 */ - 0x786F,0x7A0D,0x7A08,0x7A0B,0x7A05,0x7A00,0x7A98,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x7A97,0x7A96,0x7AE5,0x7AE3,0x7B49,0x7B56,0x7B46,/* 0xA0-0xA7 */ - 0x7B50,0x7B52,0x7B54,0x7B4D,0x7B4B,0x7B4F,0x7B51,0x7C9F,/* 0xA8-0xAF */ - 0x7CA5,0x7D5E,0x7D50,0x7D68,0x7D55,0x7D2B,0x7D6E,0x7D72,/* 0xB0-0xB7 */ - 0x7D61,0x7D66,0x7D62,0x7D70,0x7D73,0x5584,0x7FD4,0x7FD5,/* 0xB8-0xBF */ - 0x800B,0x8052,0x8085,0x8155,0x8154,0x814B,0x8151,0x814E,/* 0xC0-0xC7 */ - 0x8139,0x8146,0x813E,0x814C,0x8153,0x8174,0x8212,0x821C,/* 0xC8-0xCF */ - 0x83E9,0x8403,0x83F8,0x840D,0x83E0,0x83C5,0x840B,0x83C1,/* 0xD0-0xD7 */ - 0x83EF,0x83F1,0x83F4,0x8457,0x840A,0x83F0,0x840C,0x83CC,/* 0xD8-0xDF */ - 0x83FD,0x83F2,0x83CA,0x8438,0x840E,0x8404,0x83DC,0x8407,/* 0xE0-0xE7 */ - 0x83D4,0x83DF,0x865B,0x86DF,0x86D9,0x86ED,0x86D4,0x86DB,/* 0xE8-0xEF */ - 0x86E4,0x86D0,0x86DE,0x8857,0x88C1,0x88C2,0x88B1,0x8983,/* 0xF0-0xF7 */ - 0x8996,0x8A3B,0x8A60,0x8A55,0x8A5E,0x8A3C,0x8A41,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8A54,0x8A5B,0x8A50,0x8A46,0x8A34,0x8A3A,0x8A36,0x8A56,/* 0x40-0x47 */ - 0x8C61,0x8C82,0x8CAF,0x8CBC,0x8CB3,0x8CBD,0x8CC1,0x8CBB,/* 0x48-0x4F */ - 0x8CC0,0x8CB4,0x8CB7,0x8CB6,0x8CBF,0x8CB8,0x8D8A,0x8D85,/* 0x50-0x57 */ - 0x8D81,0x8DCE,0x8DDD,0x8DCB,0x8DDA,0x8DD1,0x8DCC,0x8DDB,/* 0x58-0x5F */ - 0x8DC6,0x8EFB,0x8EF8,0x8EFC,0x8F9C,0x902E,0x9035,0x9031,/* 0x60-0x67 */ - 0x9038,0x9032,0x9036,0x9102,0x90F5,0x9109,0x90FE,0x9163,/* 0x68-0x6F */ - 0x9165,0x91CF,0x9214,0x9215,0x9223,0x9209,0x921E,0x920D,/* 0x70-0x77 */ - 0x9210,0x9207,0x9211,0x9594,0x958F,0x958B,0x9591,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x9593,0x9592,0x958E,0x968A,0x968E,0x968B,0x967D,/* 0xA0-0xA7 */ - 0x9685,0x9686,0x968D,0x9672,0x9684,0x96C1,0x96C5,0x96C4,/* 0xA8-0xAF */ - 0x96C6,0x96C7,0x96EF,0x96F2,0x97CC,0x9805,0x9806,0x9808,/* 0xB0-0xB7 */ - 0x98E7,0x98EA,0x98EF,0x98E9,0x98F2,0x98ED,0x99AE,0x99AD,/* 0xB8-0xBF */ - 0x9EC3,0x9ECD,0x9ED1,0x4E82,0x50AD,0x50B5,0x50B2,0x50B3,/* 0xC0-0xC7 */ - 0x50C5,0x50BE,0x50AC,0x50B7,0x50BB,0x50AF,0x50C7,0x527F,/* 0xC8-0xCF */ - 0x5277,0x527D,0x52DF,0x52E6,0x52E4,0x52E2,0x52E3,0x532F,/* 0xD0-0xD7 */ - 0x55DF,0x55E8,0x55D3,0x55E6,0x55CE,0x55DC,0x55C7,0x55D1,/* 0xD8-0xDF */ - 0x55E3,0x55E4,0x55EF,0x55DA,0x55E1,0x55C5,0x55C6,0x55E5,/* 0xE0-0xE7 */ - 0x55C9,0x5712,0x5713,0x585E,0x5851,0x5858,0x5857,0x585A,/* 0xE8-0xEF */ - 0x5854,0x586B,0x584C,0x586D,0x584A,0x5862,0x5852,0x584B,/* 0xF0-0xF7 */ - 0x5967,0x5AC1,0x5AC9,0x5ACC,0x5ABE,0x5ABD,0x5ABC,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B7[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5AB3,0x5AC2,0x5AB2,0x5D69,0x5D6F,0x5E4C,0x5E79,0x5EC9,/* 0x40-0x47 */ - 0x5EC8,0x5F12,0x5F59,0x5FAC,0x5FAE,0x611A,0x610F,0x6148,/* 0x48-0x4F */ - 0x611F,0x60F3,0x611B,0x60F9,0x6101,0x6108,0x614E,0x614C,/* 0x50-0x57 */ - 0x6144,0x614D,0x613E,0x6134,0x6127,0x610D,0x6106,0x6137,/* 0x58-0x5F */ - 0x6221,0x6222,0x6413,0x643E,0x641E,0x642A,0x642D,0x643D,/* 0x60-0x67 */ - 0x642C,0x640F,0x641C,0x6414,0x640D,0x6436,0x6416,0x6417,/* 0x68-0x6F */ - 0x6406,0x656C,0x659F,0x65B0,0x6697,0x6689,0x6687,0x6688,/* 0x70-0x77 */ - 0x6696,0x6684,0x6698,0x668D,0x6703,0x6994,0x696D,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x695A,0x6977,0x6960,0x6954,0x6975,0x6930,0x6982,/* 0xA0-0xA7 */ - 0x694A,0x6968,0x696B,0x695E,0x6953,0x6979,0x6986,0x695D,/* 0xA8-0xAF */ - 0x6963,0x695B,0x6B47,0x6B72,0x6BC0,0x6BBF,0x6BD3,0x6BFD,/* 0xB0-0xB7 */ - 0x6EA2,0x6EAF,0x6ED3,0x6EB6,0x6EC2,0x6E90,0x6E9D,0x6EC7,/* 0xB8-0xBF */ - 0x6EC5,0x6EA5,0x6E98,0x6EBC,0x6EBA,0x6EAB,0x6ED1,0x6E96,/* 0xC0-0xC7 */ - 0x6E9C,0x6EC4,0x6ED4,0x6EAA,0x6EA7,0x6EB4,0x714E,0x7159,/* 0xC8-0xCF */ - 0x7169,0x7164,0x7149,0x7167,0x715C,0x716C,0x7166,0x714C,/* 0xD0-0xD7 */ - 0x7165,0x715E,0x7146,0x7168,0x7156,0x723A,0x7252,0x7337,/* 0xD8-0xDF */ - 0x7345,0x733F,0x733E,0x746F,0x745A,0x7455,0x745F,0x745E,/* 0xE0-0xE7 */ - 0x7441,0x743F,0x7459,0x745B,0x745C,0x7576,0x7578,0x7600,/* 0xE8-0xEF */ - 0x75F0,0x7601,0x75F2,0x75F1,0x75FA,0x75FF,0x75F4,0x75F3,/* 0xF0-0xF7 */ - 0x76DE,0x76DF,0x775B,0x776B,0x7766,0x775E,0x7763,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B8[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7779,0x776A,0x776C,0x775C,0x7765,0x7768,0x7762,0x77EE,/* 0x40-0x47 */ - 0x788E,0x78B0,0x7897,0x7898,0x788C,0x7889,0x787C,0x7891,/* 0x48-0x4F */ - 0x7893,0x787F,0x797A,0x797F,0x7981,0x842C,0x79BD,0x7A1C,/* 0x50-0x57 */ - 0x7A1A,0x7A20,0x7A14,0x7A1F,0x7A1E,0x7A9F,0x7AA0,0x7B77,/* 0x58-0x5F */ - 0x7BC0,0x7B60,0x7B6E,0x7B67,0x7CB1,0x7CB3,0x7CB5,0x7D93,/* 0x60-0x67 */ - 0x7D79,0x7D91,0x7D81,0x7D8F,0x7D5B,0x7F6E,0x7F69,0x7F6A,/* 0x68-0x6F */ - 0x7F72,0x7FA9,0x7FA8,0x7FA4,0x8056,0x8058,0x8086,0x8084,/* 0x70-0x77 */ - 0x8171,0x8170,0x8178,0x8165,0x816E,0x8173,0x816B,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x8179,0x817A,0x8166,0x8205,0x8247,0x8482,0x8477,/* 0xA0-0xA7 */ - 0x843D,0x8431,0x8475,0x8466,0x846B,0x8449,0x846C,0x845B,/* 0xA8-0xAF */ - 0x843C,0x8435,0x8461,0x8463,0x8469,0x846D,0x8446,0x865E,/* 0xB0-0xB7 */ - 0x865C,0x865F,0x86F9,0x8713,0x8708,0x8707,0x8700,0x86FE,/* 0xB8-0xBF */ - 0x86FB,0x8702,0x8703,0x8706,0x870A,0x8859,0x88DF,0x88D4,/* 0xC0-0xC7 */ - 0x88D9,0x88DC,0x88D8,0x88DD,0x88E1,0x88CA,0x88D5,0x88D2,/* 0xC8-0xCF */ - 0x899C,0x89E3,0x8A6B,0x8A72,0x8A73,0x8A66,0x8A69,0x8A70,/* 0xD0-0xD7 */ - 0x8A87,0x8A7C,0x8A63,0x8AA0,0x8A71,0x8A85,0x8A6D,0x8A62,/* 0xD8-0xDF */ - 0x8A6E,0x8A6C,0x8A79,0x8A7B,0x8A3E,0x8A68,0x8C62,0x8C8A,/* 0xE0-0xE7 */ - 0x8C89,0x8CCA,0x8CC7,0x8CC8,0x8CC4,0x8CB2,0x8CC3,0x8CC2,/* 0xE8-0xEF */ - 0x8CC5,0x8DE1,0x8DDF,0x8DE8,0x8DEF,0x8DF3,0x8DFA,0x8DEA,/* 0xF0-0xF7 */ - 0x8DE4,0x8DE6,0x8EB2,0x8F03,0x8F09,0x8EFE,0x8F0A,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_B9[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8F9F,0x8FB2,0x904B,0x904A,0x9053,0x9042,0x9054,0x903C,/* 0x40-0x47 */ - 0x9055,0x9050,0x9047,0x904F,0x904E,0x904D,0x9051,0x903E,/* 0x48-0x4F */ - 0x9041,0x9112,0x9117,0x916C,0x916A,0x9169,0x91C9,0x9237,/* 0x50-0x57 */ - 0x9257,0x9238,0x923D,0x9240,0x923E,0x925B,0x924B,0x9264,/* 0x58-0x5F */ - 0x9251,0x9234,0x9249,0x924D,0x9245,0x9239,0x923F,0x925A,/* 0x60-0x67 */ - 0x9598,0x9698,0x9694,0x9695,0x96CD,0x96CB,0x96C9,0x96CA,/* 0x68-0x6F */ - 0x96F7,0x96FB,0x96F9,0x96F6,0x9756,0x9774,0x9776,0x9810,/* 0x70-0x77 */ - 0x9811,0x9813,0x980A,0x9812,0x980C,0x98FC,0x98F4,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x98FD,0x98FE,0x99B3,0x99B1,0x99B4,0x9AE1,0x9CE9,/* 0xA0-0xA7 */ - 0x9E82,0x9F0E,0x9F13,0x9F20,0x50E7,0x50EE,0x50E5,0x50D6,/* 0xA8-0xAF */ - 0x50ED,0x50DA,0x50D5,0x50CF,0x50D1,0x50F1,0x50CE,0x50E9,/* 0xB0-0xB7 */ - 0x5162,0x51F3,0x5283,0x5282,0x5331,0x53AD,0x55FE,0x5600,/* 0xB8-0xBF */ - 0x561B,0x5617,0x55FD,0x5614,0x5606,0x5609,0x560D,0x560E,/* 0xC0-0xC7 */ - 0x55F7,0x5616,0x561F,0x5608,0x5610,0x55F6,0x5718,0x5716,/* 0xC8-0xCF */ - 0x5875,0x587E,0x5883,0x5893,0x588A,0x5879,0x5885,0x587D,/* 0xD0-0xD7 */ - 0x58FD,0x5925,0x5922,0x5924,0x596A,0x5969,0x5AE1,0x5AE6,/* 0xD8-0xDF */ - 0x5AE9,0x5AD7,0x5AD6,0x5AD8,0x5AE3,0x5B75,0x5BDE,0x5BE7,/* 0xE0-0xE7 */ - 0x5BE1,0x5BE5,0x5BE6,0x5BE8,0x5BE2,0x5BE4,0x5BDF,0x5C0D,/* 0xE8-0xEF */ - 0x5C62,0x5D84,0x5D87,0x5E5B,0x5E63,0x5E55,0x5E57,0x5E54,/* 0xF0-0xF7 */ - 0x5ED3,0x5ED6,0x5F0A,0x5F46,0x5F70,0x5FB9,0x6147,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_BA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x613F,0x614B,0x6177,0x6162,0x6163,0x615F,0x615A,0x6158,/* 0x40-0x47 */ - 0x6175,0x622A,0x6487,0x6458,0x6454,0x64A4,0x6478,0x645F,/* 0x48-0x4F */ - 0x647A,0x6451,0x6467,0x6434,0x646D,0x647B,0x6572,0x65A1,/* 0x50-0x57 */ - 0x65D7,0x65D6,0x66A2,0x66A8,0x669D,0x699C,0x69A8,0x6995,/* 0x58-0x5F */ - 0x69C1,0x69AE,0x69D3,0x69CB,0x699B,0x69B7,0x69BB,0x69AB,/* 0x60-0x67 */ - 0x69B4,0x69D0,0x69CD,0x69AD,0x69CC,0x69A6,0x69C3,0x69A3,/* 0x68-0x6F */ - 0x6B49,0x6B4C,0x6C33,0x6F33,0x6F14,0x6EFE,0x6F13,0x6EF4,/* 0x70-0x77 */ - 0x6F29,0x6F3E,0x6F20,0x6F2C,0x6F0F,0x6F02,0x6F22,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x6EFF,0x6EEF,0x6F06,0x6F31,0x6F38,0x6F32,0x6F23,/* 0xA0-0xA7 */ - 0x6F15,0x6F2B,0x6F2F,0x6F88,0x6F2A,0x6EEC,0x6F01,0x6EF2,/* 0xA8-0xAF */ - 0x6ECC,0x6EF7,0x7194,0x7199,0x717D,0x718A,0x7184,0x7192,/* 0xB0-0xB7 */ - 0x723E,0x7292,0x7296,0x7344,0x7350,0x7464,0x7463,0x746A,/* 0xB8-0xBF */ - 0x7470,0x746D,0x7504,0x7591,0x7627,0x760D,0x760B,0x7609,/* 0xC0-0xC7 */ - 0x7613,0x76E1,0x76E3,0x7784,0x777D,0x777F,0x7761,0x78C1,/* 0xC8-0xCF */ - 0x789F,0x78A7,0x78B3,0x78A9,0x78A3,0x798E,0x798F,0x798D,/* 0xD0-0xD7 */ - 0x7A2E,0x7A31,0x7AAA,0x7AA9,0x7AED,0x7AEF,0x7BA1,0x7B95,/* 0xD8-0xDF */ - 0x7B8B,0x7B75,0x7B97,0x7B9D,0x7B94,0x7B8F,0x7BB8,0x7B87,/* 0xE0-0xE7 */ - 0x7B84,0x7CB9,0x7CBD,0x7CBE,0x7DBB,0x7DB0,0x7D9C,0x7DBD,/* 0xE8-0xEF */ - 0x7DBE,0x7DA0,0x7DCA,0x7DB4,0x7DB2,0x7DB1,0x7DBA,0x7DA2,/* 0xF0-0xF7 */ - 0x7DBF,0x7DB5,0x7DB8,0x7DAD,0x7DD2,0x7DC7,0x7DAC,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_BB[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7F70,0x7FE0,0x7FE1,0x7FDF,0x805E,0x805A,0x8087,0x8150,/* 0x40-0x47 */ - 0x8180,0x818F,0x8188,0x818A,0x817F,0x8182,0x81E7,0x81FA,/* 0x48-0x4F */ - 0x8207,0x8214,0x821E,0x824B,0x84C9,0x84BF,0x84C6,0x84C4,/* 0x50-0x57 */ - 0x8499,0x849E,0x84B2,0x849C,0x84CB,0x84B8,0x84C0,0x84D3,/* 0x58-0x5F */ - 0x8490,0x84BC,0x84D1,0x84CA,0x873F,0x871C,0x873B,0x8722,/* 0x60-0x67 */ - 0x8725,0x8734,0x8718,0x8755,0x8737,0x8729,0x88F3,0x8902,/* 0x68-0x6F */ - 0x88F4,0x88F9,0x88F8,0x88FD,0x88E8,0x891A,0x88EF,0x8AA6,/* 0x70-0x77 */ - 0x8A8C,0x8A9E,0x8AA3,0x8A8D,0x8AA1,0x8A93,0x8AA4,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x8AAA,0x8AA5,0x8AA8,0x8A98,0x8A91,0x8A9A,0x8AA7,/* 0xA0-0xA7 */ - 0x8C6A,0x8C8D,0x8C8C,0x8CD3,0x8CD1,0x8CD2,0x8D6B,0x8D99,/* 0xA8-0xAF */ - 0x8D95,0x8DFC,0x8F14,0x8F12,0x8F15,0x8F13,0x8FA3,0x9060,/* 0xB0-0xB7 */ - 0x9058,0x905C,0x9063,0x9059,0x905E,0x9062,0x905D,0x905B,/* 0xB8-0xBF */ - 0x9119,0x9118,0x911E,0x9175,0x9178,0x9177,0x9174,0x9278,/* 0xC0-0xC7 */ - 0x9280,0x9285,0x9298,0x9296,0x927B,0x9293,0x929C,0x92A8,/* 0xC8-0xCF */ - 0x927C,0x9291,0x95A1,0x95A8,0x95A9,0x95A3,0x95A5,0x95A4,/* 0xD0-0xD7 */ - 0x9699,0x969C,0x969B,0x96CC,0x96D2,0x9700,0x977C,0x9785,/* 0xD8-0xDF */ - 0x97F6,0x9817,0x9818,0x98AF,0x98B1,0x9903,0x9905,0x990C,/* 0xE0-0xE7 */ - 0x9909,0x99C1,0x9AAF,0x9AB0,0x9AE6,0x9B41,0x9B42,0x9CF4,/* 0xE8-0xEF */ - 0x9CF6,0x9CF3,0x9EBC,0x9F3B,0x9F4A,0x5104,0x5100,0x50FB,/* 0xF0-0xF7 */ - 0x50F5,0x50F9,0x5102,0x5108,0x5109,0x5105,0x51DC,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_BC[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5287,0x5288,0x5289,0x528D,0x528A,0x52F0,0x53B2,0x562E,/* 0x40-0x47 */ - 0x563B,0x5639,0x5632,0x563F,0x5634,0x5629,0x5653,0x564E,/* 0x48-0x4F */ - 0x5657,0x5674,0x5636,0x562F,0x5630,0x5880,0x589F,0x589E,/* 0x50-0x57 */ - 0x58B3,0x589C,0x58AE,0x58A9,0x58A6,0x596D,0x5B09,0x5AFB,/* 0x58-0x5F */ - 0x5B0B,0x5AF5,0x5B0C,0x5B08,0x5BEE,0x5BEC,0x5BE9,0x5BEB,/* 0x60-0x67 */ - 0x5C64,0x5C65,0x5D9D,0x5D94,0x5E62,0x5E5F,0x5E61,0x5EE2,/* 0x68-0x6F */ - 0x5EDA,0x5EDF,0x5EDD,0x5EE3,0x5EE0,0x5F48,0x5F71,0x5FB7,/* 0x70-0x77 */ - 0x5FB5,0x6176,0x6167,0x616E,0x615D,0x6155,0x6182,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x617C,0x6170,0x616B,0x617E,0x61A7,0x6190,0x61AB,/* 0xA0-0xA7 */ - 0x618E,0x61AC,0x619A,0x61A4,0x6194,0x61AE,0x622E,0x6469,/* 0xA8-0xAF */ - 0x646F,0x6479,0x649E,0x64B2,0x6488,0x6490,0x64B0,0x64A5,/* 0xB0-0xB7 */ - 0x6493,0x6495,0x64A9,0x6492,0x64AE,0x64AD,0x64AB,0x649A,/* 0xB8-0xBF */ - 0x64AC,0x6499,0x64A2,0x64B3,0x6575,0x6577,0x6578,0x66AE,/* 0xC0-0xC7 */ - 0x66AB,0x66B4,0x66B1,0x6A23,0x6A1F,0x69E8,0x6A01,0x6A1E,/* 0xC8-0xCF */ - 0x6A19,0x69FD,0x6A21,0x6A13,0x6A0A,0x69F3,0x6A02,0x6A05,/* 0xD0-0xD7 */ - 0x69ED,0x6A11,0x6B50,0x6B4E,0x6BA4,0x6BC5,0x6BC6,0x6F3F,/* 0xD8-0xDF */ - 0x6F7C,0x6F84,0x6F51,0x6F66,0x6F54,0x6F86,0x6F6D,0x6F5B,/* 0xE0-0xE7 */ - 0x6F78,0x6F6E,0x6F8E,0x6F7A,0x6F70,0x6F64,0x6F97,0x6F58,/* 0xE8-0xEF */ - 0x6ED5,0x6F6F,0x6F60,0x6F5F,0x719F,0x71AC,0x71B1,0x71A8,/* 0xF0-0xF7 */ - 0x7256,0x729B,0x734E,0x7357,0x7469,0x748B,0x7483,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_BD[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x747E,0x7480,0x757F,0x7620,0x7629,0x761F,0x7624,0x7626,/* 0x40-0x47 */ - 0x7621,0x7622,0x769A,0x76BA,0x76E4,0x778E,0x7787,0x778C,/* 0x48-0x4F */ - 0x7791,0x778B,0x78CB,0x78C5,0x78BA,0x78CA,0x78BE,0x78D5,/* 0x50-0x57 */ - 0x78BC,0x78D0,0x7A3F,0x7A3C,0x7A40,0x7A3D,0x7A37,0x7A3B,/* 0x58-0x5F */ - 0x7AAF,0x7AAE,0x7BAD,0x7BB1,0x7BC4,0x7BB4,0x7BC6,0x7BC7,/* 0x60-0x67 */ - 0x7BC1,0x7BA0,0x7BCC,0x7CCA,0x7DE0,0x7DF4,0x7DEF,0x7DFB,/* 0x68-0x6F */ - 0x7DD8,0x7DEC,0x7DDD,0x7DE8,0x7DE3,0x7DDA,0x7DDE,0x7DE9,/* 0x70-0x77 */ - 0x7D9E,0x7DD9,0x7DF2,0x7DF9,0x7F75,0x7F77,0x7FAF,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x7FE9,0x8026,0x819B,0x819C,0x819D,0x81A0,0x819A,/* 0xA0-0xA7 */ - 0x8198,0x8517,0x853D,0x851A,0x84EE,0x852C,0x852D,0x8513,/* 0xA8-0xAF */ - 0x8511,0x8523,0x8521,0x8514,0x84EC,0x8525,0x84FF,0x8506,/* 0xB0-0xB7 */ - 0x8782,0x8774,0x8776,0x8760,0x8766,0x8778,0x8768,0x8759,/* 0xB8-0xBF */ - 0x8757,0x874C,0x8753,0x885B,0x885D,0x8910,0x8907,0x8912,/* 0xC0-0xC7 */ - 0x8913,0x8915,0x890A,0x8ABC,0x8AD2,0x8AC7,0x8AC4,0x8A95,/* 0xC8-0xCF */ - 0x8ACB,0x8AF8,0x8AB2,0x8AC9,0x8AC2,0x8ABF,0x8AB0,0x8AD6,/* 0xD0-0xD7 */ - 0x8ACD,0x8AB6,0x8AB9,0x8ADB,0x8C4C,0x8C4E,0x8C6C,0x8CE0,/* 0xD8-0xDF */ - 0x8CDE,0x8CE6,0x8CE4,0x8CEC,0x8CED,0x8CE2,0x8CE3,0x8CDC,/* 0xE0-0xE7 */ - 0x8CEA,0x8CE1,0x8D6D,0x8D9F,0x8DA3,0x8E2B,0x8E10,0x8E1D,/* 0xE8-0xEF */ - 0x8E22,0x8E0F,0x8E29,0x8E1F,0x8E21,0x8E1E,0x8EBA,0x8F1D,/* 0xF0-0xF7 */ - 0x8F1B,0x8F1F,0x8F29,0x8F26,0x8F2A,0x8F1C,0x8F1E,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_BE[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8F25,0x9069,0x906E,0x9068,0x906D,0x9077,0x9130,0x912D,/* 0x40-0x47 */ - 0x9127,0x9131,0x9187,0x9189,0x918B,0x9183,0x92C5,0x92BB,/* 0x48-0x4F */ - 0x92B7,0x92EA,0x92AC,0x92E4,0x92C1,0x92B3,0x92BC,0x92D2,/* 0x50-0x57 */ - 0x92C7,0x92F0,0x92B2,0x95AD,0x95B1,0x9704,0x9706,0x9707,/* 0x58-0x5F */ - 0x9709,0x9760,0x978D,0x978B,0x978F,0x9821,0x982B,0x981C,/* 0x60-0x67 */ - 0x98B3,0x990A,0x9913,0x9912,0x9918,0x99DD,0x99D0,0x99DF,/* 0x68-0x6F */ - 0x99DB,0x99D1,0x99D5,0x99D2,0x99D9,0x9AB7,0x9AEE,0x9AEF,/* 0x70-0x77 */ - 0x9B27,0x9B45,0x9B44,0x9B77,0x9B6F,0x9D06,0x9D09,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x9D03,0x9EA9,0x9EBE,0x9ECE,0x58A8,0x9F52,0x5112,/* 0xA0-0xA7 */ - 0x5118,0x5114,0x5110,0x5115,0x5180,0x51AA,0x51DD,0x5291,/* 0xA8-0xAF */ - 0x5293,0x52F3,0x5659,0x566B,0x5679,0x5669,0x5664,0x5678,/* 0xB0-0xB7 */ - 0x566A,0x5668,0x5665,0x5671,0x566F,0x566C,0x5662,0x5676,/* 0xB8-0xBF */ - 0x58C1,0x58BE,0x58C7,0x58C5,0x596E,0x5B1D,0x5B34,0x5B78,/* 0xC0-0xC7 */ - 0x5BF0,0x5C0E,0x5F4A,0x61B2,0x6191,0x61A9,0x618A,0x61CD,/* 0xC8-0xCF */ - 0x61B6,0x61BE,0x61CA,0x61C8,0x6230,0x64C5,0x64C1,0x64CB,/* 0xD0-0xD7 */ - 0x64BB,0x64BC,0x64DA,0x64C4,0x64C7,0x64C2,0x64CD,0x64BF,/* 0xD8-0xDF */ - 0x64D2,0x64D4,0x64BE,0x6574,0x66C6,0x66C9,0x66B9,0x66C4,/* 0xE0-0xE7 */ - 0x66C7,0x66B8,0x6A3D,0x6A38,0x6A3A,0x6A59,0x6A6B,0x6A58,/* 0xE8-0xEF */ - 0x6A39,0x6A44,0x6A62,0x6A61,0x6A4B,0x6A47,0x6A35,0x6A5F,/* 0xF0-0xF7 */ - 0x6A48,0x6B59,0x6B77,0x6C05,0x6FC2,0x6FB1,0x6FA1,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_BF[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6FC3,0x6FA4,0x6FC1,0x6FA7,0x6FB3,0x6FC0,0x6FB9,0x6FB6,/* 0x40-0x47 */ - 0x6FA6,0x6FA0,0x6FB4,0x71BE,0x71C9,0x71D0,0x71D2,0x71C8,/* 0x48-0x4F */ - 0x71D5,0x71B9,0x71CE,0x71D9,0x71DC,0x71C3,0x71C4,0x7368,/* 0x50-0x57 */ - 0x749C,0x74A3,0x7498,0x749F,0x749E,0x74E2,0x750C,0x750D,/* 0x58-0x5F */ - 0x7634,0x7638,0x763A,0x76E7,0x76E5,0x77A0,0x779E,0x779F,/* 0x60-0x67 */ - 0x77A5,0x78E8,0x78DA,0x78EC,0x78E7,0x79A6,0x7A4D,0x7A4E,/* 0x68-0x6F */ - 0x7A46,0x7A4C,0x7A4B,0x7ABA,0x7BD9,0x7C11,0x7BC9,0x7BE4,/* 0x70-0x77 */ - 0x7BDB,0x7BE1,0x7BE9,0x7BE6,0x7CD5,0x7CD6,0x7E0A,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x7E11,0x7E08,0x7E1B,0x7E23,0x7E1E,0x7E1D,0x7E09,/* 0xA0-0xA7 */ - 0x7E10,0x7F79,0x7FB2,0x7FF0,0x7FF1,0x7FEE,0x8028,0x81B3,/* 0xA8-0xAF */ - 0x81A9,0x81A8,0x81FB,0x8208,0x8258,0x8259,0x854A,0x8559,/* 0xB0-0xB7 */ - 0x8548,0x8568,0x8569,0x8543,0x8549,0x856D,0x856A,0x855E,/* 0xB8-0xBF */ - 0x8783,0x879F,0x879E,0x87A2,0x878D,0x8861,0x892A,0x8932,/* 0xC0-0xC7 */ - 0x8925,0x892B,0x8921,0x89AA,0x89A6,0x8AE6,0x8AFA,0x8AEB,/* 0xC8-0xCF */ - 0x8AF1,0x8B00,0x8ADC,0x8AE7,0x8AEE,0x8AFE,0x8B01,0x8B02,/* 0xD0-0xD7 */ - 0x8AF7,0x8AED,0x8AF3,0x8AF6,0x8AFC,0x8C6B,0x8C6D,0x8C93,/* 0xD8-0xDF */ - 0x8CF4,0x8E44,0x8E31,0x8E34,0x8E42,0x8E39,0x8E35,0x8F3B,/* 0xE0-0xE7 */ - 0x8F2F,0x8F38,0x8F33,0x8FA8,0x8FA6,0x9075,0x9074,0x9078,/* 0xE8-0xEF */ - 0x9072,0x907C,0x907A,0x9134,0x9192,0x9320,0x9336,0x92F8,/* 0xF0-0xF7 */ - 0x9333,0x932F,0x9322,0x92FC,0x932B,0x9304,0x931A,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C0[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9310,0x9326,0x9321,0x9315,0x932E,0x9319,0x95BB,0x96A7,/* 0x40-0x47 */ - 0x96A8,0x96AA,0x96D5,0x970E,0x9711,0x9716,0x970D,0x9713,/* 0x48-0x4F */ - 0x970F,0x975B,0x975C,0x9766,0x9798,0x9830,0x9838,0x983B,/* 0x50-0x57 */ - 0x9837,0x982D,0x9839,0x9824,0x9910,0x9928,0x991E,0x991B,/* 0x58-0x5F */ - 0x9921,0x991A,0x99ED,0x99E2,0x99F1,0x9AB8,0x9ABC,0x9AFB,/* 0x60-0x67 */ - 0x9AED,0x9B28,0x9B91,0x9D15,0x9D23,0x9D26,0x9D28,0x9D12,/* 0x68-0x6F */ - 0x9D1B,0x9ED8,0x9ED4,0x9F8D,0x9F9C,0x512A,0x511F,0x5121,/* 0x70-0x77 */ - 0x5132,0x52F5,0x568E,0x5680,0x5690,0x5685,0x5687,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x568F,0x58D5,0x58D3,0x58D1,0x58CE,0x5B30,0x5B2A,/* 0xA0-0xA7 */ - 0x5B24,0x5B7A,0x5C37,0x5C68,0x5DBC,0x5DBA,0x5DBD,0x5DB8,/* 0xA8-0xAF */ - 0x5E6B,0x5F4C,0x5FBD,0x61C9,0x61C2,0x61C7,0x61E6,0x61CB,/* 0xB0-0xB7 */ - 0x6232,0x6234,0x64CE,0x64CA,0x64D8,0x64E0,0x64F0,0x64E6,/* 0xB8-0xBF */ - 0x64EC,0x64F1,0x64E2,0x64ED,0x6582,0x6583,0x66D9,0x66D6,/* 0xC0-0xC7 */ - 0x6A80,0x6A94,0x6A84,0x6AA2,0x6A9C,0x6ADB,0x6AA3,0x6A7E,/* 0xC8-0xCF */ - 0x6A97,0x6A90,0x6AA0,0x6B5C,0x6BAE,0x6BDA,0x6C08,0x6FD8,/* 0xD0-0xD7 */ - 0x6FF1,0x6FDF,0x6FE0,0x6FDB,0x6FE4,0x6FEB,0x6FEF,0x6F80,/* 0xD8-0xDF */ - 0x6FEC,0x6FE1,0x6FE9,0x6FD5,0x6FEE,0x6FF0,0x71E7,0x71DF,/* 0xE0-0xE7 */ - 0x71EE,0x71E6,0x71E5,0x71ED,0x71EC,0x71F4,0x71E0,0x7235,/* 0xE8-0xEF */ - 0x7246,0x7370,0x7372,0x74A9,0x74B0,0x74A6,0x74A8,0x7646,/* 0xF0-0xF7 */ - 0x7642,0x764C,0x76EA,0x77B3,0x77AA,0x77B0,0x77AC,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x77A7,0x77AD,0x77EF,0x78F7,0x78FA,0x78F4,0x78EF,0x7901,/* 0x40-0x47 */ - 0x79A7,0x79AA,0x7A57,0x7ABF,0x7C07,0x7C0D,0x7BFE,0x7BF7,/* 0x48-0x4F */ - 0x7C0C,0x7BE0,0x7CE0,0x7CDC,0x7CDE,0x7CE2,0x7CDF,0x7CD9,/* 0x50-0x57 */ - 0x7CDD,0x7E2E,0x7E3E,0x7E46,0x7E37,0x7E32,0x7E43,0x7E2B,/* 0x58-0x5F */ - 0x7E3D,0x7E31,0x7E45,0x7E41,0x7E34,0x7E39,0x7E48,0x7E35,/* 0x60-0x67 */ - 0x7E3F,0x7E2F,0x7F44,0x7FF3,0x7FFC,0x8071,0x8072,0x8070,/* 0x68-0x6F */ - 0x806F,0x8073,0x81C6,0x81C3,0x81BA,0x81C2,0x81C0,0x81BF,/* 0x70-0x77 */ - 0x81BD,0x81C9,0x81BE,0x81E8,0x8209,0x8271,0x85AA,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x8584,0x857E,0x859C,0x8591,0x8594,0x85AF,0x859B,/* 0xA0-0xA7 */ - 0x8587,0x85A8,0x858A,0x8667,0x87C0,0x87D1,0x87B3,0x87D2,/* 0xA8-0xAF */ - 0x87C6,0x87AB,0x87BB,0x87BA,0x87C8,0x87CB,0x893B,0x8936,/* 0xB0-0xB7 */ - 0x8944,0x8938,0x893D,0x89AC,0x8B0E,0x8B17,0x8B19,0x8B1B,/* 0xB8-0xBF */ - 0x8B0A,0x8B20,0x8B1D,0x8B04,0x8B10,0x8C41,0x8C3F,0x8C73,/* 0xC0-0xC7 */ - 0x8CFA,0x8CFD,0x8CFC,0x8CF8,0x8CFB,0x8DA8,0x8E49,0x8E4B,/* 0xC8-0xCF */ - 0x8E48,0x8E4A,0x8F44,0x8F3E,0x8F42,0x8F45,0x8F3F,0x907F,/* 0xD0-0xD7 */ - 0x907D,0x9084,0x9081,0x9082,0x9080,0x9139,0x91A3,0x919E,/* 0xD8-0xDF */ - 0x919C,0x934D,0x9382,0x9328,0x9375,0x934A,0x9365,0x934B,/* 0xE0-0xE7 */ - 0x9318,0x937E,0x936C,0x935B,0x9370,0x935A,0x9354,0x95CA,/* 0xE8-0xEF */ - 0x95CB,0x95CC,0x95C8,0x95C6,0x96B1,0x96B8,0x96D6,0x971C,/* 0xF0-0xF7 */ - 0x971E,0x97A0,0x97D3,0x9846,0x98B6,0x9935,0x9A01,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x99FF,0x9BAE,0x9BAB,0x9BAA,0x9BAD,0x9D3B,0x9D3F,0x9E8B,/* 0x40-0x47 */ - 0x9ECF,0x9EDE,0x9EDC,0x9EDD,0x9EDB,0x9F3E,0x9F4B,0x53E2,/* 0x48-0x4F */ - 0x5695,0x56AE,0x58D9,0x58D8,0x5B38,0x5F5D,0x61E3,0x6233,/* 0x50-0x57 */ - 0x64F4,0x64F2,0x64FE,0x6506,0x64FA,0x64FB,0x64F7,0x65B7,/* 0x58-0x5F */ - 0x66DC,0x6726,0x6AB3,0x6AAC,0x6AC3,0x6ABB,0x6AB8,0x6AC2,/* 0x60-0x67 */ - 0x6AAE,0x6AAF,0x6B5F,0x6B78,0x6BAF,0x7009,0x700B,0x6FFE,/* 0x68-0x6F */ - 0x7006,0x6FFA,0x7011,0x700F,0x71FB,0x71FC,0x71FE,0x71F8,/* 0x70-0x77 */ - 0x7377,0x7375,0x74A7,0x74BF,0x7515,0x7656,0x7658,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x7652,0x77BD,0x77BF,0x77BB,0x77BC,0x790E,0x79AE,/* 0xA0-0xA7 */ - 0x7A61,0x7A62,0x7A60,0x7AC4,0x7AC5,0x7C2B,0x7C27,0x7C2A,/* 0xA8-0xAF */ - 0x7C1E,0x7C23,0x7C21,0x7CE7,0x7E54,0x7E55,0x7E5E,0x7E5A,/* 0xB0-0xB7 */ - 0x7E61,0x7E52,0x7E59,0x7F48,0x7FF9,0x7FFB,0x8077,0x8076,/* 0xB8-0xBF */ - 0x81CD,0x81CF,0x820A,0x85CF,0x85A9,0x85CD,0x85D0,0x85C9,/* 0xC0-0xC7 */ - 0x85B0,0x85BA,0x85B9,0x85A6,0x87EF,0x87EC,0x87F2,0x87E0,/* 0xC8-0xCF */ - 0x8986,0x89B2,0x89F4,0x8B28,0x8B39,0x8B2C,0x8B2B,0x8C50,/* 0xD0-0xD7 */ - 0x8D05,0x8E59,0x8E63,0x8E66,0x8E64,0x8E5F,0x8E55,0x8EC0,/* 0xD8-0xDF */ - 0x8F49,0x8F4D,0x9087,0x9083,0x9088,0x91AB,0x91AC,0x91D0,/* 0xE0-0xE7 */ - 0x9394,0x938A,0x9396,0x93A2,0x93B3,0x93AE,0x93AC,0x93B0,/* 0xE8-0xEF */ - 0x9398,0x939A,0x9397,0x95D4,0x95D6,0x95D0,0x95D5,0x96E2,/* 0xF0-0xF7 */ - 0x96DC,0x96D9,0x96DB,0x96DE,0x9724,0x97A3,0x97A6,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x97AD,0x97F9,0x984D,0x984F,0x984C,0x984E,0x9853,0x98BA,/* 0x40-0x47 */ - 0x993E,0x993F,0x993D,0x992E,0x99A5,0x9A0E,0x9AC1,0x9B03,/* 0x48-0x4F */ - 0x9B06,0x9B4F,0x9B4E,0x9B4D,0x9BCA,0x9BC9,0x9BFD,0x9BC8,/* 0x50-0x57 */ - 0x9BC0,0x9D51,0x9D5D,0x9D60,0x9EE0,0x9F15,0x9F2C,0x5133,/* 0x58-0x5F */ - 0x56A5,0x58DE,0x58DF,0x58E2,0x5BF5,0x9F90,0x5EEC,0x61F2,/* 0x60-0x67 */ - 0x61F7,0x61F6,0x61F5,0x6500,0x650F,0x66E0,0x66DD,0x6AE5,/* 0x68-0x6F */ - 0x6ADD,0x6ADA,0x6AD3,0x701B,0x701F,0x7028,0x701A,0x701D,/* 0x70-0x77 */ - 0x7015,0x7018,0x7206,0x720D,0x7258,0x72A2,0x7378,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x737A,0x74BD,0x74CA,0x74E3,0x7587,0x7586,0x765F,/* 0xA0-0xA7 */ - 0x7661,0x77C7,0x7919,0x79B1,0x7A6B,0x7A69,0x7C3E,0x7C3F,/* 0xA8-0xAF */ - 0x7C38,0x7C3D,0x7C37,0x7C40,0x7E6B,0x7E6D,0x7E79,0x7E69,/* 0xB0-0xB7 */ - 0x7E6A,0x7F85,0x7E73,0x7FB6,0x7FB9,0x7FB8,0x81D8,0x85E9,/* 0xB8-0xBF */ - 0x85DD,0x85EA,0x85D5,0x85E4,0x85E5,0x85F7,0x87FB,0x8805,/* 0xC0-0xC7 */ - 0x880D,0x87F9,0x87FE,0x8960,0x895F,0x8956,0x895E,0x8B41,/* 0xC8-0xCF */ - 0x8B5C,0x8B58,0x8B49,0x8B5A,0x8B4E,0x8B4F,0x8B46,0x8B59,/* 0xD0-0xD7 */ - 0x8D08,0x8D0A,0x8E7C,0x8E72,0x8E87,0x8E76,0x8E6C,0x8E7A,/* 0xD8-0xDF */ - 0x8E74,0x8F54,0x8F4E,0x8FAD,0x908A,0x908B,0x91B1,0x91AE,/* 0xE0-0xE7 */ - 0x93E1,0x93D1,0x93DF,0x93C3,0x93C8,0x93DC,0x93DD,0x93D6,/* 0xE8-0xEF */ - 0x93E2,0x93CD,0x93D8,0x93E4,0x93D7,0x93E8,0x95DC,0x96B4,/* 0xF0-0xF7 */ - 0x96E3,0x972A,0x9727,0x9761,0x97DC,0x97FB,0x985E,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x9858,0x985B,0x98BC,0x9945,0x9949,0x9A16,0x9A19,0x9B0D,/* 0x40-0x47 */ - 0x9BE8,0x9BE7,0x9BD6,0x9BDB,0x9D89,0x9D61,0x9D72,0x9D6A,/* 0x48-0x4F */ - 0x9D6C,0x9E92,0x9E97,0x9E93,0x9EB4,0x52F8,0x56A8,0x56B7,/* 0x50-0x57 */ - 0x56B6,0x56B4,0x56BC,0x58E4,0x5B40,0x5B43,0x5B7D,0x5BF6,/* 0x58-0x5F */ - 0x5DC9,0x61F8,0x61FA,0x6518,0x6514,0x6519,0x66E6,0x6727,/* 0x60-0x67 */ - 0x6AEC,0x703E,0x7030,0x7032,0x7210,0x737B,0x74CF,0x7662,/* 0x68-0x6F */ - 0x7665,0x7926,0x792A,0x792C,0x792B,0x7AC7,0x7AF6,0x7C4C,/* 0x70-0x77 */ - 0x7C43,0x7C4D,0x7CEF,0x7CF0,0x8FAE,0x7E7D,0x7E7C,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x7E82,0x7F4C,0x8000,0x81DA,0x8266,0x85FB,0x85F9,/* 0xA0-0xA7 */ - 0x8611,0x85FA,0x8606,0x860B,0x8607,0x860A,0x8814,0x8815,/* 0xA8-0xAF */ - 0x8964,0x89BA,0x89F8,0x8B70,0x8B6C,0x8B66,0x8B6F,0x8B5F,/* 0xB0-0xB7 */ - 0x8B6B,0x8D0F,0x8D0D,0x8E89,0x8E81,0x8E85,0x8E82,0x91B4,/* 0xB8-0xBF */ - 0x91CB,0x9418,0x9403,0x93FD,0x95E1,0x9730,0x98C4,0x9952,/* 0xC0-0xC7 */ - 0x9951,0x99A8,0x9A2B,0x9A30,0x9A37,0x9A35,0x9C13,0x9C0D,/* 0xC8-0xCF */ - 0x9E79,0x9EB5,0x9EE8,0x9F2F,0x9F5F,0x9F63,0x9F61,0x5137,/* 0xD0-0xD7 */ - 0x5138,0x56C1,0x56C0,0x56C2,0x5914,0x5C6C,0x5DCD,0x61FC,/* 0xD8-0xDF */ - 0x61FE,0x651D,0x651C,0x6595,0x66E9,0x6AFB,0x6B04,0x6AFA,/* 0xE0-0xE7 */ - 0x6BB2,0x704C,0x721B,0x72A7,0x74D6,0x74D4,0x7669,0x77D3,/* 0xE8-0xEF */ - 0x7C50,0x7E8F,0x7E8C,0x7FBC,0x8617,0x862D,0x861A,0x8823,/* 0xF0-0xF7 */ - 0x8822,0x8821,0x881F,0x896A,0x896C,0x89BD,0x8B74,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8B77,0x8B7D,0x8D13,0x8E8A,0x8E8D,0x8E8B,0x8F5F,0x8FAF,/* 0x40-0x47 */ - 0x91BA,0x942E,0x9433,0x9435,0x943A,0x9438,0x9432,0x942B,/* 0x48-0x4F */ - 0x95E2,0x9738,0x9739,0x9732,0x97FF,0x9867,0x9865,0x9957,/* 0x50-0x57 */ - 0x9A45,0x9A43,0x9A40,0x9A3E,0x9ACF,0x9B54,0x9B51,0x9C2D,/* 0x58-0x5F */ - 0x9C25,0x9DAF,0x9DB4,0x9DC2,0x9DB8,0x9E9D,0x9EEF,0x9F19,/* 0x60-0x67 */ - 0x9F5C,0x9F66,0x9F67,0x513C,0x513B,0x56C8,0x56CA,0x56C9,/* 0x68-0x6F */ - 0x5B7F,0x5DD4,0x5DD2,0x5F4E,0x61FF,0x6524,0x6B0A,0x6B61,/* 0x70-0x77 */ - 0x7051,0x7058,0x7380,0x74E4,0x758A,0x766E,0x766C,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x79B3,0x7C60,0x7C5F,0x807E,0x807D,0x81DF,0x8972,/* 0xA0-0xA7 */ - 0x896F,0x89FC,0x8B80,0x8D16,0x8D17,0x8E91,0x8E93,0x8F61,/* 0xA8-0xAF */ - 0x9148,0x9444,0x9451,0x9452,0x973D,0x973E,0x97C3,0x97C1,/* 0xB0-0xB7 */ - 0x986B,0x9955,0x9A55,0x9A4D,0x9AD2,0x9B1A,0x9C49,0x9C31,/* 0xB8-0xBF */ - 0x9C3E,0x9C3B,0x9DD3,0x9DD7,0x9F34,0x9F6C,0x9F6A,0x9F94,/* 0xC0-0xC7 */ - 0x56CC,0x5DD6,0x6200,0x6523,0x652B,0x652A,0x66EC,0x6B10,/* 0xC8-0xCF */ - 0x74DA,0x7ACA,0x7C64,0x7C63,0x7C65,0x7E93,0x7E96,0x7E94,/* 0xD0-0xD7 */ - 0x81E2,0x8638,0x863F,0x8831,0x8B8A,0x9090,0x908F,0x9463,/* 0xD8-0xDF */ - 0x9460,0x9464,0x9768,0x986F,0x995C,0x9A5A,0x9A5B,0x9A57,/* 0xE0-0xE7 */ - 0x9AD3,0x9AD4,0x9AD1,0x9C54,0x9C57,0x9C56,0x9DE5,0x9E9F,/* 0xE8-0xEF */ - 0x9EF4,0x56D1,0x58E9,0x652C,0x705E,0x7671,0x7672,0x77D7,/* 0xF0-0xF7 */ - 0x7F50,0x7F88,0x8836,0x8839,0x8862,0x8B93,0x8B92,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_C6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8B96,0x8277,0x8D1B,0x91C0,0x946A,0x9742,0x9748,0x9744,/* 0x40-0x47 */ - 0x97C6,0x9870,0x9A5F,0x9B22,0x9B58,0x9C5F,0x9DF9,0x9DFA,/* 0x48-0x4F */ - 0x9E7C,0x9E7D,0x9F07,0x9F77,0x9F72,0x5EF3,0x6B16,0x7063,/* 0x50-0x57 */ - 0x7C6C,0x7C6E,0x883B,0x89C0,0x8EA1,0x91C1,0x9472,0x9470,/* 0x58-0x5F */ - 0x9871,0x995E,0x9AD6,0x9B23,0x9ECC,0x7064,0x77DA,0x8B9A,/* 0x60-0x67 */ - 0x9477,0x97C9,0x9A62,0x9A65,0x7E9C,0x8B9C,0x8EAA,0x91C5,/* 0x68-0x6F */ - 0x947D,0x947E,0x947C,0x9C77,0x9C78,0x9EF7,0x8C54,0x947F,/* 0x70-0x77 */ - 0x9E1A,0x7228,0x9A6A,0x9B31,0x9E1B,0x9E1E,0x7C72,0x0000,/* 0x78-0x7F */ -}; - -static const wchar_t c2u_C9[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x4E42,0x4E5C,0x51F5,0x531A,0x5382,0x4E07,0x4E0C,0x4E47,/* 0x40-0x47 */ - 0x4E8D,0x56D7,0xFA0C,0x5C6E,0x5F73,0x4E0F,0x5187,0x4E0E,/* 0x48-0x4F */ - 0x4E2E,0x4E93,0x4EC2,0x4EC9,0x4EC8,0x5198,0x52FC,0x536C,/* 0x50-0x57 */ - 0x53B9,0x5720,0x5903,0x592C,0x5C10,0x5DFF,0x65E1,0x6BB3,/* 0x58-0x5F */ - 0x6BCC,0x6C14,0x723F,0x4E31,0x4E3C,0x4EE8,0x4EDC,0x4EE9,/* 0x60-0x67 */ - 0x4EE1,0x4EDD,0x4EDA,0x520C,0x531C,0x534C,0x5722,0x5723,/* 0x68-0x6F */ - 0x5917,0x592F,0x5B81,0x5B84,0x5C12,0x5C3B,0x5C74,0x5C73,/* 0x70-0x77 */ - 0x5E04,0x5E80,0x5E82,0x5FC9,0x6209,0x6250,0x6C15,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x6C36,0x6C43,0x6C3F,0x6C3B,0x72AE,0x72B0,0x738A,/* 0xA0-0xA7 */ - 0x79B8,0x808A,0x961E,0x4F0E,0x4F18,0x4F2C,0x4EF5,0x4F14,/* 0xA8-0xAF */ - 0x4EF1,0x4F00,0x4EF7,0x4F08,0x4F1D,0x4F02,0x4F05,0x4F22,/* 0xB0-0xB7 */ - 0x4F13,0x4F04,0x4EF4,0x4F12,0x51B1,0x5213,0x5209,0x5210,/* 0xB8-0xBF */ - 0x52A6,0x5322,0x531F,0x534D,0x538A,0x5407,0x56E1,0x56DF,/* 0xC0-0xC7 */ - 0x572E,0x572A,0x5734,0x593C,0x5980,0x597C,0x5985,0x597B,/* 0xC8-0xCF */ - 0x597E,0x5977,0x597F,0x5B56,0x5C15,0x5C25,0x5C7C,0x5C7A,/* 0xD0-0xD7 */ - 0x5C7B,0x5C7E,0x5DDF,0x5E75,0x5E84,0x5F02,0x5F1A,0x5F74,/* 0xD8-0xDF */ - 0x5FD5,0x5FD4,0x5FCF,0x625C,0x625E,0x6264,0x6261,0x6266,/* 0xE0-0xE7 */ - 0x6262,0x6259,0x6260,0x625A,0x6265,0x65EF,0x65EE,0x673E,/* 0xE8-0xEF */ - 0x6739,0x6738,0x673B,0x673A,0x673F,0x673C,0x6733,0x6C18,/* 0xF0-0xF7 */ - 0x6C46,0x6C52,0x6C5C,0x6C4F,0x6C4A,0x6C54,0x6C4B,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_CA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6C4C,0x7071,0x725E,0x72B4,0x72B5,0x738E,0x752A,0x767F,/* 0x40-0x47 */ - 0x7A75,0x7F51,0x8278,0x827C,0x8280,0x827D,0x827F,0x864D,/* 0x48-0x4F */ - 0x897E,0x9099,0x9097,0x9098,0x909B,0x9094,0x9622,0x9624,/* 0x50-0x57 */ - 0x9620,0x9623,0x4F56,0x4F3B,0x4F62,0x4F49,0x4F53,0x4F64,/* 0x58-0x5F */ - 0x4F3E,0x4F67,0x4F52,0x4F5F,0x4F41,0x4F58,0x4F2D,0x4F33,/* 0x60-0x67 */ - 0x4F3F,0x4F61,0x518F,0x51B9,0x521C,0x521E,0x5221,0x52AD,/* 0x68-0x6F */ - 0x52AE,0x5309,0x5363,0x5372,0x538E,0x538F,0x5430,0x5437,/* 0x70-0x77 */ - 0x542A,0x5454,0x5445,0x5419,0x541C,0x5425,0x5418,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x543D,0x544F,0x5441,0x5428,0x5424,0x5447,0x56EE,/* 0xA0-0xA7 */ - 0x56E7,0x56E5,0x5741,0x5745,0x574C,0x5749,0x574B,0x5752,/* 0xA8-0xAF */ - 0x5906,0x5940,0x59A6,0x5998,0x59A0,0x5997,0x598E,0x59A2,/* 0xB0-0xB7 */ - 0x5990,0x598F,0x59A7,0x59A1,0x5B8E,0x5B92,0x5C28,0x5C2A,/* 0xB8-0xBF */ - 0x5C8D,0x5C8F,0x5C88,0x5C8B,0x5C89,0x5C92,0x5C8A,0x5C86,/* 0xC0-0xC7 */ - 0x5C93,0x5C95,0x5DE0,0x5E0A,0x5E0E,0x5E8B,0x5E89,0x5E8C,/* 0xC8-0xCF */ - 0x5E88,0x5E8D,0x5F05,0x5F1D,0x5F78,0x5F76,0x5FD2,0x5FD1,/* 0xD0-0xD7 */ - 0x5FD0,0x5FED,0x5FE8,0x5FEE,0x5FF3,0x5FE1,0x5FE4,0x5FE3,/* 0xD8-0xDF */ - 0x5FFA,0x5FEF,0x5FF7,0x5FFB,0x6000,0x5FF4,0x623A,0x6283,/* 0xE0-0xE7 */ - 0x628C,0x628E,0x628F,0x6294,0x6287,0x6271,0x627B,0x627A,/* 0xE8-0xEF */ - 0x6270,0x6281,0x6288,0x6277,0x627D,0x6272,0x6274,0x6537,/* 0xF0-0xF7 */ - 0x65F0,0x65F4,0x65F3,0x65F2,0x65F5,0x6745,0x6747,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_CB[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6759,0x6755,0x674C,0x6748,0x675D,0x674D,0x675A,0x674B,/* 0x40-0x47 */ - 0x6BD0,0x6C19,0x6C1A,0x6C78,0x6C67,0x6C6B,0x6C84,0x6C8B,/* 0x48-0x4F */ - 0x6C8F,0x6C71,0x6C6F,0x6C69,0x6C9A,0x6C6D,0x6C87,0x6C95,/* 0x50-0x57 */ - 0x6C9C,0x6C66,0x6C73,0x6C65,0x6C7B,0x6C8E,0x7074,0x707A,/* 0x58-0x5F */ - 0x7263,0x72BF,0x72BD,0x72C3,0x72C6,0x72C1,0x72BA,0x72C5,/* 0x60-0x67 */ - 0x7395,0x7397,0x7393,0x7394,0x7392,0x753A,0x7539,0x7594,/* 0x68-0x6F */ - 0x7595,0x7681,0x793D,0x8034,0x8095,0x8099,0x8090,0x8092,/* 0x70-0x77 */ - 0x809C,0x8290,0x828F,0x8285,0x828E,0x8291,0x8293,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x828A,0x8283,0x8284,0x8C78,0x8FC9,0x8FBF,0x909F,/* 0xA0-0xA7 */ - 0x90A1,0x90A5,0x909E,0x90A7,0x90A0,0x9630,0x9628,0x962F,/* 0xA8-0xAF */ - 0x962D,0x4E33,0x4F98,0x4F7C,0x4F85,0x4F7D,0x4F80,0x4F87,/* 0xB0-0xB7 */ - 0x4F76,0x4F74,0x4F89,0x4F84,0x4F77,0x4F4C,0x4F97,0x4F6A,/* 0xB8-0xBF */ - 0x4F9A,0x4F79,0x4F81,0x4F78,0x4F90,0x4F9C,0x4F94,0x4F9E,/* 0xC0-0xC7 */ - 0x4F92,0x4F82,0x4F95,0x4F6B,0x4F6E,0x519E,0x51BC,0x51BE,/* 0xC8-0xCF */ - 0x5235,0x5232,0x5233,0x5246,0x5231,0x52BC,0x530A,0x530B,/* 0xD0-0xD7 */ - 0x533C,0x5392,0x5394,0x5487,0x547F,0x5481,0x5491,0x5482,/* 0xD8-0xDF */ - 0x5488,0x546B,0x547A,0x547E,0x5465,0x546C,0x5474,0x5466,/* 0xE0-0xE7 */ - 0x548D,0x546F,0x5461,0x5460,0x5498,0x5463,0x5467,0x5464,/* 0xE8-0xEF */ - 0x56F7,0x56F9,0x576F,0x5772,0x576D,0x576B,0x5771,0x5770,/* 0xF0-0xF7 */ - 0x5776,0x5780,0x5775,0x577B,0x5773,0x5774,0x5762,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_CC[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5768,0x577D,0x590C,0x5945,0x59B5,0x59BA,0x59CF,0x59CE,/* 0x40-0x47 */ - 0x59B2,0x59CC,0x59C1,0x59B6,0x59BC,0x59C3,0x59D6,0x59B1,/* 0x48-0x4F */ - 0x59BD,0x59C0,0x59C8,0x59B4,0x59C7,0x5B62,0x5B65,0x5B93,/* 0x50-0x57 */ - 0x5B95,0x5C44,0x5C47,0x5CAE,0x5CA4,0x5CA0,0x5CB5,0x5CAF,/* 0x58-0x5F */ - 0x5CA8,0x5CAC,0x5C9F,0x5CA3,0x5CAD,0x5CA2,0x5CAA,0x5CA7,/* 0x60-0x67 */ - 0x5C9D,0x5CA5,0x5CB6,0x5CB0,0x5CA6,0x5E17,0x5E14,0x5E19,/* 0x68-0x6F */ - 0x5F28,0x5F22,0x5F23,0x5F24,0x5F54,0x5F82,0x5F7E,0x5F7D,/* 0x70-0x77 */ - 0x5FDE,0x5FE5,0x602D,0x6026,0x6019,0x6032,0x600B,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x6034,0x600A,0x6017,0x6033,0x601A,0x601E,0x602C,/* 0xA0-0xA7 */ - 0x6022,0x600D,0x6010,0x602E,0x6013,0x6011,0x600C,0x6009,/* 0xA8-0xAF */ - 0x601C,0x6214,0x623D,0x62AD,0x62B4,0x62D1,0x62BE,0x62AA,/* 0xB0-0xB7 */ - 0x62B6,0x62CA,0x62AE,0x62B3,0x62AF,0x62BB,0x62A9,0x62B0,/* 0xB8-0xBF */ - 0x62B8,0x653D,0x65A8,0x65BB,0x6609,0x65FC,0x6604,0x6612,/* 0xC0-0xC7 */ - 0x6608,0x65FB,0x6603,0x660B,0x660D,0x6605,0x65FD,0x6611,/* 0xC8-0xCF */ - 0x6610,0x66F6,0x670A,0x6785,0x676C,0x678E,0x6792,0x6776,/* 0xD0-0xD7 */ - 0x677B,0x6798,0x6786,0x6784,0x6774,0x678D,0x678C,0x677A,/* 0xD8-0xDF */ - 0x679F,0x6791,0x6799,0x6783,0x677D,0x6781,0x6778,0x6779,/* 0xE0-0xE7 */ - 0x6794,0x6B25,0x6B80,0x6B7E,0x6BDE,0x6C1D,0x6C93,0x6CEC,/* 0xE8-0xEF */ - 0x6CEB,0x6CEE,0x6CD9,0x6CB6,0x6CD4,0x6CAD,0x6CE7,0x6CB7,/* 0xF0-0xF7 */ - 0x6CD0,0x6CC2,0x6CBA,0x6CC3,0x6CC6,0x6CED,0x6CF2,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_CD[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6CD2,0x6CDD,0x6CB4,0x6C8A,0x6C9D,0x6C80,0x6CDE,0x6CC0,/* 0x40-0x47 */ - 0x6D30,0x6CCD,0x6CC7,0x6CB0,0x6CF9,0x6CCF,0x6CE9,0x6CD1,/* 0x48-0x4F */ - 0x7094,0x7098,0x7085,0x7093,0x7086,0x7084,0x7091,0x7096,/* 0x50-0x57 */ - 0x7082,0x709A,0x7083,0x726A,0x72D6,0x72CB,0x72D8,0x72C9,/* 0x58-0x5F */ - 0x72DC,0x72D2,0x72D4,0x72DA,0x72CC,0x72D1,0x73A4,0x73A1,/* 0x60-0x67 */ - 0x73AD,0x73A6,0x73A2,0x73A0,0x73AC,0x739D,0x74DD,0x74E8,/* 0x68-0x6F */ - 0x753F,0x7540,0x753E,0x758C,0x7598,0x76AF,0x76F3,0x76F1,/* 0x70-0x77 */ - 0x76F0,0x76F5,0x77F8,0x77FC,0x77F9,0x77FB,0x77FA,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x77F7,0x7942,0x793F,0x79C5,0x7A78,0x7A7B,0x7AFB,/* 0xA0-0xA7 */ - 0x7C75,0x7CFD,0x8035,0x808F,0x80AE,0x80A3,0x80B8,0x80B5,/* 0xA8-0xAF */ - 0x80AD,0x8220,0x82A0,0x82C0,0x82AB,0x829A,0x8298,0x829B,/* 0xB0-0xB7 */ - 0x82B5,0x82A7,0x82AE,0x82BC,0x829E,0x82BA,0x82B4,0x82A8,/* 0xB8-0xBF */ - 0x82A1,0x82A9,0x82C2,0x82A4,0x82C3,0x82B6,0x82A2,0x8670,/* 0xC0-0xC7 */ - 0x866F,0x866D,0x866E,0x8C56,0x8FD2,0x8FCB,0x8FD3,0x8FCD,/* 0xC8-0xCF */ - 0x8FD6,0x8FD5,0x8FD7,0x90B2,0x90B4,0x90AF,0x90B3,0x90B0,/* 0xD0-0xD7 */ - 0x9639,0x963D,0x963C,0x963A,0x9643,0x4FCD,0x4FC5,0x4FD3,/* 0xD8-0xDF */ - 0x4FB2,0x4FC9,0x4FCB,0x4FC1,0x4FD4,0x4FDC,0x4FD9,0x4FBB,/* 0xE0-0xE7 */ - 0x4FB3,0x4FDB,0x4FC7,0x4FD6,0x4FBA,0x4FC0,0x4FB9,0x4FEC,/* 0xE8-0xEF */ - 0x5244,0x5249,0x52C0,0x52C2,0x533D,0x537C,0x5397,0x5396,/* 0xF0-0xF7 */ - 0x5399,0x5398,0x54BA,0x54A1,0x54AD,0x54A5,0x54CF,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_CE[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x54C3,0x830D,0x54B7,0x54AE,0x54D6,0x54B6,0x54C5,0x54C6,/* 0x40-0x47 */ - 0x54A0,0x5470,0x54BC,0x54A2,0x54BE,0x5472,0x54DE,0x54B0,/* 0x48-0x4F */ - 0x57B5,0x579E,0x579F,0x57A4,0x578C,0x5797,0x579D,0x579B,/* 0x50-0x57 */ - 0x5794,0x5798,0x578F,0x5799,0x57A5,0x579A,0x5795,0x58F4,/* 0x58-0x5F */ - 0x590D,0x5953,0x59E1,0x59DE,0x59EE,0x5A00,0x59F1,0x59DD,/* 0x60-0x67 */ - 0x59FA,0x59FD,0x59FC,0x59F6,0x59E4,0x59F2,0x59F7,0x59DB,/* 0x68-0x6F */ - 0x59E9,0x59F3,0x59F5,0x59E0,0x59FE,0x59F4,0x59ED,0x5BA8,/* 0x70-0x77 */ - 0x5C4C,0x5CD0,0x5CD8,0x5CCC,0x5CD7,0x5CCB,0x5CDB,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x5CDE,0x5CDA,0x5CC9,0x5CC7,0x5CCA,0x5CD6,0x5CD3,/* 0xA0-0xA7 */ - 0x5CD4,0x5CCF,0x5CC8,0x5CC6,0x5CCE,0x5CDF,0x5CF8,0x5DF9,/* 0xA8-0xAF */ - 0x5E21,0x5E22,0x5E23,0x5E20,0x5E24,0x5EB0,0x5EA4,0x5EA2,/* 0xB0-0xB7 */ - 0x5E9B,0x5EA3,0x5EA5,0x5F07,0x5F2E,0x5F56,0x5F86,0x6037,/* 0xB8-0xBF */ - 0x6039,0x6054,0x6072,0x605E,0x6045,0x6053,0x6047,0x6049,/* 0xC0-0xC7 */ - 0x605B,0x604C,0x6040,0x6042,0x605F,0x6024,0x6044,0x6058,/* 0xC8-0xCF */ - 0x6066,0x606E,0x6242,0x6243,0x62CF,0x630D,0x630B,0x62F5,/* 0xD0-0xD7 */ - 0x630E,0x6303,0x62EB,0x62F9,0x630F,0x630C,0x62F8,0x62F6,/* 0xD8-0xDF */ - 0x6300,0x6313,0x6314,0x62FA,0x6315,0x62FB,0x62F0,0x6541,/* 0xE0-0xE7 */ - 0x6543,0x65AA,0x65BF,0x6636,0x6621,0x6632,0x6635,0x661C,/* 0xE8-0xEF */ - 0x6626,0x6622,0x6633,0x662B,0x663A,0x661D,0x6634,0x6639,/* 0xF0-0xF7 */ - 0x662E,0x670F,0x6710,0x67C1,0x67F2,0x67C8,0x67BA,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_CF[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x67DC,0x67BB,0x67F8,0x67D8,0x67C0,0x67B7,0x67C5,0x67EB,/* 0x40-0x47 */ - 0x67E4,0x67DF,0x67B5,0x67CD,0x67B3,0x67F7,0x67F6,0x67EE,/* 0x48-0x4F */ - 0x67E3,0x67C2,0x67B9,0x67CE,0x67E7,0x67F0,0x67B2,0x67FC,/* 0x50-0x57 */ - 0x67C6,0x67ED,0x67CC,0x67AE,0x67E6,0x67DB,0x67FA,0x67C9,/* 0x58-0x5F */ - 0x67CA,0x67C3,0x67EA,0x67CB,0x6B28,0x6B82,0x6B84,0x6BB6,/* 0x60-0x67 */ - 0x6BD6,0x6BD8,0x6BE0,0x6C20,0x6C21,0x6D28,0x6D34,0x6D2D,/* 0x68-0x6F */ - 0x6D1F,0x6D3C,0x6D3F,0x6D12,0x6D0A,0x6CDA,0x6D33,0x6D04,/* 0x70-0x77 */ - 0x6D19,0x6D3A,0x6D1A,0x6D11,0x6D00,0x6D1D,0x6D42,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x6D01,0x6D18,0x6D37,0x6D03,0x6D0F,0x6D40,0x6D07,/* 0xA0-0xA7 */ - 0x6D20,0x6D2C,0x6D08,0x6D22,0x6D09,0x6D10,0x70B7,0x709F,/* 0xA8-0xAF */ - 0x70BE,0x70B1,0x70B0,0x70A1,0x70B4,0x70B5,0x70A9,0x7241,/* 0xB0-0xB7 */ - 0x7249,0x724A,0x726C,0x7270,0x7273,0x726E,0x72CA,0x72E4,/* 0xB8-0xBF */ - 0x72E8,0x72EB,0x72DF,0x72EA,0x72E6,0x72E3,0x7385,0x73CC,/* 0xC0-0xC7 */ - 0x73C2,0x73C8,0x73C5,0x73B9,0x73B6,0x73B5,0x73B4,0x73EB,/* 0xC8-0xCF */ - 0x73BF,0x73C7,0x73BE,0x73C3,0x73C6,0x73B8,0x73CB,0x74EC,/* 0xD0-0xD7 */ - 0x74EE,0x752E,0x7547,0x7548,0x75A7,0x75AA,0x7679,0x76C4,/* 0xD8-0xDF */ - 0x7708,0x7703,0x7704,0x7705,0x770A,0x76F7,0x76FB,0x76FA,/* 0xE0-0xE7 */ - 0x77E7,0x77E8,0x7806,0x7811,0x7812,0x7805,0x7810,0x780F,/* 0xE8-0xEF */ - 0x780E,0x7809,0x7803,0x7813,0x794A,0x794C,0x794B,0x7945,/* 0xF0-0xF7 */ - 0x7944,0x79D5,0x79CD,0x79CF,0x79D6,0x79CE,0x7A80,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D0[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7A7E,0x7AD1,0x7B00,0x7B01,0x7C7A,0x7C78,0x7C79,0x7C7F,/* 0x40-0x47 */ - 0x7C80,0x7C81,0x7D03,0x7D08,0x7D01,0x7F58,0x7F91,0x7F8D,/* 0x48-0x4F */ - 0x7FBE,0x8007,0x800E,0x800F,0x8014,0x8037,0x80D8,0x80C7,/* 0x50-0x57 */ - 0x80E0,0x80D1,0x80C8,0x80C2,0x80D0,0x80C5,0x80E3,0x80D9,/* 0x58-0x5F */ - 0x80DC,0x80CA,0x80D5,0x80C9,0x80CF,0x80D7,0x80E6,0x80CD,/* 0x60-0x67 */ - 0x81FF,0x8221,0x8294,0x82D9,0x82FE,0x82F9,0x8307,0x82E8,/* 0x68-0x6F */ - 0x8300,0x82D5,0x833A,0x82EB,0x82D6,0x82F4,0x82EC,0x82E1,/* 0x70-0x77 */ - 0x82F2,0x82F5,0x830C,0x82FB,0x82F6,0x82F0,0x82EA,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x82E4,0x82E0,0x82FA,0x82F3,0x82ED,0x8677,0x8674,/* 0xA0-0xA7 */ - 0x867C,0x8673,0x8841,0x884E,0x8867,0x886A,0x8869,0x89D3,/* 0xA8-0xAF */ - 0x8A04,0x8A07,0x8D72,0x8FE3,0x8FE1,0x8FEE,0x8FE0,0x90F1,/* 0xB0-0xB7 */ - 0x90BD,0x90BF,0x90D5,0x90C5,0x90BE,0x90C7,0x90CB,0x90C8,/* 0xB8-0xBF */ - 0x91D4,0x91D3,0x9654,0x964F,0x9651,0x9653,0x964A,0x964E,/* 0xC0-0xC7 */ - 0x501E,0x5005,0x5007,0x5013,0x5022,0x5030,0x501B,0x4FF5,/* 0xC8-0xCF */ - 0x4FF4,0x5033,0x5037,0x502C,0x4FF6,0x4FF7,0x5017,0x501C,/* 0xD0-0xD7 */ - 0x5020,0x5027,0x5035,0x502F,0x5031,0x500E,0x515A,0x5194,/* 0xD8-0xDF */ - 0x5193,0x51CA,0x51C4,0x51C5,0x51C8,0x51CE,0x5261,0x525A,/* 0xE0-0xE7 */ - 0x5252,0x525E,0x525F,0x5255,0x5262,0x52CD,0x530E,0x539E,/* 0xE8-0xEF */ - 0x5526,0x54E2,0x5517,0x5512,0x54E7,0x54F3,0x54E4,0x551A,/* 0xF0-0xF7 */ - 0x54FF,0x5504,0x5508,0x54EB,0x5511,0x5505,0x54F1,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x550A,0x54FB,0x54F7,0x54F8,0x54E0,0x550E,0x5503,0x550B,/* 0x40-0x47 */ - 0x5701,0x5702,0x57CC,0x5832,0x57D5,0x57D2,0x57BA,0x57C6,/* 0x48-0x4F */ - 0x57BD,0x57BC,0x57B8,0x57B6,0x57BF,0x57C7,0x57D0,0x57B9,/* 0x50-0x57 */ - 0x57C1,0x590E,0x594A,0x5A19,0x5A16,0x5A2D,0x5A2E,0x5A15,/* 0x58-0x5F */ - 0x5A0F,0x5A17,0x5A0A,0x5A1E,0x5A33,0x5B6C,0x5BA7,0x5BAD,/* 0x60-0x67 */ - 0x5BAC,0x5C03,0x5C56,0x5C54,0x5CEC,0x5CFF,0x5CEE,0x5CF1,/* 0x68-0x6F */ - 0x5CF7,0x5D00,0x5CF9,0x5E29,0x5E28,0x5EA8,0x5EAE,0x5EAA,/* 0x70-0x77 */ - 0x5EAC,0x5F33,0x5F30,0x5F67,0x605D,0x605A,0x6067,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x6041,0x60A2,0x6088,0x6080,0x6092,0x6081,0x609D,/* 0xA0-0xA7 */ - 0x6083,0x6095,0x609B,0x6097,0x6087,0x609C,0x608E,0x6219,/* 0xA8-0xAF */ - 0x6246,0x62F2,0x6310,0x6356,0x632C,0x6344,0x6345,0x6336,/* 0xB0-0xB7 */ - 0x6343,0x63E4,0x6339,0x634B,0x634A,0x633C,0x6329,0x6341,/* 0xB8-0xBF */ - 0x6334,0x6358,0x6354,0x6359,0x632D,0x6347,0x6333,0x635A,/* 0xC0-0xC7 */ - 0x6351,0x6338,0x6357,0x6340,0x6348,0x654A,0x6546,0x65C6,/* 0xC8-0xCF */ - 0x65C3,0x65C4,0x65C2,0x664A,0x665F,0x6647,0x6651,0x6712,/* 0xD0-0xD7 */ - 0x6713,0x681F,0x681A,0x6849,0x6832,0x6833,0x683B,0x684B,/* 0xD8-0xDF */ - 0x684F,0x6816,0x6831,0x681C,0x6835,0x682B,0x682D,0x682F,/* 0xE0-0xE7 */ - 0x684E,0x6844,0x6834,0x681D,0x6812,0x6814,0x6826,0x6828,/* 0xE8-0xEF */ - 0x682E,0x684D,0x683A,0x6825,0x6820,0x6B2C,0x6B2F,0x6B2D,/* 0xF0-0xF7 */ - 0x6B31,0x6B34,0x6B6D,0x8082,0x6B88,0x6BE6,0x6BE4,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6BE8,0x6BE3,0x6BE2,0x6BE7,0x6C25,0x6D7A,0x6D63,0x6D64,/* 0x40-0x47 */ - 0x6D76,0x6D0D,0x6D61,0x6D92,0x6D58,0x6D62,0x6D6D,0x6D6F,/* 0x48-0x4F */ - 0x6D91,0x6D8D,0x6DEF,0x6D7F,0x6D86,0x6D5E,0x6D67,0x6D60,/* 0x50-0x57 */ - 0x6D97,0x6D70,0x6D7C,0x6D5F,0x6D82,0x6D98,0x6D2F,0x6D68,/* 0x58-0x5F */ - 0x6D8B,0x6D7E,0x6D80,0x6D84,0x6D16,0x6D83,0x6D7B,0x6D7D,/* 0x60-0x67 */ - 0x6D75,0x6D90,0x70DC,0x70D3,0x70D1,0x70DD,0x70CB,0x7F39,/* 0x68-0x6F */ - 0x70E2,0x70D7,0x70D2,0x70DE,0x70E0,0x70D4,0x70CD,0x70C5,/* 0x70-0x77 */ - 0x70C6,0x70C7,0x70DA,0x70CE,0x70E1,0x7242,0x7278,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x7277,0x7276,0x7300,0x72FA,0x72F4,0x72FE,0x72F6,/* 0xA0-0xA7 */ - 0x72F3,0x72FB,0x7301,0x73D3,0x73D9,0x73E5,0x73D6,0x73BC,/* 0xA8-0xAF */ - 0x73E7,0x73E3,0x73E9,0x73DC,0x73D2,0x73DB,0x73D4,0x73DD,/* 0xB0-0xB7 */ - 0x73DA,0x73D7,0x73D8,0x73E8,0x74DE,0x74DF,0x74F4,0x74F5,/* 0xB8-0xBF */ - 0x7521,0x755B,0x755F,0x75B0,0x75C1,0x75BB,0x75C4,0x75C0,/* 0xC0-0xC7 */ - 0x75BF,0x75B6,0x75BA,0x768A,0x76C9,0x771D,0x771B,0x7710,/* 0xC8-0xCF */ - 0x7713,0x7712,0x7723,0x7711,0x7715,0x7719,0x771A,0x7722,/* 0xD0-0xD7 */ - 0x7727,0x7823,0x782C,0x7822,0x7835,0x782F,0x7828,0x782E,/* 0xD8-0xDF */ - 0x782B,0x7821,0x7829,0x7833,0x782A,0x7831,0x7954,0x795B,/* 0xE0-0xE7 */ - 0x794F,0x795C,0x7953,0x7952,0x7951,0x79EB,0x79EC,0x79E0,/* 0xE8-0xEF */ - 0x79EE,0x79ED,0x79EA,0x79DC,0x79DE,0x79DD,0x7A86,0x7A89,/* 0xF0-0xF7 */ - 0x7A85,0x7A8B,0x7A8C,0x7A8A,0x7A87,0x7AD8,0x7B10,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7B04,0x7B13,0x7B05,0x7B0F,0x7B08,0x7B0A,0x7B0E,0x7B09,/* 0x40-0x47 */ - 0x7B12,0x7C84,0x7C91,0x7C8A,0x7C8C,0x7C88,0x7C8D,0x7C85,/* 0x48-0x4F */ - 0x7D1E,0x7D1D,0x7D11,0x7D0E,0x7D18,0x7D16,0x7D13,0x7D1F,/* 0x50-0x57 */ - 0x7D12,0x7D0F,0x7D0C,0x7F5C,0x7F61,0x7F5E,0x7F60,0x7F5D,/* 0x58-0x5F */ - 0x7F5B,0x7F96,0x7F92,0x7FC3,0x7FC2,0x7FC0,0x8016,0x803E,/* 0x60-0x67 */ - 0x8039,0x80FA,0x80F2,0x80F9,0x80F5,0x8101,0x80FB,0x8100,/* 0x68-0x6F */ - 0x8201,0x822F,0x8225,0x8333,0x832D,0x8344,0x8319,0x8351,/* 0x70-0x77 */ - 0x8325,0x8356,0x833F,0x8341,0x8326,0x831C,0x8322,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x8342,0x834E,0x831B,0x832A,0x8308,0x833C,0x834D,/* 0xA0-0xA7 */ - 0x8316,0x8324,0x8320,0x8337,0x832F,0x8329,0x8347,0x8345,/* 0xA8-0xAF */ - 0x834C,0x8353,0x831E,0x832C,0x834B,0x8327,0x8348,0x8653,/* 0xB0-0xB7 */ - 0x8652,0x86A2,0x86A8,0x8696,0x868D,0x8691,0x869E,0x8687,/* 0xB8-0xBF */ - 0x8697,0x8686,0x868B,0x869A,0x8685,0x86A5,0x8699,0x86A1,/* 0xC0-0xC7 */ - 0x86A7,0x8695,0x8698,0x868E,0x869D,0x8690,0x8694,0x8843,/* 0xC8-0xCF */ - 0x8844,0x886D,0x8875,0x8876,0x8872,0x8880,0x8871,0x887F,/* 0xD0-0xD7 */ - 0x886F,0x8883,0x887E,0x8874,0x887C,0x8A12,0x8C47,0x8C57,/* 0xD8-0xDF */ - 0x8C7B,0x8CA4,0x8CA3,0x8D76,0x8D78,0x8DB5,0x8DB7,0x8DB6,/* 0xE0-0xE7 */ - 0x8ED1,0x8ED3,0x8FFE,0x8FF5,0x9002,0x8FFF,0x8FFB,0x9004,/* 0xE8-0xEF */ - 0x8FFC,0x8FF6,0x90D6,0x90E0,0x90D9,0x90DA,0x90E3,0x90DF,/* 0xF0-0xF7 */ - 0x90E5,0x90D8,0x90DB,0x90D7,0x90DC,0x90E4,0x9150,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x914E,0x914F,0x91D5,0x91E2,0x91DA,0x965C,0x965F,0x96BC,/* 0x40-0x47 */ - 0x98E3,0x9ADF,0x9B2F,0x4E7F,0x5070,0x506A,0x5061,0x505E,/* 0x48-0x4F */ - 0x5060,0x5053,0x504B,0x505D,0x5072,0x5048,0x504D,0x5041,/* 0x50-0x57 */ - 0x505B,0x504A,0x5062,0x5015,0x5045,0x505F,0x5069,0x506B,/* 0x58-0x5F */ - 0x5063,0x5064,0x5046,0x5040,0x506E,0x5073,0x5057,0x5051,/* 0x60-0x67 */ - 0x51D0,0x526B,0x526D,0x526C,0x526E,0x52D6,0x52D3,0x532D,/* 0x68-0x6F */ - 0x539C,0x5575,0x5576,0x553C,0x554D,0x5550,0x5534,0x552A,/* 0x70-0x77 */ - 0x5551,0x5562,0x5536,0x5535,0x5530,0x5552,0x5545,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x550C,0x5532,0x5565,0x554E,0x5539,0x5548,0x552D,/* 0xA0-0xA7 */ - 0x553B,0x5540,0x554B,0x570A,0x5707,0x57FB,0x5814,0x57E2,/* 0xA8-0xAF */ - 0x57F6,0x57DC,0x57F4,0x5800,0x57ED,0x57FD,0x5808,0x57F8,/* 0xB0-0xB7 */ - 0x580B,0x57F3,0x57CF,0x5807,0x57EE,0x57E3,0x57F2,0x57E5,/* 0xB8-0xBF */ - 0x57EC,0x57E1,0x580E,0x57FC,0x5810,0x57E7,0x5801,0x580C,/* 0xC0-0xC7 */ - 0x57F1,0x57E9,0x57F0,0x580D,0x5804,0x595C,0x5A60,0x5A58,/* 0xC8-0xCF */ - 0x5A55,0x5A67,0x5A5E,0x5A38,0x5A35,0x5A6D,0x5A50,0x5A5F,/* 0xD0-0xD7 */ - 0x5A65,0x5A6C,0x5A53,0x5A64,0x5A57,0x5A43,0x5A5D,0x5A52,/* 0xD8-0xDF */ - 0x5A44,0x5A5B,0x5A48,0x5A8E,0x5A3E,0x5A4D,0x5A39,0x5A4C,/* 0xE0-0xE7 */ - 0x5A70,0x5A69,0x5A47,0x5A51,0x5A56,0x5A42,0x5A5C,0x5B72,/* 0xE8-0xEF */ - 0x5B6E,0x5BC1,0x5BC0,0x5C59,0x5D1E,0x5D0B,0x5D1D,0x5D1A,/* 0xF0-0xF7 */ - 0x5D20,0x5D0C,0x5D28,0x5D0D,0x5D26,0x5D25,0x5D0F,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5D30,0x5D12,0x5D23,0x5D1F,0x5D2E,0x5E3E,0x5E34,0x5EB1,/* 0x40-0x47 */ - 0x5EB4,0x5EB9,0x5EB2,0x5EB3,0x5F36,0x5F38,0x5F9B,0x5F96,/* 0x48-0x4F */ - 0x5F9F,0x608A,0x6090,0x6086,0x60BE,0x60B0,0x60BA,0x60D3,/* 0x50-0x57 */ - 0x60D4,0x60CF,0x60E4,0x60D9,0x60DD,0x60C8,0x60B1,0x60DB,/* 0x58-0x5F */ - 0x60B7,0x60CA,0x60BF,0x60C3,0x60CD,0x60C0,0x6332,0x6365,/* 0x60-0x67 */ - 0x638A,0x6382,0x637D,0x63BD,0x639E,0x63AD,0x639D,0x6397,/* 0x68-0x6F */ - 0x63AB,0x638E,0x636F,0x6387,0x6390,0x636E,0x63AF,0x6375,/* 0x70-0x77 */ - 0x639C,0x636D,0x63AE,0x637C,0x63A4,0x633B,0x639F,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x6378,0x6385,0x6381,0x6391,0x638D,0x6370,0x6553,/* 0xA0-0xA7 */ - 0x65CD,0x6665,0x6661,0x665B,0x6659,0x665C,0x6662,0x6718,/* 0xA8-0xAF */ - 0x6879,0x6887,0x6890,0x689C,0x686D,0x686E,0x68AE,0x68AB,/* 0xB0-0xB7 */ - 0x6956,0x686F,0x68A3,0x68AC,0x68A9,0x6875,0x6874,0x68B2,/* 0xB8-0xBF */ - 0x688F,0x6877,0x6892,0x687C,0x686B,0x6872,0x68AA,0x6880,/* 0xC0-0xC7 */ - 0x6871,0x687E,0x689B,0x6896,0x688B,0x68A0,0x6889,0x68A4,/* 0xC8-0xCF */ - 0x6878,0x687B,0x6891,0x688C,0x688A,0x687D,0x6B36,0x6B33,/* 0xD0-0xD7 */ - 0x6B37,0x6B38,0x6B91,0x6B8F,0x6B8D,0x6B8E,0x6B8C,0x6C2A,/* 0xD8-0xDF */ - 0x6DC0,0x6DAB,0x6DB4,0x6DB3,0x6E74,0x6DAC,0x6DE9,0x6DE2,/* 0xE0-0xE7 */ - 0x6DB7,0x6DF6,0x6DD4,0x6E00,0x6DC8,0x6DE0,0x6DDF,0x6DD6,/* 0xE8-0xEF */ - 0x6DBE,0x6DE5,0x6DDC,0x6DDD,0x6DDB,0x6DF4,0x6DCA,0x6DBD,/* 0xF0-0xF7 */ - 0x6DED,0x6DF0,0x6DBA,0x6DD5,0x6DC2,0x6DCF,0x6DC9,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6DD0,0x6DF2,0x6DD3,0x6DFD,0x6DD7,0x6DCD,0x6DE3,0x6DBB,/* 0x40-0x47 */ - 0x70FA,0x710D,0x70F7,0x7117,0x70F4,0x710C,0x70F0,0x7104,/* 0x48-0x4F */ - 0x70F3,0x7110,0x70FC,0x70FF,0x7106,0x7113,0x7100,0x70F8,/* 0x50-0x57 */ - 0x70F6,0x710B,0x7102,0x710E,0x727E,0x727B,0x727C,0x727F,/* 0x58-0x5F */ - 0x731D,0x7317,0x7307,0x7311,0x7318,0x730A,0x7308,0x72FF,/* 0x60-0x67 */ - 0x730F,0x731E,0x7388,0x73F6,0x73F8,0x73F5,0x7404,0x7401,/* 0x68-0x6F */ - 0x73FD,0x7407,0x7400,0x73FA,0x73FC,0x73FF,0x740C,0x740B,/* 0x70-0x77 */ - 0x73F4,0x7408,0x7564,0x7563,0x75CE,0x75D2,0x75CF,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x75CB,0x75CC,0x75D1,0x75D0,0x768F,0x7689,0x76D3,/* 0xA0-0xA7 */ - 0x7739,0x772F,0x772D,0x7731,0x7732,0x7734,0x7733,0x773D,/* 0xA8-0xAF */ - 0x7725,0x773B,0x7735,0x7848,0x7852,0x7849,0x784D,0x784A,/* 0xB0-0xB7 */ - 0x784C,0x7826,0x7845,0x7850,0x7964,0x7967,0x7969,0x796A,/* 0xB8-0xBF */ - 0x7963,0x796B,0x7961,0x79BB,0x79FA,0x79F8,0x79F6,0x79F7,/* 0xC0-0xC7 */ - 0x7A8F,0x7A94,0x7A90,0x7B35,0x7B47,0x7B34,0x7B25,0x7B30,/* 0xC8-0xCF */ - 0x7B22,0x7B24,0x7B33,0x7B18,0x7B2A,0x7B1D,0x7B31,0x7B2B,/* 0xD0-0xD7 */ - 0x7B2D,0x7B2F,0x7B32,0x7B38,0x7B1A,0x7B23,0x7C94,0x7C98,/* 0xD8-0xDF */ - 0x7C96,0x7CA3,0x7D35,0x7D3D,0x7D38,0x7D36,0x7D3A,0x7D45,/* 0xE0-0xE7 */ - 0x7D2C,0x7D29,0x7D41,0x7D47,0x7D3E,0x7D3F,0x7D4A,0x7D3B,/* 0xE8-0xEF */ - 0x7D28,0x7F63,0x7F95,0x7F9C,0x7F9D,0x7F9B,0x7FCA,0x7FCB,/* 0xF0-0xF7 */ - 0x7FCD,0x7FD0,0x7FD1,0x7FC7,0x7FCF,0x7FC9,0x801F,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D7[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x801E,0x801B,0x8047,0x8043,0x8048,0x8118,0x8125,0x8119,/* 0x40-0x47 */ - 0x811B,0x812D,0x811F,0x812C,0x811E,0x8121,0x8115,0x8127,/* 0x48-0x4F */ - 0x811D,0x8122,0x8211,0x8238,0x8233,0x823A,0x8234,0x8232,/* 0x50-0x57 */ - 0x8274,0x8390,0x83A3,0x83A8,0x838D,0x837A,0x8373,0x83A4,/* 0x58-0x5F */ - 0x8374,0x838F,0x8381,0x8395,0x8399,0x8375,0x8394,0x83A9,/* 0x60-0x67 */ - 0x837D,0x8383,0x838C,0x839D,0x839B,0x83AA,0x838B,0x837E,/* 0x68-0x6F */ - 0x83A5,0x83AF,0x8388,0x8397,0x83B0,0x837F,0x83A6,0x8387,/* 0x70-0x77 */ - 0x83AE,0x8376,0x839A,0x8659,0x8656,0x86BF,0x86B7,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x86C2,0x86C1,0x86C5,0x86BA,0x86B0,0x86C8,0x86B9,/* 0xA0-0xA7 */ - 0x86B3,0x86B8,0x86CC,0x86B4,0x86BB,0x86BC,0x86C3,0x86BD,/* 0xA8-0xAF */ - 0x86BE,0x8852,0x8889,0x8895,0x88A8,0x88A2,0x88AA,0x889A,/* 0xB0-0xB7 */ - 0x8891,0x88A1,0x889F,0x8898,0x88A7,0x8899,0x889B,0x8897,/* 0xB8-0xBF */ - 0x88A4,0x88AC,0x888C,0x8893,0x888E,0x8982,0x89D6,0x89D9,/* 0xC0-0xC7 */ - 0x89D5,0x8A30,0x8A27,0x8A2C,0x8A1E,0x8C39,0x8C3B,0x8C5C,/* 0xC8-0xCF */ - 0x8C5D,0x8C7D,0x8CA5,0x8D7D,0x8D7B,0x8D79,0x8DBC,0x8DC2,/* 0xD0-0xD7 */ - 0x8DB9,0x8DBF,0x8DC1,0x8ED8,0x8EDE,0x8EDD,0x8EDC,0x8ED7,/* 0xD8-0xDF */ - 0x8EE0,0x8EE1,0x9024,0x900B,0x9011,0x901C,0x900C,0x9021,/* 0xE0-0xE7 */ - 0x90EF,0x90EA,0x90F0,0x90F4,0x90F2,0x90F3,0x90D4,0x90EB,/* 0xE8-0xEF */ - 0x90EC,0x90E9,0x9156,0x9158,0x915A,0x9153,0x9155,0x91EC,/* 0xF0-0xF7 */ - 0x91F4,0x91F1,0x91F3,0x91F8,0x91E4,0x91F9,0x91EA,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D8[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x91EB,0x91F7,0x91E8,0x91EE,0x957A,0x9586,0x9588,0x967C,/* 0x40-0x47 */ - 0x966D,0x966B,0x9671,0x966F,0x96BF,0x976A,0x9804,0x98E5,/* 0x48-0x4F */ - 0x9997,0x509B,0x5095,0x5094,0x509E,0x508B,0x50A3,0x5083,/* 0x50-0x57 */ - 0x508C,0x508E,0x509D,0x5068,0x509C,0x5092,0x5082,0x5087,/* 0x58-0x5F */ - 0x515F,0x51D4,0x5312,0x5311,0x53A4,0x53A7,0x5591,0x55A8,/* 0x60-0x67 */ - 0x55A5,0x55AD,0x5577,0x5645,0x55A2,0x5593,0x5588,0x558F,/* 0x68-0x6F */ - 0x55B5,0x5581,0x55A3,0x5592,0x55A4,0x557D,0x558C,0x55A6,/* 0x70-0x77 */ - 0x557F,0x5595,0x55A1,0x558E,0x570C,0x5829,0x5837,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x5819,0x581E,0x5827,0x5823,0x5828,0x57F5,0x5848,/* 0xA0-0xA7 */ - 0x5825,0x581C,0x581B,0x5833,0x583F,0x5836,0x582E,0x5839,/* 0xA8-0xAF */ - 0x5838,0x582D,0x582C,0x583B,0x5961,0x5AAF,0x5A94,0x5A9F,/* 0xB0-0xB7 */ - 0x5A7A,0x5AA2,0x5A9E,0x5A78,0x5AA6,0x5A7C,0x5AA5,0x5AAC,/* 0xB8-0xBF */ - 0x5A95,0x5AAE,0x5A37,0x5A84,0x5A8A,0x5A97,0x5A83,0x5A8B,/* 0xC0-0xC7 */ - 0x5AA9,0x5A7B,0x5A7D,0x5A8C,0x5A9C,0x5A8F,0x5A93,0x5A9D,/* 0xC8-0xCF */ - 0x5BEA,0x5BCD,0x5BCB,0x5BD4,0x5BD1,0x5BCA,0x5BCE,0x5C0C,/* 0xD0-0xD7 */ - 0x5C30,0x5D37,0x5D43,0x5D6B,0x5D41,0x5D4B,0x5D3F,0x5D35,/* 0xD8-0xDF */ - 0x5D51,0x5D4E,0x5D55,0x5D33,0x5D3A,0x5D52,0x5D3D,0x5D31,/* 0xE0-0xE7 */ - 0x5D59,0x5D42,0x5D39,0x5D49,0x5D38,0x5D3C,0x5D32,0x5D36,/* 0xE8-0xEF */ - 0x5D40,0x5D45,0x5E44,0x5E41,0x5F58,0x5FA6,0x5FA5,0x5FAB,/* 0xF0-0xF7 */ - 0x60C9,0x60B9,0x60CC,0x60E2,0x60CE,0x60C4,0x6114,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_D9[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x60F2,0x610A,0x6116,0x6105,0x60F5,0x6113,0x60F8,0x60FC,/* 0x40-0x47 */ - 0x60FE,0x60C1,0x6103,0x6118,0x611D,0x6110,0x60FF,0x6104,/* 0x48-0x4F */ - 0x610B,0x624A,0x6394,0x63B1,0x63B0,0x63CE,0x63E5,0x63E8,/* 0x50-0x57 */ - 0x63EF,0x63C3,0x649D,0x63F3,0x63CA,0x63E0,0x63F6,0x63D5,/* 0x58-0x5F */ - 0x63F2,0x63F5,0x6461,0x63DF,0x63BE,0x63DD,0x63DC,0x63C4,/* 0x60-0x67 */ - 0x63D8,0x63D3,0x63C2,0x63C7,0x63CC,0x63CB,0x63C8,0x63F0,/* 0x68-0x6F */ - 0x63D7,0x63D9,0x6532,0x6567,0x656A,0x6564,0x655C,0x6568,/* 0x70-0x77 */ - 0x6565,0x658C,0x659D,0x659E,0x65AE,0x65D0,0x65D2,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x667C,0x666C,0x667B,0x6680,0x6671,0x6679,0x666A,/* 0xA0-0xA7 */ - 0x6672,0x6701,0x690C,0x68D3,0x6904,0x68DC,0x692A,0x68EC,/* 0xA8-0xAF */ - 0x68EA,0x68F1,0x690F,0x68D6,0x68F7,0x68EB,0x68E4,0x68F6,/* 0xB0-0xB7 */ - 0x6913,0x6910,0x68F3,0x68E1,0x6907,0x68CC,0x6908,0x6970,/* 0xB8-0xBF */ - 0x68B4,0x6911,0x68EF,0x68C6,0x6914,0x68F8,0x68D0,0x68FD,/* 0xC0-0xC7 */ - 0x68FC,0x68E8,0x690B,0x690A,0x6917,0x68CE,0x68C8,0x68DD,/* 0xC8-0xCF */ - 0x68DE,0x68E6,0x68F4,0x68D1,0x6906,0x68D4,0x68E9,0x6915,/* 0xD0-0xD7 */ - 0x6925,0x68C7,0x6B39,0x6B3B,0x6B3F,0x6B3C,0x6B94,0x6B97,/* 0xD8-0xDF */ - 0x6B99,0x6B95,0x6BBD,0x6BF0,0x6BF2,0x6BF3,0x6C30,0x6DFC,/* 0xE0-0xE7 */ - 0x6E46,0x6E47,0x6E1F,0x6E49,0x6E88,0x6E3C,0x6E3D,0x6E45,/* 0xE8-0xEF */ - 0x6E62,0x6E2B,0x6E3F,0x6E41,0x6E5D,0x6E73,0x6E1C,0x6E33,/* 0xF0-0xF7 */ - 0x6E4B,0x6E40,0x6E51,0x6E3B,0x6E03,0x6E2E,0x6E5E,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_DA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6E68,0x6E5C,0x6E61,0x6E31,0x6E28,0x6E60,0x6E71,0x6E6B,/* 0x40-0x47 */ - 0x6E39,0x6E22,0x6E30,0x6E53,0x6E65,0x6E27,0x6E78,0x6E64,/* 0x48-0x4F */ - 0x6E77,0x6E55,0x6E79,0x6E52,0x6E66,0x6E35,0x6E36,0x6E5A,/* 0x50-0x57 */ - 0x7120,0x711E,0x712F,0x70FB,0x712E,0x7131,0x7123,0x7125,/* 0x58-0x5F */ - 0x7122,0x7132,0x711F,0x7128,0x713A,0x711B,0x724B,0x725A,/* 0x60-0x67 */ - 0x7288,0x7289,0x7286,0x7285,0x728B,0x7312,0x730B,0x7330,/* 0x68-0x6F */ - 0x7322,0x7331,0x7333,0x7327,0x7332,0x732D,0x7326,0x7323,/* 0x70-0x77 */ - 0x7335,0x730C,0x742E,0x742C,0x7430,0x742B,0x7416,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x741A,0x7421,0x742D,0x7431,0x7424,0x7423,0x741D,/* 0xA0-0xA7 */ - 0x7429,0x7420,0x7432,0x74FB,0x752F,0x756F,0x756C,0x75E7,/* 0xA8-0xAF */ - 0x75DA,0x75E1,0x75E6,0x75DD,0x75DF,0x75E4,0x75D7,0x7695,/* 0xB0-0xB7 */ - 0x7692,0x76DA,0x7746,0x7747,0x7744,0x774D,0x7745,0x774A,/* 0xB8-0xBF */ - 0x774E,0x774B,0x774C,0x77DE,0x77EC,0x7860,0x7864,0x7865,/* 0xC0-0xC7 */ - 0x785C,0x786D,0x7871,0x786A,0x786E,0x7870,0x7869,0x7868,/* 0xC8-0xCF */ - 0x785E,0x7862,0x7974,0x7973,0x7972,0x7970,0x7A02,0x7A0A,/* 0xD0-0xD7 */ - 0x7A03,0x7A0C,0x7A04,0x7A99,0x7AE6,0x7AE4,0x7B4A,0x7B3B,/* 0xD8-0xDF */ - 0x7B44,0x7B48,0x7B4C,0x7B4E,0x7B40,0x7B58,0x7B45,0x7CA2,/* 0xE0-0xE7 */ - 0x7C9E,0x7CA8,0x7CA1,0x7D58,0x7D6F,0x7D63,0x7D53,0x7D56,/* 0xE8-0xEF */ - 0x7D67,0x7D6A,0x7D4F,0x7D6D,0x7D5C,0x7D6B,0x7D52,0x7D54,/* 0xF0-0xF7 */ - 0x7D69,0x7D51,0x7D5F,0x7D4E,0x7F3E,0x7F3F,0x7F65,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_DB[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7F66,0x7FA2,0x7FA0,0x7FA1,0x7FD7,0x8051,0x804F,0x8050,/* 0x40-0x47 */ - 0x80FE,0x80D4,0x8143,0x814A,0x8152,0x814F,0x8147,0x813D,/* 0x48-0x4F */ - 0x814D,0x813A,0x81E6,0x81EE,0x81F7,0x81F8,0x81F9,0x8204,/* 0x50-0x57 */ - 0x823C,0x823D,0x823F,0x8275,0x833B,0x83CF,0x83F9,0x8423,/* 0x58-0x5F */ - 0x83C0,0x83E8,0x8412,0x83E7,0x83E4,0x83FC,0x83F6,0x8410,/* 0x60-0x67 */ - 0x83C6,0x83C8,0x83EB,0x83E3,0x83BF,0x8401,0x83DD,0x83E5,/* 0x68-0x6F */ - 0x83D8,0x83FF,0x83E1,0x83CB,0x83CE,0x83D6,0x83F5,0x83C9,/* 0x70-0x77 */ - 0x8409,0x840F,0x83DE,0x8411,0x8406,0x83C2,0x83F3,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x83D5,0x83FA,0x83C7,0x83D1,0x83EA,0x8413,0x83C3,/* 0xA0-0xA7 */ - 0x83EC,0x83EE,0x83C4,0x83FB,0x83D7,0x83E2,0x841B,0x83DB,/* 0xA8-0xAF */ - 0x83FE,0x86D8,0x86E2,0x86E6,0x86D3,0x86E3,0x86DA,0x86EA,/* 0xB0-0xB7 */ - 0x86DD,0x86EB,0x86DC,0x86EC,0x86E9,0x86D7,0x86E8,0x86D1,/* 0xB8-0xBF */ - 0x8848,0x8856,0x8855,0x88BA,0x88D7,0x88B9,0x88B8,0x88C0,/* 0xC0-0xC7 */ - 0x88BE,0x88B6,0x88BC,0x88B7,0x88BD,0x88B2,0x8901,0x88C9,/* 0xC8-0xCF */ - 0x8995,0x8998,0x8997,0x89DD,0x89DA,0x89DB,0x8A4E,0x8A4D,/* 0xD0-0xD7 */ - 0x8A39,0x8A59,0x8A40,0x8A57,0x8A58,0x8A44,0x8A45,0x8A52,/* 0xD8-0xDF */ - 0x8A48,0x8A51,0x8A4A,0x8A4C,0x8A4F,0x8C5F,0x8C81,0x8C80,/* 0xE0-0xE7 */ - 0x8CBA,0x8CBE,0x8CB0,0x8CB9,0x8CB5,0x8D84,0x8D80,0x8D89,/* 0xE8-0xEF */ - 0x8DD8,0x8DD3,0x8DCD,0x8DC7,0x8DD6,0x8DDC,0x8DCF,0x8DD5,/* 0xF0-0xF7 */ - 0x8DD9,0x8DC8,0x8DD7,0x8DC5,0x8EEF,0x8EF7,0x8EFA,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_DC[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8EF9,0x8EE6,0x8EEE,0x8EE5,0x8EF5,0x8EE7,0x8EE8,0x8EF6,/* 0x40-0x47 */ - 0x8EEB,0x8EF1,0x8EEC,0x8EF4,0x8EE9,0x902D,0x9034,0x902F,/* 0x48-0x4F */ - 0x9106,0x912C,0x9104,0x90FF,0x90FC,0x9108,0x90F9,0x90FB,/* 0x50-0x57 */ - 0x9101,0x9100,0x9107,0x9105,0x9103,0x9161,0x9164,0x915F,/* 0x58-0x5F */ - 0x9162,0x9160,0x9201,0x920A,0x9225,0x9203,0x921A,0x9226,/* 0x60-0x67 */ - 0x920F,0x920C,0x9200,0x9212,0x91FF,0x91FD,0x9206,0x9204,/* 0x68-0x6F */ - 0x9227,0x9202,0x921C,0x9224,0x9219,0x9217,0x9205,0x9216,/* 0x70-0x77 */ - 0x957B,0x958D,0x958C,0x9590,0x9687,0x967E,0x9688,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x9689,0x9683,0x9680,0x96C2,0x96C8,0x96C3,0x96F1,/* 0xA0-0xA7 */ - 0x96F0,0x976C,0x9770,0x976E,0x9807,0x98A9,0x98EB,0x9CE6,/* 0xA8-0xAF */ - 0x9EF9,0x4E83,0x4E84,0x4EB6,0x50BD,0x50BF,0x50C6,0x50AE,/* 0xB0-0xB7 */ - 0x50C4,0x50CA,0x50B4,0x50C8,0x50C2,0x50B0,0x50C1,0x50BA,/* 0xB8-0xBF */ - 0x50B1,0x50CB,0x50C9,0x50B6,0x50B8,0x51D7,0x527A,0x5278,/* 0xC0-0xC7 */ - 0x527B,0x527C,0x55C3,0x55DB,0x55CC,0x55D0,0x55CB,0x55CA,/* 0xC8-0xCF */ - 0x55DD,0x55C0,0x55D4,0x55C4,0x55E9,0x55BF,0x55D2,0x558D,/* 0xD0-0xD7 */ - 0x55CF,0x55D5,0x55E2,0x55D6,0x55C8,0x55F2,0x55CD,0x55D9,/* 0xD8-0xDF */ - 0x55C2,0x5714,0x5853,0x5868,0x5864,0x584F,0x584D,0x5849,/* 0xE0-0xE7 */ - 0x586F,0x5855,0x584E,0x585D,0x5859,0x5865,0x585B,0x583D,/* 0xE8-0xEF */ - 0x5863,0x5871,0x58FC,0x5AC7,0x5AC4,0x5ACB,0x5ABA,0x5AB8,/* 0xF0-0xF7 */ - 0x5AB1,0x5AB5,0x5AB0,0x5ABF,0x5AC8,0x5ABB,0x5AC6,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_DD[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5AB7,0x5AC0,0x5ACA,0x5AB4,0x5AB6,0x5ACD,0x5AB9,0x5A90,/* 0x40-0x47 */ - 0x5BD6,0x5BD8,0x5BD9,0x5C1F,0x5C33,0x5D71,0x5D63,0x5D4A,/* 0x48-0x4F */ - 0x5D65,0x5D72,0x5D6C,0x5D5E,0x5D68,0x5D67,0x5D62,0x5DF0,/* 0x50-0x57 */ - 0x5E4F,0x5E4E,0x5E4A,0x5E4D,0x5E4B,0x5EC5,0x5ECC,0x5EC6,/* 0x58-0x5F */ - 0x5ECB,0x5EC7,0x5F40,0x5FAF,0x5FAD,0x60F7,0x6149,0x614A,/* 0x60-0x67 */ - 0x612B,0x6145,0x6136,0x6132,0x612E,0x6146,0x612F,0x614F,/* 0x68-0x6F */ - 0x6129,0x6140,0x6220,0x9168,0x6223,0x6225,0x6224,0x63C5,/* 0x70-0x77 */ - 0x63F1,0x63EB,0x6410,0x6412,0x6409,0x6420,0x6424,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x6433,0x6443,0x641F,0x6415,0x6418,0x6439,0x6437,/* 0xA0-0xA7 */ - 0x6422,0x6423,0x640C,0x6426,0x6430,0x6428,0x6441,0x6435,/* 0xA8-0xAF */ - 0x642F,0x640A,0x641A,0x6440,0x6425,0x6427,0x640B,0x63E7,/* 0xB0-0xB7 */ - 0x641B,0x642E,0x6421,0x640E,0x656F,0x6592,0x65D3,0x6686,/* 0xB8-0xBF */ - 0x668C,0x6695,0x6690,0x668B,0x668A,0x6699,0x6694,0x6678,/* 0xC0-0xC7 */ - 0x6720,0x6966,0x695F,0x6938,0x694E,0x6962,0x6971,0x693F,/* 0xC8-0xCF */ - 0x6945,0x696A,0x6939,0x6942,0x6957,0x6959,0x697A,0x6948,/* 0xD0-0xD7 */ - 0x6949,0x6935,0x696C,0x6933,0x693D,0x6965,0x68F0,0x6978,/* 0xD8-0xDF */ - 0x6934,0x6969,0x6940,0x696F,0x6944,0x6976,0x6958,0x6941,/* 0xE0-0xE7 */ - 0x6974,0x694C,0x693B,0x694B,0x6937,0x695C,0x694F,0x6951,/* 0xE8-0xEF */ - 0x6932,0x6952,0x692F,0x697B,0x693C,0x6B46,0x6B45,0x6B43,/* 0xF0-0xF7 */ - 0x6B42,0x6B48,0x6B41,0x6B9B,0xFA0D,0x6BFB,0x6BFC,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_DE[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6BF9,0x6BF7,0x6BF8,0x6E9B,0x6ED6,0x6EC8,0x6E8F,0x6EC0,/* 0x40-0x47 */ - 0x6E9F,0x6E93,0x6E94,0x6EA0,0x6EB1,0x6EB9,0x6EC6,0x6ED2,/* 0x48-0x4F */ - 0x6EBD,0x6EC1,0x6E9E,0x6EC9,0x6EB7,0x6EB0,0x6ECD,0x6EA6,/* 0x50-0x57 */ - 0x6ECF,0x6EB2,0x6EBE,0x6EC3,0x6EDC,0x6ED8,0x6E99,0x6E92,/* 0x58-0x5F */ - 0x6E8E,0x6E8D,0x6EA4,0x6EA1,0x6EBF,0x6EB3,0x6ED0,0x6ECA,/* 0x60-0x67 */ - 0x6E97,0x6EAE,0x6EA3,0x7147,0x7154,0x7152,0x7163,0x7160,/* 0x68-0x6F */ - 0x7141,0x715D,0x7162,0x7172,0x7178,0x716A,0x7161,0x7142,/* 0x70-0x77 */ - 0x7158,0x7143,0x714B,0x7170,0x715F,0x7150,0x7153,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x7144,0x714D,0x715A,0x724F,0x728D,0x728C,0x7291,/* 0xA0-0xA7 */ - 0x7290,0x728E,0x733C,0x7342,0x733B,0x733A,0x7340,0x734A,/* 0xA8-0xAF */ - 0x7349,0x7444,0x744A,0x744B,0x7452,0x7451,0x7457,0x7440,/* 0xB0-0xB7 */ - 0x744F,0x7450,0x744E,0x7442,0x7446,0x744D,0x7454,0x74E1,/* 0xB8-0xBF */ - 0x74FF,0x74FE,0x74FD,0x751D,0x7579,0x7577,0x6983,0x75EF,/* 0xC0-0xC7 */ - 0x760F,0x7603,0x75F7,0x75FE,0x75FC,0x75F9,0x75F8,0x7610,/* 0xC8-0xCF */ - 0x75FB,0x75F6,0x75ED,0x75F5,0x75FD,0x7699,0x76B5,0x76DD,/* 0xD0-0xD7 */ - 0x7755,0x775F,0x7760,0x7752,0x7756,0x775A,0x7769,0x7767,/* 0xD8-0xDF */ - 0x7754,0x7759,0x776D,0x77E0,0x7887,0x789A,0x7894,0x788F,/* 0xE0-0xE7 */ - 0x7884,0x7895,0x7885,0x7886,0x78A1,0x7883,0x7879,0x7899,/* 0xE8-0xEF */ - 0x7880,0x7896,0x787B,0x797C,0x7982,0x797D,0x7979,0x7A11,/* 0xF0-0xF7 */ - 0x7A18,0x7A19,0x7A12,0x7A17,0x7A15,0x7A22,0x7A13,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_DF[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7A1B,0x7A10,0x7AA3,0x7AA2,0x7A9E,0x7AEB,0x7B66,0x7B64,/* 0x40-0x47 */ - 0x7B6D,0x7B74,0x7B69,0x7B72,0x7B65,0x7B73,0x7B71,0x7B70,/* 0x48-0x4F */ - 0x7B61,0x7B78,0x7B76,0x7B63,0x7CB2,0x7CB4,0x7CAF,0x7D88,/* 0x50-0x57 */ - 0x7D86,0x7D80,0x7D8D,0x7D7F,0x7D85,0x7D7A,0x7D8E,0x7D7B,/* 0x58-0x5F */ - 0x7D83,0x7D7C,0x7D8C,0x7D94,0x7D84,0x7D7D,0x7D92,0x7F6D,/* 0x60-0x67 */ - 0x7F6B,0x7F67,0x7F68,0x7F6C,0x7FA6,0x7FA5,0x7FA7,0x7FDB,/* 0x68-0x6F */ - 0x7FDC,0x8021,0x8164,0x8160,0x8177,0x815C,0x8169,0x815B,/* 0x70-0x77 */ - 0x8162,0x8172,0x6721,0x815E,0x8176,0x8167,0x816F,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x8144,0x8161,0x821D,0x8249,0x8244,0x8240,0x8242,/* 0xA0-0xA7 */ - 0x8245,0x84F1,0x843F,0x8456,0x8476,0x8479,0x848F,0x848D,/* 0xA8-0xAF */ - 0x8465,0x8451,0x8440,0x8486,0x8467,0x8430,0x844D,0x847D,/* 0xB0-0xB7 */ - 0x845A,0x8459,0x8474,0x8473,0x845D,0x8507,0x845E,0x8437,/* 0xB8-0xBF */ - 0x843A,0x8434,0x847A,0x8443,0x8478,0x8432,0x8445,0x8429,/* 0xC0-0xC7 */ - 0x83D9,0x844B,0x842F,0x8442,0x842D,0x845F,0x8470,0x8439,/* 0xC8-0xCF */ - 0x844E,0x844C,0x8452,0x846F,0x84C5,0x848E,0x843B,0x8447,/* 0xD0-0xD7 */ - 0x8436,0x8433,0x8468,0x847E,0x8444,0x842B,0x8460,0x8454,/* 0xD8-0xDF */ - 0x846E,0x8450,0x870B,0x8704,0x86F7,0x870C,0x86FA,0x86D6,/* 0xE0-0xE7 */ - 0x86F5,0x874D,0x86F8,0x870E,0x8709,0x8701,0x86F6,0x870D,/* 0xE8-0xEF */ - 0x8705,0x88D6,0x88CB,0x88CD,0x88CE,0x88DE,0x88DB,0x88DA,/* 0xF0-0xF7 */ - 0x88CC,0x88D0,0x8985,0x899B,0x89DF,0x89E5,0x89E4,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E0[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x89E1,0x89E0,0x89E2,0x89DC,0x89E6,0x8A76,0x8A86,0x8A7F,/* 0x40-0x47 */ - 0x8A61,0x8A3F,0x8A77,0x8A82,0x8A84,0x8A75,0x8A83,0x8A81,/* 0x48-0x4F */ - 0x8A74,0x8A7A,0x8C3C,0x8C4B,0x8C4A,0x8C65,0x8C64,0x8C66,/* 0x50-0x57 */ - 0x8C86,0x8C84,0x8C85,0x8CCC,0x8D68,0x8D69,0x8D91,0x8D8C,/* 0x58-0x5F */ - 0x8D8E,0x8D8F,0x8D8D,0x8D93,0x8D94,0x8D90,0x8D92,0x8DF0,/* 0x60-0x67 */ - 0x8DE0,0x8DEC,0x8DF1,0x8DEE,0x8DD0,0x8DE9,0x8DE3,0x8DE2,/* 0x68-0x6F */ - 0x8DE7,0x8DF2,0x8DEB,0x8DF4,0x8F06,0x8EFF,0x8F01,0x8F00,/* 0x70-0x77 */ - 0x8F05,0x8F07,0x8F08,0x8F02,0x8F0B,0x9052,0x903F,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x9044,0x9049,0x903D,0x9110,0x910D,0x910F,0x9111,/* 0xA0-0xA7 */ - 0x9116,0x9114,0x910B,0x910E,0x916E,0x916F,0x9248,0x9252,/* 0xA8-0xAF */ - 0x9230,0x923A,0x9266,0x9233,0x9265,0x925E,0x9283,0x922E,/* 0xB0-0xB7 */ - 0x924A,0x9246,0x926D,0x926C,0x924F,0x9260,0x9267,0x926F,/* 0xB8-0xBF */ - 0x9236,0x9261,0x9270,0x9231,0x9254,0x9263,0x9250,0x9272,/* 0xC0-0xC7 */ - 0x924E,0x9253,0x924C,0x9256,0x9232,0x959F,0x959C,0x959E,/* 0xC8-0xCF */ - 0x959B,0x9692,0x9693,0x9691,0x9697,0x96CE,0x96FA,0x96FD,/* 0xD0-0xD7 */ - 0x96F8,0x96F5,0x9773,0x9777,0x9778,0x9772,0x980F,0x980D,/* 0xD8-0xDF */ - 0x980E,0x98AC,0x98F6,0x98F9,0x99AF,0x99B2,0x99B0,0x99B5,/* 0xE0-0xE7 */ - 0x9AAD,0x9AAB,0x9B5B,0x9CEA,0x9CED,0x9CE7,0x9E80,0x9EFD,/* 0xE8-0xEF */ - 0x50E6,0x50D4,0x50D7,0x50E8,0x50F3,0x50DB,0x50EA,0x50DD,/* 0xF0-0xF7 */ - 0x50E4,0x50D3,0x50EC,0x50F0,0x50EF,0x50E3,0x50E0,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x51D8,0x5280,0x5281,0x52E9,0x52EB,0x5330,0x53AC,0x5627,/* 0x40-0x47 */ - 0x5615,0x560C,0x5612,0x55FC,0x560F,0x561C,0x5601,0x5613,/* 0x48-0x4F */ - 0x5602,0x55FA,0x561D,0x5604,0x55FF,0x55F9,0x5889,0x587C,/* 0x50-0x57 */ - 0x5890,0x5898,0x5886,0x5881,0x587F,0x5874,0x588B,0x587A,/* 0x58-0x5F */ - 0x5887,0x5891,0x588E,0x5876,0x5882,0x5888,0x587B,0x5894,/* 0x60-0x67 */ - 0x588F,0x58FE,0x596B,0x5ADC,0x5AEE,0x5AE5,0x5AD5,0x5AEA,/* 0x68-0x6F */ - 0x5ADA,0x5AED,0x5AEB,0x5AF3,0x5AE2,0x5AE0,0x5ADB,0x5AEC,/* 0x70-0x77 */ - 0x5ADE,0x5ADD,0x5AD9,0x5AE8,0x5ADF,0x5B77,0x5BE0,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x5BE3,0x5C63,0x5D82,0x5D80,0x5D7D,0x5D86,0x5D7A,/* 0xA0-0xA7 */ - 0x5D81,0x5D77,0x5D8A,0x5D89,0x5D88,0x5D7E,0x5D7C,0x5D8D,/* 0xA8-0xAF */ - 0x5D79,0x5D7F,0x5E58,0x5E59,0x5E53,0x5ED8,0x5ED1,0x5ED7,/* 0xB0-0xB7 */ - 0x5ECE,0x5EDC,0x5ED5,0x5ED9,0x5ED2,0x5ED4,0x5F44,0x5F43,/* 0xB8-0xBF */ - 0x5F6F,0x5FB6,0x612C,0x6128,0x6141,0x615E,0x6171,0x6173,/* 0xC0-0xC7 */ - 0x6152,0x6153,0x6172,0x616C,0x6180,0x6174,0x6154,0x617A,/* 0xC8-0xCF */ - 0x615B,0x6165,0x613B,0x616A,0x6161,0x6156,0x6229,0x6227,/* 0xD0-0xD7 */ - 0x622B,0x642B,0x644D,0x645B,0x645D,0x6474,0x6476,0x6472,/* 0xD8-0xDF */ - 0x6473,0x647D,0x6475,0x6466,0x64A6,0x644E,0x6482,0x645E,/* 0xE0-0xE7 */ - 0x645C,0x644B,0x6453,0x6460,0x6450,0x647F,0x643F,0x646C,/* 0xE8-0xEF */ - 0x646B,0x6459,0x6465,0x6477,0x6573,0x65A0,0x66A1,0x66A0,/* 0xF0-0xF7 */ - 0x669F,0x6705,0x6704,0x6722,0x69B1,0x69B6,0x69C9,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x69A0,0x69CE,0x6996,0x69B0,0x69AC,0x69BC,0x6991,0x6999,/* 0x40-0x47 */ - 0x698E,0x69A7,0x698D,0x69A9,0x69BE,0x69AF,0x69BF,0x69C4,/* 0x48-0x4F */ - 0x69BD,0x69A4,0x69D4,0x69B9,0x69CA,0x699A,0x69CF,0x69B3,/* 0x50-0x57 */ - 0x6993,0x69AA,0x69A1,0x699E,0x69D9,0x6997,0x6990,0x69C2,/* 0x58-0x5F */ - 0x69B5,0x69A5,0x69C6,0x6B4A,0x6B4D,0x6B4B,0x6B9E,0x6B9F,/* 0x60-0x67 */ - 0x6BA0,0x6BC3,0x6BC4,0x6BFE,0x6ECE,0x6EF5,0x6EF1,0x6F03,/* 0x68-0x6F */ - 0x6F25,0x6EF8,0x6F37,0x6EFB,0x6F2E,0x6F09,0x6F4E,0x6F19,/* 0x70-0x77 */ - 0x6F1A,0x6F27,0x6F18,0x6F3B,0x6F12,0x6EED,0x6F0A,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x6F36,0x6F73,0x6EF9,0x6EEE,0x6F2D,0x6F40,0x6F30,/* 0xA0-0xA7 */ - 0x6F3C,0x6F35,0x6EEB,0x6F07,0x6F0E,0x6F43,0x6F05,0x6EFD,/* 0xA8-0xAF */ - 0x6EF6,0x6F39,0x6F1C,0x6EFC,0x6F3A,0x6F1F,0x6F0D,0x6F1E,/* 0xB0-0xB7 */ - 0x6F08,0x6F21,0x7187,0x7190,0x7189,0x7180,0x7185,0x7182,/* 0xB8-0xBF */ - 0x718F,0x717B,0x7186,0x7181,0x7197,0x7244,0x7253,0x7297,/* 0xC0-0xC7 */ - 0x7295,0x7293,0x7343,0x734D,0x7351,0x734C,0x7462,0x7473,/* 0xC8-0xCF */ - 0x7471,0x7475,0x7472,0x7467,0x746E,0x7500,0x7502,0x7503,/* 0xD0-0xD7 */ - 0x757D,0x7590,0x7616,0x7608,0x760C,0x7615,0x7611,0x760A,/* 0xD8-0xDF */ - 0x7614,0x76B8,0x7781,0x777C,0x7785,0x7782,0x776E,0x7780,/* 0xE0-0xE7 */ - 0x776F,0x777E,0x7783,0x78B2,0x78AA,0x78B4,0x78AD,0x78A8,/* 0xE8-0xEF */ - 0x787E,0x78AB,0x789E,0x78A5,0x78A0,0x78AC,0x78A2,0x78A4,/* 0xF0-0xF7 */ - 0x7998,0x798A,0x798B,0x7996,0x7995,0x7994,0x7993,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7997,0x7988,0x7992,0x7990,0x7A2B,0x7A4A,0x7A30,0x7A2F,/* 0x40-0x47 */ - 0x7A28,0x7A26,0x7AA8,0x7AAB,0x7AAC,0x7AEE,0x7B88,0x7B9C,/* 0x48-0x4F */ - 0x7B8A,0x7B91,0x7B90,0x7B96,0x7B8D,0x7B8C,0x7B9B,0x7B8E,/* 0x50-0x57 */ - 0x7B85,0x7B98,0x5284,0x7B99,0x7BA4,0x7B82,0x7CBB,0x7CBF,/* 0x58-0x5F */ - 0x7CBC,0x7CBA,0x7DA7,0x7DB7,0x7DC2,0x7DA3,0x7DAA,0x7DC1,/* 0x60-0x67 */ - 0x7DC0,0x7DC5,0x7D9D,0x7DCE,0x7DC4,0x7DC6,0x7DCB,0x7DCC,/* 0x68-0x6F */ - 0x7DAF,0x7DB9,0x7D96,0x7DBC,0x7D9F,0x7DA6,0x7DAE,0x7DA9,/* 0x70-0x77 */ - 0x7DA1,0x7DC9,0x7F73,0x7FE2,0x7FE3,0x7FE5,0x7FDE,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x8024,0x805D,0x805C,0x8189,0x8186,0x8183,0x8187,/* 0xA0-0xA7 */ - 0x818D,0x818C,0x818B,0x8215,0x8497,0x84A4,0x84A1,0x849F,/* 0xA8-0xAF */ - 0x84BA,0x84CE,0x84C2,0x84AC,0x84AE,0x84AB,0x84B9,0x84B4,/* 0xB0-0xB7 */ - 0x84C1,0x84CD,0x84AA,0x849A,0x84B1,0x84D0,0x849D,0x84A7,/* 0xB8-0xBF */ - 0x84BB,0x84A2,0x8494,0x84C7,0x84CC,0x849B,0x84A9,0x84AF,/* 0xC0-0xC7 */ - 0x84A8,0x84D6,0x8498,0x84B6,0x84CF,0x84A0,0x84D7,0x84D4,/* 0xC8-0xCF */ - 0x84D2,0x84DB,0x84B0,0x8491,0x8661,0x8733,0x8723,0x8728,/* 0xD0-0xD7 */ - 0x876B,0x8740,0x872E,0x871E,0x8721,0x8719,0x871B,0x8743,/* 0xD8-0xDF */ - 0x872C,0x8741,0x873E,0x8746,0x8720,0x8732,0x872A,0x872D,/* 0xE0-0xE7 */ - 0x873C,0x8712,0x873A,0x8731,0x8735,0x8742,0x8726,0x8727,/* 0xE8-0xEF */ - 0x8738,0x8724,0x871A,0x8730,0x8711,0x88F7,0x88E7,0x88F1,/* 0xF0-0xF7 */ - 0x88F2,0x88FA,0x88FE,0x88EE,0x88FC,0x88F6,0x88FB,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x88F0,0x88EC,0x88EB,0x899D,0x89A1,0x899F,0x899E,0x89E9,/* 0x40-0x47 */ - 0x89EB,0x89E8,0x8AAB,0x8A99,0x8A8B,0x8A92,0x8A8F,0x8A96,/* 0x48-0x4F */ - 0x8C3D,0x8C68,0x8C69,0x8CD5,0x8CCF,0x8CD7,0x8D96,0x8E09,/* 0x50-0x57 */ - 0x8E02,0x8DFF,0x8E0D,0x8DFD,0x8E0A,0x8E03,0x8E07,0x8E06,/* 0x58-0x5F */ - 0x8E05,0x8DFE,0x8E00,0x8E04,0x8F10,0x8F11,0x8F0E,0x8F0D,/* 0x60-0x67 */ - 0x9123,0x911C,0x9120,0x9122,0x911F,0x911D,0x911A,0x9124,/* 0x68-0x6F */ - 0x9121,0x911B,0x917A,0x9172,0x9179,0x9173,0x92A5,0x92A4,/* 0x70-0x77 */ - 0x9276,0x929B,0x927A,0x92A0,0x9294,0x92AA,0x928D,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x92A6,0x929A,0x92AB,0x9279,0x9297,0x927F,0x92A3,/* 0xA0-0xA7 */ - 0x92EE,0x928E,0x9282,0x9295,0x92A2,0x927D,0x9288,0x92A1,/* 0xA8-0xAF */ - 0x928A,0x9286,0x928C,0x9299,0x92A7,0x927E,0x9287,0x92A9,/* 0xB0-0xB7 */ - 0x929D,0x928B,0x922D,0x969E,0x96A1,0x96FF,0x9758,0x977D,/* 0xB8-0xBF */ - 0x977A,0x977E,0x9783,0x9780,0x9782,0x977B,0x9784,0x9781,/* 0xC0-0xC7 */ - 0x977F,0x97CE,0x97CD,0x9816,0x98AD,0x98AE,0x9902,0x9900,/* 0xC8-0xCF */ - 0x9907,0x999D,0x999C,0x99C3,0x99B9,0x99BB,0x99BA,0x99C2,/* 0xD0-0xD7 */ - 0x99BD,0x99C7,0x9AB1,0x9AE3,0x9AE7,0x9B3E,0x9B3F,0x9B60,/* 0xD8-0xDF */ - 0x9B61,0x9B5F,0x9CF1,0x9CF2,0x9CF5,0x9EA7,0x50FF,0x5103,/* 0xE0-0xE7 */ - 0x5130,0x50F8,0x5106,0x5107,0x50F6,0x50FE,0x510B,0x510C,/* 0xE8-0xEF */ - 0x50FD,0x510A,0x528B,0x528C,0x52F1,0x52EF,0x5648,0x5642,/* 0xF0-0xF7 */ - 0x564C,0x5635,0x5641,0x564A,0x5649,0x5646,0x5658,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x565A,0x5640,0x5633,0x563D,0x562C,0x563E,0x5638,0x562A,/* 0x40-0x47 */ - 0x563A,0x571A,0x58AB,0x589D,0x58B1,0x58A0,0x58A3,0x58AF,/* 0x48-0x4F */ - 0x58AC,0x58A5,0x58A1,0x58FF,0x5AFF,0x5AF4,0x5AFD,0x5AF7,/* 0x50-0x57 */ - 0x5AF6,0x5B03,0x5AF8,0x5B02,0x5AF9,0x5B01,0x5B07,0x5B05,/* 0x58-0x5F */ - 0x5B0F,0x5C67,0x5D99,0x5D97,0x5D9F,0x5D92,0x5DA2,0x5D93,/* 0x60-0x67 */ - 0x5D95,0x5DA0,0x5D9C,0x5DA1,0x5D9A,0x5D9E,0x5E69,0x5E5D,/* 0x68-0x6F */ - 0x5E60,0x5E5C,0x7DF3,0x5EDB,0x5EDE,0x5EE1,0x5F49,0x5FB2,/* 0x70-0x77 */ - 0x618B,0x6183,0x6179,0x61B1,0x61B0,0x61A2,0x6189,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x619B,0x6193,0x61AF,0x61AD,0x619F,0x6192,0x61AA,/* 0xA0-0xA7 */ - 0x61A1,0x618D,0x6166,0x61B3,0x622D,0x646E,0x6470,0x6496,/* 0xA8-0xAF */ - 0x64A0,0x6485,0x6497,0x649C,0x648F,0x648B,0x648A,0x648C,/* 0xB0-0xB7 */ - 0x64A3,0x649F,0x6468,0x64B1,0x6498,0x6576,0x657A,0x6579,/* 0xB8-0xBF */ - 0x657B,0x65B2,0x65B3,0x66B5,0x66B0,0x66A9,0x66B2,0x66B7,/* 0xC0-0xC7 */ - 0x66AA,0x66AF,0x6A00,0x6A06,0x6A17,0x69E5,0x69F8,0x6A15,/* 0xC8-0xCF */ - 0x69F1,0x69E4,0x6A20,0x69FF,0x69EC,0x69E2,0x6A1B,0x6A1D,/* 0xD0-0xD7 */ - 0x69FE,0x6A27,0x69F2,0x69EE,0x6A14,0x69F7,0x69E7,0x6A40,/* 0xD8-0xDF */ - 0x6A08,0x69E6,0x69FB,0x6A0D,0x69FC,0x69EB,0x6A09,0x6A04,/* 0xE0-0xE7 */ - 0x6A18,0x6A25,0x6A0F,0x69F6,0x6A26,0x6A07,0x69F4,0x6A16,/* 0xE8-0xEF */ - 0x6B51,0x6BA5,0x6BA3,0x6BA2,0x6BA6,0x6C01,0x6C00,0x6BFF,/* 0xF0-0xF7 */ - 0x6C02,0x6F41,0x6F26,0x6F7E,0x6F87,0x6FC6,0x6F92,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6F8D,0x6F89,0x6F8C,0x6F62,0x6F4F,0x6F85,0x6F5A,0x6F96,/* 0x40-0x47 */ - 0x6F76,0x6F6C,0x6F82,0x6F55,0x6F72,0x6F52,0x6F50,0x6F57,/* 0x48-0x4F */ - 0x6F94,0x6F93,0x6F5D,0x6F00,0x6F61,0x6F6B,0x6F7D,0x6F67,/* 0x50-0x57 */ - 0x6F90,0x6F53,0x6F8B,0x6F69,0x6F7F,0x6F95,0x6F63,0x6F77,/* 0x58-0x5F */ - 0x6F6A,0x6F7B,0x71B2,0x71AF,0x719B,0x71B0,0x71A0,0x719A,/* 0x60-0x67 */ - 0x71A9,0x71B5,0x719D,0x71A5,0x719E,0x71A4,0x71A1,0x71AA,/* 0x68-0x6F */ - 0x719C,0x71A7,0x71B3,0x7298,0x729A,0x7358,0x7352,0x735E,/* 0x70-0x77 */ - 0x735F,0x7360,0x735D,0x735B,0x7361,0x735A,0x7359,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x7362,0x7487,0x7489,0x748A,0x7486,0x7481,0x747D,/* 0xA0-0xA7 */ - 0x7485,0x7488,0x747C,0x7479,0x7508,0x7507,0x757E,0x7625,/* 0xA8-0xAF */ - 0x761E,0x7619,0x761D,0x761C,0x7623,0x761A,0x7628,0x761B,/* 0xB0-0xB7 */ - 0x769C,0x769D,0x769E,0x769B,0x778D,0x778F,0x7789,0x7788,/* 0xB8-0xBF */ - 0x78CD,0x78BB,0x78CF,0x78CC,0x78D1,0x78CE,0x78D4,0x78C8,/* 0xC0-0xC7 */ - 0x78C3,0x78C4,0x78C9,0x799A,0x79A1,0x79A0,0x799C,0x79A2,/* 0xC8-0xCF */ - 0x799B,0x6B76,0x7A39,0x7AB2,0x7AB4,0x7AB3,0x7BB7,0x7BCB,/* 0xD0-0xD7 */ - 0x7BBE,0x7BAC,0x7BCE,0x7BAF,0x7BB9,0x7BCA,0x7BB5,0x7CC5,/* 0xD8-0xDF */ - 0x7CC8,0x7CCC,0x7CCB,0x7DF7,0x7DDB,0x7DEA,0x7DE7,0x7DD7,/* 0xE0-0xE7 */ - 0x7DE1,0x7E03,0x7DFA,0x7DE6,0x7DF6,0x7DF1,0x7DF0,0x7DEE,/* 0xE8-0xEF */ - 0x7DDF,0x7F76,0x7FAC,0x7FB0,0x7FAD,0x7FED,0x7FEB,0x7FEA,/* 0xF0-0xF7 */ - 0x7FEC,0x7FE6,0x7FE8,0x8064,0x8067,0x81A3,0x819F,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E7[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x819E,0x8195,0x81A2,0x8199,0x8197,0x8216,0x824F,0x8253,/* 0x40-0x47 */ - 0x8252,0x8250,0x824E,0x8251,0x8524,0x853B,0x850F,0x8500,/* 0x48-0x4F */ - 0x8529,0x850E,0x8509,0x850D,0x851F,0x850A,0x8527,0x851C,/* 0x50-0x57 */ - 0x84FB,0x852B,0x84FA,0x8508,0x850C,0x84F4,0x852A,0x84F2,/* 0x58-0x5F */ - 0x8515,0x84F7,0x84EB,0x84F3,0x84FC,0x8512,0x84EA,0x84E9,/* 0x60-0x67 */ - 0x8516,0x84FE,0x8528,0x851D,0x852E,0x8502,0x84FD,0x851E,/* 0x68-0x6F */ - 0x84F6,0x8531,0x8526,0x84E7,0x84E8,0x84F0,0x84EF,0x84F9,/* 0x70-0x77 */ - 0x8518,0x8520,0x8530,0x850B,0x8519,0x852F,0x8662,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x8756,0x8763,0x8764,0x8777,0x87E1,0x8773,0x8758,/* 0xA0-0xA7 */ - 0x8754,0x875B,0x8752,0x8761,0x875A,0x8751,0x875E,0x876D,/* 0xA8-0xAF */ - 0x876A,0x8750,0x874E,0x875F,0x875D,0x876F,0x876C,0x877A,/* 0xB0-0xB7 */ - 0x876E,0x875C,0x8765,0x874F,0x877B,0x8775,0x8762,0x8767,/* 0xB8-0xBF */ - 0x8769,0x885A,0x8905,0x890C,0x8914,0x890B,0x8917,0x8918,/* 0xC0-0xC7 */ - 0x8919,0x8906,0x8916,0x8911,0x890E,0x8909,0x89A2,0x89A4,/* 0xC8-0xCF */ - 0x89A3,0x89ED,0x89F0,0x89EC,0x8ACF,0x8AC6,0x8AB8,0x8AD3,/* 0xD0-0xD7 */ - 0x8AD1,0x8AD4,0x8AD5,0x8ABB,0x8AD7,0x8ABE,0x8AC0,0x8AC5,/* 0xD8-0xDF */ - 0x8AD8,0x8AC3,0x8ABA,0x8ABD,0x8AD9,0x8C3E,0x8C4D,0x8C8F,/* 0xE0-0xE7 */ - 0x8CE5,0x8CDF,0x8CD9,0x8CE8,0x8CDA,0x8CDD,0x8CE7,0x8DA0,/* 0xE8-0xEF */ - 0x8D9C,0x8DA1,0x8D9B,0x8E20,0x8E23,0x8E25,0x8E24,0x8E2E,/* 0xF0-0xF7 */ - 0x8E15,0x8E1B,0x8E16,0x8E11,0x8E19,0x8E26,0x8E27,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E8[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8E14,0x8E12,0x8E18,0x8E13,0x8E1C,0x8E17,0x8E1A,0x8F2C,/* 0x40-0x47 */ - 0x8F24,0x8F18,0x8F1A,0x8F20,0x8F23,0x8F16,0x8F17,0x9073,/* 0x48-0x4F */ - 0x9070,0x906F,0x9067,0x906B,0x912F,0x912B,0x9129,0x912A,/* 0x50-0x57 */ - 0x9132,0x9126,0x912E,0x9185,0x9186,0x918A,0x9181,0x9182,/* 0x58-0x5F */ - 0x9184,0x9180,0x92D0,0x92C3,0x92C4,0x92C0,0x92D9,0x92B6,/* 0x60-0x67 */ - 0x92CF,0x92F1,0x92DF,0x92D8,0x92E9,0x92D7,0x92DD,0x92CC,/* 0x68-0x6F */ - 0x92EF,0x92C2,0x92E8,0x92CA,0x92C8,0x92CE,0x92E6,0x92CD,/* 0x70-0x77 */ - 0x92D5,0x92C9,0x92E0,0x92DE,0x92E7,0x92D1,0x92D3,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x92B5,0x92E1,0x92C6,0x92B4,0x957C,0x95AC,0x95AB,/* 0xA0-0xA7 */ - 0x95AE,0x95B0,0x96A4,0x96A2,0x96D3,0x9705,0x9708,0x9702,/* 0xA8-0xAF */ - 0x975A,0x978A,0x978E,0x9788,0x97D0,0x97CF,0x981E,0x981D,/* 0xB0-0xB7 */ - 0x9826,0x9829,0x9828,0x9820,0x981B,0x9827,0x98B2,0x9908,/* 0xB8-0xBF */ - 0x98FA,0x9911,0x9914,0x9916,0x9917,0x9915,0x99DC,0x99CD,/* 0xC0-0xC7 */ - 0x99CF,0x99D3,0x99D4,0x99CE,0x99C9,0x99D6,0x99D8,0x99CB,/* 0xC8-0xCF */ - 0x99D7,0x99CC,0x9AB3,0x9AEC,0x9AEB,0x9AF3,0x9AF2,0x9AF1,/* 0xD0-0xD7 */ - 0x9B46,0x9B43,0x9B67,0x9B74,0x9B71,0x9B66,0x9B76,0x9B75,/* 0xD8-0xDF */ - 0x9B70,0x9B68,0x9B64,0x9B6C,0x9CFC,0x9CFA,0x9CFD,0x9CFF,/* 0xE0-0xE7 */ - 0x9CF7,0x9D07,0x9D00,0x9CF9,0x9CFB,0x9D08,0x9D05,0x9D04,/* 0xE8-0xEF */ - 0x9E83,0x9ED3,0x9F0F,0x9F10,0x511C,0x5113,0x5117,0x511A,/* 0xF0-0xF7 */ - 0x5111,0x51DE,0x5334,0x53E1,0x5670,0x5660,0x566E,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_E9[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5673,0x5666,0x5663,0x566D,0x5672,0x565E,0x5677,0x571C,/* 0x40-0x47 */ - 0x571B,0x58C8,0x58BD,0x58C9,0x58BF,0x58BA,0x58C2,0x58BC,/* 0x48-0x4F */ - 0x58C6,0x5B17,0x5B19,0x5B1B,0x5B21,0x5B14,0x5B13,0x5B10,/* 0x50-0x57 */ - 0x5B16,0x5B28,0x5B1A,0x5B20,0x5B1E,0x5BEF,0x5DAC,0x5DB1,/* 0x58-0x5F */ - 0x5DA9,0x5DA7,0x5DB5,0x5DB0,0x5DAE,0x5DAA,0x5DA8,0x5DB2,/* 0x60-0x67 */ - 0x5DAD,0x5DAF,0x5DB4,0x5E67,0x5E68,0x5E66,0x5E6F,0x5EE9,/* 0x68-0x6F */ - 0x5EE7,0x5EE6,0x5EE8,0x5EE5,0x5F4B,0x5FBC,0x619D,0x61A8,/* 0x70-0x77 */ - 0x6196,0x61C5,0x61B4,0x61C6,0x61C1,0x61CC,0x61BA,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x61BF,0x61B8,0x618C,0x64D7,0x64D6,0x64D0,0x64CF,/* 0xA0-0xA7 */ - 0x64C9,0x64BD,0x6489,0x64C3,0x64DB,0x64F3,0x64D9,0x6533,/* 0xA8-0xAF */ - 0x657F,0x657C,0x65A2,0x66C8,0x66BE,0x66C0,0x66CA,0x66CB,/* 0xB0-0xB7 */ - 0x66CF,0x66BD,0x66BB,0x66BA,0x66CC,0x6723,0x6A34,0x6A66,/* 0xB8-0xBF */ - 0x6A49,0x6A67,0x6A32,0x6A68,0x6A3E,0x6A5D,0x6A6D,0x6A76,/* 0xC0-0xC7 */ - 0x6A5B,0x6A51,0x6A28,0x6A5A,0x6A3B,0x6A3F,0x6A41,0x6A6A,/* 0xC8-0xCF */ - 0x6A64,0x6A50,0x6A4F,0x6A54,0x6A6F,0x6A69,0x6A60,0x6A3C,/* 0xD0-0xD7 */ - 0x6A5E,0x6A56,0x6A55,0x6A4D,0x6A4E,0x6A46,0x6B55,0x6B54,/* 0xD8-0xDF */ - 0x6B56,0x6BA7,0x6BAA,0x6BAB,0x6BC8,0x6BC7,0x6C04,0x6C03,/* 0xE0-0xE7 */ - 0x6C06,0x6FAD,0x6FCB,0x6FA3,0x6FC7,0x6FBC,0x6FCE,0x6FC8,/* 0xE8-0xEF */ - 0x6F5E,0x6FC4,0x6FBD,0x6F9E,0x6FCA,0x6FA8,0x7004,0x6FA5,/* 0xF0-0xF7 */ - 0x6FAE,0x6FBA,0x6FAC,0x6FAA,0x6FCF,0x6FBF,0x6FB8,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_EA[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6FA2,0x6FC9,0x6FAB,0x6FCD,0x6FAF,0x6FB2,0x6FB0,0x71C5,/* 0x40-0x47 */ - 0x71C2,0x71BF,0x71B8,0x71D6,0x71C0,0x71C1,0x71CB,0x71D4,/* 0x48-0x4F */ - 0x71CA,0x71C7,0x71CF,0x71BD,0x71D8,0x71BC,0x71C6,0x71DA,/* 0x50-0x57 */ - 0x71DB,0x729D,0x729E,0x7369,0x7366,0x7367,0x736C,0x7365,/* 0x58-0x5F */ - 0x736B,0x736A,0x747F,0x749A,0x74A0,0x7494,0x7492,0x7495,/* 0x60-0x67 */ - 0x74A1,0x750B,0x7580,0x762F,0x762D,0x7631,0x763D,0x7633,/* 0x68-0x6F */ - 0x763C,0x7635,0x7632,0x7630,0x76BB,0x76E6,0x779A,0x779D,/* 0x70-0x77 */ - 0x77A1,0x779C,0x779B,0x77A2,0x77A3,0x7795,0x7799,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x7797,0x78DD,0x78E9,0x78E5,0x78EA,0x78DE,0x78E3,/* 0xA0-0xA7 */ - 0x78DB,0x78E1,0x78E2,0x78ED,0x78DF,0x78E0,0x79A4,0x7A44,/* 0xA8-0xAF */ - 0x7A48,0x7A47,0x7AB6,0x7AB8,0x7AB5,0x7AB1,0x7AB7,0x7BDE,/* 0xB0-0xB7 */ - 0x7BE3,0x7BE7,0x7BDD,0x7BD5,0x7BE5,0x7BDA,0x7BE8,0x7BF9,/* 0xB8-0xBF */ - 0x7BD4,0x7BEA,0x7BE2,0x7BDC,0x7BEB,0x7BD8,0x7BDF,0x7CD2,/* 0xC0-0xC7 */ - 0x7CD4,0x7CD7,0x7CD0,0x7CD1,0x7E12,0x7E21,0x7E17,0x7E0C,/* 0xC8-0xCF */ - 0x7E1F,0x7E20,0x7E13,0x7E0E,0x7E1C,0x7E15,0x7E1A,0x7E22,/* 0xD0-0xD7 */ - 0x7E0B,0x7E0F,0x7E16,0x7E0D,0x7E14,0x7E25,0x7E24,0x7F43,/* 0xD8-0xDF */ - 0x7F7B,0x7F7C,0x7F7A,0x7FB1,0x7FEF,0x802A,0x8029,0x806C,/* 0xE0-0xE7 */ - 0x81B1,0x81A6,0x81AE,0x81B9,0x81B5,0x81AB,0x81B0,0x81AC,/* 0xE8-0xEF */ - 0x81B4,0x81B2,0x81B7,0x81A7,0x81F2,0x8255,0x8256,0x8257,/* 0xF0-0xF7 */ - 0x8556,0x8545,0x856B,0x854D,0x8553,0x8561,0x8558,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_EB[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8540,0x8546,0x8564,0x8541,0x8562,0x8544,0x8551,0x8547,/* 0x40-0x47 */ - 0x8563,0x853E,0x855B,0x8571,0x854E,0x856E,0x8575,0x8555,/* 0x48-0x4F */ - 0x8567,0x8560,0x858C,0x8566,0x855D,0x8554,0x8565,0x856C,/* 0x50-0x57 */ - 0x8663,0x8665,0x8664,0x879B,0x878F,0x8797,0x8793,0x8792,/* 0x58-0x5F */ - 0x8788,0x8781,0x8796,0x8798,0x8779,0x8787,0x87A3,0x8785,/* 0x60-0x67 */ - 0x8790,0x8791,0x879D,0x8784,0x8794,0x879C,0x879A,0x8789,/* 0x68-0x6F */ - 0x891E,0x8926,0x8930,0x892D,0x892E,0x8927,0x8931,0x8922,/* 0x70-0x77 */ - 0x8929,0x8923,0x892F,0x892C,0x891F,0x89F1,0x8AE0,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x8AE2,0x8AF2,0x8AF4,0x8AF5,0x8ADD,0x8B14,0x8AE4,/* 0xA0-0xA7 */ - 0x8ADF,0x8AF0,0x8AC8,0x8ADE,0x8AE1,0x8AE8,0x8AFF,0x8AEF,/* 0xA8-0xAF */ - 0x8AFB,0x8C91,0x8C92,0x8C90,0x8CF5,0x8CEE,0x8CF1,0x8CF0,/* 0xB0-0xB7 */ - 0x8CF3,0x8D6C,0x8D6E,0x8DA5,0x8DA7,0x8E33,0x8E3E,0x8E38,/* 0xB8-0xBF */ - 0x8E40,0x8E45,0x8E36,0x8E3C,0x8E3D,0x8E41,0x8E30,0x8E3F,/* 0xC0-0xC7 */ - 0x8EBD,0x8F36,0x8F2E,0x8F35,0x8F32,0x8F39,0x8F37,0x8F34,/* 0xC8-0xCF */ - 0x9076,0x9079,0x907B,0x9086,0x90FA,0x9133,0x9135,0x9136,/* 0xD0-0xD7 */ - 0x9193,0x9190,0x9191,0x918D,0x918F,0x9327,0x931E,0x9308,/* 0xD8-0xDF */ - 0x931F,0x9306,0x930F,0x937A,0x9338,0x933C,0x931B,0x9323,/* 0xE0-0xE7 */ - 0x9312,0x9301,0x9346,0x932D,0x930E,0x930D,0x92CB,0x931D,/* 0xE8-0xEF */ - 0x92FA,0x9325,0x9313,0x92F9,0x92F7,0x9334,0x9302,0x9324,/* 0xF0-0xF7 */ - 0x92FF,0x9329,0x9339,0x9335,0x932A,0x9314,0x930C,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_EC[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x930B,0x92FE,0x9309,0x9300,0x92FB,0x9316,0x95BC,0x95CD,/* 0x40-0x47 */ - 0x95BE,0x95B9,0x95BA,0x95B6,0x95BF,0x95B5,0x95BD,0x96A9,/* 0x48-0x4F */ - 0x96D4,0x970B,0x9712,0x9710,0x9799,0x9797,0x9794,0x97F0,/* 0x50-0x57 */ - 0x97F8,0x9835,0x982F,0x9832,0x9924,0x991F,0x9927,0x9929,/* 0x58-0x5F */ - 0x999E,0x99EE,0x99EC,0x99E5,0x99E4,0x99F0,0x99E3,0x99EA,/* 0x60-0x67 */ - 0x99E9,0x99E7,0x9AB9,0x9ABF,0x9AB4,0x9ABB,0x9AF6,0x9AFA,/* 0x68-0x6F */ - 0x9AF9,0x9AF7,0x9B33,0x9B80,0x9B85,0x9B87,0x9B7C,0x9B7E,/* 0x70-0x77 */ - 0x9B7B,0x9B82,0x9B93,0x9B92,0x9B90,0x9B7A,0x9B95,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x9B7D,0x9B88,0x9D25,0x9D17,0x9D20,0x9D1E,0x9D14,/* 0xA0-0xA7 */ - 0x9D29,0x9D1D,0x9D18,0x9D22,0x9D10,0x9D19,0x9D1F,0x9E88,/* 0xA8-0xAF */ - 0x9E86,0x9E87,0x9EAE,0x9EAD,0x9ED5,0x9ED6,0x9EFA,0x9F12,/* 0xB0-0xB7 */ - 0x9F3D,0x5126,0x5125,0x5122,0x5124,0x5120,0x5129,0x52F4,/* 0xB8-0xBF */ - 0x5693,0x568C,0x568D,0x5686,0x5684,0x5683,0x567E,0x5682,/* 0xC0-0xC7 */ - 0x567F,0x5681,0x58D6,0x58D4,0x58CF,0x58D2,0x5B2D,0x5B25,/* 0xC8-0xCF */ - 0x5B32,0x5B23,0x5B2C,0x5B27,0x5B26,0x5B2F,0x5B2E,0x5B7B,/* 0xD0-0xD7 */ - 0x5BF1,0x5BF2,0x5DB7,0x5E6C,0x5E6A,0x5FBE,0x5FBB,0x61C3,/* 0xD8-0xDF */ - 0x61B5,0x61BC,0x61E7,0x61E0,0x61E5,0x61E4,0x61E8,0x61DE,/* 0xE0-0xE7 */ - 0x64EF,0x64E9,0x64E3,0x64EB,0x64E4,0x64E8,0x6581,0x6580,/* 0xE8-0xEF */ - 0x65B6,0x65DA,0x66D2,0x6A8D,0x6A96,0x6A81,0x6AA5,0x6A89,/* 0xF0-0xF7 */ - 0x6A9F,0x6A9B,0x6AA1,0x6A9E,0x6A87,0x6A93,0x6A8E,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_ED[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x6A95,0x6A83,0x6AA8,0x6AA4,0x6A91,0x6A7F,0x6AA6,0x6A9A,/* 0x40-0x47 */ - 0x6A85,0x6A8C,0x6A92,0x6B5B,0x6BAD,0x6C09,0x6FCC,0x6FA9,/* 0x48-0x4F */ - 0x6FF4,0x6FD4,0x6FE3,0x6FDC,0x6FED,0x6FE7,0x6FE6,0x6FDE,/* 0x50-0x57 */ - 0x6FF2,0x6FDD,0x6FE2,0x6FE8,0x71E1,0x71F1,0x71E8,0x71F2,/* 0x58-0x5F */ - 0x71E4,0x71F0,0x71E2,0x7373,0x736E,0x736F,0x7497,0x74B2,/* 0x60-0x67 */ - 0x74AB,0x7490,0x74AA,0x74AD,0x74B1,0x74A5,0x74AF,0x7510,/* 0x68-0x6F */ - 0x7511,0x7512,0x750F,0x7584,0x7643,0x7648,0x7649,0x7647,/* 0x70-0x77 */ - 0x76A4,0x76E9,0x77B5,0x77AB,0x77B2,0x77B7,0x77B6,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x77B4,0x77B1,0x77A8,0x77F0,0x78F3,0x78FD,0x7902,/* 0xA0-0xA7 */ - 0x78FB,0x78FC,0x78F2,0x7905,0x78F9,0x78FE,0x7904,0x79AB,/* 0xA8-0xAF */ - 0x79A8,0x7A5C,0x7A5B,0x7A56,0x7A58,0x7A54,0x7A5A,0x7ABE,/* 0xB0-0xB7 */ - 0x7AC0,0x7AC1,0x7C05,0x7C0F,0x7BF2,0x7C00,0x7BFF,0x7BFB,/* 0xB8-0xBF */ - 0x7C0E,0x7BF4,0x7C0B,0x7BF3,0x7C02,0x7C09,0x7C03,0x7C01,/* 0xC0-0xC7 */ - 0x7BF8,0x7BFD,0x7C06,0x7BF0,0x7BF1,0x7C10,0x7C0A,0x7CE8,/* 0xC8-0xCF */ - 0x7E2D,0x7E3C,0x7E42,0x7E33,0x9848,0x7E38,0x7E2A,0x7E49,/* 0xD0-0xD7 */ - 0x7E40,0x7E47,0x7E29,0x7E4C,0x7E30,0x7E3B,0x7E36,0x7E44,/* 0xD8-0xDF */ - 0x7E3A,0x7F45,0x7F7F,0x7F7E,0x7F7D,0x7FF4,0x7FF2,0x802C,/* 0xE0-0xE7 */ - 0x81BB,0x81C4,0x81CC,0x81CA,0x81C5,0x81C7,0x81BC,0x81E9,/* 0xE8-0xEF */ - 0x825B,0x825A,0x825C,0x8583,0x8580,0x858F,0x85A7,0x8595,/* 0xF0-0xF7 */ - 0x85A0,0x858B,0x85A3,0x857B,0x85A4,0x859A,0x859E,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_EE[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8577,0x857C,0x8589,0x85A1,0x857A,0x8578,0x8557,0x858E,/* 0x40-0x47 */ - 0x8596,0x8586,0x858D,0x8599,0x859D,0x8581,0x85A2,0x8582,/* 0x48-0x4F */ - 0x8588,0x8585,0x8579,0x8576,0x8598,0x8590,0x859F,0x8668,/* 0x50-0x57 */ - 0x87BE,0x87AA,0x87AD,0x87C5,0x87B0,0x87AC,0x87B9,0x87B5,/* 0x58-0x5F */ - 0x87BC,0x87AE,0x87C9,0x87C3,0x87C2,0x87CC,0x87B7,0x87AF,/* 0x60-0x67 */ - 0x87C4,0x87CA,0x87B4,0x87B6,0x87BF,0x87B8,0x87BD,0x87DE,/* 0x68-0x6F */ - 0x87B2,0x8935,0x8933,0x893C,0x893E,0x8941,0x8952,0x8937,/* 0x70-0x77 */ - 0x8942,0x89AD,0x89AF,0x89AE,0x89F2,0x89F3,0x8B1E,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x8B18,0x8B16,0x8B11,0x8B05,0x8B0B,0x8B22,0x8B0F,/* 0xA0-0xA7 */ - 0x8B12,0x8B15,0x8B07,0x8B0D,0x8B08,0x8B06,0x8B1C,0x8B13,/* 0xA8-0xAF */ - 0x8B1A,0x8C4F,0x8C70,0x8C72,0x8C71,0x8C6F,0x8C95,0x8C94,/* 0xB0-0xB7 */ - 0x8CF9,0x8D6F,0x8E4E,0x8E4D,0x8E53,0x8E50,0x8E4C,0x8E47,/* 0xB8-0xBF */ - 0x8F43,0x8F40,0x9085,0x907E,0x9138,0x919A,0x91A2,0x919B,/* 0xC0-0xC7 */ - 0x9199,0x919F,0x91A1,0x919D,0x91A0,0x93A1,0x9383,0x93AF,/* 0xC8-0xCF */ - 0x9364,0x9356,0x9347,0x937C,0x9358,0x935C,0x9376,0x9349,/* 0xD0-0xD7 */ - 0x9350,0x9351,0x9360,0x936D,0x938F,0x934C,0x936A,0x9379,/* 0xD8-0xDF */ - 0x9357,0x9355,0x9352,0x934F,0x9371,0x9377,0x937B,0x9361,/* 0xE0-0xE7 */ - 0x935E,0x9363,0x9367,0x9380,0x934E,0x9359,0x95C7,0x95C0,/* 0xE8-0xEF */ - 0x95C9,0x95C3,0x95C5,0x95B7,0x96AE,0x96B0,0x96AC,0x9720,/* 0xF0-0xF7 */ - 0x971F,0x9718,0x971D,0x9719,0x979A,0x97A1,0x979C,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_EF[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x979E,0x979D,0x97D5,0x97D4,0x97F1,0x9841,0x9844,0x984A,/* 0x40-0x47 */ - 0x9849,0x9845,0x9843,0x9925,0x992B,0x992C,0x992A,0x9933,/* 0x48-0x4F */ - 0x9932,0x992F,0x992D,0x9931,0x9930,0x9998,0x99A3,0x99A1,/* 0x50-0x57 */ - 0x9A02,0x99FA,0x99F4,0x99F7,0x99F9,0x99F8,0x99F6,0x99FB,/* 0x58-0x5F */ - 0x99FD,0x99FE,0x99FC,0x9A03,0x9ABE,0x9AFE,0x9AFD,0x9B01,/* 0x60-0x67 */ - 0x9AFC,0x9B48,0x9B9A,0x9BA8,0x9B9E,0x9B9B,0x9BA6,0x9BA1,/* 0x68-0x6F */ - 0x9BA5,0x9BA4,0x9B86,0x9BA2,0x9BA0,0x9BAF,0x9D33,0x9D41,/* 0x70-0x77 */ - 0x9D67,0x9D36,0x9D2E,0x9D2F,0x9D31,0x9D38,0x9D30,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x9D45,0x9D42,0x9D43,0x9D3E,0x9D37,0x9D40,0x9D3D,/* 0xA0-0xA7 */ - 0x7FF5,0x9D2D,0x9E8A,0x9E89,0x9E8D,0x9EB0,0x9EC8,0x9EDA,/* 0xA8-0xAF */ - 0x9EFB,0x9EFF,0x9F24,0x9F23,0x9F22,0x9F54,0x9FA0,0x5131,/* 0xB0-0xB7 */ - 0x512D,0x512E,0x5698,0x569C,0x5697,0x569A,0x569D,0x5699,/* 0xB8-0xBF */ - 0x5970,0x5B3C,0x5C69,0x5C6A,0x5DC0,0x5E6D,0x5E6E,0x61D8,/* 0xC0-0xC7 */ - 0x61DF,0x61ED,0x61EE,0x61F1,0x61EA,0x61F0,0x61EB,0x61D6,/* 0xC8-0xCF */ - 0x61E9,0x64FF,0x6504,0x64FD,0x64F8,0x6501,0x6503,0x64FC,/* 0xD0-0xD7 */ - 0x6594,0x65DB,0x66DA,0x66DB,0x66D8,0x6AC5,0x6AB9,0x6ABD,/* 0xD8-0xDF */ - 0x6AE1,0x6AC6,0x6ABA,0x6AB6,0x6AB7,0x6AC7,0x6AB4,0x6AAD,/* 0xE0-0xE7 */ - 0x6B5E,0x6BC9,0x6C0B,0x7007,0x700C,0x700D,0x7001,0x7005,/* 0xE8-0xEF */ - 0x7014,0x700E,0x6FFF,0x7000,0x6FFB,0x7026,0x6FFC,0x6FF7,/* 0xF0-0xF7 */ - 0x700A,0x7201,0x71FF,0x71F9,0x7203,0x71FD,0x7376,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F0[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x74B8,0x74C0,0x74B5,0x74C1,0x74BE,0x74B6,0x74BB,0x74C2,/* 0x40-0x47 */ - 0x7514,0x7513,0x765C,0x7664,0x7659,0x7650,0x7653,0x7657,/* 0x48-0x4F */ - 0x765A,0x76A6,0x76BD,0x76EC,0x77C2,0x77BA,0x78FF,0x790C,/* 0x50-0x57 */ - 0x7913,0x7914,0x7909,0x7910,0x7912,0x7911,0x79AD,0x79AC,/* 0x58-0x5F */ - 0x7A5F,0x7C1C,0x7C29,0x7C19,0x7C20,0x7C1F,0x7C2D,0x7C1D,/* 0x60-0x67 */ - 0x7C26,0x7C28,0x7C22,0x7C25,0x7C30,0x7E5C,0x7E50,0x7E56,/* 0x68-0x6F */ - 0x7E63,0x7E58,0x7E62,0x7E5F,0x7E51,0x7E60,0x7E57,0x7E53,/* 0x70-0x77 */ - 0x7FB5,0x7FB3,0x7FF7,0x7FF8,0x8075,0x81D1,0x81D2,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x81D0,0x825F,0x825E,0x85B4,0x85C6,0x85C0,0x85C3,/* 0xA0-0xA7 */ - 0x85C2,0x85B3,0x85B5,0x85BD,0x85C7,0x85C4,0x85BF,0x85CB,/* 0xA8-0xAF */ - 0x85CE,0x85C8,0x85C5,0x85B1,0x85B6,0x85D2,0x8624,0x85B8,/* 0xB0-0xB7 */ - 0x85B7,0x85BE,0x8669,0x87E7,0x87E6,0x87E2,0x87DB,0x87EB,/* 0xB8-0xBF */ - 0x87EA,0x87E5,0x87DF,0x87F3,0x87E4,0x87D4,0x87DC,0x87D3,/* 0xC0-0xC7 */ - 0x87ED,0x87D8,0x87E3,0x87A4,0x87D7,0x87D9,0x8801,0x87F4,/* 0xC8-0xCF */ - 0x87E8,0x87DD,0x8953,0x894B,0x894F,0x894C,0x8946,0x8950,/* 0xD0-0xD7 */ - 0x8951,0x8949,0x8B2A,0x8B27,0x8B23,0x8B33,0x8B30,0x8B35,/* 0xD8-0xDF */ - 0x8B47,0x8B2F,0x8B3C,0x8B3E,0x8B31,0x8B25,0x8B37,0x8B26,/* 0xE0-0xE7 */ - 0x8B36,0x8B2E,0x8B24,0x8B3B,0x8B3D,0x8B3A,0x8C42,0x8C75,/* 0xE8-0xEF */ - 0x8C99,0x8C98,0x8C97,0x8CFE,0x8D04,0x8D02,0x8D00,0x8E5C,/* 0xF0-0xF7 */ - 0x8E62,0x8E60,0x8E57,0x8E56,0x8E5E,0x8E65,0x8E67,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F1[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8E5B,0x8E5A,0x8E61,0x8E5D,0x8E69,0x8E54,0x8F46,0x8F47,/* 0x40-0x47 */ - 0x8F48,0x8F4B,0x9128,0x913A,0x913B,0x913E,0x91A8,0x91A5,/* 0x48-0x4F */ - 0x91A7,0x91AF,0x91AA,0x93B5,0x938C,0x9392,0x93B7,0x939B,/* 0x50-0x57 */ - 0x939D,0x9389,0x93A7,0x938E,0x93AA,0x939E,0x93A6,0x9395,/* 0x58-0x5F */ - 0x9388,0x9399,0x939F,0x938D,0x93B1,0x9391,0x93B2,0x93A4,/* 0x60-0x67 */ - 0x93A8,0x93B4,0x93A3,0x93A5,0x95D2,0x95D3,0x95D1,0x96B3,/* 0x68-0x6F */ - 0x96D7,0x96DA,0x5DC2,0x96DF,0x96D8,0x96DD,0x9723,0x9722,/* 0x70-0x77 */ - 0x9725,0x97AC,0x97AE,0x97A8,0x97AB,0x97A4,0x97AA,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x97A2,0x97A5,0x97D7,0x97D9,0x97D6,0x97D8,0x97FA,/* 0xA0-0xA7 */ - 0x9850,0x9851,0x9852,0x98B8,0x9941,0x993C,0x993A,0x9A0F,/* 0xA8-0xAF */ - 0x9A0B,0x9A09,0x9A0D,0x9A04,0x9A11,0x9A0A,0x9A05,0x9A07,/* 0xB0-0xB7 */ - 0x9A06,0x9AC0,0x9ADC,0x9B08,0x9B04,0x9B05,0x9B29,0x9B35,/* 0xB8-0xBF */ - 0x9B4A,0x9B4C,0x9B4B,0x9BC7,0x9BC6,0x9BC3,0x9BBF,0x9BC1,/* 0xC0-0xC7 */ - 0x9BB5,0x9BB8,0x9BD3,0x9BB6,0x9BC4,0x9BB9,0x9BBD,0x9D5C,/* 0xC8-0xCF */ - 0x9D53,0x9D4F,0x9D4A,0x9D5B,0x9D4B,0x9D59,0x9D56,0x9D4C,/* 0xD0-0xD7 */ - 0x9D57,0x9D52,0x9D54,0x9D5F,0x9D58,0x9D5A,0x9E8E,0x9E8C,/* 0xD8-0xDF */ - 0x9EDF,0x9F01,0x9F00,0x9F16,0x9F25,0x9F2B,0x9F2A,0x9F29,/* 0xE0-0xE7 */ - 0x9F28,0x9F4C,0x9F55,0x5134,0x5135,0x5296,0x52F7,0x53B4,/* 0xE8-0xEF */ - 0x56AB,0x56AD,0x56A6,0x56A7,0x56AA,0x56AC,0x58DA,0x58DD,/* 0xF0-0xF7 */ - 0x58DB,0x5912,0x5B3D,0x5B3E,0x5B3F,0x5DC3,0x5E70,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F2[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x5FBF,0x61FB,0x6507,0x6510,0x650D,0x6509,0x650C,0x650E,/* 0x40-0x47 */ - 0x6584,0x65DE,0x65DD,0x66DE,0x6AE7,0x6AE0,0x6ACC,0x6AD1,/* 0x48-0x4F */ - 0x6AD9,0x6ACB,0x6ADF,0x6ADC,0x6AD0,0x6AEB,0x6ACF,0x6ACD,/* 0x50-0x57 */ - 0x6ADE,0x6B60,0x6BB0,0x6C0C,0x7019,0x7027,0x7020,0x7016,/* 0x58-0x5F */ - 0x702B,0x7021,0x7022,0x7023,0x7029,0x7017,0x7024,0x701C,/* 0x60-0x67 */ - 0x702A,0x720C,0x720A,0x7207,0x7202,0x7205,0x72A5,0x72A6,/* 0x68-0x6F */ - 0x72A4,0x72A3,0x72A1,0x74CB,0x74C5,0x74B7,0x74C3,0x7516,/* 0x70-0x77 */ - 0x7660,0x77C9,0x77CA,0x77C4,0x77F1,0x791D,0x791B,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x7921,0x791C,0x7917,0x791E,0x79B0,0x7A67,0x7A68,/* 0xA0-0xA7 */ - 0x7C33,0x7C3C,0x7C39,0x7C2C,0x7C3B,0x7CEC,0x7CEA,0x7E76,/* 0xA8-0xAF */ - 0x7E75,0x7E78,0x7E70,0x7E77,0x7E6F,0x7E7A,0x7E72,0x7E74,/* 0xB0-0xB7 */ - 0x7E68,0x7F4B,0x7F4A,0x7F83,0x7F86,0x7FB7,0x7FFD,0x7FFE,/* 0xB8-0xBF */ - 0x8078,0x81D7,0x81D5,0x8264,0x8261,0x8263,0x85EB,0x85F1,/* 0xC0-0xC7 */ - 0x85ED,0x85D9,0x85E1,0x85E8,0x85DA,0x85D7,0x85EC,0x85F2,/* 0xC8-0xCF */ - 0x85F8,0x85D8,0x85DF,0x85E3,0x85DC,0x85D1,0x85F0,0x85E6,/* 0xD0-0xD7 */ - 0x85EF,0x85DE,0x85E2,0x8800,0x87FA,0x8803,0x87F6,0x87F7,/* 0xD8-0xDF */ - 0x8809,0x880C,0x880B,0x8806,0x87FC,0x8808,0x87FF,0x880A,/* 0xE0-0xE7 */ - 0x8802,0x8962,0x895A,0x895B,0x8957,0x8961,0x895C,0x8958,/* 0xE8-0xEF */ - 0x895D,0x8959,0x8988,0x89B7,0x89B6,0x89F6,0x8B50,0x8B48,/* 0xF0-0xF7 */ - 0x8B4A,0x8B40,0x8B53,0x8B56,0x8B54,0x8B4B,0x8B55,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F3[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8B51,0x8B42,0x8B52,0x8B57,0x8C43,0x8C77,0x8C76,0x8C9A,/* 0x40-0x47 */ - 0x8D06,0x8D07,0x8D09,0x8DAC,0x8DAA,0x8DAD,0x8DAB,0x8E6D,/* 0x48-0x4F */ - 0x8E78,0x8E73,0x8E6A,0x8E6F,0x8E7B,0x8EC2,0x8F52,0x8F51,/* 0x50-0x57 */ - 0x8F4F,0x8F50,0x8F53,0x8FB4,0x9140,0x913F,0x91B0,0x91AD,/* 0x58-0x5F */ - 0x93DE,0x93C7,0x93CF,0x93C2,0x93DA,0x93D0,0x93F9,0x93EC,/* 0x60-0x67 */ - 0x93CC,0x93D9,0x93A9,0x93E6,0x93CA,0x93D4,0x93EE,0x93E3,/* 0x68-0x6F */ - 0x93D5,0x93C4,0x93CE,0x93C0,0x93D2,0x93E7,0x957D,0x95DA,/* 0x70-0x77 */ - 0x95DB,0x96E1,0x9729,0x972B,0x972C,0x9728,0x9726,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x97B3,0x97B7,0x97B6,0x97DD,0x97DE,0x97DF,0x985C,/* 0xA0-0xA7 */ - 0x9859,0x985D,0x9857,0x98BF,0x98BD,0x98BB,0x98BE,0x9948,/* 0xA8-0xAF */ - 0x9947,0x9943,0x99A6,0x99A7,0x9A1A,0x9A15,0x9A25,0x9A1D,/* 0xB0-0xB7 */ - 0x9A24,0x9A1B,0x9A22,0x9A20,0x9A27,0x9A23,0x9A1E,0x9A1C,/* 0xB8-0xBF */ - 0x9A14,0x9AC2,0x9B0B,0x9B0A,0x9B0E,0x9B0C,0x9B37,0x9BEA,/* 0xC0-0xC7 */ - 0x9BEB,0x9BE0,0x9BDE,0x9BE4,0x9BE6,0x9BE2,0x9BF0,0x9BD4,/* 0xC8-0xCF */ - 0x9BD7,0x9BEC,0x9BDC,0x9BD9,0x9BE5,0x9BD5,0x9BE1,0x9BDA,/* 0xD0-0xD7 */ - 0x9D77,0x9D81,0x9D8A,0x9D84,0x9D88,0x9D71,0x9D80,0x9D78,/* 0xD8-0xDF */ - 0x9D86,0x9D8B,0x9D8C,0x9D7D,0x9D6B,0x9D74,0x9D75,0x9D70,/* 0xE0-0xE7 */ - 0x9D69,0x9D85,0x9D73,0x9D7B,0x9D82,0x9D6F,0x9D79,0x9D7F,/* 0xE8-0xEF */ - 0x9D87,0x9D68,0x9E94,0x9E91,0x9EC0,0x9EFC,0x9F2D,0x9F40,/* 0xF0-0xF7 */ - 0x9F41,0x9F4D,0x9F56,0x9F57,0x9F58,0x5337,0x56B2,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F4[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x56B5,0x56B3,0x58E3,0x5B45,0x5DC6,0x5DC7,0x5EEE,0x5EEF,/* 0x40-0x47 */ - 0x5FC0,0x5FC1,0x61F9,0x6517,0x6516,0x6515,0x6513,0x65DF,/* 0x48-0x4F */ - 0x66E8,0x66E3,0x66E4,0x6AF3,0x6AF0,0x6AEA,0x6AE8,0x6AF9,/* 0x50-0x57 */ - 0x6AF1,0x6AEE,0x6AEF,0x703C,0x7035,0x702F,0x7037,0x7034,/* 0x58-0x5F */ - 0x7031,0x7042,0x7038,0x703F,0x703A,0x7039,0x7040,0x703B,/* 0x60-0x67 */ - 0x7033,0x7041,0x7213,0x7214,0x72A8,0x737D,0x737C,0x74BA,/* 0x68-0x6F */ - 0x76AB,0x76AA,0x76BE,0x76ED,0x77CC,0x77CE,0x77CF,0x77CD,/* 0x70-0x77 */ - 0x77F2,0x7925,0x7923,0x7927,0x7928,0x7924,0x7929,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x79B2,0x7A6E,0x7A6C,0x7A6D,0x7AF7,0x7C49,0x7C48,/* 0xA0-0xA7 */ - 0x7C4A,0x7C47,0x7C45,0x7CEE,0x7E7B,0x7E7E,0x7E81,0x7E80,/* 0xA8-0xAF */ - 0x7FBA,0x7FFF,0x8079,0x81DB,0x81D9,0x820B,0x8268,0x8269,/* 0xB0-0xB7 */ - 0x8622,0x85FF,0x8601,0x85FE,0x861B,0x8600,0x85F6,0x8604,/* 0xB8-0xBF */ - 0x8609,0x8605,0x860C,0x85FD,0x8819,0x8810,0x8811,0x8817,/* 0xC0-0xC7 */ - 0x8813,0x8816,0x8963,0x8966,0x89B9,0x89F7,0x8B60,0x8B6A,/* 0xC8-0xCF */ - 0x8B5D,0x8B68,0x8B63,0x8B65,0x8B67,0x8B6D,0x8DAE,0x8E86,/* 0xD0-0xD7 */ - 0x8E88,0x8E84,0x8F59,0x8F56,0x8F57,0x8F55,0x8F58,0x8F5A,/* 0xD8-0xDF */ - 0x908D,0x9143,0x9141,0x91B7,0x91B5,0x91B2,0x91B3,0x940B,/* 0xE0-0xE7 */ - 0x9413,0x93FB,0x9420,0x940F,0x9414,0x93FE,0x9415,0x9410,/* 0xE8-0xEF */ - 0x9428,0x9419,0x940D,0x93F5,0x9400,0x93F7,0x9407,0x940E,/* 0xF0-0xF7 */ - 0x9416,0x9412,0x93FA,0x9409,0x93F8,0x940A,0x93FF,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F5[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x93FC,0x940C,0x93F6,0x9411,0x9406,0x95DE,0x95E0,0x95DF,/* 0x40-0x47 */ - 0x972E,0x972F,0x97B9,0x97BB,0x97FD,0x97FE,0x9860,0x9862,/* 0x48-0x4F */ - 0x9863,0x985F,0x98C1,0x98C2,0x9950,0x994E,0x9959,0x994C,/* 0x50-0x57 */ - 0x994B,0x9953,0x9A32,0x9A34,0x9A31,0x9A2C,0x9A2A,0x9A36,/* 0x58-0x5F */ - 0x9A29,0x9A2E,0x9A38,0x9A2D,0x9AC7,0x9ACA,0x9AC6,0x9B10,/* 0x60-0x67 */ - 0x9B12,0x9B11,0x9C0B,0x9C08,0x9BF7,0x9C05,0x9C12,0x9BF8,/* 0x68-0x6F */ - 0x9C40,0x9C07,0x9C0E,0x9C06,0x9C17,0x9C14,0x9C09,0x9D9F,/* 0x70-0x77 */ - 0x9D99,0x9DA4,0x9D9D,0x9D92,0x9D98,0x9D90,0x9D9B,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x9DA0,0x9D94,0x9D9C,0x9DAA,0x9D97,0x9DA1,0x9D9A,/* 0xA0-0xA7 */ - 0x9DA2,0x9DA8,0x9D9E,0x9DA3,0x9DBF,0x9DA9,0x9D96,0x9DA6,/* 0xA8-0xAF */ - 0x9DA7,0x9E99,0x9E9B,0x9E9A,0x9EE5,0x9EE4,0x9EE7,0x9EE6,/* 0xB0-0xB7 */ - 0x9F30,0x9F2E,0x9F5B,0x9F60,0x9F5E,0x9F5D,0x9F59,0x9F91,/* 0xB8-0xBF */ - 0x513A,0x5139,0x5298,0x5297,0x56C3,0x56BD,0x56BE,0x5B48,/* 0xC0-0xC7 */ - 0x5B47,0x5DCB,0x5DCF,0x5EF1,0x61FD,0x651B,0x6B02,0x6AFC,/* 0xC8-0xCF */ - 0x6B03,0x6AF8,0x6B00,0x7043,0x7044,0x704A,0x7048,0x7049,/* 0xD0-0xD7 */ - 0x7045,0x7046,0x721D,0x721A,0x7219,0x737E,0x7517,0x766A,/* 0xD8-0xDF */ - 0x77D0,0x792D,0x7931,0x792F,0x7C54,0x7C53,0x7CF2,0x7E8A,/* 0xE0-0xE7 */ - 0x7E87,0x7E88,0x7E8B,0x7E86,0x7E8D,0x7F4D,0x7FBB,0x8030,/* 0xE8-0xEF */ - 0x81DD,0x8618,0x862A,0x8626,0x861F,0x8623,0x861C,0x8619,/* 0xF0-0xF7 */ - 0x8627,0x862E,0x8621,0x8620,0x8629,0x861E,0x8625,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F6[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8829,0x881D,0x881B,0x8820,0x8824,0x881C,0x882B,0x884A,/* 0x40-0x47 */ - 0x896D,0x8969,0x896E,0x896B,0x89FA,0x8B79,0x8B78,0x8B45,/* 0x48-0x4F */ - 0x8B7A,0x8B7B,0x8D10,0x8D14,0x8DAF,0x8E8E,0x8E8C,0x8F5E,/* 0x50-0x57 */ - 0x8F5B,0x8F5D,0x9146,0x9144,0x9145,0x91B9,0x943F,0x943B,/* 0x58-0x5F */ - 0x9436,0x9429,0x943D,0x943C,0x9430,0x9439,0x942A,0x9437,/* 0x60-0x67 */ - 0x942C,0x9440,0x9431,0x95E5,0x95E4,0x95E3,0x9735,0x973A,/* 0x68-0x6F */ - 0x97BF,0x97E1,0x9864,0x98C9,0x98C6,0x98C0,0x9958,0x9956,/* 0x70-0x77 */ - 0x9A39,0x9A3D,0x9A46,0x9A44,0x9A42,0x9A41,0x9A3A,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x9A3F,0x9ACD,0x9B15,0x9B17,0x9B18,0x9B16,0x9B3A,/* 0xA0-0xA7 */ - 0x9B52,0x9C2B,0x9C1D,0x9C1C,0x9C2C,0x9C23,0x9C28,0x9C29,/* 0xA8-0xAF */ - 0x9C24,0x9C21,0x9DB7,0x9DB6,0x9DBC,0x9DC1,0x9DC7,0x9DCA,/* 0xB0-0xB7 */ - 0x9DCF,0x9DBE,0x9DC5,0x9DC3,0x9DBB,0x9DB5,0x9DCE,0x9DB9,/* 0xB8-0xBF */ - 0x9DBA,0x9DAC,0x9DC8,0x9DB1,0x9DAD,0x9DCC,0x9DB3,0x9DCD,/* 0xC0-0xC7 */ - 0x9DB2,0x9E7A,0x9E9C,0x9EEB,0x9EEE,0x9EED,0x9F1B,0x9F18,/* 0xC8-0xCF */ - 0x9F1A,0x9F31,0x9F4E,0x9F65,0x9F64,0x9F92,0x4EB9,0x56C6,/* 0xD0-0xD7 */ - 0x56C5,0x56CB,0x5971,0x5B4B,0x5B4C,0x5DD5,0x5DD1,0x5EF2,/* 0xD8-0xDF */ - 0x6521,0x6520,0x6526,0x6522,0x6B0B,0x6B08,0x6B09,0x6C0D,/* 0xE0-0xE7 */ - 0x7055,0x7056,0x7057,0x7052,0x721E,0x721F,0x72A9,0x737F,/* 0xE8-0xEF */ - 0x74D8,0x74D5,0x74D9,0x74D7,0x766D,0x76AD,0x7935,0x79B4,/* 0xF0-0xF7 */ - 0x7A70,0x7A71,0x7C57,0x7C5C,0x7C59,0x7C5B,0x7C5A,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F7[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7CF4,0x7CF1,0x7E91,0x7F4F,0x7F87,0x81DE,0x826B,0x8634,/* 0x40-0x47 */ - 0x8635,0x8633,0x862C,0x8632,0x8636,0x882C,0x8828,0x8826,/* 0x48-0x4F */ - 0x882A,0x8825,0x8971,0x89BF,0x89BE,0x89FB,0x8B7E,0x8B84,/* 0x50-0x57 */ - 0x8B82,0x8B86,0x8B85,0x8B7F,0x8D15,0x8E95,0x8E94,0x8E9A,/* 0x58-0x5F */ - 0x8E92,0x8E90,0x8E96,0x8E97,0x8F60,0x8F62,0x9147,0x944C,/* 0x60-0x67 */ - 0x9450,0x944A,0x944B,0x944F,0x9447,0x9445,0x9448,0x9449,/* 0x68-0x6F */ - 0x9446,0x973F,0x97E3,0x986A,0x9869,0x98CB,0x9954,0x995B,/* 0x70-0x77 */ - 0x9A4E,0x9A53,0x9A54,0x9A4C,0x9A4F,0x9A48,0x9A4A,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x9A49,0x9A52,0x9A50,0x9AD0,0x9B19,0x9B2B,0x9B3B,/* 0xA0-0xA7 */ - 0x9B56,0x9B55,0x9C46,0x9C48,0x9C3F,0x9C44,0x9C39,0x9C33,/* 0xA8-0xAF */ - 0x9C41,0x9C3C,0x9C37,0x9C34,0x9C32,0x9C3D,0x9C36,0x9DDB,/* 0xB0-0xB7 */ - 0x9DD2,0x9DDE,0x9DDA,0x9DCB,0x9DD0,0x9DDC,0x9DD1,0x9DDF,/* 0xB8-0xBF */ - 0x9DE9,0x9DD9,0x9DD8,0x9DD6,0x9DF5,0x9DD5,0x9DDD,0x9EB6,/* 0xC0-0xC7 */ - 0x9EF0,0x9F35,0x9F33,0x9F32,0x9F42,0x9F6B,0x9F95,0x9FA2,/* 0xC8-0xCF */ - 0x513D,0x5299,0x58E8,0x58E7,0x5972,0x5B4D,0x5DD8,0x882F,/* 0xD0-0xD7 */ - 0x5F4F,0x6201,0x6203,0x6204,0x6529,0x6525,0x6596,0x66EB,/* 0xD8-0xDF */ - 0x6B11,0x6B12,0x6B0F,0x6BCA,0x705B,0x705A,0x7222,0x7382,/* 0xE0-0xE7 */ - 0x7381,0x7383,0x7670,0x77D4,0x7C67,0x7C66,0x7E95,0x826C,/* 0xE8-0xEF */ - 0x863A,0x8640,0x8639,0x863C,0x8631,0x863B,0x863E,0x8830,/* 0xF0-0xF7 */ - 0x8832,0x882E,0x8833,0x8976,0x8974,0x8973,0x89FE,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F8[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x8B8C,0x8B8E,0x8B8B,0x8B88,0x8C45,0x8D19,0x8E98,0x8F64,/* 0x40-0x47 */ - 0x8F63,0x91BC,0x9462,0x9455,0x945D,0x9457,0x945E,0x97C4,/* 0x48-0x4F */ - 0x97C5,0x9800,0x9A56,0x9A59,0x9B1E,0x9B1F,0x9B20,0x9C52,/* 0x50-0x57 */ - 0x9C58,0x9C50,0x9C4A,0x9C4D,0x9C4B,0x9C55,0x9C59,0x9C4C,/* 0x58-0x5F */ - 0x9C4E,0x9DFB,0x9DF7,0x9DEF,0x9DE3,0x9DEB,0x9DF8,0x9DE4,/* 0x60-0x67 */ - 0x9DF6,0x9DE1,0x9DEE,0x9DE6,0x9DF2,0x9DF0,0x9DE2,0x9DEC,/* 0x68-0x6F */ - 0x9DF4,0x9DF3,0x9DE8,0x9DED,0x9EC2,0x9ED0,0x9EF2,0x9EF3,/* 0x70-0x77 */ - 0x9F06,0x9F1C,0x9F38,0x9F37,0x9F36,0x9F43,0x9F4F,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x9F71,0x9F70,0x9F6E,0x9F6F,0x56D3,0x56CD,0x5B4E,/* 0xA0-0xA7 */ - 0x5C6D,0x652D,0x66ED,0x66EE,0x6B13,0x705F,0x7061,0x705D,/* 0xA8-0xAF */ - 0x7060,0x7223,0x74DB,0x74E5,0x77D5,0x7938,0x79B7,0x79B6,/* 0xB0-0xB7 */ - 0x7C6A,0x7E97,0x7F89,0x826D,0x8643,0x8838,0x8837,0x8835,/* 0xB8-0xBF */ - 0x884B,0x8B94,0x8B95,0x8E9E,0x8E9F,0x8EA0,0x8E9D,0x91BE,/* 0xC0-0xC7 */ - 0x91BD,0x91C2,0x946B,0x9468,0x9469,0x96E5,0x9746,0x9743,/* 0xC8-0xCF */ - 0x9747,0x97C7,0x97E5,0x9A5E,0x9AD5,0x9B59,0x9C63,0x9C67,/* 0xD0-0xD7 */ - 0x9C66,0x9C62,0x9C5E,0x9C60,0x9E02,0x9DFE,0x9E07,0x9E03,/* 0xD8-0xDF */ - 0x9E06,0x9E05,0x9E00,0x9E01,0x9E09,0x9DFF,0x9DFD,0x9E04,/* 0xE0-0xE7 */ - 0x9EA0,0x9F1E,0x9F46,0x9F74,0x9F75,0x9F76,0x56D4,0x652E,/* 0xE8-0xEF */ - 0x65B8,0x6B18,0x6B19,0x6B17,0x6B1A,0x7062,0x7226,0x72AA,/* 0xF0-0xF7 */ - 0x77D8,0x77D9,0x7939,0x7C69,0x7C6B,0x7CF6,0x7E9A,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t c2u_F9[256] = { - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x00-0x07 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x08-0x0F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x10-0x17 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x18-0x1F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x20-0x27 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x28-0x2F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x30-0x37 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x38-0x3F */ - 0x7E98,0x7E9B,0x7E99,0x81E0,0x81E1,0x8646,0x8647,0x8648,/* 0x40-0x47 */ - 0x8979,0x897A,0x897C,0x897B,0x89FF,0x8B98,0x8B99,0x8EA5,/* 0x48-0x4F */ - 0x8EA4,0x8EA3,0x946E,0x946D,0x946F,0x9471,0x9473,0x9749,/* 0x50-0x57 */ - 0x9872,0x995F,0x9C68,0x9C6E,0x9C6D,0x9E0B,0x9E0D,0x9E10,/* 0x58-0x5F */ - 0x9E0F,0x9E12,0x9E11,0x9EA1,0x9EF5,0x9F09,0x9F47,0x9F78,/* 0x60-0x67 */ - 0x9F7B,0x9F7A,0x9F79,0x571E,0x7066,0x7C6F,0x883C,0x8DB2,/* 0x68-0x6F */ - 0x8EA6,0x91C3,0x9474,0x9478,0x9476,0x9475,0x9A60,0x9C74,/* 0x70-0x77 */ - 0x9C73,0x9C71,0x9C75,0x9E14,0x9E13,0x9EF6,0x9F0A,0x0000,/* 0x78-0x7F */ - - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x80-0x87 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x88-0x8F */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x90-0x97 */ - 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,/* 0x98-0x9F */ - 0x0000,0x9FA4,0x7068,0x7065,0x7CF7,0x866A,0x883E,0x883D,/* 0xA0-0xA7 */ - 0x883F,0x8B9E,0x8C9C,0x8EA9,0x8EC9,0x974B,0x9873,0x9874,/* 0xA8-0xAF */ - 0x98CC,0x9961,0x99AB,0x9A64,0x9A66,0x9A67,0x9B24,0x9E15,/* 0xB0-0xB7 */ - 0x9E17,0x9F48,0x6207,0x6B1E,0x7227,0x864C,0x8EA8,0x9482,/* 0xB8-0xBF */ - 0x9480,0x9481,0x9A69,0x9A68,0x9B2E,0x9E19,0x7229,0x864B,/* 0xC0-0xC7 */ - 0x8B9F,0x9483,0x9C79,0x9EB7,0x7675,0x9A6B,0x9C7A,0x9E1D,/* 0xC8-0xCF */ - 0x7069,0x706A,0x9EA4,0x9F7E,0x9F49,0x9F98,0x7881,0x92B9,/* 0xD0-0xD7 */ - 0x88CF,0x58BB,0x6052,0x7CA7,0x5AFA,0x2554,0x2566,0x2557,/* 0xD8-0xDF */ - 0x2560,0x256C,0x2563,0x255A,0x2569,0x255D,0x2552,0x2564,/* 0xE0-0xE7 */ - 0x2555,0x255E,0x256A,0x2561,0x2558,0x2567,0x255B,0x2553,/* 0xE8-0xEF */ - 0x2565,0x2556,0x255F,0x256B,0x2562,0x2559,0x2568,0x255C,/* 0xF0-0xF7 */ - 0x2551,0x2550,0x256D,0x256E,0x2570,0x256F,0x2593,0x0000,/* 0xF8-0xFF */ -}; - -static const wchar_t *page_charset2uni[256] = { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, c2u_A1, c2u_A2, c2u_A3, c2u_A4, c2u_A5, c2u_A6, c2u_A7, - c2u_A8, c2u_A9, c2u_AA, c2u_AB, c2u_AC, c2u_AD, c2u_AE, c2u_AF, - c2u_B0, c2u_B1, c2u_B2, c2u_B3, c2u_B4, c2u_B5, c2u_B6, c2u_B7, - c2u_B8, c2u_B9, c2u_BA, c2u_BB, c2u_BC, c2u_BD, c2u_BE, c2u_BF, - c2u_C0, c2u_C1, c2u_C2, c2u_C3, c2u_C4, c2u_C5, c2u_C6, NULL, - NULL, c2u_C9, c2u_CA, c2u_CB, c2u_CC, c2u_CD, c2u_CE, c2u_CF, - c2u_D0, c2u_D1, c2u_D2, c2u_D3, c2u_D4, c2u_D5, c2u_D6, c2u_D7, - c2u_D8, c2u_D9, c2u_DA, c2u_DB, c2u_DC, c2u_DD, c2u_DE, c2u_DF, - c2u_E0, c2u_E1, c2u_E2, c2u_E3, c2u_E4, c2u_E5, c2u_E6, c2u_E7, - c2u_E8, c2u_E9, c2u_EA, c2u_EB, c2u_EC, c2u_ED, c2u_EE, c2u_EF, - c2u_F0, c2u_F1, c2u_F2, c2u_F3, c2u_F4, c2u_F5, c2u_F6, c2u_F7, - c2u_F8, c2u_F9, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char u2c_02[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA3, 0xBE, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xA3, 0xBC, 0xA3, 0xBD, 0xA3, 0xBF, /* 0xC8-0xCB */ - 0x00, 0x00, 0xA1, 0xC5, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xA3, 0xBB, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ -}; - -static const unsigned char u2c_03[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xA1, 0xC2, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xA3, 0x44, 0xA3, 0x45, 0xA3, 0x46, /* 0x90-0x93 */ - 0xA3, 0x47, 0xA3, 0x48, 0xA3, 0x49, 0xA3, 0x4A, /* 0x94-0x97 */ - 0xA3, 0x4B, 0xA3, 0x4C, 0xA3, 0x4D, 0xA3, 0x4E, /* 0x98-0x9B */ - 0xA3, 0x4F, 0xA3, 0x50, 0xA3, 0x51, 0xA3, 0x52, /* 0x9C-0x9F */ - 0xA3, 0x53, 0xA3, 0x54, 0x00, 0x00, 0xA3, 0x55, /* 0xA0-0xA3 */ - 0xA3, 0x56, 0xA3, 0x57, 0xA3, 0x58, 0xA3, 0x59, /* 0xA4-0xA7 */ - 0xA3, 0x5A, 0xA3, 0x5B, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xA3, 0x5C, 0xA3, 0x5D, 0xA3, 0x5E, /* 0xB0-0xB3 */ - 0xA3, 0x5F, 0xA3, 0x60, 0xA3, 0x61, 0xA3, 0x62, /* 0xB4-0xB7 */ - 0xA3, 0x63, 0xA3, 0x64, 0xA3, 0x65, 0xA3, 0x66, /* 0xB8-0xBB */ - 0xA3, 0x67, 0xA3, 0x68, 0xA3, 0x69, 0xA3, 0x6A, /* 0xBC-0xBF */ - 0xA3, 0x6B, 0xA3, 0x6C, 0x00, 0x00, 0xA3, 0x6D, /* 0xC0-0xC3 */ - 0xA3, 0x6E, 0xA3, 0x6F, 0xA3, 0x70, 0xA3, 0x71, /* 0xC4-0xC7 */ - 0xA3, 0x72, 0xA3, 0x73, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ -}; - -static const unsigned char u2c_20[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0x56, /* 0x10-0x13 */ - 0xA1, 0x58, 0xA2, 0x77, 0xA1, 0xFC, 0x00, 0x00, /* 0x14-0x17 */ - 0xA1, 0xA5, 0xA1, 0xA6, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xA1, 0xA7, 0xA1, 0xA8, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0x45, 0x00, 0x00, /* 0x20-0x23 */ - 0xA3, 0xBB, 0xA1, 0x4C, 0xA1, 0x4B, 0xA1, 0x45, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xAC, 0xA1, 0xB2, /* 0x30-0x33 */ - 0x00, 0x00, 0xA1, 0xAB, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xB0, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xC3, 0x00, 0x00, /* 0x3C-0x3F */ -}; - -static const unsigned char u2c_21[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA2, 0x4A, /* 0x00-0x03 */ - 0x00, 0x00, 0xA1, 0xC1, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xA2, 0x4B, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xA2, 0xB9, 0xA2, 0xBA, 0xA2, 0xBB, 0xA2, 0xBC, /* 0x60-0x63 */ - 0xA2, 0xBD, 0xA2, 0xBE, 0xA2, 0xBF, 0xA2, 0xC0, /* 0x64-0x67 */ - 0xA2, 0xC1, 0xA2, 0xC2, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xA1, 0xF6, 0xA1, 0xF4, 0xA1, 0xF7, 0xA1, 0xF5, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xF8, 0xA1, 0xF9, /* 0x94-0x97 */ - 0xA1, 0xFB, 0xA1, 0xFA, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ -}; - -static const unsigned char u2c_22[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xA2, 0x41, 0xA2, 0x42, 0x00, 0x00, /* 0x14-0x17 */ - 0xA2, 0x58, 0x00, 0x00, 0xA1, 0xD4, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xDB, 0xA1, 0xE8, /* 0x1C-0x1F */ - 0xA1, 0xE7, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xFD, /* 0x20-0x23 */ - 0x00, 0x00, 0xA1, 0xFC, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xA1, 0xE4, 0xA1, 0xE5, 0xA1, 0xEC, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xED, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xA1, 0xEF, 0xA1, 0xEE, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xDC, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xA1, 0xDA, 0xA1, 0xDD, 0x00, 0x00, 0xA1, 0xDD, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xD8, 0xA1, 0xD9, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0xA1, 0xF2, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xA1, 0xF3, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xA1, 0xE6, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xE9, /* 0xBC-0xBF */ -}; - -static const unsigned char u2c_23[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0x5B, /* 0x04-0x07 */ -}; - -static const unsigned char u2c_25[512] = { - 0xA2, 0x77, 0x00, 0x00, 0xA2, 0x78, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0xA2, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xA2, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xA2, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xA2, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xA2, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0xA2, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0xA2, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xA2, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xA2, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xF9, 0xF9, 0xF9, 0xF8, 0xF9, 0xE6, 0xF9, 0xEF, /* 0x50-0x53 */ - 0xF9, 0xDD, 0xF9, 0xE8, 0xF9, 0xF1, 0xF9, 0xDF, /* 0x54-0x57 */ - 0xF9, 0xEC, 0xF9, 0xF5, 0xF9, 0xE3, 0xF9, 0xEE, /* 0x58-0x5B */ - 0xF9, 0xF7, 0xF9, 0xE5, 0xF9, 0xE9, 0xF9, 0xF2, /* 0x5C-0x5F */ - 0xF9, 0xE0, 0xF9, 0xEB, 0xF9, 0xF4, 0xF9, 0xE2, /* 0x60-0x63 */ - 0xF9, 0xE7, 0xF9, 0xF0, 0xF9, 0xDE, 0xF9, 0xED, /* 0x64-0x67 */ - 0xF9, 0xF6, 0xF9, 0xE4, 0xF9, 0xEA, 0xF9, 0xF3, /* 0x68-0x6B */ - 0xF9, 0xE1, 0xA2, 0x7E, 0xA2, 0xA1, 0xA2, 0xA3, /* 0x6C-0x6F */ - 0xA2, 0xA2, 0xA2, 0xAC, 0xA2, 0xAD, 0xA2, 0xAE, /* 0x70-0x73 */ - 0xA1, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xA2, 0x62, 0xA2, 0x63, 0xA2, 0x64, /* 0x80-0x83 */ - 0xA2, 0x65, 0xA2, 0x66, 0xA2, 0x67, 0xA2, 0x68, /* 0x84-0x87 */ - 0xA2, 0x69, 0xA2, 0x70, 0xA2, 0x6F, 0xA2, 0x6E, /* 0x88-0x8B */ - 0xA2, 0x6D, 0xA2, 0x6C, 0xA2, 0x6B, 0xA2, 0x6A, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xFE, /* 0x90-0x93 */ - 0xA2, 0x76, 0xA2, 0x79, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xA1, 0xBD, 0xA1, 0xBC, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xB6, 0xA1, 0xB5, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0xA1, 0xBF, 0xA1, 0xBE, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xBB, 0xA1, 0xBA, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA1, 0xB3, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xA1, 0xB7, 0xA1, 0xB4, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xA2, 0xA8, 0xA2, 0xA9, /* 0xE0-0xE3 */ - 0xA2, 0xAB, 0xA2, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ -}; - -static const unsigned char u2c_26[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xA1, 0xB9, 0xA1, 0xB8, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xA1, 0xF3, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xA1, 0xF0, 0xA1, 0xF2, 0xA1, 0xF1, 0x00, 0x00, /* 0x40-0x43 */ -}; - -static const unsigned char u2c_30[512] = { - 0xA1, 0x40, 0xA1, 0x42, 0xA1, 0x43, 0xA1, 0xB2, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xA1, 0x71, 0xA1, 0x72, 0xA1, 0x6D, 0xA1, 0x6E, /* 0x08-0x0B */ - 0xA1, 0x75, 0xA1, 0x76, 0xA1, 0x79, 0xA1, 0x7A, /* 0x0C-0x0F */ - 0xA1, 0x69, 0xA1, 0x6A, 0xA2, 0x45, 0x00, 0x00, /* 0x10-0x13 */ - 0xA1, 0x65, 0xA1, 0x66, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xA1, 0xE3, 0xA1, 0xA9, 0xA1, 0xAA, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xA2, 0xC3, 0xA2, 0xC4, 0xA2, 0xC5, /* 0x20-0x23 */ - 0xA2, 0xC6, 0xA2, 0xC7, 0xA2, 0xC8, 0xA2, 0xC9, /* 0x24-0x27 */ - 0xA2, 0xCA, 0xA2, 0xCB, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xA1, 0xCA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ -}; - -static const unsigned char u2c_31[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xA3, 0x74, 0xA3, 0x75, 0xA3, 0x76, /* 0x04-0x07 */ - 0xA3, 0x77, 0xA3, 0x78, 0xA3, 0x79, 0xA3, 0x7A, /* 0x08-0x0B */ - 0xA3, 0x7B, 0xA3, 0x7C, 0xA3, 0x7D, 0xA3, 0x7E, /* 0x0C-0x0F */ - 0xA3, 0xA1, 0xA3, 0xA2, 0xA3, 0xA3, 0xA3, 0xA4, /* 0x10-0x13 */ - 0xA3, 0xA5, 0xA3, 0xA6, 0xA3, 0xA7, 0xA3, 0xA8, /* 0x14-0x17 */ - 0xA3, 0xA9, 0xA3, 0xAA, 0xA3, 0xAB, 0xA3, 0xAC, /* 0x18-0x1B */ - 0xA3, 0xAD, 0xA3, 0xAE, 0xA3, 0xAF, 0xA3, 0xB0, /* 0x1C-0x1F */ - 0xA3, 0xB1, 0xA3, 0xB2, 0xA3, 0xB3, 0xA3, 0xB4, /* 0x20-0x23 */ - 0xA3, 0xB5, 0xA3, 0xB6, 0xA3, 0xB7, 0xA3, 0xB8, /* 0x24-0x27 */ - 0xA3, 0xB9, 0xA3, 0xBA, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xA4, 0x40, 0xA4, 0x47, /* 0x90-0x93 */ - 0xA4, 0x54, 0xA5, 0x7C, 0xA4, 0x57, 0xA4, 0xA4, /* 0x94-0x97 */ - 0xA4, 0x55, 0xA5, 0xD2, 0xA4, 0x41, 0xA4, 0xFE, /* 0x98-0x9B */ - 0xA4, 0x42, 0xA4, 0xD1, 0xA6, 0x61, 0xA4, 0x48, /* 0x9C-0x9F */ -}; - -static const unsigned char u2c_32[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xA4, 0x40, 0xA4, 0x47, 0xA4, 0x54, 0xA5, 0x7C, /* 0x20-0x23 */ - 0xA4, 0xAD, 0xA4, 0xBB, 0xA4, 0x43, 0xA4, 0x4B, /* 0x24-0x27 */ - 0xA4, 0x45, 0xA4, 0x51, 0xA4, 0xEB, 0xA4, 0xF5, /* 0x28-0x2B */ - 0xA4, 0xF4, 0xA4, 0xEC, 0xAA, 0xF7, 0xA4, 0x67, /* 0x2C-0x2F */ - 0xA4, 0xE9, 0xAE, 0xE8, 0xA6, 0xB3, 0xAA, 0xC0, /* 0x30-0x33 */ - 0xA6, 0x57, 0xAF, 0x53, 0xB0, 0x5D, 0xAF, 0xAC, /* 0x34-0x37 */ - 0xB3, 0xD2, 0xA5, 0x4E, 0xA9, 0x49, 0xBE, 0xC7, /* 0x38-0x3B */ - 0xBA, 0xCA, 0xA5, 0xF8, 0xB8, 0xEA, 0xA8, 0xF3, /* 0x3C-0x3F */ - 0xB2, 0xBD, 0xA5, 0xF0, 0xA6, 0xDB, 0xA6, 0xDC, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xA4, 0x40, 0xA4, 0x47, 0xA4, 0x54, 0xA5, 0x7C, /* 0x80-0x83 */ - 0xA4, 0xAD, 0xA4, 0xBB, 0xA4, 0x43, 0xA4, 0x4B, /* 0x84-0x87 */ - 0xA4, 0x45, 0xA4, 0x51, 0xA4, 0xEB, 0xA4, 0xF5, /* 0x88-0x8B */ - 0xA4, 0xF4, 0xA4, 0xEC, 0xAA, 0xF7, 0xA4, 0x67, /* 0x8C-0x8F */ - 0xA4, 0xE9, 0xAE, 0xE8, 0xA6, 0xB3, 0xAA, 0xC0, /* 0x90-0x93 */ - 0xA6, 0x57, 0xAF, 0x53, 0xB0, 0x5D, 0xAF, 0xAC, /* 0x94-0x97 */ - 0xB3, 0xD2, 0xAF, 0xB5, 0xA8, 0x6B, 0xA4, 0x6B, /* 0x98-0x9B */ - 0xBE, 0x41, 0xC0, 0x75, 0xA6, 0x4C, 0xAA, 0x60, /* 0x9C-0x9F */ - 0xB6, 0xB5, 0xA5, 0xF0, 0xBC, 0x67, 0xA1, 0xC0, /* 0xA0-0xA3 */ - 0xA4, 0x57, 0xA4, 0xA4, 0xA4, 0x55, 0xA5, 0xAA, /* 0xA4-0xA7 */ - 0xA5, 0x6B, 0xC2, 0xE5, 0xA9, 0x76, 0xBE, 0xC7, /* 0xA8-0xAB */ - 0xBA, 0xCA, 0xA5, 0xF8, 0xB8, 0xEA, 0xA8, 0xF3, /* 0xAC-0xAF */ - 0xA9, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ -}; - -static const unsigned char u2c_33[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xA2, 0x55, 0xA2, 0x56, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xA2, 0x50, 0xA2, 0x51, 0xA2, 0x52, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xA2, 0x54, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xA2, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xA2, 0x53, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xA1, 0xEB, 0xA1, 0xEA, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xA2, 0x4F, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ -}; - -static const unsigned char u2c_4E[512] = { - 0xA4, 0x40, 0xA4, 0x42, 0x00, 0x00, 0xA4, 0x43, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC9, 0x45, /* 0x04-0x07 */ - 0xA4, 0x56, 0xA4, 0x54, 0xA4, 0x57, 0xA4, 0x55, /* 0x08-0x0B */ - 0xC9, 0x46, 0xA4, 0xA3, 0xC9, 0x4F, 0xC9, 0x4D, /* 0x0C-0x0F */ - 0xA4, 0xA2, 0xA4, 0xA1, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xA5, 0x42, 0xA5, 0x41, 0xA5, 0x40, 0x00, 0x00, /* 0x14-0x17 */ - 0xA5, 0x43, 0xA4, 0xFE, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xA5, 0xE0, 0xA5, 0xE1, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0xC3, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0x58, /* 0x28-0x2B */ - 0x00, 0x00, 0xA4, 0xA4, 0xC9, 0x50, 0x00, 0x00, /* 0x2C-0x2F */ - 0xA4, 0xA5, 0xC9, 0x63, 0xA6, 0xEA, 0xCB, 0xB1, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xA4, 0x59, 0xA4, 0xA6, 0x00, 0x00, 0xA5, 0x44, /* 0x38-0x3B */ - 0xC9, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0xC9, 0x40, 0xA4, 0x44, /* 0x40-0x43 */ - 0x00, 0x00, 0xA4, 0x5B, 0x00, 0x00, 0xC9, 0x47, /* 0x44-0x47 */ - 0xA4, 0x5C, 0x00, 0x00, 0x00, 0x00, 0xA4, 0xA7, /* 0x48-0x4B */ - 0x00, 0x00, 0xA5, 0x45, 0xA5, 0x47, 0xA5, 0x46, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xA5, 0xE2, 0xA5, 0xE3, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0xC4, 0x00, 0x00, /* 0x54-0x57 */ - 0xAD, 0xBC, 0xA4, 0x41, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0xC9, 0x41, 0xA4, 0x45, 0xA4, 0x5E, 0xA4, 0x5D, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xA5, 0xE4, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xC5, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xB0, 0xAE, 0xD4, 0x4B, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xB6, 0xC3, 0xDC, 0xB1, /* 0x80-0x83 */ - 0xDC, 0xB2, 0x00, 0x00, 0xA4, 0x46, 0x00, 0x00, /* 0x84-0x87 */ - 0xA4, 0xA9, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xC6, /* 0x88-0x8B */ - 0xA4, 0x47, 0xC9, 0x48, 0xA4, 0x5F, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xA4, 0xAA, 0xA4, 0xAC, 0xC9, 0x51, /* 0x90-0x93 */ - 0xA4, 0xAD, 0xA4, 0xAB, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xA5, 0xE5, 0x00, 0x00, 0xA8, 0xC7, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0xC8, 0xAB, 0x45, /* 0x9C-0x9F */ - 0x00, 0x00, 0xA4, 0x60, 0xA4, 0xAE, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xA5, 0xE6, 0xA5, 0xE8, 0xA5, 0xE7, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xA6, 0xEB, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xC9, /* 0xA8-0xAB */ - 0xA8, 0xCA, 0xAB, 0x46, 0xAB, 0x47, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAD, 0xBD, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xDC, 0xB3, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xF6, 0xD6, 0xA4, 0x48, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xA4, 0xB0, 0xA4, 0xAF, 0xC9, 0x52, 0xA4, 0xB1, /* 0xC0-0xC3 */ - 0xA4, 0xB7, 0x00, 0x00, 0xA4, 0xB2, 0xA4, 0xB3, /* 0xC4-0xC7 */ - 0xC9, 0x54, 0xC9, 0x53, 0xA4, 0xB5, 0xA4, 0xB6, /* 0xC8-0xCB */ - 0x00, 0x00, 0xA4, 0xB4, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xA5, 0x4A, 0xA5, 0x4B, 0xA5, 0x4C, 0xA5, 0x4D, /* 0xD4-0xD7 */ - 0xA5, 0x49, 0xA5, 0x50, 0xC9, 0x6A, 0x00, 0x00, /* 0xD8-0xDB */ - 0xC9, 0x66, 0xC9, 0x69, 0xA5, 0x51, 0xA5, 0x61, /* 0xDC-0xDF */ - 0x00, 0x00, 0xC9, 0x68, 0x00, 0x00, 0xA5, 0x4E, /* 0xE0-0xE3 */ - 0xA5, 0x4F, 0xA5, 0x48, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xC9, 0x65, 0xC9, 0x67, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xA5, 0xF5, 0xC9, 0xB0, 0xA5, 0xF2, 0xA5, 0xF6, /* 0xF0-0xF3 */ - 0xC9, 0xBA, 0xC9, 0xAE, 0xA5, 0xF3, 0xC9, 0xB2, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA5, 0xF4, /* 0xF8-0xFB */ - 0x00, 0x00, 0xA5, 0xF7, 0x00, 0x00, 0xA5, 0xE9, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_4F[512] = { - 0xC9, 0xB1, 0xA5, 0xF8, 0xC9, 0xB5, 0x00, 0x00, /* 0x00-0x03 */ - 0xC9, 0xB9, 0xC9, 0xB6, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xC9, 0xB3, 0xA5, 0xEA, 0xA5, 0xEC, 0xA5, 0xF9, /* 0x08-0x0B */ - 0x00, 0x00, 0xA5, 0xEE, 0xC9, 0xAB, 0xA5, 0xF1, /* 0x0C-0x0F */ - 0xA5, 0xEF, 0xA5, 0xF0, 0xC9, 0xBB, 0xC9, 0xB8, /* 0x10-0x13 */ - 0xC9, 0xAF, 0xA5, 0xED, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xC9, 0xAC, 0xA5, 0xEB, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0xC9, 0xB4, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0xC9, 0xB7, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0xC9, 0xAD, 0xCA, 0x66, 0x00, 0x00, 0xA7, 0x42, /* 0x2C-0x2F */ - 0xA6, 0xF4, 0x00, 0x00, 0x00, 0x00, 0xCA, 0x67, /* 0x30-0x33 */ - 0xA6, 0xF1, 0x00, 0x00, 0xA7, 0x44, 0x00, 0x00, /* 0x34-0x37 */ - 0xA6, 0xF9, 0x00, 0x00, 0xA6, 0xF8, 0xCA, 0x5B, /* 0x38-0x3B */ - 0xA6, 0xFC, 0xA6, 0xF7, 0xCA, 0x60, 0xCA, 0x68, /* 0x3C-0x3F */ - 0x00, 0x00, 0xCA, 0x64, 0x00, 0x00, 0xA6, 0xFA, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xA6, 0xFD, 0xA6, 0xEE, /* 0x44-0x47 */ - 0xA7, 0x47, 0xCA, 0x5D, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xCB, 0xBD, 0xA6, 0xEC, 0xA7, 0x43, 0xA6, 0xED, /* 0x4C-0x4F */ - 0xA6, 0xF5, 0xA6, 0xF6, 0xCA, 0x62, 0xCA, 0x5E, /* 0x50-0x53 */ - 0xA6, 0xFB, 0xA6, 0xF3, 0xCA, 0x5A, 0xA6, 0xEF, /* 0x54-0x57 */ - 0xCA, 0x65, 0xA7, 0x45, 0xA7, 0x48, 0xA6, 0xF2, /* 0x58-0x5B */ - 0xA7, 0x40, 0xA7, 0x46, 0xA6, 0xF0, 0xCA, 0x63, /* 0x5C-0x5F */ - 0xA7, 0x41, 0xCA, 0x69, 0xCA, 0x5C, 0xA6, 0xFE, /* 0x60-0x63 */ - 0xCA, 0x5F, 0x00, 0x00, 0x00, 0x00, 0xCA, 0x61, /* 0x64-0x67 */ - 0x00, 0x00, 0xA8, 0xD8, 0xCB, 0xBF, 0xCB, 0xCB, /* 0x68-0x6B */ - 0xA8, 0xD0, 0x00, 0x00, 0xCB, 0xCC, 0xA8, 0xCB, /* 0x6C-0x6F */ - 0xA8, 0xD5, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xCE, /* 0x70-0x73 */ - 0xCB, 0xB9, 0xA8, 0xD6, 0xCB, 0xB8, 0xCB, 0xBC, /* 0x74-0x77 */ - 0xCB, 0xC3, 0xCB, 0xC1, 0xA8, 0xDE, 0xA8, 0xD9, /* 0x78-0x7B */ - 0xCB, 0xB3, 0xCB, 0xB5, 0xA8, 0xDB, 0xA8, 0xCF, /* 0x7C-0x7F */ - - 0xCB, 0xB6, 0xCB, 0xC2, 0xCB, 0xC9, 0xA8, 0xD4, /* 0x80-0x83 */ - 0xCB, 0xBB, 0xCB, 0xB4, 0xA8, 0xD3, 0xCB, 0xB7, /* 0x84-0x87 */ - 0xA8, 0xD7, 0xCB, 0xBA, 0x00, 0x00, 0xA8, 0xD2, /* 0x88-0x8B */ - 0x00, 0x00, 0xA8, 0xCD, 0x00, 0x00, 0xA8, 0xDC, /* 0x8C-0x8F */ - 0xCB, 0xC4, 0xA8, 0xDD, 0xCB, 0xC8, 0x00, 0x00, /* 0x90-0x93 */ - 0xCB, 0xC6, 0xCB, 0xCA, 0xA8, 0xDA, 0xCB, 0xBE, /* 0x94-0x97 */ - 0xCB, 0xB2, 0x00, 0x00, 0xCB, 0xC0, 0xA8, 0xD1, /* 0x98-0x9B */ - 0xCB, 0xC5, 0xA8, 0xCC, 0xCB, 0xC7, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xAB, 0x56, 0xAB, 0x4A, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xCD, 0xE0, 0xCD, 0xE8, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xAB, 0x49, 0xAB, 0x51, 0xAB, 0x5D, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xCD, 0xEE, 0xCD, 0xEC, 0xCD, 0xE7, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x4B, /* 0xBC-0xBF */ - 0xCD, 0xED, 0xCD, 0xE3, 0xAB, 0x59, 0xAB, 0x50, /* 0xC0-0xC3 */ - 0xAB, 0x58, 0xCD, 0xDE, 0x00, 0x00, 0xCD, 0xEA, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xCD, 0xE1, 0xAB, 0x54, 0xCD, 0xE2, /* 0xC8-0xCB */ - 0x00, 0x00, 0xCD, 0xDD, 0xAB, 0x5B, 0xAB, 0x4E, /* 0xCC-0xCF */ - 0xAB, 0x57, 0xAB, 0x4D, 0x00, 0x00, 0xCD, 0xDF, /* 0xD0-0xD3 */ - 0xCD, 0xE4, 0x00, 0x00, 0xCD, 0xEB, 0xAB, 0x55, /* 0xD4-0xD7 */ - 0xAB, 0x52, 0xCD, 0xE6, 0xAB, 0x5A, 0xCD, 0xE9, /* 0xD8-0xDB */ - 0xCD, 0xE5, 0xAB, 0x4F, 0xAB, 0x5C, 0xAB, 0x53, /* 0xDC-0xDF */ - 0xAB, 0x4C, 0xAB, 0x48, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xCD, 0xEF, 0x00, 0x00, 0xAD, 0xD7, 0xAD, 0xC1, /* 0xEC-0xEF */ - 0x00, 0x00, 0xAD, 0xD1, 0x00, 0x00, 0xAD, 0xD6, /* 0xF0-0xF3 */ - 0xD0, 0xD0, 0xD0, 0xCF, 0xD0, 0xD4, 0xD0, 0xD5, /* 0xF4-0xF7 */ - 0xAD, 0xC4, 0x00, 0x00, 0xAD, 0xCD, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0xAD, 0xDA, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_50[512] = { - 0xAD, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xD0, 0xC9, 0xAD, 0xC7, 0xD0, 0xCA, /* 0x04-0x07 */ - 0x00, 0x00, 0xAD, 0xDC, 0x00, 0x00, 0xAD, 0xD3, /* 0x08-0x0B */ - 0xAD, 0xBE, 0xAD, 0xBF, 0xD0, 0xDD, 0xB0, 0xBF, /* 0x0C-0x0F */ - 0x00, 0x00, 0xAD, 0xCC, 0xAD, 0xCB, 0xD0, 0xCB, /* 0x10-0x13 */ - 0xAD, 0xCF, 0xD4, 0x5B, 0xAD, 0xC6, 0xD0, 0xD6, /* 0x14-0x17 */ - 0xAD, 0xD5, 0xAD, 0xD4, 0xAD, 0xCA, 0xD0, 0xCE, /* 0x18-0x1B */ - 0xD0, 0xD7, 0x00, 0x00, 0xD0, 0xC8, 0xAD, 0xC9, /* 0x1C-0x1F */ - 0xD0, 0xD8, 0xAD, 0xD2, 0xD0, 0xCC, 0xAD, 0xC0, /* 0x20-0x23 */ - 0x00, 0x00, 0xAD, 0xC3, 0xAD, 0xC2, 0xD0, 0xD9, /* 0x24-0x27 */ - 0xAD, 0xD0, 0xAD, 0xC5, 0xAD, 0xD9, 0xAD, 0xDB, /* 0x28-0x2B */ - 0xD0, 0xD3, 0xAD, 0xD8, 0x00, 0x00, 0xD0, 0xDB, /* 0x2C-0x2F */ - 0xD0, 0xCD, 0xD0, 0xDC, 0x00, 0x00, 0xD0, 0xD1, /* 0x30-0x33 */ - 0x00, 0x00, 0xD0, 0xDA, 0x00, 0x00, 0xD0, 0xD2, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xAD, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xD4, 0x63, 0xD4, 0x57, 0x00, 0x00, 0xB0, 0xB3, /* 0x40-0x43 */ - 0x00, 0x00, 0xD4, 0x5C, 0xD4, 0x62, 0xB0, 0xB2, /* 0x44-0x47 */ - 0xD4, 0x55, 0xB0, 0xB6, 0xD4, 0x59, 0xD4, 0x52, /* 0x48-0x4B */ - 0xB0, 0xB4, 0xD4, 0x56, 0xB0, 0xB9, 0xB0, 0xBE, /* 0x4C-0x4F */ - 0x00, 0x00, 0xD4, 0x67, 0x00, 0x00, 0xD4, 0x51, /* 0x50-0x53 */ - 0x00, 0x00, 0xB0, 0xBA, 0x00, 0x00, 0xD4, 0x66, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xB0, 0xB5, 0xD4, 0x58, /* 0x58-0x5B */ - 0xB0, 0xB1, 0xD4, 0x53, 0xD4, 0x4F, 0xD4, 0x5D, /* 0x5C-0x5F */ - 0xD4, 0x50, 0xD4, 0x4E, 0xD4, 0x5A, 0xD4, 0x60, /* 0x60-0x63 */ - 0xD4, 0x61, 0xB0, 0xB7, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xD8, 0x5B, 0xD4, 0x5E, 0xD4, 0x4D, 0xD4, 0x5F, /* 0x68-0x6B */ - 0x00, 0x00, 0xB0, 0xC1, 0xD4, 0x64, 0xB0, 0xC0, /* 0x6C-0x6F */ - 0xD4, 0x4C, 0x00, 0x00, 0xD4, 0x54, 0xD4, 0x65, /* 0x70-0x73 */ - 0xB0, 0xBC, 0xB0, 0xBB, 0xB0, 0xB8, 0xB0, 0xBD, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0xB0, 0xAF, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xB0, 0xB0, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xB3, 0xC8, 0x00, 0x00, 0xD8, 0x5E, 0xD8, 0x57, /* 0x80-0x83 */ - 0x00, 0x00, 0xB3, 0xC5, 0x00, 0x00, 0xD8, 0x5F, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x55, /* 0x88-0x8B */ - 0xD8, 0x58, 0xB3, 0xC4, 0xD8, 0x59, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xB3, 0xC7, 0xD8, 0x5D, 0x00, 0x00, /* 0x90-0x93 */ - 0xD8, 0x53, 0xD8, 0x52, 0xB3, 0xC9, 0x00, 0x00, /* 0x94-0x97 */ - 0xB3, 0xCA, 0xB3, 0xC6, 0xB3, 0xCB, 0xD8, 0x51, /* 0x98-0x9B */ - 0xD8, 0x5C, 0xD8, 0x5A, 0xD8, 0x54, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0xB3, 0xC3, 0xD8, 0x56, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xB6, 0xCA, 0xB6, 0xC4, 0xDC, 0xB7, 0xB6, 0xCD, /* 0xAC-0xAF */ - 0xDC, 0xBD, 0xDC, 0xC0, 0xB6, 0xC6, 0xB6, 0xC7, /* 0xB0-0xB3 */ - 0xDC, 0xBA, 0xB6, 0xC5, 0xDC, 0xC3, 0xB6, 0xCB, /* 0xB4-0xB7 */ - 0xDC, 0xC4, 0x00, 0x00, 0xDC, 0xBF, 0xB6, 0xCC, /* 0xB8-0xBB */ - 0x00, 0x00, 0xDC, 0xB4, 0xB6, 0xC9, 0xDC, 0xB5, /* 0xBC-0xBF */ - 0x00, 0x00, 0xDC, 0xBE, 0xDC, 0xBC, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xDC, 0xB8, 0xB6, 0xC8, 0xDC, 0xB6, 0xB6, 0xCE, /* 0xC4-0xC7 */ - 0xDC, 0xBB, 0xDC, 0xC2, 0xDC, 0xB9, 0xDC, 0xC1, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xB9, 0xB6, 0xB9, 0xB3, /* 0xCC-0xCF */ - 0x00, 0x00, 0xB9, 0xB4, 0x00, 0x00, 0xE0, 0xF9, /* 0xD0-0xD3 */ - 0xE0, 0xF1, 0xB9, 0xB2, 0xB9, 0xAF, 0xE0, 0xF2, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xB9, 0xB1, 0xE0, 0xF5, /* 0xD8-0xDB */ - 0x00, 0x00, 0xE0, 0xF7, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0xE0, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFD, /* 0xE0-0xE3 */ - 0xE0, 0xF8, 0xB9, 0xAE, 0xE0, 0xF0, 0xB9, 0xAC, /* 0xE4-0xE7 */ - 0xE0, 0xF3, 0xB9, 0xB7, 0xE0, 0xF6, 0x00, 0x00, /* 0xE8-0xEB */ - 0xE0, 0xFA, 0xB9, 0xB0, 0xB9, 0xAD, 0xE0, 0xFC, /* 0xEC-0xEF */ - 0xE0, 0xFB, 0xB9, 0xB5, 0x00, 0x00, 0xE0, 0xF4, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xBB, 0xF8, 0xE4, 0xEC, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xE4, 0xE9, 0xBB, 0xF9, 0x00, 0x00, 0xBB, 0xF7, /* 0xF8-0xFB */ - 0x00, 0x00, 0xE4, 0xF0, 0xE4, 0xED, 0xE4, 0xE6, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_51[512] = { - 0xBB, 0xF6, 0x00, 0x00, 0xBB, 0xFA, 0xE4, 0xE7, /* 0x00-0x03 */ - 0xBB, 0xF5, 0xBB, 0xFD, 0xE4, 0xEA, 0xE4, 0xEB, /* 0x04-0x07 */ - 0xBB, 0xFB, 0xBB, 0xFC, 0xE4, 0xF1, 0xE4, 0xEE, /* 0x08-0x0B */ - 0xE4, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xBE, 0xAA, 0xE8, 0xF8, 0xBE, 0xA7, 0xE8, 0xF5, /* 0x10-0x13 */ - 0xBE, 0xA9, 0xBE, 0xAB, 0x00, 0x00, 0xE8, 0xF6, /* 0x14-0x17 */ - 0xBE, 0xA8, 0x00, 0x00, 0xE8, 0xF7, 0x00, 0x00, /* 0x18-0x1B */ - 0xE8, 0xF4, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x76, /* 0x1C-0x1F */ - 0xEC, 0xBD, 0xC0, 0x77, 0xEC, 0xBB, 0x00, 0x00, /* 0x20-0x23 */ - 0xEC, 0xBC, 0xEC, 0xBA, 0xEC, 0xB9, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xEC, 0xBE, 0xC0, 0x75, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0xEF, 0xB8, 0xEF, 0xB9, 0x00, 0x00, /* 0x2C-0x2F */ - 0xE4, 0xE8, 0xEF, 0xB7, 0xC0, 0x78, 0xC3, 0x5F, /* 0x30-0x33 */ - 0xF1, 0xEB, 0xF1, 0xEC, 0x00, 0x00, 0xC4, 0xD7, /* 0x34-0x37 */ - 0xC4, 0xD8, 0xF5, 0xC1, 0xF5, 0xC0, 0xC5, 0x6C, /* 0x38-0x3B */ - 0xC5, 0x6B, 0xF7, 0xD0, 0x00, 0x00, 0xA4, 0x49, /* 0x3C-0x3F */ - 0xA4, 0x61, 0xA4, 0xB9, 0x00, 0x00, 0xA4, 0xB8, /* 0x40-0x43 */ - 0xA5, 0x53, 0xA5, 0x52, 0xA5, 0xFC, 0xA5, 0xFB, /* 0x44-0x47 */ - 0xA5, 0xFD, 0xA5, 0xFA, 0x00, 0x00, 0xA7, 0x4A, /* 0x48-0x4B */ - 0xA7, 0x49, 0xA7, 0x4B, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0xE0, 0x00, 0x00, /* 0x50-0x53 */ - 0xA8, 0xDF, 0xA8, 0xE1, 0x00, 0x00, 0xAB, 0x5E, /* 0x54-0x57 */ - 0x00, 0x00, 0xA2, 0x59, 0xD0, 0xDE, 0xA2, 0x5A, /* 0x58-0x5B */ - 0xB0, 0xC2, 0xA2, 0x5C, 0xA2, 0x5B, 0xD8, 0x60, /* 0x5C-0x5F */ - 0x00, 0x00, 0xA2, 0x5D, 0xB9, 0xB8, 0xA2, 0x5E, /* 0x60-0x63 */ - 0x00, 0x00, 0xA4, 0x4A, 0x00, 0x00, 0xA4, 0xBA, /* 0x64-0x67 */ - 0xA5, 0xFE, 0xA8, 0xE2, 0x00, 0x00, 0xA4, 0x4B, /* 0x68-0x6B */ - 0xA4, 0xBD, 0xA4, 0xBB, 0xA4, 0xBC, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0xA6, 0x40, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xA7, 0x4C, 0xA8, 0xE4, 0xA8, 0xE3, /* 0x74-0x77 */ - 0xA8, 0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xAD, 0xDD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xBE, 0xAC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC9, 0x4E, /* 0x84-0x87 */ - 0x00, 0x00, 0xA5, 0x54, 0xA5, 0x55, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0xA6, 0x41, 0x00, 0x00, 0xCA, 0x6A, /* 0x8C-0x8F */ - 0x00, 0x00, 0xAB, 0x60, 0xAB, 0x5F, 0xD0, 0xE0, /* 0x90-0x93 */ - 0xD0, 0xDF, 0xB0, 0xC3, 0x00, 0x00, 0xA4, 0xBE, /* 0x94-0x97 */ - 0xC9, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xCB, 0xCD, 0x00, 0x00, /* 0x9C-0x9F */ - 0xAB, 0x61, 0x00, 0x00, 0xAD, 0xE0, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xAD, 0xDE, 0xAD, 0xDF, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0xBE, 0xAD, 0x00, 0x00, /* 0xA8-0xAB */ - 0xA5, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0xA6, 0x42, 0xC9, 0xBC, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xA7, 0x4D, 0xA7, 0x4E, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xCA, 0x6B, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0xCB, 0xCE, 0xA8, 0xE6, 0xCB, 0xCF, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xD0, 0xE2, 0xD0, 0xE3, 0xAD, 0xE3, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xD0, 0xE4, 0x00, 0x00, 0xD0, 0xE1, 0xAD, 0xE4, /* 0xC8-0xCB */ - 0xAD, 0xE2, 0xAD, 0xE1, 0xD0, 0xE5, 0x00, 0x00, /* 0xCC-0xCF */ - 0xD4, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xD8, 0x61, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xC5, /* 0xD4-0xD7 */ - 0xE1, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xBB, 0xFE, 0xBE, 0xAE, 0xE8, 0xF9, 0x00, 0x00, /* 0xDC-0xDF */ - 0xA4, 0x4C, 0xA4, 0x5A, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xB0, 0xC4, 0xB3, 0xCD, 0x00, 0x00, 0xB9, 0xB9, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xC9, 0x42, 0xA4, 0xBF, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xA5, 0x59, 0xA5, 0x57, 0xA5, 0x58, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xA8, 0xE7, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_52[512] = { - 0xA4, 0x4D, 0xA4, 0x4E, 0x00, 0x00, 0xA4, 0x62, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xA4, 0xC0, 0xA4, 0xC1, /* 0x04-0x07 */ - 0xA4, 0xC2, 0xC9, 0xBE, 0xA5, 0x5A, 0x00, 0x00, /* 0x08-0x0B */ - 0xC9, 0x6B, 0x00, 0x00, 0xA6, 0x46, 0x00, 0x00, /* 0x0C-0x0F */ - 0xC9, 0xBF, 0xA6, 0x44, 0xA6, 0x45, 0xC9, 0xBD, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xA6, 0x47, 0xA6, 0x43, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xCA, 0x6C, 0xAA, 0xEC, 0xCA, 0x6D, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xCA, 0x6E, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0xA7, 0x50, 0xA7, 0x4F, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xA7, 0x53, 0xA7, 0x51, 0xA7, 0x52, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0xED, 0x00, 0x00, /* 0x2C-0x2F */ - 0xA8, 0xEC, 0xCB, 0xD4, 0xCB, 0xD1, 0xCB, 0xD2, /* 0x30-0x33 */ - 0x00, 0x00, 0xCB, 0xD0, 0xA8, 0xEE, 0xA8, 0xEA, /* 0x34-0x37 */ - 0xA8, 0xE9, 0x00, 0x00, 0xA8, 0xEB, 0xA8, 0xE8, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xA8, 0xEF, 0x00, 0x00, 0xAB, 0x63, /* 0x40-0x43 */ - 0xCD, 0xF0, 0x00, 0x00, 0xCB, 0xD3, 0xAB, 0x68, /* 0x44-0x47 */ - 0x00, 0x00, 0xCD, 0xF1, 0xAB, 0x64, 0xAB, 0x67, /* 0x48-0x4B */ - 0xAB, 0x66, 0xAB, 0x65, 0xAB, 0x62, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0xE8, 0x00, 0x00, /* 0x50-0x53 */ - 0xAD, 0xE7, 0xD0, 0xEB, 0xAD, 0xE5, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0xE7, 0xAD, 0xE8, /* 0x58-0x5B */ - 0xAD, 0xE6, 0xAD, 0xE9, 0xD0, 0xE9, 0xD0, 0xEA, /* 0x5C-0x5F */ - 0x00, 0x00, 0xD0, 0xE6, 0xD0, 0xEC, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xB3, 0xD1, 0xB0, 0xC5, 0xD4, 0x69, /* 0x68-0x6B */ - 0xD4, 0x6B, 0xD4, 0x6A, 0xD4, 0x6C, 0xB0, 0xC6, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xB3, 0xCE, 0x00, 0x00, /* 0x70-0x73 */ - 0xB3, 0xCF, 0xB3, 0xD0, 0x00, 0x00, 0xB6, 0xD0, /* 0x74-0x77 */ - 0xDC, 0xC7, 0x00, 0x00, 0xDC, 0xC6, 0xDC, 0xC8, /* 0x78-0x7B */ - 0xDC, 0xC9, 0xB6, 0xD1, 0x00, 0x00, 0xB6, 0xCF, /* 0x7C-0x7F */ - - 0xE1, 0x41, 0xE1, 0x42, 0xB9, 0xBB, 0xB9, 0xBA, /* 0x80-0x83 */ - 0xE3, 0x5A, 0x00, 0x00, 0x00, 0x00, 0xBC, 0x40, /* 0x84-0x87 */ - 0xBC, 0x41, 0xBC, 0x42, 0xBC, 0x44, 0xE4, 0xF2, /* 0x88-0x8B */ - 0xE4, 0xF3, 0xBC, 0x43, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xBE, 0xAF, 0x00, 0x00, 0xBE, 0xB0, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xED, 0xF5, 0xC3, /* 0x94-0x97 */ - 0xF5, 0xC2, 0xF7, 0xD1, 0x00, 0x00, 0xA4, 0x4F, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA5, 0x5C, /* 0x9C-0x9F */ - 0xA5, 0x5B, 0x00, 0x00, 0x00, 0x00, 0xA6, 0x48, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0xC9, 0xC0, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xA7, 0x55, 0xA7, 0x56, 0xA7, 0x54, /* 0xA8-0xAB */ - 0xA7, 0x57, 0xCA, 0x6F, 0xCA, 0x70, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xF1, /* 0xB8-0xBB */ - 0xCB, 0xD5, 0x00, 0x00, 0xA8, 0xF0, 0x00, 0x00, /* 0xBC-0xBF */ - 0xCD, 0xF2, 0xAB, 0x6C, 0xCD, 0xF3, 0xAB, 0x6B, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x69, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xAB, 0x6A, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0xD0, 0xED, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xB0, 0xC7, 0xD4, 0x6E, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xB0, 0xCA, 0xD4, 0x6D, 0xB1, 0xE5, /* 0xD4-0xD7 */ - 0xB0, 0xC9, 0xB0, 0xC8, 0x00, 0x00, 0xB3, 0xD4, /* 0xD8-0xDB */ - 0x00, 0x00, 0xB3, 0xD3, 0xB3, 0xD2, 0xB6, 0xD2, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xB6, 0xD5, 0xB6, 0xD6, /* 0xE0-0xE3 */ - 0xB6, 0xD4, 0x00, 0x00, 0xB6, 0xD3, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xE1, 0x43, 0x00, 0x00, 0xE1, 0x44, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xF5, /* 0xEC-0xEF */ - 0xBC, 0x45, 0xE4, 0xF4, 0x00, 0x00, 0xBE, 0xB1, /* 0xF0-0xF3 */ - 0xEC, 0xBF, 0xC0, 0x79, 0x00, 0x00, 0xF1, 0xEE, /* 0xF4-0xF7 */ - 0xC4, 0x55, 0x00, 0x00, 0xA4, 0x63, 0xA4, 0xC3, /* 0xF8-0xFB */ - 0xC9, 0x56, 0x00, 0x00, 0xA4, 0xC4, 0xA4, 0xC5, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_53[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xA5, 0x5D, 0xA5, 0x5E, 0x00, 0x00, /* 0x04-0x07 */ - 0xA6, 0x49, 0xCA, 0x71, 0xCB, 0xD6, 0xCB, 0xD7, /* 0x08-0x0B */ - 0x00, 0x00, 0xAB, 0x6D, 0xD0, 0xEE, 0xB0, 0xCC, /* 0x0C-0x0F */ - 0xB0, 0xCB, 0xD8, 0x63, 0xD8, 0x62, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xA4, 0x50, 0xA4, 0xC6, 0xA5, 0x5F, /* 0x14-0x17 */ - 0x00, 0x00, 0xB0, 0xCD, 0xC9, 0x43, 0x00, 0x00, /* 0x18-0x1B */ - 0xC9, 0x6C, 0xA5, 0x60, 0x00, 0x00, 0xC9, 0xC2, /* 0x1C-0x1F */ - 0xA6, 0x4B, 0xA6, 0x4A, 0xC9, 0xC1, 0xA7, 0x58, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xAD, 0xEA, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0xD4, 0x6F, 0x00, 0x00, 0xB6, 0xD7, /* 0x2C-0x2F */ - 0xE1, 0x45, 0xB9, 0xBC, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xE8, 0xFA, 0x00, 0x00, 0x00, 0x00, 0xF3, 0xFD, /* 0x34-0x37 */ - 0x00, 0x00, 0xA4, 0xC7, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xCB, 0xD8, 0xCD, 0xF4, 0xB0, 0xD0, 0xB0, 0xCE, /* 0x3C-0x3F */ - 0xB0, 0xCF, 0xA4, 0x51, 0x00, 0x00, 0xA4, 0x64, /* 0x40-0x43 */ - 0xA2, 0xCD, 0xA4, 0xCA, 0x00, 0x00, 0xA4, 0xC9, /* 0x44-0x47 */ - 0xA4, 0xC8, 0xA5, 0x63, 0xA5, 0x62, 0x00, 0x00, /* 0x48-0x4B */ - 0xC9, 0x6D, 0xC9, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0xA8, 0xF5, 0xA8, 0xF2, 0xA8, 0xF4, /* 0x50-0x53 */ - 0xA8, 0xF3, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x6E, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xB3, 0xD5, 0x00, 0x00, /* 0x58-0x5B */ - 0xA4, 0x52, 0x00, 0x00, 0xA4, 0xCB, 0x00, 0x00, /* 0x5C-0x5F */ - 0xA5, 0x65, 0xA5, 0x64, 0x00, 0x00, 0xCA, 0x72, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0xF6, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0xC9, 0x57, 0x00, 0x00, 0xA5, 0x67, 0xA5, 0x66, /* 0x6C-0x6F */ - 0xA6, 0x4C, 0xA6, 0x4D, 0xCA, 0x73, 0xA7, 0x59, /* 0x70-0x73 */ - 0x00, 0x00, 0xA7, 0x5A, 0x00, 0x00, 0xA8, 0xF7, /* 0x74-0x77 */ - 0xA8, 0xF8, 0xA8, 0xF9, 0x00, 0x00, 0xAB, 0x6F, /* 0x78-0x7B */ - 0xCD, 0xF5, 0x00, 0x00, 0x00, 0x00, 0xAD, 0xEB, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xC9, 0x44, 0x00, 0x00, /* 0x80-0x83 */ - 0xA4, 0xCC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xC9, 0xC4, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0x74, 0xCA, 0x75, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xCB, 0xD9, 0x00, 0x00, /* 0x90-0x93 */ - 0xCB, 0xDA, 0x00, 0x00, 0xCD, 0xF7, 0xCD, 0xF6, /* 0x94-0x97 */ - 0xCD, 0xF9, 0xCD, 0xF8, 0xAB, 0x70, 0x00, 0x00, /* 0x98-0x9B */ - 0xD4, 0x70, 0xAD, 0xED, 0xD0, 0xEF, 0xAD, 0xEC, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xD8, 0x64, 0xB3, 0xD6, 0x00, 0x00, 0xD8, 0x65, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xE1, 0x46, 0xB9, 0xBD, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xBC, 0x46, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xF1, 0xEF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xC9, 0x58, 0x00, 0x00, 0xA5, 0x68, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB0, 0xD1, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xA4, 0x53, 0xA4, 0x65, 0xA4, 0xCE, 0xA4, 0xCD, /* 0xC8-0xCB */ - 0x00, 0x00, 0xA4, 0xCF, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xA8, 0xFB, 0x00, 0x00, 0xA8, 0xFA, 0xA8, 0xFC, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0x71, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAD, 0xEE, /* 0xDC-0xDF */ - 0x00, 0x00, 0xE8, 0xFB, 0xC2, 0x4F, 0xA4, 0x66, /* 0xE0-0xE3 */ - 0xA5, 0x6A, 0xA5, 0x79, 0xA5, 0x74, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xA5, 0x6F, 0xA5, 0x6E, 0xA5, 0x75, 0xA5, 0x73, /* 0xE8-0xEB */ - 0xA5, 0x6C, 0xA5, 0x7A, 0xA5, 0x6D, 0xA5, 0x69, /* 0xEC-0xEF */ - 0xA5, 0x78, 0xA5, 0x77, 0xA5, 0x76, 0xA5, 0x6B, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xA5, 0x72, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xA5, 0x71, 0x00, 0x00, 0x00, 0x00, 0xA5, 0x7B, /* 0xF8-0xFB */ - 0xA5, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_54[512] = { - 0x00, 0x00, 0xA6, 0x53, 0x00, 0x00, 0xA6, 0x59, /* 0x00-0x03 */ - 0xA6, 0x55, 0x00, 0x00, 0xA6, 0x5B, 0xC9, 0xC5, /* 0x04-0x07 */ - 0xA6, 0x58, 0xA6, 0x4E, 0xA6, 0x51, 0xA6, 0x54, /* 0x08-0x0B */ - 0xA6, 0x50, 0xA6, 0x57, 0xA6, 0x5A, 0xA6, 0x4F, /* 0x0C-0x0F */ - 0xA6, 0x52, 0xA6, 0x56, 0xA6, 0x5C, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xCA, 0x7E, 0xCA, 0x7B, 0x00, 0x00, 0xA7, 0x67, /* 0x18-0x1B */ - 0xCA, 0x7C, 0xA7, 0x5B, 0xA7, 0x5D, 0xA7, 0x75, /* 0x1C-0x1F */ - 0xA7, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0xCA, 0xA5, 0xCA, 0x7D, 0xA7, 0x5F, 0xA7, 0x61, /* 0x24-0x27 */ - 0xCA, 0xA4, 0xA7, 0x68, 0xCA, 0x78, 0xA7, 0x74, /* 0x28-0x2B */ - 0xA7, 0x76, 0xA7, 0x5C, 0xA7, 0x6D, 0x00, 0x00, /* 0x2C-0x2F */ - 0xCA, 0x76, 0xA7, 0x73, 0x00, 0x00, 0xA7, 0x64, /* 0x30-0x33 */ - 0x00, 0x00, 0xA7, 0x6E, 0xA7, 0x6F, 0xCA, 0x77, /* 0x34-0x37 */ - 0xA7, 0x6C, 0xA7, 0x6A, 0x00, 0x00, 0xA7, 0x6B, /* 0x38-0x3B */ - 0xA7, 0x71, 0xCA, 0xA1, 0xA7, 0x5E, 0x00, 0x00, /* 0x3C-0x3F */ - 0xA7, 0x72, 0xCA, 0xA3, 0xA7, 0x66, 0xA7, 0x63, /* 0x40-0x43 */ - 0x00, 0x00, 0xCA, 0x7A, 0xA7, 0x62, 0xCA, 0xA6, /* 0x44-0x47 */ - 0xA7, 0x65, 0x00, 0x00, 0xA7, 0x69, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xA7, 0x60, 0xCA, 0xA2, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xCA, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xCB, 0xEB, 0xCB, 0xEA, 0xA9, 0x4F, 0xCB, 0xED, /* 0x60-0x63 */ - 0xCB, 0xEF, 0xCB, 0xE4, 0xCB, 0xE7, 0xCB, 0xEE, /* 0x64-0x67 */ - 0xA9, 0x50, 0x00, 0x00, 0x00, 0x00, 0xCB, 0xE1, /* 0x68-0x6B */ - 0xCB, 0xE5, 0x00, 0x00, 0x00, 0x00, 0xCB, 0xE9, /* 0x6C-0x6F */ - 0xCE, 0x49, 0xA9, 0x4B, 0xCE, 0x4D, 0xA8, 0xFD, /* 0x70-0x73 */ - 0xCB, 0xE6, 0xA8, 0xFE, 0xA9, 0x4C, 0xA9, 0x45, /* 0x74-0x77 */ - 0xA9, 0x41, 0x00, 0x00, 0xCB, 0xE2, 0xA9, 0x44, /* 0x78-0x7B */ - 0xA9, 0x49, 0xA9, 0x52, 0xCB, 0xE3, 0xCB, 0xDC, /* 0x7C-0x7F */ - - 0xA9, 0x43, 0xCB, 0xDD, 0xCB, 0xDF, 0x00, 0x00, /* 0x80-0x83 */ - 0xA9, 0x46, 0x00, 0x00, 0xA9, 0x48, 0xCB, 0xDB, /* 0x84-0x87 */ - 0xCB, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xA9, 0x51, /* 0x88-0x8B */ - 0xA9, 0x4D, 0xCB, 0xE8, 0xA9, 0x53, 0x00, 0x00, /* 0x8C-0x8F */ - 0xA9, 0x4A, 0xCB, 0xDE, 0xA9, 0x47, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0xA9, 0x42, 0xA9, 0x40, 0x00, 0x00, /* 0x94-0x97 */ - 0xCB, 0xEC, 0x00, 0x00, 0xA9, 0x4E, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xCE, 0x48, 0xCD, 0xFB, 0xCE, 0x4B, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xCD, 0xFD, 0xAB, 0x78, 0xAB, 0xA8, /* 0xA4-0xA7 */ - 0xAB, 0x74, 0xAB, 0xA7, 0xAB, 0x7D, 0xAB, 0xA4, /* 0xA8-0xAB */ - 0xAB, 0x72, 0xCD, 0xFC, 0xCE, 0x43, 0xAB, 0xA3, /* 0xAC-0xAF */ - 0xCE, 0x4F, 0xAB, 0xA5, 0x00, 0x00, 0xAB, 0x79, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0x45, 0xCE, 0x42, /* 0xB4-0xB7 */ - 0xAB, 0x77, 0x00, 0x00, 0xCD, 0xFA, 0xAB, 0xA6, /* 0xB8-0xBB */ - 0xCE, 0x4A, 0xAB, 0x7C, 0xCE, 0x4C, 0xAB, 0xA9, /* 0xBC-0xBF */ - 0xAB, 0x73, 0xAB, 0x7E, 0xAB, 0x7B, 0xCE, 0x40, /* 0xC0-0xC3 */ - 0xAB, 0xA1, 0xCE, 0x46, 0xCE, 0x47, 0xAB, 0x7A, /* 0xC4-0xC7 */ - 0xAB, 0xA2, 0xAB, 0x76, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xAB, 0x75, 0xCD, 0xFE, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0x44, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0x4E, 0x00, 0x00, /* 0xDC-0xDF */ - 0xD1, 0x44, 0xAD, 0xFB, 0xD0, 0xF1, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xD0, 0xF6, 0xAD, 0xF4, 0xAE, 0x40, 0xD0, 0xF4, /* 0xE4-0xE7 */ - 0xAD, 0xEF, 0xAD, 0xF9, 0xAD, 0xFE, 0xD0, 0xFB, /* 0xE8-0xEB */ - 0x00, 0x00, 0xAD, 0xFA, 0xAD, 0xFD, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0xD0, 0xFE, 0xAD, 0xF5, 0xD0, 0xF5, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0x42, /* 0xF4-0xF7 */ - 0xD1, 0x43, 0x00, 0x00, 0xAD, 0xF7, 0xD1, 0x41, /* 0xF8-0xFB */ - 0xAD, 0xF3, 0xAE, 0x43, 0x00, 0x00, 0xD0, 0xF8, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_55[512] = { - 0x00, 0x00, 0xAD, 0xF1, 0x00, 0x00, 0xD1, 0x46, /* 0x00-0x03 */ - 0xD0, 0xF9, 0xD0, 0xFD, 0xAD, 0xF6, 0xAE, 0x42, /* 0x04-0x07 */ - 0xD0, 0xFA, 0xAD, 0xFC, 0xD1, 0x40, 0xD1, 0x47, /* 0x08-0x0B */ - 0xD4, 0xA1, 0x00, 0x00, 0xD1, 0x45, 0xAE, 0x44, /* 0x0C-0x0F */ - 0xAD, 0xF0, 0xD0, 0xFC, 0xD0, 0xF3, 0x00, 0x00, /* 0x10-0x13 */ - 0xAD, 0xF8, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xF2, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0xF7, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0xF0, 0xAE, 0x41, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xD4, 0x77, 0x00, 0x00, /* 0x28-0x2B */ - 0xB0, 0xE4, 0xD4, 0xA7, 0xB0, 0xE2, 0xB0, 0xDF, /* 0x2C-0x2F */ - 0xD4, 0x7C, 0xB0, 0xDB, 0xD4, 0xA2, 0xB0, 0xE6, /* 0x30-0x33 */ - 0xD4, 0x76, 0xD4, 0x7B, 0xD4, 0x7A, 0xAD, 0xF2, /* 0x34-0x37 */ - 0xB0, 0xE1, 0xD4, 0xA5, 0x00, 0x00, 0xD4, 0xA8, /* 0x38-0x3B */ - 0xD4, 0x73, 0x00, 0x00, 0xB3, 0xE8, 0x00, 0x00, /* 0x3C-0x3F */ - 0xD4, 0xA9, 0xB0, 0xE7, 0x00, 0x00, 0xB0, 0xD9, /* 0x40-0x43 */ - 0xB0, 0xD6, 0xD4, 0x7E, 0xB0, 0xD3, 0x00, 0x00, /* 0x44-0x47 */ - 0xD4, 0xA6, 0x00, 0x00, 0xB0, 0xDA, 0xD4, 0xAA, /* 0x48-0x4B */ - 0x00, 0x00, 0xD4, 0x74, 0xD4, 0xA4, 0xB0, 0xDD, /* 0x4C-0x4F */ - 0xD4, 0x75, 0xD4, 0x78, 0xD4, 0x7D, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xB0, 0xDE, 0xB0, 0xDC, 0xB0, 0xE8, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0xB0, 0xE3, 0x00, 0x00, 0xB0, 0xD7, 0xB1, 0xD2, /* 0x5C-0x5F */ - 0x00, 0x00, 0xB0, 0xD8, 0xD4, 0x79, 0xB0, 0xE5, /* 0x60-0x63 */ - 0xB0, 0xE0, 0xD4, 0xA3, 0xB0, 0xD5, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xB0, 0xD4, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xD4, 0x71, 0xD4, 0x72, 0xD8, 0x6A, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB3, 0xD7, /* 0x78-0x7B */ - 0xB3, 0xDA, 0xD8, 0x75, 0xB3, 0xEE, 0xD8, 0x78, /* 0x7C-0x7F */ - - 0xB3, 0xD8, 0xD8, 0x71, 0xB3, 0xDE, 0xB3, 0xE4, /* 0x80-0x83 */ - 0xB5, 0xBD, 0x00, 0x00, 0x00, 0x00, 0xB3, 0xE2, /* 0x84-0x87 */ - 0xD8, 0x6E, 0xB3, 0xEF, 0xB3, 0xDB, 0xB3, 0xE3, /* 0x88-0x8B */ - 0xD8, 0x76, 0xDC, 0xD7, 0xD8, 0x7B, 0xD8, 0x6F, /* 0x8C-0x8F */ - 0x00, 0x00, 0xD8, 0x66, 0xD8, 0x73, 0xD8, 0x6D, /* 0x90-0x93 */ - 0xB3, 0xE1, 0xD8, 0x79, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xB3, 0xDD, 0xB3, 0xF1, 0xB3, 0xEA, 0x00, 0x00, /* 0x98-0x9B */ - 0xB3, 0xDF, 0xB3, 0xDC, 0x00, 0x00, 0xB3, 0xE7, /* 0x9C-0x9F */ - 0x00, 0x00, 0xD8, 0x7A, 0xD8, 0x6C, 0xD8, 0x72, /* 0xA0-0xA3 */ - 0xD8, 0x74, 0xD8, 0x68, 0xD8, 0x77, 0xB3, 0xD9, /* 0xA4-0xA7 */ - 0xD8, 0x67, 0x00, 0x00, 0xB3, 0xE0, 0xB3, 0xF0, /* 0xA8-0xAB */ - 0xB3, 0xEC, 0xD8, 0x69, 0xB3, 0xE6, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xB3, 0xED, 0xB3, 0xE9, 0xB3, 0xE5, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xD8, 0x70, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB3, 0xEB, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xD5, /* 0xBC-0xBF */ - 0xDC, 0xD1, 0x00, 0x00, 0xDC, 0xE0, 0xDC, 0xCA, /* 0xC0-0xC3 */ - 0xDC, 0xD3, 0xB6, 0xE5, 0xB6, 0xE6, 0xB6, 0xDE, /* 0xC4-0xC7 */ - 0xDC, 0xDC, 0xB6, 0xE8, 0xDC, 0xCF, 0xDC, 0xCE, /* 0xC8-0xCB */ - 0xDC, 0xCC, 0xDC, 0xDE, 0xB6, 0xDC, 0xDC, 0xD8, /* 0xCC-0xCF */ - 0xDC, 0xCD, 0xB6, 0xDF, 0xDC, 0xD6, 0xB6, 0xDA, /* 0xD0-0xD3 */ - 0xDC, 0xD2, 0xDC, 0xD9, 0xDC, 0xDB, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xDC, 0xDF, 0xB6, 0xE3, 0xDC, 0xCB, /* 0xD8-0xDB */ - 0xB6, 0xDD, 0xDC, 0xD0, 0x00, 0x00, 0xB6, 0xD8, /* 0xDC-0xDF */ - 0x00, 0x00, 0xB6, 0xE4, 0xDC, 0xDA, 0xB6, 0xE0, /* 0xE0-0xE3 */ - 0xB6, 0xE1, 0xB6, 0xE7, 0xB6, 0xDB, 0xA2, 0x5F, /* 0xE4-0xE7 */ - 0xB6, 0xD9, 0xDC, 0xD4, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB6, 0xE2, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0xDC, 0xDD, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xB9, 0xCD, 0xB9, 0xC8, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xE1, 0x55, 0xE1, 0x51, 0x00, 0x00, /* 0xF8-0xFB */ - 0xE1, 0x4B, 0xB9, 0xC2, 0xB9, 0xBE, 0xE1, 0x54, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_56[512] = { - 0xB9, 0xBF, 0xE1, 0x4E, 0xE1, 0x50, 0x00, 0x00, /* 0x00-0x03 */ - 0xE1, 0x53, 0x00, 0x00, 0xB9, 0xC4, 0x00, 0x00, /* 0x04-0x07 */ - 0xB9, 0xCB, 0xB9, 0xC5, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0xE1, 0x49, 0xB9, 0xC6, 0xB9, 0xC7, 0xE1, 0x4C, /* 0x0C-0x0F */ - 0xB9, 0xCC, 0x00, 0x00, 0xE1, 0x4A, 0xE1, 0x4F, /* 0x10-0x13 */ - 0xB9, 0xC3, 0xE1, 0x48, 0xB9, 0xC9, 0xB9, 0xC1, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB9, 0xC0, /* 0x18-0x1B */ - 0xE1, 0x4D, 0xE1, 0x52, 0x00, 0x00, 0xB9, 0xCA, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0x47, /* 0x24-0x27 */ - 0x00, 0x00, 0xBC, 0x4D, 0xE5, 0x47, 0x00, 0x00, /* 0x28-0x2B */ - 0xE5, 0x44, 0x00, 0x00, 0xBC, 0x47, 0xBC, 0x53, /* 0x2C-0x2F */ - 0xBC, 0x54, 0x00, 0x00, 0xBC, 0x4A, 0xE5, 0x42, /* 0x30-0x33 */ - 0xBC, 0x4C, 0xE4, 0xF9, 0xBC, 0x52, 0x00, 0x00, /* 0x34-0x37 */ - 0xE5, 0x46, 0xBC, 0x49, 0xE5, 0x48, 0xBC, 0x48, /* 0x38-0x3B */ - 0x00, 0x00, 0xE5, 0x43, 0xE5, 0x45, 0xBC, 0x4B, /* 0x3C-0x3F */ - 0xE5, 0x41, 0xE4, 0xFA, 0xE4, 0xF7, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0xD8, 0x6B, 0xE4, 0xFD, 0x00, 0x00, /* 0x44-0x47 */ - 0xE4, 0xF6, 0xE4, 0xFC, 0xE4, 0xFB, 0x00, 0x00, /* 0x48-0x4B */ - 0xE4, 0xF8, 0x00, 0x00, 0xBC, 0x4F, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0x4E, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0x50, /* 0x54-0x57 */ - 0xE4, 0xFE, 0xBE, 0xB2, 0xE5, 0x40, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0x45, 0x00, 0x00, /* 0x5C-0x5F */ - 0xE8, 0xFD, 0x00, 0x00, 0xBE, 0xBE, 0xE9, 0x42, /* 0x60-0x63 */ - 0xBE, 0xB6, 0xBE, 0xBA, 0xE9, 0x41, 0x00, 0x00, /* 0x64-0x67 */ - 0xBE, 0xB9, 0xBE, 0xB5, 0xBE, 0xB8, 0xBE, 0xB3, /* 0x68-0x6B */ - 0xBE, 0xBD, 0xE9, 0x43, 0xE8, 0xFE, 0xBE, 0xBC, /* 0x6C-0x6F */ - 0xE8, 0xFC, 0xBE, 0xBB, 0xE9, 0x44, 0xE9, 0x40, /* 0x70-0x73 */ - 0xBC, 0x51, 0x00, 0x00, 0xBE, 0xBF, 0xE9, 0x46, /* 0x74-0x77 */ - 0xBE, 0xB7, 0xBE, 0xB4, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xEC, 0xC6, 0xEC, 0xC8, /* 0x7C-0x7F */ - - 0xC0, 0x7B, 0xEC, 0xC9, 0xEC, 0xC7, 0xEC, 0xC5, /* 0x80-0x83 */ - 0xEC, 0xC4, 0xC0, 0x7D, 0xEC, 0xC3, 0xC0, 0x7E, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0xEC, 0xC1, 0xEC, 0xC2, 0xC0, 0x7A, 0xC0, 0xA1, /* 0x8C-0x8F */ - 0xC0, 0x7C, 0x00, 0x00, 0x00, 0x00, 0xEC, 0xC0, /* 0x90-0x93 */ - 0x00, 0x00, 0xC2, 0x50, 0x00, 0x00, 0xEF, 0xBC, /* 0x94-0x97 */ - 0xEF, 0xBA, 0xEF, 0xBF, 0xEF, 0xBD, 0x00, 0x00, /* 0x98-0x9B */ - 0xEF, 0xBB, 0xEF, 0xBE, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xC3, 0x60, 0xF1, 0xF2, 0xF1, 0xF3, /* 0xA4-0xA7 */ - 0xC4, 0x56, 0x00, 0x00, 0xF1, 0xF4, 0xF1, 0xF0, /* 0xA8-0xAB */ - 0xF1, 0xF5, 0xF1, 0xF1, 0xC2, 0x51, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xF3, 0xFE, 0xF4, 0x41, /* 0xB0-0xB3 */ - 0xC4, 0x59, 0xF4, 0x40, 0xC4, 0x58, 0xC4, 0x57, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0xC4, 0x5A, 0xF5, 0xC5, 0xF5, 0xC6, 0x00, 0x00, /* 0xBC-0xBF */ - 0xC4, 0xDA, 0xC4, 0xD9, 0xC4, 0xDB, 0xF5, 0xC4, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xF6, 0xD8, 0xF6, 0xD7, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xC5, 0x6D, 0xC5, 0x6F, 0xC5, 0x6E, 0xF6, 0xD9, /* 0xC8-0xCB */ - 0xC5, 0xC8, 0xF8, 0xA6, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xC5, 0xF1, 0x00, 0x00, 0xF8, 0xA5, /* 0xD0-0xD3 */ - 0xF8, 0xEE, 0x00, 0x00, 0x00, 0x00, 0xC9, 0x49, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xA5, 0x7D, 0xA5, 0x7C, /* 0xD8-0xDB */ - 0x00, 0x00, 0xA6, 0x5F, 0xA6, 0x5E, 0xC9, 0xC7, /* 0xDC-0xDF */ - 0xA6, 0x5D, 0xC9, 0xC6, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xA7, 0x79, 0xCA, 0xA9, 0x00, 0x00, 0xCA, 0xA8, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0xA7, 0x77, 0xA7, 0x7A, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xA7, 0x00, 0x00, /* 0xEC-0xEF */ - 0xA7, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCB, 0xF0, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xCB, 0xF1, 0xA9, 0x54, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0xAA, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_57[512] = { - 0x00, 0x00, 0xD1, 0x48, 0xD1, 0x49, 0xAE, 0x45, /* 0x00-0x03 */ - 0xAE, 0x46, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xAC, /* 0x04-0x07 */ - 0xB0, 0xE9, 0xB0, 0xEB, 0xD4, 0xAB, 0xB0, 0xEA, /* 0x08-0x0B */ - 0xD8, 0x7C, 0xB3, 0xF2, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xB6, 0xE9, 0xB6, 0xEA, /* 0x10-0x13 */ - 0xDC, 0xE1, 0x00, 0x00, 0xB9, 0xCF, 0x00, 0x00, /* 0x14-0x17 */ - 0xB9, 0xCE, 0x00, 0x00, 0xE5, 0x49, 0xE9, 0x48, /* 0x18-0x1B */ - 0xE9, 0x47, 0x00, 0x00, 0xF9, 0x6B, 0xA4, 0x67, /* 0x1C-0x1F */ - 0xC9, 0x59, 0x00, 0x00, 0xC9, 0x6E, 0xC9, 0x6F, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xA6, 0x62, 0xA6, 0x66, 0xC9, 0xC9, 0x00, 0x00, /* 0x28-0x2B */ - 0xA6, 0x64, 0xA6, 0x63, 0xC9, 0xC8, 0xA6, 0x65, /* 0x2C-0x2F */ - 0xA6, 0x61, 0x00, 0x00, 0x00, 0x00, 0xA6, 0x60, /* 0x30-0x33 */ - 0xC9, 0xCA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA7, 0xA6, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xA7, 0xA3, 0x00, 0x00, /* 0x3C-0x3F */ - 0xA7, 0x7D, 0xCA, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0xCA, 0xAB, 0x00, 0x00, 0xA7, 0xA1, /* 0x44-0x47 */ - 0x00, 0x00, 0xCA, 0xAD, 0xA7, 0x7B, 0xCA, 0xAE, /* 0x48-0x4B */ - 0xCA, 0xAC, 0xA7, 0x7E, 0xA7, 0xA2, 0xA7, 0xA5, /* 0x4C-0x4F */ - 0xA7, 0xA4, 0xA7, 0x7C, 0xCA, 0xAF, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0xA9, 0x59, 0xCB, 0xFE, 0x00, 0x00, /* 0x60-0x63 */ - 0xA9, 0x5B, 0x00, 0x00, 0xA9, 0x5A, 0x00, 0x00, /* 0x64-0x67 */ - 0xCC, 0x40, 0xA9, 0x58, 0xA9, 0x57, 0xCB, 0xF5, /* 0x68-0x6B */ - 0x00, 0x00, 0xCB, 0xF4, 0x00, 0x00, 0xCB, 0xF2, /* 0x6C-0x6F */ - 0xCB, 0xF7, 0xCB, 0xF6, 0xCB, 0xF3, 0xCB, 0xFC, /* 0x70-0x73 */ - 0xCB, 0xFD, 0xCB, 0xFA, 0xCB, 0xF8, 0xA9, 0x56, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCB, 0xFB, /* 0x78-0x7B */ - 0xA9, 0x5C, 0xCC, 0x41, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xCB, 0xF9, 0x00, 0x00, 0xAB, 0xAB, 0xA9, 0x55, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0xAC, /* 0x88-0x8B */ - 0xCE, 0x54, 0x00, 0x00, 0x00, 0x00, 0xCE, 0x5A, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0xB2, /* 0x90-0x93 */ - 0xCE, 0x58, 0xCE, 0x5E, 0x00, 0x00, 0xCE, 0x55, /* 0x94-0x97 */ - 0xCE, 0x59, 0xCE, 0x5B, 0xCE, 0x5D, 0xCE, 0x57, /* 0x98-0x9B */ - 0x00, 0x00, 0xCE, 0x56, 0xCE, 0x51, 0xCE, 0x52, /* 0x9C-0x9F */ - 0xAB, 0xAD, 0x00, 0x00, 0xAB, 0xAF, 0xAB, 0xAE, /* 0xA0-0xA3 */ - 0xCE, 0x53, 0xCE, 0x5C, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xAB, 0xB1, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xCE, 0x50, 0xD1, 0x53, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xD1, 0x52, 0xD1, 0x57, 0xD1, 0x4E, 0x00, 0x00, /* 0xB8-0xBB */ - 0xD1, 0x51, 0xD1, 0x50, 0x00, 0x00, 0xD1, 0x54, /* 0xBC-0xBF */ - 0x00, 0x00, 0xD1, 0x58, 0xAE, 0x47, 0xAE, 0x4A, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0xD1, 0x4F, 0xD1, 0x55, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAE, 0x49, /* 0xC8-0xCB */ - 0xD1, 0x4A, 0x00, 0x00, 0xAB, 0xB0, 0xD4, 0xBA, /* 0xCC-0xCF */ - 0xD1, 0x56, 0x00, 0x00, 0xD1, 0x4D, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xAE, 0x48, 0xD1, 0x4C, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xD4, 0xB1, 0x00, 0x00, 0x00, 0x00, 0xB0, 0xEC, /* 0xDC-0xDF */ - 0xB0, 0xF0, 0xD4, 0xC1, 0xD4, 0xAF, 0xD4, 0xBD, /* 0xE0-0xE3 */ - 0xB0, 0xF1, 0xD4, 0xBF, 0x00, 0x00, 0xD4, 0xC5, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xD4, 0xC9, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xD4, 0xC0, 0xD4, 0xB4, 0xD4, 0xBC, 0x00, 0x00, /* 0xEC-0xEF */ - 0xD4, 0xCA, 0xD4, 0xC8, 0xD4, 0xBE, 0xD4, 0xB9, /* 0xF0-0xF3 */ - 0xD4, 0xB2, 0xD8, 0xA6, 0xD4, 0xB0, 0xB0, 0xF5, /* 0xF4-0xF7 */ - 0xD4, 0xB7, 0xB0, 0xF6, 0xB0, 0xF2, 0xD4, 0xAD, /* 0xF8-0xFB */ - 0xD4, 0xC3, 0xD4, 0xB5, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_58[512] = { - 0xD4, 0xB3, 0xD4, 0xC6, 0xB0, 0xF3, 0x00, 0x00, /* 0x00-0x03 */ - 0xD4, 0xCC, 0xB0, 0xED, 0xB0, 0xEF, 0xD4, 0xBB, /* 0x04-0x07 */ - 0xD4, 0xB6, 0xAE, 0x4B, 0xB0, 0xEE, 0xD4, 0xB8, /* 0x08-0x0B */ - 0xD4, 0xC7, 0xD4, 0xCB, 0xD4, 0xC2, 0x00, 0x00, /* 0x0C-0x0F */ - 0xD4, 0xC4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xD4, 0xAE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xD8, 0xA1, 0x00, 0x00, 0xD8, 0xAA, /* 0x18-0x1B */ - 0xD8, 0xA9, 0xB3, 0xFA, 0xD8, 0xA2, 0x00, 0x00, /* 0x1C-0x1F */ - 0xB3, 0xFB, 0xB3, 0xF9, 0x00, 0x00, 0xD8, 0xA4, /* 0x20-0x23 */ - 0xB3, 0xF6, 0xD8, 0xA8, 0x00, 0x00, 0xD8, 0xA3, /* 0x24-0x27 */ - 0xD8, 0xA5, 0xD8, 0x7D, 0xB3, 0xF4, 0x00, 0x00, /* 0x28-0x2B */ - 0xD8, 0xB2, 0xD8, 0xB1, 0xD8, 0xAE, 0xB3, 0xF3, /* 0x2C-0x2F */ - 0xB3, 0xF7, 0xB3, 0xF8, 0xD1, 0x4B, 0xD8, 0xAB, /* 0x30-0x33 */ - 0xB3, 0xF5, 0xB0, 0xF4, 0xD8, 0xAD, 0xD8, 0x7E, /* 0x34-0x37 */ - 0xD8, 0xB0, 0xD8, 0xAF, 0x00, 0x00, 0xD8, 0xB3, /* 0x38-0x3B */ - 0x00, 0x00, 0xDC, 0xEF, 0x00, 0x00, 0xD8, 0xAC, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0xD8, 0xA7, 0xDC, 0xE7, 0xB6, 0xF4, 0xB6, 0xF7, /* 0x48-0x4B */ - 0xB6, 0xF2, 0xDC, 0xE6, 0xDC, 0xEA, 0xDC, 0xE5, /* 0x4C-0x4F */ - 0x00, 0x00, 0xB6, 0xEC, 0xB6, 0xF6, 0xDC, 0xE2, /* 0x50-0x53 */ - 0xB6, 0xF0, 0xDC, 0xE9, 0x00, 0x00, 0xB6, 0xEE, /* 0x54-0x57 */ - 0xB6, 0xED, 0xDC, 0xEC, 0xB6, 0xEF, 0xDC, 0xEE, /* 0x58-0x5B */ - 0x00, 0x00, 0xDC, 0xEB, 0xB6, 0xEB, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xB6, 0xF5, 0xDC, 0xF0, /* 0x60-0x63 */ - 0xDC, 0xE4, 0xDC, 0xED, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xDC, 0xE3, 0x00, 0x00, 0x00, 0x00, 0xB6, 0xF1, /* 0x68-0x6B */ - 0x00, 0x00, 0xB6, 0xF3, 0x00, 0x00, 0xDC, 0xE8, /* 0x6C-0x6F */ - 0x00, 0x00, 0xDC, 0xF1, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xE1, 0x5D, 0xB9, 0xD0, 0xE1, 0x63, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xB9, 0xD5, 0xE1, 0x5F, 0xE1, 0x66, /* 0x78-0x7B */ - 0xE1, 0x57, 0xB9, 0xD7, 0xB9, 0xD1, 0xE1, 0x5C, /* 0x7C-0x7F */ - - 0xBC, 0x55, 0xE1, 0x5B, 0xE1, 0x64, 0xB9, 0xD2, /* 0x80-0x83 */ - 0x00, 0x00, 0xB9, 0xD6, 0xE1, 0x5A, 0xE1, 0x60, /* 0x84-0x87 */ - 0xE1, 0x65, 0xE1, 0x56, 0xB9, 0xD4, 0xE1, 0x5E, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0x62, 0xE1, 0x68, /* 0x8C-0x8F */ - 0xE1, 0x58, 0xE1, 0x61, 0x00, 0x00, 0xB9, 0xD3, /* 0x90-0x93 */ - 0xE1, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xE1, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xBC, 0x59, 0xE5, 0x4B, 0xBC, 0x57, 0xBC, 0x56, /* 0x9C-0x9F */ - 0xE5, 0x4D, 0xE5, 0x52, 0x00, 0x00, 0xE5, 0x4E, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xE5, 0x51, 0xBC, 0x5C, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xBE, 0xA5, 0xBC, 0x5B, 0x00, 0x00, 0xE5, 0x4A, /* 0xA8-0xAB */ - 0xE5, 0x50, 0x00, 0x00, 0xBC, 0x5A, 0xE5, 0x4F, /* 0xAC-0xAF */ - 0x00, 0x00, 0xE5, 0x4C, 0x00, 0x00, 0xBC, 0x58, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0x4D, 0xF9, 0xD9, /* 0xB8-0xBB */ - 0xE9, 0x4F, 0xE9, 0x4A, 0xBE, 0xC1, 0xE9, 0x4C, /* 0xBC-0xBF */ - 0x00, 0x00, 0xBE, 0xC0, 0xE9, 0x4E, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xBE, 0xC3, 0xE9, 0x50, 0xBE, 0xC2, /* 0xC4-0xC7 */ - 0xE9, 0x49, 0xE9, 0x4B, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xC0, 0xA5, 0xEC, 0xCC, /* 0xCC-0xCF */ - 0x00, 0x00, 0xC0, 0xA4, 0xEC, 0xCD, 0xC0, 0xA3, /* 0xD0-0xD3 */ - 0xEC, 0xCB, 0xC0, 0xA2, 0xEC, 0xCA, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xC2, 0x53, 0xC2, 0x52, 0xF1, 0xF6, 0xF1, 0xF8, /* 0xD8-0xDB */ - 0x00, 0x00, 0xF1, 0xF7, 0xC3, 0x61, 0xC3, 0x62, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xC3, 0x63, 0xF4, 0x42, /* 0xE0-0xE3 */ - 0xC4, 0x5B, 0x00, 0x00, 0x00, 0x00, 0xF7, 0xD3, /* 0xE4-0xE7 */ - 0xF7, 0xD2, 0xC5, 0xF2, 0x00, 0x00, 0xA4, 0x68, /* 0xE8-0xEB */ - 0xA4, 0xD0, 0x00, 0x00, 0x00, 0x00, 0xA7, 0xA7, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xCE, 0x5F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xB3, 0xFC, 0xB3, 0xFD, 0x00, 0x00, /* 0xF8-0xFB */ - 0xDC, 0xF2, 0xB9, 0xD8, 0xE1, 0x69, 0xE5, 0x53, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_59[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC9, 0x5A, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xB0, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0xCC, 0x42, 0xCE, 0x60, 0xD1, 0x59, 0xAE, 0x4C, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xF9, 0x00, 0x00, /* 0x10-0x13 */ - 0xC4, 0xDC, 0xA4, 0x69, 0xA5, 0x7E, 0xC9, 0x70, /* 0x14-0x17 */ - 0x00, 0x00, 0xA6, 0x67, 0xA6, 0x68, 0x00, 0x00, /* 0x18-0x1B */ - 0xA9, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xB0, 0xF7, 0x00, 0x00, 0xB9, 0xDA, 0x00, 0x00, /* 0x20-0x23 */ - 0xB9, 0xDB, 0xB9, 0xD9, 0x00, 0x00, 0xA4, 0x6A, /* 0x24-0x27 */ - 0x00, 0x00, 0xA4, 0xD1, 0xA4, 0xD3, 0xA4, 0xD2, /* 0x28-0x2B */ - 0xC9, 0x5B, 0xA4, 0xD4, 0xA5, 0xA1, 0xC9, 0x71, /* 0x2C-0x2F */ - 0x00, 0x00, 0xA5, 0xA2, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0x69, /* 0x34-0x37 */ - 0xA6, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xC9, 0xCB, 0x00, 0x00, 0xA7, 0xA8, 0x00, 0x00, /* 0x3C-0x3F */ - 0xCA, 0xB1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xA9, 0x61, 0xCC, 0x43, 0x00, 0x00, 0xA9, 0x5F, /* 0x44-0x47 */ - 0xA9, 0x60, 0xA9, 0x5E, 0xD1, 0x5A, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xAB, 0xB6, 0xAB, 0xB5, /* 0x4C-0x4F */ - 0xAB, 0xB7, 0xAB, 0xB4, 0x00, 0x00, 0xCE, 0x61, /* 0x50-0x53 */ - 0xA9, 0x62, 0xAB, 0xB3, 0x00, 0x00, 0xAE, 0x4D, /* 0x54-0x57 */ - 0xAE, 0x4E, 0x00, 0x00, 0xAE, 0x4F, 0x00, 0x00, /* 0x58-0x5B */ - 0xD4, 0xCD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xB3, 0xFE, 0xD8, 0xB4, 0xB0, 0xF8, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB6, 0xF8, /* 0x64-0x67 */ - 0x00, 0x00, 0xB9, 0xDD, 0xB9, 0xDC, 0xE1, 0x6A, /* 0x68-0x6B */ - 0x00, 0x00, 0xBC, 0x5D, 0xBE, 0xC4, 0x00, 0x00, /* 0x6C-0x6F */ - 0xEF, 0xC0, 0xF6, 0xDA, 0xF7, 0xD4, 0xA4, 0x6B, /* 0x70-0x73 */ - 0xA5, 0xA3, 0x00, 0x00, 0xA5, 0xA4, 0xC9, 0xD1, /* 0x74-0x77 */ - 0xA6, 0x6C, 0xA6, 0x6F, 0x00, 0x00, 0xC9, 0xCF, /* 0x78-0x7B */ - 0xC9, 0xCD, 0xA6, 0x6E, 0xC9, 0xD0, 0xC9, 0xD2, /* 0x7C-0x7F */ - - 0xC9, 0xCC, 0xA6, 0x71, 0xA6, 0x70, 0xA6, 0x6D, /* 0x80-0x83 */ - 0xA6, 0x6B, 0xC9, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xA7, 0xB3, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0xA7, 0xB0, 0xCA, 0xB6, 0xCA, 0xB9, /* 0x8C-0x8F */ - 0xCA, 0xB8, 0x00, 0x00, 0xA7, 0xAA, 0xA7, 0xB2, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xA7, 0xAF, 0xCA, 0xB5, /* 0x94-0x97 */ - 0xCA, 0xB3, 0xA7, 0xAE, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xA7, 0xA9, 0xA7, 0xAC, 0x00, 0x00, /* 0x9C-0x9F */ - 0xCA, 0xB4, 0xCA, 0xBB, 0xCA, 0xB7, 0xA7, 0xAD, /* 0xA0-0xA3 */ - 0xA7, 0xB1, 0xA7, 0xB4, 0xCA, 0xB2, 0xCA, 0xBA, /* 0xA4-0xA7 */ - 0xA7, 0xAB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xA9, 0x67, 0xA9, 0x6F, /* 0xAC-0xAF */ - 0x00, 0x00, 0xCC, 0x4F, 0xCC, 0x48, 0xA9, 0x70, /* 0xB0-0xB3 */ - 0xCC, 0x53, 0xCC, 0x44, 0xCC, 0x4B, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xA9, 0x66, 0xCC, 0x45, 0xA9, 0x64, /* 0xB8-0xBB */ - 0xCC, 0x4C, 0xCC, 0x50, 0xA9, 0x63, 0x00, 0x00, /* 0xBC-0xBF */ - 0xCC, 0x51, 0xCC, 0x4A, 0x00, 0x00, 0xCC, 0x4D, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xA9, 0x72, 0xA9, 0x69, 0xCC, 0x54, /* 0xC4-0xC7 */ - 0xCC, 0x52, 0x00, 0x00, 0xA9, 0x6E, 0xA9, 0x6C, /* 0xC8-0xCB */ - 0xCC, 0x49, 0xA9, 0x6B, 0xCC, 0x47, 0xCC, 0x46, /* 0xCC-0xCF */ - 0xA9, 0x6A, 0xA9, 0x68, 0xA9, 0x71, 0xA9, 0x6D, /* 0xD0-0xD3 */ - 0xA9, 0x65, 0x00, 0x00, 0xCC, 0x4E, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xAB, 0xB9, 0x00, 0x00, 0xAB, 0xC0, 0xCE, 0x6F, /* 0xD8-0xDB */ - 0xAB, 0xB8, 0xCE, 0x67, 0xCE, 0x63, 0x00, 0x00, /* 0xDC-0xDF */ - 0xCE, 0x73, 0xCE, 0x62, 0x00, 0x00, 0xAB, 0xBB, /* 0xE0-0xE3 */ - 0xCE, 0x6C, 0xAB, 0xBE, 0xAB, 0xC1, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xAB, 0xBC, 0xCE, 0x70, 0xAB, 0xBF, 0x00, 0x00, /* 0xE8-0xEB */ - 0xAE, 0x56, 0xCE, 0x76, 0xCE, 0x64, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0xCE, 0x66, 0xCE, 0x6D, 0xCE, 0x71, /* 0xF0-0xF3 */ - 0xCE, 0x75, 0xCE, 0x72, 0xCE, 0x6B, 0xCE, 0x6E, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0x68, 0xAB, 0xC3, /* 0xF8-0xFB */ - 0xCE, 0x6A, 0xCE, 0x69, 0xCE, 0x74, 0xAB, 0xBA, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5A[512] = { - 0xCE, 0x65, 0xAB, 0xC2, 0x00, 0x00, 0xAB, 0xBD, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xAE, 0x5C, 0xD1, 0x62, 0x00, 0x00, /* 0x08-0x0B */ - 0xAE, 0x5B, 0x00, 0x00, 0x00, 0x00, 0xD1, 0x60, /* 0x0C-0x0F */ - 0x00, 0x00, 0xAE, 0x50, 0x00, 0x00, 0xAE, 0x55, /* 0x10-0x13 */ - 0x00, 0x00, 0xD1, 0x5F, 0xD1, 0x5C, 0xD1, 0x61, /* 0x14-0x17 */ - 0xAE, 0x51, 0xD1, 0x5B, 0x00, 0x00, 0xAE, 0x54, /* 0x18-0x1B */ - 0xAE, 0x52, 0x00, 0x00, 0xD1, 0x63, 0xAE, 0x53, /* 0x1C-0x1F */ - 0xAE, 0x57, 0x00, 0x00, 0x00, 0x00, 0xAE, 0x58, /* 0x20-0x23 */ - 0x00, 0x00, 0xAE, 0x5A, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xAE, 0x59, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0xD1, 0x5D, 0xD1, 0x5E, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0x64, /* 0x30-0x33 */ - 0x00, 0x00, 0xD4, 0xD4, 0xB0, 0xF9, 0xD8, 0xC2, /* 0x34-0x37 */ - 0xD4, 0xD3, 0xD4, 0xE6, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xB1, 0x40, 0x00, 0x00, 0xD4, 0xE4, 0x00, 0x00, /* 0x3C-0x3F */ - 0xB0, 0xFE, 0xB0, 0xFA, 0xD4, 0xED, 0xD4, 0xDD, /* 0x40-0x43 */ - 0xD4, 0xE0, 0x00, 0x00, 0xB1, 0x43, 0xD4, 0xEA, /* 0x44-0x47 */ - 0xD4, 0xE2, 0xB0, 0xFB, 0xB1, 0x44, 0x00, 0x00, /* 0x48-0x4B */ - 0xD4, 0xE7, 0xD4, 0xE5, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xD4, 0xD6, 0xD4, 0xEB, 0xD4, 0xDF, 0xD4, 0xDA, /* 0x50-0x53 */ - 0x00, 0x00, 0xD4, 0xD0, 0xD4, 0xEC, 0xD4, 0xDC, /* 0x54-0x57 */ - 0xD4, 0xCF, 0x00, 0x00, 0xB1, 0x42, 0xD4, 0xE1, /* 0x58-0x5B */ - 0xD4, 0xEE, 0xD4, 0xDE, 0xD4, 0xD2, 0xD4, 0xD7, /* 0x5C-0x5F */ - 0xD4, 0xCE, 0x00, 0x00, 0xB1, 0x41, 0x00, 0x00, /* 0x60-0x63 */ - 0xD4, 0xDB, 0xD4, 0xD8, 0xB0, 0xFC, 0xD4, 0xD1, /* 0x64-0x67 */ - 0x00, 0x00, 0xD4, 0xE9, 0xB0, 0xFD, 0x00, 0x00, /* 0x68-0x6B */ - 0xD4, 0xD9, 0xD4, 0xD5, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xD4, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x40, /* 0x74-0x77 */ - 0xD8, 0xBB, 0x00, 0x00, 0xD8, 0xB8, 0xD8, 0xC9, /* 0x78-0x7B */ - 0xD8, 0xBD, 0xD8, 0xCA, 0x00, 0x00, 0xB4, 0x42, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD8, 0xC6, /* 0x80-0x83 */ - 0xD8, 0xC3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xD8, 0xC4, 0xD8, 0xC7, /* 0x88-0x8B */ - 0xD8, 0xCB, 0x00, 0x00, 0xD4, 0xE3, 0xD8, 0xCD, /* 0x8C-0x8F */ - 0xDD, 0x47, 0x00, 0x00, 0xB4, 0x43, 0xD8, 0xCE, /* 0x90-0x93 */ - 0xD8, 0xB6, 0xD8, 0xC0, 0x00, 0x00, 0xD8, 0xC5, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xB4, 0x41, 0xB4, 0x44, /* 0x98-0x9B */ - 0xD8, 0xCC, 0xD8, 0xCF, 0xD8, 0xBA, 0xD8, 0xB7, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0xD8, 0xB9, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xD8, 0xBE, 0xD8, 0xBC, 0xB4, 0x45, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xD8, 0xC8, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xD8, 0xBF, 0x00, 0x00, 0xD8, 0xC1, 0xD8, 0xB5, /* 0xAC-0xAF */ - 0xDC, 0xFA, 0xDC, 0xF8, 0xB7, 0x42, 0xB7, 0x40, /* 0xB0-0xB3 */ - 0xDD, 0x43, 0xDC, 0xF9, 0xDD, 0x44, 0xDD, 0x40, /* 0xB4-0xB7 */ - 0xDC, 0xF7, 0xDD, 0x46, 0xDC, 0xF6, 0xDC, 0xFD, /* 0xB8-0xBB */ - 0xB6, 0xFE, 0xB6, 0xFD, 0xB6, 0xFC, 0xDC, 0xFB, /* 0xBC-0xBF */ - 0xDD, 0x41, 0xB6, 0xF9, 0xB7, 0x41, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xDC, 0xF4, 0x00, 0x00, 0xDC, 0xFE, 0xDC, 0xF3, /* 0xC4-0xC7 */ - 0xDC, 0xFC, 0xB6, 0xFA, 0xDD, 0x42, 0xDC, 0xF5, /* 0xC8-0xCB */ - 0xB6, 0xFB, 0xDD, 0x45, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xE1, 0x6E, 0xB9, 0xE2, 0xB9, 0xE1, /* 0xD4-0xD7 */ - 0xB9, 0xE3, 0xE1, 0x7A, 0xE1, 0x70, 0xE1, 0x76, /* 0xD8-0xDB */ - 0xE1, 0x6B, 0xE1, 0x79, 0xE1, 0x78, 0xE1, 0x7C, /* 0xDC-0xDF */ - 0xE1, 0x75, 0xB9, 0xDE, 0xE1, 0x74, 0xB9, 0xE4, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xE1, 0x6D, 0xB9, 0xDF, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xE1, 0x7B, 0xB9, 0xE0, 0xE1, 0x6F, 0xE1, 0x72, /* 0xE8-0xEB */ - 0xE1, 0x77, 0xE1, 0x71, 0xE1, 0x6C, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0x73, /* 0xF0-0xF3 */ - 0xE5, 0x55, 0xBC, 0x61, 0xE5, 0x58, 0xE5, 0x57, /* 0xF4-0xF7 */ - 0xE5, 0x5A, 0xE5, 0x5C, 0xF9, 0xDC, 0xBC, 0x5F, /* 0xF8-0xFB */ - 0x00, 0x00, 0xE5, 0x56, 0x00, 0x00, 0xE5, 0x54, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5B[512] = { - 0x00, 0x00, 0xE5, 0x5D, 0xE5, 0x5B, 0xE5, 0x59, /* 0x00-0x03 */ - 0x00, 0x00, 0xE5, 0x5F, 0x00, 0x00, 0xE5, 0x5E, /* 0x04-0x07 */ - 0xBC, 0x63, 0xBC, 0x5E, 0x00, 0x00, 0xBC, 0x60, /* 0x08-0x0B */ - 0xBC, 0x62, 0x00, 0x00, 0x00, 0x00, 0xE5, 0x60, /* 0x0C-0x0F */ - 0xE9, 0x57, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x56, /* 0x10-0x13 */ - 0xE9, 0x55, 0x00, 0x00, 0xE9, 0x58, 0xE9, 0x51, /* 0x14-0x17 */ - 0x00, 0x00, 0xE9, 0x52, 0xE9, 0x5A, 0xE9, 0x53, /* 0x18-0x1B */ - 0x00, 0x00, 0xBE, 0xC5, 0xE9, 0x5C, 0x00, 0x00, /* 0x1C-0x1F */ - 0xE9, 0x5B, 0xE9, 0x54, 0x00, 0x00, 0xEC, 0xD1, /* 0x20-0x23 */ - 0xC0, 0xA8, 0xEC, 0xCF, 0xEC, 0xD4, 0xEC, 0xD3, /* 0x24-0x27 */ - 0xE9, 0x59, 0x00, 0x00, 0xC0, 0xA7, 0x00, 0x00, /* 0x28-0x2B */ - 0xEC, 0xD2, 0xEC, 0xCE, 0xEC, 0xD6, 0xEC, 0xD5, /* 0x2C-0x2F */ - 0xC0, 0xA6, 0x00, 0x00, 0xEC, 0xD0, 0x00, 0x00, /* 0x30-0x33 */ - 0xBE, 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xC2, 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xEF, 0xC1, 0xF1, 0xFA, 0xF1, 0xFB, 0xF1, 0xFC, /* 0x3C-0x3F */ - 0xC4, 0x5C, 0x00, 0x00, 0x00, 0x00, 0xC4, 0x5D, /* 0x40-0x43 */ - 0x00, 0x00, 0xF4, 0x43, 0x00, 0x00, 0xF5, 0xC8, /* 0x44-0x47 */ - 0xF5, 0xC7, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xDB, /* 0x48-0x4B */ - 0xF6, 0xDC, 0xF7, 0xD5, 0xF8, 0xA7, 0x00, 0x00, /* 0x4C-0x4F */ - 0xA4, 0x6C, 0xA4, 0x6D, 0x00, 0x00, 0xA4, 0x6E, /* 0x50-0x53 */ - 0xA4, 0xD5, 0xA5, 0xA5, 0xC9, 0xD3, 0xA6, 0x72, /* 0x54-0x57 */ - 0xA6, 0x73, 0x00, 0x00, 0xA7, 0xB7, 0xA7, 0xB8, /* 0x58-0x5B */ - 0xA7, 0xB6, 0xA7, 0xB5, 0x00, 0x00, 0xA9, 0x73, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xCC, 0x55, 0xA9, 0x75, /* 0x60-0x63 */ - 0xA9, 0x74, 0xCC, 0x56, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xAB, 0xC4, 0x00, 0x00, 0xAE, 0x5D, /* 0x68-0x6B */ - 0xD1, 0x65, 0x00, 0x00, 0xD4, 0xF0, 0x00, 0x00, /* 0x6C-0x6F */ - 0xB1, 0x45, 0xB4, 0x47, 0xD4, 0xEF, 0xB4, 0x46, /* 0x70-0x73 */ - 0x00, 0x00, 0xB9, 0xE5, 0x00, 0x00, 0xE1, 0x7D, /* 0x74-0x77 */ - 0xBE, 0xC7, 0x00, 0x00, 0xC0, 0xA9, 0xEC, 0xD7, /* 0x78-0x7B */ - 0x00, 0x00, 0xC4, 0x5E, 0x00, 0x00, 0xC5, 0x70, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xC9, 0x72, 0x00, 0x00, 0xA5, 0xA6, /* 0x80-0x83 */ - 0xC9, 0x73, 0xA6, 0x76, 0x00, 0x00, 0xA6, 0x74, /* 0x84-0x87 */ - 0xA6, 0x75, 0xA6, 0x77, 0x00, 0x00, 0xA7, 0xBA, /* 0x88-0x8B */ - 0xA7, 0xB9, 0x00, 0x00, 0xCA, 0xBC, 0xA7, 0xBB, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xBD, 0xCC, 0x57, /* 0x90-0x93 */ - 0x00, 0x00, 0xCC, 0x58, 0x00, 0x00, 0xA9, 0x76, /* 0x94-0x97 */ - 0xA9, 0x78, 0xA9, 0x7A, 0xA9, 0x77, 0xA9, 0x7B, /* 0x98-0x9B */ - 0xA9, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0xAB, 0xC8, 0xAB, 0xC5, /* 0xA0-0xA3 */ - 0xAB, 0xC7, 0xAB, 0xC9, 0xAB, 0xC6, 0xD1, 0x66, /* 0xA4-0xA7 */ - 0xCE, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xD1, 0x68, 0xD1, 0x67, 0xAE, 0x63, 0x00, 0x00, /* 0xAC-0xAF */ - 0xAE, 0x5F, 0x00, 0x00, 0x00, 0x00, 0xAE, 0x60, /* 0xB0-0xB3 */ - 0xAE, 0x62, 0xAE, 0x64, 0xAE, 0x61, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xAE, 0x66, 0xAE, 0x65, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB1, 0x4A, /* 0xBC-0xBF */ - 0xD4, 0xF2, 0xD4, 0xF1, 0xB1, 0x49, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xB1, 0x48, 0xB1, 0x47, 0xB1, 0x4B, 0xB1, 0x46, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xD8, 0xD5, 0xD8, 0xD2, /* 0xC8-0xCB */ - 0xB4, 0x49, 0xD8, 0xD1, 0xD8, 0xD6, 0x00, 0x00, /* 0xCC-0xCF */ - 0xB4, 0x4B, 0xD8, 0xD4, 0xB4, 0x48, 0xB4, 0x4A, /* 0xD0-0xD3 */ - 0xD8, 0xD3, 0x00, 0x00, 0xDD, 0x48, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xDD, 0x49, 0xDD, 0x4A, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xB9, 0xE6, 0xB9, 0xEE, /* 0xDC-0xDF */ - 0xE1, 0x7E, 0xB9, 0xE8, 0xB9, 0xEC, 0xE1, 0xA1, /* 0xE0-0xE3 */ - 0xB9, 0xED, 0xB9, 0xE9, 0xB9, 0xEA, 0xB9, 0xE7, /* 0xE4-0xE7 */ - 0xB9, 0xEB, 0xBC, 0x66, 0xD8, 0xD0, 0xBC, 0x67, /* 0xE8-0xEB */ - 0xBC, 0x65, 0x00, 0x00, 0xBC, 0x64, 0xE9, 0x5D, /* 0xEC-0xEF */ - 0xBE, 0xC8, 0xEC, 0xD8, 0xEC, 0xD9, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xC3, 0x64, 0xC4, 0x5F, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xA4, 0x6F, 0x00, 0x00, 0xA6, 0x78, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5C[512] = { - 0x00, 0x00, 0xAB, 0xCA, 0x00, 0x00, 0xD1, 0x69, /* 0x00-0x03 */ - 0xAE, 0x67, 0x00, 0x00, 0x00, 0x00, 0xB1, 0x4E, /* 0x04-0x07 */ - 0xB1, 0x4D, 0xB1, 0x4C, 0xB4, 0x4C, 0xB4, 0x4D, /* 0x08-0x0B */ - 0xD8, 0xD7, 0xB9, 0xEF, 0xBE, 0xC9, 0xA4, 0x70, /* 0x0C-0x0F */ - 0xC9, 0x5C, 0xA4, 0xD6, 0xC9, 0x74, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xC9, 0xD4, 0xA6, 0x79, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0xA9, 0x7C, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDD, 0x4B, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0xA4, 0x71, 0x00, 0x00, /* 0x20-0x23 */ - 0xA4, 0xD7, 0xC9, 0xD5, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xCA, 0xBE, 0x00, 0x00, 0xCA, 0xBF, 0x00, 0x00, /* 0x28-0x2B */ - 0xA7, 0xBC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xD8, 0xD8, 0xB4, 0x4E, 0x00, 0x00, 0xDD, 0x4C, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xAA, /* 0x34-0x37 */ - 0xA4, 0x72, 0xA4, 0xA8, 0xA4, 0xD8, 0xC9, 0x75, /* 0x38-0x3B */ - 0xA5, 0xA7, 0x00, 0x00, 0xA7, 0xC0, 0xA7, 0xBF, /* 0x3C-0x3F */ - 0xA7, 0xBD, 0xA7, 0xBE, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xCC, 0x59, 0xA9, 0x7E, 0xA9, 0xA1, 0xCC, 0x5A, /* 0x44-0x47 */ - 0xA9, 0x7D, 0x00, 0x00, 0x00, 0x00, 0xAB, 0xCE, /* 0x48-0x4B */ - 0xCE, 0x78, 0xAB, 0xCD, 0xAB, 0xCB, 0xAB, 0xCC, /* 0x4C-0x4F */ - 0xAE, 0x6A, 0xAE, 0x68, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xD1, 0x6B, 0xAE, 0x69, 0xD1, 0x6A, 0x00, 0x00, /* 0x54-0x57 */ - 0xAE, 0x5E, 0xD4, 0xF3, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0xB1, 0x50, 0xB1, 0x51, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xB1, 0x4F, 0x00, 0x00, 0xB9, 0xF0, 0xE1, 0xA2, /* 0x60-0x63 */ - 0xBC, 0x68, 0xBC, 0x69, 0x00, 0x00, 0xE5, 0x61, /* 0x64-0x67 */ - 0xC0, 0xAB, 0xEF, 0xC2, 0xEF, 0xC3, 0x00, 0x00, /* 0x68-0x6B */ - 0xC4, 0xDD, 0xF8, 0xA8, 0xC9, 0x4B, 0xA4, 0xD9, /* 0x6C-0x6F */ - 0x00, 0x00, 0xA4, 0x73, 0x00, 0x00, 0xC9, 0x77, /* 0x70-0x73 */ - 0xC9, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xA6, 0x7A, 0xC9, 0xD7, 0xC9, 0xD8, /* 0x78-0x7B */ - 0xC9, 0xD6, 0x00, 0x00, 0xC9, 0xD9, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xC7, 0x00, 0x00, /* 0x84-0x87 */ - 0xCA, 0xC2, 0xCA, 0xC4, 0xCA, 0xC6, 0xCA, 0xC3, /* 0x88-0x8B */ - 0xA7, 0xC4, 0xCA, 0xC0, 0x00, 0x00, 0xCA, 0xC1, /* 0x8C-0x8F */ - 0xA7, 0xC1, 0xA7, 0xC2, 0xCA, 0xC5, 0xCA, 0xC8, /* 0x90-0x93 */ - 0xA7, 0xC3, 0xCA, 0xC9, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xCC, 0x68, 0x00, 0x00, 0xCC, 0x62, /* 0x9C-0x9F */ - 0xCC, 0x5D, 0xA9, 0xA3, 0xCC, 0x65, 0xCC, 0x63, /* 0xA0-0xA3 */ - 0xCC, 0x5C, 0xCC, 0x69, 0xCC, 0x6C, 0xCC, 0x67, /* 0xA4-0xA7 */ - 0xCC, 0x60, 0xA9, 0xA5, 0xCC, 0x66, 0xA9, 0xA6, /* 0xA8-0xAB */ - 0xCC, 0x61, 0xCC, 0x64, 0xCC, 0x5B, 0xCC, 0x5F, /* 0xAC-0xAF */ - 0xCC, 0x6B, 0xA9, 0xA7, 0x00, 0x00, 0xA9, 0xA8, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xCC, 0x5E, 0xCC, 0x6A, 0xA9, 0xA2, /* 0xB4-0xB7 */ - 0xA9, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0xAB, 0xCE, 0xA4, /* 0xC4-0xC7 */ - 0xCE, 0xAA, 0xCE, 0xA3, 0xCE, 0xA5, 0xCE, 0x7D, /* 0xC8-0xCB */ - 0xCE, 0x7B, 0x00, 0x00, 0xCE, 0xAC, 0xCE, 0xA9, /* 0xCC-0xCF */ - 0xCE, 0x79, 0x00, 0x00, 0xAB, 0xD0, 0xCE, 0xA7, /* 0xD0-0xD3 */ - 0xCE, 0xA8, 0x00, 0x00, 0xCE, 0xA6, 0xCE, 0x7C, /* 0xD4-0xD7 */ - 0xCE, 0x7A, 0xAB, 0xCF, 0xCE, 0xA2, 0xCE, 0x7E, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xCE, 0xA1, 0xCE, 0xAD, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xAE, 0x6F, 0x00, 0x00, 0xAE, 0x6E, 0x00, 0x00, /* 0xE8-0xEB */ - 0xD1, 0x6C, 0xAE, 0x6B, 0xD1, 0x6E, 0x00, 0x00, /* 0xEC-0xEF */ - 0xAE, 0x70, 0xD1, 0x6F, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xAE, 0x73, 0x00, 0x00, 0xAE, 0x71, 0xD1, 0x70, /* 0xF4-0xF7 */ - 0xCE, 0xAE, 0xD1, 0x72, 0x00, 0x00, 0xAE, 0x6D, /* 0xF8-0xFB */ - 0x00, 0x00, 0xAE, 0x6C, 0x00, 0x00, 0xD1, 0x6D, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5D[512] = { - 0xD1, 0x71, 0xAE, 0x72, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xB1, 0x53, 0xB1, 0x52, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0xF5, /* 0x08-0x0B */ - 0xD4, 0xF9, 0xD4, 0xFB, 0xB1, 0x54, 0xD4, 0xFE, /* 0x0C-0x0F */ - 0x00, 0x00, 0xB1, 0x58, 0xD5, 0x41, 0x00, 0x00, /* 0x10-0x13 */ - 0xB1, 0x5A, 0x00, 0x00, 0xB1, 0x56, 0xB1, 0x5E, /* 0x14-0x17 */ - 0x00, 0x00, 0xB1, 0x5B, 0xD4, 0xF7, 0xB1, 0x55, /* 0x18-0x1B */ - 0x00, 0x00, 0xD4, 0xF6, 0xD4, 0xF4, 0xD5, 0x43, /* 0x1C-0x1F */ - 0xD4, 0xF8, 0x00, 0x00, 0xB1, 0x57, 0xD5, 0x42, /* 0x20-0x23 */ - 0xB1, 0x5C, 0xD4, 0xFD, 0xD4, 0xFC, 0xB1, 0x5D, /* 0x24-0x27 */ - 0xD4, 0xFA, 0xB1, 0x59, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0x44, 0x00, 0x00, /* 0x2C-0x2F */ - 0xD5, 0x40, 0xD8, 0xE7, 0xD8, 0xEE, 0xD8, 0xE3, /* 0x30-0x33 */ - 0xB4, 0x51, 0xD8, 0xDF, 0xD8, 0xEF, 0xD8, 0xD9, /* 0x34-0x37 */ - 0xD8, 0xEC, 0xD8, 0xEA, 0xD8, 0xE4, 0x00, 0x00, /* 0x38-0x3B */ - 0xD8, 0xED, 0xD8, 0xE6, 0x00, 0x00, 0xD8, 0xDE, /* 0x3C-0x3F */ - 0xD8, 0xF0, 0xD8, 0xDC, 0xD8, 0xE9, 0xD8, 0xDA, /* 0x40-0x43 */ - 0x00, 0x00, 0xD8, 0xF1, 0x00, 0x00, 0xB4, 0x52, /* 0x44-0x47 */ - 0x00, 0x00, 0xD8, 0xEB, 0xDD, 0x4F, 0xD8, 0xDD, /* 0x48-0x4B */ - 0xB4, 0x4F, 0x00, 0x00, 0xD8, 0xE1, 0x00, 0x00, /* 0x4C-0x4F */ - 0xB4, 0x50, 0xD8, 0xE0, 0xD8, 0xE5, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xD8, 0xE2, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xD8, 0xE8, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0x53, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0x56, 0xDD, 0x4E, /* 0x60-0x63 */ - 0x00, 0x00, 0xDD, 0x50, 0x00, 0x00, 0xDD, 0x55, /* 0x64-0x67 */ - 0xDD, 0x54, 0xB7, 0x43, 0x00, 0x00, 0xD8, 0xDB, /* 0x68-0x6B */ - 0xDD, 0x52, 0x00, 0x00, 0x00, 0x00, 0xB7, 0x44, /* 0x6C-0x6F */ - 0x00, 0x00, 0xDD, 0x4D, 0xDD, 0x51, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xA9, /* 0x74-0x77 */ - 0x00, 0x00, 0xE1, 0xB0, 0xE1, 0xA7, 0x00, 0x00, /* 0x78-0x7B */ - 0xE1, 0xAE, 0xE1, 0xA5, 0xE1, 0xAD, 0xE1, 0xB1, /* 0x7C-0x7F */ - - 0xE1, 0xA4, 0xE1, 0xA8, 0xE1, 0xA3, 0x00, 0x00, /* 0x80-0x83 */ - 0xB9, 0xF1, 0x00, 0x00, 0xE1, 0xA6, 0xB9, 0xF2, /* 0x84-0x87 */ - 0xE1, 0xAC, 0xE1, 0xAB, 0xE1, 0xAA, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0xE1, 0xAF, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0x65, 0xE5, 0x67, /* 0x90-0x93 */ - 0xBC, 0x6B, 0xE5, 0x68, 0x00, 0x00, 0xE5, 0x63, /* 0x94-0x97 */ - 0x00, 0x00, 0xE5, 0x62, 0xE5, 0x6C, 0x00, 0x00, /* 0x98-0x9B */ - 0xE5, 0x6A, 0xBC, 0x6A, 0xE5, 0x6D, 0xE5, 0x64, /* 0x9C-0x9F */ - 0xE5, 0x69, 0xE5, 0x6B, 0xE5, 0x66, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE9, 0x61, /* 0xA4-0xA7 */ - 0xE9, 0x66, 0xE9, 0x60, 0xE9, 0x65, 0x00, 0x00, /* 0xA8-0xAB */ - 0xE9, 0x5E, 0xE9, 0x68, 0xE9, 0x64, 0xE9, 0x69, /* 0xAC-0xAF */ - 0xE9, 0x63, 0xE9, 0x5F, 0xE9, 0x67, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xE9, 0x6A, 0xE9, 0x62, 0x00, 0x00, 0xEC, 0xDA, /* 0xB4-0xB7 */ - 0xC0, 0xAF, 0x00, 0x00, 0xC0, 0xAD, 0x00, 0x00, /* 0xB8-0xBB */ - 0xC0, 0xAC, 0xC0, 0xAE, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xEF, 0xC4, 0x00, 0x00, 0xF1, 0x72, 0xF1, 0xFD, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0x44, 0xF4, 0x45, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xC4, 0x60, 0x00, 0x00, 0xF5, 0xC9, /* 0xC8-0xCB */ - 0x00, 0x00, 0xC4, 0xDE, 0x00, 0x00, 0xF5, 0xCA, /* 0xCC-0xCF */ - 0x00, 0x00, 0xF6, 0xDE, 0xC5, 0x72, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xC5, 0x71, 0xF6, 0xDD, 0xC5, 0xC9, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xF7, 0xD6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0xA4, 0x74, 0xA6, 0x7B, 0xC9, 0xDA, /* 0xDC-0xDF */ - 0xCA, 0xCA, 0xA8, 0xB5, 0xB1, 0x5F, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xA4, 0x75, 0xA5, 0xAA, 0xA5, 0xA9, /* 0xE4-0xE7 */ - 0xA5, 0xA8, 0x00, 0x00, 0x00, 0x00, 0xA7, 0xC5, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0xAE, 0x74, 0x00, 0x00, /* 0xEC-0xEF */ - 0xDD, 0x57, 0xA4, 0x76, 0xA4, 0x77, 0xA4, 0x78, /* 0xF0-0xF3 */ - 0xA4, 0xDA, 0x00, 0x00, 0x00, 0x00, 0xAB, 0xD1, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xCE, 0xAF, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xB4, 0x53, 0xA4, 0x79, 0xC9, 0x5D, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5E[512] = { - 0x00, 0x00, 0x00, 0x00, 0xA5, 0xAB, 0xA5, 0xAC, /* 0x00-0x03 */ - 0xC9, 0x78, 0x00, 0x00, 0xA6, 0x7C, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xCB, 0x00, 0x00, /* 0x08-0x0B */ - 0xA7, 0xC6, 0x00, 0x00, 0xCA, 0xCC, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0xA9, 0xAE, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xCC, 0x6E, 0xA9, 0xAC, 0xA9, 0xAB, 0xCC, 0x6D, /* 0x14-0x17 */ - 0xA9, 0xA9, 0xCC, 0x6F, 0xA9, 0xAA, 0xA9, 0xAD, /* 0x18-0x1B */ - 0x00, 0x00, 0xAB, 0xD2, 0x00, 0x00, 0xAB, 0xD4, /* 0x1C-0x1F */ - 0xCE, 0xB3, 0xCE, 0xB0, 0xCE, 0xB1, 0xCE, 0xB2, /* 0x20-0x23 */ - 0xCE, 0xB4, 0xAB, 0xD3, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xD1, 0x74, 0xD1, 0x73, 0x00, 0x00, 0xAE, 0x76, /* 0x28-0x2B */ - 0x00, 0x00, 0xAE, 0x75, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB1, 0x62, /* 0x30-0x33 */ - 0xD5, 0x46, 0x00, 0x00, 0xB1, 0x61, 0xB1, 0x63, /* 0x34-0x37 */ - 0xB1, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xB4, 0x55, 0xD5, 0x45, 0x00, 0x00, /* 0x3C-0x3F */ - 0xB4, 0x56, 0xD8, 0xF3, 0x00, 0x00, 0xB4, 0x57, /* 0x40-0x43 */ - 0xD8, 0xF2, 0xB4, 0x54, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0x5A, 0xDD, 0x5C, /* 0x48-0x4B */ - 0xB7, 0x45, 0xDD, 0x5B, 0xDD, 0x59, 0xDD, 0x58, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xB4, /* 0x50-0x53 */ - 0xB9, 0xF7, 0xB9, 0xF5, 0x00, 0x00, 0xB9, 0xF6, /* 0x54-0x57 */ - 0xE1, 0xB2, 0xE1, 0xB3, 0x00, 0x00, 0xB9, 0xF3, /* 0x58-0x5B */ - 0xE5, 0x71, 0xE5, 0x6F, 0x00, 0x00, 0xBC, 0x6D, /* 0x5C-0x5F */ - 0xE5, 0x70, 0xBC, 0x6E, 0xBC, 0x6C, 0xB9, 0xF4, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0x6D, 0xE9, 0x6B, /* 0x64-0x67 */ - 0xE9, 0x6C, 0xE5, 0x6E, 0xEC, 0xDC, 0xC0, 0xB0, /* 0x68-0x6B */ - 0xEC, 0xDB, 0xEF, 0xC5, 0xEF, 0xC6, 0xE9, 0x6E, /* 0x6C-0x6F */ - 0xF1, 0xFE, 0x00, 0x00, 0xA4, 0x7A, 0xA5, 0xAD, /* 0x70-0x73 */ - 0xA6, 0x7E, 0xC9, 0xDB, 0xA6, 0x7D, 0x00, 0x00, /* 0x74-0x77 */ - 0xA9, 0xAF, 0xB7, 0x46, 0x00, 0x00, 0xA4, 0xDB, /* 0x78-0x7B */ - 0xA5, 0xAE, 0xAB, 0xD5, 0xB4, 0x58, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xC9, 0x79, 0x00, 0x00, 0xC9, 0x7A, 0x00, 0x00, /* 0x80-0x83 */ - 0xC9, 0xDC, 0x00, 0x00, 0x00, 0x00, 0xA7, 0xC8, /* 0x84-0x87 */ - 0xCA, 0xD0, 0xCA, 0xCE, 0xA7, 0xC9, 0xCA, 0xCD, /* 0x88-0x8B */ - 0xCA, 0xCF, 0xCA, 0xD1, 0x00, 0x00, 0xA7, 0xC7, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0xA9, 0xB3, 0xA9, 0xB4, 0xA9, 0xB1, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xA9, 0xB0, 0xCE, 0xB8, /* 0x98-0x9B */ - 0xA9, 0xB2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xAB, 0xD6, 0x00, 0x00, 0xCE, 0xB7, 0xCE, 0xB9, /* 0xA0-0xA3 */ - 0xCE, 0xB6, 0xCE, 0xBA, 0xAB, 0xD7, 0xAE, 0x79, /* 0xA4-0xA7 */ - 0xD1, 0x75, 0x00, 0x00, 0xD1, 0x77, 0xAE, 0x77, /* 0xA8-0xAB */ - 0xD1, 0x78, 0xAE, 0x78, 0xD1, 0x76, 0x00, 0x00, /* 0xAC-0xAF */ - 0xCE, 0xB5, 0xD5, 0x47, 0xD5, 0x4A, 0xD5, 0x4B, /* 0xB0-0xB3 */ - 0xD5, 0x48, 0xB1, 0x67, 0xB1, 0x66, 0xB1, 0x64, /* 0xB4-0xB7 */ - 0xB1, 0x65, 0xD5, 0x49, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xB1, 0x68, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xB4, 0x5A, 0xB4, 0x5B, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xB4, 0x5C, 0xDD, 0x5D, 0xDD, 0x5F, 0xDD, 0x61, /* 0xC4-0xC7 */ - 0xB7, 0x48, 0xB7, 0x47, 0xB4, 0x59, 0xDD, 0x60, /* 0xC8-0xCB */ - 0xDD, 0x5E, 0x00, 0x00, 0xE1, 0xB8, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xE1, 0xB6, 0xE1, 0xBC, 0xB9, 0xF8, /* 0xD0-0xD3 */ - 0xE1, 0xBD, 0xE1, 0xBA, 0xB9, 0xF9, 0xE1, 0xB7, /* 0xD4-0xD7 */ - 0xE1, 0xB5, 0xE1, 0xBB, 0xBC, 0x70, 0xE5, 0x73, /* 0xD8-0xDB */ - 0xE1, 0xB9, 0xBC, 0x72, 0xE5, 0x74, 0xBC, 0x71, /* 0xDC-0xDF */ - 0xBC, 0x74, 0xE5, 0x75, 0xBC, 0x6F, 0xBC, 0x73, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xE9, 0x73, 0xE9, 0x71, 0xE9, 0x70, /* 0xE4-0xE7 */ - 0xE9, 0x72, 0xE9, 0x6F, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xC3, 0x66, 0x00, 0x00, 0xF4, 0x46, 0xF4, 0x47, /* 0xEC-0xEF */ - 0x00, 0x00, 0xF5, 0xCB, 0xF6, 0xDF, 0xC6, 0x55, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xA9, 0xB5, 0xA7, 0xCA, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0xAB, 0xD8, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0xA4, 0x7B, 0xA4, 0xDC, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_5F[512] = { - 0x00, 0x00, 0xA5, 0xAF, 0xC9, 0xDD, 0x00, 0x00, /* 0x00-0x03 */ - 0xA7, 0xCB, 0xCA, 0xD2, 0x00, 0x00, 0xCE, 0xBB, /* 0x04-0x07 */ - 0xAB, 0xD9, 0x00, 0x00, 0xB9, 0xFA, 0xA4, 0x7C, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xA1, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xB7, 0x49, 0xA4, 0x7D, /* 0x10-0x13 */ - 0xA4, 0xDD, 0xA4, 0xDE, 0x00, 0x00, 0xA5, 0xB1, /* 0x14-0x17 */ - 0xA5, 0xB0, 0x00, 0x00, 0xC9, 0xDE, 0xA6, 0xA2, /* 0x18-0x1B */ - 0x00, 0x00, 0xCA, 0xD3, 0x00, 0x00, 0xA7, 0xCC, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0xCC, 0x71, 0xCC, 0x72, /* 0x20-0x23 */ - 0xCC, 0x73, 0x00, 0x00, 0xA9, 0xB6, 0xA9, 0xB7, /* 0x24-0x27 */ - 0xCC, 0x70, 0xA9, 0xB8, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0xAB, 0xDA, 0xCE, 0xBC, 0x00, 0x00, /* 0x2C-0x2F */ - 0xD1, 0x7A, 0xAE, 0x7A, 0x00, 0x00, 0xD1, 0x79, /* 0x30-0x33 */ - 0x00, 0x00, 0xB1, 0x69, 0xD5, 0x4C, 0xB1, 0x6A, /* 0x34-0x37 */ - 0xD5, 0x4D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xB4, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xDD, 0x62, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xBF, /* 0x40-0x43 */ - 0xE1, 0xBE, 0x00, 0x00, 0xB9, 0xFB, 0x00, 0x00, /* 0x44-0x47 */ - 0xBC, 0x75, 0xE5, 0x76, 0xBE, 0xCA, 0xE9, 0x74, /* 0x48-0x4B */ - 0xC0, 0xB1, 0x00, 0x00, 0xC5, 0x73, 0xF7, 0xD8, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xCC, 0x74, 0x00, 0x00, 0xCE, 0xBD, 0xB1, 0x6B, /* 0x54-0x57 */ - 0xD8, 0xF4, 0xB7, 0x4A, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0xC2, 0x55, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xA7, 0xCE, 0x00, 0x00, /* 0x60-0x63 */ - 0xA7, 0xCD, 0xAB, 0xDB, 0x00, 0x00, 0xD1, 0x7B, /* 0x64-0x67 */ - 0x00, 0x00, 0xB1, 0x6D, 0xB3, 0x43, 0xB1, 0x6E, /* 0x68-0x6B */ - 0xB1, 0x6C, 0xB4, 0x5E, 0x00, 0x00, 0xE1, 0xC0, /* 0x6C-0x6F */ - 0xB9, 0xFC, 0xBC, 0x76, 0x00, 0x00, 0xC9, 0x4C, /* 0x70-0x73 */ - 0xC9, 0xDF, 0x00, 0x00, 0xCA, 0xD5, 0xA7, 0xCF, /* 0x74-0x77 */ - 0xCA, 0xD4, 0xA7, 0xD0, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xA9, 0xBC, 0xCC, 0x77, 0xCC, 0x76, 0xA9, 0xBB, /* 0x7C-0x7F */ - - 0xA9, 0xB9, 0xA9, 0xBA, 0xCC, 0x75, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0xAB, 0xDD, 0xCE, 0xBE, 0xAB, 0xE0, /* 0x84-0x87 */ - 0xAB, 0xDC, 0xAB, 0xE2, 0xAB, 0xDE, 0xAB, 0xDF, /* 0x88-0x8B */ - 0xAB, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xAE, 0x7D, 0xAE, 0x7C, 0xAE, 0x7B, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0x4F, 0xB1, 0x6F, /* 0x94-0x97 */ - 0xB1, 0x72, 0xB1, 0x70, 0x00, 0x00, 0xD5, 0x4E, /* 0x98-0x9B */ - 0xB1, 0x75, 0x00, 0x00, 0xB1, 0x71, 0xD5, 0x50, /* 0x9C-0x9F */ - 0xB1, 0x74, 0xB1, 0x73, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xD8, 0xF6, 0xD8, 0xF5, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xB4, 0x61, 0xB4, 0x5F, 0xB4, 0x60, 0xD8, 0xF7, /* 0xA8-0xAB */ - 0xB7, 0x4B, 0xDD, 0x64, 0xB7, 0x4C, 0xDD, 0x63, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0x77, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xBC, 0x78, 0xE1, 0xC1, 0xBC, 0x77, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xB9, 0xFD, 0x00, 0x00, 0xEC, 0xDE, /* 0xB8-0xBB */ - 0xE9, 0x75, 0xC0, 0xB2, 0xEC, 0xDD, 0xF2, 0x40, /* 0xBC-0xBF */ - 0xF4, 0x48, 0xF4, 0x49, 0x00, 0x00, 0xA4, 0xDF, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xA5, 0xB2, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xC9, 0x7B, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0xA7, 0xD2, 0xA7, 0xD4, 0x00, 0x00, 0xC9, 0xE2, /* 0xCC-0xCF */ - 0xCA, 0xD8, 0xCA, 0xD7, 0xCA, 0xD6, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xC9, 0xE1, 0xC9, 0xE0, 0xA6, 0xA4, 0xA7, 0xD3, /* 0xD4-0xD7 */ - 0xA7, 0xD1, 0xA6, 0xA3, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0xA9, 0xBD, 0xCC, 0x78, 0x00, 0x00, /* 0xDC-0xDF */ - 0xA9, 0xBE, 0xCA, 0xDD, 0x00, 0x00, 0xCA, 0xDF, /* 0xE0-0xE3 */ - 0xCA, 0xDE, 0xCC, 0x79, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xCA, 0xDA, 0x00, 0x00, 0xA7, 0xD8, 0xA7, 0xD6, /* 0xE8-0xEB */ - 0x00, 0x00, 0xCA, 0xD9, 0xCA, 0xDB, 0xCA, 0xE1, /* 0xEC-0xEF */ - 0x00, 0x00, 0xA7, 0xD5, 0x00, 0x00, 0xCA, 0xDC, /* 0xF0-0xF3 */ - 0xCA, 0xE5, 0xA9, 0xC0, 0x00, 0x00, 0xCA, 0xE2, /* 0xF4-0xF7 */ - 0xA7, 0xD7, 0x00, 0x00, 0xCA, 0xE0, 0xCA, 0xE3, /* 0xF8-0xFB */ - 0x00, 0x00, 0xA9, 0xBF, 0x00, 0x00, 0xA9, 0xC1, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_60[512] = { - 0xCA, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xCC, 0xAF, 0xCC, 0xA2, 0xCC, 0x7E, /* 0x08-0x0B */ - 0xCC, 0xAE, 0xCC, 0xA9, 0xAB, 0xE7, 0xA9, 0xC2, /* 0x0C-0x0F */ - 0xCC, 0xAA, 0xCC, 0xAD, 0xAB, 0xE3, 0xCC, 0xAC, /* 0x10-0x13 */ - 0xA9, 0xC3, 0xA9, 0xC8, 0xA9, 0xC6, 0xCC, 0xA3, /* 0x14-0x17 */ - 0x00, 0x00, 0xCC, 0x7C, 0xCC, 0xA5, 0xA9, 0xCD, /* 0x18-0x1B */ - 0xCC, 0xB0, 0xAB, 0xE4, 0xCC, 0xA6, 0x00, 0x00, /* 0x1C-0x1F */ - 0xAB, 0xE5, 0xA9, 0xC9, 0xCC, 0xA8, 0x00, 0x00, /* 0x20-0x23 */ - 0xCE, 0xCD, 0xAB, 0xE6, 0xCC, 0x7B, 0xA9, 0xCA, /* 0x24-0x27 */ - 0xAB, 0xE8, 0xA9, 0xCB, 0xA9, 0xC7, 0xA9, 0xCC, /* 0x28-0x2B */ - 0xCC, 0xA7, 0xCC, 0x7A, 0xCC, 0xAB, 0xA9, 0xC4, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xCC, 0x7D, 0xCC, 0xA4, /* 0x30-0x33 */ - 0xCC, 0xA1, 0xA9, 0xC5, 0x00, 0x00, 0xCE, 0xBF, /* 0x34-0x37 */ - 0x00, 0x00, 0xCE, 0xC0, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xCE, 0xCA, 0xD1, 0xA1, 0xCE, 0xCB, 0xAB, 0xEE, /* 0x40-0x43 */ - 0xCE, 0xCE, 0xCE, 0xC4, 0xAB, 0xED, 0xCE, 0xC6, /* 0x44-0x47 */ - 0x00, 0x00, 0xCE, 0xC7, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xCE, 0xC9, 0xAB, 0xE9, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xAE, 0xA3, 0x00, 0x00, 0xF9, 0xDA, 0xCE, 0xC5, /* 0x50-0x53 */ - 0xCE, 0xC1, 0xAE, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xCE, 0xCF, 0xAE, 0x7E, 0xD1, 0x7D, 0xCE, 0xC8, /* 0x58-0x5B */ - 0x00, 0x00, 0xD1, 0x7C, 0xCE, 0xC3, 0xCE, 0xCC, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xAB, 0xEC, 0xAE, 0xA1, /* 0x60-0x63 */ - 0xAB, 0xF2, 0xAE, 0xA2, 0xCE, 0xD0, 0xD1, 0x7E, /* 0x64-0x67 */ - 0xAB, 0xEB, 0xAE, 0xA6, 0xAB, 0xF1, 0xAB, 0xF0, /* 0x68-0x6B */ - 0xAB, 0xEF, 0xAE, 0xA5, 0xCE, 0xD1, 0xAE, 0xA7, /* 0x6C-0x6F */ - 0xAB, 0xEA, 0x00, 0x00, 0xCE, 0xC2, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB1, 0x76, /* 0x7C-0x7F */ - - 0xD1, 0xA4, 0xD1, 0xA6, 0x00, 0x00, 0xD1, 0xA8, /* 0x80-0x83 */ - 0xAE, 0xA8, 0xAE, 0xAE, 0xD5, 0x53, 0xD1, 0xAC, /* 0x84-0x87 */ - 0xD1, 0xA3, 0xB1, 0x78, 0xD5, 0x51, 0x00, 0x00, /* 0x88-0x8B */ - 0xAE, 0xAD, 0xAE, 0xAB, 0xD1, 0xAE, 0x00, 0x00, /* 0x8C-0x8F */ - 0xD5, 0x52, 0x00, 0x00, 0xD1, 0xA5, 0x00, 0x00, /* 0x90-0x93 */ - 0xAE, 0xAC, 0xD1, 0xA9, 0xAE, 0xAF, 0xD1, 0xAB, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xAE, 0xAA, 0xD1, 0xAA, /* 0x98-0x9B */ - 0xD1, 0xAD, 0xD1, 0xA7, 0x00, 0x00, 0xAE, 0xA9, /* 0x9C-0x9F */ - 0xB1, 0x79, 0x00, 0x00, 0xD1, 0xA2, 0xB1, 0x77, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xB1, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0xD5, 0x55, 0xD5, 0x5E, 0xB4, 0x64, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xB1, 0x7C, 0xB1, 0xA3, 0xB4, 0x65, 0xD5, 0x60, /* 0xB4-0xB7 */ - 0xB1, 0xAA, 0xD8, 0xF9, 0xD5, 0x56, 0xB1, 0xA2, /* 0xB8-0xBB */ - 0xB1, 0xA5, 0xB1, 0x7E, 0xD5, 0x54, 0xD5, 0x62, /* 0xBC-0xBF */ - 0xD5, 0x65, 0xD9, 0x49, 0x00, 0x00, 0xD5, 0x63, /* 0xC0-0xC3 */ - 0xD8, 0xFD, 0xB1, 0xA1, 0xB1, 0xA8, 0xB1, 0xAC, /* 0xC4-0xC7 */ - 0xD5, 0x5D, 0xD8, 0xF8, 0xD5, 0x61, 0xB1, 0x7B, /* 0xC8-0xCB */ - 0xD8, 0xFA, 0xD5, 0x64, 0xD8, 0xFC, 0xD5, 0x59, /* 0xCC-0xCF */ - 0x00, 0x00, 0xB4, 0x62, 0x00, 0x00, 0xD5, 0x57, /* 0xD0-0xD3 */ - 0xD5, 0x58, 0xB1, 0xA7, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xB1, 0xA6, 0xD5, 0x5B, 0xB1, 0xAB, 0xD5, 0x5F, /* 0xD8-0xDB */ - 0xB1, 0xA4, 0xD5, 0x5C, 0x00, 0x00, 0xB1, 0xA9, /* 0xDC-0xDF */ - 0xB4, 0x66, 0xB4, 0x63, 0xD8, 0xFB, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xD5, 0x5A, 0x00, 0x00, 0xB1, 0x7D, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xB4, 0x6B, 0xB4, 0x6F, 0xD9, 0x40, 0xB7, 0x51, /* 0xF0-0xF3 */ - 0xB4, 0x6D, 0xD9, 0x44, 0xB4, 0x71, 0xDD, 0x65, /* 0xF4-0xF7 */ - 0xD9, 0x46, 0xB7, 0x53, 0xB4, 0x69, 0xB4, 0x6C, /* 0xF8-0xFB */ - 0xD9, 0x47, 0x00, 0x00, 0xD9, 0x48, 0xD9, 0x4E, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_61[512] = { - 0xB4, 0x73, 0xB7, 0x54, 0x00, 0x00, 0xD9, 0x4A, /* 0x00-0x03 */ - 0xD9, 0x4F, 0xD9, 0x43, 0xB7, 0x5E, 0x00, 0x00, /* 0x04-0x07 */ - 0xB7, 0x55, 0xB4, 0x72, 0xD9, 0x41, 0xD9, 0x50, /* 0x08-0x0B */ - 0x00, 0x00, 0xB7, 0x5D, 0xB4, 0x70, 0xB7, 0x4E, /* 0x0C-0x0F */ - 0xD9, 0x4D, 0x00, 0x00, 0xB4, 0x74, 0xD9, 0x45, /* 0x10-0x13 */ - 0xD8, 0xFE, 0xB4, 0x6A, 0xD9, 0x42, 0x00, 0x00, /* 0x14-0x17 */ - 0xD9, 0x4B, 0x00, 0x00, 0xB7, 0x4D, 0xB7, 0x52, /* 0x18-0x1B */ - 0xB4, 0x67, 0xD9, 0x4C, 0x00, 0x00, 0xB7, 0x50, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x68, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB7, 0x5C, /* 0x24-0x27 */ - 0xE1, 0xC3, 0xDD, 0x70, 0x00, 0x00, 0xDD, 0x68, /* 0x28-0x2B */ - 0xE1, 0xC2, 0x00, 0x00, 0xDD, 0x6C, 0xDD, 0x6E, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xDD, 0x6B, 0x00, 0x00, /* 0x30-0x33 */ - 0xB7, 0x5B, 0x00, 0x00, 0xDD, 0x6A, 0xB7, 0x5F, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xD2, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xB7, 0x5A, 0xBA, 0x40, /* 0x3C-0x3F */ - 0xDD, 0x71, 0xE1, 0xC4, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xB7, 0x58, 0xDD, 0x69, 0xDD, 0x6D, 0xB9, 0xFE, /* 0x44-0x47 */ - 0xB7, 0x4F, 0xDD, 0x66, 0xDD, 0x67, 0xBA, 0x41, /* 0x48-0x4B */ - 0xB7, 0x57, 0xB7, 0x59, 0xB7, 0x56, 0xDD, 0x6F, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xC8, 0xE1, 0xC9, /* 0x50-0x53 */ - 0xE1, 0xCE, 0xBC, 0x7D, 0xE1, 0xD5, 0x00, 0x00, /* 0x54-0x57 */ - 0xBA, 0x47, 0x00, 0x00, 0xBA, 0x46, 0xE1, 0xD0, /* 0x58-0x5B */ - 0x00, 0x00, 0xBC, 0x7C, 0xE1, 0xC5, 0xBA, 0x45, /* 0x5C-0x5F */ - 0x00, 0x00, 0xE1, 0xD4, 0xBA, 0x43, 0xBA, 0x44, /* 0x60-0x63 */ - 0x00, 0x00, 0xE1, 0xD1, 0xE5, 0xAA, 0xBC, 0x7A, /* 0x64-0x67 */ - 0xB4, 0x6E, 0x00, 0x00, 0xE1, 0xD3, 0xBC, 0xA3, /* 0x68-0x6B */ - 0xE1, 0xCB, 0x00, 0x00, 0xBC, 0x7B, 0x00, 0x00, /* 0x6C-0x6F */ - 0xBC, 0xA2, 0xE1, 0xC6, 0xE1, 0xCA, 0xE1, 0xC7, /* 0x70-0x73 */ - 0xE1, 0xCD, 0xBA, 0x48, 0xBC, 0x79, 0xBA, 0x42, /* 0x74-0x77 */ - 0x00, 0x00, 0xE5, 0x7A, 0xE1, 0xCF, 0x00, 0x00, /* 0x78-0x7B */ - 0xBC, 0xA1, 0x00, 0x00, 0xBC, 0xA4, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xE1, 0xCC, 0x00, 0x00, 0xBC, 0x7E, 0xE5, 0x79, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0xE5, 0x7E, 0xBE, 0xCE, 0xE5, 0x78, /* 0x88-0x8B */ - 0xE9, 0xA3, 0xE5, 0xA9, 0xBC, 0xA8, 0x00, 0x00, /* 0x8C-0x8F */ - 0xBC, 0xA6, 0xBE, 0xCC, 0xE5, 0xA6, 0xE5, 0xA2, /* 0x90-0x93 */ - 0xBC, 0xAC, 0x00, 0x00, 0xE9, 0x78, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xBC, 0xAA, 0xE5, 0xA1, /* 0x98-0x9B */ - 0x00, 0x00, 0xE9, 0x76, 0x00, 0x00, 0xE5, 0xA5, /* 0x9C-0x9F */ - 0x00, 0x00, 0xE5, 0xA8, 0xE5, 0x7D, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xBC, 0xAB, 0x00, 0x00, 0x00, 0x00, 0xBC, 0xA5, /* 0xA4-0xA7 */ - 0xE9, 0x77, 0xBE, 0xCD, 0xE5, 0xA7, 0xBC, 0xA7, /* 0xA8-0xAB */ - 0xBC, 0xA9, 0xE5, 0xA4, 0xBC, 0xAD, 0xE5, 0xA3, /* 0xAC-0xAF */ - 0xE5, 0x7C, 0xE5, 0x7B, 0xBE, 0xCB, 0xE5, 0xAB, /* 0xB0-0xB3 */ - 0xE9, 0x7A, 0xEC, 0xE0, 0xBE, 0xD0, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xE9, 0xA2, 0x00, 0x00, 0xE9, 0x7E, 0x00, 0x00, /* 0xB8-0xBB */ - 0xEC, 0xE1, 0x00, 0x00, 0xBE, 0xD1, 0xE9, 0xA1, /* 0xBC-0xBF */ - 0x00, 0x00, 0xE9, 0x7C, 0xC0, 0xB4, 0xEC, 0xDF, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xE9, 0x79, 0xE9, 0x7B, 0xC0, 0xB5, /* 0xC4-0xC7 */ - 0xBE, 0xD3, 0xC0, 0xB3, 0xBE, 0xD2, 0xC0, 0xB7, /* 0xC8-0xCB */ - 0xE9, 0x7D, 0xBE, 0xCF, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0xCF, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xEF, 0xC7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xEC, 0xE7, 0xEF, 0xC8, /* 0xDC-0xDF */ - 0xEC, 0xE3, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x56, /* 0xE0-0xE3 */ - 0xEC, 0xE5, 0xEC, 0xE4, 0xC0, 0xB6, 0xEC, 0xE2, /* 0xE4-0xE7 */ - 0xEC, 0xE6, 0xEF, 0xD0, 0xEF, 0xCC, 0xEF, 0xCE, /* 0xE8-0xEB */ - 0x00, 0x00, 0xEF, 0xC9, 0xEF, 0xCA, 0x00, 0x00, /* 0xEC-0xEF */ - 0xEF, 0xCD, 0xEF, 0xCB, 0xC3, 0x67, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xC3, 0x6A, 0xC3, 0x69, 0xC3, 0x68, /* 0xF4-0xF7 */ - 0xC4, 0x61, 0xF4, 0x4A, 0xC4, 0x62, 0xF2, 0x41, /* 0xF8-0xFB */ - 0xC4, 0xDF, 0xF5, 0xCC, 0xC4, 0xE0, 0xC5, 0x74, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_62[512] = { - 0xC5, 0xCA, 0xF7, 0xD9, 0x00, 0x00, 0xF7, 0xDA, /* 0x00-0x03 */ - 0xF7, 0xDB, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xBA, /* 0x04-0x07 */ - 0xA4, 0xE0, 0xC9, 0x7C, 0xA5, 0xB3, 0x00, 0x00, /* 0x08-0x0B */ - 0xA6, 0xA6, 0xA6, 0xA7, 0xA6, 0xA5, 0x00, 0x00, /* 0x0C-0x0F */ - 0xA6, 0xA8, 0xA7, 0xDA, 0xA7, 0xD9, 0x00, 0x00, /* 0x10-0x13 */ - 0xCC, 0xB1, 0xA9, 0xCF, 0xA9, 0xCE, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xD1, 0xAF, 0xB1, 0xAD, 0xB1, 0xAE, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB4, 0x75, /* 0x1C-0x1F */ - 0xDD, 0x72, 0xB7, 0x60, 0xB7, 0x61, 0xDD, 0x74, /* 0x20-0x23 */ - 0xDD, 0x76, 0xDD, 0x75, 0x00, 0x00, 0xE1, 0xD7, /* 0x24-0x27 */ - 0x00, 0x00, 0xE1, 0xD6, 0xBA, 0x49, 0xE1, 0xD8, /* 0x28-0x2B */ - 0x00, 0x00, 0xE5, 0xAC, 0xBC, 0xAE, 0x00, 0x00, /* 0x2C-0x2F */ - 0xBE, 0xD4, 0x00, 0x00, 0xC0, 0xB8, 0xC2, 0x57, /* 0x30-0x33 */ - 0xC0, 0xB9, 0x00, 0x00, 0xA4, 0xE1, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0xE6, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xCC, 0xB2, 0xA9, 0xD1, 0xA9, 0xD0, /* 0x3C-0x3F */ - 0xA9, 0xD2, 0xAB, 0xF3, 0xCE, 0xD2, 0xCE, 0xD3, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xD1, 0xB0, 0xAE, 0xB0, /* 0x44-0x47 */ - 0xB1, 0xAF, 0xB4, 0x76, 0xD9, 0x51, 0xA4, 0xE2, /* 0x48-0x4B */ - 0x00, 0x00, 0xA4, 0x7E, 0xA4, 0xE3, 0x00, 0x00, /* 0x4C-0x4F */ - 0xC9, 0x7D, 0xA5, 0xB7, 0xA5, 0xB6, 0xA5, 0xB4, /* 0x50-0x53 */ - 0xA5, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xA6, 0xAB, 0xC9, 0xE9, 0xC9, 0xEB, 0xA6, 0xAA, /* 0x58-0x5B */ - 0xC9, 0xE3, 0x00, 0x00, 0xC9, 0xE4, 0x00, 0x00, /* 0x5C-0x5F */ - 0xC9, 0xEA, 0xC9, 0xE6, 0xC9, 0xE8, 0xA6, 0xA9, /* 0x60-0x63 */ - 0xC9, 0xE5, 0xC9, 0xEC, 0xC9, 0xE7, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0xA7, 0xE1, 0xA7, 0xEA, 0xA7, 0xE8, /* 0x6C-0x6F */ - 0xCA, 0xF0, 0xCA, 0xED, 0xCA, 0xF5, 0xA7, 0xE6, /* 0x70-0x73 */ - 0xCA, 0xF6, 0x00, 0x00, 0xA7, 0xDF, 0xCA, 0xF3, /* 0x74-0x77 */ - 0x00, 0x00, 0xA7, 0xE5, 0xCA, 0xEF, 0xCA, 0xEE, /* 0x78-0x7B */ - 0xA7, 0xE3, 0xCA, 0xF4, 0xA7, 0xE4, 0xA9, 0xD3, /* 0x7C-0x7F */ - - 0xA7, 0xDE, 0xCA, 0xF1, 0x00, 0x00, 0xCA, 0xE7, /* 0x80-0x83 */ - 0xA7, 0xDB, 0x00, 0x00, 0xA7, 0xEE, 0xCA, 0xEC, /* 0x84-0x87 */ - 0xCA, 0xF2, 0xA7, 0xE0, 0xA7, 0xE2, 0x00, 0x00, /* 0x88-0x8B */ - 0xCA, 0xE8, 0x00, 0x00, 0xCA, 0xE9, 0xCA, 0xEA, /* 0x8C-0x8F */ - 0x00, 0x00, 0xA7, 0xED, 0xA7, 0xE7, 0xA7, 0xEC, /* 0x90-0x93 */ - 0xCA, 0xEB, 0xA7, 0xEB, 0xA7, 0xDD, 0xA7, 0xDC, /* 0x94-0x97 */ - 0xA7, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xA9, 0xE1, 0xCC, 0xBE, 0xCC, 0xB7, 0xA9, 0xDC, /* 0xA8-0xAB */ - 0xA9, 0xEF, 0xCC, 0xB3, 0xCC, 0xBA, 0xCC, 0xBC, /* 0xAC-0xAF */ - 0xCC, 0xBF, 0xA9, 0xEA, 0x00, 0x00, 0xCC, 0xBB, /* 0xB0-0xB3 */ - 0xCC, 0xB4, 0xA9, 0xE8, 0xCC, 0xB8, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xCC, 0xC0, 0xA9, 0xD9, 0x00, 0x00, 0xCC, 0xBD, /* 0xB8-0xBB */ - 0xA9, 0xE3, 0xA9, 0xE2, 0xCC, 0xB6, 0xA9, 0xD7, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xA9, 0xD8, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xA9, 0xD6, 0x00, 0x00, 0xA9, 0xEE, 0xA9, 0xE6, /* 0xC4-0xC7 */ - 0xA9, 0xE0, 0xA9, 0xD4, 0xCC, 0xB9, 0xA9, 0xDF, /* 0xC8-0xCB */ - 0xA9, 0xD5, 0xA9, 0xE7, 0xA9, 0xF0, 0xCE, 0xD4, /* 0xCC-0xCF */ - 0xA9, 0xE4, 0xCC, 0xB5, 0xA9, 0xDA, 0xA9, 0xDD, /* 0xD0-0xD3 */ - 0xA9, 0xDE, 0x00, 0x00, 0xA9, 0xEC, 0xA9, 0xED, /* 0xD4-0xD7 */ - 0xA9, 0xEB, 0xA9, 0xE5, 0xA9, 0xE9, 0xA9, 0xDB, /* 0xD8-0xDB */ - 0xAB, 0xF4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xDA, /* 0xE8-0xEB */ - 0xAC, 0x41, 0xAB, 0xF8, 0xAB, 0xFA, 0xAC, 0x40, /* 0xEC-0xEF */ - 0xCE, 0xE6, 0xAB, 0xFD, 0xD1, 0xB1, 0xAE, 0xB1, /* 0xF0-0xF3 */ - 0xAC, 0x43, 0xCE, 0xD7, 0xCE, 0xDF, 0xAB, 0xFE, /* 0xF4-0xF7 */ - 0xCE, 0xDE, 0xCE, 0xDB, 0xCE, 0xE3, 0xCE, 0xE5, /* 0xF8-0xFB */ - 0xAB, 0xF7, 0xAB, 0xFB, 0xAC, 0x42, 0xAE, 0xB3, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_63[512] = { - 0xCE, 0xE0, 0xAB, 0xF9, 0xAC, 0x45, 0xCE, 0xD9, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0xFC, /* 0x04-0x07 */ - 0xAE, 0xB2, 0xAB, 0xF6, 0x00, 0x00, 0xCE, 0xD6, /* 0x08-0x0B */ - 0xCE, 0xDD, 0xCE, 0xD5, 0xCE, 0xD8, 0xCE, 0xDC, /* 0x0C-0x0F */ - 0xD1, 0xB2, 0xAC, 0x44, 0x00, 0x00, 0xCE, 0xE1, /* 0x10-0x13 */ - 0xCE, 0xE2, 0xCE, 0xE4, 0xAB, 0xF5, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xAE, 0xC1, 0xD1, 0xBE, 0xAE, 0xBF, 0xAE, 0xC0, /* 0x28-0x2B */ - 0xD1, 0xB4, 0xD1, 0xC4, 0x00, 0x00, 0xAE, 0xB6, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xD5, 0x66, 0xD1, 0xC6, /* 0x30-0x33 */ - 0xD1, 0xC0, 0x00, 0x00, 0xD1, 0xB7, 0x00, 0x00, /* 0x34-0x37 */ - 0xD1, 0xC9, 0xD1, 0xBA, 0xAE, 0xBC, 0xD5, 0x7D, /* 0x38-0x3B */ - 0xD1, 0xBD, 0xAE, 0xBE, 0xAE, 0xB5, 0x00, 0x00, /* 0x3C-0x3F */ - 0xD1, 0xCB, 0xD1, 0xBF, 0xAE, 0xB8, 0xD1, 0xB8, /* 0x40-0x43 */ - 0xD1, 0xB5, 0xD1, 0xB6, 0xAE, 0xB9, 0xD1, 0xC5, /* 0x44-0x47 */ - 0xD1, 0xCC, 0xAE, 0xBB, 0xD1, 0xBC, 0xD1, 0xBB, /* 0x48-0x4B */ - 0xAE, 0xC3, 0xAE, 0xC2, 0xAE, 0xB4, 0xAE, 0xBA, /* 0x4C-0x4F */ - 0xAE, 0xBD, 0xD1, 0xC8, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xD1, 0xC2, 0xAE, 0xB7, 0xD1, 0xB3, 0xD1, 0xCA, /* 0x54-0x57 */ - 0xD1, 0xC1, 0xD1, 0xC3, 0xD1, 0xC7, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0xD5, 0x67, 0x00, 0x00, 0xB1, 0xB7, /* 0x64-0x67 */ - 0xB1, 0xCB, 0xB1, 0xCA, 0x00, 0x00, 0xB1, 0xBF, /* 0x68-0x6B */ - 0x00, 0x00, 0xD5, 0x79, 0xD5, 0x75, 0xD5, 0x72, /* 0x6C-0x6F */ - 0xD5, 0xA6, 0xB1, 0xBA, 0xB1, 0xB2, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xD5, 0x77, 0xB4, 0xA8, 0xB1, 0xB6, /* 0x74-0x77 */ - 0xD5, 0xA1, 0x00, 0x00, 0xB1, 0xCC, 0xB1, 0xC9, /* 0x78-0x7B */ - 0xD5, 0x7B, 0xD5, 0x6A, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xB1, 0xC8, 0xD5, 0xA3, 0xD5, 0x69, 0xB1, 0xBD, /* 0x80-0x83 */ - 0xB1, 0xC1, 0xD5, 0xA2, 0x00, 0x00, 0xD5, 0x73, /* 0x84-0x87 */ - 0xB1, 0xC2, 0xB1, 0xBC, 0xD5, 0x68, 0x00, 0x00, /* 0x88-0x8B */ - 0xB4, 0x78, 0xD5, 0xA5, 0xD5, 0x71, 0xB1, 0xC7, /* 0x8C-0x8F */ - 0xD5, 0x74, 0xD5, 0xA4, 0xB1, 0xC6, 0x00, 0x00, /* 0x90-0x93 */ - 0xD9, 0x52, 0x00, 0x00, 0xB1, 0xB3, 0xD5, 0x6F, /* 0x94-0x97 */ - 0xB1, 0xB8, 0xB1, 0xC3, 0x00, 0x00, 0xB1, 0xBE, /* 0x98-0x9B */ - 0xD5, 0x78, 0xD5, 0x6E, 0xD5, 0x6C, 0xD5, 0x7E, /* 0x9C-0x9F */ - 0xB1, 0xB0, 0xB1, 0xC4, 0xB1, 0xB4, 0xB4, 0x77, /* 0xA0-0xA3 */ - 0xD5, 0x7C, 0xB1, 0xB5, 0x00, 0x00, 0xB1, 0xB1, /* 0xA4-0xA7 */ - 0xB1, 0xC0, 0xB1, 0xBB, 0xB1, 0xB9, 0xD5, 0x70, /* 0xA8-0xAB */ - 0xB1, 0xC5, 0xD5, 0x6D, 0xD5, 0x7A, 0xD5, 0x76, /* 0xAC-0xAF */ - 0xD9, 0x54, 0xD9, 0x53, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xD5, 0x6B, 0xD9, 0x64, 0x00, 0x00, /* 0xBC-0xBF */ - 0xB4, 0x7A, 0x00, 0x00, 0xD9, 0x6A, 0xD9, 0x59, /* 0xC0-0xC3 */ - 0xD9, 0x67, 0xDD, 0x77, 0xB4, 0x7D, 0xD9, 0x6B, /* 0xC4-0xC7 */ - 0xD9, 0x6E, 0xB4, 0x7C, 0xD9, 0x5C, 0xD9, 0x6D, /* 0xC8-0xCB */ - 0xD9, 0x6C, 0xB4, 0x7E, 0xD9, 0x55, 0xB4, 0x79, /* 0xCC-0xCF */ - 0xB4, 0xA3, 0x00, 0x00, 0xB4, 0xA1, 0xD9, 0x69, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xD9, 0x5F, 0xB4, 0xA5, 0xD9, 0x70, /* 0xD4-0xD7 */ - 0xD9, 0x68, 0xD9, 0x71, 0xB4, 0xAD, 0xB4, 0xAB, /* 0xD8-0xDB */ - 0xD9, 0x66, 0xD9, 0x65, 0x00, 0x00, 0xD9, 0x63, /* 0xDC-0xDF */ - 0xD9, 0x5D, 0xB4, 0xA4, 0x00, 0x00, 0xB4, 0xA2, /* 0xE0-0xE3 */ - 0xD1, 0xB9, 0xD9, 0x56, 0x00, 0x00, 0xDD, 0xB7, /* 0xE4-0xE7 */ - 0xD9, 0x57, 0xB4, 0x7B, 0xB4, 0xAA, 0xDD, 0x79, /* 0xE8-0xEB */ - 0x00, 0x00, 0xB4, 0xA6, 0xB4, 0xA7, 0xD9, 0x58, /* 0xEC-0xEF */ - 0xD9, 0x6F, 0xDD, 0x78, 0xD9, 0x60, 0xD9, 0x5B, /* 0xF0-0xF3 */ - 0xB4, 0xA9, 0xD9, 0x61, 0xD9, 0x5E, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xB4, 0xAE, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_64[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xB7, 0x70, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xDD, 0x7C, 0xDD, 0xB1, 0xDD, 0xB6, /* 0x08-0x0B */ - 0xDD, 0xAA, 0xB7, 0x6C, 0xDD, 0xBB, 0xB7, 0x69, /* 0x0C-0x0F */ - 0xDD, 0x7A, 0x00, 0x00, 0xDD, 0x7B, 0xB7, 0x62, /* 0x10-0x13 */ - 0xB7, 0x6B, 0xDD, 0xA4, 0xB7, 0x6E, 0xB7, 0x6F, /* 0x14-0x17 */ - 0xDD, 0xA5, 0x00, 0x00, 0xDD, 0xB2, 0xDD, 0xB8, /* 0x18-0x1B */ - 0xB7, 0x6A, 0x00, 0x00, 0xB7, 0x64, 0xDD, 0xA3, /* 0x1C-0x1F */ - 0xDD, 0x7D, 0xDD, 0xBA, 0xDD, 0xA8, 0xDD, 0xA9, /* 0x20-0x23 */ - 0xDD, 0x7E, 0xDD, 0xB4, 0xDD, 0xAB, 0xDD, 0xB5, /* 0x24-0x27 */ - 0xDD, 0xAD, 0x00, 0x00, 0xB7, 0x65, 0xE1, 0xD9, /* 0x28-0x2B */ - 0xB7, 0x68, 0xB7, 0x66, 0xDD, 0xB9, 0xDD, 0xB0, /* 0x2C-0x2F */ - 0xDD, 0xAC, 0x00, 0x00, 0x00, 0x00, 0xDD, 0xA1, /* 0x30-0x33 */ - 0xBA, 0x53, 0xDD, 0xAF, 0xB7, 0x6D, 0xDD, 0xA7, /* 0x34-0x37 */ - 0x00, 0x00, 0xDD, 0xA6, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xB7, 0x67, 0xB7, 0x63, 0xE1, 0xEE, /* 0x3C-0x3F */ - 0xDD, 0xB3, 0xDD, 0xAE, 0x00, 0x00, 0xDD, 0xA2, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE1, 0xE9, /* 0x48-0x4B */ - 0x00, 0x00, 0xE1, 0xDA, 0xE1, 0xE5, 0x00, 0x00, /* 0x4C-0x4F */ - 0xE1, 0xEC, 0xBA, 0x51, 0xB4, 0xAC, 0xE1, 0xEA, /* 0x50-0x53 */ - 0xBA, 0x4C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xBA, 0x4B, 0xE1, 0xF1, 0x00, 0x00, 0xE1, 0xDB, /* 0x58-0x5B */ - 0xE1, 0xE8, 0xE1, 0xDC, 0xE1, 0xE7, 0xBA, 0x4F, /* 0x5C-0x5F */ - 0xE1, 0xEB, 0xD9, 0x62, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0xE1, 0xF2, 0xE1, 0xE3, 0xBA, 0x52, /* 0x64-0x67 */ - 0xE5, 0xBA, 0xBC, 0xAF, 0x00, 0x00, 0xE1, 0xF0, /* 0x68-0x6B */ - 0xE1, 0xEF, 0xBA, 0x54, 0xE5, 0xAD, 0xBC, 0xB0, /* 0x6C-0x6F */ - 0xE5, 0xAE, 0x00, 0x00, 0xE1, 0xDF, 0xE1, 0xE0, /* 0x70-0x73 */ - 0xE1, 0xDD, 0xE1, 0xE2, 0xE1, 0xDE, 0xE1, 0xF3, /* 0x74-0x77 */ - 0xBA, 0x4E, 0xBC, 0xB1, 0xBA, 0x50, 0xBA, 0x55, /* 0x78-0x7B */ - 0x00, 0x00, 0xE1, 0xE1, 0x00, 0x00, 0xE1, 0xED, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xE1, 0xE6, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0xE5, 0xB1, 0x00, 0x00, 0xBA, 0x4A, /* 0x84-0x87 */ - 0xBC, 0xB4, 0xE9, 0xAA, 0xE5, 0xB6, 0xE5, 0xB5, /* 0x88-0x8B */ - 0xE5, 0xB7, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xB4, /* 0x8C-0x8F */ - 0xBC, 0xB5, 0x00, 0x00, 0xBC, 0xBB, 0xBC, 0xB8, /* 0x90-0x93 */ - 0x00, 0x00, 0xBC, 0xB9, 0xE5, 0xAF, 0xE5, 0xB2, /* 0x94-0x97 */ - 0xE5, 0xBC, 0xBC, 0xC1, 0xBC, 0xBF, 0x00, 0x00, /* 0x98-0x9B */ - 0xE5, 0xB3, 0xD9, 0x5A, 0xBC, 0xB2, 0xE5, 0xB9, /* 0x9C-0x9F */ - 0xE5, 0xB0, 0x00, 0x00, 0xBC, 0xC2, 0xE5, 0xB8, /* 0xA0-0xA3 */ - 0xBA, 0x4D, 0xBC, 0xB7, 0xE1, 0xE4, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xBC, 0xBA, 0x00, 0x00, 0xBC, 0xBE, /* 0xA8-0xAB */ - 0xBC, 0xC0, 0xBC, 0xBD, 0xBC, 0xBC, 0x00, 0x00, /* 0xAC-0xAF */ - 0xBC, 0xB6, 0xE5, 0xBB, 0xBC, 0xB3, 0xBC, 0xC3, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xD8, /* 0xB8-0xBB */ - 0xBE, 0xD9, 0xE9, 0xA9, 0xBE, 0xE2, 0xBE, 0xDF, /* 0xBC-0xBF */ - 0x00, 0x00, 0xBE, 0xD6, 0xBE, 0xDD, 0xE9, 0xAB, /* 0xC0-0xC3 */ - 0xBE, 0xDB, 0xBE, 0xD5, 0x00, 0x00, 0xBE, 0xDC, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xE9, 0xA8, 0xC0, 0xBB, 0xBE, 0xD7, /* 0xC8-0xCB */ - 0x00, 0x00, 0xBE, 0xDE, 0xC0, 0xBA, 0xE9, 0xA7, /* 0xCC-0xCF */ - 0xE9, 0xA6, 0x00, 0x00, 0xBE, 0xE0, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xBE, 0xE1, 0x00, 0x00, 0xE9, 0xA5, 0xE9, 0xA4, /* 0xD4-0xD7 */ - 0xC0, 0xBC, 0xE9, 0xAE, 0xBE, 0xDA, 0xE9, 0xAC, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0xC0, 0xBD, 0x00, 0x00, 0xC0, 0xC2, 0xEC, 0xEA, /* 0xE0-0xE3 */ - 0xEC, 0xEC, 0x00, 0x00, 0xC0, 0xBF, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xEC, 0xED, 0xEC, 0xE9, 0x00, 0x00, 0xEC, 0xEB, /* 0xE8-0xEB */ - 0xC0, 0xC0, 0xC0, 0xC3, 0x00, 0x00, 0xEC, 0xE8, /* 0xEC-0xEF */ - 0xC0, 0xBE, 0xC0, 0xC1, 0xC2, 0x59, 0xE9, 0xAD, /* 0xF0-0xF3 */ - 0xC2, 0x58, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x5E, /* 0xF4-0xF7 */ - 0xEF, 0xD4, 0x00, 0x00, 0xC2, 0x5C, 0xC2, 0x5D, /* 0xF8-0xFB */ - 0xEF, 0xD7, 0xEF, 0xD3, 0xC2, 0x5A, 0xEF, 0xD1, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_65[512] = { - 0xC3, 0x6B, 0xEF, 0xD5, 0x00, 0x00, 0xEF, 0xD6, /* 0x00-0x03 */ - 0xEF, 0xD2, 0x00, 0x00, 0xC2, 0x5B, 0xF2, 0x42, /* 0x04-0x07 */ - 0x00, 0x00, 0xF2, 0x45, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0xF2, 0x46, 0xF2, 0x44, 0xF2, 0x47, 0xC3, 0x6C, /* 0x0C-0x0F */ - 0xF2, 0x43, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x4E, /* 0x10-0x13 */ - 0xC4, 0x64, 0xF4, 0x4D, 0xF4, 0x4C, 0xF4, 0x4B, /* 0x14-0x17 */ - 0xC4, 0x63, 0xC4, 0x65, 0x00, 0x00, 0xF5, 0xCD, /* 0x18-0x1B */ - 0xC4, 0xE2, 0xC4, 0xE1, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xF6, 0xE1, 0xF6, 0xE0, 0xF6, 0xE3, 0xC5, 0xCB, /* 0x20-0x23 */ - 0xC5, 0x75, 0xF7, 0xDD, 0xF6, 0xE2, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xF7, 0xDC, 0xC5, 0xCD, 0xC5, 0xCC, /* 0x28-0x2B */ - 0xC5, 0xF3, 0xF8, 0xA9, 0xF8, 0xEF, 0xA4, 0xE4, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xD9, 0x72, 0xE9, 0xAF, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xA6, 0xAC, 0xCA, 0xF7, /* 0x34-0x37 */ - 0xA7, 0xF1, 0xA7, 0xEF, 0x00, 0x00, 0xA7, 0xF0, /* 0x38-0x3B */ - 0x00, 0x00, 0xCC, 0xC1, 0xA9, 0xF1, 0xAC, 0x46, /* 0x3C-0x3F */ - 0x00, 0x00, 0xCE, 0xE7, 0x00, 0x00, 0xCE, 0xE8, /* 0x40-0x43 */ - 0x00, 0x00, 0xAC, 0x47, 0xD1, 0xCE, 0x00, 0x00, /* 0x44-0x47 */ - 0xAE, 0xC4, 0xAE, 0xC5, 0xD1, 0xCD, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB1, 0xD3, /* 0x4C-0x4F */ - 0x00, 0x00, 0xB1, 0xCF, 0x00, 0x00, 0xD5, 0xA7, /* 0x50-0x53 */ - 0xB1, 0xD6, 0xB1, 0xD5, 0xB1, 0xCE, 0xB1, 0xD1, /* 0x54-0x57 */ - 0xB1, 0xD4, 0xB1, 0xD0, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0xD9, 0x76, 0xB1, 0xCD, 0xB4, 0xAF, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xB4, 0xB1, 0xB4, 0xB2, /* 0x60-0x63 */ - 0xD9, 0x75, 0xD9, 0x78, 0xB4, 0xB0, 0xD9, 0x73, /* 0x64-0x67 */ - 0xD9, 0x77, 0x00, 0x00, 0xD9, 0x74, 0x00, 0x00, /* 0x68-0x6B */ - 0xB7, 0x71, 0x00, 0x00, 0x00, 0x00, 0xDD, 0xBC, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xBA, 0x56, 0xE1, 0xF4, /* 0x70-0x73 */ - 0xBE, 0xE3, 0xBC, 0xC4, 0xE5, 0xBD, 0xBC, 0xC5, /* 0x74-0x77 */ - 0xBC, 0xC6, 0xE5, 0xBF, 0xE5, 0xBE, 0xE5, 0xC0, /* 0x78-0x7B */ - 0xE9, 0xB1, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xB0, /* 0x7C-0x7F */ - - 0xEC, 0xEF, 0xEC, 0xEE, 0xC0, 0xC4, 0xC0, 0xC5, /* 0x80-0x83 */ - 0xF2, 0x48, 0x00, 0x00, 0x00, 0x00, 0xA4, 0xE5, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0xD9, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xB4, 0xB4, 0xB4, 0xB3, 0xDD, 0xBD, 0x00, 0x00, /* 0x90-0x93 */ - 0xEF, 0xD8, 0xC4, 0xE3, 0xF7, 0xDE, 0xA4, 0xE6, /* 0x94-0x97 */ - 0x00, 0x00, 0xAE, 0xC6, 0x00, 0x00, 0xB1, 0xD8, /* 0x98-0x9B */ - 0xB1, 0xD7, 0xD9, 0x7A, 0xD9, 0x7B, 0xB7, 0x72, /* 0x9C-0x9F */ - 0xE1, 0xF5, 0xBA, 0x57, 0xE9, 0xB2, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xA4, 0xE7, 0xA5, 0xB8, 0x00, 0x00, 0xA9, 0xF2, /* 0xA4-0xA7 */ - 0xCC, 0xC2, 0x00, 0x00, 0xCE, 0xE9, 0xAC, 0x48, /* 0xA8-0xAB */ - 0xB1, 0xD9, 0x00, 0x00, 0xD9, 0x7C, 0xB4, 0xB5, /* 0xAC-0xAF */ - 0xB7, 0x73, 0x00, 0x00, 0xE5, 0xC1, 0xE5, 0xC2, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xEC, 0xF0, 0xC2, 0x5F, /* 0xB4-0xB7 */ - 0xF8, 0xF0, 0xA4, 0xE8, 0x00, 0x00, 0xCC, 0xC3, /* 0xB8-0xBB */ - 0xA9, 0xF3, 0xAC, 0x49, 0x00, 0x00, 0xCE, 0xEA, /* 0xBC-0xBF */ - 0x00, 0x00, 0xAE, 0xC7, 0xD1, 0xD2, 0xD1, 0xD0, /* 0xC0-0xC3 */ - 0xD1, 0xD1, 0xAE, 0xC8, 0xD1, 0xCF, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB1, 0xDB, /* 0xC8-0xCB */ - 0xB1, 0xDC, 0xD5, 0xA8, 0xB1, 0xDD, 0xB1, 0xDA, /* 0xCC-0xCF */ - 0xD9, 0x7D, 0x00, 0x00, 0xD9, 0x7E, 0xDD, 0xBE, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xBA, 0x59, 0xBA, 0x58, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xEC, 0xF1, 0xEF, 0xD9, /* 0xD8-0xDB */ - 0x00, 0x00, 0xF2, 0x4A, 0xF2, 0x49, 0xF4, 0x4F, /* 0xDC-0xDF */ - 0x00, 0x00, 0xC9, 0x5E, 0xAC, 0x4A, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xA4, 0xE9, 0xA5, 0xB9, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xA6, 0xAE, 0xA6, 0xAD, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xA6, 0xAF, 0xA6, 0xB0, 0xC9, 0xEE, 0xC9, 0xED, /* 0xEC-0xEF */ - 0xCA, 0xF8, 0xA7, 0xF2, 0xCA, 0xFB, 0xCA, 0xFA, /* 0xF0-0xF3 */ - 0xCA, 0xF9, 0xCA, 0xFC, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0xA9, 0xF4, 0xCC, 0xC9, /* 0xF8-0xFB */ - 0xCC, 0xC5, 0xCC, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_66[512] = { - 0xA9, 0xFB, 0x00, 0x00, 0xA9, 0xF9, 0xCC, 0xCA, /* 0x00-0x03 */ - 0xCC, 0xC6, 0xCC, 0xCD, 0xA9, 0xF8, 0xAA, 0x40, /* 0x04-0x07 */ - 0xCC, 0xC8, 0xCC, 0xC4, 0xA9, 0xFE, 0xCC, 0xCB, /* 0x08-0x0B */ - 0xA9, 0xF7, 0xCC, 0xCC, 0xA9, 0xFA, 0xA9, 0xFC, /* 0x0C-0x0F */ - 0xCC, 0xD0, 0xCC, 0xCF, 0xCC, 0xC7, 0xA9, 0xF6, /* 0x10-0x13 */ - 0xA9, 0xF5, 0xA9, 0xFD, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xCE, 0xEF, 0xCE, 0xF5, 0x00, 0x00, 0xAC, 0x50, /* 0x1C-0x1F */ - 0xAC, 0x4D, 0xCE, 0xEC, 0xCE, 0xF1, 0x00, 0x00, /* 0x20-0x23 */ - 0xAC, 0x53, 0xAC, 0x4B, 0xCE, 0xF0, 0xAC, 0x4E, /* 0x24-0x27 */ - 0xAC, 0x51, 0x00, 0x00, 0x00, 0x00, 0xCE, 0xF3, /* 0x28-0x2B */ - 0x00, 0x00, 0xAC, 0x4C, 0xCE, 0xF8, 0xAC, 0x4F, /* 0x2C-0x2F */ - 0x00, 0x00, 0xAC, 0x52, 0xCE, 0xED, 0xCE, 0xF2, /* 0x30-0x33 */ - 0xCE, 0xF6, 0xCE, 0xEE, 0xCE, 0xEB, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0xCE, 0xF7, 0xCE, 0xF4, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xAE, 0xD0, 0xAE, 0xC9, 0xAE, 0xCC, /* 0x40-0x43 */ - 0x00, 0x00, 0xAE, 0xCF, 0x00, 0x00, 0xD1, 0xD5, /* 0x44-0x47 */ - 0x00, 0x00, 0xAE, 0xCA, 0xD1, 0xD3, 0x00, 0x00, /* 0x48-0x4B */ - 0xAE, 0xCE, 0x00, 0x00, 0x00, 0x00, 0xAE, 0xCB, /* 0x4C-0x4F */ - 0x00, 0x00, 0xD1, 0xD6, 0xAE, 0xCD, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xD5, 0xAC, 0xB1, 0xDF, 0xD5, 0xAB, /* 0x58-0x5B */ - 0xD5, 0xAD, 0xB1, 0xDE, 0xB1, 0xE3, 0xD1, 0xD4, /* 0x5C-0x5F */ - 0x00, 0x00, 0xD5, 0xAA, 0xD5, 0xAE, 0x00, 0x00, /* 0x60-0x63 */ - 0xB1, 0xE0, 0xD5, 0xA9, 0xB1, 0xE2, 0x00, 0x00, /* 0x64-0x67 */ - 0xB1, 0xE1, 0x00, 0x00, 0xD9, 0xA7, 0x00, 0x00, /* 0x68-0x6B */ - 0xD9, 0xA2, 0x00, 0x00, 0xB4, 0xB6, 0xB4, 0xBA, /* 0x6C-0x6F */ - 0xB4, 0xB7, 0xD9, 0xA5, 0xD9, 0xA8, 0x00, 0x00, /* 0x70-0x73 */ - 0xB4, 0xB8, 0x00, 0x00, 0xB4, 0xB9, 0xB4, 0xBE, /* 0x74-0x77 */ - 0xDD, 0xC7, 0xD9, 0xA6, 0xB4, 0xBC, 0xD9, 0xA3, /* 0x78-0x7B */ - 0xD9, 0xA1, 0x00, 0x00, 0xB4, 0xBD, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xD9, 0xA4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xB7, 0x79, 0x00, 0x00, 0xDD, 0xBF, 0xB7, 0x76, /* 0x84-0x87 */ - 0xB7, 0x77, 0xB7, 0x75, 0xDD, 0xC4, 0xDD, 0xC3, /* 0x88-0x8B */ - 0xDD, 0xC0, 0xB7, 0x7B, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xDD, 0xC2, 0xB4, 0xBB, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xDD, 0xC6, 0xDD, 0xC1, 0xB7, 0x78, 0xB7, 0x74, /* 0x94-0x97 */ - 0xB7, 0x7A, 0xDD, 0xC5, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xBA, 0x5C, 0x00, 0x00, 0xE1, 0xF8, /* 0x9C-0x9F */ - 0xE1, 0xF7, 0xE1, 0xF6, 0xBA, 0x5A, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xBA, 0x5B, 0xE5, 0xC5, 0xE5, 0xC8, 0xBC, 0xC8, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xBC, 0xC7, 0xE5, 0xC9, /* 0xAC-0xAF */ - 0xE5, 0xC4, 0xBC, 0xCA, 0xE5, 0xC6, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xBC, 0xC9, 0xE5, 0xC3, 0x00, 0x00, 0xE5, 0xC7, /* 0xB4-0xB7 */ - 0xBE, 0xE9, 0xBE, 0xE6, 0xE9, 0xBB, 0xE9, 0xBA, /* 0xB8-0xBB */ - 0x00, 0x00, 0xE9, 0xB9, 0xE9, 0xB4, 0x00, 0x00, /* 0xBC-0xBF */ - 0xE9, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xBE, 0xE7, 0x00, 0x00, 0xBE, 0xE4, 0xBE, 0xE8, /* 0xC4-0xC7 */ - 0xE9, 0xB3, 0xBE, 0xE5, 0xE9, 0xB6, 0xE9, 0xB7, /* 0xC8-0xCB */ - 0xE9, 0xBC, 0x00, 0x00, 0x00, 0x00, 0xE9, 0xB8, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xEC, 0xF2, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0xC0, 0xC7, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xEF, 0xDC, 0xC0, 0xC6, 0xEF, 0xDA, 0xEF, 0xDB, /* 0xD8-0xDB */ - 0xC2, 0x60, 0xC3, 0x6E, 0xF2, 0x4B, 0x00, 0x00, /* 0xDC-0xDF */ - 0xC3, 0x6D, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x51, /* 0xE0-0xE3 */ - 0xF4, 0x52, 0x00, 0x00, 0xC4, 0x66, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xF4, 0x50, 0xC4, 0xE4, 0x00, 0x00, 0xF7, 0xDF, /* 0xE8-0xEB */ - 0xC5, 0xCE, 0xF8, 0xAA, 0xF8, 0xAB, 0x00, 0x00, /* 0xEC-0xEF */ - 0xA4, 0xEA, 0x00, 0x00, 0xA6, 0xB1, 0xA6, 0xB2, /* 0xF0-0xF3 */ - 0xA7, 0xF3, 0x00, 0x00, 0xCC, 0xD1, 0xAC, 0x54, /* 0xF4-0xF7 */ - 0xAE, 0xD1, 0xB1, 0xE4, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0xB0, 0xD2, 0x00, 0x00, 0xB4, 0xBF, 0xB4, 0xC0, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_67[512] = { - 0xB3, 0xCC, 0xD9, 0xA9, 0x00, 0x00, 0xB7, 0x7C, /* 0x00-0x03 */ - 0xE1, 0xFA, 0xE1, 0xF9, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xA4, 0xEB, 0xA6, 0xB3, 0xCC, 0xD2, 0xAA, 0x42, /* 0x08-0x0B */ - 0x00, 0x00, 0xAA, 0x41, 0x00, 0x00, 0xCE, 0xF9, /* 0x0C-0x0F */ - 0xCE, 0xFA, 0x00, 0x00, 0xD1, 0xD7, 0xD1, 0xD8, /* 0x10-0x13 */ - 0xAE, 0xD2, 0xAE, 0xD3, 0x00, 0x00, 0xAE, 0xD4, /* 0x14-0x17 */ - 0xD5, 0xAF, 0x00, 0x00, 0x00, 0x00, 0xB1, 0xE6, /* 0x18-0x1B */ - 0x00, 0x00, 0xB4, 0xC2, 0x00, 0x00, 0xB4, 0xC1, /* 0x1C-0x1F */ - 0xDD, 0xC8, 0xDF, 0x7A, 0xE1, 0xFB, 0xE9, 0xBD, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0xC2, 0x61, 0xC4, 0x67, /* 0x24-0x27 */ - 0xA4, 0xEC, 0x00, 0x00, 0xA5, 0xBC, 0xA5, 0xBD, /* 0x28-0x2B */ - 0xA5, 0xBB, 0xA5, 0xBE, 0xA5, 0xBA, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xA6, 0xB6, 0x00, 0x00, 0xC9, 0xF6, /* 0x30-0x33 */ - 0xA6, 0xB5, 0xA6, 0xB7, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xC9, 0xF1, 0xC9, 0xF0, 0xC9, 0xF3, 0xC9, 0xF2, /* 0x38-0x3B */ - 0xC9, 0xF5, 0xA6, 0xB4, 0xC9, 0xEF, 0xC9, 0xF4, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0xCA, 0xFD, 0xA7, 0xFD, 0xCA, 0xFE, /* 0x44-0x47 */ - 0xCB, 0x43, 0xA7, 0xFC, 0x00, 0x00, 0xCB, 0x47, /* 0x48-0x4B */ - 0xCB, 0x42, 0xCB, 0x45, 0xA7, 0xF5, 0xA7, 0xF6, /* 0x4C-0x4F */ - 0xA7, 0xF7, 0xA7, 0xF8, 0x00, 0x00, 0xA8, 0x40, /* 0x50-0x53 */ - 0x00, 0x00, 0xCB, 0x41, 0xA7, 0xFA, 0xA8, 0x41, /* 0x54-0x57 */ - 0x00, 0x00, 0xCB, 0x40, 0xCB, 0x46, 0x00, 0x00, /* 0x58-0x5B */ - 0xA7, 0xF9, 0xCB, 0x44, 0xA7, 0xFB, 0xA7, 0xF4, /* 0x5C-0x5F */ - 0xA7, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xAA, 0x57, 0x00, 0x00, /* 0x68-0x6B */ - 0xCC, 0xD4, 0xAA, 0x43, 0x00, 0x00, 0xAA, 0x4D, /* 0x6C-0x6F */ - 0xAA, 0x4E, 0xAA, 0x46, 0xAA, 0x58, 0xAA, 0x48, /* 0x70-0x73 */ - 0xCC, 0xDC, 0xAA, 0x53, 0xCC, 0xD7, 0xAA, 0x49, /* 0x74-0x77 */ - 0xCC, 0xE6, 0xCC, 0xE7, 0xCC, 0xDF, 0xCC, 0xD8, /* 0x78-0x7B */ - 0xAA, 0x56, 0xCC, 0xE4, 0xAA, 0x51, 0xAA, 0x4F, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xCC, 0xE5, 0x00, 0x00, 0xCC, 0xE3, /* 0x80-0x83 */ - 0xCC, 0xDB, 0xCC, 0xD3, 0xCC, 0xDA, 0xAA, 0x4A, /* 0x84-0x87 */ - 0x00, 0x00, 0xAA, 0x50, 0x00, 0x00, 0xAA, 0x44, /* 0x88-0x8B */ - 0xCC, 0xDE, 0xCC, 0xDD, 0xCC, 0xD5, 0x00, 0x00, /* 0x8C-0x8F */ - 0xAA, 0x52, 0xCC, 0xE1, 0xCC, 0xD6, 0xAA, 0x55, /* 0x90-0x93 */ - 0xCC, 0xE8, 0xAA, 0x45, 0x00, 0x00, 0xAA, 0x4C, /* 0x94-0x97 */ - 0xCC, 0xD9, 0xCC, 0xE2, 0xAA, 0x54, 0x00, 0x00, /* 0x98-0x9B */ - 0xAA, 0x47, 0xAA, 0x4B, 0x00, 0x00, 0xCC, 0xE0, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xCF, 0x5B, 0xAC, 0x5C, /* 0xAC-0xAF */ - 0xAC, 0x69, 0x00, 0x00, 0xCF, 0x56, 0xCF, 0x4C, /* 0xB0-0xB3 */ - 0xAC, 0x62, 0xCF, 0x4A, 0xAC, 0x5B, 0xCF, 0x45, /* 0xB4-0xB7 */ - 0xAC, 0x65, 0xCF, 0x52, 0xCE, 0xFE, 0xCF, 0x41, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xCF, 0x44, 0xCE, 0xFB, 0xCF, 0x51, 0xCF, 0x61, /* 0xC0-0xC3 */ - 0xAC, 0x60, 0xCF, 0x46, 0xCF, 0x58, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xCE, 0xFD, 0xCF, 0x5F, 0xCF, 0x60, 0xCF, 0x63, /* 0xC8-0xCB */ - 0xCF, 0x5A, 0xCF, 0x4B, 0xCF, 0x53, 0xAC, 0x66, /* 0xCC-0xCF */ - 0xAC, 0x59, 0xAC, 0x61, 0xAC, 0x6D, 0xAC, 0x56, /* 0xD0-0xD3 */ - 0xAC, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xCF, 0x43, 0xAC, 0x6A, 0xAC, 0x63, 0xCF, 0x5D, /* 0xD8-0xDB */ - 0xCF, 0x40, 0xAC, 0x6C, 0xAC, 0x67, 0xCF, 0x49, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xAC, 0x6B, 0xCF, 0x50, /* 0xE0-0xE3 */ - 0xCF, 0x48, 0xAC, 0x64, 0xCF, 0x5C, 0xCF, 0x54, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xAC, 0x5E, 0xCF, 0x62, 0xCF, 0x47, /* 0xE8-0xEB */ - 0xAC, 0x5A, 0xCF, 0x59, 0xCF, 0x4F, 0xAC, 0x5F, /* 0xEC-0xEF */ - 0xCF, 0x55, 0xAC, 0x57, 0xCE, 0xFC, 0xAC, 0x68, /* 0xF0-0xF3 */ - 0xAE, 0xE3, 0xAC, 0x5D, 0xCF, 0x4E, 0xCF, 0x4D, /* 0xF4-0xF7 */ - 0xCF, 0x42, 0x00, 0x00, 0xCF, 0x5E, 0x00, 0x00, /* 0xF8-0xFB */ - 0xCF, 0x57, 0x00, 0x00, 0x00, 0x00, 0xAC, 0x55, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_68[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xD1, 0xEC, 0xAE, 0xEA, /* 0x10-0x13 */ - 0xD1, 0xED, 0x00, 0x00, 0xD1, 0xE1, 0xAE, 0xDF, /* 0x14-0x17 */ - 0xAE, 0xEB, 0x00, 0x00, 0xD1, 0xDA, 0x00, 0x00, /* 0x18-0x1B */ - 0xD1, 0xE3, 0xD1, 0xEB, 0x00, 0x00, 0xD1, 0xD9, /* 0x1C-0x1F */ - 0xD1, 0xF4, 0xAE, 0xD5, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xD1, 0xF3, 0xD1, 0xEE, 0x00, 0x00, /* 0x24-0x27 */ - 0xD1, 0xEF, 0xAE, 0xDD, 0xAE, 0xE8, 0xD1, 0xE5, /* 0x28-0x2B */ - 0x00, 0x00, 0xD1, 0xE6, 0xD1, 0xF0, 0xD1, 0xE7, /* 0x2C-0x2F */ - 0x00, 0x00, 0xD1, 0xE2, 0xD1, 0xDC, 0xD1, 0xDD, /* 0x30-0x33 */ - 0xD1, 0xEA, 0xD1, 0xE4, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xAE, 0xD6, 0xAE, 0xDA, 0xD1, 0xF2, 0xD1, 0xDE, /* 0x38-0x3B */ - 0xAE, 0xE6, 0xAE, 0xE2, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xAE, 0xE5, 0xAE, 0xEC, 0xAE, 0xDB, 0xAE, 0xE7, /* 0x40-0x43 */ - 0xD1, 0xE9, 0xAE, 0xE9, 0xAE, 0xD8, 0x00, 0x00, /* 0x44-0x47 */ - 0xAE, 0xD7, 0xD1, 0xDB, 0x00, 0x00, 0xD1, 0xDF, /* 0x48-0x4B */ - 0xAE, 0xE0, 0xD1, 0xF1, 0xD1, 0xE8, 0xD1, 0xE0, /* 0x4C-0x4F */ - 0xAE, 0xE4, 0xAE, 0xE1, 0x00, 0x00, 0xAE, 0xD9, /* 0x50-0x53 */ - 0xAE, 0xDC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xC4, /* 0x68-0x6B */ - 0x00, 0x00, 0xD5, 0xB4, 0xD5, 0xB5, 0xD5, 0xB9, /* 0x6C-0x6F */ - 0x00, 0x00, 0xD5, 0xC8, 0xD5, 0xC5, 0x00, 0x00, /* 0x70-0x73 */ - 0xD5, 0xBE, 0xD5, 0xBD, 0xB1, 0xED, 0xD5, 0xC1, /* 0x74-0x77 */ - 0xD5, 0xD0, 0xD5, 0xB0, 0x00, 0x00, 0xD5, 0xD1, /* 0x78-0x7B */ - 0xD5, 0xC3, 0xD5, 0xD5, 0xD5, 0xC9, 0xB1, 0xEC, /* 0x7C-0x7F */ - - 0xD5, 0xC7, 0xB1, 0xE7, 0xB1, 0xFC, 0xB1, 0xF2, /* 0x80-0x83 */ - 0x00, 0x00, 0xB1, 0xF6, 0xB1, 0xF5, 0xD5, 0xB1, /* 0x84-0x87 */ - 0x00, 0x00, 0xD5, 0xCE, 0xD5, 0xD4, 0xD5, 0xCC, /* 0x88-0x8B */ - 0xD5, 0xD3, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xC0, /* 0x8C-0x8F */ - 0xD5, 0xB2, 0xD5, 0xD2, 0xD5, 0xC2, 0xB1, 0xEA, /* 0x90-0x93 */ - 0xB1, 0xF7, 0x00, 0x00, 0xD5, 0xCB, 0xB1, 0xF0, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD5, 0xCA, /* 0x98-0x9B */ - 0xD5, 0xB3, 0xB1, 0xF8, 0x00, 0x00, 0xB1, 0xFA, /* 0x9C-0x9F */ - 0xD5, 0xCD, 0xB1, 0xFB, 0xB1, 0xE9, 0xD5, 0xBA, /* 0xA0-0xA3 */ - 0xD5, 0xCF, 0x00, 0x00, 0x00, 0x00, 0xB1, 0xEF, /* 0xA4-0xA7 */ - 0xB1, 0xF9, 0xD5, 0xBC, 0xD5, 0xC6, 0xD5, 0xB7, /* 0xA8-0xAB */ - 0xD5, 0xBB, 0xB1, 0xF4, 0xD5, 0xB6, 0xB1, 0xE8, /* 0xAC-0xAF */ - 0xB1, 0xF1, 0xB1, 0xEE, 0xD5, 0xBF, 0xAE, 0xDE, /* 0xB0-0xB3 */ - 0xD9, 0xC0, 0xB1, 0xEB, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xB1, 0xF3, 0x00, 0x00, 0xD9, 0xC3, 0xD9, 0xD9, /* 0xC4-0xC7 */ - 0xD9, 0xCE, 0xB4, 0xD6, 0x00, 0x00, 0xB4, 0xD1, /* 0xC8-0xCB */ - 0xD9, 0xBD, 0xB4, 0xD2, 0xD9, 0xCD, 0x00, 0x00, /* 0xCC-0xCF */ - 0xD9, 0xC6, 0xD9, 0xD3, 0xB4, 0xCE, 0xD9, 0xAB, /* 0xD0-0xD3 */ - 0xD9, 0xD5, 0xB4, 0xC4, 0xD9, 0xB3, 0xB4, 0xC7, /* 0xD4-0xD7 */ - 0xB4, 0xC6, 0x00, 0x00, 0xB4, 0xD7, 0x00, 0x00, /* 0xD8-0xDB */ - 0xD9, 0xAD, 0xD9, 0xCF, 0xD9, 0xD0, 0xB4, 0xC9, /* 0xDC-0xDF */ - 0xB4, 0xC5, 0xD9, 0xBB, 0x00, 0x00, 0xB4, 0xD0, /* 0xE0-0xE3 */ - 0xD9, 0xB6, 0x00, 0x00, 0xD9, 0xD1, 0xB4, 0xCC, /* 0xE4-0xE7 */ - 0xD9, 0xC9, 0xD9, 0xD6, 0xD9, 0xB0, 0xD9, 0xB5, /* 0xE8-0xEB */ - 0xD9, 0xAF, 0x00, 0x00, 0xB4, 0xCB, 0xD9, 0xC2, /* 0xEC-0xEF */ - 0xDD, 0xDE, 0xD9, 0xB1, 0xB4, 0xCF, 0xD9, 0xBA, /* 0xF0-0xF3 */ - 0xD9, 0xD2, 0xB4, 0xCA, 0xD9, 0xB7, 0xD9, 0xB4, /* 0xF4-0xF7 */ - 0xD9, 0xC5, 0xB4, 0xCD, 0xB4, 0xC3, 0xB4, 0xD9, /* 0xF8-0xFB */ - 0xD9, 0xC8, 0xD9, 0xC7, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_69[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xD9, 0xAC, 0xB4, 0xC8, 0xD9, 0xD4, 0xD9, 0xBC, /* 0x04-0x07 */ - 0xD9, 0xBE, 0x00, 0x00, 0xD9, 0xCB, 0xD9, 0xCA, /* 0x08-0x0B */ - 0xD9, 0xAA, 0xB4, 0xD3, 0xB4, 0xD5, 0xD9, 0xB2, /* 0x0C-0x0F */ - 0xD9, 0xB9, 0xD9, 0xC1, 0xB4, 0xD4, 0xD9, 0xB8, /* 0x10-0x13 */ - 0xD9, 0xC4, 0xD9, 0xD7, 0x00, 0x00, 0xD9, 0xCC, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xD9, 0xD8, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xD9, 0xAE, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDD, 0xF2, /* 0x2C-0x2F */ - 0xB7, 0xA6, 0x00, 0x00, 0xDD, 0xF0, 0xDD, 0xDB, /* 0x30-0x33 */ - 0xDD, 0xE0, 0xDD, 0xD9, 0x00, 0x00, 0xDD, 0xEC, /* 0x34-0x37 */ - 0xDD, 0xCB, 0xDD, 0xD2, 0x00, 0x00, 0xDD, 0xEA, /* 0x38-0x3B */ - 0xDD, 0xF4, 0xDD, 0xDC, 0x00, 0x00, 0xDD, 0xCF, /* 0x3C-0x3F */ - 0xDD, 0xE2, 0xDD, 0xE7, 0xDD, 0xD3, 0x00, 0x00, /* 0x40-0x43 */ - 0xDD, 0xE4, 0xDD, 0xD0, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0xDD, 0xD7, 0xDD, 0xD8, 0xB7, 0xA8, 0xDD, 0xEB, /* 0x48-0x4B */ - 0xDD, 0xE9, 0x00, 0x00, 0xDD, 0xCC, 0xDD, 0xEE, /* 0x4C-0x4F */ - 0x00, 0x00, 0xDD, 0xEF, 0xDD, 0xF1, 0xB7, 0xAC, /* 0x50-0x53 */ - 0xB7, 0xA4, 0x00, 0x00, 0xD5, 0xB8, 0xDD, 0xD4, /* 0x54-0x57 */ - 0xDD, 0xE6, 0xDD, 0xD5, 0xB7, 0xA1, 0xB7, 0xB1, /* 0x58-0x5B */ - 0xDD, 0xED, 0xB7, 0xAF, 0xB7, 0xAB, 0xDD, 0xCA, /* 0x5C-0x5F */ - 0xB7, 0xA3, 0x00, 0x00, 0xDD, 0xCD, 0xB7, 0xB0, /* 0x60-0x63 */ - 0x00, 0x00, 0xDD, 0xDD, 0xDD, 0xC9, 0x00, 0x00, /* 0x64-0x67 */ - 0xB7, 0xA9, 0xDD, 0xE1, 0xDD, 0xD1, 0xB7, 0xAA, /* 0x68-0x6B */ - 0xDD, 0xDA, 0xB7, 0x7E, 0xB4, 0xD8, 0xDD, 0xE3, /* 0x6C-0x6F */ - 0xD9, 0xBF, 0xDD, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xDD, 0xE8, 0xB7, 0xA5, 0xDD, 0xE5, 0xB7, 0xA2, /* 0x74-0x77 */ - 0xDD, 0xDF, 0xB7, 0xAD, 0xDD, 0xD6, 0xDD, 0xF3, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xB7, 0xA7, 0xDE, 0xC6, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0xB7, 0xAE, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0xE2, 0x4A, 0xE2, 0x48, 0x00, 0x00, /* 0x8C-0x8F */ - 0xE2, 0x5E, 0xE2, 0x46, 0x00, 0x00, 0xE2, 0x58, /* 0x90-0x93 */ - 0xB7, 0x7D, 0xBA, 0x5F, 0xE2, 0x42, 0xE2, 0x5D, /* 0x94-0x97 */ - 0x00, 0x00, 0xE2, 0x47, 0xE2, 0x55, 0xBA, 0x64, /* 0x98-0x9B */ - 0xBA, 0x5D, 0x00, 0x00, 0xE2, 0x5B, 0x00, 0x00, /* 0x9C-0x9F */ - 0xE2, 0x40, 0xE2, 0x5A, 0x00, 0x00, 0xBA, 0x6F, /* 0xA0-0xA3 */ - 0xE2, 0x51, 0xE2, 0x61, 0xBA, 0x6D, 0xE2, 0x49, /* 0xA4-0xA7 */ - 0xBA, 0x5E, 0xE2, 0x4B, 0xE2, 0x59, 0xBA, 0x67, /* 0xA8-0xAB */ - 0xE2, 0x44, 0xBA, 0x6B, 0xBA, 0x61, 0xE2, 0x4D, /* 0xAC-0xAF */ - 0xE2, 0x43, 0xE1, 0xFC, 0x00, 0x00, 0xE2, 0x57, /* 0xB0-0xB3 */ - 0xBA, 0x68, 0xE2, 0x60, 0xE1, 0xFD, 0xBA, 0x65, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xE2, 0x53, 0x00, 0x00, 0xBA, 0x66, /* 0xB8-0xBB */ - 0xE2, 0x45, 0xE2, 0x50, 0xE2, 0x4C, 0xE2, 0x4E, /* 0xBC-0xBF */ - 0x00, 0x00, 0xBA, 0x60, 0xE2, 0x5F, 0xBA, 0x6E, /* 0xC0-0xC3 */ - 0xE2, 0x4F, 0x00, 0x00, 0xE2, 0x62, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xE1, 0xFE, 0xE2, 0x54, 0xBA, 0x63, /* 0xC8-0xCB */ - 0xBA, 0x6C, 0xBA, 0x6A, 0xE2, 0x41, 0xE2, 0x56, /* 0xCC-0xCF */ - 0xBA, 0x69, 0x00, 0x00, 0x00, 0x00, 0xBA, 0x62, /* 0xD0-0xD3 */ - 0xE2, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xE2, 0x5C, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xE5, 0xD5, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xE5, 0xD1, 0xE5, 0xCD, 0xE5, 0xE1, 0xE5, 0xDE, /* 0xE4-0xE7 */ - 0xBC, 0xCD, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xE5, /* 0xE8-0xEB */ - 0xE5, 0xD4, 0xBC, 0xD8, 0xE5, 0xDB, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0xE5, 0xD0, 0xE5, 0xDA, 0xBC, 0xD5, /* 0xF0-0xF3 */ - 0xE5, 0xEE, 0x00, 0x00, 0xE5, 0xEB, 0xE5, 0xDD, /* 0xF4-0xF7 */ - 0xE5, 0xCE, 0x00, 0x00, 0x00, 0x00, 0xE5, 0xE2, /* 0xF8-0xFB */ - 0xE5, 0xE4, 0xBC, 0xD1, 0xE5, 0xD8, 0xE5, 0xD3, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_6A[512] = { - 0xE5, 0xCA, 0xBC, 0xCE, 0xBC, 0xD6, 0x00, 0x00, /* 0x00-0x03 */ - 0xE5, 0xE7, 0xBC, 0xD7, 0xE5, 0xCB, 0xE5, 0xED, /* 0x04-0x07 */ - 0xE5, 0xE0, 0xE5, 0xE6, 0xBC, 0xD4, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0xE5, 0xE3, 0x00, 0x00, 0xE5, 0xEA, /* 0x0C-0x0F */ - 0x00, 0x00, 0xBC, 0xD9, 0x00, 0x00, 0xBC, 0xD3, /* 0x10-0x13 */ - 0xE5, 0xDC, 0xE5, 0xCF, 0xE5, 0xEF, 0xE5, 0xCC, /* 0x14-0x17 */ - 0xE5, 0xE8, 0xBC, 0xD0, 0x00, 0x00, 0xE5, 0xD6, /* 0x18-0x1B */ - 0x00, 0x00, 0xE5, 0xD7, 0xBC, 0xCF, 0xBC, 0xCC, /* 0x1C-0x1F */ - 0xE5, 0xD2, 0xBC, 0xD2, 0x00, 0x00, 0xBC, 0xCB, /* 0x20-0x23 */ - 0x00, 0x00, 0xE5, 0xE9, 0xE5, 0xEC, 0xE5, 0xD9, /* 0x24-0x27 */ - 0xE9, 0xCA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xC2, 0x00, 0x00, /* 0x30-0x33 */ - 0xE9, 0xBE, 0xBE, 0xF6, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xBE, 0xEB, 0xBE, 0xF0, 0xBE, 0xEC, 0xE9, 0xCC, /* 0x38-0x3B */ - 0xE9, 0xD7, 0xBE, 0xEA, 0xE9, 0xC4, 0xE9, 0xCD, /* 0x3C-0x3F */ - 0xE5, 0xDF, 0xE9, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xBE, 0xF1, 0x00, 0x00, 0xE9, 0xDD, 0xBE, 0xF5, /* 0x44-0x47 */ - 0xBE, 0xF8, 0xE9, 0xC0, 0x00, 0x00, 0xBE, 0xF4, /* 0x48-0x4B */ - 0x00, 0x00, 0xE9, 0xDB, 0xE9, 0xDC, 0xE9, 0xD2, /* 0x4C-0x4F */ - 0xE9, 0xD1, 0xE9, 0xC9, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xE9, 0xD3, 0xE9, 0xDA, 0xE9, 0xD9, 0x00, 0x00, /* 0x54-0x57 */ - 0xBE, 0xEF, 0xBE, 0xED, 0xE9, 0xCB, 0xE9, 0xC8, /* 0x58-0x5B */ - 0x00, 0x00, 0xE9, 0xC5, 0xE9, 0xD8, 0xBE, 0xF7, /* 0x5C-0x5F */ - 0xE9, 0xD6, 0xBE, 0xF3, 0xBE, 0xF2, 0x00, 0x00, /* 0x60-0x63 */ - 0xE9, 0xD0, 0x00, 0x00, 0xE9, 0xBF, 0xE9, 0xC1, /* 0x64-0x67 */ - 0xE9, 0xC3, 0xE9, 0xD5, 0xE9, 0xCF, 0xBE, 0xEE, /* 0x68-0x6B */ - 0x00, 0x00, 0xE9, 0xC6, 0x00, 0x00, 0xE9, 0xD4, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xC7, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xC0, 0xCF, 0xED, 0x45, /* 0x7C-0x7F */ - - 0xC0, 0xC8, 0xEC, 0xF5, 0x00, 0x00, 0xED, 0x41, /* 0x80-0x83 */ - 0xC0, 0xCA, 0xED, 0x48, 0x00, 0x00, 0xEC, 0xFC, /* 0x84-0x87 */ - 0x00, 0x00, 0xEC, 0xF7, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0xED, 0x49, 0xEC, 0xF3, 0xEC, 0xFE, 0x00, 0x00, /* 0x8C-0x8F */ - 0xC0, 0xD1, 0xED, 0x44, 0xED, 0x4A, 0xEC, 0xFD, /* 0x90-0x93 */ - 0xC0, 0xC9, 0xED, 0x40, 0xEC, 0xF4, 0xC0, 0xD0, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0x47, 0xEC, 0xF9, /* 0x98-0x9B */ - 0xC0, 0xCC, 0x00, 0x00, 0xEC, 0xFB, 0xEC, 0xF8, /* 0x9C-0x9F */ - 0xC0, 0xD2, 0xEC, 0xFA, 0xC0, 0xCB, 0xC0, 0xCE, /* 0xA0-0xA3 */ - 0xED, 0x43, 0xEC, 0xF6, 0xED, 0x46, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xED, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xC2, 0x63, 0xEF, 0xE7, 0xC2, 0x68, 0xC2, 0x69, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x62, /* 0xB0-0xB3 */ - 0xEF, 0xE6, 0x00, 0x00, 0xEF, 0xE3, 0xEF, 0xE4, /* 0xB4-0xB7 */ - 0xC2, 0x66, 0xEF, 0xDE, 0xEF, 0xE2, 0xC2, 0x65, /* 0xB8-0xBB */ - 0x00, 0x00, 0xEF, 0xDF, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xC2, 0x67, 0xC2, 0x64, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xEF, 0xDD, 0xEF, 0xE1, 0xEF, 0xE5, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0x51, /* 0xC8-0xCB */ - 0xF2, 0x4E, 0xF2, 0x57, 0x00, 0x00, 0xF2, 0x56, /* 0xCC-0xCF */ - 0xF2, 0x54, 0xF2, 0x4F, 0x00, 0x00, 0xC3, 0x72, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xF2, 0x50, 0xC3, 0x71, 0xC0, 0xCD, /* 0xD8-0xDB */ - 0xF2, 0x53, 0xC3, 0x70, 0xF2, 0x58, 0xF2, 0x52, /* 0xDC-0xDF */ - 0xF2, 0x4D, 0xEF, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xC3, 0x6F, 0x00, 0x00, 0xF2, 0x4C, /* 0xE4-0xE7 */ - 0xF4, 0x56, 0x00, 0x00, 0xF4, 0x55, 0xF2, 0x55, /* 0xE8-0xEB */ - 0xC4, 0x68, 0x00, 0x00, 0xF4, 0x59, 0xF4, 0x5A, /* 0xEC-0xEF */ - 0xF4, 0x54, 0xF4, 0x58, 0x00, 0x00, 0xF4, 0x53, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xF5, 0xD1, 0xF4, 0x57, 0xC4, 0xE7, 0xC4, 0xE5, /* 0xF8-0xFB */ - 0xF5, 0xCF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_6B[512] = { - 0xF5, 0xD2, 0x00, 0x00, 0xF5, 0xCE, 0xF5, 0xD0, /* 0x00-0x03 */ - 0xC4, 0xE6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xF6, 0xE5, 0xF6, 0xE6, 0xC5, 0x76, 0xF6, 0xE4, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF7, 0xE2, /* 0x0C-0x0F */ - 0xC5, 0xCF, 0xF7, 0xE0, 0xF7, 0xE1, 0xF8, 0xAC, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xC6, 0x56, 0xF8, 0xF3, /* 0x14-0x17 */ - 0xF8, 0xF1, 0xF8, 0xF2, 0xF8, 0xF4, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xF9, 0xBB, 0x00, 0x00, /* 0x1C-0x1F */ - 0xA4, 0xED, 0xA6, 0xB8, 0x00, 0x00, 0xAA, 0x59, /* 0x20-0x23 */ - 0x00, 0x00, 0xCC, 0xE9, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xCF, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0xD1, 0xF5, 0xD1, 0xF7, 0x00, 0x00, 0xD1, 0xF6, /* 0x2C-0x2F */ - 0x00, 0x00, 0xD1, 0xF8, 0xB1, 0xFD, 0xD5, 0xD7, /* 0x30-0x33 */ - 0xD1, 0xF9, 0x00, 0x00, 0xD5, 0xD6, 0xD5, 0xD8, /* 0x34-0x37 */ - 0xD5, 0xD9, 0xD9, 0xDA, 0xB4, 0xDB, 0xD9, 0xDB, /* 0x38-0x3B */ - 0xD9, 0xDD, 0xB4, 0xDC, 0xB4, 0xDA, 0xD9, 0xDC, /* 0x3C-0x3F */ - 0x00, 0x00, 0xDD, 0xFA, 0xDD, 0xF8, 0xDD, 0xF7, /* 0x40-0x43 */ - 0x00, 0x00, 0xDD, 0xF6, 0xDD, 0xF5, 0xB7, 0xB2, /* 0x44-0x47 */ - 0xDD, 0xF9, 0xBA, 0x70, 0xE2, 0x63, 0xE2, 0x65, /* 0x48-0x4B */ - 0xBA, 0x71, 0xE2, 0x64, 0xBC, 0xDB, 0x00, 0x00, /* 0x4C-0x4F */ - 0xBC, 0xDA, 0xE5, 0xF0, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xE9, 0xDF, 0xE9, 0xDE, 0xE9, 0xE0, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xBE, 0xF9, 0x00, 0x00, 0xED, 0x4B, /* 0x58-0x5B */ - 0xC0, 0xD3, 0x00, 0x00, 0xEF, 0xE8, 0xC2, 0x6A, /* 0x5C-0x5F */ - 0xF2, 0x59, 0xC5, 0x77, 0xA4, 0xEE, 0xA5, 0xBF, /* 0x60-0x63 */ - 0xA6, 0xB9, 0xA8, 0x42, 0xAA, 0x5A, 0xAA, 0x5B, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xAC, 0x6E, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0xD1, 0xFA, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xB7, 0xB3, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xD1, 0xBE, 0xFA, /* 0x74-0x77 */ - 0xC2, 0x6B, 0xA4, 0xEF, 0x00, 0x00, 0xA6, 0xBA, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xCC, 0xEB, 0xAA, 0x5C, /* 0x7C-0x7F */ - - 0xCC, 0xEA, 0x00, 0x00, 0xCF, 0x65, 0xAC, 0x6F, /* 0x80-0x83 */ - 0xCF, 0x66, 0x00, 0x00, 0xAC, 0x70, 0x00, 0x00, /* 0x84-0x87 */ - 0xD1, 0xFC, 0xAE, 0xEE, 0xAE, 0xED, 0x00, 0x00, /* 0x88-0x8B */ - 0xD5, 0xDE, 0xD5, 0xDC, 0xD5, 0xDD, 0xD5, 0xDB, /* 0x8C-0x8F */ - 0x00, 0x00, 0xD5, 0xDA, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xD9, 0xDE, 0xD9, 0xE1, 0xB4, 0xDE, 0xD9, 0xDF, /* 0x94-0x97 */ - 0xB4, 0xDD, 0xD9, 0xE0, 0x00, 0x00, 0xDD, 0xFB, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0x66, 0xE2, 0x67, /* 0x9C-0x9F */ - 0xE2, 0x68, 0x00, 0x00, 0xE5, 0xF3, 0xE5, 0xF2, /* 0xA0-0xA3 */ - 0xBC, 0xDC, 0xE5, 0xF1, 0xE5, 0xF4, 0xE9, 0xE1, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xE2, 0xE9, 0xE3, /* 0xA8-0xAB */ - 0x00, 0x00, 0xED, 0x4C, 0xC0, 0xD4, 0xC2, 0x6C, /* 0xAC-0xAF */ - 0xF2, 0x5A, 0x00, 0x00, 0xC4, 0xE8, 0xC9, 0x5F, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xAC, 0x71, 0xCF, 0x67, 0xAE, 0xEF, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xB1, 0xFE, 0x00, 0x00, /* 0xB8-0xBB */ - 0xB4, 0xDF, 0xD9, 0xE2, 0x00, 0x00, 0xB7, 0xB5, /* 0xBC-0xBF */ - 0xB7, 0xB4, 0x00, 0x00, 0x00, 0x00, 0xE2, 0x69, /* 0xC0-0xC3 */ - 0xE2, 0x6A, 0xBC, 0xDD, 0xBC, 0xDE, 0xE9, 0xE5, /* 0xC4-0xC7 */ - 0xE9, 0xE4, 0xEF, 0xE9, 0xF7, 0xE3, 0xA4, 0xF0, /* 0xC8-0xCB */ - 0xC9, 0x60, 0xA5, 0xC0, 0x00, 0x00, 0xA8, 0x43, /* 0xCC-0xCF */ - 0xCB, 0x48, 0x00, 0x00, 0xAC, 0x72, 0xB7, 0xB6, /* 0xD0-0xD3 */ - 0xA4, 0xF1, 0x00, 0x00, 0xCF, 0x68, 0xAC, 0x73, /* 0xD4-0xD7 */ - 0xCF, 0x69, 0x00, 0x00, 0xC0, 0xD5, 0xA4, 0xF2, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0xCC, 0xEC, 0x00, 0x00, /* 0xDC-0xDF */ - 0xCF, 0x6A, 0x00, 0x00, 0xD2, 0x42, 0xD2, 0x41, /* 0xE0-0xE3 */ - 0xD1, 0xFE, 0x00, 0x00, 0xD1, 0xFD, 0xD2, 0x43, /* 0xE4-0xE7 */ - 0xD2, 0x40, 0x00, 0x00, 0x00, 0x00, 0xB2, 0x40, /* 0xE8-0xEB */ - 0xB2, 0x41, 0x00, 0x00, 0x00, 0x00, 0xB4, 0xE0, /* 0xEC-0xEF */ - 0xD9, 0xE3, 0x00, 0x00, 0xD9, 0xE4, 0xD9, 0xE5, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDE, 0x41, /* 0xF4-0xF7 */ - 0xDE, 0x42, 0xDE, 0x40, 0x00, 0x00, 0xDD, 0xFD, /* 0xF8-0xFB */ - 0xDD, 0xFE, 0xB7, 0xB7, 0xE2, 0x6B, 0xE5, 0xF7, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_6C[512] = { - 0xE5, 0xF6, 0xE5, 0xF5, 0xE5, 0xF8, 0xE9, 0xE7, /* 0x00-0x03 */ - 0xE9, 0xE6, 0xBE, 0xFB, 0xE9, 0xE8, 0x00, 0x00, /* 0x04-0x07 */ - 0xC0, 0xD6, 0xED, 0x4D, 0x00, 0x00, 0xEF, 0xEA, /* 0x08-0x0B */ - 0xF2, 0x5B, 0xF6, 0xE7, 0x00, 0x00, 0xA4, 0xF3, /* 0x0C-0x0F */ - 0xA5, 0xC2, 0xA5, 0xC1, 0x00, 0x00, 0xAA, 0x5D, /* 0x10-0x13 */ - 0xC9, 0x61, 0xC9, 0x7E, 0xA6, 0xBB, 0x00, 0x00, /* 0x14-0x17 */ - 0xC9, 0xF7, 0xCB, 0x49, 0xCB, 0x4A, 0xAA, 0x5E, /* 0x18-0x1B */ - 0x00, 0x00, 0xCC, 0xED, 0x00, 0x00, 0xAC, 0x74, /* 0x1C-0x1F */ - 0xCF, 0x6B, 0xCF, 0x6C, 0x00, 0x00, 0xAE, 0xF0, /* 0x20-0x23 */ - 0xAE, 0xF4, 0xD2, 0x44, 0xAE, 0xF3, 0xAE, 0xF1, /* 0x24-0x27 */ - 0xAE, 0xF2, 0x00, 0x00, 0xD5, 0xDF, 0xB2, 0x42, /* 0x28-0x2B */ - 0xB4, 0xE3, 0x00, 0x00, 0xB4, 0xE1, 0xB4, 0xE2, /* 0x2C-0x2F */ - 0xD9, 0xE6, 0x00, 0x00, 0x00, 0x00, 0xBA, 0x72, /* 0x30-0x33 */ - 0xA4, 0xF4, 0x00, 0x00, 0xC9, 0xA1, 0x00, 0x00, /* 0x34-0x37 */ - 0xA5, 0xC3, 0x00, 0x00, 0x00, 0x00, 0xC9, 0xA4, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xA5, 0xC6, 0xC9, 0xA3, /* 0x3C-0x3F */ - 0xA5, 0xC5, 0xA5, 0xC4, 0xA8, 0x44, 0xC9, 0xA2, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xC9, 0xF8, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xC9, 0xFC, 0xC9, 0xFE, /* 0x48-0x4B */ - 0xCA, 0x40, 0xA6, 0xC5, 0xA6, 0xC6, 0xC9, 0xFB, /* 0x4C-0x4F */ - 0xA6, 0xC1, 0x00, 0x00, 0xC9, 0xF9, 0x00, 0x00, /* 0x50-0x53 */ - 0xC9, 0xFD, 0xA6, 0xC2, 0x00, 0x00, 0xA6, 0xBD, /* 0x54-0x57 */ - 0x00, 0x00, 0xA6, 0xBE, 0x00, 0x00, 0xA6, 0xC4, /* 0x58-0x5B */ - 0xC9, 0xFA, 0xA6, 0xBC, 0xA8, 0x45, 0xA6, 0xBF, /* 0x5C-0x5F */ - 0xA6, 0xC0, 0xA6, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0xCB, 0x5B, 0xCB, 0x59, 0xCB, 0x4C, /* 0x64-0x67 */ - 0xA8, 0x51, 0xCB, 0x53, 0xA8, 0x4C, 0xCB, 0x4D, /* 0x68-0x6B */ - 0x00, 0x00, 0xCB, 0x55, 0x00, 0x00, 0xCB, 0x52, /* 0x6C-0x6F */ - 0xA8, 0x4F, 0xCB, 0x51, 0xA8, 0x56, 0xCB, 0x5A, /* 0x70-0x73 */ - 0xA8, 0x58, 0x00, 0x00, 0xA8, 0x5A, 0x00, 0x00, /* 0x74-0x77 */ - 0xCB, 0x4B, 0x00, 0x00, 0xA8, 0x4D, 0xCB, 0x5C, /* 0x78-0x7B */ - 0x00, 0x00, 0xA8, 0x54, 0xA8, 0x57, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xCD, 0x45, 0xA8, 0x47, 0xA8, 0x5E, 0xA8, 0x55, /* 0x80-0x83 */ - 0xCB, 0x4E, 0xA8, 0x4A, 0xA8, 0x59, 0xCB, 0x56, /* 0x84-0x87 */ - 0xA8, 0x48, 0xA8, 0x49, 0xCD, 0x43, 0xCB, 0x4F, /* 0x88-0x8B */ - 0xA8, 0x50, 0xA8, 0x5B, 0xCB, 0x5D, 0xCB, 0x50, /* 0x8C-0x8F */ - 0xA8, 0x4E, 0x00, 0x00, 0xA8, 0x53, 0xCC, 0xEE, /* 0x90-0x93 */ - 0xA8, 0x5C, 0xCB, 0x57, 0xA8, 0x52, 0x00, 0x00, /* 0x94-0x97 */ - 0xA8, 0x5D, 0xA8, 0x46, 0xCB, 0x54, 0xA8, 0x4B, /* 0x98-0x9B */ - 0xCB, 0x58, 0xCD, 0x44, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0x6A, /* 0xA8-0xAB */ - 0xAA, 0x7A, 0xCC, 0xF5, 0xAA, 0x71, 0x00, 0x00, /* 0xAC-0xAF */ - 0xCD, 0x4B, 0xAA, 0x62, 0x00, 0x00, 0xAA, 0x65, /* 0xB0-0xB3 */ - 0xCD, 0x42, 0x00, 0x00, 0xCC, 0xF3, 0xCC, 0xF7, /* 0xB4-0xB7 */ - 0xAA, 0x6D, 0xAA, 0x6F, 0xCC, 0xFA, 0xAA, 0x76, /* 0xB8-0xBB */ - 0xAA, 0x68, 0xAA, 0x66, 0xAA, 0x67, 0xAA, 0x75, /* 0xBC-0xBF */ - 0xCD, 0x47, 0xAA, 0x70, 0xCC, 0xF9, 0xCC, 0xFB, /* 0xC0-0xC3 */ - 0xAA, 0x6E, 0xAA, 0x73, 0xCC, 0xFC, 0xCD, 0x4A, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xAC, 0x75, 0xAA, 0x79, 0x00, 0x00, /* 0xC8-0xCB */ - 0xAA, 0x63, 0xCD, 0x49, 0x00, 0x00, 0xCD, 0x4D, /* 0xCC-0xCF */ - 0xCC, 0xF8, 0xCD, 0x4F, 0xCD, 0x40, 0xAA, 0x6C, /* 0xD0-0xD3 */ - 0xCC, 0xF4, 0xAA, 0x6B, 0xAA, 0x7D, 0xAA, 0x72, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xCC, 0xF2, 0xCF, 0x75, 0xAA, 0x78, /* 0xD8-0xDB */ - 0xAA, 0x7C, 0xCD, 0x41, 0xCD, 0x46, 0x00, 0x00, /* 0xDC-0xDF */ - 0xAA, 0x7E, 0xAA, 0x77, 0xAA, 0x69, 0xAA, 0x5F, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xAA, 0x64, 0x00, 0x00, 0xCC, 0xF6, /* 0xE4-0xE7 */ - 0xAA, 0x60, 0xCD, 0x4E, 0x00, 0x00, 0xCC, 0xF0, /* 0xE8-0xEB */ - 0xCC, 0xEF, 0xCC, 0xFD, 0xCC, 0xF1, 0xAA, 0x7B, /* 0xEC-0xEF */ - 0xAE, 0xF5, 0xAA, 0x74, 0xCC, 0xFE, 0xAA, 0x61, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xAC, 0xA6, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xCD, 0x4C, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_6D[512] = { - 0xCF, 0x7C, 0xCF, 0xA1, 0x00, 0x00, 0xCF, 0xA4, /* 0x00-0x03 */ - 0xCF, 0x77, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xA7, /* 0x04-0x07 */ - 0xCF, 0xAA, 0xCF, 0xAC, 0xCF, 0x74, 0xAC, 0x76, /* 0x08-0x0B */ - 0xAC, 0x7B, 0xD2, 0x49, 0xAC, 0xAD, 0xCF, 0xA5, /* 0x0C-0x0F */ - 0xCF, 0xAD, 0xCF, 0x7B, 0xCF, 0x73, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xD2, 0x64, 0xAC, 0x7E, /* 0x14-0x17 */ - 0xCF, 0xA2, 0xCF, 0x78, 0xCF, 0x7A, 0xAC, 0xA5, /* 0x18-0x1B */ - 0x00, 0x00, 0xCF, 0x7D, 0xAC, 0x7D, 0xCF, 0x70, /* 0x1C-0x1F */ - 0xCF, 0xA8, 0x00, 0x00, 0xCF, 0xAB, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xAC, 0x7A, 0x00, 0x00, 0xAC, 0xA8, /* 0x24-0x27 */ - 0xCF, 0x6D, 0xAC, 0xAA, 0xAC, 0x78, 0xAC, 0xAE, /* 0x28-0x2B */ - 0xCF, 0xA9, 0xCF, 0x6F, 0xAC, 0xAB, 0xD2, 0x5E, /* 0x2C-0x2F */ - 0xCD, 0x48, 0xAC, 0x7C, 0xAC, 0x77, 0xCF, 0x76, /* 0x30-0x33 */ - 0xCF, 0x6E, 0xAC, 0xAC, 0xAC, 0xA4, 0xCF, 0xA3, /* 0x34-0x37 */ - 0xAC, 0xA9, 0xAC, 0xA7, 0xCF, 0x79, 0xAC, 0xA1, /* 0x38-0x3B */ - 0xCF, 0x71, 0xAC, 0xA2, 0xAC, 0xA3, 0xCF, 0x72, /* 0x3C-0x3F */ - 0xCF, 0xA6, 0xAC, 0x79, 0xCF, 0x7E, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xD2, 0x4C, 0xAE, 0xFD, 0xAF, 0x43, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xD2, 0x55, 0xD2, 0x5B, /* 0x5C-0x5F */ - 0xD2, 0x57, 0xD2, 0x4A, 0xD2, 0x4D, 0xD2, 0x46, /* 0x60-0x63 */ - 0xD2, 0x47, 0xAF, 0x4A, 0xAE, 0xFA, 0xD2, 0x56, /* 0x64-0x67 */ - 0xD2, 0x5F, 0xAF, 0x45, 0xAE, 0xF6, 0x00, 0x00, /* 0x68-0x6B */ - 0xAF, 0x40, 0xD2, 0x4E, 0xAF, 0x42, 0xD2, 0x4F, /* 0x6C-0x6F */ - 0xD2, 0x59, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xAF, 0x44, 0xD2, 0x68, 0xD2, 0x48, 0xAE, 0xFC, /* 0x74-0x77 */ - 0xAE, 0xFB, 0xAF, 0x48, 0xD2, 0x45, 0xD2, 0x66, /* 0x78-0x7B */ - 0xD2, 0x5A, 0xD2, 0x67, 0xD2, 0x61, 0xD2, 0x53, /* 0x7C-0x7F */ - - 0xD2, 0x62, 0x00, 0x00, 0xD2, 0x5C, 0xD2, 0x65, /* 0x80-0x83 */ - 0xD2, 0x63, 0xAF, 0x49, 0xD2, 0x54, 0xAE, 0xF9, /* 0x84-0x87 */ - 0xAE, 0xF8, 0xAF, 0x41, 0xAF, 0x47, 0xD2, 0x60, /* 0x88-0x8B */ - 0xAF, 0x46, 0xD2, 0x51, 0xB2, 0x43, 0x00, 0x00, /* 0x8C-0x8F */ - 0xD2, 0x69, 0xD2, 0x50, 0xD2, 0x4B, 0xAE, 0xFE, /* 0x90-0x93 */ - 0xAF, 0x4B, 0xAE, 0xF7, 0x00, 0x00, 0xD2, 0x58, /* 0x94-0x97 */ - 0xD2, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0xB2, 0x65, 0xD5, 0xE1, /* 0xA8-0xAB */ - 0xD5, 0xE5, 0x00, 0x00, 0xB2, 0x52, 0xB2, 0x50, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xB2, 0x47, 0xD5, 0xE3, /* 0xB0-0xB3 */ - 0xD5, 0xE2, 0xB2, 0x5B, 0x00, 0x00, 0xD5, 0xE8, /* 0xB4-0xB7 */ - 0xB2, 0x55, 0x00, 0x00, 0xD5, 0xFA, 0xD6, 0x47, /* 0xB8-0xBB */ - 0xB2, 0x44, 0xD5, 0xF7, 0xD5, 0xF0, 0xB2, 0x67, /* 0xBC-0xBF */ - 0xD5, 0xE0, 0x00, 0x00, 0xD5, 0xFC, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xB2, 0x64, 0xB2, 0x58, 0xB2, 0x63, 0xB2, 0x4E, /* 0xC4-0xC7 */ - 0xD5, 0xEC, 0xD5, 0xFE, 0xD5, 0xF6, 0xB2, 0x4F, /* 0xC8-0xCB */ - 0xB2, 0x49, 0xD6, 0x45, 0x00, 0x00, 0xD5, 0xFD, /* 0xCC-0xCF */ - 0xD6, 0x40, 0xB2, 0x51, 0xB2, 0x59, 0xD6, 0x42, /* 0xD0-0xD3 */ - 0xD5, 0xEA, 0xD5, 0xFB, 0xD5, 0xEF, 0xD6, 0x44, /* 0xD4-0xD7 */ - 0xB2, 0x5E, 0xB2, 0x46, 0xB2, 0x5C, 0xD5, 0xF4, /* 0xD8-0xDB */ - 0xD5, 0xF2, 0xD5, 0xF3, 0xB2, 0x53, 0xD5, 0xEE, /* 0xDC-0xDF */ - 0xD5, 0xED, 0xB2, 0x48, 0xD5, 0xE7, 0xD6, 0x46, /* 0xE0-0xE3 */ - 0xB2, 0x4A, 0xD5, 0xF1, 0xB2, 0x68, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xB2, 0x62, 0xD5, 0xE6, 0xB2, 0x5F, 0xB2, 0x5D, /* 0xE8-0xEB */ - 0xB2, 0x66, 0xD5, 0xF8, 0xB2, 0x61, 0xD2, 0x52, /* 0xEC-0xEF */ - 0xD5, 0xF9, 0xB2, 0x60, 0xD6, 0x41, 0xB2, 0x45, /* 0xF0-0xF3 */ - 0xD5, 0xF5, 0xB2, 0x57, 0xD5, 0xE9, 0xB2, 0x56, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xB2, 0x54, 0xB2, 0x4C, 0xB2, 0x4B, /* 0xF8-0xFB */ - 0xD9, 0xE7, 0xD6, 0x43, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_6E[512] = { - 0xD5, 0xEB, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xFC, /* 0x00-0x03 */ - 0x00, 0x00, 0xB2, 0x4D, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xB5, 0x41, 0xB2, 0x5A, 0xB4, 0xEE, /* 0x18-0x1B */ - 0xD9, 0xF6, 0xB4, 0xFC, 0x00, 0x00, 0xD9, 0xEA, /* 0x1C-0x1F */ - 0xB4, 0xEB, 0xB4, 0xE7, 0xDA, 0x49, 0xB4, 0xED, /* 0x20-0x23 */ - 0xB4, 0xF1, 0xB4, 0xEC, 0xB4, 0xF5, 0xDA, 0x4D, /* 0x24-0x27 */ - 0xDA, 0x44, 0x00, 0x00, 0x00, 0x00, 0xD9, 0xF1, /* 0x28-0x2B */ - 0xB4, 0xFA, 0xB4, 0xF4, 0xD9, 0xFD, 0xB4, 0xE4, /* 0x2C-0x2F */ - 0xDA, 0x4A, 0xDA, 0x43, 0xB4, 0xE8, 0xD9, 0xF7, /* 0x30-0x33 */ - 0xB4, 0xF7, 0xDA, 0x55, 0xDA, 0x56, 0x00, 0x00, /* 0x34-0x37 */ - 0xB4, 0xE5, 0xDA, 0x48, 0xB4, 0xF9, 0xD9, 0xFB, /* 0x38-0x3B */ - 0xD9, 0xED, 0xD9, 0xEE, 0xB4, 0xFD, 0xD9, 0xF2, /* 0x3C-0x3F */ - 0xD9, 0xF9, 0xD9, 0xF3, 0x00, 0x00, 0xB4, 0xFB, /* 0x40-0x43 */ - 0xB5, 0x44, 0xD9, 0xEF, 0xD9, 0xE8, 0xD9, 0xE9, /* 0x44-0x47 */ - 0x00, 0x00, 0xD9, 0xEB, 0xB4, 0xEA, 0xD9, 0xF8, /* 0x48-0x4B */ - 0x00, 0x00, 0xB4, 0xF8, 0xB5, 0x42, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0xD9, 0xFA, 0xDA, 0x53, 0xDA, 0x4B, /* 0x50-0x53 */ - 0xB4, 0xE6, 0xDA, 0x51, 0xB4, 0xF2, 0x00, 0x00, /* 0x54-0x57 */ - 0xB4, 0xF0, 0x00, 0x00, 0xDA, 0x57, 0xB4, 0xEF, /* 0x58-0x5B */ - 0xDA, 0x41, 0xD9, 0xF4, 0xD9, 0xFE, 0xB5, 0x47, /* 0x5C-0x5F */ - 0xDA, 0x45, 0xDA, 0x42, 0xD9, 0xF0, 0xB5, 0x43, /* 0x60-0x63 */ - 0xDA, 0x4F, 0xDA, 0x4C, 0xDA, 0x54, 0xB4, 0xE9, /* 0x64-0x67 */ - 0xDA, 0x40, 0xB5, 0x46, 0x00, 0x00, 0xDA, 0x47, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0xB4, 0xF3, 0xB4, 0xF6, /* 0x6C-0x6F */ - 0x00, 0x00, 0xDA, 0x46, 0xB5, 0x45, 0xD9, 0xF5, /* 0x70-0x73 */ - 0xD5, 0xE4, 0x00, 0x00, 0x00, 0x00, 0xDA, 0x50, /* 0x74-0x77 */ - 0xDA, 0x4E, 0xDA, 0x52, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xD9, 0xEC, 0xB5, 0x40, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0xDE, 0x61, 0xDE, 0x60, 0xDE, 0x46, /* 0x8C-0x8F */ - 0xB7, 0xBD, 0x00, 0x00, 0xDE, 0x5F, 0xDE, 0x49, /* 0x90-0x93 */ - 0xDE, 0x4A, 0x00, 0x00, 0xB7, 0xC7, 0xDE, 0x68, /* 0x94-0x97 */ - 0xB7, 0xC2, 0xDE, 0x5E, 0x00, 0x00, 0xDE, 0x43, /* 0x98-0x9B */ - 0xB7, 0xC8, 0xB7, 0xBE, 0xDE, 0x52, 0xDE, 0x48, /* 0x9C-0x9F */ - 0xDE, 0x4B, 0xDE, 0x63, 0xB7, 0xB8, 0xDE, 0x6A, /* 0xA0-0xA3 */ - 0xDE, 0x62, 0xB7, 0xC1, 0xDE, 0x57, 0xB7, 0xCC, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0xB7, 0xCB, 0xB7, 0xC5, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xDE, 0x69, 0xB7, 0xB9, /* 0xAC-0xAF */ - 0xDE, 0x55, 0xDE, 0x4C, 0xDE, 0x59, 0xDE, 0x65, /* 0xB0-0xB3 */ - 0xB7, 0xCD, 0x00, 0x00, 0xB7, 0xBB, 0xDE, 0x54, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xDE, 0x4D, 0xB7, 0xC4, 0x00, 0x00, /* 0xB8-0xBB */ - 0xB7, 0xC3, 0xDE, 0x50, 0xDE, 0x5A, 0xDE, 0x64, /* 0xBC-0xBF */ - 0xDE, 0x47, 0xDE, 0x51, 0xB7, 0xBC, 0xDE, 0x5B, /* 0xC0-0xC3 */ - 0xB7, 0xC9, 0xB7, 0xC0, 0xDE, 0x4E, 0xB7, 0xBF, /* 0xC4-0xC7 */ - 0xDE, 0x45, 0xDE, 0x53, 0xDE, 0x67, 0xB4, 0xFE, /* 0xC8-0xCB */ - 0xBA, 0xB0, 0xDE, 0x56, 0xE2, 0x6C, 0xDE, 0x58, /* 0xCC-0xCF */ - 0xDE, 0x66, 0xB7, 0xC6, 0xDE, 0x4F, 0xB7, 0xBA, /* 0xD0-0xD3 */ - 0xB7, 0xCA, 0xBC, 0xF0, 0xDE, 0x44, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xDE, 0x5D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xDE, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xAA, /* 0xE8-0xEB */ - 0xBA, 0xAD, 0xE2, 0x7D, 0xE2, 0xA4, 0xBA, 0xA2, /* 0xEC-0xEF */ - 0x00, 0x00, 0xE2, 0x6E, 0xBA, 0xAF, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xBA, 0x77, 0xE2, 0x6D, 0xE2, 0xB0, 0xBA, 0xB1, /* 0xF4-0xF7 */ - 0xE2, 0x71, 0xE2, 0xA3, 0x00, 0x00, 0xE2, 0x73, /* 0xF8-0xFB */ - 0xE2, 0xB3, 0xE2, 0xAF, 0xBA, 0x75, 0xBA, 0xA1, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_6F[512] = { - 0xE6, 0x53, 0xBA, 0xAE, 0xBA, 0x7D, 0xE2, 0x6F, /* 0x00-0x03 */ - 0x00, 0x00, 0xE2, 0xAE, 0xBA, 0xA3, 0xE2, 0xAB, /* 0x04-0x07 */ - 0xE2, 0xB8, 0xE2, 0x75, 0xE2, 0x7E, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0xE2, 0xB6, 0xE2, 0xAC, 0xBA, 0x7C, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0x7C, 0xBA, 0x76, /* 0x10-0x13 */ - 0xBA, 0x74, 0xBA, 0xA8, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xE2, 0x7A, 0xE2, 0x77, 0xE2, 0x78, 0x00, 0x00, /* 0x18-0x1B */ - 0xE2, 0xB2, 0x00, 0x00, 0xE2, 0xB7, 0xE2, 0xB5, /* 0x1C-0x1F */ - 0xBA, 0x7A, 0xE2, 0xB9, 0xBA, 0x7E, 0xBA, 0xA7, /* 0x20-0x23 */ - 0x00, 0x00, 0xE2, 0x70, 0xE5, 0xFA, 0xE2, 0x79, /* 0x24-0x27 */ - 0x00, 0x00, 0xBA, 0x78, 0xBA, 0xAC, 0xBA, 0xA9, /* 0x28-0x2B */ - 0xBA, 0x7B, 0xE2, 0xA5, 0xE2, 0x74, 0xBA, 0xAA, /* 0x2C-0x2F */ - 0xE2, 0xA7, 0xBA, 0xA4, 0xBA, 0xA6, 0xBA, 0x73, /* 0x30-0x33 */ - 0x00, 0x00, 0xE2, 0xA9, 0xE2, 0xA1, 0xE2, 0x72, /* 0x34-0x37 */ - 0xBA, 0xA5, 0xE2, 0xB1, 0xE2, 0xB4, 0xE2, 0x7B, /* 0x38-0x3B */ - 0xE2, 0xA8, 0x00, 0x00, 0xBA, 0x79, 0xBC, 0xDF, /* 0x3C-0x3F */ - 0xE2, 0xA6, 0xE5, 0xF9, 0x00, 0x00, 0xE2, 0xAD, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0x76, 0xE6, 0x44, /* 0x4C-0x4F */ - 0xE6, 0x4E, 0xBC, 0xE2, 0xE6, 0x4D, 0xE6, 0x59, /* 0x50-0x53 */ - 0xBC, 0xE4, 0xE6, 0x4B, 0x00, 0x00, 0xE6, 0x4F, /* 0x54-0x57 */ - 0xBC, 0xEF, 0x00, 0x00, 0xE6, 0x46, 0xBC, 0xE7, /* 0x58-0x5B */ - 0x00, 0x00, 0xE6, 0x52, 0xE9, 0xF0, 0xBC, 0xF3, /* 0x5C-0x5F */ - 0xBC, 0xF2, 0xE6, 0x54, 0xE6, 0x43, 0xE6, 0x5E, /* 0x60-0x63 */ - 0xBC, 0xED, 0x00, 0x00, 0xBC, 0xE3, 0xE6, 0x57, /* 0x64-0x67 */ - 0x00, 0x00, 0xE6, 0x5B, 0xE6, 0x60, 0xE6, 0x55, /* 0x68-0x6B */ - 0xE6, 0x49, 0xBC, 0xE6, 0xBC, 0xE9, 0xBC, 0xF1, /* 0x6C-0x6F */ - 0xBC, 0xEC, 0x00, 0x00, 0xE6, 0x4C, 0xE2, 0xA2, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0x48, 0xE6, 0x5F, /* 0x74-0x77 */ - 0xBC, 0xE8, 0x00, 0x00, 0xBC, 0xEB, 0xE6, 0x61, /* 0x78-0x7B */ - 0xBC, 0xE0, 0xE6, 0x56, 0xE5, 0xFB, 0xE6, 0x5C, /* 0x7C-0x7F */ - - 0xC0, 0xDF, 0x00, 0x00, 0xE6, 0x4A, 0x00, 0x00, /* 0x80-0x83 */ - 0xBC, 0xE1, 0xE6, 0x45, 0xBC, 0xE5, 0xE5, 0xFC, /* 0x84-0x87 */ - 0xBA, 0xAB, 0xE6, 0x41, 0x00, 0x00, 0xE6, 0x5A, /* 0x88-0x8B */ - 0xE6, 0x42, 0xE6, 0x40, 0xBC, 0xEA, 0x00, 0x00, /* 0x8C-0x8F */ - 0xE6, 0x58, 0x00, 0x00, 0xE5, 0xFE, 0xE6, 0x51, /* 0x90-0x93 */ - 0xE6, 0x50, 0xE6, 0x5D, 0xE6, 0x47, 0xBC, 0xEE, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xE9, 0xF3, 0x00, 0x00, /* 0x9C-0x9F */ - 0xBF, 0x49, 0xBE, 0xFE, 0xEA, 0x40, 0xE9, 0xEB, /* 0xA0-0xA3 */ - 0xBF, 0x41, 0xE9, 0xF7, 0xBF, 0x48, 0xBF, 0x43, /* 0xA4-0xA7 */ - 0xE9, 0xF5, 0xED, 0x4F, 0xE9, 0xFB, 0xEA, 0x42, /* 0xA8-0xAB */ - 0xE9, 0xFA, 0xE9, 0xE9, 0xE9, 0xF8, 0xEA, 0x44, /* 0xAC-0xAF */ - 0xEA, 0x46, 0xBE, 0xFD, 0xEA, 0x45, 0xBF, 0x44, /* 0xB0-0xB3 */ - 0xBF, 0x4A, 0x00, 0x00, 0xBF, 0x47, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xE9, 0xFE, 0xBF, 0x46, 0xE9, 0xF9, 0x00, 0x00, /* 0xB8-0xBB */ - 0xE9, 0xED, 0xE9, 0xF2, 0x00, 0x00, 0xE9, 0xFD, /* 0xBC-0xBF */ - 0xBF, 0x45, 0xBF, 0x42, 0xBE, 0xFC, 0xBF, 0x40, /* 0xC0-0xC3 */ - 0xE9, 0xF1, 0x00, 0x00, 0xE5, 0xFD, 0xE9, 0xEC, /* 0xC4-0xC7 */ - 0xE9, 0xEF, 0xEA, 0x41, 0xE9, 0xF4, 0xE9, 0xEA, /* 0xC8-0xCB */ - 0xED, 0x4E, 0xEA, 0x43, 0xE9, 0xEE, 0xE9, 0xFC, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xED, 0x51, 0xC0, 0xE3, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xC0, 0xD7, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xDB, /* 0xD8-0xDB */ - 0xED, 0x53, 0xED, 0x59, 0xED, 0x57, 0xC0, 0xD9, /* 0xDC-0xDF */ - 0xC0, 0xDA, 0xC0, 0xE1, 0xED, 0x5A, 0xED, 0x52, /* 0xE0-0xE3 */ - 0xC0, 0xDC, 0x00, 0x00, 0xED, 0x56, 0xED, 0x55, /* 0xE4-0xE7 */ - 0xED, 0x5B, 0xC0, 0xE2, 0x00, 0x00, 0xC0, 0xDD, /* 0xE8-0xEB */ - 0xC0, 0xE0, 0xED, 0x54, 0xC0, 0xE4, 0xC0, 0xDE, /* 0xEC-0xEF */ - 0xC0, 0xE5, 0xC0, 0xD8, 0xED, 0x58, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xED, 0x50, 0x00, 0x00, 0x00, 0x00, 0xEF, 0xF7, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0xC2, 0x71, 0xEF, 0xF4, /* 0xF8-0xFB */ - 0xEF, 0xF6, 0x00, 0x00, 0xC2, 0x6F, 0xEF, 0xF2, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_70[512] = { - 0xEF, 0xF3, 0xEF, 0xEE, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xE9, 0xF6, 0xEF, 0xEF, 0xC2, 0x70, 0xEF, 0xEB, /* 0x04-0x07 */ - 0x00, 0x00, 0xC2, 0x6D, 0xEF, 0xF8, 0xC2, 0x6E, /* 0x08-0x0B */ - 0xEF, 0xEC, 0xEF, 0xED, 0xEF, 0xF1, 0xC2, 0x73, /* 0x0C-0x0F */ - 0x00, 0x00, 0xC2, 0x72, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xEF, 0xF0, 0xC3, 0x78, 0xF2, 0x5F, 0xF2, 0x65, /* 0x14-0x17 */ - 0xC3, 0x79, 0xF2, 0x5C, 0xC3, 0x76, 0xC3, 0x73, /* 0x18-0x1B */ - 0xF2, 0x67, 0xC3, 0x77, 0x00, 0x00, 0xC3, 0x74, /* 0x1C-0x1F */ - 0xF2, 0x5E, 0xF2, 0x61, 0xF2, 0x62, 0xF2, 0x63, /* 0x20-0x23 */ - 0xF2, 0x66, 0x00, 0x00, 0xEF, 0xF5, 0xF2, 0x5D, /* 0x24-0x27 */ - 0xC3, 0x75, 0xF2, 0x64, 0xF2, 0x68, 0xF2, 0x60, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x5D, /* 0x2C-0x2F */ - 0xC4, 0x6A, 0xF4, 0x60, 0xC4, 0x6B, 0xF4, 0x68, /* 0x30-0x33 */ - 0xF4, 0x5F, 0xF4, 0x5C, 0x00, 0x00, 0xF4, 0x5E, /* 0x34-0x37 */ - 0xF4, 0x62, 0xF4, 0x65, 0xF4, 0x64, 0xF4, 0x67, /* 0x38-0x3B */ - 0xF4, 0x5B, 0x00, 0x00, 0xC4, 0x69, 0xF4, 0x63, /* 0x3C-0x3F */ - 0xF4, 0x66, 0xF4, 0x69, 0xF4, 0x61, 0xF5, 0xD3, /* 0x40-0x43 */ - 0xF5, 0xD4, 0xF5, 0xD8, 0xF5, 0xD9, 0x00, 0x00, /* 0x44-0x47 */ - 0xF5, 0xD6, 0xF5, 0xD7, 0xF5, 0xD5, 0x00, 0x00, /* 0x48-0x4B */ - 0xC4, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0xC5, 0x78, 0xF6, 0xEB, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xF6, 0xE8, 0xF6, 0xE9, 0xF6, 0xEA, /* 0x54-0x57 */ - 0xC5, 0x79, 0x00, 0x00, 0xF7, 0xE5, 0xF7, 0xE4, /* 0x58-0x5B */ - 0x00, 0x00, 0xF8, 0xAF, 0xC5, 0xF4, 0xF8, 0xAD, /* 0x5C-0x5F */ - 0xF8, 0xB0, 0xF8, 0xAE, 0xF8, 0xF5, 0xC6, 0x57, /* 0x60-0x63 */ - 0xC6, 0x65, 0xF9, 0xA3, 0xF9, 0x6C, 0x00, 0x00, /* 0x64-0x67 */ - 0xF9, 0xA2, 0xF9, 0xD0, 0xF9, 0xD1, 0xA4, 0xF5, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xA6, 0xC7, 0xCA, 0x41, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xCB, 0x5E, 0x00, 0x00, 0xA8, 0x5F, 0x00, 0x00, /* 0x74-0x77 */ - 0xA8, 0x62, 0x00, 0x00, 0xCB, 0x5F, 0x00, 0x00, /* 0x78-0x7B */ - 0xA8, 0x60, 0xA8, 0x61, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xCD, 0x58, 0xCD, 0x5A, /* 0x80-0x83 */ - 0xCD, 0x55, 0xCD, 0x52, 0xCD, 0x54, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA4, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xAA, 0xA2, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xCD, 0x56, 0xAA, 0xA3, 0xCD, 0x53, /* 0x90-0x93 */ - 0xCD, 0x50, 0xAA, 0xA1, 0xCD, 0x57, 0x00, 0x00, /* 0x94-0x97 */ - 0xCD, 0x51, 0xAA, 0xA5, 0xCD, 0x59, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xAF, /* 0x9C-0x9F */ - 0x00, 0x00, 0xCF, 0xB3, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xAC, 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xCF, 0xB6, 0x00, 0x00, 0xAC, 0xAF, /* 0xA8-0xAB */ - 0xAC, 0xB2, 0xAC, 0xB4, 0xAC, 0xB6, 0xAC, 0xB3, /* 0xAC-0xAF */ - 0xCF, 0xB2, 0xCF, 0xB1, 0x00, 0x00, 0xAC, 0xB1, /* 0xB0-0xB3 */ - 0xCF, 0xB4, 0xCF, 0xB5, 0x00, 0x00, 0xCF, 0xAE, /* 0xB4-0xB7 */ - 0xAC, 0xB5, 0x00, 0x00, 0xAC, 0xB0, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xCF, 0xB0, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xD2, 0x77, 0xD2, 0x78, 0xD2, 0x79, /* 0xC4-0xC7 */ - 0xAF, 0x50, 0x00, 0x00, 0xAF, 0x4C, 0xD2, 0x6E, /* 0xC8-0xCB */ - 0x00, 0x00, 0xD2, 0x76, 0xD2, 0x7B, 0xAF, 0x51, /* 0xCC-0xCF */ - 0x00, 0x00, 0xD2, 0x6C, 0xD2, 0x72, 0xD2, 0x6B, /* 0xD0-0xD3 */ - 0xD2, 0x75, 0x00, 0x00, 0x00, 0x00, 0xD2, 0x71, /* 0xD4-0xD7 */ - 0xAF, 0x4D, 0xAF, 0x4F, 0xD2, 0x7A, 0x00, 0x00, /* 0xD8-0xDB */ - 0xD2, 0x6A, 0xD2, 0x6D, 0xD2, 0x73, 0x00, 0x00, /* 0xDC-0xDF */ - 0xD2, 0x74, 0xD2, 0x7C, 0xD2, 0x70, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xAF, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB2, 0x6D, /* 0xEC-0xEF */ - 0xD6, 0x4E, 0x00, 0x00, 0x00, 0x00, 0xD6, 0x50, /* 0xF0-0xF3 */ - 0xD6, 0x4C, 0x00, 0x00, 0xD6, 0x58, 0xD6, 0x4A, /* 0xF4-0xF7 */ - 0xD6, 0x57, 0xB2, 0x69, 0xD6, 0x48, 0xDA, 0x5B, /* 0xF8-0xFB */ - 0xD6, 0x52, 0xB2, 0x6C, 0x00, 0x00, 0xD6, 0x53, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_71[512] = { - 0xD6, 0x56, 0x00, 0x00, 0xD6, 0x5A, 0x00, 0x00, /* 0x00-0x03 */ - 0xD6, 0x4F, 0x00, 0x00, 0xD6, 0x54, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xB2, 0x6A, 0xB2, 0x6B, 0xD6, 0x59, /* 0x08-0x0B */ - 0xD6, 0x4D, 0xD6, 0x49, 0xD6, 0x5B, 0x00, 0x00, /* 0x0C-0x0F */ - 0xD6, 0x51, 0x00, 0x00, 0x00, 0x00, 0xD6, 0x55, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0x4B, /* 0x14-0x17 */ - 0x00, 0x00, 0xB5, 0x48, 0xB5, 0x49, 0xDA, 0x65, /* 0x18-0x1B */ - 0xB5, 0x4F, 0x00, 0x00, 0xDA, 0x59, 0xDA, 0x62, /* 0x1C-0x1F */ - 0xDA, 0x58, 0xB5, 0x4C, 0xDA, 0x60, 0xDA, 0x5E, /* 0x20-0x23 */ - 0x00, 0x00, 0xDA, 0x5F, 0xB5, 0x4A, 0x00, 0x00, /* 0x24-0x27 */ - 0xDA, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0x5C, 0xDA, 0x5A, /* 0x2C-0x2F */ - 0xB5, 0x4B, 0xDA, 0x5D, 0xDA, 0x61, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xB5, 0x4D, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0x64, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xDE, 0x70, 0xDE, 0x77, 0xDE, 0x79, /* 0x40-0x43 */ - 0xDE, 0xA1, 0x00, 0x00, 0xB7, 0xDA, 0xDE, 0x6B, /* 0x44-0x47 */ - 0x00, 0x00, 0xB7, 0xD2, 0x00, 0x00, 0xDE, 0x7A, /* 0x48-0x4B */ - 0xB7, 0xD7, 0xDE, 0xA2, 0xB7, 0xCE, 0x00, 0x00, /* 0x4C-0x4F */ - 0xDE, 0x7D, 0x00, 0x00, 0xDE, 0x6D, 0xDE, 0x7E, /* 0x50-0x53 */ - 0xDE, 0x6C, 0x00, 0x00, 0xB7, 0xDC, 0x00, 0x00, /* 0x54-0x57 */ - 0xDE, 0x78, 0xB7, 0xCF, 0xDE, 0xA3, 0x00, 0x00, /* 0x58-0x5B */ - 0xB7, 0xD4, 0xDE, 0x71, 0xB7, 0xD9, 0xDE, 0x7C, /* 0x5C-0x5F */ - 0xDE, 0x6F, 0xDE, 0x76, 0xDE, 0x72, 0xDE, 0x6E, /* 0x60-0x63 */ - 0xB7, 0xD1, 0xB7, 0xD8, 0xB7, 0xD6, 0xB7, 0xD3, /* 0x64-0x67 */ - 0xB7, 0xDB, 0xB7, 0xD0, 0xDE, 0x75, 0x00, 0x00, /* 0x68-0x6B */ - 0xB7, 0xD5, 0x00, 0x00, 0xB5, 0x4E, 0x00, 0x00, /* 0x6C-0x6F */ - 0xDE, 0x7B, 0x00, 0x00, 0xDE, 0x73, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0xDE, 0x74, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xC1, /* 0x78-0x7B */ - 0x00, 0x00, 0xBA, 0xB4, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xE2, 0xBD, 0xE2, 0xC3, 0xE2, 0xBF, 0x00, 0x00, /* 0x80-0x83 */ - 0xBA, 0xB6, 0xE2, 0xBE, 0xE2, 0xC2, 0xE2, 0xBA, /* 0x84-0x87 */ - 0x00, 0x00, 0xE2, 0xBC, 0xBA, 0xB5, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xC0, /* 0x8C-0x8F */ - 0xE2, 0xBB, 0x00, 0x00, 0xBA, 0xB7, 0x00, 0x00, /* 0x90-0x93 */ - 0xBA, 0xB2, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xC4, /* 0x94-0x97 */ - 0x00, 0x00, 0xBA, 0xB3, 0xE6, 0x67, 0xE6, 0x64, /* 0x98-0x9B */ - 0xE6, 0x70, 0xE6, 0x6A, 0xE6, 0x6C, 0xBC, 0xF4, /* 0x9C-0x9F */ - 0xE6, 0x66, 0xE6, 0x6E, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xE6, 0x6D, 0xE6, 0x6B, 0x00, 0x00, 0xE6, 0x71, /* 0xA4-0xA7 */ - 0xBC, 0xF7, 0xE6, 0x68, 0xE6, 0x6F, 0x00, 0x00, /* 0xA8-0xAB */ - 0xBC, 0xF5, 0x00, 0x00, 0x00, 0x00, 0xE6, 0x63, /* 0xAC-0xAF */ - 0xE6, 0x65, 0xBC, 0xF6, 0xE6, 0x62, 0xE6, 0x72, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xE6, 0x69, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xEA, 0x4A, 0xBF, 0x51, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0xEA, 0x55, 0xEA, 0x53, 0xBF, 0x4B, 0xEA, 0x49, /* 0xBC-0xBF */ - 0xEA, 0x4C, 0xEA, 0x4D, 0xEA, 0x48, 0xBF, 0x55, /* 0xC0-0xC3 */ - 0xBF, 0x56, 0xEA, 0x47, 0xEA, 0x56, 0xEA, 0x51, /* 0xC4-0xC7 */ - 0xBF, 0x4F, 0xBF, 0x4C, 0xEA, 0x50, 0xEA, 0x4E, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xBF, 0x52, 0xEA, 0x52, /* 0xCC-0xCF */ - 0xBF, 0x4D, 0x00, 0x00, 0xBF, 0x4E, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xEA, 0x4F, 0xBF, 0x50, 0xEA, 0x4B, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xEA, 0x54, 0xBF, 0x53, 0xEA, 0x57, 0xEA, 0x58, /* 0xD8-0xDB */ - 0xBF, 0x54, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xE7, /* 0xDC-0xDF */ - 0xC0, 0xEE, 0xED, 0x5C, 0xED, 0x62, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xED, 0x60, 0xC0, 0xEA, 0xC0, 0xE9, 0xC0, 0xE6, /* 0xE4-0xE7 */ - 0xED, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xC0, 0xEC, 0xC0, 0xEB, 0xC0, 0xE8, 0x00, 0x00, /* 0xEC-0xEF */ - 0xED, 0x61, 0xED, 0x5D, 0xED, 0x5F, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xC0, 0xED, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xC2, 0x77, 0xEF, 0xFB, 0x00, 0x00, 0xC2, 0x74, /* 0xF8-0xFB */ - 0xC2, 0x75, 0xEF, 0xFD, 0xC2, 0x76, 0xEF, 0xFA, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_72[512] = { - 0x00, 0x00, 0xEF, 0xF9, 0xF2, 0x6C, 0xEF, 0xFC, /* 0x00-0x03 */ - 0x00, 0x00, 0xF2, 0x6D, 0xC3, 0x7A, 0xF2, 0x6B, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xF2, 0x6A, 0x00, 0x00, /* 0x08-0x0B */ - 0xF2, 0x69, 0xC3, 0x7B, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xC4, 0x6C, 0x00, 0x00, 0x00, 0x00, 0xF4, 0x6A, /* 0x10-0x13 */ - 0xF4, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xF5, 0xDC, 0xF5, 0xDB, 0xC4, 0xEA, /* 0x18-0x1B */ - 0x00, 0x00, 0xF5, 0xDA, 0xF6, 0xEC, 0xF6, 0xED, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0xF7, 0xE6, 0xF8, 0xB1, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xF6, 0xF9, 0xBC, /* 0x24-0x27 */ - 0xC6, 0x79, 0xF9, 0xC6, 0xA4, 0xF6, 0x00, 0x00, /* 0x28-0x2B */ - 0xAA, 0xA6, 0xAA, 0xA7, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xAC, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0xC0, 0xEF, 0xA4, 0xF7, 0x00, 0x00, /* 0x34-0x37 */ - 0xAA, 0xA8, 0xAF, 0x52, 0xB7, 0xDD, 0xA4, 0xF8, /* 0x38-0x3B */ - 0x00, 0x00, 0xB2, 0x6E, 0xBA, 0xB8, 0xC9, 0x62, /* 0x3C-0x3F */ - 0x00, 0x00, 0xCF, 0xB7, 0xD2, 0x7D, 0x00, 0x00, /* 0x40-0x43 */ - 0xE2, 0xC5, 0x00, 0x00, 0xC0, 0xF0, 0xA4, 0xF9, /* 0x44-0x47 */ - 0xAA, 0xA9, 0xCF, 0xB8, 0xCF, 0xB9, 0xDA, 0x66, /* 0x48-0x4B */ - 0xB5, 0x50, 0x00, 0x00, 0x00, 0x00, 0xDE, 0xA4, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xB7, 0xDE, 0xE2, 0xC6, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xBC, 0xF8, 0x00, 0x00, /* 0x54-0x57 */ - 0xC3, 0x7C, 0xA4, 0xFA, 0xDA, 0x67, 0xA4, 0xFB, /* 0x58-0x5B */ - 0x00, 0x00, 0xA6, 0xC9, 0xCA, 0x42, 0xA6, 0xC8, /* 0x5C-0x5F */ - 0xA8, 0x65, 0xA8, 0x64, 0xA8, 0x63, 0xCB, 0x60, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xAA, /* 0x64-0x67 */ - 0x00, 0x00, 0xAA, 0xAB, 0xCD, 0x5B, 0x00, 0x00, /* 0x68-0x6B */ - 0xCF, 0xBA, 0x00, 0x00, 0xCF, 0xBD, 0xAC, 0xBA, /* 0x6C-0x6F */ - 0xCF, 0xBB, 0x00, 0x00, 0xAC, 0xB9, 0xCF, 0xBC, /* 0x70-0x73 */ - 0xAC, 0xBB, 0x00, 0x00, 0xD2, 0xA2, 0xD2, 0xA1, /* 0x74-0x77 */ - 0xD2, 0x7E, 0xAF, 0x53, 0x00, 0x00, 0xD6, 0x5D, /* 0x78-0x7B */ - 0xD6, 0x5E, 0xB2, 0x6F, 0xD6, 0x5C, 0xD6, 0x5F, /* 0x7C-0x7F */ - - 0xB5, 0x52, 0xB2, 0x70, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xB5, 0x51, 0xDA, 0x6B, 0xDA, 0x6A, 0x00, 0x00, /* 0x84-0x87 */ - 0xDA, 0x68, 0xDA, 0x69, 0x00, 0x00, 0xDA, 0x6C, /* 0x88-0x8B */ - 0xDE, 0xA6, 0xDE, 0xA5, 0xDE, 0xA9, 0x00, 0x00, /* 0x8C-0x8F */ - 0xDE, 0xA8, 0xDE, 0xA7, 0xBA, 0xB9, 0xE2, 0xC9, /* 0x90-0x93 */ - 0x00, 0x00, 0xE2, 0xC8, 0xBA, 0xBA, 0xE2, 0xC7, /* 0x94-0x97 */ - 0xE6, 0x73, 0x00, 0x00, 0xE6, 0x74, 0xBC, 0xF9, /* 0x98-0x9B */ - 0x00, 0x00, 0xEA, 0x59, 0xEA, 0x5A, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xF2, 0x72, 0xC3, 0x7D, 0xF2, 0x71, /* 0xA0-0xA3 */ - 0xF2, 0x70, 0xF2, 0x6E, 0xF2, 0x6F, 0xC4, 0xEB, /* 0xA4-0xA7 */ - 0xF4, 0x6C, 0xF6, 0xEE, 0xF8, 0xF7, 0x00, 0x00, /* 0xA8-0xAB */ - 0xA4, 0xFC, 0x00, 0x00, 0xC9, 0xA5, 0xA5, 0xC7, /* 0xAC-0xAF */ - 0xC9, 0xA6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xCA, 0x43, 0xCA, 0x44, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xCB, 0x66, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xCB, 0x62, 0x00, 0x00, 0xCB, 0x61, /* 0xBC-0xBF */ - 0xAA, 0xAC, 0xCB, 0x65, 0xA8, 0x67, 0xCB, 0x63, /* 0xC0-0xC3 */ - 0xA8, 0x66, 0xCB, 0x67, 0xCB, 0x64, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xCD, 0x5F, 0xCF, 0xBE, 0xCD, 0x5D, /* 0xC8-0xCB */ - 0xCD, 0x64, 0x00, 0x00, 0xAA, 0xAD, 0x00, 0x00, /* 0xCC-0xCF */ - 0xAA, 0xB0, 0xCD, 0x65, 0xCD, 0x61, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xCD, 0x62, 0x00, 0x00, 0xCD, 0x5C, 0xAA, 0xAF, /* 0xD4-0xD7 */ - 0xCD, 0x5E, 0xAA, 0xAE, 0xCD, 0x63, 0x00, 0x00, /* 0xD8-0xDB */ - 0xCD, 0x60, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xC2, /* 0xDC-0xDF */ - 0xAC, 0xBD, 0xAC, 0xBE, 0x00, 0x00, 0xCF, 0xC5, /* 0xE0-0xE3 */ - 0xCF, 0xBF, 0x00, 0x00, 0xCF, 0xC4, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xCF, 0xC0, 0xAC, 0xBC, 0xCF, 0xC3, 0xCF, 0xC1, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD2, 0xA8, /* 0xF0-0xF3 */ - 0xD2, 0xA5, 0x00, 0x00, 0xD2, 0xA7, 0xAF, 0x58, /* 0xF4-0xF7 */ - 0xAF, 0x57, 0xAF, 0x55, 0xD2, 0xA4, 0xD2, 0xA9, /* 0xF8-0xFB */ - 0xAF, 0x54, 0xAF, 0x56, 0xD2, 0xA6, 0xD6, 0x67, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_73[512] = { - 0xD2, 0xA3, 0xD2, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD6, 0x62, /* 0x04-0x07 */ - 0xD6, 0x66, 0x00, 0x00, 0xD6, 0x65, 0xDA, 0x6E, /* 0x08-0x0B */ - 0xDA, 0x79, 0x00, 0x00, 0x00, 0x00, 0xD6, 0x68, /* 0x0C-0x0F */ - 0x00, 0x00, 0xD6, 0x63, 0xDA, 0x6D, 0xB2, 0x74, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xB2, 0x73, 0xD6, 0x61, /* 0x14-0x17 */ - 0xD6, 0x64, 0xB2, 0x75, 0x00, 0x00, 0xB2, 0x72, /* 0x18-0x1B */ - 0xB2, 0x71, 0xD6, 0x60, 0xD6, 0x69, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0x70, 0xDA, 0x77, /* 0x20-0x23 */ - 0x00, 0x00, 0xB5, 0x54, 0xDA, 0x76, 0xDA, 0x73, /* 0x24-0x27 */ - 0x00, 0x00, 0xB5, 0x56, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0xDA, 0x75, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xDA, 0x6F, 0xDA, 0x71, 0xDA, 0x74, 0xDA, 0x72, /* 0x30-0x33 */ - 0xB5, 0x55, 0xDA, 0x78, 0xB5, 0x53, 0xB7, 0xDF, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xDE, 0xAD, 0xDE, 0xAC, /* 0x38-0x3B */ - 0xDE, 0xAA, 0x00, 0x00, 0xB7, 0xE2, 0xB7, 0xE1, /* 0x3C-0x3F */ - 0xDE, 0xAE, 0x00, 0x00, 0xDE, 0xAB, 0xE2, 0xCA, /* 0x40-0x43 */ - 0xBA, 0xBB, 0xB7, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xDE, 0xB0, 0xDE, 0xAF, 0x00, 0x00, /* 0x48-0x4B */ - 0xE2, 0xCD, 0xE2, 0xCB, 0xBC, 0xFA, 0x00, 0x00, /* 0x4C-0x4F */ - 0xBA, 0xBC, 0xE2, 0xCC, 0xE6, 0x76, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBC, 0xFB, /* 0x54-0x57 */ - 0xE6, 0x75, 0xE6, 0x7E, 0xE6, 0x7D, 0xE6, 0x7B, /* 0x58-0x5B */ - 0x00, 0x00, 0xE6, 0x7A, 0xE6, 0x77, 0xE6, 0x78, /* 0x5C-0x5F */ - 0xE6, 0x79, 0xE6, 0x7C, 0xE6, 0xA1, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0xEA, 0x5F, 0xEA, 0x5C, 0xEA, 0x5D, /* 0x64-0x67 */ - 0xBF, 0x57, 0xEA, 0x5B, 0xEA, 0x61, 0xEA, 0x60, /* 0x68-0x6B */ - 0xEA, 0x5E, 0x00, 0x00, 0xED, 0x64, 0xED, 0x65, /* 0x6C-0x6F */ - 0xC0, 0xF1, 0x00, 0x00, 0xC0, 0xF2, 0xED, 0x63, /* 0x70-0x73 */ - 0x00, 0x00, 0xC2, 0x79, 0xEF, 0xFE, 0xC2, 0x78, /* 0x74-0x77 */ - 0xC3, 0x7E, 0x00, 0x00, 0xC3, 0xA1, 0xC4, 0x6D, /* 0x78-0x7B */ - 0xF4, 0x6E, 0xF4, 0x6D, 0xF5, 0xDD, 0xF6, 0xEF, /* 0x7C-0x7F */ - - 0xC5, 0x7A, 0xF7, 0xE8, 0xF7, 0xE7, 0xF7, 0xE9, /* 0x80-0x83 */ - 0xA5, 0xC8, 0xCF, 0xC6, 0xAF, 0x59, 0xB2, 0x76, /* 0x84-0x87 */ - 0xD6, 0x6A, 0xA5, 0xC9, 0xC9, 0xA7, 0xA4, 0xFD, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xCA, 0x45, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xCB, 0x6C, 0xCB, 0x6A, /* 0x90-0x93 */ - 0xCB, 0x6B, 0xCB, 0x68, 0xA8, 0x68, 0xCB, 0x69, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xCD, 0x6D, 0x00, 0x00, 0xAA, 0xB3, /* 0x9C-0x9F */ - 0xCD, 0x6B, 0xCD, 0x67, 0xCD, 0x6A, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xCD, 0x66, 0xAA, 0xB5, 0xCD, 0x69, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xAA, 0xB2, 0xAA, 0xB1, 0x00, 0x00, 0xAA, 0xB4, /* 0xA8-0xAB */ - 0xCD, 0x6C, 0xCD, 0x68, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xAC, 0xC2, 0xAC, 0xC5, /* 0xB0-0xB3 */ - 0xCF, 0xCE, 0xCF, 0xCD, 0xCF, 0xCC, 0xAC, 0xBF, /* 0xB4-0xB7 */ - 0xCF, 0xD5, 0xCF, 0xCB, 0x00, 0x00, 0xAC, 0xC1, /* 0xB8-0xBB */ - 0xD2, 0xAF, 0x00, 0x00, 0xCF, 0xD2, 0xCF, 0xD0, /* 0xBC-0xBF */ - 0xAC, 0xC4, 0x00, 0x00, 0xCF, 0xC8, 0xCF, 0xD3, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xCF, 0xCA, 0xCF, 0xD4, 0xCF, 0xD1, /* 0xC4-0xC7 */ - 0xCF, 0xC9, 0x00, 0x00, 0xAC, 0xC0, 0xCF, 0xD6, /* 0xC8-0xCB */ - 0xCF, 0xC7, 0xAC, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xD2, 0xB4, 0xD2, 0xAB, /* 0xD0-0xD3 */ - 0xD2, 0xB6, 0x00, 0x00, 0xD2, 0xAE, 0xD2, 0xB9, /* 0xD4-0xD7 */ - 0xD2, 0xBA, 0xD2, 0xAC, 0xD2, 0xB8, 0xD2, 0xB5, /* 0xD8-0xDB */ - 0xD2, 0xB3, 0xD2, 0xB7, 0xAF, 0x5F, 0x00, 0x00, /* 0xDC-0xDF */ - 0xAF, 0x5D, 0x00, 0x00, 0x00, 0x00, 0xD2, 0xB1, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xD2, 0xAD, 0x00, 0x00, 0xD2, 0xB0, /* 0xE4-0xE7 */ - 0xD2, 0xBB, 0xD2, 0xB2, 0xAF, 0x5E, 0xCF, 0xCF, /* 0xE8-0xEB */ - 0x00, 0x00, 0xAF, 0x5A, 0xAF, 0x5C, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xD6, 0x78, 0xD6, 0x6D, 0xD6, 0x6B, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xD6, 0x6C, 0x00, 0x00, 0xD6, 0x73, 0x00, 0x00, /* 0xF8-0xFB */ - 0xD6, 0x74, 0xD6, 0x70, 0xB2, 0x7B, 0xD6, 0x75, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_74[512] = { - 0xD6, 0x72, 0xD6, 0x6F, 0x00, 0x00, 0xB2, 0x79, /* 0x00-0x03 */ - 0xD6, 0x6E, 0xB2, 0x77, 0xB2, 0x7A, 0xD6, 0x71, /* 0x04-0x07 */ - 0xD6, 0x79, 0xAF, 0x5B, 0xB2, 0x78, 0xD6, 0x77, /* 0x08-0x0B */ - 0xD6, 0x76, 0xB2, 0x7C, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0x7E, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0xA1, 0xB5, 0x60, /* 0x18-0x1B */ - 0x00, 0x00, 0xDA, 0xA7, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xDA, 0xA9, 0xDA, 0xA2, 0xB5, 0x5A, 0xDA, 0xA6, /* 0x20-0x23 */ - 0xDA, 0xA5, 0xB5, 0x5B, 0xB5, 0x61, 0x00, 0x00, /* 0x24-0x27 */ - 0xB5, 0x62, 0xDA, 0xA8, 0xB5, 0x58, 0xDA, 0x7D, /* 0x28-0x2B */ - 0xDA, 0x7B, 0xDA, 0xA3, 0xDA, 0x7A, 0xB5, 0x5F, /* 0x2C-0x2F */ - 0xDA, 0x7C, 0xDA, 0xA4, 0xDA, 0xAA, 0xB5, 0x59, /* 0x30-0x33 */ - 0xB5, 0x5E, 0xB5, 0x5C, 0xB5, 0x5D, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xB5, 0x57, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB7, 0xE9, /* 0x3C-0x3F */ - 0xDE, 0xB7, 0xB7, 0xE8, 0xDE, 0xBB, 0x00, 0x00, /* 0x40-0x43 */ - 0xDE, 0xB1, 0x00, 0x00, 0xDE, 0xBC, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xDE, 0xB2, 0xDE, 0xB3, /* 0x48-0x4B */ - 0x00, 0x00, 0xDE, 0xBD, 0xDE, 0xBA, 0xDE, 0xB8, /* 0x4C-0x4F */ - 0xDE, 0xB9, 0xDE, 0xB5, 0xDE, 0xB4, 0x00, 0x00, /* 0x50-0x53 */ - 0xDE, 0xBE, 0xB7, 0xE5, 0x00, 0x00, 0xDE, 0xB6, /* 0x54-0x57 */ - 0x00, 0x00, 0xB7, 0xEA, 0xB7, 0xE4, 0xB7, 0xEB, /* 0x58-0x5B */ - 0xB7, 0xEC, 0x00, 0x00, 0xB7, 0xE7, 0xB7, 0xE6, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0xCE, 0xBA, 0xBE, /* 0x60-0x63 */ - 0xBA, 0xBD, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xD3, /* 0x64-0x67 */ - 0x00, 0x00, 0xBC, 0xFC, 0xBA, 0xBF, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0xBA, 0xC1, 0xE2, 0xD4, 0xB7, 0xE3, /* 0x6C-0x6F */ - 0xBA, 0xC0, 0xE2, 0xD0, 0xE2, 0xD2, 0xE2, 0xCF, /* 0x70-0x73 */ - 0x00, 0x00, 0xE2, 0xD1, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xE6, 0xAB, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xE6, 0xAA, 0xE6, 0xA7, 0xBD, 0x40, 0xEA, 0x62, /* 0x7C-0x7F */ - - 0xBD, 0x41, 0xE6, 0xA6, 0x00, 0x00, 0xBC, 0xFE, /* 0x80-0x83 */ - 0x00, 0x00, 0xE6, 0xA8, 0xE6, 0xA5, 0xE6, 0xA2, /* 0x84-0x87 */ - 0xE6, 0xA9, 0xE6, 0xA3, 0xE6, 0xA4, 0xBC, 0xFD, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xED, 0x69, 0x00, 0x00, 0xEA, 0x66, 0x00, 0x00, /* 0x90-0x93 */ - 0xEA, 0x65, 0xEA, 0x67, 0x00, 0x00, 0xED, 0x66, /* 0x94-0x97 */ - 0xBF, 0x5A, 0x00, 0x00, 0xEA, 0x63, 0x00, 0x00, /* 0x98-0x9B */ - 0xBF, 0x58, 0x00, 0x00, 0xBF, 0x5C, 0xBF, 0x5B, /* 0x9C-0x9F */ - 0xEA, 0x64, 0xEA, 0x68, 0x00, 0x00, 0xBF, 0x59, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xED, 0x6D, 0xC0, 0xF5, 0xC2, 0x7A, /* 0xA4-0xA7 */ - 0xC0, 0xF6, 0xC0, 0xF3, 0xED, 0x6A, 0xED, 0x68, /* 0xA8-0xAB */ - 0x00, 0x00, 0xED, 0x6B, 0x00, 0x00, 0xED, 0x6E, /* 0xAC-0xAF */ - 0xC0, 0xF4, 0xED, 0x6C, 0xED, 0x67, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xF0, 0x42, 0xF0, 0x45, 0xF2, 0x75, /* 0xB4-0xB7 */ - 0xF0, 0x40, 0x00, 0x00, 0xF4, 0x6F, 0xF0, 0x46, /* 0xB8-0xBB */ - 0x00, 0x00, 0xC3, 0xA2, 0xF0, 0x44, 0xC2, 0x7B, /* 0xBC-0xBF */ - 0xF0, 0x41, 0xF0, 0x43, 0xF0, 0x47, 0xF2, 0x76, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xF2, 0x74, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xC3, 0xA3, 0xF2, 0x73, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC4, 0x6E, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xC4, 0xED, 0xF6, 0xF1, 0xC4, 0xEC, 0xF6, 0xF3, /* 0xD4-0xD7 */ - 0xF6, 0xF0, 0xF6, 0xF2, 0xC5, 0xD0, 0xF8, 0xB2, /* 0xD8-0xDB */ - 0xA5, 0xCA, 0xCD, 0x6E, 0xD2, 0xBC, 0xD2, 0xBD, /* 0xDC-0xDF */ - 0xB2, 0x7D, 0xDE, 0xBF, 0xBF, 0x5D, 0xC3, 0xA4, /* 0xE0-0xE3 */ - 0xC5, 0x7B, 0xF8, 0xB3, 0xA5, 0xCB, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xCD, 0x6F, 0xA2, 0x60, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xCF, 0xD7, 0x00, 0x00, 0xCF, 0xD8, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xD2, 0xBE, 0xD2, 0xBF, 0xB2, 0x7E, 0xB2, 0xA1, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xAB, /* 0xF8-0xFB */ - 0x00, 0x00, 0xDE, 0xC2, 0xDE, 0xC1, 0xDE, 0xC0, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_75[512] = { - 0xE2, 0xD5, 0x00, 0x00, 0xE2, 0xD6, 0xE2, 0xD7, /* 0x00-0x03 */ - 0xBA, 0xC2, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xAD, /* 0x04-0x07 */ - 0xE6, 0xAC, 0x00, 0x00, 0x00, 0x00, 0xEA, 0x69, /* 0x08-0x0B */ - 0xBF, 0x5E, 0xBF, 0x5F, 0x00, 0x00, 0xED, 0x72, /* 0x0C-0x0F */ - 0xED, 0x6F, 0xED, 0x70, 0xED, 0x71, 0xF0, 0x49, /* 0x10-0x13 */ - 0xF0, 0x48, 0xC2, 0x7C, 0xF2, 0x77, 0xF5, 0xDE, /* 0x14-0x17 */ - 0xA5, 0xCC, 0x00, 0x00, 0xAC, 0xC6, 0x00, 0x00, /* 0x18-0x1B */ - 0xB2, 0xA2, 0xDE, 0xC3, 0x00, 0x00, 0xA5, 0xCD, /* 0x1C-0x1F */ - 0x00, 0x00, 0xD2, 0xC0, 0xB2, 0xA3, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xB5, 0x63, 0xB5, 0x64, 0x00, 0x00, /* 0x24-0x27 */ - 0xA5, 0xCE, 0xA5, 0xCF, 0xCA, 0x46, 0xA8, 0x6A, /* 0x28-0x2B */ - 0xA8, 0x69, 0xAC, 0xC7, 0xCF, 0xD9, 0xDA, 0xAC, /* 0x2C-0x2F */ - 0xA5, 0xD0, 0xA5, 0xD1, 0xA5, 0xD2, 0xA5, 0xD3, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x6B, /* 0x34-0x37 */ - 0xA8, 0x6C, 0xCB, 0x6E, 0xCB, 0x6D, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xAA, 0xB6, 0xCD, 0x72, 0xCD, 0x70, /* 0x3C-0x3F */ - 0xCD, 0x71, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCF, 0xDA, /* 0x44-0x47 */ - 0xCF, 0xDB, 0x00, 0x00, 0x00, 0x00, 0xAC, 0xCB, /* 0x48-0x4B */ - 0xAC, 0xC9, 0x00, 0x00, 0xAC, 0xCA, 0xAC, 0xC8, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xAF, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xAF, 0x64, 0xAF, 0x63, 0xD2, 0xC1, /* 0x58-0x5B */ - 0xAF, 0x62, 0xAF, 0x61, 0x00, 0x00, 0xD2, 0xC2, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0xB2, 0xA6, 0xD6, 0x7B, /* 0x60-0x63 */ - 0xD6, 0x7A, 0xB2, 0xA4, 0xB2, 0xA5, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xB5, 0x66, 0xB5, 0x65, /* 0x68-0x6B */ - 0xDA, 0xAE, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xAD, /* 0x6C-0x6F */ - 0xB2, 0xA7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0xB7, 0xED, 0xDE, 0xC5, /* 0x74-0x77 */ - 0xB7, 0xEE, 0xDE, 0xC4, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xE2, 0xD8, 0xE6, 0xAE, 0xBD, 0x42, /* 0x7C-0x7F */ - - 0xEA, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xED, 0x73, 0x00, 0x00, 0xC3, 0xA6, 0xC3, 0xA5, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xC5, 0x7C, 0xA5, 0xD4, /* 0x88-0x8B */ - 0xCD, 0x73, 0x00, 0x00, 0x00, 0x00, 0xB2, 0xA8, /* 0x8C-0x8F */ - 0xE2, 0xD9, 0xBA, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xCB, 0x6F, 0xCB, 0x70, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xCD, 0x74, 0xAA, 0xB8, 0xAA, 0xB9, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xAA, 0xB7, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0xAC, 0xCF, 0xAC, 0xD0, /* 0xA0-0xA3 */ - 0xAC, 0xCD, 0xAC, 0xCE, 0x00, 0x00, 0xCF, 0xDC, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0xCF, 0xDD, 0xAC, 0xCC, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0xD2, 0xC3, 0x00, 0x00, 0xAF, 0x68, 0xAF, 0x69, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xB2, 0xAB, 0xD2, 0xC9, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xAF, 0x6E, 0xAF, 0x6C, 0xD2, 0xCA, 0xD2, 0xC5, /* 0xB8-0xBB */ - 0xAF, 0x6B, 0xAF, 0x6A, 0xAF, 0x65, 0xD2, 0xC8, /* 0xBC-0xBF */ - 0xD2, 0xC7, 0xD2, 0xC4, 0xAF, 0x6D, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xD2, 0xC6, 0xAF, 0x66, 0x00, 0x00, 0xAF, 0x67, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xB2, 0xAC, 0xD6, 0xA1, /* 0xC8-0xCB */ - 0xD6, 0xA2, 0xB2, 0xAD, 0xD6, 0x7C, 0xD6, 0x7E, /* 0xCC-0xCF */ - 0xD6, 0xA4, 0xD6, 0xA3, 0xD6, 0x7D, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xB2, 0xA9, 0xB2, 0xAA, 0x00, 0x00, 0xDA, 0xB6, /* 0xD4-0xD7 */ - 0xB5, 0x6B, 0xB5, 0x6A, 0xDA, 0xB0, 0xB5, 0x68, /* 0xD8-0xDB */ - 0x00, 0x00, 0xDA, 0xB3, 0xB5, 0x6C, 0xDA, 0xB4, /* 0xDC-0xDF */ - 0xB5, 0x6D, 0xDA, 0xB1, 0xB5, 0x67, 0xB5, 0x69, /* 0xE0-0xE3 */ - 0xDA, 0xB5, 0x00, 0x00, 0xDA, 0xB2, 0xDA, 0xAF, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xDE, 0xD2, 0x00, 0x00, 0xDE, 0xC7, /* 0xEC-0xEF */ - 0xB7, 0xF0, 0xB7, 0xF3, 0xB7, 0xF2, 0xB7, 0xF7, /* 0xF0-0xF3 */ - 0xB7, 0xF6, 0xDE, 0xD3, 0xDE, 0xD1, 0xDE, 0xCA, /* 0xF4-0xF7 */ - 0xDE, 0xCE, 0xDE, 0xCD, 0xB7, 0xF4, 0xDE, 0xD0, /* 0xF8-0xFB */ - 0xDE, 0xCC, 0xDE, 0xD4, 0xDE, 0xCB, 0xB7, 0xF5, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_76[512] = { - 0xB7, 0xEF, 0xB7, 0xF1, 0x00, 0x00, 0xDE, 0xC9, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xE2, 0xDB, 0xBA, 0xC7, 0xE2, 0xDF, 0xBA, 0xC6, /* 0x08-0x0B */ - 0xE2, 0xDC, 0xBA, 0xC5, 0x00, 0x00, 0xDE, 0xC8, /* 0x0C-0x0F */ - 0xDE, 0xCF, 0xE2, 0xDE, 0x00, 0x00, 0xBA, 0xC8, /* 0x10-0x13 */ - 0xE2, 0xE0, 0xE2, 0xDD, 0xE2, 0xDA, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xE6, 0xB1, 0xE6, 0xB5, 0xE6, 0xB7, /* 0x18-0x1B */ - 0xE6, 0xB3, 0xE6, 0xB2, 0xE6, 0xB0, 0xBD, 0x45, /* 0x1C-0x1F */ - 0xBD, 0x43, 0xBD, 0x48, 0xBD, 0x49, 0xE6, 0xB4, /* 0x20-0x23 */ - 0xBD, 0x46, 0xE6, 0xAF, 0xBD, 0x47, 0xBA, 0xC4, /* 0x24-0x27 */ - 0xE6, 0xB6, 0xBD, 0x44, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0xEA, 0x6C, 0x00, 0x00, 0xEA, 0x6B, /* 0x2C-0x2F */ - 0xEA, 0x73, 0xEA, 0x6D, 0xEA, 0x72, 0xEA, 0x6F, /* 0x30-0x33 */ - 0xBF, 0x60, 0xEA, 0x71, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xBF, 0x61, 0x00, 0x00, 0xBF, 0x62, 0x00, 0x00, /* 0x38-0x3B */ - 0xEA, 0x70, 0xEA, 0x6E, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0xC0, 0xF8, 0xED, 0x74, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xC0, 0xF7, 0xED, 0x77, /* 0x44-0x47 */ - 0xED, 0x75, 0xED, 0x76, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xC0, 0xF9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xF0, 0x4D, 0x00, 0x00, 0xC2, 0xA1, 0xF0, 0x4E, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xC2, 0x7D, 0xF0, 0x4F, /* 0x54-0x57 */ - 0xC2, 0x7E, 0xF0, 0x4C, 0xF0, 0x50, 0x00, 0x00, /* 0x58-0x5B */ - 0xF0, 0x4A, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xA7, /* 0x5C-0x5F */ - 0xF2, 0x78, 0xC3, 0xA8, 0xC4, 0x6F, 0x00, 0x00, /* 0x60-0x63 */ - 0xF0, 0x4B, 0xC4, 0x70, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xC4, 0xEE, 0xF5, 0xDF, 0x00, 0x00, /* 0x68-0x6B */ - 0xC5, 0x7E, 0xF6, 0xF4, 0xC5, 0x7D, 0x00, 0x00, /* 0x6C-0x6F */ - 0xF7, 0xEA, 0xC5, 0xF5, 0xC5, 0xF6, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xF9, 0xCC, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0xAC, 0xD1, 0xCF, 0xDE, 0x00, 0x00, 0xB5, 0x6E, /* 0x78-0x7B */ - 0xB5, 0x6F, 0xA5, 0xD5, 0xA6, 0xCA, 0xCA, 0x47, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xCB, 0x71, 0xA8, 0x6D, 0x00, 0x00, /* 0x80-0x83 */ - 0xAA, 0xBA, 0x00, 0x00, 0xAC, 0xD2, 0xAC, 0xD3, /* 0x84-0x87 */ - 0xAC, 0xD4, 0xD6, 0xA6, 0xD2, 0xCB, 0xAF, 0x6F, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0xB2, 0xAE, 0xD6, 0xA5, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0xB8, 0xB5, 0x71, /* 0x90-0x93 */ - 0x00, 0x00, 0xDA, 0xB7, 0xB5, 0x70, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xDE, 0xD5, 0xBD, 0x4A, 0xE6, 0xBB, /* 0x98-0x9B */ - 0xE6, 0xB8, 0xE6, 0xB9, 0xE6, 0xBA, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xED, 0x78, 0x00, 0x00, 0xF0, 0x51, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0x71, 0xF4, 0x70, /* 0xA8-0xAB */ - 0x00, 0x00, 0xF6, 0xF5, 0xA5, 0xD6, 0xCD, 0x75, /* 0xAC-0xAF */ - 0xAF, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xB5, 0x72, 0xDE, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xE2, 0xE1, 0x00, 0x00, 0xBD, 0x4B, 0xEA, 0x74, /* 0xB8-0xBB */ - 0x00, 0x00, 0xF0, 0x52, 0xF4, 0x72, 0xA5, 0xD7, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xAA, 0xBB, 0xAC, 0xD7, /* 0xC0-0xC3 */ - 0xCF, 0xDF, 0xAC, 0xD8, 0xAC, 0xD6, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xAC, 0xD5, 0xD2, 0xCC, 0xAF, 0x71, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0xAF, 0x72, 0xAF, 0x73, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xB2, 0xB0, 0xD6, 0xA7, /* 0xD0-0xD3 */ - 0xB2, 0xAF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0xB9, 0xB2, 0xB1, /* 0xD8-0xDB */ - 0xB5, 0x73, 0xDE, 0xD7, 0xB7, 0xF8, 0xB7, 0xF9, /* 0xDC-0xDF */ - 0x00, 0x00, 0xBA, 0xC9, 0x00, 0x00, 0xBA, 0xCA, /* 0xE0-0xE3 */ - 0xBD, 0x4C, 0xBF, 0x64, 0xEA, 0x75, 0xBF, 0x63, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xED, 0x79, 0xC0, 0xFA, 0x00, 0x00, /* 0xE8-0xEB */ - 0xF0, 0x53, 0xF4, 0x73, 0xA5, 0xD8, 0xA8, 0x6E, /* 0xEC-0xEF */ - 0xCD, 0x78, 0xCD, 0x77, 0xAA, 0xBC, 0xCD, 0x76, /* 0xF0-0xF3 */ - 0xAA, 0xBD, 0xCD, 0x79, 0x00, 0x00, 0xCF, 0xE5, /* 0xF4-0xF7 */ - 0xAC, 0xDB, 0xAC, 0xDA, 0xCF, 0xE7, 0xCF, 0xE6, /* 0xF8-0xFB */ - 0xAC, 0xDF, 0x00, 0x00, 0xAC, 0xDE, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_77[512] = { - 0x00, 0x00, 0xAC, 0xD9, 0x00, 0x00, 0xCF, 0xE1, /* 0x00-0x03 */ - 0xCF, 0xE2, 0xCF, 0xE3, 0x00, 0x00, 0xAC, 0xE0, /* 0x04-0x07 */ - 0xCF, 0xE0, 0xAC, 0xDC, 0xCF, 0xE4, 0xAC, 0xDD, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xD2, 0xCF, 0xD2, 0xD3, 0xD2, 0xD1, 0xD2, 0xD0, /* 0x10-0x13 */ - 0x00, 0x00, 0xD2, 0xD4, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xD2, 0xD5, 0xD2, 0xD6, 0xD2, 0xCE, /* 0x18-0x1B */ - 0x00, 0x00, 0xD2, 0xCD, 0x00, 0x00, 0xAF, 0x75, /* 0x1C-0x1F */ - 0xAF, 0x76, 0x00, 0x00, 0xD2, 0xD7, 0xD2, 0xD2, /* 0x20-0x23 */ - 0x00, 0x00, 0xD6, 0xB0, 0x00, 0x00, 0xD2, 0xD8, /* 0x24-0x27 */ - 0xAF, 0x77, 0xAF, 0x74, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0xD6, 0xAA, 0x00, 0x00, 0xD6, 0xA9, /* 0x2C-0x2F */ - 0x00, 0x00, 0xD6, 0xAB, 0xD6, 0xAC, 0xD6, 0xAE, /* 0x30-0x33 */ - 0xD6, 0xAD, 0xD6, 0xB2, 0xB2, 0xB5, 0xB2, 0xB2, /* 0x34-0x37 */ - 0xB2, 0xB6, 0xD6, 0xA8, 0xB2, 0xB7, 0xD6, 0xB1, /* 0x38-0x3B */ - 0xB2, 0xB4, 0xD6, 0xAF, 0xB2, 0xB3, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xDA, 0xBC, 0xDA, 0xBE, 0xDA, 0xBA, 0xDA, 0xBB, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0xBF, 0xDA, 0xC1, /* 0x48-0x4B */ - 0xDA, 0xC2, 0xDA, 0xBD, 0xDA, 0xC0, 0xB5, 0x74, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xDE, 0xDB, 0x00, 0x00, /* 0x50-0x53 */ - 0xDE, 0xE0, 0xDE, 0xD8, 0xDE, 0xDC, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xDE, 0xE1, 0xDE, 0xDD, 0xB7, 0xFA, /* 0x58-0x5B */ - 0xB8, 0x43, 0x00, 0x00, 0xB7, 0xFD, 0xDE, 0xD9, /* 0x5C-0x5F */ - 0xDE, 0xDA, 0xBA, 0xCE, 0xB8, 0x46, 0xB7, 0xFE, /* 0x60-0x63 */ - 0x00, 0x00, 0xB8, 0x44, 0xB7, 0xFC, 0xDE, 0xDF, /* 0x64-0x67 */ - 0xB8, 0x45, 0xDE, 0xDE, 0xB8, 0x41, 0xB7, 0xFB, /* 0x68-0x6B */ - 0xB8, 0x42, 0xDE, 0xE2, 0xE2, 0xE6, 0xE2, 0xE8, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xB8, 0x40, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xE2, 0xE3, 0xBA, 0xCC, 0xE2, 0xE9, 0xBA, 0xCD, /* 0x7C-0x7F */ - - 0xE2, 0xE7, 0xE2, 0xE2, 0xE2, 0xE5, 0xE2, 0xEA, /* 0x80-0x83 */ - 0xBA, 0xCB, 0xE2, 0xE4, 0x00, 0x00, 0xBD, 0x4E, /* 0x84-0x87 */ - 0xE6, 0xBF, 0xE6, 0xBE, 0x00, 0x00, 0xBD, 0x51, /* 0x88-0x8B */ - 0xBD, 0x4F, 0xE6, 0xBC, 0xBD, 0x4D, 0xE6, 0xBD, /* 0x8C-0x8F */ - 0x00, 0x00, 0xBD, 0x50, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0xEA, 0x7D, 0x00, 0x00, 0xEA, 0xA1, /* 0x94-0x97 */ - 0x00, 0x00, 0xEA, 0x7E, 0xEA, 0x76, 0xEA, 0x7A, /* 0x98-0x9B */ - 0xEA, 0x79, 0xEA, 0x77, 0xBF, 0x66, 0xBF, 0x67, /* 0x9C-0x9F */ - 0xBF, 0x65, 0xEA, 0x78, 0xEA, 0x7B, 0xEA, 0x7C, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xBF, 0x68, 0x00, 0x00, 0xC1, 0x40, /* 0xA4-0xA7 */ - 0xED, 0xA3, 0x00, 0x00, 0xC0, 0xFC, 0xED, 0x7B, /* 0xA8-0xAB */ - 0xC0, 0xFE, 0xC1, 0x41, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0xC0, 0xFD, 0xED, 0xA2, 0xED, 0x7C, 0xC0, 0xFB, /* 0xB0-0xB3 */ - 0xED, 0xA1, 0xED, 0x7A, 0xED, 0x7E, 0xED, 0x7D, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xF0, 0x55, 0xC2, 0xA4, /* 0xB8-0xBB */ - 0xC2, 0xA5, 0xC2, 0xA2, 0x00, 0x00, 0xC2, 0xA3, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xF0, 0x54, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xF2, 0x7B, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xA9, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xF2, 0x79, 0xF2, 0x7A, 0x00, 0x00, /* 0xC8-0xCB */ - 0xF4, 0x74, 0xF4, 0x77, 0xF4, 0x75, 0xF4, 0x76, /* 0xCC-0xCF */ - 0xF5, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xC4, 0xEF, /* 0xD0-0xD3 */ - 0xF7, 0xEB, 0xF8, 0xB4, 0x00, 0x00, 0xC5, 0xF7, /* 0xD4-0xD7 */ - 0xF8, 0xF8, 0xF8, 0xF9, 0xC6, 0x66, 0xA5, 0xD9, /* 0xD8-0xDB */ - 0xAC, 0xE1, 0x00, 0x00, 0xDA, 0xC3, 0x00, 0x00, /* 0xDC-0xDF */ - 0xDE, 0xE3, 0x00, 0x00, 0xA5, 0xDA, 0xA8, 0x6F, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xAA, 0xBE, 0x00, 0x00, 0xCF, 0xE8, /* 0xE4-0xE7 */ - 0xCF, 0xE9, 0xAF, 0x78, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xDA, 0xC4, 0xB5, 0x75, 0xB8, 0x47, 0xC1, 0x42, /* 0xEC-0xEF */ - 0xED, 0xA4, 0xF2, 0x7C, 0xF4, 0x78, 0xA5, 0xDB, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xA1, /* 0xF4-0xF7 */ - 0xCD, 0x7A, 0xCD, 0x7C, 0xCD, 0x7E, 0xCD, 0x7D, /* 0xF8-0xFB */ - 0xCD, 0x7B, 0xAA, 0xBF, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_78[512] = { - 0x00, 0x00, 0x00, 0x00, 0xAC, 0xE2, 0xCF, 0xF2, /* 0x00-0x03 */ - 0x00, 0x00, 0xCF, 0xED, 0xCF, 0xEA, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xCF, 0xF1, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0xAC, 0xE4, 0xAC, 0xE5, 0xCF, 0xF0, 0xCF, 0xEF, /* 0x0C-0x0F */ - 0xCF, 0xEE, 0xCF, 0xEB, 0xCF, 0xEC, 0xCF, 0xF3, /* 0x10-0x13 */ - 0xAC, 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0xAF, 0x7C, 0x00, 0x00, 0xAF, 0xA4, /* 0x1C-0x1F */ - 0xAF, 0xA3, 0xD2, 0xE1, 0xD2, 0xDB, 0xD2, 0xD9, /* 0x20-0x23 */ - 0x00, 0x00, 0xAF, 0xA1, 0xD6, 0xB9, 0xAF, 0x7A, /* 0x24-0x27 */ - 0xD2, 0xDE, 0xD2, 0xE2, 0xD2, 0xE4, 0xD2, 0xE0, /* 0x28-0x2B */ - 0xD2, 0xDA, 0xAF, 0xA2, 0xD2, 0xDF, 0xD2, 0xDD, /* 0x2C-0x2F */ - 0xAF, 0x79, 0xD2, 0xE5, 0xAF, 0xA5, 0xD2, 0xE3, /* 0x30-0x33 */ - 0xAF, 0x7D, 0xD2, 0xDC, 0x00, 0x00, 0xAF, 0x7E, /* 0x34-0x37 */ - 0xAF, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB2, 0xB9, /* 0x40-0x43 */ - 0x00, 0x00, 0xD6, 0xBA, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0xD6, 0xB3, 0xD6, 0xB5, 0xD6, 0xB7, 0x00, 0x00, /* 0x48-0x4B */ - 0xD6, 0xB8, 0xD6, 0xB6, 0xB2, 0xBA, 0x00, 0x00, /* 0x4C-0x4F */ - 0xD6, 0xBB, 0x00, 0x00, 0xD6, 0xB4, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0xDA, 0xC8, 0xB5, 0x76, 0xDA, 0xD0, 0x00, 0x00, /* 0x5C-0x5F */ - 0xDA, 0xC5, 0x00, 0x00, 0xDA, 0xD1, 0x00, 0x00, /* 0x60-0x63 */ - 0xDA, 0xC6, 0xDA, 0xC7, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xDA, 0xCF, 0xDA, 0xCE, 0xDA, 0xCB, 0xB2, 0xB8, /* 0x68-0x6B */ - 0xB5, 0x77, 0xDA, 0xC9, 0xDA, 0xCC, 0xB5, 0x78, /* 0x6C-0x6F */ - 0xDA, 0xCD, 0xDA, 0xCA, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xDE, 0xEE, 0x00, 0x00, 0xDE, 0xF2, /* 0x78-0x7B */ - 0xB8, 0x4E, 0x00, 0x00, 0xE2, 0xF0, 0xB8, 0x51, /* 0x7C-0x7F */ - - 0xDE, 0xF0, 0xF9, 0xD6, 0x00, 0x00, 0xDE, 0xED, /* 0x80-0x83 */ - 0xDE, 0xE8, 0xDE, 0xEA, 0xDE, 0xEB, 0xDE, 0xE4, /* 0x84-0x87 */ - 0x00, 0x00, 0xB8, 0x4D, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0xB8, 0x4C, 0x00, 0x00, 0xB8, 0x48, 0xDE, 0xE7, /* 0x8C-0x8F */ - 0x00, 0x00, 0xB8, 0x4F, 0x00, 0x00, 0xB8, 0x50, /* 0x90-0x93 */ - 0xDE, 0xE6, 0xDE, 0xE9, 0xDE, 0xF1, 0xB8, 0x4A, /* 0x94-0x97 */ - 0xB8, 0x4B, 0xDE, 0xEF, 0xDE, 0xE5, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xE2, 0xF2, 0xBA, 0xD0, /* 0x9C-0x9F */ - 0xE2, 0xF4, 0xDE, 0xEC, 0xE2, 0xF6, 0xBA, 0xD4, /* 0xA0-0xA3 */ - 0xE2, 0xF7, 0xE2, 0xF3, 0x00, 0x00, 0xBA, 0xD1, /* 0xA4-0xA7 */ - 0xE2, 0xEF, 0xBA, 0xD3, 0xE2, 0xEC, 0xE2, 0xF1, /* 0xA8-0xAB */ - 0xE2, 0xF5, 0xE2, 0xEE, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0xB8, 0x49, 0x00, 0x00, 0xE2, 0xEB, 0xBA, 0xD2, /* 0xB0-0xB3 */ - 0xE2, 0xED, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xBD, 0x54, 0xE6, 0xC1, /* 0xB8-0xBB */ - 0xBD, 0x58, 0x00, 0x00, 0xBD, 0x56, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xBA, 0xCF, 0x00, 0x00, 0xE6, 0xC8, /* 0xC0-0xC3 */ - 0xE6, 0xC9, 0xBD, 0x53, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xE6, 0xC7, 0xE6, 0xCA, 0xBD, 0x55, 0xBD, 0x52, /* 0xC8-0xCB */ - 0xE6, 0xC3, 0xE6, 0xC0, 0xE6, 0xC5, 0xE6, 0xC2, /* 0xCC-0xCF */ - 0xBD, 0x59, 0xE6, 0xC4, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xE6, 0xC6, 0xBD, 0x57, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xBF, 0x6A, 0xEA, 0xA8, /* 0xD8-0xDB */ - 0x00, 0x00, 0xEA, 0xA2, 0xEA, 0xA6, 0xEA, 0xAC, /* 0xDC-0xDF */ - 0xEA, 0xAD, 0xEA, 0xA9, 0xEA, 0xAA, 0xEA, 0xA7, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xEA, 0xA4, 0x00, 0x00, 0xBF, 0x6C, /* 0xE4-0xE7 */ - 0xBF, 0x69, 0xEA, 0xA3, 0xEA, 0xA5, 0x00, 0x00, /* 0xE8-0xEB */ - 0xBF, 0x6B, 0xEA, 0xAB, 0x00, 0x00, 0xC1, 0x46, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0xAA, 0xED, 0xA5, /* 0xF0-0xF3 */ - 0xC1, 0x45, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x43, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xED, 0xAC, 0xC1, 0x44, 0xED, 0xA8, /* 0xF8-0xFB */ - 0xED, 0xA9, 0xED, 0xA6, 0xED, 0xAD, 0xF0, 0x56, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_79[512] = { - 0x00, 0x00, 0xC1, 0x47, 0xED, 0xA7, 0x00, 0x00, /* 0x00-0x03 */ - 0xED, 0xAE, 0xED, 0xAB, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0xF0, 0x5A, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0xF0, 0x57, 0x00, 0x00, 0xC2, 0xA6, 0x00, 0x00, /* 0x0C-0x0F */ - 0xF0, 0x5B, 0xF0, 0x5D, 0xF0, 0x5C, 0xF0, 0x58, /* 0x10-0x13 */ - 0xF0, 0x59, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xA3, /* 0x14-0x17 */ - 0x00, 0x00, 0xC3, 0xAA, 0x00, 0x00, 0xF2, 0x7E, /* 0x18-0x1B */ - 0xF2, 0xA2, 0xF2, 0x7D, 0xF2, 0xA4, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xF2, 0xA1, 0x00, 0x00, 0xF4, 0x7A, /* 0x20-0x23 */ - 0xF4, 0x7D, 0xF4, 0x79, 0xC4, 0x71, 0xF4, 0x7B, /* 0x24-0x27 */ - 0xF4, 0x7C, 0xF4, 0x7E, 0xC4, 0x72, 0xC4, 0x74, /* 0x28-0x2B */ - 0xC4, 0x73, 0xF5, 0xE1, 0x00, 0x00, 0xF5, 0xE3, /* 0x2C-0x2F */ - 0x00, 0x00, 0xF5, 0xE2, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0xF6, 0xF6, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xF8, 0xB5, 0xF8, 0xFA, 0xA5, 0xDC, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xCB, 0x72, 0xAA, 0xC0, 0xCD, 0xA3, /* 0x3C-0x3F */ - 0xAA, 0xC1, 0xAA, 0xC2, 0xCD, 0xA2, 0x00, 0x00, /* 0x40-0x43 */ - 0xCF, 0xF8, 0xCF, 0xF7, 0xAC, 0xE6, 0xAC, 0xE9, /* 0x44-0x47 */ - 0xAC, 0xE8, 0xAC, 0xE7, 0xCF, 0xF4, 0xCF, 0xF6, /* 0x48-0x4B */ - 0xCF, 0xF5, 0x00, 0x00, 0x00, 0x00, 0xD2, 0xE8, /* 0x4C-0x4F */ - 0xAF, 0xA7, 0xD2, 0xEC, 0xD2, 0xEB, 0xD2, 0xEA, /* 0x50-0x53 */ - 0xD2, 0xE6, 0xAF, 0xA6, 0xAF, 0xAA, 0xAF, 0xAD, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xAF, 0xAE, 0xD2, 0xE7, /* 0x58-0x5B */ - 0xD2, 0xE9, 0xAF, 0xAC, 0xAF, 0xAB, 0xAF, 0xA9, /* 0x5C-0x5F */ - 0xAF, 0xA8, 0xD6, 0xC2, 0x00, 0x00, 0xD6, 0xC0, /* 0x60-0x63 */ - 0xD6, 0xBC, 0xB2, 0xBB, 0x00, 0x00, 0xD6, 0xBD, /* 0x64-0x67 */ - 0xB2, 0xBC, 0xD6, 0xBE, 0xD6, 0xBF, 0xD6, 0xC1, /* 0x68-0x6B */ - 0x00, 0x00, 0xB2, 0xBD, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xDA, 0xD5, 0x00, 0x00, 0xDA, 0xD4, 0xDA, 0xD3, /* 0x70-0x73 */ - 0xDA, 0xD2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xDE, 0xF6, 0xB8, 0x52, 0x00, 0x00, /* 0x78-0x7B */ - 0xDE, 0xF3, 0xDE, 0xF5, 0x00, 0x00, 0xB8, 0x53, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xB8, 0x54, 0xDE, 0xF4, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xE3, 0x41, 0x00, 0x00, 0xE2, 0xF9, 0xE2, 0xFA, /* 0x88-0x8B */ - 0x00, 0x00, 0xBA, 0xD7, 0xBA, 0xD5, 0xBA, 0xD6, /* 0x8C-0x8F */ - 0xE3, 0x43, 0x00, 0x00, 0xE3, 0x42, 0xE2, 0xFE, /* 0x90-0x93 */ - 0xE2, 0xFD, 0xE2, 0xFC, 0xE2, 0xFB, 0xE3, 0x40, /* 0x94-0x97 */ - 0xE2, 0xF8, 0x00, 0x00, 0xE6, 0xCB, 0xE6, 0xD0, /* 0x98-0x9B */ - 0xE6, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xE6, 0xCD, 0xE6, 0xCC, 0xE6, 0xCF, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xEA, 0xAE, 0x00, 0x00, 0xBF, 0x6D, 0xC1, 0x48, /* 0xA4-0xA7 */ - 0xED, 0xB0, 0x00, 0x00, 0xC1, 0x49, 0xED, 0xAF, /* 0xA8-0xAB */ - 0xF0, 0x5F, 0xF0, 0x5E, 0xC2, 0xA7, 0x00, 0x00, /* 0xAC-0xAF */ - 0xF2, 0xA5, 0xC3, 0xAB, 0xF4, 0xA1, 0xC5, 0xA1, /* 0xB0-0xB3 */ - 0xF6, 0xF7, 0x00, 0x00, 0xF8, 0xB7, 0xF8, 0xB6, /* 0xB4-0xB7 */ - 0xC9, 0xA8, 0xAC, 0xEA, 0xAC, 0xEB, 0xD6, 0xC3, /* 0xB8-0xBB */ - 0x00, 0x00, 0xB8, 0x56, 0xA5, 0xDD, 0xA8, 0x72, /* 0xBC-0xBF */ - 0xA8, 0x71, 0xA8, 0x70, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xCD, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xAA, 0xC4, 0xAA, 0xC3, 0x00, 0x00, 0xAC, 0xEE, /* 0xC8-0xCB */ - 0x00, 0x00, 0xCF, 0xFA, 0xCF, 0xFD, 0xCF, 0xFB, /* 0xCC-0xCF */ - 0x00, 0x00, 0xAC, 0xEC, 0xAC, 0xED, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xCF, 0xF9, 0xCF, 0xFC, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xAF, 0xB5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xD2, 0xF3, 0xD2, 0xF5, 0xD2, 0xF4, 0xAF, 0xB2, /* 0xDC-0xDF */ - 0xD2, 0xEF, 0x00, 0x00, 0x00, 0x00, 0xAF, 0xB0, /* 0xE0-0xE3 */ - 0xAF, 0xAF, 0x00, 0x00, 0xAF, 0xB3, 0xAF, 0xB1, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xAF, 0xB4, 0xD2, 0xF2, 0xD2, 0xED, /* 0xE8-0xEB */ - 0xD2, 0xEE, 0xD2, 0xF1, 0xD2, 0xF0, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xC6, 0xD6, 0xC7, /* 0xF4-0xF7 */ - 0xD6, 0xC5, 0x00, 0x00, 0xD6, 0xC4, 0xB2, 0xBE, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_7A[512] = { - 0xB5, 0x7D, 0x00, 0x00, 0xDA, 0xD6, 0xDA, 0xD8, /* 0x00-0x03 */ - 0xDA, 0xDA, 0xB5, 0x7C, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xB5, 0x7A, 0x00, 0x00, 0xDA, 0xD7, 0xB5, 0x7B, /* 0x08-0x0B */ - 0xDA, 0xD9, 0xB5, 0x79, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xDF, 0x41, 0xDE, 0xF7, 0xDE, 0xFA, 0xDE, 0xFE, /* 0x10-0x13 */ - 0xB8, 0x5A, 0xDE, 0xFC, 0x00, 0x00, 0xDE, 0xFB, /* 0x14-0x17 */ - 0xDE, 0xF8, 0xDE, 0xF9, 0xB8, 0x58, 0xDF, 0x40, /* 0x18-0x1B */ - 0xB8, 0x57, 0x00, 0x00, 0xB8, 0x5C, 0xB8, 0x5B, /* 0x1C-0x1F */ - 0xB8, 0x59, 0x00, 0x00, 0xDE, 0xFD, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0x49, 0x00, 0x00, /* 0x24-0x27 */ - 0xE3, 0x48, 0x00, 0x00, 0x00, 0x00, 0xE3, 0x44, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0xBA, 0xD8, 0xE3, 0x47, /* 0x2C-0x2F */ - 0xE3, 0x46, 0xBA, 0xD9, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBD, 0x5E, /* 0x34-0x37 */ - 0x00, 0x00, 0xE6, 0xD2, 0x00, 0x00, 0xBD, 0x5F, /* 0x38-0x3B */ - 0xBD, 0x5B, 0xBD, 0x5D, 0x00, 0x00, 0xBD, 0x5A, /* 0x3C-0x3F */ - 0xBD, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xEA, 0xAF, 0x00, 0x00, 0xBF, 0x70, 0xEA, 0xB1, /* 0x44-0x47 */ - 0xEA, 0xB0, 0x00, 0x00, 0xE3, 0x45, 0xBF, 0x72, /* 0x48-0x4B */ - 0xBF, 0x71, 0xBF, 0x6E, 0xBF, 0x6F, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xED, 0xB5, 0x00, 0x00, 0xED, 0xB3, 0xC1, 0x4A, /* 0x54-0x57 */ - 0xED, 0xB4, 0x00, 0x00, 0xED, 0xB6, 0xED, 0xB2, /* 0x58-0x5B */ - 0xED, 0xB1, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, /* 0x5C-0x5F */ - 0xC2, 0xAA, 0xC2, 0xA8, 0xC2, 0xA9, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xA6, /* 0x64-0x67 */ - 0xF2, 0xA7, 0xC3, 0xAD, 0x00, 0x00, 0xC3, 0xAC, /* 0x68-0x6B */ - 0xF4, 0xA3, 0xF4, 0xA4, 0xF4, 0xA2, 0x00, 0x00, /* 0x6C-0x6F */ - 0xF6, 0xF8, 0xF6, 0xF9, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xA5, 0xDE, 0xCA, 0x48, 0xA8, 0x73, 0x00, 0x00, /* 0x74-0x77 */ - 0xCD, 0xA5, 0xAA, 0xC6, 0xAA, 0xC5, 0xCD, 0xA6, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0x40, 0xAC, 0xEF, /* 0x7C-0x7F */ - - 0xCF, 0xFE, 0xAC, 0xF0, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xAF, 0xB6, 0xD2, 0xF8, 0xD2, 0xF6, 0xD2, 0xFC, /* 0x84-0x87 */ - 0xAF, 0xB7, 0xD2, 0xF7, 0xD2, 0xFB, 0xD2, 0xF9, /* 0x88-0x8B */ - 0xD2, 0xFA, 0x00, 0x00, 0x00, 0x00, 0xD6, 0xC8, /* 0x8C-0x8F */ - 0xD6, 0xCA, 0x00, 0x00, 0xB2, 0xBF, 0x00, 0x00, /* 0x90-0x93 */ - 0xD6, 0xC9, 0xB2, 0xC0, 0xB5, 0xA2, 0xB5, 0xA1, /* 0x94-0x97 */ - 0xB5, 0x7E, 0xDA, 0xDB, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xDF, 0x44, 0xB8, 0x5D, /* 0x9C-0x9F */ - 0xB8, 0x5E, 0x00, 0x00, 0xDF, 0x43, 0xDF, 0x42, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xE3, 0x4A, 0xBA, 0xDB, 0xBA, 0xDA, 0xE3, 0x4B, /* 0xA8-0xAB */ - 0xE3, 0x4C, 0x00, 0x00, 0xBD, 0x61, 0xBD, 0x60, /* 0xAC-0xAF */ - 0x00, 0x00, 0xEA, 0xB5, 0xE6, 0xD3, 0xE6, 0xD5, /* 0xB0-0xB3 */ - 0xE6, 0xD4, 0xEA, 0xB4, 0xEA, 0xB2, 0xEA, 0xB6, /* 0xB4-0xB7 */ - 0xEA, 0xB3, 0x00, 0x00, 0xBF, 0x73, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xED, 0xB7, 0xC1, 0x4B, /* 0xBC-0xBF */ - 0xED, 0xB8, 0xED, 0xB9, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xC2, 0xAB, 0xC2, 0xAC, 0x00, 0x00, 0xC4, 0x75, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xC5, 0xD1, 0xA5, 0xDF, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xD0, 0x41, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xD2, 0xFD, 0xAF, 0xB8, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB3, 0xBA, /* 0xDC-0xDF */ - 0xB3, 0xB9, 0x00, 0x00, 0x00, 0x00, 0xB5, 0xA4, /* 0xE0-0xE3 */ - 0xDA, 0xDD, 0xB5, 0xA3, 0xDA, 0xDC, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0x45, /* 0xE8-0xEB */ - 0x00, 0x00, 0xBA, 0xDC, 0xE3, 0x4D, 0xBA, 0xDD, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xC4, 0x76, 0xF4, 0xA5, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xA6, 0xCB, 0xAA, 0xC7, 0xCD, 0xA7, /* 0xF8-0xFB */ - 0x00, 0x00, 0xAC, 0xF2, 0x00, 0x00, 0xAC, 0xF1, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_7B[512] = { - 0xD0, 0x42, 0xD0, 0x43, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xD3, 0x40, 0xD3, 0x42, 0xAF, 0xB9, 0x00, 0x00, /* 0x04-0x07 */ - 0xD3, 0x44, 0xD3, 0x47, 0xD3, 0x45, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0x46, 0xD3, 0x43, /* 0x0C-0x0F */ - 0xD2, 0xFE, 0xAF, 0xBA, 0xD3, 0x48, 0xD3, 0x41, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xD6, 0xD3, 0xB2, 0xC6, 0xD6, 0xDC, 0xB2, 0xC3, /* 0x18-0x1B */ - 0x00, 0x00, 0xD6, 0xD5, 0xB2, 0xC7, 0x00, 0x00, /* 0x1C-0x1F */ - 0xB2, 0xC1, 0x00, 0x00, 0xD6, 0xD0, 0xD6, 0xDD, /* 0x20-0x23 */ - 0xD6, 0xD1, 0xD6, 0xCE, 0xB2, 0xC5, 0x00, 0x00, /* 0x24-0x27 */ - 0xB2, 0xC2, 0x00, 0x00, 0xD6, 0xD4, 0xD6, 0xD7, /* 0x28-0x2B */ - 0xB2, 0xC4, 0xD6, 0xD8, 0xB2, 0xC8, 0xD6, 0xD9, /* 0x2C-0x2F */ - 0xD6, 0xCF, 0xD6, 0xD6, 0xD6, 0xDA, 0xD6, 0xD2, /* 0x30-0x33 */ - 0xD6, 0xCD, 0xD6, 0xCB, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xD6, 0xDB, 0x00, 0x00, 0x00, 0x00, 0xDA, 0xDF, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0xDA, 0xE4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xDA, 0xE0, 0xDA, 0xE6, 0xB5, 0xA7, 0xD6, 0xCC, /* 0x44-0x47 */ - 0xDA, 0xE1, 0xB5, 0xA5, 0xDA, 0xDE, 0xB5, 0xAC, /* 0x48-0x4B */ - 0xDA, 0xE2, 0xB5, 0xAB, 0xDA, 0xE3, 0xB5, 0xAD, /* 0x4C-0x4F */ - 0xB5, 0xA8, 0xB5, 0xAE, 0xB5, 0xA9, 0x00, 0x00, /* 0x50-0x53 */ - 0xB5, 0xAA, 0x00, 0x00, 0xB5, 0xA6, 0x00, 0x00, /* 0x54-0x57 */ - 0xDA, 0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0xB8, 0x61, 0xDF, 0x50, 0x00, 0x00, 0xDF, 0x53, /* 0x60-0x63 */ - 0xDF, 0x47, 0xDF, 0x4C, 0xDF, 0x46, 0xB8, 0x63, /* 0x64-0x67 */ - 0x00, 0x00, 0xDF, 0x4A, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0xDF, 0x48, 0xB8, 0x62, 0x00, 0x00, /* 0x6C-0x6F */ - 0xDF, 0x4F, 0xDF, 0x4E, 0xDF, 0x4B, 0xDF, 0x4D, /* 0x70-0x73 */ - 0xDF, 0x49, 0xBA, 0xE1, 0xDF, 0x52, 0xB8, 0x5F, /* 0x74-0x77 */ - 0xDF, 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xE3, 0x5D, 0x00, 0x00, /* 0x80-0x83 */ - 0xBA, 0xE8, 0xE3, 0x58, 0x00, 0x00, 0xBA, 0xE7, /* 0x84-0x87 */ - 0xE3, 0x4E, 0x00, 0x00, 0xE3, 0x50, 0xBA, 0xE0, /* 0x88-0x8B */ - 0xE3, 0x55, 0xE3, 0x54, 0xE3, 0x57, 0xBA, 0xE5, /* 0x8C-0x8F */ - 0xE3, 0x52, 0xE3, 0x51, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xBA, 0xE4, 0xBA, 0xDF, 0xE3, 0x53, 0xBA, 0xE2, /* 0x94-0x97 */ - 0xE3, 0x59, 0xE3, 0x5B, 0x00, 0x00, 0xE3, 0x56, /* 0x98-0x9B */ - 0xE3, 0x4F, 0xBA, 0xE3, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xBD, 0x69, 0xBA, 0xDE, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xE3, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xE6, 0xD9, 0xBD, 0x62, 0x00, 0x00, 0xE6, 0xDB, /* 0xAC-0xAF */ - 0x00, 0x00, 0xBD, 0x63, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xBD, 0x65, 0xE6, 0xDE, 0x00, 0x00, 0xE6, 0xD6, /* 0xB4-0xB7 */ - 0xBA, 0xE6, 0xE6, 0xDC, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xD8, 0x00, 0x00, /* 0xBC-0xBF */ - 0xB8, 0x60, 0xBD, 0x68, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xBD, 0x64, 0x00, 0x00, 0xBD, 0x66, 0xBD, 0x67, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xBF, 0x76, 0xE6, 0xDD, 0xE6, 0xD7, /* 0xC8-0xCB */ - 0xBD, 0x6A, 0x00, 0x00, 0xE6, 0xDA, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xEA, 0xC0, 0xEA, 0xBB, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xEA, 0xC5, 0xBF, 0x74, 0xEA, 0xBD, 0xBF, 0x78, /* 0xD8-0xDB */ - 0xEA, 0xC3, 0xEA, 0xBA, 0xEA, 0xB7, 0xEA, 0xC6, /* 0xDC-0xDF */ - 0xC1, 0x51, 0xBF, 0x79, 0xEA, 0xC2, 0xEA, 0xB8, /* 0xE0-0xE3 */ - 0xBF, 0x77, 0xEA, 0xBC, 0xBF, 0x7B, 0xEA, 0xB9, /* 0xE4-0xE7 */ - 0xEA, 0xBE, 0xBF, 0x7A, 0xEA, 0xC1, 0xEA, 0xC4, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xED, 0xCB, 0xED, 0xCC, 0xED, 0xBC, 0xED, 0xC3, /* 0xF0-0xF3 */ - 0xED, 0xC1, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x4F, /* 0xF4-0xF7 */ - 0xED, 0xC8, 0xEA, 0xBF, 0x00, 0x00, 0xED, 0xBF, /* 0xF8-0xFB */ - 0x00, 0x00, 0xED, 0xC9, 0xC1, 0x4E, 0xED, 0xBE, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_7C[512] = { - 0xED, 0xBD, 0xED, 0xC7, 0xED, 0xC4, 0xED, 0xC6, /* 0x00-0x03 */ - 0x00, 0x00, 0xED, 0xBA, 0xED, 0xCA, 0xC1, 0x4C, /* 0x04-0x07 */ - 0x00, 0x00, 0xED, 0xC5, 0xED, 0xCE, 0xED, 0xC2, /* 0x08-0x0B */ - 0xC1, 0x50, 0xC1, 0x4D, 0xED, 0xC0, 0xED, 0xBB, /* 0x0C-0x0F */ - 0xED, 0xCD, 0xBF, 0x75, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xF0, 0x63, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xF0, 0x61, 0xF0, 0x67, 0xC2, 0xB0, 0xF0, 0x65, /* 0x1C-0x1F */ - 0xF0, 0x64, 0xC2, 0xB2, 0xF0, 0x6A, 0xC2, 0xB1, /* 0x20-0x23 */ - 0x00, 0x00, 0xF0, 0x6B, 0xF0, 0x68, 0xC2, 0xAE, /* 0x24-0x27 */ - 0xF0, 0x69, 0xF0, 0x62, 0xC2, 0xAF, 0xC2, 0xAD, /* 0x28-0x2B */ - 0xF2, 0xAB, 0xF0, 0x66, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xF0, 0x6C, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xA8, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC3, 0xB2, /* 0x34-0x37 */ - 0xC3, 0xB0, 0xF2, 0xAA, 0x00, 0x00, 0xF2, 0xAC, /* 0x38-0x3B */ - 0xF2, 0xA9, 0xC3, 0xB1, 0xC3, 0xAE, 0xC3, 0xAF, /* 0x3C-0x3F */ - 0xC3, 0xB3, 0x00, 0x00, 0x00, 0x00, 0xC4, 0x78, /* 0x40-0x43 */ - 0x00, 0x00, 0xF4, 0xAA, 0x00, 0x00, 0xF4, 0xA9, /* 0x44-0x47 */ - 0xF4, 0xA7, 0xF4, 0xA6, 0xF4, 0xA8, 0x00, 0x00, /* 0x48-0x4B */ - 0xC4, 0x77, 0xC4, 0x79, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xC4, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xF5, 0xE5, /* 0x50-0x53 */ - 0xF5, 0xE4, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xFA, /* 0x54-0x57 */ - 0x00, 0x00, 0xF6, 0xFC, 0xF6, 0xFE, 0xF6, 0xFD, /* 0x58-0x5B */ - 0xF6, 0xFB, 0x00, 0x00, 0x00, 0x00, 0xC5, 0xA3, /* 0x5C-0x5F */ - 0xC5, 0xA2, 0x00, 0x00, 0x00, 0x00, 0xC5, 0xD3, /* 0x60-0x63 */ - 0xC5, 0xD2, 0xC5, 0xD4, 0xF7, 0xED, 0xF7, 0xEC, /* 0x64-0x67 */ - 0x00, 0x00, 0xF8, 0xFB, 0xF8, 0xB8, 0xF8, 0xFC, /* 0x68-0x6B */ - 0xC6, 0x58, 0x00, 0x00, 0xC6, 0x59, 0xF9, 0x6D, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xC6, 0x7E, 0xA6, 0xCC, /* 0x70-0x73 */ - 0x00, 0x00, 0xCD, 0xA8, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0xD0, 0x45, 0xD0, 0x46, 0xD0, 0x44, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xAC, 0xF3, 0x00, 0x00, 0xD0, 0x47, /* 0x7C-0x7F */ - - 0xD0, 0x48, 0xD0, 0x49, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xD3, 0x49, 0xD3, 0x4F, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xD3, 0x4D, 0xAF, 0xBB, 0xD3, 0x4B, 0x00, 0x00, /* 0x88-0x8B */ - 0xD3, 0x4C, 0xD3, 0x4E, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xD3, 0x4A, 0xB2, 0xC9, 0x00, 0x00, /* 0x90-0x93 */ - 0xD6, 0xDE, 0xB2, 0xCB, 0xD6, 0xE0, 0xB2, 0xCA, /* 0x94-0x97 */ - 0xD6, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0xE8, 0xB5, 0xAF, /* 0x9C-0x9F */ - 0x00, 0x00, 0xDA, 0xEA, 0xDA, 0xE7, 0xD6, 0xE1, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xB5, 0xB0, 0x00, 0x00, 0xF9, 0xDB, /* 0xA4-0xA7 */ - 0xDA, 0xE9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0x56, /* 0xAC-0xAF */ - 0x00, 0x00, 0xB8, 0x64, 0xDF, 0x54, 0xB8, 0x65, /* 0xB0-0xB3 */ - 0xDF, 0x55, 0xB8, 0x66, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xBA, 0xE9, 0xE3, 0x61, 0xE3, 0x5E, /* 0xB8-0xBB */ - 0xE3, 0x60, 0xBA, 0xEA, 0xBA, 0xEB, 0xE3, 0x5F, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xE6, 0xDF, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xE6, 0xE0, 0x00, 0x00, 0xBD, 0x6B, 0xE6, 0xE2, /* 0xC8-0xCB */ - 0xE6, 0xE1, 0x00, 0x00, 0xA2, 0x61, 0x00, 0x00, /* 0xCC-0xCF */ - 0xEA, 0xCA, 0xEA, 0xCB, 0xEA, 0xC7, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xEA, 0xC8, 0xBF, 0x7C, 0xBF, 0x7D, 0xEA, 0xC9, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xC1, 0x57, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xC1, 0x53, 0xC1, 0x58, 0xC1, 0x54, 0xC1, 0x56, /* 0xDC-0xDF */ - 0xC1, 0x52, 0x00, 0x00, 0xC1, 0x55, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC2, 0xB3, /* 0xE4-0xE7 */ - 0xED, 0xCF, 0x00, 0x00, 0xF2, 0xAE, 0x00, 0x00, /* 0xE8-0xEB */ - 0xF2, 0xAD, 0x00, 0x00, 0xF4, 0xAB, 0xC4, 0x7A, /* 0xEC-0xEF */ - 0xC4, 0x7B, 0xF7, 0x41, 0xF5, 0xE6, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xF7, 0x40, 0x00, 0x00, 0xF8, 0xFD, 0xF9, 0xA4, /* 0xF4-0xF7 */ - 0xA6, 0xCD, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x74, /* 0xF8-0xFB */ - 0x00, 0x00, 0xCD, 0xA9, 0xAA, 0xC8, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_7D[512] = { - 0xAC, 0xF6, 0xD0, 0x4C, 0xAC, 0xF4, 0xD0, 0x4A, /* 0x00-0x03 */ - 0xAC, 0xF9, 0xAC, 0xF5, 0xAC, 0xFA, 0xAC, 0xF8, /* 0x04-0x07 */ - 0xD0, 0x4B, 0xAC, 0xF7, 0xAF, 0xBF, 0xAF, 0xBE, /* 0x08-0x0B */ - 0xD3, 0x5A, 0xAF, 0xC7, 0xD3, 0x53, 0xD3, 0x59, /* 0x0C-0x0F */ - 0xAF, 0xC3, 0xD3, 0x52, 0xD3, 0x58, 0xD3, 0x56, /* 0x10-0x13 */ - 0xAF, 0xC2, 0xAF, 0xC4, 0xD3, 0x55, 0xAF, 0xBD, /* 0x14-0x17 */ - 0xD3, 0x54, 0xAF, 0xC8, 0xAF, 0xC5, 0xAF, 0xC9, /* 0x18-0x1B */ - 0xAF, 0xC6, 0xD3, 0x51, 0xD3, 0x50, 0xD3, 0x57, /* 0x1C-0x1F */ - 0xAF, 0xC0, 0xAF, 0xBC, 0xAF, 0xC1, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xD6, 0xF0, 0xD6, 0xE9, 0x00, 0x00, 0xB5, 0xB5, /* 0x28-0x2B */ - 0xD6, 0xE8, 0x00, 0x00, 0xB2, 0xCF, 0xB2, 0xD6, /* 0x2C-0x2F */ - 0xB2, 0xD3, 0xB2, 0xD9, 0xB2, 0xD8, 0xB2, 0xD4, /* 0x30-0x33 */ - 0x00, 0x00, 0xD6, 0xE2, 0xD6, 0xE5, 0x00, 0x00, /* 0x34-0x37 */ - 0xD6, 0xE4, 0xB2, 0xD0, 0xD6, 0xE6, 0xD6, 0xEF, /* 0x38-0x3B */ - 0xB2, 0xD1, 0xD6, 0xE3, 0xD6, 0xEC, 0xD6, 0xED, /* 0x3C-0x3F */ - 0xB2, 0xD2, 0xD6, 0xEA, 0xB2, 0xD7, 0xB2, 0xCD, /* 0x40-0x43 */ - 0xB2, 0xD5, 0xD6, 0xE7, 0xB2, 0xCC, 0xD6, 0xEB, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xD6, 0xEE, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xDA, 0xFB, 0xDA, 0xF2, /* 0x4C-0x4F */ - 0xB5, 0xB2, 0xDA, 0xF9, 0xDA, 0xF6, 0xDA, 0xEE, /* 0x50-0x53 */ - 0xDA, 0xF7, 0xB5, 0xB4, 0xDA, 0xEF, 0x00, 0x00, /* 0x54-0x57 */ - 0xDA, 0xEB, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x6C, /* 0x58-0x5B */ - 0xDA, 0xF4, 0x00, 0x00, 0xB5, 0xB1, 0xDA, 0xFA, /* 0x5C-0x5F */ - 0x00, 0x00, 0xB5, 0xB8, 0xB5, 0xBA, 0xDA, 0xED, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xB5, 0xB9, 0xDA, 0xF0, /* 0x64-0x67 */ - 0xB5, 0xB3, 0xDA, 0xF8, 0xDA, 0xF1, 0xDA, 0xF5, /* 0x68-0x6B */ - 0x00, 0x00, 0xDA, 0xF3, 0xB5, 0xB6, 0xDA, 0xEC, /* 0x6C-0x6F */ - 0xB5, 0xBB, 0xB2, 0xCE, 0xB5, 0xB7, 0xB5, 0xBC, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xB8, 0x68, 0xDF, 0x5D, 0xDF, 0x5F, /* 0x78-0x7B */ - 0xDF, 0x61, 0xDF, 0x65, 0x00, 0x00, 0xDF, 0x5B, /* 0x7C-0x7F */ - - 0xDF, 0x59, 0xB8, 0x6A, 0x00, 0x00, 0xDF, 0x60, /* 0x80-0x83 */ - 0xDF, 0x64, 0xDF, 0x5C, 0xDF, 0x58, 0x00, 0x00, /* 0x84-0x87 */ - 0xDF, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0xDF, 0x62, 0xDF, 0x5A, 0xDF, 0x5E, 0xB8, 0x6B, /* 0x8C-0x8F */ - 0x00, 0x00, 0xB8, 0x69, 0xDF, 0x66, 0xB8, 0x67, /* 0x90-0x93 */ - 0xDF, 0x63, 0x00, 0x00, 0xE3, 0x72, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xBA, 0xEE, 0xE3, 0x6A, 0xBD, 0x78, 0xE3, 0x74, /* 0x9C-0x9F */ - 0xBA, 0xF1, 0xE3, 0x78, 0xBA, 0xF7, 0xE3, 0x65, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0x75, 0xE3, 0x62, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xE3, 0x77, 0xE3, 0x66, 0x00, 0x00, /* 0xA8-0xAB */ - 0xBA, 0xFE, 0xBA, 0xFB, 0xE3, 0x76, 0xE3, 0x70, /* 0xAC-0xAF */ - 0xBA, 0xED, 0xBA, 0xF5, 0xBA, 0xF4, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xBA, 0xF3, 0xBA, 0xF9, 0x00, 0x00, 0xE3, 0x63, /* 0xB4-0xB7 */ - 0xBA, 0xFA, 0xE3, 0x71, 0xBA, 0xF6, 0xBA, 0xEC, /* 0xB8-0xBB */ - 0xE3, 0x73, 0xBA, 0xEF, 0xBA, 0xF0, 0xBA, 0xF8, /* 0xBC-0xBF */ - 0xE3, 0x68, 0xE3, 0x67, 0xE3, 0x64, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xE3, 0x6C, 0xE3, 0x69, 0xE3, 0x6D, 0xBA, 0xFD, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xE3, 0x79, 0xBA, 0xF2, 0xE3, 0x6E, /* 0xC8-0xCB */ - 0xE3, 0x6F, 0x00, 0x00, 0xE3, 0x6B, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xBA, 0xFC, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE7, /* 0xD4-0xD7 */ - 0xBD, 0x70, 0xBD, 0x79, 0xBD, 0x75, 0xE6, 0xE4, /* 0xD8-0xDB */ - 0x00, 0x00, 0xBD, 0x72, 0xBD, 0x76, 0xE6, 0xF0, /* 0xDC-0xDF */ - 0xBD, 0x6C, 0xE6, 0xE8, 0x00, 0x00, 0xBD, 0x74, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0xE6, 0xEB, 0xE6, 0xE6, /* 0xE4-0xE7 */ - 0xBD, 0x73, 0xBD, 0x77, 0xE6, 0xE5, 0x00, 0x00, /* 0xE8-0xEB */ - 0xBD, 0x71, 0x00, 0x00, 0xE6, 0xEF, 0xBD, 0x6E, /* 0xEC-0xEF */ - 0xE6, 0xEE, 0xE6, 0xED, 0xBD, 0x7A, 0xE5, 0x72, /* 0xF0-0xF3 */ - 0xBD, 0x6D, 0x00, 0x00, 0xE6, 0xEC, 0xE6, 0xE3, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xBD, 0x7B, 0xE6, 0xEA, 0xBD, 0x6F, /* 0xF8-0xFB */ -}; - -static const unsigned char u2c_7E[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xE9, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0xBF, 0xA2, 0xBF, 0xA7, 0xBF, 0x7E, 0xEA, 0xD8, /* 0x08-0x0B */ - 0xEA, 0xCF, 0xEA, 0xDB, 0xEA, 0xD3, 0xEA, 0xD9, /* 0x0C-0x0F */ - 0xBF, 0xA8, 0xBF, 0xA1, 0xEA, 0xCC, 0xEA, 0xD2, /* 0x10-0x13 */ - 0xEA, 0xDC, 0xEA, 0xD5, 0xEA, 0xDA, 0xEA, 0xCE, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0xD6, 0xBF, 0xA3, /* 0x18-0x1B */ - 0xEA, 0xD4, 0xBF, 0xA6, 0xBF, 0xA5, 0xEA, 0xD0, /* 0x1C-0x1F */ - 0xEA, 0xD1, 0xEA, 0xCD, 0xEA, 0xD7, 0xBF, 0xA4, /* 0x20-0x23 */ - 0xEA, 0xDE, 0xEA, 0xDD, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xED, 0xDA, 0xED, 0xD6, 0xC1, 0x5F, /* 0x28-0x2B */ - 0x00, 0x00, 0xED, 0xD0, 0xC1, 0x59, 0xC1, 0x69, /* 0x2C-0x2F */ - 0xED, 0xDC, 0xC1, 0x61, 0xC1, 0x5D, 0xED, 0xD3, /* 0x30-0x33 */ - 0xC1, 0x64, 0xC1, 0x67, 0xED, 0xDE, 0xC1, 0x5C, /* 0x34-0x37 */ - 0xED, 0xD5, 0xC1, 0x65, 0xED, 0xE0, 0xED, 0xDD, /* 0x38-0x3B */ - 0xED, 0xD1, 0xC1, 0x60, 0xC1, 0x5A, 0xC1, 0x68, /* 0x3C-0x3F */ - 0xED, 0xD8, 0xC1, 0x63, 0xED, 0xD2, 0xC1, 0x5E, /* 0x40-0x43 */ - 0xED, 0xDF, 0xC1, 0x62, 0xC1, 0x5B, 0xED, 0xD9, /* 0x44-0x47 */ - 0xC1, 0x66, 0xED, 0xD7, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xED, 0xDB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0xF0, 0x6E, 0xF0, 0x74, 0xC2, 0xB9, 0xF0, 0x77, /* 0x50-0x53 */ - 0xC2, 0xB4, 0xC2, 0xB5, 0xF0, 0x6F, 0xF0, 0x76, /* 0x54-0x57 */ - 0xF0, 0x71, 0xC2, 0xBA, 0xC2, 0xB7, 0x00, 0x00, /* 0x58-0x5B */ - 0xF0, 0x6D, 0x00, 0x00, 0xC2, 0xB6, 0xF0, 0x73, /* 0x5C-0x5F */ - 0xF0, 0x75, 0xC2, 0xB8, 0xF0, 0x72, 0xF0, 0x70, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xF2, 0xB8, 0xC3, 0xB7, 0xC3, 0xB8, 0xC3, 0xB4, /* 0x68-0x6B */ - 0x00, 0x00, 0xC3, 0xB5, 0x00, 0x00, 0xF2, 0xB4, /* 0x6C-0x6F */ - 0xF2, 0xB2, 0x00, 0x00, 0xF2, 0xB6, 0xC3, 0xBA, /* 0x70-0x73 */ - 0xF2, 0xB7, 0xF2, 0xB0, 0xF2, 0xAF, 0xF2, 0xB3, /* 0x74-0x77 */ - 0xF2, 0xB1, 0xC3, 0xB6, 0xF2, 0xB5, 0xF4, 0xAC, /* 0x78-0x7B */ - 0xC4, 0x7E, 0xC4, 0x7D, 0xF4, 0xAD, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xF4, 0xAF, 0xF4, 0xAE, 0xC4, 0xA1, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0xEB, 0xF5, 0xE8, /* 0x84-0x87 */ - 0xF5, 0xE9, 0x00, 0x00, 0xF5, 0xE7, 0xF5, 0xEA, /* 0x88-0x8B */ - 0xC4, 0xF2, 0xF5, 0xEC, 0x00, 0x00, 0xC4, 0xF1, /* 0x8C-0x8F */ - 0x00, 0x00, 0xF7, 0x42, 0x00, 0x00, 0xC5, 0xD5, /* 0x90-0x93 */ - 0xC5, 0xD7, 0xF7, 0xEE, 0xC5, 0xD6, 0xF8, 0xB9, /* 0x94-0x97 */ - 0xF9, 0x40, 0xF9, 0x42, 0xF8, 0xFE, 0xF9, 0x41, /* 0x98-0x9B */ - 0xC6, 0x6C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ -}; - -static const unsigned char u2c_7F[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xA6, 0xCE, 0x00, 0x00, /* 0x34-0x37 */ - 0xAC, 0xFB, 0xD2, 0x6F, 0xAF, 0xCA, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xB2, 0xDA, 0xDA, 0xFC, 0xDA, 0xFD, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEA, 0xDF, /* 0x40-0x43 */ - 0xC1, 0x6A, 0xED, 0xE1, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0xC2, 0xBB, 0x00, 0x00, 0xF2, 0xBA, 0xF2, 0xB9, /* 0x48-0x4B */ - 0xC4, 0xA2, 0xF5, 0xED, 0x00, 0x00, 0xF7, 0x43, /* 0x4C-0x4F */ - 0xC5, 0xF8, 0xCA, 0x49, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xAA, 0xC9, 0xA8, 0x75, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xD0, 0x4D, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x60, /* 0x58-0x5B */ - 0xD3, 0x5B, 0xD3, 0x5F, 0xD3, 0x5D, 0xAF, 0xCB, /* 0x5C-0x5F */ - 0xD3, 0x5E, 0xD3, 0x5C, 0x00, 0x00, 0xD6, 0xF1, /* 0x60-0x63 */ - 0x00, 0x00, 0xDA, 0xFE, 0xDB, 0x40, 0xDF, 0x69, /* 0x64-0x67 */ - 0xDF, 0x6A, 0xB8, 0x6E, 0xB8, 0x6F, 0xDF, 0x68, /* 0x68-0x6B */ - 0xDF, 0x6B, 0xDF, 0x67, 0xB8, 0x6D, 0x00, 0x00, /* 0x6C-0x6F */ - 0xBB, 0x40, 0x00, 0x00, 0xB8, 0x70, 0xE3, 0x7A, /* 0x70-0x73 */ - 0x00, 0x00, 0xBD, 0x7C, 0xE6, 0xF1, 0xBD, 0x7D, /* 0x74-0x77 */ - 0x00, 0x00, 0xBF, 0xA9, 0xEA, 0xE2, 0xEA, 0xE0, /* 0x78-0x7B */ - 0xEA, 0xE1, 0xED, 0xE4, 0xED, 0xE3, 0xED, 0xE2, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF2, 0xBB, /* 0x80-0x83 */ - 0x00, 0x00, 0xC3, 0xB9, 0xF2, 0xBC, 0xF7, 0x44, /* 0x84-0x87 */ - 0xC5, 0xF9, 0xF8, 0xBA, 0xA6, 0xCF, 0xAA, 0xCB, /* 0x88-0x8B */ - 0xAA, 0xCA, 0xD0, 0x4F, 0xAC, 0xFC, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xD0, 0x4E, 0xD3, 0x62, 0x00, 0x00, /* 0x90-0x93 */ - 0xAF, 0xCC, 0xD6, 0xF2, 0xD3, 0x61, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xB2, 0xDC, 0xD6, 0xF5, /* 0x98-0x9B */ - 0xD6, 0xF3, 0xD6, 0xF4, 0xB2, 0xDB, 0x00, 0x00, /* 0x9C-0x9F */ - 0xDB, 0x42, 0xDB, 0x43, 0xDB, 0x41, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xB8, 0x73, 0xDF, 0x6D, 0xDF, 0x6C, 0xDF, 0x6E, /* 0xA4-0xA7 */ - 0xB8, 0x72, 0xB8, 0x71, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xE6, 0xF2, 0xE6, 0xF4, 0x00, 0x00, 0xBD, 0x7E, /* 0xAC-0xAF */ - 0xE6, 0xF3, 0xEA, 0xE3, 0xBF, 0xAA, 0xF0, 0x79, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xF0, 0x78, 0xC3, 0xBB, 0xF2, 0xBD, /* 0xB4-0xB7 */ - 0xC3, 0xBD, 0xC3, 0xBC, 0xF4, 0xB0, 0xF5, 0xEE, /* 0xB8-0xBB */ - 0xC4, 0xF3, 0xA6, 0xD0, 0xD0, 0x50, 0xAC, 0xFD, /* 0xBC-0xBF */ - 0xD3, 0x65, 0xAF, 0xCE, 0xD3, 0x64, 0xD3, 0x63, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xAF, 0xCD, 0x00, 0x00, 0xD6, 0xFB, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xD6, 0xFD, 0xD6, 0xF6, 0xD6, 0xF7, /* 0xC8-0xCB */ - 0xB2, 0xDD, 0xD6, 0xF8, 0xB2, 0xDE, 0xD6, 0xFC, /* 0xCC-0xCF */ - 0xD6, 0xF9, 0xD6, 0xFA, 0xB2, 0xDF, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xB5, 0xBE, 0xB5, 0xBF, 0x00, 0x00, 0xDB, 0x44, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0x6F, /* 0xD8-0xDB */ - 0xDF, 0x70, 0x00, 0x00, 0xE3, 0x7E, 0xBB, 0x43, /* 0xDC-0xDF */ - 0xBB, 0x41, 0xBB, 0x42, 0xE3, 0x7B, 0xE3, 0x7C, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xE3, 0x7D, 0xE6, 0xF9, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xE6, 0xFA, 0xBD, 0xA1, 0xE6, 0xF7, 0xE6, 0xF6, /* 0xE8-0xEB */ - 0xE6, 0xF8, 0xE6, 0xF5, 0xBF, 0xAD, 0xEA, 0xE4, /* 0xEC-0xEF */ - 0xBF, 0xAB, 0xBF, 0xAC, 0xED, 0xE6, 0xC1, 0x6B, /* 0xF0-0xF3 */ - 0xED, 0xE5, 0xEF, 0xA8, 0x00, 0x00, 0xF0, 0x7A, /* 0xF4-0xF7 */ - 0xF0, 0x7B, 0xC2, 0xBC, 0x00, 0x00, 0xC2, 0xBD, /* 0xF8-0xFB */ - 0xC1, 0x6C, 0xF2, 0xBE, 0xF2, 0xBF, 0xF4, 0xB1, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_80[512] = { - 0xC4, 0xA3, 0xA6, 0xD1, 0x00, 0x00, 0xA6, 0xD2, /* 0x00-0x03 */ - 0xAC, 0xFE, 0xAA, 0xCC, 0xAF, 0xCF, 0xD0, 0x51, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB5, 0xC0, /* 0x08-0x0B */ - 0xA6, 0xD3, 0xAD, 0x41, 0xD0, 0x52, 0xD0, 0x53, /* 0x0C-0x0F */ - 0xAD, 0x40, 0xAD, 0x42, 0xA6, 0xD4, 0x00, 0x00, /* 0x10-0x13 */ - 0xD0, 0x54, 0xAF, 0xD1, 0xD3, 0x66, 0xAF, 0xD3, /* 0x14-0x17 */ - 0xAF, 0xD0, 0xAF, 0xD2, 0x00, 0x00, 0xD7, 0x41, /* 0x18-0x1B */ - 0xB2, 0xE0, 0x00, 0x00, 0xD7, 0x40, 0xD6, 0xFE, /* 0x1C-0x1F */ - 0x00, 0x00, 0xDF, 0x71, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0xE3, 0xA1, 0x00, 0x00, 0xBD, 0xA2, 0x00, 0x00, /* 0x24-0x27 */ - 0xBF, 0xAE, 0xEA, 0xE6, 0xEA, 0xE5, 0x00, 0x00, /* 0x28-0x2B */ - 0xED, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xF5, 0xEF, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xD5, /* 0x30-0x33 */ - 0xCB, 0x73, 0xCD, 0xAA, 0xAD, 0x43, 0xD0, 0x55, /* 0x34-0x37 */ - 0x00, 0x00, 0xD3, 0x68, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xAF, 0xD4, 0xD3, 0x67, 0xAF, 0xD5, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0x43, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xB2, 0xE2, 0xD7, 0x42, /* 0x44-0x47 */ - 0xD7, 0x44, 0x00, 0x00, 0xB2, 0xE1, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0x46, /* 0x4C-0x4F */ - 0xDB, 0x47, 0xDB, 0x45, 0xB5, 0xC1, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xB8, 0x74, 0x00, 0x00, /* 0x54-0x57 */ - 0xB8, 0x75, 0x00, 0x00, 0xBB, 0x45, 0x00, 0x00, /* 0x58-0x5B */ - 0xE3, 0xA3, 0xE3, 0xA2, 0xBB, 0x44, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0xE6, 0xFB, 0x00, 0x00, 0x00, 0x00, 0xE6, 0xFC, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0xEA, 0xE7, 0x00, 0x00, 0x00, 0x00, 0xC1, 0x70, /* 0x6C-0x6F */ - 0xC1, 0x6F, 0xC1, 0x6D, 0xC1, 0x6E, 0xC1, 0x71, /* 0x70-0x73 */ - 0x00, 0x00, 0xF0, 0x7C, 0xC2, 0xBF, 0xC2, 0xBE, /* 0x74-0x77 */ - 0xF2, 0xC0, 0xF4, 0xB2, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xC5, 0xA5, 0xC5, 0xA4, 0xA6, 0xD6, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xD1, 0xFB, 0x00, 0x00, /* 0x80-0x83 */ - 0xB8, 0x77, 0xB5, 0xC2, 0xB8, 0x76, 0xBB, 0x46, /* 0x84-0x87 */ - 0x00, 0x00, 0xA6, 0xD7, 0xC9, 0xA9, 0xA6, 0xD8, /* 0x88-0x8B */ - 0xA6, 0xD9, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xAB, /* 0x8C-0x8F */ - 0xCB, 0x76, 0x00, 0x00, 0xCB, 0x77, 0xA8, 0x77, /* 0x90-0x93 */ - 0x00, 0x00, 0xCB, 0x74, 0xA8, 0x76, 0x00, 0x00, /* 0x94-0x97 */ - 0xA8, 0x79, 0xCB, 0x75, 0xA8, 0x7B, 0xA8, 0x7A, /* 0x98-0x9B */ - 0xCB, 0x78, 0xA8, 0x78, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xAA, 0xD1, 0xAA, 0xCF, 0xCD, 0xAD, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xAA, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xAA, 0xD3, 0xAA, 0xD5, 0xAA, 0xD2, /* 0xA8-0xAB */ - 0x00, 0x00, 0xCD, 0xB0, 0xCD, 0xAC, 0xAA, 0xD6, /* 0xAC-0xAF */ - 0x00, 0x00, 0xAA, 0xD0, 0xA8, 0x7C, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xAA, 0xD4, 0xCD, 0xAF, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xCD, 0xAE, 0x00, 0x00, 0xAA, 0xCD, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0x5B, 0xAD, 0x47, /* 0xC0-0xC3 */ - 0xAD, 0x48, 0xD0, 0x5D, 0x00, 0x00, 0xD0, 0x57, /* 0xC4-0xC7 */ - 0xD0, 0x5A, 0xD0, 0x63, 0xD0, 0x61, 0x00, 0x00, /* 0xC8-0xCB */ - 0xAD, 0x49, 0xD0, 0x67, 0xAD, 0x4C, 0xD0, 0x64, /* 0xCC-0xCF */ - 0xD0, 0x5C, 0xD0, 0x59, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xDB, 0x49, 0xD0, 0x62, 0xAD, 0x44, 0xD0, 0x65, /* 0xD4-0xD7 */ - 0xD0, 0x56, 0xD0, 0x5F, 0xAD, 0x46, 0xAD, 0x4B, /* 0xD8-0xDB */ - 0xD0, 0x60, 0xAD, 0x4F, 0xAD, 0x4D, 0x00, 0x00, /* 0xDC-0xDF */ - 0xD0, 0x58, 0xAD, 0x4A, 0x00, 0x00, 0xD0, 0x5E, /* 0xE0-0xE3 */ - 0xAD, 0x4E, 0xAD, 0x45, 0xD0, 0x66, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xAF, 0xDA, 0x00, 0x00, 0xAF, 0xE3, /* 0xEC-0xEF */ - 0xAF, 0xD8, 0xAF, 0xD6, 0xD3, 0x6A, 0xAF, 0xDE, /* 0xF0-0xF3 */ - 0xAF, 0xDB, 0xD3, 0x6C, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xAF, 0xDD, 0xD3, 0x6B, 0xD3, 0x69, 0xD3, 0x6E, /* 0xF8-0xFB */ - 0xAF, 0xE2, 0xAF, 0xE0, 0xDB, 0x48, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_81[512] = { - 0xD3, 0x6F, 0xD3, 0x6D, 0xAF, 0xD7, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xAF, 0xD9, 0xAF, 0xDC, 0x00, 0x00, /* 0x04-0x07 */ - 0xAF, 0xDF, 0x00, 0x00, 0xAF, 0xE1, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xD7, 0x4E, 0xB2, 0xE4, 0x00, 0x00, /* 0x14-0x17 */ - 0xD7, 0x45, 0xD7, 0x47, 0x00, 0x00, 0xD7, 0x48, /* 0x18-0x1B */ - 0x00, 0x00, 0xD7, 0x50, 0xD7, 0x4C, 0xD7, 0x4A, /* 0x1C-0x1F */ - 0x00, 0x00, 0xD7, 0x4D, 0xD7, 0x51, 0xB2, 0xE5, /* 0x20-0x23 */ - 0xB2, 0xE9, 0xD7, 0x46, 0x00, 0x00, 0xD7, 0x4F, /* 0x24-0x27 */ - 0x00, 0x00, 0xB2, 0xE7, 0x00, 0x00, 0xB2, 0xE6, /* 0x28-0x2B */ - 0xD7, 0x4B, 0xD7, 0x49, 0x00, 0x00, 0xB2, 0xE3, /* 0x2C-0x2F */ - 0xB2, 0xE8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0xB5, 0xC8, 0xDB, 0x51, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xDB, 0x4F, 0xB5, 0xCA, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0x4A, /* 0x40-0x43 */ - 0xDF, 0xA1, 0x00, 0x00, 0xB5, 0xC9, 0xDB, 0x4E, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0x4B, 0xB5, 0xC5, /* 0x48-0x4B */ - 0xB5, 0xCB, 0xDB, 0x50, 0xB5, 0xC7, 0xDB, 0x4D, /* 0x4C-0x4F */ - 0xBB, 0x47, 0xB5, 0xC6, 0xDB, 0x4C, 0xB5, 0xCC, /* 0x50-0x53 */ - 0xB5, 0xC4, 0xB5, 0xC3, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDF, 0x77, /* 0x58-0x5B */ - 0xDF, 0x75, 0x00, 0x00, 0xDF, 0x7B, 0x00, 0x00, /* 0x5C-0x5F */ - 0xDF, 0x73, 0xDF, 0xA2, 0xDF, 0x78, 0x00, 0x00, /* 0x60-0x63 */ - 0xDF, 0x72, 0xB8, 0x7B, 0xB8, 0xA3, 0xDF, 0x7D, /* 0x64-0x67 */ - 0x00, 0x00, 0xDF, 0x76, 0x00, 0x00, 0xB8, 0x7E, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0xB8, 0x7C, 0xDF, 0x7E, /* 0x6C-0x6F */ - 0xB8, 0x79, 0xB8, 0x78, 0xDF, 0x79, 0xB8, 0x7D, /* 0x70-0x73 */ - 0xB5, 0xCD, 0x00, 0x00, 0xDF, 0x7C, 0xDF, 0x74, /* 0x74-0x77 */ - 0xB8, 0x7A, 0xB8, 0xA1, 0xB8, 0xA2, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBB, 0x4C, /* 0x7C-0x7F */ - - 0xBB, 0x48, 0x00, 0x00, 0xBB, 0x4D, 0xE3, 0xA6, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xA5, 0xE3, 0xA7, /* 0x84-0x87 */ - 0xBB, 0x4A, 0xE3, 0xA4, 0xBB, 0x4B, 0xE3, 0xAA, /* 0x88-0x8B */ - 0xE3, 0xA9, 0xE3, 0xA8, 0x00, 0x00, 0xBB, 0x49, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0xE7, 0x41, 0x00, 0x00, 0xE7, 0x44, /* 0x94-0x97 */ - 0xBD, 0xA8, 0xE7, 0x43, 0xBD, 0xA7, 0xBD, 0xA3, /* 0x98-0x9B */ - 0xBD, 0xA4, 0xBD, 0xA5, 0xE7, 0x40, 0xE6, 0xFE, /* 0x9C-0x9F */ - 0xBD, 0xA6, 0x00, 0x00, 0xE7, 0x42, 0xE6, 0xFD, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0xE9, 0xEA, 0xF3, /* 0xA4-0xA7 */ - 0xBF, 0xB1, 0xBF, 0xB0, 0x00, 0x00, 0xEA, 0xED, /* 0xA8-0xAB */ - 0xEA, 0xEF, 0x00, 0x00, 0xEA, 0xEA, 0x00, 0x00, /* 0xAC-0xAF */ - 0xEA, 0xEE, 0xEA, 0xE8, 0xEA, 0xF1, 0xBF, 0xAF, /* 0xB0-0xB3 */ - 0xEA, 0xF0, 0xEA, 0xEC, 0x00, 0x00, 0xEA, 0xF2, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xEA, 0xEB, 0xC1, 0x74, 0xED, 0xE8, /* 0xB8-0xBB */ - 0xED, 0xEE, 0xC1, 0x78, 0xC1, 0x7A, 0xC1, 0x77, /* 0xBC-0xBF */ - 0xC1, 0x76, 0x00, 0x00, 0xC1, 0x75, 0xC1, 0x73, /* 0xC0-0xC3 */ - 0xED, 0xE9, 0xED, 0xEC, 0xC1, 0x72, 0xED, 0xED, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xC1, 0x79, 0xED, 0xEB, 0x00, 0x00, /* 0xC8-0xCB */ - 0xED, 0xEA, 0xC2, 0xC0, 0x00, 0x00, 0xC2, 0xC1, /* 0xCC-0xCF */ - 0xF0, 0xA1, 0xF0, 0x7D, 0xF0, 0x7E, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xF2, 0xC2, 0x00, 0x00, 0xF2, 0xC1, /* 0xD4-0xD7 */ - 0xC3, 0xBE, 0xF4, 0xB4, 0xC4, 0xA4, 0xF4, 0xB3, /* 0xD8-0xDB */ - 0x00, 0x00, 0xF5, 0xF0, 0xF7, 0x45, 0xC5, 0xA6, /* 0xDC-0xDF */ - 0xF9, 0x43, 0xF9, 0x44, 0xC5, 0xD8, 0xA6, 0xDA, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xAA, 0xD7, 0xDB, 0x52, 0xBB, 0x4E, /* 0xE4-0xE7 */ - 0xC1, 0x7B, 0xED, 0xEF, 0xA6, 0xDB, 0x00, 0x00, /* 0xE8-0xEB */ - 0xAF, 0xE5, 0xAF, 0xE4, 0xDB, 0x53, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0xEA, 0xF4, 0xA6, 0xDC, /* 0xF0-0xF3 */ - 0xAD, 0x50, 0x00, 0x00, 0x00, 0x00, 0xDB, 0x54, /* 0xF4-0xF7 */ - 0xDB, 0x55, 0xDB, 0x56, 0xBB, 0x4F, 0xBF, 0xB2, /* 0xF8-0xFB */ - 0xA6, 0xDD, 0x00, 0x00, 0xAA, 0xD8, 0xD0, 0x68, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_82[512] = { - 0xAF, 0xE6, 0xD3, 0x70, 0xB2, 0xEA, 0x00, 0x00, /* 0x00-0x03 */ - 0xDB, 0x57, 0xB8, 0xA4, 0x00, 0x00, 0xBB, 0x50, /* 0x04-0x07 */ - 0xBF, 0xB3, 0xC1, 0x7C, 0xC2, 0xC2, 0xF4, 0xB5, /* 0x08-0x0B */ - 0xA6, 0xDE, 0xAA, 0xD9, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xAF, 0xE7, 0xD7, 0x52, 0xB5, 0xCE, 0x00, 0x00, /* 0x10-0x13 */ - 0xBB, 0x51, 0xE3, 0xAB, 0xE7, 0x45, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA6, 0xDF, /* 0x18-0x1B */ - 0xB5, 0xCF, 0xDF, 0xA3, 0xBB, 0x52, 0xA6, 0xE0, /* 0x1C-0x1F */ - 0xCD, 0xB1, 0xD0, 0x69, 0xAD, 0x51, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xD3, 0x72, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xAF, 0xEA, 0x00, 0x00, 0xAF, 0xE8, 0xAF, 0xE9, /* 0x28-0x2B */ - 0xAF, 0xEB, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x71, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xD7, 0x57, 0xD7, 0x54, /* 0x30-0x33 */ - 0xD7, 0x56, 0xB2, 0xEB, 0xB2, 0xED, 0xB2, 0xEC, /* 0x34-0x37 */ - 0xD7, 0x53, 0xB2, 0xEE, 0xD7, 0x55, 0x00, 0x00, /* 0x38-0x3B */ - 0xDB, 0x58, 0xDB, 0x59, 0x00, 0x00, 0xDB, 0x5A, /* 0x3C-0x3F */ - 0xDF, 0xA6, 0x00, 0x00, 0xDF, 0xA7, 0x00, 0x00, /* 0x40-0x43 */ - 0xDF, 0xA5, 0xDF, 0xA8, 0x00, 0x00, 0xB8, 0xA5, /* 0x44-0x47 */ - 0x00, 0x00, 0xDF, 0xA4, 0x00, 0x00, 0xBB, 0x53, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0x4A, 0xE7, 0x46, /* 0x4C-0x4F */ - 0xE7, 0x49, 0xE7, 0x4B, 0xE7, 0x48, 0xE7, 0x47, /* 0x50-0x53 */ - 0x00, 0x00, 0xEA, 0xF5, 0xEA, 0xF6, 0xEA, 0xF7, /* 0x54-0x57 */ - 0xBF, 0xB4, 0xBF, 0xB5, 0xED, 0xF1, 0xED, 0xF0, /* 0x58-0x5B */ - 0xED, 0xF2, 0x00, 0x00, 0xF0, 0xA3, 0xF0, 0xA2, /* 0x5C-0x5F */ - 0x00, 0x00, 0xF2, 0xC4, 0x00, 0x00, 0xF2, 0xC5, /* 0x60-0x63 */ - 0xF2, 0xC3, 0x00, 0x00, 0xC4, 0xA5, 0x00, 0x00, /* 0x64-0x67 */ - 0xF4, 0xB6, 0xF4, 0xB7, 0x00, 0x00, 0xF7, 0x46, /* 0x68-0x6B */ - 0xF7, 0xEF, 0xF8, 0xBB, 0xA6, 0xE1, 0xA8, 0x7D, /* 0x6C-0x6F */ - 0x00, 0x00, 0xC1, 0x7D, 0xA6, 0xE2, 0x00, 0x00, /* 0x70-0x73 */ - 0xD7, 0x58, 0xDB, 0x5B, 0x00, 0x00, 0xC6, 0x41, /* 0x74-0x77 */ - 0xCA, 0x4A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xCA, 0x4B, 0xCA, 0x4D, 0xA6, 0xE3, 0xCA, 0x4E, /* 0x7C-0x7F */ - - 0xCA, 0x4C, 0x00, 0x00, 0x00, 0x00, 0xCB, 0xA2, /* 0x80-0x83 */ - 0xCB, 0xA3, 0xCB, 0x7B, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xCB, 0xA1, 0xA8, 0xA1, /* 0x88-0x8B */ - 0x00, 0x00, 0xA8, 0xA2, 0xCB, 0x7C, 0xCB, 0x7A, /* 0x8C-0x8F */ - 0xCB, 0x79, 0xCB, 0x7D, 0xA8, 0x7E, 0xCB, 0x7E, /* 0x90-0x93 */ - 0xD0, 0x6A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xCD, 0xB6, 0xAA, 0xDC, 0xCD, 0xB5, 0xCD, 0xB7, /* 0x98-0x9B */ - 0x00, 0x00, 0xAA, 0xDB, 0xCD, 0xBC, 0xAA, 0xDF, /* 0x9C-0x9F */ - 0xCD, 0xB2, 0xCD, 0xC0, 0xCD, 0xC6, 0xAA, 0xE6, /* 0xA0-0xA3 */ - 0xCD, 0xC3, 0xAA, 0xE3, 0x00, 0x00, 0xCD, 0xB9, /* 0xA4-0xA7 */ - 0xCD, 0xBF, 0xCD, 0xC1, 0x00, 0x00, 0xCD, 0xB4, /* 0xA8-0xAB */ - 0xAA, 0xE2, 0xAA, 0xDD, 0xCD, 0xBA, 0xAA, 0xE4, /* 0xAC-0xAF */ - 0xAA, 0xE7, 0xAA, 0xE1, 0x00, 0x00, 0xAA, 0xDA, /* 0xB0-0xB3 */ - 0xCD, 0xBE, 0xCD, 0xB8, 0xCD, 0xC5, 0xAA, 0xE9, /* 0xB4-0xB7 */ - 0xAA, 0xE5, 0xAA, 0xE0, 0xCD, 0xBD, 0xAF, 0xEC, /* 0xB8-0xBB */ - 0xCD, 0xBB, 0xAA, 0xDE, 0xAA, 0xE8, 0x00, 0x00, /* 0xBC-0xBF */ - 0xCD, 0xB3, 0x00, 0x00, 0xCD, 0xC2, 0xCD, 0xC4, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xAD, 0x62, 0xAD, 0x5C, 0xAD, 0x64, /* 0xD0-0xD3 */ - 0xAD, 0x61, 0xD0, 0x71, 0xD0, 0x74, 0xAD, 0x5D, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xD0, 0x6B, 0x00, 0x00, 0xAD, 0x56, /* 0xD8-0xDB */ - 0xAD, 0x60, 0x00, 0x00, 0xAD, 0x63, 0xAD, 0x65, /* 0xDC-0xDF */ - 0xD0, 0xA2, 0xD0, 0x77, 0x00, 0x00, 0xAD, 0x55, /* 0xE0-0xE3 */ - 0xD0, 0xA1, 0xAD, 0x59, 0xAD, 0x57, 0xAD, 0x52, /* 0xE4-0xE7 */ - 0xD0, 0x6F, 0x00, 0x00, 0xD0, 0x7E, 0xD0, 0x73, /* 0xE8-0xEB */ - 0xD0, 0x76, 0xD0, 0xA5, 0x00, 0x00, 0xAD, 0x66, /* 0xEC-0xEF */ - 0xD0, 0x7D, 0xAD, 0x5E, 0xD0, 0x78, 0xD0, 0xA4, /* 0xF0-0xF3 */ - 0xD0, 0x75, 0xD0, 0x79, 0xD0, 0x7C, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xD0, 0x6D, 0xD0, 0xA3, 0xD0, 0x7B, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0x6C, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_83[512] = { - 0xD0, 0x70, 0xAD, 0x5F, 0xAD, 0x5A, 0xAD, 0x53, /* 0x00-0x03 */ - 0xAD, 0x58, 0xAD, 0x54, 0xAD, 0x67, 0xD0, 0x6E, /* 0x04-0x07 */ - 0xD3, 0xA5, 0xAD, 0x5B, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0xD0, 0x7A, 0xCE, 0x41, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xD3, 0xA8, 0xAF, 0xFA, /* 0x14-0x17 */ - 0x00, 0x00, 0xD3, 0x76, 0x00, 0x00, 0xD3, 0xA3, /* 0x18-0x1B */ - 0xD3, 0x7D, 0x00, 0x00, 0xD3, 0xB2, 0x00, 0x00, /* 0x1C-0x1F */ - 0xD3, 0xAA, 0x00, 0x00, 0xD3, 0x7E, 0x00, 0x00, /* 0x20-0x23 */ - 0xD3, 0xA9, 0xD3, 0x78, 0xD3, 0x7C, 0xD3, 0xB5, /* 0x24-0x27 */ - 0xAF, 0xFD, 0xD3, 0xAD, 0xD3, 0xA4, 0xAF, 0xED, /* 0x28-0x2B */ - 0xD3, 0xB3, 0xD3, 0x74, 0x00, 0x00, 0xD3, 0xAC, /* 0x2C-0x2F */ - 0x00, 0x00, 0xAF, 0xFC, 0xAF, 0xF7, 0xD3, 0x73, /* 0x30-0x33 */ - 0xAF, 0xF5, 0xAF, 0xF4, 0xAF, 0xF9, 0xD3, 0xAB, /* 0x34-0x37 */ - 0xAF, 0xF1, 0xAF, 0xF8, 0xD0, 0x72, 0xDB, 0x5C, /* 0x38-0x3B */ - 0xD3, 0xA6, 0x00, 0x00, 0x00, 0x00, 0xD3, 0x7A, /* 0x3C-0x3F */ - 0xAF, 0xFB, 0xD3, 0x7B, 0xD3, 0xA1, 0xAF, 0xFE, /* 0x40-0x43 */ - 0xD3, 0x75, 0xD3, 0xAF, 0x00, 0x00, 0xD3, 0xAE, /* 0x44-0x47 */ - 0xD3, 0xB6, 0xAF, 0xF3, 0xAF, 0xF0, 0xD3, 0xB4, /* 0x48-0x4B */ - 0xD3, 0xB0, 0xD3, 0xA7, 0xD3, 0xA2, 0xAF, 0xF6, /* 0x4C-0x4F */ - 0xAF, 0xF2, 0xD3, 0x77, 0xAF, 0xEE, 0xD3, 0xB1, /* 0x50-0x53 */ - 0xAF, 0xEF, 0x00, 0x00, 0xD3, 0x79, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0x5E, /* 0x70-0x73 */ - 0xD7, 0x60, 0xD7, 0x65, 0xD7, 0x79, 0xB2, 0xFC, /* 0x74-0x77 */ - 0xB2, 0xF2, 0x00, 0x00, 0xD7, 0x5D, 0xB2, 0xFD, /* 0x78-0x7B */ - 0xB2, 0xFE, 0xD7, 0x68, 0xD7, 0x6F, 0xD7, 0x75, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xD7, 0x62, 0x00, 0x00, 0xD7, 0x69, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0xB3, 0x40, 0xD7, 0x77, /* 0x84-0x87 */ - 0xD7, 0x72, 0xB2, 0xFA, 0xB2, 0xF8, 0xD7, 0x6E, /* 0x88-0x8B */ - 0xD7, 0x6A, 0xD7, 0x5C, 0xB2, 0xEF, 0xD7, 0x61, /* 0x8C-0x8F */ - 0xD7, 0x59, 0x00, 0x00, 0xB2, 0xF7, 0xB2, 0xF9, /* 0x90-0x93 */ - 0xD7, 0x66, 0xD7, 0x63, 0xB2, 0xF4, 0xD7, 0x73, /* 0x94-0x97 */ - 0xB2, 0xF1, 0xD7, 0x64, 0xD7, 0x7A, 0xD7, 0x6C, /* 0x98-0x9B */ - 0x00, 0x00, 0xD7, 0x6B, 0xB2, 0xF0, 0x00, 0x00, /* 0x9C-0x9F */ - 0xB2, 0xFB, 0x00, 0x00, 0xB2, 0xF3, 0xD7, 0x5A, /* 0xA0-0xA3 */ - 0xD7, 0x5F, 0xD7, 0x70, 0xD7, 0x76, 0xB3, 0x41, /* 0xA4-0xA7 */ - 0xD7, 0x5B, 0xD7, 0x67, 0xD7, 0x6D, 0xB2, 0xF6, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0xD7, 0x78, 0xD7, 0x71, /* 0xAC-0xAF */ - 0xD7, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xB2, 0xF5, 0x00, 0x00, 0xDB, 0x6C, /* 0xBC-0xBF */ - 0xDB, 0x60, 0xB5, 0xD7, 0xDB, 0x7D, 0xDB, 0xA7, /* 0xC0-0xC3 */ - 0xDB, 0xAA, 0xB5, 0xD5, 0xDB, 0x68, 0xDB, 0xA3, /* 0xC4-0xC7 */ - 0xDB, 0x69, 0xDB, 0x77, 0xB5, 0xE2, 0xDB, 0x73, /* 0xC8-0xCB */ - 0xB5, 0xDF, 0x00, 0x00, 0xDB, 0x74, 0xDB, 0x5D, /* 0xCC-0xCF */ - 0x00, 0x00, 0xDB, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xB5, 0xE8, 0xDB, 0xA1, 0xDB, 0x75, 0xDB, 0xAC, /* 0xD4-0xD7 */ - 0xDB, 0x70, 0xDF, 0xC8, 0x00, 0x00, 0xDB, 0xAF, /* 0xD8-0xDB */ - 0xB5, 0xE6, 0xDB, 0x6E, 0xDB, 0x7A, 0xB5, 0xE9, /* 0xDC-0xDF */ - 0xB5, 0xD4, 0xDB, 0x72, 0xDB, 0xAD, 0xDB, 0x6B, /* 0xE0-0xE3 */ - 0xDB, 0x64, 0xDB, 0x6F, 0x00, 0x00, 0xDB, 0x63, /* 0xE4-0xE7 */ - 0xDB, 0x61, 0xB5, 0xD0, 0xDB, 0xA5, 0xDB, 0x6A, /* 0xE8-0xEB */ - 0xDB, 0xA8, 0x00, 0x00, 0xDB, 0xA9, 0xB5, 0xD8, /* 0xEC-0xEF */ - 0xB5, 0xDD, 0xB5, 0xD9, 0xB5, 0xE1, 0xDB, 0x7E, /* 0xF0-0xF3 */ - 0xB5, 0xDA, 0xDB, 0x76, 0xDB, 0x66, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xB5, 0xD2, 0xDB, 0x5E, 0xDB, 0xA2, 0xDB, 0xAB, /* 0xF8-0xFB */ - 0xDB, 0x65, 0xB5, 0xE0, 0xDB, 0xB0, 0xDB, 0x71, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_84[512] = { - 0x00, 0x00, 0xDB, 0x6D, 0x00, 0x00, 0xB5, 0xD1, /* 0x00-0x03 */ - 0xB5, 0xE5, 0x00, 0x00, 0xDB, 0x7C, 0xB5, 0xE7, /* 0x04-0x07 */ - 0x00, 0x00, 0xDB, 0x78, 0xB5, 0xDC, 0xB5, 0xD6, /* 0x08-0x0B */ - 0xB5, 0xDE, 0xB5, 0xD3, 0xB5, 0xE4, 0xDB, 0x79, /* 0x0C-0x0F */ - 0xDB, 0x67, 0xDB, 0x7B, 0xDB, 0x62, 0xDB, 0xA6, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0xAE, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDB, 0x5F, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xDF, 0xC7, 0x00, 0x00, 0xDF, 0xDD, /* 0x28-0x2B */ - 0xB8, 0x55, 0xDF, 0xCC, 0x00, 0x00, 0xDF, 0xCA, /* 0x2C-0x2F */ - 0xDF, 0xB5, 0xB8, 0xA9, 0xDF, 0xC5, 0xDF, 0xD9, /* 0x30-0x33 */ - 0xDF, 0xC1, 0xB8, 0xB1, 0xDF, 0xD8, 0xDF, 0xBF, /* 0x34-0x37 */ - 0xB5, 0xE3, 0xDF, 0xCF, 0xDF, 0xC0, 0xDF, 0xD6, /* 0x38-0x3B */ - 0xB8, 0xB0, 0xB8, 0xA8, 0x00, 0x00, 0xDF, 0xAA, /* 0x3C-0x3F */ - 0xDF, 0xB2, 0x00, 0x00, 0xDF, 0xCB, 0xDF, 0xC3, /* 0x40-0x43 */ - 0xDF, 0xDC, 0xDF, 0xC6, 0xB8, 0xB6, 0xDF, 0xD7, /* 0x44-0x47 */ - 0x00, 0x00, 0xB8, 0xAD, 0x00, 0x00, 0xDF, 0xC9, /* 0x48-0x4B */ - 0xDF, 0xD1, 0xDF, 0xB6, 0xDF, 0xD0, 0x00, 0x00, /* 0x4C-0x4F */ - 0xDF, 0xE1, 0xDF, 0xB1, 0xDF, 0xD2, 0x00, 0x00, /* 0x50-0x53 */ - 0xDF, 0xDF, 0x00, 0x00, 0xDF, 0xAB, 0xB5, 0xDB, /* 0x54-0x57 */ - 0x00, 0x00, 0xDF, 0xB9, 0xDF, 0xB8, 0xB8, 0xAF, /* 0x58-0x5B */ - 0x00, 0x00, 0xDF, 0xBC, 0xDF, 0xBE, 0xDF, 0xCD, /* 0x5C-0x5F */ - 0xDF, 0xDE, 0xB8, 0xB2, 0x00, 0x00, 0xB8, 0xB3, /* 0x60-0x63 */ - 0x00, 0x00, 0xDF, 0xB0, 0xB8, 0xAB, 0xDF, 0xB4, /* 0x64-0x67 */ - 0xDF, 0xDA, 0xB8, 0xB4, 0x00, 0x00, 0xB8, 0xAC, /* 0x68-0x6B */ - 0xB8, 0xAE, 0xB8, 0xB5, 0xDF, 0xE0, 0xDF, 0xD3, /* 0x6C-0x6F */ - 0xDF, 0xCE, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xBB, /* 0x70-0x73 */ - 0xDF, 0xBA, 0xB8, 0xAA, 0xDF, 0xAC, 0xB8, 0xA7, /* 0x74-0x77 */ - 0xDF, 0xC4, 0xDF, 0xAD, 0xDF, 0xC2, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0xDF, 0xB7, 0xDF, 0xDB, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0xB8, 0xA6, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0xDF, 0xB3, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0xDF, 0xAF, 0xDF, 0xD5, 0xDF, 0xAE, /* 0x8C-0x8F */ - 0xBB, 0x60, 0xE3, 0xD3, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xE3, 0xC2, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xAC, /* 0x94-0x97 */ - 0xE3, 0xCA, 0xBB, 0x58, 0xE3, 0xBB, 0xE3, 0xC5, /* 0x98-0x9B */ - 0xBB, 0x5B, 0xE3, 0xBE, 0xBB, 0x59, 0xE3, 0xAF, /* 0x9C-0x9F */ - 0xE3, 0xCD, 0xE3, 0xAE, 0xE3, 0xC1, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xE3, 0xAD, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xBF, /* 0xA4-0xA7 */ - 0xE3, 0xC8, 0xE3, 0xC6, 0xE3, 0xBA, 0xE3, 0xB5, /* 0xA8-0xAB */ - 0xE3, 0xB3, 0x00, 0x00, 0xE3, 0xB4, 0xE3, 0xC7, /* 0xAC-0xAF */ - 0xE3, 0xD2, 0xE3, 0xBC, 0xBB, 0x5A, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xE3, 0xB7, 0x00, 0x00, 0xE3, 0xCB, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xBB, 0x5D, 0xE3, 0xB6, 0xE3, 0xB0, 0xE3, 0xC0, /* 0xB8-0xBB */ - 0xBB, 0x61, 0x00, 0x00, 0x00, 0x00, 0xBB, 0x55, /* 0xBC-0xBF */ - 0xBB, 0x5E, 0xE3, 0xB8, 0xE3, 0xB2, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xBB, 0x57, 0xDF, 0xD4, 0xBB, 0x56, 0xE3, 0xC3, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xBB, 0x54, 0xBB, 0x63, 0xBB, 0x5C, /* 0xC8-0xCB */ - 0xE3, 0xC4, 0xE3, 0xB9, 0xE3, 0xB1, 0xE3, 0xCC, /* 0xCC-0xCF */ - 0xE3, 0xBD, 0xBB, 0x62, 0xE3, 0xD0, 0xBB, 0x5F, /* 0xD0-0xD3 */ - 0xE3, 0xCF, 0x00, 0x00, 0xE3, 0xC9, 0xE3, 0xCE, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xD1, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x73, /* 0xE4-0xE7 */ - 0xE7, 0x74, 0xE7, 0x67, 0xE7, 0x66, 0xE7, 0x62, /* 0xE8-0xEB */ - 0xBD, 0xB4, 0x00, 0x00, 0xBD, 0xAC, 0xE7, 0x76, /* 0xEC-0xEF */ - 0xE7, 0x75, 0xDF, 0xA9, 0xE7, 0x5F, 0xE7, 0x63, /* 0xF0-0xF3 */ - 0xE7, 0x5D, 0x00, 0x00, 0xE7, 0x70, 0xE7, 0x61, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xE7, 0x77, 0xE7, 0x5A, 0xE7, 0x58, /* 0xF8-0xFB */ - 0xE7, 0x64, 0xE7, 0x6E, 0xE7, 0x69, 0xBD, 0xB6, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_85[512] = { - 0xE7, 0x4F, 0x00, 0x00, 0xE7, 0x6D, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xBD, 0xB7, 0xDF, 0xBD, /* 0x04-0x07 */ - 0xE7, 0x5B, 0xE7, 0x52, 0xE7, 0x55, 0xE7, 0x7B, /* 0x08-0x0B */ - 0xE7, 0x5C, 0xE7, 0x53, 0xE7, 0x51, 0xE7, 0x4E, /* 0x0C-0x0F */ - 0x00, 0x00, 0xBD, 0xB0, 0xE7, 0x65, 0xBD, 0xAF, /* 0x10-0x13 */ - 0xBD, 0xB3, 0xE7, 0x60, 0xE7, 0x68, 0xBD, 0xA9, /* 0x14-0x17 */ - 0xE7, 0x78, 0xE7, 0x7C, 0xBD, 0xAB, 0x00, 0x00, /* 0x18-0x1B */ - 0xE7, 0x57, 0xE7, 0x6B, 0xE7, 0x6F, 0xE7, 0x54, /* 0x1C-0x1F */ - 0xE7, 0x79, 0xBD, 0xB2, 0x00, 0x00, 0xBD, 0xB1, /* 0x20-0x23 */ - 0xE7, 0x4C, 0xBD, 0xB5, 0xE7, 0x72, 0xE7, 0x56, /* 0x24-0x27 */ - 0xE7, 0x6A, 0xE7, 0x50, 0xE7, 0x5E, 0xE7, 0x59, /* 0x28-0x2B */ - 0xBD, 0xAD, 0xBD, 0xAE, 0xE7, 0x6C, 0xE7, 0x7D, /* 0x2C-0x2F */ - 0xE7, 0x7A, 0xE7, 0x71, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x4D, /* 0x38-0x3B */ - 0x00, 0x00, 0xBD, 0xAA, 0xEB, 0x49, 0x00, 0x00, /* 0x3C-0x3F */ - 0xEB, 0x40, 0xEB, 0x43, 0x00, 0x00, 0xBF, 0xBB, /* 0x40-0x43 */ - 0xEB, 0x45, 0xEA, 0xF9, 0xEB, 0x41, 0xEB, 0x47, /* 0x44-0x47 */ - 0xBF, 0xB8, 0xBF, 0xBC, 0xBF, 0xB6, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0xEA, 0xFB, 0xEB, 0x4C, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0xEB, 0x46, 0x00, 0x00, 0xEA, 0xFC, /* 0x50-0x53 */ - 0xEB, 0x55, 0xEB, 0x4F, 0xEA, 0xF8, 0xEE, 0x46, /* 0x54-0x57 */ - 0xEA, 0xFE, 0xBF, 0xB7, 0x00, 0x00, 0xEB, 0x4A, /* 0x58-0x5B */ - 0x00, 0x00, 0xEB, 0x54, 0xBF, 0xBF, 0x00, 0x00, /* 0x5C-0x5F */ - 0xEB, 0x51, 0xEA, 0xFD, 0xEB, 0x44, 0xEB, 0x48, /* 0x60-0x63 */ - 0xEB, 0x42, 0xEB, 0x56, 0xEB, 0x53, 0xEB, 0x50, /* 0x64-0x67 */ - 0xBF, 0xB9, 0xBF, 0xBA, 0xBF, 0xBE, 0xEA, 0xFA, /* 0x68-0x6B */ - 0xEB, 0x57, 0xBF, 0xBD, 0xEB, 0x4D, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0xEB, 0x4B, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xEB, 0x4E, 0xEE, 0x53, 0xEE, 0x40, /* 0x74-0x77 */ - 0xEE, 0x45, 0xEE, 0x52, 0xEE, 0x44, 0xED, 0xFB, /* 0x78-0x7B */ - 0xEE, 0x41, 0x00, 0x00, 0xC1, 0xA2, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xED, 0xF4, 0xEE, 0x4D, 0xEE, 0x4F, 0xED, 0xF3, /* 0x80-0x83 */ - 0xC1, 0xA1, 0xEE, 0x51, 0xEE, 0x49, 0xC1, 0xA8, /* 0x84-0x87 */ - 0xEE, 0x50, 0xEE, 0x42, 0xC1, 0xAA, 0xED, 0xF9, /* 0x88-0x8B */ - 0xEB, 0x52, 0xEE, 0x4A, 0xEE, 0x47, 0xED, 0xF5, /* 0x8C-0x8F */ - 0xEE, 0x55, 0xC1, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xC1, 0xA5, 0xED, 0xF7, 0xEE, 0x48, 0x00, 0x00, /* 0x94-0x97 */ - 0xEE, 0x54, 0xEE, 0x4B, 0xED, 0xFD, 0xC1, 0xA7, /* 0x98-0x9B */ - 0xC1, 0xA3, 0xEE, 0x4C, 0xED, 0xFE, 0xEE, 0x56, /* 0x9C-0x9F */ - 0xED, 0xF8, 0xEE, 0x43, 0xEE, 0x4E, 0xED, 0xFA, /* 0xA0-0xA3 */ - 0xED, 0xFC, 0x00, 0x00, 0xC2, 0xCB, 0xED, 0xF6, /* 0xA4-0xA7 */ - 0xC1, 0xA9, 0xC2, 0xC4, 0xC1, 0x7E, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC1, 0xA6, /* 0xAC-0xAF */ - 0xC2, 0xC8, 0xF0, 0xB3, 0x00, 0x00, 0xF0, 0xA9, /* 0xB0-0xB3 */ - 0xF0, 0xA4, 0xF0, 0xAA, 0xF0, 0xB4, 0xF0, 0xB8, /* 0xB4-0xB7 */ - 0xF0, 0xB7, 0xC2, 0xCA, 0xC2, 0xC9, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xF0, 0xAB, 0xF0, 0xB9, 0xF0, 0xAE, /* 0xBC-0xBF */ - 0xF0, 0xA6, 0x00, 0x00, 0xF0, 0xA8, 0xF0, 0xA7, /* 0xC0-0xC3 */ - 0xF0, 0xAD, 0xF0, 0xB2, 0xF0, 0xA5, 0xF0, 0xAC, /* 0xC4-0xC7 */ - 0xF0, 0xB1, 0xC2, 0xC7, 0x00, 0x00, 0xF0, 0xAF, /* 0xC8-0xCB */ - 0x00, 0x00, 0xC2, 0xC5, 0xF0, 0xB0, 0xC2, 0xC3, /* 0xCC-0xCF */ - 0xC2, 0xC6, 0xF2, 0xD5, 0xF0, 0xB5, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xC3, 0xC2, 0x00, 0x00, 0xF2, 0xCD, /* 0xD4-0xD7 */ - 0xF2, 0xD1, 0xF2, 0xC9, 0xF2, 0xCC, 0x00, 0x00, /* 0xD8-0xDB */ - 0xF2, 0xD4, 0xC3, 0xC0, 0xF2, 0xD9, 0xF2, 0xD2, /* 0xDC-0xDF */ - 0x00, 0x00, 0xF2, 0xCA, 0xF2, 0xDA, 0xF2, 0xD3, /* 0xE0-0xE3 */ - 0xC3, 0xC3, 0xC3, 0xC4, 0xF2, 0xD7, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xF2, 0xCB, 0xC3, 0xBF, 0xC3, 0xC1, 0xF2, 0xC6, /* 0xE8-0xEB */ - 0xF2, 0xCE, 0xF2, 0xC8, 0x00, 0x00, 0xF2, 0xD8, /* 0xEC-0xEF */ - 0xF2, 0xD6, 0xF2, 0xC7, 0xF2, 0xCF, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xF4, 0xBE, 0xC3, 0xC5, /* 0xF4-0xF7 */ - 0xF2, 0xD0, 0xC4, 0xA7, 0xC4, 0xA9, 0xC4, 0xA6, /* 0xF8-0xFB */ - 0x00, 0x00, 0xF4, 0xC3, 0xF4, 0xBB, 0xF4, 0xB9, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_86[512] = { - 0xF4, 0xBD, 0xF4, 0xBA, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0xF4, 0xBF, 0xF4, 0xC1, 0xC4, 0xAA, 0xC4, 0xAC, /* 0x04-0x07 */ - 0x00, 0x00, 0xF4, 0xC0, 0xC4, 0xAD, 0xC4, 0xAB, /* 0x08-0x0B */ - 0xF4, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0xC4, 0xA8, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC4, 0xF4, /* 0x14-0x17 */ - 0xF5, 0xF1, 0xF5, 0xF7, 0xC4, 0xF6, 0xF4, 0xBC, /* 0x18-0x1B */ - 0xF5, 0xF6, 0x00, 0x00, 0xF5, 0xFD, 0xF5, 0xF4, /* 0x1C-0x1F */ - 0xF5, 0xFB, 0xF5, 0xFA, 0xF4, 0xB8, 0xF5, 0xF5, /* 0x20-0x23 */ - 0xF0, 0xB6, 0xF5, 0xFE, 0xF5, 0xF3, 0xF5, 0xF8, /* 0x24-0x27 */ - 0x00, 0x00, 0xF5, 0xFC, 0xF5, 0xF2, 0x00, 0x00, /* 0x28-0x2B */ - 0xF7, 0x4A, 0xC4, 0xF5, 0xF5, 0xF9, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xF7, 0xF4, 0xF7, 0x4B, 0xF7, 0x49, /* 0x30-0x33 */ - 0xF7, 0x47, 0xF7, 0x48, 0xF7, 0x4C, 0x00, 0x00, /* 0x34-0x37 */ - 0xC5, 0xD9, 0xF7, 0xF2, 0xF7, 0xF0, 0xF7, 0xF5, /* 0x38-0x3B */ - 0xF7, 0xF3, 0x00, 0x00, 0xF7, 0xF6, 0xC5, 0xDA, /* 0x3C-0x3F */ - 0xF7, 0xF1, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xBC, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xF9, 0x45, 0xF9, 0x46, /* 0x44-0x47 */ - 0xF9, 0x47, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xC7, /* 0x48-0x4B */ - 0xF9, 0xBD, 0xCA, 0x4F, 0xAA, 0xEA, 0x00, 0x00, /* 0x4C-0x4F */ - 0xAD, 0x68, 0x00, 0x00, 0xD3, 0xB8, 0xD3, 0xB7, /* 0x50-0x53 */ - 0xB0, 0x40, 0xB3, 0x42, 0xD7, 0x7C, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0xD7, 0x7B, 0x00, 0x00, 0xB5, 0xEA, /* 0x58-0x5B */ - 0xB8, 0xB8, 0x00, 0x00, 0xB8, 0xB7, 0xB8, 0xB9, /* 0x5C-0x5F */ - 0x00, 0x00, 0xE3, 0xD4, 0xE7, 0x7E, 0xEB, 0x58, /* 0x60-0x63 */ - 0xEB, 0x5A, 0xEB, 0x59, 0x00, 0x00, 0xC1, 0xAB, /* 0x64-0x67 */ - 0xEE, 0x57, 0xF0, 0xBA, 0xF9, 0xA5, 0xA6, 0xE4, /* 0x68-0x6B */ - 0x00, 0x00, 0xCD, 0xC9, 0xCD, 0xCA, 0xCD, 0xC8, /* 0x6C-0x6F */ - 0xCD, 0xC7, 0xAA, 0xEB, 0x00, 0x00, 0xD0, 0xA9, /* 0x70-0x73 */ - 0xD0, 0xA7, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xA6, /* 0x74-0x77 */ - 0x00, 0x00, 0xAD, 0x69, 0xAD, 0x6B, 0xAD, 0x6A, /* 0x78-0x7B */ - 0xD0, 0xA8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0xD3, 0xC4, 0xD3, 0xC1, 0xD3, 0xBF, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0xB0, 0x41, 0xD3, 0xC2, /* 0x88-0x8B */ - 0xB0, 0x46, 0xD3, 0xBC, 0xD3, 0xCB, 0x00, 0x00, /* 0x8C-0x8F */ - 0xD3, 0xCD, 0xD3, 0xBD, 0x00, 0x00, 0xB0, 0x43, /* 0x90-0x93 */ - 0xD3, 0xCE, 0xD3, 0xC9, 0xD3, 0xBB, 0xD3, 0xC0, /* 0x94-0x97 */ - 0xD3, 0xCA, 0xD3, 0xC6, 0xD3, 0xC3, 0x00, 0x00, /* 0x98-0x9B */ - 0xB0, 0x48, 0xD3, 0xCC, 0xD3, 0xBE, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xD3, 0xC7, 0xD3, 0xB9, 0xB0, 0x47, /* 0xA0-0xA3 */ - 0xB0, 0x44, 0xD3, 0xC5, 0x00, 0x00, 0xD3, 0xC8, /* 0xA4-0xA7 */ - 0xD3, 0xBA, 0xB0, 0x45, 0xB0, 0x42, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB3, 0x4C, /* 0xAC-0xAF */ - 0xD7, 0xA5, 0xB3, 0x4B, 0x00, 0x00, 0xD7, 0xA8, /* 0xB0-0xB3 */ - 0xD7, 0xAB, 0xB3, 0x48, 0xB3, 0x46, 0xD7, 0x7E, /* 0xB4-0xB7 */ - 0xD7, 0xA9, 0xD7, 0xA7, 0xD7, 0xA4, 0xD7, 0xAC, /* 0xB8-0xBB */ - 0xD7, 0xAD, 0xD7, 0xAF, 0xD7, 0xB0, 0xD7, 0x7D, /* 0xBC-0xBF */ - 0xB3, 0x45, 0xD7, 0xA2, 0xD7, 0xA1, 0xD7, 0xAE, /* 0xC0-0xC3 */ - 0xB3, 0x47, 0xD7, 0xA3, 0xB3, 0x49, 0xB3, 0x44, /* 0xC4-0xC7 */ - 0xD7, 0xA6, 0xB3, 0x4D, 0x00, 0x00, 0xB3, 0x4A, /* 0xC8-0xCB */ - 0xD7, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0xB5, 0xF1, 0xDB, 0xBF, 0x00, 0x00, 0xDB, 0xB4, /* 0xD0-0xD3 */ - 0xB5, 0xEE, 0x00, 0x00, 0xDF, 0xE7, 0xDB, 0xBD, /* 0xD4-0xD7 */ - 0xDB, 0xB1, 0xB5, 0xEC, 0xDB, 0xB6, 0xB5, 0xEF, /* 0xD8-0xDB */ - 0xDB, 0xBA, 0xDB, 0xB8, 0xB5, 0xF2, 0xB5, 0xEB, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xB2, 0xDB, 0xB5, /* 0xE0-0xE3 */ - 0xB5, 0xF0, 0x00, 0x00, 0xDB, 0xB3, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xDB, 0xBE, 0xDB, 0xBC, 0xDB, 0xB7, 0xDB, 0xB9, /* 0xE8-0xEB */ - 0xDB, 0xBB, 0xB5, 0xED, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xDF, 0xE8, 0xDF, 0xEE, 0xDF, 0xE4, /* 0xF4-0xF7 */ - 0xDF, 0xEA, 0xB8, 0xBA, 0xDF, 0xE6, 0xB8, 0xC0, /* 0xF8-0xFB */ - 0x00, 0x00, 0x00, 0x00, 0xB8, 0xBF, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_87[512] = { - 0xB8, 0xBE, 0xDF, 0xED, 0xB8, 0xC1, 0xB8, 0xC2, /* 0x00-0x03 */ - 0xDF, 0xE3, 0xDF, 0xF0, 0xB8, 0xC3, 0xB8, 0xBD, /* 0x04-0x07 */ - 0xB8, 0xBC, 0xDF, 0xEC, 0xB8, 0xC4, 0xDF, 0xE2, /* 0x08-0x0B */ - 0xDF, 0xE5, 0xDF, 0xEF, 0xDF, 0xEB, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0xE3, 0xF4, 0xE3, 0xE9, 0xB8, 0xBB, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0xBB, 0x6A, 0xE3, 0xDD, 0xE3, 0xF2, 0xE3, 0xDE, /* 0x18-0x1B */ - 0xBB, 0x65, 0x00, 0x00, 0xE3, 0xDB, 0x00, 0x00, /* 0x1C-0x1F */ - 0xE3, 0xE4, 0xE3, 0xDC, 0xBB, 0x67, 0xE3, 0xD6, /* 0x20-0x23 */ - 0xE3, 0xF1, 0xBB, 0x68, 0xE3, 0xEE, 0xE3, 0xEF, /* 0x24-0x27 */ - 0xE3, 0xD7, 0xBB, 0x6D, 0xE3, 0xE6, 0x00, 0x00, /* 0x28-0x2B */ - 0xE3, 0xE0, 0xE3, 0xE7, 0xE3, 0xDA, 0x00, 0x00, /* 0x2C-0x2F */ - 0xE3, 0xF3, 0xE3, 0xEB, 0xE3, 0xE5, 0xE3, 0xD5, /* 0x30-0x33 */ - 0xBB, 0x69, 0xE3, 0xEC, 0x00, 0x00, 0xBB, 0x6C, /* 0x34-0x37 */ - 0xE3, 0xF0, 0x00, 0x00, 0xE3, 0xEA, 0xBB, 0x66, /* 0x38-0x3B */ - 0xE3, 0xE8, 0x00, 0x00, 0xE3, 0xE2, 0xBB, 0x64, /* 0x3C-0x3F */ - 0xE3, 0xD9, 0xE3, 0xE1, 0xE3, 0xED, 0xE3, 0xDF, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xE3, 0xE3, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0xBD, 0xC1, 0xDF, 0xE9, 0xE7, 0xB2, 0xE7, 0xBB, /* 0x4C-0x4F */ - 0xE7, 0xB1, 0xE7, 0xAD, 0xE7, 0xAA, 0xBD, 0xC2, /* 0x50-0x53 */ - 0xE7, 0xA8, 0xBB, 0x6B, 0xE7, 0xA1, 0xBD, 0xC0, /* 0x54-0x57 */ - 0xE7, 0xA7, 0xBD, 0xBF, 0xE7, 0xAC, 0xE7, 0xA9, /* 0x58-0x5B */ - 0xE7, 0xB9, 0xE7, 0xB4, 0xE7, 0xAE, 0xE7, 0xB3, /* 0x5C-0x5F */ - 0xBD, 0xBB, 0xE7, 0xAB, 0xE7, 0xBE, 0xE7, 0xA2, /* 0x60-0x63 */ - 0xE7, 0xA3, 0xE7, 0xBA, 0xBD, 0xBC, 0xE7, 0xBF, /* 0x64-0x67 */ - 0xBD, 0xBE, 0xE7, 0xC0, 0xE7, 0xB0, 0xE3, 0xD8, /* 0x68-0x6B */ - 0xE7, 0xB6, 0xE7, 0xAF, 0xE7, 0xB8, 0xE7, 0xB5, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xA6, /* 0x70-0x73 */ - 0xBD, 0xB9, 0xE7, 0xBD, 0xBD, 0xBA, 0xE7, 0xA4, /* 0x74-0x77 */ - 0xBD, 0xBD, 0xEB, 0x64, 0xE7, 0xB7, 0xE7, 0xBC, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xEB, 0x61, 0xBD, 0xB8, 0xBF, 0xC0, /* 0x80-0x83 */ - 0xEB, 0x6B, 0xEB, 0x67, 0x00, 0x00, 0xEB, 0x65, /* 0x84-0x87 */ - 0xEB, 0x60, 0xEB, 0x6F, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0xBF, 0xC4, 0x00, 0x00, 0xEB, 0x5C, /* 0x8C-0x8F */ - 0xEB, 0x68, 0xEB, 0x69, 0xEB, 0x5F, 0xEB, 0x5E, /* 0x90-0x93 */ - 0xEB, 0x6C, 0x00, 0x00, 0xEB, 0x62, 0xEB, 0x5D, /* 0x94-0x97 */ - 0xEB, 0x63, 0x00, 0x00, 0xEB, 0x6E, 0xEB, 0x5B, /* 0x98-0x9B */ - 0xEB, 0x6D, 0xEB, 0x6A, 0xBF, 0xC2, 0xBF, 0xC1, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0xBF, 0xC3, 0xEB, 0x66, /* 0xA0-0xA3 */ - 0xF0, 0xCB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0x59, 0xC1, 0xB1, /* 0xA8-0xAB */ - 0xEE, 0x5D, 0xEE, 0x5A, 0xEE, 0x61, 0xEE, 0x67, /* 0xAC-0xAF */ - 0xEE, 0x5C, 0x00, 0x00, 0xEE, 0x70, 0xC1, 0xAE, /* 0xB0-0xB3 */ - 0xEE, 0x6A, 0xEE, 0x5F, 0xEE, 0x6B, 0xEE, 0x66, /* 0xB4-0xB7 */ - 0xEE, 0x6D, 0xEE, 0x5E, 0xC1, 0xB3, 0xC1, 0xB2, /* 0xB8-0xBB */ - 0xEE, 0x60, 0xEE, 0x6E, 0xEE, 0x58, 0xEE, 0x6C, /* 0xBC-0xBF */ - 0xC1, 0xAC, 0x00, 0x00, 0xEE, 0x64, 0xEE, 0x63, /* 0xC0-0xC3 */ - 0xEE, 0x68, 0xEE, 0x5B, 0xC1, 0xB0, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xC1, 0xB4, 0xEE, 0x62, 0xEE, 0x69, 0xC1, 0xB5, /* 0xC8-0xCB */ - 0xEE, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xC1, 0xAD, 0xC1, 0xAF, 0xF0, 0xC7, /* 0xD0-0xD3 */ - 0xF0, 0xC5, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xCC, /* 0xD4-0xD7 */ - 0xF0, 0xC9, 0xF0, 0xCD, 0x00, 0x00, 0xF0, 0xBE, /* 0xD8-0xDB */ - 0xF0, 0xC6, 0xF0, 0xD1, 0xEE, 0x6F, 0xF0, 0xC2, /* 0xDC-0xDF */ - 0xC2, 0xCF, 0xE7, 0xA5, 0xF0, 0xBD, 0xF0, 0xCA, /* 0xE0-0xE3 */ - 0xF0, 0xC4, 0xF0, 0xC1, 0xF0, 0xBC, 0xF0, 0xBB, /* 0xE4-0xE7 */ - 0xF0, 0xD0, 0x00, 0x00, 0xF0, 0xC0, 0xF0, 0xBF, /* 0xE8-0xEB */ - 0xC2, 0xCD, 0xF0, 0xC8, 0x00, 0x00, 0xC2, 0xCC, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0xC2, 0xCE, 0xF0, 0xC3, /* 0xF0-0xF3 */ - 0xF0, 0xCF, 0x00, 0x00, 0xF2, 0xDE, 0xF2, 0xDF, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xC3, 0xC9, 0xF2, 0xDC, 0xC3, 0xC6, /* 0xF8-0xFB */ - 0xF2, 0xE4, 0x00, 0x00, 0xC3, 0xCA, 0xF2, 0xE6, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_88[512] = { - 0xF2, 0xDB, 0xF0, 0xCE, 0xF2, 0xE8, 0xF2, 0xDD, /* 0x00-0x03 */ - 0x00, 0x00, 0xC3, 0xC7, 0xF2, 0xE3, 0x00, 0x00, /* 0x04-0x07 */ - 0xF2, 0xE5, 0xF2, 0xE0, 0xF2, 0xE7, 0xF2, 0xE2, /* 0x08-0x0B */ - 0xF2, 0xE1, 0xC3, 0xC8, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xF4, 0xC5, 0xF4, 0xC6, 0x00, 0x00, 0xF4, 0xC8, /* 0x10-0x13 */ - 0xC4, 0xAE, 0xC4, 0xAF, 0xF4, 0xC9, 0xF4, 0xC7, /* 0x14-0x17 */ - 0x00, 0x00, 0xF4, 0xC4, 0x00, 0x00, 0xF6, 0x42, /* 0x18-0x1B */ - 0xF6, 0x45, 0xF6, 0x41, 0x00, 0x00, 0xC4, 0xFA, /* 0x1C-0x1F */ - 0xF6, 0x43, 0xC4, 0xF9, 0xC4, 0xF8, 0xC4, 0xF7, /* 0x20-0x23 */ - 0xF6, 0x44, 0xF7, 0x51, 0xF7, 0x4F, 0x00, 0x00, /* 0x24-0x27 */ - 0xF7, 0x4E, 0xF6, 0x40, 0xF7, 0x50, 0xF6, 0x46, /* 0x28-0x2B */ - 0xF7, 0x4D, 0x00, 0x00, 0xF7, 0xF9, 0xF7, 0xD7, /* 0x2C-0x2F */ - 0xF7, 0xF7, 0xC5, 0xDB, 0xF7, 0xF8, 0xF7, 0xFA, /* 0x30-0x33 */ - 0x00, 0x00, 0xF8, 0xBF, 0xC5, 0xFA, 0xF8, 0xBE, /* 0x34-0x37 */ - 0xF8, 0xBD, 0xC5, 0xFB, 0x00, 0x00, 0xC6, 0x5A, /* 0x38-0x3B */ - 0xF9, 0x6E, 0xF9, 0xA7, 0xF9, 0xA6, 0xF9, 0xA8, /* 0x3C-0x3F */ - 0xA6, 0xE5, 0xD0, 0xAA, 0x00, 0x00, 0xD3, 0xCF, /* 0x40-0x43 */ - 0xD3, 0xD0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0xDB, 0xC0, 0x00, 0x00, 0xF6, 0x47, 0xF8, 0xC0, /* 0x48-0x4B */ - 0xA6, 0xE6, 0xAD, 0x6C, 0xD0, 0xAB, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xD7, 0xB1, 0xB3, 0x4E, /* 0x50-0x53 */ - 0x00, 0x00, 0xDB, 0xC2, 0xDB, 0xC1, 0xB5, 0xF3, /* 0x54-0x57 */ - 0x00, 0x00, 0xB8, 0xC5, 0xE7, 0xC1, 0xBD, 0xC3, /* 0x58-0x5B */ - 0x00, 0x00, 0xBD, 0xC4, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0xBF, 0xC5, 0xC5, 0xFC, 0xA6, 0xE7, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xAC, /* 0x64-0x67 */ - 0xAA, 0xED, 0xD0, 0xAE, 0xD0, 0xAD, 0xAD, 0x6D, /* 0x68-0x6B */ - 0x00, 0x00, 0xD3, 0xD1, 0x00, 0x00, 0xD3, 0xD8, /* 0x6C-0x6F */ - 0xB0, 0x49, 0xD3, 0xD6, 0xD3, 0xD4, 0x00, 0x00, /* 0x70-0x73 */ - 0xD3, 0xDB, 0xD3, 0xD2, 0xD3, 0xD3, 0xB0, 0x4A, /* 0x74-0x77 */ - 0x00, 0x00, 0xB0, 0x4E, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xD3, 0xDC, 0xB0, 0x4D, 0xD3, 0xDA, 0xD3, 0xD7, /* 0x7C-0x7F */ - - 0xD3, 0xD5, 0xB0, 0x4B, 0xB0, 0x4C, 0xD3, 0xD9, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xB3, 0x50, 0xD7, 0xB2, 0x00, 0x00, 0xB3, 0x55, /* 0x88-0x8B */ - 0xD7, 0xC2, 0xB3, 0x54, 0xD7, 0xC4, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xD7, 0xB8, 0xB3, 0x52, 0xD7, 0xC3, /* 0x90-0x93 */ - 0x00, 0x00, 0xD7, 0xB3, 0xB3, 0x53, 0xD7, 0xBF, /* 0x94-0x97 */ - 0xD7, 0xBB, 0xD7, 0xBD, 0xD7, 0xB7, 0xD7, 0xBE, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xB3, 0x4F, 0xD7, 0xBA, /* 0x9C-0x9F */ - 0x00, 0x00, 0xD7, 0xB9, 0xD7, 0xB5, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xD7, 0xC0, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xBC, /* 0xA4-0xA7 */ - 0xD7, 0xB4, 0x00, 0x00, 0xD7, 0xB6, 0xB3, 0x51, /* 0xA8-0xAB */ - 0xD7, 0xC1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0xB5, 0xF6, 0xDB, 0xCD, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xDB, 0xC9, 0xDB, 0xCB, /* 0xB4-0xB7 */ - 0xDB, 0xC6, 0xDB, 0xC5, 0xDB, 0xC3, 0x00, 0x00, /* 0xB8-0xBB */ - 0xDB, 0xCA, 0xDB, 0xCC, 0xDB, 0xC8, 0x00, 0x00, /* 0xBC-0xBF */ - 0xDB, 0xC7, 0xB5, 0xF4, 0xB5, 0xF5, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xDB, 0xCF, 0xB8, 0xCD, 0xDF, 0xF2, /* 0xC8-0xCB */ - 0xDF, 0xF8, 0xDF, 0xF3, 0xDF, 0xF4, 0xF9, 0xD8, /* 0xCC-0xCF */ - 0xDF, 0xF9, 0x00, 0x00, 0xB8, 0xCF, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xB8, 0xC7, 0xB8, 0xCE, 0xDF, 0xF1, 0xDB, 0xC4, /* 0xD4-0xD7 */ - 0xB8, 0xCA, 0xB8, 0xC8, 0xDF, 0xF7, 0xDF, 0xF6, /* 0xD8-0xDB */ - 0xB8, 0xC9, 0xB8, 0xCB, 0xDF, 0xF5, 0xB8, 0xC6, /* 0xDC-0xDF */ - 0x00, 0x00, 0xB8, 0xCC, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0xF6, /* 0xE4-0xE7 */ - 0xBB, 0x74, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x42, /* 0xE8-0xEB */ - 0xE4, 0x41, 0x00, 0x00, 0xE3, 0xFB, 0xBB, 0x76, /* 0xEC-0xEF */ - 0xE4, 0x40, 0xE3, 0xF7, 0xE3, 0xF8, 0xBB, 0x6E, /* 0xF0-0xF3 */ - 0xBB, 0x70, 0x00, 0x00, 0xE3, 0xFD, 0xE3, 0xF5, /* 0xF4-0xF7 */ - 0xBB, 0x72, 0xBB, 0x71, 0xE3, 0xF9, 0xE3, 0xFE, /* 0xF8-0xFB */ - 0xE3, 0xFC, 0xBB, 0x73, 0xE3, 0xFA, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_89[512] = { - 0x00, 0x00, 0xDB, 0xCE, 0xBB, 0x6F, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xE7, 0xC2, 0xE7, 0xC9, 0xBD, 0xC6, /* 0x04-0x07 */ - 0x00, 0x00, 0xE7, 0xCD, 0xBD, 0xCA, 0xE7, 0xC5, /* 0x08-0x0B */ - 0xE7, 0xC3, 0x00, 0x00, 0xE7, 0xCC, 0x00, 0x00, /* 0x0C-0x0F */ - 0xBD, 0xC5, 0xE7, 0xCB, 0xBD, 0xC7, 0xBD, 0xC8, /* 0x10-0x13 */ - 0xE7, 0xC4, 0xBD, 0xC9, 0xE7, 0xCA, 0xE7, 0xC6, /* 0x14-0x17 */ - 0xE7, 0xC7, 0xE7, 0xC8, 0xBB, 0x75, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xEB, 0x70, 0xEB, 0x7C, /* 0x1C-0x1F */ - 0x00, 0x00, 0xBF, 0xCA, 0xEB, 0x77, 0xEB, 0x79, /* 0x20-0x23 */ - 0x00, 0x00, 0xBF, 0xC8, 0xEB, 0x71, 0xEB, 0x75, /* 0x24-0x27 */ - 0x00, 0x00, 0xEB, 0x78, 0xBF, 0xC6, 0xBF, 0xC9, /* 0x28-0x2B */ - 0xEB, 0x7B, 0xEB, 0x73, 0xEB, 0x74, 0xEB, 0x7A, /* 0x2C-0x2F */ - 0xEB, 0x72, 0xEB, 0x76, 0xBF, 0xC7, 0xEE, 0x72, /* 0x30-0x33 */ - 0x00, 0x00, 0xEE, 0x71, 0xC1, 0xB7, 0xEE, 0x77, /* 0x34-0x37 */ - 0xC1, 0xB9, 0x00, 0x00, 0x00, 0x00, 0xC1, 0xB6, /* 0x38-0x3B */ - 0xEE, 0x73, 0xC1, 0xBA, 0xEE, 0x74, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xEE, 0x75, 0xEE, 0x78, 0x00, 0x00, /* 0x40-0x43 */ - 0xC1, 0xB8, 0x00, 0x00, 0xF0, 0xD6, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xF0, 0xD9, 0x00, 0x00, 0xF0, 0xD3, /* 0x48-0x4B */ - 0xF0, 0xD5, 0x00, 0x00, 0x00, 0x00, 0xF0, 0xD4, /* 0x4C-0x4F */ - 0xF0, 0xD7, 0xF0, 0xD8, 0xEE, 0x76, 0xF0, 0xD2, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xC3, 0xCD, 0xF2, 0xEC, /* 0x54-0x57 */ - 0xF2, 0xEF, 0xF2, 0xF1, 0xF2, 0xEA, 0xF2, 0xEB, /* 0x58-0x5B */ - 0xF2, 0xEE, 0xF2, 0xF0, 0xC3, 0xCE, 0xC3, 0xCC, /* 0x5C-0x5F */ - 0xC3, 0xCB, 0xF2, 0xED, 0xF2, 0xE9, 0xF4, 0xCA, /* 0x60-0x63 */ - 0xC4, 0xB0, 0x00, 0x00, 0xF4, 0xCB, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0xF6, 0x49, 0xC4, 0xFB, 0xF6, 0x4B, /* 0x68-0x6B */ - 0xC4, 0xFC, 0xF6, 0x48, 0xF6, 0x4A, 0xC5, 0xA8, /* 0x6C-0x6F */ - 0x00, 0x00, 0xF7, 0x52, 0xC5, 0xA7, 0xF7, 0xFD, /* 0x70-0x73 */ - 0xF7, 0xFC, 0x00, 0x00, 0xF7, 0xFB, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xF9, 0x48, 0xF9, 0x49, 0xF9, 0x4B, /* 0x78-0x7B */ - 0xF9, 0x4A, 0x00, 0x00, 0xCA, 0x50, 0xA6, 0xE8, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xAD, 0x6E, 0xD7, 0xC5, 0xB5, 0xF7, /* 0x80-0x83 */ - 0x00, 0x00, 0xDF, 0xFA, 0xC2, 0xD0, 0x00, 0x00, /* 0x84-0x87 */ - 0xF2, 0xF2, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xA3, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB3, 0x57, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB3, 0x56, /* 0x90-0x93 */ - 0x00, 0x00, 0xDB, 0xD0, 0xB5, 0xF8, 0xDB, 0xD2, /* 0x94-0x97 */ - 0xDB, 0xD1, 0x00, 0x00, 0x00, 0x00, 0xDF, 0xFB, /* 0x98-0x9B */ - 0xB8, 0xD0, 0xE4, 0x43, 0xE4, 0x46, 0xE4, 0x45, /* 0x9C-0x9F */ - 0x00, 0x00, 0xE4, 0x44, 0xE7, 0xCE, 0xE7, 0xD0, /* 0xA0-0xA3 */ - 0xE7, 0xCF, 0x00, 0x00, 0xBF, 0xCC, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0xBF, 0xCB, 0x00, 0x00, /* 0xA8-0xAB */ - 0xC1, 0xBB, 0xEE, 0x79, 0xEE, 0x7B, 0xEE, 0x7A, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xC2, 0xD1, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xF2, 0xF4, 0xF2, 0xF3, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xF4, 0xCC, 0xC4, 0xB1, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xC4, 0xFD, 0xF7, 0x54, 0xF7, 0x53, /* 0xBC-0xBF */ - 0xC6, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0xA4, 0xD0, 0xAF, /* 0xD0-0xD3 */ - 0xAD, 0x6F, 0xD7, 0xC8, 0xD7, 0xC6, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xD7, 0xC7, 0xDB, 0xD4, 0xDB, 0xD5, /* 0xD8-0xDB */ - 0xE0, 0x43, 0xDB, 0xD3, 0x00, 0x00, 0xDF, 0xFC, /* 0xDC-0xDF */ - 0xE0, 0x41, 0xE0, 0x40, 0xE0, 0x42, 0xB8, 0xD1, /* 0xE0-0xE3 */ - 0xDF, 0xFE, 0xDF, 0xFD, 0xE0, 0x44, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xE4, 0x49, 0xE4, 0x47, 0x00, 0x00, 0xE4, 0x48, /* 0xE8-0xEB */ - 0xE7, 0xD3, 0xE7, 0xD1, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xE7, 0xD2, 0xEB, 0x7D, 0xEE, 0x7C, 0xEE, 0x7D, /* 0xF0-0xF3 */ - 0xC2, 0xD2, 0x00, 0x00, 0xF2, 0xF5, 0xF4, 0xCD, /* 0xF4-0xF7 */ - 0xC4, 0xB2, 0x00, 0x00, 0xF6, 0x4C, 0xF7, 0x55, /* 0xF8-0xFB */ - 0xC5, 0xA9, 0x00, 0x00, 0xF7, 0xFE, 0xF9, 0x4C, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_8A[512] = { - 0xA8, 0xA5, 0x00, 0x00, 0xAD, 0x71, 0xAD, 0x72, /* 0x00-0x03 */ - 0xD0, 0xB0, 0x00, 0x00, 0x00, 0x00, 0xD0, 0xB1, /* 0x04-0x07 */ - 0xAD, 0x70, 0x00, 0x00, 0xB0, 0x54, 0x00, 0x00, /* 0x08-0x0B */ - 0xB0, 0x52, 0x00, 0x00, 0xB0, 0x51, 0xB0, 0x58, /* 0x0C-0x0F */ - 0xB0, 0x50, 0xB0, 0x59, 0xD3, 0xDD, 0xB0, 0x56, /* 0x10-0x13 */ - 0x00, 0x00, 0xB0, 0x53, 0xB0, 0x57, 0xB0, 0x55, /* 0x14-0x17 */ - 0xB0, 0x4F, 0x00, 0x00, 0x00, 0x00, 0xB3, 0x5F, /* 0x18-0x1B */ - 0x00, 0x00, 0xB3, 0x59, 0xD7, 0xCC, 0xB3, 0x5E, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0xB3, 0x60, 0xB3, 0x5A, /* 0x20-0x23 */ - 0x00, 0x00, 0xB3, 0x5B, 0x00, 0x00, 0xD7, 0xCA, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xB3, 0x58, 0x00, 0x00, /* 0x28-0x2B */ - 0xD7, 0xCB, 0xB3, 0x5D, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xD7, 0xC9, 0xB3, 0x5C, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0xB6, 0x44, 0x00, 0x00, 0xB6, 0x46, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0xDB, 0xD8, 0xB6, 0x45, 0xB5, 0xF9, /* 0x38-0x3B */ - 0xB5, 0xFD, 0x00, 0x00, 0xB8, 0xE4, 0xE0, 0x49, /* 0x3C-0x3F */ - 0xDB, 0xDA, 0xB5, 0xFE, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xDB, 0xDD, 0xDB, 0xDE, 0xB6, 0x43, 0x00, 0x00, /* 0x44-0x47 */ - 0xDB, 0xE0, 0x00, 0x00, 0xDB, 0xE2, 0x00, 0x00, /* 0x48-0x4B */ - 0xDB, 0xE3, 0xDB, 0xD7, 0xDB, 0xD6, 0xDB, 0xE4, /* 0x4C-0x4F */ - 0xB6, 0x42, 0xDB, 0xE1, 0xDB, 0xDF, 0x00, 0x00, /* 0x50-0x53 */ - 0xB6, 0x40, 0xB5, 0xFB, 0xB6, 0x47, 0xDB, 0xDB, /* 0x54-0x57 */ - 0xDB, 0xDC, 0xDB, 0xD9, 0x00, 0x00, 0xB6, 0x41, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xB5, 0xFC, 0x00, 0x00, /* 0x5C-0x5F */ - 0xB5, 0xFA, 0xE0, 0x48, 0xB8, 0xDF, 0xB8, 0xDA, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xB8, 0xD5, 0x00, 0x00, /* 0x64-0x67 */ - 0xB8, 0xE5, 0xB8, 0xD6, 0x00, 0x00, 0xB8, 0xD2, /* 0x68-0x6B */ - 0xB8, 0xE1, 0xB8, 0xDE, 0xB8, 0xE0, 0x00, 0x00, /* 0x6C-0x6F */ - 0xB8, 0xD7, 0xB8, 0xDC, 0xB8, 0xD3, 0xB8, 0xD4, /* 0x70-0x73 */ - 0xE0, 0x50, 0xE0, 0x4D, 0xE0, 0x45, 0xE0, 0x4A, /* 0x74-0x77 */ - 0x00, 0x00, 0xB8, 0xE2, 0xE0, 0x51, 0xB8, 0xE3, /* 0x78-0x7B */ - 0xB8, 0xD9, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x47, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xE0, 0x4F, 0xE0, 0x4B, 0xE0, 0x4E, /* 0x80-0x83 */ - 0xE0, 0x4C, 0xB8, 0xDD, 0xE0, 0x46, 0xB8, 0xD8, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x4C, /* 0x88-0x8B */ - 0xBB, 0x78, 0xBB, 0x7B, 0x00, 0x00, 0xE4, 0x4E, /* 0x8C-0x8F */ - 0x00, 0x00, 0xBB, 0xA5, 0xE4, 0x4D, 0xBB, 0x7D, /* 0x90-0x93 */ - 0x00, 0x00, 0xBD, 0xCF, 0xE4, 0x4F, 0x00, 0x00, /* 0x94-0x97 */ - 0xBB, 0xA4, 0xE4, 0x4B, 0xBB, 0xA6, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xBB, 0x79, 0x00, 0x00, /* 0x9C-0x9F */ - 0xB8, 0xDB, 0xBB, 0x7C, 0x00, 0x00, 0xBB, 0x7A, /* 0xA0-0xA3 */ - 0xBB, 0x7E, 0xBB, 0xA2, 0xBB, 0x77, 0xBB, 0xA7, /* 0xA4-0xA7 */ - 0xBB, 0xA3, 0x00, 0x00, 0xBB, 0xA1, 0xE4, 0x4A, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0xBD, 0xD6, 0x00, 0x00, 0xBD, 0xD2, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xBD, 0xD9, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xE7, 0xD6, 0xBD, 0xDA, 0xE7, 0xE2, 0xE7, 0xDB, /* 0xB8-0xBB */ - 0xBD, 0xCB, 0xE7, 0xE3, 0xE7, 0xDD, 0xBD, 0xD5, /* 0xBC-0xBF */ - 0xE7, 0xDE, 0x00, 0x00, 0xBD, 0xD4, 0xE7, 0xE1, /* 0xC0-0xC3 */ - 0xBD, 0xCE, 0xE7, 0xDF, 0xE7, 0xD5, 0xBD, 0xCD, /* 0xC4-0xC7 */ - 0xEB, 0xAA, 0xBD, 0xD3, 0x00, 0x00, 0xBD, 0xD0, /* 0xC8-0xCB */ - 0x00, 0x00, 0xBD, 0xD8, 0x00, 0x00, 0xE7, 0xD4, /* 0xCC-0xCF */ - 0x00, 0x00, 0xE7, 0xD8, 0xBD, 0xCC, 0xE7, 0xD7, /* 0xD0-0xD3 */ - 0xE7, 0xD9, 0xE7, 0xDA, 0xBD, 0xD7, 0xE7, 0xDC, /* 0xD4-0xD7 */ - 0xE7, 0xE0, 0xE7, 0xE4, 0x00, 0x00, 0xBD, 0xDB, /* 0xD8-0xDB */ - 0xBF, 0xD2, 0xEB, 0xA5, 0xEB, 0xAB, 0xEB, 0xA8, /* 0xDC-0xDF */ - 0xEB, 0x7E, 0xEB, 0xAC, 0xEB, 0xA1, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xEB, 0xA7, 0x00, 0x00, 0xBF, 0xCD, 0xBF, 0xD3, /* 0xE4-0xE7 */ - 0xEB, 0xAD, 0x00, 0x00, 0x00, 0x00, 0xBF, 0xCF, /* 0xE8-0xEB */ - 0x00, 0x00, 0xBF, 0xD9, 0xBF, 0xD4, 0xEB, 0xAF, /* 0xEC-0xEF */ - 0xEB, 0xA9, 0xBF, 0xD0, 0xEB, 0xA2, 0xBF, 0xDA, /* 0xF0-0xF3 */ - 0xEB, 0xA3, 0xEB, 0xA4, 0xBF, 0xDB, 0xBF, 0xD8, /* 0xF4-0xF7 */ - 0xBD, 0xD1, 0x00, 0x00, 0xBF, 0xCE, 0xEB, 0xB0, /* 0xF8-0xFB */ - 0xBF, 0xDC, 0x00, 0x00, 0xBF, 0xD5, 0xEB, 0xAE, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_8B[512] = { - 0xBF, 0xD1, 0xBF, 0xD6, 0xBF, 0xD7, 0x00, 0x00, /* 0x00-0x03 */ - 0xC1, 0xC3, 0xEE, 0xA4, 0xEE, 0xAD, 0xEE, 0xAA, /* 0x04-0x07 */ - 0xEE, 0xAC, 0x00, 0x00, 0xC1, 0xC0, 0xEE, 0xA5, /* 0x08-0x0B */ - 0x00, 0x00, 0xEE, 0xAB, 0xC1, 0xBC, 0xEE, 0xA7, /* 0x0C-0x0F */ - 0xC1, 0xC4, 0xEE, 0xA3, 0xEE, 0xA8, 0xEE, 0xAF, /* 0x10-0x13 */ - 0xEB, 0xA6, 0xEE, 0xA9, 0xEE, 0xA2, 0xC1, 0xBD, /* 0x14-0x17 */ - 0xEE, 0xA1, 0xC1, 0xBE, 0xEE, 0xB0, 0xC1, 0xBF, /* 0x18-0x1B */ - 0xEE, 0xAE, 0xC1, 0xC2, 0xEE, 0x7E, 0x00, 0x00, /* 0x1C-0x1F */ - 0xC1, 0xC1, 0x00, 0x00, 0xEE, 0xA6, 0xF0, 0xDC, /* 0x20-0x23 */ - 0xF0, 0xEA, 0xF0, 0xE5, 0xF0, 0xE7, 0xF0, 0xDB, /* 0x24-0x27 */ - 0xC2, 0xD3, 0x00, 0x00, 0xF0, 0xDA, 0xC2, 0xD6, /* 0x28-0x2B */ - 0xC2, 0xD5, 0x00, 0x00, 0xF0, 0xE9, 0xF0, 0xE1, /* 0x2C-0x2F */ - 0xF0, 0xDE, 0xF0, 0xE4, 0x00, 0x00, 0xF0, 0xDD, /* 0x30-0x33 */ - 0x00, 0x00, 0xF0, 0xDF, 0xF0, 0xE8, 0xF0, 0xE6, /* 0x34-0x37 */ - 0x00, 0x00, 0xC2, 0xD4, 0xF0, 0xED, 0xF0, 0xEB, /* 0x38-0x3B */ - 0xF0, 0xE2, 0xF0, 0xEC, 0xF0, 0xE3, 0x00, 0x00, /* 0x3C-0x3F */ - 0xF2, 0xF9, 0xC3, 0xCF, 0xF3, 0x41, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0xF6, 0x4F, 0xC3, 0xD6, 0xF0, 0xE0, /* 0x44-0x47 */ - 0xF2, 0xF7, 0xC3, 0xD2, 0xF2, 0xF8, 0xF2, 0xFD, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0xC3, 0xD4, 0xC3, 0xD5, /* 0x4C-0x4F */ - 0xF2, 0xF6, 0xF3, 0x40, 0xF3, 0x42, 0xF2, 0xFA, /* 0x50-0x53 */ - 0xF2, 0xFC, 0xF2, 0xFE, 0xF2, 0xFB, 0xF3, 0x43, /* 0x54-0x57 */ - 0xC3, 0xD1, 0xC3, 0xD7, 0xC3, 0xD3, 0x00, 0x00, /* 0x58-0x5B */ - 0xC3, 0xD0, 0xF4, 0xD0, 0x00, 0x00, 0xC4, 0xB7, /* 0x5C-0x5F */ - 0xF4, 0xCE, 0x00, 0x00, 0x00, 0x00, 0xF4, 0xD2, /* 0x60-0x63 */ - 0x00, 0x00, 0xF4, 0xD3, 0xC4, 0xB5, 0xF4, 0xD4, /* 0x64-0x67 */ - 0xF4, 0xD1, 0x00, 0x00, 0xF4, 0xCF, 0xC4, 0xB8, /* 0x68-0x6B */ - 0xC4, 0xB4, 0xF4, 0xD5, 0x00, 0x00, 0xC4, 0xB6, /* 0x6C-0x6F */ - 0xC4, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xC4, 0xFE, 0x00, 0x00, 0x00, 0x00, 0xC5, 0x40, /* 0x74-0x77 */ - 0xF6, 0x4E, 0xF6, 0x4D, 0xF6, 0x50, 0xF6, 0x51, /* 0x78-0x7B */ - 0x00, 0x00, 0xC5, 0x41, 0xF7, 0x56, 0xF7, 0x5B, /* 0x7C-0x7F */ - - 0xC5, 0xAA, 0x00, 0x00, 0xF7, 0x58, 0x00, 0x00, /* 0x80-0x83 */ - 0xF7, 0x57, 0xF7, 0x5A, 0xF7, 0x59, 0x00, 0x00, /* 0x84-0x87 */ - 0xF8, 0x43, 0x00, 0x00, 0xC5, 0xDC, 0xF8, 0x42, /* 0x88-0x8B */ - 0xF8, 0x40, 0x00, 0x00, 0xF8, 0x41, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0xC5, 0xFE, 0xC5, 0xFD, /* 0x90-0x93 */ - 0xF8, 0xC1, 0xF8, 0xC2, 0xC6, 0x40, 0x00, 0x00, /* 0x94-0x97 */ - 0xF9, 0x4D, 0xF9, 0x4E, 0xC6, 0x67, 0x00, 0x00, /* 0x98-0x9B */ - 0xC6, 0x6D, 0x00, 0x00, 0xF9, 0xA9, 0xF9, 0xC8, /* 0x9C-0x9F */ -}; - -static const unsigned char u2c_8C[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xA6, /* 0x34-0x37 */ - 0x00, 0x00, 0xD7, 0xCD, 0x00, 0x00, 0xD7, 0xCE, /* 0x38-0x3B */ - 0xE0, 0x52, 0xE4, 0x50, 0xE7, 0xE5, 0xC1, 0xC6, /* 0x3C-0x3F */ - 0x00, 0x00, 0xC1, 0xC5, 0xF0, 0xEE, 0xF3, 0x44, /* 0x40-0x43 */ - 0x00, 0x00, 0xF8, 0x44, 0xA8, 0xA7, 0xD3, 0xDE, /* 0x44-0x47 */ - 0xB0, 0x5A, 0xB3, 0x61, 0xE0, 0x54, 0xE0, 0x53, /* 0x48-0x4B */ - 0xBD, 0xDC, 0xE7, 0xE6, 0xBD, 0xDD, 0xEE, 0xB1, /* 0x4C-0x4F */ - 0xC2, 0xD7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0xC6, 0x76, 0xA8, 0xA8, 0xCD, 0xCB, 0xD3, 0xDF, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xB3, 0x62, 0x00, 0x00, /* 0x58-0x5B */ - 0xD7, 0xCF, 0xD7, 0xD0, 0x00, 0x00, 0xDB, 0xE5, /* 0x5C-0x5F */ - 0x00, 0x00, 0xB6, 0x48, 0xB8, 0xE6, 0x00, 0x00, /* 0x60-0x63 */ - 0xE0, 0x56, 0xE0, 0x55, 0xE0, 0x57, 0x00, 0x00, /* 0x64-0x67 */ - 0xE4, 0x51, 0xE4, 0x52, 0xBB, 0xA8, 0xBF, 0xDD, /* 0x68-0x6B */ - 0xBD, 0xDE, 0xBF, 0xDE, 0x00, 0x00, 0xEE, 0xB5, /* 0x6C-0x6F */ - 0xEE, 0xB2, 0xEE, 0xB4, 0xEE, 0xB3, 0xC1, 0xC7, /* 0x70-0x73 */ - 0x00, 0x00, 0xF0, 0xEF, 0xF3, 0x46, 0xF3, 0x45, /* 0x74-0x77 */ - 0xCB, 0xA4, 0xB0, 0x5C, 0xB0, 0x5B, 0xD3, 0xE0, /* 0x78-0x7B */ - 0x00, 0x00, 0xD7, 0xD1, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xDB, 0xE7, 0xDB, 0xE6, 0xB6, 0x49, 0x00, 0x00, /* 0x80-0x83 */ - 0xE0, 0x59, 0xE0, 0x5A, 0xE0, 0x58, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0xB8, 0xE8, 0xB8, 0xE7, 0x00, 0x00, /* 0x88-0x8B */ - 0xBB, 0xAA, 0xBB, 0xA9, 0x00, 0x00, 0xE7, 0xE7, /* 0x8C-0x8F */ - 0xEB, 0xB3, 0xEB, 0xB1, 0xEB, 0xB2, 0xBF, 0xDF, /* 0x90-0x93 */ - 0xEE, 0xB7, 0xEE, 0xB6, 0x00, 0x00, 0xF0, 0xF2, /* 0x94-0x97 */ - 0xF0, 0xF1, 0xF0, 0xF0, 0xF3, 0x47, 0x00, 0x00, /* 0x98-0x9B */ - 0xF9, 0xAA, 0xA8, 0xA9, 0xAD, 0x73, 0x00, 0x00, /* 0x9C-0x9F */ - 0xAD, 0x74, 0xB0, 0x5D, 0xB0, 0x5E, 0xD3, 0xE2, /* 0xA0-0xA3 */ - 0xD3, 0xE1, 0xD7, 0xD2, 0x00, 0x00, 0xB3, 0x68, /* 0xA4-0xA7 */ - 0xB3, 0x66, 0xB3, 0x63, 0xB3, 0x67, 0xB3, 0x65, /* 0xA8-0xAB */ - 0xB3, 0x64, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x4A, /* 0xAC-0xAF */ - 0xDB, 0xEA, 0x00, 0x00, 0xB8, 0xED, 0xB6, 0x4C, /* 0xB0-0xB3 */ - 0xB6, 0x51, 0xDB, 0xEC, 0xB6, 0x53, 0xB6, 0x52, /* 0xB4-0xB7 */ - 0xB6, 0x55, 0xDB, 0xEB, 0xDB, 0xE8, 0xB6, 0x4F, /* 0xB8-0xBB */ - 0xB6, 0x4B, 0xB6, 0x4D, 0xDB, 0xE9, 0xB6, 0x54, /* 0xBC-0xBF */ - 0xB6, 0x50, 0xB6, 0x4E, 0xB8, 0xEF, 0xB8, 0xEE, /* 0xC0-0xC3 */ - 0xB8, 0xEC, 0xB8, 0xF0, 0x00, 0x00, 0xB8, 0xEA, /* 0xC4-0xC7 */ - 0xB8, 0xEB, 0x00, 0x00, 0xB8, 0xE9, 0x00, 0x00, /* 0xC8-0xCB */ - 0xE0, 0x5B, 0x00, 0x00, 0x00, 0x00, 0xE4, 0x54, /* 0xCC-0xCF */ - 0x00, 0x00, 0xBB, 0xAC, 0xBB, 0xAD, 0xBB, 0xAB, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xE4, 0x53, 0x00, 0x00, 0xE4, 0x55, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xE7, 0xEA, 0xE7, 0xEC, 0x00, 0x00, /* 0xD8-0xDB */ - 0xBD, 0xE7, 0xE7, 0xED, 0xBD, 0xE0, 0xE7, 0xE9, /* 0xDC-0xDF */ - 0xBD, 0xDF, 0xBD, 0xE9, 0xBD, 0xE5, 0xBD, 0xE6, /* 0xE0-0xE3 */ - 0xBD, 0xE2, 0xE7, 0xE8, 0xBD, 0xE1, 0xE7, 0xEE, /* 0xE4-0xE7 */ - 0xE7, 0xEB, 0x00, 0x00, 0xBD, 0xE8, 0x00, 0x00, /* 0xE8-0xEB */ - 0xBD, 0xE3, 0xBD, 0xE4, 0xEB, 0xB5, 0x00, 0x00, /* 0xEC-0xEF */ - 0xEB, 0xB7, 0xEB, 0xB6, 0x00, 0x00, 0xEB, 0xB8, /* 0xF0-0xF3 */ - 0xBF, 0xE0, 0xEB, 0xB4, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xC1, 0xCB, 0xEE, 0xB8, 0xC1, 0xC8, 0xC1, 0xCC, /* 0xF8-0xFB */ - 0xC1, 0xCA, 0xC1, 0xC9, 0xF0, 0xF3, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_8D[512] = { - 0xF0, 0xF6, 0x00, 0x00, 0xF0, 0xF5, 0x00, 0x00, /* 0x00-0x03 */ - 0xF0, 0xF4, 0xC2, 0xD8, 0xF3, 0x48, 0xF3, 0x49, /* 0x04-0x07 */ - 0xC3, 0xD8, 0xF3, 0x4A, 0xC3, 0xD9, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0xC4, 0xBA, 0x00, 0x00, 0xC4, 0xB9, /* 0x0C-0x0F */ - 0xF6, 0x52, 0x00, 0x00, 0x00, 0x00, 0xC5, 0x42, /* 0x10-0x13 */ - 0xF6, 0x53, 0xF7, 0x5C, 0xC5, 0xAB, 0xC5, 0xAC, /* 0x14-0x17 */ - 0x00, 0x00, 0xF8, 0x45, 0x00, 0x00, 0xC6, 0x42, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0xA8, 0xAA, 0x00, 0x00, 0xB3, 0x6A, 0xB3, 0x69, /* 0x64-0x67 */ - 0xE0, 0x5C, 0xE0, 0x5D, 0x00, 0x00, 0xBB, 0xAE, /* 0x68-0x6B */ - 0xEB, 0xB9, 0xBD, 0xEA, 0xEB, 0xBA, 0xEE, 0xB9, /* 0x6C-0x6F */ - 0xA8, 0xAB, 0x00, 0x00, 0xD0, 0xB2, 0xAD, 0x76, /* 0x70-0x73 */ - 0xAD, 0x75, 0x00, 0x00, 0xD3, 0xE3, 0xB0, 0x5F, /* 0x74-0x77 */ - 0xD3, 0xE4, 0xD7, 0xD5, 0x00, 0x00, 0xD7, 0xD4, /* 0x78-0x7B */ - 0x00, 0x00, 0xD7, 0xD3, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xDB, 0xEE, 0xB6, 0x58, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0xDB, 0xED, 0xB6, 0x57, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0xDB, 0xEF, 0xB6, 0x56, 0x00, 0x00, /* 0x88-0x8B */ - 0xE0, 0x5F, 0xE0, 0x62, 0xE0, 0x60, 0xE0, 0x61, /* 0x8C-0x8F */ - 0xE0, 0x65, 0xE0, 0x5E, 0xE0, 0x66, 0xE0, 0x63, /* 0x90-0x93 */ - 0xE0, 0x64, 0xBB, 0xB0, 0xE4, 0x56, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xBB, 0xAF, 0x00, 0x00, 0xE7, 0xF2, /* 0x98-0x9B */ - 0xE7, 0xF0, 0x00, 0x00, 0x00, 0x00, 0xBD, 0xEB, /* 0x9C-0x9F */ - 0xE7, 0xEF, 0xE7, 0xF1, 0x00, 0x00, 0xBD, 0xEC, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xEB, 0xBB, 0x00, 0x00, 0xEB, 0xBC, /* 0xA4-0xA7 */ - 0xC1, 0xCD, 0x00, 0x00, 0xF3, 0x4C, 0xF3, 0x4E, /* 0xA8-0xAB */ - 0xF3, 0x4B, 0xF3, 0x4D, 0xF4, 0xD6, 0xF6, 0x54, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xF9, 0x6F, 0xA8, 0xAC, /* 0xB0-0xB3 */ - 0xAD, 0x77, 0xD3, 0xE5, 0xD3, 0xE7, 0xD3, 0xE6, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xD7, 0xD8, 0xB3, 0x6C, 0x00, 0x00, /* 0xB8-0xBB */ - 0xD7, 0xD6, 0x00, 0x00, 0xB3, 0x6B, 0xD7, 0xD9, /* 0xBC-0xBF */ - 0x00, 0x00, 0xD7, 0xDA, 0xD7, 0xD7, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xDB, 0xFB, 0xB6, 0x60, 0xDB, 0xF3, /* 0xC4-0xC7 */ - 0xDB, 0xF9, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x5B, /* 0xC8-0xCB */ - 0xB6, 0x5E, 0xDB, 0xF2, 0xB6, 0x59, 0xDB, 0xF6, /* 0xCC-0xCF */ - 0xE0, 0x6C, 0xB6, 0x5D, 0x00, 0x00, 0xDB, 0xF1, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xDB, 0xF7, 0xDB, 0xF4, 0xDB, 0xFA, /* 0xD4-0xD7 */ - 0xDB, 0xF0, 0xDB, 0xF8, 0xB6, 0x5C, 0xB6, 0x5F, /* 0xD8-0xDB */ - 0xDB, 0xF5, 0xB6, 0x5A, 0x00, 0x00, 0xB8, 0xF2, /* 0xDC-0xDF */ - 0xE0, 0x68, 0xB8, 0xF1, 0xE0, 0x6F, 0xE0, 0x6E, /* 0xE0-0xE3 */ - 0xB8, 0xF8, 0x00, 0x00, 0xB8, 0xF9, 0xE0, 0x70, /* 0xE4-0xE7 */ - 0xB8, 0xF3, 0xE0, 0x6D, 0xB8, 0xF7, 0xE0, 0x72, /* 0xE8-0xEB */ - 0xE0, 0x69, 0x00, 0x00, 0xE0, 0x6B, 0xB8, 0xF4, /* 0xEC-0xEF */ - 0xE0, 0x67, 0xE0, 0x6A, 0xE0, 0x71, 0xB8, 0xF5, /* 0xF0-0xF3 */ - 0xE0, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0x00, 0x00, 0xB8, 0xF6, 0x00, 0x00, /* 0xF8-0xFB */ - 0xBB, 0xB1, 0xE4, 0x5B, 0xE4, 0x61, 0xE4, 0x59, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_8E[512] = { - 0xE4, 0x62, 0x00, 0x00, 0xE4, 0x58, 0xE4, 0x5D, /* 0x00-0x03 */ - 0xE4, 0x63, 0xE4, 0x60, 0xE4, 0x5F, 0xE4, 0x5E, /* 0x04-0x07 */ - 0x00, 0x00, 0xE4, 0x57, 0xE4, 0x5C, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0xE4, 0x5A, 0x00, 0x00, 0xBD, 0xF1, /* 0x0C-0x0F */ - 0xBD, 0xEE, 0xE7, 0xFB, 0xE8, 0x41, 0xE8, 0x43, /* 0x10-0x13 */ - 0xE8, 0x40, 0xE7, 0xF8, 0xE7, 0xFA, 0xE8, 0x45, /* 0x14-0x17 */ - 0xE8, 0x42, 0xE7, 0xFC, 0xE8, 0x46, 0xE7, 0xF9, /* 0x18-0x1B */ - 0xE8, 0x44, 0xBD, 0xEF, 0xBD, 0xF5, 0xBD, 0xF3, /* 0x1C-0x1F */ - 0xE7, 0xF3, 0xBD, 0xF4, 0xBD, 0xF0, 0xE7, 0xF4, /* 0x20-0x23 */ - 0xE7, 0xF6, 0xE7, 0xF5, 0xE7, 0xFD, 0xE7, 0xFE, /* 0x24-0x27 */ - 0x00, 0x00, 0xBD, 0xF2, 0x00, 0x00, 0xBD, 0xED, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0xE7, 0xF7, 0x00, 0x00, /* 0x2C-0x2F */ - 0xEB, 0xC6, 0xBF, 0xE2, 0x00, 0x00, 0xEB, 0xBD, /* 0x30-0x33 */ - 0xBF, 0xE3, 0xBF, 0xE6, 0xEB, 0xC2, 0x00, 0x00, /* 0x34-0x37 */ - 0xEB, 0xBF, 0xBF, 0xE5, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xEB, 0xC3, 0xEB, 0xC4, 0xEB, 0xBE, 0xEB, 0xC7, /* 0x3C-0x3F */ - 0xEB, 0xC0, 0xEB, 0xC5, 0xBF, 0xE4, 0x00, 0x00, /* 0x40-0x43 */ - 0xBF, 0xE1, 0xEB, 0xC1, 0x00, 0x00, 0xEE, 0xBF, /* 0x44-0x47 */ - 0xC1, 0xD0, 0xC1, 0xCE, 0xC1, 0xD1, 0xC1, 0xCF, /* 0x48-0x4B */ - 0xEE, 0xBE, 0xEE, 0xBB, 0xEE, 0xBA, 0x00, 0x00, /* 0x4C-0x4F */ - 0xEE, 0xBD, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xBC, /* 0x50-0x53 */ - 0xF1, 0x45, 0xC2, 0xDE, 0xF0, 0xFB, 0xF0, 0xFA, /* 0x54-0x57 */ - 0x00, 0x00, 0xC2, 0xD9, 0xF1, 0x41, 0xF1, 0x40, /* 0x58-0x5B */ - 0xF0, 0xF7, 0xF1, 0x43, 0xF0, 0xFC, 0xC2, 0xDD, /* 0x5C-0x5F */ - 0xF0, 0xF9, 0xF1, 0x42, 0xF0, 0xF8, 0xC2, 0xDA, /* 0x60-0x63 */ - 0xC2, 0xDC, 0xF0, 0xFD, 0xC2, 0xDB, 0xF0, 0xFE, /* 0x64-0x67 */ - 0x00, 0x00, 0xF1, 0x44, 0xF3, 0x52, 0x00, 0x00, /* 0x68-0x6B */ - 0xC3, 0xDE, 0xF3, 0x4F, 0x00, 0x00, 0xF3, 0x53, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xC3, 0xDB, 0xF3, 0x51, /* 0x70-0x73 */ - 0xC3, 0xE0, 0x00, 0x00, 0xC3, 0xDD, 0x00, 0x00, /* 0x74-0x77 */ - 0xF3, 0x50, 0x00, 0x00, 0xC3, 0xDF, 0xF3, 0x54, /* 0x78-0x7B */ - 0xC3, 0xDA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0xC4, 0xBC, 0xC4, 0xBE, 0x00, 0x00, /* 0x80-0x83 */ - 0xF4, 0xD9, 0xC4, 0xBD, 0xF4, 0xD7, 0xC3, 0xDC, /* 0x84-0x87 */ - 0xF4, 0xD8, 0xC4, 0xBB, 0xC5, 0x43, 0xC5, 0x45, /* 0x88-0x8B */ - 0xF6, 0x56, 0xC5, 0x44, 0xF6, 0x55, 0x00, 0x00, /* 0x8C-0x8F */ - 0xF7, 0x61, 0xC5, 0xAD, 0xF7, 0x60, 0xC5, 0xAE, /* 0x90-0x93 */ - 0xF7, 0x5E, 0xF7, 0x5D, 0xF7, 0x62, 0xF7, 0x63, /* 0x94-0x97 */ - 0xF8, 0x46, 0x00, 0x00, 0xF7, 0x5F, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0xF8, 0xC6, 0xF8, 0xC3, 0xF8, 0xC4, /* 0x9C-0x9F */ - 0xF8, 0xC5, 0xC6, 0x5C, 0x00, 0x00, 0xF9, 0x51, /* 0xA0-0xA3 */ - 0xF9, 0x50, 0xF9, 0x4F, 0xF9, 0x70, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xF9, 0xBE, 0xF9, 0xAB, 0xC6, 0x6E, 0xA8, 0xAD, /* 0xA8-0xAB */ - 0xB0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xB8, 0xFA, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0xBD, 0xF6, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xEB, 0xC8, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xC2, 0xDF, 0x00, 0x00, 0xF3, 0x55, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xF9, 0xAC, 0xA8, 0xAE, 0xAA, 0xEE, /* 0xC8-0xCB */ - 0xAD, 0x79, 0xAD, 0x78, 0x00, 0x00, 0xB0, 0x63, /* 0xCC-0xCF */ - 0x00, 0x00, 0xD3, 0xE8, 0xB0, 0x61, 0xD3, 0xE9, /* 0xD0-0xD3 */ - 0xB0, 0x62, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xDF, /* 0xD4-0xD7 */ - 0xD7, 0xDB, 0x00, 0x00, 0x00, 0x00, 0xB3, 0x6D, /* 0xD8-0xDB */ - 0xD7, 0xDE, 0xD7, 0xDD, 0xD7, 0xDC, 0xB3, 0x6E, /* 0xDC-0xDF */ - 0xD7, 0xE0, 0xD7, 0xE1, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xDC, 0x43, 0xDC, 0x41, 0xDC, 0x45, /* 0xE4-0xE7 */ - 0xDC, 0x46, 0xDC, 0x4C, 0x00, 0x00, 0xDC, 0x48, /* 0xE8-0xEB */ - 0xDC, 0x4A, 0x00, 0x00, 0xDC, 0x42, 0xDB, 0xFC, /* 0xEC-0xEF */ - 0x00, 0x00, 0xDC, 0x49, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xDC, 0x4B, 0xDC, 0x44, 0xDC, 0x47, 0xDB, 0xFD, /* 0xF4-0xF7 */ - 0xB6, 0x62, 0xDC, 0x40, 0xDB, 0xFE, 0xB6, 0x61, /* 0xF8-0xFB */ - 0xB6, 0x63, 0x00, 0x00, 0xB8, 0xFD, 0xE0, 0x75, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_8F[512] = { - 0xE0, 0x77, 0xE0, 0x76, 0xE0, 0x7B, 0xB8, 0xFB, /* 0x00-0x03 */ - 0x00, 0x00, 0xE0, 0x78, 0xE0, 0x74, 0xE0, 0x79, /* 0x04-0x07 */ - 0xE0, 0x7A, 0xB8, 0xFC, 0xB8, 0xFE, 0xE0, 0x7C, /* 0x08-0x0B */ - 0x00, 0x00, 0xE4, 0x67, 0xE4, 0x66, 0x00, 0x00, /* 0x0C-0x0F */ - 0xE4, 0x64, 0xE4, 0x65, 0xBB, 0xB3, 0xBB, 0xB5, /* 0x10-0x13 */ - 0xBB, 0xB2, 0xBB, 0xB4, 0xE8, 0x4D, 0xE8, 0x4E, /* 0x14-0x17 */ - 0xE8, 0x49, 0x00, 0x00, 0xE8, 0x4A, 0xBD, 0xF8, /* 0x18-0x1B */ - 0xBD, 0xFD, 0xBD, 0xF7, 0xBD, 0xFE, 0xBD, 0xF9, /* 0x1C-0x1F */ - 0xE8, 0x4B, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x4C, /* 0x20-0x23 */ - 0xE8, 0x48, 0xBE, 0x40, 0xBD, 0xFB, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0xBD, 0xFA, 0xBD, 0xFC, 0x00, 0x00, /* 0x28-0x2B */ - 0xE8, 0x47, 0x00, 0x00, 0xEB, 0xCA, 0xBF, 0xE8, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0xEB, 0xCC, 0xBF, 0xEA, /* 0x30-0x33 */ - 0xEB, 0xCF, 0xEB, 0xCB, 0xEB, 0xC9, 0xEB, 0xCE, /* 0x34-0x37 */ - 0xBF, 0xE9, 0xEB, 0xCD, 0x00, 0x00, 0xBF, 0xE7, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xC1, 0xD3, 0xC1, 0xD6, /* 0x3C-0x3F */ - 0xEE, 0xC1, 0x00, 0x00, 0xC1, 0xD4, 0xEE, 0xC0, /* 0x40-0x43 */ - 0xC1, 0xD2, 0xC1, 0xD5, 0xF1, 0x46, 0xF1, 0x47, /* 0x44-0x47 */ - 0xF1, 0x48, 0xC2, 0xE0, 0x00, 0x00, 0xF1, 0x49, /* 0x48-0x4B */ - 0x00, 0x00, 0xC2, 0xE1, 0xC3, 0xE2, 0xF3, 0x58, /* 0x4C-0x4F */ - 0xF3, 0x59, 0xF3, 0x57, 0xF3, 0x56, 0xF3, 0x5A, /* 0x50-0x53 */ - 0xC3, 0xE1, 0xF4, 0xDD, 0xF4, 0xDB, 0xF4, 0xDC, /* 0x54-0x57 */ - 0xF4, 0xDE, 0xF4, 0xDA, 0xF4, 0xDF, 0xF6, 0x58, /* 0x58-0x5B */ - 0x00, 0x00, 0xF6, 0x59, 0xF6, 0x57, 0xC5, 0x46, /* 0x5C-0x5F */ - 0xF7, 0x64, 0xC5, 0xAF, 0xF7, 0x65, 0xF8, 0x48, /* 0x60-0x63 */ - 0xF8, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA8, 0xAF, /* 0x98-0x9B */ - 0xB6, 0x64, 0x00, 0x00, 0x00, 0x00, 0xB9, 0x40, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBB, 0xB6, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0xBF, 0xEC, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xBF, 0xEB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0xC3, 0xE3, 0xC4, 0x7C, 0xC5, 0x47, /* 0xAC-0xAF */ - 0xA8, 0xB0, 0xB0, 0x64, 0xB9, 0x41, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xF3, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCB, 0xA6, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0xB1, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xA8, 0xB4, 0xA8, 0xB3, 0xA8, 0xB2, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xCB, 0xA5, 0x00, 0x00, 0xCD, 0xCD, /* 0xC8-0xCB */ - 0x00, 0x00, 0xCD, 0xCF, 0xAA, 0xEF, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0xAA, 0xF1, 0xCD, 0xCC, 0xCD, 0xCE, /* 0xD0-0xD3 */ - 0xAA, 0xF0, 0xCD, 0xD1, 0xCD, 0xD0, 0xCD, 0xD2, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0xD0, 0xB6, 0xD0, 0xB4, 0xAD, 0x7C, 0xD0, 0xB3, /* 0xE0-0xE3 */ - 0xAD, 0xA3, 0xAD, 0x7E, 0xAD, 0x7B, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xAD, 0xA4, 0x00, 0x00, 0xAD, 0x7D, 0xAD, 0xA2, /* 0xE8-0xEB */ - 0x00, 0x00, 0xAD, 0xA1, 0xD0, 0xB5, 0x00, 0x00, /* 0xEC-0xEF */ - 0xAD, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xB0, 0x6A, 0xD3, 0xEB, 0xD3, 0xF1, 0xB0, 0x67, /* 0xF4-0xF7 */ - 0xB0, 0x6E, 0x00, 0x00, 0xB0, 0x69, 0xD3, 0xEE, /* 0xF8-0xFB */ - 0xD3, 0xF0, 0xB0, 0x6C, 0xD3, 0xEA, 0xD3, 0xED, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_90[512] = { - 0xB0, 0x68, 0xB0, 0x65, 0xD3, 0xEC, 0xB0, 0x6B, /* 0x00-0x03 */ - 0xD3, 0xEF, 0xB0, 0x6D, 0xB0, 0x66, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD7, 0xE3, /* 0x08-0x0B */ - 0xD7, 0xE6, 0xB3, 0x70, 0x00, 0x00, 0xB3, 0x7A, /* 0x0C-0x0F */ - 0xB3, 0x76, 0xD7, 0xE4, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xB3, 0x7E, 0xB3, 0x77, 0xB3, 0x7C, 0xB3, 0x72, /* 0x14-0x17 */ - 0x00, 0x00, 0xB3, 0x6F, 0xB3, 0x71, 0xB3, 0x7D, /* 0x18-0x1B */ - 0xD7, 0xE5, 0xB3, 0x75, 0xB3, 0x78, 0xB3, 0x74, /* 0x1C-0x1F */ - 0xB3, 0x79, 0xD7, 0xE7, 0xB3, 0x7B, 0xB3, 0x73, /* 0x20-0x23 */ - 0xD7, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0xDC, 0x4D, 0xB6, 0x65, 0xDC, 0x4F, /* 0x2C-0x2F */ - 0x00, 0x00, 0xB6, 0x67, 0xB6, 0x69, 0x00, 0x00, /* 0x30-0x33 */ - 0xDC, 0x4E, 0xB6, 0x66, 0xB6, 0x6A, 0x00, 0x00, /* 0x34-0x37 */ - 0xB6, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xB9, 0x47, 0xE0, 0xA3, 0xB9, 0x4F, 0xE0, 0x7E, /* 0x3C-0x3F */ - 0x00, 0x00, 0xB9, 0x50, 0xB9, 0x45, 0x00, 0x00, /* 0x40-0x43 */ - 0xE0, 0xA1, 0x00, 0x00, 0x00, 0x00, 0xB9, 0x4A, /* 0x44-0x47 */ - 0x00, 0x00, 0xE0, 0xA2, 0xB9, 0x43, 0xB9, 0x42, /* 0x48-0x4B */ - 0x00, 0x00, 0xB9, 0x4D, 0xB9, 0x4C, 0xB9, 0x4B, /* 0x4C-0x4F */ - 0xB9, 0x49, 0xB9, 0x4E, 0xE0, 0x7D, 0xB9, 0x44, /* 0x50-0x53 */ - 0xB9, 0x46, 0xB9, 0x48, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xBB, 0xB8, 0xBB, 0xBB, 0x00, 0x00, 0xBB, 0xBF, /* 0x58-0x5B */ - 0xBB, 0xB9, 0xBB, 0xBE, 0xBB, 0xBC, 0x00, 0x00, /* 0x5C-0x5F */ - 0xBB, 0xB7, 0x00, 0x00, 0xBB, 0xBD, 0xBB, 0xBA, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0x52, /* 0x64-0x67 */ - 0xBE, 0x43, 0xBE, 0x41, 0x00, 0x00, 0xE8, 0x53, /* 0x68-0x6B */ - 0x00, 0x00, 0xBE, 0x44, 0xBE, 0x42, 0xE8, 0x51, /* 0x6C-0x6F */ - 0xE8, 0x50, 0x00, 0x00, 0xBF, 0xF0, 0xE8, 0x4F, /* 0x70-0x73 */ - 0xBF, 0xEE, 0xBF, 0xED, 0xEB, 0xD0, 0xBE, 0x45, /* 0x74-0x77 */ - 0xBF, 0xEF, 0xEB, 0xD1, 0xBF, 0xF2, 0xEB, 0xD2, /* 0x78-0x7B */ - 0xBF, 0xF1, 0xC1, 0xD8, 0xEE, 0xC3, 0xC1, 0xD7, /* 0x7C-0x7F */ - - 0xC1, 0xDC, 0xC1, 0xDA, 0xC1, 0xDB, 0xC2, 0xE3, /* 0x80-0x83 */ - 0xC1, 0xD9, 0xEE, 0xC2, 0xEB, 0xD3, 0xC2, 0xE2, /* 0x84-0x87 */ - 0xC2, 0xE4, 0x00, 0x00, 0xC3, 0xE4, 0xC3, 0xE5, /* 0x88-0x8B */ - 0x00, 0x00, 0xF4, 0xE0, 0x00, 0x00, 0xC5, 0xDE, /* 0x8C-0x8F */ - 0xC5, 0xDD, 0xA8, 0xB6, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xCA, 0x55, 0xB0, 0x6F, 0x00, 0x00, 0xCA, 0x52, /* 0x94-0x97 */ - 0xCA, 0x53, 0xCA, 0x51, 0x00, 0x00, 0xCA, 0x54, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xCB, 0xAA, 0xCB, 0xA7, /* 0x9C-0x9F */ - 0xCB, 0xAC, 0xCB, 0xA8, 0xA8, 0xB7, 0xA8, 0xBA, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xCB, 0xA9, 0xA8, 0xB9, 0xCB, 0xAB, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0xA8, 0xB8, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCD, 0xD5, /* 0xAC-0xAF */ - 0xCD, 0xD7, 0xAA, 0xF4, 0xCD, 0xD3, 0xCD, 0xD6, /* 0xB0-0xB3 */ - 0xCD, 0xD4, 0xAA, 0xF2, 0xAA, 0xF5, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xAA, 0xF3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xD0, 0xB8, 0xD0, 0xBC, 0xD0, 0xB9, /* 0xBC-0xBF */ - 0x00, 0x00, 0xAD, 0xA7, 0x00, 0x00, 0xAD, 0xA8, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xD0, 0xBB, 0x00, 0x00, 0xD0, 0xBD, /* 0xC4-0xC7 */ - 0xD0, 0xBF, 0x00, 0x00, 0xAD, 0xA5, 0xD0, 0xBE, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0xAD, 0xA6, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xD7, 0xEE, 0xD0, 0xBA, 0xD3, 0xF2, 0xD3, 0xFB, /* 0xD4-0xD7 */ - 0xD3, 0xF9, 0xD3, 0xF4, 0xD3, 0xF5, 0xD3, 0xFA, /* 0xD8-0xDB */ - 0xD3, 0xFC, 0xB0, 0x71, 0x00, 0x00, 0xD3, 0xF7, /* 0xDC-0xDF */ - 0xD3, 0xF3, 0xB0, 0x70, 0xB0, 0x72, 0xD3, 0xF6, /* 0xE0-0xE3 */ - 0xD3, 0xFD, 0xD3, 0xF8, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xB3, 0xA1, 0xD7, 0xF1, 0xD7, 0xE9, 0xD7, 0xEF, /* 0xE8-0xEB */ - 0xD7, 0xF0, 0xB3, 0xA2, 0x00, 0x00, 0xD7, 0xE8, /* 0xEC-0xEF */ - 0xD7, 0xEA, 0xD0, 0xB7, 0xD7, 0xEC, 0xD7, 0xED, /* 0xF0-0xF3 */ - 0xD7, 0xEB, 0xB6, 0x6C, 0x00, 0x00, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xDC, 0x56, 0xEB, 0xD4, 0xDC, 0x57, /* 0xF8-0xFB */ - 0xDC, 0x54, 0xB3, 0xA3, 0xB6, 0x6E, 0xDC, 0x53, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_91[512] = { - 0xDC, 0x59, 0xDC, 0x58, 0xB6, 0x6B, 0xDC, 0x5C, /* 0x00-0x03 */ - 0xDC, 0x52, 0xDC, 0x5B, 0xDC, 0x50, 0xDC, 0x5A, /* 0x04-0x07 */ - 0xDC, 0x55, 0xB6, 0x6D, 0x00, 0x00, 0xE0, 0xAA, /* 0x08-0x0B */ - 0x00, 0x00, 0xE0, 0xA5, 0xE0, 0xAB, 0xE0, 0xA6, /* 0x0C-0x0F */ - 0xE0, 0xA4, 0xE0, 0xA7, 0xB9, 0x51, 0x00, 0x00, /* 0x10-0x13 */ - 0xE0, 0xA9, 0x00, 0x00, 0xE0, 0xA8, 0xB9, 0x52, /* 0x14-0x17 */ - 0xBB, 0xC1, 0xBB, 0xC0, 0xE4, 0x6E, 0xE4, 0x71, /* 0x18-0x1B */ - 0xE4, 0x69, 0xE4, 0x6D, 0xBB, 0xC2, 0xE4, 0x6C, /* 0x1C-0x1F */ - 0xE4, 0x6A, 0xE4, 0x70, 0xE4, 0x6B, 0xE4, 0x68, /* 0x20-0x23 */ - 0xE4, 0x6F, 0x00, 0x00, 0xE8, 0x59, 0xBE, 0x48, /* 0x24-0x27 */ - 0xF1, 0x4A, 0xE8, 0x56, 0xE8, 0x57, 0xE8, 0x55, /* 0x28-0x2B */ - 0xDC, 0x51, 0xBE, 0x47, 0xE8, 0x5A, 0xE8, 0x54, /* 0x2C-0x2F */ - 0xBE, 0x46, 0xBE, 0x49, 0xE8, 0x58, 0xEB, 0xD5, /* 0x30-0x33 */ - 0xBF, 0xF3, 0xEB, 0xD6, 0xEB, 0xD7, 0x00, 0x00, /* 0x34-0x37 */ - 0xEE, 0xC4, 0xC1, 0xDD, 0xF1, 0x4B, 0xF1, 0x4C, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0x4D, 0xF3, 0x5D, /* 0x3C-0x3F */ - 0xF3, 0x5C, 0xF4, 0xE2, 0x00, 0x00, 0xF4, 0xE1, /* 0x40-0x43 */ - 0xF6, 0x5B, 0xF6, 0x5C, 0xF6, 0x5A, 0xF7, 0x66, /* 0x44-0x47 */ - 0xC5, 0xB0, 0xA8, 0xBB, 0xAD, 0xAA, 0xAD, 0xA9, /* 0x48-0x4B */ - 0xB0, 0x75, 0xB0, 0x74, 0xD4, 0x40, 0xD4, 0x41, /* 0x4C-0x4F */ - 0xD3, 0xFE, 0x00, 0x00, 0xB0, 0x73, 0xD7, 0xF5, /* 0x50-0x53 */ - 0x00, 0x00, 0xD7, 0xF6, 0xD7, 0xF2, 0xB3, 0xA4, /* 0x54-0x57 */ - 0xD7, 0xF3, 0x00, 0x00, 0xD7, 0xF4, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x5F, /* 0x5C-0x5F */ - 0xDC, 0x61, 0xDC, 0x5D, 0xDC, 0x60, 0xB6, 0x6F, /* 0x60-0x63 */ - 0xDC, 0x5E, 0xB6, 0x70, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xDD, 0x73, 0xB9, 0x55, 0xB9, 0x54, 0x00, 0x00, /* 0x68-0x6B */ - 0xB9, 0x53, 0x00, 0x00, 0xE0, 0xAC, 0xE0, 0xAD, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0x73, 0xE4, 0x75, /* 0x70-0x73 */ - 0xBB, 0xC6, 0xBB, 0xC3, 0x00, 0x00, 0xBB, 0xC5, /* 0x74-0x77 */ - 0xBB, 0xC4, 0xE4, 0x74, 0xE4, 0x72, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xE8, 0x61, 0xE8, 0x5E, 0xE8, 0x5F, 0xBE, 0x4D, /* 0x80-0x83 */ - 0xE8, 0x60, 0xE8, 0x5B, 0xE8, 0x5C, 0xBE, 0x4A, /* 0x84-0x87 */ - 0x00, 0x00, 0xBE, 0x4B, 0xE8, 0x5D, 0xBE, 0x4C, /* 0x88-0x8B */ - 0x00, 0x00, 0xEB, 0xDB, 0x00, 0x00, 0xEB, 0xDC, /* 0x8C-0x8F */ - 0xEB, 0xD9, 0xEB, 0xDA, 0xBF, 0xF4, 0xEB, 0xD8, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0xEE, 0xC8, 0xEE, 0xC5, 0xEE, 0xC7, /* 0x98-0x9B */ - 0xC1, 0xE0, 0xEE, 0xCB, 0xC1, 0xDF, 0xEE, 0xC9, /* 0x9C-0x9F */ - 0xEE, 0xCC, 0xEE, 0xCA, 0xEE, 0xC6, 0xC1, 0xDE, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xF1, 0x4F, 0x00, 0x00, 0xF1, 0x50, /* 0xA4-0xA7 */ - 0xF1, 0x4E, 0x00, 0x00, 0xF1, 0x52, 0xC2, 0xE5, /* 0xA8-0xAB */ - 0xC2, 0xE6, 0xF3, 0x5F, 0xC3, 0xE7, 0xF1, 0x51, /* 0xAC-0xAF */ - 0xF3, 0x5E, 0xC3, 0xE6, 0xF4, 0xE5, 0xF4, 0xE6, /* 0xB0-0xB3 */ - 0xC4, 0xBF, 0xF4, 0xE4, 0x00, 0x00, 0xF4, 0xE3, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xF6, 0x5D, 0xC5, 0x48, 0x00, 0x00, /* 0xB8-0xBB */ - 0xF8, 0x49, 0xF8, 0xC8, 0xF8, 0xC7, 0x00, 0x00, /* 0xBC-0xBF */ - 0xC6, 0x43, 0xC6, 0x5D, 0xF8, 0xC9, 0xF9, 0x71, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xC6, 0x6F, 0xA8, 0xBC, 0xAA, 0xF6, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xB9, 0x56, 0x00, 0x00, 0xC4, 0xC0, /* 0xC8-0xCB */ - 0xA8, 0xBD, 0xAD, 0xAB, 0xB3, 0xA5, 0xB6, 0x71, /* 0xCC-0xCF */ - 0xC2, 0xE7, 0xAA, 0xF7, 0x00, 0x00, 0xD0, 0xC1, /* 0xD0-0xD3 */ - 0xD0, 0xC0, 0xD4, 0x42, 0x00, 0x00, 0xB0, 0x78, /* 0xD4-0xD7 */ - 0xB0, 0x76, 0xB0, 0x7A, 0xD4, 0x44, 0x00, 0x00, /* 0xD8-0xDB */ - 0xB0, 0x79, 0xB0, 0x77, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xD4, 0x43, 0xB3, 0xA8, /* 0xE0-0xE3 */ - 0xD7, 0xFC, 0x00, 0x00, 0xB3, 0xA7, 0xB3, 0xA9, /* 0xE4-0xE7 */ - 0xD8, 0x42, 0xB3, 0xAB, 0xD7, 0xFE, 0xD8, 0x40, /* 0xE8-0xEB */ - 0xD7, 0xF7, 0xB3, 0xAA, 0xD8, 0x43, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0xD7, 0xF9, 0x00, 0x00, 0xD7, 0xFA, /* 0xF0-0xF3 */ - 0xD7, 0xF8, 0xB3, 0xA6, 0x00, 0x00, 0xD8, 0x41, /* 0xF4-0xF7 */ - 0xD7, 0xFB, 0xD7, 0xFD, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xDC, 0x6D, 0x00, 0x00, 0xDC, 0x6C, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_92[512] = { - 0xDC, 0x6A, 0xDC, 0x62, 0xDC, 0x71, 0xDC, 0x65, /* 0x00-0x03 */ - 0xDC, 0x6F, 0xDC, 0x76, 0xDC, 0x6E, 0xB6, 0x79, /* 0x04-0x07 */ - 0x00, 0x00, 0xB6, 0x75, 0xDC, 0x63, 0x00, 0x00, /* 0x08-0x0B */ - 0xDC, 0x69, 0xB6, 0x77, 0x00, 0x00, 0xDC, 0x68, /* 0x0C-0x0F */ - 0xB6, 0x78, 0xB6, 0x7A, 0xDC, 0x6B, 0x00, 0x00, /* 0x10-0x13 */ - 0xB6, 0x72, 0xB6, 0x73, 0xDC, 0x77, 0xDC, 0x75, /* 0x14-0x17 */ - 0x00, 0x00, 0xDC, 0x74, 0xDC, 0x66, 0x00, 0x00, /* 0x18-0x1B */ - 0xDC, 0x72, 0x00, 0x00, 0xB6, 0x76, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB6, 0x74, /* 0x20-0x23 */ - 0xDC, 0x73, 0xDC, 0x64, 0xDC, 0x67, 0xDC, 0x70, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0xE4, 0xBA, 0xE0, 0xB7, 0x00, 0x00, /* 0x2C-0x2F */ - 0xE0, 0xB0, 0xE0, 0xC3, 0xE0, 0xCC, 0xE0, 0xB3, /* 0x30-0x33 */ - 0xB9, 0x61, 0x00, 0x00, 0xE0, 0xC0, 0xB9, 0x57, /* 0x34-0x37 */ - 0xB9, 0x59, 0xB9, 0x65, 0xE0, 0xB1, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xB9, 0x5A, 0xB9, 0x5C, 0xB9, 0x66, /* 0x3C-0x3F */ - 0xB9, 0x5B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0xB9, 0x64, 0xE0, 0xB9, 0x00, 0x00, /* 0x44-0x47 */ - 0xE0, 0xAE, 0xB9, 0x62, 0xE0, 0xB8, 0xB9, 0x5E, /* 0x48-0x4B */ - 0xE0, 0xCA, 0xB9, 0x63, 0xE0, 0xC8, 0xE0, 0xBC, /* 0x4C-0x4F */ - 0xE0, 0xC6, 0xB9, 0x60, 0xE0, 0xAF, 0xE0, 0xC9, /* 0x50-0x53 */ - 0xE0, 0xC4, 0x00, 0x00, 0xE0, 0xCB, 0xB9, 0x58, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xB9, 0x67, 0xB9, 0x5D, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xE0, 0xB5, 0x00, 0x00, /* 0x5C-0x5F */ - 0xE0, 0xBD, 0xE0, 0xC1, 0x00, 0x00, 0xE0, 0xC5, /* 0x60-0x63 */ - 0xB9, 0x5F, 0xE0, 0xB4, 0xE0, 0xB2, 0xE0, 0xBE, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0xE0, 0xBB, 0xE0, 0xBA, 0x00, 0x00, 0xE0, 0xBF, /* 0x6C-0x6F */ - 0xE0, 0xC2, 0x00, 0x00, 0xE0, 0xC7, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0x78, 0x00, 0x00, /* 0x74-0x77 */ - 0xBB, 0xC7, 0xE4, 0xA4, 0xE4, 0x7A, 0xBB, 0xCC, /* 0x78-0x7B */ - 0xBB, 0xD0, 0xE4, 0xAD, 0xE4, 0xB5, 0xE4, 0xA6, /* 0x7C-0x7F */ - - 0xBB, 0xC8, 0x00, 0x00, 0xE4, 0xAA, 0xE0, 0xB6, /* 0x80-0x83 */ - 0x00, 0x00, 0xBB, 0xC9, 0xE4, 0xB1, 0xE4, 0xB6, /* 0x84-0x87 */ - 0xE4, 0xAE, 0x00, 0x00, 0xE4, 0xB0, 0xE4, 0xB9, /* 0x88-0x8B */ - 0xE4, 0xB2, 0xE4, 0x7E, 0xE4, 0xA9, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xBB, 0xD1, 0x00, 0x00, 0xBB, 0xCD, /* 0x90-0x93 */ - 0xE4, 0x7C, 0xE4, 0xAB, 0xBB, 0xCB, 0xE4, 0xA5, /* 0x94-0x97 */ - 0xBB, 0xCA, 0xE4, 0xB3, 0xE4, 0xA2, 0xE4, 0x79, /* 0x98-0x9B */ - 0xBB, 0xCE, 0xE4, 0xB8, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xE4, 0x7B, 0xE4, 0xAF, 0xE4, 0xAC, 0xE4, 0xA7, /* 0xA0-0xA3 */ - 0xE4, 0x77, 0xE4, 0x76, 0xE4, 0xA1, 0xE4, 0xB4, /* 0xA4-0xA7 */ - 0xBB, 0xCF, 0xE4, 0xB7, 0xE4, 0x7D, 0xE4, 0xA3, /* 0xA8-0xAB */ - 0xBE, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0xBE, 0x5A, 0xBE, 0x55, /* 0xB0-0xB3 */ - 0xE8, 0xA4, 0xE8, 0xA1, 0xE8, 0x67, 0xBE, 0x50, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xF9, 0xD7, 0x00, 0x00, 0xBE, 0x4F, /* 0xB8-0xBB */ - 0xBE, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xE8, 0x65, 0xBE, 0x54, 0xE8, 0x71, 0xE8, 0x63, /* 0xC0-0xC3 */ - 0xE8, 0x64, 0xBE, 0x4E, 0xE8, 0xA3, 0xBE, 0x58, /* 0xC4-0xC7 */ - 0xE8, 0x74, 0xE8, 0x79, 0xE8, 0x73, 0xEB, 0xEE, /* 0xC8-0xCB */ - 0xE8, 0x6F, 0xE8, 0x77, 0xE8, 0x75, 0xE8, 0x68, /* 0xCC-0xCF */ - 0xE8, 0x62, 0xE8, 0x7D, 0xBE, 0x57, 0xE8, 0x7E, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xE8, 0x78, 0x00, 0x00, 0xE8, 0x6D, /* 0xD4-0xD7 */ - 0xE8, 0x6B, 0xE8, 0x66, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0xE8, 0x6E, 0xE8, 0x7B, 0xE8, 0x6A, /* 0xDC-0xDF */ - 0xE8, 0x7A, 0xE8, 0xA2, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xBE, 0x53, 0x00, 0x00, 0xE8, 0x76, 0xE8, 0x7C, /* 0xE4-0xE7 */ - 0xE8, 0x72, 0xE8, 0x6C, 0xBE, 0x51, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xA8, 0xE8, 0x70, /* 0xEC-0xEF */ - 0xBE, 0x59, 0xE8, 0x69, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEB, 0xF4, /* 0xF4-0xF7 */ - 0xBF, 0xF7, 0xEB, 0xF3, 0xEB, 0xF0, 0xEC, 0x44, /* 0xF8-0xFB */ - 0xBF, 0xFB, 0x00, 0x00, 0xEC, 0x41, 0xEB, 0xF8, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_93[512] = { - 0xEC, 0x43, 0xEB, 0xE9, 0xEB, 0xF6, 0x00, 0x00, /* 0x00-0x03 */ - 0xBF, 0xFD, 0x00, 0x00, 0xEB, 0xE1, 0x00, 0x00, /* 0x04-0x07 */ - 0xEB, 0xDF, 0xEC, 0x42, 0x00, 0x00, 0xEC, 0x40, /* 0x08-0x0B */ - 0xEB, 0xFE, 0xEB, 0xED, 0xEB, 0xEC, 0xEB, 0xE2, /* 0x0C-0x0F */ - 0xC0, 0x40, 0x00, 0x00, 0xEB, 0xE8, 0xEB, 0xF2, /* 0x10-0x13 */ - 0xEB, 0xFD, 0xC0, 0x43, 0xEC, 0x45, 0x00, 0x00, /* 0x14-0x17 */ - 0xC1, 0xE8, 0xC0, 0x45, 0xBF, 0xFE, 0xEB, 0xE6, /* 0x18-0x1B */ - 0x00, 0x00, 0xEB, 0xEF, 0xEB, 0xDE, 0xEB, 0xE0, /* 0x1C-0x1F */ - 0xBF, 0xF5, 0xC0, 0x42, 0xBF, 0xFA, 0xEB, 0xE7, /* 0x20-0x23 */ - 0xEB, 0xF7, 0xEB, 0xF1, 0xC0, 0x41, 0xEB, 0xDD, /* 0x24-0x27 */ - 0xC1, 0xE3, 0xEB, 0xF9, 0xEB, 0xFC, 0xBF, 0xFC, /* 0x28-0x2B */ - 0x00, 0x00, 0xEB, 0xEB, 0xC0, 0x44, 0xBF, 0xF9, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBF, 0xF8, /* 0x30-0x33 */ - 0xEB, 0xF5, 0xEB, 0xFB, 0xBF, 0xF6, 0x00, 0x00, /* 0x34-0x37 */ - 0xEB, 0xE4, 0xEB, 0xFA, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0xEB, 0xE5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xEB, 0xEA, 0xEE, 0xD2, /* 0x44-0x47 */ - 0x00, 0x00, 0xEE, 0xD7, 0xC1, 0xE5, 0xC1, 0xE7, /* 0x48-0x4B */ - 0xEE, 0xDD, 0xC1, 0xE1, 0xEE, 0xEC, 0xEE, 0xE3, /* 0x4C-0x4F */ - 0xEE, 0xD8, 0xEE, 0xD9, 0xEE, 0xE2, 0x00, 0x00, /* 0x50-0x53 */ - 0xC1, 0xEE, 0xEE, 0xE1, 0xEE, 0xD1, 0xEE, 0xE0, /* 0x54-0x57 */ - 0xEE, 0xD4, 0xEE, 0xED, 0xC1, 0xED, 0xC1, 0xEB, /* 0x58-0x5B */ - 0xEE, 0xD5, 0x00, 0x00, 0xEE, 0xE8, 0x00, 0x00, /* 0x5C-0x5F */ - 0xEE, 0xDA, 0xEE, 0xE7, 0x00, 0x00, 0xEE, 0xE9, /* 0x60-0x63 */ - 0xEE, 0xD0, 0xC1, 0xE6, 0x00, 0x00, 0xEE, 0xEA, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xEE, 0xDE, 0x00, 0x00, /* 0x68-0x6B */ - 0xC1, 0xEA, 0xEE, 0xDB, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0xC1, 0xEC, 0xEE, 0xE4, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xC1, 0xE4, 0xEE, 0xD6, 0xEE, 0xE5, /* 0x74-0x77 */ - 0x00, 0x00, 0xEE, 0xDF, 0xEB, 0xE3, 0xEE, 0xE6, /* 0x78-0x7B */ - 0xEE, 0xD3, 0x00, 0x00, 0xC1, 0xE9, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xEE, 0xEB, 0x00, 0x00, 0xC1, 0xE2, 0xEE, 0xCE, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xF1, 0x60, 0xF1, 0x59, 0xC2, 0xE9, 0x00, 0x00, /* 0x88-0x8B */ - 0xF1, 0x54, 0xF1, 0x63, 0xF1, 0x5B, 0xEE, 0xDC, /* 0x8C-0x8F */ - 0x00, 0x00, 0xF1, 0x65, 0xF1, 0x55, 0x00, 0x00, /* 0x90-0x93 */ - 0xC2, 0xE8, 0xF1, 0x5F, 0xC2, 0xEA, 0xC2, 0xF2, /* 0x94-0x97 */ - 0xC2, 0xF0, 0xF1, 0x61, 0xC2, 0xF1, 0xF1, 0x57, /* 0x98-0x9B */ - 0x00, 0x00, 0xF1, 0x58, 0xF1, 0x5D, 0xF1, 0x62, /* 0x9C-0x9F */ - 0x00, 0x00, 0xEE, 0xCD, 0xC2, 0xEB, 0xF1, 0x6A, /* 0xA0-0xA3 */ - 0xF1, 0x67, 0xF1, 0x6B, 0xF1, 0x5E, 0xF1, 0x5A, /* 0xA4-0xA7 */ - 0xF1, 0x68, 0xF3, 0x6A, 0xF1, 0x5C, 0x00, 0x00, /* 0xA8-0xAB */ - 0xC2, 0xEE, 0x00, 0x00, 0xC2, 0xED, 0xEE, 0xCF, /* 0xAC-0xAF */ - 0xC2, 0xEF, 0xF1, 0x64, 0xF1, 0x66, 0xC2, 0xEC, /* 0xB0-0xB3 */ - 0xF1, 0x69, 0xF1, 0x53, 0x00, 0x00, 0xF1, 0x56, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0xF3, 0x73, 0x00, 0x00, 0xF3, 0x63, 0xC3, 0xEB, /* 0xC0-0xC3 */ - 0xF3, 0x71, 0x00, 0x00, 0x00, 0x00, 0xF3, 0x61, /* 0xC4-0xC7 */ - 0xC3, 0xEC, 0x00, 0x00, 0xF3, 0x6C, 0x00, 0x00, /* 0xC8-0xCB */ - 0xF3, 0x68, 0xC3, 0xF1, 0xF3, 0x72, 0xF3, 0x62, /* 0xCC-0xCF */ - 0xF3, 0x65, 0xC3, 0xE9, 0xF3, 0x74, 0x00, 0x00, /* 0xD0-0xD3 */ - 0xF3, 0x6D, 0xF3, 0x70, 0xC3, 0xEF, 0xC3, 0xF4, /* 0xD4-0xD7 */ - 0xC3, 0xF2, 0xF3, 0x69, 0xF3, 0x64, 0x00, 0x00, /* 0xD8-0xDB */ - 0xC3, 0xED, 0xC3, 0xEE, 0xF3, 0x60, 0xC3, 0xEA, /* 0xDC-0xDF */ - 0x00, 0x00, 0xC3, 0xE8, 0xC3, 0xF0, 0xF3, 0x6F, /* 0xE0-0xE3 */ - 0xC3, 0xF3, 0x00, 0x00, 0xF3, 0x6B, 0xF3, 0x75, /* 0xE4-0xE7 */ - 0xC3, 0xF5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0xF3, 0x67, 0x00, 0x00, 0xF3, 0x6E, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xF4, 0xF3, 0xF5, 0x42, 0xF4, 0xF5, /* 0xF4-0xF7 */ - 0xF4, 0xFC, 0xF3, 0x66, 0xF4, 0xFA, 0xF4, 0xE9, /* 0xF8-0xFB */ - 0xF5, 0x40, 0xC4, 0xC3, 0xF4, 0xED, 0xF4, 0xFE, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_94[512] = { - 0xF4, 0xF4, 0x00, 0x00, 0x00, 0x00, 0xC4, 0xC2, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0x44, 0xF4, 0xF6, /* 0x04-0x07 */ - 0x00, 0x00, 0xF4, 0xFB, 0xF4, 0xFD, 0xF4, 0xE7, /* 0x08-0x0B */ - 0xF5, 0x41, 0xF4, 0xF2, 0xF4, 0xF7, 0xF4, 0xEB, /* 0x0C-0x0F */ - 0xF4, 0xEF, 0xF5, 0x43, 0xF4, 0xF9, 0xF4, 0xE8, /* 0x10-0x13 */ - 0xF4, 0xEC, 0xF4, 0xEE, 0xF4, 0xF8, 0x00, 0x00, /* 0x14-0x17 */ - 0xC4, 0xC1, 0xF4, 0xF1, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0xF4, 0xEA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xF4, 0xF0, 0xF6, 0x61, 0xF6, 0x66, 0xC5, 0x4F, /* 0x28-0x2B */ - 0xF6, 0x68, 0x00, 0x00, 0xC5, 0x49, 0x00, 0x00, /* 0x2C-0x2F */ - 0xF6, 0x64, 0xF6, 0x6A, 0xC5, 0x4E, 0xC5, 0x4A, /* 0x30-0x33 */ - 0x00, 0x00, 0xC5, 0x4B, 0xF6, 0x60, 0xF6, 0x67, /* 0x34-0x37 */ - 0xC5, 0x4D, 0xF6, 0x65, 0xC5, 0x4C, 0xF6, 0x5F, /* 0x38-0x3B */ - 0xF6, 0x63, 0xF6, 0x62, 0x00, 0x00, 0xF6, 0x5E, /* 0x3C-0x3F */ - 0xF6, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xC5, 0xB1, 0xF7, 0x6D, 0xF7, 0x70, 0xF7, 0x6C, /* 0x44-0x47 */ - 0xF7, 0x6E, 0xF7, 0x6F, 0xF7, 0x69, 0xF7, 0x6A, /* 0x48-0x4B */ - 0xF7, 0x67, 0x00, 0x00, 0x00, 0x00, 0xF7, 0x6B, /* 0x4C-0x4F */ - 0xF7, 0x68, 0xC5, 0xB2, 0xC5, 0xB3, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0xF8, 0x4B, 0x00, 0x00, 0xF8, 0x4D, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0xF8, 0x4C, 0xF8, 0x4E, 0x00, 0x00, /* 0x5C-0x5F */ - 0xC5, 0xE0, 0x00, 0x00, 0xF8, 0x4A, 0xC5, 0xDF, /* 0x60-0x63 */ - 0xC5, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0xF8, 0xCB, 0xF8, 0xCC, 0xC6, 0x44, 0xF8, 0xCA, /* 0x68-0x6B */ - 0x00, 0x00, 0xF9, 0x53, 0xF9, 0x52, 0xF9, 0x54, /* 0x6C-0x6F */ - 0xC6, 0x5F, 0xF9, 0x55, 0xC6, 0x5E, 0xF9, 0x56, /* 0x70-0x73 */ - 0xF9, 0x72, 0xF9, 0x75, 0xF9, 0x74, 0xC6, 0x68, /* 0x74-0x77 */ - 0xF9, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xC6, 0x72, 0xC6, 0x70, 0xC6, 0x71, 0xC6, 0x77, /* 0x7C-0x7F */ - - 0xF9, 0xC0, 0xF9, 0xC1, 0xF9, 0xBF, 0xF9, 0xC9, /* 0x80-0x83 */ -}; - -static const unsigned char u2c_95[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, 0xF8, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0xD8, 0x44, 0xDC, 0x78, /* 0x78-0x7B */ - 0xE8, 0xA5, 0xF3, 0x76, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xAA, 0xF9, 0x00, 0x00, 0xAD, 0xAC, 0xB0, 0x7B, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0xD8, 0x45, 0x00, 0x00, /* 0x84-0x87 */ - 0xD8, 0x46, 0xB3, 0xAC, 0x00, 0x00, 0xB6, 0x7D, /* 0x88-0x8B */ - 0xDC, 0x7A, 0xDC, 0x79, 0xB6, 0xA3, 0xB6, 0x7C, /* 0x8C-0x8F */ - 0xDC, 0x7B, 0xB6, 0x7E, 0xB6, 0xA2, 0xB6, 0xA1, /* 0x90-0x93 */ - 0xB6, 0x7B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xB9, 0x68, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xD0, /* 0x98-0x9B */ - 0xE0, 0xCE, 0x00, 0x00, 0xE0, 0xCF, 0xE0, 0xCD, /* 0x9C-0x9F */ - 0x00, 0x00, 0xBB, 0xD2, 0x00, 0x00, 0xBB, 0xD5, /* 0xA0-0xA3 */ - 0xBB, 0xD7, 0xBB, 0xD6, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xBB, 0xD3, 0xBB, 0xD4, 0x00, 0x00, 0xE8, 0xA7, /* 0xA8-0xAB */ - 0xE8, 0xA6, 0xBE, 0x5B, 0xE8, 0xA8, 0x00, 0x00, /* 0xAC-0xAF */ - 0xE8, 0xA9, 0xBE, 0x5C, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xEC, 0x4D, 0xEC, 0x4B, 0xEE, 0xF3, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xEC, 0x49, 0xEC, 0x4A, 0xC0, 0x46, /* 0xB8-0xBB */ - 0xEC, 0x46, 0xEC, 0x4E, 0xEC, 0x48, 0xEC, 0x4C, /* 0xBC-0xBF */ - 0xEE, 0xEF, 0x00, 0x00, 0x00, 0x00, 0xEE, 0xF1, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xEE, 0xF2, 0xC1, 0xF3, 0xEE, 0xEE, /* 0xC4-0xC7 */ - 0xC1, 0xF2, 0xEE, 0xF0, 0xC1, 0xEF, 0xC1, 0xF0, /* 0xC8-0xCB */ - 0xC1, 0xF1, 0xEC, 0x47, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0xC2, 0xF5, 0xF1, 0x6E, 0xF1, 0x6C, 0xF1, 0x6D, /* 0xD0-0xD3 */ - 0xC2, 0xF3, 0xC2, 0xF6, 0xC2, 0xF4, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0xF3, 0x77, 0xF3, 0x78, /* 0xD8-0xDB */ - 0xC3, 0xF6, 0x00, 0x00, 0xF5, 0x45, 0xF5, 0x47, /* 0xDC-0xDF */ - 0xF5, 0x46, 0xC4, 0xC4, 0xC5, 0x50, 0xF6, 0x6D, /* 0xE0-0xE3 */ - 0xF6, 0x6C, 0xF6, 0x6B, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ -}; - -static const unsigned char u2c_96[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xAA, 0xFA, 0x00, 0x00, 0xC9, 0xAA, 0x00, 0x00, /* 0x1C-0x1F */ - 0xCA, 0x58, 0xA6, 0xE9, 0xCA, 0x56, 0xCA, 0x59, /* 0x20-0x23 */ - 0xCA, 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xCB, 0xAE, 0x00, 0x00, 0xA8, 0xC1, 0x00, 0x00, /* 0x28-0x2B */ - 0xA8, 0xC2, 0xCB, 0xB0, 0xA8, 0xBF, 0xCB, 0xAF, /* 0x2C-0x2F */ - 0xCB, 0xAD, 0xA8, 0xC0, 0xA8, 0xBE, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0xCD, 0xD8, 0xCD, 0xDB, 0xAA, 0xFD, /* 0x38-0x3B */ - 0xCD, 0xDA, 0xCD, 0xD9, 0x00, 0x00, 0xAA, 0xFC, /* 0x3C-0x3F */ - 0xAA, 0xFB, 0x00, 0x00, 0xAB, 0x40, 0xCD, 0xDC, /* 0x40-0x43 */ - 0xAA, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xD0, 0xC6, 0xAD, 0xAE, /* 0x48-0x4B */ - 0xAD, 0xAF, 0xAD, 0xB0, 0xD0, 0xC7, 0xD0, 0xC3, /* 0x4C-0x4F */ - 0xAD, 0xAD, 0xD0, 0xC4, 0x00, 0x00, 0xD0, 0xC5, /* 0x50-0x53 */ - 0xD0, 0xC2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0xB0, 0xA4, 0x00, 0x00, 0x00, 0x00, 0xB0, 0xA1, /* 0x58-0x5B */ - 0xD4, 0x45, 0xB0, 0xA2, 0xB0, 0xA5, 0xD4, 0x46, /* 0x5C-0x5F */ - 0x00, 0x00, 0xB0, 0x7E, 0xB0, 0x7C, 0xB0, 0x7D, /* 0x60-0x63 */ - 0xB0, 0xA3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xB3, 0xAD, 0xD8, 0x49, /* 0x68-0x6B */ - 0xB3, 0xB5, 0xD8, 0x48, 0x00, 0x00, 0xD8, 0x4B, /* 0x6C-0x6F */ - 0xB3, 0xB1, 0xD8, 0x4A, 0xB6, 0xAB, 0xB3, 0xAF, /* 0x70-0x73 */ - 0xB3, 0xB2, 0xB3, 0xAE, 0xB3, 0xB3, 0xB3, 0xB4, /* 0x74-0x77 */ - 0xB3, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0xD8, 0x47, 0xB6, 0xA7, 0xDC, 0x7D, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xDC, 0xA3, 0x00, 0x00, 0x00, 0x00, 0xDC, 0xA2, /* 0x80-0x83 */ - 0xB6, 0xAC, 0xB6, 0xA8, 0xB6, 0xA9, 0xDC, 0x7C, /* 0x84-0x87 */ - 0xDC, 0x7E, 0xDC, 0xA1, 0xB6, 0xA4, 0xB6, 0xA6, /* 0x88-0x8B */ - 0x00, 0x00, 0xB6, 0xAA, 0xB6, 0xA5, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xE0, 0xD3, 0xE0, 0xD1, 0xE0, 0xD2, /* 0x90-0x93 */ - 0xB9, 0x6A, 0xB9, 0x6B, 0x00, 0x00, 0xE0, 0xD4, /* 0x94-0x97 */ - 0xB9, 0x69, 0xBB, 0xD8, 0x00, 0x00, 0xBB, 0xDA, /* 0x98-0x9B */ - 0xBB, 0xD9, 0x00, 0x00, 0xE4, 0xBB, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xE4, 0xBC, 0xE8, 0xAB, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xE8, 0xAA, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x47, /* 0xA4-0xA7 */ - 0xC0, 0x48, 0xEC, 0x4F, 0xC0, 0x49, 0x00, 0x00, /* 0xA8-0xAB */ - 0xEE, 0xF6, 0x00, 0x00, 0xEE, 0xF4, 0x00, 0x00, /* 0xAC-0xAF */ - 0xEE, 0xF5, 0xC1, 0xF4, 0x00, 0x00, 0xF1, 0x6F, /* 0xB0-0xB3 */ - 0xC3, 0xF7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xC1, 0xF5, 0xAB, 0x41, 0x00, 0x00, 0xB0, 0xA6, /* 0xB8-0xBB */ - 0xD4, 0x47, 0x00, 0x00, 0x00, 0x00, 0xD8, 0x4C, /* 0xBC-0xBF */ - 0xB3, 0xB6, 0xB6, 0xAD, 0xDC, 0xA4, 0xDC, 0xA6, /* 0xC0-0xC3 */ - 0xB6, 0xAF, 0xB6, 0xAE, 0xB6, 0xB0, 0xB6, 0xB1, /* 0xC4-0xC7 */ - 0xDC, 0xA5, 0xB9, 0x6E, 0xB9, 0x6F, 0xB9, 0x6D, /* 0xC8-0xCB */ - 0xBB, 0xDB, 0xB9, 0x6C, 0xE0, 0xD5, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0xBB, 0xDC, 0xE8, 0xAC, /* 0xD0-0xD3 */ - 0xEC, 0x50, 0xC0, 0x4A, 0xC1, 0xF6, 0xF1, 0x70, /* 0xD4-0xD7 */ - 0xF1, 0x74, 0xC2, 0xF9, 0xF1, 0x71, 0xC2, 0xFA, /* 0xD8-0xDB */ - 0xC2, 0xF8, 0xF1, 0x75, 0xC2, 0xFB, 0xF1, 0x73, /* 0xDC-0xDF */ - 0x00, 0x00, 0xF3, 0x79, 0xC2, 0xF7, 0xC3, 0xF8, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xF8, 0xCD, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xAB, 0x42, 0xB3, 0xB8, 0xB3, 0xB7, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB6, 0xB2, /* 0xEC-0xEF */ - 0xDC, 0xA8, 0xDC, 0xA7, 0xB6, 0xB3, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0xE0, 0xD9, 0xB9, 0x73, 0xB9, 0x70, /* 0xF4-0xF7 */ - 0xE0, 0xD8, 0xB9, 0x72, 0xE0, 0xD6, 0xB9, 0x71, /* 0xF8-0xFB */ - 0x00, 0x00, 0xE0, 0xD7, 0x00, 0x00, 0xE4, 0xBD, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_97[512] = { - 0xBB, 0xDD, 0x00, 0x00, 0xE8, 0xAF, 0x00, 0x00, /* 0x00-0x03 */ - 0xBE, 0x5D, 0xE8, 0xAD, 0xBE, 0x5E, 0xBE, 0x5F, /* 0x04-0x07 */ - 0xE8, 0xAE, 0xBE, 0x60, 0x00, 0x00, 0xEC, 0x51, /* 0x08-0x0B */ - 0x00, 0x00, 0xC0, 0x4E, 0xC0, 0x4B, 0xC0, 0x50, /* 0x0C-0x0F */ - 0xEC, 0x53, 0xC0, 0x4C, 0xEC, 0x52, 0xC0, 0x4F, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x4D, 0x00, 0x00, /* 0x14-0x17 */ - 0xEE, 0xF9, 0xEE, 0xFB, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xC1, 0xF7, 0xEE, 0xFA, 0xC1, 0xF8, 0xEE, 0xF8, /* 0x1C-0x1F */ - 0xEE, 0xF7, 0x00, 0x00, 0xF1, 0x77, 0xF1, 0x76, /* 0x20-0x23 */ - 0xC2, 0xFC, 0xF1, 0x78, 0xF3, 0x7E, 0xC3, 0xFA, /* 0x24-0x27 */ - 0xF3, 0x7D, 0xF3, 0x7A, 0xC3, 0xF9, 0xF3, 0x7B, /* 0x28-0x2B */ - 0xF3, 0x7C, 0x00, 0x00, 0xF5, 0x48, 0xF5, 0x49, /* 0x2C-0x2F */ - 0xC4, 0xC5, 0x00, 0x00, 0xC5, 0x53, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0xF6, 0x6E, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0xC5, 0x51, 0xC5, 0x52, 0xF6, 0x6F, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xC5, 0xB4, 0xC5, 0xB5, 0xF7, 0x71, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0xC6, 0x45, 0xF8, 0xCF, /* 0x40-0x43 */ - 0xC6, 0x47, 0x00, 0x00, 0xF8, 0xCE, 0xF8, 0xD0, /* 0x44-0x47 */ - 0xC6, 0x46, 0xF9, 0x57, 0x00, 0x00, 0xF9, 0xAD, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xAB, 0x43, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0xB9, 0x74, 0x00, 0x00, /* 0x54-0x57 */ - 0xE4, 0xBE, 0x00, 0x00, 0xE8, 0xB0, 0xC0, 0x51, /* 0x58-0x5B */ - 0xC0, 0x52, 0x00, 0x00, 0xAB, 0x44, 0x00, 0x00, /* 0x5C-0x5F */ - 0xBE, 0x61, 0xC3, 0xFB, 0xAD, 0xB1, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x53, 0x00, 0x00, /* 0x64-0x67 */ - 0xC5, 0xE2, 0xAD, 0xB2, 0xD8, 0x4D, 0x00, 0x00, /* 0x68-0x6B */ - 0xDC, 0xA9, 0x00, 0x00, 0xDC, 0xAB, 0x00, 0x00, /* 0x6C-0x6F */ - 0xDC, 0xAA, 0x00, 0x00, 0xE0, 0xDD, 0xE0, 0xDA, /* 0x70-0x73 */ - 0xB9, 0x75, 0x00, 0x00, 0xB9, 0x76, 0xE0, 0xDB, /* 0x74-0x77 */ - 0xE0, 0xDC, 0x00, 0x00, 0xE4, 0xC0, 0xE4, 0xC5, /* 0x78-0x7B */ - 0xBB, 0xDE, 0xE4, 0xBF, 0xE4, 0xC1, 0xE4, 0xC8, /* 0x7C-0x7F */ - - 0xE4, 0xC3, 0xE4, 0xC7, 0xE4, 0xC4, 0xE4, 0xC2, /* 0x80-0x83 */ - 0xE4, 0xC6, 0xBB, 0xDF, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0xE8, 0xB3, 0x00, 0x00, 0xE8, 0xB1, 0xBE, 0x63, /* 0x88-0x8B */ - 0x00, 0x00, 0xBE, 0x62, 0xE8, 0xB2, 0xBE, 0x64, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0xEC, 0x56, 0x00, 0x00, 0x00, 0x00, 0xEC, 0x55, /* 0x94-0x97 */ - 0xC0, 0x54, 0xEC, 0x54, 0xEE, 0xFC, 0x00, 0x00, /* 0x98-0x9B */ - 0xEE, 0xFE, 0xEF, 0x41, 0xEF, 0x40, 0x00, 0x00, /* 0x9C-0x9F */ - 0xC1, 0xF9, 0xEE, 0xFD, 0xF1, 0xA1, 0xC2, 0xFD, /* 0xA0-0xA3 */ - 0xF1, 0x7D, 0xF1, 0xA2, 0xC2, 0xFE, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xF1, 0x7B, 0x00, 0x00, 0xF1, 0x7E, 0xF1, 0x7C, /* 0xA8-0xAB */ - 0xF1, 0x79, 0xC3, 0x40, 0xF1, 0x7A, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF3, 0xA1, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xF3, 0xA3, 0xF3, 0xA2, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xF5, 0x4A, 0x00, 0x00, 0xF5, 0x4B, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF6, 0x70, /* 0xBC-0xBF */ - 0x00, 0x00, 0xC5, 0xB7, 0x00, 0x00, 0xC5, 0xB6, /* 0xC0-0xC3 */ - 0xF8, 0x4F, 0xF8, 0x50, 0xC6, 0x48, 0xF8, 0xD1, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xC6, 0x69, 0x00, 0x00, 0xAD, 0xB3, /* 0xC8-0xCB */ - 0xB6, 0xB4, 0xE4, 0xCA, 0xE4, 0xC9, 0xE8, 0xB5, /* 0xCC-0xCF */ - 0xE8, 0xB4, 0x00, 0x00, 0x00, 0x00, 0xC1, 0xFA, /* 0xD0-0xD3 */ - 0xEF, 0x43, 0xEF, 0x42, 0xF1, 0xA5, 0xF1, 0xA3, /* 0xD4-0xD7 */ - 0xF1, 0xA6, 0xF1, 0xA4, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xC3, 0xFC, 0xF3, 0xA4, 0xF3, 0xA5, 0xF3, 0xA6, /* 0xDC-0xDF */ - 0x00, 0x00, 0xF6, 0x71, 0x00, 0x00, 0xF7, 0x72, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xF8, 0xD2, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xAD, 0xB4, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xEC, 0x57, 0xEF, 0x44, 0x00, 0x00, 0xAD, 0xB5, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xBB, 0xE0, 0x00, 0x00, /* 0xF4-0xF7 */ - 0xEC, 0x58, 0xC3, 0x41, 0xF1, 0xA7, 0xC3, 0xFD, /* 0xF8-0xFB */ - 0x00, 0x00, 0xF5, 0x4C, 0xF5, 0x4D, 0xC5, 0x54, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_98[512] = { - 0xF8, 0x51, 0xAD, 0xB6, 0xB3, 0xBB, 0xB3, 0xBC, /* 0x00-0x03 */ - 0xD8, 0x4E, 0xB6, 0xB5, 0xB6, 0xB6, 0xDC, 0xAC, /* 0x04-0x07 */ - 0xB6, 0xB7, 0x00, 0x00, 0xB9, 0x7A, 0x00, 0x00, /* 0x08-0x0B */ - 0xB9, 0x7C, 0xE0, 0xDF, 0xE0, 0xE0, 0xE0, 0xDE, /* 0x0C-0x0F */ - 0xB9, 0x77, 0xB9, 0x78, 0xB9, 0x7B, 0xB9, 0x79, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0xE4, 0xCB, 0xBB, 0xE1, /* 0x14-0x17 */ - 0xBB, 0xE2, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xBC, /* 0x18-0x1B */ - 0xBE, 0x67, 0xE8, 0xB7, 0xE8, 0xB6, 0x00, 0x00, /* 0x1C-0x1F */ - 0xE8, 0xBB, 0xBE, 0x65, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0xC0, 0x5B, 0x00, 0x00, 0xE8, 0xB8, 0xE8, 0xBD, /* 0x24-0x27 */ - 0xE8, 0xBA, 0xE8, 0xB9, 0x00, 0x00, 0xBE, 0x66, /* 0x28-0x2B */ - 0x00, 0x00, 0xC0, 0x59, 0x00, 0x00, 0xEC, 0x5A, /* 0x2C-0x2F */ - 0xC0, 0x55, 0x00, 0x00, 0xEC, 0x5B, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0xEC, 0x59, 0x00, 0x00, 0xC0, 0x58, /* 0x34-0x37 */ - 0xC0, 0x56, 0xC0, 0x5A, 0x00, 0x00, 0xC0, 0x57, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0xEF, 0x45, 0x00, 0x00, 0xEF, 0x4A, /* 0x40-0x43 */ - 0xEF, 0x46, 0xEF, 0x49, 0xC1, 0xFB, 0x00, 0x00, /* 0x44-0x47 */ - 0xED, 0xD4, 0xEF, 0x48, 0xEF, 0x47, 0x00, 0x00, /* 0x48-0x4B */ - 0xC3, 0x44, 0xC3, 0x42, 0xC3, 0x45, 0xC3, 0x43, /* 0x4C-0x4F */ - 0xF1, 0xA8, 0xF1, 0xA9, 0xF1, 0xAA, 0xC3, 0x46, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF3, 0xAA, /* 0x54-0x57 */ - 0xC4, 0x40, 0xF3, 0xA8, 0x00, 0x00, 0xC4, 0x41, /* 0x58-0x5B */ - 0xF3, 0xA7, 0xF3, 0xA9, 0xC3, 0xFE, 0xF5, 0x51, /* 0x5C-0x5F */ - 0xF5, 0x4E, 0x00, 0x00, 0xF5, 0x4F, 0xF5, 0x50, /* 0x60-0x63 */ - 0xF6, 0x72, 0xC5, 0x56, 0x00, 0x00, 0xC5, 0x55, /* 0x64-0x67 */ - 0x00, 0x00, 0xF7, 0x74, 0xF7, 0x73, 0xC5, 0xB8, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC5, 0xE3, /* 0x6C-0x6F */ - 0xC6, 0x49, 0xC6, 0x60, 0xF9, 0x58, 0xF9, 0xAE, /* 0x70-0x73 */ - 0xF9, 0xAF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xAD, 0xB7, 0xDC, 0xAD, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0xE0, 0xE1, 0xE4, 0xCC, 0xE4, 0xCD, 0xBB, 0xE3, /* 0xAC-0xAF */ - 0x00, 0x00, 0xBB, 0xE4, 0xE8, 0xBE, 0xBE, 0x68, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0xC1, 0xFC, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xF1, 0xAB, 0x00, 0x00, 0xC3, 0x47, 0xF3, 0xAD, /* 0xB8-0xBB */ - 0xC4, 0x42, 0xF3, 0xAC, 0xF3, 0xAE, 0xF3, 0xAB, /* 0xBC-0xBF */ - 0xF6, 0x75, 0xF5, 0x52, 0xF5, 0x53, 0x00, 0x00, /* 0xC0-0xC3 */ - 0xC4, 0xC6, 0x00, 0x00, 0xF6, 0x74, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xF6, 0x73, 0x00, 0x00, 0xF7, 0x75, /* 0xC8-0xCB */ - 0xF9, 0xB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAD, 0xB8, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAD, 0xB9, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xB0, 0xA7, 0xD4, 0x48, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xD8, 0x4F, 0x00, 0x00, 0xB6, 0xB8, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xB6, 0xBB, 0xB6, 0xB9, 0xDC, 0xAE, /* 0xE8-0xEB */ - 0x00, 0x00, 0xB6, 0xBD, 0x00, 0x00, 0xB6, 0xBA, /* 0xEC-0xEF */ - 0x00, 0x00, 0x00, 0x00, 0xB6, 0xBC, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xB9, 0x7E, 0x00, 0x00, 0xE0, 0xE2, 0x00, 0x00, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xE0, 0xE3, 0xE8, 0xC0, 0x00, 0x00, /* 0xF8-0xFB */ - 0xB9, 0x7D, 0xB9, 0xA1, 0xB9, 0xA2, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_99[512] = { - 0xE4, 0xCF, 0x00, 0x00, 0xE4, 0xCE, 0xBB, 0xE5, /* 0x00-0x03 */ - 0x00, 0x00, 0xBB, 0xE6, 0x00, 0x00, 0xE4, 0xD0, /* 0x04-0x07 */ - 0xE8, 0xBF, 0xBB, 0xE8, 0xBE, 0x69, 0x00, 0x00, /* 0x08-0x0B */ - 0xBB, 0xE7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xC0, 0x5C, 0xE8, 0xC1, 0xBE, 0x6B, 0xBE, 0x6A, /* 0x10-0x13 */ - 0xE8, 0xC2, 0xE8, 0xC5, 0xE8, 0xC3, 0xE8, 0xC4, /* 0x14-0x17 */ - 0xBE, 0x6C, 0x00, 0x00, 0xC0, 0x61, 0xC0, 0x5F, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x5E, 0xEC, 0x5D, /* 0x1C-0x1F */ - 0x00, 0x00, 0xC0, 0x60, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0xEC, 0x5C, 0xEF, 0x4B, 0x00, 0x00, 0xEC, 0x5E, /* 0x24-0x27 */ - 0xC0, 0x5D, 0xEC, 0x5F, 0xEF, 0x4E, 0xEF, 0x4C, /* 0x28-0x2B */ - 0xEF, 0x4D, 0xEF, 0x52, 0xC3, 0x4B, 0xEF, 0x51, /* 0x2C-0x2F */ - 0xEF, 0x54, 0xEF, 0x53, 0xEF, 0x50, 0xEF, 0x4F, /* 0x30-0x33 */ - 0x00, 0x00, 0xC1, 0xFD, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xAE, 0x00, 0x00, /* 0x38-0x3B */ - 0xF1, 0xAD, 0xC3, 0x4A, 0xC3, 0x48, 0xC3, 0x49, /* 0x3C-0x3F */ - 0x00, 0x00, 0xF1, 0xAC, 0x00, 0x00, 0xF3, 0xB1, /* 0x40-0x43 */ - 0x00, 0x00, 0xC4, 0x43, 0x00, 0x00, 0xF3, 0xB0, /* 0x44-0x47 */ - 0xF3, 0xAF, 0xC4, 0x44, 0x00, 0x00, 0xF5, 0x58, /* 0x48-0x4B */ - 0xF5, 0x57, 0x00, 0x00, 0xF5, 0x55, 0x00, 0x00, /* 0x4C-0x4F */ - 0xF5, 0x54, 0xC4, 0xC8, 0xC4, 0xC7, 0xF5, 0x59, /* 0x50-0x53 */ - 0xF7, 0x76, 0xC5, 0xB9, 0xF6, 0x77, 0xC5, 0x57, /* 0x54-0x57 */ - 0xF6, 0x76, 0xF5, 0x56, 0x00, 0x00, 0xF7, 0x77, /* 0x58-0x5B */ - 0xC5, 0xE4, 0x00, 0x00, 0xC6, 0x61, 0xF9, 0x59, /* 0x5C-0x5F */ - 0x00, 0x00, 0xF9, 0xB1, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0xAD, 0xBA, 0xD8, 0x50, /* 0x94-0x97 */ - 0xEF, 0x55, 0xAD, 0xBB, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xE4, 0xD2, 0xE4, 0xD1, 0xEC, 0x60, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0xEF, 0x57, 0x00, 0x00, 0xEF, 0x56, /* 0xA0-0xA3 */ - 0x00, 0x00, 0xC3, 0x4C, 0xF3, 0xB2, 0xF3, 0xB3, /* 0xA4-0xA7 */ - 0xC4, 0xC9, 0x00, 0x00, 0x00, 0x00, 0xF9, 0xB2, /* 0xA8-0xAB */ - 0xB0, 0xA8, 0xB6, 0xBF, 0xB6, 0xBE, 0xE0, 0xE4, /* 0xAC-0xAF */ - 0xE0, 0xE6, 0xB9, 0xA4, 0xE0, 0xE5, 0xB9, 0xA3, /* 0xB0-0xB3 */ - 0xB9, 0xA5, 0xE0, 0xE7, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0xE4, 0xD4, 0xE4, 0xD6, 0xE4, 0xD5, /* 0xB8-0xBB */ - 0x00, 0x00, 0xE4, 0xD8, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0xBB, 0xE9, 0xE4, 0xD7, 0xE4, 0xD3, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xD9, /* 0xC4-0xC7 */ - 0x00, 0x00, 0xE8, 0xCC, 0x00, 0x00, 0xE8, 0xCF, /* 0xC8-0xCB */ - 0xE8, 0xD1, 0xE8, 0xC7, 0xE8, 0xCB, 0xE8, 0xC8, /* 0xCC-0xCF */ - 0xBE, 0x6E, 0xBE, 0x71, 0xBE, 0x73, 0xE8, 0xC9, /* 0xD0-0xD3 */ - 0xE8, 0xCA, 0xBE, 0x72, 0xE8, 0xCD, 0xE8, 0xD0, /* 0xD4-0xD7 */ - 0xE8, 0xCE, 0xBE, 0x74, 0x00, 0x00, 0xBE, 0x70, /* 0xD8-0xDB */ - 0xE8, 0xC6, 0xBE, 0x6D, 0x00, 0x00, 0xBE, 0x6F, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0xC0, 0x63, 0xEC, 0x66, /* 0xE0-0xE3 */ - 0xEC, 0x64, 0xEC, 0x63, 0x00, 0x00, 0xEC, 0x69, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xEC, 0x68, 0xEC, 0x67, 0x00, 0x00, /* 0xE8-0xEB */ - 0xEC, 0x62, 0xC0, 0x62, 0xEC, 0x61, 0x00, 0x00, /* 0xEC-0xEF */ - 0xEC, 0x65, 0xC0, 0x64, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0xEF, 0x5A, 0x00, 0x00, 0xEF, 0x5E, 0xEF, 0x5B, /* 0xF4-0xF7 */ - 0xEF, 0x5D, 0xEF, 0x5C, 0xEF, 0x59, 0xEF, 0x5F, /* 0xF8-0xFB */ - 0xEF, 0x62, 0xEF, 0x60, 0xEF, 0x61, 0xC2, 0x40, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_9A[512] = { - 0x00, 0x00, 0xC1, 0xFE, 0xEF, 0x58, 0xEF, 0x63, /* 0x00-0x03 */ - 0xF1, 0xB3, 0xF1, 0xB6, 0xF1, 0xB8, 0xF1, 0xB7, /* 0x04-0x07 */ - 0x00, 0x00, 0xF1, 0xB1, 0xF1, 0xB5, 0xF1, 0xB0, /* 0x08-0x0B */ - 0x00, 0x00, 0xF1, 0xB2, 0xC3, 0x4D, 0xF1, 0xAF, /* 0x0C-0x0F */ - 0x00, 0x00, 0xF1, 0xB4, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0xF3, 0xC0, 0xF3, 0xB5, 0xC4, 0x45, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0xC4, 0x46, 0xF3, 0xB4, 0xF3, 0xB9, /* 0x18-0x1B */ - 0xF3, 0xBF, 0xF3, 0xB7, 0xF3, 0xBE, 0x00, 0x00, /* 0x1C-0x1F */ - 0xF3, 0xBB, 0x00, 0x00, 0xF3, 0xBA, 0xF3, 0xBD, /* 0x20-0x23 */ - 0xF3, 0xB8, 0xF3, 0xB6, 0x00, 0x00, 0xF3, 0xBC, /* 0x24-0x27 */ - 0x00, 0x00, 0xF5, 0x60, 0xF5, 0x5E, 0xC4, 0xCA, /* 0x28-0x2B */ - 0xF5, 0x5D, 0xF5, 0x63, 0xF5, 0x61, 0x00, 0x00, /* 0x2C-0x2F */ - 0xC4, 0xCB, 0xF5, 0x5C, 0xF5, 0x5A, 0x00, 0x00, /* 0x30-0x33 */ - 0xF5, 0x5B, 0xC4, 0xCD, 0xF5, 0x5F, 0xC4, 0xCC, /* 0x34-0x37 */ - 0xF5, 0x62, 0xF6, 0x78, 0xF6, 0x7E, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0xF6, 0x79, 0xC5, 0x5B, 0xF6, 0xA1, /* 0x3C-0x3F */ - 0xC5, 0x5A, 0xF6, 0x7D, 0xF6, 0x7C, 0xC5, 0x59, /* 0x40-0x43 */ - 0xF6, 0x7B, 0xC5, 0x58, 0xF6, 0x7A, 0x00, 0x00, /* 0x44-0x47 */ - 0xF7, 0x7D, 0xF7, 0xA1, 0xF7, 0x7E, 0x00, 0x00, /* 0x48-0x4B */ - 0xF7, 0x7B, 0xC5, 0xBB, 0xF7, 0x78, 0xF7, 0x7C, /* 0x4C-0x4F */ - 0xF7, 0xA3, 0x00, 0x00, 0xF7, 0xA2, 0xF7, 0x79, /* 0x50-0x53 */ - 0xF7, 0x7A, 0xC5, 0xBA, 0xF8, 0x52, 0xC5, 0xE7, /* 0x54-0x57 */ - 0x00, 0x00, 0xF8, 0x53, 0xC5, 0xE5, 0xC5, 0xE6, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xD3, 0xC6, 0x4A, /* 0x5C-0x5F */ - 0xF9, 0x76, 0x00, 0x00, 0xC6, 0x6A, 0x00, 0x00, /* 0x60-0x63 */ - 0xF9, 0xB3, 0xC6, 0x6B, 0xF9, 0xB4, 0xF9, 0xB5, /* 0x64-0x67 */ - 0xF9, 0xC3, 0xF9, 0xC2, 0xC6, 0x7A, 0xF9, 0xCD, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xB0, 0xA9, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xE9, /* 0xA8-0xAB */ - 0x00, 0x00, 0xE0, 0xE8, 0x00, 0x00, 0xBB, 0xEA, /* 0xAC-0xAF */ - 0xBB, 0xEB, 0xE4, 0xDA, 0x00, 0x00, 0xE8, 0xD2, /* 0xB0-0xB3 */ - 0xEC, 0x6C, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x75, /* 0xB4-0xB7 */ - 0xC0, 0x65, 0xEC, 0x6A, 0x00, 0x00, 0xEC, 0x6D, /* 0xB8-0xBB */ - 0xC0, 0x66, 0x00, 0x00, 0xEF, 0x64, 0xEC, 0x6B, /* 0xBC-0xBF */ - 0xF1, 0xB9, 0xC3, 0x4E, 0xF3, 0xC1, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0x66, 0xF5, 0x64, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0x65, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0xF6, 0xA2, 0x00, 0x00, 0xC5, 0x5C, /* 0xCC-0xCF */ - 0xF7, 0xA4, 0xC5, 0xEA, 0xC5, 0xBC, 0xC5, 0xE8, /* 0xD0-0xD3 */ - 0xC5, 0xE9, 0xF8, 0xD4, 0xC6, 0x62, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xB0, 0xAA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0xF1, 0xBA, 0x00, 0x00, 0x00, 0x00, 0xD4, 0x49, /* 0xDC-0xDF */ - 0x00, 0x00, 0xB9, 0xA6, 0x00, 0x00, 0xE4, 0xDB, /* 0xE0-0xE3 */ - 0x00, 0x00, 0x00, 0x00, 0xBB, 0xEC, 0xE4, 0xDC, /* 0xE4-0xE7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE8, 0xD4, /* 0xE8-0xEB */ - 0xE8, 0xD3, 0xC0, 0x68, 0xBE, 0x76, 0xBE, 0x77, /* 0xEC-0xEF */ - 0x00, 0x00, 0xE8, 0xD7, 0xE8, 0xD6, 0xE8, 0xD5, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0xEC, 0x6E, 0xEC, 0x71, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xEC, 0x70, 0xEC, 0x6F, 0xC0, 0x67, /* 0xF8-0xFB */ - 0xEF, 0x68, 0xEF, 0x66, 0xEF, 0x65, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_9B[512] = { - 0x00, 0x00, 0xEF, 0x67, 0x00, 0x00, 0xC3, 0x4F, /* 0x00-0x03 */ - 0xF1, 0xBC, 0xF1, 0xBD, 0xC3, 0x50, 0x00, 0x00, /* 0x04-0x07 */ - 0xF1, 0xBB, 0x00, 0x00, 0xF3, 0xC3, 0xF3, 0xC2, /* 0x08-0x0B */ - 0xF3, 0xC5, 0xC4, 0x47, 0xF3, 0xC4, 0x00, 0x00, /* 0x0C-0x0F */ - 0xF5, 0x67, 0xF5, 0x69, 0xF5, 0x68, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xF6, 0xA3, 0xF6, 0xA6, 0xF6, 0xA4, /* 0x14-0x17 */ - 0xF6, 0xA5, 0xF7, 0xA5, 0xC5, 0xBD, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0x54, 0xF8, 0x55, /* 0x1C-0x1F */ - 0xF8, 0x56, 0x00, 0x00, 0xC6, 0x4B, 0xC6, 0x63, /* 0x20-0x23 */ - 0xF9, 0xB6, 0xB0, 0xAB, 0x00, 0x00, 0xBE, 0x78, /* 0x24-0x27 */ - 0xC0, 0x69, 0xF1, 0xBE, 0x00, 0x00, 0xF7, 0xA6, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0xF9, 0xC4, 0xD4, 0x4A, /* 0x2C-0x2F */ - 0x00, 0x00, 0xC6, 0x7B, 0xB0, 0xAC, 0xEC, 0x72, /* 0x30-0x33 */ - 0x00, 0x00, 0xF1, 0xBF, 0x00, 0x00, 0xF3, 0xC6, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0xF6, 0xA7, 0xF7, 0xA7, /* 0x38-0x3B */ - 0xB0, 0xAD, 0x00, 0x00, 0xE4, 0xDD, 0xE4, 0xDE, /* 0x3C-0x3F */ - 0x00, 0x00, 0xBB, 0xED, 0xBB, 0xEE, 0xE8, 0xD9, /* 0x40-0x43 */ - 0xBE, 0x7A, 0xBE, 0x79, 0xE8, 0xD8, 0x00, 0x00, /* 0x44-0x47 */ - 0xEF, 0x69, 0x00, 0x00, 0xF1, 0xC0, 0xF1, 0xC2, /* 0x48-0x4B */ - 0xF1, 0xC1, 0xC3, 0x53, 0xC3, 0x52, 0xC3, 0x51, /* 0x4C-0x4F */ - 0x00, 0x00, 0xC5, 0x5E, 0xF6, 0xA8, 0x00, 0x00, /* 0x50-0x53 */ - 0xC5, 0x5D, 0xF7, 0xA9, 0xF7, 0xA8, 0x00, 0x00, /* 0x54-0x57 */ - 0xC6, 0x4C, 0xF8, 0xD5, 0xB3, 0xBD, 0xE0, 0xEA, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE4, 0xE1, /* 0x5C-0x5F */ - 0xE4, 0xDF, 0xE4, 0xE0, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0xE8, 0xE2, 0x00, 0x00, 0xE8, 0xDD, 0xE8, 0xDA, /* 0x64-0x67 */ - 0xE8, 0xE1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0xE8, 0xE3, 0x00, 0x00, 0x00, 0x00, 0xBE, 0x7C, /* 0x6C-0x6F */ - 0xE8, 0xE0, 0xE8, 0xDC, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0xE8, 0xDB, 0xE8, 0xDF, 0xE8, 0xDE, 0xBE, 0x7B, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0xEC, 0x7D, 0xEC, 0x78, /* 0x78-0x7B */ - 0xEC, 0x76, 0xEC, 0xA1, 0xEC, 0x77, 0x00, 0x00, /* 0x7C-0x7F */ - - 0xEC, 0x73, 0x00, 0x00, 0xEC, 0x79, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0xEC, 0x74, 0xEF, 0x72, 0xEC, 0x75, /* 0x84-0x87 */ - 0xEC, 0xA2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xEC, 0x7C, 0xC0, 0x6A, 0xEC, 0x7B, 0xEC, 0x7A, /* 0x90-0x93 */ - 0x00, 0x00, 0xEC, 0x7E, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0x6A, 0xEF, 0x6D, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0x6C, 0x00, 0x00, /* 0x9C-0x9F */ - 0xEF, 0x74, 0xEF, 0x6F, 0xEF, 0x73, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xEF, 0x71, 0xEF, 0x70, 0xEF, 0x6E, 0x00, 0x00, /* 0xA4-0xA7 */ - 0xEF, 0x6B, 0x00, 0x00, 0xC2, 0x43, 0xC2, 0x42, /* 0xA8-0xAB */ - 0x00, 0x00, 0xC2, 0x44, 0xC2, 0x41, 0xEF, 0x75, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0xF1, 0xC8, 0xF1, 0xCB, 0x00, 0x00, /* 0xB4-0xB7 */ - 0xF1, 0xC9, 0xF1, 0xCD, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0xF1, 0xCE, 0x00, 0x00, 0xF1, 0xC6, /* 0xBC-0xBF */ - 0xC3, 0x58, 0xF1, 0xC7, 0x00, 0x00, 0xF1, 0xC5, /* 0xC0-0xC3 */ - 0xF1, 0xCC, 0x00, 0x00, 0xF1, 0xC4, 0xF1, 0xC3, /* 0xC4-0xC7 */ - 0xC3, 0x57, 0xC3, 0x55, 0xC3, 0x54, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xCA, /* 0xD0-0xD3 */ - 0xF3, 0xCF, 0xF3, 0xD5, 0xC4, 0x4A, 0xF3, 0xD0, /* 0xD4-0xD7 */ - 0x00, 0x00, 0xF3, 0xD3, 0xF3, 0xD7, 0xC4, 0x4B, /* 0xD8-0xDB */ - 0xF3, 0xD2, 0x00, 0x00, 0xF3, 0xCA, 0x00, 0x00, /* 0xDC-0xDF */ - 0xF3, 0xC9, 0xF3, 0xD6, 0xF3, 0xCD, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xF3, 0xCB, 0xF3, 0xD4, 0xF3, 0xCC, 0xC4, 0x49, /* 0xE4-0xE7 */ - 0xC4, 0x48, 0x00, 0x00, 0xF3, 0xC7, 0xF3, 0xC8, /* 0xE8-0xEB */ - 0xF3, 0xD1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0xF3, 0xCE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF0-0xF3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF5, 0x6C, /* 0xF4-0xF7 */ - 0xF5, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xF8-0xFB */ - 0x00, 0x00, 0xC3, 0x56, 0x00, 0x00, 0x00, 0x00, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_9C[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0xF5, 0x6D, 0xF5, 0x73, 0xF5, 0x71, /* 0x04-0x07 */ - 0xF5, 0x6B, 0xF5, 0x76, 0x00, 0x00, 0xF5, 0x6A, /* 0x08-0x0B */ - 0x00, 0x00, 0xC4, 0xCF, 0xF5, 0x72, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0xF5, 0x6E, 0xC4, 0xCE, /* 0x10-0x13 */ - 0xF5, 0x75, 0x00, 0x00, 0x00, 0x00, 0xF5, 0x74, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0xF6, 0xAB, 0xF6, 0xAA, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0xF6, 0xB1, 0x00, 0x00, 0xF6, 0xAD, /* 0x20-0x23 */ - 0xF6, 0xB0, 0xC5, 0x60, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xF6, 0xAE, 0xF6, 0xAF, 0x00, 0x00, 0xF6, 0xA9, /* 0x28-0x2B */ - 0xF6, 0xAC, 0xC5, 0x5F, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0xC5, 0xBF, 0xF7, 0xB4, 0xF7, 0xAF, /* 0x30-0x33 */ - 0xF7, 0xB3, 0x00, 0x00, 0xF7, 0xB6, 0xF7, 0xB2, /* 0x34-0x37 */ - 0x00, 0x00, 0xF7, 0xAE, 0x00, 0x00, 0xC5, 0xC1, /* 0x38-0x3B */ - 0xF7, 0xB1, 0xF7, 0xB5, 0xC5, 0xC0, 0xF7, 0xAC, /* 0x3C-0x3F */ - 0xF5, 0x70, 0xF7, 0xB0, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0xF7, 0xAD, 0x00, 0x00, 0xF7, 0xAA, 0x00, 0x00, /* 0x44-0x47 */ - 0xF7, 0xAB, 0xC5, 0xBE, 0xF8, 0x5A, 0xF8, 0x5C, /* 0x48-0x4B */ - 0xF8, 0x5F, 0xF8, 0x5B, 0xF8, 0x60, 0x00, 0x00, /* 0x4C-0x4F */ - 0xF8, 0x59, 0x00, 0x00, 0xF8, 0x57, 0x00, 0x00, /* 0x50-0x53 */ - 0xC5, 0xEB, 0xF8, 0x5D, 0xC5, 0xED, 0xC5, 0xEC, /* 0x54-0x57 */ - 0xF8, 0x58, 0xF8, 0x5E, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xDA, 0xC6, 0x4D, /* 0x5C-0x5F */ - 0xF8, 0xDB, 0x00, 0x00, 0xF8, 0xD9, 0xF8, 0xD6, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xD8, 0xF8, 0xD7, /* 0x64-0x67 */ - 0xF9, 0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0xF9, 0x5C, 0xF9, 0x5B, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0xF9, 0x79, 0x00, 0x00, 0xF9, 0x78, /* 0x70-0x73 */ - 0xF9, 0x77, 0xF9, 0x7A, 0x00, 0x00, 0xC6, 0x73, /* 0x74-0x77 */ - 0xC6, 0x74, 0xF9, 0xCA, 0xF9, 0xCE, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xB3, 0xBE, 0xDC, 0xAF, 0xE0, 0xED, /* 0xE4-0xE7 */ - 0x00, 0x00, 0xB9, 0xA7, 0xE0, 0xEB, 0x00, 0x00, /* 0xE8-0xEB */ - 0x00, 0x00, 0xE0, 0xEC, 0x00, 0x00, 0x00, 0x00, /* 0xEC-0xEF */ - 0x00, 0x00, 0xE4, 0xE2, 0xE4, 0xE3, 0xBB, 0xF1, /* 0xF0-0xF3 */ - 0xBB, 0xEF, 0xE4, 0xE4, 0xBB, 0xF0, 0xE8, 0xE8, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xE8, 0xEB, 0xE8, 0xE5, 0xE8, 0xEC, /* 0xF8-0xFB */ - 0xE8, 0xE4, 0xE8, 0xE6, 0x00, 0x00, 0xE8, 0xE7, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_9D[512] = { - 0xE8, 0xEA, 0x00, 0x00, 0x00, 0x00, 0xBE, 0xA1, /* 0x00-0x03 */ - 0xE8, 0xEF, 0xE8, 0xEE, 0xBE, 0x7D, 0xE8, 0xE9, /* 0x04-0x07 */ - 0xE8, 0xED, 0xBE, 0x7E, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xEC, 0xAC, 0x00, 0x00, 0xC0, 0x6F, 0x00, 0x00, /* 0x10-0x13 */ - 0xEC, 0xA7, 0xC0, 0x6B, 0x00, 0x00, 0xEC, 0xA4, /* 0x14-0x17 */ - 0xEC, 0xAA, 0xEC, 0xAD, 0x00, 0x00, 0xC0, 0x70, /* 0x18-0x1B */ - 0x00, 0x00, 0xEC, 0xA9, 0xEC, 0xA6, 0xEC, 0xAE, /* 0x1C-0x1F */ - 0xEC, 0xA5, 0x00, 0x00, 0xEC, 0xAB, 0xC0, 0x6C, /* 0x20-0x23 */ - 0x00, 0x00, 0xEC, 0xA3, 0xC0, 0x6D, 0x00, 0x00, /* 0x24-0x27 */ - 0xC0, 0x6E, 0xEC, 0xA8, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0xEF, 0xA9, 0xEF, 0x7A, 0xEF, 0x7B, /* 0x2C-0x2F */ - 0xEF, 0x7E, 0xEF, 0x7C, 0x00, 0x00, 0xEF, 0x76, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0xEF, 0x79, 0xEF, 0xA5, /* 0x34-0x37 */ - 0xEF, 0x7D, 0x00, 0x00, 0x00, 0x00, 0xC2, 0x45, /* 0x38-0x3B */ - 0x00, 0x00, 0xEF, 0xA7, 0xEF, 0xA4, 0xC2, 0x46, /* 0x3C-0x3F */ - 0xEF, 0xA6, 0xEF, 0x77, 0xEF, 0xA2, 0xEF, 0xA3, /* 0x40-0x43 */ - 0x00, 0x00, 0xEF, 0xA1, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xF1, 0xD2, 0xF1, 0xD4, /* 0x48-0x4B */ - 0xF1, 0xD7, 0x00, 0x00, 0x00, 0x00, 0xF1, 0xD1, /* 0x4C-0x4F */ - 0x00, 0x00, 0xC3, 0x59, 0xF1, 0xD9, 0xF1, 0xD0, /* 0x50-0x53 */ - 0xF1, 0xDA, 0x00, 0x00, 0xF1, 0xD6, 0xF1, 0xD8, /* 0x54-0x57 */ - 0xF1, 0xDC, 0xF1, 0xD5, 0xF1, 0xDD, 0xF1, 0xD3, /* 0x58-0x5B */ - 0xF1, 0xCF, 0xC3, 0x5A, 0x00, 0x00, 0xF1, 0xDB, /* 0x5C-0x5F */ - 0xC3, 0x5B, 0xC4, 0x4D, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEF, 0x78, /* 0x64-0x67 */ - 0xF3, 0xF1, 0xF3, 0xE8, 0xC4, 0x4F, 0xF3, 0xE4, /* 0x68-0x6B */ - 0xC4, 0x50, 0x00, 0x00, 0x00, 0x00, 0xF3, 0xED, /* 0x6C-0x6F */ - 0xF3, 0xE7, 0xF3, 0xDD, 0xC4, 0x4E, 0xF3, 0xEA, /* 0x70-0x73 */ - 0xF3, 0xE5, 0xF3, 0xE6, 0x00, 0x00, 0xF3, 0xD8, /* 0x74-0x77 */ - 0xF3, 0xDF, 0xF3, 0xEE, 0x00, 0x00, 0xF3, 0xEB, /* 0x78-0x7B */ - 0x00, 0x00, 0xF3, 0xE3, 0x00, 0x00, 0xF3, 0xEF, /* 0x7C-0x7F */ - - 0xF3, 0xDE, 0xF3, 0xD9, 0xF3, 0xEC, 0x00, 0x00, /* 0x80-0x83 */ - 0xF3, 0xDB, 0xF3, 0xE9, 0xF3, 0xE0, 0xF3, 0xF0, /* 0x84-0x87 */ - 0xF3, 0xDC, 0xC4, 0x4C, 0xF3, 0xDA, 0xF3, 0xE1, /* 0x88-0x8B */ - 0xF3, 0xE2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xF5, 0x7D, 0x00, 0x00, 0xF5, 0x7B, 0x00, 0x00, /* 0x90-0x93 */ - 0xF5, 0xA2, 0x00, 0x00, 0xF5, 0xAE, 0xF5, 0xA5, /* 0x94-0x97 */ - 0xF5, 0x7C, 0xF5, 0x78, 0xF5, 0xA7, 0xF5, 0x7E, /* 0x98-0x9B */ - 0xF5, 0xA3, 0xF5, 0x7A, 0xF5, 0xAA, 0xF5, 0x77, /* 0x9C-0x9F */ - 0xF5, 0xA1, 0xF5, 0xA6, 0xF5, 0xA8, 0xF5, 0xAB, /* 0xA0-0xA3 */ - 0xF5, 0x79, 0x00, 0x00, 0xF5, 0xAF, 0xF5, 0xB0, /* 0xA4-0xA7 */ - 0xF5, 0xA9, 0xF5, 0xAD, 0xF5, 0xA4, 0x00, 0x00, /* 0xA8-0xAB */ - 0xF6, 0xC1, 0xF6, 0xC4, 0x00, 0x00, 0xC5, 0x61, /* 0xAC-0xAF */ - 0x00, 0x00, 0xF6, 0xC3, 0xF6, 0xC8, 0xF6, 0xC6, /* 0xB0-0xB3 */ - 0xC5, 0x62, 0xF6, 0xBD, 0xF6, 0xB3, 0xF6, 0xB2, /* 0xB4-0xB7 */ - 0xC5, 0x64, 0xF6, 0xBF, 0xF6, 0xC0, 0xF6, 0xBC, /* 0xB8-0xBB */ - 0xF6, 0xB4, 0x00, 0x00, 0xF6, 0xB9, 0xF5, 0xAC, /* 0xBC-0xBF */ - 0x00, 0x00, 0xF6, 0xB5, 0xC5, 0x63, 0xF6, 0xBB, /* 0xC0-0xC3 */ - 0x00, 0x00, 0xF6, 0xBA, 0x00, 0x00, 0xF6, 0xB6, /* 0xC4-0xC7 */ - 0xF6, 0xC2, 0x00, 0x00, 0xF6, 0xB7, 0xF7, 0xBB, /* 0xC8-0xCB */ - 0xF6, 0xC5, 0xF6, 0xC7, 0xF6, 0xBE, 0xF6, 0xB8, /* 0xCC-0xCF */ - 0xF7, 0xBC, 0xF7, 0xBE, 0xF7, 0xB8, 0xC5, 0xC2, /* 0xD0-0xD3 */ - 0x00, 0x00, 0xF7, 0xC5, 0xF7, 0xC3, 0xC5, 0xC3, /* 0xD4-0xD7 */ - 0xF7, 0xC2, 0xF7, 0xC1, 0xF7, 0xBA, 0xF7, 0xB7, /* 0xD8-0xDB */ - 0xF7, 0xBD, 0xF7, 0xC6, 0xF7, 0xB9, 0xF7, 0xBF, /* 0xDC-0xDF */ - 0x00, 0x00, 0xF8, 0x69, 0xF8, 0x6E, 0xF8, 0x64, /* 0xE0-0xE3 */ - 0xF8, 0x67, 0xC5, 0xEE, 0xF8, 0x6B, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xF8, 0x72, 0xF7, 0xC0, 0x00, 0x00, 0xF8, 0x65, /* 0xE8-0xEB */ - 0xF8, 0x6F, 0xF8, 0x73, 0xF8, 0x6A, 0xF8, 0x63, /* 0xEC-0xEF */ - 0xF8, 0x6D, 0x00, 0x00, 0xF8, 0x6C, 0xF8, 0x71, /* 0xF0-0xF3 */ - 0xF8, 0x70, 0xF7, 0xC4, 0xF8, 0x68, 0xF8, 0x62, /* 0xF4-0xF7 */ - 0xF8, 0x66, 0xC6, 0x4E, 0xC6, 0x4F, 0xF8, 0x61, /* 0xF8-0xFB */ - 0x00, 0x00, 0xF8, 0xE6, 0xF8, 0xDD, 0xF8, 0xE5, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_9E[512] = { - 0xF8, 0xE2, 0xF8, 0xE3, 0xF8, 0xDC, 0xF8, 0xDF, /* 0x00-0x03 */ - 0xF8, 0xE7, 0xF8, 0xE1, 0xF8, 0xE0, 0xF8, 0xDE, /* 0x04-0x07 */ - 0x00, 0x00, 0xF8, 0xE4, 0x00, 0x00, 0xF9, 0x5D, /* 0x08-0x0B */ - 0x00, 0x00, 0xF9, 0x5E, 0x00, 0x00, 0xF9, 0x60, /* 0x0C-0x0F */ - 0xF9, 0x5F, 0xF9, 0x62, 0xF9, 0x61, 0xF9, 0x7C, /* 0x10-0x13 */ - 0xF9, 0x7B, 0xF9, 0xB7, 0x00, 0x00, 0xF9, 0xB8, /* 0x14-0x17 */ - 0x00, 0x00, 0xF9, 0xC5, 0xC6, 0x78, 0xC6, 0x7C, /* 0x18-0x1B */ - 0x00, 0x00, 0xF9, 0xCF, 0xC6, 0x7D, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x33 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x34-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x3C-0x3F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x53 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x54-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0xB3, 0xBF, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0xC4, 0xD0, 0xF6, 0xC9, 0x00, 0x00, /* 0x78-0x7B */ - 0xC6, 0x50, 0xC6, 0x51, 0x00, 0x00, 0xB3, 0xC0, /* 0x7C-0x7F */ - - 0xE0, 0xEE, 0x00, 0x00, 0xB9, 0xA8, 0xE8, 0xF0, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0xEC, 0xB0, 0xEC, 0xB1, /* 0x84-0x87 */ - 0xEC, 0xAF, 0xEF, 0xAB, 0xEF, 0xAA, 0xC2, 0x47, /* 0x88-0x8B */ - 0xF1, 0xDF, 0xEF, 0xAC, 0xF1, 0xDE, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0xF3, 0xF3, 0xC4, 0x51, 0xC4, 0x53, /* 0x90-0x93 */ - 0xF3, 0xF2, 0x00, 0x00, 0x00, 0x00, 0xC4, 0x52, /* 0x94-0x97 */ - 0x00, 0x00, 0xF5, 0xB1, 0xF5, 0xB3, 0xF5, 0xB2, /* 0x98-0x9B */ - 0xF6, 0xCA, 0xC5, 0x65, 0x00, 0x00, 0xC5, 0xEF, /* 0x9C-0x9F */ - 0xF8, 0xE8, 0xF9, 0x63, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xF9, 0xD2, 0xB3, 0xC1, 0x00, 0x00, 0xE4, 0xE5, /* 0xA4-0xA7 */ - 0x00, 0x00, 0xBE, 0xA2, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0xEC, 0xB3, 0xEC, 0xB2, 0x00, 0x00, /* 0xAC-0xAF */ - 0xEF, 0xAD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0xC4, 0x54, 0xC4, 0xD1, 0xF7, 0xC7, 0xF9, 0xCB, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB3, 0xC2, /* 0xB8-0xBB */ - 0xBB, 0xF2, 0x00, 0x00, 0xBE, 0xA3, 0x00, 0x00, /* 0xBC-0xBF */ - 0xF3, 0xF4, 0x00, 0x00, 0xF8, 0x74, 0xB6, 0xC0, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0xEF, 0xAE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0xC6, 0x64, 0xB6, 0xC1, 0xBE, 0xA4, 0xC2, 0x48, /* 0xCC-0xCF */ - 0xF8, 0x75, 0xB6, 0xC2, 0x00, 0x00, 0xE8, 0xF1, /* 0xD0-0xD3 */ - 0xC0, 0x72, 0xEC, 0xB4, 0xEC, 0xB5, 0x00, 0x00, /* 0xD4-0xD7 */ - 0xC0, 0x71, 0x00, 0x00, 0xEF, 0xAF, 0xC2, 0x4C, /* 0xD8-0xDB */ - 0xC2, 0x4A, 0xC2, 0x4B, 0xC2, 0x49, 0xF1, 0xE0, /* 0xDC-0xDF */ - 0xC3, 0x5C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xE0-0xE3 */ - 0xF5, 0xB5, 0xF5, 0xB4, 0xF5, 0xB7, 0xF5, 0xB6, /* 0xE4-0xE7 */ - 0xC4, 0xD2, 0x00, 0x00, 0x00, 0x00, 0xF6, 0xCB, /* 0xE8-0xEB */ - 0x00, 0x00, 0xF6, 0xCD, 0xF6, 0xCC, 0xC5, 0x66, /* 0xEC-0xEF */ - 0xF7, 0xC8, 0x00, 0x00, 0xF8, 0x76, 0xF8, 0x77, /* 0xF0-0xF3 */ - 0xC5, 0xF0, 0xF9, 0x64, 0xF9, 0x7D, 0xC6, 0x75, /* 0xF4-0xF7 */ - 0x00, 0x00, 0xDC, 0xB0, 0xEC, 0xB6, 0xEF, 0xB0, /* 0xF8-0xFB */ - 0xF3, 0xF5, 0xE0, 0xEF, 0x00, 0x00, 0xEF, 0xB1, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_9F[512] = { - 0xF1, 0xE2, 0xF1, 0xE1, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0x78, 0xC6, 0x52, /* 0x04-0x07 */ - 0x00, 0x00, 0xF9, 0x65, 0xF9, 0x7E, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0xB9, 0xA9, 0xE8, 0xF2, /* 0x0C-0x0F */ - 0xE8, 0xF3, 0x00, 0x00, 0xEC, 0xB7, 0xB9, 0xAA, /* 0x10-0x13 */ - 0x00, 0x00, 0xC3, 0x5D, 0xF1, 0xE3, 0x00, 0x00, /* 0x14-0x17 */ - 0xF6, 0xCF, 0xC5, 0x67, 0xF6, 0xD0, 0xF6, 0xCE, /* 0x18-0x1B */ - 0xF8, 0x79, 0x00, 0x00, 0xF8, 0xE9, 0x00, 0x00, /* 0x1C-0x1F */ - 0xB9, 0xAB, 0x00, 0x00, 0xEF, 0xB4, 0xEF, 0xB3, /* 0x20-0x23 */ - 0xEF, 0xB2, 0xF1, 0xE4, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0xF1, 0xE8, 0xF1, 0xE7, 0xF1, 0xE6, 0xF1, 0xE5, /* 0x28-0x2B */ - 0xC3, 0x5E, 0xF3, 0xF6, 0xF5, 0xB9, 0xC4, 0xD3, /* 0x2C-0x2F */ - 0xF5, 0xB8, 0xF6, 0xD1, 0xF7, 0xCB, 0xF7, 0xCA, /* 0x30-0x33 */ - 0xC5, 0xC4, 0xF7, 0xC9, 0xF8, 0x7C, 0xF8, 0x7B, /* 0x34-0x37 */ - 0xF8, 0x7A, 0x00, 0x00, 0x00, 0x00, 0xBB, 0xF3, /* 0x38-0x3B */ - 0x00, 0x00, 0xEC, 0xB8, 0xC2, 0x4D, 0x00, 0x00, /* 0x3C-0x3F */ - 0xF3, 0xF7, 0xF3, 0xF8, 0xF7, 0xCC, 0xF8, 0x7D, /* 0x40-0x43 */ - 0x00, 0x00, 0x00, 0x00, 0xF8, 0xEA, 0xF9, 0x66, /* 0x44-0x47 */ - 0xF9, 0xB9, 0xF9, 0xD4, 0xBB, 0xF4, 0xC2, 0x4E, /* 0x48-0x4B */ - 0xF1, 0xE9, 0xF3, 0xF9, 0xF6, 0xD2, 0xF8, 0x7E, /* 0x4C-0x4F */ - 0x00, 0x00, 0x00, 0x00, 0xBE, 0xA6, 0x00, 0x00, /* 0x50-0x53 */ - 0xEF, 0xB5, 0xF1, 0xEA, 0xF3, 0xFA, 0xF3, 0xFB, /* 0x54-0x57 */ - 0xF3, 0xFC, 0xF5, 0xBE, 0x00, 0x00, 0xF5, 0xBA, /* 0x58-0x5B */ - 0xC5, 0x68, 0xF5, 0xBD, 0xF5, 0xBC, 0xC4, 0xD4, /* 0x5C-0x5F */ - 0xF5, 0xBB, 0xC4, 0xD6, 0x00, 0x00, 0xC4, 0xD5, /* 0x60-0x63 */ - 0xF6, 0xD4, 0xF6, 0xD3, 0xC5, 0x69, 0xC5, 0x6A, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xC5, 0xC6, 0xF7, 0xCD, /* 0x68-0x6B */ - 0xC5, 0xC5, 0x00, 0x00, 0xF8, 0xA3, 0xF8, 0xA4, /* 0x6C-0x6F */ - 0xF8, 0xA2, 0xF8, 0xA1, 0xC6, 0x54, 0x00, 0x00, /* 0x70-0x73 */ - 0xF8, 0xEB, 0xF8, 0xEC, 0xF8, 0xED, 0xC6, 0x53, /* 0x74-0x77 */ - 0xF9, 0x67, 0xF9, 0x6A, 0xF9, 0x69, 0xF9, 0x68, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0xF9, 0xD3, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0xC0, 0x73, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0xC3, 0x65, 0xF5, 0xBF, 0xF6, 0xD5, 0x00, 0x00, /* 0x90-0x93 */ - 0xC5, 0xC7, 0xF7, 0xCE, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0xF9, 0xD5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0xC0, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0xEF, 0xB6, 0x00, 0x00, 0xF7, 0xCF, 0x00, 0x00, /* 0xA0-0xA3 */ - 0xF9, 0xA1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ -}; - -static const unsigned char u2c_DC[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ -}; - -static const unsigned char u2c_F9[512] = { - 0xB0, 0x5A, 0xA7, 0xF3, 0xA8, 0xAE, 0xB8, 0xEB, /* 0x00-0x03 */ - 0xB7, 0xC6, 0xA6, 0xEA, 0xA5, 0x79, 0xC0, 0x74, /* 0x04-0x07 */ - 0xC0, 0x74, 0xAB, 0xB4, 0xAA, 0xF7, 0xB3, 0xE2, /* 0x08-0x0B */ - 0xA9, 0x60, 0xC3, 0x69, 0xC4, 0xEE, 0xC3, 0xB9, /* 0x0C-0x0F */ - 0xC5, 0xDA, 0xC1, 0xB3, 0xBB, 0x72, 0xC5, 0xDE, /* 0x10-0x13 */ - 0xBC, 0xD6, 0xAC, 0xA5, 0xAF, 0x4F, 0xAF, 0x5F, /* 0x14-0x17 */ - 0xB8, 0xA8, 0xB9, 0x54, 0xC0, 0x64, 0xB6, 0xC3, /* 0x18-0x1B */ - 0xA7, 0x5A, 0xC4, 0xE6, 0xC4, 0xEA, 0xC4, 0xF5, /* 0x1C-0x1F */ - 0xC6, 0x7D, 0xB4, 0x50, 0xC0, 0xDD, 0xC2, 0xC5, /* 0x20-0x23 */ - 0xC4, 0xB0, 0xA9, 0xD4, 0xC3, 0xBE, 0xC4, 0xFA, /* 0x24-0x27 */ - 0xB4, 0x59, 0xAE, 0xD4, 0xAE, 0xF6, 0xAF, 0x54, /* 0x28-0x2B */ - 0x00, 0x00, 0xA8, 0xD3, 0xA7, 0x4E, 0xB3, 0xD2, /* 0x2C-0x2F */ - 0xBE, 0xDB, 0xC3, 0x72, 0xC4, 0x6C, 0xBF, 0x63, /* 0x30-0x33 */ - 0xA6, 0xD1, 0xC4, 0xAA, 0xB8, 0xB8, 0xB8, 0xF4, /* 0x34-0x37 */ - 0xC5, 0x53, 0xBE, 0x7C, 0xC6, 0x4F, 0xB8, 0x4C, /* 0x38-0x3B */ - 0xB8, 0x53, 0xBA, 0xF1, 0xDB, 0x77, 0xBF, 0xFD, /* 0x3C-0x3F */ - 0xB3, 0xC0, 0xBD, 0xD7, 0xC3, 0x62, 0xA7, 0xCB, /* 0x40-0x43 */ - 0xC5, 0xA2, 0xC5, 0xA4, 0xA8, 0x63, 0xBD, 0x55, /* 0x44-0x47 */ - 0xB8, 0xEF, 0xB9, 0x70, 0xC2, 0x53, 0xB9, 0xF0, /* 0x48-0x4B */ - 0xBC, 0xD3, 0xB2, 0x5C, 0xBA, 0x7C, 0xB2, 0xD6, /* 0x4C-0x4F */ - 0xC1, 0x5C, 0xAD, 0xAE, 0xB0, 0xC7, 0xA6, 0xD8, /* 0x50-0x53 */ - 0xBB, 0xFE, 0xAD, 0xE2, 0xB8, 0x57, 0xBA, 0xF0, /* 0x54-0x57 */ - 0xB5, 0xD9, 0xB3, 0xAE, 0xC5, 0xAA, 0xCE, 0xD4, /* 0x58-0x5B */ - 0xBC, 0xD6, 0xBF, 0xD5, 0xA4, 0xA6, 0xB9, 0xE7, /* 0x5C-0x5F */ - 0xAB, 0xE3, 0xB2, 0x76, 0xB2, 0xA7, 0xA5, 0x5F, /* 0x60-0x63 */ - 0xED, 0xA8, 0xAB, 0x4B, 0xB4, 0x5F, 0xA4, 0xA3, /* 0x64-0x67 */ - 0xAA, 0x63, 0xBC, 0xC6, 0xAF, 0xC1, 0xB0, 0xD1, /* 0x68-0x6B */ - 0xB6, 0xEB, 0xAC, 0xD9, 0xB8, 0xAD, 0xBB, 0xA1, /* 0x6C-0x6F */ - 0xB1, 0xFE, 0xA8, 0xB0, 0xA8, 0x48, 0xAC, 0x42, /* 0x70-0x73 */ - 0xAD, 0x59, 0xB1, 0xB0, 0xB2, 0xA4, 0xAB, 0x47, /* 0x74-0x77 */ - 0xA8, 0xE2, 0x00, 0x00, 0xB1, 0xE7, 0xC2, 0xB3, /* 0x78-0x7B */ - 0xA8, 0x7D, 0xBD, 0xCC, 0xB6, 0x71, 0xC0, 0x79, /* 0x7C-0x7F */ - - 0xA7, 0x66, 0xA4, 0x6B, 0xC3, 0x66, 0xAE, 0xC8, /* 0x80-0x83 */ - 0xC2, 0x6F, 0xC4, 0x72, 0xBE, 0x5B, 0xC6, 0x7A, /* 0x84-0x87 */ - 0xC4, 0x52, 0xBE, 0xA4, 0xA4, 0x4F, 0xBE, 0xE4, /* 0x88-0x8B */ - 0xBE, 0xFA, 0xF7, 0x65, 0xA6, 0x7E, 0xBC, 0xA6, /* 0x8C-0x8F */ - 0xC5, 0xCA, 0xBC, 0xBF, 0xBA, 0xA7, 0xB7, 0xD2, /* 0x90-0x93 */ - 0xE6, 0xA3, 0x00, 0x00, 0xBD, 0x6D, 0xC1, 0x70, /* 0x94-0x97 */ - 0xBD, 0xFB, 0xBD, 0xAC, 0xB3, 0x73, 0xC1, 0xE5, /* 0x98-0x9B */ - 0xA6, 0x43, 0xA6, 0x48, 0xAB, 0x7C, 0xAF, 0x50, /* 0x9C-0x9F */ - 0xB5, 0xF5, 0xBB, 0xA1, 0xB7, 0x47, 0xA9, 0xC0, /* 0xA0-0xA3 */ - 0xB1, 0xC9, 0xC0, 0xD4, 0xC3, 0xAE, 0xC2, 0x79, /* 0xA4-0xA7 */ - 0xA5, 0x4F, 0xCB, 0xF1, 0xB9, 0xE7, 0xC0, 0xAD, /* 0xA8-0xAB */ - 0xCC, 0xB0, 0xAC, 0xC2, 0xBC, 0xFC, 0xB2, 0xDC, /* 0xAC-0xAF */ - 0xB2, 0xE2, 0xB9, 0x61, 0xB9, 0x73, 0xC6, 0x46, /* 0xB0-0xB3 */ - 0xBB, 0xE2, 0xA8, 0xD2, 0xC2, 0xA7, 0xC4, 0xBF, /* 0xB4-0xB7 */ - 0xC1, 0xF5, 0xB4, 0x63, 0xA4, 0x46, 0xB9, 0xB1, /* 0xB8-0xBB */ - 0xBC, 0x64, 0xA7, 0xBF, 0xAE, 0xC6, 0xBC, 0xD6, /* 0xBC-0xBF */ - 0xBF, 0x52, 0xC0, 0xF8, 0xE7, 0x64, 0xBF, 0xF1, /* 0xC0-0xC3 */ - 0xC0, 0x73, 0xB7, 0x77, 0xA8, 0xBF, 0xBC, 0x42, /* 0xC4-0xC7 */ - 0xCC, 0xD8, 0xAC, 0x68, 0xAC, 0x79, 0xB7, 0xC8, /* 0xC8-0xCB */ - 0xAF, 0x5B, 0xAF, 0x64, 0xB2, 0xB8, 0xAF, 0xC3, /* 0xCC-0xCF */ - 0xC3, 0xFE, 0xA4, 0xBB, 0xBC, 0xAE, 0xB3, 0xB0, /* 0xD0-0xD3 */ - 0xAD, 0xDB, 0xB1, 0x5B, 0xB2, 0x5F, 0xBD, 0xFC, /* 0xD4-0xD7 */ - 0xAB, 0xDF, 0xB7, 0x58, 0xAE, 0xDF, 0xB2, 0x76, /* 0xD8-0xDB */ - 0xB6, 0xA9, 0xA7, 0x51, 0xA6, 0x4F, 0xBC, 0x69, /* 0xDC-0xDF */ - 0xA9, 0xF6, 0xA7, 0xF5, 0xB1, 0xF9, 0xAA, 0x64, /* 0xE0-0xE3 */ - 0xB2, 0x7A, 0xB5, 0x67, 0xBF, 0xA9, 0x00, 0x00, /* 0xE4-0xE7 */ - 0xB8, 0xCC, 0xA8, 0xBD, 0xC2, 0xF7, 0xB0, 0xCE, /* 0xE8-0xEB */ - 0xB7, 0xC4, 0xA7, 0x5B, 0xBF, 0x4D, 0xBF, 0x5A, /* 0xEC-0xEF */ - 0xC4, 0xA9, 0x00, 0x00, 0xC5, 0xEC, 0xC5, 0xEF, /* 0xF0-0xF3 */ - 0xAA, 0x4C, 0xB2, 0x4F, 0xC1, 0x7B, 0xA5, 0xDF, /* 0xF4-0xF7 */ - 0xB2, 0xC1, 0xB2, 0xC9, 0xAA, 0xAC, 0xAA, 0xA5, /* 0xF8-0xFB */ - 0xC3, 0xD1, 0xA4, 0xB0, 0xAF, 0xF9, 0xA8, 0xEB, /* 0xFC-0xFF */ -}; - -static const unsigned char u2c_FA[512] = { - 0xA4, 0xC1, 0xAB, 0xD7, 0xA9, 0xDD, 0xBF, 0x7D, /* 0x00-0x03 */ - 0xA6, 0x76, 0xAC, 0x7D, 0xBC, 0xC9, 0xBF, 0xE7, /* 0x04-0x07 */ - 0xA6, 0xE6, 0xAD, 0xB0, 0xA8, 0xA3, 0xB9, 0xF8, /* 0x08-0x0B */ - 0xC9, 0x4A, 0xDD, 0xFC, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0xB6, 0xEF, 0x00, 0x00, 0xB4, 0xB8, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0xE8, 0xF9, 0xBD, 0xDE, 0xAF, 0x71, /* 0x14-0x17 */ - 0x00, 0x00, 0xAF, 0xAB, 0xB2, 0xBB, 0xBA, 0xD6, /* 0x18-0x1B */ - 0xB9, 0x74, 0xBA, 0xEB, 0xA6, 0xD0, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0xBD, 0xD1, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0xB6, 0x68, 0xB3, 0xA3, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0xB6, 0xBA, 0xB9, 0x7D, /* 0x28-0x2B */ - 0xC0, 0x5D, 0xC5, 0x62, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ -}; - -static const unsigned char u2c_FE[512] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x03 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x04-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0C-0x0F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x13 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x14-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x1C-0x1F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x23 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x24-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x2C-0x2F */ - 0xA1, 0x4A, 0xA1, 0x57, 0x00, 0x00, 0xA1, 0x59, /* 0x30-0x33 */ - 0xA1, 0x5B, 0xA1, 0x5F, 0xA1, 0x60, 0xA1, 0x63, /* 0x34-0x37 */ - 0xA1, 0x64, 0xA1, 0x67, 0xA1, 0x68, 0xA1, 0x6B, /* 0x38-0x3B */ - 0xA1, 0x6C, 0xA1, 0x6F, 0xA1, 0x70, 0xA1, 0x73, /* 0x3C-0x3F */ - 0xA1, 0x74, 0xA1, 0x77, 0xA1, 0x78, 0xA1, 0x7B, /* 0x40-0x43 */ - 0xA1, 0x7C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x44-0x47 */ - 0x00, 0x00, 0xA1, 0xC6, 0xA1, 0xC7, 0xA1, 0xCA, /* 0x48-0x4B */ - 0xA1, 0xCB, 0xA1, 0xC8, 0xA1, 0xC9, 0xA1, 0x5C, /* 0x4C-0x4F */ - 0xA1, 0x4D, 0xA1, 0x4E, 0xA1, 0x4F, 0x00, 0x00, /* 0x50-0x53 */ - 0xA1, 0x51, 0xA1, 0x52, 0xA1, 0x53, 0xA1, 0x54, /* 0x54-0x57 */ - 0x00, 0x00, 0xA1, 0x7D, 0xA1, 0x7E, 0xA1, 0xA1, /* 0x58-0x5B */ - 0xA1, 0xA2, 0xA1, 0xA3, 0xA1, 0xA4, 0xA1, 0xCC, /* 0x5C-0x5F */ - 0xA1, 0xCD, 0xA1, 0xCE, 0xA1, 0xDE, 0xA1, 0xDF, /* 0x60-0x63 */ - 0xA1, 0xE0, 0xA1, 0xE1, 0xA1, 0xE2, 0x00, 0x00, /* 0x64-0x67 */ - 0xA2, 0x42, 0xA2, 0x4C, 0xA2, 0x4D, 0xA2, 0x4E, /* 0x68-0x6B */ -}; - -static const unsigned char u2c_FF[512] = { - 0x00, 0x00, 0xA1, 0x49, 0xA1, 0xA8, 0xA1, 0xAD, /* 0x00-0x03 */ - 0xA2, 0x43, 0xA2, 0x48, 0xA1, 0xAE, 0xA1, 0xA6, /* 0x04-0x07 */ - 0xA1, 0x5D, 0xA1, 0x5E, 0xA1, 0xAF, 0xA1, 0xCF, /* 0x08-0x0B */ - 0xA1, 0x41, 0xA1, 0xD0, 0xA1, 0x44, 0xA1, 0xFE, /* 0x0C-0x0F */ - 0xA2, 0xAF, 0xA2, 0xB0, 0xA2, 0xB1, 0xA2, 0xB2, /* 0x10-0x13 */ - 0xA2, 0xB3, 0xA2, 0xB4, 0xA2, 0xB5, 0xA2, 0xB6, /* 0x14-0x17 */ - 0xA2, 0xB7, 0xA2, 0xB8, 0xA1, 0x47, 0xA1, 0x46, /* 0x18-0x1B */ - 0xA1, 0xD5, 0xA1, 0xD7, 0xA1, 0xD6, 0xA1, 0x48, /* 0x1C-0x1F */ - 0xA2, 0x49, 0xA2, 0xCF, 0xA2, 0xD0, 0xA2, 0xD1, /* 0x20-0x23 */ - 0xA2, 0xD2, 0xA2, 0xD3, 0xA2, 0xD4, 0xA2, 0xD5, /* 0x24-0x27 */ - 0xA2, 0xD6, 0xA2, 0xD7, 0xA2, 0xD8, 0xA2, 0xD9, /* 0x28-0x2B */ - 0xA2, 0xDA, 0xA2, 0xDB, 0xA2, 0xDC, 0xA2, 0xDD, /* 0x2C-0x2F */ - 0xA2, 0xDE, 0xA2, 0xDF, 0xA2, 0xE0, 0xA2, 0xE1, /* 0x30-0x33 */ - 0xA2, 0xE2, 0xA2, 0xE3, 0xA2, 0xE4, 0xA2, 0xE5, /* 0x34-0x37 */ - 0xA2, 0xE6, 0xA2, 0xE7, 0xA2, 0xE8, 0xA1, 0x65, /* 0x38-0x3B */ - 0xA2, 0x40, 0xA1, 0x66, 0xA1, 0x73, 0xA1, 0xC4, /* 0x3C-0x3F */ - 0xA1, 0xA5, 0xA2, 0xE9, 0xA2, 0xEA, 0xA2, 0xEB, /* 0x40-0x43 */ - 0xA2, 0xEC, 0xA2, 0xED, 0xA2, 0xEE, 0xA2, 0xEF, /* 0x44-0x47 */ - 0xA2, 0xF0, 0xA2, 0xF1, 0xA2, 0xF2, 0xA2, 0xF3, /* 0x48-0x4B */ - 0xA2, 0xF4, 0xA2, 0xF5, 0xA2, 0xF6, 0xA2, 0xF7, /* 0x4C-0x4F */ - 0xA2, 0xF8, 0xA2, 0xF9, 0xA2, 0xFA, 0xA2, 0xFB, /* 0x50-0x53 */ - 0xA2, 0xFC, 0xA2, 0xFD, 0xA2, 0xFE, 0xA3, 0x40, /* 0x54-0x57 */ - 0xA3, 0x41, 0xA3, 0x42, 0xA3, 0x43, 0xA1, 0x61, /* 0x58-0x5B */ - 0xA1, 0x55, 0xA1, 0x62, 0xA1, 0xE3, 0x00, 0x00, /* 0x5C-0x5F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x63 */ - 0xA1, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x64-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x6C-0x6F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x73 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x74-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x7C-0x7F */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x83 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x84-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x8C-0x8F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x93 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x94-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9B */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x9C-0x9F */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA0-0xA3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA4-0xA7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xA8-0xAB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xAC-0xAF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB0-0xB3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB4-0xB7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xB8-0xBB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xBC-0xBF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC0-0xC3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC4-0xC7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xC8-0xCB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xCC-0xCF */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD0-0xD3 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD4-0xD7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xD8-0xDB */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xDC-0xDF */ - 0xA2, 0x46, 0xA2, 0x47, 0x00, 0x00, 0xA1, 0xC3, /* 0xE0-0xE3 */ - 0x00, 0x00, 0xA2, 0x44, 0x00, 0x00, 0x00, 0x00, /* 0xE4-0xE7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - NULL, NULL, u2c_02, u2c_03, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - u2c_20, u2c_21, u2c_22, u2c_23, NULL, u2c_25, u2c_26, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - u2c_30, u2c_31, u2c_32, u2c_33, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, u2c_4E, u2c_4F, - u2c_50, u2c_51, u2c_52, u2c_53, u2c_54, u2c_55, u2c_56, u2c_57, - u2c_58, u2c_59, u2c_5A, u2c_5B, u2c_5C, u2c_5D, u2c_5E, u2c_5F, - u2c_60, u2c_61, u2c_62, u2c_63, u2c_64, u2c_65, u2c_66, u2c_67, - u2c_68, u2c_69, u2c_6A, u2c_6B, u2c_6C, u2c_6D, u2c_6E, u2c_6F, - u2c_70, u2c_71, u2c_72, u2c_73, u2c_74, u2c_75, u2c_76, u2c_77, - u2c_78, u2c_79, u2c_7A, u2c_7B, u2c_7C, u2c_7D, u2c_7E, u2c_7F, - u2c_80, u2c_81, u2c_82, u2c_83, u2c_84, u2c_85, u2c_86, u2c_87, - u2c_88, u2c_89, u2c_8A, u2c_8B, u2c_8C, u2c_8D, u2c_8E, u2c_8F, - u2c_90, u2c_91, u2c_92, u2c_93, u2c_94, u2c_95, u2c_96, u2c_97, - u2c_98, u2c_99, u2c_9A, u2c_9B, u2c_9C, u2c_9D, u2c_9E, u2c_9F, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, u2c_DC, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, u2c_F9, u2c_FA, NULL, NULL, NULL, u2c_FE, u2c_FF, }; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(const wchar_t uni, - unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni&0xFF; - unsigned char ch = (uni>>8)&0xFF; - int n; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - - uni2charset = page_uni2charset[ch]; - if (uni2charset) { - if (boundlen <= 1) - return -ENAMETOOLONG; - out[0] = uni2charset[cl*2]; - out[1] = uni2charset[cl*2+1]; - if (out[0] == 0x00 && out[1] == 0x00) - return -EINVAL; - n = 2; - } else if (ch==0 && cl) { - out[0] = cl; - n = 1; - } - else - return -EINVAL; - - return n; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, - wchar_t *uni) -{ - unsigned char ch, cl; - const wchar_t *charset2uni; - int n; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - if (boundlen == 1) { - *uni = rawstring[0]; - return 1; - } - - ch = rawstring[0]; - cl = rawstring[1]; - - charset2uni = page_charset2uni[ch]; - if (charset2uni && cl) { - *uni = charset2uni[cl]; - if (*uni == 0x0000) - return -EINVAL; - n = 2; - } else{ - *uni = ch; - n = 1; - } - return n; -} - -static struct nls_table table = { - .charset = "cp950", - .alias = "big5", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_cp950(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_cp950(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_cp950) -module_exit(exit_nls_cp950) - -MODULE_LICENSE("Dual BSD/GPL"); -MODULE_ALIAS_NLS(big5); diff --git a/src/linux/fs/nls/nls_euc-jp.c b/src/linux/fs/nls/nls_euc-jp.c deleted file mode 100644 index 162b3f1..0000000 --- a/src/linux/fs/nls/nls_euc-jp.c +++ /dev/null @@ -1,580 +0,0 @@ -/* - * linux/fs/nls/nls_euc-jp.c - * - * Added `OSF/JVC Recommended Code Set Conversion Specification - * between Japanese EUC and Shift-JIS' support: - * (http://www.opengroup.or.jp/jvc/cde/sjis-euc-e.html) - */ - -#include -#include -#include -#include -#include - -static struct nls_table *p_nls; - -#define IS_SJIS_LOW_BYTE(l) ((0x40 <= (l)) && ((l) <= 0xFC) && ((l) != 0x7F)) -/* JIS X 0208 (include NEC spesial characters) */ -#define IS_SJIS_JISX0208(h, l) ((((0x81 <= (h)) && ((h) <= 0x9F)) \ - || ((0xE0 <= (h)) && ((h) <= 0xEA))) \ - && IS_SJIS_LOW_BYTE(l)) -#define IS_SJIS_JISX0201KANA(c) ((0xA1 <= (c)) && ((c) <= 0xDF)) -#define IS_SJIS_UDC_LOW(h, l) (((0xF0 <= (h)) && ((h) <= 0xF4)) \ - && IS_SJIS_LOW_BYTE(l)) -#define IS_SJIS_UDC_HI(h, l) (((0xF5 <= (h)) && ((h) <= 0xF9)) \ - && IS_SJIS_LOW_BYTE(l)) -#define IS_SJIS_IBM(h, l) (((0xFA <= (h)) && ((h) <= 0xFC)) \ - && IS_SJIS_LOW_BYTE(l)) -#define IS_SJIS_NECIBM(h, l) (((0xED <= (h)) && ((h) <= 0xEE)) \ - && IS_SJIS_LOW_BYTE(l)) -#define MAP_SJIS2EUC(sjis_hi, sjis_lo, sjis_p, euc_hi, euc_lo, euc_p) { \ - if ((sjis_lo) >= 0x9F) { \ - (euc_hi) = (sjis_hi) * 2 - (((sjis_p) * 2 - (euc_p)) - 1); \ - (euc_lo) = (sjis_lo) + 2; \ - } else { \ - (euc_hi) = (sjis_hi) * 2 - ((sjis_p) * 2 - (euc_p)); \ - (euc_lo) = (sjis_lo) + ((sjis_lo) >= 0x7F ? 0x60 : 0x61); \ - } \ -} while(0) - -#define SS2 (0x8E) /* Single Shift 2 */ -#define SS3 (0x8F) /* Single Shift 3 */ -#define IS_EUC_BYTE(c) ((0xA1 <= (c)) && ((c) <= 0xFE)) -#define IS_EUC_JISX0208(h, l) (IS_EUC_BYTE(h) && IS_EUC_BYTE(l)) -#define IS_EUC_JISX0201KANA(h, l) (((h) == SS2) && (0xA1 <= (l) && (l) <= 0xDF)) -#define IS_EUC_UDC_LOW(h, l) (((0xF5 <= (h)) && ((h) <= 0xFE)) \ - && IS_EUC_BYTE(l)) -#define IS_EUC_UDC_HI(h, l) IS_EUC_UDC_LOW(h, l) /* G3 block */ -#define MAP_EUC2SJIS(euc_hi, euc_lo, euc_p, sjis_hi, sjis_lo, sjis_p) { \ - if ((euc_hi) & 1) { \ - (sjis_hi) = (euc_hi) / 2 + ((sjis_p) - (euc_p) / 2); \ - (sjis_lo) = (euc_lo) - ((euc_lo) >= 0xE0 ? 0x60 : 0x61); \ - } else { \ - (sjis_hi) = (euc_hi) / 2 + (((sjis_p) - (euc_p) / 2) - 1); \ - (sjis_lo) = (euc_lo) - 2; \ - } \ -} while(0) - -/* SJIS IBM extended characters to EUC map */ -static const unsigned char sjisibm2euc_map[][2] = { - {0xF3, 0xF3}, {0xF3, 0xF4}, {0xF3, 0xF5}, {0xF3, 0xF6}, {0xF3, 0xF7}, - {0xF3, 0xF8}, {0xF3, 0xF9}, {0xF3, 0xFA}, {0xF3, 0xFB}, {0xF3, 0xFC}, - {0xF3, 0xFD}, {0xF3, 0xFE}, {0xF4, 0xA1}, {0xF4, 0xA2}, {0xF4, 0xA3}, - {0xF4, 0xA4}, {0xF4, 0xA5}, {0xF4, 0xA6}, {0xF4, 0xA7}, {0xF4, 0xA8}, - {0xA2, 0xCC}, {0xA2, 0xC3}, {0xF4, 0xA9}, {0xF4, 0xAA}, {0xF4, 0xAB}, - {0xF4, 0xAC}, {0xF4, 0xAD}, {0xA2, 0xE8}, {0xD4, 0xE3}, {0xDC, 0xDF}, - {0xE4, 0xE9}, {0xE3, 0xF8}, {0xD9, 0xA1}, {0xB1, 0xBB}, {0xF4, 0xAE}, - {0xC2, 0xAD}, {0xC3, 0xFC}, {0xE4, 0xD0}, {0xC2, 0xBF}, {0xBC, 0xF4}, - {0xB0, 0xA9}, {0xB0, 0xC8}, {0xF4, 0xAF}, {0xB0, 0xD2}, {0xB0, 0xD4}, - {0xB0, 0xE3}, {0xB0, 0xEE}, {0xB1, 0xA7}, {0xB1, 0xA3}, {0xB1, 0xAC}, - {0xB1, 0xA9}, {0xB1, 0xBE}, {0xB1, 0xDF}, {0xB1, 0xD8}, {0xB1, 0xC8}, - {0xB1, 0xD7}, {0xB1, 0xE3}, {0xB1, 0xF4}, {0xB1, 0xE1}, {0xB2, 0xA3}, - {0xF4, 0xB0}, {0xB2, 0xBB}, {0xB2, 0xE6}, {0x00, 0x00}, {0xB2, 0xED}, - {0xB2, 0xF5}, {0xB2, 0xFC}, {0xF4, 0xB1}, {0xB3, 0xB5}, {0xB3, 0xD8}, - {0xB3, 0xDB}, {0xB3, 0xE5}, {0xB3, 0xEE}, {0xB3, 0xFB}, {0xF4, 0xB2}, - {0xF4, 0xB3}, {0xB4, 0xC0}, {0xB4, 0xC7}, {0xB4, 0xD0}, {0xB4, 0xDE}, - {0xF4, 0xB4}, {0xB5, 0xAA}, {0xF4, 0xB5}, {0xB5, 0xAF}, {0xB5, 0xC4}, - {0xB5, 0xE8}, {0xF4, 0xB6}, {0xB7, 0xC2}, {0xB7, 0xE4}, {0xB7, 0xE8}, - {0xB7, 0xE7}, {0xF4, 0xB7}, {0xF4, 0xB8}, {0xF4, 0xB9}, {0xB8, 0xCE}, - {0xB8, 0xE1}, {0xB8, 0xF5}, {0xB8, 0xF7}, {0xB8, 0xF8}, {0xB8, 0xFC}, - {0xB9, 0xAF}, {0xB9, 0xB7}, {0xBA, 0xBE}, {0xBA, 0xDB}, {0xCD, 0xAA}, - {0xBA, 0xE1}, {0xF4, 0xBA}, {0xBA, 0xEB}, {0xBB, 0xB3}, {0xBB, 0xB8}, - {0xF4, 0xBB}, {0xBB, 0xCA}, {0xF4, 0xBC}, {0xF4, 0xBD}, {0xBB, 0xD0}, - {0xBB, 0xDE}, {0xBB, 0xF4}, {0xBB, 0xF5}, {0xBB, 0xF9}, {0xBC, 0xE4}, - {0xBC, 0xED}, {0xBC, 0xFE}, {0xF4, 0xBE}, {0xBD, 0xC2}, {0xBD, 0xE7}, - {0xF4, 0xBF}, {0xBD, 0xF0}, {0xBE, 0xB0}, {0xBE, 0xAC}, {0xF4, 0xC0}, - {0xBE, 0xB3}, {0xBE, 0xBD}, {0xBE, 0xCD}, {0xBE, 0xC9}, {0xBE, 0xE4}, - {0xBF, 0xA8}, {0xBF, 0xC9}, {0xC0, 0xC4}, {0xC0, 0xE4}, {0xC0, 0xF4}, - {0xC1, 0xA6}, {0xF4, 0xC1}, {0xC1, 0xF5}, {0xC1, 0xFC}, {0xF4, 0xC2}, - {0xC1, 0xF8}, {0xC2, 0xAB}, {0xC2, 0xA1}, {0xC2, 0xA5}, {0xF4, 0xC3}, - {0xC2, 0xB8}, {0xC2, 0xBA}, {0xF4, 0xC4}, {0xC2, 0xC4}, {0xC2, 0xD2}, - {0xC2, 0xD7}, {0xC2, 0xDB}, {0xC2, 0xDE}, {0xC2, 0xED}, {0xC2, 0xF0}, - {0xF4, 0xC5}, {0xC3, 0xA1}, {0xC3, 0xB5}, {0xC3, 0xC9}, {0xC3, 0xB9}, - {0xF4, 0xC6}, {0xC3, 0xD8}, {0xC3, 0xFE}, {0xF4, 0xC7}, {0xC4, 0xCC}, - {0xF4, 0xC8}, {0xC4, 0xD9}, {0xC4, 0xEA}, {0xC4, 0xFD}, {0xF4, 0xC9}, - {0xC5, 0xA7}, {0xC5, 0xB5}, {0xC5, 0xB6}, {0xF4, 0xCA}, {0xC5, 0xD5}, - {0xC6, 0xB8}, {0xC6, 0xD7}, {0xC6, 0xE0}, {0xC6, 0xEA}, {0xC6, 0xE3}, - {0xC7, 0xA1}, {0xC7, 0xAB}, {0xC7, 0xC7}, {0xC7, 0xC3}, {0xC7, 0xCB}, - {0xC7, 0xCF}, {0xC7, 0xD9}, {0xF4, 0xCB}, {0xF4, 0xCC}, {0xC7, 0xE6}, - {0xC7, 0xEE}, {0xC7, 0xFC}, {0xC7, 0xEB}, {0xC7, 0xF0}, {0xC8, 0xB1}, - {0xC8, 0xE5}, {0xC8, 0xF8}, {0xC9, 0xA6}, {0xC9, 0xAB}, {0xC9, 0xAD}, - {0xF4, 0xCD}, {0xC9, 0xCA}, {0xC9, 0xD3}, {0xC9, 0xE9}, {0xC9, 0xE3}, - {0xC9, 0xFC}, {0xC9, 0xF4}, {0xC9, 0xF5}, {0xF4, 0xCE}, {0xCA, 0xB3}, - {0xCA, 0xBD}, {0xCA, 0xEF}, {0xCA, 0xF1}, {0xCB, 0xAE}, {0xF4, 0xCF}, - {0xCB, 0xCA}, {0xCB, 0xE6}, {0xCB, 0xEA}, {0xCB, 0xF0}, {0xCB, 0xF4}, - {0xCB, 0xEE}, {0xCC, 0xA5}, {0xCB, 0xF9}, {0xCC, 0xAB}, {0xCC, 0xAE}, - {0xCC, 0xAD}, {0xCC, 0xB2}, {0xCC, 0xC2}, {0xCC, 0xD0}, {0xCC, 0xD9}, - {0xF4, 0xD0}, {0xCD, 0xBB}, {0xF4, 0xD1}, {0xCE, 0xBB}, {0xF4, 0xD2}, - {0xCE, 0xBA}, {0xCE, 0xC3}, {0xF4, 0xD3}, {0xCE, 0xF2}, {0xB3, 0xDD}, - {0xCF, 0xD5}, {0xCF, 0xE2}, {0xCF, 0xE9}, {0xCF, 0xED}, {0xF4, 0xD4}, - {0xF4, 0xD5}, {0xF4, 0xD6}, {0x00, 0x00}, {0xF4, 0xD7}, {0xD0, 0xE5}, - {0xF4, 0xD8}, {0xD0, 0xE9}, {0xD1, 0xE8}, {0xF4, 0xD9}, {0xF4, 0xDA}, - {0xD1, 0xEC}, {0xD2, 0xBB}, {0xF4, 0xDB}, {0xD3, 0xE1}, {0xD3, 0xE8}, - {0xD4, 0xA7}, {0xF4, 0xDC}, {0xF4, 0xDD}, {0xD4, 0xD4}, {0xD4, 0xF2}, - {0xD5, 0xAE}, {0xF4, 0xDE}, {0xD7, 0xDE}, {0xF4, 0xDF}, {0xD8, 0xA2}, - {0xD8, 0xB7}, {0xD8, 0xC1}, {0xD8, 0xD1}, {0xD8, 0xF4}, {0xD9, 0xC6}, - {0xD9, 0xC8}, {0xD9, 0xD1}, {0xF4, 0xE0}, {0xF4, 0xE1}, {0xF4, 0xE2}, - {0xF4, 0xE3}, {0xF4, 0xE4}, {0xDC, 0xD3}, {0xDD, 0xC8}, {0xDD, 0xD4}, - {0xDD, 0xEA}, {0xDD, 0xFA}, {0xDE, 0xA4}, {0xDE, 0xB0}, {0xF4, 0xE5}, - {0xDE, 0xB5}, {0xDE, 0xCB}, {0xF4, 0xE6}, {0xDF, 0xB9}, {0xF4, 0xE7}, - {0xDF, 0xC3}, {0xF4, 0xE8}, {0xF4, 0xE9}, {0xE0, 0xD9}, {0xF4, 0xEA}, - {0xF4, 0xEB}, {0xE1, 0xE2}, {0xF4, 0xEC}, {0xF4, 0xED}, {0xF4, 0xEE}, - {0xE2, 0xC7}, {0xE3, 0xA8}, {0xE3, 0xA6}, {0xE3, 0xA9}, {0xE3, 0xAF}, - {0xE3, 0xB0}, {0xE3, 0xAA}, {0xE3, 0xAB}, {0xE3, 0xBC}, {0xE3, 0xC1}, - {0xE3, 0xBF}, {0xE3, 0xD5}, {0xE3, 0xD8}, {0xE3, 0xD6}, {0xE3, 0xDF}, - {0xE3, 0xE3}, {0xE3, 0xE1}, {0xE3, 0xD4}, {0xE3, 0xE9}, {0xE4, 0xA6}, - {0xE3, 0xF1}, {0xE3, 0xF2}, {0xE4, 0xCB}, {0xE4, 0xC1}, {0xE4, 0xC3}, - {0xE4, 0xBE}, {0xF4, 0xEF}, {0xE4, 0xC0}, {0xE4, 0xC7}, {0xE4, 0xBF}, - {0xE4, 0xE0}, {0xE4, 0xDE}, {0xE4, 0xD1}, {0xF4, 0xF0}, {0xE4, 0xDC}, - {0xE4, 0xD2}, {0xE4, 0xDB}, {0xE4, 0xD4}, {0xE4, 0xFA}, {0xE4, 0xEF}, - {0xE5, 0xB3}, {0xE5, 0xBF}, {0xE5, 0xC9}, {0xE5, 0xD0}, {0xE5, 0xE2}, - {0xE5, 0xEA}, {0xE5, 0xEB}, {0xF4, 0xF1}, {0xF4, 0xF2}, {0xF4, 0xF3}, - {0xE6, 0xE8}, {0xE6, 0xEF}, {0xE7, 0xAC}, {0xF4, 0xF4}, {0xE7, 0xAE}, - {0xF4, 0xF5}, {0xE7, 0xB1}, {0xF4, 0xF6}, {0xE7, 0xB2}, {0xE8, 0xB1}, - {0xE8, 0xB6}, {0xF4, 0xF7}, {0xF4, 0xF8}, {0xE8, 0xDD}, {0xF4, 0xF9}, - {0xF4, 0xFA}, {0xE9, 0xD1}, {0xF4, 0xFB}, {0xE9, 0xED}, {0xEA, 0xCD}, - {0xF4, 0xFC}, {0xEA, 0xDB}, {0xEA, 0xE6}, {0xEA, 0xEA}, {0xEB, 0xA5}, - {0xEB, 0xFB}, {0xEB, 0xFA}, {0xF4, 0xFD}, {0xEC, 0xD6}, {0xF4, 0xFE}, -}; - -#define IS_EUC_IBM2JISX0208(h, l) \ - (((h) == 0xA2 && (l) == 0xCC) || ((h) == 0xA2 && (l) == 0xE8)) - -/* EUC to SJIS IBM extended characters map (G3 JIS X 0212 block) */ -static struct { - unsigned short euc; - unsigned char sjis[2]; -} euc2sjisibm_jisx0212_map[] = { - {0xA2C3, {0xFA, 0x55}}, {0xB0A9, {0xFA, 0x68}}, {0xB0C8, {0xFA, 0x69}}, - {0xB0D2, {0xFA, 0x6B}}, {0xB0D4, {0xFA, 0x6C}}, {0xB0E3, {0xFA, 0x6D}}, - {0xB0EE, {0xFA, 0x6E}}, {0xB1A3, {0xFA, 0x70}}, {0xB1A7, {0xFA, 0x6F}}, - {0xB1A9, {0xFA, 0x72}}, {0xB1AC, {0xFA, 0x71}}, {0xB1BB, {0xFA, 0x61}}, - {0xB1BE, {0xFA, 0x73}}, {0xB1C8, {0xFA, 0x76}}, {0xB1D7, {0xFA, 0x77}}, - {0xB1D8, {0xFA, 0x75}}, {0xB1DF, {0xFA, 0x74}}, {0xB1E1, {0xFA, 0x7A}}, - {0xB1E3, {0xFA, 0x78}}, {0xB1F4, {0xFA, 0x79}}, {0xB2A3, {0xFA, 0x7B}}, - {0xB2BB, {0xFA, 0x7D}}, {0xB2E6, {0xFA, 0x7E}}, {0xB2ED, {0xFA, 0x80}}, - {0xB2F5, {0xFA, 0x81}}, {0xB2FC, {0xFA, 0x82}}, {0xB3B5, {0xFA, 0x84}}, - {0xB3D8, {0xFA, 0x85}}, {0xB3DB, {0xFA, 0x86}}, {0xB3DD, {0xFB, 0x77}}, - {0xB3E5, {0xFA, 0x87}}, {0xB3EE, {0xFA, 0x88}}, {0xB3FB, {0xFA, 0x89}}, - {0xB4C0, {0xFA, 0x8C}}, {0xB4C7, {0xFA, 0x8D}}, {0xB4D0, {0xFA, 0x8E}}, - {0xB4DE, {0xFA, 0x8F}}, {0xB5AA, {0xFA, 0x91}}, {0xB5AF, {0xFA, 0x93}}, - {0xB5C4, {0xFA, 0x94}}, {0xB5E8, {0xFA, 0x95}}, {0xB7C2, {0xFA, 0x97}}, - {0xB7E4, {0xFA, 0x98}}, {0xB7E7, {0xFA, 0x9A}}, {0xB7E8, {0xFA, 0x99}}, - {0xB8CE, {0xFA, 0x9E}}, {0xB8E1, {0xFA, 0x9F}}, {0xB8F5, {0xFA, 0xA0}}, - {0xB8F7, {0xFA, 0xA1}}, {0xB8F8, {0xFA, 0xA2}}, {0xB8FC, {0xFA, 0xA3}}, - {0xB9AF, {0xFA, 0xA4}}, {0xB9B7, {0xFA, 0xA5}}, {0xBABE, {0xFA, 0xA6}}, - {0xBADB, {0xFA, 0xA7}}, {0xBAE1, {0xFA, 0xA9}}, {0xBAEB, {0xFA, 0xAB}}, - {0xBBB3, {0xFA, 0xAC}}, {0xBBB8, {0xFA, 0xAD}}, {0xBBCA, {0xFA, 0xAF}}, - {0xBBD0, {0xFA, 0xB2}}, {0xBBDE, {0xFA, 0xB3}}, {0xBBF4, {0xFA, 0xB4}}, - {0xBBF5, {0xFA, 0xB5}}, {0xBBF9, {0xFA, 0xB6}}, {0xBCE4, {0xFA, 0xB7}}, - {0xBCED, {0xFA, 0xB8}}, {0xBCF4, {0xFA, 0x67}}, {0xBCFE, {0xFA, 0xB9}}, - {0xBDC2, {0xFA, 0xBB}}, {0xBDE7, {0xFA, 0xBC}}, {0xBDF0, {0xFA, 0xBE}}, - {0xBEAC, {0xFA, 0xC0}}, {0xBEB0, {0xFA, 0xBF}}, {0xBEB3, {0xFA, 0xC2}}, - {0xBEBD, {0xFA, 0xC3}}, {0xBEC9, {0xFA, 0xC5}}, {0xBECD, {0xFA, 0xC4}}, - {0xBEE4, {0xFA, 0xC6}}, {0xBFA8, {0xFA, 0xC7}}, {0xBFC9, {0xFA, 0xC8}}, - {0xC0C4, {0xFA, 0xC9}}, {0xC0E4, {0xFA, 0xCA}}, {0xC0F4, {0xFA, 0xCB}}, - {0xC1A6, {0xFA, 0xCC}}, {0xC1F5, {0xFA, 0xCE}}, {0xC1F8, {0xFA, 0xD1}}, - {0xC1FC, {0xFA, 0xCF}}, {0xC2A1, {0xFA, 0xD3}}, {0xC2A5, {0xFA, 0xD4}}, - {0xC2AB, {0xFA, 0xD2}}, {0xC2AD, {0xFA, 0x63}}, {0xC2B8, {0xFA, 0xD6}}, - {0xC2BA, {0xFA, 0xD7}}, {0xC2BF, {0xFA, 0x66}}, {0xC2C4, {0xFA, 0xD9}}, - {0xC2D2, {0xFA, 0xDA}}, {0xC2D7, {0xFA, 0xDB}}, {0xC2DB, {0xFA, 0xDC}}, - {0xC2DE, {0xFA, 0xDD}}, {0xC2ED, {0xFA, 0xDE}}, {0xC2F0, {0xFA, 0xDF}}, - {0xC3A1, {0xFA, 0xE1}}, {0xC3B5, {0xFA, 0xE2}}, {0xC3B9, {0xFA, 0xE4}}, - {0xC3C9, {0xFA, 0xE3}}, {0xC3D8, {0xFA, 0xE6}}, {0xC3FC, {0xFA, 0x64}}, - {0xC3FE, {0xFA, 0xE7}}, {0xC4CC, {0xFA, 0xE9}}, {0xC4D9, {0xFA, 0xEB}}, - {0xC4EA, {0xFA, 0xEC}}, {0xC4FD, {0xFA, 0xED}}, {0xC5A7, {0xFA, 0xEF}}, - {0xC5B5, {0xFA, 0xF0}}, {0xC5B6, {0xFA, 0xF1}}, {0xC5D5, {0xFA, 0xF3}}, - {0xC6B8, {0xFA, 0xF4}}, {0xC6D7, {0xFA, 0xF5}}, {0xC6E0, {0xFA, 0xF6}}, - {0xC6E3, {0xFA, 0xF8}}, {0xC6EA, {0xFA, 0xF7}}, {0xC7A1, {0xFA, 0xF9}}, - {0xC7AB, {0xFA, 0xFA}}, {0xC7C3, {0xFA, 0xFC}}, {0xC7C7, {0xFA, 0xFB}}, - {0xC7CB, {0xFB, 0x40}}, {0xC7CF, {0xFB, 0x41}}, {0xC7D9, {0xFB, 0x42}}, - {0xC7E6, {0xFB, 0x45}}, {0xC7EB, {0xFB, 0x48}}, {0xC7EE, {0xFB, 0x46}}, - {0xC7F0, {0xFB, 0x49}}, {0xC7FC, {0xFB, 0x47}}, {0xC8B1, {0xFB, 0x4A}}, - {0xC8E5, {0xFB, 0x4B}}, {0xC8F8, {0xFB, 0x4C}}, {0xC9A6, {0xFB, 0x4D}}, - {0xC9AB, {0xFB, 0x4E}}, {0xC9AD, {0xFB, 0x4F}}, {0xC9CA, {0xFB, 0x51}}, - {0xC9D3, {0xFB, 0x52}}, {0xC9E3, {0xFB, 0x54}}, {0xC9E9, {0xFB, 0x53}}, - {0xC9F4, {0xFB, 0x56}}, {0xC9F5, {0xFB, 0x57}}, {0xC9FC, {0xFB, 0x55}}, - {0xCAB3, {0xFB, 0x59}}, {0xCABD, {0xFB, 0x5A}}, {0xCAEF, {0xFB, 0x5B}}, - {0xCAF1, {0xFB, 0x5C}}, {0xCBAE, {0xFB, 0x5D}}, {0xCBCA, {0xFB, 0x5F}}, - {0xCBE6, {0xFB, 0x60}}, {0xCBEA, {0xFB, 0x61}}, {0xCBEE, {0xFB, 0x64}}, - {0xCBF0, {0xFB, 0x62}}, {0xCBF4, {0xFB, 0x63}}, {0xCBF9, {0xFB, 0x66}}, - {0xCCA5, {0xFB, 0x65}}, {0xCCAB, {0xFB, 0x67}}, {0xCCAD, {0xFB, 0x69}}, - {0xCCAE, {0xFB, 0x68}}, {0xCCB2, {0xFB, 0x6A}}, {0xCCC2, {0xFB, 0x6B}}, - {0xCCD0, {0xFB, 0x6C}}, {0xCCD9, {0xFB, 0x6D}}, {0xCDAA, {0xFA, 0xA8}}, - {0xCDBB, {0xFB, 0x6F}}, {0xCEBA, {0xFB, 0x73}}, {0xCEBB, {0xFB, 0x71}}, - {0xCEC3, {0xFB, 0x74}}, {0xCEF2, {0xFB, 0x76}}, {0xCFD5, {0xFB, 0x78}}, - {0xCFE2, {0xFB, 0x79}}, {0xCFE9, {0xFB, 0x7A}}, {0xCFED, {0xFB, 0x7B}}, - {0xD0E5, {0xFB, 0x81}}, {0xD0E9, {0xFB, 0x83}}, {0xD1E8, {0xFB, 0x84}}, - {0xD1EC, {0xFB, 0x87}}, {0xD2BB, {0xFB, 0x88}}, {0xD3E1, {0xFB, 0x8A}}, - {0xD3E8, {0xFB, 0x8B}}, {0xD4A7, {0xFB, 0x8C}}, {0xD4D4, {0xFB, 0x8F}}, - {0xD4E3, {0xFA, 0x5C}}, {0xD4F2, {0xFB, 0x90}}, {0xD5AE, {0xFB, 0x91}}, - {0xD7DE, {0xFB, 0x93}}, {0xD8A2, {0xFB, 0x95}}, {0xD8B7, {0xFB, 0x96}}, - {0xD8C1, {0xFB, 0x97}}, {0xD8D1, {0xFB, 0x98}}, {0xD8F4, {0xFB, 0x99}}, - {0xD9A1, {0xFA, 0x60}}, {0xD9C6, {0xFB, 0x9A}}, {0xD9C8, {0xFB, 0x9B}}, - {0xD9D1, {0xFB, 0x9C}}, {0xDCD3, {0xFB, 0xA2}}, {0xDCDF, {0xFA, 0x5D}}, - {0xDDC8, {0xFB, 0xA3}}, {0xDDD4, {0xFB, 0xA4}}, {0xDDEA, {0xFB, 0xA5}}, - {0xDDFA, {0xFB, 0xA6}}, {0xDEA4, {0xFB, 0xA7}}, {0xDEB0, {0xFB, 0xA8}}, - {0xDEB5, {0xFB, 0xAA}}, {0xDECB, {0xFB, 0xAB}}, {0xDFB9, {0xFB, 0xAD}}, - {0xDFC3, {0xFB, 0xAF}}, {0xE0D9, {0xFB, 0xB2}}, {0xE1E2, {0xFB, 0xB5}}, - {0xE2C7, {0xFB, 0xB9}}, {0xE3A6, {0xFB, 0xBB}}, {0xE3A8, {0xFB, 0xBA}}, - {0xE3A9, {0xFB, 0xBC}}, {0xE3AA, {0xFB, 0xBF}}, {0xE3AB, {0xFB, 0xC0}}, - {0xE3AF, {0xFB, 0xBD}}, {0xE3B0, {0xFB, 0xBE}}, {0xE3BC, {0xFB, 0xC1}}, - {0xE3BF, {0xFB, 0xC3}}, {0xE3C1, {0xFB, 0xC2}}, {0xE3D4, {0xFB, 0xCA}}, - {0xE3D5, {0xFB, 0xC4}}, {0xE3D6, {0xFB, 0xC6}}, {0xE3D8, {0xFB, 0xC5}}, - {0xE3DF, {0xFB, 0xC7}}, {0xE3E1, {0xFB, 0xC9}}, {0xE3E3, {0xFB, 0xC8}}, - {0xE3E9, {0xFB, 0xCB}}, {0xE3F1, {0xFB, 0xCD}}, {0xE3F2, {0xFB, 0xCE}}, - {0xE3F8, {0xFA, 0x5F}}, {0xE4A6, {0xFB, 0xCC}}, {0xE4BE, {0xFB, 0xD2}}, - {0xE4BF, {0xFB, 0xD6}}, {0xE4C0, {0xFB, 0xD4}}, {0xE4C1, {0xFB, 0xD0}}, - {0xE4C3, {0xFB, 0xD1}}, {0xE4C7, {0xFB, 0xD5}}, {0xE4CB, {0xFB, 0xCF}}, - {0xE4D0, {0xFA, 0x65}}, {0xE4D1, {0xFB, 0xD9}}, {0xE4D2, {0xFB, 0xDC}}, - {0xE4D4, {0xFB, 0xDE}}, {0xE4DB, {0xFB, 0xDD}}, {0xE4DC, {0xFB, 0xDB}}, - {0xE4DE, {0xFB, 0xD8}}, {0xE4E0, {0xFB, 0xD7}}, {0xE4E9, {0xFA, 0x5E}}, - {0xE4EF, {0xFB, 0xE0}}, {0xE4FA, {0xFB, 0xDF}}, {0xE5B3, {0xFB, 0xE1}}, - {0xE5BF, {0xFB, 0xE2}}, {0xE5C9, {0xFB, 0xE3}}, {0xE5D0, {0xFB, 0xE4}}, - {0xE5E2, {0xFB, 0xE5}}, {0xE5EA, {0xFB, 0xE6}}, {0xE5EB, {0xFB, 0xE7}}, - {0xE6E8, {0xFB, 0xEB}}, {0xE6EF, {0xFB, 0xEC}}, {0xE7AC, {0xFB, 0xED}}, - {0xE7AE, {0xFB, 0xEF}}, {0xE7B1, {0xFB, 0xF1}}, {0xE7B2, {0xFB, 0xF3}}, - {0xE8B1, {0xFB, 0xF4}}, {0xE8B6, {0xFB, 0xF5}}, {0xE8DD, {0xFB, 0xF8}}, - {0xE9D1, {0xFB, 0xFB}}, {0xE9ED, {0xFC, 0x40}}, {0xEACD, {0xFC, 0x41}}, - {0xEADB, {0xFC, 0x43}}, {0xEAE6, {0xFC, 0x44}}, {0xEAEA, {0xFC, 0x45}}, - {0xEBA5, {0xFC, 0x46}}, {0xEBFA, {0xFC, 0x48}}, {0xEBFB, {0xFC, 0x47}}, - {0xECD6, {0xFC, 0x4A}}, -}; - -/* EUC to SJIS IBM extended characters map (G3 Upper block) */ -static const unsigned char euc2sjisibm_g3upper_map[][2] = { - {0xFA, 0x40}, {0xFA, 0x41}, {0xFA, 0x42}, {0xFA, 0x43}, {0xFA, 0x44}, - {0xFA, 0x45}, {0xFA, 0x46}, {0xFA, 0x47}, {0xFA, 0x48}, {0xFA, 0x49}, - {0xFA, 0x4A}, {0xFA, 0x4B}, {0xFA, 0x4C}, {0xFA, 0x4D}, {0xFA, 0x4E}, - {0xFA, 0x4F}, {0xFA, 0x50}, {0xFA, 0x51}, {0xFA, 0x52}, {0xFA, 0x53}, - {0xFA, 0x56}, {0xFA, 0x57}, {0xFA, 0x58}, {0xFA, 0x59}, {0xFA, 0x5A}, - {0xFA, 0x62}, {0xFA, 0x6A}, {0xFA, 0x7C}, {0xFA, 0x83}, {0xFA, 0x8A}, - {0xFA, 0x8B}, {0xFA, 0x90}, {0xFA, 0x92}, {0xFA, 0x96}, {0xFA, 0x9B}, - {0xFA, 0x9C}, {0xFA, 0x9D}, {0xFA, 0xAA}, {0xFA, 0xAE}, {0xFA, 0xB0}, - {0xFA, 0xB1}, {0xFA, 0xBA}, {0xFA, 0xBD}, {0xFA, 0xC1}, {0xFA, 0xCD}, - {0xFA, 0xD0}, {0xFA, 0xD5}, {0xFA, 0xD8}, {0xFA, 0xE0}, {0xFA, 0xE5}, - {0xFA, 0xE8}, {0xFA, 0xEA}, {0xFA, 0xEE}, {0xFA, 0xF2}, {0xFB, 0x43}, - {0xFB, 0x44}, {0xFB, 0x50}, {0xFB, 0x58}, {0xFB, 0x5E}, {0xFB, 0x6E}, - {0xFB, 0x70}, {0xFB, 0x72}, {0xFB, 0x75}, {0xFB, 0x7C}, {0xFB, 0x7D}, - {0xFB, 0x7E}, {0xFB, 0x80}, {0xFB, 0x82}, {0xFB, 0x85}, {0xFB, 0x86}, - {0xFB, 0x89}, {0xFB, 0x8D}, {0xFB, 0x8E}, {0xFB, 0x92}, {0xFB, 0x94}, - {0xFB, 0x9D}, {0xFB, 0x9E}, {0xFB, 0x9F}, {0xFB, 0xA0}, {0xFB, 0xA1}, - {0xFB, 0xA9}, {0xFB, 0xAC}, {0xFB, 0xAE}, {0xFB, 0xB0}, {0xFB, 0xB1}, - {0xFB, 0xB3}, {0xFB, 0xB4}, {0xFB, 0xB6}, {0xFB, 0xB7}, {0xFB, 0xB8}, - {0xFB, 0xD3}, {0xFB, 0xDA}, {0xFB, 0xE8}, {0xFB, 0xE9}, {0xFB, 0xEA}, - {0xFB, 0xEE}, {0xFB, 0xF0}, {0xFB, 0xF2}, {0xFB, 0xF6}, {0xFB, 0xF7}, - {0xFB, 0xF9}, {0xFB, 0xFA}, {0xFB, 0xFC}, {0xFC, 0x42}, {0xFC, 0x49}, - {0xFC, 0x4B}, -}; - -static inline int sjisibm2euc(unsigned char *euc, const unsigned char sjis_hi, - const unsigned char sjis_lo); -static inline int euc2sjisibm_jisx0212(unsigned char *sjis, const unsigned char euc_hi, - const unsigned char euc_lo); -static inline int euc2sjisibm_g3upper(unsigned char *sjis, const unsigned char euc_hi, - const unsigned char euc_lo); -static inline int euc2sjisibm(unsigned char *sjis, const unsigned char euc_hi, - const unsigned char euc_lo); -static inline int sjisnec2sjisibm(unsigned char *sjisibm, - const unsigned char sjisnec_hi, - const unsigned char sjisnec_lo); - -/* SJIS IBM extended characters to EUC */ -static inline int sjisibm2euc(unsigned char *euc, const unsigned char sjis_hi, - const unsigned char sjis_lo) -{ - int index; - - index = ((sjis_hi - 0xFA) * (0xFD - 0x40)) + (sjis_lo - 0x40); - if (IS_EUC_IBM2JISX0208(sjisibm2euc_map[index][0], - sjisibm2euc_map[index][1])) { - euc[0] = sjisibm2euc_map[index][0]; - euc[1] = sjisibm2euc_map[index][1]; - return 2; - } else { - euc[0] = SS3; - euc[1] = sjisibm2euc_map[index][0]; - euc[2] = sjisibm2euc_map[index][1]; - return 3; - } -} - -/* EUC to SJIS IBM extended characters (G3 JIS X 0212 block) */ -static inline int euc2sjisibm_jisx0212(unsigned char *sjis, const unsigned char euc_hi, - const unsigned char euc_lo) -{ - int index, min_index, max_index; - unsigned short euc; - - min_index = 0; - max_index = ARRAY_SIZE(euc2sjisibm_jisx0212_map) - 1; - euc = (euc_hi << 8) | euc_lo; - - while (min_index <= max_index) { - index = (min_index + max_index) / 2; - if (euc < euc2sjisibm_jisx0212_map[index].euc) - max_index = index - 1; - else - min_index = index + 1; - if (euc == euc2sjisibm_jisx0212_map[index].euc) { - sjis[0] = euc2sjisibm_jisx0212_map[index].sjis[0]; - sjis[1] = euc2sjisibm_jisx0212_map[index].sjis[1]; - return 3; - } - } - return 0; -} - -/* EUC to SJIS IBM extended characters (G3 Upper block) */ -static inline int euc2sjisibm_g3upper(unsigned char *sjis, const unsigned char euc_hi, - const unsigned char euc_lo) -{ - int index; - - if (euc_hi == 0xF3) - index = ((euc_hi << 8) | euc_lo) - 0xF3F3; - else - index = ((euc_hi << 8) | euc_lo) - 0xF4A1 + 12; - - if ((index < 0) || (index >= ARRAY_SIZE(euc2sjisibm_g3upper_map))) - return 0; - - sjis[0] = euc2sjisibm_g3upper_map[index][0]; - sjis[1] = euc2sjisibm_g3upper_map[index][1]; - - return 3; -} - -/* EUC to SJIS IBM extended characters (G3 block) */ -static inline int euc2sjisibm(unsigned char *sjis, const unsigned char euc_hi, - const unsigned char euc_lo) -{ - int n; - -#if 0 - if ((euc_hi == 0xA2) && (euc_lo == 0xCC)) { - sjis[0] = 0xFA; - sjis[1] = 0x54; - return 2; - } else if ((euc_hi == 0xA2) && (euc_lo == 0xE8)) { - sjis[0] = 0xFA; - sjis[1] = 0x5B; - return 2; - } -#endif - if ((n = euc2sjisibm_g3upper(sjis, euc_hi, euc_lo))) { - return n; - } else if ((n = euc2sjisibm_jisx0212(sjis, euc_hi, euc_lo))) { - return n; - } - - return 0; -} - -/* NEC/IBM extended characters to IBM extended characters */ -static inline int sjisnec2sjisibm(unsigned char *sjisibm, - const unsigned char sjisnec_hi, - const unsigned char sjisnec_lo) -{ - int count; - - if (! IS_SJIS_NECIBM(sjisnec_hi, sjisnec_lo)) - return 0; - - if ((sjisnec_hi == 0xEE) && (sjisnec_lo == 0xF9)) { - sjisibm[0] = 0x81; - sjisibm[1] = 0xCA; - return 2; - } - - if ((sjisnec_hi == 0xEE) && (sjisnec_lo >= 0xEF)) { - count = (sjisnec_hi << 8 | sjisnec_lo) - - (sjisnec_lo <= 0xF9 ? 0xEEEF : (0xEEEF - 10)); - } else { - count = (sjisnec_hi - 0xED) * (0xFC - 0x40) - + (sjisnec_lo - 0x40) + (0x5C - 0x40); - if (sjisnec_lo >= 0x7F) - count--; - } - - sjisibm[0] = 0xFA + (count / (0xFC - 0x40)); - sjisibm[1] = 0x40 + (count % (0xFC - 0x40)); - if (sjisibm[1] >= 0x7F) - sjisibm[1]++; - - return 2; -} - -static int uni2char(const wchar_t uni, - unsigned char *out, int boundlen) -{ - int n; - - if (!p_nls) - return -EINVAL; - if ((n = p_nls->uni2char(uni, out, boundlen)) < 0) - return n; - - /* translate SJIS into EUC-JP */ - if (n == 1) { - if (IS_SJIS_JISX0201KANA(out[0])) { - /* JIS X 0201 KANA */ - if (boundlen < 2) - return -ENAMETOOLONG; - - out[1] = out[0]; - out[0] = SS2; - return 2; - } - } else if (n == 2) { - /* NEC/IBM extended characters to IBM extended characters */ - sjisnec2sjisibm(out, out[0], out[1]); - - if (IS_SJIS_UDC_LOW(out[0], out[1])) { - /* User defined characters half low */ - MAP_SJIS2EUC(out[0], out[1], 0xF0, out[0], out[1], 0xF5); - } else if (IS_SJIS_UDC_HI(out[0], out[1])) { - /* User defined characters half high */ - unsigned char ch, cl; - - if (boundlen < 3) - return -ENAMETOOLONG; - - n = 3; ch = out[0]; cl = out[1]; - out[0] = SS3; - MAP_SJIS2EUC(ch, cl, 0xF5, out[1], out[2], 0xF5); - } else if (IS_SJIS_IBM(out[0], out[1])) { - /* IBM extended characters */ - unsigned char euc[3], i; - - n = sjisibm2euc(euc, out[0], out[1]); - if (boundlen < n) - return -ENAMETOOLONG; - for (i = 0; i < n; i++) - out[i] = euc[i]; - } else if (IS_SJIS_JISX0208(out[0], out[1])) { - /* JIS X 0208 (include NEC special characters) */ - out[0] = (out[0]^0xA0)*2 + 0x5F; - if (out[1] > 0x9E) - out[0]++; - - if (out[1] < 0x7F) - out[1] = out[1] + 0x61; - else if (out[1] < 0x9F) - out[1] = out[1] + 0x60; - else - out[1] = out[1] + 0x02; - } else { - /* Invalid characters */ - return -EINVAL; - } - } - else - return -EINVAL; - - return n; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, - wchar_t *uni) -{ - unsigned char sjis_temp[2]; - int euc_offset, n; - - if ( !p_nls ) - return -EINVAL; - if (boundlen <= 0) - return -ENAMETOOLONG; - - /* translate EUC-JP into SJIS */ - if (rawstring[0] > 0x7F) { - if (rawstring[0] == SS3) { - if (boundlen < 3) - return -EINVAL; - euc_offset = 3; - - if (IS_EUC_UDC_HI(rawstring[1], rawstring[2])) { - /* User defined characters half high */ - MAP_EUC2SJIS(rawstring[1], rawstring[2], 0xF5, - sjis_temp[0], sjis_temp[1], 0xF5); - } else if (euc2sjisibm(sjis_temp,rawstring[1],rawstring[2])) { - /* IBM extended characters */ - } else { - /* JIS X 0212 and Invalid characters*/ - return -EINVAL; - - /* 'GETA' with SJIS coding */ - /* sjis_temp[0] = 0x81; */ - /* sjis_temp[1] = 0xAC; */ - } - } else { - if (boundlen < 2) - return -EINVAL; - euc_offset = 2; - - if (IS_EUC_JISX0201KANA(rawstring[0], rawstring[1])) { - /* JIS X 0201 KANA */ - sjis_temp[0] = rawstring[1]; - sjis_temp[1] = 0x00; - } else if (IS_EUC_UDC_LOW(rawstring[0], rawstring[1])) { - /* User defined characters half low */ - MAP_EUC2SJIS(rawstring[0], rawstring[1], 0xF5, - sjis_temp[0], sjis_temp[1], 0xF0); - } else if (IS_EUC_JISX0208(rawstring[0], rawstring[1])) { - /* JIS X 0208 (include NEC spesial characters) */ - sjis_temp[0] = ((rawstring[0]-0x5f)/2) ^ 0xA0; - if (!(rawstring[0] & 1)) - sjis_temp[1] = rawstring[1] - 0x02; - else if (rawstring[1] < 0xE0) - sjis_temp[1] = rawstring[1] - 0x61; - else - sjis_temp[1] = rawstring[1] - 0x60; - } else { - /* Invalid characters */ - return -EINVAL; - } - } - } else { - euc_offset = 1; - - /* JIS X 0201 ROMAJI */ - sjis_temp[0] = rawstring[0]; - sjis_temp[1] = 0x00; - } - - if ( (n = p_nls->char2uni(sjis_temp, sizeof(sjis_temp), uni)) < 0) - return n; - - return euc_offset; -} - -static struct nls_table table = { - .charset = "euc-jp", - .uni2char = uni2char, - .char2uni = char2uni, -}; - -static int __init init_nls_euc_jp(void) -{ - p_nls = load_nls("cp932"); - - if (p_nls) { - table.charset2upper = p_nls->charset2upper; - table.charset2lower = p_nls->charset2lower; - return register_nls(&table); - } - - return -EINVAL; -} - -static void __exit exit_nls_euc_jp(void) -{ - unregister_nls(&table); - unload_nls(p_nls); -} - -module_init(init_nls_euc_jp) -module_exit(exit_nls_euc_jp) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_iso8859-1.c b/src/linux/fs/nls/nls_iso8859-1.c deleted file mode 100644 index 69ac020..0000000 --- a/src/linux/fs/nls/nls_iso8859-1.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * linux/fs/nls/nls_iso8859-1.c - * - * Charset iso8859-1 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0080, 0x0081, 0x0082, 0x0083, - 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008a, 0x008b, - 0x008c, 0x008d, 0x008e, 0x008f, - /* 0x90*/ - 0x0090, 0x0091, 0x0092, 0x0093, - 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009a, 0x009b, - 0x009c, 0x009d, 0x009e, 0x009f, - /* 0xa0*/ - 0x00a0, 0x00a1, 0x00a2, 0x00a3, - 0x00a4, 0x00a5, 0x00a6, 0x00a7, - 0x00a8, 0x00a9, 0x00aa, 0x00ab, - 0x00ac, 0x00ad, 0x00ae, 0x00af, - /* 0xb0*/ - 0x00b0, 0x00b1, 0x00b2, 0x00b3, - 0x00b4, 0x00b5, 0x00b6, 0x00b7, - 0x00b8, 0x00b9, 0x00ba, 0x00bb, - 0x00bc, 0x00bd, 0x00be, 0x00bf, - /* 0xc0*/ - 0x00c0, 0x00c1, 0x00c2, 0x00c3, - 0x00c4, 0x00c5, 0x00c6, 0x00c7, - 0x00c8, 0x00c9, 0x00ca, 0x00cb, - 0x00cc, 0x00cd, 0x00ce, 0x00cf, - /* 0xd0*/ - 0x00d0, 0x00d1, 0x00d2, 0x00d3, - 0x00d4, 0x00d5, 0x00d6, 0x00d7, - 0x00d8, 0x00d9, 0x00da, 0x00db, - 0x00dc, 0x00dd, 0x00de, 0x00df, - /* 0xe0*/ - 0x00e0, 0x00e1, 0x00e2, 0x00e3, - 0x00e4, 0x00e5, 0x00e6, 0x00e7, - 0x00e8, 0x00e9, 0x00ea, 0x00eb, - 0x00ec, 0x00ed, 0x00ee, 0x00ef, - /* 0xf0*/ - 0x00f0, 0x00f1, 0x00f2, 0x00f3, - 0x00f4, 0x00f5, 0x00f6, 0x00f7, - 0x00f8, 0x00f9, 0x00fa, 0x00fb, - 0x00fc, 0x00fd, 0x00fe, 0x00ff, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* 0xd0-0xd7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0x00, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xf7, /* 0xf0-0xf7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0x00, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "iso8859-1", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_iso8859_1(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_iso8859_1(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_iso8859_1) -module_exit(exit_nls_iso8859_1) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_iso8859-13.c b/src/linux/fs/nls/nls_iso8859-13.c deleted file mode 100644 index afb3f8f..0000000 --- a/src/linux/fs/nls/nls_iso8859-13.c +++ /dev/null @@ -1,285 +0,0 @@ -/* - * linux/fs/nls/nls_iso8859-13.c - * - * Charset iso8859-13 translation tables. - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0080, 0x0081, 0x0082, 0x0083, - 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008a, 0x008b, - 0x008c, 0x008d, 0x008e, 0x008f, - /* 0x90*/ - 0x0090, 0x0091, 0x0092, 0x0093, - 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009a, 0x009b, - 0x009c, 0x009d, 0x009e, 0x009f, - /* 0xa0*/ - 0x00a0, 0x201d, 0x00a2, 0x00a3, - 0x00a4, 0x201e, 0x00a6, 0x00a7, - 0x00d8, 0x00a9, 0x0156, 0x00ab, - 0x00ac, 0x00ad, 0x00ae, 0x00c6, - /* 0xb0*/ - 0x00b0, 0x00b1, 0x00b2, 0x00b3, - 0x201c, 0x00b5, 0x00b6, 0x00b7, - 0x00f8, 0x00b9, 0x0157, 0x00bb, - 0x00bc, 0x00bd, 0x00be, 0x00e6, - /* 0xc0*/ - 0x0104, 0x012e, 0x0100, 0x0106, - 0x00c4, 0x00c5, 0x0118, 0x0112, - 0x010c, 0x00c9, 0x0179, 0x0116, - 0x0122, 0x0136, 0x012a, 0x013b, - /* 0xd0*/ - 0x0160, 0x0143, 0x0145, 0x00d3, - 0x014c, 0x00d5, 0x00d6, 0x00d7, - 0x0172, 0x0141, 0x015a, 0x016a, - 0x00dc, 0x017b, 0x017d, 0x00df, - /* 0xe0*/ - 0x0105, 0x012f, 0x0101, 0x0107, - 0x00e4, 0x00e5, 0x0119, 0x0113, - 0x010d, 0x00e9, 0x017a, 0x0117, - 0x0123, 0x0137, 0x012b, 0x013c, - /* 0xf0*/ - 0x0161, 0x0144, 0x0146, 0x00f3, - 0x014d, 0x00f5, 0x00f6, 0x00f7, - 0x0173, 0x0142, 0x015b, 0x016b, - 0x00fc, 0x017c, 0x017e, 0x2019, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0x00, 0xa2, 0xa3, 0xa4, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0x00, 0xa9, 0x00, 0xab, 0xac, 0xad, 0xae, 0x00, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0x00, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0x00, 0xb9, 0x00, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0xc4, 0xc5, 0xaf, 0x00, /* 0xc0-0xc7 */ - 0x00, 0xc9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0xd3, 0x00, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xa8, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0xe4, 0xe5, 0xbf, 0x00, /* 0xe0-0xe7 */ - 0x00, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0xf3, 0x00, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xb8, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0xc2, 0xe2, 0x00, 0x00, 0xc0, 0xe0, 0xc3, 0xe3, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0xc7, 0xe7, 0x00, 0x00, 0xcb, 0xeb, /* 0x10-0x17 */ - 0xc6, 0xe6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0xcc, 0xec, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0xce, 0xee, 0x00, 0x00, 0xc1, 0xe1, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcd, 0xed, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0xcf, 0xef, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0xd9, 0xf9, 0xd1, 0xf1, 0xd2, 0xf2, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0xd4, 0xf4, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xba, /* 0x50-0x57 */ - 0x00, 0x00, 0xda, 0xfa, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0xdb, 0xfb, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0xd8, 0xf8, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0xca, 0xea, 0xdd, 0xfd, 0xde, 0xfe, 0x00, /* 0x78-0x7f */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0xff, 0x00, 0x00, 0xb4, 0xa1, 0xa5, 0x00, /* 0x18-0x1f */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xb1, 0xa2, 0xb3, 0xa4, 0xb5, 0xb6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xb9, 0xba, 0xbb, 0xbc, 0xad, 0xbe, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbf, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* 0xd0-0xd7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xa1, 0xb2, 0xa3, 0xb4, 0xa5, 0xa6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xa9, 0xaa, 0xab, 0xac, 0xbd, 0xae, 0xbd, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xf7, /* 0xf0-0xf7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "iso8859-13", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_iso8859_13(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_iso8859_13(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_iso8859_13) -module_exit(exit_nls_iso8859_13) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_iso8859-14.c b/src/linux/fs/nls/nls_iso8859-14.c deleted file mode 100644 index 046370f..0000000 --- a/src/linux/fs/nls/nls_iso8859-14.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - * linux/fs/nls/nls_iso8859-14.c - * - * Charset iso8859-14 translation tables. - * - * Generated automatically from the Unicode and charset table - * provided by the Unicode Organisation at - * http://www.unicode.org/ - * The Unicode to charset table has only exact mappings. - * - * Rhys Jones, Swansea University Computer Society - * rhys@sucs.swan.ac.uk - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0080, 0x0081, 0x0082, 0x0083, - 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008a, 0x008b, - 0x008c, 0x008d, 0x008e, 0x008f, - /* 0x90*/ - 0x0090, 0x0091, 0x0092, 0x0093, - 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009a, 0x009b, - 0x009c, 0x009d, 0x009e, 0x009f, - /* 0xa0*/ - 0x00a0, 0x1e02, 0x1e03, 0x00a3, - 0x010a, 0x010b, 0x1e0a, 0x00a7, - 0x1e80, 0x00a9, 0x1e82, 0x1e0b, - 0x1ef2, 0x00ad, 0x00ae, 0x0178, - /* 0xb0*/ - 0x1e1e, 0x1e1f, 0x0120, 0x0121, - 0x1e40, 0x1e41, 0x00b6, 0x1e56, - 0x1e81, 0x1e57, 0x1e83, 0x1e60, - 0x1ef3, 0x1e84, 0x1e85, 0x1e61, - /* 0xc0*/ - 0x00c0, 0x00c1, 0x00c2, 0x00c3, - 0x00c4, 0x00c5, 0x00c6, 0x00c7, - 0x00c8, 0x00c9, 0x00ca, 0x00cb, - 0x00cc, 0x00cd, 0x00ce, 0x00cf, - /* 0xd0*/ - 0x0174, 0x00d1, 0x00d2, 0x00d3, - 0x00d4, 0x00d5, 0x00d6, 0x1e6a, - 0x00d8, 0x00d9, 0x00da, 0x00db, - 0x00dc, 0x00dd, 0x0176, 0x00df, - /* 0xe0*/ - 0x00e0, 0x00e1, 0x00e2, 0x00e3, - 0x00e4, 0x00e5, 0x00e6, 0x00e7, - 0x00e8, 0x00e9, 0x00ea, 0x00eb, - 0x00ec, 0x00ed, 0x00ee, 0x00ef, - /* 0xf0*/ - 0x0175, 0x00f1, 0x00f2, 0x00f3, - 0x00f4, 0x00f5, 0x00f6, 0x1e6b, - 0x00f8, 0x00f9, 0x00fa, 0x00fb, - 0x00fc, 0x00fd, 0x0177, 0x00ff, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0xa7, /* 0xa0-0xa7 */ - 0x00, 0xa9, 0x00, 0x00, 0x00, 0xad, 0xae, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0x00, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0x00, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0x00, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0x00, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0x00, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0x00, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0xa1, 0xa2, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0xa6, 0xab, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb1, /* 0x18-0x1f */ - 0xb2, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0xb4, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0xb9, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xbb, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0xd7, 0xf7, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0xd0, 0xf0, 0xde, 0xfe, /* 0x70-0x77 */ - 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0xa8, 0xb8, 0xaa, 0xba, 0xbd, 0xbe, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0xac, 0xbc, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page1e[256] = { - 0x00, 0x00, 0xa1, 0xa2, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0xa6, 0xab, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xb1, /* 0x18-0x1f */ - 0xb2, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0xb4, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0xb9, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xbb, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0xd7, 0xf7, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0xd0, 0xf0, 0xde, 0xfe, /* 0x70-0x77 */ - 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0xa8, 0xb8, 0xaa, 0xba, 0xbd, 0xbe, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0xac, 0xbc, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, page1e, NULL, - - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa2, 0xa2, 0xa3, 0xab, 0xab, 0xab, 0xa7, /* 0xa0-0xa7 */ - 0xb8, 0xa9, 0xba, 0xab, 0xbc, 0xad, 0xae, 0xff, /* 0xa8-0xaf */ - 0xb1, 0xb1, 0xb3, 0xb3, 0xb5, 0xb5, 0xb6, 0xb9, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbf, 0xbc, 0xbe, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xd0-0xd7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa1, 0xa3, 0xa6, 0xa6, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xa6, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb0, 0xb2, 0xb2, 0xb4, 0xb4, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xa8, 0xb7, 0xaa, 0xbb, 0xac, 0xbd, 0xbd, 0xbb, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xf0-0xf7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xaf, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "iso8859-14", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_iso8859_14(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_iso8859_14(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_iso8859_14) -module_exit(exit_nls_iso8859_14) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_iso8859-15.c b/src/linux/fs/nls/nls_iso8859-15.c deleted file mode 100644 index 7e34a84..0000000 --- a/src/linux/fs/nls/nls_iso8859-15.c +++ /dev/null @@ -1,307 +0,0 @@ -/* - * linux/fs/nls/nls_iso8859-15.c - * - * Charset iso8859-15 translation tables. - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0080, 0x0081, 0x0082, 0x0083, - 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008a, 0x008b, - 0x008c, 0x008d, 0x008e, 0x008f, - /* 0x90*/ - 0x0090, 0x0091, 0x0092, 0x0093, - 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009a, 0x009b, - 0x009c, 0x009d, 0x009e, 0x009f, - /* 0xa0*/ - 0x00a0, 0x00a1, 0x00a2, 0x00a3, - 0x20ac, 0x00a5, 0x0160, 0x00a7, - 0x0161, 0x00a9, 0x00aa, 0x00ab, - 0x00ac, 0x00ad, 0x00ae, 0x00af, - /* 0xb0*/ - 0x00b0, 0x00b1, 0x00b2, 0x00b3, - 0x017d, 0x00b5, 0x00b6, 0x00b7, - 0x017e, 0x00b9, 0x00ba, 0x00bb, - 0x0152, 0x0153, 0x0178, 0x00bf, - /* 0xc0*/ - 0x00c0, 0x00c1, 0x00c2, 0x00c3, - 0x00c4, 0x00c5, 0x00c6, 0x00c7, - 0x00c8, 0x00c9, 0x00ca, 0x00cb, - 0x00cc, 0x00cd, 0x00ce, 0x00cf, - /* 0xd0*/ - 0x00d0, 0x00d1, 0x00d2, 0x00d3, - 0x00d4, 0x00d5, 0x00d6, 0x00d7, - 0x00d8, 0x00d9, 0x00da, 0x00db, - 0x00dc, 0x00dd, 0x00de, 0x00df, - /* 0xe0*/ - 0x00e0, 0x00e1, 0x00e2, 0x00e3, - 0x00e4, 0x00e5, 0x00e6, 0x00e7, - 0x00e8, 0x00e9, 0x00ea, 0x00eb, - 0x00ec, 0x00ed, 0x00ee, 0x00ef, - /* 0xf0*/ - 0x00f0, 0x00f1, 0x00f2, 0x00f3, - 0x00f4, 0x00f5, 0x00f6, 0x00f7, - 0x00f8, 0x00f9, 0x00fa, 0x00fb, - 0x00fc, 0x00fd, 0x00fe, 0x00ff, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0x00, 0xa5, 0x00, 0xa7, /* 0xa0-0xa7 */ - 0x00, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0x00, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0x00, 0xb9, 0xba, 0xbb, 0x00, 0x00, 0x00, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0xbc, 0xbd, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xa6, 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0xbe, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xb8, 0x00, /* 0x78-0x7f */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - - page20, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa8, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb8, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbd, 0xbd, 0xff, 0xbf, /* 0xb8-0xbf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* 0xd0-0xd7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa6, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0x00, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb4, 0xb9, 0xba, 0xbb, 0xbc, 0xbc, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xf7, /* 0xf0-0xf7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xbe, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "iso8859-15", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_iso8859_15(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_iso8859_15(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_iso8859_15) -module_exit(exit_nls_iso8859_15) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_iso8859-2.c b/src/linux/fs/nls/nls_iso8859-2.c deleted file mode 100644 index 7dd5711..0000000 --- a/src/linux/fs/nls/nls_iso8859-2.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * linux/fs/nls/nls_iso8859-2.c - * - * Charset iso8859-2 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0080, 0x0081, 0x0082, 0x0083, - 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008a, 0x008b, - 0x008c, 0x008d, 0x008e, 0x008f, - /* 0x90*/ - 0x0090, 0x0091, 0x0092, 0x0093, - 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009a, 0x009b, - 0x009c, 0x009d, 0x009e, 0x009f, - /* 0xa0*/ - 0x00a0, 0x0104, 0x02d8, 0x0141, - 0x00a4, 0x013d, 0x015a, 0x00a7, - 0x00a8, 0x0160, 0x015e, 0x0164, - 0x0179, 0x00ad, 0x017d, 0x017b, - /* 0xb0*/ - 0x00b0, 0x0105, 0x02db, 0x0142, - 0x00b4, 0x013e, 0x015b, 0x02c7, - 0x00b8, 0x0161, 0x015f, 0x0165, - 0x017a, 0x02dd, 0x017e, 0x017c, - /* 0xc0*/ - 0x0154, 0x00c1, 0x00c2, 0x0102, - 0x00c4, 0x0139, 0x0106, 0x00c7, - 0x010c, 0x00c9, 0x0118, 0x00cb, - 0x011a, 0x00cd, 0x00ce, 0x010e, - /* 0xd0*/ - 0x0110, 0x0143, 0x0147, 0x00d3, - 0x00d4, 0x0150, 0x00d6, 0x00d7, - 0x0158, 0x016e, 0x00da, 0x0170, - 0x00dc, 0x00dd, 0x0162, 0x00df, - /* 0xe0*/ - 0x0155, 0x00e1, 0x00e2, 0x0103, - 0x00e4, 0x013a, 0x0107, 0x00e7, - 0x010d, 0x00e9, 0x0119, 0x00eb, - 0x011b, 0x00ed, 0x00ee, 0x010f, - /* 0xf0*/ - 0x0111, 0x0144, 0x0148, 0x00f3, - 0x00f4, 0x0151, 0x00f6, 0x00f7, - 0x0159, 0x016f, 0x00fa, 0x0171, - 0x00fc, 0x00fd, 0x0163, 0x02d9, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, /* 0xa8-0xaf */ - 0xb0, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0xc1, 0xc2, 0x00, 0xc4, 0x00, 0x00, 0xc7, /* 0xc0-0xc7 */ - 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcd, 0xce, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0xd3, 0xd4, 0x00, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0x00, 0x00, 0xda, 0x00, 0xdc, 0xdd, 0x00, 0xdf, /* 0xd8-0xdf */ - 0x00, 0xe1, 0xe2, 0x00, 0xe4, 0x00, 0x00, 0xe7, /* 0xe0-0xe7 */ - 0x00, 0xe9, 0x00, 0xeb, 0x00, 0xed, 0xee, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0xf3, 0xf4, 0x00, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0x00, 0x00, 0xfa, 0x00, 0xfc, 0xfd, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0xc3, 0xe3, 0xa1, 0xb1, 0xc6, 0xe6, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0xcf, 0xef, /* 0x08-0x0f */ - 0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0xca, 0xea, 0xcc, 0xec, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0xc5, 0xe5, 0x00, 0x00, 0xa5, 0xb5, 0x00, /* 0x38-0x3f */ - 0x00, 0xa3, 0xb3, 0xd1, 0xf1, 0x00, 0x00, 0xd2, /* 0x40-0x47 */ - 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xd5, 0xf5, 0x00, 0x00, 0xc0, 0xe0, 0x00, 0x00, /* 0x50-0x57 */ - 0xd8, 0xf8, 0xa6, 0xb6, 0x00, 0x00, 0xaa, 0xba, /* 0x58-0x5f */ - 0xa9, 0xb9, 0xde, 0xfe, 0xab, 0xbb, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0xf9, /* 0x68-0x6f */ - 0xdb, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0xac, 0xbc, 0xaf, 0xbf, 0xae, 0xbe, 0x00, /* 0x78-0x7f */ -}; - -static const unsigned char page02[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0xa2, 0xff, 0x00, 0xb2, 0x00, 0xbd, 0x00, 0x00, /* 0xd8-0xdf */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, page02, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xb1, 0xa2, 0xb3, 0xa4, 0xb5, 0xb6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xb9, 0xba, 0xbb, 0xbc, 0xad, 0xbe, 0xbf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* 0xd0-0xd7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xa1, 0xb2, 0xa3, 0xb4, 0xa5, 0xa6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xa9, 0xaa, 0xab, 0xac, 0xbd, 0xae, 0xaf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xf7, /* 0xf0-0xf7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "iso8859-2", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_iso8859_2(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_iso8859_2(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_iso8859_2) -module_exit(exit_nls_iso8859_2) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_iso8859-3.c b/src/linux/fs/nls/nls_iso8859-3.c deleted file mode 100644 index 740b75e..0000000 --- a/src/linux/fs/nls/nls_iso8859-3.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * linux/fs/nls/nls_iso8859-3.c - * - * Charset iso8859-3 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0080, 0x0081, 0x0082, 0x0083, - 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008a, 0x008b, - 0x008c, 0x008d, 0x008e, 0x008f, - /* 0x90*/ - 0x0090, 0x0091, 0x0092, 0x0093, - 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009a, 0x009b, - 0x009c, 0x009d, 0x009e, 0x009f, - /* 0xa0*/ - 0x00a0, 0x0126, 0x02d8, 0x00a3, - 0x00a4, 0x0000, 0x0124, 0x00a7, - 0x00a8, 0x0130, 0x015e, 0x011e, - 0x0134, 0x00ad, 0x0000, 0x017b, - /* 0xb0*/ - 0x00b0, 0x0127, 0x00b2, 0x00b3, - 0x00b4, 0x00b5, 0x0125, 0x00b7, - 0x00b8, 0x0131, 0x015f, 0x011f, - 0x0135, 0x00bd, 0x0000, 0x017c, - /* 0xc0*/ - 0x00c0, 0x00c1, 0x00c2, 0x0000, - 0x00c4, 0x010a, 0x0108, 0x00c7, - 0x00c8, 0x00c9, 0x00ca, 0x00cb, - 0x00cc, 0x00cd, 0x00ce, 0x00cf, - /* 0xd0*/ - 0x0000, 0x00d1, 0x00d2, 0x00d3, - 0x00d4, 0x0120, 0x00d6, 0x00d7, - 0x011c, 0x00d9, 0x00da, 0x00db, - 0x00dc, 0x016c, 0x015c, 0x00df, - /* 0xe0*/ - 0x00e0, 0x00e1, 0x00e2, 0x0000, - 0x00e4, 0x010b, 0x0109, 0x00e7, - 0x00e8, 0x00e9, 0x00ea, 0x00eb, - 0x00ec, 0x00ed, 0x00ee, 0x00ef, - /* 0xf0*/ - 0x0000, 0x00f1, 0x00f2, 0x00f3, - 0x00f4, 0x0121, 0x00f6, 0x00f7, - 0x011d, 0x00f9, 0x00fa, 0x00fb, - 0x00fc, 0x016d, 0x015d, 0x02d9, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0x00, 0x00, 0xa3, 0xa4, 0x00, 0x00, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, /* 0xa8-0xaf */ - 0xb0, 0x00, 0xb2, 0xb3, 0xb4, 0xb5, 0x00, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0x00, 0x00, 0x00, 0x00, 0xbd, 0x00, 0x00, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0x00, 0xc4, 0x00, 0x00, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0x00, 0xd1, 0xd2, 0xd3, 0xd4, 0x00, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0x00, 0xd9, 0xda, 0xdb, 0xdc, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0x00, 0xe4, 0x00, 0x00, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0x00, 0xf1, 0xf2, 0xf3, 0xf4, 0x00, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0x00, 0xf9, 0xfa, 0xfb, 0xfc, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0xc6, 0xe6, 0xc5, 0xe5, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0xd8, 0xf8, 0xab, 0xbb, /* 0x18-0x1f */ - 0xd5, 0xf5, 0x00, 0x00, 0xa6, 0xb6, 0xa1, 0xb1, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0xa9, 0xb9, 0x00, 0x00, 0xac, 0xbc, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0xde, 0xfe, 0xaa, 0xba, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0xdd, 0xfd, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0xaf, 0xbf, 0x00, 0x00, 0x00, /* 0x78-0x7f */ -}; - -static const unsigned char page02[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0xa2, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, page02, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xb1, 0xa2, 0xa3, 0xa4, 0x00, 0xb6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0x69, 0xba, 0xbb, 0xbc, 0xad, 0x00, 0xbf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0x00, 0xbf, /* 0xb8-0xbf */ - 0xe0, 0xe1, 0xe2, 0x00, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ - 0x00, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* 0xd0-0xd7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0x00, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0x00, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0x00, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xa1, 0xb2, 0xb3, 0xb4, 0x00, 0xa6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0x49, 0xaa, 0xab, 0xac, 0xbd, 0x00, 0xaf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0x00, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0x00, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xc0, 0xc1, 0xc2, 0x00, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ - 0x00, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xf7, /* 0xf0-0xf7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "iso8859-3", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_iso8859_3(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_iso8859_3(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_iso8859_3) -module_exit(exit_nls_iso8859_3) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_iso8859-4.c b/src/linux/fs/nls/nls_iso8859-4.c deleted file mode 100644 index 8826021..0000000 --- a/src/linux/fs/nls/nls_iso8859-4.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * linux/fs/nls/nls_iso8859-4.c - * - * Charset iso8859-4 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0080, 0x0081, 0x0082, 0x0083, - 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008a, 0x008b, - 0x008c, 0x008d, 0x008e, 0x008f, - /* 0x90*/ - 0x0090, 0x0091, 0x0092, 0x0093, - 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009a, 0x009b, - 0x009c, 0x009d, 0x009e, 0x009f, - /* 0xa0*/ - 0x00a0, 0x0104, 0x0138, 0x0156, - 0x00a4, 0x0128, 0x013b, 0x00a7, - 0x00a8, 0x0160, 0x0112, 0x0122, - 0x0166, 0x00ad, 0x017d, 0x00af, - /* 0xb0*/ - 0x00b0, 0x0105, 0x02db, 0x0157, - 0x00b4, 0x0129, 0x013c, 0x02c7, - 0x00b8, 0x0161, 0x0113, 0x0123, - 0x0167, 0x014a, 0x017e, 0x014b, - /* 0xc0*/ - 0x0100, 0x00c1, 0x00c2, 0x00c3, - 0x00c4, 0x00c5, 0x00c6, 0x012e, - 0x010c, 0x00c9, 0x0118, 0x00cb, - 0x0116, 0x00cd, 0x00ce, 0x012a, - /* 0xd0*/ - 0x0110, 0x0145, 0x014c, 0x0136, - 0x00d4, 0x00d5, 0x00d6, 0x00d7, - 0x00d8, 0x0172, 0x00da, 0x00db, - 0x00dc, 0x0168, 0x016a, 0x00df, - /* 0xe0*/ - 0x0101, 0x00e1, 0x00e2, 0x00e3, - 0x00e4, 0x00e5, 0x00e6, 0x012f, - 0x010d, 0x00e9, 0x0119, 0x00eb, - 0x0117, 0x00ed, 0x00ee, 0x012b, - /* 0xf0*/ - 0x0111, 0x0146, 0x014d, 0x0137, - 0x00f4, 0x00f5, 0x00f6, 0x00f7, - 0x00f8, 0x0173, 0x00fa, 0x00fb, - 0x00fc, 0x0169, 0x016b, 0x02d9, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0x00, 0x00, 0x00, 0xb4, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0x00, /* 0xc0-0xc7 */ - 0x00, 0xc9, 0x00, 0xcb, 0x00, 0xcd, 0xce, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0x00, 0xda, 0xdb, 0xdc, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */ - 0x00, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0x00, /* 0xe0-0xe7 */ - 0x00, 0xe9, 0x00, 0xeb, 0x00, 0xed, 0xee, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0x00, 0xfa, 0xfb, 0xfc, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0xc0, 0xe0, 0x00, 0x00, 0xa1, 0xb1, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0x00, 0x00, /* 0x08-0x0f */ - 0xd0, 0xf0, 0xaa, 0xba, 0x00, 0x00, 0xcc, 0xec, /* 0x10-0x17 */ - 0xca, 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0xab, 0xbb, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0xa5, 0xb5, 0xcf, 0xef, 0x00, 0x00, 0xc7, 0xe7, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd3, 0xf3, /* 0x30-0x37 */ - 0xa2, 0x00, 0x00, 0xa6, 0xb6, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0xf1, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0xbd, 0xbf, 0xd2, 0xf2, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0xb3, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0xa9, 0xb9, 0x00, 0x00, 0x00, 0x00, 0xac, 0xbc, /* 0x60-0x67 */ - 0xdd, 0xfd, 0xde, 0xfe, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0xd9, 0xf9, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0xae, 0xbe, 0x00, /* 0x78-0x7f */ -}; - -static const unsigned char page02[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0xff, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, page02, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xb1, 0xa2, 0xb3, 0xa4, 0xb5, 0xb6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xb9, 0xba, 0xbb, 0xbc, 0xad, 0xbe, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbf, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* 0xd0-0xd7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xa1, 0xb2, 0xa3, 0xb4, 0xa5, 0xa6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xa9, 0xaa, 0xab, 0xac, 0xbd, 0xae, 0xbd, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xf7, /* 0xf0-0xf7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "iso8859-4", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_iso8859_4(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_iso8859_4(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_iso8859_4) -module_exit(exit_nls_iso8859_4) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_iso8859-5.c b/src/linux/fs/nls/nls_iso8859-5.c deleted file mode 100644 index 7c04057..0000000 --- a/src/linux/fs/nls/nls_iso8859-5.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * linux/fs/nls/nls_iso8859-5.c - * - * Charset iso8859-5 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0080, 0x0081, 0x0082, 0x0083, - 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008a, 0x008b, - 0x008c, 0x008d, 0x008e, 0x008f, - /* 0x90*/ - 0x0090, 0x0091, 0x0092, 0x0093, - 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009a, 0x009b, - 0x009c, 0x009d, 0x009e, 0x009f, - /* 0xa0*/ - 0x00a0, 0x0401, 0x0402, 0x0403, - 0x0404, 0x0405, 0x0406, 0x0407, - 0x0408, 0x0409, 0x040a, 0x040b, - 0x040c, 0x00ad, 0x040e, 0x040f, - /* 0xb0*/ - 0x0410, 0x0411, 0x0412, 0x0413, - 0x0414, 0x0415, 0x0416, 0x0417, - 0x0418, 0x0419, 0x041a, 0x041b, - 0x041c, 0x041d, 0x041e, 0x041f, - /* 0xc0*/ - 0x0420, 0x0421, 0x0422, 0x0423, - 0x0424, 0x0425, 0x0426, 0x0427, - 0x0428, 0x0429, 0x042a, 0x042b, - 0x042c, 0x042d, 0x042e, 0x042f, - /* 0xd0*/ - 0x0430, 0x0431, 0x0432, 0x0433, - 0x0434, 0x0435, 0x0436, 0x0437, - 0x0438, 0x0439, 0x043a, 0x043b, - 0x043c, 0x043d, 0x043e, 0x043f, - /* 0xe0*/ - 0x0440, 0x0441, 0x0442, 0x0443, - 0x0444, 0x0445, 0x0446, 0x0447, - 0x0448, 0x0449, 0x044a, 0x044b, - 0x044c, 0x044d, 0x044e, 0x044f, - /* 0xf0*/ - 0x2116, 0x0451, 0x0452, 0x0453, - 0x0454, 0x0455, 0x0456, 0x0457, - 0x0458, 0x0459, 0x045a, 0x045b, - 0x045c, 0x00a7, 0x045e, 0x045f, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, /* 0xa8-0xaf */ -}; - -static const unsigned char page04[256] = { - 0x00, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0x00-0x07 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0x00, 0xae, 0xaf, /* 0x08-0x0f */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0x10-0x17 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0x18-0x1f */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x20-0x27 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0x28-0x2f */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0x30-0x37 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0x38-0x3f */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x40-0x47 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x48-0x4f */ - 0x00, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0x50-0x57 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0x00, 0xfe, 0xff, /* 0x58-0x5f */ -}; - -static const unsigned char page21[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, /* 0x10-0x17 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, NULL, NULL, NULL, page04, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, page21, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xa0-0xa7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xad, 0xfe, 0xff, /* 0xa8-0xaf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xb0-0xb7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xb8-0xbf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xd0-0xd7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xd8-0xdf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ - 0xf0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xf0-0xf7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xfd, 0xae, 0xaf, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "iso8859-5", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_iso8859_5(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_iso8859_5(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_iso8859_5) -module_exit(exit_nls_iso8859_5) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_iso8859-6.c b/src/linux/fs/nls/nls_iso8859-6.c deleted file mode 100644 index d4a8814..0000000 --- a/src/linux/fs/nls/nls_iso8859-6.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * linux/fs/nls/nls_iso8859-6.c - * - * Charset iso8859-6 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0660, 0x0661, 0x0662, 0x0663, - 0x0664, 0x0665, 0x0666, 0x0667, - 0x0668, 0x0669, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0080, 0x0081, 0x0082, 0x0083, - 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008a, 0x008b, - 0x008c, 0x008d, 0x008e, 0x008f, - /* 0x90*/ - 0x0090, 0x0091, 0x0092, 0x0093, - 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009a, 0x009b, - 0x009c, 0x009d, 0x009e, 0x009f, - /* 0xa0*/ - 0x00a0, 0x0000, 0x0000, 0x0000, - 0x00a4, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x060c, 0x00ad, 0x0000, 0x0000, - /* 0xb0*/ - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x061b, - 0x0000, 0x0000, 0x0000, 0x061f, - /* 0xc0*/ - 0x0000, 0x0621, 0x0622, 0x0623, - 0x0624, 0x0625, 0x0626, 0x0627, - 0x0628, 0x0629, 0x062a, 0x062b, - 0x062c, 0x062d, 0x062e, 0x062f, - /* 0xd0*/ - 0x0630, 0x0631, 0x0632, 0x0633, - 0x0634, 0x0635, 0x0636, 0x0637, - 0x0638, 0x0639, 0x063a, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - /* 0xe0*/ - 0x0640, 0x0641, 0x0642, 0x0643, - 0x0644, 0x0645, 0x0646, 0x0647, - 0x0648, 0x0649, 0x064a, 0x064b, - 0x064c, 0x064d, 0x064e, 0x064f, - /* 0xf0*/ - 0x0650, 0x0651, 0x0652, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, /* 0xa8-0xaf */ -}; - -static const unsigned char page06[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xbf, /* 0x18-0x1f */ - 0x00, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x20-0x27 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0x28-0x2f */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0x30-0x37 */ - 0xd8, 0xd9, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0x40-0x47 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0x48-0x4f */ - 0xf0, 0xf1, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x60-0x67 */ - 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, NULL, NULL, NULL, NULL, NULL, page06, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0xac, 0xad, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xbf, /* 0xb8-0xbf */ - 0x00, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0xac, 0xad, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0xbf, /* 0xb8-0xbf */ - 0x00, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xf0-0xf7 */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "iso8859-6", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_iso8859_6(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_iso8859_6(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_iso8859_6) -module_exit(exit_nls_iso8859_6) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_iso8859-7.c b/src/linux/fs/nls/nls_iso8859-7.c deleted file mode 100644 index 37b75d8..0000000 --- a/src/linux/fs/nls/nls_iso8859-7.c +++ /dev/null @@ -1,317 +0,0 @@ -/* - * linux/fs/nls/nls_iso8859-7.c - * - * Charset iso8859-7 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0080, 0x0081, 0x0082, 0x0083, - 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008a, 0x008b, - 0x008c, 0x008d, 0x008e, 0x008f, - /* 0x90*/ - 0x0090, 0x0091, 0x0092, 0x0093, - 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009a, 0x009b, - 0x009c, 0x009d, 0x009e, 0x009f, - /* 0xa0*/ - 0x00a0, 0x02bd, 0x02bc, 0x00a3, - 0x0000, 0x0000, 0x00a6, 0x00a7, - 0x00a8, 0x00a9, 0x0000, 0x00ab, - 0x00ac, 0x00ad, 0x0000, 0x2015, - /* 0xb0*/ - 0x00b0, 0x00b1, 0x00b2, 0x00b3, - 0x0384, 0x0385, 0x0386, 0x00b7, - 0x0388, 0x0389, 0x038a, 0x00bb, - 0x038c, 0x00bd, 0x038e, 0x038f, - /* 0xc0*/ - 0x0390, 0x0391, 0x0392, 0x0393, - 0x0394, 0x0395, 0x0396, 0x0397, - 0x0398, 0x0399, 0x039a, 0x039b, - 0x039c, 0x039d, 0x039e, 0x039f, - /* 0xd0*/ - 0x03a0, 0x03a1, 0x0000, 0x03a3, - 0x03a4, 0x03a5, 0x03a6, 0x03a7, - 0x03a8, 0x03a9, 0x03aa, 0x03ab, - 0x03ac, 0x03ad, 0x03ae, 0x03af, - /* 0xe0*/ - 0x03b0, 0x03b1, 0x03b2, 0x03b3, - 0x03b4, 0x03b5, 0x03b6, 0x03b7, - 0x03b8, 0x03b9, 0x03ba, 0x03bb, - 0x03bc, 0x03bd, 0x03be, 0x03bf, - /* 0xf0*/ - 0x03c0, 0x03c1, 0x03c2, 0x03c3, - 0x03c4, 0x03c5, 0x03c6, 0x03c7, - 0x03c8, 0x03c9, 0x03ca, 0x03cb, - 0x03cc, 0x03cd, 0x03ce, 0x0000, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0x00, 0x00, 0xa3, 0x00, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0x00, 0x00, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0x00, 0x00, 0x00, 0xb7, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0xbb, 0x00, 0xbd, 0x00, 0x00, /* 0xb8-0xbf */ -}; - -static const unsigned char page02[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0xa2, 0xa1, 0x00, 0x00, /* 0xb8-0xbf */ -}; - -static const unsigned char page03[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0xb4, 0xb5, 0xb6, 0x00, /* 0x80-0x87 */ - 0xb8, 0xb9, 0xba, 0x00, 0xbc, 0x00, 0xbe, 0xbf, /* 0x88-0x8f */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0x90-0x97 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0x98-0x9f */ - 0xd0, 0xd1, 0x00, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xa0-0xa7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xa8-0xaf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xb0-0xb7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xb8-0xbf */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xc0-0xc7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0x00, /* 0xc8-0xcf */ -}; - -static const unsigned char page20[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, /* 0x10-0x17 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, NULL, page02, page03, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - page20, NULL, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0x00, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0x00, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xdc, 0xb7, /* 0xb0-0xb7 */ - 0xdd, 0xde, 0xdf, 0xbb, 0xfc, 0xbd, 0xfd, 0xfe, /* 0xb8-0xbf */ - 0xc0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ - 0xf0, 0xf1, 0x00, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xd0-0xd7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0x00, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0x00, 0x00, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0x00, 0xab, 0xac, 0xad, 0x00, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0x00, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xb6, 0xb8, 0xb9, 0xba, /* 0xd8-0xdf */ - 0xe0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ - 0xd0, 0xd1, 0xd3, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xf0-0xf7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xbc, 0xbe, 0xbf, 0x00, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "iso8859-7", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_iso8859_7(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_iso8859_7(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_iso8859_7) -module_exit(exit_nls_iso8859_7) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_iso8859-9.c b/src/linux/fs/nls/nls_iso8859-9.c deleted file mode 100644 index 557b982..0000000 --- a/src/linux/fs/nls/nls_iso8859-9.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * linux/fs/nls/nls_iso8859-9.c - * - * Charset iso8859-9 translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x0080, 0x0081, 0x0082, 0x0083, - 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008a, 0x008b, - 0x008c, 0x008d, 0x008e, 0x008f, - /* 0x90*/ - 0x0090, 0x0091, 0x0092, 0x0093, - 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009a, 0x009b, - 0x009c, 0x009d, 0x009e, 0x009f, - /* 0xa0*/ - 0x00a0, 0x00a1, 0x00a2, 0x00a3, - 0x00a4, 0x00a5, 0x00a6, 0x00a7, - 0x00a8, 0x00a9, 0x00aa, 0x00ab, - 0x00ac, 0x00ad, 0x00ae, 0x00af, - /* 0xb0*/ - 0x00b0, 0x00b1, 0x00b2, 0x00b3, - 0x00b4, 0x00b5, 0x00b6, 0x00b7, - 0x00b8, 0x00b9, 0x00ba, 0x00bb, - 0x00bc, 0x00bd, 0x00be, 0x00bf, - /* 0xc0*/ - 0x00c0, 0x00c1, 0x00c2, 0x00c3, - 0x00c4, 0x00c5, 0x00c6, 0x00c7, - 0x00c8, 0x00c9, 0x00ca, 0x00cb, - 0x00cc, 0x00cd, 0x00ce, 0x00cf, - /* 0xd0*/ - 0x011e, 0x00d1, 0x00d2, 0x00d3, - 0x00d4, 0x00d5, 0x00d6, 0x00d7, - 0x00d8, 0x00d9, 0x00da, 0x00db, - 0x00dc, 0x0130, 0x015e, 0x00df, - /* 0xe0*/ - 0x00e0, 0x00e1, 0x00e2, 0x00e3, - 0x00e4, 0x00e5, 0x00e6, 0x00e7, - 0x00e8, 0x00e9, 0x00ea, 0x00eb, - 0x00ec, 0x00ed, 0x00ee, 0x00ef, - /* 0xf0*/ - 0x011f, 0x00f1, 0x00f2, 0x00f3, - 0x00f4, 0x00f5, 0x00f6, 0x00f7, - 0x00f8, 0x00f9, 0x00fa, 0x00fb, - 0x00fc, 0x0131, 0x015f, 0x00ff, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0x00, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0x00, 0x00, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0x00, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0x00, 0x00, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char page01[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0xf0, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0xdd, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xde, 0xfe, /* 0x58-0x5f */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, page01, NULL, NULL, NULL, NULL, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xd7, /* 0xd0-0xd7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0x69, 0xfe, 0xdf, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0x00, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xf7, /* 0xf0-0xf7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0x49, 0xde, 0x00, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "iso8859-9", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_iso8859_9(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_iso8859_9(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_iso8859_9) -module_exit(exit_nls_iso8859_9) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_koi8-r.c b/src/linux/fs/nls/nls_koi8-r.c deleted file mode 100644 index 811f232..0000000 --- a/src/linux/fs/nls/nls_koi8-r.c +++ /dev/null @@ -1,323 +0,0 @@ -/* - * linux/fs/nls/nls_koi8-r.c - * - * Charset koi8-r translation tables. - * Generated automatically from the Unicode and charset - * tables from the Unicode Organization (www.unicode.org). - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x2500, 0x2502, 0x250c, 0x2510, - 0x2514, 0x2518, 0x251c, 0x2524, - 0x252c, 0x2534, 0x253c, 0x2580, - 0x2584, 0x2588, 0x258c, 0x2590, - /* 0x90*/ - 0x2591, 0x2592, 0x2593, 0x2320, - 0x25a0, 0x2219, 0x221a, 0x2248, - 0x2264, 0x2265, 0x00a0, 0x2321, - 0x00b0, 0x00b2, 0x00b7, 0x00f7, - /* 0xa0*/ - 0x2550, 0x2551, 0x2552, 0x0451, - 0x2553, 0x2554, 0x2555, 0x2556, - 0x2557, 0x2558, 0x2559, 0x255a, - 0x255b, 0x255c, 0x255d, 0x255e, - /* 0xb0*/ - 0x255f, 0x2560, 0x2561, 0x0401, - 0x2562, 0x2563, 0x2564, 0x2565, - 0x2566, 0x2567, 0x2568, 0x2569, - 0x256a, 0x256b, 0x256c, 0x00a9, - /* 0xc0*/ - 0x044e, 0x0430, 0x0431, 0x0446, - 0x0434, 0x0435, 0x0444, 0x0433, - 0x0445, 0x0438, 0x0439, 0x043a, - 0x043b, 0x043c, 0x043d, 0x043e, - /* 0xd0*/ - 0x043f, 0x044f, 0x0440, 0x0441, - 0x0442, 0x0443, 0x0436, 0x0432, - 0x044c, 0x044b, 0x0437, 0x0448, - 0x044d, 0x0449, 0x0447, 0x044a, - /* 0xe0*/ - 0x042e, 0x0410, 0x0411, 0x0426, - 0x0414, 0x0415, 0x0424, 0x0413, - 0x0425, 0x0418, 0x0419, 0x041a, - 0x041b, 0x041c, 0x041d, 0x041e, - /* 0xf0*/ - 0x041f, 0x042f, 0x0420, 0x0421, - 0x0422, 0x0423, 0x0416, 0x0412, - 0x042c, 0x042b, 0x0417, 0x0428, - 0x042d, 0x0429, 0x0427, 0x042a, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x9c, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, /* 0xf0-0xf7 */ -}; - -static const unsigned char page04[256] = { - 0x00, 0xb3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xe1, 0xe2, 0xf7, 0xe7, 0xe4, 0xe5, 0xf6, 0xfa, /* 0x10-0x17 */ - 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, /* 0x18-0x1f */ - 0xf2, 0xf3, 0xf4, 0xf5, 0xe6, 0xe8, 0xe3, 0xfe, /* 0x20-0x27 */ - 0xfb, 0xfd, 0xff, 0xf9, 0xf8, 0xfc, 0xe0, 0xf1, /* 0x28-0x2f */ - 0xc1, 0xc2, 0xd7, 0xc7, 0xc4, 0xc5, 0xd6, 0xda, /* 0x30-0x37 */ - 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, /* 0x38-0x3f */ - 0xd2, 0xd3, 0xd4, 0xd5, 0xc6, 0xc8, 0xc3, 0xde, /* 0x40-0x47 */ - 0xdb, 0xdd, 0xdf, 0xd9, 0xd8, 0xdc, 0xc0, 0xd1, /* 0x48-0x4f */ - 0x00, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x95, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x98, 0x99, 0x00, 0x00, /* 0x60-0x67 */ -}; - -static const unsigned char page23[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x93, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ -}; - -static const unsigned char page25[256] = { - 0x80, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x83, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x85, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xa0, 0xa1, 0xa2, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, /* 0x50-0x57 */ - 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, /* 0x58-0x5f */ - 0xb1, 0xb2, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, /* 0x60-0x67 */ - 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x8b, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x8d, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x8f, 0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, NULL, NULL, NULL, page04, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, page22, page23, NULL, page25, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xa3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xf0-0xf7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xb3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xd0-0xd7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "koi8-r", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_koi8_r(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_koi8_r(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_koi8_r) -module_exit(exit_nls_koi8_r) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_koi8-ru.c b/src/linux/fs/nls/nls_koi8-ru.c deleted file mode 100644 index a80a741..0000000 --- a/src/linux/fs/nls/nls_koi8-ru.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * linux/fs/nls/nls_koi8-ru.c - * - * Charset koi8-ru translation based on charset koi8-u. - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static struct nls_table *p_nls; - -static int uni2char(const wchar_t uni, - unsigned char *out, int boundlen) -{ - if (boundlen <= 0) - return -ENAMETOOLONG; - - if ((uni & 0xffaf) == 0x040e || (uni & 0xffce) == 0x254c) { - /* koi8-ru and koi8-u differ only on two characters */ - if (uni == 0x040e) - out[0] = 0xbe; - else if (uni == 0x045e) - out[0] = 0xae; - else if (uni == 0x255d || uni == 0x256c) - return 0; - else - return p_nls->uni2char(uni, out, boundlen); - return 1; - } - else - /* fast path */ - return p_nls->uni2char(uni, out, boundlen); -} - -static int char2uni(const unsigned char *rawstring, int boundlen, - wchar_t *uni) -{ - int n; - - if ((*rawstring & 0xef) != 0xae) { - /* koi8-ru and koi8-u differ only on two characters */ - *uni = (*rawstring & 0x10) ? 0x040e : 0x045e; - return 1; - } - - n = p_nls->char2uni(rawstring, boundlen, uni); - return n; -} - -static struct nls_table table = { - .charset = "koi8-ru", - .uni2char = uni2char, - .char2uni = char2uni, -}; - -static int __init init_nls_koi8_ru(void) -{ - p_nls = load_nls("koi8-u"); - - if (p_nls) { - table.charset2upper = p_nls->charset2upper; - table.charset2lower = p_nls->charset2lower; - return register_nls(&table); - } - - return -EINVAL; -} - -static void __exit exit_nls_koi8_ru(void) -{ - unregister_nls(&table); - unload_nls(p_nls); -} - -module_init(init_nls_koi8_ru) -module_exit(exit_nls_koi8_ru) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_koi8-u.c b/src/linux/fs/nls/nls_koi8-u.c deleted file mode 100644 index 7e029e4..0000000 --- a/src/linux/fs/nls/nls_koi8-u.c +++ /dev/null @@ -1,330 +0,0 @@ -/* - * linux/fs/nls/nls_koi8-u.c - * - * Charset koi8-u translation tables. - * The Unicode to charset table has only exact mappings. - */ - -#include -#include -#include -#include -#include - -static const wchar_t charset2uni[256] = { - /* 0x00*/ - 0x0000, 0x0001, 0x0002, 0x0003, - 0x0004, 0x0005, 0x0006, 0x0007, - 0x0008, 0x0009, 0x000a, 0x000b, - 0x000c, 0x000d, 0x000e, 0x000f, - /* 0x10*/ - 0x0010, 0x0011, 0x0012, 0x0013, - 0x0014, 0x0015, 0x0016, 0x0017, - 0x0018, 0x0019, 0x001a, 0x001b, - 0x001c, 0x001d, 0x001e, 0x001f, - /* 0x20*/ - 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0025, 0x0026, 0x0027, - 0x0028, 0x0029, 0x002a, 0x002b, - 0x002c, 0x002d, 0x002e, 0x002f, - /* 0x30*/ - 0x0030, 0x0031, 0x0032, 0x0033, - 0x0034, 0x0035, 0x0036, 0x0037, - 0x0038, 0x0039, 0x003a, 0x003b, - 0x003c, 0x003d, 0x003e, 0x003f, - /* 0x40*/ - 0x0040, 0x0041, 0x0042, 0x0043, - 0x0044, 0x0045, 0x0046, 0x0047, - 0x0048, 0x0049, 0x004a, 0x004b, - 0x004c, 0x004d, 0x004e, 0x004f, - /* 0x50*/ - 0x0050, 0x0051, 0x0052, 0x0053, - 0x0054, 0x0055, 0x0056, 0x0057, - 0x0058, 0x0059, 0x005a, 0x005b, - 0x005c, 0x005d, 0x005e, 0x005f, - /* 0x60*/ - 0x0060, 0x0061, 0x0062, 0x0063, - 0x0064, 0x0065, 0x0066, 0x0067, - 0x0068, 0x0069, 0x006a, 0x006b, - 0x006c, 0x006d, 0x006e, 0x006f, - /* 0x70*/ - 0x0070, 0x0071, 0x0072, 0x0073, - 0x0074, 0x0075, 0x0076, 0x0077, - 0x0078, 0x0079, 0x007a, 0x007b, - 0x007c, 0x007d, 0x007e, 0x007f, - /* 0x80*/ - 0x2500, 0x2502, 0x250c, 0x2510, - 0x2514, 0x2518, 0x251c, 0x2524, - 0x252c, 0x2534, 0x253c, 0x2580, - 0x2584, 0x2588, 0x258c, 0x2590, - /* 0x90*/ - 0x2591, 0x2592, 0x2593, 0x2320, - 0x25a0, 0x2219, 0x221a, 0x2248, - 0x2264, 0x2265, 0x00a0, 0x2321, - 0x00b0, 0x00b2, 0x00b7, 0x00f7, - /* 0xa0*/ - 0x2550, 0x2551, 0x2552, 0x0451, - 0x0454, 0x2554, 0x0456, 0x0457, - 0x2557, 0x2558, 0x2559, 0x255a, - 0x255b, 0x0491, 0x255d, 0x255e, - /* 0xb0*/ - 0x255f, 0x2560, 0x2561, 0x0401, - 0x0404, 0x2563, 0x0406, 0x0407, - 0x2566, 0x2567, 0x2568, 0x2569, - 0x256a, 0x0490, 0x256c, 0x00a9, - /* 0xc0*/ - 0x044e, 0x0430, 0x0431, 0x0446, - 0x0434, 0x0435, 0x0444, 0x0433, - 0x0445, 0x0438, 0x0439, 0x043a, - 0x043b, 0x043c, 0x043d, 0x043e, - /* 0xd0*/ - 0x043f, 0x044f, 0x0440, 0x0441, - 0x0442, 0x0443, 0x0436, 0x0432, - 0x044c, 0x044b, 0x0437, 0x0448, - 0x044d, 0x0449, 0x0447, 0x044a, - /* 0xe0*/ - 0x042e, 0x0410, 0x0411, 0x0426, - 0x0414, 0x0415, 0x0424, 0x0413, - 0x0425, 0x0418, 0x0419, 0x041a, - 0x041b, 0x041c, 0x041d, 0x041e, - /* 0xf0*/ - 0x041f, 0x042f, 0x0420, 0x0421, - 0x0422, 0x0423, 0x0416, 0x0412, - 0x042c, 0x042b, 0x0417, 0x0428, - 0x042d, 0x0429, 0x0427, 0x042a, -}; - -static const unsigned char page00[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ - 0x00, 0xbf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa8-0xaf */ - 0x9c, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x9e, /* 0xb0-0xb7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xb8-0xbf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc0-0xc7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xc8-0xcf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd0-0xd7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xd8-0xdf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe0-0xe7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xe8-0xef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9f, /* 0xf0-0xf7 */ -}; - -static const unsigned char page04[256] = { - 0x00, 0xb3, 0x00, 0x00, 0xb4, 0x00, 0xb6, 0xb7, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0xe1, 0xe2, 0xf7, 0xe7, 0xe4, 0xe5, 0xf6, 0xfa, /* 0x10-0x17 */ - 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, /* 0x18-0x1f */ - 0xf2, 0xf3, 0xf4, 0xf5, 0xe6, 0xe8, 0xe3, 0xfe, /* 0x20-0x27 */ - 0xfb, 0xfd, 0xff, 0xf9, 0xf8, 0xfc, 0xe0, 0xf1, /* 0x28-0x2f */ - 0xc1, 0xc2, 0xd7, 0xc7, 0xc4, 0xc5, 0xd6, 0xda, /* 0x30-0x37 */ - 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, /* 0x38-0x3f */ - 0xd2, 0xd3, 0xd4, 0xd5, 0xc6, 0xc8, 0xc3, 0xde, /* 0x40-0x47 */ - 0xdb, 0xdd, 0xdf, 0xd9, 0xd8, 0xdc, 0xc0, 0xd1, /* 0x48-0x4f */ - 0x00, 0xa3, 0x00, 0x00, 0xa4, 0x00, 0xa6, 0xa7, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x60-0x67 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0xbd, 0xad, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ -}; - -static const unsigned char page22[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x95, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x50-0x57 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x58-0x5f */ - 0x00, 0x00, 0x00, 0x00, 0x98, 0x99, 0x00, 0x00, /* 0x60-0x67 */ -}; - -static const unsigned char page23[256] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x93, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x20-0x27 */ -}; - -static const unsigned char page25[256] = { - 0x80, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x00-0x07 */ - 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, /* 0x08-0x0f */ - 0x83, 0x00, 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, /* 0x10-0x17 */ - 0x85, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, /* 0x18-0x1f */ - 0x00, 0x00, 0x00, 0x00, 0x87, 0x00, 0x00, 0x00, /* 0x20-0x27 */ - 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, /* 0x28-0x2f */ - 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, /* 0x30-0x37 */ - 0x00, 0x00, 0x00, 0x00, 0x8a, 0x00, 0x00, 0x00, /* 0x38-0x3f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x40-0x47 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x48-0x4f */ - 0xa0, 0xa1, 0xa2, 0x00, 0xa5, 0x00, 0x00, 0xa8, /* 0x50-0x57 */ - 0xa9, 0xaa, 0xab, 0xac, 0x00, 0xae, 0xaf, 0xb0, /* 0x58-0x5f */ - 0xb1, 0xb2, 0x00, 0xb5, 0x00, 0x00, 0xb8, 0xb9, /* 0x60-0x67 */ - 0xba, 0xbb, 0xbc, 0x00, 0xbe, 0x00, 0x00, 0x00, /* 0x68-0x6f */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x70-0x77 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x78-0x7f */ - - 0x8b, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, /* 0x80-0x87 */ - 0x8d, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, /* 0x88-0x8f */ - 0x8f, 0x90, 0x91, 0x92, 0x00, 0x00, 0x00, 0x00, /* 0x90-0x97 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x98-0x9f */ - 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0-0xa7 */ -}; - -static const unsigned char *const page_uni2charset[256] = { - page00, NULL, NULL, NULL, page04, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, page22, page23, NULL, page25, NULL, NULL, -}; - -static const unsigned char charset2lower[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x40-0x47 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x48-0x4f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x50-0x57 */ - 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* 0x60-0x67 */ - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, /* 0x68-0x6f */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 0x70-0x77 */ - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xa3, 0xa4, 0xb5, 0xa6, 0xa7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xad, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xc0-0xc7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xc8-0xcf */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xd0-0xd7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xd8-0xdf */ - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* 0xe0-0xe7 */ - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* 0xe8-0xef */ - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* 0xf0-0xf7 */ - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* 0xf8-0xff */ -}; - -static const unsigned char charset2upper[256] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 0x00-0x07 */ - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, /* 0x08-0x0f */ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* 0x10-0x17 */ - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, /* 0x18-0x1f */ - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, /* 0x20-0x27 */ - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 0x28-0x2f */ - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 0x30-0x37 */ - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, /* 0x38-0x3f */ - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x40-0x47 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x48-0x4f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x50-0x57 */ - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, /* 0x58-0x5f */ - 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 0x60-0x67 */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 0x68-0x6f */ - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 0x70-0x77 */ - 0x58, 0x59, 0x5a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, /* 0x78-0x7f */ - - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 0x80-0x87 */ - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 0x88-0x8f */ - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 0x90-0x97 */ - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 0x98-0x9f */ - 0xa0, 0xa1, 0xa2, 0xb3, 0xb4, 0xa5, 0xb6, 0xb7, /* 0xa0-0xa7 */ - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xbd, 0xae, 0xaf, /* 0xa8-0xaf */ - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* 0xb0-0xb7 */ - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* 0xb8-0xbf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xc0-0xc7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xc8-0xcf */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xd0-0xd7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xd8-0xdf */ - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* 0xe0-0xe7 */ - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* 0xe8-0xef */ - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* 0xf0-0xf7 */ - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, /* 0xf8-0xff */ -}; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - const unsigned char *uni2charset; - unsigned char cl = uni & 0x00ff; - unsigned char ch = (uni & 0xff00) >> 8; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - uni2charset = page_uni2charset[ch]; - if (uni2charset && uni2charset[cl]) - out[0] = uni2charset[cl]; - else - return -EINVAL; - return 1; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - *uni = charset2uni[*rawstring]; - if (*uni == 0x0000) - return -EINVAL; - return 1; -} - -static struct nls_table table = { - .charset = "koi8-u", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = charset2lower, - .charset2upper = charset2upper, -}; - -static int __init init_nls_koi8_u(void) -{ - return register_nls(&table); -} - -static void __exit exit_nls_koi8_u(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_koi8_u) -module_exit(exit_nls_koi8_u) - -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/nls/nls_utf8.c b/src/linux/fs/nls/nls_utf8.c deleted file mode 100644 index afcfbc4..0000000 --- a/src/linux/fs/nls/nls_utf8.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Module for handling utf8 just like any other charset. - * By Urban Widmark 2000 - */ - -#include -#include -#include -#include -#include - -static unsigned char identity[256]; - -static int uni2char(wchar_t uni, unsigned char *out, int boundlen) -{ - int n; - - if (boundlen <= 0) - return -ENAMETOOLONG; - - n = utf32_to_utf8(uni, out, boundlen); - if (n < 0) { - *out = '?'; - return -EINVAL; - } - return n; -} - -static int char2uni(const unsigned char *rawstring, int boundlen, wchar_t *uni) -{ - int n; - unicode_t u; - - n = utf8_to_utf32(rawstring, boundlen, &u); - if (n < 0 || u > MAX_WCHAR_T) { - *uni = 0x003f; /* ? */ - return -EINVAL; - } - *uni = (wchar_t) u; - return n; -} - -static struct nls_table table = { - .charset = "utf8", - .uni2char = uni2char, - .char2uni = char2uni, - .charset2lower = identity, /* no conversion */ - .charset2upper = identity, -}; - -static int __init init_nls_utf8(void) -{ - int i; - for (i=0; i<256; i++) - identity[i] = i; - - return register_nls(&table); -} - -static void __exit exit_nls_utf8(void) -{ - unregister_nls(&table); -} - -module_init(init_nls_utf8) -module_exit(exit_nls_utf8) -MODULE_LICENSE("Dual BSD/GPL"); diff --git a/src/linux/fs/notify/Kconfig b/src/linux/fs/notify/Kconfig deleted file mode 100644 index 2a24249..0000000 --- a/src/linux/fs/notify/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -config FSNOTIFY - def_bool n - select SRCU - -source "fs/notify/dnotify/Kconfig" -source "fs/notify/inotify/Kconfig" -source "fs/notify/fanotify/Kconfig" diff --git a/src/linux/fs/notify/Makefile b/src/linux/fs/notify/Makefile deleted file mode 100644 index 96d3420..0000000 --- a/src/linux/fs/notify/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -obj-$(CONFIG_FSNOTIFY) += fsnotify.o notification.o group.o inode_mark.o \ - mark.o vfsmount_mark.o fdinfo.o - -obj-y += dnotify/ -obj-y += inotify/ -obj-y += fanotify/ diff --git a/src/linux/fs/notify/dnotify/Kconfig b/src/linux/fs/notify/dnotify/Kconfig deleted file mode 100644 index f9c1ca1..0000000 --- a/src/linux/fs/notify/dnotify/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config DNOTIFY - bool "Dnotify support" - select FSNOTIFY - default y - help - Dnotify is a directory-based per-fd file change notification system - that uses signals to communicate events to user-space. There exist - superior alternatives, but some applications may still rely on - dnotify. - - If unsure, say Y. diff --git a/src/linux/fs/notify/dnotify/Makefile b/src/linux/fs/notify/dnotify/Makefile deleted file mode 100644 index f145251..0000000 --- a/src/linux/fs/notify/dnotify/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_DNOTIFY) += dnotify.o diff --git a/src/linux/fs/notify/fanotify/Kconfig b/src/linux/fs/notify/fanotify/Kconfig deleted file mode 100644 index e5f911b..0000000 --- a/src/linux/fs/notify/fanotify/Kconfig +++ /dev/null @@ -1,26 +0,0 @@ -config FANOTIFY - bool "Filesystem wide access notification" - select FSNOTIFY - select ANON_INODES - default n - ---help--- - Say Y here to enable fanotify support. fanotify is a file access - notification system which differs from inotify in that it sends - an open file descriptor to the userspace listener along with - the event. - - If unsure, say Y. - -config FANOTIFY_ACCESS_PERMISSIONS - bool "fanotify permissions checking" - depends on FANOTIFY - depends on SECURITY - default n - ---help--- - Say Y here is you want fanotify listeners to be able to make permissions - decisions concerning filesystem events. This is used by some fanotify - listeners which need to scan files before allowing the system access to - use those files. This is used by some anti-malware vendors and by some - hierarchical storage managent systems. - - If unsure, say N. diff --git a/src/linux/fs/notify/fanotify/Makefile b/src/linux/fs/notify/fanotify/Makefile deleted file mode 100644 index 0999213..0000000 --- a/src/linux/fs/notify/fanotify/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_FANOTIFY) += fanotify.o fanotify_user.o diff --git a/src/linux/fs/notify/inotify/Kconfig b/src/linux/fs/notify/inotify/Kconfig deleted file mode 100644 index b981fc0..0000000 --- a/src/linux/fs/notify/inotify/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -config INOTIFY_USER - bool "Inotify support for userspace" - select ANON_INODES - select FSNOTIFY - default y - ---help--- - Say Y here to enable inotify support for userspace, including the - associated system calls. Inotify allows monitoring of both files and - directories via a single open fd. Events are read from the file - descriptor, which is also select()- and poll()-able. - Inotify fixes numerous shortcomings in dnotify and introduces several - new features including multiple file events, one-shot support, and - unmount notification. - - For more information, see - - If unsure, say Y. diff --git a/src/linux/fs/notify/inotify/Makefile b/src/linux/fs/notify/inotify/Makefile deleted file mode 100644 index a380dab..0000000 --- a/src/linux/fs/notify/inotify/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_INOTIFY_USER) += inotify_fsnotify.o inotify_user.o diff --git a/src/linux/fs/nsfs.c b/src/linux/fs/nsfs.c deleted file mode 100644 index 8718af8..0000000 --- a/src/linux/fs/nsfs.c +++ /dev/null @@ -1,243 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct vfsmount *nsfs_mnt; - -static long ns_ioctl(struct file *filp, unsigned int ioctl, - unsigned long arg); -static const struct file_operations ns_file_operations = { - .llseek = no_llseek, - .unlocked_ioctl = ns_ioctl, -}; - -static char *ns_dname(struct dentry *dentry, char *buffer, int buflen) -{ - struct inode *inode = d_inode(dentry); - const struct proc_ns_operations *ns_ops = dentry->d_fsdata; - - return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]", - ns_ops->name, inode->i_ino); -} - -static void ns_prune_dentry(struct dentry *dentry) -{ - struct inode *inode = d_inode(dentry); - if (inode) { - struct ns_common *ns = inode->i_private; - atomic_long_set(&ns->stashed, 0); - } -} - -const struct dentry_operations ns_dentry_operations = -{ - .d_prune = ns_prune_dentry, - .d_delete = always_delete_dentry, - .d_dname = ns_dname, -}; - -static void nsfs_evict(struct inode *inode) -{ - struct ns_common *ns = inode->i_private; - clear_inode(inode); - ns->ops->put(ns); -} - -static void *__ns_get_path(struct path *path, struct ns_common *ns) -{ - struct vfsmount *mnt = nsfs_mnt; - struct qstr qname = { .name = "", }; - struct dentry *dentry; - struct inode *inode; - unsigned long d; - - rcu_read_lock(); - d = atomic_long_read(&ns->stashed); - if (!d) - goto slow; - dentry = (struct dentry *)d; - if (!lockref_get_not_dead(&dentry->d_lockref)) - goto slow; - rcu_read_unlock(); - ns->ops->put(ns); -got_it: - path->mnt = mntget(mnt); - path->dentry = dentry; - return NULL; -slow: - rcu_read_unlock(); - inode = new_inode_pseudo(mnt->mnt_sb); - if (!inode) { - ns->ops->put(ns); - return ERR_PTR(-ENOMEM); - } - inode->i_ino = ns->inum; - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); - inode->i_flags |= S_IMMUTABLE; - inode->i_mode = S_IFREG | S_IRUGO; - inode->i_fop = &ns_file_operations; - inode->i_private = ns; - - dentry = d_alloc_pseudo(mnt->mnt_sb, &qname); - if (!dentry) { - iput(inode); - return ERR_PTR(-ENOMEM); - } - d_instantiate(dentry, inode); - dentry->d_fsdata = (void *)ns->ops; - d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry); - if (d) { - d_delete(dentry); /* make sure ->d_prune() does nothing */ - dput(dentry); - cpu_relax(); - return ERR_PTR(-EAGAIN); - } - goto got_it; -} - -void *ns_get_path(struct path *path, struct task_struct *task, - const struct proc_ns_operations *ns_ops) -{ - struct ns_common *ns; - void *ret; - -again: - ns = ns_ops->get(task); - if (!ns) - return ERR_PTR(-ENOENT); - - ret = __ns_get_path(path, ns); - if (IS_ERR(ret) && PTR_ERR(ret) == -EAGAIN) - goto again; - return ret; -} - -static int open_related_ns(struct ns_common *ns, - struct ns_common *(*get_ns)(struct ns_common *ns)) -{ - struct path path = {}; - struct file *f; - void *err; - int fd; - - fd = get_unused_fd_flags(O_CLOEXEC); - if (fd < 0) - return fd; - - while (1) { - struct ns_common *relative; - - relative = get_ns(ns); - if (IS_ERR(relative)) { - put_unused_fd(fd); - return PTR_ERR(relative); - } - - err = __ns_get_path(&path, relative); - if (IS_ERR(err) && PTR_ERR(err) == -EAGAIN) - continue; - break; - } - if (IS_ERR(err)) { - put_unused_fd(fd); - return PTR_ERR(err); - } - - f = dentry_open(&path, O_RDONLY, current_cred()); - path_put(&path); - if (IS_ERR(f)) { - put_unused_fd(fd); - fd = PTR_ERR(f); - } else - fd_install(fd, f); - - return fd; -} - -static long ns_ioctl(struct file *filp, unsigned int ioctl, - unsigned long arg) -{ - struct ns_common *ns = get_proc_ns(file_inode(filp)); - - switch (ioctl) { - case NS_GET_USERNS: - return open_related_ns(ns, ns_get_owner); - case NS_GET_PARENT: - if (!ns->ops->get_parent) - return -EINVAL; - return open_related_ns(ns, ns->ops->get_parent); - default: - return -ENOTTY; - } -} - -int ns_get_name(char *buf, size_t size, struct task_struct *task, - const struct proc_ns_operations *ns_ops) -{ - struct ns_common *ns; - int res = -ENOENT; - ns = ns_ops->get(task); - if (ns) { - res = snprintf(buf, size, "%s:[%u]", ns_ops->name, ns->inum); - ns_ops->put(ns); - } - return res; -} - -struct file *proc_ns_fget(int fd) -{ - struct file *file; - - file = fget(fd); - if (!file) - return ERR_PTR(-EBADF); - - if (file->f_op != &ns_file_operations) - goto out_invalid; - - return file; - -out_invalid: - fput(file); - return ERR_PTR(-EINVAL); -} - -static int nsfs_show_path(struct seq_file *seq, struct dentry *dentry) -{ - struct inode *inode = d_inode(dentry); - const struct proc_ns_operations *ns_ops = dentry->d_fsdata; - - seq_printf(seq, "%s:[%lu]", ns_ops->name, inode->i_ino); - return 0; -} - -static const struct super_operations nsfs_ops = { - .statfs = simple_statfs, - .evict_inode = nsfs_evict, - .show_path = nsfs_show_path, -}; -static struct dentry *nsfs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_pseudo(fs_type, "nsfs:", &nsfs_ops, - &ns_dentry_operations, NSFS_MAGIC); -} -static struct file_system_type nsfs = { - .name = "nsfs", - .mount = nsfs_mount, - .kill_sb = kill_anon_super, -}; - -void __init nsfs_init(void) -{ - nsfs_mnt = kern_mount(&nsfs); - if (IS_ERR(nsfs_mnt)) - panic("can't set nsfs up\n"); - nsfs_mnt->mnt_sb->s_flags &= ~MS_NOUSER; -} diff --git a/src/linux/fs/ntfs/Kconfig b/src/linux/fs/ntfs/Kconfig deleted file mode 100644 index f5a868c..0000000 --- a/src/linux/fs/ntfs/Kconfig +++ /dev/null @@ -1,78 +0,0 @@ -config NTFS_FS - tristate "NTFS file system support" - select NLS - help - NTFS is the file system of Microsoft Windows NT, 2000, XP and 2003. - - Saying Y or M here enables read support. There is partial, but - safe, write support available. For write support you must also - say Y to "NTFS write support" below. - - There are also a number of user-space tools available, called - ntfsprogs. These include ntfsundelete and ntfsresize, that work - without NTFS support enabled in the kernel. - - This is a rewrite from scratch of Linux NTFS support and replaced - the old NTFS code starting with Linux 2.5.11. A backport to - the Linux 2.4 kernel series is separately available as a patch - from the project web site. - - For more information see - and . - - To compile this file system support as a module, choose M here: the - module will be called ntfs. - - If you are not using Windows NT, 2000, XP or 2003 in addition to - Linux on your computer it is safe to say N. - -config NTFS_DEBUG - bool "NTFS debugging support" - depends on NTFS_FS - help - If you are experiencing any problems with the NTFS file system, say - Y here. This will result in additional consistency checks to be - performed by the driver as well as additional debugging messages to - be written to the system log. Note that debugging messages are - disabled by default. To enable them, supply the option debug_msgs=1 - at the kernel command line when booting the kernel or as an option - to insmod when loading the ntfs module. Once the driver is active, - you can enable debugging messages by doing (as root): - echo 1 > /proc/sys/fs/ntfs-debug - Replacing the "1" with "0" would disable debug messages. - - If you leave debugging messages disabled, this results in little - overhead, but enabling debug messages results in very significant - slowdown of the system. - - When reporting bugs, please try to have available a full dump of - debugging messages while the misbehaviour was occurring. - -config NTFS_RW - bool "NTFS write support" - depends on NTFS_FS - help - This enables the partial, but safe, write support in the NTFS driver. - - The only supported operation is overwriting existing files, without - changing the file length. No file or directory creation, deletion or - renaming is possible. Note only non-resident files can be written to - so you may find that some very small files (<500 bytes or so) cannot - be written to. - - While we cannot guarantee that it will not damage any data, we have - so far not received a single report where the driver would have - damaged someones data so we assume it is perfectly safe to use. - - Note: While write support is safe in this version (a rewrite from - scratch of the NTFS support), it should be noted that the old NTFS - write support, included in Linux 2.5.10 and before (since 1997), - is not safe. - - This is currently useful with TopologiLinux. TopologiLinux is run - on top of any DOS/Microsoft Windows system without partitioning your - hard disk. Unlike other Linux distributions TopologiLinux does not - need its own partition. For more information see - - - It is perfectly safe to say N here. diff --git a/src/linux/fs/ocfs2/Kconfig b/src/linux/fs/ocfs2/Kconfig deleted file mode 100644 index 77a8de5..0000000 --- a/src/linux/fs/ocfs2/Kconfig +++ /dev/null @@ -1,76 +0,0 @@ -config OCFS2_FS - tristate "OCFS2 file system support" - depends on NET && SYSFS && CONFIGFS_FS - select JBD2 - select CRC32 - select QUOTA - select QUOTA_TREE - select FS_POSIX_ACL - help - OCFS2 is a general purpose extent based shared disk cluster file - system with many similarities to ext3. It supports 64 bit inode - numbers, and has automatically extending metadata groups which may - also make it attractive for non-clustered use. - - You'll want to install the ocfs2-tools package in order to at least - get "mount.ocfs2". - - Project web page: http://oss.oracle.com/projects/ocfs2 - Tools web page: http://oss.oracle.com/projects/ocfs2-tools - OCFS2 mailing lists: http://oss.oracle.com/projects/ocfs2/mailman/ - - For more information on OCFS2, see the file - . - -config OCFS2_FS_O2CB - tristate "O2CB Kernelspace Clustering" - depends on OCFS2_FS - default y - help - OCFS2 includes a simple kernelspace clustering package, the OCFS2 - Cluster Base. It only requires a very small userspace component - to configure it. This comes with the standard ocfs2-tools package. - O2CB is limited to maintaining a cluster for OCFS2 file systems. - It cannot manage any other cluster applications. - - It is always safe to say Y here, as the clustering method is - run-time selectable. - -config OCFS2_FS_USERSPACE_CLUSTER - tristate "OCFS2 Userspace Clustering" - depends on OCFS2_FS && DLM - default y - help - This option will allow OCFS2 to use userspace clustering services - in conjunction with the DLM in fs/dlm. If you are using a - userspace cluster manager, say Y here. - - It is safe to say Y, as the clustering method is run-time - selectable. - -config OCFS2_FS_STATS - bool "OCFS2 statistics" - depends on OCFS2_FS && DEBUG_FS - default y - help - This option allows some fs statistics to be captured. Enabling - this option may increase the memory consumption. - -config OCFS2_DEBUG_MASKLOG - bool "OCFS2 logging support" - depends on OCFS2_FS - default y - help - The ocfs2 filesystem has an extensive logging system. The system - allows selection of events to log via files in /sys/o2cb/logmask/. - This option will enlarge your kernel, but it allows debugging of - ocfs2 filesystem issues. - -config OCFS2_DEBUG_FS - bool "OCFS2 expensive checks" - depends on OCFS2_FS - default n - help - This option will enable expensive consistency checks. Enable - this option for debugging only as it is likely to decrease - performance of the filesystem. diff --git a/src/linux/fs/omfs/Kconfig b/src/linux/fs/omfs/Kconfig deleted file mode 100644 index b1b9a0a..0000000 --- a/src/linux/fs/omfs/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config OMFS_FS - tristate "SonicBlue Optimized MPEG File System support" - depends on BLOCK - select CRC_ITU_T - help - This is the proprietary file system used by the Rio Karma music - player and ReplayTV DVR. Despite the name, this filesystem is not - more efficient than a standard FS for MPEG files, in fact likely - the opposite is true. Say Y if you have either of these devices - and wish to mount its disk. - - To compile this file system support as a module, choose M here: the - module will be called omfs. If unsure, say N. diff --git a/src/linux/fs/open.c b/src/linux/fs/open.c deleted file mode 100644 index d3ed817..0000000 --- a/src/linux/fs/open.c +++ /dev/null @@ -1,1182 +0,0 @@ -/* - * linux/fs/open.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#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 "internal.h" - -int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, - struct file *filp) -{ - int ret; - struct iattr newattrs; - - /* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */ - if (length < 0) - return -EINVAL; - - newattrs.ia_size = length; - newattrs.ia_valid = ATTR_SIZE | time_attrs; - if (filp) { - newattrs.ia_file = filp; - newattrs.ia_valid |= ATTR_FILE; - } - - /* Remove suid, sgid, and file capabilities on truncate too */ - ret = dentry_needs_remove_privs(dentry); - if (ret < 0) - return ret; - if (ret) - newattrs.ia_valid |= ret | ATTR_FORCE; - - inode_lock(dentry->d_inode); - /* Note any delegations or leases have already been broken: */ - ret = notify_change(dentry, &newattrs, NULL); - inode_unlock(dentry->d_inode); - return ret; -} - -long vfs_truncate(const struct path *path, loff_t length) -{ - struct inode *inode; - struct dentry *upperdentry; - long error; - - inode = path->dentry->d_inode; - - /* For directories it's -EISDIR, for other non-regulars - -EINVAL */ - if (S_ISDIR(inode->i_mode)) - return -EISDIR; - if (!S_ISREG(inode->i_mode)) - return -EINVAL; - - error = mnt_want_write(path->mnt); - if (error) - goto out; - - error = inode_permission(inode, MAY_WRITE); - if (error) - goto mnt_drop_write_and_out; - - error = -EPERM; - if (IS_APPEND(inode)) - goto mnt_drop_write_and_out; - - /* - * If this is an overlayfs then do as if opening the file so we get - * write access on the upper inode, not on the overlay inode. For - * non-overlay filesystems d_real() is an identity function. - */ - upperdentry = d_real(path->dentry, NULL, O_WRONLY); - error = PTR_ERR(upperdentry); - if (IS_ERR(upperdentry)) - goto mnt_drop_write_and_out; - - error = get_write_access(upperdentry->d_inode); - if (error) - goto mnt_drop_write_and_out; - - /* - * Make sure that there are no leases. get_write_access() protects - * against the truncate racing with a lease-granting setlease(). - */ - error = break_lease(inode, O_WRONLY); - if (error) - goto put_write_and_out; - - error = locks_verify_truncate(inode, NULL, length); - if (!error) - error = security_path_truncate(path); - if (!error) - error = do_truncate(path->dentry, length, 0, NULL); - -put_write_and_out: - put_write_access(upperdentry->d_inode); -mnt_drop_write_and_out: - mnt_drop_write(path->mnt); -out: - return error; -} -EXPORT_SYMBOL_GPL(vfs_truncate); - -static long do_sys_truncate(const char __user *pathname, loff_t length) -{ - unsigned int lookup_flags = LOOKUP_FOLLOW; - struct path path; - int error; - - if (length < 0) /* sorry, but loff_t says... */ - return -EINVAL; - -retry: - error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path); - if (!error) { - error = vfs_truncate(&path, length); - path_put(&path); - } - if (retry_estale(error, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - goto retry; - } - return error; -} - -SYSCALL_DEFINE2(truncate, const char __user *, path, long, length) -{ - return do_sys_truncate(path, length); -} - -#ifdef CONFIG_COMPAT -COMPAT_SYSCALL_DEFINE2(truncate, const char __user *, path, compat_off_t, length) -{ - return do_sys_truncate(path, length); -} -#endif - -static long do_sys_ftruncate(unsigned int fd, loff_t length, int small) -{ - struct inode *inode; - struct dentry *dentry; - struct fd f; - int error; - - error = -EINVAL; - if (length < 0) - goto out; - error = -EBADF; - f = fdget(fd); - if (!f.file) - goto out; - - /* explicitly opened as large or we are on 64-bit box */ - if (f.file->f_flags & O_LARGEFILE) - small = 0; - - dentry = f.file->f_path.dentry; - inode = dentry->d_inode; - error = -EINVAL; - if (!S_ISREG(inode->i_mode) || !(f.file->f_mode & FMODE_WRITE)) - goto out_putf; - - error = -EINVAL; - /* Cannot ftruncate over 2^31 bytes without large file support */ - if (small && length > MAX_NON_LFS) - goto out_putf; - - error = -EPERM; - if (IS_APPEND(inode)) - goto out_putf; - - sb_start_write(inode->i_sb); - error = locks_verify_truncate(inode, f.file, length); - if (!error) - error = security_path_truncate(&f.file->f_path); - if (!error) - error = do_truncate(dentry, length, ATTR_MTIME|ATTR_CTIME, f.file); - sb_end_write(inode->i_sb); -out_putf: - fdput(f); -out: - return error; -} - -SYSCALL_DEFINE2(ftruncate, unsigned int, fd, unsigned long, length) -{ - return do_sys_ftruncate(fd, length, 1); -} - -#ifdef CONFIG_COMPAT -COMPAT_SYSCALL_DEFINE2(ftruncate, unsigned int, fd, compat_ulong_t, length) -{ - return do_sys_ftruncate(fd, length, 1); -} -#endif - -/* LFS versions of truncate are only needed on 32 bit machines */ -#if BITS_PER_LONG == 32 -SYSCALL_DEFINE2(truncate64, const char __user *, path, loff_t, length) -{ - return do_sys_truncate(path, length); -} - -SYSCALL_DEFINE2(ftruncate64, unsigned int, fd, loff_t, length) -{ - return do_sys_ftruncate(fd, length, 0); -} -#endif /* BITS_PER_LONG == 32 */ - - -int vfs_fallocate(struct file *file, int mode, loff_t offset, loff_t len) -{ - struct inode *inode = file_inode(file); - long ret; - - if (offset < 0 || len <= 0) - return -EINVAL; - - /* Return error if mode is not supported */ - if (mode & ~FALLOC_FL_SUPPORTED_MASK) - return -EOPNOTSUPP; - - /* Punch hole and zero range are mutually exclusive */ - if ((mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)) == - (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)) - return -EOPNOTSUPP; - - /* Punch hole must have keep size set */ - if ((mode & FALLOC_FL_PUNCH_HOLE) && - !(mode & FALLOC_FL_KEEP_SIZE)) - return -EOPNOTSUPP; - - /* Collapse range should only be used exclusively. */ - if ((mode & FALLOC_FL_COLLAPSE_RANGE) && - (mode & ~FALLOC_FL_COLLAPSE_RANGE)) - return -EINVAL; - - /* Insert range should only be used exclusively. */ - if ((mode & FALLOC_FL_INSERT_RANGE) && - (mode & ~FALLOC_FL_INSERT_RANGE)) - return -EINVAL; - - /* Unshare range should only be used with allocate mode. */ - if ((mode & FALLOC_FL_UNSHARE_RANGE) && - (mode & ~(FALLOC_FL_UNSHARE_RANGE | FALLOC_FL_KEEP_SIZE))) - return -EINVAL; - - if (!(file->f_mode & FMODE_WRITE)) - return -EBADF; - - /* - * We can only allow pure fallocate on append only files - */ - if ((mode & ~FALLOC_FL_KEEP_SIZE) && IS_APPEND(inode)) - return -EPERM; - - if (IS_IMMUTABLE(inode)) - return -EPERM; - - /* - * We cannot allow any fallocate operation on an active swapfile - */ - if (IS_SWAPFILE(inode)) - return -ETXTBSY; - - /* - * Revalidate the write permissions, in case security policy has - * changed since the files were opened. - */ - ret = security_file_permission(file, MAY_WRITE); - if (ret) - return ret; - - if (S_ISFIFO(inode->i_mode)) - return -ESPIPE; - - /* - * Let individual file system decide if it supports preallocation - * for directories or not. - */ - if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode) && - !S_ISBLK(inode->i_mode)) - return -ENODEV; - - /* Check for wrap through zero too */ - if (((offset + len) > inode->i_sb->s_maxbytes) || ((offset + len) < 0)) - return -EFBIG; - - if (!file->f_op->fallocate) - return -EOPNOTSUPP; - - sb_start_write(inode->i_sb); - ret = file->f_op->fallocate(file, mode, offset, len); - - /* - * Create inotify and fanotify events. - * - * To keep the logic simple always create events if fallocate succeeds. - * This implies that events are even created if the file size remains - * unchanged, e.g. when using flag FALLOC_FL_KEEP_SIZE. - */ - if (ret == 0) - fsnotify_modify(file); - - sb_end_write(inode->i_sb); - return ret; -} -EXPORT_SYMBOL_GPL(vfs_fallocate); - -SYSCALL_DEFINE4(fallocate, int, fd, int, mode, loff_t, offset, loff_t, len) -{ - struct fd f = fdget(fd); - int error = -EBADF; - - if (f.file) { - error = vfs_fallocate(f.file, mode, offset, len); - fdput(f); - } - return error; -} - -/* - * access() needs to use the real uid/gid, not the effective uid/gid. - * We do this by temporarily clearing all FS-related capabilities and - * switching the fsuid/fsgid around to the real ones. - */ -SYSCALL_DEFINE3(faccessat, int, dfd, const char __user *, filename, int, mode) -{ - const struct cred *old_cred; - struct cred *override_cred; - struct path path; - struct inode *inode; - int res; - unsigned int lookup_flags = LOOKUP_FOLLOW; - - if (mode & ~S_IRWXO) /* where's F_OK, X_OK, W_OK, R_OK? */ - return -EINVAL; - - override_cred = prepare_creds(); - if (!override_cred) - return -ENOMEM; - - override_cred->fsuid = override_cred->uid; - override_cred->fsgid = override_cred->gid; - - if (!issecure(SECURE_NO_SETUID_FIXUP)) { - /* Clear the capabilities if we switch to a non-root user */ - kuid_t root_uid = make_kuid(override_cred->user_ns, 0); - if (!uid_eq(override_cred->uid, root_uid)) - cap_clear(override_cred->cap_effective); - else - override_cred->cap_effective = - override_cred->cap_permitted; - } - - old_cred = override_creds(override_cred); -retry: - res = user_path_at(dfd, filename, lookup_flags, &path); - if (res) - goto out; - - inode = d_backing_inode(path.dentry); - - if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) { - /* - * MAY_EXEC on regular files is denied if the fs is mounted - * with the "noexec" flag. - */ - res = -EACCES; - if (path_noexec(&path)) - goto out_path_release; - } - - res = inode_permission(inode, mode | MAY_ACCESS); - /* SuS v2 requires we report a read only fs too */ - if (res || !(mode & S_IWOTH) || special_file(inode->i_mode)) - goto out_path_release; - /* - * This is a rare case where using __mnt_is_readonly() - * is OK without a mnt_want/drop_write() pair. Since - * no actual write to the fs is performed here, we do - * not need to telegraph to that to anyone. - * - * By doing this, we accept that this access is - * inherently racy and know that the fs may change - * state before we even see this result. - */ - if (__mnt_is_readonly(path.mnt)) - res = -EROFS; - -out_path_release: - path_put(&path); - if (retry_estale(res, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - goto retry; - } -out: - revert_creds(old_cred); - put_cred(override_cred); - return res; -} - -SYSCALL_DEFINE2(access, const char __user *, filename, int, mode) -{ - return sys_faccessat(AT_FDCWD, filename, mode); -} - -SYSCALL_DEFINE1(chdir, const char __user *, filename) -{ - struct path path; - int error; - unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; -retry: - error = user_path_at(AT_FDCWD, filename, lookup_flags, &path); - if (error) - goto out; - - error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); - if (error) - goto dput_and_out; - - set_fs_pwd(current->fs, &path); - -dput_and_out: - path_put(&path); - if (retry_estale(error, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - goto retry; - } -out: - return error; -} - -SYSCALL_DEFINE1(fchdir, unsigned int, fd) -{ - struct fd f = fdget_raw(fd); - struct inode *inode; - int error = -EBADF; - - error = -EBADF; - if (!f.file) - goto out; - - inode = file_inode(f.file); - - error = -ENOTDIR; - if (!S_ISDIR(inode->i_mode)) - goto out_putf; - - error = inode_permission(inode, MAY_EXEC | MAY_CHDIR); - if (!error) - set_fs_pwd(current->fs, &f.file->f_path); -out_putf: - fdput(f); -out: - return error; -} - -SYSCALL_DEFINE1(chroot, const char __user *, filename) -{ - struct path path; - int error; - unsigned int lookup_flags = LOOKUP_FOLLOW | LOOKUP_DIRECTORY; -retry: - error = user_path_at(AT_FDCWD, filename, lookup_flags, &path); - if (error) - goto out; - - error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); - if (error) - goto dput_and_out; - - error = -EPERM; - if (!ns_capable(current_user_ns(), CAP_SYS_CHROOT)) - goto dput_and_out; - error = security_path_chroot(&path); - if (error) - goto dput_and_out; - - set_fs_root(current->fs, &path); - error = 0; -dput_and_out: - path_put(&path); - if (retry_estale(error, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - goto retry; - } -out: - return error; -} - -static int chmod_common(const struct path *path, umode_t mode) -{ - struct inode *inode = path->dentry->d_inode; - struct inode *delegated_inode = NULL; - struct iattr newattrs; - int error; - - error = mnt_want_write(path->mnt); - if (error) - return error; -retry_deleg: - inode_lock(inode); - error = security_path_chmod(path, mode); - if (error) - goto out_unlock; - newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); - newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; - error = notify_change(path->dentry, &newattrs, &delegated_inode); -out_unlock: - inode_unlock(inode); - if (delegated_inode) { - error = break_deleg_wait(&delegated_inode); - if (!error) - goto retry_deleg; - } - mnt_drop_write(path->mnt); - return error; -} - -SYSCALL_DEFINE2(fchmod, unsigned int, fd, umode_t, mode) -{ - struct fd f = fdget(fd); - int err = -EBADF; - - if (f.file) { - audit_file(f.file); - err = chmod_common(&f.file->f_path, mode); - fdput(f); - } - return err; -} - -SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, umode_t, mode) -{ - struct path path; - int error; - unsigned int lookup_flags = LOOKUP_FOLLOW; -retry: - error = user_path_at(dfd, filename, lookup_flags, &path); - if (!error) { - error = chmod_common(&path, mode); - path_put(&path); - if (retry_estale(error, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - goto retry; - } - } - return error; -} - -SYSCALL_DEFINE2(chmod, const char __user *, filename, umode_t, mode) -{ - return sys_fchmodat(AT_FDCWD, filename, mode); -} - -static int chown_common(const struct path *path, uid_t user, gid_t group) -{ - struct inode *inode = path->dentry->d_inode; - struct inode *delegated_inode = NULL; - int error; - struct iattr newattrs; - kuid_t uid; - kgid_t gid; - - uid = make_kuid(current_user_ns(), user); - gid = make_kgid(current_user_ns(), group); - -retry_deleg: - newattrs.ia_valid = ATTR_CTIME; - if (user != (uid_t) -1) { - if (!uid_valid(uid)) - return -EINVAL; - newattrs.ia_valid |= ATTR_UID; - newattrs.ia_uid = uid; - } - if (group != (gid_t) -1) { - if (!gid_valid(gid)) - return -EINVAL; - newattrs.ia_valid |= ATTR_GID; - newattrs.ia_gid = gid; - } - if (!S_ISDIR(inode->i_mode)) - newattrs.ia_valid |= - ATTR_KILL_SUID | ATTR_KILL_SGID | ATTR_KILL_PRIV; - inode_lock(inode); - error = security_path_chown(path, uid, gid); - if (!error) - error = notify_change(path->dentry, &newattrs, &delegated_inode); - inode_unlock(inode); - if (delegated_inode) { - error = break_deleg_wait(&delegated_inode); - if (!error) - goto retry_deleg; - } - return error; -} - -SYSCALL_DEFINE5(fchownat, int, dfd, const char __user *, filename, uid_t, user, - gid_t, group, int, flag) -{ - struct path path; - int error = -EINVAL; - int lookup_flags; - - if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) != 0) - goto out; - - lookup_flags = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; - if (flag & AT_EMPTY_PATH) - lookup_flags |= LOOKUP_EMPTY; -retry: - error = user_path_at(dfd, filename, lookup_flags, &path); - if (error) - goto out; - error = mnt_want_write(path.mnt); - if (error) - goto out_release; - error = chown_common(&path, user, group); - mnt_drop_write(path.mnt); -out_release: - path_put(&path); - if (retry_estale(error, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - goto retry; - } -out: - return error; -} - -SYSCALL_DEFINE3(chown, const char __user *, filename, uid_t, user, gid_t, group) -{ - return sys_fchownat(AT_FDCWD, filename, user, group, 0); -} - -SYSCALL_DEFINE3(lchown, const char __user *, filename, uid_t, user, gid_t, group) -{ - return sys_fchownat(AT_FDCWD, filename, user, group, - AT_SYMLINK_NOFOLLOW); -} - -SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group) -{ - struct fd f = fdget(fd); - int error = -EBADF; - - if (!f.file) - goto out; - - error = mnt_want_write_file(f.file); - if (error) - goto out_fput; - audit_file(f.file); - error = chown_common(&f.file->f_path, user, group); - mnt_drop_write_file(f.file); -out_fput: - fdput(f); -out: - return error; -} - -int open_check_o_direct(struct file *f) -{ - /* NB: we're sure to have correct a_ops only after f_op->open */ - if (f->f_flags & O_DIRECT) { - if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO) - return -EINVAL; - } - return 0; -} - -static int do_dentry_open(struct file *f, - struct inode *inode, - int (*open)(struct inode *, struct file *), - const struct cred *cred) -{ - static const struct file_operations empty_fops = {}; - int error; - - f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK | - FMODE_PREAD | FMODE_PWRITE; - - path_get(&f->f_path); - f->f_inode = inode; - f->f_mapping = inode->i_mapping; - - if (unlikely(f->f_flags & O_PATH)) { - f->f_mode = FMODE_PATH; - f->f_op = &empty_fops; - return 0; - } - - if (f->f_mode & FMODE_WRITE && !special_file(inode->i_mode)) { - error = get_write_access(inode); - if (unlikely(error)) - goto cleanup_file; - error = __mnt_want_write(f->f_path.mnt); - if (unlikely(error)) { - put_write_access(inode); - goto cleanup_file; - } - f->f_mode |= FMODE_WRITER; - } - - /* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */ - if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)) - f->f_mode |= FMODE_ATOMIC_POS; - - f->f_op = fops_get(inode->i_fop); - if (unlikely(WARN_ON(!f->f_op))) { - error = -ENODEV; - goto cleanup_all; - } - - error = security_file_open(f, cred); - if (error) - goto cleanup_all; - - error = break_lease(locks_inode(f), f->f_flags); - if (error) - goto cleanup_all; - - if (!open) - open = f->f_op->open; - if (open) { - error = open(inode, f); - if (error) - goto cleanup_all; - } - if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ) - i_readcount_inc(inode); - if ((f->f_mode & FMODE_READ) && - likely(f->f_op->read || f->f_op->read_iter)) - f->f_mode |= FMODE_CAN_READ; - if ((f->f_mode & FMODE_WRITE) && - likely(f->f_op->write || f->f_op->write_iter)) - f->f_mode |= FMODE_CAN_WRITE; - - f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); - - file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping); - - return 0; - -cleanup_all: - fops_put(f->f_op); - if (f->f_mode & FMODE_WRITER) { - put_write_access(inode); - __mnt_drop_write(f->f_path.mnt); - } -cleanup_file: - path_put(&f->f_path); - f->f_path.mnt = NULL; - f->f_path.dentry = NULL; - f->f_inode = NULL; - return error; -} - -/** - * finish_open - finish opening a file - * @file: file pointer - * @dentry: pointer to dentry - * @open: open callback - * @opened: state of open - * - * This can be used to finish opening a file passed to i_op->atomic_open(). - * - * If the open callback is set to NULL, then the standard f_op->open() - * filesystem callback is substituted. - * - * NB: the dentry reference is _not_ consumed. If, for example, the dentry is - * the return value of d_splice_alias(), then the caller needs to perform dput() - * on it after finish_open(). - * - * On successful return @file is a fully instantiated open file. After this, if - * an error occurs in ->atomic_open(), it needs to clean up with fput(). - * - * Returns zero on success or -errno if the open failed. - */ -int finish_open(struct file *file, struct dentry *dentry, - int (*open)(struct inode *, struct file *), - int *opened) -{ - int error; - BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */ - - file->f_path.dentry = dentry; - error = do_dentry_open(file, d_backing_inode(dentry), open, - current_cred()); - if (!error) - *opened |= FILE_OPENED; - - return error; -} -EXPORT_SYMBOL(finish_open); - -/** - * finish_no_open - finish ->atomic_open() without opening the file - * - * @file: file pointer - * @dentry: dentry or NULL (as returned from ->lookup()) - * - * This can be used to set the result of a successful lookup in ->atomic_open(). - * - * NB: unlike finish_open() this function does consume the dentry reference and - * the caller need not dput() it. - * - * Returns "1" which must be the return value of ->atomic_open() after having - * called this function. - */ -int finish_no_open(struct file *file, struct dentry *dentry) -{ - file->f_path.dentry = dentry; - return 1; -} -EXPORT_SYMBOL(finish_no_open); - -char *file_path(struct file *filp, char *buf, int buflen) -{ - return d_path(&filp->f_path, buf, buflen); -} -EXPORT_SYMBOL(file_path); - -/** - * vfs_open - open the file at the given path - * @path: path to open - * @file: newly allocated file with f_flag initialized - * @cred: credentials to use - */ -int vfs_open(const struct path *path, struct file *file, - const struct cred *cred) -{ - struct dentry *dentry = d_real(path->dentry, NULL, file->f_flags); - - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - - file->f_path = *path; - return do_dentry_open(file, d_backing_inode(dentry), NULL, cred); -} - -struct file *dentry_open(const struct path *path, int flags, - const struct cred *cred) -{ - int error; - struct file *f; - - validate_creds(cred); - - /* We must always pass in a valid mount pointer. */ - BUG_ON(!path->mnt); - - f = get_empty_filp(); - if (!IS_ERR(f)) { - f->f_flags = flags; - error = vfs_open(path, f, cred); - if (!error) { - /* from now on we need fput() to dispose of f */ - error = open_check_o_direct(f); - if (error) { - fput(f); - f = ERR_PTR(error); - } - } else { - put_filp(f); - f = ERR_PTR(error); - } - } - return f; -} -EXPORT_SYMBOL(dentry_open); - -static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op) -{ - int lookup_flags = 0; - int acc_mode = ACC_MODE(flags); - - if (flags & (O_CREAT | __O_TMPFILE)) - op->mode = (mode & S_IALLUGO) | S_IFREG; - else - op->mode = 0; - - /* Must never be set by userspace */ - flags &= ~FMODE_NONOTIFY & ~O_CLOEXEC; - - /* - * O_SYNC is implemented as __O_SYNC|O_DSYNC. As many places only - * check for O_DSYNC if the need any syncing at all we enforce it's - * always set instead of having to deal with possibly weird behaviour - * for malicious applications setting only __O_SYNC. - */ - if (flags & __O_SYNC) - flags |= O_DSYNC; - - if (flags & __O_TMPFILE) { - if ((flags & O_TMPFILE_MASK) != O_TMPFILE) - return -EINVAL; - if (!(acc_mode & MAY_WRITE)) - return -EINVAL; - } else if (flags & O_PATH) { - /* - * If we have O_PATH in the open flag. Then we - * cannot have anything other than the below set of flags - */ - flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH; - acc_mode = 0; - } - - op->open_flag = flags; - - /* O_TRUNC implies we need access checks for write permissions */ - if (flags & O_TRUNC) - acc_mode |= MAY_WRITE; - - /* Allow the LSM permission hook to distinguish append - access from general write access. */ - if (flags & O_APPEND) - acc_mode |= MAY_APPEND; - - op->acc_mode = acc_mode; - - op->intent = flags & O_PATH ? 0 : LOOKUP_OPEN; - - if (flags & O_CREAT) { - op->intent |= LOOKUP_CREATE; - if (flags & O_EXCL) - op->intent |= LOOKUP_EXCL; - } - - if (flags & O_DIRECTORY) - lookup_flags |= LOOKUP_DIRECTORY; - if (!(flags & O_NOFOLLOW)) - lookup_flags |= LOOKUP_FOLLOW; - op->lookup_flags = lookup_flags; - return 0; -} - -/** - * file_open_name - open file and return file pointer - * - * @name: struct filename containing path to open - * @flags: open flags as per the open(2) second argument - * @mode: mode for the new file if O_CREAT is set, else ignored - * - * This is the helper to open a file from kernelspace if you really - * have to. But in generally you should not do this, so please move - * along, nothing to see here.. - */ -struct file *file_open_name(struct filename *name, int flags, umode_t mode) -{ - struct open_flags op; - int err = build_open_flags(flags, mode, &op); - return err ? ERR_PTR(err) : do_filp_open(AT_FDCWD, name, &op); -} - -/** - * filp_open - open file and return file pointer - * - * @filename: path to open - * @flags: open flags as per the open(2) second argument - * @mode: mode for the new file if O_CREAT is set, else ignored - * - * This is the helper to open a file from kernelspace if you really - * have to. But in generally you should not do this, so please move - * along, nothing to see here.. - */ -struct file *filp_open(const char *filename, int flags, umode_t mode) -{ - struct filename *name = getname_kernel(filename); - struct file *file = ERR_CAST(name); - - if (!IS_ERR(name)) { - file = file_open_name(name, flags, mode); - putname(name); - } - return file; -} -EXPORT_SYMBOL(filp_open); - -struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt, - const char *filename, int flags, umode_t mode) -{ - struct open_flags op; - int err = build_open_flags(flags, mode, &op); - if (err) - return ERR_PTR(err); - return do_file_open_root(dentry, mnt, filename, &op); -} -EXPORT_SYMBOL(file_open_root); - -struct file *filp_clone_open(struct file *oldfile) -{ - struct file *file; - int retval; - - file = get_empty_filp(); - if (IS_ERR(file)) - return file; - - file->f_flags = oldfile->f_flags; - retval = vfs_open(&oldfile->f_path, file, oldfile->f_cred); - if (retval) { - put_filp(file); - return ERR_PTR(retval); - } - - return file; -} -EXPORT_SYMBOL(filp_clone_open); - -long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode) -{ - struct open_flags op; - int fd = build_open_flags(flags, mode, &op); - struct filename *tmp; - - if (fd) - return fd; - - tmp = getname(filename); - if (IS_ERR(tmp)) - return PTR_ERR(tmp); - - fd = get_unused_fd_flags(flags); - if (fd >= 0) { - struct file *f = do_filp_open(dfd, tmp, &op); - if (IS_ERR(f)) { - put_unused_fd(fd); - fd = PTR_ERR(f); - } else { - fsnotify_open(f); - fd_install(fd, f); - } - } - putname(tmp); - return fd; -} - -SYSCALL_DEFINE3(open, const char __user *, filename, int, flags, umode_t, mode) -{ - if (force_o_largefile()) - flags |= O_LARGEFILE; - - return do_sys_open(AT_FDCWD, filename, flags, mode); -} - -SYSCALL_DEFINE4(openat, int, dfd, const char __user *, filename, int, flags, - umode_t, mode) -{ - if (force_o_largefile()) - flags |= O_LARGEFILE; - - return do_sys_open(dfd, filename, flags, mode); -} - -#ifndef __alpha__ - -/* - * For backward compatibility? Maybe this should be moved - * into arch/i386 instead? - */ -SYSCALL_DEFINE2(creat, const char __user *, pathname, umode_t, mode) -{ - return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); -} - -#endif - -/* - * "id" is the POSIX thread ID. We use the - * files pointer for this.. - */ -int filp_close(struct file *filp, fl_owner_t id) -{ - int retval = 0; - - if (!file_count(filp)) { - printk(KERN_ERR "VFS: Close: file count is 0\n"); - return 0; - } - - if (filp->f_op->flush) - retval = filp->f_op->flush(filp, id); - - if (likely(!(filp->f_mode & FMODE_PATH))) { - dnotify_flush(filp, id); - locks_remove_posix(filp, id); - } - fput(filp); - return retval; -} - -EXPORT_SYMBOL(filp_close); - -/* - * Careful here! We test whether the file pointer is NULL before - * releasing the fd. This ensures that one clone task can't release - * an fd while another clone is opening it. - */ -SYSCALL_DEFINE1(close, unsigned int, fd) -{ - int retval = __close_fd(current->files, fd); - - /* can't restart close syscall because file table entry was cleared */ - if (unlikely(retval == -ERESTARTSYS || - retval == -ERESTARTNOINTR || - retval == -ERESTARTNOHAND || - retval == -ERESTART_RESTARTBLOCK)) - retval = -EINTR; - - return retval; -} -EXPORT_SYMBOL(sys_close); - -/* - * This routine simulates a hangup on the tty, to arrange that users - * are given clean terminals at login time. - */ -SYSCALL_DEFINE0(vhangup) -{ - if (capable(CAP_SYS_TTY_CONFIG)) { - tty_vhangup_self(); - return 0; - } - return -EPERM; -} - -/* - * Called when an inode is about to be open. - * We use this to disallow opening large files on 32bit systems if - * the caller didn't specify O_LARGEFILE. On 64bit systems we force - * on this flag in sys_open. - */ -int generic_file_open(struct inode * inode, struct file * filp) -{ - if (!(filp->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS) - return -EOVERFLOW; - return 0; -} - -EXPORT_SYMBOL(generic_file_open); - -/* - * This is used by subsystems that don't want seekable - * file descriptors. The function is not supposed to ever fail, the only - * reason it returns an 'int' and not 'void' is so that it can be plugged - * directly into file_operations structure. - */ -int nonseekable_open(struct inode *inode, struct file *filp) -{ - filp->f_mode &= ~(FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE); - return 0; -} - -EXPORT_SYMBOL(nonseekable_open); diff --git a/src/linux/fs/orangefs/Kconfig b/src/linux/fs/orangefs/Kconfig deleted file mode 100644 index 1554c02..0000000 --- a/src/linux/fs/orangefs/Kconfig +++ /dev/null @@ -1,6 +0,0 @@ -config ORANGEFS_FS - tristate "ORANGEFS (Powered by PVFS) support" - select FS_POSIX_ACL - help - Orange is a parallel file system designed for use on high end - computing (HEC) systems. diff --git a/src/linux/fs/overlayfs/Kconfig b/src/linux/fs/overlayfs/Kconfig deleted file mode 100644 index 3435581..0000000 --- a/src/linux/fs/overlayfs/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config OVERLAY_FS - tristate "Overlay filesystem support" - help - An overlay filesystem combines two filesystems - an 'upper' filesystem - and a 'lower' filesystem. When a name exists in both filesystems, the - object in the 'upper' filesystem is visible while the object in the - 'lower' filesystem is either hidden or, in the case of directories, - merged with the 'upper' object. - - For more information see Documentation/filesystems/overlayfs.txt diff --git a/src/linux/fs/pipe.c b/src/linux/fs/pipe.c deleted file mode 100644 index 8e0d9f2..0000000 --- a/src/linux/fs/pipe.c +++ /dev/null @@ -1,1211 +0,0 @@ -/* - * linux/fs/pipe.c - * - * Copyright (C) 1991, 1992, 1999 Linus Torvalds - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "internal.h" - -/* - * The max size that a non-root user is allowed to grow the pipe. Can - * be set by root in /proc/sys/fs/pipe-max-size - */ -unsigned int pipe_max_size = 1048576; - -/* - * Minimum pipe size, as required by POSIX - */ -unsigned int pipe_min_size = PAGE_SIZE; - -/* Maximum allocatable pages per user. Hard limit is unset by default, soft - * matches default values. - */ -unsigned long pipe_user_pages_hard; -unsigned long pipe_user_pages_soft = PIPE_DEF_BUFFERS * INR_OPEN_CUR; - -/* - * We use a start+len construction, which provides full use of the - * allocated memory. - * -- Florian Coosmann (FGC) - * - * Reads with count = 0 should always return 0. - * -- Julian Bradfield 1999-06-07. - * - * FIFOs and Pipes now generate SIGIO for both readers and writers. - * -- Jeremy Elson 2001-08-16 - * - * pipe_read & write cleanup - * -- Manfred Spraul 2002-05-09 - */ - -static void pipe_lock_nested(struct pipe_inode_info *pipe, int subclass) -{ - if (pipe->files) - mutex_lock_nested(&pipe->mutex, subclass); -} - -void pipe_lock(struct pipe_inode_info *pipe) -{ - /* - * pipe_lock() nests non-pipe inode locks (for writing to a file) - */ - pipe_lock_nested(pipe, I_MUTEX_PARENT); -} -EXPORT_SYMBOL(pipe_lock); - -void pipe_unlock(struct pipe_inode_info *pipe) -{ - if (pipe->files) - mutex_unlock(&pipe->mutex); -} -EXPORT_SYMBOL(pipe_unlock); - -static inline void __pipe_lock(struct pipe_inode_info *pipe) -{ - mutex_lock_nested(&pipe->mutex, I_MUTEX_PARENT); -} - -static inline void __pipe_unlock(struct pipe_inode_info *pipe) -{ - mutex_unlock(&pipe->mutex); -} - -void pipe_double_lock(struct pipe_inode_info *pipe1, - struct pipe_inode_info *pipe2) -{ - BUG_ON(pipe1 == pipe2); - - if (pipe1 < pipe2) { - pipe_lock_nested(pipe1, I_MUTEX_PARENT); - pipe_lock_nested(pipe2, I_MUTEX_CHILD); - } else { - pipe_lock_nested(pipe2, I_MUTEX_PARENT); - pipe_lock_nested(pipe1, I_MUTEX_CHILD); - } -} - -/* Drop the inode semaphore and wait for a pipe event, atomically */ -void pipe_wait(struct pipe_inode_info *pipe) -{ - DEFINE_WAIT(wait); - - /* - * Pipes are system-local resources, so sleeping on them - * is considered a noninteractive wait: - */ - prepare_to_wait(&pipe->wait, &wait, TASK_INTERRUPTIBLE); - pipe_unlock(pipe); - schedule(); - finish_wait(&pipe->wait, &wait); - pipe_lock(pipe); -} - -static void anon_pipe_buf_release(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) -{ - struct page *page = buf->page; - - /* - * If nobody else uses this page, and we don't already have a - * temporary page, let's keep track of it as a one-deep - * allocation cache. (Otherwise just release our reference to it) - */ - if (page_count(page) == 1 && !pipe->tmp_page) - pipe->tmp_page = page; - else - put_page(page); -} - -static int anon_pipe_buf_steal(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) -{ - struct page *page = buf->page; - - if (page_count(page) == 1) { - if (memcg_kmem_enabled()) - memcg_kmem_uncharge(page, 0); - __SetPageLocked(page); - return 0; - } - return 1; -} - -/** - * generic_pipe_buf_steal - attempt to take ownership of a &pipe_buffer - * @pipe: the pipe that the buffer belongs to - * @buf: the buffer to attempt to steal - * - * Description: - * This function attempts to steal the &struct page attached to - * @buf. If successful, this function returns 0 and returns with - * the page locked. The caller may then reuse the page for whatever - * he wishes; the typical use is insertion into a different file - * page cache. - */ -int generic_pipe_buf_steal(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) -{ - struct page *page = buf->page; - - /* - * A reference of one is golden, that means that the owner of this - * page is the only one holding a reference to it. lock the page - * and return OK. - */ - if (page_count(page) == 1) { - lock_page(page); - return 0; - } - - return 1; -} -EXPORT_SYMBOL(generic_pipe_buf_steal); - -/** - * generic_pipe_buf_get - get a reference to a &struct pipe_buffer - * @pipe: the pipe that the buffer belongs to - * @buf: the buffer to get a reference to - * - * Description: - * This function grabs an extra reference to @buf. It's used in - * in the tee() system call, when we duplicate the buffers in one - * pipe into another. - */ -void generic_pipe_buf_get(struct pipe_inode_info *pipe, struct pipe_buffer *buf) -{ - get_page(buf->page); -} -EXPORT_SYMBOL(generic_pipe_buf_get); - -/** - * generic_pipe_buf_confirm - verify contents of the pipe buffer - * @info: the pipe that the buffer belongs to - * @buf: the buffer to confirm - * - * Description: - * This function does nothing, because the generic pipe code uses - * pages that are always good when inserted into the pipe. - */ -int generic_pipe_buf_confirm(struct pipe_inode_info *info, - struct pipe_buffer *buf) -{ - return 0; -} -EXPORT_SYMBOL(generic_pipe_buf_confirm); - -/** - * generic_pipe_buf_release - put a reference to a &struct pipe_buffer - * @pipe: the pipe that the buffer belongs to - * @buf: the buffer to put a reference to - * - * Description: - * This function releases a reference to @buf. - */ -void generic_pipe_buf_release(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) -{ - put_page(buf->page); -} -EXPORT_SYMBOL(generic_pipe_buf_release); - -static const struct pipe_buf_operations anon_pipe_buf_ops = { - .can_merge = 1, - .confirm = generic_pipe_buf_confirm, - .release = anon_pipe_buf_release, - .steal = anon_pipe_buf_steal, - .get = generic_pipe_buf_get, -}; - -static const struct pipe_buf_operations packet_pipe_buf_ops = { - .can_merge = 0, - .confirm = generic_pipe_buf_confirm, - .release = anon_pipe_buf_release, - .steal = anon_pipe_buf_steal, - .get = generic_pipe_buf_get, -}; - -static ssize_t -pipe_read(struct kiocb *iocb, struct iov_iter *to) -{ - size_t total_len = iov_iter_count(to); - struct file *filp = iocb->ki_filp; - struct pipe_inode_info *pipe = filp->private_data; - int do_wakeup; - ssize_t ret; - - /* Null read succeeds. */ - if (unlikely(total_len == 0)) - return 0; - - do_wakeup = 0; - ret = 0; - __pipe_lock(pipe); - for (;;) { - int bufs = pipe->nrbufs; - if (bufs) { - int curbuf = pipe->curbuf; - struct pipe_buffer *buf = pipe->bufs + curbuf; - size_t chars = buf->len; - size_t written; - int error; - - if (chars > total_len) - chars = total_len; - - error = pipe_buf_confirm(pipe, buf); - if (error) { - if (!ret) - ret = error; - break; - } - - written = copy_page_to_iter(buf->page, buf->offset, chars, to); - if (unlikely(written < chars)) { - if (!ret) - ret = -EFAULT; - break; - } - ret += chars; - buf->offset += chars; - buf->len -= chars; - - /* Was it a packet buffer? Clean up and exit */ - if (buf->flags & PIPE_BUF_FLAG_PACKET) { - total_len = chars; - buf->len = 0; - } - - if (!buf->len) { - pipe_buf_release(pipe, buf); - curbuf = (curbuf + 1) & (pipe->buffers - 1); - pipe->curbuf = curbuf; - pipe->nrbufs = --bufs; - do_wakeup = 1; - } - total_len -= chars; - if (!total_len) - break; /* common path: read succeeded */ - } - if (bufs) /* More to do? */ - continue; - if (!pipe->writers) - break; - if (!pipe->waiting_writers) { - /* syscall merging: Usually we must not sleep - * if O_NONBLOCK is set, or if we got some data. - * But if a writer sleeps in kernel space, then - * we can wait for that data without violating POSIX. - */ - if (ret) - break; - if (filp->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - break; - } - } - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - if (do_wakeup) { - wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT | POLLWRNORM); - kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); - } - pipe_wait(pipe); - } - __pipe_unlock(pipe); - - /* Signal writers asynchronously that there is more room. */ - if (do_wakeup) { - wake_up_interruptible_sync_poll(&pipe->wait, POLLOUT | POLLWRNORM); - kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); - } - if (ret > 0) - file_accessed(filp); - return ret; -} - -static inline int is_packetized(struct file *file) -{ - return (file->f_flags & O_DIRECT) != 0; -} - -static ssize_t -pipe_write(struct kiocb *iocb, struct iov_iter *from) -{ - struct file *filp = iocb->ki_filp; - struct pipe_inode_info *pipe = filp->private_data; - ssize_t ret = 0; - int do_wakeup = 0; - size_t total_len = iov_iter_count(from); - ssize_t chars; - - /* Null write succeeds. */ - if (unlikely(total_len == 0)) - return 0; - - __pipe_lock(pipe); - - if (!pipe->readers) { - send_sig(SIGPIPE, current, 0); - ret = -EPIPE; - goto out; - } - - /* We try to merge small writes */ - chars = total_len & (PAGE_SIZE-1); /* size of the last buffer */ - if (pipe->nrbufs && chars != 0) { - int lastbuf = (pipe->curbuf + pipe->nrbufs - 1) & - (pipe->buffers - 1); - struct pipe_buffer *buf = pipe->bufs + lastbuf; - int offset = buf->offset + buf->len; - - if (buf->ops->can_merge && offset + chars <= PAGE_SIZE) { - ret = pipe_buf_confirm(pipe, buf); - if (ret) - goto out; - - ret = copy_page_from_iter(buf->page, offset, chars, from); - if (unlikely(ret < chars)) { - ret = -EFAULT; - goto out; - } - do_wakeup = 1; - buf->len += ret; - if (!iov_iter_count(from)) - goto out; - } - } - - for (;;) { - int bufs; - - if (!pipe->readers) { - send_sig(SIGPIPE, current, 0); - if (!ret) - ret = -EPIPE; - break; - } - bufs = pipe->nrbufs; - if (bufs < pipe->buffers) { - int newbuf = (pipe->curbuf + bufs) & (pipe->buffers-1); - struct pipe_buffer *buf = pipe->bufs + newbuf; - struct page *page = pipe->tmp_page; - int copied; - - if (!page) { - page = alloc_page(GFP_HIGHUSER | __GFP_ACCOUNT); - if (unlikely(!page)) { - ret = ret ? : -ENOMEM; - break; - } - pipe->tmp_page = page; - } - /* Always wake up, even if the copy fails. Otherwise - * we lock up (O_NONBLOCK-)readers that sleep due to - * syscall merging. - * FIXME! Is this really true? - */ - do_wakeup = 1; - copied = copy_page_from_iter(page, 0, PAGE_SIZE, from); - if (unlikely(copied < PAGE_SIZE && iov_iter_count(from))) { - if (!ret) - ret = -EFAULT; - break; - } - ret += copied; - - /* Insert it into the buffer array */ - buf->page = page; - buf->ops = &anon_pipe_buf_ops; - buf->offset = 0; - buf->len = copied; - buf->flags = 0; - if (is_packetized(filp)) { - buf->ops = &packet_pipe_buf_ops; - buf->flags = PIPE_BUF_FLAG_PACKET; - } - pipe->nrbufs = ++bufs; - pipe->tmp_page = NULL; - - if (!iov_iter_count(from)) - break; - } - if (bufs < pipe->buffers) - continue; - if (filp->f_flags & O_NONBLOCK) { - if (!ret) - ret = -EAGAIN; - break; - } - if (signal_pending(current)) { - if (!ret) - ret = -ERESTARTSYS; - break; - } - if (do_wakeup) { - wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLRDNORM); - kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); - do_wakeup = 0; - } - pipe->waiting_writers++; - pipe_wait(pipe); - pipe->waiting_writers--; - } -out: - __pipe_unlock(pipe); - if (do_wakeup) { - wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLRDNORM); - kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); - } - if (ret > 0 && sb_start_write_trylock(file_inode(filp)->i_sb)) { - int err = file_update_time(filp); - if (err) - ret = err; - sb_end_write(file_inode(filp)->i_sb); - } - return ret; -} - -static long pipe_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) -{ - struct pipe_inode_info *pipe = filp->private_data; - int count, buf, nrbufs; - - switch (cmd) { - case FIONREAD: - __pipe_lock(pipe); - count = 0; - buf = pipe->curbuf; - nrbufs = pipe->nrbufs; - while (--nrbufs >= 0) { - count += pipe->bufs[buf].len; - buf = (buf+1) & (pipe->buffers - 1); - } - __pipe_unlock(pipe); - - return put_user(count, (int __user *)arg); - default: - return -ENOIOCTLCMD; - } -} - -/* No kernel lock held - fine */ -static unsigned int -pipe_poll(struct file *filp, poll_table *wait) -{ - unsigned int mask; - struct pipe_inode_info *pipe = filp->private_data; - int nrbufs; - - poll_wait(filp, &pipe->wait, wait); - - /* Reading only -- no need for acquiring the semaphore. */ - nrbufs = pipe->nrbufs; - mask = 0; - if (filp->f_mode & FMODE_READ) { - mask = (nrbufs > 0) ? POLLIN | POLLRDNORM : 0; - if (!pipe->writers && filp->f_version != pipe->w_counter) - mask |= POLLHUP; - } - - if (filp->f_mode & FMODE_WRITE) { - mask |= (nrbufs < pipe->buffers) ? POLLOUT | POLLWRNORM : 0; - /* - * Most Unices do not set POLLERR for FIFOs but on Linux they - * behave exactly like pipes for poll(). - */ - if (!pipe->readers) - mask |= POLLERR; - } - - return mask; -} - -static void put_pipe_info(struct inode *inode, struct pipe_inode_info *pipe) -{ - int kill = 0; - - spin_lock(&inode->i_lock); - if (!--pipe->files) { - inode->i_pipe = NULL; - kill = 1; - } - spin_unlock(&inode->i_lock); - - if (kill) - free_pipe_info(pipe); -} - -static int -pipe_release(struct inode *inode, struct file *file) -{ - struct pipe_inode_info *pipe = file->private_data; - - __pipe_lock(pipe); - if (file->f_mode & FMODE_READ) - pipe->readers--; - if (file->f_mode & FMODE_WRITE) - pipe->writers--; - - if (pipe->readers || pipe->writers) { - wake_up_interruptible_sync_poll(&pipe->wait, POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM | POLLERR | POLLHUP); - kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); - kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); - } - __pipe_unlock(pipe); - - put_pipe_info(inode, pipe); - return 0; -} - -static int -pipe_fasync(int fd, struct file *filp, int on) -{ - struct pipe_inode_info *pipe = filp->private_data; - int retval = 0; - - __pipe_lock(pipe); - if (filp->f_mode & FMODE_READ) - retval = fasync_helper(fd, filp, on, &pipe->fasync_readers); - if ((filp->f_mode & FMODE_WRITE) && retval >= 0) { - retval = fasync_helper(fd, filp, on, &pipe->fasync_writers); - if (retval < 0 && (filp->f_mode & FMODE_READ)) - /* this can happen only if on == T */ - fasync_helper(-1, filp, 0, &pipe->fasync_readers); - } - __pipe_unlock(pipe); - return retval; -} - -static unsigned long account_pipe_buffers(struct user_struct *user, - unsigned long old, unsigned long new) -{ - return atomic_long_add_return(new - old, &user->pipe_bufs); -} - -static bool too_many_pipe_buffers_soft(unsigned long user_bufs) -{ - return pipe_user_pages_soft && user_bufs >= pipe_user_pages_soft; -} - -static bool too_many_pipe_buffers_hard(unsigned long user_bufs) -{ - return pipe_user_pages_hard && user_bufs >= pipe_user_pages_hard; -} - -struct pipe_inode_info *alloc_pipe_info(void) -{ - struct pipe_inode_info *pipe; - unsigned long pipe_bufs = PIPE_DEF_BUFFERS; - struct user_struct *user = get_current_user(); - unsigned long user_bufs; - - pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL_ACCOUNT); - if (pipe == NULL) - goto out_free_uid; - - if (pipe_bufs * PAGE_SIZE > pipe_max_size && !capable(CAP_SYS_RESOURCE)) - pipe_bufs = pipe_max_size >> PAGE_SHIFT; - - user_bufs = account_pipe_buffers(user, 0, pipe_bufs); - - if (too_many_pipe_buffers_soft(user_bufs)) { - user_bufs = account_pipe_buffers(user, pipe_bufs, 1); - pipe_bufs = 1; - } - - if (too_many_pipe_buffers_hard(user_bufs)) - goto out_revert_acct; - - pipe->bufs = kcalloc(pipe_bufs, sizeof(struct pipe_buffer), - GFP_KERNEL_ACCOUNT); - - if (pipe->bufs) { - init_waitqueue_head(&pipe->wait); - pipe->r_counter = pipe->w_counter = 1; - pipe->buffers = pipe_bufs; - pipe->user = user; - mutex_init(&pipe->mutex); - return pipe; - } - -out_revert_acct: - (void) account_pipe_buffers(user, pipe_bufs, 0); - kfree(pipe); -out_free_uid: - free_uid(user); - return NULL; -} - -void free_pipe_info(struct pipe_inode_info *pipe) -{ - int i; - - (void) account_pipe_buffers(pipe->user, pipe->buffers, 0); - free_uid(pipe->user); - for (i = 0; i < pipe->buffers; i++) { - struct pipe_buffer *buf = pipe->bufs + i; - if (buf->ops) - pipe_buf_release(pipe, buf); - } - if (pipe->tmp_page) - __free_page(pipe->tmp_page); - kfree(pipe->bufs); - kfree(pipe); -} - -static struct vfsmount *pipe_mnt __read_mostly; - -/* - * pipefs_dname() is called from d_path(). - */ -static char *pipefs_dname(struct dentry *dentry, char *buffer, int buflen) -{ - return dynamic_dname(dentry, buffer, buflen, "pipe:[%lu]", - d_inode(dentry)->i_ino); -} - -static const struct dentry_operations pipefs_dentry_operations = { - .d_dname = pipefs_dname, -}; - -static struct inode * get_pipe_inode(void) -{ - struct inode *inode = new_inode_pseudo(pipe_mnt->mnt_sb); - struct pipe_inode_info *pipe; - - if (!inode) - goto fail_inode; - - inode->i_ino = get_next_ino(); - - pipe = alloc_pipe_info(); - if (!pipe) - goto fail_iput; - - inode->i_pipe = pipe; - pipe->files = 2; - pipe->readers = pipe->writers = 1; - inode->i_fop = &pipefifo_fops; - - /* - * Mark the inode dirty from the very beginning, - * that way it will never be moved to the dirty - * list because "mark_inode_dirty()" will think - * that it already _is_ on the dirty list. - */ - inode->i_state = I_DIRTY; - inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR; - inode->i_uid = current_fsuid(); - inode->i_gid = current_fsgid(); - inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); - - return inode; - -fail_iput: - iput(inode); - -fail_inode: - return NULL; -} - -int create_pipe_files(struct file **res, int flags) -{ - int err; - struct inode *inode = get_pipe_inode(); - struct file *f; - struct path path; - static struct qstr name = { .name = "" }; - - if (!inode) - return -ENFILE; - - err = -ENOMEM; - path.dentry = d_alloc_pseudo(pipe_mnt->mnt_sb, &name); - if (!path.dentry) - goto err_inode; - path.mnt = mntget(pipe_mnt); - - d_instantiate(path.dentry, inode); - - f = alloc_file(&path, FMODE_WRITE, &pipefifo_fops); - if (IS_ERR(f)) { - err = PTR_ERR(f); - goto err_dentry; - } - - f->f_flags = O_WRONLY | (flags & (O_NONBLOCK | O_DIRECT)); - f->private_data = inode->i_pipe; - - res[0] = alloc_file(&path, FMODE_READ, &pipefifo_fops); - if (IS_ERR(res[0])) { - err = PTR_ERR(res[0]); - goto err_file; - } - - path_get(&path); - res[0]->private_data = inode->i_pipe; - res[0]->f_flags = O_RDONLY | (flags & O_NONBLOCK); - res[1] = f; - return 0; - -err_file: - put_filp(f); -err_dentry: - free_pipe_info(inode->i_pipe); - path_put(&path); - return err; - -err_inode: - free_pipe_info(inode->i_pipe); - iput(inode); - return err; -} - -static int __do_pipe_flags(int *fd, struct file **files, int flags) -{ - int error; - int fdw, fdr; - - if (flags & ~(O_CLOEXEC | O_NONBLOCK | O_DIRECT)) - return -EINVAL; - - error = create_pipe_files(files, flags); - if (error) - return error; - - error = get_unused_fd_flags(flags); - if (error < 0) - goto err_read_pipe; - fdr = error; - - error = get_unused_fd_flags(flags); - if (error < 0) - goto err_fdr; - fdw = error; - - audit_fd_pair(fdr, fdw); - fd[0] = fdr; - fd[1] = fdw; - return 0; - - err_fdr: - put_unused_fd(fdr); - err_read_pipe: - fput(files[0]); - fput(files[1]); - return error; -} - -int do_pipe_flags(int *fd, int flags) -{ - struct file *files[2]; - int error = __do_pipe_flags(fd, files, flags); - if (!error) { - fd_install(fd[0], files[0]); - fd_install(fd[1], files[1]); - } - return error; -} - -/* - * sys_pipe() is the normal C calling standard for creating - * a pipe. It's not the way Unix traditionally does this, though. - */ -SYSCALL_DEFINE2(pipe2, int __user *, fildes, int, flags) -{ - struct file *files[2]; - int fd[2]; - int error; - - error = __do_pipe_flags(fd, files, flags); - if (!error) { - if (unlikely(copy_to_user(fildes, fd, sizeof(fd)))) { - fput(files[0]); - fput(files[1]); - put_unused_fd(fd[0]); - put_unused_fd(fd[1]); - error = -EFAULT; - } else { - fd_install(fd[0], files[0]); - fd_install(fd[1], files[1]); - } - } - return error; -} - -SYSCALL_DEFINE1(pipe, int __user *, fildes) -{ - return sys_pipe2(fildes, 0); -} - -static int wait_for_partner(struct pipe_inode_info *pipe, unsigned int *cnt) -{ - int cur = *cnt; - - while (cur == *cnt) { - pipe_wait(pipe); - if (signal_pending(current)) - break; - } - return cur == *cnt ? -ERESTARTSYS : 0; -} - -static void wake_up_partner(struct pipe_inode_info *pipe) -{ - wake_up_interruptible(&pipe->wait); -} - -static int fifo_open(struct inode *inode, struct file *filp) -{ - struct pipe_inode_info *pipe; - bool is_pipe = inode->i_sb->s_magic == PIPEFS_MAGIC; - int ret; - - filp->f_version = 0; - - spin_lock(&inode->i_lock); - if (inode->i_pipe) { - pipe = inode->i_pipe; - pipe->files++; - spin_unlock(&inode->i_lock); - } else { - spin_unlock(&inode->i_lock); - pipe = alloc_pipe_info(); - if (!pipe) - return -ENOMEM; - pipe->files = 1; - spin_lock(&inode->i_lock); - if (unlikely(inode->i_pipe)) { - inode->i_pipe->files++; - spin_unlock(&inode->i_lock); - free_pipe_info(pipe); - pipe = inode->i_pipe; - } else { - inode->i_pipe = pipe; - spin_unlock(&inode->i_lock); - } - } - filp->private_data = pipe; - /* OK, we have a pipe and it's pinned down */ - - __pipe_lock(pipe); - - /* We can only do regular read/write on fifos */ - filp->f_mode &= (FMODE_READ | FMODE_WRITE); - - switch (filp->f_mode) { - case FMODE_READ: - /* - * O_RDONLY - * POSIX.1 says that O_NONBLOCK means return with the FIFO - * opened, even when there is no process writing the FIFO. - */ - pipe->r_counter++; - if (pipe->readers++ == 0) - wake_up_partner(pipe); - - if (!is_pipe && !pipe->writers) { - if ((filp->f_flags & O_NONBLOCK)) { - /* suppress POLLHUP until we have - * seen a writer */ - filp->f_version = pipe->w_counter; - } else { - if (wait_for_partner(pipe, &pipe->w_counter)) - goto err_rd; - } - } - break; - - case FMODE_WRITE: - /* - * O_WRONLY - * POSIX.1 says that O_NONBLOCK means return -1 with - * errno=ENXIO when there is no process reading the FIFO. - */ - ret = -ENXIO; - if (!is_pipe && (filp->f_flags & O_NONBLOCK) && !pipe->readers) - goto err; - - pipe->w_counter++; - if (!pipe->writers++) - wake_up_partner(pipe); - - if (!is_pipe && !pipe->readers) { - if (wait_for_partner(pipe, &pipe->r_counter)) - goto err_wr; - } - break; - - case FMODE_READ | FMODE_WRITE: - /* - * O_RDWR - * POSIX.1 leaves this case "undefined" when O_NONBLOCK is set. - * This implementation will NEVER block on a O_RDWR open, since - * the process can at least talk to itself. - */ - - pipe->readers++; - pipe->writers++; - pipe->r_counter++; - pipe->w_counter++; - if (pipe->readers == 1 || pipe->writers == 1) - wake_up_partner(pipe); - break; - - default: - ret = -EINVAL; - goto err; - } - - /* Ok! */ - __pipe_unlock(pipe); - return 0; - -err_rd: - if (!--pipe->readers) - wake_up_interruptible(&pipe->wait); - ret = -ERESTARTSYS; - goto err; - -err_wr: - if (!--pipe->writers) - wake_up_interruptible(&pipe->wait); - ret = -ERESTARTSYS; - goto err; - -err: - __pipe_unlock(pipe); - - put_pipe_info(inode, pipe); - return ret; -} - -const struct file_operations pipefifo_fops = { - .open = fifo_open, - .llseek = no_llseek, - .read_iter = pipe_read, - .write_iter = pipe_write, - .poll = pipe_poll, - .unlocked_ioctl = pipe_ioctl, - .release = pipe_release, - .fasync = pipe_fasync, -}; - -/* - * Currently we rely on the pipe array holding a power-of-2 number - * of pages. - */ -static inline unsigned int round_pipe_size(unsigned int size) -{ - unsigned long nr_pages; - - nr_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - return roundup_pow_of_two(nr_pages) << PAGE_SHIFT; -} - -/* - * Allocate a new array of pipe buffers and copy the info over. Returns the - * pipe size if successful, or return -ERROR on error. - */ -static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg) -{ - struct pipe_buffer *bufs; - unsigned int size, nr_pages; - unsigned long user_bufs; - long ret = 0; - - size = round_pipe_size(arg); - nr_pages = size >> PAGE_SHIFT; - - if (!nr_pages) - return -EINVAL; - - /* - * If trying to increase the pipe capacity, check that an - * unprivileged user is not trying to exceed various limits - * (soft limit check here, hard limit check just below). - * Decreasing the pipe capacity is always permitted, even - * if the user is currently over a limit. - */ - if (nr_pages > pipe->buffers && - size > pipe_max_size && !capable(CAP_SYS_RESOURCE)) - return -EPERM; - - user_bufs = account_pipe_buffers(pipe->user, pipe->buffers, nr_pages); - - if (nr_pages > pipe->buffers && - (too_many_pipe_buffers_hard(user_bufs) || - too_many_pipe_buffers_soft(user_bufs)) && - !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) { - ret = -EPERM; - goto out_revert_acct; - } - - /* - * We can shrink the pipe, if arg >= pipe->nrbufs. Since we don't - * expect a lot of shrink+grow operations, just free and allocate - * again like we would do for growing. If the pipe currently - * contains more buffers than arg, then return busy. - */ - if (nr_pages < pipe->nrbufs) { - ret = -EBUSY; - goto out_revert_acct; - } - - bufs = kcalloc(nr_pages, sizeof(*bufs), - GFP_KERNEL_ACCOUNT | __GFP_NOWARN); - if (unlikely(!bufs)) { - ret = -ENOMEM; - goto out_revert_acct; - } - - /* - * The pipe array wraps around, so just start the new one at zero - * and adjust the indexes. - */ - if (pipe->nrbufs) { - unsigned int tail; - unsigned int head; - - tail = pipe->curbuf + pipe->nrbufs; - if (tail < pipe->buffers) - tail = 0; - else - tail &= (pipe->buffers - 1); - - head = pipe->nrbufs - tail; - if (head) - memcpy(bufs, pipe->bufs + pipe->curbuf, head * sizeof(struct pipe_buffer)); - if (tail) - memcpy(bufs + head, pipe->bufs, tail * sizeof(struct pipe_buffer)); - } - - pipe->curbuf = 0; - kfree(pipe->bufs); - pipe->bufs = bufs; - pipe->buffers = nr_pages; - return nr_pages * PAGE_SIZE; - -out_revert_acct: - (void) account_pipe_buffers(pipe->user, nr_pages, pipe->buffers); - return ret; -} - -/* - * This should work even if CONFIG_PROC_FS isn't set, as proc_dointvec_minmax - * will return an error. - */ -int pipe_proc_fn(struct ctl_table *table, int write, void __user *buf, - size_t *lenp, loff_t *ppos) -{ - int ret; - - ret = proc_dointvec_minmax(table, write, buf, lenp, ppos); - if (ret < 0 || !write) - return ret; - - pipe_max_size = round_pipe_size(pipe_max_size); - return ret; -} - -/* - * After the inode slimming patch, i_pipe/i_bdev/i_cdev share the same - * location, so checking ->i_pipe is not enough to verify that this is a - * pipe. - */ -struct pipe_inode_info *get_pipe_info(struct file *file) -{ - return file->f_op == &pipefifo_fops ? file->private_data : NULL; -} - -long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct pipe_inode_info *pipe; - long ret; - - pipe = get_pipe_info(file); - if (!pipe) - return -EBADF; - - __pipe_lock(pipe); - - switch (cmd) { - case F_SETPIPE_SZ: - ret = pipe_set_size(pipe, arg); - break; - case F_GETPIPE_SZ: - ret = pipe->buffers * PAGE_SIZE; - break; - default: - ret = -EINVAL; - break; - } - - __pipe_unlock(pipe); - return ret; -} - -static const struct super_operations pipefs_ops = { - .destroy_inode = free_inode_nonrcu, - .statfs = simple_statfs, -}; - -/* - * pipefs should _never_ be mounted by userland - too much of security hassle, - * no real gain from having the whole whorehouse mounted. So we don't need - * any operations on the root directory. However, we need a non-trivial - * d_name - pipe: will go nicely and kill the special-casing in procfs. - */ -static struct dentry *pipefs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_pseudo(fs_type, "pipe:", &pipefs_ops, - &pipefs_dentry_operations, PIPEFS_MAGIC); -} - -static struct file_system_type pipe_fs_type = { - .name = "pipefs", - .mount = pipefs_mount, - .kill_sb = kill_anon_super, -}; - -static int __init init_pipe_fs(void) -{ - int err = register_filesystem(&pipe_fs_type); - - if (!err) { - pipe_mnt = kern_mount(&pipe_fs_type); - if (IS_ERR(pipe_mnt)) { - err = PTR_ERR(pipe_mnt); - unregister_filesystem(&pipe_fs_type); - } - } - return err; -} - -fs_initcall(init_pipe_fs); diff --git a/src/linux/fs/pnode.c b/src/linux/fs/pnode.c deleted file mode 100644 index 234a9ac..0000000 --- a/src/linux/fs/pnode.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - * linux/fs/pnode.c - * - * (C) Copyright IBM Corporation 2005. - * Released under GPL v2. - * Author : Ram Pai (linuxram@us.ibm.com) - * - */ -#include -#include -#include -#include -#include "internal.h" -#include "pnode.h" - -/* return the next shared peer mount of @p */ -static inline struct mount *next_peer(struct mount *p) -{ - return list_entry(p->mnt_share.next, struct mount, mnt_share); -} - -static inline struct mount *first_slave(struct mount *p) -{ - return list_entry(p->mnt_slave_list.next, struct mount, mnt_slave); -} - -static inline struct mount *next_slave(struct mount *p) -{ - return list_entry(p->mnt_slave.next, struct mount, mnt_slave); -} - -static struct mount *get_peer_under_root(struct mount *mnt, - struct mnt_namespace *ns, - const struct path *root) -{ - struct mount *m = mnt; - - do { - /* Check the namespace first for optimization */ - if (m->mnt_ns == ns && is_path_reachable(m, m->mnt.mnt_root, root)) - return m; - - m = next_peer(m); - } while (m != mnt); - - return NULL; -} - -/* - * Get ID of closest dominating peer group having a representative - * under the given root. - * - * Caller must hold namespace_sem - */ -int get_dominating_id(struct mount *mnt, const struct path *root) -{ - struct mount *m; - - for (m = mnt->mnt_master; m != NULL; m = m->mnt_master) { - struct mount *d = get_peer_under_root(m, mnt->mnt_ns, root); - if (d) - return d->mnt_group_id; - } - - return 0; -} - -static int do_make_slave(struct mount *mnt) -{ - struct mount *peer_mnt = mnt, *master = mnt->mnt_master; - struct mount *slave_mnt; - - /* - * slave 'mnt' to a peer mount that has the - * same root dentry. If none is available then - * slave it to anything that is available. - */ - while ((peer_mnt = next_peer(peer_mnt)) != mnt && - peer_mnt->mnt.mnt_root != mnt->mnt.mnt_root) ; - - if (peer_mnt == mnt) { - peer_mnt = next_peer(mnt); - if (peer_mnt == mnt) - peer_mnt = NULL; - } - if (mnt->mnt_group_id && IS_MNT_SHARED(mnt) && - list_empty(&mnt->mnt_share)) - mnt_release_group_id(mnt); - - list_del_init(&mnt->mnt_share); - mnt->mnt_group_id = 0; - - if (peer_mnt) - master = peer_mnt; - - if (master) { - list_for_each_entry(slave_mnt, &mnt->mnt_slave_list, mnt_slave) - slave_mnt->mnt_master = master; - list_move(&mnt->mnt_slave, &master->mnt_slave_list); - list_splice(&mnt->mnt_slave_list, master->mnt_slave_list.prev); - INIT_LIST_HEAD(&mnt->mnt_slave_list); - } else { - struct list_head *p = &mnt->mnt_slave_list; - while (!list_empty(p)) { - slave_mnt = list_first_entry(p, - struct mount, mnt_slave); - list_del_init(&slave_mnt->mnt_slave); - slave_mnt->mnt_master = NULL; - } - } - mnt->mnt_master = master; - CLEAR_MNT_SHARED(mnt); - return 0; -} - -/* - * vfsmount lock must be held for write - */ -void change_mnt_propagation(struct mount *mnt, int type) -{ - if (type == MS_SHARED) { - set_mnt_shared(mnt); - return; - } - do_make_slave(mnt); - if (type != MS_SLAVE) { - list_del_init(&mnt->mnt_slave); - mnt->mnt_master = NULL; - if (type == MS_UNBINDABLE) - mnt->mnt.mnt_flags |= MNT_UNBINDABLE; - else - mnt->mnt.mnt_flags &= ~MNT_UNBINDABLE; - } -} - -/* - * get the next mount in the propagation tree. - * @m: the mount seen last - * @origin: the original mount from where the tree walk initiated - * - * Note that peer groups form contiguous segments of slave lists. - * We rely on that in get_source() to be able to find out if - * vfsmount found while iterating with propagation_next() is - * a peer of one we'd found earlier. - */ -static struct mount *propagation_next(struct mount *m, - struct mount *origin) -{ - /* are there any slaves of this mount? */ - if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list)) - return first_slave(m); - - while (1) { - struct mount *master = m->mnt_master; - - if (master == origin->mnt_master) { - struct mount *next = next_peer(m); - return (next == origin) ? NULL : next; - } else if (m->mnt_slave.next != &master->mnt_slave_list) - return next_slave(m); - - /* back at master */ - m = master; - } -} - -static struct mount *next_group(struct mount *m, struct mount *origin) -{ - while (1) { - while (1) { - struct mount *next; - if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list)) - return first_slave(m); - next = next_peer(m); - if (m->mnt_group_id == origin->mnt_group_id) { - if (next == origin) - return NULL; - } else if (m->mnt_slave.next != &next->mnt_slave) - break; - m = next; - } - /* m is the last peer */ - while (1) { - struct mount *master = m->mnt_master; - if (m->mnt_slave.next != &master->mnt_slave_list) - return next_slave(m); - m = next_peer(master); - if (master->mnt_group_id == origin->mnt_group_id) - break; - if (master->mnt_slave.next == &m->mnt_slave) - break; - m = master; - } - if (m == origin) - return NULL; - } -} - -/* all accesses are serialized by namespace_sem */ -static struct user_namespace *user_ns; -static struct mount *last_dest, *first_source, *last_source, *dest_master; -static struct mountpoint *mp; -static struct hlist_head *list; - -static inline bool peers(struct mount *m1, struct mount *m2) -{ - return m1->mnt_group_id == m2->mnt_group_id && m1->mnt_group_id; -} - -static int propagate_one(struct mount *m) -{ - struct mount *child; - int type; - /* skip ones added by this propagate_mnt() */ - if (IS_MNT_NEW(m)) - return 0; - /* skip if mountpoint isn't covered by it */ - if (!is_subdir(mp->m_dentry, m->mnt.mnt_root)) - return 0; - if (peers(m, last_dest)) { - type = CL_MAKE_SHARED; - } else { - struct mount *n, *p; - bool done; - for (n = m; ; n = p) { - p = n->mnt_master; - if (p == dest_master || IS_MNT_MARKED(p)) - break; - } - do { - struct mount *parent = last_source->mnt_parent; - if (last_source == first_source) - break; - done = parent->mnt_master == p; - if (done && peers(n, parent)) - break; - last_source = last_source->mnt_master; - } while (!done); - - type = CL_SLAVE; - /* beginning of peer group among the slaves? */ - if (IS_MNT_SHARED(m)) - type |= CL_MAKE_SHARED; - } - - /* Notice when we are propagating across user namespaces */ - if (m->mnt_ns->user_ns != user_ns) - type |= CL_UNPRIVILEGED; - child = copy_tree(last_source, last_source->mnt.mnt_root, type); - if (IS_ERR(child)) - return PTR_ERR(child); - child->mnt.mnt_flags &= ~MNT_LOCKED; - mnt_set_mountpoint(m, mp, child); - last_dest = m; - last_source = child; - if (m->mnt_master != dest_master) { - read_seqlock_excl(&mount_lock); - SET_MNT_MARK(m->mnt_master); - read_sequnlock_excl(&mount_lock); - } - hlist_add_head(&child->mnt_hash, list); - return count_mounts(m->mnt_ns, child); -} - -/* - * mount 'source_mnt' under the destination 'dest_mnt' at - * dentry 'dest_dentry'. And propagate that mount to - * all the peer and slave mounts of 'dest_mnt'. - * Link all the new mounts into a propagation tree headed at - * source_mnt. Also link all the new mounts using ->mnt_list - * headed at source_mnt's ->mnt_list - * - * @dest_mnt: destination mount. - * @dest_dentry: destination dentry. - * @source_mnt: source mount. - * @tree_list : list of heads of trees to be attached. - */ -int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp, - struct mount *source_mnt, struct hlist_head *tree_list) -{ - struct mount *m, *n; - int ret = 0; - - /* - * we don't want to bother passing tons of arguments to - * propagate_one(); everything is serialized by namespace_sem, - * so globals will do just fine. - */ - user_ns = current->nsproxy->mnt_ns->user_ns; - last_dest = dest_mnt; - first_source = source_mnt; - last_source = source_mnt; - mp = dest_mp; - list = tree_list; - dest_master = dest_mnt->mnt_master; - - /* all peers of dest_mnt, except dest_mnt itself */ - for (n = next_peer(dest_mnt); n != dest_mnt; n = next_peer(n)) { - ret = propagate_one(n); - if (ret) - goto out; - } - - /* all slave groups */ - for (m = next_group(dest_mnt, dest_mnt); m; - m = next_group(m, dest_mnt)) { - /* everything in that slave group */ - n = m; - do { - ret = propagate_one(n); - if (ret) - goto out; - n = next_peer(n); - } while (n != m); - } -out: - read_seqlock_excl(&mount_lock); - hlist_for_each_entry(n, tree_list, mnt_hash) { - m = n->mnt_parent; - if (m->mnt_master != dest_mnt->mnt_master) - CLEAR_MNT_MARK(m->mnt_master); - } - read_sequnlock_excl(&mount_lock); - return ret; -} - -/* - * return true if the refcount is greater than count - */ -static inline int do_refcount_check(struct mount *mnt, int count) -{ - return mnt_get_count(mnt) > count; -} - -/* - * check if the mount 'mnt' can be unmounted successfully. - * @mnt: the mount to be checked for unmount - * NOTE: unmounting 'mnt' would naturally propagate to all - * other mounts its parent propagates to. - * Check if any of these mounts that **do not have submounts** - * have more references than 'refcnt'. If so return busy. - * - * vfsmount lock must be held for write - */ -int propagate_mount_busy(struct mount *mnt, int refcnt) -{ - struct mount *m, *child; - struct mount *parent = mnt->mnt_parent; - int ret = 0; - - if (mnt == parent) - return do_refcount_check(mnt, refcnt); - - /* - * quickly check if the current mount can be unmounted. - * If not, we don't have to go checking for all other - * mounts - */ - if (!list_empty(&mnt->mnt_mounts) || do_refcount_check(mnt, refcnt)) - return 1; - - for (m = propagation_next(parent, parent); m; - m = propagation_next(m, parent)) { - child = __lookup_mnt_last(&m->mnt, mnt->mnt_mountpoint); - if (child && list_empty(&child->mnt_mounts) && - (ret = do_refcount_check(child, 1))) - break; - } - return ret; -} - -/* - * Clear MNT_LOCKED when it can be shown to be safe. - * - * mount_lock lock must be held for write - */ -void propagate_mount_unlock(struct mount *mnt) -{ - struct mount *parent = mnt->mnt_parent; - struct mount *m, *child; - - BUG_ON(parent == mnt); - - for (m = propagation_next(parent, parent); m; - m = propagation_next(m, parent)) { - child = __lookup_mnt_last(&m->mnt, mnt->mnt_mountpoint); - if (child) - child->mnt.mnt_flags &= ~MNT_LOCKED; - } -} - -/* - * Mark all mounts that the MNT_LOCKED logic will allow to be unmounted. - */ -static void mark_umount_candidates(struct mount *mnt) -{ - struct mount *parent = mnt->mnt_parent; - struct mount *m; - - BUG_ON(parent == mnt); - - for (m = propagation_next(parent, parent); m; - m = propagation_next(m, parent)) { - struct mount *child = __lookup_mnt_last(&m->mnt, - mnt->mnt_mountpoint); - if (child && (!IS_MNT_LOCKED(child) || IS_MNT_MARKED(m))) { - SET_MNT_MARK(child); - } - } -} - -/* - * NOTE: unmounting 'mnt' naturally propagates to all other mounts its - * parent propagates to. - */ -static void __propagate_umount(struct mount *mnt) -{ - struct mount *parent = mnt->mnt_parent; - struct mount *m; - - BUG_ON(parent == mnt); - - for (m = propagation_next(parent, parent); m; - m = propagation_next(m, parent)) { - - struct mount *child = __lookup_mnt_last(&m->mnt, - mnt->mnt_mountpoint); - /* - * umount the child only if the child has no children - * and the child is marked safe to unmount. - */ - if (!child || !IS_MNT_MARKED(child)) - continue; - CLEAR_MNT_MARK(child); - if (list_empty(&child->mnt_mounts)) { - list_del_init(&child->mnt_child); - child->mnt.mnt_flags |= MNT_UMOUNT; - list_move_tail(&child->mnt_list, &mnt->mnt_list); - } - } -} - -/* - * collect all mounts that receive propagation from the mount in @list, - * and return these additional mounts in the same list. - * @list: the list of mounts to be unmounted. - * - * vfsmount lock must be held for write - */ -int propagate_umount(struct list_head *list) -{ - struct mount *mnt; - - list_for_each_entry_reverse(mnt, list, mnt_list) - mark_umount_candidates(mnt); - - list_for_each_entry(mnt, list, mnt_list) - __propagate_umount(mnt); - return 0; -} diff --git a/src/linux/fs/pnode.h b/src/linux/fs/pnode.h deleted file mode 100644 index 550f5a8..0000000 --- a/src/linux/fs/pnode.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * linux/fs/pnode.h - * - * (C) Copyright IBM Corporation 2005. - * Released under GPL v2. - * - */ -#ifndef _LINUX_PNODE_H -#define _LINUX_PNODE_H - -#include -#include "mount.h" - -#define IS_MNT_SHARED(m) ((m)->mnt.mnt_flags & MNT_SHARED) -#define IS_MNT_SLAVE(m) ((m)->mnt_master) -#define IS_MNT_NEW(m) (!(m)->mnt_ns) -#define CLEAR_MNT_SHARED(m) ((m)->mnt.mnt_flags &= ~MNT_SHARED) -#define IS_MNT_UNBINDABLE(m) ((m)->mnt.mnt_flags & MNT_UNBINDABLE) -#define IS_MNT_MARKED(m) ((m)->mnt.mnt_flags & MNT_MARKED) -#define SET_MNT_MARK(m) ((m)->mnt.mnt_flags |= MNT_MARKED) -#define CLEAR_MNT_MARK(m) ((m)->mnt.mnt_flags &= ~MNT_MARKED) -#define IS_MNT_LOCKED(m) ((m)->mnt.mnt_flags & MNT_LOCKED) - -#define CL_EXPIRE 0x01 -#define CL_SLAVE 0x02 -#define CL_COPY_UNBINDABLE 0x04 -#define CL_MAKE_SHARED 0x08 -#define CL_PRIVATE 0x10 -#define CL_SHARED_TO_SLAVE 0x20 -#define CL_UNPRIVILEGED 0x40 -#define CL_COPY_MNT_NS_FILE 0x80 - -#define CL_COPY_ALL (CL_COPY_UNBINDABLE | CL_COPY_MNT_NS_FILE) - -static inline void set_mnt_shared(struct mount *mnt) -{ - mnt->mnt.mnt_flags &= ~MNT_SHARED_MASK; - mnt->mnt.mnt_flags |= MNT_SHARED; -} - -void change_mnt_propagation(struct mount *, int); -int propagate_mnt(struct mount *, struct mountpoint *, struct mount *, - struct hlist_head *); -int propagate_umount(struct list_head *); -int propagate_mount_busy(struct mount *, int); -void propagate_mount_unlock(struct mount *); -void mnt_release_group_id(struct mount *); -int get_dominating_id(struct mount *mnt, const struct path *root); -unsigned int mnt_get_count(struct mount *mnt); -void mnt_set_mountpoint(struct mount *, struct mountpoint *, - struct mount *); -struct mount *copy_tree(struct mount *, struct dentry *, int); -bool is_path_reachable(struct mount *, struct dentry *, - const struct path *root); -int count_mounts(struct mnt_namespace *ns, struct mount *mnt); -#endif /* _LINUX_PNODE_H */ diff --git a/src/linux/fs/posix_acl.c b/src/linux/fs/posix_acl.c deleted file mode 100644 index 5955220..0000000 --- a/src/linux/fs/posix_acl.c +++ /dev/null @@ -1,954 +0,0 @@ -/* - * Copyright (C) 2002,2003 by Andreas Gruenbacher - * - * Fixes from William Schumacher incorporated on 15 March 2001. - * (Reported by Charles Bertsch, ). - */ - -/* - * This file contains generic functions for manipulating - * POSIX 1003.1e draft standard 17 ACLs. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct posix_acl **acl_by_type(struct inode *inode, int type) -{ - switch (type) { - case ACL_TYPE_ACCESS: - return &inode->i_acl; - case ACL_TYPE_DEFAULT: - return &inode->i_default_acl; - default: - BUG(); - } -} - -struct posix_acl *get_cached_acl(struct inode *inode, int type) -{ - struct posix_acl **p = acl_by_type(inode, type); - struct posix_acl *acl; - - for (;;) { - rcu_read_lock(); - acl = rcu_dereference(*p); - if (!acl || is_uncached_acl(acl) || - atomic_inc_not_zero(&acl->a_refcount)) - break; - rcu_read_unlock(); - cpu_relax(); - } - rcu_read_unlock(); - return acl; -} -EXPORT_SYMBOL(get_cached_acl); - -struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type) -{ - return rcu_dereference(*acl_by_type(inode, type)); -} -EXPORT_SYMBOL(get_cached_acl_rcu); - -void set_cached_acl(struct inode *inode, int type, struct posix_acl *acl) -{ - struct posix_acl **p = acl_by_type(inode, type); - struct posix_acl *old; - - old = xchg(p, posix_acl_dup(acl)); - if (!is_uncached_acl(old)) - posix_acl_release(old); -} -EXPORT_SYMBOL(set_cached_acl); - -static void __forget_cached_acl(struct posix_acl **p) -{ - struct posix_acl *old; - - old = xchg(p, ACL_NOT_CACHED); - if (!is_uncached_acl(old)) - posix_acl_release(old); -} - -void forget_cached_acl(struct inode *inode, int type) -{ - __forget_cached_acl(acl_by_type(inode, type)); -} -EXPORT_SYMBOL(forget_cached_acl); - -void forget_all_cached_acls(struct inode *inode) -{ - __forget_cached_acl(&inode->i_acl); - __forget_cached_acl(&inode->i_default_acl); -} -EXPORT_SYMBOL(forget_all_cached_acls); - -struct posix_acl *get_acl(struct inode *inode, int type) -{ - void *sentinel; - struct posix_acl **p; - struct posix_acl *acl; - - /* - * The sentinel is used to detect when another operation like - * set_cached_acl() or forget_cached_acl() races with get_acl(). - * It is guaranteed that is_uncached_acl(sentinel) is true. - */ - - acl = get_cached_acl(inode, type); - if (!is_uncached_acl(acl)) - return acl; - - if (!IS_POSIXACL(inode)) - return NULL; - - sentinel = uncached_acl_sentinel(current); - p = acl_by_type(inode, type); - - /* - * If the ACL isn't being read yet, set our sentinel. Otherwise, the - * current value of the ACL will not be ACL_NOT_CACHED and so our own - * sentinel will not be set; another task will update the cache. We - * could wait for that other task to complete its job, but it's easier - * to just call ->get_acl to fetch the ACL ourself. (This is going to - * be an unlikely race.) - */ - if (cmpxchg(p, ACL_NOT_CACHED, sentinel) != ACL_NOT_CACHED) - /* fall through */ ; - - /* - * Normally, the ACL returned by ->get_acl will be cached. - * A filesystem can prevent that by calling - * forget_cached_acl(inode, type) in ->get_acl. - * - * If the filesystem doesn't have a get_acl() function at all, we'll - * just create the negative cache entry. - */ - if (!inode->i_op->get_acl) { - set_cached_acl(inode, type, NULL); - return NULL; - } - acl = inode->i_op->get_acl(inode, type); - - if (IS_ERR(acl)) { - /* - * Remove our sentinel so that we don't block future attempts - * to cache the ACL. - */ - cmpxchg(p, sentinel, ACL_NOT_CACHED); - return acl; - } - - /* - * Cache the result, but only if our sentinel is still in place. - */ - posix_acl_dup(acl); - if (unlikely(cmpxchg(p, sentinel, acl) != sentinel)) - posix_acl_release(acl); - return acl; -} -EXPORT_SYMBOL(get_acl); - -/* - * Init a fresh posix_acl - */ -void -posix_acl_init(struct posix_acl *acl, int count) -{ - atomic_set(&acl->a_refcount, 1); - acl->a_count = count; -} -EXPORT_SYMBOL(posix_acl_init); - -/* - * Allocate a new ACL with the specified number of entries. - */ -struct posix_acl * -posix_acl_alloc(int count, gfp_t flags) -{ - const size_t size = sizeof(struct posix_acl) + - count * sizeof(struct posix_acl_entry); - struct posix_acl *acl = kmalloc(size, flags); - if (acl) - posix_acl_init(acl, count); - return acl; -} -EXPORT_SYMBOL(posix_acl_alloc); - -/* - * Clone an ACL. - */ -static struct posix_acl * -posix_acl_clone(const struct posix_acl *acl, gfp_t flags) -{ - struct posix_acl *clone = NULL; - - if (acl) { - int size = sizeof(struct posix_acl) + acl->a_count * - sizeof(struct posix_acl_entry); - clone = kmemdup(acl, size, flags); - if (clone) - atomic_set(&clone->a_refcount, 1); - } - return clone; -} - -/* - * Check if an acl is valid. Returns 0 if it is, or -E... otherwise. - */ -int -posix_acl_valid(struct user_namespace *user_ns, const struct posix_acl *acl) -{ - const struct posix_acl_entry *pa, *pe; - int state = ACL_USER_OBJ; - int needs_mask = 0; - - FOREACH_ACL_ENTRY(pa, acl, pe) { - if (pa->e_perm & ~(ACL_READ|ACL_WRITE|ACL_EXECUTE)) - return -EINVAL; - switch (pa->e_tag) { - case ACL_USER_OBJ: - if (state == ACL_USER_OBJ) { - state = ACL_USER; - break; - } - return -EINVAL; - - case ACL_USER: - if (state != ACL_USER) - return -EINVAL; - if (!kuid_has_mapping(user_ns, pa->e_uid)) - return -EINVAL; - needs_mask = 1; - break; - - case ACL_GROUP_OBJ: - if (state == ACL_USER) { - state = ACL_GROUP; - break; - } - return -EINVAL; - - case ACL_GROUP: - if (state != ACL_GROUP) - return -EINVAL; - if (!kgid_has_mapping(user_ns, pa->e_gid)) - return -EINVAL; - needs_mask = 1; - break; - - case ACL_MASK: - if (state != ACL_GROUP) - return -EINVAL; - state = ACL_OTHER; - break; - - case ACL_OTHER: - if (state == ACL_OTHER || - (state == ACL_GROUP && !needs_mask)) { - state = 0; - break; - } - return -EINVAL; - - default: - return -EINVAL; - } - } - if (state == 0) - return 0; - return -EINVAL; -} -EXPORT_SYMBOL(posix_acl_valid); - -/* - * Returns 0 if the acl can be exactly represented in the traditional - * file mode permission bits, or else 1. Returns -E... on error. - */ -int -posix_acl_equiv_mode(const struct posix_acl *acl, umode_t *mode_p) -{ - const struct posix_acl_entry *pa, *pe; - umode_t mode = 0; - int not_equiv = 0; - - /* - * A null ACL can always be presented as mode bits. - */ - if (!acl) - return 0; - - FOREACH_ACL_ENTRY(pa, acl, pe) { - switch (pa->e_tag) { - case ACL_USER_OBJ: - mode |= (pa->e_perm & S_IRWXO) << 6; - break; - case ACL_GROUP_OBJ: - mode |= (pa->e_perm & S_IRWXO) << 3; - break; - case ACL_OTHER: - mode |= pa->e_perm & S_IRWXO; - break; - case ACL_MASK: - mode = (mode & ~S_IRWXG) | - ((pa->e_perm & S_IRWXO) << 3); - not_equiv = 1; - break; - case ACL_USER: - case ACL_GROUP: - not_equiv = 1; - break; - default: - return -EINVAL; - } - } - if (mode_p) - *mode_p = (*mode_p & ~S_IRWXUGO) | mode; - return not_equiv; -} -EXPORT_SYMBOL(posix_acl_equiv_mode); - -/* - * Create an ACL representing the file mode permission bits of an inode. - */ -struct posix_acl * -posix_acl_from_mode(umode_t mode, gfp_t flags) -{ - struct posix_acl *acl = posix_acl_alloc(3, flags); - if (!acl) - return ERR_PTR(-ENOMEM); - - acl->a_entries[0].e_tag = ACL_USER_OBJ; - acl->a_entries[0].e_perm = (mode & S_IRWXU) >> 6; - - acl->a_entries[1].e_tag = ACL_GROUP_OBJ; - acl->a_entries[1].e_perm = (mode & S_IRWXG) >> 3; - - acl->a_entries[2].e_tag = ACL_OTHER; - acl->a_entries[2].e_perm = (mode & S_IRWXO); - return acl; -} -EXPORT_SYMBOL(posix_acl_from_mode); - -/* - * Return 0 if current is granted want access to the inode - * by the acl. Returns -E... otherwise. - */ -int -posix_acl_permission(struct inode *inode, const struct posix_acl *acl, int want) -{ - const struct posix_acl_entry *pa, *pe, *mask_obj; - int found = 0; - - want &= MAY_READ | MAY_WRITE | MAY_EXEC | MAY_NOT_BLOCK; - - FOREACH_ACL_ENTRY(pa, acl, pe) { - switch(pa->e_tag) { - case ACL_USER_OBJ: - /* (May have been checked already) */ - if (uid_eq(inode->i_uid, current_fsuid())) - goto check_perm; - break; - case ACL_USER: - if (uid_eq(pa->e_uid, current_fsuid())) - goto mask; - break; - case ACL_GROUP_OBJ: - if (in_group_p(inode->i_gid)) { - found = 1; - if ((pa->e_perm & want) == want) - goto mask; - } - break; - case ACL_GROUP: - if (in_group_p(pa->e_gid)) { - found = 1; - if ((pa->e_perm & want) == want) - goto mask; - } - break; - case ACL_MASK: - break; - case ACL_OTHER: - if (found) - return -EACCES; - else - goto check_perm; - default: - return -EIO; - } - } - return -EIO; - -mask: - for (mask_obj = pa+1; mask_obj != pe; mask_obj++) { - if (mask_obj->e_tag == ACL_MASK) { - if ((pa->e_perm & mask_obj->e_perm & want) == want) - return 0; - return -EACCES; - } - } - -check_perm: - if ((pa->e_perm & want) == want) - return 0; - return -EACCES; -} - -/* - * Modify acl when creating a new inode. The caller must ensure the acl is - * only referenced once. - * - * mode_p initially must contain the mode parameter to the open() / creat() - * system calls. All permissions that are not granted by the acl are removed. - * The permissions in the acl are changed to reflect the mode_p parameter. - */ -static int posix_acl_create_masq(struct posix_acl *acl, umode_t *mode_p) -{ - struct posix_acl_entry *pa, *pe; - struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL; - umode_t mode = *mode_p; - int not_equiv = 0; - - /* assert(atomic_read(acl->a_refcount) == 1); */ - - FOREACH_ACL_ENTRY(pa, acl, pe) { - switch(pa->e_tag) { - case ACL_USER_OBJ: - pa->e_perm &= (mode >> 6) | ~S_IRWXO; - mode &= (pa->e_perm << 6) | ~S_IRWXU; - break; - - case ACL_USER: - case ACL_GROUP: - not_equiv = 1; - break; - - case ACL_GROUP_OBJ: - group_obj = pa; - break; - - case ACL_OTHER: - pa->e_perm &= mode | ~S_IRWXO; - mode &= pa->e_perm | ~S_IRWXO; - break; - - case ACL_MASK: - mask_obj = pa; - not_equiv = 1; - break; - - default: - return -EIO; - } - } - - if (mask_obj) { - mask_obj->e_perm &= (mode >> 3) | ~S_IRWXO; - mode &= (mask_obj->e_perm << 3) | ~S_IRWXG; - } else { - if (!group_obj) - return -EIO; - group_obj->e_perm &= (mode >> 3) | ~S_IRWXO; - mode &= (group_obj->e_perm << 3) | ~S_IRWXG; - } - - *mode_p = (*mode_p & ~S_IRWXUGO) | mode; - return not_equiv; -} - -/* - * Modify the ACL for the chmod syscall. - */ -static int __posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode) -{ - struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL; - struct posix_acl_entry *pa, *pe; - - /* assert(atomic_read(acl->a_refcount) == 1); */ - - FOREACH_ACL_ENTRY(pa, acl, pe) { - switch(pa->e_tag) { - case ACL_USER_OBJ: - pa->e_perm = (mode & S_IRWXU) >> 6; - break; - - case ACL_USER: - case ACL_GROUP: - break; - - case ACL_GROUP_OBJ: - group_obj = pa; - break; - - case ACL_MASK: - mask_obj = pa; - break; - - case ACL_OTHER: - pa->e_perm = (mode & S_IRWXO); - break; - - default: - return -EIO; - } - } - - if (mask_obj) { - mask_obj->e_perm = (mode & S_IRWXG) >> 3; - } else { - if (!group_obj) - return -EIO; - group_obj->e_perm = (mode & S_IRWXG) >> 3; - } - - return 0; -} - -int -__posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p) -{ - struct posix_acl *clone = posix_acl_clone(*acl, gfp); - int err = -ENOMEM; - if (clone) { - err = posix_acl_create_masq(clone, mode_p); - if (err < 0) { - posix_acl_release(clone); - clone = NULL; - } - } - posix_acl_release(*acl); - *acl = clone; - return err; -} -EXPORT_SYMBOL(__posix_acl_create); - -int -__posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode) -{ - struct posix_acl *clone = posix_acl_clone(*acl, gfp); - int err = -ENOMEM; - if (clone) { - err = __posix_acl_chmod_masq(clone, mode); - if (err) { - posix_acl_release(clone); - clone = NULL; - } - } - posix_acl_release(*acl); - *acl = clone; - return err; -} -EXPORT_SYMBOL(__posix_acl_chmod); - -int -posix_acl_chmod(struct inode *inode, umode_t mode) -{ - struct posix_acl *acl; - int ret = 0; - - if (!IS_POSIXACL(inode)) - return 0; - if (!inode->i_op->set_acl) - return -EOPNOTSUPP; - - acl = get_acl(inode, ACL_TYPE_ACCESS); - if (IS_ERR_OR_NULL(acl)) { - if (acl == ERR_PTR(-EOPNOTSUPP)) - return 0; - return PTR_ERR(acl); - } - - ret = __posix_acl_chmod(&acl, GFP_KERNEL, mode); - if (ret) - return ret; - ret = inode->i_op->set_acl(inode, acl, ACL_TYPE_ACCESS); - posix_acl_release(acl); - return ret; -} -EXPORT_SYMBOL(posix_acl_chmod); - -int -posix_acl_create(struct inode *dir, umode_t *mode, - struct posix_acl **default_acl, struct posix_acl **acl) -{ - struct posix_acl *p; - struct posix_acl *clone; - int ret; - - *acl = NULL; - *default_acl = NULL; - - if (S_ISLNK(*mode) || !IS_POSIXACL(dir)) - return 0; - - p = get_acl(dir, ACL_TYPE_DEFAULT); - if (!p || p == ERR_PTR(-EOPNOTSUPP)) { - *mode &= ~current_umask(); - return 0; - } - if (IS_ERR(p)) - return PTR_ERR(p); - - ret = -ENOMEM; - clone = posix_acl_clone(p, GFP_NOFS); - if (!clone) - goto err_release; - - ret = posix_acl_create_masq(clone, mode); - if (ret < 0) - goto err_release_clone; - - if (ret == 0) - posix_acl_release(clone); - else - *acl = clone; - - if (!S_ISDIR(*mode)) - posix_acl_release(p); - else - *default_acl = p; - - return 0; - -err_release_clone: - posix_acl_release(clone); -err_release: - posix_acl_release(p); - return ret; -} -EXPORT_SYMBOL_GPL(posix_acl_create); - -/** - * posix_acl_update_mode - update mode in set_acl - * - * Update the file mode when setting an ACL: compute the new file permission - * bits based on the ACL. In addition, if the ACL is equivalent to the new - * file mode, set *acl to NULL to indicate that no ACL should be set. - * - * As with chmod, clear the setgit bit if the caller is not in the owning group - * or capable of CAP_FSETID (see inode_change_ok). - * - * Called from set_acl inode operations. - */ -int posix_acl_update_mode(struct inode *inode, umode_t *mode_p, - struct posix_acl **acl) -{ - umode_t mode = inode->i_mode; - int error; - - error = posix_acl_equiv_mode(*acl, &mode); - if (error < 0) - return error; - if (error == 0) - *acl = NULL; - if (!in_group_p(inode->i_gid) && - !capable_wrt_inode_uidgid(inode, CAP_FSETID)) - mode &= ~S_ISGID; - *mode_p = mode; - return 0; -} -EXPORT_SYMBOL(posix_acl_update_mode); - -/* - * Fix up the uids and gids in posix acl extended attributes in place. - */ -static void posix_acl_fix_xattr_userns( - struct user_namespace *to, struct user_namespace *from, - void *value, size_t size) -{ - struct posix_acl_xattr_header *header = value; - struct posix_acl_xattr_entry *entry = (void *)(header + 1), *end; - int count; - kuid_t uid; - kgid_t gid; - - if (!value) - return; - if (size < sizeof(struct posix_acl_xattr_header)) - return; - if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) - return; - - count = posix_acl_xattr_count(size); - if (count < 0) - return; - if (count == 0) - return; - - for (end = entry + count; entry != end; entry++) { - switch(le16_to_cpu(entry->e_tag)) { - case ACL_USER: - uid = make_kuid(from, le32_to_cpu(entry->e_id)); - entry->e_id = cpu_to_le32(from_kuid(to, uid)); - break; - case ACL_GROUP: - gid = make_kgid(from, le32_to_cpu(entry->e_id)); - entry->e_id = cpu_to_le32(from_kgid(to, gid)); - break; - default: - break; - } - } -} - -void posix_acl_fix_xattr_from_user(void *value, size_t size) -{ - struct user_namespace *user_ns = current_user_ns(); - if (user_ns == &init_user_ns) - return; - posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size); -} - -void posix_acl_fix_xattr_to_user(void *value, size_t size) -{ - struct user_namespace *user_ns = current_user_ns(); - if (user_ns == &init_user_ns) - return; - posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size); -} - -/* - * Convert from extended attribute to in-memory representation. - */ -struct posix_acl * -posix_acl_from_xattr(struct user_namespace *user_ns, - const void *value, size_t size) -{ - const struct posix_acl_xattr_header *header = value; - const struct posix_acl_xattr_entry *entry = (const void *)(header + 1), *end; - int count; - struct posix_acl *acl; - struct posix_acl_entry *acl_e; - - if (!value) - return NULL; - if (size < sizeof(struct posix_acl_xattr_header)) - return ERR_PTR(-EINVAL); - if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION)) - return ERR_PTR(-EOPNOTSUPP); - - count = posix_acl_xattr_count(size); - if (count < 0) - return ERR_PTR(-EINVAL); - if (count == 0) - return NULL; - - acl = posix_acl_alloc(count, GFP_NOFS); - if (!acl) - return ERR_PTR(-ENOMEM); - acl_e = acl->a_entries; - - for (end = entry + count; entry != end; acl_e++, entry++) { - acl_e->e_tag = le16_to_cpu(entry->e_tag); - acl_e->e_perm = le16_to_cpu(entry->e_perm); - - switch(acl_e->e_tag) { - case ACL_USER_OBJ: - case ACL_GROUP_OBJ: - case ACL_MASK: - case ACL_OTHER: - break; - - case ACL_USER: - acl_e->e_uid = - make_kuid(user_ns, - le32_to_cpu(entry->e_id)); - if (!uid_valid(acl_e->e_uid)) - goto fail; - break; - case ACL_GROUP: - acl_e->e_gid = - make_kgid(user_ns, - le32_to_cpu(entry->e_id)); - if (!gid_valid(acl_e->e_gid)) - goto fail; - break; - - default: - goto fail; - } - } - return acl; - -fail: - posix_acl_release(acl); - return ERR_PTR(-EINVAL); -} -EXPORT_SYMBOL (posix_acl_from_xattr); - -/* - * Convert from in-memory to extended attribute representation. - */ -int -posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl, - void *buffer, size_t size) -{ - struct posix_acl_xattr_header *ext_acl = buffer; - struct posix_acl_xattr_entry *ext_entry; - int real_size, n; - - real_size = posix_acl_xattr_size(acl->a_count); - if (!buffer) - return real_size; - if (real_size > size) - return -ERANGE; - - ext_entry = (void *)(ext_acl + 1); - ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); - - for (n=0; n < acl->a_count; n++, ext_entry++) { - const struct posix_acl_entry *acl_e = &acl->a_entries[n]; - ext_entry->e_tag = cpu_to_le16(acl_e->e_tag); - ext_entry->e_perm = cpu_to_le16(acl_e->e_perm); - switch(acl_e->e_tag) { - case ACL_USER: - ext_entry->e_id = - cpu_to_le32(from_kuid(user_ns, acl_e->e_uid)); - break; - case ACL_GROUP: - ext_entry->e_id = - cpu_to_le32(from_kgid(user_ns, acl_e->e_gid)); - break; - default: - ext_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID); - break; - } - } - return real_size; -} -EXPORT_SYMBOL (posix_acl_to_xattr); - -static int -posix_acl_xattr_get(const struct xattr_handler *handler, - struct dentry *unused, struct inode *inode, - const char *name, void *value, size_t size) -{ - struct posix_acl *acl; - int error; - - if (!IS_POSIXACL(inode)) - return -EOPNOTSUPP; - if (S_ISLNK(inode->i_mode)) - return -EOPNOTSUPP; - - acl = get_acl(inode, handler->flags); - if (IS_ERR(acl)) - return PTR_ERR(acl); - if (acl == NULL) - return -ENODATA; - - error = posix_acl_to_xattr(&init_user_ns, acl, value, size); - posix_acl_release(acl); - - return error; -} - -int -set_posix_acl(struct inode *inode, int type, struct posix_acl *acl) -{ - if (!IS_POSIXACL(inode)) - return -EOPNOTSUPP; - if (!inode->i_op->set_acl) - return -EOPNOTSUPP; - - if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) - return acl ? -EACCES : 0; - if (!inode_owner_or_capable(inode)) - return -EPERM; - - if (acl) { - int ret = posix_acl_valid(inode->i_sb->s_user_ns, acl); - if (ret) - return ret; - } - return inode->i_op->set_acl(inode, acl, type); -} -EXPORT_SYMBOL(set_posix_acl); - -static int -posix_acl_xattr_set(const struct xattr_handler *handler, - struct dentry *unused, struct inode *inode, - const char *name, const void *value, - size_t size, int flags) -{ - struct posix_acl *acl = NULL; - int ret; - - if (value) { - acl = posix_acl_from_xattr(&init_user_ns, value, size); - if (IS_ERR(acl)) - return PTR_ERR(acl); - } - ret = set_posix_acl(inode, handler->flags, acl); - posix_acl_release(acl); - return ret; -} - -static bool -posix_acl_xattr_list(struct dentry *dentry) -{ - return IS_POSIXACL(d_backing_inode(dentry)); -} - -const struct xattr_handler posix_acl_access_xattr_handler = { - .name = XATTR_NAME_POSIX_ACL_ACCESS, - .flags = ACL_TYPE_ACCESS, - .list = posix_acl_xattr_list, - .get = posix_acl_xattr_get, - .set = posix_acl_xattr_set, -}; -EXPORT_SYMBOL_GPL(posix_acl_access_xattr_handler); - -const struct xattr_handler posix_acl_default_xattr_handler = { - .name = XATTR_NAME_POSIX_ACL_DEFAULT, - .flags = ACL_TYPE_DEFAULT, - .list = posix_acl_xattr_list, - .get = posix_acl_xattr_get, - .set = posix_acl_xattr_set, -}; -EXPORT_SYMBOL_GPL(posix_acl_default_xattr_handler); - -int simple_set_acl(struct inode *inode, struct posix_acl *acl, int type) -{ - int error; - - if (type == ACL_TYPE_ACCESS) { - error = posix_acl_equiv_mode(acl, &inode->i_mode); - if (error < 0) - return 0; - if (error == 0) - acl = NULL; - } - - inode->i_ctime = current_time(inode); - set_cached_acl(inode, type, acl); - return 0; -} - -int simple_acl_create(struct inode *dir, struct inode *inode) -{ - struct posix_acl *default_acl, *acl; - int error; - - error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl); - if (error) - return error; - - set_cached_acl(inode, ACL_TYPE_DEFAULT, default_acl); - set_cached_acl(inode, ACL_TYPE_ACCESS, acl); - - if (default_acl) - posix_acl_release(default_acl); - if (acl) - posix_acl_release(acl); - return 0; -} diff --git a/src/linux/fs/proc/Kconfig b/src/linux/fs/proc/Kconfig deleted file mode 100644 index 1ade120..0000000 --- a/src/linux/fs/proc/Kconfig +++ /dev/null @@ -1,83 +0,0 @@ -config PROC_FS - bool "/proc file system support" if EXPERT - default y - help - This is a virtual file system providing information about the status - of the system. "Virtual" means that it doesn't take up any space on - your hard disk: the files are created on the fly by the kernel when - you try to access them. Also, you cannot read the files with older - version of the program less: you need to use more or cat. - - It's totally cool; for example, "cat /proc/interrupts" gives - information about what the different IRQs are used for at the moment - (there is a small number of Interrupt ReQuest lines in your computer - that are used by the attached devices to gain the CPU's attention -- - often a source of trouble if two devices are mistakenly configured - to use the same IRQ). The program procinfo to display some - information about your system gathered from the /proc file system. - - Before you can use the /proc file system, it has to be mounted, - meaning it has to be given a location in the directory hierarchy. - That location should be /proc. A command such as "mount -t proc proc - /proc" or the equivalent line in /etc/fstab does the job. - - The /proc file system is explained in the file - and on the proc(5) manpage - ("man 5 proc"). - - This option will enlarge your kernel by about 67 KB. Several - programs depend on this, so everyone should say Y here. - -config PROC_KCORE - bool "/proc/kcore support" if !ARM - depends on PROC_FS && MMU - help - Provides a virtual ELF core file of the live kernel. This can - be read with gdb and other ELF tools. No modifications can be - made using this mechanism. - -config PROC_VMCORE - bool "/proc/vmcore support" - depends on PROC_FS && CRASH_DUMP - default y - help - Exports the dump image of crashed kernel in ELF format. - -config PROC_SYSCTL - bool "Sysctl support (/proc/sys)" if EXPERT - depends on PROC_FS - select SYSCTL - default y - ---help--- - The sysctl interface provides a means of dynamically changing - certain kernel parameters and variables on the fly without requiring - a recompile of the kernel or reboot of the system. The primary - interface is through /proc/sys. If you say Y here a tree of - modifiable sysctl entries will be generated beneath the - /proc/sys directory. They are explained in the files - in . Note that enabling this - option will enlarge the kernel by at least 8 KB. - - As it is generally a good thing, you should say Y here unless - building a kernel for install/rescue disks or your system is very - limited in memory. - -config PROC_PAGE_MONITOR - default y - depends on PROC_FS && MMU - bool "Enable /proc page monitoring" if EXPERT - help - Various /proc files exist to monitor process memory utilization: - /proc/pid/smaps, /proc/pid/clear_refs, /proc/pid/pagemap, - /proc/kpagecount, and /proc/kpageflags. Disabling these - interfaces will reduce the size of the kernel by approximately 4kb. - -config PROC_CHILDREN - bool "Include /proc//task//children file" - default n - help - Provides a fast way to retrieve first level children pids of a task. See - for more information. - - Say Y if you are running any user-space software which takes benefit from - this interface. For example, rkt is such a piece of software. diff --git a/src/linux/fs/proc/Makefile b/src/linux/fs/proc/Makefile deleted file mode 100644 index 12c6922..0000000 --- a/src/linux/fs/proc/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# -# Makefile for the Linux proc filesystem routines. -# - -obj-y += proc.o - -CFLAGS_task_mmu.o += $(call cc-option,-Wno-override-init,) -proc-y := nommu.o task_nommu.o -proc-$(CONFIG_MMU) := task_mmu.o - -proc-y += inode.o root.o base.o generic.o array.o \ - fd.o -proc-$(CONFIG_TTY) += proc_tty.o -proc-y += cmdline.o -proc-y += consoles.o -proc-y += cpuinfo.o -proc-y += devices.o -proc-y += interrupts.o -proc-y += loadavg.o -proc-y += meminfo.o -proc-y += stat.o -proc-y += uptime.o -proc-y += version.o -proc-y += softirqs.o -proc-y += namespaces.o -proc-y += self.o -proc-y += thread_self.o -proc-$(CONFIG_PROC_SYSCTL) += proc_sysctl.o -proc-$(CONFIG_NET) += proc_net.o -proc-$(CONFIG_PROC_KCORE) += kcore.o -proc-$(CONFIG_PROC_VMCORE) += vmcore.o -proc-$(CONFIG_PRINTK) += kmsg.o -proc-$(CONFIG_PROC_PAGE_MONITOR) += page.o diff --git a/src/linux/fs/proc/array.c b/src/linux/fs/proc/array.c deleted file mode 100644 index 81818ad..0000000 --- a/src/linux/fs/proc/array.c +++ /dev/null @@ -1,732 +0,0 @@ -/* - * linux/fs/proc/array.c - * - * Copyright (C) 1992 by Linus Torvalds - * based on ideas by Darren Senn - * - * Fixes: - * Michael. K. Johnson: stat,statm extensions. - * - * - * Pauline Middelink : Made cmdline,envline only break at '\0's, to - * make sure SET_PROCTITLE works. Also removed - * bad '!' which forced address recalculation for - * EVERY character on the current page. - * - * - * Danny ter Haar : added cpuinfo - * - * - * Alessandro Rubini : profile extension. - * - * - * Jeff Tranter : added BogoMips field to cpuinfo - * - * - * Bruno Haible : remove 4K limit for the maps file - * - * - * Yves Arrouye : remove removal of trailing spaces in get_array. - * - * - * Jerome Forissier : added per-CPU time information to /proc/stat - * and /proc//cpu extension - * - * - Incorporation and non-SMP safe operation - * of forissier patch in 2.1.78 by - * Hans Marcus - * - * aeb@cwi.nl : /proc/partitions - * - * - * Alan Cox : security fixes. - * - * - * Al Viro : safe handling of mm_struct - * - * Gerhard Wichert : added BIGMEM support - * Siemens AG - * - * Al Viro & Jeff Garzik : moved most of the thing into base.c and - * : proc_misc.c. The rest may eventually go into - * : base.c too. - */ - -#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 -#include -#include -#include -#include - -#include -#include -#include "internal.h" - -static inline void task_name(struct seq_file *m, struct task_struct *p) -{ - char *buf; - size_t size; - char tcomm[sizeof(p->comm)]; - int ret; - - get_task_comm(tcomm, p); - - seq_puts(m, "Name:\t"); - - size = seq_get_buf(m, &buf); - ret = string_escape_str(tcomm, buf, size, ESCAPE_SPACE | ESCAPE_SPECIAL, "\n\\"); - seq_commit(m, ret < size ? ret : -1); - - seq_putc(m, '\n'); -} - -/* - * The task state array is a strange "bitmap" of - * reasons to sleep. Thus "running" is zero, and - * you can test for combinations of others with - * simple bit tests. - */ -static const char * const task_state_array[] = { - "R (running)", /* 0 */ - "S (sleeping)", /* 1 */ - "D (disk sleep)", /* 2 */ - "T (stopped)", /* 4 */ - "t (tracing stop)", /* 8 */ - "X (dead)", /* 16 */ - "Z (zombie)", /* 32 */ -}; - -static inline const char *get_task_state(struct task_struct *tsk) -{ - unsigned int state = (tsk->state | tsk->exit_state) & TASK_REPORT; - - /* - * Parked tasks do not run; they sit in __kthread_parkme(). - * Without this check, we would report them as running, which is - * clearly wrong, so we report them as sleeping instead. - */ - if (tsk->state == TASK_PARKED) - state = TASK_INTERRUPTIBLE; - - BUILD_BUG_ON(1 + ilog2(TASK_REPORT) != ARRAY_SIZE(task_state_array)-1); - - return task_state_array[fls(state)]; -} - -static inline int get_task_umask(struct task_struct *tsk) -{ - struct fs_struct *fs; - int umask = -ENOENT; - - task_lock(tsk); - fs = tsk->fs; - if (fs) - umask = fs->umask; - task_unlock(tsk); - return umask; -} - -static inline void task_state(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *p) -{ - struct user_namespace *user_ns = seq_user_ns(m); - struct group_info *group_info; - int g, umask; - struct task_struct *tracer; - const struct cred *cred; - pid_t ppid, tpid = 0, tgid, ngid; - unsigned int max_fds = 0; - - rcu_read_lock(); - ppid = pid_alive(p) ? - task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0; - - tracer = ptrace_parent(p); - if (tracer) - tpid = task_pid_nr_ns(tracer, ns); - - tgid = task_tgid_nr_ns(p, ns); - ngid = task_numa_group_id(p); - cred = get_task_cred(p); - - umask = get_task_umask(p); - if (umask >= 0) - seq_printf(m, "Umask:\t%#04o\n", umask); - - task_lock(p); - if (p->files) - max_fds = files_fdtable(p->files)->max_fds; - task_unlock(p); - rcu_read_unlock(); - - seq_printf(m, "State:\t%s", get_task_state(p)); - - seq_put_decimal_ull(m, "\nTgid:\t", tgid); - seq_put_decimal_ull(m, "\nNgid:\t", ngid); - seq_put_decimal_ull(m, "\nPid:\t", pid_nr_ns(pid, ns)); - seq_put_decimal_ull(m, "\nPPid:\t", ppid); - seq_put_decimal_ull(m, "\nTracerPid:\t", tpid); - seq_put_decimal_ull(m, "\nUid:\t", from_kuid_munged(user_ns, cred->uid)); - seq_put_decimal_ull(m, "\t", from_kuid_munged(user_ns, cred->euid)); - seq_put_decimal_ull(m, "\t", from_kuid_munged(user_ns, cred->suid)); - seq_put_decimal_ull(m, "\t", from_kuid_munged(user_ns, cred->fsuid)); - seq_put_decimal_ull(m, "\nGid:\t", from_kgid_munged(user_ns, cred->gid)); - seq_put_decimal_ull(m, "\t", from_kgid_munged(user_ns, cred->egid)); - seq_put_decimal_ull(m, "\t", from_kgid_munged(user_ns, cred->sgid)); - seq_put_decimal_ull(m, "\t", from_kgid_munged(user_ns, cred->fsgid)); - seq_put_decimal_ull(m, "\nFDSize:\t", max_fds); - - seq_puts(m, "\nGroups:\t"); - group_info = cred->group_info; - for (g = 0; g < group_info->ngroups; g++) - seq_put_decimal_ull(m, g ? " " : "", - from_kgid_munged(user_ns, group_info->gid[g])); - put_cred(cred); - /* Trailing space shouldn't have been added in the first place. */ - seq_putc(m, ' '); - -#ifdef CONFIG_PID_NS - seq_puts(m, "\nNStgid:"); - for (g = ns->level; g <= pid->level; g++) - seq_put_decimal_ull(m, "\t", task_tgid_nr_ns(p, pid->numbers[g].ns)); - seq_puts(m, "\nNSpid:"); - for (g = ns->level; g <= pid->level; g++) - seq_put_decimal_ull(m, "\t", task_pid_nr_ns(p, pid->numbers[g].ns)); - seq_puts(m, "\nNSpgid:"); - for (g = ns->level; g <= pid->level; g++) - seq_put_decimal_ull(m, "\t", task_pgrp_nr_ns(p, pid->numbers[g].ns)); - seq_puts(m, "\nNSsid:"); - for (g = ns->level; g <= pid->level; g++) - seq_put_decimal_ull(m, "\t", task_session_nr_ns(p, pid->numbers[g].ns)); -#endif - seq_putc(m, '\n'); -} - -void render_sigset_t(struct seq_file *m, const char *header, - sigset_t *set) -{ - int i; - - seq_puts(m, header); - - i = _NSIG; - do { - int x = 0; - - i -= 4; - if (sigismember(set, i+1)) x |= 1; - if (sigismember(set, i+2)) x |= 2; - if (sigismember(set, i+3)) x |= 4; - if (sigismember(set, i+4)) x |= 8; - seq_printf(m, "%x", x); - } while (i >= 4); - - seq_putc(m, '\n'); -} - -static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign, - sigset_t *catch) -{ - struct k_sigaction *k; - int i; - - k = p->sighand->action; - for (i = 1; i <= _NSIG; ++i, ++k) { - if (k->sa.sa_handler == SIG_IGN) - sigaddset(ign, i); - else if (k->sa.sa_handler != SIG_DFL) - sigaddset(catch, i); - } -} - -static inline void task_sig(struct seq_file *m, struct task_struct *p) -{ - unsigned long flags; - sigset_t pending, shpending, blocked, ignored, caught; - int num_threads = 0; - unsigned long qsize = 0; - unsigned long qlim = 0; - - sigemptyset(&pending); - sigemptyset(&shpending); - sigemptyset(&blocked); - sigemptyset(&ignored); - sigemptyset(&caught); - - if (lock_task_sighand(p, &flags)) { - pending = p->pending.signal; - shpending = p->signal->shared_pending.signal; - blocked = p->blocked; - collect_sigign_sigcatch(p, &ignored, &caught); - num_threads = get_nr_threads(p); - rcu_read_lock(); /* FIXME: is this correct? */ - qsize = atomic_read(&__task_cred(p)->user->sigpending); - rcu_read_unlock(); - qlim = task_rlimit(p, RLIMIT_SIGPENDING); - unlock_task_sighand(p, &flags); - } - - seq_put_decimal_ull(m, "Threads:\t", num_threads); - seq_put_decimal_ull(m, "\nSigQ:\t", qsize); - seq_put_decimal_ull(m, "/", qlim); - - /* render them all */ - render_sigset_t(m, "\nSigPnd:\t", &pending); - render_sigset_t(m, "ShdPnd:\t", &shpending); - render_sigset_t(m, "SigBlk:\t", &blocked); - render_sigset_t(m, "SigIgn:\t", &ignored); - render_sigset_t(m, "SigCgt:\t", &caught); -} - -static void render_cap_t(struct seq_file *m, const char *header, - kernel_cap_t *a) -{ - unsigned __capi; - - seq_puts(m, header); - CAP_FOR_EACH_U32(__capi) { - seq_printf(m, "%08x", - a->cap[CAP_LAST_U32 - __capi]); - } - seq_putc(m, '\n'); -} - -static inline void task_cap(struct seq_file *m, struct task_struct *p) -{ - const struct cred *cred; - kernel_cap_t cap_inheritable, cap_permitted, cap_effective, - cap_bset, cap_ambient; - - rcu_read_lock(); - cred = __task_cred(p); - cap_inheritable = cred->cap_inheritable; - cap_permitted = cred->cap_permitted; - cap_effective = cred->cap_effective; - cap_bset = cred->cap_bset; - cap_ambient = cred->cap_ambient; - rcu_read_unlock(); - - render_cap_t(m, "CapInh:\t", &cap_inheritable); - render_cap_t(m, "CapPrm:\t", &cap_permitted); - render_cap_t(m, "CapEff:\t", &cap_effective); - render_cap_t(m, "CapBnd:\t", &cap_bset); - render_cap_t(m, "CapAmb:\t", &cap_ambient); -} - -static inline void task_seccomp(struct seq_file *m, struct task_struct *p) -{ -#ifdef CONFIG_SECCOMP - seq_put_decimal_ull(m, "Seccomp:\t", p->seccomp.mode); - seq_putc(m, '\n'); -#endif -} - -static inline void task_context_switch_counts(struct seq_file *m, - struct task_struct *p) -{ - seq_put_decimal_ull(m, "voluntary_ctxt_switches:\t", p->nvcsw); - seq_put_decimal_ull(m, "\nnonvoluntary_ctxt_switches:\t", p->nivcsw); - seq_putc(m, '\n'); -} - -static void task_cpus_allowed(struct seq_file *m, struct task_struct *task) -{ - seq_printf(m, "Cpus_allowed:\t%*pb\n", - cpumask_pr_args(&task->cpus_allowed)); - seq_printf(m, "Cpus_allowed_list:\t%*pbl\n", - cpumask_pr_args(&task->cpus_allowed)); -} - -int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *task) -{ - struct mm_struct *mm = get_task_mm(task); - - task_name(m, task); - task_state(m, ns, pid, task); - - if (mm) { - task_mem(m, mm); - mmput(mm); - } - task_sig(m, task); - task_cap(m, task); - task_seccomp(m, task); - task_cpus_allowed(m, task); - cpuset_task_status_allowed(m, task); - task_context_switch_counts(m, task); - return 0; -} - -static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *task, int whole) -{ - unsigned long vsize, eip, esp, wchan = 0; - int priority, nice; - int tty_pgrp = -1, tty_nr = 0; - sigset_t sigign, sigcatch; - char state; - pid_t ppid = 0, pgid = -1, sid = -1; - int num_threads = 0; - int permitted; - struct mm_struct *mm; - unsigned long long start_time; - unsigned long cmin_flt = 0, cmaj_flt = 0; - unsigned long min_flt = 0, maj_flt = 0; - cputime_t cutime, cstime, utime, stime; - cputime_t cgtime, gtime; - unsigned long rsslim = 0; - char tcomm[sizeof(task->comm)]; - unsigned long flags; - - state = *get_task_state(task); - vsize = eip = esp = 0; - permitted = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS | PTRACE_MODE_NOAUDIT); - mm = get_task_mm(task); - if (mm) { - vsize = task_vsize(mm); - /* - * esp and eip are intentionally zeroed out. There is no - * non-racy way to read them without freezing the task. - * Programs that need reliable values can use ptrace(2). - */ - } - - get_task_comm(tcomm, task); - - sigemptyset(&sigign); - sigemptyset(&sigcatch); - cutime = cstime = utime = stime = 0; - cgtime = gtime = 0; - - if (lock_task_sighand(task, &flags)) { - struct signal_struct *sig = task->signal; - - if (sig->tty) { - struct pid *pgrp = tty_get_pgrp(sig->tty); - tty_pgrp = pid_nr_ns(pgrp, ns); - put_pid(pgrp); - tty_nr = new_encode_dev(tty_devnum(sig->tty)); - } - - num_threads = get_nr_threads(task); - collect_sigign_sigcatch(task, &sigign, &sigcatch); - - cmin_flt = sig->cmin_flt; - cmaj_flt = sig->cmaj_flt; - cutime = sig->cutime; - cstime = sig->cstime; - cgtime = sig->cgtime; - rsslim = ACCESS_ONCE(sig->rlim[RLIMIT_RSS].rlim_cur); - - /* add up live thread stats at the group level */ - if (whole) { - struct task_struct *t = task; - do { - min_flt += t->min_flt; - maj_flt += t->maj_flt; - gtime += task_gtime(t); - } while_each_thread(task, t); - - min_flt += sig->min_flt; - maj_flt += sig->maj_flt; - thread_group_cputime_adjusted(task, &utime, &stime); - gtime += sig->gtime; - } - - sid = task_session_nr_ns(task, ns); - ppid = task_tgid_nr_ns(task->real_parent, ns); - pgid = task_pgrp_nr_ns(task, ns); - - unlock_task_sighand(task, &flags); - } - - if (permitted && (!whole || num_threads < 2)) - wchan = get_wchan(task); - if (!whole) { - min_flt = task->min_flt; - maj_flt = task->maj_flt; - task_cputime_adjusted(task, &utime, &stime); - gtime = task_gtime(task); - } - - /* scale priority and nice values from timeslices to -20..20 */ - /* to make it look like a "normal" Unix priority/nice value */ - priority = task_prio(task); - nice = task_nice(task); - - /* convert nsec -> ticks */ - start_time = nsec_to_clock_t(task->real_start_time); - - seq_printf(m, "%d (%s) %c", pid_nr_ns(pid, ns), tcomm, state); - seq_put_decimal_ll(m, " ", ppid); - seq_put_decimal_ll(m, " ", pgid); - seq_put_decimal_ll(m, " ", sid); - seq_put_decimal_ll(m, " ", tty_nr); - seq_put_decimal_ll(m, " ", tty_pgrp); - seq_put_decimal_ull(m, " ", task->flags); - seq_put_decimal_ull(m, " ", min_flt); - seq_put_decimal_ull(m, " ", cmin_flt); - seq_put_decimal_ull(m, " ", maj_flt); - seq_put_decimal_ull(m, " ", cmaj_flt); - seq_put_decimal_ull(m, " ", cputime_to_clock_t(utime)); - seq_put_decimal_ull(m, " ", cputime_to_clock_t(stime)); - seq_put_decimal_ll(m, " ", cputime_to_clock_t(cutime)); - seq_put_decimal_ll(m, " ", cputime_to_clock_t(cstime)); - seq_put_decimal_ll(m, " ", priority); - seq_put_decimal_ll(m, " ", nice); - seq_put_decimal_ll(m, " ", num_threads); - seq_put_decimal_ull(m, " ", 0); - seq_put_decimal_ull(m, " ", start_time); - seq_put_decimal_ull(m, " ", vsize); - seq_put_decimal_ull(m, " ", mm ? get_mm_rss(mm) : 0); - seq_put_decimal_ull(m, " ", rsslim); - seq_put_decimal_ull(m, " ", mm ? (permitted ? mm->start_code : 1) : 0); - seq_put_decimal_ull(m, " ", mm ? (permitted ? mm->end_code : 1) : 0); - seq_put_decimal_ull(m, " ", (permitted && mm) ? mm->start_stack : 0); - seq_put_decimal_ull(m, " ", esp); - seq_put_decimal_ull(m, " ", eip); - /* The signal information here is obsolete. - * It must be decimal for Linux 2.0 compatibility. - * Use /proc/#/status for real-time signals. - */ - seq_put_decimal_ull(m, " ", task->pending.signal.sig[0] & 0x7fffffffUL); - seq_put_decimal_ull(m, " ", task->blocked.sig[0] & 0x7fffffffUL); - seq_put_decimal_ull(m, " ", sigign.sig[0] & 0x7fffffffUL); - seq_put_decimal_ull(m, " ", sigcatch.sig[0] & 0x7fffffffUL); - - /* - * We used to output the absolute kernel address, but that's an - * information leak - so instead we show a 0/1 flag here, to signal - * to user-space whether there's a wchan field in /proc/PID/wchan. - * - * This works with older implementations of procps as well. - */ - if (wchan) - seq_puts(m, " 1"); - else - seq_puts(m, " 0"); - - seq_put_decimal_ull(m, " ", 0); - seq_put_decimal_ull(m, " ", 0); - seq_put_decimal_ll(m, " ", task->exit_signal); - seq_put_decimal_ll(m, " ", task_cpu(task)); - seq_put_decimal_ull(m, " ", task->rt_priority); - seq_put_decimal_ull(m, " ", task->policy); - seq_put_decimal_ull(m, " ", delayacct_blkio_ticks(task)); - seq_put_decimal_ull(m, " ", cputime_to_clock_t(gtime)); - seq_put_decimal_ll(m, " ", cputime_to_clock_t(cgtime)); - - if (mm && permitted) { - seq_put_decimal_ull(m, " ", mm->start_data); - seq_put_decimal_ull(m, " ", mm->end_data); - seq_put_decimal_ull(m, " ", mm->start_brk); - seq_put_decimal_ull(m, " ", mm->arg_start); - seq_put_decimal_ull(m, " ", mm->arg_end); - seq_put_decimal_ull(m, " ", mm->env_start); - seq_put_decimal_ull(m, " ", mm->env_end); - } else - seq_puts(m, " 0 0 0 0 0 0 0"); - - if (permitted) - seq_put_decimal_ll(m, " ", task->exit_code); - else - seq_puts(m, " 0"); - - seq_putc(m, '\n'); - if (mm) - mmput(mm); - return 0; -} - -int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *task) -{ - return do_task_stat(m, ns, pid, task, 0); -} - -int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *task) -{ - return do_task_stat(m, ns, pid, task, 1); -} - -int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *task) -{ - unsigned long size = 0, resident = 0, shared = 0, text = 0, data = 0; - struct mm_struct *mm = get_task_mm(task); - - if (mm) { - size = task_statm(mm, &shared, &text, &data, &resident); - mmput(mm); - } - /* - * For quick read, open code by putting numbers directly - * expected format is - * seq_printf(m, "%lu %lu %lu %lu 0 %lu 0\n", - * size, resident, shared, text, data); - */ - seq_put_decimal_ull(m, "", size); - seq_put_decimal_ull(m, " ", resident); - seq_put_decimal_ull(m, " ", shared); - seq_put_decimal_ull(m, " ", text); - seq_put_decimal_ull(m, " ", 0); - seq_put_decimal_ull(m, " ", data); - seq_put_decimal_ull(m, " ", 0); - seq_putc(m, '\n'); - - return 0; -} - -#ifdef CONFIG_PROC_CHILDREN -static struct pid * -get_children_pid(struct inode *inode, struct pid *pid_prev, loff_t pos) -{ - struct task_struct *start, *task; - struct pid *pid = NULL; - - read_lock(&tasklist_lock); - - start = pid_task(proc_pid(inode), PIDTYPE_PID); - if (!start) - goto out; - - /* - * Lets try to continue searching first, this gives - * us significant speedup on children-rich processes. - */ - if (pid_prev) { - task = pid_task(pid_prev, PIDTYPE_PID); - if (task && task->real_parent == start && - !(list_empty(&task->sibling))) { - if (list_is_last(&task->sibling, &start->children)) - goto out; - task = list_first_entry(&task->sibling, - struct task_struct, sibling); - pid = get_pid(task_pid(task)); - goto out; - } - } - - /* - * Slow search case. - * - * We might miss some children here if children - * are exited while we were not holding the lock, - * but it was never promised to be accurate that - * much. - * - * "Just suppose that the parent sleeps, but N children - * exit after we printed their tids. Now the slow paths - * skips N extra children, we miss N tasks." (c) - * - * So one need to stop or freeze the leader and all - * its children to get a precise result. - */ - list_for_each_entry(task, &start->children, sibling) { - if (pos-- == 0) { - pid = get_pid(task_pid(task)); - break; - } - } - -out: - read_unlock(&tasklist_lock); - return pid; -} - -static int children_seq_show(struct seq_file *seq, void *v) -{ - struct inode *inode = seq->private; - pid_t pid; - - pid = pid_nr_ns(v, inode->i_sb->s_fs_info); - seq_printf(seq, "%d ", pid); - - return 0; -} - -static void *children_seq_start(struct seq_file *seq, loff_t *pos) -{ - return get_children_pid(seq->private, NULL, *pos); -} - -static void *children_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct pid *pid; - - pid = get_children_pid(seq->private, v, *pos + 1); - put_pid(v); - - ++*pos; - return pid; -} - -static void children_seq_stop(struct seq_file *seq, void *v) -{ - put_pid(v); -} - -static const struct seq_operations children_seq_ops = { - .start = children_seq_start, - .next = children_seq_next, - .stop = children_seq_stop, - .show = children_seq_show, -}; - -static int children_seq_open(struct inode *inode, struct file *file) -{ - struct seq_file *m; - int ret; - - ret = seq_open(file, &children_seq_ops); - if (ret) - return ret; - - m = file->private_data; - m->private = inode; - - return ret; -} - -int children_seq_release(struct inode *inode, struct file *file) -{ - seq_release(inode, file); - return 0; -} - -const struct file_operations proc_tid_children_operations = { - .open = children_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = children_seq_release, -}; -#endif /* CONFIG_PROC_CHILDREN */ diff --git a/src/linux/fs/proc/base.c b/src/linux/fs/proc/base.c deleted file mode 100644 index ca651ac..0000000 --- a/src/linux/fs/proc/base.c +++ /dev/null @@ -1,3554 +0,0 @@ -/* - * linux/fs/proc/base.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * proc base directory handling functions - * - * 1999, Al Viro. Rewritten. Now it covers the whole per-process part. - * Instead of using magical inumbers to determine the kind of object - * we allocate and fill in-core inodes upon lookup. They don't even - * go into icache. We cache the reference to task_struct upon lookup too. - * Eventually it should become a filesystem in its own. We don't use the - * rest of procfs anymore. - * - * - * Changelog: - * 17-Jan-2005 - * Allan Bezerra - * Bruna Moreira - * Edjard Mota - * Ilias Biris - * Mauricio Lin - * - * Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT - * - * A new process specific entry (smaps) included in /proc. It shows the - * size of rss for each memory area. The maps entry lacks information - * about physical memory size (rss) for each mapped file, i.e., - * rss information for executables and library files. - * This additional information is useful for any tools that need to know - * about physical memory consumption for a process specific library. - * - * Changelog: - * 21-Feb-2005 - * Embedded Linux Lab - 10LE Instituto Nokia de Tecnologia - INdT - * Pud inclusion in the page table walking. - * - * ChangeLog: - * 10-Mar-2005 - * 10LE Instituto Nokia de Tecnologia - INdT: - * A better way to walks through the page table as suggested by Hugh Dickins. - * - * Simo Piiroinen : - * Smaps information related to shared, private, clean and dirty pages. - * - * Paul Mundt : - * Overall revision about smaps. - */ - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_HARDWALL -#include -#endif -#include -#include "internal.h" -#include "fd.h" - -/* NOTE: - * Implementing inode permission operations in /proc is almost - * certainly an error. Permission checks need to happen during - * each system call not at open time. The reason is that most of - * what we wish to check for permissions in /proc varies at runtime. - * - * The classic example of a problem is opening file descriptors - * in /proc for a task before it execs a suid executable. - */ - -struct pid_entry { - const char *name; - int len; - umode_t mode; - const struct inode_operations *iop; - const struct file_operations *fop; - union proc_op op; -}; - -#define NOD(NAME, MODE, IOP, FOP, OP) { \ - .name = (NAME), \ - .len = sizeof(NAME) - 1, \ - .mode = MODE, \ - .iop = IOP, \ - .fop = FOP, \ - .op = OP, \ -} - -#define DIR(NAME, MODE, iops, fops) \ - NOD(NAME, (S_IFDIR|(MODE)), &iops, &fops, {} ) -#define LNK(NAME, get_link) \ - NOD(NAME, (S_IFLNK|S_IRWXUGO), \ - &proc_pid_link_inode_operations, NULL, \ - { .proc_get_link = get_link } ) -#define REG(NAME, MODE, fops) \ - NOD(NAME, (S_IFREG|(MODE)), NULL, &fops, {}) -#define ONE(NAME, MODE, show) \ - NOD(NAME, (S_IFREG|(MODE)), \ - NULL, &proc_single_file_operations, \ - { .proc_show = show } ) - -/* - * Count the number of hardlinks for the pid_entry table, excluding the . - * and .. links. - */ -static unsigned int pid_entry_count_dirs(const struct pid_entry *entries, - unsigned int n) -{ - unsigned int i; - unsigned int count; - - count = 0; - for (i = 0; i < n; ++i) { - if (S_ISDIR(entries[i].mode)) - ++count; - } - - return count; -} - -static int get_task_root(struct task_struct *task, struct path *root) -{ - int result = -ENOENT; - - task_lock(task); - if (task->fs) { - get_fs_root(task->fs, root); - result = 0; - } - task_unlock(task); - return result; -} - -static int proc_cwd_link(struct dentry *dentry, struct path *path) -{ - struct task_struct *task = get_proc_task(d_inode(dentry)); - int result = -ENOENT; - - if (task) { - task_lock(task); - if (task->fs) { - get_fs_pwd(task->fs, path); - result = 0; - } - task_unlock(task); - put_task_struct(task); - } - return result; -} - -static int proc_root_link(struct dentry *dentry, struct path *path) -{ - struct task_struct *task = get_proc_task(d_inode(dentry)); - int result = -ENOENT; - - if (task) { - result = get_task_root(task, path); - put_task_struct(task); - } - return result; -} - -static ssize_t proc_pid_cmdline_read(struct file *file, char __user *buf, - size_t _count, loff_t *pos) -{ - struct task_struct *tsk; - struct mm_struct *mm; - char *page; - unsigned long count = _count; - unsigned long arg_start, arg_end, env_start, env_end; - unsigned long len1, len2, len; - unsigned long p; - char c; - ssize_t rv; - - BUG_ON(*pos < 0); - - tsk = get_proc_task(file_inode(file)); - if (!tsk) - return -ESRCH; - mm = get_task_mm(tsk); - put_task_struct(tsk); - if (!mm) - return 0; - /* Check if process spawned far enough to have cmdline. */ - if (!mm->env_end) { - rv = 0; - goto out_mmput; - } - - page = (char *)__get_free_page(GFP_TEMPORARY); - if (!page) { - rv = -ENOMEM; - goto out_mmput; - } - - down_read(&mm->mmap_sem); - arg_start = mm->arg_start; - arg_end = mm->arg_end; - env_start = mm->env_start; - env_end = mm->env_end; - up_read(&mm->mmap_sem); - - BUG_ON(arg_start > arg_end); - BUG_ON(env_start > env_end); - - len1 = arg_end - arg_start; - len2 = env_end - env_start; - - /* Empty ARGV. */ - if (len1 == 0) { - rv = 0; - goto out_free_page; - } - /* - * Inherently racy -- command line shares address space - * with code and data. - */ - rv = access_remote_vm(mm, arg_end - 1, &c, 1, 0); - if (rv <= 0) - goto out_free_page; - - rv = 0; - - if (c == '\0') { - /* Command line (set of strings) occupies whole ARGV. */ - if (len1 <= *pos) - goto out_free_page; - - p = arg_start + *pos; - len = len1 - *pos; - while (count > 0 && len > 0) { - unsigned int _count; - int nr_read; - - _count = min3(count, len, PAGE_SIZE); - nr_read = access_remote_vm(mm, p, page, _count, 0); - if (nr_read < 0) - rv = nr_read; - if (nr_read <= 0) - goto out_free_page; - - if (copy_to_user(buf, page, nr_read)) { - rv = -EFAULT; - goto out_free_page; - } - - p += nr_read; - len -= nr_read; - buf += nr_read; - count -= nr_read; - rv += nr_read; - } - } else { - /* - * Command line (1 string) occupies ARGV and maybe - * extends into ENVP. - */ - if (len1 + len2 <= *pos) - goto skip_argv_envp; - if (len1 <= *pos) - goto skip_argv; - - p = arg_start + *pos; - len = len1 - *pos; - while (count > 0 && len > 0) { - unsigned int _count, l; - int nr_read; - bool final; - - _count = min3(count, len, PAGE_SIZE); - nr_read = access_remote_vm(mm, p, page, _count, 0); - if (nr_read < 0) - rv = nr_read; - if (nr_read <= 0) - goto out_free_page; - - /* - * Command line can be shorter than whole ARGV - * even if last "marker" byte says it is not. - */ - final = false; - l = strnlen(page, nr_read); - if (l < nr_read) { - nr_read = l; - final = true; - } - - if (copy_to_user(buf, page, nr_read)) { - rv = -EFAULT; - goto out_free_page; - } - - p += nr_read; - len -= nr_read; - buf += nr_read; - count -= nr_read; - rv += nr_read; - - if (final) - goto out_free_page; - } -skip_argv: - /* - * Command line (1 string) occupies ARGV and - * extends into ENVP. - */ - if (len1 <= *pos) { - p = env_start + *pos - len1; - len = len1 + len2 - *pos; - } else { - p = env_start; - len = len2; - } - while (count > 0 && len > 0) { - unsigned int _count, l; - int nr_read; - bool final; - - _count = min3(count, len, PAGE_SIZE); - nr_read = access_remote_vm(mm, p, page, _count, 0); - if (nr_read < 0) - rv = nr_read; - if (nr_read <= 0) - goto out_free_page; - - /* Find EOS. */ - final = false; - l = strnlen(page, nr_read); - if (l < nr_read) { - nr_read = l; - final = true; - } - - if (copy_to_user(buf, page, nr_read)) { - rv = -EFAULT; - goto out_free_page; - } - - p += nr_read; - len -= nr_read; - buf += nr_read; - count -= nr_read; - rv += nr_read; - - if (final) - goto out_free_page; - } -skip_argv_envp: - ; - } - -out_free_page: - free_page((unsigned long)page); -out_mmput: - mmput(mm); - if (rv > 0) - *pos += rv; - return rv; -} - -static const struct file_operations proc_pid_cmdline_ops = { - .read = proc_pid_cmdline_read, - .llseek = generic_file_llseek, -}; - -#ifdef CONFIG_KALLSYMS -/* - * Provides a wchan file via kallsyms in a proper one-value-per-file format. - * Returns the resolved symbol. If that fails, simply return the address. - */ -static int proc_pid_wchan(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *task) -{ - unsigned long wchan; - char symname[KSYM_NAME_LEN]; - - wchan = get_wchan(task); - - if (wchan && ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS) - && !lookup_symbol_name(wchan, symname)) - seq_printf(m, "%s", symname); - else - seq_putc(m, '0'); - - return 0; -} -#endif /* CONFIG_KALLSYMS */ - -static int lock_trace(struct task_struct *task) -{ - int err = mutex_lock_killable(&task->signal->cred_guard_mutex); - if (err) - return err; - if (!ptrace_may_access(task, PTRACE_MODE_ATTACH_FSCREDS)) { - mutex_unlock(&task->signal->cred_guard_mutex); - return -EPERM; - } - return 0; -} - -static void unlock_trace(struct task_struct *task) -{ - mutex_unlock(&task->signal->cred_guard_mutex); -} - -#ifdef CONFIG_STACKTRACE - -#define MAX_STACK_TRACE_DEPTH 64 - -static int proc_pid_stack(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *task) -{ - struct stack_trace trace; - unsigned long *entries; - int err; - int i; - - entries = kmalloc(MAX_STACK_TRACE_DEPTH * sizeof(*entries), GFP_KERNEL); - if (!entries) - return -ENOMEM; - - trace.nr_entries = 0; - trace.max_entries = MAX_STACK_TRACE_DEPTH; - trace.entries = entries; - trace.skip = 0; - - err = lock_trace(task); - if (!err) { - save_stack_trace_tsk(task, &trace); - - for (i = 0; i < trace.nr_entries; i++) { - seq_printf(m, "[<%pK>] %pB\n", - (void *)entries[i], (void *)entries[i]); - } - unlock_trace(task); - } - kfree(entries); - - return err; -} -#endif - -#ifdef CONFIG_SCHED_INFO -/* - * Provides /proc/PID/schedstat - */ -static int proc_pid_schedstat(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *task) -{ - if (unlikely(!sched_info_on())) - seq_printf(m, "0 0 0\n"); - else - seq_printf(m, "%llu %llu %lu\n", - (unsigned long long)task->se.sum_exec_runtime, - (unsigned long long)task->sched_info.run_delay, - task->sched_info.pcount); - - return 0; -} -#endif - -#ifdef CONFIG_LATENCYTOP -static int lstats_show_proc(struct seq_file *m, void *v) -{ - int i; - struct inode *inode = m->private; - struct task_struct *task = get_proc_task(inode); - - if (!task) - return -ESRCH; - seq_puts(m, "Latency Top version : v0.1\n"); - for (i = 0; i < 32; i++) { - struct latency_record *lr = &task->latency_record[i]; - if (lr->backtrace[0]) { - int q; - seq_printf(m, "%i %li %li", - lr->count, lr->time, lr->max); - for (q = 0; q < LT_BACKTRACEDEPTH; q++) { - unsigned long bt = lr->backtrace[q]; - if (!bt) - break; - if (bt == ULONG_MAX) - break; - seq_printf(m, " %ps", (void *)bt); - } - seq_putc(m, '\n'); - } - - } - put_task_struct(task); - return 0; -} - -static int lstats_open(struct inode *inode, struct file *file) -{ - return single_open(file, lstats_show_proc, inode); -} - -static ssize_t lstats_write(struct file *file, const char __user *buf, - size_t count, loff_t *offs) -{ - struct task_struct *task = get_proc_task(file_inode(file)); - - if (!task) - return -ESRCH; - clear_all_latency_tracing(task); - put_task_struct(task); - - return count; -} - -static const struct file_operations proc_lstats_operations = { - .open = lstats_open, - .read = seq_read, - .write = lstats_write, - .llseek = seq_lseek, - .release = single_release, -}; - -#endif - -static int proc_oom_score(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *task) -{ - unsigned long totalpages = totalram_pages + total_swap_pages; - unsigned long points = 0; - - points = oom_badness(task, NULL, NULL, totalpages) * - 1000 / totalpages; - seq_printf(m, "%lu\n", points); - - return 0; -} - -struct limit_names { - const char *name; - const char *unit; -}; - -static const struct limit_names lnames[RLIM_NLIMITS] = { - [RLIMIT_CPU] = {"Max cpu time", "seconds"}, - [RLIMIT_FSIZE] = {"Max file size", "bytes"}, - [RLIMIT_DATA] = {"Max data size", "bytes"}, - [RLIMIT_STACK] = {"Max stack size", "bytes"}, - [RLIMIT_CORE] = {"Max core file size", "bytes"}, - [RLIMIT_RSS] = {"Max resident set", "bytes"}, - [RLIMIT_NPROC] = {"Max processes", "processes"}, - [RLIMIT_NOFILE] = {"Max open files", "files"}, - [RLIMIT_MEMLOCK] = {"Max locked memory", "bytes"}, - [RLIMIT_AS] = {"Max address space", "bytes"}, - [RLIMIT_LOCKS] = {"Max file locks", "locks"}, - [RLIMIT_SIGPENDING] = {"Max pending signals", "signals"}, - [RLIMIT_MSGQUEUE] = {"Max msgqueue size", "bytes"}, - [RLIMIT_NICE] = {"Max nice priority", NULL}, - [RLIMIT_RTPRIO] = {"Max realtime priority", NULL}, - [RLIMIT_RTTIME] = {"Max realtime timeout", "us"}, -}; - -/* Display limits for a process */ -static int proc_pid_limits(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *task) -{ - unsigned int i; - unsigned long flags; - - struct rlimit rlim[RLIM_NLIMITS]; - - if (!lock_task_sighand(task, &flags)) - return 0; - memcpy(rlim, task->signal->rlim, sizeof(struct rlimit) * RLIM_NLIMITS); - unlock_task_sighand(task, &flags); - - /* - * print the file header - */ - seq_printf(m, "%-25s %-20s %-20s %-10s\n", - "Limit", "Soft Limit", "Hard Limit", "Units"); - - for (i = 0; i < RLIM_NLIMITS; i++) { - if (rlim[i].rlim_cur == RLIM_INFINITY) - seq_printf(m, "%-25s %-20s ", - lnames[i].name, "unlimited"); - else - seq_printf(m, "%-25s %-20lu ", - lnames[i].name, rlim[i].rlim_cur); - - if (rlim[i].rlim_max == RLIM_INFINITY) - seq_printf(m, "%-20s ", "unlimited"); - else - seq_printf(m, "%-20lu ", rlim[i].rlim_max); - - if (lnames[i].unit) - seq_printf(m, "%-10s\n", lnames[i].unit); - else - seq_putc(m, '\n'); - } - - return 0; -} - -#ifdef CONFIG_HAVE_ARCH_TRACEHOOK -static int proc_pid_syscall(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *task) -{ - long nr; - unsigned long args[6], sp, pc; - int res; - - res = lock_trace(task); - if (res) - return res; - - if (task_current_syscall(task, &nr, args, 6, &sp, &pc)) - seq_puts(m, "running\n"); - else if (nr < 0) - seq_printf(m, "%ld 0x%lx 0x%lx\n", nr, sp, pc); - else - seq_printf(m, - "%ld 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", - nr, - args[0], args[1], args[2], args[3], args[4], args[5], - sp, pc); - unlock_trace(task); - - return 0; -} -#endif /* CONFIG_HAVE_ARCH_TRACEHOOK */ - -/************************************************************************/ -/* Here the fs part begins */ -/************************************************************************/ - -/* permission checks */ -static int proc_fd_access_allowed(struct inode *inode) -{ - struct task_struct *task; - int allowed = 0; - /* Allow access to a task's file descriptors if it is us or we - * may use ptrace attach to the process and find out that - * information. - */ - task = get_proc_task(inode); - if (task) { - allowed = ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); - put_task_struct(task); - } - return allowed; -} - -int proc_setattr(struct dentry *dentry, struct iattr *attr) -{ - int error; - struct inode *inode = d_inode(dentry); - - if (attr->ia_valid & ATTR_MODE) - return -EPERM; - - error = setattr_prepare(dentry, attr); - if (error) - return error; - - setattr_copy(inode, attr); - mark_inode_dirty(inode); - return 0; -} - -/* - * May current process learn task's sched/cmdline info (for hide_pid_min=1) - * or euid/egid (for hide_pid_min=2)? - */ -static bool has_pid_permissions(struct pid_namespace *pid, - struct task_struct *task, - int hide_pid_min) -{ - if (pid->hide_pid < hide_pid_min) - return true; - if (in_group_p(pid->pid_gid)) - return true; - return ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS); -} - - -static int proc_pid_permission(struct inode *inode, int mask) -{ - struct pid_namespace *pid = inode->i_sb->s_fs_info; - struct task_struct *task; - bool has_perms; - - task = get_proc_task(inode); - if (!task) - return -ESRCH; - has_perms = has_pid_permissions(pid, task, 1); - put_task_struct(task); - - if (!has_perms) { - if (pid->hide_pid == 2) { - /* - * Let's make getdents(), stat(), and open() - * consistent with each other. If a process - * may not stat() a file, it shouldn't be seen - * in procfs at all. - */ - return -ENOENT; - } - - return -EPERM; - } - return generic_permission(inode, mask); -} - - - -static const struct inode_operations proc_def_inode_operations = { - .setattr = proc_setattr, -}; - -static int proc_single_show(struct seq_file *m, void *v) -{ - struct inode *inode = m->private; - struct pid_namespace *ns; - struct pid *pid; - struct task_struct *task; - int ret; - - ns = inode->i_sb->s_fs_info; - pid = proc_pid(inode); - task = get_pid_task(pid, PIDTYPE_PID); - if (!task) - return -ESRCH; - - ret = PROC_I(inode)->op.proc_show(m, ns, pid, task); - - put_task_struct(task); - return ret; -} - -static int proc_single_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, proc_single_show, inode); -} - -static const struct file_operations proc_single_file_operations = { - .open = proc_single_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - - -struct mm_struct *proc_mem_open(struct inode *inode, unsigned int mode) -{ - struct task_struct *task = get_proc_task(inode); - struct mm_struct *mm = ERR_PTR(-ESRCH); - - if (task) { - mm = mm_access(task, mode | PTRACE_MODE_FSCREDS); - put_task_struct(task); - - if (!IS_ERR_OR_NULL(mm)) { - /* ensure this mm_struct can't be freed */ - atomic_inc(&mm->mm_count); - /* but do not pin its memory */ - mmput(mm); - } - } - - return mm; -} - -static int __mem_open(struct inode *inode, struct file *file, unsigned int mode) -{ - struct mm_struct *mm = proc_mem_open(inode, mode); - - if (IS_ERR(mm)) - return PTR_ERR(mm); - - file->private_data = mm; - return 0; -} - -static int mem_open(struct inode *inode, struct file *file) -{ - int ret = __mem_open(inode, file, PTRACE_MODE_ATTACH); - - /* OK to pass negative loff_t, we can catch out-of-range */ - file->f_mode |= FMODE_UNSIGNED_OFFSET; - - return ret; -} - -static ssize_t mem_rw(struct file *file, char __user *buf, - size_t count, loff_t *ppos, int write) -{ - struct mm_struct *mm = file->private_data; - unsigned long addr = *ppos; - ssize_t copied; - char *page; - unsigned int flags; - - if (!mm) - return 0; - - page = (char *)__get_free_page(GFP_TEMPORARY); - if (!page) - return -ENOMEM; - - copied = 0; - if (!atomic_inc_not_zero(&mm->mm_users)) - goto free; - - /* Maybe we should limit FOLL_FORCE to actual ptrace users? */ - flags = FOLL_FORCE; - if (write) - flags |= FOLL_WRITE; - - while (count > 0) { - int this_len = min_t(int, count, PAGE_SIZE); - - if (write && copy_from_user(page, buf, this_len)) { - copied = -EFAULT; - break; - } - - this_len = access_remote_vm(mm, addr, page, this_len, flags); - if (!this_len) { - if (!copied) - copied = -EIO; - break; - } - - if (!write && copy_to_user(buf, page, this_len)) { - copied = -EFAULT; - break; - } - - buf += this_len; - addr += this_len; - copied += this_len; - count -= this_len; - } - *ppos = addr; - - mmput(mm); -free: - free_page((unsigned long) page); - return copied; -} - -static ssize_t mem_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - return mem_rw(file, buf, count, ppos, 0); -} - -static ssize_t mem_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - return mem_rw(file, (char __user*)buf, count, ppos, 1); -} - -loff_t mem_lseek(struct file *file, loff_t offset, int orig) -{ - switch (orig) { - case 0: - file->f_pos = offset; - break; - case 1: - file->f_pos += offset; - break; - default: - return -EINVAL; - } - force_successful_syscall_return(); - return file->f_pos; -} - -static int mem_release(struct inode *inode, struct file *file) -{ - struct mm_struct *mm = file->private_data; - if (mm) - mmdrop(mm); - return 0; -} - -static const struct file_operations proc_mem_operations = { - .llseek = mem_lseek, - .read = mem_read, - .write = mem_write, - .open = mem_open, - .release = mem_release, -}; - -static int environ_open(struct inode *inode, struct file *file) -{ - return __mem_open(inode, file, PTRACE_MODE_READ); -} - -static ssize_t environ_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - char *page; - unsigned long src = *ppos; - int ret = 0; - struct mm_struct *mm = file->private_data; - unsigned long env_start, env_end; - - /* Ensure the process spawned far enough to have an environment. */ - if (!mm || !mm->env_end) - return 0; - - page = (char *)__get_free_page(GFP_TEMPORARY); - if (!page) - return -ENOMEM; - - ret = 0; - if (!atomic_inc_not_zero(&mm->mm_users)) - goto free; - - down_read(&mm->mmap_sem); - env_start = mm->env_start; - env_end = mm->env_end; - up_read(&mm->mmap_sem); - - while (count > 0) { - size_t this_len, max_len; - int retval; - - if (src >= (env_end - env_start)) - break; - - this_len = env_end - (env_start + src); - - max_len = min_t(size_t, PAGE_SIZE, count); - this_len = min(max_len, this_len); - - retval = access_remote_vm(mm, (env_start + src), page, this_len, 0); - - if (retval <= 0) { - ret = retval; - break; - } - - if (copy_to_user(buf, page, retval)) { - ret = -EFAULT; - break; - } - - ret += retval; - src += retval; - buf += retval; - count -= retval; - } - *ppos = src; - mmput(mm); - -free: - free_page((unsigned long) page); - return ret; -} - -static const struct file_operations proc_environ_operations = { - .open = environ_open, - .read = environ_read, - .llseek = generic_file_llseek, - .release = mem_release, -}; - -static int auxv_open(struct inode *inode, struct file *file) -{ - return __mem_open(inode, file, PTRACE_MODE_READ_FSCREDS); -} - -static ssize_t auxv_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct mm_struct *mm = file->private_data; - unsigned int nwords = 0; - - if (!mm) - return 0; - do { - nwords += 2; - } while (mm->saved_auxv[nwords - 2] != 0); /* AT_NULL */ - return simple_read_from_buffer(buf, count, ppos, mm->saved_auxv, - nwords * sizeof(mm->saved_auxv[0])); -} - -static const struct file_operations proc_auxv_operations = { - .open = auxv_open, - .read = auxv_read, - .llseek = generic_file_llseek, - .release = mem_release, -}; - -static ssize_t oom_adj_read(struct file *file, char __user *buf, size_t count, - loff_t *ppos) -{ - struct task_struct *task = get_proc_task(file_inode(file)); - char buffer[PROC_NUMBUF]; - int oom_adj = OOM_ADJUST_MIN; - size_t len; - - if (!task) - return -ESRCH; - if (task->signal->oom_score_adj == OOM_SCORE_ADJ_MAX) - oom_adj = OOM_ADJUST_MAX; - else - oom_adj = (task->signal->oom_score_adj * -OOM_DISABLE) / - OOM_SCORE_ADJ_MAX; - put_task_struct(task); - len = snprintf(buffer, sizeof(buffer), "%d\n", oom_adj); - return simple_read_from_buffer(buf, count, ppos, buffer, len); -} - -static int __set_oom_adj(struct file *file, int oom_adj, bool legacy) -{ - static DEFINE_MUTEX(oom_adj_mutex); - struct mm_struct *mm = NULL; - struct task_struct *task; - int err = 0; - - task = get_proc_task(file_inode(file)); - if (!task) - return -ESRCH; - - mutex_lock(&oom_adj_mutex); - if (legacy) { - if (oom_adj < task->signal->oom_score_adj && - !capable(CAP_SYS_RESOURCE)) { - err = -EACCES; - goto err_unlock; - } - /* - * /proc/pid/oom_adj is provided for legacy purposes, ask users to use - * /proc/pid/oom_score_adj instead. - */ - pr_warn_once("%s (%d): /proc/%d/oom_adj is deprecated, please use /proc/%d/oom_score_adj instead.\n", - current->comm, task_pid_nr(current), task_pid_nr(task), - task_pid_nr(task)); - } else { - if ((short)oom_adj < task->signal->oom_score_adj_min && - !capable(CAP_SYS_RESOURCE)) { - err = -EACCES; - goto err_unlock; - } - } - - /* - * Make sure we will check other processes sharing the mm if this is - * not vfrok which wants its own oom_score_adj. - * pin the mm so it doesn't go away and get reused after task_unlock - */ - if (!task->vfork_done) { - struct task_struct *p = find_lock_task_mm(task); - - if (p) { - if (atomic_read(&p->mm->mm_users) > 1) { - mm = p->mm; - atomic_inc(&mm->mm_count); - } - task_unlock(p); - } - } - - task->signal->oom_score_adj = oom_adj; - if (!legacy && has_capability_noaudit(current, CAP_SYS_RESOURCE)) - task->signal->oom_score_adj_min = (short)oom_adj; - trace_oom_score_adj_update(task); - - if (mm) { - struct task_struct *p; - - rcu_read_lock(); - for_each_process(p) { - if (same_thread_group(task, p)) - continue; - - /* do not touch kernel threads or the global init */ - if (p->flags & PF_KTHREAD || is_global_init(p)) - continue; - - task_lock(p); - if (!p->vfork_done && process_shares_mm(p, mm)) { - pr_info("updating oom_score_adj for %d (%s) from %d to %d because it shares mm with %d (%s). Report if this is unexpected.\n", - task_pid_nr(p), p->comm, - p->signal->oom_score_adj, oom_adj, - task_pid_nr(task), task->comm); - p->signal->oom_score_adj = oom_adj; - if (!legacy && has_capability_noaudit(current, CAP_SYS_RESOURCE)) - p->signal->oom_score_adj_min = (short)oom_adj; - } - task_unlock(p); - } - rcu_read_unlock(); - mmdrop(mm); - } -err_unlock: - mutex_unlock(&oom_adj_mutex); - put_task_struct(task); - return err; -} - -/* - * /proc/pid/oom_adj exists solely for backwards compatibility with previous - * kernels. The effective policy is defined by oom_score_adj, which has a - * different scale: oom_adj grew exponentially and oom_score_adj grows linearly. - * Values written to oom_adj are simply mapped linearly to oom_score_adj. - * Processes that become oom disabled via oom_adj will still be oom disabled - * with this implementation. - * - * oom_adj cannot be removed since existing userspace binaries use it. - */ -static ssize_t oom_adj_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - char buffer[PROC_NUMBUF]; - int oom_adj; - int err; - - memset(buffer, 0, sizeof(buffer)); - if (count > sizeof(buffer) - 1) - count = sizeof(buffer) - 1; - if (copy_from_user(buffer, buf, count)) { - err = -EFAULT; - goto out; - } - - err = kstrtoint(strstrip(buffer), 0, &oom_adj); - if (err) - goto out; - if ((oom_adj < OOM_ADJUST_MIN || oom_adj > OOM_ADJUST_MAX) && - oom_adj != OOM_DISABLE) { - err = -EINVAL; - goto out; - } - - /* - * Scale /proc/pid/oom_score_adj appropriately ensuring that a maximum - * value is always attainable. - */ - if (oom_adj == OOM_ADJUST_MAX) - oom_adj = OOM_SCORE_ADJ_MAX; - else - oom_adj = (oom_adj * OOM_SCORE_ADJ_MAX) / -OOM_DISABLE; - - err = __set_oom_adj(file, oom_adj, true); -out: - return err < 0 ? err : count; -} - -static const struct file_operations proc_oom_adj_operations = { - .read = oom_adj_read, - .write = oom_adj_write, - .llseek = generic_file_llseek, -}; - -static ssize_t oom_score_adj_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct task_struct *task = get_proc_task(file_inode(file)); - char buffer[PROC_NUMBUF]; - short oom_score_adj = OOM_SCORE_ADJ_MIN; - size_t len; - - if (!task) - return -ESRCH; - oom_score_adj = task->signal->oom_score_adj; - put_task_struct(task); - len = snprintf(buffer, sizeof(buffer), "%hd\n", oom_score_adj); - return simple_read_from_buffer(buf, count, ppos, buffer, len); -} - -static ssize_t oom_score_adj_write(struct file *file, const char __user *buf, - size_t count, loff_t *ppos) -{ - char buffer[PROC_NUMBUF]; - int oom_score_adj; - int err; - - memset(buffer, 0, sizeof(buffer)); - if (count > sizeof(buffer) - 1) - count = sizeof(buffer) - 1; - if (copy_from_user(buffer, buf, count)) { - err = -EFAULT; - goto out; - } - - err = kstrtoint(strstrip(buffer), 0, &oom_score_adj); - if (err) - goto out; - if (oom_score_adj < OOM_SCORE_ADJ_MIN || - oom_score_adj > OOM_SCORE_ADJ_MAX) { - err = -EINVAL; - goto out; - } - - err = __set_oom_adj(file, oom_score_adj, false); -out: - return err < 0 ? err : count; -} - -static const struct file_operations proc_oom_score_adj_operations = { - .read = oom_score_adj_read, - .write = oom_score_adj_write, - .llseek = default_llseek, -}; - -#ifdef CONFIG_AUDITSYSCALL -#define TMPBUFLEN 21 -static ssize_t proc_loginuid_read(struct file * file, char __user * buf, - size_t count, loff_t *ppos) -{ - struct inode * inode = file_inode(file); - struct task_struct *task = get_proc_task(inode); - ssize_t length; - char tmpbuf[TMPBUFLEN]; - - if (!task) - return -ESRCH; - length = scnprintf(tmpbuf, TMPBUFLEN, "%u", - from_kuid(file->f_cred->user_ns, - audit_get_loginuid(task))); - put_task_struct(task); - return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); -} - -static ssize_t proc_loginuid_write(struct file * file, const char __user * buf, - size_t count, loff_t *ppos) -{ - struct inode * inode = file_inode(file); - uid_t loginuid; - kuid_t kloginuid; - int rv; - - rcu_read_lock(); - if (current != pid_task(proc_pid(inode), PIDTYPE_PID)) { - rcu_read_unlock(); - return -EPERM; - } - rcu_read_unlock(); - - if (*ppos != 0) { - /* No partial writes. */ - return -EINVAL; - } - - rv = kstrtou32_from_user(buf, count, 10, &loginuid); - if (rv < 0) - return rv; - - /* is userspace tring to explicitly UNSET the loginuid? */ - if (loginuid == AUDIT_UID_UNSET) { - kloginuid = INVALID_UID; - } else { - kloginuid = make_kuid(file->f_cred->user_ns, loginuid); - if (!uid_valid(kloginuid)) - return -EINVAL; - } - - rv = audit_set_loginuid(kloginuid); - if (rv < 0) - return rv; - return count; -} - -static const struct file_operations proc_loginuid_operations = { - .read = proc_loginuid_read, - .write = proc_loginuid_write, - .llseek = generic_file_llseek, -}; - -static ssize_t proc_sessionid_read(struct file * file, char __user * buf, - size_t count, loff_t *ppos) -{ - struct inode * inode = file_inode(file); - struct task_struct *task = get_proc_task(inode); - ssize_t length; - char tmpbuf[TMPBUFLEN]; - - if (!task) - return -ESRCH; - length = scnprintf(tmpbuf, TMPBUFLEN, "%u", - audit_get_sessionid(task)); - put_task_struct(task); - return simple_read_from_buffer(buf, count, ppos, tmpbuf, length); -} - -static const struct file_operations proc_sessionid_operations = { - .read = proc_sessionid_read, - .llseek = generic_file_llseek, -}; -#endif - -#ifdef CONFIG_FAULT_INJECTION -static ssize_t proc_fault_inject_read(struct file * file, char __user * buf, - size_t count, loff_t *ppos) -{ - struct task_struct *task = get_proc_task(file_inode(file)); - char buffer[PROC_NUMBUF]; - size_t len; - int make_it_fail; - - if (!task) - return -ESRCH; - make_it_fail = task->make_it_fail; - put_task_struct(task); - - len = snprintf(buffer, sizeof(buffer), "%i\n", make_it_fail); - - return simple_read_from_buffer(buf, count, ppos, buffer, len); -} - -static ssize_t proc_fault_inject_write(struct file * file, - const char __user * buf, size_t count, loff_t *ppos) -{ - struct task_struct *task; - char buffer[PROC_NUMBUF]; - int make_it_fail; - int rv; - - if (!capable(CAP_SYS_RESOURCE)) - return -EPERM; - memset(buffer, 0, sizeof(buffer)); - if (count > sizeof(buffer) - 1) - count = sizeof(buffer) - 1; - if (copy_from_user(buffer, buf, count)) - return -EFAULT; - rv = kstrtoint(strstrip(buffer), 0, &make_it_fail); - if (rv < 0) - return rv; - if (make_it_fail < 0 || make_it_fail > 1) - return -EINVAL; - - task = get_proc_task(file_inode(file)); - if (!task) - return -ESRCH; - task->make_it_fail = make_it_fail; - put_task_struct(task); - - return count; -} - -static const struct file_operations proc_fault_inject_operations = { - .read = proc_fault_inject_read, - .write = proc_fault_inject_write, - .llseek = generic_file_llseek, -}; -#endif - - -#ifdef CONFIG_SCHED_DEBUG -/* - * Print out various scheduling related per-task fields: - */ -static int sched_show(struct seq_file *m, void *v) -{ - struct inode *inode = m->private; - struct task_struct *p; - - p = get_proc_task(inode); - if (!p) - return -ESRCH; - proc_sched_show_task(p, m); - - put_task_struct(p); - - return 0; -} - -static ssize_t -sched_write(struct file *file, const char __user *buf, - size_t count, loff_t *offset) -{ - struct inode *inode = file_inode(file); - struct task_struct *p; - - p = get_proc_task(inode); - if (!p) - return -ESRCH; - proc_sched_set_task(p); - - put_task_struct(p); - - return count; -} - -static int sched_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, sched_show, inode); -} - -static const struct file_operations proc_pid_sched_operations = { - .open = sched_open, - .read = seq_read, - .write = sched_write, - .llseek = seq_lseek, - .release = single_release, -}; - -#endif - -#ifdef CONFIG_SCHED_AUTOGROUP -/* - * Print out autogroup related information: - */ -static int sched_autogroup_show(struct seq_file *m, void *v) -{ - struct inode *inode = m->private; - struct task_struct *p; - - p = get_proc_task(inode); - if (!p) - return -ESRCH; - proc_sched_autogroup_show_task(p, m); - - put_task_struct(p); - - return 0; -} - -static ssize_t -sched_autogroup_write(struct file *file, const char __user *buf, - size_t count, loff_t *offset) -{ - struct inode *inode = file_inode(file); - struct task_struct *p; - char buffer[PROC_NUMBUF]; - int nice; - int err; - - memset(buffer, 0, sizeof(buffer)); - if (count > sizeof(buffer) - 1) - count = sizeof(buffer) - 1; - if (copy_from_user(buffer, buf, count)) - return -EFAULT; - - err = kstrtoint(strstrip(buffer), 0, &nice); - if (err < 0) - return err; - - p = get_proc_task(inode); - if (!p) - return -ESRCH; - - err = proc_sched_autogroup_set_nice(p, nice); - if (err) - count = err; - - put_task_struct(p); - - return count; -} - -static int sched_autogroup_open(struct inode *inode, struct file *filp) -{ - int ret; - - ret = single_open(filp, sched_autogroup_show, NULL); - if (!ret) { - struct seq_file *m = filp->private_data; - - m->private = inode; - } - return ret; -} - -static const struct file_operations proc_pid_sched_autogroup_operations = { - .open = sched_autogroup_open, - .read = seq_read, - .write = sched_autogroup_write, - .llseek = seq_lseek, - .release = single_release, -}; - -#endif /* CONFIG_SCHED_AUTOGROUP */ - -static ssize_t comm_write(struct file *file, const char __user *buf, - size_t count, loff_t *offset) -{ - struct inode *inode = file_inode(file); - struct task_struct *p; - char buffer[TASK_COMM_LEN]; - const size_t maxlen = sizeof(buffer) - 1; - - memset(buffer, 0, sizeof(buffer)); - if (copy_from_user(buffer, buf, count > maxlen ? maxlen : count)) - return -EFAULT; - - p = get_proc_task(inode); - if (!p) - return -ESRCH; - - if (same_thread_group(current, p)) - set_task_comm(p, buffer); - else - count = -EINVAL; - - put_task_struct(p); - - return count; -} - -static int comm_show(struct seq_file *m, void *v) -{ - struct inode *inode = m->private; - struct task_struct *p; - - p = get_proc_task(inode); - if (!p) - return -ESRCH; - - task_lock(p); - seq_printf(m, "%s\n", p->comm); - task_unlock(p); - - put_task_struct(p); - - return 0; -} - -static int comm_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, comm_show, inode); -} - -static const struct file_operations proc_pid_set_comm_operations = { - .open = comm_open, - .read = seq_read, - .write = comm_write, - .llseek = seq_lseek, - .release = single_release, -}; - -static int proc_exe_link(struct dentry *dentry, struct path *exe_path) -{ - struct task_struct *task; - struct file *exe_file; - - task = get_proc_task(d_inode(dentry)); - if (!task) - return -ENOENT; - exe_file = get_task_exe_file(task); - put_task_struct(task); - if (exe_file) { - *exe_path = exe_file->f_path; - path_get(&exe_file->f_path); - fput(exe_file); - return 0; - } else - return -ENOENT; -} - -static const char *proc_pid_get_link(struct dentry *dentry, - struct inode *inode, - struct delayed_call *done) -{ - struct path path; - int error = -EACCES; - - if (!dentry) - return ERR_PTR(-ECHILD); - - /* Are we allowed to snoop on the tasks file descriptors? */ - if (!proc_fd_access_allowed(inode)) - goto out; - - error = PROC_I(inode)->op.proc_get_link(dentry, &path); - if (error) - goto out; - - nd_jump_link(&path); - return NULL; -out: - return ERR_PTR(error); -} - -static int do_proc_readlink(struct path *path, char __user *buffer, int buflen) -{ - char *tmp = (char*)__get_free_page(GFP_TEMPORARY); - char *pathname; - int len; - - if (!tmp) - return -ENOMEM; - - pathname = d_path(path, tmp, PAGE_SIZE); - len = PTR_ERR(pathname); - if (IS_ERR(pathname)) - goto out; - len = tmp + PAGE_SIZE - 1 - pathname; - - if (len > buflen) - len = buflen; - if (copy_to_user(buffer, pathname, len)) - len = -EFAULT; - out: - free_page((unsigned long)tmp); - return len; -} - -static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int buflen) -{ - int error = -EACCES; - struct inode *inode = d_inode(dentry); - struct path path; - - /* Are we allowed to snoop on the tasks file descriptors? */ - if (!proc_fd_access_allowed(inode)) - goto out; - - error = PROC_I(inode)->op.proc_get_link(dentry, &path); - if (error) - goto out; - - error = do_proc_readlink(&path, buffer, buflen); - path_put(&path); -out: - return error; -} - -const struct inode_operations proc_pid_link_inode_operations = { - .readlink = proc_pid_readlink, - .get_link = proc_pid_get_link, - .setattr = proc_setattr, -}; - - -/* building an inode */ - -struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task) -{ - struct inode * inode; - struct proc_inode *ei; - const struct cred *cred; - - /* We need a new inode */ - - inode = new_inode(sb); - if (!inode) - goto out; - - /* Common stuff */ - ei = PROC_I(inode); - inode->i_ino = get_next_ino(); - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); - inode->i_op = &proc_def_inode_operations; - - /* - * grab the reference to task. - */ - ei->pid = get_task_pid(task, PIDTYPE_PID); - if (!ei->pid) - goto out_unlock; - - if (task_dumpable(task)) { - rcu_read_lock(); - cred = __task_cred(task); - inode->i_uid = cred->euid; - inode->i_gid = cred->egid; - rcu_read_unlock(); - } - security_task_to_inode(task, inode); - -out: - return inode; - -out_unlock: - iput(inode); - return NULL; -} - -int pid_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) -{ - struct inode *inode = d_inode(dentry); - struct task_struct *task; - const struct cred *cred; - struct pid_namespace *pid = dentry->d_sb->s_fs_info; - - generic_fillattr(inode, stat); - - rcu_read_lock(); - stat->uid = GLOBAL_ROOT_UID; - stat->gid = GLOBAL_ROOT_GID; - task = pid_task(proc_pid(inode), PIDTYPE_PID); - if (task) { - if (!has_pid_permissions(pid, task, 2)) { - rcu_read_unlock(); - /* - * This doesn't prevent learning whether PID exists, - * it only makes getattr() consistent with readdir(). - */ - return -ENOENT; - } - if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) || - task_dumpable(task)) { - cred = __task_cred(task); - stat->uid = cred->euid; - stat->gid = cred->egid; - } - } - rcu_read_unlock(); - return 0; -} - -/* dentry stuff */ - -/* - * Exceptional case: normally we are not allowed to unhash a busy - * directory. In this case, however, we can do it - no aliasing problems - * due to the way we treat inodes. - * - * Rewrite the inode's ownerships here because the owning task may have - * performed a setuid(), etc. - * - * Before the /proc/pid/status file was created the only way to read - * the effective uid of a /process was to stat /proc/pid. Reading - * /proc/pid/status is slow enough that procps and other packages - * kept stating /proc/pid. To keep the rules in /proc simple I have - * made this apply to all per process world readable and executable - * directories. - */ -int pid_revalidate(struct dentry *dentry, unsigned int flags) -{ - struct inode *inode; - struct task_struct *task; - const struct cred *cred; - - if (flags & LOOKUP_RCU) - return -ECHILD; - - inode = d_inode(dentry); - task = get_proc_task(inode); - - if (task) { - if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) || - task_dumpable(task)) { - rcu_read_lock(); - cred = __task_cred(task); - inode->i_uid = cred->euid; - inode->i_gid = cred->egid; - rcu_read_unlock(); - } else { - inode->i_uid = GLOBAL_ROOT_UID; - inode->i_gid = GLOBAL_ROOT_GID; - } - inode->i_mode &= ~(S_ISUID | S_ISGID); - security_task_to_inode(task, inode); - put_task_struct(task); - return 1; - } - return 0; -} - -static inline bool proc_inode_is_dead(struct inode *inode) -{ - return !proc_pid(inode)->tasks[PIDTYPE_PID].first; -} - -int pid_delete_dentry(const struct dentry *dentry) -{ - /* Is the task we represent dead? - * If so, then don't put the dentry on the lru list, - * kill it immediately. - */ - return proc_inode_is_dead(d_inode(dentry)); -} - -const struct dentry_operations pid_dentry_operations = -{ - .d_revalidate = pid_revalidate, - .d_delete = pid_delete_dentry, -}; - -/* Lookups */ - -/* - * Fill a directory entry. - * - * If possible create the dcache entry and derive our inode number and - * file type from dcache entry. - * - * Since all of the proc inode numbers are dynamically generated, the inode - * numbers do not exist until the inode is cache. This means creating the - * the dcache entry in readdir is necessary to keep the inode numbers - * reported by readdir in sync with the inode numbers reported - * by stat. - */ -bool proc_fill_cache(struct file *file, struct dir_context *ctx, - const char *name, int len, - instantiate_t instantiate, struct task_struct *task, const void *ptr) -{ - struct dentry *child, *dir = file->f_path.dentry; - struct qstr qname = QSTR_INIT(name, len); - struct inode *inode; - unsigned type; - ino_t ino; - - child = d_hash_and_lookup(dir, &qname); - if (!child) { - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); - child = d_alloc_parallel(dir, &qname, &wq); - if (IS_ERR(child)) - goto end_instantiate; - if (d_in_lookup(child)) { - int err = instantiate(d_inode(dir), child, task, ptr); - d_lookup_done(child); - if (err < 0) { - dput(child); - goto end_instantiate; - } - } - } - inode = d_inode(child); - ino = inode->i_ino; - type = inode->i_mode >> 12; - dput(child); - return dir_emit(ctx, name, len, ino, type); - -end_instantiate: - return dir_emit(ctx, name, len, 1, DT_UNKNOWN); -} - -/* - * dname_to_vma_addr - maps a dentry name into two unsigned longs - * which represent vma start and end addresses. - */ -static int dname_to_vma_addr(struct dentry *dentry, - unsigned long *start, unsigned long *end) -{ - if (sscanf(dentry->d_name.name, "%lx-%lx", start, end) != 2) - return -EINVAL; - - return 0; -} - -static int map_files_d_revalidate(struct dentry *dentry, unsigned int flags) -{ - unsigned long vm_start, vm_end; - bool exact_vma_exists = false; - struct mm_struct *mm = NULL; - struct task_struct *task; - const struct cred *cred; - struct inode *inode; - int status = 0; - - if (flags & LOOKUP_RCU) - return -ECHILD; - - inode = d_inode(dentry); - task = get_proc_task(inode); - if (!task) - goto out_notask; - - mm = mm_access(task, PTRACE_MODE_READ_FSCREDS); - if (IS_ERR_OR_NULL(mm)) - goto out; - - if (!dname_to_vma_addr(dentry, &vm_start, &vm_end)) { - down_read(&mm->mmap_sem); - exact_vma_exists = !!find_exact_vma(mm, vm_start, vm_end); - up_read(&mm->mmap_sem); - } - - mmput(mm); - - if (exact_vma_exists) { - if (task_dumpable(task)) { - rcu_read_lock(); - cred = __task_cred(task); - inode->i_uid = cred->euid; - inode->i_gid = cred->egid; - rcu_read_unlock(); - } else { - inode->i_uid = GLOBAL_ROOT_UID; - inode->i_gid = GLOBAL_ROOT_GID; - } - security_task_to_inode(task, inode); - status = 1; - } - -out: - put_task_struct(task); - -out_notask: - return status; -} - -static const struct dentry_operations tid_map_files_dentry_operations = { - .d_revalidate = map_files_d_revalidate, - .d_delete = pid_delete_dentry, -}; - -static int map_files_get_link(struct dentry *dentry, struct path *path) -{ - unsigned long vm_start, vm_end; - struct vm_area_struct *vma; - struct task_struct *task; - struct mm_struct *mm; - int rc; - - rc = -ENOENT; - task = get_proc_task(d_inode(dentry)); - if (!task) - goto out; - - mm = get_task_mm(task); - put_task_struct(task); - if (!mm) - goto out; - - rc = dname_to_vma_addr(dentry, &vm_start, &vm_end); - if (rc) - goto out_mmput; - - rc = -ENOENT; - down_read(&mm->mmap_sem); - vma = find_exact_vma(mm, vm_start, vm_end); - if (vma && vma->vm_file) { - *path = vma->vm_file->f_path; - path_get(path); - rc = 0; - } - up_read(&mm->mmap_sem); - -out_mmput: - mmput(mm); -out: - return rc; -} - -struct map_files_info { - fmode_t mode; - unsigned long len; - unsigned char name[4*sizeof(long)+2]; /* max: %lx-%lx\0 */ -}; - -/* - * Only allow CAP_SYS_ADMIN to follow the links, due to concerns about how the - * symlinks may be used to bypass permissions on ancestor directories in the - * path to the file in question. - */ -static const char * -proc_map_files_get_link(struct dentry *dentry, - struct inode *inode, - struct delayed_call *done) -{ - if (!capable(CAP_SYS_ADMIN)) - return ERR_PTR(-EPERM); - - return proc_pid_get_link(dentry, inode, done); -} - -/* - * Identical to proc_pid_link_inode_operations except for get_link() - */ -static const struct inode_operations proc_map_files_link_inode_operations = { - .readlink = proc_pid_readlink, - .get_link = proc_map_files_get_link, - .setattr = proc_setattr, -}; - -static int -proc_map_files_instantiate(struct inode *dir, struct dentry *dentry, - struct task_struct *task, const void *ptr) -{ - fmode_t mode = (fmode_t)(unsigned long)ptr; - struct proc_inode *ei; - struct inode *inode; - - inode = proc_pid_make_inode(dir->i_sb, task); - if (!inode) - return -ENOENT; - - ei = PROC_I(inode); - ei->op.proc_get_link = map_files_get_link; - - inode->i_op = &proc_map_files_link_inode_operations; - inode->i_size = 64; - inode->i_mode = S_IFLNK; - - if (mode & FMODE_READ) - inode->i_mode |= S_IRUSR; - if (mode & FMODE_WRITE) - inode->i_mode |= S_IWUSR; - - d_set_d_op(dentry, &tid_map_files_dentry_operations); - d_add(dentry, inode); - - return 0; -} - -static struct dentry *proc_map_files_lookup(struct inode *dir, - struct dentry *dentry, unsigned int flags) -{ - unsigned long vm_start, vm_end; - struct vm_area_struct *vma; - struct task_struct *task; - int result; - struct mm_struct *mm; - - result = -ENOENT; - task = get_proc_task(dir); - if (!task) - goto out; - - result = -EACCES; - if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) - goto out_put_task; - - result = -ENOENT; - if (dname_to_vma_addr(dentry, &vm_start, &vm_end)) - goto out_put_task; - - mm = get_task_mm(task); - if (!mm) - goto out_put_task; - - down_read(&mm->mmap_sem); - vma = find_exact_vma(mm, vm_start, vm_end); - if (!vma) - goto out_no_vma; - - if (vma->vm_file) - result = proc_map_files_instantiate(dir, dentry, task, - (void *)(unsigned long)vma->vm_file->f_mode); - -out_no_vma: - up_read(&mm->mmap_sem); - mmput(mm); -out_put_task: - put_task_struct(task); -out: - return ERR_PTR(result); -} - -static const struct inode_operations proc_map_files_inode_operations = { - .lookup = proc_map_files_lookup, - .permission = proc_fd_permission, - .setattr = proc_setattr, -}; - -static int -proc_map_files_readdir(struct file *file, struct dir_context *ctx) -{ - struct vm_area_struct *vma; - struct task_struct *task; - struct mm_struct *mm; - unsigned long nr_files, pos, i; - struct flex_array *fa = NULL; - struct map_files_info info; - struct map_files_info *p; - int ret; - - ret = -ENOENT; - task = get_proc_task(file_inode(file)); - if (!task) - goto out; - - ret = -EACCES; - if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) - goto out_put_task; - - ret = 0; - if (!dir_emit_dots(file, ctx)) - goto out_put_task; - - mm = get_task_mm(task); - if (!mm) - goto out_put_task; - down_read(&mm->mmap_sem); - - nr_files = 0; - - /* - * We need two passes here: - * - * 1) Collect vmas of mapped files with mmap_sem taken - * 2) Release mmap_sem and instantiate entries - * - * otherwise we get lockdep complained, since filldir() - * routine might require mmap_sem taken in might_fault(). - */ - - for (vma = mm->mmap, pos = 2; vma; vma = vma->vm_next) { - if (vma->vm_file && ++pos > ctx->pos) - nr_files++; - } - - if (nr_files) { - fa = flex_array_alloc(sizeof(info), nr_files, - GFP_KERNEL); - if (!fa || flex_array_prealloc(fa, 0, nr_files, - GFP_KERNEL)) { - ret = -ENOMEM; - if (fa) - flex_array_free(fa); - up_read(&mm->mmap_sem); - mmput(mm); - goto out_put_task; - } - for (i = 0, vma = mm->mmap, pos = 2; vma; - vma = vma->vm_next) { - if (!vma->vm_file) - continue; - if (++pos <= ctx->pos) - continue; - - info.mode = vma->vm_file->f_mode; - info.len = snprintf(info.name, - sizeof(info.name), "%lx-%lx", - vma->vm_start, vma->vm_end); - if (flex_array_put(fa, i++, &info, GFP_KERNEL)) - BUG(); - } - } - up_read(&mm->mmap_sem); - - for (i = 0; i < nr_files; i++) { - p = flex_array_get(fa, i); - if (!proc_fill_cache(file, ctx, - p->name, p->len, - proc_map_files_instantiate, - task, - (void *)(unsigned long)p->mode)) - break; - ctx->pos++; - } - if (fa) - flex_array_free(fa); - mmput(mm); - -out_put_task: - put_task_struct(task); -out: - return ret; -} - -static const struct file_operations proc_map_files_operations = { - .read = generic_read_dir, - .iterate_shared = proc_map_files_readdir, - .llseek = generic_file_llseek, -}; - -#ifdef CONFIG_CHECKPOINT_RESTORE -struct timers_private { - struct pid *pid; - struct task_struct *task; - struct sighand_struct *sighand; - struct pid_namespace *ns; - unsigned long flags; -}; - -static void *timers_start(struct seq_file *m, loff_t *pos) -{ - struct timers_private *tp = m->private; - - tp->task = get_pid_task(tp->pid, PIDTYPE_PID); - if (!tp->task) - return ERR_PTR(-ESRCH); - - tp->sighand = lock_task_sighand(tp->task, &tp->flags); - if (!tp->sighand) - return ERR_PTR(-ESRCH); - - return seq_list_start(&tp->task->signal->posix_timers, *pos); -} - -static void *timers_next(struct seq_file *m, void *v, loff_t *pos) -{ - struct timers_private *tp = m->private; - return seq_list_next(v, &tp->task->signal->posix_timers, pos); -} - -static void timers_stop(struct seq_file *m, void *v) -{ - struct timers_private *tp = m->private; - - if (tp->sighand) { - unlock_task_sighand(tp->task, &tp->flags); - tp->sighand = NULL; - } - - if (tp->task) { - put_task_struct(tp->task); - tp->task = NULL; - } -} - -static int show_timer(struct seq_file *m, void *v) -{ - struct k_itimer *timer; - struct timers_private *tp = m->private; - int notify; - static const char * const nstr[] = { - [SIGEV_SIGNAL] = "signal", - [SIGEV_NONE] = "none", - [SIGEV_THREAD] = "thread", - }; - - timer = list_entry((struct list_head *)v, struct k_itimer, list); - notify = timer->it_sigev_notify; - - seq_printf(m, "ID: %d\n", timer->it_id); - seq_printf(m, "signal: %d/%p\n", - timer->sigq->info.si_signo, - timer->sigq->info.si_value.sival_ptr); - seq_printf(m, "notify: %s/%s.%d\n", - nstr[notify & ~SIGEV_THREAD_ID], - (notify & SIGEV_THREAD_ID) ? "tid" : "pid", - pid_nr_ns(timer->it_pid, tp->ns)); - seq_printf(m, "ClockID: %d\n", timer->it_clock); - - return 0; -} - -static const struct seq_operations proc_timers_seq_ops = { - .start = timers_start, - .next = timers_next, - .stop = timers_stop, - .show = show_timer, -}; - -static int proc_timers_open(struct inode *inode, struct file *file) -{ - struct timers_private *tp; - - tp = __seq_open_private(file, &proc_timers_seq_ops, - sizeof(struct timers_private)); - if (!tp) - return -ENOMEM; - - tp->pid = proc_pid(inode); - tp->ns = inode->i_sb->s_fs_info; - return 0; -} - -static const struct file_operations proc_timers_operations = { - .open = proc_timers_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_private, -}; -#endif - -static ssize_t timerslack_ns_write(struct file *file, const char __user *buf, - size_t count, loff_t *offset) -{ - struct inode *inode = file_inode(file); - struct task_struct *p; - u64 slack_ns; - int err; - - err = kstrtoull_from_user(buf, count, 10, &slack_ns); - if (err < 0) - return err; - - p = get_proc_task(inode); - if (!p) - return -ESRCH; - - if (p != current) { - if (!capable(CAP_SYS_NICE)) { - count = -EPERM; - goto out; - } - - err = security_task_setscheduler(p); - if (err) { - count = err; - goto out; - } - } - - task_lock(p); - if (slack_ns == 0) - p->timer_slack_ns = p->default_timer_slack_ns; - else - p->timer_slack_ns = slack_ns; - task_unlock(p); - -out: - put_task_struct(p); - - return count; -} - -static int timerslack_ns_show(struct seq_file *m, void *v) -{ - struct inode *inode = m->private; - struct task_struct *p; - int err = 0; - - p = get_proc_task(inode); - if (!p) - return -ESRCH; - - if (p != current) { - - if (!capable(CAP_SYS_NICE)) { - err = -EPERM; - goto out; - } - err = security_task_getscheduler(p); - if (err) - goto out; - } - - task_lock(p); - seq_printf(m, "%llu\n", p->timer_slack_ns); - task_unlock(p); - -out: - put_task_struct(p); - - return err; -} - -static int timerslack_ns_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, timerslack_ns_show, inode); -} - -static const struct file_operations proc_pid_set_timerslack_ns_operations = { - .open = timerslack_ns_open, - .read = seq_read, - .write = timerslack_ns_write, - .llseek = seq_lseek, - .release = single_release, -}; - -static int proc_pident_instantiate(struct inode *dir, - struct dentry *dentry, struct task_struct *task, const void *ptr) -{ - const struct pid_entry *p = ptr; - struct inode *inode; - struct proc_inode *ei; - - inode = proc_pid_make_inode(dir->i_sb, task); - if (!inode) - goto out; - - ei = PROC_I(inode); - inode->i_mode = p->mode; - if (S_ISDIR(inode->i_mode)) - set_nlink(inode, 2); /* Use getattr to fix if necessary */ - if (p->iop) - inode->i_op = p->iop; - if (p->fop) - inode->i_fop = p->fop; - ei->op = p->op; - d_set_d_op(dentry, &pid_dentry_operations); - d_add(dentry, inode); - /* Close the race of the process dying before we return the dentry */ - if (pid_revalidate(dentry, 0)) - return 0; -out: - return -ENOENT; -} - -static struct dentry *proc_pident_lookup(struct inode *dir, - struct dentry *dentry, - const struct pid_entry *ents, - unsigned int nents) -{ - int error; - struct task_struct *task = get_proc_task(dir); - const struct pid_entry *p, *last; - - error = -ENOENT; - - if (!task) - goto out_no_task; - - /* - * Yes, it does not scale. And it should not. Don't add - * new entries into /proc// without very good reasons. - */ - last = &ents[nents - 1]; - for (p = ents; p <= last; p++) { - if (p->len != dentry->d_name.len) - continue; - if (!memcmp(dentry->d_name.name, p->name, p->len)) - break; - } - if (p > last) - goto out; - - error = proc_pident_instantiate(dir, dentry, task, p); -out: - put_task_struct(task); -out_no_task: - return ERR_PTR(error); -} - -static int proc_pident_readdir(struct file *file, struct dir_context *ctx, - const struct pid_entry *ents, unsigned int nents) -{ - struct task_struct *task = get_proc_task(file_inode(file)); - const struct pid_entry *p; - - if (!task) - return -ENOENT; - - if (!dir_emit_dots(file, ctx)) - goto out; - - if (ctx->pos >= nents + 2) - goto out; - - for (p = ents + (ctx->pos - 2); p <= ents + nents - 1; p++) { - if (!proc_fill_cache(file, ctx, p->name, p->len, - proc_pident_instantiate, task, p)) - break; - ctx->pos++; - } -out: - put_task_struct(task); - return 0; -} - -#ifdef CONFIG_SECURITY -static ssize_t proc_pid_attr_read(struct file * file, char __user * buf, - size_t count, loff_t *ppos) -{ - struct inode * inode = file_inode(file); - char *p = NULL; - ssize_t length; - struct task_struct *task = get_proc_task(inode); - - if (!task) - return -ESRCH; - - length = security_getprocattr(task, - (char*)file->f_path.dentry->d_name.name, - &p); - put_task_struct(task); - if (length > 0) - length = simple_read_from_buffer(buf, count, ppos, p, length); - kfree(p); - return length; -} - -static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, - size_t count, loff_t *ppos) -{ - struct inode * inode = file_inode(file); - void *page; - ssize_t length; - struct task_struct *task = get_proc_task(inode); - - length = -ESRCH; - if (!task) - goto out_no_task; - if (count > PAGE_SIZE) - count = PAGE_SIZE; - - /* No partial writes. */ - length = -EINVAL; - if (*ppos != 0) - goto out; - - page = memdup_user(buf, count); - if (IS_ERR(page)) { - length = PTR_ERR(page); - goto out; - } - - /* Guard against adverse ptrace interaction */ - length = mutex_lock_interruptible(&task->signal->cred_guard_mutex); - if (length < 0) - goto out_free; - - length = security_setprocattr(task, - (char*)file->f_path.dentry->d_name.name, - page, count); - mutex_unlock(&task->signal->cred_guard_mutex); -out_free: - kfree(page); -out: - put_task_struct(task); -out_no_task: - return length; -} - -static const struct file_operations proc_pid_attr_operations = { - .read = proc_pid_attr_read, - .write = proc_pid_attr_write, - .llseek = generic_file_llseek, -}; - -static const struct pid_entry attr_dir_stuff[] = { - REG("current", S_IRUGO|S_IWUGO, proc_pid_attr_operations), - REG("prev", S_IRUGO, proc_pid_attr_operations), - REG("exec", S_IRUGO|S_IWUGO, proc_pid_attr_operations), - REG("fscreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations), - REG("keycreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations), - REG("sockcreate", S_IRUGO|S_IWUGO, proc_pid_attr_operations), -}; - -static int proc_attr_dir_readdir(struct file *file, struct dir_context *ctx) -{ - return proc_pident_readdir(file, ctx, - attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff)); -} - -static const struct file_operations proc_attr_dir_operations = { - .read = generic_read_dir, - .iterate_shared = proc_attr_dir_readdir, - .llseek = generic_file_llseek, -}; - -static struct dentry *proc_attr_dir_lookup(struct inode *dir, - struct dentry *dentry, unsigned int flags) -{ - return proc_pident_lookup(dir, dentry, - attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff)); -} - -static const struct inode_operations proc_attr_dir_inode_operations = { - .lookup = proc_attr_dir_lookup, - .getattr = pid_getattr, - .setattr = proc_setattr, -}; - -#endif - -#ifdef CONFIG_ELF_CORE -static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct task_struct *task = get_proc_task(file_inode(file)); - struct mm_struct *mm; - char buffer[PROC_NUMBUF]; - size_t len; - int ret; - - if (!task) - return -ESRCH; - - ret = 0; - mm = get_task_mm(task); - if (mm) { - len = snprintf(buffer, sizeof(buffer), "%08lx\n", - ((mm->flags & MMF_DUMP_FILTER_MASK) >> - MMF_DUMP_FILTER_SHIFT)); - mmput(mm); - ret = simple_read_from_buffer(buf, count, ppos, buffer, len); - } - - put_task_struct(task); - - return ret; -} - -static ssize_t proc_coredump_filter_write(struct file *file, - const char __user *buf, - size_t count, - loff_t *ppos) -{ - struct task_struct *task; - struct mm_struct *mm; - unsigned int val; - int ret; - int i; - unsigned long mask; - - ret = kstrtouint_from_user(buf, count, 0, &val); - if (ret < 0) - return ret; - - ret = -ESRCH; - task = get_proc_task(file_inode(file)); - if (!task) - goto out_no_task; - - mm = get_task_mm(task); - if (!mm) - goto out_no_mm; - ret = 0; - - for (i = 0, mask = 1; i < MMF_DUMP_FILTER_BITS; i++, mask <<= 1) { - if (val & mask) - set_bit(i + MMF_DUMP_FILTER_SHIFT, &mm->flags); - else - clear_bit(i + MMF_DUMP_FILTER_SHIFT, &mm->flags); - } - - mmput(mm); - out_no_mm: - put_task_struct(task); - out_no_task: - if (ret < 0) - return ret; - return count; -} - -static const struct file_operations proc_coredump_filter_operations = { - .read = proc_coredump_filter_read, - .write = proc_coredump_filter_write, - .llseek = generic_file_llseek, -}; -#endif - -#ifdef CONFIG_TASK_IO_ACCOUNTING -static int do_io_accounting(struct task_struct *task, struct seq_file *m, int whole) -{ - struct task_io_accounting acct = task->ioac; - unsigned long flags; - int result; - - result = mutex_lock_killable(&task->signal->cred_guard_mutex); - if (result) - return result; - - if (!ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) { - result = -EACCES; - goto out_unlock; - } - - if (whole && lock_task_sighand(task, &flags)) { - struct task_struct *t = task; - - task_io_accounting_add(&acct, &task->signal->ioac); - while_each_thread(task, t) - task_io_accounting_add(&acct, &t->ioac); - - unlock_task_sighand(task, &flags); - } - seq_printf(m, - "rchar: %llu\n" - "wchar: %llu\n" - "syscr: %llu\n" - "syscw: %llu\n" - "read_bytes: %llu\n" - "write_bytes: %llu\n" - "cancelled_write_bytes: %llu\n", - (unsigned long long)acct.rchar, - (unsigned long long)acct.wchar, - (unsigned long long)acct.syscr, - (unsigned long long)acct.syscw, - (unsigned long long)acct.read_bytes, - (unsigned long long)acct.write_bytes, - (unsigned long long)acct.cancelled_write_bytes); - result = 0; - -out_unlock: - mutex_unlock(&task->signal->cred_guard_mutex); - return result; -} - -static int proc_tid_io_accounting(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *task) -{ - return do_io_accounting(task, m, 0); -} - -static int proc_tgid_io_accounting(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *task) -{ - return do_io_accounting(task, m, 1); -} -#endif /* CONFIG_TASK_IO_ACCOUNTING */ - -#ifdef CONFIG_USER_NS -static int proc_id_map_open(struct inode *inode, struct file *file, - const struct seq_operations *seq_ops) -{ - struct user_namespace *ns = NULL; - struct task_struct *task; - struct seq_file *seq; - int ret = -EINVAL; - - task = get_proc_task(inode); - if (task) { - rcu_read_lock(); - ns = get_user_ns(task_cred_xxx(task, user_ns)); - rcu_read_unlock(); - put_task_struct(task); - } - if (!ns) - goto err; - - ret = seq_open(file, seq_ops); - if (ret) - goto err_put_ns; - - seq = file->private_data; - seq->private = ns; - - return 0; -err_put_ns: - put_user_ns(ns); -err: - return ret; -} - -static int proc_id_map_release(struct inode *inode, struct file *file) -{ - struct seq_file *seq = file->private_data; - struct user_namespace *ns = seq->private; - put_user_ns(ns); - return seq_release(inode, file); -} - -static int proc_uid_map_open(struct inode *inode, struct file *file) -{ - return proc_id_map_open(inode, file, &proc_uid_seq_operations); -} - -static int proc_gid_map_open(struct inode *inode, struct file *file) -{ - return proc_id_map_open(inode, file, &proc_gid_seq_operations); -} - -static int proc_projid_map_open(struct inode *inode, struct file *file) -{ - return proc_id_map_open(inode, file, &proc_projid_seq_operations); -} - -static const struct file_operations proc_uid_map_operations = { - .open = proc_uid_map_open, - .write = proc_uid_map_write, - .read = seq_read, - .llseek = seq_lseek, - .release = proc_id_map_release, -}; - -static const struct file_operations proc_gid_map_operations = { - .open = proc_gid_map_open, - .write = proc_gid_map_write, - .read = seq_read, - .llseek = seq_lseek, - .release = proc_id_map_release, -}; - -static const struct file_operations proc_projid_map_operations = { - .open = proc_projid_map_open, - .write = proc_projid_map_write, - .read = seq_read, - .llseek = seq_lseek, - .release = proc_id_map_release, -}; - -static int proc_setgroups_open(struct inode *inode, struct file *file) -{ - struct user_namespace *ns = NULL; - struct task_struct *task; - int ret; - - ret = -ESRCH; - task = get_proc_task(inode); - if (task) { - rcu_read_lock(); - ns = get_user_ns(task_cred_xxx(task, user_ns)); - rcu_read_unlock(); - put_task_struct(task); - } - if (!ns) - goto err; - - if (file->f_mode & FMODE_WRITE) { - ret = -EACCES; - if (!ns_capable(ns, CAP_SYS_ADMIN)) - goto err_put_ns; - } - - ret = single_open(file, &proc_setgroups_show, ns); - if (ret) - goto err_put_ns; - - return 0; -err_put_ns: - put_user_ns(ns); -err: - return ret; -} - -static int proc_setgroups_release(struct inode *inode, struct file *file) -{ - struct seq_file *seq = file->private_data; - struct user_namespace *ns = seq->private; - int ret = single_release(inode, file); - put_user_ns(ns); - return ret; -} - -static const struct file_operations proc_setgroups_operations = { - .open = proc_setgroups_open, - .write = proc_setgroups_write, - .read = seq_read, - .llseek = seq_lseek, - .release = proc_setgroups_release, -}; -#endif /* CONFIG_USER_NS */ - -static int proc_pid_personality(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *task) -{ - int err = lock_trace(task); - if (!err) { - seq_printf(m, "%08x\n", task->personality); - unlock_trace(task); - } - return err; -} - -/* - * Thread groups - */ -static const struct file_operations proc_task_operations; -static const struct inode_operations proc_task_inode_operations; - -static const struct pid_entry tgid_base_stuff[] = { - DIR("task", S_IRUGO|S_IXUGO, proc_task_inode_operations, proc_task_operations), - DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations), - DIR("map_files", S_IRUSR|S_IXUSR, proc_map_files_inode_operations, proc_map_files_operations), - DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations), - DIR("ns", S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations), -#ifdef CONFIG_NET - DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations), -#endif - REG("environ", S_IRUSR, proc_environ_operations), - REG("auxv", S_IRUSR, proc_auxv_operations), - ONE("status", S_IRUGO, proc_pid_status), - ONE("personality", S_IRUSR, proc_pid_personality), - ONE("limits", S_IRUGO, proc_pid_limits), -#ifdef CONFIG_SCHED_DEBUG - REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), -#endif -#ifdef CONFIG_SCHED_AUTOGROUP - REG("autogroup", S_IRUGO|S_IWUSR, proc_pid_sched_autogroup_operations), -#endif - REG("comm", S_IRUGO|S_IWUSR, proc_pid_set_comm_operations), -#ifdef CONFIG_HAVE_ARCH_TRACEHOOK - ONE("syscall", S_IRUSR, proc_pid_syscall), -#endif - REG("cmdline", S_IRUGO, proc_pid_cmdline_ops), - ONE("stat", S_IRUGO, proc_tgid_stat), - ONE("statm", S_IRUGO, proc_pid_statm), - REG("maps", S_IRUGO, proc_pid_maps_operations), -#ifdef CONFIG_NUMA - REG("numa_maps", S_IRUGO, proc_pid_numa_maps_operations), -#endif - REG("mem", S_IRUSR|S_IWUSR, proc_mem_operations), - LNK("cwd", proc_cwd_link), - LNK("root", proc_root_link), - LNK("exe", proc_exe_link), - REG("mounts", S_IRUGO, proc_mounts_operations), - REG("mountinfo", S_IRUGO, proc_mountinfo_operations), - REG("mountstats", S_IRUSR, proc_mountstats_operations), -#ifdef CONFIG_PROC_PAGE_MONITOR - REG("clear_refs", S_IWUSR, proc_clear_refs_operations), - REG("smaps", S_IRUGO, proc_pid_smaps_operations), - REG("pagemap", S_IRUSR, proc_pagemap_operations), -#endif -#ifdef CONFIG_SECURITY - DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations), -#endif -#ifdef CONFIG_KALLSYMS - ONE("wchan", S_IRUGO, proc_pid_wchan), -#endif -#ifdef CONFIG_STACKTRACE - ONE("stack", S_IRUSR, proc_pid_stack), -#endif -#ifdef CONFIG_SCHED_INFO - ONE("schedstat", S_IRUGO, proc_pid_schedstat), -#endif -#ifdef CONFIG_LATENCYTOP - REG("latency", S_IRUGO, proc_lstats_operations), -#endif -#ifdef CONFIG_PROC_PID_CPUSET - ONE("cpuset", S_IRUGO, proc_cpuset_show), -#endif -#ifdef CONFIG_CGROUPS - ONE("cgroup", S_IRUGO, proc_cgroup_show), -#endif - ONE("oom_score", S_IRUGO, proc_oom_score), - REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations), - REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), -#ifdef CONFIG_AUDITSYSCALL - REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), - REG("sessionid", S_IRUGO, proc_sessionid_operations), -#endif -#ifdef CONFIG_FAULT_INJECTION - REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), -#endif -#ifdef CONFIG_ELF_CORE - REG("coredump_filter", S_IRUGO|S_IWUSR, proc_coredump_filter_operations), -#endif -#ifdef CONFIG_TASK_IO_ACCOUNTING - ONE("io", S_IRUSR, proc_tgid_io_accounting), -#endif -#ifdef CONFIG_HARDWALL - ONE("hardwall", S_IRUGO, proc_pid_hardwall), -#endif -#ifdef CONFIG_USER_NS - REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations), - REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), - REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations), - REG("setgroups", S_IRUGO|S_IWUSR, proc_setgroups_operations), -#endif -#ifdef CONFIG_CHECKPOINT_RESTORE - REG("timers", S_IRUGO, proc_timers_operations), -#endif - REG("timerslack_ns", S_IRUGO|S_IWUGO, proc_pid_set_timerslack_ns_operations), -}; - -static int proc_tgid_base_readdir(struct file *file, struct dir_context *ctx) -{ - return proc_pident_readdir(file, ctx, - tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff)); -} - -static const struct file_operations proc_tgid_base_operations = { - .read = generic_read_dir, - .iterate_shared = proc_tgid_base_readdir, - .llseek = generic_file_llseek, -}; - -static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) -{ - return proc_pident_lookup(dir, dentry, - tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff)); -} - -static const struct inode_operations proc_tgid_base_inode_operations = { - .lookup = proc_tgid_base_lookup, - .getattr = pid_getattr, - .setattr = proc_setattr, - .permission = proc_pid_permission, -}; - -static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid) -{ - struct dentry *dentry, *leader, *dir; - char buf[PROC_NUMBUF]; - struct qstr name; - - name.name = buf; - name.len = snprintf(buf, sizeof(buf), "%d", pid); - /* no ->d_hash() rejects on procfs */ - dentry = d_hash_and_lookup(mnt->mnt_root, &name); - if (dentry) { - d_invalidate(dentry); - dput(dentry); - } - - if (pid == tgid) - return; - - name.name = buf; - name.len = snprintf(buf, sizeof(buf), "%d", tgid); - leader = d_hash_and_lookup(mnt->mnt_root, &name); - if (!leader) - goto out; - - name.name = "task"; - name.len = strlen(name.name); - dir = d_hash_and_lookup(leader, &name); - if (!dir) - goto out_put_leader; - - name.name = buf; - name.len = snprintf(buf, sizeof(buf), "%d", pid); - dentry = d_hash_and_lookup(dir, &name); - if (dentry) { - d_invalidate(dentry); - dput(dentry); - } - - dput(dir); -out_put_leader: - dput(leader); -out: - return; -} - -/** - * proc_flush_task - Remove dcache entries for @task from the /proc dcache. - * @task: task that should be flushed. - * - * When flushing dentries from proc, one needs to flush them from global - * proc (proc_mnt) and from all the namespaces' procs this task was seen - * in. This call is supposed to do all of this job. - * - * Looks in the dcache for - * /proc/@pid - * /proc/@tgid/task/@pid - * if either directory is present flushes it and all of it'ts children - * from the dcache. - * - * It is safe and reasonable to cache /proc entries for a task until - * that task exits. After that they just clog up the dcache with - * useless entries, possibly causing useful dcache entries to be - * flushed instead. This routine is proved to flush those useless - * dcache entries at process exit time. - * - * NOTE: This routine is just an optimization so it does not guarantee - * that no dcache entries will exist at process exit time it - * just makes it very unlikely that any will persist. - */ - -void proc_flush_task(struct task_struct *task) -{ - int i; - struct pid *pid, *tgid; - struct upid *upid; - - pid = task_pid(task); - tgid = task_tgid(task); - - for (i = 0; i <= pid->level; i++) { - upid = &pid->numbers[i]; - proc_flush_task_mnt(upid->ns->proc_mnt, upid->nr, - tgid->numbers[i].nr); - } -} - -static int proc_pid_instantiate(struct inode *dir, - struct dentry * dentry, - struct task_struct *task, const void *ptr) -{ - struct inode *inode; - - inode = proc_pid_make_inode(dir->i_sb, task); - if (!inode) - goto out; - - inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; - inode->i_op = &proc_tgid_base_inode_operations; - inode->i_fop = &proc_tgid_base_operations; - inode->i_flags|=S_IMMUTABLE; - - set_nlink(inode, 2 + pid_entry_count_dirs(tgid_base_stuff, - ARRAY_SIZE(tgid_base_stuff))); - - d_set_d_op(dentry, &pid_dentry_operations); - - d_add(dentry, inode); - /* Close the race of the process dying before we return the dentry */ - if (pid_revalidate(dentry, 0)) - return 0; -out: - return -ENOENT; -} - -struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags) -{ - int result = -ENOENT; - struct task_struct *task; - unsigned tgid; - struct pid_namespace *ns; - - tgid = name_to_int(&dentry->d_name); - if (tgid == ~0U) - goto out; - - ns = dentry->d_sb->s_fs_info; - rcu_read_lock(); - task = find_task_by_pid_ns(tgid, ns); - if (task) - get_task_struct(task); - rcu_read_unlock(); - if (!task) - goto out; - - result = proc_pid_instantiate(dir, dentry, task, NULL); - put_task_struct(task); -out: - return ERR_PTR(result); -} - -/* - * Find the first task with tgid >= tgid - * - */ -struct tgid_iter { - unsigned int tgid; - struct task_struct *task; -}; -static struct tgid_iter next_tgid(struct pid_namespace *ns, struct tgid_iter iter) -{ - struct pid *pid; - - if (iter.task) - put_task_struct(iter.task); - rcu_read_lock(); -retry: - iter.task = NULL; - pid = find_ge_pid(iter.tgid, ns); - if (pid) { - iter.tgid = pid_nr_ns(pid, ns); - iter.task = pid_task(pid, PIDTYPE_PID); - /* What we to know is if the pid we have find is the - * pid of a thread_group_leader. Testing for task - * being a thread_group_leader is the obvious thing - * todo but there is a window when it fails, due to - * the pid transfer logic in de_thread. - * - * So we perform the straight forward test of seeing - * if the pid we have found is the pid of a thread - * group leader, and don't worry if the task we have - * found doesn't happen to be a thread group leader. - * As we don't care in the case of readdir. - */ - if (!iter.task || !has_group_leader_pid(iter.task)) { - iter.tgid += 1; - goto retry; - } - get_task_struct(iter.task); - } - rcu_read_unlock(); - return iter; -} - -#define TGID_OFFSET (FIRST_PROCESS_ENTRY + 2) - -/* for the /proc/ directory itself, after non-process stuff has been done */ -int proc_pid_readdir(struct file *file, struct dir_context *ctx) -{ - struct tgid_iter iter; - struct pid_namespace *ns = file_inode(file)->i_sb->s_fs_info; - loff_t pos = ctx->pos; - - if (pos >= PID_MAX_LIMIT + TGID_OFFSET) - return 0; - - if (pos == TGID_OFFSET - 2) { - struct inode *inode = d_inode(ns->proc_self); - if (!dir_emit(ctx, "self", 4, inode->i_ino, DT_LNK)) - return 0; - ctx->pos = pos = pos + 1; - } - if (pos == TGID_OFFSET - 1) { - struct inode *inode = d_inode(ns->proc_thread_self); - if (!dir_emit(ctx, "thread-self", 11, inode->i_ino, DT_LNK)) - return 0; - ctx->pos = pos = pos + 1; - } - iter.tgid = pos - TGID_OFFSET; - iter.task = NULL; - for (iter = next_tgid(ns, iter); - iter.task; - iter.tgid += 1, iter = next_tgid(ns, iter)) { - char name[PROC_NUMBUF]; - int len; - if (!has_pid_permissions(ns, iter.task, 2)) - continue; - - len = snprintf(name, sizeof(name), "%d", iter.tgid); - ctx->pos = iter.tgid + TGID_OFFSET; - if (!proc_fill_cache(file, ctx, name, len, - proc_pid_instantiate, iter.task, NULL)) { - put_task_struct(iter.task); - return 0; - } - } - ctx->pos = PID_MAX_LIMIT + TGID_OFFSET; - return 0; -} - -/* - * proc_tid_comm_permission is a special permission function exclusively - * used for the node /proc//task//comm. - * It bypasses generic permission checks in the case where a task of the same - * task group attempts to access the node. - * The rationale behind this is that glibc and bionic access this node for - * cross thread naming (pthread_set/getname_np(!self)). However, if - * PR_SET_DUMPABLE gets set to 0 this node among others becomes uid=0 gid=0, - * which locks out the cross thread naming implementation. - * This function makes sure that the node is always accessible for members of - * same thread group. - */ -static int proc_tid_comm_permission(struct inode *inode, int mask) -{ - bool is_same_tgroup; - struct task_struct *task; - - task = get_proc_task(inode); - if (!task) - return -ESRCH; - is_same_tgroup = same_thread_group(current, task); - put_task_struct(task); - - if (likely(is_same_tgroup && !(mask & MAY_EXEC))) { - /* This file (/proc//task//comm) can always be - * read or written by the members of the corresponding - * thread group. - */ - return 0; - } - - return generic_permission(inode, mask); -} - -static const struct inode_operations proc_tid_comm_inode_operations = { - .permission = proc_tid_comm_permission, -}; - -/* - * Tasks - */ -static const struct pid_entry tid_base_stuff[] = { - DIR("fd", S_IRUSR|S_IXUSR, proc_fd_inode_operations, proc_fd_operations), - DIR("fdinfo", S_IRUSR|S_IXUSR, proc_fdinfo_inode_operations, proc_fdinfo_operations), - DIR("ns", S_IRUSR|S_IXUGO, proc_ns_dir_inode_operations, proc_ns_dir_operations), -#ifdef CONFIG_NET - DIR("net", S_IRUGO|S_IXUGO, proc_net_inode_operations, proc_net_operations), -#endif - REG("environ", S_IRUSR, proc_environ_operations), - REG("auxv", S_IRUSR, proc_auxv_operations), - ONE("status", S_IRUGO, proc_pid_status), - ONE("personality", S_IRUSR, proc_pid_personality), - ONE("limits", S_IRUGO, proc_pid_limits), -#ifdef CONFIG_SCHED_DEBUG - REG("sched", S_IRUGO|S_IWUSR, proc_pid_sched_operations), -#endif - NOD("comm", S_IFREG|S_IRUGO|S_IWUSR, - &proc_tid_comm_inode_operations, - &proc_pid_set_comm_operations, {}), -#ifdef CONFIG_HAVE_ARCH_TRACEHOOK - ONE("syscall", S_IRUSR, proc_pid_syscall), -#endif - REG("cmdline", S_IRUGO, proc_pid_cmdline_ops), - ONE("stat", S_IRUGO, proc_tid_stat), - ONE("statm", S_IRUGO, proc_pid_statm), - REG("maps", S_IRUGO, proc_tid_maps_operations), -#ifdef CONFIG_PROC_CHILDREN - REG("children", S_IRUGO, proc_tid_children_operations), -#endif -#ifdef CONFIG_NUMA - REG("numa_maps", S_IRUGO, proc_tid_numa_maps_operations), -#endif - REG("mem", S_IRUSR|S_IWUSR, proc_mem_operations), - LNK("cwd", proc_cwd_link), - LNK("root", proc_root_link), - LNK("exe", proc_exe_link), - REG("mounts", S_IRUGO, proc_mounts_operations), - REG("mountinfo", S_IRUGO, proc_mountinfo_operations), -#ifdef CONFIG_PROC_PAGE_MONITOR - REG("clear_refs", S_IWUSR, proc_clear_refs_operations), - REG("smaps", S_IRUGO, proc_tid_smaps_operations), - REG("pagemap", S_IRUSR, proc_pagemap_operations), -#endif -#ifdef CONFIG_SECURITY - DIR("attr", S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations), -#endif -#ifdef CONFIG_KALLSYMS - ONE("wchan", S_IRUGO, proc_pid_wchan), -#endif -#ifdef CONFIG_STACKTRACE - ONE("stack", S_IRUSR, proc_pid_stack), -#endif -#ifdef CONFIG_SCHED_INFO - ONE("schedstat", S_IRUGO, proc_pid_schedstat), -#endif -#ifdef CONFIG_LATENCYTOP - REG("latency", S_IRUGO, proc_lstats_operations), -#endif -#ifdef CONFIG_PROC_PID_CPUSET - ONE("cpuset", S_IRUGO, proc_cpuset_show), -#endif -#ifdef CONFIG_CGROUPS - ONE("cgroup", S_IRUGO, proc_cgroup_show), -#endif - ONE("oom_score", S_IRUGO, proc_oom_score), - REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations), - REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations), -#ifdef CONFIG_AUDITSYSCALL - REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations), - REG("sessionid", S_IRUGO, proc_sessionid_operations), -#endif -#ifdef CONFIG_FAULT_INJECTION - REG("make-it-fail", S_IRUGO|S_IWUSR, proc_fault_inject_operations), -#endif -#ifdef CONFIG_TASK_IO_ACCOUNTING - ONE("io", S_IRUSR, proc_tid_io_accounting), -#endif -#ifdef CONFIG_HARDWALL - ONE("hardwall", S_IRUGO, proc_pid_hardwall), -#endif -#ifdef CONFIG_USER_NS - REG("uid_map", S_IRUGO|S_IWUSR, proc_uid_map_operations), - REG("gid_map", S_IRUGO|S_IWUSR, proc_gid_map_operations), - REG("projid_map", S_IRUGO|S_IWUSR, proc_projid_map_operations), - REG("setgroups", S_IRUGO|S_IWUSR, proc_setgroups_operations), -#endif -}; - -static int proc_tid_base_readdir(struct file *file, struct dir_context *ctx) -{ - return proc_pident_readdir(file, ctx, - tid_base_stuff, ARRAY_SIZE(tid_base_stuff)); -} - -static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) -{ - return proc_pident_lookup(dir, dentry, - tid_base_stuff, ARRAY_SIZE(tid_base_stuff)); -} - -static const struct file_operations proc_tid_base_operations = { - .read = generic_read_dir, - .iterate_shared = proc_tid_base_readdir, - .llseek = generic_file_llseek, -}; - -static const struct inode_operations proc_tid_base_inode_operations = { - .lookup = proc_tid_base_lookup, - .getattr = pid_getattr, - .setattr = proc_setattr, -}; - -static int proc_task_instantiate(struct inode *dir, - struct dentry *dentry, struct task_struct *task, const void *ptr) -{ - struct inode *inode; - inode = proc_pid_make_inode(dir->i_sb, task); - - if (!inode) - goto out; - inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; - inode->i_op = &proc_tid_base_inode_operations; - inode->i_fop = &proc_tid_base_operations; - inode->i_flags|=S_IMMUTABLE; - - set_nlink(inode, 2 + pid_entry_count_dirs(tid_base_stuff, - ARRAY_SIZE(tid_base_stuff))); - - d_set_d_op(dentry, &pid_dentry_operations); - - d_add(dentry, inode); - /* Close the race of the process dying before we return the dentry */ - if (pid_revalidate(dentry, 0)) - return 0; -out: - return -ENOENT; -} - -static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, unsigned int flags) -{ - int result = -ENOENT; - struct task_struct *task; - struct task_struct *leader = get_proc_task(dir); - unsigned tid; - struct pid_namespace *ns; - - if (!leader) - goto out_no_task; - - tid = name_to_int(&dentry->d_name); - if (tid == ~0U) - goto out; - - ns = dentry->d_sb->s_fs_info; - rcu_read_lock(); - task = find_task_by_pid_ns(tid, ns); - if (task) - get_task_struct(task); - rcu_read_unlock(); - if (!task) - goto out; - if (!same_thread_group(leader, task)) - goto out_drop_task; - - result = proc_task_instantiate(dir, dentry, task, NULL); -out_drop_task: - put_task_struct(task); -out: - put_task_struct(leader); -out_no_task: - return ERR_PTR(result); -} - -/* - * Find the first tid of a thread group to return to user space. - * - * Usually this is just the thread group leader, but if the users - * buffer was too small or there was a seek into the middle of the - * directory we have more work todo. - * - * In the case of a short read we start with find_task_by_pid. - * - * In the case of a seek we start with the leader and walk nr - * threads past it. - */ -static struct task_struct *first_tid(struct pid *pid, int tid, loff_t f_pos, - struct pid_namespace *ns) -{ - struct task_struct *pos, *task; - unsigned long nr = f_pos; - - if (nr != f_pos) /* 32bit overflow? */ - return NULL; - - rcu_read_lock(); - task = pid_task(pid, PIDTYPE_PID); - if (!task) - goto fail; - - /* Attempt to start with the tid of a thread */ - if (tid && nr) { - pos = find_task_by_pid_ns(tid, ns); - if (pos && same_thread_group(pos, task)) - goto found; - } - - /* If nr exceeds the number of threads there is nothing todo */ - if (nr >= get_nr_threads(task)) - goto fail; - - /* If we haven't found our starting place yet start - * with the leader and walk nr threads forward. - */ - pos = task = task->group_leader; - do { - if (!nr--) - goto found; - } while_each_thread(task, pos); -fail: - pos = NULL; - goto out; -found: - get_task_struct(pos); -out: - rcu_read_unlock(); - return pos; -} - -/* - * Find the next thread in the thread list. - * Return NULL if there is an error or no next thread. - * - * The reference to the input task_struct is released. - */ -static struct task_struct *next_tid(struct task_struct *start) -{ - struct task_struct *pos = NULL; - rcu_read_lock(); - if (pid_alive(start)) { - pos = next_thread(start); - if (thread_group_leader(pos)) - pos = NULL; - else - get_task_struct(pos); - } - rcu_read_unlock(); - put_task_struct(start); - return pos; -} - -/* for the /proc/TGID/task/ directories */ -static int proc_task_readdir(struct file *file, struct dir_context *ctx) -{ - struct inode *inode = file_inode(file); - struct task_struct *task; - struct pid_namespace *ns; - int tid; - - if (proc_inode_is_dead(inode)) - return -ENOENT; - - if (!dir_emit_dots(file, ctx)) - return 0; - - /* f_version caches the tgid value that the last readdir call couldn't - * return. lseek aka telldir automagically resets f_version to 0. - */ - ns = inode->i_sb->s_fs_info; - tid = (int)file->f_version; - file->f_version = 0; - for (task = first_tid(proc_pid(inode), tid, ctx->pos - 2, ns); - task; - task = next_tid(task), ctx->pos++) { - char name[PROC_NUMBUF]; - int len; - tid = task_pid_nr_ns(task, ns); - len = snprintf(name, sizeof(name), "%d", tid); - if (!proc_fill_cache(file, ctx, name, len, - proc_task_instantiate, task, NULL)) { - /* returning this tgid failed, save it as the first - * pid for the next readir call */ - file->f_version = (u64)tid; - put_task_struct(task); - break; - } - } - - return 0; -} - -static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) -{ - struct inode *inode = d_inode(dentry); - struct task_struct *p = get_proc_task(inode); - generic_fillattr(inode, stat); - - if (p) { - stat->nlink += get_nr_threads(p); - put_task_struct(p); - } - - return 0; -} - -static const struct inode_operations proc_task_inode_operations = { - .lookup = proc_task_lookup, - .getattr = proc_task_getattr, - .setattr = proc_setattr, - .permission = proc_pid_permission, -}; - -static const struct file_operations proc_task_operations = { - .read = generic_read_dir, - .iterate_shared = proc_task_readdir, - .llseek = generic_file_llseek, -}; diff --git a/src/linux/fs/proc/cmdline.c b/src/linux/fs/proc/cmdline.c deleted file mode 100644 index cbd82df..0000000 --- a/src/linux/fs/proc/cmdline.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -#include -#include - -static int cmdline_proc_show(struct seq_file *m, void *v) -{ - seq_printf(m, "%s\n", saved_command_line); - return 0; -} - -static int cmdline_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, cmdline_proc_show, NULL); -} - -static const struct file_operations cmdline_proc_fops = { - .open = cmdline_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init proc_cmdline_init(void) -{ - proc_create("cmdline", 0, NULL, &cmdline_proc_fops); - return 0; -} -fs_initcall(proc_cmdline_init); diff --git a/src/linux/fs/proc/consoles.c b/src/linux/fs/proc/consoles.c deleted file mode 100644 index 290ba85..0000000 --- a/src/linux/fs/proc/consoles.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2010 Werner Fink, Jiri Slaby - * - * Licensed under GPLv2 - */ - -#include -#include -#include -#include -#include - -/* - * This is handler for /proc/consoles - */ -static int show_console_dev(struct seq_file *m, void *v) -{ - static const struct { - short flag; - char name; - } con_flags[] = { - { CON_ENABLED, 'E' }, - { CON_CONSDEV, 'C' }, - { CON_BOOT, 'B' }, - { CON_PRINTBUFFER, 'p' }, - { CON_BRL, 'b' }, - { CON_ANYTIME, 'a' }, - }; - char flags[ARRAY_SIZE(con_flags) + 1]; - struct console *con = v; - unsigned int a; - dev_t dev = 0; - - if (con->device) { - const struct tty_driver *driver; - int index; - driver = con->device(con, &index); - if (driver) { - dev = MKDEV(driver->major, driver->minor_start); - dev += index; - } - } - - for (a = 0; a < ARRAY_SIZE(con_flags); a++) - flags[a] = (con->flags & con_flags[a].flag) ? - con_flags[a].name : ' '; - flags[a] = 0; - - seq_setwidth(m, 21 - 1); - seq_printf(m, "%s%d", con->name, con->index); - seq_pad(m, ' '); - seq_printf(m, "%c%c%c (%s)", con->read ? 'R' : '-', - con->write ? 'W' : '-', con->unblank ? 'U' : '-', - flags); - if (dev) - seq_printf(m, " %4d:%d", MAJOR(dev), MINOR(dev)); - - seq_printf(m, "\n"); - - return 0; -} - -static void *c_start(struct seq_file *m, loff_t *pos) -{ - struct console *con; - loff_t off = 0; - - console_lock(); - for_each_console(con) - if (off++ == *pos) - break; - - return con; -} - -static void *c_next(struct seq_file *m, void *v, loff_t *pos) -{ - struct console *con = v; - ++*pos; - return con->next; -} - -static void c_stop(struct seq_file *m, void *v) -{ - console_unlock(); -} - -static const struct seq_operations consoles_op = { - .start = c_start, - .next = c_next, - .stop = c_stop, - .show = show_console_dev -}; - -static int consoles_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &consoles_op); -} - -static const struct file_operations proc_consoles_operations = { - .open = consoles_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int __init proc_consoles_init(void) -{ - proc_create("consoles", 0, NULL, &proc_consoles_operations); - return 0; -} -fs_initcall(proc_consoles_init); diff --git a/src/linux/fs/proc/cpuinfo.c b/src/linux/fs/proc/cpuinfo.c deleted file mode 100644 index 06f4d31..0000000 --- a/src/linux/fs/proc/cpuinfo.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include -#include - -extern const struct seq_operations cpuinfo_op; -static int cpuinfo_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &cpuinfo_op); -} - -static const struct file_operations proc_cpuinfo_operations = { - .open = cpuinfo_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int __init proc_cpuinfo_init(void) -{ - proc_create("cpuinfo", 0, NULL, &proc_cpuinfo_operations); - return 0; -} -fs_initcall(proc_cpuinfo_init); diff --git a/src/linux/fs/proc/devices.c b/src/linux/fs/proc/devices.c deleted file mode 100644 index 50493ed..0000000 --- a/src/linux/fs/proc/devices.c +++ /dev/null @@ -1,70 +0,0 @@ -#include -#include -#include -#include - -static int devinfo_show(struct seq_file *f, void *v) -{ - int i = *(loff_t *) v; - - if (i < CHRDEV_MAJOR_HASH_SIZE) { - if (i == 0) - seq_puts(f, "Character devices:\n"); - chrdev_show(f, i); - } -#ifdef CONFIG_BLOCK - else { - i -= CHRDEV_MAJOR_HASH_SIZE; - if (i == 0) - seq_puts(f, "\nBlock devices:\n"); - blkdev_show(f, i); - } -#endif - return 0; -} - -static void *devinfo_start(struct seq_file *f, loff_t *pos) -{ - if (*pos < (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE)) - return pos; - return NULL; -} - -static void *devinfo_next(struct seq_file *f, void *v, loff_t *pos) -{ - (*pos)++; - if (*pos >= (BLKDEV_MAJOR_HASH_SIZE + CHRDEV_MAJOR_HASH_SIZE)) - return NULL; - return pos; -} - -static void devinfo_stop(struct seq_file *f, void *v) -{ - /* Nothing to do */ -} - -static const struct seq_operations devinfo_ops = { - .start = devinfo_start, - .next = devinfo_next, - .stop = devinfo_stop, - .show = devinfo_show -}; - -static int devinfo_open(struct inode *inode, struct file *filp) -{ - return seq_open(filp, &devinfo_ops); -} - -static const struct file_operations proc_devinfo_operations = { - .open = devinfo_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int __init proc_devices_init(void) -{ - proc_create("devices", 0, NULL, &proc_devinfo_operations); - return 0; -} -fs_initcall(proc_devices_init); diff --git a/src/linux/fs/proc/fd.c b/src/linux/fs/proc/fd.c deleted file mode 100644 index d21dafe..0000000 --- a/src/linux/fs/proc/fd.c +++ /dev/null @@ -1,366 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "../mount.h" -#include "internal.h" -#include "fd.h" - -static int seq_show(struct seq_file *m, void *v) -{ - struct files_struct *files = NULL; - int f_flags = 0, ret = -ENOENT; - struct file *file = NULL; - struct task_struct *task; - - task = get_proc_task(m->private); - if (!task) - return -ENOENT; - - files = get_files_struct(task); - put_task_struct(task); - - if (files) { - unsigned int fd = proc_fd(m->private); - - spin_lock(&files->file_lock); - file = fcheck_files(files, fd); - if (file) { - struct fdtable *fdt = files_fdtable(files); - - f_flags = file->f_flags; - if (close_on_exec(fd, fdt)) - f_flags |= O_CLOEXEC; - - get_file(file); - ret = 0; - } - spin_unlock(&files->file_lock); - put_files_struct(files); - } - - if (ret) - return ret; - - seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\n", - (long long)file->f_pos, f_flags, - real_mount(file->f_path.mnt)->mnt_id); - - show_fd_locks(m, file, files); - if (seq_has_overflowed(m)) - goto out; - - if (file->f_op->show_fdinfo) - file->f_op->show_fdinfo(m, file); - -out: - fput(file); - return 0; -} - -static int seq_fdinfo_open(struct inode *inode, struct file *file) -{ - return single_open(file, seq_show, inode); -} - -static const struct file_operations proc_fdinfo_file_operations = { - .open = seq_fdinfo_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags) -{ - struct files_struct *files; - struct task_struct *task; - const struct cred *cred; - struct inode *inode; - unsigned int fd; - - if (flags & LOOKUP_RCU) - return -ECHILD; - - inode = d_inode(dentry); - task = get_proc_task(inode); - fd = proc_fd(inode); - - if (task) { - files = get_files_struct(task); - if (files) { - struct file *file; - - rcu_read_lock(); - file = fcheck_files(files, fd); - if (file) { - unsigned f_mode = file->f_mode; - - rcu_read_unlock(); - put_files_struct(files); - - if (task_dumpable(task)) { - rcu_read_lock(); - cred = __task_cred(task); - inode->i_uid = cred->euid; - inode->i_gid = cred->egid; - rcu_read_unlock(); - } else { - inode->i_uid = GLOBAL_ROOT_UID; - inode->i_gid = GLOBAL_ROOT_GID; - } - - if (S_ISLNK(inode->i_mode)) { - unsigned i_mode = S_IFLNK; - if (f_mode & FMODE_READ) - i_mode |= S_IRUSR | S_IXUSR; - if (f_mode & FMODE_WRITE) - i_mode |= S_IWUSR | S_IXUSR; - inode->i_mode = i_mode; - } - - security_task_to_inode(task, inode); - put_task_struct(task); - return 1; - } - rcu_read_unlock(); - put_files_struct(files); - } - put_task_struct(task); - } - return 0; -} - -static const struct dentry_operations tid_fd_dentry_operations = { - .d_revalidate = tid_fd_revalidate, - .d_delete = pid_delete_dentry, -}; - -static int proc_fd_link(struct dentry *dentry, struct path *path) -{ - struct files_struct *files = NULL; - struct task_struct *task; - int ret = -ENOENT; - - task = get_proc_task(d_inode(dentry)); - if (task) { - files = get_files_struct(task); - put_task_struct(task); - } - - if (files) { - unsigned int fd = proc_fd(d_inode(dentry)); - struct file *fd_file; - - spin_lock(&files->file_lock); - fd_file = fcheck_files(files, fd); - if (fd_file) { - *path = fd_file->f_path; - path_get(&fd_file->f_path); - ret = 0; - } - spin_unlock(&files->file_lock); - put_files_struct(files); - } - - return ret; -} - -static int -proc_fd_instantiate(struct inode *dir, struct dentry *dentry, - struct task_struct *task, const void *ptr) -{ - unsigned fd = (unsigned long)ptr; - struct proc_inode *ei; - struct inode *inode; - - inode = proc_pid_make_inode(dir->i_sb, task); - if (!inode) - goto out; - - ei = PROC_I(inode); - ei->fd = fd; - - inode->i_mode = S_IFLNK; - inode->i_op = &proc_pid_link_inode_operations; - inode->i_size = 64; - - ei->op.proc_get_link = proc_fd_link; - - d_set_d_op(dentry, &tid_fd_dentry_operations); - d_add(dentry, inode); - - /* Close the race of the process dying before we return the dentry */ - if (tid_fd_revalidate(dentry, 0)) - return 0; - out: - return -ENOENT; -} - -static struct dentry *proc_lookupfd_common(struct inode *dir, - struct dentry *dentry, - instantiate_t instantiate) -{ - struct task_struct *task = get_proc_task(dir); - int result = -ENOENT; - unsigned fd = name_to_int(&dentry->d_name); - - if (!task) - goto out_no_task; - if (fd == ~0U) - goto out; - - result = instantiate(dir, dentry, task, (void *)(unsigned long)fd); -out: - put_task_struct(task); -out_no_task: - return ERR_PTR(result); -} - -static int proc_readfd_common(struct file *file, struct dir_context *ctx, - instantiate_t instantiate) -{ - struct task_struct *p = get_proc_task(file_inode(file)); - struct files_struct *files; - unsigned int fd; - - if (!p) - return -ENOENT; - - if (!dir_emit_dots(file, ctx)) - goto out; - files = get_files_struct(p); - if (!files) - goto out; - - rcu_read_lock(); - for (fd = ctx->pos - 2; - fd < files_fdtable(files)->max_fds; - fd++, ctx->pos++) { - char name[PROC_NUMBUF]; - int len; - - if (!fcheck_files(files, fd)) - continue; - rcu_read_unlock(); - - len = snprintf(name, sizeof(name), "%u", fd); - if (!proc_fill_cache(file, ctx, - name, len, instantiate, p, - (void *)(unsigned long)fd)) - goto out_fd_loop; - cond_resched(); - rcu_read_lock(); - } - rcu_read_unlock(); -out_fd_loop: - put_files_struct(files); -out: - put_task_struct(p); - return 0; -} - -static int proc_readfd(struct file *file, struct dir_context *ctx) -{ - return proc_readfd_common(file, ctx, proc_fd_instantiate); -} - -const struct file_operations proc_fd_operations = { - .read = generic_read_dir, - .iterate_shared = proc_readfd, - .llseek = generic_file_llseek, -}; - -static struct dentry *proc_lookupfd(struct inode *dir, struct dentry *dentry, - unsigned int flags) -{ - return proc_lookupfd_common(dir, dentry, proc_fd_instantiate); -} - -/* - * /proc/pid/fd needs a special permission handler so that a process can still - * access /proc/self/fd after it has executed a setuid(). - */ -int proc_fd_permission(struct inode *inode, int mask) -{ - struct task_struct *p; - int rv; - - rv = generic_permission(inode, mask); - if (rv == 0) - return rv; - - rcu_read_lock(); - p = pid_task(proc_pid(inode), PIDTYPE_PID); - if (p && same_thread_group(p, current)) - rv = 0; - rcu_read_unlock(); - - return rv; -} - -const struct inode_operations proc_fd_inode_operations = { - .lookup = proc_lookupfd, - .permission = proc_fd_permission, - .setattr = proc_setattr, -}; - -static int -proc_fdinfo_instantiate(struct inode *dir, struct dentry *dentry, - struct task_struct *task, const void *ptr) -{ - unsigned fd = (unsigned long)ptr; - struct proc_inode *ei; - struct inode *inode; - - inode = proc_pid_make_inode(dir->i_sb, task); - if (!inode) - goto out; - - ei = PROC_I(inode); - ei->fd = fd; - - inode->i_mode = S_IFREG | S_IRUSR; - inode->i_fop = &proc_fdinfo_file_operations; - - d_set_d_op(dentry, &tid_fd_dentry_operations); - d_add(dentry, inode); - - /* Close the race of the process dying before we return the dentry */ - if (tid_fd_revalidate(dentry, 0)) - return 0; - out: - return -ENOENT; -} - -static struct dentry * -proc_lookupfdinfo(struct inode *dir, struct dentry *dentry, unsigned int flags) -{ - return proc_lookupfd_common(dir, dentry, proc_fdinfo_instantiate); -} - -static int proc_readfdinfo(struct file *file, struct dir_context *ctx) -{ - return proc_readfd_common(file, ctx, - proc_fdinfo_instantiate); -} - -const struct inode_operations proc_fdinfo_inode_operations = { - .lookup = proc_lookupfdinfo, - .setattr = proc_setattr, -}; - -const struct file_operations proc_fdinfo_operations = { - .read = generic_read_dir, - .iterate_shared = proc_readfdinfo, - .llseek = generic_file_llseek, -}; diff --git a/src/linux/fs/proc/fd.h b/src/linux/fs/proc/fd.h deleted file mode 100644 index 46dafad..0000000 --- a/src/linux/fs/proc/fd.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef __PROCFS_FD_H__ -#define __PROCFS_FD_H__ - -#include - -extern const struct file_operations proc_fd_operations; -extern const struct inode_operations proc_fd_inode_operations; - -extern const struct file_operations proc_fdinfo_operations; -extern const struct inode_operations proc_fdinfo_inode_operations; - -extern int proc_fd_permission(struct inode *inode, int mask); - -static inline unsigned int proc_fd(struct inode *inode) -{ - return PROC_I(inode)->fd; -} - -#endif /* __PROCFS_FD_H__ */ diff --git a/src/linux/fs/proc/generic.c b/src/linux/fs/proc/generic.c deleted file mode 100644 index 5f2dc20..0000000 --- a/src/linux/fs/proc/generic.c +++ /dev/null @@ -1,647 +0,0 @@ -/* - * proc/fs/generic.c --- generic routines for the proc-fs - * - * This file contains generic proc-fs routines for handling - * directories and files. - * - * Copyright (C) 1991, 1992 Linus Torvalds. - * Copyright (C) 1997 Theodore Ts'o - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -static DEFINE_RWLOCK(proc_subdir_lock); - -static int proc_match(unsigned int len, const char *name, struct proc_dir_entry *de) -{ - if (len < de->namelen) - return -1; - if (len > de->namelen) - return 1; - - return memcmp(name, de->name, len); -} - -static struct proc_dir_entry *pde_subdir_first(struct proc_dir_entry *dir) -{ - return rb_entry_safe(rb_first(&dir->subdir), struct proc_dir_entry, - subdir_node); -} - -static struct proc_dir_entry *pde_subdir_next(struct proc_dir_entry *dir) -{ - return rb_entry_safe(rb_next(&dir->subdir_node), struct proc_dir_entry, - subdir_node); -} - -static struct proc_dir_entry *pde_subdir_find(struct proc_dir_entry *dir, - const char *name, - unsigned int len) -{ - struct rb_node *node = dir->subdir.rb_node; - - while (node) { - struct proc_dir_entry *de = container_of(node, - struct proc_dir_entry, - subdir_node); - int result = proc_match(len, name, de); - - if (result < 0) - node = node->rb_left; - else if (result > 0) - node = node->rb_right; - else - return de; - } - return NULL; -} - -static bool pde_subdir_insert(struct proc_dir_entry *dir, - struct proc_dir_entry *de) -{ - struct rb_root *root = &dir->subdir; - struct rb_node **new = &root->rb_node, *parent = NULL; - - /* Figure out where to put new node */ - while (*new) { - struct proc_dir_entry *this = - container_of(*new, struct proc_dir_entry, subdir_node); - int result = proc_match(de->namelen, de->name, this); - - parent = *new; - if (result < 0) - new = &(*new)->rb_left; - else if (result > 0) - new = &(*new)->rb_right; - else - return false; - } - - /* Add new node and rebalance tree. */ - rb_link_node(&de->subdir_node, parent, new); - rb_insert_color(&de->subdir_node, root); - return true; -} - -static int proc_notify_change(struct dentry *dentry, struct iattr *iattr) -{ - struct inode *inode = d_inode(dentry); - struct proc_dir_entry *de = PDE(inode); - int error; - - error = setattr_prepare(dentry, iattr); - if (error) - return error; - - setattr_copy(inode, iattr); - mark_inode_dirty(inode); - - proc_set_user(de, inode->i_uid, inode->i_gid); - de->mode = inode->i_mode; - return 0; -} - -static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry, - struct kstat *stat) -{ - struct inode *inode = d_inode(dentry); - struct proc_dir_entry *de = PDE(inode); - if (de && de->nlink) - set_nlink(inode, de->nlink); - - generic_fillattr(inode, stat); - return 0; -} - -static const struct inode_operations proc_file_inode_operations = { - .setattr = proc_notify_change, -}; - -/* - * This function parses a name such as "tty/driver/serial", and - * returns the struct proc_dir_entry for "/proc/tty/driver", and - * returns "serial" in residual. - */ -static int __xlate_proc_name(const char *name, struct proc_dir_entry **ret, - const char **residual) -{ - const char *cp = name, *next; - struct proc_dir_entry *de; - unsigned int len; - - de = *ret; - if (!de) - de = &proc_root; - - while (1) { - next = strchr(cp, '/'); - if (!next) - break; - - len = next - cp; - de = pde_subdir_find(de, cp, len); - if (!de) { - WARN(1, "name '%s'\n", name); - return -ENOENT; - } - cp += len + 1; - } - *residual = cp; - *ret = de; - return 0; -} - -static int xlate_proc_name(const char *name, struct proc_dir_entry **ret, - const char **residual) -{ - int rv; - - read_lock(&proc_subdir_lock); - rv = __xlate_proc_name(name, ret, residual); - read_unlock(&proc_subdir_lock); - return rv; -} - -static DEFINE_IDA(proc_inum_ida); -static DEFINE_SPINLOCK(proc_inum_lock); /* protects the above */ - -#define PROC_DYNAMIC_FIRST 0xF0000000U - -/* - * Return an inode number between PROC_DYNAMIC_FIRST and - * 0xffffffff, or zero on failure. - */ -int proc_alloc_inum(unsigned int *inum) -{ - unsigned int i; - int error; - -retry: - if (!ida_pre_get(&proc_inum_ida, GFP_KERNEL)) - return -ENOMEM; - - spin_lock_irq(&proc_inum_lock); - error = ida_get_new(&proc_inum_ida, &i); - spin_unlock_irq(&proc_inum_lock); - if (error == -EAGAIN) - goto retry; - else if (error) - return error; - - if (i > UINT_MAX - PROC_DYNAMIC_FIRST) { - spin_lock_irq(&proc_inum_lock); - ida_remove(&proc_inum_ida, i); - spin_unlock_irq(&proc_inum_lock); - return -ENOSPC; - } - *inum = PROC_DYNAMIC_FIRST + i; - return 0; -} - -void proc_free_inum(unsigned int inum) -{ - unsigned long flags; - spin_lock_irqsave(&proc_inum_lock, flags); - ida_remove(&proc_inum_ida, inum - PROC_DYNAMIC_FIRST); - spin_unlock_irqrestore(&proc_inum_lock, flags); -} - -/* - * Don't create negative dentries here, return -ENOENT by hand - * instead. - */ -struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir, - struct dentry *dentry) -{ - struct inode *inode; - - read_lock(&proc_subdir_lock); - de = pde_subdir_find(de, dentry->d_name.name, dentry->d_name.len); - if (de) { - pde_get(de); - read_unlock(&proc_subdir_lock); - inode = proc_get_inode(dir->i_sb, de); - if (!inode) - return ERR_PTR(-ENOMEM); - d_set_d_op(dentry, &simple_dentry_operations); - d_add(dentry, inode); - return NULL; - } - read_unlock(&proc_subdir_lock); - return ERR_PTR(-ENOENT); -} - -struct dentry *proc_lookup(struct inode *dir, struct dentry *dentry, - unsigned int flags) -{ - return proc_lookup_de(PDE(dir), dir, dentry); -} - -/* - * This returns non-zero if at EOF, so that the /proc - * root directory can use this and check if it should - * continue with the entries.. - * - * Note that the VFS-layer doesn't care about the return - * value of the readdir() call, as long as it's non-negative - * for success.. - */ -int proc_readdir_de(struct proc_dir_entry *de, struct file *file, - struct dir_context *ctx) -{ - int i; - - if (!dir_emit_dots(file, ctx)) - return 0; - - read_lock(&proc_subdir_lock); - de = pde_subdir_first(de); - i = ctx->pos - 2; - for (;;) { - if (!de) { - read_unlock(&proc_subdir_lock); - return 0; - } - if (!i) - break; - de = pde_subdir_next(de); - i--; - } - - do { - struct proc_dir_entry *next; - pde_get(de); - read_unlock(&proc_subdir_lock); - if (!dir_emit(ctx, de->name, de->namelen, - de->low_ino, de->mode >> 12)) { - pde_put(de); - return 0; - } - read_lock(&proc_subdir_lock); - ctx->pos++; - next = pde_subdir_next(de); - pde_put(de); - de = next; - } while (de); - read_unlock(&proc_subdir_lock); - return 1; -} - -int proc_readdir(struct file *file, struct dir_context *ctx) -{ - struct inode *inode = file_inode(file); - - return proc_readdir_de(PDE(inode), file, ctx); -} - -/* - * These are the generic /proc directory operations. They - * use the in-memory "struct proc_dir_entry" tree to parse - * the /proc directory. - */ -static const struct file_operations proc_dir_operations = { - .llseek = generic_file_llseek, - .read = generic_read_dir, - .iterate_shared = proc_readdir, -}; - -/* - * proc directories can do almost nothing.. - */ -static const struct inode_operations proc_dir_inode_operations = { - .lookup = proc_lookup, - .getattr = proc_getattr, - .setattr = proc_notify_change, -}; - -static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp) -{ - int ret; - - ret = proc_alloc_inum(&dp->low_ino); - if (ret) - return ret; - - write_lock(&proc_subdir_lock); - dp->parent = dir; - if (pde_subdir_insert(dir, dp) == false) { - WARN(1, "proc_dir_entry '%s/%s' already registered\n", - dir->name, dp->name); - write_unlock(&proc_subdir_lock); - proc_free_inum(dp->low_ino); - return -EEXIST; - } - write_unlock(&proc_subdir_lock); - - return 0; -} - -static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent, - const char *name, - umode_t mode, - nlink_t nlink) -{ - struct proc_dir_entry *ent = NULL; - const char *fn; - struct qstr qstr; - - if (xlate_proc_name(name, parent, &fn) != 0) - goto out; - qstr.name = fn; - qstr.len = strlen(fn); - if (qstr.len == 0 || qstr.len >= 256) { - WARN(1, "name len %u\n", qstr.len); - return NULL; - } - if (*parent == &proc_root && name_to_int(&qstr) != ~0U) { - WARN(1, "create '/proc/%s' by hand\n", qstr.name); - return NULL; - } - if (is_empty_pde(*parent)) { - WARN(1, "attempt to add to permanently empty directory"); - return NULL; - } - - ent = kzalloc(sizeof(struct proc_dir_entry) + qstr.len + 1, GFP_KERNEL); - if (!ent) - goto out; - - memcpy(ent->name, fn, qstr.len + 1); - ent->namelen = qstr.len; - ent->mode = mode; - ent->nlink = nlink; - ent->subdir = RB_ROOT; - atomic_set(&ent->count, 1); - spin_lock_init(&ent->pde_unload_lock); - INIT_LIST_HEAD(&ent->pde_openers); - proc_set_user(ent, (*parent)->uid, (*parent)->gid); - -out: - return ent; -} - -struct proc_dir_entry *proc_symlink(const char *name, - struct proc_dir_entry *parent, const char *dest) -{ - struct proc_dir_entry *ent; - - ent = __proc_create(&parent, name, - (S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO),1); - - if (ent) { - ent->data = kmalloc((ent->size=strlen(dest))+1, GFP_KERNEL); - if (ent->data) { - strcpy((char*)ent->data,dest); - ent->proc_iops = &proc_link_inode_operations; - if (proc_register(parent, ent) < 0) { - kfree(ent->data); - kfree(ent); - ent = NULL; - } - } else { - kfree(ent); - ent = NULL; - } - } - return ent; -} -EXPORT_SYMBOL(proc_symlink); - -struct proc_dir_entry *proc_mkdir_data(const char *name, umode_t mode, - struct proc_dir_entry *parent, void *data) -{ - struct proc_dir_entry *ent; - - if (mode == 0) - mode = S_IRUGO | S_IXUGO; - - ent = __proc_create(&parent, name, S_IFDIR | mode, 2); - if (ent) { - ent->data = data; - ent->proc_fops = &proc_dir_operations; - ent->proc_iops = &proc_dir_inode_operations; - parent->nlink++; - if (proc_register(parent, ent) < 0) { - kfree(ent); - parent->nlink--; - ent = NULL; - } - } - return ent; -} -EXPORT_SYMBOL_GPL(proc_mkdir_data); - -struct proc_dir_entry *proc_mkdir_mode(const char *name, umode_t mode, - struct proc_dir_entry *parent) -{ - return proc_mkdir_data(name, mode, parent, NULL); -} -EXPORT_SYMBOL(proc_mkdir_mode); - -struct proc_dir_entry *proc_mkdir(const char *name, - struct proc_dir_entry *parent) -{ - return proc_mkdir_data(name, 0, parent, NULL); -} -EXPORT_SYMBOL(proc_mkdir); - -struct proc_dir_entry *proc_create_mount_point(const char *name) -{ - umode_t mode = S_IFDIR | S_IRUGO | S_IXUGO; - struct proc_dir_entry *ent, *parent = NULL; - - ent = __proc_create(&parent, name, mode, 2); - if (ent) { - ent->data = NULL; - ent->proc_fops = NULL; - ent->proc_iops = NULL; - if (proc_register(parent, ent) < 0) { - kfree(ent); - parent->nlink--; - ent = NULL; - } - } - return ent; -} - -struct proc_dir_entry *proc_create_data(const char *name, umode_t mode, - struct proc_dir_entry *parent, - const struct file_operations *proc_fops, - void *data) -{ - struct proc_dir_entry *pde; - if ((mode & S_IFMT) == 0) - mode |= S_IFREG; - - if (!S_ISREG(mode)) { - WARN_ON(1); /* use proc_mkdir() */ - return NULL; - } - - BUG_ON(proc_fops == NULL); - - if ((mode & S_IALLUGO) == 0) - mode |= S_IRUGO; - pde = __proc_create(&parent, name, mode, 1); - if (!pde) - goto out; - pde->proc_fops = proc_fops; - pde->data = data; - pde->proc_iops = &proc_file_inode_operations; - if (proc_register(parent, pde) < 0) - goto out_free; - return pde; -out_free: - kfree(pde); -out: - return NULL; -} -EXPORT_SYMBOL(proc_create_data); - -void proc_set_size(struct proc_dir_entry *de, loff_t size) -{ - de->size = size; -} -EXPORT_SYMBOL(proc_set_size); - -void proc_set_user(struct proc_dir_entry *de, kuid_t uid, kgid_t gid) -{ - de->uid = uid; - de->gid = gid; -} -EXPORT_SYMBOL(proc_set_user); - -static void free_proc_entry(struct proc_dir_entry *de) -{ - proc_free_inum(de->low_ino); - - if (S_ISLNK(de->mode)) - kfree(de->data); - kfree(de); -} - -void pde_put(struct proc_dir_entry *pde) -{ - if (atomic_dec_and_test(&pde->count)) - free_proc_entry(pde); -} - -/* - * Remove a /proc entry and free it if it's not currently in use. - */ -void remove_proc_entry(const char *name, struct proc_dir_entry *parent) -{ - struct proc_dir_entry *de = NULL; - const char *fn = name; - unsigned int len; - - write_lock(&proc_subdir_lock); - if (__xlate_proc_name(name, &parent, &fn) != 0) { - write_unlock(&proc_subdir_lock); - return; - } - len = strlen(fn); - - de = pde_subdir_find(parent, fn, len); - if (de) - rb_erase(&de->subdir_node, &parent->subdir); - write_unlock(&proc_subdir_lock); - if (!de) { - WARN(1, "name '%s'\n", name); - return; - } - - proc_entry_rundown(de); - - if (S_ISDIR(de->mode)) - parent->nlink--; - de->nlink = 0; - WARN(pde_subdir_first(de), - "%s: removing non-empty directory '%s/%s', leaking at least '%s'\n", - __func__, de->parent->name, de->name, pde_subdir_first(de)->name); - pde_put(de); -} -EXPORT_SYMBOL(remove_proc_entry); - -int remove_proc_subtree(const char *name, struct proc_dir_entry *parent) -{ - struct proc_dir_entry *root = NULL, *de, *next; - const char *fn = name; - unsigned int len; - - write_lock(&proc_subdir_lock); - if (__xlate_proc_name(name, &parent, &fn) != 0) { - write_unlock(&proc_subdir_lock); - return -ENOENT; - } - len = strlen(fn); - - root = pde_subdir_find(parent, fn, len); - if (!root) { - write_unlock(&proc_subdir_lock); - return -ENOENT; - } - rb_erase(&root->subdir_node, &parent->subdir); - - de = root; - while (1) { - next = pde_subdir_first(de); - if (next) { - rb_erase(&next->subdir_node, &de->subdir); - de = next; - continue; - } - write_unlock(&proc_subdir_lock); - - proc_entry_rundown(de); - next = de->parent; - if (S_ISDIR(de->mode)) - next->nlink--; - de->nlink = 0; - if (de == root) - break; - pde_put(de); - - write_lock(&proc_subdir_lock); - de = next; - } - pde_put(root); - return 0; -} -EXPORT_SYMBOL(remove_proc_subtree); - -void *proc_get_parent_data(const struct inode *inode) -{ - struct proc_dir_entry *de = PDE(inode); - return de->parent->data; -} -EXPORT_SYMBOL_GPL(proc_get_parent_data); - -void proc_remove(struct proc_dir_entry *de) -{ - if (de) - remove_proc_subtree(de->name, de->parent); -} -EXPORT_SYMBOL(proc_remove); - -void *PDE_DATA(const struct inode *inode) -{ - return __PDE_DATA(inode); -} -EXPORT_SYMBOL(PDE_DATA); diff --git a/src/linux/fs/proc/inode.c b/src/linux/fs/proc/inode.c deleted file mode 100644 index e69ebe6..0000000 --- a/src/linux/fs/proc/inode.c +++ /dev/null @@ -1,502 +0,0 @@ -/* - * linux/fs/proc/inode.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "internal.h" - -static void proc_evict_inode(struct inode *inode) -{ - struct proc_dir_entry *de; - struct ctl_table_header *head; - - truncate_inode_pages_final(&inode->i_data); - clear_inode(inode); - - /* Stop tracking associated processes */ - put_pid(PROC_I(inode)->pid); - - /* Let go of any associated proc directory entry */ - de = PDE(inode); - if (de) - pde_put(de); - head = PROC_I(inode)->sysctl; - if (head) { - RCU_INIT_POINTER(PROC_I(inode)->sysctl, NULL); - sysctl_head_put(head); - } -} - -static struct kmem_cache * proc_inode_cachep; - -static struct inode *proc_alloc_inode(struct super_block *sb) -{ - struct proc_inode *ei; - struct inode *inode; - - ei = (struct proc_inode *)kmem_cache_alloc(proc_inode_cachep, GFP_KERNEL); - if (!ei) - return NULL; - ei->pid = NULL; - ei->fd = 0; - ei->op.proc_get_link = NULL; - ei->pde = NULL; - ei->sysctl = NULL; - ei->sysctl_entry = NULL; - ei->ns_ops = NULL; - inode = &ei->vfs_inode; - return inode; -} - -static void proc_i_callback(struct rcu_head *head) -{ - struct inode *inode = container_of(head, struct inode, i_rcu); - kmem_cache_free(proc_inode_cachep, PROC_I(inode)); -} - -static void proc_destroy_inode(struct inode *inode) -{ - call_rcu(&inode->i_rcu, proc_i_callback); -} - -static void init_once(void *foo) -{ - struct proc_inode *ei = (struct proc_inode *) foo; - - inode_init_once(&ei->vfs_inode); -} - -void __init proc_init_inodecache(void) -{ - proc_inode_cachep = kmem_cache_create("proc_inode_cache", - sizeof(struct proc_inode), - 0, (SLAB_RECLAIM_ACCOUNT| - SLAB_MEM_SPREAD|SLAB_ACCOUNT| - SLAB_PANIC), - init_once); -} - -static int proc_show_options(struct seq_file *seq, struct dentry *root) -{ - struct super_block *sb = root->d_sb; - struct pid_namespace *pid = sb->s_fs_info; - - if (!gid_eq(pid->pid_gid, GLOBAL_ROOT_GID)) - seq_printf(seq, ",gid=%u", from_kgid_munged(&init_user_ns, pid->pid_gid)); - if (pid->hide_pid != 0) - seq_printf(seq, ",hidepid=%u", pid->hide_pid); - - return 0; -} - -static const struct super_operations proc_sops = { - .alloc_inode = proc_alloc_inode, - .destroy_inode = proc_destroy_inode, - .drop_inode = generic_delete_inode, - .evict_inode = proc_evict_inode, - .statfs = simple_statfs, - .remount_fs = proc_remount, - .show_options = proc_show_options, -}; - -enum {BIAS = -1U<<31}; - -static inline int use_pde(struct proc_dir_entry *pde) -{ - return atomic_inc_unless_negative(&pde->in_use); -} - -static void unuse_pde(struct proc_dir_entry *pde) -{ - if (atomic_dec_return(&pde->in_use) == BIAS) - complete(pde->pde_unload_completion); -} - -/* pde is locked */ -static void close_pdeo(struct proc_dir_entry *pde, struct pde_opener *pdeo) -{ - if (pdeo->closing) { - /* somebody else is doing that, just wait */ - DECLARE_COMPLETION_ONSTACK(c); - pdeo->c = &c; - spin_unlock(&pde->pde_unload_lock); - wait_for_completion(&c); - spin_lock(&pde->pde_unload_lock); - } else { - struct file *file; - pdeo->closing = 1; - spin_unlock(&pde->pde_unload_lock); - file = pdeo->file; - pde->proc_fops->release(file_inode(file), file); - spin_lock(&pde->pde_unload_lock); - list_del_init(&pdeo->lh); - if (pdeo->c) - complete(pdeo->c); - kfree(pdeo); - } -} - -void proc_entry_rundown(struct proc_dir_entry *de) -{ - DECLARE_COMPLETION_ONSTACK(c); - /* Wait until all existing callers into module are done. */ - de->pde_unload_completion = &c; - if (atomic_add_return(BIAS, &de->in_use) != BIAS) - wait_for_completion(&c); - - spin_lock(&de->pde_unload_lock); - while (!list_empty(&de->pde_openers)) { - struct pde_opener *pdeo; - pdeo = list_first_entry(&de->pde_openers, struct pde_opener, lh); - close_pdeo(de, pdeo); - } - spin_unlock(&de->pde_unload_lock); -} - -static loff_t proc_reg_llseek(struct file *file, loff_t offset, int whence) -{ - struct proc_dir_entry *pde = PDE(file_inode(file)); - loff_t rv = -EINVAL; - if (use_pde(pde)) { - loff_t (*llseek)(struct file *, loff_t, int); - llseek = pde->proc_fops->llseek; - if (!llseek) - llseek = default_llseek; - rv = llseek(file, offset, whence); - unuse_pde(pde); - } - return rv; -} - -static ssize_t proc_reg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) -{ - ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); - struct proc_dir_entry *pde = PDE(file_inode(file)); - ssize_t rv = -EIO; - if (use_pde(pde)) { - read = pde->proc_fops->read; - if (read) - rv = read(file, buf, count, ppos); - unuse_pde(pde); - } - return rv; -} - -static ssize_t proc_reg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) -{ - ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); - struct proc_dir_entry *pde = PDE(file_inode(file)); - ssize_t rv = -EIO; - if (use_pde(pde)) { - write = pde->proc_fops->write; - if (write) - rv = write(file, buf, count, ppos); - unuse_pde(pde); - } - return rv; -} - -static unsigned int proc_reg_poll(struct file *file, struct poll_table_struct *pts) -{ - struct proc_dir_entry *pde = PDE(file_inode(file)); - unsigned int rv = DEFAULT_POLLMASK; - unsigned int (*poll)(struct file *, struct poll_table_struct *); - if (use_pde(pde)) { - poll = pde->proc_fops->poll; - if (poll) - rv = poll(file, pts); - unuse_pde(pde); - } - return rv; -} - -static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct proc_dir_entry *pde = PDE(file_inode(file)); - long rv = -ENOTTY; - long (*ioctl)(struct file *, unsigned int, unsigned long); - if (use_pde(pde)) { - ioctl = pde->proc_fops->unlocked_ioctl; - if (ioctl) - rv = ioctl(file, cmd, arg); - unuse_pde(pde); - } - return rv; -} - -#ifdef CONFIG_COMPAT -static long proc_reg_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) -{ - struct proc_dir_entry *pde = PDE(file_inode(file)); - long rv = -ENOTTY; - long (*compat_ioctl)(struct file *, unsigned int, unsigned long); - if (use_pde(pde)) { - compat_ioctl = pde->proc_fops->compat_ioctl; - if (compat_ioctl) - rv = compat_ioctl(file, cmd, arg); - unuse_pde(pde); - } - return rv; -} -#endif - -static int proc_reg_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct proc_dir_entry *pde = PDE(file_inode(file)); - int rv = -EIO; - int (*mmap)(struct file *, struct vm_area_struct *); - if (use_pde(pde)) { - mmap = pde->proc_fops->mmap; - if (mmap) - rv = mmap(file, vma); - unuse_pde(pde); - } - return rv; -} - -static unsigned long -proc_reg_get_unmapped_area(struct file *file, unsigned long orig_addr, - unsigned long len, unsigned long pgoff, - unsigned long flags) -{ - struct proc_dir_entry *pde = PDE(file_inode(file)); - unsigned long rv = -EIO; - - if (use_pde(pde)) { - typeof(proc_reg_get_unmapped_area) *get_area; - - get_area = pde->proc_fops->get_unmapped_area; -#ifdef CONFIG_MMU - if (!get_area) - get_area = current->mm->get_unmapped_area; -#endif - - if (get_area) - rv = get_area(file, orig_addr, len, pgoff, flags); - else - rv = orig_addr; - unuse_pde(pde); - } - return rv; -} - -static int proc_reg_open(struct inode *inode, struct file *file) -{ - struct proc_dir_entry *pde = PDE(inode); - int rv = 0; - int (*open)(struct inode *, struct file *); - int (*release)(struct inode *, struct file *); - struct pde_opener *pdeo; - - /* - * What for, you ask? Well, we can have open, rmmod, remove_proc_entry - * sequence. ->release won't be called because ->proc_fops will be - * cleared. Depending on complexity of ->release, consequences vary. - * - * We can't wait for mercy when close will be done for real, it's - * deadlockable: rmmod foo release - * by hand in remove_proc_entry(). For this, save opener's credentials - * for later. - */ - pdeo = kzalloc(sizeof(struct pde_opener), GFP_KERNEL); - if (!pdeo) - return -ENOMEM; - - if (!use_pde(pde)) { - kfree(pdeo); - return -ENOENT; - } - open = pde->proc_fops->open; - release = pde->proc_fops->release; - - if (open) - rv = open(inode, file); - - if (rv == 0 && release) { - /* To know what to release. */ - pdeo->file = file; - /* Strictly for "too late" ->release in proc_reg_release(). */ - spin_lock(&pde->pde_unload_lock); - list_add(&pdeo->lh, &pde->pde_openers); - spin_unlock(&pde->pde_unload_lock); - } else - kfree(pdeo); - - unuse_pde(pde); - return rv; -} - -static int proc_reg_release(struct inode *inode, struct file *file) -{ - struct proc_dir_entry *pde = PDE(inode); - struct pde_opener *pdeo; - spin_lock(&pde->pde_unload_lock); - list_for_each_entry(pdeo, &pde->pde_openers, lh) { - if (pdeo->file == file) { - close_pdeo(pde, pdeo); - break; - } - } - spin_unlock(&pde->pde_unload_lock); - return 0; -} - -static const struct file_operations proc_reg_file_ops = { - .llseek = proc_reg_llseek, - .read = proc_reg_read, - .write = proc_reg_write, - .poll = proc_reg_poll, - .unlocked_ioctl = proc_reg_unlocked_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = proc_reg_compat_ioctl, -#endif - .mmap = proc_reg_mmap, - .get_unmapped_area = proc_reg_get_unmapped_area, - .open = proc_reg_open, - .release = proc_reg_release, -}; - -#ifdef CONFIG_COMPAT -static const struct file_operations proc_reg_file_ops_no_compat = { - .llseek = proc_reg_llseek, - .read = proc_reg_read, - .write = proc_reg_write, - .poll = proc_reg_poll, - .unlocked_ioctl = proc_reg_unlocked_ioctl, - .mmap = proc_reg_mmap, - .get_unmapped_area = proc_reg_get_unmapped_area, - .open = proc_reg_open, - .release = proc_reg_release, -}; -#endif - -static void proc_put_link(void *p) -{ - unuse_pde(p); -} - -static const char *proc_get_link(struct dentry *dentry, - struct inode *inode, - struct delayed_call *done) -{ - struct proc_dir_entry *pde = PDE(inode); - if (unlikely(!use_pde(pde))) - return ERR_PTR(-EINVAL); - set_delayed_call(done, proc_put_link, pde); - return pde->data; -} - -const struct inode_operations proc_link_inode_operations = { - .readlink = generic_readlink, - .get_link = proc_get_link, -}; - -struct inode *proc_get_inode(struct super_block *sb, struct proc_dir_entry *de) -{ - struct inode *inode = new_inode_pseudo(sb); - - if (inode) { - inode->i_ino = de->low_ino; - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); - PROC_I(inode)->pde = de; - - if (is_empty_pde(de)) { - make_empty_dir_inode(inode); - return inode; - } - if (de->mode) { - inode->i_mode = de->mode; - inode->i_uid = de->uid; - inode->i_gid = de->gid; - } - if (de->size) - inode->i_size = de->size; - if (de->nlink) - set_nlink(inode, de->nlink); - WARN_ON(!de->proc_iops); - inode->i_op = de->proc_iops; - if (de->proc_fops) { - if (S_ISREG(inode->i_mode)) { -#ifdef CONFIG_COMPAT - if (!de->proc_fops->compat_ioctl) - inode->i_fop = - &proc_reg_file_ops_no_compat; - else -#endif - inode->i_fop = &proc_reg_file_ops; - } else { - inode->i_fop = de->proc_fops; - } - } - } else - pde_put(de); - return inode; -} - -int proc_fill_super(struct super_block *s, void *data, int silent) -{ - struct pid_namespace *ns = get_pid_ns(s->s_fs_info); - struct inode *root_inode; - int ret; - - if (!proc_parse_options(data, ns)) - return -EINVAL; - - /* User space would break if executables or devices appear on proc */ - s->s_iflags |= SB_I_USERNS_VISIBLE | SB_I_NOEXEC | SB_I_NODEV; - s->s_flags |= MS_NODIRATIME | MS_NOSUID | MS_NOEXEC; - s->s_blocksize = 1024; - s->s_blocksize_bits = 10; - s->s_magic = PROC_SUPER_MAGIC; - s->s_op = &proc_sops; - s->s_time_gran = 1; - - /* - * procfs isn't actually a stacking filesystem; however, there is - * too much magic going on inside it to permit stacking things on - * top of it - */ - s->s_stack_depth = FILESYSTEM_MAX_STACK_DEPTH; - - pde_get(&proc_root); - root_inode = proc_get_inode(s, &proc_root); - if (!root_inode) { - pr_err("proc_fill_super: get root inode failed\n"); - return -ENOMEM; - } - - s->s_root = d_make_root(root_inode); - if (!s->s_root) { - pr_err("proc_fill_super: allocate dentry failed\n"); - return -ENOMEM; - } - - ret = proc_setup_self(s); - if (ret) { - return ret; - } - return proc_setup_thread_self(s); -} diff --git a/src/linux/fs/proc/internal.h b/src/linux/fs/proc/internal.h deleted file mode 100644 index 5378441..0000000 --- a/src/linux/fs/proc/internal.h +++ /dev/null @@ -1,306 +0,0 @@ -/* Internal procfs definitions - * - * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include - -struct ctl_table_header; -struct mempolicy; - -/* - * This is not completely implemented yet. The idea is to - * create an in-memory tree (like the actual /proc filesystem - * tree) of these proc_dir_entries, so that we can dynamically - * add new files to /proc. - * - * parent/subdir are used for the directory structure (every /proc file has a - * parent, but "subdir" is empty for all non-directory entries). - * subdir_node is used to build the rb tree "subdir" of the parent. - */ -struct proc_dir_entry { - unsigned int low_ino; - umode_t mode; - nlink_t nlink; - kuid_t uid; - kgid_t gid; - loff_t size; - const struct inode_operations *proc_iops; - const struct file_operations *proc_fops; - struct proc_dir_entry *parent; - struct rb_root subdir; - struct rb_node subdir_node; - void *data; - atomic_t count; /* use count */ - atomic_t in_use; /* number of callers into module in progress; */ - /* negative -> it's going away RSN */ - struct completion *pde_unload_completion; - struct list_head pde_openers; /* who did ->open, but not ->release */ - spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */ - u8 namelen; - char name[]; -}; - -union proc_op { - int (*proc_get_link)(struct dentry *, struct path *); - int (*proc_show)(struct seq_file *m, - struct pid_namespace *ns, struct pid *pid, - struct task_struct *task); -}; - -struct proc_inode { - struct pid *pid; - unsigned int fd; - union proc_op op; - struct proc_dir_entry *pde; - struct ctl_table_header *sysctl; - struct ctl_table *sysctl_entry; - const struct proc_ns_operations *ns_ops; - struct inode vfs_inode; -}; - -/* - * General functions - */ -static inline struct proc_inode *PROC_I(const struct inode *inode) -{ - return container_of(inode, struct proc_inode, vfs_inode); -} - -static inline struct proc_dir_entry *PDE(const struct inode *inode) -{ - return PROC_I(inode)->pde; -} - -static inline void *__PDE_DATA(const struct inode *inode) -{ - return PDE(inode)->data; -} - -static inline struct pid *proc_pid(struct inode *inode) -{ - return PROC_I(inode)->pid; -} - -static inline struct task_struct *get_proc_task(struct inode *inode) -{ - return get_pid_task(proc_pid(inode), PIDTYPE_PID); -} - -static inline int task_dumpable(struct task_struct *task) -{ - int dumpable = 0; - struct mm_struct *mm; - - task_lock(task); - mm = task->mm; - if (mm) - dumpable = get_dumpable(mm); - task_unlock(task); - if (dumpable == SUID_DUMP_USER) - return 1; - return 0; -} - -static inline unsigned name_to_int(const struct qstr *qstr) -{ - const char *name = qstr->name; - int len = qstr->len; - unsigned n = 0; - - if (len > 1 && *name == '0') - goto out; - while (len-- > 0) { - unsigned c = *name++ - '0'; - if (c > 9) - goto out; - if (n >= (~0U-9)/10) - goto out; - n *= 10; - n += c; - } - return n; -out: - return ~0U; -} - -/* - * Offset of the first process in the /proc root directory.. - */ -#define FIRST_PROCESS_ENTRY 256 - -/* Worst case buffer size needed for holding an integer. */ -#define PROC_NUMBUF 13 - -/* - * array.c - */ -extern const struct file_operations proc_tid_children_operations; - -extern int proc_tid_stat(struct seq_file *, struct pid_namespace *, - struct pid *, struct task_struct *); -extern int proc_tgid_stat(struct seq_file *, struct pid_namespace *, - struct pid *, struct task_struct *); -extern int proc_pid_status(struct seq_file *, struct pid_namespace *, - struct pid *, struct task_struct *); -extern int proc_pid_statm(struct seq_file *, struct pid_namespace *, - struct pid *, struct task_struct *); - -/* - * base.c - */ -extern const struct dentry_operations pid_dentry_operations; -extern int pid_getattr(struct vfsmount *, struct dentry *, struct kstat *); -extern int proc_setattr(struct dentry *, struct iattr *); -extern struct inode *proc_pid_make_inode(struct super_block *, struct task_struct *); -extern int pid_revalidate(struct dentry *, unsigned int); -extern int pid_delete_dentry(const struct dentry *); -extern int proc_pid_readdir(struct file *, struct dir_context *); -extern struct dentry *proc_pid_lookup(struct inode *, struct dentry *, unsigned int); -extern loff_t mem_lseek(struct file *, loff_t, int); - -/* Lookups */ -typedef int instantiate_t(struct inode *, struct dentry *, - struct task_struct *, const void *); -extern bool proc_fill_cache(struct file *, struct dir_context *, const char *, int, - instantiate_t, struct task_struct *, const void *); - -/* - * generic.c - */ -extern struct dentry *proc_lookup(struct inode *, struct dentry *, unsigned int); -extern struct dentry *proc_lookup_de(struct proc_dir_entry *, struct inode *, - struct dentry *); -extern int proc_readdir(struct file *, struct dir_context *); -extern int proc_readdir_de(struct proc_dir_entry *, struct file *, struct dir_context *); - -static inline struct proc_dir_entry *pde_get(struct proc_dir_entry *pde) -{ - atomic_inc(&pde->count); - return pde; -} -extern void pde_put(struct proc_dir_entry *); - -static inline bool is_empty_pde(const struct proc_dir_entry *pde) -{ - return S_ISDIR(pde->mode) && !pde->proc_iops; -} -struct proc_dir_entry *proc_create_mount_point(const char *name); - -/* - * inode.c - */ -struct pde_opener { - struct file *file; - struct list_head lh; - int closing; - struct completion *c; -}; -extern const struct inode_operations proc_link_inode_operations; - -extern const struct inode_operations proc_pid_link_inode_operations; - -extern void proc_init_inodecache(void); -extern struct inode *proc_get_inode(struct super_block *, struct proc_dir_entry *); -extern int proc_fill_super(struct super_block *, void *data, int flags); -extern void proc_entry_rundown(struct proc_dir_entry *); - -/* - * proc_namespaces.c - */ -extern const struct inode_operations proc_ns_dir_inode_operations; -extern const struct file_operations proc_ns_dir_operations; - -/* - * proc_net.c - */ -extern const struct file_operations proc_net_operations; -extern const struct inode_operations proc_net_inode_operations; - -#ifdef CONFIG_NET -extern int proc_net_init(void); -#else -static inline int proc_net_init(void) { return 0; } -#endif - -/* - * proc_self.c - */ -extern int proc_setup_self(struct super_block *); - -/* - * proc_thread_self.c - */ -extern int proc_setup_thread_self(struct super_block *); -extern void proc_thread_self_init(void); - -/* - * proc_sysctl.c - */ -#ifdef CONFIG_PROC_SYSCTL -extern int proc_sys_init(void); -extern void sysctl_head_put(struct ctl_table_header *); -#else -static inline void proc_sys_init(void) { } -static inline void sysctl_head_put(struct ctl_table_header *head) { } -#endif - -/* - * proc_tty.c - */ -#ifdef CONFIG_TTY -extern void proc_tty_init(void); -#else -static inline void proc_tty_init(void) {} -#endif - -/* - * root.c - */ -extern struct proc_dir_entry proc_root; -extern int proc_parse_options(char *options, struct pid_namespace *pid); - -extern void proc_self_init(void); -extern int proc_remount(struct super_block *, int *, char *); - -/* - * task_[no]mmu.c - */ -struct proc_maps_private { - struct inode *inode; - struct task_struct *task; - struct mm_struct *mm; -#ifdef CONFIG_MMU - struct vm_area_struct *tail_vma; -#endif -#ifdef CONFIG_NUMA - struct mempolicy *task_mempolicy; -#endif -}; - -struct mm_struct *proc_mem_open(struct inode *inode, unsigned int mode); - -extern const struct file_operations proc_pid_maps_operations; -extern const struct file_operations proc_tid_maps_operations; -extern const struct file_operations proc_pid_numa_maps_operations; -extern const struct file_operations proc_tid_numa_maps_operations; -extern const struct file_operations proc_pid_smaps_operations; -extern const struct file_operations proc_tid_smaps_operations; -extern const struct file_operations proc_clear_refs_operations; -extern const struct file_operations proc_pagemap_operations; - -extern unsigned long task_vsize(struct mm_struct *); -extern unsigned long task_statm(struct mm_struct *, - unsigned long *, unsigned long *, - unsigned long *, unsigned long *); -extern void task_mem(struct seq_file *, struct mm_struct *); diff --git a/src/linux/fs/proc/interrupts.c b/src/linux/fs/proc/interrupts.c deleted file mode 100644 index a352d57..0000000 --- a/src/linux/fs/proc/interrupts.c +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include -#include -#include -#include - -/* - * /proc/interrupts - */ -static void *int_seq_start(struct seq_file *f, loff_t *pos) -{ - return (*pos <= nr_irqs) ? pos : NULL; -} - -static void *int_seq_next(struct seq_file *f, void *v, loff_t *pos) -{ - (*pos)++; - if (*pos > nr_irqs) - return NULL; - return pos; -} - -static void int_seq_stop(struct seq_file *f, void *v) -{ - /* Nothing to do */ -} - -static const struct seq_operations int_seq_ops = { - .start = int_seq_start, - .next = int_seq_next, - .stop = int_seq_stop, - .show = show_interrupts -}; - -static int interrupts_open(struct inode *inode, struct file *filp) -{ - return seq_open(filp, &int_seq_ops); -} - -static const struct file_operations proc_interrupts_operations = { - .open = interrupts_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int __init proc_interrupts_init(void) -{ - proc_create("interrupts", 0, NULL, &proc_interrupts_operations); - return 0; -} -fs_initcall(proc_interrupts_init); diff --git a/src/linux/fs/proc/kmsg.c b/src/linux/fs/proc/kmsg.c deleted file mode 100644 index 05f8dcd..0000000 --- a/src/linux/fs/proc/kmsg.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * linux/fs/proc/kmsg.c - * - * Copyright (C) 1992 by Linus Torvalds - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -extern wait_queue_head_t log_wait; - -static int kmsg_open(struct inode * inode, struct file * file) -{ - return do_syslog(SYSLOG_ACTION_OPEN, NULL, 0, SYSLOG_FROM_PROC); -} - -static int kmsg_release(struct inode * inode, struct file * file) -{ - (void) do_syslog(SYSLOG_ACTION_CLOSE, NULL, 0, SYSLOG_FROM_PROC); - return 0; -} - -static ssize_t kmsg_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - if ((file->f_flags & O_NONBLOCK) && - !do_syslog(SYSLOG_ACTION_SIZE_UNREAD, NULL, 0, SYSLOG_FROM_PROC)) - return -EAGAIN; - return do_syslog(SYSLOG_ACTION_READ, buf, count, SYSLOG_FROM_PROC); -} - -static unsigned int kmsg_poll(struct file *file, poll_table *wait) -{ - poll_wait(file, &log_wait, wait); - if (do_syslog(SYSLOG_ACTION_SIZE_UNREAD, NULL, 0, SYSLOG_FROM_PROC)) - return POLLIN | POLLRDNORM; - return 0; -} - - -static const struct file_operations proc_kmsg_operations = { - .read = kmsg_read, - .poll = kmsg_poll, - .open = kmsg_open, - .release = kmsg_release, - .llseek = generic_file_llseek, -}; - -static int __init proc_kmsg_init(void) -{ - proc_create("kmsg", S_IRUSR, NULL, &proc_kmsg_operations); - return 0; -} -fs_initcall(proc_kmsg_init); diff --git a/src/linux/fs/proc/loadavg.c b/src/linux/fs/proc/loadavg.c deleted file mode 100644 index aec66e6..0000000 --- a/src/linux/fs/proc/loadavg.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#define LOAD_INT(x) ((x) >> FSHIFT) -#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) - -static int loadavg_proc_show(struct seq_file *m, void *v) -{ - unsigned long avnrun[3]; - - get_avenrun(avnrun, FIXED_1/200, 0); - - seq_printf(m, "%lu.%02lu %lu.%02lu %lu.%02lu %ld/%d %d\n", - LOAD_INT(avnrun[0]), LOAD_FRAC(avnrun[0]), - LOAD_INT(avnrun[1]), LOAD_FRAC(avnrun[1]), - LOAD_INT(avnrun[2]), LOAD_FRAC(avnrun[2]), - nr_running(), nr_threads, - task_active_pid_ns(current)->last_pid); - return 0; -} - -static int loadavg_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, loadavg_proc_show, NULL); -} - -static const struct file_operations loadavg_proc_fops = { - .open = loadavg_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init proc_loadavg_init(void) -{ - proc_create("loadavg", 0, NULL, &loadavg_proc_fops); - return 0; -} -fs_initcall(proc_loadavg_init); diff --git a/src/linux/fs/proc/meminfo.c b/src/linux/fs/proc/meminfo.c deleted file mode 100644 index 8a42849..0000000 --- a/src/linux/fs/proc/meminfo.c +++ /dev/null @@ -1,181 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_CMA -#include -#endif -#include -#include -#include "internal.h" - -void __attribute__((weak)) arch_report_meminfo(struct seq_file *m) -{ -} - -static void show_val_kb(struct seq_file *m, const char *s, unsigned long num) -{ - char v[32]; - static const char blanks[7] = {' ', ' ', ' ', ' ',' ', ' ', ' '}; - int len; - - len = num_to_str(v, sizeof(v), num << (PAGE_SHIFT - 10)); - - seq_write(m, s, 16); - - if (len > 0) { - if (len < 8) - seq_write(m, blanks, 8 - len); - - seq_write(m, v, len); - } - seq_write(m, " kB\n", 4); -} - -static int meminfo_proc_show(struct seq_file *m, void *v) -{ - struct sysinfo i; - unsigned long committed; - long cached; - long available; - unsigned long pages[NR_LRU_LISTS]; - int lru; - - si_meminfo(&i); - si_swapinfo(&i); - committed = percpu_counter_read_positive(&vm_committed_as); - - cached = global_node_page_state(NR_FILE_PAGES) - - total_swapcache_pages() - i.bufferram; - if (cached < 0) - cached = 0; - - for (lru = LRU_BASE; lru < NR_LRU_LISTS; lru++) - pages[lru] = global_node_page_state(NR_LRU_BASE + lru); - - available = si_mem_available(); - - show_val_kb(m, "MemTotal: ", i.totalram); - show_val_kb(m, "MemFree: ", i.freeram); - show_val_kb(m, "MemAvailable: ", available); - show_val_kb(m, "Buffers: ", i.bufferram); - show_val_kb(m, "Cached: ", cached); - show_val_kb(m, "SwapCached: ", total_swapcache_pages()); - show_val_kb(m, "Active: ", pages[LRU_ACTIVE_ANON] + - pages[LRU_ACTIVE_FILE]); - show_val_kb(m, "Inactive: ", pages[LRU_INACTIVE_ANON] + - pages[LRU_INACTIVE_FILE]); - show_val_kb(m, "Active(anon): ", pages[LRU_ACTIVE_ANON]); - show_val_kb(m, "Inactive(anon): ", pages[LRU_INACTIVE_ANON]); - show_val_kb(m, "Active(file): ", pages[LRU_ACTIVE_FILE]); - show_val_kb(m, "Inactive(file): ", pages[LRU_INACTIVE_FILE]); - show_val_kb(m, "Unevictable: ", pages[LRU_UNEVICTABLE]); - show_val_kb(m, "Mlocked: ", global_page_state(NR_MLOCK)); - -#ifdef CONFIG_HIGHMEM - show_val_kb(m, "HighTotal: ", i.totalhigh); - show_val_kb(m, "HighFree: ", i.freehigh); - show_val_kb(m, "LowTotal: ", i.totalram - i.totalhigh); - show_val_kb(m, "LowFree: ", i.freeram - i.freehigh); -#endif - -#ifndef CONFIG_MMU - show_val_kb(m, "MmapCopy: ", - (unsigned long)atomic_long_read(&mmap_pages_allocated)); -#endif - - show_val_kb(m, "SwapTotal: ", i.totalswap); - show_val_kb(m, "SwapFree: ", i.freeswap); - show_val_kb(m, "Dirty: ", - global_node_page_state(NR_FILE_DIRTY)); - show_val_kb(m, "Writeback: ", - global_node_page_state(NR_WRITEBACK)); - show_val_kb(m, "AnonPages: ", - global_node_page_state(NR_ANON_MAPPED)); - show_val_kb(m, "Mapped: ", - global_node_page_state(NR_FILE_MAPPED)); - show_val_kb(m, "Shmem: ", i.sharedram); - show_val_kb(m, "Slab: ", - global_page_state(NR_SLAB_RECLAIMABLE) + - global_page_state(NR_SLAB_UNRECLAIMABLE)); - - show_val_kb(m, "SReclaimable: ", - global_page_state(NR_SLAB_RECLAIMABLE)); - show_val_kb(m, "SUnreclaim: ", - global_page_state(NR_SLAB_UNRECLAIMABLE)); - seq_printf(m, "KernelStack: %8lu kB\n", - global_page_state(NR_KERNEL_STACK_KB)); - show_val_kb(m, "PageTables: ", - global_page_state(NR_PAGETABLE)); -#ifdef CONFIG_QUICKLIST - show_val_kb(m, "Quicklists: ", quicklist_total_size()); -#endif - - show_val_kb(m, "NFS_Unstable: ", - global_node_page_state(NR_UNSTABLE_NFS)); - show_val_kb(m, "Bounce: ", - global_page_state(NR_BOUNCE)); - show_val_kb(m, "WritebackTmp: ", - global_node_page_state(NR_WRITEBACK_TEMP)); - show_val_kb(m, "CommitLimit: ", vm_commit_limit()); - show_val_kb(m, "Committed_AS: ", committed); - seq_printf(m, "VmallocTotal: %8lu kB\n", - (unsigned long)VMALLOC_TOTAL >> 10); - show_val_kb(m, "VmallocUsed: ", 0ul); - show_val_kb(m, "VmallocChunk: ", 0ul); - -#ifdef CONFIG_MEMORY_FAILURE - seq_printf(m, "HardwareCorrupted: %5lu kB\n", - atomic_long_read(&num_poisoned_pages) << (PAGE_SHIFT - 10)); -#endif - -#ifdef CONFIG_TRANSPARENT_HUGEPAGE - show_val_kb(m, "AnonHugePages: ", - global_node_page_state(NR_ANON_THPS) * HPAGE_PMD_NR); - show_val_kb(m, "ShmemHugePages: ", - global_node_page_state(NR_SHMEM_THPS) * HPAGE_PMD_NR); - show_val_kb(m, "ShmemPmdMapped: ", - global_node_page_state(NR_SHMEM_PMDMAPPED) * HPAGE_PMD_NR); -#endif - -#ifdef CONFIG_CMA - show_val_kb(m, "CmaTotal: ", totalcma_pages); - show_val_kb(m, "CmaFree: ", - global_page_state(NR_FREE_CMA_PAGES)); -#endif - - hugetlb_report_meminfo(m); - - arch_report_meminfo(m); - - return 0; -} - -static int meminfo_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, meminfo_proc_show, NULL); -} - -static const struct file_operations meminfo_proc_fops = { - .open = meminfo_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init proc_meminfo_init(void) -{ - proc_create("meminfo", 0, NULL, &meminfo_proc_fops); - return 0; -} -fs_initcall(proc_meminfo_init); diff --git a/src/linux/fs/proc/namespaces.c b/src/linux/fs/proc/namespaces.c deleted file mode 100644 index 51b8b0a..0000000 --- a/src/linux/fs/proc/namespaces.c +++ /dev/null @@ -1,180 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - - -static const struct proc_ns_operations *ns_entries[] = { -#ifdef CONFIG_NET_NS - &netns_operations, -#endif -#ifdef CONFIG_UTS_NS - &utsns_operations, -#endif -#ifdef CONFIG_IPC_NS - &ipcns_operations, -#endif -#ifdef CONFIG_PID_NS - &pidns_operations, -#endif -#ifdef CONFIG_USER_NS - &userns_operations, -#endif - &mntns_operations, -#ifdef CONFIG_CGROUPS - &cgroupns_operations, -#endif -}; - -static const char *proc_ns_get_link(struct dentry *dentry, - struct inode *inode, - struct delayed_call *done) -{ - const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops; - struct task_struct *task; - struct path ns_path; - void *error = ERR_PTR(-EACCES); - - if (!dentry) - return ERR_PTR(-ECHILD); - - task = get_proc_task(inode); - if (!task) - return error; - - if (ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) { - error = ns_get_path(&ns_path, task, ns_ops); - if (!error) - nd_jump_link(&ns_path); - } - put_task_struct(task); - return error; -} - -static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflen) -{ - struct inode *inode = d_inode(dentry); - const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops; - struct task_struct *task; - char name[50]; - int res = -EACCES; - - task = get_proc_task(inode); - if (!task) - return res; - - if (ptrace_may_access(task, PTRACE_MODE_READ_FSCREDS)) { - res = ns_get_name(name, sizeof(name), task, ns_ops); - if (res >= 0) - res = readlink_copy(buffer, buflen, name); - } - put_task_struct(task); - return res; -} - -static const struct inode_operations proc_ns_link_inode_operations = { - .readlink = proc_ns_readlink, - .get_link = proc_ns_get_link, - .setattr = proc_setattr, -}; - -static int proc_ns_instantiate(struct inode *dir, - struct dentry *dentry, struct task_struct *task, const void *ptr) -{ - const struct proc_ns_operations *ns_ops = ptr; - struct inode *inode; - struct proc_inode *ei; - - inode = proc_pid_make_inode(dir->i_sb, task); - if (!inode) - goto out; - - ei = PROC_I(inode); - inode->i_mode = S_IFLNK|S_IRWXUGO; - inode->i_op = &proc_ns_link_inode_operations; - ei->ns_ops = ns_ops; - - d_set_d_op(dentry, &pid_dentry_operations); - d_add(dentry, inode); - /* Close the race of the process dying before we return the dentry */ - if (pid_revalidate(dentry, 0)) - return 0; -out: - return -ENOENT; -} - -static int proc_ns_dir_readdir(struct file *file, struct dir_context *ctx) -{ - struct task_struct *task = get_proc_task(file_inode(file)); - const struct proc_ns_operations **entry, **last; - - if (!task) - return -ENOENT; - - if (!dir_emit_dots(file, ctx)) - goto out; - if (ctx->pos >= 2 + ARRAY_SIZE(ns_entries)) - goto out; - entry = ns_entries + (ctx->pos - 2); - last = &ns_entries[ARRAY_SIZE(ns_entries) - 1]; - while (entry <= last) { - const struct proc_ns_operations *ops = *entry; - if (!proc_fill_cache(file, ctx, ops->name, strlen(ops->name), - proc_ns_instantiate, task, ops)) - break; - ctx->pos++; - entry++; - } -out: - put_task_struct(task); - return 0; -} - -const struct file_operations proc_ns_dir_operations = { - .read = generic_read_dir, - .iterate_shared = proc_ns_dir_readdir, - .llseek = generic_file_llseek, -}; - -static struct dentry *proc_ns_dir_lookup(struct inode *dir, - struct dentry *dentry, unsigned int flags) -{ - int error; - struct task_struct *task = get_proc_task(dir); - const struct proc_ns_operations **entry, **last; - unsigned int len = dentry->d_name.len; - - error = -ENOENT; - - if (!task) - goto out_no_task; - - last = &ns_entries[ARRAY_SIZE(ns_entries)]; - for (entry = ns_entries; entry < last; entry++) { - if (strlen((*entry)->name) != len) - continue; - if (!memcmp(dentry->d_name.name, (*entry)->name, len)) - break; - } - if (entry == last) - goto out; - - error = proc_ns_instantiate(dir, dentry, task, *entry); -out: - put_task_struct(task); -out_no_task: - return ERR_PTR(error); -} - -const struct inode_operations proc_ns_dir_inode_operations = { - .lookup = proc_ns_dir_lookup, - .getattr = pid_getattr, - .setattr = proc_setattr, -}; diff --git a/src/linux/fs/proc/nommu.c b/src/linux/fs/proc/nommu.c deleted file mode 100644 index f8595e8..0000000 --- a/src/linux/fs/proc/nommu.c +++ /dev/null @@ -1,134 +0,0 @@ -/* nommu.c: mmu-less memory info files - * - * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -/* - * display a single region to a sequenced file - */ -static int nommu_region_show(struct seq_file *m, struct vm_region *region) -{ - unsigned long ino = 0; - struct file *file; - dev_t dev = 0; - int flags; - - flags = region->vm_flags; - file = region->vm_file; - - if (file) { - struct inode *inode = file_inode(region->vm_file); - dev = inode->i_sb->s_dev; - ino = inode->i_ino; - } - - seq_setwidth(m, 25 + sizeof(void *) * 6 - 1); - seq_printf(m, - "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ", - region->vm_start, - region->vm_end, - flags & VM_READ ? 'r' : '-', - flags & VM_WRITE ? 'w' : '-', - flags & VM_EXEC ? 'x' : '-', - flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p', - ((loff_t)region->vm_pgoff) << PAGE_SHIFT, - MAJOR(dev), MINOR(dev), ino); - - if (file) { - seq_pad(m, ' '); - seq_file_path(m, file, ""); - } - - seq_putc(m, '\n'); - return 0; -} - -/* - * display a list of all the REGIONs the kernel knows about - * - nommu kernels have a single flat list - */ -static int nommu_region_list_show(struct seq_file *m, void *_p) -{ - struct rb_node *p = _p; - - return nommu_region_show(m, rb_entry(p, struct vm_region, vm_rb)); -} - -static void *nommu_region_list_start(struct seq_file *m, loff_t *_pos) -{ - struct rb_node *p; - loff_t pos = *_pos; - - down_read(&nommu_region_sem); - - for (p = rb_first(&nommu_region_tree); p; p = rb_next(p)) - if (pos-- == 0) - return p; - return NULL; -} - -static void nommu_region_list_stop(struct seq_file *m, void *v) -{ - up_read(&nommu_region_sem); -} - -static void *nommu_region_list_next(struct seq_file *m, void *v, loff_t *pos) -{ - (*pos)++; - return rb_next((struct rb_node *) v); -} - -static const struct seq_operations proc_nommu_region_list_seqop = { - .start = nommu_region_list_start, - .next = nommu_region_list_next, - .stop = nommu_region_list_stop, - .show = nommu_region_list_show -}; - -static int proc_nommu_region_list_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &proc_nommu_region_list_seqop); -} - -static const struct file_operations proc_nommu_region_list_operations = { - .open = proc_nommu_region_list_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int __init proc_nommu_init(void) -{ - proc_create("maps", S_IRUGO, NULL, &proc_nommu_region_list_operations); - return 0; -} - -fs_initcall(proc_nommu_init); diff --git a/src/linux/fs/proc/proc_net.c b/src/linux/fs/proc/proc_net.c deleted file mode 100644 index 7ae6b1d..0000000 --- a/src/linux/fs/proc/proc_net.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * linux/fs/proc/net.c - * - * Copyright (C) 2007 - * - * Author: Eric Biederman - * - * proc net directory handling functions - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -static inline struct net *PDE_NET(struct proc_dir_entry *pde) -{ - return pde->parent->data; -} - -static struct net *get_proc_net(const struct inode *inode) -{ - return maybe_get_net(PDE_NET(PDE(inode))); -} - -int seq_open_net(struct inode *ino, struct file *f, - const struct seq_operations *ops, int size) -{ - struct net *net; - struct seq_net_private *p; - - BUG_ON(size < sizeof(*p)); - - net = get_proc_net(ino); - if (net == NULL) - return -ENXIO; - - p = __seq_open_private(f, ops, size); - if (p == NULL) { - put_net(net); - return -ENOMEM; - } -#ifdef CONFIG_NET_NS - p->net = net; -#endif - return 0; -} -EXPORT_SYMBOL_GPL(seq_open_net); - -int single_open_net(struct inode *inode, struct file *file, - int (*show)(struct seq_file *, void *)) -{ - int err; - struct net *net; - - err = -ENXIO; - net = get_proc_net(inode); - if (net == NULL) - goto err_net; - - err = single_open(file, show, net); - if (err < 0) - goto err_open; - - return 0; - -err_open: - put_net(net); -err_net: - return err; -} -EXPORT_SYMBOL_GPL(single_open_net); - -int seq_release_net(struct inode *ino, struct file *f) -{ - struct seq_file *seq; - - seq = f->private_data; - - put_net(seq_file_net(seq)); - seq_release_private(ino, f); - return 0; -} -EXPORT_SYMBOL_GPL(seq_release_net); - -int single_release_net(struct inode *ino, struct file *f) -{ - struct seq_file *seq = f->private_data; - put_net(seq->private); - return single_release(ino, f); -} -EXPORT_SYMBOL_GPL(single_release_net); - -static struct net *get_proc_task_net(struct inode *dir) -{ - struct task_struct *task; - struct nsproxy *ns; - struct net *net = NULL; - - rcu_read_lock(); - task = pid_task(proc_pid(dir), PIDTYPE_PID); - if (task != NULL) { - task_lock(task); - ns = task->nsproxy; - if (ns != NULL) - net = get_net(ns->net_ns); - task_unlock(task); - } - rcu_read_unlock(); - - return net; -} - -static struct dentry *proc_tgid_net_lookup(struct inode *dir, - struct dentry *dentry, unsigned int flags) -{ - struct dentry *de; - struct net *net; - - de = ERR_PTR(-ENOENT); - net = get_proc_task_net(dir); - if (net != NULL) { - de = proc_lookup_de(net->proc_net, dir, dentry); - put_net(net); - } - return de; -} - -static int proc_tgid_net_getattr(struct vfsmount *mnt, struct dentry *dentry, - struct kstat *stat) -{ - struct inode *inode = d_inode(dentry); - struct net *net; - - net = get_proc_task_net(inode); - - generic_fillattr(inode, stat); - - if (net != NULL) { - stat->nlink = net->proc_net->nlink; - put_net(net); - } - - return 0; -} - -const struct inode_operations proc_net_inode_operations = { - .lookup = proc_tgid_net_lookup, - .getattr = proc_tgid_net_getattr, -}; - -static int proc_tgid_net_readdir(struct file *file, struct dir_context *ctx) -{ - int ret; - struct net *net; - - ret = -EINVAL; - net = get_proc_task_net(file_inode(file)); - if (net != NULL) { - ret = proc_readdir_de(net->proc_net, file, ctx); - put_net(net); - } - return ret; -} - -const struct file_operations proc_net_operations = { - .llseek = generic_file_llseek, - .read = generic_read_dir, - .iterate_shared = proc_tgid_net_readdir, -}; - -static __net_init int proc_net_ns_init(struct net *net) -{ - struct proc_dir_entry *netd, *net_statd; - kuid_t uid; - kgid_t gid; - int err; - - err = -ENOMEM; - netd = kzalloc(sizeof(*netd) + 4, GFP_KERNEL); - if (!netd) - goto out; - - netd->subdir = RB_ROOT; - netd->data = net; - netd->nlink = 2; - netd->namelen = 3; - netd->parent = &proc_root; - memcpy(netd->name, "net", 4); - - uid = make_kuid(net->user_ns, 0); - if (!uid_valid(uid)) - uid = netd->uid; - - gid = make_kgid(net->user_ns, 0); - if (!gid_valid(gid)) - gid = netd->gid; - - proc_set_user(netd, uid, gid); - - err = -EEXIST; - net_statd = proc_net_mkdir(net, "stat", netd); - if (!net_statd) - goto free_net; - - net->proc_net = netd; - net->proc_net_stat = net_statd; - return 0; - -free_net: - kfree(netd); -out: - return err; -} - -static __net_exit void proc_net_ns_exit(struct net *net) -{ - remove_proc_entry("stat", net->proc_net); - kfree(net->proc_net); -} - -static struct pernet_operations __net_initdata proc_net_ns_ops = { - .init = proc_net_ns_init, - .exit = proc_net_ns_exit, -}; - -int __init proc_net_init(void) -{ - proc_symlink("net", NULL, "self/net"); - - return register_pernet_subsys(&proc_net_ns_ops); -} diff --git a/src/linux/fs/proc/proc_sysctl.c b/src/linux/fs/proc/proc_sysctl.c deleted file mode 100644 index 55313d9..0000000 --- a/src/linux/fs/proc/proc_sysctl.c +++ /dev/null @@ -1,1625 +0,0 @@ -/* - * /proc/sys support - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -static const struct dentry_operations proc_sys_dentry_operations; -static const struct file_operations proc_sys_file_operations; -static const struct inode_operations proc_sys_inode_operations; -static const struct file_operations proc_sys_dir_file_operations; -static const struct inode_operations proc_sys_dir_operations; - -/* Support for permanently empty directories */ - -struct ctl_table sysctl_mount_point[] = { - { } -}; - -static bool is_empty_dir(struct ctl_table_header *head) -{ - return head->ctl_table[0].child == sysctl_mount_point; -} - -static void set_empty_dir(struct ctl_dir *dir) -{ - dir->header.ctl_table[0].child = sysctl_mount_point; -} - -static void clear_empty_dir(struct ctl_dir *dir) - -{ - dir->header.ctl_table[0].child = NULL; -} - -void proc_sys_poll_notify(struct ctl_table_poll *poll) -{ - if (!poll) - return; - - atomic_inc(&poll->event); - wake_up_interruptible(&poll->wait); -} - -static struct ctl_table root_table[] = { - { - .procname = "", - .mode = S_IFDIR|S_IRUGO|S_IXUGO, - }, - { } -}; -static struct ctl_table_root sysctl_table_root = { - .default_set.dir.header = { - {{.count = 1, - .nreg = 1, - .ctl_table = root_table }}, - .ctl_table_arg = root_table, - .root = &sysctl_table_root, - .set = &sysctl_table_root.default_set, - }, -}; - -static DEFINE_SPINLOCK(sysctl_lock); - -static void drop_sysctl_table(struct ctl_table_header *header); -static int sysctl_follow_link(struct ctl_table_header **phead, - struct ctl_table **pentry); -static int insert_links(struct ctl_table_header *head); -static void put_links(struct ctl_table_header *header); - -static void sysctl_print_dir(struct ctl_dir *dir) -{ - if (dir->header.parent) - sysctl_print_dir(dir->header.parent); - pr_cont("%s/", dir->header.ctl_table[0].procname); -} - -static int namecmp(const char *name1, int len1, const char *name2, int len2) -{ - int minlen; - int cmp; - - minlen = len1; - if (minlen > len2) - minlen = len2; - - cmp = memcmp(name1, name2, minlen); - if (cmp == 0) - cmp = len1 - len2; - return cmp; -} - -/* Called under sysctl_lock */ -static struct ctl_table *find_entry(struct ctl_table_header **phead, - struct ctl_dir *dir, const char *name, int namelen) -{ - struct ctl_table_header *head; - struct ctl_table *entry; - struct rb_node *node = dir->root.rb_node; - - while (node) - { - struct ctl_node *ctl_node; - const char *procname; - int cmp; - - ctl_node = rb_entry(node, struct ctl_node, node); - head = ctl_node->header; - entry = &head->ctl_table[ctl_node - head->node]; - procname = entry->procname; - - cmp = namecmp(name, namelen, procname, strlen(procname)); - if (cmp < 0) - node = node->rb_left; - else if (cmp > 0) - node = node->rb_right; - else { - *phead = head; - return entry; - } - } - return NULL; -} - -static int insert_entry(struct ctl_table_header *head, struct ctl_table *entry) -{ - struct rb_node *node = &head->node[entry - head->ctl_table].node; - struct rb_node **p = &head->parent->root.rb_node; - struct rb_node *parent = NULL; - const char *name = entry->procname; - int namelen = strlen(name); - - while (*p) { - struct ctl_table_header *parent_head; - struct ctl_table *parent_entry; - struct ctl_node *parent_node; - const char *parent_name; - int cmp; - - parent = *p; - parent_node = rb_entry(parent, struct ctl_node, node); - parent_head = parent_node->header; - parent_entry = &parent_head->ctl_table[parent_node - parent_head->node]; - parent_name = parent_entry->procname; - - cmp = namecmp(name, namelen, parent_name, strlen(parent_name)); - if (cmp < 0) - p = &(*p)->rb_left; - else if (cmp > 0) - p = &(*p)->rb_right; - else { - pr_err("sysctl duplicate entry: "); - sysctl_print_dir(head->parent); - pr_cont("/%s\n", entry->procname); - return -EEXIST; - } - } - - rb_link_node(node, parent, p); - rb_insert_color(node, &head->parent->root); - return 0; -} - -static void erase_entry(struct ctl_table_header *head, struct ctl_table *entry) -{ - struct rb_node *node = &head->node[entry - head->ctl_table].node; - - rb_erase(node, &head->parent->root); -} - -static void init_header(struct ctl_table_header *head, - struct ctl_table_root *root, struct ctl_table_set *set, - struct ctl_node *node, struct ctl_table *table) -{ - head->ctl_table = table; - head->ctl_table_arg = table; - head->used = 0; - head->count = 1; - head->nreg = 1; - head->unregistering = NULL; - head->root = root; - head->set = set; - head->parent = NULL; - head->node = node; - if (node) { - struct ctl_table *entry; - for (entry = table; entry->procname; entry++, node++) - node->header = head; - } -} - -static void erase_header(struct ctl_table_header *head) -{ - struct ctl_table *entry; - for (entry = head->ctl_table; entry->procname; entry++) - erase_entry(head, entry); -} - -static int insert_header(struct ctl_dir *dir, struct ctl_table_header *header) -{ - struct ctl_table *entry; - int err; - - /* Is this a permanently empty directory? */ - if (is_empty_dir(&dir->header)) - return -EROFS; - - /* Am I creating a permanently empty directory? */ - if (header->ctl_table == sysctl_mount_point) { - if (!RB_EMPTY_ROOT(&dir->root)) - return -EINVAL; - set_empty_dir(dir); - } - - dir->header.nreg++; - header->parent = dir; - err = insert_links(header); - if (err) - goto fail_links; - for (entry = header->ctl_table; entry->procname; entry++) { - err = insert_entry(header, entry); - if (err) - goto fail; - } - return 0; -fail: - erase_header(header); - put_links(header); -fail_links: - if (header->ctl_table == sysctl_mount_point) - clear_empty_dir(dir); - header->parent = NULL; - drop_sysctl_table(&dir->header); - return err; -} - -/* called under sysctl_lock */ -static int use_table(struct ctl_table_header *p) -{ - if (unlikely(p->unregistering)) - return 0; - p->used++; - return 1; -} - -/* called under sysctl_lock */ -static void unuse_table(struct ctl_table_header *p) -{ - if (!--p->used) - if (unlikely(p->unregistering)) - complete(p->unregistering); -} - -/* called under sysctl_lock, will reacquire if has to wait */ -static void start_unregistering(struct ctl_table_header *p) -{ - /* - * if p->used is 0, nobody will ever touch that entry again; - * we'll eliminate all paths to it before dropping sysctl_lock - */ - if (unlikely(p->used)) { - struct completion wait; - init_completion(&wait); - p->unregistering = &wait; - spin_unlock(&sysctl_lock); - wait_for_completion(&wait); - spin_lock(&sysctl_lock); - } else { - /* anything non-NULL; we'll never dereference it */ - p->unregistering = ERR_PTR(-EINVAL); - } - /* - * do not remove from the list until nobody holds it; walking the - * list in do_sysctl() relies on that. - */ - erase_header(p); -} - -static void sysctl_head_get(struct ctl_table_header *head) -{ - spin_lock(&sysctl_lock); - head->count++; - spin_unlock(&sysctl_lock); -} - -void sysctl_head_put(struct ctl_table_header *head) -{ - spin_lock(&sysctl_lock); - if (!--head->count) - kfree_rcu(head, rcu); - spin_unlock(&sysctl_lock); -} - -static struct ctl_table_header *sysctl_head_grab(struct ctl_table_header *head) -{ - BUG_ON(!head); - spin_lock(&sysctl_lock); - if (!use_table(head)) - head = ERR_PTR(-ENOENT); - spin_unlock(&sysctl_lock); - return head; -} - -static void sysctl_head_finish(struct ctl_table_header *head) -{ - if (!head) - return; - spin_lock(&sysctl_lock); - unuse_table(head); - spin_unlock(&sysctl_lock); -} - -static struct ctl_table_set * -lookup_header_set(struct ctl_table_root *root) -{ - struct ctl_table_set *set = &root->default_set; - if (root->lookup) - set = root->lookup(root); - return set; -} - -static struct ctl_table *lookup_entry(struct ctl_table_header **phead, - struct ctl_dir *dir, - const char *name, int namelen) -{ - struct ctl_table_header *head; - struct ctl_table *entry; - - spin_lock(&sysctl_lock); - entry = find_entry(&head, dir, name, namelen); - if (entry && use_table(head)) - *phead = head; - else - entry = NULL; - spin_unlock(&sysctl_lock); - return entry; -} - -static struct ctl_node *first_usable_entry(struct rb_node *node) -{ - struct ctl_node *ctl_node; - - for (;node; node = rb_next(node)) { - ctl_node = rb_entry(node, struct ctl_node, node); - if (use_table(ctl_node->header)) - return ctl_node; - } - return NULL; -} - -static void first_entry(struct ctl_dir *dir, - struct ctl_table_header **phead, struct ctl_table **pentry) -{ - struct ctl_table_header *head = NULL; - struct ctl_table *entry = NULL; - struct ctl_node *ctl_node; - - spin_lock(&sysctl_lock); - ctl_node = first_usable_entry(rb_first(&dir->root)); - spin_unlock(&sysctl_lock); - if (ctl_node) { - head = ctl_node->header; - entry = &head->ctl_table[ctl_node - head->node]; - } - *phead = head; - *pentry = entry; -} - -static void next_entry(struct ctl_table_header **phead, struct ctl_table **pentry) -{ - struct ctl_table_header *head = *phead; - struct ctl_table *entry = *pentry; - struct ctl_node *ctl_node = &head->node[entry - head->ctl_table]; - - spin_lock(&sysctl_lock); - unuse_table(head); - - ctl_node = first_usable_entry(rb_next(&ctl_node->node)); - spin_unlock(&sysctl_lock); - head = NULL; - if (ctl_node) { - head = ctl_node->header; - entry = &head->ctl_table[ctl_node - head->node]; - } - *phead = head; - *pentry = entry; -} - -void register_sysctl_root(struct ctl_table_root *root) -{ -} - -/* - * sysctl_perm does NOT grant the superuser all rights automatically, because - * some sysctl variables are readonly even to root. - */ - -static int test_perm(int mode, int op) -{ - if (uid_eq(current_euid(), GLOBAL_ROOT_UID)) - mode >>= 6; - else if (in_egroup_p(GLOBAL_ROOT_GID)) - mode >>= 3; - if ((op & ~mode & (MAY_READ|MAY_WRITE|MAY_EXEC)) == 0) - return 0; - return -EACCES; -} - -static int sysctl_perm(struct ctl_table_header *head, struct ctl_table *table, int op) -{ - struct ctl_table_root *root = head->root; - int mode; - - if (root->permissions) - mode = root->permissions(head, table); - else - mode = table->mode; - - return test_perm(mode, op); -} - -static struct inode *proc_sys_make_inode(struct super_block *sb, - struct ctl_table_header *head, struct ctl_table *table) -{ - struct ctl_table_root *root = head->root; - struct inode *inode; - struct proc_inode *ei; - - inode = new_inode(sb); - if (!inode) - goto out; - - inode->i_ino = get_next_ino(); - - sysctl_head_get(head); - ei = PROC_I(inode); - ei->sysctl = head; - ei->sysctl_entry = table; - - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); - inode->i_mode = table->mode; - if (!S_ISDIR(table->mode)) { - inode->i_mode |= S_IFREG; - inode->i_op = &proc_sys_inode_operations; - inode->i_fop = &proc_sys_file_operations; - } else { - inode->i_mode |= S_IFDIR; - inode->i_op = &proc_sys_dir_operations; - inode->i_fop = &proc_sys_dir_file_operations; - if (is_empty_dir(head)) - make_empty_dir_inode(inode); - } - - if (root->set_ownership) - root->set_ownership(head, table, &inode->i_uid, &inode->i_gid); - -out: - return inode; -} - -static struct ctl_table_header *grab_header(struct inode *inode) -{ - struct ctl_table_header *head = PROC_I(inode)->sysctl; - if (!head) - head = &sysctl_table_root.default_set.dir.header; - return sysctl_head_grab(head); -} - -static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry, - unsigned int flags) -{ - struct ctl_table_header *head = grab_header(dir); - struct ctl_table_header *h = NULL; - const struct qstr *name = &dentry->d_name; - struct ctl_table *p; - struct inode *inode; - struct dentry *err = ERR_PTR(-ENOENT); - struct ctl_dir *ctl_dir; - int ret; - - if (IS_ERR(head)) - return ERR_CAST(head); - - ctl_dir = container_of(head, struct ctl_dir, header); - - p = lookup_entry(&h, ctl_dir, name->name, name->len); - if (!p) - goto out; - - if (S_ISLNK(p->mode)) { - ret = sysctl_follow_link(&h, &p); - err = ERR_PTR(ret); - if (ret) - goto out; - } - - err = ERR_PTR(-ENOMEM); - inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p); - if (!inode) - goto out; - - err = NULL; - d_set_d_op(dentry, &proc_sys_dentry_operations); - d_add(dentry, inode); - -out: - if (h) - sysctl_head_finish(h); - sysctl_head_finish(head); - return err; -} - -static ssize_t proc_sys_call_handler(struct file *filp, void __user *buf, - size_t count, loff_t *ppos, int write) -{ - struct inode *inode = file_inode(filp); - struct ctl_table_header *head = grab_header(inode); - struct ctl_table *table = PROC_I(inode)->sysctl_entry; - ssize_t error; - size_t res; - - if (IS_ERR(head)) - return PTR_ERR(head); - - /* - * At this point we know that the sysctl was not unregistered - * and won't be until we finish. - */ - error = -EPERM; - if (sysctl_perm(head, table, write ? MAY_WRITE : MAY_READ)) - goto out; - - /* if that can happen at all, it should be -EINVAL, not -EISDIR */ - error = -EINVAL; - if (!table->proc_handler) - goto out; - - /* careful: calling conventions are nasty here */ - res = count; - error = table->proc_handler(table, write, buf, &res, ppos); - if (!error) - error = res; -out: - sysctl_head_finish(head); - - return error; -} - -static ssize_t proc_sys_read(struct file *filp, char __user *buf, - size_t count, loff_t *ppos) -{ - return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 0); -} - -static ssize_t proc_sys_write(struct file *filp, const char __user *buf, - size_t count, loff_t *ppos) -{ - return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 1); -} - -static int proc_sys_open(struct inode *inode, struct file *filp) -{ - struct ctl_table_header *head = grab_header(inode); - struct ctl_table *table = PROC_I(inode)->sysctl_entry; - - /* sysctl was unregistered */ - if (IS_ERR(head)) - return PTR_ERR(head); - - if (table->poll) - filp->private_data = proc_sys_poll_event(table->poll); - - sysctl_head_finish(head); - - return 0; -} - -static unsigned int proc_sys_poll(struct file *filp, poll_table *wait) -{ - struct inode *inode = file_inode(filp); - struct ctl_table_header *head = grab_header(inode); - struct ctl_table *table = PROC_I(inode)->sysctl_entry; - unsigned int ret = DEFAULT_POLLMASK; - unsigned long event; - - /* sysctl was unregistered */ - if (IS_ERR(head)) - return POLLERR | POLLHUP; - - if (!table->proc_handler) - goto out; - - if (!table->poll) - goto out; - - event = (unsigned long)filp->private_data; - poll_wait(filp, &table->poll->wait, wait); - - if (event != atomic_read(&table->poll->event)) { - filp->private_data = proc_sys_poll_event(table->poll); - ret = POLLIN | POLLRDNORM | POLLERR | POLLPRI; - } - -out: - sysctl_head_finish(head); - - return ret; -} - -static bool proc_sys_fill_cache(struct file *file, - struct dir_context *ctx, - struct ctl_table_header *head, - struct ctl_table *table) -{ - struct dentry *child, *dir = file->f_path.dentry; - struct inode *inode; - struct qstr qname; - ino_t ino = 0; - unsigned type = DT_UNKNOWN; - - qname.name = table->procname; - qname.len = strlen(table->procname); - qname.hash = full_name_hash(dir, qname.name, qname.len); - - child = d_lookup(dir, &qname); - if (!child) { - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq); - child = d_alloc_parallel(dir, &qname, &wq); - if (IS_ERR(child)) - return false; - if (d_in_lookup(child)) { - inode = proc_sys_make_inode(dir->d_sb, head, table); - if (!inode) { - d_lookup_done(child); - dput(child); - return false; - } - d_set_d_op(child, &proc_sys_dentry_operations); - d_add(child, inode); - } - } - inode = d_inode(child); - ino = inode->i_ino; - type = inode->i_mode >> 12; - dput(child); - return dir_emit(ctx, qname.name, qname.len, ino, type); -} - -static bool proc_sys_link_fill_cache(struct file *file, - struct dir_context *ctx, - struct ctl_table_header *head, - struct ctl_table *table) -{ - bool ret = true; - head = sysctl_head_grab(head); - - if (S_ISLNK(table->mode)) { - /* It is not an error if we can not follow the link ignore it */ - int err = sysctl_follow_link(&head, &table); - if (err) - goto out; - } - - ret = proc_sys_fill_cache(file, ctx, head, table); -out: - sysctl_head_finish(head); - return ret; -} - -static int scan(struct ctl_table_header *head, struct ctl_table *table, - unsigned long *pos, struct file *file, - struct dir_context *ctx) -{ - bool res; - - if ((*pos)++ < ctx->pos) - return true; - - if (unlikely(S_ISLNK(table->mode))) - res = proc_sys_link_fill_cache(file, ctx, head, table); - else - res = proc_sys_fill_cache(file, ctx, head, table); - - if (res) - ctx->pos = *pos; - - return res; -} - -static int proc_sys_readdir(struct file *file, struct dir_context *ctx) -{ - struct ctl_table_header *head = grab_header(file_inode(file)); - struct ctl_table_header *h = NULL; - struct ctl_table *entry; - struct ctl_dir *ctl_dir; - unsigned long pos; - - if (IS_ERR(head)) - return PTR_ERR(head); - - ctl_dir = container_of(head, struct ctl_dir, header); - - if (!dir_emit_dots(file, ctx)) - return 0; - - pos = 2; - - for (first_entry(ctl_dir, &h, &entry); h; next_entry(&h, &entry)) { - if (!scan(h, entry, &pos, file, ctx)) { - sysctl_head_finish(h); - break; - } - } - sysctl_head_finish(head); - return 0; -} - -static int proc_sys_permission(struct inode *inode, int mask) -{ - /* - * sysctl entries that are not writeable, - * are _NOT_ writeable, capabilities or not. - */ - struct ctl_table_header *head; - struct ctl_table *table; - int error; - - /* Executable files are not allowed under /proc/sys/ */ - if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) - return -EACCES; - - head = grab_header(inode); - if (IS_ERR(head)) - return PTR_ERR(head); - - table = PROC_I(inode)->sysctl_entry; - if (!table) /* global root - r-xr-xr-x */ - error = mask & MAY_WRITE ? -EACCES : 0; - else /* Use the permissions on the sysctl table entry */ - error = sysctl_perm(head, table, mask & ~MAY_NOT_BLOCK); - - sysctl_head_finish(head); - return error; -} - -static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr) -{ - struct inode *inode = d_inode(dentry); - int error; - - if (attr->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)) - return -EPERM; - - error = setattr_prepare(dentry, attr); - if (error) - return error; - - setattr_copy(inode, attr); - mark_inode_dirty(inode); - return 0; -} - -static int proc_sys_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) -{ - struct inode *inode = d_inode(dentry); - struct ctl_table_header *head = grab_header(inode); - struct ctl_table *table = PROC_I(inode)->sysctl_entry; - - if (IS_ERR(head)) - return PTR_ERR(head); - - generic_fillattr(inode, stat); - if (table) - stat->mode = (stat->mode & S_IFMT) | table->mode; - - sysctl_head_finish(head); - return 0; -} - -static const struct file_operations proc_sys_file_operations = { - .open = proc_sys_open, - .poll = proc_sys_poll, - .read = proc_sys_read, - .write = proc_sys_write, - .llseek = default_llseek, -}; - -static const struct file_operations proc_sys_dir_file_operations = { - .read = generic_read_dir, - .iterate_shared = proc_sys_readdir, - .llseek = generic_file_llseek, -}; - -static const struct inode_operations proc_sys_inode_operations = { - .permission = proc_sys_permission, - .setattr = proc_sys_setattr, - .getattr = proc_sys_getattr, -}; - -static const struct inode_operations proc_sys_dir_operations = { - .lookup = proc_sys_lookup, - .permission = proc_sys_permission, - .setattr = proc_sys_setattr, - .getattr = proc_sys_getattr, -}; - -static int proc_sys_revalidate(struct dentry *dentry, unsigned int flags) -{ - if (flags & LOOKUP_RCU) - return -ECHILD; - return !PROC_I(d_inode(dentry))->sysctl->unregistering; -} - -static int proc_sys_delete(const struct dentry *dentry) -{ - return !!PROC_I(d_inode(dentry))->sysctl->unregistering; -} - -static int sysctl_is_seen(struct ctl_table_header *p) -{ - struct ctl_table_set *set = p->set; - int res; - spin_lock(&sysctl_lock); - if (p->unregistering) - res = 0; - else if (!set->is_seen) - res = 1; - else - res = set->is_seen(set); - spin_unlock(&sysctl_lock); - return res; -} - -static int proc_sys_compare(const struct dentry *dentry, - unsigned int len, const char *str, const struct qstr *name) -{ - struct ctl_table_header *head; - struct inode *inode; - - /* Although proc doesn't have negative dentries, rcu-walk means - * that inode here can be NULL */ - /* AV: can it, indeed? */ - inode = d_inode_rcu(dentry); - if (!inode) - return 1; - if (name->len != len) - return 1; - if (memcmp(name->name, str, len)) - return 1; - head = rcu_dereference(PROC_I(inode)->sysctl); - return !head || !sysctl_is_seen(head); -} - -static const struct dentry_operations proc_sys_dentry_operations = { - .d_revalidate = proc_sys_revalidate, - .d_delete = proc_sys_delete, - .d_compare = proc_sys_compare, -}; - -static struct ctl_dir *find_subdir(struct ctl_dir *dir, - const char *name, int namelen) -{ - struct ctl_table_header *head; - struct ctl_table *entry; - - entry = find_entry(&head, dir, name, namelen); - if (!entry) - return ERR_PTR(-ENOENT); - if (!S_ISDIR(entry->mode)) - return ERR_PTR(-ENOTDIR); - return container_of(head, struct ctl_dir, header); -} - -static struct ctl_dir *new_dir(struct ctl_table_set *set, - const char *name, int namelen) -{ - struct ctl_table *table; - struct ctl_dir *new; - struct ctl_node *node; - char *new_name; - - new = kzalloc(sizeof(*new) + sizeof(struct ctl_node) + - sizeof(struct ctl_table)*2 + namelen + 1, - GFP_KERNEL); - if (!new) - return NULL; - - node = (struct ctl_node *)(new + 1); - table = (struct ctl_table *)(node + 1); - new_name = (char *)(table + 2); - memcpy(new_name, name, namelen); - new_name[namelen] = '\0'; - table[0].procname = new_name; - table[0].mode = S_IFDIR|S_IRUGO|S_IXUGO; - init_header(&new->header, set->dir.header.root, set, node, table); - - return new; -} - -/** - * get_subdir - find or create a subdir with the specified name. - * @dir: Directory to create the subdirectory in - * @name: The name of the subdirectory to find or create - * @namelen: The length of name - * - * Takes a directory with an elevated reference count so we know that - * if we drop the lock the directory will not go away. Upon success - * the reference is moved from @dir to the returned subdirectory. - * Upon error an error code is returned and the reference on @dir is - * simply dropped. - */ -static struct ctl_dir *get_subdir(struct ctl_dir *dir, - const char *name, int namelen) -{ - struct ctl_table_set *set = dir->header.set; - struct ctl_dir *subdir, *new = NULL; - int err; - - spin_lock(&sysctl_lock); - subdir = find_subdir(dir, name, namelen); - if (!IS_ERR(subdir)) - goto found; - if (PTR_ERR(subdir) != -ENOENT) - goto failed; - - spin_unlock(&sysctl_lock); - new = new_dir(set, name, namelen); - spin_lock(&sysctl_lock); - subdir = ERR_PTR(-ENOMEM); - if (!new) - goto failed; - - /* Was the subdir added while we dropped the lock? */ - subdir = find_subdir(dir, name, namelen); - if (!IS_ERR(subdir)) - goto found; - if (PTR_ERR(subdir) != -ENOENT) - goto failed; - - /* Nope. Use the our freshly made directory entry. */ - err = insert_header(dir, &new->header); - subdir = ERR_PTR(err); - if (err) - goto failed; - subdir = new; -found: - subdir->header.nreg++; -failed: - if (IS_ERR(subdir)) { - pr_err("sysctl could not get directory: "); - sysctl_print_dir(dir); - pr_cont("/%*.*s %ld\n", - namelen, namelen, name, PTR_ERR(subdir)); - } - drop_sysctl_table(&dir->header); - if (new) - drop_sysctl_table(&new->header); - spin_unlock(&sysctl_lock); - return subdir; -} - -static struct ctl_dir *xlate_dir(struct ctl_table_set *set, struct ctl_dir *dir) -{ - struct ctl_dir *parent; - const char *procname; - if (!dir->header.parent) - return &set->dir; - parent = xlate_dir(set, dir->header.parent); - if (IS_ERR(parent)) - return parent; - procname = dir->header.ctl_table[0].procname; - return find_subdir(parent, procname, strlen(procname)); -} - -static int sysctl_follow_link(struct ctl_table_header **phead, - struct ctl_table **pentry) -{ - struct ctl_table_header *head; - struct ctl_table_root *root; - struct ctl_table_set *set; - struct ctl_table *entry; - struct ctl_dir *dir; - int ret; - - ret = 0; - spin_lock(&sysctl_lock); - root = (*pentry)->data; - set = lookup_header_set(root); - dir = xlate_dir(set, (*phead)->parent); - if (IS_ERR(dir)) - ret = PTR_ERR(dir); - else { - const char *procname = (*pentry)->procname; - head = NULL; - entry = find_entry(&head, dir, procname, strlen(procname)); - ret = -ENOENT; - if (entry && use_table(head)) { - unuse_table(*phead); - *phead = head; - *pentry = entry; - ret = 0; - } - } - - spin_unlock(&sysctl_lock); - return ret; -} - -static int sysctl_err(const char *path, struct ctl_table *table, char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; - - pr_err("sysctl table check failed: %s/%s %pV\n", - path, table->procname, &vaf); - - va_end(args); - return -EINVAL; -} - -static int sysctl_check_table(const char *path, struct ctl_table *table) -{ - int err = 0; - for (; table->procname; table++) { - if (table->child) - err = sysctl_err(path, table, "Not a file"); - - if ((table->proc_handler == proc_dostring) || - (table->proc_handler == proc_dointvec) || - (table->proc_handler == proc_dointvec_minmax) || - (table->proc_handler == proc_dointvec_jiffies) || - (table->proc_handler == proc_dointvec_userhz_jiffies) || - (table->proc_handler == proc_dointvec_ms_jiffies) || - (table->proc_handler == proc_doulongvec_minmax) || - (table->proc_handler == proc_doulongvec_ms_jiffies_minmax)) { - if (!table->data) - err = sysctl_err(path, table, "No data"); - if (!table->maxlen) - err = sysctl_err(path, table, "No maxlen"); - } - if (!table->proc_handler) - err = sysctl_err(path, table, "No proc_handler"); - - if ((table->mode & (S_IRUGO|S_IWUGO)) != table->mode) - err = sysctl_err(path, table, "bogus .mode 0%o", - table->mode); - } - return err; -} - -static struct ctl_table_header *new_links(struct ctl_dir *dir, struct ctl_table *table, - struct ctl_table_root *link_root) -{ - struct ctl_table *link_table, *entry, *link; - struct ctl_table_header *links; - struct ctl_node *node; - char *link_name; - int nr_entries, name_bytes; - - name_bytes = 0; - nr_entries = 0; - for (entry = table; entry->procname; entry++) { - nr_entries++; - name_bytes += strlen(entry->procname) + 1; - } - - links = kzalloc(sizeof(struct ctl_table_header) + - sizeof(struct ctl_node)*nr_entries + - sizeof(struct ctl_table)*(nr_entries + 1) + - name_bytes, - GFP_KERNEL); - - if (!links) - return NULL; - - node = (struct ctl_node *)(links + 1); - link_table = (struct ctl_table *)(node + nr_entries); - link_name = (char *)&link_table[nr_entries + 1]; - - for (link = link_table, entry = table; entry->procname; link++, entry++) { - int len = strlen(entry->procname) + 1; - memcpy(link_name, entry->procname, len); - link->procname = link_name; - link->mode = S_IFLNK|S_IRWXUGO; - link->data = link_root; - link_name += len; - } - init_header(links, dir->header.root, dir->header.set, node, link_table); - links->nreg = nr_entries; - - return links; -} - -static bool get_links(struct ctl_dir *dir, - struct ctl_table *table, struct ctl_table_root *link_root) -{ - struct ctl_table_header *head; - struct ctl_table *entry, *link; - - /* Are there links available for every entry in table? */ - for (entry = table; entry->procname; entry++) { - const char *procname = entry->procname; - link = find_entry(&head, dir, procname, strlen(procname)); - if (!link) - return false; - if (S_ISDIR(link->mode) && S_ISDIR(entry->mode)) - continue; - if (S_ISLNK(link->mode) && (link->data == link_root)) - continue; - return false; - } - - /* The checks passed. Increase the registration count on the links */ - for (entry = table; entry->procname; entry++) { - const char *procname = entry->procname; - link = find_entry(&head, dir, procname, strlen(procname)); - head->nreg++; - } - return true; -} - -static int insert_links(struct ctl_table_header *head) -{ - struct ctl_table_set *root_set = &sysctl_table_root.default_set; - struct ctl_dir *core_parent = NULL; - struct ctl_table_header *links; - int err; - - if (head->set == root_set) - return 0; - - core_parent = xlate_dir(root_set, head->parent); - if (IS_ERR(core_parent)) - return 0; - - if (get_links(core_parent, head->ctl_table, head->root)) - return 0; - - core_parent->header.nreg++; - spin_unlock(&sysctl_lock); - - links = new_links(core_parent, head->ctl_table, head->root); - - spin_lock(&sysctl_lock); - err = -ENOMEM; - if (!links) - goto out; - - err = 0; - if (get_links(core_parent, head->ctl_table, head->root)) { - kfree(links); - goto out; - } - - err = insert_header(core_parent, links); - if (err) - kfree(links); -out: - drop_sysctl_table(&core_parent->header); - return err; -} - -/** - * __register_sysctl_table - register a leaf sysctl table - * @set: Sysctl tree to register on - * @path: The path to the directory the sysctl table is in. - * @table: the top-level table structure - * - * Register a sysctl table hierarchy. @table should be a filled in ctl_table - * array. A completely 0 filled entry terminates the table. - * - * The members of the &struct ctl_table structure are used as follows: - * - * procname - the name of the sysctl file under /proc/sys. Set to %NULL to not - * enter a sysctl file - * - * data - a pointer to data for use by proc_handler - * - * maxlen - the maximum size in bytes of the data - * - * mode - the file permissions for the /proc/sys file - * - * child - must be %NULL. - * - * proc_handler - the text handler routine (described below) - * - * extra1, extra2 - extra pointers usable by the proc handler routines - * - * Leaf nodes in the sysctl tree will be represented by a single file - * under /proc; non-leaf nodes will be represented by directories. - * - * There must be a proc_handler routine for any terminal nodes. - * Several default handlers are available to cover common cases - - * - * proc_dostring(), proc_dointvec(), proc_dointvec_jiffies(), - * proc_dointvec_userhz_jiffies(), proc_dointvec_minmax(), - * proc_doulongvec_ms_jiffies_minmax(), proc_doulongvec_minmax() - * - * It is the handler's job to read the input buffer from user memory - * and process it. The handler should return 0 on success. - * - * This routine returns %NULL on a failure to register, and a pointer - * to the table header on success. - */ -struct ctl_table_header *__register_sysctl_table( - struct ctl_table_set *set, - const char *path, struct ctl_table *table) -{ - struct ctl_table_root *root = set->dir.header.root; - struct ctl_table_header *header; - const char *name, *nextname; - struct ctl_dir *dir; - struct ctl_table *entry; - struct ctl_node *node; - int nr_entries = 0; - - for (entry = table; entry->procname; entry++) - nr_entries++; - - header = kzalloc(sizeof(struct ctl_table_header) + - sizeof(struct ctl_node)*nr_entries, GFP_KERNEL); - if (!header) - return NULL; - - node = (struct ctl_node *)(header + 1); - init_header(header, root, set, node, table); - if (sysctl_check_table(path, table)) - goto fail; - - spin_lock(&sysctl_lock); - dir = &set->dir; - /* Reference moved down the diretory tree get_subdir */ - dir->header.nreg++; - spin_unlock(&sysctl_lock); - - /* Find the directory for the ctl_table */ - for (name = path; name; name = nextname) { - int namelen; - nextname = strchr(name, '/'); - if (nextname) { - namelen = nextname - name; - nextname++; - } else { - namelen = strlen(name); - } - if (namelen == 0) - continue; - - dir = get_subdir(dir, name, namelen); - if (IS_ERR(dir)) - goto fail; - } - - spin_lock(&sysctl_lock); - if (insert_header(dir, header)) - goto fail_put_dir_locked; - - drop_sysctl_table(&dir->header); - spin_unlock(&sysctl_lock); - - return header; - -fail_put_dir_locked: - drop_sysctl_table(&dir->header); - spin_unlock(&sysctl_lock); -fail: - kfree(header); - dump_stack(); - return NULL; -} - -/** - * register_sysctl - register a sysctl table - * @path: The path to the directory the sysctl table is in. - * @table: the table structure - * - * Register a sysctl table. @table should be a filled in ctl_table - * array. A completely 0 filled entry terminates the table. - * - * See __register_sysctl_table for more details. - */ -struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table) -{ - return __register_sysctl_table(&sysctl_table_root.default_set, - path, table); -} -EXPORT_SYMBOL(register_sysctl); - -static char *append_path(const char *path, char *pos, const char *name) -{ - int namelen; - namelen = strlen(name); - if (((pos - path) + namelen + 2) >= PATH_MAX) - return NULL; - memcpy(pos, name, namelen); - pos[namelen] = '/'; - pos[namelen + 1] = '\0'; - pos += namelen + 1; - return pos; -} - -static int count_subheaders(struct ctl_table *table) -{ - int has_files = 0; - int nr_subheaders = 0; - struct ctl_table *entry; - - /* special case: no directory and empty directory */ - if (!table || !table->procname) - return 1; - - for (entry = table; entry->procname; entry++) { - if (entry->child) - nr_subheaders += count_subheaders(entry->child); - else - has_files = 1; - } - return nr_subheaders + has_files; -} - -static int register_leaf_sysctl_tables(const char *path, char *pos, - struct ctl_table_header ***subheader, struct ctl_table_set *set, - struct ctl_table *table) -{ - struct ctl_table *ctl_table_arg = NULL; - struct ctl_table *entry, *files; - int nr_files = 0; - int nr_dirs = 0; - int err = -ENOMEM; - - for (entry = table; entry->procname; entry++) { - if (entry->child) - nr_dirs++; - else - nr_files++; - } - - files = table; - /* If there are mixed files and directories we need a new table */ - if (nr_dirs && nr_files) { - struct ctl_table *new; - files = kzalloc(sizeof(struct ctl_table) * (nr_files + 1), - GFP_KERNEL); - if (!files) - goto out; - - ctl_table_arg = files; - for (new = files, entry = table; entry->procname; entry++) { - if (entry->child) - continue; - *new = *entry; - new++; - } - } - - /* Register everything except a directory full of subdirectories */ - if (nr_files || !nr_dirs) { - struct ctl_table_header *header; - header = __register_sysctl_table(set, path, files); - if (!header) { - kfree(ctl_table_arg); - goto out; - } - - /* Remember if we need to free the file table */ - header->ctl_table_arg = ctl_table_arg; - **subheader = header; - (*subheader)++; - } - - /* Recurse into the subdirectories. */ - for (entry = table; entry->procname; entry++) { - char *child_pos; - - if (!entry->child) - continue; - - err = -ENAMETOOLONG; - child_pos = append_path(path, pos, entry->procname); - if (!child_pos) - goto out; - - err = register_leaf_sysctl_tables(path, child_pos, subheader, - set, entry->child); - pos[0] = '\0'; - if (err) - goto out; - } - err = 0; -out: - /* On failure our caller will unregister all registered subheaders */ - return err; -} - -/** - * __register_sysctl_paths - register a sysctl table hierarchy - * @set: Sysctl tree to register on - * @path: The path to the directory the sysctl table is in. - * @table: the top-level table structure - * - * Register a sysctl table hierarchy. @table should be a filled in ctl_table - * array. A completely 0 filled entry terminates the table. - * - * See __register_sysctl_table for more details. - */ -struct ctl_table_header *__register_sysctl_paths( - struct ctl_table_set *set, - const struct ctl_path *path, struct ctl_table *table) -{ - struct ctl_table *ctl_table_arg = table; - int nr_subheaders = count_subheaders(table); - struct ctl_table_header *header = NULL, **subheaders, **subheader; - const struct ctl_path *component; - char *new_path, *pos; - - pos = new_path = kmalloc(PATH_MAX, GFP_KERNEL); - if (!new_path) - return NULL; - - pos[0] = '\0'; - for (component = path; component->procname; component++) { - pos = append_path(new_path, pos, component->procname); - if (!pos) - goto out; - } - while (table->procname && table->child && !table[1].procname) { - pos = append_path(new_path, pos, table->procname); - if (!pos) - goto out; - table = table->child; - } - if (nr_subheaders == 1) { - header = __register_sysctl_table(set, new_path, table); - if (header) - header->ctl_table_arg = ctl_table_arg; - } else { - header = kzalloc(sizeof(*header) + - sizeof(*subheaders)*nr_subheaders, GFP_KERNEL); - if (!header) - goto out; - - subheaders = (struct ctl_table_header **) (header + 1); - subheader = subheaders; - header->ctl_table_arg = ctl_table_arg; - - if (register_leaf_sysctl_tables(new_path, pos, &subheader, - set, table)) - goto err_register_leaves; - } - -out: - kfree(new_path); - return header; - -err_register_leaves: - while (subheader > subheaders) { - struct ctl_table_header *subh = *(--subheader); - struct ctl_table *table = subh->ctl_table_arg; - unregister_sysctl_table(subh); - kfree(table); - } - kfree(header); - header = NULL; - goto out; -} - -/** - * register_sysctl_table_path - register a sysctl table hierarchy - * @path: The path to the directory the sysctl table is in. - * @table: the top-level table structure - * - * Register a sysctl table hierarchy. @table should be a filled in ctl_table - * array. A completely 0 filled entry terminates the table. - * - * See __register_sysctl_paths for more details. - */ -struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path, - struct ctl_table *table) -{ - return __register_sysctl_paths(&sysctl_table_root.default_set, - path, table); -} -EXPORT_SYMBOL(register_sysctl_paths); - -/** - * register_sysctl_table - register a sysctl table hierarchy - * @table: the top-level table structure - * - * Register a sysctl table hierarchy. @table should be a filled in ctl_table - * array. A completely 0 filled entry terminates the table. - * - * See register_sysctl_paths for more details. - */ -struct ctl_table_header *register_sysctl_table(struct ctl_table *table) -{ - static const struct ctl_path null_path[] = { {} }; - - return register_sysctl_paths(null_path, table); -} -EXPORT_SYMBOL(register_sysctl_table); - -static void put_links(struct ctl_table_header *header) -{ - struct ctl_table_set *root_set = &sysctl_table_root.default_set; - struct ctl_table_root *root = header->root; - struct ctl_dir *parent = header->parent; - struct ctl_dir *core_parent; - struct ctl_table *entry; - - if (header->set == root_set) - return; - - core_parent = xlate_dir(root_set, parent); - if (IS_ERR(core_parent)) - return; - - for (entry = header->ctl_table; entry->procname; entry++) { - struct ctl_table_header *link_head; - struct ctl_table *link; - const char *name = entry->procname; - - link = find_entry(&link_head, core_parent, name, strlen(name)); - if (link && - ((S_ISDIR(link->mode) && S_ISDIR(entry->mode)) || - (S_ISLNK(link->mode) && (link->data == root)))) { - drop_sysctl_table(link_head); - } - else { - pr_err("sysctl link missing during unregister: "); - sysctl_print_dir(parent); - pr_cont("/%s\n", name); - } - } -} - -static void drop_sysctl_table(struct ctl_table_header *header) -{ - struct ctl_dir *parent = header->parent; - - if (--header->nreg) - return; - - put_links(header); - start_unregistering(header); - if (!--header->count) - kfree_rcu(header, rcu); - - if (parent) - drop_sysctl_table(&parent->header); -} - -/** - * unregister_sysctl_table - unregister a sysctl table hierarchy - * @header: the header returned from register_sysctl_table - * - * Unregisters the sysctl table and all children. proc entries may not - * actually be removed until they are no longer used by anyone. - */ -void unregister_sysctl_table(struct ctl_table_header * header) -{ - int nr_subheaders; - might_sleep(); - - if (header == NULL) - return; - - nr_subheaders = count_subheaders(header->ctl_table_arg); - if (unlikely(nr_subheaders > 1)) { - struct ctl_table_header **subheaders; - int i; - - subheaders = (struct ctl_table_header **)(header + 1); - for (i = nr_subheaders -1; i >= 0; i--) { - struct ctl_table_header *subh = subheaders[i]; - struct ctl_table *table = subh->ctl_table_arg; - unregister_sysctl_table(subh); - kfree(table); - } - kfree(header); - return; - } - - spin_lock(&sysctl_lock); - drop_sysctl_table(header); - spin_unlock(&sysctl_lock); -} -EXPORT_SYMBOL(unregister_sysctl_table); - -void setup_sysctl_set(struct ctl_table_set *set, - struct ctl_table_root *root, - int (*is_seen)(struct ctl_table_set *)) -{ - memset(set, 0, sizeof(*set)); - set->is_seen = is_seen; - init_header(&set->dir.header, root, set, NULL, root_table); -} - -void retire_sysctl_set(struct ctl_table_set *set) -{ - WARN_ON(!RB_EMPTY_ROOT(&set->dir.root)); -} - -int __init proc_sys_init(void) -{ - struct proc_dir_entry *proc_sys_root; - - proc_sys_root = proc_mkdir("sys", NULL); - proc_sys_root->proc_iops = &proc_sys_dir_operations; - proc_sys_root->proc_fops = &proc_sys_dir_file_operations; - proc_sys_root->nlink = 0; - - return sysctl_init(); -} diff --git a/src/linux/fs/proc/proc_tty.c b/src/linux/fs/proc/proc_tty.c deleted file mode 100644 index 15f327b..0000000 --- a/src/linux/fs/proc/proc_tty.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - * proc_tty.c -- handles /proc/tty - * - * Copyright 1997, Theodore Ts'o - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * The /proc/tty directory inodes... - */ -static struct proc_dir_entry *proc_tty_driver; - -/* - * This is the handler for /proc/tty/drivers - */ -static void show_tty_range(struct seq_file *m, struct tty_driver *p, - dev_t from, int num) -{ - seq_printf(m, "%-20s ", p->driver_name ? p->driver_name : "unknown"); - seq_printf(m, "/dev/%-8s ", p->name); - if (p->num > 1) { - seq_printf(m, "%3d %d-%d ", MAJOR(from), MINOR(from), - MINOR(from) + num - 1); - } else { - seq_printf(m, "%3d %7d ", MAJOR(from), MINOR(from)); - } - switch (p->type) { - case TTY_DRIVER_TYPE_SYSTEM: - seq_puts(m, "system"); - if (p->subtype == SYSTEM_TYPE_TTY) - seq_puts(m, ":/dev/tty"); - else if (p->subtype == SYSTEM_TYPE_SYSCONS) - seq_puts(m, ":console"); - else if (p->subtype == SYSTEM_TYPE_CONSOLE) - seq_puts(m, ":vtmaster"); - break; - case TTY_DRIVER_TYPE_CONSOLE: - seq_puts(m, "console"); - break; - case TTY_DRIVER_TYPE_SERIAL: - seq_puts(m, "serial"); - break; - case TTY_DRIVER_TYPE_PTY: - if (p->subtype == PTY_TYPE_MASTER) - seq_puts(m, "pty:master"); - else if (p->subtype == PTY_TYPE_SLAVE) - seq_puts(m, "pty:slave"); - else - seq_puts(m, "pty"); - break; - default: - seq_printf(m, "type:%d.%d", p->type, p->subtype); - } - seq_putc(m, '\n'); -} - -static int show_tty_driver(struct seq_file *m, void *v) -{ - struct tty_driver *p = list_entry(v, struct tty_driver, tty_drivers); - dev_t from = MKDEV(p->major, p->minor_start); - dev_t to = from + p->num; - - if (&p->tty_drivers == tty_drivers.next) { - /* pseudo-drivers first */ - seq_printf(m, "%-20s /dev/%-8s ", "/dev/tty", "tty"); - seq_printf(m, "%3d %7d ", TTYAUX_MAJOR, 0); - seq_puts(m, "system:/dev/tty\n"); - seq_printf(m, "%-20s /dev/%-8s ", "/dev/console", "console"); - seq_printf(m, "%3d %7d ", TTYAUX_MAJOR, 1); - seq_puts(m, "system:console\n"); -#ifdef CONFIG_UNIX98_PTYS - seq_printf(m, "%-20s /dev/%-8s ", "/dev/ptmx", "ptmx"); - seq_printf(m, "%3d %7d ", TTYAUX_MAJOR, 2); - seq_puts(m, "system\n"); -#endif -#ifdef CONFIG_VT - seq_printf(m, "%-20s /dev/%-8s ", "/dev/vc/0", "vc/0"); - seq_printf(m, "%3d %7d ", TTY_MAJOR, 0); - seq_puts(m, "system:vtmaster\n"); -#endif - } - - while (MAJOR(from) < MAJOR(to)) { - dev_t next = MKDEV(MAJOR(from)+1, 0); - show_tty_range(m, p, from, next - from); - from = next; - } - if (from != to) - show_tty_range(m, p, from, to - from); - return 0; -} - -/* iterator */ -static void *t_start(struct seq_file *m, loff_t *pos) -{ - mutex_lock(&tty_mutex); - return seq_list_start(&tty_drivers, *pos); -} - -static void *t_next(struct seq_file *m, void *v, loff_t *pos) -{ - return seq_list_next(v, &tty_drivers, pos); -} - -static void t_stop(struct seq_file *m, void *v) -{ - mutex_unlock(&tty_mutex); -} - -static const struct seq_operations tty_drivers_op = { - .start = t_start, - .next = t_next, - .stop = t_stop, - .show = show_tty_driver -}; - -static int tty_drivers_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &tty_drivers_op); -} - -static const struct file_operations proc_tty_drivers_operations = { - .open = tty_drivers_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -/* - * This function is called by tty_register_driver() to handle - * registering the driver's /proc handler into /proc/tty/driver/ - */ -void proc_tty_register_driver(struct tty_driver *driver) -{ - struct proc_dir_entry *ent; - - if (!driver->driver_name || driver->proc_entry || - !driver->ops->proc_fops) - return; - - ent = proc_create_data(driver->driver_name, 0, proc_tty_driver, - driver->ops->proc_fops, driver); - driver->proc_entry = ent; -} - -/* - * This function is called by tty_unregister_driver() - */ -void proc_tty_unregister_driver(struct tty_driver *driver) -{ - struct proc_dir_entry *ent; - - ent = driver->proc_entry; - if (!ent) - return; - - remove_proc_entry(driver->driver_name, proc_tty_driver); - - driver->proc_entry = NULL; -} - -/* - * Called by proc_root_init() to initialize the /proc/tty subtree - */ -void __init proc_tty_init(void) -{ - if (!proc_mkdir("tty", NULL)) - return; - proc_mkdir("tty/ldisc", NULL); /* Preserved: it's userspace visible */ - /* - * /proc/tty/driver/serial reveals the exact character counts for - * serial links which is just too easy to abuse for inferring - * password lengths and inter-keystroke timings during password - * entry. - */ - proc_tty_driver = proc_mkdir_mode("tty/driver", S_IRUSR|S_IXUSR, NULL); - proc_create("tty/ldiscs", 0, NULL, &tty_ldiscs_proc_fops); - proc_create("tty/drivers", 0, NULL, &proc_tty_drivers_operations); -} diff --git a/src/linux/fs/proc/root.c b/src/linux/fs/proc/root.c deleted file mode 100644 index 8d3e484..0000000 --- a/src/linux/fs/proc/root.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * linux/fs/proc/root.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * proc root directory handling functions - */ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -enum { - Opt_gid, Opt_hidepid, Opt_err, -}; - -static const match_table_t tokens = { - {Opt_hidepid, "hidepid=%u"}, - {Opt_gid, "gid=%u"}, - {Opt_err, NULL}, -}; - -int proc_parse_options(char *options, struct pid_namespace *pid) -{ - char *p; - substring_t args[MAX_OPT_ARGS]; - int option; - - if (!options) - return 1; - - while ((p = strsep(&options, ",")) != NULL) { - int token; - if (!*p) - continue; - - args[0].to = args[0].from = NULL; - token = match_token(p, tokens, args); - switch (token) { - case Opt_gid: - if (match_int(&args[0], &option)) - return 0; - pid->pid_gid = make_kgid(current_user_ns(), option); - break; - case Opt_hidepid: - if (match_int(&args[0], &option)) - return 0; - if (option < 0 || option > 2) { - pr_err("proc: hidepid value must be between 0 and 2.\n"); - return 0; - } - pid->hide_pid = option; - break; - default: - pr_err("proc: unrecognized mount option \"%s\" " - "or missing value\n", p); - return 0; - } - } - - return 1; -} - -int proc_remount(struct super_block *sb, int *flags, char *data) -{ - struct pid_namespace *pid = sb->s_fs_info; - - sync_filesystem(sb); - return !proc_parse_options(data, pid); -} - -static struct dentry *proc_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - struct pid_namespace *ns; - - if (flags & MS_KERNMOUNT) { - ns = data; - data = NULL; - } else { - ns = task_active_pid_ns(current); - } - - return mount_ns(fs_type, flags, data, ns, ns->user_ns, proc_fill_super); -} - -static void proc_kill_sb(struct super_block *sb) -{ - struct pid_namespace *ns; - - ns = (struct pid_namespace *)sb->s_fs_info; - if (ns->proc_self) - dput(ns->proc_self); - if (ns->proc_thread_self) - dput(ns->proc_thread_self); - kill_anon_super(sb); - put_pid_ns(ns); -} - -static struct file_system_type proc_fs_type = { - .name = "proc", - .mount = proc_mount, - .kill_sb = proc_kill_sb, - .fs_flags = FS_USERNS_MOUNT, -}; - -void __init proc_root_init(void) -{ - int err; - - proc_init_inodecache(); - err = register_filesystem(&proc_fs_type); - if (err) - return; - - proc_self_init(); - proc_thread_self_init(); - proc_symlink("mounts", NULL, "self/mounts"); - - proc_net_init(); - -#ifdef CONFIG_SYSVIPC - proc_mkdir("sysvipc", NULL); -#endif - proc_mkdir("fs", NULL); - proc_mkdir("driver", NULL); - proc_create_mount_point("fs/nfsd"); /* somewhere for the nfsd filesystem to be mounted */ -#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE) - /* just give it a mountpoint */ - proc_create_mount_point("openprom"); -#endif - proc_tty_init(); - proc_mkdir("bus", NULL); - proc_sys_init(); -} - -static int proc_root_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat -) -{ - generic_fillattr(d_inode(dentry), stat); - stat->nlink = proc_root.nlink + nr_processes(); - return 0; -} - -static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry, unsigned int flags) -{ - if (!proc_pid_lookup(dir, dentry, flags)) - return NULL; - - return proc_lookup(dir, dentry, flags); -} - -static int proc_root_readdir(struct file *file, struct dir_context *ctx) -{ - if (ctx->pos < FIRST_PROCESS_ENTRY) { - int error = proc_readdir(file, ctx); - if (unlikely(error <= 0)) - return error; - ctx->pos = FIRST_PROCESS_ENTRY; - } - - return proc_pid_readdir(file, ctx); -} - -/* - * The root /proc directory is special, as it has the - * directories. Thus we don't use the generic - * directory handling functions for that.. - */ -static const struct file_operations proc_root_operations = { - .read = generic_read_dir, - .iterate_shared = proc_root_readdir, - .llseek = generic_file_llseek, -}; - -/* - * proc root can do almost nothing.. - */ -static const struct inode_operations proc_root_inode_operations = { - .lookup = proc_root_lookup, - .getattr = proc_root_getattr, -}; - -/* - * This is the root "inode" in the /proc tree.. - */ -struct proc_dir_entry proc_root = { - .low_ino = PROC_ROOT_INO, - .namelen = 5, - .mode = S_IFDIR | S_IRUGO | S_IXUGO, - .nlink = 2, - .count = ATOMIC_INIT(1), - .proc_iops = &proc_root_inode_operations, - .proc_fops = &proc_root_operations, - .parent = &proc_root, - .subdir = RB_ROOT, - .name = "/proc", -}; - -int pid_ns_prepare_proc(struct pid_namespace *ns) -{ - struct vfsmount *mnt; - - mnt = kern_mount_data(&proc_fs_type, ns); - if (IS_ERR(mnt)) - return PTR_ERR(mnt); - - ns->proc_mnt = mnt; - return 0; -} - -void pid_ns_release_proc(struct pid_namespace *ns) -{ - kern_unmount(ns->proc_mnt); -} diff --git a/src/linux/fs/proc/self.c b/src/linux/fs/proc/self.c deleted file mode 100644 index 4024595..0000000 --- a/src/linux/fs/proc/self.c +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include -#include -#include "internal.h" - -/* - * /proc/self: - */ -static int proc_self_readlink(struct dentry *dentry, char __user *buffer, - int buflen) -{ - struct pid_namespace *ns = dentry->d_sb->s_fs_info; - pid_t tgid = task_tgid_nr_ns(current, ns); - char tmp[PROC_NUMBUF]; - if (!tgid) - return -ENOENT; - sprintf(tmp, "%d", tgid); - return readlink_copy(buffer, buflen, tmp); -} - -static const char *proc_self_get_link(struct dentry *dentry, - struct inode *inode, - struct delayed_call *done) -{ - struct pid_namespace *ns = inode->i_sb->s_fs_info; - pid_t tgid = task_tgid_nr_ns(current, ns); - char *name; - - if (!tgid) - return ERR_PTR(-ENOENT); - /* 11 for max length of signed int in decimal + NULL term */ - name = kmalloc(12, dentry ? GFP_KERNEL : GFP_ATOMIC); - if (unlikely(!name)) - return dentry ? ERR_PTR(-ENOMEM) : ERR_PTR(-ECHILD); - sprintf(name, "%d", tgid); - set_delayed_call(done, kfree_link, name); - return name; -} - -static const struct inode_operations proc_self_inode_operations = { - .readlink = proc_self_readlink, - .get_link = proc_self_get_link, -}; - -static unsigned self_inum; - -int proc_setup_self(struct super_block *s) -{ - struct inode *root_inode = d_inode(s->s_root); - struct pid_namespace *ns = s->s_fs_info; - struct dentry *self; - - inode_lock(root_inode); - self = d_alloc_name(s->s_root, "self"); - if (self) { - struct inode *inode = new_inode_pseudo(s); - if (inode) { - inode->i_ino = self_inum; - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); - inode->i_mode = S_IFLNK | S_IRWXUGO; - inode->i_uid = GLOBAL_ROOT_UID; - inode->i_gid = GLOBAL_ROOT_GID; - inode->i_op = &proc_self_inode_operations; - d_add(self, inode); - } else { - dput(self); - self = ERR_PTR(-ENOMEM); - } - } else { - self = ERR_PTR(-ENOMEM); - } - inode_unlock(root_inode); - if (IS_ERR(self)) { - pr_err("proc_fill_super: can't allocate /proc/self\n"); - return PTR_ERR(self); - } - ns->proc_self = self; - return 0; -} - -void __init proc_self_init(void) -{ - proc_alloc_inum(&self_inum); -} diff --git a/src/linux/fs/proc/softirqs.c b/src/linux/fs/proc/softirqs.c deleted file mode 100644 index ad8a77f..0000000 --- a/src/linux/fs/proc/softirqs.c +++ /dev/null @@ -1,44 +0,0 @@ -#include -#include -#include -#include - -/* - * /proc/softirqs ... display the number of softirqs - */ -static int show_softirqs(struct seq_file *p, void *v) -{ - int i, j; - - seq_puts(p, " "); - for_each_possible_cpu(i) - seq_printf(p, "CPU%-8d", i); - seq_putc(p, '\n'); - - for (i = 0; i < NR_SOFTIRQS; i++) { - seq_printf(p, "%12s:", softirq_to_name[i]); - for_each_possible_cpu(j) - seq_printf(p, " %10u", kstat_softirqs_cpu(i, j)); - seq_putc(p, '\n'); - } - return 0; -} - -static int softirqs_open(struct inode *inode, struct file *file) -{ - return single_open(file, show_softirqs, NULL); -} - -static const struct file_operations proc_softirqs_operations = { - .open = softirqs_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init proc_softirqs_init(void) -{ - proc_create("softirqs", 0, NULL, &proc_softirqs_operations); - return 0; -} -fs_initcall(proc_softirqs_init); diff --git a/src/linux/fs/proc/stat.c b/src/linux/fs/proc/stat.c deleted file mode 100644 index d700c42..0000000 --- a/src/linux/fs/proc/stat.c +++ /dev/null @@ -1,203 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef arch_irq_stat_cpu -#define arch_irq_stat_cpu(cpu) 0 -#endif -#ifndef arch_irq_stat -#define arch_irq_stat() 0 -#endif - -#ifdef arch_idle_time - -static cputime64_t get_idle_time(int cpu) -{ - cputime64_t idle; - - idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE]; - if (cpu_online(cpu) && !nr_iowait_cpu(cpu)) - idle += arch_idle_time(cpu); - return idle; -} - -static cputime64_t get_iowait_time(int cpu) -{ - cputime64_t iowait; - - iowait = kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT]; - if (cpu_online(cpu) && nr_iowait_cpu(cpu)) - iowait += arch_idle_time(cpu); - return iowait; -} - -#else - -static u64 get_idle_time(int cpu) -{ - u64 idle, idle_time = -1ULL; - - if (cpu_online(cpu)) - idle_time = get_cpu_idle_time_us(cpu, NULL); - - if (idle_time == -1ULL) - /* !NO_HZ or cpu offline so we can rely on cpustat.idle */ - idle = kcpustat_cpu(cpu).cpustat[CPUTIME_IDLE]; - else - idle = usecs_to_cputime64(idle_time); - - return idle; -} - -static u64 get_iowait_time(int cpu) -{ - u64 iowait, iowait_time = -1ULL; - - if (cpu_online(cpu)) - iowait_time = get_cpu_iowait_time_us(cpu, NULL); - - if (iowait_time == -1ULL) - /* !NO_HZ or cpu offline so we can rely on cpustat.iowait */ - iowait = kcpustat_cpu(cpu).cpustat[CPUTIME_IOWAIT]; - else - iowait = usecs_to_cputime64(iowait_time); - - return iowait; -} - -#endif - -static int show_stat(struct seq_file *p, void *v) -{ - int i, j; - u64 user, nice, system, idle, iowait, irq, softirq, steal; - u64 guest, guest_nice; - u64 sum = 0; - u64 sum_softirq = 0; - unsigned int per_softirq_sums[NR_SOFTIRQS] = {0}; - struct timespec64 boottime; - - user = nice = system = idle = iowait = - irq = softirq = steal = 0; - guest = guest_nice = 0; - getboottime64(&boottime); - - for_each_possible_cpu(i) { - user += kcpustat_cpu(i).cpustat[CPUTIME_USER]; - nice += kcpustat_cpu(i).cpustat[CPUTIME_NICE]; - system += kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM]; - idle += get_idle_time(i); - iowait += get_iowait_time(i); - irq += kcpustat_cpu(i).cpustat[CPUTIME_IRQ]; - softirq += kcpustat_cpu(i).cpustat[CPUTIME_SOFTIRQ]; - steal += kcpustat_cpu(i).cpustat[CPUTIME_STEAL]; - guest += kcpustat_cpu(i).cpustat[CPUTIME_GUEST]; - guest_nice += kcpustat_cpu(i).cpustat[CPUTIME_GUEST_NICE]; - sum += kstat_cpu_irqs_sum(i); - sum += arch_irq_stat_cpu(i); - - for (j = 0; j < NR_SOFTIRQS; j++) { - unsigned int softirq_stat = kstat_softirqs_cpu(j, i); - - per_softirq_sums[j] += softirq_stat; - sum_softirq += softirq_stat; - } - } - sum += arch_irq_stat(); - - seq_put_decimal_ull(p, "cpu ", cputime64_to_clock_t(user)); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(nice)); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(system)); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(idle)); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(iowait)); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(irq)); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(softirq)); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(steal)); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(guest)); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(guest_nice)); - seq_putc(p, '\n'); - - for_each_online_cpu(i) { - /* Copy values here to work around gcc-2.95.3, gcc-2.96 */ - user = kcpustat_cpu(i).cpustat[CPUTIME_USER]; - nice = kcpustat_cpu(i).cpustat[CPUTIME_NICE]; - system = kcpustat_cpu(i).cpustat[CPUTIME_SYSTEM]; - idle = get_idle_time(i); - iowait = get_iowait_time(i); - irq = kcpustat_cpu(i).cpustat[CPUTIME_IRQ]; - softirq = kcpustat_cpu(i).cpustat[CPUTIME_SOFTIRQ]; - steal = kcpustat_cpu(i).cpustat[CPUTIME_STEAL]; - guest = kcpustat_cpu(i).cpustat[CPUTIME_GUEST]; - guest_nice = kcpustat_cpu(i).cpustat[CPUTIME_GUEST_NICE]; - seq_printf(p, "cpu%d", i); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(user)); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(nice)); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(system)); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(idle)); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(iowait)); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(irq)); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(softirq)); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(steal)); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(guest)); - seq_put_decimal_ull(p, " ", cputime64_to_clock_t(guest_nice)); - seq_putc(p, '\n'); - } - seq_put_decimal_ull(p, "intr ", (unsigned long long)sum); - - /* sum again ? it could be updated? */ - for_each_irq_nr(j) - seq_put_decimal_ull(p, " ", kstat_irqs_usr(j)); - - seq_printf(p, - "\nctxt %llu\n" - "btime %llu\n" - "processes %lu\n" - "procs_running %lu\n" - "procs_blocked %lu\n", - nr_context_switches(), - (unsigned long long)boottime.tv_sec, - total_forks, - nr_running(), - nr_iowait()); - - seq_put_decimal_ull(p, "softirq ", (unsigned long long)sum_softirq); - - for (i = 0; i < NR_SOFTIRQS; i++) - seq_put_decimal_ull(p, " ", per_softirq_sums[i]); - seq_putc(p, '\n'); - - return 0; -} - -static int stat_open(struct inode *inode, struct file *file) -{ - size_t size = 1024 + 128 * num_online_cpus(); - - /* minimum size to display an interrupt count : 2 bytes */ - size += 2 * nr_irqs; - return single_open_size(file, show_stat, NULL, size); -} - -static const struct file_operations proc_stat_operations = { - .open = stat_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init proc_stat_init(void) -{ - proc_create("stat", 0, NULL, &proc_stat_operations); - return 0; -} -fs_initcall(proc_stat_init); diff --git a/src/linux/fs/proc/task_nommu.c b/src/linux/fs/proc/task_nommu.c deleted file mode 100644 index 3717562..0000000 --- a/src/linux/fs/proc/task_nommu.c +++ /dev/null @@ -1,328 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -/* - * Logic: we've got two memory sums for each process, "shared", and - * "non-shared". Shared memory may get counted more than once, for - * each process that owns it. Non-shared memory is counted - * accurately. - */ -void task_mem(struct seq_file *m, struct mm_struct *mm) -{ - struct vm_area_struct *vma; - struct vm_region *region; - struct rb_node *p; - unsigned long bytes = 0, sbytes = 0, slack = 0, size; - - down_read(&mm->mmap_sem); - for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) { - vma = rb_entry(p, struct vm_area_struct, vm_rb); - - bytes += kobjsize(vma); - - region = vma->vm_region; - if (region) { - size = kobjsize(region); - size += region->vm_end - region->vm_start; - } else { - size = vma->vm_end - vma->vm_start; - } - - if (atomic_read(&mm->mm_count) > 1 || - vma->vm_flags & VM_MAYSHARE) { - sbytes += size; - } else { - bytes += size; - if (region) - slack = region->vm_end - vma->vm_end; - } - } - - if (atomic_read(&mm->mm_count) > 1) - sbytes += kobjsize(mm); - else - bytes += kobjsize(mm); - - if (current->fs && current->fs->users > 1) - sbytes += kobjsize(current->fs); - else - bytes += kobjsize(current->fs); - - if (current->files && atomic_read(¤t->files->count) > 1) - sbytes += kobjsize(current->files); - else - bytes += kobjsize(current->files); - - if (current->sighand && atomic_read(¤t->sighand->count) > 1) - sbytes += kobjsize(current->sighand); - else - bytes += kobjsize(current->sighand); - - bytes += kobjsize(current); /* includes kernel stack */ - - seq_printf(m, - "Mem:\t%8lu bytes\n" - "Slack:\t%8lu bytes\n" - "Shared:\t%8lu bytes\n", - bytes, slack, sbytes); - - up_read(&mm->mmap_sem); -} - -unsigned long task_vsize(struct mm_struct *mm) -{ - struct vm_area_struct *vma; - struct rb_node *p; - unsigned long vsize = 0; - - down_read(&mm->mmap_sem); - for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) { - vma = rb_entry(p, struct vm_area_struct, vm_rb); - vsize += vma->vm_end - vma->vm_start; - } - up_read(&mm->mmap_sem); - return vsize; -} - -unsigned long task_statm(struct mm_struct *mm, - unsigned long *shared, unsigned long *text, - unsigned long *data, unsigned long *resident) -{ - struct vm_area_struct *vma; - struct vm_region *region; - struct rb_node *p; - unsigned long size = kobjsize(mm); - - down_read(&mm->mmap_sem); - for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) { - vma = rb_entry(p, struct vm_area_struct, vm_rb); - size += kobjsize(vma); - region = vma->vm_region; - if (region) { - size += kobjsize(region); - size += region->vm_end - region->vm_start; - } - } - - *text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) - >> PAGE_SHIFT; - *data = (PAGE_ALIGN(mm->start_stack) - (mm->start_data & PAGE_MASK)) - >> PAGE_SHIFT; - up_read(&mm->mmap_sem); - size >>= PAGE_SHIFT; - size += *text + *data; - *resident = size; - return size; -} - -static int is_stack(struct proc_maps_private *priv, - struct vm_area_struct *vma) -{ - struct mm_struct *mm = vma->vm_mm; - - /* - * We make no effort to guess what a given thread considers to be - * its "stack". It's not even well-defined for programs written - * languages like Go. - */ - return vma->vm_start <= mm->start_stack && - vma->vm_end >= mm->start_stack; -} - -/* - * display a single VMA to a sequenced file - */ -static int nommu_vma_show(struct seq_file *m, struct vm_area_struct *vma, - int is_pid) -{ - struct mm_struct *mm = vma->vm_mm; - struct proc_maps_private *priv = m->private; - unsigned long ino = 0; - struct file *file; - dev_t dev = 0; - int flags; - unsigned long long pgoff = 0; - - flags = vma->vm_flags; - file = vma->vm_file; - - if (file) { - struct inode *inode = file_inode(vma->vm_file); - dev = inode->i_sb->s_dev; - ino = inode->i_ino; - pgoff = (loff_t)vma->vm_pgoff << PAGE_SHIFT; - } - - seq_setwidth(m, 25 + sizeof(void *) * 6 - 1); - seq_printf(m, - "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ", - vma->vm_start, - vma->vm_end, - flags & VM_READ ? 'r' : '-', - flags & VM_WRITE ? 'w' : '-', - flags & VM_EXEC ? 'x' : '-', - flags & VM_MAYSHARE ? flags & VM_SHARED ? 'S' : 's' : 'p', - pgoff, - MAJOR(dev), MINOR(dev), ino); - - if (file) { - seq_pad(m, ' '); - seq_file_path(m, file, ""); - } else if (mm && is_stack(priv, vma)) { - seq_pad(m, ' '); - seq_printf(m, "[stack]"); - } - - seq_putc(m, '\n'); - return 0; -} - -/* - * display mapping lines for a particular process's /proc/pid/maps - */ -static int show_map(struct seq_file *m, void *_p, int is_pid) -{ - struct rb_node *p = _p; - - return nommu_vma_show(m, rb_entry(p, struct vm_area_struct, vm_rb), - is_pid); -} - -static int show_pid_map(struct seq_file *m, void *_p) -{ - return show_map(m, _p, 1); -} - -static int show_tid_map(struct seq_file *m, void *_p) -{ - return show_map(m, _p, 0); -} - -static void *m_start(struct seq_file *m, loff_t *pos) -{ - struct proc_maps_private *priv = m->private; - struct mm_struct *mm; - struct rb_node *p; - loff_t n = *pos; - - /* pin the task and mm whilst we play with them */ - priv->task = get_proc_task(priv->inode); - if (!priv->task) - return ERR_PTR(-ESRCH); - - mm = priv->mm; - if (!mm || !atomic_inc_not_zero(&mm->mm_users)) - return NULL; - - down_read(&mm->mmap_sem); - /* start from the Nth VMA */ - for (p = rb_first(&mm->mm_rb); p; p = rb_next(p)) - if (n-- == 0) - return p; - - up_read(&mm->mmap_sem); - mmput(mm); - return NULL; -} - -static void m_stop(struct seq_file *m, void *_vml) -{ - struct proc_maps_private *priv = m->private; - - if (!IS_ERR_OR_NULL(_vml)) { - up_read(&priv->mm->mmap_sem); - mmput(priv->mm); - } - if (priv->task) { - put_task_struct(priv->task); - priv->task = NULL; - } -} - -static void *m_next(struct seq_file *m, void *_p, loff_t *pos) -{ - struct rb_node *p = _p; - - (*pos)++; - return p ? rb_next(p) : NULL; -} - -static const struct seq_operations proc_pid_maps_ops = { - .start = m_start, - .next = m_next, - .stop = m_stop, - .show = show_pid_map -}; - -static const struct seq_operations proc_tid_maps_ops = { - .start = m_start, - .next = m_next, - .stop = m_stop, - .show = show_tid_map -}; - -static int maps_open(struct inode *inode, struct file *file, - const struct seq_operations *ops) -{ - struct proc_maps_private *priv; - - priv = __seq_open_private(file, ops, sizeof(*priv)); - if (!priv) - return -ENOMEM; - - priv->inode = inode; - priv->mm = proc_mem_open(inode, PTRACE_MODE_READ); - if (IS_ERR(priv->mm)) { - int err = PTR_ERR(priv->mm); - - seq_release_private(inode, file); - return err; - } - - return 0; -} - - -static int map_release(struct inode *inode, struct file *file) -{ - struct seq_file *seq = file->private_data; - struct proc_maps_private *priv = seq->private; - - if (priv->mm) - mmdrop(priv->mm); - - return seq_release_private(inode, file); -} - -static int pid_maps_open(struct inode *inode, struct file *file) -{ - return maps_open(inode, file, &proc_pid_maps_ops); -} - -static int tid_maps_open(struct inode *inode, struct file *file) -{ - return maps_open(inode, file, &proc_tid_maps_ops); -} - -const struct file_operations proc_pid_maps_operations = { - .open = pid_maps_open, - .read = seq_read, - .llseek = seq_lseek, - .release = map_release, -}; - -const struct file_operations proc_tid_maps_operations = { - .open = tid_maps_open, - .read = seq_read, - .llseek = seq_lseek, - .release = map_release, -}; - diff --git a/src/linux/fs/proc/thread_self.c b/src/linux/fs/proc/thread_self.c deleted file mode 100644 index 595b90a..0000000 --- a/src/linux/fs/proc/thread_self.c +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include -#include -#include "internal.h" - -/* - * /proc/thread_self: - */ -static int proc_thread_self_readlink(struct dentry *dentry, char __user *buffer, - int buflen) -{ - struct pid_namespace *ns = dentry->d_sb->s_fs_info; - pid_t tgid = task_tgid_nr_ns(current, ns); - pid_t pid = task_pid_nr_ns(current, ns); - char tmp[PROC_NUMBUF + 6 + PROC_NUMBUF]; - if (!pid) - return -ENOENT; - sprintf(tmp, "%d/task/%d", tgid, pid); - return readlink_copy(buffer, buflen, tmp); -} - -static const char *proc_thread_self_get_link(struct dentry *dentry, - struct inode *inode, - struct delayed_call *done) -{ - struct pid_namespace *ns = inode->i_sb->s_fs_info; - pid_t tgid = task_tgid_nr_ns(current, ns); - pid_t pid = task_pid_nr_ns(current, ns); - char *name; - - if (!pid) - return ERR_PTR(-ENOENT); - name = kmalloc(PROC_NUMBUF + 6 + PROC_NUMBUF, - dentry ? GFP_KERNEL : GFP_ATOMIC); - if (unlikely(!name)) - return dentry ? ERR_PTR(-ENOMEM) : ERR_PTR(-ECHILD); - sprintf(name, "%d/task/%d", tgid, pid); - set_delayed_call(done, kfree_link, name); - return name; -} - -static const struct inode_operations proc_thread_self_inode_operations = { - .readlink = proc_thread_self_readlink, - .get_link = proc_thread_self_get_link, -}; - -static unsigned thread_self_inum; - -int proc_setup_thread_self(struct super_block *s) -{ - struct inode *root_inode = d_inode(s->s_root); - struct pid_namespace *ns = s->s_fs_info; - struct dentry *thread_self; - - inode_lock(root_inode); - thread_self = d_alloc_name(s->s_root, "thread-self"); - if (thread_self) { - struct inode *inode = new_inode_pseudo(s); - if (inode) { - inode->i_ino = thread_self_inum; - inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); - inode->i_mode = S_IFLNK | S_IRWXUGO; - inode->i_uid = GLOBAL_ROOT_UID; - inode->i_gid = GLOBAL_ROOT_GID; - inode->i_op = &proc_thread_self_inode_operations; - d_add(thread_self, inode); - } else { - dput(thread_self); - thread_self = ERR_PTR(-ENOMEM); - } - } else { - thread_self = ERR_PTR(-ENOMEM); - } - inode_unlock(root_inode); - if (IS_ERR(thread_self)) { - pr_err("proc_fill_super: can't allocate /proc/thread_self\n"); - return PTR_ERR(thread_self); - } - ns->proc_thread_self = thread_self; - return 0; -} - -void __init proc_thread_self_init(void) -{ - proc_alloc_inum(&thread_self_inum); -} diff --git a/src/linux/fs/proc/uptime.c b/src/linux/fs/proc/uptime.c deleted file mode 100644 index 33de567..0000000 --- a/src/linux/fs/proc/uptime.c +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -static int uptime_proc_show(struct seq_file *m, void *v) -{ - struct timespec uptime; - struct timespec idle; - u64 idletime; - u64 nsec; - u32 rem; - int i; - - idletime = 0; - for_each_possible_cpu(i) - idletime += (__force u64) kcpustat_cpu(i).cpustat[CPUTIME_IDLE]; - - get_monotonic_boottime(&uptime); - nsec = cputime64_to_jiffies64(idletime) * TICK_NSEC; - idle.tv_sec = div_u64_rem(nsec, NSEC_PER_SEC, &rem); - idle.tv_nsec = rem; - seq_printf(m, "%lu.%02lu %lu.%02lu\n", - (unsigned long) uptime.tv_sec, - (uptime.tv_nsec / (NSEC_PER_SEC / 100)), - (unsigned long) idle.tv_sec, - (idle.tv_nsec / (NSEC_PER_SEC / 100))); - return 0; -} - -static int uptime_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, uptime_proc_show, NULL); -} - -static const struct file_operations uptime_proc_fops = { - .open = uptime_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init proc_uptime_init(void) -{ - proc_create("uptime", 0, NULL, &uptime_proc_fops); - return 0; -} -fs_initcall(proc_uptime_init); diff --git a/src/linux/fs/proc/version.c b/src/linux/fs/proc/version.c deleted file mode 100644 index d2154eb..0000000 --- a/src/linux/fs/proc/version.c +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include -#include -#include -#include -#include - -static int version_proc_show(struct seq_file *m, void *v) -{ - seq_printf(m, linux_proc_banner, - utsname()->sysname, - utsname()->release, - utsname()->version); - return 0; -} - -static int version_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, version_proc_show, NULL); -} - -static const struct file_operations version_proc_fops = { - .open = version_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init proc_version_init(void) -{ - proc_create("version", 0, NULL, &version_proc_fops); - return 0; -} -fs_initcall(proc_version_init); diff --git a/src/linux/fs/proc_namespace.c b/src/linux/fs/proc_namespace.c deleted file mode 100644 index 3f1190d..0000000 --- a/src/linux/fs/proc_namespace.c +++ /dev/null @@ -1,336 +0,0 @@ -/* - * fs/proc_namespace.c - handling of /proc//{mounts,mountinfo,mountstats} - * - * In fact, that's a piece of procfs; it's *almost* isolated from - * the rest of fs/proc, but has rather close relationships with - * fs/namespace.c, thus here instead of fs/proc - * - */ -#include -#include -#include -#include -#include "proc/internal.h" /* only for get_proc_task() in ->open() */ - -#include "pnode.h" -#include "internal.h" - -static unsigned mounts_poll(struct file *file, poll_table *wait) -{ - struct seq_file *m = file->private_data; - struct proc_mounts *p = m->private; - struct mnt_namespace *ns = p->ns; - unsigned res = POLLIN | POLLRDNORM; - int event; - - poll_wait(file, &p->ns->poll, wait); - - event = ACCESS_ONCE(ns->event); - if (m->poll_event != event) { - m->poll_event = event; - res |= POLLERR | POLLPRI; - } - - return res; -} - -struct proc_fs_info { - int flag; - const char *str; -}; - -static int show_sb_opts(struct seq_file *m, struct super_block *sb) -{ - static const struct proc_fs_info fs_info[] = { - { MS_SYNCHRONOUS, ",sync" }, - { MS_DIRSYNC, ",dirsync" }, - { MS_MANDLOCK, ",mand" }, - { MS_LAZYTIME, ",lazytime" }, - { 0, NULL } - }; - const struct proc_fs_info *fs_infop; - - for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { - if (sb->s_flags & fs_infop->flag) - seq_puts(m, fs_infop->str); - } - - return security_sb_show_options(m, sb); -} - -static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt) -{ - static const struct proc_fs_info mnt_info[] = { - { MNT_NOSUID, ",nosuid" }, - { MNT_NODEV, ",nodev" }, - { MNT_NOEXEC, ",noexec" }, - { MNT_NOATIME, ",noatime" }, - { MNT_NODIRATIME, ",nodiratime" }, - { MNT_RELATIME, ",relatime" }, - { 0, NULL } - }; - const struct proc_fs_info *fs_infop; - - for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) { - if (mnt->mnt_flags & fs_infop->flag) - seq_puts(m, fs_infop->str); - } -} - -static inline void mangle(struct seq_file *m, const char *s) -{ - seq_escape(m, s, " \t\n\\"); -} - -static void show_type(struct seq_file *m, struct super_block *sb) -{ - mangle(m, sb->s_type->name); - if (sb->s_subtype && sb->s_subtype[0]) { - seq_putc(m, '.'); - mangle(m, sb->s_subtype); - } -} - -static int show_vfsmnt(struct seq_file *m, struct vfsmount *mnt) -{ - struct proc_mounts *p = m->private; - struct mount *r = real_mount(mnt); - struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; - struct super_block *sb = mnt_path.dentry->d_sb; - int err; - - if (sb->s_op->show_devname) { - err = sb->s_op->show_devname(m, mnt_path.dentry); - if (err) - goto out; - } else { - mangle(m, r->mnt_devname ? r->mnt_devname : "none"); - } - seq_putc(m, ' '); - /* mountpoints outside of chroot jail will give SEQ_SKIP on this */ - err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\"); - if (err) - goto out; - seq_putc(m, ' '); - show_type(m, sb); - seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw"); - err = show_sb_opts(m, sb); - if (err) - goto out; - show_mnt_opts(m, mnt); - if (sb->s_op->show_options) - err = sb->s_op->show_options(m, mnt_path.dentry); - seq_puts(m, " 0 0\n"); -out: - return err; -} - -static int show_mountinfo(struct seq_file *m, struct vfsmount *mnt) -{ - struct proc_mounts *p = m->private; - struct mount *r = real_mount(mnt); - struct super_block *sb = mnt->mnt_sb; - struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; - int err; - - seq_printf(m, "%i %i %u:%u ", r->mnt_id, r->mnt_parent->mnt_id, - MAJOR(sb->s_dev), MINOR(sb->s_dev)); - if (sb->s_op->show_path) { - err = sb->s_op->show_path(m, mnt->mnt_root); - if (err) - goto out; - } else { - seq_dentry(m, mnt->mnt_root, " \t\n\\"); - } - seq_putc(m, ' '); - - /* mountpoints outside of chroot jail will give SEQ_SKIP on this */ - err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\"); - if (err) - goto out; - - seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw"); - show_mnt_opts(m, mnt); - - /* Tagged fields ("foo:X" or "bar") */ - if (IS_MNT_SHARED(r)) - seq_printf(m, " shared:%i", r->mnt_group_id); - if (IS_MNT_SLAVE(r)) { - int master = r->mnt_master->mnt_group_id; - int dom = get_dominating_id(r, &p->root); - seq_printf(m, " master:%i", master); - if (dom && dom != master) - seq_printf(m, " propagate_from:%i", dom); - } - if (IS_MNT_UNBINDABLE(r)) - seq_puts(m, " unbindable"); - - /* Filesystem specific data */ - seq_puts(m, " - "); - show_type(m, sb); - seq_putc(m, ' '); - if (sb->s_op->show_devname) { - err = sb->s_op->show_devname(m, mnt->mnt_root); - if (err) - goto out; - } else { - mangle(m, r->mnt_devname ? r->mnt_devname : "none"); - } - seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw"); - err = show_sb_opts(m, sb); - if (err) - goto out; - if (sb->s_op->show_options) - err = sb->s_op->show_options(m, mnt->mnt_root); - seq_putc(m, '\n'); -out: - return err; -} - -static int show_vfsstat(struct seq_file *m, struct vfsmount *mnt) -{ - struct proc_mounts *p = m->private; - struct mount *r = real_mount(mnt); - struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; - struct super_block *sb = mnt_path.dentry->d_sb; - int err; - - /* device */ - if (sb->s_op->show_devname) { - seq_puts(m, "device "); - err = sb->s_op->show_devname(m, mnt_path.dentry); - if (err) - goto out; - } else { - if (r->mnt_devname) { - seq_puts(m, "device "); - mangle(m, r->mnt_devname); - } else - seq_puts(m, "no device"); - } - - /* mount point */ - seq_puts(m, " mounted on "); - /* mountpoints outside of chroot jail will give SEQ_SKIP on this */ - err = seq_path_root(m, &mnt_path, &p->root, " \t\n\\"); - if (err) - goto out; - seq_putc(m, ' '); - - /* file system type */ - seq_puts(m, "with fstype "); - show_type(m, sb); - - /* optional statistics */ - if (sb->s_op->show_stats) { - seq_putc(m, ' '); - err = sb->s_op->show_stats(m, mnt_path.dentry); - } - - seq_putc(m, '\n'); -out: - return err; -} - -static int mounts_open_common(struct inode *inode, struct file *file, - int (*show)(struct seq_file *, struct vfsmount *)) -{ - struct task_struct *task = get_proc_task(inode); - struct nsproxy *nsp; - struct mnt_namespace *ns = NULL; - struct path root; - struct proc_mounts *p; - struct seq_file *m; - int ret = -EINVAL; - - if (!task) - goto err; - - task_lock(task); - nsp = task->nsproxy; - if (!nsp || !nsp->mnt_ns) { - task_unlock(task); - put_task_struct(task); - goto err; - } - ns = nsp->mnt_ns; - get_mnt_ns(ns); - if (!task->fs) { - task_unlock(task); - put_task_struct(task); - ret = -ENOENT; - goto err_put_ns; - } - get_fs_root(task->fs, &root); - task_unlock(task); - put_task_struct(task); - - ret = seq_open_private(file, &mounts_op, sizeof(struct proc_mounts)); - if (ret) - goto err_put_path; - - m = file->private_data; - m->poll_event = ns->event; - - p = m->private; - p->ns = ns; - p->root = root; - p->show = show; - p->cached_event = ~0ULL; - - return 0; - - err_put_path: - path_put(&root); - err_put_ns: - put_mnt_ns(ns); - err: - return ret; -} - -static int mounts_release(struct inode *inode, struct file *file) -{ - struct seq_file *m = file->private_data; - struct proc_mounts *p = m->private; - path_put(&p->root); - put_mnt_ns(p->ns); - return seq_release_private(inode, file); -} - -static int mounts_open(struct inode *inode, struct file *file) -{ - return mounts_open_common(inode, file, show_vfsmnt); -} - -static int mountinfo_open(struct inode *inode, struct file *file) -{ - return mounts_open_common(inode, file, show_mountinfo); -} - -static int mountstats_open(struct inode *inode, struct file *file) -{ - return mounts_open_common(inode, file, show_vfsstat); -} - -const struct file_operations proc_mounts_operations = { - .open = mounts_open, - .read = seq_read, - .llseek = seq_lseek, - .release = mounts_release, - .poll = mounts_poll, -}; - -const struct file_operations proc_mountinfo_operations = { - .open = mountinfo_open, - .read = seq_read, - .llseek = seq_lseek, - .release = mounts_release, - .poll = mounts_poll, -}; - -const struct file_operations proc_mountstats_operations = { - .open = mountstats_open, - .read = seq_read, - .llseek = seq_lseek, - .release = mounts_release, -}; diff --git a/src/linux/fs/pstore/Kconfig b/src/linux/fs/pstore/Kconfig deleted file mode 100644 index be40813..0000000 --- a/src/linux/fs/pstore/Kconfig +++ /dev/null @@ -1,89 +0,0 @@ -config PSTORE - tristate "Persistent store support" - default n - help - This option enables generic access to platform level - persistent storage via "pstore" filesystem that can - be mounted as /dev/pstore. Only useful if you have - a platform level driver that registers with pstore to - provide the data, so you probably should just go say "Y" - (or "M") to a platform specific persistent store driver - (e.g. ACPI_APEI on X86) which will select this for you. - If you don't have a platform persistent store driver, - say N. - -choice - prompt "Choose compression algorithm" - depends on PSTORE - default PSTORE_ZLIB_COMPRESS - help - This option chooses compression algorithm. - -config PSTORE_ZLIB_COMPRESS - bool "ZLIB" - select ZLIB_DEFLATE - select ZLIB_INFLATE - help - This option enables ZLIB compression algorithm support. - -config PSTORE_LZO_COMPRESS - bool "LZO" - select LZO_COMPRESS - select LZO_DECOMPRESS - help - This option enables LZO compression algorithm support. - -config PSTORE_LZ4_COMPRESS - bool "LZ4" - select LZ4_COMPRESS - select LZ4_DECOMPRESS - help - This option enables LZ4 compression algorithm support. -endchoice - -config PSTORE_CONSOLE - bool "Log kernel console messages" - depends on PSTORE - help - When the option is enabled, pstore will log all kernel - messages, even if no oops or panic happened. - -config PSTORE_PMSG - bool "Log user space messages" - depends on PSTORE - help - When the option is enabled, pstore will export a character - interface /dev/pmsg0 to log user space messages. On reboot - data can be retrieved from /sys/fs/pstore/pmsg-ramoops-[ID]. - - If unsure, say N. - -config PSTORE_FTRACE - bool "Persistent function tracer" - depends on PSTORE - depends on FUNCTION_TRACER - depends on DEBUG_FS - help - With this option kernel traces function calls into a persistent - ram buffer that can be decoded and dumped after reboot through - pstore filesystem. It can be used to determine what function - was last called before a reset or panic. - - If unsure, say N. - -config PSTORE_RAM - tristate "Log panic/oops to a RAM buffer" - depends on PSTORE - depends on HAS_IOMEM - depends on HAVE_MEMBLOCK - select REED_SOLOMON - select REED_SOLOMON_ENC8 - select REED_SOLOMON_DEC8 - help - This enables panic and oops messages to be logged to a circular - buffer in RAM where it can be read back at some later point. - - Note that for historical reasons, the module will be named - "ramoops.ko". - - For more information, see Documentation/ramoops.txt. diff --git a/src/linux/fs/qnx4/Kconfig b/src/linux/fs/qnx4/Kconfig deleted file mode 100644 index 5f60899..0000000 --- a/src/linux/fs/qnx4/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config QNX4FS_FS - tristate "QNX4 file system support (read only)" - depends on BLOCK - help - This is the file system used by the real-time operating systems - QNX 4 and QNX 6 (the latter is also called QNX RTP). - Further information is available at . - Say Y if you intend to mount QNX hard disks or floppies. - - To compile this file system support as a module, choose M here: the - module will be called qnx4. - - If you don't know whether you need it, then you don't need it: - answer N. diff --git a/src/linux/fs/qnx6/Kconfig b/src/linux/fs/qnx6/Kconfig deleted file mode 100644 index edbba5c..0000000 --- a/src/linux/fs/qnx6/Kconfig +++ /dev/null @@ -1,26 +0,0 @@ -config QNX6FS_FS - tristate "QNX6 file system support (read only)" - depends on BLOCK && CRC32 - help - This is the file system used by the real-time operating systems - QNX 6 (also called QNX RTP). - Further information is available at . - Say Y if you intend to mount QNX hard disks or floppies formatted - with a mkqnx6fs. - However, keep in mind that this currently is a readonly driver! - - To compile this file system support as a module, choose M here: the - module will be called qnx6. - - If you don't know whether you need it, then you don't need it: - answer N. - -config QNX6FS_DEBUG - bool "QNX6 debugging information" - depends on QNX6FS_FS - help - Turns on extended debugging output. - - If you are not a developer working on the QNX6FS, you probably don't - want this: - answer N. diff --git a/src/linux/fs/quota/Kconfig b/src/linux/fs/quota/Kconfig deleted file mode 100644 index 4a09975..0000000 --- a/src/linux/fs/quota/Kconfig +++ /dev/null @@ -1,76 +0,0 @@ -# -# Quota configuration -# - -config QUOTA - bool "Quota support" - select QUOTACTL - select SRCU - help - If you say Y here, you will be able to set per user limits for disk - usage (also called disk quotas). Currently, it works for the - ext2, ext3, ext4, jfs, ocfs2 and reiserfs file systems. - Note that gfs2 and xfs use their own quota system. - Ext3, ext4 and reiserfs also support journaled quotas for which - you don't need to run quotacheck(8) after an unclean shutdown. - For further details, read the Quota mini-HOWTO, available from - , or the documentation provided - with the quota tools. Probably the quota support is only useful for - multi user systems. If unsure, say N. - -config QUOTA_NETLINK_INTERFACE - bool "Report quota messages through netlink interface" - depends on QUOTACTL && NET - help - If you say Y here, quota warnings (about exceeding softlimit, reaching - hardlimit, etc.) will be reported through netlink interface. If unsure, - say Y. - -config PRINT_QUOTA_WARNING - bool "Print quota warnings to console (OBSOLETE)" - depends on QUOTA - default y - help - If you say Y here, quota warnings (about exceeding softlimit, reaching - hardlimit, etc.) will be printed to the process' controlling terminal. - Note that this behavior is currently deprecated and may go away in - future. Please use notification via netlink socket instead. - -config QUOTA_DEBUG - bool "Additional quota sanity checks" - depends on QUOTA - default n - help - If you say Y here, quota subsystem will perform some additional - sanity checks of quota internal structures. If unsure, say N. - -# Generic support for tree structured quota files. Selected when needed. -config QUOTA_TREE - tristate - -config QFMT_V1 - tristate "Old quota format support" - depends on QUOTA - help - This quota format was (is) used by kernels earlier than 2.4.22. If - you have quota working and you don't want to convert to new quota - format say Y here. - -config QFMT_V2 - tristate "Quota format vfsv0 and vfsv1 support" - depends on QUOTA - select QUOTA_TREE - help - This config option enables kernel support for vfsv0 and vfsv1 quota - formats. Both these formats support 32-bit UIDs/GIDs and vfsv1 format - also supports 64-bit inode and block quota limits. If you need this - functionality say Y here. - -config QUOTACTL - bool - default n - -config QUOTACTL_COMPAT - bool - depends on QUOTACTL && COMPAT_FOR_U64_ALIGNMENT - default y diff --git a/src/linux/fs/quota/Makefile b/src/linux/fs/quota/Makefile deleted file mode 100644 index c66c37c..0000000 --- a/src/linux/fs/quota/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -obj-$(CONFIG_QUOTA) += dquot.o -obj-$(CONFIG_QFMT_V1) += quota_v1.o -obj-$(CONFIG_QFMT_V2) += quota_v2.o -obj-$(CONFIG_QUOTA_TREE) += quota_tree.o -obj-$(CONFIG_QUOTACTL) += quota.o kqid.o -obj-$(CONFIG_QUOTACTL_COMPAT) += compat.o -obj-$(CONFIG_QUOTA_NETLINK_INTERFACE) += netlink.o diff --git a/src/linux/fs/ramfs/Makefile b/src/linux/fs/ramfs/Makefile deleted file mode 100644 index c71e65d..0000000 --- a/src/linux/fs/ramfs/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for the linux ramfs routines. -# - -obj-y += ramfs.o - -file-mmu-y := file-nommu.o -file-mmu-$(CONFIG_MMU) := file-mmu.o -ramfs-objs += inode.o $(file-mmu-y) diff --git a/src/linux/fs/ramfs/file-nommu.c b/src/linux/fs/ramfs/file-nommu.c deleted file mode 100644 index 2bcbf4e..0000000 --- a/src/linux/fs/ramfs/file-nommu.c +++ /dev/null @@ -1,268 +0,0 @@ -/* file-nommu.c: no-MMU version of ramfs - * - * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "internal.h" - -static int ramfs_nommu_setattr(struct dentry *, struct iattr *); -static unsigned long ramfs_nommu_get_unmapped_area(struct file *file, - unsigned long addr, - unsigned long len, - unsigned long pgoff, - unsigned long flags); -static int ramfs_nommu_mmap(struct file *file, struct vm_area_struct *vma); - -static unsigned ramfs_mmap_capabilities(struct file *file) -{ - return NOMMU_MAP_DIRECT | NOMMU_MAP_COPY | NOMMU_MAP_READ | - NOMMU_MAP_WRITE | NOMMU_MAP_EXEC; -} - -const struct file_operations ramfs_file_operations = { - .mmap_capabilities = ramfs_mmap_capabilities, - .mmap = ramfs_nommu_mmap, - .get_unmapped_area = ramfs_nommu_get_unmapped_area, - .read_iter = generic_file_read_iter, - .write_iter = generic_file_write_iter, - .fsync = noop_fsync, - .splice_read = generic_file_splice_read, - .splice_write = iter_file_splice_write, - .llseek = generic_file_llseek, -}; - -const struct inode_operations ramfs_file_inode_operations = { - .setattr = ramfs_nommu_setattr, - .getattr = simple_getattr, -}; - -/*****************************************************************************/ -/* - * add a contiguous set of pages into a ramfs inode when it's truncated from - * size 0 on the assumption that it's going to be used for an mmap of shared - * memory - */ -int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize) -{ - unsigned long npages, xpages, loop; - struct page *pages; - unsigned order; - void *data; - int ret; - gfp_t gfp = mapping_gfp_mask(inode->i_mapping); - - /* make various checks */ - order = get_order(newsize); - if (unlikely(order >= MAX_ORDER)) - return -EFBIG; - - ret = inode_newsize_ok(inode, newsize); - if (ret) - return ret; - - i_size_write(inode, newsize); - - /* allocate enough contiguous pages to be able to satisfy the - * request */ - pages = alloc_pages(gfp, order); - if (!pages) - return -ENOMEM; - - /* split the high-order page into an array of single pages */ - xpages = 1UL << order; - npages = (newsize + PAGE_SIZE - 1) >> PAGE_SHIFT; - - split_page(pages, order); - - /* trim off any pages we don't actually require */ - for (loop = npages; loop < xpages; loop++) - __free_page(pages + loop); - - /* clear the memory we allocated */ - newsize = PAGE_SIZE * npages; - data = page_address(pages); - memset(data, 0, newsize); - - /* attach all the pages to the inode's address space */ - for (loop = 0; loop < npages; loop++) { - struct page *page = pages + loop; - - ret = add_to_page_cache_lru(page, inode->i_mapping, loop, - gfp); - if (ret < 0) - goto add_error; - - /* prevent the page from being discarded on memory pressure */ - SetPageDirty(page); - SetPageUptodate(page); - - unlock_page(page); - put_page(page); - } - - return 0; - -add_error: - while (loop < npages) - __free_page(pages + loop++); - return ret; -} - -/*****************************************************************************/ -/* - * - */ -static int ramfs_nommu_resize(struct inode *inode, loff_t newsize, loff_t size) -{ - int ret; - - /* assume a truncate from zero size is going to be for the purposes of - * shared mmap */ - if (size == 0) { - if (unlikely(newsize >> 32)) - return -EFBIG; - - return ramfs_nommu_expand_for_mapping(inode, newsize); - } - - /* check that a decrease in size doesn't cut off any shared mappings */ - if (newsize < size) { - ret = nommu_shrink_inode_mappings(inode, size, newsize); - if (ret < 0) - return ret; - } - - truncate_setsize(inode, newsize); - return 0; -} - -/*****************************************************************************/ -/* - * handle a change of attributes - * - we're specifically interested in a change of size - */ -static int ramfs_nommu_setattr(struct dentry *dentry, struct iattr *ia) -{ - struct inode *inode = d_inode(dentry); - unsigned int old_ia_valid = ia->ia_valid; - int ret = 0; - - /* POSIX UID/GID verification for setting inode attributes */ - ret = setattr_prepare(dentry, ia); - if (ret) - return ret; - - /* pick out size-changing events */ - if (ia->ia_valid & ATTR_SIZE) { - loff_t size = inode->i_size; - - if (ia->ia_size != size) { - ret = ramfs_nommu_resize(inode, ia->ia_size, size); - if (ret < 0 || ia->ia_valid == ATTR_SIZE) - goto out; - } else { - /* we skipped the truncate but must still update - * timestamps - */ - ia->ia_valid |= ATTR_MTIME|ATTR_CTIME; - } - } - - setattr_copy(inode, ia); - out: - ia->ia_valid = old_ia_valid; - return ret; -} - -/*****************************************************************************/ -/* - * try to determine where a shared mapping can be made - * - we require that: - * - the pages to be mapped must exist - * - the pages be physically contiguous in sequence - */ -static unsigned long ramfs_nommu_get_unmapped_area(struct file *file, - unsigned long addr, unsigned long len, - unsigned long pgoff, unsigned long flags) -{ - unsigned long maxpages, lpages, nr, loop, ret; - struct inode *inode = file_inode(file); - struct page **pages = NULL, **ptr, *page; - loff_t isize; - - /* the mapping mustn't extend beyond the EOF */ - lpages = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; - isize = i_size_read(inode); - - ret = -ENOSYS; - maxpages = (isize + PAGE_SIZE - 1) >> PAGE_SHIFT; - if (pgoff >= maxpages) - goto out; - - if (maxpages - pgoff < lpages) - goto out; - - /* gang-find the pages */ - pages = kcalloc(lpages, sizeof(struct page *), GFP_KERNEL); - if (!pages) - goto out_free; - - nr = find_get_pages(inode->i_mapping, pgoff, lpages, pages); - if (nr != lpages) - goto out_free_pages; /* leave if some pages were missing */ - - /* check the pages for physical adjacency */ - ptr = pages; - page = *ptr++; - page++; - for (loop = lpages; loop > 1; loop--) - if (*ptr++ != page++) - goto out_free_pages; - - /* okay - all conditions fulfilled */ - ret = (unsigned long) page_address(pages[0]); - -out_free_pages: - ptr = pages; - for (loop = nr; loop > 0; loop--) - put_page(*ptr++); -out_free: - kfree(pages); -out: - return ret; -} - -/*****************************************************************************/ -/* - * set up a mapping for shared memory segments - */ -static int ramfs_nommu_mmap(struct file *file, struct vm_area_struct *vma) -{ - if (!(vma->vm_flags & (VM_SHARED | VM_MAYSHARE))) - return -ENOSYS; - - file_accessed(file); - vma->vm_ops = &generic_file_vm_ops; - return 0; -} diff --git a/src/linux/fs/ramfs/inode.c b/src/linux/fs/ramfs/inode.c deleted file mode 100644 index 8621c03..0000000 --- a/src/linux/fs/ramfs/inode.c +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Resizable simple ram filesystem for Linux. - * - * Copyright (C) 2000 Linus Torvalds. - * 2000 Transmeta Corp. - * - * Usage limits added by David Gibson, Linuxcare Australia. - * This file is released under the GPL. - */ - -/* - * NOTE! This filesystem is probably most useful - * not as a real filesystem, but as an example of - * how virtual filesystems can be written. - * - * It doesn't get much simpler than this. Consider - * that this file implements the full semantics of - * a POSIX-compliant read-write filesystem. - * - * Note in particular how the filesystem does not - * need to implement any data structures of its own - * to keep track of the virtual data: using the VFS - * caches is sufficient. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -#define RAMFS_DEFAULT_MODE 0755 - -static const struct super_operations ramfs_ops; -static const struct inode_operations ramfs_dir_inode_operations; - -static const struct address_space_operations ramfs_aops = { - .readpage = simple_readpage, - .write_begin = simple_write_begin, - .write_end = simple_write_end, - .set_page_dirty = __set_page_dirty_no_writeback, -}; - -struct inode *ramfs_get_inode(struct super_block *sb, - const struct inode *dir, umode_t mode, dev_t dev) -{ - struct inode * inode = new_inode(sb); - - if (inode) { - inode->i_ino = get_next_ino(); - inode_init_owner(inode, dir, mode); - inode->i_mapping->a_ops = &ramfs_aops; - mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER); - mapping_set_unevictable(inode->i_mapping); - inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); - switch (mode & S_IFMT) { - default: - init_special_inode(inode, mode, dev); - break; - case S_IFREG: - inode->i_op = &ramfs_file_inode_operations; - inode->i_fop = &ramfs_file_operations; - break; - case S_IFDIR: - inode->i_op = &ramfs_dir_inode_operations; - inode->i_fop = &simple_dir_operations; - - /* directory inodes start off with i_nlink == 2 (for "." entry) */ - inc_nlink(inode); - break; - case S_IFLNK: - inode->i_op = &page_symlink_inode_operations; - inode_nohighmem(inode); - break; - } - } - return inode; -} - -/* - * File creation. Allocate an inode, and we're done.. - */ -/* SMP-safe */ -static int -ramfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) -{ - struct inode * inode = ramfs_get_inode(dir->i_sb, dir, mode, dev); - int error = -ENOSPC; - - if (inode) { - d_instantiate(dentry, inode); - dget(dentry); /* Extra count - pin the dentry in core */ - error = 0; - dir->i_mtime = dir->i_ctime = current_time(dir); - } - return error; -} - -static int ramfs_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode) -{ - int retval = ramfs_mknod(dir, dentry, mode | S_IFDIR, 0); - if (!retval) - inc_nlink(dir); - return retval; -} - -static int ramfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) -{ - return ramfs_mknod(dir, dentry, mode | S_IFREG, 0); -} - -static int ramfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname) -{ - struct inode *inode; - int error = -ENOSPC; - - inode = ramfs_get_inode(dir->i_sb, dir, S_IFLNK|S_IRWXUGO, 0); - if (inode) { - int l = strlen(symname)+1; - error = page_symlink(inode, symname, l); - if (!error) { - d_instantiate(dentry, inode); - dget(dentry); - dir->i_mtime = dir->i_ctime = current_time(dir); - } else - iput(inode); - } - return error; -} - -static const struct inode_operations ramfs_dir_inode_operations = { - .create = ramfs_create, - .lookup = simple_lookup, - .link = simple_link, - .unlink = simple_unlink, - .symlink = ramfs_symlink, - .mkdir = ramfs_mkdir, - .rmdir = simple_rmdir, - .mknod = ramfs_mknod, - .rename = simple_rename, -}; - -static const struct super_operations ramfs_ops = { - .statfs = simple_statfs, - .drop_inode = generic_delete_inode, - .show_options = generic_show_options, -}; - -struct ramfs_mount_opts { - umode_t mode; -}; - -enum { - Opt_mode, - Opt_err -}; - -static const match_table_t tokens = { - {Opt_mode, "mode=%o"}, - {Opt_err, NULL} -}; - -struct ramfs_fs_info { - struct ramfs_mount_opts mount_opts; -}; - -static int ramfs_parse_options(char *data, struct ramfs_mount_opts *opts) -{ - substring_t args[MAX_OPT_ARGS]; - int option; - int token; - char *p; - - opts->mode = RAMFS_DEFAULT_MODE; - - while ((p = strsep(&data, ",")) != NULL) { - if (!*p) - continue; - - token = match_token(p, tokens, args); - switch (token) { - case Opt_mode: - if (match_octal(&args[0], &option)) - return -EINVAL; - opts->mode = option & S_IALLUGO; - break; - /* - * We might like to report bad mount options here; - * but traditionally ramfs has ignored all mount options, - * and as it is used as a !CONFIG_SHMEM simple substitute - * for tmpfs, better continue to ignore other mount options. - */ - } - } - - return 0; -} - -int ramfs_fill_super(struct super_block *sb, void *data, int silent) -{ - struct ramfs_fs_info *fsi; - struct inode *inode; - int err; - - save_mount_options(sb, data); - - fsi = kzalloc(sizeof(struct ramfs_fs_info), GFP_KERNEL); - sb->s_fs_info = fsi; - if (!fsi) - return -ENOMEM; - - err = ramfs_parse_options(data, &fsi->mount_opts); - if (err) - return err; - - sb->s_maxbytes = MAX_LFS_FILESIZE; - sb->s_blocksize = PAGE_SIZE; - sb->s_blocksize_bits = PAGE_SHIFT; - sb->s_magic = RAMFS_MAGIC; - sb->s_op = &ramfs_ops; - sb->s_time_gran = 1; - - inode = ramfs_get_inode(sb, NULL, S_IFDIR | fsi->mount_opts.mode, 0); - sb->s_root = d_make_root(inode); - if (!sb->s_root) - return -ENOMEM; - - return 0; -} - -struct dentry *ramfs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_nodev(fs_type, flags, data, ramfs_fill_super); -} - -static void ramfs_kill_sb(struct super_block *sb) -{ - kfree(sb->s_fs_info); - kill_litter_super(sb); -} - -static struct file_system_type ramfs_fs_type = { - .name = "ramfs", - .mount = ramfs_mount, - .kill_sb = ramfs_kill_sb, - .fs_flags = FS_USERNS_MOUNT, -}; - -int __init init_ramfs_fs(void) -{ - static unsigned long once; - - if (test_and_set_bit(0, &once)) - return 0; - return register_filesystem(&ramfs_fs_type); -} -fs_initcall(init_ramfs_fs); diff --git a/src/linux/fs/ramfs/internal.h b/src/linux/fs/ramfs/internal.h deleted file mode 100644 index a9d8ae8..0000000 --- a/src/linux/fs/ramfs/internal.h +++ /dev/null @@ -1,13 +0,0 @@ -/* internal.h: ramfs internal definitions - * - * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - - -extern const struct inode_operations ramfs_file_inode_operations; diff --git a/src/linux/fs/read_write.c b/src/linux/fs/read_write.c deleted file mode 100644 index 190e0d3..0000000 --- a/src/linux/fs/read_write.c +++ /dev/null @@ -1,1805 +0,0 @@ -/* - * linux/fs/read_write.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -#include -#include - -typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *); -typedef ssize_t (*iter_fn_t)(struct kiocb *, struct iov_iter *); - -const struct file_operations generic_ro_fops = { - .llseek = generic_file_llseek, - .read_iter = generic_file_read_iter, - .mmap = generic_file_readonly_mmap, - .splice_read = generic_file_splice_read, -}; - -EXPORT_SYMBOL(generic_ro_fops); - -static inline int unsigned_offsets(struct file *file) -{ - return file->f_mode & FMODE_UNSIGNED_OFFSET; -} - -/** - * vfs_setpos - update the file offset for lseek - * @file: file structure in question - * @offset: file offset to seek to - * @maxsize: maximum file size - * - * This is a low-level filesystem helper for updating the file offset to - * the value specified by @offset if the given offset is valid and it is - * not equal to the current file offset. - * - * Return the specified offset on success and -EINVAL on invalid offset. - */ -loff_t vfs_setpos(struct file *file, loff_t offset, loff_t maxsize) -{ - if (offset < 0 && !unsigned_offsets(file)) - return -EINVAL; - if (offset > maxsize) - return -EINVAL; - - if (offset != file->f_pos) { - file->f_pos = offset; - file->f_version = 0; - } - return offset; -} -EXPORT_SYMBOL(vfs_setpos); - -/** - * generic_file_llseek_size - generic llseek implementation for regular files - * @file: file structure to seek on - * @offset: file offset to seek to - * @whence: type of seek - * @size: max size of this file in file system - * @eof: offset used for SEEK_END position - * - * This is a variant of generic_file_llseek that allows passing in a custom - * maximum file size and a custom EOF position, for e.g. hashed directories - * - * Synchronization: - * SEEK_SET and SEEK_END are unsynchronized (but atomic on 64bit platforms) - * SEEK_CUR is synchronized against other SEEK_CURs, but not read/writes. - * read/writes behave like SEEK_SET against seeks. - */ -loff_t -generic_file_llseek_size(struct file *file, loff_t offset, int whence, - loff_t maxsize, loff_t eof) -{ - switch (whence) { - case SEEK_END: - offset += eof; - break; - case SEEK_CUR: - /* - * Here we special-case the lseek(fd, 0, SEEK_CUR) - * position-querying operation. Avoid rewriting the "same" - * f_pos value back to the file because a concurrent read(), - * write() or lseek() might have altered it - */ - if (offset == 0) - return file->f_pos; - /* - * f_lock protects against read/modify/write race with other - * SEEK_CURs. Note that parallel writes and reads behave - * like SEEK_SET. - */ - spin_lock(&file->f_lock); - offset = vfs_setpos(file, file->f_pos + offset, maxsize); - spin_unlock(&file->f_lock); - return offset; - case SEEK_DATA: - /* - * In the generic case the entire file is data, so as long as - * offset isn't at the end of the file then the offset is data. - */ - if (offset >= eof) - return -ENXIO; - break; - case SEEK_HOLE: - /* - * There is a virtual hole at the end of the file, so as long as - * offset isn't i_size or larger, return i_size. - */ - if (offset >= eof) - return -ENXIO; - offset = eof; - break; - } - - return vfs_setpos(file, offset, maxsize); -} -EXPORT_SYMBOL(generic_file_llseek_size); - -/** - * generic_file_llseek - generic llseek implementation for regular files - * @file: file structure to seek on - * @offset: file offset to seek to - * @whence: type of seek - * - * This is a generic implemenation of ->llseek useable for all normal local - * filesystems. It just updates the file offset to the value specified by - * @offset and @whence. - */ -loff_t generic_file_llseek(struct file *file, loff_t offset, int whence) -{ - struct inode *inode = file->f_mapping->host; - - return generic_file_llseek_size(file, offset, whence, - inode->i_sb->s_maxbytes, - i_size_read(inode)); -} -EXPORT_SYMBOL(generic_file_llseek); - -/** - * fixed_size_llseek - llseek implementation for fixed-sized devices - * @file: file structure to seek on - * @offset: file offset to seek to - * @whence: type of seek - * @size: size of the file - * - */ -loff_t fixed_size_llseek(struct file *file, loff_t offset, int whence, loff_t size) -{ - switch (whence) { - case SEEK_SET: case SEEK_CUR: case SEEK_END: - return generic_file_llseek_size(file, offset, whence, - size, size); - default: - return -EINVAL; - } -} -EXPORT_SYMBOL(fixed_size_llseek); - -/** - * no_seek_end_llseek - llseek implementation for fixed-sized devices - * @file: file structure to seek on - * @offset: file offset to seek to - * @whence: type of seek - * - */ -loff_t no_seek_end_llseek(struct file *file, loff_t offset, int whence) -{ - switch (whence) { - case SEEK_SET: case SEEK_CUR: - return generic_file_llseek_size(file, offset, whence, - OFFSET_MAX, 0); - default: - return -EINVAL; - } -} -EXPORT_SYMBOL(no_seek_end_llseek); - -/** - * no_seek_end_llseek_size - llseek implementation for fixed-sized devices - * @file: file structure to seek on - * @offset: file offset to seek to - * @whence: type of seek - * @size: maximal offset allowed - * - */ -loff_t no_seek_end_llseek_size(struct file *file, loff_t offset, int whence, loff_t size) -{ - switch (whence) { - case SEEK_SET: case SEEK_CUR: - return generic_file_llseek_size(file, offset, whence, - size, 0); - default: - return -EINVAL; - } -} -EXPORT_SYMBOL(no_seek_end_llseek_size); - -/** - * noop_llseek - No Operation Performed llseek implementation - * @file: file structure to seek on - * @offset: file offset to seek to - * @whence: type of seek - * - * This is an implementation of ->llseek useable for the rare special case when - * userspace expects the seek to succeed but the (device) file is actually not - * able to perform the seek. In this case you use noop_llseek() instead of - * falling back to the default implementation of ->llseek. - */ -loff_t noop_llseek(struct file *file, loff_t offset, int whence) -{ - return file->f_pos; -} -EXPORT_SYMBOL(noop_llseek); - -loff_t no_llseek(struct file *file, loff_t offset, int whence) -{ - return -ESPIPE; -} -EXPORT_SYMBOL(no_llseek); - -loff_t default_llseek(struct file *file, loff_t offset, int whence) -{ - struct inode *inode = file_inode(file); - loff_t retval; - - inode_lock(inode); - switch (whence) { - case SEEK_END: - offset += i_size_read(inode); - break; - case SEEK_CUR: - if (offset == 0) { - retval = file->f_pos; - goto out; - } - offset += file->f_pos; - break; - case SEEK_DATA: - /* - * In the generic case the entire file is data, so as - * long as offset isn't at the end of the file then the - * offset is data. - */ - if (offset >= inode->i_size) { - retval = -ENXIO; - goto out; - } - break; - case SEEK_HOLE: - /* - * There is a virtual hole at the end of the file, so - * as long as offset isn't i_size or larger, return - * i_size. - */ - if (offset >= inode->i_size) { - retval = -ENXIO; - goto out; - } - offset = inode->i_size; - break; - } - retval = -EINVAL; - if (offset >= 0 || unsigned_offsets(file)) { - if (offset != file->f_pos) { - file->f_pos = offset; - file->f_version = 0; - } - retval = offset; - } -out: - inode_unlock(inode); - return retval; -} -EXPORT_SYMBOL(default_llseek); - -loff_t vfs_llseek(struct file *file, loff_t offset, int whence) -{ - loff_t (*fn)(struct file *, loff_t, int); - - fn = no_llseek; - if (file->f_mode & FMODE_LSEEK) { - if (file->f_op->llseek) - fn = file->f_op->llseek; - } - return fn(file, offset, whence); -} -EXPORT_SYMBOL(vfs_llseek); - -SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence) -{ - off_t retval; - struct fd f = fdget_pos(fd); - if (!f.file) - return -EBADF; - - retval = -EINVAL; - if (whence <= SEEK_MAX) { - loff_t res = vfs_llseek(f.file, offset, whence); - retval = res; - if (res != (loff_t)retval) - retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */ - } - fdput_pos(f); - return retval; -} - -#ifdef CONFIG_COMPAT -COMPAT_SYSCALL_DEFINE3(lseek, unsigned int, fd, compat_off_t, offset, unsigned int, whence) -{ - return sys_lseek(fd, offset, whence); -} -#endif - -#ifdef __ARCH_WANT_SYS_LLSEEK -SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high, - unsigned long, offset_low, loff_t __user *, result, - unsigned int, whence) -{ - int retval; - struct fd f = fdget_pos(fd); - loff_t offset; - - if (!f.file) - return -EBADF; - - retval = -EINVAL; - if (whence > SEEK_MAX) - goto out_putf; - - offset = vfs_llseek(f.file, ((loff_t) offset_high << 32) | offset_low, - whence); - - retval = (int)offset; - if (offset >= 0) { - retval = -EFAULT; - if (!copy_to_user(result, &offset, sizeof(offset))) - retval = 0; - } -out_putf: - fdput_pos(f); - return retval; -} -#endif - -ssize_t vfs_iter_read(struct file *file, struct iov_iter *iter, loff_t *ppos) -{ - struct kiocb kiocb; - ssize_t ret; - - if (!file->f_op->read_iter) - return -EINVAL; - - init_sync_kiocb(&kiocb, file); - kiocb.ki_pos = *ppos; - - iter->type |= READ; - ret = file->f_op->read_iter(&kiocb, iter); - BUG_ON(ret == -EIOCBQUEUED); - if (ret > 0) - *ppos = kiocb.ki_pos; - return ret; -} -EXPORT_SYMBOL(vfs_iter_read); - -ssize_t vfs_iter_write(struct file *file, struct iov_iter *iter, loff_t *ppos) -{ - struct kiocb kiocb; - ssize_t ret; - - if (!file->f_op->write_iter) - return -EINVAL; - - init_sync_kiocb(&kiocb, file); - kiocb.ki_pos = *ppos; - - iter->type |= WRITE; - ret = file->f_op->write_iter(&kiocb, iter); - BUG_ON(ret == -EIOCBQUEUED); - if (ret > 0) - *ppos = kiocb.ki_pos; - return ret; -} -EXPORT_SYMBOL(vfs_iter_write); - -int rw_verify_area(int read_write, struct file *file, const loff_t *ppos, size_t count) -{ - struct inode *inode; - loff_t pos; - int retval = -EINVAL; - - inode = file_inode(file); - if (unlikely((ssize_t) count < 0)) - return retval; - pos = *ppos; - if (unlikely(pos < 0)) { - if (!unsigned_offsets(file)) - return retval; - if (count >= -pos) /* both values are in 0..LLONG_MAX */ - return -EOVERFLOW; - } else if (unlikely((loff_t) (pos + count) < 0)) { - if (!unsigned_offsets(file)) - return retval; - } - - if (unlikely(inode->i_flctx && mandatory_lock(inode))) { - retval = locks_mandatory_area(inode, file, pos, pos + count - 1, - read_write == READ ? F_RDLCK : F_WRLCK); - if (retval < 0) - return retval; - } - return security_file_permission(file, - read_write == READ ? MAY_READ : MAY_WRITE); -} - -static ssize_t new_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) -{ - struct iovec iov = { .iov_base = buf, .iov_len = len }; - struct kiocb kiocb; - struct iov_iter iter; - ssize_t ret; - - init_sync_kiocb(&kiocb, filp); - kiocb.ki_pos = *ppos; - iov_iter_init(&iter, READ, &iov, 1, len); - - ret = filp->f_op->read_iter(&kiocb, &iter); - BUG_ON(ret == -EIOCBQUEUED); - *ppos = kiocb.ki_pos; - return ret; -} - -ssize_t __vfs_read(struct file *file, char __user *buf, size_t count, - loff_t *pos) -{ - if (file->f_op->read) - return file->f_op->read(file, buf, count, pos); - else if (file->f_op->read_iter) - return new_sync_read(file, buf, count, pos); - else - return -EINVAL; -} -EXPORT_SYMBOL(__vfs_read); - -ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) -{ - ssize_t ret; - - if (!(file->f_mode & FMODE_READ)) - return -EBADF; - if (!(file->f_mode & FMODE_CAN_READ)) - return -EINVAL; - if (unlikely(!access_ok(VERIFY_WRITE, buf, count))) - return -EFAULT; - - ret = rw_verify_area(READ, file, pos, count); - if (!ret) { - if (count > MAX_RW_COUNT) - count = MAX_RW_COUNT; - ret = __vfs_read(file, buf, count, pos); - if (ret > 0) { - fsnotify_access(file); - add_rchar(current, ret); - } - inc_syscr(current); - } - - return ret; -} - -EXPORT_SYMBOL(vfs_read); - -static ssize_t new_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos) -{ - struct iovec iov = { .iov_base = (void __user *)buf, .iov_len = len }; - struct kiocb kiocb; - struct iov_iter iter; - ssize_t ret; - - init_sync_kiocb(&kiocb, filp); - kiocb.ki_pos = *ppos; - iov_iter_init(&iter, WRITE, &iov, 1, len); - - ret = filp->f_op->write_iter(&kiocb, &iter); - BUG_ON(ret == -EIOCBQUEUED); - if (ret > 0) - *ppos = kiocb.ki_pos; - return ret; -} - -ssize_t __vfs_write(struct file *file, const char __user *p, size_t count, - loff_t *pos) -{ - if (file->f_op->write) - return file->f_op->write(file, p, count, pos); - else if (file->f_op->write_iter) - return new_sync_write(file, p, count, pos); - else - return -EINVAL; -} -EXPORT_SYMBOL(__vfs_write); - -ssize_t __kernel_write(struct file *file, const char *buf, size_t count, loff_t *pos) -{ - mm_segment_t old_fs; - const char __user *p; - ssize_t ret; - - if (!(file->f_mode & FMODE_CAN_WRITE)) - return -EINVAL; - - old_fs = get_fs(); - set_fs(get_ds()); - p = (__force const char __user *)buf; - if (count > MAX_RW_COUNT) - count = MAX_RW_COUNT; - ret = __vfs_write(file, p, count, pos); - set_fs(old_fs); - if (ret > 0) { - fsnotify_modify(file); - add_wchar(current, ret); - } - inc_syscw(current); - return ret; -} - -EXPORT_SYMBOL(__kernel_write); - -ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) -{ - ssize_t ret; - - if (!(file->f_mode & FMODE_WRITE)) - return -EBADF; - if (!(file->f_mode & FMODE_CAN_WRITE)) - return -EINVAL; - if (unlikely(!access_ok(VERIFY_READ, buf, count))) - return -EFAULT; - - ret = rw_verify_area(WRITE, file, pos, count); - if (!ret) { - if (count > MAX_RW_COUNT) - count = MAX_RW_COUNT; - file_start_write(file); - ret = __vfs_write(file, buf, count, pos); - if (ret > 0) { - fsnotify_modify(file); - add_wchar(current, ret); - } - inc_syscw(current); - file_end_write(file); - } - - return ret; -} - -EXPORT_SYMBOL(vfs_write); - -static inline loff_t file_pos_read(struct file *file) -{ - return file->f_pos; -} - -static inline void file_pos_write(struct file *file, loff_t pos) -{ - file->f_pos = pos; -} - -SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) -{ - struct fd f = fdget_pos(fd); - ssize_t ret = -EBADF; - - if (f.file) { - loff_t pos = file_pos_read(f.file); - ret = vfs_read(f.file, buf, count, &pos); - if (ret >= 0) - file_pos_write(f.file, pos); - fdput_pos(f); - } - return ret; -} - -SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, - size_t, count) -{ - struct fd f = fdget_pos(fd); - ssize_t ret = -EBADF; - - if (f.file) { - loff_t pos = file_pos_read(f.file); - ret = vfs_write(f.file, buf, count, &pos); - if (ret >= 0) - file_pos_write(f.file, pos); - fdput_pos(f); - } - - return ret; -} - -SYSCALL_DEFINE4(pread64, unsigned int, fd, char __user *, buf, - size_t, count, loff_t, pos) -{ - struct fd f; - ssize_t ret = -EBADF; - - if (pos < 0) - return -EINVAL; - - f = fdget(fd); - if (f.file) { - ret = -ESPIPE; - if (f.file->f_mode & FMODE_PREAD) - ret = vfs_read(f.file, buf, count, &pos); - fdput(f); - } - - return ret; -} - -SYSCALL_DEFINE4(pwrite64, unsigned int, fd, const char __user *, buf, - size_t, count, loff_t, pos) -{ - struct fd f; - ssize_t ret = -EBADF; - - if (pos < 0) - return -EINVAL; - - f = fdget(fd); - if (f.file) { - ret = -ESPIPE; - if (f.file->f_mode & FMODE_PWRITE) - ret = vfs_write(f.file, buf, count, &pos); - fdput(f); - } - - return ret; -} - -/* - * Reduce an iovec's length in-place. Return the resulting number of segments - */ -unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to) -{ - unsigned long seg = 0; - size_t len = 0; - - while (seg < nr_segs) { - seg++; - if (len + iov->iov_len >= to) { - iov->iov_len = to - len; - break; - } - len += iov->iov_len; - iov++; - } - return seg; -} -EXPORT_SYMBOL(iov_shorten); - -static ssize_t do_iter_readv_writev(struct file *filp, struct iov_iter *iter, - loff_t *ppos, iter_fn_t fn, int flags) -{ - struct kiocb kiocb; - ssize_t ret; - - if (flags & ~(RWF_HIPRI | RWF_DSYNC | RWF_SYNC)) - return -EOPNOTSUPP; - - init_sync_kiocb(&kiocb, filp); - if (flags & RWF_HIPRI) - kiocb.ki_flags |= IOCB_HIPRI; - if (flags & RWF_DSYNC) - kiocb.ki_flags |= IOCB_DSYNC; - if (flags & RWF_SYNC) - kiocb.ki_flags |= (IOCB_DSYNC | IOCB_SYNC); - kiocb.ki_pos = *ppos; - - ret = fn(&kiocb, iter); - BUG_ON(ret == -EIOCBQUEUED); - *ppos = kiocb.ki_pos; - return ret; -} - -/* Do it by hand, with file-ops */ -static ssize_t do_loop_readv_writev(struct file *filp, struct iov_iter *iter, - loff_t *ppos, io_fn_t fn, int flags) -{ - ssize_t ret = 0; - - if (flags & ~RWF_HIPRI) - return -EOPNOTSUPP; - - while (iov_iter_count(iter)) { - struct iovec iovec = iov_iter_iovec(iter); - ssize_t nr; - - nr = fn(filp, iovec.iov_base, iovec.iov_len, ppos); - - if (nr < 0) { - if (!ret) - ret = nr; - break; - } - ret += nr; - if (nr != iovec.iov_len) - break; - iov_iter_advance(iter, nr); - } - - return ret; -} - -/* A write operation does a read from user space and vice versa */ -#define vrfy_dir(type) ((type) == READ ? VERIFY_WRITE : VERIFY_READ) - -/** - * rw_copy_check_uvector() - Copy an array of &struct iovec from userspace - * into the kernel and check that it is valid. - * - * @type: One of %CHECK_IOVEC_ONLY, %READ, or %WRITE. - * @uvector: Pointer to the userspace array. - * @nr_segs: Number of elements in userspace array. - * @fast_segs: Number of elements in @fast_pointer. - * @fast_pointer: Pointer to (usually small on-stack) kernel array. - * @ret_pointer: (output parameter) Pointer to a variable that will point to - * either @fast_pointer, a newly allocated kernel array, or NULL, - * depending on which array was used. - * - * This function copies an array of &struct iovec of @nr_segs from - * userspace into the kernel and checks that each element is valid (e.g. - * it does not point to a kernel address or cause overflow by being too - * large, etc.). - * - * As an optimization, the caller may provide a pointer to a small - * on-stack array in @fast_pointer, typically %UIO_FASTIOV elements long - * (the size of this array, or 0 if unused, should be given in @fast_segs). - * - * @ret_pointer will always point to the array that was used, so the - * caller must take care not to call kfree() on it e.g. in case the - * @fast_pointer array was used and it was allocated on the stack. - * - * Return: The total number of bytes covered by the iovec array on success - * or a negative error code on error. - */ -ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, - unsigned long nr_segs, unsigned long fast_segs, - struct iovec *fast_pointer, - struct iovec **ret_pointer) -{ - unsigned long seg; - ssize_t ret; - struct iovec *iov = fast_pointer; - - /* - * SuS says "The readv() function *may* fail if the iovcnt argument - * was less than or equal to 0, or greater than {IOV_MAX}. Linux has - * traditionally returned zero for zero segments, so... - */ - if (nr_segs == 0) { - ret = 0; - goto out; - } - - /* - * First get the "struct iovec" from user memory and - * verify all the pointers - */ - if (nr_segs > UIO_MAXIOV) { - ret = -EINVAL; - goto out; - } - if (nr_segs > fast_segs) { - iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL); - if (iov == NULL) { - ret = -ENOMEM; - goto out; - } - } - if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector))) { - ret = -EFAULT; - goto out; - } - - /* - * According to the Single Unix Specification we should return EINVAL - * if an element length is < 0 when cast to ssize_t or if the - * total length would overflow the ssize_t return value of the - * system call. - * - * Linux caps all read/write calls to MAX_RW_COUNT, and avoids the - * overflow case. - */ - ret = 0; - for (seg = 0; seg < nr_segs; seg++) { - void __user *buf = iov[seg].iov_base; - ssize_t len = (ssize_t)iov[seg].iov_len; - - /* see if we we're about to use an invalid len or if - * it's about to overflow ssize_t */ - if (len < 0) { - ret = -EINVAL; - goto out; - } - if (type >= 0 - && unlikely(!access_ok(vrfy_dir(type), buf, len))) { - ret = -EFAULT; - goto out; - } - if (len > MAX_RW_COUNT - ret) { - len = MAX_RW_COUNT - ret; - iov[seg].iov_len = len; - } - ret += len; - } -out: - *ret_pointer = iov; - return ret; -} - -static ssize_t do_readv_writev(int type, struct file *file, - const struct iovec __user * uvector, - unsigned long nr_segs, loff_t *pos, - int flags) -{ - size_t tot_len; - struct iovec iovstack[UIO_FASTIOV]; - struct iovec *iov = iovstack; - struct iov_iter iter; - ssize_t ret; - io_fn_t fn; - iter_fn_t iter_fn; - - ret = import_iovec(type, uvector, nr_segs, - ARRAY_SIZE(iovstack), &iov, &iter); - if (ret < 0) - return ret; - - tot_len = iov_iter_count(&iter); - if (!tot_len) - goto out; - ret = rw_verify_area(type, file, pos, tot_len); - if (ret < 0) - goto out; - - if (type == READ) { - fn = file->f_op->read; - iter_fn = file->f_op->read_iter; - } else { - fn = (io_fn_t)file->f_op->write; - iter_fn = file->f_op->write_iter; - file_start_write(file); - } - - if (iter_fn) - ret = do_iter_readv_writev(file, &iter, pos, iter_fn, flags); - else - ret = do_loop_readv_writev(file, &iter, pos, fn, flags); - - if (type != READ) - file_end_write(file); - -out: - kfree(iov); - if ((ret + (type == READ)) > 0) { - if (type == READ) - fsnotify_access(file); - else - fsnotify_modify(file); - } - return ret; -} - -ssize_t vfs_readv(struct file *file, const struct iovec __user *vec, - unsigned long vlen, loff_t *pos, int flags) -{ - if (!(file->f_mode & FMODE_READ)) - return -EBADF; - if (!(file->f_mode & FMODE_CAN_READ)) - return -EINVAL; - - return do_readv_writev(READ, file, vec, vlen, pos, flags); -} - -EXPORT_SYMBOL(vfs_readv); - -ssize_t vfs_writev(struct file *file, const struct iovec __user *vec, - unsigned long vlen, loff_t *pos, int flags) -{ - if (!(file->f_mode & FMODE_WRITE)) - return -EBADF; - if (!(file->f_mode & FMODE_CAN_WRITE)) - return -EINVAL; - - return do_readv_writev(WRITE, file, vec, vlen, pos, flags); -} - -EXPORT_SYMBOL(vfs_writev); - -static ssize_t do_readv(unsigned long fd, const struct iovec __user *vec, - unsigned long vlen, int flags) -{ - struct fd f = fdget_pos(fd); - ssize_t ret = -EBADF; - - if (f.file) { - loff_t pos = file_pos_read(f.file); - ret = vfs_readv(f.file, vec, vlen, &pos, flags); - if (ret >= 0) - file_pos_write(f.file, pos); - fdput_pos(f); - } - - if (ret > 0) - add_rchar(current, ret); - inc_syscr(current); - return ret; -} - -static ssize_t do_writev(unsigned long fd, const struct iovec __user *vec, - unsigned long vlen, int flags) -{ - struct fd f = fdget_pos(fd); - ssize_t ret = -EBADF; - - if (f.file) { - loff_t pos = file_pos_read(f.file); - ret = vfs_writev(f.file, vec, vlen, &pos, flags); - if (ret >= 0) - file_pos_write(f.file, pos); - fdput_pos(f); - } - - if (ret > 0) - add_wchar(current, ret); - inc_syscw(current); - return ret; -} - -static inline loff_t pos_from_hilo(unsigned long high, unsigned long low) -{ -#define HALF_LONG_BITS (BITS_PER_LONG / 2) - return (((loff_t)high << HALF_LONG_BITS) << HALF_LONG_BITS) | low; -} - -static ssize_t do_preadv(unsigned long fd, const struct iovec __user *vec, - unsigned long vlen, loff_t pos, int flags) -{ - struct fd f; - ssize_t ret = -EBADF; - - if (pos < 0) - return -EINVAL; - - f = fdget(fd); - if (f.file) { - ret = -ESPIPE; - if (f.file->f_mode & FMODE_PREAD) - ret = vfs_readv(f.file, vec, vlen, &pos, flags); - fdput(f); - } - - if (ret > 0) - add_rchar(current, ret); - inc_syscr(current); - return ret; -} - -static ssize_t do_pwritev(unsigned long fd, const struct iovec __user *vec, - unsigned long vlen, loff_t pos, int flags) -{ - struct fd f; - ssize_t ret = -EBADF; - - if (pos < 0) - return -EINVAL; - - f = fdget(fd); - if (f.file) { - ret = -ESPIPE; - if (f.file->f_mode & FMODE_PWRITE) - ret = vfs_writev(f.file, vec, vlen, &pos, flags); - fdput(f); - } - - if (ret > 0) - add_wchar(current, ret); - inc_syscw(current); - return ret; -} - -SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec, - unsigned long, vlen) -{ - return do_readv(fd, vec, vlen, 0); -} - -SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec, - unsigned long, vlen) -{ - return do_writev(fd, vec, vlen, 0); -} - -SYSCALL_DEFINE5(preadv, unsigned long, fd, const struct iovec __user *, vec, - unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h) -{ - loff_t pos = pos_from_hilo(pos_h, pos_l); - - return do_preadv(fd, vec, vlen, pos, 0); -} - -SYSCALL_DEFINE6(preadv2, unsigned long, fd, const struct iovec __user *, vec, - unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h, - int, flags) -{ - loff_t pos = pos_from_hilo(pos_h, pos_l); - - if (pos == -1) - return do_readv(fd, vec, vlen, flags); - - return do_preadv(fd, vec, vlen, pos, flags); -} - -SYSCALL_DEFINE5(pwritev, unsigned long, fd, const struct iovec __user *, vec, - unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h) -{ - loff_t pos = pos_from_hilo(pos_h, pos_l); - - return do_pwritev(fd, vec, vlen, pos, 0); -} - -SYSCALL_DEFINE6(pwritev2, unsigned long, fd, const struct iovec __user *, vec, - unsigned long, vlen, unsigned long, pos_l, unsigned long, pos_h, - int, flags) -{ - loff_t pos = pos_from_hilo(pos_h, pos_l); - - if (pos == -1) - return do_writev(fd, vec, vlen, flags); - - return do_pwritev(fd, vec, vlen, pos, flags); -} - -#ifdef CONFIG_COMPAT - -static ssize_t compat_do_readv_writev(int type, struct file *file, - const struct compat_iovec __user *uvector, - unsigned long nr_segs, loff_t *pos, - int flags) -{ - compat_ssize_t tot_len; - struct iovec iovstack[UIO_FASTIOV]; - struct iovec *iov = iovstack; - struct iov_iter iter; - ssize_t ret; - io_fn_t fn; - iter_fn_t iter_fn; - - ret = compat_import_iovec(type, uvector, nr_segs, - UIO_FASTIOV, &iov, &iter); - if (ret < 0) - return ret; - - tot_len = iov_iter_count(&iter); - if (!tot_len) - goto out; - ret = rw_verify_area(type, file, pos, tot_len); - if (ret < 0) - goto out; - - if (type == READ) { - fn = file->f_op->read; - iter_fn = file->f_op->read_iter; - } else { - fn = (io_fn_t)file->f_op->write; - iter_fn = file->f_op->write_iter; - file_start_write(file); - } - - if (iter_fn) - ret = do_iter_readv_writev(file, &iter, pos, iter_fn, flags); - else - ret = do_loop_readv_writev(file, &iter, pos, fn, flags); - - if (type != READ) - file_end_write(file); - -out: - kfree(iov); - if ((ret + (type == READ)) > 0) { - if (type == READ) - fsnotify_access(file); - else - fsnotify_modify(file); - } - return ret; -} - -static size_t compat_readv(struct file *file, - const struct compat_iovec __user *vec, - unsigned long vlen, loff_t *pos, int flags) -{ - ssize_t ret = -EBADF; - - if (!(file->f_mode & FMODE_READ)) - goto out; - - ret = -EINVAL; - if (!(file->f_mode & FMODE_CAN_READ)) - goto out; - - ret = compat_do_readv_writev(READ, file, vec, vlen, pos, flags); - -out: - if (ret > 0) - add_rchar(current, ret); - inc_syscr(current); - return ret; -} - -static size_t do_compat_readv(compat_ulong_t fd, - const struct compat_iovec __user *vec, - compat_ulong_t vlen, int flags) -{ - struct fd f = fdget_pos(fd); - ssize_t ret; - loff_t pos; - - if (!f.file) - return -EBADF; - pos = f.file->f_pos; - ret = compat_readv(f.file, vec, vlen, &pos, flags); - if (ret >= 0) - f.file->f_pos = pos; - fdput_pos(f); - return ret; - -} - -COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd, - const struct compat_iovec __user *,vec, - compat_ulong_t, vlen) -{ - return do_compat_readv(fd, vec, vlen, 0); -} - -static long do_compat_preadv64(unsigned long fd, - const struct compat_iovec __user *vec, - unsigned long vlen, loff_t pos, int flags) -{ - struct fd f; - ssize_t ret; - - if (pos < 0) - return -EINVAL; - f = fdget(fd); - if (!f.file) - return -EBADF; - ret = -ESPIPE; - if (f.file->f_mode & FMODE_PREAD) - ret = compat_readv(f.file, vec, vlen, &pos, flags); - fdput(f); - return ret; -} - -#ifdef __ARCH_WANT_COMPAT_SYS_PREADV64 -COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd, - const struct compat_iovec __user *,vec, - unsigned long, vlen, loff_t, pos) -{ - return do_compat_preadv64(fd, vec, vlen, pos, 0); -} -#endif - -COMPAT_SYSCALL_DEFINE5(preadv, compat_ulong_t, fd, - const struct compat_iovec __user *,vec, - compat_ulong_t, vlen, u32, pos_low, u32, pos_high) -{ - loff_t pos = ((loff_t)pos_high << 32) | pos_low; - - return do_compat_preadv64(fd, vec, vlen, pos, 0); -} - -#ifdef __ARCH_WANT_COMPAT_SYS_PREADV64V2 -COMPAT_SYSCALL_DEFINE5(preadv64v2, unsigned long, fd, - const struct compat_iovec __user *,vec, - unsigned long, vlen, loff_t, pos, int, flags) -{ - return do_compat_preadv64(fd, vec, vlen, pos, flags); -} -#endif - -COMPAT_SYSCALL_DEFINE6(preadv2, compat_ulong_t, fd, - const struct compat_iovec __user *,vec, - compat_ulong_t, vlen, u32, pos_low, u32, pos_high, - int, flags) -{ - loff_t pos = ((loff_t)pos_high << 32) | pos_low; - - if (pos == -1) - return do_compat_readv(fd, vec, vlen, flags); - - return do_compat_preadv64(fd, vec, vlen, pos, flags); -} - -static size_t compat_writev(struct file *file, - const struct compat_iovec __user *vec, - unsigned long vlen, loff_t *pos, int flags) -{ - ssize_t ret = -EBADF; - - if (!(file->f_mode & FMODE_WRITE)) - goto out; - - ret = -EINVAL; - if (!(file->f_mode & FMODE_CAN_WRITE)) - goto out; - - ret = compat_do_readv_writev(WRITE, file, vec, vlen, pos, 0); - -out: - if (ret > 0) - add_wchar(current, ret); - inc_syscw(current); - return ret; -} - -static size_t do_compat_writev(compat_ulong_t fd, - const struct compat_iovec __user* vec, - compat_ulong_t vlen, int flags) -{ - struct fd f = fdget_pos(fd); - ssize_t ret; - loff_t pos; - - if (!f.file) - return -EBADF; - pos = f.file->f_pos; - ret = compat_writev(f.file, vec, vlen, &pos, flags); - if (ret >= 0) - f.file->f_pos = pos; - fdput_pos(f); - return ret; -} - -COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd, - const struct compat_iovec __user *, vec, - compat_ulong_t, vlen) -{ - return do_compat_writev(fd, vec, vlen, 0); -} - -static long do_compat_pwritev64(unsigned long fd, - const struct compat_iovec __user *vec, - unsigned long vlen, loff_t pos, int flags) -{ - struct fd f; - ssize_t ret; - - if (pos < 0) - return -EINVAL; - f = fdget(fd); - if (!f.file) - return -EBADF; - ret = -ESPIPE; - if (f.file->f_mode & FMODE_PWRITE) - ret = compat_writev(f.file, vec, vlen, &pos, flags); - fdput(f); - return ret; -} - -#ifdef __ARCH_WANT_COMPAT_SYS_PWRITEV64 -COMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd, - const struct compat_iovec __user *,vec, - unsigned long, vlen, loff_t, pos) -{ - return do_compat_pwritev64(fd, vec, vlen, pos, 0); -} -#endif - -COMPAT_SYSCALL_DEFINE5(pwritev, compat_ulong_t, fd, - const struct compat_iovec __user *,vec, - compat_ulong_t, vlen, u32, pos_low, u32, pos_high) -{ - loff_t pos = ((loff_t)pos_high << 32) | pos_low; - - return do_compat_pwritev64(fd, vec, vlen, pos, 0); -} - -#ifdef __ARCH_WANT_COMPAT_SYS_PWRITEV64V2 -COMPAT_SYSCALL_DEFINE5(pwritev64v2, unsigned long, fd, - const struct compat_iovec __user *,vec, - unsigned long, vlen, loff_t, pos, int, flags) -{ - return do_compat_pwritev64(fd, vec, vlen, pos, flags); -} -#endif - -COMPAT_SYSCALL_DEFINE6(pwritev2, compat_ulong_t, fd, - const struct compat_iovec __user *,vec, - compat_ulong_t, vlen, u32, pos_low, u32, pos_high, int, flags) -{ - loff_t pos = ((loff_t)pos_high << 32) | pos_low; - - if (pos == -1) - return do_compat_writev(fd, vec, vlen, flags); - - return do_compat_pwritev64(fd, vec, vlen, pos, flags); -} - -#endif - -static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, - size_t count, loff_t max) -{ - struct fd in, out; - struct inode *in_inode, *out_inode; - loff_t pos; - loff_t out_pos; - ssize_t retval; - int fl; - - /* - * Get input file, and verify that it is ok.. - */ - retval = -EBADF; - in = fdget(in_fd); - if (!in.file) - goto out; - if (!(in.file->f_mode & FMODE_READ)) - goto fput_in; - retval = -ESPIPE; - if (!ppos) { - pos = in.file->f_pos; - } else { - pos = *ppos; - if (!(in.file->f_mode & FMODE_PREAD)) - goto fput_in; - } - retval = rw_verify_area(READ, in.file, &pos, count); - if (retval < 0) - goto fput_in; - if (count > MAX_RW_COUNT) - count = MAX_RW_COUNT; - - /* - * Get output file, and verify that it is ok.. - */ - retval = -EBADF; - out = fdget(out_fd); - if (!out.file) - goto fput_in; - if (!(out.file->f_mode & FMODE_WRITE)) - goto fput_out; - retval = -EINVAL; - in_inode = file_inode(in.file); - out_inode = file_inode(out.file); - out_pos = out.file->f_pos; - retval = rw_verify_area(WRITE, out.file, &out_pos, count); - if (retval < 0) - goto fput_out; - - if (!max) - max = min(in_inode->i_sb->s_maxbytes, out_inode->i_sb->s_maxbytes); - - if (unlikely(pos + count > max)) { - retval = -EOVERFLOW; - if (pos >= max) - goto fput_out; - count = max - pos; - } - - fl = 0; -#if 0 - /* - * We need to debate whether we can enable this or not. The - * man page documents EAGAIN return for the output at least, - * and the application is arguably buggy if it doesn't expect - * EAGAIN on a non-blocking file descriptor. - */ - if (in.file->f_flags & O_NONBLOCK) - fl = SPLICE_F_NONBLOCK; -#endif - file_start_write(out.file); - retval = do_splice_direct(in.file, &pos, out.file, &out_pos, count, fl); - file_end_write(out.file); - - if (retval > 0) { - add_rchar(current, retval); - add_wchar(current, retval); - fsnotify_access(in.file); - fsnotify_modify(out.file); - out.file->f_pos = out_pos; - if (ppos) - *ppos = pos; - else - in.file->f_pos = pos; - } - - inc_syscr(current); - inc_syscw(current); - if (pos > max) - retval = -EOVERFLOW; - -fput_out: - fdput(out); -fput_in: - fdput(in); -out: - return retval; -} - -SYSCALL_DEFINE4(sendfile, int, out_fd, int, in_fd, off_t __user *, offset, size_t, count) -{ - loff_t pos; - off_t off; - ssize_t ret; - - if (offset) { - if (unlikely(get_user(off, offset))) - return -EFAULT; - pos = off; - ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS); - if (unlikely(put_user(pos, offset))) - return -EFAULT; - return ret; - } - - return do_sendfile(out_fd, in_fd, NULL, count, 0); -} - -SYSCALL_DEFINE4(sendfile64, int, out_fd, int, in_fd, loff_t __user *, offset, size_t, count) -{ - loff_t pos; - ssize_t ret; - - if (offset) { - if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t)))) - return -EFAULT; - ret = do_sendfile(out_fd, in_fd, &pos, count, 0); - if (unlikely(put_user(pos, offset))) - return -EFAULT; - return ret; - } - - return do_sendfile(out_fd, in_fd, NULL, count, 0); -} - -#ifdef CONFIG_COMPAT -COMPAT_SYSCALL_DEFINE4(sendfile, int, out_fd, int, in_fd, - compat_off_t __user *, offset, compat_size_t, count) -{ - loff_t pos; - off_t off; - ssize_t ret; - - if (offset) { - if (unlikely(get_user(off, offset))) - return -EFAULT; - pos = off; - ret = do_sendfile(out_fd, in_fd, &pos, count, MAX_NON_LFS); - if (unlikely(put_user(pos, offset))) - return -EFAULT; - return ret; - } - - return do_sendfile(out_fd, in_fd, NULL, count, 0); -} - -COMPAT_SYSCALL_DEFINE4(sendfile64, int, out_fd, int, in_fd, - compat_loff_t __user *, offset, compat_size_t, count) -{ - loff_t pos; - ssize_t ret; - - if (offset) { - if (unlikely(copy_from_user(&pos, offset, sizeof(loff_t)))) - return -EFAULT; - ret = do_sendfile(out_fd, in_fd, &pos, count, 0); - if (unlikely(put_user(pos, offset))) - return -EFAULT; - return ret; - } - - return do_sendfile(out_fd, in_fd, NULL, count, 0); -} -#endif - -/* - * copy_file_range() differs from regular file read and write in that it - * specifically allows return partial success. When it does so is up to - * the copy_file_range method. - */ -ssize_t vfs_copy_file_range(struct file *file_in, loff_t pos_in, - struct file *file_out, loff_t pos_out, - size_t len, unsigned int flags) -{ - struct inode *inode_in = file_inode(file_in); - struct inode *inode_out = file_inode(file_out); - ssize_t ret; - - if (flags != 0) - return -EINVAL; - - ret = rw_verify_area(READ, file_in, &pos_in, len); - if (unlikely(ret)) - return ret; - - ret = rw_verify_area(WRITE, file_out, &pos_out, len); - if (unlikely(ret)) - return ret; - - if (!(file_in->f_mode & FMODE_READ) || - !(file_out->f_mode & FMODE_WRITE) || - (file_out->f_flags & O_APPEND)) - return -EBADF; - - /* this could be relaxed once a method supports cross-fs copies */ - if (inode_in->i_sb != inode_out->i_sb) - return -EXDEV; - - if (len == 0) - return 0; - - ret = mnt_want_write_file(file_out); - if (ret) - return ret; - - ret = -EOPNOTSUPP; - if (file_out->f_op->copy_file_range) - ret = file_out->f_op->copy_file_range(file_in, pos_in, file_out, - pos_out, len, flags); - if (ret == -EOPNOTSUPP) - ret = do_splice_direct(file_in, &pos_in, file_out, &pos_out, - len > MAX_RW_COUNT ? MAX_RW_COUNT : len, 0); - - if (ret > 0) { - fsnotify_access(file_in); - add_rchar(current, ret); - fsnotify_modify(file_out); - add_wchar(current, ret); - } - inc_syscr(current); - inc_syscw(current); - - mnt_drop_write_file(file_out); - - return ret; -} -EXPORT_SYMBOL(vfs_copy_file_range); - -SYSCALL_DEFINE6(copy_file_range, int, fd_in, loff_t __user *, off_in, - int, fd_out, loff_t __user *, off_out, - size_t, len, unsigned int, flags) -{ - loff_t pos_in; - loff_t pos_out; - struct fd f_in; - struct fd f_out; - ssize_t ret = -EBADF; - - f_in = fdget(fd_in); - if (!f_in.file) - goto out2; - - f_out = fdget(fd_out); - if (!f_out.file) - goto out1; - - ret = -EFAULT; - if (off_in) { - if (copy_from_user(&pos_in, off_in, sizeof(loff_t))) - goto out; - } else { - pos_in = f_in.file->f_pos; - } - - if (off_out) { - if (copy_from_user(&pos_out, off_out, sizeof(loff_t))) - goto out; - } else { - pos_out = f_out.file->f_pos; - } - - ret = vfs_copy_file_range(f_in.file, pos_in, f_out.file, pos_out, len, - flags); - if (ret > 0) { - pos_in += ret; - pos_out += ret; - - if (off_in) { - if (copy_to_user(off_in, &pos_in, sizeof(loff_t))) - ret = -EFAULT; - } else { - f_in.file->f_pos = pos_in; - } - - if (off_out) { - if (copy_to_user(off_out, &pos_out, sizeof(loff_t))) - ret = -EFAULT; - } else { - f_out.file->f_pos = pos_out; - } - } - -out: - fdput(f_out); -out1: - fdput(f_in); -out2: - return ret; -} - -static int clone_verify_area(struct file *file, loff_t pos, u64 len, bool write) -{ - struct inode *inode = file_inode(file); - - if (unlikely(pos < 0)) - return -EINVAL; - - if (unlikely((loff_t) (pos + len) < 0)) - return -EINVAL; - - if (unlikely(inode->i_flctx && mandatory_lock(inode))) { - loff_t end = len ? pos + len - 1 : OFFSET_MAX; - int retval; - - retval = locks_mandatory_area(inode, file, pos, end, - write ? F_WRLCK : F_RDLCK); - if (retval < 0) - return retval; - } - - return security_file_permission(file, write ? MAY_WRITE : MAY_READ); -} - -int vfs_clone_file_range(struct file *file_in, loff_t pos_in, - struct file *file_out, loff_t pos_out, u64 len) -{ - struct inode *inode_in = file_inode(file_in); - struct inode *inode_out = file_inode(file_out); - int ret; - - if (inode_in->i_sb != inode_out->i_sb || - file_in->f_path.mnt != file_out->f_path.mnt) - return -EXDEV; - - if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode)) - return -EISDIR; - if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode)) - return -EINVAL; - - if (!(file_in->f_mode & FMODE_READ) || - !(file_out->f_mode & FMODE_WRITE) || - (file_out->f_flags & O_APPEND)) - return -EBADF; - - if (!file_in->f_op->clone_file_range) - return -EOPNOTSUPP; - - ret = clone_verify_area(file_in, pos_in, len, false); - if (ret) - return ret; - - ret = clone_verify_area(file_out, pos_out, len, true); - if (ret) - return ret; - - if (pos_in + len > i_size_read(inode_in)) - return -EINVAL; - - ret = mnt_want_write_file(file_out); - if (ret) - return ret; - - ret = file_in->f_op->clone_file_range(file_in, pos_in, - file_out, pos_out, len); - if (!ret) { - fsnotify_access(file_in); - fsnotify_modify(file_out); - } - - mnt_drop_write_file(file_out); - return ret; -} -EXPORT_SYMBOL(vfs_clone_file_range); - -int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same) -{ - struct file_dedupe_range_info *info; - struct inode *src = file_inode(file); - u64 off; - u64 len; - int i; - int ret; - bool is_admin = capable(CAP_SYS_ADMIN); - u16 count = same->dest_count; - struct file *dst_file; - loff_t dst_off; - ssize_t deduped; - - if (!(file->f_mode & FMODE_READ)) - return -EINVAL; - - if (same->reserved1 || same->reserved2) - return -EINVAL; - - off = same->src_offset; - len = same->src_length; - - ret = -EISDIR; - if (S_ISDIR(src->i_mode)) - goto out; - - ret = -EINVAL; - if (!S_ISREG(src->i_mode)) - goto out; - - ret = clone_verify_area(file, off, len, false); - if (ret < 0) - goto out; - ret = 0; - - /* pre-format output fields to sane values */ - for (i = 0; i < count; i++) { - same->info[i].bytes_deduped = 0ULL; - same->info[i].status = FILE_DEDUPE_RANGE_SAME; - } - - for (i = 0, info = same->info; i < count; i++, info++) { - struct inode *dst; - struct fd dst_fd = fdget(info->dest_fd); - - dst_file = dst_fd.file; - if (!dst_file) { - info->status = -EBADF; - goto next_loop; - } - dst = file_inode(dst_file); - - ret = mnt_want_write_file(dst_file); - if (ret) { - info->status = ret; - goto next_loop; - } - - dst_off = info->dest_offset; - ret = clone_verify_area(dst_file, dst_off, len, true); - if (ret < 0) { - info->status = ret; - goto next_file; - } - ret = 0; - - if (info->reserved) { - info->status = -EINVAL; - } else if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) { - info->status = -EINVAL; - } else if (file->f_path.mnt != dst_file->f_path.mnt) { - info->status = -EXDEV; - } else if (S_ISDIR(dst->i_mode)) { - info->status = -EISDIR; - } else if (dst_file->f_op->dedupe_file_range == NULL) { - info->status = -EINVAL; - } else { - deduped = dst_file->f_op->dedupe_file_range(file, off, - len, dst_file, - info->dest_offset); - if (deduped == -EBADE) - info->status = FILE_DEDUPE_RANGE_DIFFERS; - else if (deduped < 0) - info->status = deduped; - else - info->bytes_deduped += deduped; - } - -next_file: - mnt_drop_write_file(dst_file); -next_loop: - fdput(dst_fd); - - if (fatal_signal_pending(current)) - goto out; - } - -out: - return ret; -} -EXPORT_SYMBOL(vfs_dedupe_file_range); diff --git a/src/linux/fs/readdir.c b/src/linux/fs/readdir.c deleted file mode 100644 index 9d0212c..0000000 --- a/src/linux/fs/readdir.c +++ /dev/null @@ -1,326 +0,0 @@ -/* - * linux/fs/readdir.c - * - * Copyright (C) 1995 Linus Torvalds - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -int iterate_dir(struct file *file, struct dir_context *ctx) -{ - struct inode *inode = file_inode(file); - bool shared = false; - int res = -ENOTDIR; - if (file->f_op->iterate_shared) - shared = true; - else if (!file->f_op->iterate) - goto out; - - res = security_file_permission(file, MAY_READ); - if (res) - goto out; - - if (shared) { - inode_lock_shared(inode); - } else { - res = down_write_killable(&inode->i_rwsem); - if (res) - goto out; - } - - res = -ENOENT; - if (!IS_DEADDIR(inode)) { - ctx->pos = file->f_pos; - if (shared) - res = file->f_op->iterate_shared(file, ctx); - else - res = file->f_op->iterate(file, ctx); - file->f_pos = ctx->pos; - fsnotify_access(file); - file_accessed(file); - } - if (shared) - inode_unlock_shared(inode); - else - inode_unlock(inode); -out: - return res; -} -EXPORT_SYMBOL(iterate_dir); - -/* - * Traditional linux readdir() handling.. - * - * "count=1" is a special case, meaning that the buffer is one - * dirent-structure in size and that the code can't handle more - * anyway. Thus the special "fillonedir()" function for that - * case (the low-level handlers don't need to care about this). - */ - -#ifdef __ARCH_WANT_OLD_READDIR - -struct old_linux_dirent { - unsigned long d_ino; - unsigned long d_offset; - unsigned short d_namlen; - char d_name[1]; -}; - -struct readdir_callback { - struct dir_context ctx; - struct old_linux_dirent __user * dirent; - int result; -}; - -static int fillonedir(struct dir_context *ctx, const char *name, int namlen, - loff_t offset, u64 ino, unsigned int d_type) -{ - struct readdir_callback *buf = - container_of(ctx, struct readdir_callback, ctx); - struct old_linux_dirent __user * dirent; - unsigned long d_ino; - - if (buf->result) - return -EINVAL; - d_ino = ino; - if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { - buf->result = -EOVERFLOW; - return -EOVERFLOW; - } - buf->result++; - dirent = buf->dirent; - if (!access_ok(VERIFY_WRITE, dirent, - (unsigned long)(dirent->d_name + namlen + 1) - - (unsigned long)dirent)) - goto efault; - if ( __put_user(d_ino, &dirent->d_ino) || - __put_user(offset, &dirent->d_offset) || - __put_user(namlen, &dirent->d_namlen) || - __copy_to_user(dirent->d_name, name, namlen) || - __put_user(0, dirent->d_name + namlen)) - goto efault; - return 0; -efault: - buf->result = -EFAULT; - return -EFAULT; -} - -SYSCALL_DEFINE3(old_readdir, unsigned int, fd, - struct old_linux_dirent __user *, dirent, unsigned int, count) -{ - int error; - struct fd f = fdget_pos(fd); - struct readdir_callback buf = { - .ctx.actor = fillonedir, - .dirent = dirent - }; - - if (!f.file) - return -EBADF; - - error = iterate_dir(f.file, &buf.ctx); - if (buf.result) - error = buf.result; - - fdput_pos(f); - return error; -} - -#endif /* __ARCH_WANT_OLD_READDIR */ - -/* - * New, all-improved, singing, dancing, iBCS2-compliant getdents() - * interface. - */ -struct linux_dirent { - unsigned long d_ino; - unsigned long d_off; - unsigned short d_reclen; - char d_name[1]; -}; - -struct getdents_callback { - struct dir_context ctx; - struct linux_dirent __user * current_dir; - struct linux_dirent __user * previous; - int count; - int error; -}; - -static int filldir(struct dir_context *ctx, const char *name, int namlen, - loff_t offset, u64 ino, unsigned int d_type) -{ - struct linux_dirent __user * dirent; - struct getdents_callback *buf = - container_of(ctx, struct getdents_callback, ctx); - unsigned long d_ino; - int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2, - sizeof(long)); - - buf->error = -EINVAL; /* only used if we fail.. */ - if (reclen > buf->count) - return -EINVAL; - d_ino = ino; - if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) { - buf->error = -EOVERFLOW; - return -EOVERFLOW; - } - dirent = buf->previous; - if (dirent) { - if (signal_pending(current)) - return -EINTR; - if (__put_user(offset, &dirent->d_off)) - goto efault; - } - dirent = buf->current_dir; - if (__put_user(d_ino, &dirent->d_ino)) - goto efault; - if (__put_user(reclen, &dirent->d_reclen)) - goto efault; - if (copy_to_user(dirent->d_name, name, namlen)) - goto efault; - if (__put_user(0, dirent->d_name + namlen)) - goto efault; - if (__put_user(d_type, (char __user *) dirent + reclen - 1)) - goto efault; - buf->previous = dirent; - dirent = (void __user *)dirent + reclen; - buf->current_dir = dirent; - buf->count -= reclen; - return 0; -efault: - buf->error = -EFAULT; - return -EFAULT; -} - -SYSCALL_DEFINE3(getdents, unsigned int, fd, - struct linux_dirent __user *, dirent, unsigned int, count) -{ - struct fd f; - struct linux_dirent __user * lastdirent; - struct getdents_callback buf = { - .ctx.actor = filldir, - .count = count, - .current_dir = dirent - }; - int error; - - if (!access_ok(VERIFY_WRITE, dirent, count)) - return -EFAULT; - - f = fdget_pos(fd); - if (!f.file) - return -EBADF; - - error = iterate_dir(f.file, &buf.ctx); - if (error >= 0) - error = buf.error; - lastdirent = buf.previous; - if (lastdirent) { - if (put_user(buf.ctx.pos, &lastdirent->d_off)) - error = -EFAULT; - else - error = count - buf.count; - } - fdput_pos(f); - return error; -} - -struct getdents_callback64 { - struct dir_context ctx; - struct linux_dirent64 __user * current_dir; - struct linux_dirent64 __user * previous; - int count; - int error; -}; - -static int filldir64(struct dir_context *ctx, const char *name, int namlen, - loff_t offset, u64 ino, unsigned int d_type) -{ - struct linux_dirent64 __user *dirent; - struct getdents_callback64 *buf = - container_of(ctx, struct getdents_callback64, ctx); - int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1, - sizeof(u64)); - - buf->error = -EINVAL; /* only used if we fail.. */ - if (reclen > buf->count) - return -EINVAL; - dirent = buf->previous; - if (dirent) { - if (signal_pending(current)) - return -EINTR; - if (__put_user(offset, &dirent->d_off)) - goto efault; - } - dirent = buf->current_dir; - if (__put_user(ino, &dirent->d_ino)) - goto efault; - if (__put_user(0, &dirent->d_off)) - goto efault; - if (__put_user(reclen, &dirent->d_reclen)) - goto efault; - if (__put_user(d_type, &dirent->d_type)) - goto efault; - if (copy_to_user(dirent->d_name, name, namlen)) - goto efault; - if (__put_user(0, dirent->d_name + namlen)) - goto efault; - buf->previous = dirent; - dirent = (void __user *)dirent + reclen; - buf->current_dir = dirent; - buf->count -= reclen; - return 0; -efault: - buf->error = -EFAULT; - return -EFAULT; -} - -SYSCALL_DEFINE3(getdents64, unsigned int, fd, - struct linux_dirent64 __user *, dirent, unsigned int, count) -{ - struct fd f; - struct linux_dirent64 __user * lastdirent; - struct getdents_callback64 buf = { - .ctx.actor = filldir64, - .count = count, - .current_dir = dirent - }; - int error; - - if (!access_ok(VERIFY_WRITE, dirent, count)) - return -EFAULT; - - f = fdget_pos(fd); - if (!f.file) - return -EBADF; - - error = iterate_dir(f.file, &buf.ctx); - if (error >= 0) - error = buf.error; - lastdirent = buf.previous; - if (lastdirent) { - typeof(lastdirent->d_off) d_off = buf.ctx.pos; - if (__put_user(d_off, &lastdirent->d_off)) - error = -EFAULT; - else - error = count - buf.count; - } - fdput_pos(f); - return error; -} diff --git a/src/linux/fs/reiserfs/Kconfig b/src/linux/fs/reiserfs/Kconfig deleted file mode 100644 index 7cd4666..0000000 --- a/src/linux/fs/reiserfs/Kconfig +++ /dev/null @@ -1,88 +0,0 @@ -config REISERFS_FS - tristate "Reiserfs support" - select CRC32 - help - Stores not just filenames but the files themselves in a balanced - tree. Uses journalling. - - Balanced trees are more efficient than traditional file system - architectural foundations. - - In general, ReiserFS is as fast as ext2, but is very efficient with - large directories and small files. Additional patches are needed - for NFS and quotas, please see - for links. - - It is more easily extended to have features currently found in - database and keyword search systems than block allocation based file - systems are. The next version will be so extended, and will support - plugins consistent with our motto ``It takes more than a license to - make source code open.'' - - Read - to learn more about reiserfs. - - Sponsored by Threshold Networks, Emusic.com, and Bigstorage.com. - - If you like it, you can pay us to add new features to it that you - need, buy a support contract, or pay us to port it to another OS. - -config REISERFS_CHECK - bool "Enable reiserfs debug mode" - depends on REISERFS_FS - help - If you set this to Y, then ReiserFS will perform every check it can - possibly imagine of its internal consistency throughout its - operation. It will also go substantially slower. More than once we - have forgotten that this was on, and then gone despondent over the - latest benchmarks.:-) Use of this option allows our team to go all - out in checking for consistency when debugging without fear of its - effect on end users. If you are on the verge of sending in a bug - report, say Y and you might get a useful error message. Almost - everyone should say N. - -config REISERFS_PROC_INFO - bool "Stats in /proc/fs/reiserfs" - depends on REISERFS_FS && PROC_FS - help - Create under /proc/fs/reiserfs a hierarchy of files, displaying - various ReiserFS statistics and internal data at the expense of - making your kernel or module slightly larger (+8 KB). This also - increases the amount of kernel memory required for each mount. - Almost everyone but ReiserFS developers and people fine-tuning - reiserfs or tracing problems should say N. - -config REISERFS_FS_XATTR - bool "ReiserFS extended attributes" - depends on REISERFS_FS - help - Extended attributes are name:value pairs associated with inodes by - the kernel or by users (see the attr(5) manual page, or visit - for details). - - If unsure, say N. - -config REISERFS_FS_POSIX_ACL - bool "ReiserFS POSIX Access Control Lists" - depends on REISERFS_FS_XATTR - select FS_POSIX_ACL - help - Posix Access Control Lists (ACLs) support permissions for users and - groups beyond the owner/group/world scheme. - - To learn more about Access Control Lists, visit the Posix ACLs for - Linux website . - - If you don't know what Access Control Lists are, say N - -config REISERFS_FS_SECURITY - bool "ReiserFS Security Labels" - depends on REISERFS_FS_XATTR - help - Security labels support alternative access control models - implemented by security modules like SELinux. This option - enables an extended attribute handler for file security - labels in the ReiserFS filesystem. - - If you are not using a security module that requires using - extended attributes for file security labels, say N. diff --git a/src/linux/fs/romfs/Kconfig b/src/linux/fs/romfs/Kconfig deleted file mode 100644 index ce2d6bc..0000000 --- a/src/linux/fs/romfs/Kconfig +++ /dev/null @@ -1,62 +0,0 @@ -config ROMFS_FS - tristate "ROM file system support" - depends on BLOCK || MTD - ---help--- - This is a very small read-only file system mainly intended for - initial ram disks of installation disks, but it could be used for - other read-only media as well. Read - for details. - - To compile this file system support as a module, choose M here: the - module will be called romfs. Note that the file system of your - root partition (the one containing the directory /) cannot be a - module. - - If you don't know whether you need it, then you don't need it: - answer N. - -# -# Select the backing stores to be supported -# -choice - prompt "RomFS backing stores" - depends on ROMFS_FS - default ROMFS_BACKED_BY_BLOCK - help - Select the backing stores to be supported. - -config ROMFS_BACKED_BY_BLOCK - bool "Block device-backed ROM file system support" - depends on BLOCK - help - This permits ROMFS to use block devices buffered through the page - cache as the medium from which to retrieve data. It does not allow - direct mapping of the medium. - - If unsure, answer Y. - -config ROMFS_BACKED_BY_MTD - bool "MTD-backed ROM file system support" - depends on MTD=y || (ROMFS_FS=m && MTD) - help - This permits ROMFS to use MTD based devices directly, without the - intercession of the block layer (which may have been disabled). It - also allows direct mapping of MTD devices through romfs files under - NOMMU conditions if the underlying device is directly addressable by - the CPU. - - If unsure, answer Y. - -config ROMFS_BACKED_BY_BOTH - bool "Both the above" - depends on BLOCK && (MTD=y || (ROMFS_FS=m && MTD)) -endchoice - - -config ROMFS_ON_BLOCK - bool - default y if ROMFS_BACKED_BY_BLOCK || ROMFS_BACKED_BY_BOTH - -config ROMFS_ON_MTD - bool - default y if ROMFS_BACKED_BY_MTD || ROMFS_BACKED_BY_BOTH diff --git a/src/linux/fs/select.c b/src/linux/fs/select.c deleted file mode 100644 index 3d4f85d..0000000 --- a/src/linux/fs/select.c +++ /dev/null @@ -1,1055 +0,0 @@ -/* - * This file contains the procedures for the handling of select and poll - * - * Created for Linux based loosely upon Mathius Lattner's minix - * patches by Peter MacDonald. Heavily edited by Linus. - * - * 4 February 1994 - * COFF/ELF binary emulation. If the process has the STICKY_TIMEOUTS - * flag set in its personality we do *not* modify the given timeout - * parameter to reflect time remaining. - * - * 24 January 2000 - * Changed sys_poll()/do_poll() to use PAGE_SIZE chunk-based allocation - * of fds to overcome nfds < 16390 descriptors limit (Tigran Aivazian). - */ - -#include -#include -#include -#include -#include -#include -#include /* for STICKY_TIMEOUTS */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - - -/* - * Estimate expected accuracy in ns from a timeval. - * - * After quite a bit of churning around, we've settled on - * a simple thing of taking 0.1% of the timeout as the - * slack, with a cap of 100 msec. - * "nice" tasks get a 0.5% slack instead. - * - * Consider this comment an open invitation to come up with even - * better solutions.. - */ - -#define MAX_SLACK (100 * NSEC_PER_MSEC) - -static long __estimate_accuracy(struct timespec64 *tv) -{ - long slack; - int divfactor = 1000; - - if (tv->tv_sec < 0) - return 0; - - if (task_nice(current) > 0) - divfactor = divfactor / 5; - - if (tv->tv_sec > MAX_SLACK / (NSEC_PER_SEC/divfactor)) - return MAX_SLACK; - - slack = tv->tv_nsec / divfactor; - slack += tv->tv_sec * (NSEC_PER_SEC/divfactor); - - if (slack > MAX_SLACK) - return MAX_SLACK; - - return slack; -} - -u64 select_estimate_accuracy(struct timespec64 *tv) -{ - u64 ret; - struct timespec64 now; - - /* - * Realtime tasks get a slack of 0 for obvious reasons. - */ - - if (rt_task(current)) - return 0; - - ktime_get_ts64(&now); - now = timespec64_sub(*tv, now); - ret = __estimate_accuracy(&now); - if (ret < current->timer_slack_ns) - return current->timer_slack_ns; - return ret; -} - - - -struct poll_table_page { - struct poll_table_page * next; - struct poll_table_entry * entry; - struct poll_table_entry entries[0]; -}; - -#define POLL_TABLE_FULL(table) \ - ((unsigned long)((table)->entry+1) > PAGE_SIZE + (unsigned long)(table)) - -/* - * Ok, Peter made a complicated, but straightforward multiple_wait() function. - * I have rewritten this, taking some shortcuts: This code may not be easy to - * follow, but it should be free of race-conditions, and it's practical. If you - * understand what I'm doing here, then you understand how the linux - * sleep/wakeup mechanism works. - * - * Two very simple procedures, poll_wait() and poll_freewait() make all the - * work. poll_wait() is an inline-function defined in , - * as all select/poll functions have to call it to add an entry to the - * poll table. - */ -static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, - poll_table *p); - -void poll_initwait(struct poll_wqueues *pwq) -{ - init_poll_funcptr(&pwq->pt, __pollwait); - pwq->polling_task = current; - pwq->triggered = 0; - pwq->error = 0; - pwq->table = NULL; - pwq->inline_index = 0; -} -EXPORT_SYMBOL(poll_initwait); - -static void free_poll_entry(struct poll_table_entry *entry) -{ - remove_wait_queue(entry->wait_address, &entry->wait); - fput(entry->filp); -} - -void poll_freewait(struct poll_wqueues *pwq) -{ - struct poll_table_page * p = pwq->table; - int i; - for (i = 0; i < pwq->inline_index; i++) - free_poll_entry(pwq->inline_entries + i); - while (p) { - struct poll_table_entry * entry; - struct poll_table_page *old; - - entry = p->entry; - do { - entry--; - free_poll_entry(entry); - } while (entry > p->entries); - old = p; - p = p->next; - free_page((unsigned long) old); - } -} -EXPORT_SYMBOL(poll_freewait); - -static struct poll_table_entry *poll_get_entry(struct poll_wqueues *p) -{ - struct poll_table_page *table = p->table; - - if (p->inline_index < N_INLINE_POLL_ENTRIES) - return p->inline_entries + p->inline_index++; - - if (!table || POLL_TABLE_FULL(table)) { - struct poll_table_page *new_table; - - new_table = (struct poll_table_page *) __get_free_page(GFP_KERNEL); - if (!new_table) { - p->error = -ENOMEM; - return NULL; - } - new_table->entry = new_table->entries; - new_table->next = table; - p->table = new_table; - table = new_table; - } - - return table->entry++; -} - -static int __pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) -{ - struct poll_wqueues *pwq = wait->private; - DECLARE_WAITQUEUE(dummy_wait, pwq->polling_task); - - /* - * Although this function is called under waitqueue lock, LOCK - * doesn't imply write barrier and the users expect write - * barrier semantics on wakeup functions. The following - * smp_wmb() is equivalent to smp_wmb() in try_to_wake_up() - * and is paired with smp_store_mb() in poll_schedule_timeout. - */ - smp_wmb(); - pwq->triggered = 1; - - /* - * Perform the default wake up operation using a dummy - * waitqueue. - * - * TODO: This is hacky but there currently is no interface to - * pass in @sync. @sync is scheduled to be removed and once - * that happens, wake_up_process() can be used directly. - */ - return default_wake_function(&dummy_wait, mode, sync, key); -} - -static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) -{ - struct poll_table_entry *entry; - - entry = container_of(wait, struct poll_table_entry, wait); - if (key && !((unsigned long)key & entry->key)) - return 0; - return __pollwake(wait, mode, sync, key); -} - -/* Add a new entry */ -static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, - poll_table *p) -{ - struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt); - struct poll_table_entry *entry = poll_get_entry(pwq); - if (!entry) - return; - entry->filp = get_file(filp); - entry->wait_address = wait_address; - entry->key = p->_key; - init_waitqueue_func_entry(&entry->wait, pollwake); - entry->wait.private = pwq; - add_wait_queue(wait_address, &entry->wait); -} - -int poll_schedule_timeout(struct poll_wqueues *pwq, int state, - ktime_t *expires, unsigned long slack) -{ - int rc = -EINTR; - - set_current_state(state); - if (!pwq->triggered) - rc = schedule_hrtimeout_range(expires, slack, HRTIMER_MODE_ABS); - __set_current_state(TASK_RUNNING); - - /* - * Prepare for the next iteration. - * - * The following smp_store_mb() serves two purposes. First, it's - * the counterpart rmb of the wmb in pollwake() such that data - * written before wake up is always visible after wake up. - * Second, the full barrier guarantees that triggered clearing - * doesn't pass event check of the next iteration. Note that - * this problem doesn't exist for the first iteration as - * add_wait_queue() has full barrier semantics. - */ - smp_store_mb(pwq->triggered, 0); - - return rc; -} -EXPORT_SYMBOL(poll_schedule_timeout); - -/** - * poll_select_set_timeout - helper function to setup the timeout value - * @to: pointer to timespec64 variable for the final timeout - * @sec: seconds (from user space) - * @nsec: nanoseconds (from user space) - * - * Note, we do not use a timespec for the user space value here, That - * way we can use the function for timeval and compat interfaces as well. - * - * Returns -EINVAL if sec/nsec are not normalized. Otherwise 0. - */ -int poll_select_set_timeout(struct timespec64 *to, time64_t sec, long nsec) -{ - struct timespec64 ts = {.tv_sec = sec, .tv_nsec = nsec}; - - if (!timespec64_valid(&ts)) - return -EINVAL; - - /* Optimize for the zero timeout value here */ - if (!sec && !nsec) { - to->tv_sec = to->tv_nsec = 0; - } else { - ktime_get_ts64(to); - *to = timespec64_add_safe(*to, ts); - } - return 0; -} - -static int poll_select_copy_remaining(struct timespec64 *end_time, - void __user *p, - int timeval, int ret) -{ - struct timespec64 rts64; - struct timespec rts; - struct timeval rtv; - - if (!p) - return ret; - - if (current->personality & STICKY_TIMEOUTS) - goto sticky; - - /* No update for zero timeout */ - if (!end_time->tv_sec && !end_time->tv_nsec) - return ret; - - ktime_get_ts64(&rts64); - rts64 = timespec64_sub(*end_time, rts64); - if (rts64.tv_sec < 0) - rts64.tv_sec = rts64.tv_nsec = 0; - - rts = timespec64_to_timespec(rts64); - - if (timeval) { - if (sizeof(rtv) > sizeof(rtv.tv_sec) + sizeof(rtv.tv_usec)) - memset(&rtv, 0, sizeof(rtv)); - rtv.tv_sec = rts64.tv_sec; - rtv.tv_usec = rts64.tv_nsec / NSEC_PER_USEC; - - if (!copy_to_user(p, &rtv, sizeof(rtv))) - return ret; - - } else if (!copy_to_user(p, &rts, sizeof(rts))) - return ret; - - /* - * If an application puts its timeval in read-only memory, we - * don't want the Linux-specific update to the timeval to - * cause a fault after the select has completed - * successfully. However, because we're not updating the - * timeval, we can't restart the system call. - */ - -sticky: - if (ret == -ERESTARTNOHAND) - ret = -EINTR; - return ret; -} - -#define FDS_IN(fds, n) (fds->in + n) -#define FDS_OUT(fds, n) (fds->out + n) -#define FDS_EX(fds, n) (fds->ex + n) - -#define BITS(fds, n) (*FDS_IN(fds, n)|*FDS_OUT(fds, n)|*FDS_EX(fds, n)) - -static int max_select_fd(unsigned long n, fd_set_bits *fds) -{ - unsigned long *open_fds; - unsigned long set; - int max; - struct fdtable *fdt; - - /* handle last in-complete long-word first */ - set = ~(~0UL << (n & (BITS_PER_LONG-1))); - n /= BITS_PER_LONG; - fdt = files_fdtable(current->files); - open_fds = fdt->open_fds + n; - max = 0; - if (set) { - set &= BITS(fds, n); - if (set) { - if (!(set & ~*open_fds)) - goto get_max; - return -EBADF; - } - } - while (n) { - open_fds--; - n--; - set = BITS(fds, n); - if (!set) - continue; - if (set & ~*open_fds) - return -EBADF; - if (max) - continue; -get_max: - do { - max++; - set >>= 1; - } while (set); - max += n * BITS_PER_LONG; - } - - return max; -} - -#define POLLIN_SET (POLLRDNORM | POLLRDBAND | POLLIN | POLLHUP | POLLERR) -#define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR) -#define POLLEX_SET (POLLPRI) - -static inline void wait_key_set(poll_table *wait, unsigned long in, - unsigned long out, unsigned long bit, - unsigned int ll_flag) -{ - wait->_key = POLLEX_SET | ll_flag; - if (in & bit) - wait->_key |= POLLIN_SET; - if (out & bit) - wait->_key |= POLLOUT_SET; -} - -int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time) -{ - ktime_t expire, *to = NULL; - struct poll_wqueues table; - poll_table *wait; - int retval, i, timed_out = 0; - u64 slack = 0; - unsigned int busy_flag = net_busy_loop_on() ? POLL_BUSY_LOOP : 0; - unsigned long busy_end = 0; - - rcu_read_lock(); - retval = max_select_fd(n, fds); - rcu_read_unlock(); - - if (retval < 0) - return retval; - n = retval; - - poll_initwait(&table); - wait = &table.pt; - if (end_time && !end_time->tv_sec && !end_time->tv_nsec) { - wait->_qproc = NULL; - timed_out = 1; - } - - if (end_time && !timed_out) - slack = select_estimate_accuracy(end_time); - - retval = 0; - for (;;) { - unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp; - bool can_busy_loop = false; - - inp = fds->in; outp = fds->out; exp = fds->ex; - rinp = fds->res_in; routp = fds->res_out; rexp = fds->res_ex; - - for (i = 0; i < n; ++rinp, ++routp, ++rexp) { - unsigned long in, out, ex, all_bits, bit = 1, mask, j; - unsigned long res_in = 0, res_out = 0, res_ex = 0; - - in = *inp++; out = *outp++; ex = *exp++; - all_bits = in | out | ex; - if (all_bits == 0) { - i += BITS_PER_LONG; - continue; - } - - for (j = 0; j < BITS_PER_LONG; ++j, ++i, bit <<= 1) { - struct fd f; - if (i >= n) - break; - if (!(bit & all_bits)) - continue; - f = fdget(i); - if (f.file) { - const struct file_operations *f_op; - f_op = f.file->f_op; - mask = DEFAULT_POLLMASK; - if (f_op->poll) { - wait_key_set(wait, in, out, - bit, busy_flag); - mask = (*f_op->poll)(f.file, wait); - } - fdput(f); - if ((mask & POLLIN_SET) && (in & bit)) { - res_in |= bit; - retval++; - wait->_qproc = NULL; - } - if ((mask & POLLOUT_SET) && (out & bit)) { - res_out |= bit; - retval++; - wait->_qproc = NULL; - } - if ((mask & POLLEX_SET) && (ex & bit)) { - res_ex |= bit; - retval++; - wait->_qproc = NULL; - } - /* got something, stop busy polling */ - if (retval) { - can_busy_loop = false; - busy_flag = 0; - - /* - * only remember a returned - * POLL_BUSY_LOOP if we asked for it - */ - } else if (busy_flag & mask) - can_busy_loop = true; - - } - } - if (res_in) - *rinp = res_in; - if (res_out) - *routp = res_out; - if (res_ex) - *rexp = res_ex; - cond_resched(); - } - wait->_qproc = NULL; - if (retval || timed_out || signal_pending(current)) - break; - if (table.error) { - retval = table.error; - break; - } - - /* only if found POLL_BUSY_LOOP sockets && not out of time */ - if (can_busy_loop && !need_resched()) { - if (!busy_end) { - busy_end = busy_loop_end_time(); - continue; - } - if (!busy_loop_timeout(busy_end)) - continue; - } - busy_flag = 0; - - /* - * If this is the first loop and we have a timeout - * given, then we convert to ktime_t and set the to - * pointer to the expiry value. - */ - if (end_time && !to) { - expire = timespec64_to_ktime(*end_time); - to = &expire; - } - - if (!poll_schedule_timeout(&table, TASK_INTERRUPTIBLE, - to, slack)) - timed_out = 1; - } - - poll_freewait(&table); - - return retval; -} - -/* - * We can actually return ERESTARTSYS instead of EINTR, but I'd - * like to be certain this leads to no problems. So I return - * EINTR just for safety. - * - * Update: ERESTARTSYS breaks at least the xview clock binary, so - * I'm trying ERESTARTNOHAND which restart only when you want to. - */ -int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, - fd_set __user *exp, struct timespec64 *end_time) -{ - fd_set_bits fds; - void *bits; - int ret, max_fds; - size_t size, alloc_size; - struct fdtable *fdt; - /* Allocate small arguments on the stack to save memory and be faster */ - long stack_fds[SELECT_STACK_ALLOC/sizeof(long)]; - - ret = -EINVAL; - if (n < 0) - goto out_nofds; - - /* max_fds can increase, so grab it once to avoid race */ - rcu_read_lock(); - fdt = files_fdtable(current->files); - max_fds = fdt->max_fds; - rcu_read_unlock(); - if (n > max_fds) - n = max_fds; - - /* - * We need 6 bitmaps (in/out/ex for both incoming and outgoing), - * since we used fdset we need to allocate memory in units of - * long-words. - */ - size = FDS_BYTES(n); - bits = stack_fds; - if (size > sizeof(stack_fds) / 6) { - /* Not enough space in on-stack array; must use kmalloc */ - ret = -ENOMEM; - if (size > (SIZE_MAX / 6)) - goto out_nofds; - - alloc_size = 6 * size; - bits = kmalloc(alloc_size, GFP_KERNEL|__GFP_NOWARN); - if (!bits && alloc_size > PAGE_SIZE) - bits = vmalloc(alloc_size); - - if (!bits) - goto out_nofds; - } - fds.in = bits; - fds.out = bits + size; - fds.ex = bits + 2*size; - fds.res_in = bits + 3*size; - fds.res_out = bits + 4*size; - fds.res_ex = bits + 5*size; - - if ((ret = get_fd_set(n, inp, fds.in)) || - (ret = get_fd_set(n, outp, fds.out)) || - (ret = get_fd_set(n, exp, fds.ex))) - goto out; - zero_fd_set(n, fds.res_in); - zero_fd_set(n, fds.res_out); - zero_fd_set(n, fds.res_ex); - - ret = do_select(n, &fds, end_time); - - if (ret < 0) - goto out; - if (!ret) { - ret = -ERESTARTNOHAND; - if (signal_pending(current)) - goto out; - ret = 0; - } - - if (set_fd_set(n, inp, fds.res_in) || - set_fd_set(n, outp, fds.res_out) || - set_fd_set(n, exp, fds.res_ex)) - ret = -EFAULT; - -out: - if (bits != stack_fds) - kvfree(bits); -out_nofds: - return ret; -} - -SYSCALL_DEFINE5(select, int, n, fd_set __user *, inp, fd_set __user *, outp, - fd_set __user *, exp, struct timeval __user *, tvp) -{ - struct timespec64 end_time, *to = NULL; - struct timeval tv; - int ret; - - if (tvp) { - if (copy_from_user(&tv, tvp, sizeof(tv))) - return -EFAULT; - - to = &end_time; - if (poll_select_set_timeout(to, - tv.tv_sec + (tv.tv_usec / USEC_PER_SEC), - (tv.tv_usec % USEC_PER_SEC) * NSEC_PER_USEC)) - return -EINVAL; - } - - ret = core_sys_select(n, inp, outp, exp, to); - ret = poll_select_copy_remaining(&end_time, tvp, 1, ret); - - return ret; -} - -static long do_pselect(int n, fd_set __user *inp, fd_set __user *outp, - fd_set __user *exp, struct timespec __user *tsp, - const sigset_t __user *sigmask, size_t sigsetsize) -{ - sigset_t ksigmask, sigsaved; - struct timespec ts; - struct timespec64 ts64, end_time, *to = NULL; - int ret; - - if (tsp) { - if (copy_from_user(&ts, tsp, sizeof(ts))) - return -EFAULT; - ts64 = timespec_to_timespec64(ts); - - to = &end_time; - if (poll_select_set_timeout(to, ts64.tv_sec, ts64.tv_nsec)) - return -EINVAL; - } - - if (sigmask) { - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask))) - return -EFAULT; - - sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); - sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); - } - - ret = core_sys_select(n, inp, outp, exp, to); - ret = poll_select_copy_remaining(&end_time, tsp, 0, ret); - - if (ret == -ERESTARTNOHAND) { - /* - * Don't restore the signal mask yet. Let do_signal() deliver - * the signal on the way back to userspace, before the signal - * mask is restored. - */ - if (sigmask) { - memcpy(¤t->saved_sigmask, &sigsaved, - sizeof(sigsaved)); - set_restore_sigmask(); - } - } else if (sigmask) - sigprocmask(SIG_SETMASK, &sigsaved, NULL); - - return ret; -} - -/* - * Most architectures can't handle 7-argument syscalls. So we provide a - * 6-argument version where the sixth argument is a pointer to a structure - * which has a pointer to the sigset_t itself followed by a size_t containing - * the sigset size. - */ -SYSCALL_DEFINE6(pselect6, int, n, fd_set __user *, inp, fd_set __user *, outp, - fd_set __user *, exp, struct timespec __user *, tsp, - void __user *, sig) -{ - size_t sigsetsize = 0; - sigset_t __user *up = NULL; - - if (sig) { - if (!access_ok(VERIFY_READ, sig, sizeof(void *)+sizeof(size_t)) - || __get_user(up, (sigset_t __user * __user *)sig) - || __get_user(sigsetsize, - (size_t __user *)(sig+sizeof(void *)))) - return -EFAULT; - } - - return do_pselect(n, inp, outp, exp, tsp, up, sigsetsize); -} - -#ifdef __ARCH_WANT_SYS_OLD_SELECT -struct sel_arg_struct { - unsigned long n; - fd_set __user *inp, *outp, *exp; - struct timeval __user *tvp; -}; - -SYSCALL_DEFINE1(old_select, struct sel_arg_struct __user *, arg) -{ - struct sel_arg_struct a; - - if (copy_from_user(&a, arg, sizeof(a))) - return -EFAULT; - return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); -} -#endif - -struct poll_list { - struct poll_list *next; - int len; - struct pollfd entries[0]; -}; - -#define POLLFD_PER_PAGE ((PAGE_SIZE-sizeof(struct poll_list)) / sizeof(struct pollfd)) - -/* - * Fish for pollable events on the pollfd->fd file descriptor. We're only - * interested in events matching the pollfd->events mask, and the result - * matching that mask is both recorded in pollfd->revents and returned. The - * pwait poll_table will be used by the fd-provided poll handler for waiting, - * if pwait->_qproc is non-NULL. - */ -static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait, - bool *can_busy_poll, - unsigned int busy_flag) -{ - unsigned int mask; - int fd; - - mask = 0; - fd = pollfd->fd; - if (fd >= 0) { - struct fd f = fdget(fd); - mask = POLLNVAL; - if (f.file) { - mask = DEFAULT_POLLMASK; - if (f.file->f_op->poll) { - pwait->_key = pollfd->events|POLLERR|POLLHUP; - pwait->_key |= busy_flag; - mask = f.file->f_op->poll(f.file, pwait); - if (mask & busy_flag) - *can_busy_poll = true; - } - /* Mask out unneeded events. */ - mask &= pollfd->events | POLLERR | POLLHUP; - fdput(f); - } - } - pollfd->revents = mask; - - return mask; -} - -static int do_poll(struct poll_list *list, struct poll_wqueues *wait, - struct timespec64 *end_time) -{ - poll_table* pt = &wait->pt; - ktime_t expire, *to = NULL; - int timed_out = 0, count = 0; - u64 slack = 0; - unsigned int busy_flag = net_busy_loop_on() ? POLL_BUSY_LOOP : 0; - unsigned long busy_end = 0; - - /* Optimise the no-wait case */ - if (end_time && !end_time->tv_sec && !end_time->tv_nsec) { - pt->_qproc = NULL; - timed_out = 1; - } - - if (end_time && !timed_out) - slack = select_estimate_accuracy(end_time); - - for (;;) { - struct poll_list *walk; - bool can_busy_loop = false; - - for (walk = list; walk != NULL; walk = walk->next) { - struct pollfd * pfd, * pfd_end; - - pfd = walk->entries; - pfd_end = pfd + walk->len; - for (; pfd != pfd_end; pfd++) { - /* - * Fish for events. If we found one, record it - * and kill poll_table->_qproc, so we don't - * needlessly register any other waiters after - * this. They'll get immediately deregistered - * when we break out and return. - */ - if (do_pollfd(pfd, pt, &can_busy_loop, - busy_flag)) { - count++; - pt->_qproc = NULL; - /* found something, stop busy polling */ - busy_flag = 0; - can_busy_loop = false; - } - } - } - /* - * All waiters have already been registered, so don't provide - * a poll_table->_qproc to them on the next loop iteration. - */ - pt->_qproc = NULL; - if (!count) { - count = wait->error; - if (signal_pending(current)) - count = -EINTR; - } - if (count || timed_out) - break; - - /* only if found POLL_BUSY_LOOP sockets && not out of time */ - if (can_busy_loop && !need_resched()) { - if (!busy_end) { - busy_end = busy_loop_end_time(); - continue; - } - if (!busy_loop_timeout(busy_end)) - continue; - } - busy_flag = 0; - - /* - * If this is the first loop and we have a timeout - * given, then we convert to ktime_t and set the to - * pointer to the expiry value. - */ - if (end_time && !to) { - expire = timespec64_to_ktime(*end_time); - to = &expire; - } - - if (!poll_schedule_timeout(wait, TASK_INTERRUPTIBLE, to, slack)) - timed_out = 1; - } - return count; -} - -#define N_STACK_PPS ((sizeof(stack_pps) - sizeof(struct poll_list)) / \ - sizeof(struct pollfd)) - -int do_sys_poll(struct pollfd __user *ufds, unsigned int nfds, - struct timespec64 *end_time) -{ - struct poll_wqueues table; - int err = -EFAULT, fdcount, len, size; - /* Allocate small arguments on the stack to save memory and be - faster - use long to make sure the buffer is aligned properly - on 64 bit archs to avoid unaligned access */ - long stack_pps[POLL_STACK_ALLOC/sizeof(long)]; - struct poll_list *const head = (struct poll_list *)stack_pps; - struct poll_list *walk = head; - unsigned long todo = nfds; - - if (nfds > rlimit(RLIMIT_NOFILE)) - return -EINVAL; - - len = min_t(unsigned int, nfds, N_STACK_PPS); - for (;;) { - walk->next = NULL; - walk->len = len; - if (!len) - break; - - if (copy_from_user(walk->entries, ufds + nfds-todo, - sizeof(struct pollfd) * walk->len)) - goto out_fds; - - todo -= walk->len; - if (!todo) - break; - - len = min(todo, POLLFD_PER_PAGE); - size = sizeof(struct poll_list) + sizeof(struct pollfd) * len; - walk = walk->next = kmalloc(size, GFP_KERNEL); - if (!walk) { - err = -ENOMEM; - goto out_fds; - } - } - - poll_initwait(&table); - fdcount = do_poll(head, &table, end_time); - poll_freewait(&table); - - for (walk = head; walk; walk = walk->next) { - struct pollfd *fds = walk->entries; - int j; - - for (j = 0; j < walk->len; j++, ufds++) - if (__put_user(fds[j].revents, &ufds->revents)) - goto out_fds; - } - - err = fdcount; -out_fds: - walk = head->next; - while (walk) { - struct poll_list *pos = walk; - walk = walk->next; - kfree(pos); - } - - return err; -} - -static long do_restart_poll(struct restart_block *restart_block) -{ - struct pollfd __user *ufds = restart_block->poll.ufds; - int nfds = restart_block->poll.nfds; - struct timespec64 *to = NULL, end_time; - int ret; - - if (restart_block->poll.has_timeout) { - end_time.tv_sec = restart_block->poll.tv_sec; - end_time.tv_nsec = restart_block->poll.tv_nsec; - to = &end_time; - } - - ret = do_sys_poll(ufds, nfds, to); - - if (ret == -EINTR) { - restart_block->fn = do_restart_poll; - ret = -ERESTART_RESTARTBLOCK; - } - return ret; -} - -SYSCALL_DEFINE3(poll, struct pollfd __user *, ufds, unsigned int, nfds, - int, timeout_msecs) -{ - struct timespec64 end_time, *to = NULL; - int ret; - - if (timeout_msecs >= 0) { - to = &end_time; - poll_select_set_timeout(to, timeout_msecs / MSEC_PER_SEC, - NSEC_PER_MSEC * (timeout_msecs % MSEC_PER_SEC)); - } - - ret = do_sys_poll(ufds, nfds, to); - - if (ret == -EINTR) { - struct restart_block *restart_block; - - restart_block = ¤t->restart_block; - restart_block->fn = do_restart_poll; - restart_block->poll.ufds = ufds; - restart_block->poll.nfds = nfds; - - if (timeout_msecs >= 0) { - restart_block->poll.tv_sec = end_time.tv_sec; - restart_block->poll.tv_nsec = end_time.tv_nsec; - restart_block->poll.has_timeout = 1; - } else - restart_block->poll.has_timeout = 0; - - ret = -ERESTART_RESTARTBLOCK; - } - return ret; -} - -SYSCALL_DEFINE5(ppoll, struct pollfd __user *, ufds, unsigned int, nfds, - struct timespec __user *, tsp, const sigset_t __user *, sigmask, - size_t, sigsetsize) -{ - sigset_t ksigmask, sigsaved; - struct timespec ts; - struct timespec64 end_time, *to = NULL; - int ret; - - if (tsp) { - if (copy_from_user(&ts, tsp, sizeof(ts))) - return -EFAULT; - - to = &end_time; - if (poll_select_set_timeout(to, ts.tv_sec, ts.tv_nsec)) - return -EINVAL; - } - - if (sigmask) { - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - if (copy_from_user(&ksigmask, sigmask, sizeof(ksigmask))) - return -EFAULT; - - sigdelsetmask(&ksigmask, sigmask(SIGKILL)|sigmask(SIGSTOP)); - sigprocmask(SIG_SETMASK, &ksigmask, &sigsaved); - } - - ret = do_sys_poll(ufds, nfds, to); - - /* We can restart this syscall, usually */ - if (ret == -EINTR) { - /* - * Don't restore the signal mask yet. Let do_signal() deliver - * the signal on the way back to userspace, before the signal - * mask is restored. - */ - if (sigmask) { - memcpy(¤t->saved_sigmask, &sigsaved, - sizeof(sigsaved)); - set_restore_sigmask(); - } - ret = -ERESTARTNOHAND; - } else if (sigmask) - sigprocmask(SIG_SETMASK, &sigsaved, NULL); - - ret = poll_select_copy_remaining(&end_time, tsp, 0, ret); - - return ret; -} diff --git a/src/linux/fs/seq_file.c b/src/linux/fs/seq_file.c deleted file mode 100644 index 368bfb9..0000000 --- a/src/linux/fs/seq_file.c +++ /dev/null @@ -1,1045 +0,0 @@ -/* - * linux/fs/seq_file.c - * - * helper functions for making synthetic files from sequences of records. - * initial implementation -- AV, Oct 2001. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static void seq_set_overflow(struct seq_file *m) -{ - m->count = m->size; -} - -static void *seq_buf_alloc(unsigned long size) -{ - void *buf; - gfp_t gfp = GFP_KERNEL; - - /* - * For high order allocations, use __GFP_NORETRY to avoid oom-killing - - * it's better to fall back to vmalloc() than to kill things. For small - * allocations, just use GFP_KERNEL which will oom kill, thus no need - * for vmalloc fallback. - */ - if (size > PAGE_SIZE) - gfp |= __GFP_NORETRY | __GFP_NOWARN; - buf = kmalloc(size, gfp); - if (!buf && size > PAGE_SIZE) - buf = vmalloc(size); - return buf; -} - -/** - * seq_open - initialize sequential file - * @file: file we initialize - * @op: method table describing the sequence - * - * seq_open() sets @file, associating it with a sequence described - * by @op. @op->start() sets the iterator up and returns the first - * element of sequence. @op->stop() shuts it down. @op->next() - * returns the next element of sequence. @op->show() prints element - * into the buffer. In case of error ->start() and ->next() return - * ERR_PTR(error). In the end of sequence they return %NULL. ->show() - * returns 0 in case of success and negative number in case of error. - * Returning SEQ_SKIP means "discard this element and move on". - * Note: seq_open() will allocate a struct seq_file and store its - * pointer in @file->private_data. This pointer should not be modified. - */ -int seq_open(struct file *file, const struct seq_operations *op) -{ - struct seq_file *p; - - WARN_ON(file->private_data); - - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) - return -ENOMEM; - - file->private_data = p; - - mutex_init(&p->lock); - p->op = op; - - // No refcounting: the lifetime of 'p' is constrained - // to the lifetime of the file. - p->file = file; - - /* - * Wrappers around seq_open(e.g. swaps_open) need to be - * aware of this. If they set f_version themselves, they - * should call seq_open first and then set f_version. - */ - file->f_version = 0; - - /* - * seq_files support lseek() and pread(). They do not implement - * write() at all, but we clear FMODE_PWRITE here for historical - * reasons. - * - * If a client of seq_files a) implements file.write() and b) wishes to - * support pwrite() then that client will need to implement its own - * file.open() which calls seq_open() and then sets FMODE_PWRITE. - */ - file->f_mode &= ~FMODE_PWRITE; - return 0; -} -EXPORT_SYMBOL(seq_open); - -static int traverse(struct seq_file *m, loff_t offset) -{ - loff_t pos = 0, index; - int error = 0; - void *p; - - m->version = 0; - index = 0; - m->count = m->from = 0; - if (!offset) { - m->index = index; - return 0; - } - if (!m->buf) { - m->buf = seq_buf_alloc(m->size = PAGE_SIZE); - if (!m->buf) - return -ENOMEM; - } - p = m->op->start(m, &index); - while (p) { - error = PTR_ERR(p); - if (IS_ERR(p)) - break; - error = m->op->show(m, p); - if (error < 0) - break; - if (unlikely(error)) { - error = 0; - m->count = 0; - } - if (seq_has_overflowed(m)) - goto Eoverflow; - if (pos + m->count > offset) { - m->from = offset - pos; - m->count -= m->from; - m->index = index; - break; - } - pos += m->count; - m->count = 0; - if (pos == offset) { - index++; - m->index = index; - break; - } - p = m->op->next(m, p, &index); - } - m->op->stop(m, p); - m->index = index; - return error; - -Eoverflow: - m->op->stop(m, p); - kvfree(m->buf); - m->count = 0; - m->buf = seq_buf_alloc(m->size <<= 1); - return !m->buf ? -ENOMEM : -EAGAIN; -} - -/** - * seq_read - ->read() method for sequential files. - * @file: the file to read from - * @buf: the buffer to read to - * @size: the maximum number of bytes to read - * @ppos: the current position in the file - * - * Ready-made ->f_op->read() - */ -ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) -{ - struct seq_file *m = file->private_data; - size_t copied = 0; - loff_t pos; - size_t n; - void *p; - int err = 0; - - mutex_lock(&m->lock); - - /* - * seq_file->op->..m_start/m_stop/m_next may do special actions - * or optimisations based on the file->f_version, so we want to - * pass the file->f_version to those methods. - * - * seq_file->version is just copy of f_version, and seq_file - * methods can treat it simply as file version. - * It is copied in first and copied out after all operations. - * It is convenient to have it as part of structure to avoid the - * need of passing another argument to all the seq_file methods. - */ - m->version = file->f_version; - - /* Don't assume *ppos is where we left it */ - if (unlikely(*ppos != m->read_pos)) { - while ((err = traverse(m, *ppos)) == -EAGAIN) - ; - if (err) { - /* With prejudice... */ - m->read_pos = 0; - m->version = 0; - m->index = 0; - m->count = 0; - goto Done; - } else { - m->read_pos = *ppos; - } - } - - /* grab buffer if we didn't have one */ - if (!m->buf) { - m->buf = seq_buf_alloc(m->size = PAGE_SIZE); - if (!m->buf) - goto Enomem; - } - /* if not empty - flush it first */ - if (m->count) { - n = min(m->count, size); - err = copy_to_user(buf, m->buf + m->from, n); - if (err) - goto Efault; - m->count -= n; - m->from += n; - size -= n; - buf += n; - copied += n; - if (!m->count) { - m->from = 0; - m->index++; - } - if (!size) - goto Done; - } - /* we need at least one record in buffer */ - pos = m->index; - p = m->op->start(m, &pos); - while (1) { - err = PTR_ERR(p); - if (!p || IS_ERR(p)) - break; - err = m->op->show(m, p); - if (err < 0) - break; - if (unlikely(err)) - m->count = 0; - if (unlikely(!m->count)) { - p = m->op->next(m, p, &pos); - m->index = pos; - continue; - } - if (m->count < m->size) - goto Fill; - m->op->stop(m, p); - kvfree(m->buf); - m->count = 0; - m->buf = seq_buf_alloc(m->size <<= 1); - if (!m->buf) - goto Enomem; - m->version = 0; - pos = m->index; - p = m->op->start(m, &pos); - } - m->op->stop(m, p); - m->count = 0; - goto Done; -Fill: - /* they want more? let's try to get some more */ - while (m->count < size) { - size_t offs = m->count; - loff_t next = pos; - p = m->op->next(m, p, &next); - if (!p || IS_ERR(p)) { - err = PTR_ERR(p); - break; - } - err = m->op->show(m, p); - if (seq_has_overflowed(m) || err) { - m->count = offs; - if (likely(err <= 0)) - break; - } - pos = next; - } - m->op->stop(m, p); - n = min(m->count, size); - err = copy_to_user(buf, m->buf, n); - if (err) - goto Efault; - copied += n; - m->count -= n; - if (m->count) - m->from = n; - else - pos++; - m->index = pos; -Done: - if (!copied) - copied = err; - else { - *ppos += copied; - m->read_pos += copied; - } - file->f_version = m->version; - mutex_unlock(&m->lock); - return copied; -Enomem: - err = -ENOMEM; - goto Done; -Efault: - err = -EFAULT; - goto Done; -} -EXPORT_SYMBOL(seq_read); - -/** - * seq_lseek - ->llseek() method for sequential files. - * @file: the file in question - * @offset: new position - * @whence: 0 for absolute, 1 for relative position - * - * Ready-made ->f_op->llseek() - */ -loff_t seq_lseek(struct file *file, loff_t offset, int whence) -{ - struct seq_file *m = file->private_data; - loff_t retval = -EINVAL; - - mutex_lock(&m->lock); - m->version = file->f_version; - switch (whence) { - case SEEK_CUR: - offset += file->f_pos; - case SEEK_SET: - if (offset < 0) - break; - retval = offset; - if (offset != m->read_pos) { - while ((retval = traverse(m, offset)) == -EAGAIN) - ; - if (retval) { - /* with extreme prejudice... */ - file->f_pos = 0; - m->read_pos = 0; - m->version = 0; - m->index = 0; - m->count = 0; - } else { - m->read_pos = offset; - retval = file->f_pos = offset; - } - } else { - file->f_pos = offset; - } - } - file->f_version = m->version; - mutex_unlock(&m->lock); - return retval; -} -EXPORT_SYMBOL(seq_lseek); - -/** - * seq_release - free the structures associated with sequential file. - * @file: file in question - * @inode: its inode - * - * Frees the structures associated with sequential file; can be used - * as ->f_op->release() if you don't have private data to destroy. - */ -int seq_release(struct inode *inode, struct file *file) -{ - struct seq_file *m = file->private_data; - kvfree(m->buf); - kfree(m); - return 0; -} -EXPORT_SYMBOL(seq_release); - -/** - * seq_escape - print string into buffer, escaping some characters - * @m: target buffer - * @s: string - * @esc: set of characters that need escaping - * - * Puts string into buffer, replacing each occurrence of character from - * @esc with usual octal escape. - * Use seq_has_overflowed() to check for errors. - */ -void seq_escape(struct seq_file *m, const char *s, const char *esc) -{ - char *buf; - size_t size = seq_get_buf(m, &buf); - int ret; - - ret = string_escape_str(s, buf, size, ESCAPE_OCTAL, esc); - seq_commit(m, ret < size ? ret : -1); -} -EXPORT_SYMBOL(seq_escape); - -void seq_vprintf(struct seq_file *m, const char *f, va_list args) -{ - int len; - - if (m->count < m->size) { - len = vsnprintf(m->buf + m->count, m->size - m->count, f, args); - if (m->count + len < m->size) { - m->count += len; - return; - } - } - seq_set_overflow(m); -} -EXPORT_SYMBOL(seq_vprintf); - -void seq_printf(struct seq_file *m, const char *f, ...) -{ - va_list args; - - va_start(args, f); - seq_vprintf(m, f, args); - va_end(args); -} -EXPORT_SYMBOL(seq_printf); - -/** - * mangle_path - mangle and copy path to buffer beginning - * @s: buffer start - * @p: beginning of path in above buffer - * @esc: set of characters that need escaping - * - * Copy the path from @p to @s, replacing each occurrence of character from - * @esc with usual octal escape. - * Returns pointer past last written character in @s, or NULL in case of - * failure. - */ -char *mangle_path(char *s, const char *p, const char *esc) -{ - while (s <= p) { - char c = *p++; - if (!c) { - return s; - } else if (!strchr(esc, c)) { - *s++ = c; - } else if (s + 4 > p) { - break; - } else { - *s++ = '\\'; - *s++ = '0' + ((c & 0300) >> 6); - *s++ = '0' + ((c & 070) >> 3); - *s++ = '0' + (c & 07); - } - } - return NULL; -} -EXPORT_SYMBOL(mangle_path); - -/** - * seq_path - seq_file interface to print a pathname - * @m: the seq_file handle - * @path: the struct path to print - * @esc: set of characters to escape in the output - * - * return the absolute path of 'path', as represented by the - * dentry / mnt pair in the path parameter. - */ -int seq_path(struct seq_file *m, const struct path *path, const char *esc) -{ - char *buf; - size_t size = seq_get_buf(m, &buf); - int res = -1; - - if (size) { - char *p = d_path(path, buf, size); - if (!IS_ERR(p)) { - char *end = mangle_path(buf, p, esc); - if (end) - res = end - buf; - } - } - seq_commit(m, res); - - return res; -} -EXPORT_SYMBOL(seq_path); - -/** - * seq_file_path - seq_file interface to print a pathname of a file - * @m: the seq_file handle - * @file: the struct file to print - * @esc: set of characters to escape in the output - * - * return the absolute path to the file. - */ -int seq_file_path(struct seq_file *m, struct file *file, const char *esc) -{ - return seq_path(m, &file->f_path, esc); -} -EXPORT_SYMBOL(seq_file_path); - -/* - * Same as seq_path, but relative to supplied root. - */ -int seq_path_root(struct seq_file *m, const struct path *path, - const struct path *root, const char *esc) -{ - char *buf; - size_t size = seq_get_buf(m, &buf); - int res = -ENAMETOOLONG; - - if (size) { - char *p; - - p = __d_path(path, root, buf, size); - if (!p) - return SEQ_SKIP; - res = PTR_ERR(p); - if (!IS_ERR(p)) { - char *end = mangle_path(buf, p, esc); - if (end) - res = end - buf; - else - res = -ENAMETOOLONG; - } - } - seq_commit(m, res); - - return res < 0 && res != -ENAMETOOLONG ? res : 0; -} - -/* - * returns the path of the 'dentry' from the root of its filesystem. - */ -int seq_dentry(struct seq_file *m, struct dentry *dentry, const char *esc) -{ - char *buf; - size_t size = seq_get_buf(m, &buf); - int res = -1; - - if (size) { - char *p = dentry_path(dentry, buf, size); - if (!IS_ERR(p)) { - char *end = mangle_path(buf, p, esc); - if (end) - res = end - buf; - } - } - seq_commit(m, res); - - return res; -} -EXPORT_SYMBOL(seq_dentry); - -static void *single_start(struct seq_file *p, loff_t *pos) -{ - return NULL + (*pos == 0); -} - -static void *single_next(struct seq_file *p, void *v, loff_t *pos) -{ - ++*pos; - return NULL; -} - -static void single_stop(struct seq_file *p, void *v) -{ -} - -int single_open(struct file *file, int (*show)(struct seq_file *, void *), - void *data) -{ - struct seq_operations *op = kmalloc(sizeof(*op), GFP_KERNEL); - int res = -ENOMEM; - - if (op) { - op->start = single_start; - op->next = single_next; - op->stop = single_stop; - op->show = show; - res = seq_open(file, op); - if (!res) - ((struct seq_file *)file->private_data)->private = data; - else - kfree(op); - } - return res; -} -EXPORT_SYMBOL(single_open); - -int single_open_size(struct file *file, int (*show)(struct seq_file *, void *), - void *data, size_t size) -{ - char *buf = seq_buf_alloc(size); - int ret; - if (!buf) - return -ENOMEM; - ret = single_open(file, show, data); - if (ret) { - kvfree(buf); - return ret; - } - ((struct seq_file *)file->private_data)->buf = buf; - ((struct seq_file *)file->private_data)->size = size; - return 0; -} -EXPORT_SYMBOL(single_open_size); - -int single_release(struct inode *inode, struct file *file) -{ - const struct seq_operations *op = ((struct seq_file *)file->private_data)->op; - int res = seq_release(inode, file); - kfree(op); - return res; -} -EXPORT_SYMBOL(single_release); - -int seq_release_private(struct inode *inode, struct file *file) -{ - struct seq_file *seq = file->private_data; - - kfree(seq->private); - seq->private = NULL; - return seq_release(inode, file); -} -EXPORT_SYMBOL(seq_release_private); - -void *__seq_open_private(struct file *f, const struct seq_operations *ops, - int psize) -{ - int rc; - void *private; - struct seq_file *seq; - - private = kzalloc(psize, GFP_KERNEL); - if (private == NULL) - goto out; - - rc = seq_open(f, ops); - if (rc < 0) - goto out_free; - - seq = f->private_data; - seq->private = private; - return private; - -out_free: - kfree(private); -out: - return NULL; -} -EXPORT_SYMBOL(__seq_open_private); - -int seq_open_private(struct file *filp, const struct seq_operations *ops, - int psize) -{ - return __seq_open_private(filp, ops, psize) ? 0 : -ENOMEM; -} -EXPORT_SYMBOL(seq_open_private); - -void seq_putc(struct seq_file *m, char c) -{ - if (m->count >= m->size) - return; - - m->buf[m->count++] = c; -} -EXPORT_SYMBOL(seq_putc); - -void seq_puts(struct seq_file *m, const char *s) -{ - int len = strlen(s); - - if (m->count + len >= m->size) { - seq_set_overflow(m); - return; - } - memcpy(m->buf + m->count, s, len); - m->count += len; -} -EXPORT_SYMBOL(seq_puts); - -/* - * A helper routine for putting decimal numbers without rich format of printf(). - * only 'unsigned long long' is supported. - * This routine will put strlen(delimiter) + number into seq_file. - * This routine is very quick when you show lots of numbers. - * In usual cases, it will be better to use seq_printf(). It's easier to read. - */ -void seq_put_decimal_ull(struct seq_file *m, const char *delimiter, - unsigned long long num) -{ - int len; - - if (m->count + 2 >= m->size) /* we'll write 2 bytes at least */ - goto overflow; - - len = strlen(delimiter); - if (m->count + len >= m->size) - goto overflow; - - memcpy(m->buf + m->count, delimiter, len); - m->count += len; - - if (m->count + 1 >= m->size) - goto overflow; - - if (num < 10) { - m->buf[m->count++] = num + '0'; - return; - } - - len = num_to_str(m->buf + m->count, m->size - m->count, num); - if (!len) - goto overflow; - - m->count += len; - return; - -overflow: - seq_set_overflow(m); -} -EXPORT_SYMBOL(seq_put_decimal_ull); - -void seq_put_decimal_ll(struct seq_file *m, const char *delimiter, long long num) -{ - int len; - - if (m->count + 3 >= m->size) /* we'll write 2 bytes at least */ - goto overflow; - - len = strlen(delimiter); - if (m->count + len >= m->size) - goto overflow; - - memcpy(m->buf + m->count, delimiter, len); - m->count += len; - - if (m->count + 2 >= m->size) - goto overflow; - - if (num < 0) { - m->buf[m->count++] = '-'; - num = -num; - } - - if (num < 10) { - m->buf[m->count++] = num + '0'; - return; - } - - len = num_to_str(m->buf + m->count, m->size - m->count, num); - if (!len) - goto overflow; - - m->count += len; - return; - -overflow: - seq_set_overflow(m); -} -EXPORT_SYMBOL(seq_put_decimal_ll); - -/** - * seq_write - write arbitrary data to buffer - * @seq: seq_file identifying the buffer to which data should be written - * @data: data address - * @len: number of bytes - * - * Return 0 on success, non-zero otherwise. - */ -int seq_write(struct seq_file *seq, const void *data, size_t len) -{ - if (seq->count + len < seq->size) { - memcpy(seq->buf + seq->count, data, len); - seq->count += len; - return 0; - } - seq_set_overflow(seq); - return -1; -} -EXPORT_SYMBOL(seq_write); - -/** - * seq_pad - write padding spaces to buffer - * @m: seq_file identifying the buffer to which data should be written - * @c: the byte to append after padding if non-zero - */ -void seq_pad(struct seq_file *m, char c) -{ - int size = m->pad_until - m->count; - if (size > 0) - seq_printf(m, "%*s", size, ""); - if (c) - seq_putc(m, c); -} -EXPORT_SYMBOL(seq_pad); - -/* A complete analogue of print_hex_dump() */ -void seq_hex_dump(struct seq_file *m, const char *prefix_str, int prefix_type, - int rowsize, int groupsize, const void *buf, size_t len, - bool ascii) -{ - const u8 *ptr = buf; - int i, linelen, remaining = len; - char *buffer; - size_t size; - int ret; - - if (rowsize != 16 && rowsize != 32) - rowsize = 16; - - for (i = 0; i < len && !seq_has_overflowed(m); i += rowsize) { - linelen = min(remaining, rowsize); - remaining -= rowsize; - - switch (prefix_type) { - case DUMP_PREFIX_ADDRESS: - seq_printf(m, "%s%p: ", prefix_str, ptr + i); - break; - case DUMP_PREFIX_OFFSET: - seq_printf(m, "%s%.8x: ", prefix_str, i); - break; - default: - seq_printf(m, "%s", prefix_str); - break; - } - - size = seq_get_buf(m, &buffer); - ret = hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize, - buffer, size, ascii); - seq_commit(m, ret < size ? ret : -1); - - seq_putc(m, '\n'); - } -} -EXPORT_SYMBOL(seq_hex_dump); - -struct list_head *seq_list_start(struct list_head *head, loff_t pos) -{ - struct list_head *lh; - - list_for_each(lh, head) - if (pos-- == 0) - return lh; - - return NULL; -} -EXPORT_SYMBOL(seq_list_start); - -struct list_head *seq_list_start_head(struct list_head *head, loff_t pos) -{ - if (!pos) - return head; - - return seq_list_start(head, pos - 1); -} -EXPORT_SYMBOL(seq_list_start_head); - -struct list_head *seq_list_next(void *v, struct list_head *head, loff_t *ppos) -{ - struct list_head *lh; - - lh = ((struct list_head *)v)->next; - ++*ppos; - return lh == head ? NULL : lh; -} -EXPORT_SYMBOL(seq_list_next); - -/** - * seq_hlist_start - start an iteration of a hlist - * @head: the head of the hlist - * @pos: the start position of the sequence - * - * Called at seq_file->op->start(). - */ -struct hlist_node *seq_hlist_start(struct hlist_head *head, loff_t pos) -{ - struct hlist_node *node; - - hlist_for_each(node, head) - if (pos-- == 0) - return node; - return NULL; -} -EXPORT_SYMBOL(seq_hlist_start); - -/** - * seq_hlist_start_head - start an iteration of a hlist - * @head: the head of the hlist - * @pos: the start position of the sequence - * - * Called at seq_file->op->start(). Call this function if you want to - * print a header at the top of the output. - */ -struct hlist_node *seq_hlist_start_head(struct hlist_head *head, loff_t pos) -{ - if (!pos) - return SEQ_START_TOKEN; - - return seq_hlist_start(head, pos - 1); -} -EXPORT_SYMBOL(seq_hlist_start_head); - -/** - * seq_hlist_next - move to the next position of the hlist - * @v: the current iterator - * @head: the head of the hlist - * @ppos: the current position - * - * Called at seq_file->op->next(). - */ -struct hlist_node *seq_hlist_next(void *v, struct hlist_head *head, - loff_t *ppos) -{ - struct hlist_node *node = v; - - ++*ppos; - if (v == SEQ_START_TOKEN) - return head->first; - else - return node->next; -} -EXPORT_SYMBOL(seq_hlist_next); - -/** - * seq_hlist_start_rcu - start an iteration of a hlist protected by RCU - * @head: the head of the hlist - * @pos: the start position of the sequence - * - * Called at seq_file->op->start(). - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as hlist_add_head_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -struct hlist_node *seq_hlist_start_rcu(struct hlist_head *head, - loff_t pos) -{ - struct hlist_node *node; - - __hlist_for_each_rcu(node, head) - if (pos-- == 0) - return node; - return NULL; -} -EXPORT_SYMBOL(seq_hlist_start_rcu); - -/** - * seq_hlist_start_head_rcu - start an iteration of a hlist protected by RCU - * @head: the head of the hlist - * @pos: the start position of the sequence - * - * Called at seq_file->op->start(). Call this function if you want to - * print a header at the top of the output. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as hlist_add_head_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -struct hlist_node *seq_hlist_start_head_rcu(struct hlist_head *head, - loff_t pos) -{ - if (!pos) - return SEQ_START_TOKEN; - - return seq_hlist_start_rcu(head, pos - 1); -} -EXPORT_SYMBOL(seq_hlist_start_head_rcu); - -/** - * seq_hlist_next_rcu - move to the next position of the hlist protected by RCU - * @v: the current iterator - * @head: the head of the hlist - * @ppos: the current position - * - * Called at seq_file->op->next(). - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as hlist_add_head_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -struct hlist_node *seq_hlist_next_rcu(void *v, - struct hlist_head *head, - loff_t *ppos) -{ - struct hlist_node *node = v; - - ++*ppos; - if (v == SEQ_START_TOKEN) - return rcu_dereference(head->first); - else - return rcu_dereference(node->next); -} -EXPORT_SYMBOL(seq_hlist_next_rcu); - -/** - * seq_hlist_start_precpu - start an iteration of a percpu hlist array - * @head: pointer to percpu array of struct hlist_heads - * @cpu: pointer to cpu "cursor" - * @pos: start position of sequence - * - * Called at seq_file->op->start(). - */ -struct hlist_node * -seq_hlist_start_percpu(struct hlist_head __percpu *head, int *cpu, loff_t pos) -{ - struct hlist_node *node; - - for_each_possible_cpu(*cpu) { - hlist_for_each(node, per_cpu_ptr(head, *cpu)) { - if (pos-- == 0) - return node; - } - } - return NULL; -} -EXPORT_SYMBOL(seq_hlist_start_percpu); - -/** - * seq_hlist_next_percpu - move to the next position of the percpu hlist array - * @v: pointer to current hlist_node - * @head: pointer to percpu array of struct hlist_heads - * @cpu: pointer to cpu "cursor" - * @pos: start position of sequence - * - * Called at seq_file->op->next(). - */ -struct hlist_node * -seq_hlist_next_percpu(void *v, struct hlist_head __percpu *head, - int *cpu, loff_t *pos) -{ - struct hlist_node *node = v; - - ++*pos; - - if (node->next) - return node->next; - - for (*cpu = cpumask_next(*cpu, cpu_possible_mask); *cpu < nr_cpu_ids; - *cpu = cpumask_next(*cpu, cpu_possible_mask)) { - struct hlist_head *bucket = per_cpu_ptr(head, *cpu); - - if (!hlist_empty(bucket)) - return bucket->first; - } - return NULL; -} -EXPORT_SYMBOL(seq_hlist_next_percpu); diff --git a/src/linux/fs/splice.c b/src/linux/fs/splice.c deleted file mode 100644 index 5a7750b..0000000 --- a/src/linux/fs/splice.c +++ /dev/null @@ -1,1750 +0,0 @@ -/* - * "splice": joining two ropes together by interweaving their strands. - * - * This is the "extended pipe" functionality, where a pipe is used as - * an arbitrary in-memory buffer. Think of a pipe as a small kernel - * buffer that you can use to transfer data from one end to the other. - * - * The traditional unix read/write is extended with a "splice()" operation - * that transfers data buffers to or from a pipe buffer. - * - * Named by Larry McVoy, original implementation from Linus, extended by - * Jens to support splicing to files, network, direct splicing, etc and - * fixing lots of bugs. - * - * Copyright (C) 2005-2006 Jens Axboe - * Copyright (C) 2005-2006 Linus Torvalds - * Copyright (C) 2006 Ingo Molnar - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -/* - * Attempt to steal a page from a pipe buffer. This should perhaps go into - * a vm helper function, it's already simplified quite a bit by the - * addition of remove_mapping(). If success is returned, the caller may - * attempt to reuse this page for another destination. - */ -static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) -{ - struct page *page = buf->page; - struct address_space *mapping; - - lock_page(page); - - mapping = page_mapping(page); - if (mapping) { - WARN_ON(!PageUptodate(page)); - - /* - * At least for ext2 with nobh option, we need to wait on - * writeback completing on this page, since we'll remove it - * from the pagecache. Otherwise truncate wont wait on the - * page, allowing the disk blocks to be reused by someone else - * before we actually wrote our data to them. fs corruption - * ensues. - */ - wait_on_page_writeback(page); - - if (page_has_private(page) && - !try_to_release_page(page, GFP_KERNEL)) - goto out_unlock; - - /* - * If we succeeded in removing the mapping, set LRU flag - * and return good. - */ - if (remove_mapping(mapping, page)) { - buf->flags |= PIPE_BUF_FLAG_LRU; - return 0; - } - } - - /* - * Raced with truncate or failed to remove page from current - * address space, unlock and return failure. - */ -out_unlock: - unlock_page(page); - return 1; -} - -static void page_cache_pipe_buf_release(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) -{ - put_page(buf->page); - buf->flags &= ~PIPE_BUF_FLAG_LRU; -} - -/* - * Check whether the contents of buf is OK to access. Since the content - * is a page cache page, IO may be in flight. - */ -static int page_cache_pipe_buf_confirm(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) -{ - struct page *page = buf->page; - int err; - - if (!PageUptodate(page)) { - lock_page(page); - - /* - * Page got truncated/unhashed. This will cause a 0-byte - * splice, if this is the first page. - */ - if (!page->mapping) { - err = -ENODATA; - goto error; - } - - /* - * Uh oh, read-error from disk. - */ - if (!PageUptodate(page)) { - err = -EIO; - goto error; - } - - /* - * Page is ok afterall, we are done. - */ - unlock_page(page); - } - - return 0; -error: - unlock_page(page); - return err; -} - -const struct pipe_buf_operations page_cache_pipe_buf_ops = { - .can_merge = 0, - .confirm = page_cache_pipe_buf_confirm, - .release = page_cache_pipe_buf_release, - .steal = page_cache_pipe_buf_steal, - .get = generic_pipe_buf_get, -}; - -static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) -{ - if (!(buf->flags & PIPE_BUF_FLAG_GIFT)) - return 1; - - buf->flags |= PIPE_BUF_FLAG_LRU; - return generic_pipe_buf_steal(pipe, buf); -} - -static const struct pipe_buf_operations user_page_pipe_buf_ops = { - .can_merge = 0, - .confirm = generic_pipe_buf_confirm, - .release = page_cache_pipe_buf_release, - .steal = user_page_pipe_buf_steal, - .get = generic_pipe_buf_get, -}; - -static void wakeup_pipe_readers(struct pipe_inode_info *pipe) -{ - smp_mb(); - if (waitqueue_active(&pipe->wait)) - wake_up_interruptible(&pipe->wait); - kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); -} - -/** - * splice_to_pipe - fill passed data into a pipe - * @pipe: pipe to fill - * @spd: data to fill - * - * Description: - * @spd contains a map of pages and len/offset tuples, along with - * the struct pipe_buf_operations associated with these pages. This - * function will link that data to the pipe. - * - */ -ssize_t splice_to_pipe(struct pipe_inode_info *pipe, - struct splice_pipe_desc *spd) -{ - unsigned int spd_pages = spd->nr_pages; - int ret = 0, page_nr = 0; - - if (!spd_pages) - return 0; - - if (unlikely(!pipe->readers)) { - send_sig(SIGPIPE, current, 0); - ret = -EPIPE; - goto out; - } - - while (pipe->nrbufs < pipe->buffers) { - int newbuf = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1); - struct pipe_buffer *buf = pipe->bufs + newbuf; - - buf->page = spd->pages[page_nr]; - buf->offset = spd->partial[page_nr].offset; - buf->len = spd->partial[page_nr].len; - buf->private = spd->partial[page_nr].private; - buf->ops = spd->ops; - - pipe->nrbufs++; - page_nr++; - ret += buf->len; - - if (!--spd->nr_pages) - break; - } - - if (!ret) - ret = -EAGAIN; - -out: - while (page_nr < spd_pages) - spd->spd_release(spd, page_nr++); - - return ret; -} -EXPORT_SYMBOL_GPL(splice_to_pipe); - -ssize_t add_to_pipe(struct pipe_inode_info *pipe, struct pipe_buffer *buf) -{ - int ret; - - if (unlikely(!pipe->readers)) { - send_sig(SIGPIPE, current, 0); - ret = -EPIPE; - } else if (pipe->nrbufs == pipe->buffers) { - ret = -EAGAIN; - } else { - int newbuf = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1); - pipe->bufs[newbuf] = *buf; - pipe->nrbufs++; - return buf->len; - } - pipe_buf_release(pipe, buf); - return ret; -} -EXPORT_SYMBOL(add_to_pipe); - -void spd_release_page(struct splice_pipe_desc *spd, unsigned int i) -{ - put_page(spd->pages[i]); -} - -/* - * Check if we need to grow the arrays holding pages and partial page - * descriptions. - */ -int splice_grow_spd(const struct pipe_inode_info *pipe, struct splice_pipe_desc *spd) -{ - unsigned int buffers = ACCESS_ONCE(pipe->buffers); - - spd->nr_pages_max = buffers; - if (buffers <= PIPE_DEF_BUFFERS) - return 0; - - spd->pages = kmalloc(buffers * sizeof(struct page *), GFP_KERNEL); - spd->partial = kmalloc(buffers * sizeof(struct partial_page), GFP_KERNEL); - - if (spd->pages && spd->partial) - return 0; - - kfree(spd->pages); - kfree(spd->partial); - return -ENOMEM; -} - -void splice_shrink_spd(struct splice_pipe_desc *spd) -{ - if (spd->nr_pages_max <= PIPE_DEF_BUFFERS) - return; - - kfree(spd->pages); - kfree(spd->partial); -} - -/** - * generic_file_splice_read - splice data from file to a pipe - * @in: file to splice from - * @ppos: position in @in - * @pipe: pipe to splice to - * @len: number of bytes to splice - * @flags: splice modifier flags - * - * Description: - * Will read pages from given file and fill them into a pipe. Can be - * used as long as it has more or less sane ->read_iter(). - * - */ -ssize_t generic_file_splice_read(struct file *in, loff_t *ppos, - struct pipe_inode_info *pipe, size_t len, - unsigned int flags) -{ - struct iov_iter to; - struct kiocb kiocb; - int idx, ret; - - iov_iter_pipe(&to, ITER_PIPE | READ, pipe, len); - idx = to.idx; - init_sync_kiocb(&kiocb, in); - kiocb.ki_pos = *ppos; - ret = in->f_op->read_iter(&kiocb, &to); - if (ret > 0) { - *ppos = kiocb.ki_pos; - file_accessed(in); - } else if (ret < 0) { - to.idx = idx; - to.iov_offset = 0; - iov_iter_advance(&to, 0); /* to free what was emitted */ - /* - * callers of ->splice_read() expect -EAGAIN on - * "can't put anything in there", rather than -EFAULT. - */ - if (ret == -EFAULT) - ret = -EAGAIN; - } - - return ret; -} -EXPORT_SYMBOL(generic_file_splice_read); - -const struct pipe_buf_operations default_pipe_buf_ops = { - .can_merge = 0, - .confirm = generic_pipe_buf_confirm, - .release = generic_pipe_buf_release, - .steal = generic_pipe_buf_steal, - .get = generic_pipe_buf_get, -}; - -static int generic_pipe_buf_nosteal(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) -{ - return 1; -} - -/* Pipe buffer operations for a socket and similar. */ -const struct pipe_buf_operations nosteal_pipe_buf_ops = { - .can_merge = 0, - .confirm = generic_pipe_buf_confirm, - .release = generic_pipe_buf_release, - .steal = generic_pipe_buf_nosteal, - .get = generic_pipe_buf_get, -}; -EXPORT_SYMBOL(nosteal_pipe_buf_ops); - -static ssize_t kernel_readv(struct file *file, const struct kvec *vec, - unsigned long vlen, loff_t offset) -{ - mm_segment_t old_fs; - loff_t pos = offset; - ssize_t res; - - old_fs = get_fs(); - set_fs(get_ds()); - /* The cast to a user pointer is valid due to the set_fs() */ - res = vfs_readv(file, (const struct iovec __user *)vec, vlen, &pos, 0); - set_fs(old_fs); - - return res; -} - -ssize_t kernel_write(struct file *file, const char *buf, size_t count, - loff_t pos) -{ - mm_segment_t old_fs; - ssize_t res; - - old_fs = get_fs(); - set_fs(get_ds()); - /* The cast to a user pointer is valid due to the set_fs() */ - res = vfs_write(file, (__force const char __user *)buf, count, &pos); - set_fs(old_fs); - - return res; -} -EXPORT_SYMBOL(kernel_write); - -static ssize_t default_file_splice_read(struct file *in, loff_t *ppos, - struct pipe_inode_info *pipe, size_t len, - unsigned int flags) -{ - struct kvec *vec, __vec[PIPE_DEF_BUFFERS]; - struct iov_iter to; - struct page **pages; - unsigned int nr_pages; - size_t offset, dummy, copied = 0; - ssize_t res; - int i; - - if (pipe->nrbufs == pipe->buffers) - return -EAGAIN; - - /* - * Try to keep page boundaries matching to source pagecache ones - - * it probably won't be much help, but... - */ - offset = *ppos & ~PAGE_MASK; - - iov_iter_pipe(&to, ITER_PIPE | READ, pipe, len + offset); - - res = iov_iter_get_pages_alloc(&to, &pages, len + offset, &dummy); - if (res <= 0) - return -ENOMEM; - - BUG_ON(dummy); - nr_pages = DIV_ROUND_UP(res, PAGE_SIZE); - - vec = __vec; - if (nr_pages > PIPE_DEF_BUFFERS) { - vec = kmalloc(nr_pages * sizeof(struct kvec), GFP_KERNEL); - if (unlikely(!vec)) { - res = -ENOMEM; - goto out; - } - } - - pipe->bufs[to.idx].offset = offset; - pipe->bufs[to.idx].len -= offset; - - for (i = 0; i < nr_pages; i++) { - size_t this_len = min_t(size_t, len, PAGE_SIZE - offset); - vec[i].iov_base = page_address(pages[i]) + offset; - vec[i].iov_len = this_len; - len -= this_len; - offset = 0; - } - - res = kernel_readv(in, vec, nr_pages, *ppos); - if (res > 0) { - copied = res; - *ppos += res; - } - - if (vec != __vec) - kfree(vec); -out: - for (i = 0; i < nr_pages; i++) - put_page(pages[i]); - kvfree(pages); - iov_iter_advance(&to, copied); /* truncates and discards */ - return res; -} - -/* - * Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos' - * using sendpage(). Return the number of bytes sent. - */ -static int pipe_to_sendpage(struct pipe_inode_info *pipe, - struct pipe_buffer *buf, struct splice_desc *sd) -{ - struct file *file = sd->u.file; - loff_t pos = sd->pos; - int more; - - if (!likely(file->f_op->sendpage)) - return -EINVAL; - - more = (sd->flags & SPLICE_F_MORE) ? MSG_MORE : 0; - - if (sd->len < sd->total_len && pipe->nrbufs > 1) - more |= MSG_SENDPAGE_NOTLAST; - - return file->f_op->sendpage(file, buf->page, buf->offset, - sd->len, &pos, more); -} - -static void wakeup_pipe_writers(struct pipe_inode_info *pipe) -{ - smp_mb(); - if (waitqueue_active(&pipe->wait)) - wake_up_interruptible(&pipe->wait); - kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); -} - -/** - * splice_from_pipe_feed - feed available data from a pipe to a file - * @pipe: pipe to splice from - * @sd: information to @actor - * @actor: handler that splices the data - * - * Description: - * This function loops over the pipe and calls @actor to do the - * actual moving of a single struct pipe_buffer to the desired - * destination. It returns when there's no more buffers left in - * the pipe or if the requested number of bytes (@sd->total_len) - * have been copied. It returns a positive number (one) if the - * pipe needs to be filled with more data, zero if the required - * number of bytes have been copied and -errno on error. - * - * This, together with splice_from_pipe_{begin,end,next}, may be - * used to implement the functionality of __splice_from_pipe() when - * locking is required around copying the pipe buffers to the - * destination. - */ -static int splice_from_pipe_feed(struct pipe_inode_info *pipe, struct splice_desc *sd, - splice_actor *actor) -{ - int ret; - - while (pipe->nrbufs) { - struct pipe_buffer *buf = pipe->bufs + pipe->curbuf; - - sd->len = buf->len; - if (sd->len > sd->total_len) - sd->len = sd->total_len; - - ret = pipe_buf_confirm(pipe, buf); - if (unlikely(ret)) { - if (ret == -ENODATA) - ret = 0; - return ret; - } - - ret = actor(pipe, buf, sd); - if (ret <= 0) - return ret; - - buf->offset += ret; - buf->len -= ret; - - sd->num_spliced += ret; - sd->len -= ret; - sd->pos += ret; - sd->total_len -= ret; - - if (!buf->len) { - pipe_buf_release(pipe, buf); - pipe->curbuf = (pipe->curbuf + 1) & (pipe->buffers - 1); - pipe->nrbufs--; - if (pipe->files) - sd->need_wakeup = true; - } - - if (!sd->total_len) - return 0; - } - - return 1; -} - -/** - * splice_from_pipe_next - wait for some data to splice from - * @pipe: pipe to splice from - * @sd: information about the splice operation - * - * Description: - * This function will wait for some data and return a positive - * value (one) if pipe buffers are available. It will return zero - * or -errno if no more data needs to be spliced. - */ -static int splice_from_pipe_next(struct pipe_inode_info *pipe, struct splice_desc *sd) -{ - /* - * Check for signal early to make process killable when there are - * always buffers available - */ - if (signal_pending(current)) - return -ERESTARTSYS; - - while (!pipe->nrbufs) { - if (!pipe->writers) - return 0; - - if (!pipe->waiting_writers && sd->num_spliced) - return 0; - - if (sd->flags & SPLICE_F_NONBLOCK) - return -EAGAIN; - - if (signal_pending(current)) - return -ERESTARTSYS; - - if (sd->need_wakeup) { - wakeup_pipe_writers(pipe); - sd->need_wakeup = false; - } - - pipe_wait(pipe); - } - - return 1; -} - -/** - * splice_from_pipe_begin - start splicing from pipe - * @sd: information about the splice operation - * - * Description: - * This function should be called before a loop containing - * splice_from_pipe_next() and splice_from_pipe_feed() to - * initialize the necessary fields of @sd. - */ -static void splice_from_pipe_begin(struct splice_desc *sd) -{ - sd->num_spliced = 0; - sd->need_wakeup = false; -} - -/** - * splice_from_pipe_end - finish splicing from pipe - * @pipe: pipe to splice from - * @sd: information about the splice operation - * - * Description: - * This function will wake up pipe writers if necessary. It should - * be called after a loop containing splice_from_pipe_next() and - * splice_from_pipe_feed(). - */ -static void splice_from_pipe_end(struct pipe_inode_info *pipe, struct splice_desc *sd) -{ - if (sd->need_wakeup) - wakeup_pipe_writers(pipe); -} - -/** - * __splice_from_pipe - splice data from a pipe to given actor - * @pipe: pipe to splice from - * @sd: information to @actor - * @actor: handler that splices the data - * - * Description: - * This function does little more than loop over the pipe and call - * @actor to do the actual moving of a single struct pipe_buffer to - * the desired destination. See pipe_to_file, pipe_to_sendpage, or - * pipe_to_user. - * - */ -ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd, - splice_actor *actor) -{ - int ret; - - splice_from_pipe_begin(sd); - do { - cond_resched(); - ret = splice_from_pipe_next(pipe, sd); - if (ret > 0) - ret = splice_from_pipe_feed(pipe, sd, actor); - } while (ret > 0); - splice_from_pipe_end(pipe, sd); - - return sd->num_spliced ? sd->num_spliced : ret; -} -EXPORT_SYMBOL(__splice_from_pipe); - -/** - * splice_from_pipe - splice data from a pipe to a file - * @pipe: pipe to splice from - * @out: file to splice to - * @ppos: position in @out - * @len: how many bytes to splice - * @flags: splice modifier flags - * @actor: handler that splices the data - * - * Description: - * See __splice_from_pipe. This function locks the pipe inode, - * otherwise it's identical to __splice_from_pipe(). - * - */ -ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, - loff_t *ppos, size_t len, unsigned int flags, - splice_actor *actor) -{ - ssize_t ret; - struct splice_desc sd = { - .total_len = len, - .flags = flags, - .pos = *ppos, - .u.file = out, - }; - - pipe_lock(pipe); - ret = __splice_from_pipe(pipe, &sd, actor); - pipe_unlock(pipe); - - return ret; -} - -/** - * iter_file_splice_write - splice data from a pipe to a file - * @pipe: pipe info - * @out: file to write to - * @ppos: position in @out - * @len: number of bytes to splice - * @flags: splice modifier flags - * - * Description: - * Will either move or copy pages (determined by @flags options) from - * the given pipe inode to the given file. - * This one is ->write_iter-based. - * - */ -ssize_t -iter_file_splice_write(struct pipe_inode_info *pipe, struct file *out, - loff_t *ppos, size_t len, unsigned int flags) -{ - struct splice_desc sd = { - .total_len = len, - .flags = flags, - .pos = *ppos, - .u.file = out, - }; - int nbufs = pipe->buffers; - struct bio_vec *array = kcalloc(nbufs, sizeof(struct bio_vec), - GFP_KERNEL); - ssize_t ret; - - if (unlikely(!array)) - return -ENOMEM; - - pipe_lock(pipe); - - splice_from_pipe_begin(&sd); - while (sd.total_len) { - struct iov_iter from; - size_t left; - int n, idx; - - ret = splice_from_pipe_next(pipe, &sd); - if (ret <= 0) - break; - - if (unlikely(nbufs < pipe->buffers)) { - kfree(array); - nbufs = pipe->buffers; - array = kcalloc(nbufs, sizeof(struct bio_vec), - GFP_KERNEL); - if (!array) { - ret = -ENOMEM; - break; - } - } - - /* build the vector */ - left = sd.total_len; - for (n = 0, idx = pipe->curbuf; left && n < pipe->nrbufs; n++, idx++) { - struct pipe_buffer *buf = pipe->bufs + idx; - size_t this_len = buf->len; - - if (this_len > left) - this_len = left; - - if (idx == pipe->buffers - 1) - idx = -1; - - ret = pipe_buf_confirm(pipe, buf); - if (unlikely(ret)) { - if (ret == -ENODATA) - ret = 0; - goto done; - } - - array[n].bv_page = buf->page; - array[n].bv_len = this_len; - array[n].bv_offset = buf->offset; - left -= this_len; - } - - iov_iter_bvec(&from, ITER_BVEC | WRITE, array, n, - sd.total_len - left); - ret = vfs_iter_write(out, &from, &sd.pos); - if (ret <= 0) - break; - - sd.num_spliced += ret; - sd.total_len -= ret; - *ppos = sd.pos; - - /* dismiss the fully eaten buffers, adjust the partial one */ - while (ret) { - struct pipe_buffer *buf = pipe->bufs + pipe->curbuf; - if (ret >= buf->len) { - ret -= buf->len; - buf->len = 0; - pipe_buf_release(pipe, buf); - pipe->curbuf = (pipe->curbuf + 1) & (pipe->buffers - 1); - pipe->nrbufs--; - if (pipe->files) - sd.need_wakeup = true; - } else { - buf->offset += ret; - buf->len -= ret; - ret = 0; - } - } - } -done: - kfree(array); - splice_from_pipe_end(pipe, &sd); - - pipe_unlock(pipe); - - if (sd.num_spliced) - ret = sd.num_spliced; - - return ret; -} - -EXPORT_SYMBOL(iter_file_splice_write); - -static int write_pipe_buf(struct pipe_inode_info *pipe, struct pipe_buffer *buf, - struct splice_desc *sd) -{ - int ret; - void *data; - loff_t tmp = sd->pos; - - data = kmap(buf->page); - ret = __kernel_write(sd->u.file, data + buf->offset, sd->len, &tmp); - kunmap(buf->page); - - return ret; -} - -static ssize_t default_file_splice_write(struct pipe_inode_info *pipe, - struct file *out, loff_t *ppos, - size_t len, unsigned int flags) -{ - ssize_t ret; - - ret = splice_from_pipe(pipe, out, ppos, len, flags, write_pipe_buf); - if (ret > 0) - *ppos += ret; - - return ret; -} - -/** - * generic_splice_sendpage - splice data from a pipe to a socket - * @pipe: pipe to splice from - * @out: socket to write to - * @ppos: position in @out - * @len: number of bytes to splice - * @flags: splice modifier flags - * - * Description: - * Will send @len bytes from the pipe to a network socket. No data copying - * is involved. - * - */ -ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out, - loff_t *ppos, size_t len, unsigned int flags) -{ - return splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_sendpage); -} - -EXPORT_SYMBOL(generic_splice_sendpage); - -/* - * Attempt to initiate a splice from pipe to file. - */ -static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, - loff_t *ppos, size_t len, unsigned int flags) -{ - ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, - loff_t *, size_t, unsigned int); - - if (out->f_op->splice_write) - splice_write = out->f_op->splice_write; - else - splice_write = default_file_splice_write; - - return splice_write(pipe, out, ppos, len, flags); -} - -/* - * Attempt to initiate a splice from a file to a pipe. - */ -static long do_splice_to(struct file *in, loff_t *ppos, - struct pipe_inode_info *pipe, size_t len, - unsigned int flags) -{ - ssize_t (*splice_read)(struct file *, loff_t *, - struct pipe_inode_info *, size_t, unsigned int); - int ret; - - if (unlikely(!(in->f_mode & FMODE_READ))) - return -EBADF; - - ret = rw_verify_area(READ, in, ppos, len); - if (unlikely(ret < 0)) - return ret; - - if (unlikely(len > MAX_RW_COUNT)) - len = MAX_RW_COUNT; - - if (in->f_op->splice_read) - splice_read = in->f_op->splice_read; - else - splice_read = default_file_splice_read; - - return splice_read(in, ppos, pipe, len, flags); -} - -/** - * splice_direct_to_actor - splices data directly between two non-pipes - * @in: file to splice from - * @sd: actor information on where to splice to - * @actor: handles the data splicing - * - * Description: - * This is a special case helper to splice directly between two - * points, without requiring an explicit pipe. Internally an allocated - * pipe is cached in the process, and reused during the lifetime of - * that process. - * - */ -ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, - splice_direct_actor *actor) -{ - struct pipe_inode_info *pipe; - long ret, bytes; - umode_t i_mode; - size_t len; - int i, flags, more; - - /* - * We require the input being a regular file, as we don't want to - * randomly drop data for eg socket -> socket splicing. Use the - * piped splicing for that! - */ - i_mode = file_inode(in)->i_mode; - if (unlikely(!S_ISREG(i_mode) && !S_ISBLK(i_mode))) - return -EINVAL; - - /* - * neither in nor out is a pipe, setup an internal pipe attached to - * 'out' and transfer the wanted data from 'in' to 'out' through that - */ - pipe = current->splice_pipe; - if (unlikely(!pipe)) { - pipe = alloc_pipe_info(); - if (!pipe) - return -ENOMEM; - - /* - * We don't have an immediate reader, but we'll read the stuff - * out of the pipe right after the splice_to_pipe(). So set - * PIPE_READERS appropriately. - */ - pipe->readers = 1; - - current->splice_pipe = pipe; - } - - /* - * Do the splice. - */ - ret = 0; - bytes = 0; - len = sd->total_len; - flags = sd->flags; - - /* - * Don't block on output, we have to drain the direct pipe. - */ - sd->flags &= ~SPLICE_F_NONBLOCK; - more = sd->flags & SPLICE_F_MORE; - - while (len) { - size_t read_len; - loff_t pos = sd->pos, prev_pos = pos; - - ret = do_splice_to(in, &pos, pipe, len, flags); - if (unlikely(ret <= 0)) - goto out_release; - - read_len = ret; - sd->total_len = read_len; - - /* - * If more data is pending, set SPLICE_F_MORE - * If this is the last data and SPLICE_F_MORE was not set - * initially, clears it. - */ - if (read_len < len) - sd->flags |= SPLICE_F_MORE; - else if (!more) - sd->flags &= ~SPLICE_F_MORE; - /* - * NOTE: nonblocking mode only applies to the input. We - * must not do the output in nonblocking mode as then we - * could get stuck data in the internal pipe: - */ - ret = actor(pipe, sd); - if (unlikely(ret <= 0)) { - sd->pos = prev_pos; - goto out_release; - } - - bytes += ret; - len -= ret; - sd->pos = pos; - - if (ret < read_len) { - sd->pos = prev_pos + ret; - goto out_release; - } - } - -done: - pipe->nrbufs = pipe->curbuf = 0; - file_accessed(in); - return bytes; - -out_release: - /* - * If we did an incomplete transfer we must release - * the pipe buffers in question: - */ - for (i = 0; i < pipe->buffers; i++) { - struct pipe_buffer *buf = pipe->bufs + i; - - if (buf->ops) - pipe_buf_release(pipe, buf); - } - - if (!bytes) - bytes = ret; - - goto done; -} -EXPORT_SYMBOL(splice_direct_to_actor); - -static int direct_splice_actor(struct pipe_inode_info *pipe, - struct splice_desc *sd) -{ - struct file *file = sd->u.file; - - return do_splice_from(pipe, file, sd->opos, sd->total_len, - sd->flags); -} - -/** - * do_splice_direct - splices data directly between two files - * @in: file to splice from - * @ppos: input file offset - * @out: file to splice to - * @opos: output file offset - * @len: number of bytes to splice - * @flags: splice modifier flags - * - * Description: - * For use by do_sendfile(). splice can easily emulate sendfile, but - * doing it in the application would incur an extra system call - * (splice in + splice out, as compared to just sendfile()). So this helper - * can splice directly through a process-private pipe. - * - */ -long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, - loff_t *opos, size_t len, unsigned int flags) -{ - struct splice_desc sd = { - .len = len, - .total_len = len, - .flags = flags, - .pos = *ppos, - .u.file = out, - .opos = opos, - }; - long ret; - - if (unlikely(!(out->f_mode & FMODE_WRITE))) - return -EBADF; - - if (unlikely(out->f_flags & O_APPEND)) - return -EINVAL; - - ret = rw_verify_area(WRITE, out, opos, len); - if (unlikely(ret < 0)) - return ret; - - ret = splice_direct_to_actor(in, &sd, direct_splice_actor); - if (ret > 0) - *ppos = sd.pos; - - return ret; -} -EXPORT_SYMBOL(do_splice_direct); - -static int wait_for_space(struct pipe_inode_info *pipe, unsigned flags) -{ - while (pipe->nrbufs == pipe->buffers) { - if (flags & SPLICE_F_NONBLOCK) - return -EAGAIN; - if (signal_pending(current)) - return -ERESTARTSYS; - pipe->waiting_writers++; - pipe_wait(pipe); - pipe->waiting_writers--; - } - return 0; -} - -static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe, - struct pipe_inode_info *opipe, - size_t len, unsigned int flags); - -/* - * Determine where to splice to/from. - */ -static long do_splice(struct file *in, loff_t __user *off_in, - struct file *out, loff_t __user *off_out, - size_t len, unsigned int flags) -{ - struct pipe_inode_info *ipipe; - struct pipe_inode_info *opipe; - loff_t offset; - long ret; - - ipipe = get_pipe_info(in); - opipe = get_pipe_info(out); - - if (ipipe && opipe) { - if (off_in || off_out) - return -ESPIPE; - - if (!(in->f_mode & FMODE_READ)) - return -EBADF; - - if (!(out->f_mode & FMODE_WRITE)) - return -EBADF; - - /* Splicing to self would be fun, but... */ - if (ipipe == opipe) - return -EINVAL; - - return splice_pipe_to_pipe(ipipe, opipe, len, flags); - } - - if (ipipe) { - if (off_in) - return -ESPIPE; - if (off_out) { - if (!(out->f_mode & FMODE_PWRITE)) - return -EINVAL; - if (copy_from_user(&offset, off_out, sizeof(loff_t))) - return -EFAULT; - } else { - offset = out->f_pos; - } - - if (unlikely(!(out->f_mode & FMODE_WRITE))) - return -EBADF; - - if (unlikely(out->f_flags & O_APPEND)) - return -EINVAL; - - ret = rw_verify_area(WRITE, out, &offset, len); - if (unlikely(ret < 0)) - return ret; - - file_start_write(out); - ret = do_splice_from(ipipe, out, &offset, len, flags); - file_end_write(out); - - if (!off_out) - out->f_pos = offset; - else if (copy_to_user(off_out, &offset, sizeof(loff_t))) - ret = -EFAULT; - - return ret; - } - - if (opipe) { - if (off_out) - return -ESPIPE; - if (off_in) { - if (!(in->f_mode & FMODE_PREAD)) - return -EINVAL; - if (copy_from_user(&offset, off_in, sizeof(loff_t))) - return -EFAULT; - } else { - offset = in->f_pos; - } - - pipe_lock(opipe); - ret = wait_for_space(opipe, flags); - if (!ret) - ret = do_splice_to(in, &offset, opipe, len, flags); - pipe_unlock(opipe); - if (ret > 0) - wakeup_pipe_readers(opipe); - if (!off_in) - in->f_pos = offset; - else if (copy_to_user(off_in, &offset, sizeof(loff_t))) - ret = -EFAULT; - - return ret; - } - - return -EINVAL; -} - -static int iter_to_pipe(struct iov_iter *from, - struct pipe_inode_info *pipe, - unsigned flags) -{ - struct pipe_buffer buf = { - .ops = &user_page_pipe_buf_ops, - .flags = flags - }; - size_t total = 0; - int ret = 0; - bool failed = false; - - while (iov_iter_count(from) && !failed) { - struct page *pages[16]; - ssize_t copied; - size_t start; - int n; - - copied = iov_iter_get_pages(from, pages, ~0UL, 16, &start); - if (copied <= 0) { - ret = copied; - break; - } - - for (n = 0; copied; n++, start = 0) { - int size = min_t(int, copied, PAGE_SIZE - start); - if (!failed) { - buf.page = pages[n]; - buf.offset = start; - buf.len = size; - ret = add_to_pipe(pipe, &buf); - if (unlikely(ret < 0)) { - failed = true; - } else { - iov_iter_advance(from, ret); - total += ret; - } - } else { - put_page(pages[n]); - } - copied -= size; - } - } - return total ? total : ret; -} - -static int pipe_to_user(struct pipe_inode_info *pipe, struct pipe_buffer *buf, - struct splice_desc *sd) -{ - int n = copy_page_to_iter(buf->page, buf->offset, sd->len, sd->u.data); - return n == sd->len ? n : -EFAULT; -} - -/* - * For lack of a better implementation, implement vmsplice() to userspace - * as a simple copy of the pipes pages to the user iov. - */ -static long vmsplice_to_user(struct file *file, const struct iovec __user *uiov, - unsigned long nr_segs, unsigned int flags) -{ - struct pipe_inode_info *pipe; - struct splice_desc sd; - long ret; - struct iovec iovstack[UIO_FASTIOV]; - struct iovec *iov = iovstack; - struct iov_iter iter; - - pipe = get_pipe_info(file); - if (!pipe) - return -EBADF; - - ret = import_iovec(READ, uiov, nr_segs, - ARRAY_SIZE(iovstack), &iov, &iter); - if (ret < 0) - return ret; - - sd.total_len = iov_iter_count(&iter); - sd.len = 0; - sd.flags = flags; - sd.u.data = &iter; - sd.pos = 0; - - if (sd.total_len) { - pipe_lock(pipe); - ret = __splice_from_pipe(pipe, &sd, pipe_to_user); - pipe_unlock(pipe); - } - - kfree(iov); - return ret; -} - -/* - * vmsplice splices a user address range into a pipe. It can be thought of - * as splice-from-memory, where the regular splice is splice-from-file (or - * to file). In both cases the output is a pipe, naturally. - */ -static long vmsplice_to_pipe(struct file *file, const struct iovec __user *uiov, - unsigned long nr_segs, unsigned int flags) -{ - struct pipe_inode_info *pipe; - struct iovec iovstack[UIO_FASTIOV]; - struct iovec *iov = iovstack; - struct iov_iter from; - long ret; - unsigned buf_flag = 0; - - if (flags & SPLICE_F_GIFT) - buf_flag = PIPE_BUF_FLAG_GIFT; - - pipe = get_pipe_info(file); - if (!pipe) - return -EBADF; - - ret = import_iovec(WRITE, uiov, nr_segs, - ARRAY_SIZE(iovstack), &iov, &from); - if (ret < 0) - return ret; - - pipe_lock(pipe); - ret = wait_for_space(pipe, flags); - if (!ret) - ret = iter_to_pipe(&from, pipe, buf_flag); - pipe_unlock(pipe); - if (ret > 0) - wakeup_pipe_readers(pipe); - kfree(iov); - return ret; -} - -/* - * Note that vmsplice only really supports true splicing _from_ user memory - * to a pipe, not the other way around. Splicing from user memory is a simple - * operation that can be supported without any funky alignment restrictions - * or nasty vm tricks. We simply map in the user memory and fill them into - * a pipe. The reverse isn't quite as easy, though. There are two possible - * solutions for that: - * - * - memcpy() the data internally, at which point we might as well just - * do a regular read() on the buffer anyway. - * - Lots of nasty vm tricks, that are neither fast nor flexible (it - * has restriction limitations on both ends of the pipe). - * - * Currently we punt and implement it as a normal copy, see pipe_to_user(). - * - */ -SYSCALL_DEFINE4(vmsplice, int, fd, const struct iovec __user *, iov, - unsigned long, nr_segs, unsigned int, flags) -{ - struct fd f; - long error; - - if (unlikely(nr_segs > UIO_MAXIOV)) - return -EINVAL; - else if (unlikely(!nr_segs)) - return 0; - - error = -EBADF; - f = fdget(fd); - if (f.file) { - if (f.file->f_mode & FMODE_WRITE) - error = vmsplice_to_pipe(f.file, iov, nr_segs, flags); - else if (f.file->f_mode & FMODE_READ) - error = vmsplice_to_user(f.file, iov, nr_segs, flags); - - fdput(f); - } - - return error; -} - -#ifdef CONFIG_COMPAT -COMPAT_SYSCALL_DEFINE4(vmsplice, int, fd, const struct compat_iovec __user *, iov32, - unsigned int, nr_segs, unsigned int, flags) -{ - unsigned i; - struct iovec __user *iov; - if (nr_segs > UIO_MAXIOV) - return -EINVAL; - iov = compat_alloc_user_space(nr_segs * sizeof(struct iovec)); - for (i = 0; i < nr_segs; i++) { - struct compat_iovec v; - if (get_user(v.iov_base, &iov32[i].iov_base) || - get_user(v.iov_len, &iov32[i].iov_len) || - put_user(compat_ptr(v.iov_base), &iov[i].iov_base) || - put_user(v.iov_len, &iov[i].iov_len)) - return -EFAULT; - } - return sys_vmsplice(fd, iov, nr_segs, flags); -} -#endif - -SYSCALL_DEFINE6(splice, int, fd_in, loff_t __user *, off_in, - int, fd_out, loff_t __user *, off_out, - size_t, len, unsigned int, flags) -{ - struct fd in, out; - long error; - - if (unlikely(!len)) - return 0; - - error = -EBADF; - in = fdget(fd_in); - if (in.file) { - if (in.file->f_mode & FMODE_READ) { - out = fdget(fd_out); - if (out.file) { - if (out.file->f_mode & FMODE_WRITE) - error = do_splice(in.file, off_in, - out.file, off_out, - len, flags); - fdput(out); - } - } - fdput(in); - } - return error; -} - -/* - * Make sure there's data to read. Wait for input if we can, otherwise - * return an appropriate error. - */ -static int ipipe_prep(struct pipe_inode_info *pipe, unsigned int flags) -{ - int ret; - - /* - * Check ->nrbufs without the inode lock first. This function - * is speculative anyways, so missing one is ok. - */ - if (pipe->nrbufs) - return 0; - - ret = 0; - pipe_lock(pipe); - - while (!pipe->nrbufs) { - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - if (!pipe->writers) - break; - if (!pipe->waiting_writers) { - if (flags & SPLICE_F_NONBLOCK) { - ret = -EAGAIN; - break; - } - } - pipe_wait(pipe); - } - - pipe_unlock(pipe); - return ret; -} - -/* - * Make sure there's writeable room. Wait for room if we can, otherwise - * return an appropriate error. - */ -static int opipe_prep(struct pipe_inode_info *pipe, unsigned int flags) -{ - int ret; - - /* - * Check ->nrbufs without the inode lock first. This function - * is speculative anyways, so missing one is ok. - */ - if (pipe->nrbufs < pipe->buffers) - return 0; - - ret = 0; - pipe_lock(pipe); - - while (pipe->nrbufs >= pipe->buffers) { - if (!pipe->readers) { - send_sig(SIGPIPE, current, 0); - ret = -EPIPE; - break; - } - if (flags & SPLICE_F_NONBLOCK) { - ret = -EAGAIN; - break; - } - if (signal_pending(current)) { - ret = -ERESTARTSYS; - break; - } - pipe->waiting_writers++; - pipe_wait(pipe); - pipe->waiting_writers--; - } - - pipe_unlock(pipe); - return ret; -} - -/* - * Splice contents of ipipe to opipe. - */ -static int splice_pipe_to_pipe(struct pipe_inode_info *ipipe, - struct pipe_inode_info *opipe, - size_t len, unsigned int flags) -{ - struct pipe_buffer *ibuf, *obuf; - int ret = 0, nbuf; - bool input_wakeup = false; - - -retry: - ret = ipipe_prep(ipipe, flags); - if (ret) - return ret; - - ret = opipe_prep(opipe, flags); - if (ret) - return ret; - - /* - * Potential ABBA deadlock, work around it by ordering lock - * grabbing by pipe info address. Otherwise two different processes - * could deadlock (one doing tee from A -> B, the other from B -> A). - */ - pipe_double_lock(ipipe, opipe); - - do { - if (!opipe->readers) { - send_sig(SIGPIPE, current, 0); - if (!ret) - ret = -EPIPE; - break; - } - - if (!ipipe->nrbufs && !ipipe->writers) - break; - - /* - * Cannot make any progress, because either the input - * pipe is empty or the output pipe is full. - */ - if (!ipipe->nrbufs || opipe->nrbufs >= opipe->buffers) { - /* Already processed some buffers, break */ - if (ret) - break; - - if (flags & SPLICE_F_NONBLOCK) { - ret = -EAGAIN; - break; - } - - /* - * We raced with another reader/writer and haven't - * managed to process any buffers. A zero return - * value means EOF, so retry instead. - */ - pipe_unlock(ipipe); - pipe_unlock(opipe); - goto retry; - } - - ibuf = ipipe->bufs + ipipe->curbuf; - nbuf = (opipe->curbuf + opipe->nrbufs) & (opipe->buffers - 1); - obuf = opipe->bufs + nbuf; - - if (len >= ibuf->len) { - /* - * Simply move the whole buffer from ipipe to opipe - */ - *obuf = *ibuf; - ibuf->ops = NULL; - opipe->nrbufs++; - ipipe->curbuf = (ipipe->curbuf + 1) & (ipipe->buffers - 1); - ipipe->nrbufs--; - input_wakeup = true; - } else { - /* - * Get a reference to this pipe buffer, - * so we can copy the contents over. - */ - pipe_buf_get(ipipe, ibuf); - *obuf = *ibuf; - - /* - * Don't inherit the gift flag, we need to - * prevent multiple steals of this page. - */ - obuf->flags &= ~PIPE_BUF_FLAG_GIFT; - - obuf->len = len; - opipe->nrbufs++; - ibuf->offset += obuf->len; - ibuf->len -= obuf->len; - } - ret += obuf->len; - len -= obuf->len; - } while (len); - - pipe_unlock(ipipe); - pipe_unlock(opipe); - - /* - * If we put data in the output pipe, wakeup any potential readers. - */ - if (ret > 0) - wakeup_pipe_readers(opipe); - - if (input_wakeup) - wakeup_pipe_writers(ipipe); - - return ret; -} - -/* - * Link contents of ipipe to opipe. - */ -static int link_pipe(struct pipe_inode_info *ipipe, - struct pipe_inode_info *opipe, - size_t len, unsigned int flags) -{ - struct pipe_buffer *ibuf, *obuf; - int ret = 0, i = 0, nbuf; - - /* - * Potential ABBA deadlock, work around it by ordering lock - * grabbing by pipe info address. Otherwise two different processes - * could deadlock (one doing tee from A -> B, the other from B -> A). - */ - pipe_double_lock(ipipe, opipe); - - do { - if (!opipe->readers) { - send_sig(SIGPIPE, current, 0); - if (!ret) - ret = -EPIPE; - break; - } - - /* - * If we have iterated all input buffers or ran out of - * output room, break. - */ - if (i >= ipipe->nrbufs || opipe->nrbufs >= opipe->buffers) - break; - - ibuf = ipipe->bufs + ((ipipe->curbuf + i) & (ipipe->buffers-1)); - nbuf = (opipe->curbuf + opipe->nrbufs) & (opipe->buffers - 1); - - /* - * Get a reference to this pipe buffer, - * so we can copy the contents over. - */ - pipe_buf_get(ipipe, ibuf); - - obuf = opipe->bufs + nbuf; - *obuf = *ibuf; - - /* - * Don't inherit the gift flag, we need to - * prevent multiple steals of this page. - */ - obuf->flags &= ~PIPE_BUF_FLAG_GIFT; - - if (obuf->len > len) - obuf->len = len; - - opipe->nrbufs++; - ret += obuf->len; - len -= obuf->len; - i++; - } while (len); - - /* - * return EAGAIN if we have the potential of some data in the - * future, otherwise just return 0 - */ - if (!ret && ipipe->waiting_writers && (flags & SPLICE_F_NONBLOCK)) - ret = -EAGAIN; - - pipe_unlock(ipipe); - pipe_unlock(opipe); - - /* - * If we put data in the output pipe, wakeup any potential readers. - */ - if (ret > 0) - wakeup_pipe_readers(opipe); - - return ret; -} - -/* - * This is a tee(1) implementation that works on pipes. It doesn't copy - * any data, it simply references the 'in' pages on the 'out' pipe. - * The 'flags' used are the SPLICE_F_* variants, currently the only - * applicable one is SPLICE_F_NONBLOCK. - */ -static long do_tee(struct file *in, struct file *out, size_t len, - unsigned int flags) -{ - struct pipe_inode_info *ipipe = get_pipe_info(in); - struct pipe_inode_info *opipe = get_pipe_info(out); - int ret = -EINVAL; - - /* - * Duplicate the contents of ipipe to opipe without actually - * copying the data. - */ - if (ipipe && opipe && ipipe != opipe) { - /* - * Keep going, unless we encounter an error. The ipipe/opipe - * ordering doesn't really matter. - */ - ret = ipipe_prep(ipipe, flags); - if (!ret) { - ret = opipe_prep(opipe, flags); - if (!ret) - ret = link_pipe(ipipe, opipe, len, flags); - } - } - - return ret; -} - -SYSCALL_DEFINE4(tee, int, fdin, int, fdout, size_t, len, unsigned int, flags) -{ - struct fd in; - int error; - - if (unlikely(!len)) - return 0; - - error = -EBADF; - in = fdget(fdin); - if (in.file) { - if (in.file->f_mode & FMODE_READ) { - struct fd out = fdget(fdout); - if (out.file) { - if (out.file->f_mode & FMODE_WRITE) - error = do_tee(in.file, out.file, - len, flags); - fdput(out); - } - } - fdput(in); - } - - return error; -} diff --git a/src/linux/fs/squashfs/Kconfig b/src/linux/fs/squashfs/Kconfig deleted file mode 100644 index ffb093e..0000000 --- a/src/linux/fs/squashfs/Kconfig +++ /dev/null @@ -1,210 +0,0 @@ -config SQUASHFS - tristate "SquashFS 4.0 - Squashed file system support" - depends on BLOCK - help - Saying Y here includes support for SquashFS 4.0 (a Compressed - Read-Only File System). Squashfs is a highly compressed read-only - filesystem for Linux. It uses zlib, lzo or xz compression to - compress both files, inodes and directories. Inodes in the system - are very small and all blocks are packed to minimise data overhead. - Block sizes greater than 4K are supported up to a maximum of 1 Mbytes - (default block size 128K). SquashFS 4.0 supports 64 bit filesystems - and files (larger than 4GB), full uid/gid information, hard links and - timestamps. - - Squashfs is intended for general read-only filesystem use, for - archival use (i.e. in cases where a .tar.gz file may be used), and in - embedded systems where low overhead is needed. Further information - and tools are available from http://squashfs.sourceforge.net. - - If you want to compile this as a module ( = code which can be - inserted in and removed from the running kernel whenever you want), - say M here. The module will be called squashfs. Note that the root - file system (the one containing the directory /) cannot be compiled - as a module. - - If unsure, say N. - -choice - prompt "File decompression options" - depends on SQUASHFS - help - Squashfs now supports two options for decompressing file - data. Traditionally Squashfs has decompressed into an - intermediate buffer and then memcopied it into the page cache. - Squashfs now supports the ability to decompress directly into - the page cache. - - If unsure, select "Decompress file data into an intermediate buffer" - -config SQUASHFS_FILE_CACHE - bool "Decompress file data into an intermediate buffer" - help - Decompress file data into an intermediate buffer and then - memcopy it into the page cache. - -config SQUASHFS_FILE_DIRECT - bool "Decompress files directly into the page cache" - help - Directly decompress file data into the page cache. - Doing so can significantly improve performance because - it eliminates a memcpy and it also removes the lock contention - on the single buffer. - -endchoice - -choice - prompt "Decompressor parallelisation options" - depends on SQUASHFS - help - Squashfs now supports three parallelisation options for - decompression. Each one exhibits various trade-offs between - decompression performance and CPU and memory usage. - - If in doubt, select "Single threaded compression" - -config SQUASHFS_DECOMP_SINGLE - bool "Single threaded compression" - help - Traditionally Squashfs has used single-threaded decompression. - Only one block (data or metadata) can be decompressed at any - one time. This limits CPU and memory usage to a minimum. - -config SQUASHFS_DECOMP_MULTI - bool "Use multiple decompressors for parallel I/O" - help - By default Squashfs uses a single decompressor but it gives - poor performance on parallel I/O workloads when using multiple CPU - machines due to waiting on decompressor availability. - - If you have a parallel I/O workload and your system has enough memory, - using this option may improve overall I/O performance. - - This decompressor implementation uses up to two parallel - decompressors per core. It dynamically allocates decompressors - on a demand basis. - -config SQUASHFS_DECOMP_MULTI_PERCPU - bool "Use percpu multiple decompressors for parallel I/O" - help - By default Squashfs uses a single decompressor but it gives - poor performance on parallel I/O workloads when using multiple CPU - machines due to waiting on decompressor availability. - - This decompressor implementation uses a maximum of one - decompressor per core. It uses percpu variables to ensure - decompression is load-balanced across the cores. - -endchoice - -config SQUASHFS_XATTR - bool "Squashfs XATTR support" - depends on SQUASHFS - help - Saying Y here includes support for extended attributes (xattrs). - Xattrs are name:value pairs associated with inodes by - the kernel or by users (see the attr(5) manual page). - - If unsure, say N. - -config SQUASHFS_ZLIB - bool "Include support for ZLIB compressed file systems" - depends on SQUASHFS - select ZLIB_INFLATE - default y - help - ZLIB compression is the standard compression used by Squashfs - file systems. It offers a good trade-off between compression - achieved and the amount of CPU time and memory necessary to - compress and decompress. - - If unsure, say Y. - -config SQUASHFS_LZ4 - bool "Include support for LZ4 compressed file systems" - depends on SQUASHFS - select LZ4_DECOMPRESS - help - Saying Y here includes support for reading Squashfs file systems - compressed with LZ4 compression. LZ4 compression is mainly - aimed at embedded systems with slower CPUs where the overheads - of zlib are too high. - - LZ4 is not the standard compression used in Squashfs and so most - file systems will be readable without selecting this option. - - If unsure, say N. - -config SQUASHFS_LZO - bool "Include support for LZO compressed file systems" - depends on SQUASHFS - select LZO_DECOMPRESS - help - Saying Y here includes support for reading Squashfs file systems - compressed with LZO compression. LZO compression is mainly - aimed at embedded systems with slower CPUs where the overheads - of zlib are too high. - - LZO is not the standard compression used in Squashfs and so most - file systems will be readable without selecting this option. - - If unsure, say N. - -config SQUASHFS_XZ - bool "Include support for XZ compressed file systems" - depends on SQUASHFS - select XZ_DEC - help - Saying Y here includes support for reading Squashfs file systems - compressed with XZ compression. XZ gives better compression than - the default zlib compression, at the expense of greater CPU and - memory overhead. - - XZ is not the standard compression used in Squashfs and so most - file systems will be readable without selecting this option. - - If unsure, say N. - -config SQUASHFS_4K_DEVBLK_SIZE - bool "Use 4K device block size?" - depends on SQUASHFS - help - By default Squashfs sets the dev block size (sb_min_blocksize) - to 1K or the smallest block size supported by the block device - (if larger). This, because blocks are packed together and - unaligned in Squashfs, should reduce latency. - - This, however, gives poor performance on MTD NAND devices where - the optimal I/O size is 4K (even though the devices can support - smaller block sizes). - - Using a 4K device block size may also improve overall I/O - performance for some file access patterns (e.g. sequential - accesses of files in filesystem order) on all media. - - Setting this option will force Squashfs to use a 4K device block - size by default. - - If unsure, say N. - -config SQUASHFS_EMBEDDED - bool "Additional option for memory-constrained systems" - depends on SQUASHFS - help - Saying Y here allows you to specify cache size. - - If unsure, say N. - -config SQUASHFS_FRAGMENT_CACHE_SIZE - int "Number of fragments cached" if SQUASHFS_EMBEDDED - depends on SQUASHFS - default "3" - help - By default SquashFS caches the last 3 fragments read from - the filesystem. Increasing this amount may mean SquashFS - has to re-read fragments less often from disk, at the expense - of extra system memory. Decreasing this amount will mean - SquashFS uses less memory at the expense of extra reads from disk. - - Note there must be at least one cached fragment. Anything - much more than three will probably not make much difference. diff --git a/src/linux/fs/stack.c b/src/linux/fs/stack.c deleted file mode 100644 index a54e33e..0000000 --- a/src/linux/fs/stack.c +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include -#include - -/* does _NOT_ require i_mutex to be held. - * - * This function cannot be inlined since i_size_{read,write} is rather - * heavy-weight on 32-bit systems - */ -void fsstack_copy_inode_size(struct inode *dst, struct inode *src) -{ - loff_t i_size; - blkcnt_t i_blocks; - - /* - * i_size_read() includes its own seqlocking and protection from - * preemption (see include/linux/fs.h): we need nothing extra for - * that here, and prefer to avoid nesting locks than attempt to keep - * i_size and i_blocks in sync together. - */ - i_size = i_size_read(src); - - /* - * But if CONFIG_LBDAF (on 32-bit), we ought to make an effort to - * keep the two halves of i_blocks in sync despite SMP or PREEMPT - - * though stat's generic_fillattr() doesn't bother, and we won't be - * applying quotas (where i_blocks does become important) at the - * upper level. - * - * We don't actually know what locking is used at the lower level; - * but if it's a filesystem that supports quotas, it will be using - * i_lock as in inode_add_bytes(). - */ - if (sizeof(i_blocks) > sizeof(long)) - spin_lock(&src->i_lock); - i_blocks = src->i_blocks; - if (sizeof(i_blocks) > sizeof(long)) - spin_unlock(&src->i_lock); - - /* - * If CONFIG_SMP or CONFIG_PREEMPT on 32-bit, it's vital for - * fsstack_copy_inode_size() to hold some lock around - * i_size_write(), otherwise i_size_read() may spin forever (see - * include/linux/fs.h). We don't necessarily hold i_mutex when this - * is called, so take i_lock for that case. - * - * And if CONFIG_LBDAF (on 32-bit), continue our effort to keep the - * two halves of i_blocks in sync despite SMP or PREEMPT: use i_lock - * for that case too, and do both at once by combining the tests. - * - * There is none of this locking overhead in the 64-bit case. - */ - if (sizeof(i_size) > sizeof(long) || sizeof(i_blocks) > sizeof(long)) - spin_lock(&dst->i_lock); - i_size_write(dst, i_size); - dst->i_blocks = i_blocks; - if (sizeof(i_size) > sizeof(long) || sizeof(i_blocks) > sizeof(long)) - spin_unlock(&dst->i_lock); -} -EXPORT_SYMBOL_GPL(fsstack_copy_inode_size); - -/* copy all attributes */ -void fsstack_copy_attr_all(struct inode *dest, const struct inode *src) -{ - dest->i_mode = src->i_mode; - dest->i_uid = src->i_uid; - dest->i_gid = src->i_gid; - dest->i_rdev = src->i_rdev; - dest->i_atime = src->i_atime; - dest->i_mtime = src->i_mtime; - dest->i_ctime = src->i_ctime; - dest->i_blkbits = src->i_blkbits; - dest->i_flags = src->i_flags; - set_nlink(dest, src->i_nlink); -} -EXPORT_SYMBOL_GPL(fsstack_copy_attr_all); diff --git a/src/linux/fs/stat.c b/src/linux/fs/stat.c deleted file mode 100644 index bc045c7..0000000 --- a/src/linux/fs/stat.c +++ /dev/null @@ -1,509 +0,0 @@ -/* - * linux/fs/stat.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -void generic_fillattr(struct inode *inode, struct kstat *stat) -{ - stat->dev = inode->i_sb->s_dev; - stat->ino = inode->i_ino; - stat->mode = inode->i_mode; - stat->nlink = inode->i_nlink; - stat->uid = inode->i_uid; - stat->gid = inode->i_gid; - stat->rdev = inode->i_rdev; - stat->size = i_size_read(inode); - stat->atime = inode->i_atime; - stat->mtime = inode->i_mtime; - stat->ctime = inode->i_ctime; - stat->blksize = (1 << inode->i_blkbits); - stat->blocks = inode->i_blocks; -} - -EXPORT_SYMBOL(generic_fillattr); - -/** - * vfs_getattr_nosec - getattr without security checks - * @path: file to get attributes from - * @stat: structure to return attributes in - * - * Get attributes without calling security_inode_getattr. - * - * Currently the only caller other than vfs_getattr is internal to the - * filehandle lookup code, which uses only the inode number and returns - * no attributes to any user. Any other code probably wants - * vfs_getattr. - */ -int vfs_getattr_nosec(struct path *path, struct kstat *stat) -{ - struct inode *inode = d_backing_inode(path->dentry); - - if (inode->i_op->getattr) - return inode->i_op->getattr(path->mnt, path->dentry, stat); - - generic_fillattr(inode, stat); - return 0; -} - -EXPORT_SYMBOL(vfs_getattr_nosec); - -int vfs_getattr(struct path *path, struct kstat *stat) -{ - int retval; - - retval = security_inode_getattr(path); - if (retval) - return retval; - return vfs_getattr_nosec(path, stat); -} - -EXPORT_SYMBOL(vfs_getattr); - -int vfs_fstat(unsigned int fd, struct kstat *stat) -{ - struct fd f = fdget_raw(fd); - int error = -EBADF; - - if (f.file) { - error = vfs_getattr(&f.file->f_path, stat); - fdput(f); - } - return error; -} -EXPORT_SYMBOL(vfs_fstat); - -int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat, - int flag) -{ - struct path path; - int error = -EINVAL; - unsigned int lookup_flags = 0; - - if ((flag & ~(AT_SYMLINK_NOFOLLOW | AT_NO_AUTOMOUNT | - AT_EMPTY_PATH)) != 0) - goto out; - - if (!(flag & AT_SYMLINK_NOFOLLOW)) - lookup_flags |= LOOKUP_FOLLOW; - if (flag & AT_EMPTY_PATH) - lookup_flags |= LOOKUP_EMPTY; -retry: - error = user_path_at(dfd, filename, lookup_flags, &path); - if (error) - goto out; - - error = vfs_getattr(&path, stat); - path_put(&path); - if (retry_estale(error, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - goto retry; - } -out: - return error; -} -EXPORT_SYMBOL(vfs_fstatat); - -int vfs_stat(const char __user *name, struct kstat *stat) -{ - return vfs_fstatat(AT_FDCWD, name, stat, 0); -} -EXPORT_SYMBOL(vfs_stat); - -int vfs_lstat(const char __user *name, struct kstat *stat) -{ - return vfs_fstatat(AT_FDCWD, name, stat, AT_SYMLINK_NOFOLLOW); -} -EXPORT_SYMBOL(vfs_lstat); - - -#ifdef __ARCH_WANT_OLD_STAT - -/* - * For backward compatibility? Maybe this should be moved - * into arch/i386 instead? - */ -static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * statbuf) -{ - static int warncount = 5; - struct __old_kernel_stat tmp; - - if (warncount > 0) { - warncount--; - printk(KERN_WARNING "VFS: Warning: %s using old stat() call. Recompile your binary.\n", - current->comm); - } else if (warncount < 0) { - /* it's laughable, but... */ - warncount = 0; - } - - memset(&tmp, 0, sizeof(struct __old_kernel_stat)); - tmp.st_dev = old_encode_dev(stat->dev); - tmp.st_ino = stat->ino; - if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) - return -EOVERFLOW; - tmp.st_mode = stat->mode; - tmp.st_nlink = stat->nlink; - if (tmp.st_nlink != stat->nlink) - return -EOVERFLOW; - SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); - SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid)); - tmp.st_rdev = old_encode_dev(stat->rdev); -#if BITS_PER_LONG == 32 - if (stat->size > MAX_NON_LFS) - return -EOVERFLOW; -#endif - tmp.st_size = stat->size; - tmp.st_atime = stat->atime.tv_sec; - tmp.st_mtime = stat->mtime.tv_sec; - tmp.st_ctime = stat->ctime.tv_sec; - return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; -} - -SYSCALL_DEFINE2(stat, const char __user *, filename, - struct __old_kernel_stat __user *, statbuf) -{ - struct kstat stat; - int error; - - error = vfs_stat(filename, &stat); - if (error) - return error; - - return cp_old_stat(&stat, statbuf); -} - -SYSCALL_DEFINE2(lstat, const char __user *, filename, - struct __old_kernel_stat __user *, statbuf) -{ - struct kstat stat; - int error; - - error = vfs_lstat(filename, &stat); - if (error) - return error; - - return cp_old_stat(&stat, statbuf); -} - -SYSCALL_DEFINE2(fstat, unsigned int, fd, struct __old_kernel_stat __user *, statbuf) -{ - struct kstat stat; - int error = vfs_fstat(fd, &stat); - - if (!error) - error = cp_old_stat(&stat, statbuf); - - return error; -} - -#endif /* __ARCH_WANT_OLD_STAT */ - -#if BITS_PER_LONG == 32 -# define choose_32_64(a,b) a -#else -# define choose_32_64(a,b) b -#endif - -#define valid_dev(x) choose_32_64(old_valid_dev(x),true) -#define encode_dev(x) choose_32_64(old_encode_dev,new_encode_dev)(x) - -#ifndef INIT_STRUCT_STAT_PADDING -# define INIT_STRUCT_STAT_PADDING(st) memset(&st, 0, sizeof(st)) -#endif - -static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) -{ - struct stat tmp; - - if (!valid_dev(stat->dev) || !valid_dev(stat->rdev)) - return -EOVERFLOW; -#if BITS_PER_LONG == 32 - if (stat->size > MAX_NON_LFS) - return -EOVERFLOW; -#endif - - INIT_STRUCT_STAT_PADDING(tmp); - tmp.st_dev = encode_dev(stat->dev); - tmp.st_ino = stat->ino; - if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) - return -EOVERFLOW; - tmp.st_mode = stat->mode; - tmp.st_nlink = stat->nlink; - if (tmp.st_nlink != stat->nlink) - return -EOVERFLOW; - SET_UID(tmp.st_uid, from_kuid_munged(current_user_ns(), stat->uid)); - SET_GID(tmp.st_gid, from_kgid_munged(current_user_ns(), stat->gid)); - tmp.st_rdev = encode_dev(stat->rdev); - tmp.st_size = stat->size; - tmp.st_atime = stat->atime.tv_sec; - tmp.st_mtime = stat->mtime.tv_sec; - tmp.st_ctime = stat->ctime.tv_sec; -#ifdef STAT_HAVE_NSEC - tmp.st_atime_nsec = stat->atime.tv_nsec; - tmp.st_mtime_nsec = stat->mtime.tv_nsec; - tmp.st_ctime_nsec = stat->ctime.tv_nsec; -#endif - tmp.st_blocks = stat->blocks; - tmp.st_blksize = stat->blksize; - return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; -} - -SYSCALL_DEFINE2(newstat, const char __user *, filename, - struct stat __user *, statbuf) -{ - struct kstat stat; - int error = vfs_stat(filename, &stat); - - if (error) - return error; - return cp_new_stat(&stat, statbuf); -} - -SYSCALL_DEFINE2(newlstat, const char __user *, filename, - struct stat __user *, statbuf) -{ - struct kstat stat; - int error; - - error = vfs_lstat(filename, &stat); - if (error) - return error; - - return cp_new_stat(&stat, statbuf); -} - -#if !defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_SYS_NEWFSTATAT) -SYSCALL_DEFINE4(newfstatat, int, dfd, const char __user *, filename, - struct stat __user *, statbuf, int, flag) -{ - struct kstat stat; - int error; - - error = vfs_fstatat(dfd, filename, &stat, flag); - if (error) - return error; - return cp_new_stat(&stat, statbuf); -} -#endif - -SYSCALL_DEFINE2(newfstat, unsigned int, fd, struct stat __user *, statbuf) -{ - struct kstat stat; - int error = vfs_fstat(fd, &stat); - - if (!error) - error = cp_new_stat(&stat, statbuf); - - return error; -} - -SYSCALL_DEFINE4(readlinkat, int, dfd, const char __user *, pathname, - char __user *, buf, int, bufsiz) -{ - struct path path; - int error; - int empty = 0; - unsigned int lookup_flags = LOOKUP_EMPTY; - - if (bufsiz <= 0) - return -EINVAL; - -retry: - error = user_path_at_empty(dfd, pathname, lookup_flags, &path, &empty); - if (!error) { - struct inode *inode = d_backing_inode(path.dentry); - - error = empty ? -ENOENT : -EINVAL; - if (inode->i_op->readlink) { - error = security_inode_readlink(path.dentry); - if (!error) { - touch_atime(&path); - error = inode->i_op->readlink(path.dentry, - buf, bufsiz); - } - } - path_put(&path); - if (retry_estale(error, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - goto retry; - } - } - return error; -} - -SYSCALL_DEFINE3(readlink, const char __user *, path, char __user *, buf, - int, bufsiz) -{ - return sys_readlinkat(AT_FDCWD, path, buf, bufsiz); -} - - -/* ---------- LFS-64 ----------- */ -#if defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_COMPAT_STAT64) - -#ifndef INIT_STRUCT_STAT64_PADDING -# define INIT_STRUCT_STAT64_PADDING(st) memset(&st, 0, sizeof(st)) -#endif - -static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf) -{ - struct stat64 tmp; - - INIT_STRUCT_STAT64_PADDING(tmp); -#ifdef CONFIG_MIPS - /* mips has weird padding, so we don't get 64 bits there */ - tmp.st_dev = new_encode_dev(stat->dev); - tmp.st_rdev = new_encode_dev(stat->rdev); -#else - tmp.st_dev = huge_encode_dev(stat->dev); - tmp.st_rdev = huge_encode_dev(stat->rdev); -#endif - tmp.st_ino = stat->ino; - if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino) - return -EOVERFLOW; -#ifdef STAT64_HAS_BROKEN_ST_INO - tmp.__st_ino = stat->ino; -#endif - tmp.st_mode = stat->mode; - tmp.st_nlink = stat->nlink; - tmp.st_uid = from_kuid_munged(current_user_ns(), stat->uid); - tmp.st_gid = from_kgid_munged(current_user_ns(), stat->gid); - tmp.st_atime = stat->atime.tv_sec; - tmp.st_atime_nsec = stat->atime.tv_nsec; - tmp.st_mtime = stat->mtime.tv_sec; - tmp.st_mtime_nsec = stat->mtime.tv_nsec; - tmp.st_ctime = stat->ctime.tv_sec; - tmp.st_ctime_nsec = stat->ctime.tv_nsec; - tmp.st_size = stat->size; - tmp.st_blocks = stat->blocks; - tmp.st_blksize = stat->blksize; - return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; -} - -SYSCALL_DEFINE2(stat64, const char __user *, filename, - struct stat64 __user *, statbuf) -{ - struct kstat stat; - int error = vfs_stat(filename, &stat); - - if (!error) - error = cp_new_stat64(&stat, statbuf); - - return error; -} - -SYSCALL_DEFINE2(lstat64, const char __user *, filename, - struct stat64 __user *, statbuf) -{ - struct kstat stat; - int error = vfs_lstat(filename, &stat); - - if (!error) - error = cp_new_stat64(&stat, statbuf); - - return error; -} - -SYSCALL_DEFINE2(fstat64, unsigned long, fd, struct stat64 __user *, statbuf) -{ - struct kstat stat; - int error = vfs_fstat(fd, &stat); - - if (!error) - error = cp_new_stat64(&stat, statbuf); - - return error; -} - -SYSCALL_DEFINE4(fstatat64, int, dfd, const char __user *, filename, - struct stat64 __user *, statbuf, int, flag) -{ - struct kstat stat; - int error; - - error = vfs_fstatat(dfd, filename, &stat, flag); - if (error) - return error; - return cp_new_stat64(&stat, statbuf); -} -#endif /* __ARCH_WANT_STAT64 || __ARCH_WANT_COMPAT_STAT64 */ - -/* Caller is here responsible for sufficient locking (ie. inode->i_lock) */ -void __inode_add_bytes(struct inode *inode, loff_t bytes) -{ - inode->i_blocks += bytes >> 9; - bytes &= 511; - inode->i_bytes += bytes; - if (inode->i_bytes >= 512) { - inode->i_blocks++; - inode->i_bytes -= 512; - } -} - -void inode_add_bytes(struct inode *inode, loff_t bytes) -{ - spin_lock(&inode->i_lock); - __inode_add_bytes(inode, bytes); - spin_unlock(&inode->i_lock); -} - -EXPORT_SYMBOL(inode_add_bytes); - -void __inode_sub_bytes(struct inode *inode, loff_t bytes) -{ - inode->i_blocks -= bytes >> 9; - bytes &= 511; - if (inode->i_bytes < bytes) { - inode->i_blocks--; - inode->i_bytes += 512; - } - inode->i_bytes -= bytes; -} - -EXPORT_SYMBOL(__inode_sub_bytes); - -void inode_sub_bytes(struct inode *inode, loff_t bytes) -{ - spin_lock(&inode->i_lock); - __inode_sub_bytes(inode, bytes); - spin_unlock(&inode->i_lock); -} - -EXPORT_SYMBOL(inode_sub_bytes); - -loff_t inode_get_bytes(struct inode *inode) -{ - loff_t ret; - - spin_lock(&inode->i_lock); - ret = (((loff_t)inode->i_blocks) << 9) + inode->i_bytes; - spin_unlock(&inode->i_lock); - return ret; -} - -EXPORT_SYMBOL(inode_get_bytes); - -void inode_set_bytes(struct inode *inode, loff_t bytes) -{ - /* Caller is here responsible for sufficient locking - * (ie. inode->i_lock) */ - inode->i_blocks = bytes >> 9; - inode->i_bytes = bytes & 511; -} - -EXPORT_SYMBOL(inode_set_bytes); diff --git a/src/linux/fs/statfs.c b/src/linux/fs/statfs.c deleted file mode 100644 index 083dc0a..0000000 --- a/src/linux/fs/statfs.c +++ /dev/null @@ -1,241 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -static int flags_by_mnt(int mnt_flags) -{ - int flags = 0; - - if (mnt_flags & MNT_READONLY) - flags |= ST_RDONLY; - if (mnt_flags & MNT_NOSUID) - flags |= ST_NOSUID; - if (mnt_flags & MNT_NODEV) - flags |= ST_NODEV; - if (mnt_flags & MNT_NOEXEC) - flags |= ST_NOEXEC; - if (mnt_flags & MNT_NOATIME) - flags |= ST_NOATIME; - if (mnt_flags & MNT_NODIRATIME) - flags |= ST_NODIRATIME; - if (mnt_flags & MNT_RELATIME) - flags |= ST_RELATIME; - return flags; -} - -static int flags_by_sb(int s_flags) -{ - int flags = 0; - if (s_flags & MS_SYNCHRONOUS) - flags |= ST_SYNCHRONOUS; - if (s_flags & MS_MANDLOCK) - flags |= ST_MANDLOCK; - return flags; -} - -static int calculate_f_flags(struct vfsmount *mnt) -{ - return ST_VALID | flags_by_mnt(mnt->mnt_flags) | - flags_by_sb(mnt->mnt_sb->s_flags); -} - -static int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf) -{ - int retval; - - if (!dentry->d_sb->s_op->statfs) - return -ENOSYS; - - memset(buf, 0, sizeof(*buf)); - retval = security_sb_statfs(dentry); - if (retval) - return retval; - retval = dentry->d_sb->s_op->statfs(dentry, buf); - if (retval == 0 && buf->f_frsize == 0) - buf->f_frsize = buf->f_bsize; - return retval; -} - -int vfs_statfs(struct path *path, struct kstatfs *buf) -{ - int error; - - error = statfs_by_dentry(path->dentry, buf); - if (!error) - buf->f_flags = calculate_f_flags(path->mnt); - return error; -} -EXPORT_SYMBOL(vfs_statfs); - -int user_statfs(const char __user *pathname, struct kstatfs *st) -{ - struct path path; - int error; - unsigned int lookup_flags = LOOKUP_FOLLOW|LOOKUP_AUTOMOUNT; -retry: - error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path); - if (!error) { - error = vfs_statfs(&path, st); - path_put(&path); - if (retry_estale(error, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - goto retry; - } - } - return error; -} - -int fd_statfs(int fd, struct kstatfs *st) -{ - struct fd f = fdget_raw(fd); - int error = -EBADF; - if (f.file) { - error = vfs_statfs(&f.file->f_path, st); - fdput(f); - } - return error; -} - -static int do_statfs_native(struct kstatfs *st, struct statfs __user *p) -{ - struct statfs buf; - - if (sizeof(buf) == sizeof(*st)) - memcpy(&buf, st, sizeof(*st)); - else { - if (sizeof buf.f_blocks == 4) { - if ((st->f_blocks | st->f_bfree | st->f_bavail | - st->f_bsize | st->f_frsize) & - 0xffffffff00000000ULL) - return -EOVERFLOW; - /* - * f_files and f_ffree may be -1; it's okay to stuff - * that into 32 bits - */ - if (st->f_files != -1 && - (st->f_files & 0xffffffff00000000ULL)) - return -EOVERFLOW; - if (st->f_ffree != -1 && - (st->f_ffree & 0xffffffff00000000ULL)) - return -EOVERFLOW; - } - - buf.f_type = st->f_type; - buf.f_bsize = st->f_bsize; - buf.f_blocks = st->f_blocks; - buf.f_bfree = st->f_bfree; - buf.f_bavail = st->f_bavail; - buf.f_files = st->f_files; - buf.f_ffree = st->f_ffree; - buf.f_fsid = st->f_fsid; - buf.f_namelen = st->f_namelen; - buf.f_frsize = st->f_frsize; - buf.f_flags = st->f_flags; - memset(buf.f_spare, 0, sizeof(buf.f_spare)); - } - if (copy_to_user(p, &buf, sizeof(buf))) - return -EFAULT; - return 0; -} - -static int do_statfs64(struct kstatfs *st, struct statfs64 __user *p) -{ - struct statfs64 buf; - if (sizeof(buf) == sizeof(*st)) - memcpy(&buf, st, sizeof(*st)); - else { - buf.f_type = st->f_type; - buf.f_bsize = st->f_bsize; - buf.f_blocks = st->f_blocks; - buf.f_bfree = st->f_bfree; - buf.f_bavail = st->f_bavail; - buf.f_files = st->f_files; - buf.f_ffree = st->f_ffree; - buf.f_fsid = st->f_fsid; - buf.f_namelen = st->f_namelen; - buf.f_frsize = st->f_frsize; - buf.f_flags = st->f_flags; - memset(buf.f_spare, 0, sizeof(buf.f_spare)); - } - if (copy_to_user(p, &buf, sizeof(buf))) - return -EFAULT; - return 0; -} - -SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, buf) -{ - struct kstatfs st; - int error = user_statfs(pathname, &st); - if (!error) - error = do_statfs_native(&st, buf); - return error; -} - -SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct statfs64 __user *, buf) -{ - struct kstatfs st; - int error; - if (sz != sizeof(*buf)) - return -EINVAL; - error = user_statfs(pathname, &st); - if (!error) - error = do_statfs64(&st, buf); - return error; -} - -SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf) -{ - struct kstatfs st; - int error = fd_statfs(fd, &st); - if (!error) - error = do_statfs_native(&st, buf); - return error; -} - -SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user *, buf) -{ - struct kstatfs st; - int error; - - if (sz != sizeof(*buf)) - return -EINVAL; - - error = fd_statfs(fd, &st); - if (!error) - error = do_statfs64(&st, buf); - return error; -} - -int vfs_ustat(dev_t dev, struct kstatfs *sbuf) -{ - struct super_block *s = user_get_super(dev); - int err; - if (!s) - return -EINVAL; - - err = statfs_by_dentry(s->s_root, sbuf); - drop_super(s); - return err; -} - -SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf) -{ - struct ustat tmp; - struct kstatfs sbuf; - int err = vfs_ustat(new_decode_dev(dev), &sbuf); - if (err) - return err; - - memset(&tmp,0,sizeof(struct ustat)); - tmp.f_tfree = sbuf.f_bfree; - tmp.f_tinode = sbuf.f_ffree; - - return copy_to_user(ubuf, &tmp, sizeof(struct ustat)) ? -EFAULT : 0; -} diff --git a/src/linux/fs/super.c b/src/linux/fs/super.c deleted file mode 100644 index c183835..0000000 --- a/src/linux/fs/super.c +++ /dev/null @@ -1,1442 +0,0 @@ -/* - * linux/fs/super.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * super.c contains code to handle: - mount structures - * - super-block tables - * - filesystem drivers list - * - mount system call - * - umount system call - * - ustat system call - * - * GK 2/5/95 - Changed to support mounting the root fs via NFS - * - * Added kerneld support: Jacques Gelinas and Bjorn Ekwall - * Added change_root: Werner Almesberger & Hans Lermen, Feb '96 - * Added options to /proc/mounts: - * Torbjörn Lindh (torbjorn.lindh@gopta.se), April 14, 1996. - * Added devfs support: Richard Gooch , 13-JAN-1998 - * Heavily rewritten for 'one fs - one tree' dcache architecture. AV, Mar 2000 - */ - -#include -#include -#include -#include -#include -#include /* for the emergency remount stuff */ -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - - -static LIST_HEAD(super_blocks); -static DEFINE_SPINLOCK(sb_lock); - -static char *sb_writers_name[SB_FREEZE_LEVELS] = { - "sb_writers", - "sb_pagefaults", - "sb_internal", -}; - -/* - * One thing we have to be careful of with a per-sb shrinker is that we don't - * drop the last active reference to the superblock from within the shrinker. - * If that happens we could trigger unregistering the shrinker from within the - * shrinker path and that leads to deadlock on the shrinker_rwsem. Hence we - * take a passive reference to the superblock to avoid this from occurring. - */ -static unsigned long super_cache_scan(struct shrinker *shrink, - struct shrink_control *sc) -{ - struct super_block *sb; - long fs_objects = 0; - long total_objects; - long freed = 0; - long dentries; - long inodes; - - sb = container_of(shrink, struct super_block, s_shrink); - - /* - * Deadlock avoidance. We may hold various FS locks, and we don't want - * to recurse into the FS that called us in clear_inode() and friends.. - */ - if (!(sc->gfp_mask & __GFP_FS)) - return SHRINK_STOP; - - if (!trylock_super(sb)) - return SHRINK_STOP; - - if (sb->s_op->nr_cached_objects) - fs_objects = sb->s_op->nr_cached_objects(sb, sc); - - inodes = list_lru_shrink_count(&sb->s_inode_lru, sc); - dentries = list_lru_shrink_count(&sb->s_dentry_lru, sc); - total_objects = dentries + inodes + fs_objects + 1; - if (!total_objects) - total_objects = 1; - - /* proportion the scan between the caches */ - dentries = mult_frac(sc->nr_to_scan, dentries, total_objects); - inodes = mult_frac(sc->nr_to_scan, inodes, total_objects); - fs_objects = mult_frac(sc->nr_to_scan, fs_objects, total_objects); - - /* - * prune the dcache first as the icache is pinned by it, then - * prune the icache, followed by the filesystem specific caches - * - * Ensure that we always scan at least one object - memcg kmem - * accounting uses this to fully empty the caches. - */ - sc->nr_to_scan = dentries + 1; - freed = prune_dcache_sb(sb, sc); - sc->nr_to_scan = inodes + 1; - freed += prune_icache_sb(sb, sc); - - if (fs_objects) { - sc->nr_to_scan = fs_objects + 1; - freed += sb->s_op->free_cached_objects(sb, sc); - } - - up_read(&sb->s_umount); - return freed; -} - -static unsigned long super_cache_count(struct shrinker *shrink, - struct shrink_control *sc) -{ - struct super_block *sb; - long total_objects = 0; - - sb = container_of(shrink, struct super_block, s_shrink); - - /* - * Don't call trylock_super as it is a potential - * scalability bottleneck. The counts could get updated - * between super_cache_count and super_cache_scan anyway. - * Call to super_cache_count with shrinker_rwsem held - * ensures the safety of call to list_lru_shrink_count() and - * s_op->nr_cached_objects(). - */ - if (sb->s_op && sb->s_op->nr_cached_objects) - total_objects = sb->s_op->nr_cached_objects(sb, sc); - - total_objects += list_lru_shrink_count(&sb->s_dentry_lru, sc); - total_objects += list_lru_shrink_count(&sb->s_inode_lru, sc); - - total_objects = vfs_pressure_ratio(total_objects); - return total_objects; -} - -static void destroy_super_work(struct work_struct *work) -{ - struct super_block *s = container_of(work, struct super_block, - destroy_work); - int i; - - for (i = 0; i < SB_FREEZE_LEVELS; i++) - percpu_free_rwsem(&s->s_writers.rw_sem[i]); - kfree(s); -} - -static void destroy_super_rcu(struct rcu_head *head) -{ - struct super_block *s = container_of(head, struct super_block, rcu); - INIT_WORK(&s->destroy_work, destroy_super_work); - schedule_work(&s->destroy_work); -} - -/** - * destroy_super - frees a superblock - * @s: superblock to free - * - * Frees a superblock. - */ -static void destroy_super(struct super_block *s) -{ - list_lru_destroy(&s->s_dentry_lru); - list_lru_destroy(&s->s_inode_lru); - security_sb_free(s); - WARN_ON(!list_empty(&s->s_mounts)); - put_user_ns(s->s_user_ns); - kfree(s->s_subtype); - kfree(s->s_options); - call_rcu(&s->rcu, destroy_super_rcu); -} - -/** - * alloc_super - create new superblock - * @type: filesystem type superblock should belong to - * @flags: the mount flags - * @user_ns: User namespace for the super_block - * - * Allocates and initializes a new &struct super_block. alloc_super() - * returns a pointer new superblock or %NULL if allocation had failed. - */ -static struct super_block *alloc_super(struct file_system_type *type, int flags, - struct user_namespace *user_ns) -{ - struct super_block *s = kzalloc(sizeof(struct super_block), GFP_USER); - static const struct super_operations default_op; - int i; - - if (!s) - return NULL; - - INIT_LIST_HEAD(&s->s_mounts); - s->s_user_ns = get_user_ns(user_ns); - - if (security_sb_alloc(s)) - goto fail; - - for (i = 0; i < SB_FREEZE_LEVELS; i++) { - if (__percpu_init_rwsem(&s->s_writers.rw_sem[i], - sb_writers_name[i], - &type->s_writers_key[i])) - goto fail; - } - init_waitqueue_head(&s->s_writers.wait_unfrozen); - s->s_bdi = &noop_backing_dev_info; - s->s_flags = flags; - if (s->s_user_ns != &init_user_ns) - s->s_iflags |= SB_I_NODEV; - INIT_HLIST_NODE(&s->s_instances); - INIT_HLIST_BL_HEAD(&s->s_anon); - mutex_init(&s->s_sync_lock); - INIT_LIST_HEAD(&s->s_inodes); - spin_lock_init(&s->s_inode_list_lock); - INIT_LIST_HEAD(&s->s_inodes_wb); - spin_lock_init(&s->s_inode_wblist_lock); - - if (list_lru_init_memcg(&s->s_dentry_lru)) - goto fail; - if (list_lru_init_memcg(&s->s_inode_lru)) - goto fail; - - init_rwsem(&s->s_umount); - lockdep_set_class(&s->s_umount, &type->s_umount_key); - /* - * sget() can have s_umount recursion. - * - * When it cannot find a suitable sb, it allocates a new - * one (this one), and tries again to find a suitable old - * one. - * - * In case that succeeds, it will acquire the s_umount - * lock of the old one. Since these are clearly distrinct - * locks, and this object isn't exposed yet, there's no - * risk of deadlocks. - * - * Annotate this by putting this lock in a different - * subclass. - */ - down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING); - s->s_count = 1; - atomic_set(&s->s_active, 1); - mutex_init(&s->s_vfs_rename_mutex); - lockdep_set_class(&s->s_vfs_rename_mutex, &type->s_vfs_rename_key); - mutex_init(&s->s_dquot.dqio_mutex); - mutex_init(&s->s_dquot.dqonoff_mutex); - s->s_maxbytes = MAX_NON_LFS; - s->s_op = &default_op; - s->s_time_gran = 1000000000; - s->cleancache_poolid = CLEANCACHE_NO_POOL; - - s->s_shrink.seeks = DEFAULT_SEEKS; - s->s_shrink.scan_objects = super_cache_scan; - s->s_shrink.count_objects = super_cache_count; - s->s_shrink.batch = 1024; - s->s_shrink.flags = SHRINKER_NUMA_AWARE | SHRINKER_MEMCG_AWARE; - return s; - -fail: - destroy_super(s); - return NULL; -} - -/* Superblock refcounting */ - -/* - * Drop a superblock's refcount. The caller must hold sb_lock. - */ -static void __put_super(struct super_block *sb) -{ - if (!--sb->s_count) { - list_del_init(&sb->s_list); - destroy_super(sb); - } -} - -/** - * put_super - drop a temporary reference to superblock - * @sb: superblock in question - * - * Drops a temporary reference, frees superblock if there's no - * references left. - */ -static void put_super(struct super_block *sb) -{ - spin_lock(&sb_lock); - __put_super(sb); - spin_unlock(&sb_lock); -} - - -/** - * deactivate_locked_super - drop an active reference to superblock - * @s: superblock to deactivate - * - * Drops an active reference to superblock, converting it into a temporary - * one if there is no other active references left. In that case we - * tell fs driver to shut it down and drop the temporary reference we - * had just acquired. - * - * Caller holds exclusive lock on superblock; that lock is released. - */ -void deactivate_locked_super(struct super_block *s) -{ - struct file_system_type *fs = s->s_type; - if (atomic_dec_and_test(&s->s_active)) { - cleancache_invalidate_fs(s); - unregister_shrinker(&s->s_shrink); - fs->kill_sb(s); - - /* - * Since list_lru_destroy() may sleep, we cannot call it from - * put_super(), where we hold the sb_lock. Therefore we destroy - * the lru lists right now. - */ - list_lru_destroy(&s->s_dentry_lru); - list_lru_destroy(&s->s_inode_lru); - - put_filesystem(fs); - put_super(s); - } else { - up_write(&s->s_umount); - } -} - -EXPORT_SYMBOL(deactivate_locked_super); - -/** - * deactivate_super - drop an active reference to superblock - * @s: superblock to deactivate - * - * Variant of deactivate_locked_super(), except that superblock is *not* - * locked by caller. If we are going to drop the final active reference, - * lock will be acquired prior to that. - */ -void deactivate_super(struct super_block *s) -{ - if (!atomic_add_unless(&s->s_active, -1, 1)) { - down_write(&s->s_umount); - deactivate_locked_super(s); - } -} - -EXPORT_SYMBOL(deactivate_super); - -/** - * grab_super - acquire an active reference - * @s: reference we are trying to make active - * - * Tries to acquire an active reference. grab_super() is used when we - * had just found a superblock in super_blocks or fs_type->fs_supers - * and want to turn it into a full-blown active reference. grab_super() - * is called with sb_lock held and drops it. Returns 1 in case of - * success, 0 if we had failed (superblock contents was already dead or - * dying when grab_super() had been called). Note that this is only - * called for superblocks not in rundown mode (== ones still on ->fs_supers - * of their type), so increment of ->s_count is OK here. - */ -static int grab_super(struct super_block *s) __releases(sb_lock) -{ - s->s_count++; - spin_unlock(&sb_lock); - down_write(&s->s_umount); - if ((s->s_flags & MS_BORN) && atomic_inc_not_zero(&s->s_active)) { - put_super(s); - return 1; - } - up_write(&s->s_umount); - put_super(s); - return 0; -} - -/* - * trylock_super - try to grab ->s_umount shared - * @sb: reference we are trying to grab - * - * Try to prevent fs shutdown. This is used in places where we - * cannot take an active reference but we need to ensure that the - * filesystem is not shut down while we are working on it. It returns - * false if we cannot acquire s_umount or if we lose the race and - * filesystem already got into shutdown, and returns true with the s_umount - * lock held in read mode in case of success. On successful return, - * the caller must drop the s_umount lock when done. - * - * Note that unlike get_super() et.al. this one does *not* bump ->s_count. - * The reason why it's safe is that we are OK with doing trylock instead - * of down_read(). There's a couple of places that are OK with that, but - * it's very much not a general-purpose interface. - */ -bool trylock_super(struct super_block *sb) -{ - if (down_read_trylock(&sb->s_umount)) { - if (!hlist_unhashed(&sb->s_instances) && - sb->s_root && (sb->s_flags & MS_BORN)) - return true; - up_read(&sb->s_umount); - } - - return false; -} - -/** - * generic_shutdown_super - common helper for ->kill_sb() - * @sb: superblock to kill - * - * generic_shutdown_super() does all fs-independent work on superblock - * shutdown. Typical ->kill_sb() should pick all fs-specific objects - * that need destruction out of superblock, call generic_shutdown_super() - * and release aforementioned objects. Note: dentries and inodes _are_ - * taken care of and do not need specific handling. - * - * Upon calling this function, the filesystem may no longer alter or - * rearrange the set of dentries belonging to this super_block, nor may it - * change the attachments of dentries to inodes. - */ -void generic_shutdown_super(struct super_block *sb) -{ - const struct super_operations *sop = sb->s_op; - - if (sb->s_root) { - shrink_dcache_for_umount(sb); - sync_filesystem(sb); - sb->s_flags &= ~MS_ACTIVE; - - fsnotify_unmount_inodes(sb); - cgroup_writeback_umount(); - - evict_inodes(sb); - - if (sb->s_dio_done_wq) { - destroy_workqueue(sb->s_dio_done_wq); - sb->s_dio_done_wq = NULL; - } - - if (sop->put_super) - sop->put_super(sb); - - if (!list_empty(&sb->s_inodes)) { - printk("VFS: Busy inodes after unmount of %s. " - "Self-destruct in 5 seconds. Have a nice day...\n", - sb->s_id); - } - } - spin_lock(&sb_lock); - /* should be initialized for __put_super_and_need_restart() */ - hlist_del_init(&sb->s_instances); - spin_unlock(&sb_lock); - up_write(&sb->s_umount); -} - -EXPORT_SYMBOL(generic_shutdown_super); - -/** - * sget_userns - find or create a superblock - * @type: filesystem type superblock should belong to - * @test: comparison callback - * @set: setup callback - * @flags: mount flags - * @user_ns: User namespace for the super_block - * @data: argument to each of them - */ -struct super_block *sget_userns(struct file_system_type *type, - int (*test)(struct super_block *,void *), - int (*set)(struct super_block *,void *), - int flags, struct user_namespace *user_ns, - void *data) -{ - struct super_block *s = NULL; - struct super_block *old; - int err; - - if (!(flags & MS_KERNMOUNT) && - !(type->fs_flags & FS_USERNS_MOUNT) && - !capable(CAP_SYS_ADMIN)) - return ERR_PTR(-EPERM); -retry: - spin_lock(&sb_lock); - if (test) { - hlist_for_each_entry(old, &type->fs_supers, s_instances) { - if (!test(old, data)) - continue; - if (user_ns != old->s_user_ns) { - spin_unlock(&sb_lock); - if (s) { - up_write(&s->s_umount); - destroy_super(s); - } - return ERR_PTR(-EBUSY); - } - if (!grab_super(old)) - goto retry; - if (s) { - up_write(&s->s_umount); - destroy_super(s); - s = NULL; - } - return old; - } - } - if (!s) { - spin_unlock(&sb_lock); - s = alloc_super(type, flags, user_ns); - if (!s) - return ERR_PTR(-ENOMEM); - goto retry; - } - - err = set(s, data); - if (err) { - spin_unlock(&sb_lock); - up_write(&s->s_umount); - destroy_super(s); - return ERR_PTR(err); - } - s->s_type = type; - strlcpy(s->s_id, type->name, sizeof(s->s_id)); - list_add_tail(&s->s_list, &super_blocks); - hlist_add_head(&s->s_instances, &type->fs_supers); - spin_unlock(&sb_lock); - get_filesystem(type); - register_shrinker(&s->s_shrink); - return s; -} - -EXPORT_SYMBOL(sget_userns); - -/** - * sget - find or create a superblock - * @type: filesystem type superblock should belong to - * @test: comparison callback - * @set: setup callback - * @flags: mount flags - * @data: argument to each of them - */ -struct super_block *sget(struct file_system_type *type, - int (*test)(struct super_block *,void *), - int (*set)(struct super_block *,void *), - int flags, - void *data) -{ - struct user_namespace *user_ns = current_user_ns(); - - /* Ensure the requestor has permissions over the target filesystem */ - if (!(flags & MS_KERNMOUNT) && !ns_capable(user_ns, CAP_SYS_ADMIN)) - return ERR_PTR(-EPERM); - - return sget_userns(type, test, set, flags, user_ns, data); -} - -EXPORT_SYMBOL(sget); - -void drop_super(struct super_block *sb) -{ - up_read(&sb->s_umount); - put_super(sb); -} - -EXPORT_SYMBOL(drop_super); - -/** - * iterate_supers - call function for all active superblocks - * @f: function to call - * @arg: argument to pass to it - * - * Scans the superblock list and calls given function, passing it - * locked superblock and given argument. - */ -void iterate_supers(void (*f)(struct super_block *, void *), void *arg) -{ - struct super_block *sb, *p = NULL; - - spin_lock(&sb_lock); - list_for_each_entry(sb, &super_blocks, s_list) { - if (hlist_unhashed(&sb->s_instances)) - continue; - sb->s_count++; - spin_unlock(&sb_lock); - - down_read(&sb->s_umount); - if (sb->s_root && (sb->s_flags & MS_BORN)) - f(sb, arg); - up_read(&sb->s_umount); - - spin_lock(&sb_lock); - if (p) - __put_super(p); - p = sb; - } - if (p) - __put_super(p); - spin_unlock(&sb_lock); -} - -/** - * iterate_supers_type - call function for superblocks of given type - * @type: fs type - * @f: function to call - * @arg: argument to pass to it - * - * Scans the superblock list and calls given function, passing it - * locked superblock and given argument. - */ -void iterate_supers_type(struct file_system_type *type, - void (*f)(struct super_block *, void *), void *arg) -{ - struct super_block *sb, *p = NULL; - - spin_lock(&sb_lock); - hlist_for_each_entry(sb, &type->fs_supers, s_instances) { - sb->s_count++; - spin_unlock(&sb_lock); - - down_read(&sb->s_umount); - if (sb->s_root && (sb->s_flags & MS_BORN)) - f(sb, arg); - up_read(&sb->s_umount); - - spin_lock(&sb_lock); - if (p) - __put_super(p); - p = sb; - } - if (p) - __put_super(p); - spin_unlock(&sb_lock); -} - -EXPORT_SYMBOL(iterate_supers_type); - -/** - * get_super - get the superblock of a device - * @bdev: device to get the superblock for - * - * Scans the superblock list and finds the superblock of the file system - * mounted on the device given. %NULL is returned if no match is found. - */ - -struct super_block *get_super(struct block_device *bdev) -{ - struct super_block *sb; - - if (!bdev) - return NULL; - - spin_lock(&sb_lock); -rescan: - list_for_each_entry(sb, &super_blocks, s_list) { - if (hlist_unhashed(&sb->s_instances)) - continue; - if (sb->s_bdev == bdev) { - sb->s_count++; - spin_unlock(&sb_lock); - down_read(&sb->s_umount); - /* still alive? */ - if (sb->s_root && (sb->s_flags & MS_BORN)) - return sb; - up_read(&sb->s_umount); - /* nope, got unmounted */ - spin_lock(&sb_lock); - __put_super(sb); - goto rescan; - } - } - spin_unlock(&sb_lock); - return NULL; -} - -EXPORT_SYMBOL(get_super); - -/** - * get_super_thawed - get thawed superblock of a device - * @bdev: device to get the superblock for - * - * Scans the superblock list and finds the superblock of the file system - * mounted on the device. The superblock is returned once it is thawed - * (or immediately if it was not frozen). %NULL is returned if no match - * is found. - */ -struct super_block *get_super_thawed(struct block_device *bdev) -{ - while (1) { - struct super_block *s = get_super(bdev); - if (!s || s->s_writers.frozen == SB_UNFROZEN) - return s; - up_read(&s->s_umount); - wait_event(s->s_writers.wait_unfrozen, - s->s_writers.frozen == SB_UNFROZEN); - put_super(s); - } -} -EXPORT_SYMBOL(get_super_thawed); - -/** - * get_active_super - get an active reference to the superblock of a device - * @bdev: device to get the superblock for - * - * Scans the superblock list and finds the superblock of the file system - * mounted on the device given. Returns the superblock with an active - * reference or %NULL if none was found. - */ -struct super_block *get_active_super(struct block_device *bdev) -{ - struct super_block *sb; - - if (!bdev) - return NULL; - -restart: - spin_lock(&sb_lock); - list_for_each_entry(sb, &super_blocks, s_list) { - if (hlist_unhashed(&sb->s_instances)) - continue; - if (sb->s_bdev == bdev) { - if (!grab_super(sb)) - goto restart; - up_write(&sb->s_umount); - return sb; - } - } - spin_unlock(&sb_lock); - return NULL; -} - -struct super_block *user_get_super(dev_t dev) -{ - struct super_block *sb; - - spin_lock(&sb_lock); -rescan: - list_for_each_entry(sb, &super_blocks, s_list) { - if (hlist_unhashed(&sb->s_instances)) - continue; - if (sb->s_dev == dev) { - sb->s_count++; - spin_unlock(&sb_lock); - down_read(&sb->s_umount); - /* still alive? */ - if (sb->s_root && (sb->s_flags & MS_BORN)) - return sb; - up_read(&sb->s_umount); - /* nope, got unmounted */ - spin_lock(&sb_lock); - __put_super(sb); - goto rescan; - } - } - spin_unlock(&sb_lock); - return NULL; -} - -/** - * do_remount_sb - asks filesystem to change mount options. - * @sb: superblock in question - * @flags: numeric part of options - * @data: the rest of options - * @force: whether or not to force the change - * - * Alters the mount options of a mounted file system. - */ -int do_remount_sb(struct super_block *sb, int flags, void *data, int force) -{ - int retval; - int remount_ro; - - if (sb->s_writers.frozen != SB_UNFROZEN) - return -EBUSY; - -#ifdef CONFIG_BLOCK - if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev)) - return -EACCES; -#endif - - remount_ro = (flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY); - - if (remount_ro) { - if (!hlist_empty(&sb->s_pins)) { - up_write(&sb->s_umount); - group_pin_kill(&sb->s_pins); - down_write(&sb->s_umount); - if (!sb->s_root) - return 0; - if (sb->s_writers.frozen != SB_UNFROZEN) - return -EBUSY; - remount_ro = (flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY); - } - } - shrink_dcache_sb(sb); - - /* If we are remounting RDONLY and current sb is read/write, - make sure there are no rw files opened */ - if (remount_ro) { - if (force) { - sb->s_readonly_remount = 1; - smp_wmb(); - } else { - retval = sb_prepare_remount_readonly(sb); - if (retval) - return retval; - } - } - - if (sb->s_op->remount_fs) { - retval = sb->s_op->remount_fs(sb, &flags, data); - if (retval) { - if (!force) - goto cancel_readonly; - /* If forced remount, go ahead despite any errors */ - WARN(1, "forced remount of a %s fs returned %i\n", - sb->s_type->name, retval); - } - } - sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); - /* Needs to be ordered wrt mnt_is_readonly() */ - smp_wmb(); - sb->s_readonly_remount = 0; - - /* - * Some filesystems modify their metadata via some other path than the - * bdev buffer cache (eg. use a private mapping, or directories in - * pagecache, etc). Also file data modifications go via their own - * mappings. So If we try to mount readonly then copy the filesystem - * from bdev, we could get stale data, so invalidate it to give a best - * effort at coherency. - */ - if (remount_ro && sb->s_bdev) - invalidate_bdev(sb->s_bdev); - return 0; - -cancel_readonly: - sb->s_readonly_remount = 0; - return retval; -} - -static void do_emergency_remount(struct work_struct *work) -{ - struct super_block *sb, *p = NULL; - - spin_lock(&sb_lock); - list_for_each_entry(sb, &super_blocks, s_list) { - if (hlist_unhashed(&sb->s_instances)) - continue; - sb->s_count++; - spin_unlock(&sb_lock); - down_write(&sb->s_umount); - if (sb->s_root && sb->s_bdev && (sb->s_flags & MS_BORN) && - !(sb->s_flags & MS_RDONLY)) { - /* - * What lock protects sb->s_flags?? - */ - do_remount_sb(sb, MS_RDONLY, NULL, 1); - } - up_write(&sb->s_umount); - spin_lock(&sb_lock); - if (p) - __put_super(p); - p = sb; - } - if (p) - __put_super(p); - spin_unlock(&sb_lock); - kfree(work); - printk("Emergency Remount complete\n"); -} - -void emergency_remount(void) -{ - struct work_struct *work; - - work = kmalloc(sizeof(*work), GFP_ATOMIC); - if (work) { - INIT_WORK(work, do_emergency_remount); - schedule_work(work); - } -} - -/* - * Unnamed block devices are dummy devices used by virtual - * filesystems which don't use real block-devices. -- jrs - */ - -static DEFINE_IDA(unnamed_dev_ida); -static DEFINE_SPINLOCK(unnamed_dev_lock);/* protects the above */ -/* Many userspace utilities consider an FSID of 0 invalid. - * Always return at least 1 from get_anon_bdev. - */ -static int unnamed_dev_start = 1; - -int get_anon_bdev(dev_t *p) -{ - int dev; - int error; - - retry: - if (ida_pre_get(&unnamed_dev_ida, GFP_ATOMIC) == 0) - return -ENOMEM; - spin_lock(&unnamed_dev_lock); - error = ida_get_new_above(&unnamed_dev_ida, unnamed_dev_start, &dev); - if (!error) - unnamed_dev_start = dev + 1; - spin_unlock(&unnamed_dev_lock); - if (error == -EAGAIN) - /* We raced and lost with another CPU. */ - goto retry; - else if (error) - return -EAGAIN; - - if (dev >= (1 << MINORBITS)) { - spin_lock(&unnamed_dev_lock); - ida_remove(&unnamed_dev_ida, dev); - if (unnamed_dev_start > dev) - unnamed_dev_start = dev; - spin_unlock(&unnamed_dev_lock); - return -EMFILE; - } - *p = MKDEV(0, dev & MINORMASK); - return 0; -} -EXPORT_SYMBOL(get_anon_bdev); - -void free_anon_bdev(dev_t dev) -{ - int slot = MINOR(dev); - spin_lock(&unnamed_dev_lock); - ida_remove(&unnamed_dev_ida, slot); - if (slot < unnamed_dev_start) - unnamed_dev_start = slot; - spin_unlock(&unnamed_dev_lock); -} -EXPORT_SYMBOL(free_anon_bdev); - -int set_anon_super(struct super_block *s, void *data) -{ - return get_anon_bdev(&s->s_dev); -} - -EXPORT_SYMBOL(set_anon_super); - -void kill_anon_super(struct super_block *sb) -{ - dev_t dev = sb->s_dev; - generic_shutdown_super(sb); - free_anon_bdev(dev); -} - -EXPORT_SYMBOL(kill_anon_super); - -void kill_litter_super(struct super_block *sb) -{ - if (sb->s_root) - d_genocide(sb->s_root); - kill_anon_super(sb); -} - -EXPORT_SYMBOL(kill_litter_super); - -static int ns_test_super(struct super_block *sb, void *data) -{ - return sb->s_fs_info == data; -} - -static int ns_set_super(struct super_block *sb, void *data) -{ - sb->s_fs_info = data; - return set_anon_super(sb, NULL); -} - -struct dentry *mount_ns(struct file_system_type *fs_type, - int flags, void *data, void *ns, struct user_namespace *user_ns, - int (*fill_super)(struct super_block *, void *, int)) -{ - struct super_block *sb; - - /* Don't allow mounting unless the caller has CAP_SYS_ADMIN - * over the namespace. - */ - if (!(flags & MS_KERNMOUNT) && !ns_capable(user_ns, CAP_SYS_ADMIN)) - return ERR_PTR(-EPERM); - - sb = sget_userns(fs_type, ns_test_super, ns_set_super, flags, - user_ns, ns); - if (IS_ERR(sb)) - return ERR_CAST(sb); - - if (!sb->s_root) { - int err; - err = fill_super(sb, data, flags & MS_SILENT ? 1 : 0); - if (err) { - deactivate_locked_super(sb); - return ERR_PTR(err); - } - - sb->s_flags |= MS_ACTIVE; - } - - return dget(sb->s_root); -} - -EXPORT_SYMBOL(mount_ns); - -#ifdef CONFIG_BLOCK -static int set_bdev_super(struct super_block *s, void *data) -{ - s->s_bdev = data; - s->s_dev = s->s_bdev->bd_dev; - - /* - * We set the bdi here to the queue backing, file systems can - * overwrite this in ->fill_super() - */ - s->s_bdi = &bdev_get_queue(s->s_bdev)->backing_dev_info; - return 0; -} - -static int test_bdev_super(struct super_block *s, void *data) -{ - return (void *)s->s_bdev == data; -} - -struct dentry *mount_bdev(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, - int (*fill_super)(struct super_block *, void *, int)) -{ - struct block_device *bdev; - struct super_block *s; - fmode_t mode = FMODE_READ | FMODE_EXCL; - int error = 0; - - if (!(flags & MS_RDONLY)) - mode |= FMODE_WRITE; - - bdev = blkdev_get_by_path(dev_name, mode, fs_type); - if (IS_ERR(bdev)) - return ERR_CAST(bdev); - - /* - * once the super is inserted into the list by sget, s_umount - * will protect the lockfs code from trying to start a snapshot - * while we are mounting - */ - mutex_lock(&bdev->bd_fsfreeze_mutex); - if (bdev->bd_fsfreeze_count > 0) { - mutex_unlock(&bdev->bd_fsfreeze_mutex); - error = -EBUSY; - goto error_bdev; - } - s = sget(fs_type, test_bdev_super, set_bdev_super, flags | MS_NOSEC, - bdev); - mutex_unlock(&bdev->bd_fsfreeze_mutex); - if (IS_ERR(s)) - goto error_s; - - if (s->s_root) { - if ((flags ^ s->s_flags) & MS_RDONLY) { - deactivate_locked_super(s); - error = -EBUSY; - goto error_bdev; - } - - /* - * s_umount nests inside bd_mutex during - * __invalidate_device(). blkdev_put() acquires - * bd_mutex and can't be called under s_umount. Drop - * s_umount temporarily. This is safe as we're - * holding an active reference. - */ - up_write(&s->s_umount); - blkdev_put(bdev, mode); - down_write(&s->s_umount); - } else { - s->s_mode = mode; - snprintf(s->s_id, sizeof(s->s_id), "%pg", bdev); - sb_set_blocksize(s, block_size(bdev)); - error = fill_super(s, data, flags & MS_SILENT ? 1 : 0); - if (error) { - deactivate_locked_super(s); - goto error; - } - - s->s_flags |= MS_ACTIVE; - bdev->bd_super = s; - } - - return dget(s->s_root); - -error_s: - error = PTR_ERR(s); -error_bdev: - blkdev_put(bdev, mode); -error: - return ERR_PTR(error); -} -EXPORT_SYMBOL(mount_bdev); - -void kill_block_super(struct super_block *sb) -{ - struct block_device *bdev = sb->s_bdev; - fmode_t mode = sb->s_mode; - - bdev->bd_super = NULL; - generic_shutdown_super(sb); - sync_blockdev(bdev); - WARN_ON_ONCE(!(mode & FMODE_EXCL)); - blkdev_put(bdev, mode | FMODE_EXCL); -} - -EXPORT_SYMBOL(kill_block_super); -#endif - -struct dentry *mount_nodev(struct file_system_type *fs_type, - int flags, void *data, - int (*fill_super)(struct super_block *, void *, int)) -{ - int error; - struct super_block *s = sget(fs_type, NULL, set_anon_super, flags, NULL); - - if (IS_ERR(s)) - return ERR_CAST(s); - - error = fill_super(s, data, flags & MS_SILENT ? 1 : 0); - if (error) { - deactivate_locked_super(s); - return ERR_PTR(error); - } - s->s_flags |= MS_ACTIVE; - return dget(s->s_root); -} -EXPORT_SYMBOL(mount_nodev); - -static int compare_single(struct super_block *s, void *p) -{ - return 1; -} - -struct dentry *mount_single(struct file_system_type *fs_type, - int flags, void *data, - int (*fill_super)(struct super_block *, void *, int)) -{ - struct super_block *s; - int error; - - s = sget(fs_type, compare_single, set_anon_super, flags, NULL); - if (IS_ERR(s)) - return ERR_CAST(s); - if (!s->s_root) { - error = fill_super(s, data, flags & MS_SILENT ? 1 : 0); - if (error) { - deactivate_locked_super(s); - return ERR_PTR(error); - } - s->s_flags |= MS_ACTIVE; - } else { - do_remount_sb(s, flags, data, 0); - } - return dget(s->s_root); -} -EXPORT_SYMBOL(mount_single); - -struct dentry * -mount_fs(struct file_system_type *type, int flags, const char *name, void *data) -{ - struct dentry *root; - struct super_block *sb; - char *secdata = NULL; - int error = -ENOMEM; - - if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) { - secdata = alloc_secdata(); - if (!secdata) - goto out; - - error = security_sb_copy_data(data, secdata); - if (error) - goto out_free_secdata; - } - - root = type->mount(type, flags, name, data); - if (IS_ERR(root)) { - error = PTR_ERR(root); - goto out_free_secdata; - } - sb = root->d_sb; - BUG_ON(!sb); - WARN_ON(!sb->s_bdi); - sb->s_flags |= MS_BORN; - - error = security_sb_kern_mount(sb, flags, secdata); - if (error) - goto out_sb; - - /* - * filesystems should never set s_maxbytes larger than MAX_LFS_FILESIZE - * but s_maxbytes was an unsigned long long for many releases. Throw - * this warning for a little while to try and catch filesystems that - * violate this rule. - */ - WARN((sb->s_maxbytes < 0), "%s set sb->s_maxbytes to " - "negative value (%lld)\n", type->name, sb->s_maxbytes); - - up_write(&sb->s_umount); - free_secdata(secdata); - return root; -out_sb: - dput(root); - deactivate_locked_super(sb); -out_free_secdata: - free_secdata(secdata); -out: - return ERR_PTR(error); -} - -/* - * This is an internal function, please use sb_end_{write,pagefault,intwrite} - * instead. - */ -void __sb_end_write(struct super_block *sb, int level) -{ - percpu_up_read(sb->s_writers.rw_sem + level-1); -} -EXPORT_SYMBOL(__sb_end_write); - -/* - * This is an internal function, please use sb_start_{write,pagefault,intwrite} - * instead. - */ -int __sb_start_write(struct super_block *sb, int level, bool wait) -{ - bool force_trylock = false; - int ret = 1; - -#ifdef CONFIG_LOCKDEP - /* - * We want lockdep to tell us about possible deadlocks with freezing - * but it's it bit tricky to properly instrument it. Getting a freeze - * protection works as getting a read lock but there are subtle - * problems. XFS for example gets freeze protection on internal level - * twice in some cases, which is OK only because we already hold a - * freeze protection also on higher level. Due to these cases we have - * to use wait == F (trylock mode) which must not fail. - */ - if (wait) { - int i; - - for (i = 0; i < level - 1; i++) - if (percpu_rwsem_is_held(sb->s_writers.rw_sem + i)) { - force_trylock = true; - break; - } - } -#endif - if (wait && !force_trylock) - percpu_down_read(sb->s_writers.rw_sem + level-1); - else - ret = percpu_down_read_trylock(sb->s_writers.rw_sem + level-1); - - WARN_ON(force_trylock && !ret); - return ret; -} -EXPORT_SYMBOL(__sb_start_write); - -/** - * sb_wait_write - wait until all writers to given file system finish - * @sb: the super for which we wait - * @level: type of writers we wait for (normal vs page fault) - * - * This function waits until there are no writers of given type to given file - * system. - */ -static void sb_wait_write(struct super_block *sb, int level) -{ - percpu_down_write(sb->s_writers.rw_sem + level-1); -} - -/* - * We are going to return to userspace and forget about these locks, the - * ownership goes to the caller of thaw_super() which does unlock(). - */ -static void lockdep_sb_freeze_release(struct super_block *sb) -{ - int level; - - for (level = SB_FREEZE_LEVELS - 1; level >= 0; level--) - percpu_rwsem_release(sb->s_writers.rw_sem + level, 0, _THIS_IP_); -} - -/* - * Tell lockdep we are holding these locks before we call ->unfreeze_fs(sb). - */ -static void lockdep_sb_freeze_acquire(struct super_block *sb) -{ - int level; - - for (level = 0; level < SB_FREEZE_LEVELS; ++level) - percpu_rwsem_acquire(sb->s_writers.rw_sem + level, 0, _THIS_IP_); -} - -static void sb_freeze_unlock(struct super_block *sb) -{ - int level; - - for (level = SB_FREEZE_LEVELS - 1; level >= 0; level--) - percpu_up_write(sb->s_writers.rw_sem + level); -} - -/** - * freeze_super - lock the filesystem and force it into a consistent state - * @sb: the super to lock - * - * Syncs the super to make sure the filesystem is consistent and calls the fs's - * freeze_fs. Subsequent calls to this without first thawing the fs will return - * -EBUSY. - * - * During this function, sb->s_writers.frozen goes through these values: - * - * SB_UNFROZEN: File system is normal, all writes progress as usual. - * - * SB_FREEZE_WRITE: The file system is in the process of being frozen. New - * writes should be blocked, though page faults are still allowed. We wait for - * all writes to complete and then proceed to the next stage. - * - * SB_FREEZE_PAGEFAULT: Freezing continues. Now also page faults are blocked - * but internal fs threads can still modify the filesystem (although they - * should not dirty new pages or inodes), writeback can run etc. After waiting - * for all running page faults we sync the filesystem which will clean all - * dirty pages and inodes (no new dirty pages or inodes can be created when - * sync is running). - * - * SB_FREEZE_FS: The file system is frozen. Now all internal sources of fs - * modification are blocked (e.g. XFS preallocation truncation on inode - * reclaim). This is usually implemented by blocking new transactions for - * filesystems that have them and need this additional guard. After all - * internal writers are finished we call ->freeze_fs() to finish filesystem - * freezing. Then we transition to SB_FREEZE_COMPLETE state. This state is - * mostly auxiliary for filesystems to verify they do not modify frozen fs. - * - * sb->s_writers.frozen is protected by sb->s_umount. - */ -int freeze_super(struct super_block *sb) -{ - int ret; - - atomic_inc(&sb->s_active); - down_write(&sb->s_umount); - if (sb->s_writers.frozen != SB_UNFROZEN) { - deactivate_locked_super(sb); - return -EBUSY; - } - - if (!(sb->s_flags & MS_BORN)) { - up_write(&sb->s_umount); - return 0; /* sic - it's "nothing to do" */ - } - - if (sb->s_flags & MS_RDONLY) { - /* Nothing to do really... */ - sb->s_writers.frozen = SB_FREEZE_COMPLETE; - up_write(&sb->s_umount); - return 0; - } - - sb->s_writers.frozen = SB_FREEZE_WRITE; - /* Release s_umount to preserve sb_start_write -> s_umount ordering */ - up_write(&sb->s_umount); - sb_wait_write(sb, SB_FREEZE_WRITE); - down_write(&sb->s_umount); - - /* Now we go and block page faults... */ - sb->s_writers.frozen = SB_FREEZE_PAGEFAULT; - sb_wait_write(sb, SB_FREEZE_PAGEFAULT); - - /* All writers are done so after syncing there won't be dirty data */ - sync_filesystem(sb); - - /* Now wait for internal filesystem counter */ - sb->s_writers.frozen = SB_FREEZE_FS; - sb_wait_write(sb, SB_FREEZE_FS); - - if (sb->s_op->freeze_fs) { - ret = sb->s_op->freeze_fs(sb); - if (ret) { - printk(KERN_ERR - "VFS:Filesystem freeze failed\n"); - sb->s_writers.frozen = SB_UNFROZEN; - sb_freeze_unlock(sb); - wake_up(&sb->s_writers.wait_unfrozen); - deactivate_locked_super(sb); - return ret; - } - } - /* - * For debugging purposes so that fs can warn if it sees write activity - * when frozen is set to SB_FREEZE_COMPLETE, and for thaw_super(). - */ - sb->s_writers.frozen = SB_FREEZE_COMPLETE; - lockdep_sb_freeze_release(sb); - up_write(&sb->s_umount); - return 0; -} -EXPORT_SYMBOL(freeze_super); - -/** - * thaw_super -- unlock filesystem - * @sb: the super to thaw - * - * Unlocks the filesystem and marks it writeable again after freeze_super(). - */ -int thaw_super(struct super_block *sb) -{ - int error; - - down_write(&sb->s_umount); - if (sb->s_writers.frozen != SB_FREEZE_COMPLETE) { - up_write(&sb->s_umount); - return -EINVAL; - } - - if (sb->s_flags & MS_RDONLY) { - sb->s_writers.frozen = SB_UNFROZEN; - goto out; - } - - lockdep_sb_freeze_acquire(sb); - - if (sb->s_op->unfreeze_fs) { - error = sb->s_op->unfreeze_fs(sb); - if (error) { - printk(KERN_ERR - "VFS:Filesystem thaw failed\n"); - lockdep_sb_freeze_release(sb); - up_write(&sb->s_umount); - return error; - } - } - - sb->s_writers.frozen = SB_UNFROZEN; - sb_freeze_unlock(sb); -out: - wake_up(&sb->s_writers.wait_unfrozen); - deactivate_locked_super(sb); - return 0; -} -EXPORT_SYMBOL(thaw_super); diff --git a/src/linux/fs/sync.c b/src/linux/fs/sync.c deleted file mode 100644 index 2a54c1f..0000000 --- a/src/linux/fs/sync.c +++ /dev/null @@ -1,372 +0,0 @@ -/* - * High-level sync()-related operations - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -#define VALID_FLAGS (SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE| \ - SYNC_FILE_RANGE_WAIT_AFTER) - -/* - * Do the filesystem syncing work. For simple filesystems - * writeback_inodes_sb(sb) just dirties buffers with inodes so we have to - * submit IO for these buffers via __sync_blockdev(). This also speeds up the - * wait == 1 case since in that case write_inode() functions do - * sync_dirty_buffer() and thus effectively write one block at a time. - */ -static int __sync_filesystem(struct super_block *sb, int wait) -{ - if (wait) - sync_inodes_sb(sb); - else - writeback_inodes_sb(sb, WB_REASON_SYNC); - - if (sb->s_op->sync_fs) - sb->s_op->sync_fs(sb, wait); - return __sync_blockdev(sb->s_bdev, wait); -} - -/* - * Write out and wait upon all dirty data associated with this - * superblock. Filesystem data as well as the underlying block - * device. Takes the superblock lock. - */ -int sync_filesystem(struct super_block *sb) -{ - int ret; - - /* - * We need to be protected against the filesystem going from - * r/o to r/w or vice versa. - */ - WARN_ON(!rwsem_is_locked(&sb->s_umount)); - - /* - * No point in syncing out anything if the filesystem is read-only. - */ - if (sb->s_flags & MS_RDONLY) - return 0; - - ret = __sync_filesystem(sb, 0); - if (ret < 0) - return ret; - return __sync_filesystem(sb, 1); -} -EXPORT_SYMBOL(sync_filesystem); - -static void sync_inodes_one_sb(struct super_block *sb, void *arg) -{ - if (!(sb->s_flags & MS_RDONLY)) - sync_inodes_sb(sb); -} - -static void sync_fs_one_sb(struct super_block *sb, void *arg) -{ - if (!(sb->s_flags & MS_RDONLY) && sb->s_op->sync_fs) - sb->s_op->sync_fs(sb, *(int *)arg); -} - -static void fdatawrite_one_bdev(struct block_device *bdev, void *arg) -{ - filemap_fdatawrite(bdev->bd_inode->i_mapping); -} - -static void fdatawait_one_bdev(struct block_device *bdev, void *arg) -{ - /* - * We keep the error status of individual mapping so that - * applications can catch the writeback error using fsync(2). - * See filemap_fdatawait_keep_errors() for details. - */ - filemap_fdatawait_keep_errors(bdev->bd_inode->i_mapping); -} - -/* - * Sync everything. We start by waking flusher threads so that most of - * writeback runs on all devices in parallel. Then we sync all inodes reliably - * which effectively also waits for all flusher threads to finish doing - * writeback. At this point all data is on disk so metadata should be stable - * and we tell filesystems to sync their metadata via ->sync_fs() calls. - * Finally, we writeout all block devices because some filesystems (e.g. ext2) - * just write metadata (such as inodes or bitmaps) to block device page cache - * and do not sync it on their own in ->sync_fs(). - */ -SYSCALL_DEFINE0(sync) -{ - int nowait = 0, wait = 1; - - wakeup_flusher_threads(0, WB_REASON_SYNC); - iterate_supers(sync_inodes_one_sb, NULL); - iterate_supers(sync_fs_one_sb, &nowait); - iterate_supers(sync_fs_one_sb, &wait); - iterate_bdevs(fdatawrite_one_bdev, NULL); - iterate_bdevs(fdatawait_one_bdev, NULL); - if (unlikely(laptop_mode)) - laptop_sync_completion(); - return 0; -} - -static void do_sync_work(struct work_struct *work) -{ - int nowait = 0; - - /* - * Sync twice to reduce the possibility we skipped some inodes / pages - * because they were temporarily locked - */ - iterate_supers(sync_inodes_one_sb, &nowait); - iterate_supers(sync_fs_one_sb, &nowait); - iterate_bdevs(fdatawrite_one_bdev, NULL); - iterate_supers(sync_inodes_one_sb, &nowait); - iterate_supers(sync_fs_one_sb, &nowait); - iterate_bdevs(fdatawrite_one_bdev, NULL); - printk("Emergency Sync complete\n"); - kfree(work); -} - -void emergency_sync(void) -{ - struct work_struct *work; - - work = kmalloc(sizeof(*work), GFP_ATOMIC); - if (work) { - INIT_WORK(work, do_sync_work); - schedule_work(work); - } -} - -/* - * sync a single super - */ -SYSCALL_DEFINE1(syncfs, int, fd) -{ - struct fd f = fdget(fd); - struct super_block *sb; - int ret; - - if (!f.file) - return -EBADF; - sb = f.file->f_path.dentry->d_sb; - - down_read(&sb->s_umount); - ret = sync_filesystem(sb); - up_read(&sb->s_umount); - - fdput(f); - return ret; -} - -/** - * vfs_fsync_range - helper to sync a range of data & metadata to disk - * @file: file to sync - * @start: offset in bytes of the beginning of data range to sync - * @end: offset in bytes of the end of data range (inclusive) - * @datasync: perform only datasync - * - * Write back data in range @start..@end and metadata for @file to disk. If - * @datasync is set only metadata needed to access modified file data is - * written. - */ -int vfs_fsync_range(struct file *file, loff_t start, loff_t end, int datasync) -{ - struct inode *inode = file->f_mapping->host; - - if (!file->f_op->fsync) - return -EINVAL; - if (!datasync && (inode->i_state & I_DIRTY_TIME)) { - spin_lock(&inode->i_lock); - inode->i_state &= ~I_DIRTY_TIME; - spin_unlock(&inode->i_lock); - mark_inode_dirty_sync(inode); - } - return file->f_op->fsync(file, start, end, datasync); -} -EXPORT_SYMBOL(vfs_fsync_range); - -/** - * vfs_fsync - perform a fsync or fdatasync on a file - * @file: file to sync - * @datasync: only perform a fdatasync operation - * - * Write back data and metadata for @file to disk. If @datasync is - * set only metadata needed to access modified file data is written. - */ -int vfs_fsync(struct file *file, int datasync) -{ - return vfs_fsync_range(file, 0, LLONG_MAX, datasync); -} -EXPORT_SYMBOL(vfs_fsync); - -static int do_fsync(unsigned int fd, int datasync) -{ - struct fd f = fdget(fd); - int ret = -EBADF; - - if (f.file) { - ret = vfs_fsync(f.file, datasync); - fdput(f); - } - return ret; -} - -SYSCALL_DEFINE1(fsync, unsigned int, fd) -{ - return do_fsync(fd, 0); -} - -SYSCALL_DEFINE1(fdatasync, unsigned int, fd) -{ - return do_fsync(fd, 1); -} - -/* - * sys_sync_file_range() permits finely controlled syncing over a segment of - * a file in the range offset .. (offset+nbytes-1) inclusive. If nbytes is - * zero then sys_sync_file_range() will operate from offset out to EOF. - * - * The flag bits are: - * - * SYNC_FILE_RANGE_WAIT_BEFORE: wait upon writeout of all pages in the range - * before performing the write. - * - * SYNC_FILE_RANGE_WRITE: initiate writeout of all those dirty pages in the - * range which are not presently under writeback. Note that this may block for - * significant periods due to exhaustion of disk request structures. - * - * SYNC_FILE_RANGE_WAIT_AFTER: wait upon writeout of all pages in the range - * after performing the write. - * - * Useful combinations of the flag bits are: - * - * SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE: ensures that all pages - * in the range which were dirty on entry to sys_sync_file_range() are placed - * under writeout. This is a start-write-for-data-integrity operation. - * - * SYNC_FILE_RANGE_WRITE: start writeout of all dirty pages in the range which - * are not presently under writeout. This is an asynchronous flush-to-disk - * operation. Not suitable for data integrity operations. - * - * SYNC_FILE_RANGE_WAIT_BEFORE (or SYNC_FILE_RANGE_WAIT_AFTER): wait for - * completion of writeout of all pages in the range. This will be used after an - * earlier SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE operation to wait - * for that operation to complete and to return the result. - * - * SYNC_FILE_RANGE_WAIT_BEFORE|SYNC_FILE_RANGE_WRITE|SYNC_FILE_RANGE_WAIT_AFTER: - * a traditional sync() operation. This is a write-for-data-integrity operation - * which will ensure that all pages in the range which were dirty on entry to - * sys_sync_file_range() are committed to disk. - * - * - * SYNC_FILE_RANGE_WAIT_BEFORE and SYNC_FILE_RANGE_WAIT_AFTER will detect any - * I/O errors or ENOSPC conditions and will return those to the caller, after - * clearing the EIO and ENOSPC flags in the address_space. - * - * It should be noted that none of these operations write out the file's - * metadata. So unless the application is strictly performing overwrites of - * already-instantiated disk blocks, there are no guarantees here that the data - * will be available after a crash. - */ -SYSCALL_DEFINE4(sync_file_range, int, fd, loff_t, offset, loff_t, nbytes, - unsigned int, flags) -{ - int ret; - struct fd f; - struct address_space *mapping; - loff_t endbyte; /* inclusive */ - umode_t i_mode; - - ret = -EINVAL; - if (flags & ~VALID_FLAGS) - goto out; - - endbyte = offset + nbytes; - - if ((s64)offset < 0) - goto out; - if ((s64)endbyte < 0) - goto out; - if (endbyte < offset) - goto out; - - if (sizeof(pgoff_t) == 4) { - if (offset >= (0x100000000ULL << PAGE_SHIFT)) { - /* - * The range starts outside a 32 bit machine's - * pagecache addressing capabilities. Let it "succeed" - */ - ret = 0; - goto out; - } - if (endbyte >= (0x100000000ULL << PAGE_SHIFT)) { - /* - * Out to EOF - */ - nbytes = 0; - } - } - - if (nbytes == 0) - endbyte = LLONG_MAX; - else - endbyte--; /* inclusive */ - - ret = -EBADF; - f = fdget(fd); - if (!f.file) - goto out; - - i_mode = file_inode(f.file)->i_mode; - ret = -ESPIPE; - if (!S_ISREG(i_mode) && !S_ISBLK(i_mode) && !S_ISDIR(i_mode) && - !S_ISLNK(i_mode)) - goto out_put; - - mapping = f.file->f_mapping; - if (!mapping) { - ret = -EINVAL; - goto out_put; - } - - ret = 0; - if (flags & SYNC_FILE_RANGE_WAIT_BEFORE) { - ret = filemap_fdatawait_range(mapping, offset, endbyte); - if (ret < 0) - goto out_put; - } - - if (flags & SYNC_FILE_RANGE_WRITE) { - ret = __filemap_fdatawrite_range(mapping, offset, endbyte, - WB_SYNC_NONE); - if (ret < 0) - goto out_put; - } - - if (flags & SYNC_FILE_RANGE_WAIT_AFTER) - ret = filemap_fdatawait_range(mapping, offset, endbyte); - -out_put: - fdput(f); -out: - return ret; -} - -/* It would be nice if people remember that not all the world's an i386 - when they introduce new system calls */ -SYSCALL_DEFINE4(sync_file_range2, int, fd, unsigned int, flags, - loff_t, offset, loff_t, nbytes) -{ - return sys_sync_file_range(fd, offset, nbytes, flags); -} diff --git a/src/linux/fs/sysfs/Kconfig b/src/linux/fs/sysfs/Kconfig deleted file mode 100644 index b275601..0000000 --- a/src/linux/fs/sysfs/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -config SYSFS - bool "sysfs file system support" if EXPERT - default y - select KERNFS - help - The sysfs filesystem is a virtual filesystem that the kernel uses to - export internal kernel objects, their attributes, and their - relationships to one another. - - Users can use sysfs to ascertain useful information about the running - kernel, such as the devices the kernel has discovered on each bus and - which driver each is bound to. sysfs can also be used to tune devices - and other kernel subsystems. - - Some system agents rely on the information in sysfs to operate. - /sbin/hotplug uses device and object attributes in sysfs to assist in - delegating policy decisions, like persistently naming devices. - - sysfs is currently used by the block subsystem to mount the root - partition. If sysfs is disabled you must specify the boot device on - the kernel boot command line via its major and minor numbers. For - example, "root=03:01" for /dev/hda1. - - Designers of embedded systems may wish to say N here to conserve space. diff --git a/src/linux/fs/sysfs/Makefile b/src/linux/fs/sysfs/Makefile deleted file mode 100644 index 6eff6e1..0000000 --- a/src/linux/fs/sysfs/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# -# Makefile for the sysfs virtual filesystem -# - -obj-y := file.o dir.o symlink.o mount.o group.o diff --git a/src/linux/fs/sysfs/dir.c b/src/linux/fs/sysfs/dir.c deleted file mode 100644 index 2b67bda..0000000 --- a/src/linux/fs/sysfs/dir.c +++ /dev/null @@ -1,157 +0,0 @@ -/* - * fs/sysfs/dir.c - sysfs core and dir operation implementation - * - * Copyright (c) 2001-3 Patrick Mochel - * Copyright (c) 2007 SUSE Linux Products GmbH - * Copyright (c) 2007 Tejun Heo - * - * This file is released under the GPLv2. - * - * Please see Documentation/filesystems/sysfs.txt for more information. - */ - -#undef DEBUG - -#include -#include -#include -#include "sysfs.h" - -DEFINE_SPINLOCK(sysfs_symlink_target_lock); - -void sysfs_warn_dup(struct kernfs_node *parent, const char *name) -{ - char *buf; - - buf = kzalloc(PATH_MAX, GFP_KERNEL); - if (buf) - kernfs_path(parent, buf, PATH_MAX); - - WARN(1, KERN_WARNING "sysfs: cannot create duplicate filename '%s/%s'\n", - buf, name); - - kfree(buf); -} - -/** - * sysfs_create_dir_ns - create a directory for an object with a namespace tag - * @kobj: object we're creating directory for - * @ns: the namespace tag to use - */ -int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) -{ - struct kernfs_node *parent, *kn; - - BUG_ON(!kobj); - - if (kobj->parent) - parent = kobj->parent->sd; - else - parent = sysfs_root_kn; - - if (!parent) - return -ENOENT; - - kn = kernfs_create_dir_ns(parent, kobject_name(kobj), - S_IRWXU | S_IRUGO | S_IXUGO, kobj, ns); - if (IS_ERR(kn)) { - if (PTR_ERR(kn) == -EEXIST) - sysfs_warn_dup(parent, kobject_name(kobj)); - return PTR_ERR(kn); - } - - kobj->sd = kn; - return 0; -} - -/** - * sysfs_remove_dir - remove an object's directory. - * @kobj: object. - * - * The only thing special about this is that we remove any files in - * the directory before we remove the directory, and we've inlined - * what used to be sysfs_rmdir() below, instead of calling separately. - */ -void sysfs_remove_dir(struct kobject *kobj) -{ - struct kernfs_node *kn = kobj->sd; - - /* - * In general, kboject owner is responsible for ensuring removal - * doesn't race with other operations and sysfs doesn't provide any - * protection; however, when @kobj is used as a symlink target, the - * symlinking entity usually doesn't own @kobj and thus has no - * control over removal. @kobj->sd may be removed anytime - * and symlink code may end up dereferencing an already freed node. - * - * sysfs_symlink_target_lock synchronizes @kobj->sd - * disassociation against symlink operations so that symlink code - * can safely dereference @kobj->sd. - */ - spin_lock(&sysfs_symlink_target_lock); - kobj->sd = NULL; - spin_unlock(&sysfs_symlink_target_lock); - - if (kn) { - WARN_ON_ONCE(kernfs_type(kn) != KERNFS_DIR); - kernfs_remove(kn); - } -} - -int sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, - const void *new_ns) -{ - struct kernfs_node *parent; - int ret; - - parent = kernfs_get_parent(kobj->sd); - ret = kernfs_rename_ns(kobj->sd, parent, new_name, new_ns); - kernfs_put(parent); - return ret; -} - -int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, - const void *new_ns) -{ - struct kernfs_node *kn = kobj->sd; - struct kernfs_node *new_parent; - - new_parent = new_parent_kobj && new_parent_kobj->sd ? - new_parent_kobj->sd : sysfs_root_kn; - - return kernfs_rename_ns(kn, new_parent, kn->name, new_ns); -} - -/** - * sysfs_create_mount_point - create an always empty directory - * @parent_kobj: kobject that will contain this always empty directory - * @name: The name of the always empty directory to add - */ -int sysfs_create_mount_point(struct kobject *parent_kobj, const char *name) -{ - struct kernfs_node *kn, *parent = parent_kobj->sd; - - kn = kernfs_create_empty_dir(parent, name); - if (IS_ERR(kn)) { - if (PTR_ERR(kn) == -EEXIST) - sysfs_warn_dup(parent, name); - return PTR_ERR(kn); - } - - return 0; -} -EXPORT_SYMBOL_GPL(sysfs_create_mount_point); - -/** - * sysfs_remove_mount_point - remove an always empty directory. - * @parent_kobj: kobject that will contain this always empty directory - * @name: The name of the always empty directory to remove - * - */ -void sysfs_remove_mount_point(struct kobject *parent_kobj, const char *name) -{ - struct kernfs_node *parent = parent_kobj->sd; - - kernfs_remove_by_name_ns(parent, name, NULL); -} -EXPORT_SYMBOL_GPL(sysfs_remove_mount_point); diff --git a/src/linux/fs/sysfs/file.c b/src/linux/fs/sysfs/file.c deleted file mode 100644 index b803213..0000000 --- a/src/linux/fs/sysfs/file.c +++ /dev/null @@ -1,505 +0,0 @@ -/* - * fs/sysfs/file.c - sysfs regular (text) file implementation - * - * Copyright (c) 2001-3 Patrick Mochel - * Copyright (c) 2007 SUSE Linux Products GmbH - * Copyright (c) 2007 Tejun Heo - * - * This file is released under the GPLv2. - * - * Please see Documentation/filesystems/sysfs.txt for more information. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "sysfs.h" -#include "../kernfs/kernfs-internal.h" - -/* - * Determine ktype->sysfs_ops for the given kernfs_node. This function - * must be called while holding an active reference. - */ -static const struct sysfs_ops *sysfs_file_ops(struct kernfs_node *kn) -{ - struct kobject *kobj = kn->parent->priv; - - if (kn->flags & KERNFS_LOCKDEP) - lockdep_assert_held(kn); - return kobj->ktype ? kobj->ktype->sysfs_ops : NULL; -} - -/* - * Reads on sysfs are handled through seq_file, which takes care of hairy - * details like buffering and seeking. The following function pipes - * sysfs_ops->show() result through seq_file. - */ -static int sysfs_kf_seq_show(struct seq_file *sf, void *v) -{ - struct kernfs_open_file *of = sf->private; - struct kobject *kobj = of->kn->parent->priv; - const struct sysfs_ops *ops = sysfs_file_ops(of->kn); - ssize_t count; - char *buf; - - /* acquire buffer and ensure that it's >= PAGE_SIZE and clear */ - count = seq_get_buf(sf, &buf); - if (count < PAGE_SIZE) { - seq_commit(sf, -1); - return 0; - } - memset(buf, 0, PAGE_SIZE); - - /* - * Invoke show(). Control may reach here via seq file lseek even - * if @ops->show() isn't implemented. - */ - if (ops->show) { - count = ops->show(kobj, of->kn->priv, buf); - if (count < 0) - return count; - } - - /* - * The code works fine with PAGE_SIZE return but it's likely to - * indicate truncated result or overflow in normal use cases. - */ - if (count >= (ssize_t)PAGE_SIZE) { - print_symbol("fill_read_buffer: %s returned bad count\n", - (unsigned long)ops->show); - /* Try to struggle along */ - count = PAGE_SIZE - 1; - } - seq_commit(sf, count); - return 0; -} - -static ssize_t sysfs_kf_bin_read(struct kernfs_open_file *of, char *buf, - size_t count, loff_t pos) -{ - struct bin_attribute *battr = of->kn->priv; - struct kobject *kobj = of->kn->parent->priv; - loff_t size = file_inode(of->file)->i_size; - - if (!count) - return 0; - - if (size) { - if (pos >= size) - return 0; - if (pos + count > size) - count = size - pos; - } - - if (!battr->read) - return -EIO; - - return battr->read(of->file, kobj, battr, buf, pos, count); -} - -/* kernfs read callback for regular sysfs files with pre-alloc */ -static ssize_t sysfs_kf_read(struct kernfs_open_file *of, char *buf, - size_t count, loff_t pos) -{ - const struct sysfs_ops *ops = sysfs_file_ops(of->kn); - struct kobject *kobj = of->kn->parent->priv; - size_t len; - - /* - * If buf != of->prealloc_buf, we don't know how - * large it is, so cannot safely pass it to ->show - */ - if (WARN_ON_ONCE(buf != of->prealloc_buf)) - return 0; - len = ops->show(kobj, of->kn->priv, buf); - if (pos) { - if (len <= pos) - return 0; - len -= pos; - memmove(buf, buf + pos, len); - } - return min(count, len); -} - -/* kernfs write callback for regular sysfs files */ -static ssize_t sysfs_kf_write(struct kernfs_open_file *of, char *buf, - size_t count, loff_t pos) -{ - const struct sysfs_ops *ops = sysfs_file_ops(of->kn); - struct kobject *kobj = of->kn->parent->priv; - - if (!count) - return 0; - - return ops->store(kobj, of->kn->priv, buf, count); -} - -/* kernfs write callback for bin sysfs files */ -static ssize_t sysfs_kf_bin_write(struct kernfs_open_file *of, char *buf, - size_t count, loff_t pos) -{ - struct bin_attribute *battr = of->kn->priv; - struct kobject *kobj = of->kn->parent->priv; - loff_t size = file_inode(of->file)->i_size; - - if (size) { - if (size <= pos) - return -EFBIG; - count = min_t(ssize_t, count, size - pos); - } - if (!count) - return 0; - - if (!battr->write) - return -EIO; - - return battr->write(of->file, kobj, battr, buf, pos, count); -} - -static int sysfs_kf_bin_mmap(struct kernfs_open_file *of, - struct vm_area_struct *vma) -{ - struct bin_attribute *battr = of->kn->priv; - struct kobject *kobj = of->kn->parent->priv; - - return battr->mmap(of->file, kobj, battr, vma); -} - -void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr) -{ - struct kernfs_node *kn = kobj->sd, *tmp; - - if (kn && dir) - kn = kernfs_find_and_get(kn, dir); - else - kernfs_get(kn); - - if (kn && attr) { - tmp = kernfs_find_and_get(kn, attr); - kernfs_put(kn); - kn = tmp; - } - - if (kn) { - kernfs_notify(kn); - kernfs_put(kn); - } -} -EXPORT_SYMBOL_GPL(sysfs_notify); - -static const struct kernfs_ops sysfs_file_kfops_empty = { -}; - -static const struct kernfs_ops sysfs_file_kfops_ro = { - .seq_show = sysfs_kf_seq_show, -}; - -static const struct kernfs_ops sysfs_file_kfops_wo = { - .write = sysfs_kf_write, -}; - -static const struct kernfs_ops sysfs_file_kfops_rw = { - .seq_show = sysfs_kf_seq_show, - .write = sysfs_kf_write, -}; - -static const struct kernfs_ops sysfs_prealloc_kfops_ro = { - .read = sysfs_kf_read, - .prealloc = true, -}; - -static const struct kernfs_ops sysfs_prealloc_kfops_wo = { - .write = sysfs_kf_write, - .prealloc = true, -}; - -static const struct kernfs_ops sysfs_prealloc_kfops_rw = { - .read = sysfs_kf_read, - .write = sysfs_kf_write, - .prealloc = true, -}; - -static const struct kernfs_ops sysfs_bin_kfops_ro = { - .read = sysfs_kf_bin_read, -}; - -static const struct kernfs_ops sysfs_bin_kfops_wo = { - .write = sysfs_kf_bin_write, -}; - -static const struct kernfs_ops sysfs_bin_kfops_rw = { - .read = sysfs_kf_bin_read, - .write = sysfs_kf_bin_write, -}; - -static const struct kernfs_ops sysfs_bin_kfops_mmap = { - .read = sysfs_kf_bin_read, - .write = sysfs_kf_bin_write, - .mmap = sysfs_kf_bin_mmap, -}; - -int sysfs_add_file_mode_ns(struct kernfs_node *parent, - const struct attribute *attr, bool is_bin, - umode_t mode, const void *ns) -{ - struct lock_class_key *key = NULL; - const struct kernfs_ops *ops; - struct kernfs_node *kn; - loff_t size; - - if (!is_bin) { - struct kobject *kobj = parent->priv; - const struct sysfs_ops *sysfs_ops = kobj->ktype->sysfs_ops; - - /* every kobject with an attribute needs a ktype assigned */ - if (WARN(!sysfs_ops, KERN_ERR - "missing sysfs attribute operations for kobject: %s\n", - kobject_name(kobj))) - return -EINVAL; - - if (sysfs_ops->show && sysfs_ops->store) { - if (mode & SYSFS_PREALLOC) - ops = &sysfs_prealloc_kfops_rw; - else - ops = &sysfs_file_kfops_rw; - } else if (sysfs_ops->show) { - if (mode & SYSFS_PREALLOC) - ops = &sysfs_prealloc_kfops_ro; - else - ops = &sysfs_file_kfops_ro; - } else if (sysfs_ops->store) { - if (mode & SYSFS_PREALLOC) - ops = &sysfs_prealloc_kfops_wo; - else - ops = &sysfs_file_kfops_wo; - } else - ops = &sysfs_file_kfops_empty; - - size = PAGE_SIZE; - } else { - struct bin_attribute *battr = (void *)attr; - - if (battr->mmap) - ops = &sysfs_bin_kfops_mmap; - else if (battr->read && battr->write) - ops = &sysfs_bin_kfops_rw; - else if (battr->read) - ops = &sysfs_bin_kfops_ro; - else if (battr->write) - ops = &sysfs_bin_kfops_wo; - else - ops = &sysfs_file_kfops_empty; - - size = battr->size; - } - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - if (!attr->ignore_lockdep) - key = attr->key ?: (struct lock_class_key *)&attr->skey; -#endif - kn = __kernfs_create_file(parent, attr->name, mode & 0777, size, ops, - (void *)attr, ns, key); - if (IS_ERR(kn)) { - if (PTR_ERR(kn) == -EEXIST) - sysfs_warn_dup(parent, attr->name); - return PTR_ERR(kn); - } - return 0; -} - -int sysfs_add_file(struct kernfs_node *parent, const struct attribute *attr, - bool is_bin) -{ - return sysfs_add_file_mode_ns(parent, attr, is_bin, attr->mode, NULL); -} - -/** - * sysfs_create_file_ns - create an attribute file for an object with custom ns - * @kobj: object we're creating for - * @attr: attribute descriptor - * @ns: namespace the new file should belong to - */ -int sysfs_create_file_ns(struct kobject *kobj, const struct attribute *attr, - const void *ns) -{ - BUG_ON(!kobj || !kobj->sd || !attr); - - return sysfs_add_file_mode_ns(kobj->sd, attr, false, attr->mode, ns); - -} -EXPORT_SYMBOL_GPL(sysfs_create_file_ns); - -int sysfs_create_files(struct kobject *kobj, const struct attribute **ptr) -{ - int err = 0; - int i; - - for (i = 0; ptr[i] && !err; i++) - err = sysfs_create_file(kobj, ptr[i]); - if (err) - while (--i >= 0) - sysfs_remove_file(kobj, ptr[i]); - return err; -} -EXPORT_SYMBOL_GPL(sysfs_create_files); - -/** - * sysfs_add_file_to_group - add an attribute file to a pre-existing group. - * @kobj: object we're acting for. - * @attr: attribute descriptor. - * @group: group name. - */ -int sysfs_add_file_to_group(struct kobject *kobj, - const struct attribute *attr, const char *group) -{ - struct kernfs_node *parent; - int error; - - if (group) { - parent = kernfs_find_and_get(kobj->sd, group); - } else { - parent = kobj->sd; - kernfs_get(parent); - } - - if (!parent) - return -ENOENT; - - error = sysfs_add_file(parent, attr, false); - kernfs_put(parent); - - return error; -} -EXPORT_SYMBOL_GPL(sysfs_add_file_to_group); - -/** - * sysfs_chmod_file - update the modified mode value on an object attribute. - * @kobj: object we're acting for. - * @attr: attribute descriptor. - * @mode: file permissions. - * - */ -int sysfs_chmod_file(struct kobject *kobj, const struct attribute *attr, - umode_t mode) -{ - struct kernfs_node *kn; - struct iattr newattrs; - int rc; - - kn = kernfs_find_and_get(kobj->sd, attr->name); - if (!kn) - return -ENOENT; - - newattrs.ia_mode = (mode & S_IALLUGO) | (kn->mode & ~S_IALLUGO); - newattrs.ia_valid = ATTR_MODE; - - rc = kernfs_setattr(kn, &newattrs); - - kernfs_put(kn); - return rc; -} -EXPORT_SYMBOL_GPL(sysfs_chmod_file); - -/** - * sysfs_remove_file_ns - remove an object attribute with a custom ns tag - * @kobj: object we're acting for - * @attr: attribute descriptor - * @ns: namespace tag of the file to remove - * - * Hash the attribute name and namespace tag and kill the victim. - */ -void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr, - const void *ns) -{ - struct kernfs_node *parent = kobj->sd; - - kernfs_remove_by_name_ns(parent, attr->name, ns); -} -EXPORT_SYMBOL_GPL(sysfs_remove_file_ns); - -/** - * sysfs_remove_file_self - remove an object attribute from its own method - * @kobj: object we're acting for - * @attr: attribute descriptor - * - * See kernfs_remove_self() for details. - */ -bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr) -{ - struct kernfs_node *parent = kobj->sd; - struct kernfs_node *kn; - bool ret; - - kn = kernfs_find_and_get(parent, attr->name); - if (WARN_ON_ONCE(!kn)) - return false; - - ret = kernfs_remove_self(kn); - - kernfs_put(kn); - return ret; -} - -void sysfs_remove_files(struct kobject *kobj, const struct attribute **ptr) -{ - int i; - for (i = 0; ptr[i]; i++) - sysfs_remove_file(kobj, ptr[i]); -} -EXPORT_SYMBOL_GPL(sysfs_remove_files); - -/** - * sysfs_remove_file_from_group - remove an attribute file from a group. - * @kobj: object we're acting for. - * @attr: attribute descriptor. - * @group: group name. - */ -void sysfs_remove_file_from_group(struct kobject *kobj, - const struct attribute *attr, const char *group) -{ - struct kernfs_node *parent; - - if (group) { - parent = kernfs_find_and_get(kobj->sd, group); - } else { - parent = kobj->sd; - kernfs_get(parent); - } - - if (parent) { - kernfs_remove_by_name(parent, attr->name); - kernfs_put(parent); - } -} -EXPORT_SYMBOL_GPL(sysfs_remove_file_from_group); - -/** - * sysfs_create_bin_file - create binary file for object. - * @kobj: object. - * @attr: attribute descriptor. - */ -int sysfs_create_bin_file(struct kobject *kobj, - const struct bin_attribute *attr) -{ - BUG_ON(!kobj || !kobj->sd || !attr); - - return sysfs_add_file(kobj->sd, &attr->attr, true); -} -EXPORT_SYMBOL_GPL(sysfs_create_bin_file); - -/** - * sysfs_remove_bin_file - remove binary file for object. - * @kobj: object. - * @attr: attribute descriptor. - */ -void sysfs_remove_bin_file(struct kobject *kobj, - const struct bin_attribute *attr) -{ - kernfs_remove_by_name(kobj->sd, attr->attr.name); -} -EXPORT_SYMBOL_GPL(sysfs_remove_bin_file); diff --git a/src/linux/fs/sysfs/group.c b/src/linux/fs/sysfs/group.c deleted file mode 100644 index ac2de0e..0000000 --- a/src/linux/fs/sysfs/group.c +++ /dev/null @@ -1,411 +0,0 @@ -/* - * fs/sysfs/group.c - Operations for adding/removing multiple files at once. - * - * Copyright (c) 2003 Patrick Mochel - * Copyright (c) 2003 Open Source Development Lab - * Copyright (c) 2013 Greg Kroah-Hartman - * Copyright (c) 2013 The Linux Foundation - * - * This file is released undert the GPL v2. - * - */ - -#include -#include -#include -#include -#include -#include "sysfs.h" - - -static void remove_files(struct kernfs_node *parent, - const struct attribute_group *grp) -{ - struct attribute *const *attr; - struct bin_attribute *const *bin_attr; - - if (grp->attrs) - for (attr = grp->attrs; *attr; attr++) - kernfs_remove_by_name(parent, (*attr)->name); - if (grp->bin_attrs) - for (bin_attr = grp->bin_attrs; *bin_attr; bin_attr++) - kernfs_remove_by_name(parent, (*bin_attr)->attr.name); -} - -static int create_files(struct kernfs_node *parent, struct kobject *kobj, - const struct attribute_group *grp, int update) -{ - struct attribute *const *attr; - struct bin_attribute *const *bin_attr; - int error = 0, i; - - if (grp->attrs) { - for (i = 0, attr = grp->attrs; *attr && !error; i++, attr++) { - umode_t mode = (*attr)->mode; - - /* - * In update mode, we're changing the permissions or - * visibility. Do this by first removing then - * re-adding (if required) the file. - */ - if (update) - kernfs_remove_by_name(parent, (*attr)->name); - if (grp->is_visible) { - mode = grp->is_visible(kobj, *attr, i); - if (!mode) - continue; - } - - WARN(mode & ~(SYSFS_PREALLOC | 0664), - "Attribute %s: Invalid permissions 0%o\n", - (*attr)->name, mode); - - mode &= SYSFS_PREALLOC | 0664; - error = sysfs_add_file_mode_ns(parent, *attr, false, - mode, NULL); - if (unlikely(error)) - break; - } - if (error) { - remove_files(parent, grp); - goto exit; - } - } - - if (grp->bin_attrs) { - for (i = 0, bin_attr = grp->bin_attrs; *bin_attr; i++, bin_attr++) { - umode_t mode = (*bin_attr)->attr.mode; - - if (update) - kernfs_remove_by_name(parent, - (*bin_attr)->attr.name); - if (grp->is_bin_visible) { - mode = grp->is_bin_visible(kobj, *bin_attr, i); - if (!mode) - continue; - } - - WARN(mode & ~(SYSFS_PREALLOC | 0664), - "Attribute %s: Invalid permissions 0%o\n", - (*bin_attr)->attr.name, mode); - - mode &= SYSFS_PREALLOC | 0664; - error = sysfs_add_file_mode_ns(parent, - &(*bin_attr)->attr, true, - mode, NULL); - if (error) - break; - } - if (error) - remove_files(parent, grp); - } -exit: - return error; -} - - -static int internal_create_group(struct kobject *kobj, int update, - const struct attribute_group *grp) -{ - struct kernfs_node *kn; - int error; - - BUG_ON(!kobj || (!update && !kobj->sd)); - - /* Updates may happen before the object has been instantiated */ - if (unlikely(update && !kobj->sd)) - return -EINVAL; - if (!grp->attrs && !grp->bin_attrs) { - WARN(1, "sysfs: (bin_)attrs not set by subsystem for group: %s/%s\n", - kobj->name, grp->name ?: ""); - return -EINVAL; - } - if (grp->name) { - kn = kernfs_create_dir(kobj->sd, grp->name, - S_IRWXU | S_IRUGO | S_IXUGO, kobj); - if (IS_ERR(kn)) { - if (PTR_ERR(kn) == -EEXIST) - sysfs_warn_dup(kobj->sd, grp->name); - return PTR_ERR(kn); - } - } else - kn = kobj->sd; - kernfs_get(kn); - error = create_files(kn, kobj, grp, update); - if (error) { - if (grp->name) - kernfs_remove(kn); - } - kernfs_put(kn); - return error; -} - -/** - * sysfs_create_group - given a directory kobject, create an attribute group - * @kobj: The kobject to create the group on - * @grp: The attribute group to create - * - * This function creates a group for the first time. It will explicitly - * warn and error if any of the attribute files being created already exist. - * - * Returns 0 on success or error code on failure. - */ -int sysfs_create_group(struct kobject *kobj, - const struct attribute_group *grp) -{ - return internal_create_group(kobj, 0, grp); -} -EXPORT_SYMBOL_GPL(sysfs_create_group); - -/** - * sysfs_create_groups - given a directory kobject, create a bunch of attribute groups - * @kobj: The kobject to create the group on - * @groups: The attribute groups to create, NULL terminated - * - * This function creates a bunch of attribute groups. If an error occurs when - * creating a group, all previously created groups will be removed, unwinding - * everything back to the original state when this function was called. - * It will explicitly warn and error if any of the attribute files being - * created already exist. - * - * Returns 0 on success or error code from sysfs_create_group on failure. - */ -int sysfs_create_groups(struct kobject *kobj, - const struct attribute_group **groups) -{ - int error = 0; - int i; - - if (!groups) - return 0; - - for (i = 0; groups[i]; i++) { - error = sysfs_create_group(kobj, groups[i]); - if (error) { - while (--i >= 0) - sysfs_remove_group(kobj, groups[i]); - break; - } - } - return error; -} -EXPORT_SYMBOL_GPL(sysfs_create_groups); - -/** - * sysfs_update_group - given a directory kobject, update an attribute group - * @kobj: The kobject to update the group on - * @grp: The attribute group to update - * - * This function updates an attribute group. Unlike - * sysfs_create_group(), it will explicitly not warn or error if any - * of the attribute files being created already exist. Furthermore, - * if the visibility of the files has changed through the is_visible() - * callback, it will update the permissions and add or remove the - * relevant files. - * - * The primary use for this function is to call it after making a change - * that affects group visibility. - * - * Returns 0 on success or error code on failure. - */ -int sysfs_update_group(struct kobject *kobj, - const struct attribute_group *grp) -{ - return internal_create_group(kobj, 1, grp); -} -EXPORT_SYMBOL_GPL(sysfs_update_group); - -/** - * sysfs_remove_group: remove a group from a kobject - * @kobj: kobject to remove the group from - * @grp: group to remove - * - * This function removes a group of attributes from a kobject. The attributes - * previously have to have been created for this group, otherwise it will fail. - */ -void sysfs_remove_group(struct kobject *kobj, - const struct attribute_group *grp) -{ - struct kernfs_node *parent = kobj->sd; - struct kernfs_node *kn; - - if (grp->name) { - kn = kernfs_find_and_get(parent, grp->name); - if (!kn) { - WARN(!kn, KERN_WARNING - "sysfs group '%s' not found for kobject '%s'\n", - grp->name, kobject_name(kobj)); - return; - } - } else { - kn = parent; - kernfs_get(kn); - } - - remove_files(kn, grp); - if (grp->name) - kernfs_remove(kn); - - kernfs_put(kn); -} -EXPORT_SYMBOL_GPL(sysfs_remove_group); - -/** - * sysfs_remove_groups - remove a list of groups - * - * @kobj: The kobject for the groups to be removed from - * @groups: NULL terminated list of groups to be removed - * - * If groups is not NULL, remove the specified groups from the kobject. - */ -void sysfs_remove_groups(struct kobject *kobj, - const struct attribute_group **groups) -{ - int i; - - if (!groups) - return; - for (i = 0; groups[i]; i++) - sysfs_remove_group(kobj, groups[i]); -} -EXPORT_SYMBOL_GPL(sysfs_remove_groups); - -/** - * sysfs_merge_group - merge files into a pre-existing attribute group. - * @kobj: The kobject containing the group. - * @grp: The files to create and the attribute group they belong to. - * - * This function returns an error if the group doesn't exist or any of the - * files already exist in that group, in which case none of the new files - * are created. - */ -int sysfs_merge_group(struct kobject *kobj, - const struct attribute_group *grp) -{ - struct kernfs_node *parent; - int error = 0; - struct attribute *const *attr; - int i; - - parent = kernfs_find_and_get(kobj->sd, grp->name); - if (!parent) - return -ENOENT; - - for ((i = 0, attr = grp->attrs); *attr && !error; (++i, ++attr)) - error = sysfs_add_file(parent, *attr, false); - if (error) { - while (--i >= 0) - kernfs_remove_by_name(parent, (*--attr)->name); - } - kernfs_put(parent); - - return error; -} -EXPORT_SYMBOL_GPL(sysfs_merge_group); - -/** - * sysfs_unmerge_group - remove files from a pre-existing attribute group. - * @kobj: The kobject containing the group. - * @grp: The files to remove and the attribute group they belong to. - */ -void sysfs_unmerge_group(struct kobject *kobj, - const struct attribute_group *grp) -{ - struct kernfs_node *parent; - struct attribute *const *attr; - - parent = kernfs_find_and_get(kobj->sd, grp->name); - if (parent) { - for (attr = grp->attrs; *attr; ++attr) - kernfs_remove_by_name(parent, (*attr)->name); - kernfs_put(parent); - } -} -EXPORT_SYMBOL_GPL(sysfs_unmerge_group); - -/** - * sysfs_add_link_to_group - add a symlink to an attribute group. - * @kobj: The kobject containing the group. - * @group_name: The name of the group. - * @target: The target kobject of the symlink to create. - * @link_name: The name of the symlink to create. - */ -int sysfs_add_link_to_group(struct kobject *kobj, const char *group_name, - struct kobject *target, const char *link_name) -{ - struct kernfs_node *parent; - int error = 0; - - parent = kernfs_find_and_get(kobj->sd, group_name); - if (!parent) - return -ENOENT; - - error = sysfs_create_link_sd(parent, target, link_name); - kernfs_put(parent); - - return error; -} -EXPORT_SYMBOL_GPL(sysfs_add_link_to_group); - -/** - * sysfs_remove_link_from_group - remove a symlink from an attribute group. - * @kobj: The kobject containing the group. - * @group_name: The name of the group. - * @link_name: The name of the symlink to remove. - */ -void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name, - const char *link_name) -{ - struct kernfs_node *parent; - - parent = kernfs_find_and_get(kobj->sd, group_name); - if (parent) { - kernfs_remove_by_name(parent, link_name); - kernfs_put(parent); - } -} -EXPORT_SYMBOL_GPL(sysfs_remove_link_from_group); - -/** - * __compat_only_sysfs_link_entry_to_kobj - add a symlink to a kobject pointing - * to a group or an attribute - * @kobj: The kobject containing the group. - * @target_kobj: The target kobject. - * @target_name: The name of the target group or attribute. - */ -int __compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj, - struct kobject *target_kobj, - const char *target_name) -{ - struct kernfs_node *target; - struct kernfs_node *entry; - struct kernfs_node *link; - - /* - * We don't own @target_kobj and it may be removed at any time. - * Synchronize using sysfs_symlink_target_lock. See sysfs_remove_dir() - * for details. - */ - spin_lock(&sysfs_symlink_target_lock); - target = target_kobj->sd; - if (target) - kernfs_get(target); - spin_unlock(&sysfs_symlink_target_lock); - if (!target) - return -ENOENT; - - entry = kernfs_find_and_get(target_kobj->sd, target_name); - if (!entry) { - kernfs_put(target); - return -ENOENT; - } - - link = kernfs_create_link(kobj->sd, target_name, entry); - if (IS_ERR(link) && PTR_ERR(link) == -EEXIST) - sysfs_warn_dup(kobj->sd, target_name); - - kernfs_put(entry); - kernfs_put(target); - return IS_ERR(link) ? PTR_ERR(link) : 0; -} -EXPORT_SYMBOL_GPL(__compat_only_sysfs_link_entry_to_kobj); diff --git a/src/linux/fs/sysfs/mount.c b/src/linux/fs/sysfs/mount.c deleted file mode 100644 index 20b8f82..0000000 --- a/src/linux/fs/sysfs/mount.c +++ /dev/null @@ -1,82 +0,0 @@ -/* - * fs/sysfs/symlink.c - operations for initializing and mounting sysfs - * - * Copyright (c) 2001-3 Patrick Mochel - * Copyright (c) 2007 SUSE Linux Products GmbH - * Copyright (c) 2007 Tejun Heo - * - * This file is released under the GPLv2. - * - * Please see Documentation/filesystems/sysfs.txt for more information. - */ - -#define DEBUG - -#include -#include -#include -#include -#include - -#include "sysfs.h" - -static struct kernfs_root *sysfs_root; -struct kernfs_node *sysfs_root_kn; - -static struct dentry *sysfs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - struct dentry *root; - void *ns; - bool new_sb; - - if (!(flags & MS_KERNMOUNT)) { - if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET)) - return ERR_PTR(-EPERM); - } - - ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); - root = kernfs_mount_ns(fs_type, flags, sysfs_root, - SYSFS_MAGIC, &new_sb, ns); - if (IS_ERR(root) || !new_sb) - kobj_ns_drop(KOBJ_NS_TYPE_NET, ns); - else if (new_sb) - root->d_sb->s_iflags |= SB_I_USERNS_VISIBLE; - - return root; -} - -static void sysfs_kill_sb(struct super_block *sb) -{ - void *ns = (void *)kernfs_super_ns(sb); - - kernfs_kill_sb(sb); - kobj_ns_drop(KOBJ_NS_TYPE_NET, ns); -} - -static struct file_system_type sysfs_fs_type = { - .name = "sysfs", - .mount = sysfs_mount, - .kill_sb = sysfs_kill_sb, - .fs_flags = FS_USERNS_MOUNT, -}; - -int __init sysfs_init(void) -{ - int err; - - sysfs_root = kernfs_create_root(NULL, KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK, - NULL); - if (IS_ERR(sysfs_root)) - return PTR_ERR(sysfs_root); - - sysfs_root_kn = sysfs_root->kn; - - err = register_filesystem(&sysfs_fs_type); - if (err) { - kernfs_destroy_root(sysfs_root); - return err; - } - - return 0; -} diff --git a/src/linux/fs/sysfs/symlink.c b/src/linux/fs/sysfs/symlink.c deleted file mode 100644 index aecb15f..0000000 --- a/src/linux/fs/sysfs/symlink.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * fs/sysfs/symlink.c - sysfs symlink implementation - * - * Copyright (c) 2001-3 Patrick Mochel - * Copyright (c) 2007 SUSE Linux Products GmbH - * Copyright (c) 2007 Tejun Heo - * - * This file is released under the GPLv2. - * - * Please see Documentation/filesystems/sysfs.txt for more information. - */ - -#include -#include -#include -#include -#include - -#include "sysfs.h" - -static int sysfs_do_create_link_sd(struct kernfs_node *parent, - struct kobject *target_kobj, - const char *name, int warn) -{ - struct kernfs_node *kn, *target = NULL; - - BUG_ON(!name || !parent); - - /* - * We don't own @target_kobj and it may be removed at any time. - * Synchronize using sysfs_symlink_target_lock. See - * sysfs_remove_dir() for details. - */ - spin_lock(&sysfs_symlink_target_lock); - if (target_kobj->sd) { - target = target_kobj->sd; - kernfs_get(target); - } - spin_unlock(&sysfs_symlink_target_lock); - - if (!target) - return -ENOENT; - - kn = kernfs_create_link(parent, name, target); - kernfs_put(target); - - if (!IS_ERR(kn)) - return 0; - - if (warn && PTR_ERR(kn) == -EEXIST) - sysfs_warn_dup(parent, name); - return PTR_ERR(kn); -} - -/** - * sysfs_create_link_sd - create symlink to a given object. - * @kn: directory we're creating the link in. - * @target: object we're pointing to. - * @name: name of the symlink. - */ -int sysfs_create_link_sd(struct kernfs_node *kn, struct kobject *target, - const char *name) -{ - return sysfs_do_create_link_sd(kn, target, name, 1); -} - -static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target, - const char *name, int warn) -{ - struct kernfs_node *parent = NULL; - - if (!kobj) - parent = sysfs_root_kn; - else - parent = kobj->sd; - - if (!parent) - return -EFAULT; - - return sysfs_do_create_link_sd(parent, target, name, warn); -} - -/** - * sysfs_create_link - create symlink between two objects. - * @kobj: object whose directory we're creating the link in. - * @target: object we're pointing to. - * @name: name of the symlink. - */ -int sysfs_create_link(struct kobject *kobj, struct kobject *target, - const char *name) -{ - return sysfs_do_create_link(kobj, target, name, 1); -} -EXPORT_SYMBOL_GPL(sysfs_create_link); - -/** - * sysfs_create_link_nowarn - create symlink between two objects. - * @kobj: object whose directory we're creating the link in. - * @target: object we're pointing to. - * @name: name of the symlink. - * - * This function does the same as sysfs_create_link(), but it - * doesn't warn if the link already exists. - */ -int sysfs_create_link_nowarn(struct kobject *kobj, struct kobject *target, - const char *name) -{ - return sysfs_do_create_link(kobj, target, name, 0); -} - -/** - * sysfs_delete_link - remove symlink in object's directory. - * @kobj: object we're acting for. - * @targ: object we're pointing to. - * @name: name of the symlink to remove. - * - * Unlike sysfs_remove_link sysfs_delete_link has enough information - * to successfully delete symlinks in tagged directories. - */ -void sysfs_delete_link(struct kobject *kobj, struct kobject *targ, - const char *name) -{ - const void *ns = NULL; - - /* - * We don't own @target and it may be removed at any time. - * Synchronize using sysfs_symlink_target_lock. See - * sysfs_remove_dir() for details. - */ - spin_lock(&sysfs_symlink_target_lock); - if (targ->sd && kernfs_ns_enabled(kobj->sd)) - ns = targ->sd->ns; - spin_unlock(&sysfs_symlink_target_lock); - kernfs_remove_by_name_ns(kobj->sd, name, ns); -} - -/** - * sysfs_remove_link - remove symlink in object's directory. - * @kobj: object we're acting for. - * @name: name of the symlink to remove. - */ -void sysfs_remove_link(struct kobject *kobj, const char *name) -{ - struct kernfs_node *parent = NULL; - - if (!kobj) - parent = sysfs_root_kn; - else - parent = kobj->sd; - - kernfs_remove_by_name(parent, name); -} -EXPORT_SYMBOL_GPL(sysfs_remove_link); - -/** - * sysfs_rename_link_ns - rename symlink in object's directory. - * @kobj: object we're acting for. - * @targ: object we're pointing to. - * @old: previous name of the symlink. - * @new: new name of the symlink. - * @new_ns: new namespace of the symlink. - * - * A helper function for the common rename symlink idiom. - */ -int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ, - const char *old, const char *new, const void *new_ns) -{ - struct kernfs_node *parent, *kn = NULL; - const void *old_ns = NULL; - int result; - - if (!kobj) - parent = sysfs_root_kn; - else - parent = kobj->sd; - - if (targ->sd) - old_ns = targ->sd->ns; - - result = -ENOENT; - kn = kernfs_find_and_get_ns(parent, old, old_ns); - if (!kn) - goto out; - - result = -EINVAL; - if (kernfs_type(kn) != KERNFS_LINK) - goto out; - if (kn->symlink.target_kn->priv != targ) - goto out; - - result = kernfs_rename_ns(kn, parent, new, new_ns); - -out: - kernfs_put(kn); - return result; -} -EXPORT_SYMBOL_GPL(sysfs_rename_link_ns); diff --git a/src/linux/fs/sysfs/sysfs.h b/src/linux/fs/sysfs/sysfs.h deleted file mode 100644 index 0e2f1cc..0000000 --- a/src/linux/fs/sysfs/sysfs.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * fs/sysfs/sysfs.h - sysfs internal header file - * - * Copyright (c) 2001-3 Patrick Mochel - * Copyright (c) 2007 SUSE Linux Products GmbH - * Copyright (c) 2007 Tejun Heo - * - * This file is released under the GPLv2. - */ - -#ifndef __SYSFS_INTERNAL_H -#define __SYSFS_INTERNAL_H - -#include - -/* - * mount.c - */ -extern struct kernfs_node *sysfs_root_kn; - -/* - * dir.c - */ -extern spinlock_t sysfs_symlink_target_lock; - -void sysfs_warn_dup(struct kernfs_node *parent, const char *name); - -/* - * file.c - */ -int sysfs_add_file(struct kernfs_node *parent, - const struct attribute *attr, bool is_bin); -int sysfs_add_file_mode_ns(struct kernfs_node *parent, - const struct attribute *attr, bool is_bin, - umode_t amode, const void *ns); - -/* - * symlink.c - */ -int sysfs_create_link_sd(struct kernfs_node *kn, struct kobject *target, - const char *name); - -#endif /* __SYSFS_INTERNAL_H */ diff --git a/src/linux/fs/sysv/Kconfig b/src/linux/fs/sysv/Kconfig deleted file mode 100644 index 33aeb4b..0000000 --- a/src/linux/fs/sysv/Kconfig +++ /dev/null @@ -1,36 +0,0 @@ -config SYSV_FS - tristate "System V/Xenix/V7/Coherent file system support" - depends on BLOCK - help - SCO, Xenix and Coherent are commercial Unix systems for Intel - machines, and Version 7 was used on the DEC PDP-11. Saying Y - here would allow you to read from their floppies and hard disk - partitions. - - If you have floppies or hard disk partitions like that, it is likely - that they contain binaries from those other Unix systems; in order - to run these binaries, you will want to install linux-abi which is - a set of kernel modules that lets you run SCO, Xenix, Wyse, - UnixWare, Dell Unix and System V programs under Linux. It is - available via FTP (user: ftp) from - ). - NOTE: that will work only for binaries from Intel-based systems; - PDP ones will have to wait until somebody ports Linux to -11 ;-) - - If you only intend to mount files from some other Unix over the - network using NFS, you don't need the System V file system support - (but you need NFS file system support obviously). - - Note that this option is generally not needed for floppies, since a - good portable way to transport files and directories between unixes - (and even other operating systems) is given by the tar program ("man - tar" or preferably "info tar"). Note also that this option has - nothing whatsoever to do with the option "System V IPC". Read about - the System V file system in - . - Saying Y here will enlarge your kernel by about 27 KB. - - To compile this as a module, choose M here: the module will be called - sysv. - - If you haven't heard about all of this before, it's safe to say N. diff --git a/src/linux/fs/ubifs/Kconfig b/src/linux/fs/ubifs/Kconfig deleted file mode 100644 index 7ff7712..0000000 --- a/src/linux/fs/ubifs/Kconfig +++ /dev/null @@ -1,52 +0,0 @@ -config UBIFS_FS - tristate "UBIFS file system support" - select CRC16 - select CRC32 - select CRYPTO if UBIFS_FS_ADVANCED_COMPR - select CRYPTO if UBIFS_FS_LZO - select CRYPTO if UBIFS_FS_ZLIB - select CRYPTO_LZO if UBIFS_FS_LZO - select CRYPTO_DEFLATE if UBIFS_FS_ZLIB - depends on MTD_UBI - help - UBIFS is a file system for flash devices which works on top of UBI. - -config UBIFS_FS_ADVANCED_COMPR - bool "Advanced compression options" - depends on UBIFS_FS - help - This option allows to explicitly choose which compressions, if any, - are enabled in UBIFS. Removing compressors means inability to read - existing file systems. - - If unsure, say 'N'. - -config UBIFS_FS_LZO - bool "LZO compression support" if UBIFS_FS_ADVANCED_COMPR - depends on UBIFS_FS - default y - help - LZO compressor is generally faster than zlib but compresses worse. - Say 'Y' if unsure. - -config UBIFS_FS_ZLIB - bool "ZLIB compression support" if UBIFS_FS_ADVANCED_COMPR - depends on UBIFS_FS - default y - help - Zlib compresses better than LZO but it is slower. Say 'Y' if unsure. - -config UBIFS_ATIME_SUPPORT - bool "Access time support" if UBIFS_FS - depends on UBIFS_FS - default n - help - Originally UBIFS did not support atime, because it looked like a bad idea due - increased flash wear. This option adds atime support and it is disabled by default - to preserve the old behavior. If you enable this option, UBIFS starts updating atime, - which means that file-system read operations will cause writes (inode atime - updates). This may affect file-system performance and increase flash device wear, - so be careful. How often atime is updated depends on the selected strategy: - strictatime is the "heavy", relatime is "lighter", etc. - - If unsure, say 'N' diff --git a/src/linux/fs/udf/Kconfig b/src/linux/fs/udf/Kconfig deleted file mode 100644 index c6e17a7..0000000 --- a/src/linux/fs/udf/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -config UDF_FS - tristate "UDF file system support" - select CRC_ITU_T - help - This is a file system used on some CD-ROMs and DVDs. Since the - file system is supported by multiple operating systems and is more - compatible with standard unix file systems, it is also suitable for - removable USB disks. Say Y if you intend to mount DVD discs or CDRW's - written in packet mode, or if you want to use UDF for removable USB - disks. Please read . - - To compile this file system support as a module, choose M here: the - module will be called udf. - - If unsure, say N. - -config UDF_NLS - bool - default y - depends on (UDF_FS=m && NLS) || (UDF_FS=y && NLS=y) diff --git a/src/linux/fs/ufs/Kconfig b/src/linux/fs/ufs/Kconfig deleted file mode 100644 index 0bf6e16..0000000 --- a/src/linux/fs/ufs/Kconfig +++ /dev/null @@ -1,43 +0,0 @@ -config UFS_FS - tristate "UFS file system support (read only)" - depends on BLOCK - help - BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD, - OpenBSD and NeXTstep) use a file system called UFS. Some System V - Unixes can create and mount hard disk partitions and diskettes using - this file system as well. Saying Y here will allow you to read from - these partitions; if you also want to write to them, say Y to the - experimental "UFS file system write support", below. Please read the - file for more information. - - The recently released UFS2 variant (used in FreeBSD 5.x) is - READ-ONLY supported. - - Note that this option is generally not needed for floppies, since a - good portable way to transport files and directories between unixes - (and even other operating systems) is given by the tar program ("man - tar" or preferably "info tar"). - - When accessing NeXTstep files, you may need to convert them from the - NeXT character set to the Latin1 character set; use the program - recode ("info recode") for this purpose. - - To compile the UFS file system support as a module, choose M here: the - module will be called ufs. - - If you haven't heard about all of this before, it's safe to say N. - -config UFS_FS_WRITE - bool "UFS file system write support (DANGEROUS)" - depends on UFS_FS - help - Say Y here if you want to try writing to UFS partitions. This is - experimental, so you should back up your UFS partitions beforehand. - -config UFS_DEBUG - bool "UFS debugging" - depends on UFS_FS - help - If you are experiencing any problems with the UFS filesystem, say - Y here. This will result in _many_ additional debugging messages to be - written to the system log. diff --git a/src/linux/fs/utimes.c b/src/linux/fs/utimes.c deleted file mode 100644 index 22307cd..0000000 --- a/src/linux/fs/utimes.c +++ /dev/null @@ -1,221 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __ARCH_WANT_SYS_UTIME - -/* - * sys_utime() can be implemented in user-level using sys_utimes(). - * Is this for backwards compatibility? If so, why not move it - * into the appropriate arch directory (for those architectures that - * need it). - */ - -/* If times==NULL, set access and modification to current time, - * must be owner or have write permission. - * Else, update from *times, must be owner or super user. - */ -SYSCALL_DEFINE2(utime, char __user *, filename, struct utimbuf __user *, times) -{ - struct timespec tv[2]; - - if (times) { - if (get_user(tv[0].tv_sec, ×->actime) || - get_user(tv[1].tv_sec, ×->modtime)) - return -EFAULT; - tv[0].tv_nsec = 0; - tv[1].tv_nsec = 0; - } - return do_utimes(AT_FDCWD, filename, times ? tv : NULL, 0); -} - -#endif - -static bool nsec_valid(long nsec) -{ - if (nsec == UTIME_OMIT || nsec == UTIME_NOW) - return true; - - return nsec >= 0 && nsec <= 999999999; -} - -static int utimes_common(struct path *path, struct timespec *times) -{ - int error; - struct iattr newattrs; - struct inode *inode = path->dentry->d_inode; - struct inode *delegated_inode = NULL; - - error = mnt_want_write(path->mnt); - if (error) - goto out; - - if (times && times[0].tv_nsec == UTIME_NOW && - times[1].tv_nsec == UTIME_NOW) - times = NULL; - - newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME; - if (times) { - if (times[0].tv_nsec == UTIME_OMIT) - newattrs.ia_valid &= ~ATTR_ATIME; - else if (times[0].tv_nsec != UTIME_NOW) { - newattrs.ia_atime.tv_sec = times[0].tv_sec; - newattrs.ia_atime.tv_nsec = times[0].tv_nsec; - newattrs.ia_valid |= ATTR_ATIME_SET; - } - - if (times[1].tv_nsec == UTIME_OMIT) - newattrs.ia_valid &= ~ATTR_MTIME; - else if (times[1].tv_nsec != UTIME_NOW) { - newattrs.ia_mtime.tv_sec = times[1].tv_sec; - newattrs.ia_mtime.tv_nsec = times[1].tv_nsec; - newattrs.ia_valid |= ATTR_MTIME_SET; - } - /* - * Tell setattr_prepare(), that this is an explicit time - * update, even if neither ATTR_ATIME_SET nor ATTR_MTIME_SET - * were used. - */ - newattrs.ia_valid |= ATTR_TIMES_SET; - } else { - newattrs.ia_valid |= ATTR_TOUCH; - } -retry_deleg: - inode_lock(inode); - error = notify_change(path->dentry, &newattrs, &delegated_inode); - inode_unlock(inode); - if (delegated_inode) { - error = break_deleg_wait(&delegated_inode); - if (!error) - goto retry_deleg; - } - - mnt_drop_write(path->mnt); -out: - return error; -} - -/* - * do_utimes - change times on filename or file descriptor - * @dfd: open file descriptor, -1 or AT_FDCWD - * @filename: path name or NULL - * @times: new times or NULL - * @flags: zero or more flags (only AT_SYMLINK_NOFOLLOW for the moment) - * - * If filename is NULL and dfd refers to an open file, then operate on - * the file. Otherwise look up filename, possibly using dfd as a - * starting point. - * - * If times==NULL, set access and modification to current time, - * must be owner or have write permission. - * Else, update from *times, must be owner or super user. - */ -long do_utimes(int dfd, const char __user *filename, struct timespec *times, - int flags) -{ - int error = -EINVAL; - - if (times && (!nsec_valid(times[0].tv_nsec) || - !nsec_valid(times[1].tv_nsec))) { - goto out; - } - - if (flags & ~AT_SYMLINK_NOFOLLOW) - goto out; - - if (filename == NULL && dfd != AT_FDCWD) { - struct fd f; - - if (flags & AT_SYMLINK_NOFOLLOW) - goto out; - - f = fdget(dfd); - error = -EBADF; - if (!f.file) - goto out; - - error = utimes_common(&f.file->f_path, times); - fdput(f); - } else { - struct path path; - int lookup_flags = 0; - - if (!(flags & AT_SYMLINK_NOFOLLOW)) - lookup_flags |= LOOKUP_FOLLOW; -retry: - error = user_path_at(dfd, filename, lookup_flags, &path); - if (error) - goto out; - - error = utimes_common(&path, times); - path_put(&path); - if (retry_estale(error, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - goto retry; - } - } - -out: - return error; -} - -SYSCALL_DEFINE4(utimensat, int, dfd, const char __user *, filename, - struct timespec __user *, utimes, int, flags) -{ - struct timespec tstimes[2]; - - if (utimes) { - if (copy_from_user(&tstimes, utimes, sizeof(tstimes))) - return -EFAULT; - - /* Nothing to do, we must not even check the path. */ - if (tstimes[0].tv_nsec == UTIME_OMIT && - tstimes[1].tv_nsec == UTIME_OMIT) - return 0; - } - - return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags); -} - -SYSCALL_DEFINE3(futimesat, int, dfd, const char __user *, filename, - struct timeval __user *, utimes) -{ - struct timeval times[2]; - struct timespec tstimes[2]; - - if (utimes) { - if (copy_from_user(×, utimes, sizeof(times))) - return -EFAULT; - - /* This test is needed to catch all invalid values. If we - would test only in do_utimes we would miss those invalid - values truncated by the multiplication with 1000. Note - that we also catch UTIME_{NOW,OMIT} here which are only - valid for utimensat. */ - if (times[0].tv_usec >= 1000000 || times[0].tv_usec < 0 || - times[1].tv_usec >= 1000000 || times[1].tv_usec < 0) - return -EINVAL; - - tstimes[0].tv_sec = times[0].tv_sec; - tstimes[0].tv_nsec = 1000 * times[0].tv_usec; - tstimes[1].tv_sec = times[1].tv_sec; - tstimes[1].tv_nsec = 1000 * times[1].tv_usec; - } - - return do_utimes(dfd, filename, utimes ? tstimes : NULL, 0); -} - -SYSCALL_DEFINE2(utimes, char __user *, filename, - struct timeval __user *, utimes) -{ - return sys_futimesat(AT_FDCWD, filename, utimes); -} diff --git a/src/linux/fs/xattr.c b/src/linux/fs/xattr.c deleted file mode 100644 index 2d13b4e..0000000 --- a/src/linux/fs/xattr.c +++ /dev/null @@ -1,994 +0,0 @@ -/* - File: fs/xattr.c - - Extended attribute handling. - - Copyright (C) 2001 by Andreas Gruenbacher - Copyright (C) 2001 SGI - Silicon Graphics, Inc - Copyright (c) 2004 Red Hat, Inc., James Morris - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -static const char * -strcmp_prefix(const char *a, const char *a_prefix) -{ - while (*a_prefix && *a == *a_prefix) { - a++; - a_prefix++; - } - return *a_prefix ? NULL : a; -} - -/* - * In order to implement different sets of xattr operations for each xattr - * prefix, a filesystem should create a null-terminated array of struct - * xattr_handler (one for each prefix) and hang a pointer to it off of the - * s_xattr field of the superblock. - */ -#define for_each_xattr_handler(handlers, handler) \ - if (handlers) \ - for ((handler) = *(handlers)++; \ - (handler) != NULL; \ - (handler) = *(handlers)++) - -/* - * Find the xattr_handler with the matching prefix. - */ -static const struct xattr_handler * -xattr_resolve_name(struct inode *inode, const char **name) -{ - const struct xattr_handler **handlers = inode->i_sb->s_xattr; - const struct xattr_handler *handler; - - if (!(inode->i_opflags & IOP_XATTR)) { - if (unlikely(is_bad_inode(inode))) - return ERR_PTR(-EIO); - return ERR_PTR(-EOPNOTSUPP); - } - for_each_xattr_handler(handlers, handler) { - const char *n; - - n = strcmp_prefix(*name, xattr_prefix(handler)); - if (n) { - if (!handler->prefix ^ !*n) { - if (*n) - continue; - return ERR_PTR(-EINVAL); - } - *name = n; - return handler; - } - } - return ERR_PTR(-EOPNOTSUPP); -} - -/* - * Check permissions for extended attribute access. This is a bit complicated - * because different namespaces have very different rules. - */ -static int -xattr_permission(struct inode *inode, const char *name, int mask) -{ - /* - * We can never set or remove an extended attribute on a read-only - * filesystem or on an immutable / append-only inode. - */ - if (mask & MAY_WRITE) { - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - return -EPERM; - /* - * Updating an xattr will likely cause i_uid and i_gid - * to be writen back improperly if their true value is - * unknown to the vfs. - */ - if (HAS_UNMAPPED_ID(inode)) - return -EPERM; - } - - /* - * No restriction for security.* and system.* from the VFS. Decision - * on these is left to the underlying filesystem / security module. - */ - if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) || - !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) - return 0; - - /* - * The trusted.* namespace can only be accessed by privileged users. - */ - if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) { - if (!capable(CAP_SYS_ADMIN)) - return (mask & MAY_WRITE) ? -EPERM : -ENODATA; - return 0; - } - - /* - * In the user.* namespace, only regular files and directories can have - * extended attributes. For sticky directories, only the owner and - * privileged users can write attributes. - */ - if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) { - if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode)) - return (mask & MAY_WRITE) ? -EPERM : -ENODATA; - if (S_ISDIR(inode->i_mode) && (inode->i_mode & S_ISVTX) && - (mask & MAY_WRITE) && !inode_owner_or_capable(inode)) - return -EPERM; - } - - return inode_permission(inode, mask); -} - -int -__vfs_setxattr(struct dentry *dentry, struct inode *inode, const char *name, - const void *value, size_t size, int flags) -{ - const struct xattr_handler *handler; - - handler = xattr_resolve_name(inode, &name); - if (IS_ERR(handler)) - return PTR_ERR(handler); - if (!handler->set) - return -EOPNOTSUPP; - if (size == 0) - value = ""; /* empty EA, do not remove */ - return handler->set(handler, dentry, inode, name, value, size, flags); -} -EXPORT_SYMBOL(__vfs_setxattr); - -/** - * __vfs_setxattr_noperm - perform setxattr operation without performing - * permission checks. - * - * @dentry - object to perform setxattr on - * @name - xattr name to set - * @value - value to set @name to - * @size - size of @value - * @flags - flags to pass into filesystem operations - * - * returns the result of the internal setxattr or setsecurity operations. - * - * This function requires the caller to lock the inode's i_mutex before it - * is executed. It also assumes that the caller will make the appropriate - * permission checks. - */ -int __vfs_setxattr_noperm(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags) -{ - struct inode *inode = dentry->d_inode; - int error = -EAGAIN; - int issec = !strncmp(name, XATTR_SECURITY_PREFIX, - XATTR_SECURITY_PREFIX_LEN); - - if (issec) - inode->i_flags &= ~S_NOSEC; - if (inode->i_opflags & IOP_XATTR) { - error = __vfs_setxattr(dentry, inode, name, value, size, flags); - if (!error) { - fsnotify_xattr(dentry); - security_inode_post_setxattr(dentry, name, value, - size, flags); - } - } else { - if (unlikely(is_bad_inode(inode))) - return -EIO; - } - if (error == -EAGAIN) { - error = -EOPNOTSUPP; - - if (issec) { - const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; - - error = security_inode_setsecurity(inode, suffix, value, - size, flags); - if (!error) - fsnotify_xattr(dentry); - } - } - - return error; -} - - -int -vfs_setxattr(struct dentry *dentry, const char *name, const void *value, - size_t size, int flags) -{ - struct inode *inode = dentry->d_inode; - int error; - - error = xattr_permission(inode, name, MAY_WRITE); - if (error) - return error; - - inode_lock(inode); - error = security_inode_setxattr(dentry, name, value, size, flags); - if (error) - goto out; - - error = __vfs_setxattr_noperm(dentry, name, value, size, flags); - -out: - inode_unlock(inode); - return error; -} -EXPORT_SYMBOL_GPL(vfs_setxattr); - -ssize_t -xattr_getsecurity(struct inode *inode, const char *name, void *value, - size_t size) -{ - void *buffer = NULL; - ssize_t len; - - if (!value || !size) { - len = security_inode_getsecurity(inode, name, &buffer, false); - goto out_noalloc; - } - - len = security_inode_getsecurity(inode, name, &buffer, true); - if (len < 0) - return len; - if (size < len) { - len = -ERANGE; - goto out; - } - memcpy(value, buffer, len); -out: - security_release_secctx(buffer, len); -out_noalloc: - return len; -} -EXPORT_SYMBOL_GPL(xattr_getsecurity); - -/* - * vfs_getxattr_alloc - allocate memory, if necessary, before calling getxattr - * - * Allocate memory, if not already allocated, or re-allocate correct size, - * before retrieving the extended attribute. - * - * Returns the result of alloc, if failed, or the getxattr operation. - */ -ssize_t -vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value, - size_t xattr_size, gfp_t flags) -{ - const struct xattr_handler *handler; - struct inode *inode = dentry->d_inode; - char *value = *xattr_value; - int error; - - error = xattr_permission(inode, name, MAY_READ); - if (error) - return error; - - handler = xattr_resolve_name(inode, &name); - if (IS_ERR(handler)) - return PTR_ERR(handler); - if (!handler->get) - return -EOPNOTSUPP; - error = handler->get(handler, dentry, inode, name, NULL, 0); - if (error < 0) - return error; - - if (!value || (error > xattr_size)) { - value = krealloc(*xattr_value, error + 1, flags); - if (!value) - return -ENOMEM; - memset(value, 0, error + 1); - } - - error = handler->get(handler, dentry, inode, name, value, error); - *xattr_value = value; - return error; -} - -ssize_t -__vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name, - void *value, size_t size) -{ - const struct xattr_handler *handler; - - handler = xattr_resolve_name(inode, &name); - if (IS_ERR(handler)) - return PTR_ERR(handler); - if (!handler->get) - return -EOPNOTSUPP; - return handler->get(handler, dentry, inode, name, value, size); -} -EXPORT_SYMBOL(__vfs_getxattr); - -ssize_t -vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) -{ - struct inode *inode = dentry->d_inode; - int error; - - error = xattr_permission(inode, name, MAY_READ); - if (error) - return error; - - error = security_inode_getxattr(dentry, name); - if (error) - return error; - - if (!strncmp(name, XATTR_SECURITY_PREFIX, - XATTR_SECURITY_PREFIX_LEN)) { - const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; - int ret = xattr_getsecurity(inode, suffix, value, size); - /* - * Only overwrite the return value if a security module - * is actually active. - */ - if (ret == -EOPNOTSUPP) - goto nolsm; - return ret; - } -nolsm: - return __vfs_getxattr(dentry, inode, name, value, size); -} -EXPORT_SYMBOL_GPL(vfs_getxattr); - -ssize_t -vfs_listxattr(struct dentry *dentry, char *list, size_t size) -{ - struct inode *inode = d_inode(dentry); - ssize_t error; - - error = security_inode_listxattr(dentry); - if (error) - return error; - if (inode->i_op->listxattr && (inode->i_opflags & IOP_XATTR)) { - error = -EOPNOTSUPP; - error = inode->i_op->listxattr(dentry, list, size); - } else { - error = security_inode_listsecurity(inode, list, size); - if (size && error > size) - error = -ERANGE; - } - return error; -} -EXPORT_SYMBOL_GPL(vfs_listxattr); - -int -__vfs_removexattr(struct dentry *dentry, const char *name) -{ - struct inode *inode = d_inode(dentry); - const struct xattr_handler *handler; - - handler = xattr_resolve_name(inode, &name); - if (IS_ERR(handler)) - return PTR_ERR(handler); - if (!handler->set) - return -EOPNOTSUPP; - return handler->set(handler, dentry, inode, name, NULL, 0, XATTR_REPLACE); -} -EXPORT_SYMBOL(__vfs_removexattr); - -int -vfs_removexattr(struct dentry *dentry, const char *name) -{ - struct inode *inode = dentry->d_inode; - int error; - - error = xattr_permission(inode, name, MAY_WRITE); - if (error) - return error; - - inode_lock(inode); - error = security_inode_removexattr(dentry, name); - if (error) - goto out; - - error = __vfs_removexattr(dentry, name); - - if (!error) { - fsnotify_xattr(dentry); - evm_inode_post_removexattr(dentry, name); - } - -out: - inode_unlock(inode); - return error; -} -EXPORT_SYMBOL_GPL(vfs_removexattr); - - -/* - * Extended attribute SET operations - */ -static long -setxattr(struct dentry *d, const char __user *name, const void __user *value, - size_t size, int flags) -{ - int error; - void *kvalue = NULL; - char kname[XATTR_NAME_MAX + 1]; - - if (flags & ~(XATTR_CREATE|XATTR_REPLACE)) - return -EINVAL; - - error = strncpy_from_user(kname, name, sizeof(kname)); - if (error == 0 || error == sizeof(kname)) - error = -ERANGE; - if (error < 0) - return error; - - if (size) { - if (size > XATTR_SIZE_MAX) - return -E2BIG; - kvalue = kmalloc(size, GFP_KERNEL | __GFP_NOWARN); - if (!kvalue) { - kvalue = vmalloc(size); - if (!kvalue) - return -ENOMEM; - } - if (copy_from_user(kvalue, value, size)) { - error = -EFAULT; - goto out; - } - if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) || - (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0)) - posix_acl_fix_xattr_from_user(kvalue, size); - } - - error = vfs_setxattr(d, kname, kvalue, size, flags); -out: - kvfree(kvalue); - - return error; -} - -static int path_setxattr(const char __user *pathname, - const char __user *name, const void __user *value, - size_t size, int flags, unsigned int lookup_flags) -{ - struct path path; - int error; -retry: - error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path); - if (error) - return error; - error = mnt_want_write(path.mnt); - if (!error) { - error = setxattr(path.dentry, name, value, size, flags); - mnt_drop_write(path.mnt); - } - path_put(&path); - if (retry_estale(error, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - goto retry; - } - return error; -} - -SYSCALL_DEFINE5(setxattr, const char __user *, pathname, - const char __user *, name, const void __user *, value, - size_t, size, int, flags) -{ - return path_setxattr(pathname, name, value, size, flags, LOOKUP_FOLLOW); -} - -SYSCALL_DEFINE5(lsetxattr, const char __user *, pathname, - const char __user *, name, const void __user *, value, - size_t, size, int, flags) -{ - return path_setxattr(pathname, name, value, size, flags, 0); -} - -SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name, - const void __user *,value, size_t, size, int, flags) -{ - struct fd f = fdget(fd); - int error = -EBADF; - - if (!f.file) - return error; - audit_file(f.file); - error = mnt_want_write_file(f.file); - if (!error) { - error = setxattr(f.file->f_path.dentry, name, value, size, flags); - mnt_drop_write_file(f.file); - } - fdput(f); - return error; -} - -/* - * Extended attribute GET operations - */ -static ssize_t -getxattr(struct dentry *d, const char __user *name, void __user *value, - size_t size) -{ - ssize_t error; - void *kvalue = NULL; - char kname[XATTR_NAME_MAX + 1]; - - error = strncpy_from_user(kname, name, sizeof(kname)); - if (error == 0 || error == sizeof(kname)) - error = -ERANGE; - if (error < 0) - return error; - - if (size) { - if (size > XATTR_SIZE_MAX) - size = XATTR_SIZE_MAX; - kvalue = kzalloc(size, GFP_KERNEL | __GFP_NOWARN); - if (!kvalue) { - kvalue = vmalloc(size); - if (!kvalue) - return -ENOMEM; - } - } - - error = vfs_getxattr(d, kname, kvalue, size); - if (error > 0) { - if ((strcmp(kname, XATTR_NAME_POSIX_ACL_ACCESS) == 0) || - (strcmp(kname, XATTR_NAME_POSIX_ACL_DEFAULT) == 0)) - posix_acl_fix_xattr_to_user(kvalue, size); - if (size && copy_to_user(value, kvalue, error)) - error = -EFAULT; - } else if (error == -ERANGE && size >= XATTR_SIZE_MAX) { - /* The file system tried to returned a value bigger - than XATTR_SIZE_MAX bytes. Not possible. */ - error = -E2BIG; - } - - kvfree(kvalue); - - return error; -} - -static ssize_t path_getxattr(const char __user *pathname, - const char __user *name, void __user *value, - size_t size, unsigned int lookup_flags) -{ - struct path path; - ssize_t error; -retry: - error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path); - if (error) - return error; - error = getxattr(path.dentry, name, value, size); - path_put(&path); - if (retry_estale(error, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - goto retry; - } - return error; -} - -SYSCALL_DEFINE4(getxattr, const char __user *, pathname, - const char __user *, name, void __user *, value, size_t, size) -{ - return path_getxattr(pathname, name, value, size, LOOKUP_FOLLOW); -} - -SYSCALL_DEFINE4(lgetxattr, const char __user *, pathname, - const char __user *, name, void __user *, value, size_t, size) -{ - return path_getxattr(pathname, name, value, size, 0); -} - -SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name, - void __user *, value, size_t, size) -{ - struct fd f = fdget(fd); - ssize_t error = -EBADF; - - if (!f.file) - return error; - audit_file(f.file); - error = getxattr(f.file->f_path.dentry, name, value, size); - fdput(f); - return error; -} - -/* - * Extended attribute LIST operations - */ -static ssize_t -listxattr(struct dentry *d, char __user *list, size_t size) -{ - ssize_t error; - char *klist = NULL; - - if (size) { - if (size > XATTR_LIST_MAX) - size = XATTR_LIST_MAX; - klist = kmalloc(size, __GFP_NOWARN | GFP_KERNEL); - if (!klist) { - klist = vmalloc(size); - if (!klist) - return -ENOMEM; - } - } - - error = vfs_listxattr(d, klist, size); - if (error > 0) { - if (size && copy_to_user(list, klist, error)) - error = -EFAULT; - } else if (error == -ERANGE && size >= XATTR_LIST_MAX) { - /* The file system tried to returned a list bigger - than XATTR_LIST_MAX bytes. Not possible. */ - error = -E2BIG; - } - - kvfree(klist); - - return error; -} - -static ssize_t path_listxattr(const char __user *pathname, char __user *list, - size_t size, unsigned int lookup_flags) -{ - struct path path; - ssize_t error; -retry: - error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path); - if (error) - return error; - error = listxattr(path.dentry, list, size); - path_put(&path); - if (retry_estale(error, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - goto retry; - } - return error; -} - -SYSCALL_DEFINE3(listxattr, const char __user *, pathname, char __user *, list, - size_t, size) -{ - return path_listxattr(pathname, list, size, LOOKUP_FOLLOW); -} - -SYSCALL_DEFINE3(llistxattr, const char __user *, pathname, char __user *, list, - size_t, size) -{ - return path_listxattr(pathname, list, size, 0); -} - -SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size) -{ - struct fd f = fdget(fd); - ssize_t error = -EBADF; - - if (!f.file) - return error; - audit_file(f.file); - error = listxattr(f.file->f_path.dentry, list, size); - fdput(f); - return error; -} - -/* - * Extended attribute REMOVE operations - */ -static long -removexattr(struct dentry *d, const char __user *name) -{ - int error; - char kname[XATTR_NAME_MAX + 1]; - - error = strncpy_from_user(kname, name, sizeof(kname)); - if (error == 0 || error == sizeof(kname)) - error = -ERANGE; - if (error < 0) - return error; - - return vfs_removexattr(d, kname); -} - -static int path_removexattr(const char __user *pathname, - const char __user *name, unsigned int lookup_flags) -{ - struct path path; - int error; -retry: - error = user_path_at(AT_FDCWD, pathname, lookup_flags, &path); - if (error) - return error; - error = mnt_want_write(path.mnt); - if (!error) { - error = removexattr(path.dentry, name); - mnt_drop_write(path.mnt); - } - path_put(&path); - if (retry_estale(error, lookup_flags)) { - lookup_flags |= LOOKUP_REVAL; - goto retry; - } - return error; -} - -SYSCALL_DEFINE2(removexattr, const char __user *, pathname, - const char __user *, name) -{ - return path_removexattr(pathname, name, LOOKUP_FOLLOW); -} - -SYSCALL_DEFINE2(lremovexattr, const char __user *, pathname, - const char __user *, name) -{ - return path_removexattr(pathname, name, 0); -} - -SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name) -{ - struct fd f = fdget(fd); - int error = -EBADF; - - if (!f.file) - return error; - audit_file(f.file); - error = mnt_want_write_file(f.file); - if (!error) { - error = removexattr(f.file->f_path.dentry, name); - mnt_drop_write_file(f.file); - } - fdput(f); - return error; -} - -/* - * Combine the results of the list() operation from every xattr_handler in the - * list. - */ -ssize_t -generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) -{ - const struct xattr_handler *handler, **handlers = dentry->d_sb->s_xattr; - unsigned int size = 0; - - if (!buffer) { - for_each_xattr_handler(handlers, handler) { - if (!handler->name || - (handler->list && !handler->list(dentry))) - continue; - size += strlen(handler->name) + 1; - } - } else { - char *buf = buffer; - size_t len; - - for_each_xattr_handler(handlers, handler) { - if (!handler->name || - (handler->list && !handler->list(dentry))) - continue; - len = strlen(handler->name); - if (len + 1 > buffer_size) - return -ERANGE; - memcpy(buf, handler->name, len + 1); - buf += len + 1; - buffer_size -= len + 1; - } - size = buf - buffer; - } - return size; -} -EXPORT_SYMBOL(generic_listxattr); - -/** - * xattr_full_name - Compute full attribute name from suffix - * - * @handler: handler of the xattr_handler operation - * @name: name passed to the xattr_handler operation - * - * The get and set xattr handler operations are called with the remainder of - * the attribute name after skipping the handler's prefix: for example, "foo" - * is passed to the get operation of a handler with prefix "user." to get - * attribute "user.foo". The full name is still "there" in the name though. - * - * Note: the list xattr handler operation when called from the vfs is passed a - * NULL name; some file systems use this operation internally, with varying - * semantics. - */ -const char *xattr_full_name(const struct xattr_handler *handler, - const char *name) -{ - size_t prefix_len = strlen(xattr_prefix(handler)); - - return name - prefix_len; -} -EXPORT_SYMBOL(xattr_full_name); - -/* - * Allocate new xattr and copy in the value; but leave the name to callers. - */ -struct simple_xattr *simple_xattr_alloc(const void *value, size_t size) -{ - struct simple_xattr *new_xattr; - size_t len; - - /* wrap around? */ - len = sizeof(*new_xattr) + size; - if (len < sizeof(*new_xattr)) - return NULL; - - new_xattr = kmalloc(len, GFP_KERNEL); - if (!new_xattr) - return NULL; - - new_xattr->size = size; - memcpy(new_xattr->value, value, size); - return new_xattr; -} - -/* - * xattr GET operation for in-memory/pseudo filesystems - */ -int simple_xattr_get(struct simple_xattrs *xattrs, const char *name, - void *buffer, size_t size) -{ - struct simple_xattr *xattr; - int ret = -ENODATA; - - spin_lock(&xattrs->lock); - list_for_each_entry(xattr, &xattrs->head, list) { - if (strcmp(name, xattr->name)) - continue; - - ret = xattr->size; - if (buffer) { - if (size < xattr->size) - ret = -ERANGE; - else - memcpy(buffer, xattr->value, xattr->size); - } - break; - } - spin_unlock(&xattrs->lock); - return ret; -} - -/** - * simple_xattr_set - xattr SET operation for in-memory/pseudo filesystems - * @xattrs: target simple_xattr list - * @name: name of the extended attribute - * @value: value of the xattr. If %NULL, will remove the attribute. - * @size: size of the new xattr - * @flags: %XATTR_{CREATE|REPLACE} - * - * %XATTR_CREATE is set, the xattr shouldn't exist already; otherwise fails - * with -EEXIST. If %XATTR_REPLACE is set, the xattr should exist; - * otherwise, fails with -ENODATA. - * - * Returns 0 on success, -errno on failure. - */ -int simple_xattr_set(struct simple_xattrs *xattrs, const char *name, - const void *value, size_t size, int flags) -{ - struct simple_xattr *xattr; - struct simple_xattr *new_xattr = NULL; - int err = 0; - - /* value == NULL means remove */ - if (value) { - new_xattr = simple_xattr_alloc(value, size); - if (!new_xattr) - return -ENOMEM; - - new_xattr->name = kstrdup(name, GFP_KERNEL); - if (!new_xattr->name) { - kfree(new_xattr); - return -ENOMEM; - } - } - - spin_lock(&xattrs->lock); - list_for_each_entry(xattr, &xattrs->head, list) { - if (!strcmp(name, xattr->name)) { - if (flags & XATTR_CREATE) { - xattr = new_xattr; - err = -EEXIST; - } else if (new_xattr) { - list_replace(&xattr->list, &new_xattr->list); - } else { - list_del(&xattr->list); - } - goto out; - } - } - if (flags & XATTR_REPLACE) { - xattr = new_xattr; - err = -ENODATA; - } else { - list_add(&new_xattr->list, &xattrs->head); - xattr = NULL; - } -out: - spin_unlock(&xattrs->lock); - if (xattr) { - kfree(xattr->name); - kfree(xattr); - } - return err; - -} - -static bool xattr_is_trusted(const char *name) -{ - return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN); -} - -static int xattr_list_one(char **buffer, ssize_t *remaining_size, - const char *name) -{ - size_t len = strlen(name) + 1; - if (*buffer) { - if (*remaining_size < len) - return -ERANGE; - memcpy(*buffer, name, len); - *buffer += len; - } - *remaining_size -= len; - return 0; -} - -/* - * xattr LIST operation for in-memory/pseudo filesystems - */ -ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs, - char *buffer, size_t size) -{ - bool trusted = capable(CAP_SYS_ADMIN); - struct simple_xattr *xattr; - ssize_t remaining_size = size; - int err = 0; - -#ifdef CONFIG_FS_POSIX_ACL - if (inode->i_acl) { - err = xattr_list_one(&buffer, &remaining_size, - XATTR_NAME_POSIX_ACL_ACCESS); - if (err) - return err; - } - if (inode->i_default_acl) { - err = xattr_list_one(&buffer, &remaining_size, - XATTR_NAME_POSIX_ACL_DEFAULT); - if (err) - return err; - } -#endif - - spin_lock(&xattrs->lock); - list_for_each_entry(xattr, &xattrs->head, list) { - /* skip "trusted." attributes for unprivileged callers */ - if (!trusted && xattr_is_trusted(xattr->name)) - continue; - - err = xattr_list_one(&buffer, &remaining_size, xattr->name); - if (err) - break; - } - spin_unlock(&xattrs->lock); - - return err ? err : size - remaining_size; -} - -/* - * Adds an extended attribute to the list - */ -void simple_xattr_list_add(struct simple_xattrs *xattrs, - struct simple_xattr *new_xattr) -{ - spin_lock(&xattrs->lock); - list_add(&new_xattr->list, &xattrs->head); - spin_unlock(&xattrs->lock); -} diff --git a/src/linux/fs/xfs/Kconfig b/src/linux/fs/xfs/Kconfig deleted file mode 100644 index 35faf12..0000000 --- a/src/linux/fs/xfs/Kconfig +++ /dev/null @@ -1,98 +0,0 @@ -config XFS_FS - tristate "XFS filesystem support" - depends on BLOCK - depends on (64BIT || LBDAF) - select EXPORTFS - select LIBCRC32C - select FS_IOMAP - help - XFS is a high performance journaling filesystem which originated - on the SGI IRIX platform. It is completely multi-threaded, can - support large files and large filesystems, extended attributes, - variable block sizes, is extent based, and makes extensive use of - Btrees (directories, extents, free space) to aid both performance - and scalability. - - Refer to the documentation at - for complete details. This implementation is on-disk compatible - with the IRIX version of XFS. - - To compile this file system support as a module, choose M here: the - module will be called xfs. Be aware, however, that if the file - system of your root partition is compiled as a module, you'll need - to use an initial ramdisk (initrd) to boot. - -config XFS_QUOTA - bool "XFS Quota support" - depends on XFS_FS - select QUOTACTL - help - If you say Y here, you will be able to set limits for disk usage on - a per user and/or a per group basis under XFS. XFS considers quota - information as filesystem metadata and uses journaling to provide a - higher level guarantee of consistency. The on-disk data format for - quota is also compatible with the IRIX version of XFS, allowing a - filesystem to be migrated between Linux and IRIX without any need - for conversion. - - If unsure, say N. More comprehensive documentation can be found in - README.quota in the xfsprogs package. XFS quota can be used either - with or without the generic quota support enabled (CONFIG_QUOTA) - - they are completely independent subsystems. - -config XFS_POSIX_ACL - bool "XFS POSIX ACL support" - depends on XFS_FS - select FS_POSIX_ACL - help - POSIX Access Control Lists (ACLs) support permissions for users and - groups beyond the owner/group/world scheme. - - To learn more about Access Control Lists, visit the POSIX ACLs for - Linux website . - - If you don't know what Access Control Lists are, say N. - -config XFS_RT - bool "XFS Realtime subvolume support" - depends on XFS_FS - help - If you say Y here you will be able to mount and use XFS filesystems - which contain a realtime subvolume. The realtime subvolume is a - separate area of disk space where only file data is stored. It was - originally designed to provide deterministic data rates suitable - for media streaming applications, but is also useful as a generic - mechanism for ensuring data and metadata/log I/Os are completely - separated. Regular file I/Os are isolated to a separate device - from all other requests, and this can be done quite transparently - to applications via the inherit-realtime directory inode flag. - - See the xfs man page in section 5 for additional information. - - If unsure, say N. - -config XFS_WARN - bool "XFS Verbose Warnings" - depends on XFS_FS && !XFS_DEBUG - help - Say Y here to get an XFS build with many additional warnings. - It converts ASSERT checks to WARN, so will log any out-of-bounds - conditions that occur that would otherwise be missed. It is much - lighter weight than XFS_DEBUG and does not modify algorithms and will - not cause the kernel to panic on non-fatal errors. - - However, similar to XFS_DEBUG, it is only advisable to use this if you - are debugging a particular problem. - -config XFS_DEBUG - bool "XFS Debugging support" - depends on XFS_FS - help - Say Y here to get an XFS build with many debugging features, - including ASSERT checks, function wrappers around macros, - and extra sanity-checking functions in various code paths. - - Note that the resulting code will be HUGE and SLOW, and probably - not useful unless you are debugging a particular problem. - - Say N unless you are an XFS developer, or you play one on TV. diff --git a/src/linux/fs/xfs/Makefile b/src/linux/fs/xfs/Makefile deleted file mode 100644 index 26ef195..0000000 --- a/src/linux/fs/xfs/Makefile +++ /dev/null @@ -1,137 +0,0 @@ -# -# Copyright (c) 2000-2005 Silicon Graphics, Inc. -# All Rights Reserved. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it would be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -# - -ccflags-y += -I$(src) # needed for trace events -ccflags-y += -I$(src)/libxfs - -ccflags-$(CONFIG_XFS_DEBUG) += -g - -obj-$(CONFIG_XFS_FS) += xfs.o - -# this one should be compiled first, as the tracing macros can easily blow up -xfs-y += xfs_trace.o - -# build the libxfs code first -xfs-y += $(addprefix libxfs/, \ - xfs_alloc.o \ - xfs_alloc_btree.o \ - xfs_attr.o \ - xfs_attr_leaf.o \ - xfs_attr_remote.o \ - xfs_bit.o \ - xfs_bmap.o \ - xfs_bmap_btree.o \ - xfs_btree.o \ - xfs_da_btree.o \ - xfs_da_format.o \ - xfs_defer.o \ - xfs_dir2.o \ - xfs_dir2_block.o \ - xfs_dir2_data.o \ - xfs_dir2_leaf.o \ - xfs_dir2_node.o \ - xfs_dir2_sf.o \ - xfs_dquot_buf.o \ - xfs_ialloc.o \ - xfs_ialloc_btree.o \ - xfs_inode_fork.o \ - xfs_inode_buf.o \ - xfs_log_rlimit.o \ - xfs_ag_resv.o \ - xfs_rmap.o \ - xfs_rmap_btree.o \ - xfs_refcount.o \ - xfs_refcount_btree.o \ - xfs_sb.o \ - xfs_symlink_remote.o \ - xfs_trans_resv.o \ - ) -# xfs_rtbitmap is shared with libxfs -xfs-$(CONFIG_XFS_RT) += $(addprefix libxfs/, \ - xfs_rtbitmap.o \ - ) - -# highlevel code -xfs-y += xfs_aops.o \ - xfs_attr_inactive.o \ - xfs_attr_list.o \ - xfs_bmap_util.o \ - xfs_buf.o \ - xfs_dir2_readdir.o \ - xfs_discard.o \ - xfs_error.o \ - xfs_export.o \ - xfs_extent_busy.o \ - xfs_file.o \ - xfs_filestream.o \ - xfs_fsops.o \ - xfs_globals.o \ - xfs_icache.o \ - xfs_ioctl.o \ - xfs_iomap.o \ - xfs_iops.o \ - xfs_inode.o \ - xfs_itable.o \ - xfs_message.o \ - xfs_mount.o \ - xfs_mru_cache.o \ - xfs_reflink.o \ - xfs_stats.o \ - xfs_super.o \ - xfs_symlink.o \ - xfs_sysfs.o \ - xfs_trans.o \ - xfs_xattr.o \ - kmem.o \ - uuid.o - -# low-level transaction/log code -xfs-y += xfs_log.o \ - xfs_log_cil.o \ - xfs_bmap_item.o \ - xfs_buf_item.o \ - xfs_extfree_item.o \ - xfs_icreate_item.o \ - xfs_inode_item.o \ - xfs_refcount_item.o \ - xfs_rmap_item.o \ - xfs_log_recover.o \ - xfs_trans_ail.o \ - xfs_trans_bmap.o \ - xfs_trans_buf.o \ - xfs_trans_extfree.o \ - xfs_trans_inode.o \ - xfs_trans_refcount.o \ - xfs_trans_rmap.o \ - -# optional features -xfs-$(CONFIG_XFS_QUOTA) += xfs_dquot.o \ - xfs_dquot_item.o \ - xfs_trans_dquot.o \ - xfs_qm_syscalls.o \ - xfs_qm_bhv.o \ - xfs_qm.o \ - xfs_quotaops.o - -# xfs_rtbitmap is shared with libxfs -xfs-$(CONFIG_XFS_RT) += xfs_rtalloc.o - -xfs-$(CONFIG_XFS_POSIX_ACL) += xfs_acl.o -xfs-$(CONFIG_SYSCTL) += xfs_sysctl.o -xfs-$(CONFIG_COMPAT) += xfs_ioctl32.o -xfs-$(CONFIG_EXPORTFS_BLOCK_OPS) += xfs_pnfs.o diff --git a/src/linux/fs/xfs/kmem.c b/src/linux/fs/xfs/kmem.c deleted file mode 100644 index 339c696..0000000 --- a/src/linux/fs/xfs/kmem.c +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include -#include -#include -#include -#include -#include -#include "kmem.h" -#include "xfs_message.h" - -/* - * Greedy allocation. May fail and may return vmalloced memory. - */ -void * -kmem_zalloc_greedy(size_t *size, size_t minsize, size_t maxsize) -{ - void *ptr; - size_t kmsize = maxsize; - - while (!(ptr = vzalloc(kmsize))) { - if ((kmsize >>= 1) <= minsize) - kmsize = minsize; - } - if (ptr) - *size = kmsize; - return ptr; -} - -void * -kmem_alloc(size_t size, xfs_km_flags_t flags) -{ - int retries = 0; - gfp_t lflags = kmem_flags_convert(flags); - void *ptr; - - do { - ptr = kmalloc(size, lflags); - if (ptr || (flags & (KM_MAYFAIL|KM_NOSLEEP))) - return ptr; - if (!(++retries % 100)) - xfs_err(NULL, - "%s(%u) possible memory allocation deadlock size %u in %s (mode:0x%x)", - current->comm, current->pid, - (unsigned int)size, __func__, lflags); - congestion_wait(BLK_RW_ASYNC, HZ/50); - } while (1); -} - -void * -kmem_zalloc_large(size_t size, xfs_km_flags_t flags) -{ - unsigned noio_flag = 0; - void *ptr; - gfp_t lflags; - - ptr = kmem_zalloc(size, flags | KM_MAYFAIL); - if (ptr) - return ptr; - - /* - * __vmalloc() will allocate data pages and auxillary structures (e.g. - * pagetables) with GFP_KERNEL, yet we may be under GFP_NOFS context - * here. Hence we need to tell memory reclaim that we are in such a - * context via PF_MEMALLOC_NOIO to prevent memory reclaim re-entering - * the filesystem here and potentially deadlocking. - */ - if ((current->flags & PF_FSTRANS) || (flags & KM_NOFS)) - noio_flag = memalloc_noio_save(); - - lflags = kmem_flags_convert(flags); - ptr = __vmalloc(size, lflags | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL); - - if ((current->flags & PF_FSTRANS) || (flags & KM_NOFS)) - memalloc_noio_restore(noio_flag); - - return ptr; -} - -void * -kmem_realloc(const void *old, size_t newsize, xfs_km_flags_t flags) -{ - int retries = 0; - gfp_t lflags = kmem_flags_convert(flags); - void *ptr; - - do { - ptr = krealloc(old, newsize, lflags); - if (ptr || (flags & (KM_MAYFAIL|KM_NOSLEEP))) - return ptr; - if (!(++retries % 100)) - xfs_err(NULL, - "%s(%u) possible memory allocation deadlock size %zu in %s (mode:0x%x)", - current->comm, current->pid, - newsize, __func__, lflags); - congestion_wait(BLK_RW_ASYNC, HZ/50); - } while (1); -} - -void * -kmem_zone_alloc(kmem_zone_t *zone, xfs_km_flags_t flags) -{ - int retries = 0; - gfp_t lflags = kmem_flags_convert(flags); - void *ptr; - - do { - ptr = kmem_cache_alloc(zone, lflags); - if (ptr || (flags & (KM_MAYFAIL|KM_NOSLEEP))) - return ptr; - if (!(++retries % 100)) - xfs_err(NULL, - "%s(%u) possible memory allocation deadlock in %s (mode:0x%x)", - current->comm, current->pid, - __func__, lflags); - congestion_wait(BLK_RW_ASYNC, HZ/50); - } while (1); -} diff --git a/src/linux/fs/xfs/kmem.h b/src/linux/fs/xfs/kmem.h deleted file mode 100644 index 689f746..0000000 --- a/src/linux/fs/xfs/kmem.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_SUPPORT_KMEM_H__ -#define __XFS_SUPPORT_KMEM_H__ - -#include -#include -#include -#include - -/* - * General memory allocation interfaces - */ - -typedef unsigned __bitwise xfs_km_flags_t; -#define KM_SLEEP ((__force xfs_km_flags_t)0x0001u) -#define KM_NOSLEEP ((__force xfs_km_flags_t)0x0002u) -#define KM_NOFS ((__force xfs_km_flags_t)0x0004u) -#define KM_MAYFAIL ((__force xfs_km_flags_t)0x0008u) -#define KM_ZERO ((__force xfs_km_flags_t)0x0010u) - -/* - * We use a special process flag to avoid recursive callbacks into - * the filesystem during transactions. We will also issue our own - * warnings, so we explicitly skip any generic ones (silly of us). - */ -static inline gfp_t -kmem_flags_convert(xfs_km_flags_t flags) -{ - gfp_t lflags; - - BUG_ON(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS|KM_MAYFAIL|KM_ZERO)); - - if (flags & KM_NOSLEEP) { - lflags = GFP_ATOMIC | __GFP_NOWARN; - } else { - lflags = GFP_KERNEL | __GFP_NOWARN; - if ((current->flags & PF_FSTRANS) || (flags & KM_NOFS)) - lflags &= ~__GFP_FS; - } - - if (flags & KM_ZERO) - lflags |= __GFP_ZERO; - - return lflags; -} - -extern void *kmem_alloc(size_t, xfs_km_flags_t); -extern void *kmem_zalloc_large(size_t size, xfs_km_flags_t); -extern void *kmem_realloc(const void *, size_t, xfs_km_flags_t); -static inline void kmem_free(const void *ptr) -{ - kvfree(ptr); -} - - -extern void *kmem_zalloc_greedy(size_t *, size_t, size_t); - -static inline void * -kmem_zalloc(size_t size, xfs_km_flags_t flags) -{ - return kmem_alloc(size, flags | KM_ZERO); -} - -/* - * Zone interfaces - */ - -#define KM_ZONE_HWALIGN SLAB_HWCACHE_ALIGN -#define KM_ZONE_RECLAIM SLAB_RECLAIM_ACCOUNT -#define KM_ZONE_SPREAD SLAB_MEM_SPREAD -#define KM_ZONE_ACCOUNT SLAB_ACCOUNT - -#define kmem_zone kmem_cache -#define kmem_zone_t struct kmem_cache - -static inline kmem_zone_t * -kmem_zone_init(int size, char *zone_name) -{ - return kmem_cache_create(zone_name, size, 0, 0, NULL); -} - -static inline kmem_zone_t * -kmem_zone_init_flags(int size, char *zone_name, unsigned long flags, - void (*construct)(void *)) -{ - return kmem_cache_create(zone_name, size, 0, flags, construct); -} - -static inline void -kmem_zone_free(kmem_zone_t *zone, void *ptr) -{ - kmem_cache_free(zone, ptr); -} - -static inline void -kmem_zone_destroy(kmem_zone_t *zone) -{ - if (zone) - kmem_cache_destroy(zone); -} - -extern void *kmem_zone_alloc(kmem_zone_t *, xfs_km_flags_t); - -static inline void * -kmem_zone_zalloc(kmem_zone_t *zone, xfs_km_flags_t flags) -{ - return kmem_zone_alloc(zone, flags | KM_ZERO); -} - -#endif /* __XFS_SUPPORT_KMEM_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_ag_resv.c b/src/linux/fs/xfs/libxfs/xfs_ag_resv.c deleted file mode 100644 index e5ebc37..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_ag_resv.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_alloc.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_cksum.h" -#include "xfs_trans.h" -#include "xfs_bit.h" -#include "xfs_bmap.h" -#include "xfs_bmap_btree.h" -#include "xfs_ag_resv.h" -#include "xfs_trans_space.h" -#include "xfs_rmap_btree.h" -#include "xfs_btree.h" -#include "xfs_refcount_btree.h" - -/* - * Per-AG Block Reservations - * - * For some kinds of allocation group metadata structures, it is advantageous - * to reserve a small number of blocks in each AG so that future expansions of - * that data structure do not encounter ENOSPC because errors during a btree - * split cause the filesystem to go offline. - * - * Prior to the introduction of reflink, this wasn't an issue because the free - * space btrees maintain a reserve of space (the AGFL) to handle any expansion - * that may be necessary; and allocations of other metadata (inodes, BMBT, - * dir/attr) aren't restricted to a single AG. However, with reflink it is - * possible to allocate all the space in an AG, have subsequent reflink/CoW - * activity expand the refcount btree, and discover that there's no space left - * to handle that expansion. Since we can calculate the maximum size of the - * refcount btree, we can reserve space for it and avoid ENOSPC. - * - * Handling per-AG reservations consists of three changes to the allocator's - * behavior: First, because these reservations are always needed, we decrease - * the ag_max_usable counter to reflect the size of the AG after the reserved - * blocks are taken. Second, the reservations must be reflected in the - * fdblocks count to maintain proper accounting. Third, each AG must maintain - * its own reserved block counter so that we can calculate the amount of space - * that must remain free to maintain the reservations. Fourth, the "remaining - * reserved blocks" count must be used when calculating the length of the - * longest free extent in an AG and to clamp maxlen in the per-AG allocation - * functions. In other words, we maintain a virtual allocation via in-core - * accounting tricks so that we don't have to clean up after a crash. :) - * - * Reserved blocks can be managed by passing one of the enum xfs_ag_resv_type - * values via struct xfs_alloc_arg or directly to the xfs_free_extent - * function. It might seem a little funny to maintain a reservoir of blocks - * to feed another reservoir, but the AGFL only holds enough blocks to get - * through the next transaction. The per-AG reservation is to ensure (we - * hope) that each AG never runs out of blocks. Each data structure wanting - * to use the reservation system should update ask/used in xfs_ag_resv_init. - */ - -/* - * Are we critically low on blocks? For now we'll define that as the number - * of blocks we can get our hands on being less than 10% of what we reserved - * or less than some arbitrary number (maximum btree height). - */ -bool -xfs_ag_resv_critical( - struct xfs_perag *pag, - enum xfs_ag_resv_type type) -{ - xfs_extlen_t avail; - xfs_extlen_t orig; - - switch (type) { - case XFS_AG_RESV_METADATA: - avail = pag->pagf_freeblks - pag->pag_agfl_resv.ar_reserved; - orig = pag->pag_meta_resv.ar_asked; - break; - case XFS_AG_RESV_AGFL: - avail = pag->pagf_freeblks + pag->pagf_flcount - - pag->pag_meta_resv.ar_reserved; - orig = pag->pag_agfl_resv.ar_asked; - break; - default: - ASSERT(0); - return false; - } - - trace_xfs_ag_resv_critical(pag, type, avail); - - /* Critically low if less than 10% or max btree height remains. */ - return XFS_TEST_ERROR(avail < orig / 10 || avail < XFS_BTREE_MAXLEVELS, - pag->pag_mount, XFS_ERRTAG_AG_RESV_CRITICAL, - XFS_RANDOM_AG_RESV_CRITICAL); -} - -/* - * How many blocks are reserved but not used, and therefore must not be - * allocated away? - */ -xfs_extlen_t -xfs_ag_resv_needed( - struct xfs_perag *pag, - enum xfs_ag_resv_type type) -{ - xfs_extlen_t len; - - len = pag->pag_meta_resv.ar_reserved + pag->pag_agfl_resv.ar_reserved; - switch (type) { - case XFS_AG_RESV_METADATA: - case XFS_AG_RESV_AGFL: - len -= xfs_perag_resv(pag, type)->ar_reserved; - break; - case XFS_AG_RESV_NONE: - /* empty */ - break; - default: - ASSERT(0); - } - - trace_xfs_ag_resv_needed(pag, type, len); - - return len; -} - -/* Clean out a reservation */ -static int -__xfs_ag_resv_free( - struct xfs_perag *pag, - enum xfs_ag_resv_type type) -{ - struct xfs_ag_resv *resv; - xfs_extlen_t oldresv; - int error; - - trace_xfs_ag_resv_free(pag, type, 0); - - resv = xfs_perag_resv(pag, type); - pag->pag_mount->m_ag_max_usable += resv->ar_asked; - /* - * AGFL blocks are always considered "free", so whatever - * was reserved at mount time must be given back at umount. - */ - if (type == XFS_AG_RESV_AGFL) - oldresv = resv->ar_orig_reserved; - else - oldresv = resv->ar_reserved; - error = xfs_mod_fdblocks(pag->pag_mount, oldresv, true); - resv->ar_reserved = 0; - resv->ar_asked = 0; - - if (error) - trace_xfs_ag_resv_free_error(pag->pag_mount, pag->pag_agno, - error, _RET_IP_); - return error; -} - -/* Free a per-AG reservation. */ -int -xfs_ag_resv_free( - struct xfs_perag *pag) -{ - int error; - int err2; - - error = __xfs_ag_resv_free(pag, XFS_AG_RESV_AGFL); - err2 = __xfs_ag_resv_free(pag, XFS_AG_RESV_METADATA); - if (err2 && !error) - error = err2; - return error; -} - -static int -__xfs_ag_resv_init( - struct xfs_perag *pag, - enum xfs_ag_resv_type type, - xfs_extlen_t ask, - xfs_extlen_t used) -{ - struct xfs_mount *mp = pag->pag_mount; - struct xfs_ag_resv *resv; - int error; - - resv = xfs_perag_resv(pag, type); - if (used > ask) - ask = used; - resv->ar_asked = ask; - resv->ar_reserved = resv->ar_orig_reserved = ask - used; - mp->m_ag_max_usable -= ask; - - trace_xfs_ag_resv_init(pag, type, ask); - - error = xfs_mod_fdblocks(mp, -(int64_t)resv->ar_reserved, true); - if (error) - trace_xfs_ag_resv_init_error(pag->pag_mount, pag->pag_agno, - error, _RET_IP_); - - return error; -} - -/* Create a per-AG block reservation. */ -int -xfs_ag_resv_init( - struct xfs_perag *pag) -{ - xfs_extlen_t ask; - xfs_extlen_t used; - int error = 0; - - /* Create the metadata reservation. */ - if (pag->pag_meta_resv.ar_asked == 0) { - ask = used = 0; - - error = xfs_refcountbt_calc_reserves(pag->pag_mount, - pag->pag_agno, &ask, &used); - if (error) - goto out; - - error = __xfs_ag_resv_init(pag, XFS_AG_RESV_METADATA, - ask, used); - if (error) - goto out; - } - - /* Create the AGFL metadata reservation */ - if (pag->pag_agfl_resv.ar_asked == 0) { - ask = used = 0; - - error = xfs_rmapbt_calc_reserves(pag->pag_mount, pag->pag_agno, - &ask, &used); - if (error) - goto out; - - error = __xfs_ag_resv_init(pag, XFS_AG_RESV_AGFL, ask, used); - if (error) - goto out; - } - -out: - return error; -} - -/* Allocate a block from the reservation. */ -void -xfs_ag_resv_alloc_extent( - struct xfs_perag *pag, - enum xfs_ag_resv_type type, - struct xfs_alloc_arg *args) -{ - struct xfs_ag_resv *resv; - xfs_extlen_t len; - uint field; - - trace_xfs_ag_resv_alloc_extent(pag, type, args->len); - - switch (type) { - case XFS_AG_RESV_METADATA: - case XFS_AG_RESV_AGFL: - resv = xfs_perag_resv(pag, type); - break; - default: - ASSERT(0); - /* fall through */ - case XFS_AG_RESV_NONE: - field = args->wasdel ? XFS_TRANS_SB_RES_FDBLOCKS : - XFS_TRANS_SB_FDBLOCKS; - xfs_trans_mod_sb(args->tp, field, -(int64_t)args->len); - return; - } - - len = min_t(xfs_extlen_t, args->len, resv->ar_reserved); - resv->ar_reserved -= len; - if (type == XFS_AG_RESV_AGFL) - return; - /* Allocations of reserved blocks only need on-disk sb updates... */ - xfs_trans_mod_sb(args->tp, XFS_TRANS_SB_RES_FDBLOCKS, -(int64_t)len); - /* ...but non-reserved blocks need in-core and on-disk updates. */ - if (args->len > len) - xfs_trans_mod_sb(args->tp, XFS_TRANS_SB_FDBLOCKS, - -((int64_t)args->len - len)); -} - -/* Free a block to the reservation. */ -void -xfs_ag_resv_free_extent( - struct xfs_perag *pag, - enum xfs_ag_resv_type type, - struct xfs_trans *tp, - xfs_extlen_t len) -{ - xfs_extlen_t leftover; - struct xfs_ag_resv *resv; - - trace_xfs_ag_resv_free_extent(pag, type, len); - - switch (type) { - case XFS_AG_RESV_METADATA: - case XFS_AG_RESV_AGFL: - resv = xfs_perag_resv(pag, type); - break; - default: - ASSERT(0); - /* fall through */ - case XFS_AG_RESV_NONE: - xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, (int64_t)len); - return; - } - - leftover = min_t(xfs_extlen_t, len, resv->ar_asked - resv->ar_reserved); - resv->ar_reserved += leftover; - if (type == XFS_AG_RESV_AGFL) - return; - /* Freeing into the reserved pool only requires on-disk update... */ - xfs_trans_mod_sb(tp, XFS_TRANS_SB_RES_FDBLOCKS, len); - /* ...but freeing beyond that requires in-core and on-disk update. */ - if (len > leftover) - xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, len - leftover); -} diff --git a/src/linux/fs/xfs/libxfs/xfs_ag_resv.h b/src/linux/fs/xfs/libxfs/xfs_ag_resv.h deleted file mode 100644 index 8d6c687..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_ag_resv.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#ifndef __XFS_AG_RESV_H__ -#define __XFS_AG_RESV_H__ - -int xfs_ag_resv_free(struct xfs_perag *pag); -int xfs_ag_resv_init(struct xfs_perag *pag); - -bool xfs_ag_resv_critical(struct xfs_perag *pag, enum xfs_ag_resv_type type); -xfs_extlen_t xfs_ag_resv_needed(struct xfs_perag *pag, - enum xfs_ag_resv_type type); - -void xfs_ag_resv_alloc_extent(struct xfs_perag *pag, enum xfs_ag_resv_type type, - struct xfs_alloc_arg *args); -void xfs_ag_resv_free_extent(struct xfs_perag *pag, enum xfs_ag_resv_type type, - struct xfs_trans *tp, xfs_extlen_t len); - -#endif /* __XFS_AG_RESV_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_alloc.c b/src/linux/fs/xfs/libxfs/xfs_alloc.c deleted file mode 100644 index effb64c..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_alloc.c +++ /dev/null @@ -1,2932 +0,0 @@ -/* - * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_shared.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_inode.h" -#include "xfs_btree.h" -#include "xfs_rmap.h" -#include "xfs_alloc_btree.h" -#include "xfs_alloc.h" -#include "xfs_extent_busy.h" -#include "xfs_error.h" -#include "xfs_cksum.h" -#include "xfs_trace.h" -#include "xfs_trans.h" -#include "xfs_buf_item.h" -#include "xfs_log.h" -#include "xfs_ag_resv.h" - -struct workqueue_struct *xfs_alloc_wq; - -#define XFS_ABSDIFF(a,b) (((a) <= (b)) ? ((b) - (a)) : ((a) - (b))) - -#define XFSA_FIXUP_BNO_OK 1 -#define XFSA_FIXUP_CNT_OK 2 - -STATIC int xfs_alloc_ag_vextent_exact(xfs_alloc_arg_t *); -STATIC int xfs_alloc_ag_vextent_near(xfs_alloc_arg_t *); -STATIC int xfs_alloc_ag_vextent_size(xfs_alloc_arg_t *); -STATIC int xfs_alloc_ag_vextent_small(xfs_alloc_arg_t *, - xfs_btree_cur_t *, xfs_agblock_t *, xfs_extlen_t *, int *); - -unsigned int -xfs_refc_block( - struct xfs_mount *mp) -{ - if (xfs_sb_version_hasrmapbt(&mp->m_sb)) - return XFS_RMAP_BLOCK(mp) + 1; - if (xfs_sb_version_hasfinobt(&mp->m_sb)) - return XFS_FIBT_BLOCK(mp) + 1; - return XFS_IBT_BLOCK(mp) + 1; -} - -xfs_extlen_t -xfs_prealloc_blocks( - struct xfs_mount *mp) -{ - if (xfs_sb_version_hasreflink(&mp->m_sb)) - return xfs_refc_block(mp) + 1; - if (xfs_sb_version_hasrmapbt(&mp->m_sb)) - return XFS_RMAP_BLOCK(mp) + 1; - if (xfs_sb_version_hasfinobt(&mp->m_sb)) - return XFS_FIBT_BLOCK(mp) + 1; - return XFS_IBT_BLOCK(mp) + 1; -} - -/* - * In order to avoid ENOSPC-related deadlock caused by out-of-order locking of - * AGF buffer (PV 947395), we place constraints on the relationship among - * actual allocations for data blocks, freelist blocks, and potential file data - * bmap btree blocks. However, these restrictions may result in no actual space - * allocated for a delayed extent, for example, a data block in a certain AG is - * allocated but there is no additional block for the additional bmap btree - * block due to a split of the bmap btree of the file. The result of this may - * lead to an infinite loop when the file gets flushed to disk and all delayed - * extents need to be actually allocated. To get around this, we explicitly set - * aside a few blocks which will not be reserved in delayed allocation. - * - * We need to reserve 4 fsbs _per AG_ for the freelist and 4 more to handle a - * potential split of the file's bmap btree. - */ -unsigned int -xfs_alloc_set_aside( - struct xfs_mount *mp) -{ - unsigned int blocks; - - blocks = 4 + (mp->m_sb.sb_agcount * XFS_ALLOC_AGFL_RESERVE); - return blocks; -} - -/* - * When deciding how much space to allocate out of an AG, we limit the - * allocation maximum size to the size the AG. However, we cannot use all the - * blocks in the AG - some are permanently used by metadata. These - * blocks are generally: - * - the AG superblock, AGF, AGI and AGFL - * - the AGF (bno and cnt) and AGI btree root blocks, and optionally - * the AGI free inode and rmap btree root blocks. - * - blocks on the AGFL according to xfs_alloc_set_aside() limits - * - the rmapbt root block - * - * The AG headers are sector sized, so the amount of space they take up is - * dependent on filesystem geometry. The others are all single blocks. - */ -unsigned int -xfs_alloc_ag_max_usable( - struct xfs_mount *mp) -{ - unsigned int blocks; - - blocks = XFS_BB_TO_FSB(mp, XFS_FSS_TO_BB(mp, 4)); /* ag headers */ - blocks += XFS_ALLOC_AGFL_RESERVE; - blocks += 3; /* AGF, AGI btree root blocks */ - if (xfs_sb_version_hasfinobt(&mp->m_sb)) - blocks++; /* finobt root block */ - if (xfs_sb_version_hasrmapbt(&mp->m_sb)) - blocks++; /* rmap root block */ - if (xfs_sb_version_hasreflink(&mp->m_sb)) - blocks++; /* refcount root block */ - - return mp->m_sb.sb_agblocks - blocks; -} - -/* - * Lookup the record equal to [bno, len] in the btree given by cur. - */ -STATIC int /* error */ -xfs_alloc_lookup_eq( - struct xfs_btree_cur *cur, /* btree cursor */ - xfs_agblock_t bno, /* starting block of extent */ - xfs_extlen_t len, /* length of extent */ - int *stat) /* success/failure */ -{ - cur->bc_rec.a.ar_startblock = bno; - cur->bc_rec.a.ar_blockcount = len; - return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat); -} - -/* - * Lookup the first record greater than or equal to [bno, len] - * in the btree given by cur. - */ -int /* error */ -xfs_alloc_lookup_ge( - struct xfs_btree_cur *cur, /* btree cursor */ - xfs_agblock_t bno, /* starting block of extent */ - xfs_extlen_t len, /* length of extent */ - int *stat) /* success/failure */ -{ - cur->bc_rec.a.ar_startblock = bno; - cur->bc_rec.a.ar_blockcount = len; - return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat); -} - -/* - * Lookup the first record less than or equal to [bno, len] - * in the btree given by cur. - */ -static int /* error */ -xfs_alloc_lookup_le( - struct xfs_btree_cur *cur, /* btree cursor */ - xfs_agblock_t bno, /* starting block of extent */ - xfs_extlen_t len, /* length of extent */ - int *stat) /* success/failure */ -{ - cur->bc_rec.a.ar_startblock = bno; - cur->bc_rec.a.ar_blockcount = len; - return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat); -} - -/* - * Update the record referred to by cur to the value given - * by [bno, len]. - * This either works (return 0) or gets an EFSCORRUPTED error. - */ -STATIC int /* error */ -xfs_alloc_update( - struct xfs_btree_cur *cur, /* btree cursor */ - xfs_agblock_t bno, /* starting block of extent */ - xfs_extlen_t len) /* length of extent */ -{ - union xfs_btree_rec rec; - - rec.alloc.ar_startblock = cpu_to_be32(bno); - rec.alloc.ar_blockcount = cpu_to_be32(len); - return xfs_btree_update(cur, &rec); -} - -/* - * Get the data from the pointed-to record. - */ -int /* error */ -xfs_alloc_get_rec( - struct xfs_btree_cur *cur, /* btree cursor */ - xfs_agblock_t *bno, /* output: starting block of extent */ - xfs_extlen_t *len, /* output: length of extent */ - int *stat) /* output: success/failure */ -{ - union xfs_btree_rec *rec; - int error; - - error = xfs_btree_get_rec(cur, &rec, stat); - if (!error && *stat == 1) { - *bno = be32_to_cpu(rec->alloc.ar_startblock); - *len = be32_to_cpu(rec->alloc.ar_blockcount); - } - return error; -} - -/* - * Compute aligned version of the found extent. - * Takes alignment and min length into account. - */ -STATIC void -xfs_alloc_compute_aligned( - xfs_alloc_arg_t *args, /* allocation argument structure */ - xfs_agblock_t foundbno, /* starting block in found extent */ - xfs_extlen_t foundlen, /* length in found extent */ - xfs_agblock_t *resbno, /* result block number */ - xfs_extlen_t *reslen) /* result length */ -{ - xfs_agblock_t bno; - xfs_extlen_t len; - xfs_extlen_t diff; - - /* Trim busy sections out of found extent */ - xfs_extent_busy_trim(args, foundbno, foundlen, &bno, &len); - - /* - * If we have a largish extent that happens to start before min_agbno, - * see if we can shift it into range... - */ - if (bno < args->min_agbno && bno + len > args->min_agbno) { - diff = args->min_agbno - bno; - if (len > diff) { - bno += diff; - len -= diff; - } - } - - if (args->alignment > 1 && len >= args->minlen) { - xfs_agblock_t aligned_bno = roundup(bno, args->alignment); - - diff = aligned_bno - bno; - - *resbno = aligned_bno; - *reslen = diff >= len ? 0 : len - diff; - } else { - *resbno = bno; - *reslen = len; - } -} - -/* - * Compute best start block and diff for "near" allocations. - * freelen >= wantlen already checked by caller. - */ -STATIC xfs_extlen_t /* difference value (absolute) */ -xfs_alloc_compute_diff( - xfs_agblock_t wantbno, /* target starting block */ - xfs_extlen_t wantlen, /* target length */ - xfs_extlen_t alignment, /* target alignment */ - int datatype, /* are we allocating data? */ - xfs_agblock_t freebno, /* freespace's starting block */ - xfs_extlen_t freelen, /* freespace's length */ - xfs_agblock_t *newbnop) /* result: best start block from free */ -{ - xfs_agblock_t freeend; /* end of freespace extent */ - xfs_agblock_t newbno1; /* return block number */ - xfs_agblock_t newbno2; /* other new block number */ - xfs_extlen_t newlen1=0; /* length with newbno1 */ - xfs_extlen_t newlen2=0; /* length with newbno2 */ - xfs_agblock_t wantend; /* end of target extent */ - bool userdata = xfs_alloc_is_userdata(datatype); - - ASSERT(freelen >= wantlen); - freeend = freebno + freelen; - wantend = wantbno + wantlen; - /* - * We want to allocate from the start of a free extent if it is past - * the desired block or if we are allocating user data and the free - * extent is before desired block. The second case is there to allow - * for contiguous allocation from the remaining free space if the file - * grows in the short term. - */ - if (freebno >= wantbno || (userdata && freeend < wantend)) { - if ((newbno1 = roundup(freebno, alignment)) >= freeend) - newbno1 = NULLAGBLOCK; - } else if (freeend >= wantend && alignment > 1) { - newbno1 = roundup(wantbno, alignment); - newbno2 = newbno1 - alignment; - if (newbno1 >= freeend) - newbno1 = NULLAGBLOCK; - else - newlen1 = XFS_EXTLEN_MIN(wantlen, freeend - newbno1); - if (newbno2 < freebno) - newbno2 = NULLAGBLOCK; - else - newlen2 = XFS_EXTLEN_MIN(wantlen, freeend - newbno2); - if (newbno1 != NULLAGBLOCK && newbno2 != NULLAGBLOCK) { - if (newlen1 < newlen2 || - (newlen1 == newlen2 && - XFS_ABSDIFF(newbno1, wantbno) > - XFS_ABSDIFF(newbno2, wantbno))) - newbno1 = newbno2; - } else if (newbno2 != NULLAGBLOCK) - newbno1 = newbno2; - } else if (freeend >= wantend) { - newbno1 = wantbno; - } else if (alignment > 1) { - newbno1 = roundup(freeend - wantlen, alignment); - if (newbno1 > freeend - wantlen && - newbno1 - alignment >= freebno) - newbno1 -= alignment; - else if (newbno1 >= freeend) - newbno1 = NULLAGBLOCK; - } else - newbno1 = freeend - wantlen; - *newbnop = newbno1; - return newbno1 == NULLAGBLOCK ? 0 : XFS_ABSDIFF(newbno1, wantbno); -} - -/* - * Fix up the length, based on mod and prod. - * len should be k * prod + mod for some k. - * If len is too small it is returned unchanged. - * If len hits maxlen it is left alone. - */ -STATIC void -xfs_alloc_fix_len( - xfs_alloc_arg_t *args) /* allocation argument structure */ -{ - xfs_extlen_t k; - xfs_extlen_t rlen; - - ASSERT(args->mod < args->prod); - rlen = args->len; - ASSERT(rlen >= args->minlen); - ASSERT(rlen <= args->maxlen); - if (args->prod <= 1 || rlen < args->mod || rlen == args->maxlen || - (args->mod == 0 && rlen < args->prod)) - return; - k = rlen % args->prod; - if (k == args->mod) - return; - if (k > args->mod) - rlen = rlen - (k - args->mod); - else - rlen = rlen - args->prod + (args->mod - k); - /* casts to (int) catch length underflows */ - if ((int)rlen < (int)args->minlen) - return; - ASSERT(rlen >= args->minlen && rlen <= args->maxlen); - ASSERT(rlen % args->prod == args->mod); - args->len = rlen; -} - -/* - * Fix up length if there is too little space left in the a.g. - * Return 1 if ok, 0 if too little, should give up. - */ -STATIC int -xfs_alloc_fix_minleft( - xfs_alloc_arg_t *args) /* allocation argument structure */ -{ - xfs_agf_t *agf; /* a.g. freelist header */ - int diff; /* free space difference */ - - if (args->minleft == 0) - return 1; - agf = XFS_BUF_TO_AGF(args->agbp); - diff = be32_to_cpu(agf->agf_freeblks) - - args->len - args->minleft; - if (diff >= 0) - return 1; - args->len += diff; /* shrink the allocated space */ - /* casts to (int) catch length underflows */ - if ((int)args->len >= (int)args->minlen) - return 1; - args->agbno = NULLAGBLOCK; - return 0; -} - -/* - * Update the two btrees, logically removing from freespace the extent - * starting at rbno, rlen blocks. The extent is contained within the - * actual (current) free extent fbno for flen blocks. - * Flags are passed in indicating whether the cursors are set to the - * relevant records. - */ -STATIC int /* error code */ -xfs_alloc_fixup_trees( - xfs_btree_cur_t *cnt_cur, /* cursor for by-size btree */ - xfs_btree_cur_t *bno_cur, /* cursor for by-block btree */ - xfs_agblock_t fbno, /* starting block of free extent */ - xfs_extlen_t flen, /* length of free extent */ - xfs_agblock_t rbno, /* starting block of returned extent */ - xfs_extlen_t rlen, /* length of returned extent */ - int flags) /* flags, XFSA_FIXUP_... */ -{ - int error; /* error code */ - int i; /* operation results */ - xfs_agblock_t nfbno1; /* first new free startblock */ - xfs_agblock_t nfbno2; /* second new free startblock */ - xfs_extlen_t nflen1=0; /* first new free length */ - xfs_extlen_t nflen2=0; /* second new free length */ - struct xfs_mount *mp; - - mp = cnt_cur->bc_mp; - - /* - * Look up the record in the by-size tree if necessary. - */ - if (flags & XFSA_FIXUP_CNT_OK) { -#ifdef DEBUG - if ((error = xfs_alloc_get_rec(cnt_cur, &nfbno1, &nflen1, &i))) - return error; - XFS_WANT_CORRUPTED_RETURN(mp, - i == 1 && nfbno1 == fbno && nflen1 == flen); -#endif - } else { - if ((error = xfs_alloc_lookup_eq(cnt_cur, fbno, flen, &i))) - return error; - XFS_WANT_CORRUPTED_RETURN(mp, i == 1); - } - /* - * Look up the record in the by-block tree if necessary. - */ - if (flags & XFSA_FIXUP_BNO_OK) { -#ifdef DEBUG - if ((error = xfs_alloc_get_rec(bno_cur, &nfbno1, &nflen1, &i))) - return error; - XFS_WANT_CORRUPTED_RETURN(mp, - i == 1 && nfbno1 == fbno && nflen1 == flen); -#endif - } else { - if ((error = xfs_alloc_lookup_eq(bno_cur, fbno, flen, &i))) - return error; - XFS_WANT_CORRUPTED_RETURN(mp, i == 1); - } - -#ifdef DEBUG - if (bno_cur->bc_nlevels == 1 && cnt_cur->bc_nlevels == 1) { - struct xfs_btree_block *bnoblock; - struct xfs_btree_block *cntblock; - - bnoblock = XFS_BUF_TO_BLOCK(bno_cur->bc_bufs[0]); - cntblock = XFS_BUF_TO_BLOCK(cnt_cur->bc_bufs[0]); - - XFS_WANT_CORRUPTED_RETURN(mp, - bnoblock->bb_numrecs == cntblock->bb_numrecs); - } -#endif - - /* - * Deal with all four cases: the allocated record is contained - * within the freespace record, so we can have new freespace - * at either (or both) end, or no freespace remaining. - */ - if (rbno == fbno && rlen == flen) - nfbno1 = nfbno2 = NULLAGBLOCK; - else if (rbno == fbno) { - nfbno1 = rbno + rlen; - nflen1 = flen - rlen; - nfbno2 = NULLAGBLOCK; - } else if (rbno + rlen == fbno + flen) { - nfbno1 = fbno; - nflen1 = flen - rlen; - nfbno2 = NULLAGBLOCK; - } else { - nfbno1 = fbno; - nflen1 = rbno - fbno; - nfbno2 = rbno + rlen; - nflen2 = (fbno + flen) - nfbno2; - } - /* - * Delete the entry from the by-size btree. - */ - if ((error = xfs_btree_delete(cnt_cur, &i))) - return error; - XFS_WANT_CORRUPTED_RETURN(mp, i == 1); - /* - * Add new by-size btree entry(s). - */ - if (nfbno1 != NULLAGBLOCK) { - if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno1, nflen1, &i))) - return error; - XFS_WANT_CORRUPTED_RETURN(mp, i == 0); - if ((error = xfs_btree_insert(cnt_cur, &i))) - return error; - XFS_WANT_CORRUPTED_RETURN(mp, i == 1); - } - if (nfbno2 != NULLAGBLOCK) { - if ((error = xfs_alloc_lookup_eq(cnt_cur, nfbno2, nflen2, &i))) - return error; - XFS_WANT_CORRUPTED_RETURN(mp, i == 0); - if ((error = xfs_btree_insert(cnt_cur, &i))) - return error; - XFS_WANT_CORRUPTED_RETURN(mp, i == 1); - } - /* - * Fix up the by-block btree entry(s). - */ - if (nfbno1 == NULLAGBLOCK) { - /* - * No remaining freespace, just delete the by-block tree entry. - */ - if ((error = xfs_btree_delete(bno_cur, &i))) - return error; - XFS_WANT_CORRUPTED_RETURN(mp, i == 1); - } else { - /* - * Update the by-block entry to start later|be shorter. - */ - if ((error = xfs_alloc_update(bno_cur, nfbno1, nflen1))) - return error; - } - if (nfbno2 != NULLAGBLOCK) { - /* - * 2 resulting free entries, need to add one. - */ - if ((error = xfs_alloc_lookup_eq(bno_cur, nfbno2, nflen2, &i))) - return error; - XFS_WANT_CORRUPTED_RETURN(mp, i == 0); - if ((error = xfs_btree_insert(bno_cur, &i))) - return error; - XFS_WANT_CORRUPTED_RETURN(mp, i == 1); - } - return 0; -} - -static bool -xfs_agfl_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_agfl *agfl = XFS_BUF_TO_AGFL(bp); - int i; - - if (!uuid_equal(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid)) - return false; - if (be32_to_cpu(agfl->agfl_magicnum) != XFS_AGFL_MAGIC) - return false; - /* - * during growfs operations, the perag is not fully initialised, - * so we can't use it for any useful checking. growfs ensures we can't - * use it by using uncached buffers that don't have the perag attached - * so we can detect and avoid this problem. - */ - if (bp->b_pag && be32_to_cpu(agfl->agfl_seqno) != bp->b_pag->pag_agno) - return false; - - for (i = 0; i < XFS_AGFL_SIZE(mp); i++) { - if (be32_to_cpu(agfl->agfl_bno[i]) != NULLAGBLOCK && - be32_to_cpu(agfl->agfl_bno[i]) >= mp->m_sb.sb_agblocks) - return false; - } - - return xfs_log_check_lsn(mp, - be64_to_cpu(XFS_BUF_TO_AGFL(bp)->agfl_lsn)); -} - -static void -xfs_agfl_read_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - - /* - * There is no verification of non-crc AGFLs because mkfs does not - * initialise the AGFL to zero or NULL. Hence the only valid part of the - * AGFL is what the AGF says is active. We can't get to the AGF, so we - * can't verify just those entries are valid. - */ - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return; - - if (!xfs_buf_verify_cksum(bp, XFS_AGFL_CRC_OFF)) - xfs_buf_ioerror(bp, -EFSBADCRC); - else if (!xfs_agfl_verify(bp)) - xfs_buf_ioerror(bp, -EFSCORRUPTED); - - if (bp->b_error) - xfs_verifier_error(bp); -} - -static void -xfs_agfl_write_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_buf_log_item *bip = bp->b_fspriv; - - /* no verification of non-crc AGFLs */ - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return; - - if (!xfs_agfl_verify(bp)) { - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - return; - } - - if (bip) - XFS_BUF_TO_AGFL(bp)->agfl_lsn = cpu_to_be64(bip->bli_item.li_lsn); - - xfs_buf_update_cksum(bp, XFS_AGFL_CRC_OFF); -} - -const struct xfs_buf_ops xfs_agfl_buf_ops = { - .name = "xfs_agfl", - .verify_read = xfs_agfl_read_verify, - .verify_write = xfs_agfl_write_verify, -}; - -/* - * Read in the allocation group free block array. - */ -STATIC int /* error */ -xfs_alloc_read_agfl( - xfs_mount_t *mp, /* mount point structure */ - xfs_trans_t *tp, /* transaction pointer */ - xfs_agnumber_t agno, /* allocation group number */ - xfs_buf_t **bpp) /* buffer for the ag free block array */ -{ - xfs_buf_t *bp; /* return value */ - int error; - - ASSERT(agno != NULLAGNUMBER); - error = xfs_trans_read_buf( - mp, tp, mp->m_ddev_targp, - XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)), - XFS_FSS_TO_BB(mp, 1), 0, &bp, &xfs_agfl_buf_ops); - if (error) - return error; - xfs_buf_set_ref(bp, XFS_AGFL_REF); - *bpp = bp; - return 0; -} - -STATIC int -xfs_alloc_update_counters( - struct xfs_trans *tp, - struct xfs_perag *pag, - struct xfs_buf *agbp, - long len) -{ - struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); - - pag->pagf_freeblks += len; - be32_add_cpu(&agf->agf_freeblks, len); - - xfs_trans_agblocks_delta(tp, len); - if (unlikely(be32_to_cpu(agf->agf_freeblks) > - be32_to_cpu(agf->agf_length))) - return -EFSCORRUPTED; - - xfs_alloc_log_agf(tp, agbp, XFS_AGF_FREEBLKS); - return 0; -} - -/* - * Allocation group level functions. - */ - -/* - * Allocate a variable extent in the allocation group agno. - * Type and bno are used to determine where in the allocation group the - * extent will start. - * Extent's length (returned in *len) will be between minlen and maxlen, - * and of the form k * prod + mod unless there's nothing that large. - * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. - */ -STATIC int /* error */ -xfs_alloc_ag_vextent( - xfs_alloc_arg_t *args) /* argument structure for allocation */ -{ - int error=0; - xfs_extlen_t reservation; - xfs_extlen_t oldmax; - - ASSERT(args->minlen > 0); - ASSERT(args->maxlen > 0); - ASSERT(args->minlen <= args->maxlen); - ASSERT(args->mod < args->prod); - ASSERT(args->alignment > 0); - - /* - * Clamp maxlen to the amount of free space minus any reservations - * that have been made. - */ - oldmax = args->maxlen; - reservation = xfs_ag_resv_needed(args->pag, args->resv); - if (args->maxlen > args->pag->pagf_freeblks - reservation) - args->maxlen = args->pag->pagf_freeblks - reservation; - if (args->maxlen == 0) { - args->agbno = NULLAGBLOCK; - args->maxlen = oldmax; - return 0; - } - - /* - * Branch to correct routine based on the type. - */ - args->wasfromfl = 0; - switch (args->type) { - case XFS_ALLOCTYPE_THIS_AG: - error = xfs_alloc_ag_vextent_size(args); - break; - case XFS_ALLOCTYPE_NEAR_BNO: - error = xfs_alloc_ag_vextent_near(args); - break; - case XFS_ALLOCTYPE_THIS_BNO: - error = xfs_alloc_ag_vextent_exact(args); - break; - default: - ASSERT(0); - /* NOTREACHED */ - } - - args->maxlen = oldmax; - - if (error || args->agbno == NULLAGBLOCK) - return error; - - ASSERT(args->len >= args->minlen); - ASSERT(args->len <= args->maxlen); - ASSERT(!args->wasfromfl || args->resv != XFS_AG_RESV_AGFL); - ASSERT(args->agbno % args->alignment == 0); - - /* if not file data, insert new block into the reverse map btree */ - if (args->oinfo.oi_owner != XFS_RMAP_OWN_UNKNOWN) { - error = xfs_rmap_alloc(args->tp, args->agbp, args->agno, - args->agbno, args->len, &args->oinfo); - if (error) - return error; - } - - if (!args->wasfromfl) { - error = xfs_alloc_update_counters(args->tp, args->pag, - args->agbp, - -((long)(args->len))); - if (error) - return error; - - ASSERT(!xfs_extent_busy_search(args->mp, args->agno, - args->agbno, args->len)); - } - - xfs_ag_resv_alloc_extent(args->pag, args->resv, args); - - XFS_STATS_INC(args->mp, xs_allocx); - XFS_STATS_ADD(args->mp, xs_allocb, args->len); - return error; -} - -/* - * Allocate a variable extent at exactly agno/bno. - * Extent's length (returned in *len) will be between minlen and maxlen, - * and of the form k * prod + mod unless there's nothing that large. - * Return the starting a.g. block (bno), or NULLAGBLOCK if we can't do it. - */ -STATIC int /* error */ -xfs_alloc_ag_vextent_exact( - xfs_alloc_arg_t *args) /* allocation argument structure */ -{ - xfs_btree_cur_t *bno_cur;/* by block-number btree cursor */ - xfs_btree_cur_t *cnt_cur;/* by count btree cursor */ - int error; - xfs_agblock_t fbno; /* start block of found extent */ - xfs_extlen_t flen; /* length of found extent */ - xfs_agblock_t tbno; /* start block of trimmed extent */ - xfs_extlen_t tlen; /* length of trimmed extent */ - xfs_agblock_t tend; /* end block of trimmed extent */ - int i; /* success/failure of operation */ - - ASSERT(args->alignment == 1); - - /* - * Allocate/initialize a cursor for the by-number freespace btree. - */ - bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, - args->agno, XFS_BTNUM_BNO); - - /* - * Lookup bno and minlen in the btree (minlen is irrelevant, really). - * Look for the closest free block <= bno, it must contain bno - * if any free block does. - */ - error = xfs_alloc_lookup_le(bno_cur, args->agbno, args->minlen, &i); - if (error) - goto error0; - if (!i) - goto not_found; - - /* - * Grab the freespace record. - */ - error = xfs_alloc_get_rec(bno_cur, &fbno, &flen, &i); - if (error) - goto error0; - XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); - ASSERT(fbno <= args->agbno); - - /* - * Check for overlapping busy extents. - */ - xfs_extent_busy_trim(args, fbno, flen, &tbno, &tlen); - - /* - * Give up if the start of the extent is busy, or the freespace isn't - * long enough for the minimum request. - */ - if (tbno > args->agbno) - goto not_found; - if (tlen < args->minlen) - goto not_found; - tend = tbno + tlen; - if (tend < args->agbno + args->minlen) - goto not_found; - - /* - * End of extent will be smaller of the freespace end and the - * maximal requested end. - * - * Fix the length according to mod and prod if given. - */ - args->len = XFS_AGBLOCK_MIN(tend, args->agbno + args->maxlen) - - args->agbno; - xfs_alloc_fix_len(args); - if (!xfs_alloc_fix_minleft(args)) - goto not_found; - - ASSERT(args->agbno + args->len <= tend); - - /* - * We are allocating agbno for args->len - * Allocate/initialize a cursor for the by-size btree. - */ - cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, - args->agno, XFS_BTNUM_CNT); - ASSERT(args->agbno + args->len <= - be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length)); - error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, args->agbno, - args->len, XFSA_FIXUP_BNO_OK); - if (error) { - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); - goto error0; - } - - xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); - - args->wasfromfl = 0; - trace_xfs_alloc_exact_done(args); - return 0; - -not_found: - /* Didn't find it, return null. */ - xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); - args->agbno = NULLAGBLOCK; - trace_xfs_alloc_exact_notfound(args); - return 0; - -error0: - xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); - trace_xfs_alloc_exact_error(args); - return error; -} - -/* - * Search the btree in a given direction via the search cursor and compare - * the records found against the good extent we've already found. - */ -STATIC int -xfs_alloc_find_best_extent( - struct xfs_alloc_arg *args, /* allocation argument structure */ - struct xfs_btree_cur **gcur, /* good cursor */ - struct xfs_btree_cur **scur, /* searching cursor */ - xfs_agblock_t gdiff, /* difference for search comparison */ - xfs_agblock_t *sbno, /* extent found by search */ - xfs_extlen_t *slen, /* extent length */ - xfs_agblock_t *sbnoa, /* aligned extent found by search */ - xfs_extlen_t *slena, /* aligned extent length */ - int dir) /* 0 = search right, 1 = search left */ -{ - xfs_agblock_t new; - xfs_agblock_t sdiff; - int error; - int i; - - /* The good extent is perfect, no need to search. */ - if (!gdiff) - goto out_use_good; - - /* - * Look until we find a better one, run out of space or run off the end. - */ - do { - error = xfs_alloc_get_rec(*scur, sbno, slen, &i); - if (error) - goto error0; - XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); - xfs_alloc_compute_aligned(args, *sbno, *slen, sbnoa, slena); - - /* - * The good extent is closer than this one. - */ - if (!dir) { - if (*sbnoa > args->max_agbno) - goto out_use_good; - if (*sbnoa >= args->agbno + gdiff) - goto out_use_good; - } else { - if (*sbnoa < args->min_agbno) - goto out_use_good; - if (*sbnoa <= args->agbno - gdiff) - goto out_use_good; - } - - /* - * Same distance, compare length and pick the best. - */ - if (*slena >= args->minlen) { - args->len = XFS_EXTLEN_MIN(*slena, args->maxlen); - xfs_alloc_fix_len(args); - - sdiff = xfs_alloc_compute_diff(args->agbno, args->len, - args->alignment, - args->datatype, *sbnoa, - *slena, &new); - - /* - * Choose closer size and invalidate other cursor. - */ - if (sdiff < gdiff) - goto out_use_search; - goto out_use_good; - } - - if (!dir) - error = xfs_btree_increment(*scur, 0, &i); - else - error = xfs_btree_decrement(*scur, 0, &i); - if (error) - goto error0; - } while (i); - -out_use_good: - xfs_btree_del_cursor(*scur, XFS_BTREE_NOERROR); - *scur = NULL; - return 0; - -out_use_search: - xfs_btree_del_cursor(*gcur, XFS_BTREE_NOERROR); - *gcur = NULL; - return 0; - -error0: - /* caller invalidates cursors */ - return error; -} - -/* - * Allocate a variable extent near bno in the allocation group agno. - * Extent's length (returned in len) will be between minlen and maxlen, - * and of the form k * prod + mod unless there's nothing that large. - * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. - */ -STATIC int /* error */ -xfs_alloc_ag_vextent_near( - xfs_alloc_arg_t *args) /* allocation argument structure */ -{ - xfs_btree_cur_t *bno_cur_gt; /* cursor for bno btree, right side */ - xfs_btree_cur_t *bno_cur_lt; /* cursor for bno btree, left side */ - xfs_btree_cur_t *cnt_cur; /* cursor for count btree */ - xfs_agblock_t gtbno; /* start bno of right side entry */ - xfs_agblock_t gtbnoa; /* aligned ... */ - xfs_extlen_t gtdiff; /* difference to right side entry */ - xfs_extlen_t gtlen; /* length of right side entry */ - xfs_extlen_t gtlena; /* aligned ... */ - xfs_agblock_t gtnew; /* useful start bno of right side */ - int error; /* error code */ - int i; /* result code, temporary */ - int j; /* result code, temporary */ - xfs_agblock_t ltbno; /* start bno of left side entry */ - xfs_agblock_t ltbnoa; /* aligned ... */ - xfs_extlen_t ltdiff; /* difference to left side entry */ - xfs_extlen_t ltlen; /* length of left side entry */ - xfs_extlen_t ltlena; /* aligned ... */ - xfs_agblock_t ltnew; /* useful start bno of left side */ - xfs_extlen_t rlen; /* length of returned extent */ - int forced = 0; -#ifdef DEBUG - /* - * Randomly don't execute the first algorithm. - */ - int dofirst; /* set to do first algorithm */ - - dofirst = prandom_u32() & 1; -#endif - - /* handle unitialized agbno range so caller doesn't have to */ - if (!args->min_agbno && !args->max_agbno) - args->max_agbno = args->mp->m_sb.sb_agblocks - 1; - ASSERT(args->min_agbno <= args->max_agbno); - - /* clamp agbno to the range if it's outside */ - if (args->agbno < args->min_agbno) - args->agbno = args->min_agbno; - if (args->agbno > args->max_agbno) - args->agbno = args->max_agbno; - -restart: - bno_cur_lt = NULL; - bno_cur_gt = NULL; - ltlen = 0; - gtlena = 0; - ltlena = 0; - - /* - * Get a cursor for the by-size btree. - */ - cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, - args->agno, XFS_BTNUM_CNT); - - /* - * See if there are any free extents as big as maxlen. - */ - if ((error = xfs_alloc_lookup_ge(cnt_cur, 0, args->maxlen, &i))) - goto error0; - /* - * If none, then pick up the last entry in the tree unless the - * tree is empty. - */ - if (!i) { - if ((error = xfs_alloc_ag_vextent_small(args, cnt_cur, <bno, - <len, &i))) - goto error0; - if (i == 0 || ltlen == 0) { - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); - trace_xfs_alloc_near_noentry(args); - return 0; - } - ASSERT(i == 1); - } - args->wasfromfl = 0; - - /* - * First algorithm. - * If the requested extent is large wrt the freespaces available - * in this a.g., then the cursor will be pointing to a btree entry - * near the right edge of the tree. If it's in the last btree leaf - * block, then we just examine all the entries in that block - * that are big enough, and pick the best one. - * This is written as a while loop so we can break out of it, - * but we never loop back to the top. - */ - while (xfs_btree_islastblock(cnt_cur, 0)) { - xfs_extlen_t bdiff; - int besti=0; - xfs_extlen_t blen=0; - xfs_agblock_t bnew=0; - -#ifdef DEBUG - if (dofirst) - break; -#endif - /* - * Start from the entry that lookup found, sequence through - * all larger free blocks. If we're actually pointing at a - * record smaller than maxlen, go to the start of this block, - * and skip all those smaller than minlen. - */ - if (ltlen || args->alignment > 1) { - cnt_cur->bc_ptrs[0] = 1; - do { - if ((error = xfs_alloc_get_rec(cnt_cur, <bno, - <len, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); - if (ltlen >= args->minlen) - break; - if ((error = xfs_btree_increment(cnt_cur, 0, &i))) - goto error0; - } while (i); - ASSERT(ltlen >= args->minlen); - if (!i) - break; - } - i = cnt_cur->bc_ptrs[0]; - for (j = 1, blen = 0, bdiff = 0; - !error && j && (blen < args->maxlen || bdiff > 0); - error = xfs_btree_increment(cnt_cur, 0, &j)) { - /* - * For each entry, decide if it's better than - * the previous best entry. - */ - if ((error = xfs_alloc_get_rec(cnt_cur, <bno, <len, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); - xfs_alloc_compute_aligned(args, ltbno, ltlen, - <bnoa, <lena); - if (ltlena < args->minlen) - continue; - if (ltbnoa < args->min_agbno || ltbnoa > args->max_agbno) - continue; - args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); - xfs_alloc_fix_len(args); - ASSERT(args->len >= args->minlen); - if (args->len < blen) - continue; - ltdiff = xfs_alloc_compute_diff(args->agbno, args->len, - args->alignment, args->datatype, ltbnoa, - ltlena, <new); - if (ltnew != NULLAGBLOCK && - (args->len > blen || ltdiff < bdiff)) { - bdiff = ltdiff; - bnew = ltnew; - blen = args->len; - besti = cnt_cur->bc_ptrs[0]; - } - } - /* - * It didn't work. We COULD be in a case where - * there's a good record somewhere, so try again. - */ - if (blen == 0) - break; - /* - * Point at the best entry, and retrieve it again. - */ - cnt_cur->bc_ptrs[0] = besti; - if ((error = xfs_alloc_get_rec(cnt_cur, <bno, <len, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); - ASSERT(ltbno + ltlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length)); - args->len = blen; - if (!xfs_alloc_fix_minleft(args)) { - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); - trace_xfs_alloc_near_nominleft(args); - return 0; - } - blen = args->len; - /* - * We are allocating starting at bnew for blen blocks. - */ - args->agbno = bnew; - ASSERT(bnew >= ltbno); - ASSERT(bnew + blen <= ltbno + ltlen); - /* - * Set up a cursor for the by-bno tree. - */ - bno_cur_lt = xfs_allocbt_init_cursor(args->mp, args->tp, - args->agbp, args->agno, XFS_BTNUM_BNO); - /* - * Fix up the btree entries. - */ - if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, - ltlen, bnew, blen, XFSA_FIXUP_CNT_OK))) - goto error0; - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); - xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); - - trace_xfs_alloc_near_first(args); - return 0; - } - /* - * Second algorithm. - * Search in the by-bno tree to the left and to the right - * simultaneously, until in each case we find a space big enough, - * or run into the edge of the tree. When we run into the edge, - * we deallocate that cursor. - * If both searches succeed, we compare the two spaces and pick - * the better one. - * With alignment, it's possible for both to fail; the upper - * level algorithm that picks allocation groups for allocations - * is not supposed to do this. - */ - /* - * Allocate and initialize the cursor for the leftward search. - */ - bno_cur_lt = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, - args->agno, XFS_BTNUM_BNO); - /* - * Lookup <= bno to find the leftward search's starting point. - */ - if ((error = xfs_alloc_lookup_le(bno_cur_lt, args->agbno, args->maxlen, &i))) - goto error0; - if (!i) { - /* - * Didn't find anything; use this cursor for the rightward - * search. - */ - bno_cur_gt = bno_cur_lt; - bno_cur_lt = NULL; - } - /* - * Found something. Duplicate the cursor for the rightward search. - */ - else if ((error = xfs_btree_dup_cursor(bno_cur_lt, &bno_cur_gt))) - goto error0; - /* - * Increment the cursor, so we will point at the entry just right - * of the leftward entry if any, or to the leftmost entry. - */ - if ((error = xfs_btree_increment(bno_cur_gt, 0, &i))) - goto error0; - if (!i) { - /* - * It failed, there are no rightward entries. - */ - xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_NOERROR); - bno_cur_gt = NULL; - } - /* - * Loop going left with the leftward cursor, right with the - * rightward cursor, until either both directions give up or - * we find an entry at least as big as minlen. - */ - do { - if (bno_cur_lt) { - if ((error = xfs_alloc_get_rec(bno_cur_lt, <bno, <len, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); - xfs_alloc_compute_aligned(args, ltbno, ltlen, - <bnoa, <lena); - if (ltlena >= args->minlen && ltbnoa >= args->min_agbno) - break; - if ((error = xfs_btree_decrement(bno_cur_lt, 0, &i))) - goto error0; - if (!i || ltbnoa < args->min_agbno) { - xfs_btree_del_cursor(bno_cur_lt, - XFS_BTREE_NOERROR); - bno_cur_lt = NULL; - } - } - if (bno_cur_gt) { - if ((error = xfs_alloc_get_rec(bno_cur_gt, >bno, >len, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); - xfs_alloc_compute_aligned(args, gtbno, gtlen, - >bnoa, >lena); - if (gtlena >= args->minlen && gtbnoa <= args->max_agbno) - break; - if ((error = xfs_btree_increment(bno_cur_gt, 0, &i))) - goto error0; - if (!i || gtbnoa > args->max_agbno) { - xfs_btree_del_cursor(bno_cur_gt, - XFS_BTREE_NOERROR); - bno_cur_gt = NULL; - } - } - } while (bno_cur_lt || bno_cur_gt); - - /* - * Got both cursors still active, need to find better entry. - */ - if (bno_cur_lt && bno_cur_gt) { - if (ltlena >= args->minlen) { - /* - * Left side is good, look for a right side entry. - */ - args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); - xfs_alloc_fix_len(args); - ltdiff = xfs_alloc_compute_diff(args->agbno, args->len, - args->alignment, args->datatype, ltbnoa, - ltlena, <new); - - error = xfs_alloc_find_best_extent(args, - &bno_cur_lt, &bno_cur_gt, - ltdiff, >bno, >len, - >bnoa, >lena, - 0 /* search right */); - } else { - ASSERT(gtlena >= args->minlen); - - /* - * Right side is good, look for a left side entry. - */ - args->len = XFS_EXTLEN_MIN(gtlena, args->maxlen); - xfs_alloc_fix_len(args); - gtdiff = xfs_alloc_compute_diff(args->agbno, args->len, - args->alignment, args->datatype, gtbnoa, - gtlena, >new); - - error = xfs_alloc_find_best_extent(args, - &bno_cur_gt, &bno_cur_lt, - gtdiff, <bno, <len, - <bnoa, <lena, - 1 /* search left */); - } - - if (error) - goto error0; - } - - /* - * If we couldn't get anything, give up. - */ - if (bno_cur_lt == NULL && bno_cur_gt == NULL) { - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); - - if (!forced++) { - trace_xfs_alloc_near_busy(args); - xfs_log_force(args->mp, XFS_LOG_SYNC); - goto restart; - } - trace_xfs_alloc_size_neither(args); - args->agbno = NULLAGBLOCK; - return 0; - } - - /* - * At this point we have selected a freespace entry, either to the - * left or to the right. If it's on the right, copy all the - * useful variables to the "left" set so we only have one - * copy of this code. - */ - if (bno_cur_gt) { - bno_cur_lt = bno_cur_gt; - bno_cur_gt = NULL; - ltbno = gtbno; - ltbnoa = gtbnoa; - ltlen = gtlen; - ltlena = gtlena; - j = 1; - } else - j = 0; - - /* - * Fix up the length and compute the useful address. - */ - args->len = XFS_EXTLEN_MIN(ltlena, args->maxlen); - xfs_alloc_fix_len(args); - if (!xfs_alloc_fix_minleft(args)) { - trace_xfs_alloc_near_nominleft(args); - xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); - return 0; - } - rlen = args->len; - (void)xfs_alloc_compute_diff(args->agbno, rlen, args->alignment, - args->datatype, ltbnoa, ltlena, <new); - ASSERT(ltnew >= ltbno); - ASSERT(ltnew + rlen <= ltbnoa + ltlena); - ASSERT(ltnew + rlen <= be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length)); - ASSERT(ltnew >= args->min_agbno && ltnew <= args->max_agbno); - args->agbno = ltnew; - - if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur_lt, ltbno, ltlen, - ltnew, rlen, XFSA_FIXUP_BNO_OK))) - goto error0; - - if (j) - trace_xfs_alloc_near_greater(args); - else - trace_xfs_alloc_near_lesser(args); - - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); - xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_NOERROR); - return 0; - - error0: - trace_xfs_alloc_near_error(args); - if (cnt_cur != NULL) - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); - if (bno_cur_lt != NULL) - xfs_btree_del_cursor(bno_cur_lt, XFS_BTREE_ERROR); - if (bno_cur_gt != NULL) - xfs_btree_del_cursor(bno_cur_gt, XFS_BTREE_ERROR); - return error; -} - -/* - * Allocate a variable extent anywhere in the allocation group agno. - * Extent's length (returned in len) will be between minlen and maxlen, - * and of the form k * prod + mod unless there's nothing that large. - * Return the starting a.g. block, or NULLAGBLOCK if we can't do it. - */ -STATIC int /* error */ -xfs_alloc_ag_vextent_size( - xfs_alloc_arg_t *args) /* allocation argument structure */ -{ - xfs_btree_cur_t *bno_cur; /* cursor for bno btree */ - xfs_btree_cur_t *cnt_cur; /* cursor for cnt btree */ - int error; /* error result */ - xfs_agblock_t fbno; /* start of found freespace */ - xfs_extlen_t flen; /* length of found freespace */ - int i; /* temp status variable */ - xfs_agblock_t rbno; /* returned block number */ - xfs_extlen_t rlen; /* length of returned extent */ - int forced = 0; - -restart: - /* - * Allocate and initialize a cursor for the by-size btree. - */ - cnt_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, - args->agno, XFS_BTNUM_CNT); - bno_cur = NULL; - - /* - * Look for an entry >= maxlen+alignment-1 blocks. - */ - if ((error = xfs_alloc_lookup_ge(cnt_cur, 0, - args->maxlen + args->alignment - 1, &i))) - goto error0; - - /* - * If none or we have busy extents that we cannot allocate from, then - * we have to settle for a smaller extent. In the case that there are - * no large extents, this will return the last entry in the tree unless - * the tree is empty. In the case that there are only busy large - * extents, this will return the largest small extent unless there - * are no smaller extents available. - */ - if (!i || forced > 1) { - error = xfs_alloc_ag_vextent_small(args, cnt_cur, - &fbno, &flen, &i); - if (error) - goto error0; - if (i == 0 || flen == 0) { - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); - trace_xfs_alloc_size_noentry(args); - return 0; - } - ASSERT(i == 1); - xfs_alloc_compute_aligned(args, fbno, flen, &rbno, &rlen); - } else { - /* - * Search for a non-busy extent that is large enough. - * If we are at low space, don't check, or if we fall of - * the end of the btree, turn off the busy check and - * restart. - */ - for (;;) { - error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen, &i); - if (error) - goto error0; - XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); - - xfs_alloc_compute_aligned(args, fbno, flen, - &rbno, &rlen); - - if (rlen >= args->maxlen) - break; - - error = xfs_btree_increment(cnt_cur, 0, &i); - if (error) - goto error0; - if (i == 0) { - /* - * Our only valid extents must have been busy. - * Make it unbusy by forcing the log out and - * retrying. If we've been here before, forcing - * the log isn't making the extents available, - * which means they have probably been freed in - * this transaction. In that case, we have to - * give up on them and we'll attempt a minlen - * allocation the next time around. - */ - xfs_btree_del_cursor(cnt_cur, - XFS_BTREE_NOERROR); - trace_xfs_alloc_size_busy(args); - if (!forced++) - xfs_log_force(args->mp, XFS_LOG_SYNC); - goto restart; - } - } - } - - /* - * In the first case above, we got the last entry in the - * by-size btree. Now we check to see if the space hits maxlen - * once aligned; if not, we search left for something better. - * This can't happen in the second case above. - */ - rlen = XFS_EXTLEN_MIN(args->maxlen, rlen); - XFS_WANT_CORRUPTED_GOTO(args->mp, rlen == 0 || - (rlen <= flen && rbno + rlen <= fbno + flen), error0); - if (rlen < args->maxlen) { - xfs_agblock_t bestfbno; - xfs_extlen_t bestflen; - xfs_agblock_t bestrbno; - xfs_extlen_t bestrlen; - - bestrlen = rlen; - bestrbno = rbno; - bestflen = flen; - bestfbno = fbno; - for (;;) { - if ((error = xfs_btree_decrement(cnt_cur, 0, &i))) - goto error0; - if (i == 0) - break; - if ((error = xfs_alloc_get_rec(cnt_cur, &fbno, &flen, - &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); - if (flen < bestrlen) - break; - xfs_alloc_compute_aligned(args, fbno, flen, - &rbno, &rlen); - rlen = XFS_EXTLEN_MIN(args->maxlen, rlen); - XFS_WANT_CORRUPTED_GOTO(args->mp, rlen == 0 || - (rlen <= flen && rbno + rlen <= fbno + flen), - error0); - if (rlen > bestrlen) { - bestrlen = rlen; - bestrbno = rbno; - bestflen = flen; - bestfbno = fbno; - if (rlen == args->maxlen) - break; - } - } - if ((error = xfs_alloc_lookup_eq(cnt_cur, bestfbno, bestflen, - &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); - rlen = bestrlen; - rbno = bestrbno; - flen = bestflen; - fbno = bestfbno; - } - args->wasfromfl = 0; - /* - * Fix up the length. - */ - args->len = rlen; - if (rlen < args->minlen) { - if (!forced++) { - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); - trace_xfs_alloc_size_busy(args); - xfs_log_force(args->mp, XFS_LOG_SYNC); - goto restart; - } - goto out_nominleft; - } - xfs_alloc_fix_len(args); - - if (!xfs_alloc_fix_minleft(args)) - goto out_nominleft; - rlen = args->len; - XFS_WANT_CORRUPTED_GOTO(args->mp, rlen <= flen, error0); - /* - * Allocate and initialize a cursor for the by-block tree. - */ - bno_cur = xfs_allocbt_init_cursor(args->mp, args->tp, args->agbp, - args->agno, XFS_BTNUM_BNO); - if ((error = xfs_alloc_fixup_trees(cnt_cur, bno_cur, fbno, flen, - rbno, rlen, XFSA_FIXUP_CNT_OK))) - goto error0; - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); - xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); - cnt_cur = bno_cur = NULL; - args->len = rlen; - args->agbno = rbno; - XFS_WANT_CORRUPTED_GOTO(args->mp, - args->agbno + args->len <= - be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length), - error0); - trace_xfs_alloc_size_done(args); - return 0; - -error0: - trace_xfs_alloc_size_error(args); - if (cnt_cur) - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); - if (bno_cur) - xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); - return error; - -out_nominleft: - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); - trace_xfs_alloc_size_nominleft(args); - args->agbno = NULLAGBLOCK; - return 0; -} - -/* - * Deal with the case where only small freespaces remain. - * Either return the contents of the last freespace record, - * or allocate space from the freelist if there is nothing in the tree. - */ -STATIC int /* error */ -xfs_alloc_ag_vextent_small( - xfs_alloc_arg_t *args, /* allocation argument structure */ - xfs_btree_cur_t *ccur, /* by-size cursor */ - xfs_agblock_t *fbnop, /* result block number */ - xfs_extlen_t *flenp, /* result length */ - int *stat) /* status: 0-freelist, 1-normal/none */ -{ - struct xfs_owner_info oinfo; - struct xfs_perag *pag; - int error; - xfs_agblock_t fbno; - xfs_extlen_t flen; - int i; - - if ((error = xfs_btree_decrement(ccur, 0, &i))) - goto error0; - if (i) { - if ((error = xfs_alloc_get_rec(ccur, &fbno, &flen, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(args->mp, i == 1, error0); - } - /* - * Nothing in the btree, try the freelist. Make sure - * to respect minleft even when pulling from the - * freelist. - */ - else if (args->minlen == 1 && args->alignment == 1 && - args->resv != XFS_AG_RESV_AGFL && - (be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_flcount) - > args->minleft)) { - error = xfs_alloc_get_freelist(args->tp, args->agbp, &fbno, 0); - if (error) - goto error0; - if (fbno != NULLAGBLOCK) { - xfs_extent_busy_reuse(args->mp, args->agno, fbno, 1, - xfs_alloc_allow_busy_reuse(args->datatype)); - - if (xfs_alloc_is_userdata(args->datatype)) { - xfs_buf_t *bp; - - bp = xfs_btree_get_bufs(args->mp, args->tp, - args->agno, fbno, 0); - xfs_trans_binval(args->tp, bp); - } - args->len = 1; - args->agbno = fbno; - XFS_WANT_CORRUPTED_GOTO(args->mp, - args->agbno + args->len <= - be32_to_cpu(XFS_BUF_TO_AGF(args->agbp)->agf_length), - error0); - args->wasfromfl = 1; - trace_xfs_alloc_small_freelist(args); - - /* - * If we're feeding an AGFL block to something that - * doesn't live in the free space, we need to clear - * out the OWN_AG rmap and add the block back to - * the AGFL per-AG reservation. - */ - xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_AG); - error = xfs_rmap_free(args->tp, args->agbp, args->agno, - fbno, 1, &oinfo); - if (error) - goto error0; - pag = xfs_perag_get(args->mp, args->agno); - xfs_ag_resv_free_extent(pag, XFS_AG_RESV_AGFL, - args->tp, 1); - xfs_perag_put(pag); - - *stat = 0; - return 0; - } - /* - * Nothing in the freelist. - */ - else - flen = 0; - } - /* - * Can't allocate from the freelist for some reason. - */ - else { - fbno = NULLAGBLOCK; - flen = 0; - } - /* - * Can't do the allocation, give up. - */ - if (flen < args->minlen) { - args->agbno = NULLAGBLOCK; - trace_xfs_alloc_small_notenough(args); - flen = 0; - } - *fbnop = fbno; - *flenp = flen; - *stat = 1; - trace_xfs_alloc_small_done(args); - return 0; - -error0: - trace_xfs_alloc_small_error(args); - return error; -} - -/* - * Free the extent starting at agno/bno for length. - */ -STATIC int -xfs_free_ag_extent( - xfs_trans_t *tp, - xfs_buf_t *agbp, - xfs_agnumber_t agno, - xfs_agblock_t bno, - xfs_extlen_t len, - struct xfs_owner_info *oinfo, - enum xfs_ag_resv_type type) -{ - xfs_btree_cur_t *bno_cur; /* cursor for by-block btree */ - xfs_btree_cur_t *cnt_cur; /* cursor for by-size btree */ - int error; /* error return value */ - xfs_agblock_t gtbno; /* start of right neighbor block */ - xfs_extlen_t gtlen; /* length of right neighbor block */ - int haveleft; /* have a left neighbor block */ - int haveright; /* have a right neighbor block */ - int i; /* temp, result code */ - xfs_agblock_t ltbno; /* start of left neighbor block */ - xfs_extlen_t ltlen; /* length of left neighbor block */ - xfs_mount_t *mp; /* mount point struct for filesystem */ - xfs_agblock_t nbno; /* new starting block of freespace */ - xfs_extlen_t nlen; /* new length of freespace */ - xfs_perag_t *pag; /* per allocation group data */ - - bno_cur = cnt_cur = NULL; - mp = tp->t_mountp; - - if (oinfo->oi_owner != XFS_RMAP_OWN_UNKNOWN) { - error = xfs_rmap_free(tp, agbp, agno, bno, len, oinfo); - if (error) - goto error0; - } - - /* - * Allocate and initialize a cursor for the by-block btree. - */ - bno_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_BNO); - /* - * Look for a neighboring block on the left (lower block numbers) - * that is contiguous with this space. - */ - if ((error = xfs_alloc_lookup_le(bno_cur, bno, len, &haveleft))) - goto error0; - if (haveleft) { - /* - * There is a block to our left. - */ - if ((error = xfs_alloc_get_rec(bno_cur, <bno, <len, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - /* - * It's not contiguous, though. - */ - if (ltbno + ltlen < bno) - haveleft = 0; - else { - /* - * If this failure happens the request to free this - * space was invalid, it's (partly) already free. - * Very bad. - */ - XFS_WANT_CORRUPTED_GOTO(mp, - ltbno + ltlen <= bno, error0); - } - } - /* - * Look for a neighboring block on the right (higher block numbers) - * that is contiguous with this space. - */ - if ((error = xfs_btree_increment(bno_cur, 0, &haveright))) - goto error0; - if (haveright) { - /* - * There is a block to our right. - */ - if ((error = xfs_alloc_get_rec(bno_cur, >bno, >len, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - /* - * It's not contiguous, though. - */ - if (bno + len < gtbno) - haveright = 0; - else { - /* - * If this failure happens the request to free this - * space was invalid, it's (partly) already free. - * Very bad. - */ - XFS_WANT_CORRUPTED_GOTO(mp, gtbno >= bno + len, error0); - } - } - /* - * Now allocate and initialize a cursor for the by-size tree. - */ - cnt_cur = xfs_allocbt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_CNT); - /* - * Have both left and right contiguous neighbors. - * Merge all three into a single free block. - */ - if (haveleft && haveright) { - /* - * Delete the old by-size entry on the left. - */ - if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - if ((error = xfs_btree_delete(cnt_cur, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - /* - * Delete the old by-size entry on the right. - */ - if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - if ((error = xfs_btree_delete(cnt_cur, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - /* - * Delete the old by-block entry for the right block. - */ - if ((error = xfs_btree_delete(bno_cur, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - /* - * Move the by-block cursor back to the left neighbor. - */ - if ((error = xfs_btree_decrement(bno_cur, 0, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); -#ifdef DEBUG - /* - * Check that this is the right record: delete didn't - * mangle the cursor. - */ - { - xfs_agblock_t xxbno; - xfs_extlen_t xxlen; - - if ((error = xfs_alloc_get_rec(bno_cur, &xxbno, &xxlen, - &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, - i == 1 && xxbno == ltbno && xxlen == ltlen, - error0); - } -#endif - /* - * Update remaining by-block entry to the new, joined block. - */ - nbno = ltbno; - nlen = len + ltlen + gtlen; - if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) - goto error0; - } - /* - * Have only a left contiguous neighbor. - * Merge it together with the new freespace. - */ - else if (haveleft) { - /* - * Delete the old by-size entry on the left. - */ - if ((error = xfs_alloc_lookup_eq(cnt_cur, ltbno, ltlen, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - if ((error = xfs_btree_delete(cnt_cur, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - /* - * Back up the by-block cursor to the left neighbor, and - * update its length. - */ - if ((error = xfs_btree_decrement(bno_cur, 0, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - nbno = ltbno; - nlen = len + ltlen; - if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) - goto error0; - } - /* - * Have only a right contiguous neighbor. - * Merge it together with the new freespace. - */ - else if (haveright) { - /* - * Delete the old by-size entry on the right. - */ - if ((error = xfs_alloc_lookup_eq(cnt_cur, gtbno, gtlen, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - if ((error = xfs_btree_delete(cnt_cur, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - /* - * Update the starting block and length of the right - * neighbor in the by-block tree. - */ - nbno = bno; - nlen = len + gtlen; - if ((error = xfs_alloc_update(bno_cur, nbno, nlen))) - goto error0; - } - /* - * No contiguous neighbors. - * Insert the new freespace into the by-block tree. - */ - else { - nbno = bno; - nlen = len; - if ((error = xfs_btree_insert(bno_cur, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - } - xfs_btree_del_cursor(bno_cur, XFS_BTREE_NOERROR); - bno_cur = NULL; - /* - * In all cases we need to insert the new freespace in the by-size tree. - */ - if ((error = xfs_alloc_lookup_eq(cnt_cur, nbno, nlen, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 0, error0); - if ((error = xfs_btree_insert(cnt_cur, &i))) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_NOERROR); - cnt_cur = NULL; - - /* - * Update the freespace totals in the ag and superblock. - */ - pag = xfs_perag_get(mp, agno); - error = xfs_alloc_update_counters(tp, pag, agbp, len); - xfs_ag_resv_free_extent(pag, type, tp, len); - xfs_perag_put(pag); - if (error) - goto error0; - - XFS_STATS_INC(mp, xs_freex); - XFS_STATS_ADD(mp, xs_freeb, len); - - trace_xfs_free_extent(mp, agno, bno, len, type == XFS_AG_RESV_AGFL, - haveleft, haveright); - - return 0; - - error0: - trace_xfs_free_extent(mp, agno, bno, len, type == XFS_AG_RESV_AGFL, - -1, -1); - if (bno_cur) - xfs_btree_del_cursor(bno_cur, XFS_BTREE_ERROR); - if (cnt_cur) - xfs_btree_del_cursor(cnt_cur, XFS_BTREE_ERROR); - return error; -} - -/* - * Visible (exported) allocation/free functions. - * Some of these are used just by xfs_alloc_btree.c and this file. - */ - -/* - * Compute and fill in value of m_ag_maxlevels. - */ -void -xfs_alloc_compute_maxlevels( - xfs_mount_t *mp) /* file system mount structure */ -{ - mp->m_ag_maxlevels = xfs_btree_compute_maxlevels(mp, mp->m_alloc_mnr, - (mp->m_sb.sb_agblocks + 1) / 2); -} - -/* - * Find the length of the longest extent in an AG. The 'need' parameter - * specifies how much space we're going to need for the AGFL and the - * 'reserved' parameter tells us how many blocks in this AG are reserved for - * other callers. - */ -xfs_extlen_t -xfs_alloc_longest_free_extent( - struct xfs_mount *mp, - struct xfs_perag *pag, - xfs_extlen_t need, - xfs_extlen_t reserved) -{ - xfs_extlen_t delta = 0; - - /* - * If the AGFL needs a recharge, we'll have to subtract that from the - * longest extent. - */ - if (need > pag->pagf_flcount) - delta = need - pag->pagf_flcount; - - /* - * If we cannot maintain others' reservations with space from the - * not-longest freesp extents, we'll have to subtract /that/ from - * the longest extent too. - */ - if (pag->pagf_freeblks - pag->pagf_longest < reserved) - delta += reserved - (pag->pagf_freeblks - pag->pagf_longest); - - /* - * If the longest extent is long enough to satisfy all the - * reservations and AGFL rules in place, we can return this extent. - */ - if (pag->pagf_longest > delta) - return pag->pagf_longest - delta; - - /* Otherwise, let the caller try for 1 block if there's space. */ - return pag->pagf_flcount > 0 || pag->pagf_longest > 0; -} - -unsigned int -xfs_alloc_min_freelist( - struct xfs_mount *mp, - struct xfs_perag *pag) -{ - unsigned int min_free; - - /* space needed by-bno freespace btree */ - min_free = min_t(unsigned int, pag->pagf_levels[XFS_BTNUM_BNOi] + 1, - mp->m_ag_maxlevels); - /* space needed by-size freespace btree */ - min_free += min_t(unsigned int, pag->pagf_levels[XFS_BTNUM_CNTi] + 1, - mp->m_ag_maxlevels); - /* space needed reverse mapping used space btree */ - if (xfs_sb_version_hasrmapbt(&mp->m_sb)) - min_free += min_t(unsigned int, - pag->pagf_levels[XFS_BTNUM_RMAPi] + 1, - mp->m_rmap_maxlevels); - - return min_free; -} - -/* - * Check if the operation we are fixing up the freelist for should go ahead or - * not. If we are freeing blocks, we always allow it, otherwise the allocation - * is dependent on whether the size and shape of free space available will - * permit the requested allocation to take place. - */ -static bool -xfs_alloc_space_available( - struct xfs_alloc_arg *args, - xfs_extlen_t min_free, - int flags) -{ - struct xfs_perag *pag = args->pag; - xfs_extlen_t longest; - xfs_extlen_t reservation; /* blocks that are still reserved */ - int available; - - if (flags & XFS_ALLOC_FLAG_FREEING) - return true; - - reservation = xfs_ag_resv_needed(pag, args->resv); - - /* do we have enough contiguous free space for the allocation? */ - longest = xfs_alloc_longest_free_extent(args->mp, pag, min_free, - reservation); - if ((args->minlen + args->alignment + args->minalignslop - 1) > longest) - return false; - - /* do we have enough free space remaining for the allocation? */ - available = (int)(pag->pagf_freeblks + pag->pagf_flcount - - reservation - min_free - args->total); - if (available < (int)args->minleft || available <= 0) - return false; - - return true; -} - -/* - * Decide whether to use this allocation group for this allocation. - * If so, fix up the btree freelist's size. - */ -int /* error */ -xfs_alloc_fix_freelist( - struct xfs_alloc_arg *args, /* allocation argument structure */ - int flags) /* XFS_ALLOC_FLAG_... */ -{ - struct xfs_mount *mp = args->mp; - struct xfs_perag *pag = args->pag; - struct xfs_trans *tp = args->tp; - struct xfs_buf *agbp = NULL; - struct xfs_buf *agflbp = NULL; - struct xfs_alloc_arg targs; /* local allocation arguments */ - xfs_agblock_t bno; /* freelist block */ - xfs_extlen_t need; /* total blocks needed in freelist */ - int error = 0; - - if (!pag->pagf_init) { - error = xfs_alloc_read_agf(mp, tp, args->agno, flags, &agbp); - if (error) - goto out_no_agbp; - if (!pag->pagf_init) { - ASSERT(flags & XFS_ALLOC_FLAG_TRYLOCK); - ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING)); - goto out_agbp_relse; - } - } - - /* - * If this is a metadata preferred pag and we are user data then try - * somewhere else if we are not being asked to try harder at this - * point - */ - if (pag->pagf_metadata && xfs_alloc_is_userdata(args->datatype) && - (flags & XFS_ALLOC_FLAG_TRYLOCK)) { - ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING)); - goto out_agbp_relse; - } - - need = xfs_alloc_min_freelist(mp, pag); - if (!xfs_alloc_space_available(args, need, flags)) - goto out_agbp_relse; - - /* - * Get the a.g. freespace buffer. - * Can fail if we're not blocking on locks, and it's held. - */ - if (!agbp) { - error = xfs_alloc_read_agf(mp, tp, args->agno, flags, &agbp); - if (error) - goto out_no_agbp; - if (!agbp) { - ASSERT(flags & XFS_ALLOC_FLAG_TRYLOCK); - ASSERT(!(flags & XFS_ALLOC_FLAG_FREEING)); - goto out_no_agbp; - } - } - - /* If there isn't enough total space or single-extent, reject it. */ - need = xfs_alloc_min_freelist(mp, pag); - if (!xfs_alloc_space_available(args, need, flags)) - goto out_agbp_relse; - - /* - * Make the freelist shorter if it's too long. - * - * Note that from this point onwards, we will always release the agf and - * agfl buffers on error. This handles the case where we error out and - * the buffers are clean or may not have been joined to the transaction - * and hence need to be released manually. If they have been joined to - * the transaction, then xfs_trans_brelse() will handle them - * appropriately based on the recursion count and dirty state of the - * buffer. - * - * XXX (dgc): When we have lots of free space, does this buy us - * anything other than extra overhead when we need to put more blocks - * back on the free list? Maybe we should only do this when space is - * getting low or the AGFL is more than half full? - * - * The NOSHRINK flag prevents the AGFL from being shrunk if it's too - * big; the NORMAP flag prevents AGFL expand/shrink operations from - * updating the rmapbt. Both flags are used in xfs_repair while we're - * rebuilding the rmapbt, and neither are used by the kernel. They're - * both required to ensure that rmaps are correctly recorded for the - * regenerated AGFL, bnobt, and cntbt. See repair/phase5.c and - * repair/rmap.c in xfsprogs for details. - */ - memset(&targs, 0, sizeof(targs)); - if (flags & XFS_ALLOC_FLAG_NORMAP) - xfs_rmap_skip_owner_update(&targs.oinfo); - else - xfs_rmap_ag_owner(&targs.oinfo, XFS_RMAP_OWN_AG); - while (!(flags & XFS_ALLOC_FLAG_NOSHRINK) && pag->pagf_flcount > need) { - struct xfs_buf *bp; - - error = xfs_alloc_get_freelist(tp, agbp, &bno, 0); - if (error) - goto out_agbp_relse; - error = xfs_free_ag_extent(tp, agbp, args->agno, bno, 1, - &targs.oinfo, XFS_AG_RESV_AGFL); - if (error) - goto out_agbp_relse; - bp = xfs_btree_get_bufs(mp, tp, args->agno, bno, 0); - xfs_trans_binval(tp, bp); - } - - targs.tp = tp; - targs.mp = mp; - targs.agbp = agbp; - targs.agno = args->agno; - targs.alignment = targs.minlen = targs.prod = 1; - targs.type = XFS_ALLOCTYPE_THIS_AG; - targs.pag = pag; - error = xfs_alloc_read_agfl(mp, tp, targs.agno, &agflbp); - if (error) - goto out_agbp_relse; - - /* Make the freelist longer if it's too short. */ - while (pag->pagf_flcount < need) { - targs.agbno = 0; - targs.maxlen = need - pag->pagf_flcount; - targs.resv = XFS_AG_RESV_AGFL; - - /* Allocate as many blocks as possible at once. */ - error = xfs_alloc_ag_vextent(&targs); - if (error) - goto out_agflbp_relse; - - /* - * Stop if we run out. Won't happen if callers are obeying - * the restrictions correctly. Can happen for free calls - * on a completely full ag. - */ - if (targs.agbno == NULLAGBLOCK) { - if (flags & XFS_ALLOC_FLAG_FREEING) - break; - goto out_agflbp_relse; - } - /* - * Put each allocated block on the list. - */ - for (bno = targs.agbno; bno < targs.agbno + targs.len; bno++) { - error = xfs_alloc_put_freelist(tp, agbp, - agflbp, bno, 0); - if (error) - goto out_agflbp_relse; - } - } - xfs_trans_brelse(tp, agflbp); - args->agbp = agbp; - return 0; - -out_agflbp_relse: - xfs_trans_brelse(tp, agflbp); -out_agbp_relse: - if (agbp) - xfs_trans_brelse(tp, agbp); -out_no_agbp: - args->agbp = NULL; - return error; -} - -/* - * Get a block from the freelist. - * Returns with the buffer for the block gotten. - */ -int /* error */ -xfs_alloc_get_freelist( - xfs_trans_t *tp, /* transaction pointer */ - xfs_buf_t *agbp, /* buffer containing the agf structure */ - xfs_agblock_t *bnop, /* block address retrieved from freelist */ - int btreeblk) /* destination is a AGF btree */ -{ - xfs_agf_t *agf; /* a.g. freespace structure */ - xfs_buf_t *agflbp;/* buffer for a.g. freelist structure */ - xfs_agblock_t bno; /* block number returned */ - __be32 *agfl_bno; - int error; - int logflags; - xfs_mount_t *mp = tp->t_mountp; - xfs_perag_t *pag; /* per allocation group data */ - - /* - * Freelist is empty, give up. - */ - agf = XFS_BUF_TO_AGF(agbp); - if (!agf->agf_flcount) { - *bnop = NULLAGBLOCK; - return 0; - } - /* - * Read the array of free blocks. - */ - error = xfs_alloc_read_agfl(mp, tp, be32_to_cpu(agf->agf_seqno), - &agflbp); - if (error) - return error; - - - /* - * Get the block number and update the data structures. - */ - agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agflbp); - bno = be32_to_cpu(agfl_bno[be32_to_cpu(agf->agf_flfirst)]); - be32_add_cpu(&agf->agf_flfirst, 1); - xfs_trans_brelse(tp, agflbp); - if (be32_to_cpu(agf->agf_flfirst) == XFS_AGFL_SIZE(mp)) - agf->agf_flfirst = 0; - - pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno)); - be32_add_cpu(&agf->agf_flcount, -1); - xfs_trans_agflist_delta(tp, -1); - pag->pagf_flcount--; - xfs_perag_put(pag); - - logflags = XFS_AGF_FLFIRST | XFS_AGF_FLCOUNT; - if (btreeblk) { - be32_add_cpu(&agf->agf_btreeblks, 1); - pag->pagf_btreeblks++; - logflags |= XFS_AGF_BTREEBLKS; - } - - xfs_alloc_log_agf(tp, agbp, logflags); - *bnop = bno; - - return 0; -} - -/* - * Log the given fields from the agf structure. - */ -void -xfs_alloc_log_agf( - xfs_trans_t *tp, /* transaction pointer */ - xfs_buf_t *bp, /* buffer for a.g. freelist header */ - int fields) /* mask of fields to be logged (XFS_AGF_...) */ -{ - int first; /* first byte offset */ - int last; /* last byte offset */ - static const short offsets[] = { - offsetof(xfs_agf_t, agf_magicnum), - offsetof(xfs_agf_t, agf_versionnum), - offsetof(xfs_agf_t, agf_seqno), - offsetof(xfs_agf_t, agf_length), - offsetof(xfs_agf_t, agf_roots[0]), - offsetof(xfs_agf_t, agf_levels[0]), - offsetof(xfs_agf_t, agf_flfirst), - offsetof(xfs_agf_t, agf_fllast), - offsetof(xfs_agf_t, agf_flcount), - offsetof(xfs_agf_t, agf_freeblks), - offsetof(xfs_agf_t, agf_longest), - offsetof(xfs_agf_t, agf_btreeblks), - offsetof(xfs_agf_t, agf_uuid), - offsetof(xfs_agf_t, agf_rmap_blocks), - offsetof(xfs_agf_t, agf_refcount_blocks), - offsetof(xfs_agf_t, agf_refcount_root), - offsetof(xfs_agf_t, agf_refcount_level), - /* needed so that we don't log the whole rest of the structure: */ - offsetof(xfs_agf_t, agf_spare64), - sizeof(xfs_agf_t) - }; - - trace_xfs_agf(tp->t_mountp, XFS_BUF_TO_AGF(bp), fields, _RET_IP_); - - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_AGF_BUF); - - xfs_btree_offsets(fields, offsets, XFS_AGF_NUM_BITS, &first, &last); - xfs_trans_log_buf(tp, bp, (uint)first, (uint)last); -} - -/* - * Interface for inode allocation to force the pag data to be initialized. - */ -int /* error */ -xfs_alloc_pagf_init( - xfs_mount_t *mp, /* file system mount structure */ - xfs_trans_t *tp, /* transaction pointer */ - xfs_agnumber_t agno, /* allocation group number */ - int flags) /* XFS_ALLOC_FLAGS_... */ -{ - xfs_buf_t *bp; - int error; - - if ((error = xfs_alloc_read_agf(mp, tp, agno, flags, &bp))) - return error; - if (bp) - xfs_trans_brelse(tp, bp); - return 0; -} - -/* - * Put the block on the freelist for the allocation group. - */ -int /* error */ -xfs_alloc_put_freelist( - xfs_trans_t *tp, /* transaction pointer */ - xfs_buf_t *agbp, /* buffer for a.g. freelist header */ - xfs_buf_t *agflbp,/* buffer for a.g. free block array */ - xfs_agblock_t bno, /* block being freed */ - int btreeblk) /* block came from a AGF btree */ -{ - xfs_agf_t *agf; /* a.g. freespace structure */ - __be32 *blockp;/* pointer to array entry */ - int error; - int logflags; - xfs_mount_t *mp; /* mount structure */ - xfs_perag_t *pag; /* per allocation group data */ - __be32 *agfl_bno; - int startoff; - - agf = XFS_BUF_TO_AGF(agbp); - mp = tp->t_mountp; - - if (!agflbp && (error = xfs_alloc_read_agfl(mp, tp, - be32_to_cpu(agf->agf_seqno), &agflbp))) - return error; - be32_add_cpu(&agf->agf_fllast, 1); - if (be32_to_cpu(agf->agf_fllast) == XFS_AGFL_SIZE(mp)) - agf->agf_fllast = 0; - - pag = xfs_perag_get(mp, be32_to_cpu(agf->agf_seqno)); - be32_add_cpu(&agf->agf_flcount, 1); - xfs_trans_agflist_delta(tp, 1); - pag->pagf_flcount++; - - logflags = XFS_AGF_FLLAST | XFS_AGF_FLCOUNT; - if (btreeblk) { - be32_add_cpu(&agf->agf_btreeblks, -1); - pag->pagf_btreeblks--; - logflags |= XFS_AGF_BTREEBLKS; - } - xfs_perag_put(pag); - - xfs_alloc_log_agf(tp, agbp, logflags); - - ASSERT(be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp)); - - agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, agflbp); - blockp = &agfl_bno[be32_to_cpu(agf->agf_fllast)]; - *blockp = cpu_to_be32(bno); - startoff = (char *)blockp - (char *)agflbp->b_addr; - - xfs_alloc_log_agf(tp, agbp, logflags); - - xfs_trans_buf_set_type(tp, agflbp, XFS_BLFT_AGFL_BUF); - xfs_trans_log_buf(tp, agflbp, startoff, - startoff + sizeof(xfs_agblock_t) - 1); - return 0; -} - -static bool -xfs_agf_verify( - struct xfs_mount *mp, - struct xfs_buf *bp) - { - struct xfs_agf *agf = XFS_BUF_TO_AGF(bp); - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - if (!uuid_equal(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid)) - return false; - if (!xfs_log_check_lsn(mp, - be64_to_cpu(XFS_BUF_TO_AGF(bp)->agf_lsn))) - return false; - } - - if (!(agf->agf_magicnum == cpu_to_be32(XFS_AGF_MAGIC) && - XFS_AGF_GOOD_VERSION(be32_to_cpu(agf->agf_versionnum)) && - be32_to_cpu(agf->agf_freeblks) <= be32_to_cpu(agf->agf_length) && - be32_to_cpu(agf->agf_flfirst) < XFS_AGFL_SIZE(mp) && - be32_to_cpu(agf->agf_fllast) < XFS_AGFL_SIZE(mp) && - be32_to_cpu(agf->agf_flcount) <= XFS_AGFL_SIZE(mp))) - return false; - - if (be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]) > XFS_BTREE_MAXLEVELS || - be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]) > XFS_BTREE_MAXLEVELS) - return false; - - if (xfs_sb_version_hasrmapbt(&mp->m_sb) && - be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]) > XFS_BTREE_MAXLEVELS) - return false; - - /* - * during growfs operations, the perag is not fully initialised, - * so we can't use it for any useful checking. growfs ensures we can't - * use it by using uncached buffers that don't have the perag attached - * so we can detect and avoid this problem. - */ - if (bp->b_pag && be32_to_cpu(agf->agf_seqno) != bp->b_pag->pag_agno) - return false; - - if (xfs_sb_version_haslazysbcount(&mp->m_sb) && - be32_to_cpu(agf->agf_btreeblks) > be32_to_cpu(agf->agf_length)) - return false; - - if (xfs_sb_version_hasreflink(&mp->m_sb) && - be32_to_cpu(agf->agf_refcount_level) > XFS_BTREE_MAXLEVELS) - return false; - - return true;; - -} - -static void -xfs_agf_read_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - - if (xfs_sb_version_hascrc(&mp->m_sb) && - !xfs_buf_verify_cksum(bp, XFS_AGF_CRC_OFF)) - xfs_buf_ioerror(bp, -EFSBADCRC); - else if (XFS_TEST_ERROR(!xfs_agf_verify(mp, bp), mp, - XFS_ERRTAG_ALLOC_READ_AGF, - XFS_RANDOM_ALLOC_READ_AGF)) - xfs_buf_ioerror(bp, -EFSCORRUPTED); - - if (bp->b_error) - xfs_verifier_error(bp); -} - -static void -xfs_agf_write_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_buf_log_item *bip = bp->b_fspriv; - - if (!xfs_agf_verify(mp, bp)) { - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - return; - } - - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return; - - if (bip) - XFS_BUF_TO_AGF(bp)->agf_lsn = cpu_to_be64(bip->bli_item.li_lsn); - - xfs_buf_update_cksum(bp, XFS_AGF_CRC_OFF); -} - -const struct xfs_buf_ops xfs_agf_buf_ops = { - .name = "xfs_agf", - .verify_read = xfs_agf_read_verify, - .verify_write = xfs_agf_write_verify, -}; - -/* - * Read in the allocation group header (free/alloc section). - */ -int /* error */ -xfs_read_agf( - struct xfs_mount *mp, /* mount point structure */ - struct xfs_trans *tp, /* transaction pointer */ - xfs_agnumber_t agno, /* allocation group number */ - int flags, /* XFS_BUF_ */ - struct xfs_buf **bpp) /* buffer for the ag freelist header */ -{ - int error; - - trace_xfs_read_agf(mp, agno); - - ASSERT(agno != NULLAGNUMBER); - error = xfs_trans_read_buf( - mp, tp, mp->m_ddev_targp, - XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), - XFS_FSS_TO_BB(mp, 1), flags, bpp, &xfs_agf_buf_ops); - if (error) - return error; - if (!*bpp) - return 0; - - ASSERT(!(*bpp)->b_error); - xfs_buf_set_ref(*bpp, XFS_AGF_REF); - return 0; -} - -/* - * Read in the allocation group header (free/alloc section). - */ -int /* error */ -xfs_alloc_read_agf( - struct xfs_mount *mp, /* mount point structure */ - struct xfs_trans *tp, /* transaction pointer */ - xfs_agnumber_t agno, /* allocation group number */ - int flags, /* XFS_ALLOC_FLAG_... */ - struct xfs_buf **bpp) /* buffer for the ag freelist header */ -{ - struct xfs_agf *agf; /* ag freelist header */ - struct xfs_perag *pag; /* per allocation group data */ - int error; - - trace_xfs_alloc_read_agf(mp, agno); - - ASSERT(agno != NULLAGNUMBER); - error = xfs_read_agf(mp, tp, agno, - (flags & XFS_ALLOC_FLAG_TRYLOCK) ? XBF_TRYLOCK : 0, - bpp); - if (error) - return error; - if (!*bpp) - return 0; - ASSERT(!(*bpp)->b_error); - - agf = XFS_BUF_TO_AGF(*bpp); - pag = xfs_perag_get(mp, agno); - if (!pag->pagf_init) { - pag->pagf_freeblks = be32_to_cpu(agf->agf_freeblks); - pag->pagf_btreeblks = be32_to_cpu(agf->agf_btreeblks); - pag->pagf_flcount = be32_to_cpu(agf->agf_flcount); - pag->pagf_longest = be32_to_cpu(agf->agf_longest); - pag->pagf_levels[XFS_BTNUM_BNOi] = - be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNOi]); - pag->pagf_levels[XFS_BTNUM_CNTi] = - be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi]); - pag->pagf_levels[XFS_BTNUM_RMAPi] = - be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAPi]); - pag->pagf_refcount_level = be32_to_cpu(agf->agf_refcount_level); - spin_lock_init(&pag->pagb_lock); - pag->pagb_count = 0; - pag->pagb_tree = RB_ROOT; - pag->pagf_init = 1; - } -#ifdef DEBUG - else if (!XFS_FORCED_SHUTDOWN(mp)) { - ASSERT(pag->pagf_freeblks == be32_to_cpu(agf->agf_freeblks)); - ASSERT(pag->pagf_btreeblks == be32_to_cpu(agf->agf_btreeblks)); - ASSERT(pag->pagf_flcount == be32_to_cpu(agf->agf_flcount)); - ASSERT(pag->pagf_longest == be32_to_cpu(agf->agf_longest)); - ASSERT(pag->pagf_levels[XFS_BTNUM_BNOi] == - be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNOi])); - ASSERT(pag->pagf_levels[XFS_BTNUM_CNTi] == - be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNTi])); - } -#endif - xfs_perag_put(pag); - return 0; -} - -/* - * Allocate an extent (variable-size). - * Depending on the allocation type, we either look in a single allocation - * group or loop over the allocation groups to find the result. - */ -int /* error */ -xfs_alloc_vextent( - xfs_alloc_arg_t *args) /* allocation argument structure */ -{ - xfs_agblock_t agsize; /* allocation group size */ - int error; - int flags; /* XFS_ALLOC_FLAG_... locking flags */ - xfs_extlen_t minleft;/* minimum left value, temp copy */ - xfs_mount_t *mp; /* mount structure pointer */ - xfs_agnumber_t sagno; /* starting allocation group number */ - xfs_alloctype_t type; /* input allocation type */ - int bump_rotor = 0; - int no_min = 0; - xfs_agnumber_t rotorstep = xfs_rotorstep; /* inode32 agf stepper */ - - mp = args->mp; - type = args->otype = args->type; - args->agbno = NULLAGBLOCK; - /* - * Just fix this up, for the case where the last a.g. is shorter - * (or there's only one a.g.) and the caller couldn't easily figure - * that out (xfs_bmap_alloc). - */ - agsize = mp->m_sb.sb_agblocks; - if (args->maxlen > agsize) - args->maxlen = agsize; - if (args->alignment == 0) - args->alignment = 1; - ASSERT(XFS_FSB_TO_AGNO(mp, args->fsbno) < mp->m_sb.sb_agcount); - ASSERT(XFS_FSB_TO_AGBNO(mp, args->fsbno) < agsize); - ASSERT(args->minlen <= args->maxlen); - ASSERT(args->minlen <= agsize); - ASSERT(args->mod < args->prod); - if (XFS_FSB_TO_AGNO(mp, args->fsbno) >= mp->m_sb.sb_agcount || - XFS_FSB_TO_AGBNO(mp, args->fsbno) >= agsize || - args->minlen > args->maxlen || args->minlen > agsize || - args->mod >= args->prod) { - args->fsbno = NULLFSBLOCK; - trace_xfs_alloc_vextent_badargs(args); - return 0; - } - minleft = args->minleft; - - switch (type) { - case XFS_ALLOCTYPE_THIS_AG: - case XFS_ALLOCTYPE_NEAR_BNO: - case XFS_ALLOCTYPE_THIS_BNO: - /* - * These three force us into a single a.g. - */ - args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); - args->pag = xfs_perag_get(mp, args->agno); - args->minleft = 0; - error = xfs_alloc_fix_freelist(args, 0); - args->minleft = minleft; - if (error) { - trace_xfs_alloc_vextent_nofix(args); - goto error0; - } - if (!args->agbp) { - trace_xfs_alloc_vextent_noagbp(args); - break; - } - args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); - if ((error = xfs_alloc_ag_vextent(args))) - goto error0; - break; - case XFS_ALLOCTYPE_START_BNO: - /* - * Try near allocation first, then anywhere-in-ag after - * the first a.g. fails. - */ - if ((args->datatype & XFS_ALLOC_INITIAL_USER_DATA) && - (mp->m_flags & XFS_MOUNT_32BITINODES)) { - args->fsbno = XFS_AGB_TO_FSB(mp, - ((mp->m_agfrotor / rotorstep) % - mp->m_sb.sb_agcount), 0); - bump_rotor = 1; - } - args->agbno = XFS_FSB_TO_AGBNO(mp, args->fsbno); - args->type = XFS_ALLOCTYPE_NEAR_BNO; - /* FALLTHROUGH */ - case XFS_ALLOCTYPE_ANY_AG: - case XFS_ALLOCTYPE_START_AG: - case XFS_ALLOCTYPE_FIRST_AG: - /* - * Rotate through the allocation groups looking for a winner. - */ - if (type == XFS_ALLOCTYPE_ANY_AG) { - /* - * Start with the last place we left off. - */ - args->agno = sagno = (mp->m_agfrotor / rotorstep) % - mp->m_sb.sb_agcount; - args->type = XFS_ALLOCTYPE_THIS_AG; - flags = XFS_ALLOC_FLAG_TRYLOCK; - } else if (type == XFS_ALLOCTYPE_FIRST_AG) { - /* - * Start with allocation group given by bno. - */ - args->agno = XFS_FSB_TO_AGNO(mp, args->fsbno); - args->type = XFS_ALLOCTYPE_THIS_AG; - sagno = 0; - flags = 0; - } else { - if (type == XFS_ALLOCTYPE_START_AG) - args->type = XFS_ALLOCTYPE_THIS_AG; - /* - * Start with the given allocation group. - */ - args->agno = sagno = XFS_FSB_TO_AGNO(mp, args->fsbno); - flags = XFS_ALLOC_FLAG_TRYLOCK; - } - /* - * Loop over allocation groups twice; first time with - * trylock set, second time without. - */ - for (;;) { - args->pag = xfs_perag_get(mp, args->agno); - if (no_min) args->minleft = 0; - error = xfs_alloc_fix_freelist(args, flags); - args->minleft = minleft; - if (error) { - trace_xfs_alloc_vextent_nofix(args); - goto error0; - } - /* - * If we get a buffer back then the allocation will fly. - */ - if (args->agbp) { - if ((error = xfs_alloc_ag_vextent(args))) - goto error0; - break; - } - - trace_xfs_alloc_vextent_loopfailed(args); - - /* - * Didn't work, figure out the next iteration. - */ - if (args->agno == sagno && - type == XFS_ALLOCTYPE_START_BNO) - args->type = XFS_ALLOCTYPE_THIS_AG; - /* - * For the first allocation, we can try any AG to get - * space. However, if we already have allocated a - * block, we don't want to try AGs whose number is below - * sagno. Otherwise, we may end up with out-of-order - * locking of AGF, which might cause deadlock. - */ - if (++(args->agno) == mp->m_sb.sb_agcount) { - if (args->firstblock != NULLFSBLOCK) - args->agno = sagno; - else - args->agno = 0; - } - /* - * Reached the starting a.g., must either be done - * or switch to non-trylock mode. - */ - if (args->agno == sagno) { - if (no_min == 1) { - args->agbno = NULLAGBLOCK; - trace_xfs_alloc_vextent_allfailed(args); - break; - } - if (flags == 0) { - no_min = 1; - } else { - flags = 0; - if (type == XFS_ALLOCTYPE_START_BNO) { - args->agbno = XFS_FSB_TO_AGBNO(mp, - args->fsbno); - args->type = XFS_ALLOCTYPE_NEAR_BNO; - } - } - } - xfs_perag_put(args->pag); - } - if (bump_rotor || (type == XFS_ALLOCTYPE_ANY_AG)) { - if (args->agno == sagno) - mp->m_agfrotor = (mp->m_agfrotor + 1) % - (mp->m_sb.sb_agcount * rotorstep); - else - mp->m_agfrotor = (args->agno * rotorstep + 1) % - (mp->m_sb.sb_agcount * rotorstep); - } - break; - default: - ASSERT(0); - /* NOTREACHED */ - } - if (args->agbno == NULLAGBLOCK) - args->fsbno = NULLFSBLOCK; - else { - args->fsbno = XFS_AGB_TO_FSB(mp, args->agno, args->agbno); -#ifdef DEBUG - ASSERT(args->len >= args->minlen); - ASSERT(args->len <= args->maxlen); - ASSERT(args->agbno % args->alignment == 0); - XFS_AG_CHECK_DADDR(mp, XFS_FSB_TO_DADDR(mp, args->fsbno), - args->len); -#endif - - /* Zero the extent if we were asked to do so */ - if (args->datatype & XFS_ALLOC_USERDATA_ZERO) { - error = xfs_zero_extent(args->ip, args->fsbno, args->len); - if (error) - goto error0; - } - - } - xfs_perag_put(args->pag); - return 0; -error0: - xfs_perag_put(args->pag); - return error; -} - -/* Ensure that the freelist is at full capacity. */ -int -xfs_free_extent_fix_freelist( - struct xfs_trans *tp, - xfs_agnumber_t agno, - struct xfs_buf **agbp) -{ - struct xfs_alloc_arg args; - int error; - - memset(&args, 0, sizeof(struct xfs_alloc_arg)); - args.tp = tp; - args.mp = tp->t_mountp; - args.agno = agno; - - /* - * validate that the block number is legal - the enables us to detect - * and handle a silent filesystem corruption rather than crashing. - */ - if (args.agno >= args.mp->m_sb.sb_agcount) - return -EFSCORRUPTED; - - args.pag = xfs_perag_get(args.mp, args.agno); - ASSERT(args.pag); - - error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING); - if (error) - goto out; - - *agbp = args.agbp; -out: - xfs_perag_put(args.pag); - return error; -} - -/* - * Free an extent. - * Just break up the extent address and hand off to xfs_free_ag_extent - * after fixing up the freelist. - */ -int /* error */ -xfs_free_extent( - struct xfs_trans *tp, /* transaction pointer */ - xfs_fsblock_t bno, /* starting block number of extent */ - xfs_extlen_t len, /* length of extent */ - struct xfs_owner_info *oinfo, /* extent owner */ - enum xfs_ag_resv_type type) /* block reservation type */ -{ - struct xfs_mount *mp = tp->t_mountp; - struct xfs_buf *agbp; - xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, bno); - xfs_agblock_t agbno = XFS_FSB_TO_AGBNO(mp, bno); - int error; - - ASSERT(len != 0); - ASSERT(type != XFS_AG_RESV_AGFL); - - if (XFS_TEST_ERROR(false, mp, - XFS_ERRTAG_FREE_EXTENT, - XFS_RANDOM_FREE_EXTENT)) - return -EIO; - - error = xfs_free_extent_fix_freelist(tp, agno, &agbp); - if (error) - return error; - - XFS_WANT_CORRUPTED_GOTO(mp, agbno < mp->m_sb.sb_agblocks, err); - - /* validate the extent size is legal now we have the agf locked */ - XFS_WANT_CORRUPTED_GOTO(mp, - agbno + len <= be32_to_cpu(XFS_BUF_TO_AGF(agbp)->agf_length), - err); - - error = xfs_free_ag_extent(tp, agbp, agno, agbno, len, oinfo, type); - if (error) - goto err; - - xfs_extent_busy_insert(tp, agno, agbno, len, 0); - return 0; - -err: - xfs_trans_brelse(tp, agbp); - return error; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_alloc.h b/src/linux/fs/xfs/libxfs/xfs_alloc.h deleted file mode 100644 index 7c404a6..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_alloc.h +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_ALLOC_H__ -#define __XFS_ALLOC_H__ - -struct xfs_buf; -struct xfs_btree_cur; -struct xfs_mount; -struct xfs_perag; -struct xfs_trans; - -extern struct workqueue_struct *xfs_alloc_wq; - -/* - * Freespace allocation types. Argument to xfs_alloc_[v]extent. - */ -#define XFS_ALLOCTYPE_ANY_AG 0x01 /* allocate anywhere, use rotor */ -#define XFS_ALLOCTYPE_FIRST_AG 0x02 /* ... start at ag 0 */ -#define XFS_ALLOCTYPE_START_AG 0x04 /* anywhere, start in this a.g. */ -#define XFS_ALLOCTYPE_THIS_AG 0x08 /* anywhere in this a.g. */ -#define XFS_ALLOCTYPE_START_BNO 0x10 /* near this block else anywhere */ -#define XFS_ALLOCTYPE_NEAR_BNO 0x20 /* in this a.g. and near this block */ -#define XFS_ALLOCTYPE_THIS_BNO 0x40 /* at exactly this block */ - -/* this should become an enum again when the tracing code is fixed */ -typedef unsigned int xfs_alloctype_t; - -#define XFS_ALLOC_TYPES \ - { XFS_ALLOCTYPE_ANY_AG, "ANY_AG" }, \ - { XFS_ALLOCTYPE_FIRST_AG, "FIRST_AG" }, \ - { XFS_ALLOCTYPE_START_AG, "START_AG" }, \ - { XFS_ALLOCTYPE_THIS_AG, "THIS_AG" }, \ - { XFS_ALLOCTYPE_START_BNO, "START_BNO" }, \ - { XFS_ALLOCTYPE_NEAR_BNO, "NEAR_BNO" }, \ - { XFS_ALLOCTYPE_THIS_BNO, "THIS_BNO" } - -/* - * Flags for xfs_alloc_fix_freelist. - */ -#define XFS_ALLOC_FLAG_TRYLOCK 0x00000001 /* use trylock for buffer locking */ -#define XFS_ALLOC_FLAG_FREEING 0x00000002 /* indicate caller is freeing extents*/ -#define XFS_ALLOC_FLAG_NORMAP 0x00000004 /* don't modify the rmapbt */ -#define XFS_ALLOC_FLAG_NOSHRINK 0x00000008 /* don't shrink the freelist */ - - -/* - * Argument structure for xfs_alloc routines. - * This is turned into a structure to avoid having 20 arguments passed - * down several levels of the stack. - */ -typedef struct xfs_alloc_arg { - struct xfs_trans *tp; /* transaction pointer */ - struct xfs_mount *mp; /* file system mount point */ - struct xfs_buf *agbp; /* buffer for a.g. freelist header */ - struct xfs_perag *pag; /* per-ag struct for this agno */ - struct xfs_inode *ip; /* for userdata zeroing method */ - xfs_fsblock_t fsbno; /* file system block number */ - xfs_agnumber_t agno; /* allocation group number */ - xfs_agblock_t agbno; /* allocation group-relative block # */ - xfs_extlen_t minlen; /* minimum size of extent */ - xfs_extlen_t maxlen; /* maximum size of extent */ - xfs_extlen_t mod; /* mod value for extent size */ - xfs_extlen_t prod; /* prod value for extent size */ - xfs_extlen_t minleft; /* min blocks must be left after us */ - xfs_extlen_t total; /* total blocks needed in xaction */ - xfs_extlen_t alignment; /* align answer to multiple of this */ - xfs_extlen_t minalignslop; /* slop for minlen+alignment calcs */ - xfs_agblock_t min_agbno; /* set an agbno range for NEAR allocs */ - xfs_agblock_t max_agbno; /* ... */ - xfs_extlen_t len; /* output: actual size of extent */ - xfs_alloctype_t type; /* allocation type XFS_ALLOCTYPE_... */ - xfs_alloctype_t otype; /* original allocation type */ - int datatype; /* mask defining data type treatment */ - char wasdel; /* set if allocation was prev delayed */ - char wasfromfl; /* set if allocation is from freelist */ - xfs_fsblock_t firstblock; /* io first block allocated */ - struct xfs_owner_info oinfo; /* owner of blocks being allocated */ - enum xfs_ag_resv_type resv; /* block reservation to use */ -} xfs_alloc_arg_t; - -/* - * Defines for datatype - */ -#define XFS_ALLOC_USERDATA (1 << 0)/* allocation is for user data*/ -#define XFS_ALLOC_INITIAL_USER_DATA (1 << 1)/* special case start of file */ -#define XFS_ALLOC_USERDATA_ZERO (1 << 2)/* zero extent on allocation */ -#define XFS_ALLOC_NOBUSY (1 << 3)/* Busy extents not allowed */ - -static inline bool -xfs_alloc_is_userdata(int datatype) -{ - return (datatype & ~XFS_ALLOC_NOBUSY) != 0; -} - -static inline bool -xfs_alloc_allow_busy_reuse(int datatype) -{ - return (datatype & XFS_ALLOC_NOBUSY) == 0; -} - -/* freespace limit calculations */ -#define XFS_ALLOC_AGFL_RESERVE 4 -unsigned int xfs_alloc_set_aside(struct xfs_mount *mp); -unsigned int xfs_alloc_ag_max_usable(struct xfs_mount *mp); - -xfs_extlen_t xfs_alloc_longest_free_extent(struct xfs_mount *mp, - struct xfs_perag *pag, xfs_extlen_t need, - xfs_extlen_t reserved); -unsigned int xfs_alloc_min_freelist(struct xfs_mount *mp, - struct xfs_perag *pag); - -/* - * Compute and fill in value of m_ag_maxlevels. - */ -void -xfs_alloc_compute_maxlevels( - struct xfs_mount *mp); /* file system mount structure */ - -/* - * Get a block from the freelist. - * Returns with the buffer for the block gotten. - */ -int /* error */ -xfs_alloc_get_freelist( - struct xfs_trans *tp, /* transaction pointer */ - struct xfs_buf *agbp, /* buffer containing the agf structure */ - xfs_agblock_t *bnop, /* block address retrieved from freelist */ - int btreeblk); /* destination is a AGF btree */ - -/* - * Log the given fields from the agf structure. - */ -void -xfs_alloc_log_agf( - struct xfs_trans *tp, /* transaction pointer */ - struct xfs_buf *bp, /* buffer for a.g. freelist header */ - int fields);/* mask of fields to be logged (XFS_AGF_...) */ - -/* - * Interface for inode allocation to force the pag data to be initialized. - */ -int /* error */ -xfs_alloc_pagf_init( - struct xfs_mount *mp, /* file system mount structure */ - struct xfs_trans *tp, /* transaction pointer */ - xfs_agnumber_t agno, /* allocation group number */ - int flags); /* XFS_ALLOC_FLAGS_... */ - -/* - * Put the block on the freelist for the allocation group. - */ -int /* error */ -xfs_alloc_put_freelist( - struct xfs_trans *tp, /* transaction pointer */ - struct xfs_buf *agbp, /* buffer for a.g. freelist header */ - struct xfs_buf *agflbp,/* buffer for a.g. free block array */ - xfs_agblock_t bno, /* block being freed */ - int btreeblk); /* owner was a AGF btree */ - -/* - * Read in the allocation group header (free/alloc section). - */ -int /* error */ -xfs_alloc_read_agf( - struct xfs_mount *mp, /* mount point structure */ - struct xfs_trans *tp, /* transaction pointer */ - xfs_agnumber_t agno, /* allocation group number */ - int flags, /* XFS_ALLOC_FLAG_... */ - struct xfs_buf **bpp); /* buffer for the ag freelist header */ - -/* - * Allocate an extent (variable-size). - */ -int /* error */ -xfs_alloc_vextent( - xfs_alloc_arg_t *args); /* allocation argument structure */ - -/* - * Free an extent. - */ -int /* error */ -xfs_free_extent( - struct xfs_trans *tp, /* transaction pointer */ - xfs_fsblock_t bno, /* starting block number of extent */ - xfs_extlen_t len, /* length of extent */ - struct xfs_owner_info *oinfo, /* extent owner */ - enum xfs_ag_resv_type type); /* block reservation type */ - -int /* error */ -xfs_alloc_lookup_ge( - struct xfs_btree_cur *cur, /* btree cursor */ - xfs_agblock_t bno, /* starting block of extent */ - xfs_extlen_t len, /* length of extent */ - int *stat); /* success/failure */ - -int /* error */ -xfs_alloc_get_rec( - struct xfs_btree_cur *cur, /* btree cursor */ - xfs_agblock_t *bno, /* output: starting block of extent */ - xfs_extlen_t *len, /* output: length of extent */ - int *stat); /* output: success/failure */ - -int xfs_read_agf(struct xfs_mount *mp, struct xfs_trans *tp, - xfs_agnumber_t agno, int flags, struct xfs_buf **bpp); -int xfs_alloc_fix_freelist(struct xfs_alloc_arg *args, int flags); -int xfs_free_extent_fix_freelist(struct xfs_trans *tp, xfs_agnumber_t agno, - struct xfs_buf **agbp); - -xfs_extlen_t xfs_prealloc_blocks(struct xfs_mount *mp); - -#endif /* __XFS_ALLOC_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_alloc_btree.c b/src/linux/fs/xfs/libxfs/xfs_alloc_btree.c deleted file mode 100644 index 5ba2dac..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_alloc_btree.c +++ /dev/null @@ -1,462 +0,0 @@ -/* - * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_btree.h" -#include "xfs_alloc_btree.h" -#include "xfs_alloc.h" -#include "xfs_extent_busy.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_cksum.h" -#include "xfs_trans.h" - - -STATIC struct xfs_btree_cur * -xfs_allocbt_dup_cursor( - struct xfs_btree_cur *cur) -{ - return xfs_allocbt_init_cursor(cur->bc_mp, cur->bc_tp, - cur->bc_private.a.agbp, cur->bc_private.a.agno, - cur->bc_btnum); -} - -STATIC void -xfs_allocbt_set_root( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *ptr, - int inc) -{ - struct xfs_buf *agbp = cur->bc_private.a.agbp; - struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); - xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); - int btnum = cur->bc_btnum; - struct xfs_perag *pag = xfs_perag_get(cur->bc_mp, seqno); - - ASSERT(ptr->s != 0); - - agf->agf_roots[btnum] = ptr->s; - be32_add_cpu(&agf->agf_levels[btnum], inc); - pag->pagf_levels[btnum] += inc; - xfs_perag_put(pag); - - xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS); -} - -STATIC int -xfs_allocbt_alloc_block( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *start, - union xfs_btree_ptr *new, - int *stat) -{ - int error; - xfs_agblock_t bno; - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - - /* Allocate the new block from the freelist. If we can't, give up. */ - error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp, - &bno, 1); - if (error) { - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; - } - - if (bno == NULLAGBLOCK) { - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 0; - return 0; - } - - xfs_extent_busy_reuse(cur->bc_mp, cur->bc_private.a.agno, bno, 1, false); - - xfs_trans_agbtree_delta(cur->bc_tp, 1); - new->s = cpu_to_be32(bno); - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 1; - return 0; -} - -STATIC int -xfs_allocbt_free_block( - struct xfs_btree_cur *cur, - struct xfs_buf *bp) -{ - struct xfs_buf *agbp = cur->bc_private.a.agbp; - struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); - xfs_agblock_t bno; - int error; - - bno = xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp)); - error = xfs_alloc_put_freelist(cur->bc_tp, agbp, NULL, bno, 1); - if (error) - return error; - - xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1, - XFS_EXTENT_BUSY_SKIP_DISCARD); - xfs_trans_agbtree_delta(cur->bc_tp, -1); - return 0; -} - -/* - * Update the longest extent in the AGF - */ -STATIC void -xfs_allocbt_update_lastrec( - struct xfs_btree_cur *cur, - struct xfs_btree_block *block, - union xfs_btree_rec *rec, - int ptr, - int reason) -{ - struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); - xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); - struct xfs_perag *pag; - __be32 len; - int numrecs; - - ASSERT(cur->bc_btnum == XFS_BTNUM_CNT); - - switch (reason) { - case LASTREC_UPDATE: - /* - * If this is the last leaf block and it's the last record, - * then update the size of the longest extent in the AG. - */ - if (ptr != xfs_btree_get_numrecs(block)) - return; - len = rec->alloc.ar_blockcount; - break; - case LASTREC_INSREC: - if (be32_to_cpu(rec->alloc.ar_blockcount) <= - be32_to_cpu(agf->agf_longest)) - return; - len = rec->alloc.ar_blockcount; - break; - case LASTREC_DELREC: - numrecs = xfs_btree_get_numrecs(block); - if (ptr <= numrecs) - return; - ASSERT(ptr == numrecs + 1); - - if (numrecs) { - xfs_alloc_rec_t *rrp; - - rrp = XFS_ALLOC_REC_ADDR(cur->bc_mp, block, numrecs); - len = rrp->ar_blockcount; - } else { - len = 0; - } - - break; - default: - ASSERT(0); - return; - } - - agf->agf_longest = len; - pag = xfs_perag_get(cur->bc_mp, seqno); - pag->pagf_longest = be32_to_cpu(len); - xfs_perag_put(pag); - xfs_alloc_log_agf(cur->bc_tp, cur->bc_private.a.agbp, XFS_AGF_LONGEST); -} - -STATIC int -xfs_allocbt_get_minrecs( - struct xfs_btree_cur *cur, - int level) -{ - return cur->bc_mp->m_alloc_mnr[level != 0]; -} - -STATIC int -xfs_allocbt_get_maxrecs( - struct xfs_btree_cur *cur, - int level) -{ - return cur->bc_mp->m_alloc_mxr[level != 0]; -} - -STATIC void -xfs_allocbt_init_key_from_rec( - union xfs_btree_key *key, - union xfs_btree_rec *rec) -{ - ASSERT(rec->alloc.ar_startblock != 0); - - key->alloc.ar_startblock = rec->alloc.ar_startblock; - key->alloc.ar_blockcount = rec->alloc.ar_blockcount; -} - -STATIC void -xfs_allocbt_init_rec_from_cur( - struct xfs_btree_cur *cur, - union xfs_btree_rec *rec) -{ - ASSERT(cur->bc_rec.a.ar_startblock != 0); - - rec->alloc.ar_startblock = cpu_to_be32(cur->bc_rec.a.ar_startblock); - rec->alloc.ar_blockcount = cpu_to_be32(cur->bc_rec.a.ar_blockcount); -} - -STATIC void -xfs_allocbt_init_ptr_from_cur( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *ptr) -{ - struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); - - ASSERT(cur->bc_private.a.agno == be32_to_cpu(agf->agf_seqno)); - ASSERT(agf->agf_roots[cur->bc_btnum] != 0); - - ptr->s = agf->agf_roots[cur->bc_btnum]; -} - -STATIC __int64_t -xfs_allocbt_key_diff( - struct xfs_btree_cur *cur, - union xfs_btree_key *key) -{ - xfs_alloc_rec_incore_t *rec = &cur->bc_rec.a; - xfs_alloc_key_t *kp = &key->alloc; - __int64_t diff; - - if (cur->bc_btnum == XFS_BTNUM_BNO) { - return (__int64_t)be32_to_cpu(kp->ar_startblock) - - rec->ar_startblock; - } - - diff = (__int64_t)be32_to_cpu(kp->ar_blockcount) - rec->ar_blockcount; - if (diff) - return diff; - - return (__int64_t)be32_to_cpu(kp->ar_startblock) - rec->ar_startblock; -} - -static bool -xfs_allocbt_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); - struct xfs_perag *pag = bp->b_pag; - unsigned int level; - - /* - * magic number and level verification - * - * During growfs operations, we can't verify the exact level or owner as - * the perag is not fully initialised and hence not attached to the - * buffer. In this case, check against the maximum tree depth. - * - * Similarly, during log recovery we will have a perag structure - * attached, but the agf information will not yet have been initialised - * from the on disk AGF. Again, we can only check against maximum limits - * in this case. - */ - level = be16_to_cpu(block->bb_level); - switch (block->bb_magic) { - case cpu_to_be32(XFS_ABTB_CRC_MAGIC): - if (!xfs_btree_sblock_v5hdr_verify(bp)) - return false; - /* fall through */ - case cpu_to_be32(XFS_ABTB_MAGIC): - if (pag && pag->pagf_init) { - if (level >= pag->pagf_levels[XFS_BTNUM_BNOi]) - return false; - } else if (level >= mp->m_ag_maxlevels) - return false; - break; - case cpu_to_be32(XFS_ABTC_CRC_MAGIC): - if (!xfs_btree_sblock_v5hdr_verify(bp)) - return false; - /* fall through */ - case cpu_to_be32(XFS_ABTC_MAGIC): - if (pag && pag->pagf_init) { - if (level >= pag->pagf_levels[XFS_BTNUM_CNTi]) - return false; - } else if (level >= mp->m_ag_maxlevels) - return false; - break; - default: - return false; - } - - return xfs_btree_sblock_verify(bp, mp->m_alloc_mxr[level != 0]); -} - -static void -xfs_allocbt_read_verify( - struct xfs_buf *bp) -{ - if (!xfs_btree_sblock_verify_crc(bp)) - xfs_buf_ioerror(bp, -EFSBADCRC); - else if (!xfs_allocbt_verify(bp)) - xfs_buf_ioerror(bp, -EFSCORRUPTED); - - if (bp->b_error) { - trace_xfs_btree_corrupt(bp, _RET_IP_); - xfs_verifier_error(bp); - } -} - -static void -xfs_allocbt_write_verify( - struct xfs_buf *bp) -{ - if (!xfs_allocbt_verify(bp)) { - trace_xfs_btree_corrupt(bp, _RET_IP_); - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - return; - } - xfs_btree_sblock_calc_crc(bp); - -} - -const struct xfs_buf_ops xfs_allocbt_buf_ops = { - .name = "xfs_allocbt", - .verify_read = xfs_allocbt_read_verify, - .verify_write = xfs_allocbt_write_verify, -}; - - -#if defined(DEBUG) || defined(XFS_WARN) -STATIC int -xfs_allocbt_keys_inorder( - struct xfs_btree_cur *cur, - union xfs_btree_key *k1, - union xfs_btree_key *k2) -{ - if (cur->bc_btnum == XFS_BTNUM_BNO) { - return be32_to_cpu(k1->alloc.ar_startblock) < - be32_to_cpu(k2->alloc.ar_startblock); - } else { - return be32_to_cpu(k1->alloc.ar_blockcount) < - be32_to_cpu(k2->alloc.ar_blockcount) || - (k1->alloc.ar_blockcount == k2->alloc.ar_blockcount && - be32_to_cpu(k1->alloc.ar_startblock) < - be32_to_cpu(k2->alloc.ar_startblock)); - } -} - -STATIC int -xfs_allocbt_recs_inorder( - struct xfs_btree_cur *cur, - union xfs_btree_rec *r1, - union xfs_btree_rec *r2) -{ - if (cur->bc_btnum == XFS_BTNUM_BNO) { - return be32_to_cpu(r1->alloc.ar_startblock) + - be32_to_cpu(r1->alloc.ar_blockcount) <= - be32_to_cpu(r2->alloc.ar_startblock); - } else { - return be32_to_cpu(r1->alloc.ar_blockcount) < - be32_to_cpu(r2->alloc.ar_blockcount) || - (r1->alloc.ar_blockcount == r2->alloc.ar_blockcount && - be32_to_cpu(r1->alloc.ar_startblock) < - be32_to_cpu(r2->alloc.ar_startblock)); - } -} -#endif /* DEBUG */ - -static const struct xfs_btree_ops xfs_allocbt_ops = { - .rec_len = sizeof(xfs_alloc_rec_t), - .key_len = sizeof(xfs_alloc_key_t), - - .dup_cursor = xfs_allocbt_dup_cursor, - .set_root = xfs_allocbt_set_root, - .alloc_block = xfs_allocbt_alloc_block, - .free_block = xfs_allocbt_free_block, - .update_lastrec = xfs_allocbt_update_lastrec, - .get_minrecs = xfs_allocbt_get_minrecs, - .get_maxrecs = xfs_allocbt_get_maxrecs, - .init_key_from_rec = xfs_allocbt_init_key_from_rec, - .init_rec_from_cur = xfs_allocbt_init_rec_from_cur, - .init_ptr_from_cur = xfs_allocbt_init_ptr_from_cur, - .key_diff = xfs_allocbt_key_diff, - .buf_ops = &xfs_allocbt_buf_ops, -#if defined(DEBUG) || defined(XFS_WARN) - .keys_inorder = xfs_allocbt_keys_inorder, - .recs_inorder = xfs_allocbt_recs_inorder, -#endif -}; - -/* - * Allocate a new allocation btree cursor. - */ -struct xfs_btree_cur * /* new alloc btree cursor */ -xfs_allocbt_init_cursor( - struct xfs_mount *mp, /* file system mount point */ - struct xfs_trans *tp, /* transaction pointer */ - struct xfs_buf *agbp, /* buffer for agf structure */ - xfs_agnumber_t agno, /* allocation group number */ - xfs_btnum_t btnum) /* btree identifier */ -{ - struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); - struct xfs_btree_cur *cur; - - ASSERT(btnum == XFS_BTNUM_BNO || btnum == XFS_BTNUM_CNT); - - cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP); - - cur->bc_tp = tp; - cur->bc_mp = mp; - cur->bc_btnum = btnum; - cur->bc_blocklog = mp->m_sb.sb_blocklog; - cur->bc_ops = &xfs_allocbt_ops; - - if (btnum == XFS_BTNUM_CNT) { - cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]); - cur->bc_flags = XFS_BTREE_LASTREC_UPDATE; - } else { - cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]); - } - - cur->bc_private.a.agbp = agbp; - cur->bc_private.a.agno = agno; - - if (xfs_sb_version_hascrc(&mp->m_sb)) - cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; - - return cur; -} - -/* - * Calculate number of records in an alloc btree block. - */ -int -xfs_allocbt_maxrecs( - struct xfs_mount *mp, - int blocklen, - int leaf) -{ - blocklen -= XFS_ALLOC_BLOCK_LEN(mp); - - if (leaf) - return blocklen / sizeof(xfs_alloc_rec_t); - return blocklen / (sizeof(xfs_alloc_key_t) + sizeof(xfs_alloc_ptr_t)); -} diff --git a/src/linux/fs/xfs/libxfs/xfs_alloc_btree.h b/src/linux/fs/xfs/libxfs/xfs_alloc_btree.h deleted file mode 100644 index 45e189e..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_alloc_btree.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2000,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_ALLOC_BTREE_H__ -#define __XFS_ALLOC_BTREE_H__ - -/* - * Freespace on-disk structures - */ - -struct xfs_buf; -struct xfs_btree_cur; -struct xfs_mount; - -/* - * Btree block header size depends on a superblock flag. - */ -#define XFS_ALLOC_BLOCK_LEN(mp) \ - (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \ - XFS_BTREE_SBLOCK_CRC_LEN : XFS_BTREE_SBLOCK_LEN) - -/* - * Record, key, and pointer address macros for btree blocks. - * - * (note that some of these may appear unused, but they are used in userspace) - */ -#define XFS_ALLOC_REC_ADDR(mp, block, index) \ - ((xfs_alloc_rec_t *) \ - ((char *)(block) + \ - XFS_ALLOC_BLOCK_LEN(mp) + \ - (((index) - 1) * sizeof(xfs_alloc_rec_t)))) - -#define XFS_ALLOC_KEY_ADDR(mp, block, index) \ - ((xfs_alloc_key_t *) \ - ((char *)(block) + \ - XFS_ALLOC_BLOCK_LEN(mp) + \ - ((index) - 1) * sizeof(xfs_alloc_key_t))) - -#define XFS_ALLOC_PTR_ADDR(mp, block, index, maxrecs) \ - ((xfs_alloc_ptr_t *) \ - ((char *)(block) + \ - XFS_ALLOC_BLOCK_LEN(mp) + \ - (maxrecs) * sizeof(xfs_alloc_key_t) + \ - ((index) - 1) * sizeof(xfs_alloc_ptr_t))) - -extern struct xfs_btree_cur *xfs_allocbt_init_cursor(struct xfs_mount *, - struct xfs_trans *, struct xfs_buf *, - xfs_agnumber_t, xfs_btnum_t); -extern int xfs_allocbt_maxrecs(struct xfs_mount *, int, int); - -#endif /* __XFS_ALLOC_BTREE_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_attr.c b/src/linux/fs/xfs/libxfs/xfs_attr.c deleted file mode 100644 index af1ecb1..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_attr.c +++ /dev/null @@ -1,1327 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_attr_sf.h" -#include "xfs_inode.h" -#include "xfs_alloc.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_bmap.h" -#include "xfs_bmap_util.h" -#include "xfs_bmap_btree.h" -#include "xfs_attr.h" -#include "xfs_attr_leaf.h" -#include "xfs_attr_remote.h" -#include "xfs_error.h" -#include "xfs_quota.h" -#include "xfs_trans_space.h" -#include "xfs_trace.h" - -/* - * xfs_attr.c - * - * Provide the external interfaces to manage attribute lists. - */ - -/*======================================================================== - * Function prototypes for the kernel. - *========================================================================*/ - -/* - * Internal routines when attribute list fits inside the inode. - */ -STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args); - -/* - * Internal routines when attribute list is one block. - */ -STATIC int xfs_attr_leaf_get(xfs_da_args_t *args); -STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args); -STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args); - -/* - * Internal routines when attribute list is more than one block. - */ -STATIC int xfs_attr_node_get(xfs_da_args_t *args); -STATIC int xfs_attr_node_addname(xfs_da_args_t *args); -STATIC int xfs_attr_node_removename(xfs_da_args_t *args); -STATIC int xfs_attr_fillstate(xfs_da_state_t *state); -STATIC int xfs_attr_refillstate(xfs_da_state_t *state); - - -STATIC int -xfs_attr_args_init( - struct xfs_da_args *args, - struct xfs_inode *dp, - const unsigned char *name, - int flags) -{ - - if (!name) - return -EINVAL; - - memset(args, 0, sizeof(*args)); - args->geo = dp->i_mount->m_attr_geo; - args->whichfork = XFS_ATTR_FORK; - args->dp = dp; - args->flags = flags; - args->name = name; - args->namelen = strlen((const char *)name); - if (args->namelen >= MAXNAMELEN) - return -EFAULT; /* match IRIX behaviour */ - - args->hashval = xfs_da_hashname(args->name, args->namelen); - return 0; -} - -int -xfs_inode_hasattr( - struct xfs_inode *ip) -{ - if (!XFS_IFORK_Q(ip) || - (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && - ip->i_d.di_anextents == 0)) - return 0; - return 1; -} - -/*======================================================================== - * Overall external interface routines. - *========================================================================*/ - -int -xfs_attr_get( - struct xfs_inode *ip, - const unsigned char *name, - unsigned char *value, - int *valuelenp, - int flags) -{ - struct xfs_da_args args; - uint lock_mode; - int error; - - XFS_STATS_INC(ip->i_mount, xs_attr_get); - - if (XFS_FORCED_SHUTDOWN(ip->i_mount)) - return -EIO; - - if (!xfs_inode_hasattr(ip)) - return -ENOATTR; - - error = xfs_attr_args_init(&args, ip, name, flags); - if (error) - return error; - - args.value = value; - args.valuelen = *valuelenp; - /* Entirely possible to look up a name which doesn't exist */ - args.op_flags = XFS_DA_OP_OKNOENT; - - lock_mode = xfs_ilock_attr_map_shared(ip); - if (!xfs_inode_hasattr(ip)) - error = -ENOATTR; - else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) - error = xfs_attr_shortform_getvalue(&args); - else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) - error = xfs_attr_leaf_get(&args); - else - error = xfs_attr_node_get(&args); - xfs_iunlock(ip, lock_mode); - - *valuelenp = args.valuelen; - return error == -EEXIST ? 0 : error; -} - -/* - * Calculate how many blocks we need for the new attribute, - */ -STATIC int -xfs_attr_calc_size( - struct xfs_da_args *args, - int *local) -{ - struct xfs_mount *mp = args->dp->i_mount; - int size; - int nblks; - - /* - * Determine space new attribute will use, and if it would be - * "local" or "remote" (note: local != inline). - */ - size = xfs_attr_leaf_newentsize(args, local); - nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); - if (*local) { - if (size > (args->geo->blksize / 2)) { - /* Double split possible */ - nblks *= 2; - } - } else { - /* - * Out of line attribute, cannot double split, but - * make room for the attribute value itself. - */ - uint dblocks = xfs_attr3_rmt_blocks(mp, args->valuelen); - nblks += dblocks; - nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK); - } - - return nblks; -} - -int -xfs_attr_set( - struct xfs_inode *dp, - const unsigned char *name, - unsigned char *value, - int valuelen, - int flags) -{ - struct xfs_mount *mp = dp->i_mount; - struct xfs_da_args args; - struct xfs_defer_ops dfops; - struct xfs_trans_res tres; - xfs_fsblock_t firstblock; - int rsvd = (flags & ATTR_ROOT) != 0; - int error, err2, local; - - XFS_STATS_INC(mp, xs_attr_set); - - if (XFS_FORCED_SHUTDOWN(dp->i_mount)) - return -EIO; - - error = xfs_attr_args_init(&args, dp, name, flags); - if (error) - return error; - - args.value = value; - args.valuelen = valuelen; - args.firstblock = &firstblock; - args.dfops = &dfops; - args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; - args.total = xfs_attr_calc_size(&args, &local); - - error = xfs_qm_dqattach(dp, 0); - if (error) - return error; - - /* - * If the inode doesn't have an attribute fork, add one. - * (inode must not be locked when we call this routine) - */ - if (XFS_IFORK_Q(dp) == 0) { - int sf_size = sizeof(xfs_attr_sf_hdr_t) + - XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen); - - error = xfs_bmap_add_attrfork(dp, sf_size, rsvd); - if (error) - return error; - } - - tres.tr_logres = M_RES(mp)->tr_attrsetm.tr_logres + - M_RES(mp)->tr_attrsetrt.tr_logres * args.total; - tres.tr_logcount = XFS_ATTRSET_LOG_COUNT; - tres.tr_logflags = XFS_TRANS_PERM_LOG_RES; - - /* - * Root fork attributes can use reserved data blocks for this - * operation if necessary - */ - error = xfs_trans_alloc(mp, &tres, args.total, 0, - rsvd ? XFS_TRANS_RESERVE : 0, &args.trans); - if (error) - return error; - - xfs_ilock(dp, XFS_ILOCK_EXCL); - error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0, - rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : - XFS_QMOPT_RES_REGBLKS); - if (error) { - xfs_iunlock(dp, XFS_ILOCK_EXCL); - xfs_trans_cancel(args.trans); - return error; - } - - xfs_trans_ijoin(args.trans, dp, 0); - - /* - * If the attribute list is non-existent or a shortform list, - * upgrade it to a single-leaf-block attribute list. - */ - if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL || - (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && - dp->i_d.di_anextents == 0)) { - - /* - * Build initial attribute list (if required). - */ - if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) - xfs_attr_shortform_create(&args); - - /* - * Try to add the attr to the attribute list in - * the inode. - */ - error = xfs_attr_shortform_addname(&args); - if (error != -ENOSPC) { - /* - * Commit the shortform mods, and we're done. - * NOTE: this is also the error path (EEXIST, etc). - */ - ASSERT(args.trans != NULL); - - /* - * If this is a synchronous mount, make sure that - * the transaction goes to disk before returning - * to the user. - */ - if (mp->m_flags & XFS_MOUNT_WSYNC) - xfs_trans_set_sync(args.trans); - - if (!error && (flags & ATTR_KERNOTIME) == 0) { - xfs_trans_ichgtime(args.trans, dp, - XFS_ICHGTIME_CHG); - } - err2 = xfs_trans_commit(args.trans); - xfs_iunlock(dp, XFS_ILOCK_EXCL); - - return error ? error : err2; - } - - /* - * It won't fit in the shortform, transform to a leaf block. - * GROT: another possible req'mt for a double-split btree op. - */ - xfs_defer_init(args.dfops, args.firstblock); - error = xfs_attr_shortform_to_leaf(&args); - if (!error) - error = xfs_defer_finish(&args.trans, args.dfops, dp); - if (error) { - args.trans = NULL; - xfs_defer_cancel(&dfops); - goto out; - } - - /* - * Commit the leaf transformation. We'll need another (linked) - * transaction to add the new attribute to the leaf. - */ - - error = xfs_trans_roll(&args.trans, dp); - if (error) - goto out; - - } - - if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) - error = xfs_attr_leaf_addname(&args); - else - error = xfs_attr_node_addname(&args); - if (error) - goto out; - - /* - * If this is a synchronous mount, make sure that the - * transaction goes to disk before returning to the user. - */ - if (mp->m_flags & XFS_MOUNT_WSYNC) - xfs_trans_set_sync(args.trans); - - if ((flags & ATTR_KERNOTIME) == 0) - xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG); - - /* - * Commit the last in the sequence of transactions. - */ - xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); - error = xfs_trans_commit(args.trans); - xfs_iunlock(dp, XFS_ILOCK_EXCL); - - return error; - -out: - if (args.trans) - xfs_trans_cancel(args.trans); - xfs_iunlock(dp, XFS_ILOCK_EXCL); - return error; -} - -/* - * Generic handler routine to remove a name from an attribute list. - * Transitions attribute list from Btree to shortform as necessary. - */ -int -xfs_attr_remove( - struct xfs_inode *dp, - const unsigned char *name, - int flags) -{ - struct xfs_mount *mp = dp->i_mount; - struct xfs_da_args args; - struct xfs_defer_ops dfops; - xfs_fsblock_t firstblock; - int error; - - XFS_STATS_INC(mp, xs_attr_remove); - - if (XFS_FORCED_SHUTDOWN(dp->i_mount)) - return -EIO; - - if (!xfs_inode_hasattr(dp)) - return -ENOATTR; - - error = xfs_attr_args_init(&args, dp, name, flags); - if (error) - return error; - - args.firstblock = &firstblock; - args.dfops = &dfops; - - /* - * we have no control over the attribute names that userspace passes us - * to remove, so we have to allow the name lookup prior to attribute - * removal to fail. - */ - args.op_flags = XFS_DA_OP_OKNOENT; - - error = xfs_qm_dqattach(dp, 0); - if (error) - return error; - - /* - * Root fork attributes can use reserved data blocks for this - * operation if necessary - */ - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrrm, - XFS_ATTRRM_SPACE_RES(mp), 0, - (flags & ATTR_ROOT) ? XFS_TRANS_RESERVE : 0, - &args.trans); - if (error) - return error; - - xfs_ilock(dp, XFS_ILOCK_EXCL); - /* - * No need to make quota reservations here. We expect to release some - * blocks not allocate in the common case. - */ - xfs_trans_ijoin(args.trans, dp, 0); - - if (!xfs_inode_hasattr(dp)) { - error = -ENOATTR; - } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { - ASSERT(dp->i_afp->if_flags & XFS_IFINLINE); - error = xfs_attr_shortform_remove(&args); - } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { - error = xfs_attr_leaf_removename(&args); - } else { - error = xfs_attr_node_removename(&args); - } - - if (error) - goto out; - - /* - * If this is a synchronous mount, make sure that the - * transaction goes to disk before returning to the user. - */ - if (mp->m_flags & XFS_MOUNT_WSYNC) - xfs_trans_set_sync(args.trans); - - if ((flags & ATTR_KERNOTIME) == 0) - xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG); - - /* - * Commit the last in the sequence of transactions. - */ - xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); - error = xfs_trans_commit(args.trans); - xfs_iunlock(dp, XFS_ILOCK_EXCL); - - return error; - -out: - if (args.trans) - xfs_trans_cancel(args.trans); - xfs_iunlock(dp, XFS_ILOCK_EXCL); - return error; -} - -/*======================================================================== - * External routines when attribute list is inside the inode - *========================================================================*/ - -/* - * Add a name to the shortform attribute list structure - * This is the external routine. - */ -STATIC int -xfs_attr_shortform_addname(xfs_da_args_t *args) -{ - int newsize, forkoff, retval; - - trace_xfs_attr_sf_addname(args); - - retval = xfs_attr_shortform_lookup(args); - if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) { - return retval; - } else if (retval == -EEXIST) { - if (args->flags & ATTR_CREATE) - return retval; - retval = xfs_attr_shortform_remove(args); - ASSERT(retval == 0); - } - - if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX || - args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX) - return -ENOSPC; - - newsize = XFS_ATTR_SF_TOTSIZE(args->dp); - newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen); - - forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize); - if (!forkoff) - return -ENOSPC; - - xfs_attr_shortform_add(args, forkoff); - return 0; -} - - -/*======================================================================== - * External routines when attribute list is one block - *========================================================================*/ - -/* - * Add a name to the leaf attribute list structure - * - * This leaf block cannot have a "remote" value, we only call this routine - * if bmap_one_block() says there is only one block (ie: no remote blks). - */ -STATIC int -xfs_attr_leaf_addname(xfs_da_args_t *args) -{ - xfs_inode_t *dp; - struct xfs_buf *bp; - int retval, error, forkoff; - - trace_xfs_attr_leaf_addname(args); - - /* - * Read the (only) block in the attribute list in. - */ - dp = args->dp; - args->blkno = 0; - error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); - if (error) - return error; - - /* - * Look up the given attribute in the leaf block. Figure out if - * the given flags produce an error or call for an atomic rename. - */ - retval = xfs_attr3_leaf_lookup_int(bp, args); - if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) { - xfs_trans_brelse(args->trans, bp); - return retval; - } else if (retval == -EEXIST) { - if (args->flags & ATTR_CREATE) { /* pure create op */ - xfs_trans_brelse(args->trans, bp); - return retval; - } - - trace_xfs_attr_leaf_replace(args); - - /* save the attribute state for later removal*/ - args->op_flags |= XFS_DA_OP_RENAME; /* an atomic rename */ - args->blkno2 = args->blkno; /* set 2nd entry info*/ - args->index2 = args->index; - args->rmtblkno2 = args->rmtblkno; - args->rmtblkcnt2 = args->rmtblkcnt; - args->rmtvaluelen2 = args->rmtvaluelen; - - /* - * clear the remote attr state now that it is saved so that the - * values reflect the state of the attribute we are about to - * add, not the attribute we just found and will remove later. - */ - args->rmtblkno = 0; - args->rmtblkcnt = 0; - args->rmtvaluelen = 0; - } - - /* - * Add the attribute to the leaf block, transitioning to a Btree - * if required. - */ - retval = xfs_attr3_leaf_add(bp, args); - if (retval == -ENOSPC) { - /* - * Promote the attribute list to the Btree format, then - * Commit that transaction so that the node_addname() call - * can manage its own transactions. - */ - xfs_defer_init(args->dfops, args->firstblock); - error = xfs_attr3_leaf_to_node(args); - if (!error) - error = xfs_defer_finish(&args->trans, args->dfops, dp); - if (error) { - args->trans = NULL; - xfs_defer_cancel(args->dfops); - return error; - } - - /* - * Commit the current trans (including the inode) and start - * a new one. - */ - error = xfs_trans_roll(&args->trans, dp); - if (error) - return error; - - /* - * Fob the whole rest of the problem off on the Btree code. - */ - error = xfs_attr_node_addname(args); - return error; - } - - /* - * Commit the transaction that added the attr name so that - * later routines can manage their own transactions. - */ - error = xfs_trans_roll(&args->trans, dp); - if (error) - return error; - - /* - * If there was an out-of-line value, allocate the blocks we - * identified for its storage and copy the value. This is done - * after we create the attribute so that we don't overflow the - * maximum size of a transaction and/or hit a deadlock. - */ - if (args->rmtblkno > 0) { - error = xfs_attr_rmtval_set(args); - if (error) - return error; - } - - /* - * If this is an atomic rename operation, we must "flip" the - * incomplete flags on the "new" and "old" attribute/value pairs - * so that one disappears and one appears atomically. Then we - * must remove the "old" attribute/value pair. - */ - if (args->op_flags & XFS_DA_OP_RENAME) { - /* - * In a separate transaction, set the incomplete flag on the - * "old" attr and clear the incomplete flag on the "new" attr. - */ - error = xfs_attr3_leaf_flipflags(args); - if (error) - return error; - - /* - * Dismantle the "old" attribute/value pair by removing - * a "remote" value (if it exists). - */ - args->index = args->index2; - args->blkno = args->blkno2; - args->rmtblkno = args->rmtblkno2; - args->rmtblkcnt = args->rmtblkcnt2; - args->rmtvaluelen = args->rmtvaluelen2; - if (args->rmtblkno) { - error = xfs_attr_rmtval_remove(args); - if (error) - return error; - } - - /* - * Read in the block containing the "old" attr, then - * remove the "old" attr from that block (neat, huh!) - */ - error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, - -1, &bp); - if (error) - return error; - - xfs_attr3_leaf_remove(bp, args); - - /* - * If the result is small enough, shrink it all into the inode. - */ - if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) { - xfs_defer_init(args->dfops, args->firstblock); - error = xfs_attr3_leaf_to_shortform(bp, args, forkoff); - /* bp is gone due to xfs_da_shrink_inode */ - if (!error) - error = xfs_defer_finish(&args->trans, - args->dfops, dp); - if (error) { - args->trans = NULL; - xfs_defer_cancel(args->dfops); - return error; - } - } - - /* - * Commit the remove and start the next trans in series. - */ - error = xfs_trans_roll(&args->trans, dp); - - } else if (args->rmtblkno > 0) { - /* - * Added a "remote" value, just clear the incomplete flag. - */ - error = xfs_attr3_leaf_clearflag(args); - } - return error; -} - -/* - * Remove a name from the leaf attribute list structure - * - * This leaf block cannot have a "remote" value, we only call this routine - * if bmap_one_block() says there is only one block (ie: no remote blks). - */ -STATIC int -xfs_attr_leaf_removename(xfs_da_args_t *args) -{ - xfs_inode_t *dp; - struct xfs_buf *bp; - int error, forkoff; - - trace_xfs_attr_leaf_removename(args); - - /* - * Remove the attribute. - */ - dp = args->dp; - args->blkno = 0; - error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); - if (error) - return error; - - error = xfs_attr3_leaf_lookup_int(bp, args); - if (error == -ENOATTR) { - xfs_trans_brelse(args->trans, bp); - return error; - } - - xfs_attr3_leaf_remove(bp, args); - - /* - * If the result is small enough, shrink it all into the inode. - */ - if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) { - xfs_defer_init(args->dfops, args->firstblock); - error = xfs_attr3_leaf_to_shortform(bp, args, forkoff); - /* bp is gone due to xfs_da_shrink_inode */ - if (!error) - error = xfs_defer_finish(&args->trans, args->dfops, dp); - if (error) { - args->trans = NULL; - xfs_defer_cancel(args->dfops); - return error; - } - } - return 0; -} - -/* - * Look up a name in a leaf attribute list structure. - * - * This leaf block cannot have a "remote" value, we only call this routine - * if bmap_one_block() says there is only one block (ie: no remote blks). - */ -STATIC int -xfs_attr_leaf_get(xfs_da_args_t *args) -{ - struct xfs_buf *bp; - int error; - - trace_xfs_attr_leaf_get(args); - - args->blkno = 0; - error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); - if (error) - return error; - - error = xfs_attr3_leaf_lookup_int(bp, args); - if (error != -EEXIST) { - xfs_trans_brelse(args->trans, bp); - return error; - } - error = xfs_attr3_leaf_getvalue(bp, args); - xfs_trans_brelse(args->trans, bp); - if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) { - error = xfs_attr_rmtval_get(args); - } - return error; -} - -/*======================================================================== - * External routines when attribute list size > geo->blksize - *========================================================================*/ - -/* - * Add a name to a Btree-format attribute list. - * - * This will involve walking down the Btree, and may involve splitting - * leaf nodes and even splitting intermediate nodes up to and including - * the root node (a special case of an intermediate node). - * - * "Remote" attribute values confuse the issue and atomic rename operations - * add a whole extra layer of confusion on top of that. - */ -STATIC int -xfs_attr_node_addname(xfs_da_args_t *args) -{ - xfs_da_state_t *state; - xfs_da_state_blk_t *blk; - xfs_inode_t *dp; - xfs_mount_t *mp; - int retval, error; - - trace_xfs_attr_node_addname(args); - - /* - * Fill in bucket of arguments/results/context to carry around. - */ - dp = args->dp; - mp = dp->i_mount; -restart: - state = xfs_da_state_alloc(); - state->args = args; - state->mp = mp; - - /* - * Search to see if name already exists, and get back a pointer - * to where it should go. - */ - error = xfs_da3_node_lookup_int(state, &retval); - if (error) - goto out; - blk = &state->path.blk[ state->path.active-1 ]; - ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); - if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) { - goto out; - } else if (retval == -EEXIST) { - if (args->flags & ATTR_CREATE) - goto out; - - trace_xfs_attr_node_replace(args); - - /* save the attribute state for later removal*/ - args->op_flags |= XFS_DA_OP_RENAME; /* atomic rename op */ - args->blkno2 = args->blkno; /* set 2nd entry info*/ - args->index2 = args->index; - args->rmtblkno2 = args->rmtblkno; - args->rmtblkcnt2 = args->rmtblkcnt; - args->rmtvaluelen2 = args->rmtvaluelen; - - /* - * clear the remote attr state now that it is saved so that the - * values reflect the state of the attribute we are about to - * add, not the attribute we just found and will remove later. - */ - args->rmtblkno = 0; - args->rmtblkcnt = 0; - args->rmtvaluelen = 0; - } - - retval = xfs_attr3_leaf_add(blk->bp, state->args); - if (retval == -ENOSPC) { - if (state->path.active == 1) { - /* - * Its really a single leaf node, but it had - * out-of-line values so it looked like it *might* - * have been a b-tree. - */ - xfs_da_state_free(state); - state = NULL; - xfs_defer_init(args->dfops, args->firstblock); - error = xfs_attr3_leaf_to_node(args); - if (!error) - error = xfs_defer_finish(&args->trans, - args->dfops, dp); - if (error) { - args->trans = NULL; - xfs_defer_cancel(args->dfops); - goto out; - } - - /* - * Commit the node conversion and start the next - * trans in the chain. - */ - error = xfs_trans_roll(&args->trans, dp); - if (error) - goto out; - - goto restart; - } - - /* - * Split as many Btree elements as required. - * This code tracks the new and old attr's location - * in the index/blkno/rmtblkno/rmtblkcnt fields and - * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields. - */ - xfs_defer_init(args->dfops, args->firstblock); - error = xfs_da3_split(state); - if (!error) - error = xfs_defer_finish(&args->trans, args->dfops, dp); - if (error) { - args->trans = NULL; - xfs_defer_cancel(args->dfops); - goto out; - } - } else { - /* - * Addition succeeded, update Btree hashvals. - */ - xfs_da3_fixhashpath(state, &state->path); - } - - /* - * Kill the state structure, we're done with it and need to - * allow the buffers to come back later. - */ - xfs_da_state_free(state); - state = NULL; - - /* - * Commit the leaf addition or btree split and start the next - * trans in the chain. - */ - error = xfs_trans_roll(&args->trans, dp); - if (error) - goto out; - - /* - * If there was an out-of-line value, allocate the blocks we - * identified for its storage and copy the value. This is done - * after we create the attribute so that we don't overflow the - * maximum size of a transaction and/or hit a deadlock. - */ - if (args->rmtblkno > 0) { - error = xfs_attr_rmtval_set(args); - if (error) - return error; - } - - /* - * If this is an atomic rename operation, we must "flip" the - * incomplete flags on the "new" and "old" attribute/value pairs - * so that one disappears and one appears atomically. Then we - * must remove the "old" attribute/value pair. - */ - if (args->op_flags & XFS_DA_OP_RENAME) { - /* - * In a separate transaction, set the incomplete flag on the - * "old" attr and clear the incomplete flag on the "new" attr. - */ - error = xfs_attr3_leaf_flipflags(args); - if (error) - goto out; - - /* - * Dismantle the "old" attribute/value pair by removing - * a "remote" value (if it exists). - */ - args->index = args->index2; - args->blkno = args->blkno2; - args->rmtblkno = args->rmtblkno2; - args->rmtblkcnt = args->rmtblkcnt2; - args->rmtvaluelen = args->rmtvaluelen2; - if (args->rmtblkno) { - error = xfs_attr_rmtval_remove(args); - if (error) - return error; - } - - /* - * Re-find the "old" attribute entry after any split ops. - * The INCOMPLETE flag means that we will find the "old" - * attr, not the "new" one. - */ - args->flags |= XFS_ATTR_INCOMPLETE; - state = xfs_da_state_alloc(); - state->args = args; - state->mp = mp; - state->inleaf = 0; - error = xfs_da3_node_lookup_int(state, &retval); - if (error) - goto out; - - /* - * Remove the name and update the hashvals in the tree. - */ - blk = &state->path.blk[ state->path.active-1 ]; - ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); - error = xfs_attr3_leaf_remove(blk->bp, args); - xfs_da3_fixhashpath(state, &state->path); - - /* - * Check to see if the tree needs to be collapsed. - */ - if (retval && (state->path.active > 1)) { - xfs_defer_init(args->dfops, args->firstblock); - error = xfs_da3_join(state); - if (!error) - error = xfs_defer_finish(&args->trans, - args->dfops, dp); - if (error) { - args->trans = NULL; - xfs_defer_cancel(args->dfops); - goto out; - } - } - - /* - * Commit and start the next trans in the chain. - */ - error = xfs_trans_roll(&args->trans, dp); - if (error) - goto out; - - } else if (args->rmtblkno > 0) { - /* - * Added a "remote" value, just clear the incomplete flag. - */ - error = xfs_attr3_leaf_clearflag(args); - if (error) - goto out; - } - retval = error = 0; - -out: - if (state) - xfs_da_state_free(state); - if (error) - return error; - return retval; -} - -/* - * Remove a name from a B-tree attribute list. - * - * This will involve walking down the Btree, and may involve joining - * leaf nodes and even joining intermediate nodes up to and including - * the root node (a special case of an intermediate node). - */ -STATIC int -xfs_attr_node_removename(xfs_da_args_t *args) -{ - xfs_da_state_t *state; - xfs_da_state_blk_t *blk; - xfs_inode_t *dp; - struct xfs_buf *bp; - int retval, error, forkoff; - - trace_xfs_attr_node_removename(args); - - /* - * Tie a string around our finger to remind us where we are. - */ - dp = args->dp; - state = xfs_da_state_alloc(); - state->args = args; - state->mp = dp->i_mount; - - /* - * Search to see if name exists, and get back a pointer to it. - */ - error = xfs_da3_node_lookup_int(state, &retval); - if (error || (retval != -EEXIST)) { - if (error == 0) - error = retval; - goto out; - } - - /* - * If there is an out-of-line value, de-allocate the blocks. - * This is done before we remove the attribute so that we don't - * overflow the maximum size of a transaction and/or hit a deadlock. - */ - blk = &state->path.blk[ state->path.active-1 ]; - ASSERT(blk->bp != NULL); - ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); - if (args->rmtblkno > 0) { - /* - * Fill in disk block numbers in the state structure - * so that we can get the buffers back after we commit - * several transactions in the following calls. - */ - error = xfs_attr_fillstate(state); - if (error) - goto out; - - /* - * Mark the attribute as INCOMPLETE, then bunmapi() the - * remote value. - */ - error = xfs_attr3_leaf_setflag(args); - if (error) - goto out; - error = xfs_attr_rmtval_remove(args); - if (error) - goto out; - - /* - * Refill the state structure with buffers, the prior calls - * released our buffers. - */ - error = xfs_attr_refillstate(state); - if (error) - goto out; - } - - /* - * Remove the name and update the hashvals in the tree. - */ - blk = &state->path.blk[ state->path.active-1 ]; - ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); - retval = xfs_attr3_leaf_remove(blk->bp, args); - xfs_da3_fixhashpath(state, &state->path); - - /* - * Check to see if the tree needs to be collapsed. - */ - if (retval && (state->path.active > 1)) { - xfs_defer_init(args->dfops, args->firstblock); - error = xfs_da3_join(state); - if (!error) - error = xfs_defer_finish(&args->trans, args->dfops, dp); - if (error) { - args->trans = NULL; - xfs_defer_cancel(args->dfops); - goto out; - } - /* - * Commit the Btree join operation and start a new trans. - */ - error = xfs_trans_roll(&args->trans, dp); - if (error) - goto out; - } - - /* - * If the result is small enough, push it all into the inode. - */ - if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { - /* - * Have to get rid of the copy of this dabuf in the state. - */ - ASSERT(state->path.active == 1); - ASSERT(state->path.blk[0].bp); - state->path.blk[0].bp = NULL; - - error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp); - if (error) - goto out; - - if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) { - xfs_defer_init(args->dfops, args->firstblock); - error = xfs_attr3_leaf_to_shortform(bp, args, forkoff); - /* bp is gone due to xfs_da_shrink_inode */ - if (!error) - error = xfs_defer_finish(&args->trans, - args->dfops, dp); - if (error) { - args->trans = NULL; - xfs_defer_cancel(args->dfops); - goto out; - } - } else - xfs_trans_brelse(args->trans, bp); - } - error = 0; - -out: - xfs_da_state_free(state); - return error; -} - -/* - * Fill in the disk block numbers in the state structure for the buffers - * that are attached to the state structure. - * This is done so that we can quickly reattach ourselves to those buffers - * after some set of transaction commits have released these buffers. - */ -STATIC int -xfs_attr_fillstate(xfs_da_state_t *state) -{ - xfs_da_state_path_t *path; - xfs_da_state_blk_t *blk; - int level; - - trace_xfs_attr_fillstate(state->args); - - /* - * Roll down the "path" in the state structure, storing the on-disk - * block number for those buffers in the "path". - */ - path = &state->path; - ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); - for (blk = path->blk, level = 0; level < path->active; blk++, level++) { - if (blk->bp) { - blk->disk_blkno = XFS_BUF_ADDR(blk->bp); - blk->bp = NULL; - } else { - blk->disk_blkno = 0; - } - } - - /* - * Roll down the "altpath" in the state structure, storing the on-disk - * block number for those buffers in the "altpath". - */ - path = &state->altpath; - ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); - for (blk = path->blk, level = 0; level < path->active; blk++, level++) { - if (blk->bp) { - blk->disk_blkno = XFS_BUF_ADDR(blk->bp); - blk->bp = NULL; - } else { - blk->disk_blkno = 0; - } - } - - return 0; -} - -/* - * Reattach the buffers to the state structure based on the disk block - * numbers stored in the state structure. - * This is done after some set of transaction commits have released those - * buffers from our grip. - */ -STATIC int -xfs_attr_refillstate(xfs_da_state_t *state) -{ - xfs_da_state_path_t *path; - xfs_da_state_blk_t *blk; - int level, error; - - trace_xfs_attr_refillstate(state->args); - - /* - * Roll down the "path" in the state structure, storing the on-disk - * block number for those buffers in the "path". - */ - path = &state->path; - ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); - for (blk = path->blk, level = 0; level < path->active; blk++, level++) { - if (blk->disk_blkno) { - error = xfs_da3_node_read(state->args->trans, - state->args->dp, - blk->blkno, blk->disk_blkno, - &blk->bp, XFS_ATTR_FORK); - if (error) - return error; - } else { - blk->bp = NULL; - } - } - - /* - * Roll down the "altpath" in the state structure, storing the on-disk - * block number for those buffers in the "altpath". - */ - path = &state->altpath; - ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); - for (blk = path->blk, level = 0; level < path->active; blk++, level++) { - if (blk->disk_blkno) { - error = xfs_da3_node_read(state->args->trans, - state->args->dp, - blk->blkno, blk->disk_blkno, - &blk->bp, XFS_ATTR_FORK); - if (error) - return error; - } else { - blk->bp = NULL; - } - } - - return 0; -} - -/* - * Look up a filename in a node attribute list. - * - * This routine gets called for any attribute fork that has more than one - * block, ie: both true Btree attr lists and for single-leaf-blocks with - * "remote" values taking up more blocks. - */ -STATIC int -xfs_attr_node_get(xfs_da_args_t *args) -{ - xfs_da_state_t *state; - xfs_da_state_blk_t *blk; - int error, retval; - int i; - - trace_xfs_attr_node_get(args); - - state = xfs_da_state_alloc(); - state->args = args; - state->mp = args->dp->i_mount; - - /* - * Search to see if name exists, and get back a pointer to it. - */ - error = xfs_da3_node_lookup_int(state, &retval); - if (error) { - retval = error; - } else if (retval == -EEXIST) { - blk = &state->path.blk[ state->path.active-1 ]; - ASSERT(blk->bp != NULL); - ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC); - - /* - * Get the value, local or "remote" - */ - retval = xfs_attr3_leaf_getvalue(blk->bp, args); - if (!retval && (args->rmtblkno > 0) - && !(args->flags & ATTR_KERNOVAL)) { - retval = xfs_attr_rmtval_get(args); - } - } - - /* - * If not in a transaction, we have to release all the buffers. - */ - for (i = 0; i < state->path.active; i++) { - xfs_trans_brelse(args->trans, state->path.blk[i].bp); - state->path.blk[i].bp = NULL; - } - - xfs_da_state_free(state); - return retval; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_attr_leaf.c b/src/linux/fs/xfs/libxfs/xfs_attr_leaf.c deleted file mode 100644 index 8ea91f3..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_attr_leaf.c +++ /dev/null @@ -1,2777 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * Copyright (c) 2013 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_bmap_btree.h" -#include "xfs_bmap.h" -#include "xfs_attr_sf.h" -#include "xfs_attr_remote.h" -#include "xfs_attr.h" -#include "xfs_attr_leaf.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_buf_item.h" -#include "xfs_cksum.h" -#include "xfs_dir2.h" -#include "xfs_log.h" - - -/* - * xfs_attr_leaf.c - * - * Routines to implement leaf blocks of attributes as Btrees of hashed names. - */ - -/*======================================================================== - * Function prototypes for the kernel. - *========================================================================*/ - -/* - * Routines used for growing the Btree. - */ -STATIC int xfs_attr3_leaf_create(struct xfs_da_args *args, - xfs_dablk_t which_block, struct xfs_buf **bpp); -STATIC int xfs_attr3_leaf_add_work(struct xfs_buf *leaf_buffer, - struct xfs_attr3_icleaf_hdr *ichdr, - struct xfs_da_args *args, int freemap_index); -STATIC void xfs_attr3_leaf_compact(struct xfs_da_args *args, - struct xfs_attr3_icleaf_hdr *ichdr, - struct xfs_buf *leaf_buffer); -STATIC void xfs_attr3_leaf_rebalance(xfs_da_state_t *state, - xfs_da_state_blk_t *blk1, - xfs_da_state_blk_t *blk2); -STATIC int xfs_attr3_leaf_figure_balance(xfs_da_state_t *state, - xfs_da_state_blk_t *leaf_blk_1, - struct xfs_attr3_icleaf_hdr *ichdr1, - xfs_da_state_blk_t *leaf_blk_2, - struct xfs_attr3_icleaf_hdr *ichdr2, - int *number_entries_in_blk1, - int *number_usedbytes_in_blk1); - -/* - * Utility routines. - */ -STATIC void xfs_attr3_leaf_moveents(struct xfs_da_args *args, - struct xfs_attr_leafblock *src_leaf, - struct xfs_attr3_icleaf_hdr *src_ichdr, int src_start, - struct xfs_attr_leafblock *dst_leaf, - struct xfs_attr3_icleaf_hdr *dst_ichdr, int dst_start, - int move_count); -STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index); - -/* - * attr3 block 'firstused' conversion helpers. - * - * firstused refers to the offset of the first used byte of the nameval region - * of an attr leaf block. The region starts at the tail of the block and expands - * backwards towards the middle. As such, firstused is initialized to the block - * size for an empty leaf block and is reduced from there. - * - * The attr3 block size is pegged to the fsb size and the maximum fsb is 64k. - * The in-core firstused field is 32-bit and thus supports the maximum fsb size. - * The on-disk field is only 16-bit, however, and overflows at 64k. Since this - * only occurs at exactly 64k, we use zero as a magic on-disk value to represent - * the attr block size. The following helpers manage the conversion between the - * in-core and on-disk formats. - */ - -static void -xfs_attr3_leaf_firstused_from_disk( - struct xfs_da_geometry *geo, - struct xfs_attr3_icleaf_hdr *to, - struct xfs_attr_leafblock *from) -{ - struct xfs_attr3_leaf_hdr *hdr3; - - if (from->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)) { - hdr3 = (struct xfs_attr3_leaf_hdr *) from; - to->firstused = be16_to_cpu(hdr3->firstused); - } else { - to->firstused = be16_to_cpu(from->hdr.firstused); - } - - /* - * Convert from the magic fsb size value to actual blocksize. This - * should only occur for empty blocks when the block size overflows - * 16-bits. - */ - if (to->firstused == XFS_ATTR3_LEAF_NULLOFF) { - ASSERT(!to->count && !to->usedbytes); - ASSERT(geo->blksize > USHRT_MAX); - to->firstused = geo->blksize; - } -} - -static void -xfs_attr3_leaf_firstused_to_disk( - struct xfs_da_geometry *geo, - struct xfs_attr_leafblock *to, - struct xfs_attr3_icleaf_hdr *from) -{ - struct xfs_attr3_leaf_hdr *hdr3; - uint32_t firstused; - - /* magic value should only be seen on disk */ - ASSERT(from->firstused != XFS_ATTR3_LEAF_NULLOFF); - - /* - * Scale down the 32-bit in-core firstused value to the 16-bit on-disk - * value. This only overflows at the max supported value of 64k. Use the - * magic on-disk value to represent block size in this case. - */ - firstused = from->firstused; - if (firstused > USHRT_MAX) { - ASSERT(from->firstused == geo->blksize); - firstused = XFS_ATTR3_LEAF_NULLOFF; - } - - if (from->magic == XFS_ATTR3_LEAF_MAGIC) { - hdr3 = (struct xfs_attr3_leaf_hdr *) to; - hdr3->firstused = cpu_to_be16(firstused); - } else { - to->hdr.firstused = cpu_to_be16(firstused); - } -} - -void -xfs_attr3_leaf_hdr_from_disk( - struct xfs_da_geometry *geo, - struct xfs_attr3_icleaf_hdr *to, - struct xfs_attr_leafblock *from) -{ - int i; - - ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC) || - from->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)); - - if (from->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)) { - struct xfs_attr3_leaf_hdr *hdr3 = (struct xfs_attr3_leaf_hdr *)from; - - to->forw = be32_to_cpu(hdr3->info.hdr.forw); - to->back = be32_to_cpu(hdr3->info.hdr.back); - to->magic = be16_to_cpu(hdr3->info.hdr.magic); - to->count = be16_to_cpu(hdr3->count); - to->usedbytes = be16_to_cpu(hdr3->usedbytes); - xfs_attr3_leaf_firstused_from_disk(geo, to, from); - to->holes = hdr3->holes; - - for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { - to->freemap[i].base = be16_to_cpu(hdr3->freemap[i].base); - to->freemap[i].size = be16_to_cpu(hdr3->freemap[i].size); - } - return; - } - to->forw = be32_to_cpu(from->hdr.info.forw); - to->back = be32_to_cpu(from->hdr.info.back); - to->magic = be16_to_cpu(from->hdr.info.magic); - to->count = be16_to_cpu(from->hdr.count); - to->usedbytes = be16_to_cpu(from->hdr.usedbytes); - xfs_attr3_leaf_firstused_from_disk(geo, to, from); - to->holes = from->hdr.holes; - - for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { - to->freemap[i].base = be16_to_cpu(from->hdr.freemap[i].base); - to->freemap[i].size = be16_to_cpu(from->hdr.freemap[i].size); - } -} - -void -xfs_attr3_leaf_hdr_to_disk( - struct xfs_da_geometry *geo, - struct xfs_attr_leafblock *to, - struct xfs_attr3_icleaf_hdr *from) -{ - int i; - - ASSERT(from->magic == XFS_ATTR_LEAF_MAGIC || - from->magic == XFS_ATTR3_LEAF_MAGIC); - - if (from->magic == XFS_ATTR3_LEAF_MAGIC) { - struct xfs_attr3_leaf_hdr *hdr3 = (struct xfs_attr3_leaf_hdr *)to; - - hdr3->info.hdr.forw = cpu_to_be32(from->forw); - hdr3->info.hdr.back = cpu_to_be32(from->back); - hdr3->info.hdr.magic = cpu_to_be16(from->magic); - hdr3->count = cpu_to_be16(from->count); - hdr3->usedbytes = cpu_to_be16(from->usedbytes); - xfs_attr3_leaf_firstused_to_disk(geo, to, from); - hdr3->holes = from->holes; - hdr3->pad1 = 0; - - for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { - hdr3->freemap[i].base = cpu_to_be16(from->freemap[i].base); - hdr3->freemap[i].size = cpu_to_be16(from->freemap[i].size); - } - return; - } - to->hdr.info.forw = cpu_to_be32(from->forw); - to->hdr.info.back = cpu_to_be32(from->back); - to->hdr.info.magic = cpu_to_be16(from->magic); - to->hdr.count = cpu_to_be16(from->count); - to->hdr.usedbytes = cpu_to_be16(from->usedbytes); - xfs_attr3_leaf_firstused_to_disk(geo, to, from); - to->hdr.holes = from->holes; - to->hdr.pad1 = 0; - - for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { - to->hdr.freemap[i].base = cpu_to_be16(from->freemap[i].base); - to->hdr.freemap[i].size = cpu_to_be16(from->freemap[i].size); - } -} - -static bool -xfs_attr3_leaf_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_attr_leafblock *leaf = bp->b_addr; - struct xfs_attr3_icleaf_hdr ichdr; - - xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf); - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - struct xfs_da3_node_hdr *hdr3 = bp->b_addr; - - if (ichdr.magic != XFS_ATTR3_LEAF_MAGIC) - return false; - - if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid)) - return false; - if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn) - return false; - if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->info.lsn))) - return false; - } else { - if (ichdr.magic != XFS_ATTR_LEAF_MAGIC) - return false; - } - if (ichdr.count == 0) - return false; - - /* XXX: need to range check rest of attr header values */ - /* XXX: hash order check? */ - - return true; -} - -static void -xfs_attr3_leaf_write_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_buf_log_item *bip = bp->b_fspriv; - struct xfs_attr3_leaf_hdr *hdr3 = bp->b_addr; - - if (!xfs_attr3_leaf_verify(bp)) { - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - return; - } - - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return; - - if (bip) - hdr3->info.lsn = cpu_to_be64(bip->bli_item.li_lsn); - - xfs_buf_update_cksum(bp, XFS_ATTR3_LEAF_CRC_OFF); -} - -/* - * leaf/node format detection on trees is sketchy, so a node read can be done on - * leaf level blocks when detection identifies the tree as a node format tree - * incorrectly. In this case, we need to swap the verifier to match the correct - * format of the block being read. - */ -static void -xfs_attr3_leaf_read_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - - if (xfs_sb_version_hascrc(&mp->m_sb) && - !xfs_buf_verify_cksum(bp, XFS_ATTR3_LEAF_CRC_OFF)) - xfs_buf_ioerror(bp, -EFSBADCRC); - else if (!xfs_attr3_leaf_verify(bp)) - xfs_buf_ioerror(bp, -EFSCORRUPTED); - - if (bp->b_error) - xfs_verifier_error(bp); -} - -const struct xfs_buf_ops xfs_attr3_leaf_buf_ops = { - .name = "xfs_attr3_leaf", - .verify_read = xfs_attr3_leaf_read_verify, - .verify_write = xfs_attr3_leaf_write_verify, -}; - -int -xfs_attr3_leaf_read( - struct xfs_trans *tp, - struct xfs_inode *dp, - xfs_dablk_t bno, - xfs_daddr_t mappedbno, - struct xfs_buf **bpp) -{ - int err; - - err = xfs_da_read_buf(tp, dp, bno, mappedbno, bpp, - XFS_ATTR_FORK, &xfs_attr3_leaf_buf_ops); - if (!err && tp) - xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_ATTR_LEAF_BUF); - return err; -} - -/*======================================================================== - * Namespace helper routines - *========================================================================*/ - -/* - * If namespace bits don't match return 0. - * If all match then return 1. - */ -STATIC int -xfs_attr_namesp_match(int arg_flags, int ondisk_flags) -{ - return XFS_ATTR_NSP_ONDISK(ondisk_flags) == XFS_ATTR_NSP_ARGS_TO_ONDISK(arg_flags); -} - - -/*======================================================================== - * External routines when attribute fork size < XFS_LITINO(mp). - *========================================================================*/ - -/* - * Query whether the requested number of additional bytes of extended - * attribute space will be able to fit inline. - * - * Returns zero if not, else the di_forkoff fork offset to be used in the - * literal area for attribute data once the new bytes have been added. - * - * di_forkoff must be 8 byte aligned, hence is stored as a >>3 value; - * special case for dev/uuid inodes, they have fixed size data forks. - */ -int -xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes) -{ - int offset; - int minforkoff; /* lower limit on valid forkoff locations */ - int maxforkoff; /* upper limit on valid forkoff locations */ - int dsize; - xfs_mount_t *mp = dp->i_mount; - - /* rounded down */ - offset = (XFS_LITINO(mp, dp->i_d.di_version) - bytes) >> 3; - - switch (dp->i_d.di_format) { - case XFS_DINODE_FMT_DEV: - minforkoff = roundup(sizeof(xfs_dev_t), 8) >> 3; - return (offset >= minforkoff) ? minforkoff : 0; - case XFS_DINODE_FMT_UUID: - minforkoff = roundup(sizeof(uuid_t), 8) >> 3; - return (offset >= minforkoff) ? minforkoff : 0; - } - - /* - * If the requested numbers of bytes is smaller or equal to the - * current attribute fork size we can always proceed. - * - * Note that if_bytes in the data fork might actually be larger than - * the current data fork size is due to delalloc extents. In that - * case either the extent count will go down when they are converted - * to real extents, or the delalloc conversion will take care of the - * literal area rebalancing. - */ - if (bytes <= XFS_IFORK_ASIZE(dp)) - return dp->i_d.di_forkoff; - - /* - * For attr2 we can try to move the forkoff if there is space in the - * literal area, but for the old format we are done if there is no - * space in the fixed attribute fork. - */ - if (!(mp->m_flags & XFS_MOUNT_ATTR2)) - return 0; - - dsize = dp->i_df.if_bytes; - - switch (dp->i_d.di_format) { - case XFS_DINODE_FMT_EXTENTS: - /* - * If there is no attr fork and the data fork is extents, - * determine if creating the default attr fork will result - * in the extents form migrating to btree. If so, the - * minimum offset only needs to be the space required for - * the btree root. - */ - if (!dp->i_d.di_forkoff && dp->i_df.if_bytes > - xfs_default_attroffset(dp)) - dsize = XFS_BMDR_SPACE_CALC(MINDBTPTRS); - break; - case XFS_DINODE_FMT_BTREE: - /* - * If we have a data btree then keep forkoff if we have one, - * otherwise we are adding a new attr, so then we set - * minforkoff to where the btree root can finish so we have - * plenty of room for attrs - */ - if (dp->i_d.di_forkoff) { - if (offset < dp->i_d.di_forkoff) - return 0; - return dp->i_d.di_forkoff; - } - dsize = XFS_BMAP_BROOT_SPACE(mp, dp->i_df.if_broot); - break; - } - - /* - * A data fork btree root must have space for at least - * MINDBTPTRS key/ptr pairs if the data fork is small or empty. - */ - minforkoff = MAX(dsize, XFS_BMDR_SPACE_CALC(MINDBTPTRS)); - minforkoff = roundup(minforkoff, 8) >> 3; - - /* attr fork btree root can have at least this many key/ptr pairs */ - maxforkoff = XFS_LITINO(mp, dp->i_d.di_version) - - XFS_BMDR_SPACE_CALC(MINABTPTRS); - maxforkoff = maxforkoff >> 3; /* rounded down */ - - if (offset >= maxforkoff) - return maxforkoff; - if (offset >= minforkoff) - return offset; - return 0; -} - -/* - * Switch on the ATTR2 superblock bit (implies also FEATURES2) - */ -STATIC void -xfs_sbversion_add_attr2(xfs_mount_t *mp, xfs_trans_t *tp) -{ - if ((mp->m_flags & XFS_MOUNT_ATTR2) && - !(xfs_sb_version_hasattr2(&mp->m_sb))) { - spin_lock(&mp->m_sb_lock); - if (!xfs_sb_version_hasattr2(&mp->m_sb)) { - xfs_sb_version_addattr2(&mp->m_sb); - spin_unlock(&mp->m_sb_lock); - xfs_log_sb(tp); - } else - spin_unlock(&mp->m_sb_lock); - } -} - -/* - * Create the initial contents of a shortform attribute list. - */ -void -xfs_attr_shortform_create(xfs_da_args_t *args) -{ - xfs_attr_sf_hdr_t *hdr; - xfs_inode_t *dp; - xfs_ifork_t *ifp; - - trace_xfs_attr_sf_create(args); - - dp = args->dp; - ASSERT(dp != NULL); - ifp = dp->i_afp; - ASSERT(ifp != NULL); - ASSERT(ifp->if_bytes == 0); - if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) { - ifp->if_flags &= ~XFS_IFEXTENTS; /* just in case */ - dp->i_d.di_aformat = XFS_DINODE_FMT_LOCAL; - ifp->if_flags |= XFS_IFINLINE; - } else { - ASSERT(ifp->if_flags & XFS_IFINLINE); - } - xfs_idata_realloc(dp, sizeof(*hdr), XFS_ATTR_FORK); - hdr = (xfs_attr_sf_hdr_t *)ifp->if_u1.if_data; - hdr->count = 0; - hdr->totsize = cpu_to_be16(sizeof(*hdr)); - xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); -} - -/* - * Add a name/value pair to the shortform attribute list. - * Overflow from the inode has already been checked for. - */ -void -xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff) -{ - xfs_attr_shortform_t *sf; - xfs_attr_sf_entry_t *sfe; - int i, offset, size; - xfs_mount_t *mp; - xfs_inode_t *dp; - xfs_ifork_t *ifp; - - trace_xfs_attr_sf_add(args); - - dp = args->dp; - mp = dp->i_mount; - dp->i_d.di_forkoff = forkoff; - - ifp = dp->i_afp; - ASSERT(ifp->if_flags & XFS_IFINLINE); - sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; - sfe = &sf->list[0]; - for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { -#ifdef DEBUG - if (sfe->namelen != args->namelen) - continue; - if (memcmp(args->name, sfe->nameval, args->namelen) != 0) - continue; - if (!xfs_attr_namesp_match(args->flags, sfe->flags)) - continue; - ASSERT(0); -#endif - } - - offset = (char *)sfe - (char *)sf; - size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen); - xfs_idata_realloc(dp, size, XFS_ATTR_FORK); - sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; - sfe = (xfs_attr_sf_entry_t *)((char *)sf + offset); - - sfe->namelen = args->namelen; - sfe->valuelen = args->valuelen; - sfe->flags = XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags); - memcpy(sfe->nameval, args->name, args->namelen); - memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen); - sf->hdr.count++; - be16_add_cpu(&sf->hdr.totsize, size); - xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA); - - xfs_sbversion_add_attr2(mp, args->trans); -} - -/* - * After the last attribute is removed revert to original inode format, - * making all literal area available to the data fork once more. - */ -void -xfs_attr_fork_remove( - struct xfs_inode *ip, - struct xfs_trans *tp) -{ - xfs_idestroy_fork(ip, XFS_ATTR_FORK); - ip->i_d.di_forkoff = 0; - ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; - - ASSERT(ip->i_d.di_anextents == 0); - ASSERT(ip->i_afp == NULL); - - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); -} - -/* - * Remove an attribute from the shortform attribute list structure. - */ -int -xfs_attr_shortform_remove(xfs_da_args_t *args) -{ - xfs_attr_shortform_t *sf; - xfs_attr_sf_entry_t *sfe; - int base, size=0, end, totsize, i; - xfs_mount_t *mp; - xfs_inode_t *dp; - - trace_xfs_attr_sf_remove(args); - - dp = args->dp; - mp = dp->i_mount; - base = sizeof(xfs_attr_sf_hdr_t); - sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data; - sfe = &sf->list[0]; - end = sf->hdr.count; - for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), - base += size, i++) { - size = XFS_ATTR_SF_ENTSIZE(sfe); - if (sfe->namelen != args->namelen) - continue; - if (memcmp(sfe->nameval, args->name, args->namelen) != 0) - continue; - if (!xfs_attr_namesp_match(args->flags, sfe->flags)) - continue; - break; - } - if (i == end) - return -ENOATTR; - - /* - * Fix up the attribute fork data, covering the hole - */ - end = base + size; - totsize = be16_to_cpu(sf->hdr.totsize); - if (end != totsize) - memmove(&((char *)sf)[base], &((char *)sf)[end], totsize - end); - sf->hdr.count--; - be16_add_cpu(&sf->hdr.totsize, -size); - - /* - * Fix up the start offset of the attribute fork - */ - totsize -= size; - if (totsize == sizeof(xfs_attr_sf_hdr_t) && - (mp->m_flags & XFS_MOUNT_ATTR2) && - (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) && - !(args->op_flags & XFS_DA_OP_ADDNAME)) { - xfs_attr_fork_remove(dp, args->trans); - } else { - xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); - dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize); - ASSERT(dp->i_d.di_forkoff); - ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) || - (args->op_flags & XFS_DA_OP_ADDNAME) || - !(mp->m_flags & XFS_MOUNT_ATTR2) || - dp->i_d.di_format == XFS_DINODE_FMT_BTREE); - xfs_trans_log_inode(args->trans, dp, - XFS_ILOG_CORE | XFS_ILOG_ADATA); - } - - xfs_sbversion_add_attr2(mp, args->trans); - - return 0; -} - -/* - * Look up a name in a shortform attribute list structure. - */ -/*ARGSUSED*/ -int -xfs_attr_shortform_lookup(xfs_da_args_t *args) -{ - xfs_attr_shortform_t *sf; - xfs_attr_sf_entry_t *sfe; - int i; - xfs_ifork_t *ifp; - - trace_xfs_attr_sf_lookup(args); - - ifp = args->dp->i_afp; - ASSERT(ifp->if_flags & XFS_IFINLINE); - sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; - sfe = &sf->list[0]; - for (i = 0; i < sf->hdr.count; - sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { - if (sfe->namelen != args->namelen) - continue; - if (memcmp(args->name, sfe->nameval, args->namelen) != 0) - continue; - if (!xfs_attr_namesp_match(args->flags, sfe->flags)) - continue; - return -EEXIST; - } - return -ENOATTR; -} - -/* - * Look up a name in a shortform attribute list structure. - */ -/*ARGSUSED*/ -int -xfs_attr_shortform_getvalue(xfs_da_args_t *args) -{ - xfs_attr_shortform_t *sf; - xfs_attr_sf_entry_t *sfe; - int i; - - ASSERT(args->dp->i_afp->if_flags == XFS_IFINLINE); - sf = (xfs_attr_shortform_t *)args->dp->i_afp->if_u1.if_data; - sfe = &sf->list[0]; - for (i = 0; i < sf->hdr.count; - sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) { - if (sfe->namelen != args->namelen) - continue; - if (memcmp(args->name, sfe->nameval, args->namelen) != 0) - continue; - if (!xfs_attr_namesp_match(args->flags, sfe->flags)) - continue; - if (args->flags & ATTR_KERNOVAL) { - args->valuelen = sfe->valuelen; - return -EEXIST; - } - if (args->valuelen < sfe->valuelen) { - args->valuelen = sfe->valuelen; - return -ERANGE; - } - args->valuelen = sfe->valuelen; - memcpy(args->value, &sfe->nameval[args->namelen], - args->valuelen); - return -EEXIST; - } - return -ENOATTR; -} - -/* - * Convert from using the shortform to the leaf. - */ -int -xfs_attr_shortform_to_leaf(xfs_da_args_t *args) -{ - xfs_inode_t *dp; - xfs_attr_shortform_t *sf; - xfs_attr_sf_entry_t *sfe; - xfs_da_args_t nargs; - char *tmpbuffer; - int error, i, size; - xfs_dablk_t blkno; - struct xfs_buf *bp; - xfs_ifork_t *ifp; - - trace_xfs_attr_sf_to_leaf(args); - - dp = args->dp; - ifp = dp->i_afp; - sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data; - size = be16_to_cpu(sf->hdr.totsize); - tmpbuffer = kmem_alloc(size, KM_SLEEP); - ASSERT(tmpbuffer != NULL); - memcpy(tmpbuffer, ifp->if_u1.if_data, size); - sf = (xfs_attr_shortform_t *)tmpbuffer; - - xfs_idata_realloc(dp, -size, XFS_ATTR_FORK); - xfs_bmap_local_to_extents_empty(dp, XFS_ATTR_FORK); - - bp = NULL; - error = xfs_da_grow_inode(args, &blkno); - if (error) { - /* - * If we hit an IO error middle of the transaction inside - * grow_inode(), we may have inconsistent data. Bail out. - */ - if (error == -EIO) - goto out; - xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */ - memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */ - goto out; - } - - ASSERT(blkno == 0); - error = xfs_attr3_leaf_create(args, blkno, &bp); - if (error) { - error = xfs_da_shrink_inode(args, 0, bp); - bp = NULL; - if (error) - goto out; - xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */ - memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */ - goto out; - } - - memset((char *)&nargs, 0, sizeof(nargs)); - nargs.dp = dp; - nargs.geo = args->geo; - nargs.firstblock = args->firstblock; - nargs.dfops = args->dfops; - nargs.total = args->total; - nargs.whichfork = XFS_ATTR_FORK; - nargs.trans = args->trans; - nargs.op_flags = XFS_DA_OP_OKNOENT; - - sfe = &sf->list[0]; - for (i = 0; i < sf->hdr.count; i++) { - nargs.name = sfe->nameval; - nargs.namelen = sfe->namelen; - nargs.value = &sfe->nameval[nargs.namelen]; - nargs.valuelen = sfe->valuelen; - nargs.hashval = xfs_da_hashname(sfe->nameval, - sfe->namelen); - nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(sfe->flags); - error = xfs_attr3_leaf_lookup_int(bp, &nargs); /* set a->index */ - ASSERT(error == -ENOATTR); - error = xfs_attr3_leaf_add(bp, &nargs); - ASSERT(error != -ENOSPC); - if (error) - goto out; - sfe = XFS_ATTR_SF_NEXTENTRY(sfe); - } - error = 0; - -out: - kmem_free(tmpbuffer); - return error; -} - -/* - * Check a leaf attribute block to see if all the entries would fit into - * a shortform attribute list. - */ -int -xfs_attr_shortform_allfit( - struct xfs_buf *bp, - struct xfs_inode *dp) -{ - struct xfs_attr_leafblock *leaf; - struct xfs_attr_leaf_entry *entry; - xfs_attr_leaf_name_local_t *name_loc; - struct xfs_attr3_icleaf_hdr leafhdr; - int bytes; - int i; - struct xfs_mount *mp = bp->b_target->bt_mount; - - leaf = bp->b_addr; - xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); - entry = xfs_attr3_leaf_entryp(leaf); - - bytes = sizeof(struct xfs_attr_sf_hdr); - for (i = 0; i < leafhdr.count; entry++, i++) { - if (entry->flags & XFS_ATTR_INCOMPLETE) - continue; /* don't copy partial entries */ - if (!(entry->flags & XFS_ATTR_LOCAL)) - return 0; - name_loc = xfs_attr3_leaf_name_local(leaf, i); - if (name_loc->namelen >= XFS_ATTR_SF_ENTSIZE_MAX) - return 0; - if (be16_to_cpu(name_loc->valuelen) >= XFS_ATTR_SF_ENTSIZE_MAX) - return 0; - bytes += sizeof(struct xfs_attr_sf_entry) - 1 - + name_loc->namelen - + be16_to_cpu(name_loc->valuelen); - } - if ((dp->i_mount->m_flags & XFS_MOUNT_ATTR2) && - (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) && - (bytes == sizeof(struct xfs_attr_sf_hdr))) - return -1; - return xfs_attr_shortform_bytesfit(dp, bytes); -} - -/* - * Convert a leaf attribute list to shortform attribute list - */ -int -xfs_attr3_leaf_to_shortform( - struct xfs_buf *bp, - struct xfs_da_args *args, - int forkoff) -{ - struct xfs_attr_leafblock *leaf; - struct xfs_attr3_icleaf_hdr ichdr; - struct xfs_attr_leaf_entry *entry; - struct xfs_attr_leaf_name_local *name_loc; - struct xfs_da_args nargs; - struct xfs_inode *dp = args->dp; - char *tmpbuffer; - int error; - int i; - - trace_xfs_attr_leaf_to_sf(args); - - tmpbuffer = kmem_alloc(args->geo->blksize, KM_SLEEP); - if (!tmpbuffer) - return -ENOMEM; - - memcpy(tmpbuffer, bp->b_addr, args->geo->blksize); - - leaf = (xfs_attr_leafblock_t *)tmpbuffer; - xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); - entry = xfs_attr3_leaf_entryp(leaf); - - /* XXX (dgc): buffer is about to be marked stale - why zero it? */ - memset(bp->b_addr, 0, args->geo->blksize); - - /* - * Clean out the prior contents of the attribute list. - */ - error = xfs_da_shrink_inode(args, 0, bp); - if (error) - goto out; - - if (forkoff == -1) { - ASSERT(dp->i_mount->m_flags & XFS_MOUNT_ATTR2); - ASSERT(dp->i_d.di_format != XFS_DINODE_FMT_BTREE); - xfs_attr_fork_remove(dp, args->trans); - goto out; - } - - xfs_attr_shortform_create(args); - - /* - * Copy the attributes - */ - memset((char *)&nargs, 0, sizeof(nargs)); - nargs.geo = args->geo; - nargs.dp = dp; - nargs.firstblock = args->firstblock; - nargs.dfops = args->dfops; - nargs.total = args->total; - nargs.whichfork = XFS_ATTR_FORK; - nargs.trans = args->trans; - nargs.op_flags = XFS_DA_OP_OKNOENT; - - for (i = 0; i < ichdr.count; entry++, i++) { - if (entry->flags & XFS_ATTR_INCOMPLETE) - continue; /* don't copy partial entries */ - if (!entry->nameidx) - continue; - ASSERT(entry->flags & XFS_ATTR_LOCAL); - name_loc = xfs_attr3_leaf_name_local(leaf, i); - nargs.name = name_loc->nameval; - nargs.namelen = name_loc->namelen; - nargs.value = &name_loc->nameval[nargs.namelen]; - nargs.valuelen = be16_to_cpu(name_loc->valuelen); - nargs.hashval = be32_to_cpu(entry->hashval); - nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags); - xfs_attr_shortform_add(&nargs, forkoff); - } - error = 0; - -out: - kmem_free(tmpbuffer); - return error; -} - -/* - * Convert from using a single leaf to a root node and a leaf. - */ -int -xfs_attr3_leaf_to_node( - struct xfs_da_args *args) -{ - struct xfs_attr_leafblock *leaf; - struct xfs_attr3_icleaf_hdr icleafhdr; - struct xfs_attr_leaf_entry *entries; - struct xfs_da_node_entry *btree; - struct xfs_da3_icnode_hdr icnodehdr; - struct xfs_da_intnode *node; - struct xfs_inode *dp = args->dp; - struct xfs_mount *mp = dp->i_mount; - struct xfs_buf *bp1 = NULL; - struct xfs_buf *bp2 = NULL; - xfs_dablk_t blkno; - int error; - - trace_xfs_attr_leaf_to_node(args); - - error = xfs_da_grow_inode(args, &blkno); - if (error) - goto out; - error = xfs_attr3_leaf_read(args->trans, dp, 0, -1, &bp1); - if (error) - goto out; - - error = xfs_da_get_buf(args->trans, dp, blkno, -1, &bp2, XFS_ATTR_FORK); - if (error) - goto out; - - /* copy leaf to new buffer, update identifiers */ - xfs_trans_buf_set_type(args->trans, bp2, XFS_BLFT_ATTR_LEAF_BUF); - bp2->b_ops = bp1->b_ops; - memcpy(bp2->b_addr, bp1->b_addr, args->geo->blksize); - if (xfs_sb_version_hascrc(&mp->m_sb)) { - struct xfs_da3_blkinfo *hdr3 = bp2->b_addr; - hdr3->blkno = cpu_to_be64(bp2->b_bn); - } - xfs_trans_log_buf(args->trans, bp2, 0, args->geo->blksize - 1); - - /* - * Set up the new root node. - */ - error = xfs_da3_node_create(args, 0, 1, &bp1, XFS_ATTR_FORK); - if (error) - goto out; - node = bp1->b_addr; - dp->d_ops->node_hdr_from_disk(&icnodehdr, node); - btree = dp->d_ops->node_tree_p(node); - - leaf = bp2->b_addr; - xfs_attr3_leaf_hdr_from_disk(args->geo, &icleafhdr, leaf); - entries = xfs_attr3_leaf_entryp(leaf); - - /* both on-disk, don't endian-flip twice */ - btree[0].hashval = entries[icleafhdr.count - 1].hashval; - btree[0].before = cpu_to_be32(blkno); - icnodehdr.count = 1; - dp->d_ops->node_hdr_to_disk(node, &icnodehdr); - xfs_trans_log_buf(args->trans, bp1, 0, args->geo->blksize - 1); - error = 0; -out: - return error; -} - -/*======================================================================== - * Routines used for growing the Btree. - *========================================================================*/ - -/* - * Create the initial contents of a leaf attribute list - * or a leaf in a node attribute list. - */ -STATIC int -xfs_attr3_leaf_create( - struct xfs_da_args *args, - xfs_dablk_t blkno, - struct xfs_buf **bpp) -{ - struct xfs_attr_leafblock *leaf; - struct xfs_attr3_icleaf_hdr ichdr; - struct xfs_inode *dp = args->dp; - struct xfs_mount *mp = dp->i_mount; - struct xfs_buf *bp; - int error; - - trace_xfs_attr_leaf_create(args); - - error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp, - XFS_ATTR_FORK); - if (error) - return error; - bp->b_ops = &xfs_attr3_leaf_buf_ops; - xfs_trans_buf_set_type(args->trans, bp, XFS_BLFT_ATTR_LEAF_BUF); - leaf = bp->b_addr; - memset(leaf, 0, args->geo->blksize); - - memset(&ichdr, 0, sizeof(ichdr)); - ichdr.firstused = args->geo->blksize; - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - struct xfs_da3_blkinfo *hdr3 = bp->b_addr; - - ichdr.magic = XFS_ATTR3_LEAF_MAGIC; - - hdr3->blkno = cpu_to_be64(bp->b_bn); - hdr3->owner = cpu_to_be64(dp->i_ino); - uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid); - - ichdr.freemap[0].base = sizeof(struct xfs_attr3_leaf_hdr); - } else { - ichdr.magic = XFS_ATTR_LEAF_MAGIC; - ichdr.freemap[0].base = sizeof(struct xfs_attr_leaf_hdr); - } - ichdr.freemap[0].size = ichdr.firstused - ichdr.freemap[0].base; - - xfs_attr3_leaf_hdr_to_disk(args->geo, leaf, &ichdr); - xfs_trans_log_buf(args->trans, bp, 0, args->geo->blksize - 1); - - *bpp = bp; - return 0; -} - -/* - * Split the leaf node, rebalance, then add the new entry. - */ -int -xfs_attr3_leaf_split( - struct xfs_da_state *state, - struct xfs_da_state_blk *oldblk, - struct xfs_da_state_blk *newblk) -{ - xfs_dablk_t blkno; - int error; - - trace_xfs_attr_leaf_split(state->args); - - /* - * Allocate space for a new leaf node. - */ - ASSERT(oldblk->magic == XFS_ATTR_LEAF_MAGIC); - error = xfs_da_grow_inode(state->args, &blkno); - if (error) - return error; - error = xfs_attr3_leaf_create(state->args, blkno, &newblk->bp); - if (error) - return error; - newblk->blkno = blkno; - newblk->magic = XFS_ATTR_LEAF_MAGIC; - - /* - * Rebalance the entries across the two leaves. - * NOTE: rebalance() currently depends on the 2nd block being empty. - */ - xfs_attr3_leaf_rebalance(state, oldblk, newblk); - error = xfs_da3_blk_link(state, oldblk, newblk); - if (error) - return error; - - /* - * Save info on "old" attribute for "atomic rename" ops, leaf_add() - * modifies the index/blkno/rmtblk/rmtblkcnt fields to show the - * "new" attrs info. Will need the "old" info to remove it later. - * - * Insert the "new" entry in the correct block. - */ - if (state->inleaf) { - trace_xfs_attr_leaf_add_old(state->args); - error = xfs_attr3_leaf_add(oldblk->bp, state->args); - } else { - trace_xfs_attr_leaf_add_new(state->args); - error = xfs_attr3_leaf_add(newblk->bp, state->args); - } - - /* - * Update last hashval in each block since we added the name. - */ - oldblk->hashval = xfs_attr_leaf_lasthash(oldblk->bp, NULL); - newblk->hashval = xfs_attr_leaf_lasthash(newblk->bp, NULL); - return error; -} - -/* - * Add a name to the leaf attribute list structure. - */ -int -xfs_attr3_leaf_add( - struct xfs_buf *bp, - struct xfs_da_args *args) -{ - struct xfs_attr_leafblock *leaf; - struct xfs_attr3_icleaf_hdr ichdr; - int tablesize; - int entsize; - int sum; - int tmp; - int i; - - trace_xfs_attr_leaf_add(args); - - leaf = bp->b_addr; - xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); - ASSERT(args->index >= 0 && args->index <= ichdr.count); - entsize = xfs_attr_leaf_newentsize(args, NULL); - - /* - * Search through freemap for first-fit on new name length. - * (may need to figure in size of entry struct too) - */ - tablesize = (ichdr.count + 1) * sizeof(xfs_attr_leaf_entry_t) - + xfs_attr3_leaf_hdr_size(leaf); - for (sum = 0, i = XFS_ATTR_LEAF_MAPSIZE - 1; i >= 0; i--) { - if (tablesize > ichdr.firstused) { - sum += ichdr.freemap[i].size; - continue; - } - if (!ichdr.freemap[i].size) - continue; /* no space in this map */ - tmp = entsize; - if (ichdr.freemap[i].base < ichdr.firstused) - tmp += sizeof(xfs_attr_leaf_entry_t); - if (ichdr.freemap[i].size >= tmp) { - tmp = xfs_attr3_leaf_add_work(bp, &ichdr, args, i); - goto out_log_hdr; - } - sum += ichdr.freemap[i].size; - } - - /* - * If there are no holes in the address space of the block, - * and we don't have enough freespace, then compaction will do us - * no good and we should just give up. - */ - if (!ichdr.holes && sum < entsize) - return -ENOSPC; - - /* - * Compact the entries to coalesce free space. - * This may change the hdr->count via dropping INCOMPLETE entries. - */ - xfs_attr3_leaf_compact(args, &ichdr, bp); - - /* - * After compaction, the block is guaranteed to have only one - * free region, in freemap[0]. If it is not big enough, give up. - */ - if (ichdr.freemap[0].size < (entsize + sizeof(xfs_attr_leaf_entry_t))) { - tmp = -ENOSPC; - goto out_log_hdr; - } - - tmp = xfs_attr3_leaf_add_work(bp, &ichdr, args, 0); - -out_log_hdr: - xfs_attr3_leaf_hdr_to_disk(args->geo, leaf, &ichdr); - xfs_trans_log_buf(args->trans, bp, - XFS_DA_LOGRANGE(leaf, &leaf->hdr, - xfs_attr3_leaf_hdr_size(leaf))); - return tmp; -} - -/* - * Add a name to a leaf attribute list structure. - */ -STATIC int -xfs_attr3_leaf_add_work( - struct xfs_buf *bp, - struct xfs_attr3_icleaf_hdr *ichdr, - struct xfs_da_args *args, - int mapindex) -{ - struct xfs_attr_leafblock *leaf; - struct xfs_attr_leaf_entry *entry; - struct xfs_attr_leaf_name_local *name_loc; - struct xfs_attr_leaf_name_remote *name_rmt; - struct xfs_mount *mp; - int tmp; - int i; - - trace_xfs_attr_leaf_add_work(args); - - leaf = bp->b_addr; - ASSERT(mapindex >= 0 && mapindex < XFS_ATTR_LEAF_MAPSIZE); - ASSERT(args->index >= 0 && args->index <= ichdr->count); - - /* - * Force open some space in the entry array and fill it in. - */ - entry = &xfs_attr3_leaf_entryp(leaf)[args->index]; - if (args->index < ichdr->count) { - tmp = ichdr->count - args->index; - tmp *= sizeof(xfs_attr_leaf_entry_t); - memmove(entry + 1, entry, tmp); - xfs_trans_log_buf(args->trans, bp, - XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry))); - } - ichdr->count++; - - /* - * Allocate space for the new string (at the end of the run). - */ - mp = args->trans->t_mountp; - ASSERT(ichdr->freemap[mapindex].base < args->geo->blksize); - ASSERT((ichdr->freemap[mapindex].base & 0x3) == 0); - ASSERT(ichdr->freemap[mapindex].size >= - xfs_attr_leaf_newentsize(args, NULL)); - ASSERT(ichdr->freemap[mapindex].size < args->geo->blksize); - ASSERT((ichdr->freemap[mapindex].size & 0x3) == 0); - - ichdr->freemap[mapindex].size -= xfs_attr_leaf_newentsize(args, &tmp); - - entry->nameidx = cpu_to_be16(ichdr->freemap[mapindex].base + - ichdr->freemap[mapindex].size); - entry->hashval = cpu_to_be32(args->hashval); - entry->flags = tmp ? XFS_ATTR_LOCAL : 0; - entry->flags |= XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags); - if (args->op_flags & XFS_DA_OP_RENAME) { - entry->flags |= XFS_ATTR_INCOMPLETE; - if ((args->blkno2 == args->blkno) && - (args->index2 <= args->index)) { - args->index2++; - } - } - xfs_trans_log_buf(args->trans, bp, - XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); - ASSERT((args->index == 0) || - (be32_to_cpu(entry->hashval) >= be32_to_cpu((entry-1)->hashval))); - ASSERT((args->index == ichdr->count - 1) || - (be32_to_cpu(entry->hashval) <= be32_to_cpu((entry+1)->hashval))); - - /* - * For "remote" attribute values, simply note that we need to - * allocate space for the "remote" value. We can't actually - * allocate the extents in this transaction, and we can't decide - * which blocks they should be as we might allocate more blocks - * as part of this transaction (a split operation for example). - */ - if (entry->flags & XFS_ATTR_LOCAL) { - name_loc = xfs_attr3_leaf_name_local(leaf, args->index); - name_loc->namelen = args->namelen; - name_loc->valuelen = cpu_to_be16(args->valuelen); - memcpy((char *)name_loc->nameval, args->name, args->namelen); - memcpy((char *)&name_loc->nameval[args->namelen], args->value, - be16_to_cpu(name_loc->valuelen)); - } else { - name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index); - name_rmt->namelen = args->namelen; - memcpy((char *)name_rmt->name, args->name, args->namelen); - entry->flags |= XFS_ATTR_INCOMPLETE; - /* just in case */ - name_rmt->valuelen = 0; - name_rmt->valueblk = 0; - args->rmtblkno = 1; - args->rmtblkcnt = xfs_attr3_rmt_blocks(mp, args->valuelen); - args->rmtvaluelen = args->valuelen; - } - xfs_trans_log_buf(args->trans, bp, - XFS_DA_LOGRANGE(leaf, xfs_attr3_leaf_name(leaf, args->index), - xfs_attr_leaf_entsize(leaf, args->index))); - - /* - * Update the control info for this leaf node - */ - if (be16_to_cpu(entry->nameidx) < ichdr->firstused) - ichdr->firstused = be16_to_cpu(entry->nameidx); - - ASSERT(ichdr->firstused >= ichdr->count * sizeof(xfs_attr_leaf_entry_t) - + xfs_attr3_leaf_hdr_size(leaf)); - tmp = (ichdr->count - 1) * sizeof(xfs_attr_leaf_entry_t) - + xfs_attr3_leaf_hdr_size(leaf); - - for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { - if (ichdr->freemap[i].base == tmp) { - ichdr->freemap[i].base += sizeof(xfs_attr_leaf_entry_t); - ichdr->freemap[i].size -= sizeof(xfs_attr_leaf_entry_t); - } - } - ichdr->usedbytes += xfs_attr_leaf_entsize(leaf, args->index); - return 0; -} - -/* - * Garbage collect a leaf attribute list block by copying it to a new buffer. - */ -STATIC void -xfs_attr3_leaf_compact( - struct xfs_da_args *args, - struct xfs_attr3_icleaf_hdr *ichdr_dst, - struct xfs_buf *bp) -{ - struct xfs_attr_leafblock *leaf_src; - struct xfs_attr_leafblock *leaf_dst; - struct xfs_attr3_icleaf_hdr ichdr_src; - struct xfs_trans *trans = args->trans; - char *tmpbuffer; - - trace_xfs_attr_leaf_compact(args); - - tmpbuffer = kmem_alloc(args->geo->blksize, KM_SLEEP); - memcpy(tmpbuffer, bp->b_addr, args->geo->blksize); - memset(bp->b_addr, 0, args->geo->blksize); - leaf_src = (xfs_attr_leafblock_t *)tmpbuffer; - leaf_dst = bp->b_addr; - - /* - * Copy the on-disk header back into the destination buffer to ensure - * all the information in the header that is not part of the incore - * header structure is preserved. - */ - memcpy(bp->b_addr, tmpbuffer, xfs_attr3_leaf_hdr_size(leaf_src)); - - /* Initialise the incore headers */ - ichdr_src = *ichdr_dst; /* struct copy */ - ichdr_dst->firstused = args->geo->blksize; - ichdr_dst->usedbytes = 0; - ichdr_dst->count = 0; - ichdr_dst->holes = 0; - ichdr_dst->freemap[0].base = xfs_attr3_leaf_hdr_size(leaf_src); - ichdr_dst->freemap[0].size = ichdr_dst->firstused - - ichdr_dst->freemap[0].base; - - /* write the header back to initialise the underlying buffer */ - xfs_attr3_leaf_hdr_to_disk(args->geo, leaf_dst, ichdr_dst); - - /* - * Copy all entry's in the same (sorted) order, - * but allocate name/value pairs packed and in sequence. - */ - xfs_attr3_leaf_moveents(args, leaf_src, &ichdr_src, 0, - leaf_dst, ichdr_dst, 0, ichdr_src.count); - /* - * this logs the entire buffer, but the caller must write the header - * back to the buffer when it is finished modifying it. - */ - xfs_trans_log_buf(trans, bp, 0, args->geo->blksize - 1); - - kmem_free(tmpbuffer); -} - -/* - * Compare two leaf blocks "order". - * Return 0 unless leaf2 should go before leaf1. - */ -static int -xfs_attr3_leaf_order( - struct xfs_buf *leaf1_bp, - struct xfs_attr3_icleaf_hdr *leaf1hdr, - struct xfs_buf *leaf2_bp, - struct xfs_attr3_icleaf_hdr *leaf2hdr) -{ - struct xfs_attr_leaf_entry *entries1; - struct xfs_attr_leaf_entry *entries2; - - entries1 = xfs_attr3_leaf_entryp(leaf1_bp->b_addr); - entries2 = xfs_attr3_leaf_entryp(leaf2_bp->b_addr); - if (leaf1hdr->count > 0 && leaf2hdr->count > 0 && - ((be32_to_cpu(entries2[0].hashval) < - be32_to_cpu(entries1[0].hashval)) || - (be32_to_cpu(entries2[leaf2hdr->count - 1].hashval) < - be32_to_cpu(entries1[leaf1hdr->count - 1].hashval)))) { - return 1; - } - return 0; -} - -int -xfs_attr_leaf_order( - struct xfs_buf *leaf1_bp, - struct xfs_buf *leaf2_bp) -{ - struct xfs_attr3_icleaf_hdr ichdr1; - struct xfs_attr3_icleaf_hdr ichdr2; - struct xfs_mount *mp = leaf1_bp->b_target->bt_mount; - - xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr1, leaf1_bp->b_addr); - xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr2, leaf2_bp->b_addr); - return xfs_attr3_leaf_order(leaf1_bp, &ichdr1, leaf2_bp, &ichdr2); -} - -/* - * Redistribute the attribute list entries between two leaf nodes, - * taking into account the size of the new entry. - * - * NOTE: if new block is empty, then it will get the upper half of the - * old block. At present, all (one) callers pass in an empty second block. - * - * This code adjusts the args->index/blkno and args->index2/blkno2 fields - * to match what it is doing in splitting the attribute leaf block. Those - * values are used in "atomic rename" operations on attributes. Note that - * the "new" and "old" values can end up in different blocks. - */ -STATIC void -xfs_attr3_leaf_rebalance( - struct xfs_da_state *state, - struct xfs_da_state_blk *blk1, - struct xfs_da_state_blk *blk2) -{ - struct xfs_da_args *args; - struct xfs_attr_leafblock *leaf1; - struct xfs_attr_leafblock *leaf2; - struct xfs_attr3_icleaf_hdr ichdr1; - struct xfs_attr3_icleaf_hdr ichdr2; - struct xfs_attr_leaf_entry *entries1; - struct xfs_attr_leaf_entry *entries2; - int count; - int totallen; - int max; - int space; - int swap; - - /* - * Set up environment. - */ - ASSERT(blk1->magic == XFS_ATTR_LEAF_MAGIC); - ASSERT(blk2->magic == XFS_ATTR_LEAF_MAGIC); - leaf1 = blk1->bp->b_addr; - leaf2 = blk2->bp->b_addr; - xfs_attr3_leaf_hdr_from_disk(state->args->geo, &ichdr1, leaf1); - xfs_attr3_leaf_hdr_from_disk(state->args->geo, &ichdr2, leaf2); - ASSERT(ichdr2.count == 0); - args = state->args; - - trace_xfs_attr_leaf_rebalance(args); - - /* - * Check ordering of blocks, reverse if it makes things simpler. - * - * NOTE: Given that all (current) callers pass in an empty - * second block, this code should never set "swap". - */ - swap = 0; - if (xfs_attr3_leaf_order(blk1->bp, &ichdr1, blk2->bp, &ichdr2)) { - struct xfs_da_state_blk *tmp_blk; - struct xfs_attr3_icleaf_hdr tmp_ichdr; - - tmp_blk = blk1; - blk1 = blk2; - blk2 = tmp_blk; - - /* struct copies to swap them rather than reconverting */ - tmp_ichdr = ichdr1; - ichdr1 = ichdr2; - ichdr2 = tmp_ichdr; - - leaf1 = blk1->bp->b_addr; - leaf2 = blk2->bp->b_addr; - swap = 1; - } - - /* - * Examine entries until we reduce the absolute difference in - * byte usage between the two blocks to a minimum. Then get - * the direction to copy and the number of elements to move. - * - * "inleaf" is true if the new entry should be inserted into blk1. - * If "swap" is also true, then reverse the sense of "inleaf". - */ - state->inleaf = xfs_attr3_leaf_figure_balance(state, blk1, &ichdr1, - blk2, &ichdr2, - &count, &totallen); - if (swap) - state->inleaf = !state->inleaf; - - /* - * Move any entries required from leaf to leaf: - */ - if (count < ichdr1.count) { - /* - * Figure the total bytes to be added to the destination leaf. - */ - /* number entries being moved */ - count = ichdr1.count - count; - space = ichdr1.usedbytes - totallen; - space += count * sizeof(xfs_attr_leaf_entry_t); - - /* - * leaf2 is the destination, compact it if it looks tight. - */ - max = ichdr2.firstused - xfs_attr3_leaf_hdr_size(leaf1); - max -= ichdr2.count * sizeof(xfs_attr_leaf_entry_t); - if (space > max) - xfs_attr3_leaf_compact(args, &ichdr2, blk2->bp); - - /* - * Move high entries from leaf1 to low end of leaf2. - */ - xfs_attr3_leaf_moveents(args, leaf1, &ichdr1, - ichdr1.count - count, leaf2, &ichdr2, 0, count); - - } else if (count > ichdr1.count) { - /* - * I assert that since all callers pass in an empty - * second buffer, this code should never execute. - */ - ASSERT(0); - - /* - * Figure the total bytes to be added to the destination leaf. - */ - /* number entries being moved */ - count -= ichdr1.count; - space = totallen - ichdr1.usedbytes; - space += count * sizeof(xfs_attr_leaf_entry_t); - - /* - * leaf1 is the destination, compact it if it looks tight. - */ - max = ichdr1.firstused - xfs_attr3_leaf_hdr_size(leaf1); - max -= ichdr1.count * sizeof(xfs_attr_leaf_entry_t); - if (space > max) - xfs_attr3_leaf_compact(args, &ichdr1, blk1->bp); - - /* - * Move low entries from leaf2 to high end of leaf1. - */ - xfs_attr3_leaf_moveents(args, leaf2, &ichdr2, 0, leaf1, &ichdr1, - ichdr1.count, count); - } - - xfs_attr3_leaf_hdr_to_disk(state->args->geo, leaf1, &ichdr1); - xfs_attr3_leaf_hdr_to_disk(state->args->geo, leaf2, &ichdr2); - xfs_trans_log_buf(args->trans, blk1->bp, 0, args->geo->blksize - 1); - xfs_trans_log_buf(args->trans, blk2->bp, 0, args->geo->blksize - 1); - - /* - * Copy out last hashval in each block for B-tree code. - */ - entries1 = xfs_attr3_leaf_entryp(leaf1); - entries2 = xfs_attr3_leaf_entryp(leaf2); - blk1->hashval = be32_to_cpu(entries1[ichdr1.count - 1].hashval); - blk2->hashval = be32_to_cpu(entries2[ichdr2.count - 1].hashval); - - /* - * Adjust the expected index for insertion. - * NOTE: this code depends on the (current) situation that the - * second block was originally empty. - * - * If the insertion point moved to the 2nd block, we must adjust - * the index. We must also track the entry just following the - * new entry for use in an "atomic rename" operation, that entry - * is always the "old" entry and the "new" entry is what we are - * inserting. The index/blkno fields refer to the "old" entry, - * while the index2/blkno2 fields refer to the "new" entry. - */ - if (blk1->index > ichdr1.count) { - ASSERT(state->inleaf == 0); - blk2->index = blk1->index - ichdr1.count; - args->index = args->index2 = blk2->index; - args->blkno = args->blkno2 = blk2->blkno; - } else if (blk1->index == ichdr1.count) { - if (state->inleaf) { - args->index = blk1->index; - args->blkno = blk1->blkno; - args->index2 = 0; - args->blkno2 = blk2->blkno; - } else { - /* - * On a double leaf split, the original attr location - * is already stored in blkno2/index2, so don't - * overwrite it overwise we corrupt the tree. - */ - blk2->index = blk1->index - ichdr1.count; - args->index = blk2->index; - args->blkno = blk2->blkno; - if (!state->extravalid) { - /* - * set the new attr location to match the old - * one and let the higher level split code - * decide where in the leaf to place it. - */ - args->index2 = blk2->index; - args->blkno2 = blk2->blkno; - } - } - } else { - ASSERT(state->inleaf == 1); - args->index = args->index2 = blk1->index; - args->blkno = args->blkno2 = blk1->blkno; - } -} - -/* - * Examine entries until we reduce the absolute difference in - * byte usage between the two blocks to a minimum. - * GROT: Is this really necessary? With other than a 512 byte blocksize, - * GROT: there will always be enough room in either block for a new entry. - * GROT: Do a double-split for this case? - */ -STATIC int -xfs_attr3_leaf_figure_balance( - struct xfs_da_state *state, - struct xfs_da_state_blk *blk1, - struct xfs_attr3_icleaf_hdr *ichdr1, - struct xfs_da_state_blk *blk2, - struct xfs_attr3_icleaf_hdr *ichdr2, - int *countarg, - int *usedbytesarg) -{ - struct xfs_attr_leafblock *leaf1 = blk1->bp->b_addr; - struct xfs_attr_leafblock *leaf2 = blk2->bp->b_addr; - struct xfs_attr_leaf_entry *entry; - int count; - int max; - int index; - int totallen = 0; - int half; - int lastdelta; - int foundit = 0; - int tmp; - - /* - * Examine entries until we reduce the absolute difference in - * byte usage between the two blocks to a minimum. - */ - max = ichdr1->count + ichdr2->count; - half = (max + 1) * sizeof(*entry); - half += ichdr1->usedbytes + ichdr2->usedbytes + - xfs_attr_leaf_newentsize(state->args, NULL); - half /= 2; - lastdelta = state->args->geo->blksize; - entry = xfs_attr3_leaf_entryp(leaf1); - for (count = index = 0; count < max; entry++, index++, count++) { - -#define XFS_ATTR_ABS(A) (((A) < 0) ? -(A) : (A)) - /* - * The new entry is in the first block, account for it. - */ - if (count == blk1->index) { - tmp = totallen + sizeof(*entry) + - xfs_attr_leaf_newentsize(state->args, NULL); - if (XFS_ATTR_ABS(half - tmp) > lastdelta) - break; - lastdelta = XFS_ATTR_ABS(half - tmp); - totallen = tmp; - foundit = 1; - } - - /* - * Wrap around into the second block if necessary. - */ - if (count == ichdr1->count) { - leaf1 = leaf2; - entry = xfs_attr3_leaf_entryp(leaf1); - index = 0; - } - - /* - * Figure out if next leaf entry would be too much. - */ - tmp = totallen + sizeof(*entry) + xfs_attr_leaf_entsize(leaf1, - index); - if (XFS_ATTR_ABS(half - tmp) > lastdelta) - break; - lastdelta = XFS_ATTR_ABS(half - tmp); - totallen = tmp; -#undef XFS_ATTR_ABS - } - - /* - * Calculate the number of usedbytes that will end up in lower block. - * If new entry not in lower block, fix up the count. - */ - totallen -= count * sizeof(*entry); - if (foundit) { - totallen -= sizeof(*entry) + - xfs_attr_leaf_newentsize(state->args, NULL); - } - - *countarg = count; - *usedbytesarg = totallen; - return foundit; -} - -/*======================================================================== - * Routines used for shrinking the Btree. - *========================================================================*/ - -/* - * Check a leaf block and its neighbors to see if the block should be - * collapsed into one or the other neighbor. Always keep the block - * with the smaller block number. - * If the current block is over 50% full, don't try to join it, return 0. - * If the block is empty, fill in the state structure and return 2. - * If it can be collapsed, fill in the state structure and return 1. - * If nothing can be done, return 0. - * - * GROT: allow for INCOMPLETE entries in calculation. - */ -int -xfs_attr3_leaf_toosmall( - struct xfs_da_state *state, - int *action) -{ - struct xfs_attr_leafblock *leaf; - struct xfs_da_state_blk *blk; - struct xfs_attr3_icleaf_hdr ichdr; - struct xfs_buf *bp; - xfs_dablk_t blkno; - int bytes; - int forward; - int error; - int retval; - int i; - - trace_xfs_attr_leaf_toosmall(state->args); - - /* - * Check for the degenerate case of the block being over 50% full. - * If so, it's not worth even looking to see if we might be able - * to coalesce with a sibling. - */ - blk = &state->path.blk[ state->path.active-1 ]; - leaf = blk->bp->b_addr; - xfs_attr3_leaf_hdr_from_disk(state->args->geo, &ichdr, leaf); - bytes = xfs_attr3_leaf_hdr_size(leaf) + - ichdr.count * sizeof(xfs_attr_leaf_entry_t) + - ichdr.usedbytes; - if (bytes > (state->args->geo->blksize >> 1)) { - *action = 0; /* blk over 50%, don't try to join */ - return 0; - } - - /* - * Check for the degenerate case of the block being empty. - * If the block is empty, we'll simply delete it, no need to - * coalesce it with a sibling block. We choose (arbitrarily) - * to merge with the forward block unless it is NULL. - */ - if (ichdr.count == 0) { - /* - * Make altpath point to the block we want to keep and - * path point to the block we want to drop (this one). - */ - forward = (ichdr.forw != 0); - memcpy(&state->altpath, &state->path, sizeof(state->path)); - error = xfs_da3_path_shift(state, &state->altpath, forward, - 0, &retval); - if (error) - return error; - if (retval) { - *action = 0; - } else { - *action = 2; - } - return 0; - } - - /* - * Examine each sibling block to see if we can coalesce with - * at least 25% free space to spare. We need to figure out - * whether to merge with the forward or the backward block. - * We prefer coalescing with the lower numbered sibling so as - * to shrink an attribute list over time. - */ - /* start with smaller blk num */ - forward = ichdr.forw < ichdr.back; - for (i = 0; i < 2; forward = !forward, i++) { - struct xfs_attr3_icleaf_hdr ichdr2; - if (forward) - blkno = ichdr.forw; - else - blkno = ichdr.back; - if (blkno == 0) - continue; - error = xfs_attr3_leaf_read(state->args->trans, state->args->dp, - blkno, -1, &bp); - if (error) - return error; - - xfs_attr3_leaf_hdr_from_disk(state->args->geo, &ichdr2, bp->b_addr); - - bytes = state->args->geo->blksize - - (state->args->geo->blksize >> 2) - - ichdr.usedbytes - ichdr2.usedbytes - - ((ichdr.count + ichdr2.count) * - sizeof(xfs_attr_leaf_entry_t)) - - xfs_attr3_leaf_hdr_size(leaf); - - xfs_trans_brelse(state->args->trans, bp); - if (bytes >= 0) - break; /* fits with at least 25% to spare */ - } - if (i >= 2) { - *action = 0; - return 0; - } - - /* - * Make altpath point to the block we want to keep (the lower - * numbered block) and path point to the block we want to drop. - */ - memcpy(&state->altpath, &state->path, sizeof(state->path)); - if (blkno < blk->blkno) { - error = xfs_da3_path_shift(state, &state->altpath, forward, - 0, &retval); - } else { - error = xfs_da3_path_shift(state, &state->path, forward, - 0, &retval); - } - if (error) - return error; - if (retval) { - *action = 0; - } else { - *action = 1; - } - return 0; -} - -/* - * Remove a name from the leaf attribute list structure. - * - * Return 1 if leaf is less than 37% full, 0 if >= 37% full. - * If two leaves are 37% full, when combined they will leave 25% free. - */ -int -xfs_attr3_leaf_remove( - struct xfs_buf *bp, - struct xfs_da_args *args) -{ - struct xfs_attr_leafblock *leaf; - struct xfs_attr3_icleaf_hdr ichdr; - struct xfs_attr_leaf_entry *entry; - int before; - int after; - int smallest; - int entsize; - int tablesize; - int tmp; - int i; - - trace_xfs_attr_leaf_remove(args); - - leaf = bp->b_addr; - xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); - - ASSERT(ichdr.count > 0 && ichdr.count < args->geo->blksize / 8); - ASSERT(args->index >= 0 && args->index < ichdr.count); - ASSERT(ichdr.firstused >= ichdr.count * sizeof(*entry) + - xfs_attr3_leaf_hdr_size(leaf)); - - entry = &xfs_attr3_leaf_entryp(leaf)[args->index]; - - ASSERT(be16_to_cpu(entry->nameidx) >= ichdr.firstused); - ASSERT(be16_to_cpu(entry->nameidx) < args->geo->blksize); - - /* - * Scan through free region table: - * check for adjacency of free'd entry with an existing one, - * find smallest free region in case we need to replace it, - * adjust any map that borders the entry table, - */ - tablesize = ichdr.count * sizeof(xfs_attr_leaf_entry_t) - + xfs_attr3_leaf_hdr_size(leaf); - tmp = ichdr.freemap[0].size; - before = after = -1; - smallest = XFS_ATTR_LEAF_MAPSIZE - 1; - entsize = xfs_attr_leaf_entsize(leaf, args->index); - for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { - ASSERT(ichdr.freemap[i].base < args->geo->blksize); - ASSERT(ichdr.freemap[i].size < args->geo->blksize); - if (ichdr.freemap[i].base == tablesize) { - ichdr.freemap[i].base -= sizeof(xfs_attr_leaf_entry_t); - ichdr.freemap[i].size += sizeof(xfs_attr_leaf_entry_t); - } - - if (ichdr.freemap[i].base + ichdr.freemap[i].size == - be16_to_cpu(entry->nameidx)) { - before = i; - } else if (ichdr.freemap[i].base == - (be16_to_cpu(entry->nameidx) + entsize)) { - after = i; - } else if (ichdr.freemap[i].size < tmp) { - tmp = ichdr.freemap[i].size; - smallest = i; - } - } - - /* - * Coalesce adjacent freemap regions, - * or replace the smallest region. - */ - if ((before >= 0) || (after >= 0)) { - if ((before >= 0) && (after >= 0)) { - ichdr.freemap[before].size += entsize; - ichdr.freemap[before].size += ichdr.freemap[after].size; - ichdr.freemap[after].base = 0; - ichdr.freemap[after].size = 0; - } else if (before >= 0) { - ichdr.freemap[before].size += entsize; - } else { - ichdr.freemap[after].base = be16_to_cpu(entry->nameidx); - ichdr.freemap[after].size += entsize; - } - } else { - /* - * Replace smallest region (if it is smaller than free'd entry) - */ - if (ichdr.freemap[smallest].size < entsize) { - ichdr.freemap[smallest].base = be16_to_cpu(entry->nameidx); - ichdr.freemap[smallest].size = entsize; - } - } - - /* - * Did we remove the first entry? - */ - if (be16_to_cpu(entry->nameidx) == ichdr.firstused) - smallest = 1; - else - smallest = 0; - - /* - * Compress the remaining entries and zero out the removed stuff. - */ - memset(xfs_attr3_leaf_name(leaf, args->index), 0, entsize); - ichdr.usedbytes -= entsize; - xfs_trans_log_buf(args->trans, bp, - XFS_DA_LOGRANGE(leaf, xfs_attr3_leaf_name(leaf, args->index), - entsize)); - - tmp = (ichdr.count - args->index) * sizeof(xfs_attr_leaf_entry_t); - memmove(entry, entry + 1, tmp); - ichdr.count--; - xfs_trans_log_buf(args->trans, bp, - XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(xfs_attr_leaf_entry_t))); - - entry = &xfs_attr3_leaf_entryp(leaf)[ichdr.count]; - memset(entry, 0, sizeof(xfs_attr_leaf_entry_t)); - - /* - * If we removed the first entry, re-find the first used byte - * in the name area. Note that if the entry was the "firstused", - * then we don't have a "hole" in our block resulting from - * removing the name. - */ - if (smallest) { - tmp = args->geo->blksize; - entry = xfs_attr3_leaf_entryp(leaf); - for (i = ichdr.count - 1; i >= 0; entry++, i--) { - ASSERT(be16_to_cpu(entry->nameidx) >= ichdr.firstused); - ASSERT(be16_to_cpu(entry->nameidx) < args->geo->blksize); - - if (be16_to_cpu(entry->nameidx) < tmp) - tmp = be16_to_cpu(entry->nameidx); - } - ichdr.firstused = tmp; - ASSERT(ichdr.firstused != 0); - } else { - ichdr.holes = 1; /* mark as needing compaction */ - } - xfs_attr3_leaf_hdr_to_disk(args->geo, leaf, &ichdr); - xfs_trans_log_buf(args->trans, bp, - XFS_DA_LOGRANGE(leaf, &leaf->hdr, - xfs_attr3_leaf_hdr_size(leaf))); - - /* - * Check if leaf is less than 50% full, caller may want to - * "join" the leaf with a sibling if so. - */ - tmp = ichdr.usedbytes + xfs_attr3_leaf_hdr_size(leaf) + - ichdr.count * sizeof(xfs_attr_leaf_entry_t); - - return tmp < args->geo->magicpct; /* leaf is < 37% full */ -} - -/* - * Move all the attribute list entries from drop_leaf into save_leaf. - */ -void -xfs_attr3_leaf_unbalance( - struct xfs_da_state *state, - struct xfs_da_state_blk *drop_blk, - struct xfs_da_state_blk *save_blk) -{ - struct xfs_attr_leafblock *drop_leaf = drop_blk->bp->b_addr; - struct xfs_attr_leafblock *save_leaf = save_blk->bp->b_addr; - struct xfs_attr3_icleaf_hdr drophdr; - struct xfs_attr3_icleaf_hdr savehdr; - struct xfs_attr_leaf_entry *entry; - - trace_xfs_attr_leaf_unbalance(state->args); - - drop_leaf = drop_blk->bp->b_addr; - save_leaf = save_blk->bp->b_addr; - xfs_attr3_leaf_hdr_from_disk(state->args->geo, &drophdr, drop_leaf); - xfs_attr3_leaf_hdr_from_disk(state->args->geo, &savehdr, save_leaf); - entry = xfs_attr3_leaf_entryp(drop_leaf); - - /* - * Save last hashval from dying block for later Btree fixup. - */ - drop_blk->hashval = be32_to_cpu(entry[drophdr.count - 1].hashval); - - /* - * Check if we need a temp buffer, or can we do it in place. - * Note that we don't check "leaf" for holes because we will - * always be dropping it, toosmall() decided that for us already. - */ - if (savehdr.holes == 0) { - /* - * dest leaf has no holes, so we add there. May need - * to make some room in the entry array. - */ - if (xfs_attr3_leaf_order(save_blk->bp, &savehdr, - drop_blk->bp, &drophdr)) { - xfs_attr3_leaf_moveents(state->args, - drop_leaf, &drophdr, 0, - save_leaf, &savehdr, 0, - drophdr.count); - } else { - xfs_attr3_leaf_moveents(state->args, - drop_leaf, &drophdr, 0, - save_leaf, &savehdr, - savehdr.count, drophdr.count); - } - } else { - /* - * Destination has holes, so we make a temporary copy - * of the leaf and add them both to that. - */ - struct xfs_attr_leafblock *tmp_leaf; - struct xfs_attr3_icleaf_hdr tmphdr; - - tmp_leaf = kmem_zalloc(state->args->geo->blksize, KM_SLEEP); - - /* - * Copy the header into the temp leaf so that all the stuff - * not in the incore header is present and gets copied back in - * once we've moved all the entries. - */ - memcpy(tmp_leaf, save_leaf, xfs_attr3_leaf_hdr_size(save_leaf)); - - memset(&tmphdr, 0, sizeof(tmphdr)); - tmphdr.magic = savehdr.magic; - tmphdr.forw = savehdr.forw; - tmphdr.back = savehdr.back; - tmphdr.firstused = state->args->geo->blksize; - - /* write the header to the temp buffer to initialise it */ - xfs_attr3_leaf_hdr_to_disk(state->args->geo, tmp_leaf, &tmphdr); - - if (xfs_attr3_leaf_order(save_blk->bp, &savehdr, - drop_blk->bp, &drophdr)) { - xfs_attr3_leaf_moveents(state->args, - drop_leaf, &drophdr, 0, - tmp_leaf, &tmphdr, 0, - drophdr.count); - xfs_attr3_leaf_moveents(state->args, - save_leaf, &savehdr, 0, - tmp_leaf, &tmphdr, tmphdr.count, - savehdr.count); - } else { - xfs_attr3_leaf_moveents(state->args, - save_leaf, &savehdr, 0, - tmp_leaf, &tmphdr, 0, - savehdr.count); - xfs_attr3_leaf_moveents(state->args, - drop_leaf, &drophdr, 0, - tmp_leaf, &tmphdr, tmphdr.count, - drophdr.count); - } - memcpy(save_leaf, tmp_leaf, state->args->geo->blksize); - savehdr = tmphdr; /* struct copy */ - kmem_free(tmp_leaf); - } - - xfs_attr3_leaf_hdr_to_disk(state->args->geo, save_leaf, &savehdr); - xfs_trans_log_buf(state->args->trans, save_blk->bp, 0, - state->args->geo->blksize - 1); - - /* - * Copy out last hashval in each block for B-tree code. - */ - entry = xfs_attr3_leaf_entryp(save_leaf); - save_blk->hashval = be32_to_cpu(entry[savehdr.count - 1].hashval); -} - -/*======================================================================== - * Routines used for finding things in the Btree. - *========================================================================*/ - -/* - * Look up a name in a leaf attribute list structure. - * This is the internal routine, it uses the caller's buffer. - * - * Note that duplicate keys are allowed, but only check within the - * current leaf node. The Btree code must check in adjacent leaf nodes. - * - * Return in args->index the index into the entry[] array of either - * the found entry, or where the entry should have been (insert before - * that entry). - * - * Don't change the args->value unless we find the attribute. - */ -int -xfs_attr3_leaf_lookup_int( - struct xfs_buf *bp, - struct xfs_da_args *args) -{ - struct xfs_attr_leafblock *leaf; - struct xfs_attr3_icleaf_hdr ichdr; - struct xfs_attr_leaf_entry *entry; - struct xfs_attr_leaf_entry *entries; - struct xfs_attr_leaf_name_local *name_loc; - struct xfs_attr_leaf_name_remote *name_rmt; - xfs_dahash_t hashval; - int probe; - int span; - - trace_xfs_attr_leaf_lookup(args); - - leaf = bp->b_addr; - xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); - entries = xfs_attr3_leaf_entryp(leaf); - ASSERT(ichdr.count < args->geo->blksize / 8); - - /* - * Binary search. (note: small blocks will skip this loop) - */ - hashval = args->hashval; - probe = span = ichdr.count / 2; - for (entry = &entries[probe]; span > 4; entry = &entries[probe]) { - span /= 2; - if (be32_to_cpu(entry->hashval) < hashval) - probe += span; - else if (be32_to_cpu(entry->hashval) > hashval) - probe -= span; - else - break; - } - ASSERT(probe >= 0 && (!ichdr.count || probe < ichdr.count)); - ASSERT(span <= 4 || be32_to_cpu(entry->hashval) == hashval); - - /* - * Since we may have duplicate hashval's, find the first matching - * hashval in the leaf. - */ - while (probe > 0 && be32_to_cpu(entry->hashval) >= hashval) { - entry--; - probe--; - } - while (probe < ichdr.count && - be32_to_cpu(entry->hashval) < hashval) { - entry++; - probe++; - } - if (probe == ichdr.count || be32_to_cpu(entry->hashval) != hashval) { - args->index = probe; - return -ENOATTR; - } - - /* - * Duplicate keys may be present, so search all of them for a match. - */ - for (; probe < ichdr.count && (be32_to_cpu(entry->hashval) == hashval); - entry++, probe++) { -/* - * GROT: Add code to remove incomplete entries. - */ - /* - * If we are looking for INCOMPLETE entries, show only those. - * If we are looking for complete entries, show only those. - */ - if ((args->flags & XFS_ATTR_INCOMPLETE) != - (entry->flags & XFS_ATTR_INCOMPLETE)) { - continue; - } - if (entry->flags & XFS_ATTR_LOCAL) { - name_loc = xfs_attr3_leaf_name_local(leaf, probe); - if (name_loc->namelen != args->namelen) - continue; - if (memcmp(args->name, name_loc->nameval, - args->namelen) != 0) - continue; - if (!xfs_attr_namesp_match(args->flags, entry->flags)) - continue; - args->index = probe; - return -EEXIST; - } else { - name_rmt = xfs_attr3_leaf_name_remote(leaf, probe); - if (name_rmt->namelen != args->namelen) - continue; - if (memcmp(args->name, name_rmt->name, - args->namelen) != 0) - continue; - if (!xfs_attr_namesp_match(args->flags, entry->flags)) - continue; - args->index = probe; - args->rmtvaluelen = be32_to_cpu(name_rmt->valuelen); - args->rmtblkno = be32_to_cpu(name_rmt->valueblk); - args->rmtblkcnt = xfs_attr3_rmt_blocks( - args->dp->i_mount, - args->rmtvaluelen); - return -EEXIST; - } - } - args->index = probe; - return -ENOATTR; -} - -/* - * Get the value associated with an attribute name from a leaf attribute - * list structure. - */ -int -xfs_attr3_leaf_getvalue( - struct xfs_buf *bp, - struct xfs_da_args *args) -{ - struct xfs_attr_leafblock *leaf; - struct xfs_attr3_icleaf_hdr ichdr; - struct xfs_attr_leaf_entry *entry; - struct xfs_attr_leaf_name_local *name_loc; - struct xfs_attr_leaf_name_remote *name_rmt; - int valuelen; - - leaf = bp->b_addr; - xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); - ASSERT(ichdr.count < args->geo->blksize / 8); - ASSERT(args->index < ichdr.count); - - entry = &xfs_attr3_leaf_entryp(leaf)[args->index]; - if (entry->flags & XFS_ATTR_LOCAL) { - name_loc = xfs_attr3_leaf_name_local(leaf, args->index); - ASSERT(name_loc->namelen == args->namelen); - ASSERT(memcmp(args->name, name_loc->nameval, args->namelen) == 0); - valuelen = be16_to_cpu(name_loc->valuelen); - if (args->flags & ATTR_KERNOVAL) { - args->valuelen = valuelen; - return 0; - } - if (args->valuelen < valuelen) { - args->valuelen = valuelen; - return -ERANGE; - } - args->valuelen = valuelen; - memcpy(args->value, &name_loc->nameval[args->namelen], valuelen); - } else { - name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index); - ASSERT(name_rmt->namelen == args->namelen); - ASSERT(memcmp(args->name, name_rmt->name, args->namelen) == 0); - args->rmtvaluelen = be32_to_cpu(name_rmt->valuelen); - args->rmtblkno = be32_to_cpu(name_rmt->valueblk); - args->rmtblkcnt = xfs_attr3_rmt_blocks(args->dp->i_mount, - args->rmtvaluelen); - if (args->flags & ATTR_KERNOVAL) { - args->valuelen = args->rmtvaluelen; - return 0; - } - if (args->valuelen < args->rmtvaluelen) { - args->valuelen = args->rmtvaluelen; - return -ERANGE; - } - args->valuelen = args->rmtvaluelen; - } - return 0; -} - -/*======================================================================== - * Utility routines. - *========================================================================*/ - -/* - * Move the indicated entries from one leaf to another. - * NOTE: this routine modifies both source and destination leaves. - */ -/*ARGSUSED*/ -STATIC void -xfs_attr3_leaf_moveents( - struct xfs_da_args *args, - struct xfs_attr_leafblock *leaf_s, - struct xfs_attr3_icleaf_hdr *ichdr_s, - int start_s, - struct xfs_attr_leafblock *leaf_d, - struct xfs_attr3_icleaf_hdr *ichdr_d, - int start_d, - int count) -{ - struct xfs_attr_leaf_entry *entry_s; - struct xfs_attr_leaf_entry *entry_d; - int desti; - int tmp; - int i; - - /* - * Check for nothing to do. - */ - if (count == 0) - return; - - /* - * Set up environment. - */ - ASSERT(ichdr_s->magic == XFS_ATTR_LEAF_MAGIC || - ichdr_s->magic == XFS_ATTR3_LEAF_MAGIC); - ASSERT(ichdr_s->magic == ichdr_d->magic); - ASSERT(ichdr_s->count > 0 && ichdr_s->count < args->geo->blksize / 8); - ASSERT(ichdr_s->firstused >= (ichdr_s->count * sizeof(*entry_s)) - + xfs_attr3_leaf_hdr_size(leaf_s)); - ASSERT(ichdr_d->count < args->geo->blksize / 8); - ASSERT(ichdr_d->firstused >= (ichdr_d->count * sizeof(*entry_d)) - + xfs_attr3_leaf_hdr_size(leaf_d)); - - ASSERT(start_s < ichdr_s->count); - ASSERT(start_d <= ichdr_d->count); - ASSERT(count <= ichdr_s->count); - - - /* - * Move the entries in the destination leaf up to make a hole? - */ - if (start_d < ichdr_d->count) { - tmp = ichdr_d->count - start_d; - tmp *= sizeof(xfs_attr_leaf_entry_t); - entry_s = &xfs_attr3_leaf_entryp(leaf_d)[start_d]; - entry_d = &xfs_attr3_leaf_entryp(leaf_d)[start_d + count]; - memmove(entry_d, entry_s, tmp); - } - - /* - * Copy all entry's in the same (sorted) order, - * but allocate attribute info packed and in sequence. - */ - entry_s = &xfs_attr3_leaf_entryp(leaf_s)[start_s]; - entry_d = &xfs_attr3_leaf_entryp(leaf_d)[start_d]; - desti = start_d; - for (i = 0; i < count; entry_s++, entry_d++, desti++, i++) { - ASSERT(be16_to_cpu(entry_s->nameidx) >= ichdr_s->firstused); - tmp = xfs_attr_leaf_entsize(leaf_s, start_s + i); -#ifdef GROT - /* - * Code to drop INCOMPLETE entries. Difficult to use as we - * may also need to change the insertion index. Code turned - * off for 6.2, should be revisited later. - */ - if (entry_s->flags & XFS_ATTR_INCOMPLETE) { /* skip partials? */ - memset(xfs_attr3_leaf_name(leaf_s, start_s + i), 0, tmp); - ichdr_s->usedbytes -= tmp; - ichdr_s->count -= 1; - entry_d--; /* to compensate for ++ in loop hdr */ - desti--; - if ((start_s + i) < offset) - result++; /* insertion index adjustment */ - } else { -#endif /* GROT */ - ichdr_d->firstused -= tmp; - /* both on-disk, don't endian flip twice */ - entry_d->hashval = entry_s->hashval; - entry_d->nameidx = cpu_to_be16(ichdr_d->firstused); - entry_d->flags = entry_s->flags; - ASSERT(be16_to_cpu(entry_d->nameidx) + tmp - <= args->geo->blksize); - memmove(xfs_attr3_leaf_name(leaf_d, desti), - xfs_attr3_leaf_name(leaf_s, start_s + i), tmp); - ASSERT(be16_to_cpu(entry_s->nameidx) + tmp - <= args->geo->blksize); - memset(xfs_attr3_leaf_name(leaf_s, start_s + i), 0, tmp); - ichdr_s->usedbytes -= tmp; - ichdr_d->usedbytes += tmp; - ichdr_s->count -= 1; - ichdr_d->count += 1; - tmp = ichdr_d->count * sizeof(xfs_attr_leaf_entry_t) - + xfs_attr3_leaf_hdr_size(leaf_d); - ASSERT(ichdr_d->firstused >= tmp); -#ifdef GROT - } -#endif /* GROT */ - } - - /* - * Zero out the entries we just copied. - */ - if (start_s == ichdr_s->count) { - tmp = count * sizeof(xfs_attr_leaf_entry_t); - entry_s = &xfs_attr3_leaf_entryp(leaf_s)[start_s]; - ASSERT(((char *)entry_s + tmp) <= - ((char *)leaf_s + args->geo->blksize)); - memset(entry_s, 0, tmp); - } else { - /* - * Move the remaining entries down to fill the hole, - * then zero the entries at the top. - */ - tmp = (ichdr_s->count - count) * sizeof(xfs_attr_leaf_entry_t); - entry_s = &xfs_attr3_leaf_entryp(leaf_s)[start_s + count]; - entry_d = &xfs_attr3_leaf_entryp(leaf_s)[start_s]; - memmove(entry_d, entry_s, tmp); - - tmp = count * sizeof(xfs_attr_leaf_entry_t); - entry_s = &xfs_attr3_leaf_entryp(leaf_s)[ichdr_s->count]; - ASSERT(((char *)entry_s + tmp) <= - ((char *)leaf_s + args->geo->blksize)); - memset(entry_s, 0, tmp); - } - - /* - * Fill in the freemap information - */ - ichdr_d->freemap[0].base = xfs_attr3_leaf_hdr_size(leaf_d); - ichdr_d->freemap[0].base += ichdr_d->count * sizeof(xfs_attr_leaf_entry_t); - ichdr_d->freemap[0].size = ichdr_d->firstused - ichdr_d->freemap[0].base; - ichdr_d->freemap[1].base = 0; - ichdr_d->freemap[2].base = 0; - ichdr_d->freemap[1].size = 0; - ichdr_d->freemap[2].size = 0; - ichdr_s->holes = 1; /* leaf may not be compact */ -} - -/* - * Pick up the last hashvalue from a leaf block. - */ -xfs_dahash_t -xfs_attr_leaf_lasthash( - struct xfs_buf *bp, - int *count) -{ - struct xfs_attr3_icleaf_hdr ichdr; - struct xfs_attr_leaf_entry *entries; - struct xfs_mount *mp = bp->b_target->bt_mount; - - xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, bp->b_addr); - entries = xfs_attr3_leaf_entryp(bp->b_addr); - if (count) - *count = ichdr.count; - if (!ichdr.count) - return 0; - return be32_to_cpu(entries[ichdr.count - 1].hashval); -} - -/* - * Calculate the number of bytes used to store the indicated attribute - * (whether local or remote only calculate bytes in this block). - */ -STATIC int -xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index) -{ - struct xfs_attr_leaf_entry *entries; - xfs_attr_leaf_name_local_t *name_loc; - xfs_attr_leaf_name_remote_t *name_rmt; - int size; - - entries = xfs_attr3_leaf_entryp(leaf); - if (entries[index].flags & XFS_ATTR_LOCAL) { - name_loc = xfs_attr3_leaf_name_local(leaf, index); - size = xfs_attr_leaf_entsize_local(name_loc->namelen, - be16_to_cpu(name_loc->valuelen)); - } else { - name_rmt = xfs_attr3_leaf_name_remote(leaf, index); - size = xfs_attr_leaf_entsize_remote(name_rmt->namelen); - } - return size; -} - -/* - * Calculate the number of bytes that would be required to store the new - * attribute (whether local or remote only calculate bytes in this block). - * This routine decides as a side effect whether the attribute will be - * a "local" or a "remote" attribute. - */ -int -xfs_attr_leaf_newentsize( - struct xfs_da_args *args, - int *local) -{ - int size; - - size = xfs_attr_leaf_entsize_local(args->namelen, args->valuelen); - if (size < xfs_attr_leaf_entsize_local_max(args->geo->blksize)) { - if (local) - *local = 1; - return size; - } - if (local) - *local = 0; - return xfs_attr_leaf_entsize_remote(args->namelen); -} - - -/*======================================================================== - * Manage the INCOMPLETE flag in a leaf entry - *========================================================================*/ - -/* - * Clear the INCOMPLETE flag on an entry in a leaf block. - */ -int -xfs_attr3_leaf_clearflag( - struct xfs_da_args *args) -{ - struct xfs_attr_leafblock *leaf; - struct xfs_attr_leaf_entry *entry; - struct xfs_attr_leaf_name_remote *name_rmt; - struct xfs_buf *bp; - int error; -#ifdef DEBUG - struct xfs_attr3_icleaf_hdr ichdr; - xfs_attr_leaf_name_local_t *name_loc; - int namelen; - char *name; -#endif /* DEBUG */ - - trace_xfs_attr_leaf_clearflag(args); - /* - * Set up the operation. - */ - error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); - if (error) - return error; - - leaf = bp->b_addr; - entry = &xfs_attr3_leaf_entryp(leaf)[args->index]; - ASSERT(entry->flags & XFS_ATTR_INCOMPLETE); - -#ifdef DEBUG - xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); - ASSERT(args->index < ichdr.count); - ASSERT(args->index >= 0); - - if (entry->flags & XFS_ATTR_LOCAL) { - name_loc = xfs_attr3_leaf_name_local(leaf, args->index); - namelen = name_loc->namelen; - name = (char *)name_loc->nameval; - } else { - name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index); - namelen = name_rmt->namelen; - name = (char *)name_rmt->name; - } - ASSERT(be32_to_cpu(entry->hashval) == args->hashval); - ASSERT(namelen == args->namelen); - ASSERT(memcmp(name, args->name, namelen) == 0); -#endif /* DEBUG */ - - entry->flags &= ~XFS_ATTR_INCOMPLETE; - xfs_trans_log_buf(args->trans, bp, - XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); - - if (args->rmtblkno) { - ASSERT((entry->flags & XFS_ATTR_LOCAL) == 0); - name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index); - name_rmt->valueblk = cpu_to_be32(args->rmtblkno); - name_rmt->valuelen = cpu_to_be32(args->rmtvaluelen); - xfs_trans_log_buf(args->trans, bp, - XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt))); - } - - /* - * Commit the flag value change and start the next trans in series. - */ - return xfs_trans_roll(&args->trans, args->dp); -} - -/* - * Set the INCOMPLETE flag on an entry in a leaf block. - */ -int -xfs_attr3_leaf_setflag( - struct xfs_da_args *args) -{ - struct xfs_attr_leafblock *leaf; - struct xfs_attr_leaf_entry *entry; - struct xfs_attr_leaf_name_remote *name_rmt; - struct xfs_buf *bp; - int error; -#ifdef DEBUG - struct xfs_attr3_icleaf_hdr ichdr; -#endif - - trace_xfs_attr_leaf_setflag(args); - - /* - * Set up the operation. - */ - error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp); - if (error) - return error; - - leaf = bp->b_addr; -#ifdef DEBUG - xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf); - ASSERT(args->index < ichdr.count); - ASSERT(args->index >= 0); -#endif - entry = &xfs_attr3_leaf_entryp(leaf)[args->index]; - - ASSERT((entry->flags & XFS_ATTR_INCOMPLETE) == 0); - entry->flags |= XFS_ATTR_INCOMPLETE; - xfs_trans_log_buf(args->trans, bp, - XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry))); - if ((entry->flags & XFS_ATTR_LOCAL) == 0) { - name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index); - name_rmt->valueblk = 0; - name_rmt->valuelen = 0; - xfs_trans_log_buf(args->trans, bp, - XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt))); - } - - /* - * Commit the flag value change and start the next trans in series. - */ - return xfs_trans_roll(&args->trans, args->dp); -} - -/* - * In a single transaction, clear the INCOMPLETE flag on the leaf entry - * given by args->blkno/index and set the INCOMPLETE flag on the leaf - * entry given by args->blkno2/index2. - * - * Note that they could be in different blocks, or in the same block. - */ -int -xfs_attr3_leaf_flipflags( - struct xfs_da_args *args) -{ - struct xfs_attr_leafblock *leaf1; - struct xfs_attr_leafblock *leaf2; - struct xfs_attr_leaf_entry *entry1; - struct xfs_attr_leaf_entry *entry2; - struct xfs_attr_leaf_name_remote *name_rmt; - struct xfs_buf *bp1; - struct xfs_buf *bp2; - int error; -#ifdef DEBUG - struct xfs_attr3_icleaf_hdr ichdr1; - struct xfs_attr3_icleaf_hdr ichdr2; - xfs_attr_leaf_name_local_t *name_loc; - int namelen1, namelen2; - char *name1, *name2; -#endif /* DEBUG */ - - trace_xfs_attr_leaf_flipflags(args); - - /* - * Read the block containing the "old" attr - */ - error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp1); - if (error) - return error; - - /* - * Read the block containing the "new" attr, if it is different - */ - if (args->blkno2 != args->blkno) { - error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno2, - -1, &bp2); - if (error) - return error; - } else { - bp2 = bp1; - } - - leaf1 = bp1->b_addr; - entry1 = &xfs_attr3_leaf_entryp(leaf1)[args->index]; - - leaf2 = bp2->b_addr; - entry2 = &xfs_attr3_leaf_entryp(leaf2)[args->index2]; - -#ifdef DEBUG - xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr1, leaf1); - ASSERT(args->index < ichdr1.count); - ASSERT(args->index >= 0); - - xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr2, leaf2); - ASSERT(args->index2 < ichdr2.count); - ASSERT(args->index2 >= 0); - - if (entry1->flags & XFS_ATTR_LOCAL) { - name_loc = xfs_attr3_leaf_name_local(leaf1, args->index); - namelen1 = name_loc->namelen; - name1 = (char *)name_loc->nameval; - } else { - name_rmt = xfs_attr3_leaf_name_remote(leaf1, args->index); - namelen1 = name_rmt->namelen; - name1 = (char *)name_rmt->name; - } - if (entry2->flags & XFS_ATTR_LOCAL) { - name_loc = xfs_attr3_leaf_name_local(leaf2, args->index2); - namelen2 = name_loc->namelen; - name2 = (char *)name_loc->nameval; - } else { - name_rmt = xfs_attr3_leaf_name_remote(leaf2, args->index2); - namelen2 = name_rmt->namelen; - name2 = (char *)name_rmt->name; - } - ASSERT(be32_to_cpu(entry1->hashval) == be32_to_cpu(entry2->hashval)); - ASSERT(namelen1 == namelen2); - ASSERT(memcmp(name1, name2, namelen1) == 0); -#endif /* DEBUG */ - - ASSERT(entry1->flags & XFS_ATTR_INCOMPLETE); - ASSERT((entry2->flags & XFS_ATTR_INCOMPLETE) == 0); - - entry1->flags &= ~XFS_ATTR_INCOMPLETE; - xfs_trans_log_buf(args->trans, bp1, - XFS_DA_LOGRANGE(leaf1, entry1, sizeof(*entry1))); - if (args->rmtblkno) { - ASSERT((entry1->flags & XFS_ATTR_LOCAL) == 0); - name_rmt = xfs_attr3_leaf_name_remote(leaf1, args->index); - name_rmt->valueblk = cpu_to_be32(args->rmtblkno); - name_rmt->valuelen = cpu_to_be32(args->rmtvaluelen); - xfs_trans_log_buf(args->trans, bp1, - XFS_DA_LOGRANGE(leaf1, name_rmt, sizeof(*name_rmt))); - } - - entry2->flags |= XFS_ATTR_INCOMPLETE; - xfs_trans_log_buf(args->trans, bp2, - XFS_DA_LOGRANGE(leaf2, entry2, sizeof(*entry2))); - if ((entry2->flags & XFS_ATTR_LOCAL) == 0) { - name_rmt = xfs_attr3_leaf_name_remote(leaf2, args->index2); - name_rmt->valueblk = 0; - name_rmt->valuelen = 0; - xfs_trans_log_buf(args->trans, bp2, - XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt))); - } - - /* - * Commit the flag value change and start the next trans in series. - */ - error = xfs_trans_roll(&args->trans, args->dp); - - return error; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_attr_leaf.h b/src/linux/fs/xfs/libxfs/xfs_attr_leaf.h deleted file mode 100644 index 4f2aed0..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_attr_leaf.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2000,2002-2003,2005 Silicon Graphics, Inc. - * Copyright (c) 2013 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_ATTR_LEAF_H__ -#define __XFS_ATTR_LEAF_H__ - -struct attrlist; -struct attrlist_cursor_kern; -struct xfs_attr_list_context; -struct xfs_da_args; -struct xfs_da_state; -struct xfs_da_state_blk; -struct xfs_inode; -struct xfs_trans; - -/* - * Used to keep a list of "remote value" extents when unlinking an inode. - */ -typedef struct xfs_attr_inactive_list { - xfs_dablk_t valueblk; /* block number of value bytes */ - int valuelen; /* number of bytes in value */ -} xfs_attr_inactive_list_t; - - -/*======================================================================== - * Function prototypes for the kernel. - *========================================================================*/ - -/* - * Internal routines when attribute fork size < XFS_LITINO(mp). - */ -void xfs_attr_shortform_create(struct xfs_da_args *args); -void xfs_attr_shortform_add(struct xfs_da_args *args, int forkoff); -int xfs_attr_shortform_lookup(struct xfs_da_args *args); -int xfs_attr_shortform_getvalue(struct xfs_da_args *args); -int xfs_attr_shortform_to_leaf(struct xfs_da_args *args); -int xfs_attr_shortform_remove(struct xfs_da_args *args); -int xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp); -int xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes); -void xfs_attr_fork_remove(struct xfs_inode *ip, struct xfs_trans *tp); - -/* - * Internal routines when attribute fork size == XFS_LBSIZE(mp). - */ -int xfs_attr3_leaf_to_node(struct xfs_da_args *args); -int xfs_attr3_leaf_to_shortform(struct xfs_buf *bp, - struct xfs_da_args *args, int forkoff); -int xfs_attr3_leaf_clearflag(struct xfs_da_args *args); -int xfs_attr3_leaf_setflag(struct xfs_da_args *args); -int xfs_attr3_leaf_flipflags(struct xfs_da_args *args); - -/* - * Routines used for growing the Btree. - */ -int xfs_attr3_leaf_split(struct xfs_da_state *state, - struct xfs_da_state_blk *oldblk, - struct xfs_da_state_blk *newblk); -int xfs_attr3_leaf_lookup_int(struct xfs_buf *leaf, - struct xfs_da_args *args); -int xfs_attr3_leaf_getvalue(struct xfs_buf *bp, struct xfs_da_args *args); -int xfs_attr3_leaf_add(struct xfs_buf *leaf_buffer, - struct xfs_da_args *args); -int xfs_attr3_leaf_remove(struct xfs_buf *leaf_buffer, - struct xfs_da_args *args); -int xfs_attr3_leaf_list_int(struct xfs_buf *bp, - struct xfs_attr_list_context *context); - -/* - * Routines used for shrinking the Btree. - */ -int xfs_attr3_leaf_toosmall(struct xfs_da_state *state, int *retval); -void xfs_attr3_leaf_unbalance(struct xfs_da_state *state, - struct xfs_da_state_blk *drop_blk, - struct xfs_da_state_blk *save_blk); -/* - * Utility routines. - */ -xfs_dahash_t xfs_attr_leaf_lasthash(struct xfs_buf *bp, int *count); -int xfs_attr_leaf_order(struct xfs_buf *leaf1_bp, - struct xfs_buf *leaf2_bp); -int xfs_attr_leaf_newentsize(struct xfs_da_args *args, int *local); -int xfs_attr3_leaf_read(struct xfs_trans *tp, struct xfs_inode *dp, - xfs_dablk_t bno, xfs_daddr_t mappedbno, - struct xfs_buf **bpp); -void xfs_attr3_leaf_hdr_from_disk(struct xfs_da_geometry *geo, - struct xfs_attr3_icleaf_hdr *to, - struct xfs_attr_leafblock *from); -void xfs_attr3_leaf_hdr_to_disk(struct xfs_da_geometry *geo, - struct xfs_attr_leafblock *to, - struct xfs_attr3_icleaf_hdr *from); - -#endif /* __XFS_ATTR_LEAF_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_attr_remote.c b/src/linux/fs/xfs/libxfs/xfs_attr_remote.c deleted file mode 100644 index d52f525..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_attr_remote.c +++ /dev/null @@ -1,628 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * Copyright (c) 2013 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_inode.h" -#include "xfs_alloc.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_bmap.h" -#include "xfs_bmap_util.h" -#include "xfs_attr.h" -#include "xfs_attr_leaf.h" -#include "xfs_attr_remote.h" -#include "xfs_trans_space.h" -#include "xfs_trace.h" -#include "xfs_cksum.h" -#include "xfs_buf_item.h" -#include "xfs_error.h" - -#define ATTR_RMTVALUE_MAPSIZE 1 /* # of map entries at once */ - -/* - * Each contiguous block has a header, so it is not just a simple attribute - * length to FSB conversion. - */ -int -xfs_attr3_rmt_blocks( - struct xfs_mount *mp, - int attrlen) -{ - if (xfs_sb_version_hascrc(&mp->m_sb)) { - int buflen = XFS_ATTR3_RMT_BUF_SPACE(mp, mp->m_sb.sb_blocksize); - return (attrlen + buflen - 1) / buflen; - } - return XFS_B_TO_FSB(mp, attrlen); -} - -/* - * Checking of the remote attribute header is split into two parts. The verifier - * does CRC, location and bounds checking, the unpacking function checks the - * attribute parameters and owner. - */ -static bool -xfs_attr3_rmt_hdr_ok( - void *ptr, - xfs_ino_t ino, - uint32_t offset, - uint32_t size, - xfs_daddr_t bno) -{ - struct xfs_attr3_rmt_hdr *rmt = ptr; - - if (bno != be64_to_cpu(rmt->rm_blkno)) - return false; - if (offset != be32_to_cpu(rmt->rm_offset)) - return false; - if (size != be32_to_cpu(rmt->rm_bytes)) - return false; - if (ino != be64_to_cpu(rmt->rm_owner)) - return false; - - /* ok */ - return true; -} - -static bool -xfs_attr3_rmt_verify( - struct xfs_mount *mp, - void *ptr, - int fsbsize, - xfs_daddr_t bno) -{ - struct xfs_attr3_rmt_hdr *rmt = ptr; - - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return false; - if (rmt->rm_magic != cpu_to_be32(XFS_ATTR3_RMT_MAGIC)) - return false; - if (!uuid_equal(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid)) - return false; - if (be64_to_cpu(rmt->rm_blkno) != bno) - return false; - if (be32_to_cpu(rmt->rm_bytes) > fsbsize - sizeof(*rmt)) - return false; - if (be32_to_cpu(rmt->rm_offset) + - be32_to_cpu(rmt->rm_bytes) > XFS_XATTR_SIZE_MAX) - return false; - if (rmt->rm_owner == 0) - return false; - - return true; -} - -static void -xfs_attr3_rmt_read_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - char *ptr; - int len; - xfs_daddr_t bno; - int blksize = mp->m_attr_geo->blksize; - - /* no verification of non-crc buffers */ - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return; - - ptr = bp->b_addr; - bno = bp->b_bn; - len = BBTOB(bp->b_length); - ASSERT(len >= blksize); - - while (len > 0) { - if (!xfs_verify_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF)) { - xfs_buf_ioerror(bp, -EFSBADCRC); - break; - } - if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) { - xfs_buf_ioerror(bp, -EFSCORRUPTED); - break; - } - len -= blksize; - ptr += blksize; - bno += BTOBB(blksize); - } - - if (bp->b_error) - xfs_verifier_error(bp); - else - ASSERT(len == 0); -} - -static void -xfs_attr3_rmt_write_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - int blksize = mp->m_attr_geo->blksize; - char *ptr; - int len; - xfs_daddr_t bno; - - /* no verification of non-crc buffers */ - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return; - - ptr = bp->b_addr; - bno = bp->b_bn; - len = BBTOB(bp->b_length); - ASSERT(len >= blksize); - - while (len > 0) { - struct xfs_attr3_rmt_hdr *rmt = (struct xfs_attr3_rmt_hdr *)ptr; - - if (!xfs_attr3_rmt_verify(mp, ptr, blksize, bno)) { - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - return; - } - - /* - * Ensure we aren't writing bogus LSNs to disk. See - * xfs_attr3_rmt_hdr_set() for the explanation. - */ - if (rmt->rm_lsn != cpu_to_be64(NULLCOMMITLSN)) { - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - return; - } - xfs_update_cksum(ptr, blksize, XFS_ATTR3_RMT_CRC_OFF); - - len -= blksize; - ptr += blksize; - bno += BTOBB(blksize); - } - ASSERT(len == 0); -} - -const struct xfs_buf_ops xfs_attr3_rmt_buf_ops = { - .name = "xfs_attr3_rmt", - .verify_read = xfs_attr3_rmt_read_verify, - .verify_write = xfs_attr3_rmt_write_verify, -}; - -STATIC int -xfs_attr3_rmt_hdr_set( - struct xfs_mount *mp, - void *ptr, - xfs_ino_t ino, - uint32_t offset, - uint32_t size, - xfs_daddr_t bno) -{ - struct xfs_attr3_rmt_hdr *rmt = ptr; - - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return 0; - - rmt->rm_magic = cpu_to_be32(XFS_ATTR3_RMT_MAGIC); - rmt->rm_offset = cpu_to_be32(offset); - rmt->rm_bytes = cpu_to_be32(size); - uuid_copy(&rmt->rm_uuid, &mp->m_sb.sb_meta_uuid); - rmt->rm_owner = cpu_to_be64(ino); - rmt->rm_blkno = cpu_to_be64(bno); - - /* - * Remote attribute blocks are written synchronously, so we don't - * have an LSN that we can stamp in them that makes any sense to log - * recovery. To ensure that log recovery handles overwrites of these - * blocks sanely (i.e. once they've been freed and reallocated as some - * other type of metadata) we need to ensure that the LSN has a value - * that tells log recovery to ignore the LSN and overwrite the buffer - * with whatever is in it's log. To do this, we use the magic - * NULLCOMMITLSN to indicate that the LSN is invalid. - */ - rmt->rm_lsn = cpu_to_be64(NULLCOMMITLSN); - - return sizeof(struct xfs_attr3_rmt_hdr); -} - -/* - * Helper functions to copy attribute data in and out of the one disk extents - */ -STATIC int -xfs_attr_rmtval_copyout( - struct xfs_mount *mp, - struct xfs_buf *bp, - xfs_ino_t ino, - int *offset, - int *valuelen, - __uint8_t **dst) -{ - char *src = bp->b_addr; - xfs_daddr_t bno = bp->b_bn; - int len = BBTOB(bp->b_length); - int blksize = mp->m_attr_geo->blksize; - - ASSERT(len >= blksize); - - while (len > 0 && *valuelen > 0) { - int hdr_size = 0; - int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize); - - byte_cnt = min(*valuelen, byte_cnt); - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - if (!xfs_attr3_rmt_hdr_ok(src, ino, *offset, - byte_cnt, bno)) { - xfs_alert(mp, -"remote attribute header mismatch bno/off/len/owner (0x%llx/0x%x/Ox%x/0x%llx)", - bno, *offset, byte_cnt, ino); - return -EFSCORRUPTED; - } - hdr_size = sizeof(struct xfs_attr3_rmt_hdr); - } - - memcpy(*dst, src + hdr_size, byte_cnt); - - /* roll buffer forwards */ - len -= blksize; - src += blksize; - bno += BTOBB(blksize); - - /* roll attribute data forwards */ - *valuelen -= byte_cnt; - *dst += byte_cnt; - *offset += byte_cnt; - } - return 0; -} - -STATIC void -xfs_attr_rmtval_copyin( - struct xfs_mount *mp, - struct xfs_buf *bp, - xfs_ino_t ino, - int *offset, - int *valuelen, - __uint8_t **src) -{ - char *dst = bp->b_addr; - xfs_daddr_t bno = bp->b_bn; - int len = BBTOB(bp->b_length); - int blksize = mp->m_attr_geo->blksize; - - ASSERT(len >= blksize); - - while (len > 0 && *valuelen > 0) { - int hdr_size; - int byte_cnt = XFS_ATTR3_RMT_BUF_SPACE(mp, blksize); - - byte_cnt = min(*valuelen, byte_cnt); - hdr_size = xfs_attr3_rmt_hdr_set(mp, dst, ino, *offset, - byte_cnt, bno); - - memcpy(dst + hdr_size, *src, byte_cnt); - - /* - * If this is the last block, zero the remainder of it. - * Check that we are actually the last block, too. - */ - if (byte_cnt + hdr_size < blksize) { - ASSERT(*valuelen - byte_cnt == 0); - ASSERT(len == blksize); - memset(dst + hdr_size + byte_cnt, 0, - blksize - hdr_size - byte_cnt); - } - - /* roll buffer forwards */ - len -= blksize; - dst += blksize; - bno += BTOBB(blksize); - - /* roll attribute data forwards */ - *valuelen -= byte_cnt; - *src += byte_cnt; - *offset += byte_cnt; - } -} - -/* - * Read the value associated with an attribute from the out-of-line buffer - * that we stored it in. - */ -int -xfs_attr_rmtval_get( - struct xfs_da_args *args) -{ - struct xfs_bmbt_irec map[ATTR_RMTVALUE_MAPSIZE]; - struct xfs_mount *mp = args->dp->i_mount; - struct xfs_buf *bp; - xfs_dablk_t lblkno = args->rmtblkno; - __uint8_t *dst = args->value; - int valuelen; - int nmap; - int error; - int blkcnt = args->rmtblkcnt; - int i; - int offset = 0; - - trace_xfs_attr_rmtval_get(args); - - ASSERT(!(args->flags & ATTR_KERNOVAL)); - ASSERT(args->rmtvaluelen == args->valuelen); - - valuelen = args->rmtvaluelen; - while (valuelen > 0) { - nmap = ATTR_RMTVALUE_MAPSIZE; - error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, - blkcnt, map, &nmap, - XFS_BMAPI_ATTRFORK); - if (error) - return error; - ASSERT(nmap >= 1); - - for (i = 0; (i < nmap) && (valuelen > 0); i++) { - xfs_daddr_t dblkno; - int dblkcnt; - - ASSERT((map[i].br_startblock != DELAYSTARTBLOCK) && - (map[i].br_startblock != HOLESTARTBLOCK)); - dblkno = XFS_FSB_TO_DADDR(mp, map[i].br_startblock); - dblkcnt = XFS_FSB_TO_BB(mp, map[i].br_blockcount); - error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, - dblkno, dblkcnt, 0, &bp, - &xfs_attr3_rmt_buf_ops); - if (error) - return error; - - error = xfs_attr_rmtval_copyout(mp, bp, args->dp->i_ino, - &offset, &valuelen, - &dst); - xfs_buf_relse(bp); - if (error) - return error; - - /* roll attribute extent map forwards */ - lblkno += map[i].br_blockcount; - blkcnt -= map[i].br_blockcount; - } - } - ASSERT(valuelen == 0); - return 0; -} - -/* - * Write the value associated with an attribute into the out-of-line buffer - * that we have defined for it. - */ -int -xfs_attr_rmtval_set( - struct xfs_da_args *args) -{ - struct xfs_inode *dp = args->dp; - struct xfs_mount *mp = dp->i_mount; - struct xfs_bmbt_irec map; - xfs_dablk_t lblkno; - xfs_fileoff_t lfileoff = 0; - __uint8_t *src = args->value; - int blkcnt; - int valuelen; - int nmap; - int error; - int offset = 0; - - trace_xfs_attr_rmtval_set(args); - - /* - * Find a "hole" in the attribute address space large enough for - * us to drop the new attribute's value into. Because CRC enable - * attributes have headers, we can't just do a straight byte to FSB - * conversion and have to take the header space into account. - */ - blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen); - error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff, - XFS_ATTR_FORK); - if (error) - return error; - - args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff; - args->rmtblkcnt = blkcnt; - - /* - * Roll through the "value", allocating blocks on disk as required. - */ - while (blkcnt > 0) { - /* - * Allocate a single extent, up to the size of the value. - * - * Note that we have to consider this a data allocation as we - * write the remote attribute without logging the contents. - * Hence we must ensure that we aren't using blocks that are on - * the busy list so that we don't overwrite blocks which have - * recently been freed but their transactions are not yet - * committed to disk. If we overwrite the contents of a busy - * extent and then crash then the block may not contain the - * correct metadata after log recovery occurs. - */ - xfs_defer_init(args->dfops, args->firstblock); - nmap = 1; - error = xfs_bmapi_write(args->trans, dp, (xfs_fileoff_t)lblkno, - blkcnt, XFS_BMAPI_ATTRFORK, args->firstblock, - args->total, &map, &nmap, args->dfops); - if (!error) - error = xfs_defer_finish(&args->trans, args->dfops, dp); - if (error) { - args->trans = NULL; - xfs_defer_cancel(args->dfops); - return error; - } - - ASSERT(nmap == 1); - ASSERT((map.br_startblock != DELAYSTARTBLOCK) && - (map.br_startblock != HOLESTARTBLOCK)); - lblkno += map.br_blockcount; - blkcnt -= map.br_blockcount; - - /* - * Start the next trans in the chain. - */ - error = xfs_trans_roll(&args->trans, dp); - if (error) - return error; - } - - /* - * Roll through the "value", copying the attribute value to the - * already-allocated blocks. Blocks are written synchronously - * so that we can know they are all on disk before we turn off - * the INCOMPLETE flag. - */ - lblkno = args->rmtblkno; - blkcnt = args->rmtblkcnt; - valuelen = args->rmtvaluelen; - while (valuelen > 0) { - struct xfs_buf *bp; - xfs_daddr_t dblkno; - int dblkcnt; - - ASSERT(blkcnt > 0); - - xfs_defer_init(args->dfops, args->firstblock); - nmap = 1; - error = xfs_bmapi_read(dp, (xfs_fileoff_t)lblkno, - blkcnt, &map, &nmap, - XFS_BMAPI_ATTRFORK); - if (error) - return error; - ASSERT(nmap == 1); - ASSERT((map.br_startblock != DELAYSTARTBLOCK) && - (map.br_startblock != HOLESTARTBLOCK)); - - dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), - dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); - - bp = xfs_buf_get(mp->m_ddev_targp, dblkno, dblkcnt, 0); - if (!bp) - return -ENOMEM; - bp->b_ops = &xfs_attr3_rmt_buf_ops; - - xfs_attr_rmtval_copyin(mp, bp, args->dp->i_ino, &offset, - &valuelen, &src); - - error = xfs_bwrite(bp); /* GROT: NOTE: synchronous write */ - xfs_buf_relse(bp); - if (error) - return error; - - - /* roll attribute extent map forwards */ - lblkno += map.br_blockcount; - blkcnt -= map.br_blockcount; - } - ASSERT(valuelen == 0); - return 0; -} - -/* - * Remove the value associated with an attribute by deleting the - * out-of-line buffer that it is stored on. - */ -int -xfs_attr_rmtval_remove( - struct xfs_da_args *args) -{ - struct xfs_mount *mp = args->dp->i_mount; - xfs_dablk_t lblkno; - int blkcnt; - int error; - int done; - - trace_xfs_attr_rmtval_remove(args); - - /* - * Roll through the "value", invalidating the attribute value's blocks. - */ - lblkno = args->rmtblkno; - blkcnt = args->rmtblkcnt; - while (blkcnt > 0) { - struct xfs_bmbt_irec map; - struct xfs_buf *bp; - xfs_daddr_t dblkno; - int dblkcnt; - int nmap; - - /* - * Try to remember where we decided to put the value. - */ - nmap = 1; - error = xfs_bmapi_read(args->dp, (xfs_fileoff_t)lblkno, - blkcnt, &map, &nmap, XFS_BMAPI_ATTRFORK); - if (error) - return error; - ASSERT(nmap == 1); - ASSERT((map.br_startblock != DELAYSTARTBLOCK) && - (map.br_startblock != HOLESTARTBLOCK)); - - dblkno = XFS_FSB_TO_DADDR(mp, map.br_startblock), - dblkcnt = XFS_FSB_TO_BB(mp, map.br_blockcount); - - /* - * If the "remote" value is in the cache, remove it. - */ - bp = xfs_incore(mp->m_ddev_targp, dblkno, dblkcnt, XBF_TRYLOCK); - if (bp) { - xfs_buf_stale(bp); - xfs_buf_relse(bp); - bp = NULL; - } - - lblkno += map.br_blockcount; - blkcnt -= map.br_blockcount; - } - - /* - * Keep de-allocating extents until the remote-value region is gone. - */ - lblkno = args->rmtblkno; - blkcnt = args->rmtblkcnt; - done = 0; - while (!done) { - xfs_defer_init(args->dfops, args->firstblock); - error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt, - XFS_BMAPI_ATTRFORK, 1, args->firstblock, - args->dfops, &done); - if (!error) - error = xfs_defer_finish(&args->trans, args->dfops, - args->dp); - if (error) { - args->trans = NULL; - xfs_defer_cancel(args->dfops); - return error; - } - - /* - * Close out trans and start the next one in the chain. - */ - error = xfs_trans_roll(&args->trans, args->dp); - if (error) - return error; - } - return 0; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_attr_remote.h b/src/linux/fs/xfs/libxfs/xfs_attr_remote.h deleted file mode 100644 index 5a9acfa..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_attr_remote.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2013 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_ATTR_REMOTE_H__ -#define __XFS_ATTR_REMOTE_H__ - -int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen); - -int xfs_attr_rmtval_get(struct xfs_da_args *args); -int xfs_attr_rmtval_set(struct xfs_da_args *args); -int xfs_attr_rmtval_remove(struct xfs_da_args *args); - -#endif /* __XFS_ATTR_REMOTE_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_attr_sf.h b/src/linux/fs/xfs/libxfs/xfs_attr_sf.h deleted file mode 100644 index 90928bb..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_attr_sf.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2000,2002,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_ATTR_SF_H__ -#define __XFS_ATTR_SF_H__ - -/* - * Attribute storage when stored inside the inode. - * - * Small attribute lists are packed as tightly as possible so as - * to fit into the literal area of the inode. - */ -typedef struct xfs_attr_sf_hdr xfs_attr_sf_hdr_t; -typedef struct xfs_attr_sf_entry xfs_attr_sf_entry_t; - -/* - * We generate this then sort it, attr_list() must return things in hash-order. - */ -typedef struct xfs_attr_sf_sort { - __uint8_t entno; /* entry number in original list */ - __uint8_t namelen; /* length of name value (no null) */ - __uint8_t valuelen; /* length of value */ - __uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */ - xfs_dahash_t hash; /* this entry's hash value */ - unsigned char *name; /* name value, pointer into buffer */ -} xfs_attr_sf_sort_t; - -#define XFS_ATTR_SF_ENTSIZE_BYNAME(nlen,vlen) /* space name/value uses */ \ - (((int)sizeof(xfs_attr_sf_entry_t)-1 + (nlen)+(vlen))) -#define XFS_ATTR_SF_ENTSIZE_MAX /* max space for name&value */ \ - ((1 << (NBBY*(int)sizeof(__uint8_t))) - 1) -#define XFS_ATTR_SF_ENTSIZE(sfep) /* space an entry uses */ \ - ((int)sizeof(xfs_attr_sf_entry_t)-1 + (sfep)->namelen+(sfep)->valuelen) -#define XFS_ATTR_SF_NEXTENTRY(sfep) /* next entry in struct */ \ - ((xfs_attr_sf_entry_t *)((char *)(sfep) + XFS_ATTR_SF_ENTSIZE(sfep))) -#define XFS_ATTR_SF_TOTSIZE(dp) /* total space in use */ \ - (be16_to_cpu(((xfs_attr_shortform_t *) \ - ((dp)->i_afp->if_u1.if_data))->hdr.totsize)) - -#endif /* __XFS_ATTR_SF_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_bit.c b/src/linux/fs/xfs/libxfs/xfs_bit.c deleted file mode 100644 index 0a94cce..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_bit.c +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_log_format.h" -#include "xfs_bit.h" - -/* - * XFS bit manipulation routines, used in non-realtime code. - */ - -/* - * Return whether bitmap is empty. - * Size is number of words in the bitmap, which is padded to word boundary - * Returns 1 for empty, 0 for non-empty. - */ -int -xfs_bitmap_empty(uint *map, uint size) -{ - uint i; - - for (i = 0; i < size; i++) { - if (map[i] != 0) - return 0; - } - - return 1; -} - -/* - * Count the number of contiguous bits set in the bitmap starting with bit - * start_bit. Size is the size of the bitmap in words. - */ -int -xfs_contig_bits(uint *map, uint size, uint start_bit) -{ - uint * p = ((unsigned int *) map) + (start_bit >> BIT_TO_WORD_SHIFT); - uint result = 0; - uint tmp; - - size <<= BIT_TO_WORD_SHIFT; - - ASSERT(start_bit < size); - size -= start_bit & ~(NBWORD - 1); - start_bit &= (NBWORD - 1); - if (start_bit) { - tmp = *p++; - /* set to one first offset bits prior to start */ - tmp |= (~0U >> (NBWORD-start_bit)); - if (tmp != ~0U) - goto found; - result += NBWORD; - size -= NBWORD; - } - while (size) { - if ((tmp = *p++) != ~0U) - goto found; - result += NBWORD; - size -= NBWORD; - } - return result - start_bit; -found: - return result + ffz(tmp) - start_bit; -} - -/* - * This takes the bit number to start looking from and - * returns the next set bit from there. It returns -1 - * if there are no more bits set or the start bit is - * beyond the end of the bitmap. - * - * Size is the number of words, not bytes, in the bitmap. - */ -int xfs_next_bit(uint *map, uint size, uint start_bit) -{ - uint * p = ((unsigned int *) map) + (start_bit >> BIT_TO_WORD_SHIFT); - uint result = start_bit & ~(NBWORD - 1); - uint tmp; - - size <<= BIT_TO_WORD_SHIFT; - - if (start_bit >= size) - return -1; - size -= result; - start_bit &= (NBWORD - 1); - if (start_bit) { - tmp = *p++; - /* set to zero first offset bits prior to start */ - tmp &= (~0U << start_bit); - if (tmp != 0U) - goto found; - result += NBWORD; - size -= NBWORD; - } - while (size) { - if ((tmp = *p++) != 0U) - goto found; - result += NBWORD; - size -= NBWORD; - } - return -1; -found: - return result + ffs(tmp) - 1; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_bit.h b/src/linux/fs/xfs/libxfs/xfs_bit.h deleted file mode 100644 index e1649c0..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_bit.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2000,2002,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_BIT_H__ -#define __XFS_BIT_H__ - -/* - * XFS bit manipulation routines. - */ - -/* - * masks with n high/low bits set, 64-bit values - */ -static inline __uint64_t xfs_mask64hi(int n) -{ - return (__uint64_t)-1 << (64 - (n)); -} -static inline __uint32_t xfs_mask32lo(int n) -{ - return ((__uint32_t)1 << (n)) - 1; -} -static inline __uint64_t xfs_mask64lo(int n) -{ - return ((__uint64_t)1 << (n)) - 1; -} - -/* Get high bit set out of 32-bit argument, -1 if none set */ -static inline int xfs_highbit32(__uint32_t v) -{ - return fls(v) - 1; -} - -/* Get high bit set out of 64-bit argument, -1 if none set */ -static inline int xfs_highbit64(__uint64_t v) -{ - return fls64(v) - 1; -} - -/* Get low bit set out of 32-bit argument, -1 if none set */ -static inline int xfs_lowbit32(__uint32_t v) -{ - return ffs(v) - 1; -} - -/* Get low bit set out of 64-bit argument, -1 if none set */ -static inline int xfs_lowbit64(__uint64_t v) -{ - __uint32_t w = (__uint32_t)v; - int n = 0; - - if (w) { /* lower bits */ - n = ffs(w); - } else { /* upper bits */ - w = (__uint32_t)(v >> 32); - if (w) { - n = ffs(w); - if (n) - n += 32; - } - } - return n - 1; -} - -/* Return whether bitmap is empty (1 == empty) */ -extern int xfs_bitmap_empty(uint *map, uint size); - -/* Count continuous one bits in map starting with start_bit */ -extern int xfs_contig_bits(uint *map, uint size, uint start_bit); - -/* Find next set bit in map */ -extern int xfs_next_bit(uint *map, uint size, uint start_bit); - -#endif /* __XFS_BIT_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_bmap.c b/src/linux/fs/xfs/libxfs/xfs_bmap.c deleted file mode 100644 index c6eb219..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_bmap.c +++ /dev/null @@ -1,6554 +0,0 @@ -/* - * Copyright (c) 2000-2006 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_dir2.h" -#include "xfs_inode.h" -#include "xfs_btree.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_extfree_item.h" -#include "xfs_alloc.h" -#include "xfs_bmap.h" -#include "xfs_bmap_util.h" -#include "xfs_bmap_btree.h" -#include "xfs_rtalloc.h" -#include "xfs_error.h" -#include "xfs_quota.h" -#include "xfs_trans_space.h" -#include "xfs_buf_item.h" -#include "xfs_trace.h" -#include "xfs_symlink.h" -#include "xfs_attr_leaf.h" -#include "xfs_filestream.h" -#include "xfs_rmap.h" -#include "xfs_ag_resv.h" -#include "xfs_refcount.h" - - -kmem_zone_t *xfs_bmap_free_item_zone; - -/* - * Miscellaneous helper functions - */ - -/* - * Compute and fill in the value of the maximum depth of a bmap btree - * in this filesystem. Done once, during mount. - */ -void -xfs_bmap_compute_maxlevels( - xfs_mount_t *mp, /* file system mount structure */ - int whichfork) /* data or attr fork */ -{ - int level; /* btree level */ - uint maxblocks; /* max blocks at this level */ - uint maxleafents; /* max leaf entries possible */ - int maxrootrecs; /* max records in root block */ - int minleafrecs; /* min records in leaf block */ - int minnoderecs; /* min records in node block */ - int sz; /* root block size */ - - /* - * The maximum number of extents in a file, hence the maximum - * number of leaf entries, is controlled by the type of di_nextents - * (a signed 32-bit number, xfs_extnum_t), or by di_anextents - * (a signed 16-bit number, xfs_aextnum_t). - * - * Note that we can no longer assume that if we are in ATTR1 that - * the fork offset of all the inodes will be - * (xfs_default_attroffset(ip) >> 3) because we could have mounted - * with ATTR2 and then mounted back with ATTR1, keeping the - * di_forkoff's fixed but probably at various positions. Therefore, - * for both ATTR1 and ATTR2 we have to assume the worst case scenario - * of a minimum size available. - */ - if (whichfork == XFS_DATA_FORK) { - maxleafents = MAXEXTNUM; - sz = XFS_BMDR_SPACE_CALC(MINDBTPTRS); - } else { - maxleafents = MAXAEXTNUM; - sz = XFS_BMDR_SPACE_CALC(MINABTPTRS); - } - maxrootrecs = xfs_bmdr_maxrecs(sz, 0); - minleafrecs = mp->m_bmap_dmnr[0]; - minnoderecs = mp->m_bmap_dmnr[1]; - maxblocks = (maxleafents + minleafrecs - 1) / minleafrecs; - for (level = 1; maxblocks > 1; level++) { - if (maxblocks <= maxrootrecs) - maxblocks = 1; - else - maxblocks = (maxblocks + minnoderecs - 1) / minnoderecs; - } - mp->m_bm_maxlevels[whichfork] = level; -} - -STATIC int /* error */ -xfs_bmbt_lookup_eq( - struct xfs_btree_cur *cur, - xfs_fileoff_t off, - xfs_fsblock_t bno, - xfs_filblks_t len, - int *stat) /* success/failure */ -{ - cur->bc_rec.b.br_startoff = off; - cur->bc_rec.b.br_startblock = bno; - cur->bc_rec.b.br_blockcount = len; - return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat); -} - -STATIC int /* error */ -xfs_bmbt_lookup_ge( - struct xfs_btree_cur *cur, - xfs_fileoff_t off, - xfs_fsblock_t bno, - xfs_filblks_t len, - int *stat) /* success/failure */ -{ - cur->bc_rec.b.br_startoff = off; - cur->bc_rec.b.br_startblock = bno; - cur->bc_rec.b.br_blockcount = len; - return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat); -} - -/* - * Check if the inode needs to be converted to btree format. - */ -static inline bool xfs_bmap_needs_btree(struct xfs_inode *ip, int whichfork) -{ - return whichfork != XFS_COW_FORK && - XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && - XFS_IFORK_NEXTENTS(ip, whichfork) > - XFS_IFORK_MAXEXT(ip, whichfork); -} - -/* - * Check if the inode should be converted to extent format. - */ -static inline bool xfs_bmap_wants_extents(struct xfs_inode *ip, int whichfork) -{ - return whichfork != XFS_COW_FORK && - XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE && - XFS_IFORK_NEXTENTS(ip, whichfork) <= - XFS_IFORK_MAXEXT(ip, whichfork); -} - -/* - * Update the record referred to by cur to the value given - * by [off, bno, len, state]. - * This either works (return 0) or gets an EFSCORRUPTED error. - */ -STATIC int -xfs_bmbt_update( - struct xfs_btree_cur *cur, - xfs_fileoff_t off, - xfs_fsblock_t bno, - xfs_filblks_t len, - xfs_exntst_t state) -{ - union xfs_btree_rec rec; - - xfs_bmbt_disk_set_allf(&rec.bmbt, off, bno, len, state); - return xfs_btree_update(cur, &rec); -} - -/* - * Compute the worst-case number of indirect blocks that will be used - * for ip's delayed extent of length "len". - */ -STATIC xfs_filblks_t -xfs_bmap_worst_indlen( - xfs_inode_t *ip, /* incore inode pointer */ - xfs_filblks_t len) /* delayed extent length */ -{ - int level; /* btree level number */ - int maxrecs; /* maximum record count at this level */ - xfs_mount_t *mp; /* mount structure */ - xfs_filblks_t rval; /* return value */ - - mp = ip->i_mount; - maxrecs = mp->m_bmap_dmxr[0]; - for (level = 0, rval = 0; - level < XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK); - level++) { - len += maxrecs - 1; - do_div(len, maxrecs); - rval += len; - if (len == 1) - return rval + XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) - - level - 1; - if (level == 0) - maxrecs = mp->m_bmap_dmxr[1]; - } - return rval; -} - -/* - * Calculate the default attribute fork offset for newly created inodes. - */ -uint -xfs_default_attroffset( - struct xfs_inode *ip) -{ - struct xfs_mount *mp = ip->i_mount; - uint offset; - - if (mp->m_sb.sb_inodesize == 256) { - offset = XFS_LITINO(mp, ip->i_d.di_version) - - XFS_BMDR_SPACE_CALC(MINABTPTRS); - } else { - offset = XFS_BMDR_SPACE_CALC(6 * MINABTPTRS); - } - - ASSERT(offset < XFS_LITINO(mp, ip->i_d.di_version)); - return offset; -} - -/* - * Helper routine to reset inode di_forkoff field when switching - * attribute fork from local to extent format - we reset it where - * possible to make space available for inline data fork extents. - */ -STATIC void -xfs_bmap_forkoff_reset( - xfs_inode_t *ip, - int whichfork) -{ - if (whichfork == XFS_ATTR_FORK && - ip->i_d.di_format != XFS_DINODE_FMT_DEV && - ip->i_d.di_format != XFS_DINODE_FMT_UUID && - ip->i_d.di_format != XFS_DINODE_FMT_BTREE) { - uint dfl_forkoff = xfs_default_attroffset(ip) >> 3; - - if (dfl_forkoff > ip->i_d.di_forkoff) - ip->i_d.di_forkoff = dfl_forkoff; - } -} - -#ifdef DEBUG -STATIC struct xfs_buf * -xfs_bmap_get_bp( - struct xfs_btree_cur *cur, - xfs_fsblock_t bno) -{ - struct xfs_log_item_desc *lidp; - int i; - - if (!cur) - return NULL; - - for (i = 0; i < XFS_BTREE_MAXLEVELS; i++) { - if (!cur->bc_bufs[i]) - break; - if (XFS_BUF_ADDR(cur->bc_bufs[i]) == bno) - return cur->bc_bufs[i]; - } - - /* Chase down all the log items to see if the bp is there */ - list_for_each_entry(lidp, &cur->bc_tp->t_items, lid_trans) { - struct xfs_buf_log_item *bip; - bip = (struct xfs_buf_log_item *)lidp->lid_item; - if (bip->bli_item.li_type == XFS_LI_BUF && - XFS_BUF_ADDR(bip->bli_buf) == bno) - return bip->bli_buf; - } - - return NULL; -} - -STATIC void -xfs_check_block( - struct xfs_btree_block *block, - xfs_mount_t *mp, - int root, - short sz) -{ - int i, j, dmxr; - __be64 *pp, *thispa; /* pointer to block address */ - xfs_bmbt_key_t *prevp, *keyp; - - ASSERT(be16_to_cpu(block->bb_level) > 0); - - prevp = NULL; - for( i = 1; i <= xfs_btree_get_numrecs(block); i++) { - dmxr = mp->m_bmap_dmxr[0]; - keyp = XFS_BMBT_KEY_ADDR(mp, block, i); - - if (prevp) { - ASSERT(be64_to_cpu(prevp->br_startoff) < - be64_to_cpu(keyp->br_startoff)); - } - prevp = keyp; - - /* - * Compare the block numbers to see if there are dups. - */ - if (root) - pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, i, sz); - else - pp = XFS_BMBT_PTR_ADDR(mp, block, i, dmxr); - - for (j = i+1; j <= be16_to_cpu(block->bb_numrecs); j++) { - if (root) - thispa = XFS_BMAP_BROOT_PTR_ADDR(mp, block, j, sz); - else - thispa = XFS_BMBT_PTR_ADDR(mp, block, j, dmxr); - if (*thispa == *pp) { - xfs_warn(mp, "%s: thispa(%d) == pp(%d) %Ld", - __func__, j, i, - (unsigned long long)be64_to_cpu(*thispa)); - panic("%s: ptrs are equal in node\n", - __func__); - } - } - } -} - -/* - * Check that the extents for the inode ip are in the right order in all - * btree leaves. THis becomes prohibitively expensive for large extent count - * files, so don't bother with inodes that have more than 10,000 extents in - * them. The btree record ordering checks will still be done, so for such large - * bmapbt constructs that is going to catch most corruptions. - */ -STATIC void -xfs_bmap_check_leaf_extents( - xfs_btree_cur_t *cur, /* btree cursor or null */ - xfs_inode_t *ip, /* incore inode pointer */ - int whichfork) /* data or attr fork */ -{ - struct xfs_btree_block *block; /* current btree block */ - xfs_fsblock_t bno; /* block # of "block" */ - xfs_buf_t *bp; /* buffer for "block" */ - int error; /* error return value */ - xfs_extnum_t i=0, j; /* index into the extents list */ - xfs_ifork_t *ifp; /* fork structure */ - int level; /* btree level, for checking */ - xfs_mount_t *mp; /* file system mount structure */ - __be64 *pp; /* pointer to block address */ - xfs_bmbt_rec_t *ep; /* pointer to current extent */ - xfs_bmbt_rec_t last = {0, 0}; /* last extent in prev block */ - xfs_bmbt_rec_t *nextp; /* pointer to next extent */ - int bp_release = 0; - - if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) { - return; - } - - /* skip large extent count inodes */ - if (ip->i_d.di_nextents > 10000) - return; - - bno = NULLFSBLOCK; - mp = ip->i_mount; - ifp = XFS_IFORK_PTR(ip, whichfork); - block = ifp->if_broot; - /* - * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out. - */ - level = be16_to_cpu(block->bb_level); - ASSERT(level > 0); - xfs_check_block(block, mp, 1, ifp->if_broot_bytes); - pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes); - bno = be64_to_cpu(*pp); - - ASSERT(bno != NULLFSBLOCK); - ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount); - ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks); - - /* - * Go down the tree until leaf level is reached, following the first - * pointer (leftmost) at each level. - */ - while (level-- > 0) { - /* See if buf is in cur first */ - bp_release = 0; - bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno)); - if (!bp) { - bp_release = 1; - error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp, - XFS_BMAP_BTREE_REF, - &xfs_bmbt_buf_ops); - if (error) - goto error_norelse; - } - block = XFS_BUF_TO_BLOCK(bp); - if (level == 0) - break; - - /* - * Check this block for basic sanity (increasing keys and - * no duplicate blocks). - */ - - xfs_check_block(block, mp, 0, 0); - pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]); - bno = be64_to_cpu(*pp); - XFS_WANT_CORRUPTED_GOTO(mp, - XFS_FSB_SANITY_CHECK(mp, bno), error0); - if (bp_release) { - bp_release = 0; - xfs_trans_brelse(NULL, bp); - } - } - - /* - * Here with bp and block set to the leftmost leaf node in the tree. - */ - i = 0; - - /* - * Loop over all leaf nodes checking that all extents are in the right order. - */ - for (;;) { - xfs_fsblock_t nextbno; - xfs_extnum_t num_recs; - - - num_recs = xfs_btree_get_numrecs(block); - - /* - * Read-ahead the next leaf block, if any. - */ - - nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib); - - /* - * Check all the extents to make sure they are OK. - * If we had a previous block, the last entry should - * conform with the first entry in this one. - */ - - ep = XFS_BMBT_REC_ADDR(mp, block, 1); - if (i) { - ASSERT(xfs_bmbt_disk_get_startoff(&last) + - xfs_bmbt_disk_get_blockcount(&last) <= - xfs_bmbt_disk_get_startoff(ep)); - } - for (j = 1; j < num_recs; j++) { - nextp = XFS_BMBT_REC_ADDR(mp, block, j + 1); - ASSERT(xfs_bmbt_disk_get_startoff(ep) + - xfs_bmbt_disk_get_blockcount(ep) <= - xfs_bmbt_disk_get_startoff(nextp)); - ep = nextp; - } - - last = *ep; - i += num_recs; - if (bp_release) { - bp_release = 0; - xfs_trans_brelse(NULL, bp); - } - bno = nextbno; - /* - * If we've reached the end, stop. - */ - if (bno == NULLFSBLOCK) - break; - - bp_release = 0; - bp = xfs_bmap_get_bp(cur, XFS_FSB_TO_DADDR(mp, bno)); - if (!bp) { - bp_release = 1; - error = xfs_btree_read_bufl(mp, NULL, bno, 0, &bp, - XFS_BMAP_BTREE_REF, - &xfs_bmbt_buf_ops); - if (error) - goto error_norelse; - } - block = XFS_BUF_TO_BLOCK(bp); - } - - return; - -error0: - xfs_warn(mp, "%s: at error0", __func__); - if (bp_release) - xfs_trans_brelse(NULL, bp); -error_norelse: - xfs_warn(mp, "%s: BAD after btree leaves for %d extents", - __func__, i); - panic("%s: CORRUPTED BTREE OR SOMETHING", __func__); - return; -} - -/* - * Add bmap trace insert entries for all the contents of the extent records. - */ -void -xfs_bmap_trace_exlist( - xfs_inode_t *ip, /* incore inode pointer */ - xfs_extnum_t cnt, /* count of entries in the list */ - int whichfork, /* data or attr fork */ - unsigned long caller_ip) -{ - xfs_extnum_t idx; /* extent record index */ - xfs_ifork_t *ifp; /* inode fork pointer */ - int state = 0; - - if (whichfork == XFS_ATTR_FORK) - state |= BMAP_ATTRFORK; - - ifp = XFS_IFORK_PTR(ip, whichfork); - ASSERT(cnt == (ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t))); - for (idx = 0; idx < cnt; idx++) - trace_xfs_extlist(ip, idx, whichfork, caller_ip); -} - -/* - * Validate that the bmbt_irecs being returned from bmapi are valid - * given the caller's original parameters. Specifically check the - * ranges of the returned irecs to ensure that they only extend beyond - * the given parameters if the XFS_BMAPI_ENTIRE flag was set. - */ -STATIC void -xfs_bmap_validate_ret( - xfs_fileoff_t bno, - xfs_filblks_t len, - int flags, - xfs_bmbt_irec_t *mval, - int nmap, - int ret_nmap) -{ - int i; /* index to map values */ - - ASSERT(ret_nmap <= nmap); - - for (i = 0; i < ret_nmap; i++) { - ASSERT(mval[i].br_blockcount > 0); - if (!(flags & XFS_BMAPI_ENTIRE)) { - ASSERT(mval[i].br_startoff >= bno); - ASSERT(mval[i].br_blockcount <= len); - ASSERT(mval[i].br_startoff + mval[i].br_blockcount <= - bno + len); - } else { - ASSERT(mval[i].br_startoff < bno + len); - ASSERT(mval[i].br_startoff + mval[i].br_blockcount > - bno); - } - ASSERT(i == 0 || - mval[i - 1].br_startoff + mval[i - 1].br_blockcount == - mval[i].br_startoff); - ASSERT(mval[i].br_startblock != DELAYSTARTBLOCK && - mval[i].br_startblock != HOLESTARTBLOCK); - ASSERT(mval[i].br_state == XFS_EXT_NORM || - mval[i].br_state == XFS_EXT_UNWRITTEN); - } -} - -#else -#define xfs_bmap_check_leaf_extents(cur, ip, whichfork) do { } while (0) -#define xfs_bmap_validate_ret(bno,len,flags,mval,onmap,nmap) -#endif /* DEBUG */ - -/* - * bmap free list manipulation functions - */ - -/* - * Add the extent to the list of extents to be free at transaction end. - * The list is maintained sorted (by block number). - */ -void -xfs_bmap_add_free( - struct xfs_mount *mp, - struct xfs_defer_ops *dfops, - xfs_fsblock_t bno, - xfs_filblks_t len, - struct xfs_owner_info *oinfo) -{ - struct xfs_extent_free_item *new; /* new element */ -#ifdef DEBUG - xfs_agnumber_t agno; - xfs_agblock_t agbno; - - ASSERT(bno != NULLFSBLOCK); - ASSERT(len > 0); - ASSERT(len <= MAXEXTLEN); - ASSERT(!isnullstartblock(bno)); - agno = XFS_FSB_TO_AGNO(mp, bno); - agbno = XFS_FSB_TO_AGBNO(mp, bno); - ASSERT(agno < mp->m_sb.sb_agcount); - ASSERT(agbno < mp->m_sb.sb_agblocks); - ASSERT(len < mp->m_sb.sb_agblocks); - ASSERT(agbno + len <= mp->m_sb.sb_agblocks); -#endif - ASSERT(xfs_bmap_free_item_zone != NULL); - - new = kmem_zone_alloc(xfs_bmap_free_item_zone, KM_SLEEP); - new->xefi_startblock = bno; - new->xefi_blockcount = (xfs_extlen_t)len; - if (oinfo) - new->xefi_oinfo = *oinfo; - else - xfs_rmap_skip_owner_update(&new->xefi_oinfo); - trace_xfs_bmap_free_defer(mp, XFS_FSB_TO_AGNO(mp, bno), 0, - XFS_FSB_TO_AGBNO(mp, bno), len); - xfs_defer_add(dfops, XFS_DEFER_OPS_TYPE_FREE, &new->xefi_list); -} - -/* - * Inode fork format manipulation functions - */ - -/* - * Transform a btree format file with only one leaf node, where the - * extents list will fit in the inode, into an extents format file. - * Since the file extents are already in-core, all we have to do is - * give up the space for the btree root and pitch the leaf block. - */ -STATIC int /* error */ -xfs_bmap_btree_to_extents( - xfs_trans_t *tp, /* transaction pointer */ - xfs_inode_t *ip, /* incore inode pointer */ - xfs_btree_cur_t *cur, /* btree cursor */ - int *logflagsp, /* inode logging flags */ - int whichfork) /* data or attr fork */ -{ - /* REFERENCED */ - struct xfs_btree_block *cblock;/* child btree block */ - xfs_fsblock_t cbno; /* child block number */ - xfs_buf_t *cbp; /* child block's buffer */ - int error; /* error return value */ - xfs_ifork_t *ifp; /* inode fork data */ - xfs_mount_t *mp; /* mount point structure */ - __be64 *pp; /* ptr to block address */ - struct xfs_btree_block *rblock;/* root btree block */ - struct xfs_owner_info oinfo; - - mp = ip->i_mount; - ifp = XFS_IFORK_PTR(ip, whichfork); - ASSERT(whichfork != XFS_COW_FORK); - ASSERT(ifp->if_flags & XFS_IFEXTENTS); - ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE); - rblock = ifp->if_broot; - ASSERT(be16_to_cpu(rblock->bb_level) == 1); - ASSERT(be16_to_cpu(rblock->bb_numrecs) == 1); - ASSERT(xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0) == 1); - pp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, ifp->if_broot_bytes); - cbno = be64_to_cpu(*pp); - *logflagsp = 0; -#ifdef DEBUG - if ((error = xfs_btree_check_lptr(cur, cbno, 1))) - return error; -#endif - error = xfs_btree_read_bufl(mp, tp, cbno, 0, &cbp, XFS_BMAP_BTREE_REF, - &xfs_bmbt_buf_ops); - if (error) - return error; - cblock = XFS_BUF_TO_BLOCK(cbp); - if ((error = xfs_btree_check_block(cur, cblock, 0, cbp))) - return error; - xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, whichfork); - xfs_bmap_add_free(mp, cur->bc_private.b.dfops, cbno, 1, &oinfo); - ip->i_d.di_nblocks--; - xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L); - xfs_trans_binval(tp, cbp); - if (cur->bc_bufs[0] == cbp) - cur->bc_bufs[0] = NULL; - xfs_iroot_realloc(ip, -1, whichfork); - ASSERT(ifp->if_broot == NULL); - ASSERT((ifp->if_flags & XFS_IFBROOT) == 0); - XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); - *logflagsp = XFS_ILOG_CORE | xfs_ilog_fext(whichfork); - return 0; -} - -/* - * Convert an extents-format file into a btree-format file. - * The new file will have a root block (in the inode) and a single child block. - */ -STATIC int /* error */ -xfs_bmap_extents_to_btree( - xfs_trans_t *tp, /* transaction pointer */ - xfs_inode_t *ip, /* incore inode pointer */ - xfs_fsblock_t *firstblock, /* first-block-allocated */ - struct xfs_defer_ops *dfops, /* blocks freed in xaction */ - xfs_btree_cur_t **curp, /* cursor returned to caller */ - int wasdel, /* converting a delayed alloc */ - int *logflagsp, /* inode logging flags */ - int whichfork) /* data or attr fork */ -{ - struct xfs_btree_block *ablock; /* allocated (child) bt block */ - xfs_buf_t *abp; /* buffer for ablock */ - xfs_alloc_arg_t args; /* allocation arguments */ - xfs_bmbt_rec_t *arp; /* child record pointer */ - struct xfs_btree_block *block; /* btree root block */ - xfs_btree_cur_t *cur; /* bmap btree cursor */ - xfs_bmbt_rec_host_t *ep; /* extent record pointer */ - int error; /* error return value */ - xfs_extnum_t i, cnt; /* extent record index */ - xfs_ifork_t *ifp; /* inode fork pointer */ - xfs_bmbt_key_t *kp; /* root block key pointer */ - xfs_mount_t *mp; /* mount structure */ - xfs_extnum_t nextents; /* number of file extents */ - xfs_bmbt_ptr_t *pp; /* root block address pointer */ - - mp = ip->i_mount; - ASSERT(whichfork != XFS_COW_FORK); - ifp = XFS_IFORK_PTR(ip, whichfork); - ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS); - - /* - * Make space in the inode incore. - */ - xfs_iroot_realloc(ip, 1, whichfork); - ifp->if_flags |= XFS_IFBROOT; - - /* - * Fill in the root. - */ - block = ifp->if_broot; - if (xfs_sb_version_hascrc(&mp->m_sb)) - xfs_btree_init_block_int(mp, block, XFS_BUF_DADDR_NULL, - XFS_BMAP_CRC_MAGIC, 1, 1, ip->i_ino, - XFS_BTREE_LONG_PTRS | XFS_BTREE_CRC_BLOCKS); - else - xfs_btree_init_block_int(mp, block, XFS_BUF_DADDR_NULL, - XFS_BMAP_MAGIC, 1, 1, ip->i_ino, - XFS_BTREE_LONG_PTRS); - - /* - * Need a cursor. Can't allocate until bb_level is filled in. - */ - cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); - cur->bc_private.b.firstblock = *firstblock; - cur->bc_private.b.dfops = dfops; - cur->bc_private.b.flags = wasdel ? XFS_BTCUR_BPRV_WASDEL : 0; - /* - * Convert to a btree with two levels, one record in root. - */ - XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_BTREE); - memset(&args, 0, sizeof(args)); - args.tp = tp; - args.mp = mp; - xfs_rmap_ino_bmbt_owner(&args.oinfo, ip->i_ino, whichfork); - args.firstblock = *firstblock; - if (*firstblock == NULLFSBLOCK) { - args.type = XFS_ALLOCTYPE_START_BNO; - args.fsbno = XFS_INO_TO_FSB(mp, ip->i_ino); - } else if (dfops->dop_low) { -try_another_ag: - args.type = XFS_ALLOCTYPE_START_BNO; - args.fsbno = *firstblock; - } else { - args.type = XFS_ALLOCTYPE_NEAR_BNO; - args.fsbno = *firstblock; - } - args.minlen = args.maxlen = args.prod = 1; - args.wasdel = wasdel; - *logflagsp = 0; - if ((error = xfs_alloc_vextent(&args))) { - xfs_iroot_realloc(ip, -1, whichfork); - xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); - return error; - } - - /* - * During a CoW operation, the allocation and bmbt updates occur in - * different transactions. The mapping code tries to put new bmbt - * blocks near extents being mapped, but the only way to guarantee this - * is if the alloc and the mapping happen in a single transaction that - * has a block reservation. That isn't the case here, so if we run out - * of space we'll try again with another AG. - */ - if (xfs_sb_version_hasreflink(&cur->bc_mp->m_sb) && - args.fsbno == NULLFSBLOCK && - args.type == XFS_ALLOCTYPE_NEAR_BNO) { - dfops->dop_low = true; - goto try_another_ag; - } - /* - * Allocation can't fail, the space was reserved. - */ - ASSERT(args.fsbno != NULLFSBLOCK); - ASSERT(*firstblock == NULLFSBLOCK || - args.agno == XFS_FSB_TO_AGNO(mp, *firstblock) || - (dfops->dop_low && - args.agno > XFS_FSB_TO_AGNO(mp, *firstblock))); - *firstblock = cur->bc_private.b.firstblock = args.fsbno; - cur->bc_private.b.allocated++; - ip->i_d.di_nblocks++; - xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, 1L); - abp = xfs_btree_get_bufl(mp, tp, args.fsbno, 0); - /* - * Fill in the child block. - */ - abp->b_ops = &xfs_bmbt_buf_ops; - ablock = XFS_BUF_TO_BLOCK(abp); - if (xfs_sb_version_hascrc(&mp->m_sb)) - xfs_btree_init_block_int(mp, ablock, abp->b_bn, - XFS_BMAP_CRC_MAGIC, 0, 0, ip->i_ino, - XFS_BTREE_LONG_PTRS | XFS_BTREE_CRC_BLOCKS); - else - xfs_btree_init_block_int(mp, ablock, abp->b_bn, - XFS_BMAP_MAGIC, 0, 0, ip->i_ino, - XFS_BTREE_LONG_PTRS); - - arp = XFS_BMBT_REC_ADDR(mp, ablock, 1); - nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); - for (cnt = i = 0; i < nextents; i++) { - ep = xfs_iext_get_ext(ifp, i); - if (!isnullstartblock(xfs_bmbt_get_startblock(ep))) { - arp->l0 = cpu_to_be64(ep->l0); - arp->l1 = cpu_to_be64(ep->l1); - arp++; cnt++; - } - } - ASSERT(cnt == XFS_IFORK_NEXTENTS(ip, whichfork)); - xfs_btree_set_numrecs(ablock, cnt); - - /* - * Fill in the root key and pointer. - */ - kp = XFS_BMBT_KEY_ADDR(mp, block, 1); - arp = XFS_BMBT_REC_ADDR(mp, ablock, 1); - kp->br_startoff = cpu_to_be64(xfs_bmbt_disk_get_startoff(arp)); - pp = XFS_BMBT_PTR_ADDR(mp, block, 1, xfs_bmbt_get_maxrecs(cur, - be16_to_cpu(block->bb_level))); - *pp = cpu_to_be64(args.fsbno); - - /* - * Do all this logging at the end so that - * the root is at the right level. - */ - xfs_btree_log_block(cur, abp, XFS_BB_ALL_BITS); - xfs_btree_log_recs(cur, abp, 1, be16_to_cpu(ablock->bb_numrecs)); - ASSERT(*curp == NULL); - *curp = cur; - *logflagsp = XFS_ILOG_CORE | xfs_ilog_fbroot(whichfork); - return 0; -} - -/* - * Convert a local file to an extents file. - * This code is out of bounds for data forks of regular files, - * since the file data needs to get logged so things will stay consistent. - * (The bmap-level manipulations are ok, though). - */ -void -xfs_bmap_local_to_extents_empty( - struct xfs_inode *ip, - int whichfork) -{ - struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); - - ASSERT(whichfork != XFS_COW_FORK); - ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); - ASSERT(ifp->if_bytes == 0); - ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) == 0); - - xfs_bmap_forkoff_reset(ip, whichfork); - ifp->if_flags &= ~XFS_IFINLINE; - ifp->if_flags |= XFS_IFEXTENTS; - XFS_IFORK_FMT_SET(ip, whichfork, XFS_DINODE_FMT_EXTENTS); -} - - -STATIC int /* error */ -xfs_bmap_local_to_extents( - xfs_trans_t *tp, /* transaction pointer */ - xfs_inode_t *ip, /* incore inode pointer */ - xfs_fsblock_t *firstblock, /* first block allocated in xaction */ - xfs_extlen_t total, /* total blocks needed by transaction */ - int *logflagsp, /* inode logging flags */ - int whichfork, - void (*init_fn)(struct xfs_trans *tp, - struct xfs_buf *bp, - struct xfs_inode *ip, - struct xfs_ifork *ifp)) -{ - int error = 0; - int flags; /* logging flags returned */ - xfs_ifork_t *ifp; /* inode fork pointer */ - xfs_alloc_arg_t args; /* allocation arguments */ - xfs_buf_t *bp; /* buffer for extent block */ - xfs_bmbt_rec_host_t *ep; /* extent record pointer */ - - /* - * We don't want to deal with the case of keeping inode data inline yet. - * So sending the data fork of a regular inode is invalid. - */ - ASSERT(!(S_ISREG(VFS_I(ip)->i_mode) && whichfork == XFS_DATA_FORK)); - ifp = XFS_IFORK_PTR(ip, whichfork); - ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); - - if (!ifp->if_bytes) { - xfs_bmap_local_to_extents_empty(ip, whichfork); - flags = XFS_ILOG_CORE; - goto done; - } - - flags = 0; - error = 0; - ASSERT((ifp->if_flags & (XFS_IFINLINE|XFS_IFEXTENTS|XFS_IFEXTIREC)) == - XFS_IFINLINE); - memset(&args, 0, sizeof(args)); - args.tp = tp; - args.mp = ip->i_mount; - xfs_rmap_ino_owner(&args.oinfo, ip->i_ino, whichfork, 0); - args.firstblock = *firstblock; - /* - * Allocate a block. We know we need only one, since the - * file currently fits in an inode. - */ - if (*firstblock == NULLFSBLOCK) { -try_another_ag: - args.fsbno = XFS_INO_TO_FSB(args.mp, ip->i_ino); - args.type = XFS_ALLOCTYPE_START_BNO; - } else { - args.fsbno = *firstblock; - args.type = XFS_ALLOCTYPE_NEAR_BNO; - } - args.total = total; - args.minlen = args.maxlen = args.prod = 1; - error = xfs_alloc_vextent(&args); - if (error) - goto done; - - /* - * During a CoW operation, the allocation and bmbt updates occur in - * different transactions. The mapping code tries to put new bmbt - * blocks near extents being mapped, but the only way to guarantee this - * is if the alloc and the mapping happen in a single transaction that - * has a block reservation. That isn't the case here, so if we run out - * of space we'll try again with another AG. - */ - if (xfs_sb_version_hasreflink(&ip->i_mount->m_sb) && - args.fsbno == NULLFSBLOCK && - args.type == XFS_ALLOCTYPE_NEAR_BNO) { - goto try_another_ag; - } - /* Can't fail, the space was reserved. */ - ASSERT(args.fsbno != NULLFSBLOCK); - ASSERT(args.len == 1); - *firstblock = args.fsbno; - bp = xfs_btree_get_bufl(args.mp, tp, args.fsbno, 0); - - /* - * Initialize the block, copy the data and log the remote buffer. - * - * The callout is responsible for logging because the remote format - * might differ from the local format and thus we don't know how much to - * log here. Note that init_fn must also set the buffer log item type - * correctly. - */ - init_fn(tp, bp, ip, ifp); - - /* account for the change in fork size */ - xfs_idata_realloc(ip, -ifp->if_bytes, whichfork); - xfs_bmap_local_to_extents_empty(ip, whichfork); - flags |= XFS_ILOG_CORE; - - xfs_iext_add(ifp, 0, 1); - ep = xfs_iext_get_ext(ifp, 0); - xfs_bmbt_set_allf(ep, 0, args.fsbno, 1, XFS_EXT_NORM); - trace_xfs_bmap_post_update(ip, 0, - whichfork == XFS_ATTR_FORK ? BMAP_ATTRFORK : 0, - _THIS_IP_); - XFS_IFORK_NEXT_SET(ip, whichfork, 1); - ip->i_d.di_nblocks = 1; - xfs_trans_mod_dquot_byino(tp, ip, - XFS_TRANS_DQ_BCOUNT, 1L); - flags |= xfs_ilog_fext(whichfork); - -done: - *logflagsp = flags; - return error; -} - -/* - * Called from xfs_bmap_add_attrfork to handle btree format files. - */ -STATIC int /* error */ -xfs_bmap_add_attrfork_btree( - xfs_trans_t *tp, /* transaction pointer */ - xfs_inode_t *ip, /* incore inode pointer */ - xfs_fsblock_t *firstblock, /* first block allocated */ - struct xfs_defer_ops *dfops, /* blocks to free at commit */ - int *flags) /* inode logging flags */ -{ - xfs_btree_cur_t *cur; /* btree cursor */ - int error; /* error return value */ - xfs_mount_t *mp; /* file system mount struct */ - int stat; /* newroot status */ - - mp = ip->i_mount; - if (ip->i_df.if_broot_bytes <= XFS_IFORK_DSIZE(ip)) - *flags |= XFS_ILOG_DBROOT; - else { - cur = xfs_bmbt_init_cursor(mp, tp, ip, XFS_DATA_FORK); - cur->bc_private.b.dfops = dfops; - cur->bc_private.b.firstblock = *firstblock; - if ((error = xfs_bmbt_lookup_ge(cur, 0, 0, 0, &stat))) - goto error0; - /* must be at least one entry */ - XFS_WANT_CORRUPTED_GOTO(mp, stat == 1, error0); - if ((error = xfs_btree_new_iroot(cur, flags, &stat))) - goto error0; - if (stat == 0) { - xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); - return -ENOSPC; - } - *firstblock = cur->bc_private.b.firstblock; - cur->bc_private.b.allocated = 0; - xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); - } - return 0; -error0: - xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); - return error; -} - -/* - * Called from xfs_bmap_add_attrfork to handle extents format files. - */ -STATIC int /* error */ -xfs_bmap_add_attrfork_extents( - xfs_trans_t *tp, /* transaction pointer */ - xfs_inode_t *ip, /* incore inode pointer */ - xfs_fsblock_t *firstblock, /* first block allocated */ - struct xfs_defer_ops *dfops, /* blocks to free at commit */ - int *flags) /* inode logging flags */ -{ - xfs_btree_cur_t *cur; /* bmap btree cursor */ - int error; /* error return value */ - - if (ip->i_d.di_nextents * sizeof(xfs_bmbt_rec_t) <= XFS_IFORK_DSIZE(ip)) - return 0; - cur = NULL; - error = xfs_bmap_extents_to_btree(tp, ip, firstblock, dfops, &cur, 0, - flags, XFS_DATA_FORK); - if (cur) { - cur->bc_private.b.allocated = 0; - xfs_btree_del_cursor(cur, - error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); - } - return error; -} - -/* - * Called from xfs_bmap_add_attrfork to handle local format files. Each - * different data fork content type needs a different callout to do the - * conversion. Some are basic and only require special block initialisation - * callouts for the data formating, others (directories) are so specialised they - * handle everything themselves. - * - * XXX (dgc): investigate whether directory conversion can use the generic - * formatting callout. It should be possible - it's just a very complex - * formatter. - */ -STATIC int /* error */ -xfs_bmap_add_attrfork_local( - xfs_trans_t *tp, /* transaction pointer */ - xfs_inode_t *ip, /* incore inode pointer */ - xfs_fsblock_t *firstblock, /* first block allocated */ - struct xfs_defer_ops *dfops, /* blocks to free at commit */ - int *flags) /* inode logging flags */ -{ - xfs_da_args_t dargs; /* args for dir/attr code */ - - if (ip->i_df.if_bytes <= XFS_IFORK_DSIZE(ip)) - return 0; - - if (S_ISDIR(VFS_I(ip)->i_mode)) { - memset(&dargs, 0, sizeof(dargs)); - dargs.geo = ip->i_mount->m_dir_geo; - dargs.dp = ip; - dargs.firstblock = firstblock; - dargs.dfops = dfops; - dargs.total = dargs.geo->fsbcount; - dargs.whichfork = XFS_DATA_FORK; - dargs.trans = tp; - return xfs_dir2_sf_to_block(&dargs); - } - - if (S_ISLNK(VFS_I(ip)->i_mode)) - return xfs_bmap_local_to_extents(tp, ip, firstblock, 1, - flags, XFS_DATA_FORK, - xfs_symlink_local_to_remote); - - /* should only be called for types that support local format data */ - ASSERT(0); - return -EFSCORRUPTED; -} - -/* - * Convert inode from non-attributed to attributed. - * Must not be in a transaction, ip must not be locked. - */ -int /* error code */ -xfs_bmap_add_attrfork( - xfs_inode_t *ip, /* incore inode pointer */ - int size, /* space new attribute needs */ - int rsvd) /* xact may use reserved blks */ -{ - xfs_fsblock_t firstblock; /* 1st block/ag allocated */ - struct xfs_defer_ops dfops; /* freed extent records */ - xfs_mount_t *mp; /* mount structure */ - xfs_trans_t *tp; /* transaction pointer */ - int blks; /* space reservation */ - int version = 1; /* superblock attr version */ - int logflags; /* logging flags */ - int error; /* error return value */ - - ASSERT(XFS_IFORK_Q(ip) == 0); - - mp = ip->i_mount; - ASSERT(!XFS_NOT_DQATTACHED(mp, ip)); - - blks = XFS_ADDAFORK_SPACE_RES(mp); - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_addafork, blks, 0, - rsvd ? XFS_TRANS_RESERVE : 0, &tp); - if (error) - return error; - - xfs_ilock(ip, XFS_ILOCK_EXCL); - error = xfs_trans_reserve_quota_nblks(tp, ip, blks, 0, rsvd ? - XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : - XFS_QMOPT_RES_REGBLKS); - if (error) - goto trans_cancel; - if (XFS_IFORK_Q(ip)) - goto trans_cancel; - if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS) { - /* - * For inodes coming from pre-6.2 filesystems. - */ - ASSERT(ip->i_d.di_aformat == 0); - ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; - } - ASSERT(ip->i_d.di_anextents == 0); - - xfs_trans_ijoin(tp, ip, 0); - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - - switch (ip->i_d.di_format) { - case XFS_DINODE_FMT_DEV: - ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3; - break; - case XFS_DINODE_FMT_UUID: - ip->i_d.di_forkoff = roundup(sizeof(uuid_t), 8) >> 3; - break; - case XFS_DINODE_FMT_LOCAL: - case XFS_DINODE_FMT_EXTENTS: - case XFS_DINODE_FMT_BTREE: - ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size); - if (!ip->i_d.di_forkoff) - ip->i_d.di_forkoff = xfs_default_attroffset(ip) >> 3; - else if (mp->m_flags & XFS_MOUNT_ATTR2) - version = 2; - break; - default: - ASSERT(0); - error = -EINVAL; - goto trans_cancel; - } - - ASSERT(ip->i_afp == NULL); - ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP); - ip->i_afp->if_flags = XFS_IFEXTENTS; - logflags = 0; - xfs_defer_init(&dfops, &firstblock); - switch (ip->i_d.di_format) { - case XFS_DINODE_FMT_LOCAL: - error = xfs_bmap_add_attrfork_local(tp, ip, &firstblock, &dfops, - &logflags); - break; - case XFS_DINODE_FMT_EXTENTS: - error = xfs_bmap_add_attrfork_extents(tp, ip, &firstblock, - &dfops, &logflags); - break; - case XFS_DINODE_FMT_BTREE: - error = xfs_bmap_add_attrfork_btree(tp, ip, &firstblock, &dfops, - &logflags); - break; - default: - error = 0; - break; - } - if (logflags) - xfs_trans_log_inode(tp, ip, logflags); - if (error) - goto bmap_cancel; - if (!xfs_sb_version_hasattr(&mp->m_sb) || - (!xfs_sb_version_hasattr2(&mp->m_sb) && version == 2)) { - bool log_sb = false; - - spin_lock(&mp->m_sb_lock); - if (!xfs_sb_version_hasattr(&mp->m_sb)) { - xfs_sb_version_addattr(&mp->m_sb); - log_sb = true; - } - if (!xfs_sb_version_hasattr2(&mp->m_sb) && version == 2) { - xfs_sb_version_addattr2(&mp->m_sb); - log_sb = true; - } - spin_unlock(&mp->m_sb_lock); - if (log_sb) - xfs_log_sb(tp); - } - - error = xfs_defer_finish(&tp, &dfops, NULL); - if (error) - goto bmap_cancel; - error = xfs_trans_commit(tp); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return error; - -bmap_cancel: - xfs_defer_cancel(&dfops); -trans_cancel: - xfs_trans_cancel(tp); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return error; -} - -/* - * Internal and external extent tree search functions. - */ - -/* - * Read in the extents to if_extents. - * All inode fields are set up by caller, we just traverse the btree - * and copy the records in. If the file system cannot contain unwritten - * extents, the records are checked for no "state" flags. - */ -int /* error */ -xfs_bmap_read_extents( - xfs_trans_t *tp, /* transaction pointer */ - xfs_inode_t *ip, /* incore inode */ - int whichfork) /* data or attr fork */ -{ - struct xfs_btree_block *block; /* current btree block */ - xfs_fsblock_t bno; /* block # of "block" */ - xfs_buf_t *bp; /* buffer for "block" */ - int error; /* error return value */ - xfs_exntfmt_t exntf; /* XFS_EXTFMT_NOSTATE, if checking */ - xfs_extnum_t i, j; /* index into the extents list */ - xfs_ifork_t *ifp; /* fork structure */ - int level; /* btree level, for checking */ - xfs_mount_t *mp; /* file system mount structure */ - __be64 *pp; /* pointer to block address */ - /* REFERENCED */ - xfs_extnum_t room; /* number of entries there's room for */ - - bno = NULLFSBLOCK; - mp = ip->i_mount; - ifp = XFS_IFORK_PTR(ip, whichfork); - exntf = (whichfork != XFS_DATA_FORK) ? XFS_EXTFMT_NOSTATE : - XFS_EXTFMT_INODE(ip); - block = ifp->if_broot; - /* - * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out. - */ - level = be16_to_cpu(block->bb_level); - ASSERT(level > 0); - pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes); - bno = be64_to_cpu(*pp); - ASSERT(bno != NULLFSBLOCK); - ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount); - ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks); - /* - * Go down the tree until leaf level is reached, following the first - * pointer (leftmost) at each level. - */ - while (level-- > 0) { - error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, - XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops); - if (error) - return error; - block = XFS_BUF_TO_BLOCK(bp); - if (level == 0) - break; - pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]); - bno = be64_to_cpu(*pp); - XFS_WANT_CORRUPTED_GOTO(mp, - XFS_FSB_SANITY_CHECK(mp, bno), error0); - xfs_trans_brelse(tp, bp); - } - /* - * Here with bp and block set to the leftmost leaf node in the tree. - */ - room = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); - i = 0; - /* - * Loop over all leaf nodes. Copy information to the extent records. - */ - for (;;) { - xfs_bmbt_rec_t *frp; - xfs_fsblock_t nextbno; - xfs_extnum_t num_recs; - xfs_extnum_t start; - - num_recs = xfs_btree_get_numrecs(block); - if (unlikely(i + num_recs > room)) { - ASSERT(i + num_recs <= room); - xfs_warn(ip->i_mount, - "corrupt dinode %Lu, (btree extents).", - (unsigned long long) ip->i_ino); - XFS_CORRUPTION_ERROR("xfs_bmap_read_extents(1)", - XFS_ERRLEVEL_LOW, ip->i_mount, block); - goto error0; - } - /* - * Read-ahead the next leaf block, if any. - */ - nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib); - if (nextbno != NULLFSBLOCK) - xfs_btree_reada_bufl(mp, nextbno, 1, - &xfs_bmbt_buf_ops); - /* - * Copy records into the extent records. - */ - frp = XFS_BMBT_REC_ADDR(mp, block, 1); - start = i; - for (j = 0; j < num_recs; j++, i++, frp++) { - xfs_bmbt_rec_host_t *trp = xfs_iext_get_ext(ifp, i); - trp->l0 = be64_to_cpu(frp->l0); - trp->l1 = be64_to_cpu(frp->l1); - } - if (exntf == XFS_EXTFMT_NOSTATE) { - /* - * Check all attribute bmap btree records and - * any "older" data bmap btree records for a - * set bit in the "extent flag" position. - */ - if (unlikely(xfs_check_nostate_extents(ifp, - start, num_recs))) { - XFS_ERROR_REPORT("xfs_bmap_read_extents(2)", - XFS_ERRLEVEL_LOW, - ip->i_mount); - goto error0; - } - } - xfs_trans_brelse(tp, bp); - bno = nextbno; - /* - * If we've reached the end, stop. - */ - if (bno == NULLFSBLOCK) - break; - error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, - XFS_BMAP_BTREE_REF, &xfs_bmbt_buf_ops); - if (error) - return error; - block = XFS_BUF_TO_BLOCK(bp); - } - ASSERT(i == (ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t))); - ASSERT(i == XFS_IFORK_NEXTENTS(ip, whichfork)); - XFS_BMAP_TRACE_EXLIST(ip, i, whichfork); - return 0; -error0: - xfs_trans_brelse(tp, bp); - return -EFSCORRUPTED; -} - - -/* - * Search the extent records for the entry containing block bno. - * If bno lies in a hole, point to the next entry. If bno lies - * past eof, *eofp will be set, and *prevp will contain the last - * entry (null if none). Else, *lastxp will be set to the index - * of the found entry; *gotp will contain the entry. - */ -STATIC xfs_bmbt_rec_host_t * /* pointer to found extent entry */ -xfs_bmap_search_multi_extents( - xfs_ifork_t *ifp, /* inode fork pointer */ - xfs_fileoff_t bno, /* block number searched for */ - int *eofp, /* out: end of file found */ - xfs_extnum_t *lastxp, /* out: last extent index */ - xfs_bmbt_irec_t *gotp, /* out: extent entry found */ - xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */ -{ - xfs_bmbt_rec_host_t *ep; /* extent record pointer */ - xfs_extnum_t lastx; /* last extent index */ - - /* - * Initialize the extent entry structure to catch access to - * uninitialized br_startblock field. - */ - gotp->br_startoff = 0xffa5a5a5a5a5a5a5LL; - gotp->br_blockcount = 0xa55a5a5a5a5a5a5aLL; - gotp->br_state = XFS_EXT_INVALID; - gotp->br_startblock = 0xffffa5a5a5a5a5a5LL; - prevp->br_startoff = NULLFILEOFF; - - ep = xfs_iext_bno_to_ext(ifp, bno, &lastx); - if (lastx > 0) { - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx - 1), prevp); - } - if (lastx < (ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t))) { - xfs_bmbt_get_all(ep, gotp); - *eofp = 0; - } else { - if (lastx > 0) { - *gotp = *prevp; - } - *eofp = 1; - ep = NULL; - } - *lastxp = lastx; - return ep; -} - -/* - * Search the extents list for the inode, for the extent containing bno. - * If bno lies in a hole, point to the next entry. If bno lies past eof, - * *eofp will be set, and *prevp will contain the last entry (null if none). - * Else, *lastxp will be set to the index of the found - * entry; *gotp will contain the entry. - */ -xfs_bmbt_rec_host_t * /* pointer to found extent entry */ -xfs_bmap_search_extents( - xfs_inode_t *ip, /* incore inode pointer */ - xfs_fileoff_t bno, /* block number searched for */ - int fork, /* data or attr fork */ - int *eofp, /* out: end of file found */ - xfs_extnum_t *lastxp, /* out: last extent index */ - xfs_bmbt_irec_t *gotp, /* out: extent entry found */ - xfs_bmbt_irec_t *prevp) /* out: previous extent entry found */ -{ - xfs_ifork_t *ifp; /* inode fork pointer */ - xfs_bmbt_rec_host_t *ep; /* extent record pointer */ - - XFS_STATS_INC(ip->i_mount, xs_look_exlist); - ifp = XFS_IFORK_PTR(ip, fork); - - ep = xfs_bmap_search_multi_extents(ifp, bno, eofp, lastxp, gotp, prevp); - - if (unlikely(!(gotp->br_startblock) && (*lastxp != NULLEXTNUM) && - !(XFS_IS_REALTIME_INODE(ip) && fork == XFS_DATA_FORK))) { - xfs_alert_tag(ip->i_mount, XFS_PTAG_FSBLOCK_ZERO, - "Access to block zero in inode %llu " - "start_block: %llx start_off: %llx " - "blkcnt: %llx extent-state: %x lastx: %x", - (unsigned long long)ip->i_ino, - (unsigned long long)gotp->br_startblock, - (unsigned long long)gotp->br_startoff, - (unsigned long long)gotp->br_blockcount, - gotp->br_state, *lastxp); - *lastxp = NULLEXTNUM; - *eofp = 1; - return NULL; - } - return ep; -} - -/* - * Returns the file-relative block number of the first unused block(s) - * in the file with at least "len" logically contiguous blocks free. - * This is the lowest-address hole if the file has holes, else the first block - * past the end of file. - * Return 0 if the file is currently local (in-inode). - */ -int /* error */ -xfs_bmap_first_unused( - xfs_trans_t *tp, /* transaction pointer */ - xfs_inode_t *ip, /* incore inode */ - xfs_extlen_t len, /* size of hole to find */ - xfs_fileoff_t *first_unused, /* unused block */ - int whichfork) /* data or attr fork */ -{ - int error; /* error return value */ - int idx; /* extent record index */ - xfs_ifork_t *ifp; /* inode fork pointer */ - xfs_fileoff_t lastaddr; /* last block number seen */ - xfs_fileoff_t lowest; /* lowest useful block */ - xfs_fileoff_t max; /* starting useful block */ - xfs_fileoff_t off; /* offset for this block */ - xfs_extnum_t nextents; /* number of extent entries */ - - ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE || - XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS || - XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); - if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { - *first_unused = 0; - return 0; - } - ifp = XFS_IFORK_PTR(ip, whichfork); - if (!(ifp->if_flags & XFS_IFEXTENTS) && - (error = xfs_iread_extents(tp, ip, whichfork))) - return error; - lowest = *first_unused; - nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); - for (idx = 0, lastaddr = 0, max = lowest; idx < nextents; idx++) { - xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, idx); - off = xfs_bmbt_get_startoff(ep); - /* - * See if the hole before this extent will work. - */ - if (off >= lowest + len && off - max >= len) { - *first_unused = max; - return 0; - } - lastaddr = off + xfs_bmbt_get_blockcount(ep); - max = XFS_FILEOFF_MAX(lastaddr, lowest); - } - *first_unused = max; - return 0; -} - -/* - * Returns the file-relative block number of the last block - 1 before - * last_block (input value) in the file. - * This is not based on i_size, it is based on the extent records. - * Returns 0 for local files, as they do not have extent records. - */ -int /* error */ -xfs_bmap_last_before( - xfs_trans_t *tp, /* transaction pointer */ - xfs_inode_t *ip, /* incore inode */ - xfs_fileoff_t *last_block, /* last block */ - int whichfork) /* data or attr fork */ -{ - xfs_fileoff_t bno; /* input file offset */ - int eof; /* hit end of file */ - xfs_bmbt_rec_host_t *ep; /* pointer to last extent */ - int error; /* error return value */ - xfs_bmbt_irec_t got; /* current extent value */ - xfs_ifork_t *ifp; /* inode fork pointer */ - xfs_extnum_t lastx; /* last extent used */ - xfs_bmbt_irec_t prev; /* previous extent value */ - - if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && - XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && - XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL) - return -EIO; - if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { - *last_block = 0; - return 0; - } - ifp = XFS_IFORK_PTR(ip, whichfork); - if (!(ifp->if_flags & XFS_IFEXTENTS) && - (error = xfs_iread_extents(tp, ip, whichfork))) - return error; - bno = *last_block - 1; - ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, - &prev); - if (eof || xfs_bmbt_get_startoff(ep) > bno) { - if (prev.br_startoff == NULLFILEOFF) - *last_block = 0; - else - *last_block = prev.br_startoff + prev.br_blockcount; - } - /* - * Otherwise *last_block is already the right answer. - */ - return 0; -} - -int -xfs_bmap_last_extent( - struct xfs_trans *tp, - struct xfs_inode *ip, - int whichfork, - struct xfs_bmbt_irec *rec, - int *is_empty) -{ - struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); - int error; - int nextents; - - if (!(ifp->if_flags & XFS_IFEXTENTS)) { - error = xfs_iread_extents(tp, ip, whichfork); - if (error) - return error; - } - - nextents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t); - if (nextents == 0) { - *is_empty = 1; - return 0; - } - - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, nextents - 1), rec); - *is_empty = 0; - return 0; -} - -/* - * Check the last inode extent to determine whether this allocation will result - * in blocks being allocated at the end of the file. When we allocate new data - * blocks at the end of the file which do not start at the previous data block, - * we will try to align the new blocks at stripe unit boundaries. - * - * Returns 1 in bma->aeof if the file (fork) is empty as any new write will be - * at, or past the EOF. - */ -STATIC int -xfs_bmap_isaeof( - struct xfs_bmalloca *bma, - int whichfork) -{ - struct xfs_bmbt_irec rec; - int is_empty; - int error; - - bma->aeof = 0; - error = xfs_bmap_last_extent(NULL, bma->ip, whichfork, &rec, - &is_empty); - if (error) - return error; - - if (is_empty) { - bma->aeof = 1; - return 0; - } - - /* - * Check if we are allocation or past the last extent, or at least into - * the last delayed allocated extent. - */ - bma->aeof = bma->offset >= rec.br_startoff + rec.br_blockcount || - (bma->offset >= rec.br_startoff && - isnullstartblock(rec.br_startblock)); - return 0; -} - -/* - * Returns the file-relative block number of the first block past eof in - * the file. This is not based on i_size, it is based on the extent records. - * Returns 0 for local files, as they do not have extent records. - */ -int -xfs_bmap_last_offset( - struct xfs_inode *ip, - xfs_fileoff_t *last_block, - int whichfork) -{ - struct xfs_bmbt_irec rec; - int is_empty; - int error; - - *last_block = 0; - - if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) - return 0; - - if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE && - XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) - return -EIO; - - error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, &is_empty); - if (error || is_empty) - return error; - - *last_block = rec.br_startoff + rec.br_blockcount; - return 0; -} - -/* - * Returns whether the selected fork of the inode has exactly one - * block or not. For the data fork we check this matches di_size, - * implying the file's range is 0..bsize-1. - */ -int /* 1=>1 block, 0=>otherwise */ -xfs_bmap_one_block( - xfs_inode_t *ip, /* incore inode */ - int whichfork) /* data or attr fork */ -{ - xfs_bmbt_rec_host_t *ep; /* ptr to fork's extent */ - xfs_ifork_t *ifp; /* inode fork pointer */ - int rval; /* return value */ - xfs_bmbt_irec_t s; /* internal version of extent */ - -#ifndef DEBUG - if (whichfork == XFS_DATA_FORK) - return XFS_ISIZE(ip) == ip->i_mount->m_sb.sb_blocksize; -#endif /* !DEBUG */ - if (XFS_IFORK_NEXTENTS(ip, whichfork) != 1) - return 0; - if (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) - return 0; - ifp = XFS_IFORK_PTR(ip, whichfork); - ASSERT(ifp->if_flags & XFS_IFEXTENTS); - ep = xfs_iext_get_ext(ifp, 0); - xfs_bmbt_get_all(ep, &s); - rval = s.br_startoff == 0 && s.br_blockcount == 1; - if (rval && whichfork == XFS_DATA_FORK) - ASSERT(XFS_ISIZE(ip) == ip->i_mount->m_sb.sb_blocksize); - return rval; -} - -/* - * Extent tree manipulation functions used during allocation. - */ - -/* - * Convert a delayed allocation to a real allocation. - */ -STATIC int /* error */ -xfs_bmap_add_extent_delay_real( - struct xfs_bmalloca *bma, - int whichfork) -{ - struct xfs_bmbt_irec *new = &bma->got; - int diff; /* temp value */ - xfs_bmbt_rec_host_t *ep; /* extent entry for idx */ - int error; /* error return value */ - int i; /* temp state */ - xfs_ifork_t *ifp; /* inode fork pointer */ - xfs_fileoff_t new_endoff; /* end offset of new entry */ - xfs_bmbt_irec_t r[3]; /* neighbor extent entries */ - /* left is 0, right is 1, prev is 2 */ - int rval=0; /* return value (logging flags) */ - int state = 0;/* state bits, accessed thru macros */ - xfs_filblks_t da_new; /* new count del alloc blocks used */ - xfs_filblks_t da_old; /* old count del alloc blocks used */ - xfs_filblks_t temp=0; /* value for da_new calculations */ - xfs_filblks_t temp2=0;/* value for da_new calculations */ - int tmp_rval; /* partial logging flags */ - struct xfs_mount *mp; - xfs_extnum_t *nextents; - - mp = bma->ip->i_mount; - ifp = XFS_IFORK_PTR(bma->ip, whichfork); - ASSERT(whichfork != XFS_ATTR_FORK); - nextents = (whichfork == XFS_COW_FORK ? &bma->ip->i_cnextents : - &bma->ip->i_d.di_nextents); - - ASSERT(bma->idx >= 0); - ASSERT(bma->idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec)); - ASSERT(!isnullstartblock(new->br_startblock)); - ASSERT(!bma->cur || - (bma->cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL)); - - XFS_STATS_INC(mp, xs_add_exlist); - -#define LEFT r[0] -#define RIGHT r[1] -#define PREV r[2] - - if (whichfork == XFS_COW_FORK) - state |= BMAP_COWFORK; - - /* - * Set up a bunch of variables to make the tests simpler. - */ - ep = xfs_iext_get_ext(ifp, bma->idx); - xfs_bmbt_get_all(ep, &PREV); - new_endoff = new->br_startoff + new->br_blockcount; - ASSERT(PREV.br_startoff <= new->br_startoff); - ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff); - - da_old = startblockval(PREV.br_startblock); - da_new = 0; - - /* - * Set flags determining what part of the previous delayed allocation - * extent is being replaced by a real allocation. - */ - if (PREV.br_startoff == new->br_startoff) - state |= BMAP_LEFT_FILLING; - if (PREV.br_startoff + PREV.br_blockcount == new_endoff) - state |= BMAP_RIGHT_FILLING; - - /* - * Check and set flags if this segment has a left neighbor. - * Don't set contiguous if the combined extent would be too large. - */ - if (bma->idx > 0) { - state |= BMAP_LEFT_VALID; - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx - 1), &LEFT); - - if (isnullstartblock(LEFT.br_startblock)) - state |= BMAP_LEFT_DELAY; - } - - if ((state & BMAP_LEFT_VALID) && !(state & BMAP_LEFT_DELAY) && - LEFT.br_startoff + LEFT.br_blockcount == new->br_startoff && - LEFT.br_startblock + LEFT.br_blockcount == new->br_startblock && - LEFT.br_state == new->br_state && - LEFT.br_blockcount + new->br_blockcount <= MAXEXTLEN) - state |= BMAP_LEFT_CONTIG; - - /* - * Check and set flags if this segment has a right neighbor. - * Don't set contiguous if the combined extent would be too large. - * Also check for all-three-contiguous being too large. - */ - if (bma->idx < ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1) { - state |= BMAP_RIGHT_VALID; - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx + 1), &RIGHT); - - if (isnullstartblock(RIGHT.br_startblock)) - state |= BMAP_RIGHT_DELAY; - } - - if ((state & BMAP_RIGHT_VALID) && !(state & BMAP_RIGHT_DELAY) && - new_endoff == RIGHT.br_startoff && - new->br_startblock + new->br_blockcount == RIGHT.br_startblock && - new->br_state == RIGHT.br_state && - new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN && - ((state & (BMAP_LEFT_CONTIG | BMAP_LEFT_FILLING | - BMAP_RIGHT_FILLING)) != - (BMAP_LEFT_CONTIG | BMAP_LEFT_FILLING | - BMAP_RIGHT_FILLING) || - LEFT.br_blockcount + new->br_blockcount + RIGHT.br_blockcount - <= MAXEXTLEN)) - state |= BMAP_RIGHT_CONTIG; - - error = 0; - /* - * Switch out based on the FILLING and CONTIG state bits. - */ - switch (state & (BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | - BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG)) { - case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | - BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: - /* - * Filling in all of a previously delayed allocation extent. - * The left and right neighbors are both contiguous with new. - */ - bma->idx--; - trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); - xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, bma->idx), - LEFT.br_blockcount + PREV.br_blockcount + - RIGHT.br_blockcount); - trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); - - xfs_iext_remove(bma->ip, bma->idx + 1, 2, state); - (*nextents)--; - if (bma->cur == NULL) - rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; - else { - rval = XFS_ILOG_CORE; - error = xfs_bmbt_lookup_eq(bma->cur, RIGHT.br_startoff, - RIGHT.br_startblock, - RIGHT.br_blockcount, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - error = xfs_btree_delete(bma->cur, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - error = xfs_btree_decrement(bma->cur, 0, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - error = xfs_bmbt_update(bma->cur, LEFT.br_startoff, - LEFT.br_startblock, - LEFT.br_blockcount + - PREV.br_blockcount + - RIGHT.br_blockcount, LEFT.br_state); - if (error) - goto done; - } - break; - - case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG: - /* - * Filling in all of a previously delayed allocation extent. - * The left neighbor is contiguous, the right is not. - */ - bma->idx--; - - trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); - xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, bma->idx), - LEFT.br_blockcount + PREV.br_blockcount); - trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); - - xfs_iext_remove(bma->ip, bma->idx + 1, 1, state); - if (bma->cur == NULL) - rval = XFS_ILOG_DEXT; - else { - rval = 0; - error = xfs_bmbt_lookup_eq(bma->cur, LEFT.br_startoff, - LEFT.br_startblock, LEFT.br_blockcount, - &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - error = xfs_bmbt_update(bma->cur, LEFT.br_startoff, - LEFT.br_startblock, - LEFT.br_blockcount + - PREV.br_blockcount, LEFT.br_state); - if (error) - goto done; - } - break; - - case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: - /* - * Filling in all of a previously delayed allocation extent. - * The right neighbor is contiguous, the left is not. - */ - trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); - xfs_bmbt_set_startblock(ep, new->br_startblock); - xfs_bmbt_set_blockcount(ep, - PREV.br_blockcount + RIGHT.br_blockcount); - trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); - - xfs_iext_remove(bma->ip, bma->idx + 1, 1, state); - if (bma->cur == NULL) - rval = XFS_ILOG_DEXT; - else { - rval = 0; - error = xfs_bmbt_lookup_eq(bma->cur, RIGHT.br_startoff, - RIGHT.br_startblock, - RIGHT.br_blockcount, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - error = xfs_bmbt_update(bma->cur, PREV.br_startoff, - new->br_startblock, - PREV.br_blockcount + - RIGHT.br_blockcount, PREV.br_state); - if (error) - goto done; - } - break; - - case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING: - /* - * Filling in all of a previously delayed allocation extent. - * Neither the left nor right neighbors are contiguous with - * the new one. - */ - trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); - xfs_bmbt_set_startblock(ep, new->br_startblock); - trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); - - (*nextents)++; - if (bma->cur == NULL) - rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; - else { - rval = XFS_ILOG_CORE; - error = xfs_bmbt_lookup_eq(bma->cur, new->br_startoff, - new->br_startblock, new->br_blockcount, - &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); - bma->cur->bc_rec.b.br_state = XFS_EXT_NORM; - error = xfs_btree_insert(bma->cur, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - } - break; - - case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG: - /* - * Filling in the first part of a previous delayed allocation. - * The left neighbor is contiguous. - */ - trace_xfs_bmap_pre_update(bma->ip, bma->idx - 1, state, _THIS_IP_); - xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, bma->idx - 1), - LEFT.br_blockcount + new->br_blockcount); - xfs_bmbt_set_startoff(ep, - PREV.br_startoff + new->br_blockcount); - trace_xfs_bmap_post_update(bma->ip, bma->idx - 1, state, _THIS_IP_); - - temp = PREV.br_blockcount - new->br_blockcount; - trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); - xfs_bmbt_set_blockcount(ep, temp); - if (bma->cur == NULL) - rval = XFS_ILOG_DEXT; - else { - rval = 0; - error = xfs_bmbt_lookup_eq(bma->cur, LEFT.br_startoff, - LEFT.br_startblock, LEFT.br_blockcount, - &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - error = xfs_bmbt_update(bma->cur, LEFT.br_startoff, - LEFT.br_startblock, - LEFT.br_blockcount + - new->br_blockcount, - LEFT.br_state); - if (error) - goto done; - } - da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp), - startblockval(PREV.br_startblock)); - xfs_bmbt_set_startblock(ep, nullstartblock(da_new)); - trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); - - bma->idx--; - break; - - case BMAP_LEFT_FILLING: - /* - * Filling in the first part of a previous delayed allocation. - * The left neighbor is not contiguous. - */ - trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); - xfs_bmbt_set_startoff(ep, new_endoff); - temp = PREV.br_blockcount - new->br_blockcount; - xfs_bmbt_set_blockcount(ep, temp); - xfs_iext_insert(bma->ip, bma->idx, 1, new, state); - (*nextents)++; - if (bma->cur == NULL) - rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; - else { - rval = XFS_ILOG_CORE; - error = xfs_bmbt_lookup_eq(bma->cur, new->br_startoff, - new->br_startblock, new->br_blockcount, - &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); - bma->cur->bc_rec.b.br_state = XFS_EXT_NORM; - error = xfs_btree_insert(bma->cur, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - } - - if (xfs_bmap_needs_btree(bma->ip, whichfork)) { - error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, - bma->firstblock, bma->dfops, - &bma->cur, 1, &tmp_rval, whichfork); - rval |= tmp_rval; - if (error) - goto done; - } - da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp), - startblockval(PREV.br_startblock) - - (bma->cur ? bma->cur->bc_private.b.allocated : 0)); - ep = xfs_iext_get_ext(ifp, bma->idx + 1); - xfs_bmbt_set_startblock(ep, nullstartblock(da_new)); - trace_xfs_bmap_post_update(bma->ip, bma->idx + 1, state, _THIS_IP_); - break; - - case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: - /* - * Filling in the last part of a previous delayed allocation. - * The right neighbor is contiguous with the new allocation. - */ - temp = PREV.br_blockcount - new->br_blockcount; - trace_xfs_bmap_pre_update(bma->ip, bma->idx + 1, state, _THIS_IP_); - xfs_bmbt_set_blockcount(ep, temp); - xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, bma->idx + 1), - new->br_startoff, new->br_startblock, - new->br_blockcount + RIGHT.br_blockcount, - RIGHT.br_state); - trace_xfs_bmap_post_update(bma->ip, bma->idx + 1, state, _THIS_IP_); - if (bma->cur == NULL) - rval = XFS_ILOG_DEXT; - else { - rval = 0; - error = xfs_bmbt_lookup_eq(bma->cur, RIGHT.br_startoff, - RIGHT.br_startblock, - RIGHT.br_blockcount, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - error = xfs_bmbt_update(bma->cur, new->br_startoff, - new->br_startblock, - new->br_blockcount + - RIGHT.br_blockcount, - RIGHT.br_state); - if (error) - goto done; - } - - da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp), - startblockval(PREV.br_startblock)); - trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); - xfs_bmbt_set_startblock(ep, nullstartblock(da_new)); - trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); - - bma->idx++; - break; - - case BMAP_RIGHT_FILLING: - /* - * Filling in the last part of a previous delayed allocation. - * The right neighbor is not contiguous. - */ - temp = PREV.br_blockcount - new->br_blockcount; - trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); - xfs_bmbt_set_blockcount(ep, temp); - xfs_iext_insert(bma->ip, bma->idx + 1, 1, new, state); - (*nextents)++; - if (bma->cur == NULL) - rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; - else { - rval = XFS_ILOG_CORE; - error = xfs_bmbt_lookup_eq(bma->cur, new->br_startoff, - new->br_startblock, new->br_blockcount, - &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); - bma->cur->bc_rec.b.br_state = XFS_EXT_NORM; - error = xfs_btree_insert(bma->cur, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - } - - if (xfs_bmap_needs_btree(bma->ip, whichfork)) { - error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, - bma->firstblock, bma->dfops, &bma->cur, 1, - &tmp_rval, whichfork); - rval |= tmp_rval; - if (error) - goto done; - } - da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(bma->ip, temp), - startblockval(PREV.br_startblock) - - (bma->cur ? bma->cur->bc_private.b.allocated : 0)); - ep = xfs_iext_get_ext(ifp, bma->idx); - xfs_bmbt_set_startblock(ep, nullstartblock(da_new)); - trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); - - bma->idx++; - break; - - case 0: - /* - * Filling in the middle part of a previous delayed allocation. - * Contiguity is impossible here. - * This case is avoided almost all the time. - * - * We start with a delayed allocation: - * - * +ddddddddddddddddddddddddddddddddddddddddddddddddddddddd+ - * PREV @ idx - * - * and we are allocating: - * +rrrrrrrrrrrrrrrrr+ - * new - * - * and we set it up for insertion as: - * +ddddddddddddddddddd+rrrrrrrrrrrrrrrrr+ddddddddddddddddd+ - * new - * PREV @ idx LEFT RIGHT - * inserted at idx + 1 - */ - temp = new->br_startoff - PREV.br_startoff; - temp2 = PREV.br_startoff + PREV.br_blockcount - new_endoff; - trace_xfs_bmap_pre_update(bma->ip, bma->idx, 0, _THIS_IP_); - xfs_bmbt_set_blockcount(ep, temp); /* truncate PREV */ - LEFT = *new; - RIGHT.br_state = PREV.br_state; - RIGHT.br_startblock = nullstartblock( - (int)xfs_bmap_worst_indlen(bma->ip, temp2)); - RIGHT.br_startoff = new_endoff; - RIGHT.br_blockcount = temp2; - /* insert LEFT (r[0]) and RIGHT (r[1]) at the same time */ - xfs_iext_insert(bma->ip, bma->idx + 1, 2, &LEFT, state); - (*nextents)++; - if (bma->cur == NULL) - rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; - else { - rval = XFS_ILOG_CORE; - error = xfs_bmbt_lookup_eq(bma->cur, new->br_startoff, - new->br_startblock, new->br_blockcount, - &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); - bma->cur->bc_rec.b.br_state = XFS_EXT_NORM; - error = xfs_btree_insert(bma->cur, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - } - - if (xfs_bmap_needs_btree(bma->ip, whichfork)) { - error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, - bma->firstblock, bma->dfops, &bma->cur, - 1, &tmp_rval, whichfork); - rval |= tmp_rval; - if (error) - goto done; - } - temp = xfs_bmap_worst_indlen(bma->ip, temp); - temp2 = xfs_bmap_worst_indlen(bma->ip, temp2); - diff = (int)(temp + temp2 - startblockval(PREV.br_startblock) - - (bma->cur ? bma->cur->bc_private.b.allocated : 0)); - if (diff > 0) { - error = xfs_mod_fdblocks(bma->ip->i_mount, - -((int64_t)diff), false); - ASSERT(!error); - if (error) - goto done; - } - - ep = xfs_iext_get_ext(ifp, bma->idx); - xfs_bmbt_set_startblock(ep, nullstartblock((int)temp)); - trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); - trace_xfs_bmap_pre_update(bma->ip, bma->idx + 2, state, _THIS_IP_); - xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, bma->idx + 2), - nullstartblock((int)temp2)); - trace_xfs_bmap_post_update(bma->ip, bma->idx + 2, state, _THIS_IP_); - - bma->idx++; - da_new = temp + temp2; - break; - - case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: - case BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: - case BMAP_LEFT_FILLING | BMAP_RIGHT_CONTIG: - case BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG: - case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: - case BMAP_LEFT_CONTIG: - case BMAP_RIGHT_CONTIG: - /* - * These cases are all impossible. - */ - ASSERT(0); - } - - /* add reverse mapping */ - error = xfs_rmap_map_extent(mp, bma->dfops, bma->ip, whichfork, new); - if (error) - goto done; - - /* convert to a btree if necessary */ - if (xfs_bmap_needs_btree(bma->ip, whichfork)) { - int tmp_logflags; /* partial log flag return val */ - - ASSERT(bma->cur == NULL); - error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, - bma->firstblock, bma->dfops, &bma->cur, - da_old > 0, &tmp_logflags, whichfork); - bma->logflags |= tmp_logflags; - if (error) - goto done; - } - - /* adjust for changes in reserved delayed indirect blocks */ - if (da_old || da_new) { - temp = da_new; - if (bma->cur) - temp += bma->cur->bc_private.b.allocated; - ASSERT(temp <= da_old); - if (temp < da_old) - xfs_mod_fdblocks(bma->ip->i_mount, - (int64_t)(da_old - temp), false); - } - - /* clear out the allocated field, done with it now in any case. */ - if (bma->cur) - bma->cur->bc_private.b.allocated = 0; - - xfs_bmap_check_leaf_extents(bma->cur, bma->ip, whichfork); -done: - if (whichfork != XFS_COW_FORK) - bma->logflags |= rval; - return error; -#undef LEFT -#undef RIGHT -#undef PREV -} - -/* - * Convert an unwritten allocation to a real allocation or vice versa. - */ -STATIC int /* error */ -xfs_bmap_add_extent_unwritten_real( - struct xfs_trans *tp, - xfs_inode_t *ip, /* incore inode pointer */ - xfs_extnum_t *idx, /* extent number to update/insert */ - xfs_btree_cur_t **curp, /* if *curp is null, not a btree */ - xfs_bmbt_irec_t *new, /* new data to add to file extents */ - xfs_fsblock_t *first, /* pointer to firstblock variable */ - struct xfs_defer_ops *dfops, /* list of extents to be freed */ - int *logflagsp) /* inode logging flags */ -{ - xfs_btree_cur_t *cur; /* btree cursor */ - xfs_bmbt_rec_host_t *ep; /* extent entry for idx */ - int error; /* error return value */ - int i; /* temp state */ - xfs_ifork_t *ifp; /* inode fork pointer */ - xfs_fileoff_t new_endoff; /* end offset of new entry */ - xfs_exntst_t newext; /* new extent state */ - xfs_exntst_t oldext; /* old extent state */ - xfs_bmbt_irec_t r[3]; /* neighbor extent entries */ - /* left is 0, right is 1, prev is 2 */ - int rval=0; /* return value (logging flags) */ - int state = 0;/* state bits, accessed thru macros */ - struct xfs_mount *mp = tp->t_mountp; - - *logflagsp = 0; - - cur = *curp; - ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); - - ASSERT(*idx >= 0); - ASSERT(*idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec)); - ASSERT(!isnullstartblock(new->br_startblock)); - - XFS_STATS_INC(mp, xs_add_exlist); - -#define LEFT r[0] -#define RIGHT r[1] -#define PREV r[2] - - /* - * Set up a bunch of variables to make the tests simpler. - */ - error = 0; - ep = xfs_iext_get_ext(ifp, *idx); - xfs_bmbt_get_all(ep, &PREV); - newext = new->br_state; - oldext = (newext == XFS_EXT_UNWRITTEN) ? - XFS_EXT_NORM : XFS_EXT_UNWRITTEN; - ASSERT(PREV.br_state == oldext); - new_endoff = new->br_startoff + new->br_blockcount; - ASSERT(PREV.br_startoff <= new->br_startoff); - ASSERT(PREV.br_startoff + PREV.br_blockcount >= new_endoff); - - /* - * Set flags determining what part of the previous oldext allocation - * extent is being replaced by a newext allocation. - */ - if (PREV.br_startoff == new->br_startoff) - state |= BMAP_LEFT_FILLING; - if (PREV.br_startoff + PREV.br_blockcount == new_endoff) - state |= BMAP_RIGHT_FILLING; - - /* - * Check and set flags if this segment has a left neighbor. - * Don't set contiguous if the combined extent would be too large. - */ - if (*idx > 0) { - state |= BMAP_LEFT_VALID; - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx - 1), &LEFT); - - if (isnullstartblock(LEFT.br_startblock)) - state |= BMAP_LEFT_DELAY; - } - - if ((state & BMAP_LEFT_VALID) && !(state & BMAP_LEFT_DELAY) && - LEFT.br_startoff + LEFT.br_blockcount == new->br_startoff && - LEFT.br_startblock + LEFT.br_blockcount == new->br_startblock && - LEFT.br_state == newext && - LEFT.br_blockcount + new->br_blockcount <= MAXEXTLEN) - state |= BMAP_LEFT_CONTIG; - - /* - * Check and set flags if this segment has a right neighbor. - * Don't set contiguous if the combined extent would be too large. - * Also check for all-three-contiguous being too large. - */ - if (*idx < ip->i_df.if_bytes / (uint)sizeof(xfs_bmbt_rec_t) - 1) { - state |= BMAP_RIGHT_VALID; - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx + 1), &RIGHT); - if (isnullstartblock(RIGHT.br_startblock)) - state |= BMAP_RIGHT_DELAY; - } - - if ((state & BMAP_RIGHT_VALID) && !(state & BMAP_RIGHT_DELAY) && - new_endoff == RIGHT.br_startoff && - new->br_startblock + new->br_blockcount == RIGHT.br_startblock && - newext == RIGHT.br_state && - new->br_blockcount + RIGHT.br_blockcount <= MAXEXTLEN && - ((state & (BMAP_LEFT_CONTIG | BMAP_LEFT_FILLING | - BMAP_RIGHT_FILLING)) != - (BMAP_LEFT_CONTIG | BMAP_LEFT_FILLING | - BMAP_RIGHT_FILLING) || - LEFT.br_blockcount + new->br_blockcount + RIGHT.br_blockcount - <= MAXEXTLEN)) - state |= BMAP_RIGHT_CONTIG; - - /* - * Switch out based on the FILLING and CONTIG state bits. - */ - switch (state & (BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | - BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG)) { - case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | - BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: - /* - * Setting all of a previous oldext extent to newext. - * The left and right neighbors are both contiguous with new. - */ - --*idx; - - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx), - LEFT.br_blockcount + PREV.br_blockcount + - RIGHT.br_blockcount); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - - xfs_iext_remove(ip, *idx + 1, 2, state); - ip->i_d.di_nextents -= 2; - if (cur == NULL) - rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; - else { - rval = XFS_ILOG_CORE; - if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, - RIGHT.br_startblock, - RIGHT.br_blockcount, &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - if ((error = xfs_btree_delete(cur, &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - if ((error = xfs_btree_decrement(cur, 0, &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - if ((error = xfs_btree_delete(cur, &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - if ((error = xfs_btree_decrement(cur, 0, &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, - LEFT.br_startblock, - LEFT.br_blockcount + PREV.br_blockcount + - RIGHT.br_blockcount, LEFT.br_state))) - goto done; - } - break; - - case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG: - /* - * Setting all of a previous oldext extent to newext. - * The left neighbor is contiguous, the right is not. - */ - --*idx; - - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx), - LEFT.br_blockcount + PREV.br_blockcount); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - - xfs_iext_remove(ip, *idx + 1, 1, state); - ip->i_d.di_nextents--; - if (cur == NULL) - rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; - else { - rval = XFS_ILOG_CORE; - if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, - PREV.br_startblock, PREV.br_blockcount, - &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - if ((error = xfs_btree_delete(cur, &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - if ((error = xfs_btree_decrement(cur, 0, &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - if ((error = xfs_bmbt_update(cur, LEFT.br_startoff, - LEFT.br_startblock, - LEFT.br_blockcount + PREV.br_blockcount, - LEFT.br_state))) - goto done; - } - break; - - case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: - /* - * Setting all of a previous oldext extent to newext. - * The right neighbor is contiguous, the left is not. - */ - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - xfs_bmbt_set_blockcount(ep, - PREV.br_blockcount + RIGHT.br_blockcount); - xfs_bmbt_set_state(ep, newext); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - xfs_iext_remove(ip, *idx + 1, 1, state); - ip->i_d.di_nextents--; - if (cur == NULL) - rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; - else { - rval = XFS_ILOG_CORE; - if ((error = xfs_bmbt_lookup_eq(cur, RIGHT.br_startoff, - RIGHT.br_startblock, - RIGHT.br_blockcount, &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - if ((error = xfs_btree_delete(cur, &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - if ((error = xfs_btree_decrement(cur, 0, &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - if ((error = xfs_bmbt_update(cur, new->br_startoff, - new->br_startblock, - new->br_blockcount + RIGHT.br_blockcount, - newext))) - goto done; - } - break; - - case BMAP_LEFT_FILLING | BMAP_RIGHT_FILLING: - /* - * Setting all of a previous oldext extent to newext. - * Neither the left nor right neighbors are contiguous with - * the new one. - */ - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - xfs_bmbt_set_state(ep, newext); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - - if (cur == NULL) - rval = XFS_ILOG_DEXT; - else { - rval = 0; - if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, - new->br_startblock, new->br_blockcount, - &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - if ((error = xfs_bmbt_update(cur, new->br_startoff, - new->br_startblock, new->br_blockcount, - newext))) - goto done; - } - break; - - case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG: - /* - * Setting the first part of a previous oldext extent to newext. - * The left neighbor is contiguous. - */ - trace_xfs_bmap_pre_update(ip, *idx - 1, state, _THIS_IP_); - xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx - 1), - LEFT.br_blockcount + new->br_blockcount); - xfs_bmbt_set_startoff(ep, - PREV.br_startoff + new->br_blockcount); - trace_xfs_bmap_post_update(ip, *idx - 1, state, _THIS_IP_); - - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - xfs_bmbt_set_startblock(ep, - new->br_startblock + new->br_blockcount); - xfs_bmbt_set_blockcount(ep, - PREV.br_blockcount - new->br_blockcount); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - - --*idx; - - if (cur == NULL) - rval = XFS_ILOG_DEXT; - else { - rval = 0; - if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, - PREV.br_startblock, PREV.br_blockcount, - &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - if ((error = xfs_bmbt_update(cur, - PREV.br_startoff + new->br_blockcount, - PREV.br_startblock + new->br_blockcount, - PREV.br_blockcount - new->br_blockcount, - oldext))) - goto done; - if ((error = xfs_btree_decrement(cur, 0, &i))) - goto done; - error = xfs_bmbt_update(cur, LEFT.br_startoff, - LEFT.br_startblock, - LEFT.br_blockcount + new->br_blockcount, - LEFT.br_state); - if (error) - goto done; - } - break; - - case BMAP_LEFT_FILLING: - /* - * Setting the first part of a previous oldext extent to newext. - * The left neighbor is not contiguous. - */ - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - ASSERT(ep && xfs_bmbt_get_state(ep) == oldext); - xfs_bmbt_set_startoff(ep, new_endoff); - xfs_bmbt_set_blockcount(ep, - PREV.br_blockcount - new->br_blockcount); - xfs_bmbt_set_startblock(ep, - new->br_startblock + new->br_blockcount); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - - xfs_iext_insert(ip, *idx, 1, new, state); - ip->i_d.di_nextents++; - if (cur == NULL) - rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; - else { - rval = XFS_ILOG_CORE; - if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, - PREV.br_startblock, PREV.br_blockcount, - &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - if ((error = xfs_bmbt_update(cur, - PREV.br_startoff + new->br_blockcount, - PREV.br_startblock + new->br_blockcount, - PREV.br_blockcount - new->br_blockcount, - oldext))) - goto done; - cur->bc_rec.b = *new; - if ((error = xfs_btree_insert(cur, &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - } - break; - - case BMAP_RIGHT_FILLING | BMAP_RIGHT_CONTIG: - /* - * Setting the last part of a previous oldext extent to newext. - * The right neighbor is contiguous with the new allocation. - */ - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - xfs_bmbt_set_blockcount(ep, - PREV.br_blockcount - new->br_blockcount); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - - ++*idx; - - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, *idx), - new->br_startoff, new->br_startblock, - new->br_blockcount + RIGHT.br_blockcount, newext); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - - if (cur == NULL) - rval = XFS_ILOG_DEXT; - else { - rval = 0; - if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, - PREV.br_startblock, - PREV.br_blockcount, &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - if ((error = xfs_bmbt_update(cur, PREV.br_startoff, - PREV.br_startblock, - PREV.br_blockcount - new->br_blockcount, - oldext))) - goto done; - if ((error = xfs_btree_increment(cur, 0, &i))) - goto done; - if ((error = xfs_bmbt_update(cur, new->br_startoff, - new->br_startblock, - new->br_blockcount + RIGHT.br_blockcount, - newext))) - goto done; - } - break; - - case BMAP_RIGHT_FILLING: - /* - * Setting the last part of a previous oldext extent to newext. - * The right neighbor is not contiguous. - */ - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - xfs_bmbt_set_blockcount(ep, - PREV.br_blockcount - new->br_blockcount); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - - ++*idx; - xfs_iext_insert(ip, *idx, 1, new, state); - - ip->i_d.di_nextents++; - if (cur == NULL) - rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; - else { - rval = XFS_ILOG_CORE; - if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, - PREV.br_startblock, PREV.br_blockcount, - &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - if ((error = xfs_bmbt_update(cur, PREV.br_startoff, - PREV.br_startblock, - PREV.br_blockcount - new->br_blockcount, - oldext))) - goto done; - if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, - new->br_startblock, new->br_blockcount, - &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); - cur->bc_rec.b.br_state = XFS_EXT_NORM; - if ((error = xfs_btree_insert(cur, &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - } - break; - - case 0: - /* - * Setting the middle part of a previous oldext extent to - * newext. Contiguity is impossible here. - * One extent becomes three extents. - */ - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - xfs_bmbt_set_blockcount(ep, - new->br_startoff - PREV.br_startoff); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - - r[0] = *new; - r[1].br_startoff = new_endoff; - r[1].br_blockcount = - PREV.br_startoff + PREV.br_blockcount - new_endoff; - r[1].br_startblock = new->br_startblock + new->br_blockcount; - r[1].br_state = oldext; - - ++*idx; - xfs_iext_insert(ip, *idx, 2, &r[0], state); - - ip->i_d.di_nextents += 2; - if (cur == NULL) - rval = XFS_ILOG_CORE | XFS_ILOG_DEXT; - else { - rval = XFS_ILOG_CORE; - if ((error = xfs_bmbt_lookup_eq(cur, PREV.br_startoff, - PREV.br_startblock, PREV.br_blockcount, - &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - /* new right extent - oldext */ - if ((error = xfs_bmbt_update(cur, r[1].br_startoff, - r[1].br_startblock, r[1].br_blockcount, - r[1].br_state))) - goto done; - /* new left extent - oldext */ - cur->bc_rec.b = PREV; - cur->bc_rec.b.br_blockcount = - new->br_startoff - PREV.br_startoff; - if ((error = xfs_btree_insert(cur, &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - /* - * Reset the cursor to the position of the new extent - * we are about to insert as we can't trust it after - * the previous insert. - */ - if ((error = xfs_bmbt_lookup_eq(cur, new->br_startoff, - new->br_startblock, new->br_blockcount, - &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); - /* new middle extent - newext */ - cur->bc_rec.b.br_state = new->br_state; - if ((error = xfs_btree_insert(cur, &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - } - break; - - case BMAP_LEFT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: - case BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: - case BMAP_LEFT_FILLING | BMAP_RIGHT_CONTIG: - case BMAP_RIGHT_FILLING | BMAP_LEFT_CONTIG: - case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: - case BMAP_LEFT_CONTIG: - case BMAP_RIGHT_CONTIG: - /* - * These cases are all impossible. - */ - ASSERT(0); - } - - /* update reverse mappings */ - error = xfs_rmap_convert_extent(mp, dfops, ip, XFS_DATA_FORK, new); - if (error) - goto done; - - /* convert to a btree if necessary */ - if (xfs_bmap_needs_btree(ip, XFS_DATA_FORK)) { - int tmp_logflags; /* partial log flag return val */ - - ASSERT(cur == NULL); - error = xfs_bmap_extents_to_btree(tp, ip, first, dfops, &cur, - 0, &tmp_logflags, XFS_DATA_FORK); - *logflagsp |= tmp_logflags; - if (error) - goto done; - } - - /* clear out the allocated field, done with it now in any case. */ - if (cur) { - cur->bc_private.b.allocated = 0; - *curp = cur; - } - - xfs_bmap_check_leaf_extents(*curp, ip, XFS_DATA_FORK); -done: - *logflagsp |= rval; - return error; -#undef LEFT -#undef RIGHT -#undef PREV -} - -/* - * Convert a hole to a delayed allocation. - */ -STATIC void -xfs_bmap_add_extent_hole_delay( - xfs_inode_t *ip, /* incore inode pointer */ - int whichfork, - xfs_extnum_t *idx, /* extent number to update/insert */ - xfs_bmbt_irec_t *new) /* new data to add to file extents */ -{ - xfs_ifork_t *ifp; /* inode fork pointer */ - xfs_bmbt_irec_t left; /* left neighbor extent entry */ - xfs_filblks_t newlen=0; /* new indirect size */ - xfs_filblks_t oldlen=0; /* old indirect size */ - xfs_bmbt_irec_t right; /* right neighbor extent entry */ - int state; /* state bits, accessed thru macros */ - xfs_filblks_t temp=0; /* temp for indirect calculations */ - - ifp = XFS_IFORK_PTR(ip, whichfork); - state = 0; - if (whichfork == XFS_COW_FORK) - state |= BMAP_COWFORK; - ASSERT(isnullstartblock(new->br_startblock)); - - /* - * Check and set flags if this segment has a left neighbor - */ - if (*idx > 0) { - state |= BMAP_LEFT_VALID; - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx - 1), &left); - - if (isnullstartblock(left.br_startblock)) - state |= BMAP_LEFT_DELAY; - } - - /* - * Check and set flags if the current (right) segment exists. - * If it doesn't exist, we're converting the hole at end-of-file. - */ - if (*idx < ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t)) { - state |= BMAP_RIGHT_VALID; - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *idx), &right); - - if (isnullstartblock(right.br_startblock)) - state |= BMAP_RIGHT_DELAY; - } - - /* - * Set contiguity flags on the left and right neighbors. - * Don't let extents get too large, even if the pieces are contiguous. - */ - if ((state & BMAP_LEFT_VALID) && (state & BMAP_LEFT_DELAY) && - left.br_startoff + left.br_blockcount == new->br_startoff && - left.br_blockcount + new->br_blockcount <= MAXEXTLEN) - state |= BMAP_LEFT_CONTIG; - - if ((state & BMAP_RIGHT_VALID) && (state & BMAP_RIGHT_DELAY) && - new->br_startoff + new->br_blockcount == right.br_startoff && - new->br_blockcount + right.br_blockcount <= MAXEXTLEN && - (!(state & BMAP_LEFT_CONTIG) || - (left.br_blockcount + new->br_blockcount + - right.br_blockcount <= MAXEXTLEN))) - state |= BMAP_RIGHT_CONTIG; - - /* - * Switch out based on the contiguity flags. - */ - switch (state & (BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG)) { - case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: - /* - * New allocation is contiguous with delayed allocations - * on the left and on the right. - * Merge all three into a single extent record. - */ - --*idx; - temp = left.br_blockcount + new->br_blockcount + - right.br_blockcount; - - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx), temp); - oldlen = startblockval(left.br_startblock) + - startblockval(new->br_startblock) + - startblockval(right.br_startblock); - newlen = xfs_bmap_worst_indlen(ip, temp); - xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, *idx), - nullstartblock((int)newlen)); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - - xfs_iext_remove(ip, *idx + 1, 1, state); - break; - - case BMAP_LEFT_CONTIG: - /* - * New allocation is contiguous with a delayed allocation - * on the left. - * Merge the new allocation with the left neighbor. - */ - --*idx; - temp = left.br_blockcount + new->br_blockcount; - - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, *idx), temp); - oldlen = startblockval(left.br_startblock) + - startblockval(new->br_startblock); - newlen = xfs_bmap_worst_indlen(ip, temp); - xfs_bmbt_set_startblock(xfs_iext_get_ext(ifp, *idx), - nullstartblock((int)newlen)); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - break; - - case BMAP_RIGHT_CONTIG: - /* - * New allocation is contiguous with a delayed allocation - * on the right. - * Merge the new allocation with the right neighbor. - */ - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - temp = new->br_blockcount + right.br_blockcount; - oldlen = startblockval(new->br_startblock) + - startblockval(right.br_startblock); - newlen = xfs_bmap_worst_indlen(ip, temp); - xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, *idx), - new->br_startoff, - nullstartblock((int)newlen), temp, right.br_state); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - break; - - case 0: - /* - * New allocation is not contiguous with another - * delayed allocation. - * Insert a new entry. - */ - oldlen = newlen = 0; - xfs_iext_insert(ip, *idx, 1, new, state); - break; - } - if (oldlen != newlen) { - ASSERT(oldlen > newlen); - xfs_mod_fdblocks(ip->i_mount, (int64_t)(oldlen - newlen), - false); - /* - * Nothing to do for disk quota accounting here. - */ - } -} - -/* - * Convert a hole to a real allocation. - */ -STATIC int /* error */ -xfs_bmap_add_extent_hole_real( - struct xfs_bmalloca *bma, - int whichfork) -{ - struct xfs_bmbt_irec *new = &bma->got; - int error; /* error return value */ - int i; /* temp state */ - xfs_ifork_t *ifp; /* inode fork pointer */ - xfs_bmbt_irec_t left; /* left neighbor extent entry */ - xfs_bmbt_irec_t right; /* right neighbor extent entry */ - int rval=0; /* return value (logging flags) */ - int state; /* state bits, accessed thru macros */ - struct xfs_mount *mp; - - mp = bma->ip->i_mount; - ifp = XFS_IFORK_PTR(bma->ip, whichfork); - - ASSERT(bma->idx >= 0); - ASSERT(bma->idx <= ifp->if_bytes / sizeof(struct xfs_bmbt_rec)); - ASSERT(!isnullstartblock(new->br_startblock)); - ASSERT(!bma->cur || - !(bma->cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL)); - ASSERT(whichfork != XFS_COW_FORK); - - XFS_STATS_INC(mp, xs_add_exlist); - - state = 0; - if (whichfork == XFS_ATTR_FORK) - state |= BMAP_ATTRFORK; - - /* - * Check and set flags if this segment has a left neighbor. - */ - if (bma->idx > 0) { - state |= BMAP_LEFT_VALID; - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx - 1), &left); - if (isnullstartblock(left.br_startblock)) - state |= BMAP_LEFT_DELAY; - } - - /* - * Check and set flags if this segment has a current value. - * Not true if we're inserting into the "hole" at eof. - */ - if (bma->idx < ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t)) { - state |= BMAP_RIGHT_VALID; - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx), &right); - if (isnullstartblock(right.br_startblock)) - state |= BMAP_RIGHT_DELAY; - } - - /* - * We're inserting a real allocation between "left" and "right". - * Set the contiguity flags. Don't let extents get too large. - */ - if ((state & BMAP_LEFT_VALID) && !(state & BMAP_LEFT_DELAY) && - left.br_startoff + left.br_blockcount == new->br_startoff && - left.br_startblock + left.br_blockcount == new->br_startblock && - left.br_state == new->br_state && - left.br_blockcount + new->br_blockcount <= MAXEXTLEN) - state |= BMAP_LEFT_CONTIG; - - if ((state & BMAP_RIGHT_VALID) && !(state & BMAP_RIGHT_DELAY) && - new->br_startoff + new->br_blockcount == right.br_startoff && - new->br_startblock + new->br_blockcount == right.br_startblock && - new->br_state == right.br_state && - new->br_blockcount + right.br_blockcount <= MAXEXTLEN && - (!(state & BMAP_LEFT_CONTIG) || - left.br_blockcount + new->br_blockcount + - right.br_blockcount <= MAXEXTLEN)) - state |= BMAP_RIGHT_CONTIG; - - error = 0; - /* - * Select which case we're in here, and implement it. - */ - switch (state & (BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG)) { - case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: - /* - * New allocation is contiguous with real allocations on the - * left and on the right. - * Merge all three into a single extent record. - */ - --bma->idx; - trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); - xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, bma->idx), - left.br_blockcount + new->br_blockcount + - right.br_blockcount); - trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); - - xfs_iext_remove(bma->ip, bma->idx + 1, 1, state); - - XFS_IFORK_NEXT_SET(bma->ip, whichfork, - XFS_IFORK_NEXTENTS(bma->ip, whichfork) - 1); - if (bma->cur == NULL) { - rval = XFS_ILOG_CORE | xfs_ilog_fext(whichfork); - } else { - rval = XFS_ILOG_CORE; - error = xfs_bmbt_lookup_eq(bma->cur, right.br_startoff, - right.br_startblock, right.br_blockcount, - &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - error = xfs_btree_delete(bma->cur, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - error = xfs_btree_decrement(bma->cur, 0, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - error = xfs_bmbt_update(bma->cur, left.br_startoff, - left.br_startblock, - left.br_blockcount + - new->br_blockcount + - right.br_blockcount, - left.br_state); - if (error) - goto done; - } - break; - - case BMAP_LEFT_CONTIG: - /* - * New allocation is contiguous with a real allocation - * on the left. - * Merge the new allocation with the left neighbor. - */ - --bma->idx; - trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); - xfs_bmbt_set_blockcount(xfs_iext_get_ext(ifp, bma->idx), - left.br_blockcount + new->br_blockcount); - trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); - - if (bma->cur == NULL) { - rval = xfs_ilog_fext(whichfork); - } else { - rval = 0; - error = xfs_bmbt_lookup_eq(bma->cur, left.br_startoff, - left.br_startblock, left.br_blockcount, - &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - error = xfs_bmbt_update(bma->cur, left.br_startoff, - left.br_startblock, - left.br_blockcount + - new->br_blockcount, - left.br_state); - if (error) - goto done; - } - break; - - case BMAP_RIGHT_CONTIG: - /* - * New allocation is contiguous with a real allocation - * on the right. - * Merge the new allocation with the right neighbor. - */ - trace_xfs_bmap_pre_update(bma->ip, bma->idx, state, _THIS_IP_); - xfs_bmbt_set_allf(xfs_iext_get_ext(ifp, bma->idx), - new->br_startoff, new->br_startblock, - new->br_blockcount + right.br_blockcount, - right.br_state); - trace_xfs_bmap_post_update(bma->ip, bma->idx, state, _THIS_IP_); - - if (bma->cur == NULL) { - rval = xfs_ilog_fext(whichfork); - } else { - rval = 0; - error = xfs_bmbt_lookup_eq(bma->cur, - right.br_startoff, - right.br_startblock, - right.br_blockcount, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - error = xfs_bmbt_update(bma->cur, new->br_startoff, - new->br_startblock, - new->br_blockcount + - right.br_blockcount, - right.br_state); - if (error) - goto done; - } - break; - - case 0: - /* - * New allocation is not contiguous with another - * real allocation. - * Insert a new entry. - */ - xfs_iext_insert(bma->ip, bma->idx, 1, new, state); - XFS_IFORK_NEXT_SET(bma->ip, whichfork, - XFS_IFORK_NEXTENTS(bma->ip, whichfork) + 1); - if (bma->cur == NULL) { - rval = XFS_ILOG_CORE | xfs_ilog_fext(whichfork); - } else { - rval = XFS_ILOG_CORE; - error = xfs_bmbt_lookup_eq(bma->cur, - new->br_startoff, - new->br_startblock, - new->br_blockcount, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); - bma->cur->bc_rec.b.br_state = new->br_state; - error = xfs_btree_insert(bma->cur, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - } - break; - } - - /* add reverse mapping */ - error = xfs_rmap_map_extent(mp, bma->dfops, bma->ip, whichfork, new); - if (error) - goto done; - - /* convert to a btree if necessary */ - if (xfs_bmap_needs_btree(bma->ip, whichfork)) { - int tmp_logflags; /* partial log flag return val */ - - ASSERT(bma->cur == NULL); - error = xfs_bmap_extents_to_btree(bma->tp, bma->ip, - bma->firstblock, bma->dfops, &bma->cur, - 0, &tmp_logflags, whichfork); - bma->logflags |= tmp_logflags; - if (error) - goto done; - } - - /* clear out the allocated field, done with it now in any case. */ - if (bma->cur) - bma->cur->bc_private.b.allocated = 0; - - xfs_bmap_check_leaf_extents(bma->cur, bma->ip, whichfork); -done: - bma->logflags |= rval; - return error; -} - -/* - * Functions used in the extent read, allocate and remove paths - */ - -/* - * Adjust the size of the new extent based on di_extsize and rt extsize. - */ -int -xfs_bmap_extsize_align( - xfs_mount_t *mp, - xfs_bmbt_irec_t *gotp, /* next extent pointer */ - xfs_bmbt_irec_t *prevp, /* previous extent pointer */ - xfs_extlen_t extsz, /* align to this extent size */ - int rt, /* is this a realtime inode? */ - int eof, /* is extent at end-of-file? */ - int delay, /* creating delalloc extent? */ - int convert, /* overwriting unwritten extent? */ - xfs_fileoff_t *offp, /* in/out: aligned offset */ - xfs_extlen_t *lenp) /* in/out: aligned length */ -{ - xfs_fileoff_t orig_off; /* original offset */ - xfs_extlen_t orig_alen; /* original length */ - xfs_fileoff_t orig_end; /* original off+len */ - xfs_fileoff_t nexto; /* next file offset */ - xfs_fileoff_t prevo; /* previous file offset */ - xfs_fileoff_t align_off; /* temp for offset */ - xfs_extlen_t align_alen; /* temp for length */ - xfs_extlen_t temp; /* temp for calculations */ - - if (convert) - return 0; - - orig_off = align_off = *offp; - orig_alen = align_alen = *lenp; - orig_end = orig_off + orig_alen; - - /* - * If this request overlaps an existing extent, then don't - * attempt to perform any additional alignment. - */ - if (!delay && !eof && - (orig_off >= gotp->br_startoff) && - (orig_end <= gotp->br_startoff + gotp->br_blockcount)) { - return 0; - } - - /* - * If the file offset is unaligned vs. the extent size - * we need to align it. This will be possible unless - * the file was previously written with a kernel that didn't - * perform this alignment, or if a truncate shot us in the - * foot. - */ - temp = do_mod(orig_off, extsz); - if (temp) { - align_alen += temp; - align_off -= temp; - } - - /* Same adjustment for the end of the requested area. */ - temp = (align_alen % extsz); - if (temp) - align_alen += extsz - temp; - - /* - * For large extent hint sizes, the aligned extent might be larger than - * MAXEXTLEN. In that case, reduce the size by an extsz so that it pulls - * the length back under MAXEXTLEN. The outer allocation loops handle - * short allocation just fine, so it is safe to do this. We only want to - * do it when we are forced to, though, because it means more allocation - * operations are required. - */ - while (align_alen > MAXEXTLEN) - align_alen -= extsz; - ASSERT(align_alen <= MAXEXTLEN); - - /* - * If the previous block overlaps with this proposed allocation - * then move the start forward without adjusting the length. - */ - if (prevp->br_startoff != NULLFILEOFF) { - if (prevp->br_startblock == HOLESTARTBLOCK) - prevo = prevp->br_startoff; - else - prevo = prevp->br_startoff + prevp->br_blockcount; - } else - prevo = 0; - if (align_off != orig_off && align_off < prevo) - align_off = prevo; - /* - * If the next block overlaps with this proposed allocation - * then move the start back without adjusting the length, - * but not before offset 0. - * This may of course make the start overlap previous block, - * and if we hit the offset 0 limit then the next block - * can still overlap too. - */ - if (!eof && gotp->br_startoff != NULLFILEOFF) { - if ((delay && gotp->br_startblock == HOLESTARTBLOCK) || - (!delay && gotp->br_startblock == DELAYSTARTBLOCK)) - nexto = gotp->br_startoff + gotp->br_blockcount; - else - nexto = gotp->br_startoff; - } else - nexto = NULLFILEOFF; - if (!eof && - align_off + align_alen != orig_end && - align_off + align_alen > nexto) - align_off = nexto > align_alen ? nexto - align_alen : 0; - /* - * If we're now overlapping the next or previous extent that - * means we can't fit an extsz piece in this hole. Just move - * the start forward to the first valid spot and set - * the length so we hit the end. - */ - if (align_off != orig_off && align_off < prevo) - align_off = prevo; - if (align_off + align_alen != orig_end && - align_off + align_alen > nexto && - nexto != NULLFILEOFF) { - ASSERT(nexto > prevo); - align_alen = nexto - align_off; - } - - /* - * If realtime, and the result isn't a multiple of the realtime - * extent size we need to remove blocks until it is. - */ - if (rt && (temp = (align_alen % mp->m_sb.sb_rextsize))) { - /* - * We're not covering the original request, or - * we won't be able to once we fix the length. - */ - if (orig_off < align_off || - orig_end > align_off + align_alen || - align_alen - temp < orig_alen) - return -EINVAL; - /* - * Try to fix it by moving the start up. - */ - if (align_off + temp <= orig_off) { - align_alen -= temp; - align_off += temp; - } - /* - * Try to fix it by moving the end in. - */ - else if (align_off + align_alen - temp >= orig_end) - align_alen -= temp; - /* - * Set the start to the minimum then trim the length. - */ - else { - align_alen -= orig_off - align_off; - align_off = orig_off; - align_alen -= align_alen % mp->m_sb.sb_rextsize; - } - /* - * Result doesn't cover the request, fail it. - */ - if (orig_off < align_off || orig_end > align_off + align_alen) - return -EINVAL; - } else { - ASSERT(orig_off >= align_off); - /* see MAXEXTLEN handling above */ - ASSERT(orig_end <= align_off + align_alen || - align_alen + extsz > MAXEXTLEN); - } - -#ifdef DEBUG - if (!eof && gotp->br_startoff != NULLFILEOFF) - ASSERT(align_off + align_alen <= gotp->br_startoff); - if (prevp->br_startoff != NULLFILEOFF) - ASSERT(align_off >= prevp->br_startoff + prevp->br_blockcount); -#endif - - *lenp = align_alen; - *offp = align_off; - return 0; -} - -#define XFS_ALLOC_GAP_UNITS 4 - -void -xfs_bmap_adjacent( - struct xfs_bmalloca *ap) /* bmap alloc argument struct */ -{ - xfs_fsblock_t adjust; /* adjustment to block numbers */ - xfs_agnumber_t fb_agno; /* ag number of ap->firstblock */ - xfs_mount_t *mp; /* mount point structure */ - int nullfb; /* true if ap->firstblock isn't set */ - int rt; /* true if inode is realtime */ - -#define ISVALID(x,y) \ - (rt ? \ - (x) < mp->m_sb.sb_rblocks : \ - XFS_FSB_TO_AGNO(mp, x) == XFS_FSB_TO_AGNO(mp, y) && \ - XFS_FSB_TO_AGNO(mp, x) < mp->m_sb.sb_agcount && \ - XFS_FSB_TO_AGBNO(mp, x) < mp->m_sb.sb_agblocks) - - mp = ap->ip->i_mount; - nullfb = *ap->firstblock == NULLFSBLOCK; - rt = XFS_IS_REALTIME_INODE(ap->ip) && - xfs_alloc_is_userdata(ap->datatype); - fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, *ap->firstblock); - /* - * If allocating at eof, and there's a previous real block, - * try to use its last block as our starting point. - */ - if (ap->eof && ap->prev.br_startoff != NULLFILEOFF && - !isnullstartblock(ap->prev.br_startblock) && - ISVALID(ap->prev.br_startblock + ap->prev.br_blockcount, - ap->prev.br_startblock)) { - ap->blkno = ap->prev.br_startblock + ap->prev.br_blockcount; - /* - * Adjust for the gap between prevp and us. - */ - adjust = ap->offset - - (ap->prev.br_startoff + ap->prev.br_blockcount); - if (adjust && - ISVALID(ap->blkno + adjust, ap->prev.br_startblock)) - ap->blkno += adjust; - } - /* - * If not at eof, then compare the two neighbor blocks. - * Figure out whether either one gives us a good starting point, - * and pick the better one. - */ - else if (!ap->eof) { - xfs_fsblock_t gotbno; /* right side block number */ - xfs_fsblock_t gotdiff=0; /* right side difference */ - xfs_fsblock_t prevbno; /* left side block number */ - xfs_fsblock_t prevdiff=0; /* left side difference */ - - /* - * If there's a previous (left) block, select a requested - * start block based on it. - */ - if (ap->prev.br_startoff != NULLFILEOFF && - !isnullstartblock(ap->prev.br_startblock) && - (prevbno = ap->prev.br_startblock + - ap->prev.br_blockcount) && - ISVALID(prevbno, ap->prev.br_startblock)) { - /* - * Calculate gap to end of previous block. - */ - adjust = prevdiff = ap->offset - - (ap->prev.br_startoff + - ap->prev.br_blockcount); - /* - * Figure the startblock based on the previous block's - * end and the gap size. - * Heuristic! - * If the gap is large relative to the piece we're - * allocating, or using it gives us an invalid block - * number, then just use the end of the previous block. - */ - if (prevdiff <= XFS_ALLOC_GAP_UNITS * ap->length && - ISVALID(prevbno + prevdiff, - ap->prev.br_startblock)) - prevbno += adjust; - else - prevdiff += adjust; - /* - * If the firstblock forbids it, can't use it, - * must use default. - */ - if (!rt && !nullfb && - XFS_FSB_TO_AGNO(mp, prevbno) != fb_agno) - prevbno = NULLFSBLOCK; - } - /* - * No previous block or can't follow it, just default. - */ - else - prevbno = NULLFSBLOCK; - /* - * If there's a following (right) block, select a requested - * start block based on it. - */ - if (!isnullstartblock(ap->got.br_startblock)) { - /* - * Calculate gap to start of next block. - */ - adjust = gotdiff = ap->got.br_startoff - ap->offset; - /* - * Figure the startblock based on the next block's - * start and the gap size. - */ - gotbno = ap->got.br_startblock; - /* - * Heuristic! - * If the gap is large relative to the piece we're - * allocating, or using it gives us an invalid block - * number, then just use the start of the next block - * offset by our length. - */ - if (gotdiff <= XFS_ALLOC_GAP_UNITS * ap->length && - ISVALID(gotbno - gotdiff, gotbno)) - gotbno -= adjust; - else if (ISVALID(gotbno - ap->length, gotbno)) { - gotbno -= ap->length; - gotdiff += adjust - ap->length; - } else - gotdiff += adjust; - /* - * If the firstblock forbids it, can't use it, - * must use default. - */ - if (!rt && !nullfb && - XFS_FSB_TO_AGNO(mp, gotbno) != fb_agno) - gotbno = NULLFSBLOCK; - } - /* - * No next block, just default. - */ - else - gotbno = NULLFSBLOCK; - /* - * If both valid, pick the better one, else the only good - * one, else ap->blkno is already set (to 0 or the inode block). - */ - if (prevbno != NULLFSBLOCK && gotbno != NULLFSBLOCK) - ap->blkno = prevdiff <= gotdiff ? prevbno : gotbno; - else if (prevbno != NULLFSBLOCK) - ap->blkno = prevbno; - else if (gotbno != NULLFSBLOCK) - ap->blkno = gotbno; - } -#undef ISVALID -} - -static int -xfs_bmap_longest_free_extent( - struct xfs_trans *tp, - xfs_agnumber_t ag, - xfs_extlen_t *blen, - int *notinit) -{ - struct xfs_mount *mp = tp->t_mountp; - struct xfs_perag *pag; - xfs_extlen_t longest; - int error = 0; - - pag = xfs_perag_get(mp, ag); - if (!pag->pagf_init) { - error = xfs_alloc_pagf_init(mp, tp, ag, XFS_ALLOC_FLAG_TRYLOCK); - if (error) - goto out; - - if (!pag->pagf_init) { - *notinit = 1; - goto out; - } - } - - longest = xfs_alloc_longest_free_extent(mp, pag, - xfs_alloc_min_freelist(mp, pag), - xfs_ag_resv_needed(pag, XFS_AG_RESV_NONE)); - if (*blen < longest) - *blen = longest; - -out: - xfs_perag_put(pag); - return error; -} - -static void -xfs_bmap_select_minlen( - struct xfs_bmalloca *ap, - struct xfs_alloc_arg *args, - xfs_extlen_t *blen, - int notinit) -{ - if (notinit || *blen < ap->minlen) { - /* - * Since we did a BUF_TRYLOCK above, it is possible that - * there is space for this request. - */ - args->minlen = ap->minlen; - } else if (*blen < args->maxlen) { - /* - * If the best seen length is less than the request length, - * use the best as the minimum. - */ - args->minlen = *blen; - } else { - /* - * Otherwise we've seen an extent as big as maxlen, use that - * as the minimum. - */ - args->minlen = args->maxlen; - } -} - -STATIC int -xfs_bmap_btalloc_nullfb( - struct xfs_bmalloca *ap, - struct xfs_alloc_arg *args, - xfs_extlen_t *blen) -{ - struct xfs_mount *mp = ap->ip->i_mount; - xfs_agnumber_t ag, startag; - int notinit = 0; - int error; - - args->type = XFS_ALLOCTYPE_START_BNO; - args->total = ap->total; - - startag = ag = XFS_FSB_TO_AGNO(mp, args->fsbno); - if (startag == NULLAGNUMBER) - startag = ag = 0; - - while (*blen < args->maxlen) { - error = xfs_bmap_longest_free_extent(args->tp, ag, blen, - ¬init); - if (error) - return error; - - if (++ag == mp->m_sb.sb_agcount) - ag = 0; - if (ag == startag) - break; - } - - xfs_bmap_select_minlen(ap, args, blen, notinit); - return 0; -} - -STATIC int -xfs_bmap_btalloc_filestreams( - struct xfs_bmalloca *ap, - struct xfs_alloc_arg *args, - xfs_extlen_t *blen) -{ - struct xfs_mount *mp = ap->ip->i_mount; - xfs_agnumber_t ag; - int notinit = 0; - int error; - - args->type = XFS_ALLOCTYPE_NEAR_BNO; - args->total = ap->total; - - ag = XFS_FSB_TO_AGNO(mp, args->fsbno); - if (ag == NULLAGNUMBER) - ag = 0; - - error = xfs_bmap_longest_free_extent(args->tp, ag, blen, ¬init); - if (error) - return error; - - if (*blen < args->maxlen) { - error = xfs_filestream_new_ag(ap, &ag); - if (error) - return error; - - error = xfs_bmap_longest_free_extent(args->tp, ag, blen, - ¬init); - if (error) - return error; - - } - - xfs_bmap_select_minlen(ap, args, blen, notinit); - - /* - * Set the failure fallback case to look in the selected AG as stream - * may have moved. - */ - ap->blkno = args->fsbno = XFS_AGB_TO_FSB(mp, ag, 0); - return 0; -} - -STATIC int -xfs_bmap_btalloc( - struct xfs_bmalloca *ap) /* bmap alloc argument struct */ -{ - xfs_mount_t *mp; /* mount point structure */ - xfs_alloctype_t atype = 0; /* type for allocation routines */ - xfs_extlen_t align = 0; /* minimum allocation alignment */ - xfs_agnumber_t fb_agno; /* ag number of ap->firstblock */ - xfs_agnumber_t ag; - xfs_alloc_arg_t args; - xfs_extlen_t blen; - xfs_extlen_t nextminlen = 0; - int nullfb; /* true if ap->firstblock isn't set */ - int isaligned; - int tryagain; - int error; - int stripe_align; - - ASSERT(ap->length); - - mp = ap->ip->i_mount; - - /* stripe alignment for allocation is determined by mount parameters */ - stripe_align = 0; - if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC)) - stripe_align = mp->m_swidth; - else if (mp->m_dalign) - stripe_align = mp->m_dalign; - - if (ap->flags & XFS_BMAPI_COWFORK) - align = xfs_get_cowextsz_hint(ap->ip); - else if (xfs_alloc_is_userdata(ap->datatype)) - align = xfs_get_extsz_hint(ap->ip); - if (unlikely(align)) { - error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev, - align, 0, ap->eof, 0, ap->conv, - &ap->offset, &ap->length); - ASSERT(!error); - ASSERT(ap->length); - } - - - nullfb = *ap->firstblock == NULLFSBLOCK; - fb_agno = nullfb ? NULLAGNUMBER : XFS_FSB_TO_AGNO(mp, *ap->firstblock); - if (nullfb) { - if (xfs_alloc_is_userdata(ap->datatype) && - xfs_inode_is_filestream(ap->ip)) { - ag = xfs_filestream_lookup_ag(ap->ip); - ag = (ag != NULLAGNUMBER) ? ag : 0; - ap->blkno = XFS_AGB_TO_FSB(mp, ag, 0); - } else { - ap->blkno = XFS_INO_TO_FSB(mp, ap->ip->i_ino); - } - } else - ap->blkno = *ap->firstblock; - - xfs_bmap_adjacent(ap); - - /* - * If allowed, use ap->blkno; otherwise must use firstblock since - * it's in the right allocation group. - */ - if (nullfb || XFS_FSB_TO_AGNO(mp, ap->blkno) == fb_agno) - ; - else - ap->blkno = *ap->firstblock; - /* - * Normal allocation, done through xfs_alloc_vextent. - */ - tryagain = isaligned = 0; - memset(&args, 0, sizeof(args)); - args.tp = ap->tp; - args.mp = mp; - args.fsbno = ap->blkno; - xfs_rmap_skip_owner_update(&args.oinfo); - - /* Trim the allocation back to the maximum an AG can fit. */ - args.maxlen = MIN(ap->length, mp->m_ag_max_usable); - args.firstblock = *ap->firstblock; - blen = 0; - if (nullfb) { - /* - * Search for an allocation group with a single extent large - * enough for the request. If one isn't found, then adjust - * the minimum allocation size to the largest space found. - */ - if (xfs_alloc_is_userdata(ap->datatype) && - xfs_inode_is_filestream(ap->ip)) - error = xfs_bmap_btalloc_filestreams(ap, &args, &blen); - else - error = xfs_bmap_btalloc_nullfb(ap, &args, &blen); - if (error) - return error; - } else if (ap->dfops->dop_low) { - if (xfs_inode_is_filestream(ap->ip)) - args.type = XFS_ALLOCTYPE_FIRST_AG; - else - args.type = XFS_ALLOCTYPE_START_BNO; - args.total = args.minlen = ap->minlen; - } else { - args.type = XFS_ALLOCTYPE_NEAR_BNO; - args.total = ap->total; - args.minlen = ap->minlen; - } - /* apply extent size hints if obtained earlier */ - if (unlikely(align)) { - args.prod = align; - if ((args.mod = (xfs_extlen_t)do_mod(ap->offset, args.prod))) - args.mod = (xfs_extlen_t)(args.prod - args.mod); - } else if (mp->m_sb.sb_blocksize >= PAGE_SIZE) { - args.prod = 1; - args.mod = 0; - } else { - args.prod = PAGE_SIZE >> mp->m_sb.sb_blocklog; - if ((args.mod = (xfs_extlen_t)(do_mod(ap->offset, args.prod)))) - args.mod = (xfs_extlen_t)(args.prod - args.mod); - } - /* - * If we are not low on available data blocks, and the - * underlying logical volume manager is a stripe, and - * the file offset is zero then try to allocate data - * blocks on stripe unit boundary. - * NOTE: ap->aeof is only set if the allocation length - * is >= the stripe unit and the allocation offset is - * at the end of file. - */ - if (!ap->dfops->dop_low && ap->aeof) { - if (!ap->offset) { - args.alignment = stripe_align; - atype = args.type; - isaligned = 1; - /* - * Adjust for alignment - */ - if (blen > args.alignment && blen <= args.maxlen) - args.minlen = blen - args.alignment; - args.minalignslop = 0; - } else { - /* - * First try an exact bno allocation. - * If it fails then do a near or start bno - * allocation with alignment turned on. - */ - atype = args.type; - tryagain = 1; - args.type = XFS_ALLOCTYPE_THIS_BNO; - args.alignment = 1; - /* - * Compute the minlen+alignment for the - * next case. Set slop so that the value - * of minlen+alignment+slop doesn't go up - * between the calls. - */ - if (blen > stripe_align && blen <= args.maxlen) - nextminlen = blen - stripe_align; - else - nextminlen = args.minlen; - if (nextminlen + stripe_align > args.minlen + 1) - args.minalignslop = - nextminlen + stripe_align - - args.minlen - 1; - else - args.minalignslop = 0; - } - } else { - args.alignment = 1; - args.minalignslop = 0; - } - args.minleft = ap->minleft; - args.wasdel = ap->wasdel; - args.resv = XFS_AG_RESV_NONE; - args.datatype = ap->datatype; - if (ap->datatype & XFS_ALLOC_USERDATA_ZERO) - args.ip = ap->ip; - - error = xfs_alloc_vextent(&args); - if (error) - return error; - - if (tryagain && args.fsbno == NULLFSBLOCK) { - /* - * Exact allocation failed. Now try with alignment - * turned on. - */ - args.type = atype; - args.fsbno = ap->blkno; - args.alignment = stripe_align; - args.minlen = nextminlen; - args.minalignslop = 0; - isaligned = 1; - if ((error = xfs_alloc_vextent(&args))) - return error; - } - if (isaligned && args.fsbno == NULLFSBLOCK) { - /* - * allocation failed, so turn off alignment and - * try again. - */ - args.type = atype; - args.fsbno = ap->blkno; - args.alignment = 0; - if ((error = xfs_alloc_vextent(&args))) - return error; - } - if (args.fsbno == NULLFSBLOCK && nullfb && - args.minlen > ap->minlen) { - args.minlen = ap->minlen; - args.type = XFS_ALLOCTYPE_START_BNO; - args.fsbno = ap->blkno; - if ((error = xfs_alloc_vextent(&args))) - return error; - } - if (args.fsbno == NULLFSBLOCK && nullfb) { - args.fsbno = 0; - args.type = XFS_ALLOCTYPE_FIRST_AG; - args.total = ap->minlen; - args.minleft = 0; - if ((error = xfs_alloc_vextent(&args))) - return error; - ap->dfops->dop_low = true; - } - if (args.fsbno != NULLFSBLOCK) { - /* - * check the allocation happened at the same or higher AG than - * the first block that was allocated. - */ - ASSERT(*ap->firstblock == NULLFSBLOCK || - XFS_FSB_TO_AGNO(mp, *ap->firstblock) == - XFS_FSB_TO_AGNO(mp, args.fsbno) || - (ap->dfops->dop_low && - XFS_FSB_TO_AGNO(mp, *ap->firstblock) < - XFS_FSB_TO_AGNO(mp, args.fsbno))); - - ap->blkno = args.fsbno; - if (*ap->firstblock == NULLFSBLOCK) - *ap->firstblock = args.fsbno; - ASSERT(nullfb || fb_agno == args.agno || - (ap->dfops->dop_low && fb_agno < args.agno)); - ap->length = args.len; - if (!(ap->flags & XFS_BMAPI_COWFORK)) - ap->ip->i_d.di_nblocks += args.len; - xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE); - if (ap->wasdel) - ap->ip->i_delayed_blks -= args.len; - /* - * Adjust the disk quota also. This was reserved - * earlier. - */ - xfs_trans_mod_dquot_byino(ap->tp, ap->ip, - ap->wasdel ? XFS_TRANS_DQ_DELBCOUNT : - XFS_TRANS_DQ_BCOUNT, - (long) args.len); - } else { - ap->blkno = NULLFSBLOCK; - ap->length = 0; - } - return 0; -} - -/* - * For a remap operation, just "allocate" an extent at the address that the - * caller passed in, and ensure that the AGFL is the right size. The caller - * will then map the "allocated" extent into the file somewhere. - */ -STATIC int -xfs_bmap_remap_alloc( - struct xfs_bmalloca *ap) -{ - struct xfs_trans *tp = ap->tp; - struct xfs_mount *mp = tp->t_mountp; - xfs_agblock_t bno; - struct xfs_alloc_arg args; - int error; - - /* - * validate that the block number is legal - the enables us to detect - * and handle a silent filesystem corruption rather than crashing. - */ - memset(&args, 0, sizeof(struct xfs_alloc_arg)); - args.tp = ap->tp; - args.mp = ap->tp->t_mountp; - bno = *ap->firstblock; - args.agno = XFS_FSB_TO_AGNO(mp, bno); - args.agbno = XFS_FSB_TO_AGBNO(mp, bno); - if (args.agno >= mp->m_sb.sb_agcount || - args.agbno >= mp->m_sb.sb_agblocks) - return -EFSCORRUPTED; - - /* "Allocate" the extent from the range we passed in. */ - trace_xfs_bmap_remap_alloc(ap->ip, *ap->firstblock, ap->length); - ap->blkno = bno; - ap->ip->i_d.di_nblocks += ap->length; - xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE); - - /* Fix the freelist, like a real allocator does. */ - args.datatype = ap->datatype; - args.pag = xfs_perag_get(args.mp, args.agno); - ASSERT(args.pag); - - /* - * The freelist fixing code will decline the allocation if - * the size and shape of the free space doesn't allow for - * allocating the extent and updating all the metadata that - * happens during an allocation. We're remapping, not - * allocating, so skip that check by pretending to be freeing. - */ - error = xfs_alloc_fix_freelist(&args, XFS_ALLOC_FLAG_FREEING); - xfs_perag_put(args.pag); - if (error) - trace_xfs_bmap_remap_alloc_error(ap->ip, error, _RET_IP_); - return error; -} - -/* - * xfs_bmap_alloc is called by xfs_bmapi to allocate an extent for a file. - * It figures out where to ask the underlying allocator to put the new extent. - */ -STATIC int -xfs_bmap_alloc( - struct xfs_bmalloca *ap) /* bmap alloc argument struct */ -{ - if (ap->flags & XFS_BMAPI_REMAP) - return xfs_bmap_remap_alloc(ap); - if (XFS_IS_REALTIME_INODE(ap->ip) && - xfs_alloc_is_userdata(ap->datatype)) - return xfs_bmap_rtalloc(ap); - return xfs_bmap_btalloc(ap); -} - -/* Trim extent to fit a logical block range. */ -void -xfs_trim_extent( - struct xfs_bmbt_irec *irec, - xfs_fileoff_t bno, - xfs_filblks_t len) -{ - xfs_fileoff_t distance; - xfs_fileoff_t end = bno + len; - - if (irec->br_startoff + irec->br_blockcount <= bno || - irec->br_startoff >= end) { - irec->br_blockcount = 0; - return; - } - - if (irec->br_startoff < bno) { - distance = bno - irec->br_startoff; - if (isnullstartblock(irec->br_startblock)) - irec->br_startblock = DELAYSTARTBLOCK; - if (irec->br_startblock != DELAYSTARTBLOCK && - irec->br_startblock != HOLESTARTBLOCK) - irec->br_startblock += distance; - irec->br_startoff += distance; - irec->br_blockcount -= distance; - } - - if (end < irec->br_startoff + irec->br_blockcount) { - distance = irec->br_startoff + irec->br_blockcount - end; - irec->br_blockcount -= distance; - } -} - -/* - * Trim the returned map to the required bounds - */ -STATIC void -xfs_bmapi_trim_map( - struct xfs_bmbt_irec *mval, - struct xfs_bmbt_irec *got, - xfs_fileoff_t *bno, - xfs_filblks_t len, - xfs_fileoff_t obno, - xfs_fileoff_t end, - int n, - int flags) -{ - if ((flags & XFS_BMAPI_ENTIRE) || - got->br_startoff + got->br_blockcount <= obno) { - *mval = *got; - if (isnullstartblock(got->br_startblock)) - mval->br_startblock = DELAYSTARTBLOCK; - return; - } - - if (obno > *bno) - *bno = obno; - ASSERT((*bno >= obno) || (n == 0)); - ASSERT(*bno < end); - mval->br_startoff = *bno; - if (isnullstartblock(got->br_startblock)) - mval->br_startblock = DELAYSTARTBLOCK; - else - mval->br_startblock = got->br_startblock + - (*bno - got->br_startoff); - /* - * Return the minimum of what we got and what we asked for for - * the length. We can use the len variable here because it is - * modified below and we could have been there before coming - * here if the first part of the allocation didn't overlap what - * was asked for. - */ - mval->br_blockcount = XFS_FILBLKS_MIN(end - *bno, - got->br_blockcount - (*bno - got->br_startoff)); - mval->br_state = got->br_state; - ASSERT(mval->br_blockcount <= len); - return; -} - -/* - * Update and validate the extent map to return - */ -STATIC void -xfs_bmapi_update_map( - struct xfs_bmbt_irec **map, - xfs_fileoff_t *bno, - xfs_filblks_t *len, - xfs_fileoff_t obno, - xfs_fileoff_t end, - int *n, - int flags) -{ - xfs_bmbt_irec_t *mval = *map; - - ASSERT((flags & XFS_BMAPI_ENTIRE) || - ((mval->br_startoff + mval->br_blockcount) <= end)); - ASSERT((flags & XFS_BMAPI_ENTIRE) || (mval->br_blockcount <= *len) || - (mval->br_startoff < obno)); - - *bno = mval->br_startoff + mval->br_blockcount; - *len = end - *bno; - if (*n > 0 && mval->br_startoff == mval[-1].br_startoff) { - /* update previous map with new information */ - ASSERT(mval->br_startblock == mval[-1].br_startblock); - ASSERT(mval->br_blockcount > mval[-1].br_blockcount); - ASSERT(mval->br_state == mval[-1].br_state); - mval[-1].br_blockcount = mval->br_blockcount; - mval[-1].br_state = mval->br_state; - } else if (*n > 0 && mval->br_startblock != DELAYSTARTBLOCK && - mval[-1].br_startblock != DELAYSTARTBLOCK && - mval[-1].br_startblock != HOLESTARTBLOCK && - mval->br_startblock == mval[-1].br_startblock + - mval[-1].br_blockcount && - ((flags & XFS_BMAPI_IGSTATE) || - mval[-1].br_state == mval->br_state)) { - ASSERT(mval->br_startoff == - mval[-1].br_startoff + mval[-1].br_blockcount); - mval[-1].br_blockcount += mval->br_blockcount; - } else if (*n > 0 && - mval->br_startblock == DELAYSTARTBLOCK && - mval[-1].br_startblock == DELAYSTARTBLOCK && - mval->br_startoff == - mval[-1].br_startoff + mval[-1].br_blockcount) { - mval[-1].br_blockcount += mval->br_blockcount; - mval[-1].br_state = mval->br_state; - } else if (!((*n == 0) && - ((mval->br_startoff + mval->br_blockcount) <= - obno))) { - mval++; - (*n)++; - } - *map = mval; -} - -/* - * Map file blocks to filesystem blocks without allocation. - */ -int -xfs_bmapi_read( - struct xfs_inode *ip, - xfs_fileoff_t bno, - xfs_filblks_t len, - struct xfs_bmbt_irec *mval, - int *nmap, - int flags) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_ifork *ifp; - struct xfs_bmbt_irec got; - struct xfs_bmbt_irec prev; - xfs_fileoff_t obno; - xfs_fileoff_t end; - xfs_extnum_t lastx; - int error; - int eof; - int n = 0; - int whichfork = xfs_bmapi_whichfork(flags); - - ASSERT(*nmap >= 1); - ASSERT(!(flags & ~(XFS_BMAPI_ATTRFORK|XFS_BMAPI_ENTIRE| - XFS_BMAPI_IGSTATE|XFS_BMAPI_COWFORK))); - ASSERT(xfs_isilocked(ip, XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)); - - if (unlikely(XFS_TEST_ERROR( - (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && - XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE), - mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) { - XFS_ERROR_REPORT("xfs_bmapi_read", XFS_ERRLEVEL_LOW, mp); - return -EFSCORRUPTED; - } - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - XFS_STATS_INC(mp, xs_blk_mapr); - - ifp = XFS_IFORK_PTR(ip, whichfork); - - /* No CoW fork? Return a hole. */ - if (whichfork == XFS_COW_FORK && !ifp) { - mval->br_startoff = bno; - mval->br_startblock = HOLESTARTBLOCK; - mval->br_blockcount = len; - mval->br_state = XFS_EXT_NORM; - *nmap = 1; - return 0; - } - - if (!(ifp->if_flags & XFS_IFEXTENTS)) { - error = xfs_iread_extents(NULL, ip, whichfork); - if (error) - return error; - } - - xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, &prev); - end = bno + len; - obno = bno; - - while (bno < end && n < *nmap) { - /* Reading past eof, act as though there's a hole up to end. */ - if (eof) - got.br_startoff = end; - if (got.br_startoff > bno) { - /* Reading in a hole. */ - mval->br_startoff = bno; - mval->br_startblock = HOLESTARTBLOCK; - mval->br_blockcount = - XFS_FILBLKS_MIN(len, got.br_startoff - bno); - mval->br_state = XFS_EXT_NORM; - bno += mval->br_blockcount; - len -= mval->br_blockcount; - mval++; - n++; - continue; - } - - /* set up the extent map to return. */ - xfs_bmapi_trim_map(mval, &got, &bno, len, obno, end, n, flags); - xfs_bmapi_update_map(&mval, &bno, &len, obno, end, &n, flags); - - /* If we're done, stop now. */ - if (bno >= end || n >= *nmap) - break; - - /* Else go on to the next record. */ - if (++lastx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t)) - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, lastx), &got); - else - eof = 1; - } - *nmap = n; - return 0; -} - -int -xfs_bmapi_reserve_delalloc( - struct xfs_inode *ip, - int whichfork, - xfs_fileoff_t aoff, - xfs_filblks_t len, - struct xfs_bmbt_irec *got, - struct xfs_bmbt_irec *prev, - xfs_extnum_t *lastx, - int eof) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); - xfs_extlen_t alen; - xfs_extlen_t indlen; - char rt = XFS_IS_REALTIME_INODE(ip); - xfs_extlen_t extsz; - int error; - - alen = XFS_FILBLKS_MIN(len, MAXEXTLEN); - if (!eof) - alen = XFS_FILBLKS_MIN(alen, got->br_startoff - aoff); - - /* Figure out the extent size, adjust alen */ - if (whichfork == XFS_COW_FORK) - extsz = xfs_get_cowextsz_hint(ip); - else - extsz = xfs_get_extsz_hint(ip); - if (extsz) { - error = xfs_bmap_extsize_align(mp, got, prev, extsz, rt, eof, - 1, 0, &aoff, &alen); - ASSERT(!error); - } - - if (rt) - extsz = alen / mp->m_sb.sb_rextsize; - - /* - * Make a transaction-less quota reservation for delayed allocation - * blocks. This number gets adjusted later. We return if we haven't - * allocated blocks already inside this loop. - */ - error = xfs_trans_reserve_quota_nblks(NULL, ip, (long)alen, 0, - rt ? XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS); - if (error) - return error; - - /* - * Split changing sb for alen and indlen since they could be coming - * from different places. - */ - indlen = (xfs_extlen_t)xfs_bmap_worst_indlen(ip, alen); - ASSERT(indlen > 0); - - if (rt) { - error = xfs_mod_frextents(mp, -((int64_t)extsz)); - } else { - error = xfs_mod_fdblocks(mp, -((int64_t)alen), false); - } - - if (error) - goto out_unreserve_quota; - - error = xfs_mod_fdblocks(mp, -((int64_t)indlen), false); - if (error) - goto out_unreserve_blocks; - - - ip->i_delayed_blks += alen; - - got->br_startoff = aoff; - got->br_startblock = nullstartblock(indlen); - got->br_blockcount = alen; - got->br_state = XFS_EXT_NORM; - xfs_bmap_add_extent_hole_delay(ip, whichfork, lastx, got); - - /* - * Update our extent pointer, given that xfs_bmap_add_extent_hole_delay - * might have merged it into one of the neighbouring ones. - */ - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, *lastx), got); - - ASSERT(got->br_startoff <= aoff); - ASSERT(got->br_startoff + got->br_blockcount >= aoff + alen); - ASSERT(isnullstartblock(got->br_startblock)); - ASSERT(got->br_state == XFS_EXT_NORM); - return 0; - -out_unreserve_blocks: - if (rt) - xfs_mod_frextents(mp, extsz); - else - xfs_mod_fdblocks(mp, alen, false); -out_unreserve_quota: - if (XFS_IS_QUOTA_ON(mp)) - xfs_trans_unreserve_quota_nblks(NULL, ip, (long)alen, 0, rt ? - XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS); - return error; -} - -static int -xfs_bmapi_allocate( - struct xfs_bmalloca *bma) -{ - struct xfs_mount *mp = bma->ip->i_mount; - int whichfork = xfs_bmapi_whichfork(bma->flags); - struct xfs_ifork *ifp = XFS_IFORK_PTR(bma->ip, whichfork); - int tmp_logflags = 0; - int error; - - ASSERT(bma->length > 0); - - /* - * For the wasdelay case, we could also just allocate the stuff asked - * for in this bmap call but that wouldn't be as good. - */ - if (bma->wasdel) { - bma->length = (xfs_extlen_t)bma->got.br_blockcount; - bma->offset = bma->got.br_startoff; - if (bma->idx != NULLEXTNUM && bma->idx) { - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx - 1), - &bma->prev); - } - } else { - bma->length = XFS_FILBLKS_MIN(bma->length, MAXEXTLEN); - if (!bma->eof) - bma->length = XFS_FILBLKS_MIN(bma->length, - bma->got.br_startoff - bma->offset); - } - - /* - * Set the data type being allocated. For the data fork, the first data - * in the file is treated differently to all other allocations. For the - * attribute fork, we only need to ensure the allocated range is not on - * the busy list. - */ - if (!(bma->flags & XFS_BMAPI_METADATA)) { - bma->datatype = XFS_ALLOC_NOBUSY; - if (whichfork == XFS_DATA_FORK) { - if (bma->offset == 0) - bma->datatype |= XFS_ALLOC_INITIAL_USER_DATA; - else - bma->datatype |= XFS_ALLOC_USERDATA; - } - if (bma->flags & XFS_BMAPI_ZERO) - bma->datatype |= XFS_ALLOC_USERDATA_ZERO; - } - - bma->minlen = (bma->flags & XFS_BMAPI_CONTIG) ? bma->length : 1; - - /* - * Only want to do the alignment at the eof if it is userdata and - * allocation length is larger than a stripe unit. - */ - if (mp->m_dalign && bma->length >= mp->m_dalign && - !(bma->flags & XFS_BMAPI_METADATA) && whichfork == XFS_DATA_FORK) { - error = xfs_bmap_isaeof(bma, whichfork); - if (error) - return error; - } - - error = xfs_bmap_alloc(bma); - if (error) - return error; - - if (bma->dfops->dop_low) - bma->minleft = 0; - if (bma->cur) - bma->cur->bc_private.b.firstblock = *bma->firstblock; - if (bma->blkno == NULLFSBLOCK) - return 0; - if ((ifp->if_flags & XFS_IFBROOT) && !bma->cur) { - bma->cur = xfs_bmbt_init_cursor(mp, bma->tp, bma->ip, whichfork); - bma->cur->bc_private.b.firstblock = *bma->firstblock; - bma->cur->bc_private.b.dfops = bma->dfops; - } - /* - * Bump the number of extents we've allocated - * in this call. - */ - bma->nallocs++; - - if (bma->cur) - bma->cur->bc_private.b.flags = - bma->wasdel ? XFS_BTCUR_BPRV_WASDEL : 0; - - bma->got.br_startoff = bma->offset; - bma->got.br_startblock = bma->blkno; - bma->got.br_blockcount = bma->length; - bma->got.br_state = XFS_EXT_NORM; - - /* - * A wasdelay extent has been initialized, so shouldn't be flagged - * as unwritten. - */ - if (!bma->wasdel && (bma->flags & XFS_BMAPI_PREALLOC) && - xfs_sb_version_hasextflgbit(&mp->m_sb)) - bma->got.br_state = XFS_EXT_UNWRITTEN; - - if (bma->wasdel) - error = xfs_bmap_add_extent_delay_real(bma, whichfork); - else - error = xfs_bmap_add_extent_hole_real(bma, whichfork); - - bma->logflags |= tmp_logflags; - if (error) - return error; - - /* - * Update our extent pointer, given that xfs_bmap_add_extent_delay_real - * or xfs_bmap_add_extent_hole_real might have merged it into one of - * the neighbouring ones. - */ - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx), &bma->got); - - ASSERT(bma->got.br_startoff <= bma->offset); - ASSERT(bma->got.br_startoff + bma->got.br_blockcount >= - bma->offset + bma->length); - ASSERT(bma->got.br_state == XFS_EXT_NORM || - bma->got.br_state == XFS_EXT_UNWRITTEN); - return 0; -} - -STATIC int -xfs_bmapi_convert_unwritten( - struct xfs_bmalloca *bma, - struct xfs_bmbt_irec *mval, - xfs_filblks_t len, - int flags) -{ - int whichfork = xfs_bmapi_whichfork(flags); - struct xfs_ifork *ifp = XFS_IFORK_PTR(bma->ip, whichfork); - int tmp_logflags = 0; - int error; - - /* check if we need to do unwritten->real conversion */ - if (mval->br_state == XFS_EXT_UNWRITTEN && - (flags & XFS_BMAPI_PREALLOC)) - return 0; - - /* check if we need to do real->unwritten conversion */ - if (mval->br_state == XFS_EXT_NORM && - (flags & (XFS_BMAPI_PREALLOC | XFS_BMAPI_CONVERT)) != - (XFS_BMAPI_PREALLOC | XFS_BMAPI_CONVERT)) - return 0; - - ASSERT(whichfork != XFS_COW_FORK); - - /* - * Modify (by adding) the state flag, if writing. - */ - ASSERT(mval->br_blockcount <= len); - if ((ifp->if_flags & XFS_IFBROOT) && !bma->cur) { - bma->cur = xfs_bmbt_init_cursor(bma->ip->i_mount, bma->tp, - bma->ip, whichfork); - bma->cur->bc_private.b.firstblock = *bma->firstblock; - bma->cur->bc_private.b.dfops = bma->dfops; - } - mval->br_state = (mval->br_state == XFS_EXT_UNWRITTEN) - ? XFS_EXT_NORM : XFS_EXT_UNWRITTEN; - - /* - * Before insertion into the bmbt, zero the range being converted - * if required. - */ - if (flags & XFS_BMAPI_ZERO) { - error = xfs_zero_extent(bma->ip, mval->br_startblock, - mval->br_blockcount); - if (error) - return error; - } - - error = xfs_bmap_add_extent_unwritten_real(bma->tp, bma->ip, &bma->idx, - &bma->cur, mval, bma->firstblock, bma->dfops, - &tmp_logflags); - /* - * Log the inode core unconditionally in the unwritten extent conversion - * path because the conversion might not have done so (e.g., if the - * extent count hasn't changed). We need to make sure the inode is dirty - * in the transaction for the sake of fsync(), even if nothing has - * changed, because fsync() will not force the log for this transaction - * unless it sees the inode pinned. - */ - bma->logflags |= tmp_logflags | XFS_ILOG_CORE; - if (error) - return error; - - /* - * Update our extent pointer, given that - * xfs_bmap_add_extent_unwritten_real might have merged it into one - * of the neighbouring ones. - */ - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma->idx), &bma->got); - - /* - * We may have combined previously unwritten space with written space, - * so generate another request. - */ - if (mval->br_blockcount < len) - return -EAGAIN; - return 0; -} - -/* - * Map file blocks to filesystem blocks, and allocate blocks or convert the - * extent state if necessary. Details behaviour is controlled by the flags - * parameter. Only allocates blocks from a single allocation group, to avoid - * locking problems. - * - * The returned value in "firstblock" from the first call in a transaction - * must be remembered and presented to subsequent calls in "firstblock". - * An upper bound for the number of blocks to be allocated is supplied to - * the first call in "total"; if no allocation group has that many free - * blocks then the call will fail (return NULLFSBLOCK in "firstblock"). - */ -int -xfs_bmapi_write( - struct xfs_trans *tp, /* transaction pointer */ - struct xfs_inode *ip, /* incore inode */ - xfs_fileoff_t bno, /* starting file offs. mapped */ - xfs_filblks_t len, /* length to map in file */ - int flags, /* XFS_BMAPI_... */ - xfs_fsblock_t *firstblock, /* first allocated block - controls a.g. for allocs */ - xfs_extlen_t total, /* total blocks needed */ - struct xfs_bmbt_irec *mval, /* output: map values */ - int *nmap, /* i/o: mval size/count */ - struct xfs_defer_ops *dfops) /* i/o: list extents to free */ -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_ifork *ifp; - struct xfs_bmalloca bma = { NULL }; /* args for xfs_bmap_alloc */ - xfs_fileoff_t end; /* end of mapped file region */ - int eof; /* after the end of extents */ - int error; /* error return */ - int n; /* current extent index */ - xfs_fileoff_t obno; /* old block number (offset) */ - int whichfork; /* data or attr fork */ - char inhole; /* current location is hole in file */ - char wasdelay; /* old extent was delayed */ - -#ifdef DEBUG - xfs_fileoff_t orig_bno; /* original block number value */ - int orig_flags; /* original flags arg value */ - xfs_filblks_t orig_len; /* original value of len arg */ - struct xfs_bmbt_irec *orig_mval; /* original value of mval */ - int orig_nmap; /* original value of *nmap */ - - orig_bno = bno; - orig_len = len; - orig_flags = flags; - orig_mval = mval; - orig_nmap = *nmap; -#endif - whichfork = xfs_bmapi_whichfork(flags); - - ASSERT(*nmap >= 1); - ASSERT(*nmap <= XFS_BMAP_MAX_NMAP); - ASSERT(!(flags & XFS_BMAPI_IGSTATE)); - ASSERT(tp != NULL); - ASSERT(len > 0); - ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_LOCAL); - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - ASSERT(!(flags & XFS_BMAPI_REMAP) || whichfork == XFS_DATA_FORK); - ASSERT(!(flags & XFS_BMAPI_PREALLOC) || !(flags & XFS_BMAPI_REMAP)); - ASSERT(!(flags & XFS_BMAPI_CONVERT) || !(flags & XFS_BMAPI_REMAP)); - ASSERT(!(flags & XFS_BMAPI_PREALLOC) || whichfork != XFS_COW_FORK); - ASSERT(!(flags & XFS_BMAPI_CONVERT) || whichfork != XFS_COW_FORK); - - /* zeroing is for currently only for data extents, not metadata */ - ASSERT((flags & (XFS_BMAPI_METADATA | XFS_BMAPI_ZERO)) != - (XFS_BMAPI_METADATA | XFS_BMAPI_ZERO)); - /* - * we can allocate unwritten extents or pre-zero allocated blocks, - * but it makes no sense to do both at once. This would result in - * zeroing the unwritten extent twice, but it still being an - * unwritten extent.... - */ - ASSERT((flags & (XFS_BMAPI_PREALLOC | XFS_BMAPI_ZERO)) != - (XFS_BMAPI_PREALLOC | XFS_BMAPI_ZERO)); - - if (unlikely(XFS_TEST_ERROR( - (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && - XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE), - mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) { - XFS_ERROR_REPORT("xfs_bmapi_write", XFS_ERRLEVEL_LOW, mp); - return -EFSCORRUPTED; - } - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - ifp = XFS_IFORK_PTR(ip, whichfork); - - XFS_STATS_INC(mp, xs_blk_mapw); - - if (*firstblock == NULLFSBLOCK) { - if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE) - bma.minleft = be16_to_cpu(ifp->if_broot->bb_level) + 1; - else - bma.minleft = 1; - } else { - bma.minleft = 0; - } - - if (!(ifp->if_flags & XFS_IFEXTENTS)) { - error = xfs_iread_extents(tp, ip, whichfork); - if (error) - goto error0; - } - - xfs_bmap_search_extents(ip, bno, whichfork, &eof, &bma.idx, &bma.got, - &bma.prev); - n = 0; - end = bno + len; - obno = bno; - - bma.tp = tp; - bma.ip = ip; - bma.total = total; - bma.datatype = 0; - bma.dfops = dfops; - bma.firstblock = firstblock; - - while (bno < end && n < *nmap) { - inhole = eof || bma.got.br_startoff > bno; - wasdelay = !inhole && isnullstartblock(bma.got.br_startblock); - - /* - * Make sure we only reflink into a hole. - */ - if (flags & XFS_BMAPI_REMAP) - ASSERT(inhole); - if (flags & XFS_BMAPI_COWFORK) - ASSERT(!inhole); - - /* - * First, deal with the hole before the allocated space - * that we found, if any. - */ - if (inhole || wasdelay) { - bma.eof = eof; - bma.conv = !!(flags & XFS_BMAPI_CONVERT); - bma.wasdel = wasdelay; - bma.offset = bno; - bma.flags = flags; - - /* - * There's a 32/64 bit type mismatch between the - * allocation length request (which can be 64 bits in - * length) and the bma length request, which is - * xfs_extlen_t and therefore 32 bits. Hence we have to - * check for 32-bit overflows and handle them here. - */ - if (len > (xfs_filblks_t)MAXEXTLEN) - bma.length = MAXEXTLEN; - else - bma.length = len; - - ASSERT(len > 0); - ASSERT(bma.length > 0); - error = xfs_bmapi_allocate(&bma); - if (error) - goto error0; - if (bma.blkno == NULLFSBLOCK) - break; - - /* - * If this is a CoW allocation, record the data in - * the refcount btree for orphan recovery. - */ - if (whichfork == XFS_COW_FORK) { - error = xfs_refcount_alloc_cow_extent(mp, dfops, - bma.blkno, bma.length); - if (error) - goto error0; - } - } - - /* Deal with the allocated space we found. */ - xfs_bmapi_trim_map(mval, &bma.got, &bno, len, obno, - end, n, flags); - - /* Execute unwritten extent conversion if necessary */ - error = xfs_bmapi_convert_unwritten(&bma, mval, len, flags); - if (error == -EAGAIN) - continue; - if (error) - goto error0; - - /* update the extent map to return */ - xfs_bmapi_update_map(&mval, &bno, &len, obno, end, &n, flags); - - /* - * If we're done, stop now. Stop when we've allocated - * XFS_BMAP_MAX_NMAP extents no matter what. Otherwise - * the transaction may get too big. - */ - if (bno >= end || n >= *nmap || bma.nallocs >= *nmap) - break; - - /* Else go on to the next record. */ - bma.prev = bma.got; - if (++bma.idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t)) { - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, bma.idx), - &bma.got); - } else - eof = 1; - } - *nmap = n; - - /* - * Transform from btree to extents, give it cur. - */ - if (xfs_bmap_wants_extents(ip, whichfork)) { - int tmp_logflags = 0; - - ASSERT(bma.cur); - error = xfs_bmap_btree_to_extents(tp, ip, bma.cur, - &tmp_logflags, whichfork); - bma.logflags |= tmp_logflags; - if (error) - goto error0; - } - - ASSERT(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE || - XFS_IFORK_NEXTENTS(ip, whichfork) > - XFS_IFORK_MAXEXT(ip, whichfork)); - error = 0; -error0: - /* - * Log everything. Do this after conversion, there's no point in - * logging the extent records if we've converted to btree format. - */ - if ((bma.logflags & xfs_ilog_fext(whichfork)) && - XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) - bma.logflags &= ~xfs_ilog_fext(whichfork); - else if ((bma.logflags & xfs_ilog_fbroot(whichfork)) && - XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) - bma.logflags &= ~xfs_ilog_fbroot(whichfork); - /* - * Log whatever the flags say, even if error. Otherwise we might miss - * detecting a case where the data is changed, there's an error, - * and it's not logged so we don't shutdown when we should. - */ - if (bma.logflags) - xfs_trans_log_inode(tp, ip, bma.logflags); - - if (bma.cur) { - if (!error) { - ASSERT(*firstblock == NULLFSBLOCK || - XFS_FSB_TO_AGNO(mp, *firstblock) == - XFS_FSB_TO_AGNO(mp, - bma.cur->bc_private.b.firstblock) || - (dfops->dop_low && - XFS_FSB_TO_AGNO(mp, *firstblock) < - XFS_FSB_TO_AGNO(mp, - bma.cur->bc_private.b.firstblock))); - *firstblock = bma.cur->bc_private.b.firstblock; - } - xfs_btree_del_cursor(bma.cur, - error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); - } - if (!error) - xfs_bmap_validate_ret(orig_bno, orig_len, orig_flags, orig_mval, - orig_nmap, *nmap); - return error; -} - -/* - * When a delalloc extent is split (e.g., due to a hole punch), the original - * indlen reservation must be shared across the two new extents that are left - * behind. - * - * Given the original reservation and the worst case indlen for the two new - * extents (as calculated by xfs_bmap_worst_indlen()), split the original - * reservation fairly across the two new extents. If necessary, steal available - * blocks from a deleted extent to make up a reservation deficiency (e.g., if - * ores == 1). The number of stolen blocks is returned. The availability and - * subsequent accounting of stolen blocks is the responsibility of the caller. - */ -static xfs_filblks_t -xfs_bmap_split_indlen( - xfs_filblks_t ores, /* original res. */ - xfs_filblks_t *indlen1, /* ext1 worst indlen */ - xfs_filblks_t *indlen2, /* ext2 worst indlen */ - xfs_filblks_t avail) /* stealable blocks */ -{ - xfs_filblks_t len1 = *indlen1; - xfs_filblks_t len2 = *indlen2; - xfs_filblks_t nres = len1 + len2; /* new total res. */ - xfs_filblks_t stolen = 0; - - /* - * Steal as many blocks as we can to try and satisfy the worst case - * indlen for both new extents. - */ - while (nres > ores && avail) { - nres--; - avail--; - stolen++; - } - - /* - * The only blocks available are those reserved for the original - * extent and what we can steal from the extent being removed. - * If this still isn't enough to satisfy the combined - * requirements for the two new extents, skim blocks off of each - * of the new reservations until they match what is available. - */ - while (nres > ores) { - if (len1) { - len1--; - nres--; - } - if (nres == ores) - break; - if (len2) { - len2--; - nres--; - } - } - - *indlen1 = len1; - *indlen2 = len2; - - return stolen; -} - -int -xfs_bmap_del_extent_delay( - struct xfs_inode *ip, - int whichfork, - xfs_extnum_t *idx, - struct xfs_bmbt_irec *got, - struct xfs_bmbt_irec *del) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); - struct xfs_bmbt_irec new; - int64_t da_old, da_new, da_diff = 0; - xfs_fileoff_t del_endoff, got_endoff; - xfs_filblks_t got_indlen, new_indlen, stolen; - int error = 0, state = 0; - bool isrt; - - XFS_STATS_INC(mp, xs_del_exlist); - - isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip); - del_endoff = del->br_startoff + del->br_blockcount; - got_endoff = got->br_startoff + got->br_blockcount; - da_old = startblockval(got->br_startblock); - da_new = 0; - - ASSERT(*idx >= 0); - ASSERT(*idx < ifp->if_bytes / sizeof(struct xfs_bmbt_rec)); - ASSERT(del->br_blockcount > 0); - ASSERT(got->br_startoff <= del->br_startoff); - ASSERT(got_endoff >= del_endoff); - - if (isrt) { - int64_t rtexts = XFS_FSB_TO_B(mp, del->br_blockcount); - - do_div(rtexts, mp->m_sb.sb_rextsize); - xfs_mod_frextents(mp, rtexts); - } - - /* - * Update the inode delalloc counter now and wait to update the - * sb counters as we might have to borrow some blocks for the - * indirect block accounting. - */ - xfs_trans_reserve_quota_nblks(NULL, ip, -((long)del->br_blockcount), 0, - isrt ? XFS_QMOPT_RES_RTBLKS : XFS_QMOPT_RES_REGBLKS); - ip->i_delayed_blks -= del->br_blockcount; - - if (whichfork == XFS_COW_FORK) - state |= BMAP_COWFORK; - - if (got->br_startoff == del->br_startoff) - state |= BMAP_LEFT_CONTIG; - if (got_endoff == del_endoff) - state |= BMAP_RIGHT_CONTIG; - - switch (state & (BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG)) { - case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: - /* - * Matches the whole extent. Delete the entry. - */ - xfs_iext_remove(ip, *idx, 1, state); - --*idx; - break; - case BMAP_LEFT_CONTIG: - /* - * Deleting the first part of the extent. - */ - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - got->br_startoff = del_endoff; - got->br_blockcount -= del->br_blockcount; - da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, - got->br_blockcount), da_old); - got->br_startblock = nullstartblock((int)da_new); - xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - break; - case BMAP_RIGHT_CONTIG: - /* - * Deleting the last part of the extent. - */ - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - got->br_blockcount = got->br_blockcount - del->br_blockcount; - da_new = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, - got->br_blockcount), da_old); - got->br_startblock = nullstartblock((int)da_new); - xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - break; - case 0: - /* - * Deleting the middle of the extent. - * - * Distribute the original indlen reservation across the two new - * extents. Steal blocks from the deleted extent if necessary. - * Stealing blocks simply fudges the fdblocks accounting below. - * Warn if either of the new indlen reservations is zero as this - * can lead to delalloc problems. - */ - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - - got->br_blockcount = del->br_startoff - got->br_startoff; - got_indlen = xfs_bmap_worst_indlen(ip, got->br_blockcount); - - new.br_blockcount = got_endoff - del_endoff; - new_indlen = xfs_bmap_worst_indlen(ip, new.br_blockcount); - - WARN_ON_ONCE(!got_indlen || !new_indlen); - stolen = xfs_bmap_split_indlen(da_old, &got_indlen, &new_indlen, - del->br_blockcount); - - got->br_startblock = nullstartblock((int)got_indlen); - xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got); - trace_xfs_bmap_post_update(ip, *idx, 0, _THIS_IP_); - - new.br_startoff = del_endoff; - new.br_state = got->br_state; - new.br_startblock = nullstartblock((int)new_indlen); - - ++*idx; - xfs_iext_insert(ip, *idx, 1, &new, state); - - da_new = got_indlen + new_indlen - stolen; - del->br_blockcount -= stolen; - break; - } - - ASSERT(da_old >= da_new); - da_diff = da_old - da_new; - if (!isrt) - da_diff += del->br_blockcount; - if (da_diff) - xfs_mod_fdblocks(mp, da_diff, false); - return error; -} - -void -xfs_bmap_del_extent_cow( - struct xfs_inode *ip, - xfs_extnum_t *idx, - struct xfs_bmbt_irec *got, - struct xfs_bmbt_irec *del) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); - struct xfs_bmbt_irec new; - xfs_fileoff_t del_endoff, got_endoff; - int state = BMAP_COWFORK; - - XFS_STATS_INC(mp, xs_del_exlist); - - del_endoff = del->br_startoff + del->br_blockcount; - got_endoff = got->br_startoff + got->br_blockcount; - - ASSERT(*idx >= 0); - ASSERT(*idx < ifp->if_bytes / sizeof(struct xfs_bmbt_rec)); - ASSERT(del->br_blockcount > 0); - ASSERT(got->br_startoff <= del->br_startoff); - ASSERT(got_endoff >= del_endoff); - ASSERT(!isnullstartblock(got->br_startblock)); - - if (got->br_startoff == del->br_startoff) - state |= BMAP_LEFT_CONTIG; - if (got_endoff == del_endoff) - state |= BMAP_RIGHT_CONTIG; - - switch (state & (BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG)) { - case BMAP_LEFT_CONTIG | BMAP_RIGHT_CONTIG: - /* - * Matches the whole extent. Delete the entry. - */ - xfs_iext_remove(ip, *idx, 1, state); - --*idx; - break; - case BMAP_LEFT_CONTIG: - /* - * Deleting the first part of the extent. - */ - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - got->br_startoff = del_endoff; - got->br_blockcount -= del->br_blockcount; - got->br_startblock = del->br_startblock + del->br_blockcount; - xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - break; - case BMAP_RIGHT_CONTIG: - /* - * Deleting the last part of the extent. - */ - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - got->br_blockcount -= del->br_blockcount; - xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - break; - case 0: - /* - * Deleting the middle of the extent. - */ - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - got->br_blockcount = del->br_startoff - got->br_startoff; - xfs_bmbt_set_all(xfs_iext_get_ext(ifp, *idx), got); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - - new.br_startoff = del_endoff; - new.br_blockcount = got_endoff - del_endoff; - new.br_state = got->br_state; - new.br_startblock = del->br_startblock + del->br_blockcount; - - ++*idx; - xfs_iext_insert(ip, *idx, 1, &new, state); - break; - } -} - -/* - * Called by xfs_bmapi to update file extent records and the btree - * after removing space (or undoing a delayed allocation). - */ -STATIC int /* error */ -xfs_bmap_del_extent( - xfs_inode_t *ip, /* incore inode pointer */ - xfs_trans_t *tp, /* current transaction pointer */ - xfs_extnum_t *idx, /* extent number to update/delete */ - struct xfs_defer_ops *dfops, /* list of extents to be freed */ - xfs_btree_cur_t *cur, /* if null, not a btree */ - xfs_bmbt_irec_t *del, /* data to remove from extents */ - int *logflagsp, /* inode logging flags */ - int whichfork, /* data or attr fork */ - int bflags) /* bmapi flags */ -{ - xfs_filblks_t da_new; /* new delay-alloc indirect blocks */ - xfs_filblks_t da_old; /* old delay-alloc indirect blocks */ - xfs_fsblock_t del_endblock=0; /* first block past del */ - xfs_fileoff_t del_endoff; /* first offset past del */ - int delay; /* current block is delayed allocated */ - int do_fx; /* free extent at end of routine */ - xfs_bmbt_rec_host_t *ep; /* current extent entry pointer */ - int error; /* error return value */ - int flags; /* inode logging flags */ - xfs_bmbt_irec_t got; /* current extent entry */ - xfs_fileoff_t got_endoff; /* first offset past got */ - int i; /* temp state */ - xfs_ifork_t *ifp; /* inode fork pointer */ - xfs_mount_t *mp; /* mount structure */ - xfs_filblks_t nblks; /* quota/sb block count */ - xfs_bmbt_irec_t new; /* new record to be inserted */ - /* REFERENCED */ - uint qfield; /* quota field to update */ - xfs_filblks_t temp; /* for indirect length calculations */ - xfs_filblks_t temp2; /* for indirect length calculations */ - int state = 0; - - mp = ip->i_mount; - XFS_STATS_INC(mp, xs_del_exlist); - - if (whichfork == XFS_ATTR_FORK) - state |= BMAP_ATTRFORK; - else if (whichfork == XFS_COW_FORK) - state |= BMAP_COWFORK; - - ifp = XFS_IFORK_PTR(ip, whichfork); - ASSERT((*idx >= 0) && (*idx < ifp->if_bytes / - (uint)sizeof(xfs_bmbt_rec_t))); - ASSERT(del->br_blockcount > 0); - ep = xfs_iext_get_ext(ifp, *idx); - xfs_bmbt_get_all(ep, &got); - ASSERT(got.br_startoff <= del->br_startoff); - del_endoff = del->br_startoff + del->br_blockcount; - got_endoff = got.br_startoff + got.br_blockcount; - ASSERT(got_endoff >= del_endoff); - delay = isnullstartblock(got.br_startblock); - ASSERT(isnullstartblock(del->br_startblock) == delay); - flags = 0; - qfield = 0; - error = 0; - /* - * If deleting a real allocation, must free up the disk space. - */ - if (!delay) { - flags = XFS_ILOG_CORE; - /* - * Realtime allocation. Free it and record di_nblocks update. - */ - if (whichfork == XFS_DATA_FORK && XFS_IS_REALTIME_INODE(ip)) { - xfs_fsblock_t bno; - xfs_filblks_t len; - - ASSERT(do_mod(del->br_blockcount, - mp->m_sb.sb_rextsize) == 0); - ASSERT(do_mod(del->br_startblock, - mp->m_sb.sb_rextsize) == 0); - bno = del->br_startblock; - len = del->br_blockcount; - do_div(bno, mp->m_sb.sb_rextsize); - do_div(len, mp->m_sb.sb_rextsize); - error = xfs_rtfree_extent(tp, bno, (xfs_extlen_t)len); - if (error) - goto done; - do_fx = 0; - nblks = len * mp->m_sb.sb_rextsize; - qfield = XFS_TRANS_DQ_RTBCOUNT; - } - /* - * Ordinary allocation. - */ - else { - do_fx = 1; - nblks = del->br_blockcount; - qfield = XFS_TRANS_DQ_BCOUNT; - } - /* - * Set up del_endblock and cur for later. - */ - del_endblock = del->br_startblock + del->br_blockcount; - if (cur) { - if ((error = xfs_bmbt_lookup_eq(cur, got.br_startoff, - got.br_startblock, got.br_blockcount, - &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - } - da_old = da_new = 0; - } else { - da_old = startblockval(got.br_startblock); - da_new = 0; - nblks = 0; - do_fx = 0; - } - - /* - * Set flag value to use in switch statement. - * Left-contig is 2, right-contig is 1. - */ - switch (((got.br_startoff == del->br_startoff) << 1) | - (got_endoff == del_endoff)) { - case 3: - /* - * Matches the whole extent. Delete the entry. - */ - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - xfs_iext_remove(ip, *idx, 1, - whichfork == XFS_ATTR_FORK ? BMAP_ATTRFORK : 0); - --*idx; - if (delay) - break; - - XFS_IFORK_NEXT_SET(ip, whichfork, - XFS_IFORK_NEXTENTS(ip, whichfork) - 1); - flags |= XFS_ILOG_CORE; - if (!cur) { - flags |= xfs_ilog_fext(whichfork); - break; - } - if ((error = xfs_btree_delete(cur, &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - break; - - case 2: - /* - * Deleting the first part of the extent. - */ - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - xfs_bmbt_set_startoff(ep, del_endoff); - temp = got.br_blockcount - del->br_blockcount; - xfs_bmbt_set_blockcount(ep, temp); - if (delay) { - temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), - da_old); - xfs_bmbt_set_startblock(ep, nullstartblock((int)temp)); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - da_new = temp; - break; - } - xfs_bmbt_set_startblock(ep, del_endblock); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - if (!cur) { - flags |= xfs_ilog_fext(whichfork); - break; - } - if ((error = xfs_bmbt_update(cur, del_endoff, del_endblock, - got.br_blockcount - del->br_blockcount, - got.br_state))) - goto done; - break; - - case 1: - /* - * Deleting the last part of the extent. - */ - temp = got.br_blockcount - del->br_blockcount; - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - xfs_bmbt_set_blockcount(ep, temp); - if (delay) { - temp = XFS_FILBLKS_MIN(xfs_bmap_worst_indlen(ip, temp), - da_old); - xfs_bmbt_set_startblock(ep, nullstartblock((int)temp)); - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - da_new = temp; - break; - } - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - if (!cur) { - flags |= xfs_ilog_fext(whichfork); - break; - } - if ((error = xfs_bmbt_update(cur, got.br_startoff, - got.br_startblock, - got.br_blockcount - del->br_blockcount, - got.br_state))) - goto done; - break; - - case 0: - /* - * Deleting the middle of the extent. - */ - temp = del->br_startoff - got.br_startoff; - trace_xfs_bmap_pre_update(ip, *idx, state, _THIS_IP_); - xfs_bmbt_set_blockcount(ep, temp); - new.br_startoff = del_endoff; - temp2 = got_endoff - del_endoff; - new.br_blockcount = temp2; - new.br_state = got.br_state; - if (!delay) { - new.br_startblock = del_endblock; - flags |= XFS_ILOG_CORE; - if (cur) { - if ((error = xfs_bmbt_update(cur, - got.br_startoff, - got.br_startblock, temp, - got.br_state))) - goto done; - if ((error = xfs_btree_increment(cur, 0, &i))) - goto done; - cur->bc_rec.b = new; - error = xfs_btree_insert(cur, &i); - if (error && error != -ENOSPC) - goto done; - /* - * If get no-space back from btree insert, - * it tried a split, and we have a zero - * block reservation. - * Fix up our state and return the error. - */ - if (error == -ENOSPC) { - /* - * Reset the cursor, don't trust - * it after any insert operation. - */ - if ((error = xfs_bmbt_lookup_eq(cur, - got.br_startoff, - got.br_startblock, - temp, &i))) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, - i == 1, done); - /* - * Update the btree record back - * to the original value. - */ - if ((error = xfs_bmbt_update(cur, - got.br_startoff, - got.br_startblock, - got.br_blockcount, - got.br_state))) - goto done; - /* - * Reset the extent record back - * to the original value. - */ - xfs_bmbt_set_blockcount(ep, - got.br_blockcount); - flags = 0; - error = -ENOSPC; - goto done; - } - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - } else - flags |= xfs_ilog_fext(whichfork); - XFS_IFORK_NEXT_SET(ip, whichfork, - XFS_IFORK_NEXTENTS(ip, whichfork) + 1); - } else { - xfs_filblks_t stolen; - ASSERT(whichfork == XFS_DATA_FORK); - - /* - * Distribute the original indlen reservation across the - * two new extents. Steal blocks from the deleted extent - * if necessary. Stealing blocks simply fudges the - * fdblocks accounting in xfs_bunmapi(). - */ - temp = xfs_bmap_worst_indlen(ip, got.br_blockcount); - temp2 = xfs_bmap_worst_indlen(ip, new.br_blockcount); - stolen = xfs_bmap_split_indlen(da_old, &temp, &temp2, - del->br_blockcount); - da_new = temp + temp2 - stolen; - del->br_blockcount -= stolen; - - /* - * Set the reservation for each extent. Warn if either - * is zero as this can lead to delalloc problems. - */ - WARN_ON_ONCE(!temp || !temp2); - xfs_bmbt_set_startblock(ep, nullstartblock((int)temp)); - new.br_startblock = nullstartblock((int)temp2); - } - trace_xfs_bmap_post_update(ip, *idx, state, _THIS_IP_); - xfs_iext_insert(ip, *idx + 1, 1, &new, state); - ++*idx; - break; - } - - /* remove reverse mapping */ - if (!delay) { - error = xfs_rmap_unmap_extent(mp, dfops, ip, whichfork, del); - if (error) - goto done; - } - - /* - * If we need to, add to list of extents to delete. - */ - if (do_fx && !(bflags & XFS_BMAPI_REMAP)) { - if (xfs_is_reflink_inode(ip) && whichfork == XFS_DATA_FORK) { - error = xfs_refcount_decrease_extent(mp, dfops, del); - if (error) - goto done; - } else - xfs_bmap_add_free(mp, dfops, del->br_startblock, - del->br_blockcount, NULL); - } - - /* - * Adjust inode # blocks in the file. - */ - if (nblks) - ip->i_d.di_nblocks -= nblks; - /* - * Adjust quota data. - */ - if (qfield && !(bflags & XFS_BMAPI_REMAP)) - xfs_trans_mod_dquot_byino(tp, ip, qfield, (long)-nblks); - - /* - * Account for change in delayed indirect blocks. - * Nothing to do for disk quota accounting here. - */ - ASSERT(da_old >= da_new); - if (da_old > da_new) - xfs_mod_fdblocks(mp, (int64_t)(da_old - da_new), false); -done: - *logflagsp = flags; - return error; -} - -/* - * Unmap (remove) blocks from a file. - * If nexts is nonzero then the number of extents to remove is limited to - * that value. If not all extents in the block range can be removed then - * *done is set. - */ -int /* error */ -__xfs_bunmapi( - xfs_trans_t *tp, /* transaction pointer */ - struct xfs_inode *ip, /* incore inode */ - xfs_fileoff_t bno, /* starting offset to unmap */ - xfs_filblks_t *rlen, /* i/o: amount remaining */ - int flags, /* misc flags */ - xfs_extnum_t nexts, /* number of extents max */ - xfs_fsblock_t *firstblock, /* first allocated block - controls a.g. for allocs */ - struct xfs_defer_ops *dfops) /* i/o: deferred updates */ -{ - xfs_btree_cur_t *cur; /* bmap btree cursor */ - xfs_bmbt_irec_t del; /* extent being deleted */ - int eof; /* is deleting at eof */ - xfs_bmbt_rec_host_t *ep; /* extent record pointer */ - int error; /* error return value */ - xfs_extnum_t extno; /* extent number in list */ - xfs_bmbt_irec_t got; /* current extent record */ - xfs_ifork_t *ifp; /* inode fork pointer */ - int isrt; /* freeing in rt area */ - xfs_extnum_t lastx; /* last extent index used */ - int logflags; /* transaction logging flags */ - xfs_extlen_t mod; /* rt extent offset */ - xfs_mount_t *mp; /* mount structure */ - xfs_extnum_t nextents; /* number of file extents */ - xfs_bmbt_irec_t prev; /* previous extent record */ - xfs_fileoff_t start; /* first file offset deleted */ - int tmp_logflags; /* partial logging flags */ - int wasdel; /* was a delayed alloc extent */ - int whichfork; /* data or attribute fork */ - xfs_fsblock_t sum; - xfs_filblks_t len = *rlen; /* length to unmap in file */ - - trace_xfs_bunmap(ip, bno, len, flags, _RET_IP_); - - whichfork = xfs_bmapi_whichfork(flags); - ASSERT(whichfork != XFS_COW_FORK); - ifp = XFS_IFORK_PTR(ip, whichfork); - if (unlikely( - XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && - XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) { - XFS_ERROR_REPORT("xfs_bunmapi", XFS_ERRLEVEL_LOW, - ip->i_mount); - return -EFSCORRUPTED; - } - mp = ip->i_mount; - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - ASSERT(len > 0); - ASSERT(nexts >= 0); - - if (!(ifp->if_flags & XFS_IFEXTENTS) && - (error = xfs_iread_extents(tp, ip, whichfork))) - return error; - nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); - if (nextents == 0) { - *rlen = 0; - return 0; - } - XFS_STATS_INC(mp, xs_blk_unmap); - isrt = (whichfork == XFS_DATA_FORK) && XFS_IS_REALTIME_INODE(ip); - start = bno; - bno = start + len - 1; - ep = xfs_bmap_search_extents(ip, bno, whichfork, &eof, &lastx, &got, - &prev); - - /* - * Check to see if the given block number is past the end of the - * file, back up to the last block if so... - */ - if (eof) { - ep = xfs_iext_get_ext(ifp, --lastx); - xfs_bmbt_get_all(ep, &got); - bno = got.br_startoff + got.br_blockcount - 1; - } - logflags = 0; - if (ifp->if_flags & XFS_IFBROOT) { - ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_BTREE); - cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); - cur->bc_private.b.firstblock = *firstblock; - cur->bc_private.b.dfops = dfops; - cur->bc_private.b.flags = 0; - } else - cur = NULL; - - if (isrt) { - /* - * Synchronize by locking the bitmap inode. - */ - xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL|XFS_ILOCK_RTBITMAP); - xfs_trans_ijoin(tp, mp->m_rbmip, XFS_ILOCK_EXCL); - xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL|XFS_ILOCK_RTSUM); - xfs_trans_ijoin(tp, mp->m_rsumip, XFS_ILOCK_EXCL); - } - - extno = 0; - while (bno != (xfs_fileoff_t)-1 && bno >= start && lastx >= 0 && - (nexts == 0 || extno < nexts)) { - /* - * Is the found extent after a hole in which bno lives? - * Just back up to the previous extent, if so. - */ - if (got.br_startoff > bno) { - if (--lastx < 0) - break; - ep = xfs_iext_get_ext(ifp, lastx); - xfs_bmbt_get_all(ep, &got); - } - /* - * Is the last block of this extent before the range - * we're supposed to delete? If so, we're done. - */ - bno = XFS_FILEOFF_MIN(bno, - got.br_startoff + got.br_blockcount - 1); - if (bno < start) - break; - /* - * Then deal with the (possibly delayed) allocated space - * we found. - */ - ASSERT(ep != NULL); - del = got; - wasdel = isnullstartblock(del.br_startblock); - if (got.br_startoff < start) { - del.br_startoff = start; - del.br_blockcount -= start - got.br_startoff; - if (!wasdel) - del.br_startblock += start - got.br_startoff; - } - if (del.br_startoff + del.br_blockcount > bno + 1) - del.br_blockcount = bno + 1 - del.br_startoff; - sum = del.br_startblock + del.br_blockcount; - if (isrt && - (mod = do_mod(sum, mp->m_sb.sb_rextsize))) { - /* - * Realtime extent not lined up at the end. - * The extent could have been split into written - * and unwritten pieces, or we could just be - * unmapping part of it. But we can't really - * get rid of part of a realtime extent. - */ - if (del.br_state == XFS_EXT_UNWRITTEN || - !xfs_sb_version_hasextflgbit(&mp->m_sb)) { - /* - * This piece is unwritten, or we're not - * using unwritten extents. Skip over it. - */ - ASSERT(bno >= mod); - bno -= mod > del.br_blockcount ? - del.br_blockcount : mod; - if (bno < got.br_startoff) { - if (--lastx >= 0) - xfs_bmbt_get_all(xfs_iext_get_ext( - ifp, lastx), &got); - } - continue; - } - /* - * It's written, turn it unwritten. - * This is better than zeroing it. - */ - ASSERT(del.br_state == XFS_EXT_NORM); - ASSERT(tp->t_blk_res > 0); - /* - * If this spans a realtime extent boundary, - * chop it back to the start of the one we end at. - */ - if (del.br_blockcount > mod) { - del.br_startoff += del.br_blockcount - mod; - del.br_startblock += del.br_blockcount - mod; - del.br_blockcount = mod; - } - del.br_state = XFS_EXT_UNWRITTEN; - error = xfs_bmap_add_extent_unwritten_real(tp, ip, - &lastx, &cur, &del, firstblock, dfops, - &logflags); - if (error) - goto error0; - goto nodelete; - } - if (isrt && (mod = do_mod(del.br_startblock, mp->m_sb.sb_rextsize))) { - /* - * Realtime extent is lined up at the end but not - * at the front. We'll get rid of full extents if - * we can. - */ - mod = mp->m_sb.sb_rextsize - mod; - if (del.br_blockcount > mod) { - del.br_blockcount -= mod; - del.br_startoff += mod; - del.br_startblock += mod; - } else if ((del.br_startoff == start && - (del.br_state == XFS_EXT_UNWRITTEN || - tp->t_blk_res == 0)) || - !xfs_sb_version_hasextflgbit(&mp->m_sb)) { - /* - * Can't make it unwritten. There isn't - * a full extent here so just skip it. - */ - ASSERT(bno >= del.br_blockcount); - bno -= del.br_blockcount; - if (got.br_startoff > bno) { - if (--lastx >= 0) { - ep = xfs_iext_get_ext(ifp, - lastx); - xfs_bmbt_get_all(ep, &got); - } - } - continue; - } else if (del.br_state == XFS_EXT_UNWRITTEN) { - /* - * This one is already unwritten. - * It must have a written left neighbor. - * Unwrite the killed part of that one and - * try again. - */ - ASSERT(lastx > 0); - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, - lastx - 1), &prev); - ASSERT(prev.br_state == XFS_EXT_NORM); - ASSERT(!isnullstartblock(prev.br_startblock)); - ASSERT(del.br_startblock == - prev.br_startblock + prev.br_blockcount); - if (prev.br_startoff < start) { - mod = start - prev.br_startoff; - prev.br_blockcount -= mod; - prev.br_startblock += mod; - prev.br_startoff = start; - } - prev.br_state = XFS_EXT_UNWRITTEN; - lastx--; - error = xfs_bmap_add_extent_unwritten_real(tp, - ip, &lastx, &cur, &prev, - firstblock, dfops, &logflags); - if (error) - goto error0; - goto nodelete; - } else { - ASSERT(del.br_state == XFS_EXT_NORM); - del.br_state = XFS_EXT_UNWRITTEN; - error = xfs_bmap_add_extent_unwritten_real(tp, - ip, &lastx, &cur, &del, - firstblock, dfops, &logflags); - if (error) - goto error0; - goto nodelete; - } - } - - /* - * If it's the case where the directory code is running - * with no block reservation, and the deleted block is in - * the middle of its extent, and the resulting insert - * of an extent would cause transformation to btree format, - * then reject it. The calling code will then swap - * blocks around instead. - * We have to do this now, rather than waiting for the - * conversion to btree format, since the transaction - * will be dirty. - */ - if (!wasdel && tp->t_blk_res == 0 && - XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS && - XFS_IFORK_NEXTENTS(ip, whichfork) >= /* Note the >= */ - XFS_IFORK_MAXEXT(ip, whichfork) && - del.br_startoff > got.br_startoff && - del.br_startoff + del.br_blockcount < - got.br_startoff + got.br_blockcount) { - error = -ENOSPC; - goto error0; - } - - /* - * Unreserve quota and update realtime free space, if - * appropriate. If delayed allocation, update the inode delalloc - * counter now and wait to update the sb counters as - * xfs_bmap_del_extent() might need to borrow some blocks. - */ - if (wasdel) { - ASSERT(startblockval(del.br_startblock) > 0); - if (isrt) { - xfs_filblks_t rtexts; - - rtexts = XFS_FSB_TO_B(mp, del.br_blockcount); - do_div(rtexts, mp->m_sb.sb_rextsize); - xfs_mod_frextents(mp, (int64_t)rtexts); - (void)xfs_trans_reserve_quota_nblks(NULL, - ip, -((long)del.br_blockcount), 0, - XFS_QMOPT_RES_RTBLKS); - } else { - (void)xfs_trans_reserve_quota_nblks(NULL, - ip, -((long)del.br_blockcount), 0, - XFS_QMOPT_RES_REGBLKS); - } - ip->i_delayed_blks -= del.br_blockcount; - if (cur) - cur->bc_private.b.flags |= - XFS_BTCUR_BPRV_WASDEL; - } else if (cur) - cur->bc_private.b.flags &= ~XFS_BTCUR_BPRV_WASDEL; - - error = xfs_bmap_del_extent(ip, tp, &lastx, dfops, cur, &del, - &tmp_logflags, whichfork, flags); - logflags |= tmp_logflags; - if (error) - goto error0; - - if (!isrt && wasdel) - xfs_mod_fdblocks(mp, (int64_t)del.br_blockcount, false); - - bno = del.br_startoff - 1; -nodelete: - /* - * If not done go on to the next (previous) record. - */ - if (bno != (xfs_fileoff_t)-1 && bno >= start) { - if (lastx >= 0) { - ep = xfs_iext_get_ext(ifp, lastx); - if (xfs_bmbt_get_startoff(ep) > bno) { - if (--lastx >= 0) - ep = xfs_iext_get_ext(ifp, - lastx); - } - xfs_bmbt_get_all(ep, &got); - } - extno++; - } - } - if (bno == (xfs_fileoff_t)-1 || bno < start || lastx < 0) - *rlen = 0; - else - *rlen = bno - start + 1; - - /* - * Convert to a btree if necessary. - */ - if (xfs_bmap_needs_btree(ip, whichfork)) { - ASSERT(cur == NULL); - error = xfs_bmap_extents_to_btree(tp, ip, firstblock, dfops, - &cur, 0, &tmp_logflags, whichfork); - logflags |= tmp_logflags; - if (error) - goto error0; - } - /* - * transform from btree to extents, give it cur - */ - else if (xfs_bmap_wants_extents(ip, whichfork)) { - ASSERT(cur != NULL); - error = xfs_bmap_btree_to_extents(tp, ip, cur, &tmp_logflags, - whichfork); - logflags |= tmp_logflags; - if (error) - goto error0; - } - /* - * transform from extents to local? - */ - error = 0; -error0: - /* - * Log everything. Do this after conversion, there's no point in - * logging the extent records if we've converted to btree format. - */ - if ((logflags & xfs_ilog_fext(whichfork)) && - XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS) - logflags &= ~xfs_ilog_fext(whichfork); - else if ((logflags & xfs_ilog_fbroot(whichfork)) && - XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE) - logflags &= ~xfs_ilog_fbroot(whichfork); - /* - * Log inode even in the error case, if the transaction - * is dirty we'll need to shut down the filesystem. - */ - if (logflags) - xfs_trans_log_inode(tp, ip, logflags); - if (cur) { - if (!error) { - *firstblock = cur->bc_private.b.firstblock; - cur->bc_private.b.allocated = 0; - } - xfs_btree_del_cursor(cur, - error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); - } - return error; -} - -/* Unmap a range of a file. */ -int -xfs_bunmapi( - xfs_trans_t *tp, - struct xfs_inode *ip, - xfs_fileoff_t bno, - xfs_filblks_t len, - int flags, - xfs_extnum_t nexts, - xfs_fsblock_t *firstblock, - struct xfs_defer_ops *dfops, - int *done) -{ - int error; - - error = __xfs_bunmapi(tp, ip, bno, &len, flags, nexts, firstblock, - dfops); - *done = (len == 0); - return error; -} - -/* - * Determine whether an extent shift can be accomplished by a merge with the - * extent that precedes the target hole of the shift. - */ -STATIC bool -xfs_bmse_can_merge( - struct xfs_bmbt_irec *left, /* preceding extent */ - struct xfs_bmbt_irec *got, /* current extent to shift */ - xfs_fileoff_t shift) /* shift fsb */ -{ - xfs_fileoff_t startoff; - - startoff = got->br_startoff - shift; - - /* - * The extent, once shifted, must be adjacent in-file and on-disk with - * the preceding extent. - */ - if ((left->br_startoff + left->br_blockcount != startoff) || - (left->br_startblock + left->br_blockcount != got->br_startblock) || - (left->br_state != got->br_state) || - (left->br_blockcount + got->br_blockcount > MAXEXTLEN)) - return false; - - return true; -} - -/* - * A bmap extent shift adjusts the file offset of an extent to fill a preceding - * hole in the file. If an extent shift would result in the extent being fully - * adjacent to the extent that currently precedes the hole, we can merge with - * the preceding extent rather than do the shift. - * - * This function assumes the caller has verified a shift-by-merge is possible - * with the provided extents via xfs_bmse_can_merge(). - */ -STATIC int -xfs_bmse_merge( - struct xfs_inode *ip, - int whichfork, - xfs_fileoff_t shift, /* shift fsb */ - int current_ext, /* idx of gotp */ - struct xfs_bmbt_rec_host *gotp, /* extent to shift */ - struct xfs_bmbt_rec_host *leftp, /* preceding extent */ - struct xfs_btree_cur *cur, - int *logflags) /* output */ -{ - struct xfs_bmbt_irec got; - struct xfs_bmbt_irec left; - xfs_filblks_t blockcount; - int error, i; - struct xfs_mount *mp = ip->i_mount; - - xfs_bmbt_get_all(gotp, &got); - xfs_bmbt_get_all(leftp, &left); - blockcount = left.br_blockcount + got.br_blockcount; - - ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - ASSERT(xfs_bmse_can_merge(&left, &got, shift)); - - /* - * Merge the in-core extents. Note that the host record pointers and - * current_ext index are invalid once the extent has been removed via - * xfs_iext_remove(). - */ - xfs_bmbt_set_blockcount(leftp, blockcount); - xfs_iext_remove(ip, current_ext, 1, 0); - - /* - * Update the on-disk extent count, the btree if necessary and log the - * inode. - */ - XFS_IFORK_NEXT_SET(ip, whichfork, - XFS_IFORK_NEXTENTS(ip, whichfork) - 1); - *logflags |= XFS_ILOG_CORE; - if (!cur) { - *logflags |= XFS_ILOG_DEXT; - return 0; - } - - /* lookup and remove the extent to merge */ - error = xfs_bmbt_lookup_eq(cur, got.br_startoff, got.br_startblock, - got.br_blockcount, &i); - if (error) - return error; - XFS_WANT_CORRUPTED_RETURN(mp, i == 1); - - error = xfs_btree_delete(cur, &i); - if (error) - return error; - XFS_WANT_CORRUPTED_RETURN(mp, i == 1); - - /* lookup and update size of the previous extent */ - error = xfs_bmbt_lookup_eq(cur, left.br_startoff, left.br_startblock, - left.br_blockcount, &i); - if (error) - return error; - XFS_WANT_CORRUPTED_RETURN(mp, i == 1); - - left.br_blockcount = blockcount; - - return xfs_bmbt_update(cur, left.br_startoff, left.br_startblock, - left.br_blockcount, left.br_state); -} - -/* - * Shift a single extent. - */ -STATIC int -xfs_bmse_shift_one( - struct xfs_inode *ip, - int whichfork, - xfs_fileoff_t offset_shift_fsb, - int *current_ext, - struct xfs_bmbt_rec_host *gotp, - struct xfs_btree_cur *cur, - int *logflags, - enum shift_direction direction, - struct xfs_defer_ops *dfops) -{ - struct xfs_ifork *ifp; - struct xfs_mount *mp; - xfs_fileoff_t startoff; - struct xfs_bmbt_rec_host *adj_irecp; - struct xfs_bmbt_irec got; - struct xfs_bmbt_irec adj_irec; - int error; - int i; - int total_extents; - - mp = ip->i_mount; - ifp = XFS_IFORK_PTR(ip, whichfork); - total_extents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t); - - xfs_bmbt_get_all(gotp, &got); - - /* delalloc extents should be prevented by caller */ - XFS_WANT_CORRUPTED_RETURN(mp, !isnullstartblock(got.br_startblock)); - - if (direction == SHIFT_LEFT) { - startoff = got.br_startoff - offset_shift_fsb; - - /* - * Check for merge if we've got an extent to the left, - * otherwise make sure there's enough room at the start - * of the file for the shift. - */ - if (!*current_ext) { - if (got.br_startoff < offset_shift_fsb) - return -EINVAL; - goto update_current_ext; - } - /* - * grab the left extent and check for a large - * enough hole. - */ - adj_irecp = xfs_iext_get_ext(ifp, *current_ext - 1); - xfs_bmbt_get_all(adj_irecp, &adj_irec); - - if (startoff < - adj_irec.br_startoff + adj_irec.br_blockcount) - return -EINVAL; - - /* check whether to merge the extent or shift it down */ - if (xfs_bmse_can_merge(&adj_irec, &got, - offset_shift_fsb)) { - error = xfs_bmse_merge(ip, whichfork, offset_shift_fsb, - *current_ext, gotp, adj_irecp, - cur, logflags); - if (error) - return error; - adj_irec = got; - goto update_rmap; - } - } else { - startoff = got.br_startoff + offset_shift_fsb; - /* nothing to move if this is the last extent */ - if (*current_ext >= (total_extents - 1)) - goto update_current_ext; - /* - * If this is not the last extent in the file, make sure there - * is enough room between current extent and next extent for - * accommodating the shift. - */ - adj_irecp = xfs_iext_get_ext(ifp, *current_ext + 1); - xfs_bmbt_get_all(adj_irecp, &adj_irec); - if (startoff + got.br_blockcount > adj_irec.br_startoff) - return -EINVAL; - /* - * Unlike a left shift (which involves a hole punch), - * a right shift does not modify extent neighbors - * in any way. We should never find mergeable extents - * in this scenario. Check anyways and warn if we - * encounter two extents that could be one. - */ - if (xfs_bmse_can_merge(&got, &adj_irec, offset_shift_fsb)) - WARN_ON_ONCE(1); - } - /* - * Increment the extent index for the next iteration, update the start - * offset of the in-core extent and update the btree if applicable. - */ -update_current_ext: - if (direction == SHIFT_LEFT) - (*current_ext)++; - else - (*current_ext)--; - xfs_bmbt_set_startoff(gotp, startoff); - *logflags |= XFS_ILOG_CORE; - adj_irec = got; - if (!cur) { - *logflags |= XFS_ILOG_DEXT; - goto update_rmap; - } - - error = xfs_bmbt_lookup_eq(cur, got.br_startoff, got.br_startblock, - got.br_blockcount, &i); - if (error) - return error; - XFS_WANT_CORRUPTED_RETURN(mp, i == 1); - - got.br_startoff = startoff; - error = xfs_bmbt_update(cur, got.br_startoff, got.br_startblock, - got.br_blockcount, got.br_state); - if (error) - return error; - -update_rmap: - /* update reverse mapping */ - error = xfs_rmap_unmap_extent(mp, dfops, ip, whichfork, &adj_irec); - if (error) - return error; - adj_irec.br_startoff = startoff; - return xfs_rmap_map_extent(mp, dfops, ip, whichfork, &adj_irec); -} - -/* - * Shift extent records to the left/right to cover/create a hole. - * - * The maximum number of extents to be shifted in a single operation is - * @num_exts. @stop_fsb specifies the file offset at which to stop shift and the - * file offset where we've left off is returned in @next_fsb. @offset_shift_fsb - * is the length by which each extent is shifted. If there is no hole to shift - * the extents into, this will be considered invalid operation and we abort - * immediately. - */ -int -xfs_bmap_shift_extents( - struct xfs_trans *tp, - struct xfs_inode *ip, - xfs_fileoff_t *next_fsb, - xfs_fileoff_t offset_shift_fsb, - int *done, - xfs_fileoff_t stop_fsb, - xfs_fsblock_t *firstblock, - struct xfs_defer_ops *dfops, - enum shift_direction direction, - int num_exts) -{ - struct xfs_btree_cur *cur = NULL; - struct xfs_bmbt_rec_host *gotp; - struct xfs_bmbt_irec got; - struct xfs_mount *mp = ip->i_mount; - struct xfs_ifork *ifp; - xfs_extnum_t nexts = 0; - xfs_extnum_t current_ext; - xfs_extnum_t total_extents; - xfs_extnum_t stop_extent; - int error = 0; - int whichfork = XFS_DATA_FORK; - int logflags = 0; - - if (unlikely(XFS_TEST_ERROR( - (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && - XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE), - mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) { - XFS_ERROR_REPORT("xfs_bmap_shift_extents", - XFS_ERRLEVEL_LOW, mp); - return -EFSCORRUPTED; - } - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - ASSERT(direction == SHIFT_LEFT || direction == SHIFT_RIGHT); - ASSERT(*next_fsb != NULLFSBLOCK || direction == SHIFT_RIGHT); - - ifp = XFS_IFORK_PTR(ip, whichfork); - if (!(ifp->if_flags & XFS_IFEXTENTS)) { - /* Read in all the extents */ - error = xfs_iread_extents(tp, ip, whichfork); - if (error) - return error; - } - - if (ifp->if_flags & XFS_IFBROOT) { - cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); - cur->bc_private.b.firstblock = *firstblock; - cur->bc_private.b.dfops = dfops; - cur->bc_private.b.flags = 0; - } - - /* - * There may be delalloc extents in the data fork before the range we - * are collapsing out, so we cannot use the count of real extents here. - * Instead we have to calculate it from the incore fork. - */ - total_extents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t); - if (total_extents == 0) { - *done = 1; - goto del_cursor; - } - - /* - * In case of first right shift, we need to initialize next_fsb - */ - if (*next_fsb == NULLFSBLOCK) { - gotp = xfs_iext_get_ext(ifp, total_extents - 1); - xfs_bmbt_get_all(gotp, &got); - *next_fsb = got.br_startoff; - if (stop_fsb > *next_fsb) { - *done = 1; - goto del_cursor; - } - } - - /* Lookup the extent index at which we have to stop */ - if (direction == SHIFT_RIGHT) { - gotp = xfs_iext_bno_to_ext(ifp, stop_fsb, &stop_extent); - /* Make stop_extent exclusive of shift range */ - stop_extent--; - } else - stop_extent = total_extents; - - /* - * Look up the extent index for the fsb where we start shifting. We can - * henceforth iterate with current_ext as extent list changes are locked - * out via ilock. - * - * gotp can be null in 2 cases: 1) if there are no extents or 2) - * *next_fsb lies in a hole beyond which there are no extents. Either - * way, we are done. - */ - gotp = xfs_iext_bno_to_ext(ifp, *next_fsb, ¤t_ext); - if (!gotp) { - *done = 1; - goto del_cursor; - } - - /* some sanity checking before we finally start shifting extents */ - if ((direction == SHIFT_LEFT && current_ext >= stop_extent) || - (direction == SHIFT_RIGHT && current_ext <= stop_extent)) { - error = -EIO; - goto del_cursor; - } - - while (nexts++ < num_exts) { - error = xfs_bmse_shift_one(ip, whichfork, offset_shift_fsb, - ¤t_ext, gotp, cur, &logflags, - direction, dfops); - if (error) - goto del_cursor; - /* - * If there was an extent merge during the shift, the extent - * count can change. Update the total and grade the next record. - */ - if (direction == SHIFT_LEFT) { - total_extents = ifp->if_bytes / sizeof(xfs_bmbt_rec_t); - stop_extent = total_extents; - } - - if (current_ext == stop_extent) { - *done = 1; - *next_fsb = NULLFSBLOCK; - break; - } - gotp = xfs_iext_get_ext(ifp, current_ext); - } - - if (!*done) { - xfs_bmbt_get_all(gotp, &got); - *next_fsb = got.br_startoff; - } - -del_cursor: - if (cur) - xfs_btree_del_cursor(cur, - error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); - - if (logflags) - xfs_trans_log_inode(tp, ip, logflags); - - return error; -} - -/* - * Splits an extent into two extents at split_fsb block such that it is - * the first block of the current_ext. @current_ext is a target extent - * to be split. @split_fsb is a block where the extents is split. - * If split_fsb lies in a hole or the first block of extents, just return 0. - */ -STATIC int -xfs_bmap_split_extent_at( - struct xfs_trans *tp, - struct xfs_inode *ip, - xfs_fileoff_t split_fsb, - xfs_fsblock_t *firstfsb, - struct xfs_defer_ops *dfops) -{ - int whichfork = XFS_DATA_FORK; - struct xfs_btree_cur *cur = NULL; - struct xfs_bmbt_rec_host *gotp; - struct xfs_bmbt_irec got; - struct xfs_bmbt_irec new; /* split extent */ - struct xfs_mount *mp = ip->i_mount; - struct xfs_ifork *ifp; - xfs_fsblock_t gotblkcnt; /* new block count for got */ - xfs_extnum_t current_ext; - int error = 0; - int logflags = 0; - int i = 0; - - if (unlikely(XFS_TEST_ERROR( - (XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_EXTENTS && - XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE), - mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) { - XFS_ERROR_REPORT("xfs_bmap_split_extent_at", - XFS_ERRLEVEL_LOW, mp); - return -EFSCORRUPTED; - } - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - ifp = XFS_IFORK_PTR(ip, whichfork); - if (!(ifp->if_flags & XFS_IFEXTENTS)) { - /* Read in all the extents */ - error = xfs_iread_extents(tp, ip, whichfork); - if (error) - return error; - } - - /* - * gotp can be null in 2 cases: 1) if there are no extents - * or 2) split_fsb lies in a hole beyond which there are - * no extents. Either way, we are done. - */ - gotp = xfs_iext_bno_to_ext(ifp, split_fsb, ¤t_ext); - if (!gotp) - return 0; - - xfs_bmbt_get_all(gotp, &got); - - /* - * Check split_fsb lies in a hole or the start boundary offset - * of the extent. - */ - if (got.br_startoff >= split_fsb) - return 0; - - gotblkcnt = split_fsb - got.br_startoff; - new.br_startoff = split_fsb; - new.br_startblock = got.br_startblock + gotblkcnt; - new.br_blockcount = got.br_blockcount - gotblkcnt; - new.br_state = got.br_state; - - if (ifp->if_flags & XFS_IFBROOT) { - cur = xfs_bmbt_init_cursor(mp, tp, ip, whichfork); - cur->bc_private.b.firstblock = *firstfsb; - cur->bc_private.b.dfops = dfops; - cur->bc_private.b.flags = 0; - error = xfs_bmbt_lookup_eq(cur, got.br_startoff, - got.br_startblock, - got.br_blockcount, - &i); - if (error) - goto del_cursor; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, del_cursor); - } - - xfs_bmbt_set_blockcount(gotp, gotblkcnt); - got.br_blockcount = gotblkcnt; - - logflags = XFS_ILOG_CORE; - if (cur) { - error = xfs_bmbt_update(cur, got.br_startoff, - got.br_startblock, - got.br_blockcount, - got.br_state); - if (error) - goto del_cursor; - } else - logflags |= XFS_ILOG_DEXT; - - /* Add new extent */ - current_ext++; - xfs_iext_insert(ip, current_ext, 1, &new, 0); - XFS_IFORK_NEXT_SET(ip, whichfork, - XFS_IFORK_NEXTENTS(ip, whichfork) + 1); - - if (cur) { - error = xfs_bmbt_lookup_eq(cur, new.br_startoff, - new.br_startblock, new.br_blockcount, - &i); - if (error) - goto del_cursor; - XFS_WANT_CORRUPTED_GOTO(mp, i == 0, del_cursor); - cur->bc_rec.b.br_state = new.br_state; - - error = xfs_btree_insert(cur, &i); - if (error) - goto del_cursor; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, del_cursor); - } - - /* - * Convert to a btree if necessary. - */ - if (xfs_bmap_needs_btree(ip, whichfork)) { - int tmp_logflags; /* partial log flag return val */ - - ASSERT(cur == NULL); - error = xfs_bmap_extents_to_btree(tp, ip, firstfsb, dfops, - &cur, 0, &tmp_logflags, whichfork); - logflags |= tmp_logflags; - } - -del_cursor: - if (cur) { - cur->bc_private.b.allocated = 0; - xfs_btree_del_cursor(cur, - error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); - } - - if (logflags) - xfs_trans_log_inode(tp, ip, logflags); - return error; -} - -int -xfs_bmap_split_extent( - struct xfs_inode *ip, - xfs_fileoff_t split_fsb) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_trans *tp; - struct xfs_defer_ops dfops; - xfs_fsblock_t firstfsb; - int error; - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, - XFS_DIOSTRAT_SPACE_RES(mp, 0), 0, 0, &tp); - if (error) - return error; - - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); - - xfs_defer_init(&dfops, &firstfsb); - - error = xfs_bmap_split_extent_at(tp, ip, split_fsb, - &firstfsb, &dfops); - if (error) - goto out; - - error = xfs_defer_finish(&tp, &dfops, NULL); - if (error) - goto out; - - return xfs_trans_commit(tp); - -out: - xfs_defer_cancel(&dfops); - xfs_trans_cancel(tp); - return error; -} - -/* Deferred mapping is only for real extents in the data fork. */ -static bool -xfs_bmap_is_update_needed( - struct xfs_bmbt_irec *bmap) -{ - return bmap->br_startblock != HOLESTARTBLOCK && - bmap->br_startblock != DELAYSTARTBLOCK; -} - -/* Record a bmap intent. */ -static int -__xfs_bmap_add( - struct xfs_mount *mp, - struct xfs_defer_ops *dfops, - enum xfs_bmap_intent_type type, - struct xfs_inode *ip, - int whichfork, - struct xfs_bmbt_irec *bmap) -{ - int error; - struct xfs_bmap_intent *bi; - - trace_xfs_bmap_defer(mp, - XFS_FSB_TO_AGNO(mp, bmap->br_startblock), - type, - XFS_FSB_TO_AGBNO(mp, bmap->br_startblock), - ip->i_ino, whichfork, - bmap->br_startoff, - bmap->br_blockcount, - bmap->br_state); - - bi = kmem_alloc(sizeof(struct xfs_bmap_intent), KM_SLEEP | KM_NOFS); - INIT_LIST_HEAD(&bi->bi_list); - bi->bi_type = type; - bi->bi_owner = ip; - bi->bi_whichfork = whichfork; - bi->bi_bmap = *bmap; - - error = xfs_defer_join(dfops, bi->bi_owner); - if (error) { - kmem_free(bi); - return error; - } - - xfs_defer_add(dfops, XFS_DEFER_OPS_TYPE_BMAP, &bi->bi_list); - return 0; -} - -/* Map an extent into a file. */ -int -xfs_bmap_map_extent( - struct xfs_mount *mp, - struct xfs_defer_ops *dfops, - struct xfs_inode *ip, - struct xfs_bmbt_irec *PREV) -{ - if (!xfs_bmap_is_update_needed(PREV)) - return 0; - - return __xfs_bmap_add(mp, dfops, XFS_BMAP_MAP, ip, - XFS_DATA_FORK, PREV); -} - -/* Unmap an extent out of a file. */ -int -xfs_bmap_unmap_extent( - struct xfs_mount *mp, - struct xfs_defer_ops *dfops, - struct xfs_inode *ip, - struct xfs_bmbt_irec *PREV) -{ - if (!xfs_bmap_is_update_needed(PREV)) - return 0; - - return __xfs_bmap_add(mp, dfops, XFS_BMAP_UNMAP, ip, - XFS_DATA_FORK, PREV); -} - -/* - * Process one of the deferred bmap operations. We pass back the - * btree cursor to maintain our lock on the bmapbt between calls. - */ -int -xfs_bmap_finish_one( - struct xfs_trans *tp, - struct xfs_defer_ops *dfops, - struct xfs_inode *ip, - enum xfs_bmap_intent_type type, - int whichfork, - xfs_fileoff_t startoff, - xfs_fsblock_t startblock, - xfs_filblks_t blockcount, - xfs_exntst_t state) -{ - struct xfs_bmbt_irec bmap; - int nimaps = 1; - xfs_fsblock_t firstfsb; - int flags = XFS_BMAPI_REMAP; - int done; - int error = 0; - - bmap.br_startblock = startblock; - bmap.br_startoff = startoff; - bmap.br_blockcount = blockcount; - bmap.br_state = state; - - trace_xfs_bmap_deferred(tp->t_mountp, - XFS_FSB_TO_AGNO(tp->t_mountp, startblock), type, - XFS_FSB_TO_AGBNO(tp->t_mountp, startblock), - ip->i_ino, whichfork, startoff, blockcount, state); - - if (whichfork != XFS_DATA_FORK && whichfork != XFS_ATTR_FORK) - return -EFSCORRUPTED; - if (whichfork == XFS_ATTR_FORK) - flags |= XFS_BMAPI_ATTRFORK; - - if (XFS_TEST_ERROR(false, tp->t_mountp, - XFS_ERRTAG_BMAP_FINISH_ONE, - XFS_RANDOM_BMAP_FINISH_ONE)) - return -EIO; - - switch (type) { - case XFS_BMAP_MAP: - firstfsb = bmap.br_startblock; - error = xfs_bmapi_write(tp, ip, bmap.br_startoff, - bmap.br_blockcount, flags, &firstfsb, - bmap.br_blockcount, &bmap, &nimaps, - dfops); - break; - case XFS_BMAP_UNMAP: - error = xfs_bunmapi(tp, ip, bmap.br_startoff, - bmap.br_blockcount, flags, 1, &firstfsb, - dfops, &done); - ASSERT(done); - break; - default: - ASSERT(0); - error = -EFSCORRUPTED; - } - - return error; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_bmap.h b/src/linux/fs/xfs/libxfs/xfs_bmap.h deleted file mode 100644 index 7cae6ec..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_bmap.h +++ /dev/null @@ -1,271 +0,0 @@ -/* - * Copyright (c) 2000-2006 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_BMAP_H__ -#define __XFS_BMAP_H__ - -struct getbmap; -struct xfs_bmbt_irec; -struct xfs_ifork; -struct xfs_inode; -struct xfs_mount; -struct xfs_trans; - -extern kmem_zone_t *xfs_bmap_free_item_zone; - -/* - * Argument structure for xfs_bmap_alloc. - */ -struct xfs_bmalloca { - xfs_fsblock_t *firstblock; /* i/o first block allocated */ - struct xfs_defer_ops *dfops; /* bmap freelist */ - struct xfs_trans *tp; /* transaction pointer */ - struct xfs_inode *ip; /* incore inode pointer */ - struct xfs_bmbt_irec prev; /* extent before the new one */ - struct xfs_bmbt_irec got; /* extent after, or delayed */ - - xfs_fileoff_t offset; /* offset in file filling in */ - xfs_extlen_t length; /* i/o length asked/allocated */ - xfs_fsblock_t blkno; /* starting block of new extent */ - - struct xfs_btree_cur *cur; /* btree cursor */ - xfs_extnum_t idx; /* current extent index */ - int nallocs;/* number of extents alloc'd */ - int logflags;/* flags for transaction logging */ - - xfs_extlen_t total; /* total blocks needed for xaction */ - xfs_extlen_t minlen; /* minimum allocation size (blocks) */ - xfs_extlen_t minleft; /* amount must be left after alloc */ - bool eof; /* set if allocating past last extent */ - bool wasdel; /* replacing a delayed allocation */ - bool aeof; /* allocated space at eof */ - bool conv; /* overwriting unwritten extents */ - int datatype;/* data type being allocated */ - int flags; -}; - -/* - * List of extents to be free "later". - * The list is kept sorted on xbf_startblock. - */ -struct xfs_extent_free_item -{ - xfs_fsblock_t xefi_startblock;/* starting fs block number */ - xfs_extlen_t xefi_blockcount;/* number of blocks in extent */ - struct list_head xefi_list; - struct xfs_owner_info xefi_oinfo; /* extent owner */ -}; - -#define XFS_BMAP_MAX_NMAP 4 - -/* - * Flags for xfs_bmapi_* - */ -#define XFS_BMAPI_ENTIRE 0x001 /* return entire extent, not trimmed */ -#define XFS_BMAPI_METADATA 0x002 /* mapping metadata not user data */ -#define XFS_BMAPI_ATTRFORK 0x004 /* use attribute fork not data */ -#define XFS_BMAPI_PREALLOC 0x008 /* preallocation op: unwritten space */ -#define XFS_BMAPI_IGSTATE 0x010 /* Ignore state - */ - /* combine contig. space */ -#define XFS_BMAPI_CONTIG 0x020 /* must allocate only one extent */ -/* - * unwritten extent conversion - this needs write cache flushing and no additional - * allocation alignments. When specified with XFS_BMAPI_PREALLOC it converts - * from written to unwritten, otherwise convert from unwritten to written. - */ -#define XFS_BMAPI_CONVERT 0x040 - -/* - * allocate zeroed extents - this requires all newly allocated user data extents - * to be initialised to zero. It will be ignored if XFS_BMAPI_METADATA is set. - * Use in conjunction with XFS_BMAPI_CONVERT to convert unwritten extents found - * during the allocation range to zeroed written extents. - */ -#define XFS_BMAPI_ZERO 0x080 - -/* - * Map the inode offset to the block given in ap->firstblock. Primarily - * used for reflink. The range must be in a hole, and this flag cannot be - * turned on with PREALLOC or CONVERT, and cannot be used on the attr fork. - * - * For bunmapi, this flag unmaps the range without adjusting quota, reducing - * refcount, or freeing the blocks. - */ -#define XFS_BMAPI_REMAP 0x100 - -/* Map something in the CoW fork. */ -#define XFS_BMAPI_COWFORK 0x200 - -#define XFS_BMAPI_FLAGS \ - { XFS_BMAPI_ENTIRE, "ENTIRE" }, \ - { XFS_BMAPI_METADATA, "METADATA" }, \ - { XFS_BMAPI_ATTRFORK, "ATTRFORK" }, \ - { XFS_BMAPI_PREALLOC, "PREALLOC" }, \ - { XFS_BMAPI_IGSTATE, "IGSTATE" }, \ - { XFS_BMAPI_CONTIG, "CONTIG" }, \ - { XFS_BMAPI_CONVERT, "CONVERT" }, \ - { XFS_BMAPI_ZERO, "ZERO" }, \ - { XFS_BMAPI_REMAP, "REMAP" }, \ - { XFS_BMAPI_COWFORK, "COWFORK" } - - -static inline int xfs_bmapi_aflag(int w) -{ - return (w == XFS_ATTR_FORK ? XFS_BMAPI_ATTRFORK : - (w == XFS_COW_FORK ? XFS_BMAPI_COWFORK : 0)); -} - -static inline int xfs_bmapi_whichfork(int bmapi_flags) -{ - if (bmapi_flags & XFS_BMAPI_COWFORK) - return XFS_COW_FORK; - else if (bmapi_flags & XFS_BMAPI_ATTRFORK) - return XFS_ATTR_FORK; - return XFS_DATA_FORK; -} - -/* - * Special values for xfs_bmbt_irec_t br_startblock field. - */ -#define DELAYSTARTBLOCK ((xfs_fsblock_t)-1LL) -#define HOLESTARTBLOCK ((xfs_fsblock_t)-2LL) - -/* - * Flags for xfs_bmap_add_extent*. - */ -#define BMAP_LEFT_CONTIG (1 << 0) -#define BMAP_RIGHT_CONTIG (1 << 1) -#define BMAP_LEFT_FILLING (1 << 2) -#define BMAP_RIGHT_FILLING (1 << 3) -#define BMAP_LEFT_DELAY (1 << 4) -#define BMAP_RIGHT_DELAY (1 << 5) -#define BMAP_LEFT_VALID (1 << 6) -#define BMAP_RIGHT_VALID (1 << 7) -#define BMAP_ATTRFORK (1 << 8) -#define BMAP_COWFORK (1 << 9) - -#define XFS_BMAP_EXT_FLAGS \ - { BMAP_LEFT_CONTIG, "LC" }, \ - { BMAP_RIGHT_CONTIG, "RC" }, \ - { BMAP_LEFT_FILLING, "LF" }, \ - { BMAP_RIGHT_FILLING, "RF" }, \ - { BMAP_ATTRFORK, "ATTR" }, \ - { BMAP_COWFORK, "COW" } - - -/* - * This macro is used to determine how many extents will be shifted - * in one write transaction. We could require two splits, - * an extent move on the first and an extent merge on the second, - * So it is proper that one extent is shifted inside write transaction - * at a time. - */ -#define XFS_BMAP_MAX_SHIFT_EXTENTS 1 - -enum shift_direction { - SHIFT_LEFT = 0, - SHIFT_RIGHT, -}; - -#ifdef DEBUG -void xfs_bmap_trace_exlist(struct xfs_inode *ip, xfs_extnum_t cnt, - int whichfork, unsigned long caller_ip); -#define XFS_BMAP_TRACE_EXLIST(ip,c,w) \ - xfs_bmap_trace_exlist(ip,c,w, _THIS_IP_) -#else -#define XFS_BMAP_TRACE_EXLIST(ip,c,w) -#endif - -void xfs_trim_extent(struct xfs_bmbt_irec *irec, xfs_fileoff_t bno, - xfs_filblks_t len); -int xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd); -void xfs_bmap_local_to_extents_empty(struct xfs_inode *ip, int whichfork); -void xfs_bmap_add_free(struct xfs_mount *mp, struct xfs_defer_ops *dfops, - xfs_fsblock_t bno, xfs_filblks_t len, - struct xfs_owner_info *oinfo); -void xfs_bmap_compute_maxlevels(struct xfs_mount *mp, int whichfork); -int xfs_bmap_first_unused(struct xfs_trans *tp, struct xfs_inode *ip, - xfs_extlen_t len, xfs_fileoff_t *unused, int whichfork); -int xfs_bmap_last_before(struct xfs_trans *tp, struct xfs_inode *ip, - xfs_fileoff_t *last_block, int whichfork); -int xfs_bmap_last_offset(struct xfs_inode *ip, xfs_fileoff_t *unused, - int whichfork); -int xfs_bmap_one_block(struct xfs_inode *ip, int whichfork); -int xfs_bmap_read_extents(struct xfs_trans *tp, struct xfs_inode *ip, - int whichfork); -int xfs_bmapi_read(struct xfs_inode *ip, xfs_fileoff_t bno, - xfs_filblks_t len, struct xfs_bmbt_irec *mval, - int *nmap, int flags); -int xfs_bmapi_write(struct xfs_trans *tp, struct xfs_inode *ip, - xfs_fileoff_t bno, xfs_filblks_t len, int flags, - xfs_fsblock_t *firstblock, xfs_extlen_t total, - struct xfs_bmbt_irec *mval, int *nmap, - struct xfs_defer_ops *dfops); -int __xfs_bunmapi(struct xfs_trans *tp, struct xfs_inode *ip, - xfs_fileoff_t bno, xfs_filblks_t *rlen, int flags, - xfs_extnum_t nexts, xfs_fsblock_t *firstblock, - struct xfs_defer_ops *dfops); -int xfs_bunmapi(struct xfs_trans *tp, struct xfs_inode *ip, - xfs_fileoff_t bno, xfs_filblks_t len, int flags, - xfs_extnum_t nexts, xfs_fsblock_t *firstblock, - struct xfs_defer_ops *dfops, int *done); -int xfs_bmap_del_extent_delay(struct xfs_inode *ip, int whichfork, - xfs_extnum_t *idx, struct xfs_bmbt_irec *got, - struct xfs_bmbt_irec *del); -void xfs_bmap_del_extent_cow(struct xfs_inode *ip, xfs_extnum_t *idx, - struct xfs_bmbt_irec *got, struct xfs_bmbt_irec *del); -int xfs_check_nostate_extents(struct xfs_ifork *ifp, xfs_extnum_t idx, - xfs_extnum_t num); -uint xfs_default_attroffset(struct xfs_inode *ip); -int xfs_bmap_shift_extents(struct xfs_trans *tp, struct xfs_inode *ip, - xfs_fileoff_t *next_fsb, xfs_fileoff_t offset_shift_fsb, - int *done, xfs_fileoff_t stop_fsb, xfs_fsblock_t *firstblock, - struct xfs_defer_ops *dfops, enum shift_direction direction, - int num_exts); -int xfs_bmap_split_extent(struct xfs_inode *ip, xfs_fileoff_t split_offset); -struct xfs_bmbt_rec_host * - xfs_bmap_search_extents(struct xfs_inode *ip, xfs_fileoff_t bno, - int fork, int *eofp, xfs_extnum_t *lastxp, - struct xfs_bmbt_irec *gotp, struct xfs_bmbt_irec *prevp); -int xfs_bmapi_reserve_delalloc(struct xfs_inode *ip, int whichfork, - xfs_fileoff_t aoff, xfs_filblks_t len, - struct xfs_bmbt_irec *got, struct xfs_bmbt_irec *prev, - xfs_extnum_t *lastx, int eof); - -enum xfs_bmap_intent_type { - XFS_BMAP_MAP = 1, - XFS_BMAP_UNMAP, -}; - -struct xfs_bmap_intent { - struct list_head bi_list; - enum xfs_bmap_intent_type bi_type; - struct xfs_inode *bi_owner; - int bi_whichfork; - struct xfs_bmbt_irec bi_bmap; -}; - -int xfs_bmap_finish_one(struct xfs_trans *tp, struct xfs_defer_ops *dfops, - struct xfs_inode *ip, enum xfs_bmap_intent_type type, - int whichfork, xfs_fileoff_t startoff, xfs_fsblock_t startblock, - xfs_filblks_t blockcount, xfs_exntst_t state); -int xfs_bmap_map_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops, - struct xfs_inode *ip, struct xfs_bmbt_irec *imap); -int xfs_bmap_unmap_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops, - struct xfs_inode *ip, struct xfs_bmbt_irec *imap); - -#endif /* __XFS_BMAP_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_bmap_btree.c b/src/linux/fs/xfs/libxfs/xfs_bmap_btree.c deleted file mode 100644 index 8007d2b..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_bmap_btree.c +++ /dev/null @@ -1,896 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_alloc.h" -#include "xfs_btree.h" -#include "xfs_bmap_btree.h" -#include "xfs_bmap.h" -#include "xfs_error.h" -#include "xfs_quota.h" -#include "xfs_trace.h" -#include "xfs_cksum.h" -#include "xfs_rmap.h" - -/* - * Determine the extent state. - */ -/* ARGSUSED */ -STATIC xfs_exntst_t -xfs_extent_state( - xfs_filblks_t blks, - int extent_flag) -{ - if (extent_flag) { - ASSERT(blks != 0); /* saved for DMIG */ - return XFS_EXT_UNWRITTEN; - } - return XFS_EXT_NORM; -} - -/* - * Convert on-disk form of btree root to in-memory form. - */ -void -xfs_bmdr_to_bmbt( - struct xfs_inode *ip, - xfs_bmdr_block_t *dblock, - int dblocklen, - struct xfs_btree_block *rblock, - int rblocklen) -{ - struct xfs_mount *mp = ip->i_mount; - int dmxr; - xfs_bmbt_key_t *fkp; - __be64 *fpp; - xfs_bmbt_key_t *tkp; - __be64 *tpp; - - if (xfs_sb_version_hascrc(&mp->m_sb)) - xfs_btree_init_block_int(mp, rblock, XFS_BUF_DADDR_NULL, - XFS_BMAP_CRC_MAGIC, 0, 0, ip->i_ino, - XFS_BTREE_LONG_PTRS | XFS_BTREE_CRC_BLOCKS); - else - xfs_btree_init_block_int(mp, rblock, XFS_BUF_DADDR_NULL, - XFS_BMAP_MAGIC, 0, 0, ip->i_ino, - XFS_BTREE_LONG_PTRS); - - rblock->bb_level = dblock->bb_level; - ASSERT(be16_to_cpu(rblock->bb_level) > 0); - rblock->bb_numrecs = dblock->bb_numrecs; - dmxr = xfs_bmdr_maxrecs(dblocklen, 0); - fkp = XFS_BMDR_KEY_ADDR(dblock, 1); - tkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1); - fpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr); - tpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen); - dmxr = be16_to_cpu(dblock->bb_numrecs); - memcpy(tkp, fkp, sizeof(*fkp) * dmxr); - memcpy(tpp, fpp, sizeof(*fpp) * dmxr); -} - -/* - * Convert a compressed bmap extent record to an uncompressed form. - * This code must be in sync with the routines xfs_bmbt_get_startoff, - * xfs_bmbt_get_startblock, xfs_bmbt_get_blockcount and xfs_bmbt_get_state. - */ -STATIC void -__xfs_bmbt_get_all( - __uint64_t l0, - __uint64_t l1, - xfs_bmbt_irec_t *s) -{ - int ext_flag; - xfs_exntst_t st; - - ext_flag = (int)(l0 >> (64 - BMBT_EXNTFLAG_BITLEN)); - s->br_startoff = ((xfs_fileoff_t)l0 & - xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; - s->br_startblock = (((xfs_fsblock_t)l0 & xfs_mask64lo(9)) << 43) | - (((xfs_fsblock_t)l1) >> 21); - s->br_blockcount = (xfs_filblks_t)(l1 & xfs_mask64lo(21)); - /* This is xfs_extent_state() in-line */ - if (ext_flag) { - ASSERT(s->br_blockcount != 0); /* saved for DMIG */ - st = XFS_EXT_UNWRITTEN; - } else - st = XFS_EXT_NORM; - s->br_state = st; -} - -void -xfs_bmbt_get_all( - xfs_bmbt_rec_host_t *r, - xfs_bmbt_irec_t *s) -{ - __xfs_bmbt_get_all(r->l0, r->l1, s); -} - -/* - * Extract the blockcount field from an in memory bmap extent record. - */ -xfs_filblks_t -xfs_bmbt_get_blockcount( - xfs_bmbt_rec_host_t *r) -{ - return (xfs_filblks_t)(r->l1 & xfs_mask64lo(21)); -} - -/* - * Extract the startblock field from an in memory bmap extent record. - */ -xfs_fsblock_t -xfs_bmbt_get_startblock( - xfs_bmbt_rec_host_t *r) -{ - return (((xfs_fsblock_t)r->l0 & xfs_mask64lo(9)) << 43) | - (((xfs_fsblock_t)r->l1) >> 21); -} - -/* - * Extract the startoff field from an in memory bmap extent record. - */ -xfs_fileoff_t -xfs_bmbt_get_startoff( - xfs_bmbt_rec_host_t *r) -{ - return ((xfs_fileoff_t)r->l0 & - xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; -} - -xfs_exntst_t -xfs_bmbt_get_state( - xfs_bmbt_rec_host_t *r) -{ - int ext_flag; - - ext_flag = (int)((r->l0) >> (64 - BMBT_EXNTFLAG_BITLEN)); - return xfs_extent_state(xfs_bmbt_get_blockcount(r), - ext_flag); -} - -/* - * Extract the blockcount field from an on disk bmap extent record. - */ -xfs_filblks_t -xfs_bmbt_disk_get_blockcount( - xfs_bmbt_rec_t *r) -{ - return (xfs_filblks_t)(be64_to_cpu(r->l1) & xfs_mask64lo(21)); -} - -/* - * Extract the startoff field from a disk format bmap extent record. - */ -xfs_fileoff_t -xfs_bmbt_disk_get_startoff( - xfs_bmbt_rec_t *r) -{ - return ((xfs_fileoff_t)be64_to_cpu(r->l0) & - xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; -} - - -/* - * Set all the fields in a bmap extent record from the arguments. - */ -void -xfs_bmbt_set_allf( - xfs_bmbt_rec_host_t *r, - xfs_fileoff_t startoff, - xfs_fsblock_t startblock, - xfs_filblks_t blockcount, - xfs_exntst_t state) -{ - int extent_flag = (state == XFS_EXT_NORM) ? 0 : 1; - - ASSERT(state == XFS_EXT_NORM || state == XFS_EXT_UNWRITTEN); - ASSERT((startoff & xfs_mask64hi(64-BMBT_STARTOFF_BITLEN)) == 0); - ASSERT((blockcount & xfs_mask64hi(64-BMBT_BLOCKCOUNT_BITLEN)) == 0); - - ASSERT((startblock & xfs_mask64hi(64-BMBT_STARTBLOCK_BITLEN)) == 0); - - r->l0 = ((xfs_bmbt_rec_base_t)extent_flag << 63) | - ((xfs_bmbt_rec_base_t)startoff << 9) | - ((xfs_bmbt_rec_base_t)startblock >> 43); - r->l1 = ((xfs_bmbt_rec_base_t)startblock << 21) | - ((xfs_bmbt_rec_base_t)blockcount & - (xfs_bmbt_rec_base_t)xfs_mask64lo(21)); -} - -/* - * Set all the fields in a bmap extent record from the uncompressed form. - */ -void -xfs_bmbt_set_all( - xfs_bmbt_rec_host_t *r, - xfs_bmbt_irec_t *s) -{ - xfs_bmbt_set_allf(r, s->br_startoff, s->br_startblock, - s->br_blockcount, s->br_state); -} - - -/* - * Set all the fields in a disk format bmap extent record from the arguments. - */ -void -xfs_bmbt_disk_set_allf( - xfs_bmbt_rec_t *r, - xfs_fileoff_t startoff, - xfs_fsblock_t startblock, - xfs_filblks_t blockcount, - xfs_exntst_t state) -{ - int extent_flag = (state == XFS_EXT_NORM) ? 0 : 1; - - ASSERT(state == XFS_EXT_NORM || state == XFS_EXT_UNWRITTEN); - ASSERT((startoff & xfs_mask64hi(64-BMBT_STARTOFF_BITLEN)) == 0); - ASSERT((blockcount & xfs_mask64hi(64-BMBT_BLOCKCOUNT_BITLEN)) == 0); - ASSERT((startblock & xfs_mask64hi(64-BMBT_STARTBLOCK_BITLEN)) == 0); - - r->l0 = cpu_to_be64( - ((xfs_bmbt_rec_base_t)extent_flag << 63) | - ((xfs_bmbt_rec_base_t)startoff << 9) | - ((xfs_bmbt_rec_base_t)startblock >> 43)); - r->l1 = cpu_to_be64( - ((xfs_bmbt_rec_base_t)startblock << 21) | - ((xfs_bmbt_rec_base_t)blockcount & - (xfs_bmbt_rec_base_t)xfs_mask64lo(21))); -} - -/* - * Set all the fields in a bmap extent record from the uncompressed form. - */ -STATIC void -xfs_bmbt_disk_set_all( - xfs_bmbt_rec_t *r, - xfs_bmbt_irec_t *s) -{ - xfs_bmbt_disk_set_allf(r, s->br_startoff, s->br_startblock, - s->br_blockcount, s->br_state); -} - -/* - * Set the blockcount field in a bmap extent record. - */ -void -xfs_bmbt_set_blockcount( - xfs_bmbt_rec_host_t *r, - xfs_filblks_t v) -{ - ASSERT((v & xfs_mask64hi(43)) == 0); - r->l1 = (r->l1 & (xfs_bmbt_rec_base_t)xfs_mask64hi(43)) | - (xfs_bmbt_rec_base_t)(v & xfs_mask64lo(21)); -} - -/* - * Set the startblock field in a bmap extent record. - */ -void -xfs_bmbt_set_startblock( - xfs_bmbt_rec_host_t *r, - xfs_fsblock_t v) -{ - ASSERT((v & xfs_mask64hi(12)) == 0); - r->l0 = (r->l0 & (xfs_bmbt_rec_base_t)xfs_mask64hi(55)) | - (xfs_bmbt_rec_base_t)(v >> 43); - r->l1 = (r->l1 & (xfs_bmbt_rec_base_t)xfs_mask64lo(21)) | - (xfs_bmbt_rec_base_t)(v << 21); -} - -/* - * Set the startoff field in a bmap extent record. - */ -void -xfs_bmbt_set_startoff( - xfs_bmbt_rec_host_t *r, - xfs_fileoff_t v) -{ - ASSERT((v & xfs_mask64hi(9)) == 0); - r->l0 = (r->l0 & (xfs_bmbt_rec_base_t) xfs_mask64hi(1)) | - ((xfs_bmbt_rec_base_t)v << 9) | - (r->l0 & (xfs_bmbt_rec_base_t)xfs_mask64lo(9)); -} - -/* - * Set the extent state field in a bmap extent record. - */ -void -xfs_bmbt_set_state( - xfs_bmbt_rec_host_t *r, - xfs_exntst_t v) -{ - ASSERT(v == XFS_EXT_NORM || v == XFS_EXT_UNWRITTEN); - if (v == XFS_EXT_NORM) - r->l0 &= xfs_mask64lo(64 - BMBT_EXNTFLAG_BITLEN); - else - r->l0 |= xfs_mask64hi(BMBT_EXNTFLAG_BITLEN); -} - -/* - * Convert in-memory form of btree root to on-disk form. - */ -void -xfs_bmbt_to_bmdr( - struct xfs_mount *mp, - struct xfs_btree_block *rblock, - int rblocklen, - xfs_bmdr_block_t *dblock, - int dblocklen) -{ - int dmxr; - xfs_bmbt_key_t *fkp; - __be64 *fpp; - xfs_bmbt_key_t *tkp; - __be64 *tpp; - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_CRC_MAGIC)); - ASSERT(uuid_equal(&rblock->bb_u.l.bb_uuid, - &mp->m_sb.sb_meta_uuid)); - ASSERT(rblock->bb_u.l.bb_blkno == - cpu_to_be64(XFS_BUF_DADDR_NULL)); - } else - ASSERT(rblock->bb_magic == cpu_to_be32(XFS_BMAP_MAGIC)); - ASSERT(rblock->bb_u.l.bb_leftsib == cpu_to_be64(NULLFSBLOCK)); - ASSERT(rblock->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK)); - ASSERT(rblock->bb_level != 0); - dblock->bb_level = rblock->bb_level; - dblock->bb_numrecs = rblock->bb_numrecs; - dmxr = xfs_bmdr_maxrecs(dblocklen, 0); - fkp = XFS_BMBT_KEY_ADDR(mp, rblock, 1); - tkp = XFS_BMDR_KEY_ADDR(dblock, 1); - fpp = XFS_BMAP_BROOT_PTR_ADDR(mp, rblock, 1, rblocklen); - tpp = XFS_BMDR_PTR_ADDR(dblock, 1, dmxr); - dmxr = be16_to_cpu(dblock->bb_numrecs); - memcpy(tkp, fkp, sizeof(*fkp) * dmxr); - memcpy(tpp, fpp, sizeof(*fpp) * dmxr); -} - -/* - * Check extent records, which have just been read, for - * any bit in the extent flag field. ASSERT on debug - * kernels, as this condition should not occur. - * Return an error condition (1) if any flags found, - * otherwise return 0. - */ - -int -xfs_check_nostate_extents( - xfs_ifork_t *ifp, - xfs_extnum_t idx, - xfs_extnum_t num) -{ - for (; num > 0; num--, idx++) { - xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, idx); - if ((ep->l0 >> - (64 - BMBT_EXNTFLAG_BITLEN)) != 0) { - ASSERT(0); - return 1; - } - } - return 0; -} - - -STATIC struct xfs_btree_cur * -xfs_bmbt_dup_cursor( - struct xfs_btree_cur *cur) -{ - struct xfs_btree_cur *new; - - new = xfs_bmbt_init_cursor(cur->bc_mp, cur->bc_tp, - cur->bc_private.b.ip, cur->bc_private.b.whichfork); - - /* - * Copy the firstblock, dfops, and flags values, - * since init cursor doesn't get them. - */ - new->bc_private.b.firstblock = cur->bc_private.b.firstblock; - new->bc_private.b.dfops = cur->bc_private.b.dfops; - new->bc_private.b.flags = cur->bc_private.b.flags; - - return new; -} - -STATIC void -xfs_bmbt_update_cursor( - struct xfs_btree_cur *src, - struct xfs_btree_cur *dst) -{ - ASSERT((dst->bc_private.b.firstblock != NULLFSBLOCK) || - (dst->bc_private.b.ip->i_d.di_flags & XFS_DIFLAG_REALTIME)); - ASSERT(dst->bc_private.b.dfops == src->bc_private.b.dfops); - - dst->bc_private.b.allocated += src->bc_private.b.allocated; - dst->bc_private.b.firstblock = src->bc_private.b.firstblock; - - src->bc_private.b.allocated = 0; -} - -STATIC int -xfs_bmbt_alloc_block( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *start, - union xfs_btree_ptr *new, - int *stat) -{ - xfs_alloc_arg_t args; /* block allocation args */ - int error; /* error return value */ - - memset(&args, 0, sizeof(args)); - args.tp = cur->bc_tp; - args.mp = cur->bc_mp; - args.fsbno = cur->bc_private.b.firstblock; - args.firstblock = args.fsbno; - xfs_rmap_ino_bmbt_owner(&args.oinfo, cur->bc_private.b.ip->i_ino, - cur->bc_private.b.whichfork); - - if (args.fsbno == NULLFSBLOCK) { - args.fsbno = be64_to_cpu(start->l); -try_another_ag: - args.type = XFS_ALLOCTYPE_START_BNO; - /* - * Make sure there is sufficient room left in the AG to - * complete a full tree split for an extent insert. If - * we are converting the middle part of an extent then - * we may need space for two tree splits. - * - * We are relying on the caller to make the correct block - * reservation for this operation to succeed. If the - * reservation amount is insufficient then we may fail a - * block allocation here and corrupt the filesystem. - */ - args.minleft = args.tp->t_blk_res; - } else if (cur->bc_private.b.dfops->dop_low) { - args.type = XFS_ALLOCTYPE_START_BNO; - } else { - args.type = XFS_ALLOCTYPE_NEAR_BNO; - } - - args.minlen = args.maxlen = args.prod = 1; - args.wasdel = cur->bc_private.b.flags & XFS_BTCUR_BPRV_WASDEL; - if (!args.wasdel && args.tp->t_blk_res == 0) { - error = -ENOSPC; - goto error0; - } - error = xfs_alloc_vextent(&args); - if (error) - goto error0; - - /* - * During a CoW operation, the allocation and bmbt updates occur in - * different transactions. The mapping code tries to put new bmbt - * blocks near extents being mapped, but the only way to guarantee this - * is if the alloc and the mapping happen in a single transaction that - * has a block reservation. That isn't the case here, so if we run out - * of space we'll try again with another AG. - */ - if (xfs_sb_version_hasreflink(&cur->bc_mp->m_sb) && - args.fsbno == NULLFSBLOCK && - args.type == XFS_ALLOCTYPE_NEAR_BNO) { - cur->bc_private.b.dfops->dop_low = true; - args.fsbno = cur->bc_private.b.firstblock; - goto try_another_ag; - } - - if (args.fsbno == NULLFSBLOCK && args.minleft) { - /* - * Could not find an AG with enough free space to satisfy - * a full btree split. Try again without minleft and if - * successful activate the lowspace algorithm. - */ - args.fsbno = 0; - args.type = XFS_ALLOCTYPE_FIRST_AG; - args.minleft = 0; - error = xfs_alloc_vextent(&args); - if (error) - goto error0; - cur->bc_private.b.dfops->dop_low = true; - } - if (args.fsbno == NULLFSBLOCK) { - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 0; - return 0; - } - ASSERT(args.len == 1); - cur->bc_private.b.firstblock = args.fsbno; - cur->bc_private.b.allocated++; - cur->bc_private.b.ip->i_d.di_nblocks++; - xfs_trans_log_inode(args.tp, cur->bc_private.b.ip, XFS_ILOG_CORE); - xfs_trans_mod_dquot_byino(args.tp, cur->bc_private.b.ip, - XFS_TRANS_DQ_BCOUNT, 1L); - - new->l = cpu_to_be64(args.fsbno); - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 1; - return 0; - - error0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; -} - -STATIC int -xfs_bmbt_free_block( - struct xfs_btree_cur *cur, - struct xfs_buf *bp) -{ - struct xfs_mount *mp = cur->bc_mp; - struct xfs_inode *ip = cur->bc_private.b.ip; - struct xfs_trans *tp = cur->bc_tp; - xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp)); - struct xfs_owner_info oinfo; - - xfs_rmap_ino_bmbt_owner(&oinfo, ip->i_ino, cur->bc_private.b.whichfork); - xfs_bmap_add_free(mp, cur->bc_private.b.dfops, fsbno, 1, &oinfo); - ip->i_d.di_nblocks--; - - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, -1L); - return 0; -} - -STATIC int -xfs_bmbt_get_minrecs( - struct xfs_btree_cur *cur, - int level) -{ - if (level == cur->bc_nlevels - 1) { - struct xfs_ifork *ifp; - - ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, - cur->bc_private.b.whichfork); - - return xfs_bmbt_maxrecs(cur->bc_mp, - ifp->if_broot_bytes, level == 0) / 2; - } - - return cur->bc_mp->m_bmap_dmnr[level != 0]; -} - -int -xfs_bmbt_get_maxrecs( - struct xfs_btree_cur *cur, - int level) -{ - if (level == cur->bc_nlevels - 1) { - struct xfs_ifork *ifp; - - ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, - cur->bc_private.b.whichfork); - - return xfs_bmbt_maxrecs(cur->bc_mp, - ifp->if_broot_bytes, level == 0); - } - - return cur->bc_mp->m_bmap_dmxr[level != 0]; - -} - -/* - * Get the maximum records we could store in the on-disk format. - * - * For non-root nodes this is equivalent to xfs_bmbt_get_maxrecs, but - * for the root node this checks the available space in the dinode fork - * so that we can resize the in-memory buffer to match it. After a - * resize to the maximum size this function returns the same value - * as xfs_bmbt_get_maxrecs for the root node, too. - */ -STATIC int -xfs_bmbt_get_dmaxrecs( - struct xfs_btree_cur *cur, - int level) -{ - if (level != cur->bc_nlevels - 1) - return cur->bc_mp->m_bmap_dmxr[level != 0]; - return xfs_bmdr_maxrecs(cur->bc_private.b.forksize, level == 0); -} - -STATIC void -xfs_bmbt_init_key_from_rec( - union xfs_btree_key *key, - union xfs_btree_rec *rec) -{ - key->bmbt.br_startoff = - cpu_to_be64(xfs_bmbt_disk_get_startoff(&rec->bmbt)); -} - -STATIC void -xfs_bmbt_init_rec_from_cur( - struct xfs_btree_cur *cur, - union xfs_btree_rec *rec) -{ - xfs_bmbt_disk_set_all(&rec->bmbt, &cur->bc_rec.b); -} - -STATIC void -xfs_bmbt_init_ptr_from_cur( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *ptr) -{ - ptr->l = 0; -} - -STATIC __int64_t -xfs_bmbt_key_diff( - struct xfs_btree_cur *cur, - union xfs_btree_key *key) -{ - return (__int64_t)be64_to_cpu(key->bmbt.br_startoff) - - cur->bc_rec.b.br_startoff; -} - -static bool -xfs_bmbt_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); - unsigned int level; - - switch (block->bb_magic) { - case cpu_to_be32(XFS_BMAP_CRC_MAGIC): - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return false; - if (!uuid_equal(&block->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid)) - return false; - if (be64_to_cpu(block->bb_u.l.bb_blkno) != bp->b_bn) - return false; - /* - * XXX: need a better way of verifying the owner here. Right now - * just make sure there has been one set. - */ - if (be64_to_cpu(block->bb_u.l.bb_owner) == 0) - return false; - /* fall through */ - case cpu_to_be32(XFS_BMAP_MAGIC): - break; - default: - return false; - } - - /* - * numrecs and level verification. - * - * We don't know what fork we belong to, so just verify that the level - * is less than the maximum of the two. Later checks will be more - * precise. - */ - level = be16_to_cpu(block->bb_level); - if (level > max(mp->m_bm_maxlevels[0], mp->m_bm_maxlevels[1])) - return false; - if (be16_to_cpu(block->bb_numrecs) > mp->m_bmap_dmxr[level != 0]) - return false; - - /* sibling pointer verification */ - if (!block->bb_u.l.bb_leftsib || - (block->bb_u.l.bb_leftsib != cpu_to_be64(NULLFSBLOCK) && - !XFS_FSB_SANITY_CHECK(mp, be64_to_cpu(block->bb_u.l.bb_leftsib)))) - return false; - if (!block->bb_u.l.bb_rightsib || - (block->bb_u.l.bb_rightsib != cpu_to_be64(NULLFSBLOCK) && - !XFS_FSB_SANITY_CHECK(mp, be64_to_cpu(block->bb_u.l.bb_rightsib)))) - return false; - - return true; -} - -static void -xfs_bmbt_read_verify( - struct xfs_buf *bp) -{ - if (!xfs_btree_lblock_verify_crc(bp)) - xfs_buf_ioerror(bp, -EFSBADCRC); - else if (!xfs_bmbt_verify(bp)) - xfs_buf_ioerror(bp, -EFSCORRUPTED); - - if (bp->b_error) { - trace_xfs_btree_corrupt(bp, _RET_IP_); - xfs_verifier_error(bp); - } -} - -static void -xfs_bmbt_write_verify( - struct xfs_buf *bp) -{ - if (!xfs_bmbt_verify(bp)) { - trace_xfs_btree_corrupt(bp, _RET_IP_); - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - return; - } - xfs_btree_lblock_calc_crc(bp); -} - -const struct xfs_buf_ops xfs_bmbt_buf_ops = { - .name = "xfs_bmbt", - .verify_read = xfs_bmbt_read_verify, - .verify_write = xfs_bmbt_write_verify, -}; - - -#if defined(DEBUG) || defined(XFS_WARN) -STATIC int -xfs_bmbt_keys_inorder( - struct xfs_btree_cur *cur, - union xfs_btree_key *k1, - union xfs_btree_key *k2) -{ - return be64_to_cpu(k1->bmbt.br_startoff) < - be64_to_cpu(k2->bmbt.br_startoff); -} - -STATIC int -xfs_bmbt_recs_inorder( - struct xfs_btree_cur *cur, - union xfs_btree_rec *r1, - union xfs_btree_rec *r2) -{ - return xfs_bmbt_disk_get_startoff(&r1->bmbt) + - xfs_bmbt_disk_get_blockcount(&r1->bmbt) <= - xfs_bmbt_disk_get_startoff(&r2->bmbt); -} -#endif /* DEBUG */ - -static const struct xfs_btree_ops xfs_bmbt_ops = { - .rec_len = sizeof(xfs_bmbt_rec_t), - .key_len = sizeof(xfs_bmbt_key_t), - - .dup_cursor = xfs_bmbt_dup_cursor, - .update_cursor = xfs_bmbt_update_cursor, - .alloc_block = xfs_bmbt_alloc_block, - .free_block = xfs_bmbt_free_block, - .get_maxrecs = xfs_bmbt_get_maxrecs, - .get_minrecs = xfs_bmbt_get_minrecs, - .get_dmaxrecs = xfs_bmbt_get_dmaxrecs, - .init_key_from_rec = xfs_bmbt_init_key_from_rec, - .init_rec_from_cur = xfs_bmbt_init_rec_from_cur, - .init_ptr_from_cur = xfs_bmbt_init_ptr_from_cur, - .key_diff = xfs_bmbt_key_diff, - .buf_ops = &xfs_bmbt_buf_ops, -#if defined(DEBUG) || defined(XFS_WARN) - .keys_inorder = xfs_bmbt_keys_inorder, - .recs_inorder = xfs_bmbt_recs_inorder, -#endif -}; - -/* - * Allocate a new bmap btree cursor. - */ -struct xfs_btree_cur * /* new bmap btree cursor */ -xfs_bmbt_init_cursor( - struct xfs_mount *mp, /* file system mount point */ - struct xfs_trans *tp, /* transaction pointer */ - struct xfs_inode *ip, /* inode owning the btree */ - int whichfork) /* data or attr fork */ -{ - struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); - struct xfs_btree_cur *cur; - ASSERT(whichfork != XFS_COW_FORK); - - cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP); - - cur->bc_tp = tp; - cur->bc_mp = mp; - cur->bc_nlevels = be16_to_cpu(ifp->if_broot->bb_level) + 1; - cur->bc_btnum = XFS_BTNUM_BMAP; - cur->bc_blocklog = mp->m_sb.sb_blocklog; - - cur->bc_ops = &xfs_bmbt_ops; - cur->bc_flags = XFS_BTREE_LONG_PTRS | XFS_BTREE_ROOT_IN_INODE; - if (xfs_sb_version_hascrc(&mp->m_sb)) - cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; - - cur->bc_private.b.forksize = XFS_IFORK_SIZE(ip, whichfork); - cur->bc_private.b.ip = ip; - cur->bc_private.b.firstblock = NULLFSBLOCK; - cur->bc_private.b.dfops = NULL; - cur->bc_private.b.allocated = 0; - cur->bc_private.b.flags = 0; - cur->bc_private.b.whichfork = whichfork; - - return cur; -} - -/* - * Calculate number of records in a bmap btree block. - */ -int -xfs_bmbt_maxrecs( - struct xfs_mount *mp, - int blocklen, - int leaf) -{ - blocklen -= XFS_BMBT_BLOCK_LEN(mp); - - if (leaf) - return blocklen / sizeof(xfs_bmbt_rec_t); - return blocklen / (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t)); -} - -/* - * Calculate number of records in a bmap btree inode root. - */ -int -xfs_bmdr_maxrecs( - int blocklen, - int leaf) -{ - blocklen -= sizeof(xfs_bmdr_block_t); - - if (leaf) - return blocklen / sizeof(xfs_bmdr_rec_t); - return blocklen / (sizeof(xfs_bmdr_key_t) + sizeof(xfs_bmdr_ptr_t)); -} - -/* - * Change the owner of a btree format fork fo the inode passed in. Change it to - * the owner of that is passed in so that we can change owners before or after - * we switch forks between inodes. The operation that the caller is doing will - * determine whether is needs to change owner before or after the switch. - * - * For demand paged transactional modification, the fork switch should be done - * after reading in all the blocks, modifying them and pinning them in the - * transaction. For modification when the buffers are already pinned in memory, - * the fork switch can be done before changing the owner as we won't need to - * validate the owner until the btree buffers are unpinned and writes can occur - * again. - * - * For recovery based ownership change, there is no transactional context and - * so a buffer list must be supplied so that we can record the buffers that we - * modified for the caller to issue IO on. - */ -int -xfs_bmbt_change_owner( - struct xfs_trans *tp, - struct xfs_inode *ip, - int whichfork, - xfs_ino_t new_owner, - struct list_head *buffer_list) -{ - struct xfs_btree_cur *cur; - int error; - - ASSERT(tp || buffer_list); - ASSERT(!(tp && buffer_list)); - if (whichfork == XFS_DATA_FORK) - ASSERT(ip->i_d.di_format == XFS_DINODE_FMT_BTREE); - else - ASSERT(ip->i_d.di_aformat == XFS_DINODE_FMT_BTREE); - - cur = xfs_bmbt_init_cursor(ip->i_mount, tp, ip, whichfork); - if (!cur) - return -ENOMEM; - - error = xfs_btree_change_owner(cur, new_owner, buffer_list); - xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); - return error; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_bmap_btree.h b/src/linux/fs/xfs/libxfs/xfs_bmap_btree.h deleted file mode 100644 index 819a8a4..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_bmap_btree.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2000,2002-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_BMAP_BTREE_H__ -#define __XFS_BMAP_BTREE_H__ - -struct xfs_btree_cur; -struct xfs_btree_block; -struct xfs_mount; -struct xfs_inode; -struct xfs_trans; - -/* - * Extent state and extent format macros. - */ -#define XFS_EXTFMT_INODE(x) \ - (xfs_sb_version_hasextflgbit(&((x)->i_mount->m_sb)) ? \ - XFS_EXTFMT_HASSTATE : XFS_EXTFMT_NOSTATE) -#define ISUNWRITTEN(x) ((x)->br_state == XFS_EXT_UNWRITTEN) - -/* - * Btree block header size depends on a superblock flag. - */ -#define XFS_BMBT_BLOCK_LEN(mp) \ - (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \ - XFS_BTREE_LBLOCK_CRC_LEN : XFS_BTREE_LBLOCK_LEN) - -#define XFS_BMBT_REC_ADDR(mp, block, index) \ - ((xfs_bmbt_rec_t *) \ - ((char *)(block) + \ - XFS_BMBT_BLOCK_LEN(mp) + \ - ((index) - 1) * sizeof(xfs_bmbt_rec_t))) - -#define XFS_BMBT_KEY_ADDR(mp, block, index) \ - ((xfs_bmbt_key_t *) \ - ((char *)(block) + \ - XFS_BMBT_BLOCK_LEN(mp) + \ - ((index) - 1) * sizeof(xfs_bmbt_key_t))) - -#define XFS_BMBT_PTR_ADDR(mp, block, index, maxrecs) \ - ((xfs_bmbt_ptr_t *) \ - ((char *)(block) + \ - XFS_BMBT_BLOCK_LEN(mp) + \ - (maxrecs) * sizeof(xfs_bmbt_key_t) + \ - ((index) - 1) * sizeof(xfs_bmbt_ptr_t))) - -#define XFS_BMDR_REC_ADDR(block, index) \ - ((xfs_bmdr_rec_t *) \ - ((char *)(block) + \ - sizeof(struct xfs_bmdr_block) + \ - ((index) - 1) * sizeof(xfs_bmdr_rec_t))) - -#define XFS_BMDR_KEY_ADDR(block, index) \ - ((xfs_bmdr_key_t *) \ - ((char *)(block) + \ - sizeof(struct xfs_bmdr_block) + \ - ((index) - 1) * sizeof(xfs_bmdr_key_t))) - -#define XFS_BMDR_PTR_ADDR(block, index, maxrecs) \ - ((xfs_bmdr_ptr_t *) \ - ((char *)(block) + \ - sizeof(struct xfs_bmdr_block) + \ - (maxrecs) * sizeof(xfs_bmdr_key_t) + \ - ((index) - 1) * sizeof(xfs_bmdr_ptr_t))) - -/* - * These are to be used when we know the size of the block and - * we don't have a cursor. - */ -#define XFS_BMAP_BROOT_PTR_ADDR(mp, bb, i, sz) \ - XFS_BMBT_PTR_ADDR(mp, bb, i, xfs_bmbt_maxrecs(mp, sz, 0)) - -#define XFS_BMAP_BROOT_SPACE_CALC(mp, nrecs) \ - (int)(XFS_BMBT_BLOCK_LEN(mp) + \ - ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t)))) - -#define XFS_BMAP_BROOT_SPACE(mp, bb) \ - (XFS_BMAP_BROOT_SPACE_CALC(mp, be16_to_cpu((bb)->bb_numrecs))) -#define XFS_BMDR_SPACE_CALC(nrecs) \ - (int)(sizeof(xfs_bmdr_block_t) + \ - ((nrecs) * (sizeof(xfs_bmbt_key_t) + sizeof(xfs_bmbt_ptr_t)))) -#define XFS_BMAP_BMDR_SPACE(bb) \ - (XFS_BMDR_SPACE_CALC(be16_to_cpu((bb)->bb_numrecs))) - -/* - * Maximum number of bmap btree levels. - */ -#define XFS_BM_MAXLEVELS(mp,w) ((mp)->m_bm_maxlevels[(w)]) - -/* - * Prototypes for xfs_bmap.c to call. - */ -extern void xfs_bmdr_to_bmbt(struct xfs_inode *, xfs_bmdr_block_t *, int, - struct xfs_btree_block *, int); -extern void xfs_bmbt_get_all(xfs_bmbt_rec_host_t *r, xfs_bmbt_irec_t *s); -extern xfs_filblks_t xfs_bmbt_get_blockcount(xfs_bmbt_rec_host_t *r); -extern xfs_fsblock_t xfs_bmbt_get_startblock(xfs_bmbt_rec_host_t *r); -extern xfs_fileoff_t xfs_bmbt_get_startoff(xfs_bmbt_rec_host_t *r); -extern xfs_exntst_t xfs_bmbt_get_state(xfs_bmbt_rec_host_t *r); - -extern xfs_filblks_t xfs_bmbt_disk_get_blockcount(xfs_bmbt_rec_t *r); -extern xfs_fileoff_t xfs_bmbt_disk_get_startoff(xfs_bmbt_rec_t *r); - -extern void xfs_bmbt_set_all(xfs_bmbt_rec_host_t *r, xfs_bmbt_irec_t *s); -extern void xfs_bmbt_set_allf(xfs_bmbt_rec_host_t *r, xfs_fileoff_t o, - xfs_fsblock_t b, xfs_filblks_t c, xfs_exntst_t v); -extern void xfs_bmbt_set_blockcount(xfs_bmbt_rec_host_t *r, xfs_filblks_t v); -extern void xfs_bmbt_set_startblock(xfs_bmbt_rec_host_t *r, xfs_fsblock_t v); -extern void xfs_bmbt_set_startoff(xfs_bmbt_rec_host_t *r, xfs_fileoff_t v); -extern void xfs_bmbt_set_state(xfs_bmbt_rec_host_t *r, xfs_exntst_t v); - -extern void xfs_bmbt_disk_set_allf(xfs_bmbt_rec_t *r, xfs_fileoff_t o, - xfs_fsblock_t b, xfs_filblks_t c, xfs_exntst_t v); - -extern void xfs_bmbt_to_bmdr(struct xfs_mount *, struct xfs_btree_block *, int, - xfs_bmdr_block_t *, int); - -extern int xfs_bmbt_get_maxrecs(struct xfs_btree_cur *, int level); -extern int xfs_bmdr_maxrecs(int blocklen, int leaf); -extern int xfs_bmbt_maxrecs(struct xfs_mount *, int blocklen, int leaf); - -extern int xfs_bmbt_change_owner(struct xfs_trans *tp, struct xfs_inode *ip, - int whichfork, xfs_ino_t new_owner, - struct list_head *buffer_list); - -extern struct xfs_btree_cur *xfs_bmbt_init_cursor(struct xfs_mount *, - struct xfs_trans *, struct xfs_inode *, int); - -#endif /* __XFS_BMAP_BTREE_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_btree.c b/src/linux/fs/xfs/libxfs/xfs_btree.c deleted file mode 100644 index 0e80993..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_btree.c +++ /dev/null @@ -1,4850 +0,0 @@ -/* - * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_buf_item.h" -#include "xfs_btree.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_cksum.h" -#include "xfs_alloc.h" -#include "xfs_log.h" - -/* - * Cursor allocation zone. - */ -kmem_zone_t *xfs_btree_cur_zone; - -/* - * Btree magic numbers. - */ -static const __uint32_t xfs_magics[2][XFS_BTNUM_MAX] = { - { XFS_ABTB_MAGIC, XFS_ABTC_MAGIC, 0, XFS_BMAP_MAGIC, XFS_IBT_MAGIC, - XFS_FIBT_MAGIC, 0 }, - { XFS_ABTB_CRC_MAGIC, XFS_ABTC_CRC_MAGIC, XFS_RMAP_CRC_MAGIC, - XFS_BMAP_CRC_MAGIC, XFS_IBT_CRC_MAGIC, XFS_FIBT_CRC_MAGIC, - XFS_REFC_CRC_MAGIC } -}; -#define xfs_btree_magic(cur) \ - xfs_magics[!!((cur)->bc_flags & XFS_BTREE_CRC_BLOCKS)][cur->bc_btnum] - -STATIC int /* error (0 or EFSCORRUPTED) */ -xfs_btree_check_lblock( - struct xfs_btree_cur *cur, /* btree cursor */ - struct xfs_btree_block *block, /* btree long form block pointer */ - int level, /* level of the btree block */ - struct xfs_buf *bp) /* buffer for block, if any */ -{ - int lblock_ok = 1; /* block passes checks */ - struct xfs_mount *mp; /* file system mount point */ - - mp = cur->bc_mp; - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - lblock_ok = lblock_ok && - uuid_equal(&block->bb_u.l.bb_uuid, - &mp->m_sb.sb_meta_uuid) && - block->bb_u.l.bb_blkno == cpu_to_be64( - bp ? bp->b_bn : XFS_BUF_DADDR_NULL); - } - - lblock_ok = lblock_ok && - be32_to_cpu(block->bb_magic) == xfs_btree_magic(cur) && - be16_to_cpu(block->bb_level) == level && - be16_to_cpu(block->bb_numrecs) <= - cur->bc_ops->get_maxrecs(cur, level) && - block->bb_u.l.bb_leftsib && - (block->bb_u.l.bb_leftsib == cpu_to_be64(NULLFSBLOCK) || - XFS_FSB_SANITY_CHECK(mp, - be64_to_cpu(block->bb_u.l.bb_leftsib))) && - block->bb_u.l.bb_rightsib && - (block->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK) || - XFS_FSB_SANITY_CHECK(mp, - be64_to_cpu(block->bb_u.l.bb_rightsib))); - - if (unlikely(XFS_TEST_ERROR(!lblock_ok, mp, - XFS_ERRTAG_BTREE_CHECK_LBLOCK, - XFS_RANDOM_BTREE_CHECK_LBLOCK))) { - if (bp) - trace_xfs_btree_corrupt(bp, _RET_IP_); - XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp); - return -EFSCORRUPTED; - } - return 0; -} - -STATIC int /* error (0 or EFSCORRUPTED) */ -xfs_btree_check_sblock( - struct xfs_btree_cur *cur, /* btree cursor */ - struct xfs_btree_block *block, /* btree short form block pointer */ - int level, /* level of the btree block */ - struct xfs_buf *bp) /* buffer containing block */ -{ - struct xfs_mount *mp; /* file system mount point */ - struct xfs_buf *agbp; /* buffer for ag. freespace struct */ - struct xfs_agf *agf; /* ag. freespace structure */ - xfs_agblock_t agflen; /* native ag. freespace length */ - int sblock_ok = 1; /* block passes checks */ - - mp = cur->bc_mp; - agbp = cur->bc_private.a.agbp; - agf = XFS_BUF_TO_AGF(agbp); - agflen = be32_to_cpu(agf->agf_length); - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - sblock_ok = sblock_ok && - uuid_equal(&block->bb_u.s.bb_uuid, - &mp->m_sb.sb_meta_uuid) && - block->bb_u.s.bb_blkno == cpu_to_be64( - bp ? bp->b_bn : XFS_BUF_DADDR_NULL); - } - - sblock_ok = sblock_ok && - be32_to_cpu(block->bb_magic) == xfs_btree_magic(cur) && - be16_to_cpu(block->bb_level) == level && - be16_to_cpu(block->bb_numrecs) <= - cur->bc_ops->get_maxrecs(cur, level) && - (block->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK) || - be32_to_cpu(block->bb_u.s.bb_leftsib) < agflen) && - block->bb_u.s.bb_leftsib && - (block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK) || - be32_to_cpu(block->bb_u.s.bb_rightsib) < agflen) && - block->bb_u.s.bb_rightsib; - - if (unlikely(XFS_TEST_ERROR(!sblock_ok, mp, - XFS_ERRTAG_BTREE_CHECK_SBLOCK, - XFS_RANDOM_BTREE_CHECK_SBLOCK))) { - if (bp) - trace_xfs_btree_corrupt(bp, _RET_IP_); - XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp); - return -EFSCORRUPTED; - } - return 0; -} - -/* - * Debug routine: check that block header is ok. - */ -int -xfs_btree_check_block( - struct xfs_btree_cur *cur, /* btree cursor */ - struct xfs_btree_block *block, /* generic btree block pointer */ - int level, /* level of the btree block */ - struct xfs_buf *bp) /* buffer containing block, if any */ -{ - if (cur->bc_flags & XFS_BTREE_LONG_PTRS) - return xfs_btree_check_lblock(cur, block, level, bp); - else - return xfs_btree_check_sblock(cur, block, level, bp); -} - -/* - * Check that (long) pointer is ok. - */ -int /* error (0 or EFSCORRUPTED) */ -xfs_btree_check_lptr( - struct xfs_btree_cur *cur, /* btree cursor */ - xfs_fsblock_t bno, /* btree block disk address */ - int level) /* btree block level */ -{ - XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, - level > 0 && - bno != NULLFSBLOCK && - XFS_FSB_SANITY_CHECK(cur->bc_mp, bno)); - return 0; -} - -#ifdef DEBUG -/* - * Check that (short) pointer is ok. - */ -STATIC int /* error (0 or EFSCORRUPTED) */ -xfs_btree_check_sptr( - struct xfs_btree_cur *cur, /* btree cursor */ - xfs_agblock_t bno, /* btree block disk address */ - int level) /* btree block level */ -{ - xfs_agblock_t agblocks = cur->bc_mp->m_sb.sb_agblocks; - - XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, - level > 0 && - bno != NULLAGBLOCK && - bno != 0 && - bno < agblocks); - return 0; -} - -/* - * Check that block ptr is ok. - */ -STATIC int /* error (0 or EFSCORRUPTED) */ -xfs_btree_check_ptr( - struct xfs_btree_cur *cur, /* btree cursor */ - union xfs_btree_ptr *ptr, /* btree block disk address */ - int index, /* offset from ptr to check */ - int level) /* btree block level */ -{ - if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { - return xfs_btree_check_lptr(cur, - be64_to_cpu((&ptr->l)[index]), level); - } else { - return xfs_btree_check_sptr(cur, - be32_to_cpu((&ptr->s)[index]), level); - } -} -#endif - -/* - * Calculate CRC on the whole btree block and stuff it into the - * long-form btree header. - * - * Prior to calculting the CRC, pull the LSN out of the buffer log item and put - * it into the buffer so recovery knows what the last modification was that made - * it to disk. - */ -void -xfs_btree_lblock_calc_crc( - struct xfs_buf *bp) -{ - struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); - struct xfs_buf_log_item *bip = bp->b_fspriv; - - if (!xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb)) - return; - if (bip) - block->bb_u.l.bb_lsn = cpu_to_be64(bip->bli_item.li_lsn); - xfs_buf_update_cksum(bp, XFS_BTREE_LBLOCK_CRC_OFF); -} - -bool -xfs_btree_lblock_verify_crc( - struct xfs_buf *bp) -{ - struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); - struct xfs_mount *mp = bp->b_target->bt_mount; - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - if (!xfs_log_check_lsn(mp, be64_to_cpu(block->bb_u.l.bb_lsn))) - return false; - return xfs_buf_verify_cksum(bp, XFS_BTREE_LBLOCK_CRC_OFF); - } - - return true; -} - -/* - * Calculate CRC on the whole btree block and stuff it into the - * short-form btree header. - * - * Prior to calculting the CRC, pull the LSN out of the buffer log item and put - * it into the buffer so recovery knows what the last modification was that made - * it to disk. - */ -void -xfs_btree_sblock_calc_crc( - struct xfs_buf *bp) -{ - struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); - struct xfs_buf_log_item *bip = bp->b_fspriv; - - if (!xfs_sb_version_hascrc(&bp->b_target->bt_mount->m_sb)) - return; - if (bip) - block->bb_u.s.bb_lsn = cpu_to_be64(bip->bli_item.li_lsn); - xfs_buf_update_cksum(bp, XFS_BTREE_SBLOCK_CRC_OFF); -} - -bool -xfs_btree_sblock_verify_crc( - struct xfs_buf *bp) -{ - struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); - struct xfs_mount *mp = bp->b_target->bt_mount; - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - if (!xfs_log_check_lsn(mp, be64_to_cpu(block->bb_u.s.bb_lsn))) - return false; - return xfs_buf_verify_cksum(bp, XFS_BTREE_SBLOCK_CRC_OFF); - } - - return true; -} - -static int -xfs_btree_free_block( - struct xfs_btree_cur *cur, - struct xfs_buf *bp) -{ - int error; - - error = cur->bc_ops->free_block(cur, bp); - if (!error) { - xfs_trans_binval(cur->bc_tp, bp); - XFS_BTREE_STATS_INC(cur, free); - } - return error; -} - -/* - * Delete the btree cursor. - */ -void -xfs_btree_del_cursor( - xfs_btree_cur_t *cur, /* btree cursor */ - int error) /* del because of error */ -{ - int i; /* btree level */ - - /* - * Clear the buffer pointers, and release the buffers. - * If we're doing this in the face of an error, we - * need to make sure to inspect all of the entries - * in the bc_bufs array for buffers to be unlocked. - * This is because some of the btree code works from - * level n down to 0, and if we get an error along - * the way we won't have initialized all the entries - * down to 0. - */ - for (i = 0; i < cur->bc_nlevels; i++) { - if (cur->bc_bufs[i]) - xfs_trans_brelse(cur->bc_tp, cur->bc_bufs[i]); - else if (!error) - break; - } - /* - * Can't free a bmap cursor without having dealt with the - * allocated indirect blocks' accounting. - */ - ASSERT(cur->bc_btnum != XFS_BTNUM_BMAP || - cur->bc_private.b.allocated == 0); - /* - * Free the cursor. - */ - kmem_zone_free(xfs_btree_cur_zone, cur); -} - -/* - * Duplicate the btree cursor. - * Allocate a new one, copy the record, re-get the buffers. - */ -int /* error */ -xfs_btree_dup_cursor( - xfs_btree_cur_t *cur, /* input cursor */ - xfs_btree_cur_t **ncur) /* output cursor */ -{ - xfs_buf_t *bp; /* btree block's buffer pointer */ - int error; /* error return value */ - int i; /* level number of btree block */ - xfs_mount_t *mp; /* mount structure for filesystem */ - xfs_btree_cur_t *new; /* new cursor value */ - xfs_trans_t *tp; /* transaction pointer, can be NULL */ - - tp = cur->bc_tp; - mp = cur->bc_mp; - - /* - * Allocate a new cursor like the old one. - */ - new = cur->bc_ops->dup_cursor(cur); - - /* - * Copy the record currently in the cursor. - */ - new->bc_rec = cur->bc_rec; - - /* - * For each level current, re-get the buffer and copy the ptr value. - */ - for (i = 0; i < new->bc_nlevels; i++) { - new->bc_ptrs[i] = cur->bc_ptrs[i]; - new->bc_ra[i] = cur->bc_ra[i]; - bp = cur->bc_bufs[i]; - if (bp) { - error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, - XFS_BUF_ADDR(bp), mp->m_bsize, - 0, &bp, - cur->bc_ops->buf_ops); - if (error) { - xfs_btree_del_cursor(new, error); - *ncur = NULL; - return error; - } - } - new->bc_bufs[i] = bp; - } - *ncur = new; - return 0; -} - -/* - * XFS btree block layout and addressing: - * - * There are two types of blocks in the btree: leaf and non-leaf blocks. - * - * The leaf record start with a header then followed by records containing - * the values. A non-leaf block also starts with the same header, and - * then first contains lookup keys followed by an equal number of pointers - * to the btree blocks at the previous level. - * - * +--------+-------+-------+-------+-------+-------+-------+ - * Leaf: | header | rec 1 | rec 2 | rec 3 | rec 4 | rec 5 | rec N | - * +--------+-------+-------+-------+-------+-------+-------+ - * - * +--------+-------+-------+-------+-------+-------+-------+ - * Non-Leaf: | header | key 1 | key 2 | key N | ptr 1 | ptr 2 | ptr N | - * +--------+-------+-------+-------+-------+-------+-------+ - * - * The header is called struct xfs_btree_block for reasons better left unknown - * and comes in different versions for short (32bit) and long (64bit) block - * pointers. The record and key structures are defined by the btree instances - * and opaque to the btree core. The block pointers are simple disk endian - * integers, available in a short (32bit) and long (64bit) variant. - * - * The helpers below calculate the offset of a given record, key or pointer - * into a btree block (xfs_btree_*_offset) or return a pointer to the given - * record, key or pointer (xfs_btree_*_addr). Note that all addressing - * inside the btree block is done using indices starting at one, not zero! - * - * If XFS_BTREE_OVERLAPPING is set, then this btree supports keys containing - * overlapping intervals. In such a tree, records are still sorted lowest to - * highest and indexed by the smallest key value that refers to the record. - * However, nodes are different: each pointer has two associated keys -- one - * indexing the lowest key available in the block(s) below (the same behavior - * as the key in a regular btree) and another indexing the highest key - * available in the block(s) below. Because records are /not/ sorted by the - * highest key, all leaf block updates require us to compute the highest key - * that matches any record in the leaf and to recursively update the high keys - * in the nodes going further up in the tree, if necessary. Nodes look like - * this: - * - * +--------+-----+-----+-----+-----+-----+-------+-------+-----+ - * Non-Leaf: | header | lo1 | hi1 | lo2 | hi2 | ... | ptr 1 | ptr 2 | ... | - * +--------+-----+-----+-----+-----+-----+-------+-------+-----+ - * - * To perform an interval query on an overlapped tree, perform the usual - * depth-first search and use the low and high keys to decide if we can skip - * that particular node. If a leaf node is reached, return the records that - * intersect the interval. Note that an interval query may return numerous - * entries. For a non-overlapped tree, simply search for the record associated - * with the lowest key and iterate forward until a non-matching record is - * found. Section 14.3 ("Interval Trees") of _Introduction to Algorithms_ by - * Cormen, Leiserson, Rivest, and Stein (2nd or 3rd ed. only) discuss this in - * more detail. - * - * Why do we care about overlapping intervals? Let's say you have a bunch of - * reverse mapping records on a reflink filesystem: - * - * 1: +- file A startblock B offset C length D -----------+ - * 2: +- file E startblock F offset G length H --------------+ - * 3: +- file I startblock F offset J length K --+ - * 4: +- file L... --+ - * - * Now say we want to map block (B+D) into file A at offset (C+D). Ideally, - * we'd simply increment the length of record 1. But how do we find the record - * that ends at (B+D-1) (i.e. record 1)? A LE lookup of (B+D-1) would return - * record 3 because the keys are ordered first by startblock. An interval - * query would return records 1 and 2 because they both overlap (B+D-1), and - * from that we can pick out record 1 as the appropriate left neighbor. - * - * In the non-overlapped case you can do a LE lookup and decrement the cursor - * because a record's interval must end before the next record. - */ - -/* - * Return size of the btree block header for this btree instance. - */ -static inline size_t xfs_btree_block_len(struct xfs_btree_cur *cur) -{ - if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { - if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) - return XFS_BTREE_LBLOCK_CRC_LEN; - return XFS_BTREE_LBLOCK_LEN; - } - if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) - return XFS_BTREE_SBLOCK_CRC_LEN; - return XFS_BTREE_SBLOCK_LEN; -} - -/* - * Return size of btree block pointers for this btree instance. - */ -static inline size_t xfs_btree_ptr_len(struct xfs_btree_cur *cur) -{ - return (cur->bc_flags & XFS_BTREE_LONG_PTRS) ? - sizeof(__be64) : sizeof(__be32); -} - -/* - * Calculate offset of the n-th record in a btree block. - */ -STATIC size_t -xfs_btree_rec_offset( - struct xfs_btree_cur *cur, - int n) -{ - return xfs_btree_block_len(cur) + - (n - 1) * cur->bc_ops->rec_len; -} - -/* - * Calculate offset of the n-th key in a btree block. - */ -STATIC size_t -xfs_btree_key_offset( - struct xfs_btree_cur *cur, - int n) -{ - return xfs_btree_block_len(cur) + - (n - 1) * cur->bc_ops->key_len; -} - -/* - * Calculate offset of the n-th high key in a btree block. - */ -STATIC size_t -xfs_btree_high_key_offset( - struct xfs_btree_cur *cur, - int n) -{ - return xfs_btree_block_len(cur) + - (n - 1) * cur->bc_ops->key_len + (cur->bc_ops->key_len / 2); -} - -/* - * Calculate offset of the n-th block pointer in a btree block. - */ -STATIC size_t -xfs_btree_ptr_offset( - struct xfs_btree_cur *cur, - int n, - int level) -{ - return xfs_btree_block_len(cur) + - cur->bc_ops->get_maxrecs(cur, level) * cur->bc_ops->key_len + - (n - 1) * xfs_btree_ptr_len(cur); -} - -/* - * Return a pointer to the n-th record in the btree block. - */ -STATIC union xfs_btree_rec * -xfs_btree_rec_addr( - struct xfs_btree_cur *cur, - int n, - struct xfs_btree_block *block) -{ - return (union xfs_btree_rec *) - ((char *)block + xfs_btree_rec_offset(cur, n)); -} - -/* - * Return a pointer to the n-th key in the btree block. - */ -STATIC union xfs_btree_key * -xfs_btree_key_addr( - struct xfs_btree_cur *cur, - int n, - struct xfs_btree_block *block) -{ - return (union xfs_btree_key *) - ((char *)block + xfs_btree_key_offset(cur, n)); -} - -/* - * Return a pointer to the n-th high key in the btree block. - */ -STATIC union xfs_btree_key * -xfs_btree_high_key_addr( - struct xfs_btree_cur *cur, - int n, - struct xfs_btree_block *block) -{ - return (union xfs_btree_key *) - ((char *)block + xfs_btree_high_key_offset(cur, n)); -} - -/* - * Return a pointer to the n-th block pointer in the btree block. - */ -STATIC union xfs_btree_ptr * -xfs_btree_ptr_addr( - struct xfs_btree_cur *cur, - int n, - struct xfs_btree_block *block) -{ - int level = xfs_btree_get_level(block); - - ASSERT(block->bb_level != 0); - - return (union xfs_btree_ptr *) - ((char *)block + xfs_btree_ptr_offset(cur, n, level)); -} - -/* - * Get the root block which is stored in the inode. - * - * For now this btree implementation assumes the btree root is always - * stored in the if_broot field of an inode fork. - */ -STATIC struct xfs_btree_block * -xfs_btree_get_iroot( - struct xfs_btree_cur *cur) -{ - struct xfs_ifork *ifp; - - ifp = XFS_IFORK_PTR(cur->bc_private.b.ip, cur->bc_private.b.whichfork); - return (struct xfs_btree_block *)ifp->if_broot; -} - -/* - * Retrieve the block pointer from the cursor at the given level. - * This may be an inode btree root or from a buffer. - */ -STATIC struct xfs_btree_block * /* generic btree block pointer */ -xfs_btree_get_block( - struct xfs_btree_cur *cur, /* btree cursor */ - int level, /* level in btree */ - struct xfs_buf **bpp) /* buffer containing the block */ -{ - if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && - (level == cur->bc_nlevels - 1)) { - *bpp = NULL; - return xfs_btree_get_iroot(cur); - } - - *bpp = cur->bc_bufs[level]; - return XFS_BUF_TO_BLOCK(*bpp); -} - -/* - * Get a buffer for the block, return it with no data read. - * Long-form addressing. - */ -xfs_buf_t * /* buffer for fsbno */ -xfs_btree_get_bufl( - xfs_mount_t *mp, /* file system mount point */ - xfs_trans_t *tp, /* transaction pointer */ - xfs_fsblock_t fsbno, /* file system block number */ - uint lock) /* lock flags for get_buf */ -{ - xfs_daddr_t d; /* real disk block address */ - - ASSERT(fsbno != NULLFSBLOCK); - d = XFS_FSB_TO_DADDR(mp, fsbno); - return xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock); -} - -/* - * Get a buffer for the block, return it with no data read. - * Short-form addressing. - */ -xfs_buf_t * /* buffer for agno/agbno */ -xfs_btree_get_bufs( - xfs_mount_t *mp, /* file system mount point */ - xfs_trans_t *tp, /* transaction pointer */ - xfs_agnumber_t agno, /* allocation group number */ - xfs_agblock_t agbno, /* allocation group block number */ - uint lock) /* lock flags for get_buf */ -{ - xfs_daddr_t d; /* real disk block address */ - - ASSERT(agno != NULLAGNUMBER); - ASSERT(agbno != NULLAGBLOCK); - d = XFS_AGB_TO_DADDR(mp, agno, agbno); - return xfs_trans_get_buf(tp, mp->m_ddev_targp, d, mp->m_bsize, lock); -} - -/* - * Check for the cursor referring to the last block at the given level. - */ -int /* 1=is last block, 0=not last block */ -xfs_btree_islastblock( - xfs_btree_cur_t *cur, /* btree cursor */ - int level) /* level to check */ -{ - struct xfs_btree_block *block; /* generic btree block pointer */ - xfs_buf_t *bp; /* buffer containing block */ - - block = xfs_btree_get_block(cur, level, &bp); - xfs_btree_check_block(cur, block, level, bp); - if (cur->bc_flags & XFS_BTREE_LONG_PTRS) - return block->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK); - else - return block->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK); -} - -/* - * Change the cursor to point to the first record at the given level. - * Other levels are unaffected. - */ -STATIC int /* success=1, failure=0 */ -xfs_btree_firstrec( - xfs_btree_cur_t *cur, /* btree cursor */ - int level) /* level to change */ -{ - struct xfs_btree_block *block; /* generic btree block pointer */ - xfs_buf_t *bp; /* buffer containing block */ - - /* - * Get the block pointer for this level. - */ - block = xfs_btree_get_block(cur, level, &bp); - xfs_btree_check_block(cur, block, level, bp); - /* - * It's empty, there is no such record. - */ - if (!block->bb_numrecs) - return 0; - /* - * Set the ptr value to 1, that's the first record/key. - */ - cur->bc_ptrs[level] = 1; - return 1; -} - -/* - * Change the cursor to point to the last record in the current block - * at the given level. Other levels are unaffected. - */ -STATIC int /* success=1, failure=0 */ -xfs_btree_lastrec( - xfs_btree_cur_t *cur, /* btree cursor */ - int level) /* level to change */ -{ - struct xfs_btree_block *block; /* generic btree block pointer */ - xfs_buf_t *bp; /* buffer containing block */ - - /* - * Get the block pointer for this level. - */ - block = xfs_btree_get_block(cur, level, &bp); - xfs_btree_check_block(cur, block, level, bp); - /* - * It's empty, there is no such record. - */ - if (!block->bb_numrecs) - return 0; - /* - * Set the ptr value to numrecs, that's the last record/key. - */ - cur->bc_ptrs[level] = be16_to_cpu(block->bb_numrecs); - return 1; -} - -/* - * Compute first and last byte offsets for the fields given. - * Interprets the offsets table, which contains struct field offsets. - */ -void -xfs_btree_offsets( - __int64_t fields, /* bitmask of fields */ - const short *offsets, /* table of field offsets */ - int nbits, /* number of bits to inspect */ - int *first, /* output: first byte offset */ - int *last) /* output: last byte offset */ -{ - int i; /* current bit number */ - __int64_t imask; /* mask for current bit number */ - - ASSERT(fields != 0); - /* - * Find the lowest bit, so the first byte offset. - */ - for (i = 0, imask = 1LL; ; i++, imask <<= 1) { - if (imask & fields) { - *first = offsets[i]; - break; - } - } - /* - * Find the highest bit, so the last byte offset. - */ - for (i = nbits - 1, imask = 1LL << i; ; i--, imask >>= 1) { - if (imask & fields) { - *last = offsets[i + 1] - 1; - break; - } - } -} - -/* - * Get a buffer for the block, return it read in. - * Long-form addressing. - */ -int -xfs_btree_read_bufl( - struct xfs_mount *mp, /* file system mount point */ - struct xfs_trans *tp, /* transaction pointer */ - xfs_fsblock_t fsbno, /* file system block number */ - uint lock, /* lock flags for read_buf */ - struct xfs_buf **bpp, /* buffer for fsbno */ - int refval, /* ref count value for buffer */ - const struct xfs_buf_ops *ops) -{ - struct xfs_buf *bp; /* return value */ - xfs_daddr_t d; /* real disk block address */ - int error; - - ASSERT(fsbno != NULLFSBLOCK); - d = XFS_FSB_TO_DADDR(mp, fsbno); - error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, d, - mp->m_bsize, lock, &bp, ops); - if (error) - return error; - if (bp) - xfs_buf_set_ref(bp, refval); - *bpp = bp; - return 0; -} - -/* - * Read-ahead the block, don't wait for it, don't return a buffer. - * Long-form addressing. - */ -/* ARGSUSED */ -void -xfs_btree_reada_bufl( - struct xfs_mount *mp, /* file system mount point */ - xfs_fsblock_t fsbno, /* file system block number */ - xfs_extlen_t count, /* count of filesystem blocks */ - const struct xfs_buf_ops *ops) -{ - xfs_daddr_t d; - - ASSERT(fsbno != NULLFSBLOCK); - d = XFS_FSB_TO_DADDR(mp, fsbno); - xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count, ops); -} - -/* - * Read-ahead the block, don't wait for it, don't return a buffer. - * Short-form addressing. - */ -/* ARGSUSED */ -void -xfs_btree_reada_bufs( - struct xfs_mount *mp, /* file system mount point */ - xfs_agnumber_t agno, /* allocation group number */ - xfs_agblock_t agbno, /* allocation group block number */ - xfs_extlen_t count, /* count of filesystem blocks */ - const struct xfs_buf_ops *ops) -{ - xfs_daddr_t d; - - ASSERT(agno != NULLAGNUMBER); - ASSERT(agbno != NULLAGBLOCK); - d = XFS_AGB_TO_DADDR(mp, agno, agbno); - xfs_buf_readahead(mp->m_ddev_targp, d, mp->m_bsize * count, ops); -} - -STATIC int -xfs_btree_readahead_lblock( - struct xfs_btree_cur *cur, - int lr, - struct xfs_btree_block *block) -{ - int rval = 0; - xfs_fsblock_t left = be64_to_cpu(block->bb_u.l.bb_leftsib); - xfs_fsblock_t right = be64_to_cpu(block->bb_u.l.bb_rightsib); - - if ((lr & XFS_BTCUR_LEFTRA) && left != NULLFSBLOCK) { - xfs_btree_reada_bufl(cur->bc_mp, left, 1, - cur->bc_ops->buf_ops); - rval++; - } - - if ((lr & XFS_BTCUR_RIGHTRA) && right != NULLFSBLOCK) { - xfs_btree_reada_bufl(cur->bc_mp, right, 1, - cur->bc_ops->buf_ops); - rval++; - } - - return rval; -} - -STATIC int -xfs_btree_readahead_sblock( - struct xfs_btree_cur *cur, - int lr, - struct xfs_btree_block *block) -{ - int rval = 0; - xfs_agblock_t left = be32_to_cpu(block->bb_u.s.bb_leftsib); - xfs_agblock_t right = be32_to_cpu(block->bb_u.s.bb_rightsib); - - - if ((lr & XFS_BTCUR_LEFTRA) && left != NULLAGBLOCK) { - xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno, - left, 1, cur->bc_ops->buf_ops); - rval++; - } - - if ((lr & XFS_BTCUR_RIGHTRA) && right != NULLAGBLOCK) { - xfs_btree_reada_bufs(cur->bc_mp, cur->bc_private.a.agno, - right, 1, cur->bc_ops->buf_ops); - rval++; - } - - return rval; -} - -/* - * Read-ahead btree blocks, at the given level. - * Bits in lr are set from XFS_BTCUR_{LEFT,RIGHT}RA. - */ -STATIC int -xfs_btree_readahead( - struct xfs_btree_cur *cur, /* btree cursor */ - int lev, /* level in btree */ - int lr) /* left/right bits */ -{ - struct xfs_btree_block *block; - - /* - * No readahead needed if we are at the root level and the - * btree root is stored in the inode. - */ - if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && - (lev == cur->bc_nlevels - 1)) - return 0; - - if ((cur->bc_ra[lev] | lr) == cur->bc_ra[lev]) - return 0; - - cur->bc_ra[lev] |= lr; - block = XFS_BUF_TO_BLOCK(cur->bc_bufs[lev]); - - if (cur->bc_flags & XFS_BTREE_LONG_PTRS) - return xfs_btree_readahead_lblock(cur, lr, block); - return xfs_btree_readahead_sblock(cur, lr, block); -} - -STATIC xfs_daddr_t -xfs_btree_ptr_to_daddr( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *ptr) -{ - if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { - ASSERT(ptr->l != cpu_to_be64(NULLFSBLOCK)); - - return XFS_FSB_TO_DADDR(cur->bc_mp, be64_to_cpu(ptr->l)); - } else { - ASSERT(cur->bc_private.a.agno != NULLAGNUMBER); - ASSERT(ptr->s != cpu_to_be32(NULLAGBLOCK)); - - return XFS_AGB_TO_DADDR(cur->bc_mp, cur->bc_private.a.agno, - be32_to_cpu(ptr->s)); - } -} - -/* - * Readahead @count btree blocks at the given @ptr location. - * - * We don't need to care about long or short form btrees here as we have a - * method of converting the ptr directly to a daddr available to us. - */ -STATIC void -xfs_btree_readahead_ptr( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *ptr, - xfs_extlen_t count) -{ - xfs_buf_readahead(cur->bc_mp->m_ddev_targp, - xfs_btree_ptr_to_daddr(cur, ptr), - cur->bc_mp->m_bsize * count, cur->bc_ops->buf_ops); -} - -/* - * Set the buffer for level "lev" in the cursor to bp, releasing - * any previous buffer. - */ -STATIC void -xfs_btree_setbuf( - xfs_btree_cur_t *cur, /* btree cursor */ - int lev, /* level in btree */ - xfs_buf_t *bp) /* new buffer to set */ -{ - struct xfs_btree_block *b; /* btree block */ - - if (cur->bc_bufs[lev]) - xfs_trans_brelse(cur->bc_tp, cur->bc_bufs[lev]); - cur->bc_bufs[lev] = bp; - cur->bc_ra[lev] = 0; - - b = XFS_BUF_TO_BLOCK(bp); - if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { - if (b->bb_u.l.bb_leftsib == cpu_to_be64(NULLFSBLOCK)) - cur->bc_ra[lev] |= XFS_BTCUR_LEFTRA; - if (b->bb_u.l.bb_rightsib == cpu_to_be64(NULLFSBLOCK)) - cur->bc_ra[lev] |= XFS_BTCUR_RIGHTRA; - } else { - if (b->bb_u.s.bb_leftsib == cpu_to_be32(NULLAGBLOCK)) - cur->bc_ra[lev] |= XFS_BTCUR_LEFTRA; - if (b->bb_u.s.bb_rightsib == cpu_to_be32(NULLAGBLOCK)) - cur->bc_ra[lev] |= XFS_BTCUR_RIGHTRA; - } -} - -STATIC int -xfs_btree_ptr_is_null( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *ptr) -{ - if (cur->bc_flags & XFS_BTREE_LONG_PTRS) - return ptr->l == cpu_to_be64(NULLFSBLOCK); - else - return ptr->s == cpu_to_be32(NULLAGBLOCK); -} - -STATIC void -xfs_btree_set_ptr_null( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *ptr) -{ - if (cur->bc_flags & XFS_BTREE_LONG_PTRS) - ptr->l = cpu_to_be64(NULLFSBLOCK); - else - ptr->s = cpu_to_be32(NULLAGBLOCK); -} - -/* - * Get/set/init sibling pointers - */ -STATIC void -xfs_btree_get_sibling( - struct xfs_btree_cur *cur, - struct xfs_btree_block *block, - union xfs_btree_ptr *ptr, - int lr) -{ - ASSERT(lr == XFS_BB_LEFTSIB || lr == XFS_BB_RIGHTSIB); - - if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { - if (lr == XFS_BB_RIGHTSIB) - ptr->l = block->bb_u.l.bb_rightsib; - else - ptr->l = block->bb_u.l.bb_leftsib; - } else { - if (lr == XFS_BB_RIGHTSIB) - ptr->s = block->bb_u.s.bb_rightsib; - else - ptr->s = block->bb_u.s.bb_leftsib; - } -} - -STATIC void -xfs_btree_set_sibling( - struct xfs_btree_cur *cur, - struct xfs_btree_block *block, - union xfs_btree_ptr *ptr, - int lr) -{ - ASSERT(lr == XFS_BB_LEFTSIB || lr == XFS_BB_RIGHTSIB); - - if (cur->bc_flags & XFS_BTREE_LONG_PTRS) { - if (lr == XFS_BB_RIGHTSIB) - block->bb_u.l.bb_rightsib = ptr->l; - else - block->bb_u.l.bb_leftsib = ptr->l; - } else { - if (lr == XFS_BB_RIGHTSIB) - block->bb_u.s.bb_rightsib = ptr->s; - else - block->bb_u.s.bb_leftsib = ptr->s; - } -} - -void -xfs_btree_init_block_int( - struct xfs_mount *mp, - struct xfs_btree_block *buf, - xfs_daddr_t blkno, - __u32 magic, - __u16 level, - __u16 numrecs, - __u64 owner, - unsigned int flags) -{ - buf->bb_magic = cpu_to_be32(magic); - buf->bb_level = cpu_to_be16(level); - buf->bb_numrecs = cpu_to_be16(numrecs); - - if (flags & XFS_BTREE_LONG_PTRS) { - buf->bb_u.l.bb_leftsib = cpu_to_be64(NULLFSBLOCK); - buf->bb_u.l.bb_rightsib = cpu_to_be64(NULLFSBLOCK); - if (flags & XFS_BTREE_CRC_BLOCKS) { - buf->bb_u.l.bb_blkno = cpu_to_be64(blkno); - buf->bb_u.l.bb_owner = cpu_to_be64(owner); - uuid_copy(&buf->bb_u.l.bb_uuid, &mp->m_sb.sb_meta_uuid); - buf->bb_u.l.bb_pad = 0; - buf->bb_u.l.bb_lsn = 0; - } - } else { - /* owner is a 32 bit value on short blocks */ - __u32 __owner = (__u32)owner; - - buf->bb_u.s.bb_leftsib = cpu_to_be32(NULLAGBLOCK); - buf->bb_u.s.bb_rightsib = cpu_to_be32(NULLAGBLOCK); - if (flags & XFS_BTREE_CRC_BLOCKS) { - buf->bb_u.s.bb_blkno = cpu_to_be64(blkno); - buf->bb_u.s.bb_owner = cpu_to_be32(__owner); - uuid_copy(&buf->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid); - buf->bb_u.s.bb_lsn = 0; - } - } -} - -void -xfs_btree_init_block( - struct xfs_mount *mp, - struct xfs_buf *bp, - __u32 magic, - __u16 level, - __u16 numrecs, - __u64 owner, - unsigned int flags) -{ - xfs_btree_init_block_int(mp, XFS_BUF_TO_BLOCK(bp), bp->b_bn, - magic, level, numrecs, owner, flags); -} - -STATIC void -xfs_btree_init_block_cur( - struct xfs_btree_cur *cur, - struct xfs_buf *bp, - int level, - int numrecs) -{ - __u64 owner; - - /* - * we can pull the owner from the cursor right now as the different - * owners align directly with the pointer size of the btree. This may - * change in future, but is safe for current users of the generic btree - * code. - */ - if (cur->bc_flags & XFS_BTREE_LONG_PTRS) - owner = cur->bc_private.b.ip->i_ino; - else - owner = cur->bc_private.a.agno; - - xfs_btree_init_block_int(cur->bc_mp, XFS_BUF_TO_BLOCK(bp), bp->b_bn, - xfs_btree_magic(cur), level, numrecs, - owner, cur->bc_flags); -} - -/* - * Return true if ptr is the last record in the btree and - * we need to track updates to this record. The decision - * will be further refined in the update_lastrec method. - */ -STATIC int -xfs_btree_is_lastrec( - struct xfs_btree_cur *cur, - struct xfs_btree_block *block, - int level) -{ - union xfs_btree_ptr ptr; - - if (level > 0) - return 0; - if (!(cur->bc_flags & XFS_BTREE_LASTREC_UPDATE)) - return 0; - - xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_RIGHTSIB); - if (!xfs_btree_ptr_is_null(cur, &ptr)) - return 0; - return 1; -} - -STATIC void -xfs_btree_buf_to_ptr( - struct xfs_btree_cur *cur, - struct xfs_buf *bp, - union xfs_btree_ptr *ptr) -{ - if (cur->bc_flags & XFS_BTREE_LONG_PTRS) - ptr->l = cpu_to_be64(XFS_DADDR_TO_FSB(cur->bc_mp, - XFS_BUF_ADDR(bp))); - else { - ptr->s = cpu_to_be32(xfs_daddr_to_agbno(cur->bc_mp, - XFS_BUF_ADDR(bp))); - } -} - -STATIC void -xfs_btree_set_refs( - struct xfs_btree_cur *cur, - struct xfs_buf *bp) -{ - switch (cur->bc_btnum) { - case XFS_BTNUM_BNO: - case XFS_BTNUM_CNT: - xfs_buf_set_ref(bp, XFS_ALLOC_BTREE_REF); - break; - case XFS_BTNUM_INO: - case XFS_BTNUM_FINO: - xfs_buf_set_ref(bp, XFS_INO_BTREE_REF); - break; - case XFS_BTNUM_BMAP: - xfs_buf_set_ref(bp, XFS_BMAP_BTREE_REF); - break; - case XFS_BTNUM_RMAP: - xfs_buf_set_ref(bp, XFS_RMAP_BTREE_REF); - break; - case XFS_BTNUM_REFC: - xfs_buf_set_ref(bp, XFS_REFC_BTREE_REF); - break; - default: - ASSERT(0); - } -} - -STATIC int -xfs_btree_get_buf_block( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *ptr, - int flags, - struct xfs_btree_block **block, - struct xfs_buf **bpp) -{ - struct xfs_mount *mp = cur->bc_mp; - xfs_daddr_t d; - - /* need to sort out how callers deal with failures first */ - ASSERT(!(flags & XBF_TRYLOCK)); - - d = xfs_btree_ptr_to_daddr(cur, ptr); - *bpp = xfs_trans_get_buf(cur->bc_tp, mp->m_ddev_targp, d, - mp->m_bsize, flags); - - if (!*bpp) - return -ENOMEM; - - (*bpp)->b_ops = cur->bc_ops->buf_ops; - *block = XFS_BUF_TO_BLOCK(*bpp); - return 0; -} - -/* - * Read in the buffer at the given ptr and return the buffer and - * the block pointer within the buffer. - */ -STATIC int -xfs_btree_read_buf_block( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *ptr, - int flags, - struct xfs_btree_block **block, - struct xfs_buf **bpp) -{ - struct xfs_mount *mp = cur->bc_mp; - xfs_daddr_t d; - int error; - - /* need to sort out how callers deal with failures first */ - ASSERT(!(flags & XBF_TRYLOCK)); - - d = xfs_btree_ptr_to_daddr(cur, ptr); - error = xfs_trans_read_buf(mp, cur->bc_tp, mp->m_ddev_targp, d, - mp->m_bsize, flags, bpp, - cur->bc_ops->buf_ops); - if (error) - return error; - - xfs_btree_set_refs(cur, *bpp); - *block = XFS_BUF_TO_BLOCK(*bpp); - return 0; -} - -/* - * Copy keys from one btree block to another. - */ -STATIC void -xfs_btree_copy_keys( - struct xfs_btree_cur *cur, - union xfs_btree_key *dst_key, - union xfs_btree_key *src_key, - int numkeys) -{ - ASSERT(numkeys >= 0); - memcpy(dst_key, src_key, numkeys * cur->bc_ops->key_len); -} - -/* - * Copy records from one btree block to another. - */ -STATIC void -xfs_btree_copy_recs( - struct xfs_btree_cur *cur, - union xfs_btree_rec *dst_rec, - union xfs_btree_rec *src_rec, - int numrecs) -{ - ASSERT(numrecs >= 0); - memcpy(dst_rec, src_rec, numrecs * cur->bc_ops->rec_len); -} - -/* - * Copy block pointers from one btree block to another. - */ -STATIC void -xfs_btree_copy_ptrs( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *dst_ptr, - union xfs_btree_ptr *src_ptr, - int numptrs) -{ - ASSERT(numptrs >= 0); - memcpy(dst_ptr, src_ptr, numptrs * xfs_btree_ptr_len(cur)); -} - -/* - * Shift keys one index left/right inside a single btree block. - */ -STATIC void -xfs_btree_shift_keys( - struct xfs_btree_cur *cur, - union xfs_btree_key *key, - int dir, - int numkeys) -{ - char *dst_key; - - ASSERT(numkeys >= 0); - ASSERT(dir == 1 || dir == -1); - - dst_key = (char *)key + (dir * cur->bc_ops->key_len); - memmove(dst_key, key, numkeys * cur->bc_ops->key_len); -} - -/* - * Shift records one index left/right inside a single btree block. - */ -STATIC void -xfs_btree_shift_recs( - struct xfs_btree_cur *cur, - union xfs_btree_rec *rec, - int dir, - int numrecs) -{ - char *dst_rec; - - ASSERT(numrecs >= 0); - ASSERT(dir == 1 || dir == -1); - - dst_rec = (char *)rec + (dir * cur->bc_ops->rec_len); - memmove(dst_rec, rec, numrecs * cur->bc_ops->rec_len); -} - -/* - * Shift block pointers one index left/right inside a single btree block. - */ -STATIC void -xfs_btree_shift_ptrs( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *ptr, - int dir, - int numptrs) -{ - char *dst_ptr; - - ASSERT(numptrs >= 0); - ASSERT(dir == 1 || dir == -1); - - dst_ptr = (char *)ptr + (dir * xfs_btree_ptr_len(cur)); - memmove(dst_ptr, ptr, numptrs * xfs_btree_ptr_len(cur)); -} - -/* - * Log key values from the btree block. - */ -STATIC void -xfs_btree_log_keys( - struct xfs_btree_cur *cur, - struct xfs_buf *bp, - int first, - int last) -{ - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - XFS_BTREE_TRACE_ARGBII(cur, bp, first, last); - - if (bp) { - xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF); - xfs_trans_log_buf(cur->bc_tp, bp, - xfs_btree_key_offset(cur, first), - xfs_btree_key_offset(cur, last + 1) - 1); - } else { - xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, - xfs_ilog_fbroot(cur->bc_private.b.whichfork)); - } - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); -} - -/* - * Log record values from the btree block. - */ -void -xfs_btree_log_recs( - struct xfs_btree_cur *cur, - struct xfs_buf *bp, - int first, - int last) -{ - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - XFS_BTREE_TRACE_ARGBII(cur, bp, first, last); - - xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF); - xfs_trans_log_buf(cur->bc_tp, bp, - xfs_btree_rec_offset(cur, first), - xfs_btree_rec_offset(cur, last + 1) - 1); - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); -} - -/* - * Log block pointer fields from a btree block (nonleaf). - */ -STATIC void -xfs_btree_log_ptrs( - struct xfs_btree_cur *cur, /* btree cursor */ - struct xfs_buf *bp, /* buffer containing btree block */ - int first, /* index of first pointer to log */ - int last) /* index of last pointer to log */ -{ - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - XFS_BTREE_TRACE_ARGBII(cur, bp, first, last); - - if (bp) { - struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); - int level = xfs_btree_get_level(block); - - xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF); - xfs_trans_log_buf(cur->bc_tp, bp, - xfs_btree_ptr_offset(cur, first, level), - xfs_btree_ptr_offset(cur, last + 1, level) - 1); - } else { - xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, - xfs_ilog_fbroot(cur->bc_private.b.whichfork)); - } - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); -} - -/* - * Log fields from a btree block header. - */ -void -xfs_btree_log_block( - struct xfs_btree_cur *cur, /* btree cursor */ - struct xfs_buf *bp, /* buffer containing btree block */ - int fields) /* mask of fields: XFS_BB_... */ -{ - int first; /* first byte offset logged */ - int last; /* last byte offset logged */ - static const short soffsets[] = { /* table of offsets (short) */ - offsetof(struct xfs_btree_block, bb_magic), - offsetof(struct xfs_btree_block, bb_level), - offsetof(struct xfs_btree_block, bb_numrecs), - offsetof(struct xfs_btree_block, bb_u.s.bb_leftsib), - offsetof(struct xfs_btree_block, bb_u.s.bb_rightsib), - offsetof(struct xfs_btree_block, bb_u.s.bb_blkno), - offsetof(struct xfs_btree_block, bb_u.s.bb_lsn), - offsetof(struct xfs_btree_block, bb_u.s.bb_uuid), - offsetof(struct xfs_btree_block, bb_u.s.bb_owner), - offsetof(struct xfs_btree_block, bb_u.s.bb_crc), - XFS_BTREE_SBLOCK_CRC_LEN - }; - static const short loffsets[] = { /* table of offsets (long) */ - offsetof(struct xfs_btree_block, bb_magic), - offsetof(struct xfs_btree_block, bb_level), - offsetof(struct xfs_btree_block, bb_numrecs), - offsetof(struct xfs_btree_block, bb_u.l.bb_leftsib), - offsetof(struct xfs_btree_block, bb_u.l.bb_rightsib), - offsetof(struct xfs_btree_block, bb_u.l.bb_blkno), - offsetof(struct xfs_btree_block, bb_u.l.bb_lsn), - offsetof(struct xfs_btree_block, bb_u.l.bb_uuid), - offsetof(struct xfs_btree_block, bb_u.l.bb_owner), - offsetof(struct xfs_btree_block, bb_u.l.bb_crc), - offsetof(struct xfs_btree_block, bb_u.l.bb_pad), - XFS_BTREE_LBLOCK_CRC_LEN - }; - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - XFS_BTREE_TRACE_ARGBI(cur, bp, fields); - - if (bp) { - int nbits; - - if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) { - /* - * We don't log the CRC when updating a btree - * block but instead recreate it during log - * recovery. As the log buffers have checksums - * of their own this is safe and avoids logging a crc - * update in a lot of places. - */ - if (fields == XFS_BB_ALL_BITS) - fields = XFS_BB_ALL_BITS_CRC; - nbits = XFS_BB_NUM_BITS_CRC; - } else { - nbits = XFS_BB_NUM_BITS; - } - xfs_btree_offsets(fields, - (cur->bc_flags & XFS_BTREE_LONG_PTRS) ? - loffsets : soffsets, - nbits, &first, &last); - xfs_trans_buf_set_type(cur->bc_tp, bp, XFS_BLFT_BTREE_BUF); - xfs_trans_log_buf(cur->bc_tp, bp, first, last); - } else { - xfs_trans_log_inode(cur->bc_tp, cur->bc_private.b.ip, - xfs_ilog_fbroot(cur->bc_private.b.whichfork)); - } - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); -} - -/* - * Increment cursor by one record at the level. - * For nonzero levels the leaf-ward information is untouched. - */ -int /* error */ -xfs_btree_increment( - struct xfs_btree_cur *cur, - int level, - int *stat) /* success/failure */ -{ - struct xfs_btree_block *block; - union xfs_btree_ptr ptr; - struct xfs_buf *bp; - int error; /* error return value */ - int lev; - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - XFS_BTREE_TRACE_ARGI(cur, level); - - ASSERT(level < cur->bc_nlevels); - - /* Read-ahead to the right at this level. */ - xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA); - - /* Get a pointer to the btree block. */ - block = xfs_btree_get_block(cur, level, &bp); - -#ifdef DEBUG - error = xfs_btree_check_block(cur, block, level, bp); - if (error) - goto error0; -#endif - - /* We're done if we remain in the block after the increment. */ - if (++cur->bc_ptrs[level] <= xfs_btree_get_numrecs(block)) - goto out1; - - /* Fail if we just went off the right edge of the tree. */ - xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_RIGHTSIB); - if (xfs_btree_ptr_is_null(cur, &ptr)) - goto out0; - - XFS_BTREE_STATS_INC(cur, increment); - - /* - * March up the tree incrementing pointers. - * Stop when we don't go off the right edge of a block. - */ - for (lev = level + 1; lev < cur->bc_nlevels; lev++) { - block = xfs_btree_get_block(cur, lev, &bp); - -#ifdef DEBUG - error = xfs_btree_check_block(cur, block, lev, bp); - if (error) - goto error0; -#endif - - if (++cur->bc_ptrs[lev] <= xfs_btree_get_numrecs(block)) - break; - - /* Read-ahead the right block for the next loop. */ - xfs_btree_readahead(cur, lev, XFS_BTCUR_RIGHTRA); - } - - /* - * If we went off the root then we are either seriously - * confused or have the tree root in an inode. - */ - if (lev == cur->bc_nlevels) { - if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) - goto out0; - ASSERT(0); - error = -EFSCORRUPTED; - goto error0; - } - ASSERT(lev < cur->bc_nlevels); - - /* - * Now walk back down the tree, fixing up the cursor's buffer - * pointers and key numbers. - */ - for (block = xfs_btree_get_block(cur, lev, &bp); lev > level; ) { - union xfs_btree_ptr *ptrp; - - ptrp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[lev], block); - --lev; - error = xfs_btree_read_buf_block(cur, ptrp, 0, &block, &bp); - if (error) - goto error0; - - xfs_btree_setbuf(cur, lev, bp); - cur->bc_ptrs[lev] = 1; - } -out1: - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 1; - return 0; - -out0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 0; - return 0; - -error0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; -} - -/* - * Decrement cursor by one record at the level. - * For nonzero levels the leaf-ward information is untouched. - */ -int /* error */ -xfs_btree_decrement( - struct xfs_btree_cur *cur, - int level, - int *stat) /* success/failure */ -{ - struct xfs_btree_block *block; - xfs_buf_t *bp; - int error; /* error return value */ - int lev; - union xfs_btree_ptr ptr; - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - XFS_BTREE_TRACE_ARGI(cur, level); - - ASSERT(level < cur->bc_nlevels); - - /* Read-ahead to the left at this level. */ - xfs_btree_readahead(cur, level, XFS_BTCUR_LEFTRA); - - /* We're done if we remain in the block after the decrement. */ - if (--cur->bc_ptrs[level] > 0) - goto out1; - - /* Get a pointer to the btree block. */ - block = xfs_btree_get_block(cur, level, &bp); - -#ifdef DEBUG - error = xfs_btree_check_block(cur, block, level, bp); - if (error) - goto error0; -#endif - - /* Fail if we just went off the left edge of the tree. */ - xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_LEFTSIB); - if (xfs_btree_ptr_is_null(cur, &ptr)) - goto out0; - - XFS_BTREE_STATS_INC(cur, decrement); - - /* - * March up the tree decrementing pointers. - * Stop when we don't go off the left edge of a block. - */ - for (lev = level + 1; lev < cur->bc_nlevels; lev++) { - if (--cur->bc_ptrs[lev] > 0) - break; - /* Read-ahead the left block for the next loop. */ - xfs_btree_readahead(cur, lev, XFS_BTCUR_LEFTRA); - } - - /* - * If we went off the root then we are seriously confused. - * or the root of the tree is in an inode. - */ - if (lev == cur->bc_nlevels) { - if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) - goto out0; - ASSERT(0); - error = -EFSCORRUPTED; - goto error0; - } - ASSERT(lev < cur->bc_nlevels); - - /* - * Now walk back down the tree, fixing up the cursor's buffer - * pointers and key numbers. - */ - for (block = xfs_btree_get_block(cur, lev, &bp); lev > level; ) { - union xfs_btree_ptr *ptrp; - - ptrp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[lev], block); - --lev; - error = xfs_btree_read_buf_block(cur, ptrp, 0, &block, &bp); - if (error) - goto error0; - xfs_btree_setbuf(cur, lev, bp); - cur->bc_ptrs[lev] = xfs_btree_get_numrecs(block); - } -out1: - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 1; - return 0; - -out0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 0; - return 0; - -error0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; -} - -STATIC int -xfs_btree_lookup_get_block( - struct xfs_btree_cur *cur, /* btree cursor */ - int level, /* level in the btree */ - union xfs_btree_ptr *pp, /* ptr to btree block */ - struct xfs_btree_block **blkp) /* return btree block */ -{ - struct xfs_buf *bp; /* buffer pointer for btree block */ - int error = 0; - - /* special case the root block if in an inode */ - if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && - (level == cur->bc_nlevels - 1)) { - *blkp = xfs_btree_get_iroot(cur); - return 0; - } - - /* - * If the old buffer at this level for the disk address we are - * looking for re-use it. - * - * Otherwise throw it away and get a new one. - */ - bp = cur->bc_bufs[level]; - if (bp && XFS_BUF_ADDR(bp) == xfs_btree_ptr_to_daddr(cur, pp)) { - *blkp = XFS_BUF_TO_BLOCK(bp); - return 0; - } - - error = xfs_btree_read_buf_block(cur, pp, 0, blkp, &bp); - if (error) - return error; - - xfs_btree_setbuf(cur, level, bp); - return 0; -} - -/* - * Get current search key. For level 0 we don't actually have a key - * structure so we make one up from the record. For all other levels - * we just return the right key. - */ -STATIC union xfs_btree_key * -xfs_lookup_get_search_key( - struct xfs_btree_cur *cur, - int level, - int keyno, - struct xfs_btree_block *block, - union xfs_btree_key *kp) -{ - if (level == 0) { - cur->bc_ops->init_key_from_rec(kp, - xfs_btree_rec_addr(cur, keyno, block)); - return kp; - } - - return xfs_btree_key_addr(cur, keyno, block); -} - -/* - * Lookup the record. The cursor is made to point to it, based on dir. - * stat is set to 0 if can't find any such record, 1 for success. - */ -int /* error */ -xfs_btree_lookup( - struct xfs_btree_cur *cur, /* btree cursor */ - xfs_lookup_t dir, /* <=, ==, or >= */ - int *stat) /* success/failure */ -{ - struct xfs_btree_block *block; /* current btree block */ - __int64_t diff; /* difference for the current key */ - int error; /* error return value */ - int keyno; /* current key number */ - int level; /* level in the btree */ - union xfs_btree_ptr *pp; /* ptr to btree block */ - union xfs_btree_ptr ptr; /* ptr to btree block */ - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - XFS_BTREE_TRACE_ARGI(cur, dir); - - XFS_BTREE_STATS_INC(cur, lookup); - - /* No such thing as a zero-level tree. */ - if (cur->bc_nlevels == 0) - return -EFSCORRUPTED; - - block = NULL; - keyno = 0; - - /* initialise start pointer from cursor */ - cur->bc_ops->init_ptr_from_cur(cur, &ptr); - pp = &ptr; - - /* - * Iterate over each level in the btree, starting at the root. - * For each level above the leaves, find the key we need, based - * on the lookup record, then follow the corresponding block - * pointer down to the next level. - */ - for (level = cur->bc_nlevels - 1, diff = 1; level >= 0; level--) { - /* Get the block we need to do the lookup on. */ - error = xfs_btree_lookup_get_block(cur, level, pp, &block); - if (error) - goto error0; - - if (diff == 0) { - /* - * If we already had a key match at a higher level, we - * know we need to use the first entry in this block. - */ - keyno = 1; - } else { - /* Otherwise search this block. Do a binary search. */ - - int high; /* high entry number */ - int low; /* low entry number */ - - /* Set low and high entry numbers, 1-based. */ - low = 1; - high = xfs_btree_get_numrecs(block); - if (!high) { - /* Block is empty, must be an empty leaf. */ - ASSERT(level == 0 && cur->bc_nlevels == 1); - - cur->bc_ptrs[0] = dir != XFS_LOOKUP_LE; - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 0; - return 0; - } - - /* Binary search the block. */ - while (low <= high) { - union xfs_btree_key key; - union xfs_btree_key *kp; - - XFS_BTREE_STATS_INC(cur, compare); - - /* keyno is average of low and high. */ - keyno = (low + high) >> 1; - - /* Get current search key */ - kp = xfs_lookup_get_search_key(cur, level, - keyno, block, &key); - - /* - * Compute difference to get next direction: - * - less than, move right - * - greater than, move left - * - equal, we're done - */ - diff = cur->bc_ops->key_diff(cur, kp); - if (diff < 0) - low = keyno + 1; - else if (diff > 0) - high = keyno - 1; - else - break; - } - } - - /* - * If there are more levels, set up for the next level - * by getting the block number and filling in the cursor. - */ - if (level > 0) { - /* - * If we moved left, need the previous key number, - * unless there isn't one. - */ - if (diff > 0 && --keyno < 1) - keyno = 1; - pp = xfs_btree_ptr_addr(cur, keyno, block); - -#ifdef DEBUG - error = xfs_btree_check_ptr(cur, pp, 0, level); - if (error) - goto error0; -#endif - cur->bc_ptrs[level] = keyno; - } - } - - /* Done with the search. See if we need to adjust the results. */ - if (dir != XFS_LOOKUP_LE && diff < 0) { - keyno++; - /* - * If ge search and we went off the end of the block, but it's - * not the last block, we're in the wrong block. - */ - xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_RIGHTSIB); - if (dir == XFS_LOOKUP_GE && - keyno > xfs_btree_get_numrecs(block) && - !xfs_btree_ptr_is_null(cur, &ptr)) { - int i; - - cur->bc_ptrs[0] = keyno; - error = xfs_btree_increment(cur, 0, &i); - if (error) - goto error0; - XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 1; - return 0; - } - } else if (dir == XFS_LOOKUP_LE && diff > 0) - keyno--; - cur->bc_ptrs[0] = keyno; - - /* Return if we succeeded or not. */ - if (keyno == 0 || keyno > xfs_btree_get_numrecs(block)) - *stat = 0; - else if (dir != XFS_LOOKUP_EQ || diff == 0) - *stat = 1; - else - *stat = 0; - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - return 0; - -error0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; -} - -/* Find the high key storage area from a regular key. */ -STATIC union xfs_btree_key * -xfs_btree_high_key_from_key( - struct xfs_btree_cur *cur, - union xfs_btree_key *key) -{ - ASSERT(cur->bc_flags & XFS_BTREE_OVERLAPPING); - return (union xfs_btree_key *)((char *)key + - (cur->bc_ops->key_len / 2)); -} - -/* Determine the low (and high if overlapped) keys of a leaf block */ -STATIC void -xfs_btree_get_leaf_keys( - struct xfs_btree_cur *cur, - struct xfs_btree_block *block, - union xfs_btree_key *key) -{ - union xfs_btree_key max_hkey; - union xfs_btree_key hkey; - union xfs_btree_rec *rec; - union xfs_btree_key *high; - int n; - - rec = xfs_btree_rec_addr(cur, 1, block); - cur->bc_ops->init_key_from_rec(key, rec); - - if (cur->bc_flags & XFS_BTREE_OVERLAPPING) { - - cur->bc_ops->init_high_key_from_rec(&max_hkey, rec); - for (n = 2; n <= xfs_btree_get_numrecs(block); n++) { - rec = xfs_btree_rec_addr(cur, n, block); - cur->bc_ops->init_high_key_from_rec(&hkey, rec); - if (cur->bc_ops->diff_two_keys(cur, &hkey, &max_hkey) - > 0) - max_hkey = hkey; - } - - high = xfs_btree_high_key_from_key(cur, key); - memcpy(high, &max_hkey, cur->bc_ops->key_len / 2); - } -} - -/* Determine the low (and high if overlapped) keys of a node block */ -STATIC void -xfs_btree_get_node_keys( - struct xfs_btree_cur *cur, - struct xfs_btree_block *block, - union xfs_btree_key *key) -{ - union xfs_btree_key *hkey; - union xfs_btree_key *max_hkey; - union xfs_btree_key *high; - int n; - - if (cur->bc_flags & XFS_BTREE_OVERLAPPING) { - memcpy(key, xfs_btree_key_addr(cur, 1, block), - cur->bc_ops->key_len / 2); - - max_hkey = xfs_btree_high_key_addr(cur, 1, block); - for (n = 2; n <= xfs_btree_get_numrecs(block); n++) { - hkey = xfs_btree_high_key_addr(cur, n, block); - if (cur->bc_ops->diff_two_keys(cur, hkey, max_hkey) > 0) - max_hkey = hkey; - } - - high = xfs_btree_high_key_from_key(cur, key); - memcpy(high, max_hkey, cur->bc_ops->key_len / 2); - } else { - memcpy(key, xfs_btree_key_addr(cur, 1, block), - cur->bc_ops->key_len); - } -} - -/* Derive the keys for any btree block. */ -STATIC void -xfs_btree_get_keys( - struct xfs_btree_cur *cur, - struct xfs_btree_block *block, - union xfs_btree_key *key) -{ - if (be16_to_cpu(block->bb_level) == 0) - xfs_btree_get_leaf_keys(cur, block, key); - else - xfs_btree_get_node_keys(cur, block, key); -} - -/* - * Decide if we need to update the parent keys of a btree block. For - * a standard btree this is only necessary if we're updating the first - * record/key. For an overlapping btree, we must always update the - * keys because the highest key can be in any of the records or keys - * in the block. - */ -static inline bool -xfs_btree_needs_key_update( - struct xfs_btree_cur *cur, - int ptr) -{ - return (cur->bc_flags & XFS_BTREE_OVERLAPPING) || ptr == 1; -} - -/* - * Update the low and high parent keys of the given level, progressing - * towards the root. If force_all is false, stop if the keys for a given - * level do not need updating. - */ -STATIC int -__xfs_btree_updkeys( - struct xfs_btree_cur *cur, - int level, - struct xfs_btree_block *block, - struct xfs_buf *bp0, - bool force_all) -{ - union xfs_btree_key key; /* keys from current level */ - union xfs_btree_key *lkey; /* keys from the next level up */ - union xfs_btree_key *hkey; - union xfs_btree_key *nlkey; /* keys from the next level up */ - union xfs_btree_key *nhkey; - struct xfs_buf *bp; - int ptr; - - ASSERT(cur->bc_flags & XFS_BTREE_OVERLAPPING); - - /* Exit if there aren't any parent levels to update. */ - if (level + 1 >= cur->bc_nlevels) - return 0; - - trace_xfs_btree_updkeys(cur, level, bp0); - - lkey = &key; - hkey = xfs_btree_high_key_from_key(cur, lkey); - xfs_btree_get_keys(cur, block, lkey); - for (level++; level < cur->bc_nlevels; level++) { -#ifdef DEBUG - int error; -#endif - block = xfs_btree_get_block(cur, level, &bp); - trace_xfs_btree_updkeys(cur, level, bp); -#ifdef DEBUG - error = xfs_btree_check_block(cur, block, level, bp); - if (error) { - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; - } -#endif - ptr = cur->bc_ptrs[level]; - nlkey = xfs_btree_key_addr(cur, ptr, block); - nhkey = xfs_btree_high_key_addr(cur, ptr, block); - if (!force_all && - !(cur->bc_ops->diff_two_keys(cur, nlkey, lkey) != 0 || - cur->bc_ops->diff_two_keys(cur, nhkey, hkey) != 0)) - break; - xfs_btree_copy_keys(cur, nlkey, lkey, 1); - xfs_btree_log_keys(cur, bp, ptr, ptr); - if (level + 1 >= cur->bc_nlevels) - break; - xfs_btree_get_node_keys(cur, block, lkey); - } - - return 0; -} - -/* Update all the keys from some level in cursor back to the root. */ -STATIC int -xfs_btree_updkeys_force( - struct xfs_btree_cur *cur, - int level) -{ - struct xfs_buf *bp; - struct xfs_btree_block *block; - - block = xfs_btree_get_block(cur, level, &bp); - return __xfs_btree_updkeys(cur, level, block, bp, true); -} - -/* - * Update the parent keys of the given level, progressing towards the root. - */ -STATIC int -xfs_btree_update_keys( - struct xfs_btree_cur *cur, - int level) -{ - struct xfs_btree_block *block; - struct xfs_buf *bp; - union xfs_btree_key *kp; - union xfs_btree_key key; - int ptr; - - ASSERT(level >= 0); - - block = xfs_btree_get_block(cur, level, &bp); - if (cur->bc_flags & XFS_BTREE_OVERLAPPING) - return __xfs_btree_updkeys(cur, level, block, bp, false); - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - XFS_BTREE_TRACE_ARGIK(cur, level, keyp); - - /* - * Go up the tree from this level toward the root. - * At each level, update the key value to the value input. - * Stop when we reach a level where the cursor isn't pointing - * at the first entry in the block. - */ - xfs_btree_get_keys(cur, block, &key); - for (level++, ptr = 1; ptr == 1 && level < cur->bc_nlevels; level++) { -#ifdef DEBUG - int error; -#endif - block = xfs_btree_get_block(cur, level, &bp); -#ifdef DEBUG - error = xfs_btree_check_block(cur, block, level, bp); - if (error) { - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; - } -#endif - ptr = cur->bc_ptrs[level]; - kp = xfs_btree_key_addr(cur, ptr, block); - xfs_btree_copy_keys(cur, kp, &key, 1); - xfs_btree_log_keys(cur, bp, ptr, ptr); - } - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - return 0; -} - -/* - * Update the record referred to by cur to the value in the - * given record. This either works (return 0) or gets an - * EFSCORRUPTED error. - */ -int -xfs_btree_update( - struct xfs_btree_cur *cur, - union xfs_btree_rec *rec) -{ - struct xfs_btree_block *block; - struct xfs_buf *bp; - int error; - int ptr; - union xfs_btree_rec *rp; - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - XFS_BTREE_TRACE_ARGR(cur, rec); - - /* Pick up the current block. */ - block = xfs_btree_get_block(cur, 0, &bp); - -#ifdef DEBUG - error = xfs_btree_check_block(cur, block, 0, bp); - if (error) - goto error0; -#endif - /* Get the address of the rec to be updated. */ - ptr = cur->bc_ptrs[0]; - rp = xfs_btree_rec_addr(cur, ptr, block); - - /* Fill in the new contents and log them. */ - xfs_btree_copy_recs(cur, rp, rec, 1); - xfs_btree_log_recs(cur, bp, ptr, ptr); - - /* - * If we are tracking the last record in the tree and - * we are at the far right edge of the tree, update it. - */ - if (xfs_btree_is_lastrec(cur, block, 0)) { - cur->bc_ops->update_lastrec(cur, block, rec, - ptr, LASTREC_UPDATE); - } - - /* Pass new key value up to our parent. */ - if (xfs_btree_needs_key_update(cur, ptr)) { - error = xfs_btree_update_keys(cur, 0); - if (error) - goto error0; - } - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - return 0; - -error0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; -} - -/* - * Move 1 record left from cur/level if possible. - * Update cur to reflect the new path. - */ -STATIC int /* error */ -xfs_btree_lshift( - struct xfs_btree_cur *cur, - int level, - int *stat) /* success/failure */ -{ - struct xfs_buf *lbp; /* left buffer pointer */ - struct xfs_btree_block *left; /* left btree block */ - int lrecs; /* left record count */ - struct xfs_buf *rbp; /* right buffer pointer */ - struct xfs_btree_block *right; /* right btree block */ - struct xfs_btree_cur *tcur; /* temporary btree cursor */ - int rrecs; /* right record count */ - union xfs_btree_ptr lptr; /* left btree pointer */ - union xfs_btree_key *rkp = NULL; /* right btree key */ - union xfs_btree_ptr *rpp = NULL; /* right address pointer */ - union xfs_btree_rec *rrp = NULL; /* right record pointer */ - int error; /* error return value */ - int i; - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - XFS_BTREE_TRACE_ARGI(cur, level); - - if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && - level == cur->bc_nlevels - 1) - goto out0; - - /* Set up variables for this block as "right". */ - right = xfs_btree_get_block(cur, level, &rbp); - -#ifdef DEBUG - error = xfs_btree_check_block(cur, right, level, rbp); - if (error) - goto error0; -#endif - - /* If we've got no left sibling then we can't shift an entry left. */ - xfs_btree_get_sibling(cur, right, &lptr, XFS_BB_LEFTSIB); - if (xfs_btree_ptr_is_null(cur, &lptr)) - goto out0; - - /* - * If the cursor entry is the one that would be moved, don't - * do it... it's too complicated. - */ - if (cur->bc_ptrs[level] <= 1) - goto out0; - - /* Set up the left neighbor as "left". */ - error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp); - if (error) - goto error0; - - /* If it's full, it can't take another entry. */ - lrecs = xfs_btree_get_numrecs(left); - if (lrecs == cur->bc_ops->get_maxrecs(cur, level)) - goto out0; - - rrecs = xfs_btree_get_numrecs(right); - - /* - * We add one entry to the left side and remove one for the right side. - * Account for it here, the changes will be updated on disk and logged - * later. - */ - lrecs++; - rrecs--; - - XFS_BTREE_STATS_INC(cur, lshift); - XFS_BTREE_STATS_ADD(cur, moves, 1); - - /* - * If non-leaf, copy a key and a ptr to the left block. - * Log the changes to the left block. - */ - if (level > 0) { - /* It's a non-leaf. Move keys and pointers. */ - union xfs_btree_key *lkp; /* left btree key */ - union xfs_btree_ptr *lpp; /* left address pointer */ - - lkp = xfs_btree_key_addr(cur, lrecs, left); - rkp = xfs_btree_key_addr(cur, 1, right); - - lpp = xfs_btree_ptr_addr(cur, lrecs, left); - rpp = xfs_btree_ptr_addr(cur, 1, right); -#ifdef DEBUG - error = xfs_btree_check_ptr(cur, rpp, 0, level); - if (error) - goto error0; -#endif - xfs_btree_copy_keys(cur, lkp, rkp, 1); - xfs_btree_copy_ptrs(cur, lpp, rpp, 1); - - xfs_btree_log_keys(cur, lbp, lrecs, lrecs); - xfs_btree_log_ptrs(cur, lbp, lrecs, lrecs); - - ASSERT(cur->bc_ops->keys_inorder(cur, - xfs_btree_key_addr(cur, lrecs - 1, left), lkp)); - } else { - /* It's a leaf. Move records. */ - union xfs_btree_rec *lrp; /* left record pointer */ - - lrp = xfs_btree_rec_addr(cur, lrecs, left); - rrp = xfs_btree_rec_addr(cur, 1, right); - - xfs_btree_copy_recs(cur, lrp, rrp, 1); - xfs_btree_log_recs(cur, lbp, lrecs, lrecs); - - ASSERT(cur->bc_ops->recs_inorder(cur, - xfs_btree_rec_addr(cur, lrecs - 1, left), lrp)); - } - - xfs_btree_set_numrecs(left, lrecs); - xfs_btree_log_block(cur, lbp, XFS_BB_NUMRECS); - - xfs_btree_set_numrecs(right, rrecs); - xfs_btree_log_block(cur, rbp, XFS_BB_NUMRECS); - - /* - * Slide the contents of right down one entry. - */ - XFS_BTREE_STATS_ADD(cur, moves, rrecs - 1); - if (level > 0) { - /* It's a nonleaf. operate on keys and ptrs */ -#ifdef DEBUG - int i; /* loop index */ - - for (i = 0; i < rrecs; i++) { - error = xfs_btree_check_ptr(cur, rpp, i + 1, level); - if (error) - goto error0; - } -#endif - xfs_btree_shift_keys(cur, - xfs_btree_key_addr(cur, 2, right), - -1, rrecs); - xfs_btree_shift_ptrs(cur, - xfs_btree_ptr_addr(cur, 2, right), - -1, rrecs); - - xfs_btree_log_keys(cur, rbp, 1, rrecs); - xfs_btree_log_ptrs(cur, rbp, 1, rrecs); - } else { - /* It's a leaf. operate on records */ - xfs_btree_shift_recs(cur, - xfs_btree_rec_addr(cur, 2, right), - -1, rrecs); - xfs_btree_log_recs(cur, rbp, 1, rrecs); - } - - /* - * Using a temporary cursor, update the parent key values of the - * block on the left. - */ - if (cur->bc_flags & XFS_BTREE_OVERLAPPING) { - error = xfs_btree_dup_cursor(cur, &tcur); - if (error) - goto error0; - i = xfs_btree_firstrec(tcur, level); - XFS_WANT_CORRUPTED_GOTO(tcur->bc_mp, i == 1, error0); - - error = xfs_btree_decrement(tcur, level, &i); - if (error) - goto error1; - - /* Update the parent high keys of the left block, if needed. */ - error = xfs_btree_update_keys(tcur, level); - if (error) - goto error1; - - xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); - } - - /* Update the parent keys of the right block. */ - error = xfs_btree_update_keys(cur, level); - if (error) - goto error0; - - /* Slide the cursor value left one. */ - cur->bc_ptrs[level]--; - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 1; - return 0; - -out0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 0; - return 0; - -error0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; - -error1: - XFS_BTREE_TRACE_CURSOR(tcur, XBT_ERROR); - xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); - return error; -} - -/* - * Move 1 record right from cur/level if possible. - * Update cur to reflect the new path. - */ -STATIC int /* error */ -xfs_btree_rshift( - struct xfs_btree_cur *cur, - int level, - int *stat) /* success/failure */ -{ - struct xfs_buf *lbp; /* left buffer pointer */ - struct xfs_btree_block *left; /* left btree block */ - struct xfs_buf *rbp; /* right buffer pointer */ - struct xfs_btree_block *right; /* right btree block */ - struct xfs_btree_cur *tcur; /* temporary btree cursor */ - union xfs_btree_ptr rptr; /* right block pointer */ - union xfs_btree_key *rkp; /* right btree key */ - int rrecs; /* right record count */ - int lrecs; /* left record count */ - int error; /* error return value */ - int i; /* loop counter */ - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - XFS_BTREE_TRACE_ARGI(cur, level); - - if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && - (level == cur->bc_nlevels - 1)) - goto out0; - - /* Set up variables for this block as "left". */ - left = xfs_btree_get_block(cur, level, &lbp); - -#ifdef DEBUG - error = xfs_btree_check_block(cur, left, level, lbp); - if (error) - goto error0; -#endif - - /* If we've got no right sibling then we can't shift an entry right. */ - xfs_btree_get_sibling(cur, left, &rptr, XFS_BB_RIGHTSIB); - if (xfs_btree_ptr_is_null(cur, &rptr)) - goto out0; - - /* - * If the cursor entry is the one that would be moved, don't - * do it... it's too complicated. - */ - lrecs = xfs_btree_get_numrecs(left); - if (cur->bc_ptrs[level] >= lrecs) - goto out0; - - /* Set up the right neighbor as "right". */ - error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp); - if (error) - goto error0; - - /* If it's full, it can't take another entry. */ - rrecs = xfs_btree_get_numrecs(right); - if (rrecs == cur->bc_ops->get_maxrecs(cur, level)) - goto out0; - - XFS_BTREE_STATS_INC(cur, rshift); - XFS_BTREE_STATS_ADD(cur, moves, rrecs); - - /* - * Make a hole at the start of the right neighbor block, then - * copy the last left block entry to the hole. - */ - if (level > 0) { - /* It's a nonleaf. make a hole in the keys and ptrs */ - union xfs_btree_key *lkp; - union xfs_btree_ptr *lpp; - union xfs_btree_ptr *rpp; - - lkp = xfs_btree_key_addr(cur, lrecs, left); - lpp = xfs_btree_ptr_addr(cur, lrecs, left); - rkp = xfs_btree_key_addr(cur, 1, right); - rpp = xfs_btree_ptr_addr(cur, 1, right); - -#ifdef DEBUG - for (i = rrecs - 1; i >= 0; i--) { - error = xfs_btree_check_ptr(cur, rpp, i, level); - if (error) - goto error0; - } -#endif - - xfs_btree_shift_keys(cur, rkp, 1, rrecs); - xfs_btree_shift_ptrs(cur, rpp, 1, rrecs); - -#ifdef DEBUG - error = xfs_btree_check_ptr(cur, lpp, 0, level); - if (error) - goto error0; -#endif - - /* Now put the new data in, and log it. */ - xfs_btree_copy_keys(cur, rkp, lkp, 1); - xfs_btree_copy_ptrs(cur, rpp, lpp, 1); - - xfs_btree_log_keys(cur, rbp, 1, rrecs + 1); - xfs_btree_log_ptrs(cur, rbp, 1, rrecs + 1); - - ASSERT(cur->bc_ops->keys_inorder(cur, rkp, - xfs_btree_key_addr(cur, 2, right))); - } else { - /* It's a leaf. make a hole in the records */ - union xfs_btree_rec *lrp; - union xfs_btree_rec *rrp; - - lrp = xfs_btree_rec_addr(cur, lrecs, left); - rrp = xfs_btree_rec_addr(cur, 1, right); - - xfs_btree_shift_recs(cur, rrp, 1, rrecs); - - /* Now put the new data in, and log it. */ - xfs_btree_copy_recs(cur, rrp, lrp, 1); - xfs_btree_log_recs(cur, rbp, 1, rrecs + 1); - } - - /* - * Decrement and log left's numrecs, bump and log right's numrecs. - */ - xfs_btree_set_numrecs(left, --lrecs); - xfs_btree_log_block(cur, lbp, XFS_BB_NUMRECS); - - xfs_btree_set_numrecs(right, ++rrecs); - xfs_btree_log_block(cur, rbp, XFS_BB_NUMRECS); - - /* - * Using a temporary cursor, update the parent key values of the - * block on the right. - */ - error = xfs_btree_dup_cursor(cur, &tcur); - if (error) - goto error0; - i = xfs_btree_lastrec(tcur, level); - XFS_WANT_CORRUPTED_GOTO(tcur->bc_mp, i == 1, error0); - - error = xfs_btree_increment(tcur, level, &i); - if (error) - goto error1; - - /* Update the parent high keys of the left block, if needed. */ - if (cur->bc_flags & XFS_BTREE_OVERLAPPING) { - error = xfs_btree_update_keys(cur, level); - if (error) - goto error1; - } - - /* Update the parent keys of the right block. */ - error = xfs_btree_update_keys(tcur, level); - if (error) - goto error1; - - xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 1; - return 0; - -out0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 0; - return 0; - -error0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; - -error1: - XFS_BTREE_TRACE_CURSOR(tcur, XBT_ERROR); - xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); - return error; -} - -/* - * Split cur/level block in half. - * Return new block number and the key to its first - * record (to be inserted into parent). - */ -STATIC int /* error */ -__xfs_btree_split( - struct xfs_btree_cur *cur, - int level, - union xfs_btree_ptr *ptrp, - union xfs_btree_key *key, - struct xfs_btree_cur **curp, - int *stat) /* success/failure */ -{ - union xfs_btree_ptr lptr; /* left sibling block ptr */ - struct xfs_buf *lbp; /* left buffer pointer */ - struct xfs_btree_block *left; /* left btree block */ - union xfs_btree_ptr rptr; /* right sibling block ptr */ - struct xfs_buf *rbp; /* right buffer pointer */ - struct xfs_btree_block *right; /* right btree block */ - union xfs_btree_ptr rrptr; /* right-right sibling ptr */ - struct xfs_buf *rrbp; /* right-right buffer pointer */ - struct xfs_btree_block *rrblock; /* right-right btree block */ - int lrecs; - int rrecs; - int src_index; - int error; /* error return value */ -#ifdef DEBUG - int i; -#endif - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - XFS_BTREE_TRACE_ARGIPK(cur, level, *ptrp, key); - - XFS_BTREE_STATS_INC(cur, split); - - /* Set up left block (current one). */ - left = xfs_btree_get_block(cur, level, &lbp); - -#ifdef DEBUG - error = xfs_btree_check_block(cur, left, level, lbp); - if (error) - goto error0; -#endif - - xfs_btree_buf_to_ptr(cur, lbp, &lptr); - - /* Allocate the new block. If we can't do it, we're toast. Give up. */ - error = cur->bc_ops->alloc_block(cur, &lptr, &rptr, stat); - if (error) - goto error0; - if (*stat == 0) - goto out0; - XFS_BTREE_STATS_INC(cur, alloc); - - /* Set up the new block as "right". */ - error = xfs_btree_get_buf_block(cur, &rptr, 0, &right, &rbp); - if (error) - goto error0; - - /* Fill in the btree header for the new right block. */ - xfs_btree_init_block_cur(cur, rbp, xfs_btree_get_level(left), 0); - - /* - * Split the entries between the old and the new block evenly. - * Make sure that if there's an odd number of entries now, that - * each new block will have the same number of entries. - */ - lrecs = xfs_btree_get_numrecs(left); - rrecs = lrecs / 2; - if ((lrecs & 1) && cur->bc_ptrs[level] <= rrecs + 1) - rrecs++; - src_index = (lrecs - rrecs + 1); - - XFS_BTREE_STATS_ADD(cur, moves, rrecs); - - /* Adjust numrecs for the later get_*_keys() calls. */ - lrecs -= rrecs; - xfs_btree_set_numrecs(left, lrecs); - xfs_btree_set_numrecs(right, xfs_btree_get_numrecs(right) + rrecs); - - /* - * Copy btree block entries from the left block over to the - * new block, the right. Update the right block and log the - * changes. - */ - if (level > 0) { - /* It's a non-leaf. Move keys and pointers. */ - union xfs_btree_key *lkp; /* left btree key */ - union xfs_btree_ptr *lpp; /* left address pointer */ - union xfs_btree_key *rkp; /* right btree key */ - union xfs_btree_ptr *rpp; /* right address pointer */ - - lkp = xfs_btree_key_addr(cur, src_index, left); - lpp = xfs_btree_ptr_addr(cur, src_index, left); - rkp = xfs_btree_key_addr(cur, 1, right); - rpp = xfs_btree_ptr_addr(cur, 1, right); - -#ifdef DEBUG - for (i = src_index; i < rrecs; i++) { - error = xfs_btree_check_ptr(cur, lpp, i, level); - if (error) - goto error0; - } -#endif - - /* Copy the keys & pointers to the new block. */ - xfs_btree_copy_keys(cur, rkp, lkp, rrecs); - xfs_btree_copy_ptrs(cur, rpp, lpp, rrecs); - - xfs_btree_log_keys(cur, rbp, 1, rrecs); - xfs_btree_log_ptrs(cur, rbp, 1, rrecs); - - /* Stash the keys of the new block for later insertion. */ - xfs_btree_get_node_keys(cur, right, key); - } else { - /* It's a leaf. Move records. */ - union xfs_btree_rec *lrp; /* left record pointer */ - union xfs_btree_rec *rrp; /* right record pointer */ - - lrp = xfs_btree_rec_addr(cur, src_index, left); - rrp = xfs_btree_rec_addr(cur, 1, right); - - /* Copy records to the new block. */ - xfs_btree_copy_recs(cur, rrp, lrp, rrecs); - xfs_btree_log_recs(cur, rbp, 1, rrecs); - - /* Stash the keys of the new block for later insertion. */ - xfs_btree_get_leaf_keys(cur, right, key); - } - - /* - * Find the left block number by looking in the buffer. - * Adjust sibling pointers. - */ - xfs_btree_get_sibling(cur, left, &rrptr, XFS_BB_RIGHTSIB); - xfs_btree_set_sibling(cur, right, &rrptr, XFS_BB_RIGHTSIB); - xfs_btree_set_sibling(cur, right, &lptr, XFS_BB_LEFTSIB); - xfs_btree_set_sibling(cur, left, &rptr, XFS_BB_RIGHTSIB); - - xfs_btree_log_block(cur, rbp, XFS_BB_ALL_BITS); - xfs_btree_log_block(cur, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); - - /* - * If there's a block to the new block's right, make that block - * point back to right instead of to left. - */ - if (!xfs_btree_ptr_is_null(cur, &rrptr)) { - error = xfs_btree_read_buf_block(cur, &rrptr, - 0, &rrblock, &rrbp); - if (error) - goto error0; - xfs_btree_set_sibling(cur, rrblock, &rptr, XFS_BB_LEFTSIB); - xfs_btree_log_block(cur, rrbp, XFS_BB_LEFTSIB); - } - - /* Update the parent high keys of the left block, if needed. */ - if (cur->bc_flags & XFS_BTREE_OVERLAPPING) { - error = xfs_btree_update_keys(cur, level); - if (error) - goto error0; - } - - /* - * If the cursor is really in the right block, move it there. - * If it's just pointing past the last entry in left, then we'll - * insert there, so don't change anything in that case. - */ - if (cur->bc_ptrs[level] > lrecs + 1) { - xfs_btree_setbuf(cur, level, rbp); - cur->bc_ptrs[level] -= lrecs; - } - /* - * If there are more levels, we'll need another cursor which refers - * the right block, no matter where this cursor was. - */ - if (level + 1 < cur->bc_nlevels) { - error = xfs_btree_dup_cursor(cur, curp); - if (error) - goto error0; - (*curp)->bc_ptrs[level + 1]++; - } - *ptrp = rptr; - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 1; - return 0; -out0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 0; - return 0; - -error0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; -} - -struct xfs_btree_split_args { - struct xfs_btree_cur *cur; - int level; - union xfs_btree_ptr *ptrp; - union xfs_btree_key *key; - struct xfs_btree_cur **curp; - int *stat; /* success/failure */ - int result; - bool kswapd; /* allocation in kswapd context */ - struct completion *done; - struct work_struct work; -}; - -/* - * Stack switching interfaces for allocation - */ -static void -xfs_btree_split_worker( - struct work_struct *work) -{ - struct xfs_btree_split_args *args = container_of(work, - struct xfs_btree_split_args, work); - unsigned long pflags; - unsigned long new_pflags = PF_FSTRANS; - - /* - * we are in a transaction context here, but may also be doing work - * in kswapd context, and hence we may need to inherit that state - * temporarily to ensure that we don't block waiting for memory reclaim - * in any way. - */ - if (args->kswapd) - new_pflags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD; - - current_set_flags_nested(&pflags, new_pflags); - - args->result = __xfs_btree_split(args->cur, args->level, args->ptrp, - args->key, args->curp, args->stat); - complete(args->done); - - current_restore_flags_nested(&pflags, new_pflags); -} - -/* - * BMBT split requests often come in with little stack to work on. Push - * them off to a worker thread so there is lots of stack to use. For the other - * btree types, just call directly to avoid the context switch overhead here. - */ -STATIC int /* error */ -xfs_btree_split( - struct xfs_btree_cur *cur, - int level, - union xfs_btree_ptr *ptrp, - union xfs_btree_key *key, - struct xfs_btree_cur **curp, - int *stat) /* success/failure */ -{ - struct xfs_btree_split_args args; - DECLARE_COMPLETION_ONSTACK(done); - - if (cur->bc_btnum != XFS_BTNUM_BMAP) - return __xfs_btree_split(cur, level, ptrp, key, curp, stat); - - args.cur = cur; - args.level = level; - args.ptrp = ptrp; - args.key = key; - args.curp = curp; - args.stat = stat; - args.done = &done; - args.kswapd = current_is_kswapd(); - INIT_WORK_ONSTACK(&args.work, xfs_btree_split_worker); - queue_work(xfs_alloc_wq, &args.work); - wait_for_completion(&done); - destroy_work_on_stack(&args.work); - return args.result; -} - - -/* - * Copy the old inode root contents into a real block and make the - * broot point to it. - */ -int /* error */ -xfs_btree_new_iroot( - struct xfs_btree_cur *cur, /* btree cursor */ - int *logflags, /* logging flags for inode */ - int *stat) /* return status - 0 fail */ -{ - struct xfs_buf *cbp; /* buffer for cblock */ - struct xfs_btree_block *block; /* btree block */ - struct xfs_btree_block *cblock; /* child btree block */ - union xfs_btree_key *ckp; /* child key pointer */ - union xfs_btree_ptr *cpp; /* child ptr pointer */ - union xfs_btree_key *kp; /* pointer to btree key */ - union xfs_btree_ptr *pp; /* pointer to block addr */ - union xfs_btree_ptr nptr; /* new block addr */ - int level; /* btree level */ - int error; /* error return code */ -#ifdef DEBUG - int i; /* loop counter */ -#endif - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - XFS_BTREE_STATS_INC(cur, newroot); - - ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE); - - level = cur->bc_nlevels - 1; - - block = xfs_btree_get_iroot(cur); - pp = xfs_btree_ptr_addr(cur, 1, block); - - /* Allocate the new block. If we can't do it, we're toast. Give up. */ - error = cur->bc_ops->alloc_block(cur, pp, &nptr, stat); - if (error) - goto error0; - if (*stat == 0) { - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - return 0; - } - XFS_BTREE_STATS_INC(cur, alloc); - - /* Copy the root into a real block. */ - error = xfs_btree_get_buf_block(cur, &nptr, 0, &cblock, &cbp); - if (error) - goto error0; - - /* - * we can't just memcpy() the root in for CRC enabled btree blocks. - * In that case have to also ensure the blkno remains correct - */ - memcpy(cblock, block, xfs_btree_block_len(cur)); - if (cur->bc_flags & XFS_BTREE_CRC_BLOCKS) { - if (cur->bc_flags & XFS_BTREE_LONG_PTRS) - cblock->bb_u.l.bb_blkno = cpu_to_be64(cbp->b_bn); - else - cblock->bb_u.s.bb_blkno = cpu_to_be64(cbp->b_bn); - } - - be16_add_cpu(&block->bb_level, 1); - xfs_btree_set_numrecs(block, 1); - cur->bc_nlevels++; - cur->bc_ptrs[level + 1] = 1; - - kp = xfs_btree_key_addr(cur, 1, block); - ckp = xfs_btree_key_addr(cur, 1, cblock); - xfs_btree_copy_keys(cur, ckp, kp, xfs_btree_get_numrecs(cblock)); - - cpp = xfs_btree_ptr_addr(cur, 1, cblock); -#ifdef DEBUG - for (i = 0; i < be16_to_cpu(cblock->bb_numrecs); i++) { - error = xfs_btree_check_ptr(cur, pp, i, level); - if (error) - goto error0; - } -#endif - xfs_btree_copy_ptrs(cur, cpp, pp, xfs_btree_get_numrecs(cblock)); - -#ifdef DEBUG - error = xfs_btree_check_ptr(cur, &nptr, 0, level); - if (error) - goto error0; -#endif - xfs_btree_copy_ptrs(cur, pp, &nptr, 1); - - xfs_iroot_realloc(cur->bc_private.b.ip, - 1 - xfs_btree_get_numrecs(cblock), - cur->bc_private.b.whichfork); - - xfs_btree_setbuf(cur, level, cbp); - - /* - * Do all this logging at the end so that - * the root is at the right level. - */ - xfs_btree_log_block(cur, cbp, XFS_BB_ALL_BITS); - xfs_btree_log_keys(cur, cbp, 1, be16_to_cpu(cblock->bb_numrecs)); - xfs_btree_log_ptrs(cur, cbp, 1, be16_to_cpu(cblock->bb_numrecs)); - - *logflags |= - XFS_ILOG_CORE | xfs_ilog_fbroot(cur->bc_private.b.whichfork); - *stat = 1; - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - return 0; -error0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; -} - -/* - * Allocate a new root block, fill it in. - */ -STATIC int /* error */ -xfs_btree_new_root( - struct xfs_btree_cur *cur, /* btree cursor */ - int *stat) /* success/failure */ -{ - struct xfs_btree_block *block; /* one half of the old root block */ - struct xfs_buf *bp; /* buffer containing block */ - int error; /* error return value */ - struct xfs_buf *lbp; /* left buffer pointer */ - struct xfs_btree_block *left; /* left btree block */ - struct xfs_buf *nbp; /* new (root) buffer */ - struct xfs_btree_block *new; /* new (root) btree block */ - int nptr; /* new value for key index, 1 or 2 */ - struct xfs_buf *rbp; /* right buffer pointer */ - struct xfs_btree_block *right; /* right btree block */ - union xfs_btree_ptr rptr; - union xfs_btree_ptr lptr; - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - XFS_BTREE_STATS_INC(cur, newroot); - - /* initialise our start point from the cursor */ - cur->bc_ops->init_ptr_from_cur(cur, &rptr); - - /* Allocate the new block. If we can't do it, we're toast. Give up. */ - error = cur->bc_ops->alloc_block(cur, &rptr, &lptr, stat); - if (error) - goto error0; - if (*stat == 0) - goto out0; - XFS_BTREE_STATS_INC(cur, alloc); - - /* Set up the new block. */ - error = xfs_btree_get_buf_block(cur, &lptr, 0, &new, &nbp); - if (error) - goto error0; - - /* Set the root in the holding structure increasing the level by 1. */ - cur->bc_ops->set_root(cur, &lptr, 1); - - /* - * At the previous root level there are now two blocks: the old root, - * and the new block generated when it was split. We don't know which - * one the cursor is pointing at, so we set up variables "left" and - * "right" for each case. - */ - block = xfs_btree_get_block(cur, cur->bc_nlevels - 1, &bp); - -#ifdef DEBUG - error = xfs_btree_check_block(cur, block, cur->bc_nlevels - 1, bp); - if (error) - goto error0; -#endif - - xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB); - if (!xfs_btree_ptr_is_null(cur, &rptr)) { - /* Our block is left, pick up the right block. */ - lbp = bp; - xfs_btree_buf_to_ptr(cur, lbp, &lptr); - left = block; - error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp); - if (error) - goto error0; - bp = rbp; - nptr = 1; - } else { - /* Our block is right, pick up the left block. */ - rbp = bp; - xfs_btree_buf_to_ptr(cur, rbp, &rptr); - right = block; - xfs_btree_get_sibling(cur, right, &lptr, XFS_BB_LEFTSIB); - error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp); - if (error) - goto error0; - bp = lbp; - nptr = 2; - } - - /* Fill in the new block's btree header and log it. */ - xfs_btree_init_block_cur(cur, nbp, cur->bc_nlevels, 2); - xfs_btree_log_block(cur, nbp, XFS_BB_ALL_BITS); - ASSERT(!xfs_btree_ptr_is_null(cur, &lptr) && - !xfs_btree_ptr_is_null(cur, &rptr)); - - /* Fill in the key data in the new root. */ - if (xfs_btree_get_level(left) > 0) { - /* - * Get the keys for the left block's keys and put them directly - * in the parent block. Do the same for the right block. - */ - xfs_btree_get_node_keys(cur, left, - xfs_btree_key_addr(cur, 1, new)); - xfs_btree_get_node_keys(cur, right, - xfs_btree_key_addr(cur, 2, new)); - } else { - /* - * Get the keys for the left block's records and put them - * directly in the parent block. Do the same for the right - * block. - */ - xfs_btree_get_leaf_keys(cur, left, - xfs_btree_key_addr(cur, 1, new)); - xfs_btree_get_leaf_keys(cur, right, - xfs_btree_key_addr(cur, 2, new)); - } - xfs_btree_log_keys(cur, nbp, 1, 2); - - /* Fill in the pointer data in the new root. */ - xfs_btree_copy_ptrs(cur, - xfs_btree_ptr_addr(cur, 1, new), &lptr, 1); - xfs_btree_copy_ptrs(cur, - xfs_btree_ptr_addr(cur, 2, new), &rptr, 1); - xfs_btree_log_ptrs(cur, nbp, 1, 2); - - /* Fix up the cursor. */ - xfs_btree_setbuf(cur, cur->bc_nlevels, nbp); - cur->bc_ptrs[cur->bc_nlevels] = nptr; - cur->bc_nlevels++; - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 1; - return 0; -error0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; -out0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 0; - return 0; -} - -STATIC int -xfs_btree_make_block_unfull( - struct xfs_btree_cur *cur, /* btree cursor */ - int level, /* btree level */ - int numrecs,/* # of recs in block */ - int *oindex,/* old tree index */ - int *index, /* new tree index */ - union xfs_btree_ptr *nptr, /* new btree ptr */ - struct xfs_btree_cur **ncur, /* new btree cursor */ - union xfs_btree_key *key, /* key of new block */ - int *stat) -{ - int error = 0; - - if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && - level == cur->bc_nlevels - 1) { - struct xfs_inode *ip = cur->bc_private.b.ip; - - if (numrecs < cur->bc_ops->get_dmaxrecs(cur, level)) { - /* A root block that can be made bigger. */ - xfs_iroot_realloc(ip, 1, cur->bc_private.b.whichfork); - *stat = 1; - } else { - /* A root block that needs replacing */ - int logflags = 0; - - error = xfs_btree_new_iroot(cur, &logflags, stat); - if (error || *stat == 0) - return error; - - xfs_trans_log_inode(cur->bc_tp, ip, logflags); - } - - return 0; - } - - /* First, try shifting an entry to the right neighbor. */ - error = xfs_btree_rshift(cur, level, stat); - if (error || *stat) - return error; - - /* Next, try shifting an entry to the left neighbor. */ - error = xfs_btree_lshift(cur, level, stat); - if (error) - return error; - - if (*stat) { - *oindex = *index = cur->bc_ptrs[level]; - return 0; - } - - /* - * Next, try splitting the current block in half. - * - * If this works we have to re-set our variables because we - * could be in a different block now. - */ - error = xfs_btree_split(cur, level, nptr, key, ncur, stat); - if (error || *stat == 0) - return error; - - - *index = cur->bc_ptrs[level]; - return 0; -} - -/* - * Insert one record/level. Return information to the caller - * allowing the next level up to proceed if necessary. - */ -STATIC int -xfs_btree_insrec( - struct xfs_btree_cur *cur, /* btree cursor */ - int level, /* level to insert record at */ - union xfs_btree_ptr *ptrp, /* i/o: block number inserted */ - union xfs_btree_rec *rec, /* record to insert */ - union xfs_btree_key *key, /* i/o: block key for ptrp */ - struct xfs_btree_cur **curp, /* output: new cursor replacing cur */ - int *stat) /* success/failure */ -{ - struct xfs_btree_block *block; /* btree block */ - struct xfs_buf *bp; /* buffer for block */ - union xfs_btree_ptr nptr; /* new block ptr */ - struct xfs_btree_cur *ncur; /* new btree cursor */ - union xfs_btree_key nkey; /* new block key */ - union xfs_btree_key *lkey; - int optr; /* old key/record index */ - int ptr; /* key/record index */ - int numrecs;/* number of records */ - int error; /* error return value */ -#ifdef DEBUG - int i; -#endif - xfs_daddr_t old_bn; - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - XFS_BTREE_TRACE_ARGIPR(cur, level, *ptrp, &rec); - - ncur = NULL; - lkey = &nkey; - - /* - * If we have an external root pointer, and we've made it to the - * root level, allocate a new root block and we're done. - */ - if (!(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) && - (level >= cur->bc_nlevels)) { - error = xfs_btree_new_root(cur, stat); - xfs_btree_set_ptr_null(cur, ptrp); - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - return error; - } - - /* If we're off the left edge, return failure. */ - ptr = cur->bc_ptrs[level]; - if (ptr == 0) { - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 0; - return 0; - } - - optr = ptr; - - XFS_BTREE_STATS_INC(cur, insrec); - - /* Get pointers to the btree buffer and block. */ - block = xfs_btree_get_block(cur, level, &bp); - old_bn = bp ? bp->b_bn : XFS_BUF_DADDR_NULL; - numrecs = xfs_btree_get_numrecs(block); - -#ifdef DEBUG - error = xfs_btree_check_block(cur, block, level, bp); - if (error) - goto error0; - - /* Check that the new entry is being inserted in the right place. */ - if (ptr <= numrecs) { - if (level == 0) { - ASSERT(cur->bc_ops->recs_inorder(cur, rec, - xfs_btree_rec_addr(cur, ptr, block))); - } else { - ASSERT(cur->bc_ops->keys_inorder(cur, key, - xfs_btree_key_addr(cur, ptr, block))); - } - } -#endif - - /* - * If the block is full, we can't insert the new entry until we - * make the block un-full. - */ - xfs_btree_set_ptr_null(cur, &nptr); - if (numrecs == cur->bc_ops->get_maxrecs(cur, level)) { - error = xfs_btree_make_block_unfull(cur, level, numrecs, - &optr, &ptr, &nptr, &ncur, lkey, stat); - if (error || *stat == 0) - goto error0; - } - - /* - * The current block may have changed if the block was - * previously full and we have just made space in it. - */ - block = xfs_btree_get_block(cur, level, &bp); - numrecs = xfs_btree_get_numrecs(block); - -#ifdef DEBUG - error = xfs_btree_check_block(cur, block, level, bp); - if (error) - return error; -#endif - - /* - * At this point we know there's room for our new entry in the block - * we're pointing at. - */ - XFS_BTREE_STATS_ADD(cur, moves, numrecs - ptr + 1); - - if (level > 0) { - /* It's a nonleaf. make a hole in the keys and ptrs */ - union xfs_btree_key *kp; - union xfs_btree_ptr *pp; - - kp = xfs_btree_key_addr(cur, ptr, block); - pp = xfs_btree_ptr_addr(cur, ptr, block); - -#ifdef DEBUG - for (i = numrecs - ptr; i >= 0; i--) { - error = xfs_btree_check_ptr(cur, pp, i, level); - if (error) - return error; - } -#endif - - xfs_btree_shift_keys(cur, kp, 1, numrecs - ptr + 1); - xfs_btree_shift_ptrs(cur, pp, 1, numrecs - ptr + 1); - -#ifdef DEBUG - error = xfs_btree_check_ptr(cur, ptrp, 0, level); - if (error) - goto error0; -#endif - - /* Now put the new data in, bump numrecs and log it. */ - xfs_btree_copy_keys(cur, kp, key, 1); - xfs_btree_copy_ptrs(cur, pp, ptrp, 1); - numrecs++; - xfs_btree_set_numrecs(block, numrecs); - xfs_btree_log_ptrs(cur, bp, ptr, numrecs); - xfs_btree_log_keys(cur, bp, ptr, numrecs); -#ifdef DEBUG - if (ptr < numrecs) { - ASSERT(cur->bc_ops->keys_inorder(cur, kp, - xfs_btree_key_addr(cur, ptr + 1, block))); - } -#endif - } else { - /* It's a leaf. make a hole in the records */ - union xfs_btree_rec *rp; - - rp = xfs_btree_rec_addr(cur, ptr, block); - - xfs_btree_shift_recs(cur, rp, 1, numrecs - ptr + 1); - - /* Now put the new data in, bump numrecs and log it. */ - xfs_btree_copy_recs(cur, rp, rec, 1); - xfs_btree_set_numrecs(block, ++numrecs); - xfs_btree_log_recs(cur, bp, ptr, numrecs); -#ifdef DEBUG - if (ptr < numrecs) { - ASSERT(cur->bc_ops->recs_inorder(cur, rp, - xfs_btree_rec_addr(cur, ptr + 1, block))); - } -#endif - } - - /* Log the new number of records in the btree header. */ - xfs_btree_log_block(cur, bp, XFS_BB_NUMRECS); - - /* - * If we just inserted into a new tree block, we have to - * recalculate nkey here because nkey is out of date. - * - * Otherwise we're just updating an existing block (having shoved - * some records into the new tree block), so use the regular key - * update mechanism. - */ - if (bp && bp->b_bn != old_bn) { - xfs_btree_get_keys(cur, block, lkey); - } else if (xfs_btree_needs_key_update(cur, optr)) { - error = xfs_btree_update_keys(cur, level); - if (error) - goto error0; - } - - /* - * If we are tracking the last record in the tree and - * we are at the far right edge of the tree, update it. - */ - if (xfs_btree_is_lastrec(cur, block, level)) { - cur->bc_ops->update_lastrec(cur, block, rec, - ptr, LASTREC_INSREC); - } - - /* - * Return the new block number, if any. - * If there is one, give back a record value and a cursor too. - */ - *ptrp = nptr; - if (!xfs_btree_ptr_is_null(cur, &nptr)) { - xfs_btree_copy_keys(cur, key, lkey, 1); - *curp = ncur; - } - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 1; - return 0; - -error0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; -} - -/* - * Insert the record at the point referenced by cur. - * - * A multi-level split of the tree on insert will invalidate the original - * cursor. All callers of this function should assume that the cursor is - * no longer valid and revalidate it. - */ -int -xfs_btree_insert( - struct xfs_btree_cur *cur, - int *stat) -{ - int error; /* error return value */ - int i; /* result value, 0 for failure */ - int level; /* current level number in btree */ - union xfs_btree_ptr nptr; /* new block number (split result) */ - struct xfs_btree_cur *ncur; /* new cursor (split result) */ - struct xfs_btree_cur *pcur; /* previous level's cursor */ - union xfs_btree_key bkey; /* key of block to insert */ - union xfs_btree_key *key; - union xfs_btree_rec rec; /* record to insert */ - - level = 0; - ncur = NULL; - pcur = cur; - key = &bkey; - - xfs_btree_set_ptr_null(cur, &nptr); - - /* Make a key out of the record data to be inserted, and save it. */ - cur->bc_ops->init_rec_from_cur(cur, &rec); - cur->bc_ops->init_key_from_rec(key, &rec); - - /* - * Loop going up the tree, starting at the leaf level. - * Stop when we don't get a split block, that must mean that - * the insert is finished with this level. - */ - do { - /* - * Insert nrec/nptr into this level of the tree. - * Note if we fail, nptr will be null. - */ - error = xfs_btree_insrec(pcur, level, &nptr, &rec, key, - &ncur, &i); - if (error) { - if (pcur != cur) - xfs_btree_del_cursor(pcur, XFS_BTREE_ERROR); - goto error0; - } - - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); - level++; - - /* - * See if the cursor we just used is trash. - * Can't trash the caller's cursor, but otherwise we should - * if ncur is a new cursor or we're about to be done. - */ - if (pcur != cur && - (ncur || xfs_btree_ptr_is_null(cur, &nptr))) { - /* Save the state from the cursor before we trash it */ - if (cur->bc_ops->update_cursor) - cur->bc_ops->update_cursor(pcur, cur); - cur->bc_nlevels = pcur->bc_nlevels; - xfs_btree_del_cursor(pcur, XFS_BTREE_NOERROR); - } - /* If we got a new cursor, switch to it. */ - if (ncur) { - pcur = ncur; - ncur = NULL; - } - } while (!xfs_btree_ptr_is_null(cur, &nptr)); - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = i; - return 0; -error0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; -} - -/* - * Try to merge a non-leaf block back into the inode root. - * - * Note: the killroot names comes from the fact that we're effectively - * killing the old root block. But because we can't just delete the - * inode we have to copy the single block it was pointing to into the - * inode. - */ -STATIC int -xfs_btree_kill_iroot( - struct xfs_btree_cur *cur) -{ - int whichfork = cur->bc_private.b.whichfork; - struct xfs_inode *ip = cur->bc_private.b.ip; - struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); - struct xfs_btree_block *block; - struct xfs_btree_block *cblock; - union xfs_btree_key *kp; - union xfs_btree_key *ckp; - union xfs_btree_ptr *pp; - union xfs_btree_ptr *cpp; - struct xfs_buf *cbp; - int level; - int index; - int numrecs; - int error; -#ifdef DEBUG - union xfs_btree_ptr ptr; - int i; -#endif - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - - ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE); - ASSERT(cur->bc_nlevels > 1); - - /* - * Don't deal with the root block needs to be a leaf case. - * We're just going to turn the thing back into extents anyway. - */ - level = cur->bc_nlevels - 1; - if (level == 1) - goto out0; - - /* - * Give up if the root has multiple children. - */ - block = xfs_btree_get_iroot(cur); - if (xfs_btree_get_numrecs(block) != 1) - goto out0; - - cblock = xfs_btree_get_block(cur, level - 1, &cbp); - numrecs = xfs_btree_get_numrecs(cblock); - - /* - * Only do this if the next level will fit. - * Then the data must be copied up to the inode, - * instead of freeing the root you free the next level. - */ - if (numrecs > cur->bc_ops->get_dmaxrecs(cur, level)) - goto out0; - - XFS_BTREE_STATS_INC(cur, killroot); - -#ifdef DEBUG - xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_LEFTSIB); - ASSERT(xfs_btree_ptr_is_null(cur, &ptr)); - xfs_btree_get_sibling(cur, block, &ptr, XFS_BB_RIGHTSIB); - ASSERT(xfs_btree_ptr_is_null(cur, &ptr)); -#endif - - index = numrecs - cur->bc_ops->get_maxrecs(cur, level); - if (index) { - xfs_iroot_realloc(cur->bc_private.b.ip, index, - cur->bc_private.b.whichfork); - block = ifp->if_broot; - } - - be16_add_cpu(&block->bb_numrecs, index); - ASSERT(block->bb_numrecs == cblock->bb_numrecs); - - kp = xfs_btree_key_addr(cur, 1, block); - ckp = xfs_btree_key_addr(cur, 1, cblock); - xfs_btree_copy_keys(cur, kp, ckp, numrecs); - - pp = xfs_btree_ptr_addr(cur, 1, block); - cpp = xfs_btree_ptr_addr(cur, 1, cblock); -#ifdef DEBUG - for (i = 0; i < numrecs; i++) { - error = xfs_btree_check_ptr(cur, cpp, i, level - 1); - if (error) { - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; - } - } -#endif - xfs_btree_copy_ptrs(cur, pp, cpp, numrecs); - - error = xfs_btree_free_block(cur, cbp); - if (error) { - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; - } - - cur->bc_bufs[level - 1] = NULL; - be16_add_cpu(&block->bb_level, -1); - xfs_trans_log_inode(cur->bc_tp, ip, - XFS_ILOG_CORE | xfs_ilog_fbroot(cur->bc_private.b.whichfork)); - cur->bc_nlevels--; -out0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - return 0; -} - -/* - * Kill the current root node, and replace it with it's only child node. - */ -STATIC int -xfs_btree_kill_root( - struct xfs_btree_cur *cur, - struct xfs_buf *bp, - int level, - union xfs_btree_ptr *newroot) -{ - int error; - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - XFS_BTREE_STATS_INC(cur, killroot); - - /* - * Update the root pointer, decreasing the level by 1 and then - * free the old root. - */ - cur->bc_ops->set_root(cur, newroot, -1); - - error = xfs_btree_free_block(cur, bp); - if (error) { - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; - } - - cur->bc_bufs[level] = NULL; - cur->bc_ra[level] = 0; - cur->bc_nlevels--; - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - return 0; -} - -STATIC int -xfs_btree_dec_cursor( - struct xfs_btree_cur *cur, - int level, - int *stat) -{ - int error; - int i; - - if (level > 0) { - error = xfs_btree_decrement(cur, level, &i); - if (error) - return error; - } - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 1; - return 0; -} - -/* - * Single level of the btree record deletion routine. - * Delete record pointed to by cur/level. - * Remove the record from its block then rebalance the tree. - * Return 0 for error, 1 for done, 2 to go on to the next level. - */ -STATIC int /* error */ -xfs_btree_delrec( - struct xfs_btree_cur *cur, /* btree cursor */ - int level, /* level removing record from */ - int *stat) /* fail/done/go-on */ -{ - struct xfs_btree_block *block; /* btree block */ - union xfs_btree_ptr cptr; /* current block ptr */ - struct xfs_buf *bp; /* buffer for block */ - int error; /* error return value */ - int i; /* loop counter */ - union xfs_btree_ptr lptr; /* left sibling block ptr */ - struct xfs_buf *lbp; /* left buffer pointer */ - struct xfs_btree_block *left; /* left btree block */ - int lrecs = 0; /* left record count */ - int ptr; /* key/record index */ - union xfs_btree_ptr rptr; /* right sibling block ptr */ - struct xfs_buf *rbp; /* right buffer pointer */ - struct xfs_btree_block *right; /* right btree block */ - struct xfs_btree_block *rrblock; /* right-right btree block */ - struct xfs_buf *rrbp; /* right-right buffer pointer */ - int rrecs = 0; /* right record count */ - struct xfs_btree_cur *tcur; /* temporary btree cursor */ - int numrecs; /* temporary numrec count */ - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - XFS_BTREE_TRACE_ARGI(cur, level); - - tcur = NULL; - - /* Get the index of the entry being deleted, check for nothing there. */ - ptr = cur->bc_ptrs[level]; - if (ptr == 0) { - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 0; - return 0; - } - - /* Get the buffer & block containing the record or key/ptr. */ - block = xfs_btree_get_block(cur, level, &bp); - numrecs = xfs_btree_get_numrecs(block); - -#ifdef DEBUG - error = xfs_btree_check_block(cur, block, level, bp); - if (error) - goto error0; -#endif - - /* Fail if we're off the end of the block. */ - if (ptr > numrecs) { - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 0; - return 0; - } - - XFS_BTREE_STATS_INC(cur, delrec); - XFS_BTREE_STATS_ADD(cur, moves, numrecs - ptr); - - /* Excise the entries being deleted. */ - if (level > 0) { - /* It's a nonleaf. operate on keys and ptrs */ - union xfs_btree_key *lkp; - union xfs_btree_ptr *lpp; - - lkp = xfs_btree_key_addr(cur, ptr + 1, block); - lpp = xfs_btree_ptr_addr(cur, ptr + 1, block); - -#ifdef DEBUG - for (i = 0; i < numrecs - ptr; i++) { - error = xfs_btree_check_ptr(cur, lpp, i, level); - if (error) - goto error0; - } -#endif - - if (ptr < numrecs) { - xfs_btree_shift_keys(cur, lkp, -1, numrecs - ptr); - xfs_btree_shift_ptrs(cur, lpp, -1, numrecs - ptr); - xfs_btree_log_keys(cur, bp, ptr, numrecs - 1); - xfs_btree_log_ptrs(cur, bp, ptr, numrecs - 1); - } - } else { - /* It's a leaf. operate on records */ - if (ptr < numrecs) { - xfs_btree_shift_recs(cur, - xfs_btree_rec_addr(cur, ptr + 1, block), - -1, numrecs - ptr); - xfs_btree_log_recs(cur, bp, ptr, numrecs - 1); - } - } - - /* - * Decrement and log the number of entries in the block. - */ - xfs_btree_set_numrecs(block, --numrecs); - xfs_btree_log_block(cur, bp, XFS_BB_NUMRECS); - - /* - * If we are tracking the last record in the tree and - * we are at the far right edge of the tree, update it. - */ - if (xfs_btree_is_lastrec(cur, block, level)) { - cur->bc_ops->update_lastrec(cur, block, NULL, - ptr, LASTREC_DELREC); - } - - /* - * We're at the root level. First, shrink the root block in-memory. - * Try to get rid of the next level down. If we can't then there's - * nothing left to do. - */ - if (level == cur->bc_nlevels - 1) { - if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) { - xfs_iroot_realloc(cur->bc_private.b.ip, -1, - cur->bc_private.b.whichfork); - - error = xfs_btree_kill_iroot(cur); - if (error) - goto error0; - - error = xfs_btree_dec_cursor(cur, level, stat); - if (error) - goto error0; - *stat = 1; - return 0; - } - - /* - * If this is the root level, and there's only one entry left, - * and it's NOT the leaf level, then we can get rid of this - * level. - */ - if (numrecs == 1 && level > 0) { - union xfs_btree_ptr *pp; - /* - * pp is still set to the first pointer in the block. - * Make it the new root of the btree. - */ - pp = xfs_btree_ptr_addr(cur, 1, block); - error = xfs_btree_kill_root(cur, bp, level, pp); - if (error) - goto error0; - } else if (level > 0) { - error = xfs_btree_dec_cursor(cur, level, stat); - if (error) - goto error0; - } - *stat = 1; - return 0; - } - - /* - * If we deleted the leftmost entry in the block, update the - * key values above us in the tree. - */ - if (xfs_btree_needs_key_update(cur, ptr)) { - error = xfs_btree_update_keys(cur, level); - if (error) - goto error0; - } - - /* - * If the number of records remaining in the block is at least - * the minimum, we're done. - */ - if (numrecs >= cur->bc_ops->get_minrecs(cur, level)) { - error = xfs_btree_dec_cursor(cur, level, stat); - if (error) - goto error0; - return 0; - } - - /* - * Otherwise, we have to move some records around to keep the - * tree balanced. Look at the left and right sibling blocks to - * see if we can re-balance by moving only one record. - */ - xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB); - xfs_btree_get_sibling(cur, block, &lptr, XFS_BB_LEFTSIB); - - if (cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) { - /* - * One child of root, need to get a chance to copy its contents - * into the root and delete it. Can't go up to next level, - * there's nothing to delete there. - */ - if (xfs_btree_ptr_is_null(cur, &rptr) && - xfs_btree_ptr_is_null(cur, &lptr) && - level == cur->bc_nlevels - 2) { - error = xfs_btree_kill_iroot(cur); - if (!error) - error = xfs_btree_dec_cursor(cur, level, stat); - if (error) - goto error0; - return 0; - } - } - - ASSERT(!xfs_btree_ptr_is_null(cur, &rptr) || - !xfs_btree_ptr_is_null(cur, &lptr)); - - /* - * Duplicate the cursor so our btree manipulations here won't - * disrupt the next level up. - */ - error = xfs_btree_dup_cursor(cur, &tcur); - if (error) - goto error0; - - /* - * If there's a right sibling, see if it's ok to shift an entry - * out of it. - */ - if (!xfs_btree_ptr_is_null(cur, &rptr)) { - /* - * Move the temp cursor to the last entry in the next block. - * Actually any entry but the first would suffice. - */ - i = xfs_btree_lastrec(tcur, level); - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); - - error = xfs_btree_increment(tcur, level, &i); - if (error) - goto error0; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); - - i = xfs_btree_lastrec(tcur, level); - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); - - /* Grab a pointer to the block. */ - right = xfs_btree_get_block(tcur, level, &rbp); -#ifdef DEBUG - error = xfs_btree_check_block(tcur, right, level, rbp); - if (error) - goto error0; -#endif - /* Grab the current block number, for future use. */ - xfs_btree_get_sibling(tcur, right, &cptr, XFS_BB_LEFTSIB); - - /* - * If right block is full enough so that removing one entry - * won't make it too empty, and left-shifting an entry out - * of right to us works, we're done. - */ - if (xfs_btree_get_numrecs(right) - 1 >= - cur->bc_ops->get_minrecs(tcur, level)) { - error = xfs_btree_lshift(tcur, level, &i); - if (error) - goto error0; - if (i) { - ASSERT(xfs_btree_get_numrecs(block) >= - cur->bc_ops->get_minrecs(tcur, level)); - - xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); - tcur = NULL; - - error = xfs_btree_dec_cursor(cur, level, stat); - if (error) - goto error0; - return 0; - } - } - - /* - * Otherwise, grab the number of records in right for - * future reference, and fix up the temp cursor to point - * to our block again (last record). - */ - rrecs = xfs_btree_get_numrecs(right); - if (!xfs_btree_ptr_is_null(cur, &lptr)) { - i = xfs_btree_firstrec(tcur, level); - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); - - error = xfs_btree_decrement(tcur, level, &i); - if (error) - goto error0; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); - } - } - - /* - * If there's a left sibling, see if it's ok to shift an entry - * out of it. - */ - if (!xfs_btree_ptr_is_null(cur, &lptr)) { - /* - * Move the temp cursor to the first entry in the - * previous block. - */ - i = xfs_btree_firstrec(tcur, level); - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); - - error = xfs_btree_decrement(tcur, level, &i); - if (error) - goto error0; - i = xfs_btree_firstrec(tcur, level); - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, error0); - - /* Grab a pointer to the block. */ - left = xfs_btree_get_block(tcur, level, &lbp); -#ifdef DEBUG - error = xfs_btree_check_block(cur, left, level, lbp); - if (error) - goto error0; -#endif - /* Grab the current block number, for future use. */ - xfs_btree_get_sibling(tcur, left, &cptr, XFS_BB_RIGHTSIB); - - /* - * If left block is full enough so that removing one entry - * won't make it too empty, and right-shifting an entry out - * of left to us works, we're done. - */ - if (xfs_btree_get_numrecs(left) - 1 >= - cur->bc_ops->get_minrecs(tcur, level)) { - error = xfs_btree_rshift(tcur, level, &i); - if (error) - goto error0; - if (i) { - ASSERT(xfs_btree_get_numrecs(block) >= - cur->bc_ops->get_minrecs(tcur, level)); - xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); - tcur = NULL; - if (level == 0) - cur->bc_ptrs[0]++; - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 1; - return 0; - } - } - - /* - * Otherwise, grab the number of records in right for - * future reference. - */ - lrecs = xfs_btree_get_numrecs(left); - } - - /* Delete the temp cursor, we're done with it. */ - xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); - tcur = NULL; - - /* If here, we need to do a join to keep the tree balanced. */ - ASSERT(!xfs_btree_ptr_is_null(cur, &cptr)); - - if (!xfs_btree_ptr_is_null(cur, &lptr) && - lrecs + xfs_btree_get_numrecs(block) <= - cur->bc_ops->get_maxrecs(cur, level)) { - /* - * Set "right" to be the starting block, - * "left" to be the left neighbor. - */ - rptr = cptr; - right = block; - rbp = bp; - error = xfs_btree_read_buf_block(cur, &lptr, 0, &left, &lbp); - if (error) - goto error0; - - /* - * If that won't work, see if we can join with the right neighbor block. - */ - } else if (!xfs_btree_ptr_is_null(cur, &rptr) && - rrecs + xfs_btree_get_numrecs(block) <= - cur->bc_ops->get_maxrecs(cur, level)) { - /* - * Set "left" to be the starting block, - * "right" to be the right neighbor. - */ - lptr = cptr; - left = block; - lbp = bp; - error = xfs_btree_read_buf_block(cur, &rptr, 0, &right, &rbp); - if (error) - goto error0; - - /* - * Otherwise, we can't fix the imbalance. - * Just return. This is probably a logic error, but it's not fatal. - */ - } else { - error = xfs_btree_dec_cursor(cur, level, stat); - if (error) - goto error0; - return 0; - } - - rrecs = xfs_btree_get_numrecs(right); - lrecs = xfs_btree_get_numrecs(left); - - /* - * We're now going to join "left" and "right" by moving all the stuff - * in "right" to "left" and deleting "right". - */ - XFS_BTREE_STATS_ADD(cur, moves, rrecs); - if (level > 0) { - /* It's a non-leaf. Move keys and pointers. */ - union xfs_btree_key *lkp; /* left btree key */ - union xfs_btree_ptr *lpp; /* left address pointer */ - union xfs_btree_key *rkp; /* right btree key */ - union xfs_btree_ptr *rpp; /* right address pointer */ - - lkp = xfs_btree_key_addr(cur, lrecs + 1, left); - lpp = xfs_btree_ptr_addr(cur, lrecs + 1, left); - rkp = xfs_btree_key_addr(cur, 1, right); - rpp = xfs_btree_ptr_addr(cur, 1, right); -#ifdef DEBUG - for (i = 1; i < rrecs; i++) { - error = xfs_btree_check_ptr(cur, rpp, i, level); - if (error) - goto error0; - } -#endif - xfs_btree_copy_keys(cur, lkp, rkp, rrecs); - xfs_btree_copy_ptrs(cur, lpp, rpp, rrecs); - - xfs_btree_log_keys(cur, lbp, lrecs + 1, lrecs + rrecs); - xfs_btree_log_ptrs(cur, lbp, lrecs + 1, lrecs + rrecs); - } else { - /* It's a leaf. Move records. */ - union xfs_btree_rec *lrp; /* left record pointer */ - union xfs_btree_rec *rrp; /* right record pointer */ - - lrp = xfs_btree_rec_addr(cur, lrecs + 1, left); - rrp = xfs_btree_rec_addr(cur, 1, right); - - xfs_btree_copy_recs(cur, lrp, rrp, rrecs); - xfs_btree_log_recs(cur, lbp, lrecs + 1, lrecs + rrecs); - } - - XFS_BTREE_STATS_INC(cur, join); - - /* - * Fix up the number of records and right block pointer in the - * surviving block, and log it. - */ - xfs_btree_set_numrecs(left, lrecs + rrecs); - xfs_btree_get_sibling(cur, right, &cptr, XFS_BB_RIGHTSIB), - xfs_btree_set_sibling(cur, left, &cptr, XFS_BB_RIGHTSIB); - xfs_btree_log_block(cur, lbp, XFS_BB_NUMRECS | XFS_BB_RIGHTSIB); - - /* If there is a right sibling, point it to the remaining block. */ - xfs_btree_get_sibling(cur, left, &cptr, XFS_BB_RIGHTSIB); - if (!xfs_btree_ptr_is_null(cur, &cptr)) { - error = xfs_btree_read_buf_block(cur, &cptr, 0, &rrblock, &rrbp); - if (error) - goto error0; - xfs_btree_set_sibling(cur, rrblock, &lptr, XFS_BB_LEFTSIB); - xfs_btree_log_block(cur, rrbp, XFS_BB_LEFTSIB); - } - - /* Free the deleted block. */ - error = xfs_btree_free_block(cur, rbp); - if (error) - goto error0; - - /* - * If we joined with the left neighbor, set the buffer in the - * cursor to the left block, and fix up the index. - */ - if (bp != lbp) { - cur->bc_bufs[level] = lbp; - cur->bc_ptrs[level] += lrecs; - cur->bc_ra[level] = 0; - } - /* - * If we joined with the right neighbor and there's a level above - * us, increment the cursor at that level. - */ - else if ((cur->bc_flags & XFS_BTREE_ROOT_IN_INODE) || - (level + 1 < cur->bc_nlevels)) { - error = xfs_btree_increment(cur, level + 1, &i); - if (error) - goto error0; - } - - /* - * Readjust the ptr at this level if it's not a leaf, since it's - * still pointing at the deletion point, which makes the cursor - * inconsistent. If this makes the ptr 0, the caller fixes it up. - * We can't use decrement because it would change the next level up. - */ - if (level > 0) - cur->bc_ptrs[level]--; - - /* - * We combined blocks, so we have to update the parent keys if the - * btree supports overlapped intervals. However, bc_ptrs[level + 1] - * points to the old block so that the caller knows which record to - * delete. Therefore, the caller must be savvy enough to call updkeys - * for us if we return stat == 2. The other exit points from this - * function don't require deletions further up the tree, so they can - * call updkeys directly. - */ - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - /* Return value means the next level up has something to do. */ - *stat = 2; - return 0; - -error0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - if (tcur) - xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); - return error; -} - -/* - * Delete the record pointed to by cur. - * The cursor refers to the place where the record was (could be inserted) - * when the operation returns. - */ -int /* error */ -xfs_btree_delete( - struct xfs_btree_cur *cur, - int *stat) /* success/failure */ -{ - int error; /* error return value */ - int level; - int i; - bool joined = false; - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - - /* - * Go up the tree, starting at leaf level. - * - * If 2 is returned then a join was done; go to the next level. - * Otherwise we are done. - */ - for (level = 0, i = 2; i == 2; level++) { - error = xfs_btree_delrec(cur, level, &i); - if (error) - goto error0; - if (i == 2) - joined = true; - } - - /* - * If we combined blocks as part of deleting the record, delrec won't - * have updated the parent high keys so we have to do that here. - */ - if (joined && (cur->bc_flags & XFS_BTREE_OVERLAPPING)) { - error = xfs_btree_updkeys_force(cur, 0); - if (error) - goto error0; - } - - if (i == 0) { - for (level = 1; level < cur->bc_nlevels; level++) { - if (cur->bc_ptrs[level] == 0) { - error = xfs_btree_decrement(cur, level, &i); - if (error) - goto error0; - break; - } - } - } - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = i; - return 0; -error0: - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; -} - -/* - * Get the data from the pointed-to record. - */ -int /* error */ -xfs_btree_get_rec( - struct xfs_btree_cur *cur, /* btree cursor */ - union xfs_btree_rec **recp, /* output: btree record */ - int *stat) /* output: success/failure */ -{ - struct xfs_btree_block *block; /* btree block */ - struct xfs_buf *bp; /* buffer pointer */ - int ptr; /* record number */ -#ifdef DEBUG - int error; /* error return value */ -#endif - - ptr = cur->bc_ptrs[0]; - block = xfs_btree_get_block(cur, 0, &bp); - -#ifdef DEBUG - error = xfs_btree_check_block(cur, block, 0, bp); - if (error) - return error; -#endif - - /* - * Off the right end or left end, return failure. - */ - if (ptr > xfs_btree_get_numrecs(block) || ptr <= 0) { - *stat = 0; - return 0; - } - - /* - * Point to the record and extract its data. - */ - *recp = xfs_btree_rec_addr(cur, ptr, block); - *stat = 1; - return 0; -} - -/* Visit a block in a btree. */ -STATIC int -xfs_btree_visit_block( - struct xfs_btree_cur *cur, - int level, - xfs_btree_visit_blocks_fn fn, - void *data) -{ - struct xfs_btree_block *block; - struct xfs_buf *bp; - union xfs_btree_ptr rptr; - int error; - - /* do right sibling readahead */ - xfs_btree_readahead(cur, level, XFS_BTCUR_RIGHTRA); - block = xfs_btree_get_block(cur, level, &bp); - - /* process the block */ - error = fn(cur, level, data); - if (error) - return error; - - /* now read rh sibling block for next iteration */ - xfs_btree_get_sibling(cur, block, &rptr, XFS_BB_RIGHTSIB); - if (xfs_btree_ptr_is_null(cur, &rptr)) - return -ENOENT; - - return xfs_btree_lookup_get_block(cur, level, &rptr, &block); -} - - -/* Visit every block in a btree. */ -int -xfs_btree_visit_blocks( - struct xfs_btree_cur *cur, - xfs_btree_visit_blocks_fn fn, - void *data) -{ - union xfs_btree_ptr lptr; - int level; - struct xfs_btree_block *block = NULL; - int error = 0; - - cur->bc_ops->init_ptr_from_cur(cur, &lptr); - - /* for each level */ - for (level = cur->bc_nlevels - 1; level >= 0; level--) { - /* grab the left hand block */ - error = xfs_btree_lookup_get_block(cur, level, &lptr, &block); - if (error) - return error; - - /* readahead the left most block for the next level down */ - if (level > 0) { - union xfs_btree_ptr *ptr; - - ptr = xfs_btree_ptr_addr(cur, 1, block); - xfs_btree_readahead_ptr(cur, ptr, 1); - - /* save for the next iteration of the loop */ - lptr = *ptr; - } - - /* for each buffer in the level */ - do { - error = xfs_btree_visit_block(cur, level, fn, data); - } while (!error); - - if (error != -ENOENT) - return error; - } - - return 0; -} - -/* - * Change the owner of a btree. - * - * The mechanism we use here is ordered buffer logging. Because we don't know - * how many buffers were are going to need to modify, we don't really want to - * have to make transaction reservations for the worst case of every buffer in a - * full size btree as that may be more space that we can fit in the log.... - * - * We do the btree walk in the most optimal manner possible - we have sibling - * pointers so we can just walk all the blocks on each level from left to right - * in a single pass, and then move to the next level and do the same. We can - * also do readahead on the sibling pointers to get IO moving more quickly, - * though for slow disks this is unlikely to make much difference to performance - * as the amount of CPU work we have to do before moving to the next block is - * relatively small. - * - * For each btree block that we load, modify the owner appropriately, set the - * buffer as an ordered buffer and log it appropriately. We need to ensure that - * we mark the region we change dirty so that if the buffer is relogged in - * a subsequent transaction the changes we make here as an ordered buffer are - * correctly relogged in that transaction. If we are in recovery context, then - * just queue the modified buffer as delayed write buffer so the transaction - * recovery completion writes the changes to disk. - */ -struct xfs_btree_block_change_owner_info { - __uint64_t new_owner; - struct list_head *buffer_list; -}; - -static int -xfs_btree_block_change_owner( - struct xfs_btree_cur *cur, - int level, - void *data) -{ - struct xfs_btree_block_change_owner_info *bbcoi = data; - struct xfs_btree_block *block; - struct xfs_buf *bp; - - /* modify the owner */ - block = xfs_btree_get_block(cur, level, &bp); - if (cur->bc_flags & XFS_BTREE_LONG_PTRS) - block->bb_u.l.bb_owner = cpu_to_be64(bbcoi->new_owner); - else - block->bb_u.s.bb_owner = cpu_to_be32(bbcoi->new_owner); - - /* - * If the block is a root block hosted in an inode, we might not have a - * buffer pointer here and we shouldn't attempt to log the change as the - * information is already held in the inode and discarded when the root - * block is formatted into the on-disk inode fork. We still change it, - * though, so everything is consistent in memory. - */ - if (bp) { - if (cur->bc_tp) { - xfs_trans_ordered_buf(cur->bc_tp, bp); - xfs_btree_log_block(cur, bp, XFS_BB_OWNER); - } else { - xfs_buf_delwri_queue(bp, bbcoi->buffer_list); - } - } else { - ASSERT(cur->bc_flags & XFS_BTREE_ROOT_IN_INODE); - ASSERT(level == cur->bc_nlevels - 1); - } - - return 0; -} - -int -xfs_btree_change_owner( - struct xfs_btree_cur *cur, - __uint64_t new_owner, - struct list_head *buffer_list) -{ - struct xfs_btree_block_change_owner_info bbcoi; - - bbcoi.new_owner = new_owner; - bbcoi.buffer_list = buffer_list; - - return xfs_btree_visit_blocks(cur, xfs_btree_block_change_owner, - &bbcoi); -} - -/** - * xfs_btree_sblock_v5hdr_verify() -- verify the v5 fields of a short-format - * btree block - * - * @bp: buffer containing the btree block - * @max_recs: pointer to the m_*_mxr max records field in the xfs mount - * @pag_max_level: pointer to the per-ag max level field - */ -bool -xfs_btree_sblock_v5hdr_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); - struct xfs_perag *pag = bp->b_pag; - - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return false; - if (!uuid_equal(&block->bb_u.s.bb_uuid, &mp->m_sb.sb_meta_uuid)) - return false; - if (block->bb_u.s.bb_blkno != cpu_to_be64(bp->b_bn)) - return false; - if (pag && be32_to_cpu(block->bb_u.s.bb_owner) != pag->pag_agno) - return false; - return true; -} - -/** - * xfs_btree_sblock_verify() -- verify a short-format btree block - * - * @bp: buffer containing the btree block - * @max_recs: maximum records allowed in this btree node - */ -bool -xfs_btree_sblock_verify( - struct xfs_buf *bp, - unsigned int max_recs) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); - - /* numrecs verification */ - if (be16_to_cpu(block->bb_numrecs) > max_recs) - return false; - - /* sibling pointer verification */ - if (!block->bb_u.s.bb_leftsib || - (be32_to_cpu(block->bb_u.s.bb_leftsib) >= mp->m_sb.sb_agblocks && - block->bb_u.s.bb_leftsib != cpu_to_be32(NULLAGBLOCK))) - return false; - if (!block->bb_u.s.bb_rightsib || - (be32_to_cpu(block->bb_u.s.bb_rightsib) >= mp->m_sb.sb_agblocks && - block->bb_u.s.bb_rightsib != cpu_to_be32(NULLAGBLOCK))) - return false; - - return true; -} - -/* - * Calculate the number of btree levels needed to store a given number of - * records in a short-format btree. - */ -uint -xfs_btree_compute_maxlevels( - struct xfs_mount *mp, - uint *limits, - unsigned long len) -{ - uint level; - unsigned long maxblocks; - - maxblocks = (len + limits[0] - 1) / limits[0]; - for (level = 1; maxblocks > 1; level++) - maxblocks = (maxblocks + limits[1] - 1) / limits[1]; - return level; -} - -/* - * Query a regular btree for all records overlapping a given interval. - * Start with a LE lookup of the key of low_rec and return all records - * until we find a record with a key greater than the key of high_rec. - */ -STATIC int -xfs_btree_simple_query_range( - struct xfs_btree_cur *cur, - union xfs_btree_key *low_key, - union xfs_btree_key *high_key, - xfs_btree_query_range_fn fn, - void *priv) -{ - union xfs_btree_rec *recp; - union xfs_btree_key rec_key; - __int64_t diff; - int stat; - bool firstrec = true; - int error; - - ASSERT(cur->bc_ops->init_high_key_from_rec); - ASSERT(cur->bc_ops->diff_two_keys); - - /* - * Find the leftmost record. The btree cursor must be set - * to the low record used to generate low_key. - */ - stat = 0; - error = xfs_btree_lookup(cur, XFS_LOOKUP_LE, &stat); - if (error) - goto out; - - /* Nothing? See if there's anything to the right. */ - if (!stat) { - error = xfs_btree_increment(cur, 0, &stat); - if (error) - goto out; - } - - while (stat) { - /* Find the record. */ - error = xfs_btree_get_rec(cur, &recp, &stat); - if (error || !stat) - break; - - /* Skip if high_key(rec) < low_key. */ - if (firstrec) { - cur->bc_ops->init_high_key_from_rec(&rec_key, recp); - firstrec = false; - diff = cur->bc_ops->diff_two_keys(cur, low_key, - &rec_key); - if (diff > 0) - goto advloop; - } - - /* Stop if high_key < low_key(rec). */ - cur->bc_ops->init_key_from_rec(&rec_key, recp); - diff = cur->bc_ops->diff_two_keys(cur, &rec_key, high_key); - if (diff > 0) - break; - - /* Callback */ - error = fn(cur, recp, priv); - if (error < 0 || error == XFS_BTREE_QUERY_RANGE_ABORT) - break; - -advloop: - /* Move on to the next record. */ - error = xfs_btree_increment(cur, 0, &stat); - if (error) - break; - } - -out: - return error; -} - -/* - * Query an overlapped interval btree for all records overlapping a given - * interval. This function roughly follows the algorithm given in - * "Interval Trees" of _Introduction to Algorithms_, which is section - * 14.3 in the 2nd and 3rd editions. - * - * First, generate keys for the low and high records passed in. - * - * For any leaf node, generate the high and low keys for the record. - * If the record keys overlap with the query low/high keys, pass the - * record to the function iterator. - * - * For any internal node, compare the low and high keys of each - * pointer against the query low/high keys. If there's an overlap, - * follow the pointer. - * - * As an optimization, we stop scanning a block when we find a low key - * that is greater than the query's high key. - */ -STATIC int -xfs_btree_overlapped_query_range( - struct xfs_btree_cur *cur, - union xfs_btree_key *low_key, - union xfs_btree_key *high_key, - xfs_btree_query_range_fn fn, - void *priv) -{ - union xfs_btree_ptr ptr; - union xfs_btree_ptr *pp; - union xfs_btree_key rec_key; - union xfs_btree_key rec_hkey; - union xfs_btree_key *lkp; - union xfs_btree_key *hkp; - union xfs_btree_rec *recp; - struct xfs_btree_block *block; - __int64_t ldiff; - __int64_t hdiff; - int level; - struct xfs_buf *bp; - int i; - int error; - - /* Load the root of the btree. */ - level = cur->bc_nlevels - 1; - cur->bc_ops->init_ptr_from_cur(cur, &ptr); - error = xfs_btree_lookup_get_block(cur, level, &ptr, &block); - if (error) - return error; - xfs_btree_get_block(cur, level, &bp); - trace_xfs_btree_overlapped_query_range(cur, level, bp); -#ifdef DEBUG - error = xfs_btree_check_block(cur, block, level, bp); - if (error) - goto out; -#endif - cur->bc_ptrs[level] = 1; - - while (level < cur->bc_nlevels) { - block = xfs_btree_get_block(cur, level, &bp); - - /* End of node, pop back towards the root. */ - if (cur->bc_ptrs[level] > be16_to_cpu(block->bb_numrecs)) { -pop_up: - if (level < cur->bc_nlevels - 1) - cur->bc_ptrs[level + 1]++; - level++; - continue; - } - - if (level == 0) { - /* Handle a leaf node. */ - recp = xfs_btree_rec_addr(cur, cur->bc_ptrs[0], block); - - cur->bc_ops->init_high_key_from_rec(&rec_hkey, recp); - ldiff = cur->bc_ops->diff_two_keys(cur, &rec_hkey, - low_key); - - cur->bc_ops->init_key_from_rec(&rec_key, recp); - hdiff = cur->bc_ops->diff_two_keys(cur, high_key, - &rec_key); - - /* - * If (record's high key >= query's low key) and - * (query's high key >= record's low key), then - * this record overlaps the query range; callback. - */ - if (ldiff >= 0 && hdiff >= 0) { - error = fn(cur, recp, priv); - if (error < 0 || - error == XFS_BTREE_QUERY_RANGE_ABORT) - break; - } else if (hdiff < 0) { - /* Record is larger than high key; pop. */ - goto pop_up; - } - cur->bc_ptrs[level]++; - continue; - } - - /* Handle an internal node. */ - lkp = xfs_btree_key_addr(cur, cur->bc_ptrs[level], block); - hkp = xfs_btree_high_key_addr(cur, cur->bc_ptrs[level], block); - pp = xfs_btree_ptr_addr(cur, cur->bc_ptrs[level], block); - - ldiff = cur->bc_ops->diff_two_keys(cur, hkp, low_key); - hdiff = cur->bc_ops->diff_two_keys(cur, high_key, lkp); - - /* - * If (pointer's high key >= query's low key) and - * (query's high key >= pointer's low key), then - * this record overlaps the query range; follow pointer. - */ - if (ldiff >= 0 && hdiff >= 0) { - level--; - error = xfs_btree_lookup_get_block(cur, level, pp, - &block); - if (error) - goto out; - xfs_btree_get_block(cur, level, &bp); - trace_xfs_btree_overlapped_query_range(cur, level, bp); -#ifdef DEBUG - error = xfs_btree_check_block(cur, block, level, bp); - if (error) - goto out; -#endif - cur->bc_ptrs[level] = 1; - continue; - } else if (hdiff < 0) { - /* The low key is larger than the upper range; pop. */ - goto pop_up; - } - cur->bc_ptrs[level]++; - } - -out: - /* - * If we don't end this function with the cursor pointing at a record - * block, a subsequent non-error cursor deletion will not release - * node-level buffers, causing a buffer leak. This is quite possible - * with a zero-results range query, so release the buffers if we - * failed to return any results. - */ - if (cur->bc_bufs[0] == NULL) { - for (i = 0; i < cur->bc_nlevels; i++) { - if (cur->bc_bufs[i]) { - xfs_trans_brelse(cur->bc_tp, cur->bc_bufs[i]); - cur->bc_bufs[i] = NULL; - cur->bc_ptrs[i] = 0; - cur->bc_ra[i] = 0; - } - } - } - - return error; -} - -/* - * Query a btree for all records overlapping a given interval of keys. The - * supplied function will be called with each record found; return one of the - * XFS_BTREE_QUERY_RANGE_{CONTINUE,ABORT} values or the usual negative error - * code. This function returns XFS_BTREE_QUERY_RANGE_ABORT, zero, or a - * negative error code. - */ -int -xfs_btree_query_range( - struct xfs_btree_cur *cur, - union xfs_btree_irec *low_rec, - union xfs_btree_irec *high_rec, - xfs_btree_query_range_fn fn, - void *priv) -{ - union xfs_btree_rec rec; - union xfs_btree_key low_key; - union xfs_btree_key high_key; - - /* Find the keys of both ends of the interval. */ - cur->bc_rec = *high_rec; - cur->bc_ops->init_rec_from_cur(cur, &rec); - cur->bc_ops->init_key_from_rec(&high_key, &rec); - - cur->bc_rec = *low_rec; - cur->bc_ops->init_rec_from_cur(cur, &rec); - cur->bc_ops->init_key_from_rec(&low_key, &rec); - - /* Enforce low key < high key. */ - if (cur->bc_ops->diff_two_keys(cur, &low_key, &high_key) > 0) - return -EINVAL; - - if (!(cur->bc_flags & XFS_BTREE_OVERLAPPING)) - return xfs_btree_simple_query_range(cur, &low_key, - &high_key, fn, priv); - return xfs_btree_overlapped_query_range(cur, &low_key, &high_key, - fn, priv); -} - -/* - * Calculate the number of blocks needed to store a given number of records - * in a short-format (per-AG metadata) btree. - */ -xfs_extlen_t -xfs_btree_calc_size( - struct xfs_mount *mp, - uint *limits, - unsigned long long len) -{ - int level; - int maxrecs; - xfs_extlen_t rval; - - maxrecs = limits[0]; - for (level = 0, rval = 0; len > 1; level++) { - len += maxrecs - 1; - do_div(len, maxrecs); - maxrecs = limits[1]; - rval += len; - } - return rval; -} - -static int -xfs_btree_count_blocks_helper( - struct xfs_btree_cur *cur, - int level, - void *data) -{ - xfs_extlen_t *blocks = data; - (*blocks)++; - - return 0; -} - -/* Count the blocks in a btree and return the result in *blocks. */ -int -xfs_btree_count_blocks( - struct xfs_btree_cur *cur, - xfs_extlen_t *blocks) -{ - *blocks = 0; - return xfs_btree_visit_blocks(cur, xfs_btree_count_blocks_helper, - blocks); -} diff --git a/src/linux/fs/xfs/libxfs/xfs_btree.h b/src/linux/fs/xfs/libxfs/xfs_btree.h deleted file mode 100644 index c2b01d1..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_btree.h +++ /dev/null @@ -1,540 +0,0 @@ -/* - * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_BTREE_H__ -#define __XFS_BTREE_H__ - -struct xfs_buf; -struct xfs_defer_ops; -struct xfs_inode; -struct xfs_mount; -struct xfs_trans; - -extern kmem_zone_t *xfs_btree_cur_zone; - -/* - * Generic key, ptr and record wrapper structures. - * - * These are disk format structures, and are converted where necessary - * by the btree specific code that needs to interpret them. - */ -union xfs_btree_ptr { - __be32 s; /* short form ptr */ - __be64 l; /* long form ptr */ -}; - -/* - * The in-core btree key. Overlapping btrees actually store two keys - * per pointer, so we reserve enough memory to hold both. The __*bigkey - * items should never be accessed directly. - */ -union xfs_btree_key { - struct xfs_bmbt_key bmbt; - xfs_bmdr_key_t bmbr; /* bmbt root block */ - xfs_alloc_key_t alloc; - struct xfs_inobt_key inobt; - struct xfs_rmap_key rmap; - struct xfs_rmap_key __rmap_bigkey[2]; - struct xfs_refcount_key refc; -}; - -union xfs_btree_rec { - struct xfs_bmbt_rec bmbt; - xfs_bmdr_rec_t bmbr; /* bmbt root block */ - struct xfs_alloc_rec alloc; - struct xfs_inobt_rec inobt; - struct xfs_rmap_rec rmap; - struct xfs_refcount_rec refc; -}; - -/* - * This nonsense is to make -wlint happy. - */ -#define XFS_LOOKUP_EQ ((xfs_lookup_t)XFS_LOOKUP_EQi) -#define XFS_LOOKUP_LE ((xfs_lookup_t)XFS_LOOKUP_LEi) -#define XFS_LOOKUP_GE ((xfs_lookup_t)XFS_LOOKUP_GEi) - -#define XFS_BTNUM_BNO ((xfs_btnum_t)XFS_BTNUM_BNOi) -#define XFS_BTNUM_CNT ((xfs_btnum_t)XFS_BTNUM_CNTi) -#define XFS_BTNUM_BMAP ((xfs_btnum_t)XFS_BTNUM_BMAPi) -#define XFS_BTNUM_INO ((xfs_btnum_t)XFS_BTNUM_INOi) -#define XFS_BTNUM_FINO ((xfs_btnum_t)XFS_BTNUM_FINOi) -#define XFS_BTNUM_RMAP ((xfs_btnum_t)XFS_BTNUM_RMAPi) -#define XFS_BTNUM_REFC ((xfs_btnum_t)XFS_BTNUM_REFCi) - -/* - * For logging record fields. - */ -#define XFS_BB_MAGIC (1 << 0) -#define XFS_BB_LEVEL (1 << 1) -#define XFS_BB_NUMRECS (1 << 2) -#define XFS_BB_LEFTSIB (1 << 3) -#define XFS_BB_RIGHTSIB (1 << 4) -#define XFS_BB_BLKNO (1 << 5) -#define XFS_BB_LSN (1 << 6) -#define XFS_BB_UUID (1 << 7) -#define XFS_BB_OWNER (1 << 8) -#define XFS_BB_NUM_BITS 5 -#define XFS_BB_ALL_BITS ((1 << XFS_BB_NUM_BITS) - 1) -#define XFS_BB_NUM_BITS_CRC 9 -#define XFS_BB_ALL_BITS_CRC ((1 << XFS_BB_NUM_BITS_CRC) - 1) - -/* - * Generic stats interface - */ -#define __XFS_BTREE_STATS_INC(mp, type, stat) \ - XFS_STATS_INC(mp, xs_ ## type ## _2_ ## stat) -#define XFS_BTREE_STATS_INC(cur, stat) \ -do { \ - struct xfs_mount *__mp = cur->bc_mp; \ - switch (cur->bc_btnum) { \ - case XFS_BTNUM_BNO: __XFS_BTREE_STATS_INC(__mp, abtb, stat); break; \ - case XFS_BTNUM_CNT: __XFS_BTREE_STATS_INC(__mp, abtc, stat); break; \ - case XFS_BTNUM_BMAP: __XFS_BTREE_STATS_INC(__mp, bmbt, stat); break; \ - case XFS_BTNUM_INO: __XFS_BTREE_STATS_INC(__mp, ibt, stat); break; \ - case XFS_BTNUM_FINO: __XFS_BTREE_STATS_INC(__mp, fibt, stat); break; \ - case XFS_BTNUM_RMAP: __XFS_BTREE_STATS_INC(__mp, rmap, stat); break; \ - case XFS_BTNUM_REFC: __XFS_BTREE_STATS_INC(__mp, refcbt, stat); break; \ - case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \ - } \ -} while (0) - -#define __XFS_BTREE_STATS_ADD(mp, type, stat, val) \ - XFS_STATS_ADD(mp, xs_ ## type ## _2_ ## stat, val) -#define XFS_BTREE_STATS_ADD(cur, stat, val) \ -do { \ - struct xfs_mount *__mp = cur->bc_mp; \ - switch (cur->bc_btnum) { \ - case XFS_BTNUM_BNO: \ - __XFS_BTREE_STATS_ADD(__mp, abtb, stat, val); break; \ - case XFS_BTNUM_CNT: \ - __XFS_BTREE_STATS_ADD(__mp, abtc, stat, val); break; \ - case XFS_BTNUM_BMAP: \ - __XFS_BTREE_STATS_ADD(__mp, bmbt, stat, val); break; \ - case XFS_BTNUM_INO: \ - __XFS_BTREE_STATS_ADD(__mp, ibt, stat, val); break; \ - case XFS_BTNUM_FINO: \ - __XFS_BTREE_STATS_ADD(__mp, fibt, stat, val); break; \ - case XFS_BTNUM_RMAP: \ - __XFS_BTREE_STATS_ADD(__mp, rmap, stat, val); break; \ - case XFS_BTNUM_REFC: \ - __XFS_BTREE_STATS_ADD(__mp, refcbt, stat, val); break; \ - case XFS_BTNUM_MAX: ASSERT(0); /* fucking gcc */ ; break; \ - } \ -} while (0) - -#define XFS_BTREE_MAXLEVELS 9 /* max of all btrees */ - -struct xfs_btree_ops { - /* size of the key and record structures */ - size_t key_len; - size_t rec_len; - - /* cursor operations */ - struct xfs_btree_cur *(*dup_cursor)(struct xfs_btree_cur *); - void (*update_cursor)(struct xfs_btree_cur *src, - struct xfs_btree_cur *dst); - - /* update btree root pointer */ - void (*set_root)(struct xfs_btree_cur *cur, - union xfs_btree_ptr *nptr, int level_change); - - /* block allocation / freeing */ - int (*alloc_block)(struct xfs_btree_cur *cur, - union xfs_btree_ptr *start_bno, - union xfs_btree_ptr *new_bno, - int *stat); - int (*free_block)(struct xfs_btree_cur *cur, struct xfs_buf *bp); - - /* update last record information */ - void (*update_lastrec)(struct xfs_btree_cur *cur, - struct xfs_btree_block *block, - union xfs_btree_rec *rec, - int ptr, int reason); - - /* records in block/level */ - int (*get_minrecs)(struct xfs_btree_cur *cur, int level); - int (*get_maxrecs)(struct xfs_btree_cur *cur, int level); - - /* records on disk. Matter for the root in inode case. */ - int (*get_dmaxrecs)(struct xfs_btree_cur *cur, int level); - - /* init values of btree structures */ - void (*init_key_from_rec)(union xfs_btree_key *key, - union xfs_btree_rec *rec); - void (*init_rec_from_cur)(struct xfs_btree_cur *cur, - union xfs_btree_rec *rec); - void (*init_ptr_from_cur)(struct xfs_btree_cur *cur, - union xfs_btree_ptr *ptr); - void (*init_high_key_from_rec)(union xfs_btree_key *key, - union xfs_btree_rec *rec); - - /* difference between key value and cursor value */ - __int64_t (*key_diff)(struct xfs_btree_cur *cur, - union xfs_btree_key *key); - - /* - * Difference between key2 and key1 -- positive if key1 > key2, - * negative if key1 < key2, and zero if equal. - */ - __int64_t (*diff_two_keys)(struct xfs_btree_cur *cur, - union xfs_btree_key *key1, - union xfs_btree_key *key2); - - const struct xfs_buf_ops *buf_ops; - -#if defined(DEBUG) || defined(XFS_WARN) - /* check that k1 is lower than k2 */ - int (*keys_inorder)(struct xfs_btree_cur *cur, - union xfs_btree_key *k1, - union xfs_btree_key *k2); - - /* check that r1 is lower than r2 */ - int (*recs_inorder)(struct xfs_btree_cur *cur, - union xfs_btree_rec *r1, - union xfs_btree_rec *r2); -#endif -}; - -/* - * Reasons for the update_lastrec method to be called. - */ -#define LASTREC_UPDATE 0 -#define LASTREC_INSREC 1 -#define LASTREC_DELREC 2 - - -union xfs_btree_irec { - struct xfs_alloc_rec_incore a; - struct xfs_bmbt_irec b; - struct xfs_inobt_rec_incore i; - struct xfs_rmap_irec r; - struct xfs_refcount_irec rc; -}; - -/* Per-AG btree private information. */ -union xfs_btree_cur_private { - struct { - unsigned long nr_ops; /* # record updates */ - int shape_changes; /* # of extent splits */ - } refc; -}; - -/* - * Btree cursor structure. - * This collects all information needed by the btree code in one place. - */ -typedef struct xfs_btree_cur -{ - struct xfs_trans *bc_tp; /* transaction we're in, if any */ - struct xfs_mount *bc_mp; /* file system mount struct */ - const struct xfs_btree_ops *bc_ops; - uint bc_flags; /* btree features - below */ - union xfs_btree_irec bc_rec; /* current insert/search record value */ - struct xfs_buf *bc_bufs[XFS_BTREE_MAXLEVELS]; /* buf ptr per level */ - int bc_ptrs[XFS_BTREE_MAXLEVELS]; /* key/record # */ - __uint8_t bc_ra[XFS_BTREE_MAXLEVELS]; /* readahead bits */ -#define XFS_BTCUR_LEFTRA 1 /* left sibling has been read-ahead */ -#define XFS_BTCUR_RIGHTRA 2 /* right sibling has been read-ahead */ - __uint8_t bc_nlevels; /* number of levels in the tree */ - __uint8_t bc_blocklog; /* log2(blocksize) of btree blocks */ - xfs_btnum_t bc_btnum; /* identifies which btree type */ - union { - struct { /* needed for BNO, CNT, INO */ - struct xfs_buf *agbp; /* agf/agi buffer pointer */ - struct xfs_defer_ops *dfops; /* deferred updates */ - xfs_agnumber_t agno; /* ag number */ - union xfs_btree_cur_private priv; - } a; - struct { /* needed for BMAP */ - struct xfs_inode *ip; /* pointer to our inode */ - struct xfs_defer_ops *dfops; /* deferred updates */ - xfs_fsblock_t firstblock; /* 1st blk allocated */ - int allocated; /* count of alloced */ - short forksize; /* fork's inode space */ - char whichfork; /* data or attr fork */ - char flags; /* flags */ -#define XFS_BTCUR_BPRV_WASDEL 1 /* was delayed */ - } b; - } bc_private; /* per-btree type data */ -} xfs_btree_cur_t; - -/* cursor flags */ -#define XFS_BTREE_LONG_PTRS (1<<0) /* pointers are 64bits long */ -#define XFS_BTREE_ROOT_IN_INODE (1<<1) /* root may be variable size */ -#define XFS_BTREE_LASTREC_UPDATE (1<<2) /* track last rec externally */ -#define XFS_BTREE_CRC_BLOCKS (1<<3) /* uses extended btree blocks */ -#define XFS_BTREE_OVERLAPPING (1<<4) /* overlapping intervals */ - - -#define XFS_BTREE_NOERROR 0 -#define XFS_BTREE_ERROR 1 - -/* - * Convert from buffer to btree block header. - */ -#define XFS_BUF_TO_BLOCK(bp) ((struct xfs_btree_block *)((bp)->b_addr)) - - -/* - * Check that block header is ok. - */ -int -xfs_btree_check_block( - struct xfs_btree_cur *cur, /* btree cursor */ - struct xfs_btree_block *block, /* generic btree block pointer */ - int level, /* level of the btree block */ - struct xfs_buf *bp); /* buffer containing block, if any */ - -/* - * Check that (long) pointer is ok. - */ -int /* error (0 or EFSCORRUPTED) */ -xfs_btree_check_lptr( - struct xfs_btree_cur *cur, /* btree cursor */ - xfs_fsblock_t ptr, /* btree block disk address */ - int level); /* btree block level */ - -/* - * Delete the btree cursor. - */ -void -xfs_btree_del_cursor( - xfs_btree_cur_t *cur, /* btree cursor */ - int error); /* del because of error */ - -/* - * Duplicate the btree cursor. - * Allocate a new one, copy the record, re-get the buffers. - */ -int /* error */ -xfs_btree_dup_cursor( - xfs_btree_cur_t *cur, /* input cursor */ - xfs_btree_cur_t **ncur);/* output cursor */ - -/* - * Get a buffer for the block, return it with no data read. - * Long-form addressing. - */ -struct xfs_buf * /* buffer for fsbno */ -xfs_btree_get_bufl( - struct xfs_mount *mp, /* file system mount point */ - struct xfs_trans *tp, /* transaction pointer */ - xfs_fsblock_t fsbno, /* file system block number */ - uint lock); /* lock flags for get_buf */ - -/* - * Get a buffer for the block, return it with no data read. - * Short-form addressing. - */ -struct xfs_buf * /* buffer for agno/agbno */ -xfs_btree_get_bufs( - struct xfs_mount *mp, /* file system mount point */ - struct xfs_trans *tp, /* transaction pointer */ - xfs_agnumber_t agno, /* allocation group number */ - xfs_agblock_t agbno, /* allocation group block number */ - uint lock); /* lock flags for get_buf */ - -/* - * Check for the cursor referring to the last block at the given level. - */ -int /* 1=is last block, 0=not last block */ -xfs_btree_islastblock( - xfs_btree_cur_t *cur, /* btree cursor */ - int level); /* level to check */ - -/* - * Compute first and last byte offsets for the fields given. - * Interprets the offsets table, which contains struct field offsets. - */ -void -xfs_btree_offsets( - __int64_t fields, /* bitmask of fields */ - const short *offsets,/* table of field offsets */ - int nbits, /* number of bits to inspect */ - int *first, /* output: first byte offset */ - int *last); /* output: last byte offset */ - -/* - * Get a buffer for the block, return it read in. - * Long-form addressing. - */ -int /* error */ -xfs_btree_read_bufl( - struct xfs_mount *mp, /* file system mount point */ - struct xfs_trans *tp, /* transaction pointer */ - xfs_fsblock_t fsbno, /* file system block number */ - uint lock, /* lock flags for read_buf */ - struct xfs_buf **bpp, /* buffer for fsbno */ - int refval, /* ref count value for buffer */ - const struct xfs_buf_ops *ops); - -/* - * Read-ahead the block, don't wait for it, don't return a buffer. - * Long-form addressing. - */ -void /* error */ -xfs_btree_reada_bufl( - struct xfs_mount *mp, /* file system mount point */ - xfs_fsblock_t fsbno, /* file system block number */ - xfs_extlen_t count, /* count of filesystem blocks */ - const struct xfs_buf_ops *ops); - -/* - * Read-ahead the block, don't wait for it, don't return a buffer. - * Short-form addressing. - */ -void /* error */ -xfs_btree_reada_bufs( - struct xfs_mount *mp, /* file system mount point */ - xfs_agnumber_t agno, /* allocation group number */ - xfs_agblock_t agbno, /* allocation group block number */ - xfs_extlen_t count, /* count of filesystem blocks */ - const struct xfs_buf_ops *ops); - -/* - * Initialise a new btree block header - */ -void -xfs_btree_init_block( - struct xfs_mount *mp, - struct xfs_buf *bp, - __u32 magic, - __u16 level, - __u16 numrecs, - __u64 owner, - unsigned int flags); - -void -xfs_btree_init_block_int( - struct xfs_mount *mp, - struct xfs_btree_block *buf, - xfs_daddr_t blkno, - __u32 magic, - __u16 level, - __u16 numrecs, - __u64 owner, - unsigned int flags); - -/* - * Common btree core entry points. - */ -int xfs_btree_increment(struct xfs_btree_cur *, int, int *); -int xfs_btree_decrement(struct xfs_btree_cur *, int, int *); -int xfs_btree_lookup(struct xfs_btree_cur *, xfs_lookup_t, int *); -int xfs_btree_update(struct xfs_btree_cur *, union xfs_btree_rec *); -int xfs_btree_new_iroot(struct xfs_btree_cur *, int *, int *); -int xfs_btree_insert(struct xfs_btree_cur *, int *); -int xfs_btree_delete(struct xfs_btree_cur *, int *); -int xfs_btree_get_rec(struct xfs_btree_cur *, union xfs_btree_rec **, int *); -int xfs_btree_change_owner(struct xfs_btree_cur *cur, __uint64_t new_owner, - struct list_head *buffer_list); - -/* - * btree block CRC helpers - */ -void xfs_btree_lblock_calc_crc(struct xfs_buf *); -bool xfs_btree_lblock_verify_crc(struct xfs_buf *); -void xfs_btree_sblock_calc_crc(struct xfs_buf *); -bool xfs_btree_sblock_verify_crc(struct xfs_buf *); - -/* - * Internal btree helpers also used by xfs_bmap.c. - */ -void xfs_btree_log_block(struct xfs_btree_cur *, struct xfs_buf *, int); -void xfs_btree_log_recs(struct xfs_btree_cur *, struct xfs_buf *, int, int); - -/* - * Helpers. - */ -static inline int xfs_btree_get_numrecs(struct xfs_btree_block *block) -{ - return be16_to_cpu(block->bb_numrecs); -} - -static inline void xfs_btree_set_numrecs(struct xfs_btree_block *block, - __uint16_t numrecs) -{ - block->bb_numrecs = cpu_to_be16(numrecs); -} - -static inline int xfs_btree_get_level(struct xfs_btree_block *block) -{ - return be16_to_cpu(block->bb_level); -} - - -/* - * Min and max functions for extlen, agblock, fileoff, and filblks types. - */ -#define XFS_EXTLEN_MIN(a,b) min_t(xfs_extlen_t, (a), (b)) -#define XFS_EXTLEN_MAX(a,b) max_t(xfs_extlen_t, (a), (b)) -#define XFS_AGBLOCK_MIN(a,b) min_t(xfs_agblock_t, (a), (b)) -#define XFS_AGBLOCK_MAX(a,b) max_t(xfs_agblock_t, (a), (b)) -#define XFS_FILEOFF_MIN(a,b) min_t(xfs_fileoff_t, (a), (b)) -#define XFS_FILEOFF_MAX(a,b) max_t(xfs_fileoff_t, (a), (b)) -#define XFS_FILBLKS_MIN(a,b) min_t(xfs_filblks_t, (a), (b)) -#define XFS_FILBLKS_MAX(a,b) max_t(xfs_filblks_t, (a), (b)) - -#define XFS_FSB_SANITY_CHECK(mp,fsb) \ - (XFS_FSB_TO_AGNO(mp, fsb) < mp->m_sb.sb_agcount && \ - XFS_FSB_TO_AGBNO(mp, fsb) < mp->m_sb.sb_agblocks) - -/* - * Trace hooks. Currently not implemented as they need to be ported - * over to the generic tracing functionality, which is some effort. - * - * i,j = integer (32 bit) - * b = btree block buffer (xfs_buf_t) - * p = btree ptr - * r = btree record - * k = btree key - */ -#define XFS_BTREE_TRACE_ARGBI(c, b, i) -#define XFS_BTREE_TRACE_ARGBII(c, b, i, j) -#define XFS_BTREE_TRACE_ARGI(c, i) -#define XFS_BTREE_TRACE_ARGIPK(c, i, p, s) -#define XFS_BTREE_TRACE_ARGIPR(c, i, p, r) -#define XFS_BTREE_TRACE_ARGIK(c, i, k) -#define XFS_BTREE_TRACE_ARGR(c, r) -#define XFS_BTREE_TRACE_CURSOR(c, t) - -bool xfs_btree_sblock_v5hdr_verify(struct xfs_buf *bp); -bool xfs_btree_sblock_verify(struct xfs_buf *bp, unsigned int max_recs); -uint xfs_btree_compute_maxlevels(struct xfs_mount *mp, uint *limits, - unsigned long len); -xfs_extlen_t xfs_btree_calc_size(struct xfs_mount *mp, uint *limits, - unsigned long long len); - -/* return codes */ -#define XFS_BTREE_QUERY_RANGE_CONTINUE 0 /* keep iterating */ -#define XFS_BTREE_QUERY_RANGE_ABORT 1 /* stop iterating */ -typedef int (*xfs_btree_query_range_fn)(struct xfs_btree_cur *cur, - union xfs_btree_rec *rec, void *priv); - -int xfs_btree_query_range(struct xfs_btree_cur *cur, - union xfs_btree_irec *low_rec, union xfs_btree_irec *high_rec, - xfs_btree_query_range_fn fn, void *priv); - -typedef int (*xfs_btree_visit_blocks_fn)(struct xfs_btree_cur *cur, int level, - void *data); -int xfs_btree_visit_blocks(struct xfs_btree_cur *cur, - xfs_btree_visit_blocks_fn fn, void *data); - -int xfs_btree_count_blocks(struct xfs_btree_cur *cur, xfs_extlen_t *blocks); - -#endif /* __XFS_BTREE_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_cksum.h b/src/linux/fs/xfs/libxfs/xfs_cksum.h deleted file mode 100644 index fad1676..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_cksum.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef _XFS_CKSUM_H -#define _XFS_CKSUM_H 1 - -#define XFS_CRC_SEED (~(__uint32_t)0) - -/* - * Calculate the intermediate checksum for a buffer that has the CRC field - * inside it. The offset of the 32bit crc fields is passed as the - * cksum_offset parameter. - */ -static inline __uint32_t -xfs_start_cksum(char *buffer, size_t length, unsigned long cksum_offset) -{ - __uint32_t zero = 0; - __uint32_t crc; - - /* Calculate CRC up to the checksum. */ - crc = crc32c(XFS_CRC_SEED, buffer, cksum_offset); - - /* Skip checksum field */ - crc = crc32c(crc, &zero, sizeof(__u32)); - - /* Calculate the rest of the CRC. */ - return crc32c(crc, &buffer[cksum_offset + sizeof(__be32)], - length - (cksum_offset + sizeof(__be32))); -} - -/* - * Convert the intermediate checksum to the final ondisk format. - * - * The CRC32c calculation uses LE format even on BE machines, but returns the - * result in host endian format. Hence we need to byte swap it back to LE format - * so that it is consistent on disk. - */ -static inline __le32 -xfs_end_cksum(__uint32_t crc) -{ - return ~cpu_to_le32(crc); -} - -/* - * Helper to generate the checksum for a buffer. - */ -static inline void -xfs_update_cksum(char *buffer, size_t length, unsigned long cksum_offset) -{ - __uint32_t crc = xfs_start_cksum(buffer, length, cksum_offset); - - *(__le32 *)(buffer + cksum_offset) = xfs_end_cksum(crc); -} - -/* - * Helper to verify the checksum for a buffer. - */ -static inline int -xfs_verify_cksum(char *buffer, size_t length, unsigned long cksum_offset) -{ - __uint32_t crc = xfs_start_cksum(buffer, length, cksum_offset); - - return *(__le32 *)(buffer + cksum_offset) == xfs_end_cksum(crc); -} - -#endif /* _XFS_CKSUM_H */ diff --git a/src/linux/fs/xfs/libxfs/xfs_da_btree.c b/src/linux/fs/xfs/libxfs/xfs_da_btree.c deleted file mode 100644 index f2dc1a9..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_da_btree.c +++ /dev/null @@ -1,2670 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * Copyright (c) 2013 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_dir2.h" -#include "xfs_dir2_priv.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_alloc.h" -#include "xfs_bmap.h" -#include "xfs_attr.h" -#include "xfs_attr_leaf.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_cksum.h" -#include "xfs_buf_item.h" -#include "xfs_log.h" - -/* - * xfs_da_btree.c - * - * Routines to implement directories as Btrees of hashed names. - */ - -/*======================================================================== - * Function prototypes for the kernel. - *========================================================================*/ - -/* - * Routines used for growing the Btree. - */ -STATIC int xfs_da3_root_split(xfs_da_state_t *state, - xfs_da_state_blk_t *existing_root, - xfs_da_state_blk_t *new_child); -STATIC int xfs_da3_node_split(xfs_da_state_t *state, - xfs_da_state_blk_t *existing_blk, - xfs_da_state_blk_t *split_blk, - xfs_da_state_blk_t *blk_to_add, - int treelevel, - int *result); -STATIC void xfs_da3_node_rebalance(xfs_da_state_t *state, - xfs_da_state_blk_t *node_blk_1, - xfs_da_state_blk_t *node_blk_2); -STATIC void xfs_da3_node_add(xfs_da_state_t *state, - xfs_da_state_blk_t *old_node_blk, - xfs_da_state_blk_t *new_node_blk); - -/* - * Routines used for shrinking the Btree. - */ -STATIC int xfs_da3_root_join(xfs_da_state_t *state, - xfs_da_state_blk_t *root_blk); -STATIC int xfs_da3_node_toosmall(xfs_da_state_t *state, int *retval); -STATIC void xfs_da3_node_remove(xfs_da_state_t *state, - xfs_da_state_blk_t *drop_blk); -STATIC void xfs_da3_node_unbalance(xfs_da_state_t *state, - xfs_da_state_blk_t *src_node_blk, - xfs_da_state_blk_t *dst_node_blk); - -/* - * Utility routines. - */ -STATIC int xfs_da3_blk_unlink(xfs_da_state_t *state, - xfs_da_state_blk_t *drop_blk, - xfs_da_state_blk_t *save_blk); - - -kmem_zone_t *xfs_da_state_zone; /* anchor for state struct zone */ - -/* - * Allocate a dir-state structure. - * We don't put them on the stack since they're large. - */ -xfs_da_state_t * -xfs_da_state_alloc(void) -{ - return kmem_zone_zalloc(xfs_da_state_zone, KM_NOFS); -} - -/* - * Kill the altpath contents of a da-state structure. - */ -STATIC void -xfs_da_state_kill_altpath(xfs_da_state_t *state) -{ - int i; - - for (i = 0; i < state->altpath.active; i++) - state->altpath.blk[i].bp = NULL; - state->altpath.active = 0; -} - -/* - * Free a da-state structure. - */ -void -xfs_da_state_free(xfs_da_state_t *state) -{ - xfs_da_state_kill_altpath(state); -#ifdef DEBUG - memset((char *)state, 0, sizeof(*state)); -#endif /* DEBUG */ - kmem_zone_free(xfs_da_state_zone, state); -} - -static bool -xfs_da3_node_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_da_intnode *hdr = bp->b_addr; - struct xfs_da3_icnode_hdr ichdr; - const struct xfs_dir_ops *ops; - - ops = xfs_dir_get_ops(mp, NULL); - - ops->node_hdr_from_disk(&ichdr, hdr); - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - struct xfs_da3_node_hdr *hdr3 = bp->b_addr; - - if (ichdr.magic != XFS_DA3_NODE_MAGIC) - return false; - - if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid)) - return false; - if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn) - return false; - if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->info.lsn))) - return false; - } else { - if (ichdr.magic != XFS_DA_NODE_MAGIC) - return false; - } - if (ichdr.level == 0) - return false; - if (ichdr.level > XFS_DA_NODE_MAXDEPTH) - return false; - if (ichdr.count == 0) - return false; - - /* - * we don't know if the node is for and attribute or directory tree, - * so only fail if the count is outside both bounds - */ - if (ichdr.count > mp->m_dir_geo->node_ents && - ichdr.count > mp->m_attr_geo->node_ents) - return false; - - /* XXX: hash order check? */ - - return true; -} - -static void -xfs_da3_node_write_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_buf_log_item *bip = bp->b_fspriv; - struct xfs_da3_node_hdr *hdr3 = bp->b_addr; - - if (!xfs_da3_node_verify(bp)) { - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - return; - } - - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return; - - if (bip) - hdr3->info.lsn = cpu_to_be64(bip->bli_item.li_lsn); - - xfs_buf_update_cksum(bp, XFS_DA3_NODE_CRC_OFF); -} - -/* - * leaf/node format detection on trees is sketchy, so a node read can be done on - * leaf level blocks when detection identifies the tree as a node format tree - * incorrectly. In this case, we need to swap the verifier to match the correct - * format of the block being read. - */ -static void -xfs_da3_node_read_verify( - struct xfs_buf *bp) -{ - struct xfs_da_blkinfo *info = bp->b_addr; - - switch (be16_to_cpu(info->magic)) { - case XFS_DA3_NODE_MAGIC: - if (!xfs_buf_verify_cksum(bp, XFS_DA3_NODE_CRC_OFF)) { - xfs_buf_ioerror(bp, -EFSBADCRC); - break; - } - /* fall through */ - case XFS_DA_NODE_MAGIC: - if (!xfs_da3_node_verify(bp)) { - xfs_buf_ioerror(bp, -EFSCORRUPTED); - break; - } - return; - case XFS_ATTR_LEAF_MAGIC: - case XFS_ATTR3_LEAF_MAGIC: - bp->b_ops = &xfs_attr3_leaf_buf_ops; - bp->b_ops->verify_read(bp); - return; - case XFS_DIR2_LEAFN_MAGIC: - case XFS_DIR3_LEAFN_MAGIC: - bp->b_ops = &xfs_dir3_leafn_buf_ops; - bp->b_ops->verify_read(bp); - return; - default: - xfs_buf_ioerror(bp, -EFSCORRUPTED); - break; - } - - /* corrupt block */ - xfs_verifier_error(bp); -} - -const struct xfs_buf_ops xfs_da3_node_buf_ops = { - .name = "xfs_da3_node", - .verify_read = xfs_da3_node_read_verify, - .verify_write = xfs_da3_node_write_verify, -}; - -int -xfs_da3_node_read( - struct xfs_trans *tp, - struct xfs_inode *dp, - xfs_dablk_t bno, - xfs_daddr_t mappedbno, - struct xfs_buf **bpp, - int which_fork) -{ - int err; - - err = xfs_da_read_buf(tp, dp, bno, mappedbno, bpp, - which_fork, &xfs_da3_node_buf_ops); - if (!err && tp) { - struct xfs_da_blkinfo *info = (*bpp)->b_addr; - int type; - - switch (be16_to_cpu(info->magic)) { - case XFS_DA_NODE_MAGIC: - case XFS_DA3_NODE_MAGIC: - type = XFS_BLFT_DA_NODE_BUF; - break; - case XFS_ATTR_LEAF_MAGIC: - case XFS_ATTR3_LEAF_MAGIC: - type = XFS_BLFT_ATTR_LEAF_BUF; - break; - case XFS_DIR2_LEAFN_MAGIC: - case XFS_DIR3_LEAFN_MAGIC: - type = XFS_BLFT_DIR_LEAFN_BUF; - break; - default: - type = 0; - ASSERT(0); - break; - } - xfs_trans_buf_set_type(tp, *bpp, type); - } - return err; -} - -/*======================================================================== - * Routines used for growing the Btree. - *========================================================================*/ - -/* - * Create the initial contents of an intermediate node. - */ -int -xfs_da3_node_create( - struct xfs_da_args *args, - xfs_dablk_t blkno, - int level, - struct xfs_buf **bpp, - int whichfork) -{ - struct xfs_da_intnode *node; - struct xfs_trans *tp = args->trans; - struct xfs_mount *mp = tp->t_mountp; - struct xfs_da3_icnode_hdr ichdr = {0}; - struct xfs_buf *bp; - int error; - struct xfs_inode *dp = args->dp; - - trace_xfs_da_node_create(args); - ASSERT(level <= XFS_DA_NODE_MAXDEPTH); - - error = xfs_da_get_buf(tp, dp, blkno, -1, &bp, whichfork); - if (error) - return error; - bp->b_ops = &xfs_da3_node_buf_ops; - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DA_NODE_BUF); - node = bp->b_addr; - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - struct xfs_da3_node_hdr *hdr3 = bp->b_addr; - - memset(hdr3, 0, sizeof(struct xfs_da3_node_hdr)); - ichdr.magic = XFS_DA3_NODE_MAGIC; - hdr3->info.blkno = cpu_to_be64(bp->b_bn); - hdr3->info.owner = cpu_to_be64(args->dp->i_ino); - uuid_copy(&hdr3->info.uuid, &mp->m_sb.sb_meta_uuid); - } else { - ichdr.magic = XFS_DA_NODE_MAGIC; - } - ichdr.level = level; - - dp->d_ops->node_hdr_to_disk(node, &ichdr); - xfs_trans_log_buf(tp, bp, - XFS_DA_LOGRANGE(node, &node->hdr, dp->d_ops->node_hdr_size)); - - *bpp = bp; - return 0; -} - -/* - * Split a leaf node, rebalance, then possibly split - * intermediate nodes, rebalance, etc. - */ -int /* error */ -xfs_da3_split( - struct xfs_da_state *state) -{ - struct xfs_da_state_blk *oldblk; - struct xfs_da_state_blk *newblk; - struct xfs_da_state_blk *addblk; - struct xfs_da_intnode *node; - int max; - int action = 0; - int error; - int i; - - trace_xfs_da_split(state->args); - - /* - * Walk back up the tree splitting/inserting/adjusting as necessary. - * If we need to insert and there isn't room, split the node, then - * decide which fragment to insert the new block from below into. - * Note that we may split the root this way, but we need more fixup. - */ - max = state->path.active - 1; - ASSERT((max >= 0) && (max < XFS_DA_NODE_MAXDEPTH)); - ASSERT(state->path.blk[max].magic == XFS_ATTR_LEAF_MAGIC || - state->path.blk[max].magic == XFS_DIR2_LEAFN_MAGIC); - - addblk = &state->path.blk[max]; /* initial dummy value */ - for (i = max; (i >= 0) && addblk; state->path.active--, i--) { - oldblk = &state->path.blk[i]; - newblk = &state->altpath.blk[i]; - - /* - * If a leaf node then - * Allocate a new leaf node, then rebalance across them. - * else if an intermediate node then - * We split on the last layer, must we split the node? - */ - switch (oldblk->magic) { - case XFS_ATTR_LEAF_MAGIC: - error = xfs_attr3_leaf_split(state, oldblk, newblk); - if ((error != 0) && (error != -ENOSPC)) { - return error; /* GROT: attr is inconsistent */ - } - if (!error) { - addblk = newblk; - break; - } - /* - * Entry wouldn't fit, split the leaf again. The new - * extrablk will be consumed by xfs_da3_node_split if - * the node is split. - */ - state->extravalid = 1; - if (state->inleaf) { - state->extraafter = 0; /* before newblk */ - trace_xfs_attr_leaf_split_before(state->args); - error = xfs_attr3_leaf_split(state, oldblk, - &state->extrablk); - } else { - state->extraafter = 1; /* after newblk */ - trace_xfs_attr_leaf_split_after(state->args); - error = xfs_attr3_leaf_split(state, newblk, - &state->extrablk); - } - if (error) - return error; /* GROT: attr inconsistent */ - addblk = newblk; - break; - case XFS_DIR2_LEAFN_MAGIC: - error = xfs_dir2_leafn_split(state, oldblk, newblk); - if (error) - return error; - addblk = newblk; - break; - case XFS_DA_NODE_MAGIC: - error = xfs_da3_node_split(state, oldblk, newblk, addblk, - max - i, &action); - addblk->bp = NULL; - if (error) - return error; /* GROT: dir is inconsistent */ - /* - * Record the newly split block for the next time thru? - */ - if (action) - addblk = newblk; - else - addblk = NULL; - break; - } - - /* - * Update the btree to show the new hashval for this child. - */ - xfs_da3_fixhashpath(state, &state->path); - } - if (!addblk) - return 0; - - /* - * xfs_da3_node_split() should have consumed any extra blocks we added - * during a double leaf split in the attr fork. This is guaranteed as - * we can't be here if the attr fork only has a single leaf block. - */ - ASSERT(state->extravalid == 0 || - state->path.blk[max].magic == XFS_DIR2_LEAFN_MAGIC); - - /* - * Split the root node. - */ - ASSERT(state->path.active == 0); - oldblk = &state->path.blk[0]; - error = xfs_da3_root_split(state, oldblk, addblk); - if (error) { - addblk->bp = NULL; - return error; /* GROT: dir is inconsistent */ - } - - /* - * Update pointers to the node which used to be block 0 and just got - * bumped because of the addition of a new root node. Note that the - * original block 0 could be at any position in the list of blocks in - * the tree. - * - * Note: the magic numbers and sibling pointers are in the same physical - * place for both v2 and v3 headers (by design). Hence it doesn't matter - * which version of the xfs_da_intnode structure we use here as the - * result will be the same using either structure. - */ - node = oldblk->bp->b_addr; - if (node->hdr.info.forw) { - ASSERT(be32_to_cpu(node->hdr.info.forw) == addblk->blkno); - node = addblk->bp->b_addr; - node->hdr.info.back = cpu_to_be32(oldblk->blkno); - xfs_trans_log_buf(state->args->trans, addblk->bp, - XFS_DA_LOGRANGE(node, &node->hdr.info, - sizeof(node->hdr.info))); - } - node = oldblk->bp->b_addr; - if (node->hdr.info.back) { - ASSERT(be32_to_cpu(node->hdr.info.back) == addblk->blkno); - node = addblk->bp->b_addr; - node->hdr.info.forw = cpu_to_be32(oldblk->blkno); - xfs_trans_log_buf(state->args->trans, addblk->bp, - XFS_DA_LOGRANGE(node, &node->hdr.info, - sizeof(node->hdr.info))); - } - addblk->bp = NULL; - return 0; -} - -/* - * Split the root. We have to create a new root and point to the two - * parts (the split old root) that we just created. Copy block zero to - * the EOF, extending the inode in process. - */ -STATIC int /* error */ -xfs_da3_root_split( - struct xfs_da_state *state, - struct xfs_da_state_blk *blk1, - struct xfs_da_state_blk *blk2) -{ - struct xfs_da_intnode *node; - struct xfs_da_intnode *oldroot; - struct xfs_da_node_entry *btree; - struct xfs_da3_icnode_hdr nodehdr; - struct xfs_da_args *args; - struct xfs_buf *bp; - struct xfs_inode *dp; - struct xfs_trans *tp; - struct xfs_dir2_leaf *leaf; - xfs_dablk_t blkno; - int level; - int error; - int size; - - trace_xfs_da_root_split(state->args); - - /* - * Copy the existing (incorrect) block from the root node position - * to a free space somewhere. - */ - args = state->args; - error = xfs_da_grow_inode(args, &blkno); - if (error) - return error; - - dp = args->dp; - tp = args->trans; - error = xfs_da_get_buf(tp, dp, blkno, -1, &bp, args->whichfork); - if (error) - return error; - node = bp->b_addr; - oldroot = blk1->bp->b_addr; - if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC) || - oldroot->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC)) { - struct xfs_da3_icnode_hdr icnodehdr; - - dp->d_ops->node_hdr_from_disk(&icnodehdr, oldroot); - btree = dp->d_ops->node_tree_p(oldroot); - size = (int)((char *)&btree[icnodehdr.count] - (char *)oldroot); - level = icnodehdr.level; - - /* - * we are about to copy oldroot to bp, so set up the type - * of bp while we know exactly what it will be. - */ - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DA_NODE_BUF); - } else { - struct xfs_dir3_icleaf_hdr leafhdr; - struct xfs_dir2_leaf_entry *ents; - - leaf = (xfs_dir2_leaf_t *)oldroot; - dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); - ents = dp->d_ops->leaf_ents_p(leaf); - - ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC || - leafhdr.magic == XFS_DIR3_LEAFN_MAGIC); - size = (int)((char *)&ents[leafhdr.count] - (char *)leaf); - level = 0; - - /* - * we are about to copy oldroot to bp, so set up the type - * of bp while we know exactly what it will be. - */ - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_LEAFN_BUF); - } - - /* - * we can copy most of the information in the node from one block to - * another, but for CRC enabled headers we have to make sure that the - * block specific identifiers are kept intact. We update the buffer - * directly for this. - */ - memcpy(node, oldroot, size); - if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC) || - oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) { - struct xfs_da3_intnode *node3 = (struct xfs_da3_intnode *)node; - - node3->hdr.info.blkno = cpu_to_be64(bp->b_bn); - } - xfs_trans_log_buf(tp, bp, 0, size - 1); - - bp->b_ops = blk1->bp->b_ops; - xfs_trans_buf_copy_type(bp, blk1->bp); - blk1->bp = bp; - blk1->blkno = blkno; - - /* - * Set up the new root node. - */ - error = xfs_da3_node_create(args, - (args->whichfork == XFS_DATA_FORK) ? args->geo->leafblk : 0, - level + 1, &bp, args->whichfork); - if (error) - return error; - - node = bp->b_addr; - dp->d_ops->node_hdr_from_disk(&nodehdr, node); - btree = dp->d_ops->node_tree_p(node); - btree[0].hashval = cpu_to_be32(blk1->hashval); - btree[0].before = cpu_to_be32(blk1->blkno); - btree[1].hashval = cpu_to_be32(blk2->hashval); - btree[1].before = cpu_to_be32(blk2->blkno); - nodehdr.count = 2; - dp->d_ops->node_hdr_to_disk(node, &nodehdr); - -#ifdef DEBUG - if (oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || - oldroot->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) { - ASSERT(blk1->blkno >= args->geo->leafblk && - blk1->blkno < args->geo->freeblk); - ASSERT(blk2->blkno >= args->geo->leafblk && - blk2->blkno < args->geo->freeblk); - } -#endif - - /* Header is already logged by xfs_da_node_create */ - xfs_trans_log_buf(tp, bp, - XFS_DA_LOGRANGE(node, btree, sizeof(xfs_da_node_entry_t) * 2)); - - return 0; -} - -/* - * Split the node, rebalance, then add the new entry. - */ -STATIC int /* error */ -xfs_da3_node_split( - struct xfs_da_state *state, - struct xfs_da_state_blk *oldblk, - struct xfs_da_state_blk *newblk, - struct xfs_da_state_blk *addblk, - int treelevel, - int *result) -{ - struct xfs_da_intnode *node; - struct xfs_da3_icnode_hdr nodehdr; - xfs_dablk_t blkno; - int newcount; - int error; - int useextra; - struct xfs_inode *dp = state->args->dp; - - trace_xfs_da_node_split(state->args); - - node = oldblk->bp->b_addr; - dp->d_ops->node_hdr_from_disk(&nodehdr, node); - - /* - * With V2 dirs the extra block is data or freespace. - */ - useextra = state->extravalid && state->args->whichfork == XFS_ATTR_FORK; - newcount = 1 + useextra; - /* - * Do we have to split the node? - */ - if (nodehdr.count + newcount > state->args->geo->node_ents) { - /* - * Allocate a new node, add to the doubly linked chain of - * nodes, then move some of our excess entries into it. - */ - error = xfs_da_grow_inode(state->args, &blkno); - if (error) - return error; /* GROT: dir is inconsistent */ - - error = xfs_da3_node_create(state->args, blkno, treelevel, - &newblk->bp, state->args->whichfork); - if (error) - return error; /* GROT: dir is inconsistent */ - newblk->blkno = blkno; - newblk->magic = XFS_DA_NODE_MAGIC; - xfs_da3_node_rebalance(state, oldblk, newblk); - error = xfs_da3_blk_link(state, oldblk, newblk); - if (error) - return error; - *result = 1; - } else { - *result = 0; - } - - /* - * Insert the new entry(s) into the correct block - * (updating last hashval in the process). - * - * xfs_da3_node_add() inserts BEFORE the given index, - * and as a result of using node_lookup_int() we always - * point to a valid entry (not after one), but a split - * operation always results in a new block whose hashvals - * FOLLOW the current block. - * - * If we had double-split op below us, then add the extra block too. - */ - node = oldblk->bp->b_addr; - dp->d_ops->node_hdr_from_disk(&nodehdr, node); - if (oldblk->index <= nodehdr.count) { - oldblk->index++; - xfs_da3_node_add(state, oldblk, addblk); - if (useextra) { - if (state->extraafter) - oldblk->index++; - xfs_da3_node_add(state, oldblk, &state->extrablk); - state->extravalid = 0; - } - } else { - newblk->index++; - xfs_da3_node_add(state, newblk, addblk); - if (useextra) { - if (state->extraafter) - newblk->index++; - xfs_da3_node_add(state, newblk, &state->extrablk); - state->extravalid = 0; - } - } - - return 0; -} - -/* - * Balance the btree elements between two intermediate nodes, - * usually one full and one empty. - * - * NOTE: if blk2 is empty, then it will get the upper half of blk1. - */ -STATIC void -xfs_da3_node_rebalance( - struct xfs_da_state *state, - struct xfs_da_state_blk *blk1, - struct xfs_da_state_blk *blk2) -{ - struct xfs_da_intnode *node1; - struct xfs_da_intnode *node2; - struct xfs_da_intnode *tmpnode; - struct xfs_da_node_entry *btree1; - struct xfs_da_node_entry *btree2; - struct xfs_da_node_entry *btree_s; - struct xfs_da_node_entry *btree_d; - struct xfs_da3_icnode_hdr nodehdr1; - struct xfs_da3_icnode_hdr nodehdr2; - struct xfs_trans *tp; - int count; - int tmp; - int swap = 0; - struct xfs_inode *dp = state->args->dp; - - trace_xfs_da_node_rebalance(state->args); - - node1 = blk1->bp->b_addr; - node2 = blk2->bp->b_addr; - dp->d_ops->node_hdr_from_disk(&nodehdr1, node1); - dp->d_ops->node_hdr_from_disk(&nodehdr2, node2); - btree1 = dp->d_ops->node_tree_p(node1); - btree2 = dp->d_ops->node_tree_p(node2); - - /* - * Figure out how many entries need to move, and in which direction. - * Swap the nodes around if that makes it simpler. - */ - if (nodehdr1.count > 0 && nodehdr2.count > 0 && - ((be32_to_cpu(btree2[0].hashval) < be32_to_cpu(btree1[0].hashval)) || - (be32_to_cpu(btree2[nodehdr2.count - 1].hashval) < - be32_to_cpu(btree1[nodehdr1.count - 1].hashval)))) { - tmpnode = node1; - node1 = node2; - node2 = tmpnode; - dp->d_ops->node_hdr_from_disk(&nodehdr1, node1); - dp->d_ops->node_hdr_from_disk(&nodehdr2, node2); - btree1 = dp->d_ops->node_tree_p(node1); - btree2 = dp->d_ops->node_tree_p(node2); - swap = 1; - } - - count = (nodehdr1.count - nodehdr2.count) / 2; - if (count == 0) - return; - tp = state->args->trans; - /* - * Two cases: high-to-low and low-to-high. - */ - if (count > 0) { - /* - * Move elements in node2 up to make a hole. - */ - tmp = nodehdr2.count; - if (tmp > 0) { - tmp *= (uint)sizeof(xfs_da_node_entry_t); - btree_s = &btree2[0]; - btree_d = &btree2[count]; - memmove(btree_d, btree_s, tmp); - } - - /* - * Move the req'd B-tree elements from high in node1 to - * low in node2. - */ - nodehdr2.count += count; - tmp = count * (uint)sizeof(xfs_da_node_entry_t); - btree_s = &btree1[nodehdr1.count - count]; - btree_d = &btree2[0]; - memcpy(btree_d, btree_s, tmp); - nodehdr1.count -= count; - } else { - /* - * Move the req'd B-tree elements from low in node2 to - * high in node1. - */ - count = -count; - tmp = count * (uint)sizeof(xfs_da_node_entry_t); - btree_s = &btree2[0]; - btree_d = &btree1[nodehdr1.count]; - memcpy(btree_d, btree_s, tmp); - nodehdr1.count += count; - - xfs_trans_log_buf(tp, blk1->bp, - XFS_DA_LOGRANGE(node1, btree_d, tmp)); - - /* - * Move elements in node2 down to fill the hole. - */ - tmp = nodehdr2.count - count; - tmp *= (uint)sizeof(xfs_da_node_entry_t); - btree_s = &btree2[count]; - btree_d = &btree2[0]; - memmove(btree_d, btree_s, tmp); - nodehdr2.count -= count; - } - - /* - * Log header of node 1 and all current bits of node 2. - */ - dp->d_ops->node_hdr_to_disk(node1, &nodehdr1); - xfs_trans_log_buf(tp, blk1->bp, - XFS_DA_LOGRANGE(node1, &node1->hdr, dp->d_ops->node_hdr_size)); - - dp->d_ops->node_hdr_to_disk(node2, &nodehdr2); - xfs_trans_log_buf(tp, blk2->bp, - XFS_DA_LOGRANGE(node2, &node2->hdr, - dp->d_ops->node_hdr_size + - (sizeof(btree2[0]) * nodehdr2.count))); - - /* - * Record the last hashval from each block for upward propagation. - * (note: don't use the swapped node pointers) - */ - if (swap) { - node1 = blk1->bp->b_addr; - node2 = blk2->bp->b_addr; - dp->d_ops->node_hdr_from_disk(&nodehdr1, node1); - dp->d_ops->node_hdr_from_disk(&nodehdr2, node2); - btree1 = dp->d_ops->node_tree_p(node1); - btree2 = dp->d_ops->node_tree_p(node2); - } - blk1->hashval = be32_to_cpu(btree1[nodehdr1.count - 1].hashval); - blk2->hashval = be32_to_cpu(btree2[nodehdr2.count - 1].hashval); - - /* - * Adjust the expected index for insertion. - */ - if (blk1->index >= nodehdr1.count) { - blk2->index = blk1->index - nodehdr1.count; - blk1->index = nodehdr1.count + 1; /* make it invalid */ - } -} - -/* - * Add a new entry to an intermediate node. - */ -STATIC void -xfs_da3_node_add( - struct xfs_da_state *state, - struct xfs_da_state_blk *oldblk, - struct xfs_da_state_blk *newblk) -{ - struct xfs_da_intnode *node; - struct xfs_da3_icnode_hdr nodehdr; - struct xfs_da_node_entry *btree; - int tmp; - struct xfs_inode *dp = state->args->dp; - - trace_xfs_da_node_add(state->args); - - node = oldblk->bp->b_addr; - dp->d_ops->node_hdr_from_disk(&nodehdr, node); - btree = dp->d_ops->node_tree_p(node); - - ASSERT(oldblk->index >= 0 && oldblk->index <= nodehdr.count); - ASSERT(newblk->blkno != 0); - if (state->args->whichfork == XFS_DATA_FORK) - ASSERT(newblk->blkno >= state->args->geo->leafblk && - newblk->blkno < state->args->geo->freeblk); - - /* - * We may need to make some room before we insert the new node. - */ - tmp = 0; - if (oldblk->index < nodehdr.count) { - tmp = (nodehdr.count - oldblk->index) * (uint)sizeof(*btree); - memmove(&btree[oldblk->index + 1], &btree[oldblk->index], tmp); - } - btree[oldblk->index].hashval = cpu_to_be32(newblk->hashval); - btree[oldblk->index].before = cpu_to_be32(newblk->blkno); - xfs_trans_log_buf(state->args->trans, oldblk->bp, - XFS_DA_LOGRANGE(node, &btree[oldblk->index], - tmp + sizeof(*btree))); - - nodehdr.count += 1; - dp->d_ops->node_hdr_to_disk(node, &nodehdr); - xfs_trans_log_buf(state->args->trans, oldblk->bp, - XFS_DA_LOGRANGE(node, &node->hdr, dp->d_ops->node_hdr_size)); - - /* - * Copy the last hash value from the oldblk to propagate upwards. - */ - oldblk->hashval = be32_to_cpu(btree[nodehdr.count - 1].hashval); -} - -/*======================================================================== - * Routines used for shrinking the Btree. - *========================================================================*/ - -/* - * Deallocate an empty leaf node, remove it from its parent, - * possibly deallocating that block, etc... - */ -int -xfs_da3_join( - struct xfs_da_state *state) -{ - struct xfs_da_state_blk *drop_blk; - struct xfs_da_state_blk *save_blk; - int action = 0; - int error; - - trace_xfs_da_join(state->args); - - drop_blk = &state->path.blk[ state->path.active-1 ]; - save_blk = &state->altpath.blk[ state->path.active-1 ]; - ASSERT(state->path.blk[0].magic == XFS_DA_NODE_MAGIC); - ASSERT(drop_blk->magic == XFS_ATTR_LEAF_MAGIC || - drop_blk->magic == XFS_DIR2_LEAFN_MAGIC); - - /* - * Walk back up the tree joining/deallocating as necessary. - * When we stop dropping blocks, break out. - */ - for ( ; state->path.active >= 2; drop_blk--, save_blk--, - state->path.active--) { - /* - * See if we can combine the block with a neighbor. - * (action == 0) => no options, just leave - * (action == 1) => coalesce, then unlink - * (action == 2) => block empty, unlink it - */ - switch (drop_blk->magic) { - case XFS_ATTR_LEAF_MAGIC: - error = xfs_attr3_leaf_toosmall(state, &action); - if (error) - return error; - if (action == 0) - return 0; - xfs_attr3_leaf_unbalance(state, drop_blk, save_blk); - break; - case XFS_DIR2_LEAFN_MAGIC: - error = xfs_dir2_leafn_toosmall(state, &action); - if (error) - return error; - if (action == 0) - return 0; - xfs_dir2_leafn_unbalance(state, drop_blk, save_blk); - break; - case XFS_DA_NODE_MAGIC: - /* - * Remove the offending node, fixup hashvals, - * check for a toosmall neighbor. - */ - xfs_da3_node_remove(state, drop_blk); - xfs_da3_fixhashpath(state, &state->path); - error = xfs_da3_node_toosmall(state, &action); - if (error) - return error; - if (action == 0) - return 0; - xfs_da3_node_unbalance(state, drop_blk, save_blk); - break; - } - xfs_da3_fixhashpath(state, &state->altpath); - error = xfs_da3_blk_unlink(state, drop_blk, save_blk); - xfs_da_state_kill_altpath(state); - if (error) - return error; - error = xfs_da_shrink_inode(state->args, drop_blk->blkno, - drop_blk->bp); - drop_blk->bp = NULL; - if (error) - return error; - } - /* - * We joined all the way to the top. If it turns out that - * we only have one entry in the root, make the child block - * the new root. - */ - xfs_da3_node_remove(state, drop_blk); - xfs_da3_fixhashpath(state, &state->path); - error = xfs_da3_root_join(state, &state->path.blk[0]); - return error; -} - -#ifdef DEBUG -static void -xfs_da_blkinfo_onlychild_validate(struct xfs_da_blkinfo *blkinfo, __u16 level) -{ - __be16 magic = blkinfo->magic; - - if (level == 1) { - ASSERT(magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || - magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC) || - magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC) || - magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)); - } else { - ASSERT(magic == cpu_to_be16(XFS_DA_NODE_MAGIC) || - magic == cpu_to_be16(XFS_DA3_NODE_MAGIC)); - } - ASSERT(!blkinfo->forw); - ASSERT(!blkinfo->back); -} -#else /* !DEBUG */ -#define xfs_da_blkinfo_onlychild_validate(blkinfo, level) -#endif /* !DEBUG */ - -/* - * We have only one entry in the root. Copy the only remaining child of - * the old root to block 0 as the new root node. - */ -STATIC int -xfs_da3_root_join( - struct xfs_da_state *state, - struct xfs_da_state_blk *root_blk) -{ - struct xfs_da_intnode *oldroot; - struct xfs_da_args *args; - xfs_dablk_t child; - struct xfs_buf *bp; - struct xfs_da3_icnode_hdr oldroothdr; - struct xfs_da_node_entry *btree; - int error; - struct xfs_inode *dp = state->args->dp; - - trace_xfs_da_root_join(state->args); - - ASSERT(root_blk->magic == XFS_DA_NODE_MAGIC); - - args = state->args; - oldroot = root_blk->bp->b_addr; - dp->d_ops->node_hdr_from_disk(&oldroothdr, oldroot); - ASSERT(oldroothdr.forw == 0); - ASSERT(oldroothdr.back == 0); - - /* - * If the root has more than one child, then don't do anything. - */ - if (oldroothdr.count > 1) - return 0; - - /* - * Read in the (only) child block, then copy those bytes into - * the root block's buffer and free the original child block. - */ - btree = dp->d_ops->node_tree_p(oldroot); - child = be32_to_cpu(btree[0].before); - ASSERT(child != 0); - error = xfs_da3_node_read(args->trans, dp, child, -1, &bp, - args->whichfork); - if (error) - return error; - xfs_da_blkinfo_onlychild_validate(bp->b_addr, oldroothdr.level); - - /* - * This could be copying a leaf back into the root block in the case of - * there only being a single leaf block left in the tree. Hence we have - * to update the b_ops pointer as well to match the buffer type change - * that could occur. For dir3 blocks we also need to update the block - * number in the buffer header. - */ - memcpy(root_blk->bp->b_addr, bp->b_addr, args->geo->blksize); - root_blk->bp->b_ops = bp->b_ops; - xfs_trans_buf_copy_type(root_blk->bp, bp); - if (oldroothdr.magic == XFS_DA3_NODE_MAGIC) { - struct xfs_da3_blkinfo *da3 = root_blk->bp->b_addr; - da3->blkno = cpu_to_be64(root_blk->bp->b_bn); - } - xfs_trans_log_buf(args->trans, root_blk->bp, 0, - args->geo->blksize - 1); - error = xfs_da_shrink_inode(args, child, bp); - return error; -} - -/* - * Check a node block and its neighbors to see if the block should be - * collapsed into one or the other neighbor. Always keep the block - * with the smaller block number. - * If the current block is over 50% full, don't try to join it, return 0. - * If the block is empty, fill in the state structure and return 2. - * If it can be collapsed, fill in the state structure and return 1. - * If nothing can be done, return 0. - */ -STATIC int -xfs_da3_node_toosmall( - struct xfs_da_state *state, - int *action) -{ - struct xfs_da_intnode *node; - struct xfs_da_state_blk *blk; - struct xfs_da_blkinfo *info; - xfs_dablk_t blkno; - struct xfs_buf *bp; - struct xfs_da3_icnode_hdr nodehdr; - int count; - int forward; - int error; - int retval; - int i; - struct xfs_inode *dp = state->args->dp; - - trace_xfs_da_node_toosmall(state->args); - - /* - * Check for the degenerate case of the block being over 50% full. - * If so, it's not worth even looking to see if we might be able - * to coalesce with a sibling. - */ - blk = &state->path.blk[ state->path.active-1 ]; - info = blk->bp->b_addr; - node = (xfs_da_intnode_t *)info; - dp->d_ops->node_hdr_from_disk(&nodehdr, node); - if (nodehdr.count > (state->args->geo->node_ents >> 1)) { - *action = 0; /* blk over 50%, don't try to join */ - return 0; /* blk over 50%, don't try to join */ - } - - /* - * Check for the degenerate case of the block being empty. - * If the block is empty, we'll simply delete it, no need to - * coalesce it with a sibling block. We choose (arbitrarily) - * to merge with the forward block unless it is NULL. - */ - if (nodehdr.count == 0) { - /* - * Make altpath point to the block we want to keep and - * path point to the block we want to drop (this one). - */ - forward = (info->forw != 0); - memcpy(&state->altpath, &state->path, sizeof(state->path)); - error = xfs_da3_path_shift(state, &state->altpath, forward, - 0, &retval); - if (error) - return error; - if (retval) { - *action = 0; - } else { - *action = 2; - } - return 0; - } - - /* - * Examine each sibling block to see if we can coalesce with - * at least 25% free space to spare. We need to figure out - * whether to merge with the forward or the backward block. - * We prefer coalescing with the lower numbered sibling so as - * to shrink a directory over time. - */ - count = state->args->geo->node_ents; - count -= state->args->geo->node_ents >> 2; - count -= nodehdr.count; - - /* start with smaller blk num */ - forward = nodehdr.forw < nodehdr.back; - for (i = 0; i < 2; forward = !forward, i++) { - struct xfs_da3_icnode_hdr thdr; - if (forward) - blkno = nodehdr.forw; - else - blkno = nodehdr.back; - if (blkno == 0) - continue; - error = xfs_da3_node_read(state->args->trans, dp, - blkno, -1, &bp, state->args->whichfork); - if (error) - return error; - - node = bp->b_addr; - dp->d_ops->node_hdr_from_disk(&thdr, node); - xfs_trans_brelse(state->args->trans, bp); - - if (count - thdr.count >= 0) - break; /* fits with at least 25% to spare */ - } - if (i >= 2) { - *action = 0; - return 0; - } - - /* - * Make altpath point to the block we want to keep (the lower - * numbered block) and path point to the block we want to drop. - */ - memcpy(&state->altpath, &state->path, sizeof(state->path)); - if (blkno < blk->blkno) { - error = xfs_da3_path_shift(state, &state->altpath, forward, - 0, &retval); - } else { - error = xfs_da3_path_shift(state, &state->path, forward, - 0, &retval); - } - if (error) - return error; - if (retval) { - *action = 0; - return 0; - } - *action = 1; - return 0; -} - -/* - * Pick up the last hashvalue from an intermediate node. - */ -STATIC uint -xfs_da3_node_lasthash( - struct xfs_inode *dp, - struct xfs_buf *bp, - int *count) -{ - struct xfs_da_intnode *node; - struct xfs_da_node_entry *btree; - struct xfs_da3_icnode_hdr nodehdr; - - node = bp->b_addr; - dp->d_ops->node_hdr_from_disk(&nodehdr, node); - if (count) - *count = nodehdr.count; - if (!nodehdr.count) - return 0; - btree = dp->d_ops->node_tree_p(node); - return be32_to_cpu(btree[nodehdr.count - 1].hashval); -} - -/* - * Walk back up the tree adjusting hash values as necessary, - * when we stop making changes, return. - */ -void -xfs_da3_fixhashpath( - struct xfs_da_state *state, - struct xfs_da_state_path *path) -{ - struct xfs_da_state_blk *blk; - struct xfs_da_intnode *node; - struct xfs_da_node_entry *btree; - xfs_dahash_t lasthash=0; - int level; - int count; - struct xfs_inode *dp = state->args->dp; - - trace_xfs_da_fixhashpath(state->args); - - level = path->active-1; - blk = &path->blk[ level ]; - switch (blk->magic) { - case XFS_ATTR_LEAF_MAGIC: - lasthash = xfs_attr_leaf_lasthash(blk->bp, &count); - if (count == 0) - return; - break; - case XFS_DIR2_LEAFN_MAGIC: - lasthash = xfs_dir2_leafn_lasthash(dp, blk->bp, &count); - if (count == 0) - return; - break; - case XFS_DA_NODE_MAGIC: - lasthash = xfs_da3_node_lasthash(dp, blk->bp, &count); - if (count == 0) - return; - break; - } - for (blk--, level--; level >= 0; blk--, level--) { - struct xfs_da3_icnode_hdr nodehdr; - - node = blk->bp->b_addr; - dp->d_ops->node_hdr_from_disk(&nodehdr, node); - btree = dp->d_ops->node_tree_p(node); - if (be32_to_cpu(btree[blk->index].hashval) == lasthash) - break; - blk->hashval = lasthash; - btree[blk->index].hashval = cpu_to_be32(lasthash); - xfs_trans_log_buf(state->args->trans, blk->bp, - XFS_DA_LOGRANGE(node, &btree[blk->index], - sizeof(*btree))); - - lasthash = be32_to_cpu(btree[nodehdr.count - 1].hashval); - } -} - -/* - * Remove an entry from an intermediate node. - */ -STATIC void -xfs_da3_node_remove( - struct xfs_da_state *state, - struct xfs_da_state_blk *drop_blk) -{ - struct xfs_da_intnode *node; - struct xfs_da3_icnode_hdr nodehdr; - struct xfs_da_node_entry *btree; - int index; - int tmp; - struct xfs_inode *dp = state->args->dp; - - trace_xfs_da_node_remove(state->args); - - node = drop_blk->bp->b_addr; - dp->d_ops->node_hdr_from_disk(&nodehdr, node); - ASSERT(drop_blk->index < nodehdr.count); - ASSERT(drop_blk->index >= 0); - - /* - * Copy over the offending entry, or just zero it out. - */ - index = drop_blk->index; - btree = dp->d_ops->node_tree_p(node); - if (index < nodehdr.count - 1) { - tmp = nodehdr.count - index - 1; - tmp *= (uint)sizeof(xfs_da_node_entry_t); - memmove(&btree[index], &btree[index + 1], tmp); - xfs_trans_log_buf(state->args->trans, drop_blk->bp, - XFS_DA_LOGRANGE(node, &btree[index], tmp)); - index = nodehdr.count - 1; - } - memset(&btree[index], 0, sizeof(xfs_da_node_entry_t)); - xfs_trans_log_buf(state->args->trans, drop_blk->bp, - XFS_DA_LOGRANGE(node, &btree[index], sizeof(btree[index]))); - nodehdr.count -= 1; - dp->d_ops->node_hdr_to_disk(node, &nodehdr); - xfs_trans_log_buf(state->args->trans, drop_blk->bp, - XFS_DA_LOGRANGE(node, &node->hdr, dp->d_ops->node_hdr_size)); - - /* - * Copy the last hash value from the block to propagate upwards. - */ - drop_blk->hashval = be32_to_cpu(btree[index - 1].hashval); -} - -/* - * Unbalance the elements between two intermediate nodes, - * move all Btree elements from one node into another. - */ -STATIC void -xfs_da3_node_unbalance( - struct xfs_da_state *state, - struct xfs_da_state_blk *drop_blk, - struct xfs_da_state_blk *save_blk) -{ - struct xfs_da_intnode *drop_node; - struct xfs_da_intnode *save_node; - struct xfs_da_node_entry *drop_btree; - struct xfs_da_node_entry *save_btree; - struct xfs_da3_icnode_hdr drop_hdr; - struct xfs_da3_icnode_hdr save_hdr; - struct xfs_trans *tp; - int sindex; - int tmp; - struct xfs_inode *dp = state->args->dp; - - trace_xfs_da_node_unbalance(state->args); - - drop_node = drop_blk->bp->b_addr; - save_node = save_blk->bp->b_addr; - dp->d_ops->node_hdr_from_disk(&drop_hdr, drop_node); - dp->d_ops->node_hdr_from_disk(&save_hdr, save_node); - drop_btree = dp->d_ops->node_tree_p(drop_node); - save_btree = dp->d_ops->node_tree_p(save_node); - tp = state->args->trans; - - /* - * If the dying block has lower hashvals, then move all the - * elements in the remaining block up to make a hole. - */ - if ((be32_to_cpu(drop_btree[0].hashval) < - be32_to_cpu(save_btree[0].hashval)) || - (be32_to_cpu(drop_btree[drop_hdr.count - 1].hashval) < - be32_to_cpu(save_btree[save_hdr.count - 1].hashval))) { - /* XXX: check this - is memmove dst correct? */ - tmp = save_hdr.count * sizeof(xfs_da_node_entry_t); - memmove(&save_btree[drop_hdr.count], &save_btree[0], tmp); - - sindex = 0; - xfs_trans_log_buf(tp, save_blk->bp, - XFS_DA_LOGRANGE(save_node, &save_btree[0], - (save_hdr.count + drop_hdr.count) * - sizeof(xfs_da_node_entry_t))); - } else { - sindex = save_hdr.count; - xfs_trans_log_buf(tp, save_blk->bp, - XFS_DA_LOGRANGE(save_node, &save_btree[sindex], - drop_hdr.count * sizeof(xfs_da_node_entry_t))); - } - - /* - * Move all the B-tree elements from drop_blk to save_blk. - */ - tmp = drop_hdr.count * (uint)sizeof(xfs_da_node_entry_t); - memcpy(&save_btree[sindex], &drop_btree[0], tmp); - save_hdr.count += drop_hdr.count; - - dp->d_ops->node_hdr_to_disk(save_node, &save_hdr); - xfs_trans_log_buf(tp, save_blk->bp, - XFS_DA_LOGRANGE(save_node, &save_node->hdr, - dp->d_ops->node_hdr_size)); - - /* - * Save the last hashval in the remaining block for upward propagation. - */ - save_blk->hashval = be32_to_cpu(save_btree[save_hdr.count - 1].hashval); -} - -/*======================================================================== - * Routines used for finding things in the Btree. - *========================================================================*/ - -/* - * Walk down the Btree looking for a particular filename, filling - * in the state structure as we go. - * - * We will set the state structure to point to each of the elements - * in each of the nodes where either the hashval is or should be. - * - * We support duplicate hashval's so for each entry in the current - * node that could contain the desired hashval, descend. This is a - * pruned depth-first tree search. - */ -int /* error */ -xfs_da3_node_lookup_int( - struct xfs_da_state *state, - int *result) -{ - struct xfs_da_state_blk *blk; - struct xfs_da_blkinfo *curr; - struct xfs_da_intnode *node; - struct xfs_da_node_entry *btree; - struct xfs_da3_icnode_hdr nodehdr; - struct xfs_da_args *args; - xfs_dablk_t blkno; - xfs_dahash_t hashval; - xfs_dahash_t btreehashval; - int probe; - int span; - int max; - int error; - int retval; - struct xfs_inode *dp = state->args->dp; - - args = state->args; - - /* - * Descend thru the B-tree searching each level for the right - * node to use, until the right hashval is found. - */ - blkno = (args->whichfork == XFS_DATA_FORK)? args->geo->leafblk : 0; - for (blk = &state->path.blk[0], state->path.active = 1; - state->path.active <= XFS_DA_NODE_MAXDEPTH; - blk++, state->path.active++) { - /* - * Read the next node down in the tree. - */ - blk->blkno = blkno; - error = xfs_da3_node_read(args->trans, args->dp, blkno, - -1, &blk->bp, args->whichfork); - if (error) { - blk->blkno = 0; - state->path.active--; - return error; - } - curr = blk->bp->b_addr; - blk->magic = be16_to_cpu(curr->magic); - - if (blk->magic == XFS_ATTR_LEAF_MAGIC || - blk->magic == XFS_ATTR3_LEAF_MAGIC) { - blk->magic = XFS_ATTR_LEAF_MAGIC; - blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL); - break; - } - - if (blk->magic == XFS_DIR2_LEAFN_MAGIC || - blk->magic == XFS_DIR3_LEAFN_MAGIC) { - blk->magic = XFS_DIR2_LEAFN_MAGIC; - blk->hashval = xfs_dir2_leafn_lasthash(args->dp, - blk->bp, NULL); - break; - } - - blk->magic = XFS_DA_NODE_MAGIC; - - - /* - * Search an intermediate node for a match. - */ - node = blk->bp->b_addr; - dp->d_ops->node_hdr_from_disk(&nodehdr, node); - btree = dp->d_ops->node_tree_p(node); - - max = nodehdr.count; - blk->hashval = be32_to_cpu(btree[max - 1].hashval); - - /* - * Binary search. (note: small blocks will skip loop) - */ - probe = span = max / 2; - hashval = args->hashval; - while (span > 4) { - span /= 2; - btreehashval = be32_to_cpu(btree[probe].hashval); - if (btreehashval < hashval) - probe += span; - else if (btreehashval > hashval) - probe -= span; - else - break; - } - ASSERT((probe >= 0) && (probe < max)); - ASSERT((span <= 4) || - (be32_to_cpu(btree[probe].hashval) == hashval)); - - /* - * Since we may have duplicate hashval's, find the first - * matching hashval in the node. - */ - while (probe > 0 && - be32_to_cpu(btree[probe].hashval) >= hashval) { - probe--; - } - while (probe < max && - be32_to_cpu(btree[probe].hashval) < hashval) { - probe++; - } - - /* - * Pick the right block to descend on. - */ - if (probe == max) { - blk->index = max - 1; - blkno = be32_to_cpu(btree[max - 1].before); - } else { - blk->index = probe; - blkno = be32_to_cpu(btree[probe].before); - } - } - - /* - * A leaf block that ends in the hashval that we are interested in - * (final hashval == search hashval) means that the next block may - * contain more entries with the same hashval, shift upward to the - * next leaf and keep searching. - */ - for (;;) { - if (blk->magic == XFS_DIR2_LEAFN_MAGIC) { - retval = xfs_dir2_leafn_lookup_int(blk->bp, args, - &blk->index, state); - } else if (blk->magic == XFS_ATTR_LEAF_MAGIC) { - retval = xfs_attr3_leaf_lookup_int(blk->bp, args); - blk->index = args->index; - args->blkno = blk->blkno; - } else { - ASSERT(0); - return -EFSCORRUPTED; - } - if (((retval == -ENOENT) || (retval == -ENOATTR)) && - (blk->hashval == args->hashval)) { - error = xfs_da3_path_shift(state, &state->path, 1, 1, - &retval); - if (error) - return error; - if (retval == 0) { - continue; - } else if (blk->magic == XFS_ATTR_LEAF_MAGIC) { - /* path_shift() gives ENOENT */ - retval = -ENOATTR; - } - } - break; - } - *result = retval; - return 0; -} - -/*======================================================================== - * Utility routines. - *========================================================================*/ - -/* - * Compare two intermediate nodes for "order". - */ -STATIC int -xfs_da3_node_order( - struct xfs_inode *dp, - struct xfs_buf *node1_bp, - struct xfs_buf *node2_bp) -{ - struct xfs_da_intnode *node1; - struct xfs_da_intnode *node2; - struct xfs_da_node_entry *btree1; - struct xfs_da_node_entry *btree2; - struct xfs_da3_icnode_hdr node1hdr; - struct xfs_da3_icnode_hdr node2hdr; - - node1 = node1_bp->b_addr; - node2 = node2_bp->b_addr; - dp->d_ops->node_hdr_from_disk(&node1hdr, node1); - dp->d_ops->node_hdr_from_disk(&node2hdr, node2); - btree1 = dp->d_ops->node_tree_p(node1); - btree2 = dp->d_ops->node_tree_p(node2); - - if (node1hdr.count > 0 && node2hdr.count > 0 && - ((be32_to_cpu(btree2[0].hashval) < be32_to_cpu(btree1[0].hashval)) || - (be32_to_cpu(btree2[node2hdr.count - 1].hashval) < - be32_to_cpu(btree1[node1hdr.count - 1].hashval)))) { - return 1; - } - return 0; -} - -/* - * Link a new block into a doubly linked list of blocks (of whatever type). - */ -int /* error */ -xfs_da3_blk_link( - struct xfs_da_state *state, - struct xfs_da_state_blk *old_blk, - struct xfs_da_state_blk *new_blk) -{ - struct xfs_da_blkinfo *old_info; - struct xfs_da_blkinfo *new_info; - struct xfs_da_blkinfo *tmp_info; - struct xfs_da_args *args; - struct xfs_buf *bp; - int before = 0; - int error; - struct xfs_inode *dp = state->args->dp; - - /* - * Set up environment. - */ - args = state->args; - ASSERT(args != NULL); - old_info = old_blk->bp->b_addr; - new_info = new_blk->bp->b_addr; - ASSERT(old_blk->magic == XFS_DA_NODE_MAGIC || - old_blk->magic == XFS_DIR2_LEAFN_MAGIC || - old_blk->magic == XFS_ATTR_LEAF_MAGIC); - - switch (old_blk->magic) { - case XFS_ATTR_LEAF_MAGIC: - before = xfs_attr_leaf_order(old_blk->bp, new_blk->bp); - break; - case XFS_DIR2_LEAFN_MAGIC: - before = xfs_dir2_leafn_order(dp, old_blk->bp, new_blk->bp); - break; - case XFS_DA_NODE_MAGIC: - before = xfs_da3_node_order(dp, old_blk->bp, new_blk->bp); - break; - } - - /* - * Link blocks in appropriate order. - */ - if (before) { - /* - * Link new block in before existing block. - */ - trace_xfs_da_link_before(args); - new_info->forw = cpu_to_be32(old_blk->blkno); - new_info->back = old_info->back; - if (old_info->back) { - error = xfs_da3_node_read(args->trans, dp, - be32_to_cpu(old_info->back), - -1, &bp, args->whichfork); - if (error) - return error; - ASSERT(bp != NULL); - tmp_info = bp->b_addr; - ASSERT(tmp_info->magic == old_info->magic); - ASSERT(be32_to_cpu(tmp_info->forw) == old_blk->blkno); - tmp_info->forw = cpu_to_be32(new_blk->blkno); - xfs_trans_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1); - } - old_info->back = cpu_to_be32(new_blk->blkno); - } else { - /* - * Link new block in after existing block. - */ - trace_xfs_da_link_after(args); - new_info->forw = old_info->forw; - new_info->back = cpu_to_be32(old_blk->blkno); - if (old_info->forw) { - error = xfs_da3_node_read(args->trans, dp, - be32_to_cpu(old_info->forw), - -1, &bp, args->whichfork); - if (error) - return error; - ASSERT(bp != NULL); - tmp_info = bp->b_addr; - ASSERT(tmp_info->magic == old_info->magic); - ASSERT(be32_to_cpu(tmp_info->back) == old_blk->blkno); - tmp_info->back = cpu_to_be32(new_blk->blkno); - xfs_trans_log_buf(args->trans, bp, 0, sizeof(*tmp_info)-1); - } - old_info->forw = cpu_to_be32(new_blk->blkno); - } - - xfs_trans_log_buf(args->trans, old_blk->bp, 0, sizeof(*tmp_info) - 1); - xfs_trans_log_buf(args->trans, new_blk->bp, 0, sizeof(*tmp_info) - 1); - return 0; -} - -/* - * Unlink a block from a doubly linked list of blocks. - */ -STATIC int /* error */ -xfs_da3_blk_unlink( - struct xfs_da_state *state, - struct xfs_da_state_blk *drop_blk, - struct xfs_da_state_blk *save_blk) -{ - struct xfs_da_blkinfo *drop_info; - struct xfs_da_blkinfo *save_info; - struct xfs_da_blkinfo *tmp_info; - struct xfs_da_args *args; - struct xfs_buf *bp; - int error; - - /* - * Set up environment. - */ - args = state->args; - ASSERT(args != NULL); - save_info = save_blk->bp->b_addr; - drop_info = drop_blk->bp->b_addr; - ASSERT(save_blk->magic == XFS_DA_NODE_MAGIC || - save_blk->magic == XFS_DIR2_LEAFN_MAGIC || - save_blk->magic == XFS_ATTR_LEAF_MAGIC); - ASSERT(save_blk->magic == drop_blk->magic); - ASSERT((be32_to_cpu(save_info->forw) == drop_blk->blkno) || - (be32_to_cpu(save_info->back) == drop_blk->blkno)); - ASSERT((be32_to_cpu(drop_info->forw) == save_blk->blkno) || - (be32_to_cpu(drop_info->back) == save_blk->blkno)); - - /* - * Unlink the leaf block from the doubly linked chain of leaves. - */ - if (be32_to_cpu(save_info->back) == drop_blk->blkno) { - trace_xfs_da_unlink_back(args); - save_info->back = drop_info->back; - if (drop_info->back) { - error = xfs_da3_node_read(args->trans, args->dp, - be32_to_cpu(drop_info->back), - -1, &bp, args->whichfork); - if (error) - return error; - ASSERT(bp != NULL); - tmp_info = bp->b_addr; - ASSERT(tmp_info->magic == save_info->magic); - ASSERT(be32_to_cpu(tmp_info->forw) == drop_blk->blkno); - tmp_info->forw = cpu_to_be32(save_blk->blkno); - xfs_trans_log_buf(args->trans, bp, 0, - sizeof(*tmp_info) - 1); - } - } else { - trace_xfs_da_unlink_forward(args); - save_info->forw = drop_info->forw; - if (drop_info->forw) { - error = xfs_da3_node_read(args->trans, args->dp, - be32_to_cpu(drop_info->forw), - -1, &bp, args->whichfork); - if (error) - return error; - ASSERT(bp != NULL); - tmp_info = bp->b_addr; - ASSERT(tmp_info->magic == save_info->magic); - ASSERT(be32_to_cpu(tmp_info->back) == drop_blk->blkno); - tmp_info->back = cpu_to_be32(save_blk->blkno); - xfs_trans_log_buf(args->trans, bp, 0, - sizeof(*tmp_info) - 1); - } - } - - xfs_trans_log_buf(args->trans, save_blk->bp, 0, sizeof(*save_info) - 1); - return 0; -} - -/* - * Move a path "forward" or "!forward" one block at the current level. - * - * This routine will adjust a "path" to point to the next block - * "forward" (higher hashvalues) or "!forward" (lower hashvals) in the - * Btree, including updating pointers to the intermediate nodes between - * the new bottom and the root. - */ -int /* error */ -xfs_da3_path_shift( - struct xfs_da_state *state, - struct xfs_da_state_path *path, - int forward, - int release, - int *result) -{ - struct xfs_da_state_blk *blk; - struct xfs_da_blkinfo *info; - struct xfs_da_intnode *node; - struct xfs_da_args *args; - struct xfs_da_node_entry *btree; - struct xfs_da3_icnode_hdr nodehdr; - struct xfs_buf *bp; - xfs_dablk_t blkno = 0; - int level; - int error; - struct xfs_inode *dp = state->args->dp; - - trace_xfs_da_path_shift(state->args); - - /* - * Roll up the Btree looking for the first block where our - * current index is not at the edge of the block. Note that - * we skip the bottom layer because we want the sibling block. - */ - args = state->args; - ASSERT(args != NULL); - ASSERT(path != NULL); - ASSERT((path->active > 0) && (path->active < XFS_DA_NODE_MAXDEPTH)); - level = (path->active-1) - 1; /* skip bottom layer in path */ - for (blk = &path->blk[level]; level >= 0; blk--, level--) { - node = blk->bp->b_addr; - dp->d_ops->node_hdr_from_disk(&nodehdr, node); - btree = dp->d_ops->node_tree_p(node); - - if (forward && (blk->index < nodehdr.count - 1)) { - blk->index++; - blkno = be32_to_cpu(btree[blk->index].before); - break; - } else if (!forward && (blk->index > 0)) { - blk->index--; - blkno = be32_to_cpu(btree[blk->index].before); - break; - } - } - if (level < 0) { - *result = -ENOENT; /* we're out of our tree */ - ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); - return 0; - } - - /* - * Roll down the edge of the subtree until we reach the - * same depth we were at originally. - */ - for (blk++, level++; level < path->active; blk++, level++) { - /* - * Read the next child block into a local buffer. - */ - error = xfs_da3_node_read(args->trans, dp, blkno, -1, &bp, - args->whichfork); - if (error) - return error; - - /* - * Release the old block (if it's dirty, the trans doesn't - * actually let go) and swap the local buffer into the path - * structure. This ensures failure of the above read doesn't set - * a NULL buffer in an active slot in the path. - */ - if (release) - xfs_trans_brelse(args->trans, blk->bp); - blk->blkno = blkno; - blk->bp = bp; - - info = blk->bp->b_addr; - ASSERT(info->magic == cpu_to_be16(XFS_DA_NODE_MAGIC) || - info->magic == cpu_to_be16(XFS_DA3_NODE_MAGIC) || - info->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || - info->magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC) || - info->magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC) || - info->magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)); - - - /* - * Note: we flatten the magic number to a single type so we - * don't have to compare against crc/non-crc types elsewhere. - */ - switch (be16_to_cpu(info->magic)) { - case XFS_DA_NODE_MAGIC: - case XFS_DA3_NODE_MAGIC: - blk->magic = XFS_DA_NODE_MAGIC; - node = (xfs_da_intnode_t *)info; - dp->d_ops->node_hdr_from_disk(&nodehdr, node); - btree = dp->d_ops->node_tree_p(node); - blk->hashval = be32_to_cpu(btree[nodehdr.count - 1].hashval); - if (forward) - blk->index = 0; - else - blk->index = nodehdr.count - 1; - blkno = be32_to_cpu(btree[blk->index].before); - break; - case XFS_ATTR_LEAF_MAGIC: - case XFS_ATTR3_LEAF_MAGIC: - blk->magic = XFS_ATTR_LEAF_MAGIC; - ASSERT(level == path->active-1); - blk->index = 0; - blk->hashval = xfs_attr_leaf_lasthash(blk->bp, NULL); - break; - case XFS_DIR2_LEAFN_MAGIC: - case XFS_DIR3_LEAFN_MAGIC: - blk->magic = XFS_DIR2_LEAFN_MAGIC; - ASSERT(level == path->active-1); - blk->index = 0; - blk->hashval = xfs_dir2_leafn_lasthash(args->dp, - blk->bp, NULL); - break; - default: - ASSERT(0); - break; - } - } - *result = 0; - return 0; -} - - -/*======================================================================== - * Utility routines. - *========================================================================*/ - -/* - * Implement a simple hash on a character string. - * Rotate the hash value by 7 bits, then XOR each character in. - * This is implemented with some source-level loop unrolling. - */ -xfs_dahash_t -xfs_da_hashname(const __uint8_t *name, int namelen) -{ - xfs_dahash_t hash; - - /* - * Do four characters at a time as long as we can. - */ - for (hash = 0; namelen >= 4; namelen -= 4, name += 4) - hash = (name[0] << 21) ^ (name[1] << 14) ^ (name[2] << 7) ^ - (name[3] << 0) ^ rol32(hash, 7 * 4); - - /* - * Now do the rest of the characters. - */ - switch (namelen) { - case 3: - return (name[0] << 14) ^ (name[1] << 7) ^ (name[2] << 0) ^ - rol32(hash, 7 * 3); - case 2: - return (name[0] << 7) ^ (name[1] << 0) ^ rol32(hash, 7 * 2); - case 1: - return (name[0] << 0) ^ rol32(hash, 7 * 1); - default: /* case 0: */ - return hash; - } -} - -enum xfs_dacmp -xfs_da_compname( - struct xfs_da_args *args, - const unsigned char *name, - int len) -{ - return (args->namelen == len && memcmp(args->name, name, len) == 0) ? - XFS_CMP_EXACT : XFS_CMP_DIFFERENT; -} - -static xfs_dahash_t -xfs_default_hashname( - struct xfs_name *name) -{ - return xfs_da_hashname(name->name, name->len); -} - -const struct xfs_nameops xfs_default_nameops = { - .hashname = xfs_default_hashname, - .compname = xfs_da_compname -}; - -int -xfs_da_grow_inode_int( - struct xfs_da_args *args, - xfs_fileoff_t *bno, - int count) -{ - struct xfs_trans *tp = args->trans; - struct xfs_inode *dp = args->dp; - int w = args->whichfork; - xfs_rfsblock_t nblks = dp->i_d.di_nblocks; - struct xfs_bmbt_irec map, *mapp; - int nmap, error, got, i, mapi; - - /* - * Find a spot in the file space to put the new block. - */ - error = xfs_bmap_first_unused(tp, dp, count, bno, w); - if (error) - return error; - - /* - * Try mapping it in one filesystem block. - */ - nmap = 1; - ASSERT(args->firstblock != NULL); - error = xfs_bmapi_write(tp, dp, *bno, count, - xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA|XFS_BMAPI_CONTIG, - args->firstblock, args->total, &map, &nmap, - args->dfops); - if (error) - return error; - - ASSERT(nmap <= 1); - if (nmap == 1) { - mapp = ↦ - mapi = 1; - } else if (nmap == 0 && count > 1) { - xfs_fileoff_t b; - int c; - - /* - * If we didn't get it and the block might work if fragmented, - * try without the CONTIG flag. Loop until we get it all. - */ - mapp = kmem_alloc(sizeof(*mapp) * count, KM_SLEEP); - for (b = *bno, mapi = 0; b < *bno + count; ) { - nmap = MIN(XFS_BMAP_MAX_NMAP, count); - c = (int)(*bno + count - b); - error = xfs_bmapi_write(tp, dp, b, c, - xfs_bmapi_aflag(w)|XFS_BMAPI_METADATA, - args->firstblock, args->total, - &mapp[mapi], &nmap, args->dfops); - if (error) - goto out_free_map; - if (nmap < 1) - break; - mapi += nmap; - b = mapp[mapi - 1].br_startoff + - mapp[mapi - 1].br_blockcount; - } - } else { - mapi = 0; - mapp = NULL; - } - - /* - * Count the blocks we got, make sure it matches the total. - */ - for (i = 0, got = 0; i < mapi; i++) - got += mapp[i].br_blockcount; - if (got != count || mapp[0].br_startoff != *bno || - mapp[mapi - 1].br_startoff + mapp[mapi - 1].br_blockcount != - *bno + count) { - error = -ENOSPC; - goto out_free_map; - } - - /* account for newly allocated blocks in reserved blocks total */ - args->total -= dp->i_d.di_nblocks - nblks; - -out_free_map: - if (mapp != &map) - kmem_free(mapp); - return error; -} - -/* - * Add a block to the btree ahead of the file. - * Return the new block number to the caller. - */ -int -xfs_da_grow_inode( - struct xfs_da_args *args, - xfs_dablk_t *new_blkno) -{ - xfs_fileoff_t bno; - int error; - - trace_xfs_da_grow_inode(args); - - bno = args->geo->leafblk; - error = xfs_da_grow_inode_int(args, &bno, args->geo->fsbcount); - if (!error) - *new_blkno = (xfs_dablk_t)bno; - return error; -} - -/* - * Ick. We need to always be able to remove a btree block, even - * if there's no space reservation because the filesystem is full. - * This is called if xfs_bunmapi on a btree block fails due to ENOSPC. - * It swaps the target block with the last block in the file. The - * last block in the file can always be removed since it can't cause - * a bmap btree split to do that. - */ -STATIC int -xfs_da3_swap_lastblock( - struct xfs_da_args *args, - xfs_dablk_t *dead_blknop, - struct xfs_buf **dead_bufp) -{ - struct xfs_da_blkinfo *dead_info; - struct xfs_da_blkinfo *sib_info; - struct xfs_da_intnode *par_node; - struct xfs_da_intnode *dead_node; - struct xfs_dir2_leaf *dead_leaf2; - struct xfs_da_node_entry *btree; - struct xfs_da3_icnode_hdr par_hdr; - struct xfs_inode *dp; - struct xfs_trans *tp; - struct xfs_mount *mp; - struct xfs_buf *dead_buf; - struct xfs_buf *last_buf; - struct xfs_buf *sib_buf; - struct xfs_buf *par_buf; - xfs_dahash_t dead_hash; - xfs_fileoff_t lastoff; - xfs_dablk_t dead_blkno; - xfs_dablk_t last_blkno; - xfs_dablk_t sib_blkno; - xfs_dablk_t par_blkno; - int error; - int w; - int entno; - int level; - int dead_level; - - trace_xfs_da_swap_lastblock(args); - - dead_buf = *dead_bufp; - dead_blkno = *dead_blknop; - tp = args->trans; - dp = args->dp; - w = args->whichfork; - ASSERT(w == XFS_DATA_FORK); - mp = dp->i_mount; - lastoff = args->geo->freeblk; - error = xfs_bmap_last_before(tp, dp, &lastoff, w); - if (error) - return error; - if (unlikely(lastoff == 0)) { - XFS_ERROR_REPORT("xfs_da_swap_lastblock(1)", XFS_ERRLEVEL_LOW, - mp); - return -EFSCORRUPTED; - } - /* - * Read the last block in the btree space. - */ - last_blkno = (xfs_dablk_t)lastoff - args->geo->fsbcount; - error = xfs_da3_node_read(tp, dp, last_blkno, -1, &last_buf, w); - if (error) - return error; - /* - * Copy the last block into the dead buffer and log it. - */ - memcpy(dead_buf->b_addr, last_buf->b_addr, args->geo->blksize); - xfs_trans_log_buf(tp, dead_buf, 0, args->geo->blksize - 1); - dead_info = dead_buf->b_addr; - /* - * Get values from the moved block. - */ - if (dead_info->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || - dead_info->magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)) { - struct xfs_dir3_icleaf_hdr leafhdr; - struct xfs_dir2_leaf_entry *ents; - - dead_leaf2 = (xfs_dir2_leaf_t *)dead_info; - dp->d_ops->leaf_hdr_from_disk(&leafhdr, dead_leaf2); - ents = dp->d_ops->leaf_ents_p(dead_leaf2); - dead_level = 0; - dead_hash = be32_to_cpu(ents[leafhdr.count - 1].hashval); - } else { - struct xfs_da3_icnode_hdr deadhdr; - - dead_node = (xfs_da_intnode_t *)dead_info; - dp->d_ops->node_hdr_from_disk(&deadhdr, dead_node); - btree = dp->d_ops->node_tree_p(dead_node); - dead_level = deadhdr.level; - dead_hash = be32_to_cpu(btree[deadhdr.count - 1].hashval); - } - sib_buf = par_buf = NULL; - /* - * If the moved block has a left sibling, fix up the pointers. - */ - if ((sib_blkno = be32_to_cpu(dead_info->back))) { - error = xfs_da3_node_read(tp, dp, sib_blkno, -1, &sib_buf, w); - if (error) - goto done; - sib_info = sib_buf->b_addr; - if (unlikely( - be32_to_cpu(sib_info->forw) != last_blkno || - sib_info->magic != dead_info->magic)) { - XFS_ERROR_REPORT("xfs_da_swap_lastblock(2)", - XFS_ERRLEVEL_LOW, mp); - error = -EFSCORRUPTED; - goto done; - } - sib_info->forw = cpu_to_be32(dead_blkno); - xfs_trans_log_buf(tp, sib_buf, - XFS_DA_LOGRANGE(sib_info, &sib_info->forw, - sizeof(sib_info->forw))); - sib_buf = NULL; - } - /* - * If the moved block has a right sibling, fix up the pointers. - */ - if ((sib_blkno = be32_to_cpu(dead_info->forw))) { - error = xfs_da3_node_read(tp, dp, sib_blkno, -1, &sib_buf, w); - if (error) - goto done; - sib_info = sib_buf->b_addr; - if (unlikely( - be32_to_cpu(sib_info->back) != last_blkno || - sib_info->magic != dead_info->magic)) { - XFS_ERROR_REPORT("xfs_da_swap_lastblock(3)", - XFS_ERRLEVEL_LOW, mp); - error = -EFSCORRUPTED; - goto done; - } - sib_info->back = cpu_to_be32(dead_blkno); - xfs_trans_log_buf(tp, sib_buf, - XFS_DA_LOGRANGE(sib_info, &sib_info->back, - sizeof(sib_info->back))); - sib_buf = NULL; - } - par_blkno = args->geo->leafblk; - level = -1; - /* - * Walk down the tree looking for the parent of the moved block. - */ - for (;;) { - error = xfs_da3_node_read(tp, dp, par_blkno, -1, &par_buf, w); - if (error) - goto done; - par_node = par_buf->b_addr; - dp->d_ops->node_hdr_from_disk(&par_hdr, par_node); - if (level >= 0 && level != par_hdr.level + 1) { - XFS_ERROR_REPORT("xfs_da_swap_lastblock(4)", - XFS_ERRLEVEL_LOW, mp); - error = -EFSCORRUPTED; - goto done; - } - level = par_hdr.level; - btree = dp->d_ops->node_tree_p(par_node); - for (entno = 0; - entno < par_hdr.count && - be32_to_cpu(btree[entno].hashval) < dead_hash; - entno++) - continue; - if (entno == par_hdr.count) { - XFS_ERROR_REPORT("xfs_da_swap_lastblock(5)", - XFS_ERRLEVEL_LOW, mp); - error = -EFSCORRUPTED; - goto done; - } - par_blkno = be32_to_cpu(btree[entno].before); - if (level == dead_level + 1) - break; - xfs_trans_brelse(tp, par_buf); - par_buf = NULL; - } - /* - * We're in the right parent block. - * Look for the right entry. - */ - for (;;) { - for (; - entno < par_hdr.count && - be32_to_cpu(btree[entno].before) != last_blkno; - entno++) - continue; - if (entno < par_hdr.count) - break; - par_blkno = par_hdr.forw; - xfs_trans_brelse(tp, par_buf); - par_buf = NULL; - if (unlikely(par_blkno == 0)) { - XFS_ERROR_REPORT("xfs_da_swap_lastblock(6)", - XFS_ERRLEVEL_LOW, mp); - error = -EFSCORRUPTED; - goto done; - } - error = xfs_da3_node_read(tp, dp, par_blkno, -1, &par_buf, w); - if (error) - goto done; - par_node = par_buf->b_addr; - dp->d_ops->node_hdr_from_disk(&par_hdr, par_node); - if (par_hdr.level != level) { - XFS_ERROR_REPORT("xfs_da_swap_lastblock(7)", - XFS_ERRLEVEL_LOW, mp); - error = -EFSCORRUPTED; - goto done; - } - btree = dp->d_ops->node_tree_p(par_node); - entno = 0; - } - /* - * Update the parent entry pointing to the moved block. - */ - btree[entno].before = cpu_to_be32(dead_blkno); - xfs_trans_log_buf(tp, par_buf, - XFS_DA_LOGRANGE(par_node, &btree[entno].before, - sizeof(btree[entno].before))); - *dead_blknop = last_blkno; - *dead_bufp = last_buf; - return 0; -done: - if (par_buf) - xfs_trans_brelse(tp, par_buf); - if (sib_buf) - xfs_trans_brelse(tp, sib_buf); - xfs_trans_brelse(tp, last_buf); - return error; -} - -/* - * Remove a btree block from a directory or attribute. - */ -int -xfs_da_shrink_inode( - xfs_da_args_t *args, - xfs_dablk_t dead_blkno, - struct xfs_buf *dead_buf) -{ - xfs_inode_t *dp; - int done, error, w, count; - xfs_trans_t *tp; - - trace_xfs_da_shrink_inode(args); - - dp = args->dp; - w = args->whichfork; - tp = args->trans; - count = args->geo->fsbcount; - for (;;) { - /* - * Remove extents. If we get ENOSPC for a dir we have to move - * the last block to the place we want to kill. - */ - error = xfs_bunmapi(tp, dp, dead_blkno, count, - xfs_bmapi_aflag(w), 0, args->firstblock, - args->dfops, &done); - if (error == -ENOSPC) { - if (w != XFS_DATA_FORK) - break; - error = xfs_da3_swap_lastblock(args, &dead_blkno, - &dead_buf); - if (error) - break; - } else { - break; - } - } - xfs_trans_binval(tp, dead_buf); - return error; -} - -/* - * See if the mapping(s) for this btree block are valid, i.e. - * don't contain holes, are logically contiguous, and cover the whole range. - */ -STATIC int -xfs_da_map_covers_blocks( - int nmap, - xfs_bmbt_irec_t *mapp, - xfs_dablk_t bno, - int count) -{ - int i; - xfs_fileoff_t off; - - for (i = 0, off = bno; i < nmap; i++) { - if (mapp[i].br_startblock == HOLESTARTBLOCK || - mapp[i].br_startblock == DELAYSTARTBLOCK) { - return 0; - } - if (off != mapp[i].br_startoff) { - return 0; - } - off += mapp[i].br_blockcount; - } - return off == bno + count; -} - -/* - * Convert a struct xfs_bmbt_irec to a struct xfs_buf_map. - * - * For the single map case, it is assumed that the caller has provided a pointer - * to a valid xfs_buf_map. For the multiple map case, this function will - * allocate the xfs_buf_map to hold all the maps and replace the caller's single - * map pointer with the allocated map. - */ -static int -xfs_buf_map_from_irec( - struct xfs_mount *mp, - struct xfs_buf_map **mapp, - int *nmaps, - struct xfs_bmbt_irec *irecs, - int nirecs) -{ - struct xfs_buf_map *map; - int i; - - ASSERT(*nmaps == 1); - ASSERT(nirecs >= 1); - - if (nirecs > 1) { - map = kmem_zalloc(nirecs * sizeof(struct xfs_buf_map), - KM_SLEEP | KM_NOFS); - if (!map) - return -ENOMEM; - *mapp = map; - } - - *nmaps = nirecs; - map = *mapp; - for (i = 0; i < *nmaps; i++) { - ASSERT(irecs[i].br_startblock != DELAYSTARTBLOCK && - irecs[i].br_startblock != HOLESTARTBLOCK); - map[i].bm_bn = XFS_FSB_TO_DADDR(mp, irecs[i].br_startblock); - map[i].bm_len = XFS_FSB_TO_BB(mp, irecs[i].br_blockcount); - } - return 0; -} - -/* - * Map the block we are given ready for reading. There are three possible return - * values: - * -1 - will be returned if we land in a hole and mappedbno == -2 so the - * caller knows not to execute a subsequent read. - * 0 - if we mapped the block successfully - * >0 - positive error number if there was an error. - */ -static int -xfs_dabuf_map( - struct xfs_inode *dp, - xfs_dablk_t bno, - xfs_daddr_t mappedbno, - int whichfork, - struct xfs_buf_map **map, - int *nmaps) -{ - struct xfs_mount *mp = dp->i_mount; - int nfsb; - int error = 0; - struct xfs_bmbt_irec irec; - struct xfs_bmbt_irec *irecs = &irec; - int nirecs; - - ASSERT(map && *map); - ASSERT(*nmaps == 1); - - if (whichfork == XFS_DATA_FORK) - nfsb = mp->m_dir_geo->fsbcount; - else - nfsb = mp->m_attr_geo->fsbcount; - - /* - * Caller doesn't have a mapping. -2 means don't complain - * if we land in a hole. - */ - if (mappedbno == -1 || mappedbno == -2) { - /* - * Optimize the one-block case. - */ - if (nfsb != 1) - irecs = kmem_zalloc(sizeof(irec) * nfsb, - KM_SLEEP | KM_NOFS); - - nirecs = nfsb; - error = xfs_bmapi_read(dp, (xfs_fileoff_t)bno, nfsb, irecs, - &nirecs, xfs_bmapi_aflag(whichfork)); - if (error) - goto out; - } else { - irecs->br_startblock = XFS_DADDR_TO_FSB(mp, mappedbno); - irecs->br_startoff = (xfs_fileoff_t)bno; - irecs->br_blockcount = nfsb; - irecs->br_state = 0; - nirecs = 1; - } - - if (!xfs_da_map_covers_blocks(nirecs, irecs, bno, nfsb)) { - error = mappedbno == -2 ? -1 : -EFSCORRUPTED; - if (unlikely(error == -EFSCORRUPTED)) { - if (xfs_error_level >= XFS_ERRLEVEL_LOW) { - int i; - xfs_alert(mp, "%s: bno %lld dir: inode %lld", - __func__, (long long)bno, - (long long)dp->i_ino); - for (i = 0; i < *nmaps; i++) { - xfs_alert(mp, -"[%02d] br_startoff %lld br_startblock %lld br_blockcount %lld br_state %d", - i, - (long long)irecs[i].br_startoff, - (long long)irecs[i].br_startblock, - (long long)irecs[i].br_blockcount, - irecs[i].br_state); - } - } - XFS_ERROR_REPORT("xfs_da_do_buf(1)", - XFS_ERRLEVEL_LOW, mp); - } - goto out; - } - error = xfs_buf_map_from_irec(mp, map, nmaps, irecs, nirecs); -out: - if (irecs != &irec) - kmem_free(irecs); - return error; -} - -/* - * Get a buffer for the dir/attr block. - */ -int -xfs_da_get_buf( - struct xfs_trans *trans, - struct xfs_inode *dp, - xfs_dablk_t bno, - xfs_daddr_t mappedbno, - struct xfs_buf **bpp, - int whichfork) -{ - struct xfs_buf *bp; - struct xfs_buf_map map; - struct xfs_buf_map *mapp; - int nmap; - int error; - - *bpp = NULL; - mapp = ↦ - nmap = 1; - error = xfs_dabuf_map(dp, bno, mappedbno, whichfork, - &mapp, &nmap); - if (error) { - /* mapping a hole is not an error, but we don't continue */ - if (error == -1) - error = 0; - goto out_free; - } - - bp = xfs_trans_get_buf_map(trans, dp->i_mount->m_ddev_targp, - mapp, nmap, 0); - error = bp ? bp->b_error : -EIO; - if (error) { - if (bp) - xfs_trans_brelse(trans, bp); - goto out_free; - } - - *bpp = bp; - -out_free: - if (mapp != &map) - kmem_free(mapp); - - return error; -} - -/* - * Get a buffer for the dir/attr block, fill in the contents. - */ -int -xfs_da_read_buf( - struct xfs_trans *trans, - struct xfs_inode *dp, - xfs_dablk_t bno, - xfs_daddr_t mappedbno, - struct xfs_buf **bpp, - int whichfork, - const struct xfs_buf_ops *ops) -{ - struct xfs_buf *bp; - struct xfs_buf_map map; - struct xfs_buf_map *mapp; - int nmap; - int error; - - *bpp = NULL; - mapp = ↦ - nmap = 1; - error = xfs_dabuf_map(dp, bno, mappedbno, whichfork, - &mapp, &nmap); - if (error) { - /* mapping a hole is not an error, but we don't continue */ - if (error == -1) - error = 0; - goto out_free; - } - - error = xfs_trans_read_buf_map(dp->i_mount, trans, - dp->i_mount->m_ddev_targp, - mapp, nmap, 0, &bp, ops); - if (error) - goto out_free; - - if (whichfork == XFS_ATTR_FORK) - xfs_buf_set_ref(bp, XFS_ATTR_BTREE_REF); - else - xfs_buf_set_ref(bp, XFS_DIR_BTREE_REF); - *bpp = bp; -out_free: - if (mapp != &map) - kmem_free(mapp); - - return error; -} - -/* - * Readahead the dir/attr block. - */ -xfs_daddr_t -xfs_da_reada_buf( - struct xfs_inode *dp, - xfs_dablk_t bno, - xfs_daddr_t mappedbno, - int whichfork, - const struct xfs_buf_ops *ops) -{ - struct xfs_buf_map map; - struct xfs_buf_map *mapp; - int nmap; - int error; - - mapp = ↦ - nmap = 1; - error = xfs_dabuf_map(dp, bno, mappedbno, whichfork, - &mapp, &nmap); - if (error) { - /* mapping a hole is not an error, but we don't continue */ - if (error == -1) - error = 0; - goto out_free; - } - - mappedbno = mapp[0].bm_bn; - xfs_buf_readahead_map(dp->i_mount->m_ddev_targp, mapp, nmap, ops); - -out_free: - if (mapp != &map) - kmem_free(mapp); - - if (error) - return -1; - return mappedbno; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_da_btree.h b/src/linux/fs/xfs/libxfs/xfs_da_btree.h deleted file mode 100644 index 98c75cb..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_da_btree.h +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright (c) 2000,2002,2005 Silicon Graphics, Inc. - * Copyright (c) 2013 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_DA_BTREE_H__ -#define __XFS_DA_BTREE_H__ - -struct xfs_defer_ops; -struct xfs_inode; -struct xfs_trans; -struct zone; -struct xfs_dir_ops; - -/* - * Directory/attribute geometry information. There will be one of these for each - * data fork type, and it will be passed around via the xfs_da_args. Global - * structures will be attached to the xfs_mount. - */ -struct xfs_da_geometry { - int blksize; /* da block size in bytes */ - int fsbcount; /* da block size in filesystem blocks */ - uint8_t fsblog; /* log2 of _filesystem_ block size */ - uint8_t blklog; /* log2 of da block size */ - uint node_ents; /* # of entries in a danode */ - int magicpct; /* 37% of block size in bytes */ - xfs_dablk_t datablk; /* blockno of dir data v2 */ - xfs_dablk_t leafblk; /* blockno of leaf data v2 */ - xfs_dablk_t freeblk; /* blockno of free data v2 */ -}; - -/*======================================================================== - * Btree searching and modification structure definitions. - *========================================================================*/ - -/* - * Search comparison results - */ -enum xfs_dacmp { - XFS_CMP_DIFFERENT, /* names are completely different */ - XFS_CMP_EXACT, /* names are exactly the same */ - XFS_CMP_CASE /* names are same but differ in case */ -}; - -/* - * Structure to ease passing around component names. - */ -typedef struct xfs_da_args { - struct xfs_da_geometry *geo; /* da block geometry */ - const __uint8_t *name; /* string (maybe not NULL terminated) */ - int namelen; /* length of string (maybe no NULL) */ - __uint8_t filetype; /* filetype of inode for directories */ - __uint8_t *value; /* set of bytes (maybe contain NULLs) */ - int valuelen; /* length of value */ - int flags; /* argument flags (eg: ATTR_NOCREATE) */ - xfs_dahash_t hashval; /* hash value of name */ - xfs_ino_t inumber; /* input/output inode number */ - struct xfs_inode *dp; /* directory inode to manipulate */ - xfs_fsblock_t *firstblock; /* ptr to firstblock for bmap calls */ - struct xfs_defer_ops *dfops; /* ptr to freelist for bmap_finish */ - struct xfs_trans *trans; /* current trans (changes over time) */ - xfs_extlen_t total; /* total blocks needed, for 1st bmap */ - int whichfork; /* data or attribute fork */ - xfs_dablk_t blkno; /* blkno of attr leaf of interest */ - int index; /* index of attr of interest in blk */ - xfs_dablk_t rmtblkno; /* remote attr value starting blkno */ - int rmtblkcnt; /* remote attr value block count */ - int rmtvaluelen; /* remote attr value length in bytes */ - xfs_dablk_t blkno2; /* blkno of 2nd attr leaf of interest */ - int index2; /* index of 2nd attr in blk */ - xfs_dablk_t rmtblkno2; /* remote attr value starting blkno */ - int rmtblkcnt2; /* remote attr value block count */ - int rmtvaluelen2; /* remote attr value length in bytes */ - int op_flags; /* operation flags */ - enum xfs_dacmp cmpresult; /* name compare result for lookups */ -} xfs_da_args_t; - -/* - * Operation flags: - */ -#define XFS_DA_OP_JUSTCHECK 0x0001 /* check for ok with no space */ -#define XFS_DA_OP_RENAME 0x0002 /* this is an atomic rename op */ -#define XFS_DA_OP_ADDNAME 0x0004 /* this is an add operation */ -#define XFS_DA_OP_OKNOENT 0x0008 /* lookup/add op, ENOENT ok, else die */ -#define XFS_DA_OP_CILOOKUP 0x0010 /* lookup to return CI name if found */ - -#define XFS_DA_OP_FLAGS \ - { XFS_DA_OP_JUSTCHECK, "JUSTCHECK" }, \ - { XFS_DA_OP_RENAME, "RENAME" }, \ - { XFS_DA_OP_ADDNAME, "ADDNAME" }, \ - { XFS_DA_OP_OKNOENT, "OKNOENT" }, \ - { XFS_DA_OP_CILOOKUP, "CILOOKUP" } - -/* - * Storage for holding state during Btree searches and split/join ops. - * - * Only need space for 5 intermediate nodes. With a minimum of 62-way - * fanout to the Btree, we can support over 900 million directory blocks, - * which is slightly more than enough. - */ -typedef struct xfs_da_state_blk { - struct xfs_buf *bp; /* buffer containing block */ - xfs_dablk_t blkno; /* filesystem blkno of buffer */ - xfs_daddr_t disk_blkno; /* on-disk blkno (in BBs) of buffer */ - int index; /* relevant index into block */ - xfs_dahash_t hashval; /* last hash value in block */ - int magic; /* blk's magic number, ie: blk type */ -} xfs_da_state_blk_t; - -typedef struct xfs_da_state_path { - int active; /* number of active levels */ - xfs_da_state_blk_t blk[XFS_DA_NODE_MAXDEPTH]; -} xfs_da_state_path_t; - -typedef struct xfs_da_state { - xfs_da_args_t *args; /* filename arguments */ - struct xfs_mount *mp; /* filesystem mount point */ - xfs_da_state_path_t path; /* search/split paths */ - xfs_da_state_path_t altpath; /* alternate path for join */ - unsigned char inleaf; /* insert into 1->lf, 0->splf */ - unsigned char extravalid; /* T/F: extrablk is in use */ - unsigned char extraafter; /* T/F: extrablk is after new */ - xfs_da_state_blk_t extrablk; /* for double-splits on leaves */ - /* for dirv2 extrablk is data */ -} xfs_da_state_t; - -/* - * Utility macros to aid in logging changed structure fields. - */ -#define XFS_DA_LOGOFF(BASE, ADDR) ((char *)(ADDR) - (char *)(BASE)) -#define XFS_DA_LOGRANGE(BASE, ADDR, SIZE) \ - (uint)(XFS_DA_LOGOFF(BASE, ADDR)), \ - (uint)(XFS_DA_LOGOFF(BASE, ADDR)+(SIZE)-1) - -/* - * Name ops for directory and/or attr name operations - */ -struct xfs_nameops { - xfs_dahash_t (*hashname)(struct xfs_name *); - enum xfs_dacmp (*compname)(struct xfs_da_args *, - const unsigned char *, int); -}; - - -/*======================================================================== - * Function prototypes. - *========================================================================*/ - -/* - * Routines used for growing the Btree. - */ -int xfs_da3_node_create(struct xfs_da_args *args, xfs_dablk_t blkno, - int level, struct xfs_buf **bpp, int whichfork); -int xfs_da3_split(xfs_da_state_t *state); - -/* - * Routines used for shrinking the Btree. - */ -int xfs_da3_join(xfs_da_state_t *state); -void xfs_da3_fixhashpath(struct xfs_da_state *state, - struct xfs_da_state_path *path_to_to_fix); - -/* - * Routines used for finding things in the Btree. - */ -int xfs_da3_node_lookup_int(xfs_da_state_t *state, int *result); -int xfs_da3_path_shift(xfs_da_state_t *state, xfs_da_state_path_t *path, - int forward, int release, int *result); -/* - * Utility routines. - */ -int xfs_da3_blk_link(xfs_da_state_t *state, xfs_da_state_blk_t *old_blk, - xfs_da_state_blk_t *new_blk); -int xfs_da3_node_read(struct xfs_trans *tp, struct xfs_inode *dp, - xfs_dablk_t bno, xfs_daddr_t mappedbno, - struct xfs_buf **bpp, int which_fork); - -/* - * Utility routines. - */ -int xfs_da_grow_inode(xfs_da_args_t *args, xfs_dablk_t *new_blkno); -int xfs_da_grow_inode_int(struct xfs_da_args *args, xfs_fileoff_t *bno, - int count); -int xfs_da_get_buf(struct xfs_trans *trans, struct xfs_inode *dp, - xfs_dablk_t bno, xfs_daddr_t mappedbno, - struct xfs_buf **bp, int whichfork); -int xfs_da_read_buf(struct xfs_trans *trans, struct xfs_inode *dp, - xfs_dablk_t bno, xfs_daddr_t mappedbno, - struct xfs_buf **bpp, int whichfork, - const struct xfs_buf_ops *ops); -xfs_daddr_t xfs_da_reada_buf(struct xfs_inode *dp, xfs_dablk_t bno, - xfs_daddr_t mapped_bno, int whichfork, - const struct xfs_buf_ops *ops); -int xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno, - struct xfs_buf *dead_buf); - -uint xfs_da_hashname(const __uint8_t *name_string, int name_length); -enum xfs_dacmp xfs_da_compname(struct xfs_da_args *args, - const unsigned char *name, int len); - - -xfs_da_state_t *xfs_da_state_alloc(void); -void xfs_da_state_free(xfs_da_state_t *state); - -extern struct kmem_zone *xfs_da_state_zone; -extern const struct xfs_nameops xfs_default_nameops; - -#endif /* __XFS_DA_BTREE_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_da_format.c b/src/linux/fs/xfs/libxfs/xfs_da_format.c deleted file mode 100644 index f1e8d4d..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_da_format.c +++ /dev/null @@ -1,903 +0,0 @@ -/* - * Copyright (c) 2000,2002,2005 Silicon Graphics, Inc. - * Copyright (c) 2013 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_inode.h" -#include "xfs_dir2.h" -#include "xfs_dir2_priv.h" - -/* - * Shortform directory ops - */ -static int -xfs_dir2_sf_entsize( - struct xfs_dir2_sf_hdr *hdr, - int len) -{ - int count = sizeof(struct xfs_dir2_sf_entry); /* namelen + offset */ - - count += len; /* name */ - count += hdr->i8count ? XFS_INO64_SIZE : XFS_INO32_SIZE; /* ino # */ - return count; -} - -static int -xfs_dir3_sf_entsize( - struct xfs_dir2_sf_hdr *hdr, - int len) -{ - return xfs_dir2_sf_entsize(hdr, len) + sizeof(__uint8_t); -} - -static struct xfs_dir2_sf_entry * -xfs_dir2_sf_nextentry( - struct xfs_dir2_sf_hdr *hdr, - struct xfs_dir2_sf_entry *sfep) -{ - return (struct xfs_dir2_sf_entry *) - ((char *)sfep + xfs_dir2_sf_entsize(hdr, sfep->namelen)); -} - -static struct xfs_dir2_sf_entry * -xfs_dir3_sf_nextentry( - struct xfs_dir2_sf_hdr *hdr, - struct xfs_dir2_sf_entry *sfep) -{ - return (struct xfs_dir2_sf_entry *) - ((char *)sfep + xfs_dir3_sf_entsize(hdr, sfep->namelen)); -} - - -/* - * For filetype enabled shortform directories, the file type field is stored at - * the end of the name. Because it's only a single byte, endian conversion is - * not necessary. For non-filetype enable directories, the type is always - * unknown and we never store the value. - */ -static __uint8_t -xfs_dir2_sfe_get_ftype( - struct xfs_dir2_sf_entry *sfep) -{ - return XFS_DIR3_FT_UNKNOWN; -} - -static void -xfs_dir2_sfe_put_ftype( - struct xfs_dir2_sf_entry *sfep, - __uint8_t ftype) -{ - ASSERT(ftype < XFS_DIR3_FT_MAX); -} - -static __uint8_t -xfs_dir3_sfe_get_ftype( - struct xfs_dir2_sf_entry *sfep) -{ - __uint8_t ftype; - - ftype = sfep->name[sfep->namelen]; - if (ftype >= XFS_DIR3_FT_MAX) - return XFS_DIR3_FT_UNKNOWN; - return ftype; -} - -static void -xfs_dir3_sfe_put_ftype( - struct xfs_dir2_sf_entry *sfep, - __uint8_t ftype) -{ - ASSERT(ftype < XFS_DIR3_FT_MAX); - - sfep->name[sfep->namelen] = ftype; -} - -/* - * Inode numbers in short-form directories can come in two versions, - * either 4 bytes or 8 bytes wide. These helpers deal with the - * two forms transparently by looking at the headers i8count field. - * - * For 64-bit inode number the most significant byte must be zero. - */ -static xfs_ino_t -xfs_dir2_sf_get_ino( - struct xfs_dir2_sf_hdr *hdr, - __uint8_t *from) -{ - if (hdr->i8count) - return get_unaligned_be64(from) & 0x00ffffffffffffffULL; - else - return get_unaligned_be32(from); -} - -static void -xfs_dir2_sf_put_ino( - struct xfs_dir2_sf_hdr *hdr, - __uint8_t *to, - xfs_ino_t ino) -{ - ASSERT((ino & 0xff00000000000000ULL) == 0); - - if (hdr->i8count) - put_unaligned_be64(ino, to); - else - put_unaligned_be32(ino, to); -} - -static xfs_ino_t -xfs_dir2_sf_get_parent_ino( - struct xfs_dir2_sf_hdr *hdr) -{ - return xfs_dir2_sf_get_ino(hdr, hdr->parent); -} - -static void -xfs_dir2_sf_put_parent_ino( - struct xfs_dir2_sf_hdr *hdr, - xfs_ino_t ino) -{ - xfs_dir2_sf_put_ino(hdr, hdr->parent, ino); -} - -/* - * In short-form directory entries the inode numbers are stored at variable - * offset behind the entry name. If the entry stores a filetype value, then it - * sits between the name and the inode number. Hence the inode numbers may only - * be accessed through the helpers below. - */ -static xfs_ino_t -xfs_dir2_sfe_get_ino( - struct xfs_dir2_sf_hdr *hdr, - struct xfs_dir2_sf_entry *sfep) -{ - return xfs_dir2_sf_get_ino(hdr, &sfep->name[sfep->namelen]); -} - -static void -xfs_dir2_sfe_put_ino( - struct xfs_dir2_sf_hdr *hdr, - struct xfs_dir2_sf_entry *sfep, - xfs_ino_t ino) -{ - xfs_dir2_sf_put_ino(hdr, &sfep->name[sfep->namelen], ino); -} - -static xfs_ino_t -xfs_dir3_sfe_get_ino( - struct xfs_dir2_sf_hdr *hdr, - struct xfs_dir2_sf_entry *sfep) -{ - return xfs_dir2_sf_get_ino(hdr, &sfep->name[sfep->namelen + 1]); -} - -static void -xfs_dir3_sfe_put_ino( - struct xfs_dir2_sf_hdr *hdr, - struct xfs_dir2_sf_entry *sfep, - xfs_ino_t ino) -{ - xfs_dir2_sf_put_ino(hdr, &sfep->name[sfep->namelen + 1], ino); -} - - -/* - * Directory data block operations - */ - -/* - * For special situations, the dirent size ends up fixed because we always know - * what the size of the entry is. That's true for the "." and "..", and - * therefore we know that they are a fixed size and hence their offsets are - * constant, as is the first entry. - * - * Hence, this calculation is written as a macro to be able to be calculated at - * compile time and so certain offsets can be calculated directly in the - * structure initaliser via the macro. There are two macros - one for dirents - * with ftype and without so there are no unresolvable conditionals in the - * calculations. We also use round_up() as XFS_DIR2_DATA_ALIGN is always a power - * of 2 and the compiler doesn't reject it (unlike roundup()). - */ -#define XFS_DIR2_DATA_ENTSIZE(n) \ - round_up((offsetof(struct xfs_dir2_data_entry, name[0]) + (n) + \ - sizeof(xfs_dir2_data_off_t)), XFS_DIR2_DATA_ALIGN) - -#define XFS_DIR3_DATA_ENTSIZE(n) \ - round_up((offsetof(struct xfs_dir2_data_entry, name[0]) + (n) + \ - sizeof(xfs_dir2_data_off_t) + sizeof(__uint8_t)), \ - XFS_DIR2_DATA_ALIGN) - -static int -xfs_dir2_data_entsize( - int n) -{ - return XFS_DIR2_DATA_ENTSIZE(n); -} - -static int -xfs_dir3_data_entsize( - int n) -{ - return XFS_DIR3_DATA_ENTSIZE(n); -} - -static __uint8_t -xfs_dir2_data_get_ftype( - struct xfs_dir2_data_entry *dep) -{ - return XFS_DIR3_FT_UNKNOWN; -} - -static void -xfs_dir2_data_put_ftype( - struct xfs_dir2_data_entry *dep, - __uint8_t ftype) -{ - ASSERT(ftype < XFS_DIR3_FT_MAX); -} - -static __uint8_t -xfs_dir3_data_get_ftype( - struct xfs_dir2_data_entry *dep) -{ - __uint8_t ftype = dep->name[dep->namelen]; - - if (ftype >= XFS_DIR3_FT_MAX) - return XFS_DIR3_FT_UNKNOWN; - return ftype; -} - -static void -xfs_dir3_data_put_ftype( - struct xfs_dir2_data_entry *dep, - __uint8_t type) -{ - ASSERT(type < XFS_DIR3_FT_MAX); - ASSERT(dep->namelen != 0); - - dep->name[dep->namelen] = type; -} - -/* - * Pointer to an entry's tag word. - */ -static __be16 * -xfs_dir2_data_entry_tag_p( - struct xfs_dir2_data_entry *dep) -{ - return (__be16 *)((char *)dep + - xfs_dir2_data_entsize(dep->namelen) - sizeof(__be16)); -} - -static __be16 * -xfs_dir3_data_entry_tag_p( - struct xfs_dir2_data_entry *dep) -{ - return (__be16 *)((char *)dep + - xfs_dir3_data_entsize(dep->namelen) - sizeof(__be16)); -} - -/* - * location of . and .. in data space (always block 0) - */ -static struct xfs_dir2_data_entry * -xfs_dir2_data_dot_entry_p( - struct xfs_dir2_data_hdr *hdr) -{ - return (struct xfs_dir2_data_entry *) - ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); -} - -static struct xfs_dir2_data_entry * -xfs_dir2_data_dotdot_entry_p( - struct xfs_dir2_data_hdr *hdr) -{ - return (struct xfs_dir2_data_entry *) - ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + - XFS_DIR2_DATA_ENTSIZE(1)); -} - -static struct xfs_dir2_data_entry * -xfs_dir2_data_first_entry_p( - struct xfs_dir2_data_hdr *hdr) -{ - return (struct xfs_dir2_data_entry *) - ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + - XFS_DIR2_DATA_ENTSIZE(1) + - XFS_DIR2_DATA_ENTSIZE(2)); -} - -static struct xfs_dir2_data_entry * -xfs_dir2_ftype_data_dotdot_entry_p( - struct xfs_dir2_data_hdr *hdr) -{ - return (struct xfs_dir2_data_entry *) - ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + - XFS_DIR3_DATA_ENTSIZE(1)); -} - -static struct xfs_dir2_data_entry * -xfs_dir2_ftype_data_first_entry_p( - struct xfs_dir2_data_hdr *hdr) -{ - return (struct xfs_dir2_data_entry *) - ((char *)hdr + sizeof(struct xfs_dir2_data_hdr) + - XFS_DIR3_DATA_ENTSIZE(1) + - XFS_DIR3_DATA_ENTSIZE(2)); -} - -static struct xfs_dir2_data_entry * -xfs_dir3_data_dot_entry_p( - struct xfs_dir2_data_hdr *hdr) -{ - return (struct xfs_dir2_data_entry *) - ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); -} - -static struct xfs_dir2_data_entry * -xfs_dir3_data_dotdot_entry_p( - struct xfs_dir2_data_hdr *hdr) -{ - return (struct xfs_dir2_data_entry *) - ((char *)hdr + sizeof(struct xfs_dir3_data_hdr) + - XFS_DIR3_DATA_ENTSIZE(1)); -} - -static struct xfs_dir2_data_entry * -xfs_dir3_data_first_entry_p( - struct xfs_dir2_data_hdr *hdr) -{ - return (struct xfs_dir2_data_entry *) - ((char *)hdr + sizeof(struct xfs_dir3_data_hdr) + - XFS_DIR3_DATA_ENTSIZE(1) + - XFS_DIR3_DATA_ENTSIZE(2)); -} - -static struct xfs_dir2_data_free * -xfs_dir2_data_bestfree_p(struct xfs_dir2_data_hdr *hdr) -{ - return hdr->bestfree; -} - -static struct xfs_dir2_data_free * -xfs_dir3_data_bestfree_p(struct xfs_dir2_data_hdr *hdr) -{ - return ((struct xfs_dir3_data_hdr *)hdr)->best_free; -} - -static struct xfs_dir2_data_entry * -xfs_dir2_data_entry_p(struct xfs_dir2_data_hdr *hdr) -{ - return (struct xfs_dir2_data_entry *) - ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); -} - -static struct xfs_dir2_data_unused * -xfs_dir2_data_unused_p(struct xfs_dir2_data_hdr *hdr) -{ - return (struct xfs_dir2_data_unused *) - ((char *)hdr + sizeof(struct xfs_dir2_data_hdr)); -} - -static struct xfs_dir2_data_entry * -xfs_dir3_data_entry_p(struct xfs_dir2_data_hdr *hdr) -{ - return (struct xfs_dir2_data_entry *) - ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); -} - -static struct xfs_dir2_data_unused * -xfs_dir3_data_unused_p(struct xfs_dir2_data_hdr *hdr) -{ - return (struct xfs_dir2_data_unused *) - ((char *)hdr + sizeof(struct xfs_dir3_data_hdr)); -} - - -/* - * Directory Leaf block operations - */ -static int -xfs_dir2_max_leaf_ents(struct xfs_da_geometry *geo) -{ - return (geo->blksize - sizeof(struct xfs_dir2_leaf_hdr)) / - (uint)sizeof(struct xfs_dir2_leaf_entry); -} - -static struct xfs_dir2_leaf_entry * -xfs_dir2_leaf_ents_p(struct xfs_dir2_leaf *lp) -{ - return lp->__ents; -} - -static int -xfs_dir3_max_leaf_ents(struct xfs_da_geometry *geo) -{ - return (geo->blksize - sizeof(struct xfs_dir3_leaf_hdr)) / - (uint)sizeof(struct xfs_dir2_leaf_entry); -} - -static struct xfs_dir2_leaf_entry * -xfs_dir3_leaf_ents_p(struct xfs_dir2_leaf *lp) -{ - return ((struct xfs_dir3_leaf *)lp)->__ents; -} - -static void -xfs_dir2_leaf_hdr_from_disk( - struct xfs_dir3_icleaf_hdr *to, - struct xfs_dir2_leaf *from) -{ - to->forw = be32_to_cpu(from->hdr.info.forw); - to->back = be32_to_cpu(from->hdr.info.back); - to->magic = be16_to_cpu(from->hdr.info.magic); - to->count = be16_to_cpu(from->hdr.count); - to->stale = be16_to_cpu(from->hdr.stale); - - ASSERT(to->magic == XFS_DIR2_LEAF1_MAGIC || - to->magic == XFS_DIR2_LEAFN_MAGIC); -} - -static void -xfs_dir2_leaf_hdr_to_disk( - struct xfs_dir2_leaf *to, - struct xfs_dir3_icleaf_hdr *from) -{ - ASSERT(from->magic == XFS_DIR2_LEAF1_MAGIC || - from->magic == XFS_DIR2_LEAFN_MAGIC); - - to->hdr.info.forw = cpu_to_be32(from->forw); - to->hdr.info.back = cpu_to_be32(from->back); - to->hdr.info.magic = cpu_to_be16(from->magic); - to->hdr.count = cpu_to_be16(from->count); - to->hdr.stale = cpu_to_be16(from->stale); -} - -static void -xfs_dir3_leaf_hdr_from_disk( - struct xfs_dir3_icleaf_hdr *to, - struct xfs_dir2_leaf *from) -{ - struct xfs_dir3_leaf_hdr *hdr3 = (struct xfs_dir3_leaf_hdr *)from; - - to->forw = be32_to_cpu(hdr3->info.hdr.forw); - to->back = be32_to_cpu(hdr3->info.hdr.back); - to->magic = be16_to_cpu(hdr3->info.hdr.magic); - to->count = be16_to_cpu(hdr3->count); - to->stale = be16_to_cpu(hdr3->stale); - - ASSERT(to->magic == XFS_DIR3_LEAF1_MAGIC || - to->magic == XFS_DIR3_LEAFN_MAGIC); -} - -static void -xfs_dir3_leaf_hdr_to_disk( - struct xfs_dir2_leaf *to, - struct xfs_dir3_icleaf_hdr *from) -{ - struct xfs_dir3_leaf_hdr *hdr3 = (struct xfs_dir3_leaf_hdr *)to; - - ASSERT(from->magic == XFS_DIR3_LEAF1_MAGIC || - from->magic == XFS_DIR3_LEAFN_MAGIC); - - hdr3->info.hdr.forw = cpu_to_be32(from->forw); - hdr3->info.hdr.back = cpu_to_be32(from->back); - hdr3->info.hdr.magic = cpu_to_be16(from->magic); - hdr3->count = cpu_to_be16(from->count); - hdr3->stale = cpu_to_be16(from->stale); -} - - -/* - * Directory/Attribute Node block operations - */ -static struct xfs_da_node_entry * -xfs_da2_node_tree_p(struct xfs_da_intnode *dap) -{ - return dap->__btree; -} - -static struct xfs_da_node_entry * -xfs_da3_node_tree_p(struct xfs_da_intnode *dap) -{ - return ((struct xfs_da3_intnode *)dap)->__btree; -} - -static void -xfs_da2_node_hdr_from_disk( - struct xfs_da3_icnode_hdr *to, - struct xfs_da_intnode *from) -{ - ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_DA_NODE_MAGIC)); - to->forw = be32_to_cpu(from->hdr.info.forw); - to->back = be32_to_cpu(from->hdr.info.back); - to->magic = be16_to_cpu(from->hdr.info.magic); - to->count = be16_to_cpu(from->hdr.__count); - to->level = be16_to_cpu(from->hdr.__level); -} - -static void -xfs_da2_node_hdr_to_disk( - struct xfs_da_intnode *to, - struct xfs_da3_icnode_hdr *from) -{ - ASSERT(from->magic == XFS_DA_NODE_MAGIC); - to->hdr.info.forw = cpu_to_be32(from->forw); - to->hdr.info.back = cpu_to_be32(from->back); - to->hdr.info.magic = cpu_to_be16(from->magic); - to->hdr.__count = cpu_to_be16(from->count); - to->hdr.__level = cpu_to_be16(from->level); -} - -static void -xfs_da3_node_hdr_from_disk( - struct xfs_da3_icnode_hdr *to, - struct xfs_da_intnode *from) -{ - struct xfs_da3_node_hdr *hdr3 = (struct xfs_da3_node_hdr *)from; - - ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_DA3_NODE_MAGIC)); - to->forw = be32_to_cpu(hdr3->info.hdr.forw); - to->back = be32_to_cpu(hdr3->info.hdr.back); - to->magic = be16_to_cpu(hdr3->info.hdr.magic); - to->count = be16_to_cpu(hdr3->__count); - to->level = be16_to_cpu(hdr3->__level); -} - -static void -xfs_da3_node_hdr_to_disk( - struct xfs_da_intnode *to, - struct xfs_da3_icnode_hdr *from) -{ - struct xfs_da3_node_hdr *hdr3 = (struct xfs_da3_node_hdr *)to; - - ASSERT(from->magic == XFS_DA3_NODE_MAGIC); - hdr3->info.hdr.forw = cpu_to_be32(from->forw); - hdr3->info.hdr.back = cpu_to_be32(from->back); - hdr3->info.hdr.magic = cpu_to_be16(from->magic); - hdr3->__count = cpu_to_be16(from->count); - hdr3->__level = cpu_to_be16(from->level); -} - - -/* - * Directory free space block operations - */ -static int -xfs_dir2_free_max_bests(struct xfs_da_geometry *geo) -{ - return (geo->blksize - sizeof(struct xfs_dir2_free_hdr)) / - sizeof(xfs_dir2_data_off_t); -} - -static __be16 * -xfs_dir2_free_bests_p(struct xfs_dir2_free *free) -{ - return (__be16 *)((char *)free + sizeof(struct xfs_dir2_free_hdr)); -} - -/* - * Convert data space db to the corresponding free db. - */ -static xfs_dir2_db_t -xfs_dir2_db_to_fdb(struct xfs_da_geometry *geo, xfs_dir2_db_t db) -{ - return xfs_dir2_byte_to_db(geo, XFS_DIR2_FREE_OFFSET) + - (db / xfs_dir2_free_max_bests(geo)); -} - -/* - * Convert data space db to the corresponding index in a free db. - */ -static int -xfs_dir2_db_to_fdindex(struct xfs_da_geometry *geo, xfs_dir2_db_t db) -{ - return db % xfs_dir2_free_max_bests(geo); -} - -static int -xfs_dir3_free_max_bests(struct xfs_da_geometry *geo) -{ - return (geo->blksize - sizeof(struct xfs_dir3_free_hdr)) / - sizeof(xfs_dir2_data_off_t); -} - -static __be16 * -xfs_dir3_free_bests_p(struct xfs_dir2_free *free) -{ - return (__be16 *)((char *)free + sizeof(struct xfs_dir3_free_hdr)); -} - -/* - * Convert data space db to the corresponding free db. - */ -static xfs_dir2_db_t -xfs_dir3_db_to_fdb(struct xfs_da_geometry *geo, xfs_dir2_db_t db) -{ - return xfs_dir2_byte_to_db(geo, XFS_DIR2_FREE_OFFSET) + - (db / xfs_dir3_free_max_bests(geo)); -} - -/* - * Convert data space db to the corresponding index in a free db. - */ -static int -xfs_dir3_db_to_fdindex(struct xfs_da_geometry *geo, xfs_dir2_db_t db) -{ - return db % xfs_dir3_free_max_bests(geo); -} - -static void -xfs_dir2_free_hdr_from_disk( - struct xfs_dir3_icfree_hdr *to, - struct xfs_dir2_free *from) -{ - to->magic = be32_to_cpu(from->hdr.magic); - to->firstdb = be32_to_cpu(from->hdr.firstdb); - to->nvalid = be32_to_cpu(from->hdr.nvalid); - to->nused = be32_to_cpu(from->hdr.nused); - ASSERT(to->magic == XFS_DIR2_FREE_MAGIC); -} - -static void -xfs_dir2_free_hdr_to_disk( - struct xfs_dir2_free *to, - struct xfs_dir3_icfree_hdr *from) -{ - ASSERT(from->magic == XFS_DIR2_FREE_MAGIC); - - to->hdr.magic = cpu_to_be32(from->magic); - to->hdr.firstdb = cpu_to_be32(from->firstdb); - to->hdr.nvalid = cpu_to_be32(from->nvalid); - to->hdr.nused = cpu_to_be32(from->nused); -} - -static void -xfs_dir3_free_hdr_from_disk( - struct xfs_dir3_icfree_hdr *to, - struct xfs_dir2_free *from) -{ - struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)from; - - to->magic = be32_to_cpu(hdr3->hdr.magic); - to->firstdb = be32_to_cpu(hdr3->firstdb); - to->nvalid = be32_to_cpu(hdr3->nvalid); - to->nused = be32_to_cpu(hdr3->nused); - - ASSERT(to->magic == XFS_DIR3_FREE_MAGIC); -} - -static void -xfs_dir3_free_hdr_to_disk( - struct xfs_dir2_free *to, - struct xfs_dir3_icfree_hdr *from) -{ - struct xfs_dir3_free_hdr *hdr3 = (struct xfs_dir3_free_hdr *)to; - - ASSERT(from->magic == XFS_DIR3_FREE_MAGIC); - - hdr3->hdr.magic = cpu_to_be32(from->magic); - hdr3->firstdb = cpu_to_be32(from->firstdb); - hdr3->nvalid = cpu_to_be32(from->nvalid); - hdr3->nused = cpu_to_be32(from->nused); -} - -static const struct xfs_dir_ops xfs_dir2_ops = { - .sf_entsize = xfs_dir2_sf_entsize, - .sf_nextentry = xfs_dir2_sf_nextentry, - .sf_get_ftype = xfs_dir2_sfe_get_ftype, - .sf_put_ftype = xfs_dir2_sfe_put_ftype, - .sf_get_ino = xfs_dir2_sfe_get_ino, - .sf_put_ino = xfs_dir2_sfe_put_ino, - .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino, - .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino, - - .data_entsize = xfs_dir2_data_entsize, - .data_get_ftype = xfs_dir2_data_get_ftype, - .data_put_ftype = xfs_dir2_data_put_ftype, - .data_entry_tag_p = xfs_dir2_data_entry_tag_p, - .data_bestfree_p = xfs_dir2_data_bestfree_p, - - .data_dot_offset = sizeof(struct xfs_dir2_data_hdr), - .data_dotdot_offset = sizeof(struct xfs_dir2_data_hdr) + - XFS_DIR2_DATA_ENTSIZE(1), - .data_first_offset = sizeof(struct xfs_dir2_data_hdr) + - XFS_DIR2_DATA_ENTSIZE(1) + - XFS_DIR2_DATA_ENTSIZE(2), - .data_entry_offset = sizeof(struct xfs_dir2_data_hdr), - - .data_dot_entry_p = xfs_dir2_data_dot_entry_p, - .data_dotdot_entry_p = xfs_dir2_data_dotdot_entry_p, - .data_first_entry_p = xfs_dir2_data_first_entry_p, - .data_entry_p = xfs_dir2_data_entry_p, - .data_unused_p = xfs_dir2_data_unused_p, - - .leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr), - .leaf_hdr_to_disk = xfs_dir2_leaf_hdr_to_disk, - .leaf_hdr_from_disk = xfs_dir2_leaf_hdr_from_disk, - .leaf_max_ents = xfs_dir2_max_leaf_ents, - .leaf_ents_p = xfs_dir2_leaf_ents_p, - - .node_hdr_size = sizeof(struct xfs_da_node_hdr), - .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, - .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, - .node_tree_p = xfs_da2_node_tree_p, - - .free_hdr_size = sizeof(struct xfs_dir2_free_hdr), - .free_hdr_to_disk = xfs_dir2_free_hdr_to_disk, - .free_hdr_from_disk = xfs_dir2_free_hdr_from_disk, - .free_max_bests = xfs_dir2_free_max_bests, - .free_bests_p = xfs_dir2_free_bests_p, - .db_to_fdb = xfs_dir2_db_to_fdb, - .db_to_fdindex = xfs_dir2_db_to_fdindex, -}; - -static const struct xfs_dir_ops xfs_dir2_ftype_ops = { - .sf_entsize = xfs_dir3_sf_entsize, - .sf_nextentry = xfs_dir3_sf_nextentry, - .sf_get_ftype = xfs_dir3_sfe_get_ftype, - .sf_put_ftype = xfs_dir3_sfe_put_ftype, - .sf_get_ino = xfs_dir3_sfe_get_ino, - .sf_put_ino = xfs_dir3_sfe_put_ino, - .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino, - .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino, - - .data_entsize = xfs_dir3_data_entsize, - .data_get_ftype = xfs_dir3_data_get_ftype, - .data_put_ftype = xfs_dir3_data_put_ftype, - .data_entry_tag_p = xfs_dir3_data_entry_tag_p, - .data_bestfree_p = xfs_dir2_data_bestfree_p, - - .data_dot_offset = sizeof(struct xfs_dir2_data_hdr), - .data_dotdot_offset = sizeof(struct xfs_dir2_data_hdr) + - XFS_DIR3_DATA_ENTSIZE(1), - .data_first_offset = sizeof(struct xfs_dir2_data_hdr) + - XFS_DIR3_DATA_ENTSIZE(1) + - XFS_DIR3_DATA_ENTSIZE(2), - .data_entry_offset = sizeof(struct xfs_dir2_data_hdr), - - .data_dot_entry_p = xfs_dir2_data_dot_entry_p, - .data_dotdot_entry_p = xfs_dir2_ftype_data_dotdot_entry_p, - .data_first_entry_p = xfs_dir2_ftype_data_first_entry_p, - .data_entry_p = xfs_dir2_data_entry_p, - .data_unused_p = xfs_dir2_data_unused_p, - - .leaf_hdr_size = sizeof(struct xfs_dir2_leaf_hdr), - .leaf_hdr_to_disk = xfs_dir2_leaf_hdr_to_disk, - .leaf_hdr_from_disk = xfs_dir2_leaf_hdr_from_disk, - .leaf_max_ents = xfs_dir2_max_leaf_ents, - .leaf_ents_p = xfs_dir2_leaf_ents_p, - - .node_hdr_size = sizeof(struct xfs_da_node_hdr), - .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, - .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, - .node_tree_p = xfs_da2_node_tree_p, - - .free_hdr_size = sizeof(struct xfs_dir2_free_hdr), - .free_hdr_to_disk = xfs_dir2_free_hdr_to_disk, - .free_hdr_from_disk = xfs_dir2_free_hdr_from_disk, - .free_max_bests = xfs_dir2_free_max_bests, - .free_bests_p = xfs_dir2_free_bests_p, - .db_to_fdb = xfs_dir2_db_to_fdb, - .db_to_fdindex = xfs_dir2_db_to_fdindex, -}; - -static const struct xfs_dir_ops xfs_dir3_ops = { - .sf_entsize = xfs_dir3_sf_entsize, - .sf_nextentry = xfs_dir3_sf_nextentry, - .sf_get_ftype = xfs_dir3_sfe_get_ftype, - .sf_put_ftype = xfs_dir3_sfe_put_ftype, - .sf_get_ino = xfs_dir3_sfe_get_ino, - .sf_put_ino = xfs_dir3_sfe_put_ino, - .sf_get_parent_ino = xfs_dir2_sf_get_parent_ino, - .sf_put_parent_ino = xfs_dir2_sf_put_parent_ino, - - .data_entsize = xfs_dir3_data_entsize, - .data_get_ftype = xfs_dir3_data_get_ftype, - .data_put_ftype = xfs_dir3_data_put_ftype, - .data_entry_tag_p = xfs_dir3_data_entry_tag_p, - .data_bestfree_p = xfs_dir3_data_bestfree_p, - - .data_dot_offset = sizeof(struct xfs_dir3_data_hdr), - .data_dotdot_offset = sizeof(struct xfs_dir3_data_hdr) + - XFS_DIR3_DATA_ENTSIZE(1), - .data_first_offset = sizeof(struct xfs_dir3_data_hdr) + - XFS_DIR3_DATA_ENTSIZE(1) + - XFS_DIR3_DATA_ENTSIZE(2), - .data_entry_offset = sizeof(struct xfs_dir3_data_hdr), - - .data_dot_entry_p = xfs_dir3_data_dot_entry_p, - .data_dotdot_entry_p = xfs_dir3_data_dotdot_entry_p, - .data_first_entry_p = xfs_dir3_data_first_entry_p, - .data_entry_p = xfs_dir3_data_entry_p, - .data_unused_p = xfs_dir3_data_unused_p, - - .leaf_hdr_size = sizeof(struct xfs_dir3_leaf_hdr), - .leaf_hdr_to_disk = xfs_dir3_leaf_hdr_to_disk, - .leaf_hdr_from_disk = xfs_dir3_leaf_hdr_from_disk, - .leaf_max_ents = xfs_dir3_max_leaf_ents, - .leaf_ents_p = xfs_dir3_leaf_ents_p, - - .node_hdr_size = sizeof(struct xfs_da3_node_hdr), - .node_hdr_to_disk = xfs_da3_node_hdr_to_disk, - .node_hdr_from_disk = xfs_da3_node_hdr_from_disk, - .node_tree_p = xfs_da3_node_tree_p, - - .free_hdr_size = sizeof(struct xfs_dir3_free_hdr), - .free_hdr_to_disk = xfs_dir3_free_hdr_to_disk, - .free_hdr_from_disk = xfs_dir3_free_hdr_from_disk, - .free_max_bests = xfs_dir3_free_max_bests, - .free_bests_p = xfs_dir3_free_bests_p, - .db_to_fdb = xfs_dir3_db_to_fdb, - .db_to_fdindex = xfs_dir3_db_to_fdindex, -}; - -static const struct xfs_dir_ops xfs_dir2_nondir_ops = { - .node_hdr_size = sizeof(struct xfs_da_node_hdr), - .node_hdr_to_disk = xfs_da2_node_hdr_to_disk, - .node_hdr_from_disk = xfs_da2_node_hdr_from_disk, - .node_tree_p = xfs_da2_node_tree_p, -}; - -static const struct xfs_dir_ops xfs_dir3_nondir_ops = { - .node_hdr_size = sizeof(struct xfs_da3_node_hdr), - .node_hdr_to_disk = xfs_da3_node_hdr_to_disk, - .node_hdr_from_disk = xfs_da3_node_hdr_from_disk, - .node_tree_p = xfs_da3_node_tree_p, -}; - -/* - * Return the ops structure according to the current config. If we are passed - * an inode, then that overrides the default config we use which is based on - * feature bits. - */ -const struct xfs_dir_ops * -xfs_dir_get_ops( - struct xfs_mount *mp, - struct xfs_inode *dp) -{ - if (dp) - return dp->d_ops; - if (mp->m_dir_inode_ops) - return mp->m_dir_inode_ops; - if (xfs_sb_version_hascrc(&mp->m_sb)) - return &xfs_dir3_ops; - if (xfs_sb_version_hasftype(&mp->m_sb)) - return &xfs_dir2_ftype_ops; - return &xfs_dir2_ops; -} - -const struct xfs_dir_ops * -xfs_nondir_get_ops( - struct xfs_mount *mp, - struct xfs_inode *dp) -{ - if (dp) - return dp->d_ops; - if (mp->m_nondir_inode_ops) - return mp->m_nondir_inode_ops; - if (xfs_sb_version_hascrc(&mp->m_sb)) - return &xfs_dir3_nondir_ops; - return &xfs_dir2_nondir_ops; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_da_format.h b/src/linux/fs/xfs/libxfs/xfs_da_format.h deleted file mode 100644 index 9a492a9..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_da_format.h +++ /dev/null @@ -1,878 +0,0 @@ -/* - * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. - * Copyright (c) 2013 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_DA_FORMAT_H__ -#define __XFS_DA_FORMAT_H__ - -/* - * This structure is common to both leaf nodes and non-leaf nodes in the Btree. - * - * It is used to manage a doubly linked list of all blocks at the same - * level in the Btree, and to identify which type of block this is. - */ -#define XFS_DA_NODE_MAGIC 0xfebe /* magic number: non-leaf blocks */ -#define XFS_ATTR_LEAF_MAGIC 0xfbee /* magic number: attribute leaf blks */ -#define XFS_DIR2_LEAF1_MAGIC 0xd2f1 /* magic number: v2 dirlf single blks */ -#define XFS_DIR2_LEAFN_MAGIC 0xd2ff /* magic number: v2 dirlf multi blks */ - -typedef struct xfs_da_blkinfo { - __be32 forw; /* previous block in list */ - __be32 back; /* following block in list */ - __be16 magic; /* validity check on block */ - __be16 pad; /* unused */ -} xfs_da_blkinfo_t; - -/* - * CRC enabled directory structure types - * - * The headers change size for the additional verification information, but - * otherwise the tree layouts and contents are unchanged. Hence the da btree - * code can use the struct xfs_da_blkinfo for manipulating the tree links and - * magic numbers without modification for both v2 and v3 nodes. - */ -#define XFS_DA3_NODE_MAGIC 0x3ebe /* magic number: non-leaf blocks */ -#define XFS_ATTR3_LEAF_MAGIC 0x3bee /* magic number: attribute leaf blks */ -#define XFS_DIR3_LEAF1_MAGIC 0x3df1 /* magic number: v2 dirlf single blks */ -#define XFS_DIR3_LEAFN_MAGIC 0x3dff /* magic number: v2 dirlf multi blks */ - -struct xfs_da3_blkinfo { - /* - * the node link manipulation code relies on the fact that the first - * element of this structure is the struct xfs_da_blkinfo so it can - * ignore the differences in the rest of the structures. - */ - struct xfs_da_blkinfo hdr; - __be32 crc; /* CRC of block */ - __be64 blkno; /* first block of the buffer */ - __be64 lsn; /* sequence number of last write */ - uuid_t uuid; /* filesystem we belong to */ - __be64 owner; /* inode that owns the block */ -}; - -/* - * This is the structure of the root and intermediate nodes in the Btree. - * The leaf nodes are defined above. - * - * Entries are not packed. - * - * Since we have duplicate keys, use a binary search but always follow - * all match in the block, not just the first match found. - */ -#define XFS_DA_NODE_MAXDEPTH 5 /* max depth of Btree */ - -typedef struct xfs_da_node_hdr { - struct xfs_da_blkinfo info; /* block type, links, etc. */ - __be16 __count; /* count of active entries */ - __be16 __level; /* level above leaves (leaf == 0) */ -} xfs_da_node_hdr_t; - -struct xfs_da3_node_hdr { - struct xfs_da3_blkinfo info; /* block type, links, etc. */ - __be16 __count; /* count of active entries */ - __be16 __level; /* level above leaves (leaf == 0) */ - __be32 __pad32; -}; - -#define XFS_DA3_NODE_CRC_OFF (offsetof(struct xfs_da3_node_hdr, info.crc)) - -typedef struct xfs_da_node_entry { - __be32 hashval; /* hash value for this descendant */ - __be32 before; /* Btree block before this key */ -} xfs_da_node_entry_t; - -typedef struct xfs_da_intnode { - struct xfs_da_node_hdr hdr; - struct xfs_da_node_entry __btree[]; -} xfs_da_intnode_t; - -struct xfs_da3_intnode { - struct xfs_da3_node_hdr hdr; - struct xfs_da_node_entry __btree[]; -}; - -/* - * In-core version of the node header to abstract the differences in the v2 and - * v3 disk format of the headers. Callers need to convert to/from disk format as - * appropriate. - */ -struct xfs_da3_icnode_hdr { - __uint32_t forw; - __uint32_t back; - __uint16_t magic; - __uint16_t count; - __uint16_t level; -}; - -/* - * Directory version 2. - * - * There are 4 possible formats: - * - shortform - embedded into the inode - * - single block - data with embedded leaf at the end - * - multiple data blocks, single leaf+freeindex block - * - data blocks, node and leaf blocks (btree), freeindex blocks - * - * Note: many node blocks structures and constants are shared with the attr - * code and defined in xfs_da_btree.h. - */ - -#define XFS_DIR2_BLOCK_MAGIC 0x58443242 /* XD2B: single block dirs */ -#define XFS_DIR2_DATA_MAGIC 0x58443244 /* XD2D: multiblock dirs */ -#define XFS_DIR2_FREE_MAGIC 0x58443246 /* XD2F: free index blocks */ - -/* - * Directory Version 3 With CRCs. - * - * The tree formats are the same as for version 2 directories. The difference - * is in the block header and dirent formats. In many cases the v3 structures - * use v2 definitions as they are no different and this makes code sharing much - * easier. - * - * Also, the xfs_dir3_*() functions handle both v2 and v3 formats - if the - * format is v2 then they switch to the existing v2 code, or the format is v3 - * they implement the v3 functionality. This means the existing dir2 is a mix of - * xfs_dir2/xfs_dir3 calls and functions. The xfs_dir3 functions are called - * where there is a difference in the formats, otherwise the code is unchanged. - * - * Where it is possible, the code decides what to do based on the magic numbers - * in the blocks rather than feature bits in the superblock. This means the code - * is as independent of the external XFS code as possible as doesn't require - * passing struct xfs_mount pointers into places where it isn't really - * necessary. - * - * Version 3 includes: - * - * - a larger block header for CRC and identification purposes and so the - * offsets of all the structures inside the blocks are different. - * - * - new magic numbers to be able to detect the v2/v3 types on the fly. - */ - -#define XFS_DIR3_BLOCK_MAGIC 0x58444233 /* XDB3: single block dirs */ -#define XFS_DIR3_DATA_MAGIC 0x58444433 /* XDD3: multiblock dirs */ -#define XFS_DIR3_FREE_MAGIC 0x58444633 /* XDF3: free index blocks */ - -/* - * Dirents in version 3 directories have a file type field. Additions to this - * list are an on-disk format change, requiring feature bits. Valid values - * are as follows: - */ -#define XFS_DIR3_FT_UNKNOWN 0 -#define XFS_DIR3_FT_REG_FILE 1 -#define XFS_DIR3_FT_DIR 2 -#define XFS_DIR3_FT_CHRDEV 3 -#define XFS_DIR3_FT_BLKDEV 4 -#define XFS_DIR3_FT_FIFO 5 -#define XFS_DIR3_FT_SOCK 6 -#define XFS_DIR3_FT_SYMLINK 7 -#define XFS_DIR3_FT_WHT 8 - -#define XFS_DIR3_FT_MAX 9 - -/* - * Byte offset in data block and shortform entry. - */ -typedef __uint16_t xfs_dir2_data_off_t; -#define NULLDATAOFF 0xffffU -typedef uint xfs_dir2_data_aoff_t; /* argument form */ - -/* - * Offset in data space of a data entry. - */ -typedef __uint32_t xfs_dir2_dataptr_t; -#define XFS_DIR2_MAX_DATAPTR ((xfs_dir2_dataptr_t)0xffffffff) -#define XFS_DIR2_NULL_DATAPTR ((xfs_dir2_dataptr_t)0) - -/* - * Byte offset in a directory. - */ -typedef xfs_off_t xfs_dir2_off_t; - -/* - * Directory block number (logical dirblk in file) - */ -typedef __uint32_t xfs_dir2_db_t; - -#define XFS_INO32_SIZE 4 -#define XFS_INO64_SIZE 8 -#define XFS_INO64_DIFF (XFS_INO64_SIZE - XFS_INO32_SIZE) - -#define XFS_DIR2_MAX_SHORT_INUM ((xfs_ino_t)0xffffffffULL) - -/* - * Directory layout when stored internal to an inode. - * - * Small directories are packed as tightly as possible so as to fit into the - * literal area of the inode. These "shortform" directories consist of a - * single xfs_dir2_sf_hdr header followed by zero or more xfs_dir2_sf_entry - * structures. Due the different inode number storage size and the variable - * length name field in the xfs_dir2_sf_entry all these structure are - * variable length, and the accessors in this file should be used to iterate - * over them. - */ -typedef struct xfs_dir2_sf_hdr { - __uint8_t count; /* count of entries */ - __uint8_t i8count; /* count of 8-byte inode #s */ - __uint8_t parent[8]; /* parent dir inode number */ -} __packed xfs_dir2_sf_hdr_t; - -typedef struct xfs_dir2_sf_entry { - __u8 namelen; /* actual name length */ - __u8 offset[2]; /* saved offset */ - __u8 name[]; /* name, variable size */ - /* - * A single byte containing the file type field follows the inode - * number for version 3 directory entries. - * - * A 64-bit or 32-bit inode number follows here, at a variable offset - * after the name. - */ -} xfs_dir2_sf_entry_t; - -static inline int xfs_dir2_sf_hdr_size(int i8count) -{ - return sizeof(struct xfs_dir2_sf_hdr) - - (i8count == 0) * XFS_INO64_DIFF; -} - -static inline xfs_dir2_data_aoff_t -xfs_dir2_sf_get_offset(xfs_dir2_sf_entry_t *sfep) -{ - return get_unaligned_be16(sfep->offset); -} - -static inline void -xfs_dir2_sf_put_offset(xfs_dir2_sf_entry_t *sfep, xfs_dir2_data_aoff_t off) -{ - put_unaligned_be16(off, sfep->offset); -} - -static inline struct xfs_dir2_sf_entry * -xfs_dir2_sf_firstentry(struct xfs_dir2_sf_hdr *hdr) -{ - return (struct xfs_dir2_sf_entry *) - ((char *)hdr + xfs_dir2_sf_hdr_size(hdr->i8count)); -} - -/* - * Data block structures. - * - * A pure data block looks like the following drawing on disk: - * - * +-------------------------------------------------+ - * | xfs_dir2_data_hdr_t | - * +-------------------------------------------------+ - * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | - * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | - * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | - * | ... | - * +-------------------------------------------------+ - * | unused space | - * +-------------------------------------------------+ - * - * As all the entries are variable size structures the accessors below should - * be used to iterate over them. - * - * In addition to the pure data blocks for the data and node formats, - * most structures are also used for the combined data/freespace "block" - * format below. - */ - -#define XFS_DIR2_DATA_ALIGN_LOG 3 /* i.e., 8 bytes */ -#define XFS_DIR2_DATA_ALIGN (1 << XFS_DIR2_DATA_ALIGN_LOG) -#define XFS_DIR2_DATA_FREE_TAG 0xffff -#define XFS_DIR2_DATA_FD_COUNT 3 - -/* - * Directory address space divided into sections, - * spaces separated by 32GB. - */ -#define XFS_DIR2_SPACE_SIZE (1ULL << (32 + XFS_DIR2_DATA_ALIGN_LOG)) -#define XFS_DIR2_DATA_SPACE 0 -#define XFS_DIR2_DATA_OFFSET (XFS_DIR2_DATA_SPACE * XFS_DIR2_SPACE_SIZE) - -/* - * Describe a free area in the data block. - * - * The freespace will be formatted as a xfs_dir2_data_unused_t. - */ -typedef struct xfs_dir2_data_free { - __be16 offset; /* start of freespace */ - __be16 length; /* length of freespace */ -} xfs_dir2_data_free_t; - -/* - * Header for the data blocks. - * - * The code knows that XFS_DIR2_DATA_FD_COUNT is 3. - */ -typedef struct xfs_dir2_data_hdr { - __be32 magic; /* XFS_DIR2_DATA_MAGIC or */ - /* XFS_DIR2_BLOCK_MAGIC */ - xfs_dir2_data_free_t bestfree[XFS_DIR2_DATA_FD_COUNT]; -} xfs_dir2_data_hdr_t; - -/* - * define a structure for all the verification fields we are adding to the - * directory block structures. This will be used in several structures. - * The magic number must be the first entry to align with all the dir2 - * structures so we determine how to decode them just by the magic number. - */ -struct xfs_dir3_blk_hdr { - __be32 magic; /* magic number */ - __be32 crc; /* CRC of block */ - __be64 blkno; /* first block of the buffer */ - __be64 lsn; /* sequence number of last write */ - uuid_t uuid; /* filesystem we belong to */ - __be64 owner; /* inode that owns the block */ -}; - -struct xfs_dir3_data_hdr { - struct xfs_dir3_blk_hdr hdr; - xfs_dir2_data_free_t best_free[XFS_DIR2_DATA_FD_COUNT]; - __be32 pad; /* 64 bit alignment */ -}; - -#define XFS_DIR3_DATA_CRC_OFF offsetof(struct xfs_dir3_data_hdr, hdr.crc) - -/* - * Active entry in a data block. - * - * Aligned to 8 bytes. After the variable length name field there is a - * 2 byte tag field, which can be accessed using xfs_dir3_data_entry_tag_p. - * - * For dir3 structures, there is file type field between the name and the tag. - * This can only be manipulated by helper functions. It is packed hard against - * the end of the name so any padding for rounding is between the file type and - * the tag. - */ -typedef struct xfs_dir2_data_entry { - __be64 inumber; /* inode number */ - __u8 namelen; /* name length */ - __u8 name[]; /* name bytes, no null */ - /* __u8 filetype; */ /* type of inode we point to */ - /* __be16 tag; */ /* starting offset of us */ -} xfs_dir2_data_entry_t; - -/* - * Unused entry in a data block. - * - * Aligned to 8 bytes. Tag appears as the last 2 bytes and must be accessed - * using xfs_dir2_data_unused_tag_p. - */ -typedef struct xfs_dir2_data_unused { - __be16 freetag; /* XFS_DIR2_DATA_FREE_TAG */ - __be16 length; /* total free length */ - /* variable offset */ - __be16 tag; /* starting offset of us */ -} xfs_dir2_data_unused_t; - -/* - * Pointer to a freespace's tag word. - */ -static inline __be16 * -xfs_dir2_data_unused_tag_p(struct xfs_dir2_data_unused *dup) -{ - return (__be16 *)((char *)dup + - be16_to_cpu(dup->length) - sizeof(__be16)); -} - -/* - * Leaf block structures. - * - * A pure leaf block looks like the following drawing on disk: - * - * +---------------------------+ - * | xfs_dir2_leaf_hdr_t | - * +---------------------------+ - * | xfs_dir2_leaf_entry_t | - * | xfs_dir2_leaf_entry_t | - * | xfs_dir2_leaf_entry_t | - * | xfs_dir2_leaf_entry_t | - * | ... | - * +---------------------------+ - * | xfs_dir2_data_off_t | - * | xfs_dir2_data_off_t | - * | xfs_dir2_data_off_t | - * | ... | - * +---------------------------+ - * | xfs_dir2_leaf_tail_t | - * +---------------------------+ - * - * The xfs_dir2_data_off_t members (bests) and tail are at the end of the block - * for single-leaf (magic = XFS_DIR2_LEAF1_MAGIC) blocks only, but not present - * for directories with separate leaf nodes and free space blocks - * (magic = XFS_DIR2_LEAFN_MAGIC). - * - * As all the entries are variable size structures the accessors below should - * be used to iterate over them. - */ - -/* - * Offset of the leaf/node space. First block in this space - * is the btree root. - */ -#define XFS_DIR2_LEAF_SPACE 1 -#define XFS_DIR2_LEAF_OFFSET (XFS_DIR2_LEAF_SPACE * XFS_DIR2_SPACE_SIZE) - -/* - * Leaf block header. - */ -typedef struct xfs_dir2_leaf_hdr { - xfs_da_blkinfo_t info; /* header for da routines */ - __be16 count; /* count of entries */ - __be16 stale; /* count of stale entries */ -} xfs_dir2_leaf_hdr_t; - -struct xfs_dir3_leaf_hdr { - struct xfs_da3_blkinfo info; /* header for da routines */ - __be16 count; /* count of entries */ - __be16 stale; /* count of stale entries */ - __be32 pad; /* 64 bit alignment */ -}; - -struct xfs_dir3_icleaf_hdr { - __uint32_t forw; - __uint32_t back; - __uint16_t magic; - __uint16_t count; - __uint16_t stale; -}; - -/* - * Leaf block entry. - */ -typedef struct xfs_dir2_leaf_entry { - __be32 hashval; /* hash value of name */ - __be32 address; /* address of data entry */ -} xfs_dir2_leaf_entry_t; - -/* - * Leaf block tail. - */ -typedef struct xfs_dir2_leaf_tail { - __be32 bestcount; -} xfs_dir2_leaf_tail_t; - -/* - * Leaf block. - */ -typedef struct xfs_dir2_leaf { - xfs_dir2_leaf_hdr_t hdr; /* leaf header */ - xfs_dir2_leaf_entry_t __ents[]; /* entries */ -} xfs_dir2_leaf_t; - -struct xfs_dir3_leaf { - struct xfs_dir3_leaf_hdr hdr; /* leaf header */ - struct xfs_dir2_leaf_entry __ents[]; /* entries */ -}; - -#define XFS_DIR3_LEAF_CRC_OFF offsetof(struct xfs_dir3_leaf_hdr, info.crc) - -/* - * Get address of the bests array in the single-leaf block. - */ -static inline __be16 * -xfs_dir2_leaf_bests_p(struct xfs_dir2_leaf_tail *ltp) -{ - return (__be16 *)ltp - be32_to_cpu(ltp->bestcount); -} - -/* - * Free space block defintions for the node format. - */ - -/* - * Offset of the freespace index. - */ -#define XFS_DIR2_FREE_SPACE 2 -#define XFS_DIR2_FREE_OFFSET (XFS_DIR2_FREE_SPACE * XFS_DIR2_SPACE_SIZE) - -typedef struct xfs_dir2_free_hdr { - __be32 magic; /* XFS_DIR2_FREE_MAGIC */ - __be32 firstdb; /* db of first entry */ - __be32 nvalid; /* count of valid entries */ - __be32 nused; /* count of used entries */ -} xfs_dir2_free_hdr_t; - -typedef struct xfs_dir2_free { - xfs_dir2_free_hdr_t hdr; /* block header */ - __be16 bests[]; /* best free counts */ - /* unused entries are -1 */ -} xfs_dir2_free_t; - -struct xfs_dir3_free_hdr { - struct xfs_dir3_blk_hdr hdr; - __be32 firstdb; /* db of first entry */ - __be32 nvalid; /* count of valid entries */ - __be32 nused; /* count of used entries */ - __be32 pad; /* 64 bit alignment */ -}; - -struct xfs_dir3_free { - struct xfs_dir3_free_hdr hdr; - __be16 bests[]; /* best free counts */ - /* unused entries are -1 */ -}; - -#define XFS_DIR3_FREE_CRC_OFF offsetof(struct xfs_dir3_free, hdr.hdr.crc) - -/* - * In core version of the free block header, abstracted away from on-disk format - * differences. Use this in the code, and convert to/from the disk version using - * xfs_dir3_free_hdr_from_disk/xfs_dir3_free_hdr_to_disk. - */ -struct xfs_dir3_icfree_hdr { - __uint32_t magic; - __uint32_t firstdb; - __uint32_t nvalid; - __uint32_t nused; - -}; - -/* - * Single block format. - * - * The single block format looks like the following drawing on disk: - * - * +-------------------------------------------------+ - * | xfs_dir2_data_hdr_t | - * +-------------------------------------------------+ - * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | - * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t | - * | xfs_dir2_data_entry_t OR xfs_dir2_data_unused_t : - * | ... | - * +-------------------------------------------------+ - * | unused space | - * +-------------------------------------------------+ - * | ... | - * | xfs_dir2_leaf_entry_t | - * | xfs_dir2_leaf_entry_t | - * +-------------------------------------------------+ - * | xfs_dir2_block_tail_t | - * +-------------------------------------------------+ - * - * As all the entries are variable size structures the accessors below should - * be used to iterate over them. - */ - -typedef struct xfs_dir2_block_tail { - __be32 count; /* count of leaf entries */ - __be32 stale; /* count of stale lf entries */ -} xfs_dir2_block_tail_t; - -/* - * Pointer to the leaf entries embedded in a data block (1-block format) - */ -static inline struct xfs_dir2_leaf_entry * -xfs_dir2_block_leaf_p(struct xfs_dir2_block_tail *btp) -{ - return ((struct xfs_dir2_leaf_entry *)btp) - be32_to_cpu(btp->count); -} - - -/* - * Attribute storage layout - * - * Attribute lists are structured around Btrees where all the data - * elements are in the leaf nodes. Attribute names are hashed into an int, - * then that int is used as the index into the Btree. Since the hashval - * of an attribute name may not be unique, we may have duplicate keys. The - * internal links in the Btree are logical block offsets into the file. - * - * Struct leaf_entry's are packed from the top. Name/values grow from the - * bottom but are not packed. The freemap contains run-length-encoded entries - * for the free bytes after the leaf_entry's, but only the N largest such, - * smaller runs are dropped. When the freemap doesn't show enough space - * for an allocation, we compact the name/value area and try again. If we - * still don't have enough space, then we have to split the block. The - * name/value structs (both local and remote versions) must be 32bit aligned. - * - * Since we have duplicate hash keys, for each key that matches, compare - * the actual name string. The root and intermediate node search always - * takes the first-in-the-block key match found, so we should only have - * to work "forw"ard. If none matches, continue with the "forw"ard leaf - * nodes until the hash key changes or the attribute name is found. - * - * We store the fact that an attribute is a ROOT/USER/SECURE attribute in - * the leaf_entry. The namespaces are independent only because we also look - * at the namespace bit when we are looking for a matching attribute name. - * - * We also store an "incomplete" bit in the leaf_entry. It shows that an - * attribute is in the middle of being created and should not be shown to - * the user if we crash during the time that the bit is set. We clear the - * bit when we have finished setting up the attribute. We do this because - * we cannot create some large attributes inside a single transaction, and we - * need some indication that we weren't finished if we crash in the middle. - */ -#define XFS_ATTR_LEAF_MAPSIZE 3 /* how many freespace slots */ - -/* - * Entries are packed toward the top as tight as possible. - */ -typedef struct xfs_attr_shortform { - struct xfs_attr_sf_hdr { /* constant-structure header block */ - __be16 totsize; /* total bytes in shortform list */ - __u8 count; /* count of active entries */ - __u8 padding; - } hdr; - struct xfs_attr_sf_entry { - __uint8_t namelen; /* actual length of name (no NULL) */ - __uint8_t valuelen; /* actual length of value (no NULL) */ - __uint8_t flags; /* flags bits (see xfs_attr_leaf.h) */ - __uint8_t nameval[1]; /* name & value bytes concatenated */ - } list[1]; /* variable sized array */ -} xfs_attr_shortform_t; - -typedef struct xfs_attr_leaf_map { /* RLE map of free bytes */ - __be16 base; /* base of free region */ - __be16 size; /* length of free region */ -} xfs_attr_leaf_map_t; - -typedef struct xfs_attr_leaf_hdr { /* constant-structure header block */ - xfs_da_blkinfo_t info; /* block type, links, etc. */ - __be16 count; /* count of active leaf_entry's */ - __be16 usedbytes; /* num bytes of names/values stored */ - __be16 firstused; /* first used byte in name area */ - __u8 holes; /* != 0 if blk needs compaction */ - __u8 pad1; - xfs_attr_leaf_map_t freemap[XFS_ATTR_LEAF_MAPSIZE]; - /* N largest free regions */ -} xfs_attr_leaf_hdr_t; - -typedef struct xfs_attr_leaf_entry { /* sorted on key, not name */ - __be32 hashval; /* hash value of name */ - __be16 nameidx; /* index into buffer of name/value */ - __u8 flags; /* LOCAL/ROOT/SECURE/INCOMPLETE flag */ - __u8 pad2; /* unused pad byte */ -} xfs_attr_leaf_entry_t; - -typedef struct xfs_attr_leaf_name_local { - __be16 valuelen; /* number of bytes in value */ - __u8 namelen; /* length of name bytes */ - __u8 nameval[1]; /* name/value bytes */ -} xfs_attr_leaf_name_local_t; - -typedef struct xfs_attr_leaf_name_remote { - __be32 valueblk; /* block number of value bytes */ - __be32 valuelen; /* number of bytes in value */ - __u8 namelen; /* length of name bytes */ - __u8 name[1]; /* name bytes */ -} xfs_attr_leaf_name_remote_t; - -typedef struct xfs_attr_leafblock { - xfs_attr_leaf_hdr_t hdr; /* constant-structure header block */ - xfs_attr_leaf_entry_t entries[1]; /* sorted on key, not name */ - /* - * The rest of the block contains the following structures after the - * leaf entries, growing from the bottom up. The variables are never - * referenced and definining them can actually make gcc optimize away - * accesses to the 'entries' array above index 0 so don't do that. - * - * xfs_attr_leaf_name_local_t namelist; - * xfs_attr_leaf_name_remote_t valuelist; - */ -} xfs_attr_leafblock_t; - -/* - * CRC enabled leaf structures. Called "version 3" structures to match the - * version number of the directory and dablk structures for this feature, and - * attr2 is already taken by the variable inode attribute fork size feature. - */ -struct xfs_attr3_leaf_hdr { - struct xfs_da3_blkinfo info; - __be16 count; - __be16 usedbytes; - __be16 firstused; - __u8 holes; - __u8 pad1; - struct xfs_attr_leaf_map freemap[XFS_ATTR_LEAF_MAPSIZE]; - __be32 pad2; /* 64 bit alignment */ -}; - -#define XFS_ATTR3_LEAF_CRC_OFF (offsetof(struct xfs_attr3_leaf_hdr, info.crc)) - -struct xfs_attr3_leafblock { - struct xfs_attr3_leaf_hdr hdr; - struct xfs_attr_leaf_entry entries[1]; - - /* - * The rest of the block contains the following structures after the - * leaf entries, growing from the bottom up. The variables are never - * referenced, the locations accessed purely from helper functions. - * - * struct xfs_attr_leaf_name_local - * struct xfs_attr_leaf_name_remote - */ -}; - -/* - * incore, neutral version of the attribute leaf header - */ -struct xfs_attr3_icleaf_hdr { - __uint32_t forw; - __uint32_t back; - __uint16_t magic; - __uint16_t count; - __uint16_t usedbytes; - /* - * firstused is 32-bit here instead of 16-bit like the on-disk variant - * to support maximum fsb size of 64k without overflow issues throughout - * the attr code. Instead, the overflow condition is handled on - * conversion to/from disk. - */ - __uint32_t firstused; - __u8 holes; - struct { - __uint16_t base; - __uint16_t size; - } freemap[XFS_ATTR_LEAF_MAPSIZE]; -}; - -/* - * Special value to represent fs block size in the leaf header firstused field. - * Only used when block size overflows the 2-bytes available on disk. - */ -#define XFS_ATTR3_LEAF_NULLOFF 0 - -/* - * Flags used in the leaf_entry[i].flags field. - * NOTE: the INCOMPLETE bit must not collide with the flags bits specified - * on the system call, they are "or"ed together for various operations. - */ -#define XFS_ATTR_LOCAL_BIT 0 /* attr is stored locally */ -#define XFS_ATTR_ROOT_BIT 1 /* limit access to trusted attrs */ -#define XFS_ATTR_SECURE_BIT 2 /* limit access to secure attrs */ -#define XFS_ATTR_INCOMPLETE_BIT 7 /* attr in middle of create/delete */ -#define XFS_ATTR_LOCAL (1 << XFS_ATTR_LOCAL_BIT) -#define XFS_ATTR_ROOT (1 << XFS_ATTR_ROOT_BIT) -#define XFS_ATTR_SECURE (1 << XFS_ATTR_SECURE_BIT) -#define XFS_ATTR_INCOMPLETE (1 << XFS_ATTR_INCOMPLETE_BIT) - -/* - * Conversion macros for converting namespace bits from argument flags - * to ondisk flags. - */ -#define XFS_ATTR_NSP_ARGS_MASK (ATTR_ROOT | ATTR_SECURE) -#define XFS_ATTR_NSP_ONDISK_MASK (XFS_ATTR_ROOT | XFS_ATTR_SECURE) -#define XFS_ATTR_NSP_ONDISK(flags) ((flags) & XFS_ATTR_NSP_ONDISK_MASK) -#define XFS_ATTR_NSP_ARGS(flags) ((flags) & XFS_ATTR_NSP_ARGS_MASK) -#define XFS_ATTR_NSP_ARGS_TO_ONDISK(x) (((x) & ATTR_ROOT ? XFS_ATTR_ROOT : 0) |\ - ((x) & ATTR_SECURE ? XFS_ATTR_SECURE : 0)) -#define XFS_ATTR_NSP_ONDISK_TO_ARGS(x) (((x) & XFS_ATTR_ROOT ? ATTR_ROOT : 0) |\ - ((x) & XFS_ATTR_SECURE ? ATTR_SECURE : 0)) - -/* - * Alignment for namelist and valuelist entries (since they are mixed - * there can be only one alignment value) - */ -#define XFS_ATTR_LEAF_NAME_ALIGN ((uint)sizeof(xfs_dablk_t)) - -static inline int -xfs_attr3_leaf_hdr_size(struct xfs_attr_leafblock *leafp) -{ - if (leafp->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)) - return sizeof(struct xfs_attr3_leaf_hdr); - return sizeof(struct xfs_attr_leaf_hdr); -} - -static inline struct xfs_attr_leaf_entry * -xfs_attr3_leaf_entryp(xfs_attr_leafblock_t *leafp) -{ - if (leafp->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)) - return &((struct xfs_attr3_leafblock *)leafp)->entries[0]; - return &leafp->entries[0]; -} - -/* - * Cast typed pointers for "local" and "remote" name/value structs. - */ -static inline char * -xfs_attr3_leaf_name(xfs_attr_leafblock_t *leafp, int idx) -{ - struct xfs_attr_leaf_entry *entries = xfs_attr3_leaf_entryp(leafp); - - return &((char *)leafp)[be16_to_cpu(entries[idx].nameidx)]; -} - -static inline xfs_attr_leaf_name_remote_t * -xfs_attr3_leaf_name_remote(xfs_attr_leafblock_t *leafp, int idx) -{ - return (xfs_attr_leaf_name_remote_t *)xfs_attr3_leaf_name(leafp, idx); -} - -static inline xfs_attr_leaf_name_local_t * -xfs_attr3_leaf_name_local(xfs_attr_leafblock_t *leafp, int idx) -{ - return (xfs_attr_leaf_name_local_t *)xfs_attr3_leaf_name(leafp, idx); -} - -/* - * Calculate total bytes used (including trailing pad for alignment) for - * a "local" name/value structure, a "remote" name/value structure, and - * a pointer which might be either. - */ -static inline int xfs_attr_leaf_entsize_remote(int nlen) -{ - return ((uint)sizeof(xfs_attr_leaf_name_remote_t) - 1 + (nlen) + \ - XFS_ATTR_LEAF_NAME_ALIGN - 1) & ~(XFS_ATTR_LEAF_NAME_ALIGN - 1); -} - -static inline int xfs_attr_leaf_entsize_local(int nlen, int vlen) -{ - return ((uint)sizeof(xfs_attr_leaf_name_local_t) - 1 + (nlen) + (vlen) + - XFS_ATTR_LEAF_NAME_ALIGN - 1) & ~(XFS_ATTR_LEAF_NAME_ALIGN - 1); -} - -static inline int xfs_attr_leaf_entsize_local_max(int bsize) -{ - return (((bsize) >> 1) + ((bsize) >> 2)); -} - - - -/* - * Remote attribute block format definition - * - * There is one of these headers per filesystem block in a remote attribute. - * This is done to ensure there is a 1:1 mapping between the attribute value - * length and the number of blocks needed to store the attribute. This makes the - * verification of a buffer a little more complex, but greatly simplifies the - * allocation, reading and writing of these attributes as we don't have to guess - * the number of blocks needed to store the attribute data. - */ -#define XFS_ATTR3_RMT_MAGIC 0x5841524d /* XARM */ - -struct xfs_attr3_rmt_hdr { - __be32 rm_magic; - __be32 rm_offset; - __be32 rm_bytes; - __be32 rm_crc; - uuid_t rm_uuid; - __be64 rm_owner; - __be64 rm_blkno; - __be64 rm_lsn; -}; - -#define XFS_ATTR3_RMT_CRC_OFF offsetof(struct xfs_attr3_rmt_hdr, rm_crc) - -#define XFS_ATTR3_RMT_BUF_SPACE(mp, bufsize) \ - ((bufsize) - (xfs_sb_version_hascrc(&(mp)->m_sb) ? \ - sizeof(struct xfs_attr3_rmt_hdr) : 0)) - -#endif /* __XFS_DA_FORMAT_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_defer.c b/src/linux/fs/xfs/libxfs/xfs_defer.c deleted file mode 100644 index 5c2929f..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_defer.c +++ /dev/null @@ -1,512 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_trans.h" -#include "xfs_trace.h" - -/* - * Deferred Operations in XFS - * - * Due to the way locking rules work in XFS, certain transactions (block - * mapping and unmapping, typically) have permanent reservations so that - * we can roll the transaction to adhere to AG locking order rules and - * to unlock buffers between metadata updates. Prior to rmap/reflink, - * the mapping code had a mechanism to perform these deferrals for - * extents that were going to be freed; this code makes that facility - * more generic. - * - * When adding the reverse mapping and reflink features, it became - * necessary to perform complex remapping multi-transactions to comply - * with AG locking order rules, and to be able to spread a single - * refcount update operation (an operation on an n-block extent can - * update as many as n records!) among multiple transactions. XFS can - * roll a transaction to facilitate this, but using this facility - * requires us to log "intent" items in case log recovery needs to - * redo the operation, and to log "done" items to indicate that redo - * is not necessary. - * - * Deferred work is tracked in xfs_defer_pending items. Each pending - * item tracks one type of deferred work. Incoming work items (which - * have not yet had an intent logged) are attached to a pending item - * on the dop_intake list, where they wait for the caller to finish - * the deferred operations. - * - * Finishing a set of deferred operations is an involved process. To - * start, we define "rolling a deferred-op transaction" as follows: - * - * > For each xfs_defer_pending item on the dop_intake list, - * - Sort the work items in AG order. XFS locking - * order rules require us to lock buffers in AG order. - * - Create a log intent item for that type. - * - Attach it to the pending item. - * - Move the pending item from the dop_intake list to the - * dop_pending list. - * > Roll the transaction. - * - * NOTE: To avoid exceeding the transaction reservation, we limit the - * number of items that we attach to a given xfs_defer_pending. - * - * The actual finishing process looks like this: - * - * > For each xfs_defer_pending in the dop_pending list, - * - Roll the deferred-op transaction as above. - * - Create a log done item for that type, and attach it to the - * log intent item. - * - For each work item attached to the log intent item, - * * Perform the described action. - * * Attach the work item to the log done item. - * * If the result of doing the work was -EAGAIN, ->finish work - * wants a new transaction. See the "Requesting a Fresh - * Transaction while Finishing Deferred Work" section below for - * details. - * - * The key here is that we must log an intent item for all pending - * work items every time we roll the transaction, and that we must log - * a done item as soon as the work is completed. With this mechanism - * we can perform complex remapping operations, chaining intent items - * as needed. - * - * Requesting a Fresh Transaction while Finishing Deferred Work - * - * If ->finish_item decides that it needs a fresh transaction to - * finish the work, it must ask its caller (xfs_defer_finish) for a - * continuation. The most likely cause of this circumstance are the - * refcount adjust functions deciding that they've logged enough items - * to be at risk of exceeding the transaction reservation. - * - * To get a fresh transaction, we want to log the existing log done - * item to prevent the log intent item from replaying, immediately log - * a new log intent item with the unfinished work items, roll the - * transaction, and re-call ->finish_item wherever it left off. The - * log done item and the new log intent item must be in the same - * transaction or atomicity cannot be guaranteed; defer_finish ensures - * that this happens. - * - * This requires some coordination between ->finish_item and - * defer_finish. Upon deciding to request a new transaction, - * ->finish_item should update the current work item to reflect the - * unfinished work. Next, it should reset the log done item's list - * count to the number of items finished, and return -EAGAIN. - * defer_finish sees the -EAGAIN, logs the new log intent item - * with the remaining work items, and leaves the xfs_defer_pending - * item at the head of the dop_work queue. Then it rolls the - * transaction and picks up processing where it left off. It is - * required that ->finish_item must be careful to leave enough - * transaction reservation to fit the new log intent item. - * - * This is an example of remapping the extent (E, E+B) into file X at - * offset A and dealing with the extent (C, C+B) already being mapped - * there: - * +-------------------------------------------------+ - * | Unmap file X startblock C offset A length B | t0 - * | Intent to reduce refcount for extent (C, B) | - * | Intent to remove rmap (X, C, A, B) | - * | Intent to free extent (D, 1) (bmbt block) | - * | Intent to map (X, A, B) at startblock E | - * +-------------------------------------------------+ - * | Map file X startblock E offset A length B | t1 - * | Done mapping (X, E, A, B) | - * | Intent to increase refcount for extent (E, B) | - * | Intent to add rmap (X, E, A, B) | - * +-------------------------------------------------+ - * | Reduce refcount for extent (C, B) | t2 - * | Done reducing refcount for extent (C, 9) | - * | Intent to reduce refcount for extent (C+9, B-9) | - * | (ran out of space after 9 refcount updates) | - * +-------------------------------------------------+ - * | Reduce refcount for extent (C+9, B+9) | t3 - * | Done reducing refcount for extent (C+9, B-9) | - * | Increase refcount for extent (E, B) | - * | Done increasing refcount for extent (E, B) | - * | Intent to free extent (C, B) | - * | Intent to free extent (F, 1) (refcountbt block) | - * | Intent to remove rmap (F, 1, REFC) | - * +-------------------------------------------------+ - * | Remove rmap (X, C, A, B) | t4 - * | Done removing rmap (X, C, A, B) | - * | Add rmap (X, E, A, B) | - * | Done adding rmap (X, E, A, B) | - * | Remove rmap (F, 1, REFC) | - * | Done removing rmap (F, 1, REFC) | - * +-------------------------------------------------+ - * | Free extent (C, B) | t5 - * | Done freeing extent (C, B) | - * | Free extent (D, 1) | - * | Done freeing extent (D, 1) | - * | Free extent (F, 1) | - * | Done freeing extent (F, 1) | - * +-------------------------------------------------+ - * - * If we should crash before t2 commits, log recovery replays - * the following intent items: - * - * - Intent to reduce refcount for extent (C, B) - * - Intent to remove rmap (X, C, A, B) - * - Intent to free extent (D, 1) (bmbt block) - * - Intent to increase refcount for extent (E, B) - * - Intent to add rmap (X, E, A, B) - * - * In the process of recovering, it should also generate and take care - * of these intent items: - * - * - Intent to free extent (C, B) - * - Intent to free extent (F, 1) (refcountbt block) - * - Intent to remove rmap (F, 1, REFC) - * - * Note that the continuation requested between t2 and t3 is likely to - * reoccur. - */ - -static const struct xfs_defer_op_type *defer_op_types[XFS_DEFER_OPS_TYPE_MAX]; - -/* - * For each pending item in the intake list, log its intent item and the - * associated extents, then add the entire intake list to the end of - * the pending list. - */ -STATIC void -xfs_defer_intake_work( - struct xfs_trans *tp, - struct xfs_defer_ops *dop) -{ - struct list_head *li; - struct xfs_defer_pending *dfp; - - list_for_each_entry(dfp, &dop->dop_intake, dfp_list) { - dfp->dfp_intent = dfp->dfp_type->create_intent(tp, - dfp->dfp_count); - trace_xfs_defer_intake_work(tp->t_mountp, dfp); - list_sort(tp->t_mountp, &dfp->dfp_work, - dfp->dfp_type->diff_items); - list_for_each(li, &dfp->dfp_work) - dfp->dfp_type->log_item(tp, dfp->dfp_intent, li); - } - - list_splice_tail_init(&dop->dop_intake, &dop->dop_pending); -} - -/* Abort all the intents that were committed. */ -STATIC void -xfs_defer_trans_abort( - struct xfs_trans *tp, - struct xfs_defer_ops *dop, - int error) -{ - struct xfs_defer_pending *dfp; - - trace_xfs_defer_trans_abort(tp->t_mountp, dop); - - /* Abort intent items that don't have a done item. */ - list_for_each_entry(dfp, &dop->dop_pending, dfp_list) { - trace_xfs_defer_pending_abort(tp->t_mountp, dfp); - if (dfp->dfp_intent && !dfp->dfp_done) { - dfp->dfp_type->abort_intent(dfp->dfp_intent); - dfp->dfp_intent = NULL; - } - } - - /* Shut down FS. */ - xfs_force_shutdown(tp->t_mountp, (error == -EFSCORRUPTED) ? - SHUTDOWN_CORRUPT_INCORE : SHUTDOWN_META_IO_ERROR); -} - -/* Roll a transaction so we can do some deferred op processing. */ -STATIC int -xfs_defer_trans_roll( - struct xfs_trans **tp, - struct xfs_defer_ops *dop, - struct xfs_inode *ip) -{ - int i; - int error; - - /* Log all the joined inodes except the one we passed in. */ - for (i = 0; i < XFS_DEFER_OPS_NR_INODES && dop->dop_inodes[i]; i++) { - if (dop->dop_inodes[i] == ip) - continue; - xfs_trans_log_inode(*tp, dop->dop_inodes[i], XFS_ILOG_CORE); - } - - trace_xfs_defer_trans_roll((*tp)->t_mountp, dop); - - /* Roll the transaction. */ - error = xfs_trans_roll(tp, ip); - if (error) { - trace_xfs_defer_trans_roll_error((*tp)->t_mountp, dop, error); - xfs_defer_trans_abort(*tp, dop, error); - return error; - } - dop->dop_committed = true; - - /* Rejoin the joined inodes except the one we passed in. */ - for (i = 0; i < XFS_DEFER_OPS_NR_INODES && dop->dop_inodes[i]; i++) { - if (dop->dop_inodes[i] == ip) - continue; - xfs_trans_ijoin(*tp, dop->dop_inodes[i], 0); - } - - return error; -} - -/* Do we have any work items to finish? */ -bool -xfs_defer_has_unfinished_work( - struct xfs_defer_ops *dop) -{ - return !list_empty(&dop->dop_pending) || !list_empty(&dop->dop_intake); -} - -/* - * Add this inode to the deferred op. Each joined inode is relogged - * each time we roll the transaction, in addition to any inode passed - * to xfs_defer_finish(). - */ -int -xfs_defer_join( - struct xfs_defer_ops *dop, - struct xfs_inode *ip) -{ - int i; - - for (i = 0; i < XFS_DEFER_OPS_NR_INODES; i++) { - if (dop->dop_inodes[i] == ip) - return 0; - else if (dop->dop_inodes[i] == NULL) { - dop->dop_inodes[i] = ip; - return 0; - } - } - - return -EFSCORRUPTED; -} - -/* - * Finish all the pending work. This involves logging intent items for - * any work items that wandered in since the last transaction roll (if - * one has even happened), rolling the transaction, and finishing the - * work items in the first item on the logged-and-pending list. - * - * If an inode is provided, relog it to the new transaction. - */ -int -xfs_defer_finish( - struct xfs_trans **tp, - struct xfs_defer_ops *dop, - struct xfs_inode *ip) -{ - struct xfs_defer_pending *dfp; - struct list_head *li; - struct list_head *n; - void *state; - int error = 0; - void (*cleanup_fn)(struct xfs_trans *, void *, int); - - ASSERT((*tp)->t_flags & XFS_TRANS_PERM_LOG_RES); - - trace_xfs_defer_finish((*tp)->t_mountp, dop); - - /* Until we run out of pending work to finish... */ - while (xfs_defer_has_unfinished_work(dop)) { - /* Log intents for work items sitting in the intake. */ - xfs_defer_intake_work(*tp, dop); - - /* Roll the transaction. */ - error = xfs_defer_trans_roll(tp, dop, ip); - if (error) - goto out; - - /* Log an intent-done item for the first pending item. */ - dfp = list_first_entry(&dop->dop_pending, - struct xfs_defer_pending, dfp_list); - trace_xfs_defer_pending_finish((*tp)->t_mountp, dfp); - dfp->dfp_done = dfp->dfp_type->create_done(*tp, dfp->dfp_intent, - dfp->dfp_count); - cleanup_fn = dfp->dfp_type->finish_cleanup; - - /* Finish the work items. */ - state = NULL; - list_for_each_safe(li, n, &dfp->dfp_work) { - list_del(li); - dfp->dfp_count--; - error = dfp->dfp_type->finish_item(*tp, dop, li, - dfp->dfp_done, &state); - if (error == -EAGAIN) { - /* - * Caller wants a fresh transaction; - * put the work item back on the list - * and jump out. - */ - list_add(li, &dfp->dfp_work); - dfp->dfp_count++; - break; - } else if (error) { - /* - * Clean up after ourselves and jump out. - * xfs_defer_cancel will take care of freeing - * all these lists and stuff. - */ - if (cleanup_fn) - cleanup_fn(*tp, state, error); - xfs_defer_trans_abort(*tp, dop, error); - goto out; - } - } - if (error == -EAGAIN) { - /* - * Caller wants a fresh transaction, so log a - * new log intent item to replace the old one - * and roll the transaction. See "Requesting - * a Fresh Transaction while Finishing - * Deferred Work" above. - */ - dfp->dfp_intent = dfp->dfp_type->create_intent(*tp, - dfp->dfp_count); - dfp->dfp_done = NULL; - list_for_each(li, &dfp->dfp_work) - dfp->dfp_type->log_item(*tp, dfp->dfp_intent, - li); - } else { - /* Done with the dfp, free it. */ - list_del(&dfp->dfp_list); - kmem_free(dfp); - } - - if (cleanup_fn) - cleanup_fn(*tp, state, error); - } - -out: - if (error) - trace_xfs_defer_finish_error((*tp)->t_mountp, dop, error); - else - trace_xfs_defer_finish_done((*tp)->t_mountp, dop); - return error; -} - -/* - * Free up any items left in the list. - */ -void -xfs_defer_cancel( - struct xfs_defer_ops *dop) -{ - struct xfs_defer_pending *dfp; - struct xfs_defer_pending *pli; - struct list_head *pwi; - struct list_head *n; - - trace_xfs_defer_cancel(NULL, dop); - - /* - * Free the pending items. Caller should already have arranged - * for the intent items to be released. - */ - list_for_each_entry_safe(dfp, pli, &dop->dop_intake, dfp_list) { - trace_xfs_defer_intake_cancel(NULL, dfp); - list_del(&dfp->dfp_list); - list_for_each_safe(pwi, n, &dfp->dfp_work) { - list_del(pwi); - dfp->dfp_count--; - dfp->dfp_type->cancel_item(pwi); - } - ASSERT(dfp->dfp_count == 0); - kmem_free(dfp); - } - list_for_each_entry_safe(dfp, pli, &dop->dop_pending, dfp_list) { - trace_xfs_defer_pending_cancel(NULL, dfp); - list_del(&dfp->dfp_list); - list_for_each_safe(pwi, n, &dfp->dfp_work) { - list_del(pwi); - dfp->dfp_count--; - dfp->dfp_type->cancel_item(pwi); - } - ASSERT(dfp->dfp_count == 0); - kmem_free(dfp); - } -} - -/* Add an item for later deferred processing. */ -void -xfs_defer_add( - struct xfs_defer_ops *dop, - enum xfs_defer_ops_type type, - struct list_head *li) -{ - struct xfs_defer_pending *dfp = NULL; - - /* - * Add the item to a pending item at the end of the intake list. - * If the last pending item has the same type, reuse it. Else, - * create a new pending item at the end of the intake list. - */ - if (!list_empty(&dop->dop_intake)) { - dfp = list_last_entry(&dop->dop_intake, - struct xfs_defer_pending, dfp_list); - if (dfp->dfp_type->type != type || - (dfp->dfp_type->max_items && - dfp->dfp_count >= dfp->dfp_type->max_items)) - dfp = NULL; - } - if (!dfp) { - dfp = kmem_alloc(sizeof(struct xfs_defer_pending), - KM_SLEEP | KM_NOFS); - dfp->dfp_type = defer_op_types[type]; - dfp->dfp_intent = NULL; - dfp->dfp_done = NULL; - dfp->dfp_count = 0; - INIT_LIST_HEAD(&dfp->dfp_work); - list_add_tail(&dfp->dfp_list, &dop->dop_intake); - } - - list_add_tail(li, &dfp->dfp_work); - dfp->dfp_count++; -} - -/* Initialize a deferred operation list. */ -void -xfs_defer_init_op_type( - const struct xfs_defer_op_type *type) -{ - defer_op_types[type->type] = type; -} - -/* Initialize a deferred operation. */ -void -xfs_defer_init( - struct xfs_defer_ops *dop, - xfs_fsblock_t *fbp) -{ - dop->dop_committed = false; - dop->dop_low = false; - memset(&dop->dop_inodes, 0, sizeof(dop->dop_inodes)); - *fbp = NULLFSBLOCK; - INIT_LIST_HEAD(&dop->dop_intake); - INIT_LIST_HEAD(&dop->dop_pending); - trace_xfs_defer_init(NULL, dop); -} diff --git a/src/linux/fs/xfs/libxfs/xfs_defer.h b/src/linux/fs/xfs/libxfs/xfs_defer.h deleted file mode 100644 index f6e93ef..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_defer.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#ifndef __XFS_DEFER_H__ -#define __XFS_DEFER_H__ - -struct xfs_defer_op_type; - -/* - * Save a log intent item and a list of extents, so that we can replay - * whatever action had to happen to the extent list and file the log done - * item. - */ -struct xfs_defer_pending { - const struct xfs_defer_op_type *dfp_type; /* function pointers */ - struct list_head dfp_list; /* pending items */ - void *dfp_intent; /* log intent item */ - void *dfp_done; /* log done item */ - struct list_head dfp_work; /* work items */ - unsigned int dfp_count; /* # extent items */ -}; - -/* - * Header for deferred operation list. - * - * dop_low is used by the allocator to activate the lowspace algorithm - - * when free space is running low the extent allocator may choose to - * allocate an extent from an AG without leaving sufficient space for - * a btree split when inserting the new extent. In this case the allocator - * will enable the lowspace algorithm which is supposed to allow further - * allocations (such as btree splits and newroots) to allocate from - * sequential AGs. In order to avoid locking AGs out of order the lowspace - * algorithm will start searching for free space from AG 0. If the correct - * transaction reservations have been made then this algorithm will eventually - * find all the space it needs. - */ -enum xfs_defer_ops_type { - XFS_DEFER_OPS_TYPE_BMAP, - XFS_DEFER_OPS_TYPE_REFCOUNT, - XFS_DEFER_OPS_TYPE_RMAP, - XFS_DEFER_OPS_TYPE_FREE, - XFS_DEFER_OPS_TYPE_MAX, -}; - -#define XFS_DEFER_OPS_NR_INODES 2 /* join up to two inodes */ - -struct xfs_defer_ops { - bool dop_committed; /* did any trans commit? */ - bool dop_low; /* alloc in low mode */ - struct list_head dop_intake; /* unlogged pending work */ - struct list_head dop_pending; /* logged pending work */ - - /* relog these inodes with each roll */ - struct xfs_inode *dop_inodes[XFS_DEFER_OPS_NR_INODES]; -}; - -void xfs_defer_add(struct xfs_defer_ops *dop, enum xfs_defer_ops_type type, - struct list_head *h); -int xfs_defer_finish(struct xfs_trans **tp, struct xfs_defer_ops *dop, - struct xfs_inode *ip); -void xfs_defer_cancel(struct xfs_defer_ops *dop); -void xfs_defer_init(struct xfs_defer_ops *dop, xfs_fsblock_t *fbp); -bool xfs_defer_has_unfinished_work(struct xfs_defer_ops *dop); -int xfs_defer_join(struct xfs_defer_ops *dop, struct xfs_inode *ip); - -/* Description of a deferred type. */ -struct xfs_defer_op_type { - enum xfs_defer_ops_type type; - unsigned int max_items; - void (*abort_intent)(void *); - void *(*create_done)(struct xfs_trans *, void *, unsigned int); - int (*finish_item)(struct xfs_trans *, struct xfs_defer_ops *, - struct list_head *, void *, void **); - void (*finish_cleanup)(struct xfs_trans *, void *, int); - void (*cancel_item)(struct list_head *); - int (*diff_items)(void *, struct list_head *, struct list_head *); - void *(*create_intent)(struct xfs_trans *, uint); - void (*log_item)(struct xfs_trans *, void *, struct list_head *); -}; - -void xfs_defer_init_op_type(const struct xfs_defer_op_type *type); - -#endif /* __XFS_DEFER_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_dir2.c b/src/linux/fs/xfs/libxfs/xfs_dir2.c deleted file mode 100644 index 20a96dd..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_dir2.c +++ /dev/null @@ -1,732 +0,0 @@ -/* - * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_bmap.h" -#include "xfs_dir2.h" -#include "xfs_dir2_priv.h" -#include "xfs_error.h" -#include "xfs_trace.h" - -struct xfs_name xfs_name_dotdot = { (unsigned char *)"..", 2, XFS_DIR3_FT_DIR }; - -/* - * @mode, if set, indicates that the type field needs to be set up. - * This uses the transformation from file mode to DT_* as defined in linux/fs.h - * for file type specification. This will be propagated into the directory - * structure if appropriate for the given operation and filesystem config. - */ -const unsigned char xfs_mode_to_ftype[S_IFMT >> S_SHIFT] = { - [0] = XFS_DIR3_FT_UNKNOWN, - [S_IFREG >> S_SHIFT] = XFS_DIR3_FT_REG_FILE, - [S_IFDIR >> S_SHIFT] = XFS_DIR3_FT_DIR, - [S_IFCHR >> S_SHIFT] = XFS_DIR3_FT_CHRDEV, - [S_IFBLK >> S_SHIFT] = XFS_DIR3_FT_BLKDEV, - [S_IFIFO >> S_SHIFT] = XFS_DIR3_FT_FIFO, - [S_IFSOCK >> S_SHIFT] = XFS_DIR3_FT_SOCK, - [S_IFLNK >> S_SHIFT] = XFS_DIR3_FT_SYMLINK, -}; - -/* - * ASCII case-insensitive (ie. A-Z) support for directories that was - * used in IRIX. - */ -STATIC xfs_dahash_t -xfs_ascii_ci_hashname( - struct xfs_name *name) -{ - xfs_dahash_t hash; - int i; - - for (i = 0, hash = 0; i < name->len; i++) - hash = tolower(name->name[i]) ^ rol32(hash, 7); - - return hash; -} - -STATIC enum xfs_dacmp -xfs_ascii_ci_compname( - struct xfs_da_args *args, - const unsigned char *name, - int len) -{ - enum xfs_dacmp result; - int i; - - if (args->namelen != len) - return XFS_CMP_DIFFERENT; - - result = XFS_CMP_EXACT; - for (i = 0; i < len; i++) { - if (args->name[i] == name[i]) - continue; - if (tolower(args->name[i]) != tolower(name[i])) - return XFS_CMP_DIFFERENT; - result = XFS_CMP_CASE; - } - - return result; -} - -static struct xfs_nameops xfs_ascii_ci_nameops = { - .hashname = xfs_ascii_ci_hashname, - .compname = xfs_ascii_ci_compname, -}; - -int -xfs_da_mount( - struct xfs_mount *mp) -{ - struct xfs_da_geometry *dageo; - int nodehdr_size; - - - ASSERT(mp->m_sb.sb_versionnum & XFS_SB_VERSION_DIRV2BIT); - ASSERT((1 << (mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog)) <= - XFS_MAX_BLOCKSIZE); - - mp->m_dir_inode_ops = xfs_dir_get_ops(mp, NULL); - mp->m_nondir_inode_ops = xfs_nondir_get_ops(mp, NULL); - - nodehdr_size = mp->m_dir_inode_ops->node_hdr_size; - mp->m_dir_geo = kmem_zalloc(sizeof(struct xfs_da_geometry), - KM_SLEEP | KM_MAYFAIL); - mp->m_attr_geo = kmem_zalloc(sizeof(struct xfs_da_geometry), - KM_SLEEP | KM_MAYFAIL); - if (!mp->m_dir_geo || !mp->m_attr_geo) { - kmem_free(mp->m_dir_geo); - kmem_free(mp->m_attr_geo); - return -ENOMEM; - } - - /* set up directory geometry */ - dageo = mp->m_dir_geo; - dageo->blklog = mp->m_sb.sb_blocklog + mp->m_sb.sb_dirblklog; - dageo->fsblog = mp->m_sb.sb_blocklog; - dageo->blksize = 1 << dageo->blklog; - dageo->fsbcount = 1 << mp->m_sb.sb_dirblklog; - - /* - * Now we've set up the block conversion variables, we can calculate the - * segment block constants using the geometry structure. - */ - dageo->datablk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_DATA_OFFSET); - dageo->leafblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_LEAF_OFFSET); - dageo->freeblk = xfs_dir2_byte_to_da(dageo, XFS_DIR2_FREE_OFFSET); - dageo->node_ents = (dageo->blksize - nodehdr_size) / - (uint)sizeof(xfs_da_node_entry_t); - dageo->magicpct = (dageo->blksize * 37) / 100; - - /* set up attribute geometry - single fsb only */ - dageo = mp->m_attr_geo; - dageo->blklog = mp->m_sb.sb_blocklog; - dageo->fsblog = mp->m_sb.sb_blocklog; - dageo->blksize = 1 << dageo->blklog; - dageo->fsbcount = 1; - dageo->node_ents = (dageo->blksize - nodehdr_size) / - (uint)sizeof(xfs_da_node_entry_t); - dageo->magicpct = (dageo->blksize * 37) / 100; - - if (xfs_sb_version_hasasciici(&mp->m_sb)) - mp->m_dirnameops = &xfs_ascii_ci_nameops; - else - mp->m_dirnameops = &xfs_default_nameops; - - return 0; -} - -void -xfs_da_unmount( - struct xfs_mount *mp) -{ - kmem_free(mp->m_dir_geo); - kmem_free(mp->m_attr_geo); -} - -/* - * Return 1 if directory contains only "." and "..". - */ -int -xfs_dir_isempty( - xfs_inode_t *dp) -{ - xfs_dir2_sf_hdr_t *sfp; - - ASSERT(S_ISDIR(VFS_I(dp)->i_mode)); - if (dp->i_d.di_size == 0) /* might happen during shutdown. */ - return 1; - if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp)) - return 0; - sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - return !sfp->count; -} - -/* - * Validate a given inode number. - */ -int -xfs_dir_ino_validate( - xfs_mount_t *mp, - xfs_ino_t ino) -{ - xfs_agblock_t agblkno; - xfs_agino_t agino; - xfs_agnumber_t agno; - int ino_ok; - int ioff; - - agno = XFS_INO_TO_AGNO(mp, ino); - agblkno = XFS_INO_TO_AGBNO(mp, ino); - ioff = XFS_INO_TO_OFFSET(mp, ino); - agino = XFS_OFFBNO_TO_AGINO(mp, agblkno, ioff); - ino_ok = - agno < mp->m_sb.sb_agcount && - agblkno < mp->m_sb.sb_agblocks && - agblkno != 0 && - ioff < (1 << mp->m_sb.sb_inopblog) && - XFS_AGINO_TO_INO(mp, agno, agino) == ino; - if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE, - XFS_RANDOM_DIR_INO_VALIDATE))) { - xfs_warn(mp, "Invalid inode number 0x%Lx", - (unsigned long long) ino); - XFS_ERROR_REPORT("xfs_dir_ino_validate", XFS_ERRLEVEL_LOW, mp); - return -EFSCORRUPTED; - } - return 0; -} - -/* - * Initialize a directory with its "." and ".." entries. - */ -int -xfs_dir_init( - xfs_trans_t *tp, - xfs_inode_t *dp, - xfs_inode_t *pdp) -{ - struct xfs_da_args *args; - int error; - - ASSERT(S_ISDIR(VFS_I(dp)->i_mode)); - error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino); - if (error) - return error; - - args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); - if (!args) - return -ENOMEM; - - args->geo = dp->i_mount->m_dir_geo; - args->dp = dp; - args->trans = tp; - error = xfs_dir2_sf_create(args, pdp->i_ino); - kmem_free(args); - return error; -} - -/* - * Enter a name in a directory, or check for available space. - * If inum is 0, only the available space test is performed. - */ -int -xfs_dir_createname( - xfs_trans_t *tp, - xfs_inode_t *dp, - struct xfs_name *name, - xfs_ino_t inum, /* new entry inode number */ - xfs_fsblock_t *first, /* bmap's firstblock */ - struct xfs_defer_ops *dfops, /* bmap's freeblock list */ - xfs_extlen_t total) /* bmap's total block count */ -{ - struct xfs_da_args *args; - int rval; - int v; /* type-checking value */ - - ASSERT(S_ISDIR(VFS_I(dp)->i_mode)); - if (inum) { - rval = xfs_dir_ino_validate(tp->t_mountp, inum); - if (rval) - return rval; - XFS_STATS_INC(dp->i_mount, xs_dir_create); - } - - args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); - if (!args) - return -ENOMEM; - - args->geo = dp->i_mount->m_dir_geo; - args->name = name->name; - args->namelen = name->len; - args->filetype = name->type; - args->hashval = dp->i_mount->m_dirnameops->hashname(name); - args->inumber = inum; - args->dp = dp; - args->firstblock = first; - args->dfops = dfops; - args->total = total; - args->whichfork = XFS_DATA_FORK; - args->trans = tp; - args->op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT; - if (!inum) - args->op_flags |= XFS_DA_OP_JUSTCHECK; - - if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { - rval = xfs_dir2_sf_addname(args); - goto out_free; - } - - rval = xfs_dir2_isblock(args, &v); - if (rval) - goto out_free; - if (v) { - rval = xfs_dir2_block_addname(args); - goto out_free; - } - - rval = xfs_dir2_isleaf(args, &v); - if (rval) - goto out_free; - if (v) - rval = xfs_dir2_leaf_addname(args); - else - rval = xfs_dir2_node_addname(args); - -out_free: - kmem_free(args); - return rval; -} - -/* - * If doing a CI lookup and case-insensitive match, dup actual name into - * args.value. Return EEXIST for success (ie. name found) or an error. - */ -int -xfs_dir_cilookup_result( - struct xfs_da_args *args, - const unsigned char *name, - int len) -{ - if (args->cmpresult == XFS_CMP_DIFFERENT) - return -ENOENT; - if (args->cmpresult != XFS_CMP_CASE || - !(args->op_flags & XFS_DA_OP_CILOOKUP)) - return -EEXIST; - - args->value = kmem_alloc(len, KM_NOFS | KM_MAYFAIL); - if (!args->value) - return -ENOMEM; - - memcpy(args->value, name, len); - args->valuelen = len; - return -EEXIST; -} - -/* - * Lookup a name in a directory, give back the inode number. - * If ci_name is not NULL, returns the actual name in ci_name if it differs - * to name, or ci_name->name is set to NULL for an exact match. - */ - -int -xfs_dir_lookup( - xfs_trans_t *tp, - xfs_inode_t *dp, - struct xfs_name *name, - xfs_ino_t *inum, /* out: inode number */ - struct xfs_name *ci_name) /* out: actual name if CI match */ -{ - struct xfs_da_args *args; - int rval; - int v; /* type-checking value */ - int lock_mode; - - ASSERT(S_ISDIR(VFS_I(dp)->i_mode)); - XFS_STATS_INC(dp->i_mount, xs_dir_lookup); - - /* - * We need to use KM_NOFS here so that lockdep will not throw false - * positive deadlock warnings on a non-transactional lookup path. It is - * safe to recurse into inode recalim in that case, but lockdep can't - * easily be taught about it. Hence KM_NOFS avoids having to add more - * lockdep Doing this avoids having to add a bunch of lockdep class - * annotations into the reclaim path for the ilock. - */ - args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); - args->geo = dp->i_mount->m_dir_geo; - args->name = name->name; - args->namelen = name->len; - args->filetype = name->type; - args->hashval = dp->i_mount->m_dirnameops->hashname(name); - args->dp = dp; - args->whichfork = XFS_DATA_FORK; - args->trans = tp; - args->op_flags = XFS_DA_OP_OKNOENT; - if (ci_name) - args->op_flags |= XFS_DA_OP_CILOOKUP; - - lock_mode = xfs_ilock_data_map_shared(dp); - if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { - rval = xfs_dir2_sf_lookup(args); - goto out_check_rval; - } - - rval = xfs_dir2_isblock(args, &v); - if (rval) - goto out_free; - if (v) { - rval = xfs_dir2_block_lookup(args); - goto out_check_rval; - } - - rval = xfs_dir2_isleaf(args, &v); - if (rval) - goto out_free; - if (v) - rval = xfs_dir2_leaf_lookup(args); - else - rval = xfs_dir2_node_lookup(args); - -out_check_rval: - if (rval == -EEXIST) - rval = 0; - if (!rval) { - *inum = args->inumber; - if (ci_name) { - ci_name->name = args->value; - ci_name->len = args->valuelen; - } - } -out_free: - xfs_iunlock(dp, lock_mode); - kmem_free(args); - return rval; -} - -/* - * Remove an entry from a directory. - */ -int -xfs_dir_removename( - xfs_trans_t *tp, - xfs_inode_t *dp, - struct xfs_name *name, - xfs_ino_t ino, - xfs_fsblock_t *first, /* bmap's firstblock */ - struct xfs_defer_ops *dfops, /* bmap's freeblock list */ - xfs_extlen_t total) /* bmap's total block count */ -{ - struct xfs_da_args *args; - int rval; - int v; /* type-checking value */ - - ASSERT(S_ISDIR(VFS_I(dp)->i_mode)); - XFS_STATS_INC(dp->i_mount, xs_dir_remove); - - args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); - if (!args) - return -ENOMEM; - - args->geo = dp->i_mount->m_dir_geo; - args->name = name->name; - args->namelen = name->len; - args->filetype = name->type; - args->hashval = dp->i_mount->m_dirnameops->hashname(name); - args->inumber = ino; - args->dp = dp; - args->firstblock = first; - args->dfops = dfops; - args->total = total; - args->whichfork = XFS_DATA_FORK; - args->trans = tp; - - if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { - rval = xfs_dir2_sf_removename(args); - goto out_free; - } - - rval = xfs_dir2_isblock(args, &v); - if (rval) - goto out_free; - if (v) { - rval = xfs_dir2_block_removename(args); - goto out_free; - } - - rval = xfs_dir2_isleaf(args, &v); - if (rval) - goto out_free; - if (v) - rval = xfs_dir2_leaf_removename(args); - else - rval = xfs_dir2_node_removename(args); -out_free: - kmem_free(args); - return rval; -} - -/* - * Replace the inode number of a directory entry. - */ -int -xfs_dir_replace( - xfs_trans_t *tp, - xfs_inode_t *dp, - struct xfs_name *name, /* name of entry to replace */ - xfs_ino_t inum, /* new inode number */ - xfs_fsblock_t *first, /* bmap's firstblock */ - struct xfs_defer_ops *dfops, /* bmap's freeblock list */ - xfs_extlen_t total) /* bmap's total block count */ -{ - struct xfs_da_args *args; - int rval; - int v; /* type-checking value */ - - ASSERT(S_ISDIR(VFS_I(dp)->i_mode)); - - rval = xfs_dir_ino_validate(tp->t_mountp, inum); - if (rval) - return rval; - - args = kmem_zalloc(sizeof(*args), KM_SLEEP | KM_NOFS); - if (!args) - return -ENOMEM; - - args->geo = dp->i_mount->m_dir_geo; - args->name = name->name; - args->namelen = name->len; - args->filetype = name->type; - args->hashval = dp->i_mount->m_dirnameops->hashname(name); - args->inumber = inum; - args->dp = dp; - args->firstblock = first; - args->dfops = dfops; - args->total = total; - args->whichfork = XFS_DATA_FORK; - args->trans = tp; - - if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) { - rval = xfs_dir2_sf_replace(args); - goto out_free; - } - - rval = xfs_dir2_isblock(args, &v); - if (rval) - goto out_free; - if (v) { - rval = xfs_dir2_block_replace(args); - goto out_free; - } - - rval = xfs_dir2_isleaf(args, &v); - if (rval) - goto out_free; - if (v) - rval = xfs_dir2_leaf_replace(args); - else - rval = xfs_dir2_node_replace(args); -out_free: - kmem_free(args); - return rval; -} - -/* - * See if this entry can be added to the directory without allocating space. - */ -int -xfs_dir_canenter( - xfs_trans_t *tp, - xfs_inode_t *dp, - struct xfs_name *name) /* name of entry to add */ -{ - return xfs_dir_createname(tp, dp, name, 0, NULL, NULL, 0); -} - -/* - * Utility routines. - */ - -/* - * Add a block to the directory. - * - * This routine is for data and free blocks, not leaf/node blocks which are - * handled by xfs_da_grow_inode. - */ -int -xfs_dir2_grow_inode( - struct xfs_da_args *args, - int space, /* v2 dir's space XFS_DIR2_xxx_SPACE */ - xfs_dir2_db_t *dbp) /* out: block number added */ -{ - struct xfs_inode *dp = args->dp; - struct xfs_mount *mp = dp->i_mount; - xfs_fileoff_t bno; /* directory offset of new block */ - int count; /* count of filesystem blocks */ - int error; - - trace_xfs_dir2_grow_inode(args, space); - - /* - * Set lowest possible block in the space requested. - */ - bno = XFS_B_TO_FSBT(mp, space * XFS_DIR2_SPACE_SIZE); - count = args->geo->fsbcount; - - error = xfs_da_grow_inode_int(args, &bno, count); - if (error) - return error; - - *dbp = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)bno); - - /* - * Update file's size if this is the data space and it grew. - */ - if (space == XFS_DIR2_DATA_SPACE) { - xfs_fsize_t size; /* directory file (data) size */ - - size = XFS_FSB_TO_B(mp, bno + count); - if (size > dp->i_d.di_size) { - dp->i_d.di_size = size; - xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); - } - } - return 0; -} - -/* - * See if the directory is a single-block form directory. - */ -int -xfs_dir2_isblock( - struct xfs_da_args *args, - int *vp) /* out: 1 is block, 0 is not block */ -{ - xfs_fileoff_t last; /* last file offset */ - int rval; - - if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK))) - return rval; - rval = XFS_FSB_TO_B(args->dp->i_mount, last) == args->geo->blksize; - ASSERT(rval == 0 || args->dp->i_d.di_size == args->geo->blksize); - *vp = rval; - return 0; -} - -/* - * See if the directory is a single-leaf form directory. - */ -int -xfs_dir2_isleaf( - struct xfs_da_args *args, - int *vp) /* out: 1 is block, 0 is not block */ -{ - xfs_fileoff_t last; /* last file offset */ - int rval; - - if ((rval = xfs_bmap_last_offset(args->dp, &last, XFS_DATA_FORK))) - return rval; - *vp = last == args->geo->leafblk + args->geo->fsbcount; - return 0; -} - -/* - * Remove the given block from the directory. - * This routine is used for data and free blocks, leaf/node are done - * by xfs_da_shrink_inode. - */ -int -xfs_dir2_shrink_inode( - xfs_da_args_t *args, - xfs_dir2_db_t db, - struct xfs_buf *bp) -{ - xfs_fileoff_t bno; /* directory file offset */ - xfs_dablk_t da; /* directory file offset */ - int done; /* bunmap is finished */ - xfs_inode_t *dp; - int error; - xfs_mount_t *mp; - xfs_trans_t *tp; - - trace_xfs_dir2_shrink_inode(args, db); - - dp = args->dp; - mp = dp->i_mount; - tp = args->trans; - da = xfs_dir2_db_to_da(args->geo, db); - - /* Unmap the fsblock(s). */ - error = xfs_bunmapi(tp, dp, da, args->geo->fsbcount, 0, 0, - args->firstblock, args->dfops, &done); - if (error) { - /* - * ENOSPC actually can happen if we're in a removename with no - * space reservation, and the resulting block removal would - * cause a bmap btree split or conversion from extents to btree. - * This can only happen for un-fragmented directory blocks, - * since you need to be punching out the middle of an extent. - * In this case we need to leave the block in the file, and not - * binval it. So the block has to be in a consistent empty - * state and appropriately logged. We don't free up the buffer, - * the caller can tell it hasn't happened since it got an error - * back. - */ - return error; - } - ASSERT(done); - /* - * Invalidate the buffer from the transaction. - */ - xfs_trans_binval(tp, bp); - /* - * If it's not a data block, we're done. - */ - if (db >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET)) - return 0; - /* - * If the block isn't the last one in the directory, we're done. - */ - if (dp->i_d.di_size > xfs_dir2_db_off_to_byte(args->geo, db + 1, 0)) - return 0; - bno = da; - if ((error = xfs_bmap_last_before(tp, dp, &bno, XFS_DATA_FORK))) { - /* - * This can't really happen unless there's kernel corruption. - */ - return error; - } - if (db == args->geo->datablk) - ASSERT(bno == 0); - else - ASSERT(bno > 0); - /* - * Set the size to the new last block. - */ - dp->i_d.di_size = XFS_FSB_TO_B(mp, bno); - xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); - return 0; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_dir2.h b/src/linux/fs/xfs/libxfs/xfs_dir2.h deleted file mode 100644 index becc926..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_dir2.h +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_DIR2_H__ -#define __XFS_DIR2_H__ - -struct xfs_defer_ops; -struct xfs_da_args; -struct xfs_inode; -struct xfs_mount; -struct xfs_trans; -struct xfs_dir2_sf_hdr; -struct xfs_dir2_sf_entry; -struct xfs_dir2_data_hdr; -struct xfs_dir2_data_entry; -struct xfs_dir2_data_unused; - -extern struct xfs_name xfs_name_dotdot; - -/* - * directory filetype conversion tables. - */ -#define S_SHIFT 12 -extern const unsigned char xfs_mode_to_ftype[]; - -/* - * directory operations vector for encode/decode routines - */ -struct xfs_dir_ops { - int (*sf_entsize)(struct xfs_dir2_sf_hdr *hdr, int len); - struct xfs_dir2_sf_entry * - (*sf_nextentry)(struct xfs_dir2_sf_hdr *hdr, - struct xfs_dir2_sf_entry *sfep); - __uint8_t (*sf_get_ftype)(struct xfs_dir2_sf_entry *sfep); - void (*sf_put_ftype)(struct xfs_dir2_sf_entry *sfep, - __uint8_t ftype); - xfs_ino_t (*sf_get_ino)(struct xfs_dir2_sf_hdr *hdr, - struct xfs_dir2_sf_entry *sfep); - void (*sf_put_ino)(struct xfs_dir2_sf_hdr *hdr, - struct xfs_dir2_sf_entry *sfep, - xfs_ino_t ino); - xfs_ino_t (*sf_get_parent_ino)(struct xfs_dir2_sf_hdr *hdr); - void (*sf_put_parent_ino)(struct xfs_dir2_sf_hdr *hdr, - xfs_ino_t ino); - - int (*data_entsize)(int len); - __uint8_t (*data_get_ftype)(struct xfs_dir2_data_entry *dep); - void (*data_put_ftype)(struct xfs_dir2_data_entry *dep, - __uint8_t ftype); - __be16 * (*data_entry_tag_p)(struct xfs_dir2_data_entry *dep); - struct xfs_dir2_data_free * - (*data_bestfree_p)(struct xfs_dir2_data_hdr *hdr); - - xfs_dir2_data_aoff_t data_dot_offset; - xfs_dir2_data_aoff_t data_dotdot_offset; - xfs_dir2_data_aoff_t data_first_offset; - size_t data_entry_offset; - - struct xfs_dir2_data_entry * - (*data_dot_entry_p)(struct xfs_dir2_data_hdr *hdr); - struct xfs_dir2_data_entry * - (*data_dotdot_entry_p)(struct xfs_dir2_data_hdr *hdr); - struct xfs_dir2_data_entry * - (*data_first_entry_p)(struct xfs_dir2_data_hdr *hdr); - struct xfs_dir2_data_entry * - (*data_entry_p)(struct xfs_dir2_data_hdr *hdr); - struct xfs_dir2_data_unused * - (*data_unused_p)(struct xfs_dir2_data_hdr *hdr); - - int leaf_hdr_size; - void (*leaf_hdr_to_disk)(struct xfs_dir2_leaf *to, - struct xfs_dir3_icleaf_hdr *from); - void (*leaf_hdr_from_disk)(struct xfs_dir3_icleaf_hdr *to, - struct xfs_dir2_leaf *from); - int (*leaf_max_ents)(struct xfs_da_geometry *geo); - struct xfs_dir2_leaf_entry * - (*leaf_ents_p)(struct xfs_dir2_leaf *lp); - - int node_hdr_size; - void (*node_hdr_to_disk)(struct xfs_da_intnode *to, - struct xfs_da3_icnode_hdr *from); - void (*node_hdr_from_disk)(struct xfs_da3_icnode_hdr *to, - struct xfs_da_intnode *from); - struct xfs_da_node_entry * - (*node_tree_p)(struct xfs_da_intnode *dap); - - int free_hdr_size; - void (*free_hdr_to_disk)(struct xfs_dir2_free *to, - struct xfs_dir3_icfree_hdr *from); - void (*free_hdr_from_disk)(struct xfs_dir3_icfree_hdr *to, - struct xfs_dir2_free *from); - int (*free_max_bests)(struct xfs_da_geometry *geo); - __be16 * (*free_bests_p)(struct xfs_dir2_free *free); - xfs_dir2_db_t (*db_to_fdb)(struct xfs_da_geometry *geo, - xfs_dir2_db_t db); - int (*db_to_fdindex)(struct xfs_da_geometry *geo, - xfs_dir2_db_t db); -}; - -extern const struct xfs_dir_ops * - xfs_dir_get_ops(struct xfs_mount *mp, struct xfs_inode *dp); -extern const struct xfs_dir_ops * - xfs_nondir_get_ops(struct xfs_mount *mp, struct xfs_inode *dp); - -/* - * Generic directory interface routines - */ -extern void xfs_dir_startup(void); -extern int xfs_da_mount(struct xfs_mount *mp); -extern void xfs_da_unmount(struct xfs_mount *mp); - -extern int xfs_dir_isempty(struct xfs_inode *dp); -extern int xfs_dir_init(struct xfs_trans *tp, struct xfs_inode *dp, - struct xfs_inode *pdp); -extern int xfs_dir_createname(struct xfs_trans *tp, struct xfs_inode *dp, - struct xfs_name *name, xfs_ino_t inum, - xfs_fsblock_t *first, - struct xfs_defer_ops *dfops, xfs_extlen_t tot); -extern int xfs_dir_lookup(struct xfs_trans *tp, struct xfs_inode *dp, - struct xfs_name *name, xfs_ino_t *inum, - struct xfs_name *ci_name); -extern int xfs_dir_removename(struct xfs_trans *tp, struct xfs_inode *dp, - struct xfs_name *name, xfs_ino_t ino, - xfs_fsblock_t *first, - struct xfs_defer_ops *dfops, xfs_extlen_t tot); -extern int xfs_dir_replace(struct xfs_trans *tp, struct xfs_inode *dp, - struct xfs_name *name, xfs_ino_t inum, - xfs_fsblock_t *first, - struct xfs_defer_ops *dfops, xfs_extlen_t tot); -extern int xfs_dir_canenter(struct xfs_trans *tp, struct xfs_inode *dp, - struct xfs_name *name); - -/* - * Direct call from the bmap code, bypassing the generic directory layer. - */ -extern int xfs_dir2_sf_to_block(struct xfs_da_args *args); - -/* - * Interface routines used by userspace utilities - */ -extern int xfs_dir2_isblock(struct xfs_da_args *args, int *r); -extern int xfs_dir2_isleaf(struct xfs_da_args *args, int *r); -extern int xfs_dir2_shrink_inode(struct xfs_da_args *args, xfs_dir2_db_t db, - struct xfs_buf *bp); - -extern void xfs_dir2_data_freescan(struct xfs_inode *dp, - struct xfs_dir2_data_hdr *hdr, int *loghead); -extern void xfs_dir2_data_log_entry(struct xfs_da_args *args, - struct xfs_buf *bp, struct xfs_dir2_data_entry *dep); -extern void xfs_dir2_data_log_header(struct xfs_da_args *args, - struct xfs_buf *bp); -extern void xfs_dir2_data_log_unused(struct xfs_da_args *args, - struct xfs_buf *bp, struct xfs_dir2_data_unused *dup); -extern void xfs_dir2_data_make_free(struct xfs_da_args *args, - struct xfs_buf *bp, xfs_dir2_data_aoff_t offset, - xfs_dir2_data_aoff_t len, int *needlogp, int *needscanp); -extern void xfs_dir2_data_use_free(struct xfs_da_args *args, - struct xfs_buf *bp, struct xfs_dir2_data_unused *dup, - xfs_dir2_data_aoff_t offset, xfs_dir2_data_aoff_t len, - int *needlogp, int *needscanp); - -extern struct xfs_dir2_data_free *xfs_dir2_data_freefind( - struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_free *bf, - struct xfs_dir2_data_unused *dup); - -extern const struct xfs_buf_ops xfs_dir3_block_buf_ops; -extern const struct xfs_buf_ops xfs_dir3_leafn_buf_ops; -extern const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops; -extern const struct xfs_buf_ops xfs_dir3_free_buf_ops; -extern const struct xfs_buf_ops xfs_dir3_data_buf_ops; - -/* - * Directory offset/block conversion functions. - * - * DB blocks here are logical directory block numbers, not filesystem blocks. - */ - -/* - * Convert dataptr to byte in file space - */ -static inline xfs_dir2_off_t -xfs_dir2_dataptr_to_byte(xfs_dir2_dataptr_t dp) -{ - return (xfs_dir2_off_t)dp << XFS_DIR2_DATA_ALIGN_LOG; -} - -/* - * Convert byte in file space to dataptr. It had better be aligned. - */ -static inline xfs_dir2_dataptr_t -xfs_dir2_byte_to_dataptr(xfs_dir2_off_t by) -{ - return (xfs_dir2_dataptr_t)(by >> XFS_DIR2_DATA_ALIGN_LOG); -} - -/* - * Convert byte in space to (DB) block - */ -static inline xfs_dir2_db_t -xfs_dir2_byte_to_db(struct xfs_da_geometry *geo, xfs_dir2_off_t by) -{ - return (xfs_dir2_db_t)(by >> geo->blklog); -} - -/* - * Convert dataptr to a block number - */ -static inline xfs_dir2_db_t -xfs_dir2_dataptr_to_db(struct xfs_da_geometry *geo, xfs_dir2_dataptr_t dp) -{ - return xfs_dir2_byte_to_db(geo, xfs_dir2_dataptr_to_byte(dp)); -} - -/* - * Convert byte in space to offset in a block - */ -static inline xfs_dir2_data_aoff_t -xfs_dir2_byte_to_off(struct xfs_da_geometry *geo, xfs_dir2_off_t by) -{ - return (xfs_dir2_data_aoff_t)(by & (geo->blksize - 1)); -} - -/* - * Convert dataptr to a byte offset in a block - */ -static inline xfs_dir2_data_aoff_t -xfs_dir2_dataptr_to_off(struct xfs_da_geometry *geo, xfs_dir2_dataptr_t dp) -{ - return xfs_dir2_byte_to_off(geo, xfs_dir2_dataptr_to_byte(dp)); -} - -/* - * Convert block and offset to byte in space - */ -static inline xfs_dir2_off_t -xfs_dir2_db_off_to_byte(struct xfs_da_geometry *geo, xfs_dir2_db_t db, - xfs_dir2_data_aoff_t o) -{ - return ((xfs_dir2_off_t)db << geo->blklog) + o; -} - -/* - * Convert block (DB) to block (dablk) - */ -static inline xfs_dablk_t -xfs_dir2_db_to_da(struct xfs_da_geometry *geo, xfs_dir2_db_t db) -{ - return (xfs_dablk_t)(db << (geo->blklog - geo->fsblog)); -} - -/* - * Convert byte in space to (DA) block - */ -static inline xfs_dablk_t -xfs_dir2_byte_to_da(struct xfs_da_geometry *geo, xfs_dir2_off_t by) -{ - return xfs_dir2_db_to_da(geo, xfs_dir2_byte_to_db(geo, by)); -} - -/* - * Convert block and offset to dataptr - */ -static inline xfs_dir2_dataptr_t -xfs_dir2_db_off_to_dataptr(struct xfs_da_geometry *geo, xfs_dir2_db_t db, - xfs_dir2_data_aoff_t o) -{ - return xfs_dir2_byte_to_dataptr(xfs_dir2_db_off_to_byte(geo, db, o)); -} - -/* - * Convert block (dablk) to block (DB) - */ -static inline xfs_dir2_db_t -xfs_dir2_da_to_db(struct xfs_da_geometry *geo, xfs_dablk_t da) -{ - return (xfs_dir2_db_t)(da >> (geo->blklog - geo->fsblog)); -} - -/* - * Convert block (dablk) to byte offset in space - */ -static inline xfs_dir2_off_t -xfs_dir2_da_to_byte(struct xfs_da_geometry *geo, xfs_dablk_t da) -{ - return xfs_dir2_db_off_to_byte(geo, xfs_dir2_da_to_db(geo, da), 0); -} - -/* - * Directory tail pointer accessor functions. Based on block geometry. - */ -static inline struct xfs_dir2_block_tail * -xfs_dir2_block_tail_p(struct xfs_da_geometry *geo, struct xfs_dir2_data_hdr *hdr) -{ - return ((struct xfs_dir2_block_tail *) - ((char *)hdr + geo->blksize)) - 1; -} - -static inline struct xfs_dir2_leaf_tail * -xfs_dir2_leaf_tail_p(struct xfs_da_geometry *geo, struct xfs_dir2_leaf *lp) -{ - return (struct xfs_dir2_leaf_tail *) - ((char *)lp + geo->blksize - - sizeof(struct xfs_dir2_leaf_tail)); -} - -#endif /* __XFS_DIR2_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_dir2_block.c b/src/linux/fs/xfs/libxfs/xfs_dir2_block.c deleted file mode 100644 index aa17cb7..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_dir2_block.c +++ /dev/null @@ -1,1258 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * Copyright (c) 2013 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_bmap.h" -#include "xfs_buf_item.h" -#include "xfs_dir2.h" -#include "xfs_dir2_priv.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_cksum.h" -#include "xfs_log.h" - -/* - * Local function prototypes. - */ -static void xfs_dir2_block_log_leaf(xfs_trans_t *tp, struct xfs_buf *bp, - int first, int last); -static void xfs_dir2_block_log_tail(xfs_trans_t *tp, struct xfs_buf *bp); -static int xfs_dir2_block_lookup_int(xfs_da_args_t *args, struct xfs_buf **bpp, - int *entno); -static int xfs_dir2_block_sort(const void *a, const void *b); - -static xfs_dahash_t xfs_dir_hash_dot, xfs_dir_hash_dotdot; - -/* - * One-time startup routine called from xfs_init(). - */ -void -xfs_dir_startup(void) -{ - xfs_dir_hash_dot = xfs_da_hashname((unsigned char *)".", 1); - xfs_dir_hash_dotdot = xfs_da_hashname((unsigned char *)"..", 2); -} - -static bool -xfs_dir3_block_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - if (hdr3->magic != cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) - return false; - if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid)) - return false; - if (be64_to_cpu(hdr3->blkno) != bp->b_bn) - return false; - if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn))) - return false; - } else { - if (hdr3->magic != cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) - return false; - } - if (__xfs_dir3_data_check(NULL, bp)) - return false; - return true; -} - -static void -xfs_dir3_block_read_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - - if (xfs_sb_version_hascrc(&mp->m_sb) && - !xfs_buf_verify_cksum(bp, XFS_DIR3_DATA_CRC_OFF)) - xfs_buf_ioerror(bp, -EFSBADCRC); - else if (!xfs_dir3_block_verify(bp)) - xfs_buf_ioerror(bp, -EFSCORRUPTED); - - if (bp->b_error) - xfs_verifier_error(bp); -} - -static void -xfs_dir3_block_write_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_buf_log_item *bip = bp->b_fspriv; - struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; - - if (!xfs_dir3_block_verify(bp)) { - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - return; - } - - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return; - - if (bip) - hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn); - - xfs_buf_update_cksum(bp, XFS_DIR3_DATA_CRC_OFF); -} - -const struct xfs_buf_ops xfs_dir3_block_buf_ops = { - .name = "xfs_dir3_block", - .verify_read = xfs_dir3_block_read_verify, - .verify_write = xfs_dir3_block_write_verify, -}; - -int -xfs_dir3_block_read( - struct xfs_trans *tp, - struct xfs_inode *dp, - struct xfs_buf **bpp) -{ - struct xfs_mount *mp = dp->i_mount; - int err; - - err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk, -1, bpp, - XFS_DATA_FORK, &xfs_dir3_block_buf_ops); - if (!err && tp) - xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_BLOCK_BUF); - return err; -} - -static void -xfs_dir3_block_init( - struct xfs_mount *mp, - struct xfs_trans *tp, - struct xfs_buf *bp, - struct xfs_inode *dp) -{ - struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; - - bp->b_ops = &xfs_dir3_block_buf_ops; - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_BLOCK_BUF); - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - memset(hdr3, 0, sizeof(*hdr3)); - hdr3->magic = cpu_to_be32(XFS_DIR3_BLOCK_MAGIC); - hdr3->blkno = cpu_to_be64(bp->b_bn); - hdr3->owner = cpu_to_be64(dp->i_ino); - uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid); - return; - - } - hdr3->magic = cpu_to_be32(XFS_DIR2_BLOCK_MAGIC); -} - -static void -xfs_dir2_block_need_space( - struct xfs_inode *dp, - struct xfs_dir2_data_hdr *hdr, - struct xfs_dir2_block_tail *btp, - struct xfs_dir2_leaf_entry *blp, - __be16 **tagpp, - struct xfs_dir2_data_unused **dupp, - struct xfs_dir2_data_unused **enddupp, - int *compact, - int len) -{ - struct xfs_dir2_data_free *bf; - __be16 *tagp = NULL; - struct xfs_dir2_data_unused *dup = NULL; - struct xfs_dir2_data_unused *enddup = NULL; - - *compact = 0; - bf = dp->d_ops->data_bestfree_p(hdr); - - /* - * If there are stale entries we'll use one for the leaf. - */ - if (btp->stale) { - if (be16_to_cpu(bf[0].length) >= len) { - /* - * The biggest entry enough to avoid compaction. - */ - dup = (xfs_dir2_data_unused_t *) - ((char *)hdr + be16_to_cpu(bf[0].offset)); - goto out; - } - - /* - * Will need to compact to make this work. - * Tag just before the first leaf entry. - */ - *compact = 1; - tagp = (__be16 *)blp - 1; - - /* Data object just before the first leaf entry. */ - dup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp)); - - /* - * If it's not free then the data will go where the - * leaf data starts now, if it works at all. - */ - if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { - if (be16_to_cpu(dup->length) + (be32_to_cpu(btp->stale) - 1) * - (uint)sizeof(*blp) < len) - dup = NULL; - } else if ((be32_to_cpu(btp->stale) - 1) * (uint)sizeof(*blp) < len) - dup = NULL; - else - dup = (xfs_dir2_data_unused_t *)blp; - goto out; - } - - /* - * no stale entries, so just use free space. - * Tag just before the first leaf entry. - */ - tagp = (__be16 *)blp - 1; - - /* Data object just before the first leaf entry. */ - enddup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp)); - - /* - * If it's not free then can't do this add without cleaning up: - * the space before the first leaf entry needs to be free so it - * can be expanded to hold the pointer to the new entry. - */ - if (be16_to_cpu(enddup->freetag) == XFS_DIR2_DATA_FREE_TAG) { - /* - * Check out the biggest freespace and see if it's the same one. - */ - dup = (xfs_dir2_data_unused_t *) - ((char *)hdr + be16_to_cpu(bf[0].offset)); - if (dup != enddup) { - /* - * Not the same free entry, just check its length. - */ - if (be16_to_cpu(dup->length) < len) - dup = NULL; - goto out; - } - - /* - * It is the biggest freespace, can it hold the leaf too? - */ - if (be16_to_cpu(dup->length) < len + (uint)sizeof(*blp)) { - /* - * Yes, use the second-largest entry instead if it works. - */ - if (be16_to_cpu(bf[1].length) >= len) - dup = (xfs_dir2_data_unused_t *) - ((char *)hdr + be16_to_cpu(bf[1].offset)); - else - dup = NULL; - } - } -out: - *tagpp = tagp; - *dupp = dup; - *enddupp = enddup; -} - -/* - * compact the leaf entries. - * Leave the highest-numbered stale entry stale. - * XXX should be the one closest to mid but mid is not yet computed. - */ -static void -xfs_dir2_block_compact( - struct xfs_da_args *args, - struct xfs_buf *bp, - struct xfs_dir2_data_hdr *hdr, - struct xfs_dir2_block_tail *btp, - struct xfs_dir2_leaf_entry *blp, - int *needlog, - int *lfloghigh, - int *lfloglow) -{ - int fromidx; /* source leaf index */ - int toidx; /* target leaf index */ - int needscan = 0; - int highstale; /* high stale index */ - - fromidx = toidx = be32_to_cpu(btp->count) - 1; - highstale = *lfloghigh = -1; - for (; fromidx >= 0; fromidx--) { - if (blp[fromidx].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) { - if (highstale == -1) - highstale = toidx; - else { - if (*lfloghigh == -1) - *lfloghigh = toidx; - continue; - } - } - if (fromidx < toidx) - blp[toidx] = blp[fromidx]; - toidx--; - } - *lfloglow = toidx + 1 - (be32_to_cpu(btp->stale) - 1); - *lfloghigh -= be32_to_cpu(btp->stale) - 1; - be32_add_cpu(&btp->count, -(be32_to_cpu(btp->stale) - 1)); - xfs_dir2_data_make_free(args, bp, - (xfs_dir2_data_aoff_t)((char *)blp - (char *)hdr), - (xfs_dir2_data_aoff_t)((be32_to_cpu(btp->stale) - 1) * sizeof(*blp)), - needlog, &needscan); - btp->stale = cpu_to_be32(1); - /* - * If we now need to rebuild the bestfree map, do so. - * This needs to happen before the next call to use_free. - */ - if (needscan) - xfs_dir2_data_freescan(args->dp, hdr, needlog); -} - -/* - * Add an entry to a block directory. - */ -int /* error */ -xfs_dir2_block_addname( - xfs_da_args_t *args) /* directory op arguments */ -{ - xfs_dir2_data_hdr_t *hdr; /* block header */ - xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ - struct xfs_buf *bp; /* buffer for block */ - xfs_dir2_block_tail_t *btp; /* block tail */ - int compact; /* need to compact leaf ents */ - xfs_dir2_data_entry_t *dep; /* block data entry */ - xfs_inode_t *dp; /* directory inode */ - xfs_dir2_data_unused_t *dup; /* block unused entry */ - int error; /* error return value */ - xfs_dir2_data_unused_t *enddup=NULL; /* unused at end of data */ - xfs_dahash_t hash; /* hash value of found entry */ - int high; /* high index for binary srch */ - int highstale; /* high stale index */ - int lfloghigh=0; /* last final leaf to log */ - int lfloglow=0; /* first final leaf to log */ - int len; /* length of the new entry */ - int low; /* low index for binary srch */ - int lowstale; /* low stale index */ - int mid=0; /* midpoint for binary srch */ - int needlog; /* need to log header */ - int needscan; /* need to rescan freespace */ - __be16 *tagp; /* pointer to tag value */ - xfs_trans_t *tp; /* transaction structure */ - - trace_xfs_dir2_block_addname(args); - - dp = args->dp; - tp = args->trans; - - /* Read the (one and only) directory block into bp. */ - error = xfs_dir3_block_read(tp, dp, &bp); - if (error) - return error; - - len = dp->d_ops->data_entsize(args->namelen); - - /* - * Set up pointers to parts of the block. - */ - hdr = bp->b_addr; - btp = xfs_dir2_block_tail_p(args->geo, hdr); - blp = xfs_dir2_block_leaf_p(btp); - - /* - * Find out if we can reuse stale entries or whether we need extra - * space for entry and new leaf. - */ - xfs_dir2_block_need_space(dp, hdr, btp, blp, &tagp, &dup, - &enddup, &compact, len); - - /* - * Done everything we need for a space check now. - */ - if (args->op_flags & XFS_DA_OP_JUSTCHECK) { - xfs_trans_brelse(tp, bp); - if (!dup) - return -ENOSPC; - return 0; - } - - /* - * If we don't have space for the new entry & leaf ... - */ - if (!dup) { - /* Don't have a space reservation: return no-space. */ - if (args->total == 0) - return -ENOSPC; - /* - * Convert to the next larger format. - * Then add the new entry in that format. - */ - error = xfs_dir2_block_to_leaf(args, bp); - if (error) - return error; - return xfs_dir2_leaf_addname(args); - } - - needlog = needscan = 0; - - /* - * If need to compact the leaf entries, do it now. - */ - if (compact) { - xfs_dir2_block_compact(args, bp, hdr, btp, blp, &needlog, - &lfloghigh, &lfloglow); - /* recalculate blp post-compaction */ - blp = xfs_dir2_block_leaf_p(btp); - } else if (btp->stale) { - /* - * Set leaf logging boundaries to impossible state. - * For the no-stale case they're set explicitly. - */ - lfloglow = be32_to_cpu(btp->count); - lfloghigh = -1; - } - - /* - * Find the slot that's first lower than our hash value, -1 if none. - */ - for (low = 0, high = be32_to_cpu(btp->count) - 1; low <= high; ) { - mid = (low + high) >> 1; - if ((hash = be32_to_cpu(blp[mid].hashval)) == args->hashval) - break; - if (hash < args->hashval) - low = mid + 1; - else - high = mid - 1; - } - while (mid >= 0 && be32_to_cpu(blp[mid].hashval) >= args->hashval) { - mid--; - } - /* - * No stale entries, will use enddup space to hold new leaf. - */ - if (!btp->stale) { - /* - * Mark the space needed for the new leaf entry, now in use. - */ - xfs_dir2_data_use_free(args, bp, enddup, - (xfs_dir2_data_aoff_t) - ((char *)enddup - (char *)hdr + be16_to_cpu(enddup->length) - - sizeof(*blp)), - (xfs_dir2_data_aoff_t)sizeof(*blp), - &needlog, &needscan); - /* - * Update the tail (entry count). - */ - be32_add_cpu(&btp->count, 1); - /* - * If we now need to rebuild the bestfree map, do so. - * This needs to happen before the next call to use_free. - */ - if (needscan) { - xfs_dir2_data_freescan(dp, hdr, &needlog); - needscan = 0; - } - /* - * Adjust pointer to the first leaf entry, we're about to move - * the table up one to open up space for the new leaf entry. - * Then adjust our index to match. - */ - blp--; - mid++; - if (mid) - memmove(blp, &blp[1], mid * sizeof(*blp)); - lfloglow = 0; - lfloghigh = mid; - } - /* - * Use a stale leaf for our new entry. - */ - else { - for (lowstale = mid; - lowstale >= 0 && - blp[lowstale].address != - cpu_to_be32(XFS_DIR2_NULL_DATAPTR); - lowstale--) - continue; - for (highstale = mid + 1; - highstale < be32_to_cpu(btp->count) && - blp[highstale].address != - cpu_to_be32(XFS_DIR2_NULL_DATAPTR) && - (lowstale < 0 || mid - lowstale > highstale - mid); - highstale++) - continue; - /* - * Move entries toward the low-numbered stale entry. - */ - if (lowstale >= 0 && - (highstale == be32_to_cpu(btp->count) || - mid - lowstale <= highstale - mid)) { - if (mid - lowstale) - memmove(&blp[lowstale], &blp[lowstale + 1], - (mid - lowstale) * sizeof(*blp)); - lfloglow = MIN(lowstale, lfloglow); - lfloghigh = MAX(mid, lfloghigh); - } - /* - * Move entries toward the high-numbered stale entry. - */ - else { - ASSERT(highstale < be32_to_cpu(btp->count)); - mid++; - if (highstale - mid) - memmove(&blp[mid + 1], &blp[mid], - (highstale - mid) * sizeof(*blp)); - lfloglow = MIN(mid, lfloglow); - lfloghigh = MAX(highstale, lfloghigh); - } - be32_add_cpu(&btp->stale, -1); - } - /* - * Point to the new data entry. - */ - dep = (xfs_dir2_data_entry_t *)dup; - /* - * Fill in the leaf entry. - */ - blp[mid].hashval = cpu_to_be32(args->hashval); - blp[mid].address = cpu_to_be32(xfs_dir2_byte_to_dataptr( - (char *)dep - (char *)hdr)); - xfs_dir2_block_log_leaf(tp, bp, lfloglow, lfloghigh); - /* - * Mark space for the data entry used. - */ - xfs_dir2_data_use_free(args, bp, dup, - (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), - (xfs_dir2_data_aoff_t)len, &needlog, &needscan); - /* - * Create the new data entry. - */ - dep->inumber = cpu_to_be64(args->inumber); - dep->namelen = args->namelen; - memcpy(dep->name, args->name, args->namelen); - dp->d_ops->data_put_ftype(dep, args->filetype); - tagp = dp->d_ops->data_entry_tag_p(dep); - *tagp = cpu_to_be16((char *)dep - (char *)hdr); - /* - * Clean up the bestfree array and log the header, tail, and entry. - */ - if (needscan) - xfs_dir2_data_freescan(dp, hdr, &needlog); - if (needlog) - xfs_dir2_data_log_header(args, bp); - xfs_dir2_block_log_tail(tp, bp); - xfs_dir2_data_log_entry(args, bp, dep); - xfs_dir3_data_check(dp, bp); - return 0; -} - -/* - * Log leaf entries from the block. - */ -static void -xfs_dir2_block_log_leaf( - xfs_trans_t *tp, /* transaction structure */ - struct xfs_buf *bp, /* block buffer */ - int first, /* index of first logged leaf */ - int last) /* index of last logged leaf */ -{ - xfs_dir2_data_hdr_t *hdr = bp->b_addr; - xfs_dir2_leaf_entry_t *blp; - xfs_dir2_block_tail_t *btp; - - btp = xfs_dir2_block_tail_p(tp->t_mountp->m_dir_geo, hdr); - blp = xfs_dir2_block_leaf_p(btp); - xfs_trans_log_buf(tp, bp, (uint)((char *)&blp[first] - (char *)hdr), - (uint)((char *)&blp[last + 1] - (char *)hdr - 1)); -} - -/* - * Log the block tail. - */ -static void -xfs_dir2_block_log_tail( - xfs_trans_t *tp, /* transaction structure */ - struct xfs_buf *bp) /* block buffer */ -{ - xfs_dir2_data_hdr_t *hdr = bp->b_addr; - xfs_dir2_block_tail_t *btp; - - btp = xfs_dir2_block_tail_p(tp->t_mountp->m_dir_geo, hdr); - xfs_trans_log_buf(tp, bp, (uint)((char *)btp - (char *)hdr), - (uint)((char *)(btp + 1) - (char *)hdr - 1)); -} - -/* - * Look up an entry in the block. This is the external routine, - * xfs_dir2_block_lookup_int does the real work. - */ -int /* error */ -xfs_dir2_block_lookup( - xfs_da_args_t *args) /* dir lookup arguments */ -{ - xfs_dir2_data_hdr_t *hdr; /* block header */ - xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ - struct xfs_buf *bp; /* block buffer */ - xfs_dir2_block_tail_t *btp; /* block tail */ - xfs_dir2_data_entry_t *dep; /* block data entry */ - xfs_inode_t *dp; /* incore inode */ - int ent; /* entry index */ - int error; /* error return value */ - - trace_xfs_dir2_block_lookup(args); - - /* - * Get the buffer, look up the entry. - * If not found (ENOENT) then return, have no buffer. - */ - if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) - return error; - dp = args->dp; - hdr = bp->b_addr; - xfs_dir3_data_check(dp, bp); - btp = xfs_dir2_block_tail_p(args->geo, hdr); - blp = xfs_dir2_block_leaf_p(btp); - /* - * Get the offset from the leaf entry, to point to the data. - */ - dep = (xfs_dir2_data_entry_t *)((char *)hdr + - xfs_dir2_dataptr_to_off(args->geo, - be32_to_cpu(blp[ent].address))); - /* - * Fill in inode number, CI name if appropriate, release the block. - */ - args->inumber = be64_to_cpu(dep->inumber); - args->filetype = dp->d_ops->data_get_ftype(dep); - error = xfs_dir_cilookup_result(args, dep->name, dep->namelen); - xfs_trans_brelse(args->trans, bp); - return error; -} - -/* - * Internal block lookup routine. - */ -static int /* error */ -xfs_dir2_block_lookup_int( - xfs_da_args_t *args, /* dir lookup arguments */ - struct xfs_buf **bpp, /* returned block buffer */ - int *entno) /* returned entry number */ -{ - xfs_dir2_dataptr_t addr; /* data entry address */ - xfs_dir2_data_hdr_t *hdr; /* block header */ - xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ - struct xfs_buf *bp; /* block buffer */ - xfs_dir2_block_tail_t *btp; /* block tail */ - xfs_dir2_data_entry_t *dep; /* block data entry */ - xfs_inode_t *dp; /* incore inode */ - int error; /* error return value */ - xfs_dahash_t hash; /* found hash value */ - int high; /* binary search high index */ - int low; /* binary search low index */ - int mid; /* binary search current idx */ - xfs_mount_t *mp; /* filesystem mount point */ - xfs_trans_t *tp; /* transaction pointer */ - enum xfs_dacmp cmp; /* comparison result */ - - dp = args->dp; - tp = args->trans; - mp = dp->i_mount; - - error = xfs_dir3_block_read(tp, dp, &bp); - if (error) - return error; - - hdr = bp->b_addr; - xfs_dir3_data_check(dp, bp); - btp = xfs_dir2_block_tail_p(args->geo, hdr); - blp = xfs_dir2_block_leaf_p(btp); - /* - * Loop doing a binary search for our hash value. - * Find our entry, ENOENT if it's not there. - */ - for (low = 0, high = be32_to_cpu(btp->count) - 1; ; ) { - ASSERT(low <= high); - mid = (low + high) >> 1; - if ((hash = be32_to_cpu(blp[mid].hashval)) == args->hashval) - break; - if (hash < args->hashval) - low = mid + 1; - else - high = mid - 1; - if (low > high) { - ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); - xfs_trans_brelse(tp, bp); - return -ENOENT; - } - } - /* - * Back up to the first one with the right hash value. - */ - while (mid > 0 && be32_to_cpu(blp[mid - 1].hashval) == args->hashval) { - mid--; - } - /* - * Now loop forward through all the entries with the - * right hash value looking for our name. - */ - do { - if ((addr = be32_to_cpu(blp[mid].address)) == XFS_DIR2_NULL_DATAPTR) - continue; - /* - * Get pointer to the entry from the leaf. - */ - dep = (xfs_dir2_data_entry_t *) - ((char *)hdr + xfs_dir2_dataptr_to_off(args->geo, addr)); - /* - * Compare name and if it's an exact match, return the index - * and buffer. If it's the first case-insensitive match, store - * the index and buffer and continue looking for an exact match. - */ - cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen); - if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { - args->cmpresult = cmp; - *bpp = bp; - *entno = mid; - if (cmp == XFS_CMP_EXACT) - return 0; - } - } while (++mid < be32_to_cpu(btp->count) && - be32_to_cpu(blp[mid].hashval) == hash); - - ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); - /* - * Here, we can only be doing a lookup (not a rename or replace). - * If a case-insensitive match was found earlier, return success. - */ - if (args->cmpresult == XFS_CMP_CASE) - return 0; - /* - * No match, release the buffer and return ENOENT. - */ - xfs_trans_brelse(tp, bp); - return -ENOENT; -} - -/* - * Remove an entry from a block format directory. - * If that makes the block small enough to fit in shortform, transform it. - */ -int /* error */ -xfs_dir2_block_removename( - xfs_da_args_t *args) /* directory operation args */ -{ - xfs_dir2_data_hdr_t *hdr; /* block header */ - xfs_dir2_leaf_entry_t *blp; /* block leaf pointer */ - struct xfs_buf *bp; /* block buffer */ - xfs_dir2_block_tail_t *btp; /* block tail */ - xfs_dir2_data_entry_t *dep; /* block data entry */ - xfs_inode_t *dp; /* incore inode */ - int ent; /* block leaf entry index */ - int error; /* error return value */ - int needlog; /* need to log block header */ - int needscan; /* need to fixup bestfree */ - xfs_dir2_sf_hdr_t sfh; /* shortform header */ - int size; /* shortform size */ - xfs_trans_t *tp; /* transaction pointer */ - - trace_xfs_dir2_block_removename(args); - - /* - * Look up the entry in the block. Gets the buffer and entry index. - * It will always be there, the vnodeops level does a lookup first. - */ - if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) { - return error; - } - dp = args->dp; - tp = args->trans; - hdr = bp->b_addr; - btp = xfs_dir2_block_tail_p(args->geo, hdr); - blp = xfs_dir2_block_leaf_p(btp); - /* - * Point to the data entry using the leaf entry. - */ - dep = (xfs_dir2_data_entry_t *)((char *)hdr + - xfs_dir2_dataptr_to_off(args->geo, - be32_to_cpu(blp[ent].address))); - /* - * Mark the data entry's space free. - */ - needlog = needscan = 0; - xfs_dir2_data_make_free(args, bp, - (xfs_dir2_data_aoff_t)((char *)dep - (char *)hdr), - dp->d_ops->data_entsize(dep->namelen), &needlog, &needscan); - /* - * Fix up the block tail. - */ - be32_add_cpu(&btp->stale, 1); - xfs_dir2_block_log_tail(tp, bp); - /* - * Remove the leaf entry by marking it stale. - */ - blp[ent].address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR); - xfs_dir2_block_log_leaf(tp, bp, ent, ent); - /* - * Fix up bestfree, log the header if necessary. - */ - if (needscan) - xfs_dir2_data_freescan(dp, hdr, &needlog); - if (needlog) - xfs_dir2_data_log_header(args, bp); - xfs_dir3_data_check(dp, bp); - /* - * See if the size as a shortform is good enough. - */ - size = xfs_dir2_block_sfsize(dp, hdr, &sfh); - if (size > XFS_IFORK_DSIZE(dp)) - return 0; - - /* - * If it works, do the conversion. - */ - return xfs_dir2_block_to_sf(args, bp, size, &sfh); -} - -/* - * Replace an entry in a V2 block directory. - * Change the inode number to the new value. - */ -int /* error */ -xfs_dir2_block_replace( - xfs_da_args_t *args) /* directory operation args */ -{ - xfs_dir2_data_hdr_t *hdr; /* block header */ - xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ - struct xfs_buf *bp; /* block buffer */ - xfs_dir2_block_tail_t *btp; /* block tail */ - xfs_dir2_data_entry_t *dep; /* block data entry */ - xfs_inode_t *dp; /* incore inode */ - int ent; /* leaf entry index */ - int error; /* error return value */ - - trace_xfs_dir2_block_replace(args); - - /* - * Lookup the entry in the directory. Get buffer and entry index. - * This will always succeed since the caller has already done a lookup. - */ - if ((error = xfs_dir2_block_lookup_int(args, &bp, &ent))) { - return error; - } - dp = args->dp; - hdr = bp->b_addr; - btp = xfs_dir2_block_tail_p(args->geo, hdr); - blp = xfs_dir2_block_leaf_p(btp); - /* - * Point to the data entry we need to change. - */ - dep = (xfs_dir2_data_entry_t *)((char *)hdr + - xfs_dir2_dataptr_to_off(args->geo, - be32_to_cpu(blp[ent].address))); - ASSERT(be64_to_cpu(dep->inumber) != args->inumber); - /* - * Change the inode number to the new value. - */ - dep->inumber = cpu_to_be64(args->inumber); - dp->d_ops->data_put_ftype(dep, args->filetype); - xfs_dir2_data_log_entry(args, bp, dep); - xfs_dir3_data_check(dp, bp); - return 0; -} - -/* - * Qsort comparison routine for the block leaf entries. - */ -static int /* sort order */ -xfs_dir2_block_sort( - const void *a, /* first leaf entry */ - const void *b) /* second leaf entry */ -{ - const xfs_dir2_leaf_entry_t *la; /* first leaf entry */ - const xfs_dir2_leaf_entry_t *lb; /* second leaf entry */ - - la = a; - lb = b; - return be32_to_cpu(la->hashval) < be32_to_cpu(lb->hashval) ? -1 : - (be32_to_cpu(la->hashval) > be32_to_cpu(lb->hashval) ? 1 : 0); -} - -/* - * Convert a V2 leaf directory to a V2 block directory if possible. - */ -int /* error */ -xfs_dir2_leaf_to_block( - xfs_da_args_t *args, /* operation arguments */ - struct xfs_buf *lbp, /* leaf buffer */ - struct xfs_buf *dbp) /* data buffer */ -{ - __be16 *bestsp; /* leaf bests table */ - xfs_dir2_data_hdr_t *hdr; /* block header */ - xfs_dir2_block_tail_t *btp; /* block tail */ - xfs_inode_t *dp; /* incore directory inode */ - xfs_dir2_data_unused_t *dup; /* unused data entry */ - int error; /* error return value */ - int from; /* leaf from index */ - xfs_dir2_leaf_t *leaf; /* leaf structure */ - xfs_dir2_leaf_entry_t *lep; /* leaf entry */ - xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ - xfs_mount_t *mp; /* file system mount point */ - int needlog; /* need to log data header */ - int needscan; /* need to scan for bestfree */ - xfs_dir2_sf_hdr_t sfh; /* shortform header */ - int size; /* bytes used */ - __be16 *tagp; /* end of entry (tag) */ - int to; /* block/leaf to index */ - xfs_trans_t *tp; /* transaction pointer */ - struct xfs_dir2_leaf_entry *ents; - struct xfs_dir3_icleaf_hdr leafhdr; - - trace_xfs_dir2_leaf_to_block(args); - - dp = args->dp; - tp = args->trans; - mp = dp->i_mount; - leaf = lbp->b_addr; - dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); - ents = dp->d_ops->leaf_ents_p(leaf); - ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); - - ASSERT(leafhdr.magic == XFS_DIR2_LEAF1_MAGIC || - leafhdr.magic == XFS_DIR3_LEAF1_MAGIC); - /* - * If there are data blocks other than the first one, take this - * opportunity to remove trailing empty data blocks that may have - * been left behind during no-space-reservation operations. - * These will show up in the leaf bests table. - */ - while (dp->i_d.di_size > args->geo->blksize) { - int hdrsz; - - hdrsz = dp->d_ops->data_entry_offset; - bestsp = xfs_dir2_leaf_bests_p(ltp); - if (be16_to_cpu(bestsp[be32_to_cpu(ltp->bestcount) - 1]) == - args->geo->blksize - hdrsz) { - if ((error = - xfs_dir2_leaf_trim_data(args, lbp, - (xfs_dir2_db_t)(be32_to_cpu(ltp->bestcount) - 1)))) - return error; - } else - return 0; - } - /* - * Read the data block if we don't already have it, give up if it fails. - */ - if (!dbp) { - error = xfs_dir3_data_read(tp, dp, args->geo->datablk, -1, &dbp); - if (error) - return error; - } - hdr = dbp->b_addr; - ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC)); - - /* - * Size of the "leaf" area in the block. - */ - size = (uint)sizeof(xfs_dir2_block_tail_t) + - (uint)sizeof(*lep) * (leafhdr.count - leafhdr.stale); - /* - * Look at the last data entry. - */ - tagp = (__be16 *)((char *)hdr + args->geo->blksize) - 1; - dup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp)); - /* - * If it's not free or is too short we can't do it. - */ - if (be16_to_cpu(dup->freetag) != XFS_DIR2_DATA_FREE_TAG || - be16_to_cpu(dup->length) < size) - return 0; - - /* - * Start converting it to block form. - */ - xfs_dir3_block_init(mp, tp, dbp, dp); - - needlog = 1; - needscan = 0; - /* - * Use up the space at the end of the block (blp/btp). - */ - xfs_dir2_data_use_free(args, dbp, dup, args->geo->blksize - size, size, - &needlog, &needscan); - /* - * Initialize the block tail. - */ - btp = xfs_dir2_block_tail_p(args->geo, hdr); - btp->count = cpu_to_be32(leafhdr.count - leafhdr.stale); - btp->stale = 0; - xfs_dir2_block_log_tail(tp, dbp); - /* - * Initialize the block leaf area. We compact out stale entries. - */ - lep = xfs_dir2_block_leaf_p(btp); - for (from = to = 0; from < leafhdr.count; from++) { - if (ents[from].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) - continue; - lep[to++] = ents[from]; - } - ASSERT(to == be32_to_cpu(btp->count)); - xfs_dir2_block_log_leaf(tp, dbp, 0, be32_to_cpu(btp->count) - 1); - /* - * Scan the bestfree if we need it and log the data block header. - */ - if (needscan) - xfs_dir2_data_freescan(dp, hdr, &needlog); - if (needlog) - xfs_dir2_data_log_header(args, dbp); - /* - * Pitch the old leaf block. - */ - error = xfs_da_shrink_inode(args, args->geo->leafblk, lbp); - if (error) - return error; - - /* - * Now see if the resulting block can be shrunken to shortform. - */ - size = xfs_dir2_block_sfsize(dp, hdr, &sfh); - if (size > XFS_IFORK_DSIZE(dp)) - return 0; - - return xfs_dir2_block_to_sf(args, dbp, size, &sfh); -} - -/* - * Convert the shortform directory to block form. - */ -int /* error */ -xfs_dir2_sf_to_block( - xfs_da_args_t *args) /* operation arguments */ -{ - xfs_dir2_db_t blkno; /* dir-relative block # (0) */ - xfs_dir2_data_hdr_t *hdr; /* block header */ - xfs_dir2_leaf_entry_t *blp; /* block leaf entries */ - struct xfs_buf *bp; /* block buffer */ - xfs_dir2_block_tail_t *btp; /* block tail pointer */ - xfs_dir2_data_entry_t *dep; /* data entry pointer */ - xfs_inode_t *dp; /* incore directory inode */ - int dummy; /* trash */ - xfs_dir2_data_unused_t *dup; /* unused entry pointer */ - int endoffset; /* end of data objects */ - int error; /* error return value */ - int i; /* index */ - xfs_mount_t *mp; /* filesystem mount point */ - int needlog; /* need to log block header */ - int needscan; /* need to scan block freespc */ - int newoffset; /* offset from current entry */ - int offset; /* target block offset */ - xfs_dir2_sf_entry_t *sfep; /* sf entry pointer */ - xfs_dir2_sf_hdr_t *oldsfp; /* old shortform header */ - xfs_dir2_sf_hdr_t *sfp; /* shortform header */ - __be16 *tagp; /* end of data entry */ - xfs_trans_t *tp; /* transaction pointer */ - struct xfs_name name; - struct xfs_ifork *ifp; - - trace_xfs_dir2_sf_to_block(args); - - dp = args->dp; - tp = args->trans; - mp = dp->i_mount; - ifp = XFS_IFORK_PTR(dp, XFS_DATA_FORK); - ASSERT(ifp->if_flags & XFS_IFINLINE); - /* - * Bomb out if the shortform directory is way too short. - */ - if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { - ASSERT(XFS_FORCED_SHUTDOWN(mp)); - return -EIO; - } - - oldsfp = (xfs_dir2_sf_hdr_t *)ifp->if_u1.if_data; - - ASSERT(ifp->if_bytes == dp->i_d.di_size); - ASSERT(ifp->if_u1.if_data != NULL); - ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(oldsfp->i8count)); - ASSERT(dp->i_d.di_nextents == 0); - - /* - * Copy the directory into a temporary buffer. - * Then pitch the incore inode data so we can make extents. - */ - sfp = kmem_alloc(ifp->if_bytes, KM_SLEEP); - memcpy(sfp, oldsfp, ifp->if_bytes); - - xfs_idata_realloc(dp, -ifp->if_bytes, XFS_DATA_FORK); - xfs_bmap_local_to_extents_empty(dp, XFS_DATA_FORK); - dp->i_d.di_size = 0; - - /* - * Add block 0 to the inode. - */ - error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, &blkno); - if (error) { - kmem_free(sfp); - return error; - } - /* - * Initialize the data block, then convert it to block format. - */ - error = xfs_dir3_data_init(args, blkno, &bp); - if (error) { - kmem_free(sfp); - return error; - } - xfs_dir3_block_init(mp, tp, bp, dp); - hdr = bp->b_addr; - - /* - * Compute size of block "tail" area. - */ - i = (uint)sizeof(*btp) + - (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t); - /* - * The whole thing is initialized to free by the init routine. - * Say we're using the leaf and tail area. - */ - dup = dp->d_ops->data_unused_p(hdr); - needlog = needscan = 0; - xfs_dir2_data_use_free(args, bp, dup, args->geo->blksize - i, - i, &needlog, &needscan); - ASSERT(needscan == 0); - /* - * Fill in the tail. - */ - btp = xfs_dir2_block_tail_p(args->geo, hdr); - btp->count = cpu_to_be32(sfp->count + 2); /* ., .. */ - btp->stale = 0; - blp = xfs_dir2_block_leaf_p(btp); - endoffset = (uint)((char *)blp - (char *)hdr); - /* - * Remove the freespace, we'll manage it. - */ - xfs_dir2_data_use_free(args, bp, dup, - (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), - be16_to_cpu(dup->length), &needlog, &needscan); - /* - * Create entry for . - */ - dep = dp->d_ops->data_dot_entry_p(hdr); - dep->inumber = cpu_to_be64(dp->i_ino); - dep->namelen = 1; - dep->name[0] = '.'; - dp->d_ops->data_put_ftype(dep, XFS_DIR3_FT_DIR); - tagp = dp->d_ops->data_entry_tag_p(dep); - *tagp = cpu_to_be16((char *)dep - (char *)hdr); - xfs_dir2_data_log_entry(args, bp, dep); - blp[0].hashval = cpu_to_be32(xfs_dir_hash_dot); - blp[0].address = cpu_to_be32(xfs_dir2_byte_to_dataptr( - (char *)dep - (char *)hdr)); - /* - * Create entry for .. - */ - dep = dp->d_ops->data_dotdot_entry_p(hdr); - dep->inumber = cpu_to_be64(dp->d_ops->sf_get_parent_ino(sfp)); - dep->namelen = 2; - dep->name[0] = dep->name[1] = '.'; - dp->d_ops->data_put_ftype(dep, XFS_DIR3_FT_DIR); - tagp = dp->d_ops->data_entry_tag_p(dep); - *tagp = cpu_to_be16((char *)dep - (char *)hdr); - xfs_dir2_data_log_entry(args, bp, dep); - blp[1].hashval = cpu_to_be32(xfs_dir_hash_dotdot); - blp[1].address = cpu_to_be32(xfs_dir2_byte_to_dataptr( - (char *)dep - (char *)hdr)); - offset = dp->d_ops->data_first_offset; - /* - * Loop over existing entries, stuff them in. - */ - i = 0; - if (!sfp->count) - sfep = NULL; - else - sfep = xfs_dir2_sf_firstentry(sfp); - /* - * Need to preserve the existing offset values in the sf directory. - * Insert holes (unused entries) where necessary. - */ - while (offset < endoffset) { - /* - * sfep is null when we reach the end of the list. - */ - if (sfep == NULL) - newoffset = endoffset; - else - newoffset = xfs_dir2_sf_get_offset(sfep); - /* - * There should be a hole here, make one. - */ - if (offset < newoffset) { - dup = (xfs_dir2_data_unused_t *)((char *)hdr + offset); - dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); - dup->length = cpu_to_be16(newoffset - offset); - *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16( - ((char *)dup - (char *)hdr)); - xfs_dir2_data_log_unused(args, bp, dup); - xfs_dir2_data_freeinsert(hdr, - dp->d_ops->data_bestfree_p(hdr), - dup, &dummy); - offset += be16_to_cpu(dup->length); - continue; - } - /* - * Copy a real entry. - */ - dep = (xfs_dir2_data_entry_t *)((char *)hdr + newoffset); - dep->inumber = cpu_to_be64(dp->d_ops->sf_get_ino(sfp, sfep)); - dep->namelen = sfep->namelen; - dp->d_ops->data_put_ftype(dep, dp->d_ops->sf_get_ftype(sfep)); - memcpy(dep->name, sfep->name, dep->namelen); - tagp = dp->d_ops->data_entry_tag_p(dep); - *tagp = cpu_to_be16((char *)dep - (char *)hdr); - xfs_dir2_data_log_entry(args, bp, dep); - name.name = sfep->name; - name.len = sfep->namelen; - blp[2 + i].hashval = cpu_to_be32(mp->m_dirnameops-> - hashname(&name)); - blp[2 + i].address = cpu_to_be32(xfs_dir2_byte_to_dataptr( - (char *)dep - (char *)hdr)); - offset = (int)((char *)(tagp + 1) - (char *)hdr); - if (++i == sfp->count) - sfep = NULL; - else - sfep = dp->d_ops->sf_nextentry(sfp, sfep); - } - /* Done with the temporary buffer */ - kmem_free(sfp); - /* - * Sort the leaf entries by hash value. - */ - xfs_sort(blp, be32_to_cpu(btp->count), sizeof(*blp), xfs_dir2_block_sort); - /* - * Log the leaf entry area and tail. - * Already logged the header in data_init, ignore needlog. - */ - ASSERT(needscan == 0); - xfs_dir2_block_log_leaf(tp, bp, 0, be32_to_cpu(btp->count) - 1); - xfs_dir2_block_log_tail(tp, bp); - xfs_dir3_data_check(dp, bp); - return 0; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_dir2_data.c b/src/linux/fs/xfs/libxfs/xfs_dir2_data.c deleted file mode 100644 index 725fc78..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_dir2_data.c +++ /dev/null @@ -1,1055 +0,0 @@ -/* - * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. - * Copyright (c) 2013 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_inode.h" -#include "xfs_dir2.h" -#include "xfs_dir2_priv.h" -#include "xfs_error.h" -#include "xfs_trans.h" -#include "xfs_buf_item.h" -#include "xfs_cksum.h" -#include "xfs_log.h" - -/* - * Check the consistency of the data block. - * The input can also be a block-format directory. - * Return 0 is the buffer is good, otherwise an error. - */ -int -__xfs_dir3_data_check( - struct xfs_inode *dp, /* incore inode pointer */ - struct xfs_buf *bp) /* data block's buffer */ -{ - xfs_dir2_dataptr_t addr; /* addr for leaf lookup */ - xfs_dir2_data_free_t *bf; /* bestfree table */ - xfs_dir2_block_tail_t *btp=NULL; /* block tail */ - int count; /* count of entries found */ - xfs_dir2_data_hdr_t *hdr; /* data block header */ - xfs_dir2_data_entry_t *dep; /* data entry */ - xfs_dir2_data_free_t *dfp; /* bestfree entry */ - xfs_dir2_data_unused_t *dup; /* unused entry */ - char *endp; /* end of useful data */ - int freeseen; /* mask of bestfrees seen */ - xfs_dahash_t hash; /* hash of current name */ - int i; /* leaf index */ - int lastfree; /* last entry was unused */ - xfs_dir2_leaf_entry_t *lep=NULL; /* block leaf entries */ - xfs_mount_t *mp; /* filesystem mount point */ - char *p; /* current data position */ - int stale; /* count of stale leaves */ - struct xfs_name name; - const struct xfs_dir_ops *ops; - struct xfs_da_geometry *geo; - - mp = bp->b_target->bt_mount; - geo = mp->m_dir_geo; - - /* - * We can be passed a null dp here from a verifier, so we need to go the - * hard way to get them. - */ - ops = xfs_dir_get_ops(mp, dp); - - hdr = bp->b_addr; - p = (char *)ops->data_entry_p(hdr); - - switch (hdr->magic) { - case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC): - case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): - btp = xfs_dir2_block_tail_p(geo, hdr); - lep = xfs_dir2_block_leaf_p(btp); - endp = (char *)lep; - - /* - * The number of leaf entries is limited by the size of the - * block and the amount of space used by the data entries. - * We don't know how much space is used by the data entries yet, - * so just ensure that the count falls somewhere inside the - * block right now. - */ - XFS_WANT_CORRUPTED_RETURN(mp, be32_to_cpu(btp->count) < - ((char *)btp - p) / sizeof(struct xfs_dir2_leaf_entry)); - break; - case cpu_to_be32(XFS_DIR3_DATA_MAGIC): - case cpu_to_be32(XFS_DIR2_DATA_MAGIC): - endp = (char *)hdr + geo->blksize; - break; - default: - XFS_ERROR_REPORT("Bad Magic", XFS_ERRLEVEL_LOW, mp); - return -EFSCORRUPTED; - } - - /* - * Account for zero bestfree entries. - */ - bf = ops->data_bestfree_p(hdr); - count = lastfree = freeseen = 0; - if (!bf[0].length) { - XFS_WANT_CORRUPTED_RETURN(mp, !bf[0].offset); - freeseen |= 1 << 0; - } - if (!bf[1].length) { - XFS_WANT_CORRUPTED_RETURN(mp, !bf[1].offset); - freeseen |= 1 << 1; - } - if (!bf[2].length) { - XFS_WANT_CORRUPTED_RETURN(mp, !bf[2].offset); - freeseen |= 1 << 2; - } - - XFS_WANT_CORRUPTED_RETURN(mp, be16_to_cpu(bf[0].length) >= - be16_to_cpu(bf[1].length)); - XFS_WANT_CORRUPTED_RETURN(mp, be16_to_cpu(bf[1].length) >= - be16_to_cpu(bf[2].length)); - /* - * Loop over the data/unused entries. - */ - while (p < endp) { - dup = (xfs_dir2_data_unused_t *)p; - /* - * If it's unused, look for the space in the bestfree table. - * If we find it, account for that, else make sure it - * doesn't need to be there. - */ - if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { - XFS_WANT_CORRUPTED_RETURN(mp, lastfree == 0); - XFS_WANT_CORRUPTED_RETURN(mp, - be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup)) == - (char *)dup - (char *)hdr); - dfp = xfs_dir2_data_freefind(hdr, bf, dup); - if (dfp) { - i = (int)(dfp - bf); - XFS_WANT_CORRUPTED_RETURN(mp, - (freeseen & (1 << i)) == 0); - freeseen |= 1 << i; - } else { - XFS_WANT_CORRUPTED_RETURN(mp, - be16_to_cpu(dup->length) <= - be16_to_cpu(bf[2].length)); - } - p += be16_to_cpu(dup->length); - lastfree = 1; - continue; - } - /* - * It's a real entry. Validate the fields. - * If this is a block directory then make sure it's - * in the leaf section of the block. - * The linear search is crude but this is DEBUG code. - */ - dep = (xfs_dir2_data_entry_t *)p; - XFS_WANT_CORRUPTED_RETURN(mp, dep->namelen != 0); - XFS_WANT_CORRUPTED_RETURN(mp, - !xfs_dir_ino_validate(mp, be64_to_cpu(dep->inumber))); - XFS_WANT_CORRUPTED_RETURN(mp, - be16_to_cpu(*ops->data_entry_tag_p(dep)) == - (char *)dep - (char *)hdr); - XFS_WANT_CORRUPTED_RETURN(mp, - ops->data_get_ftype(dep) < XFS_DIR3_FT_MAX); - count++; - lastfree = 0; - if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) { - addr = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, - (xfs_dir2_data_aoff_t) - ((char *)dep - (char *)hdr)); - name.name = dep->name; - name.len = dep->namelen; - hash = mp->m_dirnameops->hashname(&name); - for (i = 0; i < be32_to_cpu(btp->count); i++) { - if (be32_to_cpu(lep[i].address) == addr && - be32_to_cpu(lep[i].hashval) == hash) - break; - } - XFS_WANT_CORRUPTED_RETURN(mp, - i < be32_to_cpu(btp->count)); - } - p += ops->data_entsize(dep->namelen); - } - /* - * Need to have seen all the entries and all the bestfree slots. - */ - XFS_WANT_CORRUPTED_RETURN(mp, freeseen == 7); - if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) { - for (i = stale = 0; i < be32_to_cpu(btp->count); i++) { - if (lep[i].address == - cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) - stale++; - if (i > 0) - XFS_WANT_CORRUPTED_RETURN(mp, - be32_to_cpu(lep[i].hashval) >= - be32_to_cpu(lep[i - 1].hashval)); - } - XFS_WANT_CORRUPTED_RETURN(mp, count == - be32_to_cpu(btp->count) - be32_to_cpu(btp->stale)); - XFS_WANT_CORRUPTED_RETURN(mp, stale == be32_to_cpu(btp->stale)); - } - return 0; -} - -static bool -xfs_dir3_data_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - if (hdr3->magic != cpu_to_be32(XFS_DIR3_DATA_MAGIC)) - return false; - if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid)) - return false; - if (be64_to_cpu(hdr3->blkno) != bp->b_bn) - return false; - if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn))) - return false; - } else { - if (hdr3->magic != cpu_to_be32(XFS_DIR2_DATA_MAGIC)) - return false; - } - if (__xfs_dir3_data_check(NULL, bp)) - return false; - return true; -} - -/* - * Readahead of the first block of the directory when it is opened is completely - * oblivious to the format of the directory. Hence we can either get a block - * format buffer or a data format buffer on readahead. - */ -static void -xfs_dir3_data_reada_verify( - struct xfs_buf *bp) -{ - struct xfs_dir2_data_hdr *hdr = bp->b_addr; - - switch (hdr->magic) { - case cpu_to_be32(XFS_DIR2_BLOCK_MAGIC): - case cpu_to_be32(XFS_DIR3_BLOCK_MAGIC): - bp->b_ops = &xfs_dir3_block_buf_ops; - bp->b_ops->verify_read(bp); - return; - case cpu_to_be32(XFS_DIR2_DATA_MAGIC): - case cpu_to_be32(XFS_DIR3_DATA_MAGIC): - bp->b_ops = &xfs_dir3_data_buf_ops; - bp->b_ops->verify_read(bp); - return; - default: - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - break; - } -} - -static void -xfs_dir3_data_read_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - - if (xfs_sb_version_hascrc(&mp->m_sb) && - !xfs_buf_verify_cksum(bp, XFS_DIR3_DATA_CRC_OFF)) - xfs_buf_ioerror(bp, -EFSBADCRC); - else if (!xfs_dir3_data_verify(bp)) - xfs_buf_ioerror(bp, -EFSCORRUPTED); - - if (bp->b_error) - xfs_verifier_error(bp); -} - -static void -xfs_dir3_data_write_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_buf_log_item *bip = bp->b_fspriv; - struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; - - if (!xfs_dir3_data_verify(bp)) { - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - return; - } - - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return; - - if (bip) - hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn); - - xfs_buf_update_cksum(bp, XFS_DIR3_DATA_CRC_OFF); -} - -const struct xfs_buf_ops xfs_dir3_data_buf_ops = { - .name = "xfs_dir3_data", - .verify_read = xfs_dir3_data_read_verify, - .verify_write = xfs_dir3_data_write_verify, -}; - -static const struct xfs_buf_ops xfs_dir3_data_reada_buf_ops = { - .name = "xfs_dir3_data_reada", - .verify_read = xfs_dir3_data_reada_verify, - .verify_write = xfs_dir3_data_write_verify, -}; - - -int -xfs_dir3_data_read( - struct xfs_trans *tp, - struct xfs_inode *dp, - xfs_dablk_t bno, - xfs_daddr_t mapped_bno, - struct xfs_buf **bpp) -{ - int err; - - err = xfs_da_read_buf(tp, dp, bno, mapped_bno, bpp, - XFS_DATA_FORK, &xfs_dir3_data_buf_ops); - if (!err && tp) - xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_DATA_BUF); - return err; -} - -int -xfs_dir3_data_readahead( - struct xfs_inode *dp, - xfs_dablk_t bno, - xfs_daddr_t mapped_bno) -{ - return xfs_da_reada_buf(dp, bno, mapped_bno, - XFS_DATA_FORK, &xfs_dir3_data_reada_buf_ops); -} - -/* - * Given a data block and an unused entry from that block, - * return the bestfree entry if any that corresponds to it. - */ -xfs_dir2_data_free_t * -xfs_dir2_data_freefind( - struct xfs_dir2_data_hdr *hdr, /* data block header */ - struct xfs_dir2_data_free *bf, /* bestfree table pointer */ - struct xfs_dir2_data_unused *dup) /* unused space */ -{ - xfs_dir2_data_free_t *dfp; /* bestfree entry */ - xfs_dir2_data_aoff_t off; /* offset value needed */ -#ifdef DEBUG - int matched; /* matched the value */ - int seenzero; /* saw a 0 bestfree entry */ -#endif - - off = (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr); - -#ifdef DEBUG - /* - * Validate some consistency in the bestfree table. - * Check order, non-overlapping entries, and if we find the - * one we're looking for it has to be exact. - */ - ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); - for (dfp = &bf[0], seenzero = matched = 0; - dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; - dfp++) { - if (!dfp->offset) { - ASSERT(!dfp->length); - seenzero = 1; - continue; - } - ASSERT(seenzero == 0); - if (be16_to_cpu(dfp->offset) == off) { - matched = 1; - ASSERT(dfp->length == dup->length); - } else if (off < be16_to_cpu(dfp->offset)) - ASSERT(off + be16_to_cpu(dup->length) <= be16_to_cpu(dfp->offset)); - else - ASSERT(be16_to_cpu(dfp->offset) + be16_to_cpu(dfp->length) <= off); - ASSERT(matched || be16_to_cpu(dfp->length) >= be16_to_cpu(dup->length)); - if (dfp > &bf[0]) - ASSERT(be16_to_cpu(dfp[-1].length) >= be16_to_cpu(dfp[0].length)); - } -#endif - /* - * If this is smaller than the smallest bestfree entry, - * it can't be there since they're sorted. - */ - if (be16_to_cpu(dup->length) < - be16_to_cpu(bf[XFS_DIR2_DATA_FD_COUNT - 1].length)) - return NULL; - /* - * Look at the three bestfree entries for our guy. - */ - for (dfp = &bf[0]; dfp < &bf[XFS_DIR2_DATA_FD_COUNT]; dfp++) { - if (!dfp->offset) - return NULL; - if (be16_to_cpu(dfp->offset) == off) - return dfp; - } - /* - * Didn't find it. This only happens if there are duplicate lengths. - */ - return NULL; -} - -/* - * Insert an unused-space entry into the bestfree table. - */ -xfs_dir2_data_free_t * /* entry inserted */ -xfs_dir2_data_freeinsert( - struct xfs_dir2_data_hdr *hdr, /* data block pointer */ - struct xfs_dir2_data_free *dfp, /* bestfree table pointer */ - struct xfs_dir2_data_unused *dup, /* unused space */ - int *loghead) /* log the data header (out) */ -{ - xfs_dir2_data_free_t new; /* new bestfree entry */ - - ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); - - new.length = dup->length; - new.offset = cpu_to_be16((char *)dup - (char *)hdr); - - /* - * Insert at position 0, 1, or 2; or not at all. - */ - if (be16_to_cpu(new.length) > be16_to_cpu(dfp[0].length)) { - dfp[2] = dfp[1]; - dfp[1] = dfp[0]; - dfp[0] = new; - *loghead = 1; - return &dfp[0]; - } - if (be16_to_cpu(new.length) > be16_to_cpu(dfp[1].length)) { - dfp[2] = dfp[1]; - dfp[1] = new; - *loghead = 1; - return &dfp[1]; - } - if (be16_to_cpu(new.length) > be16_to_cpu(dfp[2].length)) { - dfp[2] = new; - *loghead = 1; - return &dfp[2]; - } - return NULL; -} - -/* - * Remove a bestfree entry from the table. - */ -STATIC void -xfs_dir2_data_freeremove( - struct xfs_dir2_data_hdr *hdr, /* data block header */ - struct xfs_dir2_data_free *bf, /* bestfree table pointer */ - struct xfs_dir2_data_free *dfp, /* bestfree entry pointer */ - int *loghead) /* out: log data header */ -{ - - ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); - - /* - * It's the first entry, slide the next 2 up. - */ - if (dfp == &bf[0]) { - bf[0] = bf[1]; - bf[1] = bf[2]; - } - /* - * It's the second entry, slide the 3rd entry up. - */ - else if (dfp == &bf[1]) - bf[1] = bf[2]; - /* - * Must be the last entry. - */ - else - ASSERT(dfp == &bf[2]); - /* - * Clear the 3rd entry, must be zero now. - */ - bf[2].length = 0; - bf[2].offset = 0; - *loghead = 1; -} - -/* - * Given a data block, reconstruct its bestfree map. - */ -void -xfs_dir2_data_freescan( - struct xfs_inode *dp, - struct xfs_dir2_data_hdr *hdr, - int *loghead) -{ - xfs_dir2_block_tail_t *btp; /* block tail */ - xfs_dir2_data_entry_t *dep; /* active data entry */ - xfs_dir2_data_unused_t *dup; /* unused data entry */ - struct xfs_dir2_data_free *bf; - char *endp; /* end of block's data */ - char *p; /* current entry pointer */ - struct xfs_da_geometry *geo = dp->i_mount->m_dir_geo; - - ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); - - /* - * Start by clearing the table. - */ - bf = dp->d_ops->data_bestfree_p(hdr); - memset(bf, 0, sizeof(*bf) * XFS_DIR2_DATA_FD_COUNT); - *loghead = 1; - /* - * Set up pointers. - */ - p = (char *)dp->d_ops->data_entry_p(hdr); - if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)) { - btp = xfs_dir2_block_tail_p(geo, hdr); - endp = (char *)xfs_dir2_block_leaf_p(btp); - } else - endp = (char *)hdr + geo->blksize; - /* - * Loop over the block's entries. - */ - while (p < endp) { - dup = (xfs_dir2_data_unused_t *)p; - /* - * If it's a free entry, insert it. - */ - if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { - ASSERT((char *)dup - (char *)hdr == - be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup))); - xfs_dir2_data_freeinsert(hdr, bf, dup, loghead); - p += be16_to_cpu(dup->length); - } - /* - * For active entries, check their tags and skip them. - */ - else { - dep = (xfs_dir2_data_entry_t *)p; - ASSERT((char *)dep - (char *)hdr == - be16_to_cpu(*dp->d_ops->data_entry_tag_p(dep))); - p += dp->d_ops->data_entsize(dep->namelen); - } - } -} - -/* - * Initialize a data block at the given block number in the directory. - * Give back the buffer for the created block. - */ -int /* error */ -xfs_dir3_data_init( - xfs_da_args_t *args, /* directory operation args */ - xfs_dir2_db_t blkno, /* logical dir block number */ - struct xfs_buf **bpp) /* output block buffer */ -{ - struct xfs_buf *bp; /* block buffer */ - xfs_dir2_data_hdr_t *hdr; /* data block header */ - xfs_inode_t *dp; /* incore directory inode */ - xfs_dir2_data_unused_t *dup; /* unused entry pointer */ - struct xfs_dir2_data_free *bf; - int error; /* error return value */ - int i; /* bestfree index */ - xfs_mount_t *mp; /* filesystem mount point */ - xfs_trans_t *tp; /* transaction pointer */ - int t; /* temp */ - - dp = args->dp; - mp = dp->i_mount; - tp = args->trans; - /* - * Get the buffer set up for the block. - */ - error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, blkno), - -1, &bp, XFS_DATA_FORK); - if (error) - return error; - bp->b_ops = &xfs_dir3_data_buf_ops; - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_DATA_BUF); - - /* - * Initialize the header. - */ - hdr = bp->b_addr; - if (xfs_sb_version_hascrc(&mp->m_sb)) { - struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; - - memset(hdr3, 0, sizeof(*hdr3)); - hdr3->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC); - hdr3->blkno = cpu_to_be64(bp->b_bn); - hdr3->owner = cpu_to_be64(dp->i_ino); - uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid); - - } else - hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC); - - bf = dp->d_ops->data_bestfree_p(hdr); - bf[0].offset = cpu_to_be16(dp->d_ops->data_entry_offset); - for (i = 1; i < XFS_DIR2_DATA_FD_COUNT; i++) { - bf[i].length = 0; - bf[i].offset = 0; - } - - /* - * Set up an unused entry for the block's body. - */ - dup = dp->d_ops->data_unused_p(hdr); - dup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); - - t = args->geo->blksize - (uint)dp->d_ops->data_entry_offset; - bf[0].length = cpu_to_be16(t); - dup->length = cpu_to_be16(t); - *xfs_dir2_data_unused_tag_p(dup) = cpu_to_be16((char *)dup - (char *)hdr); - /* - * Log it and return it. - */ - xfs_dir2_data_log_header(args, bp); - xfs_dir2_data_log_unused(args, bp, dup); - *bpp = bp; - return 0; -} - -/* - * Log an active data entry from the block. - */ -void -xfs_dir2_data_log_entry( - struct xfs_da_args *args, - struct xfs_buf *bp, - xfs_dir2_data_entry_t *dep) /* data entry pointer */ -{ - struct xfs_dir2_data_hdr *hdr = bp->b_addr; - - ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); - - xfs_trans_log_buf(args->trans, bp, (uint)((char *)dep - (char *)hdr), - (uint)((char *)(args->dp->d_ops->data_entry_tag_p(dep) + 1) - - (char *)hdr - 1)); -} - -/* - * Log a data block header. - */ -void -xfs_dir2_data_log_header( - struct xfs_da_args *args, - struct xfs_buf *bp) -{ -#ifdef DEBUG - struct xfs_dir2_data_hdr *hdr = bp->b_addr; - - ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); -#endif - - xfs_trans_log_buf(args->trans, bp, 0, - args->dp->d_ops->data_entry_offset - 1); -} - -/* - * Log a data unused entry. - */ -void -xfs_dir2_data_log_unused( - struct xfs_da_args *args, - struct xfs_buf *bp, - xfs_dir2_data_unused_t *dup) /* data unused pointer */ -{ - xfs_dir2_data_hdr_t *hdr = bp->b_addr; - - ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); - - /* - * Log the first part of the unused entry. - */ - xfs_trans_log_buf(args->trans, bp, (uint)((char *)dup - (char *)hdr), - (uint)((char *)&dup->length + sizeof(dup->length) - - 1 - (char *)hdr)); - /* - * Log the end (tag) of the unused entry. - */ - xfs_trans_log_buf(args->trans, bp, - (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr), - (uint)((char *)xfs_dir2_data_unused_tag_p(dup) - (char *)hdr + - sizeof(xfs_dir2_data_off_t) - 1)); -} - -/* - * Make a byte range in the data block unused. - * Its current contents are unimportant. - */ -void -xfs_dir2_data_make_free( - struct xfs_da_args *args, - struct xfs_buf *bp, - xfs_dir2_data_aoff_t offset, /* starting byte offset */ - xfs_dir2_data_aoff_t len, /* length in bytes */ - int *needlogp, /* out: log header */ - int *needscanp) /* out: regen bestfree */ -{ - xfs_dir2_data_hdr_t *hdr; /* data block pointer */ - xfs_dir2_data_free_t *dfp; /* bestfree pointer */ - char *endptr; /* end of data area */ - int needscan; /* need to regen bestfree */ - xfs_dir2_data_unused_t *newdup; /* new unused entry */ - xfs_dir2_data_unused_t *postdup; /* unused entry after us */ - xfs_dir2_data_unused_t *prevdup; /* unused entry before us */ - struct xfs_dir2_data_free *bf; - - hdr = bp->b_addr; - - /* - * Figure out where the end of the data area is. - */ - if (hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC)) - endptr = (char *)hdr + args->geo->blksize; - else { - xfs_dir2_block_tail_t *btp; /* block tail */ - - ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); - btp = xfs_dir2_block_tail_p(args->geo, hdr); - endptr = (char *)xfs_dir2_block_leaf_p(btp); - } - /* - * If this isn't the start of the block, then back up to - * the previous entry and see if it's free. - */ - if (offset > args->dp->d_ops->data_entry_offset) { - __be16 *tagp; /* tag just before us */ - - tagp = (__be16 *)((char *)hdr + offset) - 1; - prevdup = (xfs_dir2_data_unused_t *)((char *)hdr + be16_to_cpu(*tagp)); - if (be16_to_cpu(prevdup->freetag) != XFS_DIR2_DATA_FREE_TAG) - prevdup = NULL; - } else - prevdup = NULL; - /* - * If this isn't the end of the block, see if the entry after - * us is free. - */ - if ((char *)hdr + offset + len < endptr) { - postdup = - (xfs_dir2_data_unused_t *)((char *)hdr + offset + len); - if (be16_to_cpu(postdup->freetag) != XFS_DIR2_DATA_FREE_TAG) - postdup = NULL; - } else - postdup = NULL; - ASSERT(*needscanp == 0); - needscan = 0; - /* - * Previous and following entries are both free, - * merge everything into a single free entry. - */ - bf = args->dp->d_ops->data_bestfree_p(hdr); - if (prevdup && postdup) { - xfs_dir2_data_free_t *dfp2; /* another bestfree pointer */ - - /* - * See if prevdup and/or postdup are in bestfree table. - */ - dfp = xfs_dir2_data_freefind(hdr, bf, prevdup); - dfp2 = xfs_dir2_data_freefind(hdr, bf, postdup); - /* - * We need a rescan unless there are exactly 2 free entries - * namely our two. Then we know what's happening, otherwise - * since the third bestfree is there, there might be more - * entries. - */ - needscan = (bf[2].length != 0); - /* - * Fix up the new big freespace. - */ - be16_add_cpu(&prevdup->length, len + be16_to_cpu(postdup->length)); - *xfs_dir2_data_unused_tag_p(prevdup) = - cpu_to_be16((char *)prevdup - (char *)hdr); - xfs_dir2_data_log_unused(args, bp, prevdup); - if (!needscan) { - /* - * Has to be the case that entries 0 and 1 are - * dfp and dfp2 (don't know which is which), and - * entry 2 is empty. - * Remove entry 1 first then entry 0. - */ - ASSERT(dfp && dfp2); - if (dfp == &bf[1]) { - dfp = &bf[0]; - ASSERT(dfp2 == dfp); - dfp2 = &bf[1]; - } - xfs_dir2_data_freeremove(hdr, bf, dfp2, needlogp); - xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); - /* - * Now insert the new entry. - */ - dfp = xfs_dir2_data_freeinsert(hdr, bf, prevdup, - needlogp); - ASSERT(dfp == &bf[0]); - ASSERT(dfp->length == prevdup->length); - ASSERT(!dfp[1].length); - ASSERT(!dfp[2].length); - } - } - /* - * The entry before us is free, merge with it. - */ - else if (prevdup) { - dfp = xfs_dir2_data_freefind(hdr, bf, prevdup); - be16_add_cpu(&prevdup->length, len); - *xfs_dir2_data_unused_tag_p(prevdup) = - cpu_to_be16((char *)prevdup - (char *)hdr); - xfs_dir2_data_log_unused(args, bp, prevdup); - /* - * If the previous entry was in the table, the new entry - * is longer, so it will be in the table too. Remove - * the old one and add the new one. - */ - if (dfp) { - xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); - xfs_dir2_data_freeinsert(hdr, bf, prevdup, needlogp); - } - /* - * Otherwise we need a scan if the new entry is big enough. - */ - else { - needscan = be16_to_cpu(prevdup->length) > - be16_to_cpu(bf[2].length); - } - } - /* - * The following entry is free, merge with it. - */ - else if (postdup) { - dfp = xfs_dir2_data_freefind(hdr, bf, postdup); - newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset); - newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); - newdup->length = cpu_to_be16(len + be16_to_cpu(postdup->length)); - *xfs_dir2_data_unused_tag_p(newdup) = - cpu_to_be16((char *)newdup - (char *)hdr); - xfs_dir2_data_log_unused(args, bp, newdup); - /* - * If the following entry was in the table, the new entry - * is longer, so it will be in the table too. Remove - * the old one and add the new one. - */ - if (dfp) { - xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); - xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp); - } - /* - * Otherwise we need a scan if the new entry is big enough. - */ - else { - needscan = be16_to_cpu(newdup->length) > - be16_to_cpu(bf[2].length); - } - } - /* - * Neither neighbor is free. Make a new entry. - */ - else { - newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset); - newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); - newdup->length = cpu_to_be16(len); - *xfs_dir2_data_unused_tag_p(newdup) = - cpu_to_be16((char *)newdup - (char *)hdr); - xfs_dir2_data_log_unused(args, bp, newdup); - xfs_dir2_data_freeinsert(hdr, bf, newdup, needlogp); - } - *needscanp = needscan; -} - -/* - * Take a byte range out of an existing unused space and make it un-free. - */ -void -xfs_dir2_data_use_free( - struct xfs_da_args *args, - struct xfs_buf *bp, - xfs_dir2_data_unused_t *dup, /* unused entry */ - xfs_dir2_data_aoff_t offset, /* starting offset to use */ - xfs_dir2_data_aoff_t len, /* length to use */ - int *needlogp, /* out: need to log header */ - int *needscanp) /* out: need regen bestfree */ -{ - xfs_dir2_data_hdr_t *hdr; /* data block header */ - xfs_dir2_data_free_t *dfp; /* bestfree pointer */ - int matchback; /* matches end of freespace */ - int matchfront; /* matches start of freespace */ - int needscan; /* need to regen bestfree */ - xfs_dir2_data_unused_t *newdup; /* new unused entry */ - xfs_dir2_data_unused_t *newdup2; /* another new unused entry */ - int oldlen; /* old unused entry's length */ - struct xfs_dir2_data_free *bf; - - hdr = bp->b_addr; - ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_BLOCK_MAGIC)); - ASSERT(be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG); - ASSERT(offset >= (char *)dup - (char *)hdr); - ASSERT(offset + len <= (char *)dup + be16_to_cpu(dup->length) - (char *)hdr); - ASSERT((char *)dup - (char *)hdr == be16_to_cpu(*xfs_dir2_data_unused_tag_p(dup))); - /* - * Look up the entry in the bestfree table. - */ - oldlen = be16_to_cpu(dup->length); - bf = args->dp->d_ops->data_bestfree_p(hdr); - dfp = xfs_dir2_data_freefind(hdr, bf, dup); - ASSERT(dfp || oldlen <= be16_to_cpu(bf[2].length)); - /* - * Check for alignment with front and back of the entry. - */ - matchfront = (char *)dup - (char *)hdr == offset; - matchback = (char *)dup + oldlen - (char *)hdr == offset + len; - ASSERT(*needscanp == 0); - needscan = 0; - /* - * If we matched it exactly we just need to get rid of it from - * the bestfree table. - */ - if (matchfront && matchback) { - if (dfp) { - needscan = (bf[2].offset != 0); - if (!needscan) - xfs_dir2_data_freeremove(hdr, bf, dfp, - needlogp); - } - } - /* - * We match the first part of the entry. - * Make a new entry with the remaining freespace. - */ - else if (matchfront) { - newdup = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len); - newdup->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); - newdup->length = cpu_to_be16(oldlen - len); - *xfs_dir2_data_unused_tag_p(newdup) = - cpu_to_be16((char *)newdup - (char *)hdr); - xfs_dir2_data_log_unused(args, bp, newdup); - /* - * If it was in the table, remove it and add the new one. - */ - if (dfp) { - xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); - dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup, - needlogp); - ASSERT(dfp != NULL); - ASSERT(dfp->length == newdup->length); - ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr); - /* - * If we got inserted at the last slot, - * that means we don't know if there was a better - * choice for the last slot, or not. Rescan. - */ - needscan = dfp == &bf[2]; - } - } - /* - * We match the last part of the entry. - * Trim the allocated space off the tail of the entry. - */ - else if (matchback) { - newdup = dup; - newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup); - *xfs_dir2_data_unused_tag_p(newdup) = - cpu_to_be16((char *)newdup - (char *)hdr); - xfs_dir2_data_log_unused(args, bp, newdup); - /* - * If it was in the table, remove it and add the new one. - */ - if (dfp) { - xfs_dir2_data_freeremove(hdr, bf, dfp, needlogp); - dfp = xfs_dir2_data_freeinsert(hdr, bf, newdup, - needlogp); - ASSERT(dfp != NULL); - ASSERT(dfp->length == newdup->length); - ASSERT(be16_to_cpu(dfp->offset) == (char *)newdup - (char *)hdr); - /* - * If we got inserted at the last slot, - * that means we don't know if there was a better - * choice for the last slot, or not. Rescan. - */ - needscan = dfp == &bf[2]; - } - } - /* - * Poking out the middle of an entry. - * Make two new entries. - */ - else { - newdup = dup; - newdup->length = cpu_to_be16(((char *)hdr + offset) - (char *)newdup); - *xfs_dir2_data_unused_tag_p(newdup) = - cpu_to_be16((char *)newdup - (char *)hdr); - xfs_dir2_data_log_unused(args, bp, newdup); - newdup2 = (xfs_dir2_data_unused_t *)((char *)hdr + offset + len); - newdup2->freetag = cpu_to_be16(XFS_DIR2_DATA_FREE_TAG); - newdup2->length = cpu_to_be16(oldlen - len - be16_to_cpu(newdup->length)); - *xfs_dir2_data_unused_tag_p(newdup2) = - cpu_to_be16((char *)newdup2 - (char *)hdr); - xfs_dir2_data_log_unused(args, bp, newdup2); - /* - * If the old entry was in the table, we need to scan - * if the 3rd entry was valid, since these entries - * are smaller than the old one. - * If we don't need to scan that means there were 1 or 2 - * entries in the table, and removing the old and adding - * the 2 new will work. - */ - if (dfp) { - needscan = (bf[2].length != 0); - if (!needscan) { - xfs_dir2_data_freeremove(hdr, bf, dfp, - needlogp); - xfs_dir2_data_freeinsert(hdr, bf, newdup, - needlogp); - xfs_dir2_data_freeinsert(hdr, bf, newdup2, - needlogp); - } - } - } - *needscanp = needscan; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_dir2_leaf.c b/src/linux/fs/xfs/libxfs/xfs_dir2_leaf.c deleted file mode 100644 index b887fb2..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_dir2_leaf.c +++ /dev/null @@ -1,1824 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * Copyright (c) 2013 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_inode.h" -#include "xfs_bmap.h" -#include "xfs_dir2.h" -#include "xfs_dir2_priv.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_trans.h" -#include "xfs_buf_item.h" -#include "xfs_cksum.h" -#include "xfs_log.h" - -/* - * Local function declarations. - */ -static int xfs_dir2_leaf_lookup_int(xfs_da_args_t *args, struct xfs_buf **lbpp, - int *indexp, struct xfs_buf **dbpp); -static void xfs_dir3_leaf_log_bests(struct xfs_da_args *args, - struct xfs_buf *bp, int first, int last); -static void xfs_dir3_leaf_log_tail(struct xfs_da_args *args, - struct xfs_buf *bp); - -/* - * Check the internal consistency of a leaf1 block. - * Pop an assert if something is wrong. - */ -#ifdef DEBUG -#define xfs_dir3_leaf_check(dp, bp) \ -do { \ - if (!xfs_dir3_leaf1_check((dp), (bp))) \ - ASSERT(0); \ -} while (0); - -STATIC bool -xfs_dir3_leaf1_check( - struct xfs_inode *dp, - struct xfs_buf *bp) -{ - struct xfs_dir2_leaf *leaf = bp->b_addr; - struct xfs_dir3_icleaf_hdr leafhdr; - - dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); - - if (leafhdr.magic == XFS_DIR3_LEAF1_MAGIC) { - struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr; - if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn) - return false; - } else if (leafhdr.magic != XFS_DIR2_LEAF1_MAGIC) - return false; - - return xfs_dir3_leaf_check_int(dp->i_mount, dp, &leafhdr, leaf); -} -#else -#define xfs_dir3_leaf_check(dp, bp) -#endif - -bool -xfs_dir3_leaf_check_int( - struct xfs_mount *mp, - struct xfs_inode *dp, - struct xfs_dir3_icleaf_hdr *hdr, - struct xfs_dir2_leaf *leaf) -{ - struct xfs_dir2_leaf_entry *ents; - xfs_dir2_leaf_tail_t *ltp; - int stale; - int i; - const struct xfs_dir_ops *ops; - struct xfs_dir3_icleaf_hdr leafhdr; - struct xfs_da_geometry *geo = mp->m_dir_geo; - - /* - * we can be passed a null dp here from a verifier, so we need to go the - * hard way to get them. - */ - ops = xfs_dir_get_ops(mp, dp); - - if (!hdr) { - ops->leaf_hdr_from_disk(&leafhdr, leaf); - hdr = &leafhdr; - } - - ents = ops->leaf_ents_p(leaf); - ltp = xfs_dir2_leaf_tail_p(geo, leaf); - - /* - * XXX (dgc): This value is not restrictive enough. - * Should factor in the size of the bests table as well. - * We can deduce a value for that from di_size. - */ - if (hdr->count > ops->leaf_max_ents(geo)) - return false; - - /* Leaves and bests don't overlap in leaf format. */ - if ((hdr->magic == XFS_DIR2_LEAF1_MAGIC || - hdr->magic == XFS_DIR3_LEAF1_MAGIC) && - (char *)&ents[hdr->count] > (char *)xfs_dir2_leaf_bests_p(ltp)) - return false; - - /* Check hash value order, count stale entries. */ - for (i = stale = 0; i < hdr->count; i++) { - if (i + 1 < hdr->count) { - if (be32_to_cpu(ents[i].hashval) > - be32_to_cpu(ents[i + 1].hashval)) - return false; - } - if (ents[i].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) - stale++; - } - if (hdr->stale != stale) - return false; - return true; -} - -/* - * We verify the magic numbers before decoding the leaf header so that on debug - * kernels we don't get assertion failures in xfs_dir3_leaf_hdr_from_disk() due - * to incorrect magic numbers. - */ -static bool -xfs_dir3_leaf_verify( - struct xfs_buf *bp, - __uint16_t magic) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_dir2_leaf *leaf = bp->b_addr; - - ASSERT(magic == XFS_DIR2_LEAF1_MAGIC || magic == XFS_DIR2_LEAFN_MAGIC); - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr; - __uint16_t magic3; - - magic3 = (magic == XFS_DIR2_LEAF1_MAGIC) ? XFS_DIR3_LEAF1_MAGIC - : XFS_DIR3_LEAFN_MAGIC; - - if (leaf3->info.hdr.magic != cpu_to_be16(magic3)) - return false; - if (!uuid_equal(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid)) - return false; - if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn) - return false; - if (!xfs_log_check_lsn(mp, be64_to_cpu(leaf3->info.lsn))) - return false; - } else { - if (leaf->hdr.info.magic != cpu_to_be16(magic)) - return false; - } - - return xfs_dir3_leaf_check_int(mp, NULL, NULL, leaf); -} - -static void -__read_verify( - struct xfs_buf *bp, - __uint16_t magic) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - - if (xfs_sb_version_hascrc(&mp->m_sb) && - !xfs_buf_verify_cksum(bp, XFS_DIR3_LEAF_CRC_OFF)) - xfs_buf_ioerror(bp, -EFSBADCRC); - else if (!xfs_dir3_leaf_verify(bp, magic)) - xfs_buf_ioerror(bp, -EFSCORRUPTED); - - if (bp->b_error) - xfs_verifier_error(bp); -} - -static void -__write_verify( - struct xfs_buf *bp, - __uint16_t magic) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_buf_log_item *bip = bp->b_fspriv; - struct xfs_dir3_leaf_hdr *hdr3 = bp->b_addr; - - if (!xfs_dir3_leaf_verify(bp, magic)) { - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - return; - } - - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return; - - if (bip) - hdr3->info.lsn = cpu_to_be64(bip->bli_item.li_lsn); - - xfs_buf_update_cksum(bp, XFS_DIR3_LEAF_CRC_OFF); -} - -static void -xfs_dir3_leaf1_read_verify( - struct xfs_buf *bp) -{ - __read_verify(bp, XFS_DIR2_LEAF1_MAGIC); -} - -static void -xfs_dir3_leaf1_write_verify( - struct xfs_buf *bp) -{ - __write_verify(bp, XFS_DIR2_LEAF1_MAGIC); -} - -static void -xfs_dir3_leafn_read_verify( - struct xfs_buf *bp) -{ - __read_verify(bp, XFS_DIR2_LEAFN_MAGIC); -} - -static void -xfs_dir3_leafn_write_verify( - struct xfs_buf *bp) -{ - __write_verify(bp, XFS_DIR2_LEAFN_MAGIC); -} - -const struct xfs_buf_ops xfs_dir3_leaf1_buf_ops = { - .name = "xfs_dir3_leaf1", - .verify_read = xfs_dir3_leaf1_read_verify, - .verify_write = xfs_dir3_leaf1_write_verify, -}; - -const struct xfs_buf_ops xfs_dir3_leafn_buf_ops = { - .name = "xfs_dir3_leafn", - .verify_read = xfs_dir3_leafn_read_verify, - .verify_write = xfs_dir3_leafn_write_verify, -}; - -static int -xfs_dir3_leaf_read( - struct xfs_trans *tp, - struct xfs_inode *dp, - xfs_dablk_t fbno, - xfs_daddr_t mappedbno, - struct xfs_buf **bpp) -{ - int err; - - err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, - XFS_DATA_FORK, &xfs_dir3_leaf1_buf_ops); - if (!err && tp) - xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_LEAF1_BUF); - return err; -} - -int -xfs_dir3_leafn_read( - struct xfs_trans *tp, - struct xfs_inode *dp, - xfs_dablk_t fbno, - xfs_daddr_t mappedbno, - struct xfs_buf **bpp) -{ - int err; - - err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, - XFS_DATA_FORK, &xfs_dir3_leafn_buf_ops); - if (!err && tp) - xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_LEAFN_BUF); - return err; -} - -/* - * Initialize a new leaf block, leaf1 or leafn magic accepted. - */ -static void -xfs_dir3_leaf_init( - struct xfs_mount *mp, - struct xfs_trans *tp, - struct xfs_buf *bp, - xfs_ino_t owner, - __uint16_t type) -{ - struct xfs_dir2_leaf *leaf = bp->b_addr; - - ASSERT(type == XFS_DIR2_LEAF1_MAGIC || type == XFS_DIR2_LEAFN_MAGIC); - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr; - - memset(leaf3, 0, sizeof(*leaf3)); - - leaf3->info.hdr.magic = (type == XFS_DIR2_LEAF1_MAGIC) - ? cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) - : cpu_to_be16(XFS_DIR3_LEAFN_MAGIC); - leaf3->info.blkno = cpu_to_be64(bp->b_bn); - leaf3->info.owner = cpu_to_be64(owner); - uuid_copy(&leaf3->info.uuid, &mp->m_sb.sb_meta_uuid); - } else { - memset(leaf, 0, sizeof(*leaf)); - leaf->hdr.info.magic = cpu_to_be16(type); - } - - /* - * If it's a leaf-format directory initialize the tail. - * Caller is responsible for initialising the bests table. - */ - if (type == XFS_DIR2_LEAF1_MAGIC) { - struct xfs_dir2_leaf_tail *ltp; - - ltp = xfs_dir2_leaf_tail_p(mp->m_dir_geo, leaf); - ltp->bestcount = 0; - bp->b_ops = &xfs_dir3_leaf1_buf_ops; - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_LEAF1_BUF); - } else { - bp->b_ops = &xfs_dir3_leafn_buf_ops; - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_LEAFN_BUF); - } -} - -int -xfs_dir3_leaf_get_buf( - xfs_da_args_t *args, - xfs_dir2_db_t bno, - struct xfs_buf **bpp, - __uint16_t magic) -{ - struct xfs_inode *dp = args->dp; - struct xfs_trans *tp = args->trans; - struct xfs_mount *mp = dp->i_mount; - struct xfs_buf *bp; - int error; - - ASSERT(magic == XFS_DIR2_LEAF1_MAGIC || magic == XFS_DIR2_LEAFN_MAGIC); - ASSERT(bno >= xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET) && - bno < xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET)); - - error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, bno), - -1, &bp, XFS_DATA_FORK); - if (error) - return error; - - xfs_dir3_leaf_init(mp, tp, bp, dp->i_ino, magic); - xfs_dir3_leaf_log_header(args, bp); - if (magic == XFS_DIR2_LEAF1_MAGIC) - xfs_dir3_leaf_log_tail(args, bp); - *bpp = bp; - return 0; -} - -/* - * Convert a block form directory to a leaf form directory. - */ -int /* error */ -xfs_dir2_block_to_leaf( - xfs_da_args_t *args, /* operation arguments */ - struct xfs_buf *dbp) /* input block's buffer */ -{ - __be16 *bestsp; /* leaf's bestsp entries */ - xfs_dablk_t blkno; /* leaf block's bno */ - xfs_dir2_data_hdr_t *hdr; /* block header */ - xfs_dir2_leaf_entry_t *blp; /* block's leaf entries */ - xfs_dir2_block_tail_t *btp; /* block's tail */ - xfs_inode_t *dp; /* incore directory inode */ - int error; /* error return code */ - struct xfs_buf *lbp; /* leaf block's buffer */ - xfs_dir2_db_t ldb; /* leaf block's bno */ - xfs_dir2_leaf_t *leaf; /* leaf structure */ - xfs_dir2_leaf_tail_t *ltp; /* leaf's tail */ - int needlog; /* need to log block header */ - int needscan; /* need to rescan bestfree */ - xfs_trans_t *tp; /* transaction pointer */ - struct xfs_dir2_data_free *bf; - struct xfs_dir2_leaf_entry *ents; - struct xfs_dir3_icleaf_hdr leafhdr; - - trace_xfs_dir2_block_to_leaf(args); - - dp = args->dp; - tp = args->trans; - /* - * Add the leaf block to the inode. - * This interface will only put blocks in the leaf/node range. - * Since that's empty now, we'll get the root (block 0 in range). - */ - if ((error = xfs_da_grow_inode(args, &blkno))) { - return error; - } - ldb = xfs_dir2_da_to_db(args->geo, blkno); - ASSERT(ldb == xfs_dir2_byte_to_db(args->geo, XFS_DIR2_LEAF_OFFSET)); - /* - * Initialize the leaf block, get a buffer for it. - */ - error = xfs_dir3_leaf_get_buf(args, ldb, &lbp, XFS_DIR2_LEAF1_MAGIC); - if (error) - return error; - - leaf = lbp->b_addr; - hdr = dbp->b_addr; - xfs_dir3_data_check(dp, dbp); - btp = xfs_dir2_block_tail_p(args->geo, hdr); - blp = xfs_dir2_block_leaf_p(btp); - bf = dp->d_ops->data_bestfree_p(hdr); - ents = dp->d_ops->leaf_ents_p(leaf); - - /* - * Set the counts in the leaf header. - */ - dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); - leafhdr.count = be32_to_cpu(btp->count); - leafhdr.stale = be32_to_cpu(btp->stale); - dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr); - xfs_dir3_leaf_log_header(args, lbp); - - /* - * Could compact these but I think we always do the conversion - * after squeezing out stale entries. - */ - memcpy(ents, blp, be32_to_cpu(btp->count) * sizeof(xfs_dir2_leaf_entry_t)); - xfs_dir3_leaf_log_ents(args, lbp, 0, leafhdr.count - 1); - needscan = 0; - needlog = 1; - /* - * Make the space formerly occupied by the leaf entries and block - * tail be free. - */ - xfs_dir2_data_make_free(args, dbp, - (xfs_dir2_data_aoff_t)((char *)blp - (char *)hdr), - (xfs_dir2_data_aoff_t)((char *)hdr + args->geo->blksize - - (char *)blp), - &needlog, &needscan); - /* - * Fix up the block header, make it a data block. - */ - dbp->b_ops = &xfs_dir3_data_buf_ops; - xfs_trans_buf_set_type(tp, dbp, XFS_BLFT_DIR_DATA_BUF); - if (hdr->magic == cpu_to_be32(XFS_DIR2_BLOCK_MAGIC)) - hdr->magic = cpu_to_be32(XFS_DIR2_DATA_MAGIC); - else - hdr->magic = cpu_to_be32(XFS_DIR3_DATA_MAGIC); - - if (needscan) - xfs_dir2_data_freescan(dp, hdr, &needlog); - /* - * Set up leaf tail and bests table. - */ - ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); - ltp->bestcount = cpu_to_be32(1); - bestsp = xfs_dir2_leaf_bests_p(ltp); - bestsp[0] = bf[0].length; - /* - * Log the data header and leaf bests table. - */ - if (needlog) - xfs_dir2_data_log_header(args, dbp); - xfs_dir3_leaf_check(dp, lbp); - xfs_dir3_data_check(dp, dbp); - xfs_dir3_leaf_log_bests(args, lbp, 0, 0); - return 0; -} - -STATIC void -xfs_dir3_leaf_find_stale( - struct xfs_dir3_icleaf_hdr *leafhdr, - struct xfs_dir2_leaf_entry *ents, - int index, - int *lowstale, - int *highstale) -{ - /* - * Find the first stale entry before our index, if any. - */ - for (*lowstale = index - 1; *lowstale >= 0; --*lowstale) { - if (ents[*lowstale].address == - cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) - break; - } - - /* - * Find the first stale entry at or after our index, if any. - * Stop if the result would require moving more entries than using - * lowstale. - */ - for (*highstale = index; *highstale < leafhdr->count; ++*highstale) { - if (ents[*highstale].address == - cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) - break; - if (*lowstale >= 0 && index - *lowstale <= *highstale - index) - break; - } -} - -struct xfs_dir2_leaf_entry * -xfs_dir3_leaf_find_entry( - struct xfs_dir3_icleaf_hdr *leafhdr, - struct xfs_dir2_leaf_entry *ents, - int index, /* leaf table position */ - int compact, /* need to compact leaves */ - int lowstale, /* index of prev stale leaf */ - int highstale, /* index of next stale leaf */ - int *lfloglow, /* low leaf logging index */ - int *lfloghigh) /* high leaf logging index */ -{ - if (!leafhdr->stale) { - xfs_dir2_leaf_entry_t *lep; /* leaf entry table pointer */ - - /* - * Now we need to make room to insert the leaf entry. - * - * If there are no stale entries, just insert a hole at index. - */ - lep = &ents[index]; - if (index < leafhdr->count) - memmove(lep + 1, lep, - (leafhdr->count - index) * sizeof(*lep)); - - /* - * Record low and high logging indices for the leaf. - */ - *lfloglow = index; - *lfloghigh = leafhdr->count++; - return lep; - } - - /* - * There are stale entries. - * - * We will use one of them for the new entry. It's probably not at - * the right location, so we'll have to shift some up or down first. - * - * If we didn't compact before, we need to find the nearest stale - * entries before and after our insertion point. - */ - if (compact == 0) - xfs_dir3_leaf_find_stale(leafhdr, ents, index, - &lowstale, &highstale); - - /* - * If the low one is better, use it. - */ - if (lowstale >= 0 && - (highstale == leafhdr->count || - index - lowstale - 1 < highstale - index)) { - ASSERT(index - lowstale - 1 >= 0); - ASSERT(ents[lowstale].address == - cpu_to_be32(XFS_DIR2_NULL_DATAPTR)); - - /* - * Copy entries up to cover the stale entry and make room - * for the new entry. - */ - if (index - lowstale - 1 > 0) { - memmove(&ents[lowstale], &ents[lowstale + 1], - (index - lowstale - 1) * - sizeof(xfs_dir2_leaf_entry_t)); - } - *lfloglow = MIN(lowstale, *lfloglow); - *lfloghigh = MAX(index - 1, *lfloghigh); - leafhdr->stale--; - return &ents[index - 1]; - } - - /* - * The high one is better, so use that one. - */ - ASSERT(highstale - index >= 0); - ASSERT(ents[highstale].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)); - - /* - * Copy entries down to cover the stale entry and make room for the - * new entry. - */ - if (highstale - index > 0) { - memmove(&ents[index + 1], &ents[index], - (highstale - index) * sizeof(xfs_dir2_leaf_entry_t)); - } - *lfloglow = MIN(index, *lfloglow); - *lfloghigh = MAX(highstale, *lfloghigh); - leafhdr->stale--; - return &ents[index]; -} - -/* - * Add an entry to a leaf form directory. - */ -int /* error */ -xfs_dir2_leaf_addname( - xfs_da_args_t *args) /* operation arguments */ -{ - __be16 *bestsp; /* freespace table in leaf */ - int compact; /* need to compact leaves */ - xfs_dir2_data_hdr_t *hdr; /* data block header */ - struct xfs_buf *dbp; /* data block buffer */ - xfs_dir2_data_entry_t *dep; /* data block entry */ - xfs_inode_t *dp; /* incore directory inode */ - xfs_dir2_data_unused_t *dup; /* data unused entry */ - int error; /* error return value */ - int grown; /* allocated new data block */ - int highstale; /* index of next stale leaf */ - int i; /* temporary, index */ - int index; /* leaf table position */ - struct xfs_buf *lbp; /* leaf's buffer */ - xfs_dir2_leaf_t *leaf; /* leaf structure */ - int length; /* length of new entry */ - xfs_dir2_leaf_entry_t *lep; /* leaf entry table pointer */ - int lfloglow; /* low leaf logging index */ - int lfloghigh; /* high leaf logging index */ - int lowstale; /* index of prev stale leaf */ - xfs_dir2_leaf_tail_t *ltp; /* leaf tail pointer */ - int needbytes; /* leaf block bytes needed */ - int needlog; /* need to log data header */ - int needscan; /* need to rescan data free */ - __be16 *tagp; /* end of data entry */ - xfs_trans_t *tp; /* transaction pointer */ - xfs_dir2_db_t use_block; /* data block number */ - struct xfs_dir2_data_free *bf; /* bestfree table */ - struct xfs_dir2_leaf_entry *ents; - struct xfs_dir3_icleaf_hdr leafhdr; - - trace_xfs_dir2_leaf_addname(args); - - dp = args->dp; - tp = args->trans; - - error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp); - if (error) - return error; - - /* - * Look up the entry by hash value and name. - * We know it's not there, our caller has already done a lookup. - * So the index is of the entry to insert in front of. - * But if there are dup hash values the index is of the first of those. - */ - index = xfs_dir2_leaf_search_hash(args, lbp); - leaf = lbp->b_addr; - ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); - ents = dp->d_ops->leaf_ents_p(leaf); - dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); - bestsp = xfs_dir2_leaf_bests_p(ltp); - length = dp->d_ops->data_entsize(args->namelen); - - /* - * See if there are any entries with the same hash value - * and space in their block for the new entry. - * This is good because it puts multiple same-hash value entries - * in a data block, improving the lookup of those entries. - */ - for (use_block = -1, lep = &ents[index]; - index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval; - index++, lep++) { - if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) - continue; - i = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address)); - ASSERT(i < be32_to_cpu(ltp->bestcount)); - ASSERT(bestsp[i] != cpu_to_be16(NULLDATAOFF)); - if (be16_to_cpu(bestsp[i]) >= length) { - use_block = i; - break; - } - } - /* - * Didn't find a block yet, linear search all the data blocks. - */ - if (use_block == -1) { - for (i = 0; i < be32_to_cpu(ltp->bestcount); i++) { - /* - * Remember a block we see that's missing. - */ - if (bestsp[i] == cpu_to_be16(NULLDATAOFF) && - use_block == -1) - use_block = i; - else if (be16_to_cpu(bestsp[i]) >= length) { - use_block = i; - break; - } - } - } - /* - * How many bytes do we need in the leaf block? - */ - needbytes = 0; - if (!leafhdr.stale) - needbytes += sizeof(xfs_dir2_leaf_entry_t); - if (use_block == -1) - needbytes += sizeof(xfs_dir2_data_off_t); - - /* - * Now kill use_block if it refers to a missing block, so we - * can use it as an indication of allocation needed. - */ - if (use_block != -1 && bestsp[use_block] == cpu_to_be16(NULLDATAOFF)) - use_block = -1; - /* - * If we don't have enough free bytes but we can make enough - * by compacting out stale entries, we'll do that. - */ - if ((char *)bestsp - (char *)&ents[leafhdr.count] < needbytes && - leafhdr.stale > 1) - compact = 1; - - /* - * Otherwise if we don't have enough free bytes we need to - * convert to node form. - */ - else if ((char *)bestsp - (char *)&ents[leafhdr.count] < needbytes) { - /* - * Just checking or no space reservation, give up. - */ - if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || - args->total == 0) { - xfs_trans_brelse(tp, lbp); - return -ENOSPC; - } - /* - * Convert to node form. - */ - error = xfs_dir2_leaf_to_node(args, lbp); - if (error) - return error; - /* - * Then add the new entry. - */ - return xfs_dir2_node_addname(args); - } - /* - * Otherwise it will fit without compaction. - */ - else - compact = 0; - /* - * If just checking, then it will fit unless we needed to allocate - * a new data block. - */ - if (args->op_flags & XFS_DA_OP_JUSTCHECK) { - xfs_trans_brelse(tp, lbp); - return use_block == -1 ? -ENOSPC : 0; - } - /* - * If no allocations are allowed, return now before we've - * changed anything. - */ - if (args->total == 0 && use_block == -1) { - xfs_trans_brelse(tp, lbp); - return -ENOSPC; - } - /* - * Need to compact the leaf entries, removing stale ones. - * Leave one stale entry behind - the one closest to our - * insertion index - and we'll shift that one to our insertion - * point later. - */ - if (compact) { - xfs_dir3_leaf_compact_x1(&leafhdr, ents, &index, &lowstale, - &highstale, &lfloglow, &lfloghigh); - } - /* - * There are stale entries, so we'll need log-low and log-high - * impossibly bad values later. - */ - else if (leafhdr.stale) { - lfloglow = leafhdr.count; - lfloghigh = -1; - } - /* - * If there was no data block space found, we need to allocate - * a new one. - */ - if (use_block == -1) { - /* - * Add the new data block. - */ - if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_DATA_SPACE, - &use_block))) { - xfs_trans_brelse(tp, lbp); - return error; - } - /* - * Initialize the block. - */ - if ((error = xfs_dir3_data_init(args, use_block, &dbp))) { - xfs_trans_brelse(tp, lbp); - return error; - } - /* - * If we're adding a new data block on the end we need to - * extend the bests table. Copy it up one entry. - */ - if (use_block >= be32_to_cpu(ltp->bestcount)) { - bestsp--; - memmove(&bestsp[0], &bestsp[1], - be32_to_cpu(ltp->bestcount) * sizeof(bestsp[0])); - be32_add_cpu(<p->bestcount, 1); - xfs_dir3_leaf_log_tail(args, lbp); - xfs_dir3_leaf_log_bests(args, lbp, 0, - be32_to_cpu(ltp->bestcount) - 1); - } - /* - * If we're filling in a previously empty block just log it. - */ - else - xfs_dir3_leaf_log_bests(args, lbp, use_block, use_block); - hdr = dbp->b_addr; - bf = dp->d_ops->data_bestfree_p(hdr); - bestsp[use_block] = bf[0].length; - grown = 1; - } else { - /* - * Already had space in some data block. - * Just read that one in. - */ - error = xfs_dir3_data_read(tp, dp, - xfs_dir2_db_to_da(args->geo, use_block), - -1, &dbp); - if (error) { - xfs_trans_brelse(tp, lbp); - return error; - } - hdr = dbp->b_addr; - bf = dp->d_ops->data_bestfree_p(hdr); - grown = 0; - } - /* - * Point to the biggest freespace in our data block. - */ - dup = (xfs_dir2_data_unused_t *) - ((char *)hdr + be16_to_cpu(bf[0].offset)); - ASSERT(be16_to_cpu(dup->length) >= length); - needscan = needlog = 0; - /* - * Mark the initial part of our freespace in use for the new entry. - */ - xfs_dir2_data_use_free(args, dbp, dup, - (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), length, - &needlog, &needscan); - /* - * Initialize our new entry (at last). - */ - dep = (xfs_dir2_data_entry_t *)dup; - dep->inumber = cpu_to_be64(args->inumber); - dep->namelen = args->namelen; - memcpy(dep->name, args->name, dep->namelen); - dp->d_ops->data_put_ftype(dep, args->filetype); - tagp = dp->d_ops->data_entry_tag_p(dep); - *tagp = cpu_to_be16((char *)dep - (char *)hdr); - /* - * Need to scan fix up the bestfree table. - */ - if (needscan) - xfs_dir2_data_freescan(dp, hdr, &needlog); - /* - * Need to log the data block's header. - */ - if (needlog) - xfs_dir2_data_log_header(args, dbp); - xfs_dir2_data_log_entry(args, dbp, dep); - /* - * If the bests table needs to be changed, do it. - * Log the change unless we've already done that. - */ - if (be16_to_cpu(bestsp[use_block]) != be16_to_cpu(bf[0].length)) { - bestsp[use_block] = bf[0].length; - if (!grown) - xfs_dir3_leaf_log_bests(args, lbp, use_block, use_block); - } - - lep = xfs_dir3_leaf_find_entry(&leafhdr, ents, index, compact, lowstale, - highstale, &lfloglow, &lfloghigh); - - /* - * Fill in the new leaf entry. - */ - lep->hashval = cpu_to_be32(args->hashval); - lep->address = cpu_to_be32( - xfs_dir2_db_off_to_dataptr(args->geo, use_block, - be16_to_cpu(*tagp))); - /* - * Log the leaf fields and give up the buffers. - */ - dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr); - xfs_dir3_leaf_log_header(args, lbp); - xfs_dir3_leaf_log_ents(args, lbp, lfloglow, lfloghigh); - xfs_dir3_leaf_check(dp, lbp); - xfs_dir3_data_check(dp, dbp); - return 0; -} - -/* - * Compact out any stale entries in the leaf. - * Log the header and changed leaf entries, if any. - */ -void -xfs_dir3_leaf_compact( - xfs_da_args_t *args, /* operation arguments */ - struct xfs_dir3_icleaf_hdr *leafhdr, - struct xfs_buf *bp) /* leaf buffer */ -{ - int from; /* source leaf index */ - xfs_dir2_leaf_t *leaf; /* leaf structure */ - int loglow; /* first leaf entry to log */ - int to; /* target leaf index */ - struct xfs_dir2_leaf_entry *ents; - struct xfs_inode *dp = args->dp; - - leaf = bp->b_addr; - if (!leafhdr->stale) - return; - - /* - * Compress out the stale entries in place. - */ - ents = dp->d_ops->leaf_ents_p(leaf); - for (from = to = 0, loglow = -1; from < leafhdr->count; from++) { - if (ents[from].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) - continue; - /* - * Only actually copy the entries that are different. - */ - if (from > to) { - if (loglow == -1) - loglow = to; - ents[to] = ents[from]; - } - to++; - } - /* - * Update and log the header, log the leaf entries. - */ - ASSERT(leafhdr->stale == from - to); - leafhdr->count -= leafhdr->stale; - leafhdr->stale = 0; - - dp->d_ops->leaf_hdr_to_disk(leaf, leafhdr); - xfs_dir3_leaf_log_header(args, bp); - if (loglow != -1) - xfs_dir3_leaf_log_ents(args, bp, loglow, to - 1); -} - -/* - * Compact the leaf entries, removing stale ones. - * Leave one stale entry behind - the one closest to our - * insertion index - and the caller will shift that one to our insertion - * point later. - * Return new insertion index, where the remaining stale entry is, - * and leaf logging indices. - */ -void -xfs_dir3_leaf_compact_x1( - struct xfs_dir3_icleaf_hdr *leafhdr, - struct xfs_dir2_leaf_entry *ents, - int *indexp, /* insertion index */ - int *lowstalep, /* out: stale entry before us */ - int *highstalep, /* out: stale entry after us */ - int *lowlogp, /* out: low log index */ - int *highlogp) /* out: high log index */ -{ - int from; /* source copy index */ - int highstale; /* stale entry at/after index */ - int index; /* insertion index */ - int keepstale; /* source index of kept stale */ - int lowstale; /* stale entry before index */ - int newindex=0; /* new insertion index */ - int to; /* destination copy index */ - - ASSERT(leafhdr->stale > 1); - index = *indexp; - - xfs_dir3_leaf_find_stale(leafhdr, ents, index, &lowstale, &highstale); - - /* - * Pick the better of lowstale and highstale. - */ - if (lowstale >= 0 && - (highstale == leafhdr->count || - index - lowstale <= highstale - index)) - keepstale = lowstale; - else - keepstale = highstale; - /* - * Copy the entries in place, removing all the stale entries - * except keepstale. - */ - for (from = to = 0; from < leafhdr->count; from++) { - /* - * Notice the new value of index. - */ - if (index == from) - newindex = to; - if (from != keepstale && - ents[from].address == cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) { - if (from == to) - *lowlogp = to; - continue; - } - /* - * Record the new keepstale value for the insertion. - */ - if (from == keepstale) - lowstale = highstale = to; - /* - * Copy only the entries that have moved. - */ - if (from > to) - ents[to] = ents[from]; - to++; - } - ASSERT(from > to); - /* - * If the insertion point was past the last entry, - * set the new insertion point accordingly. - */ - if (index == from) - newindex = to; - *indexp = newindex; - /* - * Adjust the leaf header values. - */ - leafhdr->count -= from - to; - leafhdr->stale = 1; - /* - * Remember the low/high stale value only in the "right" - * direction. - */ - if (lowstale >= newindex) - lowstale = -1; - else - highstale = leafhdr->count; - *highlogp = leafhdr->count - 1; - *lowstalep = lowstale; - *highstalep = highstale; -} - -/* - * Log the bests entries indicated from a leaf1 block. - */ -static void -xfs_dir3_leaf_log_bests( - struct xfs_da_args *args, - struct xfs_buf *bp, /* leaf buffer */ - int first, /* first entry to log */ - int last) /* last entry to log */ -{ - __be16 *firstb; /* pointer to first entry */ - __be16 *lastb; /* pointer to last entry */ - struct xfs_dir2_leaf *leaf = bp->b_addr; - xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ - - ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) || - leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC)); - - ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); - firstb = xfs_dir2_leaf_bests_p(ltp) + first; - lastb = xfs_dir2_leaf_bests_p(ltp) + last; - xfs_trans_log_buf(args->trans, bp, - (uint)((char *)firstb - (char *)leaf), - (uint)((char *)lastb - (char *)leaf + sizeof(*lastb) - 1)); -} - -/* - * Log the leaf entries indicated from a leaf1 or leafn block. - */ -void -xfs_dir3_leaf_log_ents( - struct xfs_da_args *args, - struct xfs_buf *bp, - int first, - int last) -{ - xfs_dir2_leaf_entry_t *firstlep; /* pointer to first entry */ - xfs_dir2_leaf_entry_t *lastlep; /* pointer to last entry */ - struct xfs_dir2_leaf *leaf = bp->b_addr; - struct xfs_dir2_leaf_entry *ents; - - ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) || - leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) || - leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || - leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)); - - ents = args->dp->d_ops->leaf_ents_p(leaf); - firstlep = &ents[first]; - lastlep = &ents[last]; - xfs_trans_log_buf(args->trans, bp, - (uint)((char *)firstlep - (char *)leaf), - (uint)((char *)lastlep - (char *)leaf + sizeof(*lastlep) - 1)); -} - -/* - * Log the header of the leaf1 or leafn block. - */ -void -xfs_dir3_leaf_log_header( - struct xfs_da_args *args, - struct xfs_buf *bp) -{ - struct xfs_dir2_leaf *leaf = bp->b_addr; - - ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) || - leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) || - leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || - leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)); - - xfs_trans_log_buf(args->trans, bp, - (uint)((char *)&leaf->hdr - (char *)leaf), - args->dp->d_ops->leaf_hdr_size - 1); -} - -/* - * Log the tail of the leaf1 block. - */ -STATIC void -xfs_dir3_leaf_log_tail( - struct xfs_da_args *args, - struct xfs_buf *bp) -{ - struct xfs_dir2_leaf *leaf = bp->b_addr; - xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ - - ASSERT(leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC) || - leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAF1_MAGIC) || - leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || - leaf->hdr.info.magic == cpu_to_be16(XFS_DIR3_LEAFN_MAGIC)); - - ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); - xfs_trans_log_buf(args->trans, bp, (uint)((char *)ltp - (char *)leaf), - (uint)(args->geo->blksize - 1)); -} - -/* - * Look up the entry referred to by args in the leaf format directory. - * Most of the work is done by the xfs_dir2_leaf_lookup_int routine which - * is also used by the node-format code. - */ -int -xfs_dir2_leaf_lookup( - xfs_da_args_t *args) /* operation arguments */ -{ - struct xfs_buf *dbp; /* data block buffer */ - xfs_dir2_data_entry_t *dep; /* data block entry */ - xfs_inode_t *dp; /* incore directory inode */ - int error; /* error return code */ - int index; /* found entry index */ - struct xfs_buf *lbp; /* leaf buffer */ - xfs_dir2_leaf_t *leaf; /* leaf structure */ - xfs_dir2_leaf_entry_t *lep; /* leaf entry */ - xfs_trans_t *tp; /* transaction pointer */ - struct xfs_dir2_leaf_entry *ents; - - trace_xfs_dir2_leaf_lookup(args); - - /* - * Look up name in the leaf block, returning both buffers and index. - */ - if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { - return error; - } - tp = args->trans; - dp = args->dp; - xfs_dir3_leaf_check(dp, lbp); - leaf = lbp->b_addr; - ents = dp->d_ops->leaf_ents_p(leaf); - /* - * Get to the leaf entry and contained data entry address. - */ - lep = &ents[index]; - - /* - * Point to the data entry. - */ - dep = (xfs_dir2_data_entry_t *) - ((char *)dbp->b_addr + - xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address))); - /* - * Return the found inode number & CI name if appropriate - */ - args->inumber = be64_to_cpu(dep->inumber); - args->filetype = dp->d_ops->data_get_ftype(dep); - error = xfs_dir_cilookup_result(args, dep->name, dep->namelen); - xfs_trans_brelse(tp, dbp); - xfs_trans_brelse(tp, lbp); - return error; -} - -/* - * Look up name/hash in the leaf block. - * Fill in indexp with the found index, and dbpp with the data buffer. - * If not found dbpp will be NULL, and ENOENT comes back. - * lbpp will always be filled in with the leaf buffer unless there's an error. - */ -static int /* error */ -xfs_dir2_leaf_lookup_int( - xfs_da_args_t *args, /* operation arguments */ - struct xfs_buf **lbpp, /* out: leaf buffer */ - int *indexp, /* out: index in leaf block */ - struct xfs_buf **dbpp) /* out: data buffer */ -{ - xfs_dir2_db_t curdb = -1; /* current data block number */ - struct xfs_buf *dbp = NULL; /* data buffer */ - xfs_dir2_data_entry_t *dep; /* data entry */ - xfs_inode_t *dp; /* incore directory inode */ - int error; /* error return code */ - int index; /* index in leaf block */ - struct xfs_buf *lbp; /* leaf buffer */ - xfs_dir2_leaf_entry_t *lep; /* leaf entry */ - xfs_dir2_leaf_t *leaf; /* leaf structure */ - xfs_mount_t *mp; /* filesystem mount point */ - xfs_dir2_db_t newdb; /* new data block number */ - xfs_trans_t *tp; /* transaction pointer */ - xfs_dir2_db_t cidb = -1; /* case match data block no. */ - enum xfs_dacmp cmp; /* name compare result */ - struct xfs_dir2_leaf_entry *ents; - struct xfs_dir3_icleaf_hdr leafhdr; - - dp = args->dp; - tp = args->trans; - mp = dp->i_mount; - - error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp); - if (error) - return error; - - *lbpp = lbp; - leaf = lbp->b_addr; - xfs_dir3_leaf_check(dp, lbp); - ents = dp->d_ops->leaf_ents_p(leaf); - dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); - - /* - * Look for the first leaf entry with our hash value. - */ - index = xfs_dir2_leaf_search_hash(args, lbp); - /* - * Loop over all the entries with the right hash value - * looking to match the name. - */ - for (lep = &ents[index]; - index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval; - lep++, index++) { - /* - * Skip over stale leaf entries. - */ - if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) - continue; - /* - * Get the new data block number. - */ - newdb = xfs_dir2_dataptr_to_db(args->geo, - be32_to_cpu(lep->address)); - /* - * If it's not the same as the old data block number, - * need to pitch the old one and read the new one. - */ - if (newdb != curdb) { - if (dbp) - xfs_trans_brelse(tp, dbp); - error = xfs_dir3_data_read(tp, dp, - xfs_dir2_db_to_da(args->geo, newdb), - -1, &dbp); - if (error) { - xfs_trans_brelse(tp, lbp); - return error; - } - curdb = newdb; - } - /* - * Point to the data entry. - */ - dep = (xfs_dir2_data_entry_t *)((char *)dbp->b_addr + - xfs_dir2_dataptr_to_off(args->geo, - be32_to_cpu(lep->address))); - /* - * Compare name and if it's an exact match, return the index - * and buffer. If it's the first case-insensitive match, store - * the index and buffer and continue looking for an exact match. - */ - cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen); - if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { - args->cmpresult = cmp; - *indexp = index; - /* case exact match: return the current buffer. */ - if (cmp == XFS_CMP_EXACT) { - *dbpp = dbp; - return 0; - } - cidb = curdb; - } - } - ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); - /* - * Here, we can only be doing a lookup (not a rename or remove). - * If a case-insensitive match was found earlier, re-read the - * appropriate data block if required and return it. - */ - if (args->cmpresult == XFS_CMP_CASE) { - ASSERT(cidb != -1); - if (cidb != curdb) { - xfs_trans_brelse(tp, dbp); - error = xfs_dir3_data_read(tp, dp, - xfs_dir2_db_to_da(args->geo, cidb), - -1, &dbp); - if (error) { - xfs_trans_brelse(tp, lbp); - return error; - } - } - *dbpp = dbp; - return 0; - } - /* - * No match found, return -ENOENT. - */ - ASSERT(cidb == -1); - if (dbp) - xfs_trans_brelse(tp, dbp); - xfs_trans_brelse(tp, lbp); - return -ENOENT; -} - -/* - * Remove an entry from a leaf format directory. - */ -int /* error */ -xfs_dir2_leaf_removename( - xfs_da_args_t *args) /* operation arguments */ -{ - __be16 *bestsp; /* leaf block best freespace */ - xfs_dir2_data_hdr_t *hdr; /* data block header */ - xfs_dir2_db_t db; /* data block number */ - struct xfs_buf *dbp; /* data block buffer */ - xfs_dir2_data_entry_t *dep; /* data entry structure */ - xfs_inode_t *dp; /* incore directory inode */ - int error; /* error return code */ - xfs_dir2_db_t i; /* temporary data block # */ - int index; /* index into leaf entries */ - struct xfs_buf *lbp; /* leaf buffer */ - xfs_dir2_leaf_t *leaf; /* leaf structure */ - xfs_dir2_leaf_entry_t *lep; /* leaf entry */ - xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ - int needlog; /* need to log data header */ - int needscan; /* need to rescan data frees */ - xfs_dir2_data_off_t oldbest; /* old value of best free */ - struct xfs_dir2_data_free *bf; /* bestfree table */ - struct xfs_dir2_leaf_entry *ents; - struct xfs_dir3_icleaf_hdr leafhdr; - - trace_xfs_dir2_leaf_removename(args); - - /* - * Lookup the leaf entry, get the leaf and data blocks read in. - */ - if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { - return error; - } - dp = args->dp; - leaf = lbp->b_addr; - hdr = dbp->b_addr; - xfs_dir3_data_check(dp, dbp); - bf = dp->d_ops->data_bestfree_p(hdr); - dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); - ents = dp->d_ops->leaf_ents_p(leaf); - /* - * Point to the leaf entry, use that to point to the data entry. - */ - lep = &ents[index]; - db = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address)); - dep = (xfs_dir2_data_entry_t *)((char *)hdr + - xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address))); - needscan = needlog = 0; - oldbest = be16_to_cpu(bf[0].length); - ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); - bestsp = xfs_dir2_leaf_bests_p(ltp); - ASSERT(be16_to_cpu(bestsp[db]) == oldbest); - /* - * Mark the former data entry unused. - */ - xfs_dir2_data_make_free(args, dbp, - (xfs_dir2_data_aoff_t)((char *)dep - (char *)hdr), - dp->d_ops->data_entsize(dep->namelen), &needlog, &needscan); - /* - * We just mark the leaf entry stale by putting a null in it. - */ - leafhdr.stale++; - dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr); - xfs_dir3_leaf_log_header(args, lbp); - - lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR); - xfs_dir3_leaf_log_ents(args, lbp, index, index); - - /* - * Scan the freespace in the data block again if necessary, - * log the data block header if necessary. - */ - if (needscan) - xfs_dir2_data_freescan(dp, hdr, &needlog); - if (needlog) - xfs_dir2_data_log_header(args, dbp); - /* - * If the longest freespace in the data block has changed, - * put the new value in the bests table and log that. - */ - if (be16_to_cpu(bf[0].length) != oldbest) { - bestsp[db] = bf[0].length; - xfs_dir3_leaf_log_bests(args, lbp, db, db); - } - xfs_dir3_data_check(dp, dbp); - /* - * If the data block is now empty then get rid of the data block. - */ - if (be16_to_cpu(bf[0].length) == - args->geo->blksize - dp->d_ops->data_entry_offset) { - ASSERT(db != args->geo->datablk); - if ((error = xfs_dir2_shrink_inode(args, db, dbp))) { - /* - * Nope, can't get rid of it because it caused - * allocation of a bmap btree block to do so. - * Just go on, returning success, leaving the - * empty block in place. - */ - if (error == -ENOSPC && args->total == 0) - error = 0; - xfs_dir3_leaf_check(dp, lbp); - return error; - } - dbp = NULL; - /* - * If this is the last data block then compact the - * bests table by getting rid of entries. - */ - if (db == be32_to_cpu(ltp->bestcount) - 1) { - /* - * Look for the last active entry (i). - */ - for (i = db - 1; i > 0; i--) { - if (bestsp[i] != cpu_to_be16(NULLDATAOFF)) - break; - } - /* - * Copy the table down so inactive entries at the - * end are removed. - */ - memmove(&bestsp[db - i], bestsp, - (be32_to_cpu(ltp->bestcount) - (db - i)) * sizeof(*bestsp)); - be32_add_cpu(<p->bestcount, -(db - i)); - xfs_dir3_leaf_log_tail(args, lbp); - xfs_dir3_leaf_log_bests(args, lbp, 0, - be32_to_cpu(ltp->bestcount) - 1); - } else - bestsp[db] = cpu_to_be16(NULLDATAOFF); - } - /* - * If the data block was not the first one, drop it. - */ - else if (db != args->geo->datablk) - dbp = NULL; - - xfs_dir3_leaf_check(dp, lbp); - /* - * See if we can convert to block form. - */ - return xfs_dir2_leaf_to_block(args, lbp, dbp); -} - -/* - * Replace the inode number in a leaf format directory entry. - */ -int /* error */ -xfs_dir2_leaf_replace( - xfs_da_args_t *args) /* operation arguments */ -{ - struct xfs_buf *dbp; /* data block buffer */ - xfs_dir2_data_entry_t *dep; /* data block entry */ - xfs_inode_t *dp; /* incore directory inode */ - int error; /* error return code */ - int index; /* index of leaf entry */ - struct xfs_buf *lbp; /* leaf buffer */ - xfs_dir2_leaf_t *leaf; /* leaf structure */ - xfs_dir2_leaf_entry_t *lep; /* leaf entry */ - xfs_trans_t *tp; /* transaction pointer */ - struct xfs_dir2_leaf_entry *ents; - - trace_xfs_dir2_leaf_replace(args); - - /* - * Look up the entry. - */ - if ((error = xfs_dir2_leaf_lookup_int(args, &lbp, &index, &dbp))) { - return error; - } - dp = args->dp; - leaf = lbp->b_addr; - ents = dp->d_ops->leaf_ents_p(leaf); - /* - * Point to the leaf entry, get data address from it. - */ - lep = &ents[index]; - /* - * Point to the data entry. - */ - dep = (xfs_dir2_data_entry_t *) - ((char *)dbp->b_addr + - xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address))); - ASSERT(args->inumber != be64_to_cpu(dep->inumber)); - /* - * Put the new inode number in, log it. - */ - dep->inumber = cpu_to_be64(args->inumber); - dp->d_ops->data_put_ftype(dep, args->filetype); - tp = args->trans; - xfs_dir2_data_log_entry(args, dbp, dep); - xfs_dir3_leaf_check(dp, lbp); - xfs_trans_brelse(tp, lbp); - return 0; -} - -/* - * Return index in the leaf block (lbp) which is either the first - * one with this hash value, or if there are none, the insert point - * for that hash value. - */ -int /* index value */ -xfs_dir2_leaf_search_hash( - xfs_da_args_t *args, /* operation arguments */ - struct xfs_buf *lbp) /* leaf buffer */ -{ - xfs_dahash_t hash=0; /* hash from this entry */ - xfs_dahash_t hashwant; /* hash value looking for */ - int high; /* high leaf index */ - int low; /* low leaf index */ - xfs_dir2_leaf_t *leaf; /* leaf structure */ - xfs_dir2_leaf_entry_t *lep; /* leaf entry */ - int mid=0; /* current leaf index */ - struct xfs_dir2_leaf_entry *ents; - struct xfs_dir3_icleaf_hdr leafhdr; - - leaf = lbp->b_addr; - ents = args->dp->d_ops->leaf_ents_p(leaf); - args->dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); - - /* - * Note, the table cannot be empty, so we have to go through the loop. - * Binary search the leaf entries looking for our hash value. - */ - for (lep = ents, low = 0, high = leafhdr.count - 1, - hashwant = args->hashval; - low <= high; ) { - mid = (low + high) >> 1; - if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant) - break; - if (hash < hashwant) - low = mid + 1; - else - high = mid - 1; - } - /* - * Found one, back up through all the equal hash values. - */ - if (hash == hashwant) { - while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant) { - mid--; - } - } - /* - * Need to point to an entry higher than ours. - */ - else if (hash < hashwant) - mid++; - return mid; -} - -/* - * Trim off a trailing data block. We know it's empty since the leaf - * freespace table says so. - */ -int /* error */ -xfs_dir2_leaf_trim_data( - xfs_da_args_t *args, /* operation arguments */ - struct xfs_buf *lbp, /* leaf buffer */ - xfs_dir2_db_t db) /* data block number */ -{ - __be16 *bestsp; /* leaf bests table */ - struct xfs_buf *dbp; /* data block buffer */ - xfs_inode_t *dp; /* incore directory inode */ - int error; /* error return value */ - xfs_dir2_leaf_t *leaf; /* leaf structure */ - xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ - xfs_trans_t *tp; /* transaction pointer */ - - dp = args->dp; - tp = args->trans; - /* - * Read the offending data block. We need its buffer. - */ - error = xfs_dir3_data_read(tp, dp, xfs_dir2_db_to_da(args->geo, db), - -1, &dbp); - if (error) - return error; - - leaf = lbp->b_addr; - ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); - -#ifdef DEBUG -{ - struct xfs_dir2_data_hdr *hdr = dbp->b_addr; - struct xfs_dir2_data_free *bf = dp->d_ops->data_bestfree_p(hdr); - - ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC)); - ASSERT(be16_to_cpu(bf[0].length) == - args->geo->blksize - dp->d_ops->data_entry_offset); - ASSERT(db == be32_to_cpu(ltp->bestcount) - 1); -} -#endif - - /* - * Get rid of the data block. - */ - if ((error = xfs_dir2_shrink_inode(args, db, dbp))) { - ASSERT(error != -ENOSPC); - xfs_trans_brelse(tp, dbp); - return error; - } - /* - * Eliminate the last bests entry from the table. - */ - bestsp = xfs_dir2_leaf_bests_p(ltp); - be32_add_cpu(<p->bestcount, -1); - memmove(&bestsp[1], &bestsp[0], be32_to_cpu(ltp->bestcount) * sizeof(*bestsp)); - xfs_dir3_leaf_log_tail(args, lbp); - xfs_dir3_leaf_log_bests(args, lbp, 0, be32_to_cpu(ltp->bestcount) - 1); - return 0; -} - -static inline size_t -xfs_dir3_leaf_size( - struct xfs_dir3_icleaf_hdr *hdr, - int counts) -{ - int entries; - int hdrsize; - - entries = hdr->count - hdr->stale; - if (hdr->magic == XFS_DIR2_LEAF1_MAGIC || - hdr->magic == XFS_DIR2_LEAFN_MAGIC) - hdrsize = sizeof(struct xfs_dir2_leaf_hdr); - else - hdrsize = sizeof(struct xfs_dir3_leaf_hdr); - - return hdrsize + entries * sizeof(xfs_dir2_leaf_entry_t) - + counts * sizeof(xfs_dir2_data_off_t) - + sizeof(xfs_dir2_leaf_tail_t); -} - -/* - * Convert node form directory to leaf form directory. - * The root of the node form dir needs to already be a LEAFN block. - * Just return if we can't do anything. - */ -int /* error */ -xfs_dir2_node_to_leaf( - xfs_da_state_t *state) /* directory operation state */ -{ - xfs_da_args_t *args; /* operation arguments */ - xfs_inode_t *dp; /* incore directory inode */ - int error; /* error return code */ - struct xfs_buf *fbp; /* buffer for freespace block */ - xfs_fileoff_t fo; /* freespace file offset */ - xfs_dir2_free_t *free; /* freespace structure */ - struct xfs_buf *lbp; /* buffer for leaf block */ - xfs_dir2_leaf_tail_t *ltp; /* tail of leaf structure */ - xfs_dir2_leaf_t *leaf; /* leaf structure */ - xfs_mount_t *mp; /* filesystem mount point */ - int rval; /* successful free trim? */ - xfs_trans_t *tp; /* transaction pointer */ - struct xfs_dir3_icleaf_hdr leafhdr; - struct xfs_dir3_icfree_hdr freehdr; - - /* - * There's more than a leaf level in the btree, so there must - * be multiple leafn blocks. Give up. - */ - if (state->path.active > 1) - return 0; - args = state->args; - - trace_xfs_dir2_node_to_leaf(args); - - mp = state->mp; - dp = args->dp; - tp = args->trans; - /* - * Get the last offset in the file. - */ - if ((error = xfs_bmap_last_offset(dp, &fo, XFS_DATA_FORK))) { - return error; - } - fo -= args->geo->fsbcount; - /* - * If there are freespace blocks other than the first one, - * take this opportunity to remove trailing empty freespace blocks - * that may have been left behind during no-space-reservation - * operations. - */ - while (fo > args->geo->freeblk) { - if ((error = xfs_dir2_node_trim_free(args, fo, &rval))) { - return error; - } - if (rval) - fo -= args->geo->fsbcount; - else - return 0; - } - /* - * Now find the block just before the freespace block. - */ - if ((error = xfs_bmap_last_before(tp, dp, &fo, XFS_DATA_FORK))) { - return error; - } - /* - * If it's not the single leaf block, give up. - */ - if (XFS_FSB_TO_B(mp, fo) > XFS_DIR2_LEAF_OFFSET + args->geo->blksize) - return 0; - lbp = state->path.blk[0].bp; - leaf = lbp->b_addr; - dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); - - ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC || - leafhdr.magic == XFS_DIR3_LEAFN_MAGIC); - - /* - * Read the freespace block. - */ - error = xfs_dir2_free_read(tp, dp, args->geo->freeblk, &fbp); - if (error) - return error; - free = fbp->b_addr; - dp->d_ops->free_hdr_from_disk(&freehdr, free); - - ASSERT(!freehdr.firstdb); - - /* - * Now see if the leafn and free data will fit in a leaf1. - * If not, release the buffer and give up. - */ - if (xfs_dir3_leaf_size(&leafhdr, freehdr.nvalid) > args->geo->blksize) { - xfs_trans_brelse(tp, fbp); - return 0; - } - - /* - * If the leaf has any stale entries in it, compress them out. - */ - if (leafhdr.stale) - xfs_dir3_leaf_compact(args, &leafhdr, lbp); - - lbp->b_ops = &xfs_dir3_leaf1_buf_ops; - xfs_trans_buf_set_type(tp, lbp, XFS_BLFT_DIR_LEAF1_BUF); - leafhdr.magic = (leafhdr.magic == XFS_DIR2_LEAFN_MAGIC) - ? XFS_DIR2_LEAF1_MAGIC - : XFS_DIR3_LEAF1_MAGIC; - - /* - * Set up the leaf tail from the freespace block. - */ - ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); - ltp->bestcount = cpu_to_be32(freehdr.nvalid); - - /* - * Set up the leaf bests table. - */ - memcpy(xfs_dir2_leaf_bests_p(ltp), dp->d_ops->free_bests_p(free), - freehdr.nvalid * sizeof(xfs_dir2_data_off_t)); - - dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr); - xfs_dir3_leaf_log_header(args, lbp); - xfs_dir3_leaf_log_bests(args, lbp, 0, be32_to_cpu(ltp->bestcount) - 1); - xfs_dir3_leaf_log_tail(args, lbp); - xfs_dir3_leaf_check(dp, lbp); - - /* - * Get rid of the freespace block. - */ - error = xfs_dir2_shrink_inode(args, - xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET), - fbp); - if (error) { - /* - * This can't fail here because it can only happen when - * punching out the middle of an extent, and this is an - * isolated block. - */ - ASSERT(error != -ENOSPC); - return error; - } - fbp = NULL; - /* - * Now see if we can convert the single-leaf directory - * down to a block form directory. - * This routine always kills the dabuf for the leaf, so - * eliminate it from the path. - */ - error = xfs_dir2_leaf_to_block(args, lbp, NULL); - state->path.blk[0].bp = NULL; - return error; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_dir2_node.c b/src/linux/fs/xfs/libxfs/xfs_dir2_node.c deleted file mode 100644 index 75a5574..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_dir2_node.c +++ /dev/null @@ -1,2283 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * Copyright (c) 2013 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_inode.h" -#include "xfs_bmap.h" -#include "xfs_dir2.h" -#include "xfs_dir2_priv.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_trans.h" -#include "xfs_buf_item.h" -#include "xfs_cksum.h" -#include "xfs_log.h" - -/* - * Function declarations. - */ -static int xfs_dir2_leafn_add(struct xfs_buf *bp, xfs_da_args_t *args, - int index); -static void xfs_dir2_leafn_rebalance(xfs_da_state_t *state, - xfs_da_state_blk_t *blk1, - xfs_da_state_blk_t *blk2); -static int xfs_dir2_leafn_remove(xfs_da_args_t *args, struct xfs_buf *bp, - int index, xfs_da_state_blk_t *dblk, - int *rval); -static int xfs_dir2_node_addname_int(xfs_da_args_t *args, - xfs_da_state_blk_t *fblk); - -/* - * Check internal consistency of a leafn block. - */ -#ifdef DEBUG -#define xfs_dir3_leaf_check(dp, bp) \ -do { \ - if (!xfs_dir3_leafn_check((dp), (bp))) \ - ASSERT(0); \ -} while (0); - -static bool -xfs_dir3_leafn_check( - struct xfs_inode *dp, - struct xfs_buf *bp) -{ - struct xfs_dir2_leaf *leaf = bp->b_addr; - struct xfs_dir3_icleaf_hdr leafhdr; - - dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); - - if (leafhdr.magic == XFS_DIR3_LEAFN_MAGIC) { - struct xfs_dir3_leaf_hdr *leaf3 = bp->b_addr; - if (be64_to_cpu(leaf3->info.blkno) != bp->b_bn) - return false; - } else if (leafhdr.magic != XFS_DIR2_LEAFN_MAGIC) - return false; - - return xfs_dir3_leaf_check_int(dp->i_mount, dp, &leafhdr, leaf); -} -#else -#define xfs_dir3_leaf_check(dp, bp) -#endif - -static bool -xfs_dir3_free_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_dir2_free_hdr *hdr = bp->b_addr; - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; - - if (hdr3->magic != cpu_to_be32(XFS_DIR3_FREE_MAGIC)) - return false; - if (!uuid_equal(&hdr3->uuid, &mp->m_sb.sb_meta_uuid)) - return false; - if (be64_to_cpu(hdr3->blkno) != bp->b_bn) - return false; - if (!xfs_log_check_lsn(mp, be64_to_cpu(hdr3->lsn))) - return false; - } else { - if (hdr->magic != cpu_to_be32(XFS_DIR2_FREE_MAGIC)) - return false; - } - - /* XXX: should bounds check the xfs_dir3_icfree_hdr here */ - - return true; -} - -static void -xfs_dir3_free_read_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - - if (xfs_sb_version_hascrc(&mp->m_sb) && - !xfs_buf_verify_cksum(bp, XFS_DIR3_FREE_CRC_OFF)) - xfs_buf_ioerror(bp, -EFSBADCRC); - else if (!xfs_dir3_free_verify(bp)) - xfs_buf_ioerror(bp, -EFSCORRUPTED); - - if (bp->b_error) - xfs_verifier_error(bp); -} - -static void -xfs_dir3_free_write_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_buf_log_item *bip = bp->b_fspriv; - struct xfs_dir3_blk_hdr *hdr3 = bp->b_addr; - - if (!xfs_dir3_free_verify(bp)) { - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - return; - } - - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return; - - if (bip) - hdr3->lsn = cpu_to_be64(bip->bli_item.li_lsn); - - xfs_buf_update_cksum(bp, XFS_DIR3_FREE_CRC_OFF); -} - -const struct xfs_buf_ops xfs_dir3_free_buf_ops = { - .name = "xfs_dir3_free", - .verify_read = xfs_dir3_free_read_verify, - .verify_write = xfs_dir3_free_write_verify, -}; - - -static int -__xfs_dir3_free_read( - struct xfs_trans *tp, - struct xfs_inode *dp, - xfs_dablk_t fbno, - xfs_daddr_t mappedbno, - struct xfs_buf **bpp) -{ - int err; - - err = xfs_da_read_buf(tp, dp, fbno, mappedbno, bpp, - XFS_DATA_FORK, &xfs_dir3_free_buf_ops); - - /* try read returns without an error or *bpp if it lands in a hole */ - if (!err && tp && *bpp) - xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_FREE_BUF); - return err; -} - -int -xfs_dir2_free_read( - struct xfs_trans *tp, - struct xfs_inode *dp, - xfs_dablk_t fbno, - struct xfs_buf **bpp) -{ - return __xfs_dir3_free_read(tp, dp, fbno, -1, bpp); -} - -static int -xfs_dir2_free_try_read( - struct xfs_trans *tp, - struct xfs_inode *dp, - xfs_dablk_t fbno, - struct xfs_buf **bpp) -{ - return __xfs_dir3_free_read(tp, dp, fbno, -2, bpp); -} - -static int -xfs_dir3_free_get_buf( - xfs_da_args_t *args, - xfs_dir2_db_t fbno, - struct xfs_buf **bpp) -{ - struct xfs_trans *tp = args->trans; - struct xfs_inode *dp = args->dp; - struct xfs_mount *mp = dp->i_mount; - struct xfs_buf *bp; - int error; - struct xfs_dir3_icfree_hdr hdr; - - error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, fbno), - -1, &bp, XFS_DATA_FORK); - if (error) - return error; - - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DIR_FREE_BUF); - bp->b_ops = &xfs_dir3_free_buf_ops; - - /* - * Initialize the new block to be empty, and remember - * its first slot as our empty slot. - */ - memset(bp->b_addr, 0, sizeof(struct xfs_dir3_free_hdr)); - memset(&hdr, 0, sizeof(hdr)); - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - struct xfs_dir3_free_hdr *hdr3 = bp->b_addr; - - hdr.magic = XFS_DIR3_FREE_MAGIC; - - hdr3->hdr.blkno = cpu_to_be64(bp->b_bn); - hdr3->hdr.owner = cpu_to_be64(dp->i_ino); - uuid_copy(&hdr3->hdr.uuid, &mp->m_sb.sb_meta_uuid); - } else - hdr.magic = XFS_DIR2_FREE_MAGIC; - dp->d_ops->free_hdr_to_disk(bp->b_addr, &hdr); - *bpp = bp; - return 0; -} - -/* - * Log entries from a freespace block. - */ -STATIC void -xfs_dir2_free_log_bests( - struct xfs_da_args *args, - struct xfs_buf *bp, - int first, /* first entry to log */ - int last) /* last entry to log */ -{ - xfs_dir2_free_t *free; /* freespace structure */ - __be16 *bests; - - free = bp->b_addr; - bests = args->dp->d_ops->free_bests_p(free); - ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || - free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC)); - xfs_trans_log_buf(args->trans, bp, - (uint)((char *)&bests[first] - (char *)free), - (uint)((char *)&bests[last] - (char *)free + - sizeof(bests[0]) - 1)); -} - -/* - * Log header from a freespace block. - */ -static void -xfs_dir2_free_log_header( - struct xfs_da_args *args, - struct xfs_buf *bp) -{ -#ifdef DEBUG - xfs_dir2_free_t *free; /* freespace structure */ - - free = bp->b_addr; - ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || - free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC)); -#endif - xfs_trans_log_buf(args->trans, bp, 0, - args->dp->d_ops->free_hdr_size - 1); -} - -/* - * Convert a leaf-format directory to a node-format directory. - * We need to change the magic number of the leaf block, and copy - * the freespace table out of the leaf block into its own block. - */ -int /* error */ -xfs_dir2_leaf_to_node( - xfs_da_args_t *args, /* operation arguments */ - struct xfs_buf *lbp) /* leaf buffer */ -{ - xfs_inode_t *dp; /* incore directory inode */ - int error; /* error return value */ - struct xfs_buf *fbp; /* freespace buffer */ - xfs_dir2_db_t fdb; /* freespace block number */ - xfs_dir2_free_t *free; /* freespace structure */ - __be16 *from; /* pointer to freespace entry */ - int i; /* leaf freespace index */ - xfs_dir2_leaf_t *leaf; /* leaf structure */ - xfs_dir2_leaf_tail_t *ltp; /* leaf tail structure */ - int n; /* count of live freespc ents */ - xfs_dir2_data_off_t off; /* freespace entry value */ - __be16 *to; /* pointer to freespace entry */ - xfs_trans_t *tp; /* transaction pointer */ - struct xfs_dir3_icfree_hdr freehdr; - - trace_xfs_dir2_leaf_to_node(args); - - dp = args->dp; - tp = args->trans; - /* - * Add a freespace block to the directory. - */ - if ((error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, &fdb))) { - return error; - } - ASSERT(fdb == xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET)); - /* - * Get the buffer for the new freespace block. - */ - error = xfs_dir3_free_get_buf(args, fdb, &fbp); - if (error) - return error; - - free = fbp->b_addr; - dp->d_ops->free_hdr_from_disk(&freehdr, free); - leaf = lbp->b_addr; - ltp = xfs_dir2_leaf_tail_p(args->geo, leaf); - ASSERT(be32_to_cpu(ltp->bestcount) <= - (uint)dp->i_d.di_size / args->geo->blksize); - - /* - * Copy freespace entries from the leaf block to the new block. - * Count active entries. - */ - from = xfs_dir2_leaf_bests_p(ltp); - to = dp->d_ops->free_bests_p(free); - for (i = n = 0; i < be32_to_cpu(ltp->bestcount); i++, from++, to++) { - if ((off = be16_to_cpu(*from)) != NULLDATAOFF) - n++; - *to = cpu_to_be16(off); - } - - /* - * Now initialize the freespace block header. - */ - freehdr.nused = n; - freehdr.nvalid = be32_to_cpu(ltp->bestcount); - - dp->d_ops->free_hdr_to_disk(fbp->b_addr, &freehdr); - xfs_dir2_free_log_bests(args, fbp, 0, freehdr.nvalid - 1); - xfs_dir2_free_log_header(args, fbp); - - /* - * Converting the leaf to a leafnode is just a matter of changing the - * magic number and the ops. Do the change directly to the buffer as - * it's less work (and less code) than decoding the header to host - * format and back again. - */ - if (leaf->hdr.info.magic == cpu_to_be16(XFS_DIR2_LEAF1_MAGIC)) - leaf->hdr.info.magic = cpu_to_be16(XFS_DIR2_LEAFN_MAGIC); - else - leaf->hdr.info.magic = cpu_to_be16(XFS_DIR3_LEAFN_MAGIC); - lbp->b_ops = &xfs_dir3_leafn_buf_ops; - xfs_trans_buf_set_type(tp, lbp, XFS_BLFT_DIR_LEAFN_BUF); - xfs_dir3_leaf_log_header(args, lbp); - xfs_dir3_leaf_check(dp, lbp); - return 0; -} - -/* - * Add a leaf entry to a leaf block in a node-form directory. - * The other work necessary is done from the caller. - */ -static int /* error */ -xfs_dir2_leafn_add( - struct xfs_buf *bp, /* leaf buffer */ - xfs_da_args_t *args, /* operation arguments */ - int index) /* insertion pt for new entry */ -{ - int compact; /* compacting stale leaves */ - xfs_inode_t *dp; /* incore directory inode */ - int highstale; /* next stale entry */ - xfs_dir2_leaf_t *leaf; /* leaf structure */ - xfs_dir2_leaf_entry_t *lep; /* leaf entry */ - int lfloghigh; /* high leaf entry logging */ - int lfloglow; /* low leaf entry logging */ - int lowstale; /* previous stale entry */ - struct xfs_dir3_icleaf_hdr leafhdr; - struct xfs_dir2_leaf_entry *ents; - - trace_xfs_dir2_leafn_add(args, index); - - dp = args->dp; - leaf = bp->b_addr; - dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); - ents = dp->d_ops->leaf_ents_p(leaf); - - /* - * Quick check just to make sure we are not going to index - * into other peoples memory - */ - if (index < 0) - return -EFSCORRUPTED; - - /* - * If there are already the maximum number of leaf entries in - * the block, if there are no stale entries it won't fit. - * Caller will do a split. If there are stale entries we'll do - * a compact. - */ - - if (leafhdr.count == dp->d_ops->leaf_max_ents(args->geo)) { - if (!leafhdr.stale) - return -ENOSPC; - compact = leafhdr.stale > 1; - } else - compact = 0; - ASSERT(index == 0 || be32_to_cpu(ents[index - 1].hashval) <= args->hashval); - ASSERT(index == leafhdr.count || - be32_to_cpu(ents[index].hashval) >= args->hashval); - - if (args->op_flags & XFS_DA_OP_JUSTCHECK) - return 0; - - /* - * Compact out all but one stale leaf entry. Leaves behind - * the entry closest to index. - */ - if (compact) - xfs_dir3_leaf_compact_x1(&leafhdr, ents, &index, &lowstale, - &highstale, &lfloglow, &lfloghigh); - else if (leafhdr.stale) { - /* - * Set impossible logging indices for this case. - */ - lfloglow = leafhdr.count; - lfloghigh = -1; - } - - /* - * Insert the new entry, log everything. - */ - lep = xfs_dir3_leaf_find_entry(&leafhdr, ents, index, compact, lowstale, - highstale, &lfloglow, &lfloghigh); - - lep->hashval = cpu_to_be32(args->hashval); - lep->address = cpu_to_be32(xfs_dir2_db_off_to_dataptr(args->geo, - args->blkno, args->index)); - - dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr); - xfs_dir3_leaf_log_header(args, bp); - xfs_dir3_leaf_log_ents(args, bp, lfloglow, lfloghigh); - xfs_dir3_leaf_check(dp, bp); - return 0; -} - -#ifdef DEBUG -static void -xfs_dir2_free_hdr_check( - struct xfs_inode *dp, - struct xfs_buf *bp, - xfs_dir2_db_t db) -{ - struct xfs_dir3_icfree_hdr hdr; - - dp->d_ops->free_hdr_from_disk(&hdr, bp->b_addr); - - ASSERT((hdr.firstdb % - dp->d_ops->free_max_bests(dp->i_mount->m_dir_geo)) == 0); - ASSERT(hdr.firstdb <= db); - ASSERT(db < hdr.firstdb + hdr.nvalid); -} -#else -#define xfs_dir2_free_hdr_check(dp, bp, db) -#endif /* DEBUG */ - -/* - * Return the last hash value in the leaf. - * Stale entries are ok. - */ -xfs_dahash_t /* hash value */ -xfs_dir2_leafn_lasthash( - struct xfs_inode *dp, - struct xfs_buf *bp, /* leaf buffer */ - int *count) /* count of entries in leaf */ -{ - struct xfs_dir2_leaf *leaf = bp->b_addr; - struct xfs_dir2_leaf_entry *ents; - struct xfs_dir3_icleaf_hdr leafhdr; - - dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); - - ASSERT(leafhdr.magic == XFS_DIR2_LEAFN_MAGIC || - leafhdr.magic == XFS_DIR3_LEAFN_MAGIC); - - if (count) - *count = leafhdr.count; - if (!leafhdr.count) - return 0; - - ents = dp->d_ops->leaf_ents_p(leaf); - return be32_to_cpu(ents[leafhdr.count - 1].hashval); -} - -/* - * Look up a leaf entry for space to add a name in a node-format leaf block. - * The extrablk in state is a freespace block. - */ -STATIC int -xfs_dir2_leafn_lookup_for_addname( - struct xfs_buf *bp, /* leaf buffer */ - xfs_da_args_t *args, /* operation arguments */ - int *indexp, /* out: leaf entry index */ - xfs_da_state_t *state) /* state to fill in */ -{ - struct xfs_buf *curbp = NULL; /* current data/free buffer */ - xfs_dir2_db_t curdb = -1; /* current data block number */ - xfs_dir2_db_t curfdb = -1; /* current free block number */ - xfs_inode_t *dp; /* incore directory inode */ - int error; /* error return value */ - int fi; /* free entry index */ - xfs_dir2_free_t *free = NULL; /* free block structure */ - int index; /* leaf entry index */ - xfs_dir2_leaf_t *leaf; /* leaf structure */ - int length; /* length of new data entry */ - xfs_dir2_leaf_entry_t *lep; /* leaf entry */ - xfs_mount_t *mp; /* filesystem mount point */ - xfs_dir2_db_t newdb; /* new data block number */ - xfs_dir2_db_t newfdb; /* new free block number */ - xfs_trans_t *tp; /* transaction pointer */ - struct xfs_dir2_leaf_entry *ents; - struct xfs_dir3_icleaf_hdr leafhdr; - - dp = args->dp; - tp = args->trans; - mp = dp->i_mount; - leaf = bp->b_addr; - dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); - ents = dp->d_ops->leaf_ents_p(leaf); - - xfs_dir3_leaf_check(dp, bp); - ASSERT(leafhdr.count > 0); - - /* - * Look up the hash value in the leaf entries. - */ - index = xfs_dir2_leaf_search_hash(args, bp); - /* - * Do we have a buffer coming in? - */ - if (state->extravalid) { - /* If so, it's a free block buffer, get the block number. */ - curbp = state->extrablk.bp; - curfdb = state->extrablk.blkno; - free = curbp->b_addr; - ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) || - free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC)); - } - length = dp->d_ops->data_entsize(args->namelen); - /* - * Loop over leaf entries with the right hash value. - */ - for (lep = &ents[index]; - index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval; - lep++, index++) { - /* - * Skip stale leaf entries. - */ - if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) - continue; - /* - * Pull the data block number from the entry. - */ - newdb = xfs_dir2_dataptr_to_db(args->geo, - be32_to_cpu(lep->address)); - /* - * For addname, we're looking for a place to put the new entry. - * We want to use a data block with an entry of equal - * hash value to ours if there is one with room. - * - * If this block isn't the data block we already have - * in hand, take a look at it. - */ - if (newdb != curdb) { - __be16 *bests; - - curdb = newdb; - /* - * Convert the data block to the free block - * holding its freespace information. - */ - newfdb = dp->d_ops->db_to_fdb(args->geo, newdb); - /* - * If it's not the one we have in hand, read it in. - */ - if (newfdb != curfdb) { - /* - * If we had one before, drop it. - */ - if (curbp) - xfs_trans_brelse(tp, curbp); - - error = xfs_dir2_free_read(tp, dp, - xfs_dir2_db_to_da(args->geo, - newfdb), - &curbp); - if (error) - return error; - free = curbp->b_addr; - - xfs_dir2_free_hdr_check(dp, curbp, curdb); - } - /* - * Get the index for our entry. - */ - fi = dp->d_ops->db_to_fdindex(args->geo, curdb); - /* - * If it has room, return it. - */ - bests = dp->d_ops->free_bests_p(free); - if (unlikely(bests[fi] == cpu_to_be16(NULLDATAOFF))) { - XFS_ERROR_REPORT("xfs_dir2_leafn_lookup_int", - XFS_ERRLEVEL_LOW, mp); - if (curfdb != newfdb) - xfs_trans_brelse(tp, curbp); - return -EFSCORRUPTED; - } - curfdb = newfdb; - if (be16_to_cpu(bests[fi]) >= length) - goto out; - } - } - /* Didn't find any space */ - fi = -1; -out: - ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); - if (curbp) { - /* Giving back a free block. */ - state->extravalid = 1; - state->extrablk.bp = curbp; - state->extrablk.index = fi; - state->extrablk.blkno = curfdb; - - /* - * Important: this magic number is not in the buffer - it's for - * buffer type information and therefore only the free/data type - * matters here, not whether CRCs are enabled or not. - */ - state->extrablk.magic = XFS_DIR2_FREE_MAGIC; - } else { - state->extravalid = 0; - } - /* - * Return the index, that will be the insertion point. - */ - *indexp = index; - return -ENOENT; -} - -/* - * Look up a leaf entry in a node-format leaf block. - * The extrablk in state a data block. - */ -STATIC int -xfs_dir2_leafn_lookup_for_entry( - struct xfs_buf *bp, /* leaf buffer */ - xfs_da_args_t *args, /* operation arguments */ - int *indexp, /* out: leaf entry index */ - xfs_da_state_t *state) /* state to fill in */ -{ - struct xfs_buf *curbp = NULL; /* current data/free buffer */ - xfs_dir2_db_t curdb = -1; /* current data block number */ - xfs_dir2_data_entry_t *dep; /* data block entry */ - xfs_inode_t *dp; /* incore directory inode */ - int error; /* error return value */ - int index; /* leaf entry index */ - xfs_dir2_leaf_t *leaf; /* leaf structure */ - xfs_dir2_leaf_entry_t *lep; /* leaf entry */ - xfs_mount_t *mp; /* filesystem mount point */ - xfs_dir2_db_t newdb; /* new data block number */ - xfs_trans_t *tp; /* transaction pointer */ - enum xfs_dacmp cmp; /* comparison result */ - struct xfs_dir2_leaf_entry *ents; - struct xfs_dir3_icleaf_hdr leafhdr; - - dp = args->dp; - tp = args->trans; - mp = dp->i_mount; - leaf = bp->b_addr; - dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); - ents = dp->d_ops->leaf_ents_p(leaf); - - xfs_dir3_leaf_check(dp, bp); - ASSERT(leafhdr.count > 0); - - /* - * Look up the hash value in the leaf entries. - */ - index = xfs_dir2_leaf_search_hash(args, bp); - /* - * Do we have a buffer coming in? - */ - if (state->extravalid) { - curbp = state->extrablk.bp; - curdb = state->extrablk.blkno; - } - /* - * Loop over leaf entries with the right hash value. - */ - for (lep = &ents[index]; - index < leafhdr.count && be32_to_cpu(lep->hashval) == args->hashval; - lep++, index++) { - /* - * Skip stale leaf entries. - */ - if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR) - continue; - /* - * Pull the data block number from the entry. - */ - newdb = xfs_dir2_dataptr_to_db(args->geo, - be32_to_cpu(lep->address)); - /* - * Not adding a new entry, so we really want to find - * the name given to us. - * - * If it's a different data block, go get it. - */ - if (newdb != curdb) { - /* - * If we had a block before that we aren't saving - * for a CI name, drop it - */ - if (curbp && (args->cmpresult == XFS_CMP_DIFFERENT || - curdb != state->extrablk.blkno)) - xfs_trans_brelse(tp, curbp); - /* - * If needing the block that is saved with a CI match, - * use it otherwise read in the new data block. - */ - if (args->cmpresult != XFS_CMP_DIFFERENT && - newdb == state->extrablk.blkno) { - ASSERT(state->extravalid); - curbp = state->extrablk.bp; - } else { - error = xfs_dir3_data_read(tp, dp, - xfs_dir2_db_to_da(args->geo, - newdb), - -1, &curbp); - if (error) - return error; - } - xfs_dir3_data_check(dp, curbp); - curdb = newdb; - } - /* - * Point to the data entry. - */ - dep = (xfs_dir2_data_entry_t *)((char *)curbp->b_addr + - xfs_dir2_dataptr_to_off(args->geo, - be32_to_cpu(lep->address))); - /* - * Compare the entry and if it's an exact match, return - * EEXIST immediately. If it's the first case-insensitive - * match, store the block & inode number and continue looking. - */ - cmp = mp->m_dirnameops->compname(args, dep->name, dep->namelen); - if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { - /* If there is a CI match block, drop it */ - if (args->cmpresult != XFS_CMP_DIFFERENT && - curdb != state->extrablk.blkno) - xfs_trans_brelse(tp, state->extrablk.bp); - args->cmpresult = cmp; - args->inumber = be64_to_cpu(dep->inumber); - args->filetype = dp->d_ops->data_get_ftype(dep); - *indexp = index; - state->extravalid = 1; - state->extrablk.bp = curbp; - state->extrablk.blkno = curdb; - state->extrablk.index = (int)((char *)dep - - (char *)curbp->b_addr); - state->extrablk.magic = XFS_DIR2_DATA_MAGIC; - curbp->b_ops = &xfs_dir3_data_buf_ops; - xfs_trans_buf_set_type(tp, curbp, XFS_BLFT_DIR_DATA_BUF); - if (cmp == XFS_CMP_EXACT) - return -EEXIST; - } - } - ASSERT(index == leafhdr.count || (args->op_flags & XFS_DA_OP_OKNOENT)); - if (curbp) { - if (args->cmpresult == XFS_CMP_DIFFERENT) { - /* Giving back last used data block. */ - state->extravalid = 1; - state->extrablk.bp = curbp; - state->extrablk.index = -1; - state->extrablk.blkno = curdb; - state->extrablk.magic = XFS_DIR2_DATA_MAGIC; - curbp->b_ops = &xfs_dir3_data_buf_ops; - xfs_trans_buf_set_type(tp, curbp, XFS_BLFT_DIR_DATA_BUF); - } else { - /* If the curbp is not the CI match block, drop it */ - if (state->extrablk.bp != curbp) - xfs_trans_brelse(tp, curbp); - } - } else { - state->extravalid = 0; - } - *indexp = index; - return -ENOENT; -} - -/* - * Look up a leaf entry in a node-format leaf block. - * If this is an addname then the extrablk in state is a freespace block, - * otherwise it's a data block. - */ -int -xfs_dir2_leafn_lookup_int( - struct xfs_buf *bp, /* leaf buffer */ - xfs_da_args_t *args, /* operation arguments */ - int *indexp, /* out: leaf entry index */ - xfs_da_state_t *state) /* state to fill in */ -{ - if (args->op_flags & XFS_DA_OP_ADDNAME) - return xfs_dir2_leafn_lookup_for_addname(bp, args, indexp, - state); - return xfs_dir2_leafn_lookup_for_entry(bp, args, indexp, state); -} - -/* - * Move count leaf entries from source to destination leaf. - * Log entries and headers. Stale entries are preserved. - */ -static void -xfs_dir3_leafn_moveents( - xfs_da_args_t *args, /* operation arguments */ - struct xfs_buf *bp_s, /* source */ - struct xfs_dir3_icleaf_hdr *shdr, - struct xfs_dir2_leaf_entry *sents, - int start_s,/* source leaf index */ - struct xfs_buf *bp_d, /* destination */ - struct xfs_dir3_icleaf_hdr *dhdr, - struct xfs_dir2_leaf_entry *dents, - int start_d,/* destination leaf index */ - int count) /* count of leaves to copy */ -{ - int stale; /* count stale leaves copied */ - - trace_xfs_dir2_leafn_moveents(args, start_s, start_d, count); - - /* - * Silently return if nothing to do. - */ - if (count == 0) - return; - - /* - * If the destination index is not the end of the current - * destination leaf entries, open up a hole in the destination - * to hold the new entries. - */ - if (start_d < dhdr->count) { - memmove(&dents[start_d + count], &dents[start_d], - (dhdr->count - start_d) * sizeof(xfs_dir2_leaf_entry_t)); - xfs_dir3_leaf_log_ents(args, bp_d, start_d + count, - count + dhdr->count - 1); - } - /* - * If the source has stale leaves, count the ones in the copy range - * so we can update the header correctly. - */ - if (shdr->stale) { - int i; /* temp leaf index */ - - for (i = start_s, stale = 0; i < start_s + count; i++) { - if (sents[i].address == - cpu_to_be32(XFS_DIR2_NULL_DATAPTR)) - stale++; - } - } else - stale = 0; - /* - * Copy the leaf entries from source to destination. - */ - memcpy(&dents[start_d], &sents[start_s], - count * sizeof(xfs_dir2_leaf_entry_t)); - xfs_dir3_leaf_log_ents(args, bp_d, start_d, start_d + count - 1); - - /* - * If there are source entries after the ones we copied, - * delete the ones we copied by sliding the next ones down. - */ - if (start_s + count < shdr->count) { - memmove(&sents[start_s], &sents[start_s + count], - count * sizeof(xfs_dir2_leaf_entry_t)); - xfs_dir3_leaf_log_ents(args, bp_s, start_s, start_s + count - 1); - } - - /* - * Update the headers and log them. - */ - shdr->count -= count; - shdr->stale -= stale; - dhdr->count += count; - dhdr->stale += stale; -} - -/* - * Determine the sort order of two leaf blocks. - * Returns 1 if both are valid and leaf2 should be before leaf1, else 0. - */ -int /* sort order */ -xfs_dir2_leafn_order( - struct xfs_inode *dp, - struct xfs_buf *leaf1_bp, /* leaf1 buffer */ - struct xfs_buf *leaf2_bp) /* leaf2 buffer */ -{ - struct xfs_dir2_leaf *leaf1 = leaf1_bp->b_addr; - struct xfs_dir2_leaf *leaf2 = leaf2_bp->b_addr; - struct xfs_dir2_leaf_entry *ents1; - struct xfs_dir2_leaf_entry *ents2; - struct xfs_dir3_icleaf_hdr hdr1; - struct xfs_dir3_icleaf_hdr hdr2; - - dp->d_ops->leaf_hdr_from_disk(&hdr1, leaf1); - dp->d_ops->leaf_hdr_from_disk(&hdr2, leaf2); - ents1 = dp->d_ops->leaf_ents_p(leaf1); - ents2 = dp->d_ops->leaf_ents_p(leaf2); - - if (hdr1.count > 0 && hdr2.count > 0 && - (be32_to_cpu(ents2[0].hashval) < be32_to_cpu(ents1[0].hashval) || - be32_to_cpu(ents2[hdr2.count - 1].hashval) < - be32_to_cpu(ents1[hdr1.count - 1].hashval))) - return 1; - return 0; -} - -/* - * Rebalance leaf entries between two leaf blocks. - * This is actually only called when the second block is new, - * though the code deals with the general case. - * A new entry will be inserted in one of the blocks, and that - * entry is taken into account when balancing. - */ -static void -xfs_dir2_leafn_rebalance( - xfs_da_state_t *state, /* btree cursor */ - xfs_da_state_blk_t *blk1, /* first btree block */ - xfs_da_state_blk_t *blk2) /* second btree block */ -{ - xfs_da_args_t *args; /* operation arguments */ - int count; /* count (& direction) leaves */ - int isleft; /* new goes in left leaf */ - xfs_dir2_leaf_t *leaf1; /* first leaf structure */ - xfs_dir2_leaf_t *leaf2; /* second leaf structure */ - int mid; /* midpoint leaf index */ -#if defined(DEBUG) || defined(XFS_WARN) - int oldstale; /* old count of stale leaves */ -#endif - int oldsum; /* old total leaf count */ - int swap; /* swapped leaf blocks */ - struct xfs_dir2_leaf_entry *ents1; - struct xfs_dir2_leaf_entry *ents2; - struct xfs_dir3_icleaf_hdr hdr1; - struct xfs_dir3_icleaf_hdr hdr2; - struct xfs_inode *dp = state->args->dp; - - args = state->args; - /* - * If the block order is wrong, swap the arguments. - */ - if ((swap = xfs_dir2_leafn_order(dp, blk1->bp, blk2->bp))) { - xfs_da_state_blk_t *tmp; /* temp for block swap */ - - tmp = blk1; - blk1 = blk2; - blk2 = tmp; - } - leaf1 = blk1->bp->b_addr; - leaf2 = blk2->bp->b_addr; - dp->d_ops->leaf_hdr_from_disk(&hdr1, leaf1); - dp->d_ops->leaf_hdr_from_disk(&hdr2, leaf2); - ents1 = dp->d_ops->leaf_ents_p(leaf1); - ents2 = dp->d_ops->leaf_ents_p(leaf2); - - oldsum = hdr1.count + hdr2.count; -#if defined(DEBUG) || defined(XFS_WARN) - oldstale = hdr1.stale + hdr2.stale; -#endif - mid = oldsum >> 1; - - /* - * If the old leaf count was odd then the new one will be even, - * so we need to divide the new count evenly. - */ - if (oldsum & 1) { - xfs_dahash_t midhash; /* middle entry hash value */ - - if (mid >= hdr1.count) - midhash = be32_to_cpu(ents2[mid - hdr1.count].hashval); - else - midhash = be32_to_cpu(ents1[mid].hashval); - isleft = args->hashval <= midhash; - } - /* - * If the old count is even then the new count is odd, so there's - * no preferred side for the new entry. - * Pick the left one. - */ - else - isleft = 1; - /* - * Calculate moved entry count. Positive means left-to-right, - * negative means right-to-left. Then move the entries. - */ - count = hdr1.count - mid + (isleft == 0); - if (count > 0) - xfs_dir3_leafn_moveents(args, blk1->bp, &hdr1, ents1, - hdr1.count - count, blk2->bp, - &hdr2, ents2, 0, count); - else if (count < 0) - xfs_dir3_leafn_moveents(args, blk2->bp, &hdr2, ents2, 0, - blk1->bp, &hdr1, ents1, - hdr1.count, count); - - ASSERT(hdr1.count + hdr2.count == oldsum); - ASSERT(hdr1.stale + hdr2.stale == oldstale); - - /* log the changes made when moving the entries */ - dp->d_ops->leaf_hdr_to_disk(leaf1, &hdr1); - dp->d_ops->leaf_hdr_to_disk(leaf2, &hdr2); - xfs_dir3_leaf_log_header(args, blk1->bp); - xfs_dir3_leaf_log_header(args, blk2->bp); - - xfs_dir3_leaf_check(dp, blk1->bp); - xfs_dir3_leaf_check(dp, blk2->bp); - - /* - * Mark whether we're inserting into the old or new leaf. - */ - if (hdr1.count < hdr2.count) - state->inleaf = swap; - else if (hdr1.count > hdr2.count) - state->inleaf = !swap; - else - state->inleaf = swap ^ (blk1->index <= hdr1.count); - /* - * Adjust the expected index for insertion. - */ - if (!state->inleaf) - blk2->index = blk1->index - hdr1.count; - - /* - * Finally sanity check just to make sure we are not returning a - * negative index - */ - if (blk2->index < 0) { - state->inleaf = 1; - blk2->index = 0; - xfs_alert(dp->i_mount, - "%s: picked the wrong leaf? reverting original leaf: blk1->index %d", - __func__, blk1->index); - } -} - -static int -xfs_dir3_data_block_free( - xfs_da_args_t *args, - struct xfs_dir2_data_hdr *hdr, - struct xfs_dir2_free *free, - xfs_dir2_db_t fdb, - int findex, - struct xfs_buf *fbp, - int longest) -{ - int logfree = 0; - __be16 *bests; - struct xfs_dir3_icfree_hdr freehdr; - struct xfs_inode *dp = args->dp; - - dp->d_ops->free_hdr_from_disk(&freehdr, free); - bests = dp->d_ops->free_bests_p(free); - if (hdr) { - /* - * Data block is not empty, just set the free entry to the new - * value. - */ - bests[findex] = cpu_to_be16(longest); - xfs_dir2_free_log_bests(args, fbp, findex, findex); - return 0; - } - - /* One less used entry in the free table. */ - freehdr.nused--; - - /* - * If this was the last entry in the table, we can trim the table size - * back. There might be other entries at the end referring to - * non-existent data blocks, get those too. - */ - if (findex == freehdr.nvalid - 1) { - int i; /* free entry index */ - - for (i = findex - 1; i >= 0; i--) { - if (bests[i] != cpu_to_be16(NULLDATAOFF)) - break; - } - freehdr.nvalid = i + 1; - logfree = 0; - } else { - /* Not the last entry, just punch it out. */ - bests[findex] = cpu_to_be16(NULLDATAOFF); - logfree = 1; - } - - dp->d_ops->free_hdr_to_disk(free, &freehdr); - xfs_dir2_free_log_header(args, fbp); - - /* - * If there are no useful entries left in the block, get rid of the - * block if we can. - */ - if (!freehdr.nused) { - int error; - - error = xfs_dir2_shrink_inode(args, fdb, fbp); - if (error == 0) { - fbp = NULL; - logfree = 0; - } else if (error != -ENOSPC || args->total != 0) - return error; - /* - * It's possible to get ENOSPC if there is no - * space reservation. In this case some one - * else will eventually get rid of this block. - */ - } - - /* Log the free entry that changed, unless we got rid of it. */ - if (logfree) - xfs_dir2_free_log_bests(args, fbp, findex, findex); - return 0; -} - -/* - * Remove an entry from a node directory. - * This removes the leaf entry and the data entry, - * and updates the free block if necessary. - */ -static int /* error */ -xfs_dir2_leafn_remove( - xfs_da_args_t *args, /* operation arguments */ - struct xfs_buf *bp, /* leaf buffer */ - int index, /* leaf entry index */ - xfs_da_state_blk_t *dblk, /* data block */ - int *rval) /* resulting block needs join */ -{ - xfs_dir2_data_hdr_t *hdr; /* data block header */ - xfs_dir2_db_t db; /* data block number */ - struct xfs_buf *dbp; /* data block buffer */ - xfs_dir2_data_entry_t *dep; /* data block entry */ - xfs_inode_t *dp; /* incore directory inode */ - xfs_dir2_leaf_t *leaf; /* leaf structure */ - xfs_dir2_leaf_entry_t *lep; /* leaf entry */ - int longest; /* longest data free entry */ - int off; /* data block entry offset */ - int needlog; /* need to log data header */ - int needscan; /* need to rescan data frees */ - xfs_trans_t *tp; /* transaction pointer */ - struct xfs_dir2_data_free *bf; /* bestfree table */ - struct xfs_dir3_icleaf_hdr leafhdr; - struct xfs_dir2_leaf_entry *ents; - - trace_xfs_dir2_leafn_remove(args, index); - - dp = args->dp; - tp = args->trans; - leaf = bp->b_addr; - dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); - ents = dp->d_ops->leaf_ents_p(leaf); - - /* - * Point to the entry we're removing. - */ - lep = &ents[index]; - - /* - * Extract the data block and offset from the entry. - */ - db = xfs_dir2_dataptr_to_db(args->geo, be32_to_cpu(lep->address)); - ASSERT(dblk->blkno == db); - off = xfs_dir2_dataptr_to_off(args->geo, be32_to_cpu(lep->address)); - ASSERT(dblk->index == off); - - /* - * Kill the leaf entry by marking it stale. - * Log the leaf block changes. - */ - leafhdr.stale++; - dp->d_ops->leaf_hdr_to_disk(leaf, &leafhdr); - xfs_dir3_leaf_log_header(args, bp); - - lep->address = cpu_to_be32(XFS_DIR2_NULL_DATAPTR); - xfs_dir3_leaf_log_ents(args, bp, index, index); - - /* - * Make the data entry free. Keep track of the longest freespace - * in the data block in case it changes. - */ - dbp = dblk->bp; - hdr = dbp->b_addr; - dep = (xfs_dir2_data_entry_t *)((char *)hdr + off); - bf = dp->d_ops->data_bestfree_p(hdr); - longest = be16_to_cpu(bf[0].length); - needlog = needscan = 0; - xfs_dir2_data_make_free(args, dbp, off, - dp->d_ops->data_entsize(dep->namelen), &needlog, &needscan); - /* - * Rescan the data block freespaces for bestfree. - * Log the data block header if needed. - */ - if (needscan) - xfs_dir2_data_freescan(dp, hdr, &needlog); - if (needlog) - xfs_dir2_data_log_header(args, dbp); - xfs_dir3_data_check(dp, dbp); - /* - * If the longest data block freespace changes, need to update - * the corresponding freeblock entry. - */ - if (longest < be16_to_cpu(bf[0].length)) { - int error; /* error return value */ - struct xfs_buf *fbp; /* freeblock buffer */ - xfs_dir2_db_t fdb; /* freeblock block number */ - int findex; /* index in freeblock entries */ - xfs_dir2_free_t *free; /* freeblock structure */ - - /* - * Convert the data block number to a free block, - * read in the free block. - */ - fdb = dp->d_ops->db_to_fdb(args->geo, db); - error = xfs_dir2_free_read(tp, dp, - xfs_dir2_db_to_da(args->geo, fdb), - &fbp); - if (error) - return error; - free = fbp->b_addr; -#ifdef DEBUG - { - struct xfs_dir3_icfree_hdr freehdr; - dp->d_ops->free_hdr_from_disk(&freehdr, free); - ASSERT(freehdr.firstdb == dp->d_ops->free_max_bests(args->geo) * - (fdb - xfs_dir2_byte_to_db(args->geo, - XFS_DIR2_FREE_OFFSET))); - } -#endif - /* - * Calculate which entry we need to fix. - */ - findex = dp->d_ops->db_to_fdindex(args->geo, db); - longest = be16_to_cpu(bf[0].length); - /* - * If the data block is now empty we can get rid of it - * (usually). - */ - if (longest == args->geo->blksize - - dp->d_ops->data_entry_offset) { - /* - * Try to punch out the data block. - */ - error = xfs_dir2_shrink_inode(args, db, dbp); - if (error == 0) { - dblk->bp = NULL; - hdr = NULL; - } - /* - * We can get ENOSPC if there's no space reservation. - * In this case just drop the buffer and some one else - * will eventually get rid of the empty block. - */ - else if (!(error == -ENOSPC && args->total == 0)) - return error; - } - /* - * If we got rid of the data block, we can eliminate that entry - * in the free block. - */ - error = xfs_dir3_data_block_free(args, hdr, free, - fdb, findex, fbp, longest); - if (error) - return error; - } - - xfs_dir3_leaf_check(dp, bp); - /* - * Return indication of whether this leaf block is empty enough - * to justify trying to join it with a neighbor. - */ - *rval = (dp->d_ops->leaf_hdr_size + - (uint)sizeof(ents[0]) * (leafhdr.count - leafhdr.stale)) < - args->geo->magicpct; - return 0; -} - -/* - * Split the leaf entries in the old block into old and new blocks. - */ -int /* error */ -xfs_dir2_leafn_split( - xfs_da_state_t *state, /* btree cursor */ - xfs_da_state_blk_t *oldblk, /* original block */ - xfs_da_state_blk_t *newblk) /* newly created block */ -{ - xfs_da_args_t *args; /* operation arguments */ - xfs_dablk_t blkno; /* new leaf block number */ - int error; /* error return value */ - struct xfs_inode *dp; - - /* - * Allocate space for a new leaf node. - */ - args = state->args; - dp = args->dp; - ASSERT(oldblk->magic == XFS_DIR2_LEAFN_MAGIC); - error = xfs_da_grow_inode(args, &blkno); - if (error) { - return error; - } - /* - * Initialize the new leaf block. - */ - error = xfs_dir3_leaf_get_buf(args, xfs_dir2_da_to_db(args->geo, blkno), - &newblk->bp, XFS_DIR2_LEAFN_MAGIC); - if (error) - return error; - - newblk->blkno = blkno; - newblk->magic = XFS_DIR2_LEAFN_MAGIC; - /* - * Rebalance the entries across the two leaves, link the new - * block into the leaves. - */ - xfs_dir2_leafn_rebalance(state, oldblk, newblk); - error = xfs_da3_blk_link(state, oldblk, newblk); - if (error) { - return error; - } - /* - * Insert the new entry in the correct block. - */ - if (state->inleaf) - error = xfs_dir2_leafn_add(oldblk->bp, args, oldblk->index); - else - error = xfs_dir2_leafn_add(newblk->bp, args, newblk->index); - /* - * Update last hashval in each block since we added the name. - */ - oldblk->hashval = xfs_dir2_leafn_lasthash(dp, oldblk->bp, NULL); - newblk->hashval = xfs_dir2_leafn_lasthash(dp, newblk->bp, NULL); - xfs_dir3_leaf_check(dp, oldblk->bp); - xfs_dir3_leaf_check(dp, newblk->bp); - return error; -} - -/* - * Check a leaf block and its neighbors to see if the block should be - * collapsed into one or the other neighbor. Always keep the block - * with the smaller block number. - * If the current block is over 50% full, don't try to join it, return 0. - * If the block is empty, fill in the state structure and return 2. - * If it can be collapsed, fill in the state structure and return 1. - * If nothing can be done, return 0. - */ -int /* error */ -xfs_dir2_leafn_toosmall( - xfs_da_state_t *state, /* btree cursor */ - int *action) /* resulting action to take */ -{ - xfs_da_state_blk_t *blk; /* leaf block */ - xfs_dablk_t blkno; /* leaf block number */ - struct xfs_buf *bp; /* leaf buffer */ - int bytes; /* bytes in use */ - int count; /* leaf live entry count */ - int error; /* error return value */ - int forward; /* sibling block direction */ - int i; /* sibling counter */ - xfs_dir2_leaf_t *leaf; /* leaf structure */ - int rval; /* result from path_shift */ - struct xfs_dir3_icleaf_hdr leafhdr; - struct xfs_dir2_leaf_entry *ents; - struct xfs_inode *dp = state->args->dp; - - /* - * Check for the degenerate case of the block being over 50% full. - * If so, it's not worth even looking to see if we might be able - * to coalesce with a sibling. - */ - blk = &state->path.blk[state->path.active - 1]; - leaf = blk->bp->b_addr; - dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf); - ents = dp->d_ops->leaf_ents_p(leaf); - xfs_dir3_leaf_check(dp, blk->bp); - - count = leafhdr.count - leafhdr.stale; - bytes = dp->d_ops->leaf_hdr_size + count * sizeof(ents[0]); - if (bytes > (state->args->geo->blksize >> 1)) { - /* - * Blk over 50%, don't try to join. - */ - *action = 0; - return 0; - } - /* - * Check for the degenerate case of the block being empty. - * If the block is empty, we'll simply delete it, no need to - * coalesce it with a sibling block. We choose (arbitrarily) - * to merge with the forward block unless it is NULL. - */ - if (count == 0) { - /* - * Make altpath point to the block we want to keep and - * path point to the block we want to drop (this one). - */ - forward = (leafhdr.forw != 0); - memcpy(&state->altpath, &state->path, sizeof(state->path)); - error = xfs_da3_path_shift(state, &state->altpath, forward, 0, - &rval); - if (error) - return error; - *action = rval ? 2 : 0; - return 0; - } - /* - * Examine each sibling block to see if we can coalesce with - * at least 25% free space to spare. We need to figure out - * whether to merge with the forward or the backward block. - * We prefer coalescing with the lower numbered sibling so as - * to shrink a directory over time. - */ - forward = leafhdr.forw < leafhdr.back; - for (i = 0, bp = NULL; i < 2; forward = !forward, i++) { - struct xfs_dir3_icleaf_hdr hdr2; - - blkno = forward ? leafhdr.forw : leafhdr.back; - if (blkno == 0) - continue; - /* - * Read the sibling leaf block. - */ - error = xfs_dir3_leafn_read(state->args->trans, dp, - blkno, -1, &bp); - if (error) - return error; - - /* - * Count bytes in the two blocks combined. - */ - count = leafhdr.count - leafhdr.stale; - bytes = state->args->geo->blksize - - (state->args->geo->blksize >> 2); - - leaf = bp->b_addr; - dp->d_ops->leaf_hdr_from_disk(&hdr2, leaf); - ents = dp->d_ops->leaf_ents_p(leaf); - count += hdr2.count - hdr2.stale; - bytes -= count * sizeof(ents[0]); - - /* - * Fits with at least 25% to spare. - */ - if (bytes >= 0) - break; - xfs_trans_brelse(state->args->trans, bp); - } - /* - * Didn't like either block, give up. - */ - if (i >= 2) { - *action = 0; - return 0; - } - - /* - * Make altpath point to the block we want to keep (the lower - * numbered block) and path point to the block we want to drop. - */ - memcpy(&state->altpath, &state->path, sizeof(state->path)); - if (blkno < blk->blkno) - error = xfs_da3_path_shift(state, &state->altpath, forward, 0, - &rval); - else - error = xfs_da3_path_shift(state, &state->path, forward, 0, - &rval); - if (error) { - return error; - } - *action = rval ? 0 : 1; - return 0; -} - -/* - * Move all the leaf entries from drop_blk to save_blk. - * This is done as part of a join operation. - */ -void -xfs_dir2_leafn_unbalance( - xfs_da_state_t *state, /* cursor */ - xfs_da_state_blk_t *drop_blk, /* dead block */ - xfs_da_state_blk_t *save_blk) /* surviving block */ -{ - xfs_da_args_t *args; /* operation arguments */ - xfs_dir2_leaf_t *drop_leaf; /* dead leaf structure */ - xfs_dir2_leaf_t *save_leaf; /* surviving leaf structure */ - struct xfs_dir3_icleaf_hdr savehdr; - struct xfs_dir3_icleaf_hdr drophdr; - struct xfs_dir2_leaf_entry *sents; - struct xfs_dir2_leaf_entry *dents; - struct xfs_inode *dp = state->args->dp; - - args = state->args; - ASSERT(drop_blk->magic == XFS_DIR2_LEAFN_MAGIC); - ASSERT(save_blk->magic == XFS_DIR2_LEAFN_MAGIC); - drop_leaf = drop_blk->bp->b_addr; - save_leaf = save_blk->bp->b_addr; - - dp->d_ops->leaf_hdr_from_disk(&savehdr, save_leaf); - dp->d_ops->leaf_hdr_from_disk(&drophdr, drop_leaf); - sents = dp->d_ops->leaf_ents_p(save_leaf); - dents = dp->d_ops->leaf_ents_p(drop_leaf); - - /* - * If there are any stale leaf entries, take this opportunity - * to purge them. - */ - if (drophdr.stale) - xfs_dir3_leaf_compact(args, &drophdr, drop_blk->bp); - if (savehdr.stale) - xfs_dir3_leaf_compact(args, &savehdr, save_blk->bp); - - /* - * Move the entries from drop to the appropriate end of save. - */ - drop_blk->hashval = be32_to_cpu(dents[drophdr.count - 1].hashval); - if (xfs_dir2_leafn_order(dp, save_blk->bp, drop_blk->bp)) - xfs_dir3_leafn_moveents(args, drop_blk->bp, &drophdr, dents, 0, - save_blk->bp, &savehdr, sents, 0, - drophdr.count); - else - xfs_dir3_leafn_moveents(args, drop_blk->bp, &drophdr, dents, 0, - save_blk->bp, &savehdr, sents, - savehdr.count, drophdr.count); - save_blk->hashval = be32_to_cpu(sents[savehdr.count - 1].hashval); - - /* log the changes made when moving the entries */ - dp->d_ops->leaf_hdr_to_disk(save_leaf, &savehdr); - dp->d_ops->leaf_hdr_to_disk(drop_leaf, &drophdr); - xfs_dir3_leaf_log_header(args, save_blk->bp); - xfs_dir3_leaf_log_header(args, drop_blk->bp); - - xfs_dir3_leaf_check(dp, save_blk->bp); - xfs_dir3_leaf_check(dp, drop_blk->bp); -} - -/* - * Top-level node form directory addname routine. - */ -int /* error */ -xfs_dir2_node_addname( - xfs_da_args_t *args) /* operation arguments */ -{ - xfs_da_state_blk_t *blk; /* leaf block for insert */ - int error; /* error return value */ - int rval; /* sub-return value */ - xfs_da_state_t *state; /* btree cursor */ - - trace_xfs_dir2_node_addname(args); - - /* - * Allocate and initialize the state (btree cursor). - */ - state = xfs_da_state_alloc(); - state->args = args; - state->mp = args->dp->i_mount; - /* - * Look up the name. We're not supposed to find it, but - * this gives us the insertion point. - */ - error = xfs_da3_node_lookup_int(state, &rval); - if (error) - rval = error; - if (rval != -ENOENT) { - goto done; - } - /* - * Add the data entry to a data block. - * Extravalid is set to a freeblock found by lookup. - */ - rval = xfs_dir2_node_addname_int(args, - state->extravalid ? &state->extrablk : NULL); - if (rval) { - goto done; - } - blk = &state->path.blk[state->path.active - 1]; - ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); - /* - * Add the new leaf entry. - */ - rval = xfs_dir2_leafn_add(blk->bp, args, blk->index); - if (rval == 0) { - /* - * It worked, fix the hash values up the btree. - */ - if (!(args->op_flags & XFS_DA_OP_JUSTCHECK)) - xfs_da3_fixhashpath(state, &state->path); - } else { - /* - * It didn't work, we need to split the leaf block. - */ - if (args->total == 0) { - ASSERT(rval == -ENOSPC); - goto done; - } - /* - * Split the leaf block and insert the new entry. - */ - rval = xfs_da3_split(state); - } -done: - xfs_da_state_free(state); - return rval; -} - -/* - * Add the data entry for a node-format directory name addition. - * The leaf entry is added in xfs_dir2_leafn_add. - * We may enter with a freespace block that the lookup found. - */ -static int /* error */ -xfs_dir2_node_addname_int( - xfs_da_args_t *args, /* operation arguments */ - xfs_da_state_blk_t *fblk) /* optional freespace block */ -{ - xfs_dir2_data_hdr_t *hdr; /* data block header */ - xfs_dir2_db_t dbno; /* data block number */ - struct xfs_buf *dbp; /* data block buffer */ - xfs_dir2_data_entry_t *dep; /* data entry pointer */ - xfs_inode_t *dp; /* incore directory inode */ - xfs_dir2_data_unused_t *dup; /* data unused entry pointer */ - int error; /* error return value */ - xfs_dir2_db_t fbno; /* freespace block number */ - struct xfs_buf *fbp; /* freespace buffer */ - int findex; /* freespace entry index */ - xfs_dir2_free_t *free=NULL; /* freespace block structure */ - xfs_dir2_db_t ifbno; /* initial freespace block no */ - xfs_dir2_db_t lastfbno=0; /* highest freespace block no */ - int length; /* length of the new entry */ - int logfree; /* need to log free entry */ - xfs_mount_t *mp; /* filesystem mount point */ - int needlog; /* need to log data header */ - int needscan; /* need to rescan data frees */ - __be16 *tagp; /* data entry tag pointer */ - xfs_trans_t *tp; /* transaction pointer */ - __be16 *bests; - struct xfs_dir3_icfree_hdr freehdr; - struct xfs_dir2_data_free *bf; - - dp = args->dp; - mp = dp->i_mount; - tp = args->trans; - length = dp->d_ops->data_entsize(args->namelen); - /* - * If we came in with a freespace block that means that lookup - * found an entry with our hash value. This is the freespace - * block for that data entry. - */ - if (fblk) { - fbp = fblk->bp; - /* - * Remember initial freespace block number. - */ - ifbno = fblk->blkno; - free = fbp->b_addr; - findex = fblk->index; - bests = dp->d_ops->free_bests_p(free); - dp->d_ops->free_hdr_from_disk(&freehdr, free); - - /* - * This means the free entry showed that the data block had - * space for our entry, so we remembered it. - * Use that data block. - */ - if (findex >= 0) { - ASSERT(findex < freehdr.nvalid); - ASSERT(be16_to_cpu(bests[findex]) != NULLDATAOFF); - ASSERT(be16_to_cpu(bests[findex]) >= length); - dbno = freehdr.firstdb + findex; - } else { - /* - * The data block looked at didn't have enough room. - * We'll start at the beginning of the freespace entries. - */ - dbno = -1; - findex = 0; - } - } else { - /* - * Didn't come in with a freespace block, so no data block. - */ - ifbno = dbno = -1; - fbp = NULL; - findex = 0; - } - - /* - * If we don't have a data block yet, we're going to scan the - * freespace blocks looking for one. Figure out what the - * highest freespace block number is. - */ - if (dbno == -1) { - xfs_fileoff_t fo; /* freespace block number */ - - if ((error = xfs_bmap_last_offset(dp, &fo, XFS_DATA_FORK))) - return error; - lastfbno = xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)fo); - fbno = ifbno; - } - /* - * While we haven't identified a data block, search the freeblock - * data for a good data block. If we find a null freeblock entry, - * indicating a hole in the data blocks, remember that. - */ - while (dbno == -1) { - /* - * If we don't have a freeblock in hand, get the next one. - */ - if (fbp == NULL) { - /* - * Happens the first time through unless lookup gave - * us a freespace block to start with. - */ - if (++fbno == 0) - fbno = xfs_dir2_byte_to_db(args->geo, - XFS_DIR2_FREE_OFFSET); - /* - * If it's ifbno we already looked at it. - */ - if (fbno == ifbno) - fbno++; - /* - * If it's off the end we're done. - */ - if (fbno >= lastfbno) - break; - /* - * Read the block. There can be holes in the - * freespace blocks, so this might not succeed. - * This should be really rare, so there's no reason - * to avoid it. - */ - error = xfs_dir2_free_try_read(tp, dp, - xfs_dir2_db_to_da(args->geo, fbno), - &fbp); - if (error) - return error; - if (!fbp) - continue; - free = fbp->b_addr; - findex = 0; - } - /* - * Look at the current free entry. Is it good enough? - * - * The bests initialisation should be where the bufer is read in - * the above branch. But gcc is too stupid to realise that bests - * and the freehdr are actually initialised if they are placed - * there, so we have to do it here to avoid warnings. Blech. - */ - bests = dp->d_ops->free_bests_p(free); - dp->d_ops->free_hdr_from_disk(&freehdr, free); - if (be16_to_cpu(bests[findex]) != NULLDATAOFF && - be16_to_cpu(bests[findex]) >= length) - dbno = freehdr.firstdb + findex; - else { - /* - * Are we done with the freeblock? - */ - if (++findex == freehdr.nvalid) { - /* - * Drop the block. - */ - xfs_trans_brelse(tp, fbp); - fbp = NULL; - if (fblk && fblk->bp) - fblk->bp = NULL; - } - } - } - /* - * If we don't have a data block, we need to allocate one and make - * the freespace entries refer to it. - */ - if (unlikely(dbno == -1)) { - /* - * Not allowed to allocate, return failure. - */ - if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0) - return -ENOSPC; - - /* - * Allocate and initialize the new data block. - */ - if (unlikely((error = xfs_dir2_grow_inode(args, - XFS_DIR2_DATA_SPACE, - &dbno)) || - (error = xfs_dir3_data_init(args, dbno, &dbp)))) - return error; - - /* - * If (somehow) we have a freespace block, get rid of it. - */ - if (fbp) - xfs_trans_brelse(tp, fbp); - if (fblk && fblk->bp) - fblk->bp = NULL; - - /* - * Get the freespace block corresponding to the data block - * that was just allocated. - */ - fbno = dp->d_ops->db_to_fdb(args->geo, dbno); - error = xfs_dir2_free_try_read(tp, dp, - xfs_dir2_db_to_da(args->geo, fbno), - &fbp); - if (error) - return error; - - /* - * If there wasn't a freespace block, the read will - * return a NULL fbp. Allocate and initialize a new one. - */ - if (!fbp) { - error = xfs_dir2_grow_inode(args, XFS_DIR2_FREE_SPACE, - &fbno); - if (error) - return error; - - if (dp->d_ops->db_to_fdb(args->geo, dbno) != fbno) { - xfs_alert(mp, -"%s: dir ino %llu needed freesp block %lld for data block %lld, got %lld ifbno %llu lastfbno %d", - __func__, (unsigned long long)dp->i_ino, - (long long)dp->d_ops->db_to_fdb( - args->geo, dbno), - (long long)dbno, (long long)fbno, - (unsigned long long)ifbno, lastfbno); - if (fblk) { - xfs_alert(mp, - " fblk 0x%p blkno %llu index %d magic 0x%x", - fblk, - (unsigned long long)fblk->blkno, - fblk->index, - fblk->magic); - } else { - xfs_alert(mp, " ... fblk is NULL"); - } - XFS_ERROR_REPORT("xfs_dir2_node_addname_int", - XFS_ERRLEVEL_LOW, mp); - return -EFSCORRUPTED; - } - - /* - * Get a buffer for the new block. - */ - error = xfs_dir3_free_get_buf(args, fbno, &fbp); - if (error) - return error; - free = fbp->b_addr; - bests = dp->d_ops->free_bests_p(free); - dp->d_ops->free_hdr_from_disk(&freehdr, free); - - /* - * Remember the first slot as our empty slot. - */ - freehdr.firstdb = - (fbno - xfs_dir2_byte_to_db(args->geo, - XFS_DIR2_FREE_OFFSET)) * - dp->d_ops->free_max_bests(args->geo); - } else { - free = fbp->b_addr; - bests = dp->d_ops->free_bests_p(free); - dp->d_ops->free_hdr_from_disk(&freehdr, free); - } - - /* - * Set the freespace block index from the data block number. - */ - findex = dp->d_ops->db_to_fdindex(args->geo, dbno); - /* - * If it's after the end of the current entries in the - * freespace block, extend that table. - */ - if (findex >= freehdr.nvalid) { - ASSERT(findex < dp->d_ops->free_max_bests(args->geo)); - freehdr.nvalid = findex + 1; - /* - * Tag new entry so nused will go up. - */ - bests[findex] = cpu_to_be16(NULLDATAOFF); - } - /* - * If this entry was for an empty data block - * (this should always be true) then update the header. - */ - if (bests[findex] == cpu_to_be16(NULLDATAOFF)) { - freehdr.nused++; - dp->d_ops->free_hdr_to_disk(fbp->b_addr, &freehdr); - xfs_dir2_free_log_header(args, fbp); - } - /* - * Update the real value in the table. - * We haven't allocated the data entry yet so this will - * change again. - */ - hdr = dbp->b_addr; - bf = dp->d_ops->data_bestfree_p(hdr); - bests[findex] = bf[0].length; - logfree = 1; - } - /* - * We had a data block so we don't have to make a new one. - */ - else { - /* - * If just checking, we succeeded. - */ - if (args->op_flags & XFS_DA_OP_JUSTCHECK) - return 0; - - /* - * Read the data block in. - */ - error = xfs_dir3_data_read(tp, dp, - xfs_dir2_db_to_da(args->geo, dbno), - -1, &dbp); - if (error) - return error; - hdr = dbp->b_addr; - bf = dp->d_ops->data_bestfree_p(hdr); - logfree = 0; - } - ASSERT(be16_to_cpu(bf[0].length) >= length); - /* - * Point to the existing unused space. - */ - dup = (xfs_dir2_data_unused_t *) - ((char *)hdr + be16_to_cpu(bf[0].offset)); - needscan = needlog = 0; - /* - * Mark the first part of the unused space, inuse for us. - */ - xfs_dir2_data_use_free(args, dbp, dup, - (xfs_dir2_data_aoff_t)((char *)dup - (char *)hdr), length, - &needlog, &needscan); - /* - * Fill in the new entry and log it. - */ - dep = (xfs_dir2_data_entry_t *)dup; - dep->inumber = cpu_to_be64(args->inumber); - dep->namelen = args->namelen; - memcpy(dep->name, args->name, dep->namelen); - dp->d_ops->data_put_ftype(dep, args->filetype); - tagp = dp->d_ops->data_entry_tag_p(dep); - *tagp = cpu_to_be16((char *)dep - (char *)hdr); - xfs_dir2_data_log_entry(args, dbp, dep); - /* - * Rescan the block for bestfree if needed. - */ - if (needscan) - xfs_dir2_data_freescan(dp, hdr, &needlog); - /* - * Log the data block header if needed. - */ - if (needlog) - xfs_dir2_data_log_header(args, dbp); - /* - * If the freespace entry is now wrong, update it. - */ - bests = dp->d_ops->free_bests_p(free); /* gcc is so stupid */ - if (be16_to_cpu(bests[findex]) != be16_to_cpu(bf[0].length)) { - bests[findex] = bf[0].length; - logfree = 1; - } - /* - * Log the freespace entry if needed. - */ - if (logfree) - xfs_dir2_free_log_bests(args, fbp, findex, findex); - /* - * Return the data block and offset in args, then drop the data block. - */ - args->blkno = (xfs_dablk_t)dbno; - args->index = be16_to_cpu(*tagp); - return 0; -} - -/* - * Lookup an entry in a node-format directory. - * All the real work happens in xfs_da3_node_lookup_int. - * The only real output is the inode number of the entry. - */ -int /* error */ -xfs_dir2_node_lookup( - xfs_da_args_t *args) /* operation arguments */ -{ - int error; /* error return value */ - int i; /* btree level */ - int rval; /* operation return value */ - xfs_da_state_t *state; /* btree cursor */ - - trace_xfs_dir2_node_lookup(args); - - /* - * Allocate and initialize the btree cursor. - */ - state = xfs_da_state_alloc(); - state->args = args; - state->mp = args->dp->i_mount; - /* - * Fill in the path to the entry in the cursor. - */ - error = xfs_da3_node_lookup_int(state, &rval); - if (error) - rval = error; - else if (rval == -ENOENT && args->cmpresult == XFS_CMP_CASE) { - /* If a CI match, dup the actual name and return -EEXIST */ - xfs_dir2_data_entry_t *dep; - - dep = (xfs_dir2_data_entry_t *) - ((char *)state->extrablk.bp->b_addr + - state->extrablk.index); - rval = xfs_dir_cilookup_result(args, dep->name, dep->namelen); - } - /* - * Release the btree blocks and leaf block. - */ - for (i = 0; i < state->path.active; i++) { - xfs_trans_brelse(args->trans, state->path.blk[i].bp); - state->path.blk[i].bp = NULL; - } - /* - * Release the data block if we have it. - */ - if (state->extravalid && state->extrablk.bp) { - xfs_trans_brelse(args->trans, state->extrablk.bp); - state->extrablk.bp = NULL; - } - xfs_da_state_free(state); - return rval; -} - -/* - * Remove an entry from a node-format directory. - */ -int /* error */ -xfs_dir2_node_removename( - struct xfs_da_args *args) /* operation arguments */ -{ - struct xfs_da_state_blk *blk; /* leaf block */ - int error; /* error return value */ - int rval; /* operation return value */ - struct xfs_da_state *state; /* btree cursor */ - - trace_xfs_dir2_node_removename(args); - - /* - * Allocate and initialize the btree cursor. - */ - state = xfs_da_state_alloc(); - state->args = args; - state->mp = args->dp->i_mount; - - /* Look up the entry we're deleting, set up the cursor. */ - error = xfs_da3_node_lookup_int(state, &rval); - if (error) - goto out_free; - - /* Didn't find it, upper layer screwed up. */ - if (rval != -EEXIST) { - error = rval; - goto out_free; - } - - blk = &state->path.blk[state->path.active - 1]; - ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); - ASSERT(state->extravalid); - /* - * Remove the leaf and data entries. - * Extrablk refers to the data block. - */ - error = xfs_dir2_leafn_remove(args, blk->bp, blk->index, - &state->extrablk, &rval); - if (error) - goto out_free; - /* - * Fix the hash values up the btree. - */ - xfs_da3_fixhashpath(state, &state->path); - /* - * If we need to join leaf blocks, do it. - */ - if (rval && state->path.active > 1) - error = xfs_da3_join(state); - /* - * If no errors so far, try conversion to leaf format. - */ - if (!error) - error = xfs_dir2_node_to_leaf(state); -out_free: - xfs_da_state_free(state); - return error; -} - -/* - * Replace an entry's inode number in a node-format directory. - */ -int /* error */ -xfs_dir2_node_replace( - xfs_da_args_t *args) /* operation arguments */ -{ - xfs_da_state_blk_t *blk; /* leaf block */ - xfs_dir2_data_hdr_t *hdr; /* data block header */ - xfs_dir2_data_entry_t *dep; /* data entry changed */ - int error; /* error return value */ - int i; /* btree level */ - xfs_ino_t inum; /* new inode number */ - int ftype; /* new file type */ - xfs_dir2_leaf_t *leaf; /* leaf structure */ - xfs_dir2_leaf_entry_t *lep; /* leaf entry being changed */ - int rval; /* internal return value */ - xfs_da_state_t *state; /* btree cursor */ - - trace_xfs_dir2_node_replace(args); - - /* - * Allocate and initialize the btree cursor. - */ - state = xfs_da_state_alloc(); - state->args = args; - state->mp = args->dp->i_mount; - - /* - * We have to save new inode number and ftype since - * xfs_da3_node_lookup_int() is going to overwrite them - */ - inum = args->inumber; - ftype = args->filetype; - - /* - * Lookup the entry to change in the btree. - */ - error = xfs_da3_node_lookup_int(state, &rval); - if (error) { - rval = error; - } - /* - * It should be found, since the vnodeops layer has looked it up - * and locked it. But paranoia is good. - */ - if (rval == -EEXIST) { - struct xfs_dir2_leaf_entry *ents; - /* - * Find the leaf entry. - */ - blk = &state->path.blk[state->path.active - 1]; - ASSERT(blk->magic == XFS_DIR2_LEAFN_MAGIC); - leaf = blk->bp->b_addr; - ents = args->dp->d_ops->leaf_ents_p(leaf); - lep = &ents[blk->index]; - ASSERT(state->extravalid); - /* - * Point to the data entry. - */ - hdr = state->extrablk.bp->b_addr; - ASSERT(hdr->magic == cpu_to_be32(XFS_DIR2_DATA_MAGIC) || - hdr->magic == cpu_to_be32(XFS_DIR3_DATA_MAGIC)); - dep = (xfs_dir2_data_entry_t *) - ((char *)hdr + - xfs_dir2_dataptr_to_off(args->geo, - be32_to_cpu(lep->address))); - ASSERT(inum != be64_to_cpu(dep->inumber)); - /* - * Fill in the new inode number and log the entry. - */ - dep->inumber = cpu_to_be64(inum); - args->dp->d_ops->data_put_ftype(dep, ftype); - xfs_dir2_data_log_entry(args, state->extrablk.bp, dep); - rval = 0; - } - /* - * Didn't find it, and we're holding a data block. Drop it. - */ - else if (state->extravalid) { - xfs_trans_brelse(args->trans, state->extrablk.bp); - state->extrablk.bp = NULL; - } - /* - * Release all the buffers in the cursor. - */ - for (i = 0; i < state->path.active; i++) { - xfs_trans_brelse(args->trans, state->path.blk[i].bp); - state->path.blk[i].bp = NULL; - } - xfs_da_state_free(state); - return rval; -} - -/* - * Trim off a trailing empty freespace block. - * Return (in rvalp) 1 if we did it, 0 if not. - */ -int /* error */ -xfs_dir2_node_trim_free( - xfs_da_args_t *args, /* operation arguments */ - xfs_fileoff_t fo, /* free block number */ - int *rvalp) /* out: did something */ -{ - struct xfs_buf *bp; /* freespace buffer */ - xfs_inode_t *dp; /* incore directory inode */ - int error; /* error return code */ - xfs_dir2_free_t *free; /* freespace structure */ - xfs_trans_t *tp; /* transaction pointer */ - struct xfs_dir3_icfree_hdr freehdr; - - dp = args->dp; - tp = args->trans; - - *rvalp = 0; - - /* - * Read the freespace block. - */ - error = xfs_dir2_free_try_read(tp, dp, fo, &bp); - if (error) - return error; - /* - * There can be holes in freespace. If fo is a hole, there's - * nothing to do. - */ - if (!bp) - return 0; - free = bp->b_addr; - dp->d_ops->free_hdr_from_disk(&freehdr, free); - - /* - * If there are used entries, there's nothing to do. - */ - if (freehdr.nused > 0) { - xfs_trans_brelse(tp, bp); - return 0; - } - /* - * Blow the block away. - */ - error = xfs_dir2_shrink_inode(args, - xfs_dir2_da_to_db(args->geo, (xfs_dablk_t)fo), bp); - if (error) { - /* - * Can't fail with ENOSPC since that only happens with no - * space reservation, when breaking up an extent into two - * pieces. This is the last block of an extent. - */ - ASSERT(error != -ENOSPC); - xfs_trans_brelse(tp, bp); - return error; - } - /* - * Return that we succeeded. - */ - *rvalp = 1; - return 0; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_dir2_priv.h b/src/linux/fs/xfs/libxfs/xfs_dir2_priv.h deleted file mode 100644 index ef9f6ea..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_dir2_priv.h +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_DIR2_PRIV_H__ -#define __XFS_DIR2_PRIV_H__ - -struct dir_context; - -/* xfs_dir2.c */ -extern int xfs_dir_ino_validate(struct xfs_mount *mp, xfs_ino_t ino); -extern int xfs_dir2_grow_inode(struct xfs_da_args *args, int space, - xfs_dir2_db_t *dbp); -extern int xfs_dir_cilookup_result(struct xfs_da_args *args, - const unsigned char *name, int len); - - -/* xfs_dir2_block.c */ -extern int xfs_dir3_block_read(struct xfs_trans *tp, struct xfs_inode *dp, - struct xfs_buf **bpp); -extern int xfs_dir2_block_addname(struct xfs_da_args *args); -extern int xfs_dir2_block_lookup(struct xfs_da_args *args); -extern int xfs_dir2_block_removename(struct xfs_da_args *args); -extern int xfs_dir2_block_replace(struct xfs_da_args *args); -extern int xfs_dir2_leaf_to_block(struct xfs_da_args *args, - struct xfs_buf *lbp, struct xfs_buf *dbp); - -/* xfs_dir2_data.c */ -#ifdef DEBUG -#define xfs_dir3_data_check(dp,bp) __xfs_dir3_data_check(dp, bp); -#else -#define xfs_dir3_data_check(dp,bp) -#endif - -extern int __xfs_dir3_data_check(struct xfs_inode *dp, struct xfs_buf *bp); -extern int xfs_dir3_data_read(struct xfs_trans *tp, struct xfs_inode *dp, - xfs_dablk_t bno, xfs_daddr_t mapped_bno, struct xfs_buf **bpp); -extern int xfs_dir3_data_readahead(struct xfs_inode *dp, xfs_dablk_t bno, - xfs_daddr_t mapped_bno); - -extern struct xfs_dir2_data_free * -xfs_dir2_data_freeinsert(struct xfs_dir2_data_hdr *hdr, - struct xfs_dir2_data_free *bf, struct xfs_dir2_data_unused *dup, - int *loghead); -extern int xfs_dir3_data_init(struct xfs_da_args *args, xfs_dir2_db_t blkno, - struct xfs_buf **bpp); - -/* xfs_dir2_leaf.c */ -extern int xfs_dir3_leafn_read(struct xfs_trans *tp, struct xfs_inode *dp, - xfs_dablk_t fbno, xfs_daddr_t mappedbno, struct xfs_buf **bpp); -extern int xfs_dir2_block_to_leaf(struct xfs_da_args *args, - struct xfs_buf *dbp); -extern int xfs_dir2_leaf_addname(struct xfs_da_args *args); -extern void xfs_dir3_leaf_compact(struct xfs_da_args *args, - struct xfs_dir3_icleaf_hdr *leafhdr, struct xfs_buf *bp); -extern void xfs_dir3_leaf_compact_x1(struct xfs_dir3_icleaf_hdr *leafhdr, - struct xfs_dir2_leaf_entry *ents, int *indexp, - int *lowstalep, int *highstalep, int *lowlogp, int *highlogp); -extern int xfs_dir3_leaf_get_buf(struct xfs_da_args *args, xfs_dir2_db_t bno, - struct xfs_buf **bpp, __uint16_t magic); -extern void xfs_dir3_leaf_log_ents(struct xfs_da_args *args, - struct xfs_buf *bp, int first, int last); -extern void xfs_dir3_leaf_log_header(struct xfs_da_args *args, - struct xfs_buf *bp); -extern int xfs_dir2_leaf_lookup(struct xfs_da_args *args); -extern int xfs_dir2_leaf_removename(struct xfs_da_args *args); -extern int xfs_dir2_leaf_replace(struct xfs_da_args *args); -extern int xfs_dir2_leaf_search_hash(struct xfs_da_args *args, - struct xfs_buf *lbp); -extern int xfs_dir2_leaf_trim_data(struct xfs_da_args *args, - struct xfs_buf *lbp, xfs_dir2_db_t db); -extern struct xfs_dir2_leaf_entry * -xfs_dir3_leaf_find_entry(struct xfs_dir3_icleaf_hdr *leafhdr, - struct xfs_dir2_leaf_entry *ents, int index, int compact, - int lowstale, int highstale, int *lfloglow, int *lfloghigh); -extern int xfs_dir2_node_to_leaf(struct xfs_da_state *state); - -extern bool xfs_dir3_leaf_check_int(struct xfs_mount *mp, struct xfs_inode *dp, - struct xfs_dir3_icleaf_hdr *hdr, struct xfs_dir2_leaf *leaf); - -/* xfs_dir2_node.c */ -extern int xfs_dir2_leaf_to_node(struct xfs_da_args *args, - struct xfs_buf *lbp); -extern xfs_dahash_t xfs_dir2_leafn_lasthash(struct xfs_inode *dp, - struct xfs_buf *bp, int *count); -extern int xfs_dir2_leafn_lookup_int(struct xfs_buf *bp, - struct xfs_da_args *args, int *indexp, - struct xfs_da_state *state); -extern int xfs_dir2_leafn_order(struct xfs_inode *dp, struct xfs_buf *leaf1_bp, - struct xfs_buf *leaf2_bp); -extern int xfs_dir2_leafn_split(struct xfs_da_state *state, - struct xfs_da_state_blk *oldblk, struct xfs_da_state_blk *newblk); -extern int xfs_dir2_leafn_toosmall(struct xfs_da_state *state, int *action); -extern void xfs_dir2_leafn_unbalance(struct xfs_da_state *state, - struct xfs_da_state_blk *drop_blk, - struct xfs_da_state_blk *save_blk); -extern int xfs_dir2_node_addname(struct xfs_da_args *args); -extern int xfs_dir2_node_lookup(struct xfs_da_args *args); -extern int xfs_dir2_node_removename(struct xfs_da_args *args); -extern int xfs_dir2_node_replace(struct xfs_da_args *args); -extern int xfs_dir2_node_trim_free(struct xfs_da_args *args, xfs_fileoff_t fo, - int *rvalp); -extern int xfs_dir2_free_read(struct xfs_trans *tp, struct xfs_inode *dp, - xfs_dablk_t fbno, struct xfs_buf **bpp); - -/* xfs_dir2_sf.c */ -extern int xfs_dir2_block_sfsize(struct xfs_inode *dp, - struct xfs_dir2_data_hdr *block, struct xfs_dir2_sf_hdr *sfhp); -extern int xfs_dir2_block_to_sf(struct xfs_da_args *args, struct xfs_buf *bp, - int size, xfs_dir2_sf_hdr_t *sfhp); -extern int xfs_dir2_sf_addname(struct xfs_da_args *args); -extern int xfs_dir2_sf_create(struct xfs_da_args *args, xfs_ino_t pino); -extern int xfs_dir2_sf_lookup(struct xfs_da_args *args); -extern int xfs_dir2_sf_removename(struct xfs_da_args *args); -extern int xfs_dir2_sf_replace(struct xfs_da_args *args); - -/* xfs_dir2_readdir.c */ -extern int xfs_readdir(struct xfs_inode *dp, struct dir_context *ctx, - size_t bufsize); - -#endif /* __XFS_DIR2_PRIV_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_dir2_sf.c b/src/linux/fs/xfs/libxfs/xfs_dir2_sf.c deleted file mode 100644 index c6809ff..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_dir2_sf.c +++ /dev/null @@ -1,1125 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_error.h" -#include "xfs_dir2.h" -#include "xfs_dir2_priv.h" -#include "xfs_trace.h" - -/* - * Prototypes for internal functions. - */ -static void xfs_dir2_sf_addname_easy(xfs_da_args_t *args, - xfs_dir2_sf_entry_t *sfep, - xfs_dir2_data_aoff_t offset, - int new_isize); -static void xfs_dir2_sf_addname_hard(xfs_da_args_t *args, int objchange, - int new_isize); -static int xfs_dir2_sf_addname_pick(xfs_da_args_t *args, int objchange, - xfs_dir2_sf_entry_t **sfepp, - xfs_dir2_data_aoff_t *offsetp); -#ifdef DEBUG -static void xfs_dir2_sf_check(xfs_da_args_t *args); -#else -#define xfs_dir2_sf_check(args) -#endif /* DEBUG */ - -static void xfs_dir2_sf_toino4(xfs_da_args_t *args); -static void xfs_dir2_sf_toino8(xfs_da_args_t *args); - -/* - * Given a block directory (dp/block), calculate its size as a shortform (sf) - * directory and a header for the sf directory, if it will fit it the - * space currently present in the inode. If it won't fit, the output - * size is too big (but not accurate). - */ -int /* size for sf form */ -xfs_dir2_block_sfsize( - xfs_inode_t *dp, /* incore inode pointer */ - xfs_dir2_data_hdr_t *hdr, /* block directory data */ - xfs_dir2_sf_hdr_t *sfhp) /* output: header for sf form */ -{ - xfs_dir2_dataptr_t addr; /* data entry address */ - xfs_dir2_leaf_entry_t *blp; /* leaf area of the block */ - xfs_dir2_block_tail_t *btp; /* tail area of the block */ - int count; /* shortform entry count */ - xfs_dir2_data_entry_t *dep; /* data entry in the block */ - int i; /* block entry index */ - int i8count; /* count of big-inode entries */ - int isdot; /* entry is "." */ - int isdotdot; /* entry is ".." */ - xfs_mount_t *mp; /* mount structure pointer */ - int namelen; /* total name bytes */ - xfs_ino_t parent = 0; /* parent inode number */ - int size=0; /* total computed size */ - int has_ftype; - struct xfs_da_geometry *geo; - - mp = dp->i_mount; - geo = mp->m_dir_geo; - - /* - * if there is a filetype field, add the extra byte to the namelen - * for each entry that we see. - */ - has_ftype = xfs_sb_version_hasftype(&mp->m_sb) ? 1 : 0; - - count = i8count = namelen = 0; - btp = xfs_dir2_block_tail_p(geo, hdr); - blp = xfs_dir2_block_leaf_p(btp); - - /* - * Iterate over the block's data entries by using the leaf pointers. - */ - for (i = 0; i < be32_to_cpu(btp->count); i++) { - if ((addr = be32_to_cpu(blp[i].address)) == XFS_DIR2_NULL_DATAPTR) - continue; - /* - * Calculate the pointer to the entry at hand. - */ - dep = (xfs_dir2_data_entry_t *)((char *)hdr + - xfs_dir2_dataptr_to_off(geo, addr)); - /* - * Detect . and .., so we can special-case them. - * . is not included in sf directories. - * .. is included by just the parent inode number. - */ - isdot = dep->namelen == 1 && dep->name[0] == '.'; - isdotdot = - dep->namelen == 2 && - dep->name[0] == '.' && dep->name[1] == '.'; - - if (!isdot) - i8count += be64_to_cpu(dep->inumber) > XFS_DIR2_MAX_SHORT_INUM; - - /* take into account the file type field */ - if (!isdot && !isdotdot) { - count++; - namelen += dep->namelen + has_ftype; - } else if (isdotdot) - parent = be64_to_cpu(dep->inumber); - /* - * Calculate the new size, see if we should give up yet. - */ - size = xfs_dir2_sf_hdr_size(i8count) + /* header */ - count * 3 * sizeof(u8) + /* namelen + offset */ - namelen + /* name */ - (i8count ? /* inumber */ - count * XFS_INO64_SIZE : - count * XFS_INO32_SIZE); - if (size > XFS_IFORK_DSIZE(dp)) - return size; /* size value is a failure */ - } - /* - * Create the output header, if it worked. - */ - sfhp->count = count; - sfhp->i8count = i8count; - dp->d_ops->sf_put_parent_ino(sfhp, parent); - return size; -} - -/* - * Convert a block format directory to shortform. - * Caller has already checked that it will fit, and built us a header. - */ -int /* error */ -xfs_dir2_block_to_sf( - xfs_da_args_t *args, /* operation arguments */ - struct xfs_buf *bp, - int size, /* shortform directory size */ - xfs_dir2_sf_hdr_t *sfhp) /* shortform directory hdr */ -{ - xfs_dir2_data_hdr_t *hdr; /* block header */ - xfs_dir2_block_tail_t *btp; /* block tail pointer */ - xfs_dir2_data_entry_t *dep; /* data entry pointer */ - xfs_inode_t *dp; /* incore directory inode */ - xfs_dir2_data_unused_t *dup; /* unused data pointer */ - char *endptr; /* end of data entries */ - int error; /* error return value */ - int logflags; /* inode logging flags */ - xfs_mount_t *mp; /* filesystem mount point */ - char *ptr; /* current data pointer */ - xfs_dir2_sf_entry_t *sfep; /* shortform entry */ - xfs_dir2_sf_hdr_t *sfp; /* shortform directory header */ - xfs_dir2_sf_hdr_t *dst; /* temporary data buffer */ - - trace_xfs_dir2_block_to_sf(args); - - dp = args->dp; - mp = dp->i_mount; - - /* - * allocate a temporary destination buffer the size of the inode - * to format the data into. Once we have formatted the data, we - * can free the block and copy the formatted data into the inode literal - * area. - */ - dst = kmem_alloc(mp->m_sb.sb_inodesize, KM_SLEEP); - hdr = bp->b_addr; - - /* - * Copy the header into the newly allocate local space. - */ - sfp = (xfs_dir2_sf_hdr_t *)dst; - memcpy(sfp, sfhp, xfs_dir2_sf_hdr_size(sfhp->i8count)); - - /* - * Set up to loop over the block's entries. - */ - btp = xfs_dir2_block_tail_p(args->geo, hdr); - ptr = (char *)dp->d_ops->data_entry_p(hdr); - endptr = (char *)xfs_dir2_block_leaf_p(btp); - sfep = xfs_dir2_sf_firstentry(sfp); - /* - * Loop over the active and unused entries. - * Stop when we reach the leaf/tail portion of the block. - */ - while (ptr < endptr) { - /* - * If it's unused, just skip over it. - */ - dup = (xfs_dir2_data_unused_t *)ptr; - if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { - ptr += be16_to_cpu(dup->length); - continue; - } - dep = (xfs_dir2_data_entry_t *)ptr; - /* - * Skip . - */ - if (dep->namelen == 1 && dep->name[0] == '.') - ASSERT(be64_to_cpu(dep->inumber) == dp->i_ino); - /* - * Skip .., but make sure the inode number is right. - */ - else if (dep->namelen == 2 && - dep->name[0] == '.' && dep->name[1] == '.') - ASSERT(be64_to_cpu(dep->inumber) == - dp->d_ops->sf_get_parent_ino(sfp)); - /* - * Normal entry, copy it into shortform. - */ - else { - sfep->namelen = dep->namelen; - xfs_dir2_sf_put_offset(sfep, - (xfs_dir2_data_aoff_t) - ((char *)dep - (char *)hdr)); - memcpy(sfep->name, dep->name, dep->namelen); - dp->d_ops->sf_put_ino(sfp, sfep, - be64_to_cpu(dep->inumber)); - dp->d_ops->sf_put_ftype(sfep, - dp->d_ops->data_get_ftype(dep)); - - sfep = dp->d_ops->sf_nextentry(sfp, sfep); - } - ptr += dp->d_ops->data_entsize(dep->namelen); - } - ASSERT((char *)sfep - (char *)sfp == size); - - /* now we are done with the block, we can shrink the inode */ - logflags = XFS_ILOG_CORE; - error = xfs_dir2_shrink_inode(args, args->geo->datablk, bp); - if (error) { - ASSERT(error != -ENOSPC); - goto out; - } - - /* - * The buffer is now unconditionally gone, whether - * xfs_dir2_shrink_inode worked or not. - * - * Convert the inode to local format and copy the data in. - */ - ASSERT(dp->i_df.if_bytes == 0); - xfs_init_local_fork(dp, XFS_DATA_FORK, dst, size); - dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; - dp->i_d.di_size = size; - - logflags |= XFS_ILOG_DDATA; - xfs_dir2_sf_check(args); -out: - xfs_trans_log_inode(args->trans, dp, logflags); - kmem_free(dst); - return error; -} - -/* - * Add a name to a shortform directory. - * There are two algorithms, "easy" and "hard" which we decide on - * before changing anything. - * Convert to block form if necessary, if the new entry won't fit. - */ -int /* error */ -xfs_dir2_sf_addname( - xfs_da_args_t *args) /* operation arguments */ -{ - xfs_inode_t *dp; /* incore directory inode */ - int error; /* error return value */ - int incr_isize; /* total change in size */ - int new_isize; /* di_size after adding name */ - int objchange; /* changing to 8-byte inodes */ - xfs_dir2_data_aoff_t offset = 0; /* offset for new entry */ - int pick; /* which algorithm to use */ - xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ - xfs_dir2_sf_entry_t *sfep = NULL; /* shortform entry */ - - trace_xfs_dir2_sf_addname(args); - - ASSERT(xfs_dir2_sf_lookup(args) == -ENOENT); - dp = args->dp; - ASSERT(dp->i_df.if_flags & XFS_IFINLINE); - /* - * Make sure the shortform value has some of its header. - */ - if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { - ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); - return -EIO; - } - ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); - ASSERT(dp->i_df.if_u1.if_data != NULL); - sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count)); - /* - * Compute entry (and change in) size. - */ - incr_isize = dp->d_ops->sf_entsize(sfp, args->namelen); - objchange = 0; - - /* - * Do we have to change to 8 byte inodes? - */ - if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) { - /* - * Yes, adjust the inode size. old count + (parent + new) - */ - incr_isize += (sfp->count + 2) * XFS_INO64_DIFF; - objchange = 1; - } - - new_isize = (int)dp->i_d.di_size + incr_isize; - /* - * Won't fit as shortform any more (due to size), - * or the pick routine says it won't (due to offset values). - */ - if (new_isize > XFS_IFORK_DSIZE(dp) || - (pick = - xfs_dir2_sf_addname_pick(args, objchange, &sfep, &offset)) == 0) { - /* - * Just checking or no space reservation, it doesn't fit. - */ - if ((args->op_flags & XFS_DA_OP_JUSTCHECK) || args->total == 0) - return -ENOSPC; - /* - * Convert to block form then add the name. - */ - error = xfs_dir2_sf_to_block(args); - if (error) - return error; - return xfs_dir2_block_addname(args); - } - /* - * Just checking, it fits. - */ - if (args->op_flags & XFS_DA_OP_JUSTCHECK) - return 0; - /* - * Do it the easy way - just add it at the end. - */ - if (pick == 1) - xfs_dir2_sf_addname_easy(args, sfep, offset, new_isize); - /* - * Do it the hard way - look for a place to insert the new entry. - * Convert to 8 byte inode numbers first if necessary. - */ - else { - ASSERT(pick == 2); - if (objchange) - xfs_dir2_sf_toino8(args); - xfs_dir2_sf_addname_hard(args, objchange, new_isize); - } - xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); - return 0; -} - -/* - * Add the new entry the "easy" way. - * This is copying the old directory and adding the new entry at the end. - * Since it's sorted by "offset" we need room after the last offset - * that's already there, and then room to convert to a block directory. - * This is already checked by the pick routine. - */ -static void -xfs_dir2_sf_addname_easy( - xfs_da_args_t *args, /* operation arguments */ - xfs_dir2_sf_entry_t *sfep, /* pointer to new entry */ - xfs_dir2_data_aoff_t offset, /* offset to use for new ent */ - int new_isize) /* new directory size */ -{ - int byteoff; /* byte offset in sf dir */ - xfs_inode_t *dp; /* incore directory inode */ - xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ - - dp = args->dp; - - sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - byteoff = (int)((char *)sfep - (char *)sfp); - /* - * Grow the in-inode space. - */ - xfs_idata_realloc(dp, dp->d_ops->sf_entsize(sfp, args->namelen), - XFS_DATA_FORK); - /* - * Need to set up again due to realloc of the inode data. - */ - sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + byteoff); - /* - * Fill in the new entry. - */ - sfep->namelen = args->namelen; - xfs_dir2_sf_put_offset(sfep, offset); - memcpy(sfep->name, args->name, sfep->namelen); - dp->d_ops->sf_put_ino(sfp, sfep, args->inumber); - dp->d_ops->sf_put_ftype(sfep, args->filetype); - - /* - * Update the header and inode. - */ - sfp->count++; - if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) - sfp->i8count++; - dp->i_d.di_size = new_isize; - xfs_dir2_sf_check(args); -} - -/* - * Add the new entry the "hard" way. - * The caller has already converted to 8 byte inode numbers if necessary, - * in which case we need to leave the i8count at 1. - * Find a hole that the new entry will fit into, and copy - * the first part of the entries, the new entry, and the last part of - * the entries. - */ -/* ARGSUSED */ -static void -xfs_dir2_sf_addname_hard( - xfs_da_args_t *args, /* operation arguments */ - int objchange, /* changing inode number size */ - int new_isize) /* new directory size */ -{ - int add_datasize; /* data size need for new ent */ - char *buf; /* buffer for old */ - xfs_inode_t *dp; /* incore directory inode */ - int eof; /* reached end of old dir */ - int nbytes; /* temp for byte copies */ - xfs_dir2_data_aoff_t new_offset; /* next offset value */ - xfs_dir2_data_aoff_t offset; /* current offset value */ - int old_isize; /* previous di_size */ - xfs_dir2_sf_entry_t *oldsfep; /* entry in original dir */ - xfs_dir2_sf_hdr_t *oldsfp; /* original shortform dir */ - xfs_dir2_sf_entry_t *sfep; /* entry in new dir */ - xfs_dir2_sf_hdr_t *sfp; /* new shortform dir */ - - /* - * Copy the old directory to the stack buffer. - */ - dp = args->dp; - - sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - old_isize = (int)dp->i_d.di_size; - buf = kmem_alloc(old_isize, KM_SLEEP); - oldsfp = (xfs_dir2_sf_hdr_t *)buf; - memcpy(oldsfp, sfp, old_isize); - /* - * Loop over the old directory finding the place we're going - * to insert the new entry. - * If it's going to end up at the end then oldsfep will point there. - */ - for (offset = dp->d_ops->data_first_offset, - oldsfep = xfs_dir2_sf_firstentry(oldsfp), - add_datasize = dp->d_ops->data_entsize(args->namelen), - eof = (char *)oldsfep == &buf[old_isize]; - !eof; - offset = new_offset + dp->d_ops->data_entsize(oldsfep->namelen), - oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep), - eof = (char *)oldsfep == &buf[old_isize]) { - new_offset = xfs_dir2_sf_get_offset(oldsfep); - if (offset + add_datasize <= new_offset) - break; - } - /* - * Get rid of the old directory, then allocate space for - * the new one. We do this so xfs_idata_realloc won't copy - * the data. - */ - xfs_idata_realloc(dp, -old_isize, XFS_DATA_FORK); - xfs_idata_realloc(dp, new_isize, XFS_DATA_FORK); - /* - * Reset the pointer since the buffer was reallocated. - */ - sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - /* - * Copy the first part of the directory, including the header. - */ - nbytes = (int)((char *)oldsfep - (char *)oldsfp); - memcpy(sfp, oldsfp, nbytes); - sfep = (xfs_dir2_sf_entry_t *)((char *)sfp + nbytes); - /* - * Fill in the new entry, and update the header counts. - */ - sfep->namelen = args->namelen; - xfs_dir2_sf_put_offset(sfep, offset); - memcpy(sfep->name, args->name, sfep->namelen); - dp->d_ops->sf_put_ino(sfp, sfep, args->inumber); - dp->d_ops->sf_put_ftype(sfep, args->filetype); - sfp->count++; - if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && !objchange) - sfp->i8count++; - /* - * If there's more left to copy, do that. - */ - if (!eof) { - sfep = dp->d_ops->sf_nextentry(sfp, sfep); - memcpy(sfep, oldsfep, old_isize - nbytes); - } - kmem_free(buf); - dp->i_d.di_size = new_isize; - xfs_dir2_sf_check(args); -} - -/* - * Decide if the new entry will fit at all. - * If it will fit, pick between adding the new entry to the end (easy) - * or somewhere else (hard). - * Return 0 (won't fit), 1 (easy), 2 (hard). - */ -/*ARGSUSED*/ -static int /* pick result */ -xfs_dir2_sf_addname_pick( - xfs_da_args_t *args, /* operation arguments */ - int objchange, /* inode # size changes */ - xfs_dir2_sf_entry_t **sfepp, /* out(1): new entry ptr */ - xfs_dir2_data_aoff_t *offsetp) /* out(1): new offset */ -{ - xfs_inode_t *dp; /* incore directory inode */ - int holefit; /* found hole it will fit in */ - int i; /* entry number */ - xfs_dir2_data_aoff_t offset; /* data block offset */ - xfs_dir2_sf_entry_t *sfep; /* shortform entry */ - xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ - int size; /* entry's data size */ - int used; /* data bytes used */ - - dp = args->dp; - - sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - size = dp->d_ops->data_entsize(args->namelen); - offset = dp->d_ops->data_first_offset; - sfep = xfs_dir2_sf_firstentry(sfp); - holefit = 0; - /* - * Loop over sf entries. - * Keep track of data offset and whether we've seen a place - * to insert the new entry. - */ - for (i = 0; i < sfp->count; i++) { - if (!holefit) - holefit = offset + size <= xfs_dir2_sf_get_offset(sfep); - offset = xfs_dir2_sf_get_offset(sfep) + - dp->d_ops->data_entsize(sfep->namelen); - sfep = dp->d_ops->sf_nextentry(sfp, sfep); - } - /* - * Calculate data bytes used excluding the new entry, if this - * was a data block (block form directory). - */ - used = offset + - (sfp->count + 3) * (uint)sizeof(xfs_dir2_leaf_entry_t) + - (uint)sizeof(xfs_dir2_block_tail_t); - /* - * If it won't fit in a block form then we can't insert it, - * we'll go back, convert to block, then try the insert and convert - * to leaf. - */ - if (used + (holefit ? 0 : size) > args->geo->blksize) - return 0; - /* - * If changing the inode number size, do it the hard way. - */ - if (objchange) - return 2; - /* - * If it won't fit at the end then do it the hard way (use the hole). - */ - if (used + size > args->geo->blksize) - return 2; - /* - * Do it the easy way. - */ - *sfepp = sfep; - *offsetp = offset; - return 1; -} - -#ifdef DEBUG -/* - * Check consistency of shortform directory, assert if bad. - */ -static void -xfs_dir2_sf_check( - xfs_da_args_t *args) /* operation arguments */ -{ - xfs_inode_t *dp; /* incore directory inode */ - int i; /* entry number */ - int i8count; /* number of big inode#s */ - xfs_ino_t ino; /* entry inode number */ - int offset; /* data offset */ - xfs_dir2_sf_entry_t *sfep; /* shortform dir entry */ - xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ - - dp = args->dp; - - sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - offset = dp->d_ops->data_first_offset; - ino = dp->d_ops->sf_get_parent_ino(sfp); - i8count = ino > XFS_DIR2_MAX_SHORT_INUM; - - for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); - i < sfp->count; - i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { - ASSERT(xfs_dir2_sf_get_offset(sfep) >= offset); - ino = dp->d_ops->sf_get_ino(sfp, sfep); - i8count += ino > XFS_DIR2_MAX_SHORT_INUM; - offset = - xfs_dir2_sf_get_offset(sfep) + - dp->d_ops->data_entsize(sfep->namelen); - ASSERT(dp->d_ops->sf_get_ftype(sfep) < XFS_DIR3_FT_MAX); - } - ASSERT(i8count == sfp->i8count); - ASSERT((char *)sfep - (char *)sfp == dp->i_d.di_size); - ASSERT(offset + - (sfp->count + 2) * (uint)sizeof(xfs_dir2_leaf_entry_t) + - (uint)sizeof(xfs_dir2_block_tail_t) <= args->geo->blksize); -} -#endif /* DEBUG */ - -/* - * Create a new (shortform) directory. - */ -int /* error, always 0 */ -xfs_dir2_sf_create( - xfs_da_args_t *args, /* operation arguments */ - xfs_ino_t pino) /* parent inode number */ -{ - xfs_inode_t *dp; /* incore directory inode */ - int i8count; /* parent inode is an 8-byte number */ - xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ - int size; /* directory size */ - - trace_xfs_dir2_sf_create(args); - - dp = args->dp; - - ASSERT(dp != NULL); - ASSERT(dp->i_d.di_size == 0); - /* - * If it's currently a zero-length extent file, - * convert it to local format. - */ - if (dp->i_d.di_format == XFS_DINODE_FMT_EXTENTS) { - dp->i_df.if_flags &= ~XFS_IFEXTENTS; /* just in case */ - dp->i_d.di_format = XFS_DINODE_FMT_LOCAL; - xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE); - dp->i_df.if_flags |= XFS_IFINLINE; - } - ASSERT(dp->i_df.if_flags & XFS_IFINLINE); - ASSERT(dp->i_df.if_bytes == 0); - i8count = pino > XFS_DIR2_MAX_SHORT_INUM; - size = xfs_dir2_sf_hdr_size(i8count); - /* - * Make a buffer for the data. - */ - xfs_idata_realloc(dp, size, XFS_DATA_FORK); - /* - * Fill in the header, - */ - sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - sfp->i8count = i8count; - /* - * Now can put in the inode number, since i8count is set. - */ - dp->d_ops->sf_put_parent_ino(sfp, pino); - sfp->count = 0; - dp->i_d.di_size = size; - xfs_dir2_sf_check(args); - xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); - return 0; -} - -/* - * Lookup an entry in a shortform directory. - * Returns EEXIST if found, ENOENT if not found. - */ -int /* error */ -xfs_dir2_sf_lookup( - xfs_da_args_t *args) /* operation arguments */ -{ - xfs_inode_t *dp; /* incore directory inode */ - int i; /* entry index */ - int error; - xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ - xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ - enum xfs_dacmp cmp; /* comparison result */ - xfs_dir2_sf_entry_t *ci_sfep; /* case-insens. entry */ - - trace_xfs_dir2_sf_lookup(args); - - xfs_dir2_sf_check(args); - dp = args->dp; - - ASSERT(dp->i_df.if_flags & XFS_IFINLINE); - /* - * Bail out if the directory is way too short. - */ - if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { - ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); - return -EIO; - } - ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); - ASSERT(dp->i_df.if_u1.if_data != NULL); - sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count)); - /* - * Special case for . - */ - if (args->namelen == 1 && args->name[0] == '.') { - args->inumber = dp->i_ino; - args->cmpresult = XFS_CMP_EXACT; - args->filetype = XFS_DIR3_FT_DIR; - return -EEXIST; - } - /* - * Special case for .. - */ - if (args->namelen == 2 && - args->name[0] == '.' && args->name[1] == '.') { - args->inumber = dp->d_ops->sf_get_parent_ino(sfp); - args->cmpresult = XFS_CMP_EXACT; - args->filetype = XFS_DIR3_FT_DIR; - return -EEXIST; - } - /* - * Loop over all the entries trying to match ours. - */ - ci_sfep = NULL; - for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; - i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { - /* - * Compare name and if it's an exact match, return the inode - * number. If it's the first case-insensitive match, store the - * inode number and continue looking for an exact match. - */ - cmp = dp->i_mount->m_dirnameops->compname(args, sfep->name, - sfep->namelen); - if (cmp != XFS_CMP_DIFFERENT && cmp != args->cmpresult) { - args->cmpresult = cmp; - args->inumber = dp->d_ops->sf_get_ino(sfp, sfep); - args->filetype = dp->d_ops->sf_get_ftype(sfep); - if (cmp == XFS_CMP_EXACT) - return -EEXIST; - ci_sfep = sfep; - } - } - ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); - /* - * Here, we can only be doing a lookup (not a rename or replace). - * If a case-insensitive match was not found, return -ENOENT. - */ - if (!ci_sfep) - return -ENOENT; - /* otherwise process the CI match as required by the caller */ - error = xfs_dir_cilookup_result(args, ci_sfep->name, ci_sfep->namelen); - return error; -} - -/* - * Remove an entry from a shortform directory. - */ -int /* error */ -xfs_dir2_sf_removename( - xfs_da_args_t *args) -{ - int byteoff; /* offset of removed entry */ - xfs_inode_t *dp; /* incore directory inode */ - int entsize; /* this entry's size */ - int i; /* shortform entry index */ - int newsize; /* new inode size */ - int oldsize; /* old inode size */ - xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ - xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ - - trace_xfs_dir2_sf_removename(args); - - dp = args->dp; - - ASSERT(dp->i_df.if_flags & XFS_IFINLINE); - oldsize = (int)dp->i_d.di_size; - /* - * Bail out if the directory is way too short. - */ - if (oldsize < offsetof(xfs_dir2_sf_hdr_t, parent)) { - ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); - return -EIO; - } - ASSERT(dp->i_df.if_bytes == oldsize); - ASSERT(dp->i_df.if_u1.if_data != NULL); - sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - ASSERT(oldsize >= xfs_dir2_sf_hdr_size(sfp->i8count)); - /* - * Loop over the old directory entries. - * Find the one we're deleting. - */ - for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; - i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { - if (xfs_da_compname(args, sfep->name, sfep->namelen) == - XFS_CMP_EXACT) { - ASSERT(dp->d_ops->sf_get_ino(sfp, sfep) == - args->inumber); - break; - } - } - /* - * Didn't find it. - */ - if (i == sfp->count) - return -ENOENT; - /* - * Calculate sizes. - */ - byteoff = (int)((char *)sfep - (char *)sfp); - entsize = dp->d_ops->sf_entsize(sfp, args->namelen); - newsize = oldsize - entsize; - /* - * Copy the part if any after the removed entry, sliding it down. - */ - if (byteoff + entsize < oldsize) - memmove((char *)sfp + byteoff, (char *)sfp + byteoff + entsize, - oldsize - (byteoff + entsize)); - /* - * Fix up the header and file size. - */ - sfp->count--; - dp->i_d.di_size = newsize; - /* - * Reallocate, making it smaller. - */ - xfs_idata_realloc(dp, newsize - oldsize, XFS_DATA_FORK); - sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - /* - * Are we changing inode number size? - */ - if (args->inumber > XFS_DIR2_MAX_SHORT_INUM) { - if (sfp->i8count == 1) - xfs_dir2_sf_toino4(args); - else - sfp->i8count--; - } - xfs_dir2_sf_check(args); - xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); - return 0; -} - -/* - * Replace the inode number of an entry in a shortform directory. - */ -int /* error */ -xfs_dir2_sf_replace( - xfs_da_args_t *args) /* operation arguments */ -{ - xfs_inode_t *dp; /* incore directory inode */ - int i; /* entry index */ - xfs_ino_t ino=0; /* entry old inode number */ - int i8elevated; /* sf_toino8 set i8count=1 */ - xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ - xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ - - trace_xfs_dir2_sf_replace(args); - - dp = args->dp; - - ASSERT(dp->i_df.if_flags & XFS_IFINLINE); - /* - * Bail out if the shortform directory is way too small. - */ - if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { - ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); - return -EIO; - } - ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); - ASSERT(dp->i_df.if_u1.if_data != NULL); - sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - ASSERT(dp->i_d.di_size >= xfs_dir2_sf_hdr_size(sfp->i8count)); - - /* - * New inode number is large, and need to convert to 8-byte inodes. - */ - if (args->inumber > XFS_DIR2_MAX_SHORT_INUM && sfp->i8count == 0) { - int error; /* error return value */ - int newsize; /* new inode size */ - - newsize = dp->i_df.if_bytes + (sfp->count + 1) * XFS_INO64_DIFF; - /* - * Won't fit as shortform, convert to block then do replace. - */ - if (newsize > XFS_IFORK_DSIZE(dp)) { - error = xfs_dir2_sf_to_block(args); - if (error) { - return error; - } - return xfs_dir2_block_replace(args); - } - /* - * Still fits, convert to 8-byte now. - */ - xfs_dir2_sf_toino8(args); - i8elevated = 1; - sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - } else - i8elevated = 0; - - ASSERT(args->namelen != 1 || args->name[0] != '.'); - /* - * Replace ..'s entry. - */ - if (args->namelen == 2 && - args->name[0] == '.' && args->name[1] == '.') { - ino = dp->d_ops->sf_get_parent_ino(sfp); - ASSERT(args->inumber != ino); - dp->d_ops->sf_put_parent_ino(sfp, args->inumber); - } - /* - * Normal entry, look for the name. - */ - else { - for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp); i < sfp->count; - i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep)) { - if (xfs_da_compname(args, sfep->name, sfep->namelen) == - XFS_CMP_EXACT) { - ino = dp->d_ops->sf_get_ino(sfp, sfep); - ASSERT(args->inumber != ino); - dp->d_ops->sf_put_ino(sfp, sfep, args->inumber); - dp->d_ops->sf_put_ftype(sfep, args->filetype); - break; - } - } - /* - * Didn't find it. - */ - if (i == sfp->count) { - ASSERT(args->op_flags & XFS_DA_OP_OKNOENT); - if (i8elevated) - xfs_dir2_sf_toino4(args); - return -ENOENT; - } - } - /* - * See if the old number was large, the new number is small. - */ - if (ino > XFS_DIR2_MAX_SHORT_INUM && - args->inumber <= XFS_DIR2_MAX_SHORT_INUM) { - /* - * And the old count was one, so need to convert to small. - */ - if (sfp->i8count == 1) - xfs_dir2_sf_toino4(args); - else - sfp->i8count--; - } - /* - * See if the old number was small, the new number is large. - */ - if (ino <= XFS_DIR2_MAX_SHORT_INUM && - args->inumber > XFS_DIR2_MAX_SHORT_INUM) { - /* - * add to the i8count unless we just converted to 8-byte - * inodes (which does an implied i8count = 1) - */ - ASSERT(sfp->i8count != 0); - if (!i8elevated) - sfp->i8count++; - } - xfs_dir2_sf_check(args); - xfs_trans_log_inode(args->trans, dp, XFS_ILOG_DDATA); - return 0; -} - -/* - * Convert from 8-byte inode numbers to 4-byte inode numbers. - * The last 8-byte inode number is gone, but the count is still 1. - */ -static void -xfs_dir2_sf_toino4( - xfs_da_args_t *args) /* operation arguments */ -{ - char *buf; /* old dir's buffer */ - xfs_inode_t *dp; /* incore directory inode */ - int i; /* entry index */ - int newsize; /* new inode size */ - xfs_dir2_sf_entry_t *oldsfep; /* old sf entry */ - xfs_dir2_sf_hdr_t *oldsfp; /* old sf directory */ - int oldsize; /* old inode size */ - xfs_dir2_sf_entry_t *sfep; /* new sf entry */ - xfs_dir2_sf_hdr_t *sfp; /* new sf directory */ - - trace_xfs_dir2_sf_toino4(args); - - dp = args->dp; - - /* - * Copy the old directory to the buffer. - * Then nuke it from the inode, and add the new buffer to the inode. - * Don't want xfs_idata_realloc copying the data here. - */ - oldsize = dp->i_df.if_bytes; - buf = kmem_alloc(oldsize, KM_SLEEP); - oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - ASSERT(oldsfp->i8count == 1); - memcpy(buf, oldsfp, oldsize); - /* - * Compute the new inode size. - */ - newsize = oldsize - (oldsfp->count + 1) * XFS_INO64_DIFF; - xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK); - xfs_idata_realloc(dp, newsize, XFS_DATA_FORK); - /* - * Reset our pointers, the data has moved. - */ - oldsfp = (xfs_dir2_sf_hdr_t *)buf; - sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - /* - * Fill in the new header. - */ - sfp->count = oldsfp->count; - sfp->i8count = 0; - dp->d_ops->sf_put_parent_ino(sfp, dp->d_ops->sf_get_parent_ino(oldsfp)); - /* - * Copy the entries field by field. - */ - for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp), - oldsfep = xfs_dir2_sf_firstentry(oldsfp); - i < sfp->count; - i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep), - oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep)) { - sfep->namelen = oldsfep->namelen; - memcpy(sfep->offset, oldsfep->offset, sizeof(sfep->offset)); - memcpy(sfep->name, oldsfep->name, sfep->namelen); - dp->d_ops->sf_put_ino(sfp, sfep, - dp->d_ops->sf_get_ino(oldsfp, oldsfep)); - dp->d_ops->sf_put_ftype(sfep, dp->d_ops->sf_get_ftype(oldsfep)); - } - /* - * Clean up the inode. - */ - kmem_free(buf); - dp->i_d.di_size = newsize; - xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); -} - -/* - * Convert existing entries from 4-byte inode numbers to 8-byte inode numbers. - * The new entry w/ an 8-byte inode number is not there yet; we leave with - * i8count set to 1, but no corresponding 8-byte entry. - */ -static void -xfs_dir2_sf_toino8( - xfs_da_args_t *args) /* operation arguments */ -{ - char *buf; /* old dir's buffer */ - xfs_inode_t *dp; /* incore directory inode */ - int i; /* entry index */ - int newsize; /* new inode size */ - xfs_dir2_sf_entry_t *oldsfep; /* old sf entry */ - xfs_dir2_sf_hdr_t *oldsfp; /* old sf directory */ - int oldsize; /* old inode size */ - xfs_dir2_sf_entry_t *sfep; /* new sf entry */ - xfs_dir2_sf_hdr_t *sfp; /* new sf directory */ - - trace_xfs_dir2_sf_toino8(args); - - dp = args->dp; - - /* - * Copy the old directory to the buffer. - * Then nuke it from the inode, and add the new buffer to the inode. - * Don't want xfs_idata_realloc copying the data here. - */ - oldsize = dp->i_df.if_bytes; - buf = kmem_alloc(oldsize, KM_SLEEP); - oldsfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - ASSERT(oldsfp->i8count == 0); - memcpy(buf, oldsfp, oldsize); - /* - * Compute the new inode size (nb: entry count + 1 for parent) - */ - newsize = oldsize + (oldsfp->count + 1) * XFS_INO64_DIFF; - xfs_idata_realloc(dp, -oldsize, XFS_DATA_FORK); - xfs_idata_realloc(dp, newsize, XFS_DATA_FORK); - /* - * Reset our pointers, the data has moved. - */ - oldsfp = (xfs_dir2_sf_hdr_t *)buf; - sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - /* - * Fill in the new header. - */ - sfp->count = oldsfp->count; - sfp->i8count = 1; - dp->d_ops->sf_put_parent_ino(sfp, dp->d_ops->sf_get_parent_ino(oldsfp)); - /* - * Copy the entries field by field. - */ - for (i = 0, sfep = xfs_dir2_sf_firstentry(sfp), - oldsfep = xfs_dir2_sf_firstentry(oldsfp); - i < sfp->count; - i++, sfep = dp->d_ops->sf_nextentry(sfp, sfep), - oldsfep = dp->d_ops->sf_nextentry(oldsfp, oldsfep)) { - sfep->namelen = oldsfep->namelen; - memcpy(sfep->offset, oldsfep->offset, sizeof(sfep->offset)); - memcpy(sfep->name, oldsfep->name, sfep->namelen); - dp->d_ops->sf_put_ino(sfp, sfep, - dp->d_ops->sf_get_ino(oldsfp, oldsfep)); - dp->d_ops->sf_put_ftype(sfep, dp->d_ops->sf_get_ftype(oldsfep)); - } - /* - * Clean up the inode. - */ - kmem_free(buf); - dp->i_d.di_size = newsize; - xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_DDATA); -} diff --git a/src/linux/fs/xfs/libxfs/xfs_dquot_buf.c b/src/linux/fs/xfs/libxfs/xfs_dquot_buf.c deleted file mode 100644 index ac9a003..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_dquot_buf.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - * Copyright (c) 2000-2006 Silicon Graphics, Inc. - * Copyright (c) 2013 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_inode.h" -#include "xfs_quota.h" -#include "xfs_trans.h" -#include "xfs_qm.h" -#include "xfs_error.h" -#include "xfs_cksum.h" -#include "xfs_trace.h" - -int -xfs_calc_dquots_per_chunk( - unsigned int nbblks) /* basic block units */ -{ - unsigned int ndquots; - - ASSERT(nbblks > 0); - ndquots = BBTOB(nbblks); - do_div(ndquots, sizeof(xfs_dqblk_t)); - - return ndquots; -} - -/* - * Do some primitive error checking on ondisk dquot data structures. - */ -int -xfs_dqcheck( - struct xfs_mount *mp, - xfs_disk_dquot_t *ddq, - xfs_dqid_t id, - uint type, /* used only when IO_dorepair is true */ - uint flags, - const char *str) -{ - xfs_dqblk_t *d = (xfs_dqblk_t *)ddq; - int errs = 0; - - /* - * We can encounter an uninitialized dquot buffer for 2 reasons: - * 1. If we crash while deleting the quotainode(s), and those blks got - * used for user data. This is because we take the path of regular - * file deletion; however, the size field of quotainodes is never - * updated, so all the tricks that we play in itruncate_finish - * don't quite matter. - * - * 2. We don't play the quota buffers when there's a quotaoff logitem. - * But the allocation will be replayed so we'll end up with an - * uninitialized quota block. - * - * This is all fine; things are still consistent, and we haven't lost - * any quota information. Just don't complain about bad dquot blks. - */ - if (ddq->d_magic != cpu_to_be16(XFS_DQUOT_MAGIC)) { - if (flags & XFS_QMOPT_DOWARN) - xfs_alert(mp, - "%s : XFS dquot ID 0x%x, magic 0x%x != 0x%x", - str, id, be16_to_cpu(ddq->d_magic), XFS_DQUOT_MAGIC); - errs++; - } - if (ddq->d_version != XFS_DQUOT_VERSION) { - if (flags & XFS_QMOPT_DOWARN) - xfs_alert(mp, - "%s : XFS dquot ID 0x%x, version 0x%x != 0x%x", - str, id, ddq->d_version, XFS_DQUOT_VERSION); - errs++; - } - - if (ddq->d_flags != XFS_DQ_USER && - ddq->d_flags != XFS_DQ_PROJ && - ddq->d_flags != XFS_DQ_GROUP) { - if (flags & XFS_QMOPT_DOWARN) - xfs_alert(mp, - "%s : XFS dquot ID 0x%x, unknown flags 0x%x", - str, id, ddq->d_flags); - errs++; - } - - if (id != -1 && id != be32_to_cpu(ddq->d_id)) { - if (flags & XFS_QMOPT_DOWARN) - xfs_alert(mp, - "%s : ondisk-dquot 0x%p, ID mismatch: " - "0x%x expected, found id 0x%x", - str, ddq, id, be32_to_cpu(ddq->d_id)); - errs++; - } - - if (!errs && ddq->d_id) { - if (ddq->d_blk_softlimit && - be64_to_cpu(ddq->d_bcount) > - be64_to_cpu(ddq->d_blk_softlimit)) { - if (!ddq->d_btimer) { - if (flags & XFS_QMOPT_DOWARN) - xfs_alert(mp, - "%s : Dquot ID 0x%x (0x%p) BLK TIMER NOT STARTED", - str, (int)be32_to_cpu(ddq->d_id), ddq); - errs++; - } - } - if (ddq->d_ino_softlimit && - be64_to_cpu(ddq->d_icount) > - be64_to_cpu(ddq->d_ino_softlimit)) { - if (!ddq->d_itimer) { - if (flags & XFS_QMOPT_DOWARN) - xfs_alert(mp, - "%s : Dquot ID 0x%x (0x%p) INODE TIMER NOT STARTED", - str, (int)be32_to_cpu(ddq->d_id), ddq); - errs++; - } - } - if (ddq->d_rtb_softlimit && - be64_to_cpu(ddq->d_rtbcount) > - be64_to_cpu(ddq->d_rtb_softlimit)) { - if (!ddq->d_rtbtimer) { - if (flags & XFS_QMOPT_DOWARN) - xfs_alert(mp, - "%s : Dquot ID 0x%x (0x%p) RTBLK TIMER NOT STARTED", - str, (int)be32_to_cpu(ddq->d_id), ddq); - errs++; - } - } - } - - if (!errs || !(flags & XFS_QMOPT_DQREPAIR)) - return errs; - - if (flags & XFS_QMOPT_DOWARN) - xfs_notice(mp, "Re-initializing dquot ID 0x%x", id); - - /* - * Typically, a repair is only requested by quotacheck. - */ - ASSERT(id != -1); - ASSERT(flags & XFS_QMOPT_DQREPAIR); - memset(d, 0, sizeof(xfs_dqblk_t)); - - d->dd_diskdq.d_magic = cpu_to_be16(XFS_DQUOT_MAGIC); - d->dd_diskdq.d_version = XFS_DQUOT_VERSION; - d->dd_diskdq.d_flags = type; - d->dd_diskdq.d_id = cpu_to_be32(id); - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - uuid_copy(&d->dd_uuid, &mp->m_sb.sb_meta_uuid); - xfs_update_cksum((char *)d, sizeof(struct xfs_dqblk), - XFS_DQUOT_CRC_OFF); - } - - return errs; -} - -STATIC bool -xfs_dquot_buf_verify_crc( - struct xfs_mount *mp, - struct xfs_buf *bp) -{ - struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr; - int ndquots; - int i; - - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return true; - - /* - * if we are in log recovery, the quota subsystem has not been - * initialised so we have no quotainfo structure. In that case, we need - * to manually calculate the number of dquots in the buffer. - */ - if (mp->m_quotainfo) - ndquots = mp->m_quotainfo->qi_dqperchunk; - else - ndquots = xfs_calc_dquots_per_chunk(bp->b_length); - - for (i = 0; i < ndquots; i++, d++) { - if (!xfs_verify_cksum((char *)d, sizeof(struct xfs_dqblk), - XFS_DQUOT_CRC_OFF)) - return false; - if (!uuid_equal(&d->dd_uuid, &mp->m_sb.sb_meta_uuid)) - return false; - } - return true; -} - -STATIC bool -xfs_dquot_buf_verify( - struct xfs_mount *mp, - struct xfs_buf *bp, - int warn) -{ - struct xfs_dqblk *d = (struct xfs_dqblk *)bp->b_addr; - xfs_dqid_t id = 0; - int ndquots; - int i; - - /* - * if we are in log recovery, the quota subsystem has not been - * initialised so we have no quotainfo structure. In that case, we need - * to manually calculate the number of dquots in the buffer. - */ - if (mp->m_quotainfo) - ndquots = mp->m_quotainfo->qi_dqperchunk; - else - ndquots = xfs_calc_dquots_per_chunk(bp->b_length); - - /* - * On the first read of the buffer, verify that each dquot is valid. - * We don't know what the id of the dquot is supposed to be, just that - * they should be increasing monotonically within the buffer. If the - * first id is corrupt, then it will fail on the second dquot in the - * buffer so corruptions could point to the wrong dquot in this case. - */ - for (i = 0; i < ndquots; i++) { - struct xfs_disk_dquot *ddq; - int error; - - ddq = &d[i].dd_diskdq; - - if (i == 0) - id = be32_to_cpu(ddq->d_id); - - error = xfs_dqcheck(mp, ddq, id + i, 0, warn, __func__); - if (error) - return false; - } - return true; -} - -static void -xfs_dquot_buf_read_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - - if (!xfs_dquot_buf_verify_crc(mp, bp)) - xfs_buf_ioerror(bp, -EFSBADCRC); - else if (!xfs_dquot_buf_verify(mp, bp, XFS_QMOPT_DOWARN)) - xfs_buf_ioerror(bp, -EFSCORRUPTED); - - if (bp->b_error) - xfs_verifier_error(bp); -} - -/* - * readahead errors are silent and simply leave the buffer as !done so a real - * read will then be run with the xfs_dquot_buf_ops verifier. See - * xfs_inode_buf_verify() for why we use EIO and ~XBF_DONE here rather than - * reporting the failure. - */ -static void -xfs_dquot_buf_readahead_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - - if (!xfs_dquot_buf_verify_crc(mp, bp) || - !xfs_dquot_buf_verify(mp, bp, 0)) { - xfs_buf_ioerror(bp, -EIO); - bp->b_flags &= ~XBF_DONE; - } -} - -/* - * we don't calculate the CRC here as that is done when the dquot is flushed to - * the buffer after the update is done. This ensures that the dquot in the - * buffer always has an up-to-date CRC value. - */ -static void -xfs_dquot_buf_write_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - - if (!xfs_dquot_buf_verify(mp, bp, XFS_QMOPT_DOWARN)) { - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - return; - } -} - -const struct xfs_buf_ops xfs_dquot_buf_ops = { - .name = "xfs_dquot", - .verify_read = xfs_dquot_buf_read_verify, - .verify_write = xfs_dquot_buf_write_verify, -}; - -const struct xfs_buf_ops xfs_dquot_buf_ra_ops = { - .name = "xfs_dquot_ra", - .verify_read = xfs_dquot_buf_readahead_verify, - .verify_write = xfs_dquot_buf_write_verify, -}; diff --git a/src/linux/fs/xfs/libxfs/xfs_format.h b/src/linux/fs/xfs/libxfs/xfs_format.h deleted file mode 100644 index 6b7579e..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_format.h +++ /dev/null @@ -1,1729 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_FORMAT_H__ -#define __XFS_FORMAT_H__ - -/* - * XFS On Disk Format Definitions - * - * This header file defines all the on-disk format definitions for - * general XFS objects. Directory and attribute related objects are defined in - * xfs_da_format.h, which log and log item formats are defined in - * xfs_log_format.h. Everything else goes here. - */ - -struct xfs_mount; -struct xfs_trans; -struct xfs_inode; -struct xfs_buf; -struct xfs_ifork; - -/* - * Super block - * Fits into a sector-sized buffer at address 0 of each allocation group. - * Only the first of these is ever updated except during growfs. - */ -#define XFS_SB_MAGIC 0x58465342 /* 'XFSB' */ -#define XFS_SB_VERSION_1 1 /* 5.3, 6.0.1, 6.1 */ -#define XFS_SB_VERSION_2 2 /* 6.2 - attributes */ -#define XFS_SB_VERSION_3 3 /* 6.2 - new inode version */ -#define XFS_SB_VERSION_4 4 /* 6.2+ - bitmask version */ -#define XFS_SB_VERSION_5 5 /* CRC enabled filesystem */ -#define XFS_SB_VERSION_NUMBITS 0x000f -#define XFS_SB_VERSION_ALLFBITS 0xfff0 -#define XFS_SB_VERSION_ATTRBIT 0x0010 -#define XFS_SB_VERSION_NLINKBIT 0x0020 -#define XFS_SB_VERSION_QUOTABIT 0x0040 -#define XFS_SB_VERSION_ALIGNBIT 0x0080 -#define XFS_SB_VERSION_DALIGNBIT 0x0100 -#define XFS_SB_VERSION_SHAREDBIT 0x0200 -#define XFS_SB_VERSION_LOGV2BIT 0x0400 -#define XFS_SB_VERSION_SECTORBIT 0x0800 -#define XFS_SB_VERSION_EXTFLGBIT 0x1000 -#define XFS_SB_VERSION_DIRV2BIT 0x2000 -#define XFS_SB_VERSION_BORGBIT 0x4000 /* ASCII only case-insens. */ -#define XFS_SB_VERSION_MOREBITSBIT 0x8000 - -/* - * The size of a single extended attribute on disk is limited by - * the size of index values within the attribute entries themselves. - * These are be16 fields, so we can only support attribute data - * sizes up to 2^16 bytes in length. - */ -#define XFS_XATTR_SIZE_MAX (1 << 16) - -/* - * Supported feature bit list is just all bits in the versionnum field because - * we've used them all up and understand them all. Except, of course, for the - * shared superblock bit, which nobody knows what it does and so is unsupported. - */ -#define XFS_SB_VERSION_OKBITS \ - ((XFS_SB_VERSION_NUMBITS | XFS_SB_VERSION_ALLFBITS) & \ - ~XFS_SB_VERSION_SHAREDBIT) - -/* - * There are two words to hold XFS "feature" bits: the original - * word, sb_versionnum, and sb_features2. Whenever a bit is set in - * sb_features2, the feature bit XFS_SB_VERSION_MOREBITSBIT must be set. - * - * These defines represent bits in sb_features2. - */ -#define XFS_SB_VERSION2_RESERVED1BIT 0x00000001 -#define XFS_SB_VERSION2_LAZYSBCOUNTBIT 0x00000002 /* Superblk counters */ -#define XFS_SB_VERSION2_RESERVED4BIT 0x00000004 -#define XFS_SB_VERSION2_ATTR2BIT 0x00000008 /* Inline attr rework */ -#define XFS_SB_VERSION2_PARENTBIT 0x00000010 /* parent pointers */ -#define XFS_SB_VERSION2_PROJID32BIT 0x00000080 /* 32 bit project id */ -#define XFS_SB_VERSION2_CRCBIT 0x00000100 /* metadata CRCs */ -#define XFS_SB_VERSION2_FTYPE 0x00000200 /* inode type in dir */ - -#define XFS_SB_VERSION2_OKBITS \ - (XFS_SB_VERSION2_LAZYSBCOUNTBIT | \ - XFS_SB_VERSION2_ATTR2BIT | \ - XFS_SB_VERSION2_PROJID32BIT | \ - XFS_SB_VERSION2_FTYPE) - -/* - * Superblock - in core version. Must match the ondisk version below. - * Must be padded to 64 bit alignment. - */ -typedef struct xfs_sb { - __uint32_t sb_magicnum; /* magic number == XFS_SB_MAGIC */ - __uint32_t sb_blocksize; /* logical block size, bytes */ - xfs_rfsblock_t sb_dblocks; /* number of data blocks */ - xfs_rfsblock_t sb_rblocks; /* number of realtime blocks */ - xfs_rtblock_t sb_rextents; /* number of realtime extents */ - uuid_t sb_uuid; /* user-visible file system unique id */ - xfs_fsblock_t sb_logstart; /* starting block of log if internal */ - xfs_ino_t sb_rootino; /* root inode number */ - xfs_ino_t sb_rbmino; /* bitmap inode for realtime extents */ - xfs_ino_t sb_rsumino; /* summary inode for rt bitmap */ - xfs_agblock_t sb_rextsize; /* realtime extent size, blocks */ - xfs_agblock_t sb_agblocks; /* size of an allocation group */ - xfs_agnumber_t sb_agcount; /* number of allocation groups */ - xfs_extlen_t sb_rbmblocks; /* number of rt bitmap blocks */ - xfs_extlen_t sb_logblocks; /* number of log blocks */ - __uint16_t sb_versionnum; /* header version == XFS_SB_VERSION */ - __uint16_t sb_sectsize; /* volume sector size, bytes */ - __uint16_t sb_inodesize; /* inode size, bytes */ - __uint16_t sb_inopblock; /* inodes per block */ - char sb_fname[12]; /* file system name */ - __uint8_t sb_blocklog; /* log2 of sb_blocksize */ - __uint8_t sb_sectlog; /* log2 of sb_sectsize */ - __uint8_t sb_inodelog; /* log2 of sb_inodesize */ - __uint8_t sb_inopblog; /* log2 of sb_inopblock */ - __uint8_t sb_agblklog; /* log2 of sb_agblocks (rounded up) */ - __uint8_t sb_rextslog; /* log2 of sb_rextents */ - __uint8_t sb_inprogress; /* mkfs is in progress, don't mount */ - __uint8_t sb_imax_pct; /* max % of fs for inode space */ - /* statistics */ - /* - * These fields must remain contiguous. If you really - * want to change their layout, make sure you fix the - * code in xfs_trans_apply_sb_deltas(). - */ - __uint64_t sb_icount; /* allocated inodes */ - __uint64_t sb_ifree; /* free inodes */ - __uint64_t sb_fdblocks; /* free data blocks */ - __uint64_t sb_frextents; /* free realtime extents */ - /* - * End contiguous fields. - */ - xfs_ino_t sb_uquotino; /* user quota inode */ - xfs_ino_t sb_gquotino; /* group quota inode */ - __uint16_t sb_qflags; /* quota flags */ - __uint8_t sb_flags; /* misc. flags */ - __uint8_t sb_shared_vn; /* shared version number */ - xfs_extlen_t sb_inoalignmt; /* inode chunk alignment, fsblocks */ - __uint32_t sb_unit; /* stripe or raid unit */ - __uint32_t sb_width; /* stripe or raid width */ - __uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */ - __uint8_t sb_logsectlog; /* log2 of the log sector size */ - __uint16_t sb_logsectsize; /* sector size for the log, bytes */ - __uint32_t sb_logsunit; /* stripe unit size for the log */ - __uint32_t sb_features2; /* additional feature bits */ - - /* - * bad features2 field as a result of failing to pad the sb structure to - * 64 bits. Some machines will be using this field for features2 bits. - * Easiest just to mark it bad and not use it for anything else. - * - * This is not kept up to date in memory; it is always overwritten by - * the value in sb_features2 when formatting the incore superblock to - * the disk buffer. - */ - __uint32_t sb_bad_features2; - - /* version 5 superblock fields start here */ - - /* feature masks */ - __uint32_t sb_features_compat; - __uint32_t sb_features_ro_compat; - __uint32_t sb_features_incompat; - __uint32_t sb_features_log_incompat; - - __uint32_t sb_crc; /* superblock crc */ - xfs_extlen_t sb_spino_align; /* sparse inode chunk alignment */ - - xfs_ino_t sb_pquotino; /* project quota inode */ - xfs_lsn_t sb_lsn; /* last write sequence */ - uuid_t sb_meta_uuid; /* metadata file system unique id */ - - /* must be padded to 64 bit alignment */ -} xfs_sb_t; - -#define XFS_SB_CRC_OFF offsetof(struct xfs_sb, sb_crc) - -/* - * Superblock - on disk version. Must match the in core version above. - * Must be padded to 64 bit alignment. - */ -typedef struct xfs_dsb { - __be32 sb_magicnum; /* magic number == XFS_SB_MAGIC */ - __be32 sb_blocksize; /* logical block size, bytes */ - __be64 sb_dblocks; /* number of data blocks */ - __be64 sb_rblocks; /* number of realtime blocks */ - __be64 sb_rextents; /* number of realtime extents */ - uuid_t sb_uuid; /* user-visible file system unique id */ - __be64 sb_logstart; /* starting block of log if internal */ - __be64 sb_rootino; /* root inode number */ - __be64 sb_rbmino; /* bitmap inode for realtime extents */ - __be64 sb_rsumino; /* summary inode for rt bitmap */ - __be32 sb_rextsize; /* realtime extent size, blocks */ - __be32 sb_agblocks; /* size of an allocation group */ - __be32 sb_agcount; /* number of allocation groups */ - __be32 sb_rbmblocks; /* number of rt bitmap blocks */ - __be32 sb_logblocks; /* number of log blocks */ - __be16 sb_versionnum; /* header version == XFS_SB_VERSION */ - __be16 sb_sectsize; /* volume sector size, bytes */ - __be16 sb_inodesize; /* inode size, bytes */ - __be16 sb_inopblock; /* inodes per block */ - char sb_fname[12]; /* file system name */ - __u8 sb_blocklog; /* log2 of sb_blocksize */ - __u8 sb_sectlog; /* log2 of sb_sectsize */ - __u8 sb_inodelog; /* log2 of sb_inodesize */ - __u8 sb_inopblog; /* log2 of sb_inopblock */ - __u8 sb_agblklog; /* log2 of sb_agblocks (rounded up) */ - __u8 sb_rextslog; /* log2 of sb_rextents */ - __u8 sb_inprogress; /* mkfs is in progress, don't mount */ - __u8 sb_imax_pct; /* max % of fs for inode space */ - /* statistics */ - /* - * These fields must remain contiguous. If you really - * want to change their layout, make sure you fix the - * code in xfs_trans_apply_sb_deltas(). - */ - __be64 sb_icount; /* allocated inodes */ - __be64 sb_ifree; /* free inodes */ - __be64 sb_fdblocks; /* free data blocks */ - __be64 sb_frextents; /* free realtime extents */ - /* - * End contiguous fields. - */ - __be64 sb_uquotino; /* user quota inode */ - __be64 sb_gquotino; /* group quota inode */ - __be16 sb_qflags; /* quota flags */ - __u8 sb_flags; /* misc. flags */ - __u8 sb_shared_vn; /* shared version number */ - __be32 sb_inoalignmt; /* inode chunk alignment, fsblocks */ - __be32 sb_unit; /* stripe or raid unit */ - __be32 sb_width; /* stripe or raid width */ - __u8 sb_dirblklog; /* log2 of dir block size (fsbs) */ - __u8 sb_logsectlog; /* log2 of the log sector size */ - __be16 sb_logsectsize; /* sector size for the log, bytes */ - __be32 sb_logsunit; /* stripe unit size for the log */ - __be32 sb_features2; /* additional feature bits */ - /* - * bad features2 field as a result of failing to pad the sb - * structure to 64 bits. Some machines will be using this field - * for features2 bits. Easiest just to mark it bad and not use - * it for anything else. - */ - __be32 sb_bad_features2; - - /* version 5 superblock fields start here */ - - /* feature masks */ - __be32 sb_features_compat; - __be32 sb_features_ro_compat; - __be32 sb_features_incompat; - __be32 sb_features_log_incompat; - - __le32 sb_crc; /* superblock crc */ - __be32 sb_spino_align; /* sparse inode chunk alignment */ - - __be64 sb_pquotino; /* project quota inode */ - __be64 sb_lsn; /* last write sequence */ - uuid_t sb_meta_uuid; /* metadata file system unique id */ - - /* must be padded to 64 bit alignment */ -} xfs_dsb_t; - - -/* - * Misc. Flags - warning - these will be cleared by xfs_repair unless - * a feature bit is set when the flag is used. - */ -#define XFS_SBF_NOFLAGS 0x00 /* no flags set */ -#define XFS_SBF_READONLY 0x01 /* only read-only mounts allowed */ - -/* - * define max. shared version we can interoperate with - */ -#define XFS_SB_MAX_SHARED_VN 0 - -#define XFS_SB_VERSION_NUM(sbp) ((sbp)->sb_versionnum & XFS_SB_VERSION_NUMBITS) - -/* - * The first XFS version we support is a v4 superblock with V2 directories. - */ -static inline bool xfs_sb_good_v4_features(struct xfs_sb *sbp) -{ - if (!(sbp->sb_versionnum & XFS_SB_VERSION_DIRV2BIT)) - return false; - - /* check for unknown features in the fs */ - if ((sbp->sb_versionnum & ~XFS_SB_VERSION_OKBITS) || - ((sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT) && - (sbp->sb_features2 & ~XFS_SB_VERSION2_OKBITS))) - return false; - - return true; -} - -static inline bool xfs_sb_good_version(struct xfs_sb *sbp) -{ - if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) - return true; - if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) - return xfs_sb_good_v4_features(sbp); - return false; -} - -/* - * Detect a mismatched features2 field. Older kernels read/wrote - * this into the wrong slot, so to be safe we keep them in sync. - */ -static inline bool xfs_sb_has_mismatched_features2(struct xfs_sb *sbp) -{ - return sbp->sb_bad_features2 != sbp->sb_features2; -} - -static inline bool xfs_sb_version_hasattr(struct xfs_sb *sbp) -{ - return (sbp->sb_versionnum & XFS_SB_VERSION_ATTRBIT); -} - -static inline void xfs_sb_version_addattr(struct xfs_sb *sbp) -{ - sbp->sb_versionnum |= XFS_SB_VERSION_ATTRBIT; -} - -static inline bool xfs_sb_version_hasquota(struct xfs_sb *sbp) -{ - return (sbp->sb_versionnum & XFS_SB_VERSION_QUOTABIT); -} - -static inline void xfs_sb_version_addquota(struct xfs_sb *sbp) -{ - sbp->sb_versionnum |= XFS_SB_VERSION_QUOTABIT; -} - -static inline bool xfs_sb_version_hasalign(struct xfs_sb *sbp) -{ - return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 || - (sbp->sb_versionnum & XFS_SB_VERSION_ALIGNBIT)); -} - -static inline bool xfs_sb_version_hasdalign(struct xfs_sb *sbp) -{ - return (sbp->sb_versionnum & XFS_SB_VERSION_DALIGNBIT); -} - -static inline bool xfs_sb_version_haslogv2(struct xfs_sb *sbp) -{ - return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 || - (sbp->sb_versionnum & XFS_SB_VERSION_LOGV2BIT); -} - -static inline bool xfs_sb_version_hasextflgbit(struct xfs_sb *sbp) -{ - return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 || - (sbp->sb_versionnum & XFS_SB_VERSION_EXTFLGBIT); -} - -static inline bool xfs_sb_version_hassector(struct xfs_sb *sbp) -{ - return (sbp->sb_versionnum & XFS_SB_VERSION_SECTORBIT); -} - -static inline bool xfs_sb_version_hasasciici(struct xfs_sb *sbp) -{ - return (sbp->sb_versionnum & XFS_SB_VERSION_BORGBIT); -} - -static inline bool xfs_sb_version_hasmorebits(struct xfs_sb *sbp) -{ - return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 || - (sbp->sb_versionnum & XFS_SB_VERSION_MOREBITSBIT); -} - -/* - * sb_features2 bit version macros. - */ -static inline bool xfs_sb_version_haslazysbcount(struct xfs_sb *sbp) -{ - return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) || - (xfs_sb_version_hasmorebits(sbp) && - (sbp->sb_features2 & XFS_SB_VERSION2_LAZYSBCOUNTBIT)); -} - -static inline bool xfs_sb_version_hasattr2(struct xfs_sb *sbp) -{ - return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) || - (xfs_sb_version_hasmorebits(sbp) && - (sbp->sb_features2 & XFS_SB_VERSION2_ATTR2BIT)); -} - -static inline void xfs_sb_version_addattr2(struct xfs_sb *sbp) -{ - sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT; - sbp->sb_features2 |= XFS_SB_VERSION2_ATTR2BIT; -} - -static inline void xfs_sb_version_removeattr2(struct xfs_sb *sbp) -{ - sbp->sb_features2 &= ~XFS_SB_VERSION2_ATTR2BIT; - if (!sbp->sb_features2) - sbp->sb_versionnum &= ~XFS_SB_VERSION_MOREBITSBIT; -} - -static inline bool xfs_sb_version_hasprojid32bit(struct xfs_sb *sbp) -{ - return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) || - (xfs_sb_version_hasmorebits(sbp) && - (sbp->sb_features2 & XFS_SB_VERSION2_PROJID32BIT)); -} - -static inline void xfs_sb_version_addprojid32bit(struct xfs_sb *sbp) -{ - sbp->sb_versionnum |= XFS_SB_VERSION_MOREBITSBIT; - sbp->sb_features2 |= XFS_SB_VERSION2_PROJID32BIT; -} - -/* - * Extended v5 superblock feature masks. These are to be used for new v5 - * superblock features only. - * - * Compat features are new features that old kernels will not notice or affect - * and so can mount read-write without issues. - * - * RO-Compat (read only) are features that old kernels can read but will break - * if they write. Hence only read-only mounts of such filesystems are allowed on - * kernels that don't support the feature bit. - * - * InCompat features are features which old kernels will not understand and so - * must not mount. - * - * Log-InCompat features are for changes to log formats or new transactions that - * can't be replayed on older kernels. The fields are set when the filesystem is - * mounted, and a clean unmount clears the fields. - */ -#define XFS_SB_FEAT_COMPAT_ALL 0 -#define XFS_SB_FEAT_COMPAT_UNKNOWN ~XFS_SB_FEAT_COMPAT_ALL -static inline bool -xfs_sb_has_compat_feature( - struct xfs_sb *sbp, - __uint32_t feature) -{ - return (sbp->sb_features_compat & feature) != 0; -} - -#define XFS_SB_FEAT_RO_COMPAT_FINOBT (1 << 0) /* free inode btree */ -#define XFS_SB_FEAT_RO_COMPAT_RMAPBT (1 << 1) /* reverse map btree */ -#define XFS_SB_FEAT_RO_COMPAT_REFLINK (1 << 2) /* reflinked files */ -#define XFS_SB_FEAT_RO_COMPAT_ALL \ - (XFS_SB_FEAT_RO_COMPAT_FINOBT | \ - XFS_SB_FEAT_RO_COMPAT_RMAPBT | \ - XFS_SB_FEAT_RO_COMPAT_REFLINK) -#define XFS_SB_FEAT_RO_COMPAT_UNKNOWN ~XFS_SB_FEAT_RO_COMPAT_ALL -static inline bool -xfs_sb_has_ro_compat_feature( - struct xfs_sb *sbp, - __uint32_t feature) -{ - return (sbp->sb_features_ro_compat & feature) != 0; -} - -#define XFS_SB_FEAT_INCOMPAT_FTYPE (1 << 0) /* filetype in dirent */ -#define XFS_SB_FEAT_INCOMPAT_SPINODES (1 << 1) /* sparse inode chunks */ -#define XFS_SB_FEAT_INCOMPAT_META_UUID (1 << 2) /* metadata UUID */ -#define XFS_SB_FEAT_INCOMPAT_ALL \ - (XFS_SB_FEAT_INCOMPAT_FTYPE| \ - XFS_SB_FEAT_INCOMPAT_SPINODES| \ - XFS_SB_FEAT_INCOMPAT_META_UUID) - -#define XFS_SB_FEAT_INCOMPAT_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_ALL -static inline bool -xfs_sb_has_incompat_feature( - struct xfs_sb *sbp, - __uint32_t feature) -{ - return (sbp->sb_features_incompat & feature) != 0; -} - -#define XFS_SB_FEAT_INCOMPAT_LOG_ALL 0 -#define XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN ~XFS_SB_FEAT_INCOMPAT_LOG_ALL -static inline bool -xfs_sb_has_incompat_log_feature( - struct xfs_sb *sbp, - __uint32_t feature) -{ - return (sbp->sb_features_log_incompat & feature) != 0; -} - -/* - * V5 superblock specific feature checks - */ -static inline int xfs_sb_version_hascrc(struct xfs_sb *sbp) -{ - return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5; -} - -static inline int xfs_sb_version_has_pquotino(struct xfs_sb *sbp) -{ - return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5; -} - -static inline int xfs_sb_version_hasftype(struct xfs_sb *sbp) -{ - return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 && - xfs_sb_has_incompat_feature(sbp, XFS_SB_FEAT_INCOMPAT_FTYPE)) || - (xfs_sb_version_hasmorebits(sbp) && - (sbp->sb_features2 & XFS_SB_VERSION2_FTYPE)); -} - -static inline int xfs_sb_version_hasfinobt(xfs_sb_t *sbp) -{ - return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) && - (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_FINOBT); -} - -static inline bool xfs_sb_version_hassparseinodes(struct xfs_sb *sbp) -{ - return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 && - xfs_sb_has_incompat_feature(sbp, XFS_SB_FEAT_INCOMPAT_SPINODES); -} - -/* - * XFS_SB_FEAT_INCOMPAT_META_UUID indicates that the metadata UUID - * is stored separately from the user-visible UUID; this allows the - * user-visible UUID to be changed on V5 filesystems which have a - * filesystem UUID stamped into every piece of metadata. - */ -static inline bool xfs_sb_version_hasmetauuid(struct xfs_sb *sbp) -{ - return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) && - (sbp->sb_features_incompat & XFS_SB_FEAT_INCOMPAT_META_UUID); -} - -static inline bool xfs_sb_version_hasrmapbt(struct xfs_sb *sbp) -{ - return (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) && - (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_RMAPBT); -} - -static inline bool xfs_sb_version_hasreflink(struct xfs_sb *sbp) -{ - return XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 && - (sbp->sb_features_ro_compat & XFS_SB_FEAT_RO_COMPAT_REFLINK); -} - -/* - * end of superblock version macros - */ - -static inline bool -xfs_is_quota_inode(struct xfs_sb *sbp, xfs_ino_t ino) -{ - return (ino == sbp->sb_uquotino || - ino == sbp->sb_gquotino || - ino == sbp->sb_pquotino); -} - -#define XFS_SB_DADDR ((xfs_daddr_t)0) /* daddr in filesystem/ag */ -#define XFS_SB_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_SB_DADDR) -#define XFS_BUF_TO_SBP(bp) ((xfs_dsb_t *)((bp)->b_addr)) - -#define XFS_HDR_BLOCK(mp,d) ((xfs_agblock_t)XFS_BB_TO_FSBT(mp,d)) -#define XFS_DADDR_TO_FSB(mp,d) XFS_AGB_TO_FSB(mp, \ - xfs_daddr_to_agno(mp,d), xfs_daddr_to_agbno(mp,d)) -#define XFS_FSB_TO_DADDR(mp,fsbno) XFS_AGB_TO_DADDR(mp, \ - XFS_FSB_TO_AGNO(mp,fsbno), XFS_FSB_TO_AGBNO(mp,fsbno)) - -/* - * File system sector to basic block conversions. - */ -#define XFS_FSS_TO_BB(mp,sec) ((sec) << (mp)->m_sectbb_log) - -/* - * File system block to basic block conversions. - */ -#define XFS_FSB_TO_BB(mp,fsbno) ((fsbno) << (mp)->m_blkbb_log) -#define XFS_BB_TO_FSB(mp,bb) \ - (((bb) + (XFS_FSB_TO_BB(mp,1) - 1)) >> (mp)->m_blkbb_log) -#define XFS_BB_TO_FSBT(mp,bb) ((bb) >> (mp)->m_blkbb_log) - -/* - * File system block to byte conversions. - */ -#define XFS_FSB_TO_B(mp,fsbno) ((xfs_fsize_t)(fsbno) << (mp)->m_sb.sb_blocklog) -#define XFS_B_TO_FSB(mp,b) \ - ((((__uint64_t)(b)) + (mp)->m_blockmask) >> (mp)->m_sb.sb_blocklog) -#define XFS_B_TO_FSBT(mp,b) (((__uint64_t)(b)) >> (mp)->m_sb.sb_blocklog) -#define XFS_B_FSB_OFFSET(mp,b) ((b) & (mp)->m_blockmask) - -/* - * Allocation group header - * - * This is divided into three structures, placed in sequential 512-byte - * buffers after a copy of the superblock (also in a 512-byte buffer). - */ -#define XFS_AGF_MAGIC 0x58414746 /* 'XAGF' */ -#define XFS_AGI_MAGIC 0x58414749 /* 'XAGI' */ -#define XFS_AGFL_MAGIC 0x5841464c /* 'XAFL' */ -#define XFS_AGF_VERSION 1 -#define XFS_AGI_VERSION 1 - -#define XFS_AGF_GOOD_VERSION(v) ((v) == XFS_AGF_VERSION) -#define XFS_AGI_GOOD_VERSION(v) ((v) == XFS_AGI_VERSION) - -/* - * Btree number 0 is bno, 1 is cnt, 2 is rmap. This value gives the size of the - * arrays below. - */ -#define XFS_BTNUM_AGF ((int)XFS_BTNUM_RMAPi + 1) - -/* - * The second word of agf_levels in the first a.g. overlaps the EFS - * superblock's magic number. Since the magic numbers valid for EFS - * are > 64k, our value cannot be confused for an EFS superblock's. - */ - -typedef struct xfs_agf { - /* - * Common allocation group header information - */ - __be32 agf_magicnum; /* magic number == XFS_AGF_MAGIC */ - __be32 agf_versionnum; /* header version == XFS_AGF_VERSION */ - __be32 agf_seqno; /* sequence # starting from 0 */ - __be32 agf_length; /* size in blocks of a.g. */ - /* - * Freespace and rmap information - */ - __be32 agf_roots[XFS_BTNUM_AGF]; /* root blocks */ - __be32 agf_levels[XFS_BTNUM_AGF]; /* btree levels */ - - __be32 agf_flfirst; /* first freelist block's index */ - __be32 agf_fllast; /* last freelist block's index */ - __be32 agf_flcount; /* count of blocks in freelist */ - __be32 agf_freeblks; /* total free blocks */ - - __be32 agf_longest; /* longest free space */ - __be32 agf_btreeblks; /* # of blocks held in AGF btrees */ - uuid_t agf_uuid; /* uuid of filesystem */ - - __be32 agf_rmap_blocks; /* rmapbt blocks used */ - __be32 agf_refcount_blocks; /* refcountbt blocks used */ - - __be32 agf_refcount_root; /* refcount tree root block */ - __be32 agf_refcount_level; /* refcount btree levels */ - - /* - * reserve some contiguous space for future logged fields before we add - * the unlogged fields. This makes the range logging via flags and - * structure offsets much simpler. - */ - __be64 agf_spare64[14]; - - /* unlogged fields, written during buffer writeback. */ - __be64 agf_lsn; /* last write sequence */ - __be32 agf_crc; /* crc of agf sector */ - __be32 agf_spare2; - - /* structure must be padded to 64 bit alignment */ -} xfs_agf_t; - -#define XFS_AGF_CRC_OFF offsetof(struct xfs_agf, agf_crc) - -#define XFS_AGF_MAGICNUM 0x00000001 -#define XFS_AGF_VERSIONNUM 0x00000002 -#define XFS_AGF_SEQNO 0x00000004 -#define XFS_AGF_LENGTH 0x00000008 -#define XFS_AGF_ROOTS 0x00000010 -#define XFS_AGF_LEVELS 0x00000020 -#define XFS_AGF_FLFIRST 0x00000040 -#define XFS_AGF_FLLAST 0x00000080 -#define XFS_AGF_FLCOUNT 0x00000100 -#define XFS_AGF_FREEBLKS 0x00000200 -#define XFS_AGF_LONGEST 0x00000400 -#define XFS_AGF_BTREEBLKS 0x00000800 -#define XFS_AGF_UUID 0x00001000 -#define XFS_AGF_RMAP_BLOCKS 0x00002000 -#define XFS_AGF_REFCOUNT_BLOCKS 0x00004000 -#define XFS_AGF_REFCOUNT_ROOT 0x00008000 -#define XFS_AGF_REFCOUNT_LEVEL 0x00010000 -#define XFS_AGF_SPARE64 0x00020000 -#define XFS_AGF_NUM_BITS 18 -#define XFS_AGF_ALL_BITS ((1 << XFS_AGF_NUM_BITS) - 1) - -#define XFS_AGF_FLAGS \ - { XFS_AGF_MAGICNUM, "MAGICNUM" }, \ - { XFS_AGF_VERSIONNUM, "VERSIONNUM" }, \ - { XFS_AGF_SEQNO, "SEQNO" }, \ - { XFS_AGF_LENGTH, "LENGTH" }, \ - { XFS_AGF_ROOTS, "ROOTS" }, \ - { XFS_AGF_LEVELS, "LEVELS" }, \ - { XFS_AGF_FLFIRST, "FLFIRST" }, \ - { XFS_AGF_FLLAST, "FLLAST" }, \ - { XFS_AGF_FLCOUNT, "FLCOUNT" }, \ - { XFS_AGF_FREEBLKS, "FREEBLKS" }, \ - { XFS_AGF_LONGEST, "LONGEST" }, \ - { XFS_AGF_BTREEBLKS, "BTREEBLKS" }, \ - { XFS_AGF_UUID, "UUID" }, \ - { XFS_AGF_RMAP_BLOCKS, "RMAP_BLOCKS" }, \ - { XFS_AGF_REFCOUNT_BLOCKS, "REFCOUNT_BLOCKS" }, \ - { XFS_AGF_REFCOUNT_ROOT, "REFCOUNT_ROOT" }, \ - { XFS_AGF_REFCOUNT_LEVEL, "REFCOUNT_LEVEL" }, \ - { XFS_AGF_SPARE64, "SPARE64" } - -/* disk block (xfs_daddr_t) in the AG */ -#define XFS_AGF_DADDR(mp) ((xfs_daddr_t)(1 << (mp)->m_sectbb_log)) -#define XFS_AGF_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGF_DADDR(mp)) -#define XFS_BUF_TO_AGF(bp) ((xfs_agf_t *)((bp)->b_addr)) - -/* - * Size of the unlinked inode hash table in the agi. - */ -#define XFS_AGI_UNLINKED_BUCKETS 64 - -typedef struct xfs_agi { - /* - * Common allocation group header information - */ - __be32 agi_magicnum; /* magic number == XFS_AGI_MAGIC */ - __be32 agi_versionnum; /* header version == XFS_AGI_VERSION */ - __be32 agi_seqno; /* sequence # starting from 0 */ - __be32 agi_length; /* size in blocks of a.g. */ - /* - * Inode information - * Inodes are mapped by interpreting the inode number, so no - * mapping data is needed here. - */ - __be32 agi_count; /* count of allocated inodes */ - __be32 agi_root; /* root of inode btree */ - __be32 agi_level; /* levels in inode btree */ - __be32 agi_freecount; /* number of free inodes */ - - __be32 agi_newino; /* new inode just allocated */ - __be32 agi_dirino; /* last directory inode chunk */ - /* - * Hash table of inodes which have been unlinked but are - * still being referenced. - */ - __be32 agi_unlinked[XFS_AGI_UNLINKED_BUCKETS]; - /* - * This marks the end of logging region 1 and start of logging region 2. - */ - uuid_t agi_uuid; /* uuid of filesystem */ - __be32 agi_crc; /* crc of agi sector */ - __be32 agi_pad32; - __be64 agi_lsn; /* last write sequence */ - - __be32 agi_free_root; /* root of the free inode btree */ - __be32 agi_free_level;/* levels in free inode btree */ - - /* structure must be padded to 64 bit alignment */ -} xfs_agi_t; - -#define XFS_AGI_CRC_OFF offsetof(struct xfs_agi, agi_crc) - -#define XFS_AGI_MAGICNUM (1 << 0) -#define XFS_AGI_VERSIONNUM (1 << 1) -#define XFS_AGI_SEQNO (1 << 2) -#define XFS_AGI_LENGTH (1 << 3) -#define XFS_AGI_COUNT (1 << 4) -#define XFS_AGI_ROOT (1 << 5) -#define XFS_AGI_LEVEL (1 << 6) -#define XFS_AGI_FREECOUNT (1 << 7) -#define XFS_AGI_NEWINO (1 << 8) -#define XFS_AGI_DIRINO (1 << 9) -#define XFS_AGI_UNLINKED (1 << 10) -#define XFS_AGI_NUM_BITS_R1 11 /* end of the 1st agi logging region */ -#define XFS_AGI_ALL_BITS_R1 ((1 << XFS_AGI_NUM_BITS_R1) - 1) -#define XFS_AGI_FREE_ROOT (1 << 11) -#define XFS_AGI_FREE_LEVEL (1 << 12) -#define XFS_AGI_NUM_BITS_R2 13 - -/* disk block (xfs_daddr_t) in the AG */ -#define XFS_AGI_DADDR(mp) ((xfs_daddr_t)(2 << (mp)->m_sectbb_log)) -#define XFS_AGI_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGI_DADDR(mp)) -#define XFS_BUF_TO_AGI(bp) ((xfs_agi_t *)((bp)->b_addr)) - -/* - * The third a.g. block contains the a.g. freelist, an array - * of block pointers to blocks owned by the allocation btree code. - */ -#define XFS_AGFL_DADDR(mp) ((xfs_daddr_t)(3 << (mp)->m_sectbb_log)) -#define XFS_AGFL_BLOCK(mp) XFS_HDR_BLOCK(mp, XFS_AGFL_DADDR(mp)) -#define XFS_BUF_TO_AGFL(bp) ((xfs_agfl_t *)((bp)->b_addr)) - -#define XFS_BUF_TO_AGFL_BNO(mp, bp) \ - (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \ - &(XFS_BUF_TO_AGFL(bp)->agfl_bno[0]) : \ - (__be32 *)(bp)->b_addr) - -/* - * Size of the AGFL. For CRC-enabled filesystes we steal a couple of - * slots in the beginning of the block for a proper header with the - * location information and CRC. - */ -#define XFS_AGFL_SIZE(mp) \ - (((mp)->m_sb.sb_sectsize - \ - (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \ - sizeof(struct xfs_agfl) : 0)) / \ - sizeof(xfs_agblock_t)) - -typedef struct xfs_agfl { - __be32 agfl_magicnum; - __be32 agfl_seqno; - uuid_t agfl_uuid; - __be64 agfl_lsn; - __be32 agfl_crc; - __be32 agfl_bno[]; /* actually XFS_AGFL_SIZE(mp) */ -} __attribute__((packed)) xfs_agfl_t; - -#define XFS_AGFL_CRC_OFF offsetof(struct xfs_agfl, agfl_crc) - -#define XFS_AGB_TO_FSB(mp,agno,agbno) \ - (((xfs_fsblock_t)(agno) << (mp)->m_sb.sb_agblklog) | (agbno)) -#define XFS_FSB_TO_AGNO(mp,fsbno) \ - ((xfs_agnumber_t)((fsbno) >> (mp)->m_sb.sb_agblklog)) -#define XFS_FSB_TO_AGBNO(mp,fsbno) \ - ((xfs_agblock_t)((fsbno) & xfs_mask32lo((mp)->m_sb.sb_agblklog))) -#define XFS_AGB_TO_DADDR(mp,agno,agbno) \ - ((xfs_daddr_t)XFS_FSB_TO_BB(mp, \ - (xfs_fsblock_t)(agno) * (mp)->m_sb.sb_agblocks + (agbno))) -#define XFS_AG_DADDR(mp,agno,d) (XFS_AGB_TO_DADDR(mp, agno, 0) + (d)) - -/* - * For checking for bad ranges of xfs_daddr_t's, covering multiple - * allocation groups or a single xfs_daddr_t that's a superblock copy. - */ -#define XFS_AG_CHECK_DADDR(mp,d,len) \ - ((len) == 1 ? \ - ASSERT((d) == XFS_SB_DADDR || \ - xfs_daddr_to_agbno(mp, d) != XFS_SB_DADDR) : \ - ASSERT(xfs_daddr_to_agno(mp, d) == \ - xfs_daddr_to_agno(mp, (d) + (len) - 1))) - -typedef struct xfs_timestamp { - __be32 t_sec; /* timestamp seconds */ - __be32 t_nsec; /* timestamp nanoseconds */ -} xfs_timestamp_t; - -/* - * On-disk inode structure. - * - * This is just the header or "dinode core", the inode is expanded to fill a - * variable size the leftover area split into a data and an attribute fork. - * The format of the data and attribute fork depends on the format of the - * inode as indicated by di_format and di_aformat. To access the data and - * attribute use the XFS_DFORK_DPTR, XFS_DFORK_APTR, and XFS_DFORK_PTR macros - * below. - * - * There is a very similar struct icdinode in xfs_inode which matches the - * layout of the first 96 bytes of this structure, but is kept in native - * format instead of big endian. - * - * Note: di_flushiter is only used by v1/2 inodes - it's effectively a zeroed - * padding field for v3 inodes. - */ -#define XFS_DINODE_MAGIC 0x494e /* 'IN' */ -typedef struct xfs_dinode { - __be16 di_magic; /* inode magic # = XFS_DINODE_MAGIC */ - __be16 di_mode; /* mode and type of file */ - __u8 di_version; /* inode version */ - __u8 di_format; /* format of di_c data */ - __be16 di_onlink; /* old number of links to file */ - __be32 di_uid; /* owner's user id */ - __be32 di_gid; /* owner's group id */ - __be32 di_nlink; /* number of links to file */ - __be16 di_projid_lo; /* lower part of owner's project id */ - __be16 di_projid_hi; /* higher part owner's project id */ - __u8 di_pad[6]; /* unused, zeroed space */ - __be16 di_flushiter; /* incremented on flush */ - xfs_timestamp_t di_atime; /* time last accessed */ - xfs_timestamp_t di_mtime; /* time last modified */ - xfs_timestamp_t di_ctime; /* time created/inode modified */ - __be64 di_size; /* number of bytes in file */ - __be64 di_nblocks; /* # of direct & btree blocks used */ - __be32 di_extsize; /* basic/minimum extent size for file */ - __be32 di_nextents; /* number of extents in data fork */ - __be16 di_anextents; /* number of extents in attribute fork*/ - __u8 di_forkoff; /* attr fork offs, <<3 for 64b align */ - __s8 di_aformat; /* format of attr fork's data */ - __be32 di_dmevmask; /* DMIG event mask */ - __be16 di_dmstate; /* DMIG state info */ - __be16 di_flags; /* random flags, XFS_DIFLAG_... */ - __be32 di_gen; /* generation number */ - - /* di_next_unlinked is the only non-core field in the old dinode */ - __be32 di_next_unlinked;/* agi unlinked list ptr */ - - /* start of the extended dinode, writable fields */ - __le32 di_crc; /* CRC of the inode */ - __be64 di_changecount; /* number of attribute changes */ - __be64 di_lsn; /* flush sequence */ - __be64 di_flags2; /* more random flags */ - __be32 di_cowextsize; /* basic cow extent size for file */ - __u8 di_pad2[12]; /* more padding for future expansion */ - - /* fields only written to during inode creation */ - xfs_timestamp_t di_crtime; /* time created */ - __be64 di_ino; /* inode number */ - uuid_t di_uuid; /* UUID of the filesystem */ - - /* structure must be padded to 64 bit alignment */ -} xfs_dinode_t; - -#define XFS_DINODE_CRC_OFF offsetof(struct xfs_dinode, di_crc) - -#define DI_MAX_FLUSH 0xffff - -/* - * Size of the core inode on disk. Version 1 and 2 inodes have - * the same size, but version 3 has grown a few additional fields. - */ -static inline uint xfs_dinode_size(int version) -{ - if (version == 3) - return sizeof(struct xfs_dinode); - return offsetof(struct xfs_dinode, di_crc); -} - -/* - * The 32 bit link count in the inode theoretically maxes out at UINT_MAX. - * Since the pathconf interface is signed, we use 2^31 - 1 instead. - * The old inode format had a 16 bit link count, so its maximum is USHRT_MAX. - */ -#define XFS_MAXLINK ((1U << 31) - 1U) -#define XFS_MAXLINK_1 65535U - -/* - * Values for di_format - */ -typedef enum xfs_dinode_fmt { - XFS_DINODE_FMT_DEV, /* xfs_dev_t */ - XFS_DINODE_FMT_LOCAL, /* bulk data */ - XFS_DINODE_FMT_EXTENTS, /* struct xfs_bmbt_rec */ - XFS_DINODE_FMT_BTREE, /* struct xfs_bmdr_block */ - XFS_DINODE_FMT_UUID /* uuid_t */ -} xfs_dinode_fmt_t; - -/* - * Inode minimum and maximum sizes. - */ -#define XFS_DINODE_MIN_LOG 8 -#define XFS_DINODE_MAX_LOG 11 -#define XFS_DINODE_MIN_SIZE (1 << XFS_DINODE_MIN_LOG) -#define XFS_DINODE_MAX_SIZE (1 << XFS_DINODE_MAX_LOG) - -/* - * Inode size for given fs. - */ -#define XFS_LITINO(mp, version) \ - ((int)(((mp)->m_sb.sb_inodesize) - xfs_dinode_size(version))) - -/* - * Inode data & attribute fork sizes, per inode. - */ -#define XFS_DFORK_Q(dip) ((dip)->di_forkoff != 0) -#define XFS_DFORK_BOFF(dip) ((int)((dip)->di_forkoff << 3)) - -#define XFS_DFORK_DSIZE(dip,mp) \ - (XFS_DFORK_Q(dip) ? \ - XFS_DFORK_BOFF(dip) : \ - XFS_LITINO(mp, (dip)->di_version)) -#define XFS_DFORK_ASIZE(dip,mp) \ - (XFS_DFORK_Q(dip) ? \ - XFS_LITINO(mp, (dip)->di_version) - XFS_DFORK_BOFF(dip) : \ - 0) -#define XFS_DFORK_SIZE(dip,mp,w) \ - ((w) == XFS_DATA_FORK ? \ - XFS_DFORK_DSIZE(dip, mp) : \ - XFS_DFORK_ASIZE(dip, mp)) - -/* - * Return pointers to the data or attribute forks. - */ -#define XFS_DFORK_DPTR(dip) \ - ((char *)dip + xfs_dinode_size(dip->di_version)) -#define XFS_DFORK_APTR(dip) \ - (XFS_DFORK_DPTR(dip) + XFS_DFORK_BOFF(dip)) -#define XFS_DFORK_PTR(dip,w) \ - ((w) == XFS_DATA_FORK ? XFS_DFORK_DPTR(dip) : XFS_DFORK_APTR(dip)) - -#define XFS_DFORK_FORMAT(dip,w) \ - ((w) == XFS_DATA_FORK ? \ - (dip)->di_format : \ - (dip)->di_aformat) -#define XFS_DFORK_NEXTENTS(dip,w) \ - ((w) == XFS_DATA_FORK ? \ - be32_to_cpu((dip)->di_nextents) : \ - be16_to_cpu((dip)->di_anextents)) - -/* - * For block and character special files the 32bit dev_t is stored at the - * beginning of the data fork. - */ -static inline xfs_dev_t xfs_dinode_get_rdev(struct xfs_dinode *dip) -{ - return be32_to_cpu(*(__be32 *)XFS_DFORK_DPTR(dip)); -} - -static inline void xfs_dinode_put_rdev(struct xfs_dinode *dip, xfs_dev_t rdev) -{ - *(__be32 *)XFS_DFORK_DPTR(dip) = cpu_to_be32(rdev); -} - -/* - * Values for di_flags - */ -#define XFS_DIFLAG_REALTIME_BIT 0 /* file's blocks come from rt area */ -#define XFS_DIFLAG_PREALLOC_BIT 1 /* file space has been preallocated */ -#define XFS_DIFLAG_NEWRTBM_BIT 2 /* for rtbitmap inode, new format */ -#define XFS_DIFLAG_IMMUTABLE_BIT 3 /* inode is immutable */ -#define XFS_DIFLAG_APPEND_BIT 4 /* inode is append-only */ -#define XFS_DIFLAG_SYNC_BIT 5 /* inode is written synchronously */ -#define XFS_DIFLAG_NOATIME_BIT 6 /* do not update atime */ -#define XFS_DIFLAG_NODUMP_BIT 7 /* do not dump */ -#define XFS_DIFLAG_RTINHERIT_BIT 8 /* create with realtime bit set */ -#define XFS_DIFLAG_PROJINHERIT_BIT 9 /* create with parents projid */ -#define XFS_DIFLAG_NOSYMLINKS_BIT 10 /* disallow symlink creation */ -#define XFS_DIFLAG_EXTSIZE_BIT 11 /* inode extent size allocator hint */ -#define XFS_DIFLAG_EXTSZINHERIT_BIT 12 /* inherit inode extent size */ -#define XFS_DIFLAG_NODEFRAG_BIT 13 /* do not reorganize/defragment */ -#define XFS_DIFLAG_FILESTREAM_BIT 14 /* use filestream allocator */ -#define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT) -#define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT) -#define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT) -#define XFS_DIFLAG_IMMUTABLE (1 << XFS_DIFLAG_IMMUTABLE_BIT) -#define XFS_DIFLAG_APPEND (1 << XFS_DIFLAG_APPEND_BIT) -#define XFS_DIFLAG_SYNC (1 << XFS_DIFLAG_SYNC_BIT) -#define XFS_DIFLAG_NOATIME (1 << XFS_DIFLAG_NOATIME_BIT) -#define XFS_DIFLAG_NODUMP (1 << XFS_DIFLAG_NODUMP_BIT) -#define XFS_DIFLAG_RTINHERIT (1 << XFS_DIFLAG_RTINHERIT_BIT) -#define XFS_DIFLAG_PROJINHERIT (1 << XFS_DIFLAG_PROJINHERIT_BIT) -#define XFS_DIFLAG_NOSYMLINKS (1 << XFS_DIFLAG_NOSYMLINKS_BIT) -#define XFS_DIFLAG_EXTSIZE (1 << XFS_DIFLAG_EXTSIZE_BIT) -#define XFS_DIFLAG_EXTSZINHERIT (1 << XFS_DIFLAG_EXTSZINHERIT_BIT) -#define XFS_DIFLAG_NODEFRAG (1 << XFS_DIFLAG_NODEFRAG_BIT) -#define XFS_DIFLAG_FILESTREAM (1 << XFS_DIFLAG_FILESTREAM_BIT) - -#define XFS_DIFLAG_ANY \ - (XFS_DIFLAG_REALTIME | XFS_DIFLAG_PREALLOC | XFS_DIFLAG_NEWRTBM | \ - XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \ - XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \ - XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS | XFS_DIFLAG_EXTSIZE | \ - XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG | XFS_DIFLAG_FILESTREAM) - -/* - * Values for di_flags2 These start by being exposed to userspace in the upper - * 16 bits of the XFS_XFLAG_s range. - */ -#define XFS_DIFLAG2_DAX_BIT 0 /* use DAX for this inode */ -#define XFS_DIFLAG2_REFLINK_BIT 1 /* file's blocks may be shared */ -#define XFS_DIFLAG2_COWEXTSIZE_BIT 2 /* copy on write extent size hint */ -#define XFS_DIFLAG2_DAX (1 << XFS_DIFLAG2_DAX_BIT) -#define XFS_DIFLAG2_REFLINK (1 << XFS_DIFLAG2_REFLINK_BIT) -#define XFS_DIFLAG2_COWEXTSIZE (1 << XFS_DIFLAG2_COWEXTSIZE_BIT) - -#define XFS_DIFLAG2_ANY \ - (XFS_DIFLAG2_DAX | XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE) - -/* - * Inode number format: - * low inopblog bits - offset in block - * next agblklog bits - block number in ag - * next agno_log bits - ag number - * high agno_log-agblklog-inopblog bits - 0 - */ -#define XFS_INO_MASK(k) (__uint32_t)((1ULL << (k)) - 1) -#define XFS_INO_OFFSET_BITS(mp) (mp)->m_sb.sb_inopblog -#define XFS_INO_AGBNO_BITS(mp) (mp)->m_sb.sb_agblklog -#define XFS_INO_AGINO_BITS(mp) (mp)->m_agino_log -#define XFS_INO_AGNO_BITS(mp) (mp)->m_agno_log -#define XFS_INO_BITS(mp) \ - XFS_INO_AGNO_BITS(mp) + XFS_INO_AGINO_BITS(mp) -#define XFS_INO_TO_AGNO(mp,i) \ - ((xfs_agnumber_t)((i) >> XFS_INO_AGINO_BITS(mp))) -#define XFS_INO_TO_AGINO(mp,i) \ - ((xfs_agino_t)(i) & XFS_INO_MASK(XFS_INO_AGINO_BITS(mp))) -#define XFS_INO_TO_AGBNO(mp,i) \ - (((xfs_agblock_t)(i) >> XFS_INO_OFFSET_BITS(mp)) & \ - XFS_INO_MASK(XFS_INO_AGBNO_BITS(mp))) -#define XFS_INO_TO_OFFSET(mp,i) \ - ((int)(i) & XFS_INO_MASK(XFS_INO_OFFSET_BITS(mp))) -#define XFS_INO_TO_FSB(mp,i) \ - XFS_AGB_TO_FSB(mp, XFS_INO_TO_AGNO(mp,i), XFS_INO_TO_AGBNO(mp,i)) -#define XFS_AGINO_TO_INO(mp,a,i) \ - (((xfs_ino_t)(a) << XFS_INO_AGINO_BITS(mp)) | (i)) -#define XFS_AGINO_TO_AGBNO(mp,i) ((i) >> XFS_INO_OFFSET_BITS(mp)) -#define XFS_AGINO_TO_OFFSET(mp,i) \ - ((i) & XFS_INO_MASK(XFS_INO_OFFSET_BITS(mp))) -#define XFS_OFFBNO_TO_AGINO(mp,b,o) \ - ((xfs_agino_t)(((b) << XFS_INO_OFFSET_BITS(mp)) | (o))) - -#define XFS_MAXINUMBER ((xfs_ino_t)((1ULL << 56) - 1ULL)) -#define XFS_MAXINUMBER_32 ((xfs_ino_t)((1ULL << 32) - 1ULL)) - -/* - * RealTime Device format definitions - */ - -/* Min and max rt extent sizes, specified in bytes */ -#define XFS_MAX_RTEXTSIZE (1024 * 1024 * 1024) /* 1GB */ -#define XFS_DFL_RTEXTSIZE (64 * 1024) /* 64kB */ -#define XFS_MIN_RTEXTSIZE (4 * 1024) /* 4kB */ - -#define XFS_BLOCKSIZE(mp) ((mp)->m_sb.sb_blocksize) -#define XFS_BLOCKMASK(mp) ((mp)->m_blockmask) -#define XFS_BLOCKWSIZE(mp) ((mp)->m_blockwsize) -#define XFS_BLOCKWMASK(mp) ((mp)->m_blockwmask) - -/* - * RT Summary and bit manipulation macros. - */ -#define XFS_SUMOFFS(mp,ls,bb) ((int)((ls) * (mp)->m_sb.sb_rbmblocks + (bb))) -#define XFS_SUMOFFSTOBLOCK(mp,s) \ - (((s) * (uint)sizeof(xfs_suminfo_t)) >> (mp)->m_sb.sb_blocklog) -#define XFS_SUMPTR(mp,bp,so) \ - ((xfs_suminfo_t *)((bp)->b_addr + \ - (((so) * (uint)sizeof(xfs_suminfo_t)) & XFS_BLOCKMASK(mp)))) - -#define XFS_BITTOBLOCK(mp,bi) ((bi) >> (mp)->m_blkbit_log) -#define XFS_BLOCKTOBIT(mp,bb) ((bb) << (mp)->m_blkbit_log) -#define XFS_BITTOWORD(mp,bi) \ - ((int)(((bi) >> XFS_NBWORDLOG) & XFS_BLOCKWMASK(mp))) - -#define XFS_RTMIN(a,b) ((a) < (b) ? (a) : (b)) -#define XFS_RTMAX(a,b) ((a) > (b) ? (a) : (b)) - -#define XFS_RTLOBIT(w) xfs_lowbit32(w) -#define XFS_RTHIBIT(w) xfs_highbit32(w) - -#define XFS_RTBLOCKLOG(b) xfs_highbit64(b) - -/* - * Dquot and dquot block format definitions - */ -#define XFS_DQUOT_MAGIC 0x4451 /* 'DQ' */ -#define XFS_DQUOT_VERSION (u_int8_t)0x01 /* latest version number */ - -/* - * This is the main portion of the on-disk representation of quota - * information for a user. This is the q_core of the xfs_dquot_t that - * is kept in kernel memory. We pad this with some more expansion room - * to construct the on disk structure. - */ -typedef struct xfs_disk_dquot { - __be16 d_magic; /* dquot magic = XFS_DQUOT_MAGIC */ - __u8 d_version; /* dquot version */ - __u8 d_flags; /* XFS_DQ_USER/PROJ/GROUP */ - __be32 d_id; /* user,project,group id */ - __be64 d_blk_hardlimit;/* absolute limit on disk blks */ - __be64 d_blk_softlimit;/* preferred limit on disk blks */ - __be64 d_ino_hardlimit;/* maximum # allocated inodes */ - __be64 d_ino_softlimit;/* preferred inode limit */ - __be64 d_bcount; /* disk blocks owned by the user */ - __be64 d_icount; /* inodes owned by the user */ - __be32 d_itimer; /* zero if within inode limits if not, - this is when we refuse service */ - __be32 d_btimer; /* similar to above; for disk blocks */ - __be16 d_iwarns; /* warnings issued wrt num inodes */ - __be16 d_bwarns; /* warnings issued wrt disk blocks */ - __be32 d_pad0; /* 64 bit align */ - __be64 d_rtb_hardlimit;/* absolute limit on realtime blks */ - __be64 d_rtb_softlimit;/* preferred limit on RT disk blks */ - __be64 d_rtbcount; /* realtime blocks owned */ - __be32 d_rtbtimer; /* similar to above; for RT disk blocks */ - __be16 d_rtbwarns; /* warnings issued wrt RT disk blocks */ - __be16 d_pad; -} xfs_disk_dquot_t; - -/* - * This is what goes on disk. This is separated from the xfs_disk_dquot because - * carrying the unnecessary padding would be a waste of memory. - */ -typedef struct xfs_dqblk { - xfs_disk_dquot_t dd_diskdq; /* portion that lives incore as well */ - char dd_fill[4]; /* filling for posterity */ - - /* - * These two are only present on filesystems with the CRC bits set. - */ - __be32 dd_crc; /* checksum */ - __be64 dd_lsn; /* last modification in log */ - uuid_t dd_uuid; /* location information */ -} xfs_dqblk_t; - -#define XFS_DQUOT_CRC_OFF offsetof(struct xfs_dqblk, dd_crc) - -/* - * Remote symlink format and access functions. - */ -#define XFS_SYMLINK_MAGIC 0x58534c4d /* XSLM */ - -struct xfs_dsymlink_hdr { - __be32 sl_magic; - __be32 sl_offset; - __be32 sl_bytes; - __be32 sl_crc; - uuid_t sl_uuid; - __be64 sl_owner; - __be64 sl_blkno; - __be64 sl_lsn; -}; - -#define XFS_SYMLINK_CRC_OFF offsetof(struct xfs_dsymlink_hdr, sl_crc) - -/* - * The maximum pathlen is 1024 bytes. Since the minimum file system - * blocksize is 512 bytes, we can get a max of 3 extents back from - * bmapi when crc headers are taken into account. - */ -#define XFS_SYMLINK_MAPS 3 - -#define XFS_SYMLINK_BUF_SPACE(mp, bufsize) \ - ((bufsize) - (xfs_sb_version_hascrc(&(mp)->m_sb) ? \ - sizeof(struct xfs_dsymlink_hdr) : 0)) - - -/* - * Allocation Btree format definitions - * - * There are two on-disk btrees, one sorted by blockno and one sorted - * by blockcount and blockno. All blocks look the same to make the code - * simpler; if we have time later, we'll make the optimizations. - */ -#define XFS_ABTB_MAGIC 0x41425442 /* 'ABTB' for bno tree */ -#define XFS_ABTB_CRC_MAGIC 0x41423342 /* 'AB3B' */ -#define XFS_ABTC_MAGIC 0x41425443 /* 'ABTC' for cnt tree */ -#define XFS_ABTC_CRC_MAGIC 0x41423343 /* 'AB3C' */ - -/* - * Data record/key structure - */ -typedef struct xfs_alloc_rec { - __be32 ar_startblock; /* starting block number */ - __be32 ar_blockcount; /* count of free blocks */ -} xfs_alloc_rec_t, xfs_alloc_key_t; - -typedef struct xfs_alloc_rec_incore { - xfs_agblock_t ar_startblock; /* starting block number */ - xfs_extlen_t ar_blockcount; /* count of free blocks */ -} xfs_alloc_rec_incore_t; - -/* btree pointer type */ -typedef __be32 xfs_alloc_ptr_t; - -/* - * Block numbers in the AG: - * SB is sector 0, AGF is sector 1, AGI is sector 2, AGFL is sector 3. - */ -#define XFS_BNO_BLOCK(mp) ((xfs_agblock_t)(XFS_AGFL_BLOCK(mp) + 1)) -#define XFS_CNT_BLOCK(mp) ((xfs_agblock_t)(XFS_BNO_BLOCK(mp) + 1)) - - -/* - * Inode Allocation Btree format definitions - * - * There is a btree for the inode map per allocation group. - */ -#define XFS_IBT_MAGIC 0x49414254 /* 'IABT' */ -#define XFS_IBT_CRC_MAGIC 0x49414233 /* 'IAB3' */ -#define XFS_FIBT_MAGIC 0x46494254 /* 'FIBT' */ -#define XFS_FIBT_CRC_MAGIC 0x46494233 /* 'FIB3' */ - -typedef __uint64_t xfs_inofree_t; -#define XFS_INODES_PER_CHUNK (NBBY * sizeof(xfs_inofree_t)) -#define XFS_INODES_PER_CHUNK_LOG (XFS_NBBYLOG + 3) -#define XFS_INOBT_ALL_FREE ((xfs_inofree_t)-1) -#define XFS_INOBT_MASK(i) ((xfs_inofree_t)1 << (i)) - -#define XFS_INOBT_HOLEMASK_FULL 0 /* holemask for full chunk */ -#define XFS_INOBT_HOLEMASK_BITS (NBBY * sizeof(__uint16_t)) -#define XFS_INODES_PER_HOLEMASK_BIT \ - (XFS_INODES_PER_CHUNK / (NBBY * sizeof(__uint16_t))) - -static inline xfs_inofree_t xfs_inobt_maskn(int i, int n) -{ - return ((n >= XFS_INODES_PER_CHUNK ? 0 : XFS_INOBT_MASK(n)) - 1) << i; -} - -/* - * The on-disk inode record structure has two formats. The original "full" - * format uses a 4-byte freecount. The "sparse" format uses a 1-byte freecount - * and replaces the 3 high-order freecount bytes wth the holemask and inode - * count. - * - * The holemask of the sparse record format allows an inode chunk to have holes - * that refer to blocks not owned by the inode record. This facilitates inode - * allocation in the event of severe free space fragmentation. - */ -typedef struct xfs_inobt_rec { - __be32 ir_startino; /* starting inode number */ - union { - struct { - __be32 ir_freecount; /* count of free inodes */ - } f; - struct { - __be16 ir_holemask;/* hole mask for sparse chunks */ - __u8 ir_count; /* total inode count */ - __u8 ir_freecount; /* count of free inodes */ - } sp; - } ir_u; - __be64 ir_free; /* free inode mask */ -} xfs_inobt_rec_t; - -typedef struct xfs_inobt_rec_incore { - xfs_agino_t ir_startino; /* starting inode number */ - __uint16_t ir_holemask; /* hole mask for sparse chunks */ - __uint8_t ir_count; /* total inode count */ - __uint8_t ir_freecount; /* count of free inodes (set bits) */ - xfs_inofree_t ir_free; /* free inode mask */ -} xfs_inobt_rec_incore_t; - -static inline bool xfs_inobt_issparse(uint16_t holemask) -{ - /* non-zero holemask represents a sparse rec. */ - return holemask; -} - -/* - * Key structure - */ -typedef struct xfs_inobt_key { - __be32 ir_startino; /* starting inode number */ -} xfs_inobt_key_t; - -/* btree pointer type */ -typedef __be32 xfs_inobt_ptr_t; - -/* - * block numbers in the AG. - */ -#define XFS_IBT_BLOCK(mp) ((xfs_agblock_t)(XFS_CNT_BLOCK(mp) + 1)) -#define XFS_FIBT_BLOCK(mp) ((xfs_agblock_t)(XFS_IBT_BLOCK(mp) + 1)) - -/* - * Reverse mapping btree format definitions - * - * There is a btree for the reverse map per allocation group - */ -#define XFS_RMAP_CRC_MAGIC 0x524d4233 /* 'RMB3' */ - -/* - * Ownership info for an extent. This is used to create reverse-mapping - * entries. - */ -#define XFS_OWNER_INFO_ATTR_FORK (1 << 0) -#define XFS_OWNER_INFO_BMBT_BLOCK (1 << 1) -struct xfs_owner_info { - uint64_t oi_owner; - xfs_fileoff_t oi_offset; - unsigned int oi_flags; -}; - -/* - * Special owner types. - * - * Seeing as we only support up to 8EB, we have the upper bit of the owner field - * to tell us we have a special owner value. We use these for static metadata - * allocated at mkfs/growfs time, as well as for freespace management metadata. - */ -#define XFS_RMAP_OWN_NULL (-1ULL) /* No owner, for growfs */ -#define XFS_RMAP_OWN_UNKNOWN (-2ULL) /* Unknown owner, for EFI recovery */ -#define XFS_RMAP_OWN_FS (-3ULL) /* static fs metadata */ -#define XFS_RMAP_OWN_LOG (-4ULL) /* static fs metadata */ -#define XFS_RMAP_OWN_AG (-5ULL) /* AG freespace btree blocks */ -#define XFS_RMAP_OWN_INOBT (-6ULL) /* Inode btree blocks */ -#define XFS_RMAP_OWN_INODES (-7ULL) /* Inode chunk */ -#define XFS_RMAP_OWN_REFC (-8ULL) /* refcount tree */ -#define XFS_RMAP_OWN_COW (-9ULL) /* cow allocations */ -#define XFS_RMAP_OWN_MIN (-10ULL) /* guard */ - -#define XFS_RMAP_NON_INODE_OWNER(owner) (!!((owner) & (1ULL << 63))) - -/* - * Data record structure - */ -struct xfs_rmap_rec { - __be32 rm_startblock; /* extent start block */ - __be32 rm_blockcount; /* extent length */ - __be64 rm_owner; /* extent owner */ - __be64 rm_offset; /* offset within the owner */ -}; - -/* - * rmap btree record - * rm_offset:63 is the attribute fork flag - * rm_offset:62 is the bmbt block flag - * rm_offset:61 is the unwritten extent flag (same as l0:63 in bmbt) - * rm_offset:54-60 aren't used and should be zero - * rm_offset:0-53 is the block offset within the inode - */ -#define XFS_RMAP_OFF_ATTR_FORK ((__uint64_t)1ULL << 63) -#define XFS_RMAP_OFF_BMBT_BLOCK ((__uint64_t)1ULL << 62) -#define XFS_RMAP_OFF_UNWRITTEN ((__uint64_t)1ULL << 61) - -#define XFS_RMAP_LEN_MAX ((__uint32_t)~0U) -#define XFS_RMAP_OFF_FLAGS (XFS_RMAP_OFF_ATTR_FORK | \ - XFS_RMAP_OFF_BMBT_BLOCK | \ - XFS_RMAP_OFF_UNWRITTEN) -#define XFS_RMAP_OFF_MASK ((__uint64_t)0x3FFFFFFFFFFFFFULL) - -#define XFS_RMAP_OFF(off) ((off) & XFS_RMAP_OFF_MASK) - -#define XFS_RMAP_IS_BMBT_BLOCK(off) (!!((off) & XFS_RMAP_OFF_BMBT_BLOCK)) -#define XFS_RMAP_IS_ATTR_FORK(off) (!!((off) & XFS_RMAP_OFF_ATTR_FORK)) -#define XFS_RMAP_IS_UNWRITTEN(len) (!!((off) & XFS_RMAP_OFF_UNWRITTEN)) - -#define RMAPBT_STARTBLOCK_BITLEN 32 -#define RMAPBT_BLOCKCOUNT_BITLEN 32 -#define RMAPBT_OWNER_BITLEN 64 -#define RMAPBT_ATTRFLAG_BITLEN 1 -#define RMAPBT_BMBTFLAG_BITLEN 1 -#define RMAPBT_EXNTFLAG_BITLEN 1 -#define RMAPBT_UNUSED_OFFSET_BITLEN 7 -#define RMAPBT_OFFSET_BITLEN 54 - -#define XFS_RMAP_ATTR_FORK (1 << 0) -#define XFS_RMAP_BMBT_BLOCK (1 << 1) -#define XFS_RMAP_UNWRITTEN (1 << 2) -#define XFS_RMAP_KEY_FLAGS (XFS_RMAP_ATTR_FORK | \ - XFS_RMAP_BMBT_BLOCK) -#define XFS_RMAP_REC_FLAGS (XFS_RMAP_UNWRITTEN) -struct xfs_rmap_irec { - xfs_agblock_t rm_startblock; /* extent start block */ - xfs_extlen_t rm_blockcount; /* extent length */ - __uint64_t rm_owner; /* extent owner */ - __uint64_t rm_offset; /* offset within the owner */ - unsigned int rm_flags; /* state flags */ -}; - -/* - * Key structure - * - * We don't use the length for lookups - */ -struct xfs_rmap_key { - __be32 rm_startblock; /* extent start block */ - __be64 rm_owner; /* extent owner */ - __be64 rm_offset; /* offset within the owner */ -} __attribute__((packed)); - -/* btree pointer type */ -typedef __be32 xfs_rmap_ptr_t; - -#define XFS_RMAP_BLOCK(mp) \ - (xfs_sb_version_hasfinobt(&((mp)->m_sb)) ? \ - XFS_FIBT_BLOCK(mp) + 1 : \ - XFS_IBT_BLOCK(mp) + 1) - -/* - * Reference Count Btree format definitions - * - */ -#define XFS_REFC_CRC_MAGIC 0x52334643 /* 'R3FC' */ - -unsigned int xfs_refc_block(struct xfs_mount *mp); - -/* - * Data record/key structure - * - * Each record associates a range of physical blocks (starting at - * rc_startblock and ending rc_blockcount blocks later) with a reference - * count (rc_refcount). Extents that are being used to stage a copy on - * write (CoW) operation are recorded in the refcount btree with a - * refcount of 1. All other records must have a refcount > 1 and must - * track an extent mapped only by file data forks. - * - * Extents with a single owner (attributes, metadata, non-shared file - * data) are not tracked here. Free space is also not tracked here. - * This is consistent with pre-reflink XFS. - */ - -/* - * Extents that are being used to stage a copy on write are stored - * in the refcount btree with a refcount of 1 and the upper bit set - * on the startblock. This speeds up mount time deletion of stale - * staging extents because they're all at the right side of the tree. - */ -#define XFS_REFC_COW_START ((xfs_agblock_t)(1U << 31)) -#define REFCNTBT_COWFLAG_BITLEN 1 -#define REFCNTBT_AGBLOCK_BITLEN 31 - -struct xfs_refcount_rec { - __be32 rc_startblock; /* starting block number */ - __be32 rc_blockcount; /* count of blocks */ - __be32 rc_refcount; /* number of inodes linked here */ -}; - -struct xfs_refcount_key { - __be32 rc_startblock; /* starting block number */ -}; - -struct xfs_refcount_irec { - xfs_agblock_t rc_startblock; /* starting block number */ - xfs_extlen_t rc_blockcount; /* count of free blocks */ - xfs_nlink_t rc_refcount; /* number of inodes linked here */ -}; - -#define MAXREFCOUNT ((xfs_nlink_t)~0U) -#define MAXREFCEXTLEN ((xfs_extlen_t)~0U) - -/* btree pointer type */ -typedef __be32 xfs_refcount_ptr_t; - - -/* - * BMAP Btree format definitions - * - * This includes both the root block definition that sits inside an inode fork - * and the record/pointer formats for the leaf/node in the blocks. - */ -#define XFS_BMAP_MAGIC 0x424d4150 /* 'BMAP' */ -#define XFS_BMAP_CRC_MAGIC 0x424d4133 /* 'BMA3' */ - -/* - * Bmap root header, on-disk form only. - */ -typedef struct xfs_bmdr_block { - __be16 bb_level; /* 0 is a leaf */ - __be16 bb_numrecs; /* current # of data records */ -} xfs_bmdr_block_t; - -/* - * Bmap btree record and extent descriptor. - * l0:63 is an extent flag (value 1 indicates non-normal). - * l0:9-62 are startoff. - * l0:0-8 and l1:21-63 are startblock. - * l1:0-20 are blockcount. - */ -#define BMBT_EXNTFLAG_BITLEN 1 -#define BMBT_STARTOFF_BITLEN 54 -#define BMBT_STARTBLOCK_BITLEN 52 -#define BMBT_BLOCKCOUNT_BITLEN 21 - -typedef struct xfs_bmbt_rec { - __be64 l0, l1; -} xfs_bmbt_rec_t; - -typedef __uint64_t xfs_bmbt_rec_base_t; /* use this for casts */ -typedef xfs_bmbt_rec_t xfs_bmdr_rec_t; - -typedef struct xfs_bmbt_rec_host { - __uint64_t l0, l1; -} xfs_bmbt_rec_host_t; - -/* - * Values and macros for delayed-allocation startblock fields. - */ -#define STARTBLOCKVALBITS 17 -#define STARTBLOCKMASKBITS (15 + 20) -#define STARTBLOCKMASK \ - (((((xfs_fsblock_t)1) << STARTBLOCKMASKBITS) - 1) << STARTBLOCKVALBITS) - -static inline int isnullstartblock(xfs_fsblock_t x) -{ - return ((x) & STARTBLOCKMASK) == STARTBLOCKMASK; -} - -static inline xfs_fsblock_t nullstartblock(int k) -{ - ASSERT(k < (1 << STARTBLOCKVALBITS)); - return STARTBLOCKMASK | (k); -} - -static inline xfs_filblks_t startblockval(xfs_fsblock_t x) -{ - return (xfs_filblks_t)((x) & ~STARTBLOCKMASK); -} - -/* - * Possible extent formats. - */ -typedef enum { - XFS_EXTFMT_NOSTATE = 0, - XFS_EXTFMT_HASSTATE -} xfs_exntfmt_t; - -/* - * Possible extent states. - */ -typedef enum { - XFS_EXT_NORM, XFS_EXT_UNWRITTEN, - XFS_EXT_DMAPI_OFFLINE, XFS_EXT_INVALID -} xfs_exntst_t; - -/* - * Incore version of above. - */ -typedef struct xfs_bmbt_irec -{ - xfs_fileoff_t br_startoff; /* starting file offset */ - xfs_fsblock_t br_startblock; /* starting block number */ - xfs_filblks_t br_blockcount; /* number of blocks */ - xfs_exntst_t br_state; /* extent state */ -} xfs_bmbt_irec_t; - -/* - * Key structure for non-leaf levels of the tree. - */ -typedef struct xfs_bmbt_key { - __be64 br_startoff; /* starting file offset */ -} xfs_bmbt_key_t, xfs_bmdr_key_t; - -/* btree pointer type */ -typedef __be64 xfs_bmbt_ptr_t, xfs_bmdr_ptr_t; - - -/* - * Generic Btree block format definitions - * - * This is a combination of the actual format used on disk for short and long - * format btrees. The first three fields are shared by both format, but the - * pointers are different and should be used with care. - * - * To get the size of the actual short or long form headers please use the size - * macros below. Never use sizeof(xfs_btree_block). - * - * The blkno, crc, lsn, owner and uuid fields are only available in filesystems - * with the crc feature bit, and all accesses to them must be conditional on - * that flag. - */ -/* short form block header */ -struct xfs_btree_block_shdr { - __be32 bb_leftsib; - __be32 bb_rightsib; - - __be64 bb_blkno; - __be64 bb_lsn; - uuid_t bb_uuid; - __be32 bb_owner; - __le32 bb_crc; -}; - -/* long form block header */ -struct xfs_btree_block_lhdr { - __be64 bb_leftsib; - __be64 bb_rightsib; - - __be64 bb_blkno; - __be64 bb_lsn; - uuid_t bb_uuid; - __be64 bb_owner; - __le32 bb_crc; - __be32 bb_pad; /* padding for alignment */ -}; - -struct xfs_btree_block { - __be32 bb_magic; /* magic number for block type */ - __be16 bb_level; /* 0 is a leaf */ - __be16 bb_numrecs; /* current # of data records */ - union { - struct xfs_btree_block_shdr s; - struct xfs_btree_block_lhdr l; - } bb_u; /* rest */ -}; - -/* size of a short form block */ -#define XFS_BTREE_SBLOCK_LEN \ - (offsetof(struct xfs_btree_block, bb_u) + \ - offsetof(struct xfs_btree_block_shdr, bb_blkno)) -/* size of a long form block */ -#define XFS_BTREE_LBLOCK_LEN \ - (offsetof(struct xfs_btree_block, bb_u) + \ - offsetof(struct xfs_btree_block_lhdr, bb_blkno)) - -/* sizes of CRC enabled btree blocks */ -#define XFS_BTREE_SBLOCK_CRC_LEN \ - (offsetof(struct xfs_btree_block, bb_u) + \ - sizeof(struct xfs_btree_block_shdr)) -#define XFS_BTREE_LBLOCK_CRC_LEN \ - (offsetof(struct xfs_btree_block, bb_u) + \ - sizeof(struct xfs_btree_block_lhdr)) - -#define XFS_BTREE_SBLOCK_CRC_OFF \ - offsetof(struct xfs_btree_block, bb_u.s.bb_crc) -#define XFS_BTREE_LBLOCK_CRC_OFF \ - offsetof(struct xfs_btree_block, bb_u.l.bb_crc) - -/* - * On-disk XFS access control list structure. - */ -struct xfs_acl_entry { - __be32 ae_tag; - __be32 ae_id; - __be16 ae_perm; - __be16 ae_pad; /* fill the implicit hole in the structure */ -}; - -struct xfs_acl { - __be32 acl_cnt; - struct xfs_acl_entry acl_entry[0]; -}; - -/* - * The number of ACL entries allowed is defined by the on-disk format. - * For v4 superblocks, that is limited to 25 entries. For v5 superblocks, it is - * limited only by the maximum size of the xattr that stores the information. - */ -#define XFS_ACL_MAX_ENTRIES(mp) \ - (xfs_sb_version_hascrc(&mp->m_sb) \ - ? (XFS_XATTR_SIZE_MAX - sizeof(struct xfs_acl)) / \ - sizeof(struct xfs_acl_entry) \ - : 25) - -#define XFS_ACL_SIZE(cnt) \ - (sizeof(struct xfs_acl) + \ - sizeof(struct xfs_acl_entry) * cnt) - -#define XFS_ACL_MAX_SIZE(mp) \ - XFS_ACL_SIZE(XFS_ACL_MAX_ENTRIES((mp))) - - -/* On-disk XFS extended attribute names */ -#define SGI_ACL_FILE "SGI_ACL_FILE" -#define SGI_ACL_DEFAULT "SGI_ACL_DEFAULT" -#define SGI_ACL_FILE_SIZE (sizeof(SGI_ACL_FILE)-1) -#define SGI_ACL_DEFAULT_SIZE (sizeof(SGI_ACL_DEFAULT)-1) - -#endif /* __XFS_FORMAT_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_fs.h b/src/linux/fs/xfs/libxfs/xfs_fs.h deleted file mode 100644 index b72dc82..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_fs.h +++ /dev/null @@ -1,554 +0,0 @@ -/* - * Copyright (c) 1995-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_FS_H__ -#define __XFS_FS_H__ - -/* - * SGI's XFS filesystem's major stuff (constants, structures) - */ - -/* - * Direct I/O attribute record used with XFS_IOC_DIOINFO - * d_miniosz is the min xfer size, xfer size multiple and file seek offset - * alignment. - */ -#ifndef HAVE_DIOATTR -struct dioattr { - __u32 d_mem; /* data buffer memory alignment */ - __u32 d_miniosz; /* min xfer size */ - __u32 d_maxiosz; /* max xfer size */ -}; -#endif - -/* - * Structure for XFS_IOC_GETBMAP. - * On input, fill in bmv_offset and bmv_length of the first structure - * to indicate the area of interest in the file, and bmv_entries with - * the number of array elements given back. The first structure is - * updated on return to give the offset and length for the next call. - */ -#ifndef HAVE_GETBMAP -struct getbmap { - __s64 bmv_offset; /* file offset of segment in blocks */ - __s64 bmv_block; /* starting block (64-bit daddr_t) */ - __s64 bmv_length; /* length of segment, blocks */ - __s32 bmv_count; /* # of entries in array incl. 1st */ - __s32 bmv_entries; /* # of entries filled in (output) */ -}; -#endif - -/* - * Structure for XFS_IOC_GETBMAPX. Fields bmv_offset through bmv_entries - * are used exactly as in the getbmap structure. The getbmapx structure - * has additional bmv_iflags and bmv_oflags fields. The bmv_iflags field - * is only used for the first structure. It contains input flags - * specifying XFS_IOC_GETBMAPX actions. The bmv_oflags field is filled - * in by the XFS_IOC_GETBMAPX command for each returned structure after - * the first. - */ -#ifndef HAVE_GETBMAPX -struct getbmapx { - __s64 bmv_offset; /* file offset of segment in blocks */ - __s64 bmv_block; /* starting block (64-bit daddr_t) */ - __s64 bmv_length; /* length of segment, blocks */ - __s32 bmv_count; /* # of entries in array incl. 1st */ - __s32 bmv_entries; /* # of entries filled in (output). */ - __s32 bmv_iflags; /* input flags (1st structure) */ - __s32 bmv_oflags; /* output flags (after 1st structure)*/ - __s32 bmv_unused1; /* future use */ - __s32 bmv_unused2; /* future use */ -}; -#endif - -/* bmv_iflags values - set by XFS_IOC_GETBMAPX caller. */ -#define BMV_IF_ATTRFORK 0x1 /* return attr fork rather than data */ -#define BMV_IF_NO_DMAPI_READ 0x2 /* Do not generate DMAPI read event */ -#define BMV_IF_PREALLOC 0x4 /* rtn status BMV_OF_PREALLOC if req */ -#define BMV_IF_DELALLOC 0x8 /* rtn status BMV_OF_DELALLOC if req */ -#define BMV_IF_NO_HOLES 0x10 /* Do not return holes */ -#define BMV_IF_COWFORK 0x20 /* return CoW fork rather than data */ -#define BMV_IF_VALID \ - (BMV_IF_ATTRFORK|BMV_IF_NO_DMAPI_READ|BMV_IF_PREALLOC| \ - BMV_IF_DELALLOC|BMV_IF_NO_HOLES|BMV_IF_COWFORK) - -/* bmv_oflags values - returned for each non-header segment */ -#define BMV_OF_PREALLOC 0x1 /* segment = unwritten pre-allocation */ -#define BMV_OF_DELALLOC 0x2 /* segment = delayed allocation */ -#define BMV_OF_LAST 0x4 /* segment is the last in the file */ -#define BMV_OF_SHARED 0x8 /* segment shared with another file */ - -/* - * Structure for XFS_IOC_FSSETDM. - * For use by backup and restore programs to set the XFS on-disk inode - * fields di_dmevmask and di_dmstate. These must be set to exactly and - * only values previously obtained via xfs_bulkstat! (Specifically the - * xfs_bstat_t fields bs_dmevmask and bs_dmstate.) - */ -#ifndef HAVE_FSDMIDATA -struct fsdmidata { - __u32 fsd_dmevmask; /* corresponds to di_dmevmask */ - __u16 fsd_padding; - __u16 fsd_dmstate; /* corresponds to di_dmstate */ -}; -#endif - -/* - * File segment locking set data type for 64 bit access. - * Also used for all the RESV/FREE interfaces. - */ -typedef struct xfs_flock64 { - __s16 l_type; - __s16 l_whence; - __s64 l_start; - __s64 l_len; /* len == 0 means until end of file */ - __s32 l_sysid; - __u32 l_pid; - __s32 l_pad[4]; /* reserve area */ -} xfs_flock64_t; - -/* - * Output for XFS_IOC_FSGEOMETRY_V1 - */ -typedef struct xfs_fsop_geom_v1 { - __u32 blocksize; /* filesystem (data) block size */ - __u32 rtextsize; /* realtime extent size */ - __u32 agblocks; /* fsblocks in an AG */ - __u32 agcount; /* number of allocation groups */ - __u32 logblocks; /* fsblocks in the log */ - __u32 sectsize; /* (data) sector size, bytes */ - __u32 inodesize; /* inode size in bytes */ - __u32 imaxpct; /* max allowed inode space(%) */ - __u64 datablocks; /* fsblocks in data subvolume */ - __u64 rtblocks; /* fsblocks in realtime subvol */ - __u64 rtextents; /* rt extents in realtime subvol*/ - __u64 logstart; /* starting fsblock of the log */ - unsigned char uuid[16]; /* unique id of the filesystem */ - __u32 sunit; /* stripe unit, fsblocks */ - __u32 swidth; /* stripe width, fsblocks */ - __s32 version; /* structure version */ - __u32 flags; /* superblock version flags */ - __u32 logsectsize; /* log sector size, bytes */ - __u32 rtsectsize; /* realtime sector size, bytes */ - __u32 dirblocksize; /* directory block size, bytes */ -} xfs_fsop_geom_v1_t; - -/* - * Output for XFS_IOC_FSGEOMETRY - */ -typedef struct xfs_fsop_geom { - __u32 blocksize; /* filesystem (data) block size */ - __u32 rtextsize; /* realtime extent size */ - __u32 agblocks; /* fsblocks in an AG */ - __u32 agcount; /* number of allocation groups */ - __u32 logblocks; /* fsblocks in the log */ - __u32 sectsize; /* (data) sector size, bytes */ - __u32 inodesize; /* inode size in bytes */ - __u32 imaxpct; /* max allowed inode space(%) */ - __u64 datablocks; /* fsblocks in data subvolume */ - __u64 rtblocks; /* fsblocks in realtime subvol */ - __u64 rtextents; /* rt extents in realtime subvol*/ - __u64 logstart; /* starting fsblock of the log */ - unsigned char uuid[16]; /* unique id of the filesystem */ - __u32 sunit; /* stripe unit, fsblocks */ - __u32 swidth; /* stripe width, fsblocks */ - __s32 version; /* structure version */ - __u32 flags; /* superblock version flags */ - __u32 logsectsize; /* log sector size, bytes */ - __u32 rtsectsize; /* realtime sector size, bytes */ - __u32 dirblocksize; /* directory block size, bytes */ - __u32 logsunit; /* log stripe unit, bytes */ -} xfs_fsop_geom_t; - -/* Output for XFS_FS_COUNTS */ -typedef struct xfs_fsop_counts { - __u64 freedata; /* free data section blocks */ - __u64 freertx; /* free rt extents */ - __u64 freeino; /* free inodes */ - __u64 allocino; /* total allocated inodes */ -} xfs_fsop_counts_t; - -/* Input/Output for XFS_GET_RESBLKS and XFS_SET_RESBLKS */ -typedef struct xfs_fsop_resblks { - __u64 resblks; - __u64 resblks_avail; -} xfs_fsop_resblks_t; - -#define XFS_FSOP_GEOM_VERSION 0 - -#define XFS_FSOP_GEOM_FLAGS_ATTR 0x0001 /* attributes in use */ -#define XFS_FSOP_GEOM_FLAGS_NLINK 0x0002 /* 32-bit nlink values */ -#define XFS_FSOP_GEOM_FLAGS_QUOTA 0x0004 /* quotas enabled */ -#define XFS_FSOP_GEOM_FLAGS_IALIGN 0x0008 /* inode alignment */ -#define XFS_FSOP_GEOM_FLAGS_DALIGN 0x0010 /* large data alignment */ -#define XFS_FSOP_GEOM_FLAGS_SHARED 0x0020 /* read-only shared */ -#define XFS_FSOP_GEOM_FLAGS_EXTFLG 0x0040 /* special extent flag */ -#define XFS_FSOP_GEOM_FLAGS_DIRV2 0x0080 /* directory version 2 */ -#define XFS_FSOP_GEOM_FLAGS_LOGV2 0x0100 /* log format version 2 */ -#define XFS_FSOP_GEOM_FLAGS_SECTOR 0x0200 /* sector sizes >1BB */ -#define XFS_FSOP_GEOM_FLAGS_ATTR2 0x0400 /* inline attributes rework */ -#define XFS_FSOP_GEOM_FLAGS_PROJID32 0x0800 /* 32-bit project IDs */ -#define XFS_FSOP_GEOM_FLAGS_DIRV2CI 0x1000 /* ASCII only CI names */ -#define XFS_FSOP_GEOM_FLAGS_LAZYSB 0x4000 /* lazy superblock counters */ -#define XFS_FSOP_GEOM_FLAGS_V5SB 0x8000 /* version 5 superblock */ -#define XFS_FSOP_GEOM_FLAGS_FTYPE 0x10000 /* inode directory types */ -#define XFS_FSOP_GEOM_FLAGS_FINOBT 0x20000 /* free inode btree */ -#define XFS_FSOP_GEOM_FLAGS_SPINODES 0x40000 /* sparse inode chunks */ -#define XFS_FSOP_GEOM_FLAGS_RMAPBT 0x80000 /* reverse mapping btree */ -#define XFS_FSOP_GEOM_FLAGS_REFLINK 0x100000 /* files can share blocks */ - -/* - * Minimum and maximum sizes need for growth checks. - * - * Block counts are in units of filesystem blocks, not basic blocks. - */ -#define XFS_MIN_AG_BLOCKS 64 -#define XFS_MIN_LOG_BLOCKS 512ULL -#define XFS_MAX_LOG_BLOCKS (1024 * 1024ULL) -#define XFS_MIN_LOG_BYTES (10 * 1024 * 1024ULL) - -/* keep the maximum size under 2^31 by a small amount */ -#define XFS_MAX_LOG_BYTES \ - ((2 * 1024 * 1024 * 1024ULL) - XFS_MIN_LOG_BYTES) - -/* Used for sanity checks on superblock */ -#define XFS_MAX_DBLOCKS(s) ((xfs_rfsblock_t)(s)->sb_agcount * (s)->sb_agblocks) -#define XFS_MIN_DBLOCKS(s) ((xfs_rfsblock_t)((s)->sb_agcount - 1) * \ - (s)->sb_agblocks + XFS_MIN_AG_BLOCKS) - -/* - * Structures for XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG & XFS_IOC_FSGROWFSRT - */ -typedef struct xfs_growfs_data { - __u64 newblocks; /* new data subvol size, fsblocks */ - __u32 imaxpct; /* new inode space percentage limit */ -} xfs_growfs_data_t; - -typedef struct xfs_growfs_log { - __u32 newblocks; /* new log size, fsblocks */ - __u32 isint; /* 1 if new log is internal */ -} xfs_growfs_log_t; - -typedef struct xfs_growfs_rt { - __u64 newblocks; /* new realtime size, fsblocks */ - __u32 extsize; /* new realtime extent size, fsblocks */ -} xfs_growfs_rt_t; - - -/* - * Structures returned from ioctl XFS_IOC_FSBULKSTAT & XFS_IOC_FSBULKSTAT_SINGLE - */ -typedef struct xfs_bstime { - time_t tv_sec; /* seconds */ - __s32 tv_nsec; /* and nanoseconds */ -} xfs_bstime_t; - -typedef struct xfs_bstat { - __u64 bs_ino; /* inode number */ - __u16 bs_mode; /* type and mode */ - __u16 bs_nlink; /* number of links */ - __u32 bs_uid; /* user id */ - __u32 bs_gid; /* group id */ - __u32 bs_rdev; /* device value */ - __s32 bs_blksize; /* block size */ - __s64 bs_size; /* file size */ - xfs_bstime_t bs_atime; /* access time */ - xfs_bstime_t bs_mtime; /* modify time */ - xfs_bstime_t bs_ctime; /* inode change time */ - int64_t bs_blocks; /* number of blocks */ - __u32 bs_xflags; /* extended flags */ - __s32 bs_extsize; /* extent size */ - __s32 bs_extents; /* number of extents */ - __u32 bs_gen; /* generation count */ - __u16 bs_projid_lo; /* lower part of project id */ -#define bs_projid bs_projid_lo /* (previously just bs_projid) */ - __u16 bs_forkoff; /* inode fork offset in bytes */ - __u16 bs_projid_hi; /* higher part of project id */ - unsigned char bs_pad[6]; /* pad space, unused */ - __u32 bs_cowextsize; /* cow extent size */ - __u32 bs_dmevmask; /* DMIG event mask */ - __u16 bs_dmstate; /* DMIG state info */ - __u16 bs_aextents; /* attribute number of extents */ -} xfs_bstat_t; - -/* - * Project quota id helpers (previously projid was 16bit only - * and using two 16bit values to hold new 32bit projid was choosen - * to retain compatibility with "old" filesystems). - */ -static inline __uint32_t -bstat_get_projid(struct xfs_bstat *bs) -{ - return (__uint32_t)bs->bs_projid_hi << 16 | bs->bs_projid_lo; -} - -/* - * The user-level BulkStat Request interface structure. - */ -typedef struct xfs_fsop_bulkreq { - __u64 __user *lastip; /* last inode # pointer */ - __s32 icount; /* count of entries in buffer */ - void __user *ubuffer;/* user buffer for inode desc. */ - __s32 __user *ocount; /* output count pointer */ -} xfs_fsop_bulkreq_t; - - -/* - * Structures returned from xfs_inumbers routine (XFS_IOC_FSINUMBERS). - */ -typedef struct xfs_inogrp { - __u64 xi_startino; /* starting inode number */ - __s32 xi_alloccount; /* # bits set in allocmask */ - __u64 xi_allocmask; /* mask of allocated inodes */ -} xfs_inogrp_t; - - -/* - * Error injection. - */ -typedef struct xfs_error_injection { - __s32 fd; - __s32 errtag; -} xfs_error_injection_t; - - -/* - * Speculative preallocation trimming. - */ -#define XFS_EOFBLOCKS_VERSION 1 -struct xfs_fs_eofblocks { - __u32 eof_version; - __u32 eof_flags; - uid_t eof_uid; - gid_t eof_gid; - prid_t eof_prid; - __u32 pad32; - __u64 eof_min_file_size; - __u64 pad64[12]; -}; - -/* eof_flags values */ -#define XFS_EOF_FLAGS_SYNC (1 << 0) /* sync/wait mode scan */ -#define XFS_EOF_FLAGS_UID (1 << 1) /* filter by uid */ -#define XFS_EOF_FLAGS_GID (1 << 2) /* filter by gid */ -#define XFS_EOF_FLAGS_PRID (1 << 3) /* filter by project id */ -#define XFS_EOF_FLAGS_MINFILESIZE (1 << 4) /* filter by min file size */ -#define XFS_EOF_FLAGS_UNION (1 << 5) /* union filter algorithm; - * kernel only, not included in - * valid mask */ -#define XFS_EOF_FLAGS_VALID \ - (XFS_EOF_FLAGS_SYNC | \ - XFS_EOF_FLAGS_UID | \ - XFS_EOF_FLAGS_GID | \ - XFS_EOF_FLAGS_PRID | \ - XFS_EOF_FLAGS_MINFILESIZE) - - -/* - * The user-level Handle Request interface structure. - */ -typedef struct xfs_fsop_handlereq { - __u32 fd; /* fd for FD_TO_HANDLE */ - void __user *path; /* user pathname */ - __u32 oflags; /* open flags */ - void __user *ihandle;/* user supplied handle */ - __u32 ihandlen; /* user supplied length */ - void __user *ohandle;/* user buffer for handle */ - __u32 __user *ohandlen;/* user buffer length */ -} xfs_fsop_handlereq_t; - -/* - * Compound structures for passing args through Handle Request interfaces - * xfs_fssetdm_by_handle, xfs_attrlist_by_handle, xfs_attrmulti_by_handle - * - ioctls: XFS_IOC_FSSETDM_BY_HANDLE, XFS_IOC_ATTRLIST_BY_HANDLE, and - * XFS_IOC_ATTRMULTI_BY_HANDLE - */ - -typedef struct xfs_fsop_setdm_handlereq { - struct xfs_fsop_handlereq hreq; /* handle information */ - struct fsdmidata __user *data; /* DMAPI data */ -} xfs_fsop_setdm_handlereq_t; - -typedef struct xfs_attrlist_cursor { - __u32 opaque[4]; -} xfs_attrlist_cursor_t; - -typedef struct xfs_fsop_attrlist_handlereq { - struct xfs_fsop_handlereq hreq; /* handle interface structure */ - struct xfs_attrlist_cursor pos; /* opaque cookie, list offset */ - __u32 flags; /* which namespace to use */ - __u32 buflen; /* length of buffer supplied */ - void __user *buffer; /* returned names */ -} xfs_fsop_attrlist_handlereq_t; - -typedef struct xfs_attr_multiop { - __u32 am_opcode; -#define ATTR_OP_GET 1 /* return the indicated attr's value */ -#define ATTR_OP_SET 2 /* set/create the indicated attr/value pair */ -#define ATTR_OP_REMOVE 3 /* remove the indicated attr */ - __s32 am_error; - void __user *am_attrname; - void __user *am_attrvalue; - __u32 am_length; - __u32 am_flags; -} xfs_attr_multiop_t; - -typedef struct xfs_fsop_attrmulti_handlereq { - struct xfs_fsop_handlereq hreq; /* handle interface structure */ - __u32 opcount;/* count of following multiop */ - struct xfs_attr_multiop __user *ops; /* attr_multi data */ -} xfs_fsop_attrmulti_handlereq_t; - -/* - * per machine unique filesystem identifier types. - */ -typedef struct { __u32 val[2]; } xfs_fsid_t; /* file system id type */ - -typedef struct xfs_fid { - __u16 fid_len; /* length of remainder */ - __u16 fid_pad; - __u32 fid_gen; /* generation number */ - __u64 fid_ino; /* 64 bits inode number */ -} xfs_fid_t; - -typedef struct xfs_handle { - union { - __s64 align; /* force alignment of ha_fid */ - xfs_fsid_t _ha_fsid; /* unique file system identifier */ - } ha_u; - xfs_fid_t ha_fid; /* file system specific file ID */ -} xfs_handle_t; -#define ha_fsid ha_u._ha_fsid - -#define XFS_HSIZE(handle) (((char *) &(handle).ha_fid.fid_pad \ - - (char *) &(handle)) \ - + (handle).ha_fid.fid_len) - -/* - * Structure passed to XFS_IOC_SWAPEXT - */ -typedef struct xfs_swapext -{ - __int64_t sx_version; /* version */ -#define XFS_SX_VERSION 0 - __int64_t sx_fdtarget; /* fd of target file */ - __int64_t sx_fdtmp; /* fd of tmp file */ - xfs_off_t sx_offset; /* offset into file */ - xfs_off_t sx_length; /* leng from offset */ - char sx_pad[16]; /* pad space, unused */ - xfs_bstat_t sx_stat; /* stat of target b4 copy */ -} xfs_swapext_t; - -/* - * Flags for going down operation - */ -#define XFS_FSOP_GOING_FLAGS_DEFAULT 0x0 /* going down */ -#define XFS_FSOP_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */ -#define XFS_FSOP_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */ - -/* - * ioctl limits - */ -#ifdef XATTR_LIST_MAX -# define XFS_XATTR_LIST_MAX XATTR_LIST_MAX -#else -# define XFS_XATTR_LIST_MAX 65536 -#endif - - -/* - * ioctl commands that are used by Linux filesystems - */ -#define XFS_IOC_GETXFLAGS FS_IOC_GETFLAGS -#define XFS_IOC_SETXFLAGS FS_IOC_SETFLAGS -#define XFS_IOC_GETVERSION FS_IOC_GETVERSION - -/* - * ioctl commands that replace IRIX fcntl()'s - * For 'documentation' purposed more than anything else, - * the "cmd #" field reflects the IRIX fcntl number. - */ -#define XFS_IOC_ALLOCSP _IOW ('X', 10, struct xfs_flock64) -#define XFS_IOC_FREESP _IOW ('X', 11, struct xfs_flock64) -#define XFS_IOC_DIOINFO _IOR ('X', 30, struct dioattr) -#define XFS_IOC_FSGETXATTR FS_IOC_FSGETXATTR -#define XFS_IOC_FSSETXATTR FS_IOC_FSSETXATTR -#define XFS_IOC_ALLOCSP64 _IOW ('X', 36, struct xfs_flock64) -#define XFS_IOC_FREESP64 _IOW ('X', 37, struct xfs_flock64) -#define XFS_IOC_GETBMAP _IOWR('X', 38, struct getbmap) -#define XFS_IOC_FSSETDM _IOW ('X', 39, struct fsdmidata) -#define XFS_IOC_RESVSP _IOW ('X', 40, struct xfs_flock64) -#define XFS_IOC_UNRESVSP _IOW ('X', 41, struct xfs_flock64) -#define XFS_IOC_RESVSP64 _IOW ('X', 42, struct xfs_flock64) -#define XFS_IOC_UNRESVSP64 _IOW ('X', 43, struct xfs_flock64) -#define XFS_IOC_GETBMAPA _IOWR('X', 44, struct getbmap) -#define XFS_IOC_FSGETXATTRA _IOR ('X', 45, struct fsxattr) -/* XFS_IOC_SETBIOSIZE ---- deprecated 46 */ -/* XFS_IOC_GETBIOSIZE ---- deprecated 47 */ -#define XFS_IOC_GETBMAPX _IOWR('X', 56, struct getbmap) -#define XFS_IOC_ZERO_RANGE _IOW ('X', 57, struct xfs_flock64) -#define XFS_IOC_FREE_EOFBLOCKS _IOR ('X', 58, struct xfs_fs_eofblocks) - -/* - * ioctl commands that replace IRIX syssgi()'s - */ -#define XFS_IOC_FSGEOMETRY_V1 _IOR ('X', 100, struct xfs_fsop_geom_v1) -#define XFS_IOC_FSBULKSTAT _IOWR('X', 101, struct xfs_fsop_bulkreq) -#define XFS_IOC_FSBULKSTAT_SINGLE _IOWR('X', 102, struct xfs_fsop_bulkreq) -#define XFS_IOC_FSINUMBERS _IOWR('X', 103, struct xfs_fsop_bulkreq) -#define XFS_IOC_PATH_TO_FSHANDLE _IOWR('X', 104, struct xfs_fsop_handlereq) -#define XFS_IOC_PATH_TO_HANDLE _IOWR('X', 105, struct xfs_fsop_handlereq) -#define XFS_IOC_FD_TO_HANDLE _IOWR('X', 106, struct xfs_fsop_handlereq) -#define XFS_IOC_OPEN_BY_HANDLE _IOWR('X', 107, struct xfs_fsop_handlereq) -#define XFS_IOC_READLINK_BY_HANDLE _IOWR('X', 108, struct xfs_fsop_handlereq) -#define XFS_IOC_SWAPEXT _IOWR('X', 109, struct xfs_swapext) -#define XFS_IOC_FSGROWFSDATA _IOW ('X', 110, struct xfs_growfs_data) -#define XFS_IOC_FSGROWFSLOG _IOW ('X', 111, struct xfs_growfs_log) -#define XFS_IOC_FSGROWFSRT _IOW ('X', 112, struct xfs_growfs_rt) -#define XFS_IOC_FSCOUNTS _IOR ('X', 113, struct xfs_fsop_counts) -#define XFS_IOC_SET_RESBLKS _IOWR('X', 114, struct xfs_fsop_resblks) -#define XFS_IOC_GET_RESBLKS _IOR ('X', 115, struct xfs_fsop_resblks) -#define XFS_IOC_ERROR_INJECTION _IOW ('X', 116, struct xfs_error_injection) -#define XFS_IOC_ERROR_CLEARALL _IOW ('X', 117, struct xfs_error_injection) -/* XFS_IOC_ATTRCTL_BY_HANDLE -- deprecated 118 */ - -#define XFS_IOC_FREEZE _IOWR('X', 119, int) /* aka FIFREEZE */ -#define XFS_IOC_THAW _IOWR('X', 120, int) /* aka FITHAW */ - -#define XFS_IOC_FSSETDM_BY_HANDLE _IOW ('X', 121, struct xfs_fsop_setdm_handlereq) -#define XFS_IOC_ATTRLIST_BY_HANDLE _IOW ('X', 122, struct xfs_fsop_attrlist_handlereq) -#define XFS_IOC_ATTRMULTI_BY_HANDLE _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq) -#define XFS_IOC_FSGEOMETRY _IOR ('X', 124, struct xfs_fsop_geom) -#define XFS_IOC_GOINGDOWN _IOR ('X', 125, __uint32_t) -/* XFS_IOC_GETFSUUID ---------- deprecated 140 */ - - -#ifndef HAVE_BBMACROS -/* - * Block I/O parameterization. A basic block (BB) is the lowest size of - * filesystem allocation, and must equal 512. Length units given to bio - * routines are in BB's. - */ -#define BBSHIFT 9 -#define BBSIZE (1<> BBSHIFT) -#define BTOBBT(bytes) ((__u64)(bytes) >> BBSHIFT) -#define BBTOB(bbs) ((bbs) << BBSHIFT) -#endif - -#endif /* __XFS_FS_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_ialloc.c b/src/linux/fs/xfs/libxfs/xfs_ialloc.c deleted file mode 100644 index 51b4e0d..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_ialloc.c +++ /dev/null @@ -1,2653 +0,0 @@ -/* - * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_inode.h" -#include "xfs_btree.h" -#include "xfs_ialloc.h" -#include "xfs_ialloc_btree.h" -#include "xfs_alloc.h" -#include "xfs_rtalloc.h" -#include "xfs_error.h" -#include "xfs_bmap.h" -#include "xfs_cksum.h" -#include "xfs_trans.h" -#include "xfs_buf_item.h" -#include "xfs_icreate_item.h" -#include "xfs_icache.h" -#include "xfs_trace.h" -#include "xfs_log.h" -#include "xfs_rmap.h" - - -/* - * Allocation group level functions. - */ -static inline int -xfs_ialloc_cluster_alignment( - struct xfs_mount *mp) -{ - if (xfs_sb_version_hasalign(&mp->m_sb) && - mp->m_sb.sb_inoalignmt >= - XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size)) - return mp->m_sb.sb_inoalignmt; - return 1; -} - -/* - * Lookup a record by ino in the btree given by cur. - */ -int /* error */ -xfs_inobt_lookup( - struct xfs_btree_cur *cur, /* btree cursor */ - xfs_agino_t ino, /* starting inode of chunk */ - xfs_lookup_t dir, /* <=, >=, == */ - int *stat) /* success/failure */ -{ - cur->bc_rec.i.ir_startino = ino; - cur->bc_rec.i.ir_holemask = 0; - cur->bc_rec.i.ir_count = 0; - cur->bc_rec.i.ir_freecount = 0; - cur->bc_rec.i.ir_free = 0; - return xfs_btree_lookup(cur, dir, stat); -} - -/* - * Update the record referred to by cur to the value given. - * This either works (return 0) or gets an EFSCORRUPTED error. - */ -STATIC int /* error */ -xfs_inobt_update( - struct xfs_btree_cur *cur, /* btree cursor */ - xfs_inobt_rec_incore_t *irec) /* btree record */ -{ - union xfs_btree_rec rec; - - rec.inobt.ir_startino = cpu_to_be32(irec->ir_startino); - if (xfs_sb_version_hassparseinodes(&cur->bc_mp->m_sb)) { - rec.inobt.ir_u.sp.ir_holemask = cpu_to_be16(irec->ir_holemask); - rec.inobt.ir_u.sp.ir_count = irec->ir_count; - rec.inobt.ir_u.sp.ir_freecount = irec->ir_freecount; - } else { - /* ir_holemask/ir_count not supported on-disk */ - rec.inobt.ir_u.f.ir_freecount = cpu_to_be32(irec->ir_freecount); - } - rec.inobt.ir_free = cpu_to_be64(irec->ir_free); - return xfs_btree_update(cur, &rec); -} - -/* - * Get the data from the pointed-to record. - */ -int /* error */ -xfs_inobt_get_rec( - struct xfs_btree_cur *cur, /* btree cursor */ - xfs_inobt_rec_incore_t *irec, /* btree record */ - int *stat) /* output: success/failure */ -{ - union xfs_btree_rec *rec; - int error; - - error = xfs_btree_get_rec(cur, &rec, stat); - if (error || *stat == 0) - return error; - - irec->ir_startino = be32_to_cpu(rec->inobt.ir_startino); - if (xfs_sb_version_hassparseinodes(&cur->bc_mp->m_sb)) { - irec->ir_holemask = be16_to_cpu(rec->inobt.ir_u.sp.ir_holemask); - irec->ir_count = rec->inobt.ir_u.sp.ir_count; - irec->ir_freecount = rec->inobt.ir_u.sp.ir_freecount; - } else { - /* - * ir_holemask/ir_count not supported on-disk. Fill in hardcoded - * values for full inode chunks. - */ - irec->ir_holemask = XFS_INOBT_HOLEMASK_FULL; - irec->ir_count = XFS_INODES_PER_CHUNK; - irec->ir_freecount = - be32_to_cpu(rec->inobt.ir_u.f.ir_freecount); - } - irec->ir_free = be64_to_cpu(rec->inobt.ir_free); - - return 0; -} - -/* - * Insert a single inobt record. Cursor must already point to desired location. - */ -STATIC int -xfs_inobt_insert_rec( - struct xfs_btree_cur *cur, - __uint16_t holemask, - __uint8_t count, - __int32_t freecount, - xfs_inofree_t free, - int *stat) -{ - cur->bc_rec.i.ir_holemask = holemask; - cur->bc_rec.i.ir_count = count; - cur->bc_rec.i.ir_freecount = freecount; - cur->bc_rec.i.ir_free = free; - return xfs_btree_insert(cur, stat); -} - -/* - * Insert records describing a newly allocated inode chunk into the inobt. - */ -STATIC int -xfs_inobt_insert( - struct xfs_mount *mp, - struct xfs_trans *tp, - struct xfs_buf *agbp, - xfs_agino_t newino, - xfs_agino_t newlen, - xfs_btnum_t btnum) -{ - struct xfs_btree_cur *cur; - struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); - xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); - xfs_agino_t thisino; - int i; - int error; - - cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum); - - for (thisino = newino; - thisino < newino + newlen; - thisino += XFS_INODES_PER_CHUNK) { - error = xfs_inobt_lookup(cur, thisino, XFS_LOOKUP_EQ, &i); - if (error) { - xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); - return error; - } - ASSERT(i == 0); - - error = xfs_inobt_insert_rec(cur, XFS_INOBT_HOLEMASK_FULL, - XFS_INODES_PER_CHUNK, - XFS_INODES_PER_CHUNK, - XFS_INOBT_ALL_FREE, &i); - if (error) { - xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); - return error; - } - ASSERT(i == 1); - } - - xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); - - return 0; -} - -/* - * Verify that the number of free inodes in the AGI is correct. - */ -#ifdef DEBUG -STATIC int -xfs_check_agi_freecount( - struct xfs_btree_cur *cur, - struct xfs_agi *agi) -{ - if (cur->bc_nlevels == 1) { - xfs_inobt_rec_incore_t rec; - int freecount = 0; - int error; - int i; - - error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i); - if (error) - return error; - - do { - error = xfs_inobt_get_rec(cur, &rec, &i); - if (error) - return error; - - if (i) { - freecount += rec.ir_freecount; - error = xfs_btree_increment(cur, 0, &i); - if (error) - return error; - } - } while (i == 1); - - if (!XFS_FORCED_SHUTDOWN(cur->bc_mp)) - ASSERT(freecount == be32_to_cpu(agi->agi_freecount)); - } - return 0; -} -#else -#define xfs_check_agi_freecount(cur, agi) 0 -#endif - -/* - * Initialise a new set of inodes. When called without a transaction context - * (e.g. from recovery) we initiate a delayed write of the inode buffers rather - * than logging them (which in a transaction context puts them into the AIL - * for writeback rather than the xfsbufd queue). - */ -int -xfs_ialloc_inode_init( - struct xfs_mount *mp, - struct xfs_trans *tp, - struct list_head *buffer_list, - int icount, - xfs_agnumber_t agno, - xfs_agblock_t agbno, - xfs_agblock_t length, - unsigned int gen) -{ - struct xfs_buf *fbuf; - struct xfs_dinode *free; - int nbufs, blks_per_cluster, inodes_per_cluster; - int version; - int i, j; - xfs_daddr_t d; - xfs_ino_t ino = 0; - - /* - * Loop over the new block(s), filling in the inodes. For small block - * sizes, manipulate the inodes in buffers which are multiples of the - * blocks size. - */ - blks_per_cluster = xfs_icluster_size_fsb(mp); - inodes_per_cluster = blks_per_cluster << mp->m_sb.sb_inopblog; - nbufs = length / blks_per_cluster; - - /* - * Figure out what version number to use in the inodes we create. If - * the superblock version has caught up to the one that supports the new - * inode format, then use the new inode version. Otherwise use the old - * version so that old kernels will continue to be able to use the file - * system. - * - * For v3 inodes, we also need to write the inode number into the inode, - * so calculate the first inode number of the chunk here as - * XFS_OFFBNO_TO_AGINO() only works within a filesystem block, not - * across multiple filesystem blocks (such as a cluster) and so cannot - * be used in the cluster buffer loop below. - * - * Further, because we are writing the inode directly into the buffer - * and calculating a CRC on the entire inode, we have ot log the entire - * inode so that the entire range the CRC covers is present in the log. - * That means for v3 inode we log the entire buffer rather than just the - * inode cores. - */ - if (xfs_sb_version_hascrc(&mp->m_sb)) { - version = 3; - ino = XFS_AGINO_TO_INO(mp, agno, - XFS_OFFBNO_TO_AGINO(mp, agbno, 0)); - - /* - * log the initialisation that is about to take place as an - * logical operation. This means the transaction does not - * need to log the physical changes to the inode buffers as log - * recovery will know what initialisation is actually needed. - * Hence we only need to log the buffers as "ordered" buffers so - * they track in the AIL as if they were physically logged. - */ - if (tp) - xfs_icreate_log(tp, agno, agbno, icount, - mp->m_sb.sb_inodesize, length, gen); - } else - version = 2; - - for (j = 0; j < nbufs; j++) { - /* - * Get the block. - */ - d = XFS_AGB_TO_DADDR(mp, agno, agbno + (j * blks_per_cluster)); - fbuf = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, - mp->m_bsize * blks_per_cluster, - XBF_UNMAPPED); - if (!fbuf) - return -ENOMEM; - - /* Initialize the inode buffers and log them appropriately. */ - fbuf->b_ops = &xfs_inode_buf_ops; - xfs_buf_zero(fbuf, 0, BBTOB(fbuf->b_length)); - for (i = 0; i < inodes_per_cluster; i++) { - int ioffset = i << mp->m_sb.sb_inodelog; - uint isize = xfs_dinode_size(version); - - free = xfs_make_iptr(mp, fbuf, i); - free->di_magic = cpu_to_be16(XFS_DINODE_MAGIC); - free->di_version = version; - free->di_gen = cpu_to_be32(gen); - free->di_next_unlinked = cpu_to_be32(NULLAGINO); - - if (version == 3) { - free->di_ino = cpu_to_be64(ino); - ino++; - uuid_copy(&free->di_uuid, - &mp->m_sb.sb_meta_uuid); - xfs_dinode_calc_crc(mp, free); - } else if (tp) { - /* just log the inode core */ - xfs_trans_log_buf(tp, fbuf, ioffset, - ioffset + isize - 1); - } - } - - if (tp) { - /* - * Mark the buffer as an inode allocation buffer so it - * sticks in AIL at the point of this allocation - * transaction. This ensures the they are on disk before - * the tail of the log can be moved past this - * transaction (i.e. by preventing relogging from moving - * it forward in the log). - */ - xfs_trans_inode_alloc_buf(tp, fbuf); - if (version == 3) { - /* - * Mark the buffer as ordered so that they are - * not physically logged in the transaction but - * still tracked in the AIL as part of the - * transaction and pin the log appropriately. - */ - xfs_trans_ordered_buf(tp, fbuf); - xfs_trans_log_buf(tp, fbuf, 0, - BBTOB(fbuf->b_length) - 1); - } - } else { - fbuf->b_flags |= XBF_DONE; - xfs_buf_delwri_queue(fbuf, buffer_list); - xfs_buf_relse(fbuf); - } - } - return 0; -} - -/* - * Align startino and allocmask for a recently allocated sparse chunk such that - * they are fit for insertion (or merge) into the on-disk inode btrees. - * - * Background: - * - * When enabled, sparse inode support increases the inode alignment from cluster - * size to inode chunk size. This means that the minimum range between two - * non-adjacent inode records in the inobt is large enough for a full inode - * record. This allows for cluster sized, cluster aligned block allocation - * without need to worry about whether the resulting inode record overlaps with - * another record in the tree. Without this basic rule, we would have to deal - * with the consequences of overlap by potentially undoing recent allocations in - * the inode allocation codepath. - * - * Because of this alignment rule (which is enforced on mount), there are two - * inobt possibilities for newly allocated sparse chunks. One is that the - * aligned inode record for the chunk covers a range of inodes not already - * covered in the inobt (i.e., it is safe to insert a new sparse record). The - * other is that a record already exists at the aligned startino that considers - * the newly allocated range as sparse. In the latter case, record content is - * merged in hope that sparse inode chunks fill to full chunks over time. - */ -STATIC void -xfs_align_sparse_ino( - struct xfs_mount *mp, - xfs_agino_t *startino, - uint16_t *allocmask) -{ - xfs_agblock_t agbno; - xfs_agblock_t mod; - int offset; - - agbno = XFS_AGINO_TO_AGBNO(mp, *startino); - mod = agbno % mp->m_sb.sb_inoalignmt; - if (!mod) - return; - - /* calculate the inode offset and align startino */ - offset = mod << mp->m_sb.sb_inopblog; - *startino -= offset; - - /* - * Since startino has been aligned down, left shift allocmask such that - * it continues to represent the same physical inodes relative to the - * new startino. - */ - *allocmask <<= offset / XFS_INODES_PER_HOLEMASK_BIT; -} - -/* - * Determine whether the source inode record can merge into the target. Both - * records must be sparse, the inode ranges must match and there must be no - * allocation overlap between the records. - */ -STATIC bool -__xfs_inobt_can_merge( - struct xfs_inobt_rec_incore *trec, /* tgt record */ - struct xfs_inobt_rec_incore *srec) /* src record */ -{ - uint64_t talloc; - uint64_t salloc; - - /* records must cover the same inode range */ - if (trec->ir_startino != srec->ir_startino) - return false; - - /* both records must be sparse */ - if (!xfs_inobt_issparse(trec->ir_holemask) || - !xfs_inobt_issparse(srec->ir_holemask)) - return false; - - /* both records must track some inodes */ - if (!trec->ir_count || !srec->ir_count) - return false; - - /* can't exceed capacity of a full record */ - if (trec->ir_count + srec->ir_count > XFS_INODES_PER_CHUNK) - return false; - - /* verify there is no allocation overlap */ - talloc = xfs_inobt_irec_to_allocmask(trec); - salloc = xfs_inobt_irec_to_allocmask(srec); - if (talloc & salloc) - return false; - - return true; -} - -/* - * Merge the source inode record into the target. The caller must call - * __xfs_inobt_can_merge() to ensure the merge is valid. - */ -STATIC void -__xfs_inobt_rec_merge( - struct xfs_inobt_rec_incore *trec, /* target */ - struct xfs_inobt_rec_incore *srec) /* src */ -{ - ASSERT(trec->ir_startino == srec->ir_startino); - - /* combine the counts */ - trec->ir_count += srec->ir_count; - trec->ir_freecount += srec->ir_freecount; - - /* - * Merge the holemask and free mask. For both fields, 0 bits refer to - * allocated inodes. We combine the allocated ranges with bitwise AND. - */ - trec->ir_holemask &= srec->ir_holemask; - trec->ir_free &= srec->ir_free; -} - -/* - * Insert a new sparse inode chunk into the associated inode btree. The inode - * record for the sparse chunk is pre-aligned to a startino that should match - * any pre-existing sparse inode record in the tree. This allows sparse chunks - * to fill over time. - * - * This function supports two modes of handling preexisting records depending on - * the merge flag. If merge is true, the provided record is merged with the - * existing record and updated in place. The merged record is returned in nrec. - * If merge is false, an existing record is replaced with the provided record. - * If no preexisting record exists, the provided record is always inserted. - * - * It is considered corruption if a merge is requested and not possible. Given - * the sparse inode alignment constraints, this should never happen. - */ -STATIC int -xfs_inobt_insert_sprec( - struct xfs_mount *mp, - struct xfs_trans *tp, - struct xfs_buf *agbp, - int btnum, - struct xfs_inobt_rec_incore *nrec, /* in/out: new/merged rec. */ - bool merge) /* merge or replace */ -{ - struct xfs_btree_cur *cur; - struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); - xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); - int error; - int i; - struct xfs_inobt_rec_incore rec; - - cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, btnum); - - /* the new record is pre-aligned so we know where to look */ - error = xfs_inobt_lookup(cur, nrec->ir_startino, XFS_LOOKUP_EQ, &i); - if (error) - goto error; - /* if nothing there, insert a new record and return */ - if (i == 0) { - error = xfs_inobt_insert_rec(cur, nrec->ir_holemask, - nrec->ir_count, nrec->ir_freecount, - nrec->ir_free, &i); - if (error) - goto error; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error); - - goto out; - } - - /* - * A record exists at this startino. Merge or replace the record - * depending on what we've been asked to do. - */ - if (merge) { - error = xfs_inobt_get_rec(cur, &rec, &i); - if (error) - goto error; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error); - XFS_WANT_CORRUPTED_GOTO(mp, - rec.ir_startino == nrec->ir_startino, - error); - - /* - * This should never fail. If we have coexisting records that - * cannot merge, something is seriously wrong. - */ - XFS_WANT_CORRUPTED_GOTO(mp, __xfs_inobt_can_merge(nrec, &rec), - error); - - trace_xfs_irec_merge_pre(mp, agno, rec.ir_startino, - rec.ir_holemask, nrec->ir_startino, - nrec->ir_holemask); - - /* merge to nrec to output the updated record */ - __xfs_inobt_rec_merge(nrec, &rec); - - trace_xfs_irec_merge_post(mp, agno, nrec->ir_startino, - nrec->ir_holemask); - - error = xfs_inobt_rec_check_count(mp, nrec); - if (error) - goto error; - } - - error = xfs_inobt_update(cur, nrec); - if (error) - goto error; - -out: - xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); - return 0; -error: - xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); - return error; -} - -/* - * Allocate new inodes in the allocation group specified by agbp. - * Return 0 for success, else error code. - */ -STATIC int /* error code or 0 */ -xfs_ialloc_ag_alloc( - xfs_trans_t *tp, /* transaction pointer */ - xfs_buf_t *agbp, /* alloc group buffer */ - int *alloc) -{ - xfs_agi_t *agi; /* allocation group header */ - xfs_alloc_arg_t args; /* allocation argument structure */ - xfs_agnumber_t agno; - int error; - xfs_agino_t newino; /* new first inode's number */ - xfs_agino_t newlen; /* new number of inodes */ - int isaligned = 0; /* inode allocation at stripe unit */ - /* boundary */ - uint16_t allocmask = (uint16_t) -1; /* init. to full chunk */ - struct xfs_inobt_rec_incore rec; - struct xfs_perag *pag; - int do_sparse = 0; - - memset(&args, 0, sizeof(args)); - args.tp = tp; - args.mp = tp->t_mountp; - args.fsbno = NULLFSBLOCK; - xfs_rmap_ag_owner(&args.oinfo, XFS_RMAP_OWN_INODES); - -#ifdef DEBUG - /* randomly do sparse inode allocations */ - if (xfs_sb_version_hassparseinodes(&tp->t_mountp->m_sb) && - args.mp->m_ialloc_min_blks < args.mp->m_ialloc_blks) - do_sparse = prandom_u32() & 1; -#endif - - /* - * Locking will ensure that we don't have two callers in here - * at one time. - */ - newlen = args.mp->m_ialloc_inos; - if (args.mp->m_maxicount && - percpu_counter_read_positive(&args.mp->m_icount) + newlen > - args.mp->m_maxicount) - return -ENOSPC; - args.minlen = args.maxlen = args.mp->m_ialloc_blks; - /* - * First try to allocate inodes contiguous with the last-allocated - * chunk of inodes. If the filesystem is striped, this will fill - * an entire stripe unit with inodes. - */ - agi = XFS_BUF_TO_AGI(agbp); - newino = be32_to_cpu(agi->agi_newino); - agno = be32_to_cpu(agi->agi_seqno); - args.agbno = XFS_AGINO_TO_AGBNO(args.mp, newino) + - args.mp->m_ialloc_blks; - if (do_sparse) - goto sparse_alloc; - if (likely(newino != NULLAGINO && - (args.agbno < be32_to_cpu(agi->agi_length)))) { - args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); - args.type = XFS_ALLOCTYPE_THIS_BNO; - args.prod = 1; - - /* - * We need to take into account alignment here to ensure that - * we don't modify the free list if we fail to have an exact - * block. If we don't have an exact match, and every oher - * attempt allocation attempt fails, we'll end up cancelling - * a dirty transaction and shutting down. - * - * For an exact allocation, alignment must be 1, - * however we need to take cluster alignment into account when - * fixing up the freelist. Use the minalignslop field to - * indicate that extra blocks might be required for alignment, - * but not to use them in the actual exact allocation. - */ - args.alignment = 1; - args.minalignslop = xfs_ialloc_cluster_alignment(args.mp) - 1; - - /* Allow space for the inode btree to split. */ - args.minleft = args.mp->m_in_maxlevels - 1; - if ((error = xfs_alloc_vextent(&args))) - return error; - - /* - * This request might have dirtied the transaction if the AG can - * satisfy the request, but the exact block was not available. - * If the allocation did fail, subsequent requests will relax - * the exact agbno requirement and increase the alignment - * instead. It is critical that the total size of the request - * (len + alignment + slop) does not increase from this point - * on, so reset minalignslop to ensure it is not included in - * subsequent requests. - */ - args.minalignslop = 0; - } - - if (unlikely(args.fsbno == NULLFSBLOCK)) { - /* - * Set the alignment for the allocation. - * If stripe alignment is turned on then align at stripe unit - * boundary. - * If the cluster size is smaller than a filesystem block - * then we're doing I/O for inodes in filesystem block size - * pieces, so don't need alignment anyway. - */ - isaligned = 0; - if (args.mp->m_sinoalign) { - ASSERT(!(args.mp->m_flags & XFS_MOUNT_NOALIGN)); - args.alignment = args.mp->m_dalign; - isaligned = 1; - } else - args.alignment = xfs_ialloc_cluster_alignment(args.mp); - /* - * Need to figure out where to allocate the inode blocks. - * Ideally they should be spaced out through the a.g. - * For now, just allocate blocks up front. - */ - args.agbno = be32_to_cpu(agi->agi_root); - args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); - /* - * Allocate a fixed-size extent of inodes. - */ - args.type = XFS_ALLOCTYPE_NEAR_BNO; - args.prod = 1; - /* - * Allow space for the inode btree to split. - */ - args.minleft = args.mp->m_in_maxlevels - 1; - if ((error = xfs_alloc_vextent(&args))) - return error; - } - - /* - * If stripe alignment is turned on, then try again with cluster - * alignment. - */ - if (isaligned && args.fsbno == NULLFSBLOCK) { - args.type = XFS_ALLOCTYPE_NEAR_BNO; - args.agbno = be32_to_cpu(agi->agi_root); - args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); - args.alignment = xfs_ialloc_cluster_alignment(args.mp); - if ((error = xfs_alloc_vextent(&args))) - return error; - } - - /* - * Finally, try a sparse allocation if the filesystem supports it and - * the sparse allocation length is smaller than a full chunk. - */ - if (xfs_sb_version_hassparseinodes(&args.mp->m_sb) && - args.mp->m_ialloc_min_blks < args.mp->m_ialloc_blks && - args.fsbno == NULLFSBLOCK) { -sparse_alloc: - args.type = XFS_ALLOCTYPE_NEAR_BNO; - args.agbno = be32_to_cpu(agi->agi_root); - args.fsbno = XFS_AGB_TO_FSB(args.mp, agno, args.agbno); - args.alignment = args.mp->m_sb.sb_spino_align; - args.prod = 1; - - args.minlen = args.mp->m_ialloc_min_blks; - args.maxlen = args.minlen; - - /* - * The inode record will be aligned to full chunk size. We must - * prevent sparse allocation from AG boundaries that result in - * invalid inode records, such as records that start at agbno 0 - * or extend beyond the AG. - * - * Set min agbno to the first aligned, non-zero agbno and max to - * the last aligned agbno that is at least one full chunk from - * the end of the AG. - */ - args.min_agbno = args.mp->m_sb.sb_inoalignmt; - args.max_agbno = round_down(args.mp->m_sb.sb_agblocks, - args.mp->m_sb.sb_inoalignmt) - - args.mp->m_ialloc_blks; - - error = xfs_alloc_vextent(&args); - if (error) - return error; - - newlen = args.len << args.mp->m_sb.sb_inopblog; - ASSERT(newlen <= XFS_INODES_PER_CHUNK); - allocmask = (1 << (newlen / XFS_INODES_PER_HOLEMASK_BIT)) - 1; - } - - if (args.fsbno == NULLFSBLOCK) { - *alloc = 0; - return 0; - } - ASSERT(args.len == args.minlen); - - /* - * Stamp and write the inode buffers. - * - * Seed the new inode cluster with a random generation number. This - * prevents short-term reuse of generation numbers if a chunk is - * freed and then immediately reallocated. We use random numbers - * rather than a linear progression to prevent the next generation - * number from being easily guessable. - */ - error = xfs_ialloc_inode_init(args.mp, tp, NULL, newlen, agno, - args.agbno, args.len, prandom_u32()); - - if (error) - return error; - /* - * Convert the results. - */ - newino = XFS_OFFBNO_TO_AGINO(args.mp, args.agbno, 0); - - if (xfs_inobt_issparse(~allocmask)) { - /* - * We've allocated a sparse chunk. Align the startino and mask. - */ - xfs_align_sparse_ino(args.mp, &newino, &allocmask); - - rec.ir_startino = newino; - rec.ir_holemask = ~allocmask; - rec.ir_count = newlen; - rec.ir_freecount = newlen; - rec.ir_free = XFS_INOBT_ALL_FREE; - - /* - * Insert the sparse record into the inobt and allow for a merge - * if necessary. If a merge does occur, rec is updated to the - * merged record. - */ - error = xfs_inobt_insert_sprec(args.mp, tp, agbp, XFS_BTNUM_INO, - &rec, true); - if (error == -EFSCORRUPTED) { - xfs_alert(args.mp, - "invalid sparse inode record: ino 0x%llx holemask 0x%x count %u", - XFS_AGINO_TO_INO(args.mp, agno, - rec.ir_startino), - rec.ir_holemask, rec.ir_count); - xfs_force_shutdown(args.mp, SHUTDOWN_CORRUPT_INCORE); - } - if (error) - return error; - - /* - * We can't merge the part we've just allocated as for the inobt - * due to finobt semantics. The original record may or may not - * exist independent of whether physical inodes exist in this - * sparse chunk. - * - * We must update the finobt record based on the inobt record. - * rec contains the fully merged and up to date inobt record - * from the previous call. Set merge false to replace any - * existing record with this one. - */ - if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) { - error = xfs_inobt_insert_sprec(args.mp, tp, agbp, - XFS_BTNUM_FINO, &rec, - false); - if (error) - return error; - } - } else { - /* full chunk - insert new records to both btrees */ - error = xfs_inobt_insert(args.mp, tp, agbp, newino, newlen, - XFS_BTNUM_INO); - if (error) - return error; - - if (xfs_sb_version_hasfinobt(&args.mp->m_sb)) { - error = xfs_inobt_insert(args.mp, tp, agbp, newino, - newlen, XFS_BTNUM_FINO); - if (error) - return error; - } - } - - /* - * Update AGI counts and newino. - */ - be32_add_cpu(&agi->agi_count, newlen); - be32_add_cpu(&agi->agi_freecount, newlen); - pag = xfs_perag_get(args.mp, agno); - pag->pagi_freecount += newlen; - xfs_perag_put(pag); - agi->agi_newino = cpu_to_be32(newino); - - /* - * Log allocation group header fields - */ - xfs_ialloc_log_agi(tp, agbp, - XFS_AGI_COUNT | XFS_AGI_FREECOUNT | XFS_AGI_NEWINO); - /* - * Modify/log superblock values for inode count and inode free count. - */ - xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, (long)newlen); - xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, (long)newlen); - *alloc = 1; - return 0; -} - -STATIC xfs_agnumber_t -xfs_ialloc_next_ag( - xfs_mount_t *mp) -{ - xfs_agnumber_t agno; - - spin_lock(&mp->m_agirotor_lock); - agno = mp->m_agirotor; - if (++mp->m_agirotor >= mp->m_maxagi) - mp->m_agirotor = 0; - spin_unlock(&mp->m_agirotor_lock); - - return agno; -} - -/* - * Select an allocation group to look for a free inode in, based on the parent - * inode and the mode. Return the allocation group buffer. - */ -STATIC xfs_agnumber_t -xfs_ialloc_ag_select( - xfs_trans_t *tp, /* transaction pointer */ - xfs_ino_t parent, /* parent directory inode number */ - umode_t mode, /* bits set to indicate file type */ - int okalloc) /* ok to allocate more space */ -{ - xfs_agnumber_t agcount; /* number of ag's in the filesystem */ - xfs_agnumber_t agno; /* current ag number */ - int flags; /* alloc buffer locking flags */ - xfs_extlen_t ineed; /* blocks needed for inode allocation */ - xfs_extlen_t longest = 0; /* longest extent available */ - xfs_mount_t *mp; /* mount point structure */ - int needspace; /* file mode implies space allocated */ - xfs_perag_t *pag; /* per allocation group data */ - xfs_agnumber_t pagno; /* parent (starting) ag number */ - int error; - - /* - * Files of these types need at least one block if length > 0 - * (and they won't fit in the inode, but that's hard to figure out). - */ - needspace = S_ISDIR(mode) || S_ISREG(mode) || S_ISLNK(mode); - mp = tp->t_mountp; - agcount = mp->m_maxagi; - if (S_ISDIR(mode)) - pagno = xfs_ialloc_next_ag(mp); - else { - pagno = XFS_INO_TO_AGNO(mp, parent); - if (pagno >= agcount) - pagno = 0; - } - - ASSERT(pagno < agcount); - - /* - * Loop through allocation groups, looking for one with a little - * free space in it. Note we don't look for free inodes, exactly. - * Instead, we include whether there is a need to allocate inodes - * to mean that blocks must be allocated for them, - * if none are currently free. - */ - agno = pagno; - flags = XFS_ALLOC_FLAG_TRYLOCK; - for (;;) { - pag = xfs_perag_get(mp, agno); - if (!pag->pagi_inodeok) { - xfs_ialloc_next_ag(mp); - goto nextag; - } - - if (!pag->pagi_init) { - error = xfs_ialloc_pagi_init(mp, tp, agno); - if (error) - goto nextag; - } - - if (pag->pagi_freecount) { - xfs_perag_put(pag); - return agno; - } - - if (!okalloc) - goto nextag; - - if (!pag->pagf_init) { - error = xfs_alloc_pagf_init(mp, tp, agno, flags); - if (error) - goto nextag; - } - - /* - * Check that there is enough free space for the file plus a - * chunk of inodes if we need to allocate some. If this is the - * first pass across the AGs, take into account the potential - * space needed for alignment of inode chunks when checking the - * longest contiguous free space in the AG - this prevents us - * from getting ENOSPC because we have free space larger than - * m_ialloc_blks but alignment constraints prevent us from using - * it. - * - * If we can't find an AG with space for full alignment slack to - * be taken into account, we must be near ENOSPC in all AGs. - * Hence we don't include alignment for the second pass and so - * if we fail allocation due to alignment issues then it is most - * likely a real ENOSPC condition. - */ - ineed = mp->m_ialloc_min_blks; - if (flags && ineed > 1) - ineed += xfs_ialloc_cluster_alignment(mp); - longest = pag->pagf_longest; - if (!longest) - longest = pag->pagf_flcount > 0; - - if (pag->pagf_freeblks >= needspace + ineed && - longest >= ineed) { - xfs_perag_put(pag); - return agno; - } -nextag: - xfs_perag_put(pag); - /* - * No point in iterating over the rest, if we're shutting - * down. - */ - if (XFS_FORCED_SHUTDOWN(mp)) - return NULLAGNUMBER; - agno++; - if (agno >= agcount) - agno = 0; - if (agno == pagno) { - if (flags == 0) - return NULLAGNUMBER; - flags = 0; - } - } -} - -/* - * Try to retrieve the next record to the left/right from the current one. - */ -STATIC int -xfs_ialloc_next_rec( - struct xfs_btree_cur *cur, - xfs_inobt_rec_incore_t *rec, - int *done, - int left) -{ - int error; - int i; - - if (left) - error = xfs_btree_decrement(cur, 0, &i); - else - error = xfs_btree_increment(cur, 0, &i); - - if (error) - return error; - *done = !i; - if (i) { - error = xfs_inobt_get_rec(cur, rec, &i); - if (error) - return error; - XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); - } - - return 0; -} - -STATIC int -xfs_ialloc_get_rec( - struct xfs_btree_cur *cur, - xfs_agino_t agino, - xfs_inobt_rec_incore_t *rec, - int *done) -{ - int error; - int i; - - error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_EQ, &i); - if (error) - return error; - *done = !i; - if (i) { - error = xfs_inobt_get_rec(cur, rec, &i); - if (error) - return error; - XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); - } - - return 0; -} - -/* - * Return the offset of the first free inode in the record. If the inode chunk - * is sparsely allocated, we convert the record holemask to inode granularity - * and mask off the unallocated regions from the inode free mask. - */ -STATIC int -xfs_inobt_first_free_inode( - struct xfs_inobt_rec_incore *rec) -{ - xfs_inofree_t realfree; - - /* if there are no holes, return the first available offset */ - if (!xfs_inobt_issparse(rec->ir_holemask)) - return xfs_lowbit64(rec->ir_free); - - realfree = xfs_inobt_irec_to_allocmask(rec); - realfree &= rec->ir_free; - - return xfs_lowbit64(realfree); -} - -/* - * Allocate an inode using the inobt-only algorithm. - */ -STATIC int -xfs_dialloc_ag_inobt( - struct xfs_trans *tp, - struct xfs_buf *agbp, - xfs_ino_t parent, - xfs_ino_t *inop) -{ - struct xfs_mount *mp = tp->t_mountp; - struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); - xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); - xfs_agnumber_t pagno = XFS_INO_TO_AGNO(mp, parent); - xfs_agino_t pagino = XFS_INO_TO_AGINO(mp, parent); - struct xfs_perag *pag; - struct xfs_btree_cur *cur, *tcur; - struct xfs_inobt_rec_incore rec, trec; - xfs_ino_t ino; - int error; - int offset; - int i, j; - - pag = xfs_perag_get(mp, agno); - - ASSERT(pag->pagi_init); - ASSERT(pag->pagi_inodeok); - ASSERT(pag->pagi_freecount > 0); - - restart_pagno: - cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); - /* - * If pagino is 0 (this is the root inode allocation) use newino. - * This must work because we've just allocated some. - */ - if (!pagino) - pagino = be32_to_cpu(agi->agi_newino); - - error = xfs_check_agi_freecount(cur, agi); - if (error) - goto error0; - - /* - * If in the same AG as the parent, try to get near the parent. - */ - if (pagno == agno) { - int doneleft; /* done, to the left */ - int doneright; /* done, to the right */ - int searchdistance = 10; - - error = xfs_inobt_lookup(cur, pagino, XFS_LOOKUP_LE, &i); - if (error) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - - error = xfs_inobt_get_rec(cur, &rec, &j); - if (error) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, j == 1, error0); - - if (rec.ir_freecount > 0) { - /* - * Found a free inode in the same chunk - * as the parent, done. - */ - goto alloc_inode; - } - - - /* - * In the same AG as parent, but parent's chunk is full. - */ - - /* duplicate the cursor, search left & right simultaneously */ - error = xfs_btree_dup_cursor(cur, &tcur); - if (error) - goto error0; - - /* - * Skip to last blocks looked up if same parent inode. - */ - if (pagino != NULLAGINO && - pag->pagl_pagino == pagino && - pag->pagl_leftrec != NULLAGINO && - pag->pagl_rightrec != NULLAGINO) { - error = xfs_ialloc_get_rec(tcur, pag->pagl_leftrec, - &trec, &doneleft); - if (error) - goto error1; - - error = xfs_ialloc_get_rec(cur, pag->pagl_rightrec, - &rec, &doneright); - if (error) - goto error1; - } else { - /* search left with tcur, back up 1 record */ - error = xfs_ialloc_next_rec(tcur, &trec, &doneleft, 1); - if (error) - goto error1; - - /* search right with cur, go forward 1 record. */ - error = xfs_ialloc_next_rec(cur, &rec, &doneright, 0); - if (error) - goto error1; - } - - /* - * Loop until we find an inode chunk with a free inode. - */ - while (!doneleft || !doneright) { - int useleft; /* using left inode chunk this time */ - - if (!--searchdistance) { - /* - * Not in range - save last search - * location and allocate a new inode - */ - xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); - pag->pagl_leftrec = trec.ir_startino; - pag->pagl_rightrec = rec.ir_startino; - pag->pagl_pagino = pagino; - goto newino; - } - - /* figure out the closer block if both are valid. */ - if (!doneleft && !doneright) { - useleft = pagino - - (trec.ir_startino + XFS_INODES_PER_CHUNK - 1) < - rec.ir_startino - pagino; - } else { - useleft = !doneleft; - } - - /* free inodes to the left? */ - if (useleft && trec.ir_freecount) { - rec = trec; - xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); - cur = tcur; - - pag->pagl_leftrec = trec.ir_startino; - pag->pagl_rightrec = rec.ir_startino; - pag->pagl_pagino = pagino; - goto alloc_inode; - } - - /* free inodes to the right? */ - if (!useleft && rec.ir_freecount) { - xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); - - pag->pagl_leftrec = trec.ir_startino; - pag->pagl_rightrec = rec.ir_startino; - pag->pagl_pagino = pagino; - goto alloc_inode; - } - - /* get next record to check */ - if (useleft) { - error = xfs_ialloc_next_rec(tcur, &trec, - &doneleft, 1); - } else { - error = xfs_ialloc_next_rec(cur, &rec, - &doneright, 0); - } - if (error) - goto error1; - } - - /* - * We've reached the end of the btree. because - * we are only searching a small chunk of the - * btree each search, there is obviously free - * inodes closer to the parent inode than we - * are now. restart the search again. - */ - pag->pagl_pagino = NULLAGINO; - pag->pagl_leftrec = NULLAGINO; - pag->pagl_rightrec = NULLAGINO; - xfs_btree_del_cursor(tcur, XFS_BTREE_NOERROR); - xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); - goto restart_pagno; - } - - /* - * In a different AG from the parent. - * See if the most recently allocated block has any free. - */ -newino: - if (agi->agi_newino != cpu_to_be32(NULLAGINO)) { - error = xfs_inobt_lookup(cur, be32_to_cpu(agi->agi_newino), - XFS_LOOKUP_EQ, &i); - if (error) - goto error0; - - if (i == 1) { - error = xfs_inobt_get_rec(cur, &rec, &j); - if (error) - goto error0; - - if (j == 1 && rec.ir_freecount > 0) { - /* - * The last chunk allocated in the group - * still has a free inode. - */ - goto alloc_inode; - } - } - } - - /* - * None left in the last group, search the whole AG - */ - error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i); - if (error) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - - for (;;) { - error = xfs_inobt_get_rec(cur, &rec, &i); - if (error) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - if (rec.ir_freecount > 0) - break; - error = xfs_btree_increment(cur, 0, &i); - if (error) - goto error0; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - } - -alloc_inode: - offset = xfs_inobt_first_free_inode(&rec); - ASSERT(offset >= 0); - ASSERT(offset < XFS_INODES_PER_CHUNK); - ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) % - XFS_INODES_PER_CHUNK) == 0); - ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset); - rec.ir_free &= ~XFS_INOBT_MASK(offset); - rec.ir_freecount--; - error = xfs_inobt_update(cur, &rec); - if (error) - goto error0; - be32_add_cpu(&agi->agi_freecount, -1); - xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); - pag->pagi_freecount--; - - error = xfs_check_agi_freecount(cur, agi); - if (error) - goto error0; - - xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); - xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1); - xfs_perag_put(pag); - *inop = ino; - return 0; -error1: - xfs_btree_del_cursor(tcur, XFS_BTREE_ERROR); -error0: - xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); - xfs_perag_put(pag); - return error; -} - -/* - * Use the free inode btree to allocate an inode based on distance from the - * parent. Note that the provided cursor may be deleted and replaced. - */ -STATIC int -xfs_dialloc_ag_finobt_near( - xfs_agino_t pagino, - struct xfs_btree_cur **ocur, - struct xfs_inobt_rec_incore *rec) -{ - struct xfs_btree_cur *lcur = *ocur; /* left search cursor */ - struct xfs_btree_cur *rcur; /* right search cursor */ - struct xfs_inobt_rec_incore rrec; - int error; - int i, j; - - error = xfs_inobt_lookup(lcur, pagino, XFS_LOOKUP_LE, &i); - if (error) - return error; - - if (i == 1) { - error = xfs_inobt_get_rec(lcur, rec, &i); - if (error) - return error; - XFS_WANT_CORRUPTED_RETURN(lcur->bc_mp, i == 1); - - /* - * See if we've landed in the parent inode record. The finobt - * only tracks chunks with at least one free inode, so record - * existence is enough. - */ - if (pagino >= rec->ir_startino && - pagino < (rec->ir_startino + XFS_INODES_PER_CHUNK)) - return 0; - } - - error = xfs_btree_dup_cursor(lcur, &rcur); - if (error) - return error; - - error = xfs_inobt_lookup(rcur, pagino, XFS_LOOKUP_GE, &j); - if (error) - goto error_rcur; - if (j == 1) { - error = xfs_inobt_get_rec(rcur, &rrec, &j); - if (error) - goto error_rcur; - XFS_WANT_CORRUPTED_GOTO(lcur->bc_mp, j == 1, error_rcur); - } - - XFS_WANT_CORRUPTED_GOTO(lcur->bc_mp, i == 1 || j == 1, error_rcur); - if (i == 1 && j == 1) { - /* - * Both the left and right records are valid. Choose the closer - * inode chunk to the target. - */ - if ((pagino - rec->ir_startino + XFS_INODES_PER_CHUNK - 1) > - (rrec.ir_startino - pagino)) { - *rec = rrec; - xfs_btree_del_cursor(lcur, XFS_BTREE_NOERROR); - *ocur = rcur; - } else { - xfs_btree_del_cursor(rcur, XFS_BTREE_NOERROR); - } - } else if (j == 1) { - /* only the right record is valid */ - *rec = rrec; - xfs_btree_del_cursor(lcur, XFS_BTREE_NOERROR); - *ocur = rcur; - } else if (i == 1) { - /* only the left record is valid */ - xfs_btree_del_cursor(rcur, XFS_BTREE_NOERROR); - } - - return 0; - -error_rcur: - xfs_btree_del_cursor(rcur, XFS_BTREE_ERROR); - return error; -} - -/* - * Use the free inode btree to find a free inode based on a newino hint. If - * the hint is NULL, find the first free inode in the AG. - */ -STATIC int -xfs_dialloc_ag_finobt_newino( - struct xfs_agi *agi, - struct xfs_btree_cur *cur, - struct xfs_inobt_rec_incore *rec) -{ - int error; - int i; - - if (agi->agi_newino != cpu_to_be32(NULLAGINO)) { - error = xfs_inobt_lookup(cur, be32_to_cpu(agi->agi_newino), - XFS_LOOKUP_EQ, &i); - if (error) - return error; - if (i == 1) { - error = xfs_inobt_get_rec(cur, rec, &i); - if (error) - return error; - XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); - return 0; - } - } - - /* - * Find the first inode available in the AG. - */ - error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &i); - if (error) - return error; - XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); - - error = xfs_inobt_get_rec(cur, rec, &i); - if (error) - return error; - XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); - - return 0; -} - -/* - * Update the inobt based on a modification made to the finobt. Also ensure that - * the records from both trees are equivalent post-modification. - */ -STATIC int -xfs_dialloc_ag_update_inobt( - struct xfs_btree_cur *cur, /* inobt cursor */ - struct xfs_inobt_rec_incore *frec, /* finobt record */ - int offset) /* inode offset */ -{ - struct xfs_inobt_rec_incore rec; - int error; - int i; - - error = xfs_inobt_lookup(cur, frec->ir_startino, XFS_LOOKUP_EQ, &i); - if (error) - return error; - XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); - - error = xfs_inobt_get_rec(cur, &rec, &i); - if (error) - return error; - XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, i == 1); - ASSERT((XFS_AGINO_TO_OFFSET(cur->bc_mp, rec.ir_startino) % - XFS_INODES_PER_CHUNK) == 0); - - rec.ir_free &= ~XFS_INOBT_MASK(offset); - rec.ir_freecount--; - - XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, (rec.ir_free == frec->ir_free) && - (rec.ir_freecount == frec->ir_freecount)); - - return xfs_inobt_update(cur, &rec); -} - -/* - * Allocate an inode using the free inode btree, if available. Otherwise, fall - * back to the inobt search algorithm. - * - * The caller selected an AG for us, and made sure that free inodes are - * available. - */ -STATIC int -xfs_dialloc_ag( - struct xfs_trans *tp, - struct xfs_buf *agbp, - xfs_ino_t parent, - xfs_ino_t *inop) -{ - struct xfs_mount *mp = tp->t_mountp; - struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); - xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); - xfs_agnumber_t pagno = XFS_INO_TO_AGNO(mp, parent); - xfs_agino_t pagino = XFS_INO_TO_AGINO(mp, parent); - struct xfs_perag *pag; - struct xfs_btree_cur *cur; /* finobt cursor */ - struct xfs_btree_cur *icur; /* inobt cursor */ - struct xfs_inobt_rec_incore rec; - xfs_ino_t ino; - int error; - int offset; - int i; - - if (!xfs_sb_version_hasfinobt(&mp->m_sb)) - return xfs_dialloc_ag_inobt(tp, agbp, parent, inop); - - pag = xfs_perag_get(mp, agno); - - /* - * If pagino is 0 (this is the root inode allocation) use newino. - * This must work because we've just allocated some. - */ - if (!pagino) - pagino = be32_to_cpu(agi->agi_newino); - - cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO); - - error = xfs_check_agi_freecount(cur, agi); - if (error) - goto error_cur; - - /* - * The search algorithm depends on whether we're in the same AG as the - * parent. If so, find the closest available inode to the parent. If - * not, consider the agi hint or find the first free inode in the AG. - */ - if (agno == pagno) - error = xfs_dialloc_ag_finobt_near(pagino, &cur, &rec); - else - error = xfs_dialloc_ag_finobt_newino(agi, cur, &rec); - if (error) - goto error_cur; - - offset = xfs_inobt_first_free_inode(&rec); - ASSERT(offset >= 0); - ASSERT(offset < XFS_INODES_PER_CHUNK); - ASSERT((XFS_AGINO_TO_OFFSET(mp, rec.ir_startino) % - XFS_INODES_PER_CHUNK) == 0); - ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino + offset); - - /* - * Modify or remove the finobt record. - */ - rec.ir_free &= ~XFS_INOBT_MASK(offset); - rec.ir_freecount--; - if (rec.ir_freecount) - error = xfs_inobt_update(cur, &rec); - else - error = xfs_btree_delete(cur, &i); - if (error) - goto error_cur; - - /* - * The finobt has now been updated appropriately. We haven't updated the - * agi and superblock yet, so we can create an inobt cursor and validate - * the original freecount. If all is well, make the equivalent update to - * the inobt using the finobt record and offset information. - */ - icur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); - - error = xfs_check_agi_freecount(icur, agi); - if (error) - goto error_icur; - - error = xfs_dialloc_ag_update_inobt(icur, &rec, offset); - if (error) - goto error_icur; - - /* - * Both trees have now been updated. We must update the perag and - * superblock before we can check the freecount for each btree. - */ - be32_add_cpu(&agi->agi_freecount, -1); - xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); - pag->pagi_freecount--; - - xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -1); - - error = xfs_check_agi_freecount(icur, agi); - if (error) - goto error_icur; - error = xfs_check_agi_freecount(cur, agi); - if (error) - goto error_icur; - - xfs_btree_del_cursor(icur, XFS_BTREE_NOERROR); - xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); - xfs_perag_put(pag); - *inop = ino; - return 0; - -error_icur: - xfs_btree_del_cursor(icur, XFS_BTREE_ERROR); -error_cur: - xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); - xfs_perag_put(pag); - return error; -} - -/* - * Allocate an inode on disk. - * - * Mode is used to tell whether the new inode will need space, and whether it - * is a directory. - * - * This function is designed to be called twice if it has to do an allocation - * to make more free inodes. On the first call, *IO_agbp should be set to NULL. - * If an inode is available without having to performn an allocation, an inode - * number is returned. In this case, *IO_agbp is set to NULL. If an allocation - * needs to be done, xfs_dialloc returns the current AGI buffer in *IO_agbp. - * The caller should then commit the current transaction, allocate a - * new transaction, and call xfs_dialloc() again, passing in the previous value - * of *IO_agbp. IO_agbp should be held across the transactions. Since the AGI - * buffer is locked across the two calls, the second call is guaranteed to have - * a free inode available. - * - * Once we successfully pick an inode its number is returned and the on-disk - * data structures are updated. The inode itself is not read in, since doing so - * would break ordering constraints with xfs_reclaim. - */ -int -xfs_dialloc( - struct xfs_trans *tp, - xfs_ino_t parent, - umode_t mode, - int okalloc, - struct xfs_buf **IO_agbp, - xfs_ino_t *inop) -{ - struct xfs_mount *mp = tp->t_mountp; - struct xfs_buf *agbp; - xfs_agnumber_t agno; - int error; - int ialloced; - int noroom = 0; - xfs_agnumber_t start_agno; - struct xfs_perag *pag; - - if (*IO_agbp) { - /* - * If the caller passes in a pointer to the AGI buffer, - * continue where we left off before. In this case, we - * know that the allocation group has free inodes. - */ - agbp = *IO_agbp; - goto out_alloc; - } - - /* - * We do not have an agbp, so select an initial allocation - * group for inode allocation. - */ - start_agno = xfs_ialloc_ag_select(tp, parent, mode, okalloc); - if (start_agno == NULLAGNUMBER) { - *inop = NULLFSINO; - return 0; - } - - /* - * If we have already hit the ceiling of inode blocks then clear - * okalloc so we scan all available agi structures for a free - * inode. - * - * Read rough value of mp->m_icount by percpu_counter_read_positive, - * which will sacrifice the preciseness but improve the performance. - */ - if (mp->m_maxicount && - percpu_counter_read_positive(&mp->m_icount) + mp->m_ialloc_inos - > mp->m_maxicount) { - noroom = 1; - okalloc = 0; - } - - /* - * Loop until we find an allocation group that either has free inodes - * or in which we can allocate some inodes. Iterate through the - * allocation groups upward, wrapping at the end. - */ - agno = start_agno; - for (;;) { - pag = xfs_perag_get(mp, agno); - if (!pag->pagi_inodeok) { - xfs_ialloc_next_ag(mp); - goto nextag; - } - - if (!pag->pagi_init) { - error = xfs_ialloc_pagi_init(mp, tp, agno); - if (error) - goto out_error; - } - - /* - * Do a first racy fast path check if this AG is usable. - */ - if (!pag->pagi_freecount && !okalloc) - goto nextag; - - /* - * Then read in the AGI buffer and recheck with the AGI buffer - * lock held. - */ - error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); - if (error) - goto out_error; - - if (pag->pagi_freecount) { - xfs_perag_put(pag); - goto out_alloc; - } - - if (!okalloc) - goto nextag_relse_buffer; - - - error = xfs_ialloc_ag_alloc(tp, agbp, &ialloced); - if (error) { - xfs_trans_brelse(tp, agbp); - - if (error != -ENOSPC) - goto out_error; - - xfs_perag_put(pag); - *inop = NULLFSINO; - return 0; - } - - if (ialloced) { - /* - * We successfully allocated some inodes, return - * the current context to the caller so that it - * can commit the current transaction and call - * us again where we left off. - */ - ASSERT(pag->pagi_freecount > 0); - xfs_perag_put(pag); - - *IO_agbp = agbp; - *inop = NULLFSINO; - return 0; - } - -nextag_relse_buffer: - xfs_trans_brelse(tp, agbp); -nextag: - xfs_perag_put(pag); - if (++agno == mp->m_sb.sb_agcount) - agno = 0; - if (agno == start_agno) { - *inop = NULLFSINO; - return noroom ? -ENOSPC : 0; - } - } - -out_alloc: - *IO_agbp = NULL; - return xfs_dialloc_ag(tp, agbp, parent, inop); -out_error: - xfs_perag_put(pag); - return error; -} - -/* - * Free the blocks of an inode chunk. We must consider that the inode chunk - * might be sparse and only free the regions that are allocated as part of the - * chunk. - */ -STATIC void -xfs_difree_inode_chunk( - struct xfs_mount *mp, - xfs_agnumber_t agno, - struct xfs_inobt_rec_incore *rec, - struct xfs_defer_ops *dfops) -{ - xfs_agblock_t sagbno = XFS_AGINO_TO_AGBNO(mp, rec->ir_startino); - int startidx, endidx; - int nextbit; - xfs_agblock_t agbno; - int contigblk; - struct xfs_owner_info oinfo; - DECLARE_BITMAP(holemask, XFS_INOBT_HOLEMASK_BITS); - xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_INODES); - - if (!xfs_inobt_issparse(rec->ir_holemask)) { - /* not sparse, calculate extent info directly */ - xfs_bmap_add_free(mp, dfops, XFS_AGB_TO_FSB(mp, agno, sagbno), - mp->m_ialloc_blks, &oinfo); - return; - } - - /* holemask is only 16-bits (fits in an unsigned long) */ - ASSERT(sizeof(rec->ir_holemask) <= sizeof(holemask[0])); - holemask[0] = rec->ir_holemask; - - /* - * Find contiguous ranges of zeroes (i.e., allocated regions) in the - * holemask and convert the start/end index of each range to an extent. - * We start with the start and end index both pointing at the first 0 in - * the mask. - */ - startidx = endidx = find_first_zero_bit(holemask, - XFS_INOBT_HOLEMASK_BITS); - nextbit = startidx + 1; - while (startidx < XFS_INOBT_HOLEMASK_BITS) { - nextbit = find_next_zero_bit(holemask, XFS_INOBT_HOLEMASK_BITS, - nextbit); - /* - * If the next zero bit is contiguous, update the end index of - * the current range and continue. - */ - if (nextbit != XFS_INOBT_HOLEMASK_BITS && - nextbit == endidx + 1) { - endidx = nextbit; - goto next; - } - - /* - * nextbit is not contiguous with the current end index. Convert - * the current start/end to an extent and add it to the free - * list. - */ - agbno = sagbno + (startidx * XFS_INODES_PER_HOLEMASK_BIT) / - mp->m_sb.sb_inopblock; - contigblk = ((endidx - startidx + 1) * - XFS_INODES_PER_HOLEMASK_BIT) / - mp->m_sb.sb_inopblock; - - ASSERT(agbno % mp->m_sb.sb_spino_align == 0); - ASSERT(contigblk % mp->m_sb.sb_spino_align == 0); - xfs_bmap_add_free(mp, dfops, XFS_AGB_TO_FSB(mp, agno, agbno), - contigblk, &oinfo); - - /* reset range to current bit and carry on... */ - startidx = endidx = nextbit; - -next: - nextbit++; - } -} - -STATIC int -xfs_difree_inobt( - struct xfs_mount *mp, - struct xfs_trans *tp, - struct xfs_buf *agbp, - xfs_agino_t agino, - struct xfs_defer_ops *dfops, - struct xfs_icluster *xic, - struct xfs_inobt_rec_incore *orec) -{ - struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); - xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); - struct xfs_perag *pag; - struct xfs_btree_cur *cur; - struct xfs_inobt_rec_incore rec; - int ilen; - int error; - int i; - int off; - - ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC)); - ASSERT(XFS_AGINO_TO_AGBNO(mp, agino) < be32_to_cpu(agi->agi_length)); - - /* - * Initialize the cursor. - */ - cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); - - error = xfs_check_agi_freecount(cur, agi); - if (error) - goto error0; - - /* - * Look for the entry describing this inode. - */ - if ((error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i))) { - xfs_warn(mp, "%s: xfs_inobt_lookup() returned error %d.", - __func__, error); - goto error0; - } - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - error = xfs_inobt_get_rec(cur, &rec, &i); - if (error) { - xfs_warn(mp, "%s: xfs_inobt_get_rec() returned error %d.", - __func__, error); - goto error0; - } - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error0); - /* - * Get the offset in the inode chunk. - */ - off = agino - rec.ir_startino; - ASSERT(off >= 0 && off < XFS_INODES_PER_CHUNK); - ASSERT(!(rec.ir_free & XFS_INOBT_MASK(off))); - /* - * Mark the inode free & increment the count. - */ - rec.ir_free |= XFS_INOBT_MASK(off); - rec.ir_freecount++; - - /* - * When an inode chunk is free, it becomes eligible for removal. Don't - * remove the chunk if the block size is large enough for multiple inode - * chunks (that might not be free). - */ - if (!(mp->m_flags & XFS_MOUNT_IKEEP) && - rec.ir_free == XFS_INOBT_ALL_FREE && - mp->m_sb.sb_inopblock <= XFS_INODES_PER_CHUNK) { - xic->deleted = 1; - xic->first_ino = XFS_AGINO_TO_INO(mp, agno, rec.ir_startino); - xic->alloc = xfs_inobt_irec_to_allocmask(&rec); - - /* - * Remove the inode cluster from the AGI B+Tree, adjust the - * AGI and Superblock inode counts, and mark the disk space - * to be freed when the transaction is committed. - */ - ilen = rec.ir_freecount; - be32_add_cpu(&agi->agi_count, -ilen); - be32_add_cpu(&agi->agi_freecount, -(ilen - 1)); - xfs_ialloc_log_agi(tp, agbp, XFS_AGI_COUNT | XFS_AGI_FREECOUNT); - pag = xfs_perag_get(mp, agno); - pag->pagi_freecount -= ilen - 1; - xfs_perag_put(pag); - xfs_trans_mod_sb(tp, XFS_TRANS_SB_ICOUNT, -ilen); - xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, -(ilen - 1)); - - if ((error = xfs_btree_delete(cur, &i))) { - xfs_warn(mp, "%s: xfs_btree_delete returned error %d.", - __func__, error); - goto error0; - } - - xfs_difree_inode_chunk(mp, agno, &rec, dfops); - } else { - xic->deleted = 0; - - error = xfs_inobt_update(cur, &rec); - if (error) { - xfs_warn(mp, "%s: xfs_inobt_update returned error %d.", - __func__, error); - goto error0; - } - - /* - * Change the inode free counts and log the ag/sb changes. - */ - be32_add_cpu(&agi->agi_freecount, 1); - xfs_ialloc_log_agi(tp, agbp, XFS_AGI_FREECOUNT); - pag = xfs_perag_get(mp, agno); - pag->pagi_freecount++; - xfs_perag_put(pag); - xfs_trans_mod_sb(tp, XFS_TRANS_SB_IFREE, 1); - } - - error = xfs_check_agi_freecount(cur, agi); - if (error) - goto error0; - - *orec = rec; - xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); - return 0; - -error0: - xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); - return error; -} - -/* - * Free an inode in the free inode btree. - */ -STATIC int -xfs_difree_finobt( - struct xfs_mount *mp, - struct xfs_trans *tp, - struct xfs_buf *agbp, - xfs_agino_t agino, - struct xfs_inobt_rec_incore *ibtrec) /* inobt record */ -{ - struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); - xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno); - struct xfs_btree_cur *cur; - struct xfs_inobt_rec_incore rec; - int offset = agino - ibtrec->ir_startino; - int error; - int i; - - cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO); - - error = xfs_inobt_lookup(cur, ibtrec->ir_startino, XFS_LOOKUP_EQ, &i); - if (error) - goto error; - if (i == 0) { - /* - * If the record does not exist in the finobt, we must have just - * freed an inode in a previously fully allocated chunk. If not, - * something is out of sync. - */ - XFS_WANT_CORRUPTED_GOTO(mp, ibtrec->ir_freecount == 1, error); - - error = xfs_inobt_insert_rec(cur, ibtrec->ir_holemask, - ibtrec->ir_count, - ibtrec->ir_freecount, - ibtrec->ir_free, &i); - if (error) - goto error; - ASSERT(i == 1); - - goto out; - } - - /* - * Read and update the existing record. We could just copy the ibtrec - * across here, but that would defeat the purpose of having redundant - * metadata. By making the modifications independently, we can catch - * corruptions that we wouldn't see if we just copied from one record - * to another. - */ - error = xfs_inobt_get_rec(cur, &rec, &i); - if (error) - goto error; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, error); - - rec.ir_free |= XFS_INOBT_MASK(offset); - rec.ir_freecount++; - - XFS_WANT_CORRUPTED_GOTO(mp, (rec.ir_free == ibtrec->ir_free) && - (rec.ir_freecount == ibtrec->ir_freecount), - error); - - /* - * The content of inobt records should always match between the inobt - * and finobt. The lifecycle of records in the finobt is different from - * the inobt in that the finobt only tracks records with at least one - * free inode. Hence, if all of the inodes are free and we aren't - * keeping inode chunks permanently on disk, remove the record. - * Otherwise, update the record with the new information. - * - * Note that we currently can't free chunks when the block size is large - * enough for multiple chunks. Leave the finobt record to remain in sync - * with the inobt. - */ - if (rec.ir_free == XFS_INOBT_ALL_FREE && - mp->m_sb.sb_inopblock <= XFS_INODES_PER_CHUNK && - !(mp->m_flags & XFS_MOUNT_IKEEP)) { - error = xfs_btree_delete(cur, &i); - if (error) - goto error; - ASSERT(i == 1); - } else { - error = xfs_inobt_update(cur, &rec); - if (error) - goto error; - } - -out: - error = xfs_check_agi_freecount(cur, agi); - if (error) - goto error; - - xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); - return 0; - -error: - xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); - return error; -} - -/* - * Free disk inode. Carefully avoids touching the incore inode, all - * manipulations incore are the caller's responsibility. - * The on-disk inode is not changed by this operation, only the - * btree (free inode mask) is changed. - */ -int -xfs_difree( - struct xfs_trans *tp, /* transaction pointer */ - xfs_ino_t inode, /* inode to be freed */ - struct xfs_defer_ops *dfops, /* extents to free */ - struct xfs_icluster *xic) /* cluster info if deleted */ -{ - /* REFERENCED */ - xfs_agblock_t agbno; /* block number containing inode */ - struct xfs_buf *agbp; /* buffer for allocation group header */ - xfs_agino_t agino; /* allocation group inode number */ - xfs_agnumber_t agno; /* allocation group number */ - int error; /* error return value */ - struct xfs_mount *mp; /* mount structure for filesystem */ - struct xfs_inobt_rec_incore rec;/* btree record */ - - mp = tp->t_mountp; - - /* - * Break up inode number into its components. - */ - agno = XFS_INO_TO_AGNO(mp, inode); - if (agno >= mp->m_sb.sb_agcount) { - xfs_warn(mp, "%s: agno >= mp->m_sb.sb_agcount (%d >= %d).", - __func__, agno, mp->m_sb.sb_agcount); - ASSERT(0); - return -EINVAL; - } - agino = XFS_INO_TO_AGINO(mp, inode); - if (inode != XFS_AGINO_TO_INO(mp, agno, agino)) { - xfs_warn(mp, "%s: inode != XFS_AGINO_TO_INO() (%llu != %llu).", - __func__, (unsigned long long)inode, - (unsigned long long)XFS_AGINO_TO_INO(mp, agno, agino)); - ASSERT(0); - return -EINVAL; - } - agbno = XFS_AGINO_TO_AGBNO(mp, agino); - if (agbno >= mp->m_sb.sb_agblocks) { - xfs_warn(mp, "%s: agbno >= mp->m_sb.sb_agblocks (%d >= %d).", - __func__, agbno, mp->m_sb.sb_agblocks); - ASSERT(0); - return -EINVAL; - } - /* - * Get the allocation group header. - */ - error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); - if (error) { - xfs_warn(mp, "%s: xfs_ialloc_read_agi() returned error %d.", - __func__, error); - return error; - } - - /* - * Fix up the inode allocation btree. - */ - error = xfs_difree_inobt(mp, tp, agbp, agino, dfops, xic, &rec); - if (error) - goto error0; - - /* - * Fix up the free inode btree. - */ - if (xfs_sb_version_hasfinobt(&mp->m_sb)) { - error = xfs_difree_finobt(mp, tp, agbp, agino, &rec); - if (error) - goto error0; - } - - return 0; - -error0: - return error; -} - -STATIC int -xfs_imap_lookup( - struct xfs_mount *mp, - struct xfs_trans *tp, - xfs_agnumber_t agno, - xfs_agino_t agino, - xfs_agblock_t agbno, - xfs_agblock_t *chunk_agbno, - xfs_agblock_t *offset_agbno, - int flags) -{ - struct xfs_inobt_rec_incore rec; - struct xfs_btree_cur *cur; - struct xfs_buf *agbp; - int error; - int i; - - error = xfs_ialloc_read_agi(mp, tp, agno, &agbp); - if (error) { - xfs_alert(mp, - "%s: xfs_ialloc_read_agi() returned error %d, agno %d", - __func__, error, agno); - return error; - } - - /* - * Lookup the inode record for the given agino. If the record cannot be - * found, then it's an invalid inode number and we should abort. Once - * we have a record, we need to ensure it contains the inode number - * we are looking up. - */ - cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_INO); - error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &i); - if (!error) { - if (i) - error = xfs_inobt_get_rec(cur, &rec, &i); - if (!error && i == 0) - error = -EINVAL; - } - - xfs_trans_brelse(tp, agbp); - xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); - if (error) - return error; - - /* check that the returned record contains the required inode */ - if (rec.ir_startino > agino || - rec.ir_startino + mp->m_ialloc_inos <= agino) - return -EINVAL; - - /* for untrusted inodes check it is allocated first */ - if ((flags & XFS_IGET_UNTRUSTED) && - (rec.ir_free & XFS_INOBT_MASK(agino - rec.ir_startino))) - return -EINVAL; - - *chunk_agbno = XFS_AGINO_TO_AGBNO(mp, rec.ir_startino); - *offset_agbno = agbno - *chunk_agbno; - return 0; -} - -/* - * Return the location of the inode in imap, for mapping it into a buffer. - */ -int -xfs_imap( - xfs_mount_t *mp, /* file system mount structure */ - xfs_trans_t *tp, /* transaction pointer */ - xfs_ino_t ino, /* inode to locate */ - struct xfs_imap *imap, /* location map structure */ - uint flags) /* flags for inode btree lookup */ -{ - xfs_agblock_t agbno; /* block number of inode in the alloc group */ - xfs_agino_t agino; /* inode number within alloc group */ - xfs_agnumber_t agno; /* allocation group number */ - int blks_per_cluster; /* num blocks per inode cluster */ - xfs_agblock_t chunk_agbno; /* first block in inode chunk */ - xfs_agblock_t cluster_agbno; /* first block in inode cluster */ - int error; /* error code */ - int offset; /* index of inode in its buffer */ - xfs_agblock_t offset_agbno; /* blks from chunk start to inode */ - - ASSERT(ino != NULLFSINO); - - /* - * Split up the inode number into its parts. - */ - agno = XFS_INO_TO_AGNO(mp, ino); - agino = XFS_INO_TO_AGINO(mp, ino); - agbno = XFS_AGINO_TO_AGBNO(mp, agino); - if (agno >= mp->m_sb.sb_agcount || agbno >= mp->m_sb.sb_agblocks || - ino != XFS_AGINO_TO_INO(mp, agno, agino)) { -#ifdef DEBUG - /* - * Don't output diagnostic information for untrusted inodes - * as they can be invalid without implying corruption. - */ - if (flags & XFS_IGET_UNTRUSTED) - return -EINVAL; - if (agno >= mp->m_sb.sb_agcount) { - xfs_alert(mp, - "%s: agno (%d) >= mp->m_sb.sb_agcount (%d)", - __func__, agno, mp->m_sb.sb_agcount); - } - if (agbno >= mp->m_sb.sb_agblocks) { - xfs_alert(mp, - "%s: agbno (0x%llx) >= mp->m_sb.sb_agblocks (0x%lx)", - __func__, (unsigned long long)agbno, - (unsigned long)mp->m_sb.sb_agblocks); - } - if (ino != XFS_AGINO_TO_INO(mp, agno, agino)) { - xfs_alert(mp, - "%s: ino (0x%llx) != XFS_AGINO_TO_INO() (0x%llx)", - __func__, ino, - XFS_AGINO_TO_INO(mp, agno, agino)); - } - xfs_stack_trace(); -#endif /* DEBUG */ - return -EINVAL; - } - - blks_per_cluster = xfs_icluster_size_fsb(mp); - - /* - * For bulkstat and handle lookups, we have an untrusted inode number - * that we have to verify is valid. We cannot do this just by reading - * the inode buffer as it may have been unlinked and removed leaving - * inodes in stale state on disk. Hence we have to do a btree lookup - * in all cases where an untrusted inode number is passed. - */ - if (flags & XFS_IGET_UNTRUSTED) { - error = xfs_imap_lookup(mp, tp, agno, agino, agbno, - &chunk_agbno, &offset_agbno, flags); - if (error) - return error; - goto out_map; - } - - /* - * If the inode cluster size is the same as the blocksize or - * smaller we get to the buffer by simple arithmetics. - */ - if (blks_per_cluster == 1) { - offset = XFS_INO_TO_OFFSET(mp, ino); - ASSERT(offset < mp->m_sb.sb_inopblock); - - imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, agbno); - imap->im_len = XFS_FSB_TO_BB(mp, 1); - imap->im_boffset = (ushort)(offset << mp->m_sb.sb_inodelog); - return 0; - } - - /* - * If the inode chunks are aligned then use simple maths to - * find the location. Otherwise we have to do a btree - * lookup to find the location. - */ - if (mp->m_inoalign_mask) { - offset_agbno = agbno & mp->m_inoalign_mask; - chunk_agbno = agbno - offset_agbno; - } else { - error = xfs_imap_lookup(mp, tp, agno, agino, agbno, - &chunk_agbno, &offset_agbno, flags); - if (error) - return error; - } - -out_map: - ASSERT(agbno >= chunk_agbno); - cluster_agbno = chunk_agbno + - ((offset_agbno / blks_per_cluster) * blks_per_cluster); - offset = ((agbno - cluster_agbno) * mp->m_sb.sb_inopblock) + - XFS_INO_TO_OFFSET(mp, ino); - - imap->im_blkno = XFS_AGB_TO_DADDR(mp, agno, cluster_agbno); - imap->im_len = XFS_FSB_TO_BB(mp, blks_per_cluster); - imap->im_boffset = (ushort)(offset << mp->m_sb.sb_inodelog); - - /* - * If the inode number maps to a block outside the bounds - * of the file system then return NULL rather than calling - * read_buf and panicing when we get an error from the - * driver. - */ - if ((imap->im_blkno + imap->im_len) > - XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)) { - xfs_alert(mp, - "%s: (im_blkno (0x%llx) + im_len (0x%llx)) > sb_dblocks (0x%llx)", - __func__, (unsigned long long) imap->im_blkno, - (unsigned long long) imap->im_len, - XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)); - return -EINVAL; - } - return 0; -} - -/* - * Compute and fill in value of m_in_maxlevels. - */ -void -xfs_ialloc_compute_maxlevels( - xfs_mount_t *mp) /* file system mount structure */ -{ - uint inodes; - - inodes = (1LL << XFS_INO_AGINO_BITS(mp)) >> XFS_INODES_PER_CHUNK_LOG; - mp->m_in_maxlevels = xfs_btree_compute_maxlevels(mp, mp->m_inobt_mnr, - inodes); -} - -/* - * Log specified fields for the ag hdr (inode section). The growth of the agi - * structure over time requires that we interpret the buffer as two logical - * regions delineated by the end of the unlinked list. This is due to the size - * of the hash table and its location in the middle of the agi. - * - * For example, a request to log a field before agi_unlinked and a field after - * agi_unlinked could cause us to log the entire hash table and use an excessive - * amount of log space. To avoid this behavior, log the region up through - * agi_unlinked in one call and the region after agi_unlinked through the end of - * the structure in another. - */ -void -xfs_ialloc_log_agi( - xfs_trans_t *tp, /* transaction pointer */ - xfs_buf_t *bp, /* allocation group header buffer */ - int fields) /* bitmask of fields to log */ -{ - int first; /* first byte number */ - int last; /* last byte number */ - static const short offsets[] = { /* field starting offsets */ - /* keep in sync with bit definitions */ - offsetof(xfs_agi_t, agi_magicnum), - offsetof(xfs_agi_t, agi_versionnum), - offsetof(xfs_agi_t, agi_seqno), - offsetof(xfs_agi_t, agi_length), - offsetof(xfs_agi_t, agi_count), - offsetof(xfs_agi_t, agi_root), - offsetof(xfs_agi_t, agi_level), - offsetof(xfs_agi_t, agi_freecount), - offsetof(xfs_agi_t, agi_newino), - offsetof(xfs_agi_t, agi_dirino), - offsetof(xfs_agi_t, agi_unlinked), - offsetof(xfs_agi_t, agi_free_root), - offsetof(xfs_agi_t, agi_free_level), - sizeof(xfs_agi_t) - }; -#ifdef DEBUG - xfs_agi_t *agi; /* allocation group header */ - - agi = XFS_BUF_TO_AGI(bp); - ASSERT(agi->agi_magicnum == cpu_to_be32(XFS_AGI_MAGIC)); -#endif - - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_AGI_BUF); - - /* - * Compute byte offsets for the first and last fields in the first - * region and log the agi buffer. This only logs up through - * agi_unlinked. - */ - if (fields & XFS_AGI_ALL_BITS_R1) { - xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS_R1, - &first, &last); - xfs_trans_log_buf(tp, bp, first, last); - } - - /* - * Mask off the bits in the first region and calculate the first and - * last field offsets for any bits in the second region. - */ - fields &= ~XFS_AGI_ALL_BITS_R1; - if (fields) { - xfs_btree_offsets(fields, offsets, XFS_AGI_NUM_BITS_R2, - &first, &last); - xfs_trans_log_buf(tp, bp, first, last); - } -} - -#ifdef DEBUG -STATIC void -xfs_check_agi_unlinked( - struct xfs_agi *agi) -{ - int i; - - for (i = 0; i < XFS_AGI_UNLINKED_BUCKETS; i++) - ASSERT(agi->agi_unlinked[i]); -} -#else -#define xfs_check_agi_unlinked(agi) -#endif - -static bool -xfs_agi_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_agi *agi = XFS_BUF_TO_AGI(bp); - - if (xfs_sb_version_hascrc(&mp->m_sb)) { - if (!uuid_equal(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid)) - return false; - if (!xfs_log_check_lsn(mp, - be64_to_cpu(XFS_BUF_TO_AGI(bp)->agi_lsn))) - return false; - } - - /* - * Validate the magic number of the agi block. - */ - if (agi->agi_magicnum != cpu_to_be32(XFS_AGI_MAGIC)) - return false; - if (!XFS_AGI_GOOD_VERSION(be32_to_cpu(agi->agi_versionnum))) - return false; - - if (be32_to_cpu(agi->agi_level) > XFS_BTREE_MAXLEVELS) - return false; - /* - * during growfs operations, the perag is not fully initialised, - * so we can't use it for any useful checking. growfs ensures we can't - * use it by using uncached buffers that don't have the perag attached - * so we can detect and avoid this problem. - */ - if (bp->b_pag && be32_to_cpu(agi->agi_seqno) != bp->b_pag->pag_agno) - return false; - - xfs_check_agi_unlinked(agi); - return true; -} - -static void -xfs_agi_read_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - - if (xfs_sb_version_hascrc(&mp->m_sb) && - !xfs_buf_verify_cksum(bp, XFS_AGI_CRC_OFF)) - xfs_buf_ioerror(bp, -EFSBADCRC); - else if (XFS_TEST_ERROR(!xfs_agi_verify(bp), mp, - XFS_ERRTAG_IALLOC_READ_AGI, - XFS_RANDOM_IALLOC_READ_AGI)) - xfs_buf_ioerror(bp, -EFSCORRUPTED); - - if (bp->b_error) - xfs_verifier_error(bp); -} - -static void -xfs_agi_write_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_buf_log_item *bip = bp->b_fspriv; - - if (!xfs_agi_verify(bp)) { - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - return; - } - - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return; - - if (bip) - XFS_BUF_TO_AGI(bp)->agi_lsn = cpu_to_be64(bip->bli_item.li_lsn); - xfs_buf_update_cksum(bp, XFS_AGI_CRC_OFF); -} - -const struct xfs_buf_ops xfs_agi_buf_ops = { - .name = "xfs_agi", - .verify_read = xfs_agi_read_verify, - .verify_write = xfs_agi_write_verify, -}; - -/* - * Read in the allocation group header (inode allocation section) - */ -int -xfs_read_agi( - struct xfs_mount *mp, /* file system mount structure */ - struct xfs_trans *tp, /* transaction pointer */ - xfs_agnumber_t agno, /* allocation group number */ - struct xfs_buf **bpp) /* allocation group hdr buf */ -{ - int error; - - trace_xfs_read_agi(mp, agno); - - ASSERT(agno != NULLAGNUMBER); - error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, - XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), - XFS_FSS_TO_BB(mp, 1), 0, bpp, &xfs_agi_buf_ops); - if (error) - return error; - - xfs_buf_set_ref(*bpp, XFS_AGI_REF); - return 0; -} - -int -xfs_ialloc_read_agi( - struct xfs_mount *mp, /* file system mount structure */ - struct xfs_trans *tp, /* transaction pointer */ - xfs_agnumber_t agno, /* allocation group number */ - struct xfs_buf **bpp) /* allocation group hdr buf */ -{ - struct xfs_agi *agi; /* allocation group header */ - struct xfs_perag *pag; /* per allocation group data */ - int error; - - trace_xfs_ialloc_read_agi(mp, agno); - - error = xfs_read_agi(mp, tp, agno, bpp); - if (error) - return error; - - agi = XFS_BUF_TO_AGI(*bpp); - pag = xfs_perag_get(mp, agno); - if (!pag->pagi_init) { - pag->pagi_freecount = be32_to_cpu(agi->agi_freecount); - pag->pagi_count = be32_to_cpu(agi->agi_count); - pag->pagi_init = 1; - } - - /* - * It's possible for these to be out of sync if - * we are in the middle of a forced shutdown. - */ - ASSERT(pag->pagi_freecount == be32_to_cpu(agi->agi_freecount) || - XFS_FORCED_SHUTDOWN(mp)); - xfs_perag_put(pag); - return 0; -} - -/* - * Read in the agi to initialise the per-ag data in the mount structure - */ -int -xfs_ialloc_pagi_init( - xfs_mount_t *mp, /* file system mount structure */ - xfs_trans_t *tp, /* transaction pointer */ - xfs_agnumber_t agno) /* allocation group number */ -{ - xfs_buf_t *bp = NULL; - int error; - - error = xfs_ialloc_read_agi(mp, tp, agno, &bp); - if (error) - return error; - if (bp) - xfs_trans_brelse(tp, bp); - return 0; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_ialloc.h b/src/linux/fs/xfs/libxfs/xfs_ialloc.h deleted file mode 100644 index 0bb8966..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_ialloc.h +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright (c) 2000,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_IALLOC_H__ -#define __XFS_IALLOC_H__ - -struct xfs_buf; -struct xfs_dinode; -struct xfs_imap; -struct xfs_mount; -struct xfs_trans; -struct xfs_btree_cur; - -/* Move inodes in clusters of this size */ -#define XFS_INODE_BIG_CLUSTER_SIZE 8192 - -struct xfs_icluster { - bool deleted; /* record is deleted */ - xfs_ino_t first_ino; /* first inode number */ - uint64_t alloc; /* inode phys. allocation bitmap for - * sparse chunks */ -}; - -/* Calculate and return the number of filesystem blocks per inode cluster */ -static inline int -xfs_icluster_size_fsb( - struct xfs_mount *mp) -{ - if (mp->m_sb.sb_blocksize >= mp->m_inode_cluster_size) - return 1; - return mp->m_inode_cluster_size >> mp->m_sb.sb_blocklog; -} - -/* - * Make an inode pointer out of the buffer/offset. - */ -static inline struct xfs_dinode * -xfs_make_iptr(struct xfs_mount *mp, struct xfs_buf *b, int o) -{ - return xfs_buf_offset(b, o << (mp)->m_sb.sb_inodelog); -} - -/* - * Allocate an inode on disk. - * Mode is used to tell whether the new inode will need space, and whether - * it is a directory. - * - * To work within the constraint of one allocation per transaction, - * xfs_dialloc() is designed to be called twice if it has to do an - * allocation to make more free inodes. If an inode is - * available without an allocation, agbp would be set to the current - * agbp and alloc_done set to false. - * If an allocation needed to be done, agbp would be set to the - * inode header of the allocation group and alloc_done set to true. - * The caller should then commit the current transaction and allocate a new - * transaction. xfs_dialloc() should then be called again with - * the agbp value returned from the previous call. - * - * Once we successfully pick an inode its number is returned and the - * on-disk data structures are updated. The inode itself is not read - * in, since doing so would break ordering constraints with xfs_reclaim. - * - * *agbp should be set to NULL on the first call, *alloc_done set to FALSE. - */ -int /* error */ -xfs_dialloc( - struct xfs_trans *tp, /* transaction pointer */ - xfs_ino_t parent, /* parent inode (directory) */ - umode_t mode, /* mode bits for new inode */ - int okalloc, /* ok to allocate more space */ - struct xfs_buf **agbp, /* buf for a.g. inode header */ - xfs_ino_t *inop); /* inode number allocated */ - -/* - * Free disk inode. Carefully avoids touching the incore inode, all - * manipulations incore are the caller's responsibility. - * The on-disk inode is not changed by this operation, only the - * btree (free inode mask) is changed. - */ -int /* error */ -xfs_difree( - struct xfs_trans *tp, /* transaction pointer */ - xfs_ino_t inode, /* inode to be freed */ - struct xfs_defer_ops *dfops, /* extents to free */ - struct xfs_icluster *ifree); /* cluster info if deleted */ - -/* - * Return the location of the inode in imap, for mapping it into a buffer. - */ -int -xfs_imap( - struct xfs_mount *mp, /* file system mount structure */ - struct xfs_trans *tp, /* transaction pointer */ - xfs_ino_t ino, /* inode to locate */ - struct xfs_imap *imap, /* location map structure */ - uint flags); /* flags for inode btree lookup */ - -/* - * Compute and fill in value of m_in_maxlevels. - */ -void -xfs_ialloc_compute_maxlevels( - struct xfs_mount *mp); /* file system mount structure */ - -/* - * Log specified fields for the ag hdr (inode section) - */ -void -xfs_ialloc_log_agi( - struct xfs_trans *tp, /* transaction pointer */ - struct xfs_buf *bp, /* allocation group header buffer */ - int fields); /* bitmask of fields to log */ - -/* - * Read in the allocation group header (inode allocation section) - */ -int /* error */ -xfs_ialloc_read_agi( - struct xfs_mount *mp, /* file system mount structure */ - struct xfs_trans *tp, /* transaction pointer */ - xfs_agnumber_t agno, /* allocation group number */ - struct xfs_buf **bpp); /* allocation group hdr buf */ - -/* - * Read in the allocation group header to initialise the per-ag data - * in the mount structure - */ -int -xfs_ialloc_pagi_init( - struct xfs_mount *mp, /* file system mount structure */ - struct xfs_trans *tp, /* transaction pointer */ - xfs_agnumber_t agno); /* allocation group number */ - -/* - * Lookup a record by ino in the btree given by cur. - */ -int xfs_inobt_lookup(struct xfs_btree_cur *cur, xfs_agino_t ino, - xfs_lookup_t dir, int *stat); - -/* - * Get the data from the pointed-to record. - */ -int xfs_inobt_get_rec(struct xfs_btree_cur *cur, - xfs_inobt_rec_incore_t *rec, int *stat); - -/* - * Inode chunk initialisation routine - */ -int xfs_ialloc_inode_init(struct xfs_mount *mp, struct xfs_trans *tp, - struct list_head *buffer_list, int icount, - xfs_agnumber_t agno, xfs_agblock_t agbno, - xfs_agblock_t length, unsigned int gen); - -int xfs_read_agi(struct xfs_mount *mp, struct xfs_trans *tp, - xfs_agnumber_t agno, struct xfs_buf **bpp); - - -#endif /* __XFS_IALLOC_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_ialloc_btree.c b/src/linux/fs/xfs/libxfs/xfs_ialloc_btree.c deleted file mode 100644 index eab68ae..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_ialloc_btree.c +++ /dev/null @@ -1,480 +0,0 @@ -/* - * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_mount.h" -#include "xfs_inode.h" -#include "xfs_btree.h" -#include "xfs_ialloc.h" -#include "xfs_ialloc_btree.h" -#include "xfs_alloc.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_cksum.h" -#include "xfs_trans.h" -#include "xfs_rmap.h" - - -STATIC int -xfs_inobt_get_minrecs( - struct xfs_btree_cur *cur, - int level) -{ - return cur->bc_mp->m_inobt_mnr[level != 0]; -} - -STATIC struct xfs_btree_cur * -xfs_inobt_dup_cursor( - struct xfs_btree_cur *cur) -{ - return xfs_inobt_init_cursor(cur->bc_mp, cur->bc_tp, - cur->bc_private.a.agbp, cur->bc_private.a.agno, - cur->bc_btnum); -} - -STATIC void -xfs_inobt_set_root( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *nptr, - int inc) /* level change */ -{ - struct xfs_buf *agbp = cur->bc_private.a.agbp; - struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); - - agi->agi_root = nptr->s; - be32_add_cpu(&agi->agi_level, inc); - xfs_ialloc_log_agi(cur->bc_tp, agbp, XFS_AGI_ROOT | XFS_AGI_LEVEL); -} - -STATIC void -xfs_finobt_set_root( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *nptr, - int inc) /* level change */ -{ - struct xfs_buf *agbp = cur->bc_private.a.agbp; - struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); - - agi->agi_free_root = nptr->s; - be32_add_cpu(&agi->agi_free_level, inc); - xfs_ialloc_log_agi(cur->bc_tp, agbp, - XFS_AGI_FREE_ROOT | XFS_AGI_FREE_LEVEL); -} - -STATIC int -xfs_inobt_alloc_block( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *start, - union xfs_btree_ptr *new, - int *stat) -{ - xfs_alloc_arg_t args; /* block allocation args */ - int error; /* error return value */ - xfs_agblock_t sbno = be32_to_cpu(start->s); - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - - memset(&args, 0, sizeof(args)); - args.tp = cur->bc_tp; - args.mp = cur->bc_mp; - xfs_rmap_ag_owner(&args.oinfo, XFS_RMAP_OWN_INOBT); - args.fsbno = XFS_AGB_TO_FSB(args.mp, cur->bc_private.a.agno, sbno); - args.minlen = 1; - args.maxlen = 1; - args.prod = 1; - args.type = XFS_ALLOCTYPE_NEAR_BNO; - - error = xfs_alloc_vextent(&args); - if (error) { - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; - } - if (args.fsbno == NULLFSBLOCK) { - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 0; - return 0; - } - ASSERT(args.len == 1); - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - - new->s = cpu_to_be32(XFS_FSB_TO_AGBNO(args.mp, args.fsbno)); - *stat = 1; - return 0; -} - -STATIC int -xfs_inobt_free_block( - struct xfs_btree_cur *cur, - struct xfs_buf *bp) -{ - struct xfs_owner_info oinfo; - - xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_INOBT); - return xfs_free_extent(cur->bc_tp, - XFS_DADDR_TO_FSB(cur->bc_mp, XFS_BUF_ADDR(bp)), 1, - &oinfo, XFS_AG_RESV_NONE); -} - -STATIC int -xfs_inobt_get_maxrecs( - struct xfs_btree_cur *cur, - int level) -{ - return cur->bc_mp->m_inobt_mxr[level != 0]; -} - -STATIC void -xfs_inobt_init_key_from_rec( - union xfs_btree_key *key, - union xfs_btree_rec *rec) -{ - key->inobt.ir_startino = rec->inobt.ir_startino; -} - -STATIC void -xfs_inobt_init_rec_from_cur( - struct xfs_btree_cur *cur, - union xfs_btree_rec *rec) -{ - rec->inobt.ir_startino = cpu_to_be32(cur->bc_rec.i.ir_startino); - if (xfs_sb_version_hassparseinodes(&cur->bc_mp->m_sb)) { - rec->inobt.ir_u.sp.ir_holemask = - cpu_to_be16(cur->bc_rec.i.ir_holemask); - rec->inobt.ir_u.sp.ir_count = cur->bc_rec.i.ir_count; - rec->inobt.ir_u.sp.ir_freecount = cur->bc_rec.i.ir_freecount; - } else { - /* ir_holemask/ir_count not supported on-disk */ - rec->inobt.ir_u.f.ir_freecount = - cpu_to_be32(cur->bc_rec.i.ir_freecount); - } - rec->inobt.ir_free = cpu_to_be64(cur->bc_rec.i.ir_free); -} - -/* - * initial value of ptr for lookup - */ -STATIC void -xfs_inobt_init_ptr_from_cur( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *ptr) -{ - struct xfs_agi *agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp); - - ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno)); - - ptr->s = agi->agi_root; -} - -STATIC void -xfs_finobt_init_ptr_from_cur( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *ptr) -{ - struct xfs_agi *agi = XFS_BUF_TO_AGI(cur->bc_private.a.agbp); - - ASSERT(cur->bc_private.a.agno == be32_to_cpu(agi->agi_seqno)); - ptr->s = agi->agi_free_root; -} - -STATIC __int64_t -xfs_inobt_key_diff( - struct xfs_btree_cur *cur, - union xfs_btree_key *key) -{ - return (__int64_t)be32_to_cpu(key->inobt.ir_startino) - - cur->bc_rec.i.ir_startino; -} - -static int -xfs_inobt_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); - unsigned int level; - - /* - * During growfs operations, we can't verify the exact owner as the - * perag is not fully initialised and hence not attached to the buffer. - * - * Similarly, during log recovery we will have a perag structure - * attached, but the agi information will not yet have been initialised - * from the on disk AGI. We don't currently use any of this information, - * but beware of the landmine (i.e. need to check pag->pagi_init) if we - * ever do. - */ - switch (block->bb_magic) { - case cpu_to_be32(XFS_IBT_CRC_MAGIC): - case cpu_to_be32(XFS_FIBT_CRC_MAGIC): - if (!xfs_btree_sblock_v5hdr_verify(bp)) - return false; - /* fall through */ - case cpu_to_be32(XFS_IBT_MAGIC): - case cpu_to_be32(XFS_FIBT_MAGIC): - break; - default: - return 0; - } - - /* level verification */ - level = be16_to_cpu(block->bb_level); - if (level >= mp->m_in_maxlevels) - return false; - - return xfs_btree_sblock_verify(bp, mp->m_inobt_mxr[level != 0]); -} - -static void -xfs_inobt_read_verify( - struct xfs_buf *bp) -{ - if (!xfs_btree_sblock_verify_crc(bp)) - xfs_buf_ioerror(bp, -EFSBADCRC); - else if (!xfs_inobt_verify(bp)) - xfs_buf_ioerror(bp, -EFSCORRUPTED); - - if (bp->b_error) { - trace_xfs_btree_corrupt(bp, _RET_IP_); - xfs_verifier_error(bp); - } -} - -static void -xfs_inobt_write_verify( - struct xfs_buf *bp) -{ - if (!xfs_inobt_verify(bp)) { - trace_xfs_btree_corrupt(bp, _RET_IP_); - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - return; - } - xfs_btree_sblock_calc_crc(bp); - -} - -const struct xfs_buf_ops xfs_inobt_buf_ops = { - .name = "xfs_inobt", - .verify_read = xfs_inobt_read_verify, - .verify_write = xfs_inobt_write_verify, -}; - -#if defined(DEBUG) || defined(XFS_WARN) -STATIC int -xfs_inobt_keys_inorder( - struct xfs_btree_cur *cur, - union xfs_btree_key *k1, - union xfs_btree_key *k2) -{ - return be32_to_cpu(k1->inobt.ir_startino) < - be32_to_cpu(k2->inobt.ir_startino); -} - -STATIC int -xfs_inobt_recs_inorder( - struct xfs_btree_cur *cur, - union xfs_btree_rec *r1, - union xfs_btree_rec *r2) -{ - return be32_to_cpu(r1->inobt.ir_startino) + XFS_INODES_PER_CHUNK <= - be32_to_cpu(r2->inobt.ir_startino); -} -#endif /* DEBUG */ - -static const struct xfs_btree_ops xfs_inobt_ops = { - .rec_len = sizeof(xfs_inobt_rec_t), - .key_len = sizeof(xfs_inobt_key_t), - - .dup_cursor = xfs_inobt_dup_cursor, - .set_root = xfs_inobt_set_root, - .alloc_block = xfs_inobt_alloc_block, - .free_block = xfs_inobt_free_block, - .get_minrecs = xfs_inobt_get_minrecs, - .get_maxrecs = xfs_inobt_get_maxrecs, - .init_key_from_rec = xfs_inobt_init_key_from_rec, - .init_rec_from_cur = xfs_inobt_init_rec_from_cur, - .init_ptr_from_cur = xfs_inobt_init_ptr_from_cur, - .key_diff = xfs_inobt_key_diff, - .buf_ops = &xfs_inobt_buf_ops, -#if defined(DEBUG) || defined(XFS_WARN) - .keys_inorder = xfs_inobt_keys_inorder, - .recs_inorder = xfs_inobt_recs_inorder, -#endif -}; - -static const struct xfs_btree_ops xfs_finobt_ops = { - .rec_len = sizeof(xfs_inobt_rec_t), - .key_len = sizeof(xfs_inobt_key_t), - - .dup_cursor = xfs_inobt_dup_cursor, - .set_root = xfs_finobt_set_root, - .alloc_block = xfs_inobt_alloc_block, - .free_block = xfs_inobt_free_block, - .get_minrecs = xfs_inobt_get_minrecs, - .get_maxrecs = xfs_inobt_get_maxrecs, - .init_key_from_rec = xfs_inobt_init_key_from_rec, - .init_rec_from_cur = xfs_inobt_init_rec_from_cur, - .init_ptr_from_cur = xfs_finobt_init_ptr_from_cur, - .key_diff = xfs_inobt_key_diff, - .buf_ops = &xfs_inobt_buf_ops, -#if defined(DEBUG) || defined(XFS_WARN) - .keys_inorder = xfs_inobt_keys_inorder, - .recs_inorder = xfs_inobt_recs_inorder, -#endif -}; - -/* - * Allocate a new inode btree cursor. - */ -struct xfs_btree_cur * /* new inode btree cursor */ -xfs_inobt_init_cursor( - struct xfs_mount *mp, /* file system mount point */ - struct xfs_trans *tp, /* transaction pointer */ - struct xfs_buf *agbp, /* buffer for agi structure */ - xfs_agnumber_t agno, /* allocation group number */ - xfs_btnum_t btnum) /* ialloc or free ino btree */ -{ - struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp); - struct xfs_btree_cur *cur; - - cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_SLEEP); - - cur->bc_tp = tp; - cur->bc_mp = mp; - cur->bc_btnum = btnum; - if (btnum == XFS_BTNUM_INO) { - cur->bc_nlevels = be32_to_cpu(agi->agi_level); - cur->bc_ops = &xfs_inobt_ops; - } else { - cur->bc_nlevels = be32_to_cpu(agi->agi_free_level); - cur->bc_ops = &xfs_finobt_ops; - } - - cur->bc_blocklog = mp->m_sb.sb_blocklog; - - if (xfs_sb_version_hascrc(&mp->m_sb)) - cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; - - cur->bc_private.a.agbp = agbp; - cur->bc_private.a.agno = agno; - - return cur; -} - -/* - * Calculate number of records in an inobt btree block. - */ -int -xfs_inobt_maxrecs( - struct xfs_mount *mp, - int blocklen, - int leaf) -{ - blocklen -= XFS_INOBT_BLOCK_LEN(mp); - - if (leaf) - return blocklen / sizeof(xfs_inobt_rec_t); - return blocklen / (sizeof(xfs_inobt_key_t) + sizeof(xfs_inobt_ptr_t)); -} - -/* - * Convert the inode record holemask to an inode allocation bitmap. The inode - * allocation bitmap is inode granularity and specifies whether an inode is - * physically allocated on disk (not whether the inode is considered allocated - * or free by the fs). - * - * A bit value of 1 means the inode is allocated, a value of 0 means it is free. - */ -uint64_t -xfs_inobt_irec_to_allocmask( - struct xfs_inobt_rec_incore *rec) -{ - uint64_t bitmap = 0; - uint64_t inodespbit; - int nextbit; - uint allocbitmap; - - /* - * The holemask has 16-bits for a 64 inode record. Therefore each - * holemask bit represents multiple inodes. Create a mask of bits to set - * in the allocmask for each holemask bit. - */ - inodespbit = (1 << XFS_INODES_PER_HOLEMASK_BIT) - 1; - - /* - * Allocated inodes are represented by 0 bits in holemask. Invert the 0 - * bits to 1 and convert to a uint so we can use xfs_next_bit(). Mask - * anything beyond the 16 holemask bits since this casts to a larger - * type. - */ - allocbitmap = ~rec->ir_holemask & ((1 << XFS_INOBT_HOLEMASK_BITS) - 1); - - /* - * allocbitmap is the inverted holemask so every set bit represents - * allocated inodes. To expand from 16-bit holemask granularity to - * 64-bit (e.g., bit-per-inode), set inodespbit bits in the target - * bitmap for every holemask bit. - */ - nextbit = xfs_next_bit(&allocbitmap, 1, 0); - while (nextbit != -1) { - ASSERT(nextbit < (sizeof(rec->ir_holemask) * NBBY)); - - bitmap |= (inodespbit << - (nextbit * XFS_INODES_PER_HOLEMASK_BIT)); - - nextbit = xfs_next_bit(&allocbitmap, 1, nextbit + 1); - } - - return bitmap; -} - -#if defined(DEBUG) || defined(XFS_WARN) -/* - * Verify that an in-core inode record has a valid inode count. - */ -int -xfs_inobt_rec_check_count( - struct xfs_mount *mp, - struct xfs_inobt_rec_incore *rec) -{ - int inocount = 0; - int nextbit = 0; - uint64_t allocbmap; - int wordsz; - - wordsz = sizeof(allocbmap) / sizeof(unsigned int); - allocbmap = xfs_inobt_irec_to_allocmask(rec); - - nextbit = xfs_next_bit((uint *) &allocbmap, wordsz, nextbit); - while (nextbit != -1) { - inocount++; - nextbit = xfs_next_bit((uint *) &allocbmap, wordsz, - nextbit + 1); - } - - if (inocount != rec->ir_count) - return -EFSCORRUPTED; - - return 0; -} -#endif /* DEBUG */ diff --git a/src/linux/fs/xfs/libxfs/xfs_ialloc_btree.h b/src/linux/fs/xfs/libxfs/xfs_ialloc_btree.h deleted file mode 100644 index bd88453..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_ialloc_btree.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2000,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_IALLOC_BTREE_H__ -#define __XFS_IALLOC_BTREE_H__ - -/* - * Inode map on-disk structures - */ - -struct xfs_buf; -struct xfs_btree_cur; -struct xfs_mount; - -/* - * Btree block header size depends on a superblock flag. - */ -#define XFS_INOBT_BLOCK_LEN(mp) \ - (xfs_sb_version_hascrc(&((mp)->m_sb)) ? \ - XFS_BTREE_SBLOCK_CRC_LEN : XFS_BTREE_SBLOCK_LEN) - -/* - * Record, key, and pointer address macros for btree blocks. - * - * (note that some of these may appear unused, but they are used in userspace) - */ -#define XFS_INOBT_REC_ADDR(mp, block, index) \ - ((xfs_inobt_rec_t *) \ - ((char *)(block) + \ - XFS_INOBT_BLOCK_LEN(mp) + \ - (((index) - 1) * sizeof(xfs_inobt_rec_t)))) - -#define XFS_INOBT_KEY_ADDR(mp, block, index) \ - ((xfs_inobt_key_t *) \ - ((char *)(block) + \ - XFS_INOBT_BLOCK_LEN(mp) + \ - ((index) - 1) * sizeof(xfs_inobt_key_t))) - -#define XFS_INOBT_PTR_ADDR(mp, block, index, maxrecs) \ - ((xfs_inobt_ptr_t *) \ - ((char *)(block) + \ - XFS_INOBT_BLOCK_LEN(mp) + \ - (maxrecs) * sizeof(xfs_inobt_key_t) + \ - ((index) - 1) * sizeof(xfs_inobt_ptr_t))) - -extern struct xfs_btree_cur *xfs_inobt_init_cursor(struct xfs_mount *, - struct xfs_trans *, struct xfs_buf *, xfs_agnumber_t, - xfs_btnum_t); -extern int xfs_inobt_maxrecs(struct xfs_mount *, int, int); - -/* ir_holemask to inode allocation bitmap conversion */ -uint64_t xfs_inobt_irec_to_allocmask(struct xfs_inobt_rec_incore *); - -#if defined(DEBUG) || defined(XFS_WARN) -int xfs_inobt_rec_check_count(struct xfs_mount *, - struct xfs_inobt_rec_incore *); -#else -#define xfs_inobt_rec_check_count(mp, rec) 0 -#endif /* DEBUG */ - -#endif /* __XFS_IALLOC_BTREE_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_inode_buf.c b/src/linux/fs/xfs/libxfs/xfs_inode_buf.c deleted file mode 100644 index 134424f..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_inode_buf.c +++ /dev/null @@ -1,566 +0,0 @@ -/* - * Copyright (c) 2000-2006 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_inode.h" -#include "xfs_error.h" -#include "xfs_cksum.h" -#include "xfs_icache.h" -#include "xfs_trans.h" -#include "xfs_ialloc.h" - -/* - * Check that none of the inode's in the buffer have a next - * unlinked field of 0. - */ -#if defined(DEBUG) -void -xfs_inobp_check( - xfs_mount_t *mp, - xfs_buf_t *bp) -{ - int i; - int j; - xfs_dinode_t *dip; - - j = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog; - - for (i = 0; i < j; i++) { - dip = xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize); - if (!dip->di_next_unlinked) { - xfs_alert(mp, - "Detected bogus zero next_unlinked field in inode %d buffer 0x%llx.", - i, (long long)bp->b_bn); - } - } -} -#endif - -bool -xfs_dinode_good_version( - struct xfs_mount *mp, - __u8 version) -{ - if (xfs_sb_version_hascrc(&mp->m_sb)) - return version == 3; - - return version == 1 || version == 2; -} - -/* - * If we are doing readahead on an inode buffer, we might be in log recovery - * reading an inode allocation buffer that hasn't yet been replayed, and hence - * has not had the inode cores stamped into it. Hence for readahead, the buffer - * may be potentially invalid. - * - * If the readahead buffer is invalid, we need to mark it with an error and - * clear the DONE status of the buffer so that a followup read will re-read it - * from disk. We don't report the error otherwise to avoid warnings during log - * recovery and we don't get unnecssary panics on debug kernels. We use EIO here - * because all we want to do is say readahead failed; there is no-one to report - * the error to, so this will distinguish it from a non-ra verifier failure. - * Changes to this readahead error behavour also need to be reflected in - * xfs_dquot_buf_readahead_verify(). - */ -static void -xfs_inode_buf_verify( - struct xfs_buf *bp, - bool readahead) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - int i; - int ni; - - /* - * Validate the magic number and version of every inode in the buffer - */ - ni = XFS_BB_TO_FSB(mp, bp->b_length) * mp->m_sb.sb_inopblock; - for (i = 0; i < ni; i++) { - int di_ok; - xfs_dinode_t *dip; - - dip = xfs_buf_offset(bp, (i << mp->m_sb.sb_inodelog)); - di_ok = dip->di_magic == cpu_to_be16(XFS_DINODE_MAGIC) && - xfs_dinode_good_version(mp, dip->di_version); - if (unlikely(XFS_TEST_ERROR(!di_ok, mp, - XFS_ERRTAG_ITOBP_INOTOBP, - XFS_RANDOM_ITOBP_INOTOBP))) { - if (readahead) { - bp->b_flags &= ~XBF_DONE; - xfs_buf_ioerror(bp, -EIO); - return; - } - - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); -#ifdef DEBUG - xfs_alert(mp, - "bad inode magic/vsn daddr %lld #%d (magic=%x)", - (unsigned long long)bp->b_bn, i, - be16_to_cpu(dip->di_magic)); -#endif - } - } - xfs_inobp_check(mp, bp); -} - - -static void -xfs_inode_buf_read_verify( - struct xfs_buf *bp) -{ - xfs_inode_buf_verify(bp, false); -} - -static void -xfs_inode_buf_readahead_verify( - struct xfs_buf *bp) -{ - xfs_inode_buf_verify(bp, true); -} - -static void -xfs_inode_buf_write_verify( - struct xfs_buf *bp) -{ - xfs_inode_buf_verify(bp, false); -} - -const struct xfs_buf_ops xfs_inode_buf_ops = { - .name = "xfs_inode", - .verify_read = xfs_inode_buf_read_verify, - .verify_write = xfs_inode_buf_write_verify, -}; - -const struct xfs_buf_ops xfs_inode_buf_ra_ops = { - .name = "xxfs_inode_ra", - .verify_read = xfs_inode_buf_readahead_verify, - .verify_write = xfs_inode_buf_write_verify, -}; - - -/* - * This routine is called to map an inode to the buffer containing the on-disk - * version of the inode. It returns a pointer to the buffer containing the - * on-disk inode in the bpp parameter, and in the dipp parameter it returns a - * pointer to the on-disk inode within that buffer. - * - * If a non-zero error is returned, then the contents of bpp and dipp are - * undefined. - */ -int -xfs_imap_to_bp( - struct xfs_mount *mp, - struct xfs_trans *tp, - struct xfs_imap *imap, - struct xfs_dinode **dipp, - struct xfs_buf **bpp, - uint buf_flags, - uint iget_flags) -{ - struct xfs_buf *bp; - int error; - - buf_flags |= XBF_UNMAPPED; - error = xfs_trans_read_buf(mp, tp, mp->m_ddev_targp, imap->im_blkno, - (int)imap->im_len, buf_flags, &bp, - &xfs_inode_buf_ops); - if (error) { - if (error == -EAGAIN) { - ASSERT(buf_flags & XBF_TRYLOCK); - return error; - } - - if (error == -EFSCORRUPTED && - (iget_flags & XFS_IGET_UNTRUSTED)) - return -EINVAL; - - xfs_warn(mp, "%s: xfs_trans_read_buf() returned error %d.", - __func__, error); - return error; - } - - *bpp = bp; - *dipp = xfs_buf_offset(bp, imap->im_boffset); - return 0; -} - -void -xfs_inode_from_disk( - struct xfs_inode *ip, - struct xfs_dinode *from) -{ - struct xfs_icdinode *to = &ip->i_d; - struct inode *inode = VFS_I(ip); - - - /* - * Convert v1 inodes immediately to v2 inode format as this is the - * minimum inode version format we support in the rest of the code. - */ - to->di_version = from->di_version; - if (to->di_version == 1) { - set_nlink(inode, be16_to_cpu(from->di_onlink)); - to->di_projid_lo = 0; - to->di_projid_hi = 0; - to->di_version = 2; - } else { - set_nlink(inode, be32_to_cpu(from->di_nlink)); - to->di_projid_lo = be16_to_cpu(from->di_projid_lo); - to->di_projid_hi = be16_to_cpu(from->di_projid_hi); - } - - to->di_format = from->di_format; - to->di_uid = be32_to_cpu(from->di_uid); - to->di_gid = be32_to_cpu(from->di_gid); - to->di_flushiter = be16_to_cpu(from->di_flushiter); - - /* - * Time is signed, so need to convert to signed 32 bit before - * storing in inode timestamp which may be 64 bit. Otherwise - * a time before epoch is converted to a time long after epoch - * on 64 bit systems. - */ - inode->i_atime.tv_sec = (int)be32_to_cpu(from->di_atime.t_sec); - inode->i_atime.tv_nsec = (int)be32_to_cpu(from->di_atime.t_nsec); - inode->i_mtime.tv_sec = (int)be32_to_cpu(from->di_mtime.t_sec); - inode->i_mtime.tv_nsec = (int)be32_to_cpu(from->di_mtime.t_nsec); - inode->i_ctime.tv_sec = (int)be32_to_cpu(from->di_ctime.t_sec); - inode->i_ctime.tv_nsec = (int)be32_to_cpu(from->di_ctime.t_nsec); - inode->i_generation = be32_to_cpu(from->di_gen); - inode->i_mode = be16_to_cpu(from->di_mode); - - to->di_size = be64_to_cpu(from->di_size); - to->di_nblocks = be64_to_cpu(from->di_nblocks); - to->di_extsize = be32_to_cpu(from->di_extsize); - to->di_nextents = be32_to_cpu(from->di_nextents); - to->di_anextents = be16_to_cpu(from->di_anextents); - to->di_forkoff = from->di_forkoff; - to->di_aformat = from->di_aformat; - to->di_dmevmask = be32_to_cpu(from->di_dmevmask); - to->di_dmstate = be16_to_cpu(from->di_dmstate); - to->di_flags = be16_to_cpu(from->di_flags); - - if (to->di_version == 3) { - inode->i_version = be64_to_cpu(from->di_changecount); - to->di_crtime.t_sec = be32_to_cpu(from->di_crtime.t_sec); - to->di_crtime.t_nsec = be32_to_cpu(from->di_crtime.t_nsec); - to->di_flags2 = be64_to_cpu(from->di_flags2); - to->di_cowextsize = be32_to_cpu(from->di_cowextsize); - } -} - -void -xfs_inode_to_disk( - struct xfs_inode *ip, - struct xfs_dinode *to, - xfs_lsn_t lsn) -{ - struct xfs_icdinode *from = &ip->i_d; - struct inode *inode = VFS_I(ip); - - to->di_magic = cpu_to_be16(XFS_DINODE_MAGIC); - to->di_onlink = 0; - - to->di_version = from->di_version; - to->di_format = from->di_format; - to->di_uid = cpu_to_be32(from->di_uid); - to->di_gid = cpu_to_be32(from->di_gid); - to->di_projid_lo = cpu_to_be16(from->di_projid_lo); - to->di_projid_hi = cpu_to_be16(from->di_projid_hi); - - memset(to->di_pad, 0, sizeof(to->di_pad)); - to->di_atime.t_sec = cpu_to_be32(inode->i_atime.tv_sec); - to->di_atime.t_nsec = cpu_to_be32(inode->i_atime.tv_nsec); - to->di_mtime.t_sec = cpu_to_be32(inode->i_mtime.tv_sec); - to->di_mtime.t_nsec = cpu_to_be32(inode->i_mtime.tv_nsec); - to->di_ctime.t_sec = cpu_to_be32(inode->i_ctime.tv_sec); - to->di_ctime.t_nsec = cpu_to_be32(inode->i_ctime.tv_nsec); - to->di_nlink = cpu_to_be32(inode->i_nlink); - to->di_gen = cpu_to_be32(inode->i_generation); - to->di_mode = cpu_to_be16(inode->i_mode); - - to->di_size = cpu_to_be64(from->di_size); - to->di_nblocks = cpu_to_be64(from->di_nblocks); - to->di_extsize = cpu_to_be32(from->di_extsize); - to->di_nextents = cpu_to_be32(from->di_nextents); - to->di_anextents = cpu_to_be16(from->di_anextents); - to->di_forkoff = from->di_forkoff; - to->di_aformat = from->di_aformat; - to->di_dmevmask = cpu_to_be32(from->di_dmevmask); - to->di_dmstate = cpu_to_be16(from->di_dmstate); - to->di_flags = cpu_to_be16(from->di_flags); - - if (from->di_version == 3) { - to->di_changecount = cpu_to_be64(inode->i_version); - to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.t_sec); - to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.t_nsec); - to->di_flags2 = cpu_to_be64(from->di_flags2); - to->di_cowextsize = cpu_to_be32(from->di_cowextsize); - to->di_ino = cpu_to_be64(ip->i_ino); - to->di_lsn = cpu_to_be64(lsn); - memset(to->di_pad2, 0, sizeof(to->di_pad2)); - uuid_copy(&to->di_uuid, &ip->i_mount->m_sb.sb_meta_uuid); - to->di_flushiter = 0; - } else { - to->di_flushiter = cpu_to_be16(from->di_flushiter); - } -} - -void -xfs_log_dinode_to_disk( - struct xfs_log_dinode *from, - struct xfs_dinode *to) -{ - to->di_magic = cpu_to_be16(from->di_magic); - to->di_mode = cpu_to_be16(from->di_mode); - to->di_version = from->di_version; - to->di_format = from->di_format; - to->di_onlink = 0; - to->di_uid = cpu_to_be32(from->di_uid); - to->di_gid = cpu_to_be32(from->di_gid); - to->di_nlink = cpu_to_be32(from->di_nlink); - to->di_projid_lo = cpu_to_be16(from->di_projid_lo); - to->di_projid_hi = cpu_to_be16(from->di_projid_hi); - memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad)); - - to->di_atime.t_sec = cpu_to_be32(from->di_atime.t_sec); - to->di_atime.t_nsec = cpu_to_be32(from->di_atime.t_nsec); - to->di_mtime.t_sec = cpu_to_be32(from->di_mtime.t_sec); - to->di_mtime.t_nsec = cpu_to_be32(from->di_mtime.t_nsec); - to->di_ctime.t_sec = cpu_to_be32(from->di_ctime.t_sec); - to->di_ctime.t_nsec = cpu_to_be32(from->di_ctime.t_nsec); - - to->di_size = cpu_to_be64(from->di_size); - to->di_nblocks = cpu_to_be64(from->di_nblocks); - to->di_extsize = cpu_to_be32(from->di_extsize); - to->di_nextents = cpu_to_be32(from->di_nextents); - to->di_anextents = cpu_to_be16(from->di_anextents); - to->di_forkoff = from->di_forkoff; - to->di_aformat = from->di_aformat; - to->di_dmevmask = cpu_to_be32(from->di_dmevmask); - to->di_dmstate = cpu_to_be16(from->di_dmstate); - to->di_flags = cpu_to_be16(from->di_flags); - to->di_gen = cpu_to_be32(from->di_gen); - - if (from->di_version == 3) { - to->di_changecount = cpu_to_be64(from->di_changecount); - to->di_crtime.t_sec = cpu_to_be32(from->di_crtime.t_sec); - to->di_crtime.t_nsec = cpu_to_be32(from->di_crtime.t_nsec); - to->di_flags2 = cpu_to_be64(from->di_flags2); - to->di_cowextsize = cpu_to_be32(from->di_cowextsize); - to->di_ino = cpu_to_be64(from->di_ino); - to->di_lsn = cpu_to_be64(from->di_lsn); - memcpy(to->di_pad2, from->di_pad2, sizeof(to->di_pad2)); - uuid_copy(&to->di_uuid, &from->di_uuid); - to->di_flushiter = 0; - } else { - to->di_flushiter = cpu_to_be16(from->di_flushiter); - } -} - -static bool -xfs_dinode_verify( - struct xfs_mount *mp, - struct xfs_inode *ip, - struct xfs_dinode *dip) -{ - uint16_t flags; - uint64_t flags2; - - if (dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC)) - return false; - - /* only version 3 or greater inodes are extensively verified here */ - if (dip->di_version < 3) - return true; - - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return false; - if (!xfs_verify_cksum((char *)dip, mp->m_sb.sb_inodesize, - XFS_DINODE_CRC_OFF)) - return false; - if (be64_to_cpu(dip->di_ino) != ip->i_ino) - return false; - if (!uuid_equal(&dip->di_uuid, &mp->m_sb.sb_meta_uuid)) - return false; - - flags = be16_to_cpu(dip->di_flags); - flags2 = be64_to_cpu(dip->di_flags2); - - /* don't allow reflink/cowextsize if we don't have reflink */ - if ((flags2 & (XFS_DIFLAG2_REFLINK | XFS_DIFLAG2_COWEXTSIZE)) && - !xfs_sb_version_hasreflink(&mp->m_sb)) - return false; - - /* don't let reflink and realtime mix */ - if ((flags2 & XFS_DIFLAG2_REFLINK) && (flags & XFS_DIFLAG_REALTIME)) - return false; - - /* don't let reflink and dax mix */ - if ((flags2 & XFS_DIFLAG2_REFLINK) && (flags2 & XFS_DIFLAG2_DAX)) - return false; - - return true; -} - -void -xfs_dinode_calc_crc( - struct xfs_mount *mp, - struct xfs_dinode *dip) -{ - __uint32_t crc; - - if (dip->di_version < 3) - return; - - ASSERT(xfs_sb_version_hascrc(&mp->m_sb)); - crc = xfs_start_cksum((char *)dip, mp->m_sb.sb_inodesize, - XFS_DINODE_CRC_OFF); - dip->di_crc = xfs_end_cksum(crc); -} - -/* - * Read the disk inode attributes into the in-core inode structure. - * - * For version 5 superblocks, if we are initialising a new inode and we are not - * utilising the XFS_MOUNT_IKEEP inode cluster mode, we can simple build the new - * inode core with a random generation number. If we are keeping inodes around, - * we need to read the inode cluster to get the existing generation number off - * disk. Further, if we are using version 4 superblocks (i.e. v1/v2 inode - * format) then log recovery is dependent on the di_flushiter field being - * initialised from the current on-disk value and hence we must also read the - * inode off disk. - */ -int -xfs_iread( - xfs_mount_t *mp, - xfs_trans_t *tp, - xfs_inode_t *ip, - uint iget_flags) -{ - xfs_buf_t *bp; - xfs_dinode_t *dip; - int error; - - /* - * Fill in the location information in the in-core inode. - */ - error = xfs_imap(mp, tp, ip->i_ino, &ip->i_imap, iget_flags); - if (error) - return error; - - /* shortcut IO on inode allocation if possible */ - if ((iget_flags & XFS_IGET_CREATE) && - xfs_sb_version_hascrc(&mp->m_sb) && - !(mp->m_flags & XFS_MOUNT_IKEEP)) { - /* initialise the on-disk inode core */ - memset(&ip->i_d, 0, sizeof(ip->i_d)); - VFS_I(ip)->i_generation = prandom_u32(); - if (xfs_sb_version_hascrc(&mp->m_sb)) - ip->i_d.di_version = 3; - else - ip->i_d.di_version = 2; - return 0; - } - - /* - * Get pointers to the on-disk inode and the buffer containing it. - */ - error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &bp, 0, iget_flags); - if (error) - return error; - - /* even unallocated inodes are verified */ - if (!xfs_dinode_verify(mp, ip, dip)) { - xfs_alert(mp, "%s: validation failed for inode %lld failed", - __func__, ip->i_ino); - - XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, dip); - error = -EFSCORRUPTED; - goto out_brelse; - } - - /* - * If the on-disk inode is already linked to a directory - * entry, copy all of the inode into the in-core inode. - * xfs_iformat_fork() handles copying in the inode format - * specific information. - * Otherwise, just get the truly permanent information. - */ - if (dip->di_mode) { - xfs_inode_from_disk(ip, dip); - error = xfs_iformat_fork(ip, dip); - if (error) { -#ifdef DEBUG - xfs_alert(mp, "%s: xfs_iformat() returned error %d", - __func__, error); -#endif /* DEBUG */ - goto out_brelse; - } - } else { - /* - * Partial initialisation of the in-core inode. Just the bits - * that xfs_ialloc won't overwrite or relies on being correct. - */ - ip->i_d.di_version = dip->di_version; - VFS_I(ip)->i_generation = be32_to_cpu(dip->di_gen); - ip->i_d.di_flushiter = be16_to_cpu(dip->di_flushiter); - - /* - * Make sure to pull in the mode here as well in - * case the inode is released without being used. - * This ensures that xfs_inactive() will see that - * the inode is already free and not try to mess - * with the uninitialized part of it. - */ - VFS_I(ip)->i_mode = 0; - } - - ASSERT(ip->i_d.di_version >= 2); - ip->i_delayed_blks = 0; - - /* - * Mark the buffer containing the inode as something to keep - * around for a while. This helps to keep recently accessed - * meta-data in-core longer. - */ - xfs_buf_set_ref(bp, XFS_INO_REF); - - /* - * Use xfs_trans_brelse() to release the buffer containing the on-disk - * inode, because it was acquired with xfs_trans_read_buf() in - * xfs_imap_to_bp() above. If tp is NULL, this is just a normal - * brelse(). If we're within a transaction, then xfs_trans_brelse() - * will only release the buffer if it is not dirty within the - * transaction. It will be OK to release the buffer in this case, - * because inodes on disk are never destroyed and we will be locking the - * new in-core inode before putting it in the cache where other - * processes can find it. Thus we don't have to worry about the inode - * being changed just because we released the buffer. - */ - out_brelse: - xfs_trans_brelse(tp, bp); - return error; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_inode_buf.h b/src/linux/fs/xfs/libxfs/xfs_inode_buf.h deleted file mode 100644 index 3cfe12a..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_inode_buf.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_INODE_BUF_H__ -#define __XFS_INODE_BUF_H__ - -struct xfs_inode; -struct xfs_dinode; - -/* - * In memory representation of the XFS inode. This is held in the in-core struct - * xfs_inode and represents the current on disk values but the structure is not - * in on-disk format. That is, this structure is always translated to on-disk - * format specific structures at the appropriate time. - */ -struct xfs_icdinode { - __int8_t di_version; /* inode version */ - __int8_t di_format; /* format of di_c data */ - __uint16_t di_flushiter; /* incremented on flush */ - __uint32_t di_uid; /* owner's user id */ - __uint32_t di_gid; /* owner's group id */ - __uint16_t di_projid_lo; /* lower part of owner's project id */ - __uint16_t di_projid_hi; /* higher part of owner's project id */ - xfs_fsize_t di_size; /* number of bytes in file */ - xfs_rfsblock_t di_nblocks; /* # of direct & btree blocks used */ - xfs_extlen_t di_extsize; /* basic/minimum extent size for file */ - xfs_extnum_t di_nextents; /* number of extents in data fork */ - xfs_aextnum_t di_anextents; /* number of extents in attribute fork*/ - __uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */ - __int8_t di_aformat; /* format of attr fork's data */ - __uint32_t di_dmevmask; /* DMIG event mask */ - __uint16_t di_dmstate; /* DMIG state info */ - __uint16_t di_flags; /* random flags, XFS_DIFLAG_... */ - - __uint64_t di_flags2; /* more random flags */ - __uint32_t di_cowextsize; /* basic cow extent size for file */ - - xfs_ictimestamp_t di_crtime; /* time created */ -}; - -/* - * Inode location information. Stored in the inode and passed to - * xfs_imap_to_bp() to get a buffer and dinode for a given inode. - */ -struct xfs_imap { - xfs_daddr_t im_blkno; /* starting BB of inode chunk */ - ushort im_len; /* length in BBs of inode chunk */ - ushort im_boffset; /* inode offset in block in bytes */ -}; - -int xfs_imap_to_bp(struct xfs_mount *, struct xfs_trans *, - struct xfs_imap *, struct xfs_dinode **, - struct xfs_buf **, uint, uint); -int xfs_iread(struct xfs_mount *, struct xfs_trans *, - struct xfs_inode *, uint); -void xfs_dinode_calc_crc(struct xfs_mount *, struct xfs_dinode *); -void xfs_inode_to_disk(struct xfs_inode *ip, struct xfs_dinode *to, - xfs_lsn_t lsn); -void xfs_inode_from_disk(struct xfs_inode *ip, struct xfs_dinode *from); -void xfs_log_dinode_to_disk(struct xfs_log_dinode *from, - struct xfs_dinode *to); - -bool xfs_dinode_good_version(struct xfs_mount *mp, __u8 version); - -#if defined(DEBUG) -void xfs_inobp_check(struct xfs_mount *, struct xfs_buf *); -#else -#define xfs_inobp_check(mp, bp) -#endif /* DEBUG */ - -#endif /* __XFS_INODE_BUF_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_inode_fork.c b/src/linux/fs/xfs/libxfs/xfs_inode_fork.c deleted file mode 100644 index 5dd56d3..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_inode_fork.c +++ /dev/null @@ -1,1998 +0,0 @@ -/* - * Copyright (c) 2000-2006 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include - -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_bmap_btree.h" -#include "xfs_bmap.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_attr_sf.h" -#include "xfs_da_format.h" - -kmem_zone_t *xfs_ifork_zone; - -STATIC int xfs_iformat_local(xfs_inode_t *, xfs_dinode_t *, int, int); -STATIC int xfs_iformat_extents(xfs_inode_t *, xfs_dinode_t *, int); -STATIC int xfs_iformat_btree(xfs_inode_t *, xfs_dinode_t *, int); - -#ifdef DEBUG -/* - * Make sure that the extents in the given memory buffer - * are valid. - */ -void -xfs_validate_extents( - xfs_ifork_t *ifp, - int nrecs, - xfs_exntfmt_t fmt) -{ - xfs_bmbt_irec_t irec; - xfs_bmbt_rec_host_t rec; - int i; - - for (i = 0; i < nrecs; i++) { - xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); - rec.l0 = get_unaligned(&ep->l0); - rec.l1 = get_unaligned(&ep->l1); - xfs_bmbt_get_all(&rec, &irec); - if (fmt == XFS_EXTFMT_NOSTATE) - ASSERT(irec.br_state == XFS_EXT_NORM); - } -} -#else /* DEBUG */ -#define xfs_validate_extents(ifp, nrecs, fmt) -#endif /* DEBUG */ - - -/* - * Move inode type and inode format specific information from the - * on-disk inode to the in-core inode. For fifos, devs, and sockets - * this means set if_rdev to the proper value. For files, directories, - * and symlinks this means to bring in the in-line data or extent - * pointers. For a file in B-tree format, only the root is immediately - * brought in-core. The rest will be in-lined in if_extents when it - * is first referenced (see xfs_iread_extents()). - */ -int -xfs_iformat_fork( - xfs_inode_t *ip, - xfs_dinode_t *dip) -{ - xfs_attr_shortform_t *atp; - int size; - int error = 0; - xfs_fsize_t di_size; - - if (unlikely(be32_to_cpu(dip->di_nextents) + - be16_to_cpu(dip->di_anextents) > - be64_to_cpu(dip->di_nblocks))) { - xfs_warn(ip->i_mount, - "corrupt dinode %Lu, extent total = %d, nblocks = %Lu.", - (unsigned long long)ip->i_ino, - (int)(be32_to_cpu(dip->di_nextents) + - be16_to_cpu(dip->di_anextents)), - (unsigned long long) - be64_to_cpu(dip->di_nblocks)); - XFS_CORRUPTION_ERROR("xfs_iformat(1)", XFS_ERRLEVEL_LOW, - ip->i_mount, dip); - return -EFSCORRUPTED; - } - - if (unlikely(dip->di_forkoff > ip->i_mount->m_sb.sb_inodesize)) { - xfs_warn(ip->i_mount, "corrupt dinode %Lu, forkoff = 0x%x.", - (unsigned long long)ip->i_ino, - dip->di_forkoff); - XFS_CORRUPTION_ERROR("xfs_iformat(2)", XFS_ERRLEVEL_LOW, - ip->i_mount, dip); - return -EFSCORRUPTED; - } - - if (unlikely((ip->i_d.di_flags & XFS_DIFLAG_REALTIME) && - !ip->i_mount->m_rtdev_targp)) { - xfs_warn(ip->i_mount, - "corrupt dinode %Lu, has realtime flag set.", - ip->i_ino); - XFS_CORRUPTION_ERROR("xfs_iformat(realtime)", - XFS_ERRLEVEL_LOW, ip->i_mount, dip); - return -EFSCORRUPTED; - } - - if (unlikely(xfs_is_reflink_inode(ip) && - (VFS_I(ip)->i_mode & S_IFMT) != S_IFREG)) { - xfs_warn(ip->i_mount, - "corrupt dinode %llu, wrong file type for reflink.", - ip->i_ino); - XFS_CORRUPTION_ERROR("xfs_iformat(reflink)", - XFS_ERRLEVEL_LOW, ip->i_mount, dip); - return -EFSCORRUPTED; - } - - if (unlikely(xfs_is_reflink_inode(ip) && - (ip->i_d.di_flags & XFS_DIFLAG_REALTIME))) { - xfs_warn(ip->i_mount, - "corrupt dinode %llu, has reflink+realtime flag set.", - ip->i_ino); - XFS_CORRUPTION_ERROR("xfs_iformat(reflink)", - XFS_ERRLEVEL_LOW, ip->i_mount, dip); - return -EFSCORRUPTED; - } - - switch (VFS_I(ip)->i_mode & S_IFMT) { - case S_IFIFO: - case S_IFCHR: - case S_IFBLK: - case S_IFSOCK: - if (unlikely(dip->di_format != XFS_DINODE_FMT_DEV)) { - XFS_CORRUPTION_ERROR("xfs_iformat(3)", XFS_ERRLEVEL_LOW, - ip->i_mount, dip); - return -EFSCORRUPTED; - } - ip->i_d.di_size = 0; - ip->i_df.if_u2.if_rdev = xfs_dinode_get_rdev(dip); - break; - - case S_IFREG: - case S_IFLNK: - case S_IFDIR: - switch (dip->di_format) { - case XFS_DINODE_FMT_LOCAL: - /* - * no local regular files yet - */ - if (unlikely(S_ISREG(be16_to_cpu(dip->di_mode)))) { - xfs_warn(ip->i_mount, - "corrupt inode %Lu (local format for regular file).", - (unsigned long long) ip->i_ino); - XFS_CORRUPTION_ERROR("xfs_iformat(4)", - XFS_ERRLEVEL_LOW, - ip->i_mount, dip); - return -EFSCORRUPTED; - } - - di_size = be64_to_cpu(dip->di_size); - if (unlikely(di_size < 0 || - di_size > XFS_DFORK_DSIZE(dip, ip->i_mount))) { - xfs_warn(ip->i_mount, - "corrupt inode %Lu (bad size %Ld for local inode).", - (unsigned long long) ip->i_ino, - (long long) di_size); - XFS_CORRUPTION_ERROR("xfs_iformat(5)", - XFS_ERRLEVEL_LOW, - ip->i_mount, dip); - return -EFSCORRUPTED; - } - - size = (int)di_size; - error = xfs_iformat_local(ip, dip, XFS_DATA_FORK, size); - break; - case XFS_DINODE_FMT_EXTENTS: - error = xfs_iformat_extents(ip, dip, XFS_DATA_FORK); - break; - case XFS_DINODE_FMT_BTREE: - error = xfs_iformat_btree(ip, dip, XFS_DATA_FORK); - break; - default: - XFS_ERROR_REPORT("xfs_iformat(6)", XFS_ERRLEVEL_LOW, - ip->i_mount); - return -EFSCORRUPTED; - } - break; - - default: - XFS_ERROR_REPORT("xfs_iformat(7)", XFS_ERRLEVEL_LOW, ip->i_mount); - return -EFSCORRUPTED; - } - if (error) - return error; - - if (xfs_is_reflink_inode(ip)) { - ASSERT(ip->i_cowfp == NULL); - xfs_ifork_init_cow(ip); - } - - if (!XFS_DFORK_Q(dip)) - return 0; - - ASSERT(ip->i_afp == NULL); - ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP | KM_NOFS); - - switch (dip->di_aformat) { - case XFS_DINODE_FMT_LOCAL: - atp = (xfs_attr_shortform_t *)XFS_DFORK_APTR(dip); - size = be16_to_cpu(atp->hdr.totsize); - - if (unlikely(size < sizeof(struct xfs_attr_sf_hdr))) { - xfs_warn(ip->i_mount, - "corrupt inode %Lu (bad attr fork size %Ld).", - (unsigned long long) ip->i_ino, - (long long) size); - XFS_CORRUPTION_ERROR("xfs_iformat(8)", - XFS_ERRLEVEL_LOW, - ip->i_mount, dip); - error = -EFSCORRUPTED; - break; - } - - error = xfs_iformat_local(ip, dip, XFS_ATTR_FORK, size); - break; - case XFS_DINODE_FMT_EXTENTS: - error = xfs_iformat_extents(ip, dip, XFS_ATTR_FORK); - break; - case XFS_DINODE_FMT_BTREE: - error = xfs_iformat_btree(ip, dip, XFS_ATTR_FORK); - break; - default: - error = -EFSCORRUPTED; - break; - } - if (error) { - kmem_zone_free(xfs_ifork_zone, ip->i_afp); - ip->i_afp = NULL; - if (ip->i_cowfp) - kmem_zone_free(xfs_ifork_zone, ip->i_cowfp); - ip->i_cowfp = NULL; - xfs_idestroy_fork(ip, XFS_DATA_FORK); - } - return error; -} - -void -xfs_init_local_fork( - struct xfs_inode *ip, - int whichfork, - const void *data, - int size) -{ - struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, whichfork); - int mem_size = size, real_size = 0; - bool zero_terminate; - - /* - * If we are using the local fork to store a symlink body we need to - * zero-terminate it so that we can pass it back to the VFS directly. - * Overallocate the in-memory fork by one for that and add a zero - * to terminate it below. - */ - zero_terminate = S_ISLNK(VFS_I(ip)->i_mode); - if (zero_terminate) - mem_size++; - - if (size == 0) - ifp->if_u1.if_data = NULL; - else if (mem_size <= sizeof(ifp->if_u2.if_inline_data)) - ifp->if_u1.if_data = ifp->if_u2.if_inline_data; - else { - real_size = roundup(mem_size, 4); - ifp->if_u1.if_data = kmem_alloc(real_size, KM_SLEEP | KM_NOFS); - } - - if (size) { - memcpy(ifp->if_u1.if_data, data, size); - if (zero_terminate) - ifp->if_u1.if_data[size] = '\0'; - } - - ifp->if_bytes = size; - ifp->if_real_bytes = real_size; - ifp->if_flags &= ~(XFS_IFEXTENTS | XFS_IFBROOT); - ifp->if_flags |= XFS_IFINLINE; -} - -/* - * The file is in-lined in the on-disk inode. - * If it fits into if_inline_data, then copy - * it there, otherwise allocate a buffer for it - * and copy the data there. Either way, set - * if_data to point at the data. - * If we allocate a buffer for the data, make - * sure that its size is a multiple of 4 and - * record the real size in i_real_bytes. - */ -STATIC int -xfs_iformat_local( - xfs_inode_t *ip, - xfs_dinode_t *dip, - int whichfork, - int size) -{ - - /* - * If the size is unreasonable, then something - * is wrong and we just bail out rather than crash in - * kmem_alloc() or memcpy() below. - */ - if (unlikely(size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) { - xfs_warn(ip->i_mount, - "corrupt inode %Lu (bad size %d for local fork, size = %d).", - (unsigned long long) ip->i_ino, size, - XFS_DFORK_SIZE(dip, ip->i_mount, whichfork)); - XFS_CORRUPTION_ERROR("xfs_iformat_local", XFS_ERRLEVEL_LOW, - ip->i_mount, dip); - return -EFSCORRUPTED; - } - - xfs_init_local_fork(ip, whichfork, XFS_DFORK_PTR(dip, whichfork), size); - return 0; -} - -/* - * The file consists of a set of extents all - * of which fit into the on-disk inode. - * If there are few enough extents to fit into - * the if_inline_ext, then copy them there. - * Otherwise allocate a buffer for them and copy - * them into it. Either way, set if_extents - * to point at the extents. - */ -STATIC int -xfs_iformat_extents( - xfs_inode_t *ip, - xfs_dinode_t *dip, - int whichfork) -{ - xfs_bmbt_rec_t *dp; - xfs_ifork_t *ifp; - int nex; - int size; - int i; - - ifp = XFS_IFORK_PTR(ip, whichfork); - nex = XFS_DFORK_NEXTENTS(dip, whichfork); - size = nex * (uint)sizeof(xfs_bmbt_rec_t); - - /* - * If the number of extents is unreasonable, then something - * is wrong and we just bail out rather than crash in - * kmem_alloc() or memcpy() below. - */ - if (unlikely(size < 0 || size > XFS_DFORK_SIZE(dip, ip->i_mount, whichfork))) { - xfs_warn(ip->i_mount, "corrupt inode %Lu ((a)extents = %d).", - (unsigned long long) ip->i_ino, nex); - XFS_CORRUPTION_ERROR("xfs_iformat_extents(1)", XFS_ERRLEVEL_LOW, - ip->i_mount, dip); - return -EFSCORRUPTED; - } - - ifp->if_real_bytes = 0; - if (nex == 0) - ifp->if_u1.if_extents = NULL; - else if (nex <= XFS_INLINE_EXTS) - ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; - else - xfs_iext_add(ifp, 0, nex); - - ifp->if_bytes = size; - if (size) { - dp = (xfs_bmbt_rec_t *) XFS_DFORK_PTR(dip, whichfork); - xfs_validate_extents(ifp, nex, XFS_EXTFMT_INODE(ip)); - for (i = 0; i < nex; i++, dp++) { - xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); - ep->l0 = get_unaligned_be64(&dp->l0); - ep->l1 = get_unaligned_be64(&dp->l1); - } - XFS_BMAP_TRACE_EXLIST(ip, nex, whichfork); - if (whichfork != XFS_DATA_FORK || - XFS_EXTFMT_INODE(ip) == XFS_EXTFMT_NOSTATE) - if (unlikely(xfs_check_nostate_extents( - ifp, 0, nex))) { - XFS_ERROR_REPORT("xfs_iformat_extents(2)", - XFS_ERRLEVEL_LOW, - ip->i_mount); - return -EFSCORRUPTED; - } - } - ifp->if_flags |= XFS_IFEXTENTS; - return 0; -} - -/* - * The file has too many extents to fit into - * the inode, so they are in B-tree format. - * Allocate a buffer for the root of the B-tree - * and copy the root into it. The i_extents - * field will remain NULL until all of the - * extents are read in (when they are needed). - */ -STATIC int -xfs_iformat_btree( - xfs_inode_t *ip, - xfs_dinode_t *dip, - int whichfork) -{ - struct xfs_mount *mp = ip->i_mount; - xfs_bmdr_block_t *dfp; - xfs_ifork_t *ifp; - /* REFERENCED */ - int nrecs; - int size; - - ifp = XFS_IFORK_PTR(ip, whichfork); - dfp = (xfs_bmdr_block_t *)XFS_DFORK_PTR(dip, whichfork); - size = XFS_BMAP_BROOT_SPACE(mp, dfp); - nrecs = be16_to_cpu(dfp->bb_numrecs); - - /* - * blow out if -- fork has less extents than can fit in - * fork (fork shouldn't be a btree format), root btree - * block has more records than can fit into the fork, - * or the number of extents is greater than the number of - * blocks. - */ - if (unlikely(XFS_IFORK_NEXTENTS(ip, whichfork) <= - XFS_IFORK_MAXEXT(ip, whichfork) || - XFS_BMDR_SPACE_CALC(nrecs) > - XFS_DFORK_SIZE(dip, mp, whichfork) || - XFS_IFORK_NEXTENTS(ip, whichfork) > ip->i_d.di_nblocks)) { - xfs_warn(mp, "corrupt inode %Lu (btree).", - (unsigned long long) ip->i_ino); - XFS_CORRUPTION_ERROR("xfs_iformat_btree", XFS_ERRLEVEL_LOW, - mp, dip); - return -EFSCORRUPTED; - } - - ifp->if_broot_bytes = size; - ifp->if_broot = kmem_alloc(size, KM_SLEEP | KM_NOFS); - ASSERT(ifp->if_broot != NULL); - /* - * Copy and convert from the on-disk structure - * to the in-memory structure. - */ - xfs_bmdr_to_bmbt(ip, dfp, XFS_DFORK_SIZE(dip, ip->i_mount, whichfork), - ifp->if_broot, size); - ifp->if_flags &= ~XFS_IFEXTENTS; - ifp->if_flags |= XFS_IFBROOT; - - return 0; -} - -/* - * Read in extents from a btree-format inode. - * Allocate and fill in if_extents. Real work is done in xfs_bmap.c. - */ -int -xfs_iread_extents( - xfs_trans_t *tp, - xfs_inode_t *ip, - int whichfork) -{ - int error; - xfs_ifork_t *ifp; - xfs_extnum_t nextents; - - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - - if (unlikely(XFS_IFORK_FORMAT(ip, whichfork) != XFS_DINODE_FMT_BTREE)) { - XFS_ERROR_REPORT("xfs_iread_extents", XFS_ERRLEVEL_LOW, - ip->i_mount); - return -EFSCORRUPTED; - } - nextents = XFS_IFORK_NEXTENTS(ip, whichfork); - ifp = XFS_IFORK_PTR(ip, whichfork); - - /* - * We know that the size is valid (it's checked in iformat_btree) - */ - ifp->if_bytes = ifp->if_real_bytes = 0; - ifp->if_flags |= XFS_IFEXTENTS; - xfs_iext_add(ifp, 0, nextents); - error = xfs_bmap_read_extents(tp, ip, whichfork); - if (error) { - xfs_iext_destroy(ifp); - ifp->if_flags &= ~XFS_IFEXTENTS; - return error; - } - xfs_validate_extents(ifp, nextents, XFS_EXTFMT_INODE(ip)); - return 0; -} -/* - * Reallocate the space for if_broot based on the number of records - * being added or deleted as indicated in rec_diff. Move the records - * and pointers in if_broot to fit the new size. When shrinking this - * will eliminate holes between the records and pointers created by - * the caller. When growing this will create holes to be filled in - * by the caller. - * - * The caller must not request to add more records than would fit in - * the on-disk inode root. If the if_broot is currently NULL, then - * if we are adding records, one will be allocated. The caller must also - * not request that the number of records go below zero, although - * it can go to zero. - * - * ip -- the inode whose if_broot area is changing - * ext_diff -- the change in the number of records, positive or negative, - * requested for the if_broot array. - */ -void -xfs_iroot_realloc( - xfs_inode_t *ip, - int rec_diff, - int whichfork) -{ - struct xfs_mount *mp = ip->i_mount; - int cur_max; - xfs_ifork_t *ifp; - struct xfs_btree_block *new_broot; - int new_max; - size_t new_size; - char *np; - char *op; - - /* - * Handle the degenerate case quietly. - */ - if (rec_diff == 0) { - return; - } - - ifp = XFS_IFORK_PTR(ip, whichfork); - if (rec_diff > 0) { - /* - * If there wasn't any memory allocated before, just - * allocate it now and get out. - */ - if (ifp->if_broot_bytes == 0) { - new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, rec_diff); - ifp->if_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS); - ifp->if_broot_bytes = (int)new_size; - return; - } - - /* - * If there is already an existing if_broot, then we need - * to realloc() it and shift the pointers to their new - * location. The records don't change location because - * they are kept butted up against the btree block header. - */ - cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0); - new_max = cur_max + rec_diff; - new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max); - ifp->if_broot = kmem_realloc(ifp->if_broot, new_size, - KM_SLEEP | KM_NOFS); - op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1, - ifp->if_broot_bytes); - np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1, - (int)new_size); - ifp->if_broot_bytes = (int)new_size; - ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <= - XFS_IFORK_SIZE(ip, whichfork)); - memmove(np, op, cur_max * (uint)sizeof(xfs_fsblock_t)); - return; - } - - /* - * rec_diff is less than 0. In this case, we are shrinking the - * if_broot buffer. It must already exist. If we go to zero - * records, just get rid of the root and clear the status bit. - */ - ASSERT((ifp->if_broot != NULL) && (ifp->if_broot_bytes > 0)); - cur_max = xfs_bmbt_maxrecs(mp, ifp->if_broot_bytes, 0); - new_max = cur_max + rec_diff; - ASSERT(new_max >= 0); - if (new_max > 0) - new_size = XFS_BMAP_BROOT_SPACE_CALC(mp, new_max); - else - new_size = 0; - if (new_size > 0) { - new_broot = kmem_alloc(new_size, KM_SLEEP | KM_NOFS); - /* - * First copy over the btree block header. - */ - memcpy(new_broot, ifp->if_broot, - XFS_BMBT_BLOCK_LEN(ip->i_mount)); - } else { - new_broot = NULL; - ifp->if_flags &= ~XFS_IFBROOT; - } - - /* - * Only copy the records and pointers if there are any. - */ - if (new_max > 0) { - /* - * First copy the records. - */ - op = (char *)XFS_BMBT_REC_ADDR(mp, ifp->if_broot, 1); - np = (char *)XFS_BMBT_REC_ADDR(mp, new_broot, 1); - memcpy(np, op, new_max * (uint)sizeof(xfs_bmbt_rec_t)); - - /* - * Then copy the pointers. - */ - op = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, ifp->if_broot, 1, - ifp->if_broot_bytes); - np = (char *)XFS_BMAP_BROOT_PTR_ADDR(mp, new_broot, 1, - (int)new_size); - memcpy(np, op, new_max * (uint)sizeof(xfs_fsblock_t)); - } - kmem_free(ifp->if_broot); - ifp->if_broot = new_broot; - ifp->if_broot_bytes = (int)new_size; - if (ifp->if_broot) - ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <= - XFS_IFORK_SIZE(ip, whichfork)); - return; -} - - -/* - * This is called when the amount of space needed for if_data - * is increased or decreased. The change in size is indicated by - * the number of bytes that need to be added or deleted in the - * byte_diff parameter. - * - * If the amount of space needed has decreased below the size of the - * inline buffer, then switch to using the inline buffer. Otherwise, - * use kmem_realloc() or kmem_alloc() to adjust the size of the buffer - * to what is needed. - * - * ip -- the inode whose if_data area is changing - * byte_diff -- the change in the number of bytes, positive or negative, - * requested for the if_data array. - */ -void -xfs_idata_realloc( - xfs_inode_t *ip, - int byte_diff, - int whichfork) -{ - xfs_ifork_t *ifp; - int new_size; - int real_size; - - if (byte_diff == 0) { - return; - } - - ifp = XFS_IFORK_PTR(ip, whichfork); - new_size = (int)ifp->if_bytes + byte_diff; - ASSERT(new_size >= 0); - - if (new_size == 0) { - if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { - kmem_free(ifp->if_u1.if_data); - } - ifp->if_u1.if_data = NULL; - real_size = 0; - } else if (new_size <= sizeof(ifp->if_u2.if_inline_data)) { - /* - * If the valid extents/data can fit in if_inline_ext/data, - * copy them from the malloc'd vector and free it. - */ - if (ifp->if_u1.if_data == NULL) { - ifp->if_u1.if_data = ifp->if_u2.if_inline_data; - } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { - ASSERT(ifp->if_real_bytes != 0); - memcpy(ifp->if_u2.if_inline_data, ifp->if_u1.if_data, - new_size); - kmem_free(ifp->if_u1.if_data); - ifp->if_u1.if_data = ifp->if_u2.if_inline_data; - } - real_size = 0; - } else { - /* - * Stuck with malloc/realloc. - * For inline data, the underlying buffer must be - * a multiple of 4 bytes in size so that it can be - * logged and stay on word boundaries. We enforce - * that here. - */ - real_size = roundup(new_size, 4); - if (ifp->if_u1.if_data == NULL) { - ASSERT(ifp->if_real_bytes == 0); - ifp->if_u1.if_data = kmem_alloc(real_size, - KM_SLEEP | KM_NOFS); - } else if (ifp->if_u1.if_data != ifp->if_u2.if_inline_data) { - /* - * Only do the realloc if the underlying size - * is really changing. - */ - if (ifp->if_real_bytes != real_size) { - ifp->if_u1.if_data = - kmem_realloc(ifp->if_u1.if_data, - real_size, - KM_SLEEP | KM_NOFS); - } - } else { - ASSERT(ifp->if_real_bytes == 0); - ifp->if_u1.if_data = kmem_alloc(real_size, - KM_SLEEP | KM_NOFS); - memcpy(ifp->if_u1.if_data, ifp->if_u2.if_inline_data, - ifp->if_bytes); - } - } - ifp->if_real_bytes = real_size; - ifp->if_bytes = new_size; - ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); -} - -void -xfs_idestroy_fork( - xfs_inode_t *ip, - int whichfork) -{ - xfs_ifork_t *ifp; - - ifp = XFS_IFORK_PTR(ip, whichfork); - if (ifp->if_broot != NULL) { - kmem_free(ifp->if_broot); - ifp->if_broot = NULL; - } - - /* - * If the format is local, then we can't have an extents - * array so just look for an inline data array. If we're - * not local then we may or may not have an extents list, - * so check and free it up if we do. - */ - if (XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL) { - if ((ifp->if_u1.if_data != ifp->if_u2.if_inline_data) && - (ifp->if_u1.if_data != NULL)) { - ASSERT(ifp->if_real_bytes != 0); - kmem_free(ifp->if_u1.if_data); - ifp->if_u1.if_data = NULL; - ifp->if_real_bytes = 0; - } - } else if ((ifp->if_flags & XFS_IFEXTENTS) && - ((ifp->if_flags & XFS_IFEXTIREC) || - ((ifp->if_u1.if_extents != NULL) && - (ifp->if_u1.if_extents != ifp->if_u2.if_inline_ext)))) { - ASSERT(ifp->if_real_bytes != 0); - xfs_iext_destroy(ifp); - } - ASSERT(ifp->if_u1.if_extents == NULL || - ifp->if_u1.if_extents == ifp->if_u2.if_inline_ext); - ASSERT(ifp->if_real_bytes == 0); - if (whichfork == XFS_ATTR_FORK) { - kmem_zone_free(xfs_ifork_zone, ip->i_afp); - ip->i_afp = NULL; - } else if (whichfork == XFS_COW_FORK) { - kmem_zone_free(xfs_ifork_zone, ip->i_cowfp); - ip->i_cowfp = NULL; - } -} - -/* - * Convert in-core extents to on-disk form - * - * For either the data or attr fork in extent format, we need to endian convert - * the in-core extent as we place them into the on-disk inode. - * - * In the case of the data fork, the in-core and on-disk fork sizes can be - * different due to delayed allocation extents. We only copy on-disk extents - * here, so callers must always use the physical fork size to determine the - * size of the buffer passed to this routine. We will return the size actually - * used. - */ -int -xfs_iextents_copy( - xfs_inode_t *ip, - xfs_bmbt_rec_t *dp, - int whichfork) -{ - int copied; - int i; - xfs_ifork_t *ifp; - int nrecs; - xfs_fsblock_t start_block; - - ifp = XFS_IFORK_PTR(ip, whichfork); - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); - ASSERT(ifp->if_bytes > 0); - - nrecs = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); - XFS_BMAP_TRACE_EXLIST(ip, nrecs, whichfork); - ASSERT(nrecs > 0); - - /* - * There are some delayed allocation extents in the - * inode, so copy the extents one at a time and skip - * the delayed ones. There must be at least one - * non-delayed extent. - */ - copied = 0; - for (i = 0; i < nrecs; i++) { - xfs_bmbt_rec_host_t *ep = xfs_iext_get_ext(ifp, i); - start_block = xfs_bmbt_get_startblock(ep); - if (isnullstartblock(start_block)) { - /* - * It's a delayed allocation extent, so skip it. - */ - continue; - } - - /* Translate to on disk format */ - put_unaligned_be64(ep->l0, &dp->l0); - put_unaligned_be64(ep->l1, &dp->l1); - dp++; - copied++; - } - ASSERT(copied != 0); - xfs_validate_extents(ifp, copied, XFS_EXTFMT_INODE(ip)); - - return (copied * (uint)sizeof(xfs_bmbt_rec_t)); -} - -/* - * Each of the following cases stores data into the same region - * of the on-disk inode, so only one of them can be valid at - * any given time. While it is possible to have conflicting formats - * and log flags, e.g. having XFS_ILOG_?DATA set when the fork is - * in EXTENTS format, this can only happen when the fork has - * changed formats after being modified but before being flushed. - * In these cases, the format always takes precedence, because the - * format indicates the current state of the fork. - */ -void -xfs_iflush_fork( - xfs_inode_t *ip, - xfs_dinode_t *dip, - xfs_inode_log_item_t *iip, - int whichfork) -{ - char *cp; - xfs_ifork_t *ifp; - xfs_mount_t *mp; - static const short brootflag[2] = - { XFS_ILOG_DBROOT, XFS_ILOG_ABROOT }; - static const short dataflag[2] = - { XFS_ILOG_DDATA, XFS_ILOG_ADATA }; - static const short extflag[2] = - { XFS_ILOG_DEXT, XFS_ILOG_AEXT }; - - if (!iip) - return; - ifp = XFS_IFORK_PTR(ip, whichfork); - /* - * This can happen if we gave up in iformat in an error path, - * for the attribute fork. - */ - if (!ifp) { - ASSERT(whichfork == XFS_ATTR_FORK); - return; - } - cp = XFS_DFORK_PTR(dip, whichfork); - mp = ip->i_mount; - switch (XFS_IFORK_FORMAT(ip, whichfork)) { - case XFS_DINODE_FMT_LOCAL: - if ((iip->ili_fields & dataflag[whichfork]) && - (ifp->if_bytes > 0)) { - ASSERT(ifp->if_u1.if_data != NULL); - ASSERT(ifp->if_bytes <= XFS_IFORK_SIZE(ip, whichfork)); - memcpy(cp, ifp->if_u1.if_data, ifp->if_bytes); - } - break; - - case XFS_DINODE_FMT_EXTENTS: - ASSERT((ifp->if_flags & XFS_IFEXTENTS) || - !(iip->ili_fields & extflag[whichfork])); - if ((iip->ili_fields & extflag[whichfork]) && - (ifp->if_bytes > 0)) { - ASSERT(xfs_iext_get_ext(ifp, 0)); - ASSERT(XFS_IFORK_NEXTENTS(ip, whichfork) > 0); - (void)xfs_iextents_copy(ip, (xfs_bmbt_rec_t *)cp, - whichfork); - } - break; - - case XFS_DINODE_FMT_BTREE: - if ((iip->ili_fields & brootflag[whichfork]) && - (ifp->if_broot_bytes > 0)) { - ASSERT(ifp->if_broot != NULL); - ASSERT(XFS_BMAP_BMDR_SPACE(ifp->if_broot) <= - XFS_IFORK_SIZE(ip, whichfork)); - xfs_bmbt_to_bmdr(mp, ifp->if_broot, ifp->if_broot_bytes, - (xfs_bmdr_block_t *)cp, - XFS_DFORK_SIZE(dip, mp, whichfork)); - } - break; - - case XFS_DINODE_FMT_DEV: - if (iip->ili_fields & XFS_ILOG_DEV) { - ASSERT(whichfork == XFS_DATA_FORK); - xfs_dinode_put_rdev(dip, ip->i_df.if_u2.if_rdev); - } - break; - - case XFS_DINODE_FMT_UUID: - if (iip->ili_fields & XFS_ILOG_UUID) { - ASSERT(whichfork == XFS_DATA_FORK); - memcpy(XFS_DFORK_DPTR(dip), - &ip->i_df.if_u2.if_uuid, - sizeof(uuid_t)); - } - break; - - default: - ASSERT(0); - break; - } -} - -/* - * Return a pointer to the extent record at file index idx. - */ -xfs_bmbt_rec_host_t * -xfs_iext_get_ext( - xfs_ifork_t *ifp, /* inode fork pointer */ - xfs_extnum_t idx) /* index of target extent */ -{ - ASSERT(idx >= 0); - ASSERT(idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t)); - - if ((ifp->if_flags & XFS_IFEXTIREC) && (idx == 0)) { - return ifp->if_u1.if_ext_irec->er_extbuf; - } else if (ifp->if_flags & XFS_IFEXTIREC) { - xfs_ext_irec_t *erp; /* irec pointer */ - int erp_idx = 0; /* irec index */ - xfs_extnum_t page_idx = idx; /* ext index in target list */ - - erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 0); - return &erp->er_extbuf[page_idx]; - } else if (ifp->if_bytes) { - return &ifp->if_u1.if_extents[idx]; - } else { - return NULL; - } -} - -/* Convert bmap state flags to an inode fork. */ -struct xfs_ifork * -xfs_iext_state_to_fork( - struct xfs_inode *ip, - int state) -{ - if (state & BMAP_COWFORK) - return ip->i_cowfp; - else if (state & BMAP_ATTRFORK) - return ip->i_afp; - return &ip->i_df; -} - -/* - * Insert new item(s) into the extent records for incore inode - * fork 'ifp'. 'count' new items are inserted at index 'idx'. - */ -void -xfs_iext_insert( - xfs_inode_t *ip, /* incore inode pointer */ - xfs_extnum_t idx, /* starting index of new items */ - xfs_extnum_t count, /* number of inserted items */ - xfs_bmbt_irec_t *new, /* items to insert */ - int state) /* type of extent conversion */ -{ - xfs_ifork_t *ifp = xfs_iext_state_to_fork(ip, state); - xfs_extnum_t i; /* extent record index */ - - trace_xfs_iext_insert(ip, idx, new, state, _RET_IP_); - - ASSERT(ifp->if_flags & XFS_IFEXTENTS); - xfs_iext_add(ifp, idx, count); - for (i = idx; i < idx + count; i++, new++) - xfs_bmbt_set_all(xfs_iext_get_ext(ifp, i), new); -} - -/* - * This is called when the amount of space required for incore file - * extents needs to be increased. The ext_diff parameter stores the - * number of new extents being added and the idx parameter contains - * the extent index where the new extents will be added. If the new - * extents are being appended, then we just need to (re)allocate and - * initialize the space. Otherwise, if the new extents are being - * inserted into the middle of the existing entries, a bit more work - * is required to make room for the new extents to be inserted. The - * caller is responsible for filling in the new extent entries upon - * return. - */ -void -xfs_iext_add( - xfs_ifork_t *ifp, /* inode fork pointer */ - xfs_extnum_t idx, /* index to begin adding exts */ - int ext_diff) /* number of extents to add */ -{ - int byte_diff; /* new bytes being added */ - int new_size; /* size of extents after adding */ - xfs_extnum_t nextents; /* number of extents in file */ - - nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); - ASSERT((idx >= 0) && (idx <= nextents)); - byte_diff = ext_diff * sizeof(xfs_bmbt_rec_t); - new_size = ifp->if_bytes + byte_diff; - /* - * If the new number of extents (nextents + ext_diff) - * fits inside the inode, then continue to use the inline - * extent buffer. - */ - if (nextents + ext_diff <= XFS_INLINE_EXTS) { - if (idx < nextents) { - memmove(&ifp->if_u2.if_inline_ext[idx + ext_diff], - &ifp->if_u2.if_inline_ext[idx], - (nextents - idx) * sizeof(xfs_bmbt_rec_t)); - memset(&ifp->if_u2.if_inline_ext[idx], 0, byte_diff); - } - ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; - ifp->if_real_bytes = 0; - } - /* - * Otherwise use a linear (direct) extent list. - * If the extents are currently inside the inode, - * xfs_iext_realloc_direct will switch us from - * inline to direct extent allocation mode. - */ - else if (nextents + ext_diff <= XFS_LINEAR_EXTS) { - xfs_iext_realloc_direct(ifp, new_size); - if (idx < nextents) { - memmove(&ifp->if_u1.if_extents[idx + ext_diff], - &ifp->if_u1.if_extents[idx], - (nextents - idx) * sizeof(xfs_bmbt_rec_t)); - memset(&ifp->if_u1.if_extents[idx], 0, byte_diff); - } - } - /* Indirection array */ - else { - xfs_ext_irec_t *erp; - int erp_idx = 0; - int page_idx = idx; - - ASSERT(nextents + ext_diff > XFS_LINEAR_EXTS); - if (ifp->if_flags & XFS_IFEXTIREC) { - erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 1); - } else { - xfs_iext_irec_init(ifp); - ASSERT(ifp->if_flags & XFS_IFEXTIREC); - erp = ifp->if_u1.if_ext_irec; - } - /* Extents fit in target extent page */ - if (erp && erp->er_extcount + ext_diff <= XFS_LINEAR_EXTS) { - if (page_idx < erp->er_extcount) { - memmove(&erp->er_extbuf[page_idx + ext_diff], - &erp->er_extbuf[page_idx], - (erp->er_extcount - page_idx) * - sizeof(xfs_bmbt_rec_t)); - memset(&erp->er_extbuf[page_idx], 0, byte_diff); - } - erp->er_extcount += ext_diff; - xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff); - } - /* Insert a new extent page */ - else if (erp) { - xfs_iext_add_indirect_multi(ifp, - erp_idx, page_idx, ext_diff); - } - /* - * If extent(s) are being appended to the last page in - * the indirection array and the new extent(s) don't fit - * in the page, then erp is NULL and erp_idx is set to - * the next index needed in the indirection array. - */ - else { - uint count = ext_diff; - - while (count) { - erp = xfs_iext_irec_new(ifp, erp_idx); - erp->er_extcount = min(count, XFS_LINEAR_EXTS); - count -= erp->er_extcount; - if (count) - erp_idx++; - } - } - } - ifp->if_bytes = new_size; -} - -/* - * This is called when incore extents are being added to the indirection - * array and the new extents do not fit in the target extent list. The - * erp_idx parameter contains the irec index for the target extent list - * in the indirection array, and the idx parameter contains the extent - * index within the list. The number of extents being added is stored - * in the count parameter. - * - * |-------| |-------| - * | | | | idx - number of extents before idx - * | idx | | count | - * | | | | count - number of extents being inserted at idx - * |-------| |-------| - * | count | | nex2 | nex2 - number of extents after idx + count - * |-------| |-------| - */ -void -xfs_iext_add_indirect_multi( - xfs_ifork_t *ifp, /* inode fork pointer */ - int erp_idx, /* target extent irec index */ - xfs_extnum_t idx, /* index within target list */ - int count) /* new extents being added */ -{ - int byte_diff; /* new bytes being added */ - xfs_ext_irec_t *erp; /* pointer to irec entry */ - xfs_extnum_t ext_diff; /* number of extents to add */ - xfs_extnum_t ext_cnt; /* new extents still needed */ - xfs_extnum_t nex2; /* extents after idx + count */ - xfs_bmbt_rec_t *nex2_ep = NULL; /* temp list for nex2 extents */ - int nlists; /* number of irec's (lists) */ - - ASSERT(ifp->if_flags & XFS_IFEXTIREC); - erp = &ifp->if_u1.if_ext_irec[erp_idx]; - nex2 = erp->er_extcount - idx; - nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; - - /* - * Save second part of target extent list - * (all extents past */ - if (nex2) { - byte_diff = nex2 * sizeof(xfs_bmbt_rec_t); - nex2_ep = (xfs_bmbt_rec_t *) kmem_alloc(byte_diff, KM_NOFS); - memmove(nex2_ep, &erp->er_extbuf[idx], byte_diff); - erp->er_extcount -= nex2; - xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -nex2); - memset(&erp->er_extbuf[idx], 0, byte_diff); - } - - /* - * Add the new extents to the end of the target - * list, then allocate new irec record(s) and - * extent buffer(s) as needed to store the rest - * of the new extents. - */ - ext_cnt = count; - ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS - erp->er_extcount); - if (ext_diff) { - erp->er_extcount += ext_diff; - xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff); - ext_cnt -= ext_diff; - } - while (ext_cnt) { - erp_idx++; - erp = xfs_iext_irec_new(ifp, erp_idx); - ext_diff = MIN(ext_cnt, (int)XFS_LINEAR_EXTS); - erp->er_extcount = ext_diff; - xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, ext_diff); - ext_cnt -= ext_diff; - } - - /* Add nex2 extents back to indirection array */ - if (nex2) { - xfs_extnum_t ext_avail; - int i; - - byte_diff = nex2 * sizeof(xfs_bmbt_rec_t); - ext_avail = XFS_LINEAR_EXTS - erp->er_extcount; - i = 0; - /* - * If nex2 extents fit in the current page, append - * nex2_ep after the new extents. - */ - if (nex2 <= ext_avail) { - i = erp->er_extcount; - } - /* - * Otherwise, check if space is available in the - * next page. - */ - else if ((erp_idx < nlists - 1) && - (nex2 <= (ext_avail = XFS_LINEAR_EXTS - - ifp->if_u1.if_ext_irec[erp_idx+1].er_extcount))) { - erp_idx++; - erp++; - /* Create a hole for nex2 extents */ - memmove(&erp->er_extbuf[nex2], erp->er_extbuf, - erp->er_extcount * sizeof(xfs_bmbt_rec_t)); - } - /* - * Final choice, create a new extent page for - * nex2 extents. - */ - else { - erp_idx++; - erp = xfs_iext_irec_new(ifp, erp_idx); - } - memmove(&erp->er_extbuf[i], nex2_ep, byte_diff); - kmem_free(nex2_ep); - erp->er_extcount += nex2; - xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, nex2); - } -} - -/* - * This is called when the amount of space required for incore file - * extents needs to be decreased. The ext_diff parameter stores the - * number of extents to be removed and the idx parameter contains - * the extent index where the extents will be removed from. - * - * If the amount of space needed has decreased below the linear - * limit, XFS_IEXT_BUFSZ, then switch to using the contiguous - * extent array. Otherwise, use kmem_realloc() to adjust the - * size to what is needed. - */ -void -xfs_iext_remove( - xfs_inode_t *ip, /* incore inode pointer */ - xfs_extnum_t idx, /* index to begin removing exts */ - int ext_diff, /* number of extents to remove */ - int state) /* type of extent conversion */ -{ - xfs_ifork_t *ifp = xfs_iext_state_to_fork(ip, state); - xfs_extnum_t nextents; /* number of extents in file */ - int new_size; /* size of extents after removal */ - - trace_xfs_iext_remove(ip, idx, state, _RET_IP_); - - ASSERT(ext_diff > 0); - nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); - new_size = (nextents - ext_diff) * sizeof(xfs_bmbt_rec_t); - - if (new_size == 0) { - xfs_iext_destroy(ifp); - } else if (ifp->if_flags & XFS_IFEXTIREC) { - xfs_iext_remove_indirect(ifp, idx, ext_diff); - } else if (ifp->if_real_bytes) { - xfs_iext_remove_direct(ifp, idx, ext_diff); - } else { - xfs_iext_remove_inline(ifp, idx, ext_diff); - } - ifp->if_bytes = new_size; -} - -/* - * This removes ext_diff extents from the inline buffer, beginning - * at extent index idx. - */ -void -xfs_iext_remove_inline( - xfs_ifork_t *ifp, /* inode fork pointer */ - xfs_extnum_t idx, /* index to begin removing exts */ - int ext_diff) /* number of extents to remove */ -{ - int nextents; /* number of extents in file */ - - ASSERT(!(ifp->if_flags & XFS_IFEXTIREC)); - ASSERT(idx < XFS_INLINE_EXTS); - nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); - ASSERT(((nextents - ext_diff) > 0) && - (nextents - ext_diff) < XFS_INLINE_EXTS); - - if (idx + ext_diff < nextents) { - memmove(&ifp->if_u2.if_inline_ext[idx], - &ifp->if_u2.if_inline_ext[idx + ext_diff], - (nextents - (idx + ext_diff)) * - sizeof(xfs_bmbt_rec_t)); - memset(&ifp->if_u2.if_inline_ext[nextents - ext_diff], - 0, ext_diff * sizeof(xfs_bmbt_rec_t)); - } else { - memset(&ifp->if_u2.if_inline_ext[idx], 0, - ext_diff * sizeof(xfs_bmbt_rec_t)); - } -} - -/* - * This removes ext_diff extents from a linear (direct) extent list, - * beginning at extent index idx. If the extents are being removed - * from the end of the list (ie. truncate) then we just need to re- - * allocate the list to remove the extra space. Otherwise, if the - * extents are being removed from the middle of the existing extent - * entries, then we first need to move the extent records beginning - * at idx + ext_diff up in the list to overwrite the records being - * removed, then remove the extra space via kmem_realloc. - */ -void -xfs_iext_remove_direct( - xfs_ifork_t *ifp, /* inode fork pointer */ - xfs_extnum_t idx, /* index to begin removing exts */ - int ext_diff) /* number of extents to remove */ -{ - xfs_extnum_t nextents; /* number of extents in file */ - int new_size; /* size of extents after removal */ - - ASSERT(!(ifp->if_flags & XFS_IFEXTIREC)); - new_size = ifp->if_bytes - - (ext_diff * sizeof(xfs_bmbt_rec_t)); - nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); - - if (new_size == 0) { - xfs_iext_destroy(ifp); - return; - } - /* Move extents up in the list (if needed) */ - if (idx + ext_diff < nextents) { - memmove(&ifp->if_u1.if_extents[idx], - &ifp->if_u1.if_extents[idx + ext_diff], - (nextents - (idx + ext_diff)) * - sizeof(xfs_bmbt_rec_t)); - } - memset(&ifp->if_u1.if_extents[nextents - ext_diff], - 0, ext_diff * sizeof(xfs_bmbt_rec_t)); - /* - * Reallocate the direct extent list. If the extents - * will fit inside the inode then xfs_iext_realloc_direct - * will switch from direct to inline extent allocation - * mode for us. - */ - xfs_iext_realloc_direct(ifp, new_size); - ifp->if_bytes = new_size; -} - -/* - * This is called when incore extents are being removed from the - * indirection array and the extents being removed span multiple extent - * buffers. The idx parameter contains the file extent index where we - * want to begin removing extents, and the count parameter contains - * how many extents need to be removed. - * - * |-------| |-------| - * | nex1 | | | nex1 - number of extents before idx - * |-------| | count | - * | | | | count - number of extents being removed at idx - * | count | |-------| - * | | | nex2 | nex2 - number of extents after idx + count - * |-------| |-------| - */ -void -xfs_iext_remove_indirect( - xfs_ifork_t *ifp, /* inode fork pointer */ - xfs_extnum_t idx, /* index to begin removing extents */ - int count) /* number of extents to remove */ -{ - xfs_ext_irec_t *erp; /* indirection array pointer */ - int erp_idx = 0; /* indirection array index */ - xfs_extnum_t ext_cnt; /* extents left to remove */ - xfs_extnum_t ext_diff; /* extents to remove in current list */ - xfs_extnum_t nex1; /* number of extents before idx */ - xfs_extnum_t nex2; /* extents after idx + count */ - int page_idx = idx; /* index in target extent list */ - - ASSERT(ifp->if_flags & XFS_IFEXTIREC); - erp = xfs_iext_idx_to_irec(ifp, &page_idx, &erp_idx, 0); - ASSERT(erp != NULL); - nex1 = page_idx; - ext_cnt = count; - while (ext_cnt) { - nex2 = MAX((erp->er_extcount - (nex1 + ext_cnt)), 0); - ext_diff = MIN(ext_cnt, (erp->er_extcount - nex1)); - /* - * Check for deletion of entire list; - * xfs_iext_irec_remove() updates extent offsets. - */ - if (ext_diff == erp->er_extcount) { - xfs_iext_irec_remove(ifp, erp_idx); - ext_cnt -= ext_diff; - nex1 = 0; - if (ext_cnt) { - ASSERT(erp_idx < ifp->if_real_bytes / - XFS_IEXT_BUFSZ); - erp = &ifp->if_u1.if_ext_irec[erp_idx]; - nex1 = 0; - continue; - } else { - break; - } - } - /* Move extents up (if needed) */ - if (nex2) { - memmove(&erp->er_extbuf[nex1], - &erp->er_extbuf[nex1 + ext_diff], - nex2 * sizeof(xfs_bmbt_rec_t)); - } - /* Zero out rest of page */ - memset(&erp->er_extbuf[nex1 + nex2], 0, (XFS_IEXT_BUFSZ - - ((nex1 + nex2) * sizeof(xfs_bmbt_rec_t)))); - /* Update remaining counters */ - erp->er_extcount -= ext_diff; - xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, -ext_diff); - ext_cnt -= ext_diff; - nex1 = 0; - erp_idx++; - erp++; - } - ifp->if_bytes -= count * sizeof(xfs_bmbt_rec_t); - xfs_iext_irec_compact(ifp); -} - -/* - * Create, destroy, or resize a linear (direct) block of extents. - */ -void -xfs_iext_realloc_direct( - xfs_ifork_t *ifp, /* inode fork pointer */ - int new_size) /* new size of extents after adding */ -{ - int rnew_size; /* real new size of extents */ - - rnew_size = new_size; - - ASSERT(!(ifp->if_flags & XFS_IFEXTIREC) || - ((new_size >= 0) && (new_size <= XFS_IEXT_BUFSZ) && - (new_size != ifp->if_real_bytes))); - - /* Free extent records */ - if (new_size == 0) { - xfs_iext_destroy(ifp); - } - /* Resize direct extent list and zero any new bytes */ - else if (ifp->if_real_bytes) { - /* Check if extents will fit inside the inode */ - if (new_size <= XFS_INLINE_EXTS * sizeof(xfs_bmbt_rec_t)) { - xfs_iext_direct_to_inline(ifp, new_size / - (uint)sizeof(xfs_bmbt_rec_t)); - ifp->if_bytes = new_size; - return; - } - if (!is_power_of_2(new_size)){ - rnew_size = roundup_pow_of_two(new_size); - } - if (rnew_size != ifp->if_real_bytes) { - ifp->if_u1.if_extents = - kmem_realloc(ifp->if_u1.if_extents, - rnew_size, KM_NOFS); - } - if (rnew_size > ifp->if_real_bytes) { - memset(&ifp->if_u1.if_extents[ifp->if_bytes / - (uint)sizeof(xfs_bmbt_rec_t)], 0, - rnew_size - ifp->if_real_bytes); - } - } - /* Switch from the inline extent buffer to a direct extent list */ - else { - if (!is_power_of_2(new_size)) { - rnew_size = roundup_pow_of_two(new_size); - } - xfs_iext_inline_to_direct(ifp, rnew_size); - } - ifp->if_real_bytes = rnew_size; - ifp->if_bytes = new_size; -} - -/* - * Switch from linear (direct) extent records to inline buffer. - */ -void -xfs_iext_direct_to_inline( - xfs_ifork_t *ifp, /* inode fork pointer */ - xfs_extnum_t nextents) /* number of extents in file */ -{ - ASSERT(ifp->if_flags & XFS_IFEXTENTS); - ASSERT(nextents <= XFS_INLINE_EXTS); - /* - * The inline buffer was zeroed when we switched - * from inline to direct extent allocation mode, - * so we don't need to clear it here. - */ - memcpy(ifp->if_u2.if_inline_ext, ifp->if_u1.if_extents, - nextents * sizeof(xfs_bmbt_rec_t)); - kmem_free(ifp->if_u1.if_extents); - ifp->if_u1.if_extents = ifp->if_u2.if_inline_ext; - ifp->if_real_bytes = 0; -} - -/* - * Switch from inline buffer to linear (direct) extent records. - * new_size should already be rounded up to the next power of 2 - * by the caller (when appropriate), so use new_size as it is. - * However, since new_size may be rounded up, we can't update - * if_bytes here. It is the caller's responsibility to update - * if_bytes upon return. - */ -void -xfs_iext_inline_to_direct( - xfs_ifork_t *ifp, /* inode fork pointer */ - int new_size) /* number of extents in file */ -{ - ifp->if_u1.if_extents = kmem_alloc(new_size, KM_NOFS); - memset(ifp->if_u1.if_extents, 0, new_size); - if (ifp->if_bytes) { - memcpy(ifp->if_u1.if_extents, ifp->if_u2.if_inline_ext, - ifp->if_bytes); - memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS * - sizeof(xfs_bmbt_rec_t)); - } - ifp->if_real_bytes = new_size; -} - -/* - * Resize an extent indirection array to new_size bytes. - */ -STATIC void -xfs_iext_realloc_indirect( - xfs_ifork_t *ifp, /* inode fork pointer */ - int new_size) /* new indirection array size */ -{ - int nlists; /* number of irec's (ex lists) */ - int size; /* current indirection array size */ - - ASSERT(ifp->if_flags & XFS_IFEXTIREC); - nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; - size = nlists * sizeof(xfs_ext_irec_t); - ASSERT(ifp->if_real_bytes); - ASSERT((new_size >= 0) && (new_size != size)); - if (new_size == 0) { - xfs_iext_destroy(ifp); - } else { - ifp->if_u1.if_ext_irec = - kmem_realloc(ifp->if_u1.if_ext_irec, new_size, KM_NOFS); - } -} - -/* - * Switch from indirection array to linear (direct) extent allocations. - */ -STATIC void -xfs_iext_indirect_to_direct( - xfs_ifork_t *ifp) /* inode fork pointer */ -{ - xfs_bmbt_rec_host_t *ep; /* extent record pointer */ - xfs_extnum_t nextents; /* number of extents in file */ - int size; /* size of file extents */ - - ASSERT(ifp->if_flags & XFS_IFEXTIREC); - nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); - ASSERT(nextents <= XFS_LINEAR_EXTS); - size = nextents * sizeof(xfs_bmbt_rec_t); - - xfs_iext_irec_compact_pages(ifp); - ASSERT(ifp->if_real_bytes == XFS_IEXT_BUFSZ); - - ep = ifp->if_u1.if_ext_irec->er_extbuf; - kmem_free(ifp->if_u1.if_ext_irec); - ifp->if_flags &= ~XFS_IFEXTIREC; - ifp->if_u1.if_extents = ep; - ifp->if_bytes = size; - if (nextents < XFS_LINEAR_EXTS) { - xfs_iext_realloc_direct(ifp, size); - } -} - -/* - * Remove all records from the indirection array. - */ -STATIC void -xfs_iext_irec_remove_all( - struct xfs_ifork *ifp) -{ - int nlists; - int i; - - ASSERT(ifp->if_flags & XFS_IFEXTIREC); - nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; - for (i = 0; i < nlists; i++) - kmem_free(ifp->if_u1.if_ext_irec[i].er_extbuf); - kmem_free(ifp->if_u1.if_ext_irec); - ifp->if_flags &= ~XFS_IFEXTIREC; -} - -/* - * Free incore file extents. - */ -void -xfs_iext_destroy( - xfs_ifork_t *ifp) /* inode fork pointer */ -{ - if (ifp->if_flags & XFS_IFEXTIREC) { - xfs_iext_irec_remove_all(ifp); - } else if (ifp->if_real_bytes) { - kmem_free(ifp->if_u1.if_extents); - } else if (ifp->if_bytes) { - memset(ifp->if_u2.if_inline_ext, 0, XFS_INLINE_EXTS * - sizeof(xfs_bmbt_rec_t)); - } - ifp->if_u1.if_extents = NULL; - ifp->if_real_bytes = 0; - ifp->if_bytes = 0; -} - -/* - * Return a pointer to the extent record for file system block bno. - */ -xfs_bmbt_rec_host_t * /* pointer to found extent record */ -xfs_iext_bno_to_ext( - xfs_ifork_t *ifp, /* inode fork pointer */ - xfs_fileoff_t bno, /* block number to search for */ - xfs_extnum_t *idxp) /* index of target extent */ -{ - xfs_bmbt_rec_host_t *base; /* pointer to first extent */ - xfs_filblks_t blockcount = 0; /* number of blocks in extent */ - xfs_bmbt_rec_host_t *ep = NULL; /* pointer to target extent */ - xfs_ext_irec_t *erp = NULL; /* indirection array pointer */ - int high; /* upper boundary in search */ - xfs_extnum_t idx = 0; /* index of target extent */ - int low; /* lower boundary in search */ - xfs_extnum_t nextents; /* number of file extents */ - xfs_fileoff_t startoff = 0; /* start offset of extent */ - - nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); - if (nextents == 0) { - *idxp = 0; - return NULL; - } - low = 0; - if (ifp->if_flags & XFS_IFEXTIREC) { - /* Find target extent list */ - int erp_idx = 0; - erp = xfs_iext_bno_to_irec(ifp, bno, &erp_idx); - base = erp->er_extbuf; - high = erp->er_extcount - 1; - } else { - base = ifp->if_u1.if_extents; - high = nextents - 1; - } - /* Binary search extent records */ - while (low <= high) { - idx = (low + high) >> 1; - ep = base + idx; - startoff = xfs_bmbt_get_startoff(ep); - blockcount = xfs_bmbt_get_blockcount(ep); - if (bno < startoff) { - high = idx - 1; - } else if (bno >= startoff + blockcount) { - low = idx + 1; - } else { - /* Convert back to file-based extent index */ - if (ifp->if_flags & XFS_IFEXTIREC) { - idx += erp->er_extoff; - } - *idxp = idx; - return ep; - } - } - /* Convert back to file-based extent index */ - if (ifp->if_flags & XFS_IFEXTIREC) { - idx += erp->er_extoff; - } - if (bno >= startoff + blockcount) { - if (++idx == nextents) { - ep = NULL; - } else { - ep = xfs_iext_get_ext(ifp, idx); - } - } - *idxp = idx; - return ep; -} - -/* - * Return a pointer to the indirection array entry containing the - * extent record for filesystem block bno. Store the index of the - * target irec in *erp_idxp. - */ -xfs_ext_irec_t * /* pointer to found extent record */ -xfs_iext_bno_to_irec( - xfs_ifork_t *ifp, /* inode fork pointer */ - xfs_fileoff_t bno, /* block number to search for */ - int *erp_idxp) /* irec index of target ext list */ -{ - xfs_ext_irec_t *erp = NULL; /* indirection array pointer */ - xfs_ext_irec_t *erp_next; /* next indirection array entry */ - int erp_idx; /* indirection array index */ - int nlists; /* number of extent irec's (lists) */ - int high; /* binary search upper limit */ - int low; /* binary search lower limit */ - - ASSERT(ifp->if_flags & XFS_IFEXTIREC); - nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; - erp_idx = 0; - low = 0; - high = nlists - 1; - while (low <= high) { - erp_idx = (low + high) >> 1; - erp = &ifp->if_u1.if_ext_irec[erp_idx]; - erp_next = erp_idx < nlists - 1 ? erp + 1 : NULL; - if (bno < xfs_bmbt_get_startoff(erp->er_extbuf)) { - high = erp_idx - 1; - } else if (erp_next && bno >= - xfs_bmbt_get_startoff(erp_next->er_extbuf)) { - low = erp_idx + 1; - } else { - break; - } - } - *erp_idxp = erp_idx; - return erp; -} - -/* - * Return a pointer to the indirection array entry containing the - * extent record at file extent index *idxp. Store the index of the - * target irec in *erp_idxp and store the page index of the target - * extent record in *idxp. - */ -xfs_ext_irec_t * -xfs_iext_idx_to_irec( - xfs_ifork_t *ifp, /* inode fork pointer */ - xfs_extnum_t *idxp, /* extent index (file -> page) */ - int *erp_idxp, /* pointer to target irec */ - int realloc) /* new bytes were just added */ -{ - xfs_ext_irec_t *prev; /* pointer to previous irec */ - xfs_ext_irec_t *erp = NULL; /* pointer to current irec */ - int erp_idx; /* indirection array index */ - int nlists; /* number of irec's (ex lists) */ - int high; /* binary search upper limit */ - int low; /* binary search lower limit */ - xfs_extnum_t page_idx = *idxp; /* extent index in target list */ - - ASSERT(ifp->if_flags & XFS_IFEXTIREC); - ASSERT(page_idx >= 0); - ASSERT(page_idx <= ifp->if_bytes / sizeof(xfs_bmbt_rec_t)); - ASSERT(page_idx < ifp->if_bytes / sizeof(xfs_bmbt_rec_t) || realloc); - - nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; - erp_idx = 0; - low = 0; - high = nlists - 1; - - /* Binary search extent irec's */ - while (low <= high) { - erp_idx = (low + high) >> 1; - erp = &ifp->if_u1.if_ext_irec[erp_idx]; - prev = erp_idx > 0 ? erp - 1 : NULL; - if (page_idx < erp->er_extoff || (page_idx == erp->er_extoff && - realloc && prev && prev->er_extcount < XFS_LINEAR_EXTS)) { - high = erp_idx - 1; - } else if (page_idx > erp->er_extoff + erp->er_extcount || - (page_idx == erp->er_extoff + erp->er_extcount && - !realloc)) { - low = erp_idx + 1; - } else if (page_idx == erp->er_extoff + erp->er_extcount && - erp->er_extcount == XFS_LINEAR_EXTS) { - ASSERT(realloc); - page_idx = 0; - erp_idx++; - erp = erp_idx < nlists ? erp + 1 : NULL; - break; - } else { - page_idx -= erp->er_extoff; - break; - } - } - *idxp = page_idx; - *erp_idxp = erp_idx; - return erp; -} - -/* - * Allocate and initialize an indirection array once the space needed - * for incore extents increases above XFS_IEXT_BUFSZ. - */ -void -xfs_iext_irec_init( - xfs_ifork_t *ifp) /* inode fork pointer */ -{ - xfs_ext_irec_t *erp; /* indirection array pointer */ - xfs_extnum_t nextents; /* number of extents in file */ - - ASSERT(!(ifp->if_flags & XFS_IFEXTIREC)); - nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); - ASSERT(nextents <= XFS_LINEAR_EXTS); - - erp = kmem_alloc(sizeof(xfs_ext_irec_t), KM_NOFS); - - if (nextents == 0) { - ifp->if_u1.if_extents = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS); - } else if (!ifp->if_real_bytes) { - xfs_iext_inline_to_direct(ifp, XFS_IEXT_BUFSZ); - } else if (ifp->if_real_bytes < XFS_IEXT_BUFSZ) { - xfs_iext_realloc_direct(ifp, XFS_IEXT_BUFSZ); - } - erp->er_extbuf = ifp->if_u1.if_extents; - erp->er_extcount = nextents; - erp->er_extoff = 0; - - ifp->if_flags |= XFS_IFEXTIREC; - ifp->if_real_bytes = XFS_IEXT_BUFSZ; - ifp->if_bytes = nextents * sizeof(xfs_bmbt_rec_t); - ifp->if_u1.if_ext_irec = erp; - - return; -} - -/* - * Allocate and initialize a new entry in the indirection array. - */ -xfs_ext_irec_t * -xfs_iext_irec_new( - xfs_ifork_t *ifp, /* inode fork pointer */ - int erp_idx) /* index for new irec */ -{ - xfs_ext_irec_t *erp; /* indirection array pointer */ - int i; /* loop counter */ - int nlists; /* number of irec's (ex lists) */ - - ASSERT(ifp->if_flags & XFS_IFEXTIREC); - nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; - - /* Resize indirection array */ - xfs_iext_realloc_indirect(ifp, ++nlists * - sizeof(xfs_ext_irec_t)); - /* - * Move records down in the array so the - * new page can use erp_idx. - */ - erp = ifp->if_u1.if_ext_irec; - for (i = nlists - 1; i > erp_idx; i--) { - memmove(&erp[i], &erp[i-1], sizeof(xfs_ext_irec_t)); - } - ASSERT(i == erp_idx); - - /* Initialize new extent record */ - erp = ifp->if_u1.if_ext_irec; - erp[erp_idx].er_extbuf = kmem_alloc(XFS_IEXT_BUFSZ, KM_NOFS); - ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ; - memset(erp[erp_idx].er_extbuf, 0, XFS_IEXT_BUFSZ); - erp[erp_idx].er_extcount = 0; - erp[erp_idx].er_extoff = erp_idx > 0 ? - erp[erp_idx-1].er_extoff + erp[erp_idx-1].er_extcount : 0; - return (&erp[erp_idx]); -} - -/* - * Remove a record from the indirection array. - */ -void -xfs_iext_irec_remove( - xfs_ifork_t *ifp, /* inode fork pointer */ - int erp_idx) /* irec index to remove */ -{ - xfs_ext_irec_t *erp; /* indirection array pointer */ - int i; /* loop counter */ - int nlists; /* number of irec's (ex lists) */ - - ASSERT(ifp->if_flags & XFS_IFEXTIREC); - nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; - erp = &ifp->if_u1.if_ext_irec[erp_idx]; - if (erp->er_extbuf) { - xfs_iext_irec_update_extoffs(ifp, erp_idx + 1, - -erp->er_extcount); - kmem_free(erp->er_extbuf); - } - /* Compact extent records */ - erp = ifp->if_u1.if_ext_irec; - for (i = erp_idx; i < nlists - 1; i++) { - memmove(&erp[i], &erp[i+1], sizeof(xfs_ext_irec_t)); - } - /* - * Manually free the last extent record from the indirection - * array. A call to xfs_iext_realloc_indirect() with a size - * of zero would result in a call to xfs_iext_destroy() which - * would in turn call this function again, creating a nasty - * infinite loop. - */ - if (--nlists) { - xfs_iext_realloc_indirect(ifp, - nlists * sizeof(xfs_ext_irec_t)); - } else { - kmem_free(ifp->if_u1.if_ext_irec); - } - ifp->if_real_bytes = nlists * XFS_IEXT_BUFSZ; -} - -/* - * This is called to clean up large amounts of unused memory allocated - * by the indirection array. Before compacting anything though, verify - * that the indirection array is still needed and switch back to the - * linear extent list (or even the inline buffer) if possible. The - * compaction policy is as follows: - * - * Full Compaction: Extents fit into a single page (or inline buffer) - * Partial Compaction: Extents occupy less than 50% of allocated space - * No Compaction: Extents occupy at least 50% of allocated space - */ -void -xfs_iext_irec_compact( - xfs_ifork_t *ifp) /* inode fork pointer */ -{ - xfs_extnum_t nextents; /* number of extents in file */ - int nlists; /* number of irec's (ex lists) */ - - ASSERT(ifp->if_flags & XFS_IFEXTIREC); - nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; - nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); - - if (nextents == 0) { - xfs_iext_destroy(ifp); - } else if (nextents <= XFS_INLINE_EXTS) { - xfs_iext_indirect_to_direct(ifp); - xfs_iext_direct_to_inline(ifp, nextents); - } else if (nextents <= XFS_LINEAR_EXTS) { - xfs_iext_indirect_to_direct(ifp); - } else if (nextents < (nlists * XFS_LINEAR_EXTS) >> 1) { - xfs_iext_irec_compact_pages(ifp); - } -} - -/* - * Combine extents from neighboring extent pages. - */ -void -xfs_iext_irec_compact_pages( - xfs_ifork_t *ifp) /* inode fork pointer */ -{ - xfs_ext_irec_t *erp, *erp_next;/* pointers to irec entries */ - int erp_idx = 0; /* indirection array index */ - int nlists; /* number of irec's (ex lists) */ - - ASSERT(ifp->if_flags & XFS_IFEXTIREC); - nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; - while (erp_idx < nlists - 1) { - erp = &ifp->if_u1.if_ext_irec[erp_idx]; - erp_next = erp + 1; - if (erp_next->er_extcount <= - (XFS_LINEAR_EXTS - erp->er_extcount)) { - memcpy(&erp->er_extbuf[erp->er_extcount], - erp_next->er_extbuf, erp_next->er_extcount * - sizeof(xfs_bmbt_rec_t)); - erp->er_extcount += erp_next->er_extcount; - /* - * Free page before removing extent record - * so er_extoffs don't get modified in - * xfs_iext_irec_remove. - */ - kmem_free(erp_next->er_extbuf); - erp_next->er_extbuf = NULL; - xfs_iext_irec_remove(ifp, erp_idx + 1); - nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; - } else { - erp_idx++; - } - } -} - -/* - * This is called to update the er_extoff field in the indirection - * array when extents have been added or removed from one of the - * extent lists. erp_idx contains the irec index to begin updating - * at and ext_diff contains the number of extents that were added - * or removed. - */ -void -xfs_iext_irec_update_extoffs( - xfs_ifork_t *ifp, /* inode fork pointer */ - int erp_idx, /* irec index to update */ - int ext_diff) /* number of new extents */ -{ - int i; /* loop counter */ - int nlists; /* number of irec's (ex lists */ - - ASSERT(ifp->if_flags & XFS_IFEXTIREC); - nlists = ifp->if_real_bytes / XFS_IEXT_BUFSZ; - for (i = erp_idx; i < nlists; i++) { - ifp->if_u1.if_ext_irec[i].er_extoff += ext_diff; - } -} - -/* - * Initialize an inode's copy-on-write fork. - */ -void -xfs_ifork_init_cow( - struct xfs_inode *ip) -{ - if (ip->i_cowfp) - return; - - ip->i_cowfp = kmem_zone_zalloc(xfs_ifork_zone, - KM_SLEEP | KM_NOFS); - ip->i_cowfp->if_flags = XFS_IFEXTENTS; - ip->i_cformat = XFS_DINODE_FMT_EXTENTS; - ip->i_cnextents = 0; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_inode_fork.h b/src/linux/fs/xfs/libxfs/xfs_inode_fork.h deleted file mode 100644 index c9476f5..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_inode_fork.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_INODE_FORK_H__ -#define __XFS_INODE_FORK_H__ - -struct xfs_inode_log_item; -struct xfs_dinode; - -/* - * The following xfs_ext_irec_t struct introduces a second (top) level - * to the in-core extent allocation scheme. These structs are allocated - * in a contiguous block, creating an indirection array where each entry - * (irec) contains a pointer to a buffer of in-core extent records which - * it manages. Each extent buffer is 4k in size, since 4k is the system - * page size on Linux i386 and systems with larger page sizes don't seem - * to gain much, if anything, by using their native page size as the - * extent buffer size. Also, using 4k extent buffers everywhere provides - * a consistent interface for CXFS across different platforms. - * - * There is currently no limit on the number of irec's (extent lists) - * allowed, so heavily fragmented files may require an indirection array - * which spans multiple system pages of memory. The number of extents - * which would require this amount of contiguous memory is very large - * and should not cause problems in the foreseeable future. However, - * if the memory needed for the contiguous array ever becomes a problem, - * it is possible that a third level of indirection may be required. - */ -typedef struct xfs_ext_irec { - xfs_bmbt_rec_host_t *er_extbuf; /* block of extent records */ - xfs_extnum_t er_extoff; /* extent offset in file */ - xfs_extnum_t er_extcount; /* number of extents in page/block */ -} xfs_ext_irec_t; - -/* - * File incore extent information, present for each of data & attr forks. - */ -#define XFS_IEXT_BUFSZ 4096 -#define XFS_LINEAR_EXTS (XFS_IEXT_BUFSZ / (uint)sizeof(xfs_bmbt_rec_t)) -#define XFS_INLINE_EXTS 2 -#define XFS_INLINE_DATA 32 -typedef struct xfs_ifork { - int if_bytes; /* bytes in if_u1 */ - int if_real_bytes; /* bytes allocated in if_u1 */ - struct xfs_btree_block *if_broot; /* file's incore btree root */ - short if_broot_bytes; /* bytes allocated for root */ - unsigned char if_flags; /* per-fork flags */ - union { - xfs_bmbt_rec_host_t *if_extents;/* linear map file exts */ - xfs_ext_irec_t *if_ext_irec; /* irec map file exts */ - char *if_data; /* inline file data */ - } if_u1; - union { - xfs_bmbt_rec_host_t if_inline_ext[XFS_INLINE_EXTS]; - /* very small file extents */ - char if_inline_data[XFS_INLINE_DATA]; - /* very small file data */ - xfs_dev_t if_rdev; /* dev number if special */ - uuid_t if_uuid; /* mount point value */ - } if_u2; -} xfs_ifork_t; - -/* - * Per-fork incore inode flags. - */ -#define XFS_IFINLINE 0x01 /* Inline data is read in */ -#define XFS_IFEXTENTS 0x02 /* All extent pointers are read in */ -#define XFS_IFBROOT 0x04 /* i_broot points to the bmap b-tree root */ -#define XFS_IFEXTIREC 0x08 /* Indirection array of extent blocks */ - -/* - * Fork handling. - */ - -#define XFS_IFORK_Q(ip) ((ip)->i_d.di_forkoff != 0) -#define XFS_IFORK_BOFF(ip) ((int)((ip)->i_d.di_forkoff << 3)) - -#define XFS_IFORK_PTR(ip,w) \ - ((w) == XFS_DATA_FORK ? \ - &(ip)->i_df : \ - ((w) == XFS_ATTR_FORK ? \ - (ip)->i_afp : \ - (ip)->i_cowfp)) -#define XFS_IFORK_DSIZE(ip) \ - (XFS_IFORK_Q(ip) ? \ - XFS_IFORK_BOFF(ip) : \ - XFS_LITINO((ip)->i_mount, (ip)->i_d.di_version)) -#define XFS_IFORK_ASIZE(ip) \ - (XFS_IFORK_Q(ip) ? \ - XFS_LITINO((ip)->i_mount, (ip)->i_d.di_version) - \ - XFS_IFORK_BOFF(ip) : \ - 0) -#define XFS_IFORK_SIZE(ip,w) \ - ((w) == XFS_DATA_FORK ? \ - XFS_IFORK_DSIZE(ip) : \ - ((w) == XFS_ATTR_FORK ? \ - XFS_IFORK_ASIZE(ip) : \ - 0)) -#define XFS_IFORK_FORMAT(ip,w) \ - ((w) == XFS_DATA_FORK ? \ - (ip)->i_d.di_format : \ - ((w) == XFS_ATTR_FORK ? \ - (ip)->i_d.di_aformat : \ - (ip)->i_cformat)) -#define XFS_IFORK_FMT_SET(ip,w,n) \ - ((w) == XFS_DATA_FORK ? \ - ((ip)->i_d.di_format = (n)) : \ - ((w) == XFS_ATTR_FORK ? \ - ((ip)->i_d.di_aformat = (n)) : \ - ((ip)->i_cformat = (n)))) -#define XFS_IFORK_NEXTENTS(ip,w) \ - ((w) == XFS_DATA_FORK ? \ - (ip)->i_d.di_nextents : \ - ((w) == XFS_ATTR_FORK ? \ - (ip)->i_d.di_anextents : \ - (ip)->i_cnextents)) -#define XFS_IFORK_NEXT_SET(ip,w,n) \ - ((w) == XFS_DATA_FORK ? \ - ((ip)->i_d.di_nextents = (n)) : \ - ((w) == XFS_ATTR_FORK ? \ - ((ip)->i_d.di_anextents = (n)) : \ - ((ip)->i_cnextents = (n)))) -#define XFS_IFORK_MAXEXT(ip, w) \ - (XFS_IFORK_SIZE(ip, w) / sizeof(xfs_bmbt_rec_t)) - -struct xfs_ifork *xfs_iext_state_to_fork(struct xfs_inode *ip, int state); - -int xfs_iformat_fork(struct xfs_inode *, struct xfs_dinode *); -void xfs_iflush_fork(struct xfs_inode *, struct xfs_dinode *, - struct xfs_inode_log_item *, int); -void xfs_idestroy_fork(struct xfs_inode *, int); -void xfs_idata_realloc(struct xfs_inode *, int, int); -void xfs_iroot_realloc(struct xfs_inode *, int, int); -int xfs_iread_extents(struct xfs_trans *, struct xfs_inode *, int); -int xfs_iextents_copy(struct xfs_inode *, struct xfs_bmbt_rec *, - int); -void xfs_init_local_fork(struct xfs_inode *, int, const void *, int); - -struct xfs_bmbt_rec_host * - xfs_iext_get_ext(struct xfs_ifork *, xfs_extnum_t); -void xfs_iext_insert(struct xfs_inode *, xfs_extnum_t, xfs_extnum_t, - struct xfs_bmbt_irec *, int); -void xfs_iext_add(struct xfs_ifork *, xfs_extnum_t, int); -void xfs_iext_add_indirect_multi(struct xfs_ifork *, int, - xfs_extnum_t, int); -void xfs_iext_remove(struct xfs_inode *, xfs_extnum_t, int, int); -void xfs_iext_remove_inline(struct xfs_ifork *, xfs_extnum_t, int); -void xfs_iext_remove_direct(struct xfs_ifork *, xfs_extnum_t, int); -void xfs_iext_remove_indirect(struct xfs_ifork *, xfs_extnum_t, int); -void xfs_iext_realloc_direct(struct xfs_ifork *, int); -void xfs_iext_direct_to_inline(struct xfs_ifork *, xfs_extnum_t); -void xfs_iext_inline_to_direct(struct xfs_ifork *, int); -void xfs_iext_destroy(struct xfs_ifork *); -struct xfs_bmbt_rec_host * - xfs_iext_bno_to_ext(struct xfs_ifork *, xfs_fileoff_t, int *); -struct xfs_ext_irec * - xfs_iext_bno_to_irec(struct xfs_ifork *, xfs_fileoff_t, int *); -struct xfs_ext_irec * - xfs_iext_idx_to_irec(struct xfs_ifork *, xfs_extnum_t *, int *, - int); -void xfs_iext_irec_init(struct xfs_ifork *); -struct xfs_ext_irec * - xfs_iext_irec_new(struct xfs_ifork *, int); -void xfs_iext_irec_remove(struct xfs_ifork *, int); -void xfs_iext_irec_compact(struct xfs_ifork *); -void xfs_iext_irec_compact_pages(struct xfs_ifork *); -void xfs_iext_irec_compact_full(struct xfs_ifork *); -void xfs_iext_irec_update_extoffs(struct xfs_ifork *, int, int); - -extern struct kmem_zone *xfs_ifork_zone; - -extern void xfs_ifork_init_cow(struct xfs_inode *ip); - -#endif /* __XFS_INODE_FORK_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_log_format.h b/src/linux/fs/xfs/libxfs/xfs_log_format.h deleted file mode 100644 index 083cdd6..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_log_format.h +++ /dev/null @@ -1,866 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_LOG_FORMAT_H__ -#define __XFS_LOG_FORMAT_H__ - -struct xfs_mount; -struct xfs_trans_res; - -/* - * On-disk Log Format definitions. - * - * This file contains all the on-disk format definitions used within the log. It - * includes the physical log structure itself, as well as all the log item - * format structures that are written into the log and intepreted by log - * recovery. We start with the physical log format definitions, and then work - * through all the log items definitions and everything they encode into the - * log. - */ -typedef __uint32_t xlog_tid_t; - -#define XLOG_MIN_ICLOGS 2 -#define XLOG_MAX_ICLOGS 8 -#define XLOG_HEADER_MAGIC_NUM 0xFEEDbabe /* Invalid cycle number */ -#define XLOG_VERSION_1 1 -#define XLOG_VERSION_2 2 /* Large IClogs, Log sunit */ -#define XLOG_VERSION_OKBITS (XLOG_VERSION_1 | XLOG_VERSION_2) -#define XLOG_MIN_RECORD_BSIZE (16*1024) /* eventually 32k */ -#define XLOG_BIG_RECORD_BSIZE (32*1024) /* 32k buffers */ -#define XLOG_MAX_RECORD_BSIZE (256*1024) -#define XLOG_HEADER_CYCLE_SIZE (32*1024) /* cycle data in header */ -#define XLOG_MIN_RECORD_BSHIFT 14 /* 16384 == 1 << 14 */ -#define XLOG_BIG_RECORD_BSHIFT 15 /* 32k == 1 << 15 */ -#define XLOG_MAX_RECORD_BSHIFT 18 /* 256k == 1 << 18 */ -#define XLOG_BTOLSUNIT(log, b) (((b)+(log)->l_mp->m_sb.sb_logsunit-1) / \ - (log)->l_mp->m_sb.sb_logsunit) -#define XLOG_LSUNITTOB(log, su) ((su) * (log)->l_mp->m_sb.sb_logsunit) - -#define XLOG_HEADER_SIZE 512 - -/* Minimum number of transactions that must fit in the log (defined by mkfs) */ -#define XFS_MIN_LOG_FACTOR 3 - -#define XLOG_REC_SHIFT(log) \ - BTOBB(1 << (xfs_sb_version_haslogv2(&log->l_mp->m_sb) ? \ - XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT)) -#define XLOG_TOTAL_REC_SHIFT(log) \ - BTOBB(XLOG_MAX_ICLOGS << (xfs_sb_version_haslogv2(&log->l_mp->m_sb) ? \ - XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT)) - -/* get lsn fields */ -#define CYCLE_LSN(lsn) ((uint)((lsn)>>32)) -#define BLOCK_LSN(lsn) ((uint)(lsn)) - -/* this is used in a spot where we might otherwise double-endian-flip */ -#define CYCLE_LSN_DISK(lsn) (((__be32 *)&(lsn))[0]) - -static inline xfs_lsn_t xlog_assign_lsn(uint cycle, uint block) -{ - return ((xfs_lsn_t)cycle << 32) | block; -} - -static inline uint xlog_get_cycle(char *ptr) -{ - if (be32_to_cpu(*(__be32 *)ptr) == XLOG_HEADER_MAGIC_NUM) - return be32_to_cpu(*((__be32 *)ptr + 1)); - else - return be32_to_cpu(*(__be32 *)ptr); -} - -/* Log Clients */ -#define XFS_TRANSACTION 0x69 -#define XFS_VOLUME 0x2 -#define XFS_LOG 0xaa - -#define XLOG_UNMOUNT_TYPE 0x556e /* Un for Unmount */ - -/* Region types for iovec's i_type */ -#define XLOG_REG_TYPE_BFORMAT 1 -#define XLOG_REG_TYPE_BCHUNK 2 -#define XLOG_REG_TYPE_EFI_FORMAT 3 -#define XLOG_REG_TYPE_EFD_FORMAT 4 -#define XLOG_REG_TYPE_IFORMAT 5 -#define XLOG_REG_TYPE_ICORE 6 -#define XLOG_REG_TYPE_IEXT 7 -#define XLOG_REG_TYPE_IBROOT 8 -#define XLOG_REG_TYPE_ILOCAL 9 -#define XLOG_REG_TYPE_IATTR_EXT 10 -#define XLOG_REG_TYPE_IATTR_BROOT 11 -#define XLOG_REG_TYPE_IATTR_LOCAL 12 -#define XLOG_REG_TYPE_QFORMAT 13 -#define XLOG_REG_TYPE_DQUOT 14 -#define XLOG_REG_TYPE_QUOTAOFF 15 -#define XLOG_REG_TYPE_LRHEADER 16 -#define XLOG_REG_TYPE_UNMOUNT 17 -#define XLOG_REG_TYPE_COMMIT 18 -#define XLOG_REG_TYPE_TRANSHDR 19 -#define XLOG_REG_TYPE_ICREATE 20 -#define XLOG_REG_TYPE_RUI_FORMAT 21 -#define XLOG_REG_TYPE_RUD_FORMAT 22 -#define XLOG_REG_TYPE_CUI_FORMAT 23 -#define XLOG_REG_TYPE_CUD_FORMAT 24 -#define XLOG_REG_TYPE_BUI_FORMAT 25 -#define XLOG_REG_TYPE_BUD_FORMAT 26 -#define XLOG_REG_TYPE_MAX 26 - -/* - * Flags to log operation header - * - * The first write of a new transaction will be preceded with a start - * record, XLOG_START_TRANS. Once a transaction is committed, a commit - * record is written, XLOG_COMMIT_TRANS. If a single region can not fit into - * the remainder of the current active in-core log, it is split up into - * multiple regions. Each partial region will be marked with a - * XLOG_CONTINUE_TRANS until the last one, which gets marked with XLOG_END_TRANS. - * - */ -#define XLOG_START_TRANS 0x01 /* Start a new transaction */ -#define XLOG_COMMIT_TRANS 0x02 /* Commit this transaction */ -#define XLOG_CONTINUE_TRANS 0x04 /* Cont this trans into new region */ -#define XLOG_WAS_CONT_TRANS 0x08 /* Cont this trans into new region */ -#define XLOG_END_TRANS 0x10 /* End a continued transaction */ -#define XLOG_UNMOUNT_TRANS 0x20 /* Unmount a filesystem transaction */ - - -typedef struct xlog_op_header { - __be32 oh_tid; /* transaction id of operation : 4 b */ - __be32 oh_len; /* bytes in data region : 4 b */ - __u8 oh_clientid; /* who sent me this : 1 b */ - __u8 oh_flags; /* : 1 b */ - __u16 oh_res2; /* 32 bit align : 2 b */ -} xlog_op_header_t; - -/* valid values for h_fmt */ -#define XLOG_FMT_UNKNOWN 0 -#define XLOG_FMT_LINUX_LE 1 -#define XLOG_FMT_LINUX_BE 2 -#define XLOG_FMT_IRIX_BE 3 - -/* our fmt */ -#ifdef XFS_NATIVE_HOST -#define XLOG_FMT XLOG_FMT_LINUX_BE -#else -#define XLOG_FMT XLOG_FMT_LINUX_LE -#endif - -typedef struct xlog_rec_header { - __be32 h_magicno; /* log record (LR) identifier : 4 */ - __be32 h_cycle; /* write cycle of log : 4 */ - __be32 h_version; /* LR version : 4 */ - __be32 h_len; /* len in bytes; should be 64-bit aligned: 4 */ - __be64 h_lsn; /* lsn of this LR : 8 */ - __be64 h_tail_lsn; /* lsn of 1st LR w/ buffers not committed: 8 */ - __le32 h_crc; /* crc of log record : 4 */ - __be32 h_prev_block; /* block number to previous LR : 4 */ - __be32 h_num_logops; /* number of log operations in this LR : 4 */ - __be32 h_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; - /* new fields */ - __be32 h_fmt; /* format of log record : 4 */ - uuid_t h_fs_uuid; /* uuid of FS : 16 */ - __be32 h_size; /* iclog size : 4 */ -} xlog_rec_header_t; - -typedef struct xlog_rec_ext_header { - __be32 xh_cycle; /* write cycle of log : 4 */ - __be32 xh_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; /* : 256 */ -} xlog_rec_ext_header_t; - -/* - * Quite misnamed, because this union lays out the actual on-disk log buffer. - */ -typedef union xlog_in_core2 { - xlog_rec_header_t hic_header; - xlog_rec_ext_header_t hic_xheader; - char hic_sector[XLOG_HEADER_SIZE]; -} xlog_in_core_2_t; - -/* not an on-disk structure, but needed by log recovery in userspace */ -typedef struct xfs_log_iovec { - void *i_addr; /* beginning address of region */ - int i_len; /* length in bytes of region */ - uint i_type; /* type of region */ -} xfs_log_iovec_t; - - -/* - * Transaction Header definitions. - * - * This is the structure written in the log at the head of every transaction. It - * identifies the type and id of the transaction, and contains the number of - * items logged by the transaction so we know how many to expect during - * recovery. - * - * Do not change the below structure without redoing the code in - * xlog_recover_add_to_trans() and xlog_recover_add_to_cont_trans(). - */ -typedef struct xfs_trans_header { - uint th_magic; /* magic number */ - uint th_type; /* transaction type */ - __int32_t th_tid; /* transaction id (unused) */ - uint th_num_items; /* num items logged by trans */ -} xfs_trans_header_t; - -#define XFS_TRANS_HEADER_MAGIC 0x5452414e /* TRAN */ - -/* - * The only type valid for th_type in CIL-enabled file system logs: - */ -#define XFS_TRANS_CHECKPOINT 40 - -/* - * Log item types. - */ -#define XFS_LI_EFI 0x1236 -#define XFS_LI_EFD 0x1237 -#define XFS_LI_IUNLINK 0x1238 -#define XFS_LI_INODE 0x123b /* aligned ino chunks, var-size ibufs */ -#define XFS_LI_BUF 0x123c /* v2 bufs, variable sized inode bufs */ -#define XFS_LI_DQUOT 0x123d -#define XFS_LI_QUOTAOFF 0x123e -#define XFS_LI_ICREATE 0x123f -#define XFS_LI_RUI 0x1240 /* rmap update intent */ -#define XFS_LI_RUD 0x1241 -#define XFS_LI_CUI 0x1242 /* refcount update intent */ -#define XFS_LI_CUD 0x1243 -#define XFS_LI_BUI 0x1244 /* bmbt update intent */ -#define XFS_LI_BUD 0x1245 - -#define XFS_LI_TYPE_DESC \ - { XFS_LI_EFI, "XFS_LI_EFI" }, \ - { XFS_LI_EFD, "XFS_LI_EFD" }, \ - { XFS_LI_IUNLINK, "XFS_LI_IUNLINK" }, \ - { XFS_LI_INODE, "XFS_LI_INODE" }, \ - { XFS_LI_BUF, "XFS_LI_BUF" }, \ - { XFS_LI_DQUOT, "XFS_LI_DQUOT" }, \ - { XFS_LI_QUOTAOFF, "XFS_LI_QUOTAOFF" }, \ - { XFS_LI_ICREATE, "XFS_LI_ICREATE" }, \ - { XFS_LI_RUI, "XFS_LI_RUI" }, \ - { XFS_LI_RUD, "XFS_LI_RUD" }, \ - { XFS_LI_CUI, "XFS_LI_CUI" }, \ - { XFS_LI_CUD, "XFS_LI_CUD" }, \ - { XFS_LI_BUI, "XFS_LI_BUI" }, \ - { XFS_LI_BUD, "XFS_LI_BUD" } - -/* - * Inode Log Item Format definitions. - * - * This is the structure used to lay out an inode log item in the - * log. The size of the inline data/extents/b-tree root to be logged - * (if any) is indicated in the ilf_dsize field. Changes to this structure - * must be added on to the end. - */ -typedef struct xfs_inode_log_format { - __uint16_t ilf_type; /* inode log item type */ - __uint16_t ilf_size; /* size of this item */ - __uint32_t ilf_fields; /* flags for fields logged */ - __uint16_t ilf_asize; /* size of attr d/ext/root */ - __uint16_t ilf_dsize; /* size of data/ext/root */ - __uint64_t ilf_ino; /* inode number */ - union { - __uint32_t ilfu_rdev; /* rdev value for dev inode*/ - uuid_t ilfu_uuid; /* mount point value */ - } ilf_u; - __int64_t ilf_blkno; /* blkno of inode buffer */ - __int32_t ilf_len; /* len of inode buffer */ - __int32_t ilf_boffset; /* off of inode in buffer */ -} xfs_inode_log_format_t; - -typedef struct xfs_inode_log_format_32 { - __uint16_t ilf_type; /* inode log item type */ - __uint16_t ilf_size; /* size of this item */ - __uint32_t ilf_fields; /* flags for fields logged */ - __uint16_t ilf_asize; /* size of attr d/ext/root */ - __uint16_t ilf_dsize; /* size of data/ext/root */ - __uint64_t ilf_ino; /* inode number */ - union { - __uint32_t ilfu_rdev; /* rdev value for dev inode*/ - uuid_t ilfu_uuid; /* mount point value */ - } ilf_u; - __int64_t ilf_blkno; /* blkno of inode buffer */ - __int32_t ilf_len; /* len of inode buffer */ - __int32_t ilf_boffset; /* off of inode in buffer */ -} __attribute__((packed)) xfs_inode_log_format_32_t; - -typedef struct xfs_inode_log_format_64 { - __uint16_t ilf_type; /* inode log item type */ - __uint16_t ilf_size; /* size of this item */ - __uint32_t ilf_fields; /* flags for fields logged */ - __uint16_t ilf_asize; /* size of attr d/ext/root */ - __uint16_t ilf_dsize; /* size of data/ext/root */ - __uint32_t ilf_pad; /* pad for 64 bit boundary */ - __uint64_t ilf_ino; /* inode number */ - union { - __uint32_t ilfu_rdev; /* rdev value for dev inode*/ - uuid_t ilfu_uuid; /* mount point value */ - } ilf_u; - __int64_t ilf_blkno; /* blkno of inode buffer */ - __int32_t ilf_len; /* len of inode buffer */ - __int32_t ilf_boffset; /* off of inode in buffer */ -} xfs_inode_log_format_64_t; - - -/* - * Flags for xfs_trans_log_inode flags field. - */ -#define XFS_ILOG_CORE 0x001 /* log standard inode fields */ -#define XFS_ILOG_DDATA 0x002 /* log i_df.if_data */ -#define XFS_ILOG_DEXT 0x004 /* log i_df.if_extents */ -#define XFS_ILOG_DBROOT 0x008 /* log i_df.i_broot */ -#define XFS_ILOG_DEV 0x010 /* log the dev field */ -#define XFS_ILOG_UUID 0x020 /* log the uuid field */ -#define XFS_ILOG_ADATA 0x040 /* log i_af.if_data */ -#define XFS_ILOG_AEXT 0x080 /* log i_af.if_extents */ -#define XFS_ILOG_ABROOT 0x100 /* log i_af.i_broot */ -#define XFS_ILOG_DOWNER 0x200 /* change the data fork owner on replay */ -#define XFS_ILOG_AOWNER 0x400 /* change the attr fork owner on replay */ - - -/* - * The timestamps are dirty, but not necessarily anything else in the inode - * core. Unlike the other fields above this one must never make it to disk - * in the ilf_fields of the inode_log_format, but is purely store in-memory in - * ili_fields in the inode_log_item. - */ -#define XFS_ILOG_TIMESTAMP 0x4000 - -#define XFS_ILOG_NONCORE (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \ - XFS_ILOG_DBROOT | XFS_ILOG_DEV | \ - XFS_ILOG_UUID | XFS_ILOG_ADATA | \ - XFS_ILOG_AEXT | XFS_ILOG_ABROOT | \ - XFS_ILOG_DOWNER | XFS_ILOG_AOWNER) - -#define XFS_ILOG_DFORK (XFS_ILOG_DDATA | XFS_ILOG_DEXT | \ - XFS_ILOG_DBROOT) - -#define XFS_ILOG_AFORK (XFS_ILOG_ADATA | XFS_ILOG_AEXT | \ - XFS_ILOG_ABROOT) - -#define XFS_ILOG_ALL (XFS_ILOG_CORE | XFS_ILOG_DDATA | \ - XFS_ILOG_DEXT | XFS_ILOG_DBROOT | \ - XFS_ILOG_DEV | XFS_ILOG_UUID | \ - XFS_ILOG_ADATA | XFS_ILOG_AEXT | \ - XFS_ILOG_ABROOT | XFS_ILOG_TIMESTAMP | \ - XFS_ILOG_DOWNER | XFS_ILOG_AOWNER) - -static inline int xfs_ilog_fbroot(int w) -{ - return (w == XFS_DATA_FORK ? XFS_ILOG_DBROOT : XFS_ILOG_ABROOT); -} - -static inline int xfs_ilog_fext(int w) -{ - return (w == XFS_DATA_FORK ? XFS_ILOG_DEXT : XFS_ILOG_AEXT); -} - -static inline int xfs_ilog_fdata(int w) -{ - return (w == XFS_DATA_FORK ? XFS_ILOG_DDATA : XFS_ILOG_ADATA); -} - -/* - * Incore version of the on-disk inode core structures. We log this directly - * into the journal in host CPU format (for better or worse) and as such - * directly mirrors the xfs_dinode structure as it must contain all the same - * information. - */ -typedef struct xfs_ictimestamp { - __int32_t t_sec; /* timestamp seconds */ - __int32_t t_nsec; /* timestamp nanoseconds */ -} xfs_ictimestamp_t; - -/* - * Define the format of the inode core that is logged. This structure must be - * kept identical to struct xfs_dinode except for the endianness annotations. - */ -struct xfs_log_dinode { - __uint16_t di_magic; /* inode magic # = XFS_DINODE_MAGIC */ - __uint16_t di_mode; /* mode and type of file */ - __int8_t di_version; /* inode version */ - __int8_t di_format; /* format of di_c data */ - __uint8_t di_pad3[2]; /* unused in v2/3 inodes */ - __uint32_t di_uid; /* owner's user id */ - __uint32_t di_gid; /* owner's group id */ - __uint32_t di_nlink; /* number of links to file */ - __uint16_t di_projid_lo; /* lower part of owner's project id */ - __uint16_t di_projid_hi; /* higher part of owner's project id */ - __uint8_t di_pad[6]; /* unused, zeroed space */ - __uint16_t di_flushiter; /* incremented on flush */ - xfs_ictimestamp_t di_atime; /* time last accessed */ - xfs_ictimestamp_t di_mtime; /* time last modified */ - xfs_ictimestamp_t di_ctime; /* time created/inode modified */ - xfs_fsize_t di_size; /* number of bytes in file */ - xfs_rfsblock_t di_nblocks; /* # of direct & btree blocks used */ - xfs_extlen_t di_extsize; /* basic/minimum extent size for file */ - xfs_extnum_t di_nextents; /* number of extents in data fork */ - xfs_aextnum_t di_anextents; /* number of extents in attribute fork*/ - __uint8_t di_forkoff; /* attr fork offs, <<3 for 64b align */ - __int8_t di_aformat; /* format of attr fork's data */ - __uint32_t di_dmevmask; /* DMIG event mask */ - __uint16_t di_dmstate; /* DMIG state info */ - __uint16_t di_flags; /* random flags, XFS_DIFLAG_... */ - __uint32_t di_gen; /* generation number */ - - /* di_next_unlinked is the only non-core field in the old dinode */ - xfs_agino_t di_next_unlinked;/* agi unlinked list ptr */ - - /* start of the extended dinode, writable fields */ - __uint32_t di_crc; /* CRC of the inode */ - __uint64_t di_changecount; /* number of attribute changes */ - xfs_lsn_t di_lsn; /* flush sequence */ - __uint64_t di_flags2; /* more random flags */ - __uint32_t di_cowextsize; /* basic cow extent size for file */ - __uint8_t di_pad2[12]; /* more padding for future expansion */ - - /* fields only written to during inode creation */ - xfs_ictimestamp_t di_crtime; /* time created */ - xfs_ino_t di_ino; /* inode number */ - uuid_t di_uuid; /* UUID of the filesystem */ - - /* structure must be padded to 64 bit alignment */ -}; - -static inline uint xfs_log_dinode_size(int version) -{ - if (version == 3) - return sizeof(struct xfs_log_dinode); - return offsetof(struct xfs_log_dinode, di_next_unlinked); -} - -/* - * Buffer Log Format defintions - * - * These are the physical dirty bitmap defintions for the log format structure. - */ -#define XFS_BLF_CHUNK 128 -#define XFS_BLF_SHIFT 7 -#define BIT_TO_WORD_SHIFT 5 -#define NBWORD (NBBY * sizeof(unsigned int)) - -/* - * This flag indicates that the buffer contains on disk inodes - * and requires special recovery handling. - */ -#define XFS_BLF_INODE_BUF (1<<0) - -/* - * This flag indicates that the buffer should not be replayed - * during recovery because its blocks are being freed. - */ -#define XFS_BLF_CANCEL (1<<1) - -/* - * This flag indicates that the buffer contains on disk - * user or group dquots and may require special recovery handling. - */ -#define XFS_BLF_UDQUOT_BUF (1<<2) -#define XFS_BLF_PDQUOT_BUF (1<<3) -#define XFS_BLF_GDQUOT_BUF (1<<4) - -/* - * This is the structure used to lay out a buf log item in the - * log. The data map describes which 128 byte chunks of the buffer - * have been logged. - */ -#define XFS_BLF_DATAMAP_SIZE ((XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK) / NBWORD) - -typedef struct xfs_buf_log_format { - unsigned short blf_type; /* buf log item type indicator */ - unsigned short blf_size; /* size of this item */ - ushort blf_flags; /* misc state */ - ushort blf_len; /* number of blocks in this buf */ - __int64_t blf_blkno; /* starting blkno of this buf */ - unsigned int blf_map_size; /* used size of data bitmap in words */ - unsigned int blf_data_map[XFS_BLF_DATAMAP_SIZE]; /* dirty bitmap */ -} xfs_buf_log_format_t; - -/* - * All buffers now need to tell recovery where the magic number - * is so that it can verify and calculate the CRCs on the buffer correctly - * once the changes have been replayed into the buffer. - * - * The type value is held in the upper 5 bits of the blf_flags field, which is - * an unsigned 16 bit field. Hence we need to shift it 11 bits up and down. - */ -#define XFS_BLFT_BITS 5 -#define XFS_BLFT_SHIFT 11 -#define XFS_BLFT_MASK (((1 << XFS_BLFT_BITS) - 1) << XFS_BLFT_SHIFT) - -enum xfs_blft { - XFS_BLFT_UNKNOWN_BUF = 0, - XFS_BLFT_UDQUOT_BUF, - XFS_BLFT_PDQUOT_BUF, - XFS_BLFT_GDQUOT_BUF, - XFS_BLFT_BTREE_BUF, - XFS_BLFT_AGF_BUF, - XFS_BLFT_AGFL_BUF, - XFS_BLFT_AGI_BUF, - XFS_BLFT_DINO_BUF, - XFS_BLFT_SYMLINK_BUF, - XFS_BLFT_DIR_BLOCK_BUF, - XFS_BLFT_DIR_DATA_BUF, - XFS_BLFT_DIR_FREE_BUF, - XFS_BLFT_DIR_LEAF1_BUF, - XFS_BLFT_DIR_LEAFN_BUF, - XFS_BLFT_DA_NODE_BUF, - XFS_BLFT_ATTR_LEAF_BUF, - XFS_BLFT_ATTR_RMT_BUF, - XFS_BLFT_SB_BUF, - XFS_BLFT_RTBITMAP_BUF, - XFS_BLFT_RTSUMMARY_BUF, - XFS_BLFT_MAX_BUF = (1 << XFS_BLFT_BITS), -}; - -static inline void -xfs_blft_to_flags(struct xfs_buf_log_format *blf, enum xfs_blft type) -{ - ASSERT(type > XFS_BLFT_UNKNOWN_BUF && type < XFS_BLFT_MAX_BUF); - blf->blf_flags &= ~XFS_BLFT_MASK; - blf->blf_flags |= ((type << XFS_BLFT_SHIFT) & XFS_BLFT_MASK); -} - -static inline __uint16_t -xfs_blft_from_flags(struct xfs_buf_log_format *blf) -{ - return (blf->blf_flags & XFS_BLFT_MASK) >> XFS_BLFT_SHIFT; -} - -/* - * EFI/EFD log format definitions - */ -typedef struct xfs_extent { - xfs_fsblock_t ext_start; - xfs_extlen_t ext_len; -} xfs_extent_t; - -/* - * Since an xfs_extent_t has types (start:64, len: 32) - * there are different alignments on 32 bit and 64 bit kernels. - * So we provide the different variants for use by a - * conversion routine. - */ -typedef struct xfs_extent_32 { - __uint64_t ext_start; - __uint32_t ext_len; -} __attribute__((packed)) xfs_extent_32_t; - -typedef struct xfs_extent_64 { - __uint64_t ext_start; - __uint32_t ext_len; - __uint32_t ext_pad; -} xfs_extent_64_t; - -/* - * This is the structure used to lay out an efi log item in the - * log. The efi_extents field is a variable size array whose - * size is given by efi_nextents. - */ -typedef struct xfs_efi_log_format { - __uint16_t efi_type; /* efi log item type */ - __uint16_t efi_size; /* size of this item */ - __uint32_t efi_nextents; /* # extents to free */ - __uint64_t efi_id; /* efi identifier */ - xfs_extent_t efi_extents[1]; /* array of extents to free */ -} xfs_efi_log_format_t; - -typedef struct xfs_efi_log_format_32 { - __uint16_t efi_type; /* efi log item type */ - __uint16_t efi_size; /* size of this item */ - __uint32_t efi_nextents; /* # extents to free */ - __uint64_t efi_id; /* efi identifier */ - xfs_extent_32_t efi_extents[1]; /* array of extents to free */ -} __attribute__((packed)) xfs_efi_log_format_32_t; - -typedef struct xfs_efi_log_format_64 { - __uint16_t efi_type; /* efi log item type */ - __uint16_t efi_size; /* size of this item */ - __uint32_t efi_nextents; /* # extents to free */ - __uint64_t efi_id; /* efi identifier */ - xfs_extent_64_t efi_extents[1]; /* array of extents to free */ -} xfs_efi_log_format_64_t; - -/* - * This is the structure used to lay out an efd log item in the - * log. The efd_extents array is a variable size array whose - * size is given by efd_nextents; - */ -typedef struct xfs_efd_log_format { - __uint16_t efd_type; /* efd log item type */ - __uint16_t efd_size; /* size of this item */ - __uint32_t efd_nextents; /* # of extents freed */ - __uint64_t efd_efi_id; /* id of corresponding efi */ - xfs_extent_t efd_extents[1]; /* array of extents freed */ -} xfs_efd_log_format_t; - -typedef struct xfs_efd_log_format_32 { - __uint16_t efd_type; /* efd log item type */ - __uint16_t efd_size; /* size of this item */ - __uint32_t efd_nextents; /* # of extents freed */ - __uint64_t efd_efi_id; /* id of corresponding efi */ - xfs_extent_32_t efd_extents[1]; /* array of extents freed */ -} __attribute__((packed)) xfs_efd_log_format_32_t; - -typedef struct xfs_efd_log_format_64 { - __uint16_t efd_type; /* efd log item type */ - __uint16_t efd_size; /* size of this item */ - __uint32_t efd_nextents; /* # of extents freed */ - __uint64_t efd_efi_id; /* id of corresponding efi */ - xfs_extent_64_t efd_extents[1]; /* array of extents freed */ -} xfs_efd_log_format_64_t; - -/* - * RUI/RUD (reverse mapping) log format definitions - */ -struct xfs_map_extent { - __uint64_t me_owner; - __uint64_t me_startblock; - __uint64_t me_startoff; - __uint32_t me_len; - __uint32_t me_flags; -}; - -/* rmap me_flags: upper bits are flags, lower byte is type code */ -#define XFS_RMAP_EXTENT_MAP 1 -#define XFS_RMAP_EXTENT_MAP_SHARED 2 -#define XFS_RMAP_EXTENT_UNMAP 3 -#define XFS_RMAP_EXTENT_UNMAP_SHARED 4 -#define XFS_RMAP_EXTENT_CONVERT 5 -#define XFS_RMAP_EXTENT_CONVERT_SHARED 6 -#define XFS_RMAP_EXTENT_ALLOC 7 -#define XFS_RMAP_EXTENT_FREE 8 -#define XFS_RMAP_EXTENT_TYPE_MASK 0xFF - -#define XFS_RMAP_EXTENT_ATTR_FORK (1U << 31) -#define XFS_RMAP_EXTENT_BMBT_BLOCK (1U << 30) -#define XFS_RMAP_EXTENT_UNWRITTEN (1U << 29) - -#define XFS_RMAP_EXTENT_FLAGS (XFS_RMAP_EXTENT_TYPE_MASK | \ - XFS_RMAP_EXTENT_ATTR_FORK | \ - XFS_RMAP_EXTENT_BMBT_BLOCK | \ - XFS_RMAP_EXTENT_UNWRITTEN) - -/* - * This is the structure used to lay out an rui log item in the - * log. The rui_extents field is a variable size array whose - * size is given by rui_nextents. - */ -struct xfs_rui_log_format { - __uint16_t rui_type; /* rui log item type */ - __uint16_t rui_size; /* size of this item */ - __uint32_t rui_nextents; /* # extents to free */ - __uint64_t rui_id; /* rui identifier */ - struct xfs_map_extent rui_extents[]; /* array of extents to rmap */ -}; - -static inline size_t -xfs_rui_log_format_sizeof( - unsigned int nr) -{ - return sizeof(struct xfs_rui_log_format) + - nr * sizeof(struct xfs_map_extent); -} - -/* - * This is the structure used to lay out an rud log item in the - * log. The rud_extents array is a variable size array whose - * size is given by rud_nextents; - */ -struct xfs_rud_log_format { - __uint16_t rud_type; /* rud log item type */ - __uint16_t rud_size; /* size of this item */ - __uint32_t __pad; - __uint64_t rud_rui_id; /* id of corresponding rui */ -}; - -/* - * CUI/CUD (refcount update) log format definitions - */ -struct xfs_phys_extent { - __uint64_t pe_startblock; - __uint32_t pe_len; - __uint32_t pe_flags; -}; - -/* refcount pe_flags: upper bits are flags, lower byte is type code */ -/* Type codes are taken directly from enum xfs_refcount_intent_type. */ -#define XFS_REFCOUNT_EXTENT_TYPE_MASK 0xFF - -#define XFS_REFCOUNT_EXTENT_FLAGS (XFS_REFCOUNT_EXTENT_TYPE_MASK) - -/* - * This is the structure used to lay out a cui log item in the - * log. The cui_extents field is a variable size array whose - * size is given by cui_nextents. - */ -struct xfs_cui_log_format { - __uint16_t cui_type; /* cui log item type */ - __uint16_t cui_size; /* size of this item */ - __uint32_t cui_nextents; /* # extents to free */ - __uint64_t cui_id; /* cui identifier */ - struct xfs_phys_extent cui_extents[]; /* array of extents */ -}; - -static inline size_t -xfs_cui_log_format_sizeof( - unsigned int nr) -{ - return sizeof(struct xfs_cui_log_format) + - nr * sizeof(struct xfs_phys_extent); -} - -/* - * This is the structure used to lay out a cud log item in the - * log. The cud_extents array is a variable size array whose - * size is given by cud_nextents; - */ -struct xfs_cud_log_format { - __uint16_t cud_type; /* cud log item type */ - __uint16_t cud_size; /* size of this item */ - __uint32_t __pad; - __uint64_t cud_cui_id; /* id of corresponding cui */ -}; - -/* - * BUI/BUD (inode block mapping) log format definitions - */ - -/* bmbt me_flags: upper bits are flags, lower byte is type code */ -/* Type codes are taken directly from enum xfs_bmap_intent_type. */ -#define XFS_BMAP_EXTENT_TYPE_MASK 0xFF - -#define XFS_BMAP_EXTENT_ATTR_FORK (1U << 31) -#define XFS_BMAP_EXTENT_UNWRITTEN (1U << 30) - -#define XFS_BMAP_EXTENT_FLAGS (XFS_BMAP_EXTENT_TYPE_MASK | \ - XFS_BMAP_EXTENT_ATTR_FORK | \ - XFS_BMAP_EXTENT_UNWRITTEN) - -/* - * This is the structure used to lay out an bui log item in the - * log. The bui_extents field is a variable size array whose - * size is given by bui_nextents. - */ -struct xfs_bui_log_format { - __uint16_t bui_type; /* bui log item type */ - __uint16_t bui_size; /* size of this item */ - __uint32_t bui_nextents; /* # extents to free */ - __uint64_t bui_id; /* bui identifier */ - struct xfs_map_extent bui_extents[]; /* array of extents to bmap */ -}; - -static inline size_t -xfs_bui_log_format_sizeof( - unsigned int nr) -{ - return sizeof(struct xfs_bui_log_format) + - nr * sizeof(struct xfs_map_extent); -} - -/* - * This is the structure used to lay out an bud log item in the - * log. The bud_extents array is a variable size array whose - * size is given by bud_nextents; - */ -struct xfs_bud_log_format { - __uint16_t bud_type; /* bud log item type */ - __uint16_t bud_size; /* size of this item */ - __uint32_t __pad; - __uint64_t bud_bui_id; /* id of corresponding bui */ -}; - -/* - * Dquot Log format definitions. - * - * The first two fields must be the type and size fitting into - * 32 bits : log_recovery code assumes that. - */ -typedef struct xfs_dq_logformat { - __uint16_t qlf_type; /* dquot log item type */ - __uint16_t qlf_size; /* size of this item */ - xfs_dqid_t qlf_id; /* usr/grp/proj id : 32 bits */ - __int64_t qlf_blkno; /* blkno of dquot buffer */ - __int32_t qlf_len; /* len of dquot buffer */ - __uint32_t qlf_boffset; /* off of dquot in buffer */ -} xfs_dq_logformat_t; - -/* - * log format struct for QUOTAOFF records. - * The first two fields must be the type and size fitting into - * 32 bits : log_recovery code assumes that. - * We write two LI_QUOTAOFF logitems per quotaoff, the last one keeps a pointer - * to the first and ensures that the first logitem is taken out of the AIL - * only when the last one is securely committed. - */ -typedef struct xfs_qoff_logformat { - unsigned short qf_type; /* quotaoff log item type */ - unsigned short qf_size; /* size of this item */ - unsigned int qf_flags; /* USR and/or GRP */ - char qf_pad[12]; /* padding for future */ -} xfs_qoff_logformat_t; - -/* - * Disk quotas status in m_qflags, and also sb_qflags. 16 bits. - */ -#define XFS_UQUOTA_ACCT 0x0001 /* user quota accounting ON */ -#define XFS_UQUOTA_ENFD 0x0002 /* user quota limits enforced */ -#define XFS_UQUOTA_CHKD 0x0004 /* quotacheck run on usr quotas */ -#define XFS_PQUOTA_ACCT 0x0008 /* project quota accounting ON */ -#define XFS_OQUOTA_ENFD 0x0010 /* other (grp/prj) quota limits enforced */ -#define XFS_OQUOTA_CHKD 0x0020 /* quotacheck run on other (grp/prj) quotas */ -#define XFS_GQUOTA_ACCT 0x0040 /* group quota accounting ON */ - -/* - * Conversion to and from the combined OQUOTA flag (if necessary) - * is done only in xfs_sb_qflags_to_disk() and xfs_sb_qflags_from_disk() - */ -#define XFS_GQUOTA_ENFD 0x0080 /* group quota limits enforced */ -#define XFS_GQUOTA_CHKD 0x0100 /* quotacheck run on group quotas */ -#define XFS_PQUOTA_ENFD 0x0200 /* project quota limits enforced */ -#define XFS_PQUOTA_CHKD 0x0400 /* quotacheck run on project quotas */ - -#define XFS_ALL_QUOTA_ACCT \ - (XFS_UQUOTA_ACCT | XFS_GQUOTA_ACCT | XFS_PQUOTA_ACCT) -#define XFS_ALL_QUOTA_ENFD \ - (XFS_UQUOTA_ENFD | XFS_GQUOTA_ENFD | XFS_PQUOTA_ENFD) -#define XFS_ALL_QUOTA_CHKD \ - (XFS_UQUOTA_CHKD | XFS_GQUOTA_CHKD | XFS_PQUOTA_CHKD) - -#define XFS_MOUNT_QUOTA_ALL (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD|\ - XFS_UQUOTA_CHKD|XFS_GQUOTA_ACCT|\ - XFS_GQUOTA_ENFD|XFS_GQUOTA_CHKD|\ - XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD|\ - XFS_PQUOTA_CHKD) - -/* - * Inode create log item structure - * - * Log recovery assumes the first two entries are the type and size and they fit - * in 32 bits. Also in host order (ugh) so they have to be 32 bit aligned so - * decoding can be done correctly. - */ -struct xfs_icreate_log { - __uint16_t icl_type; /* type of log format structure */ - __uint16_t icl_size; /* size of log format structure */ - __be32 icl_ag; /* ag being allocated in */ - __be32 icl_agbno; /* start block of inode range */ - __be32 icl_count; /* number of inodes to initialise */ - __be32 icl_isize; /* size of inodes */ - __be32 icl_length; /* length of extent to initialise */ - __be32 icl_gen; /* inode generation number to use */ -}; - -#endif /* __XFS_LOG_FORMAT_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_log_recover.h b/src/linux/fs/xfs/libxfs/xfs_log_recover.h deleted file mode 100644 index 8e385f9..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_log_recover.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2000,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_LOG_RECOVER_H__ -#define __XFS_LOG_RECOVER_H__ - -/* - * Macros, structures, prototypes for internal log manager use. - */ - -#define XLOG_RHASH_BITS 4 -#define XLOG_RHASH_SIZE 16 -#define XLOG_RHASH_SHIFT 2 -#define XLOG_RHASH(tid) \ - ((((__uint32_t)tid)>>XLOG_RHASH_SHIFT) & (XLOG_RHASH_SIZE-1)) - -#define XLOG_MAX_REGIONS_IN_ITEM (XFS_MAX_BLOCKSIZE / XFS_BLF_CHUNK / 2 + 1) - - -/* - * item headers are in ri_buf[0]. Additional buffers follow. - */ -typedef struct xlog_recover_item { - struct list_head ri_list; - int ri_type; - int ri_cnt; /* count of regions found */ - int ri_total; /* total regions */ - xfs_log_iovec_t *ri_buf; /* ptr to regions buffer */ -} xlog_recover_item_t; - -struct xlog_tid; -typedef struct xlog_recover { - struct hlist_node r_list; - xlog_tid_t r_log_tid; /* log's transaction id */ - xfs_trans_header_t r_theader; /* trans header for partial */ - int r_state; /* not needed */ - xfs_lsn_t r_lsn; /* xact lsn */ - struct list_head r_itemq; /* q for items */ -} xlog_recover_t; - -#define ITEM_TYPE(i) (*(ushort *)(i)->ri_buf[0].i_addr) - -/* - * This is the number of entries in the l_buf_cancel_table used during - * recovery. - */ -#define XLOG_BC_TABLE_SIZE 64 - -#define XLOG_RECOVER_CRCPASS 0 -#define XLOG_RECOVER_PASS1 1 -#define XLOG_RECOVER_PASS2 2 - -#endif /* __XFS_LOG_RECOVER_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_log_rlimit.c b/src/linux/fs/xfs/libxfs/xfs_log_rlimit.c deleted file mode 100644 index c105979..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_log_rlimit.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2013 Jie Liu. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_trans_space.h" -#include "xfs_inode.h" -#include "xfs_da_btree.h" -#include "xfs_attr_leaf.h" -#include "xfs_bmap_btree.h" - -/* - * Calculate the maximum length in bytes that would be required for a local - * attribute value as large attributes out of line are not logged. - */ -STATIC int -xfs_log_calc_max_attrsetm_res( - struct xfs_mount *mp) -{ - int size; - int nblks; - - size = xfs_attr_leaf_entsize_local_max(mp->m_attr_geo->blksize) - - MAXNAMELEN - 1; - nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); - nblks += XFS_B_TO_FSB(mp, size); - nblks += XFS_NEXTENTADD_SPACE_RES(mp, size, XFS_ATTR_FORK); - - return M_RES(mp)->tr_attrsetm.tr_logres + - M_RES(mp)->tr_attrsetrt.tr_logres * nblks; -} - -/* - * Iterate over the log space reservation table to figure out and return - * the maximum one in terms of the pre-calculated values which were done - * at mount time. - */ -STATIC void -xfs_log_get_max_trans_res( - struct xfs_mount *mp, - struct xfs_trans_res *max_resp) -{ - struct xfs_trans_res *resp; - struct xfs_trans_res *end_resp; - int log_space = 0; - int attr_space; - - attr_space = xfs_log_calc_max_attrsetm_res(mp); - - resp = (struct xfs_trans_res *)M_RES(mp); - end_resp = (struct xfs_trans_res *)(M_RES(mp) + 1); - for (; resp < end_resp; resp++) { - int tmp = resp->tr_logcount > 1 ? - resp->tr_logres * resp->tr_logcount : - resp->tr_logres; - if (log_space < tmp) { - log_space = tmp; - *max_resp = *resp; /* struct copy */ - } - } - - if (attr_space > log_space) { - *max_resp = M_RES(mp)->tr_attrsetm; /* struct copy */ - max_resp->tr_logres = attr_space; - } -} - -/* - * Calculate the minimum valid log size for the given superblock configuration. - * Used to calculate the minimum log size at mkfs time, and to determine if - * the log is large enough or not at mount time. Returns the minimum size in - * filesystem block size units. - */ -int -xfs_log_calc_minimum_size( - struct xfs_mount *mp) -{ - struct xfs_trans_res tres = {0}; - int max_logres; - int min_logblks = 0; - int lsunit = 0; - - xfs_log_get_max_trans_res(mp, &tres); - - max_logres = xfs_log_calc_unit_res(mp, tres.tr_logres); - if (tres.tr_logcount > 1) - max_logres *= tres.tr_logcount; - - if (xfs_sb_version_haslogv2(&mp->m_sb) && mp->m_sb.sb_logsunit > 1) - lsunit = BTOBB(mp->m_sb.sb_logsunit); - - /* - * Two factors should be taken into account for calculating the minimum - * log space. - * 1) The fundamental limitation is that no single transaction can be - * larger than half size of the log. - * - * From mkfs.xfs, this is considered by the XFS_MIN_LOG_FACTOR - * define, which is set to 3. That means we can definitely fit - * maximally sized 2 transactions in the log. We'll use this same - * value here. - * - * 2) If the lsunit option is specified, a transaction requires 2 LSU - * for the reservation because there are two log writes that can - * require padding - the transaction data and the commit record which - * are written separately and both can require padding to the LSU. - * Consider that we can have an active CIL reservation holding 2*LSU, - * but the CIL is not over a push threshold, in this case, if we - * don't have enough log space for at one new transaction, which - * includes another 2*LSU in the reservation, we will run into dead - * loop situation in log space grant procedure. i.e. - * xlog_grant_head_wait(). - * - * Hence the log size needs to be able to contain two maximally sized - * and padded transactions, which is (2 * (2 * LSU + maxlres)). - * - * Also, the log size should be a multiple of the log stripe unit, round - * it up to lsunit boundary if lsunit is specified. - */ - if (lsunit) { - min_logblks = roundup_64(BTOBB(max_logres), lsunit) + - 2 * lsunit; - } else - min_logblks = BTOBB(max_logres) + 2 * BBSIZE; - min_logblks *= XFS_MIN_LOG_FACTOR; - - return XFS_BB_TO_FSB(mp, min_logblks); -} diff --git a/src/linux/fs/xfs/libxfs/xfs_quota_defs.h b/src/linux/fs/xfs/libxfs/xfs_quota_defs.h deleted file mode 100644 index 8eed512..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_quota_defs.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_QUOTA_DEFS_H__ -#define __XFS_QUOTA_DEFS_H__ - -/* - * Quota definitions shared between user and kernel source trees. - */ - -/* - * Even though users may not have quota limits occupying all 64-bits, - * they may need 64-bit accounting. Hence, 64-bit quota-counters, - * and quota-limits. This is a waste in the common case, but hey ... - */ -typedef __uint64_t xfs_qcnt_t; -typedef __uint16_t xfs_qwarncnt_t; - -/* - * flags for q_flags field in the dquot. - */ -#define XFS_DQ_USER 0x0001 /* a user quota */ -#define XFS_DQ_PROJ 0x0002 /* project quota */ -#define XFS_DQ_GROUP 0x0004 /* a group quota */ -#define XFS_DQ_DIRTY 0x0008 /* dquot is dirty */ -#define XFS_DQ_FREEING 0x0010 /* dquot is being torn down */ - -#define XFS_DQ_ALLTYPES (XFS_DQ_USER|XFS_DQ_PROJ|XFS_DQ_GROUP) - -#define XFS_DQ_FLAGS \ - { XFS_DQ_USER, "USER" }, \ - { XFS_DQ_PROJ, "PROJ" }, \ - { XFS_DQ_GROUP, "GROUP" }, \ - { XFS_DQ_DIRTY, "DIRTY" }, \ - { XFS_DQ_FREEING, "FREEING" } - -/* - * We have the possibility of all three quota types being active at once, and - * hence free space modification requires modification of all three current - * dquots in a single transaction. For this case we need to have a reservation - * of at least 3 dquots. - * - * However, a chmod operation can change both UID and GID in a single - * transaction, resulting in requiring {old, new} x {uid, gid} dquots to be - * modified. Hence for this case we need to reserve space for at least 4 dquots. - * - * And in the worst case, there's a rename operation that can be modifying up to - * 4 inodes with dquots attached to them. In reality, the only inodes that can - * have their dquots modified are the source and destination directory inodes - * due to directory name creation and removal. That can require space allocation - * and/or freeing on both directory inodes, and hence all three dquots on each - * inode can be modified. And if the directories are world writeable, all the - * dquots can be unique and so 6 dquots can be modified.... - * - * And, of course, we also need to take into account the dquot log format item - * used to describe each dquot. - */ -#define XFS_DQUOT_LOGRES(mp) \ - ((sizeof(struct xfs_dq_logformat) + sizeof(struct xfs_disk_dquot)) * 6) - -#define XFS_IS_QUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_ALL_QUOTA_ACCT) -#define XFS_IS_UQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_UQUOTA_ACCT) -#define XFS_IS_PQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_PQUOTA_ACCT) -#define XFS_IS_GQUOTA_RUNNING(mp) ((mp)->m_qflags & XFS_GQUOTA_ACCT) -#define XFS_IS_UQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_UQUOTA_ENFD) -#define XFS_IS_GQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_GQUOTA_ENFD) -#define XFS_IS_PQUOTA_ENFORCED(mp) ((mp)->m_qflags & XFS_PQUOTA_ENFD) - -/* - * Incore only flags for quotaoff - these bits get cleared when quota(s) - * are in the process of getting turned off. These flags are in m_qflags but - * never in sb_qflags. - */ -#define XFS_UQUOTA_ACTIVE 0x1000 /* uquotas are being turned off */ -#define XFS_GQUOTA_ACTIVE 0x2000 /* gquotas are being turned off */ -#define XFS_PQUOTA_ACTIVE 0x4000 /* pquotas are being turned off */ -#define XFS_ALL_QUOTA_ACTIVE \ - (XFS_UQUOTA_ACTIVE | XFS_GQUOTA_ACTIVE | XFS_PQUOTA_ACTIVE) - -/* - * Checking XFS_IS_*QUOTA_ON() while holding any inode lock guarantees - * quota will be not be switched off as long as that inode lock is held. - */ -#define XFS_IS_QUOTA_ON(mp) ((mp)->m_qflags & (XFS_UQUOTA_ACTIVE | \ - XFS_GQUOTA_ACTIVE | \ - XFS_PQUOTA_ACTIVE)) -#define XFS_IS_UQUOTA_ON(mp) ((mp)->m_qflags & XFS_UQUOTA_ACTIVE) -#define XFS_IS_GQUOTA_ON(mp) ((mp)->m_qflags & XFS_GQUOTA_ACTIVE) -#define XFS_IS_PQUOTA_ON(mp) ((mp)->m_qflags & XFS_PQUOTA_ACTIVE) - -/* - * Flags to tell various functions what to do. Not all of these are meaningful - * to a single function. None of these XFS_QMOPT_* flags are meant to have - * persistent values (ie. their values can and will change between versions) - */ -#define XFS_QMOPT_DQALLOC 0x0000002 /* alloc dquot ondisk if needed */ -#define XFS_QMOPT_UQUOTA 0x0000004 /* user dquot requested */ -#define XFS_QMOPT_PQUOTA 0x0000008 /* project dquot requested */ -#define XFS_QMOPT_FORCE_RES 0x0000010 /* ignore quota limits */ -#define XFS_QMOPT_SBVERSION 0x0000040 /* change superblock version num */ -#define XFS_QMOPT_DOWARN 0x0000400 /* increase warning cnt if needed */ -#define XFS_QMOPT_DQREPAIR 0x0001000 /* repair dquot if damaged */ -#define XFS_QMOPT_GQUOTA 0x0002000 /* group dquot requested */ -#define XFS_QMOPT_ENOSPC 0x0004000 /* enospc instead of edquot (prj) */ -#define XFS_QMOPT_DQNEXT 0x0008000 /* return next dquot >= this ID */ - -/* - * flags to xfs_trans_mod_dquot to indicate which field needs to be - * modified. - */ -#define XFS_QMOPT_RES_REGBLKS 0x0010000 -#define XFS_QMOPT_RES_RTBLKS 0x0020000 -#define XFS_QMOPT_BCOUNT 0x0040000 -#define XFS_QMOPT_ICOUNT 0x0080000 -#define XFS_QMOPT_RTBCOUNT 0x0100000 -#define XFS_QMOPT_DELBCOUNT 0x0200000 -#define XFS_QMOPT_DELRTBCOUNT 0x0400000 -#define XFS_QMOPT_RES_INOS 0x0800000 - -/* - * flags for dqalloc. - */ -#define XFS_QMOPT_INHERIT 0x1000000 - -/* - * flags to xfs_trans_mod_dquot. - */ -#define XFS_TRANS_DQ_RES_BLKS XFS_QMOPT_RES_REGBLKS -#define XFS_TRANS_DQ_RES_RTBLKS XFS_QMOPT_RES_RTBLKS -#define XFS_TRANS_DQ_RES_INOS XFS_QMOPT_RES_INOS -#define XFS_TRANS_DQ_BCOUNT XFS_QMOPT_BCOUNT -#define XFS_TRANS_DQ_DELBCOUNT XFS_QMOPT_DELBCOUNT -#define XFS_TRANS_DQ_ICOUNT XFS_QMOPT_ICOUNT -#define XFS_TRANS_DQ_RTBCOUNT XFS_QMOPT_RTBCOUNT -#define XFS_TRANS_DQ_DELRTBCOUNT XFS_QMOPT_DELRTBCOUNT - - -#define XFS_QMOPT_QUOTALL \ - (XFS_QMOPT_UQUOTA | XFS_QMOPT_PQUOTA | XFS_QMOPT_GQUOTA) -#define XFS_QMOPT_RESBLK_MASK (XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_RES_RTBLKS) - -extern int xfs_dqcheck(struct xfs_mount *mp, xfs_disk_dquot_t *ddq, - xfs_dqid_t id, uint type, uint flags, const char *str); -extern int xfs_calc_dquots_per_chunk(unsigned int nbblks); - -#endif /* __XFS_QUOTA_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_refcount.c b/src/linux/fs/xfs/libxfs/xfs_refcount.c deleted file mode 100644 index b177ef3..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_refcount.c +++ /dev/null @@ -1,1698 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_btree.h" -#include "xfs_bmap.h" -#include "xfs_refcount_btree.h" -#include "xfs_alloc.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_cksum.h" -#include "xfs_trans.h" -#include "xfs_bit.h" -#include "xfs_refcount.h" -#include "xfs_rmap.h" - -/* Allowable refcount adjustment amounts. */ -enum xfs_refc_adjust_op { - XFS_REFCOUNT_ADJUST_INCREASE = 1, - XFS_REFCOUNT_ADJUST_DECREASE = -1, - XFS_REFCOUNT_ADJUST_COW_ALLOC = 0, - XFS_REFCOUNT_ADJUST_COW_FREE = -1, -}; - -STATIC int __xfs_refcount_cow_alloc(struct xfs_btree_cur *rcur, - xfs_agblock_t agbno, xfs_extlen_t aglen, - struct xfs_defer_ops *dfops); -STATIC int __xfs_refcount_cow_free(struct xfs_btree_cur *rcur, - xfs_agblock_t agbno, xfs_extlen_t aglen, - struct xfs_defer_ops *dfops); - -/* - * Look up the first record less than or equal to [bno, len] in the btree - * given by cur. - */ -int -xfs_refcount_lookup_le( - struct xfs_btree_cur *cur, - xfs_agblock_t bno, - int *stat) -{ - trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_private.a.agno, bno, - XFS_LOOKUP_LE); - cur->bc_rec.rc.rc_startblock = bno; - cur->bc_rec.rc.rc_blockcount = 0; - return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat); -} - -/* - * Look up the first record greater than or equal to [bno, len] in the btree - * given by cur. - */ -int -xfs_refcount_lookup_ge( - struct xfs_btree_cur *cur, - xfs_agblock_t bno, - int *stat) -{ - trace_xfs_refcount_lookup(cur->bc_mp, cur->bc_private.a.agno, bno, - XFS_LOOKUP_GE); - cur->bc_rec.rc.rc_startblock = bno; - cur->bc_rec.rc.rc_blockcount = 0; - return xfs_btree_lookup(cur, XFS_LOOKUP_GE, stat); -} - -/* Convert on-disk record to in-core format. */ -static inline void -xfs_refcount_btrec_to_irec( - union xfs_btree_rec *rec, - struct xfs_refcount_irec *irec) -{ - irec->rc_startblock = be32_to_cpu(rec->refc.rc_startblock); - irec->rc_blockcount = be32_to_cpu(rec->refc.rc_blockcount); - irec->rc_refcount = be32_to_cpu(rec->refc.rc_refcount); -} - -/* - * Get the data from the pointed-to record. - */ -int -xfs_refcount_get_rec( - struct xfs_btree_cur *cur, - struct xfs_refcount_irec *irec, - int *stat) -{ - union xfs_btree_rec *rec; - int error; - - error = xfs_btree_get_rec(cur, &rec, stat); - if (!error && *stat == 1) { - xfs_refcount_btrec_to_irec(rec, irec); - trace_xfs_refcount_get(cur->bc_mp, cur->bc_private.a.agno, - irec); - } - return error; -} - -/* - * Update the record referred to by cur to the value given - * by [bno, len, refcount]. - * This either works (return 0) or gets an EFSCORRUPTED error. - */ -STATIC int -xfs_refcount_update( - struct xfs_btree_cur *cur, - struct xfs_refcount_irec *irec) -{ - union xfs_btree_rec rec; - int error; - - trace_xfs_refcount_update(cur->bc_mp, cur->bc_private.a.agno, irec); - rec.refc.rc_startblock = cpu_to_be32(irec->rc_startblock); - rec.refc.rc_blockcount = cpu_to_be32(irec->rc_blockcount); - rec.refc.rc_refcount = cpu_to_be32(irec->rc_refcount); - error = xfs_btree_update(cur, &rec); - if (error) - trace_xfs_refcount_update_error(cur->bc_mp, - cur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -/* - * Insert the record referred to by cur to the value given - * by [bno, len, refcount]. - * This either works (return 0) or gets an EFSCORRUPTED error. - */ -STATIC int -xfs_refcount_insert( - struct xfs_btree_cur *cur, - struct xfs_refcount_irec *irec, - int *i) -{ - int error; - - trace_xfs_refcount_insert(cur->bc_mp, cur->bc_private.a.agno, irec); - cur->bc_rec.rc.rc_startblock = irec->rc_startblock; - cur->bc_rec.rc.rc_blockcount = irec->rc_blockcount; - cur->bc_rec.rc.rc_refcount = irec->rc_refcount; - error = xfs_btree_insert(cur, i); - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, *i == 1, out_error); -out_error: - if (error) - trace_xfs_refcount_insert_error(cur->bc_mp, - cur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -/* - * Remove the record referred to by cur, then set the pointer to the spot - * where the record could be re-inserted, in case we want to increment or - * decrement the cursor. - * This either works (return 0) or gets an EFSCORRUPTED error. - */ -STATIC int -xfs_refcount_delete( - struct xfs_btree_cur *cur, - int *i) -{ - struct xfs_refcount_irec irec; - int found_rec; - int error; - - error = xfs_refcount_get_rec(cur, &irec, &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); - trace_xfs_refcount_delete(cur->bc_mp, cur->bc_private.a.agno, &irec); - error = xfs_btree_delete(cur, i); - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, *i == 1, out_error); - if (error) - goto out_error; - error = xfs_refcount_lookup_ge(cur, irec.rc_startblock, &found_rec); -out_error: - if (error) - trace_xfs_refcount_delete_error(cur->bc_mp, - cur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -/* - * Adjusting the Reference Count - * - * As stated elsewhere, the reference count btree (refcbt) stores - * >1 reference counts for extents of physical blocks. In this - * operation, we're either raising or lowering the reference count of - * some subrange stored in the tree: - * - * <------ adjustment range ------> - * ----+ +---+-----+ +--+--------+--------- - * 2 | | 3 | 4 | |17| 55 | 10 - * ----+ +---+-----+ +--+--------+--------- - * X axis is physical blocks number; - * reference counts are the numbers inside the rectangles - * - * The first thing we need to do is to ensure that there are no - * refcount extents crossing either boundary of the range to be - * adjusted. For any extent that does cross a boundary, split it into - * two extents so that we can increment the refcount of one of the - * pieces later: - * - * <------ adjustment range ------> - * ----+ +---+-----+ +--+--------+----+---- - * 2 | | 3 | 2 | |17| 55 | 10 | 10 - * ----+ +---+-----+ +--+--------+----+---- - * - * For this next step, let's assume that all the physical blocks in - * the adjustment range are mapped to a file and are therefore in use - * at least once. Therefore, we can infer that any gap in the - * refcount tree within the adjustment range represents a physical - * extent with refcount == 1: - * - * <------ adjustment range ------> - * ----+---+---+-----+-+--+--------+----+---- - * 2 |"1"| 3 | 2 |1|17| 55 | 10 | 10 - * ----+---+---+-----+-+--+--------+----+---- - * ^ - * - * For each extent that falls within the interval range, figure out - * which extent is to the left or the right of that extent. Now we - * have a left, current, and right extent. If the new reference count - * of the center extent enables us to merge left, center, and right - * into one record covering all three, do so. If the center extent is - * at the left end of the range, abuts the left extent, and its new - * reference count matches the left extent's record, then merge them. - * If the center extent is at the right end of the range, abuts the - * right extent, and the reference counts match, merge those. In the - * example, we can left merge (assuming an increment operation): - * - * <------ adjustment range ------> - * --------+---+-----+-+--+--------+----+---- - * 2 | 3 | 2 |1|17| 55 | 10 | 10 - * --------+---+-----+-+--+--------+----+---- - * ^ - * - * For all other extents within the range, adjust the reference count - * or delete it if the refcount falls below 2. If we were - * incrementing, the end result looks like this: - * - * <------ adjustment range ------> - * --------+---+-----+-+--+--------+----+---- - * 2 | 4 | 3 |2|18| 56 | 11 | 10 - * --------+---+-----+-+--+--------+----+---- - * - * The result of a decrement operation looks as such: - * - * <------ adjustment range ------> - * ----+ +---+ +--+--------+----+---- - * 2 | | 2 | |16| 54 | 9 | 10 - * ----+ +---+ +--+--------+----+---- - * DDDD 111111DD - * - * The blocks marked "D" are freed; the blocks marked "1" are only - * referenced once and therefore the record is removed from the - * refcount btree. - */ - -/* Next block after this extent. */ -static inline xfs_agblock_t -xfs_refc_next( - struct xfs_refcount_irec *rc) -{ - return rc->rc_startblock + rc->rc_blockcount; -} - -/* - * Split a refcount extent that crosses agbno. - */ -STATIC int -xfs_refcount_split_extent( - struct xfs_btree_cur *cur, - xfs_agblock_t agbno, - bool *shape_changed) -{ - struct xfs_refcount_irec rcext, tmp; - int found_rec; - int error; - - *shape_changed = false; - error = xfs_refcount_lookup_le(cur, agbno, &found_rec); - if (error) - goto out_error; - if (!found_rec) - return 0; - - error = xfs_refcount_get_rec(cur, &rcext, &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); - if (rcext.rc_startblock == agbno || xfs_refc_next(&rcext) <= agbno) - return 0; - - *shape_changed = true; - trace_xfs_refcount_split_extent(cur->bc_mp, cur->bc_private.a.agno, - &rcext, agbno); - - /* Establish the right extent. */ - tmp = rcext; - tmp.rc_startblock = agbno; - tmp.rc_blockcount -= (agbno - rcext.rc_startblock); - error = xfs_refcount_update(cur, &tmp); - if (error) - goto out_error; - - /* Insert the left extent. */ - tmp = rcext; - tmp.rc_blockcount = agbno - rcext.rc_startblock; - error = xfs_refcount_insert(cur, &tmp, &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); - return error; - -out_error: - trace_xfs_refcount_split_extent_error(cur->bc_mp, - cur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -/* - * Merge the left, center, and right extents. - */ -STATIC int -xfs_refcount_merge_center_extents( - struct xfs_btree_cur *cur, - struct xfs_refcount_irec *left, - struct xfs_refcount_irec *center, - struct xfs_refcount_irec *right, - unsigned long long extlen, - xfs_agblock_t *agbno, - xfs_extlen_t *aglen) -{ - int error; - int found_rec; - - trace_xfs_refcount_merge_center_extents(cur->bc_mp, - cur->bc_private.a.agno, left, center, right); - - /* - * Make sure the center and right extents are not in the btree. - * If the center extent was synthesized, the first delete call - * removes the right extent and we skip the second deletion. - * If center and right were in the btree, then the first delete - * call removes the center and the second one removes the right - * extent. - */ - error = xfs_refcount_lookup_ge(cur, center->rc_startblock, - &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); - - error = xfs_refcount_delete(cur, &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); - - if (center->rc_refcount > 1) { - error = xfs_refcount_delete(cur, &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, - out_error); - } - - /* Enlarge the left extent. */ - error = xfs_refcount_lookup_le(cur, left->rc_startblock, - &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); - - left->rc_blockcount = extlen; - error = xfs_refcount_update(cur, left); - if (error) - goto out_error; - - *aglen = 0; - return error; - -out_error: - trace_xfs_refcount_merge_center_extents_error(cur->bc_mp, - cur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -/* - * Merge with the left extent. - */ -STATIC int -xfs_refcount_merge_left_extent( - struct xfs_btree_cur *cur, - struct xfs_refcount_irec *left, - struct xfs_refcount_irec *cleft, - xfs_agblock_t *agbno, - xfs_extlen_t *aglen) -{ - int error; - int found_rec; - - trace_xfs_refcount_merge_left_extent(cur->bc_mp, - cur->bc_private.a.agno, left, cleft); - - /* If the extent at agbno (cleft) wasn't synthesized, remove it. */ - if (cleft->rc_refcount > 1) { - error = xfs_refcount_lookup_le(cur, cleft->rc_startblock, - &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, - out_error); - - error = xfs_refcount_delete(cur, &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, - out_error); - } - - /* Enlarge the left extent. */ - error = xfs_refcount_lookup_le(cur, left->rc_startblock, - &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); - - left->rc_blockcount += cleft->rc_blockcount; - error = xfs_refcount_update(cur, left); - if (error) - goto out_error; - - *agbno += cleft->rc_blockcount; - *aglen -= cleft->rc_blockcount; - return error; - -out_error: - trace_xfs_refcount_merge_left_extent_error(cur->bc_mp, - cur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -/* - * Merge with the right extent. - */ -STATIC int -xfs_refcount_merge_right_extent( - struct xfs_btree_cur *cur, - struct xfs_refcount_irec *right, - struct xfs_refcount_irec *cright, - xfs_agblock_t *agbno, - xfs_extlen_t *aglen) -{ - int error; - int found_rec; - - trace_xfs_refcount_merge_right_extent(cur->bc_mp, - cur->bc_private.a.agno, cright, right); - - /* - * If the extent ending at agbno+aglen (cright) wasn't synthesized, - * remove it. - */ - if (cright->rc_refcount > 1) { - error = xfs_refcount_lookup_le(cur, cright->rc_startblock, - &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, - out_error); - - error = xfs_refcount_delete(cur, &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, - out_error); - } - - /* Enlarge the right extent. */ - error = xfs_refcount_lookup_le(cur, right->rc_startblock, - &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); - - right->rc_startblock -= cright->rc_blockcount; - right->rc_blockcount += cright->rc_blockcount; - error = xfs_refcount_update(cur, right); - if (error) - goto out_error; - - *aglen -= cright->rc_blockcount; - return error; - -out_error: - trace_xfs_refcount_merge_right_extent_error(cur->bc_mp, - cur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -#define XFS_FIND_RCEXT_SHARED 1 -#define XFS_FIND_RCEXT_COW 2 -/* - * Find the left extent and the one after it (cleft). This function assumes - * that we've already split any extent crossing agbno. - */ -STATIC int -xfs_refcount_find_left_extents( - struct xfs_btree_cur *cur, - struct xfs_refcount_irec *left, - struct xfs_refcount_irec *cleft, - xfs_agblock_t agbno, - xfs_extlen_t aglen, - int flags) -{ - struct xfs_refcount_irec tmp; - int error; - int found_rec; - - left->rc_startblock = cleft->rc_startblock = NULLAGBLOCK; - error = xfs_refcount_lookup_le(cur, agbno - 1, &found_rec); - if (error) - goto out_error; - if (!found_rec) - return 0; - - error = xfs_refcount_get_rec(cur, &tmp, &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); - - if (xfs_refc_next(&tmp) != agbno) - return 0; - if ((flags & XFS_FIND_RCEXT_SHARED) && tmp.rc_refcount < 2) - return 0; - if ((flags & XFS_FIND_RCEXT_COW) && tmp.rc_refcount > 1) - return 0; - /* We have a left extent; retrieve (or invent) the next right one */ - *left = tmp; - - error = xfs_btree_increment(cur, 0, &found_rec); - if (error) - goto out_error; - if (found_rec) { - error = xfs_refcount_get_rec(cur, &tmp, &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, - out_error); - - /* if tmp starts at the end of our range, just use that */ - if (tmp.rc_startblock == agbno) - *cleft = tmp; - else { - /* - * There's a gap in the refcntbt at the start of the - * range we're interested in (refcount == 1) so - * synthesize the implied extent and pass it back. - * We assume here that the agbno/aglen range was - * passed in from a data fork extent mapping and - * therefore is allocated to exactly one owner. - */ - cleft->rc_startblock = agbno; - cleft->rc_blockcount = min(aglen, - tmp.rc_startblock - agbno); - cleft->rc_refcount = 1; - } - } else { - /* - * No extents, so pretend that there's one covering the whole - * range. - */ - cleft->rc_startblock = agbno; - cleft->rc_blockcount = aglen; - cleft->rc_refcount = 1; - } - trace_xfs_refcount_find_left_extent(cur->bc_mp, cur->bc_private.a.agno, - left, cleft, agbno); - return error; - -out_error: - trace_xfs_refcount_find_left_extent_error(cur->bc_mp, - cur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -/* - * Find the right extent and the one before it (cright). This function - * assumes that we've already split any extents crossing agbno + aglen. - */ -STATIC int -xfs_refcount_find_right_extents( - struct xfs_btree_cur *cur, - struct xfs_refcount_irec *right, - struct xfs_refcount_irec *cright, - xfs_agblock_t agbno, - xfs_extlen_t aglen, - int flags) -{ - struct xfs_refcount_irec tmp; - int error; - int found_rec; - - right->rc_startblock = cright->rc_startblock = NULLAGBLOCK; - error = xfs_refcount_lookup_ge(cur, agbno + aglen, &found_rec); - if (error) - goto out_error; - if (!found_rec) - return 0; - - error = xfs_refcount_get_rec(cur, &tmp, &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, out_error); - - if (tmp.rc_startblock != agbno + aglen) - return 0; - if ((flags & XFS_FIND_RCEXT_SHARED) && tmp.rc_refcount < 2) - return 0; - if ((flags & XFS_FIND_RCEXT_COW) && tmp.rc_refcount > 1) - return 0; - /* We have a right extent; retrieve (or invent) the next left one */ - *right = tmp; - - error = xfs_btree_decrement(cur, 0, &found_rec); - if (error) - goto out_error; - if (found_rec) { - error = xfs_refcount_get_rec(cur, &tmp, &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, found_rec == 1, - out_error); - - /* if tmp ends at the end of our range, just use that */ - if (xfs_refc_next(&tmp) == agbno + aglen) - *cright = tmp; - else { - /* - * There's a gap in the refcntbt at the end of the - * range we're interested in (refcount == 1) so - * create the implied extent and pass it back. - * We assume here that the agbno/aglen range was - * passed in from a data fork extent mapping and - * therefore is allocated to exactly one owner. - */ - cright->rc_startblock = max(agbno, xfs_refc_next(&tmp)); - cright->rc_blockcount = right->rc_startblock - - cright->rc_startblock; - cright->rc_refcount = 1; - } - } else { - /* - * No extents, so pretend that there's one covering the whole - * range. - */ - cright->rc_startblock = agbno; - cright->rc_blockcount = aglen; - cright->rc_refcount = 1; - } - trace_xfs_refcount_find_right_extent(cur->bc_mp, cur->bc_private.a.agno, - cright, right, agbno + aglen); - return error; - -out_error: - trace_xfs_refcount_find_right_extent_error(cur->bc_mp, - cur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -/* Is this extent valid? */ -static inline bool -xfs_refc_valid( - struct xfs_refcount_irec *rc) -{ - return rc->rc_startblock != NULLAGBLOCK; -} - -/* - * Try to merge with any extents on the boundaries of the adjustment range. - */ -STATIC int -xfs_refcount_merge_extents( - struct xfs_btree_cur *cur, - xfs_agblock_t *agbno, - xfs_extlen_t *aglen, - enum xfs_refc_adjust_op adjust, - int flags, - bool *shape_changed) -{ - struct xfs_refcount_irec left = {0}, cleft = {0}; - struct xfs_refcount_irec cright = {0}, right = {0}; - int error; - unsigned long long ulen; - bool cequal; - - *shape_changed = false; - /* - * Find the extent just below agbno [left], just above agbno [cleft], - * just below (agbno + aglen) [cright], and just above (agbno + aglen) - * [right]. - */ - error = xfs_refcount_find_left_extents(cur, &left, &cleft, *agbno, - *aglen, flags); - if (error) - return error; - error = xfs_refcount_find_right_extents(cur, &right, &cright, *agbno, - *aglen, flags); - if (error) - return error; - - /* No left or right extent to merge; exit. */ - if (!xfs_refc_valid(&left) && !xfs_refc_valid(&right)) - return 0; - - cequal = (cleft.rc_startblock == cright.rc_startblock) && - (cleft.rc_blockcount == cright.rc_blockcount); - - /* Try to merge left, cleft, and right. cleft must == cright. */ - ulen = (unsigned long long)left.rc_blockcount + cleft.rc_blockcount + - right.rc_blockcount; - if (xfs_refc_valid(&left) && xfs_refc_valid(&right) && - xfs_refc_valid(&cleft) && xfs_refc_valid(&cright) && cequal && - left.rc_refcount == cleft.rc_refcount + adjust && - right.rc_refcount == cleft.rc_refcount + adjust && - ulen < MAXREFCEXTLEN) { - *shape_changed = true; - return xfs_refcount_merge_center_extents(cur, &left, &cleft, - &right, ulen, agbno, aglen); - } - - /* Try to merge left and cleft. */ - ulen = (unsigned long long)left.rc_blockcount + cleft.rc_blockcount; - if (xfs_refc_valid(&left) && xfs_refc_valid(&cleft) && - left.rc_refcount == cleft.rc_refcount + adjust && - ulen < MAXREFCEXTLEN) { - *shape_changed = true; - error = xfs_refcount_merge_left_extent(cur, &left, &cleft, - agbno, aglen); - if (error) - return error; - - /* - * If we just merged left + cleft and cleft == cright, - * we no longer have a cright to merge with right. We're done. - */ - if (cequal) - return 0; - } - - /* Try to merge cright and right. */ - ulen = (unsigned long long)right.rc_blockcount + cright.rc_blockcount; - if (xfs_refc_valid(&right) && xfs_refc_valid(&cright) && - right.rc_refcount == cright.rc_refcount + adjust && - ulen < MAXREFCEXTLEN) { - *shape_changed = true; - return xfs_refcount_merge_right_extent(cur, &right, &cright, - agbno, aglen); - } - - return error; -} - -/* - * While we're adjusting the refcounts records of an extent, we have - * to keep an eye on the number of extents we're dirtying -- run too - * many in a single transaction and we'll exceed the transaction's - * reservation and crash the fs. Each record adds 12 bytes to the - * log (plus any key updates) so we'll conservatively assume 24 bytes - * per record. We must also leave space for btree splits on both ends - * of the range and space for the CUD and a new CUI. - * - * XXX: This is a pretty hand-wavy estimate. The penalty for guessing - * true incorrectly is a shutdown FS; the penalty for guessing false - * incorrectly is more transaction rolls than might be necessary. - * Be conservative here. - */ -static bool -xfs_refcount_still_have_space( - struct xfs_btree_cur *cur) -{ - unsigned long overhead; - - overhead = cur->bc_private.a.priv.refc.shape_changes * - xfs_allocfree_log_count(cur->bc_mp, 1); - overhead *= cur->bc_mp->m_sb.sb_blocksize; - - /* - * Only allow 2 refcount extent updates per transaction if the - * refcount continue update "error" has been injected. - */ - if (cur->bc_private.a.priv.refc.nr_ops > 2 && - XFS_TEST_ERROR(false, cur->bc_mp, - XFS_ERRTAG_REFCOUNT_CONTINUE_UPDATE, - XFS_RANDOM_REFCOUNT_CONTINUE_UPDATE)) - return false; - - if (cur->bc_private.a.priv.refc.nr_ops == 0) - return true; - else if (overhead > cur->bc_tp->t_log_res) - return false; - return cur->bc_tp->t_log_res - overhead > - cur->bc_private.a.priv.refc.nr_ops * 32; -} - -/* - * Adjust the refcounts of middle extents. At this point we should have - * split extents that crossed the adjustment range; merged with adjacent - * extents; and updated agbno/aglen to reflect the merges. Therefore, - * all we have to do is update the extents inside [agbno, agbno + aglen]. - */ -STATIC int -xfs_refcount_adjust_extents( - struct xfs_btree_cur *cur, - xfs_agblock_t *agbno, - xfs_extlen_t *aglen, - enum xfs_refc_adjust_op adj, - struct xfs_defer_ops *dfops, - struct xfs_owner_info *oinfo) -{ - struct xfs_refcount_irec ext, tmp; - int error; - int found_rec, found_tmp; - xfs_fsblock_t fsbno; - - /* Merging did all the work already. */ - if (*aglen == 0) - return 0; - - error = xfs_refcount_lookup_ge(cur, *agbno, &found_rec); - if (error) - goto out_error; - - while (*aglen > 0 && xfs_refcount_still_have_space(cur)) { - error = xfs_refcount_get_rec(cur, &ext, &found_rec); - if (error) - goto out_error; - if (!found_rec) { - ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks; - ext.rc_blockcount = 0; - ext.rc_refcount = 0; - } - - /* - * Deal with a hole in the refcount tree; if a file maps to - * these blocks and there's no refcountbt record, pretend that - * there is one with refcount == 1. - */ - if (ext.rc_startblock != *agbno) { - tmp.rc_startblock = *agbno; - tmp.rc_blockcount = min(*aglen, - ext.rc_startblock - *agbno); - tmp.rc_refcount = 1 + adj; - trace_xfs_refcount_modify_extent(cur->bc_mp, - cur->bc_private.a.agno, &tmp); - - /* - * Either cover the hole (increment) or - * delete the range (decrement). - */ - if (tmp.rc_refcount) { - error = xfs_refcount_insert(cur, &tmp, - &found_tmp); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, - found_tmp == 1, out_error); - cur->bc_private.a.priv.refc.nr_ops++; - } else { - fsbno = XFS_AGB_TO_FSB(cur->bc_mp, - cur->bc_private.a.agno, - tmp.rc_startblock); - xfs_bmap_add_free(cur->bc_mp, dfops, fsbno, - tmp.rc_blockcount, oinfo); - } - - (*agbno) += tmp.rc_blockcount; - (*aglen) -= tmp.rc_blockcount; - - error = xfs_refcount_lookup_ge(cur, *agbno, - &found_rec); - if (error) - goto out_error; - } - - /* Stop if there's nothing left to modify */ - if (*aglen == 0 || !xfs_refcount_still_have_space(cur)) - break; - - /* - * Adjust the reference count and either update the tree - * (incr) or free the blocks (decr). - */ - if (ext.rc_refcount == MAXREFCOUNT) - goto skip; - ext.rc_refcount += adj; - trace_xfs_refcount_modify_extent(cur->bc_mp, - cur->bc_private.a.agno, &ext); - if (ext.rc_refcount > 1) { - error = xfs_refcount_update(cur, &ext); - if (error) - goto out_error; - cur->bc_private.a.priv.refc.nr_ops++; - } else if (ext.rc_refcount == 1) { - error = xfs_refcount_delete(cur, &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, - found_rec == 1, out_error); - cur->bc_private.a.priv.refc.nr_ops++; - goto advloop; - } else { - fsbno = XFS_AGB_TO_FSB(cur->bc_mp, - cur->bc_private.a.agno, - ext.rc_startblock); - xfs_bmap_add_free(cur->bc_mp, dfops, fsbno, - ext.rc_blockcount, oinfo); - } - -skip: - error = xfs_btree_increment(cur, 0, &found_rec); - if (error) - goto out_error; - -advloop: - (*agbno) += ext.rc_blockcount; - (*aglen) -= ext.rc_blockcount; - } - - return error; -out_error: - trace_xfs_refcount_modify_extent_error(cur->bc_mp, - cur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -/* Adjust the reference count of a range of AG blocks. */ -STATIC int -xfs_refcount_adjust( - struct xfs_btree_cur *cur, - xfs_agblock_t agbno, - xfs_extlen_t aglen, - xfs_agblock_t *new_agbno, - xfs_extlen_t *new_aglen, - enum xfs_refc_adjust_op adj, - struct xfs_defer_ops *dfops, - struct xfs_owner_info *oinfo) -{ - bool shape_changed; - int shape_changes = 0; - int error; - - *new_agbno = agbno; - *new_aglen = aglen; - if (adj == XFS_REFCOUNT_ADJUST_INCREASE) - trace_xfs_refcount_increase(cur->bc_mp, cur->bc_private.a.agno, - agbno, aglen); - else - trace_xfs_refcount_decrease(cur->bc_mp, cur->bc_private.a.agno, - agbno, aglen); - - /* - * Ensure that no rcextents cross the boundary of the adjustment range. - */ - error = xfs_refcount_split_extent(cur, agbno, &shape_changed); - if (error) - goto out_error; - if (shape_changed) - shape_changes++; - - error = xfs_refcount_split_extent(cur, agbno + aglen, &shape_changed); - if (error) - goto out_error; - if (shape_changed) - shape_changes++; - - /* - * Try to merge with the left or right extents of the range. - */ - error = xfs_refcount_merge_extents(cur, new_agbno, new_aglen, adj, - XFS_FIND_RCEXT_SHARED, &shape_changed); - if (error) - goto out_error; - if (shape_changed) - shape_changes++; - if (shape_changes) - cur->bc_private.a.priv.refc.shape_changes++; - - /* Now that we've taken care of the ends, adjust the middle extents */ - error = xfs_refcount_adjust_extents(cur, new_agbno, new_aglen, - adj, dfops, oinfo); - if (error) - goto out_error; - - return 0; - -out_error: - trace_xfs_refcount_adjust_error(cur->bc_mp, cur->bc_private.a.agno, - error, _RET_IP_); - return error; -} - -/* Clean up after calling xfs_refcount_finish_one. */ -void -xfs_refcount_finish_one_cleanup( - struct xfs_trans *tp, - struct xfs_btree_cur *rcur, - int error) -{ - struct xfs_buf *agbp; - - if (rcur == NULL) - return; - agbp = rcur->bc_private.a.agbp; - xfs_btree_del_cursor(rcur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); - if (error) - xfs_trans_brelse(tp, agbp); -} - -/* - * Process one of the deferred refcount operations. We pass back the - * btree cursor to maintain our lock on the btree between calls. - * This saves time and eliminates a buffer deadlock between the - * superblock and the AGF because we'll always grab them in the same - * order. - */ -int -xfs_refcount_finish_one( - struct xfs_trans *tp, - struct xfs_defer_ops *dfops, - enum xfs_refcount_intent_type type, - xfs_fsblock_t startblock, - xfs_extlen_t blockcount, - xfs_fsblock_t *new_fsb, - xfs_extlen_t *new_len, - struct xfs_btree_cur **pcur) -{ - struct xfs_mount *mp = tp->t_mountp; - struct xfs_btree_cur *rcur; - struct xfs_buf *agbp = NULL; - int error = 0; - xfs_agnumber_t agno; - xfs_agblock_t bno; - xfs_agblock_t new_agbno; - unsigned long nr_ops = 0; - int shape_changes = 0; - - agno = XFS_FSB_TO_AGNO(mp, startblock); - ASSERT(agno != NULLAGNUMBER); - bno = XFS_FSB_TO_AGBNO(mp, startblock); - - trace_xfs_refcount_deferred(mp, XFS_FSB_TO_AGNO(mp, startblock), - type, XFS_FSB_TO_AGBNO(mp, startblock), - blockcount); - - if (XFS_TEST_ERROR(false, mp, - XFS_ERRTAG_REFCOUNT_FINISH_ONE, - XFS_RANDOM_REFCOUNT_FINISH_ONE)) - return -EIO; - - /* - * If we haven't gotten a cursor or the cursor AG doesn't match - * the startblock, get one now. - */ - rcur = *pcur; - if (rcur != NULL && rcur->bc_private.a.agno != agno) { - nr_ops = rcur->bc_private.a.priv.refc.nr_ops; - shape_changes = rcur->bc_private.a.priv.refc.shape_changes; - xfs_refcount_finish_one_cleanup(tp, rcur, 0); - rcur = NULL; - *pcur = NULL; - } - if (rcur == NULL) { - error = xfs_alloc_read_agf(tp->t_mountp, tp, agno, - XFS_ALLOC_FLAG_FREEING, &agbp); - if (error) - return error; - if (!agbp) - return -EFSCORRUPTED; - - rcur = xfs_refcountbt_init_cursor(mp, tp, agbp, agno, dfops); - if (!rcur) { - error = -ENOMEM; - goto out_cur; - } - rcur->bc_private.a.priv.refc.nr_ops = nr_ops; - rcur->bc_private.a.priv.refc.shape_changes = shape_changes; - } - *pcur = rcur; - - switch (type) { - case XFS_REFCOUNT_INCREASE: - error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno, - new_len, XFS_REFCOUNT_ADJUST_INCREASE, dfops, NULL); - *new_fsb = XFS_AGB_TO_FSB(mp, agno, new_agbno); - break; - case XFS_REFCOUNT_DECREASE: - error = xfs_refcount_adjust(rcur, bno, blockcount, &new_agbno, - new_len, XFS_REFCOUNT_ADJUST_DECREASE, dfops, NULL); - *new_fsb = XFS_AGB_TO_FSB(mp, agno, new_agbno); - break; - case XFS_REFCOUNT_ALLOC_COW: - *new_fsb = startblock + blockcount; - *new_len = 0; - error = __xfs_refcount_cow_alloc(rcur, bno, blockcount, dfops); - break; - case XFS_REFCOUNT_FREE_COW: - *new_fsb = startblock + blockcount; - *new_len = 0; - error = __xfs_refcount_cow_free(rcur, bno, blockcount, dfops); - break; - default: - ASSERT(0); - error = -EFSCORRUPTED; - } - if (!error && *new_len > 0) - trace_xfs_refcount_finish_one_leftover(mp, agno, type, - bno, blockcount, new_agbno, *new_len); - return error; - -out_cur: - xfs_trans_brelse(tp, agbp); - - return error; -} - -/* - * Record a refcount intent for later processing. - */ -static int -__xfs_refcount_add( - struct xfs_mount *mp, - struct xfs_defer_ops *dfops, - enum xfs_refcount_intent_type type, - xfs_fsblock_t startblock, - xfs_extlen_t blockcount) -{ - struct xfs_refcount_intent *ri; - - trace_xfs_refcount_defer(mp, XFS_FSB_TO_AGNO(mp, startblock), - type, XFS_FSB_TO_AGBNO(mp, startblock), - blockcount); - - ri = kmem_alloc(sizeof(struct xfs_refcount_intent), - KM_SLEEP | KM_NOFS); - INIT_LIST_HEAD(&ri->ri_list); - ri->ri_type = type; - ri->ri_startblock = startblock; - ri->ri_blockcount = blockcount; - - xfs_defer_add(dfops, XFS_DEFER_OPS_TYPE_REFCOUNT, &ri->ri_list); - return 0; -} - -/* - * Increase the reference count of the blocks backing a file's extent. - */ -int -xfs_refcount_increase_extent( - struct xfs_mount *mp, - struct xfs_defer_ops *dfops, - struct xfs_bmbt_irec *PREV) -{ - if (!xfs_sb_version_hasreflink(&mp->m_sb)) - return 0; - - return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_INCREASE, - PREV->br_startblock, PREV->br_blockcount); -} - -/* - * Decrease the reference count of the blocks backing a file's extent. - */ -int -xfs_refcount_decrease_extent( - struct xfs_mount *mp, - struct xfs_defer_ops *dfops, - struct xfs_bmbt_irec *PREV) -{ - if (!xfs_sb_version_hasreflink(&mp->m_sb)) - return 0; - - return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_DECREASE, - PREV->br_startblock, PREV->br_blockcount); -} - -/* - * Given an AG extent, find the lowest-numbered run of shared blocks - * within that range and return the range in fbno/flen. If - * find_end_of_shared is set, return the longest contiguous extent of - * shared blocks; if not, just return the first extent we find. If no - * shared blocks are found, fbno and flen will be set to NULLAGBLOCK - * and 0, respectively. - */ -int -xfs_refcount_find_shared( - struct xfs_btree_cur *cur, - xfs_agblock_t agbno, - xfs_extlen_t aglen, - xfs_agblock_t *fbno, - xfs_extlen_t *flen, - bool find_end_of_shared) -{ - struct xfs_refcount_irec tmp; - int i; - int have; - int error; - - trace_xfs_refcount_find_shared(cur->bc_mp, cur->bc_private.a.agno, - agbno, aglen); - - /* By default, skip the whole range */ - *fbno = NULLAGBLOCK; - *flen = 0; - - /* Try to find a refcount extent that crosses the start */ - error = xfs_refcount_lookup_le(cur, agbno, &have); - if (error) - goto out_error; - if (!have) { - /* No left extent, look at the next one */ - error = xfs_btree_increment(cur, 0, &have); - if (error) - goto out_error; - if (!have) - goto done; - } - error = xfs_refcount_get_rec(cur, &tmp, &i); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, out_error); - - /* If the extent ends before the start, look at the next one */ - if (tmp.rc_startblock + tmp.rc_blockcount <= agbno) { - error = xfs_btree_increment(cur, 0, &have); - if (error) - goto out_error; - if (!have) - goto done; - error = xfs_refcount_get_rec(cur, &tmp, &i); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, out_error); - } - - /* If the extent starts after the range we want, bail out */ - if (tmp.rc_startblock >= agbno + aglen) - goto done; - - /* We found the start of a shared extent! */ - if (tmp.rc_startblock < agbno) { - tmp.rc_blockcount -= (agbno - tmp.rc_startblock); - tmp.rc_startblock = agbno; - } - - *fbno = tmp.rc_startblock; - *flen = min(tmp.rc_blockcount, agbno + aglen - *fbno); - if (!find_end_of_shared) - goto done; - - /* Otherwise, find the end of this shared extent */ - while (*fbno + *flen < agbno + aglen) { - error = xfs_btree_increment(cur, 0, &have); - if (error) - goto out_error; - if (!have) - break; - error = xfs_refcount_get_rec(cur, &tmp, &i); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, i == 1, out_error); - if (tmp.rc_startblock >= agbno + aglen || - tmp.rc_startblock != *fbno + *flen) - break; - *flen = min(*flen + tmp.rc_blockcount, agbno + aglen - *fbno); - } - -done: - trace_xfs_refcount_find_shared_result(cur->bc_mp, - cur->bc_private.a.agno, *fbno, *flen); - -out_error: - if (error) - trace_xfs_refcount_find_shared_error(cur->bc_mp, - cur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -/* - * Recovering CoW Blocks After a Crash - * - * Due to the way that the copy on write mechanism works, there's a window of - * opportunity in which we can lose track of allocated blocks during a crash. - * Because CoW uses delayed allocation in the in-core CoW fork, writeback - * causes blocks to be allocated and stored in the CoW fork. The blocks are - * no longer in the free space btree but are not otherwise recorded anywhere - * until the write completes and the blocks are mapped into the file. A crash - * in between allocation and remapping results in the replacement blocks being - * lost. This situation is exacerbated by the CoW extent size hint because - * allocations can hang around for long time. - * - * However, there is a place where we can record these allocations before they - * become mappings -- the reference count btree. The btree does not record - * extents with refcount == 1, so we can record allocations with a refcount of - * 1. Blocks being used for CoW writeout cannot be shared, so there should be - * no conflict with shared block records. These mappings should be created - * when we allocate blocks to the CoW fork and deleted when they're removed - * from the CoW fork. - * - * Minor nit: records for in-progress CoW allocations and records for shared - * extents must never be merged, to preserve the property that (except for CoW - * allocations) there are no refcount btree entries with refcount == 1. The - * only time this could potentially happen is when unsharing a block that's - * adjacent to CoW allocations, so we must be careful to avoid this. - * - * At mount time we recover lost CoW allocations by searching the refcount - * btree for these refcount == 1 mappings. These represent CoW allocations - * that were in progress at the time the filesystem went down, so we can free - * them to get the space back. - * - * This mechanism is superior to creating EFIs for unmapped CoW extents for - * several reasons -- first, EFIs pin the tail of the log and would have to be - * periodically relogged to avoid filling up the log. Second, CoW completions - * will have to file an EFD and create new EFIs for whatever remains in the - * CoW fork; this partially takes care of (1) but extent-size reservations - * will have to periodically relog even if there's no writeout in progress. - * This can happen if the CoW extent size hint is set, which you really want. - * Third, EFIs cannot currently be automatically relogged into newer - * transactions to advance the log tail. Fourth, stuffing the log full of - * EFIs places an upper bound on the number of CoW allocations that can be - * held filesystem-wide at any given time. Recording them in the refcount - * btree doesn't require us to maintain any state in memory and doesn't pin - * the log. - */ -/* - * Adjust the refcounts of CoW allocations. These allocations are "magic" - * in that they're not referenced anywhere else in the filesystem, so we - * stash them in the refcount btree with a refcount of 1 until either file - * remapping (or CoW cancellation) happens. - */ -STATIC int -xfs_refcount_adjust_cow_extents( - struct xfs_btree_cur *cur, - xfs_agblock_t agbno, - xfs_extlen_t aglen, - enum xfs_refc_adjust_op adj, - struct xfs_defer_ops *dfops, - struct xfs_owner_info *oinfo) -{ - struct xfs_refcount_irec ext, tmp; - int error; - int found_rec, found_tmp; - - if (aglen == 0) - return 0; - - /* Find any overlapping refcount records */ - error = xfs_refcount_lookup_ge(cur, agbno, &found_rec); - if (error) - goto out_error; - error = xfs_refcount_get_rec(cur, &ext, &found_rec); - if (error) - goto out_error; - if (!found_rec) { - ext.rc_startblock = cur->bc_mp->m_sb.sb_agblocks + - XFS_REFC_COW_START; - ext.rc_blockcount = 0; - ext.rc_refcount = 0; - } - - switch (adj) { - case XFS_REFCOUNT_ADJUST_COW_ALLOC: - /* Adding a CoW reservation, there should be nothing here. */ - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, - ext.rc_startblock >= agbno + aglen, out_error); - - tmp.rc_startblock = agbno; - tmp.rc_blockcount = aglen; - tmp.rc_refcount = 1; - trace_xfs_refcount_modify_extent(cur->bc_mp, - cur->bc_private.a.agno, &tmp); - - error = xfs_refcount_insert(cur, &tmp, - &found_tmp); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, - found_tmp == 1, out_error); - break; - case XFS_REFCOUNT_ADJUST_COW_FREE: - /* Removing a CoW reservation, there should be one extent. */ - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, - ext.rc_startblock == agbno, out_error); - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, - ext.rc_blockcount == aglen, out_error); - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, - ext.rc_refcount == 1, out_error); - - ext.rc_refcount = 0; - trace_xfs_refcount_modify_extent(cur->bc_mp, - cur->bc_private.a.agno, &ext); - error = xfs_refcount_delete(cur, &found_rec); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(cur->bc_mp, - found_rec == 1, out_error); - break; - default: - ASSERT(0); - } - - return error; -out_error: - trace_xfs_refcount_modify_extent_error(cur->bc_mp, - cur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -/* - * Add or remove refcount btree entries for CoW reservations. - */ -STATIC int -xfs_refcount_adjust_cow( - struct xfs_btree_cur *cur, - xfs_agblock_t agbno, - xfs_extlen_t aglen, - enum xfs_refc_adjust_op adj, - struct xfs_defer_ops *dfops) -{ - bool shape_changed; - int error; - - agbno += XFS_REFC_COW_START; - - /* - * Ensure that no rcextents cross the boundary of the adjustment range. - */ - error = xfs_refcount_split_extent(cur, agbno, &shape_changed); - if (error) - goto out_error; - - error = xfs_refcount_split_extent(cur, agbno + aglen, &shape_changed); - if (error) - goto out_error; - - /* - * Try to merge with the left or right extents of the range. - */ - error = xfs_refcount_merge_extents(cur, &agbno, &aglen, adj, - XFS_FIND_RCEXT_COW, &shape_changed); - if (error) - goto out_error; - - /* Now that we've taken care of the ends, adjust the middle extents */ - error = xfs_refcount_adjust_cow_extents(cur, agbno, aglen, adj, - dfops, NULL); - if (error) - goto out_error; - - return 0; - -out_error: - trace_xfs_refcount_adjust_cow_error(cur->bc_mp, cur->bc_private.a.agno, - error, _RET_IP_); - return error; -} - -/* - * Record a CoW allocation in the refcount btree. - */ -STATIC int -__xfs_refcount_cow_alloc( - struct xfs_btree_cur *rcur, - xfs_agblock_t agbno, - xfs_extlen_t aglen, - struct xfs_defer_ops *dfops) -{ - int error; - - trace_xfs_refcount_cow_increase(rcur->bc_mp, rcur->bc_private.a.agno, - agbno, aglen); - - /* Add refcount btree reservation */ - error = xfs_refcount_adjust_cow(rcur, agbno, aglen, - XFS_REFCOUNT_ADJUST_COW_ALLOC, dfops); - if (error) - return error; - - /* Add rmap entry */ - if (xfs_sb_version_hasrmapbt(&rcur->bc_mp->m_sb)) { - error = xfs_rmap_alloc_extent(rcur->bc_mp, dfops, - rcur->bc_private.a.agno, - agbno, aglen, XFS_RMAP_OWN_COW); - if (error) - return error; - } - - return error; -} - -/* - * Remove a CoW allocation from the refcount btree. - */ -STATIC int -__xfs_refcount_cow_free( - struct xfs_btree_cur *rcur, - xfs_agblock_t agbno, - xfs_extlen_t aglen, - struct xfs_defer_ops *dfops) -{ - int error; - - trace_xfs_refcount_cow_decrease(rcur->bc_mp, rcur->bc_private.a.agno, - agbno, aglen); - - /* Remove refcount btree reservation */ - error = xfs_refcount_adjust_cow(rcur, agbno, aglen, - XFS_REFCOUNT_ADJUST_COW_FREE, dfops); - if (error) - return error; - - /* Remove rmap entry */ - if (xfs_sb_version_hasrmapbt(&rcur->bc_mp->m_sb)) { - error = xfs_rmap_free_extent(rcur->bc_mp, dfops, - rcur->bc_private.a.agno, - agbno, aglen, XFS_RMAP_OWN_COW); - if (error) - return error; - } - - return error; -} - -/* Record a CoW staging extent in the refcount btree. */ -int -xfs_refcount_alloc_cow_extent( - struct xfs_mount *mp, - struct xfs_defer_ops *dfops, - xfs_fsblock_t fsb, - xfs_extlen_t len) -{ - if (!xfs_sb_version_hasreflink(&mp->m_sb)) - return 0; - - return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_ALLOC_COW, - fsb, len); -} - -/* Forget a CoW staging event in the refcount btree. */ -int -xfs_refcount_free_cow_extent( - struct xfs_mount *mp, - struct xfs_defer_ops *dfops, - xfs_fsblock_t fsb, - xfs_extlen_t len) -{ - if (!xfs_sb_version_hasreflink(&mp->m_sb)) - return 0; - - return __xfs_refcount_add(mp, dfops, XFS_REFCOUNT_FREE_COW, - fsb, len); -} - -struct xfs_refcount_recovery { - struct list_head rr_list; - struct xfs_refcount_irec rr_rrec; -}; - -/* Stuff an extent on the recovery list. */ -STATIC int -xfs_refcount_recover_extent( - struct xfs_btree_cur *cur, - union xfs_btree_rec *rec, - void *priv) -{ - struct list_head *debris = priv; - struct xfs_refcount_recovery *rr; - - if (be32_to_cpu(rec->refc.rc_refcount) != 1) - return -EFSCORRUPTED; - - rr = kmem_alloc(sizeof(struct xfs_refcount_recovery), KM_SLEEP); - xfs_refcount_btrec_to_irec(rec, &rr->rr_rrec); - list_add_tail(&rr->rr_list, debris); - - return 0; -} - -/* Find and remove leftover CoW reservations. */ -int -xfs_refcount_recover_cow_leftovers( - struct xfs_mount *mp, - xfs_agnumber_t agno) -{ - struct xfs_trans *tp; - struct xfs_btree_cur *cur; - struct xfs_buf *agbp; - struct xfs_refcount_recovery *rr, *n; - struct list_head debris; - union xfs_btree_irec low; - union xfs_btree_irec high; - struct xfs_defer_ops dfops; - xfs_fsblock_t fsb; - xfs_agblock_t agbno; - int error; - - if (mp->m_sb.sb_agblocks >= XFS_REFC_COW_START) - return -EOPNOTSUPP; - - error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); - if (error) - return error; - cur = xfs_refcountbt_init_cursor(mp, NULL, agbp, agno, NULL); - - /* Find all the leftover CoW staging extents. */ - INIT_LIST_HEAD(&debris); - memset(&low, 0, sizeof(low)); - memset(&high, 0, sizeof(high)); - low.rc.rc_startblock = XFS_REFC_COW_START; - high.rc.rc_startblock = -1U; - error = xfs_btree_query_range(cur, &low, &high, - xfs_refcount_recover_extent, &debris); - if (error) - goto out_cursor; - xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); - xfs_buf_relse(agbp); - - /* Now iterate the list to free the leftovers */ - list_for_each_entry(rr, &debris, rr_list) { - /* Set up transaction. */ - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, 0, 0, 0, &tp); - if (error) - goto out_free; - - trace_xfs_refcount_recover_extent(mp, agno, &rr->rr_rrec); - - /* Free the orphan record */ - xfs_defer_init(&dfops, &fsb); - agbno = rr->rr_rrec.rc_startblock - XFS_REFC_COW_START; - fsb = XFS_AGB_TO_FSB(mp, agno, agbno); - error = xfs_refcount_free_cow_extent(mp, &dfops, fsb, - rr->rr_rrec.rc_blockcount); - if (error) - goto out_defer; - - /* Free the block. */ - xfs_bmap_add_free(mp, &dfops, fsb, - rr->rr_rrec.rc_blockcount, NULL); - - error = xfs_defer_finish(&tp, &dfops, NULL); - if (error) - goto out_defer; - - error = xfs_trans_commit(tp); - if (error) - goto out_free; - } - -out_free: - /* Free the leftover list */ - list_for_each_entry_safe(rr, n, &debris, rr_list) { - list_del(&rr->rr_list); - kmem_free(rr); - } - return error; - -out_cursor: - xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); - xfs_buf_relse(agbp); - goto out_free; - -out_defer: - xfs_defer_cancel(&dfops); - xfs_trans_cancel(tp); - goto out_free; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_refcount.h b/src/linux/fs/xfs/libxfs/xfs_refcount.h deleted file mode 100644 index 098dc66..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_refcount.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#ifndef __XFS_REFCOUNT_H__ -#define __XFS_REFCOUNT_H__ - -extern int xfs_refcount_lookup_le(struct xfs_btree_cur *cur, - xfs_agblock_t bno, int *stat); -extern int xfs_refcount_lookup_ge(struct xfs_btree_cur *cur, - xfs_agblock_t bno, int *stat); -extern int xfs_refcount_get_rec(struct xfs_btree_cur *cur, - struct xfs_refcount_irec *irec, int *stat); - -enum xfs_refcount_intent_type { - XFS_REFCOUNT_INCREASE = 1, - XFS_REFCOUNT_DECREASE, - XFS_REFCOUNT_ALLOC_COW, - XFS_REFCOUNT_FREE_COW, -}; - -struct xfs_refcount_intent { - struct list_head ri_list; - enum xfs_refcount_intent_type ri_type; - xfs_fsblock_t ri_startblock; - xfs_extlen_t ri_blockcount; -}; - -extern int xfs_refcount_increase_extent(struct xfs_mount *mp, - struct xfs_defer_ops *dfops, struct xfs_bmbt_irec *irec); -extern int xfs_refcount_decrease_extent(struct xfs_mount *mp, - struct xfs_defer_ops *dfops, struct xfs_bmbt_irec *irec); - -extern void xfs_refcount_finish_one_cleanup(struct xfs_trans *tp, - struct xfs_btree_cur *rcur, int error); -extern int xfs_refcount_finish_one(struct xfs_trans *tp, - struct xfs_defer_ops *dfops, enum xfs_refcount_intent_type type, - xfs_fsblock_t startblock, xfs_extlen_t blockcount, - xfs_fsblock_t *new_fsb, xfs_extlen_t *new_len, - struct xfs_btree_cur **pcur); - -extern int xfs_refcount_find_shared(struct xfs_btree_cur *cur, - xfs_agblock_t agbno, xfs_extlen_t aglen, xfs_agblock_t *fbno, - xfs_extlen_t *flen, bool find_end_of_shared); - -extern int xfs_refcount_alloc_cow_extent(struct xfs_mount *mp, - struct xfs_defer_ops *dfops, xfs_fsblock_t fsb, - xfs_extlen_t len); -extern int xfs_refcount_free_cow_extent(struct xfs_mount *mp, - struct xfs_defer_ops *dfops, xfs_fsblock_t fsb, - xfs_extlen_t len); -extern int xfs_refcount_recover_cow_leftovers(struct xfs_mount *mp, - xfs_agnumber_t agno); - -#endif /* __XFS_REFCOUNT_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_refcount_btree.c b/src/linux/fs/xfs/libxfs/xfs_refcount_btree.c deleted file mode 100644 index 453bb27..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_refcount_btree.c +++ /dev/null @@ -1,451 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_btree.h" -#include "xfs_bmap.h" -#include "xfs_refcount_btree.h" -#include "xfs_alloc.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_cksum.h" -#include "xfs_trans.h" -#include "xfs_bit.h" -#include "xfs_rmap.h" - -static struct xfs_btree_cur * -xfs_refcountbt_dup_cursor( - struct xfs_btree_cur *cur) -{ - return xfs_refcountbt_init_cursor(cur->bc_mp, cur->bc_tp, - cur->bc_private.a.agbp, cur->bc_private.a.agno, - cur->bc_private.a.dfops); -} - -STATIC void -xfs_refcountbt_set_root( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *ptr, - int inc) -{ - struct xfs_buf *agbp = cur->bc_private.a.agbp; - struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); - xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); - struct xfs_perag *pag = xfs_perag_get(cur->bc_mp, seqno); - - ASSERT(ptr->s != 0); - - agf->agf_refcount_root = ptr->s; - be32_add_cpu(&agf->agf_refcount_level, inc); - pag->pagf_refcount_level += inc; - xfs_perag_put(pag); - - xfs_alloc_log_agf(cur->bc_tp, agbp, - XFS_AGF_REFCOUNT_ROOT | XFS_AGF_REFCOUNT_LEVEL); -} - -STATIC int -xfs_refcountbt_alloc_block( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *start, - union xfs_btree_ptr *new, - int *stat) -{ - struct xfs_buf *agbp = cur->bc_private.a.agbp; - struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); - struct xfs_alloc_arg args; /* block allocation args */ - int error; /* error return value */ - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - - memset(&args, 0, sizeof(args)); - args.tp = cur->bc_tp; - args.mp = cur->bc_mp; - args.type = XFS_ALLOCTYPE_NEAR_BNO; - args.fsbno = XFS_AGB_TO_FSB(cur->bc_mp, cur->bc_private.a.agno, - xfs_refc_block(args.mp)); - args.firstblock = args.fsbno; - xfs_rmap_ag_owner(&args.oinfo, XFS_RMAP_OWN_REFC); - args.minlen = args.maxlen = args.prod = 1; - args.resv = XFS_AG_RESV_METADATA; - - error = xfs_alloc_vextent(&args); - if (error) - goto out_error; - trace_xfs_refcountbt_alloc_block(cur->bc_mp, cur->bc_private.a.agno, - args.agbno, 1); - if (args.fsbno == NULLFSBLOCK) { - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 0; - return 0; - } - ASSERT(args.agno == cur->bc_private.a.agno); - ASSERT(args.len == 1); - - new->s = cpu_to_be32(args.agbno); - be32_add_cpu(&agf->agf_refcount_blocks, 1); - xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS); - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 1; - return 0; - -out_error: - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; -} - -STATIC int -xfs_refcountbt_free_block( - struct xfs_btree_cur *cur, - struct xfs_buf *bp) -{ - struct xfs_mount *mp = cur->bc_mp; - struct xfs_buf *agbp = cur->bc_private.a.agbp; - struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); - xfs_fsblock_t fsbno = XFS_DADDR_TO_FSB(mp, XFS_BUF_ADDR(bp)); - struct xfs_owner_info oinfo; - int error; - - trace_xfs_refcountbt_free_block(cur->bc_mp, cur->bc_private.a.agno, - XFS_FSB_TO_AGBNO(cur->bc_mp, fsbno), 1); - xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_REFC); - be32_add_cpu(&agf->agf_refcount_blocks, -1); - xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_REFCOUNT_BLOCKS); - error = xfs_free_extent(cur->bc_tp, fsbno, 1, &oinfo, - XFS_AG_RESV_METADATA); - if (error) - return error; - - return error; -} - -STATIC int -xfs_refcountbt_get_minrecs( - struct xfs_btree_cur *cur, - int level) -{ - return cur->bc_mp->m_refc_mnr[level != 0]; -} - -STATIC int -xfs_refcountbt_get_maxrecs( - struct xfs_btree_cur *cur, - int level) -{ - return cur->bc_mp->m_refc_mxr[level != 0]; -} - -STATIC void -xfs_refcountbt_init_key_from_rec( - union xfs_btree_key *key, - union xfs_btree_rec *rec) -{ - key->refc.rc_startblock = rec->refc.rc_startblock; -} - -STATIC void -xfs_refcountbt_init_high_key_from_rec( - union xfs_btree_key *key, - union xfs_btree_rec *rec) -{ - __u32 x; - - x = be32_to_cpu(rec->refc.rc_startblock); - x += be32_to_cpu(rec->refc.rc_blockcount) - 1; - key->refc.rc_startblock = cpu_to_be32(x); -} - -STATIC void -xfs_refcountbt_init_rec_from_cur( - struct xfs_btree_cur *cur, - union xfs_btree_rec *rec) -{ - rec->refc.rc_startblock = cpu_to_be32(cur->bc_rec.rc.rc_startblock); - rec->refc.rc_blockcount = cpu_to_be32(cur->bc_rec.rc.rc_blockcount); - rec->refc.rc_refcount = cpu_to_be32(cur->bc_rec.rc.rc_refcount); -} - -STATIC void -xfs_refcountbt_init_ptr_from_cur( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *ptr) -{ - struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); - - ASSERT(cur->bc_private.a.agno == be32_to_cpu(agf->agf_seqno)); - ASSERT(agf->agf_refcount_root != 0); - - ptr->s = agf->agf_refcount_root; -} - -STATIC __int64_t -xfs_refcountbt_key_diff( - struct xfs_btree_cur *cur, - union xfs_btree_key *key) -{ - struct xfs_refcount_irec *rec = &cur->bc_rec.rc; - struct xfs_refcount_key *kp = &key->refc; - - return (__int64_t)be32_to_cpu(kp->rc_startblock) - rec->rc_startblock; -} - -STATIC __int64_t -xfs_refcountbt_diff_two_keys( - struct xfs_btree_cur *cur, - union xfs_btree_key *k1, - union xfs_btree_key *k2) -{ - return (__int64_t)be32_to_cpu(k1->refc.rc_startblock) - - be32_to_cpu(k2->refc.rc_startblock); -} - -STATIC bool -xfs_refcountbt_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); - struct xfs_perag *pag = bp->b_pag; - unsigned int level; - - if (block->bb_magic != cpu_to_be32(XFS_REFC_CRC_MAGIC)) - return false; - - if (!xfs_sb_version_hasreflink(&mp->m_sb)) - return false; - if (!xfs_btree_sblock_v5hdr_verify(bp)) - return false; - - level = be16_to_cpu(block->bb_level); - if (pag && pag->pagf_init) { - if (level >= pag->pagf_refcount_level) - return false; - } else if (level >= mp->m_refc_maxlevels) - return false; - - return xfs_btree_sblock_verify(bp, mp->m_refc_mxr[level != 0]); -} - -STATIC void -xfs_refcountbt_read_verify( - struct xfs_buf *bp) -{ - if (!xfs_btree_sblock_verify_crc(bp)) - xfs_buf_ioerror(bp, -EFSBADCRC); - else if (!xfs_refcountbt_verify(bp)) - xfs_buf_ioerror(bp, -EFSCORRUPTED); - - if (bp->b_error) { - trace_xfs_btree_corrupt(bp, _RET_IP_); - xfs_verifier_error(bp); - } -} - -STATIC void -xfs_refcountbt_write_verify( - struct xfs_buf *bp) -{ - if (!xfs_refcountbt_verify(bp)) { - trace_xfs_btree_corrupt(bp, _RET_IP_); - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - return; - } - xfs_btree_sblock_calc_crc(bp); - -} - -const struct xfs_buf_ops xfs_refcountbt_buf_ops = { - .name = "xfs_refcountbt", - .verify_read = xfs_refcountbt_read_verify, - .verify_write = xfs_refcountbt_write_verify, -}; - -#if defined(DEBUG) || defined(XFS_WARN) -STATIC int -xfs_refcountbt_keys_inorder( - struct xfs_btree_cur *cur, - union xfs_btree_key *k1, - union xfs_btree_key *k2) -{ - return be32_to_cpu(k1->refc.rc_startblock) < - be32_to_cpu(k2->refc.rc_startblock); -} - -STATIC int -xfs_refcountbt_recs_inorder( - struct xfs_btree_cur *cur, - union xfs_btree_rec *r1, - union xfs_btree_rec *r2) -{ - return be32_to_cpu(r1->refc.rc_startblock) + - be32_to_cpu(r1->refc.rc_blockcount) <= - be32_to_cpu(r2->refc.rc_startblock); -} -#endif - -static const struct xfs_btree_ops xfs_refcountbt_ops = { - .rec_len = sizeof(struct xfs_refcount_rec), - .key_len = sizeof(struct xfs_refcount_key), - - .dup_cursor = xfs_refcountbt_dup_cursor, - .set_root = xfs_refcountbt_set_root, - .alloc_block = xfs_refcountbt_alloc_block, - .free_block = xfs_refcountbt_free_block, - .get_minrecs = xfs_refcountbt_get_minrecs, - .get_maxrecs = xfs_refcountbt_get_maxrecs, - .init_key_from_rec = xfs_refcountbt_init_key_from_rec, - .init_high_key_from_rec = xfs_refcountbt_init_high_key_from_rec, - .init_rec_from_cur = xfs_refcountbt_init_rec_from_cur, - .init_ptr_from_cur = xfs_refcountbt_init_ptr_from_cur, - .key_diff = xfs_refcountbt_key_diff, - .buf_ops = &xfs_refcountbt_buf_ops, - .diff_two_keys = xfs_refcountbt_diff_two_keys, -#if defined(DEBUG) || defined(XFS_WARN) - .keys_inorder = xfs_refcountbt_keys_inorder, - .recs_inorder = xfs_refcountbt_recs_inorder, -#endif -}; - -/* - * Allocate a new refcount btree cursor. - */ -struct xfs_btree_cur * -xfs_refcountbt_init_cursor( - struct xfs_mount *mp, - struct xfs_trans *tp, - struct xfs_buf *agbp, - xfs_agnumber_t agno, - struct xfs_defer_ops *dfops) -{ - struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); - struct xfs_btree_cur *cur; - - ASSERT(agno != NULLAGNUMBER); - ASSERT(agno < mp->m_sb.sb_agcount); - cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_NOFS); - - cur->bc_tp = tp; - cur->bc_mp = mp; - cur->bc_btnum = XFS_BTNUM_REFC; - cur->bc_blocklog = mp->m_sb.sb_blocklog; - cur->bc_ops = &xfs_refcountbt_ops; - - cur->bc_nlevels = be32_to_cpu(agf->agf_refcount_level); - - cur->bc_private.a.agbp = agbp; - cur->bc_private.a.agno = agno; - cur->bc_private.a.dfops = dfops; - cur->bc_flags |= XFS_BTREE_CRC_BLOCKS; - - cur->bc_private.a.priv.refc.nr_ops = 0; - cur->bc_private.a.priv.refc.shape_changes = 0; - - return cur; -} - -/* - * Calculate the number of records in a refcount btree block. - */ -int -xfs_refcountbt_maxrecs( - struct xfs_mount *mp, - int blocklen, - bool leaf) -{ - blocklen -= XFS_REFCOUNT_BLOCK_LEN; - - if (leaf) - return blocklen / sizeof(struct xfs_refcount_rec); - return blocklen / (sizeof(struct xfs_refcount_key) + - sizeof(xfs_refcount_ptr_t)); -} - -/* Compute the maximum height of a refcount btree. */ -void -xfs_refcountbt_compute_maxlevels( - struct xfs_mount *mp) -{ - mp->m_refc_maxlevels = xfs_btree_compute_maxlevels(mp, - mp->m_refc_mnr, mp->m_sb.sb_agblocks); -} - -/* Calculate the refcount btree size for some records. */ -xfs_extlen_t -xfs_refcountbt_calc_size( - struct xfs_mount *mp, - unsigned long long len) -{ - return xfs_btree_calc_size(mp, mp->m_refc_mnr, len); -} - -/* - * Calculate the maximum refcount btree size. - */ -xfs_extlen_t -xfs_refcountbt_max_size( - struct xfs_mount *mp) -{ - /* Bail out if we're uninitialized, which can happen in mkfs. */ - if (mp->m_refc_mxr[0] == 0) - return 0; - - return xfs_refcountbt_calc_size(mp, mp->m_sb.sb_agblocks); -} - -/* - * Figure out how many blocks to reserve and how many are used by this btree. - */ -int -xfs_refcountbt_calc_reserves( - struct xfs_mount *mp, - xfs_agnumber_t agno, - xfs_extlen_t *ask, - xfs_extlen_t *used) -{ - struct xfs_buf *agbp; - struct xfs_agf *agf; - xfs_extlen_t tree_len; - int error; - - if (!xfs_sb_version_hasreflink(&mp->m_sb)) - return 0; - - *ask += xfs_refcountbt_max_size(mp); - - error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); - if (error) - return error; - - agf = XFS_BUF_TO_AGF(agbp); - tree_len = be32_to_cpu(agf->agf_refcount_blocks); - xfs_buf_relse(agbp); - - *used += tree_len; - - return error; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_refcount_btree.h b/src/linux/fs/xfs/libxfs/xfs_refcount_btree.h deleted file mode 100644 index 3be7768..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_refcount_btree.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#ifndef __XFS_REFCOUNT_BTREE_H__ -#define __XFS_REFCOUNT_BTREE_H__ - -/* - * Reference Count Btree on-disk structures - */ - -struct xfs_buf; -struct xfs_btree_cur; -struct xfs_mount; - -/* - * Btree block header size - */ -#define XFS_REFCOUNT_BLOCK_LEN XFS_BTREE_SBLOCK_CRC_LEN - -/* - * Record, key, and pointer address macros for btree blocks. - * - * (note that some of these may appear unused, but they are used in userspace) - */ -#define XFS_REFCOUNT_REC_ADDR(block, index) \ - ((struct xfs_refcount_rec *) \ - ((char *)(block) + \ - XFS_REFCOUNT_BLOCK_LEN + \ - (((index) - 1) * sizeof(struct xfs_refcount_rec)))) - -#define XFS_REFCOUNT_KEY_ADDR(block, index) \ - ((struct xfs_refcount_key *) \ - ((char *)(block) + \ - XFS_REFCOUNT_BLOCK_LEN + \ - ((index) - 1) * sizeof(struct xfs_refcount_key))) - -#define XFS_REFCOUNT_PTR_ADDR(block, index, maxrecs) \ - ((xfs_refcount_ptr_t *) \ - ((char *)(block) + \ - XFS_REFCOUNT_BLOCK_LEN + \ - (maxrecs) * sizeof(struct xfs_refcount_key) + \ - ((index) - 1) * sizeof(xfs_refcount_ptr_t))) - -extern struct xfs_btree_cur *xfs_refcountbt_init_cursor(struct xfs_mount *mp, - struct xfs_trans *tp, struct xfs_buf *agbp, xfs_agnumber_t agno, - struct xfs_defer_ops *dfops); -extern int xfs_refcountbt_maxrecs(struct xfs_mount *mp, int blocklen, - bool leaf); -extern void xfs_refcountbt_compute_maxlevels(struct xfs_mount *mp); - -extern xfs_extlen_t xfs_refcountbt_calc_size(struct xfs_mount *mp, - unsigned long long len); -extern xfs_extlen_t xfs_refcountbt_max_size(struct xfs_mount *mp); - -extern int xfs_refcountbt_calc_reserves(struct xfs_mount *mp, - xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used); - -#endif /* __XFS_REFCOUNT_BTREE_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_rmap.c b/src/linux/fs/xfs/libxfs/xfs_rmap.c deleted file mode 100644 index 3a8cc71..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_rmap.c +++ /dev/null @@ -1,2293 +0,0 @@ -/* - * Copyright (c) 2014 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_btree.h" -#include "xfs_trans.h" -#include "xfs_alloc.h" -#include "xfs_rmap.h" -#include "xfs_rmap_btree.h" -#include "xfs_trans_space.h" -#include "xfs_trace.h" -#include "xfs_error.h" -#include "xfs_extent_busy.h" -#include "xfs_bmap.h" -#include "xfs_inode.h" - -/* - * Lookup the first record less than or equal to [bno, len, owner, offset] - * in the btree given by cur. - */ -int -xfs_rmap_lookup_le( - struct xfs_btree_cur *cur, - xfs_agblock_t bno, - xfs_extlen_t len, - uint64_t owner, - uint64_t offset, - unsigned int flags, - int *stat) -{ - cur->bc_rec.r.rm_startblock = bno; - cur->bc_rec.r.rm_blockcount = len; - cur->bc_rec.r.rm_owner = owner; - cur->bc_rec.r.rm_offset = offset; - cur->bc_rec.r.rm_flags = flags; - return xfs_btree_lookup(cur, XFS_LOOKUP_LE, stat); -} - -/* - * Lookup the record exactly matching [bno, len, owner, offset] - * in the btree given by cur. - */ -int -xfs_rmap_lookup_eq( - struct xfs_btree_cur *cur, - xfs_agblock_t bno, - xfs_extlen_t len, - uint64_t owner, - uint64_t offset, - unsigned int flags, - int *stat) -{ - cur->bc_rec.r.rm_startblock = bno; - cur->bc_rec.r.rm_blockcount = len; - cur->bc_rec.r.rm_owner = owner; - cur->bc_rec.r.rm_offset = offset; - cur->bc_rec.r.rm_flags = flags; - return xfs_btree_lookup(cur, XFS_LOOKUP_EQ, stat); -} - -/* - * Update the record referred to by cur to the value given - * by [bno, len, owner, offset]. - * This either works (return 0) or gets an EFSCORRUPTED error. - */ -STATIC int -xfs_rmap_update( - struct xfs_btree_cur *cur, - struct xfs_rmap_irec *irec) -{ - union xfs_btree_rec rec; - int error; - - trace_xfs_rmap_update(cur->bc_mp, cur->bc_private.a.agno, - irec->rm_startblock, irec->rm_blockcount, - irec->rm_owner, irec->rm_offset, irec->rm_flags); - - rec.rmap.rm_startblock = cpu_to_be32(irec->rm_startblock); - rec.rmap.rm_blockcount = cpu_to_be32(irec->rm_blockcount); - rec.rmap.rm_owner = cpu_to_be64(irec->rm_owner); - rec.rmap.rm_offset = cpu_to_be64( - xfs_rmap_irec_offset_pack(irec)); - error = xfs_btree_update(cur, &rec); - if (error) - trace_xfs_rmap_update_error(cur->bc_mp, - cur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -int -xfs_rmap_insert( - struct xfs_btree_cur *rcur, - xfs_agblock_t agbno, - xfs_extlen_t len, - uint64_t owner, - uint64_t offset, - unsigned int flags) -{ - int i; - int error; - - trace_xfs_rmap_insert(rcur->bc_mp, rcur->bc_private.a.agno, agbno, - len, owner, offset, flags); - - error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 0, done); - - rcur->bc_rec.r.rm_startblock = agbno; - rcur->bc_rec.r.rm_blockcount = len; - rcur->bc_rec.r.rm_owner = owner; - rcur->bc_rec.r.rm_offset = offset; - rcur->bc_rec.r.rm_flags = flags; - error = xfs_btree_insert(rcur, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 1, done); -done: - if (error) - trace_xfs_rmap_insert_error(rcur->bc_mp, - rcur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -STATIC int -xfs_rmap_delete( - struct xfs_btree_cur *rcur, - xfs_agblock_t agbno, - xfs_extlen_t len, - uint64_t owner, - uint64_t offset, - unsigned int flags) -{ - int i; - int error; - - trace_xfs_rmap_delete(rcur->bc_mp, rcur->bc_private.a.agno, agbno, - len, owner, offset, flags); - - error = xfs_rmap_lookup_eq(rcur, agbno, len, owner, offset, flags, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 1, done); - - error = xfs_btree_delete(rcur, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(rcur->bc_mp, i == 1, done); -done: - if (error) - trace_xfs_rmap_delete_error(rcur->bc_mp, - rcur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -static int -xfs_rmap_btrec_to_irec( - union xfs_btree_rec *rec, - struct xfs_rmap_irec *irec) -{ - irec->rm_flags = 0; - irec->rm_startblock = be32_to_cpu(rec->rmap.rm_startblock); - irec->rm_blockcount = be32_to_cpu(rec->rmap.rm_blockcount); - irec->rm_owner = be64_to_cpu(rec->rmap.rm_owner); - return xfs_rmap_irec_offset_unpack(be64_to_cpu(rec->rmap.rm_offset), - irec); -} - -/* - * Get the data from the pointed-to record. - */ -int -xfs_rmap_get_rec( - struct xfs_btree_cur *cur, - struct xfs_rmap_irec *irec, - int *stat) -{ - union xfs_btree_rec *rec; - int error; - - error = xfs_btree_get_rec(cur, &rec, stat); - if (error || !*stat) - return error; - - return xfs_rmap_btrec_to_irec(rec, irec); -} - -struct xfs_find_left_neighbor_info { - struct xfs_rmap_irec high; - struct xfs_rmap_irec *irec; - int *stat; -}; - -/* For each rmap given, figure out if it matches the key we want. */ -STATIC int -xfs_rmap_find_left_neighbor_helper( - struct xfs_btree_cur *cur, - struct xfs_rmap_irec *rec, - void *priv) -{ - struct xfs_find_left_neighbor_info *info = priv; - - trace_xfs_rmap_find_left_neighbor_candidate(cur->bc_mp, - cur->bc_private.a.agno, rec->rm_startblock, - rec->rm_blockcount, rec->rm_owner, rec->rm_offset, - rec->rm_flags); - - if (rec->rm_owner != info->high.rm_owner) - return XFS_BTREE_QUERY_RANGE_CONTINUE; - if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) && - !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK) && - rec->rm_offset + rec->rm_blockcount - 1 != info->high.rm_offset) - return XFS_BTREE_QUERY_RANGE_CONTINUE; - - *info->irec = *rec; - *info->stat = 1; - return XFS_BTREE_QUERY_RANGE_ABORT; -} - -/* - * Find the record to the left of the given extent, being careful only to - * return a match with the same owner and adjacent physical and logical - * block ranges. - */ -int -xfs_rmap_find_left_neighbor( - struct xfs_btree_cur *cur, - xfs_agblock_t bno, - uint64_t owner, - uint64_t offset, - unsigned int flags, - struct xfs_rmap_irec *irec, - int *stat) -{ - struct xfs_find_left_neighbor_info info; - int error; - - *stat = 0; - if (bno == 0) - return 0; - info.high.rm_startblock = bno - 1; - info.high.rm_owner = owner; - if (!XFS_RMAP_NON_INODE_OWNER(owner) && - !(flags & XFS_RMAP_BMBT_BLOCK)) { - if (offset == 0) - return 0; - info.high.rm_offset = offset - 1; - } else - info.high.rm_offset = 0; - info.high.rm_flags = flags; - info.high.rm_blockcount = 0; - info.irec = irec; - info.stat = stat; - - trace_xfs_rmap_find_left_neighbor_query(cur->bc_mp, - cur->bc_private.a.agno, bno, 0, owner, offset, flags); - - error = xfs_rmap_query_range(cur, &info.high, &info.high, - xfs_rmap_find_left_neighbor_helper, &info); - if (error == XFS_BTREE_QUERY_RANGE_ABORT) - error = 0; - if (*stat) - trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp, - cur->bc_private.a.agno, irec->rm_startblock, - irec->rm_blockcount, irec->rm_owner, - irec->rm_offset, irec->rm_flags); - return error; -} - -/* For each rmap given, figure out if it matches the key we want. */ -STATIC int -xfs_rmap_lookup_le_range_helper( - struct xfs_btree_cur *cur, - struct xfs_rmap_irec *rec, - void *priv) -{ - struct xfs_find_left_neighbor_info *info = priv; - - trace_xfs_rmap_lookup_le_range_candidate(cur->bc_mp, - cur->bc_private.a.agno, rec->rm_startblock, - rec->rm_blockcount, rec->rm_owner, rec->rm_offset, - rec->rm_flags); - - if (rec->rm_owner != info->high.rm_owner) - return XFS_BTREE_QUERY_RANGE_CONTINUE; - if (!XFS_RMAP_NON_INODE_OWNER(rec->rm_owner) && - !(rec->rm_flags & XFS_RMAP_BMBT_BLOCK) && - (rec->rm_offset > info->high.rm_offset || - rec->rm_offset + rec->rm_blockcount <= info->high.rm_offset)) - return XFS_BTREE_QUERY_RANGE_CONTINUE; - - *info->irec = *rec; - *info->stat = 1; - return XFS_BTREE_QUERY_RANGE_ABORT; -} - -/* - * Find the record to the left of the given extent, being careful only to - * return a match with the same owner and overlapping physical and logical - * block ranges. This is the overlapping-interval version of - * xfs_rmap_lookup_le. - */ -int -xfs_rmap_lookup_le_range( - struct xfs_btree_cur *cur, - xfs_agblock_t bno, - uint64_t owner, - uint64_t offset, - unsigned int flags, - struct xfs_rmap_irec *irec, - int *stat) -{ - struct xfs_find_left_neighbor_info info; - int error; - - info.high.rm_startblock = bno; - info.high.rm_owner = owner; - if (!XFS_RMAP_NON_INODE_OWNER(owner) && !(flags & XFS_RMAP_BMBT_BLOCK)) - info.high.rm_offset = offset; - else - info.high.rm_offset = 0; - info.high.rm_flags = flags; - info.high.rm_blockcount = 0; - *stat = 0; - info.irec = irec; - info.stat = stat; - - trace_xfs_rmap_lookup_le_range(cur->bc_mp, - cur->bc_private.a.agno, bno, 0, owner, offset, flags); - error = xfs_rmap_query_range(cur, &info.high, &info.high, - xfs_rmap_lookup_le_range_helper, &info); - if (error == XFS_BTREE_QUERY_RANGE_ABORT) - error = 0; - if (*stat) - trace_xfs_rmap_lookup_le_range_result(cur->bc_mp, - cur->bc_private.a.agno, irec->rm_startblock, - irec->rm_blockcount, irec->rm_owner, - irec->rm_offset, irec->rm_flags); - return error; -} - -/* - * Find the extent in the rmap btree and remove it. - * - * The record we find should always be an exact match for the extent that we're - * looking for, since we insert them into the btree without modification. - * - * Special Case #1: when growing the filesystem, we "free" an extent when - * growing the last AG. This extent is new space and so it is not tracked as - * used space in the btree. The growfs code will pass in an owner of - * XFS_RMAP_OWN_NULL to indicate that it expected that there is no owner of this - * extent. We verify that - the extent lookup result in a record that does not - * overlap. - * - * Special Case #2: EFIs do not record the owner of the extent, so when - * recovering EFIs from the log we pass in XFS_RMAP_OWN_UNKNOWN to tell the rmap - * btree to ignore the owner (i.e. wildcard match) so we don't trigger - * corruption checks during log recovery. - */ -STATIC int -xfs_rmap_unmap( - struct xfs_btree_cur *cur, - xfs_agblock_t bno, - xfs_extlen_t len, - bool unwritten, - struct xfs_owner_info *oinfo) -{ - struct xfs_mount *mp = cur->bc_mp; - struct xfs_rmap_irec ltrec; - uint64_t ltoff; - int error = 0; - int i; - uint64_t owner; - uint64_t offset; - unsigned int flags; - bool ignore_off; - - xfs_owner_info_unpack(oinfo, &owner, &offset, &flags); - ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) || - (flags & XFS_RMAP_BMBT_BLOCK); - if (unwritten) - flags |= XFS_RMAP_UNWRITTEN; - trace_xfs_rmap_unmap(mp, cur->bc_private.a.agno, bno, len, - unwritten, oinfo); - - /* - * We should always have a left record because there's a static record - * for the AG headers at rm_startblock == 0 created by mkfs/growfs that - * will not ever be removed from the tree. - */ - error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, flags, &i); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); - - error = xfs_rmap_get_rec(cur, <rec, &i); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); - trace_xfs_rmap_lookup_le_range_result(cur->bc_mp, - cur->bc_private.a.agno, ltrec.rm_startblock, - ltrec.rm_blockcount, ltrec.rm_owner, - ltrec.rm_offset, ltrec.rm_flags); - ltoff = ltrec.rm_offset; - - /* - * For growfs, the incoming extent must be beyond the left record we - * just found as it is new space and won't be used by anyone. This is - * just a corruption check as we don't actually do anything with this - * extent. Note that we need to use >= instead of > because it might - * be the case that the "left" extent goes all the way to EOFS. - */ - if (owner == XFS_RMAP_OWN_NULL) { - XFS_WANT_CORRUPTED_GOTO(mp, bno >= ltrec.rm_startblock + - ltrec.rm_blockcount, out_error); - goto out_done; - } - - /* Make sure the unwritten flag matches. */ - XFS_WANT_CORRUPTED_GOTO(mp, (flags & XFS_RMAP_UNWRITTEN) == - (ltrec.rm_flags & XFS_RMAP_UNWRITTEN), out_error); - - /* Make sure the extent we found covers the entire freeing range. */ - XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_startblock <= bno && - ltrec.rm_startblock + ltrec.rm_blockcount >= - bno + len, out_error); - - /* Make sure the owner matches what we expect to find in the tree. */ - XFS_WANT_CORRUPTED_GOTO(mp, owner == ltrec.rm_owner || - XFS_RMAP_NON_INODE_OWNER(owner), out_error); - - /* Check the offset, if necessary. */ - if (!XFS_RMAP_NON_INODE_OWNER(owner)) { - if (flags & XFS_RMAP_BMBT_BLOCK) { - XFS_WANT_CORRUPTED_GOTO(mp, - ltrec.rm_flags & XFS_RMAP_BMBT_BLOCK, - out_error); - } else { - XFS_WANT_CORRUPTED_GOTO(mp, - ltrec.rm_offset <= offset, out_error); - XFS_WANT_CORRUPTED_GOTO(mp, - ltoff + ltrec.rm_blockcount >= offset + len, - out_error); - } - } - - if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) { - /* exact match, simply remove the record from rmap tree */ - trace_xfs_rmap_delete(mp, cur->bc_private.a.agno, - ltrec.rm_startblock, ltrec.rm_blockcount, - ltrec.rm_owner, ltrec.rm_offset, - ltrec.rm_flags); - error = xfs_btree_delete(cur, &i); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); - } else if (ltrec.rm_startblock == bno) { - /* - * overlap left hand side of extent: move the start, trim the - * length and update the current record. - * - * ltbno ltlen - * Orig: |oooooooooooooooooooo| - * Freeing: |fffffffff| - * Result: |rrrrrrrrrr| - * bno len - */ - ltrec.rm_startblock += len; - ltrec.rm_blockcount -= len; - if (!ignore_off) - ltrec.rm_offset += len; - error = xfs_rmap_update(cur, <rec); - if (error) - goto out_error; - } else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) { - /* - * overlap right hand side of extent: trim the length and update - * the current record. - * - * ltbno ltlen - * Orig: |oooooooooooooooooooo| - * Freeing: |fffffffff| - * Result: |rrrrrrrrrr| - * bno len - */ - ltrec.rm_blockcount -= len; - error = xfs_rmap_update(cur, <rec); - if (error) - goto out_error; - } else { - - /* - * overlap middle of extent: trim the length of the existing - * record to the length of the new left-extent size, increment - * the insertion position so we can insert a new record - * containing the remaining right-extent space. - * - * ltbno ltlen - * Orig: |oooooooooooooooooooo| - * Freeing: |fffffffff| - * Result: |rrrrr| |rrrr| - * bno len - */ - xfs_extlen_t orig_len = ltrec.rm_blockcount; - - ltrec.rm_blockcount = bno - ltrec.rm_startblock; - error = xfs_rmap_update(cur, <rec); - if (error) - goto out_error; - - error = xfs_btree_increment(cur, 0, &i); - if (error) - goto out_error; - - cur->bc_rec.r.rm_startblock = bno + len; - cur->bc_rec.r.rm_blockcount = orig_len - len - - ltrec.rm_blockcount; - cur->bc_rec.r.rm_owner = ltrec.rm_owner; - if (ignore_off) - cur->bc_rec.r.rm_offset = 0; - else - cur->bc_rec.r.rm_offset = offset + len; - cur->bc_rec.r.rm_flags = flags; - trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, - cur->bc_rec.r.rm_startblock, - cur->bc_rec.r.rm_blockcount, - cur->bc_rec.r.rm_owner, - cur->bc_rec.r.rm_offset, - cur->bc_rec.r.rm_flags); - error = xfs_btree_insert(cur, &i); - if (error) - goto out_error; - } - -out_done: - trace_xfs_rmap_unmap_done(mp, cur->bc_private.a.agno, bno, len, - unwritten, oinfo); -out_error: - if (error) - trace_xfs_rmap_unmap_error(mp, cur->bc_private.a.agno, - error, _RET_IP_); - return error; -} - -/* - * Remove a reference to an extent in the rmap btree. - */ -int -xfs_rmap_free( - struct xfs_trans *tp, - struct xfs_buf *agbp, - xfs_agnumber_t agno, - xfs_agblock_t bno, - xfs_extlen_t len, - struct xfs_owner_info *oinfo) -{ - struct xfs_mount *mp = tp->t_mountp; - struct xfs_btree_cur *cur; - int error; - - if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) - return 0; - - cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno); - - error = xfs_rmap_unmap(cur, bno, len, false, oinfo); - if (error) - goto out_error; - - xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); - return 0; - -out_error: - xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); - return error; -} - -/* - * A mergeable rmap must have the same owner and the same values for - * the unwritten, attr_fork, and bmbt flags. The startblock and - * offset are checked separately. - */ -static bool -xfs_rmap_is_mergeable( - struct xfs_rmap_irec *irec, - uint64_t owner, - unsigned int flags) -{ - if (irec->rm_owner == XFS_RMAP_OWN_NULL) - return false; - if (irec->rm_owner != owner) - return false; - if ((flags & XFS_RMAP_UNWRITTEN) ^ - (irec->rm_flags & XFS_RMAP_UNWRITTEN)) - return false; - if ((flags & XFS_RMAP_ATTR_FORK) ^ - (irec->rm_flags & XFS_RMAP_ATTR_FORK)) - return false; - if ((flags & XFS_RMAP_BMBT_BLOCK) ^ - (irec->rm_flags & XFS_RMAP_BMBT_BLOCK)) - return false; - return true; -} - -/* - * When we allocate a new block, the first thing we do is add a reference to - * the extent in the rmap btree. This takes the form of a [agbno, length, - * owner, offset] record. Flags are encoded in the high bits of the offset - * field. - */ -STATIC int -xfs_rmap_map( - struct xfs_btree_cur *cur, - xfs_agblock_t bno, - xfs_extlen_t len, - bool unwritten, - struct xfs_owner_info *oinfo) -{ - struct xfs_mount *mp = cur->bc_mp; - struct xfs_rmap_irec ltrec; - struct xfs_rmap_irec gtrec; - int have_gt; - int have_lt; - int error = 0; - int i; - uint64_t owner; - uint64_t offset; - unsigned int flags = 0; - bool ignore_off; - - xfs_owner_info_unpack(oinfo, &owner, &offset, &flags); - ASSERT(owner != 0); - ignore_off = XFS_RMAP_NON_INODE_OWNER(owner) || - (flags & XFS_RMAP_BMBT_BLOCK); - if (unwritten) - flags |= XFS_RMAP_UNWRITTEN; - trace_xfs_rmap_map(mp, cur->bc_private.a.agno, bno, len, - unwritten, oinfo); - - /* - * For the initial lookup, look for an exact match or the left-adjacent - * record for our insertion point. This will also give us the record for - * start block contiguity tests. - */ - error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, flags, - &have_lt); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(mp, have_lt == 1, out_error); - - error = xfs_rmap_get_rec(cur, <rec, &have_lt); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(mp, have_lt == 1, out_error); - trace_xfs_rmap_lookup_le_range_result(cur->bc_mp, - cur->bc_private.a.agno, ltrec.rm_startblock, - ltrec.rm_blockcount, ltrec.rm_owner, - ltrec.rm_offset, ltrec.rm_flags); - - if (!xfs_rmap_is_mergeable(<rec, owner, flags)) - have_lt = 0; - - XFS_WANT_CORRUPTED_GOTO(mp, - have_lt == 0 || - ltrec.rm_startblock + ltrec.rm_blockcount <= bno, out_error); - - /* - * Increment the cursor to see if we have a right-adjacent record to our - * insertion point. This will give us the record for end block - * contiguity tests. - */ - error = xfs_btree_increment(cur, 0, &have_gt); - if (error) - goto out_error; - if (have_gt) { - error = xfs_rmap_get_rec(cur, >rec, &have_gt); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(mp, have_gt == 1, out_error); - XFS_WANT_CORRUPTED_GOTO(mp, bno + len <= gtrec.rm_startblock, - out_error); - trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp, - cur->bc_private.a.agno, gtrec.rm_startblock, - gtrec.rm_blockcount, gtrec.rm_owner, - gtrec.rm_offset, gtrec.rm_flags); - if (!xfs_rmap_is_mergeable(>rec, owner, flags)) - have_gt = 0; - } - - /* - * Note: cursor currently points one record to the right of ltrec, even - * if there is no record in the tree to the right. - */ - if (have_lt && - ltrec.rm_startblock + ltrec.rm_blockcount == bno && - (ignore_off || ltrec.rm_offset + ltrec.rm_blockcount == offset)) { - /* - * left edge contiguous, merge into left record. - * - * ltbno ltlen - * orig: |ooooooooo| - * adding: |aaaaaaaaa| - * result: |rrrrrrrrrrrrrrrrrrr| - * bno len - */ - ltrec.rm_blockcount += len; - if (have_gt && - bno + len == gtrec.rm_startblock && - (ignore_off || offset + len == gtrec.rm_offset) && - (unsigned long)ltrec.rm_blockcount + len + - gtrec.rm_blockcount <= XFS_RMAP_LEN_MAX) { - /* - * right edge also contiguous, delete right record - * and merge into left record. - * - * ltbno ltlen gtbno gtlen - * orig: |ooooooooo| |ooooooooo| - * adding: |aaaaaaaaa| - * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr| - */ - ltrec.rm_blockcount += gtrec.rm_blockcount; - trace_xfs_rmap_delete(mp, cur->bc_private.a.agno, - gtrec.rm_startblock, - gtrec.rm_blockcount, - gtrec.rm_owner, - gtrec.rm_offset, - gtrec.rm_flags); - error = xfs_btree_delete(cur, &i); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); - } - - /* point the cursor back to the left record and update */ - error = xfs_btree_decrement(cur, 0, &have_gt); - if (error) - goto out_error; - error = xfs_rmap_update(cur, <rec); - if (error) - goto out_error; - } else if (have_gt && - bno + len == gtrec.rm_startblock && - (ignore_off || offset + len == gtrec.rm_offset)) { - /* - * right edge contiguous, merge into right record. - * - * gtbno gtlen - * Orig: |ooooooooo| - * adding: |aaaaaaaaa| - * Result: |rrrrrrrrrrrrrrrrrrr| - * bno len - */ - gtrec.rm_startblock = bno; - gtrec.rm_blockcount += len; - if (!ignore_off) - gtrec.rm_offset = offset; - error = xfs_rmap_update(cur, >rec); - if (error) - goto out_error; - } else { - /* - * no contiguous edge with identical owner, insert - * new record at current cursor position. - */ - cur->bc_rec.r.rm_startblock = bno; - cur->bc_rec.r.rm_blockcount = len; - cur->bc_rec.r.rm_owner = owner; - cur->bc_rec.r.rm_offset = offset; - cur->bc_rec.r.rm_flags = flags; - trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno, len, - owner, offset, flags); - error = xfs_btree_insert(cur, &i); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); - } - - trace_xfs_rmap_map_done(mp, cur->bc_private.a.agno, bno, len, - unwritten, oinfo); -out_error: - if (error) - trace_xfs_rmap_map_error(mp, cur->bc_private.a.agno, - error, _RET_IP_); - return error; -} - -/* - * Add a reference to an extent in the rmap btree. - */ -int -xfs_rmap_alloc( - struct xfs_trans *tp, - struct xfs_buf *agbp, - xfs_agnumber_t agno, - xfs_agblock_t bno, - xfs_extlen_t len, - struct xfs_owner_info *oinfo) -{ - struct xfs_mount *mp = tp->t_mountp; - struct xfs_btree_cur *cur; - int error; - - if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) - return 0; - - cur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno); - error = xfs_rmap_map(cur, bno, len, false, oinfo); - if (error) - goto out_error; - - xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR); - return 0; - -out_error: - xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); - return error; -} - -#define RMAP_LEFT_CONTIG (1 << 0) -#define RMAP_RIGHT_CONTIG (1 << 1) -#define RMAP_LEFT_FILLING (1 << 2) -#define RMAP_RIGHT_FILLING (1 << 3) -#define RMAP_LEFT_VALID (1 << 6) -#define RMAP_RIGHT_VALID (1 << 7) - -#define LEFT r[0] -#define RIGHT r[1] -#define PREV r[2] -#define NEW r[3] - -/* - * Convert an unwritten extent to a real extent or vice versa. - * Does not handle overlapping extents. - */ -STATIC int -xfs_rmap_convert( - struct xfs_btree_cur *cur, - xfs_agblock_t bno, - xfs_extlen_t len, - bool unwritten, - struct xfs_owner_info *oinfo) -{ - struct xfs_mount *mp = cur->bc_mp; - struct xfs_rmap_irec r[4]; /* neighbor extent entries */ - /* left is 0, right is 1, prev is 2 */ - /* new is 3 */ - uint64_t owner; - uint64_t offset; - uint64_t new_endoff; - unsigned int oldext; - unsigned int newext; - unsigned int flags = 0; - int i; - int state = 0; - int error; - - xfs_owner_info_unpack(oinfo, &owner, &offset, &flags); - ASSERT(!(XFS_RMAP_NON_INODE_OWNER(owner) || - (flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK)))); - oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0; - new_endoff = offset + len; - trace_xfs_rmap_convert(mp, cur->bc_private.a.agno, bno, len, - unwritten, oinfo); - - /* - * For the initial lookup, look for an exact match or the left-adjacent - * record for our insertion point. This will also give us the record for - * start block contiguity tests. - */ - error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, oldext, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - - error = xfs_rmap_get_rec(cur, &PREV, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - trace_xfs_rmap_lookup_le_range_result(cur->bc_mp, - cur->bc_private.a.agno, PREV.rm_startblock, - PREV.rm_blockcount, PREV.rm_owner, - PREV.rm_offset, PREV.rm_flags); - - ASSERT(PREV.rm_offset <= offset); - ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff); - ASSERT((PREV.rm_flags & XFS_RMAP_UNWRITTEN) == oldext); - newext = ~oldext & XFS_RMAP_UNWRITTEN; - - /* - * Set flags determining what part of the previous oldext allocation - * extent is being replaced by a newext allocation. - */ - if (PREV.rm_offset == offset) - state |= RMAP_LEFT_FILLING; - if (PREV.rm_offset + PREV.rm_blockcount == new_endoff) - state |= RMAP_RIGHT_FILLING; - - /* - * Decrement the cursor to see if we have a left-adjacent record to our - * insertion point. This will give us the record for end block - * contiguity tests. - */ - error = xfs_btree_decrement(cur, 0, &i); - if (error) - goto done; - if (i) { - state |= RMAP_LEFT_VALID; - error = xfs_rmap_get_rec(cur, &LEFT, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - XFS_WANT_CORRUPTED_GOTO(mp, - LEFT.rm_startblock + LEFT.rm_blockcount <= bno, - done); - trace_xfs_rmap_find_left_neighbor_result(cur->bc_mp, - cur->bc_private.a.agno, LEFT.rm_startblock, - LEFT.rm_blockcount, LEFT.rm_owner, - LEFT.rm_offset, LEFT.rm_flags); - if (LEFT.rm_startblock + LEFT.rm_blockcount == bno && - LEFT.rm_offset + LEFT.rm_blockcount == offset && - xfs_rmap_is_mergeable(&LEFT, owner, newext)) - state |= RMAP_LEFT_CONTIG; - } - - /* - * Increment the cursor to see if we have a right-adjacent record to our - * insertion point. This will give us the record for end block - * contiguity tests. - */ - error = xfs_btree_increment(cur, 0, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - error = xfs_btree_increment(cur, 0, &i); - if (error) - goto done; - if (i) { - state |= RMAP_RIGHT_VALID; - error = xfs_rmap_get_rec(cur, &RIGHT, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - XFS_WANT_CORRUPTED_GOTO(mp, bno + len <= RIGHT.rm_startblock, - done); - trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp, - cur->bc_private.a.agno, RIGHT.rm_startblock, - RIGHT.rm_blockcount, RIGHT.rm_owner, - RIGHT.rm_offset, RIGHT.rm_flags); - if (bno + len == RIGHT.rm_startblock && - offset + len == RIGHT.rm_offset && - xfs_rmap_is_mergeable(&RIGHT, owner, newext)) - state |= RMAP_RIGHT_CONTIG; - } - - /* check that left + prev + right is not too long */ - if ((state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | - RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) == - (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | - RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG) && - (unsigned long)LEFT.rm_blockcount + len + - RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX) - state &= ~RMAP_RIGHT_CONTIG; - - trace_xfs_rmap_convert_state(mp, cur->bc_private.a.agno, state, - _RET_IP_); - - /* reset the cursor back to PREV */ - error = xfs_rmap_lookup_le(cur, bno, len, owner, offset, oldext, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - - /* - * Switch out based on the FILLING and CONTIG state bits. - */ - switch (state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | - RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) { - case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | - RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG: - /* - * Setting all of a previous oldext extent to newext. - * The left and right neighbors are both contiguous with new. - */ - error = xfs_btree_increment(cur, 0, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - trace_xfs_rmap_delete(mp, cur->bc_private.a.agno, - RIGHT.rm_startblock, RIGHT.rm_blockcount, - RIGHT.rm_owner, RIGHT.rm_offset, - RIGHT.rm_flags); - error = xfs_btree_delete(cur, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - error = xfs_btree_decrement(cur, 0, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - trace_xfs_rmap_delete(mp, cur->bc_private.a.agno, - PREV.rm_startblock, PREV.rm_blockcount, - PREV.rm_owner, PREV.rm_offset, - PREV.rm_flags); - error = xfs_btree_delete(cur, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - error = xfs_btree_decrement(cur, 0, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - NEW = LEFT; - NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - break; - - case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG: - /* - * Setting all of a previous oldext extent to newext. - * The left neighbor is contiguous, the right is not. - */ - trace_xfs_rmap_delete(mp, cur->bc_private.a.agno, - PREV.rm_startblock, PREV.rm_blockcount, - PREV.rm_owner, PREV.rm_offset, - PREV.rm_flags); - error = xfs_btree_delete(cur, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - error = xfs_btree_decrement(cur, 0, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - NEW = LEFT; - NEW.rm_blockcount += PREV.rm_blockcount; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - break; - - case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG: - /* - * Setting all of a previous oldext extent to newext. - * The right neighbor is contiguous, the left is not. - */ - error = xfs_btree_increment(cur, 0, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - trace_xfs_rmap_delete(mp, cur->bc_private.a.agno, - RIGHT.rm_startblock, RIGHT.rm_blockcount, - RIGHT.rm_owner, RIGHT.rm_offset, - RIGHT.rm_flags); - error = xfs_btree_delete(cur, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - error = xfs_btree_decrement(cur, 0, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - NEW = PREV; - NEW.rm_blockcount = len + RIGHT.rm_blockcount; - NEW.rm_flags = newext; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - break; - - case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING: - /* - * Setting all of a previous oldext extent to newext. - * Neither the left nor right neighbors are contiguous with - * the new one. - */ - NEW = PREV; - NEW.rm_flags = newext; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - break; - - case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG: - /* - * Setting the first part of a previous oldext extent to newext. - * The left neighbor is contiguous. - */ - NEW = PREV; - NEW.rm_offset += len; - NEW.rm_startblock += len; - NEW.rm_blockcount -= len; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - error = xfs_btree_decrement(cur, 0, &i); - if (error) - goto done; - NEW = LEFT; - NEW.rm_blockcount += len; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - break; - - case RMAP_LEFT_FILLING: - /* - * Setting the first part of a previous oldext extent to newext. - * The left neighbor is not contiguous. - */ - NEW = PREV; - NEW.rm_startblock += len; - NEW.rm_offset += len; - NEW.rm_blockcount -= len; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - NEW.rm_startblock = bno; - NEW.rm_owner = owner; - NEW.rm_offset = offset; - NEW.rm_blockcount = len; - NEW.rm_flags = newext; - cur->bc_rec.r = NEW; - trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno, - len, owner, offset, newext); - error = xfs_btree_insert(cur, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - break; - - case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG: - /* - * Setting the last part of a previous oldext extent to newext. - * The right neighbor is contiguous with the new allocation. - */ - NEW = PREV; - NEW.rm_blockcount -= len; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - error = xfs_btree_increment(cur, 0, &i); - if (error) - goto done; - NEW = RIGHT; - NEW.rm_offset = offset; - NEW.rm_startblock = bno; - NEW.rm_blockcount += len; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - break; - - case RMAP_RIGHT_FILLING: - /* - * Setting the last part of a previous oldext extent to newext. - * The right neighbor is not contiguous. - */ - NEW = PREV; - NEW.rm_blockcount -= len; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset, - oldext, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); - NEW.rm_startblock = bno; - NEW.rm_owner = owner; - NEW.rm_offset = offset; - NEW.rm_blockcount = len; - NEW.rm_flags = newext; - cur->bc_rec.r = NEW; - trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno, - len, owner, offset, newext); - error = xfs_btree_insert(cur, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - break; - - case 0: - /* - * Setting the middle part of a previous oldext extent to - * newext. Contiguity is impossible here. - * One extent becomes three extents. - */ - /* new right extent - oldext */ - NEW.rm_startblock = bno + len; - NEW.rm_owner = owner; - NEW.rm_offset = new_endoff; - NEW.rm_blockcount = PREV.rm_offset + PREV.rm_blockcount - - new_endoff; - NEW.rm_flags = PREV.rm_flags; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - /* new left extent - oldext */ - NEW = PREV; - NEW.rm_blockcount = offset - PREV.rm_offset; - cur->bc_rec.r = NEW; - trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, - NEW.rm_startblock, NEW.rm_blockcount, - NEW.rm_owner, NEW.rm_offset, - NEW.rm_flags); - error = xfs_btree_insert(cur, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - /* - * Reset the cursor to the position of the new extent - * we are about to insert as we can't trust it after - * the previous insert. - */ - error = xfs_rmap_lookup_eq(cur, bno, len, owner, offset, - oldext, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 0, done); - /* new middle extent - newext */ - cur->bc_rec.r.rm_flags &= ~XFS_RMAP_UNWRITTEN; - cur->bc_rec.r.rm_flags |= newext; - trace_xfs_rmap_insert(mp, cur->bc_private.a.agno, bno, len, - owner, offset, newext); - error = xfs_btree_insert(cur, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - break; - - case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG: - case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG: - case RMAP_LEFT_FILLING | RMAP_RIGHT_CONTIG: - case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG: - case RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG: - case RMAP_LEFT_CONTIG: - case RMAP_RIGHT_CONTIG: - /* - * These cases are all impossible. - */ - ASSERT(0); - } - - trace_xfs_rmap_convert_done(mp, cur->bc_private.a.agno, bno, len, - unwritten, oinfo); -done: - if (error) - trace_xfs_rmap_convert_error(cur->bc_mp, - cur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -/* - * Convert an unwritten extent to a real extent or vice versa. If there is no - * possibility of overlapping extents, delegate to the simpler convert - * function. - */ -STATIC int -xfs_rmap_convert_shared( - struct xfs_btree_cur *cur, - xfs_agblock_t bno, - xfs_extlen_t len, - bool unwritten, - struct xfs_owner_info *oinfo) -{ - struct xfs_mount *mp = cur->bc_mp; - struct xfs_rmap_irec r[4]; /* neighbor extent entries */ - /* left is 0, right is 1, prev is 2 */ - /* new is 3 */ - uint64_t owner; - uint64_t offset; - uint64_t new_endoff; - unsigned int oldext; - unsigned int newext; - unsigned int flags = 0; - int i; - int state = 0; - int error; - - xfs_owner_info_unpack(oinfo, &owner, &offset, &flags); - ASSERT(!(XFS_RMAP_NON_INODE_OWNER(owner) || - (flags & (XFS_RMAP_ATTR_FORK | XFS_RMAP_BMBT_BLOCK)))); - oldext = unwritten ? XFS_RMAP_UNWRITTEN : 0; - new_endoff = offset + len; - trace_xfs_rmap_convert(mp, cur->bc_private.a.agno, bno, len, - unwritten, oinfo); - - /* - * For the initial lookup, look for and exact match or the left-adjacent - * record for our insertion point. This will also give us the record for - * start block contiguity tests. - */ - error = xfs_rmap_lookup_le_range(cur, bno, owner, offset, flags, - &PREV, &i); - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - - ASSERT(PREV.rm_offset <= offset); - ASSERT(PREV.rm_offset + PREV.rm_blockcount >= new_endoff); - ASSERT((PREV.rm_flags & XFS_RMAP_UNWRITTEN) == oldext); - newext = ~oldext & XFS_RMAP_UNWRITTEN; - - /* - * Set flags determining what part of the previous oldext allocation - * extent is being replaced by a newext allocation. - */ - if (PREV.rm_offset == offset) - state |= RMAP_LEFT_FILLING; - if (PREV.rm_offset + PREV.rm_blockcount == new_endoff) - state |= RMAP_RIGHT_FILLING; - - /* Is there a left record that abuts our range? */ - error = xfs_rmap_find_left_neighbor(cur, bno, owner, offset, newext, - &LEFT, &i); - if (error) - goto done; - if (i) { - state |= RMAP_LEFT_VALID; - XFS_WANT_CORRUPTED_GOTO(mp, - LEFT.rm_startblock + LEFT.rm_blockcount <= bno, - done); - if (xfs_rmap_is_mergeable(&LEFT, owner, newext)) - state |= RMAP_LEFT_CONTIG; - } - - /* Is there a right record that abuts our range? */ - error = xfs_rmap_lookup_eq(cur, bno + len, len, owner, offset + len, - newext, &i); - if (error) - goto done; - if (i) { - state |= RMAP_RIGHT_VALID; - error = xfs_rmap_get_rec(cur, &RIGHT, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - XFS_WANT_CORRUPTED_GOTO(mp, bno + len <= RIGHT.rm_startblock, - done); - trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp, - cur->bc_private.a.agno, RIGHT.rm_startblock, - RIGHT.rm_blockcount, RIGHT.rm_owner, - RIGHT.rm_offset, RIGHT.rm_flags); - if (xfs_rmap_is_mergeable(&RIGHT, owner, newext)) - state |= RMAP_RIGHT_CONTIG; - } - - /* check that left + prev + right is not too long */ - if ((state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | - RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) == - (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | - RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG) && - (unsigned long)LEFT.rm_blockcount + len + - RIGHT.rm_blockcount > XFS_RMAP_LEN_MAX) - state &= ~RMAP_RIGHT_CONTIG; - - trace_xfs_rmap_convert_state(mp, cur->bc_private.a.agno, state, - _RET_IP_); - /* - * Switch out based on the FILLING and CONTIG state bits. - */ - switch (state & (RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | - RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG)) { - case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | - RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG: - /* - * Setting all of a previous oldext extent to newext. - * The left and right neighbors are both contiguous with new. - */ - error = xfs_rmap_delete(cur, RIGHT.rm_startblock, - RIGHT.rm_blockcount, RIGHT.rm_owner, - RIGHT.rm_offset, RIGHT.rm_flags); - if (error) - goto done; - error = xfs_rmap_delete(cur, PREV.rm_startblock, - PREV.rm_blockcount, PREV.rm_owner, - PREV.rm_offset, PREV.rm_flags); - if (error) - goto done; - NEW = LEFT; - error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock, - NEW.rm_blockcount, NEW.rm_owner, - NEW.rm_offset, NEW.rm_flags, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - NEW.rm_blockcount += PREV.rm_blockcount + RIGHT.rm_blockcount; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - break; - - case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG: - /* - * Setting all of a previous oldext extent to newext. - * The left neighbor is contiguous, the right is not. - */ - error = xfs_rmap_delete(cur, PREV.rm_startblock, - PREV.rm_blockcount, PREV.rm_owner, - PREV.rm_offset, PREV.rm_flags); - if (error) - goto done; - NEW = LEFT; - error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock, - NEW.rm_blockcount, NEW.rm_owner, - NEW.rm_offset, NEW.rm_flags, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - NEW.rm_blockcount += PREV.rm_blockcount; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - break; - - case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG: - /* - * Setting all of a previous oldext extent to newext. - * The right neighbor is contiguous, the left is not. - */ - error = xfs_rmap_delete(cur, RIGHT.rm_startblock, - RIGHT.rm_blockcount, RIGHT.rm_owner, - RIGHT.rm_offset, RIGHT.rm_flags); - if (error) - goto done; - NEW = PREV; - error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock, - NEW.rm_blockcount, NEW.rm_owner, - NEW.rm_offset, NEW.rm_flags, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - NEW.rm_blockcount += RIGHT.rm_blockcount; - NEW.rm_flags = RIGHT.rm_flags; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - break; - - case RMAP_LEFT_FILLING | RMAP_RIGHT_FILLING: - /* - * Setting all of a previous oldext extent to newext. - * Neither the left nor right neighbors are contiguous with - * the new one. - */ - NEW = PREV; - error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock, - NEW.rm_blockcount, NEW.rm_owner, - NEW.rm_offset, NEW.rm_flags, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - NEW.rm_flags = newext; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - break; - - case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG: - /* - * Setting the first part of a previous oldext extent to newext. - * The left neighbor is contiguous. - */ - NEW = PREV; - error = xfs_rmap_delete(cur, NEW.rm_startblock, - NEW.rm_blockcount, NEW.rm_owner, - NEW.rm_offset, NEW.rm_flags); - if (error) - goto done; - NEW.rm_offset += len; - NEW.rm_startblock += len; - NEW.rm_blockcount -= len; - error = xfs_rmap_insert(cur, NEW.rm_startblock, - NEW.rm_blockcount, NEW.rm_owner, - NEW.rm_offset, NEW.rm_flags); - if (error) - goto done; - NEW = LEFT; - error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock, - NEW.rm_blockcount, NEW.rm_owner, - NEW.rm_offset, NEW.rm_flags, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - NEW.rm_blockcount += len; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - break; - - case RMAP_LEFT_FILLING: - /* - * Setting the first part of a previous oldext extent to newext. - * The left neighbor is not contiguous. - */ - NEW = PREV; - error = xfs_rmap_delete(cur, NEW.rm_startblock, - NEW.rm_blockcount, NEW.rm_owner, - NEW.rm_offset, NEW.rm_flags); - if (error) - goto done; - NEW.rm_offset += len; - NEW.rm_startblock += len; - NEW.rm_blockcount -= len; - error = xfs_rmap_insert(cur, NEW.rm_startblock, - NEW.rm_blockcount, NEW.rm_owner, - NEW.rm_offset, NEW.rm_flags); - if (error) - goto done; - error = xfs_rmap_insert(cur, bno, len, owner, offset, newext); - if (error) - goto done; - break; - - case RMAP_RIGHT_FILLING | RMAP_RIGHT_CONTIG: - /* - * Setting the last part of a previous oldext extent to newext. - * The right neighbor is contiguous with the new allocation. - */ - NEW = PREV; - error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock, - NEW.rm_blockcount, NEW.rm_owner, - NEW.rm_offset, NEW.rm_flags, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - NEW.rm_blockcount = offset - NEW.rm_offset; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - NEW = RIGHT; - error = xfs_rmap_delete(cur, NEW.rm_startblock, - NEW.rm_blockcount, NEW.rm_owner, - NEW.rm_offset, NEW.rm_flags); - if (error) - goto done; - NEW.rm_offset = offset; - NEW.rm_startblock = bno; - NEW.rm_blockcount += len; - error = xfs_rmap_insert(cur, NEW.rm_startblock, - NEW.rm_blockcount, NEW.rm_owner, - NEW.rm_offset, NEW.rm_flags); - if (error) - goto done; - break; - - case RMAP_RIGHT_FILLING: - /* - * Setting the last part of a previous oldext extent to newext. - * The right neighbor is not contiguous. - */ - NEW = PREV; - error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock, - NEW.rm_blockcount, NEW.rm_owner, - NEW.rm_offset, NEW.rm_flags, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - NEW.rm_blockcount -= len; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - error = xfs_rmap_insert(cur, bno, len, owner, offset, newext); - if (error) - goto done; - break; - - case 0: - /* - * Setting the middle part of a previous oldext extent to - * newext. Contiguity is impossible here. - * One extent becomes three extents. - */ - /* new right extent - oldext */ - NEW.rm_startblock = bno + len; - NEW.rm_owner = owner; - NEW.rm_offset = new_endoff; - NEW.rm_blockcount = PREV.rm_offset + PREV.rm_blockcount - - new_endoff; - NEW.rm_flags = PREV.rm_flags; - error = xfs_rmap_insert(cur, NEW.rm_startblock, - NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, - NEW.rm_flags); - if (error) - goto done; - /* new left extent - oldext */ - NEW = PREV; - error = xfs_rmap_lookup_eq(cur, NEW.rm_startblock, - NEW.rm_blockcount, NEW.rm_owner, - NEW.rm_offset, NEW.rm_flags, &i); - if (error) - goto done; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, done); - NEW.rm_blockcount = offset - NEW.rm_offset; - error = xfs_rmap_update(cur, &NEW); - if (error) - goto done; - /* new middle extent - newext */ - NEW.rm_startblock = bno; - NEW.rm_blockcount = len; - NEW.rm_owner = owner; - NEW.rm_offset = offset; - NEW.rm_flags = newext; - error = xfs_rmap_insert(cur, NEW.rm_startblock, - NEW.rm_blockcount, NEW.rm_owner, NEW.rm_offset, - NEW.rm_flags); - if (error) - goto done; - break; - - case RMAP_LEFT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG: - case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG: - case RMAP_LEFT_FILLING | RMAP_RIGHT_CONTIG: - case RMAP_RIGHT_FILLING | RMAP_LEFT_CONTIG: - case RMAP_LEFT_CONTIG | RMAP_RIGHT_CONTIG: - case RMAP_LEFT_CONTIG: - case RMAP_RIGHT_CONTIG: - /* - * These cases are all impossible. - */ - ASSERT(0); - } - - trace_xfs_rmap_convert_done(mp, cur->bc_private.a.agno, bno, len, - unwritten, oinfo); -done: - if (error) - trace_xfs_rmap_convert_error(cur->bc_mp, - cur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -#undef NEW -#undef LEFT -#undef RIGHT -#undef PREV - -/* - * Find an extent in the rmap btree and unmap it. For rmap extent types that - * can overlap (data fork rmaps on reflink filesystems) we must be careful - * that the prev/next records in the btree might belong to another owner. - * Therefore we must use delete+insert to alter any of the key fields. - * - * For every other situation there can only be one owner for a given extent, - * so we can call the regular _free function. - */ -STATIC int -xfs_rmap_unmap_shared( - struct xfs_btree_cur *cur, - xfs_agblock_t bno, - xfs_extlen_t len, - bool unwritten, - struct xfs_owner_info *oinfo) -{ - struct xfs_mount *mp = cur->bc_mp; - struct xfs_rmap_irec ltrec; - uint64_t ltoff; - int error = 0; - int i; - uint64_t owner; - uint64_t offset; - unsigned int flags; - - xfs_owner_info_unpack(oinfo, &owner, &offset, &flags); - if (unwritten) - flags |= XFS_RMAP_UNWRITTEN; - trace_xfs_rmap_unmap(mp, cur->bc_private.a.agno, bno, len, - unwritten, oinfo); - - /* - * We should always have a left record because there's a static record - * for the AG headers at rm_startblock == 0 created by mkfs/growfs that - * will not ever be removed from the tree. - */ - error = xfs_rmap_lookup_le_range(cur, bno, owner, offset, flags, - <rec, &i); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); - ltoff = ltrec.rm_offset; - - /* Make sure the extent we found covers the entire freeing range. */ - XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_startblock <= bno && - ltrec.rm_startblock + ltrec.rm_blockcount >= - bno + len, out_error); - - /* Make sure the owner matches what we expect to find in the tree. */ - XFS_WANT_CORRUPTED_GOTO(mp, owner == ltrec.rm_owner, out_error); - - /* Make sure the unwritten flag matches. */ - XFS_WANT_CORRUPTED_GOTO(mp, (flags & XFS_RMAP_UNWRITTEN) == - (ltrec.rm_flags & XFS_RMAP_UNWRITTEN), out_error); - - /* Check the offset. */ - XFS_WANT_CORRUPTED_GOTO(mp, ltrec.rm_offset <= offset, out_error); - XFS_WANT_CORRUPTED_GOTO(mp, offset <= ltoff + ltrec.rm_blockcount, - out_error); - - if (ltrec.rm_startblock == bno && ltrec.rm_blockcount == len) { - /* Exact match, simply remove the record from rmap tree. */ - error = xfs_rmap_delete(cur, ltrec.rm_startblock, - ltrec.rm_blockcount, ltrec.rm_owner, - ltrec.rm_offset, ltrec.rm_flags); - if (error) - goto out_error; - } else if (ltrec.rm_startblock == bno) { - /* - * Overlap left hand side of extent: move the start, trim the - * length and update the current record. - * - * ltbno ltlen - * Orig: |oooooooooooooooooooo| - * Freeing: |fffffffff| - * Result: |rrrrrrrrrr| - * bno len - */ - - /* Delete prev rmap. */ - error = xfs_rmap_delete(cur, ltrec.rm_startblock, - ltrec.rm_blockcount, ltrec.rm_owner, - ltrec.rm_offset, ltrec.rm_flags); - if (error) - goto out_error; - - /* Add an rmap at the new offset. */ - ltrec.rm_startblock += len; - ltrec.rm_blockcount -= len; - ltrec.rm_offset += len; - error = xfs_rmap_insert(cur, ltrec.rm_startblock, - ltrec.rm_blockcount, ltrec.rm_owner, - ltrec.rm_offset, ltrec.rm_flags); - if (error) - goto out_error; - } else if (ltrec.rm_startblock + ltrec.rm_blockcount == bno + len) { - /* - * Overlap right hand side of extent: trim the length and - * update the current record. - * - * ltbno ltlen - * Orig: |oooooooooooooooooooo| - * Freeing: |fffffffff| - * Result: |rrrrrrrrrr| - * bno len - */ - error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock, - ltrec.rm_blockcount, ltrec.rm_owner, - ltrec.rm_offset, ltrec.rm_flags, &i); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); - ltrec.rm_blockcount -= len; - error = xfs_rmap_update(cur, <rec); - if (error) - goto out_error; - } else { - /* - * Overlap middle of extent: trim the length of the existing - * record to the length of the new left-extent size, increment - * the insertion position so we can insert a new record - * containing the remaining right-extent space. - * - * ltbno ltlen - * Orig: |oooooooooooooooooooo| - * Freeing: |fffffffff| - * Result: |rrrrr| |rrrr| - * bno len - */ - xfs_extlen_t orig_len = ltrec.rm_blockcount; - - /* Shrink the left side of the rmap */ - error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock, - ltrec.rm_blockcount, ltrec.rm_owner, - ltrec.rm_offset, ltrec.rm_flags, &i); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); - ltrec.rm_blockcount = bno - ltrec.rm_startblock; - error = xfs_rmap_update(cur, <rec); - if (error) - goto out_error; - - /* Add an rmap at the new offset */ - error = xfs_rmap_insert(cur, bno + len, - orig_len - len - ltrec.rm_blockcount, - ltrec.rm_owner, offset + len, - ltrec.rm_flags); - if (error) - goto out_error; - } - - trace_xfs_rmap_unmap_done(mp, cur->bc_private.a.agno, bno, len, - unwritten, oinfo); -out_error: - if (error) - trace_xfs_rmap_unmap_error(cur->bc_mp, - cur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -/* - * Find an extent in the rmap btree and map it. For rmap extent types that - * can overlap (data fork rmaps on reflink filesystems) we must be careful - * that the prev/next records in the btree might belong to another owner. - * Therefore we must use delete+insert to alter any of the key fields. - * - * For every other situation there can only be one owner for a given extent, - * so we can call the regular _alloc function. - */ -STATIC int -xfs_rmap_map_shared( - struct xfs_btree_cur *cur, - xfs_agblock_t bno, - xfs_extlen_t len, - bool unwritten, - struct xfs_owner_info *oinfo) -{ - struct xfs_mount *mp = cur->bc_mp; - struct xfs_rmap_irec ltrec; - struct xfs_rmap_irec gtrec; - int have_gt; - int have_lt; - int error = 0; - int i; - uint64_t owner; - uint64_t offset; - unsigned int flags = 0; - - xfs_owner_info_unpack(oinfo, &owner, &offset, &flags); - if (unwritten) - flags |= XFS_RMAP_UNWRITTEN; - trace_xfs_rmap_map(mp, cur->bc_private.a.agno, bno, len, - unwritten, oinfo); - - /* Is there a left record that abuts our range? */ - error = xfs_rmap_find_left_neighbor(cur, bno, owner, offset, flags, - <rec, &have_lt); - if (error) - goto out_error; - if (have_lt && - !xfs_rmap_is_mergeable(<rec, owner, flags)) - have_lt = 0; - - /* Is there a right record that abuts our range? */ - error = xfs_rmap_lookup_eq(cur, bno + len, len, owner, offset + len, - flags, &have_gt); - if (error) - goto out_error; - if (have_gt) { - error = xfs_rmap_get_rec(cur, >rec, &have_gt); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(mp, have_gt == 1, out_error); - trace_xfs_rmap_find_right_neighbor_result(cur->bc_mp, - cur->bc_private.a.agno, gtrec.rm_startblock, - gtrec.rm_blockcount, gtrec.rm_owner, - gtrec.rm_offset, gtrec.rm_flags); - - if (!xfs_rmap_is_mergeable(>rec, owner, flags)) - have_gt = 0; - } - - if (have_lt && - ltrec.rm_startblock + ltrec.rm_blockcount == bno && - ltrec.rm_offset + ltrec.rm_blockcount == offset) { - /* - * Left edge contiguous, merge into left record. - * - * ltbno ltlen - * orig: |ooooooooo| - * adding: |aaaaaaaaa| - * result: |rrrrrrrrrrrrrrrrrrr| - * bno len - */ - ltrec.rm_blockcount += len; - if (have_gt && - bno + len == gtrec.rm_startblock && - offset + len == gtrec.rm_offset) { - /* - * Right edge also contiguous, delete right record - * and merge into left record. - * - * ltbno ltlen gtbno gtlen - * orig: |ooooooooo| |ooooooooo| - * adding: |aaaaaaaaa| - * result: |rrrrrrrrrrrrrrrrrrrrrrrrrrrrr| - */ - ltrec.rm_blockcount += gtrec.rm_blockcount; - error = xfs_rmap_delete(cur, gtrec.rm_startblock, - gtrec.rm_blockcount, gtrec.rm_owner, - gtrec.rm_offset, gtrec.rm_flags); - if (error) - goto out_error; - } - - /* Point the cursor back to the left record and update. */ - error = xfs_rmap_lookup_eq(cur, ltrec.rm_startblock, - ltrec.rm_blockcount, ltrec.rm_owner, - ltrec.rm_offset, ltrec.rm_flags, &i); - if (error) - goto out_error; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_error); - - error = xfs_rmap_update(cur, <rec); - if (error) - goto out_error; - } else if (have_gt && - bno + len == gtrec.rm_startblock && - offset + len == gtrec.rm_offset) { - /* - * Right edge contiguous, merge into right record. - * - * gtbno gtlen - * Orig: |ooooooooo| - * adding: |aaaaaaaaa| - * Result: |rrrrrrrrrrrrrrrrrrr| - * bno len - */ - /* Delete the old record. */ - error = xfs_rmap_delete(cur, gtrec.rm_startblock, - gtrec.rm_blockcount, gtrec.rm_owner, - gtrec.rm_offset, gtrec.rm_flags); - if (error) - goto out_error; - - /* Move the start and re-add it. */ - gtrec.rm_startblock = bno; - gtrec.rm_blockcount += len; - gtrec.rm_offset = offset; - error = xfs_rmap_insert(cur, gtrec.rm_startblock, - gtrec.rm_blockcount, gtrec.rm_owner, - gtrec.rm_offset, gtrec.rm_flags); - if (error) - goto out_error; - } else { - /* - * No contiguous edge with identical owner, insert - * new record at current cursor position. - */ - error = xfs_rmap_insert(cur, bno, len, owner, offset, flags); - if (error) - goto out_error; - } - - trace_xfs_rmap_map_done(mp, cur->bc_private.a.agno, bno, len, - unwritten, oinfo); -out_error: - if (error) - trace_xfs_rmap_map_error(cur->bc_mp, - cur->bc_private.a.agno, error, _RET_IP_); - return error; -} - -struct xfs_rmap_query_range_info { - xfs_rmap_query_range_fn fn; - void *priv; -}; - -/* Format btree record and pass to our callback. */ -STATIC int -xfs_rmap_query_range_helper( - struct xfs_btree_cur *cur, - union xfs_btree_rec *rec, - void *priv) -{ - struct xfs_rmap_query_range_info *query = priv; - struct xfs_rmap_irec irec; - int error; - - error = xfs_rmap_btrec_to_irec(rec, &irec); - if (error) - return error; - return query->fn(cur, &irec, query->priv); -} - -/* Find all rmaps between two keys. */ -int -xfs_rmap_query_range( - struct xfs_btree_cur *cur, - struct xfs_rmap_irec *low_rec, - struct xfs_rmap_irec *high_rec, - xfs_rmap_query_range_fn fn, - void *priv) -{ - union xfs_btree_irec low_brec; - union xfs_btree_irec high_brec; - struct xfs_rmap_query_range_info query; - - low_brec.r = *low_rec; - high_brec.r = *high_rec; - query.priv = priv; - query.fn = fn; - return xfs_btree_query_range(cur, &low_brec, &high_brec, - xfs_rmap_query_range_helper, &query); -} - -/* Clean up after calling xfs_rmap_finish_one. */ -void -xfs_rmap_finish_one_cleanup( - struct xfs_trans *tp, - struct xfs_btree_cur *rcur, - int error) -{ - struct xfs_buf *agbp; - - if (rcur == NULL) - return; - agbp = rcur->bc_private.a.agbp; - xfs_btree_del_cursor(rcur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); - if (error) - xfs_trans_brelse(tp, agbp); -} - -/* - * Process one of the deferred rmap operations. We pass back the - * btree cursor to maintain our lock on the rmapbt between calls. - * This saves time and eliminates a buffer deadlock between the - * superblock and the AGF because we'll always grab them in the same - * order. - */ -int -xfs_rmap_finish_one( - struct xfs_trans *tp, - enum xfs_rmap_intent_type type, - __uint64_t owner, - int whichfork, - xfs_fileoff_t startoff, - xfs_fsblock_t startblock, - xfs_filblks_t blockcount, - xfs_exntst_t state, - struct xfs_btree_cur **pcur) -{ - struct xfs_mount *mp = tp->t_mountp; - struct xfs_btree_cur *rcur; - struct xfs_buf *agbp = NULL; - int error = 0; - xfs_agnumber_t agno; - struct xfs_owner_info oinfo; - xfs_agblock_t bno; - bool unwritten; - - agno = XFS_FSB_TO_AGNO(mp, startblock); - ASSERT(agno != NULLAGNUMBER); - bno = XFS_FSB_TO_AGBNO(mp, startblock); - - trace_xfs_rmap_deferred(mp, agno, type, bno, owner, whichfork, - startoff, blockcount, state); - - if (XFS_TEST_ERROR(false, mp, - XFS_ERRTAG_RMAP_FINISH_ONE, - XFS_RANDOM_RMAP_FINISH_ONE)) - return -EIO; - - /* - * If we haven't gotten a cursor or the cursor AG doesn't match - * the startblock, get one now. - */ - rcur = *pcur; - if (rcur != NULL && rcur->bc_private.a.agno != agno) { - xfs_rmap_finish_one_cleanup(tp, rcur, 0); - rcur = NULL; - *pcur = NULL; - } - if (rcur == NULL) { - /* - * Refresh the freelist before we start changing the - * rmapbt, because a shape change could cause us to - * allocate blocks. - */ - error = xfs_free_extent_fix_freelist(tp, agno, &agbp); - if (error) - return error; - if (!agbp) - return -EFSCORRUPTED; - - rcur = xfs_rmapbt_init_cursor(mp, tp, agbp, agno); - if (!rcur) { - error = -ENOMEM; - goto out_cur; - } - } - *pcur = rcur; - - xfs_rmap_ino_owner(&oinfo, owner, whichfork, startoff); - unwritten = state == XFS_EXT_UNWRITTEN; - bno = XFS_FSB_TO_AGBNO(rcur->bc_mp, startblock); - - switch (type) { - case XFS_RMAP_ALLOC: - case XFS_RMAP_MAP: - error = xfs_rmap_map(rcur, bno, blockcount, unwritten, &oinfo); - break; - case XFS_RMAP_MAP_SHARED: - error = xfs_rmap_map_shared(rcur, bno, blockcount, unwritten, - &oinfo); - break; - case XFS_RMAP_FREE: - case XFS_RMAP_UNMAP: - error = xfs_rmap_unmap(rcur, bno, blockcount, unwritten, - &oinfo); - break; - case XFS_RMAP_UNMAP_SHARED: - error = xfs_rmap_unmap_shared(rcur, bno, blockcount, unwritten, - &oinfo); - break; - case XFS_RMAP_CONVERT: - error = xfs_rmap_convert(rcur, bno, blockcount, !unwritten, - &oinfo); - break; - case XFS_RMAP_CONVERT_SHARED: - error = xfs_rmap_convert_shared(rcur, bno, blockcount, - !unwritten, &oinfo); - break; - default: - ASSERT(0); - error = -EFSCORRUPTED; - } - return error; - -out_cur: - xfs_trans_brelse(tp, agbp); - - return error; -} - -/* - * Don't defer an rmap if we aren't an rmap filesystem. - */ -static bool -xfs_rmap_update_is_needed( - struct xfs_mount *mp, - int whichfork) -{ - return xfs_sb_version_hasrmapbt(&mp->m_sb) && whichfork != XFS_COW_FORK; -} - -/* - * Record a rmap intent; the list is kept sorted first by AG and then by - * increasing age. - */ -static int -__xfs_rmap_add( - struct xfs_mount *mp, - struct xfs_defer_ops *dfops, - enum xfs_rmap_intent_type type, - __uint64_t owner, - int whichfork, - struct xfs_bmbt_irec *bmap) -{ - struct xfs_rmap_intent *ri; - - trace_xfs_rmap_defer(mp, XFS_FSB_TO_AGNO(mp, bmap->br_startblock), - type, - XFS_FSB_TO_AGBNO(mp, bmap->br_startblock), - owner, whichfork, - bmap->br_startoff, - bmap->br_blockcount, - bmap->br_state); - - ri = kmem_alloc(sizeof(struct xfs_rmap_intent), KM_SLEEP | KM_NOFS); - INIT_LIST_HEAD(&ri->ri_list); - ri->ri_type = type; - ri->ri_owner = owner; - ri->ri_whichfork = whichfork; - ri->ri_bmap = *bmap; - - xfs_defer_add(dfops, XFS_DEFER_OPS_TYPE_RMAP, &ri->ri_list); - return 0; -} - -/* Map an extent into a file. */ -int -xfs_rmap_map_extent( - struct xfs_mount *mp, - struct xfs_defer_ops *dfops, - struct xfs_inode *ip, - int whichfork, - struct xfs_bmbt_irec *PREV) -{ - if (!xfs_rmap_update_is_needed(mp, whichfork)) - return 0; - - return __xfs_rmap_add(mp, dfops, xfs_is_reflink_inode(ip) ? - XFS_RMAP_MAP_SHARED : XFS_RMAP_MAP, ip->i_ino, - whichfork, PREV); -} - -/* Unmap an extent out of a file. */ -int -xfs_rmap_unmap_extent( - struct xfs_mount *mp, - struct xfs_defer_ops *dfops, - struct xfs_inode *ip, - int whichfork, - struct xfs_bmbt_irec *PREV) -{ - if (!xfs_rmap_update_is_needed(mp, whichfork)) - return 0; - - return __xfs_rmap_add(mp, dfops, xfs_is_reflink_inode(ip) ? - XFS_RMAP_UNMAP_SHARED : XFS_RMAP_UNMAP, ip->i_ino, - whichfork, PREV); -} - -/* Convert a data fork extent from unwritten to real or vice versa. */ -int -xfs_rmap_convert_extent( - struct xfs_mount *mp, - struct xfs_defer_ops *dfops, - struct xfs_inode *ip, - int whichfork, - struct xfs_bmbt_irec *PREV) -{ - if (!xfs_rmap_update_is_needed(mp, whichfork)) - return 0; - - return __xfs_rmap_add(mp, dfops, xfs_is_reflink_inode(ip) ? - XFS_RMAP_CONVERT_SHARED : XFS_RMAP_CONVERT, ip->i_ino, - whichfork, PREV); -} - -/* Schedule the creation of an rmap for non-file data. */ -int -xfs_rmap_alloc_extent( - struct xfs_mount *mp, - struct xfs_defer_ops *dfops, - xfs_agnumber_t agno, - xfs_agblock_t bno, - xfs_extlen_t len, - __uint64_t owner) -{ - struct xfs_bmbt_irec bmap; - - if (!xfs_rmap_update_is_needed(mp, XFS_DATA_FORK)) - return 0; - - bmap.br_startblock = XFS_AGB_TO_FSB(mp, agno, bno); - bmap.br_blockcount = len; - bmap.br_startoff = 0; - bmap.br_state = XFS_EXT_NORM; - - return __xfs_rmap_add(mp, dfops, XFS_RMAP_ALLOC, owner, - XFS_DATA_FORK, &bmap); -} - -/* Schedule the deletion of an rmap for non-file data. */ -int -xfs_rmap_free_extent( - struct xfs_mount *mp, - struct xfs_defer_ops *dfops, - xfs_agnumber_t agno, - xfs_agblock_t bno, - xfs_extlen_t len, - __uint64_t owner) -{ - struct xfs_bmbt_irec bmap; - - if (!xfs_rmap_update_is_needed(mp, XFS_DATA_FORK)) - return 0; - - bmap.br_startblock = XFS_AGB_TO_FSB(mp, agno, bno); - bmap.br_blockcount = len; - bmap.br_startoff = 0; - bmap.br_state = XFS_EXT_NORM; - - return __xfs_rmap_add(mp, dfops, XFS_RMAP_FREE, owner, - XFS_DATA_FORK, &bmap); -} diff --git a/src/linux/fs/xfs/libxfs/xfs_rmap.h b/src/linux/fs/xfs/libxfs/xfs_rmap.h deleted file mode 100644 index 7899305..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_rmap.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#ifndef __XFS_RMAP_H__ -#define __XFS_RMAP_H__ - -static inline void -xfs_rmap_ag_owner( - struct xfs_owner_info *oi, - uint64_t owner) -{ - oi->oi_owner = owner; - oi->oi_offset = 0; - oi->oi_flags = 0; -} - -static inline void -xfs_rmap_ino_bmbt_owner( - struct xfs_owner_info *oi, - xfs_ino_t ino, - int whichfork) -{ - oi->oi_owner = ino; - oi->oi_offset = 0; - oi->oi_flags = XFS_OWNER_INFO_BMBT_BLOCK; - if (whichfork == XFS_ATTR_FORK) - oi->oi_flags |= XFS_OWNER_INFO_ATTR_FORK; -} - -static inline void -xfs_rmap_ino_owner( - struct xfs_owner_info *oi, - xfs_ino_t ino, - int whichfork, - xfs_fileoff_t offset) -{ - oi->oi_owner = ino; - oi->oi_offset = offset; - oi->oi_flags = 0; - if (whichfork == XFS_ATTR_FORK) - oi->oi_flags |= XFS_OWNER_INFO_ATTR_FORK; -} - -static inline void -xfs_rmap_skip_owner_update( - struct xfs_owner_info *oi) -{ - oi->oi_owner = XFS_RMAP_OWN_UNKNOWN; -} - -/* Reverse mapping functions. */ - -struct xfs_buf; - -static inline __u64 -xfs_rmap_irec_offset_pack( - const struct xfs_rmap_irec *irec) -{ - __u64 x; - - x = XFS_RMAP_OFF(irec->rm_offset); - if (irec->rm_flags & XFS_RMAP_ATTR_FORK) - x |= XFS_RMAP_OFF_ATTR_FORK; - if (irec->rm_flags & XFS_RMAP_BMBT_BLOCK) - x |= XFS_RMAP_OFF_BMBT_BLOCK; - if (irec->rm_flags & XFS_RMAP_UNWRITTEN) - x |= XFS_RMAP_OFF_UNWRITTEN; - return x; -} - -static inline int -xfs_rmap_irec_offset_unpack( - __u64 offset, - struct xfs_rmap_irec *irec) -{ - if (offset & ~(XFS_RMAP_OFF_MASK | XFS_RMAP_OFF_FLAGS)) - return -EFSCORRUPTED; - irec->rm_offset = XFS_RMAP_OFF(offset); - if (offset & XFS_RMAP_OFF_ATTR_FORK) - irec->rm_flags |= XFS_RMAP_ATTR_FORK; - if (offset & XFS_RMAP_OFF_BMBT_BLOCK) - irec->rm_flags |= XFS_RMAP_BMBT_BLOCK; - if (offset & XFS_RMAP_OFF_UNWRITTEN) - irec->rm_flags |= XFS_RMAP_UNWRITTEN; - return 0; -} - -static inline void -xfs_owner_info_unpack( - struct xfs_owner_info *oinfo, - uint64_t *owner, - uint64_t *offset, - unsigned int *flags) -{ - unsigned int r = 0; - - *owner = oinfo->oi_owner; - *offset = oinfo->oi_offset; - if (oinfo->oi_flags & XFS_OWNER_INFO_ATTR_FORK) - r |= XFS_RMAP_ATTR_FORK; - if (oinfo->oi_flags & XFS_OWNER_INFO_BMBT_BLOCK) - r |= XFS_RMAP_BMBT_BLOCK; - *flags = r; -} - -static inline void -xfs_owner_info_pack( - struct xfs_owner_info *oinfo, - uint64_t owner, - uint64_t offset, - unsigned int flags) -{ - oinfo->oi_owner = owner; - oinfo->oi_offset = XFS_RMAP_OFF(offset); - oinfo->oi_flags = 0; - if (flags & XFS_RMAP_ATTR_FORK) - oinfo->oi_flags |= XFS_OWNER_INFO_ATTR_FORK; - if (flags & XFS_RMAP_BMBT_BLOCK) - oinfo->oi_flags |= XFS_OWNER_INFO_BMBT_BLOCK; -} - -int xfs_rmap_alloc(struct xfs_trans *tp, struct xfs_buf *agbp, - xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, - struct xfs_owner_info *oinfo); -int xfs_rmap_free(struct xfs_trans *tp, struct xfs_buf *agbp, - xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, - struct xfs_owner_info *oinfo); - -int xfs_rmap_lookup_le(struct xfs_btree_cur *cur, xfs_agblock_t bno, - xfs_extlen_t len, uint64_t owner, uint64_t offset, - unsigned int flags, int *stat); -int xfs_rmap_lookup_eq(struct xfs_btree_cur *cur, xfs_agblock_t bno, - xfs_extlen_t len, uint64_t owner, uint64_t offset, - unsigned int flags, int *stat); -int xfs_rmap_insert(struct xfs_btree_cur *rcur, xfs_agblock_t agbno, - xfs_extlen_t len, uint64_t owner, uint64_t offset, - unsigned int flags); -int xfs_rmap_get_rec(struct xfs_btree_cur *cur, struct xfs_rmap_irec *irec, - int *stat); - -typedef int (*xfs_rmap_query_range_fn)( - struct xfs_btree_cur *cur, - struct xfs_rmap_irec *rec, - void *priv); - -int xfs_rmap_query_range(struct xfs_btree_cur *cur, - struct xfs_rmap_irec *low_rec, struct xfs_rmap_irec *high_rec, - xfs_rmap_query_range_fn fn, void *priv); - -enum xfs_rmap_intent_type { - XFS_RMAP_MAP, - XFS_RMAP_MAP_SHARED, - XFS_RMAP_UNMAP, - XFS_RMAP_UNMAP_SHARED, - XFS_RMAP_CONVERT, - XFS_RMAP_CONVERT_SHARED, - XFS_RMAP_ALLOC, - XFS_RMAP_FREE, -}; - -struct xfs_rmap_intent { - struct list_head ri_list; - enum xfs_rmap_intent_type ri_type; - __uint64_t ri_owner; - int ri_whichfork; - struct xfs_bmbt_irec ri_bmap; -}; - -/* functions for updating the rmapbt based on bmbt map/unmap operations */ -int xfs_rmap_map_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops, - struct xfs_inode *ip, int whichfork, - struct xfs_bmbt_irec *imap); -int xfs_rmap_unmap_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops, - struct xfs_inode *ip, int whichfork, - struct xfs_bmbt_irec *imap); -int xfs_rmap_convert_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops, - struct xfs_inode *ip, int whichfork, - struct xfs_bmbt_irec *imap); -int xfs_rmap_alloc_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops, - xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, - __uint64_t owner); -int xfs_rmap_free_extent(struct xfs_mount *mp, struct xfs_defer_ops *dfops, - xfs_agnumber_t agno, xfs_agblock_t bno, xfs_extlen_t len, - __uint64_t owner); - -void xfs_rmap_finish_one_cleanup(struct xfs_trans *tp, - struct xfs_btree_cur *rcur, int error); -int xfs_rmap_finish_one(struct xfs_trans *tp, enum xfs_rmap_intent_type type, - __uint64_t owner, int whichfork, xfs_fileoff_t startoff, - xfs_fsblock_t startblock, xfs_filblks_t blockcount, - xfs_exntst_t state, struct xfs_btree_cur **pcur); - -int xfs_rmap_find_left_neighbor(struct xfs_btree_cur *cur, xfs_agblock_t bno, - uint64_t owner, uint64_t offset, unsigned int flags, - struct xfs_rmap_irec *irec, int *stat); -int xfs_rmap_lookup_le_range(struct xfs_btree_cur *cur, xfs_agblock_t bno, - uint64_t owner, uint64_t offset, unsigned int flags, - struct xfs_rmap_irec *irec, int *stat); - -#endif /* __XFS_RMAP_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_rmap_btree.c b/src/linux/fs/xfs/libxfs/xfs_rmap_btree.c deleted file mode 100644 index 83e672f..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_rmap_btree.c +++ /dev/null @@ -1,595 +0,0 @@ -/* - * Copyright (c) 2014 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_alloc.h" -#include "xfs_btree.h" -#include "xfs_rmap.h" -#include "xfs_rmap_btree.h" -#include "xfs_trace.h" -#include "xfs_cksum.h" -#include "xfs_error.h" -#include "xfs_extent_busy.h" -#include "xfs_ag_resv.h" - -/* - * Reverse map btree. - * - * This is a per-ag tree used to track the owner(s) of a given extent. With - * reflink it is possible for there to be multiple owners, which is a departure - * from classic XFS. Owner records for data extents are inserted when the - * extent is mapped and removed when an extent is unmapped. Owner records for - * all other block types (i.e. metadata) are inserted when an extent is - * allocated and removed when an extent is freed. There can only be one owner - * of a metadata extent, usually an inode or some other metadata structure like - * an AG btree. - * - * The rmap btree is part of the free space management, so blocks for the tree - * are sourced from the agfl. Hence we need transaction reservation support for - * this tree so that the freelist is always large enough. This also impacts on - * the minimum space we need to leave free in the AG. - * - * The tree is ordered by [ag block, owner, offset]. This is a large key size, - * but it is the only way to enforce unique keys when a block can be owned by - * multiple files at any offset. There's no need to order/search by extent - * size for online updating/management of the tree. It is intended that most - * reverse lookups will be to find the owner(s) of a particular block, or to - * try to recover tree and file data from corrupt primary metadata. - */ - -static struct xfs_btree_cur * -xfs_rmapbt_dup_cursor( - struct xfs_btree_cur *cur) -{ - return xfs_rmapbt_init_cursor(cur->bc_mp, cur->bc_tp, - cur->bc_private.a.agbp, cur->bc_private.a.agno); -} - -STATIC void -xfs_rmapbt_set_root( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *ptr, - int inc) -{ - struct xfs_buf *agbp = cur->bc_private.a.agbp; - struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); - xfs_agnumber_t seqno = be32_to_cpu(agf->agf_seqno); - int btnum = cur->bc_btnum; - struct xfs_perag *pag = xfs_perag_get(cur->bc_mp, seqno); - - ASSERT(ptr->s != 0); - - agf->agf_roots[btnum] = ptr->s; - be32_add_cpu(&agf->agf_levels[btnum], inc); - pag->pagf_levels[btnum] += inc; - xfs_perag_put(pag); - - xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_ROOTS | XFS_AGF_LEVELS); -} - -STATIC int -xfs_rmapbt_alloc_block( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *start, - union xfs_btree_ptr *new, - int *stat) -{ - struct xfs_buf *agbp = cur->bc_private.a.agbp; - struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); - int error; - xfs_agblock_t bno; - - XFS_BTREE_TRACE_CURSOR(cur, XBT_ENTRY); - - /* Allocate the new block from the freelist. If we can't, give up. */ - error = xfs_alloc_get_freelist(cur->bc_tp, cur->bc_private.a.agbp, - &bno, 1); - if (error) { - XFS_BTREE_TRACE_CURSOR(cur, XBT_ERROR); - return error; - } - - trace_xfs_rmapbt_alloc_block(cur->bc_mp, cur->bc_private.a.agno, - bno, 1); - if (bno == NULLAGBLOCK) { - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 0; - return 0; - } - - xfs_extent_busy_reuse(cur->bc_mp, cur->bc_private.a.agno, bno, 1, - false); - - xfs_trans_agbtree_delta(cur->bc_tp, 1); - new->s = cpu_to_be32(bno); - be32_add_cpu(&agf->agf_rmap_blocks, 1); - xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS); - - XFS_BTREE_TRACE_CURSOR(cur, XBT_EXIT); - *stat = 1; - return 0; -} - -STATIC int -xfs_rmapbt_free_block( - struct xfs_btree_cur *cur, - struct xfs_buf *bp) -{ - struct xfs_buf *agbp = cur->bc_private.a.agbp; - struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); - xfs_agblock_t bno; - int error; - - bno = xfs_daddr_to_agbno(cur->bc_mp, XFS_BUF_ADDR(bp)); - trace_xfs_rmapbt_free_block(cur->bc_mp, cur->bc_private.a.agno, - bno, 1); - be32_add_cpu(&agf->agf_rmap_blocks, -1); - xfs_alloc_log_agf(cur->bc_tp, agbp, XFS_AGF_RMAP_BLOCKS); - error = xfs_alloc_put_freelist(cur->bc_tp, agbp, NULL, bno, 1); - if (error) - return error; - - xfs_extent_busy_insert(cur->bc_tp, be32_to_cpu(agf->agf_seqno), bno, 1, - XFS_EXTENT_BUSY_SKIP_DISCARD); - xfs_trans_agbtree_delta(cur->bc_tp, -1); - - return 0; -} - -STATIC int -xfs_rmapbt_get_minrecs( - struct xfs_btree_cur *cur, - int level) -{ - return cur->bc_mp->m_rmap_mnr[level != 0]; -} - -STATIC int -xfs_rmapbt_get_maxrecs( - struct xfs_btree_cur *cur, - int level) -{ - return cur->bc_mp->m_rmap_mxr[level != 0]; -} - -STATIC void -xfs_rmapbt_init_key_from_rec( - union xfs_btree_key *key, - union xfs_btree_rec *rec) -{ - key->rmap.rm_startblock = rec->rmap.rm_startblock; - key->rmap.rm_owner = rec->rmap.rm_owner; - key->rmap.rm_offset = rec->rmap.rm_offset; -} - -/* - * The high key for a reverse mapping record can be computed by shifting - * the startblock and offset to the highest value that would still map - * to that record. In practice this means that we add blockcount-1 to - * the startblock for all records, and if the record is for a data/attr - * fork mapping, we add blockcount-1 to the offset too. - */ -STATIC void -xfs_rmapbt_init_high_key_from_rec( - union xfs_btree_key *key, - union xfs_btree_rec *rec) -{ - __uint64_t off; - int adj; - - adj = be32_to_cpu(rec->rmap.rm_blockcount) - 1; - - key->rmap.rm_startblock = rec->rmap.rm_startblock; - be32_add_cpu(&key->rmap.rm_startblock, adj); - key->rmap.rm_owner = rec->rmap.rm_owner; - key->rmap.rm_offset = rec->rmap.rm_offset; - if (XFS_RMAP_NON_INODE_OWNER(be64_to_cpu(rec->rmap.rm_owner)) || - XFS_RMAP_IS_BMBT_BLOCK(be64_to_cpu(rec->rmap.rm_offset))) - return; - off = be64_to_cpu(key->rmap.rm_offset); - off = (XFS_RMAP_OFF(off) + adj) | (off & ~XFS_RMAP_OFF_MASK); - key->rmap.rm_offset = cpu_to_be64(off); -} - -STATIC void -xfs_rmapbt_init_rec_from_cur( - struct xfs_btree_cur *cur, - union xfs_btree_rec *rec) -{ - rec->rmap.rm_startblock = cpu_to_be32(cur->bc_rec.r.rm_startblock); - rec->rmap.rm_blockcount = cpu_to_be32(cur->bc_rec.r.rm_blockcount); - rec->rmap.rm_owner = cpu_to_be64(cur->bc_rec.r.rm_owner); - rec->rmap.rm_offset = cpu_to_be64( - xfs_rmap_irec_offset_pack(&cur->bc_rec.r)); -} - -STATIC void -xfs_rmapbt_init_ptr_from_cur( - struct xfs_btree_cur *cur, - union xfs_btree_ptr *ptr) -{ - struct xfs_agf *agf = XFS_BUF_TO_AGF(cur->bc_private.a.agbp); - - ASSERT(cur->bc_private.a.agno == be32_to_cpu(agf->agf_seqno)); - ASSERT(agf->agf_roots[cur->bc_btnum] != 0); - - ptr->s = agf->agf_roots[cur->bc_btnum]; -} - -STATIC __int64_t -xfs_rmapbt_key_diff( - struct xfs_btree_cur *cur, - union xfs_btree_key *key) -{ - struct xfs_rmap_irec *rec = &cur->bc_rec.r; - struct xfs_rmap_key *kp = &key->rmap; - __u64 x, y; - __int64_t d; - - d = (__int64_t)be32_to_cpu(kp->rm_startblock) - rec->rm_startblock; - if (d) - return d; - - x = be64_to_cpu(kp->rm_owner); - y = rec->rm_owner; - if (x > y) - return 1; - else if (y > x) - return -1; - - x = XFS_RMAP_OFF(be64_to_cpu(kp->rm_offset)); - y = rec->rm_offset; - if (x > y) - return 1; - else if (y > x) - return -1; - return 0; -} - -STATIC __int64_t -xfs_rmapbt_diff_two_keys( - struct xfs_btree_cur *cur, - union xfs_btree_key *k1, - union xfs_btree_key *k2) -{ - struct xfs_rmap_key *kp1 = &k1->rmap; - struct xfs_rmap_key *kp2 = &k2->rmap; - __int64_t d; - __u64 x, y; - - d = (__int64_t)be32_to_cpu(kp1->rm_startblock) - - be32_to_cpu(kp2->rm_startblock); - if (d) - return d; - - x = be64_to_cpu(kp1->rm_owner); - y = be64_to_cpu(kp2->rm_owner); - if (x > y) - return 1; - else if (y > x) - return -1; - - x = XFS_RMAP_OFF(be64_to_cpu(kp1->rm_offset)); - y = XFS_RMAP_OFF(be64_to_cpu(kp2->rm_offset)); - if (x > y) - return 1; - else if (y > x) - return -1; - return 0; -} - -static bool -xfs_rmapbt_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_btree_block *block = XFS_BUF_TO_BLOCK(bp); - struct xfs_perag *pag = bp->b_pag; - unsigned int level; - - /* - * magic number and level verification - * - * During growfs operations, we can't verify the exact level or owner as - * the perag is not fully initialised and hence not attached to the - * buffer. In this case, check against the maximum tree depth. - * - * Similarly, during log recovery we will have a perag structure - * attached, but the agf information will not yet have been initialised - * from the on disk AGF. Again, we can only check against maximum limits - * in this case. - */ - if (block->bb_magic != cpu_to_be32(XFS_RMAP_CRC_MAGIC)) - return false; - - if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) - return false; - if (!xfs_btree_sblock_v5hdr_verify(bp)) - return false; - - level = be16_to_cpu(block->bb_level); - if (pag && pag->pagf_init) { - if (level >= pag->pagf_levels[XFS_BTNUM_RMAPi]) - return false; - } else if (level >= mp->m_rmap_maxlevels) - return false; - - return xfs_btree_sblock_verify(bp, mp->m_rmap_mxr[level != 0]); -} - -static void -xfs_rmapbt_read_verify( - struct xfs_buf *bp) -{ - if (!xfs_btree_sblock_verify_crc(bp)) - xfs_buf_ioerror(bp, -EFSBADCRC); - else if (!xfs_rmapbt_verify(bp)) - xfs_buf_ioerror(bp, -EFSCORRUPTED); - - if (bp->b_error) { - trace_xfs_btree_corrupt(bp, _RET_IP_); - xfs_verifier_error(bp); - } -} - -static void -xfs_rmapbt_write_verify( - struct xfs_buf *bp) -{ - if (!xfs_rmapbt_verify(bp)) { - trace_xfs_btree_corrupt(bp, _RET_IP_); - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - return; - } - xfs_btree_sblock_calc_crc(bp); - -} - -const struct xfs_buf_ops xfs_rmapbt_buf_ops = { - .name = "xfs_rmapbt", - .verify_read = xfs_rmapbt_read_verify, - .verify_write = xfs_rmapbt_write_verify, -}; - -#if defined(DEBUG) || defined(XFS_WARN) -STATIC int -xfs_rmapbt_keys_inorder( - struct xfs_btree_cur *cur, - union xfs_btree_key *k1, - union xfs_btree_key *k2) -{ - __uint32_t x; - __uint32_t y; - __uint64_t a; - __uint64_t b; - - x = be32_to_cpu(k1->rmap.rm_startblock); - y = be32_to_cpu(k2->rmap.rm_startblock); - if (x < y) - return 1; - else if (x > y) - return 0; - a = be64_to_cpu(k1->rmap.rm_owner); - b = be64_to_cpu(k2->rmap.rm_owner); - if (a < b) - return 1; - else if (a > b) - return 0; - a = XFS_RMAP_OFF(be64_to_cpu(k1->rmap.rm_offset)); - b = XFS_RMAP_OFF(be64_to_cpu(k2->rmap.rm_offset)); - if (a <= b) - return 1; - return 0; -} - -STATIC int -xfs_rmapbt_recs_inorder( - struct xfs_btree_cur *cur, - union xfs_btree_rec *r1, - union xfs_btree_rec *r2) -{ - __uint32_t x; - __uint32_t y; - __uint64_t a; - __uint64_t b; - - x = be32_to_cpu(r1->rmap.rm_startblock); - y = be32_to_cpu(r2->rmap.rm_startblock); - if (x < y) - return 1; - else if (x > y) - return 0; - a = be64_to_cpu(r1->rmap.rm_owner); - b = be64_to_cpu(r2->rmap.rm_owner); - if (a < b) - return 1; - else if (a > b) - return 0; - a = XFS_RMAP_OFF(be64_to_cpu(r1->rmap.rm_offset)); - b = XFS_RMAP_OFF(be64_to_cpu(r2->rmap.rm_offset)); - if (a <= b) - return 1; - return 0; -} -#endif /* DEBUG */ - -static const struct xfs_btree_ops xfs_rmapbt_ops = { - .rec_len = sizeof(struct xfs_rmap_rec), - .key_len = 2 * sizeof(struct xfs_rmap_key), - - .dup_cursor = xfs_rmapbt_dup_cursor, - .set_root = xfs_rmapbt_set_root, - .alloc_block = xfs_rmapbt_alloc_block, - .free_block = xfs_rmapbt_free_block, - .get_minrecs = xfs_rmapbt_get_minrecs, - .get_maxrecs = xfs_rmapbt_get_maxrecs, - .init_key_from_rec = xfs_rmapbt_init_key_from_rec, - .init_high_key_from_rec = xfs_rmapbt_init_high_key_from_rec, - .init_rec_from_cur = xfs_rmapbt_init_rec_from_cur, - .init_ptr_from_cur = xfs_rmapbt_init_ptr_from_cur, - .key_diff = xfs_rmapbt_key_diff, - .buf_ops = &xfs_rmapbt_buf_ops, - .diff_two_keys = xfs_rmapbt_diff_two_keys, -#if defined(DEBUG) || defined(XFS_WARN) - .keys_inorder = xfs_rmapbt_keys_inorder, - .recs_inorder = xfs_rmapbt_recs_inorder, -#endif -}; - -/* - * Allocate a new allocation btree cursor. - */ -struct xfs_btree_cur * -xfs_rmapbt_init_cursor( - struct xfs_mount *mp, - struct xfs_trans *tp, - struct xfs_buf *agbp, - xfs_agnumber_t agno) -{ - struct xfs_agf *agf = XFS_BUF_TO_AGF(agbp); - struct xfs_btree_cur *cur; - - cur = kmem_zone_zalloc(xfs_btree_cur_zone, KM_NOFS); - cur->bc_tp = tp; - cur->bc_mp = mp; - /* Overlapping btree; 2 keys per pointer. */ - cur->bc_btnum = XFS_BTNUM_RMAP; - cur->bc_flags = XFS_BTREE_CRC_BLOCKS | XFS_BTREE_OVERLAPPING; - cur->bc_blocklog = mp->m_sb.sb_blocklog; - cur->bc_ops = &xfs_rmapbt_ops; - cur->bc_nlevels = be32_to_cpu(agf->agf_levels[XFS_BTNUM_RMAP]); - - cur->bc_private.a.agbp = agbp; - cur->bc_private.a.agno = agno; - - return cur; -} - -/* - * Calculate number of records in an rmap btree block. - */ -int -xfs_rmapbt_maxrecs( - struct xfs_mount *mp, - int blocklen, - int leaf) -{ - blocklen -= XFS_RMAP_BLOCK_LEN; - - if (leaf) - return blocklen / sizeof(struct xfs_rmap_rec); - return blocklen / - (2 * sizeof(struct xfs_rmap_key) + sizeof(xfs_rmap_ptr_t)); -} - -/* Compute the maximum height of an rmap btree. */ -void -xfs_rmapbt_compute_maxlevels( - struct xfs_mount *mp) -{ - /* - * On a non-reflink filesystem, the maximum number of rmap - * records is the number of blocks in the AG, hence the max - * rmapbt height is log_$maxrecs($agblocks). However, with - * reflink each AG block can have up to 2^32 (per the refcount - * record format) owners, which means that theoretically we - * could face up to 2^64 rmap records. - * - * That effectively means that the max rmapbt height must be - * XFS_BTREE_MAXLEVELS. "Fortunately" we'll run out of AG - * blocks to feed the rmapbt long before the rmapbt reaches - * maximum height. The reflink code uses ag_resv_critical to - * disallow reflinking when less than 10% of the per-AG metadata - * block reservation since the fallback is a regular file copy. - */ - if (xfs_sb_version_hasreflink(&mp->m_sb)) - mp->m_rmap_maxlevels = XFS_BTREE_MAXLEVELS; - else - mp->m_rmap_maxlevels = xfs_btree_compute_maxlevels(mp, - mp->m_rmap_mnr, mp->m_sb.sb_agblocks); -} - -/* Calculate the refcount btree size for some records. */ -xfs_extlen_t -xfs_rmapbt_calc_size( - struct xfs_mount *mp, - unsigned long long len) -{ - return xfs_btree_calc_size(mp, mp->m_rmap_mnr, len); -} - -/* - * Calculate the maximum refcount btree size. - */ -xfs_extlen_t -xfs_rmapbt_max_size( - struct xfs_mount *mp) -{ - /* Bail out if we're uninitialized, which can happen in mkfs. */ - if (mp->m_rmap_mxr[0] == 0) - return 0; - - return xfs_rmapbt_calc_size(mp, mp->m_sb.sb_agblocks); -} - -/* - * Figure out how many blocks to reserve and how many are used by this btree. - */ -int -xfs_rmapbt_calc_reserves( - struct xfs_mount *mp, - xfs_agnumber_t agno, - xfs_extlen_t *ask, - xfs_extlen_t *used) -{ - struct xfs_buf *agbp; - struct xfs_agf *agf; - xfs_extlen_t pool_len; - xfs_extlen_t tree_len; - int error; - - if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) - return 0; - - /* Reserve 1% of the AG or enough for 1 block per record. */ - pool_len = max(mp->m_sb.sb_agblocks / 100, xfs_rmapbt_max_size(mp)); - *ask += pool_len; - - error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); - if (error) - return error; - - agf = XFS_BUF_TO_AGF(agbp); - tree_len = be32_to_cpu(agf->agf_rmap_blocks); - xfs_buf_relse(agbp); - - *used += tree_len; - - return error; -} diff --git a/src/linux/fs/xfs/libxfs/xfs_rmap_btree.h b/src/linux/fs/xfs/libxfs/xfs_rmap_btree.h deleted file mode 100644 index 2a9ac47..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_rmap_btree.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2014 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_RMAP_BTREE_H__ -#define __XFS_RMAP_BTREE_H__ - -struct xfs_buf; -struct xfs_btree_cur; -struct xfs_mount; - -/* rmaps only exist on crc enabled filesystems */ -#define XFS_RMAP_BLOCK_LEN XFS_BTREE_SBLOCK_CRC_LEN - -/* - * Record, key, and pointer address macros for btree blocks. - * - * (note that some of these may appear unused, but they are used in userspace) - */ -#define XFS_RMAP_REC_ADDR(block, index) \ - ((struct xfs_rmap_rec *) \ - ((char *)(block) + XFS_RMAP_BLOCK_LEN + \ - (((index) - 1) * sizeof(struct xfs_rmap_rec)))) - -#define XFS_RMAP_KEY_ADDR(block, index) \ - ((struct xfs_rmap_key *) \ - ((char *)(block) + XFS_RMAP_BLOCK_LEN + \ - ((index) - 1) * 2 * sizeof(struct xfs_rmap_key))) - -#define XFS_RMAP_HIGH_KEY_ADDR(block, index) \ - ((struct xfs_rmap_key *) \ - ((char *)(block) + XFS_RMAP_BLOCK_LEN + \ - sizeof(struct xfs_rmap_key) + \ - ((index) - 1) * 2 * sizeof(struct xfs_rmap_key))) - -#define XFS_RMAP_PTR_ADDR(block, index, maxrecs) \ - ((xfs_rmap_ptr_t *) \ - ((char *)(block) + XFS_RMAP_BLOCK_LEN + \ - (maxrecs) * 2 * sizeof(struct xfs_rmap_key) + \ - ((index) - 1) * sizeof(xfs_rmap_ptr_t))) - -struct xfs_btree_cur *xfs_rmapbt_init_cursor(struct xfs_mount *mp, - struct xfs_trans *tp, struct xfs_buf *bp, - xfs_agnumber_t agno); -int xfs_rmapbt_maxrecs(struct xfs_mount *mp, int blocklen, int leaf); -extern void xfs_rmapbt_compute_maxlevels(struct xfs_mount *mp); - -extern xfs_extlen_t xfs_rmapbt_calc_size(struct xfs_mount *mp, - unsigned long long len); -extern xfs_extlen_t xfs_rmapbt_max_size(struct xfs_mount *mp); - -extern int xfs_rmapbt_calc_reserves(struct xfs_mount *mp, - xfs_agnumber_t agno, xfs_extlen_t *ask, xfs_extlen_t *used); - -#endif /* __XFS_RMAP_BTREE_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_sb.c b/src/linux/fs/xfs/libxfs/xfs_sb.c deleted file mode 100644 index a70aec9..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_sb.c +++ /dev/null @@ -1,869 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_inode.h" -#include "xfs_ialloc.h" -#include "xfs_alloc.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_cksum.h" -#include "xfs_trans.h" -#include "xfs_buf_item.h" -#include "xfs_bmap_btree.h" -#include "xfs_alloc_btree.h" -#include "xfs_ialloc_btree.h" -#include "xfs_log.h" -#include "xfs_rmap_btree.h" -#include "xfs_bmap.h" -#include "xfs_refcount_btree.h" - -/* - * Physical superblock buffer manipulations. Shared with libxfs in userspace. - */ - -/* - * Reference counting access wrappers to the perag structures. - * Because we never free per-ag structures, the only thing we - * have to protect against changes is the tree structure itself. - */ -struct xfs_perag * -xfs_perag_get( - struct xfs_mount *mp, - xfs_agnumber_t agno) -{ - struct xfs_perag *pag; - int ref = 0; - - rcu_read_lock(); - pag = radix_tree_lookup(&mp->m_perag_tree, agno); - if (pag) { - ASSERT(atomic_read(&pag->pag_ref) >= 0); - ref = atomic_inc_return(&pag->pag_ref); - } - rcu_read_unlock(); - trace_xfs_perag_get(mp, agno, ref, _RET_IP_); - return pag; -} - -/* - * search from @first to find the next perag with the given tag set. - */ -struct xfs_perag * -xfs_perag_get_tag( - struct xfs_mount *mp, - xfs_agnumber_t first, - int tag) -{ - struct xfs_perag *pag; - int found; - int ref; - - rcu_read_lock(); - found = radix_tree_gang_lookup_tag(&mp->m_perag_tree, - (void **)&pag, first, 1, tag); - if (found <= 0) { - rcu_read_unlock(); - return NULL; - } - ref = atomic_inc_return(&pag->pag_ref); - rcu_read_unlock(); - trace_xfs_perag_get_tag(mp, pag->pag_agno, ref, _RET_IP_); - return pag; -} - -void -xfs_perag_put( - struct xfs_perag *pag) -{ - int ref; - - ASSERT(atomic_read(&pag->pag_ref) > 0); - ref = atomic_dec_return(&pag->pag_ref); - trace_xfs_perag_put(pag->pag_mount, pag->pag_agno, ref, _RET_IP_); -} - -/* - * Check the validity of the SB found. - */ -STATIC int -xfs_mount_validate_sb( - xfs_mount_t *mp, - xfs_sb_t *sbp, - bool check_inprogress, - bool check_version) -{ - if (sbp->sb_magicnum != XFS_SB_MAGIC) { - xfs_warn(mp, "bad magic number"); - return -EWRONGFS; - } - - - if (!xfs_sb_good_version(sbp)) { - xfs_warn(mp, "bad version"); - return -EWRONGFS; - } - - /* - * Version 5 superblock feature mask validation. Reject combinations the - * kernel cannot support up front before checking anything else. For - * write validation, we don't need to check feature masks. - */ - if (check_version && XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5) { - if (xfs_sb_has_compat_feature(sbp, - XFS_SB_FEAT_COMPAT_UNKNOWN)) { - xfs_warn(mp, -"Superblock has unknown compatible features (0x%x) enabled.", - (sbp->sb_features_compat & - XFS_SB_FEAT_COMPAT_UNKNOWN)); - xfs_warn(mp, -"Using a more recent kernel is recommended."); - } - - if (xfs_sb_has_ro_compat_feature(sbp, - XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) { - xfs_alert(mp, -"Superblock has unknown read-only compatible features (0x%x) enabled.", - (sbp->sb_features_ro_compat & - XFS_SB_FEAT_RO_COMPAT_UNKNOWN)); - if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { - xfs_warn(mp, -"Attempted to mount read-only compatible filesystem read-write."); - xfs_warn(mp, -"Filesystem can only be safely mounted read only."); - - return -EINVAL; - } - } - if (xfs_sb_has_incompat_feature(sbp, - XFS_SB_FEAT_INCOMPAT_UNKNOWN)) { - xfs_warn(mp, -"Superblock has unknown incompatible features (0x%x) enabled.", - (sbp->sb_features_incompat & - XFS_SB_FEAT_INCOMPAT_UNKNOWN)); - xfs_warn(mp, -"Filesystem can not be safely mounted by this kernel."); - return -EINVAL; - } - } else if (xfs_sb_version_hascrc(sbp)) { - /* - * We can't read verify the sb LSN because the read verifier is - * called before the log is allocated and processed. We know the - * log is set up before write verifier (!check_version) calls, - * so just check it here. - */ - if (!xfs_log_check_lsn(mp, sbp->sb_lsn)) - return -EFSCORRUPTED; - } - - if (xfs_sb_version_has_pquotino(sbp)) { - if (sbp->sb_qflags & (XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD)) { - xfs_notice(mp, - "Version 5 of Super block has XFS_OQUOTA bits."); - return -EFSCORRUPTED; - } - } else if (sbp->sb_qflags & (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD | - XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) { - xfs_notice(mp, -"Superblock earlier than Version 5 has XFS_[PQ]UOTA_{ENFD|CHKD} bits."); - return -EFSCORRUPTED; - } - - /* - * Full inode chunks must be aligned to inode chunk size when - * sparse inodes are enabled to support the sparse chunk - * allocation algorithm and prevent overlapping inode records. - */ - if (xfs_sb_version_hassparseinodes(sbp)) { - uint32_t align; - - align = XFS_INODES_PER_CHUNK * sbp->sb_inodesize - >> sbp->sb_blocklog; - if (sbp->sb_inoalignmt != align) { - xfs_warn(mp, -"Inode block alignment (%u) must match chunk size (%u) for sparse inodes.", - sbp->sb_inoalignmt, align); - return -EINVAL; - } - } - - if (unlikely( - sbp->sb_logstart == 0 && mp->m_logdev_targp == mp->m_ddev_targp)) { - xfs_warn(mp, - "filesystem is marked as having an external log; " - "specify logdev on the mount command line."); - return -EINVAL; - } - - if (unlikely( - sbp->sb_logstart != 0 && mp->m_logdev_targp != mp->m_ddev_targp)) { - xfs_warn(mp, - "filesystem is marked as having an internal log; " - "do not specify logdev on the mount command line."); - return -EINVAL; - } - - /* - * More sanity checking. Most of these were stolen directly from - * xfs_repair. - */ - if (unlikely( - sbp->sb_agcount <= 0 || - sbp->sb_sectsize < XFS_MIN_SECTORSIZE || - sbp->sb_sectsize > XFS_MAX_SECTORSIZE || - sbp->sb_sectlog < XFS_MIN_SECTORSIZE_LOG || - sbp->sb_sectlog > XFS_MAX_SECTORSIZE_LOG || - sbp->sb_sectsize != (1 << sbp->sb_sectlog) || - sbp->sb_blocksize < XFS_MIN_BLOCKSIZE || - sbp->sb_blocksize > XFS_MAX_BLOCKSIZE || - sbp->sb_blocklog < XFS_MIN_BLOCKSIZE_LOG || - sbp->sb_blocklog > XFS_MAX_BLOCKSIZE_LOG || - sbp->sb_blocksize != (1 << sbp->sb_blocklog) || - sbp->sb_dirblklog > XFS_MAX_BLOCKSIZE_LOG || - sbp->sb_inodesize < XFS_DINODE_MIN_SIZE || - sbp->sb_inodesize > XFS_DINODE_MAX_SIZE || - sbp->sb_inodelog < XFS_DINODE_MIN_LOG || - sbp->sb_inodelog > XFS_DINODE_MAX_LOG || - sbp->sb_inodesize != (1 << sbp->sb_inodelog) || - sbp->sb_logsunit > XLOG_MAX_RECORD_BSIZE || - sbp->sb_inopblock != howmany(sbp->sb_blocksize,sbp->sb_inodesize) || - (sbp->sb_blocklog - sbp->sb_inodelog != sbp->sb_inopblog) || - (sbp->sb_rextsize * sbp->sb_blocksize > XFS_MAX_RTEXTSIZE) || - (sbp->sb_rextsize * sbp->sb_blocksize < XFS_MIN_RTEXTSIZE) || - (sbp->sb_imax_pct > 100 /* zero sb_imax_pct is valid */) || - sbp->sb_dblocks == 0 || - sbp->sb_dblocks > XFS_MAX_DBLOCKS(sbp) || - sbp->sb_dblocks < XFS_MIN_DBLOCKS(sbp) || - sbp->sb_shared_vn != 0)) { - xfs_notice(mp, "SB sanity check failed"); - return -EFSCORRUPTED; - } - - /* - * Until this is fixed only page-sized or smaller data blocks work. - */ - if (unlikely(sbp->sb_blocksize > PAGE_SIZE)) { - xfs_warn(mp, - "File system with blocksize %d bytes. " - "Only pagesize (%ld) or less will currently work.", - sbp->sb_blocksize, PAGE_SIZE); - return -ENOSYS; - } - - /* - * Currently only very few inode sizes are supported. - */ - switch (sbp->sb_inodesize) { - case 256: - case 512: - case 1024: - case 2048: - break; - default: - xfs_warn(mp, "inode size of %d bytes not supported", - sbp->sb_inodesize); - return -ENOSYS; - } - - if (xfs_sb_validate_fsb_count(sbp, sbp->sb_dblocks) || - xfs_sb_validate_fsb_count(sbp, sbp->sb_rblocks)) { - xfs_warn(mp, - "file system too large to be mounted on this system."); - return -EFBIG; - } - - if (check_inprogress && sbp->sb_inprogress) { - xfs_warn(mp, "Offline file system operation in progress!"); - return -EFSCORRUPTED; - } - return 0; -} - -void -xfs_sb_quota_from_disk(struct xfs_sb *sbp) -{ - /* - * older mkfs doesn't initialize quota inodes to NULLFSINO. This - * leads to in-core values having two different values for a quota - * inode to be invalid: 0 and NULLFSINO. Change it to a single value - * NULLFSINO. - * - * Note that this change affect only the in-core values. These - * values are not written back to disk unless any quota information - * is written to the disk. Even in that case, sb_pquotino field is - * not written to disk unless the superblock supports pquotino. - */ - if (sbp->sb_uquotino == 0) - sbp->sb_uquotino = NULLFSINO; - if (sbp->sb_gquotino == 0) - sbp->sb_gquotino = NULLFSINO; - if (sbp->sb_pquotino == 0) - sbp->sb_pquotino = NULLFSINO; - - /* - * We need to do these manipilations only if we are working - * with an older version of on-disk superblock. - */ - if (xfs_sb_version_has_pquotino(sbp)) - return; - - if (sbp->sb_qflags & XFS_OQUOTA_ENFD) - sbp->sb_qflags |= (sbp->sb_qflags & XFS_PQUOTA_ACCT) ? - XFS_PQUOTA_ENFD : XFS_GQUOTA_ENFD; - if (sbp->sb_qflags & XFS_OQUOTA_CHKD) - sbp->sb_qflags |= (sbp->sb_qflags & XFS_PQUOTA_ACCT) ? - XFS_PQUOTA_CHKD : XFS_GQUOTA_CHKD; - sbp->sb_qflags &= ~(XFS_OQUOTA_ENFD | XFS_OQUOTA_CHKD); - - if (sbp->sb_qflags & XFS_PQUOTA_ACCT) { - /* - * In older version of superblock, on-disk superblock only - * has sb_gquotino, and in-core superblock has both sb_gquotino - * and sb_pquotino. But, only one of them is supported at any - * point of time. So, if PQUOTA is set in disk superblock, - * copy over sb_gquotino to sb_pquotino. - */ - sbp->sb_pquotino = sbp->sb_gquotino; - sbp->sb_gquotino = NULLFSINO; - } -} - -static void -__xfs_sb_from_disk( - struct xfs_sb *to, - xfs_dsb_t *from, - bool convert_xquota) -{ - to->sb_magicnum = be32_to_cpu(from->sb_magicnum); - to->sb_blocksize = be32_to_cpu(from->sb_blocksize); - to->sb_dblocks = be64_to_cpu(from->sb_dblocks); - to->sb_rblocks = be64_to_cpu(from->sb_rblocks); - to->sb_rextents = be64_to_cpu(from->sb_rextents); - memcpy(&to->sb_uuid, &from->sb_uuid, sizeof(to->sb_uuid)); - to->sb_logstart = be64_to_cpu(from->sb_logstart); - to->sb_rootino = be64_to_cpu(from->sb_rootino); - to->sb_rbmino = be64_to_cpu(from->sb_rbmino); - to->sb_rsumino = be64_to_cpu(from->sb_rsumino); - to->sb_rextsize = be32_to_cpu(from->sb_rextsize); - to->sb_agblocks = be32_to_cpu(from->sb_agblocks); - to->sb_agcount = be32_to_cpu(from->sb_agcount); - to->sb_rbmblocks = be32_to_cpu(from->sb_rbmblocks); - to->sb_logblocks = be32_to_cpu(from->sb_logblocks); - to->sb_versionnum = be16_to_cpu(from->sb_versionnum); - to->sb_sectsize = be16_to_cpu(from->sb_sectsize); - to->sb_inodesize = be16_to_cpu(from->sb_inodesize); - to->sb_inopblock = be16_to_cpu(from->sb_inopblock); - memcpy(&to->sb_fname, &from->sb_fname, sizeof(to->sb_fname)); - to->sb_blocklog = from->sb_blocklog; - to->sb_sectlog = from->sb_sectlog; - to->sb_inodelog = from->sb_inodelog; - to->sb_inopblog = from->sb_inopblog; - to->sb_agblklog = from->sb_agblklog; - to->sb_rextslog = from->sb_rextslog; - to->sb_inprogress = from->sb_inprogress; - to->sb_imax_pct = from->sb_imax_pct; - to->sb_icount = be64_to_cpu(from->sb_icount); - to->sb_ifree = be64_to_cpu(from->sb_ifree); - to->sb_fdblocks = be64_to_cpu(from->sb_fdblocks); - to->sb_frextents = be64_to_cpu(from->sb_frextents); - to->sb_uquotino = be64_to_cpu(from->sb_uquotino); - to->sb_gquotino = be64_to_cpu(from->sb_gquotino); - to->sb_qflags = be16_to_cpu(from->sb_qflags); - to->sb_flags = from->sb_flags; - to->sb_shared_vn = from->sb_shared_vn; - to->sb_inoalignmt = be32_to_cpu(from->sb_inoalignmt); - to->sb_unit = be32_to_cpu(from->sb_unit); - to->sb_width = be32_to_cpu(from->sb_width); - to->sb_dirblklog = from->sb_dirblklog; - to->sb_logsectlog = from->sb_logsectlog; - to->sb_logsectsize = be16_to_cpu(from->sb_logsectsize); - to->sb_logsunit = be32_to_cpu(from->sb_logsunit); - to->sb_features2 = be32_to_cpu(from->sb_features2); - to->sb_bad_features2 = be32_to_cpu(from->sb_bad_features2); - to->sb_features_compat = be32_to_cpu(from->sb_features_compat); - to->sb_features_ro_compat = be32_to_cpu(from->sb_features_ro_compat); - to->sb_features_incompat = be32_to_cpu(from->sb_features_incompat); - to->sb_features_log_incompat = - be32_to_cpu(from->sb_features_log_incompat); - /* crc is only used on disk, not in memory; just init to 0 here. */ - to->sb_crc = 0; - to->sb_spino_align = be32_to_cpu(from->sb_spino_align); - to->sb_pquotino = be64_to_cpu(from->sb_pquotino); - to->sb_lsn = be64_to_cpu(from->sb_lsn); - /* - * sb_meta_uuid is only on disk if it differs from sb_uuid and the - * feature flag is set; if not set we keep it only in memory. - */ - if (xfs_sb_version_hasmetauuid(to)) - uuid_copy(&to->sb_meta_uuid, &from->sb_meta_uuid); - else - uuid_copy(&to->sb_meta_uuid, &from->sb_uuid); - /* Convert on-disk flags to in-memory flags? */ - if (convert_xquota) - xfs_sb_quota_from_disk(to); -} - -void -xfs_sb_from_disk( - struct xfs_sb *to, - xfs_dsb_t *from) -{ - __xfs_sb_from_disk(to, from, true); -} - -static void -xfs_sb_quota_to_disk( - struct xfs_dsb *to, - struct xfs_sb *from) -{ - __uint16_t qflags = from->sb_qflags; - - to->sb_uquotino = cpu_to_be64(from->sb_uquotino); - if (xfs_sb_version_has_pquotino(from)) { - to->sb_qflags = cpu_to_be16(from->sb_qflags); - to->sb_gquotino = cpu_to_be64(from->sb_gquotino); - to->sb_pquotino = cpu_to_be64(from->sb_pquotino); - return; - } - - /* - * The in-core version of sb_qflags do not have XFS_OQUOTA_* - * flags, whereas the on-disk version does. So, convert incore - * XFS_{PG}QUOTA_* flags to on-disk XFS_OQUOTA_* flags. - */ - qflags &= ~(XFS_PQUOTA_ENFD | XFS_PQUOTA_CHKD | - XFS_GQUOTA_ENFD | XFS_GQUOTA_CHKD); - - if (from->sb_qflags & - (XFS_PQUOTA_ENFD | XFS_GQUOTA_ENFD)) - qflags |= XFS_OQUOTA_ENFD; - if (from->sb_qflags & - (XFS_PQUOTA_CHKD | XFS_GQUOTA_CHKD)) - qflags |= XFS_OQUOTA_CHKD; - to->sb_qflags = cpu_to_be16(qflags); - - /* - * GQUOTINO and PQUOTINO cannot be used together in versions - * of superblock that do not have pquotino. from->sb_flags - * tells us which quota is active and should be copied to - * disk. If neither are active, we should NULL the inode. - * - * In all cases, the separate pquotino must remain 0 because it - * it beyond the "end" of the valid non-pquotino superblock. - */ - if (from->sb_qflags & XFS_GQUOTA_ACCT) - to->sb_gquotino = cpu_to_be64(from->sb_gquotino); - else if (from->sb_qflags & XFS_PQUOTA_ACCT) - to->sb_gquotino = cpu_to_be64(from->sb_pquotino); - else { - /* - * We can't rely on just the fields being logged to tell us - * that it is safe to write NULLFSINO - we should only do that - * if quotas are not actually enabled. Hence only write - * NULLFSINO if both in-core quota inodes are NULL. - */ - if (from->sb_gquotino == NULLFSINO && - from->sb_pquotino == NULLFSINO) - to->sb_gquotino = cpu_to_be64(NULLFSINO); - } - - to->sb_pquotino = 0; -} - -void -xfs_sb_to_disk( - struct xfs_dsb *to, - struct xfs_sb *from) -{ - xfs_sb_quota_to_disk(to, from); - - to->sb_magicnum = cpu_to_be32(from->sb_magicnum); - to->sb_blocksize = cpu_to_be32(from->sb_blocksize); - to->sb_dblocks = cpu_to_be64(from->sb_dblocks); - to->sb_rblocks = cpu_to_be64(from->sb_rblocks); - to->sb_rextents = cpu_to_be64(from->sb_rextents); - memcpy(&to->sb_uuid, &from->sb_uuid, sizeof(to->sb_uuid)); - to->sb_logstart = cpu_to_be64(from->sb_logstart); - to->sb_rootino = cpu_to_be64(from->sb_rootino); - to->sb_rbmino = cpu_to_be64(from->sb_rbmino); - to->sb_rsumino = cpu_to_be64(from->sb_rsumino); - to->sb_rextsize = cpu_to_be32(from->sb_rextsize); - to->sb_agblocks = cpu_to_be32(from->sb_agblocks); - to->sb_agcount = cpu_to_be32(from->sb_agcount); - to->sb_rbmblocks = cpu_to_be32(from->sb_rbmblocks); - to->sb_logblocks = cpu_to_be32(from->sb_logblocks); - to->sb_versionnum = cpu_to_be16(from->sb_versionnum); - to->sb_sectsize = cpu_to_be16(from->sb_sectsize); - to->sb_inodesize = cpu_to_be16(from->sb_inodesize); - to->sb_inopblock = cpu_to_be16(from->sb_inopblock); - memcpy(&to->sb_fname, &from->sb_fname, sizeof(to->sb_fname)); - to->sb_blocklog = from->sb_blocklog; - to->sb_sectlog = from->sb_sectlog; - to->sb_inodelog = from->sb_inodelog; - to->sb_inopblog = from->sb_inopblog; - to->sb_agblklog = from->sb_agblklog; - to->sb_rextslog = from->sb_rextslog; - to->sb_inprogress = from->sb_inprogress; - to->sb_imax_pct = from->sb_imax_pct; - to->sb_icount = cpu_to_be64(from->sb_icount); - to->sb_ifree = cpu_to_be64(from->sb_ifree); - to->sb_fdblocks = cpu_to_be64(from->sb_fdblocks); - to->sb_frextents = cpu_to_be64(from->sb_frextents); - - to->sb_flags = from->sb_flags; - to->sb_shared_vn = from->sb_shared_vn; - to->sb_inoalignmt = cpu_to_be32(from->sb_inoalignmt); - to->sb_unit = cpu_to_be32(from->sb_unit); - to->sb_width = cpu_to_be32(from->sb_width); - to->sb_dirblklog = from->sb_dirblklog; - to->sb_logsectlog = from->sb_logsectlog; - to->sb_logsectsize = cpu_to_be16(from->sb_logsectsize); - to->sb_logsunit = cpu_to_be32(from->sb_logsunit); - - /* - * We need to ensure that bad_features2 always matches features2. - * Hence we enforce that here rather than having to remember to do it - * everywhere else that updates features2. - */ - from->sb_bad_features2 = from->sb_features2; - to->sb_features2 = cpu_to_be32(from->sb_features2); - to->sb_bad_features2 = cpu_to_be32(from->sb_bad_features2); - - if (xfs_sb_version_hascrc(from)) { - to->sb_features_compat = cpu_to_be32(from->sb_features_compat); - to->sb_features_ro_compat = - cpu_to_be32(from->sb_features_ro_compat); - to->sb_features_incompat = - cpu_to_be32(from->sb_features_incompat); - to->sb_features_log_incompat = - cpu_to_be32(from->sb_features_log_incompat); - to->sb_spino_align = cpu_to_be32(from->sb_spino_align); - to->sb_lsn = cpu_to_be64(from->sb_lsn); - if (xfs_sb_version_hasmetauuid(from)) - uuid_copy(&to->sb_meta_uuid, &from->sb_meta_uuid); - } -} - -static int -xfs_sb_verify( - struct xfs_buf *bp, - bool check_version) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_sb sb; - - /* - * Use call variant which doesn't convert quota flags from disk - * format, because xfs_mount_validate_sb checks the on-disk flags. - */ - __xfs_sb_from_disk(&sb, XFS_BUF_TO_SBP(bp), false); - - /* - * Only check the in progress field for the primary superblock as - * mkfs.xfs doesn't clear it from secondary superblocks. - */ - return xfs_mount_validate_sb(mp, &sb, - bp->b_maps[0].bm_bn == XFS_SB_DADDR, - check_version); -} - -/* - * If the superblock has the CRC feature bit set or the CRC field is non-null, - * check that the CRC is valid. We check the CRC field is non-null because a - * single bit error could clear the feature bit and unused parts of the - * superblock are supposed to be zero. Hence a non-null crc field indicates that - * we've potentially lost a feature bit and we should check it anyway. - * - * However, past bugs (i.e. in growfs) left non-zeroed regions beyond the - * last field in V4 secondary superblocks. So for secondary superblocks, - * we are more forgiving, and ignore CRC failures if the primary doesn't - * indicate that the fs version is V5. - */ -static void -xfs_sb_read_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_dsb *dsb = XFS_BUF_TO_SBP(bp); - int error; - - /* - * open code the version check to avoid needing to convert the entire - * superblock from disk order just to check the version number - */ - if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC) && - (((be16_to_cpu(dsb->sb_versionnum) & XFS_SB_VERSION_NUMBITS) == - XFS_SB_VERSION_5) || - dsb->sb_crc != 0)) { - - if (!xfs_buf_verify_cksum(bp, XFS_SB_CRC_OFF)) { - /* Only fail bad secondaries on a known V5 filesystem */ - if (bp->b_bn == XFS_SB_DADDR || - xfs_sb_version_hascrc(&mp->m_sb)) { - error = -EFSBADCRC; - goto out_error; - } - } - } - error = xfs_sb_verify(bp, true); - -out_error: - if (error) { - xfs_buf_ioerror(bp, error); - if (error == -EFSCORRUPTED || error == -EFSBADCRC) - xfs_verifier_error(bp); - } -} - -/* - * We may be probed for a filesystem match, so we may not want to emit - * messages when the superblock buffer is not actually an XFS superblock. - * If we find an XFS superblock, then run a normal, noisy mount because we are - * really going to mount it and want to know about errors. - */ -static void -xfs_sb_quiet_read_verify( - struct xfs_buf *bp) -{ - struct xfs_dsb *dsb = XFS_BUF_TO_SBP(bp); - - if (dsb->sb_magicnum == cpu_to_be32(XFS_SB_MAGIC)) { - /* XFS filesystem, verify noisily! */ - xfs_sb_read_verify(bp); - return; - } - /* quietly fail */ - xfs_buf_ioerror(bp, -EWRONGFS); -} - -static void -xfs_sb_write_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_buf_log_item *bip = bp->b_fspriv; - int error; - - error = xfs_sb_verify(bp, false); - if (error) { - xfs_buf_ioerror(bp, error); - xfs_verifier_error(bp); - return; - } - - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return; - - if (bip) - XFS_BUF_TO_SBP(bp)->sb_lsn = cpu_to_be64(bip->bli_item.li_lsn); - - xfs_buf_update_cksum(bp, XFS_SB_CRC_OFF); -} - -const struct xfs_buf_ops xfs_sb_buf_ops = { - .name = "xfs_sb", - .verify_read = xfs_sb_read_verify, - .verify_write = xfs_sb_write_verify, -}; - -const struct xfs_buf_ops xfs_sb_quiet_buf_ops = { - .name = "xfs_sb_quiet", - .verify_read = xfs_sb_quiet_read_verify, - .verify_write = xfs_sb_write_verify, -}; - -/* - * xfs_mount_common - * - * Mount initialization code establishing various mount - * fields from the superblock associated with the given - * mount structure - */ -void -xfs_sb_mount_common( - struct xfs_mount *mp, - struct xfs_sb *sbp) -{ - mp->m_agfrotor = mp->m_agirotor = 0; - spin_lock_init(&mp->m_agirotor_lock); - mp->m_maxagi = mp->m_sb.sb_agcount; - mp->m_blkbit_log = sbp->sb_blocklog + XFS_NBBYLOG; - mp->m_blkbb_log = sbp->sb_blocklog - BBSHIFT; - mp->m_sectbb_log = sbp->sb_sectlog - BBSHIFT; - mp->m_agno_log = xfs_highbit32(sbp->sb_agcount - 1) + 1; - mp->m_agino_log = sbp->sb_inopblog + sbp->sb_agblklog; - mp->m_blockmask = sbp->sb_blocksize - 1; - mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG; - mp->m_blockwmask = mp->m_blockwsize - 1; - - mp->m_alloc_mxr[0] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 1); - mp->m_alloc_mxr[1] = xfs_allocbt_maxrecs(mp, sbp->sb_blocksize, 0); - mp->m_alloc_mnr[0] = mp->m_alloc_mxr[0] / 2; - mp->m_alloc_mnr[1] = mp->m_alloc_mxr[1] / 2; - - mp->m_inobt_mxr[0] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 1); - mp->m_inobt_mxr[1] = xfs_inobt_maxrecs(mp, sbp->sb_blocksize, 0); - mp->m_inobt_mnr[0] = mp->m_inobt_mxr[0] / 2; - mp->m_inobt_mnr[1] = mp->m_inobt_mxr[1] / 2; - - mp->m_bmap_dmxr[0] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 1); - mp->m_bmap_dmxr[1] = xfs_bmbt_maxrecs(mp, sbp->sb_blocksize, 0); - mp->m_bmap_dmnr[0] = mp->m_bmap_dmxr[0] / 2; - mp->m_bmap_dmnr[1] = mp->m_bmap_dmxr[1] / 2; - - mp->m_rmap_mxr[0] = xfs_rmapbt_maxrecs(mp, sbp->sb_blocksize, 1); - mp->m_rmap_mxr[1] = xfs_rmapbt_maxrecs(mp, sbp->sb_blocksize, 0); - mp->m_rmap_mnr[0] = mp->m_rmap_mxr[0] / 2; - mp->m_rmap_mnr[1] = mp->m_rmap_mxr[1] / 2; - - mp->m_refc_mxr[0] = xfs_refcountbt_maxrecs(mp, sbp->sb_blocksize, - true); - mp->m_refc_mxr[1] = xfs_refcountbt_maxrecs(mp, sbp->sb_blocksize, - false); - mp->m_refc_mnr[0] = mp->m_refc_mxr[0] / 2; - mp->m_refc_mnr[1] = mp->m_refc_mxr[1] / 2; - - mp->m_bsize = XFS_FSB_TO_BB(mp, 1); - mp->m_ialloc_inos = (int)MAX((__uint16_t)XFS_INODES_PER_CHUNK, - sbp->sb_inopblock); - mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog; - - if (sbp->sb_spino_align) - mp->m_ialloc_min_blks = sbp->sb_spino_align; - else - mp->m_ialloc_min_blks = mp->m_ialloc_blks; - mp->m_alloc_set_aside = xfs_alloc_set_aside(mp); - mp->m_ag_max_usable = xfs_alloc_ag_max_usable(mp); -} - -/* - * xfs_initialize_perag_data - * - * Read in each per-ag structure so we can count up the number of - * allocated inodes, free inodes and used filesystem blocks as this - * information is no longer persistent in the superblock. Once we have - * this information, write it into the in-core superblock structure. - */ -int -xfs_initialize_perag_data( - struct xfs_mount *mp, - xfs_agnumber_t agcount) -{ - xfs_agnumber_t index; - xfs_perag_t *pag; - xfs_sb_t *sbp = &mp->m_sb; - uint64_t ifree = 0; - uint64_t ialloc = 0; - uint64_t bfree = 0; - uint64_t bfreelst = 0; - uint64_t btree = 0; - int error; - - for (index = 0; index < agcount; index++) { - /* - * read the agf, then the agi. This gets us - * all the information we need and populates the - * per-ag structures for us. - */ - error = xfs_alloc_pagf_init(mp, NULL, index, 0); - if (error) - return error; - - error = xfs_ialloc_pagi_init(mp, NULL, index); - if (error) - return error; - pag = xfs_perag_get(mp, index); - ifree += pag->pagi_freecount; - ialloc += pag->pagi_count; - bfree += pag->pagf_freeblks; - bfreelst += pag->pagf_flcount; - btree += pag->pagf_btreeblks; - xfs_perag_put(pag); - } - - /* Overwrite incore superblock counters with just-read data */ - spin_lock(&mp->m_sb_lock); - sbp->sb_ifree = ifree; - sbp->sb_icount = ialloc; - sbp->sb_fdblocks = bfree + bfreelst + btree; - spin_unlock(&mp->m_sb_lock); - - xfs_reinit_percpu_counters(mp); - - return 0; -} - -/* - * xfs_log_sb() can be used to copy arbitrary changes to the in-core superblock - * into the superblock buffer to be logged. It does not provide the higher - * level of locking that is needed to protect the in-core superblock from - * concurrent access. - */ -void -xfs_log_sb( - struct xfs_trans *tp) -{ - struct xfs_mount *mp = tp->t_mountp; - struct xfs_buf *bp = xfs_trans_getsb(tp, mp, 0); - - mp->m_sb.sb_icount = percpu_counter_sum(&mp->m_icount); - mp->m_sb.sb_ifree = percpu_counter_sum(&mp->m_ifree); - mp->m_sb.sb_fdblocks = percpu_counter_sum(&mp->m_fdblocks); - - xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb); - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF); - xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsb)); -} - -/* - * xfs_sync_sb - * - * Sync the superblock to disk. - * - * Note that the caller is responsible for checking the frozen state of the - * filesystem. This procedure uses the non-blocking transaction allocator and - * thus will allow modifications to a frozen fs. This is required because this - * code can be called during the process of freezing where use of the high-level - * allocator would deadlock. - */ -int -xfs_sync_sb( - struct xfs_mount *mp, - bool wait) -{ - struct xfs_trans *tp; - int error; - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_sb, 0, 0, - XFS_TRANS_NO_WRITECOUNT, &tp); - if (error) - return error; - - xfs_log_sb(tp); - if (wait) - xfs_trans_set_sync(tp); - return xfs_trans_commit(tp); -} diff --git a/src/linux/fs/xfs/libxfs/xfs_sb.h b/src/linux/fs/xfs/libxfs/xfs_sb.h deleted file mode 100644 index 961e647..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_sb.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_SB_H__ -#define __XFS_SB_H__ - -/* - * perag get/put wrappers for ref counting - */ -extern struct xfs_perag *xfs_perag_get(struct xfs_mount *, xfs_agnumber_t); -extern struct xfs_perag *xfs_perag_get_tag(struct xfs_mount *, xfs_agnumber_t, - int tag); -extern void xfs_perag_put(struct xfs_perag *pag); -extern int xfs_initialize_perag_data(struct xfs_mount *, xfs_agnumber_t); - -extern void xfs_log_sb(struct xfs_trans *tp); -extern int xfs_sync_sb(struct xfs_mount *mp, bool wait); -extern void xfs_sb_mount_common(struct xfs_mount *mp, struct xfs_sb *sbp); -extern void xfs_sb_from_disk(struct xfs_sb *to, struct xfs_dsb *from); -extern void xfs_sb_to_disk(struct xfs_dsb *to, struct xfs_sb *from); -extern void xfs_sb_quota_from_disk(struct xfs_sb *sbp); - -#endif /* __XFS_SB_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_shared.h b/src/linux/fs/xfs/libxfs/xfs_shared.h deleted file mode 100644 index c6f4eb4..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_shared.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * Copyright (c) 2013 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_SHARED_H__ -#define __XFS_SHARED_H__ - -/* - * Definitions shared between kernel and userspace that don't fit into any other - * header file that is shared with userspace. - */ -struct xfs_ifork; -struct xfs_buf; -struct xfs_buf_ops; -struct xfs_mount; -struct xfs_trans; -struct xfs_inode; - -/* - * Buffer verifier operations are widely used, including userspace tools - */ -extern const struct xfs_buf_ops xfs_agf_buf_ops; -extern const struct xfs_buf_ops xfs_agi_buf_ops; -extern const struct xfs_buf_ops xfs_agf_buf_ops; -extern const struct xfs_buf_ops xfs_agfl_buf_ops; -extern const struct xfs_buf_ops xfs_allocbt_buf_ops; -extern const struct xfs_buf_ops xfs_rmapbt_buf_ops; -extern const struct xfs_buf_ops xfs_refcountbt_buf_ops; -extern const struct xfs_buf_ops xfs_attr3_leaf_buf_ops; -extern const struct xfs_buf_ops xfs_attr3_rmt_buf_ops; -extern const struct xfs_buf_ops xfs_bmbt_buf_ops; -extern const struct xfs_buf_ops xfs_da3_node_buf_ops; -extern const struct xfs_buf_ops xfs_dquot_buf_ops; -extern const struct xfs_buf_ops xfs_symlink_buf_ops; -extern const struct xfs_buf_ops xfs_agi_buf_ops; -extern const struct xfs_buf_ops xfs_inobt_buf_ops; -extern const struct xfs_buf_ops xfs_inode_buf_ops; -extern const struct xfs_buf_ops xfs_inode_buf_ra_ops; -extern const struct xfs_buf_ops xfs_dquot_buf_ops; -extern const struct xfs_buf_ops xfs_dquot_buf_ra_ops; -extern const struct xfs_buf_ops xfs_sb_buf_ops; -extern const struct xfs_buf_ops xfs_sb_quiet_buf_ops; -extern const struct xfs_buf_ops xfs_symlink_buf_ops; -extern const struct xfs_buf_ops xfs_rtbuf_ops; - -/* - * This structure is used to track log items associated with - * a transaction. It points to the log item and keeps some - * flags to track the state of the log item. It also tracks - * the amount of space needed to log the item it describes - * once we get to commit processing (see xfs_trans_commit()). - */ -struct xfs_log_item_desc { - struct xfs_log_item *lid_item; - struct list_head lid_trans; - unsigned char lid_flags; -}; - -#define XFS_LID_DIRTY 0x1 - -/* log size calculation functions */ -int xfs_log_calc_unit_res(struct xfs_mount *mp, int unit_bytes); -int xfs_log_calc_minimum_size(struct xfs_mount *); - - -/* - * Values for t_flags. - */ -#define XFS_TRANS_DIRTY 0x01 /* something needs to be logged */ -#define XFS_TRANS_SB_DIRTY 0x02 /* superblock is modified */ -#define XFS_TRANS_PERM_LOG_RES 0x04 /* xact took a permanent log res */ -#define XFS_TRANS_SYNC 0x08 /* make commit synchronous */ -#define XFS_TRANS_DQ_DIRTY 0x10 /* at least one dquot in trx dirty */ -#define XFS_TRANS_RESERVE 0x20 /* OK to use reserved data blocks */ -#define XFS_TRANS_NO_WRITECOUNT 0x40 /* do not elevate SB writecount */ -#define XFS_TRANS_NOFS 0x80 /* pass KM_NOFS to kmem_alloc */ - -/* - * Field values for xfs_trans_mod_sb. - */ -#define XFS_TRANS_SB_ICOUNT 0x00000001 -#define XFS_TRANS_SB_IFREE 0x00000002 -#define XFS_TRANS_SB_FDBLOCKS 0x00000004 -#define XFS_TRANS_SB_RES_FDBLOCKS 0x00000008 -#define XFS_TRANS_SB_FREXTENTS 0x00000010 -#define XFS_TRANS_SB_RES_FREXTENTS 0x00000020 -#define XFS_TRANS_SB_DBLOCKS 0x00000040 -#define XFS_TRANS_SB_AGCOUNT 0x00000080 -#define XFS_TRANS_SB_IMAXPCT 0x00000100 -#define XFS_TRANS_SB_REXTSIZE 0x00000200 -#define XFS_TRANS_SB_RBMBLOCKS 0x00000400 -#define XFS_TRANS_SB_RBLOCKS 0x00000800 -#define XFS_TRANS_SB_REXTENTS 0x00001000 -#define XFS_TRANS_SB_REXTSLOG 0x00002000 - -/* - * Here we centralize the specification of XFS meta-data buffer reference count - * values. This determines how hard the buffer cache tries to hold onto the - * buffer. - */ -#define XFS_AGF_REF 4 -#define XFS_AGI_REF 4 -#define XFS_AGFL_REF 3 -#define XFS_INO_BTREE_REF 3 -#define XFS_ALLOC_BTREE_REF 2 -#define XFS_BMAP_BTREE_REF 2 -#define XFS_RMAP_BTREE_REF 2 -#define XFS_DIR_BTREE_REF 2 -#define XFS_INO_REF 2 -#define XFS_ATTR_BTREE_REF 1 -#define XFS_DQUOT_REF 1 -#define XFS_REFC_BTREE_REF 1 - -/* - * Flags for xfs_trans_ichgtime(). - */ -#define XFS_ICHGTIME_MOD 0x1 /* data fork modification timestamp */ -#define XFS_ICHGTIME_CHG 0x2 /* inode field change timestamp */ -#define XFS_ICHGTIME_CREATE 0x4 /* inode create timestamp */ - - -/* - * Symlink decoding/encoding functions - */ -int xfs_symlink_blocks(struct xfs_mount *mp, int pathlen); -int xfs_symlink_hdr_set(struct xfs_mount *mp, xfs_ino_t ino, uint32_t offset, - uint32_t size, struct xfs_buf *bp); -bool xfs_symlink_hdr_ok(xfs_ino_t ino, uint32_t offset, - uint32_t size, struct xfs_buf *bp); -void xfs_symlink_local_to_remote(struct xfs_trans *tp, struct xfs_buf *bp, - struct xfs_inode *ip, struct xfs_ifork *ifp); - -#endif /* __XFS_SHARED_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_symlink_remote.c b/src/linux/fs/xfs/libxfs/xfs_symlink_remote.c deleted file mode 100644 index 2e2c671..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_symlink_remote.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (c) 2000-2006 Silicon Graphics, Inc. - * Copyright (c) 2012-2013 Red Hat, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_shared.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_bmap_btree.h" -#include "xfs_inode.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_symlink.h" -#include "xfs_cksum.h" -#include "xfs_trans.h" -#include "xfs_buf_item.h" -#include "xfs_log.h" - - -/* - * Each contiguous block has a header, so it is not just a simple pathlen - * to FSB conversion. - */ -int -xfs_symlink_blocks( - struct xfs_mount *mp, - int pathlen) -{ - int buflen = XFS_SYMLINK_BUF_SPACE(mp, mp->m_sb.sb_blocksize); - - return (pathlen + buflen - 1) / buflen; -} - -int -xfs_symlink_hdr_set( - struct xfs_mount *mp, - xfs_ino_t ino, - uint32_t offset, - uint32_t size, - struct xfs_buf *bp) -{ - struct xfs_dsymlink_hdr *dsl = bp->b_addr; - - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return 0; - - memset(dsl, 0, sizeof(struct xfs_dsymlink_hdr)); - dsl->sl_magic = cpu_to_be32(XFS_SYMLINK_MAGIC); - dsl->sl_offset = cpu_to_be32(offset); - dsl->sl_bytes = cpu_to_be32(size); - uuid_copy(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid); - dsl->sl_owner = cpu_to_be64(ino); - dsl->sl_blkno = cpu_to_be64(bp->b_bn); - bp->b_ops = &xfs_symlink_buf_ops; - - return sizeof(struct xfs_dsymlink_hdr); -} - -/* - * Checking of the symlink header is split into two parts. the verifier does - * CRC, location and bounds checking, the unpacking function checks the path - * parameters and owner. - */ -bool -xfs_symlink_hdr_ok( - xfs_ino_t ino, - uint32_t offset, - uint32_t size, - struct xfs_buf *bp) -{ - struct xfs_dsymlink_hdr *dsl = bp->b_addr; - - if (offset != be32_to_cpu(dsl->sl_offset)) - return false; - if (size != be32_to_cpu(dsl->sl_bytes)) - return false; - if (ino != be64_to_cpu(dsl->sl_owner)) - return false; - - /* ok */ - return true; -} - -static bool -xfs_symlink_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_dsymlink_hdr *dsl = bp->b_addr; - - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return false; - if (dsl->sl_magic != cpu_to_be32(XFS_SYMLINK_MAGIC)) - return false; - if (!uuid_equal(&dsl->sl_uuid, &mp->m_sb.sb_meta_uuid)) - return false; - if (bp->b_bn != be64_to_cpu(dsl->sl_blkno)) - return false; - if (be32_to_cpu(dsl->sl_offset) + - be32_to_cpu(dsl->sl_bytes) >= MAXPATHLEN) - return false; - if (dsl->sl_owner == 0) - return false; - if (!xfs_log_check_lsn(mp, be64_to_cpu(dsl->sl_lsn))) - return false; - - return true; -} - -static void -xfs_symlink_read_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - - /* no verification of non-crc buffers */ - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return; - - if (!xfs_buf_verify_cksum(bp, XFS_SYMLINK_CRC_OFF)) - xfs_buf_ioerror(bp, -EFSBADCRC); - else if (!xfs_symlink_verify(bp)) - xfs_buf_ioerror(bp, -EFSCORRUPTED); - - if (bp->b_error) - xfs_verifier_error(bp); -} - -static void -xfs_symlink_write_verify( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - struct xfs_buf_log_item *bip = bp->b_fspriv; - - /* no verification of non-crc buffers */ - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return; - - if (!xfs_symlink_verify(bp)) { - xfs_buf_ioerror(bp, -EFSCORRUPTED); - xfs_verifier_error(bp); - return; - } - - if (bip) { - struct xfs_dsymlink_hdr *dsl = bp->b_addr; - dsl->sl_lsn = cpu_to_be64(bip->bli_item.li_lsn); - } - xfs_buf_update_cksum(bp, XFS_SYMLINK_CRC_OFF); -} - -const struct xfs_buf_ops xfs_symlink_buf_ops = { - .name = "xfs_symlink", - .verify_read = xfs_symlink_read_verify, - .verify_write = xfs_symlink_write_verify, -}; - -void -xfs_symlink_local_to_remote( - struct xfs_trans *tp, - struct xfs_buf *bp, - struct xfs_inode *ip, - struct xfs_ifork *ifp) -{ - struct xfs_mount *mp = ip->i_mount; - char *buf; - - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF); - - if (!xfs_sb_version_hascrc(&mp->m_sb)) { - bp->b_ops = NULL; - memcpy(bp->b_addr, ifp->if_u1.if_data, ifp->if_bytes); - xfs_trans_log_buf(tp, bp, 0, ifp->if_bytes - 1); - return; - } - - /* - * As this symlink fits in an inode literal area, it must also fit in - * the smallest buffer the filesystem supports. - */ - ASSERT(BBTOB(bp->b_length) >= - ifp->if_bytes + sizeof(struct xfs_dsymlink_hdr)); - - bp->b_ops = &xfs_symlink_buf_ops; - - buf = bp->b_addr; - buf += xfs_symlink_hdr_set(mp, ip->i_ino, 0, ifp->if_bytes, bp); - memcpy(buf, ifp->if_u1.if_data, ifp->if_bytes); - xfs_trans_log_buf(tp, bp, 0, sizeof(struct xfs_dsymlink_hdr) + - ifp->if_bytes - 1); -} diff --git a/src/linux/fs/xfs/libxfs/xfs_trans_resv.c b/src/linux/fs/xfs/libxfs/xfs_trans_resv.c deleted file mode 100644 index b456cca..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_trans_resv.c +++ /dev/null @@ -1,915 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * Copyright (C) 2010 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_inode.h" -#include "xfs_bmap_btree.h" -#include "xfs_ialloc.h" -#include "xfs_quota.h" -#include "xfs_trans.h" -#include "xfs_qm.h" -#include "xfs_trans_space.h" -#include "xfs_trace.h" - -/* - * A buffer has a format structure overhead in the log in addition - * to the data, so we need to take this into account when reserving - * space in a transaction for a buffer. Round the space required up - * to a multiple of 128 bytes so that we don't change the historical - * reservation that has been used for this overhead. - */ -STATIC uint -xfs_buf_log_overhead(void) -{ - return round_up(sizeof(struct xlog_op_header) + - sizeof(struct xfs_buf_log_format), 128); -} - -/* - * Calculate out transaction log reservation per item in bytes. - * - * The nbufs argument is used to indicate the number of items that - * will be changed in a transaction. size is used to tell how many - * bytes should be reserved per item. - */ -STATIC uint -xfs_calc_buf_res( - uint nbufs, - uint size) -{ - return nbufs * (size + xfs_buf_log_overhead()); -} - -/* - * Per-extent log reservation for the btree changes involved in freeing or - * allocating an extent. In classic XFS there were two trees that will be - * modified (bnobt + cntbt). With rmap enabled, there are three trees - * (rmapbt). With reflink, there are four trees (refcountbt). The number of - * blocks reserved is based on the formula: - * - * num trees * ((2 blocks/level * max depth) - 1) - * - * Keep in mind that max depth is calculated separately for each type of tree. - */ -uint -xfs_allocfree_log_count( - struct xfs_mount *mp, - uint num_ops) -{ - uint blocks; - - blocks = num_ops * 2 * (2 * mp->m_ag_maxlevels - 1); - if (xfs_sb_version_hasrmapbt(&mp->m_sb)) - blocks += num_ops * (2 * mp->m_rmap_maxlevels - 1); - if (xfs_sb_version_hasreflink(&mp->m_sb)) - blocks += num_ops * (2 * mp->m_refc_maxlevels - 1); - - return blocks; -} - -/* - * Logging inodes is really tricksy. They are logged in memory format, - * which means that what we write into the log doesn't directly translate into - * the amount of space they use on disk. - * - * Case in point - btree format forks in memory format use more space than the - * on-disk format. In memory, the buffer contains a normal btree block header so - * the btree code can treat it as though it is just another generic buffer. - * However, when we write it to the inode fork, we don't write all of this - * header as it isn't needed. e.g. the root is only ever in the inode, so - * there's no need for sibling pointers which would waste 16 bytes of space. - * - * Hence when we have an inode with a maximally sized btree format fork, then - * amount of information we actually log is greater than the size of the inode - * on disk. Hence we need an inode reservation function that calculates all this - * correctly. So, we log: - * - * - 4 log op headers for object - * - for the ilf, the inode core and 2 forks - * - inode log format object - * - the inode core - * - two inode forks containing bmap btree root blocks. - * - the btree data contained by both forks will fit into the inode size, - * hence when combined with the inode core above, we have a total of the - * actual inode size. - * - the BMBT headers need to be accounted separately, as they are - * additional to the records and pointers that fit inside the inode - * forks. - */ -STATIC uint -xfs_calc_inode_res( - struct xfs_mount *mp, - uint ninodes) -{ - return ninodes * - (4 * sizeof(struct xlog_op_header) + - sizeof(struct xfs_inode_log_format) + - mp->m_sb.sb_inodesize + - 2 * XFS_BMBT_BLOCK_LEN(mp)); -} - -/* - * The free inode btree is a conditional feature and the log reservation - * requirements differ slightly from that of the traditional inode allocation - * btree. The finobt tracks records for inode chunks with at least one free - * inode. A record can be removed from the tree for an inode allocation - * or free and thus the finobt reservation is unconditional across: - * - * - inode allocation - * - inode free - * - inode chunk allocation - * - * The 'modify' param indicates to include the record modification scenario. The - * 'alloc' param indicates to include the reservation for free space btree - * modifications on behalf of finobt modifications. This is required only for - * transactions that do not already account for free space btree modifications. - * - * the free inode btree: max depth * block size - * the allocation btrees: 2 trees * (max depth - 1) * block size - * the free inode btree entry: block size - */ -STATIC uint -xfs_calc_finobt_res( - struct xfs_mount *mp, - int alloc, - int modify) -{ - uint res; - - if (!xfs_sb_version_hasfinobt(&mp->m_sb)) - return 0; - - res = xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)); - if (alloc) - res += xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1), - XFS_FSB_TO_B(mp, 1)); - if (modify) - res += (uint)XFS_FSB_TO_B(mp, 1); - - return res; -} - -/* - * Various log reservation values. - * - * These are based on the size of the file system block because that is what - * most transactions manipulate. Each adds in an additional 128 bytes per - * item logged to try to account for the overhead of the transaction mechanism. - * - * Note: Most of the reservations underestimate the number of allocation - * groups into which they could free extents in the xfs_defer_finish() call. - * This is because the number in the worst case is quite high and quite - * unusual. In order to fix this we need to change xfs_defer_finish() to free - * extents in only a single AG at a time. This will require changes to the - * EFI code as well, however, so that the EFI for the extents not freed is - * logged again in each transaction. See SGI PV #261917. - * - * Reservation functions here avoid a huge stack in xfs_trans_init due to - * register overflow from temporaries in the calculations. - */ - - -/* - * In a write transaction we can allocate a maximum of 2 - * extents. This gives: - * the inode getting the new extents: inode size - * the inode's bmap btree: max depth * block size - * the agfs of the ags from which the extents are allocated: 2 * sector - * the superblock free block counter: sector size - * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size - * And the bmap_finish transaction can free bmap blocks in a join: - * the agfs of the ags containing the blocks: 2 * sector size - * the agfls of the ags containing the blocks: 2 * sector size - * the super block free block counter: sector size - * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size - */ -STATIC uint -xfs_calc_write_reservation( - struct xfs_mount *mp) -{ - return XFS_DQUOT_LOGRES(mp) + - MAX((xfs_calc_inode_res(mp, 1) + - xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK), - XFS_FSB_TO_B(mp, 1)) + - xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(xfs_allocfree_log_count(mp, 2), - XFS_FSB_TO_B(mp, 1))), - (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(xfs_allocfree_log_count(mp, 2), - XFS_FSB_TO_B(mp, 1)))); -} - -/* - * In truncating a file we free up to two extents at once. We can modify: - * the inode being truncated: inode size - * the inode's bmap btree: (max depth + 1) * block size - * And the bmap_finish transaction can free the blocks and bmap blocks: - * the agf for each of the ags: 4 * sector size - * the agfl for each of the ags: 4 * sector size - * the super block to reflect the freed blocks: sector size - * worst case split in allocation btrees per extent assuming 4 extents: - * 4 exts * 2 trees * (2 * max depth - 1) * block size - * the inode btree: max depth * blocksize - * the allocation btrees: 2 trees * (max depth - 1) * block size - */ -STATIC uint -xfs_calc_itruncate_reservation( - struct xfs_mount *mp) -{ - return XFS_DQUOT_LOGRES(mp) + - MAX((xfs_calc_inode_res(mp, 1) + - xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK) + 1, - XFS_FSB_TO_B(mp, 1))), - (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(xfs_allocfree_log_count(mp, 4), - XFS_FSB_TO_B(mp, 1)) + - xfs_calc_buf_res(5, 0) + - xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1), - XFS_FSB_TO_B(mp, 1)) + - xfs_calc_buf_res(2 + mp->m_ialloc_blks + - mp->m_in_maxlevels, 0))); -} - -/* - * In renaming a files we can modify: - * the four inodes involved: 4 * inode size - * the two directory btrees: 2 * (max depth + v2) * dir block size - * the two directory bmap btrees: 2 * max depth * block size - * And the bmap_finish transaction can free dir and bmap blocks (two sets - * of bmap blocks) giving: - * the agf for the ags in which the blocks live: 3 * sector size - * the agfl for the ags in which the blocks live: 3 * sector size - * the superblock for the free block count: sector size - * the allocation btrees: 3 exts * 2 trees * (2 * max depth - 1) * block size - */ -STATIC uint -xfs_calc_rename_reservation( - struct xfs_mount *mp) -{ - return XFS_DQUOT_LOGRES(mp) + - MAX((xfs_calc_inode_res(mp, 4) + - xfs_calc_buf_res(2 * XFS_DIROP_LOG_COUNT(mp), - XFS_FSB_TO_B(mp, 1))), - (xfs_calc_buf_res(7, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(xfs_allocfree_log_count(mp, 3), - XFS_FSB_TO_B(mp, 1)))); -} - -/* - * For removing an inode from unlinked list at first, we can modify: - * the agi hash list and counters: sector size - * the on disk inode before ours in the agi hash list: inode cluster size - */ -STATIC uint -xfs_calc_iunlink_remove_reservation( - struct xfs_mount *mp) -{ - return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + - max_t(uint, XFS_FSB_TO_B(mp, 1), mp->m_inode_cluster_size); -} - -/* - * For creating a link to an inode: - * the parent directory inode: inode size - * the linked inode: inode size - * the directory btree could split: (max depth + v2) * dir block size - * the directory bmap btree could join or split: (max depth + v2) * blocksize - * And the bmap_finish transaction can free some bmap blocks giving: - * the agf for the ag in which the blocks live: sector size - * the agfl for the ag in which the blocks live: sector size - * the superblock for the free block count: sector size - * the allocation btrees: 2 trees * (2 * max depth - 1) * block size - */ -STATIC uint -xfs_calc_link_reservation( - struct xfs_mount *mp) -{ - return XFS_DQUOT_LOGRES(mp) + - xfs_calc_iunlink_remove_reservation(mp) + - MAX((xfs_calc_inode_res(mp, 2) + - xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), - XFS_FSB_TO_B(mp, 1))), - (xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1), - XFS_FSB_TO_B(mp, 1)))); -} - -/* - * For adding an inode to unlinked list we can modify: - * the agi hash list: sector size - * the unlinked inode: inode size - */ -STATIC uint -xfs_calc_iunlink_add_reservation(xfs_mount_t *mp) -{ - return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + - xfs_calc_inode_res(mp, 1); -} - -/* - * For removing a directory entry we can modify: - * the parent directory inode: inode size - * the removed inode: inode size - * the directory btree could join: (max depth + v2) * dir block size - * the directory bmap btree could join or split: (max depth + v2) * blocksize - * And the bmap_finish transaction can free the dir and bmap blocks giving: - * the agf for the ag in which the blocks live: 2 * sector size - * the agfl for the ag in which the blocks live: 2 * sector size - * the superblock for the free block count: sector size - * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size - */ -STATIC uint -xfs_calc_remove_reservation( - struct xfs_mount *mp) -{ - return XFS_DQUOT_LOGRES(mp) + - xfs_calc_iunlink_add_reservation(mp) + - MAX((xfs_calc_inode_res(mp, 1) + - xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), - XFS_FSB_TO_B(mp, 1))), - (xfs_calc_buf_res(4, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(xfs_allocfree_log_count(mp, 2), - XFS_FSB_TO_B(mp, 1)))); -} - -/* - * For create, break it in to the two cases that the transaction - * covers. We start with the modify case - allocation done by modification - * of the state of existing inodes - and the allocation case. - */ - -/* - * For create we can modify: - * the parent directory inode: inode size - * the new inode: inode size - * the inode btree entry: block size - * the superblock for the nlink flag: sector size - * the directory btree: (max depth + v2) * dir block size - * the directory inode's bmap btree: (max depth + v2) * block size - * the finobt (record modification and allocation btrees) - */ -STATIC uint -xfs_calc_create_resv_modify( - struct xfs_mount *mp) -{ - return xfs_calc_inode_res(mp, 2) + - xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + - (uint)XFS_FSB_TO_B(mp, 1) + - xfs_calc_buf_res(XFS_DIROP_LOG_COUNT(mp), XFS_FSB_TO_B(mp, 1)) + - xfs_calc_finobt_res(mp, 1, 1); -} - -/* - * For create we can allocate some inodes giving: - * the agi and agf of the ag getting the new inodes: 2 * sectorsize - * the superblock for the nlink flag: sector size - * the inode blocks allocated: mp->m_ialloc_blks * blocksize - * the inode btree: max depth * blocksize - * the allocation btrees: 2 trees * (max depth - 1) * block size - */ -STATIC uint -xfs_calc_create_resv_alloc( - struct xfs_mount *mp) -{ - return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) + - mp->m_sb.sb_sectsize + - xfs_calc_buf_res(mp->m_ialloc_blks, XFS_FSB_TO_B(mp, 1)) + - xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) + - xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1), - XFS_FSB_TO_B(mp, 1)); -} - -STATIC uint -__xfs_calc_create_reservation( - struct xfs_mount *mp) -{ - return XFS_DQUOT_LOGRES(mp) + - MAX(xfs_calc_create_resv_alloc(mp), - xfs_calc_create_resv_modify(mp)); -} - -/* - * For icreate we can allocate some inodes giving: - * the agi and agf of the ag getting the new inodes: 2 * sectorsize - * the superblock for the nlink flag: sector size - * the inode btree: max depth * blocksize - * the allocation btrees: 2 trees * (max depth - 1) * block size - * the finobt (record insertion) - */ -STATIC uint -xfs_calc_icreate_resv_alloc( - struct xfs_mount *mp) -{ - return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) + - mp->m_sb.sb_sectsize + - xfs_calc_buf_res(mp->m_in_maxlevels, XFS_FSB_TO_B(mp, 1)) + - xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1), - XFS_FSB_TO_B(mp, 1)) + - xfs_calc_finobt_res(mp, 0, 0); -} - -STATIC uint -xfs_calc_icreate_reservation(xfs_mount_t *mp) -{ - return XFS_DQUOT_LOGRES(mp) + - MAX(xfs_calc_icreate_resv_alloc(mp), - xfs_calc_create_resv_modify(mp)); -} - -STATIC uint -xfs_calc_create_reservation( - struct xfs_mount *mp) -{ - if (xfs_sb_version_hascrc(&mp->m_sb)) - return xfs_calc_icreate_reservation(mp); - return __xfs_calc_create_reservation(mp); - -} - -STATIC uint -xfs_calc_create_tmpfile_reservation( - struct xfs_mount *mp) -{ - uint res = XFS_DQUOT_LOGRES(mp); - - if (xfs_sb_version_hascrc(&mp->m_sb)) - res += xfs_calc_icreate_resv_alloc(mp); - else - res += xfs_calc_create_resv_alloc(mp); - - return res + xfs_calc_iunlink_add_reservation(mp); -} - -/* - * Making a new directory is the same as creating a new file. - */ -STATIC uint -xfs_calc_mkdir_reservation( - struct xfs_mount *mp) -{ - return xfs_calc_create_reservation(mp); -} - - -/* - * Making a new symplink is the same as creating a new file, but - * with the added blocks for remote symlink data which can be up to 1kB in - * length (MAXPATHLEN). - */ -STATIC uint -xfs_calc_symlink_reservation( - struct xfs_mount *mp) -{ - return xfs_calc_create_reservation(mp) + - xfs_calc_buf_res(1, MAXPATHLEN); -} - -/* - * In freeing an inode we can modify: - * the inode being freed: inode size - * the super block free inode counter: sector size - * the agi hash list and counters: sector size - * the inode btree entry: block size - * the on disk inode before ours in the agi hash list: inode cluster size - * the inode btree: max depth * blocksize - * the allocation btrees: 2 trees * (max depth - 1) * block size - * the finobt (record insertion, removal or modification) - */ -STATIC uint -xfs_calc_ifree_reservation( - struct xfs_mount *mp) -{ - return XFS_DQUOT_LOGRES(mp) + - xfs_calc_inode_res(mp, 1) + - xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(1, XFS_FSB_TO_B(mp, 1)) + - xfs_calc_iunlink_remove_reservation(mp) + - xfs_calc_buf_res(1, 0) + - xfs_calc_buf_res(2 + mp->m_ialloc_blks + - mp->m_in_maxlevels, 0) + - xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1), - XFS_FSB_TO_B(mp, 1)) + - xfs_calc_finobt_res(mp, 0, 1); -} - -/* - * When only changing the inode we log the inode and possibly the superblock - * We also add a bit of slop for the transaction stuff. - */ -STATIC uint -xfs_calc_ichange_reservation( - struct xfs_mount *mp) -{ - return XFS_DQUOT_LOGRES(mp) + - xfs_calc_inode_res(mp, 1) + - xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); - -} - -/* - * Growing the data section of the filesystem. - * superblock - * agi and agf - * allocation btrees - */ -STATIC uint -xfs_calc_growdata_reservation( - struct xfs_mount *mp) -{ - return xfs_calc_buf_res(3, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1), - XFS_FSB_TO_B(mp, 1)); -} - -/* - * Growing the rt section of the filesystem. - * In the first set of transactions (ALLOC) we allocate space to the - * bitmap or summary files. - * superblock: sector size - * agf of the ag from which the extent is allocated: sector size - * bmap btree for bitmap/summary inode: max depth * blocksize - * bitmap/summary inode: inode size - * allocation btrees for 1 block alloc: 2 * (2 * maxdepth - 1) * blocksize - */ -STATIC uint -xfs_calc_growrtalloc_reservation( - struct xfs_mount *mp) -{ - return xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK), - XFS_FSB_TO_B(mp, 1)) + - xfs_calc_inode_res(mp, 1) + - xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1), - XFS_FSB_TO_B(mp, 1)); -} - -/* - * Growing the rt section of the filesystem. - * In the second set of transactions (ZERO) we zero the new metadata blocks. - * one bitmap/summary block: blocksize - */ -STATIC uint -xfs_calc_growrtzero_reservation( - struct xfs_mount *mp) -{ - return xfs_calc_buf_res(1, mp->m_sb.sb_blocksize); -} - -/* - * Growing the rt section of the filesystem. - * In the third set of transactions (FREE) we update metadata without - * allocating any new blocks. - * superblock: sector size - * bitmap inode: inode size - * summary inode: inode size - * one bitmap block: blocksize - * summary blocks: new summary size - */ -STATIC uint -xfs_calc_growrtfree_reservation( - struct xfs_mount *mp) -{ - return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + - xfs_calc_inode_res(mp, 2) + - xfs_calc_buf_res(1, mp->m_sb.sb_blocksize) + - xfs_calc_buf_res(1, mp->m_rsumsize); -} - -/* - * Logging the inode modification timestamp on a synchronous write. - * inode - */ -STATIC uint -xfs_calc_swrite_reservation( - struct xfs_mount *mp) -{ - return xfs_calc_inode_res(mp, 1); -} - -/* - * Logging the inode mode bits when writing a setuid/setgid file - * inode - */ -STATIC uint -xfs_calc_writeid_reservation( - struct xfs_mount *mp) -{ - return xfs_calc_inode_res(mp, 1); -} - -/* - * Converting the inode from non-attributed to attributed. - * the inode being converted: inode size - * agf block and superblock (for block allocation) - * the new block (directory sized) - * bmap blocks for the new directory block - * allocation btrees - */ -STATIC uint -xfs_calc_addafork_reservation( - struct xfs_mount *mp) -{ - return XFS_DQUOT_LOGRES(mp) + - xfs_calc_inode_res(mp, 1) + - xfs_calc_buf_res(2, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(1, mp->m_dir_geo->blksize) + - xfs_calc_buf_res(XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK) + 1, - XFS_FSB_TO_B(mp, 1)) + - xfs_calc_buf_res(xfs_allocfree_log_count(mp, 1), - XFS_FSB_TO_B(mp, 1)); -} - -/* - * Removing the attribute fork of a file - * the inode being truncated: inode size - * the inode's bmap btree: max depth * block size - * And the bmap_finish transaction can free the blocks and bmap blocks: - * the agf for each of the ags: 4 * sector size - * the agfl for each of the ags: 4 * sector size - * the super block to reflect the freed blocks: sector size - * worst case split in allocation btrees per extent assuming 4 extents: - * 4 exts * 2 trees * (2 * max depth - 1) * block size - */ -STATIC uint -xfs_calc_attrinval_reservation( - struct xfs_mount *mp) -{ - return MAX((xfs_calc_inode_res(mp, 1) + - xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK), - XFS_FSB_TO_B(mp, 1))), - (xfs_calc_buf_res(9, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(xfs_allocfree_log_count(mp, 4), - XFS_FSB_TO_B(mp, 1)))); -} - -/* - * Setting an attribute at mount time. - * the inode getting the attribute - * the superblock for allocations - * the agfs extents are allocated from - * the attribute btree * max depth - * the inode allocation btree - * Since attribute transaction space is dependent on the size of the attribute, - * the calculation is done partially at mount time and partially at runtime(see - * below). - */ -STATIC uint -xfs_calc_attrsetm_reservation( - struct xfs_mount *mp) -{ - return XFS_DQUOT_LOGRES(mp) + - xfs_calc_inode_res(mp, 1) + - xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(XFS_DA_NODE_MAXDEPTH, XFS_FSB_TO_B(mp, 1)); -} - -/* - * Setting an attribute at runtime, transaction space unit per block. - * the superblock for allocations: sector size - * the inode bmap btree could join or split: max depth * block size - * Since the runtime attribute transaction space is dependent on the total - * blocks needed for the 1st bmap, here we calculate out the space unit for - * one block so that the caller could figure out the total space according - * to the attibute extent length in blocks by: - * ext * M_RES(mp)->tr_attrsetrt.tr_logres - */ -STATIC uint -xfs_calc_attrsetrt_reservation( - struct xfs_mount *mp) -{ - return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK), - XFS_FSB_TO_B(mp, 1)); -} - -/* - * Removing an attribute. - * the inode: inode size - * the attribute btree could join: max depth * block size - * the inode bmap btree could join or split: max depth * block size - * And the bmap_finish transaction can free the attr blocks freed giving: - * the agf for the ag in which the blocks live: 2 * sector size - * the agfl for the ag in which the blocks live: 2 * sector size - * the superblock for the free block count: sector size - * the allocation btrees: 2 exts * 2 trees * (2 * max depth - 1) * block size - */ -STATIC uint -xfs_calc_attrrm_reservation( - struct xfs_mount *mp) -{ - return XFS_DQUOT_LOGRES(mp) + - MAX((xfs_calc_inode_res(mp, 1) + - xfs_calc_buf_res(XFS_DA_NODE_MAXDEPTH, - XFS_FSB_TO_B(mp, 1)) + - (uint)XFS_FSB_TO_B(mp, - XFS_BM_MAXLEVELS(mp, XFS_ATTR_FORK)) + - xfs_calc_buf_res(XFS_BM_MAXLEVELS(mp, XFS_DATA_FORK), 0)), - (xfs_calc_buf_res(5, mp->m_sb.sb_sectsize) + - xfs_calc_buf_res(xfs_allocfree_log_count(mp, 2), - XFS_FSB_TO_B(mp, 1)))); -} - -/* - * Clearing a bad agino number in an agi hash bucket. - */ -STATIC uint -xfs_calc_clear_agi_bucket_reservation( - struct xfs_mount *mp) -{ - return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); -} - -/* - * Adjusting quota limits. - * the xfs_disk_dquot_t: sizeof(struct xfs_disk_dquot) - */ -STATIC uint -xfs_calc_qm_setqlim_reservation( - struct xfs_mount *mp) -{ - return xfs_calc_buf_res(1, sizeof(struct xfs_disk_dquot)); -} - -/* - * Allocating quota on disk if needed. - * the write transaction log space for quota file extent allocation - * the unit of quota allocation: one system block size - */ -STATIC uint -xfs_calc_qm_dqalloc_reservation( - struct xfs_mount *mp) -{ - return xfs_calc_write_reservation(mp) + - xfs_calc_buf_res(1, - XFS_FSB_TO_B(mp, XFS_DQUOT_CLUSTER_SIZE_FSB) - 1); -} - -/* - * Turning off quotas. - * the xfs_qoff_logitem_t: sizeof(struct xfs_qoff_logitem) * 2 - * the superblock for the quota flags: sector size - */ -STATIC uint -xfs_calc_qm_quotaoff_reservation( - struct xfs_mount *mp) -{ - return sizeof(struct xfs_qoff_logitem) * 2 + - xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); -} - -/* - * End of turning off quotas. - * the xfs_qoff_logitem_t: sizeof(struct xfs_qoff_logitem) * 2 - */ -STATIC uint -xfs_calc_qm_quotaoff_end_reservation( - struct xfs_mount *mp) -{ - return sizeof(struct xfs_qoff_logitem) * 2; -} - -/* - * Syncing the incore super block changes to disk. - * the super block to reflect the changes: sector size - */ -STATIC uint -xfs_calc_sb_reservation( - struct xfs_mount *mp) -{ - return xfs_calc_buf_res(1, mp->m_sb.sb_sectsize); -} - -void -xfs_trans_resv_calc( - struct xfs_mount *mp, - struct xfs_trans_resv *resp) -{ - /* - * The following transactions are logged in physical format and - * require a permanent reservation on space. - */ - resp->tr_write.tr_logres = xfs_calc_write_reservation(mp); - if (xfs_sb_version_hasreflink(&mp->m_sb)) - resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT_REFLINK; - else - resp->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT; - resp->tr_write.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_itruncate.tr_logres = xfs_calc_itruncate_reservation(mp); - if (xfs_sb_version_hasreflink(&mp->m_sb)) - resp->tr_itruncate.tr_logcount = - XFS_ITRUNCATE_LOG_COUNT_REFLINK; - else - resp->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT; - resp->tr_itruncate.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_rename.tr_logres = xfs_calc_rename_reservation(mp); - resp->tr_rename.tr_logcount = XFS_RENAME_LOG_COUNT; - resp->tr_rename.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_link.tr_logres = xfs_calc_link_reservation(mp); - resp->tr_link.tr_logcount = XFS_LINK_LOG_COUNT; - resp->tr_link.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_remove.tr_logres = xfs_calc_remove_reservation(mp); - resp->tr_remove.tr_logcount = XFS_REMOVE_LOG_COUNT; - resp->tr_remove.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_symlink.tr_logres = xfs_calc_symlink_reservation(mp); - resp->tr_symlink.tr_logcount = XFS_SYMLINK_LOG_COUNT; - resp->tr_symlink.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_create.tr_logres = xfs_calc_create_reservation(mp); - resp->tr_create.tr_logcount = XFS_CREATE_LOG_COUNT; - resp->tr_create.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_create_tmpfile.tr_logres = - xfs_calc_create_tmpfile_reservation(mp); - resp->tr_create_tmpfile.tr_logcount = XFS_CREATE_TMPFILE_LOG_COUNT; - resp->tr_create_tmpfile.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_mkdir.tr_logres = xfs_calc_mkdir_reservation(mp); - resp->tr_mkdir.tr_logcount = XFS_MKDIR_LOG_COUNT; - resp->tr_mkdir.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_ifree.tr_logres = xfs_calc_ifree_reservation(mp); - resp->tr_ifree.tr_logcount = XFS_INACTIVE_LOG_COUNT; - resp->tr_ifree.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_addafork.tr_logres = xfs_calc_addafork_reservation(mp); - resp->tr_addafork.tr_logcount = XFS_ADDAFORK_LOG_COUNT; - resp->tr_addafork.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_attrinval.tr_logres = xfs_calc_attrinval_reservation(mp); - resp->tr_attrinval.tr_logcount = XFS_ATTRINVAL_LOG_COUNT; - resp->tr_attrinval.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_attrsetm.tr_logres = xfs_calc_attrsetm_reservation(mp); - resp->tr_attrsetm.tr_logcount = XFS_ATTRSET_LOG_COUNT; - resp->tr_attrsetm.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_attrrm.tr_logres = xfs_calc_attrrm_reservation(mp); - resp->tr_attrrm.tr_logcount = XFS_ATTRRM_LOG_COUNT; - resp->tr_attrrm.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_growrtalloc.tr_logres = xfs_calc_growrtalloc_reservation(mp); - resp->tr_growrtalloc.tr_logcount = XFS_DEFAULT_PERM_LOG_COUNT; - resp->tr_growrtalloc.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - resp->tr_qm_dqalloc.tr_logres = xfs_calc_qm_dqalloc_reservation(mp); - if (xfs_sb_version_hasreflink(&mp->m_sb)) - resp->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT_REFLINK; - else - resp->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT; - resp->tr_qm_dqalloc.tr_logflags |= XFS_TRANS_PERM_LOG_RES; - - /* - * The following transactions are logged in logical format with - * a default log count. - */ - resp->tr_qm_setqlim.tr_logres = xfs_calc_qm_setqlim_reservation(mp); - resp->tr_qm_setqlim.tr_logcount = XFS_DEFAULT_LOG_COUNT; - - resp->tr_qm_quotaoff.tr_logres = xfs_calc_qm_quotaoff_reservation(mp); - resp->tr_qm_quotaoff.tr_logcount = XFS_DEFAULT_LOG_COUNT; - - resp->tr_qm_equotaoff.tr_logres = - xfs_calc_qm_quotaoff_end_reservation(mp); - resp->tr_qm_equotaoff.tr_logcount = XFS_DEFAULT_LOG_COUNT; - - resp->tr_sb.tr_logres = xfs_calc_sb_reservation(mp); - resp->tr_sb.tr_logcount = XFS_DEFAULT_LOG_COUNT; - - /* The following transaction are logged in logical format */ - resp->tr_ichange.tr_logres = xfs_calc_ichange_reservation(mp); - resp->tr_growdata.tr_logres = xfs_calc_growdata_reservation(mp); - resp->tr_fsyncts.tr_logres = xfs_calc_swrite_reservation(mp); - resp->tr_writeid.tr_logres = xfs_calc_writeid_reservation(mp); - resp->tr_attrsetrt.tr_logres = xfs_calc_attrsetrt_reservation(mp); - resp->tr_clearagi.tr_logres = xfs_calc_clear_agi_bucket_reservation(mp); - resp->tr_growrtzero.tr_logres = xfs_calc_growrtzero_reservation(mp); - resp->tr_growrtfree.tr_logres = xfs_calc_growrtfree_reservation(mp); -} diff --git a/src/linux/fs/xfs/libxfs/xfs_trans_resv.h b/src/linux/fs/xfs/libxfs/xfs_trans_resv.h deleted file mode 100644 index b7e5357..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_trans_resv.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_TRANS_RESV_H__ -#define __XFS_TRANS_RESV_H__ - -struct xfs_mount; - -/* - * structure for maintaining pre-calculated transaction reservations. - */ -struct xfs_trans_res { - uint tr_logres; /* log space unit in bytes per log ticket */ - int tr_logcount; /* number of log operations per log ticket */ - int tr_logflags; /* log flags, currently only used for indicating - * a reservation request is permanent or not */ -}; - -struct xfs_trans_resv { - struct xfs_trans_res tr_write; /* extent alloc trans */ - struct xfs_trans_res tr_itruncate; /* truncate trans */ - struct xfs_trans_res tr_rename; /* rename trans */ - struct xfs_trans_res tr_link; /* link trans */ - struct xfs_trans_res tr_remove; /* unlink trans */ - struct xfs_trans_res tr_symlink; /* symlink trans */ - struct xfs_trans_res tr_create; /* create trans */ - struct xfs_trans_res tr_create_tmpfile; /* create O_TMPFILE trans */ - struct xfs_trans_res tr_mkdir; /* mkdir trans */ - struct xfs_trans_res tr_ifree; /* inode free trans */ - struct xfs_trans_res tr_ichange; /* inode update trans */ - struct xfs_trans_res tr_growdata; /* fs data section grow trans */ - struct xfs_trans_res tr_addafork; /* add inode attr fork trans */ - struct xfs_trans_res tr_writeid; /* write setuid/setgid file */ - struct xfs_trans_res tr_attrinval; /* attr fork buffer - * invalidation */ - struct xfs_trans_res tr_attrsetm; /* set/create an attribute at - * mount time */ - struct xfs_trans_res tr_attrsetrt; /* set/create an attribute at - * runtime */ - struct xfs_trans_res tr_attrrm; /* remove an attribute */ - struct xfs_trans_res tr_clearagi; /* clear agi unlinked bucket */ - struct xfs_trans_res tr_growrtalloc; /* grow realtime allocations */ - struct xfs_trans_res tr_growrtzero; /* grow realtime zeroing */ - struct xfs_trans_res tr_growrtfree; /* grow realtime freeing */ - struct xfs_trans_res tr_qm_setqlim; /* adjust quota limits */ - struct xfs_trans_res tr_qm_dqalloc; /* allocate quota on disk */ - struct xfs_trans_res tr_qm_quotaoff; /* turn quota off */ - struct xfs_trans_res tr_qm_equotaoff;/* end of turn quota off */ - struct xfs_trans_res tr_sb; /* modify superblock */ - struct xfs_trans_res tr_fsyncts; /* update timestamps on fsync */ -}; - -/* shorthand way of accessing reservation structure */ -#define M_RES(mp) (&(mp)->m_resv) - -/* - * Per-directory log reservation for any directory change. - * dir blocks: (1 btree block per level + data block + free block) * dblock size - * bmap btree: (levels + 2) * max depth * block size - * v2 directory blocks can be fragmented below the dirblksize down to the fsb - * size, so account for that in the DAENTER macros. - */ -#define XFS_DIROP_LOG_RES(mp) \ - (XFS_FSB_TO_B(mp, XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK)) + \ - (XFS_FSB_TO_B(mp, XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1))) -#define XFS_DIROP_LOG_COUNT(mp) \ - (XFS_DAENTER_BLOCKS(mp, XFS_DATA_FORK) + \ - XFS_DAENTER_BMAPS(mp, XFS_DATA_FORK) + 1) - -/* - * Various log count values. - */ -#define XFS_DEFAULT_LOG_COUNT 1 -#define XFS_DEFAULT_PERM_LOG_COUNT 2 -#define XFS_ITRUNCATE_LOG_COUNT 2 -#define XFS_ITRUNCATE_LOG_COUNT_REFLINK 8 -#define XFS_INACTIVE_LOG_COUNT 2 -#define XFS_CREATE_LOG_COUNT 2 -#define XFS_CREATE_TMPFILE_LOG_COUNT 2 -#define XFS_MKDIR_LOG_COUNT 3 -#define XFS_SYMLINK_LOG_COUNT 3 -#define XFS_REMOVE_LOG_COUNT 2 -#define XFS_LINK_LOG_COUNT 2 -#define XFS_RENAME_LOG_COUNT 2 -#define XFS_WRITE_LOG_COUNT 2 -#define XFS_WRITE_LOG_COUNT_REFLINK 8 -#define XFS_ADDAFORK_LOG_COUNT 2 -#define XFS_ATTRINVAL_LOG_COUNT 1 -#define XFS_ATTRSET_LOG_COUNT 3 -#define XFS_ATTRRM_LOG_COUNT 3 - -void xfs_trans_resv_calc(struct xfs_mount *mp, struct xfs_trans_resv *resp); -uint xfs_allocfree_log_count(struct xfs_mount *mp, uint num_ops); - -#endif /* __XFS_TRANS_RESV_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_trans_space.h b/src/linux/fs/xfs/libxfs/xfs_trans_space.h deleted file mode 100644 index 7917f6e..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_trans_space.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2000,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_TRANS_SPACE_H__ -#define __XFS_TRANS_SPACE_H__ - -/* - * Components of space reservations. - */ -#define XFS_MAX_CONTIG_RMAPS_PER_BLOCK(mp) \ - (((mp)->m_rmap_mxr[0]) - ((mp)->m_rmap_mnr[0])) -#define XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp) \ - (((mp)->m_alloc_mxr[0]) - ((mp)->m_alloc_mnr[0])) -#define XFS_EXTENTADD_SPACE_RES(mp,w) (XFS_BM_MAXLEVELS(mp,w) - 1) -#define XFS_NEXTENTADD_SPACE_RES(mp,b,w)\ - (((b + XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp) - 1) / \ - XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp)) * \ - XFS_EXTENTADD_SPACE_RES(mp,w)) -#define XFS_SWAP_RMAP_SPACE_RES(mp,b,w)\ - (((b + XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp) - 1) / \ - XFS_MAX_CONTIG_EXTENTS_PER_BLOCK(mp)) * \ - XFS_EXTENTADD_SPACE_RES(mp,w) + \ - ((b + XFS_MAX_CONTIG_RMAPS_PER_BLOCK(mp) - 1) / \ - XFS_MAX_CONTIG_RMAPS_PER_BLOCK(mp)) * \ - (mp)->m_rmap_maxlevels) -#define XFS_DAENTER_1B(mp,w) \ - ((w) == XFS_DATA_FORK ? (mp)->m_dir_geo->fsbcount : 1) -#define XFS_DAENTER_DBS(mp,w) \ - (XFS_DA_NODE_MAXDEPTH + (((w) == XFS_DATA_FORK) ? 2 : 0)) -#define XFS_DAENTER_BLOCKS(mp,w) \ - (XFS_DAENTER_1B(mp,w) * XFS_DAENTER_DBS(mp,w)) -#define XFS_DAENTER_BMAP1B(mp,w) \ - XFS_NEXTENTADD_SPACE_RES(mp, XFS_DAENTER_1B(mp, w), w) -#define XFS_DAENTER_BMAPS(mp,w) \ - (XFS_DAENTER_DBS(mp,w) * XFS_DAENTER_BMAP1B(mp,w)) -#define XFS_DAENTER_SPACE_RES(mp,w) \ - (XFS_DAENTER_BLOCKS(mp,w) + XFS_DAENTER_BMAPS(mp,w)) -#define XFS_DAREMOVE_SPACE_RES(mp,w) XFS_DAENTER_BMAPS(mp,w) -#define XFS_DIRENTER_MAX_SPLIT(mp,nl) 1 -#define XFS_DIRENTER_SPACE_RES(mp,nl) \ - (XFS_DAENTER_SPACE_RES(mp, XFS_DATA_FORK) * \ - XFS_DIRENTER_MAX_SPLIT(mp,nl)) -#define XFS_DIRREMOVE_SPACE_RES(mp) \ - XFS_DAREMOVE_SPACE_RES(mp, XFS_DATA_FORK) -#define XFS_IALLOC_SPACE_RES(mp) \ - ((mp)->m_ialloc_blks + \ - (xfs_sb_version_hasfinobt(&mp->m_sb) ? 2 : 1 * \ - ((mp)->m_in_maxlevels - 1))) - -/* - * Space reservation values for various transactions. - */ -#define XFS_ADDAFORK_SPACE_RES(mp) \ - ((mp)->m_dir_geo->fsbcount + XFS_DAENTER_BMAP1B(mp, XFS_DATA_FORK)) -#define XFS_ATTRRM_SPACE_RES(mp) \ - XFS_DAREMOVE_SPACE_RES(mp, XFS_ATTR_FORK) -/* This macro is not used - see inline code in xfs_attr_set */ -#define XFS_ATTRSET_SPACE_RES(mp, v) \ - (XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK) + XFS_B_TO_FSB(mp, v)) -#define XFS_CREATE_SPACE_RES(mp,nl) \ - (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) -#define XFS_DIOSTRAT_SPACE_RES(mp, v) \ - (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + (v)) -#define XFS_GROWFS_SPACE_RES(mp) \ - (2 * (mp)->m_ag_maxlevels) -#define XFS_GROWFSRT_SPACE_RES(mp,b) \ - ((b) + XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK)) -#define XFS_LINK_SPACE_RES(mp,nl) \ - XFS_DIRENTER_SPACE_RES(mp,nl) -#define XFS_MKDIR_SPACE_RES(mp,nl) \ - (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) -#define XFS_QM_DQALLOC_SPACE_RES(mp) \ - (XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK) + \ - XFS_DQUOT_CLUSTER_SIZE_FSB) -#define XFS_QM_QINOCREATE_SPACE_RES(mp) \ - XFS_IALLOC_SPACE_RES(mp) -#define XFS_REMOVE_SPACE_RES(mp) \ - XFS_DIRREMOVE_SPACE_RES(mp) -#define XFS_RENAME_SPACE_RES(mp,nl) \ - (XFS_DIRREMOVE_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl)) -#define XFS_SYMLINK_SPACE_RES(mp,nl,b) \ - (XFS_IALLOC_SPACE_RES(mp) + XFS_DIRENTER_SPACE_RES(mp,nl) + (b)) -#define XFS_IFREE_SPACE_RES(mp) \ - (xfs_sb_version_hasfinobt(&mp->m_sb) ? (mp)->m_in_maxlevels : 0) - - -#endif /* __XFS_TRANS_SPACE_H__ */ diff --git a/src/linux/fs/xfs/libxfs/xfs_types.h b/src/linux/fs/xfs/libxfs/xfs_types.h deleted file mode 100644 index 8d74870..0000000 --- a/src/linux/fs/xfs/libxfs/xfs_types.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_TYPES_H__ -#define __XFS_TYPES_H__ - -typedef __uint32_t prid_t; /* project ID */ - -typedef __uint32_t xfs_agblock_t; /* blockno in alloc. group */ -typedef __uint32_t xfs_agino_t; /* inode # within allocation grp */ -typedef __uint32_t xfs_extlen_t; /* extent length in blocks */ -typedef __uint32_t xfs_agnumber_t; /* allocation group number */ -typedef __int32_t xfs_extnum_t; /* # of extents in a file */ -typedef __int16_t xfs_aextnum_t; /* # extents in an attribute fork */ -typedef __int64_t xfs_fsize_t; /* bytes in a file */ -typedef __uint64_t xfs_ufsize_t; /* unsigned bytes in a file */ - -typedef __int32_t xfs_suminfo_t; /* type of bitmap summary info */ -typedef __int32_t xfs_rtword_t; /* word type for bitmap manipulations */ - -typedef __int64_t xfs_lsn_t; /* log sequence number */ -typedef __int32_t xfs_tid_t; /* transaction identifier */ - -typedef __uint32_t xfs_dablk_t; /* dir/attr block number (in file) */ -typedef __uint32_t xfs_dahash_t; /* dir/attr hash value */ - -typedef __uint64_t xfs_fsblock_t; /* blockno in filesystem (agno|agbno) */ -typedef __uint64_t xfs_rfsblock_t; /* blockno in filesystem (raw) */ -typedef __uint64_t xfs_rtblock_t; /* extent (block) in realtime area */ -typedef __uint64_t xfs_fileoff_t; /* block number in a file */ -typedef __uint64_t xfs_filblks_t; /* number of blocks in a file */ - -typedef __int64_t xfs_srtblock_t; /* signed version of xfs_rtblock_t */ -typedef __int64_t xfs_sfiloff_t; /* signed block number in a file */ - -/* - * Null values for the types. - */ -#define NULLFSBLOCK ((xfs_fsblock_t)-1) -#define NULLRFSBLOCK ((xfs_rfsblock_t)-1) -#define NULLRTBLOCK ((xfs_rtblock_t)-1) -#define NULLFILEOFF ((xfs_fileoff_t)-1) - -#define NULLAGBLOCK ((xfs_agblock_t)-1) -#define NULLAGNUMBER ((xfs_agnumber_t)-1) -#define NULLEXTNUM ((xfs_extnum_t)-1) - -#define NULLCOMMITLSN ((xfs_lsn_t)-1) - -#define NULLFSINO ((xfs_ino_t)-1) -#define NULLAGINO ((xfs_agino_t)-1) - -/* - * Max values for extlen, extnum, aextnum. - */ -#define MAXEXTLEN ((xfs_extlen_t)0x001fffff) /* 21 bits */ -#define MAXEXTNUM ((xfs_extnum_t)0x7fffffff) /* signed int */ -#define MAXAEXTNUM ((xfs_aextnum_t)0x7fff) /* signed short */ - -/* - * Minimum and maximum blocksize and sectorsize. - * The blocksize upper limit is pretty much arbitrary. - * The sectorsize upper limit is due to sizeof(sb_sectsize). - */ -#define XFS_MIN_BLOCKSIZE_LOG 9 /* i.e. 512 bytes */ -#define XFS_MAX_BLOCKSIZE_LOG 16 /* i.e. 65536 bytes */ -#define XFS_MIN_BLOCKSIZE (1 << XFS_MIN_BLOCKSIZE_LOG) -#define XFS_MAX_BLOCKSIZE (1 << XFS_MAX_BLOCKSIZE_LOG) -#define XFS_MIN_SECTORSIZE_LOG 9 /* i.e. 512 bytes */ -#define XFS_MAX_SECTORSIZE_LOG 15 /* i.e. 32768 bytes */ -#define XFS_MIN_SECTORSIZE (1 << XFS_MIN_SECTORSIZE_LOG) -#define XFS_MAX_SECTORSIZE (1 << XFS_MAX_SECTORSIZE_LOG) - -/* - * Inode fork identifiers. - */ -#define XFS_DATA_FORK 0 -#define XFS_ATTR_FORK 1 -#define XFS_COW_FORK 2 - -/* - * Min numbers of data/attr fork btree root pointers. - */ -#define MINDBTPTRS 3 -#define MINABTPTRS 2 - -/* - * MAXNAMELEN is the length (including the terminating null) of - * the longest permissible file (component) name. - */ -#define MAXNAMELEN 256 - -typedef enum { - XFS_LOOKUP_EQi, XFS_LOOKUP_LEi, XFS_LOOKUP_GEi -} xfs_lookup_t; - -typedef enum { - XFS_BTNUM_BNOi, XFS_BTNUM_CNTi, XFS_BTNUM_RMAPi, XFS_BTNUM_BMAPi, - XFS_BTNUM_INOi, XFS_BTNUM_FINOi, XFS_BTNUM_REFCi, XFS_BTNUM_MAX -} xfs_btnum_t; - -struct xfs_name { - const unsigned char *name; - int len; - int type; -}; - -/* - * uid_t and gid_t are hard-coded to 32 bits in the inode. - * Hence, an 'id' in a dquot is 32 bits.. - */ -typedef __uint32_t xfs_dqid_t; - -/* - * Constants for bit manipulations. - */ -#define XFS_NBBYLOG 3 /* log2(NBBY) */ -#define XFS_WORDLOG 2 /* log2(sizeof(xfs_rtword_t)) */ -#define XFS_NBWORDLOG (XFS_NBBYLOG + XFS_WORDLOG) -#define XFS_NBWORD (1 << XFS_NBWORDLOG) -#define XFS_WORDMASK ((1 << XFS_WORDLOG) - 1) - - -#endif /* __XFS_TYPES_H__ */ diff --git a/src/linux/fs/xfs/mrlock.h b/src/linux/fs/xfs/mrlock.h deleted file mode 100644 index e3c92d1..0000000 --- a/src/linux/fs/xfs/mrlock.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2000-2006 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_SUPPORT_MRLOCK_H__ -#define __XFS_SUPPORT_MRLOCK_H__ - -#include - -typedef struct { - struct rw_semaphore mr_lock; -#if defined(DEBUG) || defined(XFS_WARN) - int mr_writer; -#endif -} mrlock_t; - -#if defined(DEBUG) || defined(XFS_WARN) -#define mrinit(mrp, name) \ - do { (mrp)->mr_writer = 0; init_rwsem(&(mrp)->mr_lock); } while (0) -#else -#define mrinit(mrp, name) \ - do { init_rwsem(&(mrp)->mr_lock); } while (0) -#endif - -#define mrlock_init(mrp, t,n,s) mrinit(mrp, n) -#define mrfree(mrp) do { } while (0) - -static inline void mraccess_nested(mrlock_t *mrp, int subclass) -{ - down_read_nested(&mrp->mr_lock, subclass); -} - -static inline void mrupdate_nested(mrlock_t *mrp, int subclass) -{ - down_write_nested(&mrp->mr_lock, subclass); -#if defined(DEBUG) || defined(XFS_WARN) - mrp->mr_writer = 1; -#endif -} - -static inline int mrtryaccess(mrlock_t *mrp) -{ - return down_read_trylock(&mrp->mr_lock); -} - -static inline int mrtryupdate(mrlock_t *mrp) -{ - if (!down_write_trylock(&mrp->mr_lock)) - return 0; -#if defined(DEBUG) || defined(XFS_WARN) - mrp->mr_writer = 1; -#endif - return 1; -} - -static inline void mrunlock_excl(mrlock_t *mrp) -{ -#if defined(DEBUG) || defined(XFS_WARN) - mrp->mr_writer = 0; -#endif - up_write(&mrp->mr_lock); -} - -static inline void mrunlock_shared(mrlock_t *mrp) -{ - up_read(&mrp->mr_lock); -} - -static inline void mrdemote(mrlock_t *mrp) -{ -#if defined(DEBUG) || defined(XFS_WARN) - mrp->mr_writer = 0; -#endif - downgrade_write(&mrp->mr_lock); -} - -#endif /* __XFS_SUPPORT_MRLOCK_H__ */ diff --git a/src/linux/fs/xfs/uuid.c b/src/linux/fs/xfs/uuid.c deleted file mode 100644 index b83f76b..0000000 --- a/src/linux/fs/xfs/uuid.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include - -/* IRIX interpretation of an uuid_t */ -typedef struct { - __be32 uu_timelow; - __be16 uu_timemid; - __be16 uu_timehi; - __be16 uu_clockseq; - __be16 uu_node[3]; -} xfs_uu_t; - -/* - * uuid_getnodeuniq - obtain the node unique fields of a UUID. - * - * This is not in any way a standard or condoned UUID function; - * it just something that's needed for user-level file handles. - */ -void -uuid_getnodeuniq(uuid_t *uuid, int fsid [2]) -{ - xfs_uu_t *uup = (xfs_uu_t *)uuid; - - fsid[0] = (be16_to_cpu(uup->uu_clockseq) << 16) | - be16_to_cpu(uup->uu_timemid); - fsid[1] = be32_to_cpu(uup->uu_timelow); -} - -int -uuid_is_nil(uuid_t *uuid) -{ - int i; - char *cp = (char *)uuid; - - if (uuid == NULL) - return 0; - /* implied check of version number here... */ - for (i = 0; i < sizeof *uuid; i++) - if (*cp++) return 0; /* not nil */ - return 1; /* is nil */ -} - -int -uuid_equal(uuid_t *uuid1, uuid_t *uuid2) -{ - return memcmp(uuid1, uuid2, sizeof(uuid_t)) ? 0 : 1; -} diff --git a/src/linux/fs/xfs/uuid.h b/src/linux/fs/xfs/uuid.h deleted file mode 100644 index 104db0f..0000000 --- a/src/linux/fs/xfs/uuid.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_SUPPORT_UUID_H__ -#define __XFS_SUPPORT_UUID_H__ - -typedef struct { - unsigned char __u_bits[16]; -} uuid_t; - -extern int uuid_is_nil(uuid_t *uuid); -extern int uuid_equal(uuid_t *uuid1, uuid_t *uuid2); -extern void uuid_getnodeuniq(uuid_t *uuid, int fsid [2]); - -static inline void -uuid_copy(uuid_t *dst, uuid_t *src) -{ - memcpy(dst, src, sizeof(uuid_t)); -} - -#endif /* __XFS_SUPPORT_UUID_H__ */ diff --git a/src/linux/fs/xfs/xfs.h b/src/linux/fs/xfs/xfs.h deleted file mode 100644 index a742c47..0000000 --- a/src/linux/fs/xfs/xfs.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_H__ -#define __XFS_H__ - -#ifdef CONFIG_XFS_DEBUG -#define STATIC -#define DEBUG 1 -#define XFS_BUF_LOCK_TRACKING 1 -#endif - -#ifdef CONFIG_XFS_WARN -#define XFS_WARN 1 -#endif - - -#include "xfs_linux.h" - -#endif /* __XFS_H__ */ diff --git a/src/linux/fs/xfs/xfs_acl.c b/src/linux/fs/xfs/xfs_acl.c deleted file mode 100644 index b468e04..0000000 --- a/src/linux/fs/xfs/xfs_acl.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (c) 2008, Christoph Hellwig - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_inode.h" -#include "xfs_acl.h" -#include "xfs_attr.h" -#include "xfs_trace.h" -#include -#include -#include - - -/* - * Locking scheme: - * - all ACL updates are protected by inode->i_mutex, which is taken before - * calling into this file. - */ - -STATIC struct posix_acl * -xfs_acl_from_disk( - const struct xfs_acl *aclp, - int len, - int max_entries) -{ - struct posix_acl_entry *acl_e; - struct posix_acl *acl; - const struct xfs_acl_entry *ace; - unsigned int count, i; - - if (len < sizeof(*aclp)) - return ERR_PTR(-EFSCORRUPTED); - count = be32_to_cpu(aclp->acl_cnt); - if (count > max_entries || XFS_ACL_SIZE(count) != len) - return ERR_PTR(-EFSCORRUPTED); - - acl = posix_acl_alloc(count, GFP_KERNEL); - if (!acl) - return ERR_PTR(-ENOMEM); - - for (i = 0; i < count; i++) { - acl_e = &acl->a_entries[i]; - ace = &aclp->acl_entry[i]; - - /* - * The tag is 32 bits on disk and 16 bits in core. - * - * Because every access to it goes through the core - * format first this is not a problem. - */ - acl_e->e_tag = be32_to_cpu(ace->ae_tag); - acl_e->e_perm = be16_to_cpu(ace->ae_perm); - - switch (acl_e->e_tag) { - case ACL_USER: - acl_e->e_uid = xfs_uid_to_kuid(be32_to_cpu(ace->ae_id)); - break; - case ACL_GROUP: - acl_e->e_gid = xfs_gid_to_kgid(be32_to_cpu(ace->ae_id)); - break; - case ACL_USER_OBJ: - case ACL_GROUP_OBJ: - case ACL_MASK: - case ACL_OTHER: - break; - default: - goto fail; - } - } - return acl; - -fail: - posix_acl_release(acl); - return ERR_PTR(-EINVAL); -} - -STATIC void -xfs_acl_to_disk(struct xfs_acl *aclp, const struct posix_acl *acl) -{ - const struct posix_acl_entry *acl_e; - struct xfs_acl_entry *ace; - int i; - - aclp->acl_cnt = cpu_to_be32(acl->a_count); - for (i = 0; i < acl->a_count; i++) { - ace = &aclp->acl_entry[i]; - acl_e = &acl->a_entries[i]; - - ace->ae_tag = cpu_to_be32(acl_e->e_tag); - switch (acl_e->e_tag) { - case ACL_USER: - ace->ae_id = cpu_to_be32(xfs_kuid_to_uid(acl_e->e_uid)); - break; - case ACL_GROUP: - ace->ae_id = cpu_to_be32(xfs_kgid_to_gid(acl_e->e_gid)); - break; - default: - ace->ae_id = cpu_to_be32(ACL_UNDEFINED_ID); - break; - } - - ace->ae_perm = cpu_to_be16(acl_e->e_perm); - } -} - -struct posix_acl * -xfs_get_acl(struct inode *inode, int type) -{ - struct xfs_inode *ip = XFS_I(inode); - struct posix_acl *acl = NULL; - struct xfs_acl *xfs_acl; - unsigned char *ea_name; - int error; - int len; - - trace_xfs_get_acl(ip); - - switch (type) { - case ACL_TYPE_ACCESS: - ea_name = SGI_ACL_FILE; - break; - case ACL_TYPE_DEFAULT: - ea_name = SGI_ACL_DEFAULT; - break; - default: - BUG(); - } - - /* - * If we have a cached ACLs value just return it, not need to - * go out to the disk. - */ - len = XFS_ACL_MAX_SIZE(ip->i_mount); - xfs_acl = kmem_zalloc_large(len, KM_SLEEP); - if (!xfs_acl) - return ERR_PTR(-ENOMEM); - - error = xfs_attr_get(ip, ea_name, (unsigned char *)xfs_acl, - &len, ATTR_ROOT); - if (error) { - /* - * If the attribute doesn't exist make sure we have a negative - * cache entry, for any other error assume it is transient. - */ - if (error != -ENOATTR) - acl = ERR_PTR(error); - } else { - acl = xfs_acl_from_disk(xfs_acl, len, - XFS_ACL_MAX_ENTRIES(ip->i_mount)); - } - kmem_free(xfs_acl); - return acl; -} - -STATIC int -__xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) -{ - struct xfs_inode *ip = XFS_I(inode); - unsigned char *ea_name; - int error; - - switch (type) { - case ACL_TYPE_ACCESS: - ea_name = SGI_ACL_FILE; - break; - case ACL_TYPE_DEFAULT: - if (!S_ISDIR(inode->i_mode)) - return acl ? -EACCES : 0; - ea_name = SGI_ACL_DEFAULT; - break; - default: - return -EINVAL; - } - - if (acl) { - struct xfs_acl *xfs_acl; - int len = XFS_ACL_MAX_SIZE(ip->i_mount); - - xfs_acl = kmem_zalloc_large(len, KM_SLEEP); - if (!xfs_acl) - return -ENOMEM; - - xfs_acl_to_disk(xfs_acl, acl); - - /* subtract away the unused acl entries */ - len -= sizeof(struct xfs_acl_entry) * - (XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count); - - error = xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl, - len, ATTR_ROOT); - - kmem_free(xfs_acl); - } else { - /* - * A NULL ACL argument means we want to remove the ACL. - */ - error = xfs_attr_remove(ip, ea_name, ATTR_ROOT); - - /* - * If the attribute didn't exist to start with that's fine. - */ - if (error == -ENOATTR) - error = 0; - } - - if (!error) - set_cached_acl(inode, type, acl); - return error; -} - -static int -xfs_set_mode(struct inode *inode, umode_t mode) -{ - int error = 0; - - if (mode != inode->i_mode) { - struct iattr iattr; - - iattr.ia_valid = ATTR_MODE | ATTR_CTIME; - iattr.ia_mode = mode; - iattr.ia_ctime = current_time(inode); - - error = xfs_setattr_nonsize(XFS_I(inode), &iattr, XFS_ATTR_NOACL); - } - - return error; -} - -int -xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type) -{ - int error = 0; - - if (!acl) - goto set_acl; - - error = -E2BIG; - if (acl->a_count > XFS_ACL_MAX_ENTRIES(XFS_M(inode->i_sb))) - return error; - - if (type == ACL_TYPE_ACCESS) { - umode_t mode; - - error = posix_acl_update_mode(inode, &mode, &acl); - if (error) - return error; - error = xfs_set_mode(inode, mode); - if (error) - return error; - } - - set_acl: - return __xfs_set_acl(inode, type, acl); -} diff --git a/src/linux/fs/xfs/xfs_acl.h b/src/linux/fs/xfs/xfs_acl.h deleted file mode 100644 index 286fa89..0000000 --- a/src/linux/fs/xfs/xfs_acl.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2001-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_ACL_H__ -#define __XFS_ACL_H__ - -struct inode; -struct posix_acl; - -#ifdef CONFIG_XFS_POSIX_ACL -extern struct posix_acl *xfs_get_acl(struct inode *inode, int type); -extern int xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type); -#else -static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type) -{ - return NULL; -} -# define xfs_set_acl NULL -#endif /* CONFIG_XFS_POSIX_ACL */ - -extern void xfs_forget_acl(struct inode *inode, const char *name, int xflags); - -#endif /* __XFS_ACL_H__ */ diff --git a/src/linux/fs/xfs/xfs_aops.c b/src/linux/fs/xfs/xfs_aops.c deleted file mode 100644 index 3e57a56..0000000 --- a/src/linux/fs/xfs/xfs_aops.c +++ /dev/null @@ -1,1703 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_alloc.h" -#include "xfs_error.h" -#include "xfs_iomap.h" -#include "xfs_trace.h" -#include "xfs_bmap.h" -#include "xfs_bmap_util.h" -#include "xfs_bmap_btree.h" -#include "xfs_reflink.h" -#include -#include -#include -#include - -/* flags for direct write completions */ -#define XFS_DIO_FLAG_UNWRITTEN (1 << 0) -#define XFS_DIO_FLAG_APPEND (1 << 1) -#define XFS_DIO_FLAG_COW (1 << 2) - -/* - * structure owned by writepages passed to individual writepage calls - */ -struct xfs_writepage_ctx { - struct xfs_bmbt_irec imap; - bool imap_valid; - unsigned int io_type; - struct xfs_ioend *ioend; - sector_t last_block; -}; - -void -xfs_count_page_state( - struct page *page, - int *delalloc, - int *unwritten) -{ - struct buffer_head *bh, *head; - - *delalloc = *unwritten = 0; - - bh = head = page_buffers(page); - do { - if (buffer_unwritten(bh)) - (*unwritten) = 1; - else if (buffer_delay(bh)) - (*delalloc) = 1; - } while ((bh = bh->b_this_page) != head); -} - -struct block_device * -xfs_find_bdev_for_inode( - struct inode *inode) -{ - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; - - if (XFS_IS_REALTIME_INODE(ip)) - return mp->m_rtdev_targp->bt_bdev; - else - return mp->m_ddev_targp->bt_bdev; -} - -/* - * We're now finished for good with this page. Update the page state via the - * associated buffer_heads, paying attention to the start and end offsets that - * we need to process on the page. - * - * Landmine Warning: bh->b_end_io() will call end_page_writeback() on the last - * buffer in the IO. Once it does this, it is unsafe to access the bufferhead or - * the page at all, as we may be racing with memory reclaim and it can free both - * the bufferhead chain and the page as it will see the page as clean and - * unused. - */ -static void -xfs_finish_page_writeback( - struct inode *inode, - struct bio_vec *bvec, - int error) -{ - unsigned int end = bvec->bv_offset + bvec->bv_len - 1; - struct buffer_head *head, *bh, *next; - unsigned int off = 0; - unsigned int bsize; - - ASSERT(bvec->bv_offset < PAGE_SIZE); - ASSERT((bvec->bv_offset & ((1 << inode->i_blkbits) - 1)) == 0); - ASSERT(end < PAGE_SIZE); - ASSERT((bvec->bv_len & ((1 << inode->i_blkbits) - 1)) == 0); - - bh = head = page_buffers(bvec->bv_page); - - bsize = bh->b_size; - do { - next = bh->b_this_page; - if (off < bvec->bv_offset) - goto next_bh; - if (off > end) - break; - bh->b_end_io(bh, !error); -next_bh: - off += bsize; - } while ((bh = next) != head); -} - -/* - * We're now finished for good with this ioend structure. Update the page - * state, release holds on bios, and finally free up memory. Do not use the - * ioend after this. - */ -STATIC void -xfs_destroy_ioend( - struct xfs_ioend *ioend, - int error) -{ - struct inode *inode = ioend->io_inode; - struct bio *last = ioend->io_bio; - struct bio *bio, *next; - - for (bio = &ioend->io_inline_bio; bio; bio = next) { - struct bio_vec *bvec; - int i; - - /* - * For the last bio, bi_private points to the ioend, so we - * need to explicitly end the iteration here. - */ - if (bio == last) - next = NULL; - else - next = bio->bi_private; - - /* walk each page on bio, ending page IO on them */ - bio_for_each_segment_all(bvec, bio, i) - xfs_finish_page_writeback(inode, bvec, error); - - bio_put(bio); - } -} - -/* - * Fast and loose check if this write could update the on-disk inode size. - */ -static inline bool xfs_ioend_is_append(struct xfs_ioend *ioend) -{ - return ioend->io_offset + ioend->io_size > - XFS_I(ioend->io_inode)->i_d.di_size; -} - -STATIC int -xfs_setfilesize_trans_alloc( - struct xfs_ioend *ioend) -{ - struct xfs_mount *mp = XFS_I(ioend->io_inode)->i_mount; - struct xfs_trans *tp; - int error; - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp); - if (error) - return error; - - ioend->io_append_trans = tp; - - /* - * We may pass freeze protection with a transaction. So tell lockdep - * we released it. - */ - __sb_writers_release(ioend->io_inode->i_sb, SB_FREEZE_FS); - /* - * We hand off the transaction to the completion thread now, so - * clear the flag here. - */ - current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); - return 0; -} - -/* - * Update on-disk file size now that data has been written to disk. - */ -STATIC int -__xfs_setfilesize( - struct xfs_inode *ip, - struct xfs_trans *tp, - xfs_off_t offset, - size_t size) -{ - xfs_fsize_t isize; - - xfs_ilock(ip, XFS_ILOCK_EXCL); - isize = xfs_new_eof(ip, offset + size); - if (!isize) { - xfs_iunlock(ip, XFS_ILOCK_EXCL); - xfs_trans_cancel(tp); - return 0; - } - - trace_xfs_setfilesize(ip, offset, size); - - ip->i_d.di_size = isize; - xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - - return xfs_trans_commit(tp); -} - -int -xfs_setfilesize( - struct xfs_inode *ip, - xfs_off_t offset, - size_t size) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_trans *tp; - int error; - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp); - if (error) - return error; - - return __xfs_setfilesize(ip, tp, offset, size); -} - -STATIC int -xfs_setfilesize_ioend( - struct xfs_ioend *ioend, - int error) -{ - struct xfs_inode *ip = XFS_I(ioend->io_inode); - struct xfs_trans *tp = ioend->io_append_trans; - - /* - * The transaction may have been allocated in the I/O submission thread, - * thus we need to mark ourselves as being in a transaction manually. - * Similarly for freeze protection. - */ - current_set_flags_nested(&tp->t_pflags, PF_FSTRANS); - __sb_writers_acquired(VFS_I(ip)->i_sb, SB_FREEZE_FS); - - /* we abort the update if there was an IO error */ - if (error) { - xfs_trans_cancel(tp); - return error; - } - - return __xfs_setfilesize(ip, tp, ioend->io_offset, ioend->io_size); -} - -/* - * IO write completion. - */ -STATIC void -xfs_end_io( - struct work_struct *work) -{ - struct xfs_ioend *ioend = - container_of(work, struct xfs_ioend, io_work); - struct xfs_inode *ip = XFS_I(ioend->io_inode); - int error = ioend->io_bio->bi_error; - - /* - * Set an error if the mount has shut down and proceed with end I/O - * processing so it can perform whatever cleanups are necessary. - */ - if (XFS_FORCED_SHUTDOWN(ip->i_mount)) - error = -EIO; - - /* - * For a CoW extent, we need to move the mapping from the CoW fork - * to the data fork. If instead an error happened, just dump the - * new blocks. - */ - if (ioend->io_type == XFS_IO_COW) { - if (error) - goto done; - if (ioend->io_bio->bi_error) { - error = xfs_reflink_cancel_cow_range(ip, - ioend->io_offset, ioend->io_size); - goto done; - } - error = xfs_reflink_end_cow(ip, ioend->io_offset, - ioend->io_size); - if (error) - goto done; - } - - /* - * For unwritten extents we need to issue transactions to convert a - * range to normal written extens after the data I/O has finished. - * Detecting and handling completion IO errors is done individually - * for each case as different cleanup operations need to be performed - * on error. - */ - if (ioend->io_type == XFS_IO_UNWRITTEN) { - if (error) - goto done; - error = xfs_iomap_write_unwritten(ip, ioend->io_offset, - ioend->io_size); - } else if (ioend->io_append_trans) { - error = xfs_setfilesize_ioend(ioend, error); - } else { - ASSERT(!xfs_ioend_is_append(ioend) || - ioend->io_type == XFS_IO_COW); - } - -done: - xfs_destroy_ioend(ioend, error); -} - -STATIC void -xfs_end_bio( - struct bio *bio) -{ - struct xfs_ioend *ioend = bio->bi_private; - struct xfs_mount *mp = XFS_I(ioend->io_inode)->i_mount; - - if (ioend->io_type == XFS_IO_UNWRITTEN || ioend->io_type == XFS_IO_COW) - queue_work(mp->m_unwritten_workqueue, &ioend->io_work); - else if (ioend->io_append_trans) - queue_work(mp->m_data_workqueue, &ioend->io_work); - else - xfs_destroy_ioend(ioend, bio->bi_error); -} - -STATIC int -xfs_map_blocks( - struct inode *inode, - loff_t offset, - struct xfs_bmbt_irec *imap, - int type) -{ - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; - ssize_t count = 1 << inode->i_blkbits; - xfs_fileoff_t offset_fsb, end_fsb; - int error = 0; - int bmapi_flags = XFS_BMAPI_ENTIRE; - int nimaps = 1; - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - ASSERT(type != XFS_IO_COW); - if (type == XFS_IO_UNWRITTEN) - bmapi_flags |= XFS_BMAPI_IGSTATE; - - xfs_ilock(ip, XFS_ILOCK_SHARED); - ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || - (ip->i_df.if_flags & XFS_IFEXTENTS)); - ASSERT(offset <= mp->m_super->s_maxbytes); - - if (offset + count > mp->m_super->s_maxbytes) - count = mp->m_super->s_maxbytes - offset; - end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count); - offset_fsb = XFS_B_TO_FSBT(mp, offset); - error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, - imap, &nimaps, bmapi_flags); - /* - * Truncate an overwrite extent if there's a pending CoW - * reservation before the end of this extent. This forces us - * to come back to writepage to take care of the CoW. - */ - if (nimaps && type == XFS_IO_OVERWRITE) - xfs_reflink_trim_irec_to_next_cow(ip, offset_fsb, imap); - xfs_iunlock(ip, XFS_ILOCK_SHARED); - - if (error) - return error; - - if (type == XFS_IO_DELALLOC && - (!nimaps || isnullstartblock(imap->br_startblock))) { - error = xfs_iomap_write_allocate(ip, XFS_DATA_FORK, offset, - imap); - if (!error) - trace_xfs_map_blocks_alloc(ip, offset, count, type, imap); - return error; - } - -#ifdef DEBUG - if (type == XFS_IO_UNWRITTEN) { - ASSERT(nimaps); - ASSERT(imap->br_startblock != HOLESTARTBLOCK); - ASSERT(imap->br_startblock != DELAYSTARTBLOCK); - } -#endif - if (nimaps) - trace_xfs_map_blocks_found(ip, offset, count, type, imap); - return 0; -} - -STATIC bool -xfs_imap_valid( - struct inode *inode, - struct xfs_bmbt_irec *imap, - xfs_off_t offset) -{ - offset >>= inode->i_blkbits; - - return offset >= imap->br_startoff && - offset < imap->br_startoff + imap->br_blockcount; -} - -STATIC void -xfs_start_buffer_writeback( - struct buffer_head *bh) -{ - ASSERT(buffer_mapped(bh)); - ASSERT(buffer_locked(bh)); - ASSERT(!buffer_delay(bh)); - ASSERT(!buffer_unwritten(bh)); - - mark_buffer_async_write(bh); - set_buffer_uptodate(bh); - clear_buffer_dirty(bh); -} - -STATIC void -xfs_start_page_writeback( - struct page *page, - int clear_dirty) -{ - ASSERT(PageLocked(page)); - ASSERT(!PageWriteback(page)); - - /* - * if the page was not fully cleaned, we need to ensure that the higher - * layers come back to it correctly. That means we need to keep the page - * dirty, and for WB_SYNC_ALL writeback we need to ensure the - * PAGECACHE_TAG_TOWRITE index mark is not removed so another attempt to - * write this page in this writeback sweep will be made. - */ - if (clear_dirty) { - clear_page_dirty_for_io(page); - set_page_writeback(page); - } else - set_page_writeback_keepwrite(page); - - unlock_page(page); -} - -static inline int xfs_bio_add_buffer(struct bio *bio, struct buffer_head *bh) -{ - return bio_add_page(bio, bh->b_page, bh->b_size, bh_offset(bh)); -} - -/* - * Submit the bio for an ioend. We are passed an ioend with a bio attached to - * it, and we submit that bio. The ioend may be used for multiple bio - * submissions, so we only want to allocate an append transaction for the ioend - * once. In the case of multiple bio submission, each bio will take an IO - * reference to the ioend to ensure that the ioend completion is only done once - * all bios have been submitted and the ioend is really done. - * - * If @fail is non-zero, it means that we have a situation where some part of - * the submission process has failed after we have marked paged for writeback - * and unlocked them. In this situation, we need to fail the bio and ioend - * rather than submit it to IO. This typically only happens on a filesystem - * shutdown. - */ -STATIC int -xfs_submit_ioend( - struct writeback_control *wbc, - struct xfs_ioend *ioend, - int status) -{ - /* Reserve log space if we might write beyond the on-disk inode size. */ - if (!status && - ioend->io_type != XFS_IO_UNWRITTEN && - xfs_ioend_is_append(ioend) && - !ioend->io_append_trans) - status = xfs_setfilesize_trans_alloc(ioend); - - ioend->io_bio->bi_private = ioend; - ioend->io_bio->bi_end_io = xfs_end_bio; - bio_set_op_attrs(ioend->io_bio, REQ_OP_WRITE, - (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : 0); - /* - * If we are failing the IO now, just mark the ioend with an - * error and finish it. This will run IO completion immediately - * as there is only one reference to the ioend at this point in - * time. - */ - if (status) { - ioend->io_bio->bi_error = status; - bio_endio(ioend->io_bio); - return status; - } - - submit_bio(ioend->io_bio); - return 0; -} - -static void -xfs_init_bio_from_bh( - struct bio *bio, - struct buffer_head *bh) -{ - bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9); - bio->bi_bdev = bh->b_bdev; -} - -static struct xfs_ioend * -xfs_alloc_ioend( - struct inode *inode, - unsigned int type, - xfs_off_t offset, - struct buffer_head *bh) -{ - struct xfs_ioend *ioend; - struct bio *bio; - - bio = bio_alloc_bioset(GFP_NOFS, BIO_MAX_PAGES, xfs_ioend_bioset); - xfs_init_bio_from_bh(bio, bh); - - ioend = container_of(bio, struct xfs_ioend, io_inline_bio); - INIT_LIST_HEAD(&ioend->io_list); - ioend->io_type = type; - ioend->io_inode = inode; - ioend->io_size = 0; - ioend->io_offset = offset; - INIT_WORK(&ioend->io_work, xfs_end_io); - ioend->io_append_trans = NULL; - ioend->io_bio = bio; - return ioend; -} - -/* - * Allocate a new bio, and chain the old bio to the new one. - * - * Note that we have to do perform the chaining in this unintuitive order - * so that the bi_private linkage is set up in the right direction for the - * traversal in xfs_destroy_ioend(). - */ -static void -xfs_chain_bio( - struct xfs_ioend *ioend, - struct writeback_control *wbc, - struct buffer_head *bh) -{ - struct bio *new; - - new = bio_alloc(GFP_NOFS, BIO_MAX_PAGES); - xfs_init_bio_from_bh(new, bh); - - bio_chain(ioend->io_bio, new); - bio_get(ioend->io_bio); /* for xfs_destroy_ioend */ - bio_set_op_attrs(ioend->io_bio, REQ_OP_WRITE, - (wbc->sync_mode == WB_SYNC_ALL) ? WRITE_SYNC : 0); - submit_bio(ioend->io_bio); - ioend->io_bio = new; -} - -/* - * Test to see if we've been building up a completion structure for - * earlier buffers -- if so, we try to append to this ioend if we - * can, otherwise we finish off any current ioend and start another. - * Return the ioend we finished off so that the caller can submit it - * once it has finished processing the dirty page. - */ -STATIC void -xfs_add_to_ioend( - struct inode *inode, - struct buffer_head *bh, - xfs_off_t offset, - struct xfs_writepage_ctx *wpc, - struct writeback_control *wbc, - struct list_head *iolist) -{ - if (!wpc->ioend || wpc->io_type != wpc->ioend->io_type || - bh->b_blocknr != wpc->last_block + 1 || - offset != wpc->ioend->io_offset + wpc->ioend->io_size) { - if (wpc->ioend) - list_add(&wpc->ioend->io_list, iolist); - wpc->ioend = xfs_alloc_ioend(inode, wpc->io_type, offset, bh); - } - - /* - * If the buffer doesn't fit into the bio we need to allocate a new - * one. This shouldn't happen more than once for a given buffer. - */ - while (xfs_bio_add_buffer(wpc->ioend->io_bio, bh) != bh->b_size) - xfs_chain_bio(wpc->ioend, wbc, bh); - - wpc->ioend->io_size += bh->b_size; - wpc->last_block = bh->b_blocknr; - xfs_start_buffer_writeback(bh); -} - -STATIC void -xfs_map_buffer( - struct inode *inode, - struct buffer_head *bh, - struct xfs_bmbt_irec *imap, - xfs_off_t offset) -{ - sector_t bn; - struct xfs_mount *m = XFS_I(inode)->i_mount; - xfs_off_t iomap_offset = XFS_FSB_TO_B(m, imap->br_startoff); - xfs_daddr_t iomap_bn = xfs_fsb_to_db(XFS_I(inode), imap->br_startblock); - - ASSERT(imap->br_startblock != HOLESTARTBLOCK); - ASSERT(imap->br_startblock != DELAYSTARTBLOCK); - - bn = (iomap_bn >> (inode->i_blkbits - BBSHIFT)) + - ((offset - iomap_offset) >> inode->i_blkbits); - - ASSERT(bn || XFS_IS_REALTIME_INODE(XFS_I(inode))); - - bh->b_blocknr = bn; - set_buffer_mapped(bh); -} - -STATIC void -xfs_map_at_offset( - struct inode *inode, - struct buffer_head *bh, - struct xfs_bmbt_irec *imap, - xfs_off_t offset) -{ - ASSERT(imap->br_startblock != HOLESTARTBLOCK); - ASSERT(imap->br_startblock != DELAYSTARTBLOCK); - - xfs_map_buffer(inode, bh, imap, offset); - set_buffer_mapped(bh); - clear_buffer_delay(bh); - clear_buffer_unwritten(bh); -} - -/* - * Test if a given page contains at least one buffer of a given @type. - * If @check_all_buffers is true, then we walk all the buffers in the page to - * try to find one of the type passed in. If it is not set, then the caller only - * needs to check the first buffer on the page for a match. - */ -STATIC bool -xfs_check_page_type( - struct page *page, - unsigned int type, - bool check_all_buffers) -{ - struct buffer_head *bh; - struct buffer_head *head; - - if (PageWriteback(page)) - return false; - if (!page->mapping) - return false; - if (!page_has_buffers(page)) - return false; - - bh = head = page_buffers(page); - do { - if (buffer_unwritten(bh)) { - if (type == XFS_IO_UNWRITTEN) - return true; - } else if (buffer_delay(bh)) { - if (type == XFS_IO_DELALLOC) - return true; - } else if (buffer_dirty(bh) && buffer_mapped(bh)) { - if (type == XFS_IO_OVERWRITE) - return true; - } - - /* If we are only checking the first buffer, we are done now. */ - if (!check_all_buffers) - break; - } while ((bh = bh->b_this_page) != head); - - return false; -} - -STATIC void -xfs_vm_invalidatepage( - struct page *page, - unsigned int offset, - unsigned int length) -{ - trace_xfs_invalidatepage(page->mapping->host, page, offset, - length); - block_invalidatepage(page, offset, length); -} - -/* - * If the page has delalloc buffers on it, we need to punch them out before we - * invalidate the page. If we don't, we leave a stale delalloc mapping on the - * inode that can trip a BUG() in xfs_get_blocks() later on if a direct IO read - * is done on that same region - the delalloc extent is returned when none is - * supposed to be there. - * - * We prevent this by truncating away the delalloc regions on the page before - * invalidating it. Because they are delalloc, we can do this without needing a - * transaction. Indeed - if we get ENOSPC errors, we have to be able to do this - * truncation without a transaction as there is no space left for block - * reservation (typically why we see a ENOSPC in writeback). - * - * This is not a performance critical path, so for now just do the punching a - * buffer head at a time. - */ -STATIC void -xfs_aops_discard_page( - struct page *page) -{ - struct inode *inode = page->mapping->host; - struct xfs_inode *ip = XFS_I(inode); - struct buffer_head *bh, *head; - loff_t offset = page_offset(page); - - if (!xfs_check_page_type(page, XFS_IO_DELALLOC, true)) - goto out_invalidate; - - if (XFS_FORCED_SHUTDOWN(ip->i_mount)) - goto out_invalidate; - - xfs_alert(ip->i_mount, - "page discard on page %p, inode 0x%llx, offset %llu.", - page, ip->i_ino, offset); - - xfs_ilock(ip, XFS_ILOCK_EXCL); - bh = head = page_buffers(page); - do { - int error; - xfs_fileoff_t start_fsb; - - if (!buffer_delay(bh)) - goto next_buffer; - - start_fsb = XFS_B_TO_FSBT(ip->i_mount, offset); - error = xfs_bmap_punch_delalloc_range(ip, start_fsb, 1); - if (error) { - /* something screwed, just bail */ - if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { - xfs_alert(ip->i_mount, - "page discard unable to remove delalloc mapping."); - } - break; - } -next_buffer: - offset += 1 << inode->i_blkbits; - - } while ((bh = bh->b_this_page) != head); - - xfs_iunlock(ip, XFS_ILOCK_EXCL); -out_invalidate: - xfs_vm_invalidatepage(page, 0, PAGE_SIZE); - return; -} - -static int -xfs_map_cow( - struct xfs_writepage_ctx *wpc, - struct inode *inode, - loff_t offset, - unsigned int *new_type) -{ - struct xfs_inode *ip = XFS_I(inode); - struct xfs_bmbt_irec imap; - bool is_cow = false, need_alloc = false; - int error; - - /* - * If we already have a valid COW mapping keep using it. - */ - if (wpc->io_type == XFS_IO_COW) { - wpc->imap_valid = xfs_imap_valid(inode, &wpc->imap, offset); - if (wpc->imap_valid) { - *new_type = XFS_IO_COW; - return 0; - } - } - - /* - * Else we need to check if there is a COW mapping at this offset. - */ - xfs_ilock(ip, XFS_ILOCK_SHARED); - is_cow = xfs_reflink_find_cow_mapping(ip, offset, &imap, &need_alloc); - xfs_iunlock(ip, XFS_ILOCK_SHARED); - - if (!is_cow) - return 0; - - /* - * And if the COW mapping has a delayed extent here we need to - * allocate real space for it now. - */ - if (need_alloc) { - error = xfs_iomap_write_allocate(ip, XFS_COW_FORK, offset, - &imap); - if (error) - return error; - } - - wpc->io_type = *new_type = XFS_IO_COW; - wpc->imap_valid = true; - wpc->imap = imap; - return 0; -} - -/* - * We implement an immediate ioend submission policy here to avoid needing to - * chain multiple ioends and hence nest mempool allocations which can violate - * forward progress guarantees we need to provide. The current ioend we are - * adding buffers to is cached on the writepage context, and if the new buffer - * does not append to the cached ioend it will create a new ioend and cache that - * instead. - * - * If a new ioend is created and cached, the old ioend is returned and queued - * locally for submission once the entire page is processed or an error has been - * detected. While ioends are submitted immediately after they are completed, - * batching optimisations are provided by higher level block plugging. - * - * At the end of a writeback pass, there will be a cached ioend remaining on the - * writepage context that the caller will need to submit. - */ -static int -xfs_writepage_map( - struct xfs_writepage_ctx *wpc, - struct writeback_control *wbc, - struct inode *inode, - struct page *page, - loff_t offset, - __uint64_t end_offset) -{ - LIST_HEAD(submit_list); - struct xfs_ioend *ioend, *next; - struct buffer_head *bh, *head; - ssize_t len = 1 << inode->i_blkbits; - int error = 0; - int count = 0; - int uptodate = 1; - unsigned int new_type; - - bh = head = page_buffers(page); - offset = page_offset(page); - do { - if (offset >= end_offset) - break; - if (!buffer_uptodate(bh)) - uptodate = 0; - - /* - * set_page_dirty dirties all buffers in a page, independent - * of their state. The dirty state however is entirely - * meaningless for holes (!mapped && uptodate), so skip - * buffers covering holes here. - */ - if (!buffer_mapped(bh) && buffer_uptodate(bh)) { - wpc->imap_valid = false; - continue; - } - - if (buffer_unwritten(bh)) - new_type = XFS_IO_UNWRITTEN; - else if (buffer_delay(bh)) - new_type = XFS_IO_DELALLOC; - else if (buffer_uptodate(bh)) - new_type = XFS_IO_OVERWRITE; - else { - if (PageUptodate(page)) - ASSERT(buffer_mapped(bh)); - /* - * This buffer is not uptodate and will not be - * written to disk. Ensure that we will put any - * subsequent writeable buffers into a new - * ioend. - */ - wpc->imap_valid = false; - continue; - } - - if (xfs_is_reflink_inode(XFS_I(inode))) { - error = xfs_map_cow(wpc, inode, offset, &new_type); - if (error) - goto out; - } - - if (wpc->io_type != new_type) { - wpc->io_type = new_type; - wpc->imap_valid = false; - } - - if (wpc->imap_valid) - wpc->imap_valid = xfs_imap_valid(inode, &wpc->imap, - offset); - if (!wpc->imap_valid) { - error = xfs_map_blocks(inode, offset, &wpc->imap, - wpc->io_type); - if (error) - goto out; - wpc->imap_valid = xfs_imap_valid(inode, &wpc->imap, - offset); - } - if (wpc->imap_valid) { - lock_buffer(bh); - if (wpc->io_type != XFS_IO_OVERWRITE) - xfs_map_at_offset(inode, bh, &wpc->imap, offset); - xfs_add_to_ioend(inode, bh, offset, wpc, wbc, &submit_list); - count++; - } - - } while (offset += len, ((bh = bh->b_this_page) != head)); - - if (uptodate && bh == head) - SetPageUptodate(page); - - ASSERT(wpc->ioend || list_empty(&submit_list)); - -out: - /* - * On error, we have to fail the ioend here because we have locked - * buffers in the ioend. If we don't do this, we'll deadlock - * invalidating the page as that tries to lock the buffers on the page. - * Also, because we may have set pages under writeback, we have to make - * sure we run IO completion to mark the error state of the IO - * appropriately, so we can't cancel the ioend directly here. That means - * we have to mark this page as under writeback if we included any - * buffers from it in the ioend chain so that completion treats it - * correctly. - * - * If we didn't include the page in the ioend, the on error we can - * simply discard and unlock it as there are no other users of the page - * or it's buffers right now. The caller will still need to trigger - * submission of outstanding ioends on the writepage context so they are - * treated correctly on error. - */ - if (count) { - xfs_start_page_writeback(page, !error); - - /* - * Preserve the original error if there was one, otherwise catch - * submission errors here and propagate into subsequent ioend - * submissions. - */ - list_for_each_entry_safe(ioend, next, &submit_list, io_list) { - int error2; - - list_del_init(&ioend->io_list); - error2 = xfs_submit_ioend(wbc, ioend, error); - if (error2 && !error) - error = error2; - } - } else if (error) { - xfs_aops_discard_page(page); - ClearPageUptodate(page); - unlock_page(page); - } else { - /* - * We can end up here with no error and nothing to write if we - * race with a partial page truncate on a sub-page block sized - * filesystem. In that case we need to mark the page clean. - */ - xfs_start_page_writeback(page, 1); - end_page_writeback(page); - } - - mapping_set_error(page->mapping, error); - return error; -} - -/* - * Write out a dirty page. - * - * For delalloc space on the page we need to allocate space and flush it. - * For unwritten space on the page we need to start the conversion to - * regular allocated space. - * For any other dirty buffer heads on the page we should flush them. - */ -STATIC int -xfs_do_writepage( - struct page *page, - struct writeback_control *wbc, - void *data) -{ - struct xfs_writepage_ctx *wpc = data; - struct inode *inode = page->mapping->host; - loff_t offset; - __uint64_t end_offset; - pgoff_t end_index; - - trace_xfs_writepage(inode, page, 0, 0); - - ASSERT(page_has_buffers(page)); - - /* - * Refuse to write the page out if we are called from reclaim context. - * - * This avoids stack overflows when called from deeply used stacks in - * random callers for direct reclaim or memcg reclaim. We explicitly - * allow reclaim from kswapd as the stack usage there is relatively low. - * - * This should never happen except in the case of a VM regression so - * warn about it. - */ - if (WARN_ON_ONCE((current->flags & (PF_MEMALLOC|PF_KSWAPD)) == - PF_MEMALLOC)) - goto redirty; - - /* - * Given that we do not allow direct reclaim to call us, we should - * never be called while in a filesystem transaction. - */ - if (WARN_ON_ONCE(current->flags & PF_FSTRANS)) - goto redirty; - - /* - * Is this page beyond the end of the file? - * - * The page index is less than the end_index, adjust the end_offset - * to the highest offset that this page should represent. - * ----------------------------------------------------- - * | file mapping | | - * ----------------------------------------------------- - * | Page ... | Page N-2 | Page N-1 | Page N | | - * ^--------------------------------^----------|-------- - * | desired writeback range | see else | - * ---------------------------------^------------------| - */ - offset = i_size_read(inode); - end_index = offset >> PAGE_SHIFT; - if (page->index < end_index) - end_offset = (xfs_off_t)(page->index + 1) << PAGE_SHIFT; - else { - /* - * Check whether the page to write out is beyond or straddles - * i_size or not. - * ------------------------------------------------------- - * | file mapping | | - * ------------------------------------------------------- - * | Page ... | Page N-2 | Page N-1 | Page N | Beyond | - * ^--------------------------------^-----------|--------- - * | | Straddles | - * ---------------------------------^-----------|--------| - */ - unsigned offset_into_page = offset & (PAGE_SIZE - 1); - - /* - * Skip the page if it is fully outside i_size, e.g. due to a - * truncate operation that is in progress. We must redirty the - * page so that reclaim stops reclaiming it. Otherwise - * xfs_vm_releasepage() is called on it and gets confused. - * - * Note that the end_index is unsigned long, it would overflow - * if the given offset is greater than 16TB on 32-bit system - * and if we do check the page is fully outside i_size or not - * via "if (page->index >= end_index + 1)" as "end_index + 1" - * will be evaluated to 0. Hence this page will be redirtied - * and be written out repeatedly which would result in an - * infinite loop, the user program that perform this operation - * will hang. Instead, we can verify this situation by checking - * if the page to write is totally beyond the i_size or if it's - * offset is just equal to the EOF. - */ - if (page->index > end_index || - (page->index == end_index && offset_into_page == 0)) - goto redirty; - - /* - * The page straddles i_size. It must be zeroed out on each - * and every writepage invocation because it may be mmapped. - * "A file is mapped in multiples of the page size. For a file - * that is not a multiple of the page size, the remaining - * memory is zeroed when mapped, and writes to that region are - * not written out to the file." - */ - zero_user_segment(page, offset_into_page, PAGE_SIZE); - - /* Adjust the end_offset to the end of file */ - end_offset = offset; - } - - return xfs_writepage_map(wpc, wbc, inode, page, offset, end_offset); - -redirty: - redirty_page_for_writepage(wbc, page); - unlock_page(page); - return 0; -} - -STATIC int -xfs_vm_writepage( - struct page *page, - struct writeback_control *wbc) -{ - struct xfs_writepage_ctx wpc = { - .io_type = XFS_IO_INVALID, - }; - int ret; - - ret = xfs_do_writepage(page, wbc, &wpc); - if (wpc.ioend) - ret = xfs_submit_ioend(wbc, wpc.ioend, ret); - return ret; -} - -STATIC int -xfs_vm_writepages( - struct address_space *mapping, - struct writeback_control *wbc) -{ - struct xfs_writepage_ctx wpc = { - .io_type = XFS_IO_INVALID, - }; - int ret; - - xfs_iflags_clear(XFS_I(mapping->host), XFS_ITRUNCATED); - if (dax_mapping(mapping)) - return dax_writeback_mapping_range(mapping, - xfs_find_bdev_for_inode(mapping->host), wbc); - - ret = write_cache_pages(mapping, wbc, xfs_do_writepage, &wpc); - if (wpc.ioend) - ret = xfs_submit_ioend(wbc, wpc.ioend, ret); - return ret; -} - -/* - * Called to move a page into cleanable state - and from there - * to be released. The page should already be clean. We always - * have buffer heads in this call. - * - * Returns 1 if the page is ok to release, 0 otherwise. - */ -STATIC int -xfs_vm_releasepage( - struct page *page, - gfp_t gfp_mask) -{ - int delalloc, unwritten; - - trace_xfs_releasepage(page->mapping->host, page, 0, 0); - - /* - * mm accommodates an old ext3 case where clean pages might not have had - * the dirty bit cleared. Thus, it can send actual dirty pages to - * ->releasepage() via shrink_active_list(). Conversely, - * block_invalidatepage() can send pages that are still marked dirty - * but otherwise have invalidated buffers. - * - * We've historically freed buffers on the latter. Instead, quietly - * filter out all dirty pages to avoid spurious buffer state warnings. - * This can likely be removed once shrink_active_list() is fixed. - */ - if (PageDirty(page)) - return 0; - - xfs_count_page_state(page, &delalloc, &unwritten); - - if (WARN_ON_ONCE(delalloc)) - return 0; - if (WARN_ON_ONCE(unwritten)) - return 0; - - return try_to_free_buffers(page); -} - -/* - * When we map a DIO buffer, we may need to pass flags to - * xfs_end_io_direct_write to tell it what kind of write IO we are doing. - * - * Note that for DIO, an IO to the highest supported file block offset (i.e. - * 2^63 - 1FSB bytes) will result in the offset + count overflowing a signed 64 - * bit variable. Hence if we see this overflow, we have to assume that the IO is - * extending the file size. We won't know for sure until IO completion is run - * and the actual max write offset is communicated to the IO completion - * routine. - */ -static void -xfs_map_direct( - struct inode *inode, - struct buffer_head *bh_result, - struct xfs_bmbt_irec *imap, - xfs_off_t offset, - bool is_cow) -{ - uintptr_t *flags = (uintptr_t *)&bh_result->b_private; - xfs_off_t size = bh_result->b_size; - - trace_xfs_get_blocks_map_direct(XFS_I(inode), offset, size, - ISUNWRITTEN(imap) ? XFS_IO_UNWRITTEN : is_cow ? XFS_IO_COW : - XFS_IO_OVERWRITE, imap); - - if (ISUNWRITTEN(imap)) { - *flags |= XFS_DIO_FLAG_UNWRITTEN; - set_buffer_defer_completion(bh_result); - } else if (is_cow) { - *flags |= XFS_DIO_FLAG_COW; - set_buffer_defer_completion(bh_result); - } - if (offset + size > i_size_read(inode) || offset + size < 0) { - *flags |= XFS_DIO_FLAG_APPEND; - set_buffer_defer_completion(bh_result); - } -} - -/* - * If this is O_DIRECT or the mpage code calling tell them how large the mapping - * is, so that we can avoid repeated get_blocks calls. - * - * If the mapping spans EOF, then we have to break the mapping up as the mapping - * for blocks beyond EOF must be marked new so that sub block regions can be - * correctly zeroed. We can't do this for mappings within EOF unless the mapping - * was just allocated or is unwritten, otherwise the callers would overwrite - * existing data with zeros. Hence we have to split the mapping into a range up - * to and including EOF, and a second mapping for beyond EOF. - */ -static void -xfs_map_trim_size( - struct inode *inode, - sector_t iblock, - struct buffer_head *bh_result, - struct xfs_bmbt_irec *imap, - xfs_off_t offset, - ssize_t size) -{ - xfs_off_t mapping_size; - - mapping_size = imap->br_startoff + imap->br_blockcount - iblock; - mapping_size <<= inode->i_blkbits; - - ASSERT(mapping_size > 0); - if (mapping_size > size) - mapping_size = size; - if (offset < i_size_read(inode) && - offset + mapping_size >= i_size_read(inode)) { - /* limit mapping to block that spans EOF */ - mapping_size = roundup_64(i_size_read(inode) - offset, - 1 << inode->i_blkbits); - } - if (mapping_size > LONG_MAX) - mapping_size = LONG_MAX; - - bh_result->b_size = mapping_size; -} - -/* Bounce unaligned directio writes to the page cache. */ -static int -xfs_bounce_unaligned_dio_write( - struct xfs_inode *ip, - xfs_fileoff_t offset_fsb, - struct xfs_bmbt_irec *imap) -{ - struct xfs_bmbt_irec irec; - xfs_fileoff_t delta; - bool shared; - bool x; - int error; - - irec = *imap; - if (offset_fsb > irec.br_startoff) { - delta = offset_fsb - irec.br_startoff; - irec.br_blockcount -= delta; - irec.br_startblock += delta; - irec.br_startoff = offset_fsb; - } - error = xfs_reflink_trim_around_shared(ip, &irec, &shared, &x); - if (error) - return error; - - /* - * We're here because we're trying to do a directio write to a - * region that isn't aligned to a filesystem block. If any part - * of the extent is shared, fall back to buffered mode to handle - * the RMW. This is done by returning -EREMCHG ("remote addr - * changed"), which is caught further up the call stack. - */ - if (shared) { - trace_xfs_reflink_bounce_dio_write(ip, imap); - return -EREMCHG; - } - return 0; -} - -STATIC int -__xfs_get_blocks( - struct inode *inode, - sector_t iblock, - struct buffer_head *bh_result, - int create, - bool direct, - bool dax_fault) -{ - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; - xfs_fileoff_t offset_fsb, end_fsb; - int error = 0; - int lockmode = 0; - struct xfs_bmbt_irec imap; - int nimaps = 1; - xfs_off_t offset; - ssize_t size; - int new = 0; - bool is_cow = false; - bool need_alloc = false; - - BUG_ON(create && !direct); - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - offset = (xfs_off_t)iblock << inode->i_blkbits; - ASSERT(bh_result->b_size >= (1 << inode->i_blkbits)); - size = bh_result->b_size; - - if (!create && offset >= i_size_read(inode)) - return 0; - - /* - * Direct I/O is usually done on preallocated files, so try getting - * a block mapping without an exclusive lock first. - */ - lockmode = xfs_ilock_data_map_shared(ip); - - ASSERT(offset <= mp->m_super->s_maxbytes); - if (offset + size > mp->m_super->s_maxbytes) - size = mp->m_super->s_maxbytes - offset; - end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + size); - offset_fsb = XFS_B_TO_FSBT(mp, offset); - - if (create && direct && xfs_is_reflink_inode(ip)) - is_cow = xfs_reflink_find_cow_mapping(ip, offset, &imap, - &need_alloc); - if (!is_cow) { - error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, - &imap, &nimaps, XFS_BMAPI_ENTIRE); - /* - * Truncate an overwrite extent if there's a pending CoW - * reservation before the end of this extent. This - * forces us to come back to get_blocks to take care of - * the CoW. - */ - if (create && direct && nimaps && - imap.br_startblock != HOLESTARTBLOCK && - imap.br_startblock != DELAYSTARTBLOCK && - !ISUNWRITTEN(&imap)) - xfs_reflink_trim_irec_to_next_cow(ip, offset_fsb, - &imap); - } - ASSERT(!need_alloc); - if (error) - goto out_unlock; - - /* for DAX, we convert unwritten extents directly */ - if (create && - (!nimaps || - (imap.br_startblock == HOLESTARTBLOCK || - imap.br_startblock == DELAYSTARTBLOCK) || - (IS_DAX(inode) && ISUNWRITTEN(&imap)))) { - /* - * xfs_iomap_write_direct() expects the shared lock. It - * is unlocked on return. - */ - if (lockmode == XFS_ILOCK_EXCL) - xfs_ilock_demote(ip, lockmode); - - error = xfs_iomap_write_direct(ip, offset, size, - &imap, nimaps); - if (error) - return error; - new = 1; - - trace_xfs_get_blocks_alloc(ip, offset, size, - ISUNWRITTEN(&imap) ? XFS_IO_UNWRITTEN - : XFS_IO_DELALLOC, &imap); - } else if (nimaps) { - trace_xfs_get_blocks_found(ip, offset, size, - ISUNWRITTEN(&imap) ? XFS_IO_UNWRITTEN - : XFS_IO_OVERWRITE, &imap); - xfs_iunlock(ip, lockmode); - } else { - trace_xfs_get_blocks_notfound(ip, offset, size); - goto out_unlock; - } - - if (IS_DAX(inode) && create) { - ASSERT(!ISUNWRITTEN(&imap)); - /* zeroing is not needed at a higher layer */ - new = 0; - } - - /* trim mapping down to size requested */ - xfs_map_trim_size(inode, iblock, bh_result, &imap, offset, size); - - /* - * For unwritten extents do not report a disk address in the buffered - * read case (treat as if we're reading into a hole). - */ - if (imap.br_startblock != HOLESTARTBLOCK && - imap.br_startblock != DELAYSTARTBLOCK && - (create || !ISUNWRITTEN(&imap))) { - if (create && direct && !is_cow) { - error = xfs_bounce_unaligned_dio_write(ip, offset_fsb, - &imap); - if (error) - return error; - } - - xfs_map_buffer(inode, bh_result, &imap, offset); - if (ISUNWRITTEN(&imap)) - set_buffer_unwritten(bh_result); - /* direct IO needs special help */ - if (create) { - if (dax_fault) - ASSERT(!ISUNWRITTEN(&imap)); - else - xfs_map_direct(inode, bh_result, &imap, offset, - is_cow); - } - } - - /* - * If this is a realtime file, data may be on a different device. - * to that pointed to from the buffer_head b_bdev currently. - */ - bh_result->b_bdev = xfs_find_bdev_for_inode(inode); - - /* - * If we previously allocated a block out beyond eof and we are now - * coming back to use it then we will need to flag it as new even if it - * has a disk address. - * - * With sub-block writes into unwritten extents we also need to mark - * the buffer as new so that the unwritten parts of the buffer gets - * correctly zeroed. - */ - if (create && - ((!buffer_mapped(bh_result) && !buffer_uptodate(bh_result)) || - (offset >= i_size_read(inode)) || - (new || ISUNWRITTEN(&imap)))) - set_buffer_new(bh_result); - - BUG_ON(direct && imap.br_startblock == DELAYSTARTBLOCK); - - return 0; - -out_unlock: - xfs_iunlock(ip, lockmode); - return error; -} - -int -xfs_get_blocks( - struct inode *inode, - sector_t iblock, - struct buffer_head *bh_result, - int create) -{ - return __xfs_get_blocks(inode, iblock, bh_result, create, false, false); -} - -int -xfs_get_blocks_direct( - struct inode *inode, - sector_t iblock, - struct buffer_head *bh_result, - int create) -{ - return __xfs_get_blocks(inode, iblock, bh_result, create, true, false); -} - -int -xfs_get_blocks_dax_fault( - struct inode *inode, - sector_t iblock, - struct buffer_head *bh_result, - int create) -{ - return __xfs_get_blocks(inode, iblock, bh_result, create, true, true); -} - -/* - * Complete a direct I/O write request. - * - * xfs_map_direct passes us some flags in the private data to tell us what to - * do. If no flags are set, then the write IO is an overwrite wholly within - * the existing allocated file size and so there is nothing for us to do. - * - * Note that in this case the completion can be called in interrupt context, - * whereas if we have flags set we will always be called in task context - * (i.e. from a workqueue). - */ -int -xfs_end_io_direct_write( - struct kiocb *iocb, - loff_t offset, - ssize_t size, - void *private) -{ - struct inode *inode = file_inode(iocb->ki_filp); - struct xfs_inode *ip = XFS_I(inode); - uintptr_t flags = (uintptr_t)private; - int error = 0; - - trace_xfs_end_io_direct_write(ip, offset, size); - - if (XFS_FORCED_SHUTDOWN(ip->i_mount)) - return -EIO; - - if (size <= 0) - return size; - - /* - * The flags tell us whether we are doing unwritten extent conversions - * or an append transaction that updates the on-disk file size. These - * cases are the only cases where we should *potentially* be needing - * to update the VFS inode size. - */ - if (flags == 0) { - ASSERT(offset + size <= i_size_read(inode)); - return 0; - } - - /* - * We need to update the in-core inode size here so that we don't end up - * with the on-disk inode size being outside the in-core inode size. We - * have no other method of updating EOF for AIO, so always do it here - * if necessary. - * - * We need to lock the test/set EOF update as we can be racing with - * other IO completions here to update the EOF. Failing to serialise - * here can result in EOF moving backwards and Bad Things Happen when - * that occurs. - */ - spin_lock(&ip->i_flags_lock); - if (offset + size > i_size_read(inode)) - i_size_write(inode, offset + size); - spin_unlock(&ip->i_flags_lock); - - if (flags & XFS_DIO_FLAG_COW) - error = xfs_reflink_end_cow(ip, offset, size); - if (flags & XFS_DIO_FLAG_UNWRITTEN) { - trace_xfs_end_io_direct_write_unwritten(ip, offset, size); - - error = xfs_iomap_write_unwritten(ip, offset, size); - } - if (flags & XFS_DIO_FLAG_APPEND) { - trace_xfs_end_io_direct_write_append(ip, offset, size); - - error = xfs_setfilesize(ip, offset, size); - } - - return error; -} - -STATIC ssize_t -xfs_vm_direct_IO( - struct kiocb *iocb, - struct iov_iter *iter) -{ - /* - * We just need the method present so that open/fcntl allow direct I/O. - */ - return -EINVAL; -} - -STATIC sector_t -xfs_vm_bmap( - struct address_space *mapping, - sector_t block) -{ - struct inode *inode = (struct inode *)mapping->host; - struct xfs_inode *ip = XFS_I(inode); - - trace_xfs_vm_bmap(XFS_I(inode)); - xfs_ilock(ip, XFS_IOLOCK_SHARED); - - /* - * The swap code (ab-)uses ->bmap to get a block mapping and then - * bypasseÑ• the file system for actual I/O. We really can't allow - * that on reflinks inodes, so we have to skip out here. And yes, - * 0 is the magic code for a bmap error.. - */ - if (xfs_is_reflink_inode(ip)) { - xfs_iunlock(ip, XFS_IOLOCK_SHARED); - return 0; - } - filemap_write_and_wait(mapping); - xfs_iunlock(ip, XFS_IOLOCK_SHARED); - return generic_block_bmap(mapping, block, xfs_get_blocks); -} - -STATIC int -xfs_vm_readpage( - struct file *unused, - struct page *page) -{ - trace_xfs_vm_readpage(page->mapping->host, 1); - return mpage_readpage(page, xfs_get_blocks); -} - -STATIC int -xfs_vm_readpages( - struct file *unused, - struct address_space *mapping, - struct list_head *pages, - unsigned nr_pages) -{ - trace_xfs_vm_readpages(mapping->host, nr_pages); - return mpage_readpages(mapping, pages, nr_pages, xfs_get_blocks); -} - -/* - * This is basically a copy of __set_page_dirty_buffers() with one - * small tweak: buffers beyond EOF do not get marked dirty. If we mark them - * dirty, we'll never be able to clean them because we don't write buffers - * beyond EOF, and that means we can't invalidate pages that span EOF - * that have been marked dirty. Further, the dirty state can leak into - * the file interior if the file is extended, resulting in all sorts of - * bad things happening as the state does not match the underlying data. - * - * XXX: this really indicates that bufferheads in XFS need to die. Warts like - * this only exist because of bufferheads and how the generic code manages them. - */ -STATIC int -xfs_vm_set_page_dirty( - struct page *page) -{ - struct address_space *mapping = page->mapping; - struct inode *inode = mapping->host; - loff_t end_offset; - loff_t offset; - int newly_dirty; - - if (unlikely(!mapping)) - return !TestSetPageDirty(page); - - end_offset = i_size_read(inode); - offset = page_offset(page); - - spin_lock(&mapping->private_lock); - if (page_has_buffers(page)) { - struct buffer_head *head = page_buffers(page); - struct buffer_head *bh = head; - - do { - if (offset < end_offset) - set_buffer_dirty(bh); - bh = bh->b_this_page; - offset += 1 << inode->i_blkbits; - } while (bh != head); - } - /* - * Lock out page->mem_cgroup migration to keep PageDirty - * synchronized with per-memcg dirty page counters. - */ - lock_page_memcg(page); - newly_dirty = !TestSetPageDirty(page); - spin_unlock(&mapping->private_lock); - - if (newly_dirty) { - /* sigh - __set_page_dirty() is static, so copy it here, too */ - unsigned long flags; - - spin_lock_irqsave(&mapping->tree_lock, flags); - if (page->mapping) { /* Race with truncate? */ - WARN_ON_ONCE(!PageUptodate(page)); - account_page_dirtied(page, mapping); - radix_tree_tag_set(&mapping->page_tree, - page_index(page), PAGECACHE_TAG_DIRTY); - } - spin_unlock_irqrestore(&mapping->tree_lock, flags); - } - unlock_page_memcg(page); - if (newly_dirty) - __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); - return newly_dirty; -} - -const struct address_space_operations xfs_address_space_operations = { - .readpage = xfs_vm_readpage, - .readpages = xfs_vm_readpages, - .writepage = xfs_vm_writepage, - .writepages = xfs_vm_writepages, - .set_page_dirty = xfs_vm_set_page_dirty, - .releasepage = xfs_vm_releasepage, - .invalidatepage = xfs_vm_invalidatepage, - .bmap = xfs_vm_bmap, - .direct_IO = xfs_vm_direct_IO, - .migratepage = buffer_migrate_page, - .is_partially_uptodate = block_is_partially_uptodate, - .error_remove_page = generic_error_remove_page, -}; diff --git a/src/linux/fs/xfs/xfs_aops.h b/src/linux/fs/xfs/xfs_aops.h deleted file mode 100644 index b3c6634..0000000 --- a/src/linux/fs/xfs/xfs_aops.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2005-2006 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_AOPS_H__ -#define __XFS_AOPS_H__ - -extern struct bio_set *xfs_ioend_bioset; - -/* - * Types of I/O for bmap clustering and I/O completion tracking. - */ -enum { - XFS_IO_INVALID, /* initial state */ - XFS_IO_DELALLOC, /* covers delalloc region */ - XFS_IO_UNWRITTEN, /* covers allocated but uninitialized data */ - XFS_IO_OVERWRITE, /* covers already allocated extent */ - XFS_IO_COW, /* covers copy-on-write extent */ -}; - -#define XFS_IO_TYPES \ - { XFS_IO_INVALID, "invalid" }, \ - { XFS_IO_DELALLOC, "delalloc" }, \ - { XFS_IO_UNWRITTEN, "unwritten" }, \ - { XFS_IO_OVERWRITE, "overwrite" }, \ - { XFS_IO_COW, "CoW" } - -/* - * Structure for buffered I/O completions. - */ -struct xfs_ioend { - struct list_head io_list; /* next ioend in chain */ - unsigned int io_type; /* delalloc / unwritten */ - struct inode *io_inode; /* file being written to */ - size_t io_size; /* size of the extent */ - xfs_off_t io_offset; /* offset in the file */ - struct work_struct io_work; /* xfsdatad work queue */ - struct xfs_trans *io_append_trans;/* xact. for size update */ - struct bio *io_bio; /* bio being built */ - struct bio io_inline_bio; /* MUST BE LAST! */ -}; - -extern const struct address_space_operations xfs_address_space_operations; - -int xfs_get_blocks(struct inode *inode, sector_t offset, - struct buffer_head *map_bh, int create); -int xfs_get_blocks_direct(struct inode *inode, sector_t offset, - struct buffer_head *map_bh, int create); -int xfs_get_blocks_dax_fault(struct inode *inode, sector_t offset, - struct buffer_head *map_bh, int create); - -int xfs_end_io_direct_write(struct kiocb *iocb, loff_t offset, - ssize_t size, void *private); -int xfs_setfilesize(struct xfs_inode *ip, xfs_off_t offset, size_t size); - -extern void xfs_count_page_state(struct page *, int *, int *); -extern struct block_device *xfs_find_bdev_for_inode(struct inode *); - -#endif /* __XFS_AOPS_H__ */ diff --git a/src/linux/fs/xfs/xfs_attr.h b/src/linux/fs/xfs/xfs_attr.h deleted file mode 100644 index e3da5d4..0000000 --- a/src/linux/fs/xfs/xfs_attr.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2000,2002-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_ATTR_H__ -#define __XFS_ATTR_H__ - -struct xfs_inode; -struct xfs_da_args; -struct xfs_attr_list_context; - -/* - * Large attribute lists are structured around Btrees where all the data - * elements are in the leaf nodes. Attribute names are hashed into an int, - * then that int is used as the index into the Btree. Since the hashval - * of an attribute name may not be unique, we may have duplicate keys. - * The internal links in the Btree are logical block offsets into the file. - * - * Small attribute lists use a different format and are packed as tightly - * as possible so as to fit into the literal area of the inode. - */ - -/*======================================================================== - * External interfaces - *========================================================================*/ - - -#define ATTR_DONTFOLLOW 0x0001 /* -- unused, from IRIX -- */ -#define ATTR_ROOT 0x0002 /* use attrs in root (trusted) namespace */ -#define ATTR_TRUST 0x0004 /* -- unused, from IRIX -- */ -#define ATTR_SECURE 0x0008 /* use attrs in security namespace */ -#define ATTR_CREATE 0x0010 /* pure create: fail if attr already exists */ -#define ATTR_REPLACE 0x0020 /* pure set: fail if attr does not exist */ - -#define ATTR_KERNOTIME 0x1000 /* [kernel] don't update inode timestamps */ -#define ATTR_KERNOVAL 0x2000 /* [kernel] get attr size only, not value */ - -#define XFS_ATTR_FLAGS \ - { ATTR_DONTFOLLOW, "DONTFOLLOW" }, \ - { ATTR_ROOT, "ROOT" }, \ - { ATTR_TRUST, "TRUST" }, \ - { ATTR_SECURE, "SECURE" }, \ - { ATTR_CREATE, "CREATE" }, \ - { ATTR_REPLACE, "REPLACE" }, \ - { ATTR_KERNOTIME, "KERNOTIME" }, \ - { ATTR_KERNOVAL, "KERNOVAL" } - -/* - * The maximum size (into the kernel or returned from the kernel) of an - * attribute value or the buffer used for an attr_list() call. Larger - * sizes will result in an ERANGE return code. - */ -#define ATTR_MAX_VALUELEN (64*1024) /* max length of a value */ - -/* - * Define how lists of attribute names are returned to the user from - * the attr_list() call. A large, 32bit aligned, buffer is passed in - * along with its size. We put an array of offsets at the top that each - * reference an attrlist_ent_t and pack the attrlist_ent_t's at the bottom. - */ -typedef struct attrlist { - __s32 al_count; /* number of entries in attrlist */ - __s32 al_more; /* T/F: more attrs (do call again) */ - __s32 al_offset[1]; /* byte offsets of attrs [var-sized] */ -} attrlist_t; - -/* - * Show the interesting info about one attribute. This is what the - * al_offset[i] entry points to. - */ -typedef struct attrlist_ent { /* data from attr_list() */ - __u32 a_valuelen; /* number bytes in value of attr */ - char a_name[1]; /* attr name (NULL terminated) */ -} attrlist_ent_t; - -/* - * Given a pointer to the (char*) buffer containing the attr_list() result, - * and an index, return a pointer to the indicated attribute in the buffer. - */ -#define ATTR_ENTRY(buffer, index) \ - ((attrlist_ent_t *) \ - &((char *)buffer)[ ((attrlist_t *)(buffer))->al_offset[index] ]) - -/* - * Kernel-internal version of the attrlist cursor. - */ -typedef struct attrlist_cursor_kern { - __u32 hashval; /* hash value of next entry to add */ - __u32 blkno; /* block containing entry (suggestion) */ - __u32 offset; /* offset in list of equal-hashvals */ - __u16 pad1; /* padding to match user-level */ - __u8 pad2; /* padding to match user-level */ - __u8 initted; /* T/F: cursor has been initialized */ -} attrlist_cursor_kern_t; - - -/*======================================================================== - * Structure used to pass context around among the routines. - *========================================================================*/ - - -/* Return 0 on success, or -errno; other state communicated via *context */ -typedef int (*put_listent_func_t)(struct xfs_attr_list_context *, int, - unsigned char *, int, int); - -typedef struct xfs_attr_list_context { - struct xfs_inode *dp; /* inode */ - struct attrlist_cursor_kern *cursor; /* position in list */ - char *alist; /* output buffer */ - int seen_enough; /* T/F: seen enough of list? */ - ssize_t count; /* num used entries */ - int dupcnt; /* count dup hashvals seen */ - int bufsize; /* total buffer size */ - int firstu; /* first used byte in buffer */ - int flags; /* from VOP call */ - int resynch; /* T/F: resynch with cursor */ - put_listent_func_t put_listent; /* list output fmt function */ - int index; /* index into output buffer */ -} xfs_attr_list_context_t; - - -/*======================================================================== - * Function prototypes for the kernel. - *========================================================================*/ - -/* - * Overall external interface routines. - */ -int xfs_attr_inactive(struct xfs_inode *dp); -int xfs_attr_list_int(struct xfs_attr_list_context *); -int xfs_inode_hasattr(struct xfs_inode *ip); -int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name, - unsigned char *value, int *valuelenp, int flags); -int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name, - unsigned char *value, int valuelen, int flags); -int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags); -int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize, - int flags, struct attrlist_cursor_kern *cursor); - - -#endif /* __XFS_ATTR_H__ */ diff --git a/src/linux/fs/xfs/xfs_attr_inactive.c b/src/linux/fs/xfs/xfs_attr_inactive.c deleted file mode 100644 index be0b79d..0000000 --- a/src/linux/fs/xfs/xfs_attr_inactive.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * Copyright (c) 2013 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_inode.h" -#include "xfs_alloc.h" -#include "xfs_attr_remote.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_bmap.h" -#include "xfs_attr.h" -#include "xfs_attr_leaf.h" -#include "xfs_error.h" -#include "xfs_quota.h" -#include "xfs_trace.h" -#include "xfs_dir2.h" - -/* - * Look at all the extents for this logical region, - * invalidate any buffers that are incore/in transactions. - */ -STATIC int -xfs_attr3_leaf_freextent( - struct xfs_trans **trans, - struct xfs_inode *dp, - xfs_dablk_t blkno, - int blkcnt) -{ - struct xfs_bmbt_irec map; - struct xfs_buf *bp; - xfs_dablk_t tblkno; - xfs_daddr_t dblkno; - int tblkcnt; - int dblkcnt; - int nmap; - int error; - - /* - * Roll through the "value", invalidating the attribute value's - * blocks. - */ - tblkno = blkno; - tblkcnt = blkcnt; - while (tblkcnt > 0) { - /* - * Try to remember where we decided to put the value. - */ - nmap = 1; - error = xfs_bmapi_read(dp, (xfs_fileoff_t)tblkno, tblkcnt, - &map, &nmap, XFS_BMAPI_ATTRFORK); - if (error) { - return error; - } - ASSERT(nmap == 1); - ASSERT(map.br_startblock != DELAYSTARTBLOCK); - - /* - * If it's a hole, these are already unmapped - * so there's nothing to invalidate. - */ - if (map.br_startblock != HOLESTARTBLOCK) { - - dblkno = XFS_FSB_TO_DADDR(dp->i_mount, - map.br_startblock); - dblkcnt = XFS_FSB_TO_BB(dp->i_mount, - map.br_blockcount); - bp = xfs_trans_get_buf(*trans, - dp->i_mount->m_ddev_targp, - dblkno, dblkcnt, 0); - if (!bp) - return -ENOMEM; - xfs_trans_binval(*trans, bp); - /* - * Roll to next transaction. - */ - error = xfs_trans_roll(trans, dp); - if (error) - return error; - } - - tblkno += map.br_blockcount; - tblkcnt -= map.br_blockcount; - } - - return 0; -} - -/* - * Invalidate all of the "remote" value regions pointed to by a particular - * leaf block. - * Note that we must release the lock on the buffer so that we are not - * caught holding something that the logging code wants to flush to disk. - */ -STATIC int -xfs_attr3_leaf_inactive( - struct xfs_trans **trans, - struct xfs_inode *dp, - struct xfs_buf *bp) -{ - struct xfs_attr_leafblock *leaf; - struct xfs_attr3_icleaf_hdr ichdr; - struct xfs_attr_leaf_entry *entry; - struct xfs_attr_leaf_name_remote *name_rmt; - struct xfs_attr_inactive_list *list; - struct xfs_attr_inactive_list *lp; - int error; - int count; - int size; - int tmp; - int i; - struct xfs_mount *mp = bp->b_target->bt_mount; - - leaf = bp->b_addr; - xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf); - - /* - * Count the number of "remote" value extents. - */ - count = 0; - entry = xfs_attr3_leaf_entryp(leaf); - for (i = 0; i < ichdr.count; entry++, i++) { - if (be16_to_cpu(entry->nameidx) && - ((entry->flags & XFS_ATTR_LOCAL) == 0)) { - name_rmt = xfs_attr3_leaf_name_remote(leaf, i); - if (name_rmt->valueblk) - count++; - } - } - - /* - * If there are no "remote" values, we're done. - */ - if (count == 0) { - xfs_trans_brelse(*trans, bp); - return 0; - } - - /* - * Allocate storage for a list of all the "remote" value extents. - */ - size = count * sizeof(xfs_attr_inactive_list_t); - list = kmem_alloc(size, KM_SLEEP); - - /* - * Identify each of the "remote" value extents. - */ - lp = list; - entry = xfs_attr3_leaf_entryp(leaf); - for (i = 0; i < ichdr.count; entry++, i++) { - if (be16_to_cpu(entry->nameidx) && - ((entry->flags & XFS_ATTR_LOCAL) == 0)) { - name_rmt = xfs_attr3_leaf_name_remote(leaf, i); - if (name_rmt->valueblk) { - lp->valueblk = be32_to_cpu(name_rmt->valueblk); - lp->valuelen = xfs_attr3_rmt_blocks(dp->i_mount, - be32_to_cpu(name_rmt->valuelen)); - lp++; - } - } - } - xfs_trans_brelse(*trans, bp); /* unlock for trans. in freextent() */ - - /* - * Invalidate each of the "remote" value extents. - */ - error = 0; - for (lp = list, i = 0; i < count; i++, lp++) { - tmp = xfs_attr3_leaf_freextent(trans, dp, - lp->valueblk, lp->valuelen); - - if (error == 0) - error = tmp; /* save only the 1st errno */ - } - - kmem_free(list); - return error; -} - -/* - * Recurse (gasp!) through the attribute nodes until we find leaves. - * We're doing a depth-first traversal in order to invalidate everything. - */ -STATIC int -xfs_attr3_node_inactive( - struct xfs_trans **trans, - struct xfs_inode *dp, - struct xfs_buf *bp, - int level) -{ - xfs_da_blkinfo_t *info; - xfs_da_intnode_t *node; - xfs_dablk_t child_fsb; - xfs_daddr_t parent_blkno, child_blkno; - int error, i; - struct xfs_buf *child_bp; - struct xfs_da_node_entry *btree; - struct xfs_da3_icnode_hdr ichdr; - - /* - * Since this code is recursive (gasp!) we must protect ourselves. - */ - if (level > XFS_DA_NODE_MAXDEPTH) { - xfs_trans_brelse(*trans, bp); /* no locks for later trans */ - return -EIO; - } - - node = bp->b_addr; - dp->d_ops->node_hdr_from_disk(&ichdr, node); - parent_blkno = bp->b_bn; - if (!ichdr.count) { - xfs_trans_brelse(*trans, bp); - return 0; - } - btree = dp->d_ops->node_tree_p(node); - child_fsb = be32_to_cpu(btree[0].before); - xfs_trans_brelse(*trans, bp); /* no locks for later trans */ - - /* - * If this is the node level just above the leaves, simply loop - * over the leaves removing all of them. If this is higher up - * in the tree, recurse downward. - */ - for (i = 0; i < ichdr.count; i++) { - /* - * Read the subsidiary block to see what we have to work with. - * Don't do this in a transaction. This is a depth-first - * traversal of the tree so we may deal with many blocks - * before we come back to this one. - */ - error = xfs_da3_node_read(*trans, dp, child_fsb, -2, &child_bp, - XFS_ATTR_FORK); - if (error) - return error; - if (child_bp) { - /* save for re-read later */ - child_blkno = XFS_BUF_ADDR(child_bp); - - /* - * Invalidate the subtree, however we have to. - */ - info = child_bp->b_addr; - switch (info->magic) { - case cpu_to_be16(XFS_DA_NODE_MAGIC): - case cpu_to_be16(XFS_DA3_NODE_MAGIC): - error = xfs_attr3_node_inactive(trans, dp, - child_bp, level + 1); - break; - case cpu_to_be16(XFS_ATTR_LEAF_MAGIC): - case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC): - error = xfs_attr3_leaf_inactive(trans, dp, - child_bp); - break; - default: - error = -EIO; - xfs_trans_brelse(*trans, child_bp); - break; - } - if (error) - return error; - - /* - * Remove the subsidiary block from the cache - * and from the log. - */ - error = xfs_da_get_buf(*trans, dp, 0, child_blkno, - &child_bp, XFS_ATTR_FORK); - if (error) - return error; - xfs_trans_binval(*trans, child_bp); - } - - /* - * If we're not done, re-read the parent to get the next - * child block number. - */ - if (i + 1 < ichdr.count) { - error = xfs_da3_node_read(*trans, dp, 0, parent_blkno, - &bp, XFS_ATTR_FORK); - if (error) - return error; - child_fsb = be32_to_cpu(btree[i + 1].before); - xfs_trans_brelse(*trans, bp); - } - /* - * Atomically commit the whole invalidate stuff. - */ - error = xfs_trans_roll(trans, dp); - if (error) - return error; - } - - return 0; -} - -/* - * Indiscriminately delete the entire attribute fork - * - * Recurse (gasp!) through the attribute nodes until we find leaves. - * We're doing a depth-first traversal in order to invalidate everything. - */ -static int -xfs_attr3_root_inactive( - struct xfs_trans **trans, - struct xfs_inode *dp) -{ - struct xfs_da_blkinfo *info; - struct xfs_buf *bp; - xfs_daddr_t blkno; - int error; - - /* - * Read block 0 to see what we have to work with. - * We only get here if we have extents, since we remove - * the extents in reverse order the extent containing - * block 0 must still be there. - */ - error = xfs_da3_node_read(*trans, dp, 0, -1, &bp, XFS_ATTR_FORK); - if (error) - return error; - blkno = bp->b_bn; - - /* - * Invalidate the tree, even if the "tree" is only a single leaf block. - * This is a depth-first traversal! - */ - info = bp->b_addr; - switch (info->magic) { - case cpu_to_be16(XFS_DA_NODE_MAGIC): - case cpu_to_be16(XFS_DA3_NODE_MAGIC): - error = xfs_attr3_node_inactive(trans, dp, bp, 1); - break; - case cpu_to_be16(XFS_ATTR_LEAF_MAGIC): - case cpu_to_be16(XFS_ATTR3_LEAF_MAGIC): - error = xfs_attr3_leaf_inactive(trans, dp, bp); - break; - default: - error = -EIO; - xfs_trans_brelse(*trans, bp); - break; - } - if (error) - return error; - - /* - * Invalidate the incore copy of the root block. - */ - error = xfs_da_get_buf(*trans, dp, 0, blkno, &bp, XFS_ATTR_FORK); - if (error) - return error; - xfs_trans_binval(*trans, bp); /* remove from cache */ - /* - * Commit the invalidate and start the next transaction. - */ - error = xfs_trans_roll(trans, dp); - - return error; -} - -/* - * xfs_attr_inactive kills all traces of an attribute fork on an inode. It - * removes both the on-disk and in-memory inode fork. Note that this also has to - * handle the condition of inodes without attributes but with an attribute fork - * configured, so we can't use xfs_inode_hasattr() here. - * - * The in-memory attribute fork is removed even on error. - */ -int -xfs_attr_inactive( - struct xfs_inode *dp) -{ - struct xfs_trans *trans; - struct xfs_mount *mp; - int lock_mode = XFS_ILOCK_SHARED; - int error = 0; - - mp = dp->i_mount; - ASSERT(! XFS_NOT_DQATTACHED(mp, dp)); - - xfs_ilock(dp, lock_mode); - if (!XFS_IFORK_Q(dp)) - goto out_destroy_fork; - xfs_iunlock(dp, lock_mode); - - lock_mode = 0; - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_attrinval, 0, 0, 0, &trans); - if (error) - goto out_destroy_fork; - - lock_mode = XFS_ILOCK_EXCL; - xfs_ilock(dp, lock_mode); - - if (!XFS_IFORK_Q(dp)) - goto out_cancel; - - /* - * No need to make quota reservations here. We expect to release some - * blocks, not allocate, in the common case. - */ - xfs_trans_ijoin(trans, dp, 0); - - /* - * Invalidate and truncate the attribute fork extents. Make sure the - * fork actually has attributes as otherwise the invalidation has no - * blocks to read and returns an error. In this case, just do the fork - * removal below. - */ - if (xfs_inode_hasattr(dp) && - dp->i_d.di_aformat != XFS_DINODE_FMT_LOCAL) { - error = xfs_attr3_root_inactive(&trans, dp); - if (error) - goto out_cancel; - - error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0); - if (error) - goto out_cancel; - } - - /* Reset the attribute fork - this also destroys the in-core fork */ - xfs_attr_fork_remove(dp, trans); - - error = xfs_trans_commit(trans); - xfs_iunlock(dp, lock_mode); - return error; - -out_cancel: - xfs_trans_cancel(trans); -out_destroy_fork: - /* kill the in-core attr fork before we drop the inode lock */ - if (dp->i_afp) - xfs_idestroy_fork(dp, XFS_ATTR_FORK); - if (lock_mode) - xfs_iunlock(dp, lock_mode); - return error; -} diff --git a/src/linux/fs/xfs/xfs_attr_list.c b/src/linux/fs/xfs/xfs_attr_list.c deleted file mode 100644 index 25e76cd..0000000 --- a/src/linux/fs/xfs/xfs_attr_list.c +++ /dev/null @@ -1,621 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * Copyright (c) 2013 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_bmap.h" -#include "xfs_attr.h" -#include "xfs_attr_sf.h" -#include "xfs_attr_remote.h" -#include "xfs_attr_leaf.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_buf_item.h" -#include "xfs_cksum.h" -#include "xfs_dir2.h" - -STATIC int -xfs_attr_shortform_compare(const void *a, const void *b) -{ - xfs_attr_sf_sort_t *sa, *sb; - - sa = (xfs_attr_sf_sort_t *)a; - sb = (xfs_attr_sf_sort_t *)b; - if (sa->hash < sb->hash) { - return -1; - } else if (sa->hash > sb->hash) { - return 1; - } else { - return sa->entno - sb->entno; - } -} - -#define XFS_ISRESET_CURSOR(cursor) \ - (!((cursor)->initted) && !((cursor)->hashval) && \ - !((cursor)->blkno) && !((cursor)->offset)) -/* - * Copy out entries of shortform attribute lists for attr_list(). - * Shortform attribute lists are not stored in hashval sorted order. - * If the output buffer is not large enough to hold them all, then we - * we have to calculate each entries' hashvalue and sort them before - * we can begin returning them to the user. - */ -static int -xfs_attr_shortform_list(xfs_attr_list_context_t *context) -{ - attrlist_cursor_kern_t *cursor; - xfs_attr_sf_sort_t *sbuf, *sbp; - xfs_attr_shortform_t *sf; - xfs_attr_sf_entry_t *sfe; - xfs_inode_t *dp; - int sbsize, nsbuf, count, i; - int error; - - ASSERT(context != NULL); - dp = context->dp; - ASSERT(dp != NULL); - ASSERT(dp->i_afp != NULL); - sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data; - ASSERT(sf != NULL); - if (!sf->hdr.count) - return 0; - cursor = context->cursor; - ASSERT(cursor != NULL); - - trace_xfs_attr_list_sf(context); - - /* - * If the buffer is large enough and the cursor is at the start, - * do not bother with sorting since we will return everything in - * one buffer and another call using the cursor won't need to be - * made. - * Note the generous fudge factor of 16 overhead bytes per entry. - * If bufsize is zero then put_listent must be a search function - * and can just scan through what we have. - */ - if (context->bufsize == 0 || - (XFS_ISRESET_CURSOR(cursor) && - (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) { - for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) { - error = context->put_listent(context, - sfe->flags, - sfe->nameval, - (int)sfe->namelen, - (int)sfe->valuelen); - if (error) - return error; - /* - * Either search callback finished early or - * didn't fit it all in the buffer after all. - */ - if (context->seen_enough) - break; - sfe = XFS_ATTR_SF_NEXTENTRY(sfe); - } - trace_xfs_attr_list_sf_all(context); - return 0; - } - - /* do no more for a search callback */ - if (context->bufsize == 0) - return 0; - - /* - * It didn't all fit, so we have to sort everything on hashval. - */ - sbsize = sf->hdr.count * sizeof(*sbuf); - sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP | KM_NOFS); - - /* - * Scan the attribute list for the rest of the entries, storing - * the relevant info from only those that match into a buffer. - */ - nsbuf = 0; - for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) { - if (unlikely( - ((char *)sfe < (char *)sf) || - ((char *)sfe >= ((char *)sf + dp->i_afp->if_bytes)))) { - XFS_CORRUPTION_ERROR("xfs_attr_shortform_list", - XFS_ERRLEVEL_LOW, - context->dp->i_mount, sfe); - kmem_free(sbuf); - return -EFSCORRUPTED; - } - - sbp->entno = i; - sbp->hash = xfs_da_hashname(sfe->nameval, sfe->namelen); - sbp->name = sfe->nameval; - sbp->namelen = sfe->namelen; - /* These are bytes, and both on-disk, don't endian-flip */ - sbp->valuelen = sfe->valuelen; - sbp->flags = sfe->flags; - sfe = XFS_ATTR_SF_NEXTENTRY(sfe); - sbp++; - nsbuf++; - } - - /* - * Sort the entries on hash then entno. - */ - xfs_sort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare); - - /* - * Re-find our place IN THE SORTED LIST. - */ - count = 0; - cursor->initted = 1; - cursor->blkno = 0; - for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) { - if (sbp->hash == cursor->hashval) { - if (cursor->offset == count) { - break; - } - count++; - } else if (sbp->hash > cursor->hashval) { - break; - } - } - if (i == nsbuf) { - kmem_free(sbuf); - return 0; - } - - /* - * Loop putting entries into the user buffer. - */ - for ( ; i < nsbuf; i++, sbp++) { - if (cursor->hashval != sbp->hash) { - cursor->hashval = sbp->hash; - cursor->offset = 0; - } - error = context->put_listent(context, - sbp->flags, - sbp->name, - sbp->namelen, - sbp->valuelen); - if (error) { - kmem_free(sbuf); - return error; - } - if (context->seen_enough) - break; - cursor->offset++; - } - - kmem_free(sbuf); - return 0; -} - -STATIC int -xfs_attr_node_list(xfs_attr_list_context_t *context) -{ - attrlist_cursor_kern_t *cursor; - xfs_attr_leafblock_t *leaf; - xfs_da_intnode_t *node; - struct xfs_attr3_icleaf_hdr leafhdr; - struct xfs_da3_icnode_hdr nodehdr; - struct xfs_da_node_entry *btree; - int error, i; - struct xfs_buf *bp; - struct xfs_inode *dp = context->dp; - struct xfs_mount *mp = dp->i_mount; - - trace_xfs_attr_node_list(context); - - cursor = context->cursor; - cursor->initted = 1; - - /* - * Do all sorts of validation on the passed-in cursor structure. - * If anything is amiss, ignore the cursor and look up the hashval - * starting from the btree root. - */ - bp = NULL; - if (cursor->blkno > 0) { - error = xfs_da3_node_read(NULL, dp, cursor->blkno, -1, - &bp, XFS_ATTR_FORK); - if ((error != 0) && (error != -EFSCORRUPTED)) - return error; - if (bp) { - struct xfs_attr_leaf_entry *entries; - - node = bp->b_addr; - switch (be16_to_cpu(node->hdr.info.magic)) { - case XFS_DA_NODE_MAGIC: - case XFS_DA3_NODE_MAGIC: - trace_xfs_attr_list_wrong_blk(context); - xfs_trans_brelse(NULL, bp); - bp = NULL; - break; - case XFS_ATTR_LEAF_MAGIC: - case XFS_ATTR3_LEAF_MAGIC: - leaf = bp->b_addr; - xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, - &leafhdr, leaf); - entries = xfs_attr3_leaf_entryp(leaf); - if (cursor->hashval > be32_to_cpu( - entries[leafhdr.count - 1].hashval)) { - trace_xfs_attr_list_wrong_blk(context); - xfs_trans_brelse(NULL, bp); - bp = NULL; - } else if (cursor->hashval <= be32_to_cpu( - entries[0].hashval)) { - trace_xfs_attr_list_wrong_blk(context); - xfs_trans_brelse(NULL, bp); - bp = NULL; - } - break; - default: - trace_xfs_attr_list_wrong_blk(context); - xfs_trans_brelse(NULL, bp); - bp = NULL; - } - } - } - - /* - * We did not find what we expected given the cursor's contents, - * so we start from the top and work down based on the hash value. - * Note that start of node block is same as start of leaf block. - */ - if (bp == NULL) { - cursor->blkno = 0; - for (;;) { - __uint16_t magic; - - error = xfs_da3_node_read(NULL, dp, - cursor->blkno, -1, &bp, - XFS_ATTR_FORK); - if (error) - return error; - node = bp->b_addr; - magic = be16_to_cpu(node->hdr.info.magic); - if (magic == XFS_ATTR_LEAF_MAGIC || - magic == XFS_ATTR3_LEAF_MAGIC) - break; - if (magic != XFS_DA_NODE_MAGIC && - magic != XFS_DA3_NODE_MAGIC) { - XFS_CORRUPTION_ERROR("xfs_attr_node_list(3)", - XFS_ERRLEVEL_LOW, - context->dp->i_mount, - node); - xfs_trans_brelse(NULL, bp); - return -EFSCORRUPTED; - } - - dp->d_ops->node_hdr_from_disk(&nodehdr, node); - btree = dp->d_ops->node_tree_p(node); - for (i = 0; i < nodehdr.count; btree++, i++) { - if (cursor->hashval - <= be32_to_cpu(btree->hashval)) { - cursor->blkno = be32_to_cpu(btree->before); - trace_xfs_attr_list_node_descend(context, - btree); - break; - } - } - if (i == nodehdr.count) { - xfs_trans_brelse(NULL, bp); - return 0; - } - xfs_trans_brelse(NULL, bp); - } - } - ASSERT(bp != NULL); - - /* - * Roll upward through the blocks, processing each leaf block in - * order. As long as there is space in the result buffer, keep - * adding the information. - */ - for (;;) { - leaf = bp->b_addr; - error = xfs_attr3_leaf_list_int(bp, context); - if (error) { - xfs_trans_brelse(NULL, bp); - return error; - } - xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf); - if (context->seen_enough || leafhdr.forw == 0) - break; - cursor->blkno = leafhdr.forw; - xfs_trans_brelse(NULL, bp); - error = xfs_attr3_leaf_read(NULL, dp, cursor->blkno, -1, &bp); - if (error) - return error; - } - xfs_trans_brelse(NULL, bp); - return 0; -} - -/* - * Copy out attribute list entries for attr_list(), for leaf attribute lists. - */ -int -xfs_attr3_leaf_list_int( - struct xfs_buf *bp, - struct xfs_attr_list_context *context) -{ - struct attrlist_cursor_kern *cursor; - struct xfs_attr_leafblock *leaf; - struct xfs_attr3_icleaf_hdr ichdr; - struct xfs_attr_leaf_entry *entries; - struct xfs_attr_leaf_entry *entry; - int retval; - int i; - struct xfs_mount *mp = context->dp->i_mount; - - trace_xfs_attr_list_leaf(context); - - leaf = bp->b_addr; - xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf); - entries = xfs_attr3_leaf_entryp(leaf); - - cursor = context->cursor; - cursor->initted = 1; - - /* - * Re-find our place in the leaf block if this is a new syscall. - */ - if (context->resynch) { - entry = &entries[0]; - for (i = 0; i < ichdr.count; entry++, i++) { - if (be32_to_cpu(entry->hashval) == cursor->hashval) { - if (cursor->offset == context->dupcnt) { - context->dupcnt = 0; - break; - } - context->dupcnt++; - } else if (be32_to_cpu(entry->hashval) > - cursor->hashval) { - context->dupcnt = 0; - break; - } - } - if (i == ichdr.count) { - trace_xfs_attr_list_notfound(context); - return 0; - } - } else { - entry = &entries[0]; - i = 0; - } - context->resynch = 0; - - /* - * We have found our place, start copying out the new attributes. - */ - retval = 0; - for (; i < ichdr.count; entry++, i++) { - char *name; - int namelen, valuelen; - - if (be32_to_cpu(entry->hashval) != cursor->hashval) { - cursor->hashval = be32_to_cpu(entry->hashval); - cursor->offset = 0; - } - - if (entry->flags & XFS_ATTR_INCOMPLETE) - continue; /* skip incomplete entries */ - - if (entry->flags & XFS_ATTR_LOCAL) { - xfs_attr_leaf_name_local_t *name_loc; - - name_loc = xfs_attr3_leaf_name_local(leaf, i); - name = name_loc->nameval; - namelen = name_loc->namelen; - valuelen = be16_to_cpu(name_loc->valuelen); - } else { - xfs_attr_leaf_name_remote_t *name_rmt; - - name_rmt = xfs_attr3_leaf_name_remote(leaf, i); - name = name_rmt->name; - namelen = name_rmt->namelen; - valuelen = be32_to_cpu(name_rmt->valuelen); - } - - retval = context->put_listent(context, entry->flags, - name, namelen, valuelen); - if (retval) - break; - if (context->seen_enough) - break; - cursor->offset++; - } - trace_xfs_attr_list_leaf_end(context); - return retval; -} - -/* - * Copy out attribute entries for attr_list(), for leaf attribute lists. - */ -STATIC int -xfs_attr_leaf_list(xfs_attr_list_context_t *context) -{ - int error; - struct xfs_buf *bp; - - trace_xfs_attr_leaf_list(context); - - context->cursor->blkno = 0; - error = xfs_attr3_leaf_read(NULL, context->dp, 0, -1, &bp); - if (error) - return error; - - error = xfs_attr3_leaf_list_int(bp, context); - xfs_trans_brelse(NULL, bp); - return error; -} - -int -xfs_attr_list_int( - xfs_attr_list_context_t *context) -{ - int error; - xfs_inode_t *dp = context->dp; - uint lock_mode; - - XFS_STATS_INC(dp->i_mount, xs_attr_list); - - if (XFS_FORCED_SHUTDOWN(dp->i_mount)) - return -EIO; - - /* - * Decide on what work routines to call based on the inode size. - */ - lock_mode = xfs_ilock_attr_map_shared(dp); - if (!xfs_inode_hasattr(dp)) { - error = 0; - } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { - error = xfs_attr_shortform_list(context); - } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { - error = xfs_attr_leaf_list(context); - } else { - error = xfs_attr_node_list(context); - } - xfs_iunlock(dp, lock_mode); - return error; -} - -#define ATTR_ENTBASESIZE /* minimum bytes used by an attr */ \ - (((struct attrlist_ent *) 0)->a_name - (char *) 0) -#define ATTR_ENTSIZE(namelen) /* actual bytes used by an attr */ \ - ((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \ - & ~(sizeof(u_int32_t)-1)) - -/* - * Format an attribute and copy it out to the user's buffer. - * Take care to check values and protect against them changing later, - * we may be reading them directly out of a user buffer. - */ -STATIC int -xfs_attr_put_listent( - xfs_attr_list_context_t *context, - int flags, - unsigned char *name, - int namelen, - int valuelen) -{ - struct attrlist *alist = (struct attrlist *)context->alist; - attrlist_ent_t *aep; - int arraytop; - - ASSERT(!(context->flags & ATTR_KERNOVAL)); - ASSERT(context->count >= 0); - ASSERT(context->count < (ATTR_MAX_VALUELEN/8)); - ASSERT(context->firstu >= sizeof(*alist)); - ASSERT(context->firstu <= context->bufsize); - - /* - * Only list entries in the right namespace. - */ - if (((context->flags & ATTR_SECURE) == 0) != - ((flags & XFS_ATTR_SECURE) == 0)) - return 0; - if (((context->flags & ATTR_ROOT) == 0) != - ((flags & XFS_ATTR_ROOT) == 0)) - return 0; - - arraytop = sizeof(*alist) + - context->count * sizeof(alist->al_offset[0]); - context->firstu -= ATTR_ENTSIZE(namelen); - if (context->firstu < arraytop) { - trace_xfs_attr_list_full(context); - alist->al_more = 1; - context->seen_enough = 1; - return 0; - } - - aep = (attrlist_ent_t *)&context->alist[context->firstu]; - aep->a_valuelen = valuelen; - memcpy(aep->a_name, name, namelen); - aep->a_name[namelen] = 0; - alist->al_offset[context->count++] = context->firstu; - alist->al_count = context->count; - trace_xfs_attr_list_add(context); - return 0; -} - -/* - * Generate a list of extended attribute names and optionally - * also value lengths. Positive return value follows the XFS - * convention of being an error, zero or negative return code - * is the length of the buffer returned (negated), indicating - * success. - */ -int -xfs_attr_list( - xfs_inode_t *dp, - char *buffer, - int bufsize, - int flags, - attrlist_cursor_kern_t *cursor) -{ - xfs_attr_list_context_t context; - struct attrlist *alist; - int error; - - /* - * Validate the cursor. - */ - if (cursor->pad1 || cursor->pad2) - return -EINVAL; - if ((cursor->initted == 0) && - (cursor->hashval || cursor->blkno || cursor->offset)) - return -EINVAL; - - /* - * Check for a properly aligned buffer. - */ - if (((long)buffer) & (sizeof(int)-1)) - return -EFAULT; - if (flags & ATTR_KERNOVAL) - bufsize = 0; - - /* - * Initialize the output buffer. - */ - memset(&context, 0, sizeof(context)); - context.dp = dp; - context.cursor = cursor; - context.resynch = 1; - context.flags = flags; - context.alist = buffer; - context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */ - context.firstu = context.bufsize; - context.put_listent = xfs_attr_put_listent; - - alist = (struct attrlist *)context.alist; - alist->al_count = 0; - alist->al_more = 0; - alist->al_offset[0] = context.bufsize; - - error = xfs_attr_list_int(&context); - ASSERT(error <= 0); - return error; -} diff --git a/src/linux/fs/xfs/xfs_bmap_item.c b/src/linux/fs/xfs/xfs_bmap_item.c deleted file mode 100644 index 9bf57c7..0000000 --- a/src/linux/fs/xfs/xfs_bmap_item.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_trans_priv.h" -#include "xfs_buf_item.h" -#include "xfs_bmap_item.h" -#include "xfs_log.h" -#include "xfs_bmap.h" -#include "xfs_icache.h" -#include "xfs_trace.h" - - -kmem_zone_t *xfs_bui_zone; -kmem_zone_t *xfs_bud_zone; - -static inline struct xfs_bui_log_item *BUI_ITEM(struct xfs_log_item *lip) -{ - return container_of(lip, struct xfs_bui_log_item, bui_item); -} - -void -xfs_bui_item_free( - struct xfs_bui_log_item *buip) -{ - kmem_zone_free(xfs_bui_zone, buip); -} - -STATIC void -xfs_bui_item_size( - struct xfs_log_item *lip, - int *nvecs, - int *nbytes) -{ - struct xfs_bui_log_item *buip = BUI_ITEM(lip); - - *nvecs += 1; - *nbytes += xfs_bui_log_format_sizeof(buip->bui_format.bui_nextents); -} - -/* - * This is called to fill in the vector of log iovecs for the - * given bui log item. We use only 1 iovec, and we point that - * at the bui_log_format structure embedded in the bui item. - * It is at this point that we assert that all of the extent - * slots in the bui item have been filled. - */ -STATIC void -xfs_bui_item_format( - struct xfs_log_item *lip, - struct xfs_log_vec *lv) -{ - struct xfs_bui_log_item *buip = BUI_ITEM(lip); - struct xfs_log_iovec *vecp = NULL; - - ASSERT(atomic_read(&buip->bui_next_extent) == - buip->bui_format.bui_nextents); - - buip->bui_format.bui_type = XFS_LI_BUI; - buip->bui_format.bui_size = 1; - - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_BUI_FORMAT, &buip->bui_format, - xfs_bui_log_format_sizeof(buip->bui_format.bui_nextents)); -} - -/* - * Pinning has no meaning for an bui item, so just return. - */ -STATIC void -xfs_bui_item_pin( - struct xfs_log_item *lip) -{ -} - -/* - * The unpin operation is the last place an BUI is manipulated in the log. It is - * either inserted in the AIL or aborted in the event of a log I/O error. In - * either case, the BUI transaction has been successfully committed to make it - * this far. Therefore, we expect whoever committed the BUI to either construct - * and commit the BUD or drop the BUD's reference in the event of error. Simply - * drop the log's BUI reference now that the log is done with it. - */ -STATIC void -xfs_bui_item_unpin( - struct xfs_log_item *lip, - int remove) -{ - struct xfs_bui_log_item *buip = BUI_ITEM(lip); - - xfs_bui_release(buip); -} - -/* - * BUI items have no locking or pushing. However, since BUIs are pulled from - * the AIL when their corresponding BUDs are committed to disk, their situation - * is very similar to being pinned. Return XFS_ITEM_PINNED so that the caller - * will eventually flush the log. This should help in getting the BUI out of - * the AIL. - */ -STATIC uint -xfs_bui_item_push( - struct xfs_log_item *lip, - struct list_head *buffer_list) -{ - return XFS_ITEM_PINNED; -} - -/* - * The BUI has been either committed or aborted if the transaction has been - * cancelled. If the transaction was cancelled, an BUD isn't going to be - * constructed and thus we free the BUI here directly. - */ -STATIC void -xfs_bui_item_unlock( - struct xfs_log_item *lip) -{ - if (lip->li_flags & XFS_LI_ABORTED) - xfs_bui_item_free(BUI_ITEM(lip)); -} - -/* - * The BUI is logged only once and cannot be moved in the log, so simply return - * the lsn at which it's been logged. - */ -STATIC xfs_lsn_t -xfs_bui_item_committed( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ - return lsn; -} - -/* - * The BUI dependency tracking op doesn't do squat. It can't because - * it doesn't know where the free extent is coming from. The dependency - * tracking has to be handled by the "enclosing" metadata object. For - * example, for inodes, the inode is locked throughout the extent freeing - * so the dependency should be recorded there. - */ -STATIC void -xfs_bui_item_committing( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ -} - -/* - * This is the ops vector shared by all bui log items. - */ -static const struct xfs_item_ops xfs_bui_item_ops = { - .iop_size = xfs_bui_item_size, - .iop_format = xfs_bui_item_format, - .iop_pin = xfs_bui_item_pin, - .iop_unpin = xfs_bui_item_unpin, - .iop_unlock = xfs_bui_item_unlock, - .iop_committed = xfs_bui_item_committed, - .iop_push = xfs_bui_item_push, - .iop_committing = xfs_bui_item_committing, -}; - -/* - * Allocate and initialize an bui item with the given number of extents. - */ -struct xfs_bui_log_item * -xfs_bui_init( - struct xfs_mount *mp) - -{ - struct xfs_bui_log_item *buip; - - buip = kmem_zone_zalloc(xfs_bui_zone, KM_SLEEP); - - xfs_log_item_init(mp, &buip->bui_item, XFS_LI_BUI, &xfs_bui_item_ops); - buip->bui_format.bui_nextents = XFS_BUI_MAX_FAST_EXTENTS; - buip->bui_format.bui_id = (uintptr_t)(void *)buip; - atomic_set(&buip->bui_next_extent, 0); - atomic_set(&buip->bui_refcount, 2); - - return buip; -} - -/* - * Freeing the BUI requires that we remove it from the AIL if it has already - * been placed there. However, the BUI may not yet have been placed in the AIL - * when called by xfs_bui_release() from BUD processing due to the ordering of - * committed vs unpin operations in bulk insert operations. Hence the reference - * count to ensure only the last caller frees the BUI. - */ -void -xfs_bui_release( - struct xfs_bui_log_item *buip) -{ - if (atomic_dec_and_test(&buip->bui_refcount)) { - xfs_trans_ail_remove(&buip->bui_item, SHUTDOWN_LOG_IO_ERROR); - xfs_bui_item_free(buip); - } -} - -static inline struct xfs_bud_log_item *BUD_ITEM(struct xfs_log_item *lip) -{ - return container_of(lip, struct xfs_bud_log_item, bud_item); -} - -STATIC void -xfs_bud_item_size( - struct xfs_log_item *lip, - int *nvecs, - int *nbytes) -{ - *nvecs += 1; - *nbytes += sizeof(struct xfs_bud_log_format); -} - -/* - * This is called to fill in the vector of log iovecs for the - * given bud log item. We use only 1 iovec, and we point that - * at the bud_log_format structure embedded in the bud item. - * It is at this point that we assert that all of the extent - * slots in the bud item have been filled. - */ -STATIC void -xfs_bud_item_format( - struct xfs_log_item *lip, - struct xfs_log_vec *lv) -{ - struct xfs_bud_log_item *budp = BUD_ITEM(lip); - struct xfs_log_iovec *vecp = NULL; - - budp->bud_format.bud_type = XFS_LI_BUD; - budp->bud_format.bud_size = 1; - - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_BUD_FORMAT, &budp->bud_format, - sizeof(struct xfs_bud_log_format)); -} - -/* - * Pinning has no meaning for an bud item, so just return. - */ -STATIC void -xfs_bud_item_pin( - struct xfs_log_item *lip) -{ -} - -/* - * Since pinning has no meaning for an bud item, unpinning does - * not either. - */ -STATIC void -xfs_bud_item_unpin( - struct xfs_log_item *lip, - int remove) -{ -} - -/* - * There isn't much you can do to push on an bud item. It is simply stuck - * waiting for the log to be flushed to disk. - */ -STATIC uint -xfs_bud_item_push( - struct xfs_log_item *lip, - struct list_head *buffer_list) -{ - return XFS_ITEM_PINNED; -} - -/* - * The BUD is either committed or aborted if the transaction is cancelled. If - * the transaction is cancelled, drop our reference to the BUI and free the - * BUD. - */ -STATIC void -xfs_bud_item_unlock( - struct xfs_log_item *lip) -{ - struct xfs_bud_log_item *budp = BUD_ITEM(lip); - - if (lip->li_flags & XFS_LI_ABORTED) { - xfs_bui_release(budp->bud_buip); - kmem_zone_free(xfs_bud_zone, budp); - } -} - -/* - * When the bud item is committed to disk, all we need to do is delete our - * reference to our partner bui item and then free ourselves. Since we're - * freeing ourselves we must return -1 to keep the transaction code from - * further referencing this item. - */ -STATIC xfs_lsn_t -xfs_bud_item_committed( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ - struct xfs_bud_log_item *budp = BUD_ITEM(lip); - - /* - * Drop the BUI reference regardless of whether the BUD has been - * aborted. Once the BUD transaction is constructed, it is the sole - * responsibility of the BUD to release the BUI (even if the BUI is - * aborted due to log I/O error). - */ - xfs_bui_release(budp->bud_buip); - kmem_zone_free(xfs_bud_zone, budp); - - return (xfs_lsn_t)-1; -} - -/* - * The BUD dependency tracking op doesn't do squat. It can't because - * it doesn't know where the free extent is coming from. The dependency - * tracking has to be handled by the "enclosing" metadata object. For - * example, for inodes, the inode is locked throughout the extent freeing - * so the dependency should be recorded there. - */ -STATIC void -xfs_bud_item_committing( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ -} - -/* - * This is the ops vector shared by all bud log items. - */ -static const struct xfs_item_ops xfs_bud_item_ops = { - .iop_size = xfs_bud_item_size, - .iop_format = xfs_bud_item_format, - .iop_pin = xfs_bud_item_pin, - .iop_unpin = xfs_bud_item_unpin, - .iop_unlock = xfs_bud_item_unlock, - .iop_committed = xfs_bud_item_committed, - .iop_push = xfs_bud_item_push, - .iop_committing = xfs_bud_item_committing, -}; - -/* - * Allocate and initialize an bud item with the given number of extents. - */ -struct xfs_bud_log_item * -xfs_bud_init( - struct xfs_mount *mp, - struct xfs_bui_log_item *buip) - -{ - struct xfs_bud_log_item *budp; - - budp = kmem_zone_zalloc(xfs_bud_zone, KM_SLEEP); - xfs_log_item_init(mp, &budp->bud_item, XFS_LI_BUD, &xfs_bud_item_ops); - budp->bud_buip = buip; - budp->bud_format.bud_bui_id = buip->bui_format.bui_id; - - return budp; -} - -/* - * Process a bmap update intent item that was recovered from the log. - * We need to update some inode's bmbt. - */ -int -xfs_bui_recover( - struct xfs_mount *mp, - struct xfs_bui_log_item *buip) -{ - int error = 0; - unsigned int bui_type; - struct xfs_map_extent *bmap; - xfs_fsblock_t startblock_fsb; - xfs_fsblock_t inode_fsb; - bool op_ok; - struct xfs_bud_log_item *budp; - enum xfs_bmap_intent_type type; - int whichfork; - xfs_exntst_t state; - struct xfs_trans *tp; - struct xfs_inode *ip = NULL; - struct xfs_defer_ops dfops; - xfs_fsblock_t firstfsb; - - ASSERT(!test_bit(XFS_BUI_RECOVERED, &buip->bui_flags)); - - /* Only one mapping operation per BUI... */ - if (buip->bui_format.bui_nextents != XFS_BUI_MAX_FAST_EXTENTS) { - set_bit(XFS_BUI_RECOVERED, &buip->bui_flags); - xfs_bui_release(buip); - return -EIO; - } - - /* - * First check the validity of the extent described by the - * BUI. If anything is bad, then toss the BUI. - */ - bmap = &buip->bui_format.bui_extents[0]; - startblock_fsb = XFS_BB_TO_FSB(mp, - XFS_FSB_TO_DADDR(mp, bmap->me_startblock)); - inode_fsb = XFS_BB_TO_FSB(mp, XFS_FSB_TO_DADDR(mp, - XFS_INO_TO_FSB(mp, bmap->me_owner))); - switch (bmap->me_flags & XFS_BMAP_EXTENT_TYPE_MASK) { - case XFS_BMAP_MAP: - case XFS_BMAP_UNMAP: - op_ok = true; - break; - default: - op_ok = false; - break; - } - if (!op_ok || startblock_fsb == 0 || - bmap->me_len == 0 || - inode_fsb == 0 || - startblock_fsb >= mp->m_sb.sb_dblocks || - bmap->me_len >= mp->m_sb.sb_agblocks || - inode_fsb >= mp->m_sb.sb_dblocks || - (bmap->me_flags & ~XFS_BMAP_EXTENT_FLAGS)) { - /* - * This will pull the BUI from the AIL and - * free the memory associated with it. - */ - set_bit(XFS_BUI_RECOVERED, &buip->bui_flags); - xfs_bui_release(buip); - return -EIO; - } - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp); - if (error) - return error; - budp = xfs_trans_get_bud(tp, buip); - - /* Grab the inode. */ - error = xfs_iget(mp, tp, bmap->me_owner, 0, XFS_ILOCK_EXCL, &ip); - if (error) - goto err_inode; - - if (VFS_I(ip)->i_nlink == 0) - xfs_iflags_set(ip, XFS_IRECOVERY); - xfs_defer_init(&dfops, &firstfsb); - - /* Process deferred bmap item. */ - state = (bmap->me_flags & XFS_BMAP_EXTENT_UNWRITTEN) ? - XFS_EXT_UNWRITTEN : XFS_EXT_NORM; - whichfork = (bmap->me_flags & XFS_BMAP_EXTENT_ATTR_FORK) ? - XFS_ATTR_FORK : XFS_DATA_FORK; - bui_type = bmap->me_flags & XFS_BMAP_EXTENT_TYPE_MASK; - switch (bui_type) { - case XFS_BMAP_MAP: - case XFS_BMAP_UNMAP: - type = bui_type; - break; - default: - error = -EFSCORRUPTED; - goto err_dfops; - } - xfs_trans_ijoin(tp, ip, 0); - - error = xfs_trans_log_finish_bmap_update(tp, budp, &dfops, type, - ip, whichfork, bmap->me_startoff, - bmap->me_startblock, bmap->me_len, - state); - if (error) - goto err_dfops; - - /* Finish transaction, free inodes. */ - error = xfs_defer_finish(&tp, &dfops, NULL); - if (error) - goto err_dfops; - - set_bit(XFS_BUI_RECOVERED, &buip->bui_flags); - error = xfs_trans_commit(tp); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - IRELE(ip); - - return error; - -err_dfops: - xfs_defer_cancel(&dfops); -err_inode: - xfs_trans_cancel(tp); - if (ip) { - xfs_iunlock(ip, XFS_ILOCK_EXCL); - IRELE(ip); - } - return error; -} diff --git a/src/linux/fs/xfs/xfs_bmap_item.h b/src/linux/fs/xfs/xfs_bmap_item.h deleted file mode 100644 index c867daa..0000000 --- a/src/linux/fs/xfs/xfs_bmap_item.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#ifndef __XFS_BMAP_ITEM_H__ -#define __XFS_BMAP_ITEM_H__ - -/* - * There are (currently) two pairs of bmap btree redo item types: map & unmap. - * The common abbreviations for these are BUI (bmap update intent) and BUD - * (bmap update done). The redo item type is encoded in the flags field of - * each xfs_map_extent. - * - * *I items should be recorded in the *first* of a series of rolled - * transactions, and the *D items should be recorded in the same transaction - * that records the associated bmbt updates. - * - * Should the system crash after the commit of the first transaction but - * before the commit of the final transaction in a series, log recovery will - * use the redo information recorded by the intent items to replay the - * bmbt metadata updates in the non-first transaction. - */ - -/* kernel only BUI/BUD definitions */ - -struct xfs_mount; -struct kmem_zone; - -/* - * Max number of extents in fast allocation path. - */ -#define XFS_BUI_MAX_FAST_EXTENTS 1 - -/* - * Define BUI flag bits. Manipulated by set/clear/test_bit operators. - */ -#define XFS_BUI_RECOVERED 1 - -/* - * This is the "bmap update intent" log item. It is used to log the fact that - * some reverse mappings need to change. It is used in conjunction with the - * "bmap update done" log item described below. - * - * These log items follow the same rules as struct xfs_efi_log_item; see the - * comments about that structure (in xfs_extfree_item.h) for more details. - */ -struct xfs_bui_log_item { - struct xfs_log_item bui_item; - atomic_t bui_refcount; - atomic_t bui_next_extent; - unsigned long bui_flags; /* misc flags */ - struct xfs_bui_log_format bui_format; -}; - -static inline size_t -xfs_bui_log_item_sizeof( - unsigned int nr) -{ - return offsetof(struct xfs_bui_log_item, bui_format) + - xfs_bui_log_format_sizeof(nr); -} - -/* - * This is the "bmap update done" log item. It is used to log the fact that - * some bmbt updates mentioned in an earlier bui item have been performed. - */ -struct xfs_bud_log_item { - struct xfs_log_item bud_item; - struct xfs_bui_log_item *bud_buip; - struct xfs_bud_log_format bud_format; -}; - -extern struct kmem_zone *xfs_bui_zone; -extern struct kmem_zone *xfs_bud_zone; - -struct xfs_bui_log_item *xfs_bui_init(struct xfs_mount *); -struct xfs_bud_log_item *xfs_bud_init(struct xfs_mount *, - struct xfs_bui_log_item *); -void xfs_bui_item_free(struct xfs_bui_log_item *); -void xfs_bui_release(struct xfs_bui_log_item *); -int xfs_bui_recover(struct xfs_mount *mp, struct xfs_bui_log_item *buip); - -#endif /* __XFS_BMAP_ITEM_H__ */ diff --git a/src/linux/fs/xfs/xfs_bmap_util.c b/src/linux/fs/xfs/xfs_bmap_util.c deleted file mode 100644 index 552465e..0000000 --- a/src/linux/fs/xfs/xfs_bmap_util.c +++ /dev/null @@ -1,2093 +0,0 @@ -/* - * Copyright (c) 2000-2006 Silicon Graphics, Inc. - * Copyright (c) 2012 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_defer.h" -#include "xfs_inode.h" -#include "xfs_btree.h" -#include "xfs_trans.h" -#include "xfs_extfree_item.h" -#include "xfs_alloc.h" -#include "xfs_bmap.h" -#include "xfs_bmap_util.h" -#include "xfs_bmap_btree.h" -#include "xfs_rtalloc.h" -#include "xfs_error.h" -#include "xfs_quota.h" -#include "xfs_trans_space.h" -#include "xfs_trace.h" -#include "xfs_icache.h" -#include "xfs_log.h" -#include "xfs_rmap_btree.h" -#include "xfs_iomap.h" -#include "xfs_reflink.h" -#include "xfs_refcount.h" - -/* Kernel only BMAP related definitions and functions */ - -/* - * Convert the given file system block to a disk block. We have to treat it - * differently based on whether the file is a real time file or not, because the - * bmap code does. - */ -xfs_daddr_t -xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb) -{ - return (XFS_IS_REALTIME_INODE(ip) ? \ - (xfs_daddr_t)XFS_FSB_TO_BB((ip)->i_mount, (fsb)) : \ - XFS_FSB_TO_DADDR((ip)->i_mount, (fsb))); -} - -/* - * Routine to zero an extent on disk allocated to the specific inode. - * - * The VFS functions take a linearised filesystem block offset, so we have to - * convert the sparse xfs fsb to the right format first. - * VFS types are real funky, too. - */ -int -xfs_zero_extent( - struct xfs_inode *ip, - xfs_fsblock_t start_fsb, - xfs_off_t count_fsb) -{ - struct xfs_mount *mp = ip->i_mount; - xfs_daddr_t sector = xfs_fsb_to_db(ip, start_fsb); - sector_t block = XFS_BB_TO_FSBT(mp, sector); - - return blkdev_issue_zeroout(xfs_find_bdev_for_inode(VFS_I(ip)), - block << (mp->m_super->s_blocksize_bits - 9), - count_fsb << (mp->m_super->s_blocksize_bits - 9), - GFP_NOFS, true); -} - -int -xfs_bmap_rtalloc( - struct xfs_bmalloca *ap) /* bmap alloc argument struct */ -{ - xfs_alloctype_t atype = 0; /* type for allocation routines */ - int error; /* error return value */ - xfs_mount_t *mp; /* mount point structure */ - xfs_extlen_t prod = 0; /* product factor for allocators */ - xfs_extlen_t ralen = 0; /* realtime allocation length */ - xfs_extlen_t align; /* minimum allocation alignment */ - xfs_rtblock_t rtb; - - mp = ap->ip->i_mount; - align = xfs_get_extsz_hint(ap->ip); - prod = align / mp->m_sb.sb_rextsize; - error = xfs_bmap_extsize_align(mp, &ap->got, &ap->prev, - align, 1, ap->eof, 0, - ap->conv, &ap->offset, &ap->length); - if (error) - return error; - ASSERT(ap->length); - ASSERT(ap->length % mp->m_sb.sb_rextsize == 0); - - /* - * If the offset & length are not perfectly aligned - * then kill prod, it will just get us in trouble. - */ - if (do_mod(ap->offset, align) || ap->length % align) - prod = 1; - /* - * Set ralen to be the actual requested length in rtextents. - */ - ralen = ap->length / mp->m_sb.sb_rextsize; - /* - * If the old value was close enough to MAXEXTLEN that - * we rounded up to it, cut it back so it's valid again. - * Note that if it's a really large request (bigger than - * MAXEXTLEN), we don't hear about that number, and can't - * adjust the starting point to match it. - */ - if (ralen * mp->m_sb.sb_rextsize >= MAXEXTLEN) - ralen = MAXEXTLEN / mp->m_sb.sb_rextsize; - - /* - * Lock out modifications to both the RT bitmap and summary inodes - */ - xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL|XFS_ILOCK_RTBITMAP); - xfs_trans_ijoin(ap->tp, mp->m_rbmip, XFS_ILOCK_EXCL); - xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL|XFS_ILOCK_RTSUM); - xfs_trans_ijoin(ap->tp, mp->m_rsumip, XFS_ILOCK_EXCL); - - /* - * If it's an allocation to an empty file at offset 0, - * pick an extent that will space things out in the rt area. - */ - if (ap->eof && ap->offset == 0) { - xfs_rtblock_t uninitialized_var(rtx); /* realtime extent no */ - - error = xfs_rtpick_extent(mp, ap->tp, ralen, &rtx); - if (error) - return error; - ap->blkno = rtx * mp->m_sb.sb_rextsize; - } else { - ap->blkno = 0; - } - - xfs_bmap_adjacent(ap); - - /* - * Realtime allocation, done through xfs_rtallocate_extent. - */ - atype = ap->blkno == 0 ? XFS_ALLOCTYPE_ANY_AG : XFS_ALLOCTYPE_NEAR_BNO; - do_div(ap->blkno, mp->m_sb.sb_rextsize); - rtb = ap->blkno; - ap->length = ralen; - if ((error = xfs_rtallocate_extent(ap->tp, ap->blkno, 1, ap->length, - &ralen, atype, ap->wasdel, prod, &rtb))) - return error; - if (rtb == NULLFSBLOCK && prod > 1 && - (error = xfs_rtallocate_extent(ap->tp, ap->blkno, 1, - ap->length, &ralen, atype, - ap->wasdel, 1, &rtb))) - return error; - ap->blkno = rtb; - if (ap->blkno != NULLFSBLOCK) { - ap->blkno *= mp->m_sb.sb_rextsize; - ralen *= mp->m_sb.sb_rextsize; - ap->length = ralen; - ap->ip->i_d.di_nblocks += ralen; - xfs_trans_log_inode(ap->tp, ap->ip, XFS_ILOG_CORE); - if (ap->wasdel) - ap->ip->i_delayed_blks -= ralen; - /* - * Adjust the disk quota also. This was reserved - * earlier. - */ - xfs_trans_mod_dquot_byino(ap->tp, ap->ip, - ap->wasdel ? XFS_TRANS_DQ_DELRTBCOUNT : - XFS_TRANS_DQ_RTBCOUNT, (long) ralen); - - /* Zero the extent if we were asked to do so */ - if (ap->datatype & XFS_ALLOC_USERDATA_ZERO) { - error = xfs_zero_extent(ap->ip, ap->blkno, ap->length); - if (error) - return error; - } - } else { - ap->length = 0; - } - return 0; -} - -/* - * Check if the endoff is outside the last extent. If so the caller will grow - * the allocation to a stripe unit boundary. All offsets are considered outside - * the end of file for an empty fork, so 1 is returned in *eof in that case. - */ -int -xfs_bmap_eof( - struct xfs_inode *ip, - xfs_fileoff_t endoff, - int whichfork, - int *eof) -{ - struct xfs_bmbt_irec rec; - int error; - - error = xfs_bmap_last_extent(NULL, ip, whichfork, &rec, eof); - if (error || *eof) - return error; - - *eof = endoff >= rec.br_startoff + rec.br_blockcount; - return 0; -} - -/* - * Extent tree block counting routines. - */ - -/* - * Count leaf blocks given a range of extent records. - */ -STATIC void -xfs_bmap_count_leaves( - xfs_ifork_t *ifp, - xfs_extnum_t idx, - int numrecs, - int *count) -{ - int b; - - for (b = 0; b < numrecs; b++) { - xfs_bmbt_rec_host_t *frp = xfs_iext_get_ext(ifp, idx + b); - *count += xfs_bmbt_get_blockcount(frp); - } -} - -/* - * Count leaf blocks given a range of extent records originally - * in btree format. - */ -STATIC void -xfs_bmap_disk_count_leaves( - struct xfs_mount *mp, - struct xfs_btree_block *block, - int numrecs, - int *count) -{ - int b; - xfs_bmbt_rec_t *frp; - - for (b = 1; b <= numrecs; b++) { - frp = XFS_BMBT_REC_ADDR(mp, block, b); - *count += xfs_bmbt_disk_get_blockcount(frp); - } -} - -/* - * Recursively walks each level of a btree - * to count total fsblocks in use. - */ -STATIC int /* error */ -xfs_bmap_count_tree( - xfs_mount_t *mp, /* file system mount point */ - xfs_trans_t *tp, /* transaction pointer */ - xfs_ifork_t *ifp, /* inode fork pointer */ - xfs_fsblock_t blockno, /* file system block number */ - int levelin, /* level in btree */ - int *count) /* Count of blocks */ -{ - int error; - xfs_buf_t *bp, *nbp; - int level = levelin; - __be64 *pp; - xfs_fsblock_t bno = blockno; - xfs_fsblock_t nextbno; - struct xfs_btree_block *block, *nextblock; - int numrecs; - - error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, XFS_BMAP_BTREE_REF, - &xfs_bmbt_buf_ops); - if (error) - return error; - *count += 1; - block = XFS_BUF_TO_BLOCK(bp); - - if (--level) { - /* Not at node above leaves, count this level of nodes */ - nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib); - while (nextbno != NULLFSBLOCK) { - error = xfs_btree_read_bufl(mp, tp, nextbno, 0, &nbp, - XFS_BMAP_BTREE_REF, - &xfs_bmbt_buf_ops); - if (error) - return error; - *count += 1; - nextblock = XFS_BUF_TO_BLOCK(nbp); - nextbno = be64_to_cpu(nextblock->bb_u.l.bb_rightsib); - xfs_trans_brelse(tp, nbp); - } - - /* Dive to the next level */ - pp = XFS_BMBT_PTR_ADDR(mp, block, 1, mp->m_bmap_dmxr[1]); - bno = be64_to_cpu(*pp); - if (unlikely((error = - xfs_bmap_count_tree(mp, tp, ifp, bno, level, count)) < 0)) { - xfs_trans_brelse(tp, bp); - XFS_ERROR_REPORT("xfs_bmap_count_tree(1)", - XFS_ERRLEVEL_LOW, mp); - return -EFSCORRUPTED; - } - xfs_trans_brelse(tp, bp); - } else { - /* count all level 1 nodes and their leaves */ - for (;;) { - nextbno = be64_to_cpu(block->bb_u.l.bb_rightsib); - numrecs = be16_to_cpu(block->bb_numrecs); - xfs_bmap_disk_count_leaves(mp, block, numrecs, count); - xfs_trans_brelse(tp, bp); - if (nextbno == NULLFSBLOCK) - break; - bno = nextbno; - error = xfs_btree_read_bufl(mp, tp, bno, 0, &bp, - XFS_BMAP_BTREE_REF, - &xfs_bmbt_buf_ops); - if (error) - return error; - *count += 1; - block = XFS_BUF_TO_BLOCK(bp); - } - } - return 0; -} - -/* - * Count fsblocks of the given fork. - */ -static int /* error */ -xfs_bmap_count_blocks( - xfs_trans_t *tp, /* transaction pointer */ - xfs_inode_t *ip, /* incore inode */ - int whichfork, /* data or attr fork */ - int *count) /* out: count of blocks */ -{ - struct xfs_btree_block *block; /* current btree block */ - xfs_fsblock_t bno; /* block # of "block" */ - xfs_ifork_t *ifp; /* fork structure */ - int level; /* btree level, for checking */ - xfs_mount_t *mp; /* file system mount structure */ - __be64 *pp; /* pointer to block address */ - - bno = NULLFSBLOCK; - mp = ip->i_mount; - ifp = XFS_IFORK_PTR(ip, whichfork); - if ( XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_EXTENTS ) { - xfs_bmap_count_leaves(ifp, 0, - ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t), - count); - return 0; - } - - /* - * Root level must use BMAP_BROOT_PTR_ADDR macro to get ptr out. - */ - block = ifp->if_broot; - level = be16_to_cpu(block->bb_level); - ASSERT(level > 0); - pp = XFS_BMAP_BROOT_PTR_ADDR(mp, block, 1, ifp->if_broot_bytes); - bno = be64_to_cpu(*pp); - ASSERT(bno != NULLFSBLOCK); - ASSERT(XFS_FSB_TO_AGNO(mp, bno) < mp->m_sb.sb_agcount); - ASSERT(XFS_FSB_TO_AGBNO(mp, bno) < mp->m_sb.sb_agblocks); - - if (unlikely(xfs_bmap_count_tree(mp, tp, ifp, bno, level, count) < 0)) { - XFS_ERROR_REPORT("xfs_bmap_count_blocks(2)", XFS_ERRLEVEL_LOW, - mp); - return -EFSCORRUPTED; - } - - return 0; -} - -/* - * returns 1 for success, 0 if we failed to map the extent. - */ -STATIC int -xfs_getbmapx_fix_eof_hole( - xfs_inode_t *ip, /* xfs incore inode pointer */ - int whichfork, - struct getbmapx *out, /* output structure */ - int prealloced, /* this is a file with - * preallocated data space */ - __int64_t end, /* last block requested */ - xfs_fsblock_t startblock, - bool moretocome) -{ - __int64_t fixlen; - xfs_mount_t *mp; /* file system mount point */ - xfs_ifork_t *ifp; /* inode fork pointer */ - xfs_extnum_t lastx; /* last extent pointer */ - xfs_fileoff_t fileblock; - - if (startblock == HOLESTARTBLOCK) { - mp = ip->i_mount; - out->bmv_block = -1; - fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, XFS_ISIZE(ip))); - fixlen -= out->bmv_offset; - if (prealloced && out->bmv_offset + out->bmv_length == end) { - /* Came to hole at EOF. Trim it. */ - if (fixlen <= 0) - return 0; - out->bmv_length = fixlen; - } - } else { - if (startblock == DELAYSTARTBLOCK) - out->bmv_block = -2; - else - out->bmv_block = xfs_fsb_to_db(ip, startblock); - fileblock = XFS_BB_TO_FSB(ip->i_mount, out->bmv_offset); - ifp = XFS_IFORK_PTR(ip, whichfork); - if (!moretocome && - xfs_iext_bno_to_ext(ifp, fileblock, &lastx) && - (lastx == (ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t))-1)) - out->bmv_oflags |= BMV_OF_LAST; - } - - return 1; -} - -/* Adjust the reported bmap around shared/unshared extent transitions. */ -STATIC int -xfs_getbmap_adjust_shared( - struct xfs_inode *ip, - int whichfork, - struct xfs_bmbt_irec *map, - struct getbmapx *out, - struct xfs_bmbt_irec *next_map) -{ - struct xfs_mount *mp = ip->i_mount; - xfs_agnumber_t agno; - xfs_agblock_t agbno; - xfs_agblock_t ebno; - xfs_extlen_t elen; - xfs_extlen_t nlen; - int error; - - next_map->br_startblock = NULLFSBLOCK; - next_map->br_startoff = NULLFILEOFF; - next_map->br_blockcount = 0; - - /* Only written data blocks can be shared. */ - if (!xfs_is_reflink_inode(ip) || whichfork != XFS_DATA_FORK || - map->br_startblock == DELAYSTARTBLOCK || - map->br_startblock == HOLESTARTBLOCK || - ISUNWRITTEN(map)) - return 0; - - agno = XFS_FSB_TO_AGNO(mp, map->br_startblock); - agbno = XFS_FSB_TO_AGBNO(mp, map->br_startblock); - error = xfs_reflink_find_shared(mp, agno, agbno, map->br_blockcount, - &ebno, &elen, true); - if (error) - return error; - - if (ebno == NULLAGBLOCK) { - /* No shared blocks at all. */ - return 0; - } else if (agbno == ebno) { - /* - * Shared extent at (agbno, elen). Shrink the reported - * extent length and prepare to move the start of map[i] - * to agbno+elen, with the aim of (re)formatting the new - * map[i] the next time through the inner loop. - */ - out->bmv_length = XFS_FSB_TO_BB(mp, elen); - out->bmv_oflags |= BMV_OF_SHARED; - if (elen != map->br_blockcount) { - *next_map = *map; - next_map->br_startblock += elen; - next_map->br_startoff += elen; - next_map->br_blockcount -= elen; - } - map->br_blockcount -= elen; - } else { - /* - * There's an unshared extent (agbno, ebno - agbno) - * followed by shared extent at (ebno, elen). Shrink - * the reported extent length to cover only the unshared - * extent and prepare to move up the start of map[i] to - * ebno, with the aim of (re)formatting the new map[i] - * the next time through the inner loop. - */ - *next_map = *map; - nlen = ebno - agbno; - out->bmv_length = XFS_FSB_TO_BB(mp, nlen); - next_map->br_startblock += nlen; - next_map->br_startoff += nlen; - next_map->br_blockcount -= nlen; - map->br_blockcount -= nlen; - } - - return 0; -} - -/* - * Get inode's extents as described in bmv, and format for output. - * Calls formatter to fill the user's buffer until all extents - * are mapped, until the passed-in bmv->bmv_count slots have - * been filled, or until the formatter short-circuits the loop, - * if it is tracking filled-in extents on its own. - */ -int /* error code */ -xfs_getbmap( - xfs_inode_t *ip, - struct getbmapx *bmv, /* user bmap structure */ - xfs_bmap_format_t formatter, /* format to user */ - void *arg) /* formatter arg */ -{ - __int64_t bmvend; /* last block requested */ - int error = 0; /* return value */ - __int64_t fixlen; /* length for -1 case */ - int i; /* extent number */ - int lock; /* lock state */ - xfs_bmbt_irec_t *map; /* buffer for user's data */ - xfs_mount_t *mp; /* file system mount point */ - int nex; /* # of user extents can do */ - int nexleft; /* # of user extents left */ - int subnex; /* # of bmapi's can do */ - int nmap; /* number of map entries */ - struct getbmapx *out; /* output structure */ - int whichfork; /* data or attr fork */ - int prealloced; /* this is a file with - * preallocated data space */ - int iflags; /* interface flags */ - int bmapi_flags; /* flags for xfs_bmapi */ - int cur_ext = 0; - struct xfs_bmbt_irec inject_map; - - mp = ip->i_mount; - iflags = bmv->bmv_iflags; - -#ifndef DEBUG - /* Only allow CoW fork queries if we're debugging. */ - if (iflags & BMV_IF_COWFORK) - return -EINVAL; -#endif - if ((iflags & BMV_IF_ATTRFORK) && (iflags & BMV_IF_COWFORK)) - return -EINVAL; - - if (iflags & BMV_IF_ATTRFORK) - whichfork = XFS_ATTR_FORK; - else if (iflags & BMV_IF_COWFORK) - whichfork = XFS_COW_FORK; - else - whichfork = XFS_DATA_FORK; - - switch (whichfork) { - case XFS_ATTR_FORK: - if (XFS_IFORK_Q(ip)) { - if (ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS && - ip->i_d.di_aformat != XFS_DINODE_FMT_BTREE && - ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL) - return -EINVAL; - } else if (unlikely( - ip->i_d.di_aformat != 0 && - ip->i_d.di_aformat != XFS_DINODE_FMT_EXTENTS)) { - XFS_ERROR_REPORT("xfs_getbmap", XFS_ERRLEVEL_LOW, - ip->i_mount); - return -EFSCORRUPTED; - } - - prealloced = 0; - fixlen = 1LL << 32; - break; - case XFS_COW_FORK: - if (ip->i_cformat != XFS_DINODE_FMT_EXTENTS) - return -EINVAL; - - if (xfs_get_cowextsz_hint(ip)) { - prealloced = 1; - fixlen = mp->m_super->s_maxbytes; - } else { - prealloced = 0; - fixlen = XFS_ISIZE(ip); - } - break; - default: - if (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS && - ip->i_d.di_format != XFS_DINODE_FMT_BTREE && - ip->i_d.di_format != XFS_DINODE_FMT_LOCAL) - return -EINVAL; - - if (xfs_get_extsz_hint(ip) || - ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC|XFS_DIFLAG_APPEND)){ - prealloced = 1; - fixlen = mp->m_super->s_maxbytes; - } else { - prealloced = 0; - fixlen = XFS_ISIZE(ip); - } - break; - } - - if (bmv->bmv_length == -1) { - fixlen = XFS_FSB_TO_BB(mp, XFS_B_TO_FSB(mp, fixlen)); - bmv->bmv_length = - max_t(__int64_t, fixlen - bmv->bmv_offset, 0); - } else if (bmv->bmv_length == 0) { - bmv->bmv_entries = 0; - return 0; - } else if (bmv->bmv_length < 0) { - return -EINVAL; - } - - nex = bmv->bmv_count - 1; - if (nex <= 0) - return -EINVAL; - bmvend = bmv->bmv_offset + bmv->bmv_length; - - - if (bmv->bmv_count > ULONG_MAX / sizeof(struct getbmapx)) - return -ENOMEM; - out = kmem_zalloc_large(bmv->bmv_count * sizeof(struct getbmapx), 0); - if (!out) - return -ENOMEM; - - xfs_ilock(ip, XFS_IOLOCK_SHARED); - switch (whichfork) { - case XFS_DATA_FORK: - if (!(iflags & BMV_IF_DELALLOC) && - (ip->i_delayed_blks || XFS_ISIZE(ip) > ip->i_d.di_size)) { - error = filemap_write_and_wait(VFS_I(ip)->i_mapping); - if (error) - goto out_unlock_iolock; - - /* - * Even after flushing the inode, there can still be - * delalloc blocks on the inode beyond EOF due to - * speculative preallocation. These are not removed - * until the release function is called or the inode - * is inactivated. Hence we cannot assert here that - * ip->i_delayed_blks == 0. - */ - } - - lock = xfs_ilock_data_map_shared(ip); - break; - case XFS_COW_FORK: - lock = XFS_ILOCK_SHARED; - xfs_ilock(ip, lock); - break; - case XFS_ATTR_FORK: - lock = xfs_ilock_attr_map_shared(ip); - break; - } - - /* - * Don't let nex be bigger than the number of extents - * we can have assuming alternating holes and real extents. - */ - if (nex > XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1) - nex = XFS_IFORK_NEXTENTS(ip, whichfork) * 2 + 1; - - bmapi_flags = xfs_bmapi_aflag(whichfork); - if (!(iflags & BMV_IF_PREALLOC)) - bmapi_flags |= XFS_BMAPI_IGSTATE; - - /* - * Allocate enough space to handle "subnex" maps at a time. - */ - error = -ENOMEM; - subnex = 16; - map = kmem_alloc(subnex * sizeof(*map), KM_MAYFAIL | KM_NOFS); - if (!map) - goto out_unlock_ilock; - - bmv->bmv_entries = 0; - - if (XFS_IFORK_NEXTENTS(ip, whichfork) == 0 && - (whichfork == XFS_ATTR_FORK || !(iflags & BMV_IF_DELALLOC))) { - error = 0; - goto out_free_map; - } - - nexleft = nex; - - do { - nmap = (nexleft > subnex) ? subnex : nexleft; - error = xfs_bmapi_read(ip, XFS_BB_TO_FSBT(mp, bmv->bmv_offset), - XFS_BB_TO_FSB(mp, bmv->bmv_length), - map, &nmap, bmapi_flags); - if (error) - goto out_free_map; - ASSERT(nmap <= subnex); - - for (i = 0; i < nmap && nexleft && bmv->bmv_length && - cur_ext < bmv->bmv_count; i++) { - out[cur_ext].bmv_oflags = 0; - if (map[i].br_state == XFS_EXT_UNWRITTEN) - out[cur_ext].bmv_oflags |= BMV_OF_PREALLOC; - else if (map[i].br_startblock == DELAYSTARTBLOCK) - out[cur_ext].bmv_oflags |= BMV_OF_DELALLOC; - out[cur_ext].bmv_offset = - XFS_FSB_TO_BB(mp, map[i].br_startoff); - out[cur_ext].bmv_length = - XFS_FSB_TO_BB(mp, map[i].br_blockcount); - out[cur_ext].bmv_unused1 = 0; - out[cur_ext].bmv_unused2 = 0; - - /* - * delayed allocation extents that start beyond EOF can - * occur due to speculative EOF allocation when the - * delalloc extent is larger than the largest freespace - * extent at conversion time. These extents cannot be - * converted by data writeback, so can exist here even - * if we are not supposed to be finding delalloc - * extents. - */ - if (map[i].br_startblock == DELAYSTARTBLOCK && - map[i].br_startoff <= XFS_B_TO_FSB(mp, XFS_ISIZE(ip))) - ASSERT((iflags & BMV_IF_DELALLOC) != 0); - - if (map[i].br_startblock == HOLESTARTBLOCK && - whichfork == XFS_ATTR_FORK) { - /* came to the end of attribute fork */ - out[cur_ext].bmv_oflags |= BMV_OF_LAST; - goto out_free_map; - } - - /* Is this a shared block? */ - error = xfs_getbmap_adjust_shared(ip, whichfork, - &map[i], &out[cur_ext], &inject_map); - if (error) - goto out_free_map; - - if (!xfs_getbmapx_fix_eof_hole(ip, whichfork, - &out[cur_ext], prealloced, bmvend, - map[i].br_startblock, - inject_map.br_startblock != NULLFSBLOCK)) - goto out_free_map; - - bmv->bmv_offset = - out[cur_ext].bmv_offset + - out[cur_ext].bmv_length; - bmv->bmv_length = - max_t(__int64_t, 0, bmvend - bmv->bmv_offset); - - /* - * In case we don't want to return the hole, - * don't increase cur_ext so that we can reuse - * it in the next loop. - */ - if ((iflags & BMV_IF_NO_HOLES) && - map[i].br_startblock == HOLESTARTBLOCK) { - memset(&out[cur_ext], 0, sizeof(out[cur_ext])); - continue; - } - - if (inject_map.br_startblock != NULLFSBLOCK) { - map[i] = inject_map; - i--; - } else - nexleft--; - bmv->bmv_entries++; - cur_ext++; - } - } while (nmap && nexleft && bmv->bmv_length && - cur_ext < bmv->bmv_count); - - out_free_map: - kmem_free(map); - out_unlock_ilock: - xfs_iunlock(ip, lock); - out_unlock_iolock: - xfs_iunlock(ip, XFS_IOLOCK_SHARED); - - for (i = 0; i < cur_ext; i++) { - int full = 0; /* user array is full */ - - /* format results & advance arg */ - error = formatter(&arg, &out[i], &full); - if (error || full) - break; - } - - kmem_free(out); - return error; -} - -/* - * dead simple method of punching delalyed allocation blocks from a range in - * the inode. Walks a block at a time so will be slow, but is only executed in - * rare error cases so the overhead is not critical. This will always punch out - * both the start and end blocks, even if the ranges only partially overlap - * them, so it is up to the caller to ensure that partial blocks are not - * passed in. - */ -int -xfs_bmap_punch_delalloc_range( - struct xfs_inode *ip, - xfs_fileoff_t start_fsb, - xfs_fileoff_t length) -{ - xfs_fileoff_t remaining = length; - int error = 0; - - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - - do { - int done; - xfs_bmbt_irec_t imap; - int nimaps = 1; - xfs_fsblock_t firstblock; - struct xfs_defer_ops dfops; - - /* - * Map the range first and check that it is a delalloc extent - * before trying to unmap the range. Otherwise we will be - * trying to remove a real extent (which requires a - * transaction) or a hole, which is probably a bad idea... - */ - error = xfs_bmapi_read(ip, start_fsb, 1, &imap, &nimaps, - XFS_BMAPI_ENTIRE); - - if (error) { - /* something screwed, just bail */ - if (!XFS_FORCED_SHUTDOWN(ip->i_mount)) { - xfs_alert(ip->i_mount, - "Failed delalloc mapping lookup ino %lld fsb %lld.", - ip->i_ino, start_fsb); - } - break; - } - if (!nimaps) { - /* nothing there */ - goto next_block; - } - if (imap.br_startblock != DELAYSTARTBLOCK) { - /* been converted, ignore */ - goto next_block; - } - WARN_ON(imap.br_blockcount == 0); - - /* - * Note: while we initialise the firstblock/dfops pair, they - * should never be used because blocks should never be - * allocated or freed for a delalloc extent and hence we need - * don't cancel or finish them after the xfs_bunmapi() call. - */ - xfs_defer_init(&dfops, &firstblock); - error = xfs_bunmapi(NULL, ip, start_fsb, 1, 0, 1, &firstblock, - &dfops, &done); - if (error) - break; - - ASSERT(!xfs_defer_has_unfinished_work(&dfops)); -next_block: - start_fsb++; - remaining--; - } while(remaining > 0); - - return error; -} - -/* - * Test whether it is appropriate to check an inode for and free post EOF - * blocks. The 'force' parameter determines whether we should also consider - * regular files that are marked preallocated or append-only. - */ -bool -xfs_can_free_eofblocks(struct xfs_inode *ip, bool force) -{ - /* prealloc/delalloc exists only on regular files */ - if (!S_ISREG(VFS_I(ip)->i_mode)) - return false; - - /* - * Zero sized files with no cached pages and delalloc blocks will not - * have speculative prealloc/delalloc blocks to remove. - */ - if (VFS_I(ip)->i_size == 0 && - VFS_I(ip)->i_mapping->nrpages == 0 && - ip->i_delayed_blks == 0) - return false; - - /* If we haven't read in the extent list, then don't do it now. */ - if (!(ip->i_df.if_flags & XFS_IFEXTENTS)) - return false; - - /* - * Do not free real preallocated or append-only files unless the file - * has delalloc blocks and we are forced to remove them. - */ - if (ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)) - if (!force || ip->i_delayed_blks == 0) - return false; - - return true; -} - -/* - * This is called by xfs_inactive to free any blocks beyond eof - * when the link count isn't zero and by xfs_dm_punch_hole() when - * punching a hole to EOF. - */ -int -xfs_free_eofblocks( - xfs_mount_t *mp, - xfs_inode_t *ip, - bool need_iolock) -{ - xfs_trans_t *tp; - int error; - xfs_fileoff_t end_fsb; - xfs_fileoff_t last_fsb; - xfs_filblks_t map_len; - int nimaps; - xfs_bmbt_irec_t imap; - - /* - * Figure out if there are any blocks beyond the end - * of the file. If not, then there is nothing to do. - */ - end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)XFS_ISIZE(ip)); - last_fsb = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes); - if (last_fsb <= end_fsb) - return 0; - map_len = last_fsb - end_fsb; - - nimaps = 1; - xfs_ilock(ip, XFS_ILOCK_SHARED); - error = xfs_bmapi_read(ip, end_fsb, map_len, &imap, &nimaps, 0); - xfs_iunlock(ip, XFS_ILOCK_SHARED); - - if (!error && (nimaps != 0) && - (imap.br_startblock != HOLESTARTBLOCK || - ip->i_delayed_blks)) { - /* - * Attach the dquots to the inode up front. - */ - error = xfs_qm_dqattach(ip, 0); - if (error) - return error; - - /* - * There are blocks after the end of file. - * Free them up now by truncating the file to - * its current size. - */ - if (need_iolock) { - if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) - return -EAGAIN; - } - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, - &tp); - if (error) { - ASSERT(XFS_FORCED_SHUTDOWN(mp)); - if (need_iolock) - xfs_iunlock(ip, XFS_IOLOCK_EXCL); - return error; - } - - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, 0); - - /* - * Do not update the on-disk file size. If we update the - * on-disk file size and then the system crashes before the - * contents of the file are flushed to disk then the files - * may be full of holes (ie NULL files bug). - */ - error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, - XFS_ISIZE(ip)); - if (error) { - /* - * If we get an error at this point we simply don't - * bother truncating the file. - */ - xfs_trans_cancel(tp); - } else { - error = xfs_trans_commit(tp); - if (!error) - xfs_inode_clear_eofblocks_tag(ip); - } - - xfs_iunlock(ip, XFS_ILOCK_EXCL); - if (need_iolock) - xfs_iunlock(ip, XFS_IOLOCK_EXCL); - } - return error; -} - -int -xfs_alloc_file_space( - struct xfs_inode *ip, - xfs_off_t offset, - xfs_off_t len, - int alloc_type) -{ - xfs_mount_t *mp = ip->i_mount; - xfs_off_t count; - xfs_filblks_t allocated_fsb; - xfs_filblks_t allocatesize_fsb; - xfs_extlen_t extsz, temp; - xfs_fileoff_t startoffset_fsb; - xfs_fsblock_t firstfsb; - int nimaps; - int quota_flag; - int rt; - xfs_trans_t *tp; - xfs_bmbt_irec_t imaps[1], *imapp; - struct xfs_defer_ops dfops; - uint qblocks, resblks, resrtextents; - int error; - - trace_xfs_alloc_file_space(ip); - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - error = xfs_qm_dqattach(ip, 0); - if (error) - return error; - - if (len <= 0) - return -EINVAL; - - rt = XFS_IS_REALTIME_INODE(ip); - extsz = xfs_get_extsz_hint(ip); - - count = len; - imapp = &imaps[0]; - nimaps = 1; - startoffset_fsb = XFS_B_TO_FSBT(mp, offset); - allocatesize_fsb = XFS_B_TO_FSB(mp, count); - - /* - * Allocate file space until done or until there is an error - */ - while (allocatesize_fsb && !error) { - xfs_fileoff_t s, e; - - /* - * Determine space reservations for data/realtime. - */ - if (unlikely(extsz)) { - s = startoffset_fsb; - do_div(s, extsz); - s *= extsz; - e = startoffset_fsb + allocatesize_fsb; - if ((temp = do_mod(startoffset_fsb, extsz))) - e += temp; - if ((temp = do_mod(e, extsz))) - e += extsz - temp; - } else { - s = 0; - e = allocatesize_fsb; - } - - /* - * The transaction reservation is limited to a 32-bit block - * count, hence we need to limit the number of blocks we are - * trying to reserve to avoid an overflow. We can't allocate - * more than @nimaps extents, and an extent is limited on disk - * to MAXEXTLEN (21 bits), so use that to enforce the limit. - */ - resblks = min_t(xfs_fileoff_t, (e - s), (MAXEXTLEN * nimaps)); - if (unlikely(rt)) { - resrtextents = qblocks = resblks; - resrtextents /= mp->m_sb.sb_rextsize; - resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0); - quota_flag = XFS_QMOPT_RES_RTBLKS; - } else { - resrtextents = 0; - resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, resblks); - quota_flag = XFS_QMOPT_RES_REGBLKS; - } - - /* - * Allocate and setup the transaction. - */ - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, - resrtextents, 0, &tp); - - /* - * Check for running out of space - */ - if (error) { - /* - * Free the transaction structure. - */ - ASSERT(error == -ENOSPC || XFS_FORCED_SHUTDOWN(mp)); - break; - } - xfs_ilock(ip, XFS_ILOCK_EXCL); - error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks, - 0, quota_flag); - if (error) - goto error1; - - xfs_trans_ijoin(tp, ip, 0); - - xfs_defer_init(&dfops, &firstfsb); - error = xfs_bmapi_write(tp, ip, startoffset_fsb, - allocatesize_fsb, alloc_type, &firstfsb, - resblks, imapp, &nimaps, &dfops); - if (error) - goto error0; - - /* - * Complete the transaction - */ - error = xfs_defer_finish(&tp, &dfops, NULL); - if (error) - goto error0; - - error = xfs_trans_commit(tp); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - if (error) - break; - - allocated_fsb = imapp->br_blockcount; - - if (nimaps == 0) { - error = -ENOSPC; - break; - } - - startoffset_fsb += allocated_fsb; - allocatesize_fsb -= allocated_fsb; - } - - return error; - -error0: /* Cancel bmap, unlock inode, unreserve quota blocks, cancel trans */ - xfs_defer_cancel(&dfops); - xfs_trans_unreserve_quota_nblks(tp, ip, (long)qblocks, 0, quota_flag); - -error1: /* Just cancel transaction */ - xfs_trans_cancel(tp); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return error; -} - -static int -xfs_unmap_extent( - struct xfs_inode *ip, - xfs_fileoff_t startoffset_fsb, - xfs_filblks_t len_fsb, - int *done) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_trans *tp; - struct xfs_defer_ops dfops; - xfs_fsblock_t firstfsb; - uint resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0); - int error; - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0, &tp); - if (error) { - ASSERT(error == -ENOSPC || XFS_FORCED_SHUTDOWN(mp)); - return error; - } - - xfs_ilock(ip, XFS_ILOCK_EXCL); - error = xfs_trans_reserve_quota(tp, mp, ip->i_udquot, ip->i_gdquot, - ip->i_pdquot, resblks, 0, XFS_QMOPT_RES_REGBLKS); - if (error) - goto out_trans_cancel; - - xfs_trans_ijoin(tp, ip, 0); - - xfs_defer_init(&dfops, &firstfsb); - error = xfs_bunmapi(tp, ip, startoffset_fsb, len_fsb, 0, 2, &firstfsb, - &dfops, done); - if (error) - goto out_bmap_cancel; - - error = xfs_defer_finish(&tp, &dfops, ip); - if (error) - goto out_bmap_cancel; - - error = xfs_trans_commit(tp); -out_unlock: - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return error; - -out_bmap_cancel: - xfs_defer_cancel(&dfops); -out_trans_cancel: - xfs_trans_cancel(tp); - goto out_unlock; -} - -static int -xfs_adjust_extent_unmap_boundaries( - struct xfs_inode *ip, - xfs_fileoff_t *startoffset_fsb, - xfs_fileoff_t *endoffset_fsb) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_bmbt_irec imap; - int nimap, error; - xfs_extlen_t mod = 0; - - nimap = 1; - error = xfs_bmapi_read(ip, *startoffset_fsb, 1, &imap, &nimap, 0); - if (error) - return error; - - if (nimap && imap.br_startblock != HOLESTARTBLOCK) { - xfs_daddr_t block; - - ASSERT(imap.br_startblock != DELAYSTARTBLOCK); - block = imap.br_startblock; - mod = do_div(block, mp->m_sb.sb_rextsize); - if (mod) - *startoffset_fsb += mp->m_sb.sb_rextsize - mod; - } - - nimap = 1; - error = xfs_bmapi_read(ip, *endoffset_fsb - 1, 1, &imap, &nimap, 0); - if (error) - return error; - - if (nimap && imap.br_startblock != HOLESTARTBLOCK) { - ASSERT(imap.br_startblock != DELAYSTARTBLOCK); - mod++; - if (mod && mod != mp->m_sb.sb_rextsize) - *endoffset_fsb -= mod; - } - - return 0; -} - -static int -xfs_flush_unmap_range( - struct xfs_inode *ip, - xfs_off_t offset, - xfs_off_t len) -{ - struct xfs_mount *mp = ip->i_mount; - struct inode *inode = VFS_I(ip); - xfs_off_t rounding, start, end; - int error; - - /* wait for the completion of any pending DIOs */ - inode_dio_wait(inode); - - rounding = max_t(xfs_off_t, 1 << mp->m_sb.sb_blocklog, PAGE_SIZE); - start = round_down(offset, rounding); - end = round_up(offset + len, rounding) - 1; - - error = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (error) - return error; - truncate_pagecache_range(inode, start, end); - return 0; -} - -int -xfs_free_file_space( - struct xfs_inode *ip, - xfs_off_t offset, - xfs_off_t len) -{ - struct xfs_mount *mp = ip->i_mount; - xfs_fileoff_t startoffset_fsb; - xfs_fileoff_t endoffset_fsb; - int done = 0, error; - - trace_xfs_free_file_space(ip); - - error = xfs_qm_dqattach(ip, 0); - if (error) - return error; - - if (len <= 0) /* if nothing being freed */ - return 0; - - error = xfs_flush_unmap_range(ip, offset, len); - if (error) - return error; - - startoffset_fsb = XFS_B_TO_FSB(mp, offset); - endoffset_fsb = XFS_B_TO_FSBT(mp, offset + len); - - /* - * Need to zero the stuff we're not freeing, on disk. If it's a RT file - * and we can't use unwritten extents then we actually need to ensure - * to zero the whole extent, otherwise we just need to take of block - * boundaries, and xfs_bunmapi will handle the rest. - */ - if (XFS_IS_REALTIME_INODE(ip) && - !xfs_sb_version_hasextflgbit(&mp->m_sb)) { - error = xfs_adjust_extent_unmap_boundaries(ip, &startoffset_fsb, - &endoffset_fsb); - if (error) - return error; - } - - if (endoffset_fsb > startoffset_fsb) { - while (!done) { - error = xfs_unmap_extent(ip, startoffset_fsb, - endoffset_fsb - startoffset_fsb, &done); - if (error) - return error; - } - } - - /* - * Now that we've unmap all full blocks we'll have to zero out any - * partial block at the beginning and/or end. xfs_zero_range is - * smart enough to skip any holes, including those we just created. - */ - return xfs_zero_range(ip, offset, len, NULL); -} - -/* - * Preallocate and zero a range of a file. This mechanism has the allocation - * semantics of fallocate and in addition converts data in the range to zeroes. - */ -int -xfs_zero_file_space( - struct xfs_inode *ip, - xfs_off_t offset, - xfs_off_t len) -{ - struct xfs_mount *mp = ip->i_mount; - uint blksize; - int error; - - trace_xfs_zero_file_space(ip); - - blksize = 1 << mp->m_sb.sb_blocklog; - - /* - * Punch a hole and prealloc the range. We use hole punch rather than - * unwritten extent conversion for two reasons: - * - * 1.) Hole punch handles partial block zeroing for us. - * - * 2.) If prealloc returns ENOSPC, the file range is still zero-valued - * by virtue of the hole punch. - */ - error = xfs_free_file_space(ip, offset, len); - if (error) - goto out; - - error = xfs_alloc_file_space(ip, round_down(offset, blksize), - round_up(offset + len, blksize) - - round_down(offset, blksize), - XFS_BMAPI_PREALLOC); -out: - return error; - -} - -/* - * @next_fsb will keep track of the extent currently undergoing shift. - * @stop_fsb will keep track of the extent at which we have to stop. - * If we are shifting left, we will start with block (offset + len) and - * shift each extent till last extent. - * If we are shifting right, we will start with last extent inside file space - * and continue until we reach the block corresponding to offset. - */ -static int -xfs_shift_file_space( - struct xfs_inode *ip, - xfs_off_t offset, - xfs_off_t len, - enum shift_direction direction) -{ - int done = 0; - struct xfs_mount *mp = ip->i_mount; - struct xfs_trans *tp; - int error; - struct xfs_defer_ops dfops; - xfs_fsblock_t first_block; - xfs_fileoff_t stop_fsb; - xfs_fileoff_t next_fsb; - xfs_fileoff_t shift_fsb; - - ASSERT(direction == SHIFT_LEFT || direction == SHIFT_RIGHT); - - if (direction == SHIFT_LEFT) { - next_fsb = XFS_B_TO_FSB(mp, offset + len); - stop_fsb = XFS_B_TO_FSB(mp, VFS_I(ip)->i_size); - } else { - /* - * If right shift, delegate the work of initialization of - * next_fsb to xfs_bmap_shift_extent as it has ilock held. - */ - next_fsb = NULLFSBLOCK; - stop_fsb = XFS_B_TO_FSB(mp, offset); - } - - shift_fsb = XFS_B_TO_FSB(mp, len); - - /* - * Trim eofblocks to avoid shifting uninitialized post-eof preallocation - * into the accessible region of the file. - */ - if (xfs_can_free_eofblocks(ip, true)) { - error = xfs_free_eofblocks(mp, ip, false); - if (error) - return error; - } - - /* - * Writeback and invalidate cache for the remainder of the file as we're - * about to shift down every extent from offset to EOF. - */ - error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping, - offset, -1); - if (error) - return error; - error = invalidate_inode_pages2_range(VFS_I(ip)->i_mapping, - offset >> PAGE_SHIFT, -1); - if (error) - return error; - - /* - * The extent shiting code works on extent granularity. So, if - * stop_fsb is not the starting block of extent, we need to split - * the extent at stop_fsb. - */ - if (direction == SHIFT_RIGHT) { - error = xfs_bmap_split_extent(ip, stop_fsb); - if (error) - return error; - } - - while (!error && !done) { - /* - * We would need to reserve permanent block for transaction. - * This will come into picture when after shifting extent into - * hole we found that adjacent extents can be merged which - * may lead to freeing of a block during record update. - */ - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, - XFS_DIOSTRAT_SPACE_RES(mp, 0), 0, 0, &tp); - if (error) - break; - - xfs_ilock(ip, XFS_ILOCK_EXCL); - error = xfs_trans_reserve_quota(tp, mp, ip->i_udquot, - ip->i_gdquot, ip->i_pdquot, - XFS_DIOSTRAT_SPACE_RES(mp, 0), 0, - XFS_QMOPT_RES_REGBLKS); - if (error) - goto out_trans_cancel; - - xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); - - xfs_defer_init(&dfops, &first_block); - - /* - * We are using the write transaction in which max 2 bmbt - * updates are allowed - */ - error = xfs_bmap_shift_extents(tp, ip, &next_fsb, shift_fsb, - &done, stop_fsb, &first_block, &dfops, - direction, XFS_BMAP_MAX_SHIFT_EXTENTS); - if (error) - goto out_bmap_cancel; - - error = xfs_defer_finish(&tp, &dfops, NULL); - if (error) - goto out_bmap_cancel; - - error = xfs_trans_commit(tp); - } - - return error; - -out_bmap_cancel: - xfs_defer_cancel(&dfops); -out_trans_cancel: - xfs_trans_cancel(tp); - return error; -} - -/* - * xfs_collapse_file_space() - * This routine frees disk space and shift extent for the given file. - * The first thing we do is to free data blocks in the specified range - * by calling xfs_free_file_space(). It would also sync dirty data - * and invalidate page cache over the region on which collapse range - * is working. And Shift extent records to the left to cover a hole. - * RETURNS: - * 0 on success - * errno on error - * - */ -int -xfs_collapse_file_space( - struct xfs_inode *ip, - xfs_off_t offset, - xfs_off_t len) -{ - int error; - - ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); - trace_xfs_collapse_file_space(ip); - - error = xfs_free_file_space(ip, offset, len); - if (error) - return error; - - return xfs_shift_file_space(ip, offset, len, SHIFT_LEFT); -} - -/* - * xfs_insert_file_space() - * This routine create hole space by shifting extents for the given file. - * The first thing we do is to sync dirty data and invalidate page cache - * over the region on which insert range is working. And split an extent - * to two extents at given offset by calling xfs_bmap_split_extent. - * And shift all extent records which are laying between [offset, - * last allocated extent] to the right to reserve hole range. - * RETURNS: - * 0 on success - * errno on error - */ -int -xfs_insert_file_space( - struct xfs_inode *ip, - loff_t offset, - loff_t len) -{ - ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); - trace_xfs_insert_file_space(ip); - - return xfs_shift_file_space(ip, offset, len, SHIFT_RIGHT); -} - -/* - * We need to check that the format of the data fork in the temporary inode is - * valid for the target inode before doing the swap. This is not a problem with - * attr1 because of the fixed fork offset, but attr2 has a dynamically sized - * data fork depending on the space the attribute fork is taking so we can get - * invalid formats on the target inode. - * - * E.g. target has space for 7 extents in extent format, temp inode only has - * space for 6. If we defragment down to 7 extents, then the tmp format is a - * btree, but when swapped it needs to be in extent format. Hence we can't just - * blindly swap data forks on attr2 filesystems. - * - * Note that we check the swap in both directions so that we don't end up with - * a corrupt temporary inode, either. - * - * Note that fixing the way xfs_fsr sets up the attribute fork in the source - * inode will prevent this situation from occurring, so all we do here is - * reject and log the attempt. basically we are putting the responsibility on - * userspace to get this right. - */ -static int -xfs_swap_extents_check_format( - struct xfs_inode *ip, /* target inode */ - struct xfs_inode *tip) /* tmp inode */ -{ - - /* Should never get a local format */ - if (ip->i_d.di_format == XFS_DINODE_FMT_LOCAL || - tip->i_d.di_format == XFS_DINODE_FMT_LOCAL) - return -EINVAL; - - /* - * if the target inode has less extents that then temporary inode then - * why did userspace call us? - */ - if (ip->i_d.di_nextents < tip->i_d.di_nextents) - return -EINVAL; - - /* - * If we have to use the (expensive) rmap swap method, we can - * handle any number of extents and any format. - */ - if (xfs_sb_version_hasrmapbt(&ip->i_mount->m_sb)) - return 0; - - /* - * if the target inode is in extent form and the temp inode is in btree - * form then we will end up with the target inode in the wrong format - * as we already know there are less extents in the temp inode. - */ - if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && - tip->i_d.di_format == XFS_DINODE_FMT_BTREE) - return -EINVAL; - - /* Check temp in extent form to max in target */ - if (tip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && - XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) > - XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK)) - return -EINVAL; - - /* Check target in extent form to max in temp */ - if (ip->i_d.di_format == XFS_DINODE_FMT_EXTENTS && - XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) > - XFS_IFORK_MAXEXT(tip, XFS_DATA_FORK)) - return -EINVAL; - - /* - * If we are in a btree format, check that the temp root block will fit - * in the target and that it has enough extents to be in btree format - * in the target. - * - * Note that we have to be careful to allow btree->extent conversions - * (a common defrag case) which will occur when the temp inode is in - * extent format... - */ - if (tip->i_d.di_format == XFS_DINODE_FMT_BTREE) { - if (XFS_IFORK_BOFF(ip) && - XFS_BMAP_BMDR_SPACE(tip->i_df.if_broot) > XFS_IFORK_BOFF(ip)) - return -EINVAL; - if (XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK) <= - XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK)) - return -EINVAL; - } - - /* Reciprocal target->temp btree format checks */ - if (ip->i_d.di_format == XFS_DINODE_FMT_BTREE) { - if (XFS_IFORK_BOFF(tip) && - XFS_BMAP_BMDR_SPACE(ip->i_df.if_broot) > XFS_IFORK_BOFF(tip)) - return -EINVAL; - if (XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK) <= - XFS_IFORK_MAXEXT(tip, XFS_DATA_FORK)) - return -EINVAL; - } - - return 0; -} - -static int -xfs_swap_extent_flush( - struct xfs_inode *ip) -{ - int error; - - error = filemap_write_and_wait(VFS_I(ip)->i_mapping); - if (error) - return error; - truncate_pagecache_range(VFS_I(ip), 0, -1); - - /* Verify O_DIRECT for ftmp */ - if (VFS_I(ip)->i_mapping->nrpages) - return -EINVAL; - return 0; -} - -/* - * Move extents from one file to another, when rmap is enabled. - */ -STATIC int -xfs_swap_extent_rmap( - struct xfs_trans **tpp, - struct xfs_inode *ip, - struct xfs_inode *tip) -{ - struct xfs_bmbt_irec irec; - struct xfs_bmbt_irec uirec; - struct xfs_bmbt_irec tirec; - xfs_fileoff_t offset_fsb; - xfs_fileoff_t end_fsb; - xfs_filblks_t count_fsb; - xfs_fsblock_t firstfsb; - struct xfs_defer_ops dfops; - int error; - xfs_filblks_t ilen; - xfs_filblks_t rlen; - int nimaps; - __uint64_t tip_flags2; - - /* - * If the source file has shared blocks, we must flag the donor - * file as having shared blocks so that we get the shared-block - * rmap functions when we go to fix up the rmaps. The flags - * will be switch for reals later. - */ - tip_flags2 = tip->i_d.di_flags2; - if (ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK) - tip->i_d.di_flags2 |= XFS_DIFLAG2_REFLINK; - - offset_fsb = 0; - end_fsb = XFS_B_TO_FSB(ip->i_mount, i_size_read(VFS_I(ip))); - count_fsb = (xfs_filblks_t)(end_fsb - offset_fsb); - - while (count_fsb) { - /* Read extent from the donor file */ - nimaps = 1; - error = xfs_bmapi_read(tip, offset_fsb, count_fsb, &tirec, - &nimaps, 0); - if (error) - goto out; - ASSERT(nimaps == 1); - ASSERT(tirec.br_startblock != DELAYSTARTBLOCK); - - trace_xfs_swap_extent_rmap_remap(tip, &tirec); - ilen = tirec.br_blockcount; - - /* Unmap the old blocks in the source file. */ - while (tirec.br_blockcount) { - xfs_defer_init(&dfops, &firstfsb); - trace_xfs_swap_extent_rmap_remap_piece(tip, &tirec); - - /* Read extent from the source file */ - nimaps = 1; - error = xfs_bmapi_read(ip, tirec.br_startoff, - tirec.br_blockcount, &irec, - &nimaps, 0); - if (error) - goto out_defer; - ASSERT(nimaps == 1); - ASSERT(tirec.br_startoff == irec.br_startoff); - trace_xfs_swap_extent_rmap_remap_piece(ip, &irec); - - /* Trim the extent. */ - uirec = tirec; - uirec.br_blockcount = rlen = min_t(xfs_filblks_t, - tirec.br_blockcount, - irec.br_blockcount); - trace_xfs_swap_extent_rmap_remap_piece(tip, &uirec); - - /* Remove the mapping from the donor file. */ - error = xfs_bmap_unmap_extent((*tpp)->t_mountp, &dfops, - tip, &uirec); - if (error) - goto out_defer; - - /* Remove the mapping from the source file. */ - error = xfs_bmap_unmap_extent((*tpp)->t_mountp, &dfops, - ip, &irec); - if (error) - goto out_defer; - - /* Map the donor file's blocks into the source file. */ - error = xfs_bmap_map_extent((*tpp)->t_mountp, &dfops, - ip, &uirec); - if (error) - goto out_defer; - - /* Map the source file's blocks into the donor file. */ - error = xfs_bmap_map_extent((*tpp)->t_mountp, &dfops, - tip, &irec); - if (error) - goto out_defer; - - error = xfs_defer_finish(tpp, &dfops, ip); - if (error) - goto out_defer; - - tirec.br_startoff += rlen; - if (tirec.br_startblock != HOLESTARTBLOCK && - tirec.br_startblock != DELAYSTARTBLOCK) - tirec.br_startblock += rlen; - tirec.br_blockcount -= rlen; - } - - /* Roll on... */ - count_fsb -= ilen; - offset_fsb += ilen; - } - - tip->i_d.di_flags2 = tip_flags2; - return 0; - -out_defer: - xfs_defer_cancel(&dfops); -out: - trace_xfs_swap_extent_rmap_error(ip, error, _RET_IP_); - tip->i_d.di_flags2 = tip_flags2; - return error; -} - -/* Swap the extents of two files by swapping data forks. */ -STATIC int -xfs_swap_extent_forks( - struct xfs_trans *tp, - struct xfs_inode *ip, - struct xfs_inode *tip, - int *src_log_flags, - int *target_log_flags) -{ - struct xfs_ifork tempifp, *ifp, *tifp; - int aforkblks = 0; - int taforkblks = 0; - __uint64_t tmp; - int error; - - /* - * Count the number of extended attribute blocks - */ - if ( ((XFS_IFORK_Q(ip) != 0) && (ip->i_d.di_anextents > 0)) && - (ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) { - error = xfs_bmap_count_blocks(tp, ip, XFS_ATTR_FORK, - &aforkblks); - if (error) - return error; - } - if ( ((XFS_IFORK_Q(tip) != 0) && (tip->i_d.di_anextents > 0)) && - (tip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL)) { - error = xfs_bmap_count_blocks(tp, tip, XFS_ATTR_FORK, - &taforkblks); - if (error) - return error; - } - - /* - * Before we've swapped the forks, lets set the owners of the forks - * appropriately. We have to do this as we are demand paging the btree - * buffers, and so the validation done on read will expect the owner - * field to be correctly set. Once we change the owners, we can swap the - * inode forks. - */ - if (ip->i_d.di_version == 3 && - ip->i_d.di_format == XFS_DINODE_FMT_BTREE) { - (*target_log_flags) |= XFS_ILOG_DOWNER; - error = xfs_bmbt_change_owner(tp, ip, XFS_DATA_FORK, - tip->i_ino, NULL); - if (error) - return error; - } - - if (tip->i_d.di_version == 3 && - tip->i_d.di_format == XFS_DINODE_FMT_BTREE) { - (*src_log_flags) |= XFS_ILOG_DOWNER; - error = xfs_bmbt_change_owner(tp, tip, XFS_DATA_FORK, - ip->i_ino, NULL); - if (error) - return error; - } - - /* - * Swap the data forks of the inodes - */ - ifp = &ip->i_df; - tifp = &tip->i_df; - tempifp = *ifp; /* struct copy */ - *ifp = *tifp; /* struct copy */ - *tifp = tempifp; /* struct copy */ - - /* - * Fix the on-disk inode values - */ - tmp = (__uint64_t)ip->i_d.di_nblocks; - ip->i_d.di_nblocks = tip->i_d.di_nblocks - taforkblks + aforkblks; - tip->i_d.di_nblocks = tmp + taforkblks - aforkblks; - - tmp = (__uint64_t) ip->i_d.di_nextents; - ip->i_d.di_nextents = tip->i_d.di_nextents; - tip->i_d.di_nextents = tmp; - - tmp = (__uint64_t) ip->i_d.di_format; - ip->i_d.di_format = tip->i_d.di_format; - tip->i_d.di_format = tmp; - - /* - * The extents in the source inode could still contain speculative - * preallocation beyond EOF (e.g. the file is open but not modified - * while defrag is in progress). In that case, we need to copy over the - * number of delalloc blocks the data fork in the source inode is - * tracking beyond EOF so that when the fork is truncated away when the - * temporary inode is unlinked we don't underrun the i_delayed_blks - * counter on that inode. - */ - ASSERT(tip->i_delayed_blks == 0); - tip->i_delayed_blks = ip->i_delayed_blks; - ip->i_delayed_blks = 0; - - switch (ip->i_d.di_format) { - case XFS_DINODE_FMT_EXTENTS: - /* If the extents fit in the inode, fix the - * pointer. Otherwise it's already NULL or - * pointing to the extent. - */ - if (ip->i_d.di_nextents <= XFS_INLINE_EXTS) { - ifp->if_u1.if_extents = - ifp->if_u2.if_inline_ext; - } - (*src_log_flags) |= XFS_ILOG_DEXT; - break; - case XFS_DINODE_FMT_BTREE: - ASSERT(ip->i_d.di_version < 3 || - (*src_log_flags & XFS_ILOG_DOWNER)); - (*src_log_flags) |= XFS_ILOG_DBROOT; - break; - } - - switch (tip->i_d.di_format) { - case XFS_DINODE_FMT_EXTENTS: - /* If the extents fit in the inode, fix the - * pointer. Otherwise it's already NULL or - * pointing to the extent. - */ - if (tip->i_d.di_nextents <= XFS_INLINE_EXTS) { - tifp->if_u1.if_extents = - tifp->if_u2.if_inline_ext; - } - (*target_log_flags) |= XFS_ILOG_DEXT; - break; - case XFS_DINODE_FMT_BTREE: - (*target_log_flags) |= XFS_ILOG_DBROOT; - ASSERT(tip->i_d.di_version < 3 || - (*target_log_flags & XFS_ILOG_DOWNER)); - break; - } - - return 0; -} - -int -xfs_swap_extents( - struct xfs_inode *ip, /* target inode */ - struct xfs_inode *tip, /* tmp inode */ - struct xfs_swapext *sxp) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_trans *tp; - struct xfs_bstat *sbp = &sxp->sx_stat; - int src_log_flags, target_log_flags; - int error = 0; - int lock_flags; - struct xfs_ifork *cowfp; - __uint64_t f; - int resblks; - - /* - * Lock the inodes against other IO, page faults and truncate to - * begin with. Then we can ensure the inodes are flushed and have no - * page cache safely. Once we have done this we can take the ilocks and - * do the rest of the checks. - */ - lock_flags = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL; - xfs_lock_two_inodes(ip, tip, XFS_IOLOCK_EXCL); - xfs_lock_two_inodes(ip, tip, XFS_MMAPLOCK_EXCL); - - /* Verify that both files have the same format */ - if ((VFS_I(ip)->i_mode & S_IFMT) != (VFS_I(tip)->i_mode & S_IFMT)) { - error = -EINVAL; - goto out_unlock; - } - - /* Verify both files are either real-time or non-realtime */ - if (XFS_IS_REALTIME_INODE(ip) != XFS_IS_REALTIME_INODE(tip)) { - error = -EINVAL; - goto out_unlock; - } - - error = xfs_swap_extent_flush(ip); - if (error) - goto out_unlock; - error = xfs_swap_extent_flush(tip); - if (error) - goto out_unlock; - - /* - * Extent "swapping" with rmap requires a permanent reservation and - * a block reservation because it's really just a remap operation - * performed with log redo items! - */ - if (xfs_sb_version_hasrmapbt(&mp->m_sb)) { - /* - * Conceptually this shouldn't affect the shape of either - * bmbt, but since we atomically move extents one by one, - * we reserve enough space to rebuild both trees. - */ - resblks = XFS_SWAP_RMAP_SPACE_RES(mp, - XFS_IFORK_NEXTENTS(ip, XFS_DATA_FORK), - XFS_DATA_FORK) + - XFS_SWAP_RMAP_SPACE_RES(mp, - XFS_IFORK_NEXTENTS(tip, XFS_DATA_FORK), - XFS_DATA_FORK); - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, - 0, 0, &tp); - } else - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0, - 0, 0, &tp); - if (error) - goto out_unlock; - - /* - * Lock and join the inodes to the tansaction so that transaction commit - * or cancel will unlock the inodes from this point onwards. - */ - xfs_lock_two_inodes(ip, tip, XFS_ILOCK_EXCL); - lock_flags |= XFS_ILOCK_EXCL; - xfs_trans_ijoin(tp, ip, 0); - xfs_trans_ijoin(tp, tip, 0); - - - /* Verify all data are being swapped */ - if (sxp->sx_offset != 0 || - sxp->sx_length != ip->i_d.di_size || - sxp->sx_length != tip->i_d.di_size) { - error = -EFAULT; - goto out_trans_cancel; - } - - trace_xfs_swap_extent_before(ip, 0); - trace_xfs_swap_extent_before(tip, 1); - - /* check inode formats now that data is flushed */ - error = xfs_swap_extents_check_format(ip, tip); - if (error) { - xfs_notice(mp, - "%s: inode 0x%llx format is incompatible for exchanging.", - __func__, ip->i_ino); - goto out_trans_cancel; - } - - /* - * Compare the current change & modify times with that - * passed in. If they differ, we abort this swap. - * This is the mechanism used to ensure the calling - * process that the file was not changed out from - * under it. - */ - if ((sbp->bs_ctime.tv_sec != VFS_I(ip)->i_ctime.tv_sec) || - (sbp->bs_ctime.tv_nsec != VFS_I(ip)->i_ctime.tv_nsec) || - (sbp->bs_mtime.tv_sec != VFS_I(ip)->i_mtime.tv_sec) || - (sbp->bs_mtime.tv_nsec != VFS_I(ip)->i_mtime.tv_nsec)) { - error = -EBUSY; - goto out_trans_cancel; - } - - /* - * Note the trickiness in setting the log flags - we set the owner log - * flag on the opposite inode (i.e. the inode we are setting the new - * owner to be) because once we swap the forks and log that, log - * recovery is going to see the fork as owned by the swapped inode, - * not the pre-swapped inodes. - */ - src_log_flags = XFS_ILOG_CORE; - target_log_flags = XFS_ILOG_CORE; - - if (xfs_sb_version_hasrmapbt(&mp->m_sb)) - error = xfs_swap_extent_rmap(&tp, ip, tip); - else - error = xfs_swap_extent_forks(tp, ip, tip, &src_log_flags, - &target_log_flags); - if (error) - goto out_trans_cancel; - - /* Do we have to swap reflink flags? */ - if ((ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK) ^ - (tip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK)) { - f = ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK; - ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK; - ip->i_d.di_flags2 |= tip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK; - tip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK; - tip->i_d.di_flags2 |= f & XFS_DIFLAG2_REFLINK; - cowfp = ip->i_cowfp; - ip->i_cowfp = tip->i_cowfp; - tip->i_cowfp = cowfp; - xfs_inode_set_cowblocks_tag(ip); - xfs_inode_set_cowblocks_tag(tip); - } - - xfs_trans_log_inode(tp, ip, src_log_flags); - xfs_trans_log_inode(tp, tip, target_log_flags); - - /* - * If this is a synchronous mount, make sure that the - * transaction goes to disk before returning to the user. - */ - if (mp->m_flags & XFS_MOUNT_WSYNC) - xfs_trans_set_sync(tp); - - error = xfs_trans_commit(tp); - - trace_xfs_swap_extent_after(ip, 0); - trace_xfs_swap_extent_after(tip, 1); - - xfs_iunlock(ip, lock_flags); - xfs_iunlock(tip, lock_flags); - return error; - -out_trans_cancel: - xfs_trans_cancel(tp); - -out_unlock: - xfs_iunlock(ip, lock_flags); - xfs_iunlock(tip, lock_flags); - return error; -} diff --git a/src/linux/fs/xfs/xfs_bmap_util.h b/src/linux/fs/xfs/xfs_bmap_util.h deleted file mode 100644 index 68a621a..0000000 --- a/src/linux/fs/xfs/xfs_bmap_util.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2000-2006 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_BMAP_UTIL_H__ -#define __XFS_BMAP_UTIL_H__ - -/* Kernel only BMAP related definitions and functions */ - -struct xfs_bmbt_irec; -struct xfs_extent_free_item; -struct xfs_ifork; -struct xfs_inode; -struct xfs_mount; -struct xfs_trans; -struct xfs_bmalloca; - -int xfs_bmap_rtalloc(struct xfs_bmalloca *ap); -int xfs_bmap_eof(struct xfs_inode *ip, xfs_fileoff_t endoff, - int whichfork, int *eof); -int xfs_bmap_punch_delalloc_range(struct xfs_inode *ip, - xfs_fileoff_t start_fsb, xfs_fileoff_t length); - -/* bmap to userspace formatter - copy to user & advance pointer */ -typedef int (*xfs_bmap_format_t)(void **, struct getbmapx *, int *); -int xfs_getbmap(struct xfs_inode *ip, struct getbmapx *bmv, - xfs_bmap_format_t formatter, void *arg); - -/* functions in xfs_bmap.c that are only needed by xfs_bmap_util.c */ -int xfs_bmap_extsize_align(struct xfs_mount *mp, struct xfs_bmbt_irec *gotp, - struct xfs_bmbt_irec *prevp, xfs_extlen_t extsz, - int rt, int eof, int delay, int convert, - xfs_fileoff_t *offp, xfs_extlen_t *lenp); -void xfs_bmap_adjacent(struct xfs_bmalloca *ap); -int xfs_bmap_last_extent(struct xfs_trans *tp, struct xfs_inode *ip, - int whichfork, struct xfs_bmbt_irec *rec, - int *is_empty); - -/* preallocation and hole punch interface */ -int xfs_alloc_file_space(struct xfs_inode *ip, xfs_off_t offset, - xfs_off_t len, int alloc_type); -int xfs_free_file_space(struct xfs_inode *ip, xfs_off_t offset, - xfs_off_t len); -int xfs_zero_file_space(struct xfs_inode *ip, xfs_off_t offset, - xfs_off_t len); -int xfs_collapse_file_space(struct xfs_inode *, xfs_off_t offset, - xfs_off_t len); -int xfs_insert_file_space(struct xfs_inode *, xfs_off_t offset, - xfs_off_t len); - -/* EOF block manipulation functions */ -bool xfs_can_free_eofblocks(struct xfs_inode *ip, bool force); -int xfs_free_eofblocks(struct xfs_mount *mp, struct xfs_inode *ip, - bool need_iolock); - -int xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip, - struct xfs_swapext *sx); - -xfs_daddr_t xfs_fsb_to_db(struct xfs_inode *ip, xfs_fsblock_t fsb); - -#endif /* __XFS_BMAP_UTIL_H__ */ diff --git a/src/linux/fs/xfs/xfs_buf.c b/src/linux/fs/xfs/xfs_buf.c deleted file mode 100644 index ff0f386..0000000 --- a/src/linux/fs/xfs/xfs_buf.c +++ /dev/null @@ -1,2031 +0,0 @@ -/* - * Copyright (c) 2000-2006 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_trace.h" -#include "xfs_log.h" - -static kmem_zone_t *xfs_buf_zone; - -#ifdef XFS_BUF_LOCK_TRACKING -# define XB_SET_OWNER(bp) ((bp)->b_last_holder = current->pid) -# define XB_CLEAR_OWNER(bp) ((bp)->b_last_holder = -1) -# define XB_GET_OWNER(bp) ((bp)->b_last_holder) -#else -# define XB_SET_OWNER(bp) do { } while (0) -# define XB_CLEAR_OWNER(bp) do { } while (0) -# define XB_GET_OWNER(bp) do { } while (0) -#endif - -#define xb_to_gfp(flags) \ - ((((flags) & XBF_READ_AHEAD) ? __GFP_NORETRY : GFP_NOFS) | __GFP_NOWARN) - - -static inline int -xfs_buf_is_vmapped( - struct xfs_buf *bp) -{ - /* - * Return true if the buffer is vmapped. - * - * b_addr is null if the buffer is not mapped, but the code is clever - * enough to know it doesn't have to map a single page, so the check has - * to be both for b_addr and bp->b_page_count > 1. - */ - return bp->b_addr && bp->b_page_count > 1; -} - -static inline int -xfs_buf_vmap_len( - struct xfs_buf *bp) -{ - return (bp->b_page_count * PAGE_SIZE) - bp->b_offset; -} - -/* - * Bump the I/O in flight count on the buftarg if we haven't yet done so for - * this buffer. The count is incremented once per buffer (per hold cycle) - * because the corresponding decrement is deferred to buffer release. Buffers - * can undergo I/O multiple times in a hold-release cycle and per buffer I/O - * tracking adds unnecessary overhead. This is used for sychronization purposes - * with unmount (see xfs_wait_buftarg()), so all we really need is a count of - * in-flight buffers. - * - * Buffers that are never released (e.g., superblock, iclog buffers) must set - * the XBF_NO_IOACCT flag before I/O submission. Otherwise, the buftarg count - * never reaches zero and unmount hangs indefinitely. - */ -static inline void -xfs_buf_ioacct_inc( - struct xfs_buf *bp) -{ - if (bp->b_flags & (XBF_NO_IOACCT|_XBF_IN_FLIGHT)) - return; - - ASSERT(bp->b_flags & XBF_ASYNC); - bp->b_flags |= _XBF_IN_FLIGHT; - percpu_counter_inc(&bp->b_target->bt_io_count); -} - -/* - * Clear the in-flight state on a buffer about to be released to the LRU or - * freed and unaccount from the buftarg. - */ -static inline void -xfs_buf_ioacct_dec( - struct xfs_buf *bp) -{ - if (!(bp->b_flags & _XBF_IN_FLIGHT)) - return; - - bp->b_flags &= ~_XBF_IN_FLIGHT; - percpu_counter_dec(&bp->b_target->bt_io_count); -} - -/* - * When we mark a buffer stale, we remove the buffer from the LRU and clear the - * b_lru_ref count so that the buffer is freed immediately when the buffer - * reference count falls to zero. If the buffer is already on the LRU, we need - * to remove the reference that LRU holds on the buffer. - * - * This prevents build-up of stale buffers on the LRU. - */ -void -xfs_buf_stale( - struct xfs_buf *bp) -{ - ASSERT(xfs_buf_islocked(bp)); - - bp->b_flags |= XBF_STALE; - - /* - * Clear the delwri status so that a delwri queue walker will not - * flush this buffer to disk now that it is stale. The delwri queue has - * a reference to the buffer, so this is safe to do. - */ - bp->b_flags &= ~_XBF_DELWRI_Q; - - /* - * Once the buffer is marked stale and unlocked, a subsequent lookup - * could reset b_flags. There is no guarantee that the buffer is - * unaccounted (released to LRU) before that occurs. Drop in-flight - * status now to preserve accounting consistency. - */ - xfs_buf_ioacct_dec(bp); - - spin_lock(&bp->b_lock); - atomic_set(&bp->b_lru_ref, 0); - if (!(bp->b_state & XFS_BSTATE_DISPOSE) && - (list_lru_del(&bp->b_target->bt_lru, &bp->b_lru))) - atomic_dec(&bp->b_hold); - - ASSERT(atomic_read(&bp->b_hold) >= 1); - spin_unlock(&bp->b_lock); -} - -static int -xfs_buf_get_maps( - struct xfs_buf *bp, - int map_count) -{ - ASSERT(bp->b_maps == NULL); - bp->b_map_count = map_count; - - if (map_count == 1) { - bp->b_maps = &bp->__b_map; - return 0; - } - - bp->b_maps = kmem_zalloc(map_count * sizeof(struct xfs_buf_map), - KM_NOFS); - if (!bp->b_maps) - return -ENOMEM; - return 0; -} - -/* - * Frees b_pages if it was allocated. - */ -static void -xfs_buf_free_maps( - struct xfs_buf *bp) -{ - if (bp->b_maps != &bp->__b_map) { - kmem_free(bp->b_maps); - bp->b_maps = NULL; - } -} - -struct xfs_buf * -_xfs_buf_alloc( - struct xfs_buftarg *target, - struct xfs_buf_map *map, - int nmaps, - xfs_buf_flags_t flags) -{ - struct xfs_buf *bp; - int error; - int i; - - bp = kmem_zone_zalloc(xfs_buf_zone, KM_NOFS); - if (unlikely(!bp)) - return NULL; - - /* - * We don't want certain flags to appear in b_flags unless they are - * specifically set by later operations on the buffer. - */ - flags &= ~(XBF_UNMAPPED | XBF_TRYLOCK | XBF_ASYNC | XBF_READ_AHEAD); - - atomic_set(&bp->b_hold, 1); - atomic_set(&bp->b_lru_ref, 1); - init_completion(&bp->b_iowait); - INIT_LIST_HEAD(&bp->b_lru); - INIT_LIST_HEAD(&bp->b_list); - RB_CLEAR_NODE(&bp->b_rbnode); - sema_init(&bp->b_sema, 0); /* held, no waiters */ - spin_lock_init(&bp->b_lock); - XB_SET_OWNER(bp); - bp->b_target = target; - bp->b_flags = flags; - - /* - * Set length and io_length to the same value initially. - * I/O routines should use io_length, which will be the same in - * most cases but may be reset (e.g. XFS recovery). - */ - error = xfs_buf_get_maps(bp, nmaps); - if (error) { - kmem_zone_free(xfs_buf_zone, bp); - return NULL; - } - - bp->b_bn = map[0].bm_bn; - bp->b_length = 0; - for (i = 0; i < nmaps; i++) { - bp->b_maps[i].bm_bn = map[i].bm_bn; - bp->b_maps[i].bm_len = map[i].bm_len; - bp->b_length += map[i].bm_len; - } - bp->b_io_length = bp->b_length; - - atomic_set(&bp->b_pin_count, 0); - init_waitqueue_head(&bp->b_waiters); - - XFS_STATS_INC(target->bt_mount, xb_create); - trace_xfs_buf_init(bp, _RET_IP_); - - return bp; -} - -/* - * Allocate a page array capable of holding a specified number - * of pages, and point the page buf at it. - */ -STATIC int -_xfs_buf_get_pages( - xfs_buf_t *bp, - int page_count) -{ - /* Make sure that we have a page list */ - if (bp->b_pages == NULL) { - bp->b_page_count = page_count; - if (page_count <= XB_PAGES) { - bp->b_pages = bp->b_page_array; - } else { - bp->b_pages = kmem_alloc(sizeof(struct page *) * - page_count, KM_NOFS); - if (bp->b_pages == NULL) - return -ENOMEM; - } - memset(bp->b_pages, 0, sizeof(struct page *) * page_count); - } - return 0; -} - -/* - * Frees b_pages if it was allocated. - */ -STATIC void -_xfs_buf_free_pages( - xfs_buf_t *bp) -{ - if (bp->b_pages != bp->b_page_array) { - kmem_free(bp->b_pages); - bp->b_pages = NULL; - } -} - -/* - * Releases the specified buffer. - * - * The modification state of any associated pages is left unchanged. - * The buffer must not be on any hash - use xfs_buf_rele instead for - * hashed and refcounted buffers - */ -void -xfs_buf_free( - xfs_buf_t *bp) -{ - trace_xfs_buf_free(bp, _RET_IP_); - - ASSERT(list_empty(&bp->b_lru)); - - if (bp->b_flags & _XBF_PAGES) { -#ifdef CONFIG_MMU - uint i; - - if (xfs_buf_is_vmapped(bp)) - vm_unmap_ram(bp->b_addr - bp->b_offset, - bp->b_page_count); - - for (i = 0; i < bp->b_page_count; i++) { - struct page *page = bp->b_pages[i]; - - __free_page(page); - } -#else - free_pages((unsigned long)page_to_virt(bp->b_pages[0]), - order_base_2(bp->b_page_count)); -#endif - } else if (bp->b_flags & _XBF_KMEM) - kmem_free(bp->b_addr); - _xfs_buf_free_pages(bp); - xfs_buf_free_maps(bp); - kmem_zone_free(xfs_buf_zone, bp); -} - -/* - * Allocates all the pages for buffer in question and builds it's page list. - */ -STATIC int -xfs_buf_allocate_memory( - xfs_buf_t *bp, - uint flags) -{ - size_t size; - size_t nbytes, offset; - gfp_t gfp_mask = xb_to_gfp(flags); - unsigned short page_count, i; - xfs_off_t start, end; - int error; - - /* - * for buffers that are contained within a single page, just allocate - * the memory from the heap - there's no need for the complexity of - * page arrays to keep allocation down to order 0. - */ - size = BBTOB(bp->b_length); - if (size < PAGE_SIZE) { - bp->b_addr = kmem_alloc(size, KM_NOFS); - if (!bp->b_addr) { - /* low memory - use alloc_page loop instead */ - goto use_alloc_page; - } - - if (((unsigned long)(bp->b_addr + size - 1) & PAGE_MASK) != - ((unsigned long)bp->b_addr & PAGE_MASK)) { - /* b_addr spans two pages - use alloc_page instead */ - kmem_free(bp->b_addr); - bp->b_addr = NULL; - goto use_alloc_page; - } - bp->b_offset = offset_in_page(bp->b_addr); - bp->b_pages = bp->b_page_array; - bp->b_pages[0] = virt_to_page(bp->b_addr); - bp->b_page_count = 1; - bp->b_flags |= _XBF_KMEM; - return 0; - } - -use_alloc_page: - start = BBTOB(bp->b_maps[0].bm_bn) >> PAGE_SHIFT; - end = (BBTOB(bp->b_maps[0].bm_bn + bp->b_length) + PAGE_SIZE - 1) - >> PAGE_SHIFT; - page_count = end - start; - error = _xfs_buf_get_pages(bp, page_count); - if (unlikely(error)) - return error; - - offset = bp->b_offset; - bp->b_flags |= _XBF_PAGES; - - for (i = 0; i < bp->b_page_count; i++) { - struct page *page; - uint retries = 0; -retry: -#ifdef CONFIG_MMU - page = alloc_page(gfp_mask); -#else - if (i == 0) - page = alloc_pages(gfp_mask, order_base_2(page_count)); - else - page = bp->b_pages[0] + i; -#endif - if (unlikely(page == NULL)) { - if (flags & XBF_READ_AHEAD) { - bp->b_page_count = i; - error = -ENOMEM; - goto out_free_pages; - } - - /* - * This could deadlock. - * - * But until all the XFS lowlevel code is revamped to - * handle buffer allocation failures we can't do much. - */ - if (!(++retries % 100)) - xfs_err(NULL, - "%s(%u) possible memory allocation deadlock in %s (mode:0x%x)", - current->comm, current->pid, - __func__, gfp_mask); - - XFS_STATS_INC(bp->b_target->bt_mount, xb_page_retries); - congestion_wait(BLK_RW_ASYNC, HZ/50); - goto retry; - } - - XFS_STATS_INC(bp->b_target->bt_mount, xb_page_found); - - nbytes = min_t(size_t, size, PAGE_SIZE - offset); - size -= nbytes; - bp->b_pages[i] = page; - offset = 0; - } - return 0; - -out_free_pages: -#ifdef CONFIG_MMU - for (i = 0; i < bp->b_page_count; i++) - __free_page(bp->b_pages[i]); -#endif - - return error; -} - -/* - * Map buffer into kernel address-space if necessary. - */ -STATIC int -_xfs_buf_map_pages( - xfs_buf_t *bp, - uint flags) -{ - ASSERT(bp->b_flags & _XBF_PAGES); - if (bp->b_page_count == 1) { - /* A single page buffer is always mappable */ - bp->b_addr = page_address(bp->b_pages[0]) + bp->b_offset; - } else if (flags & XBF_UNMAPPED) { - bp->b_addr = NULL; - } else { -#ifdef CONFIG_MMU - int retried = 0; - unsigned noio_flag; - - /* - * vm_map_ram() will allocate auxillary structures (e.g. - * pagetables) with GFP_KERNEL, yet we are likely to be under - * GFP_NOFS context here. Hence we need to tell memory reclaim - * that we are in such a context via PF_MEMALLOC_NOIO to prevent - * memory reclaim re-entering the filesystem here and - * potentially deadlocking. - */ - noio_flag = memalloc_noio_save(); - do { - bp->b_addr = vm_map_ram(bp->b_pages, bp->b_page_count, - -1, PAGE_KERNEL); - if (bp->b_addr) - break; - vm_unmap_aliases(); - } while (retried++ <= 1); - memalloc_noio_restore(noio_flag); -#else - bp->b_addr = page_to_virt(bp->b_pages[0]); -#endif - - if (!bp->b_addr) - return -ENOMEM; - bp->b_addr += bp->b_offset; - } - - return 0; -} - -/* - * Finding and Reading Buffers - */ - -/* - * Look up, and creates if absent, a lockable buffer for - * a given range of an inode. The buffer is returned - * locked. No I/O is implied by this call. - */ -xfs_buf_t * -_xfs_buf_find( - struct xfs_buftarg *btp, - struct xfs_buf_map *map, - int nmaps, - xfs_buf_flags_t flags, - xfs_buf_t *new_bp) -{ - struct xfs_perag *pag; - struct rb_node **rbp; - struct rb_node *parent; - xfs_buf_t *bp; - xfs_daddr_t blkno = map[0].bm_bn; - xfs_daddr_t eofs; - int numblks = 0; - int i; - - for (i = 0; i < nmaps; i++) - numblks += map[i].bm_len; - - /* Check for IOs smaller than the sector size / not sector aligned */ - ASSERT(!(BBTOB(numblks) < btp->bt_meta_sectorsize)); - ASSERT(!(BBTOB(blkno) & (xfs_off_t)btp->bt_meta_sectormask)); - - /* - * Corrupted block numbers can get through to here, unfortunately, so we - * have to check that the buffer falls within the filesystem bounds. - */ - eofs = XFS_FSB_TO_BB(btp->bt_mount, btp->bt_mount->m_sb.sb_dblocks); - if (blkno < 0 || blkno >= eofs) { - /* - * XXX (dgc): we should really be returning -EFSCORRUPTED here, - * but none of the higher level infrastructure supports - * returning a specific error on buffer lookup failures. - */ - xfs_alert(btp->bt_mount, - "%s: Block out of range: block 0x%llx, EOFS 0x%llx ", - __func__, blkno, eofs); - WARN_ON(1); - return NULL; - } - - /* get tree root */ - pag = xfs_perag_get(btp->bt_mount, - xfs_daddr_to_agno(btp->bt_mount, blkno)); - - /* walk tree */ - spin_lock(&pag->pag_buf_lock); - rbp = &pag->pag_buf_tree.rb_node; - parent = NULL; - bp = NULL; - while (*rbp) { - parent = *rbp; - bp = rb_entry(parent, struct xfs_buf, b_rbnode); - - if (blkno < bp->b_bn) - rbp = &(*rbp)->rb_left; - else if (blkno > bp->b_bn) - rbp = &(*rbp)->rb_right; - else { - /* - * found a block number match. If the range doesn't - * match, the only way this is allowed is if the buffer - * in the cache is stale and the transaction that made - * it stale has not yet committed. i.e. we are - * reallocating a busy extent. Skip this buffer and - * continue searching to the right for an exact match. - */ - if (bp->b_length != numblks) { - ASSERT(bp->b_flags & XBF_STALE); - rbp = &(*rbp)->rb_right; - continue; - } - atomic_inc(&bp->b_hold); - goto found; - } - } - - /* No match found */ - if (new_bp) { - rb_link_node(&new_bp->b_rbnode, parent, rbp); - rb_insert_color(&new_bp->b_rbnode, &pag->pag_buf_tree); - /* the buffer keeps the perag reference until it is freed */ - new_bp->b_pag = pag; - spin_unlock(&pag->pag_buf_lock); - } else { - XFS_STATS_INC(btp->bt_mount, xb_miss_locked); - spin_unlock(&pag->pag_buf_lock); - xfs_perag_put(pag); - } - return new_bp; - -found: - spin_unlock(&pag->pag_buf_lock); - xfs_perag_put(pag); - - if (!xfs_buf_trylock(bp)) { - if (flags & XBF_TRYLOCK) { - xfs_buf_rele(bp); - XFS_STATS_INC(btp->bt_mount, xb_busy_locked); - return NULL; - } - xfs_buf_lock(bp); - XFS_STATS_INC(btp->bt_mount, xb_get_locked_waited); - } - - /* - * if the buffer is stale, clear all the external state associated with - * it. We need to keep flags such as how we allocated the buffer memory - * intact here. - */ - if (bp->b_flags & XBF_STALE) { - ASSERT((bp->b_flags & _XBF_DELWRI_Q) == 0); - ASSERT(bp->b_iodone == NULL); - bp->b_flags &= _XBF_KMEM | _XBF_PAGES; - bp->b_ops = NULL; - } - - trace_xfs_buf_find(bp, flags, _RET_IP_); - XFS_STATS_INC(btp->bt_mount, xb_get_locked); - return bp; -} - -/* - * Assembles a buffer covering the specified range. The code is optimised for - * cache hits, as metadata intensive workloads will see 3 orders of magnitude - * more hits than misses. - */ -struct xfs_buf * -xfs_buf_get_map( - struct xfs_buftarg *target, - struct xfs_buf_map *map, - int nmaps, - xfs_buf_flags_t flags) -{ - struct xfs_buf *bp; - struct xfs_buf *new_bp; - int error = 0; - - bp = _xfs_buf_find(target, map, nmaps, flags, NULL); - if (likely(bp)) - goto found; - - new_bp = _xfs_buf_alloc(target, map, nmaps, flags); - if (unlikely(!new_bp)) - return NULL; - - error = xfs_buf_allocate_memory(new_bp, flags); - if (error) { - xfs_buf_free(new_bp); - return NULL; - } - - bp = _xfs_buf_find(target, map, nmaps, flags, new_bp); - if (!bp) { - xfs_buf_free(new_bp); - return NULL; - } - - if (bp != new_bp) - xfs_buf_free(new_bp); - -found: - if (!bp->b_addr) { - error = _xfs_buf_map_pages(bp, flags); - if (unlikely(error)) { - xfs_warn(target->bt_mount, - "%s: failed to map pagesn", __func__); - xfs_buf_relse(bp); - return NULL; - } - } - - /* - * Clear b_error if this is a lookup from a caller that doesn't expect - * valid data to be found in the buffer. - */ - if (!(flags & XBF_READ)) - xfs_buf_ioerror(bp, 0); - - XFS_STATS_INC(target->bt_mount, xb_get); - trace_xfs_buf_get(bp, flags, _RET_IP_); - return bp; -} - -STATIC int -_xfs_buf_read( - xfs_buf_t *bp, - xfs_buf_flags_t flags) -{ - ASSERT(!(flags & XBF_WRITE)); - ASSERT(bp->b_maps[0].bm_bn != XFS_BUF_DADDR_NULL); - - bp->b_flags &= ~(XBF_WRITE | XBF_ASYNC | XBF_READ_AHEAD); - bp->b_flags |= flags & (XBF_READ | XBF_ASYNC | XBF_READ_AHEAD); - - if (flags & XBF_ASYNC) { - xfs_buf_submit(bp); - return 0; - } - return xfs_buf_submit_wait(bp); -} - -xfs_buf_t * -xfs_buf_read_map( - struct xfs_buftarg *target, - struct xfs_buf_map *map, - int nmaps, - xfs_buf_flags_t flags, - const struct xfs_buf_ops *ops) -{ - struct xfs_buf *bp; - - flags |= XBF_READ; - - bp = xfs_buf_get_map(target, map, nmaps, flags); - if (bp) { - trace_xfs_buf_read(bp, flags, _RET_IP_); - - if (!(bp->b_flags & XBF_DONE)) { - XFS_STATS_INC(target->bt_mount, xb_get_read); - bp->b_ops = ops; - _xfs_buf_read(bp, flags); - } else if (flags & XBF_ASYNC) { - /* - * Read ahead call which is already satisfied, - * drop the buffer - */ - xfs_buf_relse(bp); - return NULL; - } else { - /* We do not want read in the flags */ - bp->b_flags &= ~XBF_READ; - } - } - - return bp; -} - -/* - * If we are not low on memory then do the readahead in a deadlock - * safe manner. - */ -void -xfs_buf_readahead_map( - struct xfs_buftarg *target, - struct xfs_buf_map *map, - int nmaps, - const struct xfs_buf_ops *ops) -{ - if (bdi_read_congested(target->bt_bdi)) - return; - - xfs_buf_read_map(target, map, nmaps, - XBF_TRYLOCK|XBF_ASYNC|XBF_READ_AHEAD, ops); -} - -/* - * Read an uncached buffer from disk. Allocates and returns a locked - * buffer containing the disk contents or nothing. - */ -int -xfs_buf_read_uncached( - struct xfs_buftarg *target, - xfs_daddr_t daddr, - size_t numblks, - int flags, - struct xfs_buf **bpp, - const struct xfs_buf_ops *ops) -{ - struct xfs_buf *bp; - - *bpp = NULL; - - bp = xfs_buf_get_uncached(target, numblks, flags); - if (!bp) - return -ENOMEM; - - /* set up the buffer for a read IO */ - ASSERT(bp->b_map_count == 1); - bp->b_bn = XFS_BUF_DADDR_NULL; /* always null for uncached buffers */ - bp->b_maps[0].bm_bn = daddr; - bp->b_flags |= XBF_READ; - bp->b_ops = ops; - - xfs_buf_submit_wait(bp); - if (bp->b_error) { - int error = bp->b_error; - xfs_buf_relse(bp); - return error; - } - - *bpp = bp; - return 0; -} - -/* - * Return a buffer allocated as an empty buffer and associated to external - * memory via xfs_buf_associate_memory() back to it's empty state. - */ -void -xfs_buf_set_empty( - struct xfs_buf *bp, - size_t numblks) -{ - if (bp->b_pages) - _xfs_buf_free_pages(bp); - - bp->b_pages = NULL; - bp->b_page_count = 0; - bp->b_addr = NULL; - bp->b_length = numblks; - bp->b_io_length = numblks; - - ASSERT(bp->b_map_count == 1); - bp->b_bn = XFS_BUF_DADDR_NULL; - bp->b_maps[0].bm_bn = XFS_BUF_DADDR_NULL; - bp->b_maps[0].bm_len = bp->b_length; -} - -static inline struct page * -mem_to_page( - void *addr) -{ - if ((!is_vmalloc_addr(addr))) { - return virt_to_page(addr); - } else { - return vmalloc_to_page(addr); - } -} - -int -xfs_buf_associate_memory( - xfs_buf_t *bp, - void *mem, - size_t len) -{ - int rval; - int i = 0; - unsigned long pageaddr; - unsigned long offset; - size_t buflen; - int page_count; - - pageaddr = (unsigned long)mem & PAGE_MASK; - offset = (unsigned long)mem - pageaddr; - buflen = PAGE_ALIGN(len + offset); - page_count = buflen >> PAGE_SHIFT; - - /* Free any previous set of page pointers */ - if (bp->b_pages) - _xfs_buf_free_pages(bp); - - bp->b_pages = NULL; - bp->b_addr = mem; - - rval = _xfs_buf_get_pages(bp, page_count); - if (rval) - return rval; - - bp->b_offset = offset; - - for (i = 0; i < bp->b_page_count; i++) { - bp->b_pages[i] = mem_to_page((void *)pageaddr); - pageaddr += PAGE_SIZE; - } - - bp->b_io_length = BTOBB(len); - bp->b_length = BTOBB(buflen); - - return 0; -} - -xfs_buf_t * -xfs_buf_get_uncached( - struct xfs_buftarg *target, - size_t numblks, - int flags) -{ - unsigned long page_count; - int error, i; - struct xfs_buf *bp; - DEFINE_SINGLE_BUF_MAP(map, XFS_BUF_DADDR_NULL, numblks); - - /* flags might contain irrelevant bits, pass only what we care about */ - bp = _xfs_buf_alloc(target, &map, 1, flags & XBF_NO_IOACCT); - if (unlikely(bp == NULL)) - goto fail; - - page_count = PAGE_ALIGN(numblks << BBSHIFT) >> PAGE_SHIFT; - error = _xfs_buf_get_pages(bp, page_count); - if (error) - goto fail_free_buf; - -#ifdef CONFIG_MMU - for (i = 0; i < page_count; i++) { - bp->b_pages[i] = alloc_page(xb_to_gfp(flags)); - if (!bp->b_pages[i]) - goto fail_free_mem; - } -#else - bp->b_pages[0] = alloc_pages(flags, order_base_2(page_count)); - if (!bp->b_pages[0]) - goto fail_free_buf; - for (i = 1; i < page_count; i++) - bp->b_pages[i] = bp->b_pages[i-1] + 1; -#endif - bp->b_flags |= _XBF_PAGES; - - error = _xfs_buf_map_pages(bp, 0); - if (unlikely(error)) { - xfs_warn(target->bt_mount, - "%s: failed to map pages", __func__); - goto fail_free_mem; - } - - trace_xfs_buf_get_uncached(bp, _RET_IP_); - return bp; - - fail_free_mem: - while (--i >= 0) - __free_page(bp->b_pages[i]); - _xfs_buf_free_pages(bp); - fail_free_buf: - xfs_buf_free_maps(bp); - kmem_zone_free(xfs_buf_zone, bp); - fail: - return NULL; -} - -/* - * Increment reference count on buffer, to hold the buffer concurrently - * with another thread which may release (free) the buffer asynchronously. - * Must hold the buffer already to call this function. - */ -void -xfs_buf_hold( - xfs_buf_t *bp) -{ - trace_xfs_buf_hold(bp, _RET_IP_); - atomic_inc(&bp->b_hold); -} - -/* - * Release a hold on the specified buffer. If the hold count is 1, the buffer is - * placed on LRU or freed (depending on b_lru_ref). - */ -void -xfs_buf_rele( - xfs_buf_t *bp) -{ - struct xfs_perag *pag = bp->b_pag; - bool release; - bool freebuf = false; - - trace_xfs_buf_rele(bp, _RET_IP_); - - if (!pag) { - ASSERT(list_empty(&bp->b_lru)); - ASSERT(RB_EMPTY_NODE(&bp->b_rbnode)); - if (atomic_dec_and_test(&bp->b_hold)) { - xfs_buf_ioacct_dec(bp); - xfs_buf_free(bp); - } - return; - } - - ASSERT(!RB_EMPTY_NODE(&bp->b_rbnode)); - - ASSERT(atomic_read(&bp->b_hold) > 0); - - release = atomic_dec_and_lock(&bp->b_hold, &pag->pag_buf_lock); - spin_lock(&bp->b_lock); - if (!release) { - /* - * Drop the in-flight state if the buffer is already on the LRU - * and it holds the only reference. This is racy because we - * haven't acquired the pag lock, but the use of _XBF_IN_FLIGHT - * ensures the decrement occurs only once per-buf. - */ - if ((atomic_read(&bp->b_hold) == 1) && !list_empty(&bp->b_lru)) - xfs_buf_ioacct_dec(bp); - goto out_unlock; - } - - /* the last reference has been dropped ... */ - xfs_buf_ioacct_dec(bp); - if (!(bp->b_flags & XBF_STALE) && atomic_read(&bp->b_lru_ref)) { - /* - * If the buffer is added to the LRU take a new reference to the - * buffer for the LRU and clear the (now stale) dispose list - * state flag - */ - if (list_lru_add(&bp->b_target->bt_lru, &bp->b_lru)) { - bp->b_state &= ~XFS_BSTATE_DISPOSE; - atomic_inc(&bp->b_hold); - } - spin_unlock(&pag->pag_buf_lock); - } else { - /* - * most of the time buffers will already be removed from the - * LRU, so optimise that case by checking for the - * XFS_BSTATE_DISPOSE flag indicating the last list the buffer - * was on was the disposal list - */ - if (!(bp->b_state & XFS_BSTATE_DISPOSE)) { - list_lru_del(&bp->b_target->bt_lru, &bp->b_lru); - } else { - ASSERT(list_empty(&bp->b_lru)); - } - - ASSERT(!(bp->b_flags & _XBF_DELWRI_Q)); - rb_erase(&bp->b_rbnode, &pag->pag_buf_tree); - spin_unlock(&pag->pag_buf_lock); - xfs_perag_put(pag); - freebuf = true; - } - -out_unlock: - spin_unlock(&bp->b_lock); - - if (freebuf) - xfs_buf_free(bp); -} - - -/* - * Lock a buffer object, if it is not already locked. - * - * If we come across a stale, pinned, locked buffer, we know that we are - * being asked to lock a buffer that has been reallocated. Because it is - * pinned, we know that the log has not been pushed to disk and hence it - * will still be locked. Rather than continuing to have trylock attempts - * fail until someone else pushes the log, push it ourselves before - * returning. This means that the xfsaild will not get stuck trying - * to push on stale inode buffers. - */ -int -xfs_buf_trylock( - struct xfs_buf *bp) -{ - int locked; - - locked = down_trylock(&bp->b_sema) == 0; - if (locked) { - XB_SET_OWNER(bp); - trace_xfs_buf_trylock(bp, _RET_IP_); - } else { - trace_xfs_buf_trylock_fail(bp, _RET_IP_); - } - return locked; -} - -/* - * Lock a buffer object. - * - * If we come across a stale, pinned, locked buffer, we know that we - * are being asked to lock a buffer that has been reallocated. Because - * it is pinned, we know that the log has not been pushed to disk and - * hence it will still be locked. Rather than sleeping until someone - * else pushes the log, push it ourselves before trying to get the lock. - */ -void -xfs_buf_lock( - struct xfs_buf *bp) -{ - trace_xfs_buf_lock(bp, _RET_IP_); - - if (atomic_read(&bp->b_pin_count) && (bp->b_flags & XBF_STALE)) - xfs_log_force(bp->b_target->bt_mount, 0); - down(&bp->b_sema); - XB_SET_OWNER(bp); - - trace_xfs_buf_lock_done(bp, _RET_IP_); -} - -void -xfs_buf_unlock( - struct xfs_buf *bp) -{ - XB_CLEAR_OWNER(bp); - up(&bp->b_sema); - - trace_xfs_buf_unlock(bp, _RET_IP_); -} - -STATIC void -xfs_buf_wait_unpin( - xfs_buf_t *bp) -{ - DECLARE_WAITQUEUE (wait, current); - - if (atomic_read(&bp->b_pin_count) == 0) - return; - - add_wait_queue(&bp->b_waiters, &wait); - for (;;) { - set_current_state(TASK_UNINTERRUPTIBLE); - if (atomic_read(&bp->b_pin_count) == 0) - break; - io_schedule(); - } - remove_wait_queue(&bp->b_waiters, &wait); - set_current_state(TASK_RUNNING); -} - -/* - * Buffer Utility Routines - */ - -void -xfs_buf_ioend( - struct xfs_buf *bp) -{ - bool read = bp->b_flags & XBF_READ; - - trace_xfs_buf_iodone(bp, _RET_IP_); - - bp->b_flags &= ~(XBF_READ | XBF_WRITE | XBF_READ_AHEAD); - - /* - * Pull in IO completion errors now. We are guaranteed to be running - * single threaded, so we don't need the lock to read b_io_error. - */ - if (!bp->b_error && bp->b_io_error) - xfs_buf_ioerror(bp, bp->b_io_error); - - /* Only validate buffers that were read without errors */ - if (read && !bp->b_error && bp->b_ops) { - ASSERT(!bp->b_iodone); - bp->b_ops->verify_read(bp); - } - - if (!bp->b_error) - bp->b_flags |= XBF_DONE; - - if (bp->b_iodone) - (*(bp->b_iodone))(bp); - else if (bp->b_flags & XBF_ASYNC) - xfs_buf_relse(bp); - else - complete(&bp->b_iowait); -} - -static void -xfs_buf_ioend_work( - struct work_struct *work) -{ - struct xfs_buf *bp = - container_of(work, xfs_buf_t, b_ioend_work); - - xfs_buf_ioend(bp); -} - -static void -xfs_buf_ioend_async( - struct xfs_buf *bp) -{ - INIT_WORK(&bp->b_ioend_work, xfs_buf_ioend_work); - queue_work(bp->b_ioend_wq, &bp->b_ioend_work); -} - -void -xfs_buf_ioerror( - xfs_buf_t *bp, - int error) -{ - ASSERT(error <= 0 && error >= -1000); - bp->b_error = error; - trace_xfs_buf_ioerror(bp, error, _RET_IP_); -} - -void -xfs_buf_ioerror_alert( - struct xfs_buf *bp, - const char *func) -{ - xfs_alert(bp->b_target->bt_mount, -"metadata I/O error: block 0x%llx (\"%s\") error %d numblks %d", - (__uint64_t)XFS_BUF_ADDR(bp), func, -bp->b_error, bp->b_length); -} - -int -xfs_bwrite( - struct xfs_buf *bp) -{ - int error; - - ASSERT(xfs_buf_islocked(bp)); - - bp->b_flags |= XBF_WRITE; - bp->b_flags &= ~(XBF_ASYNC | XBF_READ | _XBF_DELWRI_Q | - XBF_WRITE_FAIL | XBF_DONE); - - error = xfs_buf_submit_wait(bp); - if (error) { - xfs_force_shutdown(bp->b_target->bt_mount, - SHUTDOWN_META_IO_ERROR); - } - return error; -} - -static void -xfs_buf_bio_end_io( - struct bio *bio) -{ - struct xfs_buf *bp = (struct xfs_buf *)bio->bi_private; - - /* - * don't overwrite existing errors - otherwise we can lose errors on - * buffers that require multiple bios to complete. - */ - if (bio->bi_error) - cmpxchg(&bp->b_io_error, 0, bio->bi_error); - - if (!bp->b_error && xfs_buf_is_vmapped(bp) && (bp->b_flags & XBF_READ)) - invalidate_kernel_vmap_range(bp->b_addr, xfs_buf_vmap_len(bp)); - - if (atomic_dec_and_test(&bp->b_io_remaining) == 1) - xfs_buf_ioend_async(bp); - bio_put(bio); -} - -static void -xfs_buf_ioapply_map( - struct xfs_buf *bp, - int map, - int *buf_offset, - int *count, - int op, - int op_flags) -{ - int page_index; - int total_nr_pages = bp->b_page_count; - int nr_pages; - struct bio *bio; - sector_t sector = bp->b_maps[map].bm_bn; - int size; - int offset; - - total_nr_pages = bp->b_page_count; - - /* skip the pages in the buffer before the start offset */ - page_index = 0; - offset = *buf_offset; - while (offset >= PAGE_SIZE) { - page_index++; - offset -= PAGE_SIZE; - } - - /* - * Limit the IO size to the length of the current vector, and update the - * remaining IO count for the next time around. - */ - size = min_t(int, BBTOB(bp->b_maps[map].bm_len), *count); - *count -= size; - *buf_offset += size; - -next_chunk: - atomic_inc(&bp->b_io_remaining); - nr_pages = min(total_nr_pages, BIO_MAX_PAGES); - - bio = bio_alloc(GFP_NOIO, nr_pages); - bio->bi_bdev = bp->b_target->bt_bdev; - bio->bi_iter.bi_sector = sector; - bio->bi_end_io = xfs_buf_bio_end_io; - bio->bi_private = bp; - bio_set_op_attrs(bio, op, op_flags); - - for (; size && nr_pages; nr_pages--, page_index++) { - int rbytes, nbytes = PAGE_SIZE - offset; - - if (nbytes > size) - nbytes = size; - - rbytes = bio_add_page(bio, bp->b_pages[page_index], nbytes, - offset); - if (rbytes < nbytes) - break; - - offset = 0; - sector += BTOBB(nbytes); - size -= nbytes; - total_nr_pages--; - } - - if (likely(bio->bi_iter.bi_size)) { - if (xfs_buf_is_vmapped(bp)) { - flush_kernel_vmap_range(bp->b_addr, - xfs_buf_vmap_len(bp)); - } - submit_bio(bio); - if (size) - goto next_chunk; - } else { - /* - * This is guaranteed not to be the last io reference count - * because the caller (xfs_buf_submit) holds a count itself. - */ - atomic_dec(&bp->b_io_remaining); - xfs_buf_ioerror(bp, -EIO); - bio_put(bio); - } - -} - -STATIC void -_xfs_buf_ioapply( - struct xfs_buf *bp) -{ - struct blk_plug plug; - int op; - int op_flags = 0; - int offset; - int size; - int i; - - /* - * Make sure we capture only current IO errors rather than stale errors - * left over from previous use of the buffer (e.g. failed readahead). - */ - bp->b_error = 0; - - /* - * Initialize the I/O completion workqueue if we haven't yet or the - * submitter has not opted to specify a custom one. - */ - if (!bp->b_ioend_wq) - bp->b_ioend_wq = bp->b_target->bt_mount->m_buf_workqueue; - - if (bp->b_flags & XBF_WRITE) { - op = REQ_OP_WRITE; - if (bp->b_flags & XBF_SYNCIO) - op_flags = WRITE_SYNC; - if (bp->b_flags & XBF_FUA) - op_flags |= REQ_FUA; - if (bp->b_flags & XBF_FLUSH) - op_flags |= REQ_PREFLUSH; - - /* - * Run the write verifier callback function if it exists. If - * this function fails it will mark the buffer with an error and - * the IO should not be dispatched. - */ - if (bp->b_ops) { - bp->b_ops->verify_write(bp); - if (bp->b_error) { - xfs_force_shutdown(bp->b_target->bt_mount, - SHUTDOWN_CORRUPT_INCORE); - return; - } - } else if (bp->b_bn != XFS_BUF_DADDR_NULL) { - struct xfs_mount *mp = bp->b_target->bt_mount; - - /* - * non-crc filesystems don't attach verifiers during - * log recovery, so don't warn for such filesystems. - */ - if (xfs_sb_version_hascrc(&mp->m_sb)) { - xfs_warn(mp, - "%s: no ops on block 0x%llx/0x%x", - __func__, bp->b_bn, bp->b_length); - xfs_hex_dump(bp->b_addr, 64); - dump_stack(); - } - } - } else if (bp->b_flags & XBF_READ_AHEAD) { - op = REQ_OP_READ; - op_flags = REQ_RAHEAD; - } else { - op = REQ_OP_READ; - } - - /* we only use the buffer cache for meta-data */ - op_flags |= REQ_META; - - /* - * Walk all the vectors issuing IO on them. Set up the initial offset - * into the buffer and the desired IO size before we start - - * _xfs_buf_ioapply_vec() will modify them appropriately for each - * subsequent call. - */ - offset = bp->b_offset; - size = BBTOB(bp->b_io_length); - blk_start_plug(&plug); - for (i = 0; i < bp->b_map_count; i++) { - xfs_buf_ioapply_map(bp, i, &offset, &size, op, op_flags); - if (bp->b_error) - break; - if (size <= 0) - break; /* all done */ - } - blk_finish_plug(&plug); -} - -/* - * Asynchronous IO submission path. This transfers the buffer lock ownership and - * the current reference to the IO. It is not safe to reference the buffer after - * a call to this function unless the caller holds an additional reference - * itself. - */ -void -xfs_buf_submit( - struct xfs_buf *bp) -{ - trace_xfs_buf_submit(bp, _RET_IP_); - - ASSERT(!(bp->b_flags & _XBF_DELWRI_Q)); - ASSERT(bp->b_flags & XBF_ASYNC); - - /* on shutdown we stale and complete the buffer immediately */ - if (XFS_FORCED_SHUTDOWN(bp->b_target->bt_mount)) { - xfs_buf_ioerror(bp, -EIO); - bp->b_flags &= ~XBF_DONE; - xfs_buf_stale(bp); - xfs_buf_ioend(bp); - return; - } - - if (bp->b_flags & XBF_WRITE) - xfs_buf_wait_unpin(bp); - - /* clear the internal error state to avoid spurious errors */ - bp->b_io_error = 0; - - /* - * The caller's reference is released during I/O completion. - * This occurs some time after the last b_io_remaining reference is - * released, so after we drop our Io reference we have to have some - * other reference to ensure the buffer doesn't go away from underneath - * us. Take a direct reference to ensure we have safe access to the - * buffer until we are finished with it. - */ - xfs_buf_hold(bp); - - /* - * Set the count to 1 initially, this will stop an I/O completion - * callout which happens before we have started all the I/O from calling - * xfs_buf_ioend too early. - */ - atomic_set(&bp->b_io_remaining, 1); - xfs_buf_ioacct_inc(bp); - _xfs_buf_ioapply(bp); - - /* - * If _xfs_buf_ioapply failed, we can get back here with only the IO - * reference we took above. If we drop it to zero, run completion so - * that we don't return to the caller with completion still pending. - */ - if (atomic_dec_and_test(&bp->b_io_remaining) == 1) { - if (bp->b_error) - xfs_buf_ioend(bp); - else - xfs_buf_ioend_async(bp); - } - - xfs_buf_rele(bp); - /* Note: it is not safe to reference bp now we've dropped our ref */ -} - -/* - * Synchronous buffer IO submission path, read or write. - */ -int -xfs_buf_submit_wait( - struct xfs_buf *bp) -{ - int error; - - trace_xfs_buf_submit_wait(bp, _RET_IP_); - - ASSERT(!(bp->b_flags & (_XBF_DELWRI_Q | XBF_ASYNC))); - - if (XFS_FORCED_SHUTDOWN(bp->b_target->bt_mount)) { - xfs_buf_ioerror(bp, -EIO); - xfs_buf_stale(bp); - bp->b_flags &= ~XBF_DONE; - return -EIO; - } - - if (bp->b_flags & XBF_WRITE) - xfs_buf_wait_unpin(bp); - - /* clear the internal error state to avoid spurious errors */ - bp->b_io_error = 0; - - /* - * For synchronous IO, the IO does not inherit the submitters reference - * count, nor the buffer lock. Hence we cannot release the reference we - * are about to take until we've waited for all IO completion to occur, - * including any xfs_buf_ioend_async() work that may be pending. - */ - xfs_buf_hold(bp); - - /* - * Set the count to 1 initially, this will stop an I/O completion - * callout which happens before we have started all the I/O from calling - * xfs_buf_ioend too early. - */ - atomic_set(&bp->b_io_remaining, 1); - _xfs_buf_ioapply(bp); - - /* - * make sure we run completion synchronously if it raced with us and is - * already complete. - */ - if (atomic_dec_and_test(&bp->b_io_remaining) == 1) - xfs_buf_ioend(bp); - - /* wait for completion before gathering the error from the buffer */ - trace_xfs_buf_iowait(bp, _RET_IP_); - wait_for_completion(&bp->b_iowait); - trace_xfs_buf_iowait_done(bp, _RET_IP_); - error = bp->b_error; - - /* - * all done now, we can release the hold that keeps the buffer - * referenced for the entire IO. - */ - xfs_buf_rele(bp); - return error; -} - -void * -xfs_buf_offset( - struct xfs_buf *bp, - size_t offset) -{ - struct page *page; - - if (bp->b_addr) - return bp->b_addr + offset; - - offset += bp->b_offset; - page = bp->b_pages[offset >> PAGE_SHIFT]; - return page_address(page) + (offset & (PAGE_SIZE-1)); -} - -/* - * Move data into or out of a buffer. - */ -void -xfs_buf_iomove( - xfs_buf_t *bp, /* buffer to process */ - size_t boff, /* starting buffer offset */ - size_t bsize, /* length to copy */ - void *data, /* data address */ - xfs_buf_rw_t mode) /* read/write/zero flag */ -{ - size_t bend; - - bend = boff + bsize; - while (boff < bend) { - struct page *page; - int page_index, page_offset, csize; - - page_index = (boff + bp->b_offset) >> PAGE_SHIFT; - page_offset = (boff + bp->b_offset) & ~PAGE_MASK; - page = bp->b_pages[page_index]; - csize = min_t(size_t, PAGE_SIZE - page_offset, - BBTOB(bp->b_io_length) - boff); - - ASSERT((csize + page_offset) <= PAGE_SIZE); - - switch (mode) { - case XBRW_ZERO: - memset(page_address(page) + page_offset, 0, csize); - break; - case XBRW_READ: - memcpy(data, page_address(page) + page_offset, csize); - break; - case XBRW_WRITE: - memcpy(page_address(page) + page_offset, data, csize); - } - - boff += csize; - data += csize; - } -} - -/* - * Handling of buffer targets (buftargs). - */ - -/* - * Wait for any bufs with callbacks that have been submitted but have not yet - * returned. These buffers will have an elevated hold count, so wait on those - * while freeing all the buffers only held by the LRU. - */ -static enum lru_status -xfs_buftarg_wait_rele( - struct list_head *item, - struct list_lru_one *lru, - spinlock_t *lru_lock, - void *arg) - -{ - struct xfs_buf *bp = container_of(item, struct xfs_buf, b_lru); - struct list_head *dispose = arg; - - if (atomic_read(&bp->b_hold) > 1) { - /* need to wait, so skip it this pass */ - trace_xfs_buf_wait_buftarg(bp, _RET_IP_); - return LRU_SKIP; - } - if (!spin_trylock(&bp->b_lock)) - return LRU_SKIP; - - /* - * clear the LRU reference count so the buffer doesn't get - * ignored in xfs_buf_rele(). - */ - atomic_set(&bp->b_lru_ref, 0); - bp->b_state |= XFS_BSTATE_DISPOSE; - list_lru_isolate_move(lru, item, dispose); - spin_unlock(&bp->b_lock); - return LRU_REMOVED; -} - -void -xfs_wait_buftarg( - struct xfs_buftarg *btp) -{ - LIST_HEAD(dispose); - int loop = 0; - - /* - * First wait on the buftarg I/O count for all in-flight buffers to be - * released. This is critical as new buffers do not make the LRU until - * they are released. - * - * Next, flush the buffer workqueue to ensure all completion processing - * has finished. Just waiting on buffer locks is not sufficient for - * async IO as the reference count held over IO is not released until - * after the buffer lock is dropped. Hence we need to ensure here that - * all reference counts have been dropped before we start walking the - * LRU list. - */ - while (percpu_counter_sum(&btp->bt_io_count)) - delay(100); - flush_workqueue(btp->bt_mount->m_buf_workqueue); - - /* loop until there is nothing left on the lru list. */ - while (list_lru_count(&btp->bt_lru)) { - list_lru_walk(&btp->bt_lru, xfs_buftarg_wait_rele, - &dispose, LONG_MAX); - - while (!list_empty(&dispose)) { - struct xfs_buf *bp; - bp = list_first_entry(&dispose, struct xfs_buf, b_lru); - list_del_init(&bp->b_lru); - if (bp->b_flags & XBF_WRITE_FAIL) { - xfs_alert(btp->bt_mount, -"Corruption Alert: Buffer at block 0x%llx had permanent write failures!", - (long long)bp->b_bn); - xfs_alert(btp->bt_mount, -"Please run xfs_repair to determine the extent of the problem."); - } - xfs_buf_rele(bp); - } - if (loop++ != 0) - delay(100); - } -} - -static enum lru_status -xfs_buftarg_isolate( - struct list_head *item, - struct list_lru_one *lru, - spinlock_t *lru_lock, - void *arg) -{ - struct xfs_buf *bp = container_of(item, struct xfs_buf, b_lru); - struct list_head *dispose = arg; - - /* - * we are inverting the lru lock/bp->b_lock here, so use a trylock. - * If we fail to get the lock, just skip it. - */ - if (!spin_trylock(&bp->b_lock)) - return LRU_SKIP; - /* - * Decrement the b_lru_ref count unless the value is already - * zero. If the value is already zero, we need to reclaim the - * buffer, otherwise it gets another trip through the LRU. - */ - if (!atomic_add_unless(&bp->b_lru_ref, -1, 0)) { - spin_unlock(&bp->b_lock); - return LRU_ROTATE; - } - - bp->b_state |= XFS_BSTATE_DISPOSE; - list_lru_isolate_move(lru, item, dispose); - spin_unlock(&bp->b_lock); - return LRU_REMOVED; -} - -static unsigned long -xfs_buftarg_shrink_scan( - struct shrinker *shrink, - struct shrink_control *sc) -{ - struct xfs_buftarg *btp = container_of(shrink, - struct xfs_buftarg, bt_shrinker); - LIST_HEAD(dispose); - unsigned long freed; - - freed = list_lru_shrink_walk(&btp->bt_lru, sc, - xfs_buftarg_isolate, &dispose); - - while (!list_empty(&dispose)) { - struct xfs_buf *bp; - bp = list_first_entry(&dispose, struct xfs_buf, b_lru); - list_del_init(&bp->b_lru); - xfs_buf_rele(bp); - } - - return freed; -} - -static unsigned long -xfs_buftarg_shrink_count( - struct shrinker *shrink, - struct shrink_control *sc) -{ - struct xfs_buftarg *btp = container_of(shrink, - struct xfs_buftarg, bt_shrinker); - return list_lru_shrink_count(&btp->bt_lru, sc); -} - -void -xfs_free_buftarg( - struct xfs_mount *mp, - struct xfs_buftarg *btp) -{ - unregister_shrinker(&btp->bt_shrinker); - ASSERT(percpu_counter_sum(&btp->bt_io_count) == 0); - percpu_counter_destroy(&btp->bt_io_count); - list_lru_destroy(&btp->bt_lru); - - if (mp->m_flags & XFS_MOUNT_BARRIER) - xfs_blkdev_issue_flush(btp); - - kmem_free(btp); -} - -int -xfs_setsize_buftarg( - xfs_buftarg_t *btp, - unsigned int sectorsize) -{ - /* Set up metadata sector size info */ - btp->bt_meta_sectorsize = sectorsize; - btp->bt_meta_sectormask = sectorsize - 1; - - if (set_blocksize(btp->bt_bdev, sectorsize)) { - xfs_warn(btp->bt_mount, - "Cannot set_blocksize to %u on device %pg", - sectorsize, btp->bt_bdev); - return -EINVAL; - } - - /* Set up device logical sector size mask */ - btp->bt_logical_sectorsize = bdev_logical_block_size(btp->bt_bdev); - btp->bt_logical_sectormask = bdev_logical_block_size(btp->bt_bdev) - 1; - - return 0; -} - -/* - * When allocating the initial buffer target we have not yet - * read in the superblock, so don't know what sized sectors - * are being used at this early stage. Play safe. - */ -STATIC int -xfs_setsize_buftarg_early( - xfs_buftarg_t *btp, - struct block_device *bdev) -{ - return xfs_setsize_buftarg(btp, bdev_logical_block_size(bdev)); -} - -xfs_buftarg_t * -xfs_alloc_buftarg( - struct xfs_mount *mp, - struct block_device *bdev) -{ - xfs_buftarg_t *btp; - - btp = kmem_zalloc(sizeof(*btp), KM_SLEEP | KM_NOFS); - - btp->bt_mount = mp; - btp->bt_dev = bdev->bd_dev; - btp->bt_bdev = bdev; - btp->bt_bdi = blk_get_backing_dev_info(bdev); - - if (xfs_setsize_buftarg_early(btp, bdev)) - goto error; - - if (list_lru_init(&btp->bt_lru)) - goto error; - - if (percpu_counter_init(&btp->bt_io_count, 0, GFP_KERNEL)) - goto error; - - btp->bt_shrinker.count_objects = xfs_buftarg_shrink_count; - btp->bt_shrinker.scan_objects = xfs_buftarg_shrink_scan; - btp->bt_shrinker.seeks = DEFAULT_SEEKS; - btp->bt_shrinker.flags = SHRINKER_NUMA_AWARE; - register_shrinker(&btp->bt_shrinker); - return btp; - -error: - kmem_free(btp); - return NULL; -} - -/* - * Add a buffer to the delayed write list. - * - * This queues a buffer for writeout if it hasn't already been. Note that - * neither this routine nor the buffer list submission functions perform - * any internal synchronization. It is expected that the lists are thread-local - * to the callers. - * - * Returns true if we queued up the buffer, or false if it already had - * been on the buffer list. - */ -bool -xfs_buf_delwri_queue( - struct xfs_buf *bp, - struct list_head *list) -{ - ASSERT(xfs_buf_islocked(bp)); - ASSERT(!(bp->b_flags & XBF_READ)); - - /* - * If the buffer is already marked delwri it already is queued up - * by someone else for imediate writeout. Just ignore it in that - * case. - */ - if (bp->b_flags & _XBF_DELWRI_Q) { - trace_xfs_buf_delwri_queued(bp, _RET_IP_); - return false; - } - - trace_xfs_buf_delwri_queue(bp, _RET_IP_); - - /* - * If a buffer gets written out synchronously or marked stale while it - * is on a delwri list we lazily remove it. To do this, the other party - * clears the _XBF_DELWRI_Q flag but otherwise leaves the buffer alone. - * It remains referenced and on the list. In a rare corner case it - * might get readded to a delwri list after the synchronous writeout, in - * which case we need just need to re-add the flag here. - */ - bp->b_flags |= _XBF_DELWRI_Q; - if (list_empty(&bp->b_list)) { - atomic_inc(&bp->b_hold); - list_add_tail(&bp->b_list, list); - } - - return true; -} - -/* - * Compare function is more complex than it needs to be because - * the return value is only 32 bits and we are doing comparisons - * on 64 bit values - */ -static int -xfs_buf_cmp( - void *priv, - struct list_head *a, - struct list_head *b) -{ - struct xfs_buf *ap = container_of(a, struct xfs_buf, b_list); - struct xfs_buf *bp = container_of(b, struct xfs_buf, b_list); - xfs_daddr_t diff; - - diff = ap->b_maps[0].bm_bn - bp->b_maps[0].bm_bn; - if (diff < 0) - return -1; - if (diff > 0) - return 1; - return 0; -} - -/* - * submit buffers for write. - * - * When we have a large buffer list, we do not want to hold all the buffers - * locked while we block on the request queue waiting for IO dispatch. To avoid - * this problem, we lock and submit buffers in groups of 50, thereby minimising - * the lock hold times for lists which may contain thousands of objects. - * - * To do this, we sort the buffer list before we walk the list to lock and - * submit buffers, and we plug and unplug around each group of buffers we - * submit. - */ -static int -xfs_buf_delwri_submit_buffers( - struct list_head *buffer_list, - struct list_head *wait_list) -{ - struct xfs_buf *bp, *n; - LIST_HEAD (submit_list); - int pinned = 0; - struct blk_plug plug; - - list_sort(NULL, buffer_list, xfs_buf_cmp); - - blk_start_plug(&plug); - list_for_each_entry_safe(bp, n, buffer_list, b_list) { - if (!wait_list) { - if (xfs_buf_ispinned(bp)) { - pinned++; - continue; - } - if (!xfs_buf_trylock(bp)) - continue; - } else { - xfs_buf_lock(bp); - } - - /* - * Someone else might have written the buffer synchronously or - * marked it stale in the meantime. In that case only the - * _XBF_DELWRI_Q flag got cleared, and we have to drop the - * reference and remove it from the list here. - */ - if (!(bp->b_flags & _XBF_DELWRI_Q)) { - list_del_init(&bp->b_list); - xfs_buf_relse(bp); - continue; - } - - trace_xfs_buf_delwri_split(bp, _RET_IP_); - - /* - * We do all IO submission async. This means if we need - * to wait for IO completion we need to take an extra - * reference so the buffer is still valid on the other - * side. We need to move the buffer onto the io_list - * at this point so the caller can still access it. - */ - bp->b_flags &= ~(_XBF_DELWRI_Q | XBF_WRITE_FAIL); - bp->b_flags |= XBF_WRITE | XBF_ASYNC; - if (wait_list) { - xfs_buf_hold(bp); - list_move_tail(&bp->b_list, wait_list); - } else - list_del_init(&bp->b_list); - - xfs_buf_submit(bp); - } - blk_finish_plug(&plug); - - return pinned; -} - -/* - * Write out a buffer list asynchronously. - * - * This will take the @buffer_list, write all non-locked and non-pinned buffers - * out and not wait for I/O completion on any of the buffers. This interface - * is only safely useable for callers that can track I/O completion by higher - * level means, e.g. AIL pushing as the @buffer_list is consumed in this - * function. - */ -int -xfs_buf_delwri_submit_nowait( - struct list_head *buffer_list) -{ - return xfs_buf_delwri_submit_buffers(buffer_list, NULL); -} - -/* - * Write out a buffer list synchronously. - * - * This will take the @buffer_list, write all buffers out and wait for I/O - * completion on all of the buffers. @buffer_list is consumed by the function, - * so callers must have some other way of tracking buffers if they require such - * functionality. - */ -int -xfs_buf_delwri_submit( - struct list_head *buffer_list) -{ - LIST_HEAD (wait_list); - int error = 0, error2; - struct xfs_buf *bp; - - xfs_buf_delwri_submit_buffers(buffer_list, &wait_list); - - /* Wait for IO to complete. */ - while (!list_empty(&wait_list)) { - bp = list_first_entry(&wait_list, struct xfs_buf, b_list); - - list_del_init(&bp->b_list); - - /* locking the buffer will wait for async IO completion. */ - xfs_buf_lock(bp); - error2 = bp->b_error; - xfs_buf_relse(bp); - if (!error) - error = error2; - } - - return error; -} - -int __init -xfs_buf_init(void) -{ - xfs_buf_zone = kmem_zone_init_flags(sizeof(xfs_buf_t), "xfs_buf", - KM_ZONE_HWALIGN, NULL); - if (!xfs_buf_zone) - goto out; - - return 0; - - out: - return -ENOMEM; -} - -void -xfs_buf_terminate(void) -{ - kmem_zone_destroy(xfs_buf_zone); -} diff --git a/src/linux/fs/xfs/xfs_buf.h b/src/linux/fs/xfs/xfs_buf.h deleted file mode 100644 index 1c2e52b..0000000 --- a/src/linux/fs/xfs/xfs_buf.h +++ /dev/null @@ -1,396 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_BUF_H__ -#define __XFS_BUF_H__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Base types - */ - -#define XFS_BUF_DADDR_NULL ((xfs_daddr_t) (-1LL)) - -typedef enum { - XBRW_READ = 1, /* transfer into target memory */ - XBRW_WRITE = 2, /* transfer from target memory */ - XBRW_ZERO = 3, /* Zero target memory */ -} xfs_buf_rw_t; - -#define XBF_READ (1 << 0) /* buffer intended for reading from device */ -#define XBF_WRITE (1 << 1) /* buffer intended for writing to device */ -#define XBF_READ_AHEAD (1 << 2) /* asynchronous read-ahead */ -#define XBF_NO_IOACCT (1 << 3) /* bypass I/O accounting (non-LRU bufs) */ -#define XBF_ASYNC (1 << 4) /* initiator will not wait for completion */ -#define XBF_DONE (1 << 5) /* all pages in the buffer uptodate */ -#define XBF_STALE (1 << 6) /* buffer has been staled, do not find it */ -#define XBF_WRITE_FAIL (1 << 24)/* async writes have failed on this buffer */ - -/* I/O hints for the BIO layer */ -#define XBF_SYNCIO (1 << 10)/* treat this buffer as synchronous I/O */ -#define XBF_FUA (1 << 11)/* force cache write through mode */ -#define XBF_FLUSH (1 << 12)/* flush the disk cache before a write */ - -/* flags used only as arguments to access routines */ -#define XBF_TRYLOCK (1 << 16)/* lock requested, but do not wait */ -#define XBF_UNMAPPED (1 << 17)/* do not map the buffer */ - -/* flags used only internally */ -#define _XBF_PAGES (1 << 20)/* backed by refcounted pages */ -#define _XBF_KMEM (1 << 21)/* backed by heap memory */ -#define _XBF_DELWRI_Q (1 << 22)/* buffer on a delwri queue */ -#define _XBF_COMPOUND (1 << 23)/* compound buffer */ -#define _XBF_IN_FLIGHT (1 << 25) /* I/O in flight, for accounting purposes */ - -typedef unsigned int xfs_buf_flags_t; - -#define XFS_BUF_FLAGS \ - { XBF_READ, "READ" }, \ - { XBF_WRITE, "WRITE" }, \ - { XBF_READ_AHEAD, "READ_AHEAD" }, \ - { XBF_ASYNC, "ASYNC" }, \ - { XBF_DONE, "DONE" }, \ - { XBF_STALE, "STALE" }, \ - { XBF_WRITE_FAIL, "WRITE_FAIL" }, \ - { XBF_SYNCIO, "SYNCIO" }, \ - { XBF_FUA, "FUA" }, \ - { XBF_FLUSH, "FLUSH" }, \ - { XBF_TRYLOCK, "TRYLOCK" }, /* should never be set */\ - { XBF_UNMAPPED, "UNMAPPED" }, /* ditto */\ - { _XBF_PAGES, "PAGES" }, \ - { _XBF_KMEM, "KMEM" }, \ - { _XBF_DELWRI_Q, "DELWRI_Q" }, \ - { _XBF_COMPOUND, "COMPOUND" }, \ - { _XBF_IN_FLIGHT, "IN_FLIGHT" } - - -/* - * Internal state flags. - */ -#define XFS_BSTATE_DISPOSE (1 << 0) /* buffer being discarded */ - -/* - * The xfs_buftarg contains 2 notions of "sector size" - - * - * 1) The metadata sector size, which is the minimum unit and - * alignment of IO which will be performed by metadata operations. - * 2) The device logical sector size - * - * The first is specified at mkfs time, and is stored on-disk in the - * superblock's sb_sectsize. - * - * The latter is derived from the underlying device, and controls direct IO - * alignment constraints. - */ -typedef struct xfs_buftarg { - dev_t bt_dev; - struct block_device *bt_bdev; - struct backing_dev_info *bt_bdi; - struct xfs_mount *bt_mount; - unsigned int bt_meta_sectorsize; - size_t bt_meta_sectormask; - size_t bt_logical_sectorsize; - size_t bt_logical_sectormask; - - /* LRU control structures */ - struct shrinker bt_shrinker; - struct list_lru bt_lru; - - struct percpu_counter bt_io_count; -} xfs_buftarg_t; - -struct xfs_buf; -typedef void (*xfs_buf_iodone_t)(struct xfs_buf *); - - -#define XB_PAGES 2 - -struct xfs_buf_map { - xfs_daddr_t bm_bn; /* block number for I/O */ - int bm_len; /* size of I/O */ -}; - -#define DEFINE_SINGLE_BUF_MAP(map, blkno, numblk) \ - struct xfs_buf_map (map) = { .bm_bn = (blkno), .bm_len = (numblk) }; - -struct xfs_buf_ops { - char *name; - void (*verify_read)(struct xfs_buf *); - void (*verify_write)(struct xfs_buf *); -}; - -typedef struct xfs_buf { - /* - * first cacheline holds all the fields needed for an uncontended cache - * hit to be fully processed. The semaphore straddles the cacheline - * boundary, but the counter and lock sits on the first cacheline, - * which is the only bit that is touched if we hit the semaphore - * fast-path on locking. - */ - struct rb_node b_rbnode; /* rbtree node */ - xfs_daddr_t b_bn; /* block number of buffer */ - int b_length; /* size of buffer in BBs */ - atomic_t b_hold; /* reference count */ - atomic_t b_lru_ref; /* lru reclaim ref count */ - xfs_buf_flags_t b_flags; /* status flags */ - struct semaphore b_sema; /* semaphore for lockables */ - - /* - * concurrent access to b_lru and b_lru_flags are protected by - * bt_lru_lock and not by b_sema - */ - struct list_head b_lru; /* lru list */ - spinlock_t b_lock; /* internal state lock */ - unsigned int b_state; /* internal state flags */ - int b_io_error; /* internal IO error state */ - wait_queue_head_t b_waiters; /* unpin waiters */ - struct list_head b_list; - struct xfs_perag *b_pag; /* contains rbtree root */ - xfs_buftarg_t *b_target; /* buffer target (device) */ - void *b_addr; /* virtual address of buffer */ - struct work_struct b_ioend_work; - struct workqueue_struct *b_ioend_wq; /* I/O completion wq */ - xfs_buf_iodone_t b_iodone; /* I/O completion function */ - struct completion b_iowait; /* queue for I/O waiters */ - void *b_fspriv; - struct xfs_trans *b_transp; - struct page **b_pages; /* array of page pointers */ - struct page *b_page_array[XB_PAGES]; /* inline pages */ - struct xfs_buf_map *b_maps; /* compound buffer map */ - struct xfs_buf_map __b_map; /* inline compound buffer map */ - int b_map_count; - int b_io_length; /* IO size in BBs */ - atomic_t b_pin_count; /* pin count */ - atomic_t b_io_remaining; /* #outstanding I/O requests */ - unsigned int b_page_count; /* size of page array */ - unsigned int b_offset; /* page offset in first page */ - int b_error; /* error code on I/O */ - - /* - * async write failure retry count. Initialised to zero on the first - * failure, then when it exceeds the maximum configured without a - * success the write is considered to be failed permanently and the - * iodone handler will take appropriate action. - * - * For retry timeouts, we record the jiffie of the first failure. This - * means that we can change the retry timeout for buffers already under - * I/O and thus avoid getting stuck in a retry loop with a long timeout. - * - * last_error is used to ensure that we are getting repeated errors, not - * different errors. e.g. a block device might change ENOSPC to EIO when - * a failure timeout occurs, so we want to re-initialise the error - * retry behaviour appropriately when that happens. - */ - int b_retries; - unsigned long b_first_retry_time; /* in jiffies */ - int b_last_error; - - const struct xfs_buf_ops *b_ops; - -#ifdef XFS_BUF_LOCK_TRACKING - int b_last_holder; -#endif -} xfs_buf_t; - -/* Finding and Reading Buffers */ -struct xfs_buf *_xfs_buf_find(struct xfs_buftarg *target, - struct xfs_buf_map *map, int nmaps, - xfs_buf_flags_t flags, struct xfs_buf *new_bp); - -static inline struct xfs_buf * -xfs_incore( - struct xfs_buftarg *target, - xfs_daddr_t blkno, - size_t numblks, - xfs_buf_flags_t flags) -{ - DEFINE_SINGLE_BUF_MAP(map, blkno, numblks); - return _xfs_buf_find(target, &map, 1, flags, NULL); -} - -struct xfs_buf *_xfs_buf_alloc(struct xfs_buftarg *target, - struct xfs_buf_map *map, int nmaps, - xfs_buf_flags_t flags); - -static inline struct xfs_buf * -xfs_buf_alloc( - struct xfs_buftarg *target, - xfs_daddr_t blkno, - size_t numblks, - xfs_buf_flags_t flags) -{ - DEFINE_SINGLE_BUF_MAP(map, blkno, numblks); - return _xfs_buf_alloc(target, &map, 1, flags); -} - -struct xfs_buf *xfs_buf_get_map(struct xfs_buftarg *target, - struct xfs_buf_map *map, int nmaps, - xfs_buf_flags_t flags); -struct xfs_buf *xfs_buf_read_map(struct xfs_buftarg *target, - struct xfs_buf_map *map, int nmaps, - xfs_buf_flags_t flags, - const struct xfs_buf_ops *ops); -void xfs_buf_readahead_map(struct xfs_buftarg *target, - struct xfs_buf_map *map, int nmaps, - const struct xfs_buf_ops *ops); - -static inline struct xfs_buf * -xfs_buf_get( - struct xfs_buftarg *target, - xfs_daddr_t blkno, - size_t numblks, - xfs_buf_flags_t flags) -{ - DEFINE_SINGLE_BUF_MAP(map, blkno, numblks); - return xfs_buf_get_map(target, &map, 1, flags); -} - -static inline struct xfs_buf * -xfs_buf_read( - struct xfs_buftarg *target, - xfs_daddr_t blkno, - size_t numblks, - xfs_buf_flags_t flags, - const struct xfs_buf_ops *ops) -{ - DEFINE_SINGLE_BUF_MAP(map, blkno, numblks); - return xfs_buf_read_map(target, &map, 1, flags, ops); -} - -static inline void -xfs_buf_readahead( - struct xfs_buftarg *target, - xfs_daddr_t blkno, - size_t numblks, - const struct xfs_buf_ops *ops) -{ - DEFINE_SINGLE_BUF_MAP(map, blkno, numblks); - return xfs_buf_readahead_map(target, &map, 1, ops); -} - -struct xfs_buf *xfs_buf_get_empty(struct xfs_buftarg *target, size_t numblks); -void xfs_buf_set_empty(struct xfs_buf *bp, size_t numblks); -int xfs_buf_associate_memory(struct xfs_buf *bp, void *mem, size_t length); - -struct xfs_buf *xfs_buf_get_uncached(struct xfs_buftarg *target, size_t numblks, - int flags); -int xfs_buf_read_uncached(struct xfs_buftarg *target, xfs_daddr_t daddr, - size_t numblks, int flags, struct xfs_buf **bpp, - const struct xfs_buf_ops *ops); -void xfs_buf_hold(struct xfs_buf *bp); - -/* Releasing Buffers */ -extern void xfs_buf_free(xfs_buf_t *); -extern void xfs_buf_rele(xfs_buf_t *); - -/* Locking and Unlocking Buffers */ -extern int xfs_buf_trylock(xfs_buf_t *); -extern void xfs_buf_lock(xfs_buf_t *); -extern void xfs_buf_unlock(xfs_buf_t *); -#define xfs_buf_islocked(bp) \ - ((bp)->b_sema.count <= 0) - -/* Buffer Read and Write Routines */ -extern int xfs_bwrite(struct xfs_buf *bp); -extern void xfs_buf_ioend(struct xfs_buf *bp); -extern void xfs_buf_ioerror(xfs_buf_t *, int); -extern void xfs_buf_ioerror_alert(struct xfs_buf *, const char *func); -extern void xfs_buf_submit(struct xfs_buf *bp); -extern int xfs_buf_submit_wait(struct xfs_buf *bp); -extern void xfs_buf_iomove(xfs_buf_t *, size_t, size_t, void *, - xfs_buf_rw_t); -#define xfs_buf_zero(bp, off, len) \ - xfs_buf_iomove((bp), (off), (len), NULL, XBRW_ZERO) - -/* Buffer Utility Routines */ -extern void *xfs_buf_offset(struct xfs_buf *, size_t); -extern void xfs_buf_stale(struct xfs_buf *bp); - -/* Delayed Write Buffer Routines */ -extern bool xfs_buf_delwri_queue(struct xfs_buf *, struct list_head *); -extern int xfs_buf_delwri_submit(struct list_head *); -extern int xfs_buf_delwri_submit_nowait(struct list_head *); - -/* Buffer Daemon Setup Routines */ -extern int xfs_buf_init(void); -extern void xfs_buf_terminate(void); - -/* - * These macros use the IO block map rather than b_bn. b_bn is now really - * just for the buffer cache index for cached buffers. As IO does not use b_bn - * anymore, uncached buffers do not use b_bn at all and hence must modify the IO - * map directly. Uncached buffers are not allowed to be discontiguous, so this - * is safe to do. - * - * In future, uncached buffers will pass the block number directly to the io - * request function and hence these macros will go away at that point. - */ -#define XFS_BUF_ADDR(bp) ((bp)->b_maps[0].bm_bn) -#define XFS_BUF_SET_ADDR(bp, bno) ((bp)->b_maps[0].bm_bn = (xfs_daddr_t)(bno)) - -static inline void xfs_buf_set_ref(struct xfs_buf *bp, int lru_ref) -{ - atomic_set(&bp->b_lru_ref, lru_ref); -} - -static inline int xfs_buf_ispinned(struct xfs_buf *bp) -{ - return atomic_read(&bp->b_pin_count); -} - -static inline void xfs_buf_relse(xfs_buf_t *bp) -{ - xfs_buf_unlock(bp); - xfs_buf_rele(bp); -} - -static inline int -xfs_buf_verify_cksum(struct xfs_buf *bp, unsigned long cksum_offset) -{ - return xfs_verify_cksum(bp->b_addr, BBTOB(bp->b_length), - cksum_offset); -} - -static inline void -xfs_buf_update_cksum(struct xfs_buf *bp, unsigned long cksum_offset) -{ - xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), - cksum_offset); -} - -/* - * Handling of buftargs. - */ -extern xfs_buftarg_t *xfs_alloc_buftarg(struct xfs_mount *, - struct block_device *); -extern void xfs_free_buftarg(struct xfs_mount *, struct xfs_buftarg *); -extern void xfs_wait_buftarg(xfs_buftarg_t *); -extern int xfs_setsize_buftarg(xfs_buftarg_t *, unsigned int); - -#define xfs_getsize_buftarg(buftarg) block_size((buftarg)->bt_bdev) -#define xfs_readonly_buftarg(buftarg) bdev_read_only((buftarg)->bt_bdev) - -#endif /* __XFS_BUF_H__ */ diff --git a/src/linux/fs/xfs/xfs_buf_item.c b/src/linux/fs/xfs/xfs_buf_item.c deleted file mode 100644 index 2975cb2..0000000 --- a/src/linux/fs/xfs/xfs_buf_item.c +++ /dev/null @@ -1,1202 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_trans.h" -#include "xfs_buf_item.h" -#include "xfs_trans_priv.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_log.h" - - -kmem_zone_t *xfs_buf_item_zone; - -static inline struct xfs_buf_log_item *BUF_ITEM(struct xfs_log_item *lip) -{ - return container_of(lip, struct xfs_buf_log_item, bli_item); -} - -STATIC void xfs_buf_do_callbacks(struct xfs_buf *bp); - -static inline int -xfs_buf_log_format_size( - struct xfs_buf_log_format *blfp) -{ - return offsetof(struct xfs_buf_log_format, blf_data_map) + - (blfp->blf_map_size * sizeof(blfp->blf_data_map[0])); -} - -/* - * This returns the number of log iovecs needed to log the - * given buf log item. - * - * It calculates this as 1 iovec for the buf log format structure - * and 1 for each stretch of non-contiguous chunks to be logged. - * Contiguous chunks are logged in a single iovec. - * - * If the XFS_BLI_STALE flag has been set, then log nothing. - */ -STATIC void -xfs_buf_item_size_segment( - struct xfs_buf_log_item *bip, - struct xfs_buf_log_format *blfp, - int *nvecs, - int *nbytes) -{ - struct xfs_buf *bp = bip->bli_buf; - int next_bit; - int last_bit; - - last_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size, 0); - if (last_bit == -1) - return; - - /* - * initial count for a dirty buffer is 2 vectors - the format structure - * and the first dirty region. - */ - *nvecs += 2; - *nbytes += xfs_buf_log_format_size(blfp) + XFS_BLF_CHUNK; - - while (last_bit != -1) { - /* - * This takes the bit number to start looking from and - * returns the next set bit from there. It returns -1 - * if there are no more bits set or the start bit is - * beyond the end of the bitmap. - */ - next_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size, - last_bit + 1); - /* - * If we run out of bits, leave the loop, - * else if we find a new set of bits bump the number of vecs, - * else keep scanning the current set of bits. - */ - if (next_bit == -1) { - break; - } else if (next_bit != last_bit + 1) { - last_bit = next_bit; - (*nvecs)++; - } else if (xfs_buf_offset(bp, next_bit * XFS_BLF_CHUNK) != - (xfs_buf_offset(bp, last_bit * XFS_BLF_CHUNK) + - XFS_BLF_CHUNK)) { - last_bit = next_bit; - (*nvecs)++; - } else { - last_bit++; - } - *nbytes += XFS_BLF_CHUNK; - } -} - -/* - * This returns the number of log iovecs needed to log the given buf log item. - * - * It calculates this as 1 iovec for the buf log format structure and 1 for each - * stretch of non-contiguous chunks to be logged. Contiguous chunks are logged - * in a single iovec. - * - * Discontiguous buffers need a format structure per region that that is being - * logged. This makes the changes in the buffer appear to log recovery as though - * they came from separate buffers, just like would occur if multiple buffers - * were used instead of a single discontiguous buffer. This enables - * discontiguous buffers to be in-memory constructs, completely transparent to - * what ends up on disk. - * - * If the XFS_BLI_STALE flag has been set, then log nothing but the buf log - * format structures. - */ -STATIC void -xfs_buf_item_size( - struct xfs_log_item *lip, - int *nvecs, - int *nbytes) -{ - struct xfs_buf_log_item *bip = BUF_ITEM(lip); - int i; - - ASSERT(atomic_read(&bip->bli_refcount) > 0); - if (bip->bli_flags & XFS_BLI_STALE) { - /* - * The buffer is stale, so all we need to log - * is the buf log format structure with the - * cancel flag in it. - */ - trace_xfs_buf_item_size_stale(bip); - ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL); - *nvecs += bip->bli_format_count; - for (i = 0; i < bip->bli_format_count; i++) { - *nbytes += xfs_buf_log_format_size(&bip->bli_formats[i]); - } - return; - } - - ASSERT(bip->bli_flags & XFS_BLI_LOGGED); - - if (bip->bli_flags & XFS_BLI_ORDERED) { - /* - * The buffer has been logged just to order it. - * It is not being included in the transaction - * commit, so no vectors are used at all. - */ - trace_xfs_buf_item_size_ordered(bip); - *nvecs = XFS_LOG_VEC_ORDERED; - return; - } - - /* - * the vector count is based on the number of buffer vectors we have - * dirty bits in. This will only be greater than one when we have a - * compound buffer with more than one segment dirty. Hence for compound - * buffers we need to track which segment the dirty bits correspond to, - * and when we move from one segment to the next increment the vector - * count for the extra buf log format structure that will need to be - * written. - */ - for (i = 0; i < bip->bli_format_count; i++) { - xfs_buf_item_size_segment(bip, &bip->bli_formats[i], - nvecs, nbytes); - } - trace_xfs_buf_item_size(bip); -} - -static inline void -xfs_buf_item_copy_iovec( - struct xfs_log_vec *lv, - struct xfs_log_iovec **vecp, - struct xfs_buf *bp, - uint offset, - int first_bit, - uint nbits) -{ - offset += first_bit * XFS_BLF_CHUNK; - xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_BCHUNK, - xfs_buf_offset(bp, offset), - nbits * XFS_BLF_CHUNK); -} - -static inline bool -xfs_buf_item_straddle( - struct xfs_buf *bp, - uint offset, - int next_bit, - int last_bit) -{ - return xfs_buf_offset(bp, offset + (next_bit << XFS_BLF_SHIFT)) != - (xfs_buf_offset(bp, offset + (last_bit << XFS_BLF_SHIFT)) + - XFS_BLF_CHUNK); -} - -static void -xfs_buf_item_format_segment( - struct xfs_buf_log_item *bip, - struct xfs_log_vec *lv, - struct xfs_log_iovec **vecp, - uint offset, - struct xfs_buf_log_format *blfp) -{ - struct xfs_buf *bp = bip->bli_buf; - uint base_size; - int first_bit; - int last_bit; - int next_bit; - uint nbits; - - /* copy the flags across from the base format item */ - blfp->blf_flags = bip->__bli_format.blf_flags; - - /* - * Base size is the actual size of the ondisk structure - it reflects - * the actual size of the dirty bitmap rather than the size of the in - * memory structure. - */ - base_size = xfs_buf_log_format_size(blfp); - - first_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size, 0); - if (!(bip->bli_flags & XFS_BLI_STALE) && first_bit == -1) { - /* - * If the map is not be dirty in the transaction, mark - * the size as zero and do not advance the vector pointer. - */ - return; - } - - blfp = xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_BFORMAT, blfp, base_size); - blfp->blf_size = 1; - - if (bip->bli_flags & XFS_BLI_STALE) { - /* - * The buffer is stale, so all we need to log - * is the buf log format structure with the - * cancel flag in it. - */ - trace_xfs_buf_item_format_stale(bip); - ASSERT(blfp->blf_flags & XFS_BLF_CANCEL); - return; - } - - - /* - * Fill in an iovec for each set of contiguous chunks. - */ - last_bit = first_bit; - nbits = 1; - for (;;) { - /* - * This takes the bit number to start looking from and - * returns the next set bit from there. It returns -1 - * if there are no more bits set or the start bit is - * beyond the end of the bitmap. - */ - next_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size, - (uint)last_bit + 1); - /* - * If we run out of bits fill in the last iovec and get out of - * the loop. Else if we start a new set of bits then fill in - * the iovec for the series we were looking at and start - * counting the bits in the new one. Else we're still in the - * same set of bits so just keep counting and scanning. - */ - if (next_bit == -1) { - xfs_buf_item_copy_iovec(lv, vecp, bp, offset, - first_bit, nbits); - blfp->blf_size++; - break; - } else if (next_bit != last_bit + 1 || - xfs_buf_item_straddle(bp, offset, next_bit, last_bit)) { - xfs_buf_item_copy_iovec(lv, vecp, bp, offset, - first_bit, nbits); - blfp->blf_size++; - first_bit = next_bit; - last_bit = next_bit; - nbits = 1; - } else { - last_bit++; - nbits++; - } - } -} - -/* - * This is called to fill in the vector of log iovecs for the - * given log buf item. It fills the first entry with a buf log - * format structure, and the rest point to contiguous chunks - * within the buffer. - */ -STATIC void -xfs_buf_item_format( - struct xfs_log_item *lip, - struct xfs_log_vec *lv) -{ - struct xfs_buf_log_item *bip = BUF_ITEM(lip); - struct xfs_buf *bp = bip->bli_buf; - struct xfs_log_iovec *vecp = NULL; - uint offset = 0; - int i; - - ASSERT(atomic_read(&bip->bli_refcount) > 0); - ASSERT((bip->bli_flags & XFS_BLI_LOGGED) || - (bip->bli_flags & XFS_BLI_STALE)); - ASSERT((bip->bli_flags & XFS_BLI_STALE) || - (xfs_blft_from_flags(&bip->__bli_format) > XFS_BLFT_UNKNOWN_BUF - && xfs_blft_from_flags(&bip->__bli_format) < XFS_BLFT_MAX_BUF)); - - - /* - * If it is an inode buffer, transfer the in-memory state to the - * format flags and clear the in-memory state. - * - * For buffer based inode allocation, we do not transfer - * this state if the inode buffer allocation has not yet been committed - * to the log as setting the XFS_BLI_INODE_BUF flag will prevent - * correct replay of the inode allocation. - * - * For icreate item based inode allocation, the buffers aren't written - * to the journal during allocation, and hence we should always tag the - * buffer as an inode buffer so that the correct unlinked list replay - * occurs during recovery. - */ - if (bip->bli_flags & XFS_BLI_INODE_BUF) { - if (xfs_sb_version_hascrc(&lip->li_mountp->m_sb) || - !((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) && - xfs_log_item_in_current_chkpt(lip))) - bip->__bli_format.blf_flags |= XFS_BLF_INODE_BUF; - bip->bli_flags &= ~XFS_BLI_INODE_BUF; - } - - if ((bip->bli_flags & (XFS_BLI_ORDERED|XFS_BLI_STALE)) == - XFS_BLI_ORDERED) { - /* - * The buffer has been logged just to order it. It is not being - * included in the transaction commit, so don't format it. - */ - trace_xfs_buf_item_format_ordered(bip); - return; - } - - for (i = 0; i < bip->bli_format_count; i++) { - xfs_buf_item_format_segment(bip, lv, &vecp, offset, - &bip->bli_formats[i]); - offset += BBTOB(bp->b_maps[i].bm_len); - } - - /* - * Check to make sure everything is consistent. - */ - trace_xfs_buf_item_format(bip); -} - -/* - * This is called to pin the buffer associated with the buf log item in memory - * so it cannot be written out. - * - * We also always take a reference to the buffer log item here so that the bli - * is held while the item is pinned in memory. This means that we can - * unconditionally drop the reference count a transaction holds when the - * transaction is completed. - */ -STATIC void -xfs_buf_item_pin( - struct xfs_log_item *lip) -{ - struct xfs_buf_log_item *bip = BUF_ITEM(lip); - - ASSERT(atomic_read(&bip->bli_refcount) > 0); - ASSERT((bip->bli_flags & XFS_BLI_LOGGED) || - (bip->bli_flags & XFS_BLI_ORDERED) || - (bip->bli_flags & XFS_BLI_STALE)); - - trace_xfs_buf_item_pin(bip); - - atomic_inc(&bip->bli_refcount); - atomic_inc(&bip->bli_buf->b_pin_count); -} - -/* - * This is called to unpin the buffer associated with the buf log - * item which was previously pinned with a call to xfs_buf_item_pin(). - * - * Also drop the reference to the buf item for the current transaction. - * If the XFS_BLI_STALE flag is set and we are the last reference, - * then free up the buf log item and unlock the buffer. - * - * If the remove flag is set we are called from uncommit in the - * forced-shutdown path. If that is true and the reference count on - * the log item is going to drop to zero we need to free the item's - * descriptor in the transaction. - */ -STATIC void -xfs_buf_item_unpin( - struct xfs_log_item *lip, - int remove) -{ - struct xfs_buf_log_item *bip = BUF_ITEM(lip); - xfs_buf_t *bp = bip->bli_buf; - struct xfs_ail *ailp = lip->li_ailp; - int stale = bip->bli_flags & XFS_BLI_STALE; - int freed; - - ASSERT(bp->b_fspriv == bip); - ASSERT(atomic_read(&bip->bli_refcount) > 0); - - trace_xfs_buf_item_unpin(bip); - - freed = atomic_dec_and_test(&bip->bli_refcount); - - if (atomic_dec_and_test(&bp->b_pin_count)) - wake_up_all(&bp->b_waiters); - - if (freed && stale) { - ASSERT(bip->bli_flags & XFS_BLI_STALE); - ASSERT(xfs_buf_islocked(bp)); - ASSERT(bp->b_flags & XBF_STALE); - ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL); - - trace_xfs_buf_item_unpin_stale(bip); - - if (remove) { - /* - * If we are in a transaction context, we have to - * remove the log item from the transaction as we are - * about to release our reference to the buffer. If we - * don't, the unlock that occurs later in - * xfs_trans_uncommit() will try to reference the - * buffer which we no longer have a hold on. - */ - if (lip->li_desc) - xfs_trans_del_item(lip); - - /* - * Since the transaction no longer refers to the buffer, - * the buffer should no longer refer to the transaction. - */ - bp->b_transp = NULL; - } - - /* - * If we get called here because of an IO error, we may - * or may not have the item on the AIL. xfs_trans_ail_delete() - * will take care of that situation. - * xfs_trans_ail_delete() drops the AIL lock. - */ - if (bip->bli_flags & XFS_BLI_STALE_INODE) { - xfs_buf_do_callbacks(bp); - bp->b_fspriv = NULL; - bp->b_iodone = NULL; - } else { - spin_lock(&ailp->xa_lock); - xfs_trans_ail_delete(ailp, lip, SHUTDOWN_LOG_IO_ERROR); - xfs_buf_item_relse(bp); - ASSERT(bp->b_fspriv == NULL); - } - xfs_buf_relse(bp); - } else if (freed && remove) { - /* - * There are currently two references to the buffer - the active - * LRU reference and the buf log item. What we are about to do - * here - simulate a failed IO completion - requires 3 - * references. - * - * The LRU reference is removed by the xfs_buf_stale() call. The - * buf item reference is removed by the xfs_buf_iodone() - * callback that is run by xfs_buf_do_callbacks() during ioend - * processing (via the bp->b_iodone callback), and then finally - * the ioend processing will drop the IO reference if the buffer - * is marked XBF_ASYNC. - * - * Hence we need to take an additional reference here so that IO - * completion processing doesn't free the buffer prematurely. - */ - xfs_buf_lock(bp); - xfs_buf_hold(bp); - bp->b_flags |= XBF_ASYNC; - xfs_buf_ioerror(bp, -EIO); - bp->b_flags &= ~XBF_DONE; - xfs_buf_stale(bp); - xfs_buf_ioend(bp); - } -} - -/* - * Buffer IO error rate limiting. Limit it to no more than 10 messages per 30 - * seconds so as to not spam logs too much on repeated detection of the same - * buffer being bad.. - */ - -static DEFINE_RATELIMIT_STATE(xfs_buf_write_fail_rl_state, 30 * HZ, 10); - -STATIC uint -xfs_buf_item_push( - struct xfs_log_item *lip, - struct list_head *buffer_list) -{ - struct xfs_buf_log_item *bip = BUF_ITEM(lip); - struct xfs_buf *bp = bip->bli_buf; - uint rval = XFS_ITEM_SUCCESS; - - if (xfs_buf_ispinned(bp)) - return XFS_ITEM_PINNED; - if (!xfs_buf_trylock(bp)) { - /* - * If we have just raced with a buffer being pinned and it has - * been marked stale, we could end up stalling until someone else - * issues a log force to unpin the stale buffer. Check for the - * race condition here so xfsaild recognizes the buffer is pinned - * and queues a log force to move it along. - */ - if (xfs_buf_ispinned(bp)) - return XFS_ITEM_PINNED; - return XFS_ITEM_LOCKED; - } - - ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); - - trace_xfs_buf_item_push(bip); - - /* has a previous flush failed due to IO errors? */ - if ((bp->b_flags & XBF_WRITE_FAIL) && - ___ratelimit(&xfs_buf_write_fail_rl_state, "XFS: Failing async write")) { - xfs_warn(bp->b_target->bt_mount, -"Failing async write on buffer block 0x%llx. Retrying async write.", - (long long)bp->b_bn); - } - - if (!xfs_buf_delwri_queue(bp, buffer_list)) - rval = XFS_ITEM_FLUSHING; - xfs_buf_unlock(bp); - return rval; -} - -/* - * Release the buffer associated with the buf log item. If there is no dirty - * logged data associated with the buffer recorded in the buf log item, then - * free the buf log item and remove the reference to it in the buffer. - * - * This call ignores the recursion count. It is only called when the buffer - * should REALLY be unlocked, regardless of the recursion count. - * - * We unconditionally drop the transaction's reference to the log item. If the - * item was logged, then another reference was taken when it was pinned, so we - * can safely drop the transaction reference now. This also allows us to avoid - * potential races with the unpin code freeing the bli by not referencing the - * bli after we've dropped the reference count. - * - * If the XFS_BLI_HOLD flag is set in the buf log item, then free the log item - * if necessary but do not unlock the buffer. This is for support of - * xfs_trans_bhold(). Make sure the XFS_BLI_HOLD field is cleared if we don't - * free the item. - */ -STATIC void -xfs_buf_item_unlock( - struct xfs_log_item *lip) -{ - struct xfs_buf_log_item *bip = BUF_ITEM(lip); - struct xfs_buf *bp = bip->bli_buf; - bool clean; - bool aborted; - int flags; - - /* Clear the buffer's association with this transaction. */ - bp->b_transp = NULL; - - /* - * If this is a transaction abort, don't return early. Instead, allow - * the brelse to happen. Normally it would be done for stale - * (cancelled) buffers at unpin time, but we'll never go through the - * pin/unpin cycle if we abort inside commit. - */ - aborted = (lip->li_flags & XFS_LI_ABORTED) ? true : false; - /* - * Before possibly freeing the buf item, copy the per-transaction state - * so we can reference it safely later after clearing it from the - * buffer log item. - */ - flags = bip->bli_flags; - bip->bli_flags &= ~(XFS_BLI_LOGGED | XFS_BLI_HOLD | XFS_BLI_ORDERED); - - /* - * If the buf item is marked stale, then don't do anything. We'll - * unlock the buffer and free the buf item when the buffer is unpinned - * for the last time. - */ - if (flags & XFS_BLI_STALE) { - trace_xfs_buf_item_unlock_stale(bip); - ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL); - if (!aborted) { - atomic_dec(&bip->bli_refcount); - return; - } - } - - trace_xfs_buf_item_unlock(bip); - - /* - * If the buf item isn't tracking any data, free it, otherwise drop the - * reference we hold to it. If we are aborting the transaction, this may - * be the only reference to the buf item, so we free it anyway - * regardless of whether it is dirty or not. A dirty abort implies a - * shutdown, anyway. - * - * Ordered buffers are dirty but may have no recorded changes, so ensure - * we only release clean items here. - */ - clean = (flags & XFS_BLI_DIRTY) ? false : true; - if (clean) { - int i; - for (i = 0; i < bip->bli_format_count; i++) { - if (!xfs_bitmap_empty(bip->bli_formats[i].blf_data_map, - bip->bli_formats[i].blf_map_size)) { - clean = false; - break; - } - } - } - - /* - * Clean buffers, by definition, cannot be in the AIL. However, aborted - * buffers may be dirty and hence in the AIL. Therefore if we are - * aborting a buffer and we've just taken the last refernce away, we - * have to check if it is in the AIL before freeing it. We need to free - * it in this case, because an aborted transaction has already shut the - * filesystem down and this is the last chance we will have to do so. - */ - if (atomic_dec_and_test(&bip->bli_refcount)) { - if (clean) - xfs_buf_item_relse(bp); - else if (aborted) { - ASSERT(XFS_FORCED_SHUTDOWN(lip->li_mountp)); - xfs_trans_ail_remove(lip, SHUTDOWN_LOG_IO_ERROR); - xfs_buf_item_relse(bp); - } - } - - if (!(flags & XFS_BLI_HOLD)) - xfs_buf_relse(bp); -} - -/* - * This is called to find out where the oldest active copy of the - * buf log item in the on disk log resides now that the last log - * write of it completed at the given lsn. - * We always re-log all the dirty data in a buffer, so usually the - * latest copy in the on disk log is the only one that matters. For - * those cases we simply return the given lsn. - * - * The one exception to this is for buffers full of newly allocated - * inodes. These buffers are only relogged with the XFS_BLI_INODE_BUF - * flag set, indicating that only the di_next_unlinked fields from the - * inodes in the buffers will be replayed during recovery. If the - * original newly allocated inode images have not yet been flushed - * when the buffer is so relogged, then we need to make sure that we - * keep the old images in the 'active' portion of the log. We do this - * by returning the original lsn of that transaction here rather than - * the current one. - */ -STATIC xfs_lsn_t -xfs_buf_item_committed( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ - struct xfs_buf_log_item *bip = BUF_ITEM(lip); - - trace_xfs_buf_item_committed(bip); - - if ((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) && lip->li_lsn != 0) - return lip->li_lsn; - return lsn; -} - -STATIC void -xfs_buf_item_committing( - struct xfs_log_item *lip, - xfs_lsn_t commit_lsn) -{ -} - -/* - * This is the ops vector shared by all buf log items. - */ -static const struct xfs_item_ops xfs_buf_item_ops = { - .iop_size = xfs_buf_item_size, - .iop_format = xfs_buf_item_format, - .iop_pin = xfs_buf_item_pin, - .iop_unpin = xfs_buf_item_unpin, - .iop_unlock = xfs_buf_item_unlock, - .iop_committed = xfs_buf_item_committed, - .iop_push = xfs_buf_item_push, - .iop_committing = xfs_buf_item_committing -}; - -STATIC int -xfs_buf_item_get_format( - struct xfs_buf_log_item *bip, - int count) -{ - ASSERT(bip->bli_formats == NULL); - bip->bli_format_count = count; - - if (count == 1) { - bip->bli_formats = &bip->__bli_format; - return 0; - } - - bip->bli_formats = kmem_zalloc(count * sizeof(struct xfs_buf_log_format), - KM_SLEEP); - if (!bip->bli_formats) - return -ENOMEM; - return 0; -} - -STATIC void -xfs_buf_item_free_format( - struct xfs_buf_log_item *bip) -{ - if (bip->bli_formats != &bip->__bli_format) { - kmem_free(bip->bli_formats); - bip->bli_formats = NULL; - } -} - -/* - * Allocate a new buf log item to go with the given buffer. - * Set the buffer's b_fsprivate field to point to the new - * buf log item. If there are other item's attached to the - * buffer (see xfs_buf_attach_iodone() below), then put the - * buf log item at the front. - */ -int -xfs_buf_item_init( - struct xfs_buf *bp, - struct xfs_mount *mp) -{ - struct xfs_log_item *lip = bp->b_fspriv; - struct xfs_buf_log_item *bip; - int chunks; - int map_size; - int error; - int i; - - /* - * Check to see if there is already a buf log item for - * this buffer. If there is, it is guaranteed to be - * the first. If we do already have one, there is - * nothing to do here so return. - */ - ASSERT(bp->b_target->bt_mount == mp); - if (lip != NULL && lip->li_type == XFS_LI_BUF) - return 0; - - bip = kmem_zone_zalloc(xfs_buf_item_zone, KM_SLEEP); - xfs_log_item_init(mp, &bip->bli_item, XFS_LI_BUF, &xfs_buf_item_ops); - bip->bli_buf = bp; - - /* - * chunks is the number of XFS_BLF_CHUNK size pieces the buffer - * can be divided into. Make sure not to truncate any pieces. - * map_size is the size of the bitmap needed to describe the - * chunks of the buffer. - * - * Discontiguous buffer support follows the layout of the underlying - * buffer. This makes the implementation as simple as possible. - */ - error = xfs_buf_item_get_format(bip, bp->b_map_count); - ASSERT(error == 0); - if (error) { /* to stop gcc throwing set-but-unused warnings */ - kmem_zone_free(xfs_buf_item_zone, bip); - return error; - } - - - for (i = 0; i < bip->bli_format_count; i++) { - chunks = DIV_ROUND_UP(BBTOB(bp->b_maps[i].bm_len), - XFS_BLF_CHUNK); - map_size = DIV_ROUND_UP(chunks, NBWORD); - - bip->bli_formats[i].blf_type = XFS_LI_BUF; - bip->bli_formats[i].blf_blkno = bp->b_maps[i].bm_bn; - bip->bli_formats[i].blf_len = bp->b_maps[i].bm_len; - bip->bli_formats[i].blf_map_size = map_size; - } - - /* - * Put the buf item into the list of items attached to the - * buffer at the front. - */ - if (bp->b_fspriv) - bip->bli_item.li_bio_list = bp->b_fspriv; - bp->b_fspriv = bip; - xfs_buf_hold(bp); - return 0; -} - - -/* - * Mark bytes first through last inclusive as dirty in the buf - * item's bitmap. - */ -static void -xfs_buf_item_log_segment( - uint first, - uint last, - uint *map) -{ - uint first_bit; - uint last_bit; - uint bits_to_set; - uint bits_set; - uint word_num; - uint *wordp; - uint bit; - uint end_bit; - uint mask; - - /* - * Convert byte offsets to bit numbers. - */ - first_bit = first >> XFS_BLF_SHIFT; - last_bit = last >> XFS_BLF_SHIFT; - - /* - * Calculate the total number of bits to be set. - */ - bits_to_set = last_bit - first_bit + 1; - - /* - * Get a pointer to the first word in the bitmap - * to set a bit in. - */ - word_num = first_bit >> BIT_TO_WORD_SHIFT; - wordp = &map[word_num]; - - /* - * Calculate the starting bit in the first word. - */ - bit = first_bit & (uint)(NBWORD - 1); - - /* - * First set any bits in the first word of our range. - * If it starts at bit 0 of the word, it will be - * set below rather than here. That is what the variable - * bit tells us. The variable bits_set tracks the number - * of bits that have been set so far. End_bit is the number - * of the last bit to be set in this word plus one. - */ - if (bit) { - end_bit = MIN(bit + bits_to_set, (uint)NBWORD); - mask = ((1U << (end_bit - bit)) - 1) << bit; - *wordp |= mask; - wordp++; - bits_set = end_bit - bit; - } else { - bits_set = 0; - } - - /* - * Now set bits a whole word at a time that are between - * first_bit and last_bit. - */ - while ((bits_to_set - bits_set) >= NBWORD) { - *wordp |= 0xffffffff; - bits_set += NBWORD; - wordp++; - } - - /* - * Finally, set any bits left to be set in one last partial word. - */ - end_bit = bits_to_set - bits_set; - if (end_bit) { - mask = (1U << end_bit) - 1; - *wordp |= mask; - } -} - -/* - * Mark bytes first through last inclusive as dirty in the buf - * item's bitmap. - */ -void -xfs_buf_item_log( - xfs_buf_log_item_t *bip, - uint first, - uint last) -{ - int i; - uint start; - uint end; - struct xfs_buf *bp = bip->bli_buf; - - /* - * walk each buffer segment and mark them dirty appropriately. - */ - start = 0; - for (i = 0; i < bip->bli_format_count; i++) { - if (start > last) - break; - end = start + BBTOB(bp->b_maps[i].bm_len) - 1; - - /* skip to the map that includes the first byte to log */ - if (first > end) { - start += BBTOB(bp->b_maps[i].bm_len); - continue; - } - - /* - * Trim the range to this segment and mark it in the bitmap. - * Note that we must convert buffer offsets to segment relative - * offsets (e.g., the first byte of each segment is byte 0 of - * that segment). - */ - if (first < start) - first = start; - if (end > last) - end = last; - xfs_buf_item_log_segment(first - start, end - start, - &bip->bli_formats[i].blf_data_map[0]); - - start += BBTOB(bp->b_maps[i].bm_len); - } -} - - -/* - * Return 1 if the buffer has been logged or ordered in a transaction (at any - * point, not just the current transaction) and 0 if not. - */ -uint -xfs_buf_item_dirty( - xfs_buf_log_item_t *bip) -{ - return (bip->bli_flags & XFS_BLI_DIRTY); -} - -STATIC void -xfs_buf_item_free( - xfs_buf_log_item_t *bip) -{ - xfs_buf_item_free_format(bip); - kmem_free(bip->bli_item.li_lv_shadow); - kmem_zone_free(xfs_buf_item_zone, bip); -} - -/* - * This is called when the buf log item is no longer needed. It should - * free the buf log item associated with the given buffer and clear - * the buffer's pointer to the buf log item. If there are no more - * items in the list, clear the b_iodone field of the buffer (see - * xfs_buf_attach_iodone() below). - */ -void -xfs_buf_item_relse( - xfs_buf_t *bp) -{ - xfs_buf_log_item_t *bip = bp->b_fspriv; - - trace_xfs_buf_item_relse(bp, _RET_IP_); - ASSERT(!(bip->bli_item.li_flags & XFS_LI_IN_AIL)); - - bp->b_fspriv = bip->bli_item.li_bio_list; - if (bp->b_fspriv == NULL) - bp->b_iodone = NULL; - - xfs_buf_rele(bp); - xfs_buf_item_free(bip); -} - - -/* - * Add the given log item with its callback to the list of callbacks - * to be called when the buffer's I/O completes. If it is not set - * already, set the buffer's b_iodone() routine to be - * xfs_buf_iodone_callbacks() and link the log item into the list of - * items rooted at b_fsprivate. Items are always added as the second - * entry in the list if there is a first, because the buf item code - * assumes that the buf log item is first. - */ -void -xfs_buf_attach_iodone( - xfs_buf_t *bp, - void (*cb)(xfs_buf_t *, xfs_log_item_t *), - xfs_log_item_t *lip) -{ - xfs_log_item_t *head_lip; - - ASSERT(xfs_buf_islocked(bp)); - - lip->li_cb = cb; - head_lip = bp->b_fspriv; - if (head_lip) { - lip->li_bio_list = head_lip->li_bio_list; - head_lip->li_bio_list = lip; - } else { - bp->b_fspriv = lip; - } - - ASSERT(bp->b_iodone == NULL || - bp->b_iodone == xfs_buf_iodone_callbacks); - bp->b_iodone = xfs_buf_iodone_callbacks; -} - -/* - * We can have many callbacks on a buffer. Running the callbacks individually - * can cause a lot of contention on the AIL lock, so we allow for a single - * callback to be able to scan the remaining lip->li_bio_list for other items - * of the same type and callback to be processed in the first call. - * - * As a result, the loop walking the callback list below will also modify the - * list. it removes the first item from the list and then runs the callback. - * The loop then restarts from the new head of the list. This allows the - * callback to scan and modify the list attached to the buffer and we don't - * have to care about maintaining a next item pointer. - */ -STATIC void -xfs_buf_do_callbacks( - struct xfs_buf *bp) -{ - struct xfs_log_item *lip; - - while ((lip = bp->b_fspriv) != NULL) { - bp->b_fspriv = lip->li_bio_list; - ASSERT(lip->li_cb != NULL); - /* - * Clear the next pointer so we don't have any - * confusion if the item is added to another buf. - * Don't touch the log item after calling its - * callback, because it could have freed itself. - */ - lip->li_bio_list = NULL; - lip->li_cb(bp, lip); - } -} - -static bool -xfs_buf_iodone_callback_error( - struct xfs_buf *bp) -{ - struct xfs_log_item *lip = bp->b_fspriv; - struct xfs_mount *mp = lip->li_mountp; - static ulong lasttime; - static xfs_buftarg_t *lasttarg; - struct xfs_error_cfg *cfg; - - /* - * If we've already decided to shutdown the filesystem because of - * I/O errors, there's no point in giving this a retry. - */ - if (XFS_FORCED_SHUTDOWN(mp)) - goto out_stale; - - if (bp->b_target != lasttarg || - time_after(jiffies, (lasttime + 5*HZ))) { - lasttime = jiffies; - xfs_buf_ioerror_alert(bp, __func__); - } - lasttarg = bp->b_target; - - /* synchronous writes will have callers process the error */ - if (!(bp->b_flags & XBF_ASYNC)) - goto out_stale; - - trace_xfs_buf_item_iodone_async(bp, _RET_IP_); - ASSERT(bp->b_iodone != NULL); - - cfg = xfs_error_get_cfg(mp, XFS_ERR_METADATA, bp->b_error); - - /* - * If the write was asynchronous then no one will be looking for the - * error. If this is the first failure of this type, clear the error - * state and write the buffer out again. This means we always retry an - * async write failure at least once, but we also need to set the buffer - * up to behave correctly now for repeated failures. - */ - if (!(bp->b_flags & (XBF_STALE | XBF_WRITE_FAIL)) || - bp->b_last_error != bp->b_error) { - bp->b_flags |= (XBF_WRITE | XBF_DONE | XBF_WRITE_FAIL); - bp->b_last_error = bp->b_error; - if (cfg->retry_timeout != XFS_ERR_RETRY_FOREVER && - !bp->b_first_retry_time) - bp->b_first_retry_time = jiffies; - - xfs_buf_ioerror(bp, 0); - xfs_buf_submit(bp); - return true; - } - - /* - * Repeated failure on an async write. Take action according to the - * error configuration we have been set up to use. - */ - - if (cfg->max_retries != XFS_ERR_RETRY_FOREVER && - ++bp->b_retries > cfg->max_retries) - goto permanent_error; - if (cfg->retry_timeout != XFS_ERR_RETRY_FOREVER && - time_after(jiffies, cfg->retry_timeout + bp->b_first_retry_time)) - goto permanent_error; - - /* At unmount we may treat errors differently */ - if ((mp->m_flags & XFS_MOUNT_UNMOUNTING) && mp->m_fail_unmount) - goto permanent_error; - - /* still a transient error, higher layers will retry */ - xfs_buf_ioerror(bp, 0); - xfs_buf_relse(bp); - return true; - - /* - * Permanent error - we need to trigger a shutdown if we haven't already - * to indicate that inconsistency will result from this action. - */ -permanent_error: - xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR); -out_stale: - xfs_buf_stale(bp); - bp->b_flags |= XBF_DONE; - trace_xfs_buf_error_relse(bp, _RET_IP_); - return false; -} - -/* - * This is the iodone() function for buffers which have had callbacks attached - * to them by xfs_buf_attach_iodone(). We need to iterate the items on the - * callback list, mark the buffer as having no more callbacks and then push the - * buffer through IO completion processing. - */ -void -xfs_buf_iodone_callbacks( - struct xfs_buf *bp) -{ - /* - * If there is an error, process it. Some errors require us - * to run callbacks after failure processing is done so we - * detect that and take appropriate action. - */ - if (bp->b_error && xfs_buf_iodone_callback_error(bp)) - return; - - /* - * Successful IO or permanent error. Either way, we can clear the - * retry state here in preparation for the next error that may occur. - */ - bp->b_last_error = 0; - bp->b_retries = 0; - - xfs_buf_do_callbacks(bp); - bp->b_fspriv = NULL; - bp->b_iodone = NULL; - xfs_buf_ioend(bp); -} - -/* - * This is the iodone() function for buffers which have been - * logged. It is called when they are eventually flushed out. - * It should remove the buf item from the AIL, and free the buf item. - * It is called by xfs_buf_iodone_callbacks() above which will take - * care of cleaning up the buffer itself. - */ -void -xfs_buf_iodone( - struct xfs_buf *bp, - struct xfs_log_item *lip) -{ - struct xfs_ail *ailp = lip->li_ailp; - - ASSERT(BUF_ITEM(lip)->bli_buf == bp); - - xfs_buf_rele(bp); - - /* - * If we are forcibly shutting down, this may well be - * off the AIL already. That's because we simulate the - * log-committed callbacks to unpin these buffers. Or we may never - * have put this item on AIL because of the transaction was - * aborted forcibly. xfs_trans_ail_delete() takes care of these. - * - * Either way, AIL is useless if we're forcing a shutdown. - */ - spin_lock(&ailp->xa_lock); - xfs_trans_ail_delete(ailp, lip, SHUTDOWN_CORRUPT_INCORE); - xfs_buf_item_free(BUF_ITEM(lip)); -} diff --git a/src/linux/fs/xfs/xfs_buf_item.h b/src/linux/fs/xfs/xfs_buf_item.h deleted file mode 100644 index f7eba99..0000000 --- a/src/linux/fs/xfs/xfs_buf_item.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_BUF_ITEM_H__ -#define __XFS_BUF_ITEM_H__ - -/* kernel only definitions */ - -/* buf log item flags */ -#define XFS_BLI_HOLD 0x01 -#define XFS_BLI_DIRTY 0x02 -#define XFS_BLI_STALE 0x04 -#define XFS_BLI_LOGGED 0x08 -#define XFS_BLI_INODE_ALLOC_BUF 0x10 -#define XFS_BLI_STALE_INODE 0x20 -#define XFS_BLI_INODE_BUF 0x40 -#define XFS_BLI_ORDERED 0x80 - -#define XFS_BLI_FLAGS \ - { XFS_BLI_HOLD, "HOLD" }, \ - { XFS_BLI_DIRTY, "DIRTY" }, \ - { XFS_BLI_STALE, "STALE" }, \ - { XFS_BLI_LOGGED, "LOGGED" }, \ - { XFS_BLI_INODE_ALLOC_BUF, "INODE_ALLOC" }, \ - { XFS_BLI_STALE_INODE, "STALE_INODE" }, \ - { XFS_BLI_INODE_BUF, "INODE_BUF" }, \ - { XFS_BLI_ORDERED, "ORDERED" } - - -struct xfs_buf; -struct xfs_mount; -struct xfs_buf_log_item; - -/* - * This is the in core log item structure used to track information - * needed to log buffers. It tracks how many times the lock has been - * locked, and which 128 byte chunks of the buffer are dirty. - */ -typedef struct xfs_buf_log_item { - xfs_log_item_t bli_item; /* common item structure */ - struct xfs_buf *bli_buf; /* real buffer pointer */ - unsigned int bli_flags; /* misc flags */ - unsigned int bli_recur; /* lock recursion count */ - atomic_t bli_refcount; /* cnt of tp refs */ - int bli_format_count; /* count of headers */ - struct xfs_buf_log_format *bli_formats; /* array of in-log header ptrs */ - struct xfs_buf_log_format __bli_format; /* embedded in-log header */ -} xfs_buf_log_item_t; - -int xfs_buf_item_init(struct xfs_buf *, struct xfs_mount *); -void xfs_buf_item_relse(struct xfs_buf *); -void xfs_buf_item_log(xfs_buf_log_item_t *, uint, uint); -uint xfs_buf_item_dirty(xfs_buf_log_item_t *); -void xfs_buf_attach_iodone(struct xfs_buf *, - void(*)(struct xfs_buf *, xfs_log_item_t *), - xfs_log_item_t *); -void xfs_buf_iodone_callbacks(struct xfs_buf *); -void xfs_buf_iodone(struct xfs_buf *, struct xfs_log_item *); - -extern kmem_zone_t *xfs_buf_item_zone; - -#endif /* __XFS_BUF_ITEM_H__ */ diff --git a/src/linux/fs/xfs/xfs_dir2_readdir.c b/src/linux/fs/xfs/xfs_dir2_readdir.c deleted file mode 100644 index 2981698..0000000 --- a/src/linux/fs/xfs/xfs_dir2_readdir.c +++ /dev/null @@ -1,692 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * Copyright (c) 2013 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_inode.h" -#include "xfs_dir2.h" -#include "xfs_dir2_priv.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_bmap.h" -#include "xfs_trans.h" - -/* - * Directory file type support functions - */ -static unsigned char xfs_dir3_filetype_table[] = { - DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, - DT_FIFO, DT_SOCK, DT_LNK, DT_WHT, -}; - -static unsigned char -xfs_dir3_get_dtype( - struct xfs_mount *mp, - __uint8_t filetype) -{ - if (!xfs_sb_version_hasftype(&mp->m_sb)) - return DT_UNKNOWN; - - if (filetype >= XFS_DIR3_FT_MAX) - return DT_UNKNOWN; - - return xfs_dir3_filetype_table[filetype]; -} - -STATIC int -xfs_dir2_sf_getdents( - struct xfs_da_args *args, - struct dir_context *ctx) -{ - int i; /* shortform entry number */ - struct xfs_inode *dp = args->dp; /* incore directory inode */ - xfs_dir2_dataptr_t off; /* current entry's offset */ - xfs_dir2_sf_entry_t *sfep; /* shortform directory entry */ - xfs_dir2_sf_hdr_t *sfp; /* shortform structure */ - xfs_dir2_dataptr_t dot_offset; - xfs_dir2_dataptr_t dotdot_offset; - xfs_ino_t ino; - struct xfs_da_geometry *geo = args->geo; - - ASSERT(dp->i_df.if_flags & XFS_IFINLINE); - /* - * Give up if the directory is way too short. - */ - if (dp->i_d.di_size < offsetof(xfs_dir2_sf_hdr_t, parent)) { - ASSERT(XFS_FORCED_SHUTDOWN(dp->i_mount)); - return -EIO; - } - - ASSERT(dp->i_df.if_bytes == dp->i_d.di_size); - ASSERT(dp->i_df.if_u1.if_data != NULL); - - sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data; - - if (dp->i_d.di_size < xfs_dir2_sf_hdr_size(sfp->i8count)) - return -EFSCORRUPTED; - - /* - * If the block number in the offset is out of range, we're done. - */ - if (xfs_dir2_dataptr_to_db(geo, ctx->pos) > geo->datablk) - return 0; - - /* - * Precalculate offsets for . and .. as we will always need them. - * - * XXX(hch): the second argument is sometimes 0 and sometimes - * geo->datablk - */ - dot_offset = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, - dp->d_ops->data_dot_offset); - dotdot_offset = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, - dp->d_ops->data_dotdot_offset); - - /* - * Put . entry unless we're starting past it. - */ - if (ctx->pos <= dot_offset) { - ctx->pos = dot_offset & 0x7fffffff; - if (!dir_emit(ctx, ".", 1, dp->i_ino, DT_DIR)) - return 0; - } - - /* - * Put .. entry unless we're starting past it. - */ - if (ctx->pos <= dotdot_offset) { - ino = dp->d_ops->sf_get_parent_ino(sfp); - ctx->pos = dotdot_offset & 0x7fffffff; - if (!dir_emit(ctx, "..", 2, ino, DT_DIR)) - return 0; - } - - /* - * Loop while there are more entries and put'ing works. - */ - sfep = xfs_dir2_sf_firstentry(sfp); - for (i = 0; i < sfp->count; i++) { - __uint8_t filetype; - - off = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, - xfs_dir2_sf_get_offset(sfep)); - - if (ctx->pos > off) { - sfep = dp->d_ops->sf_nextentry(sfp, sfep); - continue; - } - - ino = dp->d_ops->sf_get_ino(sfp, sfep); - filetype = dp->d_ops->sf_get_ftype(sfep); - ctx->pos = off & 0x7fffffff; - if (!dir_emit(ctx, (char *)sfep->name, sfep->namelen, ino, - xfs_dir3_get_dtype(dp->i_mount, filetype))) - return 0; - sfep = dp->d_ops->sf_nextentry(sfp, sfep); - } - - ctx->pos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk + 1, 0) & - 0x7fffffff; - return 0; -} - -/* - * Readdir for block directories. - */ -STATIC int -xfs_dir2_block_getdents( - struct xfs_da_args *args, - struct dir_context *ctx) -{ - struct xfs_inode *dp = args->dp; /* incore directory inode */ - xfs_dir2_data_hdr_t *hdr; /* block header */ - struct xfs_buf *bp; /* buffer for block */ - xfs_dir2_block_tail_t *btp; /* block tail */ - xfs_dir2_data_entry_t *dep; /* block data entry */ - xfs_dir2_data_unused_t *dup; /* block unused entry */ - char *endptr; /* end of the data entries */ - int error; /* error return value */ - char *ptr; /* current data entry */ - int wantoff; /* starting block offset */ - xfs_off_t cook; - struct xfs_da_geometry *geo = args->geo; - int lock_mode; - - /* - * If the block number in the offset is out of range, we're done. - */ - if (xfs_dir2_dataptr_to_db(geo, ctx->pos) > geo->datablk) - return 0; - - lock_mode = xfs_ilock_data_map_shared(dp); - error = xfs_dir3_block_read(NULL, dp, &bp); - xfs_iunlock(dp, lock_mode); - if (error) - return error; - - /* - * Extract the byte offset we start at from the seek pointer. - * We'll skip entries before this. - */ - wantoff = xfs_dir2_dataptr_to_off(geo, ctx->pos); - hdr = bp->b_addr; - xfs_dir3_data_check(dp, bp); - /* - * Set up values for the loop. - */ - btp = xfs_dir2_block_tail_p(geo, hdr); - ptr = (char *)dp->d_ops->data_entry_p(hdr); - endptr = (char *)xfs_dir2_block_leaf_p(btp); - - /* - * Loop over the data portion of the block. - * Each object is a real entry (dep) or an unused one (dup). - */ - while (ptr < endptr) { - __uint8_t filetype; - - dup = (xfs_dir2_data_unused_t *)ptr; - /* - * Unused, skip it. - */ - if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { - ptr += be16_to_cpu(dup->length); - continue; - } - - dep = (xfs_dir2_data_entry_t *)ptr; - - /* - * Bump pointer for the next iteration. - */ - ptr += dp->d_ops->data_entsize(dep->namelen); - /* - * The entry is before the desired starting point, skip it. - */ - if ((char *)dep - (char *)hdr < wantoff) - continue; - - cook = xfs_dir2_db_off_to_dataptr(geo, geo->datablk, - (char *)dep - (char *)hdr); - - ctx->pos = cook & 0x7fffffff; - filetype = dp->d_ops->data_get_ftype(dep); - /* - * If it didn't fit, set the final offset to here & return. - */ - if (!dir_emit(ctx, (char *)dep->name, dep->namelen, - be64_to_cpu(dep->inumber), - xfs_dir3_get_dtype(dp->i_mount, filetype))) { - xfs_trans_brelse(NULL, bp); - return 0; - } - } - - /* - * Reached the end of the block. - * Set the offset to a non-existent block 1 and return. - */ - ctx->pos = xfs_dir2_db_off_to_dataptr(geo, geo->datablk + 1, 0) & - 0x7fffffff; - xfs_trans_brelse(NULL, bp); - return 0; -} - -struct xfs_dir2_leaf_map_info { - xfs_extlen_t map_blocks; /* number of fsbs in map */ - xfs_dablk_t map_off; /* last mapped file offset */ - int map_size; /* total entries in *map */ - int map_valid; /* valid entries in *map */ - int nmap; /* mappings to ask xfs_bmapi */ - xfs_dir2_db_t curdb; /* db for current block */ - int ra_current; /* number of read-ahead blks */ - int ra_index; /* *map index for read-ahead */ - int ra_offset; /* map entry offset for ra */ - int ra_want; /* readahead count wanted */ - struct xfs_bmbt_irec map[]; /* map vector for blocks */ -}; - -STATIC int -xfs_dir2_leaf_readbuf( - struct xfs_da_args *args, - size_t bufsize, - struct xfs_dir2_leaf_map_info *mip, - xfs_dir2_off_t *curoff, - struct xfs_buf **bpp, - bool trim_map) -{ - struct xfs_inode *dp = args->dp; - struct xfs_buf *bp = NULL; - struct xfs_bmbt_irec *map = mip->map; - struct blk_plug plug; - int error = 0; - int length; - int i; - int j; - struct xfs_da_geometry *geo = args->geo; - - /* - * If the caller just finished processing a buffer, it will tell us - * we need to trim that block out of the mapping now it is done. - */ - if (trim_map) { - mip->map_blocks -= geo->fsbcount; - /* - * Loop to get rid of the extents for the - * directory block. - */ - for (i = geo->fsbcount; i > 0; ) { - j = min_t(int, map->br_blockcount, i); - map->br_blockcount -= j; - map->br_startblock += j; - map->br_startoff += j; - /* - * If mapping is done, pitch it from - * the table. - */ - if (!map->br_blockcount && --mip->map_valid) - memmove(&map[0], &map[1], - sizeof(map[0]) * mip->map_valid); - i -= j; - } - } - - /* - * Recalculate the readahead blocks wanted. - */ - mip->ra_want = howmany(bufsize + geo->blksize, (1 << geo->fsblog)) - 1; - ASSERT(mip->ra_want >= 0); - - /* - * If we don't have as many as we want, and we haven't - * run out of data blocks, get some more mappings. - */ - if (1 + mip->ra_want > mip->map_blocks && - mip->map_off < xfs_dir2_byte_to_da(geo, XFS_DIR2_LEAF_OFFSET)) { - /* - * Get more bmaps, fill in after the ones - * we already have in the table. - */ - mip->nmap = mip->map_size - mip->map_valid; - error = xfs_bmapi_read(dp, mip->map_off, - xfs_dir2_byte_to_da(geo, XFS_DIR2_LEAF_OFFSET) - - mip->map_off, - &map[mip->map_valid], &mip->nmap, 0); - - /* - * Don't know if we should ignore this or try to return an - * error. The trouble with returning errors is that readdir - * will just stop without actually passing the error through. - */ - if (error) - goto out; /* XXX */ - - /* - * If we got all the mappings we asked for, set the final map - * offset based on the last bmap value received. Otherwise, - * we've reached the end. - */ - if (mip->nmap == mip->map_size - mip->map_valid) { - i = mip->map_valid + mip->nmap - 1; - mip->map_off = map[i].br_startoff + map[i].br_blockcount; - } else - mip->map_off = xfs_dir2_byte_to_da(geo, - XFS_DIR2_LEAF_OFFSET); - - /* - * Look for holes in the mapping, and eliminate them. Count up - * the valid blocks. - */ - for (i = mip->map_valid; i < mip->map_valid + mip->nmap; ) { - if (map[i].br_startblock == HOLESTARTBLOCK) { - mip->nmap--; - length = mip->map_valid + mip->nmap - i; - if (length) - memmove(&map[i], &map[i + 1], - sizeof(map[i]) * length); - } else { - mip->map_blocks += map[i].br_blockcount; - i++; - } - } - mip->map_valid += mip->nmap; - } - - /* - * No valid mappings, so no more data blocks. - */ - if (!mip->map_valid) { - *curoff = xfs_dir2_da_to_byte(geo, mip->map_off); - goto out; - } - - /* - * Read the directory block starting at the first mapping. - */ - mip->curdb = xfs_dir2_da_to_db(geo, map->br_startoff); - error = xfs_dir3_data_read(NULL, dp, map->br_startoff, - map->br_blockcount >= geo->fsbcount ? - XFS_FSB_TO_DADDR(dp->i_mount, map->br_startblock) : - -1, &bp); - /* - * Should just skip over the data block instead of giving up. - */ - if (error) - goto out; /* XXX */ - - /* - * Adjust the current amount of read-ahead: we just read a block that - * was previously ra. - */ - if (mip->ra_current) - mip->ra_current -= geo->fsbcount; - - /* - * Do we need more readahead? - */ - blk_start_plug(&plug); - for (mip->ra_index = mip->ra_offset = i = 0; - mip->ra_want > mip->ra_current && i < mip->map_blocks; - i += geo->fsbcount) { - ASSERT(mip->ra_index < mip->map_valid); - /* - * Read-ahead a contiguous directory block. - */ - if (i > mip->ra_current && - map[mip->ra_index].br_blockcount >= geo->fsbcount) { - xfs_dir3_data_readahead(dp, - map[mip->ra_index].br_startoff + mip->ra_offset, - XFS_FSB_TO_DADDR(dp->i_mount, - map[mip->ra_index].br_startblock + - mip->ra_offset)); - mip->ra_current = i; - } - - /* - * Read-ahead a non-contiguous directory block. This doesn't - * use our mapping, but this is a very rare case. - */ - else if (i > mip->ra_current) { - xfs_dir3_data_readahead(dp, - map[mip->ra_index].br_startoff + - mip->ra_offset, -1); - mip->ra_current = i; - } - - /* - * Advance offset through the mapping table. - */ - for (j = 0; j < geo->fsbcount; j += length ) { - /* - * The rest of this extent but not more than a dir - * block. - */ - length = min_t(int, geo->fsbcount, - map[mip->ra_index].br_blockcount - - mip->ra_offset); - mip->ra_offset += length; - - /* - * Advance to the next mapping if this one is used up. - */ - if (mip->ra_offset == map[mip->ra_index].br_blockcount) { - mip->ra_offset = 0; - mip->ra_index++; - } - } - } - blk_finish_plug(&plug); - -out: - *bpp = bp; - return error; -} - -/* - * Getdents (readdir) for leaf and node directories. - * This reads the data blocks only, so is the same for both forms. - */ -STATIC int -xfs_dir2_leaf_getdents( - struct xfs_da_args *args, - struct dir_context *ctx, - size_t bufsize) -{ - struct xfs_inode *dp = args->dp; - struct xfs_buf *bp = NULL; /* data block buffer */ - xfs_dir2_data_hdr_t *hdr; /* data block header */ - xfs_dir2_data_entry_t *dep; /* data entry */ - xfs_dir2_data_unused_t *dup; /* unused entry */ - int error = 0; /* error return value */ - int length; /* temporary length value */ - int byteoff; /* offset in current block */ - xfs_dir2_off_t curoff; /* current overall offset */ - xfs_dir2_off_t newoff; /* new curoff after new blk */ - char *ptr = NULL; /* pointer to current data */ - struct xfs_dir2_leaf_map_info *map_info; - struct xfs_da_geometry *geo = args->geo; - - /* - * If the offset is at or past the largest allowed value, - * give up right away. - */ - if (ctx->pos >= XFS_DIR2_MAX_DATAPTR) - return 0; - - /* - * Set up to bmap a number of blocks based on the caller's - * buffer size, the directory block size, and the filesystem - * block size. - */ - length = howmany(bufsize + geo->blksize, (1 << geo->fsblog)); - map_info = kmem_zalloc(offsetof(struct xfs_dir2_leaf_map_info, map) + - (length * sizeof(struct xfs_bmbt_irec)), - KM_SLEEP | KM_NOFS); - map_info->map_size = length; - - /* - * Inside the loop we keep the main offset value as a byte offset - * in the directory file. - */ - curoff = xfs_dir2_dataptr_to_byte(ctx->pos); - - /* - * Force this conversion through db so we truncate the offset - * down to get the start of the data block. - */ - map_info->map_off = xfs_dir2_db_to_da(geo, - xfs_dir2_byte_to_db(geo, curoff)); - - /* - * Loop over directory entries until we reach the end offset. - * Get more blocks and readahead as necessary. - */ - while (curoff < XFS_DIR2_LEAF_OFFSET) { - __uint8_t filetype; - - /* - * If we have no buffer, or we're off the end of the - * current buffer, need to get another one. - */ - if (!bp || ptr >= (char *)bp->b_addr + geo->blksize) { - int lock_mode; - bool trim_map = false; - - if (bp) { - xfs_trans_brelse(NULL, bp); - bp = NULL; - trim_map = true; - } - - lock_mode = xfs_ilock_data_map_shared(dp); - error = xfs_dir2_leaf_readbuf(args, bufsize, map_info, - &curoff, &bp, trim_map); - xfs_iunlock(dp, lock_mode); - if (error || !map_info->map_valid) - break; - - /* - * Having done a read, we need to set a new offset. - */ - newoff = xfs_dir2_db_off_to_byte(geo, - map_info->curdb, 0); - /* - * Start of the current block. - */ - if (curoff < newoff) - curoff = newoff; - /* - * Make sure we're in the right block. - */ - else if (curoff > newoff) - ASSERT(xfs_dir2_byte_to_db(geo, curoff) == - map_info->curdb); - hdr = bp->b_addr; - xfs_dir3_data_check(dp, bp); - /* - * Find our position in the block. - */ - ptr = (char *)dp->d_ops->data_entry_p(hdr); - byteoff = xfs_dir2_byte_to_off(geo, curoff); - /* - * Skip past the header. - */ - if (byteoff == 0) - curoff += dp->d_ops->data_entry_offset; - /* - * Skip past entries until we reach our offset. - */ - else { - while ((char *)ptr - (char *)hdr < byteoff) { - dup = (xfs_dir2_data_unused_t *)ptr; - - if (be16_to_cpu(dup->freetag) - == XFS_DIR2_DATA_FREE_TAG) { - - length = be16_to_cpu(dup->length); - ptr += length; - continue; - } - dep = (xfs_dir2_data_entry_t *)ptr; - length = - dp->d_ops->data_entsize(dep->namelen); - ptr += length; - } - /* - * Now set our real offset. - */ - curoff = - xfs_dir2_db_off_to_byte(geo, - xfs_dir2_byte_to_db(geo, curoff), - (char *)ptr - (char *)hdr); - if (ptr >= (char *)hdr + geo->blksize) { - continue; - } - } - } - /* - * We have a pointer to an entry. - * Is it a live one? - */ - dup = (xfs_dir2_data_unused_t *)ptr; - /* - * No, it's unused, skip over it. - */ - if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) { - length = be16_to_cpu(dup->length); - ptr += length; - curoff += length; - continue; - } - - dep = (xfs_dir2_data_entry_t *)ptr; - length = dp->d_ops->data_entsize(dep->namelen); - filetype = dp->d_ops->data_get_ftype(dep); - - ctx->pos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff; - if (!dir_emit(ctx, (char *)dep->name, dep->namelen, - be64_to_cpu(dep->inumber), - xfs_dir3_get_dtype(dp->i_mount, filetype))) - break; - - /* - * Advance to next entry in the block. - */ - ptr += length; - curoff += length; - /* bufsize may have just been a guess; don't go negative */ - bufsize = bufsize > length ? bufsize - length : 0; - } - - /* - * All done. Set output offset value to current offset. - */ - if (curoff > xfs_dir2_dataptr_to_byte(XFS_DIR2_MAX_DATAPTR)) - ctx->pos = XFS_DIR2_MAX_DATAPTR & 0x7fffffff; - else - ctx->pos = xfs_dir2_byte_to_dataptr(curoff) & 0x7fffffff; - kmem_free(map_info); - if (bp) - xfs_trans_brelse(NULL, bp); - return error; -} - -/* - * Read a directory. - */ -int -xfs_readdir( - struct xfs_inode *dp, - struct dir_context *ctx, - size_t bufsize) -{ - struct xfs_da_args args = { NULL }; - int rval; - int v; - - trace_xfs_readdir(dp); - - if (XFS_FORCED_SHUTDOWN(dp->i_mount)) - return -EIO; - - ASSERT(S_ISDIR(VFS_I(dp)->i_mode)); - XFS_STATS_INC(dp->i_mount, xs_dir_getdents); - - args.dp = dp; - args.geo = dp->i_mount->m_dir_geo; - - xfs_ilock(dp, XFS_IOLOCK_SHARED); - if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) - rval = xfs_dir2_sf_getdents(&args, ctx); - else if ((rval = xfs_dir2_isblock(&args, &v))) - ; - else if (v) - rval = xfs_dir2_block_getdents(&args, ctx); - else - rval = xfs_dir2_leaf_getdents(&args, ctx, bufsize); - xfs_iunlock(dp, XFS_IOLOCK_SHARED); - - return rval; -} diff --git a/src/linux/fs/xfs/xfs_discard.c b/src/linux/fs/xfs/xfs_discard.c deleted file mode 100644 index 4ff499a..0000000 --- a/src/linux/fs/xfs/xfs_discard.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) 2010 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_quota.h" -#include "xfs_inode.h" -#include "xfs_btree.h" -#include "xfs_alloc_btree.h" -#include "xfs_alloc.h" -#include "xfs_error.h" -#include "xfs_extent_busy.h" -#include "xfs_discard.h" -#include "xfs_trace.h" -#include "xfs_log.h" - -STATIC int -xfs_trim_extents( - struct xfs_mount *mp, - xfs_agnumber_t agno, - xfs_daddr_t start, - xfs_daddr_t end, - xfs_daddr_t minlen, - __uint64_t *blocks_trimmed) -{ - struct block_device *bdev = mp->m_ddev_targp->bt_bdev; - struct xfs_btree_cur *cur; - struct xfs_buf *agbp; - struct xfs_perag *pag; - int error; - int i; - - pag = xfs_perag_get(mp, agno); - - error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); - if (error || !agbp) - goto out_put_perag; - - cur = xfs_allocbt_init_cursor(mp, NULL, agbp, agno, XFS_BTNUM_CNT); - - /* - * Force out the log. This means any transactions that might have freed - * space before we took the AGF buffer lock are now on disk, and the - * volatile disk cache is flushed. - */ - xfs_log_force(mp, XFS_LOG_SYNC); - - /* - * Look up the longest btree in the AGF and start with it. - */ - error = xfs_alloc_lookup_ge(cur, 0, - be32_to_cpu(XFS_BUF_TO_AGF(agbp)->agf_longest), &i); - if (error) - goto out_del_cursor; - - /* - * Loop until we are done with all extents that are large - * enough to be worth discarding. - */ - while (i) { - xfs_agblock_t fbno; - xfs_extlen_t flen; - xfs_daddr_t dbno; - xfs_extlen_t dlen; - - error = xfs_alloc_get_rec(cur, &fbno, &flen, &i); - if (error) - goto out_del_cursor; - XFS_WANT_CORRUPTED_GOTO(mp, i == 1, out_del_cursor); - ASSERT(flen <= be32_to_cpu(XFS_BUF_TO_AGF(agbp)->agf_longest)); - - /* - * use daddr format for all range/len calculations as that is - * the format the range/len variables are supplied in by - * userspace. - */ - dbno = XFS_AGB_TO_DADDR(mp, agno, fbno); - dlen = XFS_FSB_TO_BB(mp, flen); - - /* - * Too small? Give up. - */ - if (dlen < minlen) { - trace_xfs_discard_toosmall(mp, agno, fbno, flen); - goto out_del_cursor; - } - - /* - * If the extent is entirely outside of the range we are - * supposed to discard skip it. Do not bother to trim - * down partially overlapping ranges for now. - */ - if (dbno + dlen < start || dbno > end) { - trace_xfs_discard_exclude(mp, agno, fbno, flen); - goto next_extent; - } - - /* - * If any blocks in the range are still busy, skip the - * discard and try again the next time. - */ - if (xfs_extent_busy_search(mp, agno, fbno, flen)) { - trace_xfs_discard_busy(mp, agno, fbno, flen); - goto next_extent; - } - - trace_xfs_discard_extent(mp, agno, fbno, flen); - error = blkdev_issue_discard(bdev, dbno, dlen, GFP_NOFS, 0); - if (error) - goto out_del_cursor; - *blocks_trimmed += flen; - -next_extent: - error = xfs_btree_decrement(cur, 0, &i); - if (error) - goto out_del_cursor; - } - -out_del_cursor: - xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); - xfs_buf_relse(agbp); -out_put_perag: - xfs_perag_put(pag); - return error; -} - -/* - * trim a range of the filesystem. - * - * Note: the parameters passed from userspace are byte ranges into the - * filesystem which does not match to the format we use for filesystem block - * addressing. FSB addressing is sparse (AGNO|AGBNO), while the incoming format - * is a linear address range. Hence we need to use DADDR based conversions and - * comparisons for determining the correct offset and regions to trim. - */ -int -xfs_ioc_trim( - struct xfs_mount *mp, - struct fstrim_range __user *urange) -{ - struct request_queue *q = bdev_get_queue(mp->m_ddev_targp->bt_bdev); - unsigned int granularity = q->limits.discard_granularity; - struct fstrim_range range; - xfs_daddr_t start, end, minlen; - xfs_agnumber_t start_agno, end_agno, agno; - __uint64_t blocks_trimmed = 0; - int error, last_error = 0; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!blk_queue_discard(q)) - return -EOPNOTSUPP; - if (copy_from_user(&range, urange, sizeof(range))) - return -EFAULT; - - /* - * Truncating down the len isn't actually quite correct, but using - * BBTOB would mean we trivially get overflows for values - * of ULLONG_MAX or slightly lower. And ULLONG_MAX is the default - * used by the fstrim application. In the end it really doesn't - * matter as trimming blocks is an advisory interface. - */ - if (range.start >= XFS_FSB_TO_B(mp, mp->m_sb.sb_dblocks) || - range.minlen > XFS_FSB_TO_B(mp, mp->m_ag_max_usable) || - range.len < mp->m_sb.sb_blocksize) - return -EINVAL; - - start = BTOBB(range.start); - end = start + BTOBBT(range.len) - 1; - minlen = BTOBB(max_t(u64, granularity, range.minlen)); - - if (end > XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks) - 1) - end = XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks)- 1; - - start_agno = xfs_daddr_to_agno(mp, start); - end_agno = xfs_daddr_to_agno(mp, end); - - for (agno = start_agno; agno <= end_agno; agno++) { - error = xfs_trim_extents(mp, agno, start, end, minlen, - &blocks_trimmed); - if (error) - last_error = error; - } - - if (last_error) - return last_error; - - range.len = XFS_FSB_TO_B(mp, blocks_trimmed); - if (copy_to_user(urange, &range, sizeof(range))) - return -EFAULT; - return 0; -} - -int -xfs_discard_extents( - struct xfs_mount *mp, - struct list_head *list) -{ - struct xfs_extent_busy *busyp; - int error = 0; - - list_for_each_entry(busyp, list, list) { - trace_xfs_discard_extent(mp, busyp->agno, busyp->bno, - busyp->length); - - error = blkdev_issue_discard(mp->m_ddev_targp->bt_bdev, - XFS_AGB_TO_DADDR(mp, busyp->agno, busyp->bno), - XFS_FSB_TO_BB(mp, busyp->length), - GFP_NOFS, 0); - if (error && error != -EOPNOTSUPP) { - xfs_info(mp, - "discard failed for extent [0x%llx,%u], error %d", - (unsigned long long)busyp->bno, - busyp->length, - error); - return error; - } - } - - return 0; -} diff --git a/src/linux/fs/xfs/xfs_discard.h b/src/linux/fs/xfs/xfs_discard.h deleted file mode 100644 index 344879a..0000000 --- a/src/linux/fs/xfs/xfs_discard.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef XFS_DISCARD_H -#define XFS_DISCARD_H 1 - -struct fstrim_range; -struct list_head; - -extern int xfs_ioc_trim(struct xfs_mount *, struct fstrim_range __user *); -extern int xfs_discard_extents(struct xfs_mount *, struct list_head *); - -#endif /* XFS_DISCARD_H */ diff --git a/src/linux/fs/xfs/xfs_dquot.h b/src/linux/fs/xfs/xfs_dquot.h deleted file mode 100644 index 2f536f3..0000000 --- a/src/linux/fs/xfs/xfs_dquot.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_DQUOT_H__ -#define __XFS_DQUOT_H__ - -/* - * Dquots are structures that hold quota information about a user or a group, - * much like inodes are for files. In fact, dquots share many characteristics - * with inodes. However, dquots can also be a centralized resource, relative - * to a collection of inodes. In this respect, dquots share some characteristics - * of the superblock. - * XFS dquots exploit both those in its algorithms. They make every attempt - * to not be a bottleneck when quotas are on and have minimal impact, if any, - * when quotas are off. - */ - -struct xfs_mount; -struct xfs_trans; - -enum { - XFS_QLOWSP_1_PCNT = 0, - XFS_QLOWSP_3_PCNT, - XFS_QLOWSP_5_PCNT, - XFS_QLOWSP_MAX -}; - -/* - * The incore dquot structure - */ -typedef struct xfs_dquot { - uint dq_flags; /* various flags (XFS_DQ_*) */ - struct list_head q_lru; /* global free list of dquots */ - struct xfs_mount*q_mount; /* filesystem this relates to */ - struct xfs_trans*q_transp; /* trans this belongs to currently */ - uint q_nrefs; /* # active refs from inodes */ - xfs_daddr_t q_blkno; /* blkno of dquot buffer */ - int q_bufoffset; /* off of dq in buffer (# dquots) */ - xfs_fileoff_t q_fileoffset; /* offset in quotas file */ - - xfs_disk_dquot_t q_core; /* actual usage & quotas */ - xfs_dq_logitem_t q_logitem; /* dquot log item */ - xfs_qcnt_t q_res_bcount; /* total regular nblks used+reserved */ - xfs_qcnt_t q_res_icount; /* total inos allocd+reserved */ - xfs_qcnt_t q_res_rtbcount;/* total realtime blks used+reserved */ - xfs_qcnt_t q_prealloc_lo_wmark;/* prealloc throttle wmark */ - xfs_qcnt_t q_prealloc_hi_wmark;/* prealloc disabled wmark */ - int64_t q_low_space[XFS_QLOWSP_MAX]; - struct mutex q_qlock; /* quota lock */ - struct completion q_flush; /* flush completion queue */ - atomic_t q_pincount; /* dquot pin count */ - wait_queue_head_t q_pinwait; /* dquot pinning wait queue */ -} xfs_dquot_t; - -/* - * Lock hierarchy for q_qlock: - * XFS_QLOCK_NORMAL is the implicit default, - * XFS_QLOCK_NESTED is the dquot with the higher id in xfs_dqlock2 - */ -enum { - XFS_QLOCK_NORMAL = 0, - XFS_QLOCK_NESTED, -}; - -/* - * Manage the q_flush completion queue embedded in the dquot. This completion - * queue synchronizes processes attempting to flush the in-core dquot back to - * disk. - */ -static inline void xfs_dqflock(xfs_dquot_t *dqp) -{ - wait_for_completion(&dqp->q_flush); -} - -static inline bool xfs_dqflock_nowait(xfs_dquot_t *dqp) -{ - return try_wait_for_completion(&dqp->q_flush); -} - -static inline void xfs_dqfunlock(xfs_dquot_t *dqp) -{ - complete(&dqp->q_flush); -} - -static inline int xfs_dqlock_nowait(struct xfs_dquot *dqp) -{ - return mutex_trylock(&dqp->q_qlock); -} - -static inline void xfs_dqlock(struct xfs_dquot *dqp) -{ - mutex_lock(&dqp->q_qlock); -} - -static inline void xfs_dqunlock(struct xfs_dquot *dqp) -{ - mutex_unlock(&dqp->q_qlock); -} - -static inline int xfs_this_quota_on(struct xfs_mount *mp, int type) -{ - switch (type & XFS_DQ_ALLTYPES) { - case XFS_DQ_USER: - return XFS_IS_UQUOTA_ON(mp); - case XFS_DQ_GROUP: - return XFS_IS_GQUOTA_ON(mp); - case XFS_DQ_PROJ: - return XFS_IS_PQUOTA_ON(mp); - default: - return 0; - } -} - -static inline xfs_dquot_t *xfs_inode_dquot(struct xfs_inode *ip, int type) -{ - switch (type & XFS_DQ_ALLTYPES) { - case XFS_DQ_USER: - return ip->i_udquot; - case XFS_DQ_GROUP: - return ip->i_gdquot; - case XFS_DQ_PROJ: - return ip->i_pdquot; - default: - return NULL; - } -} - -/* - * Check whether a dquot is under low free space conditions. We assume the quota - * is enabled and enforced. - */ -static inline bool xfs_dquot_lowsp(struct xfs_dquot *dqp) -{ - int64_t freesp; - - freesp = be64_to_cpu(dqp->q_core.d_blk_hardlimit) - dqp->q_res_bcount; - if (freesp < dqp->q_low_space[XFS_QLOWSP_1_PCNT]) - return true; - - return false; -} - -#define XFS_DQ_IS_LOCKED(dqp) (mutex_is_locked(&((dqp)->q_qlock))) -#define XFS_DQ_IS_DIRTY(dqp) ((dqp)->dq_flags & XFS_DQ_DIRTY) -#define XFS_QM_ISUDQ(dqp) ((dqp)->dq_flags & XFS_DQ_USER) -#define XFS_QM_ISPDQ(dqp) ((dqp)->dq_flags & XFS_DQ_PROJ) -#define XFS_QM_ISGDQ(dqp) ((dqp)->dq_flags & XFS_DQ_GROUP) - -extern int xfs_qm_dqread(struct xfs_mount *, xfs_dqid_t, uint, - uint, struct xfs_dquot **); -extern void xfs_qm_dqdestroy(xfs_dquot_t *); -extern int xfs_qm_dqflush(struct xfs_dquot *, struct xfs_buf **); -extern void xfs_qm_dqunpin_wait(xfs_dquot_t *); -extern void xfs_qm_adjust_dqtimers(xfs_mount_t *, - xfs_disk_dquot_t *); -extern void xfs_qm_adjust_dqlimits(struct xfs_mount *, - struct xfs_dquot *); -extern int xfs_qm_dqget(xfs_mount_t *, xfs_inode_t *, - xfs_dqid_t, uint, uint, xfs_dquot_t **); -extern void xfs_qm_dqput(xfs_dquot_t *); - -extern void xfs_dqlock2(struct xfs_dquot *, struct xfs_dquot *); - -extern void xfs_dquot_set_prealloc_limits(struct xfs_dquot *); - -static inline struct xfs_dquot *xfs_qm_dqhold(struct xfs_dquot *dqp) -{ - xfs_dqlock(dqp); - dqp->q_nrefs++; - xfs_dqunlock(dqp); - return dqp; -} - -#endif /* __XFS_DQUOT_H__ */ diff --git a/src/linux/fs/xfs/xfs_dquot_item.h b/src/linux/fs/xfs/xfs_dquot_item.h deleted file mode 100644 index 502e946..0000000 --- a/src/linux/fs/xfs/xfs_dquot_item.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2000-2003 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_DQUOT_ITEM_H__ -#define __XFS_DQUOT_ITEM_H__ - -struct xfs_dquot; -struct xfs_trans; -struct xfs_mount; -struct xfs_qoff_logitem; - -typedef struct xfs_dq_logitem { - xfs_log_item_t qli_item; /* common portion */ - struct xfs_dquot *qli_dquot; /* dquot ptr */ - xfs_lsn_t qli_flush_lsn; /* lsn at last flush */ -} xfs_dq_logitem_t; - -typedef struct xfs_qoff_logitem { - xfs_log_item_t qql_item; /* common portion */ - struct xfs_qoff_logitem *qql_start_lip; /* qoff-start logitem, if any */ - unsigned int qql_flags; -} xfs_qoff_logitem_t; - - -extern void xfs_qm_dquot_logitem_init(struct xfs_dquot *); -extern xfs_qoff_logitem_t *xfs_qm_qoff_logitem_init(struct xfs_mount *, - struct xfs_qoff_logitem *, uint); -extern xfs_qoff_logitem_t *xfs_trans_get_qoff_item(struct xfs_trans *, - struct xfs_qoff_logitem *, uint); -extern void xfs_trans_log_quotaoff_item(struct xfs_trans *, - struct xfs_qoff_logitem *); - -#endif /* __XFS_DQUOT_ITEM_H__ */ diff --git a/src/linux/fs/xfs/xfs_error.c b/src/linux/fs/xfs/xfs_error.c deleted file mode 100644 index ed7ee4e..0000000 --- a/src/linux/fs/xfs/xfs_error.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_format.h" -#include "xfs_fs.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_error.h" - -#ifdef DEBUG - -int xfs_etest[XFS_NUM_INJECT_ERROR]; -int64_t xfs_etest_fsid[XFS_NUM_INJECT_ERROR]; -char * xfs_etest_fsname[XFS_NUM_INJECT_ERROR]; -int xfs_error_test_active; - -int -xfs_error_test(int error_tag, int *fsidp, char *expression, - int line, char *file, unsigned long randfactor) -{ - int i; - int64_t fsid; - - if (prandom_u32() % randfactor) - return 0; - - memcpy(&fsid, fsidp, sizeof(xfs_fsid_t)); - - for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) { - if (xfs_etest[i] == error_tag && xfs_etest_fsid[i] == fsid) { - xfs_warn(NULL, - "Injecting error (%s) at file %s, line %d, on filesystem \"%s\"", - expression, file, line, xfs_etest_fsname[i]); - return 1; - } - } - - return 0; -} - -int -xfs_errortag_add(unsigned int error_tag, xfs_mount_t *mp) -{ - int i; - int len; - int64_t fsid; - - if (error_tag >= XFS_ERRTAG_MAX) - return -EINVAL; - - memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t)); - - for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) { - if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) { - xfs_warn(mp, "error tag #%d on", error_tag); - return 0; - } - } - - for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) { - if (xfs_etest[i] == 0) { - xfs_warn(mp, "Turned on XFS error tag #%d", - error_tag); - xfs_etest[i] = error_tag; - xfs_etest_fsid[i] = fsid; - len = strlen(mp->m_fsname); - xfs_etest_fsname[i] = kmem_alloc(len + 1, KM_SLEEP); - strcpy(xfs_etest_fsname[i], mp->m_fsname); - xfs_error_test_active++; - return 0; - } - } - - xfs_warn(mp, "error tag overflow, too many turned on"); - - return 1; -} - -int -xfs_errortag_clearall(xfs_mount_t *mp, int loud) -{ - int64_t fsid; - int cleared = 0; - int i; - - memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t)); - - - for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) { - if ((fsid == 0LL || xfs_etest_fsid[i] == fsid) && - xfs_etest[i] != 0) { - cleared = 1; - xfs_warn(mp, "Clearing XFS error tag #%d", - xfs_etest[i]); - xfs_etest[i] = 0; - xfs_etest_fsid[i] = 0LL; - kmem_free(xfs_etest_fsname[i]); - xfs_etest_fsname[i] = NULL; - xfs_error_test_active--; - } - } - - if (loud || cleared) - xfs_warn(mp, "Cleared all XFS error tags for filesystem"); - - return 0; -} -#endif /* DEBUG */ - -void -xfs_error_report( - const char *tag, - int level, - struct xfs_mount *mp, - const char *filename, - int linenum, - void *ra) -{ - if (level <= xfs_error_level) { - xfs_alert_tag(mp, XFS_PTAG_ERROR_REPORT, - "Internal error %s at line %d of file %s. Caller %pS", - tag, linenum, filename, ra); - - xfs_stack_trace(); - } -} - -void -xfs_corruption_error( - const char *tag, - int level, - struct xfs_mount *mp, - void *p, - const char *filename, - int linenum, - void *ra) -{ - if (level <= xfs_error_level) - xfs_hex_dump(p, 64); - xfs_error_report(tag, level, mp, filename, linenum, ra); - xfs_alert(mp, "Corruption detected. Unmount and run xfs_repair"); -} - -/* - * Warnings specifically for verifier errors. Differentiate CRC vs. invalid - * values, and omit the stack trace unless the error level is tuned high. - */ -void -xfs_verifier_error( - struct xfs_buf *bp) -{ - struct xfs_mount *mp = bp->b_target->bt_mount; - - xfs_alert(mp, "Metadata %s detected at %pF, %s block 0x%llx", - bp->b_error == -EFSBADCRC ? "CRC error" : "corruption", - __return_address, bp->b_ops->name, bp->b_bn); - - xfs_alert(mp, "Unmount and run xfs_repair"); - - if (xfs_error_level >= XFS_ERRLEVEL_LOW) { - xfs_alert(mp, "First 64 bytes of corrupted metadata buffer:"); - xfs_hex_dump(xfs_buf_offset(bp, 0), 64); - } - - if (xfs_error_level >= XFS_ERRLEVEL_HIGH) - xfs_stack_trace(); -} diff --git a/src/linux/fs/xfs/xfs_error.h b/src/linux/fs/xfs/xfs_error.h deleted file mode 100644 index 05f8666..0000000 --- a/src/linux/fs/xfs/xfs_error.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_ERROR_H__ -#define __XFS_ERROR_H__ - -struct xfs_mount; - -extern void xfs_error_report(const char *tag, int level, struct xfs_mount *mp, - const char *filename, int linenum, void *ra); -extern void xfs_corruption_error(const char *tag, int level, - struct xfs_mount *mp, void *p, const char *filename, - int linenum, void *ra); -extern void xfs_verifier_error(struct xfs_buf *bp); - -#define XFS_ERROR_REPORT(e, lvl, mp) \ - xfs_error_report(e, lvl, mp, __FILE__, __LINE__, __return_address) -#define XFS_CORRUPTION_ERROR(e, lvl, mp, mem) \ - xfs_corruption_error(e, lvl, mp, mem, \ - __FILE__, __LINE__, __return_address) - -#define XFS_ERRLEVEL_OFF 0 -#define XFS_ERRLEVEL_LOW 1 -#define XFS_ERRLEVEL_HIGH 5 - -/* - * Macros to set EFSCORRUPTED & return/branch. - */ -#define XFS_WANT_CORRUPTED_GOTO(mp, x, l) \ - { \ - int fs_is_ok = (x); \ - ASSERT(fs_is_ok); \ - if (unlikely(!fs_is_ok)) { \ - XFS_ERROR_REPORT("XFS_WANT_CORRUPTED_GOTO", \ - XFS_ERRLEVEL_LOW, mp); \ - error = -EFSCORRUPTED; \ - goto l; \ - } \ - } - -#define XFS_WANT_CORRUPTED_RETURN(mp, x) \ - { \ - int fs_is_ok = (x); \ - ASSERT(fs_is_ok); \ - if (unlikely(!fs_is_ok)) { \ - XFS_ERROR_REPORT("XFS_WANT_CORRUPTED_RETURN", \ - XFS_ERRLEVEL_LOW, mp); \ - return -EFSCORRUPTED; \ - } \ - } - -/* - * error injection tags - the labels can be anything you want - * but each tag should have its own unique number - */ - -#define XFS_ERRTAG_NOERROR 0 -#define XFS_ERRTAG_IFLUSH_1 1 -#define XFS_ERRTAG_IFLUSH_2 2 -#define XFS_ERRTAG_IFLUSH_3 3 -#define XFS_ERRTAG_IFLUSH_4 4 -#define XFS_ERRTAG_IFLUSH_5 5 -#define XFS_ERRTAG_IFLUSH_6 6 -#define XFS_ERRTAG_DA_READ_BUF 7 -#define XFS_ERRTAG_BTREE_CHECK_LBLOCK 8 -#define XFS_ERRTAG_BTREE_CHECK_SBLOCK 9 -#define XFS_ERRTAG_ALLOC_READ_AGF 10 -#define XFS_ERRTAG_IALLOC_READ_AGI 11 -#define XFS_ERRTAG_ITOBP_INOTOBP 12 -#define XFS_ERRTAG_IUNLINK 13 -#define XFS_ERRTAG_IUNLINK_REMOVE 14 -#define XFS_ERRTAG_DIR_INO_VALIDATE 15 -#define XFS_ERRTAG_BULKSTAT_READ_CHUNK 16 -#define XFS_ERRTAG_IODONE_IOERR 17 -#define XFS_ERRTAG_STRATREAD_IOERR 18 -#define XFS_ERRTAG_STRATCMPL_IOERR 19 -#define XFS_ERRTAG_DIOWRITE_IOERR 20 -#define XFS_ERRTAG_BMAPIFORMAT 21 -#define XFS_ERRTAG_FREE_EXTENT 22 -#define XFS_ERRTAG_RMAP_FINISH_ONE 23 -#define XFS_ERRTAG_REFCOUNT_CONTINUE_UPDATE 24 -#define XFS_ERRTAG_REFCOUNT_FINISH_ONE 25 -#define XFS_ERRTAG_BMAP_FINISH_ONE 26 -#define XFS_ERRTAG_AG_RESV_CRITICAL 27 -#define XFS_ERRTAG_MAX 28 - -/* - * Random factors for above tags, 1 means always, 2 means 1/2 time, etc. - */ -#define XFS_RANDOM_DEFAULT 100 -#define XFS_RANDOM_IFLUSH_1 XFS_RANDOM_DEFAULT -#define XFS_RANDOM_IFLUSH_2 XFS_RANDOM_DEFAULT -#define XFS_RANDOM_IFLUSH_3 XFS_RANDOM_DEFAULT -#define XFS_RANDOM_IFLUSH_4 XFS_RANDOM_DEFAULT -#define XFS_RANDOM_IFLUSH_5 XFS_RANDOM_DEFAULT -#define XFS_RANDOM_IFLUSH_6 XFS_RANDOM_DEFAULT -#define XFS_RANDOM_DA_READ_BUF XFS_RANDOM_DEFAULT -#define XFS_RANDOM_BTREE_CHECK_LBLOCK (XFS_RANDOM_DEFAULT/4) -#define XFS_RANDOM_BTREE_CHECK_SBLOCK XFS_RANDOM_DEFAULT -#define XFS_RANDOM_ALLOC_READ_AGF XFS_RANDOM_DEFAULT -#define XFS_RANDOM_IALLOC_READ_AGI XFS_RANDOM_DEFAULT -#define XFS_RANDOM_ITOBP_INOTOBP XFS_RANDOM_DEFAULT -#define XFS_RANDOM_IUNLINK XFS_RANDOM_DEFAULT -#define XFS_RANDOM_IUNLINK_REMOVE XFS_RANDOM_DEFAULT -#define XFS_RANDOM_DIR_INO_VALIDATE XFS_RANDOM_DEFAULT -#define XFS_RANDOM_BULKSTAT_READ_CHUNK XFS_RANDOM_DEFAULT -#define XFS_RANDOM_IODONE_IOERR (XFS_RANDOM_DEFAULT/10) -#define XFS_RANDOM_STRATREAD_IOERR (XFS_RANDOM_DEFAULT/10) -#define XFS_RANDOM_STRATCMPL_IOERR (XFS_RANDOM_DEFAULT/10) -#define XFS_RANDOM_DIOWRITE_IOERR (XFS_RANDOM_DEFAULT/10) -#define XFS_RANDOM_BMAPIFORMAT XFS_RANDOM_DEFAULT -#define XFS_RANDOM_FREE_EXTENT 1 -#define XFS_RANDOM_RMAP_FINISH_ONE 1 -#define XFS_RANDOM_REFCOUNT_CONTINUE_UPDATE 1 -#define XFS_RANDOM_REFCOUNT_FINISH_ONE 1 -#define XFS_RANDOM_BMAP_FINISH_ONE 1 -#define XFS_RANDOM_AG_RESV_CRITICAL 4 - -#ifdef DEBUG -extern int xfs_error_test_active; -extern int xfs_error_test(int, int *, char *, int, char *, unsigned long); - -#define XFS_NUM_INJECT_ERROR 10 -#define XFS_TEST_ERROR(expr, mp, tag, rf) \ - ((expr) || (xfs_error_test_active && \ - xfs_error_test((tag), (mp)->m_fixedfsid, "expr", __LINE__, __FILE__, \ - (rf)))) - -extern int xfs_errortag_add(unsigned int error_tag, struct xfs_mount *mp); -extern int xfs_errortag_clearall(struct xfs_mount *mp, int loud); -#else -#define XFS_TEST_ERROR(expr, mp, tag, rf) (expr) -#define xfs_errortag_add(tag, mp) (ENOSYS) -#define xfs_errortag_clearall(mp, loud) (ENOSYS) -#endif /* DEBUG */ - -/* - * XFS panic tags -- allow a call to xfs_alert_tag() be turned into - * a panic by setting xfs_panic_mask in a sysctl. - */ -#define XFS_NO_PTAG 0 -#define XFS_PTAG_IFLUSH 0x00000001 -#define XFS_PTAG_LOGRES 0x00000002 -#define XFS_PTAG_AILDELETE 0x00000004 -#define XFS_PTAG_ERROR_REPORT 0x00000008 -#define XFS_PTAG_SHUTDOWN_CORRUPT 0x00000010 -#define XFS_PTAG_SHUTDOWN_IOERROR 0x00000020 -#define XFS_PTAG_SHUTDOWN_LOGERROR 0x00000040 -#define XFS_PTAG_FSBLOCK_ZERO 0x00000080 - -#endif /* __XFS_ERROR_H__ */ diff --git a/src/linux/fs/xfs/xfs_export.c b/src/linux/fs/xfs/xfs_export.c deleted file mode 100644 index fe1bfee..0000000 --- a/src/linux/fs/xfs/xfs_export.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (c) 2004-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_dir2.h" -#include "xfs_export.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_trace.h" -#include "xfs_icache.h" -#include "xfs_log.h" -#include "xfs_pnfs.h" - -/* - * Note that we only accept fileids which are long enough rather than allow - * the parent generation number to default to zero. XFS considers zero a - * valid generation number not an invalid/wildcard value. - */ -static int xfs_fileid_length(int fileid_type) -{ - switch (fileid_type) { - case FILEID_INO32_GEN: - return 2; - case FILEID_INO32_GEN_PARENT: - return 4; - case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG: - return 3; - case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG: - return 6; - } - return FILEID_INVALID; -} - -STATIC int -xfs_fs_encode_fh( - struct inode *inode, - __u32 *fh, - int *max_len, - struct inode *parent) -{ - struct fid *fid = (struct fid *)fh; - struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fh; - int fileid_type; - int len; - - /* Directories don't need their parent encoded, they have ".." */ - if (!parent) - fileid_type = FILEID_INO32_GEN; - else - fileid_type = FILEID_INO32_GEN_PARENT; - - /* - * If the the filesystem may contain 64bit inode numbers, we need - * to use larger file handles that can represent them. - * - * While we only allocate inodes that do not fit into 32 bits any - * large enough filesystem may contain them, thus the slightly - * confusing looking conditional below. - */ - if (!(XFS_M(inode->i_sb)->m_flags & XFS_MOUNT_SMALL_INUMS) || - (XFS_M(inode->i_sb)->m_flags & XFS_MOUNT_32BITINODES)) - fileid_type |= XFS_FILEID_TYPE_64FLAG; - - /* - * Only encode if there is enough space given. In practice - * this means we can't export a filesystem with 64bit inodes - * over NFSv2 with the subtree_check export option; the other - * seven combinations work. The real answer is "don't use v2". - */ - len = xfs_fileid_length(fileid_type); - if (*max_len < len) { - *max_len = len; - return FILEID_INVALID; - } - *max_len = len; - - switch (fileid_type) { - case FILEID_INO32_GEN_PARENT: - fid->i32.parent_ino = XFS_I(parent)->i_ino; - fid->i32.parent_gen = parent->i_generation; - /*FALLTHRU*/ - case FILEID_INO32_GEN: - fid->i32.ino = XFS_I(inode)->i_ino; - fid->i32.gen = inode->i_generation; - break; - case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG: - fid64->parent_ino = XFS_I(parent)->i_ino; - fid64->parent_gen = parent->i_generation; - /*FALLTHRU*/ - case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG: - fid64->ino = XFS_I(inode)->i_ino; - fid64->gen = inode->i_generation; - break; - } - - return fileid_type; -} - -STATIC struct inode * -xfs_nfs_get_inode( - struct super_block *sb, - u64 ino, - u32 generation) - { - xfs_mount_t *mp = XFS_M(sb); - xfs_inode_t *ip; - int error; - - /* - * NFS can sometimes send requests for ino 0. Fail them gracefully. - */ - if (ino == 0) - return ERR_PTR(-ESTALE); - - /* - * The XFS_IGET_UNTRUSTED means that an invalid inode number is just - * fine and not an indication of a corrupted filesystem as clients can - * send invalid file handles and we have to handle it gracefully.. - */ - error = xfs_iget(mp, NULL, ino, XFS_IGET_UNTRUSTED, 0, &ip); - if (error) { - /* - * EINVAL means the inode cluster doesn't exist anymore. - * This implies the filehandle is stale, so we should - * translate it here. - * We don't use ESTALE directly down the chain to not - * confuse applications using bulkstat that expect EINVAL. - */ - if (error == -EINVAL || error == -ENOENT) - error = -ESTALE; - return ERR_PTR(error); - } - - if (VFS_I(ip)->i_generation != generation) { - IRELE(ip); - return ERR_PTR(-ESTALE); - } - - return VFS_I(ip); -} - -STATIC struct dentry * -xfs_fs_fh_to_dentry(struct super_block *sb, struct fid *fid, - int fh_len, int fileid_type) -{ - struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fid; - struct inode *inode = NULL; - - if (fh_len < xfs_fileid_length(fileid_type)) - return NULL; - - switch (fileid_type) { - case FILEID_INO32_GEN_PARENT: - case FILEID_INO32_GEN: - inode = xfs_nfs_get_inode(sb, fid->i32.ino, fid->i32.gen); - break; - case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG: - case FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG: - inode = xfs_nfs_get_inode(sb, fid64->ino, fid64->gen); - break; - } - - return d_obtain_alias(inode); -} - -STATIC struct dentry * -xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid, - int fh_len, int fileid_type) -{ - struct xfs_fid64 *fid64 = (struct xfs_fid64 *)fid; - struct inode *inode = NULL; - - if (fh_len < xfs_fileid_length(fileid_type)) - return NULL; - - switch (fileid_type) { - case FILEID_INO32_GEN_PARENT: - inode = xfs_nfs_get_inode(sb, fid->i32.parent_ino, - fid->i32.parent_gen); - break; - case FILEID_INO32_GEN_PARENT | XFS_FILEID_TYPE_64FLAG: - inode = xfs_nfs_get_inode(sb, fid64->parent_ino, - fid64->parent_gen); - break; - } - - return d_obtain_alias(inode); -} - -STATIC struct dentry * -xfs_fs_get_parent( - struct dentry *child) -{ - int error; - struct xfs_inode *cip; - - error = xfs_lookup(XFS_I(d_inode(child)), &xfs_name_dotdot, &cip, NULL); - if (unlikely(error)) - return ERR_PTR(error); - - return d_obtain_alias(VFS_I(cip)); -} - -STATIC int -xfs_fs_nfs_commit_metadata( - struct inode *inode) -{ - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; - xfs_lsn_t lsn = 0; - - xfs_ilock(ip, XFS_ILOCK_SHARED); - if (xfs_ipincount(ip)) - lsn = ip->i_itemp->ili_last_lsn; - xfs_iunlock(ip, XFS_ILOCK_SHARED); - - if (!lsn) - return 0; - return _xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, NULL); -} - -const struct export_operations xfs_export_operations = { - .encode_fh = xfs_fs_encode_fh, - .fh_to_dentry = xfs_fs_fh_to_dentry, - .fh_to_parent = xfs_fs_fh_to_parent, - .get_parent = xfs_fs_get_parent, - .commit_metadata = xfs_fs_nfs_commit_metadata, -#ifdef CONFIG_EXPORTFS_BLOCK_OPS - .get_uuid = xfs_fs_get_uuid, - .map_blocks = xfs_fs_map_blocks, - .commit_blocks = xfs_fs_commit_blocks, -#endif -}; diff --git a/src/linux/fs/xfs/xfs_export.h b/src/linux/fs/xfs/xfs_export.h deleted file mode 100644 index 3272b6a..0000000 --- a/src/linux/fs/xfs/xfs_export.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_EXPORT_H__ -#define __XFS_EXPORT_H__ - -/* - * Common defines for code related to exporting XFS filesystems over NFS. - * - * The NFS fileid goes out on the wire as an array of - * 32bit unsigned ints in host order. There are 5 possible - * formats. - * - * (1) fileid_type=0x00 - * (no fileid data; handled by the generic code) - * - * (2) fileid_type=0x01 - * inode-num - * generation - * - * (3) fileid_type=0x02 - * inode-num - * generation - * parent-inode-num - * parent-generation - * - * (4) fileid_type=0x81 - * inode-num-lo32 - * inode-num-hi32 - * generation - * - * (5) fileid_type=0x82 - * inode-num-lo32 - * inode-num-hi32 - * generation - * parent-inode-num-lo32 - * parent-inode-num-hi32 - * parent-generation - * - * Note, the NFS filehandle also includes an fsid portion which - * may have an inode number in it. That number is hardcoded to - * 32bits and there is no way for XFS to intercept it. In - * practice this means when exporting an XFS filesystem with 64bit - * inodes you should either export the mountpoint (rather than - * a subdirectory) or use the "fsid" export option. - */ - -struct xfs_fid64 { - u64 ino; - u32 gen; - u64 parent_ino; - u32 parent_gen; -} __attribute__((packed)); - -/* This flag goes on the wire. Don't play with it. */ -#define XFS_FILEID_TYPE_64FLAG 0x80 /* NFS fileid has 64bit inodes */ - -#endif /* __XFS_EXPORT_H__ */ diff --git a/src/linux/fs/xfs/xfs_extent_busy.c b/src/linux/fs/xfs/xfs_extent_busy.c deleted file mode 100644 index 162dc18..0000000 --- a/src/linux/fs/xfs/xfs_extent_busy.c +++ /dev/null @@ -1,604 +0,0 @@ -/* - * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. - * Copyright (c) 2010 David Chinner. - * Copyright (c) 2011 Christoph Hellwig. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_shared.h" -#include "xfs_trans_resv.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_alloc.h" -#include "xfs_extent_busy.h" -#include "xfs_trace.h" -#include "xfs_trans.h" -#include "xfs_log.h" - -void -xfs_extent_busy_insert( - struct xfs_trans *tp, - xfs_agnumber_t agno, - xfs_agblock_t bno, - xfs_extlen_t len, - unsigned int flags) -{ - struct xfs_extent_busy *new; - struct xfs_extent_busy *busyp; - struct xfs_perag *pag; - struct rb_node **rbp; - struct rb_node *parent = NULL; - - new = kmem_zalloc(sizeof(struct xfs_extent_busy), KM_MAYFAIL); - if (!new) { - /* - * No Memory! Since it is now not possible to track the free - * block, make this a synchronous transaction to insure that - * the block is not reused before this transaction commits. - */ - trace_xfs_extent_busy_enomem(tp->t_mountp, agno, bno, len); - xfs_trans_set_sync(tp); - return; - } - - new->agno = agno; - new->bno = bno; - new->length = len; - INIT_LIST_HEAD(&new->list); - new->flags = flags; - - /* trace before insert to be able to see failed inserts */ - trace_xfs_extent_busy(tp->t_mountp, agno, bno, len); - - pag = xfs_perag_get(tp->t_mountp, new->agno); - spin_lock(&pag->pagb_lock); - rbp = &pag->pagb_tree.rb_node; - while (*rbp) { - parent = *rbp; - busyp = rb_entry(parent, struct xfs_extent_busy, rb_node); - - if (new->bno < busyp->bno) { - rbp = &(*rbp)->rb_left; - ASSERT(new->bno + new->length <= busyp->bno); - } else if (new->bno > busyp->bno) { - rbp = &(*rbp)->rb_right; - ASSERT(bno >= busyp->bno + busyp->length); - } else { - ASSERT(0); - } - } - - rb_link_node(&new->rb_node, parent, rbp); - rb_insert_color(&new->rb_node, &pag->pagb_tree); - - list_add(&new->list, &tp->t_busy); - spin_unlock(&pag->pagb_lock); - xfs_perag_put(pag); -} - -/* - * Search for a busy extent within the range of the extent we are about to - * allocate. You need to be holding the busy extent tree lock when calling - * xfs_extent_busy_search(). This function returns 0 for no overlapping busy - * extent, -1 for an overlapping but not exact busy extent, and 1 for an exact - * match. This is done so that a non-zero return indicates an overlap that - * will require a synchronous transaction, but it can still be - * used to distinguish between a partial or exact match. - */ -int -xfs_extent_busy_search( - struct xfs_mount *mp, - xfs_agnumber_t agno, - xfs_agblock_t bno, - xfs_extlen_t len) -{ - struct xfs_perag *pag; - struct rb_node *rbp; - struct xfs_extent_busy *busyp; - int match = 0; - - pag = xfs_perag_get(mp, agno); - spin_lock(&pag->pagb_lock); - - rbp = pag->pagb_tree.rb_node; - - /* find closest start bno overlap */ - while (rbp) { - busyp = rb_entry(rbp, struct xfs_extent_busy, rb_node); - if (bno < busyp->bno) { - /* may overlap, but exact start block is lower */ - if (bno + len > busyp->bno) - match = -1; - rbp = rbp->rb_left; - } else if (bno > busyp->bno) { - /* may overlap, but exact start block is higher */ - if (bno < busyp->bno + busyp->length) - match = -1; - rbp = rbp->rb_right; - } else { - /* bno matches busyp, length determines exact match */ - match = (busyp->length == len) ? 1 : -1; - break; - } - } - spin_unlock(&pag->pagb_lock); - xfs_perag_put(pag); - return match; -} - -/* - * The found free extent [fbno, fend] overlaps part or all of the given busy - * extent. If the overlap covers the beginning, the end, or all of the busy - * extent, the overlapping portion can be made unbusy and used for the - * allocation. We can't split a busy extent because we can't modify a - * transaction/CIL context busy list, but we can update an entry's block - * number or length. - * - * Returns true if the extent can safely be reused, or false if the search - * needs to be restarted. - */ -STATIC bool -xfs_extent_busy_update_extent( - struct xfs_mount *mp, - struct xfs_perag *pag, - struct xfs_extent_busy *busyp, - xfs_agblock_t fbno, - xfs_extlen_t flen, - bool userdata) __releases(&pag->pagb_lock) - __acquires(&pag->pagb_lock) -{ - xfs_agblock_t fend = fbno + flen; - xfs_agblock_t bbno = busyp->bno; - xfs_agblock_t bend = bbno + busyp->length; - - /* - * This extent is currently being discarded. Give the thread - * performing the discard a chance to mark the extent unbusy - * and retry. - */ - if (busyp->flags & XFS_EXTENT_BUSY_DISCARDED) { - spin_unlock(&pag->pagb_lock); - delay(1); - spin_lock(&pag->pagb_lock); - return false; - } - - /* - * If there is a busy extent overlapping a user allocation, we have - * no choice but to force the log and retry the search. - * - * Fortunately this does not happen during normal operation, but - * only if the filesystem is very low on space and has to dip into - * the AGFL for normal allocations. - */ - if (userdata) - goto out_force_log; - - if (bbno < fbno && bend > fend) { - /* - * Case 1: - * bbno bend - * +BBBBBBBBBBBBBBBBB+ - * +---------+ - * fbno fend - */ - - /* - * We would have to split the busy extent to be able to track - * it correct, which we cannot do because we would have to - * modify the list of busy extents attached to the transaction - * or CIL context, which is immutable. - * - * Force out the log to clear the busy extent and retry the - * search. - */ - goto out_force_log; - } else if (bbno >= fbno && bend <= fend) { - /* - * Case 2: - * bbno bend - * +BBBBBBBBBBBBBBBBB+ - * +-----------------+ - * fbno fend - * - * Case 3: - * bbno bend - * +BBBBBBBBBBBBBBBBB+ - * +--------------------------+ - * fbno fend - * - * Case 4: - * bbno bend - * +BBBBBBBBBBBBBBBBB+ - * +--------------------------+ - * fbno fend - * - * Case 5: - * bbno bend - * +BBBBBBBBBBBBBBBBB+ - * +-----------------------------------+ - * fbno fend - * - */ - - /* - * The busy extent is fully covered by the extent we are - * allocating, and can simply be removed from the rbtree. - * However we cannot remove it from the immutable list - * tracking busy extents in the transaction or CIL context, - * so set the length to zero to mark it invalid. - * - * We also need to restart the busy extent search from the - * tree root, because erasing the node can rearrange the - * tree topology. - */ - rb_erase(&busyp->rb_node, &pag->pagb_tree); - busyp->length = 0; - return false; - } else if (fend < bend) { - /* - * Case 6: - * bbno bend - * +BBBBBBBBBBBBBBBBB+ - * +---------+ - * fbno fend - * - * Case 7: - * bbno bend - * +BBBBBBBBBBBBBBBBB+ - * +------------------+ - * fbno fend - * - */ - busyp->bno = fend; - } else if (bbno < fbno) { - /* - * Case 8: - * bbno bend - * +BBBBBBBBBBBBBBBBB+ - * +-------------+ - * fbno fend - * - * Case 9: - * bbno bend - * +BBBBBBBBBBBBBBBBB+ - * +----------------------+ - * fbno fend - */ - busyp->length = fbno - busyp->bno; - } else { - ASSERT(0); - } - - trace_xfs_extent_busy_reuse(mp, pag->pag_agno, fbno, flen); - return true; - -out_force_log: - spin_unlock(&pag->pagb_lock); - xfs_log_force(mp, XFS_LOG_SYNC); - trace_xfs_extent_busy_force(mp, pag->pag_agno, fbno, flen); - spin_lock(&pag->pagb_lock); - return false; -} - - -/* - * For a given extent [fbno, flen], make sure we can reuse it safely. - */ -void -xfs_extent_busy_reuse( - struct xfs_mount *mp, - xfs_agnumber_t agno, - xfs_agblock_t fbno, - xfs_extlen_t flen, - bool userdata) -{ - struct xfs_perag *pag; - struct rb_node *rbp; - - ASSERT(flen > 0); - - pag = xfs_perag_get(mp, agno); - spin_lock(&pag->pagb_lock); -restart: - rbp = pag->pagb_tree.rb_node; - while (rbp) { - struct xfs_extent_busy *busyp = - rb_entry(rbp, struct xfs_extent_busy, rb_node); - xfs_agblock_t bbno = busyp->bno; - xfs_agblock_t bend = bbno + busyp->length; - - if (fbno + flen <= bbno) { - rbp = rbp->rb_left; - continue; - } else if (fbno >= bend) { - rbp = rbp->rb_right; - continue; - } - - if (!xfs_extent_busy_update_extent(mp, pag, busyp, fbno, flen, - userdata)) - goto restart; - } - spin_unlock(&pag->pagb_lock); - xfs_perag_put(pag); -} - -/* - * For a given extent [fbno, flen], search the busy extent list to find a - * subset of the extent that is not busy. If *rlen is smaller than - * args->minlen no suitable extent could be found, and the higher level - * code needs to force out the log and retry the allocation. - */ -void -xfs_extent_busy_trim( - struct xfs_alloc_arg *args, - xfs_agblock_t bno, - xfs_extlen_t len, - xfs_agblock_t *rbno, - xfs_extlen_t *rlen) -{ - xfs_agblock_t fbno; - xfs_extlen_t flen; - struct rb_node *rbp; - - ASSERT(len > 0); - - spin_lock(&args->pag->pagb_lock); -restart: - fbno = bno; - flen = len; - rbp = args->pag->pagb_tree.rb_node; - while (rbp && flen >= args->minlen) { - struct xfs_extent_busy *busyp = - rb_entry(rbp, struct xfs_extent_busy, rb_node); - xfs_agblock_t fend = fbno + flen; - xfs_agblock_t bbno = busyp->bno; - xfs_agblock_t bend = bbno + busyp->length; - - if (fend <= bbno) { - rbp = rbp->rb_left; - continue; - } else if (fbno >= bend) { - rbp = rbp->rb_right; - continue; - } - - /* - * If this is a metadata allocation, try to reuse the busy - * extent instead of trimming the allocation. - */ - if (!xfs_alloc_is_userdata(args->datatype) && - !(busyp->flags & XFS_EXTENT_BUSY_DISCARDED)) { - if (!xfs_extent_busy_update_extent(args->mp, args->pag, - busyp, fbno, flen, - false)) - goto restart; - continue; - } - - if (bbno <= fbno) { - /* start overlap */ - - /* - * Case 1: - * bbno bend - * +BBBBBBBBBBBBBBBBB+ - * +---------+ - * fbno fend - * - * Case 2: - * bbno bend - * +BBBBBBBBBBBBBBBBB+ - * +-------------+ - * fbno fend - * - * Case 3: - * bbno bend - * +BBBBBBBBBBBBBBBBB+ - * +-------------+ - * fbno fend - * - * Case 4: - * bbno bend - * +BBBBBBBBBBBBBBBBB+ - * +-----------------+ - * fbno fend - * - * No unbusy region in extent, return failure. - */ - if (fend <= bend) - goto fail; - - /* - * Case 5: - * bbno bend - * +BBBBBBBBBBBBBBBBB+ - * +----------------------+ - * fbno fend - * - * Case 6: - * bbno bend - * +BBBBBBBBBBBBBBBBB+ - * +--------------------------+ - * fbno fend - * - * Needs to be trimmed to: - * +-------+ - * fbno fend - */ - fbno = bend; - } else if (bend >= fend) { - /* end overlap */ - - /* - * Case 7: - * bbno bend - * +BBBBBBBBBBBBBBBBB+ - * +------------------+ - * fbno fend - * - * Case 8: - * bbno bend - * +BBBBBBBBBBBBBBBBB+ - * +--------------------------+ - * fbno fend - * - * Needs to be trimmed to: - * +-------+ - * fbno fend - */ - fend = bbno; - } else { - /* middle overlap */ - - /* - * Case 9: - * bbno bend - * +BBBBBBBBBBBBBBBBB+ - * +-----------------------------------+ - * fbno fend - * - * Can be trimmed to: - * +-------+ OR +-------+ - * fbno fend fbno fend - * - * Backward allocation leads to significant - * fragmentation of directories, which degrades - * directory performance, therefore we always want to - * choose the option that produces forward allocation - * patterns. - * Preferring the lower bno extent will make the next - * request use "fend" as the start of the next - * allocation; if the segment is no longer busy at - * that point, we'll get a contiguous allocation, but - * even if it is still busy, we will get a forward - * allocation. - * We try to avoid choosing the segment at "bend", - * because that can lead to the next allocation - * taking the segment at "fbno", which would be a - * backward allocation. We only use the segment at - * "fbno" if it is much larger than the current - * requested size, because in that case there's a - * good chance subsequent allocations will be - * contiguous. - */ - if (bbno - fbno >= args->maxlen) { - /* left candidate fits perfect */ - fend = bbno; - } else if (fend - bend >= args->maxlen * 4) { - /* right candidate has enough free space */ - fbno = bend; - } else if (bbno - fbno >= args->minlen) { - /* left candidate fits minimum requirement */ - fend = bbno; - } else { - goto fail; - } - } - - flen = fend - fbno; - } - spin_unlock(&args->pag->pagb_lock); - - if (fbno != bno || flen != len) { - trace_xfs_extent_busy_trim(args->mp, args->agno, bno, len, - fbno, flen); - } - *rbno = fbno; - *rlen = flen; - return; -fail: - /* - * Return a zero extent length as failure indications. All callers - * re-check if the trimmed extent satisfies the minlen requirement. - */ - spin_unlock(&args->pag->pagb_lock); - trace_xfs_extent_busy_trim(args->mp, args->agno, bno, len, fbno, 0); - *rbno = fbno; - *rlen = 0; -} - -STATIC void -xfs_extent_busy_clear_one( - struct xfs_mount *mp, - struct xfs_perag *pag, - struct xfs_extent_busy *busyp) -{ - if (busyp->length) { - trace_xfs_extent_busy_clear(mp, busyp->agno, busyp->bno, - busyp->length); - rb_erase(&busyp->rb_node, &pag->pagb_tree); - } - - list_del_init(&busyp->list); - kmem_free(busyp); -} - -/* - * Remove all extents on the passed in list from the busy extents tree. - * If do_discard is set skip extents that need to be discarded, and mark - * these as undergoing a discard operation instead. - */ -void -xfs_extent_busy_clear( - struct xfs_mount *mp, - struct list_head *list, - bool do_discard) -{ - struct xfs_extent_busy *busyp, *n; - struct xfs_perag *pag = NULL; - xfs_agnumber_t agno = NULLAGNUMBER; - - list_for_each_entry_safe(busyp, n, list, list) { - if (busyp->agno != agno) { - if (pag) { - spin_unlock(&pag->pagb_lock); - xfs_perag_put(pag); - } - pag = xfs_perag_get(mp, busyp->agno); - spin_lock(&pag->pagb_lock); - agno = busyp->agno; - } - - if (do_discard && busyp->length && - !(busyp->flags & XFS_EXTENT_BUSY_SKIP_DISCARD)) - busyp->flags = XFS_EXTENT_BUSY_DISCARDED; - else - xfs_extent_busy_clear_one(mp, pag, busyp); - } - - if (pag) { - spin_unlock(&pag->pagb_lock); - xfs_perag_put(pag); - } -} - -/* - * Callback for list_sort to sort busy extents by the AG they reside in. - */ -int -xfs_extent_busy_ag_cmp( - void *priv, - struct list_head *a, - struct list_head *b) -{ - return container_of(a, struct xfs_extent_busy, list)->agno - - container_of(b, struct xfs_extent_busy, list)->agno; -} diff --git a/src/linux/fs/xfs/xfs_extent_busy.h b/src/linux/fs/xfs/xfs_extent_busy.h deleted file mode 100644 index bfff284..0000000 --- a/src/linux/fs/xfs/xfs_extent_busy.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. - * Copyright (c) 2010 David Chinner. - * Copyright (c) 2011 Christoph Hellwig. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_EXTENT_BUSY_H__ -#define __XFS_EXTENT_BUSY_H__ - -struct xfs_mount; -struct xfs_trans; -struct xfs_alloc_arg; - -/* - * Busy block/extent entry. Indexed by a rbtree in perag to mark blocks that - * have been freed but whose transactions aren't committed to disk yet. - * - * Note that we use the transaction ID to record the transaction, not the - * transaction structure itself. See xfs_extent_busy_insert() for details. - */ -struct xfs_extent_busy { - struct rb_node rb_node; /* ag by-bno indexed search tree */ - struct list_head list; /* transaction busy extent list */ - xfs_agnumber_t agno; - xfs_agblock_t bno; - xfs_extlen_t length; - unsigned int flags; -#define XFS_EXTENT_BUSY_DISCARDED 0x01 /* undergoing a discard op. */ -#define XFS_EXTENT_BUSY_SKIP_DISCARD 0x02 /* do not discard */ -}; - -void -xfs_extent_busy_insert(struct xfs_trans *tp, xfs_agnumber_t agno, - xfs_agblock_t bno, xfs_extlen_t len, unsigned int flags); - -void -xfs_extent_busy_clear(struct xfs_mount *mp, struct list_head *list, - bool do_discard); - -int -xfs_extent_busy_search(struct xfs_mount *mp, xfs_agnumber_t agno, - xfs_agblock_t bno, xfs_extlen_t len); - -void -xfs_extent_busy_reuse(struct xfs_mount *mp, xfs_agnumber_t agno, - xfs_agblock_t fbno, xfs_extlen_t flen, bool userdata); - -void -xfs_extent_busy_trim(struct xfs_alloc_arg *args, xfs_agblock_t bno, - xfs_extlen_t len, xfs_agblock_t *rbno, xfs_extlen_t *rlen); - -int -xfs_extent_busy_ag_cmp(void *priv, struct list_head *a, struct list_head *b); - -static inline void xfs_extent_busy_sort(struct list_head *list) -{ - list_sort(NULL, list, xfs_extent_busy_ag_cmp); -} - -#endif /* __XFS_EXTENT_BUSY_H__ */ diff --git a/src/linux/fs/xfs/xfs_extfree_item.c b/src/linux/fs/xfs/xfs_extfree_item.c deleted file mode 100644 index d7bc149..0000000 --- a/src/linux/fs/xfs/xfs_extfree_item.c +++ /dev/null @@ -1,557 +0,0 @@ -/* - * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_mount.h" -#include "xfs_trans.h" -#include "xfs_trans_priv.h" -#include "xfs_buf_item.h" -#include "xfs_extfree_item.h" -#include "xfs_log.h" -#include "xfs_btree.h" -#include "xfs_rmap.h" - - -kmem_zone_t *xfs_efi_zone; -kmem_zone_t *xfs_efd_zone; - -static inline struct xfs_efi_log_item *EFI_ITEM(struct xfs_log_item *lip) -{ - return container_of(lip, struct xfs_efi_log_item, efi_item); -} - -void -xfs_efi_item_free( - struct xfs_efi_log_item *efip) -{ - kmem_free(efip->efi_item.li_lv_shadow); - if (efip->efi_format.efi_nextents > XFS_EFI_MAX_FAST_EXTENTS) - kmem_free(efip); - else - kmem_zone_free(xfs_efi_zone, efip); -} - -/* - * This returns the number of iovecs needed to log the given efi item. - * We only need 1 iovec for an efi item. It just logs the efi_log_format - * structure. - */ -static inline int -xfs_efi_item_sizeof( - struct xfs_efi_log_item *efip) -{ - return sizeof(struct xfs_efi_log_format) + - (efip->efi_format.efi_nextents - 1) * sizeof(xfs_extent_t); -} - -STATIC void -xfs_efi_item_size( - struct xfs_log_item *lip, - int *nvecs, - int *nbytes) -{ - *nvecs += 1; - *nbytes += xfs_efi_item_sizeof(EFI_ITEM(lip)); -} - -/* - * This is called to fill in the vector of log iovecs for the - * given efi log item. We use only 1 iovec, and we point that - * at the efi_log_format structure embedded in the efi item. - * It is at this point that we assert that all of the extent - * slots in the efi item have been filled. - */ -STATIC void -xfs_efi_item_format( - struct xfs_log_item *lip, - struct xfs_log_vec *lv) -{ - struct xfs_efi_log_item *efip = EFI_ITEM(lip); - struct xfs_log_iovec *vecp = NULL; - - ASSERT(atomic_read(&efip->efi_next_extent) == - efip->efi_format.efi_nextents); - - efip->efi_format.efi_type = XFS_LI_EFI; - efip->efi_format.efi_size = 1; - - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_EFI_FORMAT, - &efip->efi_format, - xfs_efi_item_sizeof(efip)); -} - - -/* - * Pinning has no meaning for an efi item, so just return. - */ -STATIC void -xfs_efi_item_pin( - struct xfs_log_item *lip) -{ -} - -/* - * The unpin operation is the last place an EFI is manipulated in the log. It is - * either inserted in the AIL or aborted in the event of a log I/O error. In - * either case, the EFI transaction has been successfully committed to make it - * this far. Therefore, we expect whoever committed the EFI to either construct - * and commit the EFD or drop the EFD's reference in the event of error. Simply - * drop the log's EFI reference now that the log is done with it. - */ -STATIC void -xfs_efi_item_unpin( - struct xfs_log_item *lip, - int remove) -{ - struct xfs_efi_log_item *efip = EFI_ITEM(lip); - xfs_efi_release(efip); -} - -/* - * Efi items have no locking or pushing. However, since EFIs are pulled from - * the AIL when their corresponding EFDs are committed to disk, their situation - * is very similar to being pinned. Return XFS_ITEM_PINNED so that the caller - * will eventually flush the log. This should help in getting the EFI out of - * the AIL. - */ -STATIC uint -xfs_efi_item_push( - struct xfs_log_item *lip, - struct list_head *buffer_list) -{ - return XFS_ITEM_PINNED; -} - -/* - * The EFI has been either committed or aborted if the transaction has been - * cancelled. If the transaction was cancelled, an EFD isn't going to be - * constructed and thus we free the EFI here directly. - */ -STATIC void -xfs_efi_item_unlock( - struct xfs_log_item *lip) -{ - if (lip->li_flags & XFS_LI_ABORTED) - xfs_efi_item_free(EFI_ITEM(lip)); -} - -/* - * The EFI is logged only once and cannot be moved in the log, so simply return - * the lsn at which it's been logged. - */ -STATIC xfs_lsn_t -xfs_efi_item_committed( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ - return lsn; -} - -/* - * The EFI dependency tracking op doesn't do squat. It can't because - * it doesn't know where the free extent is coming from. The dependency - * tracking has to be handled by the "enclosing" metadata object. For - * example, for inodes, the inode is locked throughout the extent freeing - * so the dependency should be recorded there. - */ -STATIC void -xfs_efi_item_committing( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ -} - -/* - * This is the ops vector shared by all efi log items. - */ -static const struct xfs_item_ops xfs_efi_item_ops = { - .iop_size = xfs_efi_item_size, - .iop_format = xfs_efi_item_format, - .iop_pin = xfs_efi_item_pin, - .iop_unpin = xfs_efi_item_unpin, - .iop_unlock = xfs_efi_item_unlock, - .iop_committed = xfs_efi_item_committed, - .iop_push = xfs_efi_item_push, - .iop_committing = xfs_efi_item_committing -}; - - -/* - * Allocate and initialize an efi item with the given number of extents. - */ -struct xfs_efi_log_item * -xfs_efi_init( - struct xfs_mount *mp, - uint nextents) - -{ - struct xfs_efi_log_item *efip; - uint size; - - ASSERT(nextents > 0); - if (nextents > XFS_EFI_MAX_FAST_EXTENTS) { - size = (uint)(sizeof(xfs_efi_log_item_t) + - ((nextents - 1) * sizeof(xfs_extent_t))); - efip = kmem_zalloc(size, KM_SLEEP); - } else { - efip = kmem_zone_zalloc(xfs_efi_zone, KM_SLEEP); - } - - xfs_log_item_init(mp, &efip->efi_item, XFS_LI_EFI, &xfs_efi_item_ops); - efip->efi_format.efi_nextents = nextents; - efip->efi_format.efi_id = (uintptr_t)(void *)efip; - atomic_set(&efip->efi_next_extent, 0); - atomic_set(&efip->efi_refcount, 2); - - return efip; -} - -/* - * Copy an EFI format buffer from the given buf, and into the destination - * EFI format structure. - * The given buffer can be in 32 bit or 64 bit form (which has different padding), - * one of which will be the native format for this kernel. - * It will handle the conversion of formats if necessary. - */ -int -xfs_efi_copy_format(xfs_log_iovec_t *buf, xfs_efi_log_format_t *dst_efi_fmt) -{ - xfs_efi_log_format_t *src_efi_fmt = buf->i_addr; - uint i; - uint len = sizeof(xfs_efi_log_format_t) + - (src_efi_fmt->efi_nextents - 1) * sizeof(xfs_extent_t); - uint len32 = sizeof(xfs_efi_log_format_32_t) + - (src_efi_fmt->efi_nextents - 1) * sizeof(xfs_extent_32_t); - uint len64 = sizeof(xfs_efi_log_format_64_t) + - (src_efi_fmt->efi_nextents - 1) * sizeof(xfs_extent_64_t); - - if (buf->i_len == len) { - memcpy((char *)dst_efi_fmt, (char*)src_efi_fmt, len); - return 0; - } else if (buf->i_len == len32) { - xfs_efi_log_format_32_t *src_efi_fmt_32 = buf->i_addr; - - dst_efi_fmt->efi_type = src_efi_fmt_32->efi_type; - dst_efi_fmt->efi_size = src_efi_fmt_32->efi_size; - dst_efi_fmt->efi_nextents = src_efi_fmt_32->efi_nextents; - dst_efi_fmt->efi_id = src_efi_fmt_32->efi_id; - for (i = 0; i < dst_efi_fmt->efi_nextents; i++) { - dst_efi_fmt->efi_extents[i].ext_start = - src_efi_fmt_32->efi_extents[i].ext_start; - dst_efi_fmt->efi_extents[i].ext_len = - src_efi_fmt_32->efi_extents[i].ext_len; - } - return 0; - } else if (buf->i_len == len64) { - xfs_efi_log_format_64_t *src_efi_fmt_64 = buf->i_addr; - - dst_efi_fmt->efi_type = src_efi_fmt_64->efi_type; - dst_efi_fmt->efi_size = src_efi_fmt_64->efi_size; - dst_efi_fmt->efi_nextents = src_efi_fmt_64->efi_nextents; - dst_efi_fmt->efi_id = src_efi_fmt_64->efi_id; - for (i = 0; i < dst_efi_fmt->efi_nextents; i++) { - dst_efi_fmt->efi_extents[i].ext_start = - src_efi_fmt_64->efi_extents[i].ext_start; - dst_efi_fmt->efi_extents[i].ext_len = - src_efi_fmt_64->efi_extents[i].ext_len; - } - return 0; - } - return -EFSCORRUPTED; -} - -/* - * Freeing the efi requires that we remove it from the AIL if it has already - * been placed there. However, the EFI may not yet have been placed in the AIL - * when called by xfs_efi_release() from EFD processing due to the ordering of - * committed vs unpin operations in bulk insert operations. Hence the reference - * count to ensure only the last caller frees the EFI. - */ -void -xfs_efi_release( - struct xfs_efi_log_item *efip) -{ - if (atomic_dec_and_test(&efip->efi_refcount)) { - xfs_trans_ail_remove(&efip->efi_item, SHUTDOWN_LOG_IO_ERROR); - xfs_efi_item_free(efip); - } -} - -static inline struct xfs_efd_log_item *EFD_ITEM(struct xfs_log_item *lip) -{ - return container_of(lip, struct xfs_efd_log_item, efd_item); -} - -STATIC void -xfs_efd_item_free(struct xfs_efd_log_item *efdp) -{ - kmem_free(efdp->efd_item.li_lv_shadow); - if (efdp->efd_format.efd_nextents > XFS_EFD_MAX_FAST_EXTENTS) - kmem_free(efdp); - else - kmem_zone_free(xfs_efd_zone, efdp); -} - -/* - * This returns the number of iovecs needed to log the given efd item. - * We only need 1 iovec for an efd item. It just logs the efd_log_format - * structure. - */ -static inline int -xfs_efd_item_sizeof( - struct xfs_efd_log_item *efdp) -{ - return sizeof(xfs_efd_log_format_t) + - (efdp->efd_format.efd_nextents - 1) * sizeof(xfs_extent_t); -} - -STATIC void -xfs_efd_item_size( - struct xfs_log_item *lip, - int *nvecs, - int *nbytes) -{ - *nvecs += 1; - *nbytes += xfs_efd_item_sizeof(EFD_ITEM(lip)); -} - -/* - * This is called to fill in the vector of log iovecs for the - * given efd log item. We use only 1 iovec, and we point that - * at the efd_log_format structure embedded in the efd item. - * It is at this point that we assert that all of the extent - * slots in the efd item have been filled. - */ -STATIC void -xfs_efd_item_format( - struct xfs_log_item *lip, - struct xfs_log_vec *lv) -{ - struct xfs_efd_log_item *efdp = EFD_ITEM(lip); - struct xfs_log_iovec *vecp = NULL; - - ASSERT(efdp->efd_next_extent == efdp->efd_format.efd_nextents); - - efdp->efd_format.efd_type = XFS_LI_EFD; - efdp->efd_format.efd_size = 1; - - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_EFD_FORMAT, - &efdp->efd_format, - xfs_efd_item_sizeof(efdp)); -} - -/* - * Pinning has no meaning for an efd item, so just return. - */ -STATIC void -xfs_efd_item_pin( - struct xfs_log_item *lip) -{ -} - -/* - * Since pinning has no meaning for an efd item, unpinning does - * not either. - */ -STATIC void -xfs_efd_item_unpin( - struct xfs_log_item *lip, - int remove) -{ -} - -/* - * There isn't much you can do to push on an efd item. It is simply stuck - * waiting for the log to be flushed to disk. - */ -STATIC uint -xfs_efd_item_push( - struct xfs_log_item *lip, - struct list_head *buffer_list) -{ - return XFS_ITEM_PINNED; -} - -/* - * The EFD is either committed or aborted if the transaction is cancelled. If - * the transaction is cancelled, drop our reference to the EFI and free the EFD. - */ -STATIC void -xfs_efd_item_unlock( - struct xfs_log_item *lip) -{ - struct xfs_efd_log_item *efdp = EFD_ITEM(lip); - - if (lip->li_flags & XFS_LI_ABORTED) { - xfs_efi_release(efdp->efd_efip); - xfs_efd_item_free(efdp); - } -} - -/* - * When the efd item is committed to disk, all we need to do is delete our - * reference to our partner efi item and then free ourselves. Since we're - * freeing ourselves we must return -1 to keep the transaction code from further - * referencing this item. - */ -STATIC xfs_lsn_t -xfs_efd_item_committed( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ - struct xfs_efd_log_item *efdp = EFD_ITEM(lip); - - /* - * Drop the EFI reference regardless of whether the EFD has been - * aborted. Once the EFD transaction is constructed, it is the sole - * responsibility of the EFD to release the EFI (even if the EFI is - * aborted due to log I/O error). - */ - xfs_efi_release(efdp->efd_efip); - xfs_efd_item_free(efdp); - - return (xfs_lsn_t)-1; -} - -/* - * The EFD dependency tracking op doesn't do squat. It can't because - * it doesn't know where the free extent is coming from. The dependency - * tracking has to be handled by the "enclosing" metadata object. For - * example, for inodes, the inode is locked throughout the extent freeing - * so the dependency should be recorded there. - */ -STATIC void -xfs_efd_item_committing( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ -} - -/* - * This is the ops vector shared by all efd log items. - */ -static const struct xfs_item_ops xfs_efd_item_ops = { - .iop_size = xfs_efd_item_size, - .iop_format = xfs_efd_item_format, - .iop_pin = xfs_efd_item_pin, - .iop_unpin = xfs_efd_item_unpin, - .iop_unlock = xfs_efd_item_unlock, - .iop_committed = xfs_efd_item_committed, - .iop_push = xfs_efd_item_push, - .iop_committing = xfs_efd_item_committing -}; - -/* - * Allocate and initialize an efd item with the given number of extents. - */ -struct xfs_efd_log_item * -xfs_efd_init( - struct xfs_mount *mp, - struct xfs_efi_log_item *efip, - uint nextents) - -{ - struct xfs_efd_log_item *efdp; - uint size; - - ASSERT(nextents > 0); - if (nextents > XFS_EFD_MAX_FAST_EXTENTS) { - size = (uint)(sizeof(xfs_efd_log_item_t) + - ((nextents - 1) * sizeof(xfs_extent_t))); - efdp = kmem_zalloc(size, KM_SLEEP); - } else { - efdp = kmem_zone_zalloc(xfs_efd_zone, KM_SLEEP); - } - - xfs_log_item_init(mp, &efdp->efd_item, XFS_LI_EFD, &xfs_efd_item_ops); - efdp->efd_efip = efip; - efdp->efd_format.efd_nextents = nextents; - efdp->efd_format.efd_efi_id = efip->efi_format.efi_id; - - return efdp; -} - -/* - * Process an extent free intent item that was recovered from - * the log. We need to free the extents that it describes. - */ -int -xfs_efi_recover( - struct xfs_mount *mp, - struct xfs_efi_log_item *efip) -{ - struct xfs_efd_log_item *efdp; - struct xfs_trans *tp; - int i; - int error = 0; - xfs_extent_t *extp; - xfs_fsblock_t startblock_fsb; - struct xfs_owner_info oinfo; - - ASSERT(!test_bit(XFS_EFI_RECOVERED, &efip->efi_flags)); - - /* - * First check the validity of the extents described by the - * EFI. If any are bad, then assume that all are bad and - * just toss the EFI. - */ - for (i = 0; i < efip->efi_format.efi_nextents; i++) { - extp = &efip->efi_format.efi_extents[i]; - startblock_fsb = XFS_BB_TO_FSB(mp, - XFS_FSB_TO_DADDR(mp, extp->ext_start)); - if (startblock_fsb == 0 || - extp->ext_len == 0 || - startblock_fsb >= mp->m_sb.sb_dblocks || - extp->ext_len >= mp->m_sb.sb_agblocks) { - /* - * This will pull the EFI from the AIL and - * free the memory associated with it. - */ - set_bit(XFS_EFI_RECOVERED, &efip->efi_flags); - xfs_efi_release(efip); - return -EIO; - } - } - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp); - if (error) - return error; - efdp = xfs_trans_get_efd(tp, efip, efip->efi_format.efi_nextents); - - xfs_rmap_skip_owner_update(&oinfo); - for (i = 0; i < efip->efi_format.efi_nextents; i++) { - extp = &efip->efi_format.efi_extents[i]; - error = xfs_trans_free_extent(tp, efdp, extp->ext_start, - extp->ext_len, &oinfo); - if (error) - goto abort_error; - - } - - set_bit(XFS_EFI_RECOVERED, &efip->efi_flags); - error = xfs_trans_commit(tp); - return error; - -abort_error: - xfs_trans_cancel(tp); - return error; -} diff --git a/src/linux/fs/xfs/xfs_extfree_item.h b/src/linux/fs/xfs/xfs_extfree_item.h deleted file mode 100644 index a32c794..0000000 --- a/src/linux/fs/xfs/xfs_extfree_item.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2000,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_EXTFREE_ITEM_H__ -#define __XFS_EXTFREE_ITEM_H__ - -/* kernel only EFI/EFD definitions */ - -struct xfs_mount; -struct kmem_zone; - -/* - * Max number of extents in fast allocation path. - */ -#define XFS_EFI_MAX_FAST_EXTENTS 16 - -/* - * Define EFI flag bits. Manipulated by set/clear/test_bit operators. - */ -#define XFS_EFI_RECOVERED 1 - -/* - * This is the "extent free intention" log item. It is used to log the fact - * that some extents need to be free. It is used in conjunction with the - * "extent free done" log item described below. - * - * The EFI is reference counted so that it is not freed prior to both the EFI - * and EFD being committed and unpinned. This ensures the EFI is inserted into - * the AIL even in the event of out of order EFI/EFD processing. In other words, - * an EFI is born with two references: - * - * 1.) an EFI held reference to track EFI AIL insertion - * 2.) an EFD held reference to track EFD commit - * - * On allocation, both references are the responsibility of the caller. Once the - * EFI is added to and dirtied in a transaction, ownership of reference one - * transfers to the transaction. The reference is dropped once the EFI is - * inserted to the AIL or in the event of failure along the way (e.g., commit - * failure, log I/O error, etc.). Note that the caller remains responsible for - * the EFD reference under all circumstances to this point. The caller has no - * means to detect failure once the transaction is committed, however. - * Therefore, an EFD is required after this point, even in the event of - * unrelated failure. - * - * Once an EFD is allocated and dirtied in a transaction, reference two - * transfers to the transaction. The EFD reference is dropped once it reaches - * the unpin handler. Similar to the EFI, the reference also drops in the event - * of commit failure or log I/O errors. Note that the EFD is not inserted in the - * AIL, so at this point both the EFI and EFD are freed. - */ -typedef struct xfs_efi_log_item { - xfs_log_item_t efi_item; - atomic_t efi_refcount; - atomic_t efi_next_extent; - unsigned long efi_flags; /* misc flags */ - xfs_efi_log_format_t efi_format; -} xfs_efi_log_item_t; - -/* - * This is the "extent free done" log item. It is used to log - * the fact that some extents earlier mentioned in an efi item - * have been freed. - */ -typedef struct xfs_efd_log_item { - xfs_log_item_t efd_item; - xfs_efi_log_item_t *efd_efip; - uint efd_next_extent; - xfs_efd_log_format_t efd_format; -} xfs_efd_log_item_t; - -/* - * Max number of extents in fast allocation path. - */ -#define XFS_EFD_MAX_FAST_EXTENTS 16 - -extern struct kmem_zone *xfs_efi_zone; -extern struct kmem_zone *xfs_efd_zone; - -xfs_efi_log_item_t *xfs_efi_init(struct xfs_mount *, uint); -xfs_efd_log_item_t *xfs_efd_init(struct xfs_mount *, xfs_efi_log_item_t *, - uint); -int xfs_efi_copy_format(xfs_log_iovec_t *buf, - xfs_efi_log_format_t *dst_efi_fmt); -void xfs_efi_item_free(xfs_efi_log_item_t *); -void xfs_efi_release(struct xfs_efi_log_item *); - -int xfs_efi_recover(struct xfs_mount *mp, - struct xfs_efi_log_item *efip); - -#endif /* __XFS_EXTFREE_ITEM_H__ */ diff --git a/src/linux/fs/xfs/xfs_file.c b/src/linux/fs/xfs/xfs_file.c deleted file mode 100644 index 6e4f7f9..0000000 --- a/src/linux/fs/xfs/xfs_file.c +++ /dev/null @@ -1,1643 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_bmap.h" -#include "xfs_bmap_util.h" -#include "xfs_error.h" -#include "xfs_dir2.h" -#include "xfs_dir2_priv.h" -#include "xfs_ioctl.h" -#include "xfs_trace.h" -#include "xfs_log.h" -#include "xfs_icache.h" -#include "xfs_pnfs.h" -#include "xfs_iomap.h" -#include "xfs_reflink.h" - -#include -#include -#include -#include - -static const struct vm_operations_struct xfs_file_vm_ops; - -/* - * Locking primitives for read and write IO paths to ensure we consistently use - * and order the inode->i_mutex, ip->i_lock and ip->i_iolock. - */ -static inline void -xfs_rw_ilock( - struct xfs_inode *ip, - int type) -{ - if (type & XFS_IOLOCK_EXCL) - inode_lock(VFS_I(ip)); - xfs_ilock(ip, type); -} - -static inline void -xfs_rw_iunlock( - struct xfs_inode *ip, - int type) -{ - xfs_iunlock(ip, type); - if (type & XFS_IOLOCK_EXCL) - inode_unlock(VFS_I(ip)); -} - -static inline void -xfs_rw_ilock_demote( - struct xfs_inode *ip, - int type) -{ - xfs_ilock_demote(ip, type); - if (type & XFS_IOLOCK_EXCL) - inode_unlock(VFS_I(ip)); -} - -/* - * Clear the specified ranges to zero through either the pagecache or DAX. - * Holes and unwritten extents will be left as-is as they already are zeroed. - */ -int -xfs_zero_range( - struct xfs_inode *ip, - xfs_off_t pos, - xfs_off_t count, - bool *did_zero) -{ - return iomap_zero_range(VFS_I(ip), pos, count, NULL, &xfs_iomap_ops); -} - -int -xfs_update_prealloc_flags( - struct xfs_inode *ip, - enum xfs_prealloc_flags flags) -{ - struct xfs_trans *tp; - int error; - - error = xfs_trans_alloc(ip->i_mount, &M_RES(ip->i_mount)->tr_writeid, - 0, 0, 0, &tp); - if (error) - return error; - - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); - - if (!(flags & XFS_PREALLOC_INVISIBLE)) { - VFS_I(ip)->i_mode &= ~S_ISUID; - if (VFS_I(ip)->i_mode & S_IXGRP) - VFS_I(ip)->i_mode &= ~S_ISGID; - xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); - } - - if (flags & XFS_PREALLOC_SET) - ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC; - if (flags & XFS_PREALLOC_CLEAR) - ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC; - - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - if (flags & XFS_PREALLOC_SYNC) - xfs_trans_set_sync(tp); - return xfs_trans_commit(tp); -} - -/* - * Fsync operations on directories are much simpler than on regular files, - * as there is no file data to flush, and thus also no need for explicit - * cache flush operations, and there are no non-transaction metadata updates - * on directories either. - */ -STATIC int -xfs_dir_fsync( - struct file *file, - loff_t start, - loff_t end, - int datasync) -{ - struct xfs_inode *ip = XFS_I(file->f_mapping->host); - struct xfs_mount *mp = ip->i_mount; - xfs_lsn_t lsn = 0; - - trace_xfs_dir_fsync(ip); - - xfs_ilock(ip, XFS_ILOCK_SHARED); - if (xfs_ipincount(ip)) - lsn = ip->i_itemp->ili_last_lsn; - xfs_iunlock(ip, XFS_ILOCK_SHARED); - - if (!lsn) - return 0; - return _xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, NULL); -} - -STATIC int -xfs_file_fsync( - struct file *file, - loff_t start, - loff_t end, - int datasync) -{ - struct inode *inode = file->f_mapping->host; - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; - int error = 0; - int log_flushed = 0; - xfs_lsn_t lsn = 0; - - trace_xfs_file_fsync(ip); - - error = filemap_write_and_wait_range(inode->i_mapping, start, end); - if (error) - return error; - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - xfs_iflags_clear(ip, XFS_ITRUNCATED); - - if (mp->m_flags & XFS_MOUNT_BARRIER) { - /* - * If we have an RT and/or log subvolume we need to make sure - * to flush the write cache the device used for file data - * first. This is to ensure newly written file data make - * it to disk before logging the new inode size in case of - * an extending write. - */ - if (XFS_IS_REALTIME_INODE(ip)) - xfs_blkdev_issue_flush(mp->m_rtdev_targp); - else if (mp->m_logdev_targp != mp->m_ddev_targp) - xfs_blkdev_issue_flush(mp->m_ddev_targp); - } - - /* - * All metadata updates are logged, which means that we just have to - * flush the log up to the latest LSN that touched the inode. If we have - * concurrent fsync/fdatasync() calls, we need them to all block on the - * log force before we clear the ili_fsync_fields field. This ensures - * that we don't get a racing sync operation that does not wait for the - * metadata to hit the journal before returning. If we race with - * clearing the ili_fsync_fields, then all that will happen is the log - * force will do nothing as the lsn will already be on disk. We can't - * race with setting ili_fsync_fields because that is done under - * XFS_ILOCK_EXCL, and that can't happen because we hold the lock shared - * until after the ili_fsync_fields is cleared. - */ - xfs_ilock(ip, XFS_ILOCK_SHARED); - if (xfs_ipincount(ip)) { - if (!datasync || - (ip->i_itemp->ili_fsync_fields & ~XFS_ILOG_TIMESTAMP)) - lsn = ip->i_itemp->ili_last_lsn; - } - - if (lsn) { - error = _xfs_log_force_lsn(mp, lsn, XFS_LOG_SYNC, &log_flushed); - ip->i_itemp->ili_fsync_fields = 0; - } - xfs_iunlock(ip, XFS_ILOCK_SHARED); - - /* - * If we only have a single device, and the log force about was - * a no-op we might have to flush the data device cache here. - * This can only happen for fdatasync/O_DSYNC if we were overwriting - * an already allocated file and thus do not have any metadata to - * commit. - */ - if ((mp->m_flags & XFS_MOUNT_BARRIER) && - mp->m_logdev_targp == mp->m_ddev_targp && - !XFS_IS_REALTIME_INODE(ip) && - !log_flushed) - xfs_blkdev_issue_flush(mp->m_ddev_targp); - - return error; -} - -STATIC ssize_t -xfs_file_dio_aio_read( - struct kiocb *iocb, - struct iov_iter *to) -{ - struct address_space *mapping = iocb->ki_filp->f_mapping; - struct inode *inode = mapping->host; - struct xfs_inode *ip = XFS_I(inode); - loff_t isize = i_size_read(inode); - size_t count = iov_iter_count(to); - loff_t end = iocb->ki_pos + count - 1; - struct iov_iter data; - struct xfs_buftarg *target; - ssize_t ret = 0; - - trace_xfs_file_direct_read(ip, count, iocb->ki_pos); - - if (!count) - return 0; /* skip atime */ - - if (XFS_IS_REALTIME_INODE(ip)) - target = ip->i_mount->m_rtdev_targp; - else - target = ip->i_mount->m_ddev_targp; - - /* DIO must be aligned to device logical sector size */ - if ((iocb->ki_pos | count) & target->bt_logical_sectormask) { - if (iocb->ki_pos == isize) - return 0; - return -EINVAL; - } - - file_accessed(iocb->ki_filp); - - xfs_rw_ilock(ip, XFS_IOLOCK_SHARED); - if (mapping->nrpages) { - ret = filemap_write_and_wait_range(mapping, iocb->ki_pos, end); - if (ret) - goto out_unlock; - - /* - * Invalidate whole pages. This can return an error if we fail - * to invalidate a page, but this should never happen on XFS. - * Warn if it does fail. - */ - ret = invalidate_inode_pages2_range(mapping, - iocb->ki_pos >> PAGE_SHIFT, end >> PAGE_SHIFT); - WARN_ON_ONCE(ret); - ret = 0; - } - - data = *to; - ret = __blockdev_direct_IO(iocb, inode, target->bt_bdev, &data, - xfs_get_blocks_direct, NULL, NULL, 0); - if (ret >= 0) { - iocb->ki_pos += ret; - iov_iter_advance(to, ret); - } - -out_unlock: - xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED); - return ret; -} - -static noinline ssize_t -xfs_file_dax_read( - struct kiocb *iocb, - struct iov_iter *to) -{ - struct xfs_inode *ip = XFS_I(iocb->ki_filp->f_mapping->host); - size_t count = iov_iter_count(to); - ssize_t ret = 0; - - trace_xfs_file_dax_read(ip, count, iocb->ki_pos); - - if (!count) - return 0; /* skip atime */ - - xfs_rw_ilock(ip, XFS_IOLOCK_SHARED); - ret = iomap_dax_rw(iocb, to, &xfs_iomap_ops); - xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED); - - file_accessed(iocb->ki_filp); - return ret; -} - -STATIC ssize_t -xfs_file_buffered_aio_read( - struct kiocb *iocb, - struct iov_iter *to) -{ - struct xfs_inode *ip = XFS_I(file_inode(iocb->ki_filp)); - ssize_t ret; - - trace_xfs_file_buffered_read(ip, iov_iter_count(to), iocb->ki_pos); - - xfs_rw_ilock(ip, XFS_IOLOCK_SHARED); - ret = generic_file_read_iter(iocb, to); - xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED); - - return ret; -} - -STATIC ssize_t -xfs_file_read_iter( - struct kiocb *iocb, - struct iov_iter *to) -{ - struct inode *inode = file_inode(iocb->ki_filp); - struct xfs_mount *mp = XFS_I(inode)->i_mount; - ssize_t ret = 0; - - XFS_STATS_INC(mp, xs_read_calls); - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - if (IS_DAX(inode)) - ret = xfs_file_dax_read(iocb, to); - else if (iocb->ki_flags & IOCB_DIRECT) - ret = xfs_file_dio_aio_read(iocb, to); - else - ret = xfs_file_buffered_aio_read(iocb, to); - - if (ret > 0) - XFS_STATS_ADD(mp, xs_read_bytes, ret); - return ret; -} - -/* - * Zero any on disk space between the current EOF and the new, larger EOF. - * - * This handles the normal case of zeroing the remainder of the last block in - * the file and the unusual case of zeroing blocks out beyond the size of the - * file. This second case only happens with fixed size extents and when the - * system crashes before the inode size was updated but after blocks were - * allocated. - * - * Expects the iolock to be held exclusive, and will take the ilock internally. - */ -int /* error (positive) */ -xfs_zero_eof( - struct xfs_inode *ip, - xfs_off_t offset, /* starting I/O offset */ - xfs_fsize_t isize, /* current inode size */ - bool *did_zeroing) -{ - ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); - ASSERT(offset > isize); - - trace_xfs_zero_eof(ip, isize, offset - isize); - return xfs_zero_range(ip, isize, offset - isize, did_zeroing); -} - -/* - * Common pre-write limit and setup checks. - * - * Called with the iolocked held either shared and exclusive according to - * @iolock, and returns with it held. Might upgrade the iolock to exclusive - * if called for a direct write beyond i_size. - */ -STATIC ssize_t -xfs_file_aio_write_checks( - struct kiocb *iocb, - struct iov_iter *from, - int *iolock) -{ - struct file *file = iocb->ki_filp; - struct inode *inode = file->f_mapping->host; - struct xfs_inode *ip = XFS_I(inode); - ssize_t error = 0; - size_t count = iov_iter_count(from); - bool drained_dio = false; - -restart: - error = generic_write_checks(iocb, from); - if (error <= 0) - return error; - - error = xfs_break_layouts(inode, iolock, true); - if (error) - return error; - - /* For changing security info in file_remove_privs() we need i_mutex */ - if (*iolock == XFS_IOLOCK_SHARED && !IS_NOSEC(inode)) { - xfs_rw_iunlock(ip, *iolock); - *iolock = XFS_IOLOCK_EXCL; - xfs_rw_ilock(ip, *iolock); - goto restart; - } - /* - * If the offset is beyond the size of the file, we need to zero any - * blocks that fall between the existing EOF and the start of this - * write. If zeroing is needed and we are currently holding the - * iolock shared, we need to update it to exclusive which implies - * having to redo all checks before. - * - * We need to serialise against EOF updates that occur in IO - * completions here. We want to make sure that nobody is changing the - * size while we do this check until we have placed an IO barrier (i.e. - * hold the XFS_IOLOCK_EXCL) that prevents new IO from being dispatched. - * The spinlock effectively forms a memory barrier once we have the - * XFS_IOLOCK_EXCL so we are guaranteed to see the latest EOF value - * and hence be able to correctly determine if we need to run zeroing. - */ - spin_lock(&ip->i_flags_lock); - if (iocb->ki_pos > i_size_read(inode)) { - bool zero = false; - - spin_unlock(&ip->i_flags_lock); - if (!drained_dio) { - if (*iolock == XFS_IOLOCK_SHARED) { - xfs_rw_iunlock(ip, *iolock); - *iolock = XFS_IOLOCK_EXCL; - xfs_rw_ilock(ip, *iolock); - iov_iter_reexpand(from, count); - } - /* - * We now have an IO submission barrier in place, but - * AIO can do EOF updates during IO completion and hence - * we now need to wait for all of them to drain. Non-AIO - * DIO will have drained before we are given the - * XFS_IOLOCK_EXCL, and so for most cases this wait is a - * no-op. - */ - inode_dio_wait(inode); - drained_dio = true; - goto restart; - } - error = xfs_zero_eof(ip, iocb->ki_pos, i_size_read(inode), &zero); - if (error) - return error; - } else - spin_unlock(&ip->i_flags_lock); - - /* - * Updating the timestamps will grab the ilock again from - * xfs_fs_dirty_inode, so we have to call it after dropping the - * lock above. Eventually we should look into a way to avoid - * the pointless lock roundtrip. - */ - if (likely(!(file->f_mode & FMODE_NOCMTIME))) { - error = file_update_time(file); - if (error) - return error; - } - - /* - * If we're writing the file then make sure to clear the setuid and - * setgid bits if the process is not being run by root. This keeps - * people from modifying setuid and setgid binaries. - */ - if (!IS_NOSEC(inode)) - return file_remove_privs(file); - return 0; -} - -/* - * xfs_file_dio_aio_write - handle direct IO writes - * - * Lock the inode appropriately to prepare for and issue a direct IO write. - * By separating it from the buffered write path we remove all the tricky to - * follow locking changes and looping. - * - * If there are cached pages or we're extending the file, we need IOLOCK_EXCL - * until we're sure the bytes at the new EOF have been zeroed and/or the cached - * pages are flushed out. - * - * In most cases the direct IO writes will be done holding IOLOCK_SHARED - * allowing them to be done in parallel with reads and other direct IO writes. - * However, if the IO is not aligned to filesystem blocks, the direct IO layer - * needs to do sub-block zeroing and that requires serialisation against other - * direct IOs to the same block. In this case we need to serialise the - * submission of the unaligned IOs so that we don't get racing block zeroing in - * the dio layer. To avoid the problem with aio, we also need to wait for - * outstanding IOs to complete so that unwritten extent conversion is completed - * before we try to map the overlapping block. This is currently implemented by - * hitting it with a big hammer (i.e. inode_dio_wait()). - * - * Returns with locks held indicated by @iolock and errors indicated by - * negative return values. - */ -STATIC ssize_t -xfs_file_dio_aio_write( - struct kiocb *iocb, - struct iov_iter *from) -{ - struct file *file = iocb->ki_filp; - struct address_space *mapping = file->f_mapping; - struct inode *inode = mapping->host; - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; - ssize_t ret = 0; - int unaligned_io = 0; - int iolock; - size_t count = iov_iter_count(from); - loff_t end; - struct iov_iter data; - struct xfs_buftarg *target = XFS_IS_REALTIME_INODE(ip) ? - mp->m_rtdev_targp : mp->m_ddev_targp; - - /* DIO must be aligned to device logical sector size */ - if ((iocb->ki_pos | count) & target->bt_logical_sectormask) - return -EINVAL; - - /* - * Don't take the exclusive iolock here unless the I/O is unaligned to - * the file system block size. We don't need to consider the EOF - * extension case here because xfs_file_aio_write_checks() will relock - * the inode as necessary for EOF zeroing cases and fill out the new - * inode size as appropriate. - */ - if ((iocb->ki_pos & mp->m_blockmask) || - ((iocb->ki_pos + count) & mp->m_blockmask)) { - unaligned_io = 1; - iolock = XFS_IOLOCK_EXCL; - } else { - iolock = XFS_IOLOCK_SHARED; - } - - xfs_rw_ilock(ip, iolock); - - ret = xfs_file_aio_write_checks(iocb, from, &iolock); - if (ret) - goto out; - count = iov_iter_count(from); - end = iocb->ki_pos + count - 1; - - if (mapping->nrpages) { - ret = filemap_write_and_wait_range(mapping, iocb->ki_pos, end); - if (ret) - goto out; - - /* - * Invalidate whole pages. This can return an error if we fail - * to invalidate a page, but this should never happen on XFS. - * Warn if it does fail. - */ - ret = invalidate_inode_pages2_range(mapping, - iocb->ki_pos >> PAGE_SHIFT, end >> PAGE_SHIFT); - WARN_ON_ONCE(ret); - ret = 0; - } - - /* - * If we are doing unaligned IO, wait for all other IO to drain, - * otherwise demote the lock if we had to take the exclusive lock - * for other reasons in xfs_file_aio_write_checks. - */ - if (unaligned_io) - inode_dio_wait(inode); - else if (iolock == XFS_IOLOCK_EXCL) { - xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL); - iolock = XFS_IOLOCK_SHARED; - } - - trace_xfs_file_direct_write(ip, count, iocb->ki_pos); - - /* If this is a block-aligned directio CoW, remap immediately. */ - if (xfs_is_reflink_inode(ip) && !unaligned_io) { - ret = xfs_reflink_allocate_cow_range(ip, iocb->ki_pos, count); - if (ret) - goto out; - } - - data = *from; - ret = __blockdev_direct_IO(iocb, inode, target->bt_bdev, &data, - xfs_get_blocks_direct, xfs_end_io_direct_write, - NULL, DIO_ASYNC_EXTEND); - - /* see generic_file_direct_write() for why this is necessary */ - if (mapping->nrpages) { - invalidate_inode_pages2_range(mapping, - iocb->ki_pos >> PAGE_SHIFT, - end >> PAGE_SHIFT); - } - - if (ret > 0) { - iocb->ki_pos += ret; - iov_iter_advance(from, ret); - } -out: - xfs_rw_iunlock(ip, iolock); - - /* - * No fallback to buffered IO on errors for XFS, direct IO will either - * complete fully or fail. - */ - ASSERT(ret < 0 || ret == count); - return ret; -} - -static noinline ssize_t -xfs_file_dax_write( - struct kiocb *iocb, - struct iov_iter *from) -{ - struct inode *inode = iocb->ki_filp->f_mapping->host; - struct xfs_inode *ip = XFS_I(inode); - int iolock = XFS_IOLOCK_EXCL; - ssize_t ret, error = 0; - size_t count; - loff_t pos; - - xfs_rw_ilock(ip, iolock); - ret = xfs_file_aio_write_checks(iocb, from, &iolock); - if (ret) - goto out; - - pos = iocb->ki_pos; - count = iov_iter_count(from); - - trace_xfs_file_dax_write(ip, count, pos); - - ret = iomap_dax_rw(iocb, from, &xfs_iomap_ops); - if (ret > 0 && iocb->ki_pos > i_size_read(inode)) { - i_size_write(inode, iocb->ki_pos); - error = xfs_setfilesize(ip, pos, ret); - } - -out: - xfs_rw_iunlock(ip, iolock); - return error ? error : ret; -} - -STATIC ssize_t -xfs_file_buffered_aio_write( - struct kiocb *iocb, - struct iov_iter *from) -{ - struct file *file = iocb->ki_filp; - struct address_space *mapping = file->f_mapping; - struct inode *inode = mapping->host; - struct xfs_inode *ip = XFS_I(inode); - ssize_t ret; - int enospc = 0; - int iolock = XFS_IOLOCK_EXCL; - - xfs_rw_ilock(ip, iolock); - - ret = xfs_file_aio_write_checks(iocb, from, &iolock); - if (ret) - goto out; - - /* We can write back this queue in page reclaim */ - current->backing_dev_info = inode_to_bdi(inode); - -write_retry: - trace_xfs_file_buffered_write(ip, iov_iter_count(from), iocb->ki_pos); - ret = iomap_file_buffered_write(iocb, from, &xfs_iomap_ops); - if (likely(ret >= 0)) - iocb->ki_pos += ret; - - /* - * If we hit a space limit, try to free up some lingering preallocated - * space before returning an error. In the case of ENOSPC, first try to - * write back all dirty inodes to free up some of the excess reserved - * metadata space. This reduces the chances that the eofblocks scan - * waits on dirty mappings. Since xfs_flush_inodes() is serialized, this - * also behaves as a filter to prevent too many eofblocks scans from - * running at the same time. - */ - if (ret == -EDQUOT && !enospc) { - enospc = xfs_inode_free_quota_eofblocks(ip); - if (enospc) - goto write_retry; - enospc = xfs_inode_free_quota_cowblocks(ip); - if (enospc) - goto write_retry; - } else if (ret == -ENOSPC && !enospc) { - struct xfs_eofblocks eofb = {0}; - - enospc = 1; - xfs_flush_inodes(ip->i_mount); - eofb.eof_scan_owner = ip->i_ino; /* for locking */ - eofb.eof_flags = XFS_EOF_FLAGS_SYNC; - xfs_icache_free_eofblocks(ip->i_mount, &eofb); - goto write_retry; - } - - current->backing_dev_info = NULL; -out: - xfs_rw_iunlock(ip, iolock); - return ret; -} - -STATIC ssize_t -xfs_file_write_iter( - struct kiocb *iocb, - struct iov_iter *from) -{ - struct file *file = iocb->ki_filp; - struct address_space *mapping = file->f_mapping; - struct inode *inode = mapping->host; - struct xfs_inode *ip = XFS_I(inode); - ssize_t ret; - size_t ocount = iov_iter_count(from); - - XFS_STATS_INC(ip->i_mount, xs_write_calls); - - if (ocount == 0) - return 0; - - if (XFS_FORCED_SHUTDOWN(ip->i_mount)) - return -EIO; - - if (IS_DAX(inode)) - ret = xfs_file_dax_write(iocb, from); - else if (iocb->ki_flags & IOCB_DIRECT) { - /* - * Allow a directio write to fall back to a buffered - * write *only* in the case that we're doing a reflink - * CoW. In all other directio scenarios we do not - * allow an operation to fall back to buffered mode. - */ - ret = xfs_file_dio_aio_write(iocb, from); - if (ret == -EREMCHG) - goto buffered; - } else { -buffered: - ret = xfs_file_buffered_aio_write(iocb, from); - } - - if (ret > 0) { - XFS_STATS_ADD(ip->i_mount, xs_write_bytes, ret); - - /* Handle various SYNC-type writes */ - ret = generic_write_sync(iocb, ret); - } - return ret; -} - -#define XFS_FALLOC_FL_SUPPORTED \ - (FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE | \ - FALLOC_FL_COLLAPSE_RANGE | FALLOC_FL_ZERO_RANGE | \ - FALLOC_FL_INSERT_RANGE | FALLOC_FL_UNSHARE_RANGE) - -STATIC long -xfs_file_fallocate( - struct file *file, - int mode, - loff_t offset, - loff_t len) -{ - struct inode *inode = file_inode(file); - struct xfs_inode *ip = XFS_I(inode); - long error; - enum xfs_prealloc_flags flags = 0; - uint iolock = XFS_IOLOCK_EXCL; - loff_t new_size = 0; - bool do_file_insert = 0; - - if (!S_ISREG(inode->i_mode)) - return -EINVAL; - if (mode & ~XFS_FALLOC_FL_SUPPORTED) - return -EOPNOTSUPP; - - xfs_ilock(ip, iolock); - error = xfs_break_layouts(inode, &iolock, false); - if (error) - goto out_unlock; - - xfs_ilock(ip, XFS_MMAPLOCK_EXCL); - iolock |= XFS_MMAPLOCK_EXCL; - - if (mode & FALLOC_FL_PUNCH_HOLE) { - error = xfs_free_file_space(ip, offset, len); - if (error) - goto out_unlock; - } else if (mode & FALLOC_FL_COLLAPSE_RANGE) { - unsigned blksize_mask = (1 << inode->i_blkbits) - 1; - - if (offset & blksize_mask || len & blksize_mask) { - error = -EINVAL; - goto out_unlock; - } - - /* - * There is no need to overlap collapse range with EOF, - * in which case it is effectively a truncate operation - */ - if (offset + len >= i_size_read(inode)) { - error = -EINVAL; - goto out_unlock; - } - - new_size = i_size_read(inode) - len; - - error = xfs_collapse_file_space(ip, offset, len); - if (error) - goto out_unlock; - } else if (mode & FALLOC_FL_INSERT_RANGE) { - unsigned blksize_mask = (1 << inode->i_blkbits) - 1; - - new_size = i_size_read(inode) + len; - if (offset & blksize_mask || len & blksize_mask) { - error = -EINVAL; - goto out_unlock; - } - - /* check the new inode size does not wrap through zero */ - if (new_size > inode->i_sb->s_maxbytes) { - error = -EFBIG; - goto out_unlock; - } - - /* Offset should be less than i_size */ - if (offset >= i_size_read(inode)) { - error = -EINVAL; - goto out_unlock; - } - do_file_insert = 1; - } else { - flags |= XFS_PREALLOC_SET; - - if (!(mode & FALLOC_FL_KEEP_SIZE) && - offset + len > i_size_read(inode)) { - new_size = offset + len; - error = inode_newsize_ok(inode, new_size); - if (error) - goto out_unlock; - } - - if (mode & FALLOC_FL_ZERO_RANGE) - error = xfs_zero_file_space(ip, offset, len); - else { - if (mode & FALLOC_FL_UNSHARE_RANGE) { - error = xfs_reflink_unshare(ip, offset, len); - if (error) - goto out_unlock; - } - error = xfs_alloc_file_space(ip, offset, len, - XFS_BMAPI_PREALLOC); - } - if (error) - goto out_unlock; - } - - if (file->f_flags & O_DSYNC) - flags |= XFS_PREALLOC_SYNC; - - error = xfs_update_prealloc_flags(ip, flags); - if (error) - goto out_unlock; - - /* Change file size if needed */ - if (new_size) { - struct iattr iattr; - - iattr.ia_valid = ATTR_SIZE; - iattr.ia_size = new_size; - error = xfs_vn_setattr_size(file_dentry(file), &iattr); - if (error) - goto out_unlock; - } - - /* - * Perform hole insertion now that the file size has been - * updated so that if we crash during the operation we don't - * leave shifted extents past EOF and hence losing access to - * the data that is contained within them. - */ - if (do_file_insert) - error = xfs_insert_file_space(ip, offset, len); - -out_unlock: - xfs_iunlock(ip, iolock); - return error; -} - -STATIC ssize_t -xfs_file_copy_range( - struct file *file_in, - loff_t pos_in, - struct file *file_out, - loff_t pos_out, - size_t len, - unsigned int flags) -{ - int error; - - error = xfs_reflink_remap_range(file_in, pos_in, file_out, pos_out, - len, false); - if (error) - return error; - return len; -} - -STATIC int -xfs_file_clone_range( - struct file *file_in, - loff_t pos_in, - struct file *file_out, - loff_t pos_out, - u64 len) -{ - return xfs_reflink_remap_range(file_in, pos_in, file_out, pos_out, - len, false); -} - -#define XFS_MAX_DEDUPE_LEN (16 * 1024 * 1024) -STATIC ssize_t -xfs_file_dedupe_range( - struct file *src_file, - u64 loff, - u64 len, - struct file *dst_file, - u64 dst_loff) -{ - int error; - - /* - * Limit the total length we will dedupe for each operation. - * This is intended to bound the total time spent in this - * ioctl to something sane. - */ - if (len > XFS_MAX_DEDUPE_LEN) - len = XFS_MAX_DEDUPE_LEN; - - error = xfs_reflink_remap_range(src_file, loff, dst_file, dst_loff, - len, true); - if (error) - return error; - return len; -} - -STATIC int -xfs_file_open( - struct inode *inode, - struct file *file) -{ - if (!(file->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS) - return -EFBIG; - if (XFS_FORCED_SHUTDOWN(XFS_M(inode->i_sb))) - return -EIO; - return 0; -} - -STATIC int -xfs_dir_open( - struct inode *inode, - struct file *file) -{ - struct xfs_inode *ip = XFS_I(inode); - int mode; - int error; - - error = xfs_file_open(inode, file); - if (error) - return error; - - /* - * If there are any blocks, read-ahead block 0 as we're almost - * certain to have the next operation be a read there. - */ - mode = xfs_ilock_data_map_shared(ip); - if (ip->i_d.di_nextents > 0) - xfs_dir3_data_readahead(ip, 0, -1); - xfs_iunlock(ip, mode); - return 0; -} - -STATIC int -xfs_file_release( - struct inode *inode, - struct file *filp) -{ - return xfs_release(XFS_I(inode)); -} - -STATIC int -xfs_file_readdir( - struct file *file, - struct dir_context *ctx) -{ - struct inode *inode = file_inode(file); - xfs_inode_t *ip = XFS_I(inode); - size_t bufsize; - - /* - * The Linux API doesn't pass down the total size of the buffer - * we read into down to the filesystem. With the filldir concept - * it's not needed for correct information, but the XFS dir2 leaf - * code wants an estimate of the buffer size to calculate it's - * readahead window and size the buffers used for mapping to - * physical blocks. - * - * Try to give it an estimate that's good enough, maybe at some - * point we can change the ->readdir prototype to include the - * buffer size. For now we use the current glibc buffer size. - */ - bufsize = (size_t)min_t(loff_t, 32768, ip->i_d.di_size); - - return xfs_readdir(ip, ctx, bufsize); -} - -/* - * This type is designed to indicate the type of offset we would like - * to search from page cache for xfs_seek_hole_data(). - */ -enum { - HOLE_OFF = 0, - DATA_OFF, -}; - -/* - * Lookup the desired type of offset from the given page. - * - * On success, return true and the offset argument will point to the - * start of the region that was found. Otherwise this function will - * return false and keep the offset argument unchanged. - */ -STATIC bool -xfs_lookup_buffer_offset( - struct page *page, - loff_t *offset, - unsigned int type) -{ - loff_t lastoff = page_offset(page); - bool found = false; - struct buffer_head *bh, *head; - - bh = head = page_buffers(page); - do { - /* - * Unwritten extents that have data in the page - * cache covering them can be identified by the - * BH_Unwritten state flag. Pages with multiple - * buffers might have a mix of holes, data and - * unwritten extents - any buffer with valid - * data in it should have BH_Uptodate flag set - * on it. - */ - if (buffer_unwritten(bh) || - buffer_uptodate(bh)) { - if (type == DATA_OFF) - found = true; - } else { - if (type == HOLE_OFF) - found = true; - } - - if (found) { - *offset = lastoff; - break; - } - lastoff += bh->b_size; - } while ((bh = bh->b_this_page) != head); - - return found; -} - -/* - * This routine is called to find out and return a data or hole offset - * from the page cache for unwritten extents according to the desired - * type for xfs_seek_hole_data(). - * - * The argument offset is used to tell where we start to search from the - * page cache. Map is used to figure out the end points of the range to - * lookup pages. - * - * Return true if the desired type of offset was found, and the argument - * offset is filled with that address. Otherwise, return false and keep - * offset unchanged. - */ -STATIC bool -xfs_find_get_desired_pgoff( - struct inode *inode, - struct xfs_bmbt_irec *map, - unsigned int type, - loff_t *offset) -{ - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; - struct pagevec pvec; - pgoff_t index; - pgoff_t end; - loff_t endoff; - loff_t startoff = *offset; - loff_t lastoff = startoff; - bool found = false; - - pagevec_init(&pvec, 0); - - index = startoff >> PAGE_SHIFT; - endoff = XFS_FSB_TO_B(mp, map->br_startoff + map->br_blockcount); - end = endoff >> PAGE_SHIFT; - do { - int want; - unsigned nr_pages; - unsigned int i; - - want = min_t(pgoff_t, end - index, PAGEVEC_SIZE); - nr_pages = pagevec_lookup(&pvec, inode->i_mapping, index, - want); - /* - * No page mapped into given range. If we are searching holes - * and if this is the first time we got into the loop, it means - * that the given offset is landed in a hole, return it. - * - * If we have already stepped through some block buffers to find - * holes but they all contains data. In this case, the last - * offset is already updated and pointed to the end of the last - * mapped page, if it does not reach the endpoint to search, - * that means there should be a hole between them. - */ - if (nr_pages == 0) { - /* Data search found nothing */ - if (type == DATA_OFF) - break; - - ASSERT(type == HOLE_OFF); - if (lastoff == startoff || lastoff < endoff) { - found = true; - *offset = lastoff; - } - break; - } - - /* - * At lease we found one page. If this is the first time we - * step into the loop, and if the first page index offset is - * greater than the given search offset, a hole was found. - */ - if (type == HOLE_OFF && lastoff == startoff && - lastoff < page_offset(pvec.pages[0])) { - found = true; - break; - } - - for (i = 0; i < nr_pages; i++) { - struct page *page = pvec.pages[i]; - loff_t b_offset; - - /* - * At this point, the page may be truncated or - * invalidated (changing page->mapping to NULL), - * or even swizzled back from swapper_space to tmpfs - * file mapping. However, page->index will not change - * because we have a reference on the page. - * - * Searching done if the page index is out of range. - * If the current offset is not reaches the end of - * the specified search range, there should be a hole - * between them. - */ - if (page->index > end) { - if (type == HOLE_OFF && lastoff < endoff) { - *offset = lastoff; - found = true; - } - goto out; - } - - lock_page(page); - /* - * Page truncated or invalidated(page->mapping == NULL). - * We can freely skip it and proceed to check the next - * page. - */ - if (unlikely(page->mapping != inode->i_mapping)) { - unlock_page(page); - continue; - } - - if (!page_has_buffers(page)) { - unlock_page(page); - continue; - } - - found = xfs_lookup_buffer_offset(page, &b_offset, type); - if (found) { - /* - * The found offset may be less than the start - * point to search if this is the first time to - * come here. - */ - *offset = max_t(loff_t, startoff, b_offset); - unlock_page(page); - goto out; - } - - /* - * We either searching data but nothing was found, or - * searching hole but found a data buffer. In either - * case, probably the next page contains the desired - * things, update the last offset to it so. - */ - lastoff = page_offset(page) + PAGE_SIZE; - unlock_page(page); - } - - /* - * The number of returned pages less than our desired, search - * done. In this case, nothing was found for searching data, - * but we found a hole behind the last offset. - */ - if (nr_pages < want) { - if (type == HOLE_OFF) { - *offset = lastoff; - found = true; - } - break; - } - - index = pvec.pages[i - 1]->index + 1; - pagevec_release(&pvec); - } while (index <= end); - -out: - pagevec_release(&pvec); - return found; -} - -/* - * caller must lock inode with xfs_ilock_data_map_shared, - * can we craft an appropriate ASSERT? - * - * end is because the VFS-level lseek interface is defined such that any - * offset past i_size shall return -ENXIO, but we use this for quota code - * which does not maintain i_size, and we want to SEEK_DATA past i_size. - */ -loff_t -__xfs_seek_hole_data( - struct inode *inode, - loff_t start, - loff_t end, - int whence) -{ - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; - loff_t uninitialized_var(offset); - xfs_fileoff_t fsbno; - xfs_filblks_t lastbno; - int error; - - if (start >= end) { - error = -ENXIO; - goto out_error; - } - - /* - * Try to read extents from the first block indicated - * by fsbno to the end block of the file. - */ - fsbno = XFS_B_TO_FSBT(mp, start); - lastbno = XFS_B_TO_FSB(mp, end); - - for (;;) { - struct xfs_bmbt_irec map[2]; - int nmap = 2; - unsigned int i; - - error = xfs_bmapi_read(ip, fsbno, lastbno - fsbno, map, &nmap, - XFS_BMAPI_ENTIRE); - if (error) - goto out_error; - - /* No extents at given offset, must be beyond EOF */ - if (nmap == 0) { - error = -ENXIO; - goto out_error; - } - - for (i = 0; i < nmap; i++) { - offset = max_t(loff_t, start, - XFS_FSB_TO_B(mp, map[i].br_startoff)); - - /* Landed in the hole we wanted? */ - if (whence == SEEK_HOLE && - map[i].br_startblock == HOLESTARTBLOCK) - goto out; - - /* Landed in the data extent we wanted? */ - if (whence == SEEK_DATA && - (map[i].br_startblock == DELAYSTARTBLOCK || - (map[i].br_state == XFS_EXT_NORM && - !isnullstartblock(map[i].br_startblock)))) - goto out; - - /* - * Landed in an unwritten extent, try to search - * for hole or data from page cache. - */ - if (map[i].br_state == XFS_EXT_UNWRITTEN) { - if (xfs_find_get_desired_pgoff(inode, &map[i], - whence == SEEK_HOLE ? HOLE_OFF : DATA_OFF, - &offset)) - goto out; - } - } - - /* - * We only received one extent out of the two requested. This - * means we've hit EOF and didn't find what we are looking for. - */ - if (nmap == 1) { - /* - * If we were looking for a hole, set offset to - * the end of the file (i.e., there is an implicit - * hole at the end of any file). - */ - if (whence == SEEK_HOLE) { - offset = end; - break; - } - /* - * If we were looking for data, it's nowhere to be found - */ - ASSERT(whence == SEEK_DATA); - error = -ENXIO; - goto out_error; - } - - ASSERT(i > 1); - - /* - * Nothing was found, proceed to the next round of search - * if the next reading offset is not at or beyond EOF. - */ - fsbno = map[i - 1].br_startoff + map[i - 1].br_blockcount; - start = XFS_FSB_TO_B(mp, fsbno); - if (start >= end) { - if (whence == SEEK_HOLE) { - offset = end; - break; - } - ASSERT(whence == SEEK_DATA); - error = -ENXIO; - goto out_error; - } - } - -out: - /* - * If at this point we have found the hole we wanted, the returned - * offset may be bigger than the file size as it may be aligned to - * page boundary for unwritten extents. We need to deal with this - * situation in particular. - */ - if (whence == SEEK_HOLE) - offset = min_t(loff_t, offset, end); - - return offset; - -out_error: - return error; -} - -STATIC loff_t -xfs_seek_hole_data( - struct file *file, - loff_t start, - int whence) -{ - struct inode *inode = file->f_mapping->host; - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; - uint lock; - loff_t offset, end; - int error = 0; - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - lock = xfs_ilock_data_map_shared(ip); - - end = i_size_read(inode); - offset = __xfs_seek_hole_data(inode, start, end, whence); - if (offset < 0) { - error = offset; - goto out_unlock; - } - - offset = vfs_setpos(file, offset, inode->i_sb->s_maxbytes); - -out_unlock: - xfs_iunlock(ip, lock); - - if (error) - return error; - return offset; -} - -STATIC loff_t -xfs_file_llseek( - struct file *file, - loff_t offset, - int whence) -{ - switch (whence) { - case SEEK_END: - case SEEK_CUR: - case SEEK_SET: - return generic_file_llseek(file, offset, whence); - case SEEK_HOLE: - case SEEK_DATA: - return xfs_seek_hole_data(file, offset, whence); - default: - return -EINVAL; - } -} - -/* - * Locking for serialisation of IO during page faults. This results in a lock - * ordering of: - * - * mmap_sem (MM) - * sb_start_pagefault(vfs, freeze) - * i_mmaplock (XFS - truncate serialisation) - * page_lock (MM) - * i_lock (XFS - extent map serialisation) - */ - -/* - * mmap()d file has taken write protection fault and is being made writable. We - * can set the page state up correctly for a writable page, which means we can - * do correct delalloc accounting (ENOSPC checking!) and unwritten extent - * mapping. - */ -STATIC int -xfs_filemap_page_mkwrite( - struct vm_area_struct *vma, - struct vm_fault *vmf) -{ - struct inode *inode = file_inode(vma->vm_file); - int ret; - - trace_xfs_filemap_page_mkwrite(XFS_I(inode)); - - sb_start_pagefault(inode->i_sb); - file_update_time(vma->vm_file); - xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED); - - if (IS_DAX(inode)) { - ret = iomap_dax_fault(vma, vmf, &xfs_iomap_ops); - } else { - ret = iomap_page_mkwrite(vma, vmf, &xfs_iomap_ops); - ret = block_page_mkwrite_return(ret); - } - - xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED); - sb_end_pagefault(inode->i_sb); - - return ret; -} - -STATIC int -xfs_filemap_fault( - struct vm_area_struct *vma, - struct vm_fault *vmf) -{ - struct inode *inode = file_inode(vma->vm_file); - int ret; - - trace_xfs_filemap_fault(XFS_I(inode)); - - /* DAX can shortcut the normal fault path on write faults! */ - if ((vmf->flags & FAULT_FLAG_WRITE) && IS_DAX(inode)) - return xfs_filemap_page_mkwrite(vma, vmf); - - xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED); - if (IS_DAX(inode)) { - /* - * we do not want to trigger unwritten extent conversion on read - * faults - that is unnecessary overhead and would also require - * changes to xfs_get_blocks_direct() to map unwritten extent - * ioend for conversion on read-only mappings. - */ - ret = iomap_dax_fault(vma, vmf, &xfs_iomap_ops); - } else - ret = filemap_fault(vma, vmf); - xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED); - - return ret; -} - -/* - * Similar to xfs_filemap_fault(), the DAX fault path can call into here on - * both read and write faults. Hence we need to handle both cases. There is no - * ->pmd_mkwrite callout for huge pages, so we have a single function here to - * handle both cases here. @flags carries the information on the type of fault - * occuring. - */ -STATIC int -xfs_filemap_pmd_fault( - struct vm_area_struct *vma, - unsigned long addr, - pmd_t *pmd, - unsigned int flags) -{ - struct inode *inode = file_inode(vma->vm_file); - struct xfs_inode *ip = XFS_I(inode); - int ret; - - if (!IS_DAX(inode)) - return VM_FAULT_FALLBACK; - - trace_xfs_filemap_pmd_fault(ip); - - if (flags & FAULT_FLAG_WRITE) { - sb_start_pagefault(inode->i_sb); - file_update_time(vma->vm_file); - } - - xfs_ilock(XFS_I(inode), XFS_MMAPLOCK_SHARED); - ret = dax_pmd_fault(vma, addr, pmd, flags, xfs_get_blocks_dax_fault); - xfs_iunlock(XFS_I(inode), XFS_MMAPLOCK_SHARED); - - if (flags & FAULT_FLAG_WRITE) - sb_end_pagefault(inode->i_sb); - - return ret; -} - -/* - * pfn_mkwrite was originally inteneded to ensure we capture time stamp - * updates on write faults. In reality, it's need to serialise against - * truncate similar to page_mkwrite. Hence we cycle the XFS_MMAPLOCK_SHARED - * to ensure we serialise the fault barrier in place. - */ -static int -xfs_filemap_pfn_mkwrite( - struct vm_area_struct *vma, - struct vm_fault *vmf) -{ - - struct inode *inode = file_inode(vma->vm_file); - struct xfs_inode *ip = XFS_I(inode); - int ret = VM_FAULT_NOPAGE; - loff_t size; - - trace_xfs_filemap_pfn_mkwrite(ip); - - sb_start_pagefault(inode->i_sb); - file_update_time(vma->vm_file); - - /* check if the faulting page hasn't raced with truncate */ - xfs_ilock(ip, XFS_MMAPLOCK_SHARED); - size = (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT; - if (vmf->pgoff >= size) - ret = VM_FAULT_SIGBUS; - else if (IS_DAX(inode)) - ret = dax_pfn_mkwrite(vma, vmf); - xfs_iunlock(ip, XFS_MMAPLOCK_SHARED); - sb_end_pagefault(inode->i_sb); - return ret; - -} - -static const struct vm_operations_struct xfs_file_vm_ops = { - .fault = xfs_filemap_fault, - .pmd_fault = xfs_filemap_pmd_fault, - .map_pages = filemap_map_pages, - .page_mkwrite = xfs_filemap_page_mkwrite, - .pfn_mkwrite = xfs_filemap_pfn_mkwrite, -}; - -STATIC int -xfs_file_mmap( - struct file *filp, - struct vm_area_struct *vma) -{ - file_accessed(filp); - vma->vm_ops = &xfs_file_vm_ops; - if (IS_DAX(file_inode(filp))) - vma->vm_flags |= VM_MIXEDMAP | VM_HUGEPAGE; - return 0; -} - -const struct file_operations xfs_file_operations = { - .llseek = xfs_file_llseek, - .read_iter = xfs_file_read_iter, - .write_iter = xfs_file_write_iter, - .splice_read = generic_file_splice_read, - .splice_write = iter_file_splice_write, - .unlocked_ioctl = xfs_file_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = xfs_file_compat_ioctl, -#endif - .mmap = xfs_file_mmap, - .open = xfs_file_open, - .release = xfs_file_release, - .fsync = xfs_file_fsync, - .get_unmapped_area = thp_get_unmapped_area, - .fallocate = xfs_file_fallocate, - .copy_file_range = xfs_file_copy_range, - .clone_file_range = xfs_file_clone_range, - .dedupe_file_range = xfs_file_dedupe_range, -}; - -const struct file_operations xfs_dir_file_operations = { - .open = xfs_dir_open, - .read = generic_read_dir, - .iterate_shared = xfs_file_readdir, - .llseek = generic_file_llseek, - .unlocked_ioctl = xfs_file_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = xfs_file_compat_ioctl, -#endif - .fsync = xfs_dir_fsync, -}; diff --git a/src/linux/fs/xfs/xfs_filestream.c b/src/linux/fs/xfs/xfs_filestream.c deleted file mode 100644 index 043ca38..0000000 --- a/src/linux/fs/xfs/xfs_filestream.c +++ /dev/null @@ -1,438 +0,0 @@ -/* - * Copyright (c) 2006-2007 Silicon Graphics, Inc. - * Copyright (c) 2014 Christoph Hellwig. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_inode.h" -#include "xfs_bmap.h" -#include "xfs_bmap_util.h" -#include "xfs_alloc.h" -#include "xfs_mru_cache.h" -#include "xfs_filestream.h" -#include "xfs_trace.h" -#include "xfs_ag_resv.h" - -struct xfs_fstrm_item { - struct xfs_mru_cache_elem mru; - struct xfs_inode *ip; - xfs_agnumber_t ag; /* AG in use for this directory */ -}; - -enum xfs_fstrm_alloc { - XFS_PICK_USERDATA = 1, - XFS_PICK_LOWSPACE = 2, -}; - -/* - * Allocation group filestream associations are tracked with per-ag atomic - * counters. These counters allow xfs_filestream_pick_ag() to tell whether a - * particular AG already has active filestreams associated with it. The mount - * point's m_peraglock is used to protect these counters from per-ag array - * re-allocation during a growfs operation. When xfs_growfs_data_private() is - * about to reallocate the array, it calls xfs_filestream_flush() with the - * m_peraglock held in write mode. - * - * Since xfs_mru_cache_flush() guarantees that all the free functions for all - * the cache elements have finished executing before it returns, it's safe for - * the free functions to use the atomic counters without m_peraglock protection. - * This allows the implementation of xfs_fstrm_free_func() to be agnostic about - * whether it was called with the m_peraglock held in read mode, write mode or - * not held at all. The race condition this addresses is the following: - * - * - The work queue scheduler fires and pulls a filestream directory cache - * element off the LRU end of the cache for deletion, then gets pre-empted. - * - A growfs operation grabs the m_peraglock in write mode, flushes all the - * remaining items from the cache and reallocates the mount point's per-ag - * array, resetting all the counters to zero. - * - The work queue thread resumes and calls the free function for the element - * it started cleaning up earlier. In the process it decrements the - * filestreams counter for an AG that now has no references. - * - * With a shrinkfs feature, the above scenario could panic the system. - * - * All other uses of the following macros should be protected by either the - * m_peraglock held in read mode, or the cache's internal locking exposed by the - * interval between a call to xfs_mru_cache_lookup() and a call to - * xfs_mru_cache_done(). In addition, the m_peraglock must be held in read mode - * when new elements are added to the cache. - * - * Combined, these locking rules ensure that no associations will ever exist in - * the cache that reference per-ag array elements that have since been - * reallocated. - */ -int -xfs_filestream_peek_ag( - xfs_mount_t *mp, - xfs_agnumber_t agno) -{ - struct xfs_perag *pag; - int ret; - - pag = xfs_perag_get(mp, agno); - ret = atomic_read(&pag->pagf_fstrms); - xfs_perag_put(pag); - return ret; -} - -static int -xfs_filestream_get_ag( - xfs_mount_t *mp, - xfs_agnumber_t agno) -{ - struct xfs_perag *pag; - int ret; - - pag = xfs_perag_get(mp, agno); - ret = atomic_inc_return(&pag->pagf_fstrms); - xfs_perag_put(pag); - return ret; -} - -static void -xfs_filestream_put_ag( - xfs_mount_t *mp, - xfs_agnumber_t agno) -{ - struct xfs_perag *pag; - - pag = xfs_perag_get(mp, agno); - atomic_dec(&pag->pagf_fstrms); - xfs_perag_put(pag); -} - -static void -xfs_fstrm_free_func( - struct xfs_mru_cache_elem *mru) -{ - struct xfs_fstrm_item *item = - container_of(mru, struct xfs_fstrm_item, mru); - - xfs_filestream_put_ag(item->ip->i_mount, item->ag); - - trace_xfs_filestream_free(item->ip, item->ag); - - kmem_free(item); -} - -/* - * Scan the AGs starting at startag looking for an AG that isn't in use and has - * at least minlen blocks free. - */ -static int -xfs_filestream_pick_ag( - struct xfs_inode *ip, - xfs_agnumber_t startag, - xfs_agnumber_t *agp, - int flags, - xfs_extlen_t minlen) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_fstrm_item *item; - struct xfs_perag *pag; - xfs_extlen_t longest, free = 0, minfree, maxfree = 0; - xfs_agnumber_t ag, max_ag = NULLAGNUMBER; - int err, trylock, nscan; - - ASSERT(S_ISDIR(VFS_I(ip)->i_mode)); - - /* 2% of an AG's blocks must be free for it to be chosen. */ - minfree = mp->m_sb.sb_agblocks / 50; - - ag = startag; - *agp = NULLAGNUMBER; - - /* For the first pass, don't sleep trying to init the per-AG. */ - trylock = XFS_ALLOC_FLAG_TRYLOCK; - - for (nscan = 0; 1; nscan++) { - trace_xfs_filestream_scan(ip, ag); - - pag = xfs_perag_get(mp, ag); - - if (!pag->pagf_init) { - err = xfs_alloc_pagf_init(mp, NULL, ag, trylock); - if (err && !trylock) { - xfs_perag_put(pag); - return err; - } - } - - /* Might fail sometimes during the 1st pass with trylock set. */ - if (!pag->pagf_init) - goto next_ag; - - /* Keep track of the AG with the most free blocks. */ - if (pag->pagf_freeblks > maxfree) { - maxfree = pag->pagf_freeblks; - max_ag = ag; - } - - /* - * The AG reference count does two things: it enforces mutual - * exclusion when examining the suitability of an AG in this - * loop, and it guards against two filestreams being established - * in the same AG as each other. - */ - if (xfs_filestream_get_ag(mp, ag) > 1) { - xfs_filestream_put_ag(mp, ag); - goto next_ag; - } - - longest = xfs_alloc_longest_free_extent(mp, pag, - xfs_alloc_min_freelist(mp, pag), - xfs_ag_resv_needed(pag, XFS_AG_RESV_NONE)); - if (((minlen && longest >= minlen) || - (!minlen && pag->pagf_freeblks >= minfree)) && - (!pag->pagf_metadata || !(flags & XFS_PICK_USERDATA) || - (flags & XFS_PICK_LOWSPACE))) { - - /* Break out, retaining the reference on the AG. */ - free = pag->pagf_freeblks; - xfs_perag_put(pag); - *agp = ag; - break; - } - - /* Drop the reference on this AG, it's not usable. */ - xfs_filestream_put_ag(mp, ag); -next_ag: - xfs_perag_put(pag); - /* Move to the next AG, wrapping to AG 0 if necessary. */ - if (++ag >= mp->m_sb.sb_agcount) - ag = 0; - - /* If a full pass of the AGs hasn't been done yet, continue. */ - if (ag != startag) - continue; - - /* Allow sleeping in xfs_alloc_pagf_init() on the 2nd pass. */ - if (trylock != 0) { - trylock = 0; - continue; - } - - /* Finally, if lowspace wasn't set, set it for the 3rd pass. */ - if (!(flags & XFS_PICK_LOWSPACE)) { - flags |= XFS_PICK_LOWSPACE; - continue; - } - - /* - * Take the AG with the most free space, regardless of whether - * it's already in use by another filestream. - */ - if (max_ag != NULLAGNUMBER) { - xfs_filestream_get_ag(mp, max_ag); - free = maxfree; - *agp = max_ag; - break; - } - - /* take AG 0 if none matched */ - trace_xfs_filestream_pick(ip, *agp, free, nscan); - *agp = 0; - return 0; - } - - trace_xfs_filestream_pick(ip, *agp, free, nscan); - - if (*agp == NULLAGNUMBER) - return 0; - - err = -ENOMEM; - item = kmem_alloc(sizeof(*item), KM_MAYFAIL); - if (!item) - goto out_put_ag; - - item->ag = *agp; - item->ip = ip; - - err = xfs_mru_cache_insert(mp->m_filestream, ip->i_ino, &item->mru); - if (err) { - if (err == -EEXIST) - err = 0; - goto out_free_item; - } - - return 0; - -out_free_item: - kmem_free(item); -out_put_ag: - xfs_filestream_put_ag(mp, *agp); - return err; -} - -static struct xfs_inode * -xfs_filestream_get_parent( - struct xfs_inode *ip) -{ - struct inode *inode = VFS_I(ip), *dir = NULL; - struct dentry *dentry, *parent; - - dentry = d_find_alias(inode); - if (!dentry) - goto out; - - parent = dget_parent(dentry); - if (!parent) - goto out_dput; - - dir = igrab(d_inode(parent)); - dput(parent); - -out_dput: - dput(dentry); -out: - return dir ? XFS_I(dir) : NULL; -} - -/* - * Find the right allocation group for a file, either by finding an - * existing file stream or creating a new one. - * - * Returns NULLAGNUMBER in case of an error. - */ -xfs_agnumber_t -xfs_filestream_lookup_ag( - struct xfs_inode *ip) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_inode *pip = NULL; - xfs_agnumber_t startag, ag = NULLAGNUMBER; - struct xfs_mru_cache_elem *mru; - - ASSERT(S_ISREG(VFS_I(ip)->i_mode)); - - pip = xfs_filestream_get_parent(ip); - if (!pip) - return NULLAGNUMBER; - - mru = xfs_mru_cache_lookup(mp->m_filestream, pip->i_ino); - if (mru) { - ag = container_of(mru, struct xfs_fstrm_item, mru)->ag; - xfs_mru_cache_done(mp->m_filestream); - - trace_xfs_filestream_lookup(ip, ag); - goto out; - } - - /* - * Set the starting AG using the rotor for inode32, otherwise - * use the directory inode's AG. - */ - if (mp->m_flags & XFS_MOUNT_32BITINODES) { - xfs_agnumber_t rotorstep = xfs_rotorstep; - startag = (mp->m_agfrotor / rotorstep) % mp->m_sb.sb_agcount; - mp->m_agfrotor = (mp->m_agfrotor + 1) % - (mp->m_sb.sb_agcount * rotorstep); - } else - startag = XFS_INO_TO_AGNO(mp, pip->i_ino); - - if (xfs_filestream_pick_ag(pip, startag, &ag, 0, 0)) - ag = NULLAGNUMBER; -out: - IRELE(pip); - return ag; -} - -/* - * Pick a new allocation group for the current file and its file stream. - * - * This is called when the allocator can't find a suitable extent in the - * current AG, and we have to move the stream into a new AG with more space. - */ -int -xfs_filestream_new_ag( - struct xfs_bmalloca *ap, - xfs_agnumber_t *agp) -{ - struct xfs_inode *ip = ap->ip, *pip; - struct xfs_mount *mp = ip->i_mount; - xfs_extlen_t minlen = ap->length; - xfs_agnumber_t startag = 0; - int flags = 0; - int err = 0; - struct xfs_mru_cache_elem *mru; - - *agp = NULLAGNUMBER; - - pip = xfs_filestream_get_parent(ip); - if (!pip) - goto exit; - - mru = xfs_mru_cache_remove(mp->m_filestream, pip->i_ino); - if (mru) { - struct xfs_fstrm_item *item = - container_of(mru, struct xfs_fstrm_item, mru); - startag = (item->ag + 1) % mp->m_sb.sb_agcount; - } - - if (xfs_alloc_is_userdata(ap->datatype)) - flags |= XFS_PICK_USERDATA; - if (ap->dfops->dop_low) - flags |= XFS_PICK_LOWSPACE; - - err = xfs_filestream_pick_ag(pip, startag, agp, flags, minlen); - - /* - * Only free the item here so we skip over the old AG earlier. - */ - if (mru) - xfs_fstrm_free_func(mru); - - IRELE(pip); -exit: - if (*agp == NULLAGNUMBER) - *agp = 0; - return err; -} - -void -xfs_filestream_deassociate( - struct xfs_inode *ip) -{ - xfs_mru_cache_delete(ip->i_mount->m_filestream, ip->i_ino); -} - -int -xfs_filestream_mount( - xfs_mount_t *mp) -{ - /* - * The filestream timer tunable is currently fixed within the range of - * one second to four minutes, with five seconds being the default. The - * group count is somewhat arbitrary, but it'd be nice to adhere to the - * timer tunable to within about 10 percent. This requires at least 10 - * groups. - */ - return xfs_mru_cache_create(&mp->m_filestream, xfs_fstrm_centisecs * 10, - 10, xfs_fstrm_free_func); -} - -void -xfs_filestream_unmount( - xfs_mount_t *mp) -{ - xfs_mru_cache_destroy(mp->m_filestream); -} diff --git a/src/linux/fs/xfs/xfs_filestream.h b/src/linux/fs/xfs/xfs_filestream.h deleted file mode 100644 index 2ef4340..0000000 --- a/src/linux/fs/xfs/xfs_filestream.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2006-2007 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_FILESTREAM_H__ -#define __XFS_FILESTREAM_H__ - -struct xfs_mount; -struct xfs_inode; -struct xfs_bmalloca; - -int xfs_filestream_mount(struct xfs_mount *mp); -void xfs_filestream_unmount(struct xfs_mount *mp); -void xfs_filestream_deassociate(struct xfs_inode *ip); -xfs_agnumber_t xfs_filestream_lookup_ag(struct xfs_inode *ip); -int xfs_filestream_new_ag(struct xfs_bmalloca *ap, xfs_agnumber_t *agp); -int xfs_filestream_peek_ag(struct xfs_mount *mp, xfs_agnumber_t agno); - -static inline int -xfs_inode_is_filestream( - struct xfs_inode *ip) -{ - return (ip->i_mount->m_flags & XFS_MOUNT_FILESTREAMS) || - (ip->i_d.di_flags & XFS_DIFLAG_FILESTREAM); -} - -#endif /* __XFS_FILESTREAM_H__ */ diff --git a/src/linux/fs/xfs/xfs_fsops.c b/src/linux/fs/xfs/xfs_fsops.c deleted file mode 100644 index 93d12fa..0000000 --- a/src/linux/fs/xfs/xfs_fsops.c +++ /dev/null @@ -1,1055 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_error.h" -#include "xfs_btree.h" -#include "xfs_alloc_btree.h" -#include "xfs_alloc.h" -#include "xfs_rmap_btree.h" -#include "xfs_ialloc.h" -#include "xfs_fsops.h" -#include "xfs_itable.h" -#include "xfs_trans_space.h" -#include "xfs_rtalloc.h" -#include "xfs_trace.h" -#include "xfs_log.h" -#include "xfs_filestream.h" -#include "xfs_rmap.h" -#include "xfs_ag_resv.h" - -/* - * File system operations - */ - -int -xfs_fs_geometry( - xfs_mount_t *mp, - xfs_fsop_geom_t *geo, - int new_version) -{ - - memset(geo, 0, sizeof(*geo)); - - geo->blocksize = mp->m_sb.sb_blocksize; - geo->rtextsize = mp->m_sb.sb_rextsize; - geo->agblocks = mp->m_sb.sb_agblocks; - geo->agcount = mp->m_sb.sb_agcount; - geo->logblocks = mp->m_sb.sb_logblocks; - geo->sectsize = mp->m_sb.sb_sectsize; - geo->inodesize = mp->m_sb.sb_inodesize; - geo->imaxpct = mp->m_sb.sb_imax_pct; - geo->datablocks = mp->m_sb.sb_dblocks; - geo->rtblocks = mp->m_sb.sb_rblocks; - geo->rtextents = mp->m_sb.sb_rextents; - geo->logstart = mp->m_sb.sb_logstart; - ASSERT(sizeof(geo->uuid)==sizeof(mp->m_sb.sb_uuid)); - memcpy(geo->uuid, &mp->m_sb.sb_uuid, sizeof(mp->m_sb.sb_uuid)); - if (new_version >= 2) { - geo->sunit = mp->m_sb.sb_unit; - geo->swidth = mp->m_sb.sb_width; - } - if (new_version >= 3) { - geo->version = XFS_FSOP_GEOM_VERSION; - geo->flags = XFS_FSOP_GEOM_FLAGS_NLINK | - XFS_FSOP_GEOM_FLAGS_DIRV2 | - (xfs_sb_version_hasattr(&mp->m_sb) ? - XFS_FSOP_GEOM_FLAGS_ATTR : 0) | - (xfs_sb_version_hasquota(&mp->m_sb) ? - XFS_FSOP_GEOM_FLAGS_QUOTA : 0) | - (xfs_sb_version_hasalign(&mp->m_sb) ? - XFS_FSOP_GEOM_FLAGS_IALIGN : 0) | - (xfs_sb_version_hasdalign(&mp->m_sb) ? - XFS_FSOP_GEOM_FLAGS_DALIGN : 0) | - (xfs_sb_version_hasextflgbit(&mp->m_sb) ? - XFS_FSOP_GEOM_FLAGS_EXTFLG : 0) | - (xfs_sb_version_hassector(&mp->m_sb) ? - XFS_FSOP_GEOM_FLAGS_SECTOR : 0) | - (xfs_sb_version_hasasciici(&mp->m_sb) ? - XFS_FSOP_GEOM_FLAGS_DIRV2CI : 0) | - (xfs_sb_version_haslazysbcount(&mp->m_sb) ? - XFS_FSOP_GEOM_FLAGS_LAZYSB : 0) | - (xfs_sb_version_hasattr2(&mp->m_sb) ? - XFS_FSOP_GEOM_FLAGS_ATTR2 : 0) | - (xfs_sb_version_hasprojid32bit(&mp->m_sb) ? - XFS_FSOP_GEOM_FLAGS_PROJID32 : 0) | - (xfs_sb_version_hascrc(&mp->m_sb) ? - XFS_FSOP_GEOM_FLAGS_V5SB : 0) | - (xfs_sb_version_hasftype(&mp->m_sb) ? - XFS_FSOP_GEOM_FLAGS_FTYPE : 0) | - (xfs_sb_version_hasfinobt(&mp->m_sb) ? - XFS_FSOP_GEOM_FLAGS_FINOBT : 0) | - (xfs_sb_version_hassparseinodes(&mp->m_sb) ? - XFS_FSOP_GEOM_FLAGS_SPINODES : 0) | - (xfs_sb_version_hasrmapbt(&mp->m_sb) ? - XFS_FSOP_GEOM_FLAGS_RMAPBT : 0) | - (xfs_sb_version_hasreflink(&mp->m_sb) ? - XFS_FSOP_GEOM_FLAGS_REFLINK : 0); - geo->logsectsize = xfs_sb_version_hassector(&mp->m_sb) ? - mp->m_sb.sb_logsectsize : BBSIZE; - geo->rtsectsize = mp->m_sb.sb_blocksize; - geo->dirblocksize = mp->m_dir_geo->blksize; - } - if (new_version >= 4) { - geo->flags |= - (xfs_sb_version_haslogv2(&mp->m_sb) ? - XFS_FSOP_GEOM_FLAGS_LOGV2 : 0); - geo->logsunit = mp->m_sb.sb_logsunit; - } - return 0; -} - -static struct xfs_buf * -xfs_growfs_get_hdr_buf( - struct xfs_mount *mp, - xfs_daddr_t blkno, - size_t numblks, - int flags, - const struct xfs_buf_ops *ops) -{ - struct xfs_buf *bp; - - bp = xfs_buf_get_uncached(mp->m_ddev_targp, numblks, flags); - if (!bp) - return NULL; - - xfs_buf_zero(bp, 0, BBTOB(bp->b_length)); - bp->b_bn = blkno; - bp->b_maps[0].bm_bn = blkno; - bp->b_ops = ops; - - return bp; -} - -static int -xfs_growfs_data_private( - xfs_mount_t *mp, /* mount point for filesystem */ - xfs_growfs_data_t *in) /* growfs data input struct */ -{ - xfs_agf_t *agf; - struct xfs_agfl *agfl; - xfs_agi_t *agi; - xfs_agnumber_t agno; - xfs_extlen_t agsize; - xfs_extlen_t tmpsize; - xfs_alloc_rec_t *arec; - xfs_buf_t *bp; - int bucket; - int dpct; - int error, saved_error = 0; - xfs_agnumber_t nagcount; - xfs_agnumber_t nagimax = 0; - xfs_rfsblock_t nb, nb_mod; - xfs_rfsblock_t new; - xfs_rfsblock_t nfree; - xfs_agnumber_t oagcount; - int pct; - xfs_trans_t *tp; - - nb = in->newblocks; - pct = in->imaxpct; - if (nb < mp->m_sb.sb_dblocks || pct < 0 || pct > 100) - return -EINVAL; - if ((error = xfs_sb_validate_fsb_count(&mp->m_sb, nb))) - return error; - dpct = pct - mp->m_sb.sb_imax_pct; - error = xfs_buf_read_uncached(mp->m_ddev_targp, - XFS_FSB_TO_BB(mp, nb) - XFS_FSS_TO_BB(mp, 1), - XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL); - if (error) - return error; - xfs_buf_relse(bp); - - new = nb; /* use new as a temporary here */ - nb_mod = do_div(new, mp->m_sb.sb_agblocks); - nagcount = new + (nb_mod != 0); - if (nb_mod && nb_mod < XFS_MIN_AG_BLOCKS) { - nagcount--; - nb = (xfs_rfsblock_t)nagcount * mp->m_sb.sb_agblocks; - if (nb < mp->m_sb.sb_dblocks) - return -EINVAL; - } - new = nb - mp->m_sb.sb_dblocks; - oagcount = mp->m_sb.sb_agcount; - - /* allocate the new per-ag structures */ - if (nagcount > oagcount) { - error = xfs_initialize_perag(mp, nagcount, &nagimax); - if (error) - return error; - } - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata, - XFS_GROWFS_SPACE_RES(mp), 0, XFS_TRANS_RESERVE, &tp); - if (error) - return error; - - /* - * Write new AG headers to disk. Non-transactional, but written - * synchronously so they are completed prior to the growfs transaction - * being logged. - */ - nfree = 0; - for (agno = nagcount - 1; agno >= oagcount; agno--, new -= agsize) { - __be32 *agfl_bno; - - /* - * AG freespace header block - */ - bp = xfs_growfs_get_hdr_buf(mp, - XFS_AG_DADDR(mp, agno, XFS_AGF_DADDR(mp)), - XFS_FSS_TO_BB(mp, 1), 0, - &xfs_agf_buf_ops); - if (!bp) { - error = -ENOMEM; - goto error0; - } - - agf = XFS_BUF_TO_AGF(bp); - agf->agf_magicnum = cpu_to_be32(XFS_AGF_MAGIC); - agf->agf_versionnum = cpu_to_be32(XFS_AGF_VERSION); - agf->agf_seqno = cpu_to_be32(agno); - if (agno == nagcount - 1) - agsize = - nb - - (agno * (xfs_rfsblock_t)mp->m_sb.sb_agblocks); - else - agsize = mp->m_sb.sb_agblocks; - agf->agf_length = cpu_to_be32(agsize); - agf->agf_roots[XFS_BTNUM_BNOi] = cpu_to_be32(XFS_BNO_BLOCK(mp)); - agf->agf_roots[XFS_BTNUM_CNTi] = cpu_to_be32(XFS_CNT_BLOCK(mp)); - agf->agf_levels[XFS_BTNUM_BNOi] = cpu_to_be32(1); - agf->agf_levels[XFS_BTNUM_CNTi] = cpu_to_be32(1); - if (xfs_sb_version_hasrmapbt(&mp->m_sb)) { - agf->agf_roots[XFS_BTNUM_RMAPi] = - cpu_to_be32(XFS_RMAP_BLOCK(mp)); - agf->agf_levels[XFS_BTNUM_RMAPi] = cpu_to_be32(1); - agf->agf_rmap_blocks = cpu_to_be32(1); - } - - agf->agf_flfirst = cpu_to_be32(1); - agf->agf_fllast = 0; - agf->agf_flcount = 0; - tmpsize = agsize - mp->m_ag_prealloc_blocks; - agf->agf_freeblks = cpu_to_be32(tmpsize); - agf->agf_longest = cpu_to_be32(tmpsize); - if (xfs_sb_version_hascrc(&mp->m_sb)) - uuid_copy(&agf->agf_uuid, &mp->m_sb.sb_meta_uuid); - if (xfs_sb_version_hasreflink(&mp->m_sb)) { - agf->agf_refcount_root = cpu_to_be32( - xfs_refc_block(mp)); - agf->agf_refcount_level = cpu_to_be32(1); - agf->agf_refcount_blocks = cpu_to_be32(1); - } - - error = xfs_bwrite(bp); - xfs_buf_relse(bp); - if (error) - goto error0; - - /* - * AG freelist header block - */ - bp = xfs_growfs_get_hdr_buf(mp, - XFS_AG_DADDR(mp, agno, XFS_AGFL_DADDR(mp)), - XFS_FSS_TO_BB(mp, 1), 0, - &xfs_agfl_buf_ops); - if (!bp) { - error = -ENOMEM; - goto error0; - } - - agfl = XFS_BUF_TO_AGFL(bp); - if (xfs_sb_version_hascrc(&mp->m_sb)) { - agfl->agfl_magicnum = cpu_to_be32(XFS_AGFL_MAGIC); - agfl->agfl_seqno = cpu_to_be32(agno); - uuid_copy(&agfl->agfl_uuid, &mp->m_sb.sb_meta_uuid); - } - - agfl_bno = XFS_BUF_TO_AGFL_BNO(mp, bp); - for (bucket = 0; bucket < XFS_AGFL_SIZE(mp); bucket++) - agfl_bno[bucket] = cpu_to_be32(NULLAGBLOCK); - - error = xfs_bwrite(bp); - xfs_buf_relse(bp); - if (error) - goto error0; - - /* - * AG inode header block - */ - bp = xfs_growfs_get_hdr_buf(mp, - XFS_AG_DADDR(mp, agno, XFS_AGI_DADDR(mp)), - XFS_FSS_TO_BB(mp, 1), 0, - &xfs_agi_buf_ops); - if (!bp) { - error = -ENOMEM; - goto error0; - } - - agi = XFS_BUF_TO_AGI(bp); - agi->agi_magicnum = cpu_to_be32(XFS_AGI_MAGIC); - agi->agi_versionnum = cpu_to_be32(XFS_AGI_VERSION); - agi->agi_seqno = cpu_to_be32(agno); - agi->agi_length = cpu_to_be32(agsize); - agi->agi_count = 0; - agi->agi_root = cpu_to_be32(XFS_IBT_BLOCK(mp)); - agi->agi_level = cpu_to_be32(1); - agi->agi_freecount = 0; - agi->agi_newino = cpu_to_be32(NULLAGINO); - agi->agi_dirino = cpu_to_be32(NULLAGINO); - if (xfs_sb_version_hascrc(&mp->m_sb)) - uuid_copy(&agi->agi_uuid, &mp->m_sb.sb_meta_uuid); - if (xfs_sb_version_hasfinobt(&mp->m_sb)) { - agi->agi_free_root = cpu_to_be32(XFS_FIBT_BLOCK(mp)); - agi->agi_free_level = cpu_to_be32(1); - } - for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) - agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO); - - error = xfs_bwrite(bp); - xfs_buf_relse(bp); - if (error) - goto error0; - - /* - * BNO btree root block - */ - bp = xfs_growfs_get_hdr_buf(mp, - XFS_AGB_TO_DADDR(mp, agno, XFS_BNO_BLOCK(mp)), - BTOBB(mp->m_sb.sb_blocksize), 0, - &xfs_allocbt_buf_ops); - - if (!bp) { - error = -ENOMEM; - goto error0; - } - - if (xfs_sb_version_hascrc(&mp->m_sb)) - xfs_btree_init_block(mp, bp, XFS_ABTB_CRC_MAGIC, 0, 1, - agno, XFS_BTREE_CRC_BLOCKS); - else - xfs_btree_init_block(mp, bp, XFS_ABTB_MAGIC, 0, 1, - agno, 0); - - arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1); - arec->ar_startblock = cpu_to_be32(mp->m_ag_prealloc_blocks); - arec->ar_blockcount = cpu_to_be32( - agsize - be32_to_cpu(arec->ar_startblock)); - - error = xfs_bwrite(bp); - xfs_buf_relse(bp); - if (error) - goto error0; - - /* - * CNT btree root block - */ - bp = xfs_growfs_get_hdr_buf(mp, - XFS_AGB_TO_DADDR(mp, agno, XFS_CNT_BLOCK(mp)), - BTOBB(mp->m_sb.sb_blocksize), 0, - &xfs_allocbt_buf_ops); - if (!bp) { - error = -ENOMEM; - goto error0; - } - - if (xfs_sb_version_hascrc(&mp->m_sb)) - xfs_btree_init_block(mp, bp, XFS_ABTC_CRC_MAGIC, 0, 1, - agno, XFS_BTREE_CRC_BLOCKS); - else - xfs_btree_init_block(mp, bp, XFS_ABTC_MAGIC, 0, 1, - agno, 0); - - arec = XFS_ALLOC_REC_ADDR(mp, XFS_BUF_TO_BLOCK(bp), 1); - arec->ar_startblock = cpu_to_be32(mp->m_ag_prealloc_blocks); - arec->ar_blockcount = cpu_to_be32( - agsize - be32_to_cpu(arec->ar_startblock)); - nfree += be32_to_cpu(arec->ar_blockcount); - - error = xfs_bwrite(bp); - xfs_buf_relse(bp); - if (error) - goto error0; - - /* RMAP btree root block */ - if (xfs_sb_version_hasrmapbt(&mp->m_sb)) { - struct xfs_rmap_rec *rrec; - struct xfs_btree_block *block; - - bp = xfs_growfs_get_hdr_buf(mp, - XFS_AGB_TO_DADDR(mp, agno, XFS_RMAP_BLOCK(mp)), - BTOBB(mp->m_sb.sb_blocksize), 0, - &xfs_rmapbt_buf_ops); - if (!bp) { - error = -ENOMEM; - goto error0; - } - - xfs_btree_init_block(mp, bp, XFS_RMAP_CRC_MAGIC, 0, 0, - agno, XFS_BTREE_CRC_BLOCKS); - block = XFS_BUF_TO_BLOCK(bp); - - - /* - * mark the AG header regions as static metadata The BNO - * btree block is the first block after the headers, so - * it's location defines the size of region the static - * metadata consumes. - * - * Note: unlike mkfs, we never have to account for log - * space when growing the data regions - */ - rrec = XFS_RMAP_REC_ADDR(block, 1); - rrec->rm_startblock = 0; - rrec->rm_blockcount = cpu_to_be32(XFS_BNO_BLOCK(mp)); - rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_FS); - rrec->rm_offset = 0; - be16_add_cpu(&block->bb_numrecs, 1); - - /* account freespace btree root blocks */ - rrec = XFS_RMAP_REC_ADDR(block, 2); - rrec->rm_startblock = cpu_to_be32(XFS_BNO_BLOCK(mp)); - rrec->rm_blockcount = cpu_to_be32(2); - rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_AG); - rrec->rm_offset = 0; - be16_add_cpu(&block->bb_numrecs, 1); - - /* account inode btree root blocks */ - rrec = XFS_RMAP_REC_ADDR(block, 3); - rrec->rm_startblock = cpu_to_be32(XFS_IBT_BLOCK(mp)); - rrec->rm_blockcount = cpu_to_be32(XFS_RMAP_BLOCK(mp) - - XFS_IBT_BLOCK(mp)); - rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_INOBT); - rrec->rm_offset = 0; - be16_add_cpu(&block->bb_numrecs, 1); - - /* account for rmap btree root */ - rrec = XFS_RMAP_REC_ADDR(block, 4); - rrec->rm_startblock = cpu_to_be32(XFS_RMAP_BLOCK(mp)); - rrec->rm_blockcount = cpu_to_be32(1); - rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_AG); - rrec->rm_offset = 0; - be16_add_cpu(&block->bb_numrecs, 1); - - /* account for refc btree root */ - if (xfs_sb_version_hasreflink(&mp->m_sb)) { - rrec = XFS_RMAP_REC_ADDR(block, 5); - rrec->rm_startblock = cpu_to_be32( - xfs_refc_block(mp)); - rrec->rm_blockcount = cpu_to_be32(1); - rrec->rm_owner = cpu_to_be64(XFS_RMAP_OWN_REFC); - rrec->rm_offset = 0; - be16_add_cpu(&block->bb_numrecs, 1); - } - - error = xfs_bwrite(bp); - xfs_buf_relse(bp); - if (error) - goto error0; - } - - /* - * INO btree root block - */ - bp = xfs_growfs_get_hdr_buf(mp, - XFS_AGB_TO_DADDR(mp, agno, XFS_IBT_BLOCK(mp)), - BTOBB(mp->m_sb.sb_blocksize), 0, - &xfs_inobt_buf_ops); - if (!bp) { - error = -ENOMEM; - goto error0; - } - - if (xfs_sb_version_hascrc(&mp->m_sb)) - xfs_btree_init_block(mp, bp, XFS_IBT_CRC_MAGIC, 0, 0, - agno, XFS_BTREE_CRC_BLOCKS); - else - xfs_btree_init_block(mp, bp, XFS_IBT_MAGIC, 0, 0, - agno, 0); - - error = xfs_bwrite(bp); - xfs_buf_relse(bp); - if (error) - goto error0; - - /* - * FINO btree root block - */ - if (xfs_sb_version_hasfinobt(&mp->m_sb)) { - bp = xfs_growfs_get_hdr_buf(mp, - XFS_AGB_TO_DADDR(mp, agno, XFS_FIBT_BLOCK(mp)), - BTOBB(mp->m_sb.sb_blocksize), 0, - &xfs_inobt_buf_ops); - if (!bp) { - error = -ENOMEM; - goto error0; - } - - if (xfs_sb_version_hascrc(&mp->m_sb)) - xfs_btree_init_block(mp, bp, XFS_FIBT_CRC_MAGIC, - 0, 0, agno, - XFS_BTREE_CRC_BLOCKS); - else - xfs_btree_init_block(mp, bp, XFS_FIBT_MAGIC, 0, - 0, agno, 0); - - error = xfs_bwrite(bp); - xfs_buf_relse(bp); - if (error) - goto error0; - } - - /* - * refcount btree root block - */ - if (xfs_sb_version_hasreflink(&mp->m_sb)) { - bp = xfs_growfs_get_hdr_buf(mp, - XFS_AGB_TO_DADDR(mp, agno, xfs_refc_block(mp)), - BTOBB(mp->m_sb.sb_blocksize), 0, - &xfs_refcountbt_buf_ops); - if (!bp) { - error = -ENOMEM; - goto error0; - } - - xfs_btree_init_block(mp, bp, XFS_REFC_CRC_MAGIC, - 0, 0, agno, - XFS_BTREE_CRC_BLOCKS); - - error = xfs_bwrite(bp); - xfs_buf_relse(bp); - if (error) - goto error0; - } - } - xfs_trans_agblocks_delta(tp, nfree); - /* - * There are new blocks in the old last a.g. - */ - if (new) { - struct xfs_owner_info oinfo; - - /* - * Change the agi length. - */ - error = xfs_ialloc_read_agi(mp, tp, agno, &bp); - if (error) { - goto error0; - } - ASSERT(bp); - agi = XFS_BUF_TO_AGI(bp); - be32_add_cpu(&agi->agi_length, new); - ASSERT(nagcount == oagcount || - be32_to_cpu(agi->agi_length) == mp->m_sb.sb_agblocks); - xfs_ialloc_log_agi(tp, bp, XFS_AGI_LENGTH); - /* - * Change agf length. - */ - error = xfs_alloc_read_agf(mp, tp, agno, 0, &bp); - if (error) { - goto error0; - } - ASSERT(bp); - agf = XFS_BUF_TO_AGF(bp); - be32_add_cpu(&agf->agf_length, new); - ASSERT(be32_to_cpu(agf->agf_length) == - be32_to_cpu(agi->agi_length)); - - xfs_alloc_log_agf(tp, bp, XFS_AGF_LENGTH); - - /* - * Free the new space. - * - * XFS_RMAP_OWN_NULL is used here to tell the rmap btree that - * this doesn't actually exist in the rmap btree. - */ - xfs_rmap_ag_owner(&oinfo, XFS_RMAP_OWN_NULL); - error = xfs_free_extent(tp, - XFS_AGB_TO_FSB(mp, agno, - be32_to_cpu(agf->agf_length) - new), - new, &oinfo, XFS_AG_RESV_NONE); - if (error) - goto error0; - } - - /* - * Update changed superblock fields transactionally. These are not - * seen by the rest of the world until the transaction commit applies - * them atomically to the superblock. - */ - if (nagcount > oagcount) - xfs_trans_mod_sb(tp, XFS_TRANS_SB_AGCOUNT, nagcount - oagcount); - if (nb > mp->m_sb.sb_dblocks) - xfs_trans_mod_sb(tp, XFS_TRANS_SB_DBLOCKS, - nb - mp->m_sb.sb_dblocks); - if (nfree) - xfs_trans_mod_sb(tp, XFS_TRANS_SB_FDBLOCKS, nfree); - if (dpct) - xfs_trans_mod_sb(tp, XFS_TRANS_SB_IMAXPCT, dpct); - xfs_trans_set_sync(tp); - error = xfs_trans_commit(tp); - if (error) - return error; - - /* New allocation groups fully initialized, so update mount struct */ - if (nagimax) - mp->m_maxagi = nagimax; - if (mp->m_sb.sb_imax_pct) { - __uint64_t icount = mp->m_sb.sb_dblocks * mp->m_sb.sb_imax_pct; - do_div(icount, 100); - mp->m_maxicount = icount << mp->m_sb.sb_inopblog; - } else - mp->m_maxicount = 0; - xfs_set_low_space_thresholds(mp); - mp->m_alloc_set_aside = xfs_alloc_set_aside(mp); - - /* Reserve AG metadata blocks. */ - error = xfs_fs_reserve_ag_blocks(mp); - if (error && error != -ENOSPC) - goto out; - - /* update secondary superblocks. */ - for (agno = 1; agno < nagcount; agno++) { - error = 0; - /* - * new secondary superblocks need to be zeroed, not read from - * disk as the contents of the new area we are growing into is - * completely unknown. - */ - if (agno < oagcount) { - error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, - XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), - XFS_FSS_TO_BB(mp, 1), 0, &bp, - &xfs_sb_buf_ops); - } else { - bp = xfs_trans_get_buf(NULL, mp->m_ddev_targp, - XFS_AGB_TO_DADDR(mp, agno, XFS_SB_BLOCK(mp)), - XFS_FSS_TO_BB(mp, 1), 0); - if (bp) { - bp->b_ops = &xfs_sb_buf_ops; - xfs_buf_zero(bp, 0, BBTOB(bp->b_length)); - } else - error = -ENOMEM; - } - - /* - * If we get an error reading or writing alternate superblocks, - * continue. xfs_repair chooses the "best" superblock based - * on most matches; if we break early, we'll leave more - * superblocks un-updated than updated, and xfs_repair may - * pick them over the properly-updated primary. - */ - if (error) { - xfs_warn(mp, - "error %d reading secondary superblock for ag %d", - error, agno); - saved_error = error; - continue; - } - xfs_sb_to_disk(XFS_BUF_TO_SBP(bp), &mp->m_sb); - - error = xfs_bwrite(bp); - xfs_buf_relse(bp); - if (error) { - xfs_warn(mp, - "write error %d updating secondary superblock for ag %d", - error, agno); - saved_error = error; - continue; - } - } - - out: - return saved_error ? saved_error : error; - - error0: - xfs_trans_cancel(tp); - return error; -} - -static int -xfs_growfs_log_private( - xfs_mount_t *mp, /* mount point for filesystem */ - xfs_growfs_log_t *in) /* growfs log input struct */ -{ - xfs_extlen_t nb; - - nb = in->newblocks; - if (nb < XFS_MIN_LOG_BLOCKS || nb < XFS_B_TO_FSB(mp, XFS_MIN_LOG_BYTES)) - return -EINVAL; - if (nb == mp->m_sb.sb_logblocks && - in->isint == (mp->m_sb.sb_logstart != 0)) - return -EINVAL; - /* - * Moving the log is hard, need new interfaces to sync - * the log first, hold off all activity while moving it. - * Can have shorter or longer log in the same space, - * or transform internal to external log or vice versa. - */ - return -ENOSYS; -} - -/* - * protected versions of growfs function acquire and release locks on the mount - * point - exported through ioctls: XFS_IOC_FSGROWFSDATA, XFS_IOC_FSGROWFSLOG, - * XFS_IOC_FSGROWFSRT - */ - - -int -xfs_growfs_data( - xfs_mount_t *mp, - xfs_growfs_data_t *in) -{ - int error; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!mutex_trylock(&mp->m_growlock)) - return -EWOULDBLOCK; - error = xfs_growfs_data_private(mp, in); - /* - * Increment the generation unconditionally, the error could be from - * updating the secondary superblocks, in which case the new size - * is live already. - */ - mp->m_generation++; - mutex_unlock(&mp->m_growlock); - return error; -} - -int -xfs_growfs_log( - xfs_mount_t *mp, - xfs_growfs_log_t *in) -{ - int error; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (!mutex_trylock(&mp->m_growlock)) - return -EWOULDBLOCK; - error = xfs_growfs_log_private(mp, in); - mutex_unlock(&mp->m_growlock); - return error; -} - -/* - * exported through ioctl XFS_IOC_FSCOUNTS - */ - -int -xfs_fs_counts( - xfs_mount_t *mp, - xfs_fsop_counts_t *cnt) -{ - cnt->allocino = percpu_counter_read_positive(&mp->m_icount); - cnt->freeino = percpu_counter_read_positive(&mp->m_ifree); - cnt->freedata = percpu_counter_read_positive(&mp->m_fdblocks) - - mp->m_alloc_set_aside; - - spin_lock(&mp->m_sb_lock); - cnt->freertx = mp->m_sb.sb_frextents; - spin_unlock(&mp->m_sb_lock); - return 0; -} - -/* - * exported through ioctl XFS_IOC_SET_RESBLKS & XFS_IOC_GET_RESBLKS - * - * xfs_reserve_blocks is called to set m_resblks - * in the in-core mount table. The number of unused reserved blocks - * is kept in m_resblks_avail. - * - * Reserve the requested number of blocks if available. Otherwise return - * as many as possible to satisfy the request. The actual number - * reserved are returned in outval - * - * A null inval pointer indicates that only the current reserved blocks - * available should be returned no settings are changed. - */ - -int -xfs_reserve_blocks( - xfs_mount_t *mp, - __uint64_t *inval, - xfs_fsop_resblks_t *outval) -{ - __int64_t lcounter, delta; - __int64_t fdblks_delta = 0; - __uint64_t request; - __int64_t free; - int error = 0; - - /* If inval is null, report current values and return */ - if (inval == (__uint64_t *)NULL) { - if (!outval) - return -EINVAL; - outval->resblks = mp->m_resblks; - outval->resblks_avail = mp->m_resblks_avail; - return 0; - } - - request = *inval; - - /* - * With per-cpu counters, this becomes an interesting problem. we need - * to work out if we are freeing or allocation blocks first, then we can - * do the modification as necessary. - * - * We do this under the m_sb_lock so that if we are near ENOSPC, we will - * hold out any changes while we work out what to do. This means that - * the amount of free space can change while we do this, so we need to - * retry if we end up trying to reserve more space than is available. - */ - spin_lock(&mp->m_sb_lock); - - /* - * If our previous reservation was larger than the current value, - * then move any unused blocks back to the free pool. Modify the resblks - * counters directly since we shouldn't have any problems unreserving - * space. - */ - if (mp->m_resblks > request) { - lcounter = mp->m_resblks_avail - request; - if (lcounter > 0) { /* release unused blocks */ - fdblks_delta = lcounter; - mp->m_resblks_avail -= lcounter; - } - mp->m_resblks = request; - if (fdblks_delta) { - spin_unlock(&mp->m_sb_lock); - error = xfs_mod_fdblocks(mp, fdblks_delta, 0); - spin_lock(&mp->m_sb_lock); - } - - goto out; - } - - /* - * If the request is larger than the current reservation, reserve the - * blocks before we update the reserve counters. Sample m_fdblocks and - * perform a partial reservation if the request exceeds free space. - */ - error = -ENOSPC; - do { - free = percpu_counter_sum(&mp->m_fdblocks) - - mp->m_alloc_set_aside; - if (!free) - break; - - delta = request - mp->m_resblks; - lcounter = free - delta; - if (lcounter < 0) - /* We can't satisfy the request, just get what we can */ - fdblks_delta = free; - else - fdblks_delta = delta; - - /* - * We'll either succeed in getting space from the free block - * count or we'll get an ENOSPC. If we get a ENOSPC, it means - * things changed while we were calculating fdblks_delta and so - * we should try again to see if there is anything left to - * reserve. - * - * Don't set the reserved flag here - we don't want to reserve - * the extra reserve blocks from the reserve..... - */ - spin_unlock(&mp->m_sb_lock); - error = xfs_mod_fdblocks(mp, -fdblks_delta, 0); - spin_lock(&mp->m_sb_lock); - } while (error == -ENOSPC); - - /* - * Update the reserve counters if blocks have been successfully - * allocated. - */ - if (!error && fdblks_delta) { - mp->m_resblks += fdblks_delta; - mp->m_resblks_avail += fdblks_delta; - } - -out: - if (outval) { - outval->resblks = mp->m_resblks; - outval->resblks_avail = mp->m_resblks_avail; - } - - spin_unlock(&mp->m_sb_lock); - return error; -} - -int -xfs_fs_goingdown( - xfs_mount_t *mp, - __uint32_t inflags) -{ - switch (inflags) { - case XFS_FSOP_GOING_FLAGS_DEFAULT: { - struct super_block *sb = freeze_bdev(mp->m_super->s_bdev); - - if (sb && !IS_ERR(sb)) { - xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT); - thaw_bdev(sb->s_bdev, sb); - } - - break; - } - case XFS_FSOP_GOING_FLAGS_LOGFLUSH: - xfs_force_shutdown(mp, SHUTDOWN_FORCE_UMOUNT); - break; - case XFS_FSOP_GOING_FLAGS_NOLOGFLUSH: - xfs_force_shutdown(mp, - SHUTDOWN_FORCE_UMOUNT | SHUTDOWN_LOG_IO_ERROR); - break; - default: - return -EINVAL; - } - - return 0; -} - -/* - * Force a shutdown of the filesystem instantly while keeping the filesystem - * consistent. We don't do an unmount here; just shutdown the shop, make sure - * that absolutely nothing persistent happens to this filesystem after this - * point. - */ -void -xfs_do_force_shutdown( - xfs_mount_t *mp, - int flags, - char *fname, - int lnnum) -{ - int logerror; - - logerror = flags & SHUTDOWN_LOG_IO_ERROR; - - if (!(flags & SHUTDOWN_FORCE_UMOUNT)) { - xfs_notice(mp, - "%s(0x%x) called from line %d of file %s. Return address = 0x%p", - __func__, flags, lnnum, fname, __return_address); - } - /* - * No need to duplicate efforts. - */ - if (XFS_FORCED_SHUTDOWN(mp) && !logerror) - return; - - /* - * This flags XFS_MOUNT_FS_SHUTDOWN, makes sure that we don't - * queue up anybody new on the log reservations, and wakes up - * everybody who's sleeping on log reservations to tell them - * the bad news. - */ - if (xfs_log_force_umount(mp, logerror)) - return; - - if (flags & SHUTDOWN_CORRUPT_INCORE) { - xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_CORRUPT, - "Corruption of in-memory data detected. Shutting down filesystem"); - if (XFS_ERRLEVEL_HIGH <= xfs_error_level) - xfs_stack_trace(); - } else if (!(flags & SHUTDOWN_FORCE_UMOUNT)) { - if (logerror) { - xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_LOGERROR, - "Log I/O Error Detected. Shutting down filesystem"); - } else if (flags & SHUTDOWN_DEVICE_REQ) { - xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR, - "All device paths lost. Shutting down filesystem"); - } else if (!(flags & SHUTDOWN_REMOTE_REQ)) { - xfs_alert_tag(mp, XFS_PTAG_SHUTDOWN_IOERROR, - "I/O Error Detected. Shutting down filesystem"); - } - } - if (!(flags & SHUTDOWN_FORCE_UMOUNT)) { - xfs_alert(mp, - "Please umount the filesystem and rectify the problem(s)"); - } -} - -/* - * Reserve free space for per-AG metadata. - */ -int -xfs_fs_reserve_ag_blocks( - struct xfs_mount *mp) -{ - xfs_agnumber_t agno; - struct xfs_perag *pag; - int error = 0; - int err2; - - for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { - pag = xfs_perag_get(mp, agno); - err2 = xfs_ag_resv_init(pag); - xfs_perag_put(pag); - if (err2 && !error) - error = err2; - } - - if (error && error != -ENOSPC) { - xfs_warn(mp, - "Error %d reserving per-AG metadata reserve pool.", error); - xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); - } - - return error; -} - -/* - * Free space reserved for per-AG metadata. - */ -int -xfs_fs_unreserve_ag_blocks( - struct xfs_mount *mp) -{ - xfs_agnumber_t agno; - struct xfs_perag *pag; - int error = 0; - int err2; - - for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { - pag = xfs_perag_get(mp, agno); - err2 = xfs_ag_resv_free(pag); - xfs_perag_put(pag); - if (err2 && !error) - error = err2; - } - - if (error) - xfs_warn(mp, - "Error %d freeing per-AG metadata reserve pool.", error); - - return error; -} diff --git a/src/linux/fs/xfs/xfs_fsops.h b/src/linux/fs/xfs/xfs_fsops.h deleted file mode 100644 index f349158..0000000 --- a/src/linux/fs/xfs/xfs_fsops.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2000-2001,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_FSOPS_H__ -#define __XFS_FSOPS_H__ - -extern int xfs_fs_geometry(xfs_mount_t *mp, xfs_fsop_geom_t *geo, int nversion); -extern int xfs_growfs_data(xfs_mount_t *mp, xfs_growfs_data_t *in); -extern int xfs_growfs_log(xfs_mount_t *mp, xfs_growfs_log_t *in); -extern int xfs_fs_counts(xfs_mount_t *mp, xfs_fsop_counts_t *cnt); -extern int xfs_reserve_blocks(xfs_mount_t *mp, __uint64_t *inval, - xfs_fsop_resblks_t *outval); -extern int xfs_fs_goingdown(xfs_mount_t *mp, __uint32_t inflags); - -extern int xfs_fs_reserve_ag_blocks(struct xfs_mount *mp); -extern int xfs_fs_unreserve_ag_blocks(struct xfs_mount *mp); - -#endif /* __XFS_FSOPS_H__ */ diff --git a/src/linux/fs/xfs/xfs_globals.c b/src/linux/fs/xfs/xfs_globals.c deleted file mode 100644 index 687a4b0..0000000 --- a/src/linux/fs/xfs/xfs_globals.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_sysctl.h" - -/* - * Tunable XFS parameters. xfs_params is required even when CONFIG_SYSCTL=n, - * other XFS code uses these values. Times are measured in centisecs (i.e. - * 100ths of a second) with the exception of eofb_timer and cowb_timer, which - * are measured in seconds. - */ -xfs_param_t xfs_params = { - /* MIN DFLT MAX */ - .sgid_inherit = { 0, 0, 1 }, - .symlink_mode = { 0, 0, 1 }, - .panic_mask = { 0, 0, 255 }, - .error_level = { 0, 3, 11 }, - .syncd_timer = { 1*100, 30*100, 7200*100}, - .stats_clear = { 0, 0, 1 }, - .inherit_sync = { 0, 1, 1 }, - .inherit_nodump = { 0, 1, 1 }, - .inherit_noatim = { 0, 1, 1 }, - .xfs_buf_timer = { 100/2, 1*100, 30*100 }, - .xfs_buf_age = { 1*100, 15*100, 7200*100}, - .inherit_nosym = { 0, 0, 1 }, - .rotorstep = { 1, 1, 255 }, - .inherit_nodfrg = { 0, 1, 1 }, - .fstrm_timer = { 1, 30*100, 3600*100}, - .eofb_timer = { 1, 300, 3600*24}, - .cowb_timer = { 1, 1800, 3600*24}, -}; - -struct xfs_globals xfs_globals = { - .log_recovery_delay = 0, /* no delay by default */ -}; diff --git a/src/linux/fs/xfs/xfs_icache.c b/src/linux/fs/xfs/xfs_icache.c deleted file mode 100644 index f295049..0000000 --- a/src/linux/fs/xfs/xfs_icache.c +++ /dev/null @@ -1,1672 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_inode.h" -#include "xfs_error.h" -#include "xfs_trans.h" -#include "xfs_trans_priv.h" -#include "xfs_inode_item.h" -#include "xfs_quota.h" -#include "xfs_trace.h" -#include "xfs_icache.h" -#include "xfs_bmap_util.h" -#include "xfs_dquot_item.h" -#include "xfs_dquot.h" -#include "xfs_reflink.h" - -#include -#include - -/* - * Allocate and initialise an xfs_inode. - */ -struct xfs_inode * -xfs_inode_alloc( - struct xfs_mount *mp, - xfs_ino_t ino) -{ - struct xfs_inode *ip; - - /* - * if this didn't occur in transactions, we could use - * KM_MAYFAIL and return NULL here on ENOMEM. Set the - * code up to do this anyway. - */ - ip = kmem_zone_alloc(xfs_inode_zone, KM_SLEEP); - if (!ip) - return NULL; - if (inode_init_always(mp->m_super, VFS_I(ip))) { - kmem_zone_free(xfs_inode_zone, ip); - return NULL; - } - - /* VFS doesn't initialise i_mode! */ - VFS_I(ip)->i_mode = 0; - - XFS_STATS_INC(mp, vn_active); - ASSERT(atomic_read(&ip->i_pincount) == 0); - ASSERT(!spin_is_locked(&ip->i_flags_lock)); - ASSERT(!xfs_isiflocked(ip)); - ASSERT(ip->i_ino == 0); - - mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino); - - /* initialise the xfs inode */ - ip->i_ino = ino; - ip->i_mount = mp; - memset(&ip->i_imap, 0, sizeof(struct xfs_imap)); - ip->i_afp = NULL; - ip->i_cowfp = NULL; - ip->i_cnextents = 0; - ip->i_cformat = XFS_DINODE_FMT_EXTENTS; - memset(&ip->i_df, 0, sizeof(xfs_ifork_t)); - ip->i_flags = 0; - ip->i_delayed_blks = 0; - memset(&ip->i_d, 0, sizeof(ip->i_d)); - - return ip; -} - -STATIC void -xfs_inode_free_callback( - struct rcu_head *head) -{ - struct inode *inode = container_of(head, struct inode, i_rcu); - struct xfs_inode *ip = XFS_I(inode); - - switch (VFS_I(ip)->i_mode & S_IFMT) { - case S_IFREG: - case S_IFDIR: - case S_IFLNK: - xfs_idestroy_fork(ip, XFS_DATA_FORK); - break; - } - - if (ip->i_afp) - xfs_idestroy_fork(ip, XFS_ATTR_FORK); - if (ip->i_cowfp) - xfs_idestroy_fork(ip, XFS_COW_FORK); - - if (ip->i_itemp) { - ASSERT(!(ip->i_itemp->ili_item.li_flags & XFS_LI_IN_AIL)); - xfs_inode_item_destroy(ip); - ip->i_itemp = NULL; - } - - kmem_zone_free(xfs_inode_zone, ip); -} - -static void -__xfs_inode_free( - struct xfs_inode *ip) -{ - /* asserts to verify all state is correct here */ - ASSERT(atomic_read(&ip->i_pincount) == 0); - ASSERT(!xfs_isiflocked(ip)); - XFS_STATS_DEC(ip->i_mount, vn_active); - - call_rcu(&VFS_I(ip)->i_rcu, xfs_inode_free_callback); -} - -void -xfs_inode_free( - struct xfs_inode *ip) -{ - /* - * Because we use RCU freeing we need to ensure the inode always - * appears to be reclaimed with an invalid inode number when in the - * free state. The ip->i_flags_lock provides the barrier against lookup - * races. - */ - spin_lock(&ip->i_flags_lock); - ip->i_flags = XFS_IRECLAIM; - ip->i_ino = 0; - spin_unlock(&ip->i_flags_lock); - - __xfs_inode_free(ip); -} - -/* - * Queue a new inode reclaim pass if there are reclaimable inodes and there - * isn't a reclaim pass already in progress. By default it runs every 5s based - * on the xfs periodic sync default of 30s. Perhaps this should have it's own - * tunable, but that can be done if this method proves to be ineffective or too - * aggressive. - */ -static void -xfs_reclaim_work_queue( - struct xfs_mount *mp) -{ - - rcu_read_lock(); - if (radix_tree_tagged(&mp->m_perag_tree, XFS_ICI_RECLAIM_TAG)) { - queue_delayed_work(mp->m_reclaim_workqueue, &mp->m_reclaim_work, - msecs_to_jiffies(xfs_syncd_centisecs / 6 * 10)); - } - rcu_read_unlock(); -} - -/* - * This is a fast pass over the inode cache to try to get reclaim moving on as - * many inodes as possible in a short period of time. It kicks itself every few - * seconds, as well as being kicked by the inode cache shrinker when memory - * goes low. It scans as quickly as possible avoiding locked inodes or those - * already being flushed, and once done schedules a future pass. - */ -void -xfs_reclaim_worker( - struct work_struct *work) -{ - struct xfs_mount *mp = container_of(to_delayed_work(work), - struct xfs_mount, m_reclaim_work); - - xfs_reclaim_inodes(mp, SYNC_TRYLOCK); - xfs_reclaim_work_queue(mp); -} - -static void -xfs_perag_set_reclaim_tag( - struct xfs_perag *pag) -{ - struct xfs_mount *mp = pag->pag_mount; - - ASSERT(spin_is_locked(&pag->pag_ici_lock)); - if (pag->pag_ici_reclaimable++) - return; - - /* propagate the reclaim tag up into the perag radix tree */ - spin_lock(&mp->m_perag_lock); - radix_tree_tag_set(&mp->m_perag_tree, pag->pag_agno, - XFS_ICI_RECLAIM_TAG); - spin_unlock(&mp->m_perag_lock); - - /* schedule periodic background inode reclaim */ - xfs_reclaim_work_queue(mp); - - trace_xfs_perag_set_reclaim(mp, pag->pag_agno, -1, _RET_IP_); -} - -static void -xfs_perag_clear_reclaim_tag( - struct xfs_perag *pag) -{ - struct xfs_mount *mp = pag->pag_mount; - - ASSERT(spin_is_locked(&pag->pag_ici_lock)); - if (--pag->pag_ici_reclaimable) - return; - - /* clear the reclaim tag from the perag radix tree */ - spin_lock(&mp->m_perag_lock); - radix_tree_tag_clear(&mp->m_perag_tree, pag->pag_agno, - XFS_ICI_RECLAIM_TAG); - spin_unlock(&mp->m_perag_lock); - trace_xfs_perag_clear_reclaim(mp, pag->pag_agno, -1, _RET_IP_); -} - - -/* - * We set the inode flag atomically with the radix tree tag. - * Once we get tag lookups on the radix tree, this inode flag - * can go away. - */ -void -xfs_inode_set_reclaim_tag( - struct xfs_inode *ip) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_perag *pag; - - pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); - spin_lock(&pag->pag_ici_lock); - spin_lock(&ip->i_flags_lock); - - radix_tree_tag_set(&pag->pag_ici_root, XFS_INO_TO_AGINO(mp, ip->i_ino), - XFS_ICI_RECLAIM_TAG); - xfs_perag_set_reclaim_tag(pag); - __xfs_iflags_set(ip, XFS_IRECLAIMABLE); - - spin_unlock(&ip->i_flags_lock); - spin_unlock(&pag->pag_ici_lock); - xfs_perag_put(pag); -} - -STATIC void -xfs_inode_clear_reclaim_tag( - struct xfs_perag *pag, - xfs_ino_t ino) -{ - radix_tree_tag_clear(&pag->pag_ici_root, - XFS_INO_TO_AGINO(pag->pag_mount, ino), - XFS_ICI_RECLAIM_TAG); - xfs_perag_clear_reclaim_tag(pag); -} - -/* - * When we recycle a reclaimable inode, we need to re-initialise the VFS inode - * part of the structure. This is made more complex by the fact we store - * information about the on-disk values in the VFS inode and so we can't just - * overwrite the values unconditionally. Hence we save the parameters we - * need to retain across reinitialisation, and rewrite them into the VFS inode - * after reinitialisation even if it fails. - */ -static int -xfs_reinit_inode( - struct xfs_mount *mp, - struct inode *inode) -{ - int error; - uint32_t nlink = inode->i_nlink; - uint32_t generation = inode->i_generation; - uint64_t version = inode->i_version; - umode_t mode = inode->i_mode; - - error = inode_init_always(mp->m_super, inode); - - set_nlink(inode, nlink); - inode->i_generation = generation; - inode->i_version = version; - inode->i_mode = mode; - return error; -} - -/* - * Check the validity of the inode we just found it the cache - */ -static int -xfs_iget_cache_hit( - struct xfs_perag *pag, - struct xfs_inode *ip, - xfs_ino_t ino, - int flags, - int lock_flags) __releases(RCU) -{ - struct inode *inode = VFS_I(ip); - struct xfs_mount *mp = ip->i_mount; - int error; - - /* - * check for re-use of an inode within an RCU grace period due to the - * radix tree nodes not being updated yet. We monitor for this by - * setting the inode number to zero before freeing the inode structure. - * If the inode has been reallocated and set up, then the inode number - * will not match, so check for that, too. - */ - spin_lock(&ip->i_flags_lock); - if (ip->i_ino != ino) { - trace_xfs_iget_skip(ip); - XFS_STATS_INC(mp, xs_ig_frecycle); - error = -EAGAIN; - goto out_error; - } - - - /* - * If we are racing with another cache hit that is currently - * instantiating this inode or currently recycling it out of - * reclaimabe state, wait for the initialisation to complete - * before continuing. - * - * XXX(hch): eventually we should do something equivalent to - * wait_on_inode to wait for these flags to be cleared - * instead of polling for it. - */ - if (ip->i_flags & (XFS_INEW|XFS_IRECLAIM)) { - trace_xfs_iget_skip(ip); - XFS_STATS_INC(mp, xs_ig_frecycle); - error = -EAGAIN; - goto out_error; - } - - /* - * If lookup is racing with unlink return an error immediately. - */ - if (VFS_I(ip)->i_mode == 0 && !(flags & XFS_IGET_CREATE)) { - error = -ENOENT; - goto out_error; - } - - /* - * If IRECLAIMABLE is set, we've torn down the VFS inode already. - * Need to carefully get it back into useable state. - */ - if (ip->i_flags & XFS_IRECLAIMABLE) { - trace_xfs_iget_reclaim(ip); - - /* - * We need to set XFS_IRECLAIM to prevent xfs_reclaim_inode - * from stomping over us while we recycle the inode. We can't - * clear the radix tree reclaimable tag yet as it requires - * pag_ici_lock to be held exclusive. - */ - ip->i_flags |= XFS_IRECLAIM; - - spin_unlock(&ip->i_flags_lock); - rcu_read_unlock(); - - error = xfs_reinit_inode(mp, inode); - if (error) { - /* - * Re-initializing the inode failed, and we are in deep - * trouble. Try to re-add it to the reclaim list. - */ - rcu_read_lock(); - spin_lock(&ip->i_flags_lock); - - ip->i_flags &= ~(XFS_INEW | XFS_IRECLAIM); - ASSERT(ip->i_flags & XFS_IRECLAIMABLE); - trace_xfs_iget_reclaim_fail(ip); - goto out_error; - } - - spin_lock(&pag->pag_ici_lock); - spin_lock(&ip->i_flags_lock); - - /* - * Clear the per-lifetime state in the inode as we are now - * effectively a new inode and need to return to the initial - * state before reuse occurs. - */ - ip->i_flags &= ~XFS_IRECLAIM_RESET_FLAGS; - ip->i_flags |= XFS_INEW; - xfs_inode_clear_reclaim_tag(pag, ip->i_ino); - inode->i_state = I_NEW; - - ASSERT(!rwsem_is_locked(&ip->i_iolock.mr_lock)); - mrlock_init(&ip->i_iolock, MRLOCK_BARRIER, "xfsio", ip->i_ino); - - spin_unlock(&ip->i_flags_lock); - spin_unlock(&pag->pag_ici_lock); - } else { - /* If the VFS inode is being torn down, pause and try again. */ - if (!igrab(inode)) { - trace_xfs_iget_skip(ip); - error = -EAGAIN; - goto out_error; - } - - /* We've got a live one. */ - spin_unlock(&ip->i_flags_lock); - rcu_read_unlock(); - trace_xfs_iget_hit(ip); - } - - if (lock_flags != 0) - xfs_ilock(ip, lock_flags); - - xfs_iflags_clear(ip, XFS_ISTALE | XFS_IDONTCACHE); - XFS_STATS_INC(mp, xs_ig_found); - - return 0; - -out_error: - spin_unlock(&ip->i_flags_lock); - rcu_read_unlock(); - return error; -} - - -static int -xfs_iget_cache_miss( - struct xfs_mount *mp, - struct xfs_perag *pag, - xfs_trans_t *tp, - xfs_ino_t ino, - struct xfs_inode **ipp, - int flags, - int lock_flags) -{ - struct xfs_inode *ip; - int error; - xfs_agino_t agino = XFS_INO_TO_AGINO(mp, ino); - int iflags; - - ip = xfs_inode_alloc(mp, ino); - if (!ip) - return -ENOMEM; - - error = xfs_iread(mp, tp, ip, flags); - if (error) - goto out_destroy; - - trace_xfs_iget_miss(ip); - - if ((VFS_I(ip)->i_mode == 0) && !(flags & XFS_IGET_CREATE)) { - error = -ENOENT; - goto out_destroy; - } - - /* - * Preload the radix tree so we can insert safely under the - * write spinlock. Note that we cannot sleep inside the preload - * region. Since we can be called from transaction context, don't - * recurse into the file system. - */ - if (radix_tree_preload(GFP_NOFS)) { - error = -EAGAIN; - goto out_destroy; - } - - /* - * Because the inode hasn't been added to the radix-tree yet it can't - * be found by another thread, so we can do the non-sleeping lock here. - */ - if (lock_flags) { - if (!xfs_ilock_nowait(ip, lock_flags)) - BUG(); - } - - /* - * These values must be set before inserting the inode into the radix - * tree as the moment it is inserted a concurrent lookup (allowed by the - * RCU locking mechanism) can find it and that lookup must see that this - * is an inode currently under construction (i.e. that XFS_INEW is set). - * The ip->i_flags_lock that protects the XFS_INEW flag forms the - * memory barrier that ensures this detection works correctly at lookup - * time. - */ - iflags = XFS_INEW; - if (flags & XFS_IGET_DONTCACHE) - iflags |= XFS_IDONTCACHE; - ip->i_udquot = NULL; - ip->i_gdquot = NULL; - ip->i_pdquot = NULL; - xfs_iflags_set(ip, iflags); - - /* insert the new inode */ - spin_lock(&pag->pag_ici_lock); - error = radix_tree_insert(&pag->pag_ici_root, agino, ip); - if (unlikely(error)) { - WARN_ON(error != -EEXIST); - XFS_STATS_INC(mp, xs_ig_dup); - error = -EAGAIN; - goto out_preload_end; - } - spin_unlock(&pag->pag_ici_lock); - radix_tree_preload_end(); - - *ipp = ip; - return 0; - -out_preload_end: - spin_unlock(&pag->pag_ici_lock); - radix_tree_preload_end(); - if (lock_flags) - xfs_iunlock(ip, lock_flags); -out_destroy: - __destroy_inode(VFS_I(ip)); - xfs_inode_free(ip); - return error; -} - -/* - * Look up an inode by number in the given file system. - * The inode is looked up in the cache held in each AG. - * If the inode is found in the cache, initialise the vfs inode - * if necessary. - * - * If it is not in core, read it in from the file system's device, - * add it to the cache and initialise the vfs inode. - * - * The inode is locked according to the value of the lock_flags parameter. - * This flag parameter indicates how and if the inode's IO lock and inode lock - * should be taken. - * - * mp -- the mount point structure for the current file system. It points - * to the inode hash table. - * tp -- a pointer to the current transaction if there is one. This is - * simply passed through to the xfs_iread() call. - * ino -- the number of the inode desired. This is the unique identifier - * within the file system for the inode being requested. - * lock_flags -- flags indicating how to lock the inode. See the comment - * for xfs_ilock() for a list of valid values. - */ -int -xfs_iget( - xfs_mount_t *mp, - xfs_trans_t *tp, - xfs_ino_t ino, - uint flags, - uint lock_flags, - xfs_inode_t **ipp) -{ - xfs_inode_t *ip; - int error; - xfs_perag_t *pag; - xfs_agino_t agino; - - /* - * xfs_reclaim_inode() uses the ILOCK to ensure an inode - * doesn't get freed while it's being referenced during a - * radix tree traversal here. It assumes this function - * aqcuires only the ILOCK (and therefore it has no need to - * involve the IOLOCK in this synchronization). - */ - ASSERT((lock_flags & (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED)) == 0); - - /* reject inode numbers outside existing AGs */ - if (!ino || XFS_INO_TO_AGNO(mp, ino) >= mp->m_sb.sb_agcount) - return -EINVAL; - - XFS_STATS_INC(mp, xs_ig_attempts); - - /* get the perag structure and ensure that it's inode capable */ - pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ino)); - agino = XFS_INO_TO_AGINO(mp, ino); - -again: - error = 0; - rcu_read_lock(); - ip = radix_tree_lookup(&pag->pag_ici_root, agino); - - if (ip) { - error = xfs_iget_cache_hit(pag, ip, ino, flags, lock_flags); - if (error) - goto out_error_or_again; - } else { - rcu_read_unlock(); - XFS_STATS_INC(mp, xs_ig_missed); - - error = xfs_iget_cache_miss(mp, pag, tp, ino, &ip, - flags, lock_flags); - if (error) - goto out_error_or_again; - } - xfs_perag_put(pag); - - *ipp = ip; - - /* - * If we have a real type for an on-disk inode, we can setup the inode - * now. If it's a new inode being created, xfs_ialloc will handle it. - */ - if (xfs_iflags_test(ip, XFS_INEW) && VFS_I(ip)->i_mode != 0) - xfs_setup_existing_inode(ip); - return 0; - -out_error_or_again: - if (error == -EAGAIN) { - delay(1); - goto again; - } - xfs_perag_put(pag); - return error; -} - -/* - * The inode lookup is done in batches to keep the amount of lock traffic and - * radix tree lookups to a minimum. The batch size is a trade off between - * lookup reduction and stack usage. This is in the reclaim path, so we can't - * be too greedy. - */ -#define XFS_LOOKUP_BATCH 32 - -STATIC int -xfs_inode_ag_walk_grab( - struct xfs_inode *ip) -{ - struct inode *inode = VFS_I(ip); - - ASSERT(rcu_read_lock_held()); - - /* - * check for stale RCU freed inode - * - * If the inode has been reallocated, it doesn't matter if it's not in - * the AG we are walking - we are walking for writeback, so if it - * passes all the "valid inode" checks and is dirty, then we'll write - * it back anyway. If it has been reallocated and still being - * initialised, the XFS_INEW check below will catch it. - */ - spin_lock(&ip->i_flags_lock); - if (!ip->i_ino) - goto out_unlock_noent; - - /* avoid new or reclaimable inodes. Leave for reclaim code to flush */ - if (__xfs_iflags_test(ip, XFS_INEW | XFS_IRECLAIMABLE | XFS_IRECLAIM)) - goto out_unlock_noent; - spin_unlock(&ip->i_flags_lock); - - /* nothing to sync during shutdown */ - if (XFS_FORCED_SHUTDOWN(ip->i_mount)) - return -EFSCORRUPTED; - - /* If we can't grab the inode, it must on it's way to reclaim. */ - if (!igrab(inode)) - return -ENOENT; - - /* inode is valid */ - return 0; - -out_unlock_noent: - spin_unlock(&ip->i_flags_lock); - return -ENOENT; -} - -STATIC int -xfs_inode_ag_walk( - struct xfs_mount *mp, - struct xfs_perag *pag, - int (*execute)(struct xfs_inode *ip, int flags, - void *args), - int flags, - void *args, - int tag) -{ - uint32_t first_index; - int last_error = 0; - int skipped; - int done; - int nr_found; - -restart: - done = 0; - skipped = 0; - first_index = 0; - nr_found = 0; - do { - struct xfs_inode *batch[XFS_LOOKUP_BATCH]; - int error = 0; - int i; - - rcu_read_lock(); - - if (tag == -1) - nr_found = radix_tree_gang_lookup(&pag->pag_ici_root, - (void **)batch, first_index, - XFS_LOOKUP_BATCH); - else - nr_found = radix_tree_gang_lookup_tag( - &pag->pag_ici_root, - (void **) batch, first_index, - XFS_LOOKUP_BATCH, tag); - - if (!nr_found) { - rcu_read_unlock(); - break; - } - - /* - * Grab the inodes before we drop the lock. if we found - * nothing, nr == 0 and the loop will be skipped. - */ - for (i = 0; i < nr_found; i++) { - struct xfs_inode *ip = batch[i]; - - if (done || xfs_inode_ag_walk_grab(ip)) - batch[i] = NULL; - - /* - * Update the index for the next lookup. Catch - * overflows into the next AG range which can occur if - * we have inodes in the last block of the AG and we - * are currently pointing to the last inode. - * - * Because we may see inodes that are from the wrong AG - * due to RCU freeing and reallocation, only update the - * index if it lies in this AG. It was a race that lead - * us to see this inode, so another lookup from the - * same index will not find it again. - */ - if (XFS_INO_TO_AGNO(mp, ip->i_ino) != pag->pag_agno) - continue; - first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1); - if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino)) - done = 1; - } - - /* unlock now we've grabbed the inodes. */ - rcu_read_unlock(); - - for (i = 0; i < nr_found; i++) { - if (!batch[i]) - continue; - error = execute(batch[i], flags, args); - IRELE(batch[i]); - if (error == -EAGAIN) { - skipped++; - continue; - } - if (error && last_error != -EFSCORRUPTED) - last_error = error; - } - - /* bail out if the filesystem is corrupted. */ - if (error == -EFSCORRUPTED) - break; - - cond_resched(); - - } while (nr_found && !done); - - if (skipped) { - delay(1); - goto restart; - } - return last_error; -} - -/* - * Background scanning to trim post-EOF preallocated space. This is queued - * based on the 'speculative_prealloc_lifetime' tunable (5m by default). - */ -void -xfs_queue_eofblocks( - struct xfs_mount *mp) -{ - rcu_read_lock(); - if (radix_tree_tagged(&mp->m_perag_tree, XFS_ICI_EOFBLOCKS_TAG)) - queue_delayed_work(mp->m_eofblocks_workqueue, - &mp->m_eofblocks_work, - msecs_to_jiffies(xfs_eofb_secs * 1000)); - rcu_read_unlock(); -} - -void -xfs_eofblocks_worker( - struct work_struct *work) -{ - struct xfs_mount *mp = container_of(to_delayed_work(work), - struct xfs_mount, m_eofblocks_work); - xfs_icache_free_eofblocks(mp, NULL); - xfs_queue_eofblocks(mp); -} - -/* - * Background scanning to trim preallocated CoW space. This is queued - * based on the 'speculative_cow_prealloc_lifetime' tunable (5m by default). - * (We'll just piggyback on the post-EOF prealloc space workqueue.) - */ -STATIC void -xfs_queue_cowblocks( - struct xfs_mount *mp) -{ - rcu_read_lock(); - if (radix_tree_tagged(&mp->m_perag_tree, XFS_ICI_COWBLOCKS_TAG)) - queue_delayed_work(mp->m_eofblocks_workqueue, - &mp->m_cowblocks_work, - msecs_to_jiffies(xfs_cowb_secs * 1000)); - rcu_read_unlock(); -} - -void -xfs_cowblocks_worker( - struct work_struct *work) -{ - struct xfs_mount *mp = container_of(to_delayed_work(work), - struct xfs_mount, m_cowblocks_work); - xfs_icache_free_cowblocks(mp, NULL); - xfs_queue_cowblocks(mp); -} - -int -xfs_inode_ag_iterator( - struct xfs_mount *mp, - int (*execute)(struct xfs_inode *ip, int flags, - void *args), - int flags, - void *args) -{ - struct xfs_perag *pag; - int error = 0; - int last_error = 0; - xfs_agnumber_t ag; - - ag = 0; - while ((pag = xfs_perag_get(mp, ag))) { - ag = pag->pag_agno + 1; - error = xfs_inode_ag_walk(mp, pag, execute, flags, args, -1); - xfs_perag_put(pag); - if (error) { - last_error = error; - if (error == -EFSCORRUPTED) - break; - } - } - return last_error; -} - -int -xfs_inode_ag_iterator_tag( - struct xfs_mount *mp, - int (*execute)(struct xfs_inode *ip, int flags, - void *args), - int flags, - void *args, - int tag) -{ - struct xfs_perag *pag; - int error = 0; - int last_error = 0; - xfs_agnumber_t ag; - - ag = 0; - while ((pag = xfs_perag_get_tag(mp, ag, tag))) { - ag = pag->pag_agno + 1; - error = xfs_inode_ag_walk(mp, pag, execute, flags, args, tag); - xfs_perag_put(pag); - if (error) { - last_error = error; - if (error == -EFSCORRUPTED) - break; - } - } - return last_error; -} - -/* - * Grab the inode for reclaim exclusively. - * Return 0 if we grabbed it, non-zero otherwise. - */ -STATIC int -xfs_reclaim_inode_grab( - struct xfs_inode *ip, - int flags) -{ - ASSERT(rcu_read_lock_held()); - - /* quick check for stale RCU freed inode */ - if (!ip->i_ino) - return 1; - - /* - * If we are asked for non-blocking operation, do unlocked checks to - * see if the inode already is being flushed or in reclaim to avoid - * lock traffic. - */ - if ((flags & SYNC_TRYLOCK) && - __xfs_iflags_test(ip, XFS_IFLOCK | XFS_IRECLAIM)) - return 1; - - /* - * The radix tree lock here protects a thread in xfs_iget from racing - * with us starting reclaim on the inode. Once we have the - * XFS_IRECLAIM flag set it will not touch us. - * - * Due to RCU lookup, we may find inodes that have been freed and only - * have XFS_IRECLAIM set. Indeed, we may see reallocated inodes that - * aren't candidates for reclaim at all, so we must check the - * XFS_IRECLAIMABLE is set first before proceeding to reclaim. - */ - spin_lock(&ip->i_flags_lock); - if (!__xfs_iflags_test(ip, XFS_IRECLAIMABLE) || - __xfs_iflags_test(ip, XFS_IRECLAIM)) { - /* not a reclaim candidate. */ - spin_unlock(&ip->i_flags_lock); - return 1; - } - __xfs_iflags_set(ip, XFS_IRECLAIM); - spin_unlock(&ip->i_flags_lock); - return 0; -} - -/* - * Inodes in different states need to be treated differently. The following - * table lists the inode states and the reclaim actions necessary: - * - * inode state iflush ret required action - * --------------- ---------- --------------- - * bad - reclaim - * shutdown EIO unpin and reclaim - * clean, unpinned 0 reclaim - * stale, unpinned 0 reclaim - * clean, pinned(*) 0 requeue - * stale, pinned EAGAIN requeue - * dirty, async - requeue - * dirty, sync 0 reclaim - * - * (*) dgc: I don't think the clean, pinned state is possible but it gets - * handled anyway given the order of checks implemented. - * - * Also, because we get the flush lock first, we know that any inode that has - * been flushed delwri has had the flush completed by the time we check that - * the inode is clean. - * - * Note that because the inode is flushed delayed write by AIL pushing, the - * flush lock may already be held here and waiting on it can result in very - * long latencies. Hence for sync reclaims, where we wait on the flush lock, - * the caller should push the AIL first before trying to reclaim inodes to - * minimise the amount of time spent waiting. For background relaim, we only - * bother to reclaim clean inodes anyway. - * - * Hence the order of actions after gaining the locks should be: - * bad => reclaim - * shutdown => unpin and reclaim - * pinned, async => requeue - * pinned, sync => unpin - * stale => reclaim - * clean => reclaim - * dirty, async => requeue - * dirty, sync => flush, wait and reclaim - */ -STATIC int -xfs_reclaim_inode( - struct xfs_inode *ip, - struct xfs_perag *pag, - int sync_mode) -{ - struct xfs_buf *bp = NULL; - xfs_ino_t ino = ip->i_ino; /* for radix_tree_delete */ - int error; - -restart: - error = 0; - xfs_ilock(ip, XFS_ILOCK_EXCL); - if (!xfs_iflock_nowait(ip)) { - if (!(sync_mode & SYNC_WAIT)) - goto out; - xfs_iflock(ip); - } - - if (XFS_FORCED_SHUTDOWN(ip->i_mount)) { - xfs_iunpin_wait(ip); - xfs_iflush_abort(ip, false); - goto reclaim; - } - if (xfs_ipincount(ip)) { - if (!(sync_mode & SYNC_WAIT)) - goto out_ifunlock; - xfs_iunpin_wait(ip); - } - if (xfs_iflags_test(ip, XFS_ISTALE)) - goto reclaim; - if (xfs_inode_clean(ip)) - goto reclaim; - - /* - * Never flush out dirty data during non-blocking reclaim, as it would - * just contend with AIL pushing trying to do the same job. - */ - if (!(sync_mode & SYNC_WAIT)) - goto out_ifunlock; - - /* - * Now we have an inode that needs flushing. - * - * Note that xfs_iflush will never block on the inode buffer lock, as - * xfs_ifree_cluster() can lock the inode buffer before it locks the - * ip->i_lock, and we are doing the exact opposite here. As a result, - * doing a blocking xfs_imap_to_bp() to get the cluster buffer would - * result in an ABBA deadlock with xfs_ifree_cluster(). - * - * As xfs_ifree_cluser() must gather all inodes that are active in the - * cache to mark them stale, if we hit this case we don't actually want - * to do IO here - we want the inode marked stale so we can simply - * reclaim it. Hence if we get an EAGAIN error here, just unlock the - * inode, back off and try again. Hopefully the next pass through will - * see the stale flag set on the inode. - */ - error = xfs_iflush(ip, &bp); - if (error == -EAGAIN) { - xfs_iunlock(ip, XFS_ILOCK_EXCL); - /* backoff longer than in xfs_ifree_cluster */ - delay(2); - goto restart; - } - - if (!error) { - error = xfs_bwrite(bp); - xfs_buf_relse(bp); - } - - xfs_iflock(ip); -reclaim: - /* - * Because we use RCU freeing we need to ensure the inode always appears - * to be reclaimed with an invalid inode number when in the free state. - * We do this as early as possible under the ILOCK and flush lock so - * that xfs_iflush_cluster() can be guaranteed to detect races with us - * here. By doing this, we guarantee that once xfs_iflush_cluster has - * locked both the XFS_ILOCK and the flush lock that it will see either - * a valid, flushable inode that will serialise correctly against the - * locks below, or it will see a clean (and invalid) inode that it can - * skip. - */ - spin_lock(&ip->i_flags_lock); - ip->i_flags = XFS_IRECLAIM; - ip->i_ino = 0; - spin_unlock(&ip->i_flags_lock); - - xfs_ifunlock(ip); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - - XFS_STATS_INC(ip->i_mount, xs_ig_reclaims); - /* - * Remove the inode from the per-AG radix tree. - * - * Because radix_tree_delete won't complain even if the item was never - * added to the tree assert that it's been there before to catch - * problems with the inode life time early on. - */ - spin_lock(&pag->pag_ici_lock); - if (!radix_tree_delete(&pag->pag_ici_root, - XFS_INO_TO_AGINO(ip->i_mount, ino))) - ASSERT(0); - xfs_perag_clear_reclaim_tag(pag); - spin_unlock(&pag->pag_ici_lock); - - /* - * Here we do an (almost) spurious inode lock in order to coordinate - * with inode cache radix tree lookups. This is because the lookup - * can reference the inodes in the cache without taking references. - * - * We make that OK here by ensuring that we wait until the inode is - * unlocked after the lookup before we go ahead and free it. - */ - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_qm_dqdetach(ip); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - - __xfs_inode_free(ip); - return error; - -out_ifunlock: - xfs_ifunlock(ip); -out: - xfs_iflags_clear(ip, XFS_IRECLAIM); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - /* - * We could return -EAGAIN here to make reclaim rescan the inode tree in - * a short while. However, this just burns CPU time scanning the tree - * waiting for IO to complete and the reclaim work never goes back to - * the idle state. Instead, return 0 to let the next scheduled - * background reclaim attempt to reclaim the inode again. - */ - return 0; -} - -/* - * Walk the AGs and reclaim the inodes in them. Even if the filesystem is - * corrupted, we still want to try to reclaim all the inodes. If we don't, - * then a shut down during filesystem unmount reclaim walk leak all the - * unreclaimed inodes. - */ -STATIC int -xfs_reclaim_inodes_ag( - struct xfs_mount *mp, - int flags, - int *nr_to_scan) -{ - struct xfs_perag *pag; - int error = 0; - int last_error = 0; - xfs_agnumber_t ag; - int trylock = flags & SYNC_TRYLOCK; - int skipped; - -restart: - ag = 0; - skipped = 0; - while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) { - unsigned long first_index = 0; - int done = 0; - int nr_found = 0; - - ag = pag->pag_agno + 1; - - if (trylock) { - if (!mutex_trylock(&pag->pag_ici_reclaim_lock)) { - skipped++; - xfs_perag_put(pag); - continue; - } - first_index = pag->pag_ici_reclaim_cursor; - } else - mutex_lock(&pag->pag_ici_reclaim_lock); - - do { - struct xfs_inode *batch[XFS_LOOKUP_BATCH]; - int i; - - rcu_read_lock(); - nr_found = radix_tree_gang_lookup_tag( - &pag->pag_ici_root, - (void **)batch, first_index, - XFS_LOOKUP_BATCH, - XFS_ICI_RECLAIM_TAG); - if (!nr_found) { - done = 1; - rcu_read_unlock(); - break; - } - - /* - * Grab the inodes before we drop the lock. if we found - * nothing, nr == 0 and the loop will be skipped. - */ - for (i = 0; i < nr_found; i++) { - struct xfs_inode *ip = batch[i]; - - if (done || xfs_reclaim_inode_grab(ip, flags)) - batch[i] = NULL; - - /* - * Update the index for the next lookup. Catch - * overflows into the next AG range which can - * occur if we have inodes in the last block of - * the AG and we are currently pointing to the - * last inode. - * - * Because we may see inodes that are from the - * wrong AG due to RCU freeing and - * reallocation, only update the index if it - * lies in this AG. It was a race that lead us - * to see this inode, so another lookup from - * the same index will not find it again. - */ - if (XFS_INO_TO_AGNO(mp, ip->i_ino) != - pag->pag_agno) - continue; - first_index = XFS_INO_TO_AGINO(mp, ip->i_ino + 1); - if (first_index < XFS_INO_TO_AGINO(mp, ip->i_ino)) - done = 1; - } - - /* unlock now we've grabbed the inodes. */ - rcu_read_unlock(); - - for (i = 0; i < nr_found; i++) { - if (!batch[i]) - continue; - error = xfs_reclaim_inode(batch[i], pag, flags); - if (error && last_error != -EFSCORRUPTED) - last_error = error; - } - - *nr_to_scan -= XFS_LOOKUP_BATCH; - - cond_resched(); - - } while (nr_found && !done && *nr_to_scan > 0); - - if (trylock && !done) - pag->pag_ici_reclaim_cursor = first_index; - else - pag->pag_ici_reclaim_cursor = 0; - mutex_unlock(&pag->pag_ici_reclaim_lock); - xfs_perag_put(pag); - } - - /* - * if we skipped any AG, and we still have scan count remaining, do - * another pass this time using blocking reclaim semantics (i.e - * waiting on the reclaim locks and ignoring the reclaim cursors). This - * ensure that when we get more reclaimers than AGs we block rather - * than spin trying to execute reclaim. - */ - if (skipped && (flags & SYNC_WAIT) && *nr_to_scan > 0) { - trylock = 0; - goto restart; - } - return last_error; -} - -int -xfs_reclaim_inodes( - xfs_mount_t *mp, - int mode) -{ - int nr_to_scan = INT_MAX; - - return xfs_reclaim_inodes_ag(mp, mode, &nr_to_scan); -} - -/* - * Scan a certain number of inodes for reclaim. - * - * When called we make sure that there is a background (fast) inode reclaim in - * progress, while we will throttle the speed of reclaim via doing synchronous - * reclaim of inodes. That means if we come across dirty inodes, we wait for - * them to be cleaned, which we hope will not be very long due to the - * background walker having already kicked the IO off on those dirty inodes. - */ -long -xfs_reclaim_inodes_nr( - struct xfs_mount *mp, - int nr_to_scan) -{ - /* kick background reclaimer and push the AIL */ - xfs_reclaim_work_queue(mp); - xfs_ail_push_all(mp->m_ail); - - return xfs_reclaim_inodes_ag(mp, SYNC_TRYLOCK | SYNC_WAIT, &nr_to_scan); -} - -/* - * Return the number of reclaimable inodes in the filesystem for - * the shrinker to determine how much to reclaim. - */ -int -xfs_reclaim_inodes_count( - struct xfs_mount *mp) -{ - struct xfs_perag *pag; - xfs_agnumber_t ag = 0; - int reclaimable = 0; - - while ((pag = xfs_perag_get_tag(mp, ag, XFS_ICI_RECLAIM_TAG))) { - ag = pag->pag_agno + 1; - reclaimable += pag->pag_ici_reclaimable; - xfs_perag_put(pag); - } - return reclaimable; -} - -STATIC int -xfs_inode_match_id( - struct xfs_inode *ip, - struct xfs_eofblocks *eofb) -{ - if ((eofb->eof_flags & XFS_EOF_FLAGS_UID) && - !uid_eq(VFS_I(ip)->i_uid, eofb->eof_uid)) - return 0; - - if ((eofb->eof_flags & XFS_EOF_FLAGS_GID) && - !gid_eq(VFS_I(ip)->i_gid, eofb->eof_gid)) - return 0; - - if ((eofb->eof_flags & XFS_EOF_FLAGS_PRID) && - xfs_get_projid(ip) != eofb->eof_prid) - return 0; - - return 1; -} - -/* - * A union-based inode filtering algorithm. Process the inode if any of the - * criteria match. This is for global/internal scans only. - */ -STATIC int -xfs_inode_match_id_union( - struct xfs_inode *ip, - struct xfs_eofblocks *eofb) -{ - if ((eofb->eof_flags & XFS_EOF_FLAGS_UID) && - uid_eq(VFS_I(ip)->i_uid, eofb->eof_uid)) - return 1; - - if ((eofb->eof_flags & XFS_EOF_FLAGS_GID) && - gid_eq(VFS_I(ip)->i_gid, eofb->eof_gid)) - return 1; - - if ((eofb->eof_flags & XFS_EOF_FLAGS_PRID) && - xfs_get_projid(ip) == eofb->eof_prid) - return 1; - - return 0; -} - -STATIC int -xfs_inode_free_eofblocks( - struct xfs_inode *ip, - int flags, - void *args) -{ - int ret; - struct xfs_eofblocks *eofb = args; - bool need_iolock = true; - int match; - - ASSERT(!eofb || (eofb && eofb->eof_scan_owner != 0)); - - if (!xfs_can_free_eofblocks(ip, false)) { - /* inode could be preallocated or append-only */ - trace_xfs_inode_free_eofblocks_invalid(ip); - xfs_inode_clear_eofblocks_tag(ip); - return 0; - } - - /* - * If the mapping is dirty the operation can block and wait for some - * time. Unless we are waiting, skip it. - */ - if (!(flags & SYNC_WAIT) && - mapping_tagged(VFS_I(ip)->i_mapping, PAGECACHE_TAG_DIRTY)) - return 0; - - if (eofb) { - if (eofb->eof_flags & XFS_EOF_FLAGS_UNION) - match = xfs_inode_match_id_union(ip, eofb); - else - match = xfs_inode_match_id(ip, eofb); - if (!match) - return 0; - - /* skip the inode if the file size is too small */ - if (eofb->eof_flags & XFS_EOF_FLAGS_MINFILESIZE && - XFS_ISIZE(ip) < eofb->eof_min_file_size) - return 0; - - /* - * A scan owner implies we already hold the iolock. Skip it in - * xfs_free_eofblocks() to avoid deadlock. This also eliminates - * the possibility of EAGAIN being returned. - */ - if (eofb->eof_scan_owner == ip->i_ino) - need_iolock = false; - } - - ret = xfs_free_eofblocks(ip->i_mount, ip, need_iolock); - - /* don't revisit the inode if we're not waiting */ - if (ret == -EAGAIN && !(flags & SYNC_WAIT)) - ret = 0; - - return ret; -} - -static int -__xfs_icache_free_eofblocks( - struct xfs_mount *mp, - struct xfs_eofblocks *eofb, - int (*execute)(struct xfs_inode *ip, int flags, - void *args), - int tag) -{ - int flags = SYNC_TRYLOCK; - - if (eofb && (eofb->eof_flags & XFS_EOF_FLAGS_SYNC)) - flags = SYNC_WAIT; - - return xfs_inode_ag_iterator_tag(mp, execute, flags, - eofb, tag); -} - -int -xfs_icache_free_eofblocks( - struct xfs_mount *mp, - struct xfs_eofblocks *eofb) -{ - return __xfs_icache_free_eofblocks(mp, eofb, xfs_inode_free_eofblocks, - XFS_ICI_EOFBLOCKS_TAG); -} - -/* - * Run eofblocks scans on the quotas applicable to the inode. For inodes with - * multiple quotas, we don't know exactly which quota caused an allocation - * failure. We make a best effort by including each quota under low free space - * conditions (less than 1% free space) in the scan. - */ -static int -__xfs_inode_free_quota_eofblocks( - struct xfs_inode *ip, - int (*execute)(struct xfs_mount *mp, - struct xfs_eofblocks *eofb)) -{ - int scan = 0; - struct xfs_eofblocks eofb = {0}; - struct xfs_dquot *dq; - - ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); - - /* - * Set the scan owner to avoid a potential livelock. Otherwise, the scan - * can repeatedly trylock on the inode we're currently processing. We - * run a sync scan to increase effectiveness and use the union filter to - * cover all applicable quotas in a single scan. - */ - eofb.eof_scan_owner = ip->i_ino; - eofb.eof_flags = XFS_EOF_FLAGS_UNION|XFS_EOF_FLAGS_SYNC; - - if (XFS_IS_UQUOTA_ENFORCED(ip->i_mount)) { - dq = xfs_inode_dquot(ip, XFS_DQ_USER); - if (dq && xfs_dquot_lowsp(dq)) { - eofb.eof_uid = VFS_I(ip)->i_uid; - eofb.eof_flags |= XFS_EOF_FLAGS_UID; - scan = 1; - } - } - - if (XFS_IS_GQUOTA_ENFORCED(ip->i_mount)) { - dq = xfs_inode_dquot(ip, XFS_DQ_GROUP); - if (dq && xfs_dquot_lowsp(dq)) { - eofb.eof_gid = VFS_I(ip)->i_gid; - eofb.eof_flags |= XFS_EOF_FLAGS_GID; - scan = 1; - } - } - - if (scan) - execute(ip->i_mount, &eofb); - - return scan; -} - -int -xfs_inode_free_quota_eofblocks( - struct xfs_inode *ip) -{ - return __xfs_inode_free_quota_eofblocks(ip, xfs_icache_free_eofblocks); -} - -static void -__xfs_inode_set_eofblocks_tag( - xfs_inode_t *ip, - void (*execute)(struct xfs_mount *mp), - void (*set_tp)(struct xfs_mount *mp, xfs_agnumber_t agno, - int error, unsigned long caller_ip), - int tag) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_perag *pag; - int tagged; - - /* - * Don't bother locking the AG and looking up in the radix trees - * if we already know that we have the tag set. - */ - if (ip->i_flags & XFS_IEOFBLOCKS) - return; - spin_lock(&ip->i_flags_lock); - ip->i_flags |= XFS_IEOFBLOCKS; - spin_unlock(&ip->i_flags_lock); - - pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); - spin_lock(&pag->pag_ici_lock); - - tagged = radix_tree_tagged(&pag->pag_ici_root, tag); - radix_tree_tag_set(&pag->pag_ici_root, - XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino), tag); - if (!tagged) { - /* propagate the eofblocks tag up into the perag radix tree */ - spin_lock(&ip->i_mount->m_perag_lock); - radix_tree_tag_set(&ip->i_mount->m_perag_tree, - XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino), - tag); - spin_unlock(&ip->i_mount->m_perag_lock); - - /* kick off background trimming */ - execute(ip->i_mount); - - set_tp(ip->i_mount, pag->pag_agno, -1, _RET_IP_); - } - - spin_unlock(&pag->pag_ici_lock); - xfs_perag_put(pag); -} - -void -xfs_inode_set_eofblocks_tag( - xfs_inode_t *ip) -{ - trace_xfs_inode_set_eofblocks_tag(ip); - return __xfs_inode_set_eofblocks_tag(ip, xfs_queue_eofblocks, - trace_xfs_perag_set_eofblocks, - XFS_ICI_EOFBLOCKS_TAG); -} - -static void -__xfs_inode_clear_eofblocks_tag( - xfs_inode_t *ip, - void (*clear_tp)(struct xfs_mount *mp, xfs_agnumber_t agno, - int error, unsigned long caller_ip), - int tag) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_perag *pag; - - spin_lock(&ip->i_flags_lock); - ip->i_flags &= ~XFS_IEOFBLOCKS; - spin_unlock(&ip->i_flags_lock); - - pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); - spin_lock(&pag->pag_ici_lock); - - radix_tree_tag_clear(&pag->pag_ici_root, - XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino), tag); - if (!radix_tree_tagged(&pag->pag_ici_root, tag)) { - /* clear the eofblocks tag from the perag radix tree */ - spin_lock(&ip->i_mount->m_perag_lock); - radix_tree_tag_clear(&ip->i_mount->m_perag_tree, - XFS_INO_TO_AGNO(ip->i_mount, ip->i_ino), - tag); - spin_unlock(&ip->i_mount->m_perag_lock); - clear_tp(ip->i_mount, pag->pag_agno, -1, _RET_IP_); - } - - spin_unlock(&pag->pag_ici_lock); - xfs_perag_put(pag); -} - -void -xfs_inode_clear_eofblocks_tag( - xfs_inode_t *ip) -{ - trace_xfs_inode_clear_eofblocks_tag(ip); - return __xfs_inode_clear_eofblocks_tag(ip, - trace_xfs_perag_clear_eofblocks, XFS_ICI_EOFBLOCKS_TAG); -} - -/* - * Automatic CoW Reservation Freeing - * - * These functions automatically garbage collect leftover CoW reservations - * that were made on behalf of a cowextsize hint when we start to run out - * of quota or when the reservations sit around for too long. If the file - * has dirty pages or is undergoing writeback, its CoW reservations will - * be retained. - * - * The actual garbage collection piggybacks off the same code that runs - * the speculative EOF preallocation garbage collector. - */ -STATIC int -xfs_inode_free_cowblocks( - struct xfs_inode *ip, - int flags, - void *args) -{ - int ret; - struct xfs_eofblocks *eofb = args; - bool need_iolock = true; - int match; - - ASSERT(!eofb || (eofb && eofb->eof_scan_owner != 0)); - - if (!xfs_reflink_has_real_cow_blocks(ip)) { - trace_xfs_inode_free_cowblocks_invalid(ip); - xfs_inode_clear_cowblocks_tag(ip); - return 0; - } - - /* - * If the mapping is dirty or under writeback we cannot touch the - * CoW fork. Leave it alone if we're in the midst of a directio. - */ - if (mapping_tagged(VFS_I(ip)->i_mapping, PAGECACHE_TAG_DIRTY) || - mapping_tagged(VFS_I(ip)->i_mapping, PAGECACHE_TAG_WRITEBACK) || - atomic_read(&VFS_I(ip)->i_dio_count)) - return 0; - - if (eofb) { - if (eofb->eof_flags & XFS_EOF_FLAGS_UNION) - match = xfs_inode_match_id_union(ip, eofb); - else - match = xfs_inode_match_id(ip, eofb); - if (!match) - return 0; - - /* skip the inode if the file size is too small */ - if (eofb->eof_flags & XFS_EOF_FLAGS_MINFILESIZE && - XFS_ISIZE(ip) < eofb->eof_min_file_size) - return 0; - - /* - * A scan owner implies we already hold the iolock. Skip it in - * xfs_free_eofblocks() to avoid deadlock. This also eliminates - * the possibility of EAGAIN being returned. - */ - if (eofb->eof_scan_owner == ip->i_ino) - need_iolock = false; - } - - /* Free the CoW blocks */ - if (need_iolock) { - xfs_ilock(ip, XFS_IOLOCK_EXCL); - xfs_ilock(ip, XFS_MMAPLOCK_EXCL); - } - - ret = xfs_reflink_cancel_cow_range(ip, 0, NULLFILEOFF); - - if (need_iolock) { - xfs_iunlock(ip, XFS_MMAPLOCK_EXCL); - xfs_iunlock(ip, XFS_IOLOCK_EXCL); - } - - return ret; -} - -int -xfs_icache_free_cowblocks( - struct xfs_mount *mp, - struct xfs_eofblocks *eofb) -{ - return __xfs_icache_free_eofblocks(mp, eofb, xfs_inode_free_cowblocks, - XFS_ICI_COWBLOCKS_TAG); -} - -int -xfs_inode_free_quota_cowblocks( - struct xfs_inode *ip) -{ - return __xfs_inode_free_quota_eofblocks(ip, xfs_icache_free_cowblocks); -} - -void -xfs_inode_set_cowblocks_tag( - xfs_inode_t *ip) -{ - trace_xfs_inode_set_cowblocks_tag(ip); - return __xfs_inode_set_eofblocks_tag(ip, xfs_queue_cowblocks, - trace_xfs_perag_set_cowblocks, - XFS_ICI_COWBLOCKS_TAG); -} - -void -xfs_inode_clear_cowblocks_tag( - xfs_inode_t *ip) -{ - trace_xfs_inode_clear_cowblocks_tag(ip); - return __xfs_inode_clear_eofblocks_tag(ip, - trace_xfs_perag_clear_cowblocks, XFS_ICI_COWBLOCKS_TAG); -} diff --git a/src/linux/fs/xfs/xfs_icache.h b/src/linux/fs/xfs/xfs_icache.h deleted file mode 100644 index a1e02f4..0000000 --- a/src/linux/fs/xfs/xfs_icache.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2000-2006 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef XFS_SYNC_H -#define XFS_SYNC_H 1 - -struct xfs_mount; -struct xfs_perag; - -struct xfs_eofblocks { - __u32 eof_flags; - kuid_t eof_uid; - kgid_t eof_gid; - prid_t eof_prid; - __u64 eof_min_file_size; - xfs_ino_t eof_scan_owner; -}; - -#define SYNC_WAIT 0x0001 /* wait for i/o to complete */ -#define SYNC_TRYLOCK 0x0002 /* only try to lock inodes */ - -/* - * tags for inode radix tree - */ -#define XFS_ICI_NO_TAG (-1) /* special flag for an untagged lookup - in xfs_inode_ag_iterator */ -#define XFS_ICI_RECLAIM_TAG 0 /* inode is to be reclaimed */ -#define XFS_ICI_EOFBLOCKS_TAG 1 /* inode has blocks beyond EOF */ -#define XFS_ICI_COWBLOCKS_TAG 2 /* inode can have cow blocks to gc */ - -/* - * Flags for xfs_iget() - */ -#define XFS_IGET_CREATE 0x1 -#define XFS_IGET_UNTRUSTED 0x2 -#define XFS_IGET_DONTCACHE 0x4 - -int xfs_iget(struct xfs_mount *mp, struct xfs_trans *tp, xfs_ino_t ino, - uint flags, uint lock_flags, xfs_inode_t **ipp); - -/* recovery needs direct inode allocation capability */ -struct xfs_inode * xfs_inode_alloc(struct xfs_mount *mp, xfs_ino_t ino); -void xfs_inode_free(struct xfs_inode *ip); - -void xfs_reclaim_worker(struct work_struct *work); - -int xfs_reclaim_inodes(struct xfs_mount *mp, int mode); -int xfs_reclaim_inodes_count(struct xfs_mount *mp); -long xfs_reclaim_inodes_nr(struct xfs_mount *mp, int nr_to_scan); - -void xfs_inode_set_reclaim_tag(struct xfs_inode *ip); - -void xfs_inode_set_eofblocks_tag(struct xfs_inode *ip); -void xfs_inode_clear_eofblocks_tag(struct xfs_inode *ip); -int xfs_icache_free_eofblocks(struct xfs_mount *, struct xfs_eofblocks *); -int xfs_inode_free_quota_eofblocks(struct xfs_inode *ip); -void xfs_eofblocks_worker(struct work_struct *); -void xfs_queue_eofblocks(struct xfs_mount *); - -void xfs_inode_set_cowblocks_tag(struct xfs_inode *ip); -void xfs_inode_clear_cowblocks_tag(struct xfs_inode *ip); -int xfs_icache_free_cowblocks(struct xfs_mount *, struct xfs_eofblocks *); -int xfs_inode_free_quota_cowblocks(struct xfs_inode *ip); -void xfs_cowblocks_worker(struct work_struct *); - -int xfs_inode_ag_iterator(struct xfs_mount *mp, - int (*execute)(struct xfs_inode *ip, int flags, void *args), - int flags, void *args); -int xfs_inode_ag_iterator_tag(struct xfs_mount *mp, - int (*execute)(struct xfs_inode *ip, int flags, void *args), - int flags, void *args, int tag); - -static inline int -xfs_fs_eofblocks_from_user( - struct xfs_fs_eofblocks *src, - struct xfs_eofblocks *dst) -{ - if (src->eof_version != XFS_EOFBLOCKS_VERSION) - return -EINVAL; - - if (src->eof_flags & ~XFS_EOF_FLAGS_VALID) - return -EINVAL; - - if (memchr_inv(&src->pad32, 0, sizeof(src->pad32)) || - memchr_inv(src->pad64, 0, sizeof(src->pad64))) - return -EINVAL; - - dst->eof_flags = src->eof_flags; - dst->eof_prid = src->eof_prid; - dst->eof_min_file_size = src->eof_min_file_size; - dst->eof_scan_owner = NULLFSINO; - - dst->eof_uid = INVALID_UID; - if (src->eof_flags & XFS_EOF_FLAGS_UID) { - dst->eof_uid = make_kuid(current_user_ns(), src->eof_uid); - if (!uid_valid(dst->eof_uid)) - return -EINVAL; - } - - dst->eof_gid = INVALID_GID; - if (src->eof_flags & XFS_EOF_FLAGS_GID) { - dst->eof_gid = make_kgid(current_user_ns(), src->eof_gid); - if (!gid_valid(dst->eof_gid)) - return -EINVAL; - } - return 0; -} - -#endif diff --git a/src/linux/fs/xfs/xfs_icreate_item.c b/src/linux/fs/xfs/xfs_icreate_item.c deleted file mode 100644 index d45ca72..0000000 --- a/src/linux/fs/xfs/xfs_icreate_item.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * Copyright (c) 2008-2010, 2013 Dave Chinner - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_mount.h" -#include "xfs_trans.h" -#include "xfs_trans_priv.h" -#include "xfs_error.h" -#include "xfs_icreate_item.h" -#include "xfs_log.h" - -kmem_zone_t *xfs_icreate_zone; /* inode create item zone */ - -static inline struct xfs_icreate_item *ICR_ITEM(struct xfs_log_item *lip) -{ - return container_of(lip, struct xfs_icreate_item, ic_item); -} - -/* - * This returns the number of iovecs needed to log the given inode item. - * - * We only need one iovec for the icreate log structure. - */ -STATIC void -xfs_icreate_item_size( - struct xfs_log_item *lip, - int *nvecs, - int *nbytes) -{ - *nvecs += 1; - *nbytes += sizeof(struct xfs_icreate_log); -} - -/* - * This is called to fill in the vector of log iovecs for the - * given inode create log item. - */ -STATIC void -xfs_icreate_item_format( - struct xfs_log_item *lip, - struct xfs_log_vec *lv) -{ - struct xfs_icreate_item *icp = ICR_ITEM(lip); - struct xfs_log_iovec *vecp = NULL; - - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_ICREATE, - &icp->ic_format, - sizeof(struct xfs_icreate_log)); -} - - -/* Pinning has no meaning for the create item, so just return. */ -STATIC void -xfs_icreate_item_pin( - struct xfs_log_item *lip) -{ -} - - -/* pinning has no meaning for the create item, so just return. */ -STATIC void -xfs_icreate_item_unpin( - struct xfs_log_item *lip, - int remove) -{ -} - -STATIC void -xfs_icreate_item_unlock( - struct xfs_log_item *lip) -{ - struct xfs_icreate_item *icp = ICR_ITEM(lip); - - if (icp->ic_item.li_flags & XFS_LI_ABORTED) - kmem_zone_free(xfs_icreate_zone, icp); - return; -} - -/* - * Because we have ordered buffers being tracked in the AIL for the inode - * creation, we don't need the create item after this. Hence we can free - * the log item and return -1 to tell the caller we're done with the item. - */ -STATIC xfs_lsn_t -xfs_icreate_item_committed( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ - struct xfs_icreate_item *icp = ICR_ITEM(lip); - - kmem_zone_free(xfs_icreate_zone, icp); - return (xfs_lsn_t)-1; -} - -/* item can never get into the AIL */ -STATIC uint -xfs_icreate_item_push( - struct xfs_log_item *lip, - struct list_head *buffer_list) -{ - ASSERT(0); - return XFS_ITEM_SUCCESS; -} - -/* Ordered buffers do the dependency tracking here, so this does nothing. */ -STATIC void -xfs_icreate_item_committing( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ -} - -/* - * This is the ops vector shared by all buf log items. - */ -static struct xfs_item_ops xfs_icreate_item_ops = { - .iop_size = xfs_icreate_item_size, - .iop_format = xfs_icreate_item_format, - .iop_pin = xfs_icreate_item_pin, - .iop_unpin = xfs_icreate_item_unpin, - .iop_push = xfs_icreate_item_push, - .iop_unlock = xfs_icreate_item_unlock, - .iop_committed = xfs_icreate_item_committed, - .iop_committing = xfs_icreate_item_committing, -}; - - -/* - * Initialize the inode log item for a newly allocated (in-core) inode. - * - * Inode extents can only reside within an AG. Hence specify the starting - * block for the inode chunk by offset within an AG as well as the - * length of the allocated extent. - * - * This joins the item to the transaction and marks it dirty so - * that we don't need a separate call to do this, nor does the - * caller need to know anything about the icreate item. - */ -void -xfs_icreate_log( - struct xfs_trans *tp, - xfs_agnumber_t agno, - xfs_agblock_t agbno, - unsigned int count, - unsigned int inode_size, - xfs_agblock_t length, - unsigned int generation) -{ - struct xfs_icreate_item *icp; - - icp = kmem_zone_zalloc(xfs_icreate_zone, KM_SLEEP); - - xfs_log_item_init(tp->t_mountp, &icp->ic_item, XFS_LI_ICREATE, - &xfs_icreate_item_ops); - - icp->ic_format.icl_type = XFS_LI_ICREATE; - icp->ic_format.icl_size = 1; /* single vector */ - icp->ic_format.icl_ag = cpu_to_be32(agno); - icp->ic_format.icl_agbno = cpu_to_be32(agbno); - icp->ic_format.icl_count = cpu_to_be32(count); - icp->ic_format.icl_isize = cpu_to_be32(inode_size); - icp->ic_format.icl_length = cpu_to_be32(length); - icp->ic_format.icl_gen = cpu_to_be32(generation); - - xfs_trans_add_item(tp, &icp->ic_item); - tp->t_flags |= XFS_TRANS_DIRTY; - icp->ic_item.li_desc->lid_flags |= XFS_LID_DIRTY; -} diff --git a/src/linux/fs/xfs/xfs_icreate_item.h b/src/linux/fs/xfs/xfs_icreate_item.h deleted file mode 100644 index 59e89f8..0000000 --- a/src/linux/fs/xfs/xfs_icreate_item.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (c) 2008-2010, Dave Chinner - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef XFS_ICREATE_ITEM_H -#define XFS_ICREATE_ITEM_H 1 - -/* in memory log item structure */ -struct xfs_icreate_item { - struct xfs_log_item ic_item; - struct xfs_icreate_log ic_format; -}; - -extern kmem_zone_t *xfs_icreate_zone; /* inode create item zone */ - -void xfs_icreate_log(struct xfs_trans *tp, xfs_agnumber_t agno, - xfs_agblock_t agbno, unsigned int count, - unsigned int inode_size, xfs_agblock_t length, - unsigned int generation); - -#endif /* XFS_ICREATE_ITEM_H */ diff --git a/src/linux/fs/xfs/xfs_inode.c b/src/linux/fs/xfs/xfs_inode.c deleted file mode 100644 index 4e560e6..0000000 --- a/src/linux/fs/xfs/xfs_inode.c +++ /dev/null @@ -1,3627 +0,0 @@ -/* - * Copyright (c) 2000-2006 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include - -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_inode.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_dir2.h" -#include "xfs_attr_sf.h" -#include "xfs_attr.h" -#include "xfs_trans_space.h" -#include "xfs_trans.h" -#include "xfs_buf_item.h" -#include "xfs_inode_item.h" -#include "xfs_ialloc.h" -#include "xfs_bmap.h" -#include "xfs_bmap_util.h" -#include "xfs_error.h" -#include "xfs_quota.h" -#include "xfs_filestream.h" -#include "xfs_cksum.h" -#include "xfs_trace.h" -#include "xfs_icache.h" -#include "xfs_symlink.h" -#include "xfs_trans_priv.h" -#include "xfs_log.h" -#include "xfs_bmap_btree.h" -#include "xfs_reflink.h" - -kmem_zone_t *xfs_inode_zone; - -/* - * Used in xfs_itruncate_extents(). This is the maximum number of extents - * freed from a file in a single transaction. - */ -#define XFS_ITRUNC_MAX_EXTENTS 2 - -STATIC int xfs_iflush_int(struct xfs_inode *, struct xfs_buf *); -STATIC int xfs_iunlink(struct xfs_trans *, struct xfs_inode *); -STATIC int xfs_iunlink_remove(struct xfs_trans *, struct xfs_inode *); - -/* - * helper function to extract extent size hint from inode - */ -xfs_extlen_t -xfs_get_extsz_hint( - struct xfs_inode *ip) -{ - if ((ip->i_d.di_flags & XFS_DIFLAG_EXTSIZE) && ip->i_d.di_extsize) - return ip->i_d.di_extsize; - if (XFS_IS_REALTIME_INODE(ip)) - return ip->i_mount->m_sb.sb_rextsize; - return 0; -} - -/* - * Helper function to extract CoW extent size hint from inode. - * Between the extent size hint and the CoW extent size hint, we - * return the greater of the two. If the value is zero (automatic), - * use the default size. - */ -xfs_extlen_t -xfs_get_cowextsz_hint( - struct xfs_inode *ip) -{ - xfs_extlen_t a, b; - - a = 0; - if (ip->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE) - a = ip->i_d.di_cowextsize; - b = xfs_get_extsz_hint(ip); - - a = max(a, b); - if (a == 0) - return XFS_DEFAULT_COWEXTSZ_HINT; - return a; -} - -/* - * These two are wrapper routines around the xfs_ilock() routine used to - * centralize some grungy code. They are used in places that wish to lock the - * inode solely for reading the extents. The reason these places can't just - * call xfs_ilock(ip, XFS_ILOCK_SHARED) is that the inode lock also guards to - * bringing in of the extents from disk for a file in b-tree format. If the - * inode is in b-tree format, then we need to lock the inode exclusively until - * the extents are read in. Locking it exclusively all the time would limit - * our parallelism unnecessarily, though. What we do instead is check to see - * if the extents have been read in yet, and only lock the inode exclusively - * if they have not. - * - * The functions return a value which should be given to the corresponding - * xfs_iunlock() call. - */ -uint -xfs_ilock_data_map_shared( - struct xfs_inode *ip) -{ - uint lock_mode = XFS_ILOCK_SHARED; - - if (ip->i_d.di_format == XFS_DINODE_FMT_BTREE && - (ip->i_df.if_flags & XFS_IFEXTENTS) == 0) - lock_mode = XFS_ILOCK_EXCL; - xfs_ilock(ip, lock_mode); - return lock_mode; -} - -uint -xfs_ilock_attr_map_shared( - struct xfs_inode *ip) -{ - uint lock_mode = XFS_ILOCK_SHARED; - - if (ip->i_d.di_aformat == XFS_DINODE_FMT_BTREE && - (ip->i_afp->if_flags & XFS_IFEXTENTS) == 0) - lock_mode = XFS_ILOCK_EXCL; - xfs_ilock(ip, lock_mode); - return lock_mode; -} - -/* - * The xfs inode contains 3 multi-reader locks: the i_iolock the i_mmap_lock and - * the i_lock. This routine allows various combinations of the locks to be - * obtained. - * - * The 3 locks should always be ordered so that the IO lock is obtained first, - * the mmap lock second and the ilock last in order to prevent deadlock. - * - * Basic locking order: - * - * i_iolock -> i_mmap_lock -> page_lock -> i_ilock - * - * mmap_sem locking order: - * - * i_iolock -> page lock -> mmap_sem - * mmap_sem -> i_mmap_lock -> page_lock - * - * The difference in mmap_sem locking order mean that we cannot hold the - * i_mmap_lock over syscall based read(2)/write(2) based IO. These IO paths can - * fault in pages during copy in/out (for buffered IO) or require the mmap_sem - * in get_user_pages() to map the user pages into the kernel address space for - * direct IO. Similarly the i_iolock cannot be taken inside a page fault because - * page faults already hold the mmap_sem. - * - * Hence to serialise fully against both syscall and mmap based IO, we need to - * take both the i_iolock and the i_mmap_lock. These locks should *only* be both - * taken in places where we need to invalidate the page cache in a race - * free manner (e.g. truncate, hole punch and other extent manipulation - * functions). - */ -void -xfs_ilock( - xfs_inode_t *ip, - uint lock_flags) -{ - trace_xfs_ilock(ip, lock_flags, _RET_IP_); - - /* - * You can't set both SHARED and EXCL for the same lock, - * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED, - * and XFS_ILOCK_EXCL are valid values to set in lock_flags. - */ - ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) != - (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)); - ASSERT((lock_flags & (XFS_MMAPLOCK_SHARED | XFS_MMAPLOCK_EXCL)) != - (XFS_MMAPLOCK_SHARED | XFS_MMAPLOCK_EXCL)); - ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) != - (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); - ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_SUBCLASS_MASK)) == 0); - - if (lock_flags & XFS_IOLOCK_EXCL) - mrupdate_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags)); - else if (lock_flags & XFS_IOLOCK_SHARED) - mraccess_nested(&ip->i_iolock, XFS_IOLOCK_DEP(lock_flags)); - - if (lock_flags & XFS_MMAPLOCK_EXCL) - mrupdate_nested(&ip->i_mmaplock, XFS_MMAPLOCK_DEP(lock_flags)); - else if (lock_flags & XFS_MMAPLOCK_SHARED) - mraccess_nested(&ip->i_mmaplock, XFS_MMAPLOCK_DEP(lock_flags)); - - if (lock_flags & XFS_ILOCK_EXCL) - mrupdate_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags)); - else if (lock_flags & XFS_ILOCK_SHARED) - mraccess_nested(&ip->i_lock, XFS_ILOCK_DEP(lock_flags)); -} - -/* - * This is just like xfs_ilock(), except that the caller - * is guaranteed not to sleep. It returns 1 if it gets - * the requested locks and 0 otherwise. If the IO lock is - * obtained but the inode lock cannot be, then the IO lock - * is dropped before returning. - * - * ip -- the inode being locked - * lock_flags -- this parameter indicates the inode's locks to be - * to be locked. See the comment for xfs_ilock() for a list - * of valid values. - */ -int -xfs_ilock_nowait( - xfs_inode_t *ip, - uint lock_flags) -{ - trace_xfs_ilock_nowait(ip, lock_flags, _RET_IP_); - - /* - * You can't set both SHARED and EXCL for the same lock, - * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED, - * and XFS_ILOCK_EXCL are valid values to set in lock_flags. - */ - ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) != - (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)); - ASSERT((lock_flags & (XFS_MMAPLOCK_SHARED | XFS_MMAPLOCK_EXCL)) != - (XFS_MMAPLOCK_SHARED | XFS_MMAPLOCK_EXCL)); - ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) != - (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); - ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_SUBCLASS_MASK)) == 0); - - if (lock_flags & XFS_IOLOCK_EXCL) { - if (!mrtryupdate(&ip->i_iolock)) - goto out; - } else if (lock_flags & XFS_IOLOCK_SHARED) { - if (!mrtryaccess(&ip->i_iolock)) - goto out; - } - - if (lock_flags & XFS_MMAPLOCK_EXCL) { - if (!mrtryupdate(&ip->i_mmaplock)) - goto out_undo_iolock; - } else if (lock_flags & XFS_MMAPLOCK_SHARED) { - if (!mrtryaccess(&ip->i_mmaplock)) - goto out_undo_iolock; - } - - if (lock_flags & XFS_ILOCK_EXCL) { - if (!mrtryupdate(&ip->i_lock)) - goto out_undo_mmaplock; - } else if (lock_flags & XFS_ILOCK_SHARED) { - if (!mrtryaccess(&ip->i_lock)) - goto out_undo_mmaplock; - } - return 1; - -out_undo_mmaplock: - if (lock_flags & XFS_MMAPLOCK_EXCL) - mrunlock_excl(&ip->i_mmaplock); - else if (lock_flags & XFS_MMAPLOCK_SHARED) - mrunlock_shared(&ip->i_mmaplock); -out_undo_iolock: - if (lock_flags & XFS_IOLOCK_EXCL) - mrunlock_excl(&ip->i_iolock); - else if (lock_flags & XFS_IOLOCK_SHARED) - mrunlock_shared(&ip->i_iolock); -out: - return 0; -} - -/* - * xfs_iunlock() is used to drop the inode locks acquired with - * xfs_ilock() and xfs_ilock_nowait(). The caller must pass - * in the flags given to xfs_ilock() or xfs_ilock_nowait() so - * that we know which locks to drop. - * - * ip -- the inode being unlocked - * lock_flags -- this parameter indicates the inode's locks to be - * to be unlocked. See the comment for xfs_ilock() for a list - * of valid values for this parameter. - * - */ -void -xfs_iunlock( - xfs_inode_t *ip, - uint lock_flags) -{ - /* - * You can't set both SHARED and EXCL for the same lock, - * and only XFS_IOLOCK_SHARED, XFS_IOLOCK_EXCL, XFS_ILOCK_SHARED, - * and XFS_ILOCK_EXCL are valid values to set in lock_flags. - */ - ASSERT((lock_flags & (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)) != - (XFS_IOLOCK_SHARED | XFS_IOLOCK_EXCL)); - ASSERT((lock_flags & (XFS_MMAPLOCK_SHARED | XFS_MMAPLOCK_EXCL)) != - (XFS_MMAPLOCK_SHARED | XFS_MMAPLOCK_EXCL)); - ASSERT((lock_flags & (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)) != - (XFS_ILOCK_SHARED | XFS_ILOCK_EXCL)); - ASSERT((lock_flags & ~(XFS_LOCK_MASK | XFS_LOCK_SUBCLASS_MASK)) == 0); - ASSERT(lock_flags != 0); - - if (lock_flags & XFS_IOLOCK_EXCL) - mrunlock_excl(&ip->i_iolock); - else if (lock_flags & XFS_IOLOCK_SHARED) - mrunlock_shared(&ip->i_iolock); - - if (lock_flags & XFS_MMAPLOCK_EXCL) - mrunlock_excl(&ip->i_mmaplock); - else if (lock_flags & XFS_MMAPLOCK_SHARED) - mrunlock_shared(&ip->i_mmaplock); - - if (lock_flags & XFS_ILOCK_EXCL) - mrunlock_excl(&ip->i_lock); - else if (lock_flags & XFS_ILOCK_SHARED) - mrunlock_shared(&ip->i_lock); - - trace_xfs_iunlock(ip, lock_flags, _RET_IP_); -} - -/* - * give up write locks. the i/o lock cannot be held nested - * if it is being demoted. - */ -void -xfs_ilock_demote( - xfs_inode_t *ip, - uint lock_flags) -{ - ASSERT(lock_flags & (XFS_IOLOCK_EXCL|XFS_MMAPLOCK_EXCL|XFS_ILOCK_EXCL)); - ASSERT((lock_flags & - ~(XFS_IOLOCK_EXCL|XFS_MMAPLOCK_EXCL|XFS_ILOCK_EXCL)) == 0); - - if (lock_flags & XFS_ILOCK_EXCL) - mrdemote(&ip->i_lock); - if (lock_flags & XFS_MMAPLOCK_EXCL) - mrdemote(&ip->i_mmaplock); - if (lock_flags & XFS_IOLOCK_EXCL) - mrdemote(&ip->i_iolock); - - trace_xfs_ilock_demote(ip, lock_flags, _RET_IP_); -} - -#if defined(DEBUG) || defined(XFS_WARN) -int -xfs_isilocked( - xfs_inode_t *ip, - uint lock_flags) -{ - if (lock_flags & (XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)) { - if (!(lock_flags & XFS_ILOCK_SHARED)) - return !!ip->i_lock.mr_writer; - return rwsem_is_locked(&ip->i_lock.mr_lock); - } - - if (lock_flags & (XFS_MMAPLOCK_EXCL|XFS_MMAPLOCK_SHARED)) { - if (!(lock_flags & XFS_MMAPLOCK_SHARED)) - return !!ip->i_mmaplock.mr_writer; - return rwsem_is_locked(&ip->i_mmaplock.mr_lock); - } - - if (lock_flags & (XFS_IOLOCK_EXCL|XFS_IOLOCK_SHARED)) { - if (!(lock_flags & XFS_IOLOCK_SHARED)) - return !!ip->i_iolock.mr_writer; - return rwsem_is_locked(&ip->i_iolock.mr_lock); - } - - ASSERT(0); - return 0; -} -#endif - -#ifdef DEBUG -int xfs_locked_n; -int xfs_small_retries; -int xfs_middle_retries; -int xfs_lots_retries; -int xfs_lock_delays; -#endif - -/* - * xfs_lockdep_subclass_ok() is only used in an ASSERT, so is only called when - * DEBUG or XFS_WARN is set. And MAX_LOCKDEP_SUBCLASSES is then only defined - * when CONFIG_LOCKDEP is set. Hence the complex define below to avoid build - * errors and warnings. - */ -#if (defined(DEBUG) || defined(XFS_WARN)) && defined(CONFIG_LOCKDEP) -static bool -xfs_lockdep_subclass_ok( - int subclass) -{ - return subclass < MAX_LOCKDEP_SUBCLASSES; -} -#else -#define xfs_lockdep_subclass_ok(subclass) (true) -#endif - -/* - * Bump the subclass so xfs_lock_inodes() acquires each lock with a different - * value. This can be called for any type of inode lock combination, including - * parent locking. Care must be taken to ensure we don't overrun the subclass - * storage fields in the class mask we build. - */ -static inline int -xfs_lock_inumorder(int lock_mode, int subclass) -{ - int class = 0; - - ASSERT(!(lock_mode & (XFS_ILOCK_PARENT | XFS_ILOCK_RTBITMAP | - XFS_ILOCK_RTSUM))); - ASSERT(xfs_lockdep_subclass_ok(subclass)); - - if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL)) { - ASSERT(subclass <= XFS_IOLOCK_MAX_SUBCLASS); - ASSERT(xfs_lockdep_subclass_ok(subclass + - XFS_IOLOCK_PARENT_VAL)); - class += subclass << XFS_IOLOCK_SHIFT; - if (lock_mode & XFS_IOLOCK_PARENT) - class += XFS_IOLOCK_PARENT_VAL << XFS_IOLOCK_SHIFT; - } - - if (lock_mode & (XFS_MMAPLOCK_SHARED|XFS_MMAPLOCK_EXCL)) { - ASSERT(subclass <= XFS_MMAPLOCK_MAX_SUBCLASS); - class += subclass << XFS_MMAPLOCK_SHIFT; - } - - if (lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL)) { - ASSERT(subclass <= XFS_ILOCK_MAX_SUBCLASS); - class += subclass << XFS_ILOCK_SHIFT; - } - - return (lock_mode & ~XFS_LOCK_SUBCLASS_MASK) | class; -} - -/* - * The following routine will lock n inodes in exclusive mode. We assume the - * caller calls us with the inodes in i_ino order. - * - * We need to detect deadlock where an inode that we lock is in the AIL and we - * start waiting for another inode that is locked by a thread in a long running - * transaction (such as truncate). This can result in deadlock since the long - * running trans might need to wait for the inode we just locked in order to - * push the tail and free space in the log. - * - * xfs_lock_inodes() can only be used to lock one type of lock at a time - - * the iolock, the mmaplock or the ilock, but not more than one at a time. If we - * lock more than one at a time, lockdep will report false positives saying we - * have violated locking orders. - */ -static void -xfs_lock_inodes( - xfs_inode_t **ips, - int inodes, - uint lock_mode) -{ - int attempts = 0, i, j, try_lock; - xfs_log_item_t *lp; - - /* - * Currently supports between 2 and 5 inodes with exclusive locking. We - * support an arbitrary depth of locking here, but absolute limits on - * inodes depend on the the type of locking and the limits placed by - * lockdep annotations in xfs_lock_inumorder. These are all checked by - * the asserts. - */ - ASSERT(ips && inodes >= 2 && inodes <= 5); - ASSERT(lock_mode & (XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL | - XFS_ILOCK_EXCL)); - ASSERT(!(lock_mode & (XFS_IOLOCK_SHARED | XFS_MMAPLOCK_SHARED | - XFS_ILOCK_SHARED))); - ASSERT(!(lock_mode & XFS_IOLOCK_EXCL) || - inodes <= XFS_IOLOCK_MAX_SUBCLASS + 1); - ASSERT(!(lock_mode & XFS_MMAPLOCK_EXCL) || - inodes <= XFS_MMAPLOCK_MAX_SUBCLASS + 1); - ASSERT(!(lock_mode & XFS_ILOCK_EXCL) || - inodes <= XFS_ILOCK_MAX_SUBCLASS + 1); - - if (lock_mode & XFS_IOLOCK_EXCL) { - ASSERT(!(lock_mode & (XFS_MMAPLOCK_EXCL | XFS_ILOCK_EXCL))); - } else if (lock_mode & XFS_MMAPLOCK_EXCL) - ASSERT(!(lock_mode & XFS_ILOCK_EXCL)); - - try_lock = 0; - i = 0; -again: - for (; i < inodes; i++) { - ASSERT(ips[i]); - - if (i && (ips[i] == ips[i - 1])) /* Already locked */ - continue; - - /* - * If try_lock is not set yet, make sure all locked inodes are - * not in the AIL. If any are, set try_lock to be used later. - */ - if (!try_lock) { - for (j = (i - 1); j >= 0 && !try_lock; j--) { - lp = (xfs_log_item_t *)ips[j]->i_itemp; - if (lp && (lp->li_flags & XFS_LI_IN_AIL)) - try_lock++; - } - } - - /* - * If any of the previous locks we have locked is in the AIL, - * we must TRY to get the second and subsequent locks. If - * we can't get any, we must release all we have - * and try again. - */ - if (!try_lock) { - xfs_ilock(ips[i], xfs_lock_inumorder(lock_mode, i)); - continue; - } - - /* try_lock means we have an inode locked that is in the AIL. */ - ASSERT(i != 0); - if (xfs_ilock_nowait(ips[i], xfs_lock_inumorder(lock_mode, i))) - continue; - - /* - * Unlock all previous guys and try again. xfs_iunlock will try - * to push the tail if the inode is in the AIL. - */ - attempts++; - for (j = i - 1; j >= 0; j--) { - /* - * Check to see if we've already unlocked this one. Not - * the first one going back, and the inode ptr is the - * same. - */ - if (j != (i - 1) && ips[j] == ips[j + 1]) - continue; - - xfs_iunlock(ips[j], lock_mode); - } - - if ((attempts % 5) == 0) { - delay(1); /* Don't just spin the CPU */ -#ifdef DEBUG - xfs_lock_delays++; -#endif - } - i = 0; - try_lock = 0; - goto again; - } - -#ifdef DEBUG - if (attempts) { - if (attempts < 5) xfs_small_retries++; - else if (attempts < 100) xfs_middle_retries++; - else xfs_lots_retries++; - } else { - xfs_locked_n++; - } -#endif -} - -/* - * xfs_lock_two_inodes() can only be used to lock one type of lock at a time - - * the iolock, the mmaplock or the ilock, but not more than one at a time. If we - * lock more than one at a time, lockdep will report false positives saying we - * have violated locking orders. - */ -void -xfs_lock_two_inodes( - xfs_inode_t *ip0, - xfs_inode_t *ip1, - uint lock_mode) -{ - xfs_inode_t *temp; - int attempts = 0; - xfs_log_item_t *lp; - - if (lock_mode & (XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL)) { - ASSERT(!(lock_mode & (XFS_MMAPLOCK_SHARED|XFS_MMAPLOCK_EXCL))); - ASSERT(!(lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL))); - } else if (lock_mode & (XFS_MMAPLOCK_SHARED|XFS_MMAPLOCK_EXCL)) - ASSERT(!(lock_mode & (XFS_ILOCK_SHARED|XFS_ILOCK_EXCL))); - - ASSERT(ip0->i_ino != ip1->i_ino); - - if (ip0->i_ino > ip1->i_ino) { - temp = ip0; - ip0 = ip1; - ip1 = temp; - } - - again: - xfs_ilock(ip0, xfs_lock_inumorder(lock_mode, 0)); - - /* - * If the first lock we have locked is in the AIL, we must TRY to get - * the second lock. If we can't get it, we must release the first one - * and try again. - */ - lp = (xfs_log_item_t *)ip0->i_itemp; - if (lp && (lp->li_flags & XFS_LI_IN_AIL)) { - if (!xfs_ilock_nowait(ip1, xfs_lock_inumorder(lock_mode, 1))) { - xfs_iunlock(ip0, lock_mode); - if ((++attempts % 5) == 0) - delay(1); /* Don't just spin the CPU */ - goto again; - } - } else { - xfs_ilock(ip1, xfs_lock_inumorder(lock_mode, 1)); - } -} - - -void -__xfs_iflock( - struct xfs_inode *ip) -{ - wait_queue_head_t *wq = bit_waitqueue(&ip->i_flags, __XFS_IFLOCK_BIT); - DEFINE_WAIT_BIT(wait, &ip->i_flags, __XFS_IFLOCK_BIT); - - do { - prepare_to_wait_exclusive(wq, &wait.wait, TASK_UNINTERRUPTIBLE); - if (xfs_isiflocked(ip)) - io_schedule(); - } while (!xfs_iflock_nowait(ip)); - - finish_wait(wq, &wait.wait); -} - -STATIC uint -_xfs_dic2xflags( - __uint16_t di_flags, - uint64_t di_flags2, - bool has_attr) -{ - uint flags = 0; - - if (di_flags & XFS_DIFLAG_ANY) { - if (di_flags & XFS_DIFLAG_REALTIME) - flags |= FS_XFLAG_REALTIME; - if (di_flags & XFS_DIFLAG_PREALLOC) - flags |= FS_XFLAG_PREALLOC; - if (di_flags & XFS_DIFLAG_IMMUTABLE) - flags |= FS_XFLAG_IMMUTABLE; - if (di_flags & XFS_DIFLAG_APPEND) - flags |= FS_XFLAG_APPEND; - if (di_flags & XFS_DIFLAG_SYNC) - flags |= FS_XFLAG_SYNC; - if (di_flags & XFS_DIFLAG_NOATIME) - flags |= FS_XFLAG_NOATIME; - if (di_flags & XFS_DIFLAG_NODUMP) - flags |= FS_XFLAG_NODUMP; - if (di_flags & XFS_DIFLAG_RTINHERIT) - flags |= FS_XFLAG_RTINHERIT; - if (di_flags & XFS_DIFLAG_PROJINHERIT) - flags |= FS_XFLAG_PROJINHERIT; - if (di_flags & XFS_DIFLAG_NOSYMLINKS) - flags |= FS_XFLAG_NOSYMLINKS; - if (di_flags & XFS_DIFLAG_EXTSIZE) - flags |= FS_XFLAG_EXTSIZE; - if (di_flags & XFS_DIFLAG_EXTSZINHERIT) - flags |= FS_XFLAG_EXTSZINHERIT; - if (di_flags & XFS_DIFLAG_NODEFRAG) - flags |= FS_XFLAG_NODEFRAG; - if (di_flags & XFS_DIFLAG_FILESTREAM) - flags |= FS_XFLAG_FILESTREAM; - } - - if (di_flags2 & XFS_DIFLAG2_ANY) { - if (di_flags2 & XFS_DIFLAG2_DAX) - flags |= FS_XFLAG_DAX; - if (di_flags2 & XFS_DIFLAG2_COWEXTSIZE) - flags |= FS_XFLAG_COWEXTSIZE; - } - - if (has_attr) - flags |= FS_XFLAG_HASATTR; - - return flags; -} - -uint -xfs_ip2xflags( - struct xfs_inode *ip) -{ - struct xfs_icdinode *dic = &ip->i_d; - - return _xfs_dic2xflags(dic->di_flags, dic->di_flags2, XFS_IFORK_Q(ip)); -} - -/* - * Lookups up an inode from "name". If ci_name is not NULL, then a CI match - * is allowed, otherwise it has to be an exact match. If a CI match is found, - * ci_name->name will point to a the actual name (caller must free) or - * will be set to NULL if an exact match is found. - */ -int -xfs_lookup( - xfs_inode_t *dp, - struct xfs_name *name, - xfs_inode_t **ipp, - struct xfs_name *ci_name) -{ - xfs_ino_t inum; - int error; - - trace_xfs_lookup(dp, name); - - if (XFS_FORCED_SHUTDOWN(dp->i_mount)) - return -EIO; - - xfs_ilock(dp, XFS_IOLOCK_SHARED); - error = xfs_dir_lookup(NULL, dp, name, &inum, ci_name); - if (error) - goto out_unlock; - - error = xfs_iget(dp->i_mount, NULL, inum, 0, 0, ipp); - if (error) - goto out_free_name; - - xfs_iunlock(dp, XFS_IOLOCK_SHARED); - return 0; - -out_free_name: - if (ci_name) - kmem_free(ci_name->name); -out_unlock: - xfs_iunlock(dp, XFS_IOLOCK_SHARED); - *ipp = NULL; - return error; -} - -/* - * Allocate an inode on disk and return a copy of its in-core version. - * The in-core inode is locked exclusively. Set mode, nlink, and rdev - * appropriately within the inode. The uid and gid for the inode are - * set according to the contents of the given cred structure. - * - * Use xfs_dialloc() to allocate the on-disk inode. If xfs_dialloc() - * has a free inode available, call xfs_iget() to obtain the in-core - * version of the allocated inode. Finally, fill in the inode and - * log its initial contents. In this case, ialloc_context would be - * set to NULL. - * - * If xfs_dialloc() does not have an available inode, it will replenish - * its supply by doing an allocation. Since we can only do one - * allocation within a transaction without deadlocks, we must commit - * the current transaction before returning the inode itself. - * In this case, therefore, we will set ialloc_context and return. - * The caller should then commit the current transaction, start a new - * transaction, and call xfs_ialloc() again to actually get the inode. - * - * To ensure that some other process does not grab the inode that - * was allocated during the first call to xfs_ialloc(), this routine - * also returns the [locked] bp pointing to the head of the freelist - * as ialloc_context. The caller should hold this buffer across - * the commit and pass it back into this routine on the second call. - * - * If we are allocating quota inodes, we do not have a parent inode - * to attach to or associate with (i.e. pip == NULL) because they - * are not linked into the directory structure - they are attached - * directly to the superblock - and so have no parent. - */ -static int -xfs_ialloc( - xfs_trans_t *tp, - xfs_inode_t *pip, - umode_t mode, - xfs_nlink_t nlink, - xfs_dev_t rdev, - prid_t prid, - int okalloc, - xfs_buf_t **ialloc_context, - xfs_inode_t **ipp) -{ - struct xfs_mount *mp = tp->t_mountp; - xfs_ino_t ino; - xfs_inode_t *ip; - uint flags; - int error; - struct timespec tv; - struct inode *inode; - - /* - * Call the space management code to pick - * the on-disk inode to be allocated. - */ - error = xfs_dialloc(tp, pip ? pip->i_ino : 0, mode, okalloc, - ialloc_context, &ino); - if (error) - return error; - if (*ialloc_context || ino == NULLFSINO) { - *ipp = NULL; - return 0; - } - ASSERT(*ialloc_context == NULL); - - /* - * Get the in-core inode with the lock held exclusively. - * This is because we're setting fields here we need - * to prevent others from looking at until we're done. - */ - error = xfs_iget(mp, tp, ino, XFS_IGET_CREATE, - XFS_ILOCK_EXCL, &ip); - if (error) - return error; - ASSERT(ip != NULL); - inode = VFS_I(ip); - - /* - * We always convert v1 inodes to v2 now - we only support filesystems - * with >= v2 inode capability, so there is no reason for ever leaving - * an inode in v1 format. - */ - if (ip->i_d.di_version == 1) - ip->i_d.di_version = 2; - - inode->i_mode = mode; - set_nlink(inode, nlink); - ip->i_d.di_uid = xfs_kuid_to_uid(current_fsuid()); - ip->i_d.di_gid = xfs_kgid_to_gid(current_fsgid()); - xfs_set_projid(ip, prid); - - if (pip && XFS_INHERIT_GID(pip)) { - ip->i_d.di_gid = pip->i_d.di_gid; - if ((VFS_I(pip)->i_mode & S_ISGID) && S_ISDIR(mode)) - inode->i_mode |= S_ISGID; - } - - /* - * If the group ID of the new file does not match the effective group - * ID or one of the supplementary group IDs, the S_ISGID bit is cleared - * (and only if the irix_sgid_inherit compatibility variable is set). - */ - if ((irix_sgid_inherit) && - (inode->i_mode & S_ISGID) && - (!in_group_p(xfs_gid_to_kgid(ip->i_d.di_gid)))) - inode->i_mode &= ~S_ISGID; - - ip->i_d.di_size = 0; - ip->i_d.di_nextents = 0; - ASSERT(ip->i_d.di_nblocks == 0); - - tv = current_time(inode); - inode->i_mtime = tv; - inode->i_atime = tv; - inode->i_ctime = tv; - - ip->i_d.di_extsize = 0; - ip->i_d.di_dmevmask = 0; - ip->i_d.di_dmstate = 0; - ip->i_d.di_flags = 0; - - if (ip->i_d.di_version == 3) { - inode->i_version = 1; - ip->i_d.di_flags2 = 0; - ip->i_d.di_cowextsize = 0; - ip->i_d.di_crtime.t_sec = (__int32_t)tv.tv_sec; - ip->i_d.di_crtime.t_nsec = (__int32_t)tv.tv_nsec; - } - - - flags = XFS_ILOG_CORE; - switch (mode & S_IFMT) { - case S_IFIFO: - case S_IFCHR: - case S_IFBLK: - case S_IFSOCK: - ip->i_d.di_format = XFS_DINODE_FMT_DEV; - ip->i_df.if_u2.if_rdev = rdev; - ip->i_df.if_flags = 0; - flags |= XFS_ILOG_DEV; - break; - case S_IFREG: - case S_IFDIR: - if (pip && (pip->i_d.di_flags & XFS_DIFLAG_ANY)) { - uint64_t di_flags2 = 0; - uint di_flags = 0; - - if (S_ISDIR(mode)) { - if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) - di_flags |= XFS_DIFLAG_RTINHERIT; - if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) { - di_flags |= XFS_DIFLAG_EXTSZINHERIT; - ip->i_d.di_extsize = pip->i_d.di_extsize; - } - if (pip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) - di_flags |= XFS_DIFLAG_PROJINHERIT; - } else if (S_ISREG(mode)) { - if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) - di_flags |= XFS_DIFLAG_REALTIME; - if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) { - di_flags |= XFS_DIFLAG_EXTSIZE; - ip->i_d.di_extsize = pip->i_d.di_extsize; - } - } - if ((pip->i_d.di_flags & XFS_DIFLAG_NOATIME) && - xfs_inherit_noatime) - di_flags |= XFS_DIFLAG_NOATIME; - if ((pip->i_d.di_flags & XFS_DIFLAG_NODUMP) && - xfs_inherit_nodump) - di_flags |= XFS_DIFLAG_NODUMP; - if ((pip->i_d.di_flags & XFS_DIFLAG_SYNC) && - xfs_inherit_sync) - di_flags |= XFS_DIFLAG_SYNC; - if ((pip->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) && - xfs_inherit_nosymlinks) - di_flags |= XFS_DIFLAG_NOSYMLINKS; - if ((pip->i_d.di_flags & XFS_DIFLAG_NODEFRAG) && - xfs_inherit_nodefrag) - di_flags |= XFS_DIFLAG_NODEFRAG; - if (pip->i_d.di_flags & XFS_DIFLAG_FILESTREAM) - di_flags |= XFS_DIFLAG_FILESTREAM; - if (pip->i_d.di_flags2 & XFS_DIFLAG2_DAX) - di_flags2 |= XFS_DIFLAG2_DAX; - - ip->i_d.di_flags |= di_flags; - ip->i_d.di_flags2 |= di_flags2; - } - if (pip && - (pip->i_d.di_flags2 & XFS_DIFLAG2_ANY) && - pip->i_d.di_version == 3 && - ip->i_d.di_version == 3) { - if (pip->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE) { - ip->i_d.di_flags2 |= XFS_DIFLAG2_COWEXTSIZE; - ip->i_d.di_cowextsize = pip->i_d.di_cowextsize; - } - } - /* FALLTHROUGH */ - case S_IFLNK: - ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; - ip->i_df.if_flags = XFS_IFEXTENTS; - ip->i_df.if_bytes = ip->i_df.if_real_bytes = 0; - ip->i_df.if_u1.if_extents = NULL; - break; - default: - ASSERT(0); - } - /* - * Attribute fork settings for new inode. - */ - ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; - ip->i_d.di_anextents = 0; - - /* - * Log the new values stuffed into the inode. - */ - xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); - xfs_trans_log_inode(tp, ip, flags); - - /* now that we have an i_mode we can setup the inode structure */ - xfs_setup_inode(ip); - - *ipp = ip; - return 0; -} - -/* - * Allocates a new inode from disk and return a pointer to the - * incore copy. This routine will internally commit the current - * transaction and allocate a new one if the Space Manager needed - * to do an allocation to replenish the inode free-list. - * - * This routine is designed to be called from xfs_create and - * xfs_create_dir. - * - */ -int -xfs_dir_ialloc( - xfs_trans_t **tpp, /* input: current transaction; - output: may be a new transaction. */ - xfs_inode_t *dp, /* directory within whose allocate - the inode. */ - umode_t mode, - xfs_nlink_t nlink, - xfs_dev_t rdev, - prid_t prid, /* project id */ - int okalloc, /* ok to allocate new space */ - xfs_inode_t **ipp, /* pointer to inode; it will be - locked. */ - int *committed) - -{ - xfs_trans_t *tp; - xfs_inode_t *ip; - xfs_buf_t *ialloc_context = NULL; - int code; - void *dqinfo; - uint tflags; - - tp = *tpp; - ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); - - /* - * xfs_ialloc will return a pointer to an incore inode if - * the Space Manager has an available inode on the free - * list. Otherwise, it will do an allocation and replenish - * the freelist. Since we can only do one allocation per - * transaction without deadlocks, we will need to commit the - * current transaction and start a new one. We will then - * need to call xfs_ialloc again to get the inode. - * - * If xfs_ialloc did an allocation to replenish the freelist, - * it returns the bp containing the head of the freelist as - * ialloc_context. We will hold a lock on it across the - * transaction commit so that no other process can steal - * the inode(s) that we've just allocated. - */ - code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, okalloc, - &ialloc_context, &ip); - - /* - * Return an error if we were unable to allocate a new inode. - * This should only happen if we run out of space on disk or - * encounter a disk error. - */ - if (code) { - *ipp = NULL; - return code; - } - if (!ialloc_context && !ip) { - *ipp = NULL; - return -ENOSPC; - } - - /* - * If the AGI buffer is non-NULL, then we were unable to get an - * inode in one operation. We need to commit the current - * transaction and call xfs_ialloc() again. It is guaranteed - * to succeed the second time. - */ - if (ialloc_context) { - /* - * Normally, xfs_trans_commit releases all the locks. - * We call bhold to hang on to the ialloc_context across - * the commit. Holding this buffer prevents any other - * processes from doing any allocations in this - * allocation group. - */ - xfs_trans_bhold(tp, ialloc_context); - - /* - * We want the quota changes to be associated with the next - * transaction, NOT this one. So, detach the dqinfo from this - * and attach it to the next transaction. - */ - dqinfo = NULL; - tflags = 0; - if (tp->t_dqinfo) { - dqinfo = (void *)tp->t_dqinfo; - tp->t_dqinfo = NULL; - tflags = tp->t_flags & XFS_TRANS_DQ_DIRTY; - tp->t_flags &= ~(XFS_TRANS_DQ_DIRTY); - } - - code = xfs_trans_roll(&tp, NULL); - if (committed != NULL) - *committed = 1; - - /* - * Re-attach the quota info that we detached from prev trx. - */ - if (dqinfo) { - tp->t_dqinfo = dqinfo; - tp->t_flags |= tflags; - } - - if (code) { - xfs_buf_relse(ialloc_context); - *tpp = tp; - *ipp = NULL; - return code; - } - xfs_trans_bjoin(tp, ialloc_context); - - /* - * Call ialloc again. Since we've locked out all - * other allocations in this allocation group, - * this call should always succeed. - */ - code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, - okalloc, &ialloc_context, &ip); - - /* - * If we get an error at this point, return to the caller - * so that the current transaction can be aborted. - */ - if (code) { - *tpp = tp; - *ipp = NULL; - return code; - } - ASSERT(!ialloc_context && ip); - - } else { - if (committed != NULL) - *committed = 0; - } - - *ipp = ip; - *tpp = tp; - - return 0; -} - -/* - * Decrement the link count on an inode & log the change. If this causes the - * link count to go to zero, move the inode to AGI unlinked list so that it can - * be freed when the last active reference goes away via xfs_inactive(). - */ -static int /* error */ -xfs_droplink( - xfs_trans_t *tp, - xfs_inode_t *ip) -{ - xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG); - - drop_nlink(VFS_I(ip)); - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - - if (VFS_I(ip)->i_nlink) - return 0; - - return xfs_iunlink(tp, ip); -} - -/* - * Increment the link count on an inode & log the change. - */ -static int -xfs_bumplink( - xfs_trans_t *tp, - xfs_inode_t *ip) -{ - xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG); - - ASSERT(ip->i_d.di_version > 1); - inc_nlink(VFS_I(ip)); - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - return 0; -} - -int -xfs_create( - xfs_inode_t *dp, - struct xfs_name *name, - umode_t mode, - xfs_dev_t rdev, - xfs_inode_t **ipp) -{ - int is_dir = S_ISDIR(mode); - struct xfs_mount *mp = dp->i_mount; - struct xfs_inode *ip = NULL; - struct xfs_trans *tp = NULL; - int error; - struct xfs_defer_ops dfops; - xfs_fsblock_t first_block; - bool unlock_dp_on_error = false; - prid_t prid; - struct xfs_dquot *udqp = NULL; - struct xfs_dquot *gdqp = NULL; - struct xfs_dquot *pdqp = NULL; - struct xfs_trans_res *tres; - uint resblks; - - trace_xfs_create(dp, name); - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - prid = xfs_get_initial_prid(dp); - - /* - * Make sure that we have allocated dquot(s) on disk. - */ - error = xfs_qm_vop_dqalloc(dp, xfs_kuid_to_uid(current_fsuid()), - xfs_kgid_to_gid(current_fsgid()), prid, - XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, - &udqp, &gdqp, &pdqp); - if (error) - return error; - - if (is_dir) { - rdev = 0; - resblks = XFS_MKDIR_SPACE_RES(mp, name->len); - tres = &M_RES(mp)->tr_mkdir; - } else { - resblks = XFS_CREATE_SPACE_RES(mp, name->len); - tres = &M_RES(mp)->tr_create; - } - - /* - * Initially assume that the file does not exist and - * reserve the resources for that case. If that is not - * the case we'll drop the one we have and get a more - * appropriate transaction later. - */ - error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp); - if (error == -ENOSPC) { - /* flush outstanding delalloc blocks and retry */ - xfs_flush_inodes(mp); - error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp); - } - if (error == -ENOSPC) { - /* No space at all so try a "no-allocation" reservation */ - resblks = 0; - error = xfs_trans_alloc(mp, tres, 0, 0, 0, &tp); - } - if (error) - goto out_release_inode; - - xfs_ilock(dp, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL | - XFS_IOLOCK_PARENT | XFS_ILOCK_PARENT); - unlock_dp_on_error = true; - - xfs_defer_init(&dfops, &first_block); - - /* - * Reserve disk quota and the inode. - */ - error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, - pdqp, resblks, 1, 0); - if (error) - goto out_trans_cancel; - - if (!resblks) { - error = xfs_dir_canenter(tp, dp, name); - if (error) - goto out_trans_cancel; - } - - /* - * A newly created regular or special file just has one directory - * entry pointing to them, but a directory also the "." entry - * pointing to itself. - */ - error = xfs_dir_ialloc(&tp, dp, mode, is_dir ? 2 : 1, rdev, - prid, resblks > 0, &ip, NULL); - if (error) - goto out_trans_cancel; - - /* - * Now we join the directory inode to the transaction. We do not do it - * earlier because xfs_dir_ialloc might commit the previous transaction - * (and release all the locks). An error from here on will result in - * the transaction cancel unlocking dp so don't do it explicitly in the - * error path. - */ - xfs_trans_ijoin(tp, dp, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); - unlock_dp_on_error = false; - - error = xfs_dir_createname(tp, dp, name, ip->i_ino, - &first_block, &dfops, resblks ? - resblks - XFS_IALLOC_SPACE_RES(mp) : 0); - if (error) { - ASSERT(error != -ENOSPC); - goto out_trans_cancel; - } - xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); - xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); - - if (is_dir) { - error = xfs_dir_init(tp, ip, dp); - if (error) - goto out_bmap_cancel; - - error = xfs_bumplink(tp, dp); - if (error) - goto out_bmap_cancel; - } - - /* - * If this is a synchronous mount, make sure that the - * create transaction goes to disk before returning to - * the user. - */ - if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) - xfs_trans_set_sync(tp); - - /* - * Attach the dquot(s) to the inodes and modify them incore. - * These ids of the inode couldn't have changed since the new - * inode has been locked ever since it was created. - */ - xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp); - - error = xfs_defer_finish(&tp, &dfops, NULL); - if (error) - goto out_bmap_cancel; - - error = xfs_trans_commit(tp); - if (error) - goto out_release_inode; - - xfs_qm_dqrele(udqp); - xfs_qm_dqrele(gdqp); - xfs_qm_dqrele(pdqp); - - *ipp = ip; - return 0; - - out_bmap_cancel: - xfs_defer_cancel(&dfops); - out_trans_cancel: - xfs_trans_cancel(tp); - out_release_inode: - /* - * Wait until after the current transaction is aborted to finish the - * setup of the inode and release the inode. This prevents recursive - * transactions and deadlocks from xfs_inactive. - */ - if (ip) { - xfs_finish_inode_setup(ip); - IRELE(ip); - } - - xfs_qm_dqrele(udqp); - xfs_qm_dqrele(gdqp); - xfs_qm_dqrele(pdqp); - - if (unlock_dp_on_error) - xfs_iunlock(dp, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); - return error; -} - -int -xfs_create_tmpfile( - struct xfs_inode *dp, - struct dentry *dentry, - umode_t mode, - struct xfs_inode **ipp) -{ - struct xfs_mount *mp = dp->i_mount; - struct xfs_inode *ip = NULL; - struct xfs_trans *tp = NULL; - int error; - prid_t prid; - struct xfs_dquot *udqp = NULL; - struct xfs_dquot *gdqp = NULL; - struct xfs_dquot *pdqp = NULL; - struct xfs_trans_res *tres; - uint resblks; - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - prid = xfs_get_initial_prid(dp); - - /* - * Make sure that we have allocated dquot(s) on disk. - */ - error = xfs_qm_vop_dqalloc(dp, xfs_kuid_to_uid(current_fsuid()), - xfs_kgid_to_gid(current_fsgid()), prid, - XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, - &udqp, &gdqp, &pdqp); - if (error) - return error; - - resblks = XFS_IALLOC_SPACE_RES(mp); - tres = &M_RES(mp)->tr_create_tmpfile; - - error = xfs_trans_alloc(mp, tres, resblks, 0, 0, &tp); - if (error == -ENOSPC) { - /* No space at all so try a "no-allocation" reservation */ - resblks = 0; - error = xfs_trans_alloc(mp, tres, 0, 0, 0, &tp); - } - if (error) - goto out_release_inode; - - error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, - pdqp, resblks, 1, 0); - if (error) - goto out_trans_cancel; - - error = xfs_dir_ialloc(&tp, dp, mode, 1, 0, - prid, resblks > 0, &ip, NULL); - if (error) - goto out_trans_cancel; - - if (mp->m_flags & XFS_MOUNT_WSYNC) - xfs_trans_set_sync(tp); - - /* - * Attach the dquot(s) to the inodes and modify them incore. - * These ids of the inode couldn't have changed since the new - * inode has been locked ever since it was created. - */ - xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp); - - error = xfs_iunlink(tp, ip); - if (error) - goto out_trans_cancel; - - error = xfs_trans_commit(tp); - if (error) - goto out_release_inode; - - xfs_qm_dqrele(udqp); - xfs_qm_dqrele(gdqp); - xfs_qm_dqrele(pdqp); - - *ipp = ip; - return 0; - - out_trans_cancel: - xfs_trans_cancel(tp); - out_release_inode: - /* - * Wait until after the current transaction is aborted to finish the - * setup of the inode and release the inode. This prevents recursive - * transactions and deadlocks from xfs_inactive. - */ - if (ip) { - xfs_finish_inode_setup(ip); - IRELE(ip); - } - - xfs_qm_dqrele(udqp); - xfs_qm_dqrele(gdqp); - xfs_qm_dqrele(pdqp); - - return error; -} - -int -xfs_link( - xfs_inode_t *tdp, - xfs_inode_t *sip, - struct xfs_name *target_name) -{ - xfs_mount_t *mp = tdp->i_mount; - xfs_trans_t *tp; - int error; - struct xfs_defer_ops dfops; - xfs_fsblock_t first_block; - int resblks; - - trace_xfs_link(tdp, target_name); - - ASSERT(!S_ISDIR(VFS_I(sip)->i_mode)); - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - error = xfs_qm_dqattach(sip, 0); - if (error) - goto std_return; - - error = xfs_qm_dqattach(tdp, 0); - if (error) - goto std_return; - - resblks = XFS_LINK_SPACE_RES(mp, target_name->len); - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link, resblks, 0, 0, &tp); - if (error == -ENOSPC) { - resblks = 0; - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_link, 0, 0, 0, &tp); - } - if (error) - goto std_return; - - xfs_ilock(tdp, XFS_IOLOCK_EXCL | XFS_IOLOCK_PARENT); - xfs_lock_two_inodes(sip, tdp, XFS_ILOCK_EXCL); - - xfs_trans_ijoin(tp, sip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, tdp, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); - - /* - * If we are using project inheritance, we only allow hard link - * creation in our tree when the project IDs are the same; else - * the tree quota mechanism could be circumvented. - */ - if (unlikely((tdp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) && - (xfs_get_projid(tdp) != xfs_get_projid(sip)))) { - error = -EXDEV; - goto error_return; - } - - if (!resblks) { - error = xfs_dir_canenter(tp, tdp, target_name); - if (error) - goto error_return; - } - - xfs_defer_init(&dfops, &first_block); - - /* - * Handle initial link state of O_TMPFILE inode - */ - if (VFS_I(sip)->i_nlink == 0) { - error = xfs_iunlink_remove(tp, sip); - if (error) - goto error_return; - } - - error = xfs_dir_createname(tp, tdp, target_name, sip->i_ino, - &first_block, &dfops, resblks); - if (error) - goto error_return; - xfs_trans_ichgtime(tp, tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); - xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE); - - error = xfs_bumplink(tp, sip); - if (error) - goto error_return; - - /* - * If this is a synchronous mount, make sure that the - * link transaction goes to disk before returning to - * the user. - */ - if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) - xfs_trans_set_sync(tp); - - error = xfs_defer_finish(&tp, &dfops, NULL); - if (error) { - xfs_defer_cancel(&dfops); - goto error_return; - } - - return xfs_trans_commit(tp); - - error_return: - xfs_trans_cancel(tp); - std_return: - return error; -} - -/* - * Free up the underlying blocks past new_size. The new size must be smaller - * than the current size. This routine can be used both for the attribute and - * data fork, and does not modify the inode size, which is left to the caller. - * - * The transaction passed to this routine must have made a permanent log - * reservation of at least XFS_ITRUNCATE_LOG_RES. This routine may commit the - * given transaction and start new ones, so make sure everything involved in - * the transaction is tidy before calling here. Some transaction will be - * returned to the caller to be committed. The incoming transaction must - * already include the inode, and both inode locks must be held exclusively. - * The inode must also be "held" within the transaction. On return the inode - * will be "held" within the returned transaction. This routine does NOT - * require any disk space to be reserved for it within the transaction. - * - * If we get an error, we must return with the inode locked and linked into the - * current transaction. This keeps things simple for the higher level code, - * because it always knows that the inode is locked and held in the transaction - * that returns to it whether errors occur or not. We don't mark the inode - * dirty on error so that transactions can be easily aborted if possible. - */ -int -xfs_itruncate_extents( - struct xfs_trans **tpp, - struct xfs_inode *ip, - int whichfork, - xfs_fsize_t new_size) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_trans *tp = *tpp; - struct xfs_defer_ops dfops; - xfs_fsblock_t first_block; - xfs_fileoff_t first_unmap_block; - xfs_fileoff_t last_block; - xfs_filblks_t unmap_len; - int error = 0; - int done = 0; - - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - ASSERT(!atomic_read(&VFS_I(ip)->i_count) || - xfs_isilocked(ip, XFS_IOLOCK_EXCL)); - ASSERT(new_size <= XFS_ISIZE(ip)); - ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); - ASSERT(ip->i_itemp != NULL); - ASSERT(ip->i_itemp->ili_lock_flags == 0); - ASSERT(!XFS_NOT_DQATTACHED(mp, ip)); - - trace_xfs_itruncate_extents_start(ip, new_size); - - /* - * Since it is possible for space to become allocated beyond - * the end of the file (in a crash where the space is allocated - * but the inode size is not yet updated), simply remove any - * blocks which show up between the new EOF and the maximum - * possible file size. If the first block to be removed is - * beyond the maximum file size (ie it is the same as last_block), - * then there is nothing to do. - */ - first_unmap_block = XFS_B_TO_FSB(mp, (xfs_ufsize_t)new_size); - last_block = XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes); - if (first_unmap_block == last_block) - return 0; - - ASSERT(first_unmap_block < last_block); - unmap_len = last_block - first_unmap_block + 1; - while (!done) { - xfs_defer_init(&dfops, &first_block); - error = xfs_bunmapi(tp, ip, - first_unmap_block, unmap_len, - xfs_bmapi_aflag(whichfork), - XFS_ITRUNC_MAX_EXTENTS, - &first_block, &dfops, - &done); - if (error) - goto out_bmap_cancel; - - /* - * Duplicate the transaction that has the permanent - * reservation and commit the old transaction. - */ - error = xfs_defer_finish(&tp, &dfops, ip); - if (error) - goto out_bmap_cancel; - - error = xfs_trans_roll(&tp, ip); - if (error) - goto out; - } - - /* Remove all pending CoW reservations. */ - error = xfs_reflink_cancel_cow_blocks(ip, &tp, first_unmap_block, - last_block); - if (error) - goto out; - - /* - * Clear the reflink flag if we truncated everything. - */ - if (ip->i_d.di_nblocks == 0 && xfs_is_reflink_inode(ip)) { - ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK; - xfs_inode_clear_cowblocks_tag(ip); - } - - /* - * Always re-log the inode so that our permanent transaction can keep - * on rolling it forward in the log. - */ - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - - trace_xfs_itruncate_extents_end(ip, new_size); - -out: - *tpp = tp; - return error; -out_bmap_cancel: - /* - * If the bunmapi call encounters an error, return to the caller where - * the transaction can be properly aborted. We just need to make sure - * we're not holding any resources that we were not when we came in. - */ - xfs_defer_cancel(&dfops); - goto out; -} - -int -xfs_release( - xfs_inode_t *ip) -{ - xfs_mount_t *mp = ip->i_mount; - int error; - - if (!S_ISREG(VFS_I(ip)->i_mode) || (VFS_I(ip)->i_mode == 0)) - return 0; - - /* If this is a read-only mount, don't do this (would generate I/O) */ - if (mp->m_flags & XFS_MOUNT_RDONLY) - return 0; - - if (!XFS_FORCED_SHUTDOWN(mp)) { - int truncated; - - /* - * If we previously truncated this file and removed old data - * in the process, we want to initiate "early" writeout on - * the last close. This is an attempt to combat the notorious - * NULL files problem which is particularly noticeable from a - * truncate down, buffered (re-)write (delalloc), followed by - * a crash. What we are effectively doing here is - * significantly reducing the time window where we'd otherwise - * be exposed to that problem. - */ - truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED); - if (truncated) { - xfs_iflags_clear(ip, XFS_IDIRTY_RELEASE); - if (ip->i_delayed_blks > 0) { - error = filemap_flush(VFS_I(ip)->i_mapping); - if (error) - return error; - } - } - } - - if (VFS_I(ip)->i_nlink == 0) - return 0; - - if (xfs_can_free_eofblocks(ip, false)) { - - /* - * If we can't get the iolock just skip truncating the blocks - * past EOF because we could deadlock with the mmap_sem - * otherwise. We'll get another chance to drop them once the - * last reference to the inode is dropped, so we'll never leak - * blocks permanently. - * - * Further, check if the inode is being opened, written and - * closed frequently and we have delayed allocation blocks - * outstanding (e.g. streaming writes from the NFS server), - * truncating the blocks past EOF will cause fragmentation to - * occur. - * - * In this case don't do the truncation, either, but we have to - * be careful how we detect this case. Blocks beyond EOF show - * up as i_delayed_blks even when the inode is clean, so we - * need to truncate them away first before checking for a dirty - * release. Hence on the first dirty close we will still remove - * the speculative allocation, but after that we will leave it - * in place. - */ - if (xfs_iflags_test(ip, XFS_IDIRTY_RELEASE)) - return 0; - - error = xfs_free_eofblocks(mp, ip, true); - if (error && error != -EAGAIN) - return error; - - /* delalloc blocks after truncation means it really is dirty */ - if (ip->i_delayed_blks) - xfs_iflags_set(ip, XFS_IDIRTY_RELEASE); - } - return 0; -} - -/* - * xfs_inactive_truncate - * - * Called to perform a truncate when an inode becomes unlinked. - */ -STATIC int -xfs_inactive_truncate( - struct xfs_inode *ip) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_trans *tp; - int error; - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp); - if (error) { - ASSERT(XFS_FORCED_SHUTDOWN(mp)); - return error; - } - - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, 0); - - /* - * Log the inode size first to prevent stale data exposure in the event - * of a system crash before the truncate completes. See the related - * comment in xfs_vn_setattr_size() for details. - */ - ip->i_d.di_size = 0; - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - - error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0); - if (error) - goto error_trans_cancel; - - ASSERT(ip->i_d.di_nextents == 0); - - error = xfs_trans_commit(tp); - if (error) - goto error_unlock; - - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return 0; - -error_trans_cancel: - xfs_trans_cancel(tp); -error_unlock: - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return error; -} - -/* - * xfs_inactive_ifree() - * - * Perform the inode free when an inode is unlinked. - */ -STATIC int -xfs_inactive_ifree( - struct xfs_inode *ip) -{ - struct xfs_defer_ops dfops; - xfs_fsblock_t first_block; - struct xfs_mount *mp = ip->i_mount; - struct xfs_trans *tp; - int error; - - /* - * The ifree transaction might need to allocate blocks for record - * insertion to the finobt. We don't want to fail here at ENOSPC, so - * allow ifree to dip into the reserved block pool if necessary. - * - * Freeing large sets of inodes generally means freeing inode chunks, - * directory and file data blocks, so this should be relatively safe. - * Only under severe circumstances should it be possible to free enough - * inodes to exhaust the reserve block pool via finobt expansion while - * at the same time not creating free space in the filesystem. - * - * Send a warning if the reservation does happen to fail, as the inode - * now remains allocated and sits on the unlinked list until the fs is - * repaired. - */ - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ifree, - XFS_IFREE_SPACE_RES(mp), 0, XFS_TRANS_RESERVE, &tp); - if (error) { - if (error == -ENOSPC) { - xfs_warn_ratelimited(mp, - "Failed to remove inode(s) from unlinked list. " - "Please free space, unmount and run xfs_repair."); - } else { - ASSERT(XFS_FORCED_SHUTDOWN(mp)); - } - return error; - } - - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, 0); - - xfs_defer_init(&dfops, &first_block); - error = xfs_ifree(tp, ip, &dfops); - if (error) { - /* - * If we fail to free the inode, shut down. The cancel - * might do that, we need to make sure. Otherwise the - * inode might be lost for a long time or forever. - */ - if (!XFS_FORCED_SHUTDOWN(mp)) { - xfs_notice(mp, "%s: xfs_ifree returned error %d", - __func__, error); - xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR); - } - xfs_trans_cancel(tp); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return error; - } - - /* - * Credit the quota account(s). The inode is gone. - */ - xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_ICOUNT, -1); - - /* - * Just ignore errors at this point. There is nothing we can do except - * to try to keep going. Make sure it's not a silent error. - */ - error = xfs_defer_finish(&tp, &dfops, NULL); - if (error) { - xfs_notice(mp, "%s: xfs_defer_finish returned error %d", - __func__, error); - xfs_defer_cancel(&dfops); - } - error = xfs_trans_commit(tp); - if (error) - xfs_notice(mp, "%s: xfs_trans_commit returned error %d", - __func__, error); - - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return 0; -} - -/* - * xfs_inactive - * - * This is called when the vnode reference count for the vnode - * goes to zero. If the file has been unlinked, then it must - * now be truncated. Also, we clear all of the read-ahead state - * kept for the inode here since the file is now closed. - */ -void -xfs_inactive( - xfs_inode_t *ip) -{ - struct xfs_mount *mp; - int error; - int truncate = 0; - - /* - * If the inode is already free, then there can be nothing - * to clean up here. - */ - if (VFS_I(ip)->i_mode == 0) { - ASSERT(ip->i_df.if_real_bytes == 0); - ASSERT(ip->i_df.if_broot_bytes == 0); - return; - } - - mp = ip->i_mount; - ASSERT(!xfs_iflags_test(ip, XFS_IRECOVERY)); - - /* If this is a read-only mount, don't do this (would generate I/O) */ - if (mp->m_flags & XFS_MOUNT_RDONLY) - return; - - if (VFS_I(ip)->i_nlink != 0) { - /* - * force is true because we are evicting an inode from the - * cache. Post-eof blocks must be freed, lest we end up with - * broken free space accounting. - */ - if (xfs_can_free_eofblocks(ip, true)) - xfs_free_eofblocks(mp, ip, false); - - return; - } - - if (S_ISREG(VFS_I(ip)->i_mode) && - (ip->i_d.di_size != 0 || XFS_ISIZE(ip) != 0 || - ip->i_d.di_nextents > 0 || ip->i_delayed_blks > 0)) - truncate = 1; - - error = xfs_qm_dqattach(ip, 0); - if (error) - return; - - if (S_ISLNK(VFS_I(ip)->i_mode)) - error = xfs_inactive_symlink(ip); - else if (truncate) - error = xfs_inactive_truncate(ip); - if (error) - return; - - /* - * If there are attributes associated with the file then blow them away - * now. The code calls a routine that recursively deconstructs the - * attribute fork. If also blows away the in-core attribute fork. - */ - if (XFS_IFORK_Q(ip)) { - error = xfs_attr_inactive(ip); - if (error) - return; - } - - ASSERT(!ip->i_afp); - ASSERT(ip->i_d.di_anextents == 0); - ASSERT(ip->i_d.di_forkoff == 0); - - /* - * Free the inode. - */ - error = xfs_inactive_ifree(ip); - if (error) - return; - - /* - * Release the dquots held by inode, if any. - */ - xfs_qm_dqdetach(ip); -} - -/* - * This is called when the inode's link count goes to 0 or we are creating a - * tmpfile via O_TMPFILE. In the case of a tmpfile, @ignore_linkcount will be - * set to true as the link count is dropped to zero by the VFS after we've - * created the file successfully, so we have to add it to the unlinked list - * while the link count is non-zero. - * - * We place the on-disk inode on a list in the AGI. It will be pulled from this - * list when the inode is freed. - */ -STATIC int -xfs_iunlink( - struct xfs_trans *tp, - struct xfs_inode *ip) -{ - xfs_mount_t *mp = tp->t_mountp; - xfs_agi_t *agi; - xfs_dinode_t *dip; - xfs_buf_t *agibp; - xfs_buf_t *ibp; - xfs_agino_t agino; - short bucket_index; - int offset; - int error; - - ASSERT(VFS_I(ip)->i_mode != 0); - - /* - * Get the agi buffer first. It ensures lock ordering - * on the list. - */ - error = xfs_read_agi(mp, tp, XFS_INO_TO_AGNO(mp, ip->i_ino), &agibp); - if (error) - return error; - agi = XFS_BUF_TO_AGI(agibp); - - /* - * Get the index into the agi hash table for the - * list this inode will go on. - */ - agino = XFS_INO_TO_AGINO(mp, ip->i_ino); - ASSERT(agino != 0); - bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS; - ASSERT(agi->agi_unlinked[bucket_index]); - ASSERT(be32_to_cpu(agi->agi_unlinked[bucket_index]) != agino); - - if (agi->agi_unlinked[bucket_index] != cpu_to_be32(NULLAGINO)) { - /* - * There is already another inode in the bucket we need - * to add ourselves to. Add us at the front of the list. - * Here we put the head pointer into our next pointer, - * and then we fall through to point the head at us. - */ - error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &ibp, - 0, 0); - if (error) - return error; - - ASSERT(dip->di_next_unlinked == cpu_to_be32(NULLAGINO)); - dip->di_next_unlinked = agi->agi_unlinked[bucket_index]; - offset = ip->i_imap.im_boffset + - offsetof(xfs_dinode_t, di_next_unlinked); - - /* need to recalc the inode CRC if appropriate */ - xfs_dinode_calc_crc(mp, dip); - - xfs_trans_inode_buf(tp, ibp); - xfs_trans_log_buf(tp, ibp, offset, - (offset + sizeof(xfs_agino_t) - 1)); - xfs_inobp_check(mp, ibp); - } - - /* - * Point the bucket head pointer at the inode being inserted. - */ - ASSERT(agino != 0); - agi->agi_unlinked[bucket_index] = cpu_to_be32(agino); - offset = offsetof(xfs_agi_t, agi_unlinked) + - (sizeof(xfs_agino_t) * bucket_index); - xfs_trans_buf_set_type(tp, agibp, XFS_BLFT_AGI_BUF); - xfs_trans_log_buf(tp, agibp, offset, - (offset + sizeof(xfs_agino_t) - 1)); - return 0; -} - -/* - * Pull the on-disk inode from the AGI unlinked list. - */ -STATIC int -xfs_iunlink_remove( - xfs_trans_t *tp, - xfs_inode_t *ip) -{ - xfs_ino_t next_ino; - xfs_mount_t *mp; - xfs_agi_t *agi; - xfs_dinode_t *dip; - xfs_buf_t *agibp; - xfs_buf_t *ibp; - xfs_agnumber_t agno; - xfs_agino_t agino; - xfs_agino_t next_agino; - xfs_buf_t *last_ibp; - xfs_dinode_t *last_dip = NULL; - short bucket_index; - int offset, last_offset = 0; - int error; - - mp = tp->t_mountp; - agno = XFS_INO_TO_AGNO(mp, ip->i_ino); - - /* - * Get the agi buffer first. It ensures lock ordering - * on the list. - */ - error = xfs_read_agi(mp, tp, agno, &agibp); - if (error) - return error; - - agi = XFS_BUF_TO_AGI(agibp); - - /* - * Get the index into the agi hash table for the - * list this inode will go on. - */ - agino = XFS_INO_TO_AGINO(mp, ip->i_ino); - ASSERT(agino != 0); - bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS; - ASSERT(agi->agi_unlinked[bucket_index] != cpu_to_be32(NULLAGINO)); - ASSERT(agi->agi_unlinked[bucket_index]); - - if (be32_to_cpu(agi->agi_unlinked[bucket_index]) == agino) { - /* - * We're at the head of the list. Get the inode's on-disk - * buffer to see if there is anyone after us on the list. - * Only modify our next pointer if it is not already NULLAGINO. - * This saves us the overhead of dealing with the buffer when - * there is no need to change it. - */ - error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &ibp, - 0, 0); - if (error) { - xfs_warn(mp, "%s: xfs_imap_to_bp returned error %d.", - __func__, error); - return error; - } - next_agino = be32_to_cpu(dip->di_next_unlinked); - ASSERT(next_agino != 0); - if (next_agino != NULLAGINO) { - dip->di_next_unlinked = cpu_to_be32(NULLAGINO); - offset = ip->i_imap.im_boffset + - offsetof(xfs_dinode_t, di_next_unlinked); - - /* need to recalc the inode CRC if appropriate */ - xfs_dinode_calc_crc(mp, dip); - - xfs_trans_inode_buf(tp, ibp); - xfs_trans_log_buf(tp, ibp, offset, - (offset + sizeof(xfs_agino_t) - 1)); - xfs_inobp_check(mp, ibp); - } else { - xfs_trans_brelse(tp, ibp); - } - /* - * Point the bucket head pointer at the next inode. - */ - ASSERT(next_agino != 0); - ASSERT(next_agino != agino); - agi->agi_unlinked[bucket_index] = cpu_to_be32(next_agino); - offset = offsetof(xfs_agi_t, agi_unlinked) + - (sizeof(xfs_agino_t) * bucket_index); - xfs_trans_buf_set_type(tp, agibp, XFS_BLFT_AGI_BUF); - xfs_trans_log_buf(tp, agibp, offset, - (offset + sizeof(xfs_agino_t) - 1)); - } else { - /* - * We need to search the list for the inode being freed. - */ - next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]); - last_ibp = NULL; - while (next_agino != agino) { - struct xfs_imap imap; - - if (last_ibp) - xfs_trans_brelse(tp, last_ibp); - - imap.im_blkno = 0; - next_ino = XFS_AGINO_TO_INO(mp, agno, next_agino); - - error = xfs_imap(mp, tp, next_ino, &imap, 0); - if (error) { - xfs_warn(mp, - "%s: xfs_imap returned error %d.", - __func__, error); - return error; - } - - error = xfs_imap_to_bp(mp, tp, &imap, &last_dip, - &last_ibp, 0, 0); - if (error) { - xfs_warn(mp, - "%s: xfs_imap_to_bp returned error %d.", - __func__, error); - return error; - } - - last_offset = imap.im_boffset; - next_agino = be32_to_cpu(last_dip->di_next_unlinked); - ASSERT(next_agino != NULLAGINO); - ASSERT(next_agino != 0); - } - - /* - * Now last_ibp points to the buffer previous to us on the - * unlinked list. Pull us from the list. - */ - error = xfs_imap_to_bp(mp, tp, &ip->i_imap, &dip, &ibp, - 0, 0); - if (error) { - xfs_warn(mp, "%s: xfs_imap_to_bp(2) returned error %d.", - __func__, error); - return error; - } - next_agino = be32_to_cpu(dip->di_next_unlinked); - ASSERT(next_agino != 0); - ASSERT(next_agino != agino); - if (next_agino != NULLAGINO) { - dip->di_next_unlinked = cpu_to_be32(NULLAGINO); - offset = ip->i_imap.im_boffset + - offsetof(xfs_dinode_t, di_next_unlinked); - - /* need to recalc the inode CRC if appropriate */ - xfs_dinode_calc_crc(mp, dip); - - xfs_trans_inode_buf(tp, ibp); - xfs_trans_log_buf(tp, ibp, offset, - (offset + sizeof(xfs_agino_t) - 1)); - xfs_inobp_check(mp, ibp); - } else { - xfs_trans_brelse(tp, ibp); - } - /* - * Point the previous inode on the list to the next inode. - */ - last_dip->di_next_unlinked = cpu_to_be32(next_agino); - ASSERT(next_agino != 0); - offset = last_offset + offsetof(xfs_dinode_t, di_next_unlinked); - - /* need to recalc the inode CRC if appropriate */ - xfs_dinode_calc_crc(mp, last_dip); - - xfs_trans_inode_buf(tp, last_ibp); - xfs_trans_log_buf(tp, last_ibp, offset, - (offset + sizeof(xfs_agino_t) - 1)); - xfs_inobp_check(mp, last_ibp); - } - return 0; -} - -/* - * A big issue when freeing the inode cluster is that we _cannot_ skip any - * inodes that are in memory - they all must be marked stale and attached to - * the cluster buffer. - */ -STATIC int -xfs_ifree_cluster( - xfs_inode_t *free_ip, - xfs_trans_t *tp, - struct xfs_icluster *xic) -{ - xfs_mount_t *mp = free_ip->i_mount; - int blks_per_cluster; - int inodes_per_cluster; - int nbufs; - int i, j; - int ioffset; - xfs_daddr_t blkno; - xfs_buf_t *bp; - xfs_inode_t *ip; - xfs_inode_log_item_t *iip; - xfs_log_item_t *lip; - struct xfs_perag *pag; - xfs_ino_t inum; - - inum = xic->first_ino; - pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, inum)); - blks_per_cluster = xfs_icluster_size_fsb(mp); - inodes_per_cluster = blks_per_cluster << mp->m_sb.sb_inopblog; - nbufs = mp->m_ialloc_blks / blks_per_cluster; - - for (j = 0; j < nbufs; j++, inum += inodes_per_cluster) { - /* - * The allocation bitmap tells us which inodes of the chunk were - * physically allocated. Skip the cluster if an inode falls into - * a sparse region. - */ - ioffset = inum - xic->first_ino; - if ((xic->alloc & XFS_INOBT_MASK(ioffset)) == 0) { - ASSERT(do_mod(ioffset, inodes_per_cluster) == 0); - continue; - } - - blkno = XFS_AGB_TO_DADDR(mp, XFS_INO_TO_AGNO(mp, inum), - XFS_INO_TO_AGBNO(mp, inum)); - - /* - * We obtain and lock the backing buffer first in the process - * here, as we have to ensure that any dirty inode that we - * can't get the flush lock on is attached to the buffer. - * If we scan the in-memory inodes first, then buffer IO can - * complete before we get a lock on it, and hence we may fail - * to mark all the active inodes on the buffer stale. - */ - bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, blkno, - mp->m_bsize * blks_per_cluster, - XBF_UNMAPPED); - - if (!bp) - return -ENOMEM; - - /* - * This buffer may not have been correctly initialised as we - * didn't read it from disk. That's not important because we are - * only using to mark the buffer as stale in the log, and to - * attach stale cached inodes on it. That means it will never be - * dispatched for IO. If it is, we want to know about it, and we - * want it to fail. We can acheive this by adding a write - * verifier to the buffer. - */ - bp->b_ops = &xfs_inode_buf_ops; - - /* - * Walk the inodes already attached to the buffer and mark them - * stale. These will all have the flush locks held, so an - * in-memory inode walk can't lock them. By marking them all - * stale first, we will not attempt to lock them in the loop - * below as the XFS_ISTALE flag will be set. - */ - lip = bp->b_fspriv; - while (lip) { - if (lip->li_type == XFS_LI_INODE) { - iip = (xfs_inode_log_item_t *)lip; - ASSERT(iip->ili_logged == 1); - lip->li_cb = xfs_istale_done; - xfs_trans_ail_copy_lsn(mp->m_ail, - &iip->ili_flush_lsn, - &iip->ili_item.li_lsn); - xfs_iflags_set(iip->ili_inode, XFS_ISTALE); - } - lip = lip->li_bio_list; - } - - - /* - * For each inode in memory attempt to add it to the inode - * buffer and set it up for being staled on buffer IO - * completion. This is safe as we've locked out tail pushing - * and flushing by locking the buffer. - * - * We have already marked every inode that was part of a - * transaction stale above, which means there is no point in - * even trying to lock them. - */ - for (i = 0; i < inodes_per_cluster; i++) { -retry: - rcu_read_lock(); - ip = radix_tree_lookup(&pag->pag_ici_root, - XFS_INO_TO_AGINO(mp, (inum + i))); - - /* Inode not in memory, nothing to do */ - if (!ip) { - rcu_read_unlock(); - continue; - } - - /* - * because this is an RCU protected lookup, we could - * find a recently freed or even reallocated inode - * during the lookup. We need to check under the - * i_flags_lock for a valid inode here. Skip it if it - * is not valid, the wrong inode or stale. - */ - spin_lock(&ip->i_flags_lock); - if (ip->i_ino != inum + i || - __xfs_iflags_test(ip, XFS_ISTALE)) { - spin_unlock(&ip->i_flags_lock); - rcu_read_unlock(); - continue; - } - spin_unlock(&ip->i_flags_lock); - - /* - * Don't try to lock/unlock the current inode, but we - * _cannot_ skip the other inodes that we did not find - * in the list attached to the buffer and are not - * already marked stale. If we can't lock it, back off - * and retry. - */ - if (ip != free_ip && - !xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) { - rcu_read_unlock(); - delay(1); - goto retry; - } - rcu_read_unlock(); - - xfs_iflock(ip); - xfs_iflags_set(ip, XFS_ISTALE); - - /* - * we don't need to attach clean inodes or those only - * with unlogged changes (which we throw away, anyway). - */ - iip = ip->i_itemp; - if (!iip || xfs_inode_clean(ip)) { - ASSERT(ip != free_ip); - xfs_ifunlock(ip); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - continue; - } - - iip->ili_last_fields = iip->ili_fields; - iip->ili_fields = 0; - iip->ili_fsync_fields = 0; - iip->ili_logged = 1; - xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn, - &iip->ili_item.li_lsn); - - xfs_buf_attach_iodone(bp, xfs_istale_done, - &iip->ili_item); - - if (ip != free_ip) - xfs_iunlock(ip, XFS_ILOCK_EXCL); - } - - xfs_trans_stale_inode_buf(tp, bp); - xfs_trans_binval(tp, bp); - } - - xfs_perag_put(pag); - return 0; -} - -/* - * This is called to return an inode to the inode free list. - * The inode should already be truncated to 0 length and have - * no pages associated with it. This routine also assumes that - * the inode is already a part of the transaction. - * - * The on-disk copy of the inode will have been added to the list - * of unlinked inodes in the AGI. We need to remove the inode from - * that list atomically with respect to freeing it here. - */ -int -xfs_ifree( - xfs_trans_t *tp, - xfs_inode_t *ip, - struct xfs_defer_ops *dfops) -{ - int error; - struct xfs_icluster xic = { 0 }; - - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - ASSERT(VFS_I(ip)->i_nlink == 0); - ASSERT(ip->i_d.di_nextents == 0); - ASSERT(ip->i_d.di_anextents == 0); - ASSERT(ip->i_d.di_size == 0 || !S_ISREG(VFS_I(ip)->i_mode)); - ASSERT(ip->i_d.di_nblocks == 0); - - /* - * Pull the on-disk inode from the AGI unlinked list. - */ - error = xfs_iunlink_remove(tp, ip); - if (error) - return error; - - error = xfs_difree(tp, ip->i_ino, dfops, &xic); - if (error) - return error; - - VFS_I(ip)->i_mode = 0; /* mark incore inode as free */ - ip->i_d.di_flags = 0; - ip->i_d.di_dmevmask = 0; - ip->i_d.di_forkoff = 0; /* mark the attr fork not in use */ - ip->i_d.di_format = XFS_DINODE_FMT_EXTENTS; - ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS; - /* - * Bump the generation count so no one will be confused - * by reincarnations of this inode. - */ - VFS_I(ip)->i_generation++; - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - - if (xic.deleted) - error = xfs_ifree_cluster(ip, tp, &xic); - - return error; -} - -/* - * This is called to unpin an inode. The caller must have the inode locked - * in at least shared mode so that the buffer cannot be subsequently pinned - * once someone is waiting for it to be unpinned. - */ -static void -xfs_iunpin( - struct xfs_inode *ip) -{ - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); - - trace_xfs_inode_unpin_nowait(ip, _RET_IP_); - - /* Give the log a push to start the unpinning I/O */ - xfs_log_force_lsn(ip->i_mount, ip->i_itemp->ili_last_lsn, 0); - -} - -static void -__xfs_iunpin_wait( - struct xfs_inode *ip) -{ - wait_queue_head_t *wq = bit_waitqueue(&ip->i_flags, __XFS_IPINNED_BIT); - DEFINE_WAIT_BIT(wait, &ip->i_flags, __XFS_IPINNED_BIT); - - xfs_iunpin(ip); - - do { - prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE); - if (xfs_ipincount(ip)) - io_schedule(); - } while (xfs_ipincount(ip)); - finish_wait(wq, &wait.wait); -} - -void -xfs_iunpin_wait( - struct xfs_inode *ip) -{ - if (xfs_ipincount(ip)) - __xfs_iunpin_wait(ip); -} - -/* - * Removing an inode from the namespace involves removing the directory entry - * and dropping the link count on the inode. Removing the directory entry can - * result in locking an AGF (directory blocks were freed) and removing a link - * count can result in placing the inode on an unlinked list which results in - * locking an AGI. - * - * The big problem here is that we have an ordering constraint on AGF and AGI - * locking - inode allocation locks the AGI, then can allocate a new extent for - * new inodes, locking the AGF after the AGI. Similarly, freeing the inode - * removes the inode from the unlinked list, requiring that we lock the AGI - * first, and then freeing the inode can result in an inode chunk being freed - * and hence freeing disk space requiring that we lock an AGF. - * - * Hence the ordering that is imposed by other parts of the code is AGI before - * AGF. This means we cannot remove the directory entry before we drop the inode - * reference count and put it on the unlinked list as this results in a lock - * order of AGF then AGI, and this can deadlock against inode allocation and - * freeing. Therefore we must drop the link counts before we remove the - * directory entry. - * - * This is still safe from a transactional point of view - it is not until we - * get to xfs_defer_finish() that we have the possibility of multiple - * transactions in this operation. Hence as long as we remove the directory - * entry and drop the link count in the first transaction of the remove - * operation, there are no transactional constraints on the ordering here. - */ -int -xfs_remove( - xfs_inode_t *dp, - struct xfs_name *name, - xfs_inode_t *ip) -{ - xfs_mount_t *mp = dp->i_mount; - xfs_trans_t *tp = NULL; - int is_dir = S_ISDIR(VFS_I(ip)->i_mode); - int error = 0; - struct xfs_defer_ops dfops; - xfs_fsblock_t first_block; - uint resblks; - - trace_xfs_remove(dp, name); - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - error = xfs_qm_dqattach(dp, 0); - if (error) - goto std_return; - - error = xfs_qm_dqattach(ip, 0); - if (error) - goto std_return; - - /* - * We try to get the real space reservation first, - * allowing for directory btree deletion(s) implying - * possible bmap insert(s). If we can't get the space - * reservation then we use 0 instead, and avoid the bmap - * btree insert(s) in the directory code by, if the bmap - * insert tries to happen, instead trimming the LAST - * block from the directory. - */ - resblks = XFS_REMOVE_SPACE_RES(mp); - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_remove, resblks, 0, 0, &tp); - if (error == -ENOSPC) { - resblks = 0; - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_remove, 0, 0, 0, - &tp); - } - if (error) { - ASSERT(error != -ENOSPC); - goto std_return; - } - - xfs_ilock(dp, XFS_IOLOCK_EXCL | XFS_IOLOCK_PARENT); - xfs_lock_two_inodes(dp, ip, XFS_ILOCK_EXCL); - - xfs_trans_ijoin(tp, dp, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); - - /* - * If we're removing a directory perform some additional validation. - */ - if (is_dir) { - ASSERT(VFS_I(ip)->i_nlink >= 2); - if (VFS_I(ip)->i_nlink != 2) { - error = -ENOTEMPTY; - goto out_trans_cancel; - } - if (!xfs_dir_isempty(ip)) { - error = -ENOTEMPTY; - goto out_trans_cancel; - } - - /* Drop the link from ip's "..". */ - error = xfs_droplink(tp, dp); - if (error) - goto out_trans_cancel; - - /* Drop the "." link from ip to self. */ - error = xfs_droplink(tp, ip); - if (error) - goto out_trans_cancel; - } else { - /* - * When removing a non-directory we need to log the parent - * inode here. For a directory this is done implicitly - * by the xfs_droplink call for the ".." entry. - */ - xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); - } - xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); - - /* Drop the link from dp to ip. */ - error = xfs_droplink(tp, ip); - if (error) - goto out_trans_cancel; - - xfs_defer_init(&dfops, &first_block); - error = xfs_dir_removename(tp, dp, name, ip->i_ino, - &first_block, &dfops, resblks); - if (error) { - ASSERT(error != -ENOENT); - goto out_bmap_cancel; - } - - /* - * If this is a synchronous mount, make sure that the - * remove transaction goes to disk before returning to - * the user. - */ - if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) - xfs_trans_set_sync(tp); - - error = xfs_defer_finish(&tp, &dfops, NULL); - if (error) - goto out_bmap_cancel; - - error = xfs_trans_commit(tp); - if (error) - goto std_return; - - if (is_dir && xfs_inode_is_filestream(ip)) - xfs_filestream_deassociate(ip); - - return 0; - - out_bmap_cancel: - xfs_defer_cancel(&dfops); - out_trans_cancel: - xfs_trans_cancel(tp); - std_return: - return error; -} - -/* - * Enter all inodes for a rename transaction into a sorted array. - */ -#define __XFS_SORT_INODES 5 -STATIC void -xfs_sort_for_rename( - struct xfs_inode *dp1, /* in: old (source) directory inode */ - struct xfs_inode *dp2, /* in: new (target) directory inode */ - struct xfs_inode *ip1, /* in: inode of old entry */ - struct xfs_inode *ip2, /* in: inode of new entry */ - struct xfs_inode *wip, /* in: whiteout inode */ - struct xfs_inode **i_tab,/* out: sorted array of inodes */ - int *num_inodes) /* in/out: inodes in array */ -{ - int i, j; - - ASSERT(*num_inodes == __XFS_SORT_INODES); - memset(i_tab, 0, *num_inodes * sizeof(struct xfs_inode *)); - - /* - * i_tab contains a list of pointers to inodes. We initialize - * the table here & we'll sort it. We will then use it to - * order the acquisition of the inode locks. - * - * Note that the table may contain duplicates. e.g., dp1 == dp2. - */ - i = 0; - i_tab[i++] = dp1; - i_tab[i++] = dp2; - i_tab[i++] = ip1; - if (ip2) - i_tab[i++] = ip2; - if (wip) - i_tab[i++] = wip; - *num_inodes = i; - - /* - * Sort the elements via bubble sort. (Remember, there are at - * most 5 elements to sort, so this is adequate.) - */ - for (i = 0; i < *num_inodes; i++) { - for (j = 1; j < *num_inodes; j++) { - if (i_tab[j]->i_ino < i_tab[j-1]->i_ino) { - struct xfs_inode *temp = i_tab[j]; - i_tab[j] = i_tab[j-1]; - i_tab[j-1] = temp; - } - } - } -} - -static int -xfs_finish_rename( - struct xfs_trans *tp, - struct xfs_defer_ops *dfops) -{ - int error; - - /* - * If this is a synchronous mount, make sure that the rename transaction - * goes to disk before returning to the user. - */ - if (tp->t_mountp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) - xfs_trans_set_sync(tp); - - error = xfs_defer_finish(&tp, dfops, NULL); - if (error) { - xfs_defer_cancel(dfops); - xfs_trans_cancel(tp); - return error; - } - - return xfs_trans_commit(tp); -} - -/* - * xfs_cross_rename() - * - * responsible for handling RENAME_EXCHANGE flag in renameat2() sytemcall - */ -STATIC int -xfs_cross_rename( - struct xfs_trans *tp, - struct xfs_inode *dp1, - struct xfs_name *name1, - struct xfs_inode *ip1, - struct xfs_inode *dp2, - struct xfs_name *name2, - struct xfs_inode *ip2, - struct xfs_defer_ops *dfops, - xfs_fsblock_t *first_block, - int spaceres) -{ - int error = 0; - int ip1_flags = 0; - int ip2_flags = 0; - int dp2_flags = 0; - - /* Swap inode number for dirent in first parent */ - error = xfs_dir_replace(tp, dp1, name1, - ip2->i_ino, - first_block, dfops, spaceres); - if (error) - goto out_trans_abort; - - /* Swap inode number for dirent in second parent */ - error = xfs_dir_replace(tp, dp2, name2, - ip1->i_ino, - first_block, dfops, spaceres); - if (error) - goto out_trans_abort; - - /* - * If we're renaming one or more directories across different parents, - * update the respective ".." entries (and link counts) to match the new - * parents. - */ - if (dp1 != dp2) { - dp2_flags = XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; - - if (S_ISDIR(VFS_I(ip2)->i_mode)) { - error = xfs_dir_replace(tp, ip2, &xfs_name_dotdot, - dp1->i_ino, first_block, - dfops, spaceres); - if (error) - goto out_trans_abort; - - /* transfer ip2 ".." reference to dp1 */ - if (!S_ISDIR(VFS_I(ip1)->i_mode)) { - error = xfs_droplink(tp, dp2); - if (error) - goto out_trans_abort; - error = xfs_bumplink(tp, dp1); - if (error) - goto out_trans_abort; - } - - /* - * Although ip1 isn't changed here, userspace needs - * to be warned about the change, so that applications - * relying on it (like backup ones), will properly - * notify the change - */ - ip1_flags |= XFS_ICHGTIME_CHG; - ip2_flags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; - } - - if (S_ISDIR(VFS_I(ip1)->i_mode)) { - error = xfs_dir_replace(tp, ip1, &xfs_name_dotdot, - dp2->i_ino, first_block, - dfops, spaceres); - if (error) - goto out_trans_abort; - - /* transfer ip1 ".." reference to dp2 */ - if (!S_ISDIR(VFS_I(ip2)->i_mode)) { - error = xfs_droplink(tp, dp1); - if (error) - goto out_trans_abort; - error = xfs_bumplink(tp, dp2); - if (error) - goto out_trans_abort; - } - - /* - * Although ip2 isn't changed here, userspace needs - * to be warned about the change, so that applications - * relying on it (like backup ones), will properly - * notify the change - */ - ip1_flags |= XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG; - ip2_flags |= XFS_ICHGTIME_CHG; - } - } - - if (ip1_flags) { - xfs_trans_ichgtime(tp, ip1, ip1_flags); - xfs_trans_log_inode(tp, ip1, XFS_ILOG_CORE); - } - if (ip2_flags) { - xfs_trans_ichgtime(tp, ip2, ip2_flags); - xfs_trans_log_inode(tp, ip2, XFS_ILOG_CORE); - } - if (dp2_flags) { - xfs_trans_ichgtime(tp, dp2, dp2_flags); - xfs_trans_log_inode(tp, dp2, XFS_ILOG_CORE); - } - xfs_trans_ichgtime(tp, dp1, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); - xfs_trans_log_inode(tp, dp1, XFS_ILOG_CORE); - return xfs_finish_rename(tp, dfops); - -out_trans_abort: - xfs_defer_cancel(dfops); - xfs_trans_cancel(tp); - return error; -} - -/* - * xfs_rename_alloc_whiteout() - * - * Return a referenced, unlinked, unlocked inode that that can be used as a - * whiteout in a rename transaction. We use a tmpfile inode here so that if we - * crash between allocating the inode and linking it into the rename transaction - * recovery will free the inode and we won't leak it. - */ -static int -xfs_rename_alloc_whiteout( - struct xfs_inode *dp, - struct xfs_inode **wip) -{ - struct xfs_inode *tmpfile; - int error; - - error = xfs_create_tmpfile(dp, NULL, S_IFCHR | WHITEOUT_MODE, &tmpfile); - if (error) - return error; - - /* - * Prepare the tmpfile inode as if it were created through the VFS. - * Otherwise, the link increment paths will complain about nlink 0->1. - * Drop the link count as done by d_tmpfile(), complete the inode setup - * and flag it as linkable. - */ - drop_nlink(VFS_I(tmpfile)); - xfs_setup_iops(tmpfile); - xfs_finish_inode_setup(tmpfile); - VFS_I(tmpfile)->i_state |= I_LINKABLE; - - *wip = tmpfile; - return 0; -} - -/* - * xfs_rename - */ -int -xfs_rename( - struct xfs_inode *src_dp, - struct xfs_name *src_name, - struct xfs_inode *src_ip, - struct xfs_inode *target_dp, - struct xfs_name *target_name, - struct xfs_inode *target_ip, - unsigned int flags) -{ - struct xfs_mount *mp = src_dp->i_mount; - struct xfs_trans *tp; - struct xfs_defer_ops dfops; - xfs_fsblock_t first_block; - struct xfs_inode *wip = NULL; /* whiteout inode */ - struct xfs_inode *inodes[__XFS_SORT_INODES]; - int num_inodes = __XFS_SORT_INODES; - bool new_parent = (src_dp != target_dp); - bool src_is_directory = S_ISDIR(VFS_I(src_ip)->i_mode); - int spaceres; - int error; - - trace_xfs_rename(src_dp, target_dp, src_name, target_name); - - if ((flags & RENAME_EXCHANGE) && !target_ip) - return -EINVAL; - - /* - * If we are doing a whiteout operation, allocate the whiteout inode - * we will be placing at the target and ensure the type is set - * appropriately. - */ - if (flags & RENAME_WHITEOUT) { - ASSERT(!(flags & (RENAME_NOREPLACE | RENAME_EXCHANGE))); - error = xfs_rename_alloc_whiteout(target_dp, &wip); - if (error) - return error; - - /* setup target dirent info as whiteout */ - src_name->type = XFS_DIR3_FT_CHRDEV; - } - - xfs_sort_for_rename(src_dp, target_dp, src_ip, target_ip, wip, - inodes, &num_inodes); - - spaceres = XFS_RENAME_SPACE_RES(mp, target_name->len); - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_rename, spaceres, 0, 0, &tp); - if (error == -ENOSPC) { - spaceres = 0; - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_rename, 0, 0, 0, - &tp); - } - if (error) - goto out_release_wip; - - /* - * Attach the dquots to the inodes - */ - error = xfs_qm_vop_rename_dqattach(inodes); - if (error) - goto out_trans_cancel; - - /* - * Lock all the participating inodes. Depending upon whether - * the target_name exists in the target directory, and - * whether the target directory is the same as the source - * directory, we can lock from 2 to 4 inodes. - */ - if (!new_parent) - xfs_ilock(src_dp, XFS_IOLOCK_EXCL | XFS_IOLOCK_PARENT); - else - xfs_lock_two_inodes(src_dp, target_dp, - XFS_IOLOCK_EXCL | XFS_IOLOCK_PARENT); - - xfs_lock_inodes(inodes, num_inodes, XFS_ILOCK_EXCL); - - /* - * Join all the inodes to the transaction. From this point on, - * we can rely on either trans_commit or trans_cancel to unlock - * them. - */ - xfs_trans_ijoin(tp, src_dp, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); - if (new_parent) - xfs_trans_ijoin(tp, target_dp, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, src_ip, XFS_ILOCK_EXCL); - if (target_ip) - xfs_trans_ijoin(tp, target_ip, XFS_ILOCK_EXCL); - if (wip) - xfs_trans_ijoin(tp, wip, XFS_ILOCK_EXCL); - - /* - * If we are using project inheritance, we only allow renames - * into our tree when the project IDs are the same; else the - * tree quota mechanism would be circumvented. - */ - if (unlikely((target_dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) && - (xfs_get_projid(target_dp) != xfs_get_projid(src_ip)))) { - error = -EXDEV; - goto out_trans_cancel; - } - - xfs_defer_init(&dfops, &first_block); - - /* RENAME_EXCHANGE is unique from here on. */ - if (flags & RENAME_EXCHANGE) - return xfs_cross_rename(tp, src_dp, src_name, src_ip, - target_dp, target_name, target_ip, - &dfops, &first_block, spaceres); - - /* - * Set up the target. - */ - if (target_ip == NULL) { - /* - * If there's no space reservation, check the entry will - * fit before actually inserting it. - */ - if (!spaceres) { - error = xfs_dir_canenter(tp, target_dp, target_name); - if (error) - goto out_trans_cancel; - } - /* - * If target does not exist and the rename crosses - * directories, adjust the target directory link count - * to account for the ".." reference from the new entry. - */ - error = xfs_dir_createname(tp, target_dp, target_name, - src_ip->i_ino, &first_block, - &dfops, spaceres); - if (error) - goto out_bmap_cancel; - - xfs_trans_ichgtime(tp, target_dp, - XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); - - if (new_parent && src_is_directory) { - error = xfs_bumplink(tp, target_dp); - if (error) - goto out_bmap_cancel; - } - } else { /* target_ip != NULL */ - /* - * If target exists and it's a directory, check that both - * target and source are directories and that target can be - * destroyed, or that neither is a directory. - */ - if (S_ISDIR(VFS_I(target_ip)->i_mode)) { - /* - * Make sure target dir is empty. - */ - if (!(xfs_dir_isempty(target_ip)) || - (VFS_I(target_ip)->i_nlink > 2)) { - error = -EEXIST; - goto out_trans_cancel; - } - } - - /* - * Link the source inode under the target name. - * If the source inode is a directory and we are moving - * it across directories, its ".." entry will be - * inconsistent until we replace that down below. - * - * In case there is already an entry with the same - * name at the destination directory, remove it first. - */ - error = xfs_dir_replace(tp, target_dp, target_name, - src_ip->i_ino, - &first_block, &dfops, spaceres); - if (error) - goto out_bmap_cancel; - - xfs_trans_ichgtime(tp, target_dp, - XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); - - /* - * Decrement the link count on the target since the target - * dir no longer points to it. - */ - error = xfs_droplink(tp, target_ip); - if (error) - goto out_bmap_cancel; - - if (src_is_directory) { - /* - * Drop the link from the old "." entry. - */ - error = xfs_droplink(tp, target_ip); - if (error) - goto out_bmap_cancel; - } - } /* target_ip != NULL */ - - /* - * Remove the source. - */ - if (new_parent && src_is_directory) { - /* - * Rewrite the ".." entry to point to the new - * directory. - */ - error = xfs_dir_replace(tp, src_ip, &xfs_name_dotdot, - target_dp->i_ino, - &first_block, &dfops, spaceres); - ASSERT(error != -EEXIST); - if (error) - goto out_bmap_cancel; - } - - /* - * We always want to hit the ctime on the source inode. - * - * This isn't strictly required by the standards since the source - * inode isn't really being changed, but old unix file systems did - * it and some incremental backup programs won't work without it. - */ - xfs_trans_ichgtime(tp, src_ip, XFS_ICHGTIME_CHG); - xfs_trans_log_inode(tp, src_ip, XFS_ILOG_CORE); - - /* - * Adjust the link count on src_dp. This is necessary when - * renaming a directory, either within one parent when - * the target existed, or across two parent directories. - */ - if (src_is_directory && (new_parent || target_ip != NULL)) { - - /* - * Decrement link count on src_directory since the - * entry that's moved no longer points to it. - */ - error = xfs_droplink(tp, src_dp); - if (error) - goto out_bmap_cancel; - } - - /* - * For whiteouts, we only need to update the source dirent with the - * inode number of the whiteout inode rather than removing it - * altogether. - */ - if (wip) { - error = xfs_dir_replace(tp, src_dp, src_name, wip->i_ino, - &first_block, &dfops, spaceres); - } else - error = xfs_dir_removename(tp, src_dp, src_name, src_ip->i_ino, - &first_block, &dfops, spaceres); - if (error) - goto out_bmap_cancel; - - /* - * For whiteouts, we need to bump the link count on the whiteout inode. - * This means that failures all the way up to this point leave the inode - * on the unlinked list and so cleanup is a simple matter of dropping - * the remaining reference to it. If we fail here after bumping the link - * count, we're shutting down the filesystem so we'll never see the - * intermediate state on disk. - */ - if (wip) { - ASSERT(VFS_I(wip)->i_nlink == 0); - error = xfs_bumplink(tp, wip); - if (error) - goto out_bmap_cancel; - error = xfs_iunlink_remove(tp, wip); - if (error) - goto out_bmap_cancel; - xfs_trans_log_inode(tp, wip, XFS_ILOG_CORE); - - /* - * Now we have a real link, clear the "I'm a tmpfile" state - * flag from the inode so it doesn't accidentally get misused in - * future. - */ - VFS_I(wip)->i_state &= ~I_LINKABLE; - } - - xfs_trans_ichgtime(tp, src_dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); - xfs_trans_log_inode(tp, src_dp, XFS_ILOG_CORE); - if (new_parent) - xfs_trans_log_inode(tp, target_dp, XFS_ILOG_CORE); - - error = xfs_finish_rename(tp, &dfops); - if (wip) - IRELE(wip); - return error; - -out_bmap_cancel: - xfs_defer_cancel(&dfops); -out_trans_cancel: - xfs_trans_cancel(tp); -out_release_wip: - if (wip) - IRELE(wip); - return error; -} - -STATIC int -xfs_iflush_cluster( - struct xfs_inode *ip, - struct xfs_buf *bp) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_perag *pag; - unsigned long first_index, mask; - unsigned long inodes_per_cluster; - int cilist_size; - struct xfs_inode **cilist; - struct xfs_inode *cip; - int nr_found; - int clcount = 0; - int bufwasdelwri; - int i; - - pag = xfs_perag_get(mp, XFS_INO_TO_AGNO(mp, ip->i_ino)); - - inodes_per_cluster = mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog; - cilist_size = inodes_per_cluster * sizeof(xfs_inode_t *); - cilist = kmem_alloc(cilist_size, KM_MAYFAIL|KM_NOFS); - if (!cilist) - goto out_put; - - mask = ~(((mp->m_inode_cluster_size >> mp->m_sb.sb_inodelog)) - 1); - first_index = XFS_INO_TO_AGINO(mp, ip->i_ino) & mask; - rcu_read_lock(); - /* really need a gang lookup range call here */ - nr_found = radix_tree_gang_lookup(&pag->pag_ici_root, (void**)cilist, - first_index, inodes_per_cluster); - if (nr_found == 0) - goto out_free; - - for (i = 0; i < nr_found; i++) { - cip = cilist[i]; - if (cip == ip) - continue; - - /* - * because this is an RCU protected lookup, we could find a - * recently freed or even reallocated inode during the lookup. - * We need to check under the i_flags_lock for a valid inode - * here. Skip it if it is not valid or the wrong inode. - */ - spin_lock(&cip->i_flags_lock); - if (!cip->i_ino || - __xfs_iflags_test(cip, XFS_ISTALE)) { - spin_unlock(&cip->i_flags_lock); - continue; - } - - /* - * Once we fall off the end of the cluster, no point checking - * any more inodes in the list because they will also all be - * outside the cluster. - */ - if ((XFS_INO_TO_AGINO(mp, cip->i_ino) & mask) != first_index) { - spin_unlock(&cip->i_flags_lock); - break; - } - spin_unlock(&cip->i_flags_lock); - - /* - * Do an un-protected check to see if the inode is dirty and - * is a candidate for flushing. These checks will be repeated - * later after the appropriate locks are acquired. - */ - if (xfs_inode_clean(cip) && xfs_ipincount(cip) == 0) - continue; - - /* - * Try to get locks. If any are unavailable or it is pinned, - * then this inode cannot be flushed and is skipped. - */ - - if (!xfs_ilock_nowait(cip, XFS_ILOCK_SHARED)) - continue; - if (!xfs_iflock_nowait(cip)) { - xfs_iunlock(cip, XFS_ILOCK_SHARED); - continue; - } - if (xfs_ipincount(cip)) { - xfs_ifunlock(cip); - xfs_iunlock(cip, XFS_ILOCK_SHARED); - continue; - } - - - /* - * Check the inode number again, just to be certain we are not - * racing with freeing in xfs_reclaim_inode(). See the comments - * in that function for more information as to why the initial - * check is not sufficient. - */ - if (!cip->i_ino) { - xfs_ifunlock(cip); - xfs_iunlock(cip, XFS_ILOCK_SHARED); - continue; - } - - /* - * arriving here means that this inode can be flushed. First - * re-check that it's dirty before flushing. - */ - if (!xfs_inode_clean(cip)) { - int error; - error = xfs_iflush_int(cip, bp); - if (error) { - xfs_iunlock(cip, XFS_ILOCK_SHARED); - goto cluster_corrupt_out; - } - clcount++; - } else { - xfs_ifunlock(cip); - } - xfs_iunlock(cip, XFS_ILOCK_SHARED); - } - - if (clcount) { - XFS_STATS_INC(mp, xs_icluster_flushcnt); - XFS_STATS_ADD(mp, xs_icluster_flushinode, clcount); - } - -out_free: - rcu_read_unlock(); - kmem_free(cilist); -out_put: - xfs_perag_put(pag); - return 0; - - -cluster_corrupt_out: - /* - * Corruption detected in the clustering loop. Invalidate the - * inode buffer and shut down the filesystem. - */ - rcu_read_unlock(); - /* - * Clean up the buffer. If it was delwri, just release it -- - * brelse can handle it with no problems. If not, shut down the - * filesystem before releasing the buffer. - */ - bufwasdelwri = (bp->b_flags & _XBF_DELWRI_Q); - if (bufwasdelwri) - xfs_buf_relse(bp); - - xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); - - if (!bufwasdelwri) { - /* - * Just like incore_relse: if we have b_iodone functions, - * mark the buffer as an error and call them. Otherwise - * mark it as stale and brelse. - */ - if (bp->b_iodone) { - bp->b_flags &= ~XBF_DONE; - xfs_buf_stale(bp); - xfs_buf_ioerror(bp, -EIO); - xfs_buf_ioend(bp); - } else { - xfs_buf_stale(bp); - xfs_buf_relse(bp); - } - } - - /* - * Unlocks the flush lock - */ - xfs_iflush_abort(cip, false); - kmem_free(cilist); - xfs_perag_put(pag); - return -EFSCORRUPTED; -} - -/* - * Flush dirty inode metadata into the backing buffer. - * - * The caller must have the inode lock and the inode flush lock held. The - * inode lock will still be held upon return to the caller, and the inode - * flush lock will be released after the inode has reached the disk. - * - * The caller must write out the buffer returned in *bpp and release it. - */ -int -xfs_iflush( - struct xfs_inode *ip, - struct xfs_buf **bpp) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_buf *bp = NULL; - struct xfs_dinode *dip; - int error; - - XFS_STATS_INC(mp, xs_iflush_count); - - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); - ASSERT(xfs_isiflocked(ip)); - ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || - ip->i_d.di_nextents > XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK)); - - *bpp = NULL; - - xfs_iunpin_wait(ip); - - /* - * For stale inodes we cannot rely on the backing buffer remaining - * stale in cache for the remaining life of the stale inode and so - * xfs_imap_to_bp() below may give us a buffer that no longer contains - * inodes below. We have to check this after ensuring the inode is - * unpinned so that it is safe to reclaim the stale inode after the - * flush call. - */ - if (xfs_iflags_test(ip, XFS_ISTALE)) { - xfs_ifunlock(ip); - return 0; - } - - /* - * This may have been unpinned because the filesystem is shutting - * down forcibly. If that's the case we must not write this inode - * to disk, because the log record didn't make it to disk. - * - * We also have to remove the log item from the AIL in this case, - * as we wait for an empty AIL as part of the unmount process. - */ - if (XFS_FORCED_SHUTDOWN(mp)) { - error = -EIO; - goto abort_out; - } - - /* - * Get the buffer containing the on-disk inode. We are doing a try-lock - * operation here, so we may get an EAGAIN error. In that case, we - * simply want to return with the inode still dirty. - * - * If we get any other error, we effectively have a corruption situation - * and we cannot flush the inode, so we treat it the same as failing - * xfs_iflush_int(). - */ - error = xfs_imap_to_bp(mp, NULL, &ip->i_imap, &dip, &bp, XBF_TRYLOCK, - 0); - if (error == -EAGAIN) { - xfs_ifunlock(ip); - return error; - } - if (error) - goto corrupt_out; - - /* - * First flush out the inode that xfs_iflush was called with. - */ - error = xfs_iflush_int(ip, bp); - if (error) - goto corrupt_out; - - /* - * If the buffer is pinned then push on the log now so we won't - * get stuck waiting in the write for too long. - */ - if (xfs_buf_ispinned(bp)) - xfs_log_force(mp, 0); - - /* - * inode clustering: - * see if other inodes can be gathered into this write - */ - error = xfs_iflush_cluster(ip, bp); - if (error) - goto cluster_corrupt_out; - - *bpp = bp; - return 0; - -corrupt_out: - if (bp) - xfs_buf_relse(bp); - xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); -cluster_corrupt_out: - error = -EFSCORRUPTED; -abort_out: - /* - * Unlocks the flush lock - */ - xfs_iflush_abort(ip, false); - return error; -} - -STATIC int -xfs_iflush_int( - struct xfs_inode *ip, - struct xfs_buf *bp) -{ - struct xfs_inode_log_item *iip = ip->i_itemp; - struct xfs_dinode *dip; - struct xfs_mount *mp = ip->i_mount; - - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED)); - ASSERT(xfs_isiflocked(ip)); - ASSERT(ip->i_d.di_format != XFS_DINODE_FMT_BTREE || - ip->i_d.di_nextents > XFS_IFORK_MAXEXT(ip, XFS_DATA_FORK)); - ASSERT(iip != NULL && iip->ili_fields != 0); - ASSERT(ip->i_d.di_version > 1); - - /* set *dip = inode's place in the buffer */ - dip = xfs_buf_offset(bp, ip->i_imap.im_boffset); - - if (XFS_TEST_ERROR(dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC), - mp, XFS_ERRTAG_IFLUSH_1, XFS_RANDOM_IFLUSH_1)) { - xfs_alert_tag(mp, XFS_PTAG_IFLUSH, - "%s: Bad inode %Lu magic number 0x%x, ptr 0x%p", - __func__, ip->i_ino, be16_to_cpu(dip->di_magic), dip); - goto corrupt_out; - } - if (S_ISREG(VFS_I(ip)->i_mode)) { - if (XFS_TEST_ERROR( - (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) && - (ip->i_d.di_format != XFS_DINODE_FMT_BTREE), - mp, XFS_ERRTAG_IFLUSH_3, XFS_RANDOM_IFLUSH_3)) { - xfs_alert_tag(mp, XFS_PTAG_IFLUSH, - "%s: Bad regular inode %Lu, ptr 0x%p", - __func__, ip->i_ino, ip); - goto corrupt_out; - } - } else if (S_ISDIR(VFS_I(ip)->i_mode)) { - if (XFS_TEST_ERROR( - (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) && - (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) && - (ip->i_d.di_format != XFS_DINODE_FMT_LOCAL), - mp, XFS_ERRTAG_IFLUSH_4, XFS_RANDOM_IFLUSH_4)) { - xfs_alert_tag(mp, XFS_PTAG_IFLUSH, - "%s: Bad directory inode %Lu, ptr 0x%p", - __func__, ip->i_ino, ip); - goto corrupt_out; - } - } - if (XFS_TEST_ERROR(ip->i_d.di_nextents + ip->i_d.di_anextents > - ip->i_d.di_nblocks, mp, XFS_ERRTAG_IFLUSH_5, - XFS_RANDOM_IFLUSH_5)) { - xfs_alert_tag(mp, XFS_PTAG_IFLUSH, - "%s: detected corrupt incore inode %Lu, " - "total extents = %d, nblocks = %Ld, ptr 0x%p", - __func__, ip->i_ino, - ip->i_d.di_nextents + ip->i_d.di_anextents, - ip->i_d.di_nblocks, ip); - goto corrupt_out; - } - if (XFS_TEST_ERROR(ip->i_d.di_forkoff > mp->m_sb.sb_inodesize, - mp, XFS_ERRTAG_IFLUSH_6, XFS_RANDOM_IFLUSH_6)) { - xfs_alert_tag(mp, XFS_PTAG_IFLUSH, - "%s: bad inode %Lu, forkoff 0x%x, ptr 0x%p", - __func__, ip->i_ino, ip->i_d.di_forkoff, ip); - goto corrupt_out; - } - - /* - * Inode item log recovery for v2 inodes are dependent on the - * di_flushiter count for correct sequencing. We bump the flush - * iteration count so we can detect flushes which postdate a log record - * during recovery. This is redundant as we now log every change and - * hence this can't happen but we need to still do it to ensure - * backwards compatibility with old kernels that predate logging all - * inode changes. - */ - if (ip->i_d.di_version < 3) - ip->i_d.di_flushiter++; - - /* - * Copy the dirty parts of the inode into the on-disk inode. We always - * copy out the core of the inode, because if the inode is dirty at all - * the core must be. - */ - xfs_inode_to_disk(ip, dip, iip->ili_item.li_lsn); - - /* Wrap, we never let the log put out DI_MAX_FLUSH */ - if (ip->i_d.di_flushiter == DI_MAX_FLUSH) - ip->i_d.di_flushiter = 0; - - xfs_iflush_fork(ip, dip, iip, XFS_DATA_FORK); - if (XFS_IFORK_Q(ip)) - xfs_iflush_fork(ip, dip, iip, XFS_ATTR_FORK); - xfs_inobp_check(mp, bp); - - /* - * We've recorded everything logged in the inode, so we'd like to clear - * the ili_fields bits so we don't log and flush things unnecessarily. - * However, we can't stop logging all this information until the data - * we've copied into the disk buffer is written to disk. If we did we - * might overwrite the copy of the inode in the log with all the data - * after re-logging only part of it, and in the face of a crash we - * wouldn't have all the data we need to recover. - * - * What we do is move the bits to the ili_last_fields field. When - * logging the inode, these bits are moved back to the ili_fields field. - * In the xfs_iflush_done() routine we clear ili_last_fields, since we - * know that the information those bits represent is permanently on - * disk. As long as the flush completes before the inode is logged - * again, then both ili_fields and ili_last_fields will be cleared. - * - * We can play with the ili_fields bits here, because the inode lock - * must be held exclusively in order to set bits there and the flush - * lock protects the ili_last_fields bits. Set ili_logged so the flush - * done routine can tell whether or not to look in the AIL. Also, store - * the current LSN of the inode so that we can tell whether the item has - * moved in the AIL from xfs_iflush_done(). In order to read the lsn we - * need the AIL lock, because it is a 64 bit value that cannot be read - * atomically. - */ - iip->ili_last_fields = iip->ili_fields; - iip->ili_fields = 0; - iip->ili_fsync_fields = 0; - iip->ili_logged = 1; - - xfs_trans_ail_copy_lsn(mp->m_ail, &iip->ili_flush_lsn, - &iip->ili_item.li_lsn); - - /* - * Attach the function xfs_iflush_done to the inode's - * buffer. This will remove the inode from the AIL - * and unlock the inode's flush lock when the inode is - * completely written to disk. - */ - xfs_buf_attach_iodone(bp, xfs_iflush_done, &iip->ili_item); - - /* generate the checksum. */ - xfs_dinode_calc_crc(mp, dip); - - ASSERT(bp->b_fspriv != NULL); - ASSERT(bp->b_iodone != NULL); - return 0; - -corrupt_out: - return -EFSCORRUPTED; -} diff --git a/src/linux/fs/xfs/xfs_inode.h b/src/linux/fs/xfs/xfs_inode.h deleted file mode 100644 index f14c1de..0000000 --- a/src/linux/fs/xfs/xfs_inode.h +++ /dev/null @@ -1,496 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_INODE_H__ -#define __XFS_INODE_H__ - -#include "xfs_inode_buf.h" -#include "xfs_inode_fork.h" - -/* - * Kernel only inode definitions - */ -struct xfs_dinode; -struct xfs_inode; -struct xfs_buf; -struct xfs_defer_ops; -struct xfs_bmbt_irec; -struct xfs_inode_log_item; -struct xfs_mount; -struct xfs_trans; -struct xfs_dquot; - -typedef struct xfs_inode { - /* Inode linking and identification information. */ - struct xfs_mount *i_mount; /* fs mount struct ptr */ - struct xfs_dquot *i_udquot; /* user dquot */ - struct xfs_dquot *i_gdquot; /* group dquot */ - struct xfs_dquot *i_pdquot; /* project dquot */ - - /* Inode location stuff */ - xfs_ino_t i_ino; /* inode number (agno/agino)*/ - struct xfs_imap i_imap; /* location for xfs_imap() */ - - /* Extent information. */ - xfs_ifork_t *i_afp; /* attribute fork pointer */ - xfs_ifork_t *i_cowfp; /* copy on write extents */ - xfs_ifork_t i_df; /* data fork */ - - /* operations vectors */ - const struct xfs_dir_ops *d_ops; /* directory ops vector */ - - /* Transaction and locking information. */ - struct xfs_inode_log_item *i_itemp; /* logging information */ - mrlock_t i_lock; /* inode lock */ - mrlock_t i_iolock; /* inode IO lock */ - mrlock_t i_mmaplock; /* inode mmap IO lock */ - atomic_t i_pincount; /* inode pin count */ - spinlock_t i_flags_lock; /* inode i_flags lock */ - /* Miscellaneous state. */ - unsigned long i_flags; /* see defined flags below */ - unsigned int i_delayed_blks; /* count of delay alloc blks */ - - struct xfs_icdinode i_d; /* most of ondisk inode */ - - xfs_extnum_t i_cnextents; /* # of extents in cow fork */ - unsigned int i_cformat; /* format of cow fork */ - - /* VFS inode */ - struct inode i_vnode; /* embedded VFS inode */ -} xfs_inode_t; - -/* Convert from vfs inode to xfs inode */ -static inline struct xfs_inode *XFS_I(struct inode *inode) -{ - return container_of(inode, struct xfs_inode, i_vnode); -} - -/* convert from xfs inode to vfs inode */ -static inline struct inode *VFS_I(struct xfs_inode *ip) -{ - return &ip->i_vnode; -} - -/* - * For regular files we only update the on-disk filesize when actually - * writing data back to disk. Until then only the copy in the VFS inode - * is uptodate. - */ -static inline xfs_fsize_t XFS_ISIZE(struct xfs_inode *ip) -{ - if (S_ISREG(VFS_I(ip)->i_mode)) - return i_size_read(VFS_I(ip)); - return ip->i_d.di_size; -} - -/* - * If this I/O goes past the on-disk inode size update it unless it would - * be past the current in-core inode size. - */ -static inline xfs_fsize_t -xfs_new_eof(struct xfs_inode *ip, xfs_fsize_t new_size) -{ - xfs_fsize_t i_size = i_size_read(VFS_I(ip)); - - if (new_size > i_size || new_size < 0) - new_size = i_size; - return new_size > ip->i_d.di_size ? new_size : 0; -} - -/* - * i_flags helper functions - */ -static inline void -__xfs_iflags_set(xfs_inode_t *ip, unsigned short flags) -{ - ip->i_flags |= flags; -} - -static inline void -xfs_iflags_set(xfs_inode_t *ip, unsigned short flags) -{ - spin_lock(&ip->i_flags_lock); - __xfs_iflags_set(ip, flags); - spin_unlock(&ip->i_flags_lock); -} - -static inline void -xfs_iflags_clear(xfs_inode_t *ip, unsigned short flags) -{ - spin_lock(&ip->i_flags_lock); - ip->i_flags &= ~flags; - spin_unlock(&ip->i_flags_lock); -} - -static inline int -__xfs_iflags_test(xfs_inode_t *ip, unsigned short flags) -{ - return (ip->i_flags & flags); -} - -static inline int -xfs_iflags_test(xfs_inode_t *ip, unsigned short flags) -{ - int ret; - spin_lock(&ip->i_flags_lock); - ret = __xfs_iflags_test(ip, flags); - spin_unlock(&ip->i_flags_lock); - return ret; -} - -static inline int -xfs_iflags_test_and_clear(xfs_inode_t *ip, unsigned short flags) -{ - int ret; - - spin_lock(&ip->i_flags_lock); - ret = ip->i_flags & flags; - if (ret) - ip->i_flags &= ~flags; - spin_unlock(&ip->i_flags_lock); - return ret; -} - -static inline int -xfs_iflags_test_and_set(xfs_inode_t *ip, unsigned short flags) -{ - int ret; - - spin_lock(&ip->i_flags_lock); - ret = ip->i_flags & flags; - if (!ret) - ip->i_flags |= flags; - spin_unlock(&ip->i_flags_lock); - return ret; -} - -/* - * Project quota id helpers (previously projid was 16bit only - * and using two 16bit values to hold new 32bit projid was chosen - * to retain compatibility with "old" filesystems). - */ -static inline prid_t -xfs_get_projid(struct xfs_inode *ip) -{ - return (prid_t)ip->i_d.di_projid_hi << 16 | ip->i_d.di_projid_lo; -} - -static inline void -xfs_set_projid(struct xfs_inode *ip, - prid_t projid) -{ - ip->i_d.di_projid_hi = (__uint16_t) (projid >> 16); - ip->i_d.di_projid_lo = (__uint16_t) (projid & 0xffff); -} - -static inline prid_t -xfs_get_initial_prid(struct xfs_inode *dp) -{ - if (dp->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) - return xfs_get_projid(dp); - - return XFS_PROJID_DEFAULT; -} - -static inline bool xfs_is_reflink_inode(struct xfs_inode *ip) -{ - return ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK; -} - -/* - * In-core inode flags. - */ -#define XFS_IRECLAIM (1 << 0) /* started reclaiming this inode */ -#define XFS_ISTALE (1 << 1) /* inode has been staled */ -#define XFS_IRECLAIMABLE (1 << 2) /* inode can be reclaimed */ -#define XFS_INEW (1 << 3) /* inode has just been allocated */ -#define XFS_ITRUNCATED (1 << 5) /* truncated down so flush-on-close */ -#define XFS_IDIRTY_RELEASE (1 << 6) /* dirty release already seen */ -#define __XFS_IFLOCK_BIT 7 /* inode is being flushed right now */ -#define XFS_IFLOCK (1 << __XFS_IFLOCK_BIT) -#define __XFS_IPINNED_BIT 8 /* wakeup key for zero pin count */ -#define XFS_IPINNED (1 << __XFS_IPINNED_BIT) -#define XFS_IDONTCACHE (1 << 9) /* don't cache the inode long term */ -#define XFS_IEOFBLOCKS (1 << 10)/* has the preallocblocks tag set */ -/* - * If this unlinked inode is in the middle of recovery, don't let drop_inode - * truncate and free the inode. This can happen if we iget the inode during - * log recovery to replay a bmap operation on the inode. - */ -#define XFS_IRECOVERY (1 << 11) - -/* - * Per-lifetime flags need to be reset when re-using a reclaimable inode during - * inode lookup. This prevents unintended behaviour on the new inode from - * ocurring. - */ -#define XFS_IRECLAIM_RESET_FLAGS \ - (XFS_IRECLAIMABLE | XFS_IRECLAIM | \ - XFS_IDIRTY_RELEASE | XFS_ITRUNCATED) - -/* - * Synchronize processes attempting to flush the in-core inode back to disk. - */ - -extern void __xfs_iflock(struct xfs_inode *ip); - -static inline int xfs_iflock_nowait(struct xfs_inode *ip) -{ - return !xfs_iflags_test_and_set(ip, XFS_IFLOCK); -} - -static inline void xfs_iflock(struct xfs_inode *ip) -{ - if (!xfs_iflock_nowait(ip)) - __xfs_iflock(ip); -} - -static inline void xfs_ifunlock(struct xfs_inode *ip) -{ - xfs_iflags_clear(ip, XFS_IFLOCK); - smp_mb(); - wake_up_bit(&ip->i_flags, __XFS_IFLOCK_BIT); -} - -static inline int xfs_isiflocked(struct xfs_inode *ip) -{ - return xfs_iflags_test(ip, XFS_IFLOCK); -} - -/* - * Flags for inode locking. - * Bit ranges: 1<<1 - 1<<16-1 -- iolock/ilock modes (bitfield) - * 1<<16 - 1<<32-1 -- lockdep annotation (integers) - */ -#define XFS_IOLOCK_EXCL (1<<0) -#define XFS_IOLOCK_SHARED (1<<1) -#define XFS_ILOCK_EXCL (1<<2) -#define XFS_ILOCK_SHARED (1<<3) -#define XFS_MMAPLOCK_EXCL (1<<4) -#define XFS_MMAPLOCK_SHARED (1<<5) - -#define XFS_LOCK_MASK (XFS_IOLOCK_EXCL | XFS_IOLOCK_SHARED \ - | XFS_ILOCK_EXCL | XFS_ILOCK_SHARED \ - | XFS_MMAPLOCK_EXCL | XFS_MMAPLOCK_SHARED) - -#define XFS_LOCK_FLAGS \ - { XFS_IOLOCK_EXCL, "IOLOCK_EXCL" }, \ - { XFS_IOLOCK_SHARED, "IOLOCK_SHARED" }, \ - { XFS_ILOCK_EXCL, "ILOCK_EXCL" }, \ - { XFS_ILOCK_SHARED, "ILOCK_SHARED" }, \ - { XFS_MMAPLOCK_EXCL, "MMAPLOCK_EXCL" }, \ - { XFS_MMAPLOCK_SHARED, "MMAPLOCK_SHARED" } - - -/* - * Flags for lockdep annotations. - * - * XFS_LOCK_PARENT - for directory operations that require locking a - * parent directory inode and a child entry inode. IOLOCK requires nesting, - * MMAPLOCK does not support this class, ILOCK requires a single subclass - * to differentiate parent from child. - * - * XFS_LOCK_RTBITMAP/XFS_LOCK_RTSUM - the realtime device bitmap and summary - * inodes do not participate in the normal lock order, and thus have their - * own subclasses. - * - * XFS_LOCK_INUMORDER - for locking several inodes at the some time - * with xfs_lock_inodes(). This flag is used as the starting subclass - * and each subsequent lock acquired will increment the subclass by one. - * However, MAX_LOCKDEP_SUBCLASSES == 8, which means we are greatly - * limited to the subclasses we can represent via nesting. We need at least - * 5 inodes nest depth for the ILOCK through rename, and we also have to support - * XFS_ILOCK_PARENT, which gives 6 subclasses. Then we have XFS_ILOCK_RTBITMAP - * and XFS_ILOCK_RTSUM, which are another 2 unique subclasses, so that's all - * 8 subclasses supported by lockdep. - * - * This also means we have to number the sub-classes in the lowest bits of - * the mask we keep, and we have to ensure we never exceed 3 bits of lockdep - * mask and we can't use bit-masking to build the subclasses. What a mess. - * - * Bit layout: - * - * Bit Lock Region - * 16-19 XFS_IOLOCK_SHIFT dependencies - * 20-23 XFS_MMAPLOCK_SHIFT dependencies - * 24-31 XFS_ILOCK_SHIFT dependencies - * - * IOLOCK values - * - * 0-3 subclass value - * 4-7 PARENT subclass values - * - * MMAPLOCK values - * - * 0-3 subclass value - * 4-7 unused - * - * ILOCK values - * 0-4 subclass values - * 5 PARENT subclass (not nestable) - * 6 RTBITMAP subclass (not nestable) - * 7 RTSUM subclass (not nestable) - * - */ -#define XFS_IOLOCK_SHIFT 16 -#define XFS_IOLOCK_PARENT_VAL 4 -#define XFS_IOLOCK_MAX_SUBCLASS (XFS_IOLOCK_PARENT_VAL - 1) -#define XFS_IOLOCK_DEP_MASK 0x000f0000 -#define XFS_IOLOCK_PARENT (XFS_IOLOCK_PARENT_VAL << XFS_IOLOCK_SHIFT) - -#define XFS_MMAPLOCK_SHIFT 20 -#define XFS_MMAPLOCK_NUMORDER 0 -#define XFS_MMAPLOCK_MAX_SUBCLASS 3 -#define XFS_MMAPLOCK_DEP_MASK 0x00f00000 - -#define XFS_ILOCK_SHIFT 24 -#define XFS_ILOCK_PARENT_VAL 5 -#define XFS_ILOCK_MAX_SUBCLASS (XFS_ILOCK_PARENT_VAL - 1) -#define XFS_ILOCK_RTBITMAP_VAL 6 -#define XFS_ILOCK_RTSUM_VAL 7 -#define XFS_ILOCK_DEP_MASK 0xff000000 -#define XFS_ILOCK_PARENT (XFS_ILOCK_PARENT_VAL << XFS_ILOCK_SHIFT) -#define XFS_ILOCK_RTBITMAP (XFS_ILOCK_RTBITMAP_VAL << XFS_ILOCK_SHIFT) -#define XFS_ILOCK_RTSUM (XFS_ILOCK_RTSUM_VAL << XFS_ILOCK_SHIFT) - -#define XFS_LOCK_SUBCLASS_MASK (XFS_IOLOCK_DEP_MASK | \ - XFS_MMAPLOCK_DEP_MASK | \ - XFS_ILOCK_DEP_MASK) - -#define XFS_IOLOCK_DEP(flags) (((flags) & XFS_IOLOCK_DEP_MASK) \ - >> XFS_IOLOCK_SHIFT) -#define XFS_MMAPLOCK_DEP(flags) (((flags) & XFS_MMAPLOCK_DEP_MASK) \ - >> XFS_MMAPLOCK_SHIFT) -#define XFS_ILOCK_DEP(flags) (((flags) & XFS_ILOCK_DEP_MASK) \ - >> XFS_ILOCK_SHIFT) - -/* - * For multiple groups support: if S_ISGID bit is set in the parent - * directory, group of new file is set to that of the parent, and - * new subdirectory gets S_ISGID bit from parent. - */ -#define XFS_INHERIT_GID(pip) \ - (((pip)->i_mount->m_flags & XFS_MOUNT_GRPID) || \ - (VFS_I(pip)->i_mode & S_ISGID)) - -int xfs_release(struct xfs_inode *ip); -void xfs_inactive(struct xfs_inode *ip); -int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name, - struct xfs_inode **ipp, struct xfs_name *ci_name); -int xfs_create(struct xfs_inode *dp, struct xfs_name *name, - umode_t mode, xfs_dev_t rdev, struct xfs_inode **ipp); -int xfs_create_tmpfile(struct xfs_inode *dp, struct dentry *dentry, - umode_t mode, struct xfs_inode **ipp); -int xfs_remove(struct xfs_inode *dp, struct xfs_name *name, - struct xfs_inode *ip); -int xfs_link(struct xfs_inode *tdp, struct xfs_inode *sip, - struct xfs_name *target_name); -int xfs_rename(struct xfs_inode *src_dp, struct xfs_name *src_name, - struct xfs_inode *src_ip, struct xfs_inode *target_dp, - struct xfs_name *target_name, - struct xfs_inode *target_ip, unsigned int flags); - -void xfs_ilock(xfs_inode_t *, uint); -int xfs_ilock_nowait(xfs_inode_t *, uint); -void xfs_iunlock(xfs_inode_t *, uint); -void xfs_ilock_demote(xfs_inode_t *, uint); -int xfs_isilocked(xfs_inode_t *, uint); -uint xfs_ilock_data_map_shared(struct xfs_inode *); -uint xfs_ilock_attr_map_shared(struct xfs_inode *); - -uint xfs_ip2xflags(struct xfs_inode *); -int xfs_ifree(struct xfs_trans *, xfs_inode_t *, - struct xfs_defer_ops *); -int xfs_itruncate_extents(struct xfs_trans **, struct xfs_inode *, - int, xfs_fsize_t); -void xfs_iext_realloc(xfs_inode_t *, int, int); - -void xfs_iunpin_wait(xfs_inode_t *); -#define xfs_ipincount(ip) ((unsigned int) atomic_read(&ip->i_pincount)) - -int xfs_iflush(struct xfs_inode *, struct xfs_buf **); -void xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint); - -xfs_extlen_t xfs_get_extsz_hint(struct xfs_inode *ip); -xfs_extlen_t xfs_get_cowextsz_hint(struct xfs_inode *ip); - -int xfs_dir_ialloc(struct xfs_trans **, struct xfs_inode *, umode_t, - xfs_nlink_t, xfs_dev_t, prid_t, int, - struct xfs_inode **, int *); - -/* from xfs_file.c */ -enum xfs_prealloc_flags { - XFS_PREALLOC_SET = (1 << 1), - XFS_PREALLOC_CLEAR = (1 << 2), - XFS_PREALLOC_SYNC = (1 << 3), - XFS_PREALLOC_INVISIBLE = (1 << 4), -}; - -int xfs_update_prealloc_flags(struct xfs_inode *ip, - enum xfs_prealloc_flags flags); -int xfs_zero_eof(struct xfs_inode *ip, xfs_off_t offset, - xfs_fsize_t isize, bool *did_zeroing); -int xfs_zero_range(struct xfs_inode *ip, xfs_off_t pos, xfs_off_t count, - bool *did_zero); -loff_t __xfs_seek_hole_data(struct inode *inode, loff_t start, - loff_t eof, int whence); - - -/* from xfs_iops.c */ -extern void xfs_setup_inode(struct xfs_inode *ip); -extern void xfs_setup_iops(struct xfs_inode *ip); - -/* - * When setting up a newly allocated inode, we need to call - * xfs_finish_inode_setup() once the inode is fully instantiated at - * the VFS level to prevent the rest of the world seeing the inode - * before we've completed instantiation. Otherwise we can do it - * the moment the inode lookup is complete. - */ -static inline void xfs_finish_inode_setup(struct xfs_inode *ip) -{ - xfs_iflags_clear(ip, XFS_INEW); - barrier(); - unlock_new_inode(VFS_I(ip)); -} - -static inline void xfs_setup_existing_inode(struct xfs_inode *ip) -{ - xfs_setup_inode(ip); - xfs_setup_iops(ip); - xfs_finish_inode_setup(ip); -} - -#define IHOLD(ip) \ -do { \ - ASSERT(atomic_read(&VFS_I(ip)->i_count) > 0) ; \ - ihold(VFS_I(ip)); \ - trace_xfs_ihold(ip, _THIS_IP_); \ -} while (0) - -#define IRELE(ip) \ -do { \ - trace_xfs_irele(ip, _THIS_IP_); \ - iput(VFS_I(ip)); \ -} while (0) - -extern struct kmem_zone *xfs_inode_zone; - -/* The default CoW extent size hint. */ -#define XFS_DEFAULT_COWEXTSZ_HINT 32 - -#endif /* __XFS_INODE_H__ */ diff --git a/src/linux/fs/xfs/xfs_inode_item.c b/src/linux/fs/xfs/xfs_inode_item.c deleted file mode 100644 index 9610e9c..0000000 --- a/src/linux/fs/xfs/xfs_inode_item.c +++ /dev/null @@ -1,858 +0,0 @@ -/* - * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_trans_priv.h" -#include "xfs_log.h" - - -kmem_zone_t *xfs_ili_zone; /* inode log item zone */ - -static inline struct xfs_inode_log_item *INODE_ITEM(struct xfs_log_item *lip) -{ - return container_of(lip, struct xfs_inode_log_item, ili_item); -} - -STATIC void -xfs_inode_item_data_fork_size( - struct xfs_inode_log_item *iip, - int *nvecs, - int *nbytes) -{ - struct xfs_inode *ip = iip->ili_inode; - - switch (ip->i_d.di_format) { - case XFS_DINODE_FMT_EXTENTS: - if ((iip->ili_fields & XFS_ILOG_DEXT) && - ip->i_d.di_nextents > 0 && - ip->i_df.if_bytes > 0) { - /* worst case, doesn't subtract delalloc extents */ - *nbytes += XFS_IFORK_DSIZE(ip); - *nvecs += 1; - } - break; - case XFS_DINODE_FMT_BTREE: - if ((iip->ili_fields & XFS_ILOG_DBROOT) && - ip->i_df.if_broot_bytes > 0) { - *nbytes += ip->i_df.if_broot_bytes; - *nvecs += 1; - } - break; - case XFS_DINODE_FMT_LOCAL: - if ((iip->ili_fields & XFS_ILOG_DDATA) && - ip->i_df.if_bytes > 0) { - *nbytes += roundup(ip->i_df.if_bytes, 4); - *nvecs += 1; - } - break; - - case XFS_DINODE_FMT_DEV: - case XFS_DINODE_FMT_UUID: - break; - default: - ASSERT(0); - break; - } -} - -STATIC void -xfs_inode_item_attr_fork_size( - struct xfs_inode_log_item *iip, - int *nvecs, - int *nbytes) -{ - struct xfs_inode *ip = iip->ili_inode; - - switch (ip->i_d.di_aformat) { - case XFS_DINODE_FMT_EXTENTS: - if ((iip->ili_fields & XFS_ILOG_AEXT) && - ip->i_d.di_anextents > 0 && - ip->i_afp->if_bytes > 0) { - /* worst case, doesn't subtract unused space */ - *nbytes += XFS_IFORK_ASIZE(ip); - *nvecs += 1; - } - break; - case XFS_DINODE_FMT_BTREE: - if ((iip->ili_fields & XFS_ILOG_ABROOT) && - ip->i_afp->if_broot_bytes > 0) { - *nbytes += ip->i_afp->if_broot_bytes; - *nvecs += 1; - } - break; - case XFS_DINODE_FMT_LOCAL: - if ((iip->ili_fields & XFS_ILOG_ADATA) && - ip->i_afp->if_bytes > 0) { - *nbytes += roundup(ip->i_afp->if_bytes, 4); - *nvecs += 1; - } - break; - default: - ASSERT(0); - break; - } -} - -/* - * This returns the number of iovecs needed to log the given inode item. - * - * We need one iovec for the inode log format structure, one for the - * inode core, and possibly one for the inode data/extents/b-tree root - * and one for the inode attribute data/extents/b-tree root. - */ -STATIC void -xfs_inode_item_size( - struct xfs_log_item *lip, - int *nvecs, - int *nbytes) -{ - struct xfs_inode_log_item *iip = INODE_ITEM(lip); - struct xfs_inode *ip = iip->ili_inode; - - *nvecs += 2; - *nbytes += sizeof(struct xfs_inode_log_format) + - xfs_log_dinode_size(ip->i_d.di_version); - - xfs_inode_item_data_fork_size(iip, nvecs, nbytes); - if (XFS_IFORK_Q(ip)) - xfs_inode_item_attr_fork_size(iip, nvecs, nbytes); -} - -STATIC void -xfs_inode_item_format_data_fork( - struct xfs_inode_log_item *iip, - struct xfs_inode_log_format *ilf, - struct xfs_log_vec *lv, - struct xfs_log_iovec **vecp) -{ - struct xfs_inode *ip = iip->ili_inode; - size_t data_bytes; - - switch (ip->i_d.di_format) { - case XFS_DINODE_FMT_EXTENTS: - iip->ili_fields &= - ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT | - XFS_ILOG_DEV | XFS_ILOG_UUID); - - if ((iip->ili_fields & XFS_ILOG_DEXT) && - ip->i_d.di_nextents > 0 && - ip->i_df.if_bytes > 0) { - struct xfs_bmbt_rec *p; - - ASSERT(ip->i_df.if_u1.if_extents != NULL); - ASSERT(ip->i_df.if_bytes / sizeof(xfs_bmbt_rec_t) > 0); - - p = xlog_prepare_iovec(lv, vecp, XLOG_REG_TYPE_IEXT); - data_bytes = xfs_iextents_copy(ip, p, XFS_DATA_FORK); - xlog_finish_iovec(lv, *vecp, data_bytes); - - ASSERT(data_bytes <= ip->i_df.if_bytes); - - ilf->ilf_dsize = data_bytes; - ilf->ilf_size++; - } else { - iip->ili_fields &= ~XFS_ILOG_DEXT; - } - break; - case XFS_DINODE_FMT_BTREE: - iip->ili_fields &= - ~(XFS_ILOG_DDATA | XFS_ILOG_DEXT | - XFS_ILOG_DEV | XFS_ILOG_UUID); - - if ((iip->ili_fields & XFS_ILOG_DBROOT) && - ip->i_df.if_broot_bytes > 0) { - ASSERT(ip->i_df.if_broot != NULL); - xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_IBROOT, - ip->i_df.if_broot, - ip->i_df.if_broot_bytes); - ilf->ilf_dsize = ip->i_df.if_broot_bytes; - ilf->ilf_size++; - } else { - ASSERT(!(iip->ili_fields & - XFS_ILOG_DBROOT)); - iip->ili_fields &= ~XFS_ILOG_DBROOT; - } - break; - case XFS_DINODE_FMT_LOCAL: - iip->ili_fields &= - ~(XFS_ILOG_DEXT | XFS_ILOG_DBROOT | - XFS_ILOG_DEV | XFS_ILOG_UUID); - if ((iip->ili_fields & XFS_ILOG_DDATA) && - ip->i_df.if_bytes > 0) { - /* - * Round i_bytes up to a word boundary. - * The underlying memory is guaranteed to - * to be there by xfs_idata_realloc(). - */ - data_bytes = roundup(ip->i_df.if_bytes, 4); - ASSERT(ip->i_df.if_real_bytes == 0 || - ip->i_df.if_real_bytes >= data_bytes); - ASSERT(ip->i_df.if_u1.if_data != NULL); - ASSERT(ip->i_d.di_size > 0); - xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_ILOCAL, - ip->i_df.if_u1.if_data, data_bytes); - ilf->ilf_dsize = (unsigned)data_bytes; - ilf->ilf_size++; - } else { - iip->ili_fields &= ~XFS_ILOG_DDATA; - } - break; - case XFS_DINODE_FMT_DEV: - iip->ili_fields &= - ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT | - XFS_ILOG_DEXT | XFS_ILOG_UUID); - if (iip->ili_fields & XFS_ILOG_DEV) - ilf->ilf_u.ilfu_rdev = ip->i_df.if_u2.if_rdev; - break; - case XFS_DINODE_FMT_UUID: - iip->ili_fields &= - ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT | - XFS_ILOG_DEXT | XFS_ILOG_DEV); - if (iip->ili_fields & XFS_ILOG_UUID) - ilf->ilf_u.ilfu_uuid = ip->i_df.if_u2.if_uuid; - break; - default: - ASSERT(0); - break; - } -} - -STATIC void -xfs_inode_item_format_attr_fork( - struct xfs_inode_log_item *iip, - struct xfs_inode_log_format *ilf, - struct xfs_log_vec *lv, - struct xfs_log_iovec **vecp) -{ - struct xfs_inode *ip = iip->ili_inode; - size_t data_bytes; - - switch (ip->i_d.di_aformat) { - case XFS_DINODE_FMT_EXTENTS: - iip->ili_fields &= - ~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT); - - if ((iip->ili_fields & XFS_ILOG_AEXT) && - ip->i_d.di_anextents > 0 && - ip->i_afp->if_bytes > 0) { - struct xfs_bmbt_rec *p; - - ASSERT(ip->i_afp->if_bytes / sizeof(xfs_bmbt_rec_t) == - ip->i_d.di_anextents); - ASSERT(ip->i_afp->if_u1.if_extents != NULL); - - p = xlog_prepare_iovec(lv, vecp, XLOG_REG_TYPE_IATTR_EXT); - data_bytes = xfs_iextents_copy(ip, p, XFS_ATTR_FORK); - xlog_finish_iovec(lv, *vecp, data_bytes); - - ilf->ilf_asize = data_bytes; - ilf->ilf_size++; - } else { - iip->ili_fields &= ~XFS_ILOG_AEXT; - } - break; - case XFS_DINODE_FMT_BTREE: - iip->ili_fields &= - ~(XFS_ILOG_ADATA | XFS_ILOG_AEXT); - - if ((iip->ili_fields & XFS_ILOG_ABROOT) && - ip->i_afp->if_broot_bytes > 0) { - ASSERT(ip->i_afp->if_broot != NULL); - - xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_IATTR_BROOT, - ip->i_afp->if_broot, - ip->i_afp->if_broot_bytes); - ilf->ilf_asize = ip->i_afp->if_broot_bytes; - ilf->ilf_size++; - } else { - iip->ili_fields &= ~XFS_ILOG_ABROOT; - } - break; - case XFS_DINODE_FMT_LOCAL: - iip->ili_fields &= - ~(XFS_ILOG_AEXT | XFS_ILOG_ABROOT); - - if ((iip->ili_fields & XFS_ILOG_ADATA) && - ip->i_afp->if_bytes > 0) { - /* - * Round i_bytes up to a word boundary. - * The underlying memory is guaranteed to - * to be there by xfs_idata_realloc(). - */ - data_bytes = roundup(ip->i_afp->if_bytes, 4); - ASSERT(ip->i_afp->if_real_bytes == 0 || - ip->i_afp->if_real_bytes >= data_bytes); - ASSERT(ip->i_afp->if_u1.if_data != NULL); - xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_IATTR_LOCAL, - ip->i_afp->if_u1.if_data, - data_bytes); - ilf->ilf_asize = (unsigned)data_bytes; - ilf->ilf_size++; - } else { - iip->ili_fields &= ~XFS_ILOG_ADATA; - } - break; - default: - ASSERT(0); - break; - } -} - -static void -xfs_inode_to_log_dinode( - struct xfs_inode *ip, - struct xfs_log_dinode *to, - xfs_lsn_t lsn) -{ - struct xfs_icdinode *from = &ip->i_d; - struct inode *inode = VFS_I(ip); - - to->di_magic = XFS_DINODE_MAGIC; - - to->di_version = from->di_version; - to->di_format = from->di_format; - to->di_uid = from->di_uid; - to->di_gid = from->di_gid; - to->di_projid_lo = from->di_projid_lo; - to->di_projid_hi = from->di_projid_hi; - - memset(to->di_pad, 0, sizeof(to->di_pad)); - memset(to->di_pad3, 0, sizeof(to->di_pad3)); - to->di_atime.t_sec = inode->i_atime.tv_sec; - to->di_atime.t_nsec = inode->i_atime.tv_nsec; - to->di_mtime.t_sec = inode->i_mtime.tv_sec; - to->di_mtime.t_nsec = inode->i_mtime.tv_nsec; - to->di_ctime.t_sec = inode->i_ctime.tv_sec; - to->di_ctime.t_nsec = inode->i_ctime.tv_nsec; - to->di_nlink = inode->i_nlink; - to->di_gen = inode->i_generation; - to->di_mode = inode->i_mode; - - to->di_size = from->di_size; - to->di_nblocks = from->di_nblocks; - to->di_extsize = from->di_extsize; - to->di_nextents = from->di_nextents; - to->di_anextents = from->di_anextents; - to->di_forkoff = from->di_forkoff; - to->di_aformat = from->di_aformat; - to->di_dmevmask = from->di_dmevmask; - to->di_dmstate = from->di_dmstate; - to->di_flags = from->di_flags; - - if (from->di_version == 3) { - to->di_changecount = inode->i_version; - to->di_crtime.t_sec = from->di_crtime.t_sec; - to->di_crtime.t_nsec = from->di_crtime.t_nsec; - to->di_flags2 = from->di_flags2; - to->di_cowextsize = from->di_cowextsize; - to->di_ino = ip->i_ino; - to->di_lsn = lsn; - memset(to->di_pad2, 0, sizeof(to->di_pad2)); - uuid_copy(&to->di_uuid, &ip->i_mount->m_sb.sb_meta_uuid); - to->di_flushiter = 0; - } else { - to->di_flushiter = from->di_flushiter; - } -} - -/* - * Format the inode core. Current timestamp data is only in the VFS inode - * fields, so we need to grab them from there. Hence rather than just copying - * the XFS inode core structure, format the fields directly into the iovec. - */ -static void -xfs_inode_item_format_core( - struct xfs_inode *ip, - struct xfs_log_vec *lv, - struct xfs_log_iovec **vecp) -{ - struct xfs_log_dinode *dic; - - dic = xlog_prepare_iovec(lv, vecp, XLOG_REG_TYPE_ICORE); - xfs_inode_to_log_dinode(ip, dic, ip->i_itemp->ili_item.li_lsn); - xlog_finish_iovec(lv, *vecp, xfs_log_dinode_size(ip->i_d.di_version)); -} - -/* - * This is called to fill in the vector of log iovecs for the given inode - * log item. It fills the first item with an inode log format structure, - * the second with the on-disk inode structure, and a possible third and/or - * fourth with the inode data/extents/b-tree root and inode attributes - * data/extents/b-tree root. - */ -STATIC void -xfs_inode_item_format( - struct xfs_log_item *lip, - struct xfs_log_vec *lv) -{ - struct xfs_inode_log_item *iip = INODE_ITEM(lip); - struct xfs_inode *ip = iip->ili_inode; - struct xfs_inode_log_format *ilf; - struct xfs_log_iovec *vecp = NULL; - - ASSERT(ip->i_d.di_version > 1); - - ilf = xlog_prepare_iovec(lv, &vecp, XLOG_REG_TYPE_IFORMAT); - ilf->ilf_type = XFS_LI_INODE; - ilf->ilf_ino = ip->i_ino; - ilf->ilf_blkno = ip->i_imap.im_blkno; - ilf->ilf_len = ip->i_imap.im_len; - ilf->ilf_boffset = ip->i_imap.im_boffset; - ilf->ilf_fields = XFS_ILOG_CORE; - ilf->ilf_size = 2; /* format + core */ - xlog_finish_iovec(lv, vecp, sizeof(struct xfs_inode_log_format)); - - xfs_inode_item_format_core(ip, lv, &vecp); - xfs_inode_item_format_data_fork(iip, ilf, lv, &vecp); - if (XFS_IFORK_Q(ip)) { - xfs_inode_item_format_attr_fork(iip, ilf, lv, &vecp); - } else { - iip->ili_fields &= - ~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT | XFS_ILOG_AEXT); - } - - /* update the format with the exact fields we actually logged */ - ilf->ilf_fields |= (iip->ili_fields & ~XFS_ILOG_TIMESTAMP); -} - -/* - * This is called to pin the inode associated with the inode log - * item in memory so it cannot be written out. - */ -STATIC void -xfs_inode_item_pin( - struct xfs_log_item *lip) -{ - struct xfs_inode *ip = INODE_ITEM(lip)->ili_inode; - - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - - trace_xfs_inode_pin(ip, _RET_IP_); - atomic_inc(&ip->i_pincount); -} - - -/* - * This is called to unpin the inode associated with the inode log - * item which was previously pinned with a call to xfs_inode_item_pin(). - * - * Also wake up anyone in xfs_iunpin_wait() if the count goes to 0. - */ -STATIC void -xfs_inode_item_unpin( - struct xfs_log_item *lip, - int remove) -{ - struct xfs_inode *ip = INODE_ITEM(lip)->ili_inode; - - trace_xfs_inode_unpin(ip, _RET_IP_); - ASSERT(atomic_read(&ip->i_pincount) > 0); - if (atomic_dec_and_test(&ip->i_pincount)) - wake_up_bit(&ip->i_flags, __XFS_IPINNED_BIT); -} - -STATIC uint -xfs_inode_item_push( - struct xfs_log_item *lip, - struct list_head *buffer_list) - __releases(&lip->li_ailp->xa_lock) - __acquires(&lip->li_ailp->xa_lock) -{ - struct xfs_inode_log_item *iip = INODE_ITEM(lip); - struct xfs_inode *ip = iip->ili_inode; - struct xfs_buf *bp = NULL; - uint rval = XFS_ITEM_SUCCESS; - int error; - - if (xfs_ipincount(ip) > 0) - return XFS_ITEM_PINNED; - - if (!xfs_ilock_nowait(ip, XFS_ILOCK_SHARED)) - return XFS_ITEM_LOCKED; - - /* - * Re-check the pincount now that we stabilized the value by - * taking the ilock. - */ - if (xfs_ipincount(ip) > 0) { - rval = XFS_ITEM_PINNED; - goto out_unlock; - } - - /* - * Stale inode items should force out the iclog. - */ - if (ip->i_flags & XFS_ISTALE) { - rval = XFS_ITEM_PINNED; - goto out_unlock; - } - - /* - * Someone else is already flushing the inode. Nothing we can do - * here but wait for the flush to finish and remove the item from - * the AIL. - */ - if (!xfs_iflock_nowait(ip)) { - rval = XFS_ITEM_FLUSHING; - goto out_unlock; - } - - ASSERT(iip->ili_fields != 0 || XFS_FORCED_SHUTDOWN(ip->i_mount)); - ASSERT(iip->ili_logged == 0 || XFS_FORCED_SHUTDOWN(ip->i_mount)); - - spin_unlock(&lip->li_ailp->xa_lock); - - error = xfs_iflush(ip, &bp); - if (!error) { - if (!xfs_buf_delwri_queue(bp, buffer_list)) - rval = XFS_ITEM_FLUSHING; - xfs_buf_relse(bp); - } - - spin_lock(&lip->li_ailp->xa_lock); -out_unlock: - xfs_iunlock(ip, XFS_ILOCK_SHARED); - return rval; -} - -/* - * Unlock the inode associated with the inode log item. - * Clear the fields of the inode and inode log item that - * are specific to the current transaction. If the - * hold flags is set, do not unlock the inode. - */ -STATIC void -xfs_inode_item_unlock( - struct xfs_log_item *lip) -{ - struct xfs_inode_log_item *iip = INODE_ITEM(lip); - struct xfs_inode *ip = iip->ili_inode; - unsigned short lock_flags; - - ASSERT(ip->i_itemp != NULL); - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - - lock_flags = iip->ili_lock_flags; - iip->ili_lock_flags = 0; - if (lock_flags) - xfs_iunlock(ip, lock_flags); -} - -/* - * This is called to find out where the oldest active copy of the inode log - * item in the on disk log resides now that the last log write of it completed - * at the given lsn. Since we always re-log all dirty data in an inode, the - * latest copy in the on disk log is the only one that matters. Therefore, - * simply return the given lsn. - * - * If the inode has been marked stale because the cluster is being freed, we - * don't want to (re-)insert this inode into the AIL. There is a race condition - * where the cluster buffer may be unpinned before the inode is inserted into - * the AIL during transaction committed processing. If the buffer is unpinned - * before the inode item has been committed and inserted, then it is possible - * for the buffer to be written and IO completes before the inode is inserted - * into the AIL. In that case, we'd be inserting a clean, stale inode into the - * AIL which will never get removed. It will, however, get reclaimed which - * triggers an assert in xfs_inode_free() complaining about freein an inode - * still in the AIL. - * - * To avoid this, just unpin the inode directly and return a LSN of -1 so the - * transaction committed code knows that it does not need to do any further - * processing on the item. - */ -STATIC xfs_lsn_t -xfs_inode_item_committed( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ - struct xfs_inode_log_item *iip = INODE_ITEM(lip); - struct xfs_inode *ip = iip->ili_inode; - - if (xfs_iflags_test(ip, XFS_ISTALE)) { - xfs_inode_item_unpin(lip, 0); - return -1; - } - return lsn; -} - -/* - * XXX rcc - this one really has to do something. Probably needs - * to stamp in a new field in the incore inode. - */ -STATIC void -xfs_inode_item_committing( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ - INODE_ITEM(lip)->ili_last_lsn = lsn; -} - -/* - * This is the ops vector shared by all buf log items. - */ -static const struct xfs_item_ops xfs_inode_item_ops = { - .iop_size = xfs_inode_item_size, - .iop_format = xfs_inode_item_format, - .iop_pin = xfs_inode_item_pin, - .iop_unpin = xfs_inode_item_unpin, - .iop_unlock = xfs_inode_item_unlock, - .iop_committed = xfs_inode_item_committed, - .iop_push = xfs_inode_item_push, - .iop_committing = xfs_inode_item_committing -}; - - -/* - * Initialize the inode log item for a newly allocated (in-core) inode. - */ -void -xfs_inode_item_init( - struct xfs_inode *ip, - struct xfs_mount *mp) -{ - struct xfs_inode_log_item *iip; - - ASSERT(ip->i_itemp == NULL); - iip = ip->i_itemp = kmem_zone_zalloc(xfs_ili_zone, KM_SLEEP); - - iip->ili_inode = ip; - xfs_log_item_init(mp, &iip->ili_item, XFS_LI_INODE, - &xfs_inode_item_ops); -} - -/* - * Free the inode log item and any memory hanging off of it. - */ -void -xfs_inode_item_destroy( - xfs_inode_t *ip) -{ - kmem_free(ip->i_itemp->ili_item.li_lv_shadow); - kmem_zone_free(xfs_ili_zone, ip->i_itemp); -} - - -/* - * This is the inode flushing I/O completion routine. It is called - * from interrupt level when the buffer containing the inode is - * flushed to disk. It is responsible for removing the inode item - * from the AIL if it has not been re-logged, and unlocking the inode's - * flush lock. - * - * To reduce AIL lock traffic as much as possible, we scan the buffer log item - * list for other inodes that will run this function. We remove them from the - * buffer list so we can process all the inode IO completions in one AIL lock - * traversal. - */ -void -xfs_iflush_done( - struct xfs_buf *bp, - struct xfs_log_item *lip) -{ - struct xfs_inode_log_item *iip; - struct xfs_log_item *blip; - struct xfs_log_item *next; - struct xfs_log_item *prev; - struct xfs_ail *ailp = lip->li_ailp; - int need_ail = 0; - - /* - * Scan the buffer IO completions for other inodes being completed and - * attach them to the current inode log item. - */ - blip = bp->b_fspriv; - prev = NULL; - while (blip != NULL) { - if (blip->li_cb != xfs_iflush_done) { - prev = blip; - blip = blip->li_bio_list; - continue; - } - - /* remove from list */ - next = blip->li_bio_list; - if (!prev) { - bp->b_fspriv = next; - } else { - prev->li_bio_list = next; - } - - /* add to current list */ - blip->li_bio_list = lip->li_bio_list; - lip->li_bio_list = blip; - - /* - * while we have the item, do the unlocked check for needing - * the AIL lock. - */ - iip = INODE_ITEM(blip); - if (iip->ili_logged && blip->li_lsn == iip->ili_flush_lsn) - need_ail++; - - blip = next; - } - - /* make sure we capture the state of the initial inode. */ - iip = INODE_ITEM(lip); - if (iip->ili_logged && lip->li_lsn == iip->ili_flush_lsn) - need_ail++; - - /* - * We only want to pull the item from the AIL if it is - * actually there and its location in the log has not - * changed since we started the flush. Thus, we only bother - * if the ili_logged flag is set and the inode's lsn has not - * changed. First we check the lsn outside - * the lock since it's cheaper, and then we recheck while - * holding the lock before removing the inode from the AIL. - */ - if (need_ail) { - struct xfs_log_item *log_items[need_ail]; - int i = 0; - spin_lock(&ailp->xa_lock); - for (blip = lip; blip; blip = blip->li_bio_list) { - iip = INODE_ITEM(blip); - if (iip->ili_logged && - blip->li_lsn == iip->ili_flush_lsn) { - log_items[i++] = blip; - } - ASSERT(i <= need_ail); - } - /* xfs_trans_ail_delete_bulk() drops the AIL lock. */ - xfs_trans_ail_delete_bulk(ailp, log_items, i, - SHUTDOWN_CORRUPT_INCORE); - } - - - /* - * clean up and unlock the flush lock now we are done. We can clear the - * ili_last_fields bits now that we know that the data corresponding to - * them is safely on disk. - */ - for (blip = lip; blip; blip = next) { - next = blip->li_bio_list; - blip->li_bio_list = NULL; - - iip = INODE_ITEM(blip); - iip->ili_logged = 0; - iip->ili_last_fields = 0; - xfs_ifunlock(iip->ili_inode); - } -} - -/* - * This is the inode flushing abort routine. It is called from xfs_iflush when - * the filesystem is shutting down to clean up the inode state. It is - * responsible for removing the inode item from the AIL if it has not been - * re-logged, and unlocking the inode's flush lock. - */ -void -xfs_iflush_abort( - xfs_inode_t *ip, - bool stale) -{ - xfs_inode_log_item_t *iip = ip->i_itemp; - - if (iip) { - if (iip->ili_item.li_flags & XFS_LI_IN_AIL) { - xfs_trans_ail_remove(&iip->ili_item, - stale ? SHUTDOWN_LOG_IO_ERROR : - SHUTDOWN_CORRUPT_INCORE); - } - iip->ili_logged = 0; - /* - * Clear the ili_last_fields bits now that we know that the - * data corresponding to them is safely on disk. - */ - iip->ili_last_fields = 0; - /* - * Clear the inode logging fields so no more flushes are - * attempted. - */ - iip->ili_fields = 0; - iip->ili_fsync_fields = 0; - } - /* - * Release the inode's flush lock since we're done with it. - */ - xfs_ifunlock(ip); -} - -void -xfs_istale_done( - struct xfs_buf *bp, - struct xfs_log_item *lip) -{ - xfs_iflush_abort(INODE_ITEM(lip)->ili_inode, true); -} - -/* - * convert an xfs_inode_log_format struct from either 32 or 64 bit versions - * (which can have different field alignments) to the native version - */ -int -xfs_inode_item_format_convert( - xfs_log_iovec_t *buf, - xfs_inode_log_format_t *in_f) -{ - if (buf->i_len == sizeof(xfs_inode_log_format_32_t)) { - xfs_inode_log_format_32_t *in_f32 = buf->i_addr; - - in_f->ilf_type = in_f32->ilf_type; - in_f->ilf_size = in_f32->ilf_size; - in_f->ilf_fields = in_f32->ilf_fields; - in_f->ilf_asize = in_f32->ilf_asize; - in_f->ilf_dsize = in_f32->ilf_dsize; - in_f->ilf_ino = in_f32->ilf_ino; - /* copy biggest field of ilf_u */ - memcpy(in_f->ilf_u.ilfu_uuid.__u_bits, - in_f32->ilf_u.ilfu_uuid.__u_bits, - sizeof(uuid_t)); - in_f->ilf_blkno = in_f32->ilf_blkno; - in_f->ilf_len = in_f32->ilf_len; - in_f->ilf_boffset = in_f32->ilf_boffset; - return 0; - } else if (buf->i_len == sizeof(xfs_inode_log_format_64_t)){ - xfs_inode_log_format_64_t *in_f64 = buf->i_addr; - - in_f->ilf_type = in_f64->ilf_type; - in_f->ilf_size = in_f64->ilf_size; - in_f->ilf_fields = in_f64->ilf_fields; - in_f->ilf_asize = in_f64->ilf_asize; - in_f->ilf_dsize = in_f64->ilf_dsize; - in_f->ilf_ino = in_f64->ilf_ino; - /* copy biggest field of ilf_u */ - memcpy(in_f->ilf_u.ilfu_uuid.__u_bits, - in_f64->ilf_u.ilfu_uuid.__u_bits, - sizeof(uuid_t)); - in_f->ilf_blkno = in_f64->ilf_blkno; - in_f->ilf_len = in_f64->ilf_len; - in_f->ilf_boffset = in_f64->ilf_boffset; - return 0; - } - return -EFSCORRUPTED; -} diff --git a/src/linux/fs/xfs/xfs_inode_item.h b/src/linux/fs/xfs/xfs_inode_item.h deleted file mode 100644 index 4c7722e..0000000 --- a/src/linux/fs/xfs/xfs_inode_item.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2000,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_INODE_ITEM_H__ -#define __XFS_INODE_ITEM_H__ - -/* kernel only definitions */ - -struct xfs_buf; -struct xfs_bmbt_rec; -struct xfs_inode; -struct xfs_mount; - -typedef struct xfs_inode_log_item { - xfs_log_item_t ili_item; /* common portion */ - struct xfs_inode *ili_inode; /* inode ptr */ - xfs_lsn_t ili_flush_lsn; /* lsn at last flush */ - xfs_lsn_t ili_last_lsn; /* lsn at last transaction */ - unsigned short ili_lock_flags; /* lock flags */ - unsigned short ili_logged; /* flushed logged data */ - unsigned int ili_last_fields; /* fields when flushed */ - unsigned int ili_fields; /* fields to be logged */ - unsigned int ili_fsync_fields; /* logged since last fsync */ -} xfs_inode_log_item_t; - -static inline int xfs_inode_clean(xfs_inode_t *ip) -{ - return !ip->i_itemp || !(ip->i_itemp->ili_fields & XFS_ILOG_ALL); -} - -extern void xfs_inode_item_init(struct xfs_inode *, struct xfs_mount *); -extern void xfs_inode_item_destroy(struct xfs_inode *); -extern void xfs_iflush_done(struct xfs_buf *, struct xfs_log_item *); -extern void xfs_istale_done(struct xfs_buf *, struct xfs_log_item *); -extern void xfs_iflush_abort(struct xfs_inode *, bool); -extern int xfs_inode_item_format_convert(xfs_log_iovec_t *, - xfs_inode_log_format_t *); - -extern struct kmem_zone *xfs_ili_zone; - -#endif /* __XFS_INODE_ITEM_H__ */ diff --git a/src/linux/fs/xfs/xfs_ioctl.c b/src/linux/fs/xfs/xfs_ioctl.c deleted file mode 100644 index c245bed..0000000 --- a/src/linux/fs/xfs/xfs_ioctl.c +++ /dev/null @@ -1,1989 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_inode.h" -#include "xfs_ioctl.h" -#include "xfs_alloc.h" -#include "xfs_rtalloc.h" -#include "xfs_itable.h" -#include "xfs_error.h" -#include "xfs_attr.h" -#include "xfs_bmap.h" -#include "xfs_bmap_util.h" -#include "xfs_fsops.h" -#include "xfs_discard.h" -#include "xfs_quota.h" -#include "xfs_export.h" -#include "xfs_trace.h" -#include "xfs_icache.h" -#include "xfs_symlink.h" -#include "xfs_trans.h" -#include "xfs_pnfs.h" -#include "xfs_acl.h" - -#include -#include -#include -#include -#include -#include -#include - -/* - * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to - * a file or fs handle. - * - * XFS_IOC_PATH_TO_FSHANDLE - * returns fs handle for a mount point or path within that mount point - * XFS_IOC_FD_TO_HANDLE - * returns full handle for a FD opened in user space - * XFS_IOC_PATH_TO_HANDLE - * returns full handle for a path - */ -int -xfs_find_handle( - unsigned int cmd, - xfs_fsop_handlereq_t *hreq) -{ - int hsize; - xfs_handle_t handle; - struct inode *inode; - struct fd f = {NULL}; - struct path path; - int error; - struct xfs_inode *ip; - - if (cmd == XFS_IOC_FD_TO_HANDLE) { - f = fdget(hreq->fd); - if (!f.file) - return -EBADF; - inode = file_inode(f.file); - } else { - error = user_lpath((const char __user *)hreq->path, &path); - if (error) - return error; - inode = d_inode(path.dentry); - } - ip = XFS_I(inode); - - /* - * We can only generate handles for inodes residing on a XFS filesystem, - * and only for regular files, directories or symbolic links. - */ - error = -EINVAL; - if (inode->i_sb->s_magic != XFS_SB_MAGIC) - goto out_put; - - error = -EBADF; - if (!S_ISREG(inode->i_mode) && - !S_ISDIR(inode->i_mode) && - !S_ISLNK(inode->i_mode)) - goto out_put; - - - memcpy(&handle.ha_fsid, ip->i_mount->m_fixedfsid, sizeof(xfs_fsid_t)); - - if (cmd == XFS_IOC_PATH_TO_FSHANDLE) { - /* - * This handle only contains an fsid, zero the rest. - */ - memset(&handle.ha_fid, 0, sizeof(handle.ha_fid)); - hsize = sizeof(xfs_fsid_t); - } else { - handle.ha_fid.fid_len = sizeof(xfs_fid_t) - - sizeof(handle.ha_fid.fid_len); - handle.ha_fid.fid_pad = 0; - handle.ha_fid.fid_gen = inode->i_generation; - handle.ha_fid.fid_ino = ip->i_ino; - - hsize = XFS_HSIZE(handle); - } - - error = -EFAULT; - if (copy_to_user(hreq->ohandle, &handle, hsize) || - copy_to_user(hreq->ohandlen, &hsize, sizeof(__s32))) - goto out_put; - - error = 0; - - out_put: - if (cmd == XFS_IOC_FD_TO_HANDLE) - fdput(f); - else - path_put(&path); - return error; -} - -/* - * No need to do permission checks on the various pathname components - * as the handle operations are privileged. - */ -STATIC int -xfs_handle_acceptable( - void *context, - struct dentry *dentry) -{ - return 1; -} - -/* - * Convert userspace handle data into a dentry. - */ -struct dentry * -xfs_handle_to_dentry( - struct file *parfilp, - void __user *uhandle, - u32 hlen) -{ - xfs_handle_t handle; - struct xfs_fid64 fid; - - /* - * Only allow handle opens under a directory. - */ - if (!S_ISDIR(file_inode(parfilp)->i_mode)) - return ERR_PTR(-ENOTDIR); - - if (hlen != sizeof(xfs_handle_t)) - return ERR_PTR(-EINVAL); - if (copy_from_user(&handle, uhandle, hlen)) - return ERR_PTR(-EFAULT); - if (handle.ha_fid.fid_len != - sizeof(handle.ha_fid) - sizeof(handle.ha_fid.fid_len)) - return ERR_PTR(-EINVAL); - - memset(&fid, 0, sizeof(struct fid)); - fid.ino = handle.ha_fid.fid_ino; - fid.gen = handle.ha_fid.fid_gen; - - return exportfs_decode_fh(parfilp->f_path.mnt, (struct fid *)&fid, 3, - FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG, - xfs_handle_acceptable, NULL); -} - -STATIC struct dentry * -xfs_handlereq_to_dentry( - struct file *parfilp, - xfs_fsop_handlereq_t *hreq) -{ - return xfs_handle_to_dentry(parfilp, hreq->ihandle, hreq->ihandlen); -} - -int -xfs_open_by_handle( - struct file *parfilp, - xfs_fsop_handlereq_t *hreq) -{ - const struct cred *cred = current_cred(); - int error; - int fd; - int permflag; - struct file *filp; - struct inode *inode; - struct dentry *dentry; - fmode_t fmode; - struct path path; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - dentry = xfs_handlereq_to_dentry(parfilp, hreq); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - inode = d_inode(dentry); - - /* Restrict xfs_open_by_handle to directories & regular files. */ - if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) { - error = -EPERM; - goto out_dput; - } - -#if BITS_PER_LONG != 32 - hreq->oflags |= O_LARGEFILE; -#endif - - permflag = hreq->oflags; - fmode = OPEN_FMODE(permflag); - if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) && - (fmode & FMODE_WRITE) && IS_APPEND(inode)) { - error = -EPERM; - goto out_dput; - } - - if ((fmode & FMODE_WRITE) && IS_IMMUTABLE(inode)) { - error = -EPERM; - goto out_dput; - } - - /* Can't write directories. */ - if (S_ISDIR(inode->i_mode) && (fmode & FMODE_WRITE)) { - error = -EISDIR; - goto out_dput; - } - - fd = get_unused_fd_flags(0); - if (fd < 0) { - error = fd; - goto out_dput; - } - - path.mnt = parfilp->f_path.mnt; - path.dentry = dentry; - filp = dentry_open(&path, hreq->oflags, cred); - dput(dentry); - if (IS_ERR(filp)) { - put_unused_fd(fd); - return PTR_ERR(filp); - } - - if (S_ISREG(inode->i_mode)) { - filp->f_flags |= O_NOATIME; - filp->f_mode |= FMODE_NOCMTIME; - } - - fd_install(fd, filp); - return fd; - - out_dput: - dput(dentry); - return error; -} - -int -xfs_readlink_by_handle( - struct file *parfilp, - xfs_fsop_handlereq_t *hreq) -{ - struct dentry *dentry; - __u32 olen; - int error; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - dentry = xfs_handlereq_to_dentry(parfilp, hreq); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - - /* Restrict this handle operation to symlinks only. */ - if (!d_inode(dentry)->i_op->readlink) { - error = -EINVAL; - goto out_dput; - } - - if (copy_from_user(&olen, hreq->ohandlen, sizeof(__u32))) { - error = -EFAULT; - goto out_dput; - } - - error = d_inode(dentry)->i_op->readlink(dentry, hreq->ohandle, olen); - - out_dput: - dput(dentry); - return error; -} - -int -xfs_set_dmattrs( - xfs_inode_t *ip, - u_int evmask, - u_int16_t state) -{ - xfs_mount_t *mp = ip->i_mount; - xfs_trans_t *tp; - int error; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0, 0, 0, &tp); - if (error) - return error; - - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); - - ip->i_d.di_dmevmask = evmask; - ip->i_d.di_dmstate = state; - - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - error = xfs_trans_commit(tp); - - return error; -} - -STATIC int -xfs_fssetdm_by_handle( - struct file *parfilp, - void __user *arg) -{ - int error; - struct fsdmidata fsd; - xfs_fsop_setdm_handlereq_t dmhreq; - struct dentry *dentry; - - if (!capable(CAP_MKNOD)) - return -EPERM; - if (copy_from_user(&dmhreq, arg, sizeof(xfs_fsop_setdm_handlereq_t))) - return -EFAULT; - - error = mnt_want_write_file(parfilp); - if (error) - return error; - - dentry = xfs_handlereq_to_dentry(parfilp, &dmhreq.hreq); - if (IS_ERR(dentry)) { - mnt_drop_write_file(parfilp); - return PTR_ERR(dentry); - } - - if (IS_IMMUTABLE(d_inode(dentry)) || IS_APPEND(d_inode(dentry))) { - error = -EPERM; - goto out; - } - - if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) { - error = -EFAULT; - goto out; - } - - error = xfs_set_dmattrs(XFS_I(d_inode(dentry)), fsd.fsd_dmevmask, - fsd.fsd_dmstate); - - out: - mnt_drop_write_file(parfilp); - dput(dentry); - return error; -} - -STATIC int -xfs_attrlist_by_handle( - struct file *parfilp, - void __user *arg) -{ - int error = -ENOMEM; - attrlist_cursor_kern_t *cursor; - struct xfs_fsop_attrlist_handlereq __user *p = arg; - xfs_fsop_attrlist_handlereq_t al_hreq; - struct dentry *dentry; - char *kbuf; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (copy_from_user(&al_hreq, arg, sizeof(xfs_fsop_attrlist_handlereq_t))) - return -EFAULT; - if (al_hreq.buflen < sizeof(struct attrlist) || - al_hreq.buflen > XFS_XATTR_LIST_MAX) - return -EINVAL; - - /* - * Reject flags, only allow namespaces. - */ - if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE)) - return -EINVAL; - - dentry = xfs_handlereq_to_dentry(parfilp, &al_hreq.hreq); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - - kbuf = kmem_zalloc_large(al_hreq.buflen, KM_SLEEP); - if (!kbuf) - goto out_dput; - - cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; - error = xfs_attr_list(XFS_I(d_inode(dentry)), kbuf, al_hreq.buflen, - al_hreq.flags, cursor); - if (error) - goto out_kfree; - - if (copy_to_user(&p->pos, cursor, sizeof(attrlist_cursor_kern_t))) { - error = -EFAULT; - goto out_kfree; - } - - if (copy_to_user(al_hreq.buffer, kbuf, al_hreq.buflen)) - error = -EFAULT; - -out_kfree: - kmem_free(kbuf); -out_dput: - dput(dentry); - return error; -} - -int -xfs_attrmulti_attr_get( - struct inode *inode, - unsigned char *name, - unsigned char __user *ubuf, - __uint32_t *len, - __uint32_t flags) -{ - unsigned char *kbuf; - int error = -EFAULT; - - if (*len > XFS_XATTR_SIZE_MAX) - return -EINVAL; - kbuf = kmem_zalloc_large(*len, KM_SLEEP); - if (!kbuf) - return -ENOMEM; - - error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags); - if (error) - goto out_kfree; - - if (copy_to_user(ubuf, kbuf, *len)) - error = -EFAULT; - -out_kfree: - kmem_free(kbuf); - return error; -} - -int -xfs_attrmulti_attr_set( - struct inode *inode, - unsigned char *name, - const unsigned char __user *ubuf, - __uint32_t len, - __uint32_t flags) -{ - unsigned char *kbuf; - int error; - - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - return -EPERM; - if (len > XFS_XATTR_SIZE_MAX) - return -EINVAL; - - kbuf = memdup_user(ubuf, len); - if (IS_ERR(kbuf)) - return PTR_ERR(kbuf); - - error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags); - if (!error) - xfs_forget_acl(inode, name, flags); - kfree(kbuf); - return error; -} - -int -xfs_attrmulti_attr_remove( - struct inode *inode, - unsigned char *name, - __uint32_t flags) -{ - int error; - - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - return -EPERM; - error = xfs_attr_remove(XFS_I(inode), name, flags); - if (!error) - xfs_forget_acl(inode, name, flags); - return error; -} - -STATIC int -xfs_attrmulti_by_handle( - struct file *parfilp, - void __user *arg) -{ - int error; - xfs_attr_multiop_t *ops; - xfs_fsop_attrmulti_handlereq_t am_hreq; - struct dentry *dentry; - unsigned int i, size; - unsigned char *attr_name; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - if (copy_from_user(&am_hreq, arg, sizeof(xfs_fsop_attrmulti_handlereq_t))) - return -EFAULT; - - /* overflow check */ - if (am_hreq.opcount >= INT_MAX / sizeof(xfs_attr_multiop_t)) - return -E2BIG; - - dentry = xfs_handlereq_to_dentry(parfilp, &am_hreq.hreq); - if (IS_ERR(dentry)) - return PTR_ERR(dentry); - - error = -E2BIG; - size = am_hreq.opcount * sizeof(xfs_attr_multiop_t); - if (!size || size > 16 * PAGE_SIZE) - goto out_dput; - - ops = memdup_user(am_hreq.ops, size); - if (IS_ERR(ops)) { - error = PTR_ERR(ops); - goto out_dput; - } - - error = -ENOMEM; - attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL); - if (!attr_name) - goto out_kfree_ops; - - error = 0; - for (i = 0; i < am_hreq.opcount; i++) { - ops[i].am_error = strncpy_from_user((char *)attr_name, - ops[i].am_attrname, MAXNAMELEN); - if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN) - error = -ERANGE; - if (ops[i].am_error < 0) - break; - - switch (ops[i].am_opcode) { - case ATTR_OP_GET: - ops[i].am_error = xfs_attrmulti_attr_get( - d_inode(dentry), attr_name, - ops[i].am_attrvalue, &ops[i].am_length, - ops[i].am_flags); - break; - case ATTR_OP_SET: - ops[i].am_error = mnt_want_write_file(parfilp); - if (ops[i].am_error) - break; - ops[i].am_error = xfs_attrmulti_attr_set( - d_inode(dentry), attr_name, - ops[i].am_attrvalue, ops[i].am_length, - ops[i].am_flags); - mnt_drop_write_file(parfilp); - break; - case ATTR_OP_REMOVE: - ops[i].am_error = mnt_want_write_file(parfilp); - if (ops[i].am_error) - break; - ops[i].am_error = xfs_attrmulti_attr_remove( - d_inode(dentry), attr_name, - ops[i].am_flags); - mnt_drop_write_file(parfilp); - break; - default: - ops[i].am_error = -EINVAL; - } - } - - if (copy_to_user(am_hreq.ops, ops, size)) - error = -EFAULT; - - kfree(attr_name); - out_kfree_ops: - kfree(ops); - out_dput: - dput(dentry); - return error; -} - -int -xfs_ioc_space( - struct file *filp, - unsigned int cmd, - xfs_flock64_t *bf) -{ - struct inode *inode = file_inode(filp); - struct xfs_inode *ip = XFS_I(inode); - struct iattr iattr; - enum xfs_prealloc_flags flags = 0; - uint iolock = XFS_IOLOCK_EXCL; - int error; - - /* - * Only allow the sys admin to reserve space unless - * unwritten extents are enabled. - */ - if (!xfs_sb_version_hasextflgbit(&ip->i_mount->m_sb) && - !capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (inode->i_flags & (S_IMMUTABLE|S_APPEND)) - return -EPERM; - - if (!(filp->f_mode & FMODE_WRITE)) - return -EBADF; - - if (!S_ISREG(inode->i_mode)) - return -EINVAL; - - if (filp->f_flags & O_DSYNC) - flags |= XFS_PREALLOC_SYNC; - if (filp->f_mode & FMODE_NOCMTIME) - flags |= XFS_PREALLOC_INVISIBLE; - - error = mnt_want_write_file(filp); - if (error) - return error; - - xfs_ilock(ip, iolock); - error = xfs_break_layouts(inode, &iolock, false); - if (error) - goto out_unlock; - - xfs_ilock(ip, XFS_MMAPLOCK_EXCL); - iolock |= XFS_MMAPLOCK_EXCL; - - switch (bf->l_whence) { - case 0: /*SEEK_SET*/ - break; - case 1: /*SEEK_CUR*/ - bf->l_start += filp->f_pos; - break; - case 2: /*SEEK_END*/ - bf->l_start += XFS_ISIZE(ip); - break; - default: - error = -EINVAL; - goto out_unlock; - } - - /* - * length of <= 0 for resv/unresv/zero is invalid. length for - * alloc/free is ignored completely and we have no idea what userspace - * might have set it to, so set it to zero to allow range - * checks to pass. - */ - switch (cmd) { - case XFS_IOC_ZERO_RANGE: - case XFS_IOC_RESVSP: - case XFS_IOC_RESVSP64: - case XFS_IOC_UNRESVSP: - case XFS_IOC_UNRESVSP64: - if (bf->l_len <= 0) { - error = -EINVAL; - goto out_unlock; - } - break; - default: - bf->l_len = 0; - break; - } - - if (bf->l_start < 0 || - bf->l_start > inode->i_sb->s_maxbytes || - bf->l_start + bf->l_len < 0 || - bf->l_start + bf->l_len >= inode->i_sb->s_maxbytes) { - error = -EINVAL; - goto out_unlock; - } - - switch (cmd) { - case XFS_IOC_ZERO_RANGE: - flags |= XFS_PREALLOC_SET; - error = xfs_zero_file_space(ip, bf->l_start, bf->l_len); - break; - case XFS_IOC_RESVSP: - case XFS_IOC_RESVSP64: - flags |= XFS_PREALLOC_SET; - error = xfs_alloc_file_space(ip, bf->l_start, bf->l_len, - XFS_BMAPI_PREALLOC); - break; - case XFS_IOC_UNRESVSP: - case XFS_IOC_UNRESVSP64: - error = xfs_free_file_space(ip, bf->l_start, bf->l_len); - break; - case XFS_IOC_ALLOCSP: - case XFS_IOC_ALLOCSP64: - case XFS_IOC_FREESP: - case XFS_IOC_FREESP64: - flags |= XFS_PREALLOC_CLEAR; - if (bf->l_start > XFS_ISIZE(ip)) { - error = xfs_alloc_file_space(ip, XFS_ISIZE(ip), - bf->l_start - XFS_ISIZE(ip), 0); - if (error) - goto out_unlock; - } - - iattr.ia_valid = ATTR_SIZE; - iattr.ia_size = bf->l_start; - - error = xfs_vn_setattr_size(file_dentry(filp), &iattr); - break; - default: - ASSERT(0); - error = -EINVAL; - } - - if (error) - goto out_unlock; - - error = xfs_update_prealloc_flags(ip, flags); - -out_unlock: - xfs_iunlock(ip, iolock); - mnt_drop_write_file(filp); - return error; -} - -STATIC int -xfs_ioc_bulkstat( - xfs_mount_t *mp, - unsigned int cmd, - void __user *arg) -{ - xfs_fsop_bulkreq_t bulkreq; - int count; /* # of records returned */ - xfs_ino_t inlast; /* last inode number */ - int done; - int error; - - /* done = 1 if there are more stats to get and if bulkstat */ - /* should be called again (unused here, but used in dmapi) */ - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - if (copy_from_user(&bulkreq, arg, sizeof(xfs_fsop_bulkreq_t))) - return -EFAULT; - - if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64))) - return -EFAULT; - - if ((count = bulkreq.icount) <= 0) - return -EINVAL; - - if (bulkreq.ubuffer == NULL) - return -EINVAL; - - if (cmd == XFS_IOC_FSINUMBERS) - error = xfs_inumbers(mp, &inlast, &count, - bulkreq.ubuffer, xfs_inumbers_fmt); - else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) - error = xfs_bulkstat_one(mp, inlast, bulkreq.ubuffer, - sizeof(xfs_bstat_t), NULL, &done); - else /* XFS_IOC_FSBULKSTAT */ - error = xfs_bulkstat(mp, &inlast, &count, xfs_bulkstat_one, - sizeof(xfs_bstat_t), bulkreq.ubuffer, - &done); - - if (error) - return error; - - if (bulkreq.ocount != NULL) { - if (copy_to_user(bulkreq.lastip, &inlast, - sizeof(xfs_ino_t))) - return -EFAULT; - - if (copy_to_user(bulkreq.ocount, &count, sizeof(count))) - return -EFAULT; - } - - return 0; -} - -STATIC int -xfs_ioc_fsgeometry_v1( - xfs_mount_t *mp, - void __user *arg) -{ - xfs_fsop_geom_t fsgeo; - int error; - - error = xfs_fs_geometry(mp, &fsgeo, 3); - if (error) - return error; - - /* - * Caller should have passed an argument of type - * xfs_fsop_geom_v1_t. This is a proper subset of the - * xfs_fsop_geom_t that xfs_fs_geometry() fills in. - */ - if (copy_to_user(arg, &fsgeo, sizeof(xfs_fsop_geom_v1_t))) - return -EFAULT; - return 0; -} - -STATIC int -xfs_ioc_fsgeometry( - xfs_mount_t *mp, - void __user *arg) -{ - xfs_fsop_geom_t fsgeo; - int error; - - error = xfs_fs_geometry(mp, &fsgeo, 4); - if (error) - return error; - - if (copy_to_user(arg, &fsgeo, sizeof(fsgeo))) - return -EFAULT; - return 0; -} - -/* - * Linux extended inode flags interface. - */ - -STATIC unsigned int -xfs_merge_ioc_xflags( - unsigned int flags, - unsigned int start) -{ - unsigned int xflags = start; - - if (flags & FS_IMMUTABLE_FL) - xflags |= FS_XFLAG_IMMUTABLE; - else - xflags &= ~FS_XFLAG_IMMUTABLE; - if (flags & FS_APPEND_FL) - xflags |= FS_XFLAG_APPEND; - else - xflags &= ~FS_XFLAG_APPEND; - if (flags & FS_SYNC_FL) - xflags |= FS_XFLAG_SYNC; - else - xflags &= ~FS_XFLAG_SYNC; - if (flags & FS_NOATIME_FL) - xflags |= FS_XFLAG_NOATIME; - else - xflags &= ~FS_XFLAG_NOATIME; - if (flags & FS_NODUMP_FL) - xflags |= FS_XFLAG_NODUMP; - else - xflags &= ~FS_XFLAG_NODUMP; - - return xflags; -} - -STATIC unsigned int -xfs_di2lxflags( - __uint16_t di_flags) -{ - unsigned int flags = 0; - - if (di_flags & XFS_DIFLAG_IMMUTABLE) - flags |= FS_IMMUTABLE_FL; - if (di_flags & XFS_DIFLAG_APPEND) - flags |= FS_APPEND_FL; - if (di_flags & XFS_DIFLAG_SYNC) - flags |= FS_SYNC_FL; - if (di_flags & XFS_DIFLAG_NOATIME) - flags |= FS_NOATIME_FL; - if (di_flags & XFS_DIFLAG_NODUMP) - flags |= FS_NODUMP_FL; - return flags; -} - -STATIC int -xfs_ioc_fsgetxattr( - xfs_inode_t *ip, - int attr, - void __user *arg) -{ - struct fsxattr fa; - - memset(&fa, 0, sizeof(struct fsxattr)); - - xfs_ilock(ip, XFS_ILOCK_SHARED); - fa.fsx_xflags = xfs_ip2xflags(ip); - fa.fsx_extsize = ip->i_d.di_extsize << ip->i_mount->m_sb.sb_blocklog; - fa.fsx_cowextsize = ip->i_d.di_cowextsize << - ip->i_mount->m_sb.sb_blocklog; - fa.fsx_projid = xfs_get_projid(ip); - - if (attr) { - if (ip->i_afp) { - if (ip->i_afp->if_flags & XFS_IFEXTENTS) - fa.fsx_nextents = ip->i_afp->if_bytes / - sizeof(xfs_bmbt_rec_t); - else - fa.fsx_nextents = ip->i_d.di_anextents; - } else - fa.fsx_nextents = 0; - } else { - if (ip->i_df.if_flags & XFS_IFEXTENTS) - fa.fsx_nextents = ip->i_df.if_bytes / - sizeof(xfs_bmbt_rec_t); - else - fa.fsx_nextents = ip->i_d.di_nextents; - } - xfs_iunlock(ip, XFS_ILOCK_SHARED); - - if (copy_to_user(arg, &fa, sizeof(fa))) - return -EFAULT; - return 0; -} - -STATIC void -xfs_set_diflags( - struct xfs_inode *ip, - unsigned int xflags) -{ - unsigned int di_flags; - uint64_t di_flags2; - - /* can't set PREALLOC this way, just preserve it */ - di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC); - if (xflags & FS_XFLAG_IMMUTABLE) - di_flags |= XFS_DIFLAG_IMMUTABLE; - if (xflags & FS_XFLAG_APPEND) - di_flags |= XFS_DIFLAG_APPEND; - if (xflags & FS_XFLAG_SYNC) - di_flags |= XFS_DIFLAG_SYNC; - if (xflags & FS_XFLAG_NOATIME) - di_flags |= XFS_DIFLAG_NOATIME; - if (xflags & FS_XFLAG_NODUMP) - di_flags |= XFS_DIFLAG_NODUMP; - if (xflags & FS_XFLAG_NODEFRAG) - di_flags |= XFS_DIFLAG_NODEFRAG; - if (xflags & FS_XFLAG_FILESTREAM) - di_flags |= XFS_DIFLAG_FILESTREAM; - if (S_ISDIR(VFS_I(ip)->i_mode)) { - if (xflags & FS_XFLAG_RTINHERIT) - di_flags |= XFS_DIFLAG_RTINHERIT; - if (xflags & FS_XFLAG_NOSYMLINKS) - di_flags |= XFS_DIFLAG_NOSYMLINKS; - if (xflags & FS_XFLAG_EXTSZINHERIT) - di_flags |= XFS_DIFLAG_EXTSZINHERIT; - if (xflags & FS_XFLAG_PROJINHERIT) - di_flags |= XFS_DIFLAG_PROJINHERIT; - } else if (S_ISREG(VFS_I(ip)->i_mode)) { - if (xflags & FS_XFLAG_REALTIME) - di_flags |= XFS_DIFLAG_REALTIME; - if (xflags & FS_XFLAG_EXTSIZE) - di_flags |= XFS_DIFLAG_EXTSIZE; - } - ip->i_d.di_flags = di_flags; - - /* diflags2 only valid for v3 inodes. */ - if (ip->i_d.di_version < 3) - return; - - di_flags2 = (ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK); - if (xflags & FS_XFLAG_DAX) - di_flags2 |= XFS_DIFLAG2_DAX; - if (xflags & FS_XFLAG_COWEXTSIZE) - di_flags2 |= XFS_DIFLAG2_COWEXTSIZE; - - ip->i_d.di_flags2 = di_flags2; -} - -STATIC void -xfs_diflags_to_linux( - struct xfs_inode *ip) -{ - struct inode *inode = VFS_I(ip); - unsigned int xflags = xfs_ip2xflags(ip); - - if (xflags & FS_XFLAG_IMMUTABLE) - inode->i_flags |= S_IMMUTABLE; - else - inode->i_flags &= ~S_IMMUTABLE; - if (xflags & FS_XFLAG_APPEND) - inode->i_flags |= S_APPEND; - else - inode->i_flags &= ~S_APPEND; - if (xflags & FS_XFLAG_SYNC) - inode->i_flags |= S_SYNC; - else - inode->i_flags &= ~S_SYNC; - if (xflags & FS_XFLAG_NOATIME) - inode->i_flags |= S_NOATIME; - else - inode->i_flags &= ~S_NOATIME; - if (xflags & FS_XFLAG_DAX) - inode->i_flags |= S_DAX; - else - inode->i_flags &= ~S_DAX; - -} - -static int -xfs_ioctl_setattr_xflags( - struct xfs_trans *tp, - struct xfs_inode *ip, - struct fsxattr *fa) -{ - struct xfs_mount *mp = ip->i_mount; - - /* Can't change realtime flag if any extents are allocated. */ - if ((ip->i_d.di_nextents || ip->i_delayed_blks) && - XFS_IS_REALTIME_INODE(ip) != (fa->fsx_xflags & FS_XFLAG_REALTIME)) - return -EINVAL; - - /* If realtime flag is set then must have realtime device */ - if (fa->fsx_xflags & FS_XFLAG_REALTIME) { - if (mp->m_sb.sb_rblocks == 0 || mp->m_sb.sb_rextsize == 0 || - (ip->i_d.di_extsize % mp->m_sb.sb_rextsize)) - return -EINVAL; - } - - /* Clear reflink if we are actually able to set the rt flag. */ - if ((fa->fsx_xflags & FS_XFLAG_REALTIME) && xfs_is_reflink_inode(ip)) - ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK; - - /* Don't allow us to set DAX mode for a reflinked file for now. */ - if ((fa->fsx_xflags & FS_XFLAG_DAX) && xfs_is_reflink_inode(ip)) - return -EINVAL; - - /* - * Can't modify an immutable/append-only file unless - * we have appropriate permission. - */ - if (((ip->i_d.di_flags & (XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND)) || - (fa->fsx_xflags & (FS_XFLAG_IMMUTABLE | FS_XFLAG_APPEND))) && - !capable(CAP_LINUX_IMMUTABLE)) - return -EPERM; - - xfs_set_diflags(ip, fa->fsx_xflags); - xfs_diflags_to_linux(ip); - xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG); - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - XFS_STATS_INC(mp, xs_ig_attrchg); - return 0; -} - -/* - * If we are changing DAX flags, we have to ensure the file is clean and any - * cached objects in the address space are invalidated and removed. This - * requires us to lock out other IO and page faults similar to a truncate - * operation. The locks need to be held until the transaction has been committed - * so that the cache invalidation is atomic with respect to the DAX flag - * manipulation. - */ -static int -xfs_ioctl_setattr_dax_invalidate( - struct xfs_inode *ip, - struct fsxattr *fa, - int *join_flags) -{ - struct inode *inode = VFS_I(ip); - int error; - - *join_flags = 0; - - /* - * It is only valid to set the DAX flag on regular files and - * directories on filesystems where the block size is equal to the page - * size. On directories it serves as an inherit hint. - */ - if (fa->fsx_xflags & FS_XFLAG_DAX) { - if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) - return -EINVAL; - if (ip->i_mount->m_sb.sb_blocksize != PAGE_SIZE) - return -EINVAL; - } - - /* If the DAX state is not changing, we have nothing to do here. */ - if ((fa->fsx_xflags & FS_XFLAG_DAX) && IS_DAX(inode)) - return 0; - if (!(fa->fsx_xflags & FS_XFLAG_DAX) && !IS_DAX(inode)) - return 0; - - /* lock, flush and invalidate mapping in preparation for flag change */ - xfs_ilock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL); - error = filemap_write_and_wait(inode->i_mapping); - if (error) - goto out_unlock; - error = invalidate_inode_pages2(inode->i_mapping); - if (error) - goto out_unlock; - - *join_flags = XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL; - return 0; - -out_unlock: - xfs_iunlock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL); - return error; - -} - -/* - * Set up the transaction structure for the setattr operation, checking that we - * have permission to do so. On success, return a clean transaction and the - * inode locked exclusively ready for further operation specific checks. On - * failure, return an error without modifying or locking the inode. - * - * The inode might already be IO locked on call. If this is the case, it is - * indicated in @join_flags and we take full responsibility for ensuring they - * are unlocked from now on. Hence if we have an error here, we still have to - * unlock them. Otherwise, once they are joined to the transaction, they will - * be unlocked on commit/cancel. - */ -static struct xfs_trans * -xfs_ioctl_setattr_get_trans( - struct xfs_inode *ip, - int join_flags) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_trans *tp; - int error = -EROFS; - - if (mp->m_flags & XFS_MOUNT_RDONLY) - goto out_unlock; - error = -EIO; - if (XFS_FORCED_SHUTDOWN(mp)) - goto out_unlock; - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0, 0, 0, &tp); - if (error) - return ERR_PTR(error); - - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | join_flags); - join_flags = 0; - - /* - * CAP_FOWNER overrides the following restrictions: - * - * The user ID of the calling process must be equal to the file owner - * ID, except in cases where the CAP_FSETID capability is applicable. - */ - if (!inode_owner_or_capable(VFS_I(ip))) { - error = -EPERM; - goto out_cancel; - } - - if (mp->m_flags & XFS_MOUNT_WSYNC) - xfs_trans_set_sync(tp); - - return tp; - -out_cancel: - xfs_trans_cancel(tp); -out_unlock: - if (join_flags) - xfs_iunlock(ip, join_flags); - return ERR_PTR(error); -} - -/* - * extent size hint validation is somewhat cumbersome. Rules are: - * - * 1. extent size hint is only valid for directories and regular files - * 2. FS_XFLAG_EXTSIZE is only valid for regular files - * 3. FS_XFLAG_EXTSZINHERIT is only valid for directories. - * 4. can only be changed on regular files if no extents are allocated - * 5. can be changed on directories at any time - * 6. extsize hint of 0 turns off hints, clears inode flags. - * 7. Extent size must be a multiple of the appropriate block size. - * 8. for non-realtime files, the extent size hint must be limited - * to half the AG size to avoid alignment extending the extent beyond the - * limits of the AG. - */ -static int -xfs_ioctl_setattr_check_extsize( - struct xfs_inode *ip, - struct fsxattr *fa) -{ - struct xfs_mount *mp = ip->i_mount; - - if ((fa->fsx_xflags & FS_XFLAG_EXTSIZE) && !S_ISREG(VFS_I(ip)->i_mode)) - return -EINVAL; - - if ((fa->fsx_xflags & FS_XFLAG_EXTSZINHERIT) && - !S_ISDIR(VFS_I(ip)->i_mode)) - return -EINVAL; - - if (S_ISREG(VFS_I(ip)->i_mode) && ip->i_d.di_nextents && - ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != fa->fsx_extsize)) - return -EINVAL; - - if (fa->fsx_extsize != 0) { - xfs_extlen_t size; - xfs_fsblock_t extsize_fsb; - - extsize_fsb = XFS_B_TO_FSB(mp, fa->fsx_extsize); - if (extsize_fsb > MAXEXTLEN) - return -EINVAL; - - if (XFS_IS_REALTIME_INODE(ip) || - (fa->fsx_xflags & FS_XFLAG_REALTIME)) { - size = mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog; - } else { - size = mp->m_sb.sb_blocksize; - if (extsize_fsb > mp->m_sb.sb_agblocks / 2) - return -EINVAL; - } - - if (fa->fsx_extsize % size) - return -EINVAL; - } else - fa->fsx_xflags &= ~(FS_XFLAG_EXTSIZE | FS_XFLAG_EXTSZINHERIT); - - return 0; -} - -/* - * CoW extent size hint validation rules are: - * - * 1. CoW extent size hint can only be set if reflink is enabled on the fs. - * The inode does not have to have any shared blocks, but it must be a v3. - * 2. FS_XFLAG_COWEXTSIZE is only valid for directories and regular files; - * for a directory, the hint is propagated to new files. - * 3. Can be changed on files & directories at any time. - * 4. CoW extsize hint of 0 turns off hints, clears inode flags. - * 5. Extent size must be a multiple of the appropriate block size. - * 6. The extent size hint must be limited to half the AG size to avoid - * alignment extending the extent beyond the limits of the AG. - */ -static int -xfs_ioctl_setattr_check_cowextsize( - struct xfs_inode *ip, - struct fsxattr *fa) -{ - struct xfs_mount *mp = ip->i_mount; - - if (!(fa->fsx_xflags & FS_XFLAG_COWEXTSIZE)) - return 0; - - if (!xfs_sb_version_hasreflink(&ip->i_mount->m_sb) || - ip->i_d.di_version != 3) - return -EINVAL; - - if (!S_ISREG(VFS_I(ip)->i_mode) && !S_ISDIR(VFS_I(ip)->i_mode)) - return -EINVAL; - - if (fa->fsx_cowextsize != 0) { - xfs_extlen_t size; - xfs_fsblock_t cowextsize_fsb; - - cowextsize_fsb = XFS_B_TO_FSB(mp, fa->fsx_cowextsize); - if (cowextsize_fsb > MAXEXTLEN) - return -EINVAL; - - size = mp->m_sb.sb_blocksize; - if (cowextsize_fsb > mp->m_sb.sb_agblocks / 2) - return -EINVAL; - - if (fa->fsx_cowextsize % size) - return -EINVAL; - } else - fa->fsx_xflags &= ~FS_XFLAG_COWEXTSIZE; - - return 0; -} - -static int -xfs_ioctl_setattr_check_projid( - struct xfs_inode *ip, - struct fsxattr *fa) -{ - /* Disallow 32bit project ids if projid32bit feature is not enabled. */ - if (fa->fsx_projid > (__uint16_t)-1 && - !xfs_sb_version_hasprojid32bit(&ip->i_mount->m_sb)) - return -EINVAL; - - /* - * Project Quota ID state is only allowed to change from within the init - * namespace. Enforce that restriction only if we are trying to change - * the quota ID state. Everything else is allowed in user namespaces. - */ - if (current_user_ns() == &init_user_ns) - return 0; - - if (xfs_get_projid(ip) != fa->fsx_projid) - return -EINVAL; - if ((fa->fsx_xflags & FS_XFLAG_PROJINHERIT) != - (ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)) - return -EINVAL; - - return 0; -} - -STATIC int -xfs_ioctl_setattr( - xfs_inode_t *ip, - struct fsxattr *fa) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_trans *tp; - struct xfs_dquot *udqp = NULL; - struct xfs_dquot *pdqp = NULL; - struct xfs_dquot *olddquot = NULL; - int code; - int join_flags = 0; - - trace_xfs_ioctl_setattr(ip); - - code = xfs_ioctl_setattr_check_projid(ip, fa); - if (code) - return code; - - /* - * If disk quotas is on, we make sure that the dquots do exist on disk, - * before we start any other transactions. Trying to do this later - * is messy. We don't care to take a readlock to look at the ids - * in inode here, because we can't hold it across the trans_reserve. - * If the IDs do change before we take the ilock, we're covered - * because the i_*dquot fields will get updated anyway. - */ - if (XFS_IS_QUOTA_ON(mp)) { - code = xfs_qm_vop_dqalloc(ip, ip->i_d.di_uid, - ip->i_d.di_gid, fa->fsx_projid, - XFS_QMOPT_PQUOTA, &udqp, NULL, &pdqp); - if (code) - return code; - } - - /* - * Changing DAX config may require inode locking for mapping - * invalidation. These need to be held all the way to transaction commit - * or cancel time, so need to be passed through to - * xfs_ioctl_setattr_get_trans() so it can apply them to the join call - * appropriately. - */ - code = xfs_ioctl_setattr_dax_invalidate(ip, fa, &join_flags); - if (code) - goto error_free_dquots; - - tp = xfs_ioctl_setattr_get_trans(ip, join_flags); - if (IS_ERR(tp)) { - code = PTR_ERR(tp); - goto error_free_dquots; - } - - - if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp) && - xfs_get_projid(ip) != fa->fsx_projid) { - code = xfs_qm_vop_chown_reserve(tp, ip, udqp, NULL, pdqp, - capable(CAP_FOWNER) ? XFS_QMOPT_FORCE_RES : 0); - if (code) /* out of quota */ - goto error_trans_cancel; - } - - code = xfs_ioctl_setattr_check_extsize(ip, fa); - if (code) - goto error_trans_cancel; - - code = xfs_ioctl_setattr_check_cowextsize(ip, fa); - if (code) - goto error_trans_cancel; - - code = xfs_ioctl_setattr_xflags(tp, ip, fa); - if (code) - goto error_trans_cancel; - - /* - * Change file ownership. Must be the owner or privileged. CAP_FSETID - * overrides the following restrictions: - * - * The set-user-ID and set-group-ID bits of a file will be cleared upon - * successful return from chown() - */ - - if ((VFS_I(ip)->i_mode & (S_ISUID|S_ISGID)) && - !capable_wrt_inode_uidgid(VFS_I(ip), CAP_FSETID)) - VFS_I(ip)->i_mode &= ~(S_ISUID|S_ISGID); - - /* Change the ownerships and register project quota modifications */ - if (xfs_get_projid(ip) != fa->fsx_projid) { - if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp)) { - olddquot = xfs_qm_vop_chown(tp, ip, - &ip->i_pdquot, pdqp); - } - ASSERT(ip->i_d.di_version > 1); - xfs_set_projid(ip, fa->fsx_projid); - } - - /* - * Only set the extent size hint if we've already determined that the - * extent size hint should be set on the inode. If no extent size flags - * are set on the inode then unconditionally clear the extent size hint. - */ - if (ip->i_d.di_flags & (XFS_DIFLAG_EXTSIZE | XFS_DIFLAG_EXTSZINHERIT)) - ip->i_d.di_extsize = fa->fsx_extsize >> mp->m_sb.sb_blocklog; - else - ip->i_d.di_extsize = 0; - if (ip->i_d.di_version == 3 && - (ip->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE)) - ip->i_d.di_cowextsize = fa->fsx_cowextsize >> - mp->m_sb.sb_blocklog; - else - ip->i_d.di_cowextsize = 0; - - code = xfs_trans_commit(tp); - - /* - * Release any dquot(s) the inode had kept before chown. - */ - xfs_qm_dqrele(olddquot); - xfs_qm_dqrele(udqp); - xfs_qm_dqrele(pdqp); - - return code; - -error_trans_cancel: - xfs_trans_cancel(tp); -error_free_dquots: - xfs_qm_dqrele(udqp); - xfs_qm_dqrele(pdqp); - return code; -} - -STATIC int -xfs_ioc_fssetxattr( - xfs_inode_t *ip, - struct file *filp, - void __user *arg) -{ - struct fsxattr fa; - int error; - - if (copy_from_user(&fa, arg, sizeof(fa))) - return -EFAULT; - - error = mnt_want_write_file(filp); - if (error) - return error; - error = xfs_ioctl_setattr(ip, &fa); - mnt_drop_write_file(filp); - return error; -} - -STATIC int -xfs_ioc_getxflags( - xfs_inode_t *ip, - void __user *arg) -{ - unsigned int flags; - - flags = xfs_di2lxflags(ip->i_d.di_flags); - if (copy_to_user(arg, &flags, sizeof(flags))) - return -EFAULT; - return 0; -} - -STATIC int -xfs_ioc_setxflags( - struct xfs_inode *ip, - struct file *filp, - void __user *arg) -{ - struct xfs_trans *tp; - struct fsxattr fa; - unsigned int flags; - int join_flags = 0; - int error; - - if (copy_from_user(&flags, arg, sizeof(flags))) - return -EFAULT; - - if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ - FS_NOATIME_FL | FS_NODUMP_FL | \ - FS_SYNC_FL)) - return -EOPNOTSUPP; - - fa.fsx_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip)); - - error = mnt_want_write_file(filp); - if (error) - return error; - - /* - * Changing DAX config may require inode locking for mapping - * invalidation. These need to be held all the way to transaction commit - * or cancel time, so need to be passed through to - * xfs_ioctl_setattr_get_trans() so it can apply them to the join call - * appropriately. - */ - error = xfs_ioctl_setattr_dax_invalidate(ip, &fa, &join_flags); - if (error) - goto out_drop_write; - - tp = xfs_ioctl_setattr_get_trans(ip, join_flags); - if (IS_ERR(tp)) { - error = PTR_ERR(tp); - goto out_drop_write; - } - - error = xfs_ioctl_setattr_xflags(tp, ip, &fa); - if (error) { - xfs_trans_cancel(tp); - goto out_drop_write; - } - - error = xfs_trans_commit(tp); -out_drop_write: - mnt_drop_write_file(filp); - return error; -} - -STATIC int -xfs_getbmap_format(void **ap, struct getbmapx *bmv, int *full) -{ - struct getbmap __user *base = (struct getbmap __user *)*ap; - - /* copy only getbmap portion (not getbmapx) */ - if (copy_to_user(base, bmv, sizeof(struct getbmap))) - return -EFAULT; - - *ap += sizeof(struct getbmap); - return 0; -} - -STATIC int -xfs_ioc_getbmap( - struct file *file, - unsigned int cmd, - void __user *arg) -{ - struct getbmapx bmx; - int error; - - if (copy_from_user(&bmx, arg, sizeof(struct getbmapx))) - return -EFAULT; - - if (bmx.bmv_count < 2) - return -EINVAL; - - bmx.bmv_iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0); - if (file->f_mode & FMODE_NOCMTIME) - bmx.bmv_iflags |= BMV_IF_NO_DMAPI_READ; - - error = xfs_getbmap(XFS_I(file_inode(file)), &bmx, xfs_getbmap_format, - (__force struct getbmap *)arg+1); - if (error) - return error; - - /* copy back header - only size of getbmap */ - if (copy_to_user(arg, &bmx, sizeof(struct getbmap))) - return -EFAULT; - return 0; -} - -STATIC int -xfs_getbmapx_format(void **ap, struct getbmapx *bmv, int *full) -{ - struct getbmapx __user *base = (struct getbmapx __user *)*ap; - - if (copy_to_user(base, bmv, sizeof(struct getbmapx))) - return -EFAULT; - - *ap += sizeof(struct getbmapx); - return 0; -} - -STATIC int -xfs_ioc_getbmapx( - struct xfs_inode *ip, - void __user *arg) -{ - struct getbmapx bmx; - int error; - - if (copy_from_user(&bmx, arg, sizeof(bmx))) - return -EFAULT; - - if (bmx.bmv_count < 2) - return -EINVAL; - - if (bmx.bmv_iflags & (~BMV_IF_VALID)) - return -EINVAL; - - error = xfs_getbmap(ip, &bmx, xfs_getbmapx_format, - (__force struct getbmapx *)arg+1); - if (error) - return error; - - /* copy back header */ - if (copy_to_user(arg, &bmx, sizeof(struct getbmapx))) - return -EFAULT; - - return 0; -} - -int -xfs_ioc_swapext( - xfs_swapext_t *sxp) -{ - xfs_inode_t *ip, *tip; - struct fd f, tmp; - int error = 0; - - /* Pull information for the target fd */ - f = fdget((int)sxp->sx_fdtarget); - if (!f.file) { - error = -EINVAL; - goto out; - } - - if (!(f.file->f_mode & FMODE_WRITE) || - !(f.file->f_mode & FMODE_READ) || - (f.file->f_flags & O_APPEND)) { - error = -EBADF; - goto out_put_file; - } - - tmp = fdget((int)sxp->sx_fdtmp); - if (!tmp.file) { - error = -EINVAL; - goto out_put_file; - } - - if (!(tmp.file->f_mode & FMODE_WRITE) || - !(tmp.file->f_mode & FMODE_READ) || - (tmp.file->f_flags & O_APPEND)) { - error = -EBADF; - goto out_put_tmp_file; - } - - if (IS_SWAPFILE(file_inode(f.file)) || - IS_SWAPFILE(file_inode(tmp.file))) { - error = -EINVAL; - goto out_put_tmp_file; - } - - /* - * We need to ensure that the fds passed in point to XFS inodes - * before we cast and access them as XFS structures as we have no - * control over what the user passes us here. - */ - if (f.file->f_op != &xfs_file_operations || - tmp.file->f_op != &xfs_file_operations) { - error = -EINVAL; - goto out_put_tmp_file; - } - - ip = XFS_I(file_inode(f.file)); - tip = XFS_I(file_inode(tmp.file)); - - if (ip->i_mount != tip->i_mount) { - error = -EINVAL; - goto out_put_tmp_file; - } - - if (ip->i_ino == tip->i_ino) { - error = -EINVAL; - goto out_put_tmp_file; - } - - if (XFS_FORCED_SHUTDOWN(ip->i_mount)) { - error = -EIO; - goto out_put_tmp_file; - } - - error = xfs_swap_extents(ip, tip, sxp); - - out_put_tmp_file: - fdput(tmp); - out_put_file: - fdput(f); - out: - return error; -} - -/* - * Note: some of the ioctl's return positive numbers as a - * byte count indicating success, such as readlink_by_handle. - * So we don't "sign flip" like most other routines. This means - * true errors need to be returned as a negative value. - */ -long -xfs_file_ioctl( - struct file *filp, - unsigned int cmd, - unsigned long p) -{ - struct inode *inode = file_inode(filp); - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; - void __user *arg = (void __user *)p; - int error; - - trace_xfs_file_ioctl(ip); - - switch (cmd) { - case FITRIM: - return xfs_ioc_trim(mp, arg); - case XFS_IOC_ALLOCSP: - case XFS_IOC_FREESP: - case XFS_IOC_RESVSP: - case XFS_IOC_UNRESVSP: - case XFS_IOC_ALLOCSP64: - case XFS_IOC_FREESP64: - case XFS_IOC_RESVSP64: - case XFS_IOC_UNRESVSP64: - case XFS_IOC_ZERO_RANGE: { - xfs_flock64_t bf; - - if (copy_from_user(&bf, arg, sizeof(bf))) - return -EFAULT; - return xfs_ioc_space(filp, cmd, &bf); - } - case XFS_IOC_DIOINFO: { - struct dioattr da; - xfs_buftarg_t *target = - XFS_IS_REALTIME_INODE(ip) ? - mp->m_rtdev_targp : mp->m_ddev_targp; - - da.d_mem = da.d_miniosz = target->bt_logical_sectorsize; - da.d_maxiosz = INT_MAX & ~(da.d_miniosz - 1); - - if (copy_to_user(arg, &da, sizeof(da))) - return -EFAULT; - return 0; - } - - case XFS_IOC_FSBULKSTAT_SINGLE: - case XFS_IOC_FSBULKSTAT: - case XFS_IOC_FSINUMBERS: - return xfs_ioc_bulkstat(mp, cmd, arg); - - case XFS_IOC_FSGEOMETRY_V1: - return xfs_ioc_fsgeometry_v1(mp, arg); - - case XFS_IOC_FSGEOMETRY: - return xfs_ioc_fsgeometry(mp, arg); - - case XFS_IOC_GETVERSION: - return put_user(inode->i_generation, (int __user *)arg); - - case XFS_IOC_FSGETXATTR: - return xfs_ioc_fsgetxattr(ip, 0, arg); - case XFS_IOC_FSGETXATTRA: - return xfs_ioc_fsgetxattr(ip, 1, arg); - case XFS_IOC_FSSETXATTR: - return xfs_ioc_fssetxattr(ip, filp, arg); - case XFS_IOC_GETXFLAGS: - return xfs_ioc_getxflags(ip, arg); - case XFS_IOC_SETXFLAGS: - return xfs_ioc_setxflags(ip, filp, arg); - - case XFS_IOC_FSSETDM: { - struct fsdmidata dmi; - - if (copy_from_user(&dmi, arg, sizeof(dmi))) - return -EFAULT; - - error = mnt_want_write_file(filp); - if (error) - return error; - - error = xfs_set_dmattrs(ip, dmi.fsd_dmevmask, - dmi.fsd_dmstate); - mnt_drop_write_file(filp); - return error; - } - - case XFS_IOC_GETBMAP: - case XFS_IOC_GETBMAPA: - return xfs_ioc_getbmap(filp, cmd, arg); - - case XFS_IOC_GETBMAPX: - return xfs_ioc_getbmapx(ip, arg); - - case XFS_IOC_FD_TO_HANDLE: - case XFS_IOC_PATH_TO_HANDLE: - case XFS_IOC_PATH_TO_FSHANDLE: { - xfs_fsop_handlereq_t hreq; - - if (copy_from_user(&hreq, arg, sizeof(hreq))) - return -EFAULT; - return xfs_find_handle(cmd, &hreq); - } - case XFS_IOC_OPEN_BY_HANDLE: { - xfs_fsop_handlereq_t hreq; - - if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t))) - return -EFAULT; - return xfs_open_by_handle(filp, &hreq); - } - case XFS_IOC_FSSETDM_BY_HANDLE: - return xfs_fssetdm_by_handle(filp, arg); - - case XFS_IOC_READLINK_BY_HANDLE: { - xfs_fsop_handlereq_t hreq; - - if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t))) - return -EFAULT; - return xfs_readlink_by_handle(filp, &hreq); - } - case XFS_IOC_ATTRLIST_BY_HANDLE: - return xfs_attrlist_by_handle(filp, arg); - - case XFS_IOC_ATTRMULTI_BY_HANDLE: - return xfs_attrmulti_by_handle(filp, arg); - - case XFS_IOC_SWAPEXT: { - struct xfs_swapext sxp; - - if (copy_from_user(&sxp, arg, sizeof(xfs_swapext_t))) - return -EFAULT; - error = mnt_want_write_file(filp); - if (error) - return error; - error = xfs_ioc_swapext(&sxp); - mnt_drop_write_file(filp); - return error; - } - - case XFS_IOC_FSCOUNTS: { - xfs_fsop_counts_t out; - - error = xfs_fs_counts(mp, &out); - if (error) - return error; - - if (copy_to_user(arg, &out, sizeof(out))) - return -EFAULT; - return 0; - } - - case XFS_IOC_SET_RESBLKS: { - xfs_fsop_resblks_t inout; - __uint64_t in; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (mp->m_flags & XFS_MOUNT_RDONLY) - return -EROFS; - - if (copy_from_user(&inout, arg, sizeof(inout))) - return -EFAULT; - - error = mnt_want_write_file(filp); - if (error) - return error; - - /* input parameter is passed in resblks field of structure */ - in = inout.resblks; - error = xfs_reserve_blocks(mp, &in, &inout); - mnt_drop_write_file(filp); - if (error) - return error; - - if (copy_to_user(arg, &inout, sizeof(inout))) - return -EFAULT; - return 0; - } - - case XFS_IOC_GET_RESBLKS: { - xfs_fsop_resblks_t out; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - error = xfs_reserve_blocks(mp, NULL, &out); - if (error) - return error; - - if (copy_to_user(arg, &out, sizeof(out))) - return -EFAULT; - - return 0; - } - - case XFS_IOC_FSGROWFSDATA: { - xfs_growfs_data_t in; - - if (copy_from_user(&in, arg, sizeof(in))) - return -EFAULT; - - error = mnt_want_write_file(filp); - if (error) - return error; - error = xfs_growfs_data(mp, &in); - mnt_drop_write_file(filp); - return error; - } - - case XFS_IOC_FSGROWFSLOG: { - xfs_growfs_log_t in; - - if (copy_from_user(&in, arg, sizeof(in))) - return -EFAULT; - - error = mnt_want_write_file(filp); - if (error) - return error; - error = xfs_growfs_log(mp, &in); - mnt_drop_write_file(filp); - return error; - } - - case XFS_IOC_FSGROWFSRT: { - xfs_growfs_rt_t in; - - if (copy_from_user(&in, arg, sizeof(in))) - return -EFAULT; - - error = mnt_want_write_file(filp); - if (error) - return error; - error = xfs_growfs_rt(mp, &in); - mnt_drop_write_file(filp); - return error; - } - - case XFS_IOC_GOINGDOWN: { - __uint32_t in; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (get_user(in, (__uint32_t __user *)arg)) - return -EFAULT; - - return xfs_fs_goingdown(mp, in); - } - - case XFS_IOC_ERROR_INJECTION: { - xfs_error_injection_t in; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (copy_from_user(&in, arg, sizeof(in))) - return -EFAULT; - - return xfs_errortag_add(in.errtag, mp); - } - - case XFS_IOC_ERROR_CLEARALL: - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - return xfs_errortag_clearall(mp, 1); - - case XFS_IOC_FREE_EOFBLOCKS: { - struct xfs_fs_eofblocks eofb; - struct xfs_eofblocks keofb; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (mp->m_flags & XFS_MOUNT_RDONLY) - return -EROFS; - - if (copy_from_user(&eofb, arg, sizeof(eofb))) - return -EFAULT; - - error = xfs_fs_eofblocks_from_user(&eofb, &keofb); - if (error) - return error; - - return xfs_icache_free_eofblocks(mp, &keofb); - } - - default: - return -ENOTTY; - } -} diff --git a/src/linux/fs/xfs/xfs_ioctl.h b/src/linux/fs/xfs/xfs_ioctl.h deleted file mode 100644 index 8b52881..0000000 --- a/src/linux/fs/xfs/xfs_ioctl.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (c) 2008 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_IOCTL_H__ -#define __XFS_IOCTL_H__ - -extern int -xfs_ioc_space( - struct file *filp, - unsigned int cmd, - xfs_flock64_t *bf); - -int -xfs_ioc_swapext( - xfs_swapext_t *sxp); - -extern int -xfs_find_handle( - unsigned int cmd, - xfs_fsop_handlereq_t *hreq); - -extern int -xfs_open_by_handle( - struct file *parfilp, - xfs_fsop_handlereq_t *hreq); - -extern int -xfs_readlink_by_handle( - struct file *parfilp, - xfs_fsop_handlereq_t *hreq); - -extern int -xfs_attrmulti_attr_get( - struct inode *inode, - unsigned char *name, - unsigned char __user *ubuf, - __uint32_t *len, - __uint32_t flags); - -extern int -xfs_attrmulti_attr_set( - struct inode *inode, - unsigned char *name, - const unsigned char __user *ubuf, - __uint32_t len, - __uint32_t flags); - -extern int -xfs_attrmulti_attr_remove( - struct inode *inode, - unsigned char *name, - __uint32_t flags); - -extern struct dentry * -xfs_handle_to_dentry( - struct file *parfilp, - void __user *uhandle, - u32 hlen); - -extern long -xfs_file_ioctl( - struct file *filp, - unsigned int cmd, - unsigned long p); - -extern long -xfs_file_compat_ioctl( - struct file *file, - unsigned int cmd, - unsigned long arg); - -extern int -xfs_set_dmattrs( - struct xfs_inode *ip, - u_int evmask, - u_int16_t state); - -#endif diff --git a/src/linux/fs/xfs/xfs_iomap.c b/src/linux/fs/xfs/xfs_iomap.c deleted file mode 100644 index 436e109..0000000 --- a/src/linux/fs/xfs/xfs_iomap.c +++ /dev/null @@ -1,1171 +0,0 @@ -/* - * Copyright (c) 2000-2006 Silicon Graphics, Inc. - * Copyright (c) 2016 Christoph Hellwig. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_inode.h" -#include "xfs_btree.h" -#include "xfs_bmap_btree.h" -#include "xfs_bmap.h" -#include "xfs_bmap_util.h" -#include "xfs_error.h" -#include "xfs_trans.h" -#include "xfs_trans_space.h" -#include "xfs_iomap.h" -#include "xfs_trace.h" -#include "xfs_icache.h" -#include "xfs_quota.h" -#include "xfs_dquot_item.h" -#include "xfs_dquot.h" -#include "xfs_reflink.h" - - -#define XFS_WRITEIO_ALIGN(mp,off) (((off) >> mp->m_writeio_log) \ - << mp->m_writeio_log) - -void -xfs_bmbt_to_iomap( - struct xfs_inode *ip, - struct iomap *iomap, - struct xfs_bmbt_irec *imap) -{ - struct xfs_mount *mp = ip->i_mount; - - if (imap->br_startblock == HOLESTARTBLOCK) { - iomap->blkno = IOMAP_NULL_BLOCK; - iomap->type = IOMAP_HOLE; - } else if (imap->br_startblock == DELAYSTARTBLOCK) { - iomap->blkno = IOMAP_NULL_BLOCK; - iomap->type = IOMAP_DELALLOC; - } else { - iomap->blkno = xfs_fsb_to_db(ip, imap->br_startblock); - if (imap->br_state == XFS_EXT_UNWRITTEN) - iomap->type = IOMAP_UNWRITTEN; - else - iomap->type = IOMAP_MAPPED; - } - iomap->offset = XFS_FSB_TO_B(mp, imap->br_startoff); - iomap->length = XFS_FSB_TO_B(mp, imap->br_blockcount); - iomap->bdev = xfs_find_bdev_for_inode(VFS_I(ip)); -} - -xfs_extlen_t -xfs_eof_alignment( - struct xfs_inode *ip, - xfs_extlen_t extsize) -{ - struct xfs_mount *mp = ip->i_mount; - xfs_extlen_t align = 0; - - if (!XFS_IS_REALTIME_INODE(ip)) { - /* - * Round up the allocation request to a stripe unit - * (m_dalign) boundary if the file size is >= stripe unit - * size, and we are allocating past the allocation eof. - * - * If mounted with the "-o swalloc" option the alignment is - * increased from the strip unit size to the stripe width. - */ - if (mp->m_swidth && (mp->m_flags & XFS_MOUNT_SWALLOC)) - align = mp->m_swidth; - else if (mp->m_dalign) - align = mp->m_dalign; - - if (align && XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, align)) - align = 0; - } - - /* - * Always round up the allocation request to an extent boundary - * (when file on a real-time subvolume or has di_extsize hint). - */ - if (extsize) { - if (align) - align = roundup_64(align, extsize); - else - align = extsize; - } - - return align; -} - -STATIC int -xfs_iomap_eof_align_last_fsb( - struct xfs_inode *ip, - xfs_extlen_t extsize, - xfs_fileoff_t *last_fsb) -{ - xfs_extlen_t align = xfs_eof_alignment(ip, extsize); - - if (align) { - xfs_fileoff_t new_last_fsb = roundup_64(*last_fsb, align); - int eof, error; - - error = xfs_bmap_eof(ip, new_last_fsb, XFS_DATA_FORK, &eof); - if (error) - return error; - if (eof) - *last_fsb = new_last_fsb; - } - return 0; -} - -STATIC int -xfs_alert_fsblock_zero( - xfs_inode_t *ip, - xfs_bmbt_irec_t *imap) -{ - xfs_alert_tag(ip->i_mount, XFS_PTAG_FSBLOCK_ZERO, - "Access to block zero in inode %llu " - "start_block: %llx start_off: %llx " - "blkcnt: %llx extent-state: %x", - (unsigned long long)ip->i_ino, - (unsigned long long)imap->br_startblock, - (unsigned long long)imap->br_startoff, - (unsigned long long)imap->br_blockcount, - imap->br_state); - return -EFSCORRUPTED; -} - -int -xfs_iomap_write_direct( - xfs_inode_t *ip, - xfs_off_t offset, - size_t count, - xfs_bmbt_irec_t *imap, - int nmaps) -{ - xfs_mount_t *mp = ip->i_mount; - xfs_fileoff_t offset_fsb; - xfs_fileoff_t last_fsb; - xfs_filblks_t count_fsb, resaligned; - xfs_fsblock_t firstfsb; - xfs_extlen_t extsz, temp; - int nimaps; - int quota_flag; - int rt; - xfs_trans_t *tp; - struct xfs_defer_ops dfops; - uint qblocks, resblks, resrtextents; - int error; - int lockmode; - int bmapi_flags = XFS_BMAPI_PREALLOC; - uint tflags = 0; - - rt = XFS_IS_REALTIME_INODE(ip); - extsz = xfs_get_extsz_hint(ip); - lockmode = XFS_ILOCK_SHARED; /* locked by caller */ - - ASSERT(xfs_isilocked(ip, lockmode)); - - offset_fsb = XFS_B_TO_FSBT(mp, offset); - last_fsb = XFS_B_TO_FSB(mp, ((xfs_ufsize_t)(offset + count))); - if ((offset + count) > XFS_ISIZE(ip)) { - /* - * Assert that the in-core extent list is present since this can - * call xfs_iread_extents() and we only have the ilock shared. - * This should be safe because the lock was held around a bmapi - * call in the caller and we only need it to access the in-core - * list. - */ - ASSERT(XFS_IFORK_PTR(ip, XFS_DATA_FORK)->if_flags & - XFS_IFEXTENTS); - error = xfs_iomap_eof_align_last_fsb(ip, extsz, &last_fsb); - if (error) - goto out_unlock; - } else { - if (nmaps && (imap->br_startblock == HOLESTARTBLOCK)) - last_fsb = MIN(last_fsb, (xfs_fileoff_t) - imap->br_blockcount + - imap->br_startoff); - } - count_fsb = last_fsb - offset_fsb; - ASSERT(count_fsb > 0); - - resaligned = count_fsb; - if (unlikely(extsz)) { - if ((temp = do_mod(offset_fsb, extsz))) - resaligned += temp; - if ((temp = do_mod(resaligned, extsz))) - resaligned += extsz - temp; - } - - if (unlikely(rt)) { - resrtextents = qblocks = resaligned; - resrtextents /= mp->m_sb.sb_rextsize; - resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0); - quota_flag = XFS_QMOPT_RES_RTBLKS; - } else { - resrtextents = 0; - resblks = qblocks = XFS_DIOSTRAT_SPACE_RES(mp, resaligned); - quota_flag = XFS_QMOPT_RES_REGBLKS; - } - - /* - * Drop the shared lock acquired by the caller, attach the dquot if - * necessary and move on to transaction setup. - */ - xfs_iunlock(ip, lockmode); - error = xfs_qm_dqattach(ip, 0); - if (error) - return error; - - /* - * For DAX, we do not allocate unwritten extents, but instead we zero - * the block before we commit the transaction. Ideally we'd like to do - * this outside the transaction context, but if we commit and then crash - * we may not have zeroed the blocks and this will be exposed on - * recovery of the allocation. Hence we must zero before commit. - * - * Further, if we are mapping unwritten extents here, we need to zero - * and convert them to written so that we don't need an unwritten extent - * callback for DAX. This also means that we need to be able to dip into - * the reserve block pool for bmbt block allocation if there is no space - * left but we need to do unwritten extent conversion. - */ - if (IS_DAX(VFS_I(ip))) { - bmapi_flags = XFS_BMAPI_CONVERT | XFS_BMAPI_ZERO; - if (ISUNWRITTEN(imap)) { - tflags |= XFS_TRANS_RESERVE; - resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0) << 1; - } - } - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, resrtextents, - tflags, &tp); - if (error) - return error; - - lockmode = XFS_ILOCK_EXCL; - xfs_ilock(ip, lockmode); - - error = xfs_trans_reserve_quota_nblks(tp, ip, qblocks, 0, quota_flag); - if (error) - goto out_trans_cancel; - - xfs_trans_ijoin(tp, ip, 0); - - /* - * From this point onwards we overwrite the imap pointer that the - * caller gave to us. - */ - xfs_defer_init(&dfops, &firstfsb); - nimaps = 1; - error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb, - bmapi_flags, &firstfsb, resblks, imap, - &nimaps, &dfops); - if (error) - goto out_bmap_cancel; - - /* - * Complete the transaction - */ - error = xfs_defer_finish(&tp, &dfops, NULL); - if (error) - goto out_bmap_cancel; - - error = xfs_trans_commit(tp); - if (error) - goto out_unlock; - - /* - * Copy any maps to caller's array and return any error. - */ - if (nimaps == 0) { - error = -ENOSPC; - goto out_unlock; - } - - if (!(imap->br_startblock || XFS_IS_REALTIME_INODE(ip))) - error = xfs_alert_fsblock_zero(ip, imap); - -out_unlock: - xfs_iunlock(ip, lockmode); - return error; - -out_bmap_cancel: - xfs_defer_cancel(&dfops); - xfs_trans_unreserve_quota_nblks(tp, ip, (long)qblocks, 0, quota_flag); -out_trans_cancel: - xfs_trans_cancel(tp); - goto out_unlock; -} - -STATIC bool -xfs_quota_need_throttle( - struct xfs_inode *ip, - int type, - xfs_fsblock_t alloc_blocks) -{ - struct xfs_dquot *dq = xfs_inode_dquot(ip, type); - - if (!dq || !xfs_this_quota_on(ip->i_mount, type)) - return false; - - /* no hi watermark, no throttle */ - if (!dq->q_prealloc_hi_wmark) - return false; - - /* under the lo watermark, no throttle */ - if (dq->q_res_bcount + alloc_blocks < dq->q_prealloc_lo_wmark) - return false; - - return true; -} - -STATIC void -xfs_quota_calc_throttle( - struct xfs_inode *ip, - int type, - xfs_fsblock_t *qblocks, - int *qshift, - int64_t *qfreesp) -{ - int64_t freesp; - int shift = 0; - struct xfs_dquot *dq = xfs_inode_dquot(ip, type); - - /* no dq, or over hi wmark, squash the prealloc completely */ - if (!dq || dq->q_res_bcount >= dq->q_prealloc_hi_wmark) { - *qblocks = 0; - *qfreesp = 0; - return; - } - - freesp = dq->q_prealloc_hi_wmark - dq->q_res_bcount; - if (freesp < dq->q_low_space[XFS_QLOWSP_5_PCNT]) { - shift = 2; - if (freesp < dq->q_low_space[XFS_QLOWSP_3_PCNT]) - shift += 2; - if (freesp < dq->q_low_space[XFS_QLOWSP_1_PCNT]) - shift += 2; - } - - if (freesp < *qfreesp) - *qfreesp = freesp; - - /* only overwrite the throttle values if we are more aggressive */ - if ((freesp >> shift) < (*qblocks >> *qshift)) { - *qblocks = freesp; - *qshift = shift; - } -} - -/* - * If we are doing a write at the end of the file and there are no allocations - * past this one, then extend the allocation out to the file system's write - * iosize. - * - * If we don't have a user specified preallocation size, dynamically increase - * the preallocation size as the size of the file grows. Cap the maximum size - * at a single extent or less if the filesystem is near full. The closer the - * filesystem is to full, the smaller the maximum prealocation. - * - * As an exception we don't do any preallocation at all if the file is smaller - * than the minimum preallocation and we are using the default dynamic - * preallocation scheme, as it is likely this is the only write to the file that - * is going to be done. - * - * We clean up any extra space left over when the file is closed in - * xfs_inactive(). - */ -STATIC xfs_fsblock_t -xfs_iomap_prealloc_size( - struct xfs_inode *ip, - loff_t offset, - loff_t count, - xfs_extnum_t idx, - struct xfs_bmbt_irec *prev) -{ - struct xfs_mount *mp = ip->i_mount; - xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset); - int shift = 0; - int64_t freesp; - xfs_fsblock_t qblocks; - int qshift = 0; - xfs_fsblock_t alloc_blocks = 0; - - if (offset + count <= XFS_ISIZE(ip)) - return 0; - - if (!(mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) && - (XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_writeio_blocks))) - return 0; - - /* - * If an explicit allocsize is set, the file is small, or we - * are writing behind a hole, then use the minimum prealloc: - */ - if ((mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) || - XFS_ISIZE(ip) < XFS_FSB_TO_B(mp, mp->m_dalign) || - idx == 0 || - prev->br_startoff + prev->br_blockcount < offset_fsb) - return mp->m_writeio_blocks; - - /* - * Determine the initial size of the preallocation. We are beyond the - * current EOF here, but we need to take into account whether this is - * a sparse write or an extending write when determining the - * preallocation size. Hence we need to look up the extent that ends - * at the current write offset and use the result to determine the - * preallocation size. - * - * If the extent is a hole, then preallocation is essentially disabled. - * Otherwise we take the size of the preceding data extent as the basis - * for the preallocation size. If the size of the extent is greater than - * half the maximum extent length, then use the current offset as the - * basis. This ensures that for large files the preallocation size - * always extends to MAXEXTLEN rather than falling short due to things - * like stripe unit/width alignment of real extents. - */ - if (prev->br_blockcount <= (MAXEXTLEN >> 1)) - alloc_blocks = prev->br_blockcount << 1; - else - alloc_blocks = XFS_B_TO_FSB(mp, offset); - if (!alloc_blocks) - goto check_writeio; - qblocks = alloc_blocks; - - /* - * MAXEXTLEN is not a power of two value but we round the prealloc down - * to the nearest power of two value after throttling. To prevent the - * round down from unconditionally reducing the maximum supported prealloc - * size, we round up first, apply appropriate throttling, round down and - * cap the value to MAXEXTLEN. - */ - alloc_blocks = XFS_FILEOFF_MIN(roundup_pow_of_two(MAXEXTLEN), - alloc_blocks); - - freesp = percpu_counter_read_positive(&mp->m_fdblocks); - if (freesp < mp->m_low_space[XFS_LOWSP_5_PCNT]) { - shift = 2; - if (freesp < mp->m_low_space[XFS_LOWSP_4_PCNT]) - shift++; - if (freesp < mp->m_low_space[XFS_LOWSP_3_PCNT]) - shift++; - if (freesp < mp->m_low_space[XFS_LOWSP_2_PCNT]) - shift++; - if (freesp < mp->m_low_space[XFS_LOWSP_1_PCNT]) - shift++; - } - - /* - * Check each quota to cap the prealloc size, provide a shift value to - * throttle with and adjust amount of available space. - */ - if (xfs_quota_need_throttle(ip, XFS_DQ_USER, alloc_blocks)) - xfs_quota_calc_throttle(ip, XFS_DQ_USER, &qblocks, &qshift, - &freesp); - if (xfs_quota_need_throttle(ip, XFS_DQ_GROUP, alloc_blocks)) - xfs_quota_calc_throttle(ip, XFS_DQ_GROUP, &qblocks, &qshift, - &freesp); - if (xfs_quota_need_throttle(ip, XFS_DQ_PROJ, alloc_blocks)) - xfs_quota_calc_throttle(ip, XFS_DQ_PROJ, &qblocks, &qshift, - &freesp); - - /* - * The final prealloc size is set to the minimum of free space available - * in each of the quotas and the overall filesystem. - * - * The shift throttle value is set to the maximum value as determined by - * the global low free space values and per-quota low free space values. - */ - alloc_blocks = MIN(alloc_blocks, qblocks); - shift = MAX(shift, qshift); - - if (shift) - alloc_blocks >>= shift; - /* - * rounddown_pow_of_two() returns an undefined result if we pass in - * alloc_blocks = 0. - */ - if (alloc_blocks) - alloc_blocks = rounddown_pow_of_two(alloc_blocks); - if (alloc_blocks > MAXEXTLEN) - alloc_blocks = MAXEXTLEN; - - /* - * If we are still trying to allocate more space than is - * available, squash the prealloc hard. This can happen if we - * have a large file on a small filesystem and the above - * lowspace thresholds are smaller than MAXEXTLEN. - */ - while (alloc_blocks && alloc_blocks >= freesp) - alloc_blocks >>= 4; -check_writeio: - if (alloc_blocks < mp->m_writeio_blocks) - alloc_blocks = mp->m_writeio_blocks; - trace_xfs_iomap_prealloc_size(ip, alloc_blocks, shift, - mp->m_writeio_blocks); - return alloc_blocks; -} - -static int -xfs_file_iomap_begin_delay( - struct inode *inode, - loff_t offset, - loff_t count, - unsigned flags, - struct iomap *iomap) -{ - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; - struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_DATA_FORK); - xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset); - xfs_fileoff_t maxbytes_fsb = - XFS_B_TO_FSB(mp, mp->m_super->s_maxbytes); - xfs_fileoff_t end_fsb, orig_end_fsb; - int error = 0, eof = 0; - struct xfs_bmbt_irec got; - struct xfs_bmbt_irec prev; - xfs_extnum_t idx; - - ASSERT(!XFS_IS_REALTIME_INODE(ip)); - ASSERT(!xfs_get_extsz_hint(ip)); - - xfs_ilock(ip, XFS_ILOCK_EXCL); - - if (unlikely(XFS_TEST_ERROR( - (XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_EXTENTS && - XFS_IFORK_FORMAT(ip, XFS_DATA_FORK) != XFS_DINODE_FMT_BTREE), - mp, XFS_ERRTAG_BMAPIFORMAT, XFS_RANDOM_BMAPIFORMAT))) { - XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, mp); - error = -EFSCORRUPTED; - goto out_unlock; - } - - XFS_STATS_INC(mp, xs_blk_mapw); - - if (!(ifp->if_flags & XFS_IFEXTENTS)) { - error = xfs_iread_extents(NULL, ip, XFS_DATA_FORK); - if (error) - goto out_unlock; - } - - xfs_bmap_search_extents(ip, offset_fsb, XFS_DATA_FORK, &eof, &idx, - &got, &prev); - if (!eof && got.br_startoff <= offset_fsb) { - if (xfs_is_reflink_inode(ip)) { - bool shared; - - end_fsb = min(XFS_B_TO_FSB(mp, offset + count), - maxbytes_fsb); - xfs_trim_extent(&got, offset_fsb, end_fsb - offset_fsb); - error = xfs_reflink_reserve_cow(ip, &got, &shared); - if (error) - goto out_unlock; - } - - trace_xfs_iomap_found(ip, offset, count, 0, &got); - goto done; - } - - error = xfs_qm_dqattach_locked(ip, 0); - if (error) - goto out_unlock; - - /* - * We cap the maximum length we map here to MAX_WRITEBACK_PAGES pages - * to keep the chunks of work done where somewhat symmetric with the - * work writeback does. This is a completely arbitrary number pulled - * out of thin air as a best guess for initial testing. - * - * Note that the values needs to be less than 32-bits wide until - * the lower level functions are updated. - */ - count = min_t(loff_t, count, 1024 * PAGE_SIZE); - end_fsb = orig_end_fsb = - min(XFS_B_TO_FSB(mp, offset + count), maxbytes_fsb); - - if (eof) { - xfs_fsblock_t prealloc_blocks; - - prealloc_blocks = - xfs_iomap_prealloc_size(ip, offset, count, idx, &prev); - if (prealloc_blocks) { - xfs_extlen_t align; - xfs_off_t end_offset; - - end_offset = XFS_WRITEIO_ALIGN(mp, offset + count - 1); - end_fsb = XFS_B_TO_FSBT(mp, end_offset) + - prealloc_blocks; - - align = xfs_eof_alignment(ip, 0); - if (align) - end_fsb = roundup_64(end_fsb, align); - - end_fsb = min(end_fsb, maxbytes_fsb); - ASSERT(end_fsb > offset_fsb); - } - } - -retry: - error = xfs_bmapi_reserve_delalloc(ip, XFS_DATA_FORK, offset_fsb, - end_fsb - offset_fsb, &got, - &prev, &idx, eof); - switch (error) { - case 0: - break; - case -ENOSPC: - case -EDQUOT: - /* retry without any preallocation */ - trace_xfs_delalloc_enospc(ip, offset, count); - if (end_fsb != orig_end_fsb) { - end_fsb = orig_end_fsb; - goto retry; - } - /*FALLTHRU*/ - default: - goto out_unlock; - } - - /* - * Tag the inode as speculatively preallocated so we can reclaim this - * space on demand, if necessary. - */ - if (end_fsb != orig_end_fsb) - xfs_inode_set_eofblocks_tag(ip); - - trace_xfs_iomap_alloc(ip, offset, count, 0, &got); -done: - if (isnullstartblock(got.br_startblock)) - got.br_startblock = DELAYSTARTBLOCK; - - if (!got.br_startblock) { - error = xfs_alert_fsblock_zero(ip, &got); - if (error) - goto out_unlock; - } - - xfs_bmbt_to_iomap(ip, iomap, &got); - -out_unlock: - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return error; -} - -/* - * Pass in a delayed allocate extent, convert it to real extents; - * return to the caller the extent we create which maps on top of - * the originating callers request. - * - * Called without a lock on the inode. - * - * We no longer bother to look at the incoming map - all we have to - * guarantee is that whatever we allocate fills the required range. - */ -int -xfs_iomap_write_allocate( - xfs_inode_t *ip, - int whichfork, - xfs_off_t offset, - xfs_bmbt_irec_t *imap) -{ - xfs_mount_t *mp = ip->i_mount; - xfs_fileoff_t offset_fsb, last_block; - xfs_fileoff_t end_fsb, map_start_fsb; - xfs_fsblock_t first_block; - struct xfs_defer_ops dfops; - xfs_filblks_t count_fsb; - xfs_trans_t *tp; - int nimaps; - int error = 0; - int flags = 0; - int nres; - - if (whichfork == XFS_COW_FORK) - flags |= XFS_BMAPI_COWFORK; - - /* - * Make sure that the dquots are there. - */ - error = xfs_qm_dqattach(ip, 0); - if (error) - return error; - - offset_fsb = XFS_B_TO_FSBT(mp, offset); - count_fsb = imap->br_blockcount; - map_start_fsb = imap->br_startoff; - - XFS_STATS_ADD(mp, xs_xstrat_bytes, XFS_FSB_TO_B(mp, count_fsb)); - - while (count_fsb != 0) { - /* - * Set up a transaction with which to allocate the - * backing store for the file. Do allocations in a - * loop until we get some space in the range we are - * interested in. The other space that might be allocated - * is in the delayed allocation extent on which we sit - * but before our buffer starts. - */ - nimaps = 0; - while (nimaps == 0) { - nres = XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK); - /* - * We have already reserved space for the extent and any - * indirect blocks when creating the delalloc extent, - * there is no need to reserve space in this transaction - * again. - */ - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, 0, - 0, XFS_TRANS_RESERVE, &tp); - if (error) - return error; - - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, 0); - - xfs_defer_init(&dfops, &first_block); - - /* - * it is possible that the extents have changed since - * we did the read call as we dropped the ilock for a - * while. We have to be careful about truncates or hole - * punchs here - we are not allowed to allocate - * non-delalloc blocks here. - * - * The only protection against truncation is the pages - * for the range we are being asked to convert are - * locked and hence a truncate will block on them - * first. - * - * As a result, if we go beyond the range we really - * need and hit an delalloc extent boundary followed by - * a hole while we have excess blocks in the map, we - * will fill the hole incorrectly and overrun the - * transaction reservation. - * - * Using a single map prevents this as we are forced to - * check each map we look for overlap with the desired - * range and abort as soon as we find it. Also, given - * that we only return a single map, having one beyond - * what we can return is probably a bit silly. - * - * We also need to check that we don't go beyond EOF; - * this is a truncate optimisation as a truncate sets - * the new file size before block on the pages we - * currently have locked under writeback. Because they - * are about to be tossed, we don't need to write them - * back.... - */ - nimaps = 1; - end_fsb = XFS_B_TO_FSB(mp, XFS_ISIZE(ip)); - error = xfs_bmap_last_offset(ip, &last_block, - XFS_DATA_FORK); - if (error) - goto trans_cancel; - - last_block = XFS_FILEOFF_MAX(last_block, end_fsb); - if ((map_start_fsb + count_fsb) > last_block) { - count_fsb = last_block - map_start_fsb; - if (count_fsb == 0) { - error = -EAGAIN; - goto trans_cancel; - } - } - - /* - * From this point onwards we overwrite the imap - * pointer that the caller gave to us. - */ - error = xfs_bmapi_write(tp, ip, map_start_fsb, - count_fsb, flags, &first_block, - nres, imap, &nimaps, - &dfops); - if (error) - goto trans_cancel; - - error = xfs_defer_finish(&tp, &dfops, NULL); - if (error) - goto trans_cancel; - - error = xfs_trans_commit(tp); - if (error) - goto error0; - - xfs_iunlock(ip, XFS_ILOCK_EXCL); - } - - /* - * See if we were able to allocate an extent that - * covers at least part of the callers request - */ - if (!(imap->br_startblock || XFS_IS_REALTIME_INODE(ip))) - return xfs_alert_fsblock_zero(ip, imap); - - if ((offset_fsb >= imap->br_startoff) && - (offset_fsb < (imap->br_startoff + - imap->br_blockcount))) { - XFS_STATS_INC(mp, xs_xstrat_quick); - return 0; - } - - /* - * So far we have not mapped the requested part of the - * file, just surrounding data, try again. - */ - count_fsb -= imap->br_blockcount; - map_start_fsb = imap->br_startoff + imap->br_blockcount; - } - -trans_cancel: - xfs_defer_cancel(&dfops); - xfs_trans_cancel(tp); -error0: - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return error; -} - -int -xfs_iomap_write_unwritten( - xfs_inode_t *ip, - xfs_off_t offset, - xfs_off_t count) -{ - xfs_mount_t *mp = ip->i_mount; - xfs_fileoff_t offset_fsb; - xfs_filblks_t count_fsb; - xfs_filblks_t numblks_fsb; - xfs_fsblock_t firstfsb; - int nimaps; - xfs_trans_t *tp; - xfs_bmbt_irec_t imap; - struct xfs_defer_ops dfops; - xfs_fsize_t i_size; - uint resblks; - int error; - - trace_xfs_unwritten_convert(ip, offset, count); - - offset_fsb = XFS_B_TO_FSBT(mp, offset); - count_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + count); - count_fsb = (xfs_filblks_t)(count_fsb - offset_fsb); - - /* - * Reserve enough blocks in this transaction for two complete extent - * btree splits. We may be converting the middle part of an unwritten - * extent and in this case we will insert two new extents in the btree - * each of which could cause a full split. - * - * This reservation amount will be used in the first call to - * xfs_bmbt_split() to select an AG with enough space to satisfy the - * rest of the operation. - */ - resblks = XFS_DIOSTRAT_SPACE_RES(mp, 0) << 1; - - do { - /* - * Set up a transaction to convert the range of extents - * from unwritten to real. Do allocations in a loop until - * we have covered the range passed in. - * - * Note that we can't risk to recursing back into the filesystem - * here as we might be asked to write out the same inode that we - * complete here and might deadlock on the iolock. - */ - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, - XFS_TRANS_RESERVE | XFS_TRANS_NOFS, &tp); - if (error) - return error; - - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, 0); - - /* - * Modify the unwritten extent state of the buffer. - */ - xfs_defer_init(&dfops, &firstfsb); - nimaps = 1; - error = xfs_bmapi_write(tp, ip, offset_fsb, count_fsb, - XFS_BMAPI_CONVERT, &firstfsb, resblks, - &imap, &nimaps, &dfops); - if (error) - goto error_on_bmapi_transaction; - - /* - * Log the updated inode size as we go. We have to be careful - * to only log it up to the actual write offset if it is - * halfway into a block. - */ - i_size = XFS_FSB_TO_B(mp, offset_fsb + count_fsb); - if (i_size > offset + count) - i_size = offset + count; - - i_size = xfs_new_eof(ip, i_size); - if (i_size) { - ip->i_d.di_size = i_size; - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - } - - error = xfs_defer_finish(&tp, &dfops, NULL); - if (error) - goto error_on_bmapi_transaction; - - error = xfs_trans_commit(tp); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - if (error) - return error; - - if (!(imap.br_startblock || XFS_IS_REALTIME_INODE(ip))) - return xfs_alert_fsblock_zero(ip, &imap); - - if ((numblks_fsb = imap.br_blockcount) == 0) { - /* - * The numblks_fsb value should always get - * smaller, otherwise the loop is stuck. - */ - ASSERT(imap.br_blockcount); - break; - } - offset_fsb += numblks_fsb; - count_fsb -= numblks_fsb; - } while (count_fsb > 0); - - return 0; - -error_on_bmapi_transaction: - xfs_defer_cancel(&dfops); - xfs_trans_cancel(tp); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return error; -} - -static inline bool imap_needs_alloc(struct inode *inode, - struct xfs_bmbt_irec *imap, int nimaps) -{ - return !nimaps || - imap->br_startblock == HOLESTARTBLOCK || - imap->br_startblock == DELAYSTARTBLOCK || - (IS_DAX(inode) && ISUNWRITTEN(imap)); -} - -static int -xfs_file_iomap_begin( - struct inode *inode, - loff_t offset, - loff_t length, - unsigned flags, - struct iomap *iomap) -{ - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; - struct xfs_bmbt_irec imap; - xfs_fileoff_t offset_fsb, end_fsb; - int nimaps = 1, error = 0; - bool shared = false, trimmed = false; - unsigned lockmode; - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - if ((flags & IOMAP_WRITE) && !IS_DAX(inode) && - !xfs_get_extsz_hint(ip)) { - /* Reserve delalloc blocks for regular writeback. */ - return xfs_file_iomap_begin_delay(inode, offset, length, flags, - iomap); - } - - /* - * COW writes will allocate delalloc space, so we need to make sure - * to take the lock exclusively here. - */ - if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) { - lockmode = XFS_ILOCK_EXCL; - xfs_ilock(ip, XFS_ILOCK_EXCL); - } else { - lockmode = xfs_ilock_data_map_shared(ip); - } - - ASSERT(offset <= mp->m_super->s_maxbytes); - if ((xfs_fsize_t)offset + length > mp->m_super->s_maxbytes) - length = mp->m_super->s_maxbytes - offset; - offset_fsb = XFS_B_TO_FSBT(mp, offset); - end_fsb = XFS_B_TO_FSB(mp, offset + length); - - error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, &imap, - &nimaps, 0); - if (error) - goto out_unlock; - - if (flags & IOMAP_REPORT) { - /* Trim the mapping to the nearest shared extent boundary. */ - error = xfs_reflink_trim_around_shared(ip, &imap, &shared, - &trimmed); - if (error) - goto out_unlock; - } - - if ((flags & (IOMAP_WRITE | IOMAP_ZERO)) && xfs_is_reflink_inode(ip)) { - error = xfs_reflink_reserve_cow(ip, &imap, &shared); - if (error) - goto out_unlock; - - end_fsb = imap.br_startoff + imap.br_blockcount; - length = XFS_FSB_TO_B(mp, end_fsb) - offset; - } - - if ((flags & IOMAP_WRITE) && imap_needs_alloc(inode, &imap, nimaps)) { - /* - * We cap the maximum length we map here to MAX_WRITEBACK_PAGES - * pages to keep the chunks of work done where somewhat symmetric - * with the work writeback does. This is a completely arbitrary - * number pulled out of thin air as a best guess for initial - * testing. - * - * Note that the values needs to be less than 32-bits wide until - * the lower level functions are updated. - */ - length = min_t(loff_t, length, 1024 * PAGE_SIZE); - /* - * xfs_iomap_write_direct() expects the shared lock. It - * is unlocked on return. - */ - if (lockmode == XFS_ILOCK_EXCL) - xfs_ilock_demote(ip, lockmode); - error = xfs_iomap_write_direct(ip, offset, length, &imap, - nimaps); - if (error) - return error; - - iomap->flags = IOMAP_F_NEW; - trace_xfs_iomap_alloc(ip, offset, length, 0, &imap); - } else { - ASSERT(nimaps); - - xfs_iunlock(ip, lockmode); - trace_xfs_iomap_found(ip, offset, length, 0, &imap); - } - - xfs_bmbt_to_iomap(ip, iomap, &imap); - if (shared) - iomap->flags |= IOMAP_F_SHARED; - return 0; -out_unlock: - xfs_iunlock(ip, lockmode); - return error; -} - -static int -xfs_file_iomap_end_delalloc( - struct xfs_inode *ip, - loff_t offset, - loff_t length, - ssize_t written) -{ - struct xfs_mount *mp = ip->i_mount; - xfs_fileoff_t start_fsb; - xfs_fileoff_t end_fsb; - int error = 0; - - start_fsb = XFS_B_TO_FSB(mp, offset + written); - end_fsb = XFS_B_TO_FSB(mp, offset + length); - - /* - * Trim back delalloc blocks if we didn't manage to write the whole - * range reserved. - * - * We don't need to care about racing delalloc as we hold i_mutex - * across the reserve/allocate/unreserve calls. If there are delalloc - * blocks in the range, they are ours. - */ - if (start_fsb < end_fsb) { - xfs_ilock(ip, XFS_ILOCK_EXCL); - error = xfs_bmap_punch_delalloc_range(ip, start_fsb, - end_fsb - start_fsb); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - - if (error && !XFS_FORCED_SHUTDOWN(mp)) { - xfs_alert(mp, "%s: unable to clean up ino %lld", - __func__, ip->i_ino); - return error; - } - } - - return 0; -} - -static int -xfs_file_iomap_end( - struct inode *inode, - loff_t offset, - loff_t length, - ssize_t written, - unsigned flags, - struct iomap *iomap) -{ - if ((flags & IOMAP_WRITE) && iomap->type == IOMAP_DELALLOC) - return xfs_file_iomap_end_delalloc(XFS_I(inode), offset, - length, written); - return 0; -} - -struct iomap_ops xfs_iomap_ops = { - .iomap_begin = xfs_file_iomap_begin, - .iomap_end = xfs_file_iomap_end, -}; - -static int -xfs_xattr_iomap_begin( - struct inode *inode, - loff_t offset, - loff_t length, - unsigned flags, - struct iomap *iomap) -{ - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; - xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset); - xfs_fileoff_t end_fsb = XFS_B_TO_FSB(mp, offset + length); - struct xfs_bmbt_irec imap; - int nimaps = 1, error = 0; - unsigned lockmode; - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - lockmode = xfs_ilock_data_map_shared(ip); - - /* if there are no attribute fork or extents, return ENOENT */ - if (XFS_IFORK_Q(ip) || !ip->i_d.di_anextents) { - error = -ENOENT; - goto out_unlock; - } - - ASSERT(ip->i_d.di_aformat != XFS_DINODE_FMT_LOCAL); - error = xfs_bmapi_read(ip, offset_fsb, end_fsb - offset_fsb, &imap, - &nimaps, XFS_BMAPI_ENTIRE | XFS_BMAPI_ATTRFORK); -out_unlock: - xfs_iunlock(ip, lockmode); - - if (!error) { - ASSERT(nimaps); - xfs_bmbt_to_iomap(ip, iomap, &imap); - } - - return error; -} - -struct iomap_ops xfs_xattr_iomap_ops = { - .iomap_begin = xfs_xattr_iomap_begin, -}; diff --git a/src/linux/fs/xfs/xfs_iomap.h b/src/linux/fs/xfs/xfs_iomap.h deleted file mode 100644 index 6d45cf0..0000000 --- a/src/linux/fs/xfs/xfs_iomap.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2003-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_IOMAP_H__ -#define __XFS_IOMAP_H__ - -#include - -struct xfs_inode; -struct xfs_bmbt_irec; - -int xfs_iomap_write_direct(struct xfs_inode *, xfs_off_t, size_t, - struct xfs_bmbt_irec *, int); -int xfs_iomap_write_allocate(struct xfs_inode *, int, xfs_off_t, - struct xfs_bmbt_irec *); -int xfs_iomap_write_unwritten(struct xfs_inode *, xfs_off_t, xfs_off_t); - -void xfs_bmbt_to_iomap(struct xfs_inode *, struct iomap *, - struct xfs_bmbt_irec *); -xfs_extlen_t xfs_eof_alignment(struct xfs_inode *ip, xfs_extlen_t extsize); - -extern struct iomap_ops xfs_iomap_ops; -extern struct iomap_ops xfs_xattr_iomap_ops; - -#endif /* __XFS_IOMAP_H__*/ diff --git a/src/linux/fs/xfs/xfs_iops.c b/src/linux/fs/xfs/xfs_iops.c deleted file mode 100644 index 405a65c..0000000 --- a/src/linux/fs/xfs/xfs_iops.c +++ /dev/null @@ -1,1264 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_inode.h" -#include "xfs_bmap.h" -#include "xfs_bmap_util.h" -#include "xfs_acl.h" -#include "xfs_quota.h" -#include "xfs_error.h" -#include "xfs_attr.h" -#include "xfs_trans.h" -#include "xfs_trace.h" -#include "xfs_icache.h" -#include "xfs_symlink.h" -#include "xfs_da_btree.h" -#include "xfs_dir2.h" -#include "xfs_trans_space.h" -#include "xfs_pnfs.h" -#include "xfs_iomap.h" - -#include -#include -#include -#include -#include -#include - -/* - * Directories have different lock order w.r.t. mmap_sem compared to regular - * files. This is due to readdir potentially triggering page faults on a user - * buffer inside filldir(), and this happens with the ilock on the directory - * held. For regular files, the lock order is the other way around - the - * mmap_sem is taken during the page fault, and then we lock the ilock to do - * block mapping. Hence we need a different class for the directory ilock so - * that lockdep can tell them apart. - */ -static struct lock_class_key xfs_nondir_ilock_class; -static struct lock_class_key xfs_dir_ilock_class; - -static int -xfs_initxattrs( - struct inode *inode, - const struct xattr *xattr_array, - void *fs_info) -{ - const struct xattr *xattr; - struct xfs_inode *ip = XFS_I(inode); - int error = 0; - - for (xattr = xattr_array; xattr->name != NULL; xattr++) { - error = xfs_attr_set(ip, xattr->name, xattr->value, - xattr->value_len, ATTR_SECURE); - if (error < 0) - break; - } - return error; -} - -/* - * Hook in SELinux. This is not quite correct yet, what we really need - * here (as we do for default ACLs) is a mechanism by which creation of - * these attrs can be journalled at inode creation time (along with the - * inode, of course, such that log replay can't cause these to be lost). - */ - -STATIC int -xfs_init_security( - struct inode *inode, - struct inode *dir, - const struct qstr *qstr) -{ - return security_inode_init_security(inode, dir, qstr, - &xfs_initxattrs, NULL); -} - -static void -xfs_dentry_to_name( - struct xfs_name *namep, - struct dentry *dentry, - int mode) -{ - namep->name = dentry->d_name.name; - namep->len = dentry->d_name.len; - namep->type = xfs_mode_to_ftype[(mode & S_IFMT) >> S_SHIFT]; -} - -STATIC void -xfs_cleanup_inode( - struct inode *dir, - struct inode *inode, - struct dentry *dentry) -{ - struct xfs_name teardown; - - /* Oh, the horror. - * If we can't add the ACL or we fail in - * xfs_init_security we must back out. - * ENOSPC can hit here, among other things. - */ - xfs_dentry_to_name(&teardown, dentry, 0); - - xfs_remove(XFS_I(dir), &teardown, XFS_I(inode)); -} - -STATIC int -xfs_generic_create( - struct inode *dir, - struct dentry *dentry, - umode_t mode, - dev_t rdev, - bool tmpfile) /* unnamed file */ -{ - struct inode *inode; - struct xfs_inode *ip = NULL; - struct posix_acl *default_acl, *acl; - struct xfs_name name; - int error; - - /* - * Irix uses Missed'em'V split, but doesn't want to see - * the upper 5 bits of (14bit) major. - */ - if (S_ISCHR(mode) || S_ISBLK(mode)) { - if (unlikely(!sysv_valid_dev(rdev) || MAJOR(rdev) & ~0x1ff)) - return -EINVAL; - rdev = sysv_encode_dev(rdev); - } else { - rdev = 0; - } - - error = posix_acl_create(dir, &mode, &default_acl, &acl); - if (error) - return error; - - if (!tmpfile) { - xfs_dentry_to_name(&name, dentry, mode); - error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip); - } else { - error = xfs_create_tmpfile(XFS_I(dir), dentry, mode, &ip); - } - if (unlikely(error)) - goto out_free_acl; - - inode = VFS_I(ip); - - error = xfs_init_security(inode, dir, &dentry->d_name); - if (unlikely(error)) - goto out_cleanup_inode; - -#ifdef CONFIG_XFS_POSIX_ACL - if (default_acl) { - error = xfs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT); - if (error) - goto out_cleanup_inode; - } - if (acl) { - error = xfs_set_acl(inode, acl, ACL_TYPE_ACCESS); - if (error) - goto out_cleanup_inode; - } -#endif - - xfs_setup_iops(ip); - - if (tmpfile) - d_tmpfile(dentry, inode); - else - d_instantiate(dentry, inode); - - xfs_finish_inode_setup(ip); - - out_free_acl: - if (default_acl) - posix_acl_release(default_acl); - if (acl) - posix_acl_release(acl); - return error; - - out_cleanup_inode: - xfs_finish_inode_setup(ip); - if (!tmpfile) - xfs_cleanup_inode(dir, inode, dentry); - iput(inode); - goto out_free_acl; -} - -STATIC int -xfs_vn_mknod( - struct inode *dir, - struct dentry *dentry, - umode_t mode, - dev_t rdev) -{ - return xfs_generic_create(dir, dentry, mode, rdev, false); -} - -STATIC int -xfs_vn_create( - struct inode *dir, - struct dentry *dentry, - umode_t mode, - bool flags) -{ - return xfs_vn_mknod(dir, dentry, mode, 0); -} - -STATIC int -xfs_vn_mkdir( - struct inode *dir, - struct dentry *dentry, - umode_t mode) -{ - return xfs_vn_mknod(dir, dentry, mode|S_IFDIR, 0); -} - -STATIC struct dentry * -xfs_vn_lookup( - struct inode *dir, - struct dentry *dentry, - unsigned int flags) -{ - struct xfs_inode *cip; - struct xfs_name name; - int error; - - if (dentry->d_name.len >= MAXNAMELEN) - return ERR_PTR(-ENAMETOOLONG); - - xfs_dentry_to_name(&name, dentry, 0); - error = xfs_lookup(XFS_I(dir), &name, &cip, NULL); - if (unlikely(error)) { - if (unlikely(error != -ENOENT)) - return ERR_PTR(error); - d_add(dentry, NULL); - return NULL; - } - - return d_splice_alias(VFS_I(cip), dentry); -} - -STATIC struct dentry * -xfs_vn_ci_lookup( - struct inode *dir, - struct dentry *dentry, - unsigned int flags) -{ - struct xfs_inode *ip; - struct xfs_name xname; - struct xfs_name ci_name; - struct qstr dname; - int error; - - if (dentry->d_name.len >= MAXNAMELEN) - return ERR_PTR(-ENAMETOOLONG); - - xfs_dentry_to_name(&xname, dentry, 0); - error = xfs_lookup(XFS_I(dir), &xname, &ip, &ci_name); - if (unlikely(error)) { - if (unlikely(error != -ENOENT)) - return ERR_PTR(error); - /* - * call d_add(dentry, NULL) here when d_drop_negative_children - * is called in xfs_vn_mknod (ie. allow negative dentries - * with CI filesystems). - */ - return NULL; - } - - /* if exact match, just splice and exit */ - if (!ci_name.name) - return d_splice_alias(VFS_I(ip), dentry); - - /* else case-insensitive match... */ - dname.name = ci_name.name; - dname.len = ci_name.len; - dentry = d_add_ci(dentry, VFS_I(ip), &dname); - kmem_free(ci_name.name); - return dentry; -} - -STATIC int -xfs_vn_link( - struct dentry *old_dentry, - struct inode *dir, - struct dentry *dentry) -{ - struct inode *inode = d_inode(old_dentry); - struct xfs_name name; - int error; - - xfs_dentry_to_name(&name, dentry, inode->i_mode); - - error = xfs_link(XFS_I(dir), XFS_I(inode), &name); - if (unlikely(error)) - return error; - - ihold(inode); - d_instantiate(dentry, inode); - return 0; -} - -STATIC int -xfs_vn_unlink( - struct inode *dir, - struct dentry *dentry) -{ - struct xfs_name name; - int error; - - xfs_dentry_to_name(&name, dentry, 0); - - error = xfs_remove(XFS_I(dir), &name, XFS_I(d_inode(dentry))); - if (error) - return error; - - /* - * With unlink, the VFS makes the dentry "negative": no inode, - * but still hashed. This is incompatible with case-insensitive - * mode, so invalidate (unhash) the dentry in CI-mode. - */ - if (xfs_sb_version_hasasciici(&XFS_M(dir->i_sb)->m_sb)) - d_invalidate(dentry); - return 0; -} - -STATIC int -xfs_vn_symlink( - struct inode *dir, - struct dentry *dentry, - const char *symname) -{ - struct inode *inode; - struct xfs_inode *cip = NULL; - struct xfs_name name; - int error; - umode_t mode; - - mode = S_IFLNK | - (irix_symlink_mode ? 0777 & ~current_umask() : S_IRWXUGO); - xfs_dentry_to_name(&name, dentry, mode); - - error = xfs_symlink(XFS_I(dir), &name, symname, mode, &cip); - if (unlikely(error)) - goto out; - - inode = VFS_I(cip); - - error = xfs_init_security(inode, dir, &dentry->d_name); - if (unlikely(error)) - goto out_cleanup_inode; - - xfs_setup_iops(cip); - - d_instantiate(dentry, inode); - xfs_finish_inode_setup(cip); - return 0; - - out_cleanup_inode: - xfs_finish_inode_setup(cip); - xfs_cleanup_inode(dir, inode, dentry); - iput(inode); - out: - return error; -} - -STATIC int -xfs_vn_rename( - struct inode *odir, - struct dentry *odentry, - struct inode *ndir, - struct dentry *ndentry, - unsigned int flags) -{ - struct inode *new_inode = d_inode(ndentry); - int omode = 0; - struct xfs_name oname; - struct xfs_name nname; - - if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) - return -EINVAL; - - /* if we are exchanging files, we need to set i_mode of both files */ - if (flags & RENAME_EXCHANGE) - omode = d_inode(ndentry)->i_mode; - - xfs_dentry_to_name(&oname, odentry, omode); - xfs_dentry_to_name(&nname, ndentry, d_inode(odentry)->i_mode); - - return xfs_rename(XFS_I(odir), &oname, XFS_I(d_inode(odentry)), - XFS_I(ndir), &nname, - new_inode ? XFS_I(new_inode) : NULL, flags); -} - -/* - * careful here - this function can get called recursively, so - * we need to be very careful about how much stack we use. - * uio is kmalloced for this reason... - */ -STATIC const char * -xfs_vn_get_link( - struct dentry *dentry, - struct inode *inode, - struct delayed_call *done) -{ - char *link; - int error = -ENOMEM; - - if (!dentry) - return ERR_PTR(-ECHILD); - - link = kmalloc(MAXPATHLEN+1, GFP_KERNEL); - if (!link) - goto out_err; - - error = xfs_readlink(XFS_I(d_inode(dentry)), link); - if (unlikely(error)) - goto out_kfree; - - set_delayed_call(done, kfree_link, link); - return link; - - out_kfree: - kfree(link); - out_err: - return ERR_PTR(error); -} - -STATIC const char * -xfs_vn_get_link_inline( - struct dentry *dentry, - struct inode *inode, - struct delayed_call *done) -{ - ASSERT(XFS_I(inode)->i_df.if_flags & XFS_IFINLINE); - return XFS_I(inode)->i_df.if_u1.if_data; -} - -STATIC int -xfs_vn_getattr( - struct vfsmount *mnt, - struct dentry *dentry, - struct kstat *stat) -{ - struct inode *inode = d_inode(dentry); - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; - - trace_xfs_getattr(ip); - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - stat->size = XFS_ISIZE(ip); - stat->dev = inode->i_sb->s_dev; - stat->mode = inode->i_mode; - stat->nlink = inode->i_nlink; - stat->uid = inode->i_uid; - stat->gid = inode->i_gid; - stat->ino = ip->i_ino; - stat->atime = inode->i_atime; - stat->mtime = inode->i_mtime; - stat->ctime = inode->i_ctime; - stat->blocks = - XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks); - - - switch (inode->i_mode & S_IFMT) { - case S_IFBLK: - case S_IFCHR: - stat->blksize = BLKDEV_IOSIZE; - stat->rdev = MKDEV(sysv_major(ip->i_df.if_u2.if_rdev) & 0x1ff, - sysv_minor(ip->i_df.if_u2.if_rdev)); - break; - default: - if (XFS_IS_REALTIME_INODE(ip)) { - /* - * If the file blocks are being allocated from a - * realtime volume, then return the inode's realtime - * extent size or the realtime volume's extent size. - */ - stat->blksize = - xfs_get_extsz_hint(ip) << mp->m_sb.sb_blocklog; - } else - stat->blksize = xfs_preferred_iosize(mp); - stat->rdev = 0; - break; - } - - return 0; -} - -static void -xfs_setattr_mode( - struct xfs_inode *ip, - struct iattr *iattr) -{ - struct inode *inode = VFS_I(ip); - umode_t mode = iattr->ia_mode; - - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - - inode->i_mode &= S_IFMT; - inode->i_mode |= mode & ~S_IFMT; -} - -void -xfs_setattr_time( - struct xfs_inode *ip, - struct iattr *iattr) -{ - struct inode *inode = VFS_I(ip); - - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - - if (iattr->ia_valid & ATTR_ATIME) - inode->i_atime = iattr->ia_atime; - if (iattr->ia_valid & ATTR_CTIME) - inode->i_ctime = iattr->ia_ctime; - if (iattr->ia_valid & ATTR_MTIME) - inode->i_mtime = iattr->ia_mtime; -} - -static int -xfs_vn_change_ok( - struct dentry *dentry, - struct iattr *iattr) -{ - struct xfs_mount *mp = XFS_I(d_inode(dentry))->i_mount; - - if (mp->m_flags & XFS_MOUNT_RDONLY) - return -EROFS; - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - return setattr_prepare(dentry, iattr); -} - -/* - * Set non-size attributes of an inode. - * - * Caution: The caller of this function is responsible for calling - * setattr_prepare() or otherwise verifying the change is fine. - */ -int -xfs_setattr_nonsize( - struct xfs_inode *ip, - struct iattr *iattr, - int flags) -{ - xfs_mount_t *mp = ip->i_mount; - struct inode *inode = VFS_I(ip); - int mask = iattr->ia_valid; - xfs_trans_t *tp; - int error; - kuid_t uid = GLOBAL_ROOT_UID, iuid = GLOBAL_ROOT_UID; - kgid_t gid = GLOBAL_ROOT_GID, igid = GLOBAL_ROOT_GID; - struct xfs_dquot *udqp = NULL, *gdqp = NULL; - struct xfs_dquot *olddquot1 = NULL, *olddquot2 = NULL; - - ASSERT((mask & ATTR_SIZE) == 0); - - /* - * If disk quotas is on, we make sure that the dquots do exist on disk, - * before we start any other transactions. Trying to do this later - * is messy. We don't care to take a readlock to look at the ids - * in inode here, because we can't hold it across the trans_reserve. - * If the IDs do change before we take the ilock, we're covered - * because the i_*dquot fields will get updated anyway. - */ - if (XFS_IS_QUOTA_ON(mp) && (mask & (ATTR_UID|ATTR_GID))) { - uint qflags = 0; - - if ((mask & ATTR_UID) && XFS_IS_UQUOTA_ON(mp)) { - uid = iattr->ia_uid; - qflags |= XFS_QMOPT_UQUOTA; - } else { - uid = inode->i_uid; - } - if ((mask & ATTR_GID) && XFS_IS_GQUOTA_ON(mp)) { - gid = iattr->ia_gid; - qflags |= XFS_QMOPT_GQUOTA; - } else { - gid = inode->i_gid; - } - - /* - * We take a reference when we initialize udqp and gdqp, - * so it is important that we never blindly double trip on - * the same variable. See xfs_create() for an example. - */ - ASSERT(udqp == NULL); - ASSERT(gdqp == NULL); - error = xfs_qm_vop_dqalloc(ip, xfs_kuid_to_uid(uid), - xfs_kgid_to_gid(gid), - xfs_get_projid(ip), - qflags, &udqp, &gdqp, NULL); - if (error) - return error; - } - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0, 0, 0, &tp); - if (error) - goto out_dqrele; - - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, 0); - - /* - * Change file ownership. Must be the owner or privileged. - */ - if (mask & (ATTR_UID|ATTR_GID)) { - /* - * These IDs could have changed since we last looked at them. - * But, we're assured that if the ownership did change - * while we didn't have the inode locked, inode's dquot(s) - * would have changed also. - */ - iuid = inode->i_uid; - igid = inode->i_gid; - gid = (mask & ATTR_GID) ? iattr->ia_gid : igid; - uid = (mask & ATTR_UID) ? iattr->ia_uid : iuid; - - /* - * Do a quota reservation only if uid/gid is actually - * going to change. - */ - if (XFS_IS_QUOTA_RUNNING(mp) && - ((XFS_IS_UQUOTA_ON(mp) && !uid_eq(iuid, uid)) || - (XFS_IS_GQUOTA_ON(mp) && !gid_eq(igid, gid)))) { - ASSERT(tp); - error = xfs_qm_vop_chown_reserve(tp, ip, udqp, gdqp, - NULL, capable(CAP_FOWNER) ? - XFS_QMOPT_FORCE_RES : 0); - if (error) /* out of quota */ - goto out_cancel; - } - } - - /* - * Change file ownership. Must be the owner or privileged. - */ - if (mask & (ATTR_UID|ATTR_GID)) { - /* - * CAP_FSETID overrides the following restrictions: - * - * The set-user-ID and set-group-ID bits of a file will be - * cleared upon successful return from chown() - */ - if ((inode->i_mode & (S_ISUID|S_ISGID)) && - !capable(CAP_FSETID)) - inode->i_mode &= ~(S_ISUID|S_ISGID); - - /* - * Change the ownerships and register quota modifications - * in the transaction. - */ - if (!uid_eq(iuid, uid)) { - if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_UQUOTA_ON(mp)) { - ASSERT(mask & ATTR_UID); - ASSERT(udqp); - olddquot1 = xfs_qm_vop_chown(tp, ip, - &ip->i_udquot, udqp); - } - ip->i_d.di_uid = xfs_kuid_to_uid(uid); - inode->i_uid = uid; - } - if (!gid_eq(igid, gid)) { - if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_GQUOTA_ON(mp)) { - ASSERT(xfs_sb_version_has_pquotino(&mp->m_sb) || - !XFS_IS_PQUOTA_ON(mp)); - ASSERT(mask & ATTR_GID); - ASSERT(gdqp); - olddquot2 = xfs_qm_vop_chown(tp, ip, - &ip->i_gdquot, gdqp); - } - ip->i_d.di_gid = xfs_kgid_to_gid(gid); - inode->i_gid = gid; - } - } - - if (mask & ATTR_MODE) - xfs_setattr_mode(ip, iattr); - if (mask & (ATTR_ATIME|ATTR_CTIME|ATTR_MTIME)) - xfs_setattr_time(ip, iattr); - - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - - XFS_STATS_INC(mp, xs_ig_attrchg); - - if (mp->m_flags & XFS_MOUNT_WSYNC) - xfs_trans_set_sync(tp); - error = xfs_trans_commit(tp); - - xfs_iunlock(ip, XFS_ILOCK_EXCL); - - /* - * Release any dquot(s) the inode had kept before chown. - */ - xfs_qm_dqrele(olddquot1); - xfs_qm_dqrele(olddquot2); - xfs_qm_dqrele(udqp); - xfs_qm_dqrele(gdqp); - - if (error) - return error; - - /* - * XXX(hch): Updating the ACL entries is not atomic vs the i_mode - * update. We could avoid this with linked transactions - * and passing down the transaction pointer all the way - * to attr_set. No previous user of the generic - * Posix ACL code seems to care about this issue either. - */ - if ((mask & ATTR_MODE) && !(flags & XFS_ATTR_NOACL)) { - error = posix_acl_chmod(inode, inode->i_mode); - if (error) - return error; - } - - return 0; - -out_cancel: - xfs_trans_cancel(tp); -out_dqrele: - xfs_qm_dqrele(udqp); - xfs_qm_dqrele(gdqp); - return error; -} - -int -xfs_vn_setattr_nonsize( - struct dentry *dentry, - struct iattr *iattr) -{ - struct xfs_inode *ip = XFS_I(d_inode(dentry)); - int error; - - trace_xfs_setattr(ip); - - error = xfs_vn_change_ok(dentry, iattr); - if (error) - return error; - return xfs_setattr_nonsize(ip, iattr, 0); -} - -/* - * Truncate file. Must have write permission and not be a directory. - * - * Caution: The caller of this function is responsible for calling - * setattr_prepare() or otherwise verifying the change is fine. - */ -int -xfs_setattr_size( - struct xfs_inode *ip, - struct iattr *iattr) -{ - struct xfs_mount *mp = ip->i_mount; - struct inode *inode = VFS_I(ip); - xfs_off_t oldsize, newsize; - struct xfs_trans *tp; - int error; - uint lock_flags = 0; - bool did_zeroing = false; - - ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); - ASSERT(xfs_isilocked(ip, XFS_MMAPLOCK_EXCL)); - ASSERT(S_ISREG(inode->i_mode)); - ASSERT((iattr->ia_valid & (ATTR_UID|ATTR_GID|ATTR_ATIME|ATTR_ATIME_SET| - ATTR_MTIME_SET|ATTR_KILL_PRIV|ATTR_TIMES_SET)) == 0); - - oldsize = inode->i_size; - newsize = iattr->ia_size; - - /* - * Short circuit the truncate case for zero length files. - */ - if (newsize == 0 && oldsize == 0 && ip->i_d.di_nextents == 0) { - if (!(iattr->ia_valid & (ATTR_CTIME|ATTR_MTIME))) - return 0; - - /* - * Use the regular setattr path to update the timestamps. - */ - iattr->ia_valid &= ~ATTR_SIZE; - return xfs_setattr_nonsize(ip, iattr, 0); - } - - /* - * Make sure that the dquots are attached to the inode. - */ - error = xfs_qm_dqattach(ip, 0); - if (error) - return error; - - /* - * Wait for all direct I/O to complete. - */ - inode_dio_wait(inode); - - /* - * File data changes must be complete before we start the transaction to - * modify the inode. This needs to be done before joining the inode to - * the transaction because the inode cannot be unlocked once it is a - * part of the transaction. - * - * Start with zeroing any data beyond EOF that we may expose on file - * extension, or zeroing out the rest of the block on a downward - * truncate. - */ - if (newsize > oldsize) { - error = xfs_zero_eof(ip, newsize, oldsize, &did_zeroing); - } else { - error = iomap_truncate_page(inode, newsize, &did_zeroing, - &xfs_iomap_ops); - } - - if (error) - return error; - - /* - * We are going to log the inode size change in this transaction so - * any previous writes that are beyond the on disk EOF and the new - * EOF that have not been written out need to be written here. If we - * do not write the data out, we expose ourselves to the null files - * problem. Note that this includes any block zeroing we did above; - * otherwise those blocks may not be zeroed after a crash. - */ - if (did_zeroing || - (newsize > ip->i_d.di_size && oldsize != ip->i_d.di_size)) { - error = filemap_write_and_wait_range(VFS_I(ip)->i_mapping, - ip->i_d.di_size, newsize); - if (error) - return error; - } - - /* - * We've already locked out new page faults, so now we can safely remove - * pages from the page cache knowing they won't get refaulted until we - * drop the XFS_MMAP_EXCL lock after the extent manipulations are - * complete. The truncate_setsize() call also cleans partial EOF page - * PTEs on extending truncates and hence ensures sub-page block size - * filesystems are correctly handled, too. - * - * We have to do all the page cache truncate work outside the - * transaction context as the "lock" order is page lock->log space - * reservation as defined by extent allocation in the writeback path. - * Hence a truncate can fail with ENOMEM from xfs_trans_alloc(), but - * having already truncated the in-memory version of the file (i.e. made - * user visible changes). There's not much we can do about this, except - * to hope that the caller sees ENOMEM and retries the truncate - * operation. - */ - truncate_setsize(inode, newsize); - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp); - if (error) - return error; - - lock_flags |= XFS_ILOCK_EXCL; - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, 0); - - /* - * Only change the c/mtime if we are changing the size or we are - * explicitly asked to change it. This handles the semantic difference - * between truncate() and ftruncate() as implemented in the VFS. - * - * The regular truncate() case without ATTR_CTIME and ATTR_MTIME is a - * special case where we need to update the times despite not having - * these flags set. For all other operations the VFS set these flags - * explicitly if it wants a timestamp update. - */ - if (newsize != oldsize && - !(iattr->ia_valid & (ATTR_CTIME | ATTR_MTIME))) { - iattr->ia_ctime = iattr->ia_mtime = - current_time(inode); - iattr->ia_valid |= ATTR_CTIME | ATTR_MTIME; - } - - /* - * The first thing we do is set the size to new_size permanently on - * disk. This way we don't have to worry about anyone ever being able - * to look at the data being freed even in the face of a crash. - * What we're getting around here is the case where we free a block, it - * is allocated to another file, it is written to, and then we crash. - * If the new data gets written to the file but the log buffers - * containing the free and reallocation don't, then we'd end up with - * garbage in the blocks being freed. As long as we make the new size - * permanent before actually freeing any blocks it doesn't matter if - * they get written to. - */ - ip->i_d.di_size = newsize; - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - - if (newsize <= oldsize) { - error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, newsize); - if (error) - goto out_trans_cancel; - - /* - * Truncated "down", so we're removing references to old data - * here - if we delay flushing for a long time, we expose - * ourselves unduly to the notorious NULL files problem. So, - * we mark this inode and flush it when the file is closed, - * and do not wait the usual (long) time for writeout. - */ - xfs_iflags_set(ip, XFS_ITRUNCATED); - - /* A truncate down always removes post-EOF blocks. */ - xfs_inode_clear_eofblocks_tag(ip); - } - - if (iattr->ia_valid & ATTR_MODE) - xfs_setattr_mode(ip, iattr); - if (iattr->ia_valid & (ATTR_ATIME|ATTR_CTIME|ATTR_MTIME)) - xfs_setattr_time(ip, iattr); - - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - - XFS_STATS_INC(mp, xs_ig_attrchg); - - if (mp->m_flags & XFS_MOUNT_WSYNC) - xfs_trans_set_sync(tp); - - error = xfs_trans_commit(tp); -out_unlock: - if (lock_flags) - xfs_iunlock(ip, lock_flags); - return error; - -out_trans_cancel: - xfs_trans_cancel(tp); - goto out_unlock; -} - -int -xfs_vn_setattr_size( - struct dentry *dentry, - struct iattr *iattr) -{ - struct xfs_inode *ip = XFS_I(d_inode(dentry)); - int error; - - trace_xfs_setattr(ip); - - error = xfs_vn_change_ok(dentry, iattr); - if (error) - return error; - return xfs_setattr_size(ip, iattr); -} - -STATIC int -xfs_vn_setattr( - struct dentry *dentry, - struct iattr *iattr) -{ - int error; - - if (iattr->ia_valid & ATTR_SIZE) { - struct xfs_inode *ip = XFS_I(d_inode(dentry)); - uint iolock = XFS_IOLOCK_EXCL; - - xfs_ilock(ip, iolock); - error = xfs_break_layouts(d_inode(dentry), &iolock, true); - if (!error) { - xfs_ilock(ip, XFS_MMAPLOCK_EXCL); - iolock |= XFS_MMAPLOCK_EXCL; - - error = xfs_vn_setattr_size(dentry, iattr); - } - xfs_iunlock(ip, iolock); - } else { - error = xfs_vn_setattr_nonsize(dentry, iattr); - } - - return error; -} - -STATIC int -xfs_vn_update_time( - struct inode *inode, - struct timespec *now, - int flags) -{ - struct xfs_inode *ip = XFS_I(inode); - struct xfs_mount *mp = ip->i_mount; - struct xfs_trans *tp; - int error; - - trace_xfs_update_time(ip); - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_fsyncts, 0, 0, 0, &tp); - if (error) - return error; - - xfs_ilock(ip, XFS_ILOCK_EXCL); - if (flags & S_CTIME) - inode->i_ctime = *now; - if (flags & S_MTIME) - inode->i_mtime = *now; - if (flags & S_ATIME) - inode->i_atime = *now; - - xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); - xfs_trans_log_inode(tp, ip, XFS_ILOG_TIMESTAMP); - return xfs_trans_commit(tp); -} - -STATIC int -xfs_vn_fiemap( - struct inode *inode, - struct fiemap_extent_info *fieinfo, - u64 start, - u64 length) -{ - int error; - - xfs_ilock(XFS_I(inode), XFS_IOLOCK_SHARED); - if (fieinfo->fi_flags & FIEMAP_FLAG_XATTR) { - fieinfo->fi_flags &= ~FIEMAP_FLAG_XATTR; - error = iomap_fiemap(inode, fieinfo, start, length, - &xfs_xattr_iomap_ops); - } else { - error = iomap_fiemap(inode, fieinfo, start, length, - &xfs_iomap_ops); - } - xfs_iunlock(XFS_I(inode), XFS_IOLOCK_SHARED); - - return error; -} - -STATIC int -xfs_vn_tmpfile( - struct inode *dir, - struct dentry *dentry, - umode_t mode) -{ - return xfs_generic_create(dir, dentry, mode, 0, true); -} - -static const struct inode_operations xfs_inode_operations = { - .get_acl = xfs_get_acl, - .set_acl = xfs_set_acl, - .getattr = xfs_vn_getattr, - .setattr = xfs_vn_setattr, - .listxattr = xfs_vn_listxattr, - .fiemap = xfs_vn_fiemap, - .update_time = xfs_vn_update_time, -}; - -static const struct inode_operations xfs_dir_inode_operations = { - .create = xfs_vn_create, - .lookup = xfs_vn_lookup, - .link = xfs_vn_link, - .unlink = xfs_vn_unlink, - .symlink = xfs_vn_symlink, - .mkdir = xfs_vn_mkdir, - /* - * Yes, XFS uses the same method for rmdir and unlink. - * - * There are some subtile differences deeper in the code, - * but we use S_ISDIR to check for those. - */ - .rmdir = xfs_vn_unlink, - .mknod = xfs_vn_mknod, - .rename = xfs_vn_rename, - .get_acl = xfs_get_acl, - .set_acl = xfs_set_acl, - .getattr = xfs_vn_getattr, - .setattr = xfs_vn_setattr, - .listxattr = xfs_vn_listxattr, - .update_time = xfs_vn_update_time, - .tmpfile = xfs_vn_tmpfile, -}; - -static const struct inode_operations xfs_dir_ci_inode_operations = { - .create = xfs_vn_create, - .lookup = xfs_vn_ci_lookup, - .link = xfs_vn_link, - .unlink = xfs_vn_unlink, - .symlink = xfs_vn_symlink, - .mkdir = xfs_vn_mkdir, - /* - * Yes, XFS uses the same method for rmdir and unlink. - * - * There are some subtile differences deeper in the code, - * but we use S_ISDIR to check for those. - */ - .rmdir = xfs_vn_unlink, - .mknod = xfs_vn_mknod, - .rename = xfs_vn_rename, - .get_acl = xfs_get_acl, - .set_acl = xfs_set_acl, - .getattr = xfs_vn_getattr, - .setattr = xfs_vn_setattr, - .listxattr = xfs_vn_listxattr, - .update_time = xfs_vn_update_time, - .tmpfile = xfs_vn_tmpfile, -}; - -static const struct inode_operations xfs_symlink_inode_operations = { - .readlink = generic_readlink, - .get_link = xfs_vn_get_link, - .getattr = xfs_vn_getattr, - .setattr = xfs_vn_setattr, - .listxattr = xfs_vn_listxattr, - .update_time = xfs_vn_update_time, -}; - -static const struct inode_operations xfs_inline_symlink_inode_operations = { - .readlink = generic_readlink, - .get_link = xfs_vn_get_link_inline, - .getattr = xfs_vn_getattr, - .setattr = xfs_vn_setattr, - .listxattr = xfs_vn_listxattr, - .update_time = xfs_vn_update_time, -}; - -STATIC void -xfs_diflags_to_iflags( - struct inode *inode, - struct xfs_inode *ip) -{ - uint16_t flags = ip->i_d.di_flags; - - inode->i_flags &= ~(S_IMMUTABLE | S_APPEND | S_SYNC | - S_NOATIME | S_DAX); - - if (flags & XFS_DIFLAG_IMMUTABLE) - inode->i_flags |= S_IMMUTABLE; - if (flags & XFS_DIFLAG_APPEND) - inode->i_flags |= S_APPEND; - if (flags & XFS_DIFLAG_SYNC) - inode->i_flags |= S_SYNC; - if (flags & XFS_DIFLAG_NOATIME) - inode->i_flags |= S_NOATIME; - if (S_ISREG(inode->i_mode) && - ip->i_mount->m_sb.sb_blocksize == PAGE_SIZE && - !xfs_is_reflink_inode(ip) && - (ip->i_mount->m_flags & XFS_MOUNT_DAX || - ip->i_d.di_flags2 & XFS_DIFLAG2_DAX)) - inode->i_flags |= S_DAX; -} - -/* - * Initialize the Linux inode. - * - * When reading existing inodes from disk this is called directly from xfs_iget, - * when creating a new inode it is called from xfs_ialloc after setting up the - * inode. These callers have different criteria for clearing XFS_INEW, so leave - * it up to the caller to deal with unlocking the inode appropriately. - */ -void -xfs_setup_inode( - struct xfs_inode *ip) -{ - struct inode *inode = &ip->i_vnode; - gfp_t gfp_mask; - - inode->i_ino = ip->i_ino; - inode->i_state = I_NEW; - - inode_sb_list_add(inode); - /* make the inode look hashed for the writeback code */ - hlist_add_fake(&inode->i_hash); - - inode->i_uid = xfs_uid_to_kuid(ip->i_d.di_uid); - inode->i_gid = xfs_gid_to_kgid(ip->i_d.di_gid); - - switch (inode->i_mode & S_IFMT) { - case S_IFBLK: - case S_IFCHR: - inode->i_rdev = - MKDEV(sysv_major(ip->i_df.if_u2.if_rdev) & 0x1ff, - sysv_minor(ip->i_df.if_u2.if_rdev)); - break; - default: - inode->i_rdev = 0; - break; - } - - i_size_write(inode, ip->i_d.di_size); - xfs_diflags_to_iflags(inode, ip); - - if (S_ISDIR(inode->i_mode)) { - lockdep_set_class(&ip->i_lock.mr_lock, &xfs_dir_ilock_class); - ip->d_ops = ip->i_mount->m_dir_inode_ops; - } else { - ip->d_ops = ip->i_mount->m_nondir_inode_ops; - lockdep_set_class(&ip->i_lock.mr_lock, &xfs_nondir_ilock_class); - } - - /* - * Ensure all page cache allocations are done from GFP_NOFS context to - * prevent direct reclaim recursion back into the filesystem and blowing - * stacks or deadlocking. - */ - gfp_mask = mapping_gfp_mask(inode->i_mapping); - mapping_set_gfp_mask(inode->i_mapping, (gfp_mask & ~(__GFP_FS))); - - /* - * If there is no attribute fork no ACL can exist on this inode, - * and it can't have any file capabilities attached to it either. - */ - if (!XFS_IFORK_Q(ip)) { - inode_has_no_xattr(inode); - cache_no_acl(inode); - } -} - -void -xfs_setup_iops( - struct xfs_inode *ip) -{ - struct inode *inode = &ip->i_vnode; - - switch (inode->i_mode & S_IFMT) { - case S_IFREG: - inode->i_op = &xfs_inode_operations; - inode->i_fop = &xfs_file_operations; - inode->i_mapping->a_ops = &xfs_address_space_operations; - break; - case S_IFDIR: - if (xfs_sb_version_hasasciici(&XFS_M(inode->i_sb)->m_sb)) - inode->i_op = &xfs_dir_ci_inode_operations; - else - inode->i_op = &xfs_dir_inode_operations; - inode->i_fop = &xfs_dir_file_operations; - break; - case S_IFLNK: - if (ip->i_df.if_flags & XFS_IFINLINE) - inode->i_op = &xfs_inline_symlink_inode_operations; - else - inode->i_op = &xfs_symlink_inode_operations; - break; - default: - inode->i_op = &xfs_inode_operations; - init_special_inode(inode, inode->i_mode, inode->i_rdev); - break; - } -} diff --git a/src/linux/fs/xfs/xfs_iops.h b/src/linux/fs/xfs/xfs_iops.h deleted file mode 100644 index 0259a38..0000000 --- a/src/linux/fs/xfs/xfs_iops.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_IOPS_H__ -#define __XFS_IOPS_H__ - -struct xfs_inode; - -extern const struct file_operations xfs_file_operations; -extern const struct file_operations xfs_dir_file_operations; - -extern ssize_t xfs_vn_listxattr(struct dentry *, char *data, size_t size); - -/* - * Internal setattr interfaces. - */ -#define XFS_ATTR_NOACL 0x01 /* Don't call posix_acl_chmod */ - -extern void xfs_setattr_time(struct xfs_inode *ip, struct iattr *iattr); -extern int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap, - int flags); -extern int xfs_vn_setattr_nonsize(struct dentry *dentry, struct iattr *vap); -extern int xfs_vn_setattr_size(struct dentry *dentry, struct iattr *vap); - -#endif /* __XFS_IOPS_H__ */ diff --git a/src/linux/fs/xfs/xfs_itable.c b/src/linux/fs/xfs/xfs_itable.c deleted file mode 100644 index 66e8817..0000000 --- a/src/linux/fs/xfs/xfs_itable.c +++ /dev/null @@ -1,666 +0,0 @@ -/* - * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_inode.h" -#include "xfs_btree.h" -#include "xfs_ialloc.h" -#include "xfs_ialloc_btree.h" -#include "xfs_itable.h" -#include "xfs_error.h" -#include "xfs_trace.h" -#include "xfs_icache.h" - -STATIC int -xfs_internal_inum( - xfs_mount_t *mp, - xfs_ino_t ino) -{ - return (ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino || - (xfs_sb_version_hasquota(&mp->m_sb) && - xfs_is_quota_inode(&mp->m_sb, ino))); -} - -/* - * Return stat information for one inode. - * Return 0 if ok, else errno. - */ -int -xfs_bulkstat_one_int( - struct xfs_mount *mp, /* mount point for filesystem */ - xfs_ino_t ino, /* inode to get data for */ - void __user *buffer, /* buffer to place output in */ - int ubsize, /* size of buffer */ - bulkstat_one_fmt_pf formatter, /* formatter, copy to user */ - int *ubused, /* bytes used by me */ - int *stat) /* BULKSTAT_RV_... */ -{ - struct xfs_icdinode *dic; /* dinode core info pointer */ - struct xfs_inode *ip; /* incore inode pointer */ - struct inode *inode; - struct xfs_bstat *buf; /* return buffer */ - int error = 0; /* error value */ - - *stat = BULKSTAT_RV_NOTHING; - - if (!buffer || xfs_internal_inum(mp, ino)) - return -EINVAL; - - buf = kmem_zalloc(sizeof(*buf), KM_SLEEP | KM_MAYFAIL); - if (!buf) - return -ENOMEM; - - error = xfs_iget(mp, NULL, ino, - (XFS_IGET_DONTCACHE | XFS_IGET_UNTRUSTED), - XFS_ILOCK_SHARED, &ip); - if (error) - goto out_free; - - ASSERT(ip != NULL); - ASSERT(ip->i_imap.im_blkno != 0); - inode = VFS_I(ip); - - dic = &ip->i_d; - - /* xfs_iget returns the following without needing - * further change. - */ - buf->bs_projid_lo = dic->di_projid_lo; - buf->bs_projid_hi = dic->di_projid_hi; - buf->bs_ino = ino; - buf->bs_uid = dic->di_uid; - buf->bs_gid = dic->di_gid; - buf->bs_size = dic->di_size; - - buf->bs_nlink = inode->i_nlink; - buf->bs_atime.tv_sec = inode->i_atime.tv_sec; - buf->bs_atime.tv_nsec = inode->i_atime.tv_nsec; - buf->bs_mtime.tv_sec = inode->i_mtime.tv_sec; - buf->bs_mtime.tv_nsec = inode->i_mtime.tv_nsec; - buf->bs_ctime.tv_sec = inode->i_ctime.tv_sec; - buf->bs_ctime.tv_nsec = inode->i_ctime.tv_nsec; - buf->bs_gen = inode->i_generation; - buf->bs_mode = inode->i_mode; - - buf->bs_xflags = xfs_ip2xflags(ip); - buf->bs_extsize = dic->di_extsize << mp->m_sb.sb_blocklog; - buf->bs_extents = dic->di_nextents; - memset(buf->bs_pad, 0, sizeof(buf->bs_pad)); - buf->bs_dmevmask = dic->di_dmevmask; - buf->bs_dmstate = dic->di_dmstate; - buf->bs_aextents = dic->di_anextents; - buf->bs_forkoff = XFS_IFORK_BOFF(ip); - - if (dic->di_version == 3) { - if (dic->di_flags2 & XFS_DIFLAG2_COWEXTSIZE) - buf->bs_cowextsize = dic->di_cowextsize << - mp->m_sb.sb_blocklog; - } - - switch (dic->di_format) { - case XFS_DINODE_FMT_DEV: - buf->bs_rdev = ip->i_df.if_u2.if_rdev; - buf->bs_blksize = BLKDEV_IOSIZE; - buf->bs_blocks = 0; - break; - case XFS_DINODE_FMT_LOCAL: - case XFS_DINODE_FMT_UUID: - buf->bs_rdev = 0; - buf->bs_blksize = mp->m_sb.sb_blocksize; - buf->bs_blocks = 0; - break; - case XFS_DINODE_FMT_EXTENTS: - case XFS_DINODE_FMT_BTREE: - buf->bs_rdev = 0; - buf->bs_blksize = mp->m_sb.sb_blocksize; - buf->bs_blocks = dic->di_nblocks + ip->i_delayed_blks; - break; - } - xfs_iunlock(ip, XFS_ILOCK_SHARED); - IRELE(ip); - - error = formatter(buffer, ubsize, ubused, buf); - if (!error) - *stat = BULKSTAT_RV_DIDONE; - - out_free: - kmem_free(buf); - return error; -} - -/* Return 0 on success or positive error */ -STATIC int -xfs_bulkstat_one_fmt( - void __user *ubuffer, - int ubsize, - int *ubused, - const xfs_bstat_t *buffer) -{ - if (ubsize < sizeof(*buffer)) - return -ENOMEM; - if (copy_to_user(ubuffer, buffer, sizeof(*buffer))) - return -EFAULT; - if (ubused) - *ubused = sizeof(*buffer); - return 0; -} - -int -xfs_bulkstat_one( - xfs_mount_t *mp, /* mount point for filesystem */ - xfs_ino_t ino, /* inode number to get data for */ - void __user *buffer, /* buffer to place output in */ - int ubsize, /* size of buffer */ - int *ubused, /* bytes used by me */ - int *stat) /* BULKSTAT_RV_... */ -{ - return xfs_bulkstat_one_int(mp, ino, buffer, ubsize, - xfs_bulkstat_one_fmt, ubused, stat); -} - -/* - * Loop over all clusters in a chunk for a given incore inode allocation btree - * record. Do a readahead if there are any allocated inodes in that cluster. - */ -STATIC void -xfs_bulkstat_ichunk_ra( - struct xfs_mount *mp, - xfs_agnumber_t agno, - struct xfs_inobt_rec_incore *irec) -{ - xfs_agblock_t agbno; - struct blk_plug plug; - int blks_per_cluster; - int inodes_per_cluster; - int i; /* inode chunk index */ - - agbno = XFS_AGINO_TO_AGBNO(mp, irec->ir_startino); - blks_per_cluster = xfs_icluster_size_fsb(mp); - inodes_per_cluster = blks_per_cluster << mp->m_sb.sb_inopblog; - - blk_start_plug(&plug); - for (i = 0; i < XFS_INODES_PER_CHUNK; - i += inodes_per_cluster, agbno += blks_per_cluster) { - if (xfs_inobt_maskn(i, inodes_per_cluster) & ~irec->ir_free) { - xfs_btree_reada_bufs(mp, agno, agbno, blks_per_cluster, - &xfs_inode_buf_ops); - } - } - blk_finish_plug(&plug); -} - -/* - * Lookup the inode chunk that the given inode lives in and then get the record - * if we found the chunk. If the inode was not the last in the chunk and there - * are some left allocated, update the data for the pointed-to record as well as - * return the count of grabbed inodes. - */ -STATIC int -xfs_bulkstat_grab_ichunk( - struct xfs_btree_cur *cur, /* btree cursor */ - xfs_agino_t agino, /* starting inode of chunk */ - int *icount,/* return # of inodes grabbed */ - struct xfs_inobt_rec_incore *irec) /* btree record */ -{ - int idx; /* index into inode chunk */ - int stat; - int error = 0; - - /* Lookup the inode chunk that this inode lives in */ - error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_LE, &stat); - if (error) - return error; - if (!stat) { - *icount = 0; - return error; - } - - /* Get the record, should always work */ - error = xfs_inobt_get_rec(cur, irec, &stat); - if (error) - return error; - XFS_WANT_CORRUPTED_RETURN(cur->bc_mp, stat == 1); - - /* Check if the record contains the inode in request */ - if (irec->ir_startino + XFS_INODES_PER_CHUNK <= agino) { - *icount = 0; - return 0; - } - - idx = agino - irec->ir_startino + 1; - if (idx < XFS_INODES_PER_CHUNK && - (xfs_inobt_maskn(idx, XFS_INODES_PER_CHUNK - idx) & ~irec->ir_free)) { - int i; - - /* We got a right chunk with some left inodes allocated at it. - * Grab the chunk record. Mark all the uninteresting inodes - * free -- because they're before our start point. - */ - for (i = 0; i < idx; i++) { - if (XFS_INOBT_MASK(i) & ~irec->ir_free) - irec->ir_freecount++; - } - - irec->ir_free |= xfs_inobt_maskn(0, idx); - *icount = irec->ir_count - irec->ir_freecount; - } - - return 0; -} - -#define XFS_BULKSTAT_UBLEFT(ubleft) ((ubleft) >= statstruct_size) - -struct xfs_bulkstat_agichunk { - char __user **ac_ubuffer;/* pointer into user's buffer */ - int ac_ubleft; /* bytes left in user's buffer */ - int ac_ubelem; /* spaces used in user's buffer */ -}; - -/* - * Process inodes in chunk with a pointer to a formatter function - * that will iget the inode and fill in the appropriate structure. - */ -static int -xfs_bulkstat_ag_ichunk( - struct xfs_mount *mp, - xfs_agnumber_t agno, - struct xfs_inobt_rec_incore *irbp, - bulkstat_one_pf formatter, - size_t statstruct_size, - struct xfs_bulkstat_agichunk *acp, - xfs_agino_t *last_agino) -{ - char __user **ubufp = acp->ac_ubuffer; - int chunkidx; - int error = 0; - xfs_agino_t agino = irbp->ir_startino; - - for (chunkidx = 0; chunkidx < XFS_INODES_PER_CHUNK; - chunkidx++, agino++) { - int fmterror; - int ubused; - - /* inode won't fit in buffer, we are done */ - if (acp->ac_ubleft < statstruct_size) - break; - - /* Skip if this inode is free */ - if (XFS_INOBT_MASK(chunkidx) & irbp->ir_free) - continue; - - /* Get the inode and fill in a single buffer */ - ubused = statstruct_size; - error = formatter(mp, XFS_AGINO_TO_INO(mp, agno, agino), - *ubufp, acp->ac_ubleft, &ubused, &fmterror); - - if (fmterror == BULKSTAT_RV_GIVEUP || - (error && error != -ENOENT && error != -EINVAL)) { - acp->ac_ubleft = 0; - ASSERT(error); - break; - } - - /* be careful not to leak error if at end of chunk */ - if (fmterror == BULKSTAT_RV_NOTHING || error) { - error = 0; - continue; - } - - *ubufp += ubused; - acp->ac_ubleft -= ubused; - acp->ac_ubelem++; - } - - /* - * Post-update *last_agino. At this point, agino will always point one - * inode past the last inode we processed successfully. Hence we - * substract that inode when setting the *last_agino cursor so that we - * return the correct cookie to userspace. On the next bulkstat call, - * the inode under the lastino cookie will be skipped as we have already - * processed it here. - */ - *last_agino = agino - 1; - - return error; -} - -/* - * Return stat information in bulk (by-inode) for the filesystem. - */ -int /* error status */ -xfs_bulkstat( - xfs_mount_t *mp, /* mount point for filesystem */ - xfs_ino_t *lastinop, /* last inode returned */ - int *ubcountp, /* size of buffer/count returned */ - bulkstat_one_pf formatter, /* func that'd fill a single buf */ - size_t statstruct_size, /* sizeof struct filling */ - char __user *ubuffer, /* buffer with inode stats */ - int *done) /* 1 if there are more stats to get */ -{ - xfs_buf_t *agbp; /* agi header buffer */ - xfs_agino_t agino; /* inode # in allocation group */ - xfs_agnumber_t agno; /* allocation group number */ - xfs_btree_cur_t *cur; /* btree cursor for ialloc btree */ - size_t irbsize; /* size of irec buffer in bytes */ - xfs_inobt_rec_incore_t *irbuf; /* start of irec buffer */ - int nirbuf; /* size of irbuf */ - int ubcount; /* size of user's buffer */ - struct xfs_bulkstat_agichunk ac; - int error = 0; - - /* - * Get the last inode value, see if there's nothing to do. - */ - agno = XFS_INO_TO_AGNO(mp, *lastinop); - agino = XFS_INO_TO_AGINO(mp, *lastinop); - if (agno >= mp->m_sb.sb_agcount || - *lastinop != XFS_AGINO_TO_INO(mp, agno, agino)) { - *done = 1; - *ubcountp = 0; - return 0; - } - - ubcount = *ubcountp; /* statstruct's */ - ac.ac_ubuffer = &ubuffer; - ac.ac_ubleft = ubcount * statstruct_size; /* bytes */; - ac.ac_ubelem = 0; - - *ubcountp = 0; - *done = 0; - - irbuf = kmem_zalloc_greedy(&irbsize, PAGE_SIZE, PAGE_SIZE * 4); - if (!irbuf) - return -ENOMEM; - - nirbuf = irbsize / sizeof(*irbuf); - - /* - * Loop over the allocation groups, starting from the last - * inode returned; 0 means start of the allocation group. - */ - while (agno < mp->m_sb.sb_agcount) { - struct xfs_inobt_rec_incore *irbp = irbuf; - struct xfs_inobt_rec_incore *irbufend = irbuf + nirbuf; - bool end_of_ag = false; - int icount = 0; - int stat; - - error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp); - if (error) - break; - /* - * Allocate and initialize a btree cursor for ialloc btree. - */ - cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno, - XFS_BTNUM_INO); - if (agino > 0) { - /* - * In the middle of an allocation group, we need to get - * the remainder of the chunk we're in. - */ - struct xfs_inobt_rec_incore r; - - error = xfs_bulkstat_grab_ichunk(cur, agino, &icount, &r); - if (error) - goto del_cursor; - if (icount) { - irbp->ir_startino = r.ir_startino; - irbp->ir_holemask = r.ir_holemask; - irbp->ir_count = r.ir_count; - irbp->ir_freecount = r.ir_freecount; - irbp->ir_free = r.ir_free; - irbp++; - } - /* Increment to the next record */ - error = xfs_btree_increment(cur, 0, &stat); - } else { - /* Start of ag. Lookup the first inode chunk */ - error = xfs_inobt_lookup(cur, 0, XFS_LOOKUP_GE, &stat); - } - if (error || stat == 0) { - end_of_ag = true; - goto del_cursor; - } - - /* - * Loop through inode btree records in this ag, - * until we run out of inodes or space in the buffer. - */ - while (irbp < irbufend && icount < ubcount) { - struct xfs_inobt_rec_incore r; - - error = xfs_inobt_get_rec(cur, &r, &stat); - if (error || stat == 0) { - end_of_ag = true; - goto del_cursor; - } - - /* - * If this chunk has any allocated inodes, save it. - * Also start read-ahead now for this chunk. - */ - if (r.ir_freecount < r.ir_count) { - xfs_bulkstat_ichunk_ra(mp, agno, &r); - irbp->ir_startino = r.ir_startino; - irbp->ir_holemask = r.ir_holemask; - irbp->ir_count = r.ir_count; - irbp->ir_freecount = r.ir_freecount; - irbp->ir_free = r.ir_free; - irbp++; - icount += r.ir_count - r.ir_freecount; - } - error = xfs_btree_increment(cur, 0, &stat); - if (error || stat == 0) { - end_of_ag = true; - goto del_cursor; - } - cond_resched(); - } - - /* - * Drop the btree buffers and the agi buffer as we can't hold any - * of the locks these represent when calling iget. If there is a - * pending error, then we are done. - */ -del_cursor: - xfs_btree_del_cursor(cur, error ? - XFS_BTREE_ERROR : XFS_BTREE_NOERROR); - xfs_buf_relse(agbp); - if (error) - break; - /* - * Now format all the good inodes into the user's buffer. The - * call to xfs_bulkstat_ag_ichunk() sets up the agino pointer - * for the next loop iteration. - */ - irbufend = irbp; - for (irbp = irbuf; - irbp < irbufend && ac.ac_ubleft >= statstruct_size; - irbp++) { - error = xfs_bulkstat_ag_ichunk(mp, agno, irbp, - formatter, statstruct_size, &ac, - &agino); - if (error) - break; - - cond_resched(); - } - - /* - * If we've run out of space or had a formatting error, we - * are now done - */ - if (ac.ac_ubleft < statstruct_size || error) - break; - - if (end_of_ag) { - agno++; - agino = 0; - } - } - /* - * Done, we're either out of filesystem or space to put the data. - */ - kmem_free(irbuf); - *ubcountp = ac.ac_ubelem; - - /* - * We found some inodes, so clear the error status and return them. - * The lastino pointer will point directly at the inode that triggered - * any error that occurred, so on the next call the error will be - * triggered again and propagated to userspace as there will be no - * formatted inodes in the buffer. - */ - if (ac.ac_ubelem) - error = 0; - - /* - * If we ran out of filesystem, lastino will point off the end of - * the filesystem so the next call will return immediately. - */ - *lastinop = XFS_AGINO_TO_INO(mp, agno, agino); - if (agno >= mp->m_sb.sb_agcount) - *done = 1; - - return error; -} - -int -xfs_inumbers_fmt( - void __user *ubuffer, /* buffer to write to */ - const struct xfs_inogrp *buffer, /* buffer to read from */ - long count, /* # of elements to read */ - long *written) /* # of bytes written */ -{ - if (copy_to_user(ubuffer, buffer, count * sizeof(*buffer))) - return -EFAULT; - *written = count * sizeof(*buffer); - return 0; -} - -/* - * Return inode number table for the filesystem. - */ -int /* error status */ -xfs_inumbers( - struct xfs_mount *mp,/* mount point for filesystem */ - xfs_ino_t *lastino,/* last inode returned */ - int *count,/* size of buffer/count returned */ - void __user *ubuffer,/* buffer with inode descriptions */ - inumbers_fmt_pf formatter) -{ - xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, *lastino); - xfs_agino_t agino = XFS_INO_TO_AGINO(mp, *lastino); - struct xfs_btree_cur *cur = NULL; - struct xfs_buf *agbp = NULL; - struct xfs_inogrp *buffer; - int bcount; - int left = *count; - int bufidx = 0; - int error = 0; - - *count = 0; - if (agno >= mp->m_sb.sb_agcount || - *lastino != XFS_AGINO_TO_INO(mp, agno, agino)) - return error; - - bcount = MIN(left, (int)(PAGE_SIZE / sizeof(*buffer))); - buffer = kmem_alloc(bcount * sizeof(*buffer), KM_SLEEP); - do { - struct xfs_inobt_rec_incore r; - int stat; - - if (!agbp) { - error = xfs_ialloc_read_agi(mp, NULL, agno, &agbp); - if (error) - break; - - cur = xfs_inobt_init_cursor(mp, NULL, agbp, agno, - XFS_BTNUM_INO); - error = xfs_inobt_lookup(cur, agino, XFS_LOOKUP_GE, - &stat); - if (error) - break; - if (!stat) - goto next_ag; - } - - error = xfs_inobt_get_rec(cur, &r, &stat); - if (error) - break; - if (!stat) - goto next_ag; - - agino = r.ir_startino + XFS_INODES_PER_CHUNK - 1; - buffer[bufidx].xi_startino = - XFS_AGINO_TO_INO(mp, agno, r.ir_startino); - buffer[bufidx].xi_alloccount = r.ir_count - r.ir_freecount; - buffer[bufidx].xi_allocmask = ~r.ir_free; - if (++bufidx == bcount) { - long written; - - error = formatter(ubuffer, buffer, bufidx, &written); - if (error) - break; - ubuffer += written; - *count += bufidx; - bufidx = 0; - } - if (!--left) - break; - - error = xfs_btree_increment(cur, 0, &stat); - if (error) - break; - if (stat) - continue; - -next_ag: - xfs_btree_del_cursor(cur, XFS_BTREE_ERROR); - cur = NULL; - xfs_buf_relse(agbp); - agbp = NULL; - agino = 0; - agno++; - } while (agno < mp->m_sb.sb_agcount); - - if (!error) { - if (bufidx) { - long written; - - error = formatter(ubuffer, buffer, bufidx, &written); - if (!error) - *count += bufidx; - } - *lastino = XFS_AGINO_TO_INO(mp, agno, agino); - } - - kmem_free(buffer); - if (cur) - xfs_btree_del_cursor(cur, (error ? XFS_BTREE_ERROR : - XFS_BTREE_NOERROR)); - if (agbp) - xfs_buf_relse(agbp); - - return error; -} diff --git a/src/linux/fs/xfs/xfs_itable.h b/src/linux/fs/xfs/xfs_itable.h deleted file mode 100644 index 6ea8b39..0000000 --- a/src/linux/fs/xfs/xfs_itable.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2000-2001 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_ITABLE_H__ -#define __XFS_ITABLE_H__ - -/* - * xfs_bulkstat() is used to fill in xfs_bstat structures as well as dm_stat - * structures (by the dmi library). This is a pointer to a formatter function - * that will iget the inode and fill in the appropriate structure. - * see xfs_bulkstat_one() and xfs_dm_bulkstat_one() in dmapi_xfs.c - */ -typedef int (*bulkstat_one_pf)(struct xfs_mount *mp, - xfs_ino_t ino, - void __user *buffer, - int ubsize, - int *ubused, - int *stat); - -/* - * Values for stat return value. - */ -#define BULKSTAT_RV_NOTHING 0 -#define BULKSTAT_RV_DIDONE 1 -#define BULKSTAT_RV_GIVEUP 2 - -/* - * Return stat information in bulk (by-inode) for the filesystem. - */ -int /* error status */ -xfs_bulkstat( - xfs_mount_t *mp, /* mount point for filesystem */ - xfs_ino_t *lastino, /* last inode returned */ - int *count, /* size of buffer/count returned */ - bulkstat_one_pf formatter, /* func that'd fill a single buf */ - size_t statstruct_size,/* sizeof struct that we're filling */ - char __user *ubuffer,/* buffer with inode stats */ - int *done); /* 1 if there are more stats to get */ - -typedef int (*bulkstat_one_fmt_pf)( /* used size in bytes or negative error */ - void __user *ubuffer, /* buffer to write to */ - int ubsize, /* remaining user buffer sz */ - int *ubused, /* bytes used by formatter */ - const xfs_bstat_t *buffer); /* buffer to read from */ - -int -xfs_bulkstat_one_int( - xfs_mount_t *mp, - xfs_ino_t ino, - void __user *buffer, - int ubsize, - bulkstat_one_fmt_pf formatter, - int *ubused, - int *stat); - -int -xfs_bulkstat_one( - xfs_mount_t *mp, - xfs_ino_t ino, - void __user *buffer, - int ubsize, - int *ubused, - int *stat); - -typedef int (*inumbers_fmt_pf)( - void __user *ubuffer, /* buffer to write to */ - const xfs_inogrp_t *buffer, /* buffer to read from */ - long count, /* # of elements to read */ - long *written); /* # of bytes written */ - -int -xfs_inumbers_fmt( - void __user *ubuffer, /* buffer to write to */ - const xfs_inogrp_t *buffer, /* buffer to read from */ - long count, /* # of elements to read */ - long *written); /* # of bytes written */ - -int /* error status */ -xfs_inumbers( - xfs_mount_t *mp, /* mount point for filesystem */ - xfs_ino_t *last, /* last inode returned */ - int *count, /* size of buffer/count returned */ - void __user *buffer, /* buffer with inode info */ - inumbers_fmt_pf formatter); - -#endif /* __XFS_ITABLE_H__ */ diff --git a/src/linux/fs/xfs/xfs_linux.h b/src/linux/fs/xfs/xfs_linux.h deleted file mode 100644 index 68640fb..0000000 --- a/src/linux/fs/xfs/xfs_linux.h +++ /dev/null @@ -1,371 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_LINUX__ -#define __XFS_LINUX__ - -#include - -/* - * Kernel specific type declarations for XFS - */ -typedef signed char __int8_t; -typedef unsigned char __uint8_t; -typedef signed short int __int16_t; -typedef unsigned short int __uint16_t; -typedef signed int __int32_t; -typedef unsigned int __uint32_t; -typedef signed long long int __int64_t; -typedef unsigned long long int __uint64_t; - -typedef __s64 xfs_off_t; /* type */ -typedef unsigned long long xfs_ino_t; /* type */ -typedef __s64 xfs_daddr_t; /* type */ -typedef __u32 xfs_dev_t; -typedef __u32 xfs_nlink_t; - -#include "xfs_types.h" - -#include "kmem.h" -#include "mrlock.h" -#include "uuid.h" - -#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 -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "xfs_fs.h" -#include "xfs_stats.h" -#include "xfs_sysctl.h" -#include "xfs_iops.h" -#include "xfs_aops.h" -#include "xfs_super.h" -#include "xfs_cksum.h" -#include "xfs_buf.h" -#include "xfs_message.h" - -#ifdef __BIG_ENDIAN -#define XFS_NATIVE_HOST 1 -#else -#undef XFS_NATIVE_HOST -#endif - -#define irix_sgid_inherit xfs_params.sgid_inherit.val -#define irix_symlink_mode xfs_params.symlink_mode.val -#define xfs_panic_mask xfs_params.panic_mask.val -#define xfs_error_level xfs_params.error_level.val -#define xfs_syncd_centisecs xfs_params.syncd_timer.val -#define xfs_stats_clear xfs_params.stats_clear.val -#define xfs_inherit_sync xfs_params.inherit_sync.val -#define xfs_inherit_nodump xfs_params.inherit_nodump.val -#define xfs_inherit_noatime xfs_params.inherit_noatim.val -#define xfs_inherit_nosymlinks xfs_params.inherit_nosym.val -#define xfs_rotorstep xfs_params.rotorstep.val -#define xfs_inherit_nodefrag xfs_params.inherit_nodfrg.val -#define xfs_fstrm_centisecs xfs_params.fstrm_timer.val -#define xfs_eofb_secs xfs_params.eofb_timer.val -#define xfs_cowb_secs xfs_params.cowb_timer.val - -#define current_cpu() (raw_smp_processor_id()) -#define current_pid() (current->pid) -#define current_test_flags(f) (current->flags & (f)) -#define current_set_flags_nested(sp, f) \ - (*(sp) = current->flags, current->flags |= (f)) -#define current_clear_flags_nested(sp, f) \ - (*(sp) = current->flags, current->flags &= ~(f)) -#define current_restore_flags_nested(sp, f) \ - (current->flags = ((current->flags & ~(f)) | (*(sp) & (f)))) - -#define spinlock_destroy(lock) - -#define NBBY 8 /* number of bits per byte */ - -/* - * Size of block device i/o is parameterized here. - * Currently the system supports page-sized i/o. - */ -#define BLKDEV_IOSHIFT PAGE_SHIFT -#define BLKDEV_IOSIZE (1<> 32; - __low = c; - if (__high) { - __upper = __high % (b); - __high = __high / (b); - } - asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (b), "0" (__low), "1" (__upper)); - asm("":"=A" (c):"a" (__low),"d" (__high)); - *(__u64 *)a = c; - return __mod; - } - } - - /* NOTREACHED */ - return 0; -} - -/* Side effect free 64 bit mod operation */ -static inline __u32 xfs_do_mod(void *a, __u32 b, int n) -{ - switch (n) { - case 4: - return *(__u32 *)a % b; - case 8: - { - unsigned long __upper, __low, __high, __mod; - __u64 c = *(__u64 *)a; - __upper = __high = c >> 32; - __low = c; - if (__high) { - __upper = __high % (b); - __high = __high / (b); - } - asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (b), "0" (__low), "1" (__upper)); - asm("":"=A" (c):"a" (__low),"d" (__high)); - return __mod; - } - } - - /* NOTREACHED */ - return 0; -} -#else -static inline __u32 xfs_do_div(void *a, __u32 b, int n) -{ - __u32 mod; - - switch (n) { - case 4: - mod = *(__u32 *)a % b; - *(__u32 *)a = *(__u32 *)a / b; - return mod; - case 8: - mod = do_div(*(__u64 *)a, b); - return mod; - } - - /* NOTREACHED */ - return 0; -} - -/* Side effect free 64 bit mod operation */ -static inline __u32 xfs_do_mod(void *a, __u32 b, int n) -{ - switch (n) { - case 4: - return *(__u32 *)a % b; - case 8: - { - __u64 c = *(__u64 *)a; - return do_div(c, b); - } - } - - /* NOTREACHED */ - return 0; -} -#endif - -#undef do_div -#define do_div(a, b) xfs_do_div(&(a), (b), sizeof(a)) -#define do_mod(a, b) xfs_do_mod(&(a), (b), sizeof(a)) - -static inline __uint64_t roundup_64(__uint64_t x, __uint32_t y) -{ - x += y - 1; - do_div(x, y); - return x * y; -} - -static inline __uint64_t howmany_64(__uint64_t x, __uint32_t y) -{ - x += y - 1; - do_div(x, y); - return x; -} - -#define ASSERT_ALWAYS(expr) \ - (unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__)) - -#ifdef DEBUG -#define ASSERT(expr) \ - (unlikely(expr) ? (void)0 : assfail(#expr, __FILE__, __LINE__)) - -#ifndef STATIC -# define STATIC noinline -#endif - -#else /* !DEBUG */ - -#ifdef XFS_WARN - -#define ASSERT(expr) \ - (unlikely(expr) ? (void)0 : asswarn(#expr, __FILE__, __LINE__)) - -#ifndef STATIC -# define STATIC static noinline -#endif - -#else /* !DEBUG && !XFS_WARN */ - -#define ASSERT(expr) ((void)0) - -#ifndef STATIC -# define STATIC static noinline -#endif - -#endif /* XFS_WARN */ -#endif /* DEBUG */ - -#ifdef CONFIG_XFS_RT -#define XFS_IS_REALTIME_INODE(ip) ((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) -#else -#define XFS_IS_REALTIME_INODE(ip) (0) -#endif - -#endif /* __XFS_LINUX__ */ diff --git a/src/linux/fs/xfs/xfs_log.c b/src/linux/fs/xfs/xfs_log.c deleted file mode 100644 index 3b74fa0..0000000 --- a/src/linux/fs/xfs/xfs_log.c +++ /dev/null @@ -1,4064 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_error.h" -#include "xfs_trans.h" -#include "xfs_trans_priv.h" -#include "xfs_log.h" -#include "xfs_log_priv.h" -#include "xfs_log_recover.h" -#include "xfs_inode.h" -#include "xfs_trace.h" -#include "xfs_fsops.h" -#include "xfs_cksum.h" -#include "xfs_sysfs.h" -#include "xfs_sb.h" - -kmem_zone_t *xfs_log_ticket_zone; - -/* Local miscellaneous function prototypes */ -STATIC int -xlog_commit_record( - struct xlog *log, - struct xlog_ticket *ticket, - struct xlog_in_core **iclog, - xfs_lsn_t *commitlsnp); - -STATIC struct xlog * -xlog_alloc_log( - struct xfs_mount *mp, - struct xfs_buftarg *log_target, - xfs_daddr_t blk_offset, - int num_bblks); -STATIC int -xlog_space_left( - struct xlog *log, - atomic64_t *head); -STATIC int -xlog_sync( - struct xlog *log, - struct xlog_in_core *iclog); -STATIC void -xlog_dealloc_log( - struct xlog *log); - -/* local state machine functions */ -STATIC void xlog_state_done_syncing(xlog_in_core_t *iclog, int); -STATIC void -xlog_state_do_callback( - struct xlog *log, - int aborted, - struct xlog_in_core *iclog); -STATIC int -xlog_state_get_iclog_space( - struct xlog *log, - int len, - struct xlog_in_core **iclog, - struct xlog_ticket *ticket, - int *continued_write, - int *logoffsetp); -STATIC int -xlog_state_release_iclog( - struct xlog *log, - struct xlog_in_core *iclog); -STATIC void -xlog_state_switch_iclogs( - struct xlog *log, - struct xlog_in_core *iclog, - int eventual_size); -STATIC void -xlog_state_want_sync( - struct xlog *log, - struct xlog_in_core *iclog); - -STATIC void -xlog_grant_push_ail( - struct xlog *log, - int need_bytes); -STATIC void -xlog_regrant_reserve_log_space( - struct xlog *log, - struct xlog_ticket *ticket); -STATIC void -xlog_ungrant_log_space( - struct xlog *log, - struct xlog_ticket *ticket); - -#if defined(DEBUG) -STATIC void -xlog_verify_dest_ptr( - struct xlog *log, - void *ptr); -STATIC void -xlog_verify_grant_tail( - struct xlog *log); -STATIC void -xlog_verify_iclog( - struct xlog *log, - struct xlog_in_core *iclog, - int count, - bool syncing); -STATIC void -xlog_verify_tail_lsn( - struct xlog *log, - struct xlog_in_core *iclog, - xfs_lsn_t tail_lsn); -#else -#define xlog_verify_dest_ptr(a,b) -#define xlog_verify_grant_tail(a) -#define xlog_verify_iclog(a,b,c,d) -#define xlog_verify_tail_lsn(a,b,c) -#endif - -STATIC int -xlog_iclogs_empty( - struct xlog *log); - -static void -xlog_grant_sub_space( - struct xlog *log, - atomic64_t *head, - int bytes) -{ - int64_t head_val = atomic64_read(head); - int64_t new, old; - - do { - int cycle, space; - - xlog_crack_grant_head_val(head_val, &cycle, &space); - - space -= bytes; - if (space < 0) { - space += log->l_logsize; - cycle--; - } - - old = head_val; - new = xlog_assign_grant_head_val(cycle, space); - head_val = atomic64_cmpxchg(head, old, new); - } while (head_val != old); -} - -static void -xlog_grant_add_space( - struct xlog *log, - atomic64_t *head, - int bytes) -{ - int64_t head_val = atomic64_read(head); - int64_t new, old; - - do { - int tmp; - int cycle, space; - - xlog_crack_grant_head_val(head_val, &cycle, &space); - - tmp = log->l_logsize - space; - if (tmp > bytes) - space += bytes; - else { - space = bytes - tmp; - cycle++; - } - - old = head_val; - new = xlog_assign_grant_head_val(cycle, space); - head_val = atomic64_cmpxchg(head, old, new); - } while (head_val != old); -} - -STATIC void -xlog_grant_head_init( - struct xlog_grant_head *head) -{ - xlog_assign_grant_head(&head->grant, 1, 0); - INIT_LIST_HEAD(&head->waiters); - spin_lock_init(&head->lock); -} - -STATIC void -xlog_grant_head_wake_all( - struct xlog_grant_head *head) -{ - struct xlog_ticket *tic; - - spin_lock(&head->lock); - list_for_each_entry(tic, &head->waiters, t_queue) - wake_up_process(tic->t_task); - spin_unlock(&head->lock); -} - -static inline int -xlog_ticket_reservation( - struct xlog *log, - struct xlog_grant_head *head, - struct xlog_ticket *tic) -{ - if (head == &log->l_write_head) { - ASSERT(tic->t_flags & XLOG_TIC_PERM_RESERV); - return tic->t_unit_res; - } else { - if (tic->t_flags & XLOG_TIC_PERM_RESERV) - return tic->t_unit_res * tic->t_cnt; - else - return tic->t_unit_res; - } -} - -STATIC bool -xlog_grant_head_wake( - struct xlog *log, - struct xlog_grant_head *head, - int *free_bytes) -{ - struct xlog_ticket *tic; - int need_bytes; - - list_for_each_entry(tic, &head->waiters, t_queue) { - need_bytes = xlog_ticket_reservation(log, head, tic); - if (*free_bytes < need_bytes) - return false; - - *free_bytes -= need_bytes; - trace_xfs_log_grant_wake_up(log, tic); - wake_up_process(tic->t_task); - } - - return true; -} - -STATIC int -xlog_grant_head_wait( - struct xlog *log, - struct xlog_grant_head *head, - struct xlog_ticket *tic, - int need_bytes) __releases(&head->lock) - __acquires(&head->lock) -{ - list_add_tail(&tic->t_queue, &head->waiters); - - do { - if (XLOG_FORCED_SHUTDOWN(log)) - goto shutdown; - xlog_grant_push_ail(log, need_bytes); - - __set_current_state(TASK_UNINTERRUPTIBLE); - spin_unlock(&head->lock); - - XFS_STATS_INC(log->l_mp, xs_sleep_logspace); - - trace_xfs_log_grant_sleep(log, tic); - schedule(); - trace_xfs_log_grant_wake(log, tic); - - spin_lock(&head->lock); - if (XLOG_FORCED_SHUTDOWN(log)) - goto shutdown; - } while (xlog_space_left(log, &head->grant) < need_bytes); - - list_del_init(&tic->t_queue); - return 0; -shutdown: - list_del_init(&tic->t_queue); - return -EIO; -} - -/* - * Atomically get the log space required for a log ticket. - * - * Once a ticket gets put onto head->waiters, it will only return after the - * needed reservation is satisfied. - * - * This function is structured so that it has a lock free fast path. This is - * necessary because every new transaction reservation will come through this - * path. Hence any lock will be globally hot if we take it unconditionally on - * every pass. - * - * As tickets are only ever moved on and off head->waiters under head->lock, we - * only need to take that lock if we are going to add the ticket to the queue - * and sleep. We can avoid taking the lock if the ticket was never added to - * head->waiters because the t_queue list head will be empty and we hold the - * only reference to it so it can safely be checked unlocked. - */ -STATIC int -xlog_grant_head_check( - struct xlog *log, - struct xlog_grant_head *head, - struct xlog_ticket *tic, - int *need_bytes) -{ - int free_bytes; - int error = 0; - - ASSERT(!(log->l_flags & XLOG_ACTIVE_RECOVERY)); - - /* - * If there are other waiters on the queue then give them a chance at - * logspace before us. Wake up the first waiters, if we do not wake - * up all the waiters then go to sleep waiting for more free space, - * otherwise try to get some space for this transaction. - */ - *need_bytes = xlog_ticket_reservation(log, head, tic); - free_bytes = xlog_space_left(log, &head->grant); - if (!list_empty_careful(&head->waiters)) { - spin_lock(&head->lock); - if (!xlog_grant_head_wake(log, head, &free_bytes) || - free_bytes < *need_bytes) { - error = xlog_grant_head_wait(log, head, tic, - *need_bytes); - } - spin_unlock(&head->lock); - } else if (free_bytes < *need_bytes) { - spin_lock(&head->lock); - error = xlog_grant_head_wait(log, head, tic, *need_bytes); - spin_unlock(&head->lock); - } - - return error; -} - -static void -xlog_tic_reset_res(xlog_ticket_t *tic) -{ - tic->t_res_num = 0; - tic->t_res_arr_sum = 0; - tic->t_res_num_ophdrs = 0; -} - -static void -xlog_tic_add_region(xlog_ticket_t *tic, uint len, uint type) -{ - if (tic->t_res_num == XLOG_TIC_LEN_MAX) { - /* add to overflow and start again */ - tic->t_res_o_flow += tic->t_res_arr_sum; - tic->t_res_num = 0; - tic->t_res_arr_sum = 0; - } - - tic->t_res_arr[tic->t_res_num].r_len = len; - tic->t_res_arr[tic->t_res_num].r_type = type; - tic->t_res_arr_sum += len; - tic->t_res_num++; -} - -/* - * Replenish the byte reservation required by moving the grant write head. - */ -int -xfs_log_regrant( - struct xfs_mount *mp, - struct xlog_ticket *tic) -{ - struct xlog *log = mp->m_log; - int need_bytes; - int error = 0; - - if (XLOG_FORCED_SHUTDOWN(log)) - return -EIO; - - XFS_STATS_INC(mp, xs_try_logspace); - - /* - * This is a new transaction on the ticket, so we need to change the - * transaction ID so that the next transaction has a different TID in - * the log. Just add one to the existing tid so that we can see chains - * of rolling transactions in the log easily. - */ - tic->t_tid++; - - xlog_grant_push_ail(log, tic->t_unit_res); - - tic->t_curr_res = tic->t_unit_res; - xlog_tic_reset_res(tic); - - if (tic->t_cnt > 0) - return 0; - - trace_xfs_log_regrant(log, tic); - - error = xlog_grant_head_check(log, &log->l_write_head, tic, - &need_bytes); - if (error) - goto out_error; - - xlog_grant_add_space(log, &log->l_write_head.grant, need_bytes); - trace_xfs_log_regrant_exit(log, tic); - xlog_verify_grant_tail(log); - return 0; - -out_error: - /* - * If we are failing, make sure the ticket doesn't have any current - * reservations. We don't want to add this back when the ticket/ - * transaction gets cancelled. - */ - tic->t_curr_res = 0; - tic->t_cnt = 0; /* ungrant will give back unit_res * t_cnt. */ - return error; -} - -/* - * Reserve log space and return a ticket corresponding the reservation. - * - * Each reservation is going to reserve extra space for a log record header. - * When writes happen to the on-disk log, we don't subtract the length of the - * log record header from any reservation. By wasting space in each - * reservation, we prevent over allocation problems. - */ -int -xfs_log_reserve( - struct xfs_mount *mp, - int unit_bytes, - int cnt, - struct xlog_ticket **ticp, - __uint8_t client, - bool permanent) -{ - struct xlog *log = mp->m_log; - struct xlog_ticket *tic; - int need_bytes; - int error = 0; - - ASSERT(client == XFS_TRANSACTION || client == XFS_LOG); - - if (XLOG_FORCED_SHUTDOWN(log)) - return -EIO; - - XFS_STATS_INC(mp, xs_try_logspace); - - ASSERT(*ticp == NULL); - tic = xlog_ticket_alloc(log, unit_bytes, cnt, client, permanent, - KM_SLEEP | KM_MAYFAIL); - if (!tic) - return -ENOMEM; - - *ticp = tic; - - xlog_grant_push_ail(log, tic->t_cnt ? tic->t_unit_res * tic->t_cnt - : tic->t_unit_res); - - trace_xfs_log_reserve(log, tic); - - error = xlog_grant_head_check(log, &log->l_reserve_head, tic, - &need_bytes); - if (error) - goto out_error; - - xlog_grant_add_space(log, &log->l_reserve_head.grant, need_bytes); - xlog_grant_add_space(log, &log->l_write_head.grant, need_bytes); - trace_xfs_log_reserve_exit(log, tic); - xlog_verify_grant_tail(log); - return 0; - -out_error: - /* - * If we are failing, make sure the ticket doesn't have any current - * reservations. We don't want to add this back when the ticket/ - * transaction gets cancelled. - */ - tic->t_curr_res = 0; - tic->t_cnt = 0; /* ungrant will give back unit_res * t_cnt. */ - return error; -} - - -/* - * NOTES: - * - * 1. currblock field gets updated at startup and after in-core logs - * marked as with WANT_SYNC. - */ - -/* - * This routine is called when a user of a log manager ticket is done with - * the reservation. If the ticket was ever used, then a commit record for - * the associated transaction is written out as a log operation header with - * no data. The flag XLOG_TIC_INITED is set when the first write occurs with - * a given ticket. If the ticket was one with a permanent reservation, then - * a few operations are done differently. Permanent reservation tickets by - * default don't release the reservation. They just commit the current - * transaction with the belief that the reservation is still needed. A flag - * must be passed in before permanent reservations are actually released. - * When these type of tickets are not released, they need to be set into - * the inited state again. By doing this, a start record will be written - * out when the next write occurs. - */ -xfs_lsn_t -xfs_log_done( - struct xfs_mount *mp, - struct xlog_ticket *ticket, - struct xlog_in_core **iclog, - bool regrant) -{ - struct xlog *log = mp->m_log; - xfs_lsn_t lsn = 0; - - if (XLOG_FORCED_SHUTDOWN(log) || - /* - * If nothing was ever written, don't write out commit record. - * If we get an error, just continue and give back the log ticket. - */ - (((ticket->t_flags & XLOG_TIC_INITED) == 0) && - (xlog_commit_record(log, ticket, iclog, &lsn)))) { - lsn = (xfs_lsn_t) -1; - regrant = false; - } - - - if (!regrant) { - trace_xfs_log_done_nonperm(log, ticket); - - /* - * Release ticket if not permanent reservation or a specific - * request has been made to release a permanent reservation. - */ - xlog_ungrant_log_space(log, ticket); - } else { - trace_xfs_log_done_perm(log, ticket); - - xlog_regrant_reserve_log_space(log, ticket); - /* If this ticket was a permanent reservation and we aren't - * trying to release it, reset the inited flags; so next time - * we write, a start record will be written out. - */ - ticket->t_flags |= XLOG_TIC_INITED; - } - - xfs_log_ticket_put(ticket); - return lsn; -} - -/* - * Attaches a new iclog I/O completion callback routine during - * transaction commit. If the log is in error state, a non-zero - * return code is handed back and the caller is responsible for - * executing the callback at an appropriate time. - */ -int -xfs_log_notify( - struct xfs_mount *mp, - struct xlog_in_core *iclog, - xfs_log_callback_t *cb) -{ - int abortflg; - - spin_lock(&iclog->ic_callback_lock); - abortflg = (iclog->ic_state & XLOG_STATE_IOERROR); - if (!abortflg) { - ASSERT_ALWAYS((iclog->ic_state == XLOG_STATE_ACTIVE) || - (iclog->ic_state == XLOG_STATE_WANT_SYNC)); - cb->cb_next = NULL; - *(iclog->ic_callback_tail) = cb; - iclog->ic_callback_tail = &(cb->cb_next); - } - spin_unlock(&iclog->ic_callback_lock); - return abortflg; -} - -int -xfs_log_release_iclog( - struct xfs_mount *mp, - struct xlog_in_core *iclog) -{ - if (xlog_state_release_iclog(mp->m_log, iclog)) { - xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR); - return -EIO; - } - - return 0; -} - -/* - * Mount a log filesystem - * - * mp - ubiquitous xfs mount point structure - * log_target - buftarg of on-disk log device - * blk_offset - Start block # where block size is 512 bytes (BBSIZE) - * num_bblocks - Number of BBSIZE blocks in on-disk log - * - * Return error or zero. - */ -int -xfs_log_mount( - xfs_mount_t *mp, - xfs_buftarg_t *log_target, - xfs_daddr_t blk_offset, - int num_bblks) -{ - int error = 0; - int min_logfsbs; - - if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) { - xfs_notice(mp, "Mounting V%d Filesystem", - XFS_SB_VERSION_NUM(&mp->m_sb)); - } else { - xfs_notice(mp, -"Mounting V%d filesystem in no-recovery mode. Filesystem will be inconsistent.", - XFS_SB_VERSION_NUM(&mp->m_sb)); - ASSERT(mp->m_flags & XFS_MOUNT_RDONLY); - } - - mp->m_log = xlog_alloc_log(mp, log_target, blk_offset, num_bblks); - if (IS_ERR(mp->m_log)) { - error = PTR_ERR(mp->m_log); - goto out; - } - - /* - * Validate the given log space and drop a critical message via syslog - * if the log size is too small that would lead to some unexpected - * situations in transaction log space reservation stage. - * - * Note: we can't just reject the mount if the validation fails. This - * would mean that people would have to downgrade their kernel just to - * remedy the situation as there is no way to grow the log (short of - * black magic surgery with xfs_db). - * - * We can, however, reject mounts for CRC format filesystems, as the - * mkfs binary being used to make the filesystem should never create a - * filesystem with a log that is too small. - */ - min_logfsbs = xfs_log_calc_minimum_size(mp); - - if (mp->m_sb.sb_logblocks < min_logfsbs) { - xfs_warn(mp, - "Log size %d blocks too small, minimum size is %d blocks", - mp->m_sb.sb_logblocks, min_logfsbs); - error = -EINVAL; - } else if (mp->m_sb.sb_logblocks > XFS_MAX_LOG_BLOCKS) { - xfs_warn(mp, - "Log size %d blocks too large, maximum size is %lld blocks", - mp->m_sb.sb_logblocks, XFS_MAX_LOG_BLOCKS); - error = -EINVAL; - } else if (XFS_FSB_TO_B(mp, mp->m_sb.sb_logblocks) > XFS_MAX_LOG_BYTES) { - xfs_warn(mp, - "log size %lld bytes too large, maximum size is %lld bytes", - XFS_FSB_TO_B(mp, mp->m_sb.sb_logblocks), - XFS_MAX_LOG_BYTES); - error = -EINVAL; - } - if (error) { - if (xfs_sb_version_hascrc(&mp->m_sb)) { - xfs_crit(mp, "AAIEEE! Log failed size checks. Abort!"); - ASSERT(0); - goto out_free_log; - } - xfs_crit(mp, "Log size out of supported range."); - xfs_crit(mp, -"Continuing onwards, but if log hangs are experienced then please report this message in the bug report."); - } - - /* - * Initialize the AIL now we have a log. - */ - error = xfs_trans_ail_init(mp); - if (error) { - xfs_warn(mp, "AIL initialisation failed: error %d", error); - goto out_free_log; - } - mp->m_log->l_ailp = mp->m_ail; - - /* - * skip log recovery on a norecovery mount. pretend it all - * just worked. - */ - if (!(mp->m_flags & XFS_MOUNT_NORECOVERY)) { - int readonly = (mp->m_flags & XFS_MOUNT_RDONLY); - - if (readonly) - mp->m_flags &= ~XFS_MOUNT_RDONLY; - - error = xlog_recover(mp->m_log); - - if (readonly) - mp->m_flags |= XFS_MOUNT_RDONLY; - if (error) { - xfs_warn(mp, "log mount/recovery failed: error %d", - error); - xlog_recover_cancel(mp->m_log); - goto out_destroy_ail; - } - } - - error = xfs_sysfs_init(&mp->m_log->l_kobj, &xfs_log_ktype, &mp->m_kobj, - "log"); - if (error) - goto out_destroy_ail; - - /* Normal transactions can now occur */ - mp->m_log->l_flags &= ~XLOG_ACTIVE_RECOVERY; - - /* - * Now the log has been fully initialised and we know were our - * space grant counters are, we can initialise the permanent ticket - * needed for delayed logging to work. - */ - xlog_cil_init_post_recovery(mp->m_log); - - return 0; - -out_destroy_ail: - xfs_trans_ail_destroy(mp); -out_free_log: - xlog_dealloc_log(mp->m_log); -out: - return error; -} - -/* - * Finish the recovery of the file system. This is separate from the - * xfs_log_mount() call, because it depends on the code in xfs_mountfs() to read - * in the root and real-time bitmap inodes between calling xfs_log_mount() and - * here. - * - * If we finish recovery successfully, start the background log work. If we are - * not doing recovery, then we have a RO filesystem and we don't need to start - * it. - */ -int -xfs_log_mount_finish( - struct xfs_mount *mp) -{ - int error = 0; - - if (mp->m_flags & XFS_MOUNT_NORECOVERY) { - ASSERT(mp->m_flags & XFS_MOUNT_RDONLY); - return 0; - } - - error = xlog_recover_finish(mp->m_log); - if (!error) - xfs_log_work_queue(mp); - - return error; -} - -/* - * The mount has failed. Cancel the recovery if it hasn't completed and destroy - * the log. - */ -int -xfs_log_mount_cancel( - struct xfs_mount *mp) -{ - int error; - - error = xlog_recover_cancel(mp->m_log); - xfs_log_unmount(mp); - - return error; -} - -/* - * Final log writes as part of unmount. - * - * Mark the filesystem clean as unmount happens. Note that during relocation - * this routine needs to be executed as part of source-bag while the - * deallocation must not be done until source-end. - */ - -/* - * Unmount record used to have a string "Unmount filesystem--" in the - * data section where the "Un" was really a magic number (XLOG_UNMOUNT_TYPE). - * We just write the magic number now since that particular field isn't - * currently architecture converted and "Unmount" is a bit foo. - * As far as I know, there weren't any dependencies on the old behaviour. - */ - -static int -xfs_log_unmount_write(xfs_mount_t *mp) -{ - struct xlog *log = mp->m_log; - xlog_in_core_t *iclog; -#ifdef DEBUG - xlog_in_core_t *first_iclog; -#endif - xlog_ticket_t *tic = NULL; - xfs_lsn_t lsn; - int error; - - /* - * Don't write out unmount record on read-only mounts. - * Or, if we are doing a forced umount (typically because of IO errors). - */ - if (mp->m_flags & XFS_MOUNT_RDONLY) - return 0; - - error = _xfs_log_force(mp, XFS_LOG_SYNC, NULL); - ASSERT(error || !(XLOG_FORCED_SHUTDOWN(log))); - -#ifdef DEBUG - first_iclog = iclog = log->l_iclog; - do { - if (!(iclog->ic_state & XLOG_STATE_IOERROR)) { - ASSERT(iclog->ic_state & XLOG_STATE_ACTIVE); - ASSERT(iclog->ic_offset == 0); - } - iclog = iclog->ic_next; - } while (iclog != first_iclog); -#endif - if (! (XLOG_FORCED_SHUTDOWN(log))) { - error = xfs_log_reserve(mp, 600, 1, &tic, XFS_LOG, 0); - if (!error) { - /* the data section must be 32 bit size aligned */ - struct { - __uint16_t magic; - __uint16_t pad1; - __uint32_t pad2; /* may as well make it 64 bits */ - } magic = { - .magic = XLOG_UNMOUNT_TYPE, - }; - struct xfs_log_iovec reg = { - .i_addr = &magic, - .i_len = sizeof(magic), - .i_type = XLOG_REG_TYPE_UNMOUNT, - }; - struct xfs_log_vec vec = { - .lv_niovecs = 1, - .lv_iovecp = ®, - }; - - /* remove inited flag, and account for space used */ - tic->t_flags = 0; - tic->t_curr_res -= sizeof(magic); - error = xlog_write(log, &vec, tic, &lsn, - NULL, XLOG_UNMOUNT_TRANS); - /* - * At this point, we're umounting anyway, - * so there's no point in transitioning log state - * to IOERROR. Just continue... - */ - } - - if (error) - xfs_alert(mp, "%s: unmount record failed", __func__); - - - spin_lock(&log->l_icloglock); - iclog = log->l_iclog; - atomic_inc(&iclog->ic_refcnt); - xlog_state_want_sync(log, iclog); - spin_unlock(&log->l_icloglock); - error = xlog_state_release_iclog(log, iclog); - - spin_lock(&log->l_icloglock); - if (!(iclog->ic_state == XLOG_STATE_ACTIVE || - iclog->ic_state == XLOG_STATE_DIRTY)) { - if (!XLOG_FORCED_SHUTDOWN(log)) { - xlog_wait(&iclog->ic_force_wait, - &log->l_icloglock); - } else { - spin_unlock(&log->l_icloglock); - } - } else { - spin_unlock(&log->l_icloglock); - } - if (tic) { - trace_xfs_log_umount_write(log, tic); - xlog_ungrant_log_space(log, tic); - xfs_log_ticket_put(tic); - } - } else { - /* - * We're already in forced_shutdown mode, couldn't - * even attempt to write out the unmount transaction. - * - * Go through the motions of sync'ing and releasing - * the iclog, even though no I/O will actually happen, - * we need to wait for other log I/Os that may already - * be in progress. Do this as a separate section of - * code so we'll know if we ever get stuck here that - * we're in this odd situation of trying to unmount - * a file system that went into forced_shutdown as - * the result of an unmount.. - */ - spin_lock(&log->l_icloglock); - iclog = log->l_iclog; - atomic_inc(&iclog->ic_refcnt); - - xlog_state_want_sync(log, iclog); - spin_unlock(&log->l_icloglock); - error = xlog_state_release_iclog(log, iclog); - - spin_lock(&log->l_icloglock); - - if ( ! ( iclog->ic_state == XLOG_STATE_ACTIVE - || iclog->ic_state == XLOG_STATE_DIRTY - || iclog->ic_state == XLOG_STATE_IOERROR) ) { - - xlog_wait(&iclog->ic_force_wait, - &log->l_icloglock); - } else { - spin_unlock(&log->l_icloglock); - } - } - - return error; -} /* xfs_log_unmount_write */ - -/* - * Empty the log for unmount/freeze. - * - * To do this, we first need to shut down the background log work so it is not - * trying to cover the log as we clean up. We then need to unpin all objects in - * the log so we can then flush them out. Once they have completed their IO and - * run the callbacks removing themselves from the AIL, we can write the unmount - * record. - */ -void -xfs_log_quiesce( - struct xfs_mount *mp) -{ - cancel_delayed_work_sync(&mp->m_log->l_work); - xfs_log_force(mp, XFS_LOG_SYNC); - - /* - * The superblock buffer is uncached and while xfs_ail_push_all_sync() - * will push it, xfs_wait_buftarg() will not wait for it. Further, - * xfs_buf_iowait() cannot be used because it was pushed with the - * XBF_ASYNC flag set, so we need to use a lock/unlock pair to wait for - * the IO to complete. - */ - xfs_ail_push_all_sync(mp->m_ail); - xfs_wait_buftarg(mp->m_ddev_targp); - xfs_buf_lock(mp->m_sb_bp); - xfs_buf_unlock(mp->m_sb_bp); - - xfs_log_unmount_write(mp); -} - -/* - * Shut down and release the AIL and Log. - * - * During unmount, we need to ensure we flush all the dirty metadata objects - * from the AIL so that the log is empty before we write the unmount record to - * the log. Once this is done, we can tear down the AIL and the log. - */ -void -xfs_log_unmount( - struct xfs_mount *mp) -{ - xfs_log_quiesce(mp); - - xfs_trans_ail_destroy(mp); - - xfs_sysfs_del(&mp->m_log->l_kobj); - - xlog_dealloc_log(mp->m_log); -} - -void -xfs_log_item_init( - struct xfs_mount *mp, - struct xfs_log_item *item, - int type, - const struct xfs_item_ops *ops) -{ - item->li_mountp = mp; - item->li_ailp = mp->m_ail; - item->li_type = type; - item->li_ops = ops; - item->li_lv = NULL; - - INIT_LIST_HEAD(&item->li_ail); - INIT_LIST_HEAD(&item->li_cil); -} - -/* - * Wake up processes waiting for log space after we have moved the log tail. - */ -void -xfs_log_space_wake( - struct xfs_mount *mp) -{ - struct xlog *log = mp->m_log; - int free_bytes; - - if (XLOG_FORCED_SHUTDOWN(log)) - return; - - if (!list_empty_careful(&log->l_write_head.waiters)) { - ASSERT(!(log->l_flags & XLOG_ACTIVE_RECOVERY)); - - spin_lock(&log->l_write_head.lock); - free_bytes = xlog_space_left(log, &log->l_write_head.grant); - xlog_grant_head_wake(log, &log->l_write_head, &free_bytes); - spin_unlock(&log->l_write_head.lock); - } - - if (!list_empty_careful(&log->l_reserve_head.waiters)) { - ASSERT(!(log->l_flags & XLOG_ACTIVE_RECOVERY)); - - spin_lock(&log->l_reserve_head.lock); - free_bytes = xlog_space_left(log, &log->l_reserve_head.grant); - xlog_grant_head_wake(log, &log->l_reserve_head, &free_bytes); - spin_unlock(&log->l_reserve_head.lock); - } -} - -/* - * Determine if we have a transaction that has gone to disk that needs to be - * covered. To begin the transition to the idle state firstly the log needs to - * be idle. That means the CIL, the AIL and the iclogs needs to be empty before - * we start attempting to cover the log. - * - * Only if we are then in a state where covering is needed, the caller is - * informed that dummy transactions are required to move the log into the idle - * state. - * - * If there are any items in the AIl or CIL, then we do not want to attempt to - * cover the log as we may be in a situation where there isn't log space - * available to run a dummy transaction and this can lead to deadlocks when the - * tail of the log is pinned by an item that is modified in the CIL. Hence - * there's no point in running a dummy transaction at this point because we - * can't start trying to idle the log until both the CIL and AIL are empty. - */ -static int -xfs_log_need_covered(xfs_mount_t *mp) -{ - struct xlog *log = mp->m_log; - int needed = 0; - - if (!xfs_fs_writable(mp, SB_FREEZE_WRITE)) - return 0; - - if (!xlog_cil_empty(log)) - return 0; - - spin_lock(&log->l_icloglock); - switch (log->l_covered_state) { - case XLOG_STATE_COVER_DONE: - case XLOG_STATE_COVER_DONE2: - case XLOG_STATE_COVER_IDLE: - break; - case XLOG_STATE_COVER_NEED: - case XLOG_STATE_COVER_NEED2: - if (xfs_ail_min_lsn(log->l_ailp)) - break; - if (!xlog_iclogs_empty(log)) - break; - - needed = 1; - if (log->l_covered_state == XLOG_STATE_COVER_NEED) - log->l_covered_state = XLOG_STATE_COVER_DONE; - else - log->l_covered_state = XLOG_STATE_COVER_DONE2; - break; - default: - needed = 1; - break; - } - spin_unlock(&log->l_icloglock); - return needed; -} - -/* - * We may be holding the log iclog lock upon entering this routine. - */ -xfs_lsn_t -xlog_assign_tail_lsn_locked( - struct xfs_mount *mp) -{ - struct xlog *log = mp->m_log; - struct xfs_log_item *lip; - xfs_lsn_t tail_lsn; - - assert_spin_locked(&mp->m_ail->xa_lock); - - /* - * To make sure we always have a valid LSN for the log tail we keep - * track of the last LSN which was committed in log->l_last_sync_lsn, - * and use that when the AIL was empty. - */ - lip = xfs_ail_min(mp->m_ail); - if (lip) - tail_lsn = lip->li_lsn; - else - tail_lsn = atomic64_read(&log->l_last_sync_lsn); - trace_xfs_log_assign_tail_lsn(log, tail_lsn); - atomic64_set(&log->l_tail_lsn, tail_lsn); - return tail_lsn; -} - -xfs_lsn_t -xlog_assign_tail_lsn( - struct xfs_mount *mp) -{ - xfs_lsn_t tail_lsn; - - spin_lock(&mp->m_ail->xa_lock); - tail_lsn = xlog_assign_tail_lsn_locked(mp); - spin_unlock(&mp->m_ail->xa_lock); - - return tail_lsn; -} - -/* - * Return the space in the log between the tail and the head. The head - * is passed in the cycle/bytes formal parms. In the special case where - * the reserve head has wrapped passed the tail, this calculation is no - * longer valid. In this case, just return 0 which means there is no space - * in the log. This works for all places where this function is called - * with the reserve head. Of course, if the write head were to ever - * wrap the tail, we should blow up. Rather than catch this case here, - * we depend on other ASSERTions in other parts of the code. XXXmiken - * - * This code also handles the case where the reservation head is behind - * the tail. The details of this case are described below, but the end - * result is that we return the size of the log as the amount of space left. - */ -STATIC int -xlog_space_left( - struct xlog *log, - atomic64_t *head) -{ - int free_bytes; - int tail_bytes; - int tail_cycle; - int head_cycle; - int head_bytes; - - xlog_crack_grant_head(head, &head_cycle, &head_bytes); - xlog_crack_atomic_lsn(&log->l_tail_lsn, &tail_cycle, &tail_bytes); - tail_bytes = BBTOB(tail_bytes); - if (tail_cycle == head_cycle && head_bytes >= tail_bytes) - free_bytes = log->l_logsize - (head_bytes - tail_bytes); - else if (tail_cycle + 1 < head_cycle) - return 0; - else if (tail_cycle < head_cycle) { - ASSERT(tail_cycle == (head_cycle - 1)); - free_bytes = tail_bytes - head_bytes; - } else { - /* - * The reservation head is behind the tail. - * In this case we just want to return the size of the - * log as the amount of space left. - */ - xfs_alert(log->l_mp, "xlog_space_left: head behind tail"); - xfs_alert(log->l_mp, - " tail_cycle = %d, tail_bytes = %d", - tail_cycle, tail_bytes); - xfs_alert(log->l_mp, - " GH cycle = %d, GH bytes = %d", - head_cycle, head_bytes); - ASSERT(0); - free_bytes = log->l_logsize; - } - return free_bytes; -} - - -/* - * Log function which is called when an io completes. - * - * The log manager needs its own routine, in order to control what - * happens with the buffer after the write completes. - */ -static void -xlog_iodone(xfs_buf_t *bp) -{ - struct xlog_in_core *iclog = bp->b_fspriv; - struct xlog *l = iclog->ic_log; - int aborted = 0; - - /* - * Race to shutdown the filesystem if we see an error or the iclog is in - * IOABORT state. The IOABORT state is only set in DEBUG mode to inject - * CRC errors into log recovery. - */ - if (XFS_TEST_ERROR(bp->b_error, l->l_mp, XFS_ERRTAG_IODONE_IOERR, - XFS_RANDOM_IODONE_IOERR) || - iclog->ic_state & XLOG_STATE_IOABORT) { - if (iclog->ic_state & XLOG_STATE_IOABORT) - iclog->ic_state &= ~XLOG_STATE_IOABORT; - - xfs_buf_ioerror_alert(bp, __func__); - xfs_buf_stale(bp); - xfs_force_shutdown(l->l_mp, SHUTDOWN_LOG_IO_ERROR); - /* - * This flag will be propagated to the trans-committed - * callback routines to let them know that the log-commit - * didn't succeed. - */ - aborted = XFS_LI_ABORTED; - } else if (iclog->ic_state & XLOG_STATE_IOERROR) { - aborted = XFS_LI_ABORTED; - } - - /* log I/O is always issued ASYNC */ - ASSERT(bp->b_flags & XBF_ASYNC); - xlog_state_done_syncing(iclog, aborted); - - /* - * drop the buffer lock now that we are done. Nothing references - * the buffer after this, so an unmount waiting on this lock can now - * tear it down safely. As such, it is unsafe to reference the buffer - * (bp) after the unlock as we could race with it being freed. - */ - xfs_buf_unlock(bp); -} - -/* - * Return size of each in-core log record buffer. - * - * All machines get 8 x 32kB buffers by default, unless tuned otherwise. - * - * If the filesystem blocksize is too large, we may need to choose a - * larger size since the directory code currently logs entire blocks. - */ - -STATIC void -xlog_get_iclog_buffer_size( - struct xfs_mount *mp, - struct xlog *log) -{ - int size; - int xhdrs; - - if (mp->m_logbufs <= 0) - log->l_iclog_bufs = XLOG_MAX_ICLOGS; - else - log->l_iclog_bufs = mp->m_logbufs; - - /* - * Buffer size passed in from mount system call. - */ - if (mp->m_logbsize > 0) { - size = log->l_iclog_size = mp->m_logbsize; - log->l_iclog_size_log = 0; - while (size != 1) { - log->l_iclog_size_log++; - size >>= 1; - } - - if (xfs_sb_version_haslogv2(&mp->m_sb)) { - /* # headers = size / 32k - * one header holds cycles from 32k of data - */ - - xhdrs = mp->m_logbsize / XLOG_HEADER_CYCLE_SIZE; - if (mp->m_logbsize % XLOG_HEADER_CYCLE_SIZE) - xhdrs++; - log->l_iclog_hsize = xhdrs << BBSHIFT; - log->l_iclog_heads = xhdrs; - } else { - ASSERT(mp->m_logbsize <= XLOG_BIG_RECORD_BSIZE); - log->l_iclog_hsize = BBSIZE; - log->l_iclog_heads = 1; - } - goto done; - } - - /* All machines use 32kB buffers by default. */ - log->l_iclog_size = XLOG_BIG_RECORD_BSIZE; - log->l_iclog_size_log = XLOG_BIG_RECORD_BSHIFT; - - /* the default log size is 16k or 32k which is one header sector */ - log->l_iclog_hsize = BBSIZE; - log->l_iclog_heads = 1; - -done: - /* are we being asked to make the sizes selected above visible? */ - if (mp->m_logbufs == 0) - mp->m_logbufs = log->l_iclog_bufs; - if (mp->m_logbsize == 0) - mp->m_logbsize = log->l_iclog_size; -} /* xlog_get_iclog_buffer_size */ - - -void -xfs_log_work_queue( - struct xfs_mount *mp) -{ - queue_delayed_work(mp->m_log_workqueue, &mp->m_log->l_work, - msecs_to_jiffies(xfs_syncd_centisecs * 10)); -} - -/* - * Every sync period we need to unpin all items in the AIL and push them to - * disk. If there is nothing dirty, then we might need to cover the log to - * indicate that the filesystem is idle. - */ -static void -xfs_log_worker( - struct work_struct *work) -{ - struct xlog *log = container_of(to_delayed_work(work), - struct xlog, l_work); - struct xfs_mount *mp = log->l_mp; - - /* dgc: errors ignored - not fatal and nowhere to report them */ - if (xfs_log_need_covered(mp)) { - /* - * Dump a transaction into the log that contains no real change. - * This is needed to stamp the current tail LSN into the log - * during the covering operation. - * - * We cannot use an inode here for this - that will push dirty - * state back up into the VFS and then periodic inode flushing - * will prevent log covering from making progress. Hence we - * synchronously log the superblock instead to ensure the - * superblock is immediately unpinned and can be written back. - */ - xfs_sync_sb(mp, true); - } else - xfs_log_force(mp, 0); - - /* start pushing all the metadata that is currently dirty */ - xfs_ail_push_all(mp->m_ail); - - /* queue us up again */ - xfs_log_work_queue(mp); -} - -/* - * This routine initializes some of the log structure for a given mount point. - * Its primary purpose is to fill in enough, so recovery can occur. However, - * some other stuff may be filled in too. - */ -STATIC struct xlog * -xlog_alloc_log( - struct xfs_mount *mp, - struct xfs_buftarg *log_target, - xfs_daddr_t blk_offset, - int num_bblks) -{ - struct xlog *log; - xlog_rec_header_t *head; - xlog_in_core_t **iclogp; - xlog_in_core_t *iclog, *prev_iclog=NULL; - xfs_buf_t *bp; - int i; - int error = -ENOMEM; - uint log2_size = 0; - - log = kmem_zalloc(sizeof(struct xlog), KM_MAYFAIL); - if (!log) { - xfs_warn(mp, "Log allocation failed: No memory!"); - goto out; - } - - log->l_mp = mp; - log->l_targ = log_target; - log->l_logsize = BBTOB(num_bblks); - log->l_logBBstart = blk_offset; - log->l_logBBsize = num_bblks; - log->l_covered_state = XLOG_STATE_COVER_IDLE; - log->l_flags |= XLOG_ACTIVE_RECOVERY; - INIT_DELAYED_WORK(&log->l_work, xfs_log_worker); - - log->l_prev_block = -1; - /* log->l_tail_lsn = 0x100000000LL; cycle = 1; current block = 0 */ - xlog_assign_atomic_lsn(&log->l_tail_lsn, 1, 0); - xlog_assign_atomic_lsn(&log->l_last_sync_lsn, 1, 0); - log->l_curr_cycle = 1; /* 0 is bad since this is initial value */ - - xlog_grant_head_init(&log->l_reserve_head); - xlog_grant_head_init(&log->l_write_head); - - error = -EFSCORRUPTED; - if (xfs_sb_version_hassector(&mp->m_sb)) { - log2_size = mp->m_sb.sb_logsectlog; - if (log2_size < BBSHIFT) { - xfs_warn(mp, "Log sector size too small (0x%x < 0x%x)", - log2_size, BBSHIFT); - goto out_free_log; - } - - log2_size -= BBSHIFT; - if (log2_size > mp->m_sectbb_log) { - xfs_warn(mp, "Log sector size too large (0x%x > 0x%x)", - log2_size, mp->m_sectbb_log); - goto out_free_log; - } - - /* for larger sector sizes, must have v2 or external log */ - if (log2_size && log->l_logBBstart > 0 && - !xfs_sb_version_haslogv2(&mp->m_sb)) { - xfs_warn(mp, - "log sector size (0x%x) invalid for configuration.", - log2_size); - goto out_free_log; - } - } - log->l_sectBBsize = 1 << log2_size; - - xlog_get_iclog_buffer_size(mp, log); - - /* - * Use a NULL block for the extra log buffer used during splits so that - * it will trigger errors if we ever try to do IO on it without first - * having set it up properly. - */ - error = -ENOMEM; - bp = xfs_buf_alloc(mp->m_logdev_targp, XFS_BUF_DADDR_NULL, - BTOBB(log->l_iclog_size), XBF_NO_IOACCT); - if (!bp) - goto out_free_log; - - /* - * The iclogbuf buffer locks are held over IO but we are not going to do - * IO yet. Hence unlock the buffer so that the log IO path can grab it - * when appropriately. - */ - ASSERT(xfs_buf_islocked(bp)); - xfs_buf_unlock(bp); - - /* use high priority wq for log I/O completion */ - bp->b_ioend_wq = mp->m_log_workqueue; - bp->b_iodone = xlog_iodone; - log->l_xbuf = bp; - - spin_lock_init(&log->l_icloglock); - init_waitqueue_head(&log->l_flush_wait); - - iclogp = &log->l_iclog; - /* - * The amount of memory to allocate for the iclog structure is - * rather funky due to the way the structure is defined. It is - * done this way so that we can use different sizes for machines - * with different amounts of memory. See the definition of - * xlog_in_core_t in xfs_log_priv.h for details. - */ - ASSERT(log->l_iclog_size >= 4096); - for (i=0; i < log->l_iclog_bufs; i++) { - *iclogp = kmem_zalloc(sizeof(xlog_in_core_t), KM_MAYFAIL); - if (!*iclogp) - goto out_free_iclog; - - iclog = *iclogp; - iclog->ic_prev = prev_iclog; - prev_iclog = iclog; - - bp = xfs_buf_get_uncached(mp->m_logdev_targp, - BTOBB(log->l_iclog_size), - XBF_NO_IOACCT); - if (!bp) - goto out_free_iclog; - - ASSERT(xfs_buf_islocked(bp)); - xfs_buf_unlock(bp); - - /* use high priority wq for log I/O completion */ - bp->b_ioend_wq = mp->m_log_workqueue; - bp->b_iodone = xlog_iodone; - iclog->ic_bp = bp; - iclog->ic_data = bp->b_addr; -#ifdef DEBUG - log->l_iclog_bak[i] = &iclog->ic_header; -#endif - head = &iclog->ic_header; - memset(head, 0, sizeof(xlog_rec_header_t)); - head->h_magicno = cpu_to_be32(XLOG_HEADER_MAGIC_NUM); - head->h_version = cpu_to_be32( - xfs_sb_version_haslogv2(&log->l_mp->m_sb) ? 2 : 1); - head->h_size = cpu_to_be32(log->l_iclog_size); - /* new fields */ - head->h_fmt = cpu_to_be32(XLOG_FMT); - memcpy(&head->h_fs_uuid, &mp->m_sb.sb_uuid, sizeof(uuid_t)); - - iclog->ic_size = BBTOB(bp->b_length) - log->l_iclog_hsize; - iclog->ic_state = XLOG_STATE_ACTIVE; - iclog->ic_log = log; - atomic_set(&iclog->ic_refcnt, 0); - spin_lock_init(&iclog->ic_callback_lock); - iclog->ic_callback_tail = &(iclog->ic_callback); - iclog->ic_datap = (char *)iclog->ic_data + log->l_iclog_hsize; - - init_waitqueue_head(&iclog->ic_force_wait); - init_waitqueue_head(&iclog->ic_write_wait); - - iclogp = &iclog->ic_next; - } - *iclogp = log->l_iclog; /* complete ring */ - log->l_iclog->ic_prev = prev_iclog; /* re-write 1st prev ptr */ - - error = xlog_cil_init(log); - if (error) - goto out_free_iclog; - return log; - -out_free_iclog: - for (iclog = log->l_iclog; iclog; iclog = prev_iclog) { - prev_iclog = iclog->ic_next; - if (iclog->ic_bp) - xfs_buf_free(iclog->ic_bp); - kmem_free(iclog); - } - spinlock_destroy(&log->l_icloglock); - xfs_buf_free(log->l_xbuf); -out_free_log: - kmem_free(log); -out: - return ERR_PTR(error); -} /* xlog_alloc_log */ - - -/* - * Write out the commit record of a transaction associated with the given - * ticket. Return the lsn of the commit record. - */ -STATIC int -xlog_commit_record( - struct xlog *log, - struct xlog_ticket *ticket, - struct xlog_in_core **iclog, - xfs_lsn_t *commitlsnp) -{ - struct xfs_mount *mp = log->l_mp; - int error; - struct xfs_log_iovec reg = { - .i_addr = NULL, - .i_len = 0, - .i_type = XLOG_REG_TYPE_COMMIT, - }; - struct xfs_log_vec vec = { - .lv_niovecs = 1, - .lv_iovecp = ®, - }; - - ASSERT_ALWAYS(iclog); - error = xlog_write(log, &vec, ticket, commitlsnp, iclog, - XLOG_COMMIT_TRANS); - if (error) - xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR); - return error; -} - -/* - * Push on the buffer cache code if we ever use more than 75% of the on-disk - * log space. This code pushes on the lsn which would supposedly free up - * the 25% which we want to leave free. We may need to adopt a policy which - * pushes on an lsn which is further along in the log once we reach the high - * water mark. In this manner, we would be creating a low water mark. - */ -STATIC void -xlog_grant_push_ail( - struct xlog *log, - int need_bytes) -{ - xfs_lsn_t threshold_lsn = 0; - xfs_lsn_t last_sync_lsn; - int free_blocks; - int free_bytes; - int threshold_block; - int threshold_cycle; - int free_threshold; - - ASSERT(BTOBB(need_bytes) < log->l_logBBsize); - - free_bytes = xlog_space_left(log, &log->l_reserve_head.grant); - free_blocks = BTOBBT(free_bytes); - - /* - * Set the threshold for the minimum number of free blocks in the - * log to the maximum of what the caller needs, one quarter of the - * log, and 256 blocks. - */ - free_threshold = BTOBB(need_bytes); - free_threshold = MAX(free_threshold, (log->l_logBBsize >> 2)); - free_threshold = MAX(free_threshold, 256); - if (free_blocks >= free_threshold) - return; - - xlog_crack_atomic_lsn(&log->l_tail_lsn, &threshold_cycle, - &threshold_block); - threshold_block += free_threshold; - if (threshold_block >= log->l_logBBsize) { - threshold_block -= log->l_logBBsize; - threshold_cycle += 1; - } - threshold_lsn = xlog_assign_lsn(threshold_cycle, - threshold_block); - /* - * Don't pass in an lsn greater than the lsn of the last - * log record known to be on disk. Use a snapshot of the last sync lsn - * so that it doesn't change between the compare and the set. - */ - last_sync_lsn = atomic64_read(&log->l_last_sync_lsn); - if (XFS_LSN_CMP(threshold_lsn, last_sync_lsn) > 0) - threshold_lsn = last_sync_lsn; - - /* - * Get the transaction layer to kick the dirty buffers out to - * disk asynchronously. No point in trying to do this if - * the filesystem is shutting down. - */ - if (!XLOG_FORCED_SHUTDOWN(log)) - xfs_ail_push(log->l_ailp, threshold_lsn); -} - -/* - * Stamp cycle number in every block - */ -STATIC void -xlog_pack_data( - struct xlog *log, - struct xlog_in_core *iclog, - int roundoff) -{ - int i, j, k; - int size = iclog->ic_offset + roundoff; - __be32 cycle_lsn; - char *dp; - - cycle_lsn = CYCLE_LSN_DISK(iclog->ic_header.h_lsn); - - dp = iclog->ic_datap; - for (i = 0; i < BTOBB(size); i++) { - if (i >= (XLOG_HEADER_CYCLE_SIZE / BBSIZE)) - break; - iclog->ic_header.h_cycle_data[i] = *(__be32 *)dp; - *(__be32 *)dp = cycle_lsn; - dp += BBSIZE; - } - - if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) { - xlog_in_core_2_t *xhdr = iclog->ic_data; - - for ( ; i < BTOBB(size); i++) { - j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); - k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); - xhdr[j].hic_xheader.xh_cycle_data[k] = *(__be32 *)dp; - *(__be32 *)dp = cycle_lsn; - dp += BBSIZE; - } - - for (i = 1; i < log->l_iclog_heads; i++) - xhdr[i].hic_xheader.xh_cycle = cycle_lsn; - } -} - -/* - * Calculate the checksum for a log buffer. - * - * This is a little more complicated than it should be because the various - * headers and the actual data are non-contiguous. - */ -__le32 -xlog_cksum( - struct xlog *log, - struct xlog_rec_header *rhead, - char *dp, - int size) -{ - __uint32_t crc; - - /* first generate the crc for the record header ... */ - crc = xfs_start_cksum((char *)rhead, - sizeof(struct xlog_rec_header), - offsetof(struct xlog_rec_header, h_crc)); - - /* ... then for additional cycle data for v2 logs ... */ - if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) { - union xlog_in_core2 *xhdr = (union xlog_in_core2 *)rhead; - int i; - int xheads; - - xheads = size / XLOG_HEADER_CYCLE_SIZE; - if (size % XLOG_HEADER_CYCLE_SIZE) - xheads++; - - for (i = 1; i < xheads; i++) { - crc = crc32c(crc, &xhdr[i].hic_xheader, - sizeof(struct xlog_rec_ext_header)); - } - } - - /* ... and finally for the payload */ - crc = crc32c(crc, dp, size); - - return xfs_end_cksum(crc); -} - -/* - * The bdstrat callback function for log bufs. This gives us a central - * place to trap bufs in case we get hit by a log I/O error and need to - * shutdown. Actually, in practice, even when we didn't get a log error, - * we transition the iclogs to IOERROR state *after* flushing all existing - * iclogs to disk. This is because we don't want anymore new transactions to be - * started or completed afterwards. - * - * We lock the iclogbufs here so that we can serialise against IO completion - * during unmount. We might be processing a shutdown triggered during unmount, - * and that can occur asynchronously to the unmount thread, and hence we need to - * ensure that completes before tearing down the iclogbufs. Hence we need to - * hold the buffer lock across the log IO to acheive that. - */ -STATIC int -xlog_bdstrat( - struct xfs_buf *bp) -{ - struct xlog_in_core *iclog = bp->b_fspriv; - - xfs_buf_lock(bp); - if (iclog->ic_state & XLOG_STATE_IOERROR) { - xfs_buf_ioerror(bp, -EIO); - xfs_buf_stale(bp); - xfs_buf_ioend(bp); - /* - * It would seem logical to return EIO here, but we rely on - * the log state machine to propagate I/O errors instead of - * doing it here. Similarly, IO completion will unlock the - * buffer, so we don't do it here. - */ - return 0; - } - - xfs_buf_submit(bp); - return 0; -} - -/* - * Flush out the in-core log (iclog) to the on-disk log in an asynchronous - * fashion. Previously, we should have moved the current iclog - * ptr in the log to point to the next available iclog. This allows further - * write to continue while this code syncs out an iclog ready to go. - * Before an in-core log can be written out, the data section must be scanned - * to save away the 1st word of each BBSIZE block into the header. We replace - * it with the current cycle count. Each BBSIZE block is tagged with the - * cycle count because there in an implicit assumption that drives will - * guarantee that entire 512 byte blocks get written at once. In other words, - * we can't have part of a 512 byte block written and part not written. By - * tagging each block, we will know which blocks are valid when recovering - * after an unclean shutdown. - * - * This routine is single threaded on the iclog. No other thread can be in - * this routine with the same iclog. Changing contents of iclog can there- - * fore be done without grabbing the state machine lock. Updating the global - * log will require grabbing the lock though. - * - * The entire log manager uses a logical block numbering scheme. Only - * log_sync (and then only bwrite()) know about the fact that the log may - * not start with block zero on a given device. The log block start offset - * is added immediately before calling bwrite(). - */ - -STATIC int -xlog_sync( - struct xlog *log, - struct xlog_in_core *iclog) -{ - xfs_buf_t *bp; - int i; - uint count; /* byte count of bwrite */ - uint count_init; /* initial count before roundup */ - int roundoff; /* roundoff to BB or stripe */ - int split = 0; /* split write into two regions */ - int error; - int v2 = xfs_sb_version_haslogv2(&log->l_mp->m_sb); - int size; - - XFS_STATS_INC(log->l_mp, xs_log_writes); - ASSERT(atomic_read(&iclog->ic_refcnt) == 0); - - /* Add for LR header */ - count_init = log->l_iclog_hsize + iclog->ic_offset; - - /* Round out the log write size */ - if (v2 && log->l_mp->m_sb.sb_logsunit > 1) { - /* we have a v2 stripe unit to use */ - count = XLOG_LSUNITTOB(log, XLOG_BTOLSUNIT(log, count_init)); - } else { - count = BBTOB(BTOBB(count_init)); - } - roundoff = count - count_init; - ASSERT(roundoff >= 0); - ASSERT((v2 && log->l_mp->m_sb.sb_logsunit > 1 && - roundoff < log->l_mp->m_sb.sb_logsunit) - || - (log->l_mp->m_sb.sb_logsunit <= 1 && - roundoff < BBTOB(1))); - - /* move grant heads by roundoff in sync */ - xlog_grant_add_space(log, &log->l_reserve_head.grant, roundoff); - xlog_grant_add_space(log, &log->l_write_head.grant, roundoff); - - /* put cycle number in every block */ - xlog_pack_data(log, iclog, roundoff); - - /* real byte length */ - size = iclog->ic_offset; - if (v2) - size += roundoff; - iclog->ic_header.h_len = cpu_to_be32(size); - - bp = iclog->ic_bp; - XFS_BUF_SET_ADDR(bp, BLOCK_LSN(be64_to_cpu(iclog->ic_header.h_lsn))); - - XFS_STATS_ADD(log->l_mp, xs_log_blocks, BTOBB(count)); - - /* Do we need to split this write into 2 parts? */ - if (XFS_BUF_ADDR(bp) + BTOBB(count) > log->l_logBBsize) { - char *dptr; - - split = count - (BBTOB(log->l_logBBsize - XFS_BUF_ADDR(bp))); - count = BBTOB(log->l_logBBsize - XFS_BUF_ADDR(bp)); - iclog->ic_bwritecnt = 2; - - /* - * Bump the cycle numbers at the start of each block in the - * part of the iclog that ends up in the buffer that gets - * written to the start of the log. - * - * Watch out for the header magic number case, though. - */ - dptr = (char *)&iclog->ic_header + count; - for (i = 0; i < split; i += BBSIZE) { - __uint32_t cycle = be32_to_cpu(*(__be32 *)dptr); - if (++cycle == XLOG_HEADER_MAGIC_NUM) - cycle++; - *(__be32 *)dptr = cpu_to_be32(cycle); - - dptr += BBSIZE; - } - } else { - iclog->ic_bwritecnt = 1; - } - - /* calculcate the checksum */ - iclog->ic_header.h_crc = xlog_cksum(log, &iclog->ic_header, - iclog->ic_datap, size); -#ifdef DEBUG - /* - * Intentionally corrupt the log record CRC based on the error injection - * frequency, if defined. This facilitates testing log recovery in the - * event of torn writes. Hence, set the IOABORT state to abort the log - * write on I/O completion and shutdown the fs. The subsequent mount - * detects the bad CRC and attempts to recover. - */ - if (log->l_badcrc_factor && - (prandom_u32() % log->l_badcrc_factor == 0)) { - iclog->ic_header.h_crc &= 0xAAAAAAAA; - iclog->ic_state |= XLOG_STATE_IOABORT; - xfs_warn(log->l_mp, - "Intentionally corrupted log record at LSN 0x%llx. Shutdown imminent.", - be64_to_cpu(iclog->ic_header.h_lsn)); - } -#endif - - bp->b_io_length = BTOBB(count); - bp->b_fspriv = iclog; - bp->b_flags &= ~(XBF_FUA | XBF_FLUSH); - bp->b_flags |= (XBF_ASYNC | XBF_SYNCIO | XBF_WRITE); - - if (log->l_mp->m_flags & XFS_MOUNT_BARRIER) { - bp->b_flags |= XBF_FUA; - - /* - * Flush the data device before flushing the log to make - * sure all meta data written back from the AIL actually made - * it to disk before stamping the new log tail LSN into the - * log buffer. For an external log we need to issue the - * flush explicitly, and unfortunately synchronously here; - * for an internal log we can simply use the block layer - * state machine for preflushes. - */ - if (log->l_mp->m_logdev_targp != log->l_mp->m_ddev_targp) - xfs_blkdev_issue_flush(log->l_mp->m_ddev_targp); - else - bp->b_flags |= XBF_FLUSH; - } - - ASSERT(XFS_BUF_ADDR(bp) <= log->l_logBBsize-1); - ASSERT(XFS_BUF_ADDR(bp) + BTOBB(count) <= log->l_logBBsize); - - xlog_verify_iclog(log, iclog, count, true); - - /* account for log which doesn't start at block #0 */ - XFS_BUF_SET_ADDR(bp, XFS_BUF_ADDR(bp) + log->l_logBBstart); - - /* - * Don't call xfs_bwrite here. We do log-syncs even when the filesystem - * is shutting down. - */ - error = xlog_bdstrat(bp); - if (error) { - xfs_buf_ioerror_alert(bp, "xlog_sync"); - return error; - } - if (split) { - bp = iclog->ic_log->l_xbuf; - XFS_BUF_SET_ADDR(bp, 0); /* logical 0 */ - xfs_buf_associate_memory(bp, - (char *)&iclog->ic_header + count, split); - bp->b_fspriv = iclog; - bp->b_flags &= ~(XBF_FUA | XBF_FLUSH); - bp->b_flags |= (XBF_ASYNC | XBF_SYNCIO | XBF_WRITE); - if (log->l_mp->m_flags & XFS_MOUNT_BARRIER) - bp->b_flags |= XBF_FUA; - - ASSERT(XFS_BUF_ADDR(bp) <= log->l_logBBsize-1); - ASSERT(XFS_BUF_ADDR(bp) + BTOBB(count) <= log->l_logBBsize); - - /* account for internal log which doesn't start at block #0 */ - XFS_BUF_SET_ADDR(bp, XFS_BUF_ADDR(bp) + log->l_logBBstart); - error = xlog_bdstrat(bp); - if (error) { - xfs_buf_ioerror_alert(bp, "xlog_sync (split)"); - return error; - } - } - return 0; -} /* xlog_sync */ - -/* - * Deallocate a log structure - */ -STATIC void -xlog_dealloc_log( - struct xlog *log) -{ - xlog_in_core_t *iclog, *next_iclog; - int i; - - xlog_cil_destroy(log); - - /* - * Cycle all the iclogbuf locks to make sure all log IO completion - * is done before we tear down these buffers. - */ - iclog = log->l_iclog; - for (i = 0; i < log->l_iclog_bufs; i++) { - xfs_buf_lock(iclog->ic_bp); - xfs_buf_unlock(iclog->ic_bp); - iclog = iclog->ic_next; - } - - /* - * Always need to ensure that the extra buffer does not point to memory - * owned by another log buffer before we free it. Also, cycle the lock - * first to ensure we've completed IO on it. - */ - xfs_buf_lock(log->l_xbuf); - xfs_buf_unlock(log->l_xbuf); - xfs_buf_set_empty(log->l_xbuf, BTOBB(log->l_iclog_size)); - xfs_buf_free(log->l_xbuf); - - iclog = log->l_iclog; - for (i = 0; i < log->l_iclog_bufs; i++) { - xfs_buf_free(iclog->ic_bp); - next_iclog = iclog->ic_next; - kmem_free(iclog); - iclog = next_iclog; - } - spinlock_destroy(&log->l_icloglock); - - log->l_mp->m_log = NULL; - kmem_free(log); -} /* xlog_dealloc_log */ - -/* - * Update counters atomically now that memcpy is done. - */ -/* ARGSUSED */ -static inline void -xlog_state_finish_copy( - struct xlog *log, - struct xlog_in_core *iclog, - int record_cnt, - int copy_bytes) -{ - spin_lock(&log->l_icloglock); - - be32_add_cpu(&iclog->ic_header.h_num_logops, record_cnt); - iclog->ic_offset += copy_bytes; - - spin_unlock(&log->l_icloglock); -} /* xlog_state_finish_copy */ - - - - -/* - * print out info relating to regions written which consume - * the reservation - */ -void -xlog_print_tic_res( - struct xfs_mount *mp, - struct xlog_ticket *ticket) -{ - uint i; - uint ophdr_spc = ticket->t_res_num_ophdrs * (uint)sizeof(xlog_op_header_t); - - /* match with XLOG_REG_TYPE_* in xfs_log.h */ -#define REG_TYPE_STR(type, str) [XLOG_REG_TYPE_##type] = str - static char *res_type_str[XLOG_REG_TYPE_MAX + 1] = { - REG_TYPE_STR(BFORMAT, "bformat"), - REG_TYPE_STR(BCHUNK, "bchunk"), - REG_TYPE_STR(EFI_FORMAT, "efi_format"), - REG_TYPE_STR(EFD_FORMAT, "efd_format"), - REG_TYPE_STR(IFORMAT, "iformat"), - REG_TYPE_STR(ICORE, "icore"), - REG_TYPE_STR(IEXT, "iext"), - REG_TYPE_STR(IBROOT, "ibroot"), - REG_TYPE_STR(ILOCAL, "ilocal"), - REG_TYPE_STR(IATTR_EXT, "iattr_ext"), - REG_TYPE_STR(IATTR_BROOT, "iattr_broot"), - REG_TYPE_STR(IATTR_LOCAL, "iattr_local"), - REG_TYPE_STR(QFORMAT, "qformat"), - REG_TYPE_STR(DQUOT, "dquot"), - REG_TYPE_STR(QUOTAOFF, "quotaoff"), - REG_TYPE_STR(LRHEADER, "LR header"), - REG_TYPE_STR(UNMOUNT, "unmount"), - REG_TYPE_STR(COMMIT, "commit"), - REG_TYPE_STR(TRANSHDR, "trans header"), - REG_TYPE_STR(ICREATE, "inode create") - }; -#undef REG_TYPE_STR - - xfs_warn(mp, "xlog_write: reservation summary:"); - xfs_warn(mp, " unit res = %d bytes", - ticket->t_unit_res); - xfs_warn(mp, " current res = %d bytes", - ticket->t_curr_res); - xfs_warn(mp, " total reg = %u bytes (o/flow = %u bytes)", - ticket->t_res_arr_sum, ticket->t_res_o_flow); - xfs_warn(mp, " ophdrs = %u (ophdr space = %u bytes)", - ticket->t_res_num_ophdrs, ophdr_spc); - xfs_warn(mp, " ophdr + reg = %u bytes", - ticket->t_res_arr_sum + ticket->t_res_o_flow + ophdr_spc); - xfs_warn(mp, " num regions = %u", - ticket->t_res_num); - - for (i = 0; i < ticket->t_res_num; i++) { - uint r_type = ticket->t_res_arr[i].r_type; - xfs_warn(mp, "region[%u]: %s - %u bytes", i, - ((r_type <= 0 || r_type > XLOG_REG_TYPE_MAX) ? - "bad-rtype" : res_type_str[r_type]), - ticket->t_res_arr[i].r_len); - } - - xfs_alert_tag(mp, XFS_PTAG_LOGRES, - "xlog_write: reservation ran out. Need to up reservation"); - xfs_force_shutdown(mp, SHUTDOWN_LOG_IO_ERROR); -} - -/* - * Calculate the potential space needed by the log vector. Each region gets - * its own xlog_op_header_t and may need to be double word aligned. - */ -static int -xlog_write_calc_vec_length( - struct xlog_ticket *ticket, - struct xfs_log_vec *log_vector) -{ - struct xfs_log_vec *lv; - int headers = 0; - int len = 0; - int i; - - /* acct for start rec of xact */ - if (ticket->t_flags & XLOG_TIC_INITED) - headers++; - - for (lv = log_vector; lv; lv = lv->lv_next) { - /* we don't write ordered log vectors */ - if (lv->lv_buf_len == XFS_LOG_VEC_ORDERED) - continue; - - headers += lv->lv_niovecs; - - for (i = 0; i < lv->lv_niovecs; i++) { - struct xfs_log_iovec *vecp = &lv->lv_iovecp[i]; - - len += vecp->i_len; - xlog_tic_add_region(ticket, vecp->i_len, vecp->i_type); - } - } - - ticket->t_res_num_ophdrs += headers; - len += headers * sizeof(struct xlog_op_header); - - return len; -} - -/* - * If first write for transaction, insert start record We can't be trying to - * commit if we are inited. We can't have any "partial_copy" if we are inited. - */ -static int -xlog_write_start_rec( - struct xlog_op_header *ophdr, - struct xlog_ticket *ticket) -{ - if (!(ticket->t_flags & XLOG_TIC_INITED)) - return 0; - - ophdr->oh_tid = cpu_to_be32(ticket->t_tid); - ophdr->oh_clientid = ticket->t_clientid; - ophdr->oh_len = 0; - ophdr->oh_flags = XLOG_START_TRANS; - ophdr->oh_res2 = 0; - - ticket->t_flags &= ~XLOG_TIC_INITED; - - return sizeof(struct xlog_op_header); -} - -static xlog_op_header_t * -xlog_write_setup_ophdr( - struct xlog *log, - struct xlog_op_header *ophdr, - struct xlog_ticket *ticket, - uint flags) -{ - ophdr->oh_tid = cpu_to_be32(ticket->t_tid); - ophdr->oh_clientid = ticket->t_clientid; - ophdr->oh_res2 = 0; - - /* are we copying a commit or unmount record? */ - ophdr->oh_flags = flags; - - /* - * We've seen logs corrupted with bad transaction client ids. This - * makes sure that XFS doesn't generate them on. Turn this into an EIO - * and shut down the filesystem. - */ - switch (ophdr->oh_clientid) { - case XFS_TRANSACTION: - case XFS_VOLUME: - case XFS_LOG: - break; - default: - xfs_warn(log->l_mp, - "Bad XFS transaction clientid 0x%x in ticket 0x%p", - ophdr->oh_clientid, ticket); - return NULL; - } - - return ophdr; -} - -/* - * Set up the parameters of the region copy into the log. This has - * to handle region write split across multiple log buffers - this - * state is kept external to this function so that this code can - * be written in an obvious, self documenting manner. - */ -static int -xlog_write_setup_copy( - struct xlog_ticket *ticket, - struct xlog_op_header *ophdr, - int space_available, - int space_required, - int *copy_off, - int *copy_len, - int *last_was_partial_copy, - int *bytes_consumed) -{ - int still_to_copy; - - still_to_copy = space_required - *bytes_consumed; - *copy_off = *bytes_consumed; - - if (still_to_copy <= space_available) { - /* write of region completes here */ - *copy_len = still_to_copy; - ophdr->oh_len = cpu_to_be32(*copy_len); - if (*last_was_partial_copy) - ophdr->oh_flags |= (XLOG_END_TRANS|XLOG_WAS_CONT_TRANS); - *last_was_partial_copy = 0; - *bytes_consumed = 0; - return 0; - } - - /* partial write of region, needs extra log op header reservation */ - *copy_len = space_available; - ophdr->oh_len = cpu_to_be32(*copy_len); - ophdr->oh_flags |= XLOG_CONTINUE_TRANS; - if (*last_was_partial_copy) - ophdr->oh_flags |= XLOG_WAS_CONT_TRANS; - *bytes_consumed += *copy_len; - (*last_was_partial_copy)++; - - /* account for new log op header */ - ticket->t_curr_res -= sizeof(struct xlog_op_header); - ticket->t_res_num_ophdrs++; - - return sizeof(struct xlog_op_header); -} - -static int -xlog_write_copy_finish( - struct xlog *log, - struct xlog_in_core *iclog, - uint flags, - int *record_cnt, - int *data_cnt, - int *partial_copy, - int *partial_copy_len, - int log_offset, - struct xlog_in_core **commit_iclog) -{ - if (*partial_copy) { - /* - * This iclog has already been marked WANT_SYNC by - * xlog_state_get_iclog_space. - */ - xlog_state_finish_copy(log, iclog, *record_cnt, *data_cnt); - *record_cnt = 0; - *data_cnt = 0; - return xlog_state_release_iclog(log, iclog); - } - - *partial_copy = 0; - *partial_copy_len = 0; - - if (iclog->ic_size - log_offset <= sizeof(xlog_op_header_t)) { - /* no more space in this iclog - push it. */ - xlog_state_finish_copy(log, iclog, *record_cnt, *data_cnt); - *record_cnt = 0; - *data_cnt = 0; - - spin_lock(&log->l_icloglock); - xlog_state_want_sync(log, iclog); - spin_unlock(&log->l_icloglock); - - if (!commit_iclog) - return xlog_state_release_iclog(log, iclog); - ASSERT(flags & XLOG_COMMIT_TRANS); - *commit_iclog = iclog; - } - - return 0; -} - -/* - * Write some region out to in-core log - * - * This will be called when writing externally provided regions or when - * writing out a commit record for a given transaction. - * - * General algorithm: - * 1. Find total length of this write. This may include adding to the - * lengths passed in. - * 2. Check whether we violate the tickets reservation. - * 3. While writing to this iclog - * A. Reserve as much space in this iclog as can get - * B. If this is first write, save away start lsn - * C. While writing this region: - * 1. If first write of transaction, write start record - * 2. Write log operation header (header per region) - * 3. Find out if we can fit entire region into this iclog - * 4. Potentially, verify destination memcpy ptr - * 5. Memcpy (partial) region - * 6. If partial copy, release iclog; otherwise, continue - * copying more regions into current iclog - * 4. Mark want sync bit (in simulation mode) - * 5. Release iclog for potential flush to on-disk log. - * - * ERRORS: - * 1. Panic if reservation is overrun. This should never happen since - * reservation amounts are generated internal to the filesystem. - * NOTES: - * 1. Tickets are single threaded data structures. - * 2. The XLOG_END_TRANS & XLOG_CONTINUE_TRANS flags are passed down to the - * syncing routine. When a single log_write region needs to span - * multiple in-core logs, the XLOG_CONTINUE_TRANS bit should be set - * on all log operation writes which don't contain the end of the - * region. The XLOG_END_TRANS bit is used for the in-core log - * operation which contains the end of the continued log_write region. - * 3. When xlog_state_get_iclog_space() grabs the rest of the current iclog, - * we don't really know exactly how much space will be used. As a result, - * we don't update ic_offset until the end when we know exactly how many - * bytes have been written out. - */ -int -xlog_write( - struct xlog *log, - struct xfs_log_vec *log_vector, - struct xlog_ticket *ticket, - xfs_lsn_t *start_lsn, - struct xlog_in_core **commit_iclog, - uint flags) -{ - struct xlog_in_core *iclog = NULL; - struct xfs_log_iovec *vecp; - struct xfs_log_vec *lv; - int len; - int index; - int partial_copy = 0; - int partial_copy_len = 0; - int contwr = 0; - int record_cnt = 0; - int data_cnt = 0; - int error; - - *start_lsn = 0; - - len = xlog_write_calc_vec_length(ticket, log_vector); - - /* - * Region headers and bytes are already accounted for. - * We only need to take into account start records and - * split regions in this function. - */ - if (ticket->t_flags & XLOG_TIC_INITED) - ticket->t_curr_res -= sizeof(xlog_op_header_t); - - /* - * Commit record headers need to be accounted for. These - * come in as separate writes so are easy to detect. - */ - if (flags & (XLOG_COMMIT_TRANS | XLOG_UNMOUNT_TRANS)) - ticket->t_curr_res -= sizeof(xlog_op_header_t); - - if (ticket->t_curr_res < 0) - xlog_print_tic_res(log->l_mp, ticket); - - index = 0; - lv = log_vector; - vecp = lv->lv_iovecp; - while (lv && (!lv->lv_niovecs || index < lv->lv_niovecs)) { - void *ptr; - int log_offset; - - error = xlog_state_get_iclog_space(log, len, &iclog, ticket, - &contwr, &log_offset); - if (error) - return error; - - ASSERT(log_offset <= iclog->ic_size - 1); - ptr = iclog->ic_datap + log_offset; - - /* start_lsn is the first lsn written to. That's all we need. */ - if (!*start_lsn) - *start_lsn = be64_to_cpu(iclog->ic_header.h_lsn); - - /* - * This loop writes out as many regions as can fit in the amount - * of space which was allocated by xlog_state_get_iclog_space(). - */ - while (lv && (!lv->lv_niovecs || index < lv->lv_niovecs)) { - struct xfs_log_iovec *reg; - struct xlog_op_header *ophdr; - int start_rec_copy; - int copy_len; - int copy_off; - bool ordered = false; - - /* ordered log vectors have no regions to write */ - if (lv->lv_buf_len == XFS_LOG_VEC_ORDERED) { - ASSERT(lv->lv_niovecs == 0); - ordered = true; - goto next_lv; - } - - reg = &vecp[index]; - ASSERT(reg->i_len % sizeof(__int32_t) == 0); - ASSERT((unsigned long)ptr % sizeof(__int32_t) == 0); - - start_rec_copy = xlog_write_start_rec(ptr, ticket); - if (start_rec_copy) { - record_cnt++; - xlog_write_adv_cnt(&ptr, &len, &log_offset, - start_rec_copy); - } - - ophdr = xlog_write_setup_ophdr(log, ptr, ticket, flags); - if (!ophdr) - return -EIO; - - xlog_write_adv_cnt(&ptr, &len, &log_offset, - sizeof(struct xlog_op_header)); - - len += xlog_write_setup_copy(ticket, ophdr, - iclog->ic_size-log_offset, - reg->i_len, - ©_off, ©_len, - &partial_copy, - &partial_copy_len); - xlog_verify_dest_ptr(log, ptr); - - /* - * Copy region. - * - * Unmount records just log an opheader, so can have - * empty payloads with no data region to copy. Hence we - * only copy the payload if the vector says it has data - * to copy. - */ - ASSERT(copy_len >= 0); - if (copy_len > 0) { - memcpy(ptr, reg->i_addr + copy_off, copy_len); - xlog_write_adv_cnt(&ptr, &len, &log_offset, - copy_len); - } - copy_len += start_rec_copy + sizeof(xlog_op_header_t); - record_cnt++; - data_cnt += contwr ? copy_len : 0; - - error = xlog_write_copy_finish(log, iclog, flags, - &record_cnt, &data_cnt, - &partial_copy, - &partial_copy_len, - log_offset, - commit_iclog); - if (error) - return error; - - /* - * if we had a partial copy, we need to get more iclog - * space but we don't want to increment the region - * index because there is still more is this region to - * write. - * - * If we completed writing this region, and we flushed - * the iclog (indicated by resetting of the record - * count), then we also need to get more log space. If - * this was the last record, though, we are done and - * can just return. - */ - if (partial_copy) - break; - - if (++index == lv->lv_niovecs) { -next_lv: - lv = lv->lv_next; - index = 0; - if (lv) - vecp = lv->lv_iovecp; - } - if (record_cnt == 0 && ordered == false) { - if (!lv) - return 0; - break; - } - } - } - - ASSERT(len == 0); - - xlog_state_finish_copy(log, iclog, record_cnt, data_cnt); - if (!commit_iclog) - return xlog_state_release_iclog(log, iclog); - - ASSERT(flags & XLOG_COMMIT_TRANS); - *commit_iclog = iclog; - return 0; -} - - -/***************************************************************************** - * - * State Machine functions - * - ***************************************************************************** - */ - -/* Clean iclogs starting from the head. This ordering must be - * maintained, so an iclog doesn't become ACTIVE beyond one that - * is SYNCING. This is also required to maintain the notion that we use - * a ordered wait queue to hold off would be writers to the log when every - * iclog is trying to sync to disk. - * - * State Change: DIRTY -> ACTIVE - */ -STATIC void -xlog_state_clean_log( - struct xlog *log) -{ - xlog_in_core_t *iclog; - int changed = 0; - - iclog = log->l_iclog; - do { - if (iclog->ic_state == XLOG_STATE_DIRTY) { - iclog->ic_state = XLOG_STATE_ACTIVE; - iclog->ic_offset = 0; - ASSERT(iclog->ic_callback == NULL); - /* - * If the number of ops in this iclog indicate it just - * contains the dummy transaction, we can - * change state into IDLE (the second time around). - * Otherwise we should change the state into - * NEED a dummy. - * We don't need to cover the dummy. - */ - if (!changed && - (be32_to_cpu(iclog->ic_header.h_num_logops) == - XLOG_COVER_OPS)) { - changed = 1; - } else { - /* - * We have two dirty iclogs so start over - * This could also be num of ops indicates - * this is not the dummy going out. - */ - changed = 2; - } - iclog->ic_header.h_num_logops = 0; - memset(iclog->ic_header.h_cycle_data, 0, - sizeof(iclog->ic_header.h_cycle_data)); - iclog->ic_header.h_lsn = 0; - } else if (iclog->ic_state == XLOG_STATE_ACTIVE) - /* do nothing */; - else - break; /* stop cleaning */ - iclog = iclog->ic_next; - } while (iclog != log->l_iclog); - - /* log is locked when we are called */ - /* - * Change state for the dummy log recording. - * We usually go to NEED. But we go to NEED2 if the changed indicates - * we are done writing the dummy record. - * If we are done with the second dummy recored (DONE2), then - * we go to IDLE. - */ - if (changed) { - switch (log->l_covered_state) { - case XLOG_STATE_COVER_IDLE: - case XLOG_STATE_COVER_NEED: - case XLOG_STATE_COVER_NEED2: - log->l_covered_state = XLOG_STATE_COVER_NEED; - break; - - case XLOG_STATE_COVER_DONE: - if (changed == 1) - log->l_covered_state = XLOG_STATE_COVER_NEED2; - else - log->l_covered_state = XLOG_STATE_COVER_NEED; - break; - - case XLOG_STATE_COVER_DONE2: - if (changed == 1) - log->l_covered_state = XLOG_STATE_COVER_IDLE; - else - log->l_covered_state = XLOG_STATE_COVER_NEED; - break; - - default: - ASSERT(0); - } - } -} /* xlog_state_clean_log */ - -STATIC xfs_lsn_t -xlog_get_lowest_lsn( - struct xlog *log) -{ - xlog_in_core_t *lsn_log; - xfs_lsn_t lowest_lsn, lsn; - - lsn_log = log->l_iclog; - lowest_lsn = 0; - do { - if (!(lsn_log->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_DIRTY))) { - lsn = be64_to_cpu(lsn_log->ic_header.h_lsn); - if ((lsn && !lowest_lsn) || - (XFS_LSN_CMP(lsn, lowest_lsn) < 0)) { - lowest_lsn = lsn; - } - } - lsn_log = lsn_log->ic_next; - } while (lsn_log != log->l_iclog); - return lowest_lsn; -} - - -STATIC void -xlog_state_do_callback( - struct xlog *log, - int aborted, - struct xlog_in_core *ciclog) -{ - xlog_in_core_t *iclog; - xlog_in_core_t *first_iclog; /* used to know when we've - * processed all iclogs once */ - xfs_log_callback_t *cb, *cb_next; - int flushcnt = 0; - xfs_lsn_t lowest_lsn; - int ioerrors; /* counter: iclogs with errors */ - int loopdidcallbacks; /* flag: inner loop did callbacks*/ - int funcdidcallbacks; /* flag: function did callbacks */ - int repeats; /* for issuing console warnings if - * looping too many times */ - int wake = 0; - - spin_lock(&log->l_icloglock); - first_iclog = iclog = log->l_iclog; - ioerrors = 0; - funcdidcallbacks = 0; - repeats = 0; - - do { - /* - * Scan all iclogs starting with the one pointed to by the - * log. Reset this starting point each time the log is - * unlocked (during callbacks). - * - * Keep looping through iclogs until one full pass is made - * without running any callbacks. - */ - first_iclog = log->l_iclog; - iclog = log->l_iclog; - loopdidcallbacks = 0; - repeats++; - - do { - - /* skip all iclogs in the ACTIVE & DIRTY states */ - if (iclog->ic_state & - (XLOG_STATE_ACTIVE|XLOG_STATE_DIRTY)) { - iclog = iclog->ic_next; - continue; - } - - /* - * Between marking a filesystem SHUTDOWN and stopping - * the log, we do flush all iclogs to disk (if there - * wasn't a log I/O error). So, we do want things to - * go smoothly in case of just a SHUTDOWN w/o a - * LOG_IO_ERROR. - */ - if (!(iclog->ic_state & XLOG_STATE_IOERROR)) { - /* - * Can only perform callbacks in order. Since - * this iclog is not in the DONE_SYNC/ - * DO_CALLBACK state, we skip the rest and - * just try to clean up. If we set our iclog - * to DO_CALLBACK, we will not process it when - * we retry since a previous iclog is in the - * CALLBACK and the state cannot change since - * we are holding the l_icloglock. - */ - if (!(iclog->ic_state & - (XLOG_STATE_DONE_SYNC | - XLOG_STATE_DO_CALLBACK))) { - if (ciclog && (ciclog->ic_state == - XLOG_STATE_DONE_SYNC)) { - ciclog->ic_state = XLOG_STATE_DO_CALLBACK; - } - break; - } - /* - * We now have an iclog that is in either the - * DO_CALLBACK or DONE_SYNC states. The other - * states (WANT_SYNC, SYNCING, or CALLBACK were - * caught by the above if and are going to - * clean (i.e. we aren't doing their callbacks) - * see the above if. - */ - - /* - * We will do one more check here to see if we - * have chased our tail around. - */ - - lowest_lsn = xlog_get_lowest_lsn(log); - if (lowest_lsn && - XFS_LSN_CMP(lowest_lsn, - be64_to_cpu(iclog->ic_header.h_lsn)) < 0) { - iclog = iclog->ic_next; - continue; /* Leave this iclog for - * another thread */ - } - - iclog->ic_state = XLOG_STATE_CALLBACK; - - - /* - * Completion of a iclog IO does not imply that - * a transaction has completed, as transactions - * can be large enough to span many iclogs. We - * cannot change the tail of the log half way - * through a transaction as this may be the only - * transaction in the log and moving th etail to - * point to the middle of it will prevent - * recovery from finding the start of the - * transaction. Hence we should only update the - * last_sync_lsn if this iclog contains - * transaction completion callbacks on it. - * - * We have to do this before we drop the - * icloglock to ensure we are the only one that - * can update it. - */ - ASSERT(XFS_LSN_CMP(atomic64_read(&log->l_last_sync_lsn), - be64_to_cpu(iclog->ic_header.h_lsn)) <= 0); - if (iclog->ic_callback) - atomic64_set(&log->l_last_sync_lsn, - be64_to_cpu(iclog->ic_header.h_lsn)); - - } else - ioerrors++; - - spin_unlock(&log->l_icloglock); - - /* - * Keep processing entries in the callback list until - * we come around and it is empty. We need to - * atomically see that the list is empty and change the - * state to DIRTY so that we don't miss any more - * callbacks being added. - */ - spin_lock(&iclog->ic_callback_lock); - cb = iclog->ic_callback; - while (cb) { - iclog->ic_callback_tail = &(iclog->ic_callback); - iclog->ic_callback = NULL; - spin_unlock(&iclog->ic_callback_lock); - - /* perform callbacks in the order given */ - for (; cb; cb = cb_next) { - cb_next = cb->cb_next; - cb->cb_func(cb->cb_arg, aborted); - } - spin_lock(&iclog->ic_callback_lock); - cb = iclog->ic_callback; - } - - loopdidcallbacks++; - funcdidcallbacks++; - - spin_lock(&log->l_icloglock); - ASSERT(iclog->ic_callback == NULL); - spin_unlock(&iclog->ic_callback_lock); - if (!(iclog->ic_state & XLOG_STATE_IOERROR)) - iclog->ic_state = XLOG_STATE_DIRTY; - - /* - * Transition from DIRTY to ACTIVE if applicable. - * NOP if STATE_IOERROR. - */ - xlog_state_clean_log(log); - - /* wake up threads waiting in xfs_log_force() */ - wake_up_all(&iclog->ic_force_wait); - - iclog = iclog->ic_next; - } while (first_iclog != iclog); - - if (repeats > 5000) { - flushcnt += repeats; - repeats = 0; - xfs_warn(log->l_mp, - "%s: possible infinite loop (%d iterations)", - __func__, flushcnt); - } - } while (!ioerrors && loopdidcallbacks); - -#ifdef DEBUG - /* - * Make one last gasp attempt to see if iclogs are being left in limbo. - * If the above loop finds an iclog earlier than the current iclog and - * in one of the syncing states, the current iclog is put into - * DO_CALLBACK and the callbacks are deferred to the completion of the - * earlier iclog. Walk the iclogs in order and make sure that no iclog - * is in DO_CALLBACK unless an earlier iclog is in one of the syncing - * states. - * - * Note that SYNCING|IOABORT is a valid state so we cannot just check - * for ic_state == SYNCING. - */ - if (funcdidcallbacks) { - first_iclog = iclog = log->l_iclog; - do { - ASSERT(iclog->ic_state != XLOG_STATE_DO_CALLBACK); - /* - * Terminate the loop if iclogs are found in states - * which will cause other threads to clean up iclogs. - * - * SYNCING - i/o completion will go through logs - * DONE_SYNC - interrupt thread should be waiting for - * l_icloglock - * IOERROR - give up hope all ye who enter here - */ - if (iclog->ic_state == XLOG_STATE_WANT_SYNC || - iclog->ic_state & XLOG_STATE_SYNCING || - iclog->ic_state == XLOG_STATE_DONE_SYNC || - iclog->ic_state == XLOG_STATE_IOERROR ) - break; - iclog = iclog->ic_next; - } while (first_iclog != iclog); - } -#endif - - if (log->l_iclog->ic_state & (XLOG_STATE_ACTIVE|XLOG_STATE_IOERROR)) - wake = 1; - spin_unlock(&log->l_icloglock); - - if (wake) - wake_up_all(&log->l_flush_wait); -} - - -/* - * Finish transitioning this iclog to the dirty state. - * - * Make sure that we completely execute this routine only when this is - * the last call to the iclog. There is a good chance that iclog flushes, - * when we reach the end of the physical log, get turned into 2 separate - * calls to bwrite. Hence, one iclog flush could generate two calls to this - * routine. By using the reference count bwritecnt, we guarantee that only - * the second completion goes through. - * - * Callbacks could take time, so they are done outside the scope of the - * global state machine log lock. - */ -STATIC void -xlog_state_done_syncing( - xlog_in_core_t *iclog, - int aborted) -{ - struct xlog *log = iclog->ic_log; - - spin_lock(&log->l_icloglock); - - ASSERT(iclog->ic_state == XLOG_STATE_SYNCING || - iclog->ic_state == XLOG_STATE_IOERROR); - ASSERT(atomic_read(&iclog->ic_refcnt) == 0); - ASSERT(iclog->ic_bwritecnt == 1 || iclog->ic_bwritecnt == 2); - - - /* - * If we got an error, either on the first buffer, or in the case of - * split log writes, on the second, we mark ALL iclogs STATE_IOERROR, - * and none should ever be attempted to be written to disk - * again. - */ - if (iclog->ic_state != XLOG_STATE_IOERROR) { - if (--iclog->ic_bwritecnt == 1) { - spin_unlock(&log->l_icloglock); - return; - } - iclog->ic_state = XLOG_STATE_DONE_SYNC; - } - - /* - * Someone could be sleeping prior to writing out the next - * iclog buffer, we wake them all, one will get to do the - * I/O, the others get to wait for the result. - */ - wake_up_all(&iclog->ic_write_wait); - spin_unlock(&log->l_icloglock); - xlog_state_do_callback(log, aborted, iclog); /* also cleans log */ -} /* xlog_state_done_syncing */ - - -/* - * If the head of the in-core log ring is not (ACTIVE or DIRTY), then we must - * sleep. We wait on the flush queue on the head iclog as that should be - * the first iclog to complete flushing. Hence if all iclogs are syncing, - * we will wait here and all new writes will sleep until a sync completes. - * - * The in-core logs are used in a circular fashion. They are not used - * out-of-order even when an iclog past the head is free. - * - * return: - * * log_offset where xlog_write() can start writing into the in-core - * log's data space. - * * in-core log pointer to which xlog_write() should write. - * * boolean indicating this is a continued write to an in-core log. - * If this is the last write, then the in-core log's offset field - * needs to be incremented, depending on the amount of data which - * is copied. - */ -STATIC int -xlog_state_get_iclog_space( - struct xlog *log, - int len, - struct xlog_in_core **iclogp, - struct xlog_ticket *ticket, - int *continued_write, - int *logoffsetp) -{ - int log_offset; - xlog_rec_header_t *head; - xlog_in_core_t *iclog; - int error; - -restart: - spin_lock(&log->l_icloglock); - if (XLOG_FORCED_SHUTDOWN(log)) { - spin_unlock(&log->l_icloglock); - return -EIO; - } - - iclog = log->l_iclog; - if (iclog->ic_state != XLOG_STATE_ACTIVE) { - XFS_STATS_INC(log->l_mp, xs_log_noiclogs); - - /* Wait for log writes to have flushed */ - xlog_wait(&log->l_flush_wait, &log->l_icloglock); - goto restart; - } - - head = &iclog->ic_header; - - atomic_inc(&iclog->ic_refcnt); /* prevents sync */ - log_offset = iclog->ic_offset; - - /* On the 1st write to an iclog, figure out lsn. This works - * if iclogs marked XLOG_STATE_WANT_SYNC always write out what they are - * committing to. If the offset is set, that's how many blocks - * must be written. - */ - if (log_offset == 0) { - ticket->t_curr_res -= log->l_iclog_hsize; - xlog_tic_add_region(ticket, - log->l_iclog_hsize, - XLOG_REG_TYPE_LRHEADER); - head->h_cycle = cpu_to_be32(log->l_curr_cycle); - head->h_lsn = cpu_to_be64( - xlog_assign_lsn(log->l_curr_cycle, log->l_curr_block)); - ASSERT(log->l_curr_block >= 0); - } - - /* If there is enough room to write everything, then do it. Otherwise, - * claim the rest of the region and make sure the XLOG_STATE_WANT_SYNC - * bit is on, so this will get flushed out. Don't update ic_offset - * until you know exactly how many bytes get copied. Therefore, wait - * until later to update ic_offset. - * - * xlog_write() algorithm assumes that at least 2 xlog_op_header_t's - * can fit into remaining data section. - */ - if (iclog->ic_size - iclog->ic_offset < 2*sizeof(xlog_op_header_t)) { - xlog_state_switch_iclogs(log, iclog, iclog->ic_size); - - /* - * If I'm the only one writing to this iclog, sync it to disk. - * We need to do an atomic compare and decrement here to avoid - * racing with concurrent atomic_dec_and_lock() calls in - * xlog_state_release_iclog() when there is more than one - * reference to the iclog. - */ - if (!atomic_add_unless(&iclog->ic_refcnt, -1, 1)) { - /* we are the only one */ - spin_unlock(&log->l_icloglock); - error = xlog_state_release_iclog(log, iclog); - if (error) - return error; - } else { - spin_unlock(&log->l_icloglock); - } - goto restart; - } - - /* Do we have enough room to write the full amount in the remainder - * of this iclog? Or must we continue a write on the next iclog and - * mark this iclog as completely taken? In the case where we switch - * iclogs (to mark it taken), this particular iclog will release/sync - * to disk in xlog_write(). - */ - if (len <= iclog->ic_size - iclog->ic_offset) { - *continued_write = 0; - iclog->ic_offset += len; - } else { - *continued_write = 1; - xlog_state_switch_iclogs(log, iclog, iclog->ic_size); - } - *iclogp = iclog; - - ASSERT(iclog->ic_offset <= iclog->ic_size); - spin_unlock(&log->l_icloglock); - - *logoffsetp = log_offset; - return 0; -} /* xlog_state_get_iclog_space */ - -/* The first cnt-1 times through here we don't need to - * move the grant write head because the permanent - * reservation has reserved cnt times the unit amount. - * Release part of current permanent unit reservation and - * reset current reservation to be one units worth. Also - * move grant reservation head forward. - */ -STATIC void -xlog_regrant_reserve_log_space( - struct xlog *log, - struct xlog_ticket *ticket) -{ - trace_xfs_log_regrant_reserve_enter(log, ticket); - - if (ticket->t_cnt > 0) - ticket->t_cnt--; - - xlog_grant_sub_space(log, &log->l_reserve_head.grant, - ticket->t_curr_res); - xlog_grant_sub_space(log, &log->l_write_head.grant, - ticket->t_curr_res); - ticket->t_curr_res = ticket->t_unit_res; - xlog_tic_reset_res(ticket); - - trace_xfs_log_regrant_reserve_sub(log, ticket); - - /* just return if we still have some of the pre-reserved space */ - if (ticket->t_cnt > 0) - return; - - xlog_grant_add_space(log, &log->l_reserve_head.grant, - ticket->t_unit_res); - - trace_xfs_log_regrant_reserve_exit(log, ticket); - - ticket->t_curr_res = ticket->t_unit_res; - xlog_tic_reset_res(ticket); -} /* xlog_regrant_reserve_log_space */ - - -/* - * Give back the space left from a reservation. - * - * All the information we need to make a correct determination of space left - * is present. For non-permanent reservations, things are quite easy. The - * count should have been decremented to zero. We only need to deal with the - * space remaining in the current reservation part of the ticket. If the - * ticket contains a permanent reservation, there may be left over space which - * needs to be released. A count of N means that N-1 refills of the current - * reservation can be done before we need to ask for more space. The first - * one goes to fill up the first current reservation. Once we run out of - * space, the count will stay at zero and the only space remaining will be - * in the current reservation field. - */ -STATIC void -xlog_ungrant_log_space( - struct xlog *log, - struct xlog_ticket *ticket) -{ - int bytes; - - if (ticket->t_cnt > 0) - ticket->t_cnt--; - - trace_xfs_log_ungrant_enter(log, ticket); - trace_xfs_log_ungrant_sub(log, ticket); - - /* - * If this is a permanent reservation ticket, we may be able to free - * up more space based on the remaining count. - */ - bytes = ticket->t_curr_res; - if (ticket->t_cnt > 0) { - ASSERT(ticket->t_flags & XLOG_TIC_PERM_RESERV); - bytes += ticket->t_unit_res*ticket->t_cnt; - } - - xlog_grant_sub_space(log, &log->l_reserve_head.grant, bytes); - xlog_grant_sub_space(log, &log->l_write_head.grant, bytes); - - trace_xfs_log_ungrant_exit(log, ticket); - - xfs_log_space_wake(log->l_mp); -} - -/* - * Flush iclog to disk if this is the last reference to the given iclog and - * the WANT_SYNC bit is set. - * - * When this function is entered, the iclog is not necessarily in the - * WANT_SYNC state. It may be sitting around waiting to get filled. - * - * - */ -STATIC int -xlog_state_release_iclog( - struct xlog *log, - struct xlog_in_core *iclog) -{ - int sync = 0; /* do we sync? */ - - if (iclog->ic_state & XLOG_STATE_IOERROR) - return -EIO; - - ASSERT(atomic_read(&iclog->ic_refcnt) > 0); - if (!atomic_dec_and_lock(&iclog->ic_refcnt, &log->l_icloglock)) - return 0; - - if (iclog->ic_state & XLOG_STATE_IOERROR) { - spin_unlock(&log->l_icloglock); - return -EIO; - } - ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE || - iclog->ic_state == XLOG_STATE_WANT_SYNC); - - if (iclog->ic_state == XLOG_STATE_WANT_SYNC) { - /* update tail before writing to iclog */ - xfs_lsn_t tail_lsn = xlog_assign_tail_lsn(log->l_mp); - sync++; - iclog->ic_state = XLOG_STATE_SYNCING; - iclog->ic_header.h_tail_lsn = cpu_to_be64(tail_lsn); - xlog_verify_tail_lsn(log, iclog, tail_lsn); - /* cycle incremented when incrementing curr_block */ - } - spin_unlock(&log->l_icloglock); - - /* - * We let the log lock go, so it's possible that we hit a log I/O - * error or some other SHUTDOWN condition that marks the iclog - * as XLOG_STATE_IOERROR before the bwrite. However, we know that - * this iclog has consistent data, so we ignore IOERROR - * flags after this point. - */ - if (sync) - return xlog_sync(log, iclog); - return 0; -} /* xlog_state_release_iclog */ - - -/* - * This routine will mark the current iclog in the ring as WANT_SYNC - * and move the current iclog pointer to the next iclog in the ring. - * When this routine is called from xlog_state_get_iclog_space(), the - * exact size of the iclog has not yet been determined. All we know is - * that every data block. We have run out of space in this log record. - */ -STATIC void -xlog_state_switch_iclogs( - struct xlog *log, - struct xlog_in_core *iclog, - int eventual_size) -{ - ASSERT(iclog->ic_state == XLOG_STATE_ACTIVE); - if (!eventual_size) - eventual_size = iclog->ic_offset; - iclog->ic_state = XLOG_STATE_WANT_SYNC; - iclog->ic_header.h_prev_block = cpu_to_be32(log->l_prev_block); - log->l_prev_block = log->l_curr_block; - log->l_prev_cycle = log->l_curr_cycle; - - /* roll log?: ic_offset changed later */ - log->l_curr_block += BTOBB(eventual_size)+BTOBB(log->l_iclog_hsize); - - /* Round up to next log-sunit */ - if (xfs_sb_version_haslogv2(&log->l_mp->m_sb) && - log->l_mp->m_sb.sb_logsunit > 1) { - __uint32_t sunit_bb = BTOBB(log->l_mp->m_sb.sb_logsunit); - log->l_curr_block = roundup(log->l_curr_block, sunit_bb); - } - - if (log->l_curr_block >= log->l_logBBsize) { - /* - * Rewind the current block before the cycle is bumped to make - * sure that the combined LSN never transiently moves forward - * when the log wraps to the next cycle. This is to support the - * unlocked sample of these fields from xlog_valid_lsn(). Most - * other cases should acquire l_icloglock. - */ - log->l_curr_block -= log->l_logBBsize; - ASSERT(log->l_curr_block >= 0); - smp_wmb(); - log->l_curr_cycle++; - if (log->l_curr_cycle == XLOG_HEADER_MAGIC_NUM) - log->l_curr_cycle++; - } - ASSERT(iclog == log->l_iclog); - log->l_iclog = iclog->ic_next; -} /* xlog_state_switch_iclogs */ - -/* - * Write out all data in the in-core log as of this exact moment in time. - * - * Data may be written to the in-core log during this call. However, - * we don't guarantee this data will be written out. A change from past - * implementation means this routine will *not* write out zero length LRs. - * - * Basically, we try and perform an intelligent scan of the in-core logs. - * If we determine there is no flushable data, we just return. There is no - * flushable data if: - * - * 1. the current iclog is active and has no data; the previous iclog - * is in the active or dirty state. - * 2. the current iclog is drity, and the previous iclog is in the - * active or dirty state. - * - * We may sleep if: - * - * 1. the current iclog is not in the active nor dirty state. - * 2. the current iclog dirty, and the previous iclog is not in the - * active nor dirty state. - * 3. the current iclog is active, and there is another thread writing - * to this particular iclog. - * 4. a) the current iclog is active and has no other writers - * b) when we return from flushing out this iclog, it is still - * not in the active nor dirty state. - */ -int -_xfs_log_force( - struct xfs_mount *mp, - uint flags, - int *log_flushed) -{ - struct xlog *log = mp->m_log; - struct xlog_in_core *iclog; - xfs_lsn_t lsn; - - XFS_STATS_INC(mp, xs_log_force); - - xlog_cil_force(log); - - spin_lock(&log->l_icloglock); - - iclog = log->l_iclog; - if (iclog->ic_state & XLOG_STATE_IOERROR) { - spin_unlock(&log->l_icloglock); - return -EIO; - } - - /* If the head iclog is not active nor dirty, we just attach - * ourselves to the head and go to sleep. - */ - if (iclog->ic_state == XLOG_STATE_ACTIVE || - iclog->ic_state == XLOG_STATE_DIRTY) { - /* - * If the head is dirty or (active and empty), then - * we need to look at the previous iclog. If the previous - * iclog is active or dirty we are done. There is nothing - * to sync out. Otherwise, we attach ourselves to the - * previous iclog and go to sleep. - */ - if (iclog->ic_state == XLOG_STATE_DIRTY || - (atomic_read(&iclog->ic_refcnt) == 0 - && iclog->ic_offset == 0)) { - iclog = iclog->ic_prev; - if (iclog->ic_state == XLOG_STATE_ACTIVE || - iclog->ic_state == XLOG_STATE_DIRTY) - goto no_sleep; - else - goto maybe_sleep; - } else { - if (atomic_read(&iclog->ic_refcnt) == 0) { - /* We are the only one with access to this - * iclog. Flush it out now. There should - * be a roundoff of zero to show that someone - * has already taken care of the roundoff from - * the previous sync. - */ - atomic_inc(&iclog->ic_refcnt); - lsn = be64_to_cpu(iclog->ic_header.h_lsn); - xlog_state_switch_iclogs(log, iclog, 0); - spin_unlock(&log->l_icloglock); - - if (xlog_state_release_iclog(log, iclog)) - return -EIO; - - if (log_flushed) - *log_flushed = 1; - spin_lock(&log->l_icloglock); - if (be64_to_cpu(iclog->ic_header.h_lsn) == lsn && - iclog->ic_state != XLOG_STATE_DIRTY) - goto maybe_sleep; - else - goto no_sleep; - } else { - /* Someone else is writing to this iclog. - * Use its call to flush out the data. However, - * the other thread may not force out this LR, - * so we mark it WANT_SYNC. - */ - xlog_state_switch_iclogs(log, iclog, 0); - goto maybe_sleep; - } - } - } - - /* By the time we come around again, the iclog could've been filled - * which would give it another lsn. If we have a new lsn, just - * return because the relevant data has been flushed. - */ -maybe_sleep: - if (flags & XFS_LOG_SYNC) { - /* - * We must check if we're shutting down here, before - * we wait, while we're holding the l_icloglock. - * Then we check again after waking up, in case our - * sleep was disturbed by a bad news. - */ - if (iclog->ic_state & XLOG_STATE_IOERROR) { - spin_unlock(&log->l_icloglock); - return -EIO; - } - XFS_STATS_INC(mp, xs_log_force_sleep); - xlog_wait(&iclog->ic_force_wait, &log->l_icloglock); - /* - * No need to grab the log lock here since we're - * only deciding whether or not to return EIO - * and the memory read should be atomic. - */ - if (iclog->ic_state & XLOG_STATE_IOERROR) - return -EIO; - if (log_flushed) - *log_flushed = 1; - } else { - -no_sleep: - spin_unlock(&log->l_icloglock); - } - return 0; -} - -/* - * Wrapper for _xfs_log_force(), to be used when caller doesn't care - * about errors or whether the log was flushed or not. This is the normal - * interface to use when trying to unpin items or move the log forward. - */ -void -xfs_log_force( - xfs_mount_t *mp, - uint flags) -{ - int error; - - trace_xfs_log_force(mp, 0, _RET_IP_); - error = _xfs_log_force(mp, flags, NULL); - if (error) - xfs_warn(mp, "%s: error %d returned.", __func__, error); -} - -/* - * Force the in-core log to disk for a specific LSN. - * - * Find in-core log with lsn. - * If it is in the DIRTY state, just return. - * If it is in the ACTIVE state, move the in-core log into the WANT_SYNC - * state and go to sleep or return. - * If it is in any other state, go to sleep or return. - * - * Synchronous forces are implemented with a signal variable. All callers - * to force a given lsn to disk will wait on a the sv attached to the - * specific in-core log. When given in-core log finally completes its - * write to disk, that thread will wake up all threads waiting on the - * sv. - */ -int -_xfs_log_force_lsn( - struct xfs_mount *mp, - xfs_lsn_t lsn, - uint flags, - int *log_flushed) -{ - struct xlog *log = mp->m_log; - struct xlog_in_core *iclog; - int already_slept = 0; - - ASSERT(lsn != 0); - - XFS_STATS_INC(mp, xs_log_force); - - lsn = xlog_cil_force_lsn(log, lsn); - if (lsn == NULLCOMMITLSN) - return 0; - -try_again: - spin_lock(&log->l_icloglock); - iclog = log->l_iclog; - if (iclog->ic_state & XLOG_STATE_IOERROR) { - spin_unlock(&log->l_icloglock); - return -EIO; - } - - do { - if (be64_to_cpu(iclog->ic_header.h_lsn) != lsn) { - iclog = iclog->ic_next; - continue; - } - - if (iclog->ic_state == XLOG_STATE_DIRTY) { - spin_unlock(&log->l_icloglock); - return 0; - } - - if (iclog->ic_state == XLOG_STATE_ACTIVE) { - /* - * We sleep here if we haven't already slept (e.g. - * this is the first time we've looked at the correct - * iclog buf) and the buffer before us is going to - * be sync'ed. The reason for this is that if we - * are doing sync transactions here, by waiting for - * the previous I/O to complete, we can allow a few - * more transactions into this iclog before we close - * it down. - * - * Otherwise, we mark the buffer WANT_SYNC, and bump - * up the refcnt so we can release the log (which - * drops the ref count). The state switch keeps new - * transaction commits from using this buffer. When - * the current commits finish writing into the buffer, - * the refcount will drop to zero and the buffer will - * go out then. - */ - if (!already_slept && - (iclog->ic_prev->ic_state & - (XLOG_STATE_WANT_SYNC | XLOG_STATE_SYNCING))) { - ASSERT(!(iclog->ic_state & XLOG_STATE_IOERROR)); - - XFS_STATS_INC(mp, xs_log_force_sleep); - - xlog_wait(&iclog->ic_prev->ic_write_wait, - &log->l_icloglock); - if (log_flushed) - *log_flushed = 1; - already_slept = 1; - goto try_again; - } - atomic_inc(&iclog->ic_refcnt); - xlog_state_switch_iclogs(log, iclog, 0); - spin_unlock(&log->l_icloglock); - if (xlog_state_release_iclog(log, iclog)) - return -EIO; - if (log_flushed) - *log_flushed = 1; - spin_lock(&log->l_icloglock); - } - - if ((flags & XFS_LOG_SYNC) && /* sleep */ - !(iclog->ic_state & - (XLOG_STATE_ACTIVE | XLOG_STATE_DIRTY))) { - /* - * Don't wait on completion if we know that we've - * gotten a log write error. - */ - if (iclog->ic_state & XLOG_STATE_IOERROR) { - spin_unlock(&log->l_icloglock); - return -EIO; - } - XFS_STATS_INC(mp, xs_log_force_sleep); - xlog_wait(&iclog->ic_force_wait, &log->l_icloglock); - /* - * No need to grab the log lock here since we're - * only deciding whether or not to return EIO - * and the memory read should be atomic. - */ - if (iclog->ic_state & XLOG_STATE_IOERROR) - return -EIO; - - if (log_flushed) - *log_flushed = 1; - } else { /* just return */ - spin_unlock(&log->l_icloglock); - } - - return 0; - } while (iclog != log->l_iclog); - - spin_unlock(&log->l_icloglock); - return 0; -} - -/* - * Wrapper for _xfs_log_force_lsn(), to be used when caller doesn't care - * about errors or whether the log was flushed or not. This is the normal - * interface to use when trying to unpin items or move the log forward. - */ -void -xfs_log_force_lsn( - xfs_mount_t *mp, - xfs_lsn_t lsn, - uint flags) -{ - int error; - - trace_xfs_log_force(mp, lsn, _RET_IP_); - error = _xfs_log_force_lsn(mp, lsn, flags, NULL); - if (error) - xfs_warn(mp, "%s: error %d returned.", __func__, error); -} - -/* - * Called when we want to mark the current iclog as being ready to sync to - * disk. - */ -STATIC void -xlog_state_want_sync( - struct xlog *log, - struct xlog_in_core *iclog) -{ - assert_spin_locked(&log->l_icloglock); - - if (iclog->ic_state == XLOG_STATE_ACTIVE) { - xlog_state_switch_iclogs(log, iclog, 0); - } else { - ASSERT(iclog->ic_state & - (XLOG_STATE_WANT_SYNC|XLOG_STATE_IOERROR)); - } -} - - -/***************************************************************************** - * - * TICKET functions - * - ***************************************************************************** - */ - -/* - * Free a used ticket when its refcount falls to zero. - */ -void -xfs_log_ticket_put( - xlog_ticket_t *ticket) -{ - ASSERT(atomic_read(&ticket->t_ref) > 0); - if (atomic_dec_and_test(&ticket->t_ref)) - kmem_zone_free(xfs_log_ticket_zone, ticket); -} - -xlog_ticket_t * -xfs_log_ticket_get( - xlog_ticket_t *ticket) -{ - ASSERT(atomic_read(&ticket->t_ref) > 0); - atomic_inc(&ticket->t_ref); - return ticket; -} - -/* - * Figure out the total log space unit (in bytes) that would be - * required for a log ticket. - */ -int -xfs_log_calc_unit_res( - struct xfs_mount *mp, - int unit_bytes) -{ - struct xlog *log = mp->m_log; - int iclog_space; - uint num_headers; - - /* - * Permanent reservations have up to 'cnt'-1 active log operations - * in the log. A unit in this case is the amount of space for one - * of these log operations. Normal reservations have a cnt of 1 - * and their unit amount is the total amount of space required. - * - * The following lines of code account for non-transaction data - * which occupy space in the on-disk log. - * - * Normal form of a transaction is: - * ... - * and then there are LR hdrs, split-recs and roundoff at end of syncs. - * - * We need to account for all the leadup data and trailer data - * around the transaction data. - * And then we need to account for the worst case in terms of using - * more space. - * The worst case will happen if: - * - the placement of the transaction happens to be such that the - * roundoff is at its maximum - * - the transaction data is synced before the commit record is synced - * i.e. | - * Therefore the commit record is in its own Log Record. - * This can happen as the commit record is called with its - * own region to xlog_write(). - * This then means that in the worst case, roundoff can happen for - * the commit-rec as well. - * The commit-rec is smaller than padding in this scenario and so it is - * not added separately. - */ - - /* for trans header */ - unit_bytes += sizeof(xlog_op_header_t); - unit_bytes += sizeof(xfs_trans_header_t); - - /* for start-rec */ - unit_bytes += sizeof(xlog_op_header_t); - - /* - * for LR headers - the space for data in an iclog is the size minus - * the space used for the headers. If we use the iclog size, then we - * undercalculate the number of headers required. - * - * Furthermore - the addition of op headers for split-recs might - * increase the space required enough to require more log and op - * headers, so take that into account too. - * - * IMPORTANT: This reservation makes the assumption that if this - * transaction is the first in an iclog and hence has the LR headers - * accounted to it, then the remaining space in the iclog is - * exclusively for this transaction. i.e. if the transaction is larger - * than the iclog, it will be the only thing in that iclog. - * Fundamentally, this means we must pass the entire log vector to - * xlog_write to guarantee this. - */ - iclog_space = log->l_iclog_size - log->l_iclog_hsize; - num_headers = howmany(unit_bytes, iclog_space); - - /* for split-recs - ophdrs added when data split over LRs */ - unit_bytes += sizeof(xlog_op_header_t) * num_headers; - - /* add extra header reservations if we overrun */ - while (!num_headers || - howmany(unit_bytes, iclog_space) > num_headers) { - unit_bytes += sizeof(xlog_op_header_t); - num_headers++; - } - unit_bytes += log->l_iclog_hsize * num_headers; - - /* for commit-rec LR header - note: padding will subsume the ophdr */ - unit_bytes += log->l_iclog_hsize; - - /* for roundoff padding for transaction data and one for commit record */ - if (xfs_sb_version_haslogv2(&mp->m_sb) && mp->m_sb.sb_logsunit > 1) { - /* log su roundoff */ - unit_bytes += 2 * mp->m_sb.sb_logsunit; - } else { - /* BB roundoff */ - unit_bytes += 2 * BBSIZE; - } - - return unit_bytes; -} - -/* - * Allocate and initialise a new log ticket. - */ -struct xlog_ticket * -xlog_ticket_alloc( - struct xlog *log, - int unit_bytes, - int cnt, - char client, - bool permanent, - xfs_km_flags_t alloc_flags) -{ - struct xlog_ticket *tic; - int unit_res; - - tic = kmem_zone_zalloc(xfs_log_ticket_zone, alloc_flags); - if (!tic) - return NULL; - - unit_res = xfs_log_calc_unit_res(log->l_mp, unit_bytes); - - atomic_set(&tic->t_ref, 1); - tic->t_task = current; - INIT_LIST_HEAD(&tic->t_queue); - tic->t_unit_res = unit_res; - tic->t_curr_res = unit_res; - tic->t_cnt = cnt; - tic->t_ocnt = cnt; - tic->t_tid = prandom_u32(); - tic->t_clientid = client; - tic->t_flags = XLOG_TIC_INITED; - if (permanent) - tic->t_flags |= XLOG_TIC_PERM_RESERV; - - xlog_tic_reset_res(tic); - - return tic; -} - - -/****************************************************************************** - * - * Log debug routines - * - ****************************************************************************** - */ -#if defined(DEBUG) -/* - * Make sure that the destination ptr is within the valid data region of - * one of the iclogs. This uses backup pointers stored in a different - * part of the log in case we trash the log structure. - */ -void -xlog_verify_dest_ptr( - struct xlog *log, - void *ptr) -{ - int i; - int good_ptr = 0; - - for (i = 0; i < log->l_iclog_bufs; i++) { - if (ptr >= log->l_iclog_bak[i] && - ptr <= log->l_iclog_bak[i] + log->l_iclog_size) - good_ptr++; - } - - if (!good_ptr) - xfs_emerg(log->l_mp, "%s: invalid ptr", __func__); -} - -/* - * Check to make sure the grant write head didn't just over lap the tail. If - * the cycles are the same, we can't be overlapping. Otherwise, make sure that - * the cycles differ by exactly one and check the byte count. - * - * This check is run unlocked, so can give false positives. Rather than assert - * on failures, use a warn-once flag and a panic tag to allow the admin to - * determine if they want to panic the machine when such an error occurs. For - * debug kernels this will have the same effect as using an assert but, unlinke - * an assert, it can be turned off at runtime. - */ -STATIC void -xlog_verify_grant_tail( - struct xlog *log) -{ - int tail_cycle, tail_blocks; - int cycle, space; - - xlog_crack_grant_head(&log->l_write_head.grant, &cycle, &space); - xlog_crack_atomic_lsn(&log->l_tail_lsn, &tail_cycle, &tail_blocks); - if (tail_cycle != cycle) { - if (cycle - 1 != tail_cycle && - !(log->l_flags & XLOG_TAIL_WARN)) { - xfs_alert_tag(log->l_mp, XFS_PTAG_LOGRES, - "%s: cycle - 1 != tail_cycle", __func__); - log->l_flags |= XLOG_TAIL_WARN; - } - - if (space > BBTOB(tail_blocks) && - !(log->l_flags & XLOG_TAIL_WARN)) { - xfs_alert_tag(log->l_mp, XFS_PTAG_LOGRES, - "%s: space > BBTOB(tail_blocks)", __func__); - log->l_flags |= XLOG_TAIL_WARN; - } - } -} - -/* check if it will fit */ -STATIC void -xlog_verify_tail_lsn( - struct xlog *log, - struct xlog_in_core *iclog, - xfs_lsn_t tail_lsn) -{ - int blocks; - - if (CYCLE_LSN(tail_lsn) == log->l_prev_cycle) { - blocks = - log->l_logBBsize - (log->l_prev_block - BLOCK_LSN(tail_lsn)); - if (blocks < BTOBB(iclog->ic_offset)+BTOBB(log->l_iclog_hsize)) - xfs_emerg(log->l_mp, "%s: ran out of log space", __func__); - } else { - ASSERT(CYCLE_LSN(tail_lsn)+1 == log->l_prev_cycle); - - if (BLOCK_LSN(tail_lsn) == log->l_prev_block) - xfs_emerg(log->l_mp, "%s: tail wrapped", __func__); - - blocks = BLOCK_LSN(tail_lsn) - log->l_prev_block; - if (blocks < BTOBB(iclog->ic_offset) + 1) - xfs_emerg(log->l_mp, "%s: ran out of log space", __func__); - } -} /* xlog_verify_tail_lsn */ - -/* - * Perform a number of checks on the iclog before writing to disk. - * - * 1. Make sure the iclogs are still circular - * 2. Make sure we have a good magic number - * 3. Make sure we don't have magic numbers in the data - * 4. Check fields of each log operation header for: - * A. Valid client identifier - * B. tid ptr value falls in valid ptr space (user space code) - * C. Length in log record header is correct according to the - * individual operation headers within record. - * 5. When a bwrite will occur within 5 blocks of the front of the physical - * log, check the preceding blocks of the physical log to make sure all - * the cycle numbers agree with the current cycle number. - */ -STATIC void -xlog_verify_iclog( - struct xlog *log, - struct xlog_in_core *iclog, - int count, - bool syncing) -{ - xlog_op_header_t *ophead; - xlog_in_core_t *icptr; - xlog_in_core_2_t *xhdr; - void *base_ptr, *ptr, *p; - ptrdiff_t field_offset; - __uint8_t clientid; - int len, i, j, k, op_len; - int idx; - - /* check validity of iclog pointers */ - spin_lock(&log->l_icloglock); - icptr = log->l_iclog; - for (i = 0; i < log->l_iclog_bufs; i++, icptr = icptr->ic_next) - ASSERT(icptr); - - if (icptr != log->l_iclog) - xfs_emerg(log->l_mp, "%s: corrupt iclog ring", __func__); - spin_unlock(&log->l_icloglock); - - /* check log magic numbers */ - if (iclog->ic_header.h_magicno != cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) - xfs_emerg(log->l_mp, "%s: invalid magic num", __func__); - - base_ptr = ptr = &iclog->ic_header; - p = &iclog->ic_header; - for (ptr += BBSIZE; ptr < base_ptr + count; ptr += BBSIZE) { - if (*(__be32 *)ptr == cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) - xfs_emerg(log->l_mp, "%s: unexpected magic num", - __func__); - } - - /* check fields */ - len = be32_to_cpu(iclog->ic_header.h_num_logops); - base_ptr = ptr = iclog->ic_datap; - ophead = ptr; - xhdr = iclog->ic_data; - for (i = 0; i < len; i++) { - ophead = ptr; - - /* clientid is only 1 byte */ - p = &ophead->oh_clientid; - field_offset = p - base_ptr; - if (!syncing || (field_offset & 0x1ff)) { - clientid = ophead->oh_clientid; - } else { - idx = BTOBBT((char *)&ophead->oh_clientid - iclog->ic_datap); - if (idx >= (XLOG_HEADER_CYCLE_SIZE / BBSIZE)) { - j = idx / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); - k = idx % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); - clientid = xlog_get_client_id( - xhdr[j].hic_xheader.xh_cycle_data[k]); - } else { - clientid = xlog_get_client_id( - iclog->ic_header.h_cycle_data[idx]); - } - } - if (clientid != XFS_TRANSACTION && clientid != XFS_LOG) - xfs_warn(log->l_mp, - "%s: invalid clientid %d op 0x%p offset 0x%lx", - __func__, clientid, ophead, - (unsigned long)field_offset); - - /* check length */ - p = &ophead->oh_len; - field_offset = p - base_ptr; - if (!syncing || (field_offset & 0x1ff)) { - op_len = be32_to_cpu(ophead->oh_len); - } else { - idx = BTOBBT((uintptr_t)&ophead->oh_len - - (uintptr_t)iclog->ic_datap); - if (idx >= (XLOG_HEADER_CYCLE_SIZE / BBSIZE)) { - j = idx / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); - k = idx % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); - op_len = be32_to_cpu(xhdr[j].hic_xheader.xh_cycle_data[k]); - } else { - op_len = be32_to_cpu(iclog->ic_header.h_cycle_data[idx]); - } - } - ptr += sizeof(xlog_op_header_t) + op_len; - } -} /* xlog_verify_iclog */ -#endif - -/* - * Mark all iclogs IOERROR. l_icloglock is held by the caller. - */ -STATIC int -xlog_state_ioerror( - struct xlog *log) -{ - xlog_in_core_t *iclog, *ic; - - iclog = log->l_iclog; - if (! (iclog->ic_state & XLOG_STATE_IOERROR)) { - /* - * Mark all the incore logs IOERROR. - * From now on, no log flushes will result. - */ - ic = iclog; - do { - ic->ic_state = XLOG_STATE_IOERROR; - ic = ic->ic_next; - } while (ic != iclog); - return 0; - } - /* - * Return non-zero, if state transition has already happened. - */ - return 1; -} - -/* - * This is called from xfs_force_shutdown, when we're forcibly - * shutting down the filesystem, typically because of an IO error. - * Our main objectives here are to make sure that: - * a. if !logerror, flush the logs to disk. Anything modified - * after this is ignored. - * b. the filesystem gets marked 'SHUTDOWN' for all interested - * parties to find out, 'atomically'. - * c. those who're sleeping on log reservations, pinned objects and - * other resources get woken up, and be told the bad news. - * d. nothing new gets queued up after (b) and (c) are done. - * - * Note: for the !logerror case we need to flush the regions held in memory out - * to disk first. This needs to be done before the log is marked as shutdown, - * otherwise the iclog writes will fail. - */ -int -xfs_log_force_umount( - struct xfs_mount *mp, - int logerror) -{ - struct xlog *log; - int retval; - - log = mp->m_log; - - /* - * If this happens during log recovery, don't worry about - * locking; the log isn't open for business yet. - */ - if (!log || - log->l_flags & XLOG_ACTIVE_RECOVERY) { - mp->m_flags |= XFS_MOUNT_FS_SHUTDOWN; - if (mp->m_sb_bp) - mp->m_sb_bp->b_flags |= XBF_DONE; - return 0; - } - - /* - * Somebody could've already done the hard work for us. - * No need to get locks for this. - */ - if (logerror && log->l_iclog->ic_state & XLOG_STATE_IOERROR) { - ASSERT(XLOG_FORCED_SHUTDOWN(log)); - return 1; - } - - /* - * Flush all the completed transactions to disk before marking the log - * being shut down. We need to do it in this order to ensure that - * completed operations are safely on disk before we shut down, and that - * we don't have to issue any buffer IO after the shutdown flags are set - * to guarantee this. - */ - if (!logerror) - _xfs_log_force(mp, XFS_LOG_SYNC, NULL); - - /* - * mark the filesystem and the as in a shutdown state and wake - * everybody up to tell them the bad news. - */ - spin_lock(&log->l_icloglock); - mp->m_flags |= XFS_MOUNT_FS_SHUTDOWN; - if (mp->m_sb_bp) - mp->m_sb_bp->b_flags |= XBF_DONE; - - /* - * Mark the log and the iclogs with IO error flags to prevent any - * further log IO from being issued or completed. - */ - log->l_flags |= XLOG_IO_ERROR; - retval = xlog_state_ioerror(log); - spin_unlock(&log->l_icloglock); - - /* - * We don't want anybody waiting for log reservations after this. That - * means we have to wake up everybody queued up on reserveq as well as - * writeq. In addition, we make sure in xlog_{re}grant_log_space that - * we don't enqueue anything once the SHUTDOWN flag is set, and this - * action is protected by the grant locks. - */ - xlog_grant_head_wake_all(&log->l_reserve_head); - xlog_grant_head_wake_all(&log->l_write_head); - - /* - * Wake up everybody waiting on xfs_log_force. Wake the CIL push first - * as if the log writes were completed. The abort handling in the log - * item committed callback functions will do this again under lock to - * avoid races. - */ - wake_up_all(&log->l_cilp->xc_commit_wait); - xlog_state_do_callback(log, XFS_LI_ABORTED, NULL); - -#ifdef XFSERRORDEBUG - { - xlog_in_core_t *iclog; - - spin_lock(&log->l_icloglock); - iclog = log->l_iclog; - do { - ASSERT(iclog->ic_callback == 0); - iclog = iclog->ic_next; - } while (iclog != log->l_iclog); - spin_unlock(&log->l_icloglock); - } -#endif - /* return non-zero if log IOERROR transition had already happened */ - return retval; -} - -STATIC int -xlog_iclogs_empty( - struct xlog *log) -{ - xlog_in_core_t *iclog; - - iclog = log->l_iclog; - do { - /* endianness does not matter here, zero is zero in - * any language. - */ - if (iclog->ic_header.h_num_logops) - return 0; - iclog = iclog->ic_next; - } while (iclog != log->l_iclog); - return 1; -} - -/* - * Verify that an LSN stamped into a piece of metadata is valid. This is - * intended for use in read verifiers on v5 superblocks. - */ -bool -xfs_log_check_lsn( - struct xfs_mount *mp, - xfs_lsn_t lsn) -{ - struct xlog *log = mp->m_log; - bool valid; - - /* - * norecovery mode skips mount-time log processing and unconditionally - * resets the in-core LSN. We can't validate in this mode, but - * modifications are not allowed anyways so just return true. - */ - if (mp->m_flags & XFS_MOUNT_NORECOVERY) - return true; - - /* - * Some metadata LSNs are initialized to NULL (e.g., the agfl). This is - * handled by recovery and thus safe to ignore here. - */ - if (lsn == NULLCOMMITLSN) - return true; - - valid = xlog_valid_lsn(mp->m_log, lsn); - - /* warn the user about what's gone wrong before verifier failure */ - if (!valid) { - spin_lock(&log->l_icloglock); - xfs_warn(mp, -"Corruption warning: Metadata has LSN (%d:%d) ahead of current LSN (%d:%d). " -"Please unmount and run xfs_repair (>= v4.3) to resolve.", - CYCLE_LSN(lsn), BLOCK_LSN(lsn), - log->l_curr_cycle, log->l_curr_block); - spin_unlock(&log->l_icloglock); - } - - return valid; -} diff --git a/src/linux/fs/xfs/xfs_log.h b/src/linux/fs/xfs/xfs_log.h deleted file mode 100644 index b5e7107..0000000 --- a/src/linux/fs/xfs/xfs_log.h +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_LOG_H__ -#define __XFS_LOG_H__ - -struct xfs_log_vec { - struct xfs_log_vec *lv_next; /* next lv in build list */ - int lv_niovecs; /* number of iovecs in lv */ - struct xfs_log_iovec *lv_iovecp; /* iovec array */ - struct xfs_log_item *lv_item; /* owner */ - char *lv_buf; /* formatted buffer */ - int lv_bytes; /* accounted space in buffer */ - int lv_buf_len; /* aligned size of buffer */ - int lv_size; /* size of allocated lv */ -}; - -#define XFS_LOG_VEC_ORDERED (-1) - -static inline void * -xlog_prepare_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec **vecp, - uint type) -{ - struct xfs_log_iovec *vec = *vecp; - - if (vec) { - ASSERT(vec - lv->lv_iovecp < lv->lv_niovecs); - vec++; - } else { - vec = &lv->lv_iovecp[0]; - } - - vec->i_type = type; - vec->i_addr = lv->lv_buf + lv->lv_buf_len; - - ASSERT(IS_ALIGNED((unsigned long)vec->i_addr, sizeof(uint64_t))); - - *vecp = vec; - return vec->i_addr; -} - -/* - * We need to make sure the next buffer is naturally aligned for the biggest - * basic data type we put into it. We already accounted for this padding when - * sizing the buffer. - * - * However, this padding does not get written into the log, and hence we have to - * track the space used by the log vectors separately to prevent log space hangs - * due to inaccurate accounting (i.e. a leak) of the used log space through the - * CIL context ticket. - */ -static inline void -xlog_finish_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec *vec, int len) -{ - lv->lv_buf_len += round_up(len, sizeof(uint64_t)); - lv->lv_bytes += len; - vec->i_len = len; -} - -static inline void * -xlog_copy_iovec(struct xfs_log_vec *lv, struct xfs_log_iovec **vecp, - uint type, void *data, int len) -{ - void *buf; - - buf = xlog_prepare_iovec(lv, vecp, type); - memcpy(buf, data, len); - xlog_finish_iovec(lv, *vecp, len); - return buf; -} - -/* - * Structure used to pass callback function and the function's argument - * to the log manager. - */ -typedef struct xfs_log_callback { - struct xfs_log_callback *cb_next; - void (*cb_func)(void *, int); - void *cb_arg; -} xfs_log_callback_t; - -/* - * By comparing each component, we don't have to worry about extra - * endian issues in treating two 32 bit numbers as one 64 bit number - */ -static inline xfs_lsn_t _lsn_cmp(xfs_lsn_t lsn1, xfs_lsn_t lsn2) -{ - if (CYCLE_LSN(lsn1) != CYCLE_LSN(lsn2)) - return (CYCLE_LSN(lsn1)t_curr_res = 0; - return tic; -} - -/* - * After the first stage of log recovery is done, we know where the head and - * tail of the log are. We need this log initialisation done before we can - * initialise the first CIL checkpoint context. - * - * Here we allocate a log ticket to track space usage during a CIL push. This - * ticket is passed to xlog_write() directly so that we don't slowly leak log - * space by failing to account for space used by log headers and additional - * region headers for split regions. - */ -void -xlog_cil_init_post_recovery( - struct xlog *log) -{ - log->l_cilp->xc_ctx->ticket = xlog_cil_ticket_alloc(log); - log->l_cilp->xc_ctx->sequence = 1; -} - -static inline int -xlog_cil_iovec_space( - uint niovecs) -{ - return round_up((sizeof(struct xfs_log_vec) + - niovecs * sizeof(struct xfs_log_iovec)), - sizeof(uint64_t)); -} - -/* - * Allocate or pin log vector buffers for CIL insertion. - * - * The CIL currently uses disposable buffers for copying a snapshot of the - * modified items into the log during a push. The biggest problem with this is - * the requirement to allocate the disposable buffer during the commit if: - * a) does not exist; or - * b) it is too small - * - * If we do this allocation within xlog_cil_insert_format_items(), it is done - * under the xc_ctx_lock, which means that a CIL push cannot occur during - * the memory allocation. This means that we have a potential deadlock situation - * under low memory conditions when we have lots of dirty metadata pinned in - * the CIL and we need a CIL commit to occur to free memory. - * - * To avoid this, we need to move the memory allocation outside the - * xc_ctx_lock, but because the log vector buffers are disposable, that opens - * up a TOCTOU race condition w.r.t. the CIL committing and removing the log - * vector buffers between the check and the formatting of the item into the - * log vector buffer within the xc_ctx_lock. - * - * Because the log vector buffer needs to be unchanged during the CIL push - * process, we cannot share the buffer between the transaction commit (which - * modifies the buffer) and the CIL push context that is writing the changes - * into the log. This means skipping preallocation of buffer space is - * unreliable, but we most definitely do not want to be allocating and freeing - * buffers unnecessarily during commits when overwrites can be done safely. - * - * The simplest solution to this problem is to allocate a shadow buffer when a - * log item is committed for the second time, and then to only use this buffer - * if necessary. The buffer can remain attached to the log item until such time - * it is needed, and this is the buffer that is reallocated to match the size of - * the incoming modification. Then during the formatting of the item we can swap - * the active buffer with the new one if we can't reuse the existing buffer. We - * don't free the old buffer as it may be reused on the next modification if - * it's size is right, otherwise we'll free and reallocate it at that point. - * - * This function builds a vector for the changes in each log item in the - * transaction. It then works out the length of the buffer needed for each log - * item, allocates them and attaches the vector to the log item in preparation - * for the formatting step which occurs under the xc_ctx_lock. - * - * While this means the memory footprint goes up, it avoids the repeated - * alloc/free pattern that repeated modifications of an item would otherwise - * cause, and hence minimises the CPU overhead of such behaviour. - */ -static void -xlog_cil_alloc_shadow_bufs( - struct xlog *log, - struct xfs_trans *tp) -{ - struct xfs_log_item_desc *lidp; - - list_for_each_entry(lidp, &tp->t_items, lid_trans) { - struct xfs_log_item *lip = lidp->lid_item; - struct xfs_log_vec *lv; - int niovecs = 0; - int nbytes = 0; - int buf_size; - bool ordered = false; - - /* Skip items which aren't dirty in this transaction. */ - if (!(lidp->lid_flags & XFS_LID_DIRTY)) - continue; - - /* get number of vecs and size of data to be stored */ - lip->li_ops->iop_size(lip, &niovecs, &nbytes); - - /* - * Ordered items need to be tracked but we do not wish to write - * them. We need a logvec to track the object, but we do not - * need an iovec or buffer to be allocated for copying data. - */ - if (niovecs == XFS_LOG_VEC_ORDERED) { - ordered = true; - niovecs = 0; - nbytes = 0; - } - - /* - * We 64-bit align the length of each iovec so that the start - * of the next one is naturally aligned. We'll need to - * account for that slack space here. Then round nbytes up - * to 64-bit alignment so that the initial buffer alignment is - * easy to calculate and verify. - */ - nbytes += niovecs * sizeof(uint64_t); - nbytes = round_up(nbytes, sizeof(uint64_t)); - - /* - * The data buffer needs to start 64-bit aligned, so round up - * that space to ensure we can align it appropriately and not - * overrun the buffer. - */ - buf_size = nbytes + xlog_cil_iovec_space(niovecs); - - /* - * if we have no shadow buffer, or it is too small, we need to - * reallocate it. - */ - if (!lip->li_lv_shadow || - buf_size > lip->li_lv_shadow->lv_size) { - - /* - * We free and allocate here as a realloc would copy - * unecessary data. We don't use kmem_zalloc() for the - * same reason - we don't need to zero the data area in - * the buffer, only the log vector header and the iovec - * storage. - */ - kmem_free(lip->li_lv_shadow); - - lv = kmem_alloc(buf_size, KM_SLEEP|KM_NOFS); - memset(lv, 0, xlog_cil_iovec_space(niovecs)); - - lv->lv_item = lip; - lv->lv_size = buf_size; - if (ordered) - lv->lv_buf_len = XFS_LOG_VEC_ORDERED; - else - lv->lv_iovecp = (struct xfs_log_iovec *)&lv[1]; - lip->li_lv_shadow = lv; - } else { - /* same or smaller, optimise common overwrite case */ - lv = lip->li_lv_shadow; - if (ordered) - lv->lv_buf_len = XFS_LOG_VEC_ORDERED; - else - lv->lv_buf_len = 0; - lv->lv_bytes = 0; - lv->lv_next = NULL; - } - - /* Ensure the lv is set up according to ->iop_size */ - lv->lv_niovecs = niovecs; - - /* The allocated data region lies beyond the iovec region */ - lv->lv_buf = (char *)lv + xlog_cil_iovec_space(niovecs); - } - -} - -/* - * Prepare the log item for insertion into the CIL. Calculate the difference in - * log space and vectors it will consume, and if it is a new item pin it as - * well. - */ -STATIC void -xfs_cil_prepare_item( - struct xlog *log, - struct xfs_log_vec *lv, - struct xfs_log_vec *old_lv, - int *diff_len, - int *diff_iovecs) -{ - /* Account for the new LV being passed in */ - if (lv->lv_buf_len != XFS_LOG_VEC_ORDERED) { - *diff_len += lv->lv_bytes; - *diff_iovecs += lv->lv_niovecs; - } - - /* - * If there is no old LV, this is the first time we've seen the item in - * this CIL context and so we need to pin it. If we are replacing the - * old_lv, then remove the space it accounts for and make it the shadow - * buffer for later freeing. In both cases we are now switching to the - * shadow buffer, so update the the pointer to it appropriately. - */ - if (!old_lv) { - lv->lv_item->li_ops->iop_pin(lv->lv_item); - lv->lv_item->li_lv_shadow = NULL; - } else if (old_lv != lv) { - ASSERT(lv->lv_buf_len != XFS_LOG_VEC_ORDERED); - - *diff_len -= old_lv->lv_bytes; - *diff_iovecs -= old_lv->lv_niovecs; - lv->lv_item->li_lv_shadow = old_lv; - } - - /* attach new log vector to log item */ - lv->lv_item->li_lv = lv; - - /* - * If this is the first time the item is being committed to the - * CIL, store the sequence number on the log item so we can - * tell in future commits whether this is the first checkpoint - * the item is being committed into. - */ - if (!lv->lv_item->li_seq) - lv->lv_item->li_seq = log->l_cilp->xc_ctx->sequence; -} - -/* - * Format log item into a flat buffers - * - * For delayed logging, we need to hold a formatted buffer containing all the - * changes on the log item. This enables us to relog the item in memory and - * write it out asynchronously without needing to relock the object that was - * modified at the time it gets written into the iclog. - * - * This function takes the prepared log vectors attached to each log item, and - * formats the changes into the log vector buffer. The buffer it uses is - * dependent on the current state of the vector in the CIL - the shadow lv is - * guaranteed to be large enough for the current modification, but we will only - * use that if we can't reuse the existing lv. If we can't reuse the existing - * lv, then simple swap it out for the shadow lv. We don't free it - that is - * done lazily either by th enext modification or the freeing of the log item. - * - * We don't set up region headers during this process; we simply copy the - * regions into the flat buffer. We can do this because we still have to do a - * formatting step to write the regions into the iclog buffer. Writing the - * ophdrs during the iclog write means that we can support splitting large - * regions across iclog boundares without needing a change in the format of the - * item/region encapsulation. - * - * Hence what we need to do now is change the rewrite the vector array to point - * to the copied region inside the buffer we just allocated. This allows us to - * format the regions into the iclog as though they are being formatted - * directly out of the objects themselves. - */ -static void -xlog_cil_insert_format_items( - struct xlog *log, - struct xfs_trans *tp, - int *diff_len, - int *diff_iovecs) -{ - struct xfs_log_item_desc *lidp; - - - /* Bail out if we didn't find a log item. */ - if (list_empty(&tp->t_items)) { - ASSERT(0); - return; - } - - list_for_each_entry(lidp, &tp->t_items, lid_trans) { - struct xfs_log_item *lip = lidp->lid_item; - struct xfs_log_vec *lv; - struct xfs_log_vec *old_lv = NULL; - struct xfs_log_vec *shadow; - bool ordered = false; - - /* Skip items which aren't dirty in this transaction. */ - if (!(lidp->lid_flags & XFS_LID_DIRTY)) - continue; - - /* - * The formatting size information is already attached to - * the shadow lv on the log item. - */ - shadow = lip->li_lv_shadow; - if (shadow->lv_buf_len == XFS_LOG_VEC_ORDERED) - ordered = true; - - /* Skip items that do not have any vectors for writing */ - if (!shadow->lv_niovecs && !ordered) - continue; - - /* compare to existing item size */ - old_lv = lip->li_lv; - if (lip->li_lv && shadow->lv_size <= lip->li_lv->lv_size) { - /* same or smaller, optimise common overwrite case */ - lv = lip->li_lv; - lv->lv_next = NULL; - - if (ordered) - goto insert; - - /* - * set the item up as though it is a new insertion so - * that the space reservation accounting is correct. - */ - *diff_iovecs -= lv->lv_niovecs; - *diff_len -= lv->lv_bytes; - - /* Ensure the lv is set up according to ->iop_size */ - lv->lv_niovecs = shadow->lv_niovecs; - - /* reset the lv buffer information for new formatting */ - lv->lv_buf_len = 0; - lv->lv_bytes = 0; - lv->lv_buf = (char *)lv + - xlog_cil_iovec_space(lv->lv_niovecs); - } else { - /* switch to shadow buffer! */ - lv = shadow; - lv->lv_item = lip; - if (ordered) { - /* track as an ordered logvec */ - ASSERT(lip->li_lv == NULL); - goto insert; - } - } - - ASSERT(IS_ALIGNED((unsigned long)lv->lv_buf, sizeof(uint64_t))); - lip->li_ops->iop_format(lip, lv); -insert: - xfs_cil_prepare_item(log, lv, old_lv, diff_len, diff_iovecs); - } -} - -/* - * Insert the log items into the CIL and calculate the difference in space - * consumed by the item. Add the space to the checkpoint ticket and calculate - * if the change requires additional log metadata. If it does, take that space - * as well. Remove the amount of space we added to the checkpoint ticket from - * the current transaction ticket so that the accounting works out correctly. - */ -static void -xlog_cil_insert_items( - struct xlog *log, - struct xfs_trans *tp) -{ - struct xfs_cil *cil = log->l_cilp; - struct xfs_cil_ctx *ctx = cil->xc_ctx; - struct xfs_log_item_desc *lidp; - int len = 0; - int diff_iovecs = 0; - int iclog_space; - - ASSERT(tp); - - /* - * We can do this safely because the context can't checkpoint until we - * are done so it doesn't matter exactly how we update the CIL. - */ - xlog_cil_insert_format_items(log, tp, &len, &diff_iovecs); - - /* - * Now (re-)position everything modified at the tail of the CIL. - * We do this here so we only need to take the CIL lock once during - * the transaction commit. - */ - spin_lock(&cil->xc_cil_lock); - list_for_each_entry(lidp, &tp->t_items, lid_trans) { - struct xfs_log_item *lip = lidp->lid_item; - - /* Skip items which aren't dirty in this transaction. */ - if (!(lidp->lid_flags & XFS_LID_DIRTY)) - continue; - - /* - * Only move the item if it isn't already at the tail. This is - * to prevent a transient list_empty() state when reinserting - * an item that is already the only item in the CIL. - */ - if (!list_is_last(&lip->li_cil, &cil->xc_cil)) - list_move_tail(&lip->li_cil, &cil->xc_cil); - } - - /* account for space used by new iovec headers */ - len += diff_iovecs * sizeof(xlog_op_header_t); - ctx->nvecs += diff_iovecs; - - /* attach the transaction to the CIL if it has any busy extents */ - if (!list_empty(&tp->t_busy)) - list_splice_init(&tp->t_busy, &ctx->busy_extents); - - /* - * Now transfer enough transaction reservation to the context ticket - * for the checkpoint. The context ticket is special - the unit - * reservation has to grow as well as the current reservation as we - * steal from tickets so we can correctly determine the space used - * during the transaction commit. - */ - if (ctx->ticket->t_curr_res == 0) { - ctx->ticket->t_curr_res = ctx->ticket->t_unit_res; - tp->t_ticket->t_curr_res -= ctx->ticket->t_unit_res; - } - - /* do we need space for more log record headers? */ - iclog_space = log->l_iclog_size - log->l_iclog_hsize; - if (len > 0 && (ctx->space_used / iclog_space != - (ctx->space_used + len) / iclog_space)) { - int hdrs; - - hdrs = (len + iclog_space - 1) / iclog_space; - /* need to take into account split region headers, too */ - hdrs *= log->l_iclog_hsize + sizeof(struct xlog_op_header); - ctx->ticket->t_unit_res += hdrs; - ctx->ticket->t_curr_res += hdrs; - tp->t_ticket->t_curr_res -= hdrs; - ASSERT(tp->t_ticket->t_curr_res >= len); - } - tp->t_ticket->t_curr_res -= len; - ctx->space_used += len; - - spin_unlock(&cil->xc_cil_lock); -} - -static void -xlog_cil_free_logvec( - struct xfs_log_vec *log_vector) -{ - struct xfs_log_vec *lv; - - for (lv = log_vector; lv; ) { - struct xfs_log_vec *next = lv->lv_next; - kmem_free(lv); - lv = next; - } -} - -/* - * Mark all items committed and clear busy extents. We free the log vector - * chains in a separate pass so that we unpin the log items as quickly as - * possible. - */ -static void -xlog_cil_committed( - void *args, - int abort) -{ - struct xfs_cil_ctx *ctx = args; - struct xfs_mount *mp = ctx->cil->xc_log->l_mp; - - xfs_trans_committed_bulk(ctx->cil->xc_log->l_ailp, ctx->lv_chain, - ctx->start_lsn, abort); - - xfs_extent_busy_sort(&ctx->busy_extents); - xfs_extent_busy_clear(mp, &ctx->busy_extents, - (mp->m_flags & XFS_MOUNT_DISCARD) && !abort); - - /* - * If we are aborting the commit, wake up anyone waiting on the - * committing list. If we don't, then a shutdown we can leave processes - * waiting in xlog_cil_force_lsn() waiting on a sequence commit that - * will never happen because we aborted it. - */ - spin_lock(&ctx->cil->xc_push_lock); - if (abort) - wake_up_all(&ctx->cil->xc_commit_wait); - list_del(&ctx->committing); - spin_unlock(&ctx->cil->xc_push_lock); - - xlog_cil_free_logvec(ctx->lv_chain); - - if (!list_empty(&ctx->busy_extents)) { - ASSERT(mp->m_flags & XFS_MOUNT_DISCARD); - - xfs_discard_extents(mp, &ctx->busy_extents); - xfs_extent_busy_clear(mp, &ctx->busy_extents, false); - } - - kmem_free(ctx); -} - -/* - * Push the Committed Item List to the log. If @push_seq flag is zero, then it - * is a background flush and so we can chose to ignore it. Otherwise, if the - * current sequence is the same as @push_seq we need to do a flush. If - * @push_seq is less than the current sequence, then it has already been - * flushed and we don't need to do anything - the caller will wait for it to - * complete if necessary. - * - * @push_seq is a value rather than a flag because that allows us to do an - * unlocked check of the sequence number for a match. Hence we can allows log - * forces to run racily and not issue pushes for the same sequence twice. If we - * get a race between multiple pushes for the same sequence they will block on - * the first one and then abort, hence avoiding needless pushes. - */ -STATIC int -xlog_cil_push( - struct xlog *log) -{ - struct xfs_cil *cil = log->l_cilp; - struct xfs_log_vec *lv; - struct xfs_cil_ctx *ctx; - struct xfs_cil_ctx *new_ctx; - struct xlog_in_core *commit_iclog; - struct xlog_ticket *tic; - int num_iovecs; - int error = 0; - struct xfs_trans_header thdr; - struct xfs_log_iovec lhdr; - struct xfs_log_vec lvhdr = { NULL }; - xfs_lsn_t commit_lsn; - xfs_lsn_t push_seq; - - if (!cil) - return 0; - - new_ctx = kmem_zalloc(sizeof(*new_ctx), KM_SLEEP|KM_NOFS); - new_ctx->ticket = xlog_cil_ticket_alloc(log); - - down_write(&cil->xc_ctx_lock); - ctx = cil->xc_ctx; - - spin_lock(&cil->xc_push_lock); - push_seq = cil->xc_push_seq; - ASSERT(push_seq <= ctx->sequence); - - /* - * Check if we've anything to push. If there is nothing, then we don't - * move on to a new sequence number and so we have to be able to push - * this sequence again later. - */ - if (list_empty(&cil->xc_cil)) { - cil->xc_push_seq = 0; - spin_unlock(&cil->xc_push_lock); - goto out_skip; - } - - - /* check for a previously pushed seqeunce */ - if (push_seq < cil->xc_ctx->sequence) { - spin_unlock(&cil->xc_push_lock); - goto out_skip; - } - - /* - * We are now going to push this context, so add it to the committing - * list before we do anything else. This ensures that anyone waiting on - * this push can easily detect the difference between a "push in - * progress" and "CIL is empty, nothing to do". - * - * IOWs, a wait loop can now check for: - * the current sequence not being found on the committing list; - * an empty CIL; and - * an unchanged sequence number - * to detect a push that had nothing to do and therefore does not need - * waiting on. If the CIL is not empty, we get put on the committing - * list before emptying the CIL and bumping the sequence number. Hence - * an empty CIL and an unchanged sequence number means we jumped out - * above after doing nothing. - * - * Hence the waiter will either find the commit sequence on the - * committing list or the sequence number will be unchanged and the CIL - * still dirty. In that latter case, the push has not yet started, and - * so the waiter will have to continue trying to check the CIL - * committing list until it is found. In extreme cases of delay, the - * sequence may fully commit between the attempts the wait makes to wait - * on the commit sequence. - */ - list_add(&ctx->committing, &cil->xc_committing); - spin_unlock(&cil->xc_push_lock); - - /* - * pull all the log vectors off the items in the CIL, and - * remove the items from the CIL. We don't need the CIL lock - * here because it's only needed on the transaction commit - * side which is currently locked out by the flush lock. - */ - lv = NULL; - num_iovecs = 0; - while (!list_empty(&cil->xc_cil)) { - struct xfs_log_item *item; - - item = list_first_entry(&cil->xc_cil, - struct xfs_log_item, li_cil); - list_del_init(&item->li_cil); - if (!ctx->lv_chain) - ctx->lv_chain = item->li_lv; - else - lv->lv_next = item->li_lv; - lv = item->li_lv; - item->li_lv = NULL; - num_iovecs += lv->lv_niovecs; - } - - /* - * initialise the new context and attach it to the CIL. Then attach - * the current context to the CIL committing lsit so it can be found - * during log forces to extract the commit lsn of the sequence that - * needs to be forced. - */ - INIT_LIST_HEAD(&new_ctx->committing); - INIT_LIST_HEAD(&new_ctx->busy_extents); - new_ctx->sequence = ctx->sequence + 1; - new_ctx->cil = cil; - cil->xc_ctx = new_ctx; - - /* - * The switch is now done, so we can drop the context lock and move out - * of a shared context. We can't just go straight to the commit record, - * though - we need to synchronise with previous and future commits so - * that the commit records are correctly ordered in the log to ensure - * that we process items during log IO completion in the correct order. - * - * For example, if we get an EFI in one checkpoint and the EFD in the - * next (e.g. due to log forces), we do not want the checkpoint with - * the EFD to be committed before the checkpoint with the EFI. Hence - * we must strictly order the commit records of the checkpoints so - * that: a) the checkpoint callbacks are attached to the iclogs in the - * correct order; and b) the checkpoints are replayed in correct order - * in log recovery. - * - * Hence we need to add this context to the committing context list so - * that higher sequences will wait for us to write out a commit record - * before they do. - * - * xfs_log_force_lsn requires us to mirror the new sequence into the cil - * structure atomically with the addition of this sequence to the - * committing list. This also ensures that we can do unlocked checks - * against the current sequence in log forces without risking - * deferencing a freed context pointer. - */ - spin_lock(&cil->xc_push_lock); - cil->xc_current_sequence = new_ctx->sequence; - spin_unlock(&cil->xc_push_lock); - up_write(&cil->xc_ctx_lock); - - /* - * Build a checkpoint transaction header and write it to the log to - * begin the transaction. We need to account for the space used by the - * transaction header here as it is not accounted for in xlog_write(). - * - * The LSN we need to pass to the log items on transaction commit is - * the LSN reported by the first log vector write. If we use the commit - * record lsn then we can move the tail beyond the grant write head. - */ - tic = ctx->ticket; - thdr.th_magic = XFS_TRANS_HEADER_MAGIC; - thdr.th_type = XFS_TRANS_CHECKPOINT; - thdr.th_tid = tic->t_tid; - thdr.th_num_items = num_iovecs; - lhdr.i_addr = &thdr; - lhdr.i_len = sizeof(xfs_trans_header_t); - lhdr.i_type = XLOG_REG_TYPE_TRANSHDR; - tic->t_curr_res -= lhdr.i_len + sizeof(xlog_op_header_t); - - lvhdr.lv_niovecs = 1; - lvhdr.lv_iovecp = &lhdr; - lvhdr.lv_next = ctx->lv_chain; - - error = xlog_write(log, &lvhdr, tic, &ctx->start_lsn, NULL, 0); - if (error) - goto out_abort_free_ticket; - - /* - * now that we've written the checkpoint into the log, strictly - * order the commit records so replay will get them in the right order. - */ -restart: - spin_lock(&cil->xc_push_lock); - list_for_each_entry(new_ctx, &cil->xc_committing, committing) { - /* - * Avoid getting stuck in this loop because we were woken by the - * shutdown, but then went back to sleep once already in the - * shutdown state. - */ - if (XLOG_FORCED_SHUTDOWN(log)) { - spin_unlock(&cil->xc_push_lock); - goto out_abort_free_ticket; - } - - /* - * Higher sequences will wait for this one so skip them. - * Don't wait for our own sequence, either. - */ - if (new_ctx->sequence >= ctx->sequence) - continue; - if (!new_ctx->commit_lsn) { - /* - * It is still being pushed! Wait for the push to - * complete, then start again from the beginning. - */ - xlog_wait(&cil->xc_commit_wait, &cil->xc_push_lock); - goto restart; - } - } - spin_unlock(&cil->xc_push_lock); - - /* xfs_log_done always frees the ticket on error. */ - commit_lsn = xfs_log_done(log->l_mp, tic, &commit_iclog, false); - if (commit_lsn == -1) - goto out_abort; - - /* attach all the transactions w/ busy extents to iclog */ - ctx->log_cb.cb_func = xlog_cil_committed; - ctx->log_cb.cb_arg = ctx; - error = xfs_log_notify(log->l_mp, commit_iclog, &ctx->log_cb); - if (error) - goto out_abort; - - /* - * now the checkpoint commit is complete and we've attached the - * callbacks to the iclog we can assign the commit LSN to the context - * and wake up anyone who is waiting for the commit to complete. - */ - spin_lock(&cil->xc_push_lock); - ctx->commit_lsn = commit_lsn; - wake_up_all(&cil->xc_commit_wait); - spin_unlock(&cil->xc_push_lock); - - /* release the hounds! */ - return xfs_log_release_iclog(log->l_mp, commit_iclog); - -out_skip: - up_write(&cil->xc_ctx_lock); - xfs_log_ticket_put(new_ctx->ticket); - kmem_free(new_ctx); - return 0; - -out_abort_free_ticket: - xfs_log_ticket_put(tic); -out_abort: - xlog_cil_committed(ctx, XFS_LI_ABORTED); - return -EIO; -} - -static void -xlog_cil_push_work( - struct work_struct *work) -{ - struct xfs_cil *cil = container_of(work, struct xfs_cil, - xc_push_work); - xlog_cil_push(cil->xc_log); -} - -/* - * We need to push CIL every so often so we don't cache more than we can fit in - * the log. The limit really is that a checkpoint can't be more than half the - * log (the current checkpoint is not allowed to overwrite the previous - * checkpoint), but commit latency and memory usage limit this to a smaller - * size. - */ -static void -xlog_cil_push_background( - struct xlog *log) -{ - struct xfs_cil *cil = log->l_cilp; - - /* - * The cil won't be empty because we are called while holding the - * context lock so whatever we added to the CIL will still be there - */ - ASSERT(!list_empty(&cil->xc_cil)); - - /* - * don't do a background push if we haven't used up all the - * space available yet. - */ - if (cil->xc_ctx->space_used < XLOG_CIL_SPACE_LIMIT(log)) - return; - - spin_lock(&cil->xc_push_lock); - if (cil->xc_push_seq < cil->xc_current_sequence) { - cil->xc_push_seq = cil->xc_current_sequence; - queue_work(log->l_mp->m_cil_workqueue, &cil->xc_push_work); - } - spin_unlock(&cil->xc_push_lock); - -} - -/* - * xlog_cil_push_now() is used to trigger an immediate CIL push to the sequence - * number that is passed. When it returns, the work will be queued for - * @push_seq, but it won't be completed. The caller is expected to do any - * waiting for push_seq to complete if it is required. - */ -static void -xlog_cil_push_now( - struct xlog *log, - xfs_lsn_t push_seq) -{ - struct xfs_cil *cil = log->l_cilp; - - if (!cil) - return; - - ASSERT(push_seq && push_seq <= cil->xc_current_sequence); - - /* start on any pending background push to minimise wait time on it */ - flush_work(&cil->xc_push_work); - - /* - * If the CIL is empty or we've already pushed the sequence then - * there's no work we need to do. - */ - spin_lock(&cil->xc_push_lock); - if (list_empty(&cil->xc_cil) || push_seq <= cil->xc_push_seq) { - spin_unlock(&cil->xc_push_lock); - return; - } - - cil->xc_push_seq = push_seq; - queue_work(log->l_mp->m_cil_workqueue, &cil->xc_push_work); - spin_unlock(&cil->xc_push_lock); -} - -bool -xlog_cil_empty( - struct xlog *log) -{ - struct xfs_cil *cil = log->l_cilp; - bool empty = false; - - spin_lock(&cil->xc_push_lock); - if (list_empty(&cil->xc_cil)) - empty = true; - spin_unlock(&cil->xc_push_lock); - return empty; -} - -/* - * Commit a transaction with the given vector to the Committed Item List. - * - * To do this, we need to format the item, pin it in memory if required and - * account for the space used by the transaction. Once we have done that we - * need to release the unused reservation for the transaction, attach the - * transaction to the checkpoint context so we carry the busy extents through - * to checkpoint completion, and then unlock all the items in the transaction. - * - * Called with the context lock already held in read mode to lock out - * background commit, returns without it held once background commits are - * allowed again. - */ -void -xfs_log_commit_cil( - struct xfs_mount *mp, - struct xfs_trans *tp, - xfs_lsn_t *commit_lsn, - bool regrant) -{ - struct xlog *log = mp->m_log; - struct xfs_cil *cil = log->l_cilp; - - /* - * Do all necessary memory allocation before we lock the CIL. - * This ensures the allocation does not deadlock with a CIL - * push in memory reclaim (e.g. from kswapd). - */ - xlog_cil_alloc_shadow_bufs(log, tp); - - /* lock out background commit */ - down_read(&cil->xc_ctx_lock); - - xlog_cil_insert_items(log, tp); - - /* check we didn't blow the reservation */ - if (tp->t_ticket->t_curr_res < 0) - xlog_print_tic_res(mp, tp->t_ticket); - - tp->t_commit_lsn = cil->xc_ctx->sequence; - if (commit_lsn) - *commit_lsn = tp->t_commit_lsn; - - xfs_log_done(mp, tp->t_ticket, NULL, regrant); - xfs_trans_unreserve_and_mod_sb(tp); - - /* - * Once all the items of the transaction have been copied to the CIL, - * the items can be unlocked and freed. - * - * This needs to be done before we drop the CIL context lock because we - * have to update state in the log items and unlock them before they go - * to disk. If we don't, then the CIL checkpoint can race with us and - * we can run checkpoint completion before we've updated and unlocked - * the log items. This affects (at least) processing of stale buffers, - * inodes and EFIs. - */ - xfs_trans_free_items(tp, tp->t_commit_lsn, false); - - xlog_cil_push_background(log); - - up_read(&cil->xc_ctx_lock); -} - -/* - * Conditionally push the CIL based on the sequence passed in. - * - * We only need to push if we haven't already pushed the sequence - * number given. Hence the only time we will trigger a push here is - * if the push sequence is the same as the current context. - * - * We return the current commit lsn to allow the callers to determine if a - * iclog flush is necessary following this call. - */ -xfs_lsn_t -xlog_cil_force_lsn( - struct xlog *log, - xfs_lsn_t sequence) -{ - struct xfs_cil *cil = log->l_cilp; - struct xfs_cil_ctx *ctx; - xfs_lsn_t commit_lsn = NULLCOMMITLSN; - - ASSERT(sequence <= cil->xc_current_sequence); - - /* - * check to see if we need to force out the current context. - * xlog_cil_push() handles racing pushes for the same sequence, - * so no need to deal with it here. - */ -restart: - xlog_cil_push_now(log, sequence); - - /* - * See if we can find a previous sequence still committing. - * We need to wait for all previous sequence commits to complete - * before allowing the force of push_seq to go ahead. Hence block - * on commits for those as well. - */ - spin_lock(&cil->xc_push_lock); - list_for_each_entry(ctx, &cil->xc_committing, committing) { - /* - * Avoid getting stuck in this loop because we were woken by the - * shutdown, but then went back to sleep once already in the - * shutdown state. - */ - if (XLOG_FORCED_SHUTDOWN(log)) - goto out_shutdown; - if (ctx->sequence > sequence) - continue; - if (!ctx->commit_lsn) { - /* - * It is still being pushed! Wait for the push to - * complete, then start again from the beginning. - */ - xlog_wait(&cil->xc_commit_wait, &cil->xc_push_lock); - goto restart; - } - if (ctx->sequence != sequence) - continue; - /* found it! */ - commit_lsn = ctx->commit_lsn; - } - - /* - * The call to xlog_cil_push_now() executes the push in the background. - * Hence by the time we have got here it our sequence may not have been - * pushed yet. This is true if the current sequence still matches the - * push sequence after the above wait loop and the CIL still contains - * dirty objects. This is guaranteed by the push code first adding the - * context to the committing list before emptying the CIL. - * - * Hence if we don't find the context in the committing list and the - * current sequence number is unchanged then the CIL contents are - * significant. If the CIL is empty, if means there was nothing to push - * and that means there is nothing to wait for. If the CIL is not empty, - * it means we haven't yet started the push, because if it had started - * we would have found the context on the committing list. - */ - if (sequence == cil->xc_current_sequence && - !list_empty(&cil->xc_cil)) { - spin_unlock(&cil->xc_push_lock); - goto restart; - } - - spin_unlock(&cil->xc_push_lock); - return commit_lsn; - - /* - * We detected a shutdown in progress. We need to trigger the log force - * to pass through it's iclog state machine error handling, even though - * we are already in a shutdown state. Hence we can't return - * NULLCOMMITLSN here as that has special meaning to log forces (i.e. - * LSN is already stable), so we return a zero LSN instead. - */ -out_shutdown: - spin_unlock(&cil->xc_push_lock); - return 0; -} - -/* - * Check if the current log item was first committed in this sequence. - * We can't rely on just the log item being in the CIL, we have to check - * the recorded commit sequence number. - * - * Note: for this to be used in a non-racy manner, it has to be called with - * CIL flushing locked out. As a result, it should only be used during the - * transaction commit process when deciding what to format into the item. - */ -bool -xfs_log_item_in_current_chkpt( - struct xfs_log_item *lip) -{ - struct xfs_cil_ctx *ctx; - - if (list_empty(&lip->li_cil)) - return false; - - ctx = lip->li_mountp->m_log->l_cilp->xc_ctx; - - /* - * li_seq is written on the first commit of a log item to record the - * first checkpoint it is written to. Hence if it is different to the - * current sequence, we're in a new checkpoint. - */ - if (XFS_LSN_CMP(lip->li_seq, ctx->sequence) != 0) - return false; - return true; -} - -/* - * Perform initial CIL structure initialisation. - */ -int -xlog_cil_init( - struct xlog *log) -{ - struct xfs_cil *cil; - struct xfs_cil_ctx *ctx; - - cil = kmem_zalloc(sizeof(*cil), KM_SLEEP|KM_MAYFAIL); - if (!cil) - return -ENOMEM; - - ctx = kmem_zalloc(sizeof(*ctx), KM_SLEEP|KM_MAYFAIL); - if (!ctx) { - kmem_free(cil); - return -ENOMEM; - } - - INIT_WORK(&cil->xc_push_work, xlog_cil_push_work); - INIT_LIST_HEAD(&cil->xc_cil); - INIT_LIST_HEAD(&cil->xc_committing); - spin_lock_init(&cil->xc_cil_lock); - spin_lock_init(&cil->xc_push_lock); - init_rwsem(&cil->xc_ctx_lock); - init_waitqueue_head(&cil->xc_commit_wait); - - INIT_LIST_HEAD(&ctx->committing); - INIT_LIST_HEAD(&ctx->busy_extents); - ctx->sequence = 1; - ctx->cil = cil; - cil->xc_ctx = ctx; - cil->xc_current_sequence = ctx->sequence; - - cil->xc_log = log; - log->l_cilp = cil; - return 0; -} - -void -xlog_cil_destroy( - struct xlog *log) -{ - if (log->l_cilp->xc_ctx) { - if (log->l_cilp->xc_ctx->ticket) - xfs_log_ticket_put(log->l_cilp->xc_ctx->ticket); - kmem_free(log->l_cilp->xc_ctx); - } - - ASSERT(list_empty(&log->l_cilp->xc_cil)); - kmem_free(log->l_cilp); -} - diff --git a/src/linux/fs/xfs/xfs_log_priv.h b/src/linux/fs/xfs/xfs_log_priv.h deleted file mode 100644 index 2b6eec5..0000000 --- a/src/linux/fs/xfs/xfs_log_priv.h +++ /dev/null @@ -1,617 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_LOG_PRIV_H__ -#define __XFS_LOG_PRIV_H__ - -struct xfs_buf; -struct xlog; -struct xlog_ticket; -struct xfs_mount; -struct xfs_log_callback; - -/* - * Flags for log structure - */ -#define XLOG_ACTIVE_RECOVERY 0x2 /* in the middle of recovery */ -#define XLOG_RECOVERY_NEEDED 0x4 /* log was recovered */ -#define XLOG_IO_ERROR 0x8 /* log hit an I/O error, and being - shutdown */ -#define XLOG_TAIL_WARN 0x10 /* log tail verify warning issued */ - -/* - * get client id from packed copy. - * - * this hack is here because the xlog_pack code copies four bytes - * of xlog_op_header containing the fields oh_clientid, oh_flags - * and oh_res2 into the packed copy. - * - * later on this four byte chunk is treated as an int and the - * client id is pulled out. - * - * this has endian issues, of course. - */ -static inline uint xlog_get_client_id(__be32 i) -{ - return be32_to_cpu(i) >> 24; -} - -/* - * In core log state - */ -#define XLOG_STATE_ACTIVE 0x0001 /* Current IC log being written to */ -#define XLOG_STATE_WANT_SYNC 0x0002 /* Want to sync this iclog; no more writes */ -#define XLOG_STATE_SYNCING 0x0004 /* This IC log is syncing */ -#define XLOG_STATE_DONE_SYNC 0x0008 /* Done syncing to disk */ -#define XLOG_STATE_DO_CALLBACK \ - 0x0010 /* Process callback functions */ -#define XLOG_STATE_CALLBACK 0x0020 /* Callback functions now */ -#define XLOG_STATE_DIRTY 0x0040 /* Dirty IC log, not ready for ACTIVE status*/ -#define XLOG_STATE_IOERROR 0x0080 /* IO error happened in sync'ing log */ -#define XLOG_STATE_IOABORT 0x0100 /* force abort on I/O completion (debug) */ -#define XLOG_STATE_ALL 0x7FFF /* All possible valid flags */ -#define XLOG_STATE_NOTUSED 0x8000 /* This IC log not being used */ - -/* - * Flags to log ticket - */ -#define XLOG_TIC_INITED 0x1 /* has been initialized */ -#define XLOG_TIC_PERM_RESERV 0x2 /* permanent reservation */ - -#define XLOG_TIC_FLAGS \ - { XLOG_TIC_INITED, "XLOG_TIC_INITED" }, \ - { XLOG_TIC_PERM_RESERV, "XLOG_TIC_PERM_RESERV" } - -/* - * Below are states for covering allocation transactions. - * By covering, we mean changing the h_tail_lsn in the last on-disk - * log write such that no allocation transactions will be re-done during - * recovery after a system crash. Recovery starts at the last on-disk - * log write. - * - * These states are used to insert dummy log entries to cover - * space allocation transactions which can undo non-transactional changes - * after a crash. Writes to a file with space - * already allocated do not result in any transactions. Allocations - * might include space beyond the EOF. So if we just push the EOF a - * little, the last transaction for the file could contain the wrong - * size. If there is no file system activity, after an allocation - * transaction, and the system crashes, the allocation transaction - * will get replayed and the file will be truncated. This could - * be hours/days/... after the allocation occurred. - * - * The fix for this is to do two dummy transactions when the - * system is idle. We need two dummy transaction because the h_tail_lsn - * in the log record header needs to point beyond the last possible - * non-dummy transaction. The first dummy changes the h_tail_lsn to - * the first transaction before the dummy. The second dummy causes - * h_tail_lsn to point to the first dummy. Recovery starts at h_tail_lsn. - * - * These dummy transactions get committed when everything - * is idle (after there has been some activity). - * - * There are 5 states used to control this. - * - * IDLE -- no logging has been done on the file system or - * we are done covering previous transactions. - * NEED -- logging has occurred and we need a dummy transaction - * when the log becomes idle. - * DONE -- we were in the NEED state and have committed a dummy - * transaction. - * NEED2 -- we detected that a dummy transaction has gone to the - * on disk log with no other transactions. - * DONE2 -- we committed a dummy transaction when in the NEED2 state. - * - * There are two places where we switch states: - * - * 1.) In xfs_sync, when we detect an idle log and are in NEED or NEED2. - * We commit the dummy transaction and switch to DONE or DONE2, - * respectively. In all other states, we don't do anything. - * - * 2.) When we finish writing the on-disk log (xlog_state_clean_log). - * - * No matter what state we are in, if this isn't the dummy - * transaction going out, the next state is NEED. - * So, if we aren't in the DONE or DONE2 states, the next state - * is NEED. We can't be finishing a write of the dummy record - * unless it was committed and the state switched to DONE or DONE2. - * - * If we are in the DONE state and this was a write of the - * dummy transaction, we move to NEED2. - * - * If we are in the DONE2 state and this was a write of the - * dummy transaction, we move to IDLE. - * - * - * Writing only one dummy transaction can get appended to - * one file space allocation. When this happens, the log recovery - * code replays the space allocation and a file could be truncated. - * This is why we have the NEED2 and DONE2 states before going idle. - */ - -#define XLOG_STATE_COVER_IDLE 0 -#define XLOG_STATE_COVER_NEED 1 -#define XLOG_STATE_COVER_DONE 2 -#define XLOG_STATE_COVER_NEED2 3 -#define XLOG_STATE_COVER_DONE2 4 - -#define XLOG_COVER_OPS 5 - -/* Ticket reservation region accounting */ -#define XLOG_TIC_LEN_MAX 15 - -/* - * Reservation region - * As would be stored in xfs_log_iovec but without the i_addr which - * we don't care about. - */ -typedef struct xlog_res { - uint r_len; /* region length :4 */ - uint r_type; /* region's transaction type :4 */ -} xlog_res_t; - -typedef struct xlog_ticket { - struct list_head t_queue; /* reserve/write queue */ - struct task_struct *t_task; /* task that owns this ticket */ - xlog_tid_t t_tid; /* transaction identifier : 4 */ - atomic_t t_ref; /* ticket reference count : 4 */ - int t_curr_res; /* current reservation in bytes : 4 */ - int t_unit_res; /* unit reservation in bytes : 4 */ - char t_ocnt; /* original count : 1 */ - char t_cnt; /* current count : 1 */ - char t_clientid; /* who does this belong to; : 1 */ - char t_flags; /* properties of reservation : 1 */ - - /* reservation array fields */ - uint t_res_num; /* num in array : 4 */ - uint t_res_num_ophdrs; /* num op hdrs : 4 */ - uint t_res_arr_sum; /* array sum : 4 */ - uint t_res_o_flow; /* sum overflow : 4 */ - xlog_res_t t_res_arr[XLOG_TIC_LEN_MAX]; /* array of res : 8 * 15 */ -} xlog_ticket_t; - -/* - * - A log record header is 512 bytes. There is plenty of room to grow the - * xlog_rec_header_t into the reserved space. - * - ic_data follows, so a write to disk can start at the beginning of - * the iclog. - * - ic_forcewait is used to implement synchronous forcing of the iclog to disk. - * - ic_next is the pointer to the next iclog in the ring. - * - ic_bp is a pointer to the buffer used to write this incore log to disk. - * - ic_log is a pointer back to the global log structure. - * - ic_callback is a linked list of callback function/argument pairs to be - * called after an iclog finishes writing. - * - ic_size is the full size of the header plus data. - * - ic_offset is the current number of bytes written to in this iclog. - * - ic_refcnt is bumped when someone is writing to the log. - * - ic_state is the state of the iclog. - * - * Because of cacheline contention on large machines, we need to separate - * various resources onto different cachelines. To start with, make the - * structure cacheline aligned. The following fields can be contended on - * by independent processes: - * - * - ic_callback_* - * - ic_refcnt - * - fields protected by the global l_icloglock - * - * so we need to ensure that these fields are located in separate cachelines. - * We'll put all the read-only and l_icloglock fields in the first cacheline, - * and move everything else out to subsequent cachelines. - */ -typedef struct xlog_in_core { - wait_queue_head_t ic_force_wait; - wait_queue_head_t ic_write_wait; - struct xlog_in_core *ic_next; - struct xlog_in_core *ic_prev; - struct xfs_buf *ic_bp; - struct xlog *ic_log; - int ic_size; - int ic_offset; - int ic_bwritecnt; - unsigned short ic_state; - char *ic_datap; /* pointer to iclog data */ - - /* Callback structures need their own cacheline */ - spinlock_t ic_callback_lock ____cacheline_aligned_in_smp; - struct xfs_log_callback *ic_callback; - struct xfs_log_callback **ic_callback_tail; - - /* reference counts need their own cacheline */ - atomic_t ic_refcnt ____cacheline_aligned_in_smp; - xlog_in_core_2_t *ic_data; -#define ic_header ic_data->hic_header -} xlog_in_core_t; - -/* - * The CIL context is used to aggregate per-transaction details as well be - * passed to the iclog for checkpoint post-commit processing. After being - * passed to the iclog, another context needs to be allocated for tracking the - * next set of transactions to be aggregated into a checkpoint. - */ -struct xfs_cil; - -struct xfs_cil_ctx { - struct xfs_cil *cil; - xfs_lsn_t sequence; /* chkpt sequence # */ - xfs_lsn_t start_lsn; /* first LSN of chkpt commit */ - xfs_lsn_t commit_lsn; /* chkpt commit record lsn */ - struct xlog_ticket *ticket; /* chkpt ticket */ - int nvecs; /* number of regions */ - int space_used; /* aggregate size of regions */ - struct list_head busy_extents; /* busy extents in chkpt */ - struct xfs_log_vec *lv_chain; /* logvecs being pushed */ - struct xfs_log_callback log_cb; /* completion callback hook. */ - struct list_head committing; /* ctx committing list */ -}; - -/* - * Committed Item List structure - * - * This structure is used to track log items that have been committed but not - * yet written into the log. It is used only when the delayed logging mount - * option is enabled. - * - * This structure tracks the list of committing checkpoint contexts so - * we can avoid the problem of having to hold out new transactions during a - * flush until we have a the commit record LSN of the checkpoint. We can - * traverse the list of committing contexts in xlog_cil_push_lsn() to find a - * sequence match and extract the commit LSN directly from there. If the - * checkpoint is still in the process of committing, we can block waiting for - * the commit LSN to be determined as well. This should make synchronous - * operations almost as efficient as the old logging methods. - */ -struct xfs_cil { - struct xlog *xc_log; - struct list_head xc_cil; - spinlock_t xc_cil_lock; - - struct rw_semaphore xc_ctx_lock ____cacheline_aligned_in_smp; - struct xfs_cil_ctx *xc_ctx; - - spinlock_t xc_push_lock ____cacheline_aligned_in_smp; - xfs_lsn_t xc_push_seq; - struct list_head xc_committing; - wait_queue_head_t xc_commit_wait; - xfs_lsn_t xc_current_sequence; - struct work_struct xc_push_work; -} ____cacheline_aligned_in_smp; - -/* - * The amount of log space we allow the CIL to aggregate is difficult to size. - * Whatever we choose, we have to make sure we can get a reservation for the - * log space effectively, that it is large enough to capture sufficient - * relogging to reduce log buffer IO significantly, but it is not too large for - * the log or induces too much latency when writing out through the iclogs. We - * track both space consumed and the number of vectors in the checkpoint - * context, so we need to decide which to use for limiting. - * - * Every log buffer we write out during a push needs a header reserved, which - * is at least one sector and more for v2 logs. Hence we need a reservation of - * at least 512 bytes per 32k of log space just for the LR headers. That means - * 16KB of reservation per megabyte of delayed logging space we will consume, - * plus various headers. The number of headers will vary based on the num of - * io vectors, so limiting on a specific number of vectors is going to result - * in transactions of varying size. IOWs, it is more consistent to track and - * limit space consumed in the log rather than by the number of objects being - * logged in order to prevent checkpoint ticket overruns. - * - * Further, use of static reservations through the log grant mechanism is - * problematic. It introduces a lot of complexity (e.g. reserve grant vs write - * grant) and a significant deadlock potential because regranting write space - * can block on log pushes. Hence if we have to regrant log space during a log - * push, we can deadlock. - * - * However, we can avoid this by use of a dynamic "reservation stealing" - * technique during transaction commit whereby unused reservation space in the - * transaction ticket is transferred to the CIL ctx commit ticket to cover the - * space needed by the checkpoint transaction. This means that we never need to - * specifically reserve space for the CIL checkpoint transaction, nor do we - * need to regrant space once the checkpoint completes. This also means the - * checkpoint transaction ticket is specific to the checkpoint context, rather - * than the CIL itself. - * - * With dynamic reservations, we can effectively make up arbitrary limits for - * the checkpoint size so long as they don't violate any other size rules. - * Recovery imposes a rule that no transaction exceed half the log, so we are - * limited by that. Furthermore, the log transaction reservation subsystem - * tries to keep 25% of the log free, so we need to keep below that limit or we - * risk running out of free log space to start any new transactions. - * - * In order to keep background CIL push efficient, we will set a lower - * threshold at which background pushing is attempted without blocking current - * transaction commits. A separate, higher bound defines when CIL pushes are - * enforced to ensure we stay within our maximum checkpoint size bounds. - * threshold, yet give us plenty of space for aggregation on large logs. - */ -#define XLOG_CIL_SPACE_LIMIT(log) (log->l_logsize >> 3) - -/* - * ticket grant locks, queues and accounting have their own cachlines - * as these are quite hot and can be operated on concurrently. - */ -struct xlog_grant_head { - spinlock_t lock ____cacheline_aligned_in_smp; - struct list_head waiters; - atomic64_t grant; -}; - -/* - * The reservation head lsn is not made up of a cycle number and block number. - * Instead, it uses a cycle number and byte number. Logs don't expect to - * overflow 31 bits worth of byte offset, so using a byte number will mean - * that round off problems won't occur when releasing partial reservations. - */ -struct xlog { - /* The following fields don't need locking */ - struct xfs_mount *l_mp; /* mount point */ - struct xfs_ail *l_ailp; /* AIL log is working with */ - struct xfs_cil *l_cilp; /* CIL log is working with */ - struct xfs_buf *l_xbuf; /* extra buffer for log - * wrapping */ - struct xfs_buftarg *l_targ; /* buftarg of log */ - struct delayed_work l_work; /* background flush work */ - uint l_flags; - uint l_quotaoffs_flag; /* XFS_DQ_*, for QUOTAOFFs */ - struct list_head *l_buf_cancel_table; - int l_iclog_hsize; /* size of iclog header */ - int l_iclog_heads; /* # of iclog header sectors */ - uint l_sectBBsize; /* sector size in BBs (2^n) */ - int l_iclog_size; /* size of log in bytes */ - int l_iclog_size_log; /* log power size of log */ - int l_iclog_bufs; /* number of iclog buffers */ - xfs_daddr_t l_logBBstart; /* start block of log */ - int l_logsize; /* size of log in bytes */ - int l_logBBsize; /* size of log in BB chunks */ - - /* The following block of fields are changed while holding icloglock */ - wait_queue_head_t l_flush_wait ____cacheline_aligned_in_smp; - /* waiting for iclog flush */ - int l_covered_state;/* state of "covering disk - * log entries" */ - xlog_in_core_t *l_iclog; /* head log queue */ - spinlock_t l_icloglock; /* grab to change iclog state */ - int l_curr_cycle; /* Cycle number of log writes */ - int l_prev_cycle; /* Cycle number before last - * block increment */ - int l_curr_block; /* current logical log block */ - int l_prev_block; /* previous logical log block */ - - /* - * l_last_sync_lsn and l_tail_lsn are atomics so they can be set and - * read without needing to hold specific locks. To avoid operations - * contending with other hot objects, place each of them on a separate - * cacheline. - */ - /* lsn of last LR on disk */ - atomic64_t l_last_sync_lsn ____cacheline_aligned_in_smp; - /* lsn of 1st LR with unflushed * buffers */ - atomic64_t l_tail_lsn ____cacheline_aligned_in_smp; - - struct xlog_grant_head l_reserve_head; - struct xlog_grant_head l_write_head; - - struct xfs_kobj l_kobj; - - /* The following field are used for debugging; need to hold icloglock */ -#ifdef DEBUG - void *l_iclog_bak[XLOG_MAX_ICLOGS]; - /* log record crc error injection factor */ - uint32_t l_badcrc_factor; -#endif - /* log recovery lsn tracking (for buffer submission */ - xfs_lsn_t l_recovery_lsn; -}; - -#define XLOG_BUF_CANCEL_BUCKET(log, blkno) \ - ((log)->l_buf_cancel_table + ((__uint64_t)blkno % XLOG_BC_TABLE_SIZE)) - -#define XLOG_FORCED_SHUTDOWN(log) ((log)->l_flags & XLOG_IO_ERROR) - -/* common routines */ -extern int -xlog_recover( - struct xlog *log); -extern int -xlog_recover_finish( - struct xlog *log); -extern int -xlog_recover_cancel(struct xlog *); - -extern __le32 xlog_cksum(struct xlog *log, struct xlog_rec_header *rhead, - char *dp, int size); - -extern kmem_zone_t *xfs_log_ticket_zone; -struct xlog_ticket * -xlog_ticket_alloc( - struct xlog *log, - int unit_bytes, - int count, - char client, - bool permanent, - xfs_km_flags_t alloc_flags); - - -static inline void -xlog_write_adv_cnt(void **ptr, int *len, int *off, size_t bytes) -{ - *ptr += bytes; - *len -= bytes; - *off += bytes; -} - -void xlog_print_tic_res(struct xfs_mount *mp, struct xlog_ticket *ticket); -int -xlog_write( - struct xlog *log, - struct xfs_log_vec *log_vector, - struct xlog_ticket *tic, - xfs_lsn_t *start_lsn, - struct xlog_in_core **commit_iclog, - uint flags); - -/* - * When we crack an atomic LSN, we sample it first so that the value will not - * change while we are cracking it into the component values. This means we - * will always get consistent component values to work from. This should always - * be used to sample and crack LSNs that are stored and updated in atomic - * variables. - */ -static inline void -xlog_crack_atomic_lsn(atomic64_t *lsn, uint *cycle, uint *block) -{ - xfs_lsn_t val = atomic64_read(lsn); - - *cycle = CYCLE_LSN(val); - *block = BLOCK_LSN(val); -} - -/* - * Calculate and assign a value to an atomic LSN variable from component pieces. - */ -static inline void -xlog_assign_atomic_lsn(atomic64_t *lsn, uint cycle, uint block) -{ - atomic64_set(lsn, xlog_assign_lsn(cycle, block)); -} - -/* - * When we crack the grant head, we sample it first so that the value will not - * change while we are cracking it into the component values. This means we - * will always get consistent component values to work from. - */ -static inline void -xlog_crack_grant_head_val(int64_t val, int *cycle, int *space) -{ - *cycle = val >> 32; - *space = val & 0xffffffff; -} - -static inline void -xlog_crack_grant_head(atomic64_t *head, int *cycle, int *space) -{ - xlog_crack_grant_head_val(atomic64_read(head), cycle, space); -} - -static inline int64_t -xlog_assign_grant_head_val(int cycle, int space) -{ - return ((int64_t)cycle << 32) | space; -} - -static inline void -xlog_assign_grant_head(atomic64_t *head, int cycle, int space) -{ - atomic64_set(head, xlog_assign_grant_head_val(cycle, space)); -} - -/* - * Committed Item List interfaces - */ -int xlog_cil_init(struct xlog *log); -void xlog_cil_init_post_recovery(struct xlog *log); -void xlog_cil_destroy(struct xlog *log); -bool xlog_cil_empty(struct xlog *log); - -/* - * CIL force routines - */ -xfs_lsn_t -xlog_cil_force_lsn( - struct xlog *log, - xfs_lsn_t sequence); - -static inline void -xlog_cil_force(struct xlog *log) -{ - xlog_cil_force_lsn(log, log->l_cilp->xc_current_sequence); -} - -/* - * Unmount record type is used as a pseudo transaction type for the ticket. - * It's value must be outside the range of XFS_TRANS_* values. - */ -#define XLOG_UNMOUNT_REC_TYPE (-1U) - -/* - * Wrapper function for waiting on a wait queue serialised against wakeups - * by a spinlock. This matches the semantics of all the wait queues used in the - * log code. - */ -static inline void xlog_wait(wait_queue_head_t *wq, spinlock_t *lock) -{ - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue_exclusive(wq, &wait); - __set_current_state(TASK_UNINTERRUPTIBLE); - spin_unlock(lock); - schedule(); - remove_wait_queue(wq, &wait); -} - -/* - * The LSN is valid so long as it is behind the current LSN. If it isn't, this - * means that the next log record that includes this metadata could have a - * smaller LSN. In turn, this means that the modification in the log would not - * replay. - */ -static inline bool -xlog_valid_lsn( - struct xlog *log, - xfs_lsn_t lsn) -{ - int cur_cycle; - int cur_block; - bool valid = true; - - /* - * First, sample the current lsn without locking to avoid added - * contention from metadata I/O. The current cycle and block are updated - * (in xlog_state_switch_iclogs()) and read here in a particular order - * to avoid false negatives (e.g., thinking the metadata LSN is valid - * when it is not). - * - * The current block is always rewound before the cycle is bumped in - * xlog_state_switch_iclogs() to ensure the current LSN is never seen in - * a transiently forward state. Instead, we can see the LSN in a - * transiently behind state if we happen to race with a cycle wrap. - */ - cur_cycle = ACCESS_ONCE(log->l_curr_cycle); - smp_rmb(); - cur_block = ACCESS_ONCE(log->l_curr_block); - - if ((CYCLE_LSN(lsn) > cur_cycle) || - (CYCLE_LSN(lsn) == cur_cycle && BLOCK_LSN(lsn) > cur_block)) { - /* - * If the metadata LSN appears invalid, it's possible the check - * above raced with a wrap to the next log cycle. Grab the lock - * to check for sure. - */ - spin_lock(&log->l_icloglock); - cur_cycle = log->l_curr_cycle; - cur_block = log->l_curr_block; - spin_unlock(&log->l_icloglock); - - if ((CYCLE_LSN(lsn) > cur_cycle) || - (CYCLE_LSN(lsn) == cur_cycle && BLOCK_LSN(lsn) > cur_block)) - valid = false; - } - - return valid; -} - -#endif /* __XFS_LOG_PRIV_H__ */ diff --git a/src/linux/fs/xfs/xfs_log_recover.c b/src/linux/fs/xfs/xfs_log_recover.c deleted file mode 100644 index 9b3d7c7..0000000 --- a/src/linux/fs/xfs/xfs_log_recover.c +++ /dev/null @@ -1,5808 +0,0 @@ -/* - * Copyright (c) 2000-2006 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_log.h" -#include "xfs_log_priv.h" -#include "xfs_log_recover.h" -#include "xfs_inode_item.h" -#include "xfs_extfree_item.h" -#include "xfs_trans_priv.h" -#include "xfs_alloc.h" -#include "xfs_ialloc.h" -#include "xfs_quota.h" -#include "xfs_cksum.h" -#include "xfs_trace.h" -#include "xfs_icache.h" -#include "xfs_bmap_btree.h" -#include "xfs_error.h" -#include "xfs_dir2.h" -#include "xfs_rmap_item.h" -#include "xfs_buf_item.h" -#include "xfs_refcount_item.h" -#include "xfs_bmap_item.h" - -#define BLK_AVG(blk1, blk2) ((blk1+blk2) >> 1) - -STATIC int -xlog_find_zeroed( - struct xlog *, - xfs_daddr_t *); -STATIC int -xlog_clear_stale_blocks( - struct xlog *, - xfs_lsn_t); -#if defined(DEBUG) -STATIC void -xlog_recover_check_summary( - struct xlog *); -#else -#define xlog_recover_check_summary(log) -#endif -STATIC int -xlog_do_recovery_pass( - struct xlog *, xfs_daddr_t, xfs_daddr_t, int, xfs_daddr_t *); - -/* - * This structure is used during recovery to record the buf log items which - * have been canceled and should not be replayed. - */ -struct xfs_buf_cancel { - xfs_daddr_t bc_blkno; - uint bc_len; - int bc_refcount; - struct list_head bc_list; -}; - -/* - * Sector aligned buffer routines for buffer create/read/write/access - */ - -/* - * Verify the given count of basic blocks is valid number of blocks - * to specify for an operation involving the given XFS log buffer. - * Returns nonzero if the count is valid, 0 otherwise. - */ - -static inline int -xlog_buf_bbcount_valid( - struct xlog *log, - int bbcount) -{ - return bbcount > 0 && bbcount <= log->l_logBBsize; -} - -/* - * Allocate a buffer to hold log data. The buffer needs to be able - * to map to a range of nbblks basic blocks at any valid (basic - * block) offset within the log. - */ -STATIC xfs_buf_t * -xlog_get_bp( - struct xlog *log, - int nbblks) -{ - struct xfs_buf *bp; - - if (!xlog_buf_bbcount_valid(log, nbblks)) { - xfs_warn(log->l_mp, "Invalid block length (0x%x) for buffer", - nbblks); - XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp); - return NULL; - } - - /* - * We do log I/O in units of log sectors (a power-of-2 - * multiple of the basic block size), so we round up the - * requested size to accommodate the basic blocks required - * for complete log sectors. - * - * In addition, the buffer may be used for a non-sector- - * aligned block offset, in which case an I/O of the - * requested size could extend beyond the end of the - * buffer. If the requested size is only 1 basic block it - * will never straddle a sector boundary, so this won't be - * an issue. Nor will this be a problem if the log I/O is - * done in basic blocks (sector size 1). But otherwise we - * extend the buffer by one extra log sector to ensure - * there's space to accommodate this possibility. - */ - if (nbblks > 1 && log->l_sectBBsize > 1) - nbblks += log->l_sectBBsize; - nbblks = round_up(nbblks, log->l_sectBBsize); - - bp = xfs_buf_get_uncached(log->l_mp->m_logdev_targp, nbblks, 0); - if (bp) - xfs_buf_unlock(bp); - return bp; -} - -STATIC void -xlog_put_bp( - xfs_buf_t *bp) -{ - xfs_buf_free(bp); -} - -/* - * Return the address of the start of the given block number's data - * in a log buffer. The buffer covers a log sector-aligned region. - */ -STATIC char * -xlog_align( - struct xlog *log, - xfs_daddr_t blk_no, - int nbblks, - struct xfs_buf *bp) -{ - xfs_daddr_t offset = blk_no & ((xfs_daddr_t)log->l_sectBBsize - 1); - - ASSERT(offset + nbblks <= bp->b_length); - return bp->b_addr + BBTOB(offset); -} - - -/* - * nbblks should be uint, but oh well. Just want to catch that 32-bit length. - */ -STATIC int -xlog_bread_noalign( - struct xlog *log, - xfs_daddr_t blk_no, - int nbblks, - struct xfs_buf *bp) -{ - int error; - - if (!xlog_buf_bbcount_valid(log, nbblks)) { - xfs_warn(log->l_mp, "Invalid block length (0x%x) for buffer", - nbblks); - XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp); - return -EFSCORRUPTED; - } - - blk_no = round_down(blk_no, log->l_sectBBsize); - nbblks = round_up(nbblks, log->l_sectBBsize); - - ASSERT(nbblks > 0); - ASSERT(nbblks <= bp->b_length); - - XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no); - bp->b_flags |= XBF_READ; - bp->b_io_length = nbblks; - bp->b_error = 0; - - error = xfs_buf_submit_wait(bp); - if (error && !XFS_FORCED_SHUTDOWN(log->l_mp)) - xfs_buf_ioerror_alert(bp, __func__); - return error; -} - -STATIC int -xlog_bread( - struct xlog *log, - xfs_daddr_t blk_no, - int nbblks, - struct xfs_buf *bp, - char **offset) -{ - int error; - - error = xlog_bread_noalign(log, blk_no, nbblks, bp); - if (error) - return error; - - *offset = xlog_align(log, blk_no, nbblks, bp); - return 0; -} - -/* - * Read at an offset into the buffer. Returns with the buffer in it's original - * state regardless of the result of the read. - */ -STATIC int -xlog_bread_offset( - struct xlog *log, - xfs_daddr_t blk_no, /* block to read from */ - int nbblks, /* blocks to read */ - struct xfs_buf *bp, - char *offset) -{ - char *orig_offset = bp->b_addr; - int orig_len = BBTOB(bp->b_length); - int error, error2; - - error = xfs_buf_associate_memory(bp, offset, BBTOB(nbblks)); - if (error) - return error; - - error = xlog_bread_noalign(log, blk_no, nbblks, bp); - - /* must reset buffer pointer even on error */ - error2 = xfs_buf_associate_memory(bp, orig_offset, orig_len); - if (error) - return error; - return error2; -} - -/* - * Write out the buffer at the given block for the given number of blocks. - * The buffer is kept locked across the write and is returned locked. - * This can only be used for synchronous log writes. - */ -STATIC int -xlog_bwrite( - struct xlog *log, - xfs_daddr_t blk_no, - int nbblks, - struct xfs_buf *bp) -{ - int error; - - if (!xlog_buf_bbcount_valid(log, nbblks)) { - xfs_warn(log->l_mp, "Invalid block length (0x%x) for buffer", - nbblks); - XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_HIGH, log->l_mp); - return -EFSCORRUPTED; - } - - blk_no = round_down(blk_no, log->l_sectBBsize); - nbblks = round_up(nbblks, log->l_sectBBsize); - - ASSERT(nbblks > 0); - ASSERT(nbblks <= bp->b_length); - - XFS_BUF_SET_ADDR(bp, log->l_logBBstart + blk_no); - xfs_buf_hold(bp); - xfs_buf_lock(bp); - bp->b_io_length = nbblks; - bp->b_error = 0; - - error = xfs_bwrite(bp); - if (error) - xfs_buf_ioerror_alert(bp, __func__); - xfs_buf_relse(bp); - return error; -} - -#ifdef DEBUG -/* - * dump debug superblock and log record information - */ -STATIC void -xlog_header_check_dump( - xfs_mount_t *mp, - xlog_rec_header_t *head) -{ - xfs_debug(mp, "%s: SB : uuid = %pU, fmt = %d", - __func__, &mp->m_sb.sb_uuid, XLOG_FMT); - xfs_debug(mp, " log : uuid = %pU, fmt = %d", - &head->h_fs_uuid, be32_to_cpu(head->h_fmt)); -} -#else -#define xlog_header_check_dump(mp, head) -#endif - -/* - * check log record header for recovery - */ -STATIC int -xlog_header_check_recover( - xfs_mount_t *mp, - xlog_rec_header_t *head) -{ - ASSERT(head->h_magicno == cpu_to_be32(XLOG_HEADER_MAGIC_NUM)); - - /* - * IRIX doesn't write the h_fmt field and leaves it zeroed - * (XLOG_FMT_UNKNOWN). This stops us from trying to recover - * a dirty log created in IRIX. - */ - if (unlikely(head->h_fmt != cpu_to_be32(XLOG_FMT))) { - xfs_warn(mp, - "dirty log written in incompatible format - can't recover"); - xlog_header_check_dump(mp, head); - XFS_ERROR_REPORT("xlog_header_check_recover(1)", - XFS_ERRLEVEL_HIGH, mp); - return -EFSCORRUPTED; - } else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) { - xfs_warn(mp, - "dirty log entry has mismatched uuid - can't recover"); - xlog_header_check_dump(mp, head); - XFS_ERROR_REPORT("xlog_header_check_recover(2)", - XFS_ERRLEVEL_HIGH, mp); - return -EFSCORRUPTED; - } - return 0; -} - -/* - * read the head block of the log and check the header - */ -STATIC int -xlog_header_check_mount( - xfs_mount_t *mp, - xlog_rec_header_t *head) -{ - ASSERT(head->h_magicno == cpu_to_be32(XLOG_HEADER_MAGIC_NUM)); - - if (uuid_is_nil(&head->h_fs_uuid)) { - /* - * IRIX doesn't write the h_fs_uuid or h_fmt fields. If - * h_fs_uuid is nil, we assume this log was last mounted - * by IRIX and continue. - */ - xfs_warn(mp, "nil uuid in log - IRIX style log"); - } else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) { - xfs_warn(mp, "log has mismatched uuid - can't recover"); - xlog_header_check_dump(mp, head); - XFS_ERROR_REPORT("xlog_header_check_mount", - XFS_ERRLEVEL_HIGH, mp); - return -EFSCORRUPTED; - } - return 0; -} - -STATIC void -xlog_recover_iodone( - struct xfs_buf *bp) -{ - if (bp->b_error) { - /* - * We're not going to bother about retrying - * this during recovery. One strike! - */ - if (!XFS_FORCED_SHUTDOWN(bp->b_target->bt_mount)) { - xfs_buf_ioerror_alert(bp, __func__); - xfs_force_shutdown(bp->b_target->bt_mount, - SHUTDOWN_META_IO_ERROR); - } - } - - /* - * On v5 supers, a bli could be attached to update the metadata LSN. - * Clean it up. - */ - if (bp->b_fspriv) - xfs_buf_item_relse(bp); - ASSERT(bp->b_fspriv == NULL); - - bp->b_iodone = NULL; - xfs_buf_ioend(bp); -} - -/* - * This routine finds (to an approximation) the first block in the physical - * log which contains the given cycle. It uses a binary search algorithm. - * Note that the algorithm can not be perfect because the disk will not - * necessarily be perfect. - */ -STATIC int -xlog_find_cycle_start( - struct xlog *log, - struct xfs_buf *bp, - xfs_daddr_t first_blk, - xfs_daddr_t *last_blk, - uint cycle) -{ - char *offset; - xfs_daddr_t mid_blk; - xfs_daddr_t end_blk; - uint mid_cycle; - int error; - - end_blk = *last_blk; - mid_blk = BLK_AVG(first_blk, end_blk); - while (mid_blk != first_blk && mid_blk != end_blk) { - error = xlog_bread(log, mid_blk, 1, bp, &offset); - if (error) - return error; - mid_cycle = xlog_get_cycle(offset); - if (mid_cycle == cycle) - end_blk = mid_blk; /* last_half_cycle == mid_cycle */ - else - first_blk = mid_blk; /* first_half_cycle == mid_cycle */ - mid_blk = BLK_AVG(first_blk, end_blk); - } - ASSERT((mid_blk == first_blk && mid_blk+1 == end_blk) || - (mid_blk == end_blk && mid_blk-1 == first_blk)); - - *last_blk = end_blk; - - return 0; -} - -/* - * Check that a range of blocks does not contain stop_on_cycle_no. - * Fill in *new_blk with the block offset where such a block is - * found, or with -1 (an invalid block number) if there is no such - * block in the range. The scan needs to occur from front to back - * and the pointer into the region must be updated since a later - * routine will need to perform another test. - */ -STATIC int -xlog_find_verify_cycle( - struct xlog *log, - xfs_daddr_t start_blk, - int nbblks, - uint stop_on_cycle_no, - xfs_daddr_t *new_blk) -{ - xfs_daddr_t i, j; - uint cycle; - xfs_buf_t *bp; - xfs_daddr_t bufblks; - char *buf = NULL; - int error = 0; - - /* - * Greedily allocate a buffer big enough to handle the full - * range of basic blocks we'll be examining. If that fails, - * try a smaller size. We need to be able to read at least - * a log sector, or we're out of luck. - */ - bufblks = 1 << ffs(nbblks); - while (bufblks > log->l_logBBsize) - bufblks >>= 1; - while (!(bp = xlog_get_bp(log, bufblks))) { - bufblks >>= 1; - if (bufblks < log->l_sectBBsize) - return -ENOMEM; - } - - for (i = start_blk; i < start_blk + nbblks; i += bufblks) { - int bcount; - - bcount = min(bufblks, (start_blk + nbblks - i)); - - error = xlog_bread(log, i, bcount, bp, &buf); - if (error) - goto out; - - for (j = 0; j < bcount; j++) { - cycle = xlog_get_cycle(buf); - if (cycle == stop_on_cycle_no) { - *new_blk = i+j; - goto out; - } - - buf += BBSIZE; - } - } - - *new_blk = -1; - -out: - xlog_put_bp(bp); - return error; -} - -/* - * Potentially backup over partial log record write. - * - * In the typical case, last_blk is the number of the block directly after - * a good log record. Therefore, we subtract one to get the block number - * of the last block in the given buffer. extra_bblks contains the number - * of blocks we would have read on a previous read. This happens when the - * last log record is split over the end of the physical log. - * - * extra_bblks is the number of blocks potentially verified on a previous - * call to this routine. - */ -STATIC int -xlog_find_verify_log_record( - struct xlog *log, - xfs_daddr_t start_blk, - xfs_daddr_t *last_blk, - int extra_bblks) -{ - xfs_daddr_t i; - xfs_buf_t *bp; - char *offset = NULL; - xlog_rec_header_t *head = NULL; - int error = 0; - int smallmem = 0; - int num_blks = *last_blk - start_blk; - int xhdrs; - - ASSERT(start_blk != 0 || *last_blk != start_blk); - - if (!(bp = xlog_get_bp(log, num_blks))) { - if (!(bp = xlog_get_bp(log, 1))) - return -ENOMEM; - smallmem = 1; - } else { - error = xlog_bread(log, start_blk, num_blks, bp, &offset); - if (error) - goto out; - offset += ((num_blks - 1) << BBSHIFT); - } - - for (i = (*last_blk) - 1; i >= 0; i--) { - if (i < start_blk) { - /* valid log record not found */ - xfs_warn(log->l_mp, - "Log inconsistent (didn't find previous header)"); - ASSERT(0); - error = -EIO; - goto out; - } - - if (smallmem) { - error = xlog_bread(log, i, 1, bp, &offset); - if (error) - goto out; - } - - head = (xlog_rec_header_t *)offset; - - if (head->h_magicno == cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) - break; - - if (!smallmem) - offset -= BBSIZE; - } - - /* - * We hit the beginning of the physical log & still no header. Return - * to caller. If caller can handle a return of -1, then this routine - * will be called again for the end of the physical log. - */ - if (i == -1) { - error = 1; - goto out; - } - - /* - * We have the final block of the good log (the first block - * of the log record _before_ the head. So we check the uuid. - */ - if ((error = xlog_header_check_mount(log->l_mp, head))) - goto out; - - /* - * We may have found a log record header before we expected one. - * last_blk will be the 1st block # with a given cycle #. We may end - * up reading an entire log record. In this case, we don't want to - * reset last_blk. Only when last_blk points in the middle of a log - * record do we update last_blk. - */ - if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) { - uint h_size = be32_to_cpu(head->h_size); - - xhdrs = h_size / XLOG_HEADER_CYCLE_SIZE; - if (h_size % XLOG_HEADER_CYCLE_SIZE) - xhdrs++; - } else { - xhdrs = 1; - } - - if (*last_blk - i + extra_bblks != - BTOBB(be32_to_cpu(head->h_len)) + xhdrs) - *last_blk = i; - -out: - xlog_put_bp(bp); - return error; -} - -/* - * Head is defined to be the point of the log where the next log write - * could go. This means that incomplete LR writes at the end are - * eliminated when calculating the head. We aren't guaranteed that previous - * LR have complete transactions. We only know that a cycle number of - * current cycle number -1 won't be present in the log if we start writing - * from our current block number. - * - * last_blk contains the block number of the first block with a given - * cycle number. - * - * Return: zero if normal, non-zero if error. - */ -STATIC int -xlog_find_head( - struct xlog *log, - xfs_daddr_t *return_head_blk) -{ - xfs_buf_t *bp; - char *offset; - xfs_daddr_t new_blk, first_blk, start_blk, last_blk, head_blk; - int num_scan_bblks; - uint first_half_cycle, last_half_cycle; - uint stop_on_cycle; - int error, log_bbnum = log->l_logBBsize; - - /* Is the end of the log device zeroed? */ - error = xlog_find_zeroed(log, &first_blk); - if (error < 0) { - xfs_warn(log->l_mp, "empty log check failed"); - return error; - } - if (error == 1) { - *return_head_blk = first_blk; - - /* Is the whole lot zeroed? */ - if (!first_blk) { - /* Linux XFS shouldn't generate totally zeroed logs - - * mkfs etc write a dummy unmount record to a fresh - * log so we can store the uuid in there - */ - xfs_warn(log->l_mp, "totally zeroed log"); - } - - return 0; - } - - first_blk = 0; /* get cycle # of 1st block */ - bp = xlog_get_bp(log, 1); - if (!bp) - return -ENOMEM; - - error = xlog_bread(log, 0, 1, bp, &offset); - if (error) - goto bp_err; - - first_half_cycle = xlog_get_cycle(offset); - - last_blk = head_blk = log_bbnum - 1; /* get cycle # of last block */ - error = xlog_bread(log, last_blk, 1, bp, &offset); - if (error) - goto bp_err; - - last_half_cycle = xlog_get_cycle(offset); - ASSERT(last_half_cycle != 0); - - /* - * If the 1st half cycle number is equal to the last half cycle number, - * then the entire log is stamped with the same cycle number. In this - * case, head_blk can't be set to zero (which makes sense). The below - * math doesn't work out properly with head_blk equal to zero. Instead, - * we set it to log_bbnum which is an invalid block number, but this - * value makes the math correct. If head_blk doesn't changed through - * all the tests below, *head_blk is set to zero at the very end rather - * than log_bbnum. In a sense, log_bbnum and zero are the same block - * in a circular file. - */ - if (first_half_cycle == last_half_cycle) { - /* - * In this case we believe that the entire log should have - * cycle number last_half_cycle. We need to scan backwards - * from the end verifying that there are no holes still - * containing last_half_cycle - 1. If we find such a hole, - * then the start of that hole will be the new head. The - * simple case looks like - * x | x ... | x - 1 | x - * Another case that fits this picture would be - * x | x + 1 | x ... | x - * In this case the head really is somewhere at the end of the - * log, as one of the latest writes at the beginning was - * incomplete. - * One more case is - * x | x + 1 | x ... | x - 1 | x - * This is really the combination of the above two cases, and - * the head has to end up at the start of the x-1 hole at the - * end of the log. - * - * In the 256k log case, we will read from the beginning to the - * end of the log and search for cycle numbers equal to x-1. - * We don't worry about the x+1 blocks that we encounter, - * because we know that they cannot be the head since the log - * started with x. - */ - head_blk = log_bbnum; - stop_on_cycle = last_half_cycle - 1; - } else { - /* - * In this case we want to find the first block with cycle - * number matching last_half_cycle. We expect the log to be - * some variation on - * x + 1 ... | x ... | x - * The first block with cycle number x (last_half_cycle) will - * be where the new head belongs. First we do a binary search - * for the first occurrence of last_half_cycle. The binary - * search may not be totally accurate, so then we scan back - * from there looking for occurrences of last_half_cycle before - * us. If that backwards scan wraps around the beginning of - * the log, then we look for occurrences of last_half_cycle - 1 - * at the end of the log. The cases we're looking for look - * like - * v binary search stopped here - * x + 1 ... | x | x + 1 | x ... | x - * ^ but we want to locate this spot - * or - * <---------> less than scan distance - * x + 1 ... | x ... | x - 1 | x - * ^ we want to locate this spot - */ - stop_on_cycle = last_half_cycle; - if ((error = xlog_find_cycle_start(log, bp, first_blk, - &head_blk, last_half_cycle))) - goto bp_err; - } - - /* - * Now validate the answer. Scan back some number of maximum possible - * blocks and make sure each one has the expected cycle number. The - * maximum is determined by the total possible amount of buffering - * in the in-core log. The following number can be made tighter if - * we actually look at the block size of the filesystem. - */ - num_scan_bblks = XLOG_TOTAL_REC_SHIFT(log); - if (head_blk >= num_scan_bblks) { - /* - * We are guaranteed that the entire check can be performed - * in one buffer. - */ - start_blk = head_blk - num_scan_bblks; - if ((error = xlog_find_verify_cycle(log, - start_blk, num_scan_bblks, - stop_on_cycle, &new_blk))) - goto bp_err; - if (new_blk != -1) - head_blk = new_blk; - } else { /* need to read 2 parts of log */ - /* - * We are going to scan backwards in the log in two parts. - * First we scan the physical end of the log. In this part - * of the log, we are looking for blocks with cycle number - * last_half_cycle - 1. - * If we find one, then we know that the log starts there, as - * we've found a hole that didn't get written in going around - * the end of the physical log. The simple case for this is - * x + 1 ... | x ... | x - 1 | x - * <---------> less than scan distance - * If all of the blocks at the end of the log have cycle number - * last_half_cycle, then we check the blocks at the start of - * the log looking for occurrences of last_half_cycle. If we - * find one, then our current estimate for the location of the - * first occurrence of last_half_cycle is wrong and we move - * back to the hole we've found. This case looks like - * x + 1 ... | x | x + 1 | x ... - * ^ binary search stopped here - * Another case we need to handle that only occurs in 256k - * logs is - * x + 1 ... | x ... | x+1 | x ... - * ^ binary search stops here - * In a 256k log, the scan at the end of the log will see the - * x + 1 blocks. We need to skip past those since that is - * certainly not the head of the log. By searching for - * last_half_cycle-1 we accomplish that. - */ - ASSERT(head_blk <= INT_MAX && - (xfs_daddr_t) num_scan_bblks >= head_blk); - start_blk = log_bbnum - (num_scan_bblks - head_blk); - if ((error = xlog_find_verify_cycle(log, start_blk, - num_scan_bblks - (int)head_blk, - (stop_on_cycle - 1), &new_blk))) - goto bp_err; - if (new_blk != -1) { - head_blk = new_blk; - goto validate_head; - } - - /* - * Scan beginning of log now. The last part of the physical - * log is good. This scan needs to verify that it doesn't find - * the last_half_cycle. - */ - start_blk = 0; - ASSERT(head_blk <= INT_MAX); - if ((error = xlog_find_verify_cycle(log, - start_blk, (int)head_blk, - stop_on_cycle, &new_blk))) - goto bp_err; - if (new_blk != -1) - head_blk = new_blk; - } - -validate_head: - /* - * Now we need to make sure head_blk is not pointing to a block in - * the middle of a log record. - */ - num_scan_bblks = XLOG_REC_SHIFT(log); - if (head_blk >= num_scan_bblks) { - start_blk = head_blk - num_scan_bblks; /* don't read head_blk */ - - /* start ptr at last block ptr before head_blk */ - error = xlog_find_verify_log_record(log, start_blk, &head_blk, 0); - if (error == 1) - error = -EIO; - if (error) - goto bp_err; - } else { - start_blk = 0; - ASSERT(head_blk <= INT_MAX); - error = xlog_find_verify_log_record(log, start_blk, &head_blk, 0); - if (error < 0) - goto bp_err; - if (error == 1) { - /* We hit the beginning of the log during our search */ - start_blk = log_bbnum - (num_scan_bblks - head_blk); - new_blk = log_bbnum; - ASSERT(start_blk <= INT_MAX && - (xfs_daddr_t) log_bbnum-start_blk >= 0); - ASSERT(head_blk <= INT_MAX); - error = xlog_find_verify_log_record(log, start_blk, - &new_blk, (int)head_blk); - if (error == 1) - error = -EIO; - if (error) - goto bp_err; - if (new_blk != log_bbnum) - head_blk = new_blk; - } else if (error) - goto bp_err; - } - - xlog_put_bp(bp); - if (head_blk == log_bbnum) - *return_head_blk = 0; - else - *return_head_blk = head_blk; - /* - * When returning here, we have a good block number. Bad block - * means that during a previous crash, we didn't have a clean break - * from cycle number N to cycle number N-1. In this case, we need - * to find the first block with cycle number N-1. - */ - return 0; - - bp_err: - xlog_put_bp(bp); - - if (error) - xfs_warn(log->l_mp, "failed to find log head"); - return error; -} - -/* - * Seek backwards in the log for log record headers. - * - * Given a starting log block, walk backwards until we find the provided number - * of records or hit the provided tail block. The return value is the number of - * records encountered or a negative error code. The log block and buffer - * pointer of the last record seen are returned in rblk and rhead respectively. - */ -STATIC int -xlog_rseek_logrec_hdr( - struct xlog *log, - xfs_daddr_t head_blk, - xfs_daddr_t tail_blk, - int count, - struct xfs_buf *bp, - xfs_daddr_t *rblk, - struct xlog_rec_header **rhead, - bool *wrapped) -{ - int i; - int error; - int found = 0; - char *offset = NULL; - xfs_daddr_t end_blk; - - *wrapped = false; - - /* - * Walk backwards from the head block until we hit the tail or the first - * block in the log. - */ - end_blk = head_blk > tail_blk ? tail_blk : 0; - for (i = (int) head_blk - 1; i >= end_blk; i--) { - error = xlog_bread(log, i, 1, bp, &offset); - if (error) - goto out_error; - - if (*(__be32 *) offset == cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) { - *rblk = i; - *rhead = (struct xlog_rec_header *) offset; - if (++found == count) - break; - } - } - - /* - * If we haven't hit the tail block or the log record header count, - * start looking again from the end of the physical log. Note that - * callers can pass head == tail if the tail is not yet known. - */ - if (tail_blk >= head_blk && found != count) { - for (i = log->l_logBBsize - 1; i >= (int) tail_blk; i--) { - error = xlog_bread(log, i, 1, bp, &offset); - if (error) - goto out_error; - - if (*(__be32 *)offset == - cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) { - *wrapped = true; - *rblk = i; - *rhead = (struct xlog_rec_header *) offset; - if (++found == count) - break; - } - } - } - - return found; - -out_error: - return error; -} - -/* - * Seek forward in the log for log record headers. - * - * Given head and tail blocks, walk forward from the tail block until we find - * the provided number of records or hit the head block. The return value is the - * number of records encountered or a negative error code. The log block and - * buffer pointer of the last record seen are returned in rblk and rhead - * respectively. - */ -STATIC int -xlog_seek_logrec_hdr( - struct xlog *log, - xfs_daddr_t head_blk, - xfs_daddr_t tail_blk, - int count, - struct xfs_buf *bp, - xfs_daddr_t *rblk, - struct xlog_rec_header **rhead, - bool *wrapped) -{ - int i; - int error; - int found = 0; - char *offset = NULL; - xfs_daddr_t end_blk; - - *wrapped = false; - - /* - * Walk forward from the tail block until we hit the head or the last - * block in the log. - */ - end_blk = head_blk > tail_blk ? head_blk : log->l_logBBsize - 1; - for (i = (int) tail_blk; i <= end_blk; i++) { - error = xlog_bread(log, i, 1, bp, &offset); - if (error) - goto out_error; - - if (*(__be32 *) offset == cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) { - *rblk = i; - *rhead = (struct xlog_rec_header *) offset; - if (++found == count) - break; - } - } - - /* - * If we haven't hit the head block or the log record header count, - * start looking again from the start of the physical log. - */ - if (tail_blk > head_blk && found != count) { - for (i = 0; i < (int) head_blk; i++) { - error = xlog_bread(log, i, 1, bp, &offset); - if (error) - goto out_error; - - if (*(__be32 *)offset == - cpu_to_be32(XLOG_HEADER_MAGIC_NUM)) { - *wrapped = true; - *rblk = i; - *rhead = (struct xlog_rec_header *) offset; - if (++found == count) - break; - } - } - } - - return found; - -out_error: - return error; -} - -/* - * Check the log tail for torn writes. This is required when torn writes are - * detected at the head and the head had to be walked back to a previous record. - * The tail of the previous record must now be verified to ensure the torn - * writes didn't corrupt the previous tail. - * - * Return an error if CRC verification fails as recovery cannot proceed. - */ -STATIC int -xlog_verify_tail( - struct xlog *log, - xfs_daddr_t head_blk, - xfs_daddr_t tail_blk) -{ - struct xlog_rec_header *thead; - struct xfs_buf *bp; - xfs_daddr_t first_bad; - int count; - int error = 0; - bool wrapped; - xfs_daddr_t tmp_head; - - bp = xlog_get_bp(log, 1); - if (!bp) - return -ENOMEM; - - /* - * Seek XLOG_MAX_ICLOGS + 1 records past the current tail record to get - * a temporary head block that points after the last possible - * concurrently written record of the tail. - */ - count = xlog_seek_logrec_hdr(log, head_blk, tail_blk, - XLOG_MAX_ICLOGS + 1, bp, &tmp_head, &thead, - &wrapped); - if (count < 0) { - error = count; - goto out; - } - - /* - * If the call above didn't find XLOG_MAX_ICLOGS + 1 records, we ran - * into the actual log head. tmp_head points to the start of the record - * so update it to the actual head block. - */ - if (count < XLOG_MAX_ICLOGS + 1) - tmp_head = head_blk; - - /* - * We now have a tail and temporary head block that covers at least - * XLOG_MAX_ICLOGS records from the tail. We need to verify that these - * records were completely written. Run a CRC verification pass from - * tail to head and return the result. - */ - error = xlog_do_recovery_pass(log, tmp_head, tail_blk, - XLOG_RECOVER_CRCPASS, &first_bad); - -out: - xlog_put_bp(bp); - return error; -} - -/* - * Detect and trim torn writes from the head of the log. - * - * Storage without sector atomicity guarantees can result in torn writes in the - * log in the event of a crash. Our only means to detect this scenario is via - * CRC verification. While we can't always be certain that CRC verification - * failure is due to a torn write vs. an unrelated corruption, we do know that - * only a certain number (XLOG_MAX_ICLOGS) of log records can be written out at - * one time. Therefore, CRC verify up to XLOG_MAX_ICLOGS records at the head of - * the log and treat failures in this range as torn writes as a matter of - * policy. In the event of CRC failure, the head is walked back to the last good - * record in the log and the tail is updated from that record and verified. - */ -STATIC int -xlog_verify_head( - struct xlog *log, - xfs_daddr_t *head_blk, /* in/out: unverified head */ - xfs_daddr_t *tail_blk, /* out: tail block */ - struct xfs_buf *bp, - xfs_daddr_t *rhead_blk, /* start blk of last record */ - struct xlog_rec_header **rhead, /* ptr to last record */ - bool *wrapped) /* last rec. wraps phys. log */ -{ - struct xlog_rec_header *tmp_rhead; - struct xfs_buf *tmp_bp; - xfs_daddr_t first_bad; - xfs_daddr_t tmp_rhead_blk; - int found; - int error; - bool tmp_wrapped; - - /* - * Check the head of the log for torn writes. Search backwards from the - * head until we hit the tail or the maximum number of log record I/Os - * that could have been in flight at one time. Use a temporary buffer so - * we don't trash the rhead/bp pointers from the caller. - */ - tmp_bp = xlog_get_bp(log, 1); - if (!tmp_bp) - return -ENOMEM; - error = xlog_rseek_logrec_hdr(log, *head_blk, *tail_blk, - XLOG_MAX_ICLOGS, tmp_bp, &tmp_rhead_blk, - &tmp_rhead, &tmp_wrapped); - xlog_put_bp(tmp_bp); - if (error < 0) - return error; - - /* - * Now run a CRC verification pass over the records starting at the - * block found above to the current head. If a CRC failure occurs, the - * log block of the first bad record is saved in first_bad. - */ - error = xlog_do_recovery_pass(log, *head_blk, tmp_rhead_blk, - XLOG_RECOVER_CRCPASS, &first_bad); - if (error == -EFSBADCRC) { - /* - * We've hit a potential torn write. Reset the error and warn - * about it. - */ - error = 0; - xfs_warn(log->l_mp, -"Torn write (CRC failure) detected at log block 0x%llx. Truncating head block from 0x%llx.", - first_bad, *head_blk); - - /* - * Get the header block and buffer pointer for the last good - * record before the bad record. - * - * Note that xlog_find_tail() clears the blocks at the new head - * (i.e., the records with invalid CRC) if the cycle number - * matches the the current cycle. - */ - found = xlog_rseek_logrec_hdr(log, first_bad, *tail_blk, 1, bp, - rhead_blk, rhead, wrapped); - if (found < 0) - return found; - if (found == 0) /* XXX: right thing to do here? */ - return -EIO; - - /* - * Reset the head block to the starting block of the first bad - * log record and set the tail block based on the last good - * record. - * - * Bail out if the updated head/tail match as this indicates - * possible corruption outside of the acceptable - * (XLOG_MAX_ICLOGS) range. This is a job for xfs_repair... - */ - *head_blk = first_bad; - *tail_blk = BLOCK_LSN(be64_to_cpu((*rhead)->h_tail_lsn)); - if (*head_blk == *tail_blk) { - ASSERT(0); - return 0; - } - - /* - * Now verify the tail based on the updated head. This is - * required because the torn writes trimmed from the head could - * have been written over the tail of a previous record. Return - * any errors since recovery cannot proceed if the tail is - * corrupt. - * - * XXX: This leaves a gap in truly robust protection from torn - * writes in the log. If the head is behind the tail, the tail - * pushes forward to create some space and then a crash occurs - * causing the writes into the previous record's tail region to - * tear, log recovery isn't able to recover. - * - * How likely is this to occur? If possible, can we do something - * more intelligent here? Is it safe to push the tail forward if - * we can determine that the tail is within the range of the - * torn write (e.g., the kernel can only overwrite the tail if - * it has actually been pushed forward)? Alternatively, could we - * somehow prevent this condition at runtime? - */ - error = xlog_verify_tail(log, *head_blk, *tail_blk); - } - - return error; -} - -/* - * Check whether the head of the log points to an unmount record. In other - * words, determine whether the log is clean. If so, update the in-core state - * appropriately. - */ -static int -xlog_check_unmount_rec( - struct xlog *log, - xfs_daddr_t *head_blk, - xfs_daddr_t *tail_blk, - struct xlog_rec_header *rhead, - xfs_daddr_t rhead_blk, - struct xfs_buf *bp, - bool *clean) -{ - struct xlog_op_header *op_head; - xfs_daddr_t umount_data_blk; - xfs_daddr_t after_umount_blk; - int hblks; - int error; - char *offset; - - *clean = false; - - /* - * Look for unmount record. If we find it, then we know there was a - * clean unmount. Since 'i' could be the last block in the physical - * log, we convert to a log block before comparing to the head_blk. - * - * Save the current tail lsn to use to pass to xlog_clear_stale_blocks() - * below. We won't want to clear the unmount record if there is one, so - * we pass the lsn of the unmount record rather than the block after it. - */ - if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) { - int h_size = be32_to_cpu(rhead->h_size); - int h_version = be32_to_cpu(rhead->h_version); - - if ((h_version & XLOG_VERSION_2) && - (h_size > XLOG_HEADER_CYCLE_SIZE)) { - hblks = h_size / XLOG_HEADER_CYCLE_SIZE; - if (h_size % XLOG_HEADER_CYCLE_SIZE) - hblks++; - } else { - hblks = 1; - } - } else { - hblks = 1; - } - after_umount_blk = rhead_blk + hblks + BTOBB(be32_to_cpu(rhead->h_len)); - after_umount_blk = do_mod(after_umount_blk, log->l_logBBsize); - if (*head_blk == after_umount_blk && - be32_to_cpu(rhead->h_num_logops) == 1) { - umount_data_blk = rhead_blk + hblks; - umount_data_blk = do_mod(umount_data_blk, log->l_logBBsize); - error = xlog_bread(log, umount_data_blk, 1, bp, &offset); - if (error) - return error; - - op_head = (struct xlog_op_header *)offset; - if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) { - /* - * Set tail and last sync so that newly written log - * records will point recovery to after the current - * unmount record. - */ - xlog_assign_atomic_lsn(&log->l_tail_lsn, - log->l_curr_cycle, after_umount_blk); - xlog_assign_atomic_lsn(&log->l_last_sync_lsn, - log->l_curr_cycle, after_umount_blk); - *tail_blk = after_umount_blk; - - *clean = true; - } - } - - return 0; -} - -static void -xlog_set_state( - struct xlog *log, - xfs_daddr_t head_blk, - struct xlog_rec_header *rhead, - xfs_daddr_t rhead_blk, - bool bump_cycle) -{ - /* - * Reset log values according to the state of the log when we - * crashed. In the case where head_blk == 0, we bump curr_cycle - * one because the next write starts a new cycle rather than - * continuing the cycle of the last good log record. At this - * point we have guaranteed that all partial log records have been - * accounted for. Therefore, we know that the last good log record - * written was complete and ended exactly on the end boundary - * of the physical log. - */ - log->l_prev_block = rhead_blk; - log->l_curr_block = (int)head_blk; - log->l_curr_cycle = be32_to_cpu(rhead->h_cycle); - if (bump_cycle) - log->l_curr_cycle++; - atomic64_set(&log->l_tail_lsn, be64_to_cpu(rhead->h_tail_lsn)); - atomic64_set(&log->l_last_sync_lsn, be64_to_cpu(rhead->h_lsn)); - xlog_assign_grant_head(&log->l_reserve_head.grant, log->l_curr_cycle, - BBTOB(log->l_curr_block)); - xlog_assign_grant_head(&log->l_write_head.grant, log->l_curr_cycle, - BBTOB(log->l_curr_block)); -} - -/* - * Find the sync block number or the tail of the log. - * - * This will be the block number of the last record to have its - * associated buffers synced to disk. Every log record header has - * a sync lsn embedded in it. LSNs hold block numbers, so it is easy - * to get a sync block number. The only concern is to figure out which - * log record header to believe. - * - * The following algorithm uses the log record header with the largest - * lsn. The entire log record does not need to be valid. We only care - * that the header is valid. - * - * We could speed up search by using current head_blk buffer, but it is not - * available. - */ -STATIC int -xlog_find_tail( - struct xlog *log, - xfs_daddr_t *head_blk, - xfs_daddr_t *tail_blk) -{ - xlog_rec_header_t *rhead; - char *offset = NULL; - xfs_buf_t *bp; - int error; - xfs_daddr_t rhead_blk; - xfs_lsn_t tail_lsn; - bool wrapped = false; - bool clean = false; - - /* - * Find previous log record - */ - if ((error = xlog_find_head(log, head_blk))) - return error; - ASSERT(*head_blk < INT_MAX); - - bp = xlog_get_bp(log, 1); - if (!bp) - return -ENOMEM; - if (*head_blk == 0) { /* special case */ - error = xlog_bread(log, 0, 1, bp, &offset); - if (error) - goto done; - - if (xlog_get_cycle(offset) == 0) { - *tail_blk = 0; - /* leave all other log inited values alone */ - goto done; - } - } - - /* - * Search backwards through the log looking for the log record header - * block. This wraps all the way back around to the head so something is - * seriously wrong if we can't find it. - */ - error = xlog_rseek_logrec_hdr(log, *head_blk, *head_blk, 1, bp, - &rhead_blk, &rhead, &wrapped); - if (error < 0) - return error; - if (!error) { - xfs_warn(log->l_mp, "%s: couldn't find sync record", __func__); - return -EIO; - } - *tail_blk = BLOCK_LSN(be64_to_cpu(rhead->h_tail_lsn)); - - /* - * Set the log state based on the current head record. - */ - xlog_set_state(log, *head_blk, rhead, rhead_blk, wrapped); - tail_lsn = atomic64_read(&log->l_tail_lsn); - - /* - * Look for an unmount record at the head of the log. This sets the log - * state to determine whether recovery is necessary. - */ - error = xlog_check_unmount_rec(log, head_blk, tail_blk, rhead, - rhead_blk, bp, &clean); - if (error) - goto done; - - /* - * Verify the log head if the log is not clean (e.g., we have anything - * but an unmount record at the head). This uses CRC verification to - * detect and trim torn writes. If discovered, CRC failures are - * considered torn writes and the log head is trimmed accordingly. - * - * Note that we can only run CRC verification when the log is dirty - * because there's no guarantee that the log data behind an unmount - * record is compatible with the current architecture. - */ - if (!clean) { - xfs_daddr_t orig_head = *head_blk; - - error = xlog_verify_head(log, head_blk, tail_blk, bp, - &rhead_blk, &rhead, &wrapped); - if (error) - goto done; - - /* update in-core state again if the head changed */ - if (*head_blk != orig_head) { - xlog_set_state(log, *head_blk, rhead, rhead_blk, - wrapped); - tail_lsn = atomic64_read(&log->l_tail_lsn); - error = xlog_check_unmount_rec(log, head_blk, tail_blk, - rhead, rhead_blk, bp, - &clean); - if (error) - goto done; - } - } - - /* - * Note that the unmount was clean. If the unmount was not clean, we - * need to know this to rebuild the superblock counters from the perag - * headers if we have a filesystem using non-persistent counters. - */ - if (clean) - log->l_mp->m_flags |= XFS_MOUNT_WAS_CLEAN; - - /* - * Make sure that there are no blocks in front of the head - * with the same cycle number as the head. This can happen - * because we allow multiple outstanding log writes concurrently, - * and the later writes might make it out before earlier ones. - * - * We use the lsn from before modifying it so that we'll never - * overwrite the unmount record after a clean unmount. - * - * Do this only if we are going to recover the filesystem - * - * NOTE: This used to say "if (!readonly)" - * However on Linux, we can & do recover a read-only filesystem. - * We only skip recovery if NORECOVERY is specified on mount, - * in which case we would not be here. - * - * But... if the -device- itself is readonly, just skip this. - * We can't recover this device anyway, so it won't matter. - */ - if (!xfs_readonly_buftarg(log->l_mp->m_logdev_targp)) - error = xlog_clear_stale_blocks(log, tail_lsn); - -done: - xlog_put_bp(bp); - - if (error) - xfs_warn(log->l_mp, "failed to locate log tail"); - return error; -} - -/* - * Is the log zeroed at all? - * - * The last binary search should be changed to perform an X block read - * once X becomes small enough. You can then search linearly through - * the X blocks. This will cut down on the number of reads we need to do. - * - * If the log is partially zeroed, this routine will pass back the blkno - * of the first block with cycle number 0. It won't have a complete LR - * preceding it. - * - * Return: - * 0 => the log is completely written to - * 1 => use *blk_no as the first block of the log - * <0 => error has occurred - */ -STATIC int -xlog_find_zeroed( - struct xlog *log, - xfs_daddr_t *blk_no) -{ - xfs_buf_t *bp; - char *offset; - uint first_cycle, last_cycle; - xfs_daddr_t new_blk, last_blk, start_blk; - xfs_daddr_t num_scan_bblks; - int error, log_bbnum = log->l_logBBsize; - - *blk_no = 0; - - /* check totally zeroed log */ - bp = xlog_get_bp(log, 1); - if (!bp) - return -ENOMEM; - error = xlog_bread(log, 0, 1, bp, &offset); - if (error) - goto bp_err; - - first_cycle = xlog_get_cycle(offset); - if (first_cycle == 0) { /* completely zeroed log */ - *blk_no = 0; - xlog_put_bp(bp); - return 1; - } - - /* check partially zeroed log */ - error = xlog_bread(log, log_bbnum-1, 1, bp, &offset); - if (error) - goto bp_err; - - last_cycle = xlog_get_cycle(offset); - if (last_cycle != 0) { /* log completely written to */ - xlog_put_bp(bp); - return 0; - } else if (first_cycle != 1) { - /* - * If the cycle of the last block is zero, the cycle of - * the first block must be 1. If it's not, maybe we're - * not looking at a log... Bail out. - */ - xfs_warn(log->l_mp, - "Log inconsistent or not a log (last==0, first!=1)"); - error = -EINVAL; - goto bp_err; - } - - /* we have a partially zeroed log */ - last_blk = log_bbnum-1; - if ((error = xlog_find_cycle_start(log, bp, 0, &last_blk, 0))) - goto bp_err; - - /* - * Validate the answer. Because there is no way to guarantee that - * the entire log is made up of log records which are the same size, - * we scan over the defined maximum blocks. At this point, the maximum - * is not chosen to mean anything special. XXXmiken - */ - num_scan_bblks = XLOG_TOTAL_REC_SHIFT(log); - ASSERT(num_scan_bblks <= INT_MAX); - - if (last_blk < num_scan_bblks) - num_scan_bblks = last_blk; - start_blk = last_blk - num_scan_bblks; - - /* - * We search for any instances of cycle number 0 that occur before - * our current estimate of the head. What we're trying to detect is - * 1 ... | 0 | 1 | 0... - * ^ binary search ends here - */ - if ((error = xlog_find_verify_cycle(log, start_blk, - (int)num_scan_bblks, 0, &new_blk))) - goto bp_err; - if (new_blk != -1) - last_blk = new_blk; - - /* - * Potentially backup over partial log record write. We don't need - * to search the end of the log because we know it is zero. - */ - error = xlog_find_verify_log_record(log, start_blk, &last_blk, 0); - if (error == 1) - error = -EIO; - if (error) - goto bp_err; - - *blk_no = last_blk; -bp_err: - xlog_put_bp(bp); - if (error) - return error; - return 1; -} - -/* - * These are simple subroutines used by xlog_clear_stale_blocks() below - * to initialize a buffer full of empty log record headers and write - * them into the log. - */ -STATIC void -xlog_add_record( - struct xlog *log, - char *buf, - int cycle, - int block, - int tail_cycle, - int tail_block) -{ - xlog_rec_header_t *recp = (xlog_rec_header_t *)buf; - - memset(buf, 0, BBSIZE); - recp->h_magicno = cpu_to_be32(XLOG_HEADER_MAGIC_NUM); - recp->h_cycle = cpu_to_be32(cycle); - recp->h_version = cpu_to_be32( - xfs_sb_version_haslogv2(&log->l_mp->m_sb) ? 2 : 1); - recp->h_lsn = cpu_to_be64(xlog_assign_lsn(cycle, block)); - recp->h_tail_lsn = cpu_to_be64(xlog_assign_lsn(tail_cycle, tail_block)); - recp->h_fmt = cpu_to_be32(XLOG_FMT); - memcpy(&recp->h_fs_uuid, &log->l_mp->m_sb.sb_uuid, sizeof(uuid_t)); -} - -STATIC int -xlog_write_log_records( - struct xlog *log, - int cycle, - int start_block, - int blocks, - int tail_cycle, - int tail_block) -{ - char *offset; - xfs_buf_t *bp; - int balign, ealign; - int sectbb = log->l_sectBBsize; - int end_block = start_block + blocks; - int bufblks; - int error = 0; - int i, j = 0; - - /* - * Greedily allocate a buffer big enough to handle the full - * range of basic blocks to be written. If that fails, try - * a smaller size. We need to be able to write at least a - * log sector, or we're out of luck. - */ - bufblks = 1 << ffs(blocks); - while (bufblks > log->l_logBBsize) - bufblks >>= 1; - while (!(bp = xlog_get_bp(log, bufblks))) { - bufblks >>= 1; - if (bufblks < sectbb) - return -ENOMEM; - } - - /* We may need to do a read at the start to fill in part of - * the buffer in the starting sector not covered by the first - * write below. - */ - balign = round_down(start_block, sectbb); - if (balign != start_block) { - error = xlog_bread_noalign(log, start_block, 1, bp); - if (error) - goto out_put_bp; - - j = start_block - balign; - } - - for (i = start_block; i < end_block; i += bufblks) { - int bcount, endcount; - - bcount = min(bufblks, end_block - start_block); - endcount = bcount - j; - - /* We may need to do a read at the end to fill in part of - * the buffer in the final sector not covered by the write. - * If this is the same sector as the above read, skip it. - */ - ealign = round_down(end_block, sectbb); - if (j == 0 && (start_block + endcount > ealign)) { - offset = bp->b_addr + BBTOB(ealign - start_block); - error = xlog_bread_offset(log, ealign, sectbb, - bp, offset); - if (error) - break; - - } - - offset = xlog_align(log, start_block, endcount, bp); - for (; j < endcount; j++) { - xlog_add_record(log, offset, cycle, i+j, - tail_cycle, tail_block); - offset += BBSIZE; - } - error = xlog_bwrite(log, start_block, endcount, bp); - if (error) - break; - start_block += endcount; - j = 0; - } - - out_put_bp: - xlog_put_bp(bp); - return error; -} - -/* - * This routine is called to blow away any incomplete log writes out - * in front of the log head. We do this so that we won't become confused - * if we come up, write only a little bit more, and then crash again. - * If we leave the partial log records out there, this situation could - * cause us to think those partial writes are valid blocks since they - * have the current cycle number. We get rid of them by overwriting them - * with empty log records with the old cycle number rather than the - * current one. - * - * The tail lsn is passed in rather than taken from - * the log so that we will not write over the unmount record after a - * clean unmount in a 512 block log. Doing so would leave the log without - * any valid log records in it until a new one was written. If we crashed - * during that time we would not be able to recover. - */ -STATIC int -xlog_clear_stale_blocks( - struct xlog *log, - xfs_lsn_t tail_lsn) -{ - int tail_cycle, head_cycle; - int tail_block, head_block; - int tail_distance, max_distance; - int distance; - int error; - - tail_cycle = CYCLE_LSN(tail_lsn); - tail_block = BLOCK_LSN(tail_lsn); - head_cycle = log->l_curr_cycle; - head_block = log->l_curr_block; - - /* - * Figure out the distance between the new head of the log - * and the tail. We want to write over any blocks beyond the - * head that we may have written just before the crash, but - * we don't want to overwrite the tail of the log. - */ - if (head_cycle == tail_cycle) { - /* - * The tail is behind the head in the physical log, - * so the distance from the head to the tail is the - * distance from the head to the end of the log plus - * the distance from the beginning of the log to the - * tail. - */ - if (unlikely(head_block < tail_block || head_block >= log->l_logBBsize)) { - XFS_ERROR_REPORT("xlog_clear_stale_blocks(1)", - XFS_ERRLEVEL_LOW, log->l_mp); - return -EFSCORRUPTED; - } - tail_distance = tail_block + (log->l_logBBsize - head_block); - } else { - /* - * The head is behind the tail in the physical log, - * so the distance from the head to the tail is just - * the tail block minus the head block. - */ - if (unlikely(head_block >= tail_block || head_cycle != (tail_cycle + 1))){ - XFS_ERROR_REPORT("xlog_clear_stale_blocks(2)", - XFS_ERRLEVEL_LOW, log->l_mp); - return -EFSCORRUPTED; - } - tail_distance = tail_block - head_block; - } - - /* - * If the head is right up against the tail, we can't clear - * anything. - */ - if (tail_distance <= 0) { - ASSERT(tail_distance == 0); - return 0; - } - - max_distance = XLOG_TOTAL_REC_SHIFT(log); - /* - * Take the smaller of the maximum amount of outstanding I/O - * we could have and the distance to the tail to clear out. - * We take the smaller so that we don't overwrite the tail and - * we don't waste all day writing from the head to the tail - * for no reason. - */ - max_distance = MIN(max_distance, tail_distance); - - if ((head_block + max_distance) <= log->l_logBBsize) { - /* - * We can stomp all the blocks we need to without - * wrapping around the end of the log. Just do it - * in a single write. Use the cycle number of the - * current cycle minus one so that the log will look like: - * n ... | n - 1 ... - */ - error = xlog_write_log_records(log, (head_cycle - 1), - head_block, max_distance, tail_cycle, - tail_block); - if (error) - return error; - } else { - /* - * We need to wrap around the end of the physical log in - * order to clear all the blocks. Do it in two separate - * I/Os. The first write should be from the head to the - * end of the physical log, and it should use the current - * cycle number minus one just like above. - */ - distance = log->l_logBBsize - head_block; - error = xlog_write_log_records(log, (head_cycle - 1), - head_block, distance, tail_cycle, - tail_block); - - if (error) - return error; - - /* - * Now write the blocks at the start of the physical log. - * This writes the remainder of the blocks we want to clear. - * It uses the current cycle number since we're now on the - * same cycle as the head so that we get: - * n ... n ... | n - 1 ... - * ^^^^^ blocks we're writing - */ - distance = max_distance - (log->l_logBBsize - head_block); - error = xlog_write_log_records(log, head_cycle, 0, distance, - tail_cycle, tail_block); - if (error) - return error; - } - - return 0; -} - -/****************************************************************************** - * - * Log recover routines - * - ****************************************************************************** - */ - -/* - * Sort the log items in the transaction. - * - * The ordering constraints are defined by the inode allocation and unlink - * behaviour. The rules are: - * - * 1. Every item is only logged once in a given transaction. Hence it - * represents the last logged state of the item. Hence ordering is - * dependent on the order in which operations need to be performed so - * required initial conditions are always met. - * - * 2. Cancelled buffers are recorded in pass 1 in a separate table and - * there's nothing to replay from them so we can simply cull them - * from the transaction. However, we can't do that until after we've - * replayed all the other items because they may be dependent on the - * cancelled buffer and replaying the cancelled buffer can remove it - * form the cancelled buffer table. Hence they have tobe done last. - * - * 3. Inode allocation buffers must be replayed before inode items that - * read the buffer and replay changes into it. For filesystems using the - * ICREATE transactions, this means XFS_LI_ICREATE objects need to get - * treated the same as inode allocation buffers as they create and - * initialise the buffers directly. - * - * 4. Inode unlink buffers must be replayed after inode items are replayed. - * This ensures that inodes are completely flushed to the inode buffer - * in a "free" state before we remove the unlinked inode list pointer. - * - * Hence the ordering needs to be inode allocation buffers first, inode items - * second, inode unlink buffers third and cancelled buffers last. - * - * But there's a problem with that - we can't tell an inode allocation buffer - * apart from a regular buffer, so we can't separate them. We can, however, - * tell an inode unlink buffer from the others, and so we can separate them out - * from all the other buffers and move them to last. - * - * Hence, 4 lists, in order from head to tail: - * - buffer_list for all buffers except cancelled/inode unlink buffers - * - item_list for all non-buffer items - * - inode_buffer_list for inode unlink buffers - * - cancel_list for the cancelled buffers - * - * Note that we add objects to the tail of the lists so that first-to-last - * ordering is preserved within the lists. Adding objects to the head of the - * list means when we traverse from the head we walk them in last-to-first - * order. For cancelled buffers and inode unlink buffers this doesn't matter, - * but for all other items there may be specific ordering that we need to - * preserve. - */ -STATIC int -xlog_recover_reorder_trans( - struct xlog *log, - struct xlog_recover *trans, - int pass) -{ - xlog_recover_item_t *item, *n; - int error = 0; - LIST_HEAD(sort_list); - LIST_HEAD(cancel_list); - LIST_HEAD(buffer_list); - LIST_HEAD(inode_buffer_list); - LIST_HEAD(inode_list); - - list_splice_init(&trans->r_itemq, &sort_list); - list_for_each_entry_safe(item, n, &sort_list, ri_list) { - xfs_buf_log_format_t *buf_f = item->ri_buf[0].i_addr; - - switch (ITEM_TYPE(item)) { - case XFS_LI_ICREATE: - list_move_tail(&item->ri_list, &buffer_list); - break; - case XFS_LI_BUF: - if (buf_f->blf_flags & XFS_BLF_CANCEL) { - trace_xfs_log_recover_item_reorder_head(log, - trans, item, pass); - list_move(&item->ri_list, &cancel_list); - break; - } - if (buf_f->blf_flags & XFS_BLF_INODE_BUF) { - list_move(&item->ri_list, &inode_buffer_list); - break; - } - list_move_tail(&item->ri_list, &buffer_list); - break; - case XFS_LI_INODE: - case XFS_LI_DQUOT: - case XFS_LI_QUOTAOFF: - case XFS_LI_EFD: - case XFS_LI_EFI: - case XFS_LI_RUI: - case XFS_LI_RUD: - case XFS_LI_CUI: - case XFS_LI_CUD: - case XFS_LI_BUI: - case XFS_LI_BUD: - trace_xfs_log_recover_item_reorder_tail(log, - trans, item, pass); - list_move_tail(&item->ri_list, &inode_list); - break; - default: - xfs_warn(log->l_mp, - "%s: unrecognized type of log operation", - __func__); - ASSERT(0); - /* - * return the remaining items back to the transaction - * item list so they can be freed in caller. - */ - if (!list_empty(&sort_list)) - list_splice_init(&sort_list, &trans->r_itemq); - error = -EIO; - goto out; - } - } -out: - ASSERT(list_empty(&sort_list)); - if (!list_empty(&buffer_list)) - list_splice(&buffer_list, &trans->r_itemq); - if (!list_empty(&inode_list)) - list_splice_tail(&inode_list, &trans->r_itemq); - if (!list_empty(&inode_buffer_list)) - list_splice_tail(&inode_buffer_list, &trans->r_itemq); - if (!list_empty(&cancel_list)) - list_splice_tail(&cancel_list, &trans->r_itemq); - return error; -} - -/* - * Build up the table of buf cancel records so that we don't replay - * cancelled data in the second pass. For buffer records that are - * not cancel records, there is nothing to do here so we just return. - * - * If we get a cancel record which is already in the table, this indicates - * that the buffer was cancelled multiple times. In order to ensure - * that during pass 2 we keep the record in the table until we reach its - * last occurrence in the log, we keep a reference count in the cancel - * record in the table to tell us how many times we expect to see this - * record during the second pass. - */ -STATIC int -xlog_recover_buffer_pass1( - struct xlog *log, - struct xlog_recover_item *item) -{ - xfs_buf_log_format_t *buf_f = item->ri_buf[0].i_addr; - struct list_head *bucket; - struct xfs_buf_cancel *bcp; - - /* - * If this isn't a cancel buffer item, then just return. - */ - if (!(buf_f->blf_flags & XFS_BLF_CANCEL)) { - trace_xfs_log_recover_buf_not_cancel(log, buf_f); - return 0; - } - - /* - * Insert an xfs_buf_cancel record into the hash table of them. - * If there is already an identical record, bump its reference count. - */ - bucket = XLOG_BUF_CANCEL_BUCKET(log, buf_f->blf_blkno); - list_for_each_entry(bcp, bucket, bc_list) { - if (bcp->bc_blkno == buf_f->blf_blkno && - bcp->bc_len == buf_f->blf_len) { - bcp->bc_refcount++; - trace_xfs_log_recover_buf_cancel_ref_inc(log, buf_f); - return 0; - } - } - - bcp = kmem_alloc(sizeof(struct xfs_buf_cancel), KM_SLEEP); - bcp->bc_blkno = buf_f->blf_blkno; - bcp->bc_len = buf_f->blf_len; - bcp->bc_refcount = 1; - list_add_tail(&bcp->bc_list, bucket); - - trace_xfs_log_recover_buf_cancel_add(log, buf_f); - return 0; -} - -/* - * Check to see whether the buffer being recovered has a corresponding - * entry in the buffer cancel record table. If it is, return the cancel - * buffer structure to the caller. - */ -STATIC struct xfs_buf_cancel * -xlog_peek_buffer_cancelled( - struct xlog *log, - xfs_daddr_t blkno, - uint len, - ushort flags) -{ - struct list_head *bucket; - struct xfs_buf_cancel *bcp; - - if (!log->l_buf_cancel_table) { - /* empty table means no cancelled buffers in the log */ - ASSERT(!(flags & XFS_BLF_CANCEL)); - return NULL; - } - - bucket = XLOG_BUF_CANCEL_BUCKET(log, blkno); - list_for_each_entry(bcp, bucket, bc_list) { - if (bcp->bc_blkno == blkno && bcp->bc_len == len) - return bcp; - } - - /* - * We didn't find a corresponding entry in the table, so return 0 so - * that the buffer is NOT cancelled. - */ - ASSERT(!(flags & XFS_BLF_CANCEL)); - return NULL; -} - -/* - * If the buffer is being cancelled then return 1 so that it will be cancelled, - * otherwise return 0. If the buffer is actually a buffer cancel item - * (XFS_BLF_CANCEL is set), then decrement the refcount on the entry in the - * table and remove it from the table if this is the last reference. - * - * We remove the cancel record from the table when we encounter its last - * occurrence in the log so that if the same buffer is re-used again after its - * last cancellation we actually replay the changes made at that point. - */ -STATIC int -xlog_check_buffer_cancelled( - struct xlog *log, - xfs_daddr_t blkno, - uint len, - ushort flags) -{ - struct xfs_buf_cancel *bcp; - - bcp = xlog_peek_buffer_cancelled(log, blkno, len, flags); - if (!bcp) - return 0; - - /* - * We've go a match, so return 1 so that the recovery of this buffer - * is cancelled. If this buffer is actually a buffer cancel log - * item, then decrement the refcount on the one in the table and - * remove it if this is the last reference. - */ - if (flags & XFS_BLF_CANCEL) { - if (--bcp->bc_refcount == 0) { - list_del(&bcp->bc_list); - kmem_free(bcp); - } - } - return 1; -} - -/* - * Perform recovery for a buffer full of inodes. In these buffers, the only - * data which should be recovered is that which corresponds to the - * di_next_unlinked pointers in the on disk inode structures. The rest of the - * data for the inodes is always logged through the inodes themselves rather - * than the inode buffer and is recovered in xlog_recover_inode_pass2(). - * - * The only time when buffers full of inodes are fully recovered is when the - * buffer is full of newly allocated inodes. In this case the buffer will - * not be marked as an inode buffer and so will be sent to - * xlog_recover_do_reg_buffer() below during recovery. - */ -STATIC int -xlog_recover_do_inode_buffer( - struct xfs_mount *mp, - xlog_recover_item_t *item, - struct xfs_buf *bp, - xfs_buf_log_format_t *buf_f) -{ - int i; - int item_index = 0; - int bit = 0; - int nbits = 0; - int reg_buf_offset = 0; - int reg_buf_bytes = 0; - int next_unlinked_offset; - int inodes_per_buf; - xfs_agino_t *logged_nextp; - xfs_agino_t *buffer_nextp; - - trace_xfs_log_recover_buf_inode_buf(mp->m_log, buf_f); - - /* - * Post recovery validation only works properly on CRC enabled - * filesystems. - */ - if (xfs_sb_version_hascrc(&mp->m_sb)) - bp->b_ops = &xfs_inode_buf_ops; - - inodes_per_buf = BBTOB(bp->b_io_length) >> mp->m_sb.sb_inodelog; - for (i = 0; i < inodes_per_buf; i++) { - next_unlinked_offset = (i * mp->m_sb.sb_inodesize) + - offsetof(xfs_dinode_t, di_next_unlinked); - - while (next_unlinked_offset >= - (reg_buf_offset + reg_buf_bytes)) { - /* - * The next di_next_unlinked field is beyond - * the current logged region. Find the next - * logged region that contains or is beyond - * the current di_next_unlinked field. - */ - bit += nbits; - bit = xfs_next_bit(buf_f->blf_data_map, - buf_f->blf_map_size, bit); - - /* - * If there are no more logged regions in the - * buffer, then we're done. - */ - if (bit == -1) - return 0; - - nbits = xfs_contig_bits(buf_f->blf_data_map, - buf_f->blf_map_size, bit); - ASSERT(nbits > 0); - reg_buf_offset = bit << XFS_BLF_SHIFT; - reg_buf_bytes = nbits << XFS_BLF_SHIFT; - item_index++; - } - - /* - * If the current logged region starts after the current - * di_next_unlinked field, then move on to the next - * di_next_unlinked field. - */ - if (next_unlinked_offset < reg_buf_offset) - continue; - - ASSERT(item->ri_buf[item_index].i_addr != NULL); - ASSERT((item->ri_buf[item_index].i_len % XFS_BLF_CHUNK) == 0); - ASSERT((reg_buf_offset + reg_buf_bytes) <= - BBTOB(bp->b_io_length)); - - /* - * The current logged region contains a copy of the - * current di_next_unlinked field. Extract its value - * and copy it to the buffer copy. - */ - logged_nextp = item->ri_buf[item_index].i_addr + - next_unlinked_offset - reg_buf_offset; - if (unlikely(*logged_nextp == 0)) { - xfs_alert(mp, - "Bad inode buffer log record (ptr = 0x%p, bp = 0x%p). " - "Trying to replay bad (0) inode di_next_unlinked field.", - item, bp); - XFS_ERROR_REPORT("xlog_recover_do_inode_buf", - XFS_ERRLEVEL_LOW, mp); - return -EFSCORRUPTED; - } - - buffer_nextp = xfs_buf_offset(bp, next_unlinked_offset); - *buffer_nextp = *logged_nextp; - - /* - * If necessary, recalculate the CRC in the on-disk inode. We - * have to leave the inode in a consistent state for whoever - * reads it next.... - */ - xfs_dinode_calc_crc(mp, - xfs_buf_offset(bp, i * mp->m_sb.sb_inodesize)); - - } - - return 0; -} - -/* - * V5 filesystems know the age of the buffer on disk being recovered. We can - * have newer objects on disk than we are replaying, and so for these cases we - * don't want to replay the current change as that will make the buffer contents - * temporarily invalid on disk. - * - * The magic number might not match the buffer type we are going to recover - * (e.g. reallocated blocks), so we ignore the xfs_buf_log_format flags. Hence - * extract the LSN of the existing object in the buffer based on it's current - * magic number. If we don't recognise the magic number in the buffer, then - * return a LSN of -1 so that the caller knows it was an unrecognised block and - * so can recover the buffer. - * - * Note: we cannot rely solely on magic number matches to determine that the - * buffer has a valid LSN - we also need to verify that it belongs to this - * filesystem, so we need to extract the object's LSN and compare it to that - * which we read from the superblock. If the UUIDs don't match, then we've got a - * stale metadata block from an old filesystem instance that we need to recover - * over the top of. - */ -static xfs_lsn_t -xlog_recover_get_buf_lsn( - struct xfs_mount *mp, - struct xfs_buf *bp) -{ - __uint32_t magic32; - __uint16_t magic16; - __uint16_t magicda; - void *blk = bp->b_addr; - uuid_t *uuid; - xfs_lsn_t lsn = -1; - - /* v4 filesystems always recover immediately */ - if (!xfs_sb_version_hascrc(&mp->m_sb)) - goto recover_immediately; - - magic32 = be32_to_cpu(*(__be32 *)blk); - switch (magic32) { - case XFS_ABTB_CRC_MAGIC: - case XFS_ABTC_CRC_MAGIC: - case XFS_ABTB_MAGIC: - case XFS_ABTC_MAGIC: - case XFS_RMAP_CRC_MAGIC: - case XFS_REFC_CRC_MAGIC: - case XFS_IBT_CRC_MAGIC: - case XFS_IBT_MAGIC: { - struct xfs_btree_block *btb = blk; - - lsn = be64_to_cpu(btb->bb_u.s.bb_lsn); - uuid = &btb->bb_u.s.bb_uuid; - break; - } - case XFS_BMAP_CRC_MAGIC: - case XFS_BMAP_MAGIC: { - struct xfs_btree_block *btb = blk; - - lsn = be64_to_cpu(btb->bb_u.l.bb_lsn); - uuid = &btb->bb_u.l.bb_uuid; - break; - } - case XFS_AGF_MAGIC: - lsn = be64_to_cpu(((struct xfs_agf *)blk)->agf_lsn); - uuid = &((struct xfs_agf *)blk)->agf_uuid; - break; - case XFS_AGFL_MAGIC: - lsn = be64_to_cpu(((struct xfs_agfl *)blk)->agfl_lsn); - uuid = &((struct xfs_agfl *)blk)->agfl_uuid; - break; - case XFS_AGI_MAGIC: - lsn = be64_to_cpu(((struct xfs_agi *)blk)->agi_lsn); - uuid = &((struct xfs_agi *)blk)->agi_uuid; - break; - case XFS_SYMLINK_MAGIC: - lsn = be64_to_cpu(((struct xfs_dsymlink_hdr *)blk)->sl_lsn); - uuid = &((struct xfs_dsymlink_hdr *)blk)->sl_uuid; - break; - case XFS_DIR3_BLOCK_MAGIC: - case XFS_DIR3_DATA_MAGIC: - case XFS_DIR3_FREE_MAGIC: - lsn = be64_to_cpu(((struct xfs_dir3_blk_hdr *)blk)->lsn); - uuid = &((struct xfs_dir3_blk_hdr *)blk)->uuid; - break; - case XFS_ATTR3_RMT_MAGIC: - /* - * Remote attr blocks are written synchronously, rather than - * being logged. That means they do not contain a valid LSN - * (i.e. transactionally ordered) in them, and hence any time we - * see a buffer to replay over the top of a remote attribute - * block we should simply do so. - */ - goto recover_immediately; - case XFS_SB_MAGIC: - /* - * superblock uuids are magic. We may or may not have a - * sb_meta_uuid on disk, but it will be set in the in-core - * superblock. We set the uuid pointer for verification - * according to the superblock feature mask to ensure we check - * the relevant UUID in the superblock. - */ - lsn = be64_to_cpu(((struct xfs_dsb *)blk)->sb_lsn); - if (xfs_sb_version_hasmetauuid(&mp->m_sb)) - uuid = &((struct xfs_dsb *)blk)->sb_meta_uuid; - else - uuid = &((struct xfs_dsb *)blk)->sb_uuid; - break; - default: - break; - } - - if (lsn != (xfs_lsn_t)-1) { - if (!uuid_equal(&mp->m_sb.sb_meta_uuid, uuid)) - goto recover_immediately; - return lsn; - } - - magicda = be16_to_cpu(((struct xfs_da_blkinfo *)blk)->magic); - switch (magicda) { - case XFS_DIR3_LEAF1_MAGIC: - case XFS_DIR3_LEAFN_MAGIC: - case XFS_DA3_NODE_MAGIC: - lsn = be64_to_cpu(((struct xfs_da3_blkinfo *)blk)->lsn); - uuid = &((struct xfs_da3_blkinfo *)blk)->uuid; - break; - default: - break; - } - - if (lsn != (xfs_lsn_t)-1) { - if (!uuid_equal(&mp->m_sb.sb_uuid, uuid)) - goto recover_immediately; - return lsn; - } - - /* - * We do individual object checks on dquot and inode buffers as they - * have their own individual LSN records. Also, we could have a stale - * buffer here, so we have to at least recognise these buffer types. - * - * A notd complexity here is inode unlinked list processing - it logs - * the inode directly in the buffer, but we don't know which inodes have - * been modified, and there is no global buffer LSN. Hence we need to - * recover all inode buffer types immediately. This problem will be - * fixed by logical logging of the unlinked list modifications. - */ - magic16 = be16_to_cpu(*(__be16 *)blk); - switch (magic16) { - case XFS_DQUOT_MAGIC: - case XFS_DINODE_MAGIC: - goto recover_immediately; - default: - break; - } - - /* unknown buffer contents, recover immediately */ - -recover_immediately: - return (xfs_lsn_t)-1; - -} - -/* - * Validate the recovered buffer is of the correct type and attach the - * appropriate buffer operations to them for writeback. Magic numbers are in a - * few places: - * the first 16 bits of the buffer (inode buffer, dquot buffer), - * the first 32 bits of the buffer (most blocks), - * inside a struct xfs_da_blkinfo at the start of the buffer. - */ -static void -xlog_recover_validate_buf_type( - struct xfs_mount *mp, - struct xfs_buf *bp, - xfs_buf_log_format_t *buf_f, - xfs_lsn_t current_lsn) -{ - struct xfs_da_blkinfo *info = bp->b_addr; - __uint32_t magic32; - __uint16_t magic16; - __uint16_t magicda; - char *warnmsg = NULL; - - /* - * We can only do post recovery validation on items on CRC enabled - * fielsystems as we need to know when the buffer was written to be able - * to determine if we should have replayed the item. If we replay old - * metadata over a newer buffer, then it will enter a temporarily - * inconsistent state resulting in verification failures. Hence for now - * just avoid the verification stage for non-crc filesystems - */ - if (!xfs_sb_version_hascrc(&mp->m_sb)) - return; - - magic32 = be32_to_cpu(*(__be32 *)bp->b_addr); - magic16 = be16_to_cpu(*(__be16*)bp->b_addr); - magicda = be16_to_cpu(info->magic); - switch (xfs_blft_from_flags(buf_f)) { - case XFS_BLFT_BTREE_BUF: - switch (magic32) { - case XFS_ABTB_CRC_MAGIC: - case XFS_ABTC_CRC_MAGIC: - case XFS_ABTB_MAGIC: - case XFS_ABTC_MAGIC: - bp->b_ops = &xfs_allocbt_buf_ops; - break; - case XFS_IBT_CRC_MAGIC: - case XFS_FIBT_CRC_MAGIC: - case XFS_IBT_MAGIC: - case XFS_FIBT_MAGIC: - bp->b_ops = &xfs_inobt_buf_ops; - break; - case XFS_BMAP_CRC_MAGIC: - case XFS_BMAP_MAGIC: - bp->b_ops = &xfs_bmbt_buf_ops; - break; - case XFS_RMAP_CRC_MAGIC: - bp->b_ops = &xfs_rmapbt_buf_ops; - break; - case XFS_REFC_CRC_MAGIC: - bp->b_ops = &xfs_refcountbt_buf_ops; - break; - default: - warnmsg = "Bad btree block magic!"; - break; - } - break; - case XFS_BLFT_AGF_BUF: - if (magic32 != XFS_AGF_MAGIC) { - warnmsg = "Bad AGF block magic!"; - break; - } - bp->b_ops = &xfs_agf_buf_ops; - break; - case XFS_BLFT_AGFL_BUF: - if (magic32 != XFS_AGFL_MAGIC) { - warnmsg = "Bad AGFL block magic!"; - break; - } - bp->b_ops = &xfs_agfl_buf_ops; - break; - case XFS_BLFT_AGI_BUF: - if (magic32 != XFS_AGI_MAGIC) { - warnmsg = "Bad AGI block magic!"; - break; - } - bp->b_ops = &xfs_agi_buf_ops; - break; - case XFS_BLFT_UDQUOT_BUF: - case XFS_BLFT_PDQUOT_BUF: - case XFS_BLFT_GDQUOT_BUF: -#ifdef CONFIG_XFS_QUOTA - if (magic16 != XFS_DQUOT_MAGIC) { - warnmsg = "Bad DQUOT block magic!"; - break; - } - bp->b_ops = &xfs_dquot_buf_ops; -#else - xfs_alert(mp, - "Trying to recover dquots without QUOTA support built in!"); - ASSERT(0); -#endif - break; - case XFS_BLFT_DINO_BUF: - if (magic16 != XFS_DINODE_MAGIC) { - warnmsg = "Bad INODE block magic!"; - break; - } - bp->b_ops = &xfs_inode_buf_ops; - break; - case XFS_BLFT_SYMLINK_BUF: - if (magic32 != XFS_SYMLINK_MAGIC) { - warnmsg = "Bad symlink block magic!"; - break; - } - bp->b_ops = &xfs_symlink_buf_ops; - break; - case XFS_BLFT_DIR_BLOCK_BUF: - if (magic32 != XFS_DIR2_BLOCK_MAGIC && - magic32 != XFS_DIR3_BLOCK_MAGIC) { - warnmsg = "Bad dir block magic!"; - break; - } - bp->b_ops = &xfs_dir3_block_buf_ops; - break; - case XFS_BLFT_DIR_DATA_BUF: - if (magic32 != XFS_DIR2_DATA_MAGIC && - magic32 != XFS_DIR3_DATA_MAGIC) { - warnmsg = "Bad dir data magic!"; - break; - } - bp->b_ops = &xfs_dir3_data_buf_ops; - break; - case XFS_BLFT_DIR_FREE_BUF: - if (magic32 != XFS_DIR2_FREE_MAGIC && - magic32 != XFS_DIR3_FREE_MAGIC) { - warnmsg = "Bad dir3 free magic!"; - break; - } - bp->b_ops = &xfs_dir3_free_buf_ops; - break; - case XFS_BLFT_DIR_LEAF1_BUF: - if (magicda != XFS_DIR2_LEAF1_MAGIC && - magicda != XFS_DIR3_LEAF1_MAGIC) { - warnmsg = "Bad dir leaf1 magic!"; - break; - } - bp->b_ops = &xfs_dir3_leaf1_buf_ops; - break; - case XFS_BLFT_DIR_LEAFN_BUF: - if (magicda != XFS_DIR2_LEAFN_MAGIC && - magicda != XFS_DIR3_LEAFN_MAGIC) { - warnmsg = "Bad dir leafn magic!"; - break; - } - bp->b_ops = &xfs_dir3_leafn_buf_ops; - break; - case XFS_BLFT_DA_NODE_BUF: - if (magicda != XFS_DA_NODE_MAGIC && - magicda != XFS_DA3_NODE_MAGIC) { - warnmsg = "Bad da node magic!"; - break; - } - bp->b_ops = &xfs_da3_node_buf_ops; - break; - case XFS_BLFT_ATTR_LEAF_BUF: - if (magicda != XFS_ATTR_LEAF_MAGIC && - magicda != XFS_ATTR3_LEAF_MAGIC) { - warnmsg = "Bad attr leaf magic!"; - break; - } - bp->b_ops = &xfs_attr3_leaf_buf_ops; - break; - case XFS_BLFT_ATTR_RMT_BUF: - if (magic32 != XFS_ATTR3_RMT_MAGIC) { - warnmsg = "Bad attr remote magic!"; - break; - } - bp->b_ops = &xfs_attr3_rmt_buf_ops; - break; - case XFS_BLFT_SB_BUF: - if (magic32 != XFS_SB_MAGIC) { - warnmsg = "Bad SB block magic!"; - break; - } - bp->b_ops = &xfs_sb_buf_ops; - break; -#ifdef CONFIG_XFS_RT - case XFS_BLFT_RTBITMAP_BUF: - case XFS_BLFT_RTSUMMARY_BUF: - /* no magic numbers for verification of RT buffers */ - bp->b_ops = &xfs_rtbuf_ops; - break; -#endif /* CONFIG_XFS_RT */ - default: - xfs_warn(mp, "Unknown buffer type %d!", - xfs_blft_from_flags(buf_f)); - break; - } - - /* - * Nothing else to do in the case of a NULL current LSN as this means - * the buffer is more recent than the change in the log and will be - * skipped. - */ - if (current_lsn == NULLCOMMITLSN) - return; - - if (warnmsg) { - xfs_warn(mp, warnmsg); - ASSERT(0); - } - - /* - * We must update the metadata LSN of the buffer as it is written out to - * ensure that older transactions never replay over this one and corrupt - * the buffer. This can occur if log recovery is interrupted at some - * point after the current transaction completes, at which point a - * subsequent mount starts recovery from the beginning. - * - * Write verifiers update the metadata LSN from log items attached to - * the buffer. Therefore, initialize a bli purely to carry the LSN to - * the verifier. We'll clean it up in our ->iodone() callback. - */ - if (bp->b_ops) { - struct xfs_buf_log_item *bip; - - ASSERT(!bp->b_iodone || bp->b_iodone == xlog_recover_iodone); - bp->b_iodone = xlog_recover_iodone; - xfs_buf_item_init(bp, mp); - bip = bp->b_fspriv; - bip->bli_item.li_lsn = current_lsn; - } -} - -/* - * Perform a 'normal' buffer recovery. Each logged region of the - * buffer should be copied over the corresponding region in the - * given buffer. The bitmap in the buf log format structure indicates - * where to place the logged data. - */ -STATIC void -xlog_recover_do_reg_buffer( - struct xfs_mount *mp, - xlog_recover_item_t *item, - struct xfs_buf *bp, - xfs_buf_log_format_t *buf_f, - xfs_lsn_t current_lsn) -{ - int i; - int bit; - int nbits; - int error; - - trace_xfs_log_recover_buf_reg_buf(mp->m_log, buf_f); - - bit = 0; - i = 1; /* 0 is the buf format structure */ - while (1) { - bit = xfs_next_bit(buf_f->blf_data_map, - buf_f->blf_map_size, bit); - if (bit == -1) - break; - nbits = xfs_contig_bits(buf_f->blf_data_map, - buf_f->blf_map_size, bit); - ASSERT(nbits > 0); - ASSERT(item->ri_buf[i].i_addr != NULL); - ASSERT(item->ri_buf[i].i_len % XFS_BLF_CHUNK == 0); - ASSERT(BBTOB(bp->b_io_length) >= - ((uint)bit << XFS_BLF_SHIFT) + (nbits << XFS_BLF_SHIFT)); - - /* - * The dirty regions logged in the buffer, even though - * contiguous, may span multiple chunks. This is because the - * dirty region may span a physical page boundary in a buffer - * and hence be split into two separate vectors for writing into - * the log. Hence we need to trim nbits back to the length of - * the current region being copied out of the log. - */ - if (item->ri_buf[i].i_len < (nbits << XFS_BLF_SHIFT)) - nbits = item->ri_buf[i].i_len >> XFS_BLF_SHIFT; - - /* - * Do a sanity check if this is a dquot buffer. Just checking - * the first dquot in the buffer should do. XXXThis is - * probably a good thing to do for other buf types also. - */ - error = 0; - if (buf_f->blf_flags & - (XFS_BLF_UDQUOT_BUF|XFS_BLF_PDQUOT_BUF|XFS_BLF_GDQUOT_BUF)) { - if (item->ri_buf[i].i_addr == NULL) { - xfs_alert(mp, - "XFS: NULL dquot in %s.", __func__); - goto next; - } - if (item->ri_buf[i].i_len < sizeof(xfs_disk_dquot_t)) { - xfs_alert(mp, - "XFS: dquot too small (%d) in %s.", - item->ri_buf[i].i_len, __func__); - goto next; - } - error = xfs_dqcheck(mp, item->ri_buf[i].i_addr, - -1, 0, XFS_QMOPT_DOWARN, - "dquot_buf_recover"); - if (error) - goto next; - } - - memcpy(xfs_buf_offset(bp, - (uint)bit << XFS_BLF_SHIFT), /* dest */ - item->ri_buf[i].i_addr, /* source */ - nbits<ri_total); - - xlog_recover_validate_buf_type(mp, bp, buf_f, current_lsn); -} - -/* - * Perform a dquot buffer recovery. - * Simple algorithm: if we have found a QUOTAOFF log item of the same type - * (ie. USR or GRP), then just toss this buffer away; don't recover it. - * Else, treat it as a regular buffer and do recovery. - * - * Return false if the buffer was tossed and true if we recovered the buffer to - * indicate to the caller if the buffer needs writing. - */ -STATIC bool -xlog_recover_do_dquot_buffer( - struct xfs_mount *mp, - struct xlog *log, - struct xlog_recover_item *item, - struct xfs_buf *bp, - struct xfs_buf_log_format *buf_f) -{ - uint type; - - trace_xfs_log_recover_buf_dquot_buf(log, buf_f); - - /* - * Filesystems are required to send in quota flags at mount time. - */ - if (!mp->m_qflags) - return false; - - type = 0; - if (buf_f->blf_flags & XFS_BLF_UDQUOT_BUF) - type |= XFS_DQ_USER; - if (buf_f->blf_flags & XFS_BLF_PDQUOT_BUF) - type |= XFS_DQ_PROJ; - if (buf_f->blf_flags & XFS_BLF_GDQUOT_BUF) - type |= XFS_DQ_GROUP; - /* - * This type of quotas was turned off, so ignore this buffer - */ - if (log->l_quotaoffs_flag & type) - return false; - - xlog_recover_do_reg_buffer(mp, item, bp, buf_f, NULLCOMMITLSN); - return true; -} - -/* - * This routine replays a modification made to a buffer at runtime. - * There are actually two types of buffer, regular and inode, which - * are handled differently. Inode buffers are handled differently - * in that we only recover a specific set of data from them, namely - * the inode di_next_unlinked fields. This is because all other inode - * data is actually logged via inode records and any data we replay - * here which overlaps that may be stale. - * - * When meta-data buffers are freed at run time we log a buffer item - * with the XFS_BLF_CANCEL bit set to indicate that previous copies - * of the buffer in the log should not be replayed at recovery time. - * This is so that if the blocks covered by the buffer are reused for - * file data before we crash we don't end up replaying old, freed - * meta-data into a user's file. - * - * To handle the cancellation of buffer log items, we make two passes - * over the log during recovery. During the first we build a table of - * those buffers which have been cancelled, and during the second we - * only replay those buffers which do not have corresponding cancel - * records in the table. See xlog_recover_buffer_pass[1,2] above - * for more details on the implementation of the table of cancel records. - */ -STATIC int -xlog_recover_buffer_pass2( - struct xlog *log, - struct list_head *buffer_list, - struct xlog_recover_item *item, - xfs_lsn_t current_lsn) -{ - xfs_buf_log_format_t *buf_f = item->ri_buf[0].i_addr; - xfs_mount_t *mp = log->l_mp; - xfs_buf_t *bp; - int error; - uint buf_flags; - xfs_lsn_t lsn; - - /* - * In this pass we only want to recover all the buffers which have - * not been cancelled and are not cancellation buffers themselves. - */ - if (xlog_check_buffer_cancelled(log, buf_f->blf_blkno, - buf_f->blf_len, buf_f->blf_flags)) { - trace_xfs_log_recover_buf_cancel(log, buf_f); - return 0; - } - - trace_xfs_log_recover_buf_recover(log, buf_f); - - buf_flags = 0; - if (buf_f->blf_flags & XFS_BLF_INODE_BUF) - buf_flags |= XBF_UNMAPPED; - - bp = xfs_buf_read(mp->m_ddev_targp, buf_f->blf_blkno, buf_f->blf_len, - buf_flags, NULL); - if (!bp) - return -ENOMEM; - error = bp->b_error; - if (error) { - xfs_buf_ioerror_alert(bp, "xlog_recover_do..(read#1)"); - goto out_release; - } - - /* - * Recover the buffer only if we get an LSN from it and it's less than - * the lsn of the transaction we are replaying. - * - * Note that we have to be extremely careful of readahead here. - * Readahead does not attach verfiers to the buffers so if we don't - * actually do any replay after readahead because of the LSN we found - * in the buffer if more recent than that current transaction then we - * need to attach the verifier directly. Failure to do so can lead to - * future recovery actions (e.g. EFI and unlinked list recovery) can - * operate on the buffers and they won't get the verifier attached. This - * can lead to blocks on disk having the correct content but a stale - * CRC. - * - * It is safe to assume these clean buffers are currently up to date. - * If the buffer is dirtied by a later transaction being replayed, then - * the verifier will be reset to match whatever recover turns that - * buffer into. - */ - lsn = xlog_recover_get_buf_lsn(mp, bp); - if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) { - trace_xfs_log_recover_buf_skip(log, buf_f); - xlog_recover_validate_buf_type(mp, bp, buf_f, NULLCOMMITLSN); - goto out_release; - } - - if (buf_f->blf_flags & XFS_BLF_INODE_BUF) { - error = xlog_recover_do_inode_buffer(mp, item, bp, buf_f); - if (error) - goto out_release; - } else if (buf_f->blf_flags & - (XFS_BLF_UDQUOT_BUF|XFS_BLF_PDQUOT_BUF|XFS_BLF_GDQUOT_BUF)) { - bool dirty; - - dirty = xlog_recover_do_dquot_buffer(mp, log, item, bp, buf_f); - if (!dirty) - goto out_release; - } else { - xlog_recover_do_reg_buffer(mp, item, bp, buf_f, current_lsn); - } - - /* - * Perform delayed write on the buffer. Asynchronous writes will be - * slower when taking into account all the buffers to be flushed. - * - * Also make sure that only inode buffers with good sizes stay in - * the buffer cache. The kernel moves inodes in buffers of 1 block - * or mp->m_inode_cluster_size bytes, whichever is bigger. The inode - * buffers in the log can be a different size if the log was generated - * by an older kernel using unclustered inode buffers or a newer kernel - * running with a different inode cluster size. Regardless, if the - * the inode buffer size isn't MAX(blocksize, mp->m_inode_cluster_size) - * for *our* value of mp->m_inode_cluster_size, then we need to keep - * the buffer out of the buffer cache so that the buffer won't - * overlap with future reads of those inodes. - */ - if (XFS_DINODE_MAGIC == - be16_to_cpu(*((__be16 *)xfs_buf_offset(bp, 0))) && - (BBTOB(bp->b_io_length) != MAX(log->l_mp->m_sb.sb_blocksize, - (__uint32_t)log->l_mp->m_inode_cluster_size))) { - xfs_buf_stale(bp); - error = xfs_bwrite(bp); - } else { - ASSERT(bp->b_target->bt_mount == mp); - bp->b_iodone = xlog_recover_iodone; - xfs_buf_delwri_queue(bp, buffer_list); - } - -out_release: - xfs_buf_relse(bp); - return error; -} - -/* - * Inode fork owner changes - * - * If we have been told that we have to reparent the inode fork, it's because an - * extent swap operation on a CRC enabled filesystem has been done and we are - * replaying it. We need to walk the BMBT of the appropriate fork and change the - * owners of it. - * - * The complexity here is that we don't have an inode context to work with, so - * after we've replayed the inode we need to instantiate one. This is where the - * fun begins. - * - * We are in the middle of log recovery, so we can't run transactions. That - * means we cannot use cache coherent inode instantiation via xfs_iget(), as - * that will result in the corresponding iput() running the inode through - * xfs_inactive(). If we've just replayed an inode core that changes the link - * count to zero (i.e. it's been unlinked), then xfs_inactive() will run - * transactions (bad!). - * - * So, to avoid this, we instantiate an inode directly from the inode core we've - * just recovered. We have the buffer still locked, and all we really need to - * instantiate is the inode core and the forks being modified. We can do this - * manually, then run the inode btree owner change, and then tear down the - * xfs_inode without having to run any transactions at all. - * - * Also, because we don't have a transaction context available here but need to - * gather all the buffers we modify for writeback so we pass the buffer_list - * instead for the operation to use. - */ - -STATIC int -xfs_recover_inode_owner_change( - struct xfs_mount *mp, - struct xfs_dinode *dip, - struct xfs_inode_log_format *in_f, - struct list_head *buffer_list) -{ - struct xfs_inode *ip; - int error; - - ASSERT(in_f->ilf_fields & (XFS_ILOG_DOWNER|XFS_ILOG_AOWNER)); - - ip = xfs_inode_alloc(mp, in_f->ilf_ino); - if (!ip) - return -ENOMEM; - - /* instantiate the inode */ - xfs_inode_from_disk(ip, dip); - ASSERT(ip->i_d.di_version >= 3); - - error = xfs_iformat_fork(ip, dip); - if (error) - goto out_free_ip; - - - if (in_f->ilf_fields & XFS_ILOG_DOWNER) { - ASSERT(in_f->ilf_fields & XFS_ILOG_DBROOT); - error = xfs_bmbt_change_owner(NULL, ip, XFS_DATA_FORK, - ip->i_ino, buffer_list); - if (error) - goto out_free_ip; - } - - if (in_f->ilf_fields & XFS_ILOG_AOWNER) { - ASSERT(in_f->ilf_fields & XFS_ILOG_ABROOT); - error = xfs_bmbt_change_owner(NULL, ip, XFS_ATTR_FORK, - ip->i_ino, buffer_list); - if (error) - goto out_free_ip; - } - -out_free_ip: - xfs_inode_free(ip); - return error; -} - -STATIC int -xlog_recover_inode_pass2( - struct xlog *log, - struct list_head *buffer_list, - struct xlog_recover_item *item, - xfs_lsn_t current_lsn) -{ - xfs_inode_log_format_t *in_f; - xfs_mount_t *mp = log->l_mp; - xfs_buf_t *bp; - xfs_dinode_t *dip; - int len; - char *src; - char *dest; - int error; - int attr_index; - uint fields; - struct xfs_log_dinode *ldip; - uint isize; - int need_free = 0; - - if (item->ri_buf[0].i_len == sizeof(xfs_inode_log_format_t)) { - in_f = item->ri_buf[0].i_addr; - } else { - in_f = kmem_alloc(sizeof(xfs_inode_log_format_t), KM_SLEEP); - need_free = 1; - error = xfs_inode_item_format_convert(&item->ri_buf[0], in_f); - if (error) - goto error; - } - - /* - * Inode buffers can be freed, look out for it, - * and do not replay the inode. - */ - if (xlog_check_buffer_cancelled(log, in_f->ilf_blkno, - in_f->ilf_len, 0)) { - error = 0; - trace_xfs_log_recover_inode_cancel(log, in_f); - goto error; - } - trace_xfs_log_recover_inode_recover(log, in_f); - - bp = xfs_buf_read(mp->m_ddev_targp, in_f->ilf_blkno, in_f->ilf_len, 0, - &xfs_inode_buf_ops); - if (!bp) { - error = -ENOMEM; - goto error; - } - error = bp->b_error; - if (error) { - xfs_buf_ioerror_alert(bp, "xlog_recover_do..(read#2)"); - goto out_release; - } - ASSERT(in_f->ilf_fields & XFS_ILOG_CORE); - dip = xfs_buf_offset(bp, in_f->ilf_boffset); - - /* - * Make sure the place we're flushing out to really looks - * like an inode! - */ - if (unlikely(dip->di_magic != cpu_to_be16(XFS_DINODE_MAGIC))) { - xfs_alert(mp, - "%s: Bad inode magic number, dip = 0x%p, dino bp = 0x%p, ino = %Ld", - __func__, dip, bp, in_f->ilf_ino); - XFS_ERROR_REPORT("xlog_recover_inode_pass2(1)", - XFS_ERRLEVEL_LOW, mp); - error = -EFSCORRUPTED; - goto out_release; - } - ldip = item->ri_buf[1].i_addr; - if (unlikely(ldip->di_magic != XFS_DINODE_MAGIC)) { - xfs_alert(mp, - "%s: Bad inode log record, rec ptr 0x%p, ino %Ld", - __func__, item, in_f->ilf_ino); - XFS_ERROR_REPORT("xlog_recover_inode_pass2(2)", - XFS_ERRLEVEL_LOW, mp); - error = -EFSCORRUPTED; - goto out_release; - } - - /* - * If the inode has an LSN in it, recover the inode only if it's less - * than the lsn of the transaction we are replaying. Note: we still - * need to replay an owner change even though the inode is more recent - * than the transaction as there is no guarantee that all the btree - * blocks are more recent than this transaction, too. - */ - if (dip->di_version >= 3) { - xfs_lsn_t lsn = be64_to_cpu(dip->di_lsn); - - if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) { - trace_xfs_log_recover_inode_skip(log, in_f); - error = 0; - goto out_owner_change; - } - } - - /* - * di_flushiter is only valid for v1/2 inodes. All changes for v3 inodes - * are transactional and if ordering is necessary we can determine that - * more accurately by the LSN field in the V3 inode core. Don't trust - * the inode versions we might be changing them here - use the - * superblock flag to determine whether we need to look at di_flushiter - * to skip replay when the on disk inode is newer than the log one - */ - if (!xfs_sb_version_hascrc(&mp->m_sb) && - ldip->di_flushiter < be16_to_cpu(dip->di_flushiter)) { - /* - * Deal with the wrap case, DI_MAX_FLUSH is less - * than smaller numbers - */ - if (be16_to_cpu(dip->di_flushiter) == DI_MAX_FLUSH && - ldip->di_flushiter < (DI_MAX_FLUSH >> 1)) { - /* do nothing */ - } else { - trace_xfs_log_recover_inode_skip(log, in_f); - error = 0; - goto out_release; - } - } - - /* Take the opportunity to reset the flush iteration count */ - ldip->di_flushiter = 0; - - if (unlikely(S_ISREG(ldip->di_mode))) { - if ((ldip->di_format != XFS_DINODE_FMT_EXTENTS) && - (ldip->di_format != XFS_DINODE_FMT_BTREE)) { - XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(3)", - XFS_ERRLEVEL_LOW, mp, ldip); - xfs_alert(mp, - "%s: Bad regular inode log record, rec ptr 0x%p, " - "ino ptr = 0x%p, ino bp = 0x%p, ino %Ld", - __func__, item, dip, bp, in_f->ilf_ino); - error = -EFSCORRUPTED; - goto out_release; - } - } else if (unlikely(S_ISDIR(ldip->di_mode))) { - if ((ldip->di_format != XFS_DINODE_FMT_EXTENTS) && - (ldip->di_format != XFS_DINODE_FMT_BTREE) && - (ldip->di_format != XFS_DINODE_FMT_LOCAL)) { - XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(4)", - XFS_ERRLEVEL_LOW, mp, ldip); - xfs_alert(mp, - "%s: Bad dir inode log record, rec ptr 0x%p, " - "ino ptr = 0x%p, ino bp = 0x%p, ino %Ld", - __func__, item, dip, bp, in_f->ilf_ino); - error = -EFSCORRUPTED; - goto out_release; - } - } - if (unlikely(ldip->di_nextents + ldip->di_anextents > ldip->di_nblocks)){ - XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(5)", - XFS_ERRLEVEL_LOW, mp, ldip); - xfs_alert(mp, - "%s: Bad inode log record, rec ptr 0x%p, dino ptr 0x%p, " - "dino bp 0x%p, ino %Ld, total extents = %d, nblocks = %Ld", - __func__, item, dip, bp, in_f->ilf_ino, - ldip->di_nextents + ldip->di_anextents, - ldip->di_nblocks); - error = -EFSCORRUPTED; - goto out_release; - } - if (unlikely(ldip->di_forkoff > mp->m_sb.sb_inodesize)) { - XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(6)", - XFS_ERRLEVEL_LOW, mp, ldip); - xfs_alert(mp, - "%s: Bad inode log record, rec ptr 0x%p, dino ptr 0x%p, " - "dino bp 0x%p, ino %Ld, forkoff 0x%x", __func__, - item, dip, bp, in_f->ilf_ino, ldip->di_forkoff); - error = -EFSCORRUPTED; - goto out_release; - } - isize = xfs_log_dinode_size(ldip->di_version); - if (unlikely(item->ri_buf[1].i_len > isize)) { - XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(7)", - XFS_ERRLEVEL_LOW, mp, ldip); - xfs_alert(mp, - "%s: Bad inode log record length %d, rec ptr 0x%p", - __func__, item->ri_buf[1].i_len, item); - error = -EFSCORRUPTED; - goto out_release; - } - - /* recover the log dinode inode into the on disk inode */ - xfs_log_dinode_to_disk(ldip, dip); - - /* the rest is in on-disk format */ - if (item->ri_buf[1].i_len > isize) { - memcpy((char *)dip + isize, - item->ri_buf[1].i_addr + isize, - item->ri_buf[1].i_len - isize); - } - - fields = in_f->ilf_fields; - switch (fields & (XFS_ILOG_DEV | XFS_ILOG_UUID)) { - case XFS_ILOG_DEV: - xfs_dinode_put_rdev(dip, in_f->ilf_u.ilfu_rdev); - break; - case XFS_ILOG_UUID: - memcpy(XFS_DFORK_DPTR(dip), - &in_f->ilf_u.ilfu_uuid, - sizeof(uuid_t)); - break; - } - - if (in_f->ilf_size == 2) - goto out_owner_change; - len = item->ri_buf[2].i_len; - src = item->ri_buf[2].i_addr; - ASSERT(in_f->ilf_size <= 4); - ASSERT((in_f->ilf_size == 3) || (fields & XFS_ILOG_AFORK)); - ASSERT(!(fields & XFS_ILOG_DFORK) || - (len == in_f->ilf_dsize)); - - switch (fields & XFS_ILOG_DFORK) { - case XFS_ILOG_DDATA: - case XFS_ILOG_DEXT: - memcpy(XFS_DFORK_DPTR(dip), src, len); - break; - - case XFS_ILOG_DBROOT: - xfs_bmbt_to_bmdr(mp, (struct xfs_btree_block *)src, len, - (xfs_bmdr_block_t *)XFS_DFORK_DPTR(dip), - XFS_DFORK_DSIZE(dip, mp)); - break; - - default: - /* - * There are no data fork flags set. - */ - ASSERT((fields & XFS_ILOG_DFORK) == 0); - break; - } - - /* - * If we logged any attribute data, recover it. There may or - * may not have been any other non-core data logged in this - * transaction. - */ - if (in_f->ilf_fields & XFS_ILOG_AFORK) { - if (in_f->ilf_fields & XFS_ILOG_DFORK) { - attr_index = 3; - } else { - attr_index = 2; - } - len = item->ri_buf[attr_index].i_len; - src = item->ri_buf[attr_index].i_addr; - ASSERT(len == in_f->ilf_asize); - - switch (in_f->ilf_fields & XFS_ILOG_AFORK) { - case XFS_ILOG_ADATA: - case XFS_ILOG_AEXT: - dest = XFS_DFORK_APTR(dip); - ASSERT(len <= XFS_DFORK_ASIZE(dip, mp)); - memcpy(dest, src, len); - break; - - case XFS_ILOG_ABROOT: - dest = XFS_DFORK_APTR(dip); - xfs_bmbt_to_bmdr(mp, (struct xfs_btree_block *)src, - len, (xfs_bmdr_block_t*)dest, - XFS_DFORK_ASIZE(dip, mp)); - break; - - default: - xfs_warn(log->l_mp, "%s: Invalid flag", __func__); - ASSERT(0); - error = -EIO; - goto out_release; - } - } - -out_owner_change: - if (in_f->ilf_fields & (XFS_ILOG_DOWNER|XFS_ILOG_AOWNER)) - error = xfs_recover_inode_owner_change(mp, dip, in_f, - buffer_list); - /* re-generate the checksum. */ - xfs_dinode_calc_crc(log->l_mp, dip); - - ASSERT(bp->b_target->bt_mount == mp); - bp->b_iodone = xlog_recover_iodone; - xfs_buf_delwri_queue(bp, buffer_list); - -out_release: - xfs_buf_relse(bp); -error: - if (need_free) - kmem_free(in_f); - return error; -} - -/* - * Recover QUOTAOFF records. We simply make a note of it in the xlog - * structure, so that we know not to do any dquot item or dquot buffer recovery, - * of that type. - */ -STATIC int -xlog_recover_quotaoff_pass1( - struct xlog *log, - struct xlog_recover_item *item) -{ - xfs_qoff_logformat_t *qoff_f = item->ri_buf[0].i_addr; - ASSERT(qoff_f); - - /* - * The logitem format's flag tells us if this was user quotaoff, - * group/project quotaoff or both. - */ - if (qoff_f->qf_flags & XFS_UQUOTA_ACCT) - log->l_quotaoffs_flag |= XFS_DQ_USER; - if (qoff_f->qf_flags & XFS_PQUOTA_ACCT) - log->l_quotaoffs_flag |= XFS_DQ_PROJ; - if (qoff_f->qf_flags & XFS_GQUOTA_ACCT) - log->l_quotaoffs_flag |= XFS_DQ_GROUP; - - return 0; -} - -/* - * Recover a dquot record - */ -STATIC int -xlog_recover_dquot_pass2( - struct xlog *log, - struct list_head *buffer_list, - struct xlog_recover_item *item, - xfs_lsn_t current_lsn) -{ - xfs_mount_t *mp = log->l_mp; - xfs_buf_t *bp; - struct xfs_disk_dquot *ddq, *recddq; - int error; - xfs_dq_logformat_t *dq_f; - uint type; - - - /* - * Filesystems are required to send in quota flags at mount time. - */ - if (mp->m_qflags == 0) - return 0; - - recddq = item->ri_buf[1].i_addr; - if (recddq == NULL) { - xfs_alert(log->l_mp, "NULL dquot in %s.", __func__); - return -EIO; - } - if (item->ri_buf[1].i_len < sizeof(xfs_disk_dquot_t)) { - xfs_alert(log->l_mp, "dquot too small (%d) in %s.", - item->ri_buf[1].i_len, __func__); - return -EIO; - } - - /* - * This type of quotas was turned off, so ignore this record. - */ - type = recddq->d_flags & (XFS_DQ_USER | XFS_DQ_PROJ | XFS_DQ_GROUP); - ASSERT(type); - if (log->l_quotaoffs_flag & type) - return 0; - - /* - * At this point we know that quota was _not_ turned off. - * Since the mount flags are not indicating to us otherwise, this - * must mean that quota is on, and the dquot needs to be replayed. - * Remember that we may not have fully recovered the superblock yet, - * so we can't do the usual trick of looking at the SB quota bits. - * - * The other possibility, of course, is that the quota subsystem was - * removed since the last mount - ENOSYS. - */ - dq_f = item->ri_buf[0].i_addr; - ASSERT(dq_f); - error = xfs_dqcheck(mp, recddq, dq_f->qlf_id, 0, XFS_QMOPT_DOWARN, - "xlog_recover_dquot_pass2 (log copy)"); - if (error) - return -EIO; - ASSERT(dq_f->qlf_len == 1); - - /* - * At this point we are assuming that the dquots have been allocated - * and hence the buffer has valid dquots stamped in it. It should, - * therefore, pass verifier validation. If the dquot is bad, then the - * we'll return an error here, so we don't need to specifically check - * the dquot in the buffer after the verifier has run. - */ - error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dq_f->qlf_blkno, - XFS_FSB_TO_BB(mp, dq_f->qlf_len), 0, &bp, - &xfs_dquot_buf_ops); - if (error) - return error; - - ASSERT(bp); - ddq = xfs_buf_offset(bp, dq_f->qlf_boffset); - - /* - * If the dquot has an LSN in it, recover the dquot only if it's less - * than the lsn of the transaction we are replaying. - */ - if (xfs_sb_version_hascrc(&mp->m_sb)) { - struct xfs_dqblk *dqb = (struct xfs_dqblk *)ddq; - xfs_lsn_t lsn = be64_to_cpu(dqb->dd_lsn); - - if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) { - goto out_release; - } - } - - memcpy(ddq, recddq, item->ri_buf[1].i_len); - if (xfs_sb_version_hascrc(&mp->m_sb)) { - xfs_update_cksum((char *)ddq, sizeof(struct xfs_dqblk), - XFS_DQUOT_CRC_OFF); - } - - ASSERT(dq_f->qlf_size == 2); - ASSERT(bp->b_target->bt_mount == mp); - bp->b_iodone = xlog_recover_iodone; - xfs_buf_delwri_queue(bp, buffer_list); - -out_release: - xfs_buf_relse(bp); - return 0; -} - -/* - * This routine is called to create an in-core extent free intent - * item from the efi format structure which was logged on disk. - * It allocates an in-core efi, copies the extents from the format - * structure into it, and adds the efi to the AIL with the given - * LSN. - */ -STATIC int -xlog_recover_efi_pass2( - struct xlog *log, - struct xlog_recover_item *item, - xfs_lsn_t lsn) -{ - int error; - struct xfs_mount *mp = log->l_mp; - struct xfs_efi_log_item *efip; - struct xfs_efi_log_format *efi_formatp; - - efi_formatp = item->ri_buf[0].i_addr; - - efip = xfs_efi_init(mp, efi_formatp->efi_nextents); - error = xfs_efi_copy_format(&item->ri_buf[0], &efip->efi_format); - if (error) { - xfs_efi_item_free(efip); - return error; - } - atomic_set(&efip->efi_next_extent, efi_formatp->efi_nextents); - - spin_lock(&log->l_ailp->xa_lock); - /* - * The EFI has two references. One for the EFD and one for EFI to ensure - * it makes it into the AIL. Insert the EFI into the AIL directly and - * drop the EFI reference. Note that xfs_trans_ail_update() drops the - * AIL lock. - */ - xfs_trans_ail_update(log->l_ailp, &efip->efi_item, lsn); - xfs_efi_release(efip); - return 0; -} - - -/* - * This routine is called when an EFD format structure is found in a committed - * transaction in the log. Its purpose is to cancel the corresponding EFI if it - * was still in the log. To do this it searches the AIL for the EFI with an id - * equal to that in the EFD format structure. If we find it we drop the EFD - * reference, which removes the EFI from the AIL and frees it. - */ -STATIC int -xlog_recover_efd_pass2( - struct xlog *log, - struct xlog_recover_item *item) -{ - xfs_efd_log_format_t *efd_formatp; - xfs_efi_log_item_t *efip = NULL; - xfs_log_item_t *lip; - __uint64_t efi_id; - struct xfs_ail_cursor cur; - struct xfs_ail *ailp = log->l_ailp; - - efd_formatp = item->ri_buf[0].i_addr; - ASSERT((item->ri_buf[0].i_len == (sizeof(xfs_efd_log_format_32_t) + - ((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_32_t)))) || - (item->ri_buf[0].i_len == (sizeof(xfs_efd_log_format_64_t) + - ((efd_formatp->efd_nextents - 1) * sizeof(xfs_extent_64_t))))); - efi_id = efd_formatp->efd_efi_id; - - /* - * Search for the EFI with the id in the EFD format structure in the - * AIL. - */ - spin_lock(&ailp->xa_lock); - lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); - while (lip != NULL) { - if (lip->li_type == XFS_LI_EFI) { - efip = (xfs_efi_log_item_t *)lip; - if (efip->efi_format.efi_id == efi_id) { - /* - * Drop the EFD reference to the EFI. This - * removes the EFI from the AIL and frees it. - */ - spin_unlock(&ailp->xa_lock); - xfs_efi_release(efip); - spin_lock(&ailp->xa_lock); - break; - } - } - lip = xfs_trans_ail_cursor_next(ailp, &cur); - } - - xfs_trans_ail_cursor_done(&cur); - spin_unlock(&ailp->xa_lock); - - return 0; -} - -/* - * This routine is called to create an in-core extent rmap update - * item from the rui format structure which was logged on disk. - * It allocates an in-core rui, copies the extents from the format - * structure into it, and adds the rui to the AIL with the given - * LSN. - */ -STATIC int -xlog_recover_rui_pass2( - struct xlog *log, - struct xlog_recover_item *item, - xfs_lsn_t lsn) -{ - int error; - struct xfs_mount *mp = log->l_mp; - struct xfs_rui_log_item *ruip; - struct xfs_rui_log_format *rui_formatp; - - rui_formatp = item->ri_buf[0].i_addr; - - ruip = xfs_rui_init(mp, rui_formatp->rui_nextents); - error = xfs_rui_copy_format(&item->ri_buf[0], &ruip->rui_format); - if (error) { - xfs_rui_item_free(ruip); - return error; - } - atomic_set(&ruip->rui_next_extent, rui_formatp->rui_nextents); - - spin_lock(&log->l_ailp->xa_lock); - /* - * The RUI has two references. One for the RUD and one for RUI to ensure - * it makes it into the AIL. Insert the RUI into the AIL directly and - * drop the RUI reference. Note that xfs_trans_ail_update() drops the - * AIL lock. - */ - xfs_trans_ail_update(log->l_ailp, &ruip->rui_item, lsn); - xfs_rui_release(ruip); - return 0; -} - - -/* - * This routine is called when an RUD format structure is found in a committed - * transaction in the log. Its purpose is to cancel the corresponding RUI if it - * was still in the log. To do this it searches the AIL for the RUI with an id - * equal to that in the RUD format structure. If we find it we drop the RUD - * reference, which removes the RUI from the AIL and frees it. - */ -STATIC int -xlog_recover_rud_pass2( - struct xlog *log, - struct xlog_recover_item *item) -{ - struct xfs_rud_log_format *rud_formatp; - struct xfs_rui_log_item *ruip = NULL; - struct xfs_log_item *lip; - __uint64_t rui_id; - struct xfs_ail_cursor cur; - struct xfs_ail *ailp = log->l_ailp; - - rud_formatp = item->ri_buf[0].i_addr; - ASSERT(item->ri_buf[0].i_len == sizeof(struct xfs_rud_log_format)); - rui_id = rud_formatp->rud_rui_id; - - /* - * Search for the RUI with the id in the RUD format structure in the - * AIL. - */ - spin_lock(&ailp->xa_lock); - lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); - while (lip != NULL) { - if (lip->li_type == XFS_LI_RUI) { - ruip = (struct xfs_rui_log_item *)lip; - if (ruip->rui_format.rui_id == rui_id) { - /* - * Drop the RUD reference to the RUI. This - * removes the RUI from the AIL and frees it. - */ - spin_unlock(&ailp->xa_lock); - xfs_rui_release(ruip); - spin_lock(&ailp->xa_lock); - break; - } - } - lip = xfs_trans_ail_cursor_next(ailp, &cur); - } - - xfs_trans_ail_cursor_done(&cur); - spin_unlock(&ailp->xa_lock); - - return 0; -} - -/* - * Copy an CUI format buffer from the given buf, and into the destination - * CUI format structure. The CUI/CUD items were designed not to need any - * special alignment handling. - */ -static int -xfs_cui_copy_format( - struct xfs_log_iovec *buf, - struct xfs_cui_log_format *dst_cui_fmt) -{ - struct xfs_cui_log_format *src_cui_fmt; - uint len; - - src_cui_fmt = buf->i_addr; - len = xfs_cui_log_format_sizeof(src_cui_fmt->cui_nextents); - - if (buf->i_len == len) { - memcpy(dst_cui_fmt, src_cui_fmt, len); - return 0; - } - return -EFSCORRUPTED; -} - -/* - * This routine is called to create an in-core extent refcount update - * item from the cui format structure which was logged on disk. - * It allocates an in-core cui, copies the extents from the format - * structure into it, and adds the cui to the AIL with the given - * LSN. - */ -STATIC int -xlog_recover_cui_pass2( - struct xlog *log, - struct xlog_recover_item *item, - xfs_lsn_t lsn) -{ - int error; - struct xfs_mount *mp = log->l_mp; - struct xfs_cui_log_item *cuip; - struct xfs_cui_log_format *cui_formatp; - - cui_formatp = item->ri_buf[0].i_addr; - - cuip = xfs_cui_init(mp, cui_formatp->cui_nextents); - error = xfs_cui_copy_format(&item->ri_buf[0], &cuip->cui_format); - if (error) { - xfs_cui_item_free(cuip); - return error; - } - atomic_set(&cuip->cui_next_extent, cui_formatp->cui_nextents); - - spin_lock(&log->l_ailp->xa_lock); - /* - * The CUI has two references. One for the CUD and one for CUI to ensure - * it makes it into the AIL. Insert the CUI into the AIL directly and - * drop the CUI reference. Note that xfs_trans_ail_update() drops the - * AIL lock. - */ - xfs_trans_ail_update(log->l_ailp, &cuip->cui_item, lsn); - xfs_cui_release(cuip); - return 0; -} - - -/* - * This routine is called when an CUD format structure is found in a committed - * transaction in the log. Its purpose is to cancel the corresponding CUI if it - * was still in the log. To do this it searches the AIL for the CUI with an id - * equal to that in the CUD format structure. If we find it we drop the CUD - * reference, which removes the CUI from the AIL and frees it. - */ -STATIC int -xlog_recover_cud_pass2( - struct xlog *log, - struct xlog_recover_item *item) -{ - struct xfs_cud_log_format *cud_formatp; - struct xfs_cui_log_item *cuip = NULL; - struct xfs_log_item *lip; - __uint64_t cui_id; - struct xfs_ail_cursor cur; - struct xfs_ail *ailp = log->l_ailp; - - cud_formatp = item->ri_buf[0].i_addr; - if (item->ri_buf[0].i_len != sizeof(struct xfs_cud_log_format)) - return -EFSCORRUPTED; - cui_id = cud_formatp->cud_cui_id; - - /* - * Search for the CUI with the id in the CUD format structure in the - * AIL. - */ - spin_lock(&ailp->xa_lock); - lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); - while (lip != NULL) { - if (lip->li_type == XFS_LI_CUI) { - cuip = (struct xfs_cui_log_item *)lip; - if (cuip->cui_format.cui_id == cui_id) { - /* - * Drop the CUD reference to the CUI. This - * removes the CUI from the AIL and frees it. - */ - spin_unlock(&ailp->xa_lock); - xfs_cui_release(cuip); - spin_lock(&ailp->xa_lock); - break; - } - } - lip = xfs_trans_ail_cursor_next(ailp, &cur); - } - - xfs_trans_ail_cursor_done(&cur); - spin_unlock(&ailp->xa_lock); - - return 0; -} - -/* - * Copy an BUI format buffer from the given buf, and into the destination - * BUI format structure. The BUI/BUD items were designed not to need any - * special alignment handling. - */ -static int -xfs_bui_copy_format( - struct xfs_log_iovec *buf, - struct xfs_bui_log_format *dst_bui_fmt) -{ - struct xfs_bui_log_format *src_bui_fmt; - uint len; - - src_bui_fmt = buf->i_addr; - len = xfs_bui_log_format_sizeof(src_bui_fmt->bui_nextents); - - if (buf->i_len == len) { - memcpy(dst_bui_fmt, src_bui_fmt, len); - return 0; - } - return -EFSCORRUPTED; -} - -/* - * This routine is called to create an in-core extent bmap update - * item from the bui format structure which was logged on disk. - * It allocates an in-core bui, copies the extents from the format - * structure into it, and adds the bui to the AIL with the given - * LSN. - */ -STATIC int -xlog_recover_bui_pass2( - struct xlog *log, - struct xlog_recover_item *item, - xfs_lsn_t lsn) -{ - int error; - struct xfs_mount *mp = log->l_mp; - struct xfs_bui_log_item *buip; - struct xfs_bui_log_format *bui_formatp; - - bui_formatp = item->ri_buf[0].i_addr; - - if (bui_formatp->bui_nextents != XFS_BUI_MAX_FAST_EXTENTS) - return -EFSCORRUPTED; - buip = xfs_bui_init(mp); - error = xfs_bui_copy_format(&item->ri_buf[0], &buip->bui_format); - if (error) { - xfs_bui_item_free(buip); - return error; - } - atomic_set(&buip->bui_next_extent, bui_formatp->bui_nextents); - - spin_lock(&log->l_ailp->xa_lock); - /* - * The RUI has two references. One for the RUD and one for RUI to ensure - * it makes it into the AIL. Insert the RUI into the AIL directly and - * drop the RUI reference. Note that xfs_trans_ail_update() drops the - * AIL lock. - */ - xfs_trans_ail_update(log->l_ailp, &buip->bui_item, lsn); - xfs_bui_release(buip); - return 0; -} - - -/* - * This routine is called when an BUD format structure is found in a committed - * transaction in the log. Its purpose is to cancel the corresponding BUI if it - * was still in the log. To do this it searches the AIL for the BUI with an id - * equal to that in the BUD format structure. If we find it we drop the BUD - * reference, which removes the BUI from the AIL and frees it. - */ -STATIC int -xlog_recover_bud_pass2( - struct xlog *log, - struct xlog_recover_item *item) -{ - struct xfs_bud_log_format *bud_formatp; - struct xfs_bui_log_item *buip = NULL; - struct xfs_log_item *lip; - __uint64_t bui_id; - struct xfs_ail_cursor cur; - struct xfs_ail *ailp = log->l_ailp; - - bud_formatp = item->ri_buf[0].i_addr; - if (item->ri_buf[0].i_len != sizeof(struct xfs_bud_log_format)) - return -EFSCORRUPTED; - bui_id = bud_formatp->bud_bui_id; - - /* - * Search for the BUI with the id in the BUD format structure in the - * AIL. - */ - spin_lock(&ailp->xa_lock); - lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); - while (lip != NULL) { - if (lip->li_type == XFS_LI_BUI) { - buip = (struct xfs_bui_log_item *)lip; - if (buip->bui_format.bui_id == bui_id) { - /* - * Drop the BUD reference to the BUI. This - * removes the BUI from the AIL and frees it. - */ - spin_unlock(&ailp->xa_lock); - xfs_bui_release(buip); - spin_lock(&ailp->xa_lock); - break; - } - } - lip = xfs_trans_ail_cursor_next(ailp, &cur); - } - - xfs_trans_ail_cursor_done(&cur); - spin_unlock(&ailp->xa_lock); - - return 0; -} - -/* - * This routine is called when an inode create format structure is found in a - * committed transaction in the log. It's purpose is to initialise the inodes - * being allocated on disk. This requires us to get inode cluster buffers that - * match the range to be intialised, stamped with inode templates and written - * by delayed write so that subsequent modifications will hit the cached buffer - * and only need writing out at the end of recovery. - */ -STATIC int -xlog_recover_do_icreate_pass2( - struct xlog *log, - struct list_head *buffer_list, - xlog_recover_item_t *item) -{ - struct xfs_mount *mp = log->l_mp; - struct xfs_icreate_log *icl; - xfs_agnumber_t agno; - xfs_agblock_t agbno; - unsigned int count; - unsigned int isize; - xfs_agblock_t length; - int blks_per_cluster; - int bb_per_cluster; - int cancel_count; - int nbufs; - int i; - - icl = (struct xfs_icreate_log *)item->ri_buf[0].i_addr; - if (icl->icl_type != XFS_LI_ICREATE) { - xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad type"); - return -EINVAL; - } - - if (icl->icl_size != 1) { - xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad icl size"); - return -EINVAL; - } - - agno = be32_to_cpu(icl->icl_ag); - if (agno >= mp->m_sb.sb_agcount) { - xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad agno"); - return -EINVAL; - } - agbno = be32_to_cpu(icl->icl_agbno); - if (!agbno || agbno == NULLAGBLOCK || agbno >= mp->m_sb.sb_agblocks) { - xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad agbno"); - return -EINVAL; - } - isize = be32_to_cpu(icl->icl_isize); - if (isize != mp->m_sb.sb_inodesize) { - xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad isize"); - return -EINVAL; - } - count = be32_to_cpu(icl->icl_count); - if (!count) { - xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad count"); - return -EINVAL; - } - length = be32_to_cpu(icl->icl_length); - if (!length || length >= mp->m_sb.sb_agblocks) { - xfs_warn(log->l_mp, "xlog_recover_do_icreate_trans: bad length"); - return -EINVAL; - } - - /* - * The inode chunk is either full or sparse and we only support - * m_ialloc_min_blks sized sparse allocations at this time. - */ - if (length != mp->m_ialloc_blks && - length != mp->m_ialloc_min_blks) { - xfs_warn(log->l_mp, - "%s: unsupported chunk length", __FUNCTION__); - return -EINVAL; - } - - /* verify inode count is consistent with extent length */ - if ((count >> mp->m_sb.sb_inopblog) != length) { - xfs_warn(log->l_mp, - "%s: inconsistent inode count and chunk length", - __FUNCTION__); - return -EINVAL; - } - - /* - * The icreate transaction can cover multiple cluster buffers and these - * buffers could have been freed and reused. Check the individual - * buffers for cancellation so we don't overwrite anything written after - * a cancellation. - */ - blks_per_cluster = xfs_icluster_size_fsb(mp); - bb_per_cluster = XFS_FSB_TO_BB(mp, blks_per_cluster); - nbufs = length / blks_per_cluster; - for (i = 0, cancel_count = 0; i < nbufs; i++) { - xfs_daddr_t daddr; - - daddr = XFS_AGB_TO_DADDR(mp, agno, - agbno + i * blks_per_cluster); - if (xlog_check_buffer_cancelled(log, daddr, bb_per_cluster, 0)) - cancel_count++; - } - - /* - * We currently only use icreate for a single allocation at a time. This - * means we should expect either all or none of the buffers to be - * cancelled. Be conservative and skip replay if at least one buffer is - * cancelled, but warn the user that something is awry if the buffers - * are not consistent. - * - * XXX: This must be refined to only skip cancelled clusters once we use - * icreate for multiple chunk allocations. - */ - ASSERT(!cancel_count || cancel_count == nbufs); - if (cancel_count) { - if (cancel_count != nbufs) - xfs_warn(mp, - "WARNING: partial inode chunk cancellation, skipped icreate."); - trace_xfs_log_recover_icreate_cancel(log, icl); - return 0; - } - - trace_xfs_log_recover_icreate_recover(log, icl); - return xfs_ialloc_inode_init(mp, NULL, buffer_list, count, agno, agbno, - length, be32_to_cpu(icl->icl_gen)); -} - -STATIC void -xlog_recover_buffer_ra_pass2( - struct xlog *log, - struct xlog_recover_item *item) -{ - struct xfs_buf_log_format *buf_f = item->ri_buf[0].i_addr; - struct xfs_mount *mp = log->l_mp; - - if (xlog_peek_buffer_cancelled(log, buf_f->blf_blkno, - buf_f->blf_len, buf_f->blf_flags)) { - return; - } - - xfs_buf_readahead(mp->m_ddev_targp, buf_f->blf_blkno, - buf_f->blf_len, NULL); -} - -STATIC void -xlog_recover_inode_ra_pass2( - struct xlog *log, - struct xlog_recover_item *item) -{ - struct xfs_inode_log_format ilf_buf; - struct xfs_inode_log_format *ilfp; - struct xfs_mount *mp = log->l_mp; - int error; - - if (item->ri_buf[0].i_len == sizeof(struct xfs_inode_log_format)) { - ilfp = item->ri_buf[0].i_addr; - } else { - ilfp = &ilf_buf; - memset(ilfp, 0, sizeof(*ilfp)); - error = xfs_inode_item_format_convert(&item->ri_buf[0], ilfp); - if (error) - return; - } - - if (xlog_peek_buffer_cancelled(log, ilfp->ilf_blkno, ilfp->ilf_len, 0)) - return; - - xfs_buf_readahead(mp->m_ddev_targp, ilfp->ilf_blkno, - ilfp->ilf_len, &xfs_inode_buf_ra_ops); -} - -STATIC void -xlog_recover_dquot_ra_pass2( - struct xlog *log, - struct xlog_recover_item *item) -{ - struct xfs_mount *mp = log->l_mp; - struct xfs_disk_dquot *recddq; - struct xfs_dq_logformat *dq_f; - uint type; - int len; - - - if (mp->m_qflags == 0) - return; - - recddq = item->ri_buf[1].i_addr; - if (recddq == NULL) - return; - if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot)) - return; - - type = recddq->d_flags & (XFS_DQ_USER | XFS_DQ_PROJ | XFS_DQ_GROUP); - ASSERT(type); - if (log->l_quotaoffs_flag & type) - return; - - dq_f = item->ri_buf[0].i_addr; - ASSERT(dq_f); - ASSERT(dq_f->qlf_len == 1); - - len = XFS_FSB_TO_BB(mp, dq_f->qlf_len); - if (xlog_peek_buffer_cancelled(log, dq_f->qlf_blkno, len, 0)) - return; - - xfs_buf_readahead(mp->m_ddev_targp, dq_f->qlf_blkno, len, - &xfs_dquot_buf_ra_ops); -} - -STATIC void -xlog_recover_ra_pass2( - struct xlog *log, - struct xlog_recover_item *item) -{ - switch (ITEM_TYPE(item)) { - case XFS_LI_BUF: - xlog_recover_buffer_ra_pass2(log, item); - break; - case XFS_LI_INODE: - xlog_recover_inode_ra_pass2(log, item); - break; - case XFS_LI_DQUOT: - xlog_recover_dquot_ra_pass2(log, item); - break; - case XFS_LI_EFI: - case XFS_LI_EFD: - case XFS_LI_QUOTAOFF: - case XFS_LI_RUI: - case XFS_LI_RUD: - case XFS_LI_CUI: - case XFS_LI_CUD: - case XFS_LI_BUI: - case XFS_LI_BUD: - default: - break; - } -} - -STATIC int -xlog_recover_commit_pass1( - struct xlog *log, - struct xlog_recover *trans, - struct xlog_recover_item *item) -{ - trace_xfs_log_recover_item_recover(log, trans, item, XLOG_RECOVER_PASS1); - - switch (ITEM_TYPE(item)) { - case XFS_LI_BUF: - return xlog_recover_buffer_pass1(log, item); - case XFS_LI_QUOTAOFF: - return xlog_recover_quotaoff_pass1(log, item); - case XFS_LI_INODE: - case XFS_LI_EFI: - case XFS_LI_EFD: - case XFS_LI_DQUOT: - case XFS_LI_ICREATE: - case XFS_LI_RUI: - case XFS_LI_RUD: - case XFS_LI_CUI: - case XFS_LI_CUD: - case XFS_LI_BUI: - case XFS_LI_BUD: - /* nothing to do in pass 1 */ - return 0; - default: - xfs_warn(log->l_mp, "%s: invalid item type (%d)", - __func__, ITEM_TYPE(item)); - ASSERT(0); - return -EIO; - } -} - -STATIC int -xlog_recover_commit_pass2( - struct xlog *log, - struct xlog_recover *trans, - struct list_head *buffer_list, - struct xlog_recover_item *item) -{ - trace_xfs_log_recover_item_recover(log, trans, item, XLOG_RECOVER_PASS2); - - switch (ITEM_TYPE(item)) { - case XFS_LI_BUF: - return xlog_recover_buffer_pass2(log, buffer_list, item, - trans->r_lsn); - case XFS_LI_INODE: - return xlog_recover_inode_pass2(log, buffer_list, item, - trans->r_lsn); - case XFS_LI_EFI: - return xlog_recover_efi_pass2(log, item, trans->r_lsn); - case XFS_LI_EFD: - return xlog_recover_efd_pass2(log, item); - case XFS_LI_RUI: - return xlog_recover_rui_pass2(log, item, trans->r_lsn); - case XFS_LI_RUD: - return xlog_recover_rud_pass2(log, item); - case XFS_LI_CUI: - return xlog_recover_cui_pass2(log, item, trans->r_lsn); - case XFS_LI_CUD: - return xlog_recover_cud_pass2(log, item); - case XFS_LI_BUI: - return xlog_recover_bui_pass2(log, item, trans->r_lsn); - case XFS_LI_BUD: - return xlog_recover_bud_pass2(log, item); - case XFS_LI_DQUOT: - return xlog_recover_dquot_pass2(log, buffer_list, item, - trans->r_lsn); - case XFS_LI_ICREATE: - return xlog_recover_do_icreate_pass2(log, buffer_list, item); - case XFS_LI_QUOTAOFF: - /* nothing to do in pass2 */ - return 0; - default: - xfs_warn(log->l_mp, "%s: invalid item type (%d)", - __func__, ITEM_TYPE(item)); - ASSERT(0); - return -EIO; - } -} - -STATIC int -xlog_recover_items_pass2( - struct xlog *log, - struct xlog_recover *trans, - struct list_head *buffer_list, - struct list_head *item_list) -{ - struct xlog_recover_item *item; - int error = 0; - - list_for_each_entry(item, item_list, ri_list) { - error = xlog_recover_commit_pass2(log, trans, - buffer_list, item); - if (error) - return error; - } - - return error; -} - -/* - * Perform the transaction. - * - * If the transaction modifies a buffer or inode, do it now. Otherwise, - * EFIs and EFDs get queued up by adding entries into the AIL for them. - */ -STATIC int -xlog_recover_commit_trans( - struct xlog *log, - struct xlog_recover *trans, - int pass, - struct list_head *buffer_list) -{ - int error = 0; - int items_queued = 0; - struct xlog_recover_item *item; - struct xlog_recover_item *next; - LIST_HEAD (ra_list); - LIST_HEAD (done_list); - - #define XLOG_RECOVER_COMMIT_QUEUE_MAX 100 - - hlist_del(&trans->r_list); - - error = xlog_recover_reorder_trans(log, trans, pass); - if (error) - return error; - - list_for_each_entry_safe(item, next, &trans->r_itemq, ri_list) { - switch (pass) { - case XLOG_RECOVER_PASS1: - error = xlog_recover_commit_pass1(log, trans, item); - break; - case XLOG_RECOVER_PASS2: - xlog_recover_ra_pass2(log, item); - list_move_tail(&item->ri_list, &ra_list); - items_queued++; - if (items_queued >= XLOG_RECOVER_COMMIT_QUEUE_MAX) { - error = xlog_recover_items_pass2(log, trans, - buffer_list, &ra_list); - list_splice_tail_init(&ra_list, &done_list); - items_queued = 0; - } - - break; - default: - ASSERT(0); - } - - if (error) - goto out; - } - -out: - if (!list_empty(&ra_list)) { - if (!error) - error = xlog_recover_items_pass2(log, trans, - buffer_list, &ra_list); - list_splice_tail_init(&ra_list, &done_list); - } - - if (!list_empty(&done_list)) - list_splice_init(&done_list, &trans->r_itemq); - - return error; -} - -STATIC void -xlog_recover_add_item( - struct list_head *head) -{ - xlog_recover_item_t *item; - - item = kmem_zalloc(sizeof(xlog_recover_item_t), KM_SLEEP); - INIT_LIST_HEAD(&item->ri_list); - list_add_tail(&item->ri_list, head); -} - -STATIC int -xlog_recover_add_to_cont_trans( - struct xlog *log, - struct xlog_recover *trans, - char *dp, - int len) -{ - xlog_recover_item_t *item; - char *ptr, *old_ptr; - int old_len; - - /* - * If the transaction is empty, the header was split across this and the - * previous record. Copy the rest of the header. - */ - if (list_empty(&trans->r_itemq)) { - ASSERT(len <= sizeof(struct xfs_trans_header)); - if (len > sizeof(struct xfs_trans_header)) { - xfs_warn(log->l_mp, "%s: bad header length", __func__); - return -EIO; - } - - xlog_recover_add_item(&trans->r_itemq); - ptr = (char *)&trans->r_theader + - sizeof(struct xfs_trans_header) - len; - memcpy(ptr, dp, len); - return 0; - } - - /* take the tail entry */ - item = list_entry(trans->r_itemq.prev, xlog_recover_item_t, ri_list); - - old_ptr = item->ri_buf[item->ri_cnt-1].i_addr; - old_len = item->ri_buf[item->ri_cnt-1].i_len; - - ptr = kmem_realloc(old_ptr, len + old_len, KM_SLEEP); - memcpy(&ptr[old_len], dp, len); - item->ri_buf[item->ri_cnt-1].i_len += len; - item->ri_buf[item->ri_cnt-1].i_addr = ptr; - trace_xfs_log_recover_item_add_cont(log, trans, item, 0); - return 0; -} - -/* - * The next region to add is the start of a new region. It could be - * a whole region or it could be the first part of a new region. Because - * of this, the assumption here is that the type and size fields of all - * format structures fit into the first 32 bits of the structure. - * - * This works because all regions must be 32 bit aligned. Therefore, we - * either have both fields or we have neither field. In the case we have - * neither field, the data part of the region is zero length. We only have - * a log_op_header and can throw away the header since a new one will appear - * later. If we have at least 4 bytes, then we can determine how many regions - * will appear in the current log item. - */ -STATIC int -xlog_recover_add_to_trans( - struct xlog *log, - struct xlog_recover *trans, - char *dp, - int len) -{ - xfs_inode_log_format_t *in_f; /* any will do */ - xlog_recover_item_t *item; - char *ptr; - - if (!len) - return 0; - if (list_empty(&trans->r_itemq)) { - /* we need to catch log corruptions here */ - if (*(uint *)dp != XFS_TRANS_HEADER_MAGIC) { - xfs_warn(log->l_mp, "%s: bad header magic number", - __func__); - ASSERT(0); - return -EIO; - } - - if (len > sizeof(struct xfs_trans_header)) { - xfs_warn(log->l_mp, "%s: bad header length", __func__); - ASSERT(0); - return -EIO; - } - - /* - * The transaction header can be arbitrarily split across op - * records. If we don't have the whole thing here, copy what we - * do have and handle the rest in the next record. - */ - if (len == sizeof(struct xfs_trans_header)) - xlog_recover_add_item(&trans->r_itemq); - memcpy(&trans->r_theader, dp, len); - return 0; - } - - ptr = kmem_alloc(len, KM_SLEEP); - memcpy(ptr, dp, len); - in_f = (xfs_inode_log_format_t *)ptr; - - /* take the tail entry */ - item = list_entry(trans->r_itemq.prev, xlog_recover_item_t, ri_list); - if (item->ri_total != 0 && - item->ri_total == item->ri_cnt) { - /* tail item is in use, get a new one */ - xlog_recover_add_item(&trans->r_itemq); - item = list_entry(trans->r_itemq.prev, - xlog_recover_item_t, ri_list); - } - - if (item->ri_total == 0) { /* first region to be added */ - if (in_f->ilf_size == 0 || - in_f->ilf_size > XLOG_MAX_REGIONS_IN_ITEM) { - xfs_warn(log->l_mp, - "bad number of regions (%d) in inode log format", - in_f->ilf_size); - ASSERT(0); - kmem_free(ptr); - return -EIO; - } - - item->ri_total = in_f->ilf_size; - item->ri_buf = - kmem_zalloc(item->ri_total * sizeof(xfs_log_iovec_t), - KM_SLEEP); - } - ASSERT(item->ri_total > item->ri_cnt); - /* Description region is ri_buf[0] */ - item->ri_buf[item->ri_cnt].i_addr = ptr; - item->ri_buf[item->ri_cnt].i_len = len; - item->ri_cnt++; - trace_xfs_log_recover_item_add(log, trans, item, 0); - return 0; -} - -/* - * Free up any resources allocated by the transaction - * - * Remember that EFIs, EFDs, and IUNLINKs are handled later. - */ -STATIC void -xlog_recover_free_trans( - struct xlog_recover *trans) -{ - xlog_recover_item_t *item, *n; - int i; - - list_for_each_entry_safe(item, n, &trans->r_itemq, ri_list) { - /* Free the regions in the item. */ - list_del(&item->ri_list); - for (i = 0; i < item->ri_cnt; i++) - kmem_free(item->ri_buf[i].i_addr); - /* Free the item itself */ - kmem_free(item->ri_buf); - kmem_free(item); - } - /* Free the transaction recover structure */ - kmem_free(trans); -} - -/* - * On error or completion, trans is freed. - */ -STATIC int -xlog_recovery_process_trans( - struct xlog *log, - struct xlog_recover *trans, - char *dp, - unsigned int len, - unsigned int flags, - int pass, - struct list_head *buffer_list) -{ - int error = 0; - bool freeit = false; - - /* mask off ophdr transaction container flags */ - flags &= ~XLOG_END_TRANS; - if (flags & XLOG_WAS_CONT_TRANS) - flags &= ~XLOG_CONTINUE_TRANS; - - /* - * Callees must not free the trans structure. We'll decide if we need to - * free it or not based on the operation being done and it's result. - */ - switch (flags) { - /* expected flag values */ - case 0: - case XLOG_CONTINUE_TRANS: - error = xlog_recover_add_to_trans(log, trans, dp, len); - break; - case XLOG_WAS_CONT_TRANS: - error = xlog_recover_add_to_cont_trans(log, trans, dp, len); - break; - case XLOG_COMMIT_TRANS: - error = xlog_recover_commit_trans(log, trans, pass, - buffer_list); - /* success or fail, we are now done with this transaction. */ - freeit = true; - break; - - /* unexpected flag values */ - case XLOG_UNMOUNT_TRANS: - /* just skip trans */ - xfs_warn(log->l_mp, "%s: Unmount LR", __func__); - freeit = true; - break; - case XLOG_START_TRANS: - default: - xfs_warn(log->l_mp, "%s: bad flag 0x%x", __func__, flags); - ASSERT(0); - error = -EIO; - break; - } - if (error || freeit) - xlog_recover_free_trans(trans); - return error; -} - -/* - * Lookup the transaction recovery structure associated with the ID in the - * current ophdr. If the transaction doesn't exist and the start flag is set in - * the ophdr, then allocate a new transaction for future ID matches to find. - * Either way, return what we found during the lookup - an existing transaction - * or nothing. - */ -STATIC struct xlog_recover * -xlog_recover_ophdr_to_trans( - struct hlist_head rhash[], - struct xlog_rec_header *rhead, - struct xlog_op_header *ohead) -{ - struct xlog_recover *trans; - xlog_tid_t tid; - struct hlist_head *rhp; - - tid = be32_to_cpu(ohead->oh_tid); - rhp = &rhash[XLOG_RHASH(tid)]; - hlist_for_each_entry(trans, rhp, r_list) { - if (trans->r_log_tid == tid) - return trans; - } - - /* - * skip over non-start transaction headers - we could be - * processing slack space before the next transaction starts - */ - if (!(ohead->oh_flags & XLOG_START_TRANS)) - return NULL; - - ASSERT(be32_to_cpu(ohead->oh_len) == 0); - - /* - * This is a new transaction so allocate a new recovery container to - * hold the recovery ops that will follow. - */ - trans = kmem_zalloc(sizeof(struct xlog_recover), KM_SLEEP); - trans->r_log_tid = tid; - trans->r_lsn = be64_to_cpu(rhead->h_lsn); - INIT_LIST_HEAD(&trans->r_itemq); - INIT_HLIST_NODE(&trans->r_list); - hlist_add_head(&trans->r_list, rhp); - - /* - * Nothing more to do for this ophdr. Items to be added to this new - * transaction will be in subsequent ophdr containers. - */ - return NULL; -} - -STATIC int -xlog_recover_process_ophdr( - struct xlog *log, - struct hlist_head rhash[], - struct xlog_rec_header *rhead, - struct xlog_op_header *ohead, - char *dp, - char *end, - int pass, - struct list_head *buffer_list) -{ - struct xlog_recover *trans; - unsigned int len; - int error; - - /* Do we understand who wrote this op? */ - if (ohead->oh_clientid != XFS_TRANSACTION && - ohead->oh_clientid != XFS_LOG) { - xfs_warn(log->l_mp, "%s: bad clientid 0x%x", - __func__, ohead->oh_clientid); - ASSERT(0); - return -EIO; - } - - /* - * Check the ophdr contains all the data it is supposed to contain. - */ - len = be32_to_cpu(ohead->oh_len); - if (dp + len > end) { - xfs_warn(log->l_mp, "%s: bad length 0x%x", __func__, len); - WARN_ON(1); - return -EIO; - } - - trans = xlog_recover_ophdr_to_trans(rhash, rhead, ohead); - if (!trans) { - /* nothing to do, so skip over this ophdr */ - return 0; - } - - /* - * The recovered buffer queue is drained only once we know that all - * recovery items for the current LSN have been processed. This is - * required because: - * - * - Buffer write submission updates the metadata LSN of the buffer. - * - Log recovery skips items with a metadata LSN >= the current LSN of - * the recovery item. - * - Separate recovery items against the same metadata buffer can share - * a current LSN. I.e., consider that the LSN of a recovery item is - * defined as the starting LSN of the first record in which its - * transaction appears, that a record can hold multiple transactions, - * and/or that a transaction can span multiple records. - * - * In other words, we are allowed to submit a buffer from log recovery - * once per current LSN. Otherwise, we may incorrectly skip recovery - * items and cause corruption. - * - * We don't know up front whether buffers are updated multiple times per - * LSN. Therefore, track the current LSN of each commit log record as it - * is processed and drain the queue when it changes. Use commit records - * because they are ordered correctly by the logging code. - */ - if (log->l_recovery_lsn != trans->r_lsn && - ohead->oh_flags & XLOG_COMMIT_TRANS) { - error = xfs_buf_delwri_submit(buffer_list); - if (error) - return error; - log->l_recovery_lsn = trans->r_lsn; - } - - return xlog_recovery_process_trans(log, trans, dp, len, - ohead->oh_flags, pass, buffer_list); -} - -/* - * There are two valid states of the r_state field. 0 indicates that the - * transaction structure is in a normal state. We have either seen the - * start of the transaction or the last operation we added was not a partial - * operation. If the last operation we added to the transaction was a - * partial operation, we need to mark r_state with XLOG_WAS_CONT_TRANS. - * - * NOTE: skip LRs with 0 data length. - */ -STATIC int -xlog_recover_process_data( - struct xlog *log, - struct hlist_head rhash[], - struct xlog_rec_header *rhead, - char *dp, - int pass, - struct list_head *buffer_list) -{ - struct xlog_op_header *ohead; - char *end; - int num_logops; - int error; - - end = dp + be32_to_cpu(rhead->h_len); - num_logops = be32_to_cpu(rhead->h_num_logops); - - /* check the log format matches our own - else we can't recover */ - if (xlog_header_check_recover(log->l_mp, rhead)) - return -EIO; - - trace_xfs_log_recover_record(log, rhead, pass); - while ((dp < end) && num_logops) { - - ohead = (struct xlog_op_header *)dp; - dp += sizeof(*ohead); - ASSERT(dp <= end); - - /* errors will abort recovery */ - error = xlog_recover_process_ophdr(log, rhash, rhead, ohead, - dp, end, pass, buffer_list); - if (error) - return error; - - dp += be32_to_cpu(ohead->oh_len); - num_logops--; - } - return 0; -} - -/* Recover the EFI if necessary. */ -STATIC int -xlog_recover_process_efi( - struct xfs_mount *mp, - struct xfs_ail *ailp, - struct xfs_log_item *lip) -{ - struct xfs_efi_log_item *efip; - int error; - - /* - * Skip EFIs that we've already processed. - */ - efip = container_of(lip, struct xfs_efi_log_item, efi_item); - if (test_bit(XFS_EFI_RECOVERED, &efip->efi_flags)) - return 0; - - spin_unlock(&ailp->xa_lock); - error = xfs_efi_recover(mp, efip); - spin_lock(&ailp->xa_lock); - - return error; -} - -/* Release the EFI since we're cancelling everything. */ -STATIC void -xlog_recover_cancel_efi( - struct xfs_mount *mp, - struct xfs_ail *ailp, - struct xfs_log_item *lip) -{ - struct xfs_efi_log_item *efip; - - efip = container_of(lip, struct xfs_efi_log_item, efi_item); - - spin_unlock(&ailp->xa_lock); - xfs_efi_release(efip); - spin_lock(&ailp->xa_lock); -} - -/* Recover the RUI if necessary. */ -STATIC int -xlog_recover_process_rui( - struct xfs_mount *mp, - struct xfs_ail *ailp, - struct xfs_log_item *lip) -{ - struct xfs_rui_log_item *ruip; - int error; - - /* - * Skip RUIs that we've already processed. - */ - ruip = container_of(lip, struct xfs_rui_log_item, rui_item); - if (test_bit(XFS_RUI_RECOVERED, &ruip->rui_flags)) - return 0; - - spin_unlock(&ailp->xa_lock); - error = xfs_rui_recover(mp, ruip); - spin_lock(&ailp->xa_lock); - - return error; -} - -/* Release the RUI since we're cancelling everything. */ -STATIC void -xlog_recover_cancel_rui( - struct xfs_mount *mp, - struct xfs_ail *ailp, - struct xfs_log_item *lip) -{ - struct xfs_rui_log_item *ruip; - - ruip = container_of(lip, struct xfs_rui_log_item, rui_item); - - spin_unlock(&ailp->xa_lock); - xfs_rui_release(ruip); - spin_lock(&ailp->xa_lock); -} - -/* Recover the CUI if necessary. */ -STATIC int -xlog_recover_process_cui( - struct xfs_mount *mp, - struct xfs_ail *ailp, - struct xfs_log_item *lip) -{ - struct xfs_cui_log_item *cuip; - int error; - - /* - * Skip CUIs that we've already processed. - */ - cuip = container_of(lip, struct xfs_cui_log_item, cui_item); - if (test_bit(XFS_CUI_RECOVERED, &cuip->cui_flags)) - return 0; - - spin_unlock(&ailp->xa_lock); - error = xfs_cui_recover(mp, cuip); - spin_lock(&ailp->xa_lock); - - return error; -} - -/* Release the CUI since we're cancelling everything. */ -STATIC void -xlog_recover_cancel_cui( - struct xfs_mount *mp, - struct xfs_ail *ailp, - struct xfs_log_item *lip) -{ - struct xfs_cui_log_item *cuip; - - cuip = container_of(lip, struct xfs_cui_log_item, cui_item); - - spin_unlock(&ailp->xa_lock); - xfs_cui_release(cuip); - spin_lock(&ailp->xa_lock); -} - -/* Recover the BUI if necessary. */ -STATIC int -xlog_recover_process_bui( - struct xfs_mount *mp, - struct xfs_ail *ailp, - struct xfs_log_item *lip) -{ - struct xfs_bui_log_item *buip; - int error; - - /* - * Skip BUIs that we've already processed. - */ - buip = container_of(lip, struct xfs_bui_log_item, bui_item); - if (test_bit(XFS_BUI_RECOVERED, &buip->bui_flags)) - return 0; - - spin_unlock(&ailp->xa_lock); - error = xfs_bui_recover(mp, buip); - spin_lock(&ailp->xa_lock); - - return error; -} - -/* Release the BUI since we're cancelling everything. */ -STATIC void -xlog_recover_cancel_bui( - struct xfs_mount *mp, - struct xfs_ail *ailp, - struct xfs_log_item *lip) -{ - struct xfs_bui_log_item *buip; - - buip = container_of(lip, struct xfs_bui_log_item, bui_item); - - spin_unlock(&ailp->xa_lock); - xfs_bui_release(buip); - spin_lock(&ailp->xa_lock); -} - -/* Is this log item a deferred action intent? */ -static inline bool xlog_item_is_intent(struct xfs_log_item *lip) -{ - switch (lip->li_type) { - case XFS_LI_EFI: - case XFS_LI_RUI: - case XFS_LI_CUI: - case XFS_LI_BUI: - return true; - default: - return false; - } -} - -/* - * When this is called, all of the log intent items which did not have - * corresponding log done items should be in the AIL. What we do now - * is update the data structures associated with each one. - * - * Since we process the log intent items in normal transactions, they - * will be removed at some point after the commit. This prevents us - * from just walking down the list processing each one. We'll use a - * flag in the intent item to skip those that we've already processed - * and use the AIL iteration mechanism's generation count to try to - * speed this up at least a bit. - * - * When we start, we know that the intents are the only things in the - * AIL. As we process them, however, other items are added to the - * AIL. - */ -STATIC int -xlog_recover_process_intents( - struct xlog *log) -{ - struct xfs_log_item *lip; - int error = 0; - struct xfs_ail_cursor cur; - struct xfs_ail *ailp; - xfs_lsn_t last_lsn; - - ailp = log->l_ailp; - spin_lock(&ailp->xa_lock); - lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); - last_lsn = xlog_assign_lsn(log->l_curr_cycle, log->l_curr_block); - while (lip != NULL) { - /* - * We're done when we see something other than an intent. - * There should be no intents left in the AIL now. - */ - if (!xlog_item_is_intent(lip)) { -#ifdef DEBUG - for (; lip; lip = xfs_trans_ail_cursor_next(ailp, &cur)) - ASSERT(!xlog_item_is_intent(lip)); -#endif - break; - } - - /* - * We should never see a redo item with a LSN higher than - * the last transaction we found in the log at the start - * of recovery. - */ - ASSERT(XFS_LSN_CMP(last_lsn, lip->li_lsn) >= 0); - - switch (lip->li_type) { - case XFS_LI_EFI: - error = xlog_recover_process_efi(log->l_mp, ailp, lip); - break; - case XFS_LI_RUI: - error = xlog_recover_process_rui(log->l_mp, ailp, lip); - break; - case XFS_LI_CUI: - error = xlog_recover_process_cui(log->l_mp, ailp, lip); - break; - case XFS_LI_BUI: - error = xlog_recover_process_bui(log->l_mp, ailp, lip); - break; - } - if (error) - goto out; - lip = xfs_trans_ail_cursor_next(ailp, &cur); - } -out: - xfs_trans_ail_cursor_done(&cur); - spin_unlock(&ailp->xa_lock); - return error; -} - -/* - * A cancel occurs when the mount has failed and we're bailing out. - * Release all pending log intent items so they don't pin the AIL. - */ -STATIC int -xlog_recover_cancel_intents( - struct xlog *log) -{ - struct xfs_log_item *lip; - int error = 0; - struct xfs_ail_cursor cur; - struct xfs_ail *ailp; - - ailp = log->l_ailp; - spin_lock(&ailp->xa_lock); - lip = xfs_trans_ail_cursor_first(ailp, &cur, 0); - while (lip != NULL) { - /* - * We're done when we see something other than an intent. - * There should be no intents left in the AIL now. - */ - if (!xlog_item_is_intent(lip)) { -#ifdef DEBUG - for (; lip; lip = xfs_trans_ail_cursor_next(ailp, &cur)) - ASSERT(!xlog_item_is_intent(lip)); -#endif - break; - } - - switch (lip->li_type) { - case XFS_LI_EFI: - xlog_recover_cancel_efi(log->l_mp, ailp, lip); - break; - case XFS_LI_RUI: - xlog_recover_cancel_rui(log->l_mp, ailp, lip); - break; - case XFS_LI_CUI: - xlog_recover_cancel_cui(log->l_mp, ailp, lip); - break; - case XFS_LI_BUI: - xlog_recover_cancel_bui(log->l_mp, ailp, lip); - break; - } - - lip = xfs_trans_ail_cursor_next(ailp, &cur); - } - - xfs_trans_ail_cursor_done(&cur); - spin_unlock(&ailp->xa_lock); - return error; -} - -/* - * This routine performs a transaction to null out a bad inode pointer - * in an agi unlinked inode hash bucket. - */ -STATIC void -xlog_recover_clear_agi_bucket( - xfs_mount_t *mp, - xfs_agnumber_t agno, - int bucket) -{ - xfs_trans_t *tp; - xfs_agi_t *agi; - xfs_buf_t *agibp; - int offset; - int error; - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_clearagi, 0, 0, 0, &tp); - if (error) - goto out_error; - - error = xfs_read_agi(mp, tp, agno, &agibp); - if (error) - goto out_abort; - - agi = XFS_BUF_TO_AGI(agibp); - agi->agi_unlinked[bucket] = cpu_to_be32(NULLAGINO); - offset = offsetof(xfs_agi_t, agi_unlinked) + - (sizeof(xfs_agino_t) * bucket); - xfs_trans_log_buf(tp, agibp, offset, - (offset + sizeof(xfs_agino_t) - 1)); - - error = xfs_trans_commit(tp); - if (error) - goto out_error; - return; - -out_abort: - xfs_trans_cancel(tp); -out_error: - xfs_warn(mp, "%s: failed to clear agi %d. Continuing.", __func__, agno); - return; -} - -STATIC xfs_agino_t -xlog_recover_process_one_iunlink( - struct xfs_mount *mp, - xfs_agnumber_t agno, - xfs_agino_t agino, - int bucket) -{ - struct xfs_buf *ibp; - struct xfs_dinode *dip; - struct xfs_inode *ip; - xfs_ino_t ino; - int error; - - ino = XFS_AGINO_TO_INO(mp, agno, agino); - error = xfs_iget(mp, NULL, ino, 0, 0, &ip); - if (error) - goto fail; - - /* - * Get the on disk inode to find the next inode in the bucket. - */ - error = xfs_imap_to_bp(mp, NULL, &ip->i_imap, &dip, &ibp, 0, 0); - if (error) - goto fail_iput; - - xfs_iflags_clear(ip, XFS_IRECOVERY); - ASSERT(VFS_I(ip)->i_nlink == 0); - ASSERT(VFS_I(ip)->i_mode != 0); - - /* setup for the next pass */ - agino = be32_to_cpu(dip->di_next_unlinked); - xfs_buf_relse(ibp); - - /* - * Prevent any DMAPI event from being sent when the reference on - * the inode is dropped. - */ - ip->i_d.di_dmevmask = 0; - - IRELE(ip); - return agino; - - fail_iput: - IRELE(ip); - fail: - /* - * We can't read in the inode this bucket points to, or this inode - * is messed up. Just ditch this bucket of inodes. We will lose - * some inodes and space, but at least we won't hang. - * - * Call xlog_recover_clear_agi_bucket() to perform a transaction to - * clear the inode pointer in the bucket. - */ - xlog_recover_clear_agi_bucket(mp, agno, bucket); - return NULLAGINO; -} - -/* - * xlog_iunlink_recover - * - * This is called during recovery to process any inodes which - * we unlinked but not freed when the system crashed. These - * inodes will be on the lists in the AGI blocks. What we do - * here is scan all the AGIs and fully truncate and free any - * inodes found on the lists. Each inode is removed from the - * lists when it has been fully truncated and is freed. The - * freeing of the inode and its removal from the list must be - * atomic. - */ -STATIC void -xlog_recover_process_iunlinks( - struct xlog *log) -{ - xfs_mount_t *mp; - xfs_agnumber_t agno; - xfs_agi_t *agi; - xfs_buf_t *agibp; - xfs_agino_t agino; - int bucket; - int error; - uint mp_dmevmask; - - mp = log->l_mp; - - /* - * Prevent any DMAPI event from being sent while in this function. - */ - mp_dmevmask = mp->m_dmevmask; - mp->m_dmevmask = 0; - - for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { - /* - * Find the agi for this ag. - */ - error = xfs_read_agi(mp, NULL, agno, &agibp); - if (error) { - /* - * AGI is b0rked. Don't process it. - * - * We should probably mark the filesystem as corrupt - * after we've recovered all the ag's we can.... - */ - continue; - } - /* - * Unlock the buffer so that it can be acquired in the normal - * course of the transaction to truncate and free each inode. - * Because we are not racing with anyone else here for the AGI - * buffer, we don't even need to hold it locked to read the - * initial unlinked bucket entries out of the buffer. We keep - * buffer reference though, so that it stays pinned in memory - * while we need the buffer. - */ - agi = XFS_BUF_TO_AGI(agibp); - xfs_buf_unlock(agibp); - - for (bucket = 0; bucket < XFS_AGI_UNLINKED_BUCKETS; bucket++) { - agino = be32_to_cpu(agi->agi_unlinked[bucket]); - while (agino != NULLAGINO) { - agino = xlog_recover_process_one_iunlink(mp, - agno, agino, bucket); - } - } - xfs_buf_rele(agibp); - } - - mp->m_dmevmask = mp_dmevmask; -} - -STATIC int -xlog_unpack_data( - struct xlog_rec_header *rhead, - char *dp, - struct xlog *log) -{ - int i, j, k; - - for (i = 0; i < BTOBB(be32_to_cpu(rhead->h_len)) && - i < (XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) { - *(__be32 *)dp = *(__be32 *)&rhead->h_cycle_data[i]; - dp += BBSIZE; - } - - if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) { - xlog_in_core_2_t *xhdr = (xlog_in_core_2_t *)rhead; - for ( ; i < BTOBB(be32_to_cpu(rhead->h_len)); i++) { - j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE); - k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE); - *(__be32 *)dp = xhdr[j].hic_xheader.xh_cycle_data[k]; - dp += BBSIZE; - } - } - - return 0; -} - -/* - * CRC check, unpack and process a log record. - */ -STATIC int -xlog_recover_process( - struct xlog *log, - struct hlist_head rhash[], - struct xlog_rec_header *rhead, - char *dp, - int pass, - struct list_head *buffer_list) -{ - int error; - __le32 crc; - - crc = xlog_cksum(log, rhead, dp, be32_to_cpu(rhead->h_len)); - - /* - * Nothing else to do if this is a CRC verification pass. Just return - * if this a record with a non-zero crc. Unfortunately, mkfs always - * sets h_crc to 0 so we must consider this valid even on v5 supers. - * Otherwise, return EFSBADCRC on failure so the callers up the stack - * know precisely what failed. - */ - if (pass == XLOG_RECOVER_CRCPASS) { - if (rhead->h_crc && crc != rhead->h_crc) - return -EFSBADCRC; - return 0; - } - - /* - * We're in the normal recovery path. Issue a warning if and only if the - * CRC in the header is non-zero. This is an advisory warning and the - * zero CRC check prevents warnings from being emitted when upgrading - * the kernel from one that does not add CRCs by default. - */ - if (crc != rhead->h_crc) { - if (rhead->h_crc || xfs_sb_version_hascrc(&log->l_mp->m_sb)) { - xfs_alert(log->l_mp, - "log record CRC mismatch: found 0x%x, expected 0x%x.", - le32_to_cpu(rhead->h_crc), - le32_to_cpu(crc)); - xfs_hex_dump(dp, 32); - } - - /* - * If the filesystem is CRC enabled, this mismatch becomes a - * fatal log corruption failure. - */ - if (xfs_sb_version_hascrc(&log->l_mp->m_sb)) - return -EFSCORRUPTED; - } - - error = xlog_unpack_data(rhead, dp, log); - if (error) - return error; - - return xlog_recover_process_data(log, rhash, rhead, dp, pass, - buffer_list); -} - -STATIC int -xlog_valid_rec_header( - struct xlog *log, - struct xlog_rec_header *rhead, - xfs_daddr_t blkno) -{ - int hlen; - - if (unlikely(rhead->h_magicno != cpu_to_be32(XLOG_HEADER_MAGIC_NUM))) { - XFS_ERROR_REPORT("xlog_valid_rec_header(1)", - XFS_ERRLEVEL_LOW, log->l_mp); - return -EFSCORRUPTED; - } - if (unlikely( - (!rhead->h_version || - (be32_to_cpu(rhead->h_version) & (~XLOG_VERSION_OKBITS))))) { - xfs_warn(log->l_mp, "%s: unrecognised log version (%d).", - __func__, be32_to_cpu(rhead->h_version)); - return -EIO; - } - - /* LR body must have data or it wouldn't have been written */ - hlen = be32_to_cpu(rhead->h_len); - if (unlikely( hlen <= 0 || hlen > INT_MAX )) { - XFS_ERROR_REPORT("xlog_valid_rec_header(2)", - XFS_ERRLEVEL_LOW, log->l_mp); - return -EFSCORRUPTED; - } - if (unlikely( blkno > log->l_logBBsize || blkno > INT_MAX )) { - XFS_ERROR_REPORT("xlog_valid_rec_header(3)", - XFS_ERRLEVEL_LOW, log->l_mp); - return -EFSCORRUPTED; - } - return 0; -} - -/* - * Read the log from tail to head and process the log records found. - * Handle the two cases where the tail and head are in the same cycle - * and where the active portion of the log wraps around the end of - * the physical log separately. The pass parameter is passed through - * to the routines called to process the data and is not looked at - * here. - */ -STATIC int -xlog_do_recovery_pass( - struct xlog *log, - xfs_daddr_t head_blk, - xfs_daddr_t tail_blk, - int pass, - xfs_daddr_t *first_bad) /* out: first bad log rec */ -{ - xlog_rec_header_t *rhead; - xfs_daddr_t blk_no; - xfs_daddr_t rhead_blk; - char *offset; - xfs_buf_t *hbp, *dbp; - int error = 0, h_size, h_len; - int error2 = 0; - int bblks, split_bblks; - int hblks, split_hblks, wrapped_hblks; - struct hlist_head rhash[XLOG_RHASH_SIZE]; - LIST_HEAD (buffer_list); - - ASSERT(head_blk != tail_blk); - rhead_blk = 0; - - /* - * Read the header of the tail block and get the iclog buffer size from - * h_size. Use this to tell how many sectors make up the log header. - */ - if (xfs_sb_version_haslogv2(&log->l_mp->m_sb)) { - /* - * When using variable length iclogs, read first sector of - * iclog header and extract the header size from it. Get a - * new hbp that is the correct size. - */ - hbp = xlog_get_bp(log, 1); - if (!hbp) - return -ENOMEM; - - error = xlog_bread(log, tail_blk, 1, hbp, &offset); - if (error) - goto bread_err1; - - rhead = (xlog_rec_header_t *)offset; - error = xlog_valid_rec_header(log, rhead, tail_blk); - if (error) - goto bread_err1; - - /* - * xfsprogs has a bug where record length is based on lsunit but - * h_size (iclog size) is hardcoded to 32k. Now that we - * unconditionally CRC verify the unmount record, this means the - * log buffer can be too small for the record and cause an - * overrun. - * - * Detect this condition here. Use lsunit for the buffer size as - * long as this looks like the mkfs case. Otherwise, return an - * error to avoid a buffer overrun. - */ - h_size = be32_to_cpu(rhead->h_size); - h_len = be32_to_cpu(rhead->h_len); - if (h_len > h_size) { - if (h_len <= log->l_mp->m_logbsize && - be32_to_cpu(rhead->h_num_logops) == 1) { - xfs_warn(log->l_mp, - "invalid iclog size (%d bytes), using lsunit (%d bytes)", - h_size, log->l_mp->m_logbsize); - h_size = log->l_mp->m_logbsize; - } else - return -EFSCORRUPTED; - } - - if ((be32_to_cpu(rhead->h_version) & XLOG_VERSION_2) && - (h_size > XLOG_HEADER_CYCLE_SIZE)) { - hblks = h_size / XLOG_HEADER_CYCLE_SIZE; - if (h_size % XLOG_HEADER_CYCLE_SIZE) - hblks++; - xlog_put_bp(hbp); - hbp = xlog_get_bp(log, hblks); - } else { - hblks = 1; - } - } else { - ASSERT(log->l_sectBBsize == 1); - hblks = 1; - hbp = xlog_get_bp(log, 1); - h_size = XLOG_BIG_RECORD_BSIZE; - } - - if (!hbp) - return -ENOMEM; - dbp = xlog_get_bp(log, BTOBB(h_size)); - if (!dbp) { - xlog_put_bp(hbp); - return -ENOMEM; - } - - memset(rhash, 0, sizeof(rhash)); - blk_no = rhead_blk = tail_blk; - if (tail_blk > head_blk) { - /* - * Perform recovery around the end of the physical log. - * When the head is not on the same cycle number as the tail, - * we can't do a sequential recovery. - */ - while (blk_no < log->l_logBBsize) { - /* - * Check for header wrapping around physical end-of-log - */ - offset = hbp->b_addr; - split_hblks = 0; - wrapped_hblks = 0; - if (blk_no + hblks <= log->l_logBBsize) { - /* Read header in one read */ - error = xlog_bread(log, blk_no, hblks, hbp, - &offset); - if (error) - goto bread_err2; - } else { - /* This LR is split across physical log end */ - if (blk_no != log->l_logBBsize) { - /* some data before physical log end */ - ASSERT(blk_no <= INT_MAX); - split_hblks = log->l_logBBsize - (int)blk_no; - ASSERT(split_hblks > 0); - error = xlog_bread(log, blk_no, - split_hblks, hbp, - &offset); - if (error) - goto bread_err2; - } - - /* - * Note: this black magic still works with - * large sector sizes (non-512) only because: - * - we increased the buffer size originally - * by 1 sector giving us enough extra space - * for the second read; - * - the log start is guaranteed to be sector - * aligned; - * - we read the log end (LR header start) - * _first_, then the log start (LR header end) - * - order is important. - */ - wrapped_hblks = hblks - split_hblks; - error = xlog_bread_offset(log, 0, - wrapped_hblks, hbp, - offset + BBTOB(split_hblks)); - if (error) - goto bread_err2; - } - rhead = (xlog_rec_header_t *)offset; - error = xlog_valid_rec_header(log, rhead, - split_hblks ? blk_no : 0); - if (error) - goto bread_err2; - - bblks = (int)BTOBB(be32_to_cpu(rhead->h_len)); - blk_no += hblks; - - /* Read in data for log record */ - if (blk_no + bblks <= log->l_logBBsize) { - error = xlog_bread(log, blk_no, bblks, dbp, - &offset); - if (error) - goto bread_err2; - } else { - /* This log record is split across the - * physical end of log */ - offset = dbp->b_addr; - split_bblks = 0; - if (blk_no != log->l_logBBsize) { - /* some data is before the physical - * end of log */ - ASSERT(!wrapped_hblks); - ASSERT(blk_no <= INT_MAX); - split_bblks = - log->l_logBBsize - (int)blk_no; - ASSERT(split_bblks > 0); - error = xlog_bread(log, blk_no, - split_bblks, dbp, - &offset); - if (error) - goto bread_err2; - } - - /* - * Note: this black magic still works with - * large sector sizes (non-512) only because: - * - we increased the buffer size originally - * by 1 sector giving us enough extra space - * for the second read; - * - the log start is guaranteed to be sector - * aligned; - * - we read the log end (LR header start) - * _first_, then the log start (LR header end) - * - order is important. - */ - error = xlog_bread_offset(log, 0, - bblks - split_bblks, dbp, - offset + BBTOB(split_bblks)); - if (error) - goto bread_err2; - } - - error = xlog_recover_process(log, rhash, rhead, offset, - pass, &buffer_list); - if (error) - goto bread_err2; - - blk_no += bblks; - rhead_blk = blk_no; - } - - ASSERT(blk_no >= log->l_logBBsize); - blk_no -= log->l_logBBsize; - rhead_blk = blk_no; - } - - /* read first part of physical log */ - while (blk_no < head_blk) { - error = xlog_bread(log, blk_no, hblks, hbp, &offset); - if (error) - goto bread_err2; - - rhead = (xlog_rec_header_t *)offset; - error = xlog_valid_rec_header(log, rhead, blk_no); - if (error) - goto bread_err2; - - /* blocks in data section */ - bblks = (int)BTOBB(be32_to_cpu(rhead->h_len)); - error = xlog_bread(log, blk_no+hblks, bblks, dbp, - &offset); - if (error) - goto bread_err2; - - error = xlog_recover_process(log, rhash, rhead, offset, pass, - &buffer_list); - if (error) - goto bread_err2; - - blk_no += bblks + hblks; - rhead_blk = blk_no; - } - - bread_err2: - xlog_put_bp(dbp); - bread_err1: - xlog_put_bp(hbp); - - /* - * Submit buffers that have been added from the last record processed, - * regardless of error status. - */ - if (!list_empty(&buffer_list)) - error2 = xfs_buf_delwri_submit(&buffer_list); - - if (error && first_bad) - *first_bad = rhead_blk; - - return error ? error : error2; -} - -/* - * Do the recovery of the log. We actually do this in two phases. - * The two passes are necessary in order to implement the function - * of cancelling a record written into the log. The first pass - * determines those things which have been cancelled, and the - * second pass replays log items normally except for those which - * have been cancelled. The handling of the replay and cancellations - * takes place in the log item type specific routines. - * - * The table of items which have cancel records in the log is allocated - * and freed at this level, since only here do we know when all of - * the log recovery has been completed. - */ -STATIC int -xlog_do_log_recovery( - struct xlog *log, - xfs_daddr_t head_blk, - xfs_daddr_t tail_blk) -{ - int error, i; - - ASSERT(head_blk != tail_blk); - - /* - * First do a pass to find all of the cancelled buf log items. - * Store them in the buf_cancel_table for use in the second pass. - */ - log->l_buf_cancel_table = kmem_zalloc(XLOG_BC_TABLE_SIZE * - sizeof(struct list_head), - KM_SLEEP); - for (i = 0; i < XLOG_BC_TABLE_SIZE; i++) - INIT_LIST_HEAD(&log->l_buf_cancel_table[i]); - - error = xlog_do_recovery_pass(log, head_blk, tail_blk, - XLOG_RECOVER_PASS1, NULL); - if (error != 0) { - kmem_free(log->l_buf_cancel_table); - log->l_buf_cancel_table = NULL; - return error; - } - /* - * Then do a second pass to actually recover the items in the log. - * When it is complete free the table of buf cancel items. - */ - error = xlog_do_recovery_pass(log, head_blk, tail_blk, - XLOG_RECOVER_PASS2, NULL); -#ifdef DEBUG - if (!error) { - int i; - - for (i = 0; i < XLOG_BC_TABLE_SIZE; i++) - ASSERT(list_empty(&log->l_buf_cancel_table[i])); - } -#endif /* DEBUG */ - - kmem_free(log->l_buf_cancel_table); - log->l_buf_cancel_table = NULL; - - return error; -} - -/* - * Do the actual recovery - */ -STATIC int -xlog_do_recover( - struct xlog *log, - xfs_daddr_t head_blk, - xfs_daddr_t tail_blk) -{ - struct xfs_mount *mp = log->l_mp; - int error; - xfs_buf_t *bp; - xfs_sb_t *sbp; - - /* - * First replay the images in the log. - */ - error = xlog_do_log_recovery(log, head_blk, tail_blk); - if (error) - return error; - - /* - * If IO errors happened during recovery, bail out. - */ - if (XFS_FORCED_SHUTDOWN(mp)) { - return -EIO; - } - - /* - * We now update the tail_lsn since much of the recovery has completed - * and there may be space available to use. If there were no extent - * or iunlinks, we can free up the entire log and set the tail_lsn to - * be the last_sync_lsn. This was set in xlog_find_tail to be the - * lsn of the last known good LR on disk. If there are extent frees - * or iunlinks they will have some entries in the AIL; so we look at - * the AIL to determine how to set the tail_lsn. - */ - xlog_assign_tail_lsn(mp); - - /* - * Now that we've finished replaying all buffer and inode - * updates, re-read in the superblock and reverify it. - */ - bp = xfs_getsb(mp, 0); - bp->b_flags &= ~(XBF_DONE | XBF_ASYNC); - ASSERT(!(bp->b_flags & XBF_WRITE)); - bp->b_flags |= XBF_READ; - bp->b_ops = &xfs_sb_buf_ops; - - error = xfs_buf_submit_wait(bp); - if (error) { - if (!XFS_FORCED_SHUTDOWN(mp)) { - xfs_buf_ioerror_alert(bp, __func__); - ASSERT(0); - } - xfs_buf_relse(bp); - return error; - } - - /* Convert superblock from on-disk format */ - sbp = &mp->m_sb; - xfs_sb_from_disk(sbp, XFS_BUF_TO_SBP(bp)); - xfs_buf_relse(bp); - - /* re-initialise in-core superblock and geometry structures */ - xfs_reinit_percpu_counters(mp); - error = xfs_initialize_perag(mp, sbp->sb_agcount, &mp->m_maxagi); - if (error) { - xfs_warn(mp, "Failed post-recovery per-ag init: %d", error); - return error; - } - mp->m_alloc_set_aside = xfs_alloc_set_aside(mp); - - xlog_recover_check_summary(log); - - /* Normal transactions can now occur */ - log->l_flags &= ~XLOG_ACTIVE_RECOVERY; - return 0; -} - -/* - * Perform recovery and re-initialize some log variables in xlog_find_tail. - * - * Return error or zero. - */ -int -xlog_recover( - struct xlog *log) -{ - xfs_daddr_t head_blk, tail_blk; - int error; - - /* find the tail of the log */ - error = xlog_find_tail(log, &head_blk, &tail_blk); - if (error) - return error; - - /* - * The superblock was read before the log was available and thus the LSN - * could not be verified. Check the superblock LSN against the current - * LSN now that it's known. - */ - if (xfs_sb_version_hascrc(&log->l_mp->m_sb) && - !xfs_log_check_lsn(log->l_mp, log->l_mp->m_sb.sb_lsn)) - return -EINVAL; - - if (tail_blk != head_blk) { - /* There used to be a comment here: - * - * disallow recovery on read-only mounts. note -- mount - * checks for ENOSPC and turns it into an intelligent - * error message. - * ...but this is no longer true. Now, unless you specify - * NORECOVERY (in which case this function would never be - * called), we just go ahead and recover. We do this all - * under the vfs layer, so we can get away with it unless - * the device itself is read-only, in which case we fail. - */ - if ((error = xfs_dev_is_read_only(log->l_mp, "recovery"))) { - return error; - } - - /* - * Version 5 superblock log feature mask validation. We know the - * log is dirty so check if there are any unknown log features - * in what we need to recover. If there are unknown features - * (e.g. unsupported transactions, then simply reject the - * attempt at recovery before touching anything. - */ - if (XFS_SB_VERSION_NUM(&log->l_mp->m_sb) == XFS_SB_VERSION_5 && - xfs_sb_has_incompat_log_feature(&log->l_mp->m_sb, - XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN)) { - xfs_warn(log->l_mp, -"Superblock has unknown incompatible log features (0x%x) enabled.", - (log->l_mp->m_sb.sb_features_log_incompat & - XFS_SB_FEAT_INCOMPAT_LOG_UNKNOWN)); - xfs_warn(log->l_mp, -"The log can not be fully and/or safely recovered by this kernel."); - xfs_warn(log->l_mp, -"Please recover the log on a kernel that supports the unknown features."); - return -EINVAL; - } - - /* - * Delay log recovery if the debug hook is set. This is debug - * instrumention to coordinate simulation of I/O failures with - * log recovery. - */ - if (xfs_globals.log_recovery_delay) { - xfs_notice(log->l_mp, - "Delaying log recovery for %d seconds.", - xfs_globals.log_recovery_delay); - msleep(xfs_globals.log_recovery_delay * 1000); - } - - xfs_notice(log->l_mp, "Starting recovery (logdev: %s)", - log->l_mp->m_logname ? log->l_mp->m_logname - : "internal"); - - error = xlog_do_recover(log, head_blk, tail_blk); - log->l_flags |= XLOG_RECOVERY_NEEDED; - } - return error; -} - -/* - * In the first part of recovery we replay inodes and buffers and build - * up the list of extent free items which need to be processed. Here - * we process the extent free items and clean up the on disk unlinked - * inode lists. This is separated from the first part of recovery so - * that the root and real-time bitmap inodes can be read in from disk in - * between the two stages. This is necessary so that we can free space - * in the real-time portion of the file system. - */ -int -xlog_recover_finish( - struct xlog *log) -{ - /* - * Now we're ready to do the transactions needed for the - * rest of recovery. Start with completing all the extent - * free intent records and then process the unlinked inode - * lists. At this point, we essentially run in normal mode - * except that we're still performing recovery actions - * rather than accepting new requests. - */ - if (log->l_flags & XLOG_RECOVERY_NEEDED) { - int error; - error = xlog_recover_process_intents(log); - if (error) { - xfs_alert(log->l_mp, "Failed to recover intents"); - return error; - } - - /* - * Sync the log to get all the intents out of the AIL. - * This isn't absolutely necessary, but it helps in - * case the unlink transactions would have problems - * pushing the intents out of the way. - */ - xfs_log_force(log->l_mp, XFS_LOG_SYNC); - - xlog_recover_process_iunlinks(log); - - xlog_recover_check_summary(log); - - xfs_notice(log->l_mp, "Ending recovery (logdev: %s)", - log->l_mp->m_logname ? log->l_mp->m_logname - : "internal"); - log->l_flags &= ~XLOG_RECOVERY_NEEDED; - } else { - xfs_info(log->l_mp, "Ending clean mount"); - } - return 0; -} - -int -xlog_recover_cancel( - struct xlog *log) -{ - int error = 0; - - if (log->l_flags & XLOG_RECOVERY_NEEDED) - error = xlog_recover_cancel_intents(log); - - return error; -} - -#if defined(DEBUG) -/* - * Read all of the agf and agi counters and check that they - * are consistent with the superblock counters. - */ -void -xlog_recover_check_summary( - struct xlog *log) -{ - xfs_mount_t *mp; - xfs_agf_t *agfp; - xfs_buf_t *agfbp; - xfs_buf_t *agibp; - xfs_agnumber_t agno; - __uint64_t freeblks; - __uint64_t itotal; - __uint64_t ifree; - int error; - - mp = log->l_mp; - - freeblks = 0LL; - itotal = 0LL; - ifree = 0LL; - for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { - error = xfs_read_agf(mp, NULL, agno, 0, &agfbp); - if (error) { - xfs_alert(mp, "%s agf read failed agno %d error %d", - __func__, agno, error); - } else { - agfp = XFS_BUF_TO_AGF(agfbp); - freeblks += be32_to_cpu(agfp->agf_freeblks) + - be32_to_cpu(agfp->agf_flcount); - xfs_buf_relse(agfbp); - } - - error = xfs_read_agi(mp, NULL, agno, &agibp); - if (error) { - xfs_alert(mp, "%s agi read failed agno %d error %d", - __func__, agno, error); - } else { - struct xfs_agi *agi = XFS_BUF_TO_AGI(agibp); - - itotal += be32_to_cpu(agi->agi_count); - ifree += be32_to_cpu(agi->agi_freecount); - xfs_buf_relse(agibp); - } - } -} -#endif /* DEBUG */ diff --git a/src/linux/fs/xfs/xfs_message.c b/src/linux/fs/xfs/xfs_message.c deleted file mode 100644 index 11792d8..0000000 --- a/src/linux/fs/xfs/xfs_message.c +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (c) 2011 Red Hat, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_error.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" - -/* - * XFS logging functions - */ -static void -__xfs_printk( - const char *level, - const struct xfs_mount *mp, - struct va_format *vaf) -{ - if (mp && mp->m_fsname) { - printk("%sXFS (%s): %pV\n", level, mp->m_fsname, vaf); - return; - } - printk("%sXFS: %pV\n", level, vaf); -} - -#define define_xfs_printk_level(func, kern_level) \ -void func(const struct xfs_mount *mp, const char *fmt, ...) \ -{ \ - struct va_format vaf; \ - va_list args; \ - int level; \ - \ - va_start(args, fmt); \ - \ - vaf.fmt = fmt; \ - vaf.va = &args; \ - \ - __xfs_printk(kern_level, mp, &vaf); \ - va_end(args); \ - \ - if (!kstrtoint(kern_level, 0, &level) && \ - level <= LOGLEVEL_ERR && \ - xfs_error_level >= XFS_ERRLEVEL_HIGH) \ - xfs_stack_trace(); \ -} \ - -define_xfs_printk_level(xfs_emerg, KERN_EMERG); -define_xfs_printk_level(xfs_alert, KERN_ALERT); -define_xfs_printk_level(xfs_crit, KERN_CRIT); -define_xfs_printk_level(xfs_err, KERN_ERR); -define_xfs_printk_level(xfs_warn, KERN_WARNING); -define_xfs_printk_level(xfs_notice, KERN_NOTICE); -define_xfs_printk_level(xfs_info, KERN_INFO); -#ifdef DEBUG -define_xfs_printk_level(xfs_debug, KERN_DEBUG); -#endif - -void -xfs_alert_tag( - const struct xfs_mount *mp, - int panic_tag, - const char *fmt, ...) -{ - struct va_format vaf; - va_list args; - int do_panic = 0; - - if (xfs_panic_mask && (xfs_panic_mask & panic_tag)) { - xfs_alert(mp, "Transforming an alert into a BUG."); - do_panic = 1; - } - - va_start(args, fmt); - - vaf.fmt = fmt; - vaf.va = &args; - - __xfs_printk(KERN_ALERT, mp, &vaf); - va_end(args); - - BUG_ON(do_panic); -} - -void -asswarn(char *expr, char *file, int line) -{ - xfs_warn(NULL, "Assertion failed: %s, file: %s, line: %d", - expr, file, line); - WARN_ON(1); -} - -void -assfail(char *expr, char *file, int line) -{ - xfs_emerg(NULL, "Assertion failed: %s, file: %s, line: %d", - expr, file, line); - BUG(); -} - -void -xfs_hex_dump(void *p, int length) -{ - print_hex_dump(KERN_ALERT, "", DUMP_PREFIX_ADDRESS, 16, 1, p, length, 1); -} diff --git a/src/linux/fs/xfs/xfs_message.h b/src/linux/fs/xfs/xfs_message.h deleted file mode 100644 index 8540115..0000000 --- a/src/linux/fs/xfs/xfs_message.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef __XFS_MESSAGE_H -#define __XFS_MESSAGE_H 1 - -struct xfs_mount; - -extern __printf(2, 3) -void xfs_emerg(const struct xfs_mount *mp, const char *fmt, ...); -extern __printf(2, 3) -void xfs_alert(const struct xfs_mount *mp, const char *fmt, ...); -extern __printf(3, 4) -void xfs_alert_tag(const struct xfs_mount *mp, int tag, const char *fmt, ...); -extern __printf(2, 3) -void xfs_crit(const struct xfs_mount *mp, const char *fmt, ...); -extern __printf(2, 3) -void xfs_err(const struct xfs_mount *mp, const char *fmt, ...); -extern __printf(2, 3) -void xfs_warn(const struct xfs_mount *mp, const char *fmt, ...); -extern __printf(2, 3) -void xfs_notice(const struct xfs_mount *mp, const char *fmt, ...); -extern __printf(2, 3) -void xfs_info(const struct xfs_mount *mp, const char *fmt, ...); - -#ifdef DEBUG -extern __printf(2, 3) -void xfs_debug(const struct xfs_mount *mp, const char *fmt, ...); -#else -static inline __printf(2, 3) -void xfs_debug(const struct xfs_mount *mp, const char *fmt, ...) -{ -} -#endif - -#define xfs_printk_ratelimited(func, dev, fmt, ...) \ -do { \ - static DEFINE_RATELIMIT_STATE(_rs, \ - DEFAULT_RATELIMIT_INTERVAL, \ - DEFAULT_RATELIMIT_BURST); \ - if (__ratelimit(&_rs)) \ - func(dev, fmt, ##__VA_ARGS__); \ -} while (0) - -#define xfs_emerg_ratelimited(dev, fmt, ...) \ - xfs_printk_ratelimited(xfs_emerg, dev, fmt, ##__VA_ARGS__) -#define xfs_alert_ratelimited(dev, fmt, ...) \ - xfs_printk_ratelimited(xfs_alert, dev, fmt, ##__VA_ARGS__) -#define xfs_crit_ratelimited(dev, fmt, ...) \ - xfs_printk_ratelimited(xfs_crit, dev, fmt, ##__VA_ARGS__) -#define xfs_err_ratelimited(dev, fmt, ...) \ - xfs_printk_ratelimited(xfs_err, dev, fmt, ##__VA_ARGS__) -#define xfs_warn_ratelimited(dev, fmt, ...) \ - xfs_printk_ratelimited(xfs_warn, dev, fmt, ##__VA_ARGS__) -#define xfs_notice_ratelimited(dev, fmt, ...) \ - xfs_printk_ratelimited(xfs_notice, dev, fmt, ##__VA_ARGS__) -#define xfs_info_ratelimited(dev, fmt, ...) \ - xfs_printk_ratelimited(xfs_info, dev, fmt, ##__VA_ARGS__) -#define xfs_debug_ratelimited(dev, fmt, ...) \ - xfs_printk_ratelimited(xfs_debug, dev, fmt, ##__VA_ARGS__) - -extern void assfail(char *expr, char *f, int l); -extern void asswarn(char *expr, char *f, int l); - -extern void xfs_hex_dump(void *p, int length); - -#endif /* __XFS_MESSAGE_H */ diff --git a/src/linux/fs/xfs/xfs_mount.c b/src/linux/fs/xfs/xfs_mount.c deleted file mode 100644 index b341f10..0000000 --- a/src/linux/fs/xfs/xfs_mount.c +++ /dev/null @@ -1,1377 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_inode.h" -#include "xfs_dir2.h" -#include "xfs_ialloc.h" -#include "xfs_alloc.h" -#include "xfs_rtalloc.h" -#include "xfs_bmap.h" -#include "xfs_trans.h" -#include "xfs_trans_priv.h" -#include "xfs_log.h" -#include "xfs_error.h" -#include "xfs_quota.h" -#include "xfs_fsops.h" -#include "xfs_trace.h" -#include "xfs_icache.h" -#include "xfs_sysfs.h" -#include "xfs_rmap_btree.h" -#include "xfs_refcount_btree.h" -#include "xfs_reflink.h" - - -static DEFINE_MUTEX(xfs_uuid_table_mutex); -static int xfs_uuid_table_size; -static uuid_t *xfs_uuid_table; - -void -xfs_uuid_table_free(void) -{ - if (xfs_uuid_table_size == 0) - return; - kmem_free(xfs_uuid_table); - xfs_uuid_table = NULL; - xfs_uuid_table_size = 0; -} - -/* - * See if the UUID is unique among mounted XFS filesystems. - * Mount fails if UUID is nil or a FS with the same UUID is already mounted. - */ -STATIC int -xfs_uuid_mount( - struct xfs_mount *mp) -{ - uuid_t *uuid = &mp->m_sb.sb_uuid; - int hole, i; - - if (mp->m_flags & XFS_MOUNT_NOUUID) - return 0; - - if (uuid_is_nil(uuid)) { - xfs_warn(mp, "Filesystem has nil UUID - can't mount"); - return -EINVAL; - } - - mutex_lock(&xfs_uuid_table_mutex); - for (i = 0, hole = -1; i < xfs_uuid_table_size; i++) { - if (uuid_is_nil(&xfs_uuid_table[i])) { - hole = i; - continue; - } - if (uuid_equal(uuid, &xfs_uuid_table[i])) - goto out_duplicate; - } - - if (hole < 0) { - xfs_uuid_table = kmem_realloc(xfs_uuid_table, - (xfs_uuid_table_size + 1) * sizeof(*xfs_uuid_table), - KM_SLEEP); - hole = xfs_uuid_table_size++; - } - xfs_uuid_table[hole] = *uuid; - mutex_unlock(&xfs_uuid_table_mutex); - - return 0; - - out_duplicate: - mutex_unlock(&xfs_uuid_table_mutex); - xfs_warn(mp, "Filesystem has duplicate UUID %pU - can't mount", uuid); - return -EINVAL; -} - -STATIC void -xfs_uuid_unmount( - struct xfs_mount *mp) -{ - uuid_t *uuid = &mp->m_sb.sb_uuid; - int i; - - if (mp->m_flags & XFS_MOUNT_NOUUID) - return; - - mutex_lock(&xfs_uuid_table_mutex); - for (i = 0; i < xfs_uuid_table_size; i++) { - if (uuid_is_nil(&xfs_uuid_table[i])) - continue; - if (!uuid_equal(uuid, &xfs_uuid_table[i])) - continue; - memset(&xfs_uuid_table[i], 0, sizeof(uuid_t)); - break; - } - ASSERT(i < xfs_uuid_table_size); - mutex_unlock(&xfs_uuid_table_mutex); -} - - -STATIC void -__xfs_free_perag( - struct rcu_head *head) -{ - struct xfs_perag *pag = container_of(head, struct xfs_perag, rcu_head); - - ASSERT(atomic_read(&pag->pag_ref) == 0); - kmem_free(pag); -} - -/* - * Free up the per-ag resources associated with the mount structure. - */ -STATIC void -xfs_free_perag( - xfs_mount_t *mp) -{ - xfs_agnumber_t agno; - struct xfs_perag *pag; - - for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { - spin_lock(&mp->m_perag_lock); - pag = radix_tree_delete(&mp->m_perag_tree, agno); - spin_unlock(&mp->m_perag_lock); - ASSERT(pag); - ASSERT(atomic_read(&pag->pag_ref) == 0); - call_rcu(&pag->rcu_head, __xfs_free_perag); - } -} - -/* - * Check size of device based on the (data/realtime) block count. - * Note: this check is used by the growfs code as well as mount. - */ -int -xfs_sb_validate_fsb_count( - xfs_sb_t *sbp, - __uint64_t nblocks) -{ - ASSERT(PAGE_SHIFT >= sbp->sb_blocklog); - ASSERT(sbp->sb_blocklog >= BBSHIFT); - - /* Limited by ULONG_MAX of page cache index */ - if (nblocks >> (PAGE_SHIFT - sbp->sb_blocklog) > ULONG_MAX) - return -EFBIG; - return 0; -} - -int -xfs_initialize_perag( - xfs_mount_t *mp, - xfs_agnumber_t agcount, - xfs_agnumber_t *maxagi) -{ - xfs_agnumber_t index; - xfs_agnumber_t first_initialised = 0; - xfs_perag_t *pag; - int error = -ENOMEM; - - /* - * Walk the current per-ag tree so we don't try to initialise AGs - * that already exist (growfs case). Allocate and insert all the - * AGs we don't find ready for initialisation. - */ - for (index = 0; index < agcount; index++) { - pag = xfs_perag_get(mp, index); - if (pag) { - xfs_perag_put(pag); - continue; - } - if (!first_initialised) - first_initialised = index; - - pag = kmem_zalloc(sizeof(*pag), KM_MAYFAIL); - if (!pag) - goto out_unwind; - pag->pag_agno = index; - pag->pag_mount = mp; - spin_lock_init(&pag->pag_ici_lock); - mutex_init(&pag->pag_ici_reclaim_lock); - INIT_RADIX_TREE(&pag->pag_ici_root, GFP_ATOMIC); - spin_lock_init(&pag->pag_buf_lock); - pag->pag_buf_tree = RB_ROOT; - - if (radix_tree_preload(GFP_NOFS)) - goto out_unwind; - - spin_lock(&mp->m_perag_lock); - if (radix_tree_insert(&mp->m_perag_tree, index, pag)) { - BUG(); - spin_unlock(&mp->m_perag_lock); - radix_tree_preload_end(); - error = -EEXIST; - goto out_unwind; - } - spin_unlock(&mp->m_perag_lock); - radix_tree_preload_end(); - } - - index = xfs_set_inode_alloc(mp, agcount); - - if (maxagi) - *maxagi = index; - - mp->m_ag_prealloc_blocks = xfs_prealloc_blocks(mp); - return 0; - -out_unwind: - kmem_free(pag); - for (; index > first_initialised; index--) { - pag = radix_tree_delete(&mp->m_perag_tree, index); - kmem_free(pag); - } - return error; -} - -/* - * xfs_readsb - * - * Does the initial read of the superblock. - */ -int -xfs_readsb( - struct xfs_mount *mp, - int flags) -{ - unsigned int sector_size; - struct xfs_buf *bp; - struct xfs_sb *sbp = &mp->m_sb; - int error; - int loud = !(flags & XFS_MFSI_QUIET); - const struct xfs_buf_ops *buf_ops; - - ASSERT(mp->m_sb_bp == NULL); - ASSERT(mp->m_ddev_targp != NULL); - - /* - * For the initial read, we must guess at the sector - * size based on the block device. It's enough to - * get the sb_sectsize out of the superblock and - * then reread with the proper length. - * We don't verify it yet, because it may not be complete. - */ - sector_size = xfs_getsize_buftarg(mp->m_ddev_targp); - buf_ops = NULL; - - /* - * Allocate a (locked) buffer to hold the superblock. This will be kept - * around at all times to optimize access to the superblock. Therefore, - * set XBF_NO_IOACCT to make sure it doesn't hold the buftarg count - * elevated. - */ -reread: - error = xfs_buf_read_uncached(mp->m_ddev_targp, XFS_SB_DADDR, - BTOBB(sector_size), XBF_NO_IOACCT, &bp, - buf_ops); - if (error) { - if (loud) - xfs_warn(mp, "SB validate failed with error %d.", error); - /* bad CRC means corrupted metadata */ - if (error == -EFSBADCRC) - error = -EFSCORRUPTED; - return error; - } - - /* - * Initialize the mount structure from the superblock. - */ - xfs_sb_from_disk(sbp, XFS_BUF_TO_SBP(bp)); - - /* - * If we haven't validated the superblock, do so now before we try - * to check the sector size and reread the superblock appropriately. - */ - if (sbp->sb_magicnum != XFS_SB_MAGIC) { - if (loud) - xfs_warn(mp, "Invalid superblock magic number"); - error = -EINVAL; - goto release_buf; - } - - /* - * We must be able to do sector-sized and sector-aligned IO. - */ - if (sector_size > sbp->sb_sectsize) { - if (loud) - xfs_warn(mp, "device supports %u byte sectors (not %u)", - sector_size, sbp->sb_sectsize); - error = -ENOSYS; - goto release_buf; - } - - if (buf_ops == NULL) { - /* - * Re-read the superblock so the buffer is correctly sized, - * and properly verified. - */ - xfs_buf_relse(bp); - sector_size = sbp->sb_sectsize; - buf_ops = loud ? &xfs_sb_buf_ops : &xfs_sb_quiet_buf_ops; - goto reread; - } - - xfs_reinit_percpu_counters(mp); - - /* no need to be quiet anymore, so reset the buf ops */ - bp->b_ops = &xfs_sb_buf_ops; - - mp->m_sb_bp = bp; - xfs_buf_unlock(bp); - return 0; - -release_buf: - xfs_buf_relse(bp); - return error; -} - -/* - * Update alignment values based on mount options and sb values - */ -STATIC int -xfs_update_alignment(xfs_mount_t *mp) -{ - xfs_sb_t *sbp = &(mp->m_sb); - - if (mp->m_dalign) { - /* - * If stripe unit and stripe width are not multiples - * of the fs blocksize turn off alignment. - */ - if ((BBTOB(mp->m_dalign) & mp->m_blockmask) || - (BBTOB(mp->m_swidth) & mp->m_blockmask)) { - xfs_warn(mp, - "alignment check failed: sunit/swidth vs. blocksize(%d)", - sbp->sb_blocksize); - return -EINVAL; - } else { - /* - * Convert the stripe unit and width to FSBs. - */ - mp->m_dalign = XFS_BB_TO_FSBT(mp, mp->m_dalign); - if (mp->m_dalign && (sbp->sb_agblocks % mp->m_dalign)) { - xfs_warn(mp, - "alignment check failed: sunit/swidth vs. agsize(%d)", - sbp->sb_agblocks); - return -EINVAL; - } else if (mp->m_dalign) { - mp->m_swidth = XFS_BB_TO_FSBT(mp, mp->m_swidth); - } else { - xfs_warn(mp, - "alignment check failed: sunit(%d) less than bsize(%d)", - mp->m_dalign, sbp->sb_blocksize); - return -EINVAL; - } - } - - /* - * Update superblock with new values - * and log changes - */ - if (xfs_sb_version_hasdalign(sbp)) { - if (sbp->sb_unit != mp->m_dalign) { - sbp->sb_unit = mp->m_dalign; - mp->m_update_sb = true; - } - if (sbp->sb_width != mp->m_swidth) { - sbp->sb_width = mp->m_swidth; - mp->m_update_sb = true; - } - } else { - xfs_warn(mp, - "cannot change alignment: superblock does not support data alignment"); - return -EINVAL; - } - } else if ((mp->m_flags & XFS_MOUNT_NOALIGN) != XFS_MOUNT_NOALIGN && - xfs_sb_version_hasdalign(&mp->m_sb)) { - mp->m_dalign = sbp->sb_unit; - mp->m_swidth = sbp->sb_width; - } - - return 0; -} - -/* - * Set the maximum inode count for this filesystem - */ -STATIC void -xfs_set_maxicount(xfs_mount_t *mp) -{ - xfs_sb_t *sbp = &(mp->m_sb); - __uint64_t icount; - - if (sbp->sb_imax_pct) { - /* - * Make sure the maximum inode count is a multiple - * of the units we allocate inodes in. - */ - icount = sbp->sb_dblocks * sbp->sb_imax_pct; - do_div(icount, 100); - do_div(icount, mp->m_ialloc_blks); - mp->m_maxicount = (icount * mp->m_ialloc_blks) << - sbp->sb_inopblog; - } else { - mp->m_maxicount = 0; - } -} - -/* - * Set the default minimum read and write sizes unless - * already specified in a mount option. - * We use smaller I/O sizes when the file system - * is being used for NFS service (wsync mount option). - */ -STATIC void -xfs_set_rw_sizes(xfs_mount_t *mp) -{ - xfs_sb_t *sbp = &(mp->m_sb); - int readio_log, writeio_log; - - if (!(mp->m_flags & XFS_MOUNT_DFLT_IOSIZE)) { - if (mp->m_flags & XFS_MOUNT_WSYNC) { - readio_log = XFS_WSYNC_READIO_LOG; - writeio_log = XFS_WSYNC_WRITEIO_LOG; - } else { - readio_log = XFS_READIO_LOG_LARGE; - writeio_log = XFS_WRITEIO_LOG_LARGE; - } - } else { - readio_log = mp->m_readio_log; - writeio_log = mp->m_writeio_log; - } - - if (sbp->sb_blocklog > readio_log) { - mp->m_readio_log = sbp->sb_blocklog; - } else { - mp->m_readio_log = readio_log; - } - mp->m_readio_blocks = 1 << (mp->m_readio_log - sbp->sb_blocklog); - if (sbp->sb_blocklog > writeio_log) { - mp->m_writeio_log = sbp->sb_blocklog; - } else { - mp->m_writeio_log = writeio_log; - } - mp->m_writeio_blocks = 1 << (mp->m_writeio_log - sbp->sb_blocklog); -} - -/* - * precalculate the low space thresholds for dynamic speculative preallocation. - */ -void -xfs_set_low_space_thresholds( - struct xfs_mount *mp) -{ - int i; - - for (i = 0; i < XFS_LOWSP_MAX; i++) { - __uint64_t space = mp->m_sb.sb_dblocks; - - do_div(space, 100); - mp->m_low_space[i] = space * (i + 1); - } -} - - -/* - * Set whether we're using inode alignment. - */ -STATIC void -xfs_set_inoalignment(xfs_mount_t *mp) -{ - if (xfs_sb_version_hasalign(&mp->m_sb) && - mp->m_sb.sb_inoalignmt >= - XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size)) - mp->m_inoalign_mask = mp->m_sb.sb_inoalignmt - 1; - else - mp->m_inoalign_mask = 0; - /* - * If we are using stripe alignment, check whether - * the stripe unit is a multiple of the inode alignment - */ - if (mp->m_dalign && mp->m_inoalign_mask && - !(mp->m_dalign & mp->m_inoalign_mask)) - mp->m_sinoalign = mp->m_dalign; - else - mp->m_sinoalign = 0; -} - -/* - * Check that the data (and log if separate) is an ok size. - */ -STATIC int -xfs_check_sizes( - struct xfs_mount *mp) -{ - struct xfs_buf *bp; - xfs_daddr_t d; - int error; - - d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_dblocks); - if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_dblocks) { - xfs_warn(mp, "filesystem size mismatch detected"); - return -EFBIG; - } - error = xfs_buf_read_uncached(mp->m_ddev_targp, - d - XFS_FSS_TO_BB(mp, 1), - XFS_FSS_TO_BB(mp, 1), 0, &bp, NULL); - if (error) { - xfs_warn(mp, "last sector read failed"); - return error; - } - xfs_buf_relse(bp); - - if (mp->m_logdev_targp == mp->m_ddev_targp) - return 0; - - d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks); - if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_logblocks) { - xfs_warn(mp, "log size mismatch detected"); - return -EFBIG; - } - error = xfs_buf_read_uncached(mp->m_logdev_targp, - d - XFS_FSB_TO_BB(mp, 1), - XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL); - if (error) { - xfs_warn(mp, "log device read failed"); - return error; - } - xfs_buf_relse(bp); - return 0; -} - -/* - * Clear the quotaflags in memory and in the superblock. - */ -int -xfs_mount_reset_sbqflags( - struct xfs_mount *mp) -{ - mp->m_qflags = 0; - - /* It is OK to look at sb_qflags in the mount path without m_sb_lock. */ - if (mp->m_sb.sb_qflags == 0) - return 0; - spin_lock(&mp->m_sb_lock); - mp->m_sb.sb_qflags = 0; - spin_unlock(&mp->m_sb_lock); - - if (!xfs_fs_writable(mp, SB_FREEZE_WRITE)) - return 0; - - return xfs_sync_sb(mp, false); -} - -__uint64_t -xfs_default_resblks(xfs_mount_t *mp) -{ - __uint64_t resblks; - - /* - * We default to 5% or 8192 fsbs of space reserved, whichever is - * smaller. This is intended to cover concurrent allocation - * transactions when we initially hit enospc. These each require a 4 - * block reservation. Hence by default we cover roughly 2000 concurrent - * allocation reservations. - */ - resblks = mp->m_sb.sb_dblocks; - do_div(resblks, 20); - resblks = min_t(__uint64_t, resblks, 8192); - return resblks; -} - -/* - * This function does the following on an initial mount of a file system: - * - reads the superblock from disk and init the mount struct - * - if we're a 32-bit kernel, do a size check on the superblock - * so we don't mount terabyte filesystems - * - init mount struct realtime fields - * - allocate inode hash table for fs - * - init directory manager - * - perform recovery and init the log manager - */ -int -xfs_mountfs( - struct xfs_mount *mp) -{ - struct xfs_sb *sbp = &(mp->m_sb); - struct xfs_inode *rip; - __uint64_t resblks; - uint quotamount = 0; - uint quotaflags = 0; - int error = 0; - - xfs_sb_mount_common(mp, sbp); - - /* - * Check for a mismatched features2 values. Older kernels read & wrote - * into the wrong sb offset for sb_features2 on some platforms due to - * xfs_sb_t not being 64bit size aligned when sb_features2 was added, - * which made older superblock reading/writing routines swap it as a - * 64-bit value. - * - * For backwards compatibility, we make both slots equal. - * - * If we detect a mismatched field, we OR the set bits into the existing - * features2 field in case it has already been modified; we don't want - * to lose any features. We then update the bad location with the ORed - * value so that older kernels will see any features2 flags. The - * superblock writeback code ensures the new sb_features2 is copied to - * sb_bad_features2 before it is logged or written to disk. - */ - if (xfs_sb_has_mismatched_features2(sbp)) { - xfs_warn(mp, "correcting sb_features alignment problem"); - sbp->sb_features2 |= sbp->sb_bad_features2; - mp->m_update_sb = true; - - /* - * Re-check for ATTR2 in case it was found in bad_features2 - * slot. - */ - if (xfs_sb_version_hasattr2(&mp->m_sb) && - !(mp->m_flags & XFS_MOUNT_NOATTR2)) - mp->m_flags |= XFS_MOUNT_ATTR2; - } - - if (xfs_sb_version_hasattr2(&mp->m_sb) && - (mp->m_flags & XFS_MOUNT_NOATTR2)) { - xfs_sb_version_removeattr2(&mp->m_sb); - mp->m_update_sb = true; - - /* update sb_versionnum for the clearing of the morebits */ - if (!sbp->sb_features2) - mp->m_update_sb = true; - } - - /* always use v2 inodes by default now */ - if (!(mp->m_sb.sb_versionnum & XFS_SB_VERSION_NLINKBIT)) { - mp->m_sb.sb_versionnum |= XFS_SB_VERSION_NLINKBIT; - mp->m_update_sb = true; - } - - /* - * Check if sb_agblocks is aligned at stripe boundary - * If sb_agblocks is NOT aligned turn off m_dalign since - * allocator alignment is within an ag, therefore ag has - * to be aligned at stripe boundary. - */ - error = xfs_update_alignment(mp); - if (error) - goto out; - - xfs_alloc_compute_maxlevels(mp); - xfs_bmap_compute_maxlevels(mp, XFS_DATA_FORK); - xfs_bmap_compute_maxlevels(mp, XFS_ATTR_FORK); - xfs_ialloc_compute_maxlevels(mp); - xfs_rmapbt_compute_maxlevels(mp); - xfs_refcountbt_compute_maxlevels(mp); - - xfs_set_maxicount(mp); - - /* enable fail_at_unmount as default */ - mp->m_fail_unmount = 1; - - error = xfs_sysfs_init(&mp->m_kobj, &xfs_mp_ktype, NULL, mp->m_fsname); - if (error) - goto out; - - error = xfs_sysfs_init(&mp->m_stats.xs_kobj, &xfs_stats_ktype, - &mp->m_kobj, "stats"); - if (error) - goto out_remove_sysfs; - - error = xfs_error_sysfs_init(mp); - if (error) - goto out_del_stats; - - - error = xfs_uuid_mount(mp); - if (error) - goto out_remove_error_sysfs; - - /* - * Set the minimum read and write sizes - */ - xfs_set_rw_sizes(mp); - - /* set the low space thresholds for dynamic preallocation */ - xfs_set_low_space_thresholds(mp); - - /* - * Set the inode cluster size. - * This may still be overridden by the file system - * block size if it is larger than the chosen cluster size. - * - * For v5 filesystems, scale the cluster size with the inode size to - * keep a constant ratio of inode per cluster buffer, but only if mkfs - * has set the inode alignment value appropriately for larger cluster - * sizes. - */ - mp->m_inode_cluster_size = XFS_INODE_BIG_CLUSTER_SIZE; - if (xfs_sb_version_hascrc(&mp->m_sb)) { - int new_size = mp->m_inode_cluster_size; - - new_size *= mp->m_sb.sb_inodesize / XFS_DINODE_MIN_SIZE; - if (mp->m_sb.sb_inoalignmt >= XFS_B_TO_FSBT(mp, new_size)) - mp->m_inode_cluster_size = new_size; - } - - /* - * If enabled, sparse inode chunk alignment is expected to match the - * cluster size. Full inode chunk alignment must match the chunk size, - * but that is checked on sb read verification... - */ - if (xfs_sb_version_hassparseinodes(&mp->m_sb) && - mp->m_sb.sb_spino_align != - XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size)) { - xfs_warn(mp, - "Sparse inode block alignment (%u) must match cluster size (%llu).", - mp->m_sb.sb_spino_align, - XFS_B_TO_FSBT(mp, mp->m_inode_cluster_size)); - error = -EINVAL; - goto out_remove_uuid; - } - - /* - * Set inode alignment fields - */ - xfs_set_inoalignment(mp); - - /* - * Check that the data (and log if separate) is an ok size. - */ - error = xfs_check_sizes(mp); - if (error) - goto out_remove_uuid; - - /* - * Initialize realtime fields in the mount structure - */ - error = xfs_rtmount_init(mp); - if (error) { - xfs_warn(mp, "RT mount failed"); - goto out_remove_uuid; - } - - /* - * Copies the low order bits of the timestamp and the randomly - * set "sequence" number out of a UUID. - */ - uuid_getnodeuniq(&sbp->sb_uuid, mp->m_fixedfsid); - - mp->m_dmevmask = 0; /* not persistent; set after each mount */ - - error = xfs_da_mount(mp); - if (error) { - xfs_warn(mp, "Failed dir/attr init: %d", error); - goto out_remove_uuid; - } - - /* - * Initialize the precomputed transaction reservations values. - */ - xfs_trans_init(mp); - - /* - * Allocate and initialize the per-ag data. - */ - spin_lock_init(&mp->m_perag_lock); - INIT_RADIX_TREE(&mp->m_perag_tree, GFP_ATOMIC); - error = xfs_initialize_perag(mp, sbp->sb_agcount, &mp->m_maxagi); - if (error) { - xfs_warn(mp, "Failed per-ag init: %d", error); - goto out_free_dir; - } - - if (!sbp->sb_logblocks) { - xfs_warn(mp, "no log defined"); - XFS_ERROR_REPORT("xfs_mountfs", XFS_ERRLEVEL_LOW, mp); - error = -EFSCORRUPTED; - goto out_free_perag; - } - - /* - * Log's mount-time initialization. The first part of recovery can place - * some items on the AIL, to be handled when recovery is finished or - * cancelled. - */ - error = xfs_log_mount(mp, mp->m_logdev_targp, - XFS_FSB_TO_DADDR(mp, sbp->sb_logstart), - XFS_FSB_TO_BB(mp, sbp->sb_logblocks)); - if (error) { - xfs_warn(mp, "log mount failed"); - goto out_fail_wait; - } - - /* - * Now the log is mounted, we know if it was an unclean shutdown or - * not. If it was, with the first phase of recovery has completed, we - * have consistent AG blocks on disk. We have not recovered EFIs yet, - * but they are recovered transactionally in the second recovery phase - * later. - * - * Hence we can safely re-initialise incore superblock counters from - * the per-ag data. These may not be correct if the filesystem was not - * cleanly unmounted, so we need to wait for recovery to finish before - * doing this. - * - * If the filesystem was cleanly unmounted, then we can trust the - * values in the superblock to be correct and we don't need to do - * anything here. - * - * If we are currently making the filesystem, the initialisation will - * fail as the perag data is in an undefined state. - */ - if (xfs_sb_version_haslazysbcount(&mp->m_sb) && - !XFS_LAST_UNMOUNT_WAS_CLEAN(mp) && - !mp->m_sb.sb_inprogress) { - error = xfs_initialize_perag_data(mp, sbp->sb_agcount); - if (error) - goto out_log_dealloc; - } - - /* - * Get and sanity-check the root inode. - * Save the pointer to it in the mount structure. - */ - error = xfs_iget(mp, NULL, sbp->sb_rootino, 0, XFS_ILOCK_EXCL, &rip); - if (error) { - xfs_warn(mp, "failed to read root inode"); - goto out_log_dealloc; - } - - ASSERT(rip != NULL); - - if (unlikely(!S_ISDIR(VFS_I(rip)->i_mode))) { - xfs_warn(mp, "corrupted root inode %llu: not a directory", - (unsigned long long)rip->i_ino); - xfs_iunlock(rip, XFS_ILOCK_EXCL); - XFS_ERROR_REPORT("xfs_mountfs_int(2)", XFS_ERRLEVEL_LOW, - mp); - error = -EFSCORRUPTED; - goto out_rele_rip; - } - mp->m_rootip = rip; /* save it */ - - xfs_iunlock(rip, XFS_ILOCK_EXCL); - - /* - * Initialize realtime inode pointers in the mount structure - */ - error = xfs_rtmount_inodes(mp); - if (error) { - /* - * Free up the root inode. - */ - xfs_warn(mp, "failed to read RT inodes"); - goto out_rele_rip; - } - - /* - * If this is a read-only mount defer the superblock updates until - * the next remount into writeable mode. Otherwise we would never - * perform the update e.g. for the root filesystem. - */ - if (mp->m_update_sb && !(mp->m_flags & XFS_MOUNT_RDONLY)) { - error = xfs_sync_sb(mp, false); - if (error) { - xfs_warn(mp, "failed to write sb changes"); - goto out_rtunmount; - } - } - - /* - * Initialise the XFS quota management subsystem for this mount - */ - if (XFS_IS_QUOTA_RUNNING(mp)) { - error = xfs_qm_newmount(mp, "amount, "aflags); - if (error) - goto out_rtunmount; - } else { - ASSERT(!XFS_IS_QUOTA_ON(mp)); - - /* - * If a file system had quotas running earlier, but decided to - * mount without -o uquota/pquota/gquota options, revoke the - * quotachecked license. - */ - if (mp->m_sb.sb_qflags & XFS_ALL_QUOTA_ACCT) { - xfs_notice(mp, "resetting quota flags"); - error = xfs_mount_reset_sbqflags(mp); - if (error) - goto out_rtunmount; - } - } - - /* - * During the second phase of log recovery, we need iget and - * iput to behave like they do for an active filesystem. - * xfs_fs_drop_inode needs to be able to prevent the deletion - * of inodes before we're done replaying log items on those - * inodes. - */ - mp->m_super->s_flags |= MS_ACTIVE; - - /* - * Finish recovering the file system. This part needed to be delayed - * until after the root and real-time bitmap inodes were consistently - * read in. - */ - error = xfs_log_mount_finish(mp); - if (error) { - xfs_warn(mp, "log mount finish failed"); - goto out_rtunmount; - } - - /* - * Now the log is fully replayed, we can transition to full read-only - * mode for read-only mounts. This will sync all the metadata and clean - * the log so that the recovery we just performed does not have to be - * replayed again on the next mount. - * - * We use the same quiesce mechanism as the rw->ro remount, as they are - * semantically identical operations. - */ - if ((mp->m_flags & (XFS_MOUNT_RDONLY|XFS_MOUNT_NORECOVERY)) == - XFS_MOUNT_RDONLY) { - xfs_quiesce_attr(mp); - } - - /* - * Complete the quota initialisation, post-log-replay component. - */ - if (quotamount) { - ASSERT(mp->m_qflags == 0); - mp->m_qflags = quotaflags; - - xfs_qm_mount_quotas(mp); - } - - /* - * Now we are mounted, reserve a small amount of unused space for - * privileged transactions. This is needed so that transaction - * space required for critical operations can dip into this pool - * when at ENOSPC. This is needed for operations like create with - * attr, unwritten extent conversion at ENOSPC, etc. Data allocations - * are not allowed to use this reserved space. - * - * This may drive us straight to ENOSPC on mount, but that implies - * we were already there on the last unmount. Warn if this occurs. - */ - if (!(mp->m_flags & XFS_MOUNT_RDONLY)) { - resblks = xfs_default_resblks(mp); - error = xfs_reserve_blocks(mp, &resblks, NULL); - if (error) - xfs_warn(mp, - "Unable to allocate reserve blocks. Continuing without reserve pool."); - - /* Recover any CoW blocks that never got remapped. */ - error = xfs_reflink_recover_cow(mp); - if (error) { - xfs_err(mp, - "Error %d recovering leftover CoW allocations.", error); - xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); - goto out_quota; - } - - /* Reserve AG blocks for future btree expansion. */ - error = xfs_fs_reserve_ag_blocks(mp); - if (error && error != -ENOSPC) - goto out_agresv; - } - - return 0; - - out_agresv: - xfs_fs_unreserve_ag_blocks(mp); - out_quota: - xfs_qm_unmount_quotas(mp); - out_rtunmount: - mp->m_super->s_flags &= ~MS_ACTIVE; - xfs_rtunmount_inodes(mp); - out_rele_rip: - IRELE(rip); - cancel_delayed_work_sync(&mp->m_reclaim_work); - xfs_reclaim_inodes(mp, SYNC_WAIT); - out_log_dealloc: - mp->m_flags |= XFS_MOUNT_UNMOUNTING; - xfs_log_mount_cancel(mp); - out_fail_wait: - if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) - xfs_wait_buftarg(mp->m_logdev_targp); - xfs_wait_buftarg(mp->m_ddev_targp); - out_free_perag: - xfs_free_perag(mp); - out_free_dir: - xfs_da_unmount(mp); - out_remove_uuid: - xfs_uuid_unmount(mp); - out_remove_error_sysfs: - xfs_error_sysfs_del(mp); - out_del_stats: - xfs_sysfs_del(&mp->m_stats.xs_kobj); - out_remove_sysfs: - xfs_sysfs_del(&mp->m_kobj); - out: - return error; -} - -/* - * This flushes out the inodes,dquots and the superblock, unmounts the - * log and makes sure that incore structures are freed. - */ -void -xfs_unmountfs( - struct xfs_mount *mp) -{ - __uint64_t resblks; - int error; - - cancel_delayed_work_sync(&mp->m_eofblocks_work); - cancel_delayed_work_sync(&mp->m_cowblocks_work); - - xfs_fs_unreserve_ag_blocks(mp); - xfs_qm_unmount_quotas(mp); - xfs_rtunmount_inodes(mp); - IRELE(mp->m_rootip); - - /* - * We can potentially deadlock here if we have an inode cluster - * that has been freed has its buffer still pinned in memory because - * the transaction is still sitting in a iclog. The stale inodes - * on that buffer will have their flush locks held until the - * transaction hits the disk and the callbacks run. the inode - * flush takes the flush lock unconditionally and with nothing to - * push out the iclog we will never get that unlocked. hence we - * need to force the log first. - */ - xfs_log_force(mp, XFS_LOG_SYNC); - - /* - * We now need to tell the world we are unmounting. This will allow - * us to detect that the filesystem is going away and we should error - * out anything that we have been retrying in the background. This will - * prevent neverending retries in AIL pushing from hanging the unmount. - */ - mp->m_flags |= XFS_MOUNT_UNMOUNTING; - - /* - * Flush all pending changes from the AIL. - */ - xfs_ail_push_all_sync(mp->m_ail); - - /* - * And reclaim all inodes. At this point there should be no dirty - * inodes and none should be pinned or locked, but use synchronous - * reclaim just to be sure. We can stop background inode reclaim - * here as well if it is still running. - */ - cancel_delayed_work_sync(&mp->m_reclaim_work); - xfs_reclaim_inodes(mp, SYNC_WAIT); - - xfs_qm_unmount(mp); - - /* - * Unreserve any blocks we have so that when we unmount we don't account - * the reserved free space as used. This is really only necessary for - * lazy superblock counting because it trusts the incore superblock - * counters to be absolutely correct on clean unmount. - * - * We don't bother correcting this elsewhere for lazy superblock - * counting because on mount of an unclean filesystem we reconstruct the - * correct counter value and this is irrelevant. - * - * For non-lazy counter filesystems, this doesn't matter at all because - * we only every apply deltas to the superblock and hence the incore - * value does not matter.... - */ - resblks = 0; - error = xfs_reserve_blocks(mp, &resblks, NULL); - if (error) - xfs_warn(mp, "Unable to free reserved block pool. " - "Freespace may not be correct on next mount."); - - error = xfs_log_sbcount(mp); - if (error) - xfs_warn(mp, "Unable to update superblock counters. " - "Freespace may not be correct on next mount."); - - - xfs_log_unmount(mp); - xfs_da_unmount(mp); - xfs_uuid_unmount(mp); - -#if defined(DEBUG) - xfs_errortag_clearall(mp, 0); -#endif - xfs_free_perag(mp); - - xfs_error_sysfs_del(mp); - xfs_sysfs_del(&mp->m_stats.xs_kobj); - xfs_sysfs_del(&mp->m_kobj); -} - -/* - * Determine whether modifications can proceed. The caller specifies the minimum - * freeze level for which modifications should not be allowed. This allows - * certain operations to proceed while the freeze sequence is in progress, if - * necessary. - */ -bool -xfs_fs_writable( - struct xfs_mount *mp, - int level) -{ - ASSERT(level > SB_UNFROZEN); - if ((mp->m_super->s_writers.frozen >= level) || - XFS_FORCED_SHUTDOWN(mp) || (mp->m_flags & XFS_MOUNT_RDONLY)) - return false; - - return true; -} - -/* - * xfs_log_sbcount - * - * Sync the superblock counters to disk. - * - * Note this code can be called during the process of freezing, so we use the - * transaction allocator that does not block when the transaction subsystem is - * in its frozen state. - */ -int -xfs_log_sbcount(xfs_mount_t *mp) -{ - /* allow this to proceed during the freeze sequence... */ - if (!xfs_fs_writable(mp, SB_FREEZE_COMPLETE)) - return 0; - - /* - * we don't need to do this if we are updating the superblock - * counters on every modification. - */ - if (!xfs_sb_version_haslazysbcount(&mp->m_sb)) - return 0; - - return xfs_sync_sb(mp, true); -} - -/* - * Deltas for the inode count are +/-64, hence we use a large batch size - * of 128 so we don't need to take the counter lock on every update. - */ -#define XFS_ICOUNT_BATCH 128 -int -xfs_mod_icount( - struct xfs_mount *mp, - int64_t delta) -{ - __percpu_counter_add(&mp->m_icount, delta, XFS_ICOUNT_BATCH); - if (__percpu_counter_compare(&mp->m_icount, 0, XFS_ICOUNT_BATCH) < 0) { - ASSERT(0); - percpu_counter_add(&mp->m_icount, -delta); - return -EINVAL; - } - return 0; -} - -int -xfs_mod_ifree( - struct xfs_mount *mp, - int64_t delta) -{ - percpu_counter_add(&mp->m_ifree, delta); - if (percpu_counter_compare(&mp->m_ifree, 0) < 0) { - ASSERT(0); - percpu_counter_add(&mp->m_ifree, -delta); - return -EINVAL; - } - return 0; -} - -/* - * Deltas for the block count can vary from 1 to very large, but lock contention - * only occurs on frequent small block count updates such as in the delayed - * allocation path for buffered writes (page a time updates). Hence we set - * a large batch count (1024) to minimise global counter updates except when - * we get near to ENOSPC and we have to be very accurate with our updates. - */ -#define XFS_FDBLOCKS_BATCH 1024 -int -xfs_mod_fdblocks( - struct xfs_mount *mp, - int64_t delta, - bool rsvd) -{ - int64_t lcounter; - long long res_used; - s32 batch; - - if (delta > 0) { - /* - * If the reserve pool is depleted, put blocks back into it - * first. Most of the time the pool is full. - */ - if (likely(mp->m_resblks == mp->m_resblks_avail)) { - percpu_counter_add(&mp->m_fdblocks, delta); - return 0; - } - - spin_lock(&mp->m_sb_lock); - res_used = (long long)(mp->m_resblks - mp->m_resblks_avail); - - if (res_used > delta) { - mp->m_resblks_avail += delta; - } else { - delta -= res_used; - mp->m_resblks_avail = mp->m_resblks; - percpu_counter_add(&mp->m_fdblocks, delta); - } - spin_unlock(&mp->m_sb_lock); - return 0; - } - - /* - * Taking blocks away, need to be more accurate the closer we - * are to zero. - * - * If the counter has a value of less than 2 * max batch size, - * then make everything serialise as we are real close to - * ENOSPC. - */ - if (__percpu_counter_compare(&mp->m_fdblocks, 2 * XFS_FDBLOCKS_BATCH, - XFS_FDBLOCKS_BATCH) < 0) - batch = 1; - else - batch = XFS_FDBLOCKS_BATCH; - - __percpu_counter_add(&mp->m_fdblocks, delta, batch); - if (__percpu_counter_compare(&mp->m_fdblocks, mp->m_alloc_set_aside, - XFS_FDBLOCKS_BATCH) >= 0) { - /* we had space! */ - return 0; - } - - /* - * lock up the sb for dipping into reserves before releasing the space - * that took us to ENOSPC. - */ - spin_lock(&mp->m_sb_lock); - percpu_counter_add(&mp->m_fdblocks, -delta); - if (!rsvd) - goto fdblocks_enospc; - - lcounter = (long long)mp->m_resblks_avail + delta; - if (lcounter >= 0) { - mp->m_resblks_avail = lcounter; - spin_unlock(&mp->m_sb_lock); - return 0; - } - printk_once(KERN_WARNING - "Filesystem \"%s\": reserve blocks depleted! " - "Consider increasing reserve pool size.", - mp->m_fsname); -fdblocks_enospc: - spin_unlock(&mp->m_sb_lock); - return -ENOSPC; -} - -int -xfs_mod_frextents( - struct xfs_mount *mp, - int64_t delta) -{ - int64_t lcounter; - int ret = 0; - - spin_lock(&mp->m_sb_lock); - lcounter = mp->m_sb.sb_frextents + delta; - if (lcounter < 0) - ret = -ENOSPC; - else - mp->m_sb.sb_frextents = lcounter; - spin_unlock(&mp->m_sb_lock); - return ret; -} - -/* - * xfs_getsb() is called to obtain the buffer for the superblock. - * The buffer is returned locked and read in from disk. - * The buffer should be released with a call to xfs_brelse(). - * - * If the flags parameter is BUF_TRYLOCK, then we'll only return - * the superblock buffer if it can be locked without sleeping. - * If it can't then we'll return NULL. - */ -struct xfs_buf * -xfs_getsb( - struct xfs_mount *mp, - int flags) -{ - struct xfs_buf *bp = mp->m_sb_bp; - - if (!xfs_buf_trylock(bp)) { - if (flags & XBF_TRYLOCK) - return NULL; - xfs_buf_lock(bp); - } - - xfs_buf_hold(bp); - ASSERT(bp->b_flags & XBF_DONE); - return bp; -} - -/* - * Used to free the superblock along various error paths. - */ -void -xfs_freesb( - struct xfs_mount *mp) -{ - struct xfs_buf *bp = mp->m_sb_bp; - - xfs_buf_lock(bp); - mp->m_sb_bp = NULL; - xfs_buf_relse(bp); -} - -/* - * If the underlying (data/log/rt) device is readonly, there are some - * operations that cannot proceed. - */ -int -xfs_dev_is_read_only( - struct xfs_mount *mp, - char *message) -{ - if (xfs_readonly_buftarg(mp->m_ddev_targp) || - xfs_readonly_buftarg(mp->m_logdev_targp) || - (mp->m_rtdev_targp && xfs_readonly_buftarg(mp->m_rtdev_targp))) { - xfs_notice(mp, "%s required on read-only device.", message); - xfs_notice(mp, "write access unavailable, cannot proceed."); - return -EROFS; - } - return 0; -} diff --git a/src/linux/fs/xfs/xfs_mount.h b/src/linux/fs/xfs/xfs_mount.h deleted file mode 100644 index 819b80b..0000000 --- a/src/linux/fs/xfs/xfs_mount.h +++ /dev/null @@ -1,457 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_MOUNT_H__ -#define __XFS_MOUNT_H__ - -struct xlog; -struct xfs_inode; -struct xfs_mru_cache; -struct xfs_nameops; -struct xfs_ail; -struct xfs_quotainfo; -struct xfs_dir_ops; -struct xfs_da_geometry; - -/* dynamic preallocation free space thresholds, 5% down to 1% */ -enum { - XFS_LOWSP_1_PCNT = 0, - XFS_LOWSP_2_PCNT, - XFS_LOWSP_3_PCNT, - XFS_LOWSP_4_PCNT, - XFS_LOWSP_5_PCNT, - XFS_LOWSP_MAX, -}; - -/* - * Error Configuration - * - * Error classes define the subsystem the configuration belongs to. - * Error numbers define the errors that are configurable. - */ -enum { - XFS_ERR_METADATA, - XFS_ERR_CLASS_MAX, -}; -enum { - XFS_ERR_DEFAULT, - XFS_ERR_EIO, - XFS_ERR_ENOSPC, - XFS_ERR_ENODEV, - XFS_ERR_ERRNO_MAX, -}; - -#define XFS_ERR_RETRY_FOREVER -1 - -/* - * Although retry_timeout is in jiffies which is normally an unsigned long, - * we limit the retry timeout to 86400 seconds, or one day. So even a - * signed 32-bit long is sufficient for a HZ value up to 24855. Making it - * signed lets us store the special "-1" value, meaning retry forever. - */ -struct xfs_error_cfg { - struct xfs_kobj kobj; - int max_retries; - long retry_timeout; /* in jiffies, -1 = infinite */ -}; - -typedef struct xfs_mount { - struct super_block *m_super; - xfs_tid_t m_tid; /* next unused tid for fs */ - struct xfs_ail *m_ail; /* fs active log item list */ - - struct xfs_sb m_sb; /* copy of fs superblock */ - spinlock_t m_sb_lock; /* sb counter lock */ - struct percpu_counter m_icount; /* allocated inodes counter */ - struct percpu_counter m_ifree; /* free inodes counter */ - struct percpu_counter m_fdblocks; /* free block counter */ - - struct xfs_buf *m_sb_bp; /* buffer for superblock */ - char *m_fsname; /* filesystem name */ - int m_fsname_len; /* strlen of fs name */ - char *m_rtname; /* realtime device name */ - char *m_logname; /* external log device name */ - int m_bsize; /* fs logical block size */ - xfs_agnumber_t m_agfrotor; /* last ag where space found */ - xfs_agnumber_t m_agirotor; /* last ag dir inode alloced */ - spinlock_t m_agirotor_lock;/* .. and lock protecting it */ - xfs_agnumber_t m_maxagi; /* highest inode alloc group */ - uint m_readio_log; /* min read size log bytes */ - uint m_readio_blocks; /* min read size blocks */ - uint m_writeio_log; /* min write size log bytes */ - uint m_writeio_blocks; /* min write size blocks */ - struct xfs_da_geometry *m_dir_geo; /* directory block geometry */ - struct xfs_da_geometry *m_attr_geo; /* attribute block geometry */ - struct xlog *m_log; /* log specific stuff */ - int m_logbufs; /* number of log buffers */ - int m_logbsize; /* size of each log buffer */ - uint m_rsumlevels; /* rt summary levels */ - uint m_rsumsize; /* size of rt summary, bytes */ - struct xfs_inode *m_rbmip; /* pointer to bitmap inode */ - struct xfs_inode *m_rsumip; /* pointer to summary inode */ - struct xfs_inode *m_rootip; /* pointer to root directory */ - struct xfs_quotainfo *m_quotainfo; /* disk quota information */ - xfs_buftarg_t *m_ddev_targp; /* saves taking the address */ - xfs_buftarg_t *m_logdev_targp;/* ptr to log device */ - xfs_buftarg_t *m_rtdev_targp; /* ptr to rt device */ - __uint8_t m_blkbit_log; /* blocklog + NBBY */ - __uint8_t m_blkbb_log; /* blocklog - BBSHIFT */ - __uint8_t m_agno_log; /* log #ag's */ - __uint8_t m_agino_log; /* #bits for agino in inum */ - uint m_inode_cluster_size;/* min inode buf size */ - uint m_blockmask; /* sb_blocksize-1 */ - uint m_blockwsize; /* sb_blocksize in words */ - uint m_blockwmask; /* blockwsize-1 */ - uint m_alloc_mxr[2]; /* max alloc btree records */ - uint m_alloc_mnr[2]; /* min alloc btree records */ - uint m_bmap_dmxr[2]; /* max bmap btree records */ - uint m_bmap_dmnr[2]; /* min bmap btree records */ - uint m_inobt_mxr[2]; /* max inobt btree records */ - uint m_inobt_mnr[2]; /* min inobt btree records */ - uint m_rmap_mxr[2]; /* max rmap btree records */ - uint m_rmap_mnr[2]; /* min rmap btree records */ - uint m_refc_mxr[2]; /* max refc btree records */ - uint m_refc_mnr[2]; /* min refc btree records */ - uint m_ag_maxlevels; /* XFS_AG_MAXLEVELS */ - uint m_bm_maxlevels[2]; /* XFS_BM_MAXLEVELS */ - uint m_in_maxlevels; /* max inobt btree levels. */ - uint m_rmap_maxlevels; /* max rmap btree levels */ - uint m_refc_maxlevels; /* max refcount btree level */ - xfs_extlen_t m_ag_prealloc_blocks; /* reserved ag blocks */ - uint m_alloc_set_aside; /* space we can't use */ - uint m_ag_max_usable; /* max space per AG */ - struct radix_tree_root m_perag_tree; /* per-ag accounting info */ - spinlock_t m_perag_lock; /* lock for m_perag_tree */ - struct mutex m_growlock; /* growfs mutex */ - int m_fixedfsid[2]; /* unchanged for life of FS */ - uint m_dmevmask; /* DMI events for this FS */ - __uint64_t m_flags; /* global mount flags */ - int m_ialloc_inos; /* inodes in inode allocation */ - int m_ialloc_blks; /* blocks in inode allocation */ - int m_ialloc_min_blks;/* min blocks in sparse inode - * allocation */ - int m_inoalign_mask;/* mask sb_inoalignmt if used */ - uint m_qflags; /* quota status flags */ - struct xfs_trans_resv m_resv; /* precomputed res values */ - __uint64_t m_maxicount; /* maximum inode count */ - __uint64_t m_resblks; /* total reserved blocks */ - __uint64_t m_resblks_avail;/* available reserved blocks */ - __uint64_t m_resblks_save; /* reserved blks @ remount,ro */ - int m_dalign; /* stripe unit */ - int m_swidth; /* stripe width */ - int m_sinoalign; /* stripe unit inode alignment */ - __uint8_t m_sectbb_log; /* sectlog - BBSHIFT */ - const struct xfs_nameops *m_dirnameops; /* vector of dir name ops */ - const struct xfs_dir_ops *m_dir_inode_ops; /* vector of dir inode ops */ - const struct xfs_dir_ops *m_nondir_inode_ops; /* !dir inode ops */ - uint m_chsize; /* size of next field */ - atomic_t m_active_trans; /* number trans frozen */ - struct xfs_mru_cache *m_filestream; /* per-mount filestream data */ - struct delayed_work m_reclaim_work; /* background inode reclaim */ - struct delayed_work m_eofblocks_work; /* background eof blocks - trimming */ - struct delayed_work m_cowblocks_work; /* background cow blocks - trimming */ - bool m_update_sb; /* sb needs update in mount */ - int64_t m_low_space[XFS_LOWSP_MAX]; - /* low free space thresholds */ - struct xfs_kobj m_kobj; - struct xfs_kobj m_error_kobj; - struct xfs_kobj m_error_meta_kobj; - struct xfs_error_cfg m_error_cfg[XFS_ERR_CLASS_MAX][XFS_ERR_ERRNO_MAX]; - struct xstats m_stats; /* per-fs stats */ - - struct workqueue_struct *m_buf_workqueue; - struct workqueue_struct *m_data_workqueue; - struct workqueue_struct *m_unwritten_workqueue; - struct workqueue_struct *m_cil_workqueue; - struct workqueue_struct *m_reclaim_workqueue; - struct workqueue_struct *m_log_workqueue; - struct workqueue_struct *m_eofblocks_workqueue; - - /* - * Generation of the filesysyem layout. This is incremented by each - * growfs, and used by the pNFS server to ensure the client updates - * its view of the block device once it gets a layout that might - * reference the newly added blocks. Does not need to be persistent - * as long as we only allow file system size increments, but if we - * ever support shrinks it would have to be persisted in addition - * to various other kinds of pain inflicted on the pNFS server. - */ - __uint32_t m_generation; - - bool m_fail_unmount; -#ifdef DEBUG - /* - * DEBUG mode instrumentation to test and/or trigger delayed allocation - * block killing in the event of failed writes. When enabled, all - * buffered writes are forced to fail. All delalloc blocks in the range - * of the write (including pre-existing delalloc blocks!) are tossed as - * part of the write failure error handling sequence. - */ - bool m_fail_writes; -#endif -} xfs_mount_t; - -/* - * Flags for m_flags. - */ -#define XFS_MOUNT_WSYNC (1ULL << 0) /* for nfs - all metadata ops - must be synchronous except - for space allocations */ -#define XFS_MOUNT_UNMOUNTING (1ULL << 1) /* filesystem is unmounting */ -#define XFS_MOUNT_WAS_CLEAN (1ULL << 3) -#define XFS_MOUNT_FS_SHUTDOWN (1ULL << 4) /* atomic stop of all filesystem - operations, typically for - disk errors in metadata */ -#define XFS_MOUNT_DISCARD (1ULL << 5) /* discard unused blocks */ -#define XFS_MOUNT_NOALIGN (1ULL << 7) /* turn off stripe alignment - allocations */ -#define XFS_MOUNT_ATTR2 (1ULL << 8) /* allow use of attr2 format */ -#define XFS_MOUNT_GRPID (1ULL << 9) /* group-ID assigned from directory */ -#define XFS_MOUNT_NORECOVERY (1ULL << 10) /* no recovery - dirty fs */ -#define XFS_MOUNT_DFLT_IOSIZE (1ULL << 12) /* set default i/o size */ -#define XFS_MOUNT_SMALL_INUMS (1ULL << 14) /* user wants 32bit inodes */ -#define XFS_MOUNT_32BITINODES (1ULL << 15) /* inode32 allocator active */ -#define XFS_MOUNT_NOUUID (1ULL << 16) /* ignore uuid during mount */ -#define XFS_MOUNT_BARRIER (1ULL << 17) -#define XFS_MOUNT_IKEEP (1ULL << 18) /* keep empty inode clusters*/ -#define XFS_MOUNT_SWALLOC (1ULL << 19) /* turn on stripe width - * allocation */ -#define XFS_MOUNT_RDONLY (1ULL << 20) /* read-only fs */ -#define XFS_MOUNT_DIRSYNC (1ULL << 21) /* synchronous directory ops */ -#define XFS_MOUNT_COMPAT_IOSIZE (1ULL << 22) /* don't report large preferred - * I/O size in stat() */ -#define XFS_MOUNT_FILESTREAMS (1ULL << 24) /* enable the filestreams - allocator */ -#define XFS_MOUNT_NOATTR2 (1ULL << 25) /* disable use of attr2 format */ - -#define XFS_MOUNT_DAX (1ULL << 62) /* TEST ONLY! */ - - -/* - * Default minimum read and write sizes. - */ -#define XFS_READIO_LOG_LARGE 16 -#define XFS_WRITEIO_LOG_LARGE 16 - -/* - * Max and min values for mount-option defined I/O - * preallocation sizes. - */ -#define XFS_MAX_IO_LOG 30 /* 1G */ -#define XFS_MIN_IO_LOG PAGE_SHIFT - -/* - * Synchronous read and write sizes. This should be - * better for NFSv2 wsync filesystems. - */ -#define XFS_WSYNC_READIO_LOG 15 /* 32k */ -#define XFS_WSYNC_WRITEIO_LOG 14 /* 16k */ - -/* - * Allow large block sizes to be reported to userspace programs if the - * "largeio" mount option is used. - * - * If compatibility mode is specified, simply return the basic unit of caching - * so that we don't get inefficient read/modify/write I/O from user apps. - * Otherwise.... - * - * If the underlying volume is a stripe, then return the stripe width in bytes - * as the recommended I/O size. It is not a stripe and we've set a default - * buffered I/O size, return that, otherwise return the compat default. - */ -static inline unsigned long -xfs_preferred_iosize(xfs_mount_t *mp) -{ - if (mp->m_flags & XFS_MOUNT_COMPAT_IOSIZE) - return PAGE_SIZE; - return (mp->m_swidth ? - (mp->m_swidth << mp->m_sb.sb_blocklog) : - ((mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) ? - (1 << (int)MAX(mp->m_readio_log, mp->m_writeio_log)) : - PAGE_SIZE)); -} - -#define XFS_LAST_UNMOUNT_WAS_CLEAN(mp) \ - ((mp)->m_flags & XFS_MOUNT_WAS_CLEAN) -#define XFS_FORCED_SHUTDOWN(mp) ((mp)->m_flags & XFS_MOUNT_FS_SHUTDOWN) -void xfs_do_force_shutdown(struct xfs_mount *mp, int flags, char *fname, - int lnnum); -#define xfs_force_shutdown(m,f) \ - xfs_do_force_shutdown(m, f, __FILE__, __LINE__) - -#define SHUTDOWN_META_IO_ERROR 0x0001 /* write attempt to metadata failed */ -#define SHUTDOWN_LOG_IO_ERROR 0x0002 /* write attempt to the log failed */ -#define SHUTDOWN_FORCE_UMOUNT 0x0004 /* shutdown from a forced unmount */ -#define SHUTDOWN_CORRUPT_INCORE 0x0008 /* corrupt in-memory data structures */ -#define SHUTDOWN_REMOTE_REQ 0x0010 /* shutdown came from remote cell */ -#define SHUTDOWN_DEVICE_REQ 0x0020 /* failed all paths to the device */ - -/* - * Flags for xfs_mountfs - */ -#define XFS_MFSI_QUIET 0x40 /* Be silent if mount errors found */ - -static inline xfs_agnumber_t -xfs_daddr_to_agno(struct xfs_mount *mp, xfs_daddr_t d) -{ - xfs_daddr_t ld = XFS_BB_TO_FSBT(mp, d); - do_div(ld, mp->m_sb.sb_agblocks); - return (xfs_agnumber_t) ld; -} - -static inline xfs_agblock_t -xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d) -{ - xfs_daddr_t ld = XFS_BB_TO_FSBT(mp, d); - return (xfs_agblock_t) do_div(ld, mp->m_sb.sb_agblocks); -} - -#ifdef DEBUG -static inline bool -xfs_mp_fail_writes(struct xfs_mount *mp) -{ - return mp->m_fail_writes; -} -#else -static inline bool -xfs_mp_fail_writes(struct xfs_mount *mp) -{ - return 0; -} -#endif - -/* per-AG block reservation data structures*/ -enum xfs_ag_resv_type { - XFS_AG_RESV_NONE = 0, - XFS_AG_RESV_METADATA, - XFS_AG_RESV_AGFL, -}; - -struct xfs_ag_resv { - /* number of blocks originally reserved here */ - xfs_extlen_t ar_orig_reserved; - /* number of blocks reserved here */ - xfs_extlen_t ar_reserved; - /* number of blocks originally asked for */ - xfs_extlen_t ar_asked; -}; - -/* - * Per-ag incore structure, copies of information in agf and agi, to improve the - * performance of allocation group selection. - */ -typedef struct xfs_perag { - struct xfs_mount *pag_mount; /* owner filesystem */ - xfs_agnumber_t pag_agno; /* AG this structure belongs to */ - atomic_t pag_ref; /* perag reference count */ - char pagf_init; /* this agf's entry is initialized */ - char pagi_init; /* this agi's entry is initialized */ - char pagf_metadata; /* the agf is preferred to be metadata */ - char pagi_inodeok; /* The agi is ok for inodes */ - __uint8_t pagf_levels[XFS_BTNUM_AGF]; - /* # of levels in bno & cnt btree */ - __uint32_t pagf_flcount; /* count of blocks in freelist */ - xfs_extlen_t pagf_freeblks; /* total free blocks */ - xfs_extlen_t pagf_longest; /* longest free space */ - __uint32_t pagf_btreeblks; /* # of blocks held in AGF btrees */ - xfs_agino_t pagi_freecount; /* number of free inodes */ - xfs_agino_t pagi_count; /* number of allocated inodes */ - - /* - * Inode allocation search lookup optimisation. - * If the pagino matches, the search for new inodes - * doesn't need to search the near ones again straight away - */ - xfs_agino_t pagl_pagino; - xfs_agino_t pagl_leftrec; - xfs_agino_t pagl_rightrec; - spinlock_t pagb_lock; /* lock for pagb_tree */ - struct rb_root pagb_tree; /* ordered tree of busy extents */ - - atomic_t pagf_fstrms; /* # of filestreams active in this AG */ - - spinlock_t pag_ici_lock; /* incore inode cache lock */ - struct radix_tree_root pag_ici_root; /* incore inode cache root */ - int pag_ici_reclaimable; /* reclaimable inodes */ - struct mutex pag_ici_reclaim_lock; /* serialisation point */ - unsigned long pag_ici_reclaim_cursor; /* reclaim restart point */ - - /* buffer cache index */ - spinlock_t pag_buf_lock; /* lock for pag_buf_tree */ - struct rb_root pag_buf_tree; /* ordered tree of active buffers */ - - /* for rcu-safe freeing */ - struct rcu_head rcu_head; - int pagb_count; /* pagb slots in use */ - - /* Blocks reserved for all kinds of metadata. */ - struct xfs_ag_resv pag_meta_resv; - /* Blocks reserved for just AGFL-based metadata. */ - struct xfs_ag_resv pag_agfl_resv; - - /* reference count */ - __uint8_t pagf_refcount_level; -} xfs_perag_t; - -static inline struct xfs_ag_resv * -xfs_perag_resv( - struct xfs_perag *pag, - enum xfs_ag_resv_type type) -{ - switch (type) { - case XFS_AG_RESV_METADATA: - return &pag->pag_meta_resv; - case XFS_AG_RESV_AGFL: - return &pag->pag_agfl_resv; - default: - return NULL; - } -} - -extern void xfs_uuid_table_free(void); -extern int xfs_log_sbcount(xfs_mount_t *); -extern __uint64_t xfs_default_resblks(xfs_mount_t *mp); -extern int xfs_mountfs(xfs_mount_t *mp); -extern int xfs_initialize_perag(xfs_mount_t *mp, xfs_agnumber_t agcount, - xfs_agnumber_t *maxagi); -extern void xfs_unmountfs(xfs_mount_t *); - -extern int xfs_mod_icount(struct xfs_mount *mp, int64_t delta); -extern int xfs_mod_ifree(struct xfs_mount *mp, int64_t delta); -extern int xfs_mod_fdblocks(struct xfs_mount *mp, int64_t delta, - bool reserved); -extern int xfs_mod_frextents(struct xfs_mount *mp, int64_t delta); - -extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int); -extern int xfs_readsb(xfs_mount_t *, int); -extern void xfs_freesb(xfs_mount_t *); -extern bool xfs_fs_writable(struct xfs_mount *mp, int level); -extern int xfs_sb_validate_fsb_count(struct xfs_sb *, __uint64_t); - -extern int xfs_dev_is_read_only(struct xfs_mount *, char *); - -extern void xfs_set_low_space_thresholds(struct xfs_mount *); - -int xfs_zero_extent(struct xfs_inode *ip, xfs_fsblock_t start_fsb, - xfs_off_t count_fsb); - -struct xfs_error_cfg * xfs_error_get_cfg(struct xfs_mount *mp, - int error_class, int error); - -#endif /* __XFS_MOUNT_H__ */ diff --git a/src/linux/fs/xfs/xfs_mru_cache.c b/src/linux/fs/xfs/xfs_mru_cache.c deleted file mode 100644 index f8a674d..0000000 --- a/src/linux/fs/xfs/xfs_mru_cache.c +++ /dev/null @@ -1,552 +0,0 @@ -/* - * Copyright (c) 2006-2007 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_mru_cache.h" - -/* - * The MRU Cache data structure consists of a data store, an array of lists and - * a lock to protect its internal state. At initialisation time, the client - * supplies an element lifetime in milliseconds and a group count, as well as a - * function pointer to call when deleting elements. A data structure for - * queueing up work in the form of timed callbacks is also included. - * - * The group count controls how many lists are created, and thereby how finely - * the elements are grouped in time. When reaping occurs, all the elements in - * all the lists whose time has expired are deleted. - * - * To give an example of how this works in practice, consider a client that - * initialises an MRU Cache with a lifetime of ten seconds and a group count of - * five. Five internal lists will be created, each representing a two second - * period in time. When the first element is added, time zero for the data - * structure is initialised to the current time. - * - * All the elements added in the first two seconds are appended to the first - * list. Elements added in the third second go into the second list, and so on. - * If an element is accessed at any point, it is removed from its list and - * inserted at the head of the current most-recently-used list. - * - * The reaper function will have nothing to do until at least twelve seconds - * have elapsed since the first element was added. The reason for this is that - * if it were called at t=11s, there could be elements in the first list that - * have only been inactive for nine seconds, so it still does nothing. If it is - * called anywhere between t=12 and t=14 seconds, it will delete all the - * elements that remain in the first list. It's therefore possible for elements - * to remain in the data store even after they've been inactive for up to - * (t + t/g) seconds, where t is the inactive element lifetime and g is the - * number of groups. - * - * The above example assumes that the reaper function gets called at least once - * every (t/g) seconds. If it is called less frequently, unused elements will - * accumulate in the reap list until the reaper function is eventually called. - * The current implementation uses work queue callbacks to carefully time the - * reaper function calls, so this should happen rarely, if at all. - * - * From a design perspective, the primary reason for the choice of a list array - * representing discrete time intervals is that it's only practical to reap - * expired elements in groups of some appreciable size. This automatically - * introduces a granularity to element lifetimes, so there's no point storing an - * individual timeout with each element that specifies a more precise reap time. - * The bonus is a saving of sizeof(long) bytes of memory per element stored. - * - * The elements could have been stored in just one list, but an array of - * counters or pointers would need to be maintained to allow them to be divided - * up into discrete time groups. More critically, the process of touching or - * removing an element would involve walking large portions of the entire list, - * which would have a detrimental effect on performance. The additional memory - * requirement for the array of list heads is minimal. - * - * When an element is touched or deleted, it needs to be removed from its - * current list. Doubly linked lists are used to make the list maintenance - * portion of these operations O(1). Since reaper timing can be imprecise, - * inserts and lookups can occur when there are no free lists available. When - * this happens, all the elements on the LRU list need to be migrated to the end - * of the reap list. To keep the list maintenance portion of these operations - * O(1) also, list tails need to be accessible without walking the entire list. - * This is the reason why doubly linked list heads are used. - */ - -/* - * An MRU Cache is a dynamic data structure that stores its elements in a way - * that allows efficient lookups, but also groups them into discrete time - * intervals based on insertion time. This allows elements to be efficiently - * and automatically reaped after a fixed period of inactivity. - * - * When a client data pointer is stored in the MRU Cache it needs to be added to - * both the data store and to one of the lists. It must also be possible to - * access each of these entries via the other, i.e. to: - * - * a) Walk a list, removing the corresponding data store entry for each item. - * b) Look up a data store entry, then access its list entry directly. - * - * To achieve both of these goals, each entry must contain both a list entry and - * a key, in addition to the user's data pointer. Note that it's not a good - * idea to have the client embed one of these structures at the top of their own - * data structure, because inserting the same item more than once would most - * likely result in a loop in one of the lists. That's a sure-fire recipe for - * an infinite loop in the code. - */ -struct xfs_mru_cache { - struct radix_tree_root store; /* Core storage data structure. */ - struct list_head *lists; /* Array of lists, one per grp. */ - struct list_head reap_list; /* Elements overdue for reaping. */ - spinlock_t lock; /* Lock to protect this struct. */ - unsigned int grp_count; /* Number of discrete groups. */ - unsigned int grp_time; /* Time period spanned by grps. */ - unsigned int lru_grp; /* Group containing time zero. */ - unsigned long time_zero; /* Time first element was added. */ - xfs_mru_cache_free_func_t free_func; /* Function pointer for freeing. */ - struct delayed_work work; /* Workqueue data for reaping. */ - unsigned int queued; /* work has been queued */ -}; - -static struct workqueue_struct *xfs_mru_reap_wq; - -/* - * When inserting, destroying or reaping, it's first necessary to update the - * lists relative to a particular time. In the case of destroying, that time - * will be well in the future to ensure that all items are moved to the reap - * list. In all other cases though, the time will be the current time. - * - * This function enters a loop, moving the contents of the LRU list to the reap - * list again and again until either a) the lists are all empty, or b) time zero - * has been advanced sufficiently to be within the immediate element lifetime. - * - * Case a) above is detected by counting how many groups are migrated and - * stopping when they've all been moved. Case b) is detected by monitoring the - * time_zero field, which is updated as each group is migrated. - * - * The return value is the earliest time that more migration could be needed, or - * zero if there's no need to schedule more work because the lists are empty. - */ -STATIC unsigned long -_xfs_mru_cache_migrate( - struct xfs_mru_cache *mru, - unsigned long now) -{ - unsigned int grp; - unsigned int migrated = 0; - struct list_head *lru_list; - - /* Nothing to do if the data store is empty. */ - if (!mru->time_zero) - return 0; - - /* While time zero is older than the time spanned by all the lists. */ - while (mru->time_zero <= now - mru->grp_count * mru->grp_time) { - - /* - * If the LRU list isn't empty, migrate its elements to the tail - * of the reap list. - */ - lru_list = mru->lists + mru->lru_grp; - if (!list_empty(lru_list)) - list_splice_init(lru_list, mru->reap_list.prev); - - /* - * Advance the LRU group number, freeing the old LRU list to - * become the new MRU list; advance time zero accordingly. - */ - mru->lru_grp = (mru->lru_grp + 1) % mru->grp_count; - mru->time_zero += mru->grp_time; - - /* - * If reaping is so far behind that all the elements on all the - * lists have been migrated to the reap list, it's now empty. - */ - if (++migrated == mru->grp_count) { - mru->lru_grp = 0; - mru->time_zero = 0; - return 0; - } - } - - /* Find the first non-empty list from the LRU end. */ - for (grp = 0; grp < mru->grp_count; grp++) { - - /* Check the grp'th list from the LRU end. */ - lru_list = mru->lists + ((mru->lru_grp + grp) % mru->grp_count); - if (!list_empty(lru_list)) - return mru->time_zero + - (mru->grp_count + grp) * mru->grp_time; - } - - /* All the lists must be empty. */ - mru->lru_grp = 0; - mru->time_zero = 0; - return 0; -} - -/* - * When inserting or doing a lookup, an element needs to be inserted into the - * MRU list. The lists must be migrated first to ensure that they're - * up-to-date, otherwise the new element could be given a shorter lifetime in - * the cache than it should. - */ -STATIC void -_xfs_mru_cache_list_insert( - struct xfs_mru_cache *mru, - struct xfs_mru_cache_elem *elem) -{ - unsigned int grp = 0; - unsigned long now = jiffies; - - /* - * If the data store is empty, initialise time zero, leave grp set to - * zero and start the work queue timer if necessary. Otherwise, set grp - * to the number of group times that have elapsed since time zero. - */ - if (!_xfs_mru_cache_migrate(mru, now)) { - mru->time_zero = now; - if (!mru->queued) { - mru->queued = 1; - queue_delayed_work(xfs_mru_reap_wq, &mru->work, - mru->grp_count * mru->grp_time); - } - } else { - grp = (now - mru->time_zero) / mru->grp_time; - grp = (mru->lru_grp + grp) % mru->grp_count; - } - - /* Insert the element at the tail of the corresponding list. */ - list_add_tail(&elem->list_node, mru->lists + grp); -} - -/* - * When destroying or reaping, all the elements that were migrated to the reap - * list need to be deleted. For each element this involves removing it from the - * data store, removing it from the reap list, calling the client's free - * function and deleting the element from the element zone. - * - * We get called holding the mru->lock, which we drop and then reacquire. - * Sparse need special help with this to tell it we know what we are doing. - */ -STATIC void -_xfs_mru_cache_clear_reap_list( - struct xfs_mru_cache *mru) - __releases(mru->lock) __acquires(mru->lock) -{ - struct xfs_mru_cache_elem *elem, *next; - struct list_head tmp; - - INIT_LIST_HEAD(&tmp); - list_for_each_entry_safe(elem, next, &mru->reap_list, list_node) { - - /* Remove the element from the data store. */ - radix_tree_delete(&mru->store, elem->key); - - /* - * remove to temp list so it can be freed without - * needing to hold the lock - */ - list_move(&elem->list_node, &tmp); - } - spin_unlock(&mru->lock); - - list_for_each_entry_safe(elem, next, &tmp, list_node) { - list_del_init(&elem->list_node); - mru->free_func(elem); - } - - spin_lock(&mru->lock); -} - -/* - * We fire the reap timer every group expiry interval so - * we always have a reaper ready to run. This makes shutdown - * and flushing of the reaper easy to do. Hence we need to - * keep when the next reap must occur so we can determine - * at each interval whether there is anything we need to do. - */ -STATIC void -_xfs_mru_cache_reap( - struct work_struct *work) -{ - struct xfs_mru_cache *mru = - container_of(work, struct xfs_mru_cache, work.work); - unsigned long now, next; - - ASSERT(mru && mru->lists); - if (!mru || !mru->lists) - return; - - spin_lock(&mru->lock); - next = _xfs_mru_cache_migrate(mru, jiffies); - _xfs_mru_cache_clear_reap_list(mru); - - mru->queued = next; - if ((mru->queued > 0)) { - now = jiffies; - if (next <= now) - next = 0; - else - next -= now; - queue_delayed_work(xfs_mru_reap_wq, &mru->work, next); - } - - spin_unlock(&mru->lock); -} - -int -xfs_mru_cache_init(void) -{ - xfs_mru_reap_wq = alloc_workqueue("xfs_mru_cache", - WQ_MEM_RECLAIM|WQ_FREEZABLE, 1); - if (!xfs_mru_reap_wq) - return -ENOMEM; - return 0; -} - -void -xfs_mru_cache_uninit(void) -{ - destroy_workqueue(xfs_mru_reap_wq); -} - -/* - * To initialise a struct xfs_mru_cache pointer, call xfs_mru_cache_create() - * with the address of the pointer, a lifetime value in milliseconds, a group - * count and a free function to use when deleting elements. This function - * returns 0 if the initialisation was successful. - */ -int -xfs_mru_cache_create( - struct xfs_mru_cache **mrup, - unsigned int lifetime_ms, - unsigned int grp_count, - xfs_mru_cache_free_func_t free_func) -{ - struct xfs_mru_cache *mru = NULL; - int err = 0, grp; - unsigned int grp_time; - - if (mrup) - *mrup = NULL; - - if (!mrup || !grp_count || !lifetime_ms || !free_func) - return -EINVAL; - - if (!(grp_time = msecs_to_jiffies(lifetime_ms) / grp_count)) - return -EINVAL; - - if (!(mru = kmem_zalloc(sizeof(*mru), KM_SLEEP))) - return -ENOMEM; - - /* An extra list is needed to avoid reaping up to a grp_time early. */ - mru->grp_count = grp_count + 1; - mru->lists = kmem_zalloc(mru->grp_count * sizeof(*mru->lists), KM_SLEEP); - - if (!mru->lists) { - err = -ENOMEM; - goto exit; - } - - for (grp = 0; grp < mru->grp_count; grp++) - INIT_LIST_HEAD(mru->lists + grp); - - /* - * We use GFP_KERNEL radix tree preload and do inserts under a - * spinlock so GFP_ATOMIC is appropriate for the radix tree itself. - */ - INIT_RADIX_TREE(&mru->store, GFP_ATOMIC); - INIT_LIST_HEAD(&mru->reap_list); - spin_lock_init(&mru->lock); - INIT_DELAYED_WORK(&mru->work, _xfs_mru_cache_reap); - - mru->grp_time = grp_time; - mru->free_func = free_func; - - *mrup = mru; - -exit: - if (err && mru && mru->lists) - kmem_free(mru->lists); - if (err && mru) - kmem_free(mru); - - return err; -} - -/* - * Call xfs_mru_cache_flush() to flush out all cached entries, calling their - * free functions as they're deleted. When this function returns, the caller is - * guaranteed that all the free functions for all the elements have finished - * executing and the reaper is not running. - */ -static void -xfs_mru_cache_flush( - struct xfs_mru_cache *mru) -{ - if (!mru || !mru->lists) - return; - - spin_lock(&mru->lock); - if (mru->queued) { - spin_unlock(&mru->lock); - cancel_delayed_work_sync(&mru->work); - spin_lock(&mru->lock); - } - - _xfs_mru_cache_migrate(mru, jiffies + mru->grp_count * mru->grp_time); - _xfs_mru_cache_clear_reap_list(mru); - - spin_unlock(&mru->lock); -} - -void -xfs_mru_cache_destroy( - struct xfs_mru_cache *mru) -{ - if (!mru || !mru->lists) - return; - - xfs_mru_cache_flush(mru); - - kmem_free(mru->lists); - kmem_free(mru); -} - -/* - * To insert an element, call xfs_mru_cache_insert() with the data store, the - * element's key and the client data pointer. This function returns 0 on - * success or ENOMEM if memory for the data element couldn't be allocated. - */ -int -xfs_mru_cache_insert( - struct xfs_mru_cache *mru, - unsigned long key, - struct xfs_mru_cache_elem *elem) -{ - int error; - - ASSERT(mru && mru->lists); - if (!mru || !mru->lists) - return -EINVAL; - - if (radix_tree_preload(GFP_NOFS)) - return -ENOMEM; - - INIT_LIST_HEAD(&elem->list_node); - elem->key = key; - - spin_lock(&mru->lock); - error = radix_tree_insert(&mru->store, key, elem); - radix_tree_preload_end(); - if (!error) - _xfs_mru_cache_list_insert(mru, elem); - spin_unlock(&mru->lock); - - return error; -} - -/* - * To remove an element without calling the free function, call - * xfs_mru_cache_remove() with the data store and the element's key. On success - * the client data pointer for the removed element is returned, otherwise this - * function will return a NULL pointer. - */ -struct xfs_mru_cache_elem * -xfs_mru_cache_remove( - struct xfs_mru_cache *mru, - unsigned long key) -{ - struct xfs_mru_cache_elem *elem; - - ASSERT(mru && mru->lists); - if (!mru || !mru->lists) - return NULL; - - spin_lock(&mru->lock); - elem = radix_tree_delete(&mru->store, key); - if (elem) - list_del(&elem->list_node); - spin_unlock(&mru->lock); - - return elem; -} - -/* - * To remove and element and call the free function, call xfs_mru_cache_delete() - * with the data store and the element's key. - */ -void -xfs_mru_cache_delete( - struct xfs_mru_cache *mru, - unsigned long key) -{ - struct xfs_mru_cache_elem *elem; - - elem = xfs_mru_cache_remove(mru, key); - if (elem) - mru->free_func(elem); -} - -/* - * To look up an element using its key, call xfs_mru_cache_lookup() with the - * data store and the element's key. If found, the element will be moved to the - * head of the MRU list to indicate that it's been touched. - * - * The internal data structures are protected by a spinlock that is STILL HELD - * when this function returns. Call xfs_mru_cache_done() to release it. Note - * that it is not safe to call any function that might sleep in the interim. - * - * The implementation could have used reference counting to avoid this - * restriction, but since most clients simply want to get, set or test a member - * of the returned data structure, the extra per-element memory isn't warranted. - * - * If the element isn't found, this function returns NULL and the spinlock is - * released. xfs_mru_cache_done() should NOT be called when this occurs. - * - * Because sparse isn't smart enough to know about conditional lock return - * status, we need to help it get it right by annotating the path that does - * not release the lock. - */ -struct xfs_mru_cache_elem * -xfs_mru_cache_lookup( - struct xfs_mru_cache *mru, - unsigned long key) -{ - struct xfs_mru_cache_elem *elem; - - ASSERT(mru && mru->lists); - if (!mru || !mru->lists) - return NULL; - - spin_lock(&mru->lock); - elem = radix_tree_lookup(&mru->store, key); - if (elem) { - list_del(&elem->list_node); - _xfs_mru_cache_list_insert(mru, elem); - __release(mru_lock); /* help sparse not be stupid */ - } else - spin_unlock(&mru->lock); - - return elem; -} - -/* - * To release the internal data structure spinlock after having performed an - * xfs_mru_cache_lookup() or an xfs_mru_cache_peek(), call xfs_mru_cache_done() - * with the data store pointer. - */ -void -xfs_mru_cache_done( - struct xfs_mru_cache *mru) - __releases(mru->lock) -{ - spin_unlock(&mru->lock); -} diff --git a/src/linux/fs/xfs/xfs_mru_cache.h b/src/linux/fs/xfs/xfs_mru_cache.h deleted file mode 100644 index fb5245b..0000000 --- a/src/linux/fs/xfs/xfs_mru_cache.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2006-2007 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_MRU_CACHE_H__ -#define __XFS_MRU_CACHE_H__ - -struct xfs_mru_cache; - -struct xfs_mru_cache_elem { - struct list_head list_node; - unsigned long key; -}; - -/* Function pointer type for callback to free a client's data pointer. */ -typedef void (*xfs_mru_cache_free_func_t)(struct xfs_mru_cache_elem *elem); - -int xfs_mru_cache_init(void); -void xfs_mru_cache_uninit(void); -int xfs_mru_cache_create(struct xfs_mru_cache **mrup, unsigned int lifetime_ms, - unsigned int grp_count, - xfs_mru_cache_free_func_t free_func); -void xfs_mru_cache_destroy(struct xfs_mru_cache *mru); -int xfs_mru_cache_insert(struct xfs_mru_cache *mru, unsigned long key, - struct xfs_mru_cache_elem *elem); -struct xfs_mru_cache_elem * -xfs_mru_cache_remove(struct xfs_mru_cache *mru, unsigned long key); -void xfs_mru_cache_delete(struct xfs_mru_cache *mru, unsigned long key); -struct xfs_mru_cache_elem * -xfs_mru_cache_lookup(struct xfs_mru_cache *mru, unsigned long key); -void xfs_mru_cache_done(struct xfs_mru_cache *mru); - -#endif /* __XFS_MRU_CACHE_H__ */ diff --git a/src/linux/fs/xfs/xfs_ondisk.h b/src/linux/fs/xfs/xfs_ondisk.h deleted file mode 100644 index 0c381d7..0000000 --- a/src/linux/fs/xfs/xfs_ondisk.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2016 Oracle. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_ONDISK_H -#define __XFS_ONDISK_H - -#define XFS_CHECK_STRUCT_SIZE(structname, size) \ - BUILD_BUG_ON_MSG(sizeof(structname) != (size), "XFS: sizeof(" \ - #structname ") is wrong, expected " #size) - -#define XFS_CHECK_OFFSET(structname, member, off) \ - BUILD_BUG_ON_MSG(offsetof(structname, member) != (off), \ - "XFS: offsetof(" #structname ", " #member ") is wrong, " \ - "expected " #off) - -static inline void __init -xfs_check_ondisk_structs(void) -{ - /* ag/file structures */ - XFS_CHECK_STRUCT_SIZE(struct xfs_acl, 4); - XFS_CHECK_STRUCT_SIZE(struct xfs_acl_entry, 12); - XFS_CHECK_STRUCT_SIZE(struct xfs_agf, 224); - XFS_CHECK_STRUCT_SIZE(struct xfs_agfl, 36); - XFS_CHECK_STRUCT_SIZE(struct xfs_agi, 336); - XFS_CHECK_STRUCT_SIZE(struct xfs_bmbt_key, 8); - XFS_CHECK_STRUCT_SIZE(struct xfs_bmbt_rec, 16); - XFS_CHECK_STRUCT_SIZE(struct xfs_bmdr_block, 4); - XFS_CHECK_STRUCT_SIZE(struct xfs_btree_block_shdr, 48); - XFS_CHECK_STRUCT_SIZE(struct xfs_btree_block_lhdr, 64); - XFS_CHECK_STRUCT_SIZE(struct xfs_btree_block, 72); - XFS_CHECK_STRUCT_SIZE(struct xfs_dinode, 176); - XFS_CHECK_STRUCT_SIZE(struct xfs_disk_dquot, 104); - XFS_CHECK_STRUCT_SIZE(struct xfs_dqblk, 136); - XFS_CHECK_STRUCT_SIZE(struct xfs_dsb, 264); - XFS_CHECK_STRUCT_SIZE(struct xfs_dsymlink_hdr, 56); - XFS_CHECK_STRUCT_SIZE(struct xfs_inobt_key, 4); - XFS_CHECK_STRUCT_SIZE(struct xfs_inobt_rec, 16); - XFS_CHECK_STRUCT_SIZE(struct xfs_refcount_key, 4); - XFS_CHECK_STRUCT_SIZE(struct xfs_refcount_rec, 12); - XFS_CHECK_STRUCT_SIZE(struct xfs_rmap_key, 20); - XFS_CHECK_STRUCT_SIZE(struct xfs_rmap_rec, 24); - XFS_CHECK_STRUCT_SIZE(struct xfs_timestamp, 8); - XFS_CHECK_STRUCT_SIZE(xfs_alloc_key_t, 8); - XFS_CHECK_STRUCT_SIZE(xfs_alloc_ptr_t, 4); - XFS_CHECK_STRUCT_SIZE(xfs_alloc_rec_t, 8); - XFS_CHECK_STRUCT_SIZE(xfs_inobt_ptr_t, 4); - XFS_CHECK_STRUCT_SIZE(xfs_refcount_ptr_t, 4); - XFS_CHECK_STRUCT_SIZE(xfs_rmap_ptr_t, 4); - - /* dir/attr trees */ - XFS_CHECK_STRUCT_SIZE(struct xfs_attr3_leaf_hdr, 80); - XFS_CHECK_STRUCT_SIZE(struct xfs_attr3_leafblock, 88); - XFS_CHECK_STRUCT_SIZE(struct xfs_attr3_rmt_hdr, 56); - XFS_CHECK_STRUCT_SIZE(struct xfs_da3_blkinfo, 56); - XFS_CHECK_STRUCT_SIZE(struct xfs_da3_intnode, 64); - XFS_CHECK_STRUCT_SIZE(struct xfs_da3_node_hdr, 64); - XFS_CHECK_STRUCT_SIZE(struct xfs_dir3_blk_hdr, 48); - XFS_CHECK_STRUCT_SIZE(struct xfs_dir3_data_hdr, 64); - XFS_CHECK_STRUCT_SIZE(struct xfs_dir3_free, 64); - XFS_CHECK_STRUCT_SIZE(struct xfs_dir3_free_hdr, 64); - XFS_CHECK_STRUCT_SIZE(struct xfs_dir3_leaf, 64); - XFS_CHECK_STRUCT_SIZE(struct xfs_dir3_leaf_hdr, 64); - XFS_CHECK_STRUCT_SIZE(xfs_attr_leaf_entry_t, 8); - XFS_CHECK_STRUCT_SIZE(xfs_attr_leaf_hdr_t, 32); - XFS_CHECK_STRUCT_SIZE(xfs_attr_leaf_map_t, 4); - XFS_CHECK_STRUCT_SIZE(xfs_attr_leaf_name_local_t, 4); - - /* - * m68k has problems with xfs_attr_leaf_name_remote_t, but we pad it to - * 4 bytes anyway so it's not obviously a problem. Hence for the moment - * we don't check this structure. This can be re-instated when the attr - * definitions are updated to use c99 VLA definitions. - * - XFS_CHECK_STRUCT_SIZE(xfs_attr_leaf_name_remote_t, 12); - */ - - XFS_CHECK_OFFSET(xfs_attr_leaf_name_local_t, valuelen, 0); - XFS_CHECK_OFFSET(xfs_attr_leaf_name_local_t, namelen, 2); - XFS_CHECK_OFFSET(xfs_attr_leaf_name_local_t, nameval, 3); - XFS_CHECK_OFFSET(xfs_attr_leaf_name_remote_t, valueblk, 0); - XFS_CHECK_OFFSET(xfs_attr_leaf_name_remote_t, valuelen, 4); - XFS_CHECK_OFFSET(xfs_attr_leaf_name_remote_t, namelen, 8); - XFS_CHECK_OFFSET(xfs_attr_leaf_name_remote_t, name, 9); - XFS_CHECK_STRUCT_SIZE(xfs_attr_leafblock_t, 40); - XFS_CHECK_OFFSET(xfs_attr_shortform_t, hdr.totsize, 0); - XFS_CHECK_OFFSET(xfs_attr_shortform_t, hdr.count, 2); - XFS_CHECK_OFFSET(xfs_attr_shortform_t, list[0].namelen, 4); - XFS_CHECK_OFFSET(xfs_attr_shortform_t, list[0].valuelen, 5); - XFS_CHECK_OFFSET(xfs_attr_shortform_t, list[0].flags, 6); - XFS_CHECK_OFFSET(xfs_attr_shortform_t, list[0].nameval, 7); - XFS_CHECK_STRUCT_SIZE(xfs_da_blkinfo_t, 12); - XFS_CHECK_STRUCT_SIZE(xfs_da_intnode_t, 16); - XFS_CHECK_STRUCT_SIZE(xfs_da_node_entry_t, 8); - XFS_CHECK_STRUCT_SIZE(xfs_da_node_hdr_t, 16); - XFS_CHECK_STRUCT_SIZE(xfs_dir2_data_free_t, 4); - XFS_CHECK_STRUCT_SIZE(xfs_dir2_data_hdr_t, 16); - XFS_CHECK_OFFSET(xfs_dir2_data_unused_t, freetag, 0); - XFS_CHECK_OFFSET(xfs_dir2_data_unused_t, length, 2); - XFS_CHECK_STRUCT_SIZE(xfs_dir2_free_hdr_t, 16); - XFS_CHECK_STRUCT_SIZE(xfs_dir2_free_t, 16); - XFS_CHECK_STRUCT_SIZE(xfs_dir2_leaf_entry_t, 8); - XFS_CHECK_STRUCT_SIZE(xfs_dir2_leaf_hdr_t, 16); - XFS_CHECK_STRUCT_SIZE(xfs_dir2_leaf_t, 16); - XFS_CHECK_STRUCT_SIZE(xfs_dir2_leaf_tail_t, 4); - XFS_CHECK_STRUCT_SIZE(xfs_dir2_sf_entry_t, 3); - XFS_CHECK_OFFSET(xfs_dir2_sf_entry_t, namelen, 0); - XFS_CHECK_OFFSET(xfs_dir2_sf_entry_t, offset, 1); - XFS_CHECK_OFFSET(xfs_dir2_sf_entry_t, name, 3); - XFS_CHECK_STRUCT_SIZE(xfs_dir2_sf_hdr_t, 10); - - /* log structures */ - XFS_CHECK_STRUCT_SIZE(struct xfs_dq_logformat, 24); - XFS_CHECK_STRUCT_SIZE(struct xfs_efd_log_format_32, 28); - XFS_CHECK_STRUCT_SIZE(struct xfs_efd_log_format_64, 32); - XFS_CHECK_STRUCT_SIZE(struct xfs_efi_log_format_32, 28); - XFS_CHECK_STRUCT_SIZE(struct xfs_efi_log_format_64, 32); - XFS_CHECK_STRUCT_SIZE(struct xfs_extent_32, 12); - XFS_CHECK_STRUCT_SIZE(struct xfs_extent_64, 16); - XFS_CHECK_STRUCT_SIZE(struct xfs_log_dinode, 176); - XFS_CHECK_STRUCT_SIZE(struct xfs_icreate_log, 28); - XFS_CHECK_STRUCT_SIZE(struct xfs_ictimestamp, 8); - XFS_CHECK_STRUCT_SIZE(struct xfs_inode_log_format_32, 52); - XFS_CHECK_STRUCT_SIZE(struct xfs_inode_log_format_64, 56); - XFS_CHECK_STRUCT_SIZE(struct xfs_qoff_logformat, 20); - XFS_CHECK_STRUCT_SIZE(struct xfs_trans_header, 16); -} - -#endif /* __XFS_ONDISK_H */ diff --git a/src/linux/fs/xfs/xfs_pnfs.h b/src/linux/fs/xfs/xfs_pnfs.h deleted file mode 100644 index e8339f7..0000000 --- a/src/linux/fs/xfs/xfs_pnfs.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _XFS_PNFS_H -#define _XFS_PNFS_H 1 - -#ifdef CONFIG_EXPORTFS_BLOCK_OPS -int xfs_fs_get_uuid(struct super_block *sb, u8 *buf, u32 *len, u64 *offset); -int xfs_fs_map_blocks(struct inode *inode, loff_t offset, u64 length, - struct iomap *iomap, bool write, u32 *device_generation); -int xfs_fs_commit_blocks(struct inode *inode, struct iomap *maps, int nr_maps, - struct iattr *iattr); - -int xfs_break_layouts(struct inode *inode, uint *iolock, bool with_imutex); -#else -static inline int -xfs_break_layouts(struct inode *inode, uint *iolock, bool with_imutex) -{ - return 0; -} -#endif /* CONFIG_EXPORTFS_BLOCK_OPS */ -#endif /* _XFS_PNFS_H */ diff --git a/src/linux/fs/xfs/xfs_qm.h b/src/linux/fs/xfs/xfs_qm.h deleted file mode 100644 index 2975a82..0000000 --- a/src/linux/fs/xfs/xfs_qm.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_QM_H__ -#define __XFS_QM_H__ - -#include "xfs_dquot_item.h" -#include "xfs_dquot.h" - -struct xfs_inode; - -extern struct kmem_zone *xfs_qm_dqtrxzone; - -/* - * Number of bmaps that we ask from bmapi when doing a quotacheck. - * We make this restriction to keep the memory usage to a minimum. - */ -#define XFS_DQITER_MAP_SIZE 10 - -#define XFS_IS_DQUOT_UNINITIALIZED(dqp) ( \ - !dqp->q_core.d_blk_hardlimit && \ - !dqp->q_core.d_blk_softlimit && \ - !dqp->q_core.d_rtb_hardlimit && \ - !dqp->q_core.d_rtb_softlimit && \ - !dqp->q_core.d_ino_hardlimit && \ - !dqp->q_core.d_ino_softlimit && \ - !dqp->q_core.d_bcount && \ - !dqp->q_core.d_rtbcount && \ - !dqp->q_core.d_icount) - -/* - * This defines the unit of allocation of dquots. - * Currently, it is just one file system block, and a 4K blk contains 30 - * (136 * 30 = 4080) dquots. It's probably not worth trying to make - * this more dynamic. - * XXXsup However, if this number is changed, we have to make sure that we don't - * implicitly assume that we do allocations in chunks of a single filesystem - * block in the dquot/xqm code. - */ -#define XFS_DQUOT_CLUSTER_SIZE_FSB (xfs_filblks_t)1 - -struct xfs_def_quota { - xfs_qcnt_t bhardlimit; /* default data blk hard limit */ - xfs_qcnt_t bsoftlimit; /* default data blk soft limit */ - xfs_qcnt_t ihardlimit; /* default inode count hard limit */ - xfs_qcnt_t isoftlimit; /* default inode count soft limit */ - xfs_qcnt_t rtbhardlimit; /* default realtime blk hard limit */ - xfs_qcnt_t rtbsoftlimit; /* default realtime blk soft limit */ -}; - -/* - * Various quota information for individual filesystems. - * The mount structure keeps a pointer to this. - */ -typedef struct xfs_quotainfo { - struct radix_tree_root qi_uquota_tree; - struct radix_tree_root qi_gquota_tree; - struct radix_tree_root qi_pquota_tree; - struct mutex qi_tree_lock; - struct xfs_inode *qi_uquotaip; /* user quota inode */ - struct xfs_inode *qi_gquotaip; /* group quota inode */ - struct xfs_inode *qi_pquotaip; /* project quota inode */ - struct list_lru qi_lru; - int qi_dquots; - time_t qi_btimelimit; /* limit for blks timer */ - time_t qi_itimelimit; /* limit for inodes timer */ - time_t qi_rtbtimelimit;/* limit for rt blks timer */ - xfs_qwarncnt_t qi_bwarnlimit; /* limit for blks warnings */ - xfs_qwarncnt_t qi_iwarnlimit; /* limit for inodes warnings */ - xfs_qwarncnt_t qi_rtbwarnlimit;/* limit for rt blks warnings */ - struct mutex qi_quotaofflock;/* to serialize quotaoff */ - xfs_filblks_t qi_dqchunklen; /* # BBs in a chunk of dqs */ - uint qi_dqperchunk; /* # ondisk dqs in above chunk */ - struct xfs_def_quota qi_usr_default; - struct xfs_def_quota qi_grp_default; - struct xfs_def_quota qi_prj_default; - struct shrinker qi_shrinker; -} xfs_quotainfo_t; - -static inline struct radix_tree_root * -xfs_dquot_tree( - struct xfs_quotainfo *qi, - int type) -{ - switch (type) { - case XFS_DQ_USER: - return &qi->qi_uquota_tree; - case XFS_DQ_GROUP: - return &qi->qi_gquota_tree; - case XFS_DQ_PROJ: - return &qi->qi_pquota_tree; - default: - ASSERT(0); - } - return NULL; -} - -static inline struct xfs_inode * -xfs_quota_inode(xfs_mount_t *mp, uint dq_flags) -{ - switch (dq_flags & XFS_DQ_ALLTYPES) { - case XFS_DQ_USER: - return mp->m_quotainfo->qi_uquotaip; - case XFS_DQ_GROUP: - return mp->m_quotainfo->qi_gquotaip; - case XFS_DQ_PROJ: - return mp->m_quotainfo->qi_pquotaip; - default: - ASSERT(0); - } - return NULL; -} - -extern void xfs_trans_mod_dquot(struct xfs_trans *, - struct xfs_dquot *, uint, long); -extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *, - struct xfs_mount *, struct xfs_dquot *, - struct xfs_dquot *, struct xfs_dquot *, - long, long, uint); -extern void xfs_trans_dqjoin(struct xfs_trans *, struct xfs_dquot *); -extern void xfs_trans_log_dquot(struct xfs_trans *, struct xfs_dquot *); - -/* - * We keep the usr, grp, and prj dquots separately so that locking will be - * easier to do at commit time. All transactions that we know of at this point - * affect no more than two dquots of one type. Hence, the TRANS_MAXDQS value. - */ -enum { - XFS_QM_TRANS_USR = 0, - XFS_QM_TRANS_GRP, - XFS_QM_TRANS_PRJ, - XFS_QM_TRANS_DQTYPES -}; -#define XFS_QM_TRANS_MAXDQS 2 -struct xfs_dquot_acct { - struct xfs_dqtrx dqs[XFS_QM_TRANS_DQTYPES][XFS_QM_TRANS_MAXDQS]; -}; - -/* - * Users are allowed to have a usage exceeding their softlimit for - * a period this long. - */ -#define XFS_QM_BTIMELIMIT (7 * 24*60*60) /* 1 week */ -#define XFS_QM_RTBTIMELIMIT (7 * 24*60*60) /* 1 week */ -#define XFS_QM_ITIMELIMIT (7 * 24*60*60) /* 1 week */ - -#define XFS_QM_BWARNLIMIT 5 -#define XFS_QM_IWARNLIMIT 5 -#define XFS_QM_RTBWARNLIMIT 5 - -extern void xfs_qm_destroy_quotainfo(struct xfs_mount *); - -/* dquot stuff */ -extern void xfs_qm_dqpurge_all(struct xfs_mount *, uint); -extern void xfs_qm_dqrele_all_inodes(struct xfs_mount *, uint); - -/* quota ops */ -extern int xfs_qm_scall_trunc_qfiles(struct xfs_mount *, uint); -extern int xfs_qm_scall_getquota(struct xfs_mount *, xfs_dqid_t *, - uint, struct qc_dqblk *, uint); -extern int xfs_qm_scall_setqlim(struct xfs_mount *, xfs_dqid_t, uint, - struct qc_dqblk *); -extern int xfs_qm_scall_quotaon(struct xfs_mount *, uint); -extern int xfs_qm_scall_quotaoff(struct xfs_mount *, uint); - -static inline struct xfs_def_quota * -xfs_get_defquota(struct xfs_dquot *dqp, struct xfs_quotainfo *qi) -{ - struct xfs_def_quota *defq; - - if (XFS_QM_ISUDQ(dqp)) - defq = &qi->qi_usr_default; - else if (XFS_QM_ISGDQ(dqp)) - defq = &qi->qi_grp_default; - else { - ASSERT(XFS_QM_ISPDQ(dqp)); - defq = &qi->qi_prj_default; - } - return defq; -} - -#endif /* __XFS_QM_H__ */ diff --git a/src/linux/fs/xfs/xfs_quota.h b/src/linux/fs/xfs/xfs_quota.h deleted file mode 100644 index ce6506a..0000000 --- a/src/linux/fs/xfs/xfs_quota.h +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_QUOTA_H__ -#define __XFS_QUOTA_H__ - -#include "xfs_quota_defs.h" - -/* - * Kernel only quota definitions and functions - */ - -struct xfs_trans; - -/* - * This check is done typically without holding the inode lock; - * that may seem racy, but it is harmless in the context that it is used. - * The inode cannot go inactive as long a reference is kept, and - * therefore if dquot(s) were attached, they'll stay consistent. - * If, for example, the ownership of the inode changes while - * we didn't have the inode locked, the appropriate dquot(s) will be - * attached atomically. - */ -#define XFS_NOT_DQATTACHED(mp, ip) \ - ((XFS_IS_UQUOTA_ON(mp) && (ip)->i_udquot == NULL) || \ - (XFS_IS_GQUOTA_ON(mp) && (ip)->i_gdquot == NULL) || \ - (XFS_IS_PQUOTA_ON(mp) && (ip)->i_pdquot == NULL)) - -#define XFS_QM_NEED_QUOTACHECK(mp) \ - ((XFS_IS_UQUOTA_ON(mp) && \ - (mp->m_sb.sb_qflags & XFS_UQUOTA_CHKD) == 0) || \ - (XFS_IS_GQUOTA_ON(mp) && \ - (mp->m_sb.sb_qflags & XFS_GQUOTA_CHKD) == 0) || \ - (XFS_IS_PQUOTA_ON(mp) && \ - (mp->m_sb.sb_qflags & XFS_PQUOTA_CHKD) == 0)) - -/* - * The structure kept inside the xfs_trans_t keep track of dquot changes - * within a transaction and apply them later. - */ -typedef struct xfs_dqtrx { - struct xfs_dquot *qt_dquot; /* the dquot this refers to */ - ulong qt_blk_res; /* blks reserved on a dquot */ - ulong qt_ino_res; /* inode reserved on a dquot */ - ulong qt_ino_res_used; /* inodes used from the reservation */ - long qt_bcount_delta; /* dquot blk count changes */ - long qt_delbcnt_delta; /* delayed dquot blk count changes */ - long qt_icount_delta; /* dquot inode count changes */ - ulong qt_rtblk_res; /* # blks reserved on a dquot */ - ulong qt_rtblk_res_used;/* # blks used from reservation */ - long qt_rtbcount_delta;/* dquot realtime blk changes */ - long qt_delrtb_delta; /* delayed RT blk count changes */ -} xfs_dqtrx_t; - -#ifdef CONFIG_XFS_QUOTA -extern void xfs_trans_dup_dqinfo(struct xfs_trans *, struct xfs_trans *); -extern void xfs_trans_free_dqinfo(struct xfs_trans *); -extern void xfs_trans_mod_dquot_byino(struct xfs_trans *, struct xfs_inode *, - uint, long); -extern void xfs_trans_apply_dquot_deltas(struct xfs_trans *); -extern void xfs_trans_unreserve_and_mod_dquots(struct xfs_trans *); -extern int xfs_trans_reserve_quota_nblks(struct xfs_trans *, - struct xfs_inode *, long, long, uint); -extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *, - struct xfs_mount *, struct xfs_dquot *, - struct xfs_dquot *, struct xfs_dquot *, long, long, uint); - -extern int xfs_qm_vop_dqalloc(struct xfs_inode *, xfs_dqid_t, xfs_dqid_t, - prid_t, uint, struct xfs_dquot **, struct xfs_dquot **, - struct xfs_dquot **); -extern void xfs_qm_vop_create_dqattach(struct xfs_trans *, struct xfs_inode *, - struct xfs_dquot *, struct xfs_dquot *, struct xfs_dquot *); -extern int xfs_qm_vop_rename_dqattach(struct xfs_inode **); -extern struct xfs_dquot *xfs_qm_vop_chown(struct xfs_trans *, - struct xfs_inode *, struct xfs_dquot **, struct xfs_dquot *); -extern int xfs_qm_vop_chown_reserve(struct xfs_trans *, struct xfs_inode *, - struct xfs_dquot *, struct xfs_dquot *, - struct xfs_dquot *, uint); -extern int xfs_qm_dqattach(struct xfs_inode *, uint); -extern int xfs_qm_dqattach_locked(struct xfs_inode *, uint); -extern void xfs_qm_dqdetach(struct xfs_inode *); -extern void xfs_qm_dqrele(struct xfs_dquot *); -extern void xfs_qm_statvfs(struct xfs_inode *, struct kstatfs *); -extern int xfs_qm_newmount(struct xfs_mount *, uint *, uint *); -extern void xfs_qm_mount_quotas(struct xfs_mount *); -extern void xfs_qm_unmount(struct xfs_mount *); -extern void xfs_qm_unmount_quotas(struct xfs_mount *); - -#else -static inline int -xfs_qm_vop_dqalloc(struct xfs_inode *ip, xfs_dqid_t uid, xfs_dqid_t gid, - prid_t prid, uint flags, struct xfs_dquot **udqp, - struct xfs_dquot **gdqp, struct xfs_dquot **pdqp) -{ - *udqp = NULL; - *gdqp = NULL; - *pdqp = NULL; - return 0; -} -#define xfs_trans_dup_dqinfo(tp, tp2) -#define xfs_trans_free_dqinfo(tp) -#define xfs_trans_mod_dquot_byino(tp, ip, fields, delta) -#define xfs_trans_apply_dquot_deltas(tp) -#define xfs_trans_unreserve_and_mod_dquots(tp) -static inline int xfs_trans_reserve_quota_nblks(struct xfs_trans *tp, - struct xfs_inode *ip, long nblks, long ninos, uint flags) -{ - return 0; -} -static inline int xfs_trans_reserve_quota_bydquots(struct xfs_trans *tp, - struct xfs_mount *mp, struct xfs_dquot *udqp, - struct xfs_dquot *gdqp, struct xfs_dquot *pdqp, - long nblks, long nions, uint flags) -{ - return 0; -} -#define xfs_qm_vop_create_dqattach(tp, ip, u, g, p) -#define xfs_qm_vop_rename_dqattach(it) (0) -#define xfs_qm_vop_chown(tp, ip, old, new) (NULL) -#define xfs_qm_vop_chown_reserve(tp, ip, u, g, p, fl) (0) -#define xfs_qm_dqattach(ip, fl) (0) -#define xfs_qm_dqattach_locked(ip, fl) (0) -#define xfs_qm_dqdetach(ip) -#define xfs_qm_dqrele(d) -#define xfs_qm_statvfs(ip, s) -#define xfs_qm_newmount(mp, a, b) (0) -#define xfs_qm_mount_quotas(mp) -#define xfs_qm_unmount(mp) -#define xfs_qm_unmount_quotas(mp) -#endif /* CONFIG_XFS_QUOTA */ - -#define xfs_trans_unreserve_quota_nblks(tp, ip, nblks, ninos, flags) \ - xfs_trans_reserve_quota_nblks(tp, ip, -(nblks), -(ninos), flags) -#define xfs_trans_reserve_quota(tp, mp, ud, gd, pd, nb, ni, f) \ - xfs_trans_reserve_quota_bydquots(tp, mp, ud, gd, pd, nb, ni, \ - f | XFS_QMOPT_RES_REGBLKS) - -extern int xfs_mount_reset_sbqflags(struct xfs_mount *); - -#endif /* __XFS_QUOTA_H__ */ diff --git a/src/linux/fs/xfs/xfs_refcount_item.c b/src/linux/fs/xfs/xfs_refcount_item.c deleted file mode 100644 index fe86a66..0000000 --- a/src/linux/fs/xfs/xfs_refcount_item.c +++ /dev/null @@ -1,539 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_trans.h" -#include "xfs_trans_priv.h" -#include "xfs_buf_item.h" -#include "xfs_refcount_item.h" -#include "xfs_log.h" -#include "xfs_refcount.h" - - -kmem_zone_t *xfs_cui_zone; -kmem_zone_t *xfs_cud_zone; - -static inline struct xfs_cui_log_item *CUI_ITEM(struct xfs_log_item *lip) -{ - return container_of(lip, struct xfs_cui_log_item, cui_item); -} - -void -xfs_cui_item_free( - struct xfs_cui_log_item *cuip) -{ - if (cuip->cui_format.cui_nextents > XFS_CUI_MAX_FAST_EXTENTS) - kmem_free(cuip); - else - kmem_zone_free(xfs_cui_zone, cuip); -} - -STATIC void -xfs_cui_item_size( - struct xfs_log_item *lip, - int *nvecs, - int *nbytes) -{ - struct xfs_cui_log_item *cuip = CUI_ITEM(lip); - - *nvecs += 1; - *nbytes += xfs_cui_log_format_sizeof(cuip->cui_format.cui_nextents); -} - -/* - * This is called to fill in the vector of log iovecs for the - * given cui log item. We use only 1 iovec, and we point that - * at the cui_log_format structure embedded in the cui item. - * It is at this point that we assert that all of the extent - * slots in the cui item have been filled. - */ -STATIC void -xfs_cui_item_format( - struct xfs_log_item *lip, - struct xfs_log_vec *lv) -{ - struct xfs_cui_log_item *cuip = CUI_ITEM(lip); - struct xfs_log_iovec *vecp = NULL; - - ASSERT(atomic_read(&cuip->cui_next_extent) == - cuip->cui_format.cui_nextents); - - cuip->cui_format.cui_type = XFS_LI_CUI; - cuip->cui_format.cui_size = 1; - - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_CUI_FORMAT, &cuip->cui_format, - xfs_cui_log_format_sizeof(cuip->cui_format.cui_nextents)); -} - -/* - * Pinning has no meaning for an cui item, so just return. - */ -STATIC void -xfs_cui_item_pin( - struct xfs_log_item *lip) -{ -} - -/* - * The unpin operation is the last place an CUI is manipulated in the log. It is - * either inserted in the AIL or aborted in the event of a log I/O error. In - * either case, the CUI transaction has been successfully committed to make it - * this far. Therefore, we expect whoever committed the CUI to either construct - * and commit the CUD or drop the CUD's reference in the event of error. Simply - * drop the log's CUI reference now that the log is done with it. - */ -STATIC void -xfs_cui_item_unpin( - struct xfs_log_item *lip, - int remove) -{ - struct xfs_cui_log_item *cuip = CUI_ITEM(lip); - - xfs_cui_release(cuip); -} - -/* - * CUI items have no locking or pushing. However, since CUIs are pulled from - * the AIL when their corresponding CUDs are committed to disk, their situation - * is very similar to being pinned. Return XFS_ITEM_PINNED so that the caller - * will eventually flush the log. This should help in getting the CUI out of - * the AIL. - */ -STATIC uint -xfs_cui_item_push( - struct xfs_log_item *lip, - struct list_head *buffer_list) -{ - return XFS_ITEM_PINNED; -} - -/* - * The CUI has been either committed or aborted if the transaction has been - * cancelled. If the transaction was cancelled, an CUD isn't going to be - * constructed and thus we free the CUI here directly. - */ -STATIC void -xfs_cui_item_unlock( - struct xfs_log_item *lip) -{ - if (lip->li_flags & XFS_LI_ABORTED) - xfs_cui_item_free(CUI_ITEM(lip)); -} - -/* - * The CUI is logged only once and cannot be moved in the log, so simply return - * the lsn at which it's been logged. - */ -STATIC xfs_lsn_t -xfs_cui_item_committed( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ - return lsn; -} - -/* - * The CUI dependency tracking op doesn't do squat. It can't because - * it doesn't know where the free extent is coming from. The dependency - * tracking has to be handled by the "enclosing" metadata object. For - * example, for inodes, the inode is locked throughout the extent freeing - * so the dependency should be recorded there. - */ -STATIC void -xfs_cui_item_committing( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ -} - -/* - * This is the ops vector shared by all cui log items. - */ -static const struct xfs_item_ops xfs_cui_item_ops = { - .iop_size = xfs_cui_item_size, - .iop_format = xfs_cui_item_format, - .iop_pin = xfs_cui_item_pin, - .iop_unpin = xfs_cui_item_unpin, - .iop_unlock = xfs_cui_item_unlock, - .iop_committed = xfs_cui_item_committed, - .iop_push = xfs_cui_item_push, - .iop_committing = xfs_cui_item_committing, -}; - -/* - * Allocate and initialize an cui item with the given number of extents. - */ -struct xfs_cui_log_item * -xfs_cui_init( - struct xfs_mount *mp, - uint nextents) - -{ - struct xfs_cui_log_item *cuip; - - ASSERT(nextents > 0); - if (nextents > XFS_CUI_MAX_FAST_EXTENTS) - cuip = kmem_zalloc(xfs_cui_log_item_sizeof(nextents), - KM_SLEEP); - else - cuip = kmem_zone_zalloc(xfs_cui_zone, KM_SLEEP); - - xfs_log_item_init(mp, &cuip->cui_item, XFS_LI_CUI, &xfs_cui_item_ops); - cuip->cui_format.cui_nextents = nextents; - cuip->cui_format.cui_id = (uintptr_t)(void *)cuip; - atomic_set(&cuip->cui_next_extent, 0); - atomic_set(&cuip->cui_refcount, 2); - - return cuip; -} - -/* - * Freeing the CUI requires that we remove it from the AIL if it has already - * been placed there. However, the CUI may not yet have been placed in the AIL - * when called by xfs_cui_release() from CUD processing due to the ordering of - * committed vs unpin operations in bulk insert operations. Hence the reference - * count to ensure only the last caller frees the CUI. - */ -void -xfs_cui_release( - struct xfs_cui_log_item *cuip) -{ - if (atomic_dec_and_test(&cuip->cui_refcount)) { - xfs_trans_ail_remove(&cuip->cui_item, SHUTDOWN_LOG_IO_ERROR); - xfs_cui_item_free(cuip); - } -} - -static inline struct xfs_cud_log_item *CUD_ITEM(struct xfs_log_item *lip) -{ - return container_of(lip, struct xfs_cud_log_item, cud_item); -} - -STATIC void -xfs_cud_item_size( - struct xfs_log_item *lip, - int *nvecs, - int *nbytes) -{ - *nvecs += 1; - *nbytes += sizeof(struct xfs_cud_log_format); -} - -/* - * This is called to fill in the vector of log iovecs for the - * given cud log item. We use only 1 iovec, and we point that - * at the cud_log_format structure embedded in the cud item. - * It is at this point that we assert that all of the extent - * slots in the cud item have been filled. - */ -STATIC void -xfs_cud_item_format( - struct xfs_log_item *lip, - struct xfs_log_vec *lv) -{ - struct xfs_cud_log_item *cudp = CUD_ITEM(lip); - struct xfs_log_iovec *vecp = NULL; - - cudp->cud_format.cud_type = XFS_LI_CUD; - cudp->cud_format.cud_size = 1; - - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_CUD_FORMAT, &cudp->cud_format, - sizeof(struct xfs_cud_log_format)); -} - -/* - * Pinning has no meaning for an cud item, so just return. - */ -STATIC void -xfs_cud_item_pin( - struct xfs_log_item *lip) -{ -} - -/* - * Since pinning has no meaning for an cud item, unpinning does - * not either. - */ -STATIC void -xfs_cud_item_unpin( - struct xfs_log_item *lip, - int remove) -{ -} - -/* - * There isn't much you can do to push on an cud item. It is simply stuck - * waiting for the log to be flushed to disk. - */ -STATIC uint -xfs_cud_item_push( - struct xfs_log_item *lip, - struct list_head *buffer_list) -{ - return XFS_ITEM_PINNED; -} - -/* - * The CUD is either committed or aborted if the transaction is cancelled. If - * the transaction is cancelled, drop our reference to the CUI and free the - * CUD. - */ -STATIC void -xfs_cud_item_unlock( - struct xfs_log_item *lip) -{ - struct xfs_cud_log_item *cudp = CUD_ITEM(lip); - - if (lip->li_flags & XFS_LI_ABORTED) { - xfs_cui_release(cudp->cud_cuip); - kmem_zone_free(xfs_cud_zone, cudp); - } -} - -/* - * When the cud item is committed to disk, all we need to do is delete our - * reference to our partner cui item and then free ourselves. Since we're - * freeing ourselves we must return -1 to keep the transaction code from - * further referencing this item. - */ -STATIC xfs_lsn_t -xfs_cud_item_committed( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ - struct xfs_cud_log_item *cudp = CUD_ITEM(lip); - - /* - * Drop the CUI reference regardless of whether the CUD has been - * aborted. Once the CUD transaction is constructed, it is the sole - * responsibility of the CUD to release the CUI (even if the CUI is - * aborted due to log I/O error). - */ - xfs_cui_release(cudp->cud_cuip); - kmem_zone_free(xfs_cud_zone, cudp); - - return (xfs_lsn_t)-1; -} - -/* - * The CUD dependency tracking op doesn't do squat. It can't because - * it doesn't know where the free extent is coming from. The dependency - * tracking has to be handled by the "enclosing" metadata object. For - * example, for inodes, the inode is locked throughout the extent freeing - * so the dependency should be recorded there. - */ -STATIC void -xfs_cud_item_committing( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ -} - -/* - * This is the ops vector shared by all cud log items. - */ -static const struct xfs_item_ops xfs_cud_item_ops = { - .iop_size = xfs_cud_item_size, - .iop_format = xfs_cud_item_format, - .iop_pin = xfs_cud_item_pin, - .iop_unpin = xfs_cud_item_unpin, - .iop_unlock = xfs_cud_item_unlock, - .iop_committed = xfs_cud_item_committed, - .iop_push = xfs_cud_item_push, - .iop_committing = xfs_cud_item_committing, -}; - -/* - * Allocate and initialize an cud item with the given number of extents. - */ -struct xfs_cud_log_item * -xfs_cud_init( - struct xfs_mount *mp, - struct xfs_cui_log_item *cuip) - -{ - struct xfs_cud_log_item *cudp; - - cudp = kmem_zone_zalloc(xfs_cud_zone, KM_SLEEP); - xfs_log_item_init(mp, &cudp->cud_item, XFS_LI_CUD, &xfs_cud_item_ops); - cudp->cud_cuip = cuip; - cudp->cud_format.cud_cui_id = cuip->cui_format.cui_id; - - return cudp; -} - -/* - * Process a refcount update intent item that was recovered from the log. - * We need to update the refcountbt. - */ -int -xfs_cui_recover( - struct xfs_mount *mp, - struct xfs_cui_log_item *cuip) -{ - int i; - int error = 0; - unsigned int refc_type; - struct xfs_phys_extent *refc; - xfs_fsblock_t startblock_fsb; - bool op_ok; - struct xfs_cud_log_item *cudp; - struct xfs_trans *tp; - struct xfs_btree_cur *rcur = NULL; - enum xfs_refcount_intent_type type; - xfs_fsblock_t firstfsb; - xfs_fsblock_t new_fsb; - xfs_extlen_t new_len; - struct xfs_bmbt_irec irec; - struct xfs_defer_ops dfops; - bool requeue_only = false; - - ASSERT(!test_bit(XFS_CUI_RECOVERED, &cuip->cui_flags)); - - /* - * First check the validity of the extents described by the - * CUI. If any are bad, then assume that all are bad and - * just toss the CUI. - */ - for (i = 0; i < cuip->cui_format.cui_nextents; i++) { - refc = &cuip->cui_format.cui_extents[i]; - startblock_fsb = XFS_BB_TO_FSB(mp, - XFS_FSB_TO_DADDR(mp, refc->pe_startblock)); - switch (refc->pe_flags & XFS_REFCOUNT_EXTENT_TYPE_MASK) { - case XFS_REFCOUNT_INCREASE: - case XFS_REFCOUNT_DECREASE: - case XFS_REFCOUNT_ALLOC_COW: - case XFS_REFCOUNT_FREE_COW: - op_ok = true; - break; - default: - op_ok = false; - break; - } - if (!op_ok || startblock_fsb == 0 || - refc->pe_len == 0 || - startblock_fsb >= mp->m_sb.sb_dblocks || - refc->pe_len >= mp->m_sb.sb_agblocks || - (refc->pe_flags & ~XFS_REFCOUNT_EXTENT_FLAGS)) { - /* - * This will pull the CUI from the AIL and - * free the memory associated with it. - */ - set_bit(XFS_CUI_RECOVERED, &cuip->cui_flags); - xfs_cui_release(cuip); - return -EIO; - } - } - - /* - * Under normal operation, refcount updates are deferred, so we - * wouldn't be adding them directly to a transaction. All - * refcount updates manage reservation usage internally and - * dynamically by deferring work that won't fit in the - * transaction. Normally, any work that needs to be deferred - * gets attached to the same defer_ops that scheduled the - * refcount update. However, we're in log recovery here, so we - * we create our own defer_ops and use that to finish up any - * work that doesn't fit. - */ - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp); - if (error) - return error; - cudp = xfs_trans_get_cud(tp, cuip); - - xfs_defer_init(&dfops, &firstfsb); - for (i = 0; i < cuip->cui_format.cui_nextents; i++) { - refc = &cuip->cui_format.cui_extents[i]; - refc_type = refc->pe_flags & XFS_REFCOUNT_EXTENT_TYPE_MASK; - switch (refc_type) { - case XFS_REFCOUNT_INCREASE: - case XFS_REFCOUNT_DECREASE: - case XFS_REFCOUNT_ALLOC_COW: - case XFS_REFCOUNT_FREE_COW: - type = refc_type; - break; - default: - error = -EFSCORRUPTED; - goto abort_error; - } - if (requeue_only) { - new_fsb = refc->pe_startblock; - new_len = refc->pe_len; - } else - error = xfs_trans_log_finish_refcount_update(tp, cudp, - &dfops, type, refc->pe_startblock, refc->pe_len, - &new_fsb, &new_len, &rcur); - if (error) - goto abort_error; - - /* Requeue what we didn't finish. */ - if (new_len > 0) { - irec.br_startblock = new_fsb; - irec.br_blockcount = new_len; - switch (type) { - case XFS_REFCOUNT_INCREASE: - error = xfs_refcount_increase_extent( - tp->t_mountp, &dfops, &irec); - break; - case XFS_REFCOUNT_DECREASE: - error = xfs_refcount_decrease_extent( - tp->t_mountp, &dfops, &irec); - break; - case XFS_REFCOUNT_ALLOC_COW: - error = xfs_refcount_alloc_cow_extent( - tp->t_mountp, &dfops, - irec.br_startblock, - irec.br_blockcount); - break; - case XFS_REFCOUNT_FREE_COW: - error = xfs_refcount_free_cow_extent( - tp->t_mountp, &dfops, - irec.br_startblock, - irec.br_blockcount); - break; - default: - ASSERT(0); - } - if (error) - goto abort_error; - requeue_only = true; - } - } - - xfs_refcount_finish_one_cleanup(tp, rcur, error); - error = xfs_defer_finish(&tp, &dfops, NULL); - if (error) - goto abort_error; - set_bit(XFS_CUI_RECOVERED, &cuip->cui_flags); - error = xfs_trans_commit(tp); - return error; - -abort_error: - xfs_refcount_finish_one_cleanup(tp, rcur, error); - xfs_defer_cancel(&dfops); - xfs_trans_cancel(tp); - return error; -} diff --git a/src/linux/fs/xfs/xfs_refcount_item.h b/src/linux/fs/xfs/xfs_refcount_item.h deleted file mode 100644 index 5b74ddd..0000000 --- a/src/linux/fs/xfs/xfs_refcount_item.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#ifndef __XFS_REFCOUNT_ITEM_H__ -#define __XFS_REFCOUNT_ITEM_H__ - -/* - * There are (currently) two pairs of refcount btree redo item types: - * increase and decrease. The log items for these are CUI (refcount - * update intent) and CUD (refcount update done). The redo item type - * is encoded in the flags field of each xfs_map_extent. - * - * *I items should be recorded in the *first* of a series of rolled - * transactions, and the *D items should be recorded in the same - * transaction that records the associated refcountbt updates. - * - * Should the system crash after the commit of the first transaction - * but before the commit of the final transaction in a series, log - * recovery will use the redo information recorded by the intent items - * to replay the refcountbt metadata updates. - */ - -/* kernel only CUI/CUD definitions */ - -struct xfs_mount; -struct kmem_zone; - -/* - * Max number of extents in fast allocation path. - */ -#define XFS_CUI_MAX_FAST_EXTENTS 16 - -/* - * Define CUI flag bits. Manipulated by set/clear/test_bit operators. - */ -#define XFS_CUI_RECOVERED 1 - -/* - * This is the "refcount update intent" log item. It is used to log - * the fact that some reverse mappings need to change. It is used in - * conjunction with the "refcount update done" log item described - * below. - * - * These log items follow the same rules as struct xfs_efi_log_item; - * see the comments about that structure (in xfs_extfree_item.h) for - * more details. - */ -struct xfs_cui_log_item { - struct xfs_log_item cui_item; - atomic_t cui_refcount; - atomic_t cui_next_extent; - unsigned long cui_flags; /* misc flags */ - struct xfs_cui_log_format cui_format; -}; - -static inline size_t -xfs_cui_log_item_sizeof( - unsigned int nr) -{ - return offsetof(struct xfs_cui_log_item, cui_format) + - xfs_cui_log_format_sizeof(nr); -} - -/* - * This is the "refcount update done" log item. It is used to log the - * fact that some refcountbt updates mentioned in an earlier cui item - * have been performed. - */ -struct xfs_cud_log_item { - struct xfs_log_item cud_item; - struct xfs_cui_log_item *cud_cuip; - struct xfs_cud_log_format cud_format; -}; - -extern struct kmem_zone *xfs_cui_zone; -extern struct kmem_zone *xfs_cud_zone; - -struct xfs_cui_log_item *xfs_cui_init(struct xfs_mount *, uint); -struct xfs_cud_log_item *xfs_cud_init(struct xfs_mount *, - struct xfs_cui_log_item *); -void xfs_cui_item_free(struct xfs_cui_log_item *); -void xfs_cui_release(struct xfs_cui_log_item *); -int xfs_cui_recover(struct xfs_mount *mp, struct xfs_cui_log_item *cuip); - -#endif /* __XFS_REFCOUNT_ITEM_H__ */ diff --git a/src/linux/fs/xfs/xfs_reflink.c b/src/linux/fs/xfs/xfs_reflink.c deleted file mode 100644 index a279b4e..0000000 --- a/src/linux/fs/xfs/xfs_reflink.c +++ /dev/null @@ -1,1733 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_inode_item.h" -#include "xfs_bmap.h" -#include "xfs_bmap_util.h" -#include "xfs_error.h" -#include "xfs_dir2.h" -#include "xfs_dir2_priv.h" -#include "xfs_ioctl.h" -#include "xfs_trace.h" -#include "xfs_log.h" -#include "xfs_icache.h" -#include "xfs_pnfs.h" -#include "xfs_btree.h" -#include "xfs_refcount_btree.h" -#include "xfs_refcount.h" -#include "xfs_bmap_btree.h" -#include "xfs_trans_space.h" -#include "xfs_bit.h" -#include "xfs_alloc.h" -#include "xfs_quota_defs.h" -#include "xfs_quota.h" -#include "xfs_btree.h" -#include "xfs_bmap_btree.h" -#include "xfs_reflink.h" -#include "xfs_iomap.h" -#include "xfs_rmap_btree.h" -#include "xfs_sb.h" -#include "xfs_ag_resv.h" - -/* - * Copy on Write of Shared Blocks - * - * XFS must preserve "the usual" file semantics even when two files share - * the same physical blocks. This means that a write to one file must not - * alter the blocks in a different file; the way that we'll do that is - * through the use of a copy-on-write mechanism. At a high level, that - * means that when we want to write to a shared block, we allocate a new - * block, write the data to the new block, and if that succeeds we map the - * new block into the file. - * - * XFS provides a "delayed allocation" mechanism that defers the allocation - * of disk blocks to dirty-but-not-yet-mapped file blocks as long as - * possible. This reduces fragmentation by enabling the filesystem to ask - * for bigger chunks less often, which is exactly what we want for CoW. - * - * The delalloc mechanism begins when the kernel wants to make a block - * writable (write_begin or page_mkwrite). If the offset is not mapped, we - * create a delalloc mapping, which is a regular in-core extent, but without - * a real startblock. (For delalloc mappings, the startblock encodes both - * a flag that this is a delalloc mapping, and a worst-case estimate of how - * many blocks might be required to put the mapping into the BMBT.) delalloc - * mappings are a reservation against the free space in the filesystem; - * adjacent mappings can also be combined into fewer larger mappings. - * - * When dirty pages are being written out (typically in writepage), the - * delalloc reservations are converted into real mappings by allocating - * blocks and replacing the delalloc mapping with real ones. A delalloc - * mapping can be replaced by several real ones if the free space is - * fragmented. - * - * We want to adapt the delalloc mechanism for copy-on-write, since the - * write paths are similar. The first two steps (creating the reservation - * and allocating the blocks) are exactly the same as delalloc except that - * the mappings must be stored in a separate CoW fork because we do not want - * to disturb the mapping in the data fork until we're sure that the write - * succeeded. IO completion in this case is the process of removing the old - * mapping from the data fork and moving the new mapping from the CoW fork to - * the data fork. This will be discussed shortly. - * - * For now, unaligned directio writes will be bounced back to the page cache. - * Block-aligned directio writes will use the same mechanism as buffered - * writes. - * - * CoW remapping must be done after the data block write completes, - * because we don't want to destroy the old data fork map until we're sure - * the new block has been written. Since the new mappings are kept in a - * separate fork, we can simply iterate these mappings to find the ones - * that cover the file blocks that we just CoW'd. For each extent, simply - * unmap the corresponding range in the data fork, map the new range into - * the data fork, and remove the extent from the CoW fork. - * - * Since the remapping operation can be applied to an arbitrary file - * range, we record the need for the remap step as a flag in the ioend - * instead of declaring a new IO type. This is required for direct io - * because we only have ioend for the whole dio, and we have to be able to - * remember the presence of unwritten blocks and CoW blocks with a single - * ioend structure. Better yet, the more ground we can cover with one - * ioend, the better. - */ - -/* - * Given an AG extent, find the lowest-numbered run of shared blocks - * within that range and return the range in fbno/flen. If - * find_end_of_shared is true, return the longest contiguous extent of - * shared blocks. If there are no shared extents, fbno and flen will - * be set to NULLAGBLOCK and 0, respectively. - */ -int -xfs_reflink_find_shared( - struct xfs_mount *mp, - xfs_agnumber_t agno, - xfs_agblock_t agbno, - xfs_extlen_t aglen, - xfs_agblock_t *fbno, - xfs_extlen_t *flen, - bool find_end_of_shared) -{ - struct xfs_buf *agbp; - struct xfs_btree_cur *cur; - int error; - - error = xfs_alloc_read_agf(mp, NULL, agno, 0, &agbp); - if (error) - return error; - - cur = xfs_refcountbt_init_cursor(mp, NULL, agbp, agno, NULL); - - error = xfs_refcount_find_shared(cur, agbno, aglen, fbno, flen, - find_end_of_shared); - - xfs_btree_del_cursor(cur, error ? XFS_BTREE_ERROR : XFS_BTREE_NOERROR); - - xfs_buf_relse(agbp); - return error; -} - -/* - * Trim the mapping to the next block where there's a change in the - * shared/unshared status. More specifically, this means that we - * find the lowest-numbered extent of shared blocks that coincides with - * the given block mapping. If the shared extent overlaps the start of - * the mapping, trim the mapping to the end of the shared extent. If - * the shared region intersects the mapping, trim the mapping to the - * start of the shared extent. If there are no shared regions that - * overlap, just return the original extent. - */ -int -xfs_reflink_trim_around_shared( - struct xfs_inode *ip, - struct xfs_bmbt_irec *irec, - bool *shared, - bool *trimmed) -{ - xfs_agnumber_t agno; - xfs_agblock_t agbno; - xfs_extlen_t aglen; - xfs_agblock_t fbno; - xfs_extlen_t flen; - int error = 0; - - /* Holes, unwritten, and delalloc extents cannot be shared */ - if (!xfs_is_reflink_inode(ip) || - ISUNWRITTEN(irec) || - irec->br_startblock == HOLESTARTBLOCK || - irec->br_startblock == DELAYSTARTBLOCK || - isnullstartblock(irec->br_startblock)) { - *shared = false; - return 0; - } - - trace_xfs_reflink_trim_around_shared(ip, irec); - - agno = XFS_FSB_TO_AGNO(ip->i_mount, irec->br_startblock); - agbno = XFS_FSB_TO_AGBNO(ip->i_mount, irec->br_startblock); - aglen = irec->br_blockcount; - - error = xfs_reflink_find_shared(ip->i_mount, agno, agbno, - aglen, &fbno, &flen, true); - if (error) - return error; - - *shared = *trimmed = false; - if (fbno == NULLAGBLOCK) { - /* No shared blocks at all. */ - return 0; - } else if (fbno == agbno) { - /* - * The start of this extent is shared. Truncate the - * mapping at the end of the shared region so that a - * subsequent iteration starts at the start of the - * unshared region. - */ - irec->br_blockcount = flen; - *shared = true; - if (flen != aglen) - *trimmed = true; - return 0; - } else { - /* - * There's a shared extent midway through this extent. - * Truncate the mapping at the start of the shared - * extent so that a subsequent iteration starts at the - * start of the shared region. - */ - irec->br_blockcount = fbno - agbno; - *trimmed = true; - return 0; - } -} - -/* - * Trim the passed in imap to the next shared/unshared extent boundary, and - * if imap->br_startoff points to a shared extent reserve space for it in the - * COW fork. In this case *shared is set to true, else to false. - * - * Note that imap will always contain the block numbers for the existing blocks - * in the data fork, as the upper layers need them for read-modify-write - * operations. - */ -int -xfs_reflink_reserve_cow( - struct xfs_inode *ip, - struct xfs_bmbt_irec *imap, - bool *shared) -{ - struct xfs_bmbt_irec got, prev; - xfs_fileoff_t end_fsb, orig_end_fsb; - int eof = 0, error = 0; - bool trimmed; - xfs_extnum_t idx; - xfs_extlen_t align; - - /* - * Search the COW fork extent list first. This serves two purposes: - * first this implement the speculative preallocation using cowextisze, - * so that we also unshared block adjacent to shared blocks instead - * of just the shared blocks themselves. Second the lookup in the - * extent list is generally faster than going out to the shared extent - * tree. - */ - xfs_bmap_search_extents(ip, imap->br_startoff, XFS_COW_FORK, &eof, &idx, - &got, &prev); - if (!eof && got.br_startoff <= imap->br_startoff) { - trace_xfs_reflink_cow_found(ip, imap); - xfs_trim_extent(imap, got.br_startoff, got.br_blockcount); - - *shared = true; - return 0; - } - - /* Trim the mapping to the nearest shared extent boundary. */ - error = xfs_reflink_trim_around_shared(ip, imap, shared, &trimmed); - if (error) - return error; - - /* Not shared? Just report the (potentially capped) extent. */ - if (!*shared) - return 0; - - /* - * Fork all the shared blocks from our write offset until the end of - * the extent. - */ - error = xfs_qm_dqattach_locked(ip, 0); - if (error) - return error; - - end_fsb = orig_end_fsb = imap->br_startoff + imap->br_blockcount; - - align = xfs_eof_alignment(ip, xfs_get_cowextsz_hint(ip)); - if (align) - end_fsb = roundup_64(end_fsb, align); - -retry: - error = xfs_bmapi_reserve_delalloc(ip, XFS_COW_FORK, imap->br_startoff, - end_fsb - imap->br_startoff, &got, &prev, &idx, eof); - switch (error) { - case 0: - break; - case -ENOSPC: - case -EDQUOT: - /* retry without any preallocation */ - trace_xfs_reflink_cow_enospc(ip, imap); - if (end_fsb != orig_end_fsb) { - end_fsb = orig_end_fsb; - goto retry; - } - /*FALLTHRU*/ - default: - return error; - } - - if (end_fsb != orig_end_fsb) - xfs_inode_set_cowblocks_tag(ip); - - trace_xfs_reflink_cow_alloc(ip, &got); - return 0; -} - -/* Allocate all CoW reservations covering a range of blocks in a file. */ -static int -__xfs_reflink_allocate_cow( - struct xfs_inode *ip, - xfs_fileoff_t *offset_fsb, - xfs_fileoff_t end_fsb) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_bmbt_irec imap; - struct xfs_defer_ops dfops; - struct xfs_trans *tp; - xfs_fsblock_t first_block; - int nimaps = 1, error; - bool shared; - - xfs_defer_init(&dfops, &first_block); - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, 0, 0, - XFS_TRANS_RESERVE, &tp); - if (error) - return error; - - xfs_ilock(ip, XFS_ILOCK_EXCL); - - /* Read extent from the source file. */ - nimaps = 1; - error = xfs_bmapi_read(ip, *offset_fsb, end_fsb - *offset_fsb, - &imap, &nimaps, 0); - if (error) - goto out_unlock; - ASSERT(nimaps == 1); - - error = xfs_reflink_reserve_cow(ip, &imap, &shared); - if (error) - goto out_trans_cancel; - - if (!shared) { - *offset_fsb = imap.br_startoff + imap.br_blockcount; - goto out_trans_cancel; - } - - xfs_trans_ijoin(tp, ip, 0); - error = xfs_bmapi_write(tp, ip, imap.br_startoff, imap.br_blockcount, - XFS_BMAPI_COWFORK, &first_block, - XFS_EXTENTADD_SPACE_RES(mp, XFS_DATA_FORK), - &imap, &nimaps, &dfops); - if (error) - goto out_trans_cancel; - - error = xfs_defer_finish(&tp, &dfops, NULL); - if (error) - goto out_trans_cancel; - - error = xfs_trans_commit(tp); - - *offset_fsb = imap.br_startoff + imap.br_blockcount; -out_unlock: - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return error; -out_trans_cancel: - xfs_defer_cancel(&dfops); - xfs_trans_cancel(tp); - goto out_unlock; -} - -/* Allocate all CoW reservations covering a part of a file. */ -int -xfs_reflink_allocate_cow_range( - struct xfs_inode *ip, - xfs_off_t offset, - xfs_off_t count) -{ - struct xfs_mount *mp = ip->i_mount; - xfs_fileoff_t offset_fsb = XFS_B_TO_FSBT(mp, offset); - xfs_fileoff_t end_fsb = XFS_B_TO_FSB(mp, offset + count); - int error; - - ASSERT(xfs_is_reflink_inode(ip)); - - trace_xfs_reflink_allocate_cow_range(ip, offset, count); - - /* - * Make sure that the dquots are there. - */ - error = xfs_qm_dqattach(ip, 0); - if (error) - return error; - - while (offset_fsb < end_fsb) { - error = __xfs_reflink_allocate_cow(ip, &offset_fsb, end_fsb); - if (error) { - trace_xfs_reflink_allocate_cow_range_error(ip, error, - _RET_IP_); - break; - } - } - - return error; -} - -/* - * Find the CoW reservation (and whether or not it needs block allocation) - * for a given byte offset of a file. - */ -bool -xfs_reflink_find_cow_mapping( - struct xfs_inode *ip, - xfs_off_t offset, - struct xfs_bmbt_irec *imap, - bool *need_alloc) -{ - struct xfs_bmbt_irec irec; - struct xfs_ifork *ifp; - struct xfs_bmbt_rec_host *gotp; - xfs_fileoff_t bno; - xfs_extnum_t idx; - - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL | XFS_ILOCK_SHARED)); - ASSERT(xfs_is_reflink_inode(ip)); - - /* Find the extent in the CoW fork. */ - ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); - bno = XFS_B_TO_FSBT(ip->i_mount, offset); - gotp = xfs_iext_bno_to_ext(ifp, bno, &idx); - if (!gotp) - return false; - - xfs_bmbt_get_all(gotp, &irec); - if (bno >= irec.br_startoff + irec.br_blockcount || - bno < irec.br_startoff) - return false; - - trace_xfs_reflink_find_cow_mapping(ip, offset, 1, XFS_IO_OVERWRITE, - &irec); - - /* If it's still delalloc, we must allocate later. */ - *imap = irec; - *need_alloc = !!(isnullstartblock(irec.br_startblock)); - - return true; -} - -/* - * Trim an extent to end at the next CoW reservation past offset_fsb. - */ -int -xfs_reflink_trim_irec_to_next_cow( - struct xfs_inode *ip, - xfs_fileoff_t offset_fsb, - struct xfs_bmbt_irec *imap) -{ - struct xfs_bmbt_irec irec; - struct xfs_ifork *ifp; - struct xfs_bmbt_rec_host *gotp; - xfs_extnum_t idx; - - if (!xfs_is_reflink_inode(ip)) - return 0; - - /* Find the extent in the CoW fork. */ - ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); - gotp = xfs_iext_bno_to_ext(ifp, offset_fsb, &idx); - if (!gotp) - return 0; - xfs_bmbt_get_all(gotp, &irec); - - /* This is the extent before; try sliding up one. */ - if (irec.br_startoff < offset_fsb) { - idx++; - if (idx >= ifp->if_bytes / sizeof(xfs_bmbt_rec_t)) - return 0; - gotp = xfs_iext_get_ext(ifp, idx); - xfs_bmbt_get_all(gotp, &irec); - } - - if (irec.br_startoff >= imap->br_startoff + imap->br_blockcount) - return 0; - - imap->br_blockcount = irec.br_startoff - imap->br_startoff; - trace_xfs_reflink_trim_irec(ip, imap); - - return 0; -} - -/* - * Cancel all pending CoW reservations for some block range of an inode. - */ -int -xfs_reflink_cancel_cow_blocks( - struct xfs_inode *ip, - struct xfs_trans **tpp, - xfs_fileoff_t offset_fsb, - xfs_fileoff_t end_fsb) -{ - struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); - struct xfs_bmbt_irec got, prev, del; - xfs_extnum_t idx; - xfs_fsblock_t firstfsb; - struct xfs_defer_ops dfops; - int error = 0, eof = 0; - - if (!xfs_is_reflink_inode(ip)) - return 0; - - xfs_bmap_search_extents(ip, offset_fsb, XFS_COW_FORK, &eof, &idx, - &got, &prev); - if (eof) - return 0; - - while (got.br_startoff < end_fsb) { - del = got; - xfs_trim_extent(&del, offset_fsb, end_fsb - offset_fsb); - trace_xfs_reflink_cancel_cow(ip, &del); - - if (isnullstartblock(del.br_startblock)) { - error = xfs_bmap_del_extent_delay(ip, XFS_COW_FORK, - &idx, &got, &del); - if (error) - break; - } else { - xfs_trans_ijoin(*tpp, ip, 0); - xfs_defer_init(&dfops, &firstfsb); - - /* Free the CoW orphan record. */ - error = xfs_refcount_free_cow_extent(ip->i_mount, - &dfops, del.br_startblock, - del.br_blockcount); - if (error) - break; - - xfs_bmap_add_free(ip->i_mount, &dfops, - del.br_startblock, del.br_blockcount, - NULL); - - /* Update quota accounting */ - xfs_trans_mod_dquot_byino(*tpp, ip, XFS_TRANS_DQ_BCOUNT, - -(long)del.br_blockcount); - - /* Roll the transaction */ - error = xfs_defer_finish(tpp, &dfops, ip); - if (error) { - xfs_defer_cancel(&dfops); - break; - } - - /* Remove the mapping from the CoW fork. */ - xfs_bmap_del_extent_cow(ip, &idx, &got, &del); - } - - if (++idx >= ifp->if_bytes / sizeof(struct xfs_bmbt_rec)) - break; - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), &got); - } - - /* clear tag if cow fork is emptied */ - if (!ifp->if_bytes) - xfs_inode_clear_cowblocks_tag(ip); - - return error; -} - -/* - * Cancel all pending CoW reservations for some byte range of an inode. - */ -int -xfs_reflink_cancel_cow_range( - struct xfs_inode *ip, - xfs_off_t offset, - xfs_off_t count) -{ - struct xfs_trans *tp; - xfs_fileoff_t offset_fsb; - xfs_fileoff_t end_fsb; - int error; - - trace_xfs_reflink_cancel_cow_range(ip, offset, count); - ASSERT(xfs_is_reflink_inode(ip)); - - offset_fsb = XFS_B_TO_FSBT(ip->i_mount, offset); - if (count == NULLFILEOFF) - end_fsb = NULLFILEOFF; - else - end_fsb = XFS_B_TO_FSB(ip->i_mount, offset + count); - - /* Start a rolling transaction to remove the mappings */ - error = xfs_trans_alloc(ip->i_mount, &M_RES(ip->i_mount)->tr_write, - 0, 0, 0, &tp); - if (error) - goto out; - - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, 0); - - /* Scrape out the old CoW reservations */ - error = xfs_reflink_cancel_cow_blocks(ip, &tp, offset_fsb, end_fsb); - if (error) - goto out_cancel; - - error = xfs_trans_commit(tp); - - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return error; - -out_cancel: - xfs_trans_cancel(tp); - xfs_iunlock(ip, XFS_ILOCK_EXCL); -out: - trace_xfs_reflink_cancel_cow_range_error(ip, error, _RET_IP_); - return error; -} - -/* - * Remap parts of a file's data fork after a successful CoW. - */ -int -xfs_reflink_end_cow( - struct xfs_inode *ip, - xfs_off_t offset, - xfs_off_t count) -{ - struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); - struct xfs_bmbt_irec got, prev, del; - struct xfs_trans *tp; - xfs_fileoff_t offset_fsb; - xfs_fileoff_t end_fsb; - xfs_fsblock_t firstfsb; - struct xfs_defer_ops dfops; - int error, eof = 0; - unsigned int resblks; - xfs_filblks_t rlen; - xfs_extnum_t idx; - - trace_xfs_reflink_end_cow(ip, offset, count); - - /* No COW extents? That's easy! */ - if (ifp->if_bytes == 0) - return 0; - - offset_fsb = XFS_B_TO_FSBT(ip->i_mount, offset); - end_fsb = XFS_B_TO_FSB(ip->i_mount, offset + count); - - /* Start a rolling transaction to switch the mappings */ - resblks = XFS_EXTENTADD_SPACE_RES(ip->i_mount, XFS_DATA_FORK); - error = xfs_trans_alloc(ip->i_mount, &M_RES(ip->i_mount)->tr_write, - resblks, 0, 0, &tp); - if (error) - goto out; - - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, 0); - - xfs_bmap_search_extents(ip, end_fsb - 1, XFS_COW_FORK, &eof, &idx, - &got, &prev); - - /* If there is a hole at end_fsb - 1 go to the previous extent */ - if (eof || got.br_startoff > end_fsb) { - ASSERT(idx > 0); - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, --idx), &got); - } - - /* Walk backwards until we're out of the I/O range... */ - while (got.br_startoff + got.br_blockcount > offset_fsb) { - del = got; - xfs_trim_extent(&del, offset_fsb, end_fsb - offset_fsb); - - /* Extent delete may have bumped idx forward */ - if (!del.br_blockcount) { - idx--; - goto next_extent; - } - - ASSERT(!isnullstartblock(got.br_startblock)); - - /* Unmap the old blocks in the data fork. */ - xfs_defer_init(&dfops, &firstfsb); - rlen = del.br_blockcount; - error = __xfs_bunmapi(tp, ip, del.br_startoff, &rlen, 0, 1, - &firstfsb, &dfops); - if (error) - goto out_defer; - - /* Trim the extent to whatever got unmapped. */ - if (rlen) { - xfs_trim_extent(&del, del.br_startoff + rlen, - del.br_blockcount - rlen); - } - trace_xfs_reflink_cow_remap(ip, &del); - - /* Free the CoW orphan record. */ - error = xfs_refcount_free_cow_extent(tp->t_mountp, &dfops, - del.br_startblock, del.br_blockcount); - if (error) - goto out_defer; - - /* Map the new blocks into the data fork. */ - error = xfs_bmap_map_extent(tp->t_mountp, &dfops, ip, &del); - if (error) - goto out_defer; - - /* Remove the mapping from the CoW fork. */ - xfs_bmap_del_extent_cow(ip, &idx, &got, &del); - - error = xfs_defer_finish(&tp, &dfops, ip); - if (error) - goto out_defer; - -next_extent: - if (idx < 0) - break; - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), &got); - } - - error = xfs_trans_commit(tp); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - if (error) - goto out; - return 0; - -out_defer: - xfs_defer_cancel(&dfops); - xfs_trans_cancel(tp); - xfs_iunlock(ip, XFS_ILOCK_EXCL); -out: - trace_xfs_reflink_end_cow_error(ip, error, _RET_IP_); - return error; -} - -/* - * Free leftover CoW reservations that didn't get cleaned out. - */ -int -xfs_reflink_recover_cow( - struct xfs_mount *mp) -{ - xfs_agnumber_t agno; - int error = 0; - - if (!xfs_sb_version_hasreflink(&mp->m_sb)) - return 0; - - for (agno = 0; agno < mp->m_sb.sb_agcount; agno++) { - error = xfs_refcount_recover_cow_leftovers(mp, agno); - if (error) - break; - } - - return error; -} - -/* - * Reflinking (Block) Ranges of Two Files Together - * - * First, ensure that the reflink flag is set on both inodes. The flag is an - * optimization to avoid unnecessary refcount btree lookups in the write path. - * - * Now we can iteratively remap the range of extents (and holes) in src to the - * corresponding ranges in dest. Let drange and srange denote the ranges of - * logical blocks in dest and src touched by the reflink operation. - * - * While the length of drange is greater than zero, - * - Read src's bmbt at the start of srange ("imap") - * - If imap doesn't exist, make imap appear to start at the end of srange - * with zero length. - * - If imap starts before srange, advance imap to start at srange. - * - If imap goes beyond srange, truncate imap to end at the end of srange. - * - Punch (imap start - srange start + imap len) blocks from dest at - * offset (drange start). - * - If imap points to a real range of pblks, - * > Increase the refcount of the imap's pblks - * > Map imap's pblks into dest at the offset - * (drange start + imap start - srange start) - * - Advance drange and srange by (imap start - srange start + imap len) - * - * Finally, if the reflink made dest longer, update both the in-core and - * on-disk file sizes. - * - * ASCII Art Demonstration: - * - * Let's say we want to reflink this source file: - * - * ----SSSSSSS-SSSSS----SSSSSS (src file) - * <--------------------> - * - * into this destination file: - * - * --DDDDDDDDDDDDDDDDDDD--DDD (dest file) - * <--------------------> - * '-' means a hole, and 'S' and 'D' are written blocks in the src and dest. - * Observe that the range has different logical offsets in either file. - * - * Consider that the first extent in the source file doesn't line up with our - * reflink range. Unmapping and remapping are separate operations, so we can - * unmap more blocks from the destination file than we remap. - * - * ----SSSSSSS-SSSSS----SSSSSS - * <-------> - * --DDDDD---------DDDDD--DDD - * <-------> - * - * Now remap the source extent into the destination file: - * - * ----SSSSSSS-SSSSS----SSSSSS - * <-------> - * --DDDDD--SSSSSSSDDDDD--DDD - * <-------> - * - * Do likewise with the second hole and extent in our range. Holes in the - * unmap range don't affect our operation. - * - * ----SSSSSSS-SSSSS----SSSSSS - * <----> - * --DDDDD--SSSSSSS-SSSSS-DDD - * <----> - * - * Finally, unmap and remap part of the third extent. This will increase the - * size of the destination file. - * - * ----SSSSSSS-SSSSS----SSSSSS - * <-----> - * --DDDDD--SSSSSSS-SSSSS----SSS - * <-----> - * - * Once we update the destination file's i_size, we're done. - */ - -/* - * Ensure the reflink bit is set in both inodes. - */ -STATIC int -xfs_reflink_set_inode_flag( - struct xfs_inode *src, - struct xfs_inode *dest) -{ - struct xfs_mount *mp = src->i_mount; - int error; - struct xfs_trans *tp; - - if (xfs_is_reflink_inode(src) && xfs_is_reflink_inode(dest)) - return 0; - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0, 0, 0, &tp); - if (error) - goto out_error; - - /* Lock both files against IO */ - if (src->i_ino == dest->i_ino) - xfs_ilock(src, XFS_ILOCK_EXCL); - else - xfs_lock_two_inodes(src, dest, XFS_ILOCK_EXCL); - - if (!xfs_is_reflink_inode(src)) { - trace_xfs_reflink_set_inode_flag(src); - xfs_trans_ijoin(tp, src, XFS_ILOCK_EXCL); - src->i_d.di_flags2 |= XFS_DIFLAG2_REFLINK; - xfs_trans_log_inode(tp, src, XFS_ILOG_CORE); - xfs_ifork_init_cow(src); - } else - xfs_iunlock(src, XFS_ILOCK_EXCL); - - if (src->i_ino == dest->i_ino) - goto commit_flags; - - if (!xfs_is_reflink_inode(dest)) { - trace_xfs_reflink_set_inode_flag(dest); - xfs_trans_ijoin(tp, dest, XFS_ILOCK_EXCL); - dest->i_d.di_flags2 |= XFS_DIFLAG2_REFLINK; - xfs_trans_log_inode(tp, dest, XFS_ILOG_CORE); - xfs_ifork_init_cow(dest); - } else - xfs_iunlock(dest, XFS_ILOCK_EXCL); - -commit_flags: - error = xfs_trans_commit(tp); - if (error) - goto out_error; - return error; - -out_error: - trace_xfs_reflink_set_inode_flag_error(dest, error, _RET_IP_); - return error; -} - -/* - * Update destination inode size & cowextsize hint, if necessary. - */ -STATIC int -xfs_reflink_update_dest( - struct xfs_inode *dest, - xfs_off_t newlen, - xfs_extlen_t cowextsize) -{ - struct xfs_mount *mp = dest->i_mount; - struct xfs_trans *tp; - int error; - - if (newlen <= i_size_read(VFS_I(dest)) && cowextsize == 0) - return 0; - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0, 0, 0, &tp); - if (error) - goto out_error; - - xfs_ilock(dest, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, dest, XFS_ILOCK_EXCL); - - if (newlen > i_size_read(VFS_I(dest))) { - trace_xfs_reflink_update_inode_size(dest, newlen); - i_size_write(VFS_I(dest), newlen); - dest->i_d.di_size = newlen; - } - - if (cowextsize) { - dest->i_d.di_cowextsize = cowextsize; - dest->i_d.di_flags2 |= XFS_DIFLAG2_COWEXTSIZE; - } - - xfs_trans_log_inode(tp, dest, XFS_ILOG_CORE); - - error = xfs_trans_commit(tp); - if (error) - goto out_error; - return error; - -out_error: - trace_xfs_reflink_update_inode_size_error(dest, error, _RET_IP_); - return error; -} - -/* - * Do we have enough reserve in this AG to handle a reflink? The refcount - * btree already reserved all the space it needs, but the rmap btree can grow - * infinitely, so we won't allow more reflinks when the AG is down to the - * btree reserves. - */ -static int -xfs_reflink_ag_has_free_space( - struct xfs_mount *mp, - xfs_agnumber_t agno) -{ - struct xfs_perag *pag; - int error = 0; - - if (!xfs_sb_version_hasrmapbt(&mp->m_sb)) - return 0; - - pag = xfs_perag_get(mp, agno); - if (xfs_ag_resv_critical(pag, XFS_AG_RESV_AGFL) || - xfs_ag_resv_critical(pag, XFS_AG_RESV_METADATA)) - error = -ENOSPC; - xfs_perag_put(pag); - return error; -} - -/* - * Unmap a range of blocks from a file, then map other blocks into the hole. - * The range to unmap is (destoff : destoff + srcioff + irec->br_blockcount). - * The extent irec is mapped into dest at irec->br_startoff. - */ -STATIC int -xfs_reflink_remap_extent( - struct xfs_inode *ip, - struct xfs_bmbt_irec *irec, - xfs_fileoff_t destoff, - xfs_off_t new_isize) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_trans *tp; - xfs_fsblock_t firstfsb; - unsigned int resblks; - struct xfs_defer_ops dfops; - struct xfs_bmbt_irec uirec; - bool real_extent; - xfs_filblks_t rlen; - xfs_filblks_t unmap_len; - xfs_off_t newlen; - int error; - - unmap_len = irec->br_startoff + irec->br_blockcount - destoff; - trace_xfs_reflink_punch_range(ip, destoff, unmap_len); - - /* Only remap normal extents. */ - real_extent = (irec->br_startblock != HOLESTARTBLOCK && - irec->br_startblock != DELAYSTARTBLOCK && - !ISUNWRITTEN(irec)); - - /* No reflinking if we're low on space */ - if (real_extent) { - error = xfs_reflink_ag_has_free_space(mp, - XFS_FSB_TO_AGNO(mp, irec->br_startblock)); - if (error) - goto out; - } - - /* Start a rolling transaction to switch the mappings */ - resblks = XFS_EXTENTADD_SPACE_RES(ip->i_mount, XFS_DATA_FORK); - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, resblks, 0, 0, &tp); - if (error) - goto out; - - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, 0); - - /* If we're not just clearing space, then do we have enough quota? */ - if (real_extent) { - error = xfs_trans_reserve_quota_nblks(tp, ip, - irec->br_blockcount, 0, XFS_QMOPT_RES_REGBLKS); - if (error) - goto out_cancel; - } - - trace_xfs_reflink_remap(ip, irec->br_startoff, - irec->br_blockcount, irec->br_startblock); - - /* Unmap the old blocks in the data fork. */ - rlen = unmap_len; - while (rlen) { - xfs_defer_init(&dfops, &firstfsb); - error = __xfs_bunmapi(tp, ip, destoff, &rlen, 0, 1, - &firstfsb, &dfops); - if (error) - goto out_defer; - - /* - * Trim the extent to whatever got unmapped. - * Remember, bunmapi works backwards. - */ - uirec.br_startblock = irec->br_startblock + rlen; - uirec.br_startoff = irec->br_startoff + rlen; - uirec.br_blockcount = unmap_len - rlen; - unmap_len = rlen; - - /* If this isn't a real mapping, we're done. */ - if (!real_extent || uirec.br_blockcount == 0) - goto next_extent; - - trace_xfs_reflink_remap(ip, uirec.br_startoff, - uirec.br_blockcount, uirec.br_startblock); - - /* Update the refcount tree */ - error = xfs_refcount_increase_extent(mp, &dfops, &uirec); - if (error) - goto out_defer; - - /* Map the new blocks into the data fork. */ - error = xfs_bmap_map_extent(mp, &dfops, ip, &uirec); - if (error) - goto out_defer; - - /* Update quota accounting. */ - xfs_trans_mod_dquot_byino(tp, ip, XFS_TRANS_DQ_BCOUNT, - uirec.br_blockcount); - - /* Update dest isize if needed. */ - newlen = XFS_FSB_TO_B(mp, - uirec.br_startoff + uirec.br_blockcount); - newlen = min_t(xfs_off_t, newlen, new_isize); - if (newlen > i_size_read(VFS_I(ip))) { - trace_xfs_reflink_update_inode_size(ip, newlen); - i_size_write(VFS_I(ip), newlen); - ip->i_d.di_size = newlen; - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - } - -next_extent: - /* Process all the deferred stuff. */ - error = xfs_defer_finish(&tp, &dfops, ip); - if (error) - goto out_defer; - } - - error = xfs_trans_commit(tp); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - if (error) - goto out; - return 0; - -out_defer: - xfs_defer_cancel(&dfops); -out_cancel: - xfs_trans_cancel(tp); - xfs_iunlock(ip, XFS_ILOCK_EXCL); -out: - trace_xfs_reflink_remap_extent_error(ip, error, _RET_IP_); - return error; -} - -/* - * Iteratively remap one file's extents (and holes) to another's. - */ -STATIC int -xfs_reflink_remap_blocks( - struct xfs_inode *src, - xfs_fileoff_t srcoff, - struct xfs_inode *dest, - xfs_fileoff_t destoff, - xfs_filblks_t len, - xfs_off_t new_isize) -{ - struct xfs_bmbt_irec imap; - int nimaps; - int error = 0; - xfs_filblks_t range_len; - - /* drange = (destoff, destoff + len); srange = (srcoff, srcoff + len) */ - while (len) { - trace_xfs_reflink_remap_blocks_loop(src, srcoff, len, - dest, destoff); - /* Read extent from the source file */ - nimaps = 1; - xfs_ilock(src, XFS_ILOCK_EXCL); - error = xfs_bmapi_read(src, srcoff, len, &imap, &nimaps, 0); - xfs_iunlock(src, XFS_ILOCK_EXCL); - if (error) - goto err; - ASSERT(nimaps == 1); - - trace_xfs_reflink_remap_imap(src, srcoff, len, XFS_IO_OVERWRITE, - &imap); - - /* Translate imap into the destination file. */ - range_len = imap.br_startoff + imap.br_blockcount - srcoff; - imap.br_startoff += destoff - srcoff; - - /* Clear dest from destoff to the end of imap and map it in. */ - error = xfs_reflink_remap_extent(dest, &imap, destoff, - new_isize); - if (error) - goto err; - - if (fatal_signal_pending(current)) { - error = -EINTR; - goto err; - } - - /* Advance drange/srange */ - srcoff += range_len; - destoff += range_len; - len -= range_len; - } - - return 0; - -err: - trace_xfs_reflink_remap_blocks_error(dest, error, _RET_IP_); - return error; -} - -/* - * Read a page's worth of file data into the page cache. Return the page - * locked. - */ -static struct page * -xfs_get_page( - struct inode *inode, - xfs_off_t offset) -{ - struct address_space *mapping; - struct page *page; - pgoff_t n; - - n = offset >> PAGE_SHIFT; - mapping = inode->i_mapping; - page = read_mapping_page(mapping, n, NULL); - if (IS_ERR(page)) - return page; - if (!PageUptodate(page)) { - put_page(page); - return ERR_PTR(-EIO); - } - lock_page(page); - return page; -} - -/* - * Compare extents of two files to see if they are the same. - */ -static int -xfs_compare_extents( - struct inode *src, - xfs_off_t srcoff, - struct inode *dest, - xfs_off_t destoff, - xfs_off_t len, - bool *is_same) -{ - xfs_off_t src_poff; - xfs_off_t dest_poff; - void *src_addr; - void *dest_addr; - struct page *src_page; - struct page *dest_page; - xfs_off_t cmp_len; - bool same; - int error; - - error = -EINVAL; - same = true; - while (len) { - src_poff = srcoff & (PAGE_SIZE - 1); - dest_poff = destoff & (PAGE_SIZE - 1); - cmp_len = min(PAGE_SIZE - src_poff, - PAGE_SIZE - dest_poff); - cmp_len = min(cmp_len, len); - ASSERT(cmp_len > 0); - - trace_xfs_reflink_compare_extents(XFS_I(src), srcoff, cmp_len, - XFS_I(dest), destoff); - - src_page = xfs_get_page(src, srcoff); - if (IS_ERR(src_page)) { - error = PTR_ERR(src_page); - goto out_error; - } - dest_page = xfs_get_page(dest, destoff); - if (IS_ERR(dest_page)) { - error = PTR_ERR(dest_page); - unlock_page(src_page); - put_page(src_page); - goto out_error; - } - src_addr = kmap_atomic(src_page); - dest_addr = kmap_atomic(dest_page); - - flush_dcache_page(src_page); - flush_dcache_page(dest_page); - - if (memcmp(src_addr + src_poff, dest_addr + dest_poff, cmp_len)) - same = false; - - kunmap_atomic(dest_addr); - kunmap_atomic(src_addr); - unlock_page(dest_page); - unlock_page(src_page); - put_page(dest_page); - put_page(src_page); - - if (!same) - break; - - srcoff += cmp_len; - destoff += cmp_len; - len -= cmp_len; - } - - *is_same = same; - return 0; - -out_error: - trace_xfs_reflink_compare_extents_error(XFS_I(dest), error, _RET_IP_); - return error; -} - -/* - * Link a range of blocks from one file to another. - */ -int -xfs_reflink_remap_range( - struct file *file_in, - loff_t pos_in, - struct file *file_out, - loff_t pos_out, - u64 len, - bool is_dedupe) -{ - struct inode *inode_in = file_inode(file_in); - struct xfs_inode *src = XFS_I(inode_in); - struct inode *inode_out = file_inode(file_out); - struct xfs_inode *dest = XFS_I(inode_out); - struct xfs_mount *mp = src->i_mount; - loff_t bs = inode_out->i_sb->s_blocksize; - bool same_inode = (inode_in == inode_out); - xfs_fileoff_t sfsbno, dfsbno; - xfs_filblks_t fsblen; - xfs_extlen_t cowextsize; - loff_t isize; - ssize_t ret; - loff_t blen; - - if (!xfs_sb_version_hasreflink(&mp->m_sb)) - return -EOPNOTSUPP; - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - /* Lock both files against IO */ - if (same_inode) { - xfs_ilock(src, XFS_IOLOCK_EXCL); - xfs_ilock(src, XFS_MMAPLOCK_EXCL); - } else { - xfs_lock_two_inodes(src, dest, XFS_IOLOCK_EXCL); - xfs_lock_two_inodes(src, dest, XFS_MMAPLOCK_EXCL); - } - - /* Don't touch certain kinds of inodes */ - ret = -EPERM; - if (IS_IMMUTABLE(inode_out)) - goto out_unlock; - - ret = -ETXTBSY; - if (IS_SWAPFILE(inode_in) || IS_SWAPFILE(inode_out)) - goto out_unlock; - - - /* Don't reflink dirs, pipes, sockets... */ - ret = -EISDIR; - if (S_ISDIR(inode_in->i_mode) || S_ISDIR(inode_out->i_mode)) - goto out_unlock; - ret = -EINVAL; - if (S_ISFIFO(inode_in->i_mode) || S_ISFIFO(inode_out->i_mode)) - goto out_unlock; - if (!S_ISREG(inode_in->i_mode) || !S_ISREG(inode_out->i_mode)) - goto out_unlock; - - /* Don't reflink realtime inodes */ - if (XFS_IS_REALTIME_INODE(src) || XFS_IS_REALTIME_INODE(dest)) - goto out_unlock; - - /* Don't share DAX file data for now. */ - if (IS_DAX(inode_in) || IS_DAX(inode_out)) - goto out_unlock; - - /* Are we going all the way to the end? */ - isize = i_size_read(inode_in); - if (isize == 0) { - ret = 0; - goto out_unlock; - } - - if (len == 0) - len = isize - pos_in; - - /* Ensure offsets don't wrap and the input is inside i_size */ - if (pos_in + len < pos_in || pos_out + len < pos_out || - pos_in + len > isize) - goto out_unlock; - - /* Don't allow dedupe past EOF in the dest file */ - if (is_dedupe) { - loff_t disize; - - disize = i_size_read(inode_out); - if (pos_out >= disize || pos_out + len > disize) - goto out_unlock; - } - - /* If we're linking to EOF, continue to the block boundary. */ - if (pos_in + len == isize) - blen = ALIGN(isize, bs) - pos_in; - else - blen = len; - - /* Only reflink if we're aligned to block boundaries */ - if (!IS_ALIGNED(pos_in, bs) || !IS_ALIGNED(pos_in + blen, bs) || - !IS_ALIGNED(pos_out, bs) || !IS_ALIGNED(pos_out + blen, bs)) - goto out_unlock; - - /* Don't allow overlapped reflink within the same file */ - if (same_inode) { - if (pos_out + blen > pos_in && pos_out < pos_in + blen) - goto out_unlock; - } - - /* Wait for the completion of any pending IOs on both files */ - inode_dio_wait(inode_in); - if (!same_inode) - inode_dio_wait(inode_out); - - ret = filemap_write_and_wait_range(inode_in->i_mapping, - pos_in, pos_in + len - 1); - if (ret) - goto out_unlock; - - ret = filemap_write_and_wait_range(inode_out->i_mapping, - pos_out, pos_out + len - 1); - if (ret) - goto out_unlock; - - trace_xfs_reflink_remap_range(src, pos_in, len, dest, pos_out); - - /* - * Check that the extents are the same. - */ - if (is_dedupe) { - bool is_same = false; - - ret = xfs_compare_extents(inode_in, pos_in, inode_out, pos_out, - len, &is_same); - if (ret) - goto out_unlock; - if (!is_same) { - ret = -EBADE; - goto out_unlock; - } - } - - ret = xfs_reflink_set_inode_flag(src, dest); - if (ret) - goto out_unlock; - - /* - * Invalidate the page cache so that we can clear any CoW mappings - * in the destination file. - */ - truncate_inode_pages_range(&inode_out->i_data, pos_out, - PAGE_ALIGN(pos_out + len) - 1); - - dfsbno = XFS_B_TO_FSBT(mp, pos_out); - sfsbno = XFS_B_TO_FSBT(mp, pos_in); - fsblen = XFS_B_TO_FSB(mp, len); - ret = xfs_reflink_remap_blocks(src, sfsbno, dest, dfsbno, fsblen, - pos_out + len); - if (ret) - goto out_unlock; - - /* - * Carry the cowextsize hint from src to dest if we're sharing the - * entire source file to the entire destination file, the source file - * has a cowextsize hint, and the destination file does not. - */ - cowextsize = 0; - if (pos_in == 0 && len == i_size_read(inode_in) && - (src->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE) && - pos_out == 0 && len >= i_size_read(inode_out) && - !(dest->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE)) - cowextsize = src->i_d.di_cowextsize; - - ret = xfs_reflink_update_dest(dest, pos_out + len, cowextsize); - -out_unlock: - xfs_iunlock(src, XFS_MMAPLOCK_EXCL); - xfs_iunlock(src, XFS_IOLOCK_EXCL); - if (src->i_ino != dest->i_ino) { - xfs_iunlock(dest, XFS_MMAPLOCK_EXCL); - xfs_iunlock(dest, XFS_IOLOCK_EXCL); - } - if (ret) - trace_xfs_reflink_remap_range_error(dest, ret, _RET_IP_); - return ret; -} - -/* - * The user wants to preemptively CoW all shared blocks in this file, - * which enables us to turn off the reflink flag. Iterate all - * extents which are not prealloc/delalloc to see which ranges are - * mentioned in the refcount tree, then read those blocks into the - * pagecache, dirty them, fsync them back out, and then we can update - * the inode flag. What happens if we run out of memory? :) - */ -STATIC int -xfs_reflink_dirty_extents( - struct xfs_inode *ip, - xfs_fileoff_t fbno, - xfs_filblks_t end, - xfs_off_t isize) -{ - struct xfs_mount *mp = ip->i_mount; - xfs_agnumber_t agno; - xfs_agblock_t agbno; - xfs_extlen_t aglen; - xfs_agblock_t rbno; - xfs_extlen_t rlen; - xfs_off_t fpos; - xfs_off_t flen; - struct xfs_bmbt_irec map[2]; - int nmaps; - int error = 0; - - while (end - fbno > 0) { - nmaps = 1; - /* - * Look for extents in the file. Skip holes, delalloc, or - * unwritten extents; they can't be reflinked. - */ - error = xfs_bmapi_read(ip, fbno, end - fbno, map, &nmaps, 0); - if (error) - goto out; - if (nmaps == 0) - break; - if (map[0].br_startblock == HOLESTARTBLOCK || - map[0].br_startblock == DELAYSTARTBLOCK || - ISUNWRITTEN(&map[0])) - goto next; - - map[1] = map[0]; - while (map[1].br_blockcount) { - agno = XFS_FSB_TO_AGNO(mp, map[1].br_startblock); - agbno = XFS_FSB_TO_AGBNO(mp, map[1].br_startblock); - aglen = map[1].br_blockcount; - - error = xfs_reflink_find_shared(mp, agno, agbno, aglen, - &rbno, &rlen, true); - if (error) - goto out; - if (rbno == NULLAGBLOCK) - break; - - /* Dirty the pages */ - xfs_iunlock(ip, XFS_ILOCK_EXCL); - fpos = XFS_FSB_TO_B(mp, map[1].br_startoff + - (rbno - agbno)); - flen = XFS_FSB_TO_B(mp, rlen); - if (fpos + flen > isize) - flen = isize - fpos; - error = iomap_file_dirty(VFS_I(ip), fpos, flen, - &xfs_iomap_ops); - xfs_ilock(ip, XFS_ILOCK_EXCL); - if (error) - goto out; - - map[1].br_blockcount -= (rbno - agbno + rlen); - map[1].br_startoff += (rbno - agbno + rlen); - map[1].br_startblock += (rbno - agbno + rlen); - } - -next: - fbno = map[0].br_startoff + map[0].br_blockcount; - } -out: - return error; -} - -/* Clear the inode reflink flag if there are no shared extents. */ -int -xfs_reflink_clear_inode_flag( - struct xfs_inode *ip, - struct xfs_trans **tpp) -{ - struct xfs_mount *mp = ip->i_mount; - xfs_fileoff_t fbno; - xfs_filblks_t end; - xfs_agnumber_t agno; - xfs_agblock_t agbno; - xfs_extlen_t aglen; - xfs_agblock_t rbno; - xfs_extlen_t rlen; - struct xfs_bmbt_irec map; - int nmaps; - int error = 0; - - ASSERT(xfs_is_reflink_inode(ip)); - - fbno = 0; - end = XFS_B_TO_FSB(mp, i_size_read(VFS_I(ip))); - while (end - fbno > 0) { - nmaps = 1; - /* - * Look for extents in the file. Skip holes, delalloc, or - * unwritten extents; they can't be reflinked. - */ - error = xfs_bmapi_read(ip, fbno, end - fbno, &map, &nmaps, 0); - if (error) - return error; - if (nmaps == 0) - break; - if (map.br_startblock == HOLESTARTBLOCK || - map.br_startblock == DELAYSTARTBLOCK || - ISUNWRITTEN(&map)) - goto next; - - agno = XFS_FSB_TO_AGNO(mp, map.br_startblock); - agbno = XFS_FSB_TO_AGBNO(mp, map.br_startblock); - aglen = map.br_blockcount; - - error = xfs_reflink_find_shared(mp, agno, agbno, aglen, - &rbno, &rlen, false); - if (error) - return error; - /* Is there still a shared block here? */ - if (rbno != NULLAGBLOCK) - return 0; -next: - fbno = map.br_startoff + map.br_blockcount; - } - - /* - * We didn't find any shared blocks so turn off the reflink flag. - * First, get rid of any leftover CoW mappings. - */ - error = xfs_reflink_cancel_cow_blocks(ip, tpp, 0, NULLFILEOFF); - if (error) - return error; - - /* Clear the inode flag. */ - trace_xfs_reflink_unset_inode_flag(ip); - ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK; - xfs_inode_clear_cowblocks_tag(ip); - xfs_trans_ijoin(*tpp, ip, 0); - xfs_trans_log_inode(*tpp, ip, XFS_ILOG_CORE); - - return error; -} - -/* - * Clear the inode reflink flag if there are no shared extents and the size - * hasn't changed. - */ -STATIC int -xfs_reflink_try_clear_inode_flag( - struct xfs_inode *ip) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_trans *tp; - int error = 0; - - /* Start a rolling transaction to remove the mappings */ - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_write, 0, 0, 0, &tp); - if (error) - return error; - - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, 0); - - error = xfs_reflink_clear_inode_flag(ip, &tp); - if (error) - goto cancel; - - error = xfs_trans_commit(tp); - if (error) - goto out; - - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return 0; -cancel: - xfs_trans_cancel(tp); -out: - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return error; -} - -/* - * Pre-COW all shared blocks within a given byte range of a file and turn off - * the reflink flag if we unshare all of the file's blocks. - */ -int -xfs_reflink_unshare( - struct xfs_inode *ip, - xfs_off_t offset, - xfs_off_t len) -{ - struct xfs_mount *mp = ip->i_mount; - xfs_fileoff_t fbno; - xfs_filblks_t end; - xfs_off_t isize; - int error; - - if (!xfs_is_reflink_inode(ip)) - return 0; - - trace_xfs_reflink_unshare(ip, offset, len); - - inode_dio_wait(VFS_I(ip)); - - /* Try to CoW the selected ranges */ - xfs_ilock(ip, XFS_ILOCK_EXCL); - fbno = XFS_B_TO_FSBT(mp, offset); - isize = i_size_read(VFS_I(ip)); - end = XFS_B_TO_FSB(mp, offset + len); - error = xfs_reflink_dirty_extents(ip, fbno, end, isize); - if (error) - goto out_unlock; - xfs_iunlock(ip, XFS_ILOCK_EXCL); - - /* Wait for the IO to finish */ - error = filemap_write_and_wait(VFS_I(ip)->i_mapping); - if (error) - goto out; - - /* Turn off the reflink flag if possible. */ - error = xfs_reflink_try_clear_inode_flag(ip); - if (error) - goto out; - - return 0; - -out_unlock: - xfs_iunlock(ip, XFS_ILOCK_EXCL); -out: - trace_xfs_reflink_unshare_error(ip, error, _RET_IP_); - return error; -} - -/* - * Does this inode have any real CoW reservations? - */ -bool -xfs_reflink_has_real_cow_blocks( - struct xfs_inode *ip) -{ - struct xfs_bmbt_irec irec; - struct xfs_ifork *ifp; - struct xfs_bmbt_rec_host *gotp; - xfs_extnum_t idx; - - if (!xfs_is_reflink_inode(ip)) - return false; - - /* Go find the old extent in the CoW fork. */ - ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); - gotp = xfs_iext_bno_to_ext(ifp, 0, &idx); - while (gotp) { - xfs_bmbt_get_all(gotp, &irec); - - if (!isnullstartblock(irec.br_startblock)) - return true; - - /* Roll on... */ - idx++; - if (idx >= ifp->if_bytes / sizeof(xfs_bmbt_rec_t)) - break; - gotp = xfs_iext_get_ext(ifp, idx); - } - - return false; -} diff --git a/src/linux/fs/xfs/xfs_reflink.h b/src/linux/fs/xfs/xfs_reflink.h deleted file mode 100644 index fad1160..0000000 --- a/src/linux/fs/xfs/xfs_reflink.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#ifndef __XFS_REFLINK_H -#define __XFS_REFLINK_H 1 - -extern int xfs_reflink_find_shared(struct xfs_mount *mp, xfs_agnumber_t agno, - xfs_agblock_t agbno, xfs_extlen_t aglen, xfs_agblock_t *fbno, - xfs_extlen_t *flen, bool find_maximal); -extern int xfs_reflink_trim_around_shared(struct xfs_inode *ip, - struct xfs_bmbt_irec *irec, bool *shared, bool *trimmed); - -extern int xfs_reflink_reserve_cow(struct xfs_inode *ip, - struct xfs_bmbt_irec *imap, bool *shared); -extern int xfs_reflink_allocate_cow_range(struct xfs_inode *ip, - xfs_off_t offset, xfs_off_t count); -extern bool xfs_reflink_find_cow_mapping(struct xfs_inode *ip, xfs_off_t offset, - struct xfs_bmbt_irec *imap, bool *need_alloc); -extern int xfs_reflink_trim_irec_to_next_cow(struct xfs_inode *ip, - xfs_fileoff_t offset_fsb, struct xfs_bmbt_irec *imap); - -extern int xfs_reflink_cancel_cow_blocks(struct xfs_inode *ip, - struct xfs_trans **tpp, xfs_fileoff_t offset_fsb, - xfs_fileoff_t end_fsb); -extern int xfs_reflink_cancel_cow_range(struct xfs_inode *ip, xfs_off_t offset, - xfs_off_t count); -extern int xfs_reflink_end_cow(struct xfs_inode *ip, xfs_off_t offset, - xfs_off_t count); -extern int xfs_reflink_recover_cow(struct xfs_mount *mp); -extern int xfs_reflink_remap_range(struct file *file_in, loff_t pos_in, - struct file *file_out, loff_t pos_out, u64 len, bool is_dedupe); -extern int xfs_reflink_clear_inode_flag(struct xfs_inode *ip, - struct xfs_trans **tpp); -extern int xfs_reflink_unshare(struct xfs_inode *ip, xfs_off_t offset, - xfs_off_t len); - -extern bool xfs_reflink_has_real_cow_blocks(struct xfs_inode *ip); - -#endif /* __XFS_REFLINK_H */ diff --git a/src/linux/fs/xfs/xfs_rmap_item.c b/src/linux/fs/xfs/xfs_rmap_item.c deleted file mode 100644 index 73c8278..0000000 --- a/src/linux/fs/xfs/xfs_rmap_item.c +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_trans.h" -#include "xfs_trans_priv.h" -#include "xfs_buf_item.h" -#include "xfs_rmap_item.h" -#include "xfs_log.h" -#include "xfs_rmap.h" - - -kmem_zone_t *xfs_rui_zone; -kmem_zone_t *xfs_rud_zone; - -static inline struct xfs_rui_log_item *RUI_ITEM(struct xfs_log_item *lip) -{ - return container_of(lip, struct xfs_rui_log_item, rui_item); -} - -void -xfs_rui_item_free( - struct xfs_rui_log_item *ruip) -{ - if (ruip->rui_format.rui_nextents > XFS_RUI_MAX_FAST_EXTENTS) - kmem_free(ruip); - else - kmem_zone_free(xfs_rui_zone, ruip); -} - -STATIC void -xfs_rui_item_size( - struct xfs_log_item *lip, - int *nvecs, - int *nbytes) -{ - struct xfs_rui_log_item *ruip = RUI_ITEM(lip); - - *nvecs += 1; - *nbytes += xfs_rui_log_format_sizeof(ruip->rui_format.rui_nextents); -} - -/* - * This is called to fill in the vector of log iovecs for the - * given rui log item. We use only 1 iovec, and we point that - * at the rui_log_format structure embedded in the rui item. - * It is at this point that we assert that all of the extent - * slots in the rui item have been filled. - */ -STATIC void -xfs_rui_item_format( - struct xfs_log_item *lip, - struct xfs_log_vec *lv) -{ - struct xfs_rui_log_item *ruip = RUI_ITEM(lip); - struct xfs_log_iovec *vecp = NULL; - - ASSERT(atomic_read(&ruip->rui_next_extent) == - ruip->rui_format.rui_nextents); - - ruip->rui_format.rui_type = XFS_LI_RUI; - ruip->rui_format.rui_size = 1; - - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_RUI_FORMAT, &ruip->rui_format, - xfs_rui_log_format_sizeof(ruip->rui_format.rui_nextents)); -} - -/* - * Pinning has no meaning for an rui item, so just return. - */ -STATIC void -xfs_rui_item_pin( - struct xfs_log_item *lip) -{ -} - -/* - * The unpin operation is the last place an RUI is manipulated in the log. It is - * either inserted in the AIL or aborted in the event of a log I/O error. In - * either case, the RUI transaction has been successfully committed to make it - * this far. Therefore, we expect whoever committed the RUI to either construct - * and commit the RUD or drop the RUD's reference in the event of error. Simply - * drop the log's RUI reference now that the log is done with it. - */ -STATIC void -xfs_rui_item_unpin( - struct xfs_log_item *lip, - int remove) -{ - struct xfs_rui_log_item *ruip = RUI_ITEM(lip); - - xfs_rui_release(ruip); -} - -/* - * RUI items have no locking or pushing. However, since RUIs are pulled from - * the AIL when their corresponding RUDs are committed to disk, their situation - * is very similar to being pinned. Return XFS_ITEM_PINNED so that the caller - * will eventually flush the log. This should help in getting the RUI out of - * the AIL. - */ -STATIC uint -xfs_rui_item_push( - struct xfs_log_item *lip, - struct list_head *buffer_list) -{ - return XFS_ITEM_PINNED; -} - -/* - * The RUI has been either committed or aborted if the transaction has been - * cancelled. If the transaction was cancelled, an RUD isn't going to be - * constructed and thus we free the RUI here directly. - */ -STATIC void -xfs_rui_item_unlock( - struct xfs_log_item *lip) -{ - if (lip->li_flags & XFS_LI_ABORTED) - xfs_rui_item_free(RUI_ITEM(lip)); -} - -/* - * The RUI is logged only once and cannot be moved in the log, so simply return - * the lsn at which it's been logged. - */ -STATIC xfs_lsn_t -xfs_rui_item_committed( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ - return lsn; -} - -/* - * The RUI dependency tracking op doesn't do squat. It can't because - * it doesn't know where the free extent is coming from. The dependency - * tracking has to be handled by the "enclosing" metadata object. For - * example, for inodes, the inode is locked throughout the extent freeing - * so the dependency should be recorded there. - */ -STATIC void -xfs_rui_item_committing( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ -} - -/* - * This is the ops vector shared by all rui log items. - */ -static const struct xfs_item_ops xfs_rui_item_ops = { - .iop_size = xfs_rui_item_size, - .iop_format = xfs_rui_item_format, - .iop_pin = xfs_rui_item_pin, - .iop_unpin = xfs_rui_item_unpin, - .iop_unlock = xfs_rui_item_unlock, - .iop_committed = xfs_rui_item_committed, - .iop_push = xfs_rui_item_push, - .iop_committing = xfs_rui_item_committing, -}; - -/* - * Allocate and initialize an rui item with the given number of extents. - */ -struct xfs_rui_log_item * -xfs_rui_init( - struct xfs_mount *mp, - uint nextents) - -{ - struct xfs_rui_log_item *ruip; - - ASSERT(nextents > 0); - if (nextents > XFS_RUI_MAX_FAST_EXTENTS) - ruip = kmem_zalloc(xfs_rui_log_item_sizeof(nextents), KM_SLEEP); - else - ruip = kmem_zone_zalloc(xfs_rui_zone, KM_SLEEP); - - xfs_log_item_init(mp, &ruip->rui_item, XFS_LI_RUI, &xfs_rui_item_ops); - ruip->rui_format.rui_nextents = nextents; - ruip->rui_format.rui_id = (uintptr_t)(void *)ruip; - atomic_set(&ruip->rui_next_extent, 0); - atomic_set(&ruip->rui_refcount, 2); - - return ruip; -} - -/* - * Copy an RUI format buffer from the given buf, and into the destination - * RUI format structure. The RUI/RUD items were designed not to need any - * special alignment handling. - */ -int -xfs_rui_copy_format( - struct xfs_log_iovec *buf, - struct xfs_rui_log_format *dst_rui_fmt) -{ - struct xfs_rui_log_format *src_rui_fmt; - uint len; - - src_rui_fmt = buf->i_addr; - len = xfs_rui_log_format_sizeof(src_rui_fmt->rui_nextents); - - if (buf->i_len != len) - return -EFSCORRUPTED; - - memcpy(dst_rui_fmt, src_rui_fmt, len); - return 0; -} - -/* - * Freeing the RUI requires that we remove it from the AIL if it has already - * been placed there. However, the RUI may not yet have been placed in the AIL - * when called by xfs_rui_release() from RUD processing due to the ordering of - * committed vs unpin operations in bulk insert operations. Hence the reference - * count to ensure only the last caller frees the RUI. - */ -void -xfs_rui_release( - struct xfs_rui_log_item *ruip) -{ - if (atomic_dec_and_test(&ruip->rui_refcount)) { - xfs_trans_ail_remove(&ruip->rui_item, SHUTDOWN_LOG_IO_ERROR); - xfs_rui_item_free(ruip); - } -} - -static inline struct xfs_rud_log_item *RUD_ITEM(struct xfs_log_item *lip) -{ - return container_of(lip, struct xfs_rud_log_item, rud_item); -} - -STATIC void -xfs_rud_item_size( - struct xfs_log_item *lip, - int *nvecs, - int *nbytes) -{ - *nvecs += 1; - *nbytes += sizeof(struct xfs_rud_log_format); -} - -/* - * This is called to fill in the vector of log iovecs for the - * given rud log item. We use only 1 iovec, and we point that - * at the rud_log_format structure embedded in the rud item. - * It is at this point that we assert that all of the extent - * slots in the rud item have been filled. - */ -STATIC void -xfs_rud_item_format( - struct xfs_log_item *lip, - struct xfs_log_vec *lv) -{ - struct xfs_rud_log_item *rudp = RUD_ITEM(lip); - struct xfs_log_iovec *vecp = NULL; - - rudp->rud_format.rud_type = XFS_LI_RUD; - rudp->rud_format.rud_size = 1; - - xlog_copy_iovec(lv, &vecp, XLOG_REG_TYPE_RUD_FORMAT, &rudp->rud_format, - sizeof(struct xfs_rud_log_format)); -} - -/* - * Pinning has no meaning for an rud item, so just return. - */ -STATIC void -xfs_rud_item_pin( - struct xfs_log_item *lip) -{ -} - -/* - * Since pinning has no meaning for an rud item, unpinning does - * not either. - */ -STATIC void -xfs_rud_item_unpin( - struct xfs_log_item *lip, - int remove) -{ -} - -/* - * There isn't much you can do to push on an rud item. It is simply stuck - * waiting for the log to be flushed to disk. - */ -STATIC uint -xfs_rud_item_push( - struct xfs_log_item *lip, - struct list_head *buffer_list) -{ - return XFS_ITEM_PINNED; -} - -/* - * The RUD is either committed or aborted if the transaction is cancelled. If - * the transaction is cancelled, drop our reference to the RUI and free the - * RUD. - */ -STATIC void -xfs_rud_item_unlock( - struct xfs_log_item *lip) -{ - struct xfs_rud_log_item *rudp = RUD_ITEM(lip); - - if (lip->li_flags & XFS_LI_ABORTED) { - xfs_rui_release(rudp->rud_ruip); - kmem_zone_free(xfs_rud_zone, rudp); - } -} - -/* - * When the rud item is committed to disk, all we need to do is delete our - * reference to our partner rui item and then free ourselves. Since we're - * freeing ourselves we must return -1 to keep the transaction code from - * further referencing this item. - */ -STATIC xfs_lsn_t -xfs_rud_item_committed( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ - struct xfs_rud_log_item *rudp = RUD_ITEM(lip); - - /* - * Drop the RUI reference regardless of whether the RUD has been - * aborted. Once the RUD transaction is constructed, it is the sole - * responsibility of the RUD to release the RUI (even if the RUI is - * aborted due to log I/O error). - */ - xfs_rui_release(rudp->rud_ruip); - kmem_zone_free(xfs_rud_zone, rudp); - - return (xfs_lsn_t)-1; -} - -/* - * The RUD dependency tracking op doesn't do squat. It can't because - * it doesn't know where the free extent is coming from. The dependency - * tracking has to be handled by the "enclosing" metadata object. For - * example, for inodes, the inode is locked throughout the extent freeing - * so the dependency should be recorded there. - */ -STATIC void -xfs_rud_item_committing( - struct xfs_log_item *lip, - xfs_lsn_t lsn) -{ -} - -/* - * This is the ops vector shared by all rud log items. - */ -static const struct xfs_item_ops xfs_rud_item_ops = { - .iop_size = xfs_rud_item_size, - .iop_format = xfs_rud_item_format, - .iop_pin = xfs_rud_item_pin, - .iop_unpin = xfs_rud_item_unpin, - .iop_unlock = xfs_rud_item_unlock, - .iop_committed = xfs_rud_item_committed, - .iop_push = xfs_rud_item_push, - .iop_committing = xfs_rud_item_committing, -}; - -/* - * Allocate and initialize an rud item with the given number of extents. - */ -struct xfs_rud_log_item * -xfs_rud_init( - struct xfs_mount *mp, - struct xfs_rui_log_item *ruip) - -{ - struct xfs_rud_log_item *rudp; - - rudp = kmem_zone_zalloc(xfs_rud_zone, KM_SLEEP); - xfs_log_item_init(mp, &rudp->rud_item, XFS_LI_RUD, &xfs_rud_item_ops); - rudp->rud_ruip = ruip; - rudp->rud_format.rud_rui_id = ruip->rui_format.rui_id; - - return rudp; -} - -/* - * Process an rmap update intent item that was recovered from the log. - * We need to update the rmapbt. - */ -int -xfs_rui_recover( - struct xfs_mount *mp, - struct xfs_rui_log_item *ruip) -{ - int i; - int error = 0; - struct xfs_map_extent *rmap; - xfs_fsblock_t startblock_fsb; - bool op_ok; - struct xfs_rud_log_item *rudp; - enum xfs_rmap_intent_type type; - int whichfork; - xfs_exntst_t state; - struct xfs_trans *tp; - struct xfs_btree_cur *rcur = NULL; - - ASSERT(!test_bit(XFS_RUI_RECOVERED, &ruip->rui_flags)); - - /* - * First check the validity of the extents described by the - * RUI. If any are bad, then assume that all are bad and - * just toss the RUI. - */ - for (i = 0; i < ruip->rui_format.rui_nextents; i++) { - rmap = &ruip->rui_format.rui_extents[i]; - startblock_fsb = XFS_BB_TO_FSB(mp, - XFS_FSB_TO_DADDR(mp, rmap->me_startblock)); - switch (rmap->me_flags & XFS_RMAP_EXTENT_TYPE_MASK) { - case XFS_RMAP_EXTENT_MAP: - case XFS_RMAP_EXTENT_MAP_SHARED: - case XFS_RMAP_EXTENT_UNMAP: - case XFS_RMAP_EXTENT_UNMAP_SHARED: - case XFS_RMAP_EXTENT_CONVERT: - case XFS_RMAP_EXTENT_CONVERT_SHARED: - case XFS_RMAP_EXTENT_ALLOC: - case XFS_RMAP_EXTENT_FREE: - op_ok = true; - break; - default: - op_ok = false; - break; - } - if (!op_ok || startblock_fsb == 0 || - rmap->me_len == 0 || - startblock_fsb >= mp->m_sb.sb_dblocks || - rmap->me_len >= mp->m_sb.sb_agblocks || - (rmap->me_flags & ~XFS_RMAP_EXTENT_FLAGS)) { - /* - * This will pull the RUI from the AIL and - * free the memory associated with it. - */ - set_bit(XFS_RUI_RECOVERED, &ruip->rui_flags); - xfs_rui_release(ruip); - return -EIO; - } - } - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp); - if (error) - return error; - rudp = xfs_trans_get_rud(tp, ruip); - - for (i = 0; i < ruip->rui_format.rui_nextents; i++) { - rmap = &ruip->rui_format.rui_extents[i]; - state = (rmap->me_flags & XFS_RMAP_EXTENT_UNWRITTEN) ? - XFS_EXT_UNWRITTEN : XFS_EXT_NORM; - whichfork = (rmap->me_flags & XFS_RMAP_EXTENT_ATTR_FORK) ? - XFS_ATTR_FORK : XFS_DATA_FORK; - switch (rmap->me_flags & XFS_RMAP_EXTENT_TYPE_MASK) { - case XFS_RMAP_EXTENT_MAP: - type = XFS_RMAP_MAP; - break; - case XFS_RMAP_EXTENT_MAP_SHARED: - type = XFS_RMAP_MAP_SHARED; - break; - case XFS_RMAP_EXTENT_UNMAP: - type = XFS_RMAP_UNMAP; - break; - case XFS_RMAP_EXTENT_UNMAP_SHARED: - type = XFS_RMAP_UNMAP_SHARED; - break; - case XFS_RMAP_EXTENT_CONVERT: - type = XFS_RMAP_CONVERT; - break; - case XFS_RMAP_EXTENT_CONVERT_SHARED: - type = XFS_RMAP_CONVERT_SHARED; - break; - case XFS_RMAP_EXTENT_ALLOC: - type = XFS_RMAP_ALLOC; - break; - case XFS_RMAP_EXTENT_FREE: - type = XFS_RMAP_FREE; - break; - default: - error = -EFSCORRUPTED; - goto abort_error; - } - error = xfs_trans_log_finish_rmap_update(tp, rudp, type, - rmap->me_owner, whichfork, - rmap->me_startoff, rmap->me_startblock, - rmap->me_len, state, &rcur); - if (error) - goto abort_error; - - } - - xfs_rmap_finish_one_cleanup(tp, rcur, error); - set_bit(XFS_RUI_RECOVERED, &ruip->rui_flags); - error = xfs_trans_commit(tp); - return error; - -abort_error: - xfs_rmap_finish_one_cleanup(tp, rcur, error); - xfs_trans_cancel(tp); - return error; -} diff --git a/src/linux/fs/xfs/xfs_rmap_item.h b/src/linux/fs/xfs/xfs_rmap_item.h deleted file mode 100644 index 340c968..0000000 --- a/src/linux/fs/xfs/xfs_rmap_item.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#ifndef __XFS_RMAP_ITEM_H__ -#define __XFS_RMAP_ITEM_H__ - -/* - * There are (currently) three pairs of rmap btree redo item types: map, unmap, - * and convert. The common abbreviations for these are RUI (rmap update - * intent) and RUD (rmap update done). The redo item type is encoded in the - * flags field of each xfs_map_extent. - * - * *I items should be recorded in the *first* of a series of rolled - * transactions, and the *D items should be recorded in the same transaction - * that records the associated rmapbt updates. Typically, the first - * transaction will record a bmbt update, followed by some number of - * transactions containing rmapbt updates, and finally transactions with any - * bnobt/cntbt updates. - * - * Should the system crash after the commit of the first transaction but - * before the commit of the final transaction in a series, log recovery will - * use the redo information recorded by the intent items to replay the - * (rmapbt/bnobt/cntbt) metadata updates in the non-first transaction. - */ - -/* kernel only RUI/RUD definitions */ - -struct xfs_mount; -struct kmem_zone; - -/* - * Max number of extents in fast allocation path. - */ -#define XFS_RUI_MAX_FAST_EXTENTS 16 - -/* - * Define RUI flag bits. Manipulated by set/clear/test_bit operators. - */ -#define XFS_RUI_RECOVERED 1 - -/* - * This is the "rmap update intent" log item. It is used to log the fact that - * some reverse mappings need to change. It is used in conjunction with the - * "rmap update done" log item described below. - * - * These log items follow the same rules as struct xfs_efi_log_item; see the - * comments about that structure (in xfs_extfree_item.h) for more details. - */ -struct xfs_rui_log_item { - struct xfs_log_item rui_item; - atomic_t rui_refcount; - atomic_t rui_next_extent; - unsigned long rui_flags; /* misc flags */ - struct xfs_rui_log_format rui_format; -}; - -static inline size_t -xfs_rui_log_item_sizeof( - unsigned int nr) -{ - return offsetof(struct xfs_rui_log_item, rui_format) + - xfs_rui_log_format_sizeof(nr); -} - -/* - * This is the "rmap update done" log item. It is used to log the fact that - * some rmapbt updates mentioned in an earlier rui item have been performed. - */ -struct xfs_rud_log_item { - struct xfs_log_item rud_item; - struct xfs_rui_log_item *rud_ruip; - struct xfs_rud_log_format rud_format; -}; - -extern struct kmem_zone *xfs_rui_zone; -extern struct kmem_zone *xfs_rud_zone; - -struct xfs_rui_log_item *xfs_rui_init(struct xfs_mount *, uint); -struct xfs_rud_log_item *xfs_rud_init(struct xfs_mount *, - struct xfs_rui_log_item *); -int xfs_rui_copy_format(struct xfs_log_iovec *buf, - struct xfs_rui_log_format *dst_rui_fmt); -void xfs_rui_item_free(struct xfs_rui_log_item *); -void xfs_rui_release(struct xfs_rui_log_item *); -int xfs_rui_recover(struct xfs_mount *mp, struct xfs_rui_log_item *ruip); - -#endif /* __XFS_RMAP_ITEM_H__ */ diff --git a/src/linux/fs/xfs/xfs_rtalloc.h b/src/linux/fs/xfs/xfs_rtalloc.h deleted file mode 100644 index 355dd9e..0000000 --- a/src/linux/fs/xfs/xfs_rtalloc.h +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_RTALLOC_H__ -#define __XFS_RTALLOC_H__ - -/* kernel only definitions and functions */ - -struct xfs_mount; -struct xfs_trans; - -#ifdef CONFIG_XFS_RT -/* - * Function prototypes for exported functions. - */ - -/* - * Allocate an extent in the realtime subvolume, with the usual allocation - * parameters. The length units are all in realtime extents, as is the - * result block number. - */ -int /* error */ -xfs_rtallocate_extent( - struct xfs_trans *tp, /* transaction pointer */ - xfs_rtblock_t bno, /* starting block number to allocate */ - xfs_extlen_t minlen, /* minimum length to allocate */ - xfs_extlen_t maxlen, /* maximum length to allocate */ - xfs_extlen_t *len, /* out: actual length allocated */ - xfs_alloctype_t type, /* allocation type XFS_ALLOCTYPE... */ - int wasdel, /* was a delayed allocation extent */ - xfs_extlen_t prod, /* extent product factor */ - xfs_rtblock_t *rtblock); /* out: start block allocated */ - -/* - * Free an extent in the realtime subvolume. Length is expressed in - * realtime extents, as is the block number. - */ -int /* error */ -xfs_rtfree_extent( - struct xfs_trans *tp, /* transaction pointer */ - xfs_rtblock_t bno, /* starting block number to free */ - xfs_extlen_t len); /* length of extent freed */ - -/* - * Initialize realtime fields in the mount structure. - */ -int /* error */ -xfs_rtmount_init( - struct xfs_mount *mp); /* file system mount structure */ -void -xfs_rtunmount_inodes( - struct xfs_mount *mp); - -/* - * Get the bitmap and summary inodes into the mount structure - * at mount time. - */ -int /* error */ -xfs_rtmount_inodes( - struct xfs_mount *mp); /* file system mount structure */ - -/* - * Pick an extent for allocation at the start of a new realtime file. - * Use the sequence number stored in the atime field of the bitmap inode. - * Translate this to a fraction of the rtextents, and return the product - * of rtextents and the fraction. - * The fraction sequence is 0, 1/2, 1/4, 3/4, 1/8, ..., 7/8, 1/16, ... - */ -int /* error */ -xfs_rtpick_extent( - struct xfs_mount *mp, /* file system mount point */ - struct xfs_trans *tp, /* transaction pointer */ - xfs_extlen_t len, /* allocation length (rtextents) */ - xfs_rtblock_t *pick); /* result rt extent */ - -/* - * Grow the realtime area of the filesystem. - */ -int -xfs_growfs_rt( - struct xfs_mount *mp, /* file system mount structure */ - xfs_growfs_rt_t *in); /* user supplied growfs struct */ - -/* - * From xfs_rtbitmap.c - */ -int xfs_rtcheck_range(struct xfs_mount *mp, struct xfs_trans *tp, - xfs_rtblock_t start, xfs_extlen_t len, int val, - xfs_rtblock_t *new, int *stat); -int xfs_rtfind_back(struct xfs_mount *mp, struct xfs_trans *tp, - xfs_rtblock_t start, xfs_rtblock_t limit, - xfs_rtblock_t *rtblock); -int xfs_rtfind_forw(struct xfs_mount *mp, struct xfs_trans *tp, - xfs_rtblock_t start, xfs_rtblock_t limit, - xfs_rtblock_t *rtblock); -int xfs_rtmodify_range(struct xfs_mount *mp, struct xfs_trans *tp, - xfs_rtblock_t start, xfs_extlen_t len, int val); -int xfs_rtmodify_summary_int(struct xfs_mount *mp, struct xfs_trans *tp, - int log, xfs_rtblock_t bbno, int delta, - xfs_buf_t **rbpp, xfs_fsblock_t *rsb, - xfs_suminfo_t *sum); -int xfs_rtmodify_summary(struct xfs_mount *mp, struct xfs_trans *tp, int log, - xfs_rtblock_t bbno, int delta, xfs_buf_t **rbpp, - xfs_fsblock_t *rsb); -int xfs_rtfree_range(struct xfs_mount *mp, struct xfs_trans *tp, - xfs_rtblock_t start, xfs_extlen_t len, - struct xfs_buf **rbpp, xfs_fsblock_t *rsb); - - -#else -# define xfs_rtallocate_extent(t,b,min,max,l,a,f,p,rb) (ENOSYS) -# define xfs_rtfree_extent(t,b,l) (ENOSYS) -# define xfs_rtpick_extent(m,t,l,rb) (ENOSYS) -# define xfs_growfs_rt(mp,in) (ENOSYS) -static inline int /* error */ -xfs_rtmount_init( - xfs_mount_t *mp) /* file system mount structure */ -{ - if (mp->m_sb.sb_rblocks == 0) - return 0; - - xfs_warn(mp, "Not built with CONFIG_XFS_RT"); - return -ENOSYS; -} -# define xfs_rtmount_inodes(m) (((mp)->m_sb.sb_rblocks == 0)? 0 : (ENOSYS)) -# define xfs_rtunmount_inodes(m) -#endif /* CONFIG_XFS_RT */ - -#endif /* __XFS_RTALLOC_H__ */ diff --git a/src/linux/fs/xfs/xfs_stats.c b/src/linux/fs/xfs/xfs_stats.c deleted file mode 100644 index 12d48cd..0000000 --- a/src/linux/fs/xfs/xfs_stats.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include - -struct xstats xfsstats; - -static int counter_val(struct xfsstats __percpu *stats, int idx) -{ - int val = 0, cpu; - - for_each_possible_cpu(cpu) - val += *(((__u32 *)per_cpu_ptr(stats, cpu) + idx)); - return val; -} - -int xfs_stats_format(struct xfsstats __percpu *stats, char *buf) -{ - int i, j; - int len = 0; - __uint64_t xs_xstrat_bytes = 0; - __uint64_t xs_write_bytes = 0; - __uint64_t xs_read_bytes = 0; - - static const struct xstats_entry { - char *desc; - int endpoint; - } xstats[] = { - { "extent_alloc", XFSSTAT_END_EXTENT_ALLOC }, - { "abt", XFSSTAT_END_ALLOC_BTREE }, - { "blk_map", XFSSTAT_END_BLOCK_MAPPING }, - { "bmbt", XFSSTAT_END_BLOCK_MAP_BTREE }, - { "dir", XFSSTAT_END_DIRECTORY_OPS }, - { "trans", XFSSTAT_END_TRANSACTIONS }, - { "ig", XFSSTAT_END_INODE_OPS }, - { "log", XFSSTAT_END_LOG_OPS }, - { "push_ail", XFSSTAT_END_TAIL_PUSHING }, - { "xstrat", XFSSTAT_END_WRITE_CONVERT }, - { "rw", XFSSTAT_END_READ_WRITE_OPS }, - { "attr", XFSSTAT_END_ATTRIBUTE_OPS }, - { "icluster", XFSSTAT_END_INODE_CLUSTER }, - { "vnodes", XFSSTAT_END_VNODE_OPS }, - { "buf", XFSSTAT_END_BUF }, - { "abtb2", XFSSTAT_END_ABTB_V2 }, - { "abtc2", XFSSTAT_END_ABTC_V2 }, - { "bmbt2", XFSSTAT_END_BMBT_V2 }, - { "ibt2", XFSSTAT_END_IBT_V2 }, - { "fibt2", XFSSTAT_END_FIBT_V2 }, - { "rmapbt", XFSSTAT_END_RMAP_V2 }, - { "refcntbt", XFSSTAT_END_REFCOUNT }, - /* we print both series of quota information together */ - { "qm", XFSSTAT_END_QM }, - }; - - /* Loop over all stats groups */ - - for (i = j = 0; i < ARRAY_SIZE(xstats); i++) { - len += snprintf(buf + len, PATH_MAX - len, "%s", - xstats[i].desc); - /* inner loop does each group */ - for (; j < xstats[i].endpoint; j++) - len += snprintf(buf + len, PATH_MAX - len, " %u", - counter_val(stats, j)); - len += snprintf(buf + len, PATH_MAX - len, "\n"); - } - /* extra precision counters */ - for_each_possible_cpu(i) { - xs_xstrat_bytes += per_cpu_ptr(stats, i)->xs_xstrat_bytes; - xs_write_bytes += per_cpu_ptr(stats, i)->xs_write_bytes; - xs_read_bytes += per_cpu_ptr(stats, i)->xs_read_bytes; - } - - len += snprintf(buf + len, PATH_MAX-len, "xpc %Lu %Lu %Lu\n", - xs_xstrat_bytes, xs_write_bytes, xs_read_bytes); - len += snprintf(buf + len, PATH_MAX-len, "debug %u\n", -#if defined(DEBUG) - 1); -#else - 0); -#endif - - return len; -} - -void xfs_stats_clearall(struct xfsstats __percpu *stats) -{ - int c; - __uint32_t vn_active; - - xfs_notice(NULL, "Clearing xfsstats"); - for_each_possible_cpu(c) { - preempt_disable(); - /* save vn_active, it's a universal truth! */ - vn_active = per_cpu_ptr(stats, c)->vn_active; - memset(per_cpu_ptr(stats, c), 0, sizeof(*stats)); - per_cpu_ptr(stats, c)->vn_active = vn_active; - preempt_enable(); - } -} - -/* legacy quota interfaces */ -#ifdef CONFIG_XFS_QUOTA -static int xqm_proc_show(struct seq_file *m, void *v) -{ - /* maximum; incore; ratio free to inuse; freelist */ - seq_printf(m, "%d\t%d\t%d\t%u\n", - 0, counter_val(xfsstats.xs_stats, XFSSTAT_END_XQMSTAT), - 0, counter_val(xfsstats.xs_stats, XFSSTAT_END_XQMSTAT + 1)); - return 0; -} - -static int xqm_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, xqm_proc_show, NULL); -} - -static const struct file_operations xqm_proc_fops = { - .open = xqm_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -/* legacy quota stats interface no 2 */ -static int xqmstat_proc_show(struct seq_file *m, void *v) -{ - int j; - - seq_printf(m, "qm"); - for (j = XFSSTAT_END_IBT_V2; j < XFSSTAT_END_XQMSTAT; j++) - seq_printf(m, " %u", counter_val(xfsstats.xs_stats, j)); - seq_putc(m, '\n'); - return 0; -} - -static int xqmstat_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, xqmstat_proc_show, NULL); -} - -static const struct file_operations xqmstat_proc_fops = { - .owner = THIS_MODULE, - .open = xqmstat_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -#endif /* CONFIG_XFS_QUOTA */ - -#ifdef CONFIG_PROC_FS -int -xfs_init_procfs(void) -{ - if (!proc_mkdir("fs/xfs", NULL)) - return -ENOMEM; - - if (!proc_symlink("fs/xfs/stat", NULL, - "/sys/fs/xfs/stats/stats")) - goto out; - -#ifdef CONFIG_XFS_QUOTA - if (!proc_create("fs/xfs/xqmstat", 0, NULL, - &xqmstat_proc_fops)) - goto out; - if (!proc_create("fs/xfs/xqm", 0, NULL, - &xqm_proc_fops)) - goto out; -#endif - return 0; - -out: - remove_proc_subtree("fs/xfs", NULL); - return -ENOMEM; -} - -void -xfs_cleanup_procfs(void) -{ - remove_proc_subtree("fs/xfs", NULL); -} -#endif /* CONFIG_PROC_FS */ diff --git a/src/linux/fs/xfs/xfs_stats.h b/src/linux/fs/xfs/xfs_stats.h deleted file mode 100644 index 79ad2e6..0000000 --- a/src/linux/fs/xfs/xfs_stats.h +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (c) 2000,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_STATS_H__ -#define __XFS_STATS_H__ - - -#include - -/* - * XFS global statistics - */ -struct xfsstats { -# define XFSSTAT_END_EXTENT_ALLOC 4 - __uint32_t xs_allocx; - __uint32_t xs_allocb; - __uint32_t xs_freex; - __uint32_t xs_freeb; -# define XFSSTAT_END_ALLOC_BTREE (XFSSTAT_END_EXTENT_ALLOC+4) - __uint32_t xs_abt_lookup; - __uint32_t xs_abt_compare; - __uint32_t xs_abt_insrec; - __uint32_t xs_abt_delrec; -# define XFSSTAT_END_BLOCK_MAPPING (XFSSTAT_END_ALLOC_BTREE+7) - __uint32_t xs_blk_mapr; - __uint32_t xs_blk_mapw; - __uint32_t xs_blk_unmap; - __uint32_t xs_add_exlist; - __uint32_t xs_del_exlist; - __uint32_t xs_look_exlist; - __uint32_t xs_cmp_exlist; -# define XFSSTAT_END_BLOCK_MAP_BTREE (XFSSTAT_END_BLOCK_MAPPING+4) - __uint32_t xs_bmbt_lookup; - __uint32_t xs_bmbt_compare; - __uint32_t xs_bmbt_insrec; - __uint32_t xs_bmbt_delrec; -# define XFSSTAT_END_DIRECTORY_OPS (XFSSTAT_END_BLOCK_MAP_BTREE+4) - __uint32_t xs_dir_lookup; - __uint32_t xs_dir_create; - __uint32_t xs_dir_remove; - __uint32_t xs_dir_getdents; -# define XFSSTAT_END_TRANSACTIONS (XFSSTAT_END_DIRECTORY_OPS+3) - __uint32_t xs_trans_sync; - __uint32_t xs_trans_async; - __uint32_t xs_trans_empty; -# define XFSSTAT_END_INODE_OPS (XFSSTAT_END_TRANSACTIONS+7) - __uint32_t xs_ig_attempts; - __uint32_t xs_ig_found; - __uint32_t xs_ig_frecycle; - __uint32_t xs_ig_missed; - __uint32_t xs_ig_dup; - __uint32_t xs_ig_reclaims; - __uint32_t xs_ig_attrchg; -# define XFSSTAT_END_LOG_OPS (XFSSTAT_END_INODE_OPS+5) - __uint32_t xs_log_writes; - __uint32_t xs_log_blocks; - __uint32_t xs_log_noiclogs; - __uint32_t xs_log_force; - __uint32_t xs_log_force_sleep; -# define XFSSTAT_END_TAIL_PUSHING (XFSSTAT_END_LOG_OPS+10) - __uint32_t xs_try_logspace; - __uint32_t xs_sleep_logspace; - __uint32_t xs_push_ail; - __uint32_t xs_push_ail_success; - __uint32_t xs_push_ail_pushbuf; - __uint32_t xs_push_ail_pinned; - __uint32_t xs_push_ail_locked; - __uint32_t xs_push_ail_flushing; - __uint32_t xs_push_ail_restarts; - __uint32_t xs_push_ail_flush; -# define XFSSTAT_END_WRITE_CONVERT (XFSSTAT_END_TAIL_PUSHING+2) - __uint32_t xs_xstrat_quick; - __uint32_t xs_xstrat_split; -# define XFSSTAT_END_READ_WRITE_OPS (XFSSTAT_END_WRITE_CONVERT+2) - __uint32_t xs_write_calls; - __uint32_t xs_read_calls; -# define XFSSTAT_END_ATTRIBUTE_OPS (XFSSTAT_END_READ_WRITE_OPS+4) - __uint32_t xs_attr_get; - __uint32_t xs_attr_set; - __uint32_t xs_attr_remove; - __uint32_t xs_attr_list; -# define XFSSTAT_END_INODE_CLUSTER (XFSSTAT_END_ATTRIBUTE_OPS+3) - __uint32_t xs_iflush_count; - __uint32_t xs_icluster_flushcnt; - __uint32_t xs_icluster_flushinode; -# define XFSSTAT_END_VNODE_OPS (XFSSTAT_END_INODE_CLUSTER+8) - __uint32_t vn_active; /* # vnodes not on free lists */ - __uint32_t vn_alloc; /* # times vn_alloc called */ - __uint32_t vn_get; /* # times vn_get called */ - __uint32_t vn_hold; /* # times vn_hold called */ - __uint32_t vn_rele; /* # times vn_rele called */ - __uint32_t vn_reclaim; /* # times vn_reclaim called */ - __uint32_t vn_remove; /* # times vn_remove called */ - __uint32_t vn_free; /* # times vn_free called */ -#define XFSSTAT_END_BUF (XFSSTAT_END_VNODE_OPS+9) - __uint32_t xb_get; - __uint32_t xb_create; - __uint32_t xb_get_locked; - __uint32_t xb_get_locked_waited; - __uint32_t xb_busy_locked; - __uint32_t xb_miss_locked; - __uint32_t xb_page_retries; - __uint32_t xb_page_found; - __uint32_t xb_get_read; -/* Version 2 btree counters */ -#define XFSSTAT_END_ABTB_V2 (XFSSTAT_END_BUF+15) - __uint32_t xs_abtb_2_lookup; - __uint32_t xs_abtb_2_compare; - __uint32_t xs_abtb_2_insrec; - __uint32_t xs_abtb_2_delrec; - __uint32_t xs_abtb_2_newroot; - __uint32_t xs_abtb_2_killroot; - __uint32_t xs_abtb_2_increment; - __uint32_t xs_abtb_2_decrement; - __uint32_t xs_abtb_2_lshift; - __uint32_t xs_abtb_2_rshift; - __uint32_t xs_abtb_2_split; - __uint32_t xs_abtb_2_join; - __uint32_t xs_abtb_2_alloc; - __uint32_t xs_abtb_2_free; - __uint32_t xs_abtb_2_moves; -#define XFSSTAT_END_ABTC_V2 (XFSSTAT_END_ABTB_V2+15) - __uint32_t xs_abtc_2_lookup; - __uint32_t xs_abtc_2_compare; - __uint32_t xs_abtc_2_insrec; - __uint32_t xs_abtc_2_delrec; - __uint32_t xs_abtc_2_newroot; - __uint32_t xs_abtc_2_killroot; - __uint32_t xs_abtc_2_increment; - __uint32_t xs_abtc_2_decrement; - __uint32_t xs_abtc_2_lshift; - __uint32_t xs_abtc_2_rshift; - __uint32_t xs_abtc_2_split; - __uint32_t xs_abtc_2_join; - __uint32_t xs_abtc_2_alloc; - __uint32_t xs_abtc_2_free; - __uint32_t xs_abtc_2_moves; -#define XFSSTAT_END_BMBT_V2 (XFSSTAT_END_ABTC_V2+15) - __uint32_t xs_bmbt_2_lookup; - __uint32_t xs_bmbt_2_compare; - __uint32_t xs_bmbt_2_insrec; - __uint32_t xs_bmbt_2_delrec; - __uint32_t xs_bmbt_2_newroot; - __uint32_t xs_bmbt_2_killroot; - __uint32_t xs_bmbt_2_increment; - __uint32_t xs_bmbt_2_decrement; - __uint32_t xs_bmbt_2_lshift; - __uint32_t xs_bmbt_2_rshift; - __uint32_t xs_bmbt_2_split; - __uint32_t xs_bmbt_2_join; - __uint32_t xs_bmbt_2_alloc; - __uint32_t xs_bmbt_2_free; - __uint32_t xs_bmbt_2_moves; -#define XFSSTAT_END_IBT_V2 (XFSSTAT_END_BMBT_V2+15) - __uint32_t xs_ibt_2_lookup; - __uint32_t xs_ibt_2_compare; - __uint32_t xs_ibt_2_insrec; - __uint32_t xs_ibt_2_delrec; - __uint32_t xs_ibt_2_newroot; - __uint32_t xs_ibt_2_killroot; - __uint32_t xs_ibt_2_increment; - __uint32_t xs_ibt_2_decrement; - __uint32_t xs_ibt_2_lshift; - __uint32_t xs_ibt_2_rshift; - __uint32_t xs_ibt_2_split; - __uint32_t xs_ibt_2_join; - __uint32_t xs_ibt_2_alloc; - __uint32_t xs_ibt_2_free; - __uint32_t xs_ibt_2_moves; -#define XFSSTAT_END_FIBT_V2 (XFSSTAT_END_IBT_V2+15) - __uint32_t xs_fibt_2_lookup; - __uint32_t xs_fibt_2_compare; - __uint32_t xs_fibt_2_insrec; - __uint32_t xs_fibt_2_delrec; - __uint32_t xs_fibt_2_newroot; - __uint32_t xs_fibt_2_killroot; - __uint32_t xs_fibt_2_increment; - __uint32_t xs_fibt_2_decrement; - __uint32_t xs_fibt_2_lshift; - __uint32_t xs_fibt_2_rshift; - __uint32_t xs_fibt_2_split; - __uint32_t xs_fibt_2_join; - __uint32_t xs_fibt_2_alloc; - __uint32_t xs_fibt_2_free; - __uint32_t xs_fibt_2_moves; -#define XFSSTAT_END_RMAP_V2 (XFSSTAT_END_FIBT_V2+15) - __uint32_t xs_rmap_2_lookup; - __uint32_t xs_rmap_2_compare; - __uint32_t xs_rmap_2_insrec; - __uint32_t xs_rmap_2_delrec; - __uint32_t xs_rmap_2_newroot; - __uint32_t xs_rmap_2_killroot; - __uint32_t xs_rmap_2_increment; - __uint32_t xs_rmap_2_decrement; - __uint32_t xs_rmap_2_lshift; - __uint32_t xs_rmap_2_rshift; - __uint32_t xs_rmap_2_split; - __uint32_t xs_rmap_2_join; - __uint32_t xs_rmap_2_alloc; - __uint32_t xs_rmap_2_free; - __uint32_t xs_rmap_2_moves; -#define XFSSTAT_END_REFCOUNT (XFSSTAT_END_RMAP_V2 + 15) - __uint32_t xs_refcbt_2_lookup; - __uint32_t xs_refcbt_2_compare; - __uint32_t xs_refcbt_2_insrec; - __uint32_t xs_refcbt_2_delrec; - __uint32_t xs_refcbt_2_newroot; - __uint32_t xs_refcbt_2_killroot; - __uint32_t xs_refcbt_2_increment; - __uint32_t xs_refcbt_2_decrement; - __uint32_t xs_refcbt_2_lshift; - __uint32_t xs_refcbt_2_rshift; - __uint32_t xs_refcbt_2_split; - __uint32_t xs_refcbt_2_join; - __uint32_t xs_refcbt_2_alloc; - __uint32_t xs_refcbt_2_free; - __uint32_t xs_refcbt_2_moves; -#define XFSSTAT_END_XQMSTAT (XFSSTAT_END_REFCOUNT + 6) - __uint32_t xs_qm_dqreclaims; - __uint32_t xs_qm_dqreclaim_misses; - __uint32_t xs_qm_dquot_dups; - __uint32_t xs_qm_dqcachemisses; - __uint32_t xs_qm_dqcachehits; - __uint32_t xs_qm_dqwants; -#define XFSSTAT_END_QM (XFSSTAT_END_XQMSTAT+2) - __uint32_t xs_qm_dquot; - __uint32_t xs_qm_dquot_unused; -/* Extra precision counters */ - __uint64_t xs_xstrat_bytes; - __uint64_t xs_write_bytes; - __uint64_t xs_read_bytes; -}; - -int xfs_stats_format(struct xfsstats __percpu *stats, char *buf); -void xfs_stats_clearall(struct xfsstats __percpu *stats); -extern struct xstats xfsstats; - -#define XFS_STATS_INC(mp, v) \ -do { \ - per_cpu_ptr(xfsstats.xs_stats, current_cpu())->v++; \ - per_cpu_ptr(mp->m_stats.xs_stats, current_cpu())->v++; \ -} while (0) - -#define XFS_STATS_DEC(mp, v) \ -do { \ - per_cpu_ptr(xfsstats.xs_stats, current_cpu())->v--; \ - per_cpu_ptr(mp->m_stats.xs_stats, current_cpu())->v--; \ -} while (0) - -#define XFS_STATS_ADD(mp, v, inc) \ -do { \ - per_cpu_ptr(xfsstats.xs_stats, current_cpu())->v += (inc); \ - per_cpu_ptr(mp->m_stats.xs_stats, current_cpu())->v += (inc); \ -} while (0) - -#if defined(CONFIG_PROC_FS) - -extern int xfs_init_procfs(void); -extern void xfs_cleanup_procfs(void); - - -#else /* !CONFIG_PROC_FS */ - -static inline int xfs_init_procfs(void) -{ - return 0; -} - -static inline void xfs_cleanup_procfs(void) -{ -} - -#endif /* !CONFIG_PROC_FS */ - -#endif /* __XFS_STATS_H__ */ diff --git a/src/linux/fs/xfs/xfs_super.c b/src/linux/fs/xfs/xfs_super.c deleted file mode 100644 index ade4691..0000000 --- a/src/linux/fs/xfs/xfs_super.c +++ /dev/null @@ -1,2090 +0,0 @@ -/* - * Copyright (c) 2000-2006 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "xfs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_sb.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_inode.h" -#include "xfs_btree.h" -#include "xfs_bmap.h" -#include "xfs_alloc.h" -#include "xfs_error.h" -#include "xfs_fsops.h" -#include "xfs_trans.h" -#include "xfs_buf_item.h" -#include "xfs_log.h" -#include "xfs_log_priv.h" -#include "xfs_da_btree.h" -#include "xfs_dir2.h" -#include "xfs_extfree_item.h" -#include "xfs_mru_cache.h" -#include "xfs_inode_item.h" -#include "xfs_icache.h" -#include "xfs_trace.h" -#include "xfs_icreate_item.h" -#include "xfs_filestream.h" -#include "xfs_quota.h" -#include "xfs_sysfs.h" -#include "xfs_ondisk.h" -#include "xfs_rmap_item.h" -#include "xfs_refcount_item.h" -#include "xfs_bmap_item.h" -#include "xfs_reflink.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static const struct super_operations xfs_super_operations; -struct bio_set *xfs_ioend_bioset; - -static struct kset *xfs_kset; /* top-level xfs sysfs dir */ -#ifdef DEBUG -static struct xfs_kobj xfs_dbg_kobj; /* global debug sysfs attrs */ -#endif - -/* - * Table driven mount option parser. - */ -enum { - Opt_logbufs, Opt_logbsize, Opt_logdev, Opt_rtdev, Opt_biosize, - Opt_wsync, Opt_noalign, Opt_swalloc, Opt_sunit, Opt_swidth, Opt_nouuid, - Opt_mtpt, Opt_grpid, Opt_nogrpid, Opt_bsdgroups, Opt_sysvgroups, - Opt_allocsize, Opt_norecovery, Opt_barrier, Opt_nobarrier, - Opt_inode64, Opt_inode32, Opt_ikeep, Opt_noikeep, - Opt_largeio, Opt_nolargeio, Opt_attr2, Opt_noattr2, Opt_filestreams, - Opt_quota, Opt_noquota, Opt_usrquota, Opt_grpquota, Opt_prjquota, - Opt_uquota, Opt_gquota, Opt_pquota, - Opt_uqnoenforce, Opt_gqnoenforce, Opt_pqnoenforce, Opt_qnoenforce, - Opt_discard, Opt_nodiscard, Opt_dax, Opt_err, -}; - -static const match_table_t tokens = { - {Opt_logbufs, "logbufs=%u"}, /* number of XFS log buffers */ - {Opt_logbsize, "logbsize=%s"}, /* size of XFS log buffers */ - {Opt_logdev, "logdev=%s"}, /* log device */ - {Opt_rtdev, "rtdev=%s"}, /* realtime I/O device */ - {Opt_biosize, "biosize=%u"}, /* log2 of preferred buffered io size */ - {Opt_wsync, "wsync"}, /* safe-mode nfs compatible mount */ - {Opt_noalign, "noalign"}, /* turn off stripe alignment */ - {Opt_swalloc, "swalloc"}, /* turn on stripe width allocation */ - {Opt_sunit, "sunit=%u"}, /* data volume stripe unit */ - {Opt_swidth, "swidth=%u"}, /* data volume stripe width */ - {Opt_nouuid, "nouuid"}, /* ignore filesystem UUID */ - {Opt_mtpt, "mtpt"}, /* filesystem mount point */ - {Opt_grpid, "grpid"}, /* group-ID from parent directory */ - {Opt_nogrpid, "nogrpid"}, /* group-ID from current process */ - {Opt_bsdgroups, "bsdgroups"}, /* group-ID from parent directory */ - {Opt_sysvgroups,"sysvgroups"}, /* group-ID from current process */ - {Opt_allocsize, "allocsize=%s"},/* preferred allocation size */ - {Opt_norecovery,"norecovery"}, /* don't run XFS recovery */ - {Opt_barrier, "barrier"}, /* use writer barriers for log write and - * unwritten extent conversion */ - {Opt_nobarrier, "nobarrier"}, /* .. disable */ - {Opt_inode64, "inode64"}, /* inodes can be allocated anywhere */ - {Opt_inode32, "inode32"}, /* inode allocation limited to - * XFS_MAXINUMBER_32 */ - {Opt_ikeep, "ikeep"}, /* do not free empty inode clusters */ - {Opt_noikeep, "noikeep"}, /* free empty inode clusters */ - {Opt_largeio, "largeio"}, /* report large I/O sizes in stat() */ - {Opt_nolargeio, "nolargeio"}, /* do not report large I/O sizes - * in stat(). */ - {Opt_attr2, "attr2"}, /* do use attr2 attribute format */ - {Opt_noattr2, "noattr2"}, /* do not use attr2 attribute format */ - {Opt_filestreams,"filestreams"},/* use filestreams allocator */ - {Opt_quota, "quota"}, /* disk quotas (user) */ - {Opt_noquota, "noquota"}, /* no quotas */ - {Opt_usrquota, "usrquota"}, /* user quota enabled */ - {Opt_grpquota, "grpquota"}, /* group quota enabled */ - {Opt_prjquota, "prjquota"}, /* project quota enabled */ - {Opt_uquota, "uquota"}, /* user quota (IRIX variant) */ - {Opt_gquota, "gquota"}, /* group quota (IRIX variant) */ - {Opt_pquota, "pquota"}, /* project quota (IRIX variant) */ - {Opt_uqnoenforce,"uqnoenforce"},/* user quota limit enforcement */ - {Opt_gqnoenforce,"gqnoenforce"},/* group quota limit enforcement */ - {Opt_pqnoenforce,"pqnoenforce"},/* project quota limit enforcement */ - {Opt_qnoenforce, "qnoenforce"}, /* same as uqnoenforce */ - {Opt_discard, "discard"}, /* Discard unused blocks */ - {Opt_nodiscard, "nodiscard"}, /* Do not discard unused blocks */ - - {Opt_dax, "dax"}, /* Enable direct access to bdev pages */ - {Opt_err, NULL}, -}; - - -STATIC int -suffix_kstrtoint(const substring_t *s, unsigned int base, int *res) -{ - int last, shift_left_factor = 0, _res; - char *value; - int ret = 0; - - value = match_strdup(s); - if (!value) - return -ENOMEM; - - last = strlen(value) - 1; - if (value[last] == 'K' || value[last] == 'k') { - shift_left_factor = 10; - value[last] = '\0'; - } - if (value[last] == 'M' || value[last] == 'm') { - shift_left_factor = 20; - value[last] = '\0'; - } - if (value[last] == 'G' || value[last] == 'g') { - shift_left_factor = 30; - value[last] = '\0'; - } - - if (kstrtoint(value, base, &_res)) - ret = -EINVAL; - kfree(value); - *res = _res << shift_left_factor; - return ret; -} - -/* - * This function fills in xfs_mount_t fields based on mount args. - * Note: the superblock has _not_ yet been read in. - * - * Note that this function leaks the various device name allocations on - * failure. The caller takes care of them. - * - * *sb is const because this is also used to test options on the remount - * path, and we don't want this to have any side effects at remount time. - * Today this function does not change *sb, but just to future-proof... - */ -STATIC int -xfs_parseargs( - struct xfs_mount *mp, - char *options) -{ - const struct super_block *sb = mp->m_super; - char *p; - substring_t args[MAX_OPT_ARGS]; - int dsunit = 0; - int dswidth = 0; - int iosize = 0; - __uint8_t iosizelog = 0; - - /* - * set up the mount name first so all the errors will refer to the - * correct device. - */ - mp->m_fsname = kstrndup(sb->s_id, MAXNAMELEN, GFP_KERNEL); - if (!mp->m_fsname) - return -ENOMEM; - mp->m_fsname_len = strlen(mp->m_fsname) + 1; - - /* - * Copy binary VFS mount flags we are interested in. - */ - if (sb->s_flags & MS_RDONLY) - mp->m_flags |= XFS_MOUNT_RDONLY; - if (sb->s_flags & MS_DIRSYNC) - mp->m_flags |= XFS_MOUNT_DIRSYNC; - if (sb->s_flags & MS_SYNCHRONOUS) - mp->m_flags |= XFS_MOUNT_WSYNC; - - /* - * Set some default flags that could be cleared by the mount option - * parsing. - */ - mp->m_flags |= XFS_MOUNT_BARRIER; - mp->m_flags |= XFS_MOUNT_COMPAT_IOSIZE; - - /* - * These can be overridden by the mount option parsing. - */ - mp->m_logbufs = -1; - mp->m_logbsize = -1; - - if (!options) - goto done; - - while ((p = strsep(&options, ",")) != NULL) { - int token; - - if (!*p) - continue; - - token = match_token(p, tokens, args); - switch (token) { - case Opt_logbufs: - if (match_int(args, &mp->m_logbufs)) - return -EINVAL; - break; - case Opt_logbsize: - if (suffix_kstrtoint(args, 10, &mp->m_logbsize)) - return -EINVAL; - break; - case Opt_logdev: - mp->m_logname = match_strdup(args); - if (!mp->m_logname) - return -ENOMEM; - break; - case Opt_mtpt: - xfs_warn(mp, "%s option not allowed on this system", p); - return -EINVAL; - case Opt_rtdev: - mp->m_rtname = match_strdup(args); - if (!mp->m_rtname) - return -ENOMEM; - break; - case Opt_allocsize: - case Opt_biosize: - if (suffix_kstrtoint(args, 10, &iosize)) - return -EINVAL; - iosizelog = ffs(iosize) - 1; - break; - case Opt_grpid: - case Opt_bsdgroups: - mp->m_flags |= XFS_MOUNT_GRPID; - break; - case Opt_nogrpid: - case Opt_sysvgroups: - mp->m_flags &= ~XFS_MOUNT_GRPID; - break; - case Opt_wsync: - mp->m_flags |= XFS_MOUNT_WSYNC; - break; - case Opt_norecovery: - mp->m_flags |= XFS_MOUNT_NORECOVERY; - break; - case Opt_noalign: - mp->m_flags |= XFS_MOUNT_NOALIGN; - break; - case Opt_swalloc: - mp->m_flags |= XFS_MOUNT_SWALLOC; - break; - case Opt_sunit: - if (match_int(args, &dsunit)) - return -EINVAL; - break; - case Opt_swidth: - if (match_int(args, &dswidth)) - return -EINVAL; - break; - case Opt_inode32: - mp->m_flags |= XFS_MOUNT_SMALL_INUMS; - break; - case Opt_inode64: - mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS; - break; - case Opt_nouuid: - mp->m_flags |= XFS_MOUNT_NOUUID; - break; - case Opt_barrier: - mp->m_flags |= XFS_MOUNT_BARRIER; - break; - case Opt_nobarrier: - mp->m_flags &= ~XFS_MOUNT_BARRIER; - break; - case Opt_ikeep: - mp->m_flags |= XFS_MOUNT_IKEEP; - break; - case Opt_noikeep: - mp->m_flags &= ~XFS_MOUNT_IKEEP; - break; - case Opt_largeio: - mp->m_flags &= ~XFS_MOUNT_COMPAT_IOSIZE; - break; - case Opt_nolargeio: - mp->m_flags |= XFS_MOUNT_COMPAT_IOSIZE; - break; - case Opt_attr2: - mp->m_flags |= XFS_MOUNT_ATTR2; - break; - case Opt_noattr2: - mp->m_flags &= ~XFS_MOUNT_ATTR2; - mp->m_flags |= XFS_MOUNT_NOATTR2; - break; - case Opt_filestreams: - mp->m_flags |= XFS_MOUNT_FILESTREAMS; - break; - case Opt_noquota: - mp->m_qflags &= ~XFS_ALL_QUOTA_ACCT; - mp->m_qflags &= ~XFS_ALL_QUOTA_ENFD; - mp->m_qflags &= ~XFS_ALL_QUOTA_ACTIVE; - break; - case Opt_quota: - case Opt_uquota: - case Opt_usrquota: - mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE | - XFS_UQUOTA_ENFD); - break; - case Opt_qnoenforce: - case Opt_uqnoenforce: - mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE); - mp->m_qflags &= ~XFS_UQUOTA_ENFD; - break; - case Opt_pquota: - case Opt_prjquota: - mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE | - XFS_PQUOTA_ENFD); - break; - case Opt_pqnoenforce: - mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE); - mp->m_qflags &= ~XFS_PQUOTA_ENFD; - break; - case Opt_gquota: - case Opt_grpquota: - mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE | - XFS_GQUOTA_ENFD); - break; - case Opt_gqnoenforce: - mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE); - mp->m_qflags &= ~XFS_GQUOTA_ENFD; - break; - case Opt_discard: - mp->m_flags |= XFS_MOUNT_DISCARD; - break; - case Opt_nodiscard: - mp->m_flags &= ~XFS_MOUNT_DISCARD; - break; -#ifdef CONFIG_FS_DAX - case Opt_dax: - mp->m_flags |= XFS_MOUNT_DAX; - break; -#endif - default: - xfs_warn(mp, "unknown mount option [%s].", p); - return -EINVAL; - } - } - - /* - * no recovery flag requires a read-only mount - */ - if ((mp->m_flags & XFS_MOUNT_NORECOVERY) && - !(mp->m_flags & XFS_MOUNT_RDONLY)) { - xfs_warn(mp, "no-recovery mounts must be read-only."); - return -EINVAL; - } - - if ((mp->m_flags & XFS_MOUNT_NOALIGN) && (dsunit || dswidth)) { - xfs_warn(mp, - "sunit and swidth options incompatible with the noalign option"); - return -EINVAL; - } - -#ifndef CONFIG_XFS_QUOTA - if (XFS_IS_QUOTA_RUNNING(mp)) { - xfs_warn(mp, "quota support not available in this kernel."); - return -EINVAL; - } -#endif - - if ((dsunit && !dswidth) || (!dsunit && dswidth)) { - xfs_warn(mp, "sunit and swidth must be specified together"); - return -EINVAL; - } - - if (dsunit && (dswidth % dsunit != 0)) { - xfs_warn(mp, - "stripe width (%d) must be a multiple of the stripe unit (%d)", - dswidth, dsunit); - return -EINVAL; - } - -done: - if (dsunit && !(mp->m_flags & XFS_MOUNT_NOALIGN)) { - /* - * At this point the superblock has not been read - * in, therefore we do not know the block size. - * Before the mount call ends we will convert - * these to FSBs. - */ - mp->m_dalign = dsunit; - mp->m_swidth = dswidth; - } - - if (mp->m_logbufs != -1 && - mp->m_logbufs != 0 && - (mp->m_logbufs < XLOG_MIN_ICLOGS || - mp->m_logbufs > XLOG_MAX_ICLOGS)) { - xfs_warn(mp, "invalid logbufs value: %d [not %d-%d]", - mp->m_logbufs, XLOG_MIN_ICLOGS, XLOG_MAX_ICLOGS); - return -EINVAL; - } - if (mp->m_logbsize != -1 && - mp->m_logbsize != 0 && - (mp->m_logbsize < XLOG_MIN_RECORD_BSIZE || - mp->m_logbsize > XLOG_MAX_RECORD_BSIZE || - !is_power_of_2(mp->m_logbsize))) { - xfs_warn(mp, - "invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]", - mp->m_logbsize); - return -EINVAL; - } - - if (iosizelog) { - if (iosizelog > XFS_MAX_IO_LOG || - iosizelog < XFS_MIN_IO_LOG) { - xfs_warn(mp, "invalid log iosize: %d [not %d-%d]", - iosizelog, XFS_MIN_IO_LOG, - XFS_MAX_IO_LOG); - return -EINVAL; - } - - mp->m_flags |= XFS_MOUNT_DFLT_IOSIZE; - mp->m_readio_log = iosizelog; - mp->m_writeio_log = iosizelog; - } - - return 0; -} - -struct proc_xfs_info { - uint64_t flag; - char *str; -}; - -STATIC int -xfs_showargs( - struct xfs_mount *mp, - struct seq_file *m) -{ - static struct proc_xfs_info xfs_info_set[] = { - /* the few simple ones we can get from the mount struct */ - { XFS_MOUNT_IKEEP, ",ikeep" }, - { XFS_MOUNT_WSYNC, ",wsync" }, - { XFS_MOUNT_NOALIGN, ",noalign" }, - { XFS_MOUNT_SWALLOC, ",swalloc" }, - { XFS_MOUNT_NOUUID, ",nouuid" }, - { XFS_MOUNT_NORECOVERY, ",norecovery" }, - { XFS_MOUNT_ATTR2, ",attr2" }, - { XFS_MOUNT_FILESTREAMS, ",filestreams" }, - { XFS_MOUNT_GRPID, ",grpid" }, - { XFS_MOUNT_DISCARD, ",discard" }, - { XFS_MOUNT_SMALL_INUMS, ",inode32" }, - { XFS_MOUNT_DAX, ",dax" }, - { 0, NULL } - }; - static struct proc_xfs_info xfs_info_unset[] = { - /* the few simple ones we can get from the mount struct */ - { XFS_MOUNT_COMPAT_IOSIZE, ",largeio" }, - { XFS_MOUNT_BARRIER, ",nobarrier" }, - { XFS_MOUNT_SMALL_INUMS, ",inode64" }, - { 0, NULL } - }; - struct proc_xfs_info *xfs_infop; - - for (xfs_infop = xfs_info_set; xfs_infop->flag; xfs_infop++) { - if (mp->m_flags & xfs_infop->flag) - seq_puts(m, xfs_infop->str); - } - for (xfs_infop = xfs_info_unset; xfs_infop->flag; xfs_infop++) { - if (!(mp->m_flags & xfs_infop->flag)) - seq_puts(m, xfs_infop->str); - } - - if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) - seq_printf(m, ",allocsize=%dk", - (int)(1 << mp->m_writeio_log) >> 10); - - if (mp->m_logbufs > 0) - seq_printf(m, ",logbufs=%d", mp->m_logbufs); - if (mp->m_logbsize > 0) - seq_printf(m, ",logbsize=%dk", mp->m_logbsize >> 10); - - if (mp->m_logname) - seq_show_option(m, "logdev", mp->m_logname); - if (mp->m_rtname) - seq_show_option(m, "rtdev", mp->m_rtname); - - if (mp->m_dalign > 0) - seq_printf(m, ",sunit=%d", - (int)XFS_FSB_TO_BB(mp, mp->m_dalign)); - if (mp->m_swidth > 0) - seq_printf(m, ",swidth=%d", - (int)XFS_FSB_TO_BB(mp, mp->m_swidth)); - - if (mp->m_qflags & (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD)) - seq_puts(m, ",usrquota"); - else if (mp->m_qflags & XFS_UQUOTA_ACCT) - seq_puts(m, ",uqnoenforce"); - - if (mp->m_qflags & XFS_PQUOTA_ACCT) { - if (mp->m_qflags & XFS_PQUOTA_ENFD) - seq_puts(m, ",prjquota"); - else - seq_puts(m, ",pqnoenforce"); - } - if (mp->m_qflags & XFS_GQUOTA_ACCT) { - if (mp->m_qflags & XFS_GQUOTA_ENFD) - seq_puts(m, ",grpquota"); - else - seq_puts(m, ",gqnoenforce"); - } - - if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT)) - seq_puts(m, ",noquota"); - - return 0; -} -static __uint64_t -xfs_max_file_offset( - unsigned int blockshift) -{ - unsigned int pagefactor = 1; - unsigned int bitshift = BITS_PER_LONG - 1; - - /* Figure out maximum filesize, on Linux this can depend on - * the filesystem blocksize (on 32 bit platforms). - * __block_write_begin does this in an [unsigned] long... - * page->index << (PAGE_SHIFT - bbits) - * So, for page sized blocks (4K on 32 bit platforms), - * this wraps at around 8Tb (hence MAX_LFS_FILESIZE which is - * (((u64)PAGE_SIZE << (BITS_PER_LONG-1))-1) - * but for smaller blocksizes it is less (bbits = log2 bsize). - * Note1: get_block_t takes a long (implicit cast from above) - * Note2: The Large Block Device (LBD and HAVE_SECTOR_T) patch - * can optionally convert the [unsigned] long from above into - * an [unsigned] long long. - */ - -#if BITS_PER_LONG == 32 -# if defined(CONFIG_LBDAF) - ASSERT(sizeof(sector_t) == 8); - pagefactor = PAGE_SIZE; - bitshift = BITS_PER_LONG; -# else - pagefactor = PAGE_SIZE >> (PAGE_SHIFT - blockshift); -# endif -#endif - - return (((__uint64_t)pagefactor) << bitshift) - 1; -} - -/* - * Set parameters for inode allocation heuristics, taking into account - * filesystem size and inode32/inode64 mount options; i.e. specifically - * whether or not XFS_MOUNT_SMALL_INUMS is set. - * - * Inode allocation patterns are altered only if inode32 is requested - * (XFS_MOUNT_SMALL_INUMS), and the filesystem is sufficiently large. - * If altered, XFS_MOUNT_32BITINODES is set as well. - * - * An agcount independent of that in the mount structure is provided - * because in the growfs case, mp->m_sb.sb_agcount is not yet updated - * to the potentially higher ag count. - * - * Returns the maximum AG index which may contain inodes. - */ -xfs_agnumber_t -xfs_set_inode_alloc( - struct xfs_mount *mp, - xfs_agnumber_t agcount) -{ - xfs_agnumber_t index; - xfs_agnumber_t maxagi = 0; - xfs_sb_t *sbp = &mp->m_sb; - xfs_agnumber_t max_metadata; - xfs_agino_t agino; - xfs_ino_t ino; - - /* - * Calculate how much should be reserved for inodes to meet - * the max inode percentage. Used only for inode32. - */ - if (mp->m_maxicount) { - __uint64_t icount; - - icount = sbp->sb_dblocks * sbp->sb_imax_pct; - do_div(icount, 100); - icount += sbp->sb_agblocks - 1; - do_div(icount, sbp->sb_agblocks); - max_metadata = icount; - } else { - max_metadata = agcount; - } - - /* Get the last possible inode in the filesystem */ - agino = XFS_OFFBNO_TO_AGINO(mp, sbp->sb_agblocks - 1, 0); - ino = XFS_AGINO_TO_INO(mp, agcount - 1, agino); - - /* - * If user asked for no more than 32-bit inodes, and the fs is - * sufficiently large, set XFS_MOUNT_32BITINODES if we must alter - * the allocator to accommodate the request. - */ - if ((mp->m_flags & XFS_MOUNT_SMALL_INUMS) && ino > XFS_MAXINUMBER_32) - mp->m_flags |= XFS_MOUNT_32BITINODES; - else - mp->m_flags &= ~XFS_MOUNT_32BITINODES; - - for (index = 0; index < agcount; index++) { - struct xfs_perag *pag; - - ino = XFS_AGINO_TO_INO(mp, index, agino); - - pag = xfs_perag_get(mp, index); - - if (mp->m_flags & XFS_MOUNT_32BITINODES) { - if (ino > XFS_MAXINUMBER_32) { - pag->pagi_inodeok = 0; - pag->pagf_metadata = 0; - } else { - pag->pagi_inodeok = 1; - maxagi++; - if (index < max_metadata) - pag->pagf_metadata = 1; - else - pag->pagf_metadata = 0; - } - } else { - pag->pagi_inodeok = 1; - pag->pagf_metadata = 0; - } - - xfs_perag_put(pag); - } - - return (mp->m_flags & XFS_MOUNT_32BITINODES) ? maxagi : agcount; -} - -STATIC int -xfs_blkdev_get( - xfs_mount_t *mp, - const char *name, - struct block_device **bdevp) -{ - int error = 0; - - *bdevp = blkdev_get_by_path(name, FMODE_READ|FMODE_WRITE|FMODE_EXCL, - mp); - if (IS_ERR(*bdevp)) { - error = PTR_ERR(*bdevp); - xfs_warn(mp, "Invalid device [%s], error=%d", name, error); - } - - return error; -} - -STATIC void -xfs_blkdev_put( - struct block_device *bdev) -{ - if (bdev) - blkdev_put(bdev, FMODE_READ|FMODE_WRITE|FMODE_EXCL); -} - -void -xfs_blkdev_issue_flush( - xfs_buftarg_t *buftarg) -{ - blkdev_issue_flush(buftarg->bt_bdev, GFP_NOFS, NULL); -} - -STATIC void -xfs_close_devices( - struct xfs_mount *mp) -{ - if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) { - struct block_device *logdev = mp->m_logdev_targp->bt_bdev; - xfs_free_buftarg(mp, mp->m_logdev_targp); - xfs_blkdev_put(logdev); - } - if (mp->m_rtdev_targp) { - struct block_device *rtdev = mp->m_rtdev_targp->bt_bdev; - xfs_free_buftarg(mp, mp->m_rtdev_targp); - xfs_blkdev_put(rtdev); - } - xfs_free_buftarg(mp, mp->m_ddev_targp); -} - -/* - * The file system configurations are: - * (1) device (partition) with data and internal log - * (2) logical volume with data and log subvolumes. - * (3) logical volume with data, log, and realtime subvolumes. - * - * We only have to handle opening the log and realtime volumes here if - * they are present. The data subvolume has already been opened by - * get_sb_bdev() and is stored in sb->s_bdev. - */ -STATIC int -xfs_open_devices( - struct xfs_mount *mp) -{ - struct block_device *ddev = mp->m_super->s_bdev; - struct block_device *logdev = NULL, *rtdev = NULL; - int error; - - /* - * Open real time and log devices - order is important. - */ - if (mp->m_logname) { - error = xfs_blkdev_get(mp, mp->m_logname, &logdev); - if (error) - goto out; - } - - if (mp->m_rtname) { - error = xfs_blkdev_get(mp, mp->m_rtname, &rtdev); - if (error) - goto out_close_logdev; - - if (rtdev == ddev || rtdev == logdev) { - xfs_warn(mp, - "Cannot mount filesystem with identical rtdev and ddev/logdev."); - error = -EINVAL; - goto out_close_rtdev; - } - } - - /* - * Setup xfs_mount buffer target pointers - */ - error = -ENOMEM; - mp->m_ddev_targp = xfs_alloc_buftarg(mp, ddev); - if (!mp->m_ddev_targp) - goto out_close_rtdev; - - if (rtdev) { - mp->m_rtdev_targp = xfs_alloc_buftarg(mp, rtdev); - if (!mp->m_rtdev_targp) - goto out_free_ddev_targ; - } - - if (logdev && logdev != ddev) { - mp->m_logdev_targp = xfs_alloc_buftarg(mp, logdev); - if (!mp->m_logdev_targp) - goto out_free_rtdev_targ; - } else { - mp->m_logdev_targp = mp->m_ddev_targp; - } - - return 0; - - out_free_rtdev_targ: - if (mp->m_rtdev_targp) - xfs_free_buftarg(mp, mp->m_rtdev_targp); - out_free_ddev_targ: - xfs_free_buftarg(mp, mp->m_ddev_targp); - out_close_rtdev: - xfs_blkdev_put(rtdev); - out_close_logdev: - if (logdev && logdev != ddev) - xfs_blkdev_put(logdev); - out: - return error; -} - -/* - * Setup xfs_mount buffer target pointers based on superblock - */ -STATIC int -xfs_setup_devices( - struct xfs_mount *mp) -{ - int error; - - error = xfs_setsize_buftarg(mp->m_ddev_targp, mp->m_sb.sb_sectsize); - if (error) - return error; - - if (mp->m_logdev_targp && mp->m_logdev_targp != mp->m_ddev_targp) { - unsigned int log_sector_size = BBSIZE; - - if (xfs_sb_version_hassector(&mp->m_sb)) - log_sector_size = mp->m_sb.sb_logsectsize; - error = xfs_setsize_buftarg(mp->m_logdev_targp, - log_sector_size); - if (error) - return error; - } - if (mp->m_rtdev_targp) { - error = xfs_setsize_buftarg(mp->m_rtdev_targp, - mp->m_sb.sb_sectsize); - if (error) - return error; - } - - return 0; -} - -STATIC int -xfs_init_mount_workqueues( - struct xfs_mount *mp) -{ - mp->m_buf_workqueue = alloc_workqueue("xfs-buf/%s", - WQ_MEM_RECLAIM|WQ_FREEZABLE, 1, mp->m_fsname); - if (!mp->m_buf_workqueue) - goto out; - - mp->m_data_workqueue = alloc_workqueue("xfs-data/%s", - WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname); - if (!mp->m_data_workqueue) - goto out_destroy_buf; - - mp->m_unwritten_workqueue = alloc_workqueue("xfs-conv/%s", - WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname); - if (!mp->m_unwritten_workqueue) - goto out_destroy_data_iodone_queue; - - mp->m_cil_workqueue = alloc_workqueue("xfs-cil/%s", - WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname); - if (!mp->m_cil_workqueue) - goto out_destroy_unwritten; - - mp->m_reclaim_workqueue = alloc_workqueue("xfs-reclaim/%s", - WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname); - if (!mp->m_reclaim_workqueue) - goto out_destroy_cil; - - mp->m_log_workqueue = alloc_workqueue("xfs-log/%s", - WQ_MEM_RECLAIM|WQ_FREEZABLE|WQ_HIGHPRI, 0, - mp->m_fsname); - if (!mp->m_log_workqueue) - goto out_destroy_reclaim; - - mp->m_eofblocks_workqueue = alloc_workqueue("xfs-eofblocks/%s", - WQ_MEM_RECLAIM|WQ_FREEZABLE, 0, mp->m_fsname); - if (!mp->m_eofblocks_workqueue) - goto out_destroy_log; - - return 0; - -out_destroy_log: - destroy_workqueue(mp->m_log_workqueue); -out_destroy_reclaim: - destroy_workqueue(mp->m_reclaim_workqueue); -out_destroy_cil: - destroy_workqueue(mp->m_cil_workqueue); -out_destroy_unwritten: - destroy_workqueue(mp->m_unwritten_workqueue); -out_destroy_data_iodone_queue: - destroy_workqueue(mp->m_data_workqueue); -out_destroy_buf: - destroy_workqueue(mp->m_buf_workqueue); -out: - return -ENOMEM; -} - -STATIC void -xfs_destroy_mount_workqueues( - struct xfs_mount *mp) -{ - destroy_workqueue(mp->m_eofblocks_workqueue); - destroy_workqueue(mp->m_log_workqueue); - destroy_workqueue(mp->m_reclaim_workqueue); - destroy_workqueue(mp->m_cil_workqueue); - destroy_workqueue(mp->m_data_workqueue); - destroy_workqueue(mp->m_unwritten_workqueue); - destroy_workqueue(mp->m_buf_workqueue); -} - -/* - * Flush all dirty data to disk. Must not be called while holding an XFS_ILOCK - * or a page lock. We use sync_inodes_sb() here to ensure we block while waiting - * for IO to complete so that we effectively throttle multiple callers to the - * rate at which IO is completing. - */ -void -xfs_flush_inodes( - struct xfs_mount *mp) -{ - struct super_block *sb = mp->m_super; - - if (down_read_trylock(&sb->s_umount)) { - sync_inodes_sb(sb); - up_read(&sb->s_umount); - } -} - -/* Catch misguided souls that try to use this interface on XFS */ -STATIC struct inode * -xfs_fs_alloc_inode( - struct super_block *sb) -{ - BUG(); - return NULL; -} - -/* - * Now that the generic code is guaranteed not to be accessing - * the linux inode, we can inactivate and reclaim the inode. - */ -STATIC void -xfs_fs_destroy_inode( - struct inode *inode) -{ - struct xfs_inode *ip = XFS_I(inode); - int error; - - trace_xfs_destroy_inode(ip); - - ASSERT(!rwsem_is_locked(&ip->i_iolock.mr_lock)); - XFS_STATS_INC(ip->i_mount, vn_rele); - XFS_STATS_INC(ip->i_mount, vn_remove); - - if (xfs_is_reflink_inode(ip)) { - error = xfs_reflink_cancel_cow_range(ip, 0, NULLFILEOFF); - if (error && !XFS_FORCED_SHUTDOWN(ip->i_mount)) - xfs_warn(ip->i_mount, -"Error %d while evicting CoW blocks for inode %llu.", - error, ip->i_ino); - } - - xfs_inactive(ip); - - ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0); - XFS_STATS_INC(ip->i_mount, vn_reclaim); - - /* - * We should never get here with one of the reclaim flags already set. - */ - ASSERT_ALWAYS(!xfs_iflags_test(ip, XFS_IRECLAIMABLE)); - ASSERT_ALWAYS(!xfs_iflags_test(ip, XFS_IRECLAIM)); - - /* - * We always use background reclaim here because even if the - * inode is clean, it still may be under IO and hence we have - * to take the flush lock. The background reclaim path handles - * this more efficiently than we can here, so simply let background - * reclaim tear down all inodes. - */ - xfs_inode_set_reclaim_tag(ip); -} - -/* - * Slab object creation initialisation for the XFS inode. - * This covers only the idempotent fields in the XFS inode; - * all other fields need to be initialised on allocation - * from the slab. This avoids the need to repeatedly initialise - * fields in the xfs inode that left in the initialise state - * when freeing the inode. - */ -STATIC void -xfs_fs_inode_init_once( - void *inode) -{ - struct xfs_inode *ip = inode; - - memset(ip, 0, sizeof(struct xfs_inode)); - - /* vfs inode */ - inode_init_once(VFS_I(ip)); - - /* xfs inode */ - atomic_set(&ip->i_pincount, 0); - spin_lock_init(&ip->i_flags_lock); - - mrlock_init(&ip->i_mmaplock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER, - "xfsino", ip->i_ino); - mrlock_init(&ip->i_lock, MRLOCK_ALLOW_EQUAL_PRI|MRLOCK_BARRIER, - "xfsino", ip->i_ino); -} - -/* - * We do an unlocked check for XFS_IDONTCACHE here because we are already - * serialised against cache hits here via the inode->i_lock and igrab() in - * xfs_iget_cache_hit(). Hence a lookup that might clear this flag will not be - * racing with us, and it avoids needing to grab a spinlock here for every inode - * we drop the final reference on. - */ -STATIC int -xfs_fs_drop_inode( - struct inode *inode) -{ - struct xfs_inode *ip = XFS_I(inode); - - /* - * If this unlinked inode is in the middle of recovery, don't - * drop the inode just yet; log recovery will take care of - * that. See the comment for this inode flag. - */ - if (ip->i_flags & XFS_IRECOVERY) { - ASSERT(ip->i_mount->m_log->l_flags & XLOG_RECOVERY_NEEDED); - return 0; - } - - return generic_drop_inode(inode) || (ip->i_flags & XFS_IDONTCACHE); -} - -STATIC void -xfs_free_fsname( - struct xfs_mount *mp) -{ - kfree(mp->m_fsname); - kfree(mp->m_rtname); - kfree(mp->m_logname); -} - -STATIC int -xfs_fs_sync_fs( - struct super_block *sb, - int wait) -{ - struct xfs_mount *mp = XFS_M(sb); - - /* - * Doing anything during the async pass would be counterproductive. - */ - if (!wait) - return 0; - - xfs_log_force(mp, XFS_LOG_SYNC); - if (laptop_mode) { - /* - * The disk must be active because we're syncing. - * We schedule log work now (now that the disk is - * active) instead of later (when it might not be). - */ - flush_delayed_work(&mp->m_log->l_work); - } - - return 0; -} - -STATIC int -xfs_fs_statfs( - struct dentry *dentry, - struct kstatfs *statp) -{ - struct xfs_mount *mp = XFS_M(dentry->d_sb); - xfs_sb_t *sbp = &mp->m_sb; - struct xfs_inode *ip = XFS_I(d_inode(dentry)); - __uint64_t fakeinos, id; - __uint64_t icount; - __uint64_t ifree; - __uint64_t fdblocks; - xfs_extlen_t lsize; - __int64_t ffree; - - statp->f_type = XFS_SB_MAGIC; - statp->f_namelen = MAXNAMELEN - 1; - - id = huge_encode_dev(mp->m_ddev_targp->bt_dev); - statp->f_fsid.val[0] = (u32)id; - statp->f_fsid.val[1] = (u32)(id >> 32); - - icount = percpu_counter_sum(&mp->m_icount); - ifree = percpu_counter_sum(&mp->m_ifree); - fdblocks = percpu_counter_sum(&mp->m_fdblocks); - - spin_lock(&mp->m_sb_lock); - statp->f_bsize = sbp->sb_blocksize; - lsize = sbp->sb_logstart ? sbp->sb_logblocks : 0; - statp->f_blocks = sbp->sb_dblocks - lsize; - spin_unlock(&mp->m_sb_lock); - - statp->f_bfree = fdblocks - mp->m_alloc_set_aside; - statp->f_bavail = statp->f_bfree; - - fakeinos = statp->f_bfree << sbp->sb_inopblog; - statp->f_files = MIN(icount + fakeinos, (__uint64_t)XFS_MAXINUMBER); - if (mp->m_maxicount) - statp->f_files = min_t(typeof(statp->f_files), - statp->f_files, - mp->m_maxicount); - - /* If sb_icount overshot maxicount, report actual allocation */ - statp->f_files = max_t(typeof(statp->f_files), - statp->f_files, - sbp->sb_icount); - - /* make sure statp->f_ffree does not underflow */ - ffree = statp->f_files - (icount - ifree); - statp->f_ffree = max_t(__int64_t, ffree, 0); - - - if ((ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT) && - ((mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD))) == - (XFS_PQUOTA_ACCT|XFS_PQUOTA_ENFD)) - xfs_qm_statvfs(ip, statp); - return 0; -} - -STATIC void -xfs_save_resvblks(struct xfs_mount *mp) -{ - __uint64_t resblks = 0; - - mp->m_resblks_save = mp->m_resblks; - xfs_reserve_blocks(mp, &resblks, NULL); -} - -STATIC void -xfs_restore_resvblks(struct xfs_mount *mp) -{ - __uint64_t resblks; - - if (mp->m_resblks_save) { - resblks = mp->m_resblks_save; - mp->m_resblks_save = 0; - } else - resblks = xfs_default_resblks(mp); - - xfs_reserve_blocks(mp, &resblks, NULL); -} - -/* - * Trigger writeback of all the dirty metadata in the file system. - * - * This ensures that the metadata is written to their location on disk rather - * than just existing in transactions in the log. This means after a quiesce - * there is no log replay required to write the inodes to disk - this is the - * primary difference between a sync and a quiesce. - * - * Note: xfs_log_quiesce() stops background log work - the callers must ensure - * it is started again when appropriate. - */ -void -xfs_quiesce_attr( - struct xfs_mount *mp) -{ - int error = 0; - - /* wait for all modifications to complete */ - while (atomic_read(&mp->m_active_trans) > 0) - delay(100); - - /* force the log to unpin objects from the now complete transactions */ - xfs_log_force(mp, XFS_LOG_SYNC); - - /* reclaim inodes to do any IO before the freeze completes */ - xfs_reclaim_inodes(mp, 0); - xfs_reclaim_inodes(mp, SYNC_WAIT); - - /* Push the superblock and write an unmount record */ - error = xfs_log_sbcount(mp); - if (error) - xfs_warn(mp, "xfs_attr_quiesce: failed to log sb changes. " - "Frozen image may not be consistent."); - /* - * Just warn here till VFS can correctly support - * read-only remount without racing. - */ - WARN_ON(atomic_read(&mp->m_active_trans) != 0); - - xfs_log_quiesce(mp); -} - -STATIC int -xfs_test_remount_options( - struct super_block *sb, - struct xfs_mount *mp, - char *options) -{ - int error = 0; - struct xfs_mount *tmp_mp; - - tmp_mp = kmem_zalloc(sizeof(*tmp_mp), KM_MAYFAIL); - if (!tmp_mp) - return -ENOMEM; - - tmp_mp->m_super = sb; - error = xfs_parseargs(tmp_mp, options); - xfs_free_fsname(tmp_mp); - kfree(tmp_mp); - - return error; -} - -STATIC int -xfs_fs_remount( - struct super_block *sb, - int *flags, - char *options) -{ - struct xfs_mount *mp = XFS_M(sb); - xfs_sb_t *sbp = &mp->m_sb; - substring_t args[MAX_OPT_ARGS]; - char *p; - int error; - - /* First, check for complete junk; i.e. invalid options */ - error = xfs_test_remount_options(sb, mp, options); - if (error) - return error; - - sync_filesystem(sb); - while ((p = strsep(&options, ",")) != NULL) { - int token; - - if (!*p) - continue; - - token = match_token(p, tokens, args); - switch (token) { - case Opt_barrier: - mp->m_flags |= XFS_MOUNT_BARRIER; - break; - case Opt_nobarrier: - mp->m_flags &= ~XFS_MOUNT_BARRIER; - break; - case Opt_inode64: - mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS; - mp->m_maxagi = xfs_set_inode_alloc(mp, sbp->sb_agcount); - break; - case Opt_inode32: - mp->m_flags |= XFS_MOUNT_SMALL_INUMS; - mp->m_maxagi = xfs_set_inode_alloc(mp, sbp->sb_agcount); - break; - default: - /* - * Logically we would return an error here to prevent - * users from believing they might have changed - * mount options using remount which can't be changed. - * - * But unfortunately mount(8) adds all options from - * mtab and fstab to the mount arguments in some cases - * so we can't blindly reject options, but have to - * check for each specified option if it actually - * differs from the currently set option and only - * reject it if that's the case. - * - * Until that is implemented we return success for - * every remount request, and silently ignore all - * options that we can't actually change. - */ -#if 0 - xfs_info(mp, - "mount option \"%s\" not supported for remount", p); - return -EINVAL; -#else - break; -#endif - } - } - - /* ro -> rw */ - if ((mp->m_flags & XFS_MOUNT_RDONLY) && !(*flags & MS_RDONLY)) { - if (mp->m_flags & XFS_MOUNT_NORECOVERY) { - xfs_warn(mp, - "ro->rw transition prohibited on norecovery mount"); - return -EINVAL; - } - - if (XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_5 && - xfs_sb_has_ro_compat_feature(sbp, - XFS_SB_FEAT_RO_COMPAT_UNKNOWN)) { - xfs_warn(mp, -"ro->rw transition prohibited on unknown (0x%x) ro-compat filesystem", - (sbp->sb_features_ro_compat & - XFS_SB_FEAT_RO_COMPAT_UNKNOWN)); - return -EINVAL; - } - - mp->m_flags &= ~XFS_MOUNT_RDONLY; - - /* - * If this is the first remount to writeable state we - * might have some superblock changes to update. - */ - if (mp->m_update_sb) { - error = xfs_sync_sb(mp, false); - if (error) { - xfs_warn(mp, "failed to write sb changes"); - return error; - } - mp->m_update_sb = false; - } - - /* - * Fill out the reserve pool if it is empty. Use the stashed - * value if it is non-zero, otherwise go with the default. - */ - xfs_restore_resvblks(mp); - xfs_log_work_queue(mp); - xfs_queue_eofblocks(mp); - - /* Recover any CoW blocks that never got remapped. */ - error = xfs_reflink_recover_cow(mp); - if (error) { - xfs_err(mp, - "Error %d recovering leftover CoW allocations.", error); - xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); - return error; - } - - /* Create the per-AG metadata reservation pool .*/ - error = xfs_fs_reserve_ag_blocks(mp); - if (error && error != -ENOSPC) - return error; - } - - /* rw -> ro */ - if (!(mp->m_flags & XFS_MOUNT_RDONLY) && (*flags & MS_RDONLY)) { - /* Free the per-AG metadata reservation pool. */ - error = xfs_fs_unreserve_ag_blocks(mp); - if (error) { - xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); - return error; - } - - /* - * Before we sync the metadata, we need to free up the reserve - * block pool so that the used block count in the superblock on - * disk is correct at the end of the remount. Stash the current - * reserve pool size so that if we get remounted rw, we can - * return it to the same size. - */ - xfs_save_resvblks(mp); - - /* - * Cancel background eofb scanning so it cannot race with the - * final log force+buftarg wait and deadlock the remount. - */ - cancel_delayed_work_sync(&mp->m_eofblocks_work); - - xfs_quiesce_attr(mp); - mp->m_flags |= XFS_MOUNT_RDONLY; - } - - return 0; -} - -/* - * Second stage of a freeze. The data is already frozen so we only - * need to take care of the metadata. Once that's done sync the superblock - * to the log to dirty it in case of a crash while frozen. This ensures that we - * will recover the unlinked inode lists on the next mount. - */ -STATIC int -xfs_fs_freeze( - struct super_block *sb) -{ - struct xfs_mount *mp = XFS_M(sb); - - xfs_save_resvblks(mp); - xfs_quiesce_attr(mp); - return xfs_sync_sb(mp, true); -} - -STATIC int -xfs_fs_unfreeze( - struct super_block *sb) -{ - struct xfs_mount *mp = XFS_M(sb); - - xfs_restore_resvblks(mp); - xfs_log_work_queue(mp); - return 0; -} - -STATIC int -xfs_fs_show_options( - struct seq_file *m, - struct dentry *root) -{ - return xfs_showargs(XFS_M(root->d_sb), m); -} - -/* - * This function fills in xfs_mount_t fields based on mount args. - * Note: the superblock _has_ now been read in. - */ -STATIC int -xfs_finish_flags( - struct xfs_mount *mp) -{ - int ronly = (mp->m_flags & XFS_MOUNT_RDONLY); - - /* Fail a mount where the logbuf is smaller than the log stripe */ - if (xfs_sb_version_haslogv2(&mp->m_sb)) { - if (mp->m_logbsize <= 0 && - mp->m_sb.sb_logsunit > XLOG_BIG_RECORD_BSIZE) { - mp->m_logbsize = mp->m_sb.sb_logsunit; - } else if (mp->m_logbsize > 0 && - mp->m_logbsize < mp->m_sb.sb_logsunit) { - xfs_warn(mp, - "logbuf size must be greater than or equal to log stripe size"); - return -EINVAL; - } - } else { - /* Fail a mount if the logbuf is larger than 32K */ - if (mp->m_logbsize > XLOG_BIG_RECORD_BSIZE) { - xfs_warn(mp, - "logbuf size for version 1 logs must be 16K or 32K"); - return -EINVAL; - } - } - - /* - * V5 filesystems always use attr2 format for attributes. - */ - if (xfs_sb_version_hascrc(&mp->m_sb) && - (mp->m_flags & XFS_MOUNT_NOATTR2)) { - xfs_warn(mp, "Cannot mount a V5 filesystem as noattr2. " - "attr2 is always enabled for V5 filesystems."); - return -EINVAL; - } - - /* - * mkfs'ed attr2 will turn on attr2 mount unless explicitly - * told by noattr2 to turn it off - */ - if (xfs_sb_version_hasattr2(&mp->m_sb) && - !(mp->m_flags & XFS_MOUNT_NOATTR2)) - mp->m_flags |= XFS_MOUNT_ATTR2; - - /* - * prohibit r/w mounts of read-only filesystems - */ - if ((mp->m_sb.sb_flags & XFS_SBF_READONLY) && !ronly) { - xfs_warn(mp, - "cannot mount a read-only filesystem as read-write"); - return -EROFS; - } - - if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) && - (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE)) && - !xfs_sb_version_has_pquotino(&mp->m_sb)) { - xfs_warn(mp, - "Super block does not support project and group quota together"); - return -EINVAL; - } - - return 0; -} - -static int -xfs_init_percpu_counters( - struct xfs_mount *mp) -{ - int error; - - error = percpu_counter_init(&mp->m_icount, 0, GFP_KERNEL); - if (error) - return -ENOMEM; - - error = percpu_counter_init(&mp->m_ifree, 0, GFP_KERNEL); - if (error) - goto free_icount; - - error = percpu_counter_init(&mp->m_fdblocks, 0, GFP_KERNEL); - if (error) - goto free_ifree; - - return 0; - -free_ifree: - percpu_counter_destroy(&mp->m_ifree); -free_icount: - percpu_counter_destroy(&mp->m_icount); - return -ENOMEM; -} - -void -xfs_reinit_percpu_counters( - struct xfs_mount *mp) -{ - percpu_counter_set(&mp->m_icount, mp->m_sb.sb_icount); - percpu_counter_set(&mp->m_ifree, mp->m_sb.sb_ifree); - percpu_counter_set(&mp->m_fdblocks, mp->m_sb.sb_fdblocks); -} - -static void -xfs_destroy_percpu_counters( - struct xfs_mount *mp) -{ - percpu_counter_destroy(&mp->m_icount); - percpu_counter_destroy(&mp->m_ifree); - percpu_counter_destroy(&mp->m_fdblocks); -} - -STATIC int -xfs_fs_fill_super( - struct super_block *sb, - void *data, - int silent) -{ - struct inode *root; - struct xfs_mount *mp = NULL; - int flags = 0, error = -ENOMEM; - - mp = kzalloc(sizeof(struct xfs_mount), GFP_KERNEL); - if (!mp) - goto out; - - spin_lock_init(&mp->m_sb_lock); - mutex_init(&mp->m_growlock); - atomic_set(&mp->m_active_trans, 0); - INIT_DELAYED_WORK(&mp->m_reclaim_work, xfs_reclaim_worker); - INIT_DELAYED_WORK(&mp->m_eofblocks_work, xfs_eofblocks_worker); - INIT_DELAYED_WORK(&mp->m_cowblocks_work, xfs_cowblocks_worker); - mp->m_kobj.kobject.kset = xfs_kset; - - mp->m_super = sb; - sb->s_fs_info = mp; - - error = xfs_parseargs(mp, (char *)data); - if (error) - goto out_free_fsname; - - sb_min_blocksize(sb, BBSIZE); - sb->s_xattr = xfs_xattr_handlers; - sb->s_export_op = &xfs_export_operations; -#ifdef CONFIG_XFS_QUOTA - sb->s_qcop = &xfs_quotactl_operations; - sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ; -#endif - sb->s_op = &xfs_super_operations; - - if (silent) - flags |= XFS_MFSI_QUIET; - - error = xfs_open_devices(mp); - if (error) - goto out_free_fsname; - - error = xfs_init_mount_workqueues(mp); - if (error) - goto out_close_devices; - - error = xfs_init_percpu_counters(mp); - if (error) - goto out_destroy_workqueues; - - /* Allocate stats memory before we do operations that might use it */ - mp->m_stats.xs_stats = alloc_percpu(struct xfsstats); - if (!mp->m_stats.xs_stats) { - error = -ENOMEM; - goto out_destroy_counters; - } - - error = xfs_readsb(mp, flags); - if (error) - goto out_free_stats; - - error = xfs_finish_flags(mp); - if (error) - goto out_free_sb; - - error = xfs_setup_devices(mp); - if (error) - goto out_free_sb; - - error = xfs_filestream_mount(mp); - if (error) - goto out_free_sb; - - /* - * we must configure the block size in the superblock before we run the - * full mount process as the mount process can lookup and cache inodes. - */ - sb->s_magic = XFS_SB_MAGIC; - sb->s_blocksize = mp->m_sb.sb_blocksize; - sb->s_blocksize_bits = ffs(sb->s_blocksize) - 1; - sb->s_maxbytes = xfs_max_file_offset(sb->s_blocksize_bits); - sb->s_max_links = XFS_MAXLINK; - sb->s_time_gran = 1; - set_posix_acl_flag(sb); - - /* version 5 superblocks support inode version counters. */ - if (XFS_SB_VERSION_NUM(&mp->m_sb) == XFS_SB_VERSION_5) - sb->s_flags |= MS_I_VERSION; - - if (mp->m_flags & XFS_MOUNT_DAX) { - xfs_warn(mp, - "DAX enabled. Warning: EXPERIMENTAL, use at your own risk"); - - error = bdev_dax_supported(sb, sb->s_blocksize); - if (error) { - xfs_alert(mp, - "DAX unsupported by block device. Turning off DAX."); - mp->m_flags &= ~XFS_MOUNT_DAX; - } - if (xfs_sb_version_hasreflink(&mp->m_sb)) - xfs_alert(mp, - "DAX and reflink have not been tested together!"); - } - - if (xfs_sb_version_hasrmapbt(&mp->m_sb)) { - if (mp->m_sb.sb_rblocks) { - xfs_alert(mp, - "EXPERIMENTAL reverse mapping btree not compatible with realtime device!"); - error = -EINVAL; - goto out_filestream_unmount; - } - xfs_alert(mp, - "EXPERIMENTAL reverse mapping btree feature enabled. Use at your own risk!"); - } - - if (xfs_sb_version_hasreflink(&mp->m_sb)) - xfs_alert(mp, - "EXPERIMENTAL reflink feature enabled. Use at your own risk!"); - - error = xfs_mountfs(mp); - if (error) - goto out_filestream_unmount; - - root = igrab(VFS_I(mp->m_rootip)); - if (!root) { - error = -ENOENT; - goto out_unmount; - } - sb->s_root = d_make_root(root); - if (!sb->s_root) { - error = -ENOMEM; - goto out_unmount; - } - - return 0; - - out_filestream_unmount: - xfs_filestream_unmount(mp); - out_free_sb: - xfs_freesb(mp); - out_free_stats: - free_percpu(mp->m_stats.xs_stats); - out_destroy_counters: - xfs_destroy_percpu_counters(mp); - out_destroy_workqueues: - xfs_destroy_mount_workqueues(mp); - out_close_devices: - xfs_close_devices(mp); - out_free_fsname: - xfs_free_fsname(mp); - kfree(mp); - out: - return error; - - out_unmount: - xfs_filestream_unmount(mp); - xfs_unmountfs(mp); - goto out_free_sb; -} - -STATIC void -xfs_fs_put_super( - struct super_block *sb) -{ - struct xfs_mount *mp = XFS_M(sb); - - xfs_notice(mp, "Unmounting Filesystem"); - xfs_filestream_unmount(mp); - xfs_unmountfs(mp); - - xfs_freesb(mp); - free_percpu(mp->m_stats.xs_stats); - xfs_destroy_percpu_counters(mp); - xfs_destroy_mount_workqueues(mp); - xfs_close_devices(mp); - xfs_free_fsname(mp); - kfree(mp); -} - -STATIC struct dentry * -xfs_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, xfs_fs_fill_super); -} - -static long -xfs_fs_nr_cached_objects( - struct super_block *sb, - struct shrink_control *sc) -{ - return xfs_reclaim_inodes_count(XFS_M(sb)); -} - -static long -xfs_fs_free_cached_objects( - struct super_block *sb, - struct shrink_control *sc) -{ - return xfs_reclaim_inodes_nr(XFS_M(sb), sc->nr_to_scan); -} - -static const struct super_operations xfs_super_operations = { - .alloc_inode = xfs_fs_alloc_inode, - .destroy_inode = xfs_fs_destroy_inode, - .drop_inode = xfs_fs_drop_inode, - .put_super = xfs_fs_put_super, - .sync_fs = xfs_fs_sync_fs, - .freeze_fs = xfs_fs_freeze, - .unfreeze_fs = xfs_fs_unfreeze, - .statfs = xfs_fs_statfs, - .remount_fs = xfs_fs_remount, - .show_options = xfs_fs_show_options, - .nr_cached_objects = xfs_fs_nr_cached_objects, - .free_cached_objects = xfs_fs_free_cached_objects, -}; - -static struct file_system_type xfs_fs_type = { - .owner = THIS_MODULE, - .name = "xfs", - .mount = xfs_fs_mount, - .kill_sb = kill_block_super, - .fs_flags = FS_REQUIRES_DEV, -}; -MODULE_ALIAS_FS("xfs"); - -STATIC int __init -xfs_init_zones(void) -{ - xfs_ioend_bioset = bioset_create(4 * MAX_BUF_PER_PAGE, - offsetof(struct xfs_ioend, io_inline_bio)); - if (!xfs_ioend_bioset) - goto out; - - xfs_log_ticket_zone = kmem_zone_init(sizeof(xlog_ticket_t), - "xfs_log_ticket"); - if (!xfs_log_ticket_zone) - goto out_free_ioend_bioset; - - xfs_bmap_free_item_zone = kmem_zone_init( - sizeof(struct xfs_extent_free_item), - "xfs_bmap_free_item"); - if (!xfs_bmap_free_item_zone) - goto out_destroy_log_ticket_zone; - - xfs_btree_cur_zone = kmem_zone_init(sizeof(xfs_btree_cur_t), - "xfs_btree_cur"); - if (!xfs_btree_cur_zone) - goto out_destroy_bmap_free_item_zone; - - xfs_da_state_zone = kmem_zone_init(sizeof(xfs_da_state_t), - "xfs_da_state"); - if (!xfs_da_state_zone) - goto out_destroy_btree_cur_zone; - - xfs_ifork_zone = kmem_zone_init(sizeof(xfs_ifork_t), "xfs_ifork"); - if (!xfs_ifork_zone) - goto out_destroy_da_state_zone; - - xfs_trans_zone = kmem_zone_init(sizeof(xfs_trans_t), "xfs_trans"); - if (!xfs_trans_zone) - goto out_destroy_ifork_zone; - - xfs_log_item_desc_zone = - kmem_zone_init(sizeof(struct xfs_log_item_desc), - "xfs_log_item_desc"); - if (!xfs_log_item_desc_zone) - goto out_destroy_trans_zone; - - /* - * The size of the zone allocated buf log item is the maximum - * size possible under XFS. This wastes a little bit of memory, - * but it is much faster. - */ - xfs_buf_item_zone = kmem_zone_init(sizeof(struct xfs_buf_log_item), - "xfs_buf_item"); - if (!xfs_buf_item_zone) - goto out_destroy_log_item_desc_zone; - - xfs_efd_zone = kmem_zone_init((sizeof(xfs_efd_log_item_t) + - ((XFS_EFD_MAX_FAST_EXTENTS - 1) * - sizeof(xfs_extent_t))), "xfs_efd_item"); - if (!xfs_efd_zone) - goto out_destroy_buf_item_zone; - - xfs_efi_zone = kmem_zone_init((sizeof(xfs_efi_log_item_t) + - ((XFS_EFI_MAX_FAST_EXTENTS - 1) * - sizeof(xfs_extent_t))), "xfs_efi_item"); - if (!xfs_efi_zone) - goto out_destroy_efd_zone; - - xfs_inode_zone = - kmem_zone_init_flags(sizeof(xfs_inode_t), "xfs_inode", - KM_ZONE_HWALIGN | KM_ZONE_RECLAIM | KM_ZONE_SPREAD | - KM_ZONE_ACCOUNT, xfs_fs_inode_init_once); - if (!xfs_inode_zone) - goto out_destroy_efi_zone; - - xfs_ili_zone = - kmem_zone_init_flags(sizeof(xfs_inode_log_item_t), "xfs_ili", - KM_ZONE_SPREAD, NULL); - if (!xfs_ili_zone) - goto out_destroy_inode_zone; - xfs_icreate_zone = kmem_zone_init(sizeof(struct xfs_icreate_item), - "xfs_icr"); - if (!xfs_icreate_zone) - goto out_destroy_ili_zone; - - xfs_rud_zone = kmem_zone_init(sizeof(struct xfs_rud_log_item), - "xfs_rud_item"); - if (!xfs_rud_zone) - goto out_destroy_icreate_zone; - - xfs_rui_zone = kmem_zone_init( - xfs_rui_log_item_sizeof(XFS_RUI_MAX_FAST_EXTENTS), - "xfs_rui_item"); - if (!xfs_rui_zone) - goto out_destroy_rud_zone; - - xfs_cud_zone = kmem_zone_init(sizeof(struct xfs_cud_log_item), - "xfs_cud_item"); - if (!xfs_cud_zone) - goto out_destroy_rui_zone; - - xfs_cui_zone = kmem_zone_init( - xfs_cui_log_item_sizeof(XFS_CUI_MAX_FAST_EXTENTS), - "xfs_cui_item"); - if (!xfs_cui_zone) - goto out_destroy_cud_zone; - - xfs_bud_zone = kmem_zone_init(sizeof(struct xfs_bud_log_item), - "xfs_bud_item"); - if (!xfs_bud_zone) - goto out_destroy_cui_zone; - - xfs_bui_zone = kmem_zone_init( - xfs_bui_log_item_sizeof(XFS_BUI_MAX_FAST_EXTENTS), - "xfs_bui_item"); - if (!xfs_bui_zone) - goto out_destroy_bud_zone; - - return 0; - - out_destroy_bud_zone: - kmem_zone_destroy(xfs_bud_zone); - out_destroy_cui_zone: - kmem_zone_destroy(xfs_cui_zone); - out_destroy_cud_zone: - kmem_zone_destroy(xfs_cud_zone); - out_destroy_rui_zone: - kmem_zone_destroy(xfs_rui_zone); - out_destroy_rud_zone: - kmem_zone_destroy(xfs_rud_zone); - out_destroy_icreate_zone: - kmem_zone_destroy(xfs_icreate_zone); - out_destroy_ili_zone: - kmem_zone_destroy(xfs_ili_zone); - out_destroy_inode_zone: - kmem_zone_destroy(xfs_inode_zone); - out_destroy_efi_zone: - kmem_zone_destroy(xfs_efi_zone); - out_destroy_efd_zone: - kmem_zone_destroy(xfs_efd_zone); - out_destroy_buf_item_zone: - kmem_zone_destroy(xfs_buf_item_zone); - out_destroy_log_item_desc_zone: - kmem_zone_destroy(xfs_log_item_desc_zone); - out_destroy_trans_zone: - kmem_zone_destroy(xfs_trans_zone); - out_destroy_ifork_zone: - kmem_zone_destroy(xfs_ifork_zone); - out_destroy_da_state_zone: - kmem_zone_destroy(xfs_da_state_zone); - out_destroy_btree_cur_zone: - kmem_zone_destroy(xfs_btree_cur_zone); - out_destroy_bmap_free_item_zone: - kmem_zone_destroy(xfs_bmap_free_item_zone); - out_destroy_log_ticket_zone: - kmem_zone_destroy(xfs_log_ticket_zone); - out_free_ioend_bioset: - bioset_free(xfs_ioend_bioset); - out: - return -ENOMEM; -} - -STATIC void -xfs_destroy_zones(void) -{ - /* - * Make sure all delayed rcu free are flushed before we - * destroy caches. - */ - rcu_barrier(); - kmem_zone_destroy(xfs_bui_zone); - kmem_zone_destroy(xfs_bud_zone); - kmem_zone_destroy(xfs_cui_zone); - kmem_zone_destroy(xfs_cud_zone); - kmem_zone_destroy(xfs_rui_zone); - kmem_zone_destroy(xfs_rud_zone); - kmem_zone_destroy(xfs_icreate_zone); - kmem_zone_destroy(xfs_ili_zone); - kmem_zone_destroy(xfs_inode_zone); - kmem_zone_destroy(xfs_efi_zone); - kmem_zone_destroy(xfs_efd_zone); - kmem_zone_destroy(xfs_buf_item_zone); - kmem_zone_destroy(xfs_log_item_desc_zone); - kmem_zone_destroy(xfs_trans_zone); - kmem_zone_destroy(xfs_ifork_zone); - kmem_zone_destroy(xfs_da_state_zone); - kmem_zone_destroy(xfs_btree_cur_zone); - kmem_zone_destroy(xfs_bmap_free_item_zone); - kmem_zone_destroy(xfs_log_ticket_zone); - bioset_free(xfs_ioend_bioset); -} - -STATIC int __init -xfs_init_workqueues(void) -{ - /* - * The allocation workqueue can be used in memory reclaim situations - * (writepage path), and parallelism is only limited by the number of - * AGs in all the filesystems mounted. Hence use the default large - * max_active value for this workqueue. - */ - xfs_alloc_wq = alloc_workqueue("xfsalloc", - WQ_MEM_RECLAIM|WQ_FREEZABLE, 0); - if (!xfs_alloc_wq) - return -ENOMEM; - - return 0; -} - -STATIC void -xfs_destroy_workqueues(void) -{ - destroy_workqueue(xfs_alloc_wq); -} - -STATIC int __init -init_xfs_fs(void) -{ - int error; - - xfs_check_ondisk_structs(); - - printk(KERN_INFO XFS_VERSION_STRING " with " - XFS_BUILD_OPTIONS " enabled\n"); - - xfs_extent_free_init_defer_op(); - xfs_rmap_update_init_defer_op(); - xfs_refcount_update_init_defer_op(); - xfs_bmap_update_init_defer_op(); - - xfs_dir_startup(); - - error = xfs_init_zones(); - if (error) - goto out; - - error = xfs_init_workqueues(); - if (error) - goto out_destroy_zones; - - error = xfs_mru_cache_init(); - if (error) - goto out_destroy_wq; - - error = xfs_buf_init(); - if (error) - goto out_mru_cache_uninit; - - error = xfs_init_procfs(); - if (error) - goto out_buf_terminate; - - error = xfs_sysctl_register(); - if (error) - goto out_cleanup_procfs; - - xfs_kset = kset_create_and_add("xfs", NULL, fs_kobj); - if (!xfs_kset) { - error = -ENOMEM; - goto out_sysctl_unregister; - } - - xfsstats.xs_kobj.kobject.kset = xfs_kset; - - xfsstats.xs_stats = alloc_percpu(struct xfsstats); - if (!xfsstats.xs_stats) { - error = -ENOMEM; - goto out_kset_unregister; - } - - error = xfs_sysfs_init(&xfsstats.xs_kobj, &xfs_stats_ktype, NULL, - "stats"); - if (error) - goto out_free_stats; - -#ifdef DEBUG - xfs_dbg_kobj.kobject.kset = xfs_kset; - error = xfs_sysfs_init(&xfs_dbg_kobj, &xfs_dbg_ktype, NULL, "debug"); - if (error) - goto out_remove_stats_kobj; -#endif - - error = xfs_qm_init(); - if (error) - goto out_remove_dbg_kobj; - - error = register_filesystem(&xfs_fs_type); - if (error) - goto out_qm_exit; - return 0; - - out_qm_exit: - xfs_qm_exit(); - out_remove_dbg_kobj: -#ifdef DEBUG - xfs_sysfs_del(&xfs_dbg_kobj); - out_remove_stats_kobj: -#endif - xfs_sysfs_del(&xfsstats.xs_kobj); - out_free_stats: - free_percpu(xfsstats.xs_stats); - out_kset_unregister: - kset_unregister(xfs_kset); - out_sysctl_unregister: - xfs_sysctl_unregister(); - out_cleanup_procfs: - xfs_cleanup_procfs(); - out_buf_terminate: - xfs_buf_terminate(); - out_mru_cache_uninit: - xfs_mru_cache_uninit(); - out_destroy_wq: - xfs_destroy_workqueues(); - out_destroy_zones: - xfs_destroy_zones(); - out: - return error; -} - -STATIC void __exit -exit_xfs_fs(void) -{ - xfs_qm_exit(); - unregister_filesystem(&xfs_fs_type); -#ifdef DEBUG - xfs_sysfs_del(&xfs_dbg_kobj); -#endif - xfs_sysfs_del(&xfsstats.xs_kobj); - free_percpu(xfsstats.xs_stats); - kset_unregister(xfs_kset); - xfs_sysctl_unregister(); - xfs_cleanup_procfs(); - xfs_buf_terminate(); - xfs_mru_cache_uninit(); - xfs_destroy_workqueues(); - xfs_destroy_zones(); - xfs_uuid_table_free(); -} - -module_init(init_xfs_fs); -module_exit(exit_xfs_fs); - -MODULE_AUTHOR("Silicon Graphics, Inc."); -MODULE_DESCRIPTION(XFS_VERSION_STRING " with " XFS_BUILD_OPTIONS " enabled"); -MODULE_LICENSE("GPL"); diff --git a/src/linux/fs/xfs/xfs_super.h b/src/linux/fs/xfs/xfs_super.h deleted file mode 100644 index b6418ab..0000000 --- a/src/linux/fs/xfs/xfs_super.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2000-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_SUPER_H__ -#define __XFS_SUPER_H__ - -#include - -#ifdef CONFIG_XFS_QUOTA -extern int xfs_qm_init(void); -extern void xfs_qm_exit(void); -#else -# define xfs_qm_init() (0) -# define xfs_qm_exit() do { } while (0) -#endif - -#ifdef CONFIG_XFS_POSIX_ACL -# define XFS_ACL_STRING "ACLs, " -# define set_posix_acl_flag(sb) ((sb)->s_flags |= MS_POSIXACL) -#else -# define XFS_ACL_STRING -# define set_posix_acl_flag(sb) do { } while (0) -#endif - -#define XFS_SECURITY_STRING "security attributes, " - -#ifdef CONFIG_XFS_RT -# define XFS_REALTIME_STRING "realtime, " -#else -# define XFS_REALTIME_STRING -#endif - -#ifdef DEBUG -# define XFS_DBG_STRING "debug" -#else -# define XFS_DBG_STRING "no debug" -#endif - -#define XFS_VERSION_STRING "SGI XFS" -#define XFS_BUILD_OPTIONS XFS_ACL_STRING \ - XFS_SECURITY_STRING \ - XFS_REALTIME_STRING \ - XFS_DBG_STRING /* DBG must be last */ - -struct xfs_inode; -struct xfs_mount; -struct xfs_buftarg; -struct block_device; - -extern void xfs_quiesce_attr(struct xfs_mount *mp); -extern void xfs_flush_inodes(struct xfs_mount *mp); -extern void xfs_blkdev_issue_flush(struct xfs_buftarg *); -extern xfs_agnumber_t xfs_set_inode_alloc(struct xfs_mount *, - xfs_agnumber_t agcount); - -extern const struct export_operations xfs_export_operations; -extern const struct xattr_handler *xfs_xattr_handlers[]; -extern const struct quotactl_ops xfs_quotactl_operations; - -extern void xfs_reinit_percpu_counters(struct xfs_mount *mp); - -#define XFS_M(sb) ((struct xfs_mount *)((sb)->s_fs_info)) - -#endif /* __XFS_SUPER_H__ */ diff --git a/src/linux/fs/xfs/xfs_symlink.c b/src/linux/fs/xfs/xfs_symlink.c deleted file mode 100644 index 58142ae..0000000 --- a/src/linux/fs/xfs/xfs_symlink.c +++ /dev/null @@ -1,584 +0,0 @@ -/* - * Copyright (c) 2000-2006 Silicon Graphics, Inc. - * Copyright (c) 2012-2013 Red Hat, Inc. - * All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_shared.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_da_btree.h" -#include "xfs_defer.h" -#include "xfs_dir2.h" -#include "xfs_inode.h" -#include "xfs_ialloc.h" -#include "xfs_alloc.h" -#include "xfs_bmap.h" -#include "xfs_bmap_btree.h" -#include "xfs_bmap_util.h" -#include "xfs_error.h" -#include "xfs_quota.h" -#include "xfs_trans_space.h" -#include "xfs_trace.h" -#include "xfs_symlink.h" -#include "xfs_trans.h" -#include "xfs_log.h" - -/* ----- Kernel only functions below ----- */ -STATIC int -xfs_readlink_bmap( - struct xfs_inode *ip, - char *link) -{ - struct xfs_mount *mp = ip->i_mount; - struct xfs_bmbt_irec mval[XFS_SYMLINK_MAPS]; - struct xfs_buf *bp; - xfs_daddr_t d; - char *cur_chunk; - int pathlen = ip->i_d.di_size; - int nmaps = XFS_SYMLINK_MAPS; - int byte_cnt; - int n; - int error = 0; - int fsblocks = 0; - int offset; - - fsblocks = xfs_symlink_blocks(mp, pathlen); - error = xfs_bmapi_read(ip, 0, fsblocks, mval, &nmaps, 0); - if (error) - goto out; - - offset = 0; - for (n = 0; n < nmaps; n++) { - d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); - byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); - - bp = xfs_buf_read(mp->m_ddev_targp, d, BTOBB(byte_cnt), 0, - &xfs_symlink_buf_ops); - if (!bp) - return -ENOMEM; - error = bp->b_error; - if (error) { - xfs_buf_ioerror_alert(bp, __func__); - xfs_buf_relse(bp); - - /* bad CRC means corrupted metadata */ - if (error == -EFSBADCRC) - error = -EFSCORRUPTED; - goto out; - } - byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt); - if (pathlen < byte_cnt) - byte_cnt = pathlen; - - cur_chunk = bp->b_addr; - if (xfs_sb_version_hascrc(&mp->m_sb)) { - if (!xfs_symlink_hdr_ok(ip->i_ino, offset, - byte_cnt, bp)) { - error = -EFSCORRUPTED; - xfs_alert(mp, -"symlink header does not match required off/len/owner (0x%x/Ox%x,0x%llx)", - offset, byte_cnt, ip->i_ino); - xfs_buf_relse(bp); - goto out; - - } - - cur_chunk += sizeof(struct xfs_dsymlink_hdr); - } - - memcpy(link + offset, cur_chunk, byte_cnt); - - pathlen -= byte_cnt; - offset += byte_cnt; - - xfs_buf_relse(bp); - } - ASSERT(pathlen == 0); - - link[ip->i_d.di_size] = '\0'; - error = 0; - - out: - return error; -} - -int -xfs_readlink( - struct xfs_inode *ip, - char *link) -{ - struct xfs_mount *mp = ip->i_mount; - xfs_fsize_t pathlen; - int error = 0; - - trace_xfs_readlink(ip); - - ASSERT(!(ip->i_df.if_flags & XFS_IFINLINE)); - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - xfs_ilock(ip, XFS_ILOCK_SHARED); - - pathlen = ip->i_d.di_size; - if (!pathlen) - goto out; - - if (pathlen < 0 || pathlen > MAXPATHLEN) { - xfs_alert(mp, "%s: inode (%llu) bad symlink length (%lld)", - __func__, (unsigned long long) ip->i_ino, - (long long) pathlen); - ASSERT(0); - error = -EFSCORRUPTED; - goto out; - } - - - error = xfs_readlink_bmap(ip, link); - - out: - xfs_iunlock(ip, XFS_ILOCK_SHARED); - return error; -} - -int -xfs_symlink( - struct xfs_inode *dp, - struct xfs_name *link_name, - const char *target_path, - umode_t mode, - struct xfs_inode **ipp) -{ - struct xfs_mount *mp = dp->i_mount; - struct xfs_trans *tp = NULL; - struct xfs_inode *ip = NULL; - int error = 0; - int pathlen; - struct xfs_defer_ops dfops; - xfs_fsblock_t first_block; - bool unlock_dp_on_error = false; - xfs_fileoff_t first_fsb; - xfs_filblks_t fs_blocks; - int nmaps; - struct xfs_bmbt_irec mval[XFS_SYMLINK_MAPS]; - xfs_daddr_t d; - const char *cur_chunk; - int byte_cnt; - int n; - xfs_buf_t *bp; - prid_t prid; - struct xfs_dquot *udqp = NULL; - struct xfs_dquot *gdqp = NULL; - struct xfs_dquot *pdqp = NULL; - uint resblks; - - *ipp = NULL; - - trace_xfs_symlink(dp, link_name); - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - /* - * Check component lengths of the target path name. - */ - pathlen = strlen(target_path); - if (pathlen >= MAXPATHLEN) /* total string too long */ - return -ENAMETOOLONG; - - udqp = gdqp = NULL; - prid = xfs_get_initial_prid(dp); - - /* - * Make sure that we have allocated dquot(s) on disk. - */ - error = xfs_qm_vop_dqalloc(dp, - xfs_kuid_to_uid(current_fsuid()), - xfs_kgid_to_gid(current_fsgid()), prid, - XFS_QMOPT_QUOTALL | XFS_QMOPT_INHERIT, - &udqp, &gdqp, &pdqp); - if (error) - return error; - - /* - * The symlink will fit into the inode data fork? - * There can't be any attributes so we get the whole variable part. - */ - if (pathlen <= XFS_LITINO(mp, dp->i_d.di_version)) - fs_blocks = 0; - else - fs_blocks = xfs_symlink_blocks(mp, pathlen); - resblks = XFS_SYMLINK_SPACE_RES(mp, link_name->len, fs_blocks); - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_symlink, resblks, 0, 0, &tp); - if (error == -ENOSPC && fs_blocks == 0) { - resblks = 0; - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_symlink, 0, 0, 0, - &tp); - } - if (error) - goto out_release_inode; - - xfs_ilock(dp, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL | - XFS_IOLOCK_PARENT | XFS_ILOCK_PARENT); - unlock_dp_on_error = true; - - /* - * Check whether the directory allows new symlinks or not. - */ - if (dp->i_d.di_flags & XFS_DIFLAG_NOSYMLINKS) { - error = -EPERM; - goto out_trans_cancel; - } - - /* - * Reserve disk quota : blocks and inode. - */ - error = xfs_trans_reserve_quota(tp, mp, udqp, gdqp, - pdqp, resblks, 1, 0); - if (error) - goto out_trans_cancel; - - /* - * Check for ability to enter directory entry, if no space reserved. - */ - if (!resblks) { - error = xfs_dir_canenter(tp, dp, link_name); - if (error) - goto out_trans_cancel; - } - /* - * Initialize the bmap freelist prior to calling either - * bmapi or the directory create code. - */ - xfs_defer_init(&dfops, &first_block); - - /* - * Allocate an inode for the symlink. - */ - error = xfs_dir_ialloc(&tp, dp, S_IFLNK | (mode & ~S_IFMT), 1, 0, - prid, resblks > 0, &ip, NULL); - if (error) - goto out_trans_cancel; - - /* - * Now we join the directory inode to the transaction. We do not do it - * earlier because xfs_dir_ialloc might commit the previous transaction - * (and release all the locks). An error from here on will result in - * the transaction cancel unlocking dp so don't do it explicitly in the - * error path. - */ - xfs_trans_ijoin(tp, dp, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); - unlock_dp_on_error = false; - - /* - * Also attach the dquot(s) to it, if applicable. - */ - xfs_qm_vop_create_dqattach(tp, ip, udqp, gdqp, pdqp); - - if (resblks) - resblks -= XFS_IALLOC_SPACE_RES(mp); - /* - * If the symlink will fit into the inode, write it inline. - */ - if (pathlen <= XFS_IFORK_DSIZE(ip)) { - xfs_init_local_fork(ip, XFS_DATA_FORK, target_path, pathlen); - - ip->i_d.di_size = pathlen; - ip->i_d.di_format = XFS_DINODE_FMT_LOCAL; - xfs_trans_log_inode(tp, ip, XFS_ILOG_DDATA | XFS_ILOG_CORE); - } else { - int offset; - - first_fsb = 0; - nmaps = XFS_SYMLINK_MAPS; - - error = xfs_bmapi_write(tp, ip, first_fsb, fs_blocks, - XFS_BMAPI_METADATA, &first_block, resblks, - mval, &nmaps, &dfops); - if (error) - goto out_bmap_cancel; - - if (resblks) - resblks -= fs_blocks; - ip->i_d.di_size = pathlen; - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - - cur_chunk = target_path; - offset = 0; - for (n = 0; n < nmaps; n++) { - char *buf; - - d = XFS_FSB_TO_DADDR(mp, mval[n].br_startblock); - byte_cnt = XFS_FSB_TO_B(mp, mval[n].br_blockcount); - bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, d, - BTOBB(byte_cnt), 0); - if (!bp) { - error = -ENOMEM; - goto out_bmap_cancel; - } - bp->b_ops = &xfs_symlink_buf_ops; - - byte_cnt = XFS_SYMLINK_BUF_SPACE(mp, byte_cnt); - byte_cnt = min(byte_cnt, pathlen); - - buf = bp->b_addr; - buf += xfs_symlink_hdr_set(mp, ip->i_ino, offset, - byte_cnt, bp); - - memcpy(buf, cur_chunk, byte_cnt); - - cur_chunk += byte_cnt; - pathlen -= byte_cnt; - offset += byte_cnt; - - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SYMLINK_BUF); - xfs_trans_log_buf(tp, bp, 0, (buf + byte_cnt - 1) - - (char *)bp->b_addr); - } - ASSERT(pathlen == 0); - } - - /* - * Create the directory entry for the symlink. - */ - error = xfs_dir_createname(tp, dp, link_name, ip->i_ino, - &first_block, &dfops, resblks); - if (error) - goto out_bmap_cancel; - xfs_trans_ichgtime(tp, dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); - xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE); - - /* - * If this is a synchronous mount, make sure that the - * symlink transaction goes to disk before returning to - * the user. - */ - if (mp->m_flags & (XFS_MOUNT_WSYNC|XFS_MOUNT_DIRSYNC)) { - xfs_trans_set_sync(tp); - } - - error = xfs_defer_finish(&tp, &dfops, NULL); - if (error) - goto out_bmap_cancel; - - error = xfs_trans_commit(tp); - if (error) - goto out_release_inode; - - xfs_qm_dqrele(udqp); - xfs_qm_dqrele(gdqp); - xfs_qm_dqrele(pdqp); - - *ipp = ip; - return 0; - -out_bmap_cancel: - xfs_defer_cancel(&dfops); -out_trans_cancel: - xfs_trans_cancel(tp); -out_release_inode: - /* - * Wait until after the current transaction is aborted to finish the - * setup of the inode and release the inode. This prevents recursive - * transactions and deadlocks from xfs_inactive. - */ - if (ip) { - xfs_finish_inode_setup(ip); - IRELE(ip); - } - - xfs_qm_dqrele(udqp); - xfs_qm_dqrele(gdqp); - xfs_qm_dqrele(pdqp); - - if (unlock_dp_on_error) - xfs_iunlock(dp, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); - return error; -} - -/* - * Free a symlink that has blocks associated with it. - */ -STATIC int -xfs_inactive_symlink_rmt( - struct xfs_inode *ip) -{ - xfs_buf_t *bp; - int done; - int error; - xfs_fsblock_t first_block; - struct xfs_defer_ops dfops; - int i; - xfs_mount_t *mp; - xfs_bmbt_irec_t mval[XFS_SYMLINK_MAPS]; - int nmaps; - int size; - xfs_trans_t *tp; - - mp = ip->i_mount; - ASSERT(ip->i_df.if_flags & XFS_IFEXTENTS); - /* - * We're freeing a symlink that has some - * blocks allocated to it. Free the - * blocks here. We know that we've got - * either 1 or 2 extents and that we can - * free them all in one bunmapi call. - */ - ASSERT(ip->i_d.di_nextents > 0 && ip->i_d.di_nextents <= 2); - - error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp); - if (error) - return error; - - xfs_ilock(ip, XFS_ILOCK_EXCL); - xfs_trans_ijoin(tp, ip, 0); - - /* - * Lock the inode, fix the size, and join it to the transaction. - * Hold it so in the normal path, we still have it locked for - * the second transaction. In the error paths we need it - * held so the cancel won't rele it, see below. - */ - size = (int)ip->i_d.di_size; - ip->i_d.di_size = 0; - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - /* - * Find the block(s) so we can inval and unmap them. - */ - done = 0; - xfs_defer_init(&dfops, &first_block); - nmaps = ARRAY_SIZE(mval); - error = xfs_bmapi_read(ip, 0, xfs_symlink_blocks(mp, size), - mval, &nmaps, 0); - if (error) - goto error_trans_cancel; - /* - * Invalidate the block(s). No validation is done. - */ - for (i = 0; i < nmaps; i++) { - bp = xfs_trans_get_buf(tp, mp->m_ddev_targp, - XFS_FSB_TO_DADDR(mp, mval[i].br_startblock), - XFS_FSB_TO_BB(mp, mval[i].br_blockcount), 0); - if (!bp) { - error = -ENOMEM; - goto error_bmap_cancel; - } - xfs_trans_binval(tp, bp); - } - /* - * Unmap the dead block(s) to the dfops. - */ - error = xfs_bunmapi(tp, ip, 0, size, 0, nmaps, - &first_block, &dfops, &done); - if (error) - goto error_bmap_cancel; - ASSERT(done); - /* - * Commit the first transaction. This logs the EFI and the inode. - */ - error = xfs_defer_finish(&tp, &dfops, ip); - if (error) - goto error_bmap_cancel; - /* - * The first xact was committed, so add the inode to the new one. - * Mark it dirty so it will be logged and moved forward in the log as - * part of every commit. - */ - xfs_trans_ijoin(tp, ip, 0); - xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); - /* - * Commit the transaction containing extent freeing and EFDs. - */ - error = xfs_trans_commit(tp); - if (error) { - ASSERT(XFS_FORCED_SHUTDOWN(mp)); - goto error_unlock; - } - - /* - * Remove the memory for extent descriptions (just bookkeeping). - */ - if (ip->i_df.if_bytes) - xfs_idata_realloc(ip, -ip->i_df.if_bytes, XFS_DATA_FORK); - ASSERT(ip->i_df.if_bytes == 0); - - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return 0; - -error_bmap_cancel: - xfs_defer_cancel(&dfops); -error_trans_cancel: - xfs_trans_cancel(tp); -error_unlock: - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return error; -} - -/* - * xfs_inactive_symlink - free a symlink - */ -int -xfs_inactive_symlink( - struct xfs_inode *ip) -{ - struct xfs_mount *mp = ip->i_mount; - int pathlen; - - trace_xfs_inactive_symlink(ip); - - if (XFS_FORCED_SHUTDOWN(mp)) - return -EIO; - - xfs_ilock(ip, XFS_ILOCK_EXCL); - - /* - * Zero length symlinks _can_ exist. - */ - pathlen = (int)ip->i_d.di_size; - if (!pathlen) { - xfs_iunlock(ip, XFS_ILOCK_EXCL); - return 0; - } - - if (pathlen < 0 || pathlen > MAXPATHLEN) { - xfs_alert(mp, "%s: inode (0x%llx) bad symlink length (%d)", - __func__, (unsigned long long)ip->i_ino, pathlen); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - ASSERT(0); - return -EFSCORRUPTED; - } - - if (ip->i_df.if_flags & XFS_IFINLINE) { - if (ip->i_df.if_bytes > 0) - xfs_idata_realloc(ip, -(ip->i_df.if_bytes), - XFS_DATA_FORK); - xfs_iunlock(ip, XFS_ILOCK_EXCL); - ASSERT(ip->i_df.if_bytes == 0); - return 0; - } - - xfs_iunlock(ip, XFS_ILOCK_EXCL); - - /* remove the remote symlink */ - return xfs_inactive_symlink_rmt(ip); -} diff --git a/src/linux/fs/xfs/xfs_symlink.h b/src/linux/fs/xfs/xfs_symlink.h deleted file mode 100644 index e75245d..0000000 --- a/src/linux/fs/xfs/xfs_symlink.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2012 Red Hat, Inc. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_SYMLINK_H -#define __XFS_SYMLINK_H 1 - -/* Kernel only symlink defintions */ - -int xfs_symlink(struct xfs_inode *dp, struct xfs_name *link_name, - const char *target_path, umode_t mode, struct xfs_inode **ipp); -int xfs_readlink(struct xfs_inode *ip, char *link); -int xfs_inactive_symlink(struct xfs_inode *ip); - -#endif /* __XFS_SYMLINK_H */ diff --git a/src/linux/fs/xfs/xfs_sysctl.c b/src/linux/fs/xfs/xfs_sysctl.c deleted file mode 100644 index afe1f66..0000000 --- a/src/linux/fs/xfs/xfs_sysctl.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright (c) 2001-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include -#include -#include "xfs_error.h" -#include "xfs_stats.h" - -static struct ctl_table_header *xfs_table_header; - -#ifdef CONFIG_PROC_FS -STATIC int -xfs_stats_clear_proc_handler( - struct ctl_table *ctl, - int write, - void __user *buffer, - size_t *lenp, - loff_t *ppos) -{ - int ret, *valp = ctl->data; - - ret = proc_dointvec_minmax(ctl, write, buffer, lenp, ppos); - - if (!ret && write && *valp) { - xfs_stats_clearall(xfsstats.xs_stats); - xfs_stats_clear = 0; - } - - return ret; -} - -STATIC int -xfs_panic_mask_proc_handler( - struct ctl_table *ctl, - int write, - void __user *buffer, - size_t *lenp, - loff_t *ppos) -{ - int ret, *valp = ctl->data; - - ret = proc_dointvec_minmax(ctl, write, buffer, lenp, ppos); - if (!ret && write) { - xfs_panic_mask = *valp; -#ifdef DEBUG - xfs_panic_mask |= (XFS_PTAG_SHUTDOWN_CORRUPT | XFS_PTAG_LOGRES); -#endif - } - return ret; -} -#endif /* CONFIG_PROC_FS */ - -static struct ctl_table xfs_table[] = { - { - .procname = "irix_sgid_inherit", - .data = &xfs_params.sgid_inherit.val, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &xfs_params.sgid_inherit.min, - .extra2 = &xfs_params.sgid_inherit.max - }, - { - .procname = "irix_symlink_mode", - .data = &xfs_params.symlink_mode.val, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &xfs_params.symlink_mode.min, - .extra2 = &xfs_params.symlink_mode.max - }, - { - .procname = "panic_mask", - .data = &xfs_params.panic_mask.val, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = xfs_panic_mask_proc_handler, - .extra1 = &xfs_params.panic_mask.min, - .extra2 = &xfs_params.panic_mask.max - }, - - { - .procname = "error_level", - .data = &xfs_params.error_level.val, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &xfs_params.error_level.min, - .extra2 = &xfs_params.error_level.max - }, - { - .procname = "xfssyncd_centisecs", - .data = &xfs_params.syncd_timer.val, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &xfs_params.syncd_timer.min, - .extra2 = &xfs_params.syncd_timer.max - }, - { - .procname = "inherit_sync", - .data = &xfs_params.inherit_sync.val, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &xfs_params.inherit_sync.min, - .extra2 = &xfs_params.inherit_sync.max - }, - { - .procname = "inherit_nodump", - .data = &xfs_params.inherit_nodump.val, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &xfs_params.inherit_nodump.min, - .extra2 = &xfs_params.inherit_nodump.max - }, - { - .procname = "inherit_noatime", - .data = &xfs_params.inherit_noatim.val, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &xfs_params.inherit_noatim.min, - .extra2 = &xfs_params.inherit_noatim.max - }, - { - .procname = "inherit_nosymlinks", - .data = &xfs_params.inherit_nosym.val, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &xfs_params.inherit_nosym.min, - .extra2 = &xfs_params.inherit_nosym.max - }, - { - .procname = "rotorstep", - .data = &xfs_params.rotorstep.val, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &xfs_params.rotorstep.min, - .extra2 = &xfs_params.rotorstep.max - }, - { - .procname = "inherit_nodefrag", - .data = &xfs_params.inherit_nodfrg.val, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &xfs_params.inherit_nodfrg.min, - .extra2 = &xfs_params.inherit_nodfrg.max - }, - { - .procname = "filestream_centisecs", - .data = &xfs_params.fstrm_timer.val, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &xfs_params.fstrm_timer.min, - .extra2 = &xfs_params.fstrm_timer.max, - }, - { - .procname = "speculative_prealloc_lifetime", - .data = &xfs_params.eofb_timer.val, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &xfs_params.eofb_timer.min, - .extra2 = &xfs_params.eofb_timer.max, - }, - { - .procname = "speculative_cow_prealloc_lifetime", - .data = &xfs_params.cowb_timer.val, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &xfs_params.cowb_timer.min, - .extra2 = &xfs_params.cowb_timer.max, - }, - /* please keep this the last entry */ -#ifdef CONFIG_PROC_FS - { - .procname = "stats_clear", - .data = &xfs_params.stats_clear.val, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = xfs_stats_clear_proc_handler, - .extra1 = &xfs_params.stats_clear.min, - .extra2 = &xfs_params.stats_clear.max - }, -#endif /* CONFIG_PROC_FS */ - - {} -}; - -static struct ctl_table xfs_dir_table[] = { - { - .procname = "xfs", - .mode = 0555, - .child = xfs_table - }, - {} -}; - -static struct ctl_table xfs_root_table[] = { - { - .procname = "fs", - .mode = 0555, - .child = xfs_dir_table - }, - {} -}; - -int -xfs_sysctl_register(void) -{ - xfs_table_header = register_sysctl_table(xfs_root_table); - if (!xfs_table_header) - return -ENOMEM; - return 0; -} - -void -xfs_sysctl_unregister(void) -{ - unregister_sysctl_table(xfs_table_header); -} diff --git a/src/linux/fs/xfs/xfs_sysctl.h b/src/linux/fs/xfs/xfs_sysctl.h deleted file mode 100644 index 984a349..0000000 --- a/src/linux/fs/xfs/xfs_sysctl.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2001-2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_SYSCTL_H__ -#define __XFS_SYSCTL_H__ - -#include - -/* - * Tunable xfs parameters - */ - -typedef struct xfs_sysctl_val { - int min; - int val; - int max; -} xfs_sysctl_val_t; - -typedef struct xfs_param { - xfs_sysctl_val_t sgid_inherit; /* Inherit S_ISGID if process' GID is - * not a member of parent dir GID. */ - xfs_sysctl_val_t symlink_mode; /* Link creat mode affected by umask */ - xfs_sysctl_val_t panic_mask; /* bitmask to cause panic on errors. */ - xfs_sysctl_val_t error_level; /* Degree of reporting for problems */ - xfs_sysctl_val_t syncd_timer; /* Interval between xfssyncd wakeups */ - xfs_sysctl_val_t stats_clear; /* Reset all XFS statistics to zero. */ - xfs_sysctl_val_t inherit_sync; /* Inherit the "sync" inode flag. */ - xfs_sysctl_val_t inherit_nodump;/* Inherit the "nodump" inode flag. */ - xfs_sysctl_val_t inherit_noatim;/* Inherit the "noatime" inode flag. */ - xfs_sysctl_val_t xfs_buf_timer; /* Interval between xfsbufd wakeups. */ - xfs_sysctl_val_t xfs_buf_age; /* Metadata buffer age before flush. */ - xfs_sysctl_val_t inherit_nosym; /* Inherit the "nosymlinks" flag. */ - xfs_sysctl_val_t rotorstep; /* inode32 AG rotoring control knob */ - xfs_sysctl_val_t inherit_nodfrg;/* Inherit the "nodefrag" inode flag. */ - xfs_sysctl_val_t fstrm_timer; /* Filestream dir-AG assoc'n timeout. */ - xfs_sysctl_val_t eofb_timer; /* Interval between eofb scan wakeups */ - xfs_sysctl_val_t cowb_timer; /* Interval between cowb scan wakeups */ -} xfs_param_t; - -/* - * xfs_error_level: - * - * How much error reporting will be done when internal problems are - * encountered. These problems normally return an EFSCORRUPTED to their - * caller, with no other information reported. - * - * 0 No error reports - * 1 Report EFSCORRUPTED errors that will cause a filesystem shutdown - * 5 Report all EFSCORRUPTED errors (all of the above errors, plus any - * additional errors that are known to not cause shutdowns) - * - * xfs_panic_mask bit 0x8 turns the error reports into panics - */ - -enum { - /* XFS_REFCACHE_SIZE = 1 */ - /* XFS_REFCACHE_PURGE = 2 */ - /* XFS_RESTRICT_CHOWN = 3 */ - XFS_SGID_INHERIT = 4, - XFS_SYMLINK_MODE = 5, - XFS_PANIC_MASK = 6, - XFS_ERRLEVEL = 7, - XFS_SYNCD_TIMER = 8, - /* XFS_PROBE_DMAPI = 9 */ - /* XFS_PROBE_IOOPS = 10 */ - /* XFS_PROBE_QUOTA = 11 */ - XFS_STATS_CLEAR = 12, - XFS_INHERIT_SYNC = 13, - XFS_INHERIT_NODUMP = 14, - XFS_INHERIT_NOATIME = 15, - XFS_BUF_TIMER = 16, - XFS_BUF_AGE = 17, - /* XFS_IO_BYPASS = 18 */ - XFS_INHERIT_NOSYM = 19, - XFS_ROTORSTEP = 20, - XFS_INHERIT_NODFRG = 21, - XFS_FILESTREAM_TIMER = 22, -}; - -extern xfs_param_t xfs_params; - -struct xfs_globals { - int log_recovery_delay; /* log recovery delay (secs) */ -}; -extern struct xfs_globals xfs_globals; - -#ifdef CONFIG_SYSCTL -extern int xfs_sysctl_register(void); -extern void xfs_sysctl_unregister(void); -#else -# define xfs_sysctl_register() (0) -# define xfs_sysctl_unregister() do { } while (0) -#endif /* CONFIG_SYSCTL */ - -#endif /* __XFS_SYSCTL_H__ */ diff --git a/src/linux/fs/xfs/xfs_sysfs.c b/src/linux/fs/xfs/xfs_sysfs.c deleted file mode 100644 index 276d302..0000000 --- a/src/linux/fs/xfs/xfs_sysfs.c +++ /dev/null @@ -1,679 +0,0 @@ -/* - * Copyright (c) 2014 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "xfs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_sysfs.h" -#include "xfs_log.h" -#include "xfs_log_priv.h" -#include "xfs_stats.h" -#include "xfs_mount.h" - -struct xfs_sysfs_attr { - struct attribute attr; - ssize_t (*show)(struct kobject *kobject, char *buf); - ssize_t (*store)(struct kobject *kobject, const char *buf, - size_t count); -}; - -static inline struct xfs_sysfs_attr * -to_attr(struct attribute *attr) -{ - return container_of(attr, struct xfs_sysfs_attr, attr); -} - -#define XFS_SYSFS_ATTR_RW(name) \ - static struct xfs_sysfs_attr xfs_sysfs_attr_##name = __ATTR_RW(name) -#define XFS_SYSFS_ATTR_RO(name) \ - static struct xfs_sysfs_attr xfs_sysfs_attr_##name = __ATTR_RO(name) -#define XFS_SYSFS_ATTR_WO(name) \ - static struct xfs_sysfs_attr xfs_sysfs_attr_##name = __ATTR_WO(name) - -#define ATTR_LIST(name) &xfs_sysfs_attr_##name.attr - -STATIC ssize_t -xfs_sysfs_object_show( - struct kobject *kobject, - struct attribute *attr, - char *buf) -{ - struct xfs_sysfs_attr *xfs_attr = to_attr(attr); - - return xfs_attr->show ? xfs_attr->show(kobject, buf) : 0; -} - -STATIC ssize_t -xfs_sysfs_object_store( - struct kobject *kobject, - struct attribute *attr, - const char *buf, - size_t count) -{ - struct xfs_sysfs_attr *xfs_attr = to_attr(attr); - - return xfs_attr->store ? xfs_attr->store(kobject, buf, count) : 0; -} - -static const struct sysfs_ops xfs_sysfs_ops = { - .show = xfs_sysfs_object_show, - .store = xfs_sysfs_object_store, -}; - -/* - * xfs_mount kobject. The mp kobject also serves as the per-mount parent object - * that is identified by the fsname under sysfs. - */ - -static inline struct xfs_mount * -to_mp(struct kobject *kobject) -{ - struct xfs_kobj *kobj = to_kobj(kobject); - - return container_of(kobj, struct xfs_mount, m_kobj); -} - -#ifdef DEBUG - -STATIC ssize_t -fail_writes_store( - struct kobject *kobject, - const char *buf, - size_t count) -{ - struct xfs_mount *mp = to_mp(kobject); - int ret; - int val; - - ret = kstrtoint(buf, 0, &val); - if (ret) - return ret; - - if (val == 1) - mp->m_fail_writes = true; - else if (val == 0) - mp->m_fail_writes = false; - else - return -EINVAL; - - return count; -} - -STATIC ssize_t -fail_writes_show( - struct kobject *kobject, - char *buf) -{ - struct xfs_mount *mp = to_mp(kobject); - - return snprintf(buf, PAGE_SIZE, "%d\n", mp->m_fail_writes ? 1 : 0); -} -XFS_SYSFS_ATTR_RW(fail_writes); - -#endif /* DEBUG */ - -static struct attribute *xfs_mp_attrs[] = { -#ifdef DEBUG - ATTR_LIST(fail_writes), -#endif - NULL, -}; - -struct kobj_type xfs_mp_ktype = { - .release = xfs_sysfs_release, - .sysfs_ops = &xfs_sysfs_ops, - .default_attrs = xfs_mp_attrs, -}; - -#ifdef DEBUG -/* debug */ - -STATIC ssize_t -log_recovery_delay_store( - struct kobject *kobject, - const char *buf, - size_t count) -{ - int ret; - int val; - - ret = kstrtoint(buf, 0, &val); - if (ret) - return ret; - - if (val < 0 || val > 60) - return -EINVAL; - - xfs_globals.log_recovery_delay = val; - - return count; -} - -STATIC ssize_t -log_recovery_delay_show( - struct kobject *kobject, - char *buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", xfs_globals.log_recovery_delay); -} -XFS_SYSFS_ATTR_RW(log_recovery_delay); - -static struct attribute *xfs_dbg_attrs[] = { - ATTR_LIST(log_recovery_delay), - NULL, -}; - -struct kobj_type xfs_dbg_ktype = { - .release = xfs_sysfs_release, - .sysfs_ops = &xfs_sysfs_ops, - .default_attrs = xfs_dbg_attrs, -}; - -#endif /* DEBUG */ - -/* stats */ - -static inline struct xstats * -to_xstats(struct kobject *kobject) -{ - struct xfs_kobj *kobj = to_kobj(kobject); - - return container_of(kobj, struct xstats, xs_kobj); -} - -STATIC ssize_t -stats_show( - struct kobject *kobject, - char *buf) -{ - struct xstats *stats = to_xstats(kobject); - - return xfs_stats_format(stats->xs_stats, buf); -} -XFS_SYSFS_ATTR_RO(stats); - -STATIC ssize_t -stats_clear_store( - struct kobject *kobject, - const char *buf, - size_t count) -{ - int ret; - int val; - struct xstats *stats = to_xstats(kobject); - - ret = kstrtoint(buf, 0, &val); - if (ret) - return ret; - - if (val != 1) - return -EINVAL; - - xfs_stats_clearall(stats->xs_stats); - return count; -} -XFS_SYSFS_ATTR_WO(stats_clear); - -static struct attribute *xfs_stats_attrs[] = { - ATTR_LIST(stats), - ATTR_LIST(stats_clear), - NULL, -}; - -struct kobj_type xfs_stats_ktype = { - .release = xfs_sysfs_release, - .sysfs_ops = &xfs_sysfs_ops, - .default_attrs = xfs_stats_attrs, -}; - -/* xlog */ - -static inline struct xlog * -to_xlog(struct kobject *kobject) -{ - struct xfs_kobj *kobj = to_kobj(kobject); - - return container_of(kobj, struct xlog, l_kobj); -} - -STATIC ssize_t -log_head_lsn_show( - struct kobject *kobject, - char *buf) -{ - int cycle; - int block; - struct xlog *log = to_xlog(kobject); - - spin_lock(&log->l_icloglock); - cycle = log->l_curr_cycle; - block = log->l_curr_block; - spin_unlock(&log->l_icloglock); - - return snprintf(buf, PAGE_SIZE, "%d:%d\n", cycle, block); -} -XFS_SYSFS_ATTR_RO(log_head_lsn); - -STATIC ssize_t -log_tail_lsn_show( - struct kobject *kobject, - char *buf) -{ - int cycle; - int block; - struct xlog *log = to_xlog(kobject); - - xlog_crack_atomic_lsn(&log->l_tail_lsn, &cycle, &block); - return snprintf(buf, PAGE_SIZE, "%d:%d\n", cycle, block); -} -XFS_SYSFS_ATTR_RO(log_tail_lsn); - -STATIC ssize_t -reserve_grant_head_show( - struct kobject *kobject, - char *buf) - -{ - int cycle; - int bytes; - struct xlog *log = to_xlog(kobject); - - xlog_crack_grant_head(&log->l_reserve_head.grant, &cycle, &bytes); - return snprintf(buf, PAGE_SIZE, "%d:%d\n", cycle, bytes); -} -XFS_SYSFS_ATTR_RO(reserve_grant_head); - -STATIC ssize_t -write_grant_head_show( - struct kobject *kobject, - char *buf) -{ - int cycle; - int bytes; - struct xlog *log = to_xlog(kobject); - - xlog_crack_grant_head(&log->l_write_head.grant, &cycle, &bytes); - return snprintf(buf, PAGE_SIZE, "%d:%d\n", cycle, bytes); -} -XFS_SYSFS_ATTR_RO(write_grant_head); - -#ifdef DEBUG -STATIC ssize_t -log_badcrc_factor_store( - struct kobject *kobject, - const char *buf, - size_t count) -{ - struct xlog *log = to_xlog(kobject); - int ret; - uint32_t val; - - ret = kstrtouint(buf, 0, &val); - if (ret) - return ret; - - log->l_badcrc_factor = val; - - return count; -} - -STATIC ssize_t -log_badcrc_factor_show( - struct kobject *kobject, - char *buf) -{ - struct xlog *log = to_xlog(kobject); - - return snprintf(buf, PAGE_SIZE, "%d\n", log->l_badcrc_factor); -} - -XFS_SYSFS_ATTR_RW(log_badcrc_factor); -#endif /* DEBUG */ - -static struct attribute *xfs_log_attrs[] = { - ATTR_LIST(log_head_lsn), - ATTR_LIST(log_tail_lsn), - ATTR_LIST(reserve_grant_head), - ATTR_LIST(write_grant_head), -#ifdef DEBUG - ATTR_LIST(log_badcrc_factor), -#endif - NULL, -}; - -struct kobj_type xfs_log_ktype = { - .release = xfs_sysfs_release, - .sysfs_ops = &xfs_sysfs_ops, - .default_attrs = xfs_log_attrs, -}; - -/* - * Metadata IO error configuration - * - * The sysfs structure here is: - * ...xfs//error/// - * - * where allows us to discriminate between data IO and metadata IO, - * and any other future type of IO (e.g. special inode or directory error - * handling) we care to support. - */ -static inline struct xfs_error_cfg * -to_error_cfg(struct kobject *kobject) -{ - struct xfs_kobj *kobj = to_kobj(kobject); - return container_of(kobj, struct xfs_error_cfg, kobj); -} - -static inline struct xfs_mount * -err_to_mp(struct kobject *kobject) -{ - struct xfs_kobj *kobj = to_kobj(kobject); - return container_of(kobj, struct xfs_mount, m_error_kobj); -} - -static ssize_t -max_retries_show( - struct kobject *kobject, - char *buf) -{ - int retries; - struct xfs_error_cfg *cfg = to_error_cfg(kobject); - - if (cfg->retry_timeout == XFS_ERR_RETRY_FOREVER) - retries = -1; - else - retries = cfg->max_retries; - - return snprintf(buf, PAGE_SIZE, "%d\n", retries); -} - -static ssize_t -max_retries_store( - struct kobject *kobject, - const char *buf, - size_t count) -{ - struct xfs_error_cfg *cfg = to_error_cfg(kobject); - int ret; - int val; - - ret = kstrtoint(buf, 0, &val); - if (ret) - return ret; - - if (val < -1) - return -EINVAL; - - if (val == -1) - cfg->retry_timeout = XFS_ERR_RETRY_FOREVER; - else - cfg->max_retries = val; - return count; -} -XFS_SYSFS_ATTR_RW(max_retries); - -static ssize_t -retry_timeout_seconds_show( - struct kobject *kobject, - char *buf) -{ - int timeout; - struct xfs_error_cfg *cfg = to_error_cfg(kobject); - - if (cfg->retry_timeout == XFS_ERR_RETRY_FOREVER) - timeout = -1; - else - timeout = jiffies_to_msecs(cfg->retry_timeout) / MSEC_PER_SEC; - - return snprintf(buf, PAGE_SIZE, "%d\n", timeout); -} - -static ssize_t -retry_timeout_seconds_store( - struct kobject *kobject, - const char *buf, - size_t count) -{ - struct xfs_error_cfg *cfg = to_error_cfg(kobject); - int ret; - int val; - - ret = kstrtoint(buf, 0, &val); - if (ret) - return ret; - - /* 1 day timeout maximum, -1 means infinite */ - if (val < -1 || val > 86400) - return -EINVAL; - - if (val == -1) - cfg->retry_timeout = XFS_ERR_RETRY_FOREVER; - else { - cfg->retry_timeout = msecs_to_jiffies(val * MSEC_PER_SEC); - ASSERT(msecs_to_jiffies(val * MSEC_PER_SEC) < LONG_MAX); - } - return count; -} -XFS_SYSFS_ATTR_RW(retry_timeout_seconds); - -static ssize_t -fail_at_unmount_show( - struct kobject *kobject, - char *buf) -{ - struct xfs_mount *mp = err_to_mp(kobject); - - return snprintf(buf, PAGE_SIZE, "%d\n", mp->m_fail_unmount); -} - -static ssize_t -fail_at_unmount_store( - struct kobject *kobject, - const char *buf, - size_t count) -{ - struct xfs_mount *mp = err_to_mp(kobject); - int ret; - int val; - - ret = kstrtoint(buf, 0, &val); - if (ret) - return ret; - - if (val < 0 || val > 1) - return -EINVAL; - - mp->m_fail_unmount = val; - return count; -} -XFS_SYSFS_ATTR_RW(fail_at_unmount); - -static struct attribute *xfs_error_attrs[] = { - ATTR_LIST(max_retries), - ATTR_LIST(retry_timeout_seconds), - NULL, -}; - - -static struct kobj_type xfs_error_cfg_ktype = { - .release = xfs_sysfs_release, - .sysfs_ops = &xfs_sysfs_ops, - .default_attrs = xfs_error_attrs, -}; - -static struct kobj_type xfs_error_ktype = { - .release = xfs_sysfs_release, - .sysfs_ops = &xfs_sysfs_ops, -}; - -/* - * Error initialization tables. These need to be ordered in the same - * order as the enums used to index the array. All class init tables need to - * define a "default" behaviour as the first entry, all other entries can be - * empty. - */ -struct xfs_error_init { - char *name; - int max_retries; - int retry_timeout; /* in seconds */ -}; - -static const struct xfs_error_init xfs_error_meta_init[XFS_ERR_ERRNO_MAX] = { - { .name = "default", - .max_retries = XFS_ERR_RETRY_FOREVER, - .retry_timeout = XFS_ERR_RETRY_FOREVER, - }, - { .name = "EIO", - .max_retries = XFS_ERR_RETRY_FOREVER, - .retry_timeout = XFS_ERR_RETRY_FOREVER, - }, - { .name = "ENOSPC", - .max_retries = XFS_ERR_RETRY_FOREVER, - .retry_timeout = XFS_ERR_RETRY_FOREVER, - }, - { .name = "ENODEV", - .max_retries = 0, /* We can't recover from devices disappearing */ - .retry_timeout = 0, - }, -}; - -static int -xfs_error_sysfs_init_class( - struct xfs_mount *mp, - int class, - const char *parent_name, - struct xfs_kobj *parent_kobj, - const struct xfs_error_init init[]) -{ - struct xfs_error_cfg *cfg; - int error; - int i; - - ASSERT(class < XFS_ERR_CLASS_MAX); - - error = xfs_sysfs_init(parent_kobj, &xfs_error_ktype, - &mp->m_error_kobj, parent_name); - if (error) - return error; - - for (i = 0; i < XFS_ERR_ERRNO_MAX; i++) { - cfg = &mp->m_error_cfg[class][i]; - error = xfs_sysfs_init(&cfg->kobj, &xfs_error_cfg_ktype, - parent_kobj, init[i].name); - if (error) - goto out_error; - - cfg->max_retries = init[i].max_retries; - if (init[i].retry_timeout == XFS_ERR_RETRY_FOREVER) - cfg->retry_timeout = XFS_ERR_RETRY_FOREVER; - else - cfg->retry_timeout = msecs_to_jiffies( - init[i].retry_timeout * MSEC_PER_SEC); - } - return 0; - -out_error: - /* unwind the entries that succeeded */ - for (i--; i >= 0; i--) { - cfg = &mp->m_error_cfg[class][i]; - xfs_sysfs_del(&cfg->kobj); - } - xfs_sysfs_del(parent_kobj); - return error; -} - -int -xfs_error_sysfs_init( - struct xfs_mount *mp) -{ - int error; - - /* .../xfs//error/ */ - error = xfs_sysfs_init(&mp->m_error_kobj, &xfs_error_ktype, - &mp->m_kobj, "error"); - if (error) - return error; - - error = sysfs_create_file(&mp->m_error_kobj.kobject, - ATTR_LIST(fail_at_unmount)); - - if (error) - goto out_error; - - /* .../xfs//error/metadata/ */ - error = xfs_error_sysfs_init_class(mp, XFS_ERR_METADATA, - "metadata", &mp->m_error_meta_kobj, - xfs_error_meta_init); - if (error) - goto out_error; - - return 0; - -out_error: - xfs_sysfs_del(&mp->m_error_kobj); - return error; -} - -void -xfs_error_sysfs_del( - struct xfs_mount *mp) -{ - struct xfs_error_cfg *cfg; - int i, j; - - for (i = 0; i < XFS_ERR_CLASS_MAX; i++) { - for (j = 0; j < XFS_ERR_ERRNO_MAX; j++) { - cfg = &mp->m_error_cfg[i][j]; - - xfs_sysfs_del(&cfg->kobj); - } - } - xfs_sysfs_del(&mp->m_error_meta_kobj); - xfs_sysfs_del(&mp->m_error_kobj); -} - -struct xfs_error_cfg * -xfs_error_get_cfg( - struct xfs_mount *mp, - int error_class, - int error) -{ - struct xfs_error_cfg *cfg; - - if (error < 0) - error = -error; - - switch (error) { - case EIO: - cfg = &mp->m_error_cfg[error_class][XFS_ERR_EIO]; - break; - case ENOSPC: - cfg = &mp->m_error_cfg[error_class][XFS_ERR_ENOSPC]; - break; - case ENODEV: - cfg = &mp->m_error_cfg[error_class][XFS_ERR_ENODEV]; - break; - default: - cfg = &mp->m_error_cfg[error_class][XFS_ERR_DEFAULT]; - break; - } - - return cfg; -} diff --git a/src/linux/fs/xfs/xfs_sysfs.h b/src/linux/fs/xfs/xfs_sysfs.h deleted file mode 100644 index d046371..0000000 --- a/src/linux/fs/xfs/xfs_sysfs.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2014 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#ifndef __XFS_SYSFS_H__ -#define __XFS_SYSFS_H__ - -extern struct kobj_type xfs_mp_ktype; /* xfs_mount */ -extern struct kobj_type xfs_dbg_ktype; /* debug */ -extern struct kobj_type xfs_log_ktype; /* xlog */ -extern struct kobj_type xfs_stats_ktype; /* stats */ - -static inline struct xfs_kobj * -to_kobj(struct kobject *kobject) -{ - return container_of(kobject, struct xfs_kobj, kobject); -} - -static inline void -xfs_sysfs_release(struct kobject *kobject) -{ - struct xfs_kobj *kobj = to_kobj(kobject); - complete(&kobj->complete); -} - -static inline int -xfs_sysfs_init( - struct xfs_kobj *kobj, - struct kobj_type *ktype, - struct xfs_kobj *parent_kobj, - const char *name) -{ - init_completion(&kobj->complete); - return kobject_init_and_add(&kobj->kobject, ktype, - &parent_kobj->kobject, "%s", name); -} - -static inline void -xfs_sysfs_del( - struct xfs_kobj *kobj) -{ - kobject_del(&kobj->kobject); - kobject_put(&kobj->kobject); - wait_for_completion(&kobj->complete); -} - -int xfs_error_sysfs_init(struct xfs_mount *mp); -void xfs_error_sysfs_del(struct xfs_mount *mp); - -#endif /* __XFS_SYSFS_H__ */ diff --git a/src/linux/fs/xfs/xfs_trace.c b/src/linux/fs/xfs/xfs_trace.c deleted file mode 100644 index 7f17ae6..0000000 --- a/src/linux/fs/xfs/xfs_trace.c +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2009, Christoph Hellwig - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_da_format.h" -#include "xfs_defer.h" -#include "xfs_inode.h" -#include "xfs_btree.h" -#include "xfs_da_btree.h" -#include "xfs_ialloc.h" -#include "xfs_itable.h" -#include "xfs_alloc.h" -#include "xfs_bmap.h" -#include "xfs_attr.h" -#include "xfs_attr_leaf.h" -#include "xfs_trans.h" -#include "xfs_log.h" -#include "xfs_log_priv.h" -#include "xfs_buf_item.h" -#include "xfs_quota.h" -#include "xfs_iomap.h" -#include "xfs_aops.h" -#include "xfs_dquot_item.h" -#include "xfs_dquot.h" -#include "xfs_log_recover.h" -#include "xfs_inode_item.h" -#include "xfs_bmap_btree.h" -#include "xfs_filestream.h" - -/* - * We include this last to have the helpers above available for the trace - * event implementations. - */ -#define CREATE_TRACE_POINTS -#include "xfs_trace.h" diff --git a/src/linux/fs/xfs/xfs_trace.h b/src/linux/fs/xfs/xfs_trace.h deleted file mode 100644 index 0907752..0000000 --- a/src/linux/fs/xfs/xfs_trace.h +++ /dev/null @@ -1,3383 +0,0 @@ -/* - * Copyright (c) 2009, Christoph Hellwig - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM xfs - -#if !defined(_TRACE_XFS_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_XFS_H - -#include - -struct xfs_agf; -struct xfs_alloc_arg; -struct xfs_attr_list_context; -struct xfs_buf_log_item; -struct xfs_da_args; -struct xfs_da_node_entry; -struct xfs_dquot; -struct xfs_log_item; -struct xlog; -struct xlog_ticket; -struct xlog_recover; -struct xlog_recover_item; -struct xfs_buf_log_format; -struct xfs_inode_log_format; -struct xfs_bmbt_irec; -struct xfs_btree_cur; -struct xfs_refcount_irec; - -DECLARE_EVENT_CLASS(xfs_attr_list_class, - TP_PROTO(struct xfs_attr_list_context *ctx), - TP_ARGS(ctx), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(u32, hashval) - __field(u32, blkno) - __field(u32, offset) - __field(void *, alist) - __field(int, bufsize) - __field(int, count) - __field(int, firstu) - __field(int, dupcnt) - __field(int, flags) - ), - TP_fast_assign( - __entry->dev = VFS_I(ctx->dp)->i_sb->s_dev; - __entry->ino = ctx->dp->i_ino; - __entry->hashval = ctx->cursor->hashval; - __entry->blkno = ctx->cursor->blkno; - __entry->offset = ctx->cursor->offset; - __entry->alist = ctx->alist; - __entry->bufsize = ctx->bufsize; - __entry->count = ctx->count; - __entry->firstu = ctx->firstu; - __entry->flags = ctx->flags; - ), - TP_printk("dev %d:%d ino 0x%llx cursor h/b/o 0x%x/0x%x/%u dupcnt %u " - "alist 0x%p size %u count %u firstu %u flags %d %s", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->hashval, - __entry->blkno, - __entry->offset, - __entry->dupcnt, - __entry->alist, - __entry->bufsize, - __entry->count, - __entry->firstu, - __entry->flags, - __print_flags(__entry->flags, "|", XFS_ATTR_FLAGS) - ) -) - -#define DEFINE_ATTR_LIST_EVENT(name) \ -DEFINE_EVENT(xfs_attr_list_class, name, \ - TP_PROTO(struct xfs_attr_list_context *ctx), \ - TP_ARGS(ctx)) -DEFINE_ATTR_LIST_EVENT(xfs_attr_list_sf); -DEFINE_ATTR_LIST_EVENT(xfs_attr_list_sf_all); -DEFINE_ATTR_LIST_EVENT(xfs_attr_list_leaf); -DEFINE_ATTR_LIST_EVENT(xfs_attr_list_leaf_end); -DEFINE_ATTR_LIST_EVENT(xfs_attr_list_full); -DEFINE_ATTR_LIST_EVENT(xfs_attr_list_add); -DEFINE_ATTR_LIST_EVENT(xfs_attr_list_wrong_blk); -DEFINE_ATTR_LIST_EVENT(xfs_attr_list_notfound); -DEFINE_ATTR_LIST_EVENT(xfs_attr_leaf_list); -DEFINE_ATTR_LIST_EVENT(xfs_attr_node_list); - -DECLARE_EVENT_CLASS(xfs_perag_class, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, int refcount, - unsigned long caller_ip), - TP_ARGS(mp, agno, refcount, caller_ip), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(int, refcount) - __field(unsigned long, caller_ip) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->refcount = refcount; - __entry->caller_ip = caller_ip; - ), - TP_printk("dev %d:%d agno %u refcount %d caller %ps", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno, - __entry->refcount, - (char *)__entry->caller_ip) -); - -#define DEFINE_PERAG_REF_EVENT(name) \ -DEFINE_EVENT(xfs_perag_class, name, \ - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, int refcount, \ - unsigned long caller_ip), \ - TP_ARGS(mp, agno, refcount, caller_ip)) -DEFINE_PERAG_REF_EVENT(xfs_perag_get); -DEFINE_PERAG_REF_EVENT(xfs_perag_get_tag); -DEFINE_PERAG_REF_EVENT(xfs_perag_put); -DEFINE_PERAG_REF_EVENT(xfs_perag_set_reclaim); -DEFINE_PERAG_REF_EVENT(xfs_perag_clear_reclaim); -DEFINE_PERAG_REF_EVENT(xfs_perag_set_eofblocks); -DEFINE_PERAG_REF_EVENT(xfs_perag_clear_eofblocks); -DEFINE_PERAG_REF_EVENT(xfs_perag_set_cowblocks); -DEFINE_PERAG_REF_EVENT(xfs_perag_clear_cowblocks); - -DECLARE_EVENT_CLASS(xfs_ag_class, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno), - TP_ARGS(mp, agno), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - ), - TP_printk("dev %d:%d agno %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno) -); -#define DEFINE_AG_EVENT(name) \ -DEFINE_EVENT(xfs_ag_class, name, \ - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno), \ - TP_ARGS(mp, agno)) - -DEFINE_AG_EVENT(xfs_read_agf); -DEFINE_AG_EVENT(xfs_alloc_read_agf); -DEFINE_AG_EVENT(xfs_read_agi); -DEFINE_AG_EVENT(xfs_ialloc_read_agi); - -TRACE_EVENT(xfs_attr_list_node_descend, - TP_PROTO(struct xfs_attr_list_context *ctx, - struct xfs_da_node_entry *btree), - TP_ARGS(ctx, btree), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(u32, hashval) - __field(u32, blkno) - __field(u32, offset) - __field(void *, alist) - __field(int, bufsize) - __field(int, count) - __field(int, firstu) - __field(int, dupcnt) - __field(int, flags) - __field(u32, bt_hashval) - __field(u32, bt_before) - ), - TP_fast_assign( - __entry->dev = VFS_I(ctx->dp)->i_sb->s_dev; - __entry->ino = ctx->dp->i_ino; - __entry->hashval = ctx->cursor->hashval; - __entry->blkno = ctx->cursor->blkno; - __entry->offset = ctx->cursor->offset; - __entry->alist = ctx->alist; - __entry->bufsize = ctx->bufsize; - __entry->count = ctx->count; - __entry->firstu = ctx->firstu; - __entry->flags = ctx->flags; - __entry->bt_hashval = be32_to_cpu(btree->hashval); - __entry->bt_before = be32_to_cpu(btree->before); - ), - TP_printk("dev %d:%d ino 0x%llx cursor h/b/o 0x%x/0x%x/%u dupcnt %u " - "alist 0x%p size %u count %u firstu %u flags %d %s " - "node hashval %u, node before %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->hashval, - __entry->blkno, - __entry->offset, - __entry->dupcnt, - __entry->alist, - __entry->bufsize, - __entry->count, - __entry->firstu, - __entry->flags, - __print_flags(__entry->flags, "|", XFS_ATTR_FLAGS), - __entry->bt_hashval, - __entry->bt_before) -); - -TRACE_EVENT(xfs_iext_insert, - TP_PROTO(struct xfs_inode *ip, xfs_extnum_t idx, - struct xfs_bmbt_irec *r, int state, unsigned long caller_ip), - TP_ARGS(ip, idx, r, state, caller_ip), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(xfs_extnum_t, idx) - __field(xfs_fileoff_t, startoff) - __field(xfs_fsblock_t, startblock) - __field(xfs_filblks_t, blockcount) - __field(xfs_exntst_t, state) - __field(int, bmap_state) - __field(unsigned long, caller_ip) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->idx = idx; - __entry->startoff = r->br_startoff; - __entry->startblock = r->br_startblock; - __entry->blockcount = r->br_blockcount; - __entry->state = r->br_state; - __entry->bmap_state = state; - __entry->caller_ip = caller_ip; - ), - TP_printk("dev %d:%d ino 0x%llx state %s idx %ld " - "offset %lld block %lld count %lld flag %d caller %ps", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __print_flags(__entry->bmap_state, "|", XFS_BMAP_EXT_FLAGS), - (long)__entry->idx, - __entry->startoff, - (__int64_t)__entry->startblock, - __entry->blockcount, - __entry->state, - (char *)__entry->caller_ip) -); - -DECLARE_EVENT_CLASS(xfs_bmap_class, - TP_PROTO(struct xfs_inode *ip, xfs_extnum_t idx, int state, - unsigned long caller_ip), - TP_ARGS(ip, idx, state, caller_ip), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(xfs_extnum_t, idx) - __field(xfs_fileoff_t, startoff) - __field(xfs_fsblock_t, startblock) - __field(xfs_filblks_t, blockcount) - __field(xfs_exntst_t, state) - __field(int, bmap_state) - __field(unsigned long, caller_ip) - ), - TP_fast_assign( - struct xfs_ifork *ifp; - struct xfs_bmbt_irec r; - - ifp = xfs_iext_state_to_fork(ip, state); - xfs_bmbt_get_all(xfs_iext_get_ext(ifp, idx), &r); - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->idx = idx; - __entry->startoff = r.br_startoff; - __entry->startblock = r.br_startblock; - __entry->blockcount = r.br_blockcount; - __entry->state = r.br_state; - __entry->bmap_state = state; - __entry->caller_ip = caller_ip; - ), - TP_printk("dev %d:%d ino 0x%llx state %s idx %ld " - "offset %lld block %lld count %lld flag %d caller %ps", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __print_flags(__entry->bmap_state, "|", XFS_BMAP_EXT_FLAGS), - (long)__entry->idx, - __entry->startoff, - (__int64_t)__entry->startblock, - __entry->blockcount, - __entry->state, - (char *)__entry->caller_ip) -) - -#define DEFINE_BMAP_EVENT(name) \ -DEFINE_EVENT(xfs_bmap_class, name, \ - TP_PROTO(struct xfs_inode *ip, xfs_extnum_t idx, int state, \ - unsigned long caller_ip), \ - TP_ARGS(ip, idx, state, caller_ip)) -DEFINE_BMAP_EVENT(xfs_iext_remove); -DEFINE_BMAP_EVENT(xfs_bmap_pre_update); -DEFINE_BMAP_EVENT(xfs_bmap_post_update); -DEFINE_BMAP_EVENT(xfs_extlist); - -DECLARE_EVENT_CLASS(xfs_buf_class, - TP_PROTO(struct xfs_buf *bp, unsigned long caller_ip), - TP_ARGS(bp, caller_ip), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_daddr_t, bno) - __field(int, nblks) - __field(int, hold) - __field(int, pincount) - __field(unsigned, lockval) - __field(unsigned, flags) - __field(unsigned long, caller_ip) - ), - TP_fast_assign( - __entry->dev = bp->b_target->bt_dev; - __entry->bno = bp->b_bn; - __entry->nblks = bp->b_length; - __entry->hold = atomic_read(&bp->b_hold); - __entry->pincount = atomic_read(&bp->b_pin_count); - __entry->lockval = bp->b_sema.count; - __entry->flags = bp->b_flags; - __entry->caller_ip = caller_ip; - ), - TP_printk("dev %d:%d bno 0x%llx nblks 0x%x hold %d pincount %d " - "lock %d flags %s caller %ps", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long long)__entry->bno, - __entry->nblks, - __entry->hold, - __entry->pincount, - __entry->lockval, - __print_flags(__entry->flags, "|", XFS_BUF_FLAGS), - (void *)__entry->caller_ip) -) - -#define DEFINE_BUF_EVENT(name) \ -DEFINE_EVENT(xfs_buf_class, name, \ - TP_PROTO(struct xfs_buf *bp, unsigned long caller_ip), \ - TP_ARGS(bp, caller_ip)) -DEFINE_BUF_EVENT(xfs_buf_init); -DEFINE_BUF_EVENT(xfs_buf_free); -DEFINE_BUF_EVENT(xfs_buf_hold); -DEFINE_BUF_EVENT(xfs_buf_rele); -DEFINE_BUF_EVENT(xfs_buf_iodone); -DEFINE_BUF_EVENT(xfs_buf_submit); -DEFINE_BUF_EVENT(xfs_buf_submit_wait); -DEFINE_BUF_EVENT(xfs_buf_bawrite); -DEFINE_BUF_EVENT(xfs_buf_lock); -DEFINE_BUF_EVENT(xfs_buf_lock_done); -DEFINE_BUF_EVENT(xfs_buf_trylock_fail); -DEFINE_BUF_EVENT(xfs_buf_trylock); -DEFINE_BUF_EVENT(xfs_buf_unlock); -DEFINE_BUF_EVENT(xfs_buf_iowait); -DEFINE_BUF_EVENT(xfs_buf_iowait_done); -DEFINE_BUF_EVENT(xfs_buf_delwri_queue); -DEFINE_BUF_EVENT(xfs_buf_delwri_queued); -DEFINE_BUF_EVENT(xfs_buf_delwri_split); -DEFINE_BUF_EVENT(xfs_buf_get_uncached); -DEFINE_BUF_EVENT(xfs_bdstrat_shut); -DEFINE_BUF_EVENT(xfs_buf_item_relse); -DEFINE_BUF_EVENT(xfs_buf_item_iodone_async); -DEFINE_BUF_EVENT(xfs_buf_error_relse); -DEFINE_BUF_EVENT(xfs_buf_wait_buftarg); -DEFINE_BUF_EVENT(xfs_trans_read_buf_io); -DEFINE_BUF_EVENT(xfs_trans_read_buf_shut); - -/* not really buffer traces, but the buf provides useful information */ -DEFINE_BUF_EVENT(xfs_btree_corrupt); -DEFINE_BUF_EVENT(xfs_da_btree_corrupt); -DEFINE_BUF_EVENT(xfs_reset_dqcounts); -DEFINE_BUF_EVENT(xfs_inode_item_push); - -/* pass flags explicitly */ -DECLARE_EVENT_CLASS(xfs_buf_flags_class, - TP_PROTO(struct xfs_buf *bp, unsigned flags, unsigned long caller_ip), - TP_ARGS(bp, flags, caller_ip), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_daddr_t, bno) - __field(size_t, buffer_length) - __field(int, hold) - __field(int, pincount) - __field(unsigned, lockval) - __field(unsigned, flags) - __field(unsigned long, caller_ip) - ), - TP_fast_assign( - __entry->dev = bp->b_target->bt_dev; - __entry->bno = bp->b_bn; - __entry->buffer_length = BBTOB(bp->b_length); - __entry->flags = flags; - __entry->hold = atomic_read(&bp->b_hold); - __entry->pincount = atomic_read(&bp->b_pin_count); - __entry->lockval = bp->b_sema.count; - __entry->caller_ip = caller_ip; - ), - TP_printk("dev %d:%d bno 0x%llx len 0x%zx hold %d pincount %d " - "lock %d flags %s caller %ps", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long long)__entry->bno, - __entry->buffer_length, - __entry->hold, - __entry->pincount, - __entry->lockval, - __print_flags(__entry->flags, "|", XFS_BUF_FLAGS), - (void *)__entry->caller_ip) -) - -#define DEFINE_BUF_FLAGS_EVENT(name) \ -DEFINE_EVENT(xfs_buf_flags_class, name, \ - TP_PROTO(struct xfs_buf *bp, unsigned flags, unsigned long caller_ip), \ - TP_ARGS(bp, flags, caller_ip)) -DEFINE_BUF_FLAGS_EVENT(xfs_buf_find); -DEFINE_BUF_FLAGS_EVENT(xfs_buf_get); -DEFINE_BUF_FLAGS_EVENT(xfs_buf_read); - -TRACE_EVENT(xfs_buf_ioerror, - TP_PROTO(struct xfs_buf *bp, int error, unsigned long caller_ip), - TP_ARGS(bp, error, caller_ip), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_daddr_t, bno) - __field(size_t, buffer_length) - __field(unsigned, flags) - __field(int, hold) - __field(int, pincount) - __field(unsigned, lockval) - __field(int, error) - __field(unsigned long, caller_ip) - ), - TP_fast_assign( - __entry->dev = bp->b_target->bt_dev; - __entry->bno = bp->b_bn; - __entry->buffer_length = BBTOB(bp->b_length); - __entry->hold = atomic_read(&bp->b_hold); - __entry->pincount = atomic_read(&bp->b_pin_count); - __entry->lockval = bp->b_sema.count; - __entry->error = error; - __entry->flags = bp->b_flags; - __entry->caller_ip = caller_ip; - ), - TP_printk("dev %d:%d bno 0x%llx len 0x%zx hold %d pincount %d " - "lock %d error %d flags %s caller %ps", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long long)__entry->bno, - __entry->buffer_length, - __entry->hold, - __entry->pincount, - __entry->lockval, - __entry->error, - __print_flags(__entry->flags, "|", XFS_BUF_FLAGS), - (void *)__entry->caller_ip) -); - -DECLARE_EVENT_CLASS(xfs_buf_item_class, - TP_PROTO(struct xfs_buf_log_item *bip), - TP_ARGS(bip), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_daddr_t, buf_bno) - __field(size_t, buf_len) - __field(int, buf_hold) - __field(int, buf_pincount) - __field(int, buf_lockval) - __field(unsigned, buf_flags) - __field(unsigned, bli_recur) - __field(int, bli_refcount) - __field(unsigned, bli_flags) - __field(void *, li_desc) - __field(unsigned, li_flags) - ), - TP_fast_assign( - __entry->dev = bip->bli_buf->b_target->bt_dev; - __entry->bli_flags = bip->bli_flags; - __entry->bli_recur = bip->bli_recur; - __entry->bli_refcount = atomic_read(&bip->bli_refcount); - __entry->buf_bno = bip->bli_buf->b_bn; - __entry->buf_len = BBTOB(bip->bli_buf->b_length); - __entry->buf_flags = bip->bli_buf->b_flags; - __entry->buf_hold = atomic_read(&bip->bli_buf->b_hold); - __entry->buf_pincount = atomic_read(&bip->bli_buf->b_pin_count); - __entry->buf_lockval = bip->bli_buf->b_sema.count; - __entry->li_desc = bip->bli_item.li_desc; - __entry->li_flags = bip->bli_item.li_flags; - ), - TP_printk("dev %d:%d bno 0x%llx len 0x%zx hold %d pincount %d " - "lock %d flags %s recur %d refcount %d bliflags %s " - "lidesc 0x%p liflags %s", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long long)__entry->buf_bno, - __entry->buf_len, - __entry->buf_hold, - __entry->buf_pincount, - __entry->buf_lockval, - __print_flags(__entry->buf_flags, "|", XFS_BUF_FLAGS), - __entry->bli_recur, - __entry->bli_refcount, - __print_flags(__entry->bli_flags, "|", XFS_BLI_FLAGS), - __entry->li_desc, - __print_flags(__entry->li_flags, "|", XFS_LI_FLAGS)) -) - -#define DEFINE_BUF_ITEM_EVENT(name) \ -DEFINE_EVENT(xfs_buf_item_class, name, \ - TP_PROTO(struct xfs_buf_log_item *bip), \ - TP_ARGS(bip)) -DEFINE_BUF_ITEM_EVENT(xfs_buf_item_size); -DEFINE_BUF_ITEM_EVENT(xfs_buf_item_size_ordered); -DEFINE_BUF_ITEM_EVENT(xfs_buf_item_size_stale); -DEFINE_BUF_ITEM_EVENT(xfs_buf_item_format); -DEFINE_BUF_ITEM_EVENT(xfs_buf_item_format_ordered); -DEFINE_BUF_ITEM_EVENT(xfs_buf_item_format_stale); -DEFINE_BUF_ITEM_EVENT(xfs_buf_item_ordered); -DEFINE_BUF_ITEM_EVENT(xfs_buf_item_pin); -DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unpin); -DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unpin_stale); -DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unlock); -DEFINE_BUF_ITEM_EVENT(xfs_buf_item_unlock_stale); -DEFINE_BUF_ITEM_EVENT(xfs_buf_item_committed); -DEFINE_BUF_ITEM_EVENT(xfs_buf_item_push); -DEFINE_BUF_ITEM_EVENT(xfs_trans_get_buf); -DEFINE_BUF_ITEM_EVENT(xfs_trans_get_buf_recur); -DEFINE_BUF_ITEM_EVENT(xfs_trans_getsb); -DEFINE_BUF_ITEM_EVENT(xfs_trans_getsb_recur); -DEFINE_BUF_ITEM_EVENT(xfs_trans_read_buf); -DEFINE_BUF_ITEM_EVENT(xfs_trans_read_buf_recur); -DEFINE_BUF_ITEM_EVENT(xfs_trans_log_buf); -DEFINE_BUF_ITEM_EVENT(xfs_trans_brelse); -DEFINE_BUF_ITEM_EVENT(xfs_trans_bjoin); -DEFINE_BUF_ITEM_EVENT(xfs_trans_bhold); -DEFINE_BUF_ITEM_EVENT(xfs_trans_bhold_release); -DEFINE_BUF_ITEM_EVENT(xfs_trans_binval); -DEFINE_BUF_ITEM_EVENT(xfs_trans_buf_ordered); - -DECLARE_EVENT_CLASS(xfs_filestream_class, - TP_PROTO(struct xfs_inode *ip, xfs_agnumber_t agno), - TP_ARGS(ip, agno), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(xfs_agnumber_t, agno) - __field(int, streams) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->agno = agno; - __entry->streams = xfs_filestream_peek_ag(ip->i_mount, agno); - ), - TP_printk("dev %d:%d ino 0x%llx agno %u streams %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->agno, - __entry->streams) -) -#define DEFINE_FILESTREAM_EVENT(name) \ -DEFINE_EVENT(xfs_filestream_class, name, \ - TP_PROTO(struct xfs_inode *ip, xfs_agnumber_t agno), \ - TP_ARGS(ip, agno)) -DEFINE_FILESTREAM_EVENT(xfs_filestream_free); -DEFINE_FILESTREAM_EVENT(xfs_filestream_lookup); -DEFINE_FILESTREAM_EVENT(xfs_filestream_scan); - -TRACE_EVENT(xfs_filestream_pick, - TP_PROTO(struct xfs_inode *ip, xfs_agnumber_t agno, - xfs_extlen_t free, int nscan), - TP_ARGS(ip, agno, free, nscan), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(xfs_agnumber_t, agno) - __field(int, streams) - __field(xfs_extlen_t, free) - __field(int, nscan) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->agno = agno; - __entry->streams = xfs_filestream_peek_ag(ip->i_mount, agno); - __entry->free = free; - __entry->nscan = nscan; - ), - TP_printk("dev %d:%d ino 0x%llx agno %u streams %d free %d nscan %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->agno, - __entry->streams, - __entry->free, - __entry->nscan) -); - -DECLARE_EVENT_CLASS(xfs_lock_class, - TP_PROTO(struct xfs_inode *ip, unsigned lock_flags, - unsigned long caller_ip), - TP_ARGS(ip, lock_flags, caller_ip), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(int, lock_flags) - __field(unsigned long, caller_ip) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->lock_flags = lock_flags; - __entry->caller_ip = caller_ip; - ), - TP_printk("dev %d:%d ino 0x%llx flags %s caller %ps", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __print_flags(__entry->lock_flags, "|", XFS_LOCK_FLAGS), - (void *)__entry->caller_ip) -) - -#define DEFINE_LOCK_EVENT(name) \ -DEFINE_EVENT(xfs_lock_class, name, \ - TP_PROTO(struct xfs_inode *ip, unsigned lock_flags, \ - unsigned long caller_ip), \ - TP_ARGS(ip, lock_flags, caller_ip)) -DEFINE_LOCK_EVENT(xfs_ilock); -DEFINE_LOCK_EVENT(xfs_ilock_nowait); -DEFINE_LOCK_EVENT(xfs_ilock_demote); -DEFINE_LOCK_EVENT(xfs_iunlock); - -DECLARE_EVENT_CLASS(xfs_inode_class, - TP_PROTO(struct xfs_inode *ip), - TP_ARGS(ip), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - ), - TP_printk("dev %d:%d ino 0x%llx", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino) -) - -#define DEFINE_INODE_EVENT(name) \ -DEFINE_EVENT(xfs_inode_class, name, \ - TP_PROTO(struct xfs_inode *ip), \ - TP_ARGS(ip)) -DEFINE_INODE_EVENT(xfs_iget_skip); -DEFINE_INODE_EVENT(xfs_iget_reclaim); -DEFINE_INODE_EVENT(xfs_iget_reclaim_fail); -DEFINE_INODE_EVENT(xfs_iget_hit); -DEFINE_INODE_EVENT(xfs_iget_miss); - -DEFINE_INODE_EVENT(xfs_getattr); -DEFINE_INODE_EVENT(xfs_setattr); -DEFINE_INODE_EVENT(xfs_readlink); -DEFINE_INODE_EVENT(xfs_inactive_symlink); -DEFINE_INODE_EVENT(xfs_alloc_file_space); -DEFINE_INODE_EVENT(xfs_free_file_space); -DEFINE_INODE_EVENT(xfs_zero_file_space); -DEFINE_INODE_EVENT(xfs_collapse_file_space); -DEFINE_INODE_EVENT(xfs_insert_file_space); -DEFINE_INODE_EVENT(xfs_readdir); -#ifdef CONFIG_XFS_POSIX_ACL -DEFINE_INODE_EVENT(xfs_get_acl); -#endif -DEFINE_INODE_EVENT(xfs_vm_bmap); -DEFINE_INODE_EVENT(xfs_file_ioctl); -DEFINE_INODE_EVENT(xfs_file_compat_ioctl); -DEFINE_INODE_EVENT(xfs_ioctl_setattr); -DEFINE_INODE_EVENT(xfs_dir_fsync); -DEFINE_INODE_EVENT(xfs_file_fsync); -DEFINE_INODE_EVENT(xfs_destroy_inode); -DEFINE_INODE_EVENT(xfs_evict_inode); -DEFINE_INODE_EVENT(xfs_update_time); - -DEFINE_INODE_EVENT(xfs_dquot_dqalloc); -DEFINE_INODE_EVENT(xfs_dquot_dqdetach); - -DEFINE_INODE_EVENT(xfs_inode_set_eofblocks_tag); -DEFINE_INODE_EVENT(xfs_inode_clear_eofblocks_tag); -DEFINE_INODE_EVENT(xfs_inode_free_eofblocks_invalid); -DEFINE_INODE_EVENT(xfs_inode_set_cowblocks_tag); -DEFINE_INODE_EVENT(xfs_inode_clear_cowblocks_tag); -DEFINE_INODE_EVENT(xfs_inode_free_cowblocks_invalid); - -DEFINE_INODE_EVENT(xfs_filemap_fault); -DEFINE_INODE_EVENT(xfs_filemap_pmd_fault); -DEFINE_INODE_EVENT(xfs_filemap_page_mkwrite); -DEFINE_INODE_EVENT(xfs_filemap_pfn_mkwrite); - -DECLARE_EVENT_CLASS(xfs_iref_class, - TP_PROTO(struct xfs_inode *ip, unsigned long caller_ip), - TP_ARGS(ip, caller_ip), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(int, count) - __field(int, pincount) - __field(unsigned long, caller_ip) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->count = atomic_read(&VFS_I(ip)->i_count); - __entry->pincount = atomic_read(&ip->i_pincount); - __entry->caller_ip = caller_ip; - ), - TP_printk("dev %d:%d ino 0x%llx count %d pincount %d caller %ps", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->count, - __entry->pincount, - (char *)__entry->caller_ip) -) - -TRACE_EVENT(xfs_iomap_prealloc_size, - TP_PROTO(struct xfs_inode *ip, xfs_fsblock_t blocks, int shift, - unsigned int writeio_blocks), - TP_ARGS(ip, blocks, shift, writeio_blocks), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(xfs_fsblock_t, blocks) - __field(int, shift) - __field(unsigned int, writeio_blocks) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->blocks = blocks; - __entry->shift = shift; - __entry->writeio_blocks = writeio_blocks; - ), - TP_printk("dev %d:%d ino 0x%llx prealloc blocks %llu shift %d " - "m_writeio_blocks %u", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->ino, - __entry->blocks, __entry->shift, __entry->writeio_blocks) -) - -TRACE_EVENT(xfs_irec_merge_pre, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t agino, - uint16_t holemask, xfs_agino_t nagino, uint16_t nholemask), - TP_ARGS(mp, agno, agino, holemask, nagino, nholemask), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(xfs_agino_t, agino) - __field(uint16_t, holemask) - __field(xfs_agino_t, nagino) - __field(uint16_t, nholemask) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->agino = agino; - __entry->holemask = holemask; - __entry->nagino = nagino; - __entry->nholemask = holemask; - ), - TP_printk("dev %d:%d agno %d inobt (%u:0x%x) new (%u:0x%x)", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->agno, - __entry->agino, __entry->holemask, __entry->nagino, - __entry->nholemask) -) - -TRACE_EVENT(xfs_irec_merge_post, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agino_t agino, - uint16_t holemask), - TP_ARGS(mp, agno, agino, holemask), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(xfs_agino_t, agino) - __field(uint16_t, holemask) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->agino = agino; - __entry->holemask = holemask; - ), - TP_printk("dev %d:%d agno %d inobt (%u:0x%x)", MAJOR(__entry->dev), - MINOR(__entry->dev), __entry->agno, __entry->agino, - __entry->holemask) -) - -#define DEFINE_IREF_EVENT(name) \ -DEFINE_EVENT(xfs_iref_class, name, \ - TP_PROTO(struct xfs_inode *ip, unsigned long caller_ip), \ - TP_ARGS(ip, caller_ip)) -DEFINE_IREF_EVENT(xfs_ihold); -DEFINE_IREF_EVENT(xfs_irele); -DEFINE_IREF_EVENT(xfs_inode_pin); -DEFINE_IREF_EVENT(xfs_inode_unpin); -DEFINE_IREF_EVENT(xfs_inode_unpin_nowait); - -DECLARE_EVENT_CLASS(xfs_namespace_class, - TP_PROTO(struct xfs_inode *dp, struct xfs_name *name), - TP_ARGS(dp, name), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, dp_ino) - __field(int, namelen) - __dynamic_array(char, name, name->len) - ), - TP_fast_assign( - __entry->dev = VFS_I(dp)->i_sb->s_dev; - __entry->dp_ino = dp->i_ino; - __entry->namelen = name->len; - memcpy(__get_str(name), name->name, name->len); - ), - TP_printk("dev %d:%d dp ino 0x%llx name %.*s", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->dp_ino, - __entry->namelen, - __get_str(name)) -) - -#define DEFINE_NAMESPACE_EVENT(name) \ -DEFINE_EVENT(xfs_namespace_class, name, \ - TP_PROTO(struct xfs_inode *dp, struct xfs_name *name), \ - TP_ARGS(dp, name)) -DEFINE_NAMESPACE_EVENT(xfs_remove); -DEFINE_NAMESPACE_EVENT(xfs_link); -DEFINE_NAMESPACE_EVENT(xfs_lookup); -DEFINE_NAMESPACE_EVENT(xfs_create); -DEFINE_NAMESPACE_EVENT(xfs_symlink); - -TRACE_EVENT(xfs_rename, - TP_PROTO(struct xfs_inode *src_dp, struct xfs_inode *target_dp, - struct xfs_name *src_name, struct xfs_name *target_name), - TP_ARGS(src_dp, target_dp, src_name, target_name), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, src_dp_ino) - __field(xfs_ino_t, target_dp_ino) - __field(int, src_namelen) - __field(int, target_namelen) - __dynamic_array(char, src_name, src_name->len) - __dynamic_array(char, target_name, target_name->len) - ), - TP_fast_assign( - __entry->dev = VFS_I(src_dp)->i_sb->s_dev; - __entry->src_dp_ino = src_dp->i_ino; - __entry->target_dp_ino = target_dp->i_ino; - __entry->src_namelen = src_name->len; - __entry->target_namelen = target_name->len; - memcpy(__get_str(src_name), src_name->name, src_name->len); - memcpy(__get_str(target_name), target_name->name, - target_name->len); - ), - TP_printk("dev %d:%d src dp ino 0x%llx target dp ino 0x%llx" - " src name %.*s target name %.*s", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->src_dp_ino, - __entry->target_dp_ino, - __entry->src_namelen, - __get_str(src_name), - __entry->target_namelen, - __get_str(target_name)) -) - -DECLARE_EVENT_CLASS(xfs_dquot_class, - TP_PROTO(struct xfs_dquot *dqp), - TP_ARGS(dqp), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(u32, id) - __field(unsigned, flags) - __field(unsigned, nrefs) - __field(unsigned long long, res_bcount) - __field(unsigned long long, bcount) - __field(unsigned long long, icount) - __field(unsigned long long, blk_hardlimit) - __field(unsigned long long, blk_softlimit) - __field(unsigned long long, ino_hardlimit) - __field(unsigned long long, ino_softlimit) - ), \ - TP_fast_assign( - __entry->dev = dqp->q_mount->m_super->s_dev; - __entry->id = be32_to_cpu(dqp->q_core.d_id); - __entry->flags = dqp->dq_flags; - __entry->nrefs = dqp->q_nrefs; - __entry->res_bcount = dqp->q_res_bcount; - __entry->bcount = be64_to_cpu(dqp->q_core.d_bcount); - __entry->icount = be64_to_cpu(dqp->q_core.d_icount); - __entry->blk_hardlimit = - be64_to_cpu(dqp->q_core.d_blk_hardlimit); - __entry->blk_softlimit = - be64_to_cpu(dqp->q_core.d_blk_softlimit); - __entry->ino_hardlimit = - be64_to_cpu(dqp->q_core.d_ino_hardlimit); - __entry->ino_softlimit = - be64_to_cpu(dqp->q_core.d_ino_softlimit); - ), - TP_printk("dev %d:%d id 0x%x flags %s nrefs %u res_bc 0x%llx " - "bcnt 0x%llx bhardlimit 0x%llx bsoftlimit 0x%llx " - "icnt 0x%llx ihardlimit 0x%llx isoftlimit 0x%llx]", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->id, - __print_flags(__entry->flags, "|", XFS_DQ_FLAGS), - __entry->nrefs, - __entry->res_bcount, - __entry->bcount, - __entry->blk_hardlimit, - __entry->blk_softlimit, - __entry->icount, - __entry->ino_hardlimit, - __entry->ino_softlimit) -) - -#define DEFINE_DQUOT_EVENT(name) \ -DEFINE_EVENT(xfs_dquot_class, name, \ - TP_PROTO(struct xfs_dquot *dqp), \ - TP_ARGS(dqp)) -DEFINE_DQUOT_EVENT(xfs_dqadjust); -DEFINE_DQUOT_EVENT(xfs_dqreclaim_want); -DEFINE_DQUOT_EVENT(xfs_dqreclaim_dirty); -DEFINE_DQUOT_EVENT(xfs_dqreclaim_busy); -DEFINE_DQUOT_EVENT(xfs_dqreclaim_done); -DEFINE_DQUOT_EVENT(xfs_dqattach_found); -DEFINE_DQUOT_EVENT(xfs_dqattach_get); -DEFINE_DQUOT_EVENT(xfs_dqalloc); -DEFINE_DQUOT_EVENT(xfs_dqtobp_read); -DEFINE_DQUOT_EVENT(xfs_dqread); -DEFINE_DQUOT_EVENT(xfs_dqread_fail); -DEFINE_DQUOT_EVENT(xfs_dqget_hit); -DEFINE_DQUOT_EVENT(xfs_dqget_miss); -DEFINE_DQUOT_EVENT(xfs_dqget_freeing); -DEFINE_DQUOT_EVENT(xfs_dqget_dup); -DEFINE_DQUOT_EVENT(xfs_dqput); -DEFINE_DQUOT_EVENT(xfs_dqput_wait); -DEFINE_DQUOT_EVENT(xfs_dqput_free); -DEFINE_DQUOT_EVENT(xfs_dqrele); -DEFINE_DQUOT_EVENT(xfs_dqflush); -DEFINE_DQUOT_EVENT(xfs_dqflush_force); -DEFINE_DQUOT_EVENT(xfs_dqflush_done); - -DECLARE_EVENT_CLASS(xfs_loggrant_class, - TP_PROTO(struct xlog *log, struct xlog_ticket *tic), - TP_ARGS(log, tic), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(char, ocnt) - __field(char, cnt) - __field(int, curr_res) - __field(int, unit_res) - __field(unsigned int, flags) - __field(int, reserveq) - __field(int, writeq) - __field(int, grant_reserve_cycle) - __field(int, grant_reserve_bytes) - __field(int, grant_write_cycle) - __field(int, grant_write_bytes) - __field(int, curr_cycle) - __field(int, curr_block) - __field(xfs_lsn_t, tail_lsn) - ), - TP_fast_assign( - __entry->dev = log->l_mp->m_super->s_dev; - __entry->ocnt = tic->t_ocnt; - __entry->cnt = tic->t_cnt; - __entry->curr_res = tic->t_curr_res; - __entry->unit_res = tic->t_unit_res; - __entry->flags = tic->t_flags; - __entry->reserveq = list_empty(&log->l_reserve_head.waiters); - __entry->writeq = list_empty(&log->l_write_head.waiters); - xlog_crack_grant_head(&log->l_reserve_head.grant, - &__entry->grant_reserve_cycle, - &__entry->grant_reserve_bytes); - xlog_crack_grant_head(&log->l_write_head.grant, - &__entry->grant_write_cycle, - &__entry->grant_write_bytes); - __entry->curr_cycle = log->l_curr_cycle; - __entry->curr_block = log->l_curr_block; - __entry->tail_lsn = atomic64_read(&log->l_tail_lsn); - ), - TP_printk("dev %d:%d t_ocnt %u t_cnt %u t_curr_res %u " - "t_unit_res %u t_flags %s reserveq %s " - "writeq %s grant_reserve_cycle %d " - "grant_reserve_bytes %d grant_write_cycle %d " - "grant_write_bytes %d curr_cycle %d curr_block %d " - "tail_cycle %d tail_block %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ocnt, - __entry->cnt, - __entry->curr_res, - __entry->unit_res, - __print_flags(__entry->flags, "|", XLOG_TIC_FLAGS), - __entry->reserveq ? "empty" : "active", - __entry->writeq ? "empty" : "active", - __entry->grant_reserve_cycle, - __entry->grant_reserve_bytes, - __entry->grant_write_cycle, - __entry->grant_write_bytes, - __entry->curr_cycle, - __entry->curr_block, - CYCLE_LSN(__entry->tail_lsn), - BLOCK_LSN(__entry->tail_lsn) - ) -) - -#define DEFINE_LOGGRANT_EVENT(name) \ -DEFINE_EVENT(xfs_loggrant_class, name, \ - TP_PROTO(struct xlog *log, struct xlog_ticket *tic), \ - TP_ARGS(log, tic)) -DEFINE_LOGGRANT_EVENT(xfs_log_done_nonperm); -DEFINE_LOGGRANT_EVENT(xfs_log_done_perm); -DEFINE_LOGGRANT_EVENT(xfs_log_umount_write); -DEFINE_LOGGRANT_EVENT(xfs_log_grant_sleep); -DEFINE_LOGGRANT_EVENT(xfs_log_grant_wake); -DEFINE_LOGGRANT_EVENT(xfs_log_grant_wake_up); -DEFINE_LOGGRANT_EVENT(xfs_log_reserve); -DEFINE_LOGGRANT_EVENT(xfs_log_reserve_exit); -DEFINE_LOGGRANT_EVENT(xfs_log_regrant); -DEFINE_LOGGRANT_EVENT(xfs_log_regrant_exit); -DEFINE_LOGGRANT_EVENT(xfs_log_regrant_reserve_enter); -DEFINE_LOGGRANT_EVENT(xfs_log_regrant_reserve_exit); -DEFINE_LOGGRANT_EVENT(xfs_log_regrant_reserve_sub); -DEFINE_LOGGRANT_EVENT(xfs_log_ungrant_enter); -DEFINE_LOGGRANT_EVENT(xfs_log_ungrant_exit); -DEFINE_LOGGRANT_EVENT(xfs_log_ungrant_sub); - -DECLARE_EVENT_CLASS(xfs_log_item_class, - TP_PROTO(struct xfs_log_item *lip), - TP_ARGS(lip), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(void *, lip) - __field(uint, type) - __field(uint, flags) - __field(xfs_lsn_t, lsn) - ), - TP_fast_assign( - __entry->dev = lip->li_mountp->m_super->s_dev; - __entry->lip = lip; - __entry->type = lip->li_type; - __entry->flags = lip->li_flags; - __entry->lsn = lip->li_lsn; - ), - TP_printk("dev %d:%d lip 0x%p lsn %d/%d type %s flags %s", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->lip, - CYCLE_LSN(__entry->lsn), BLOCK_LSN(__entry->lsn), - __print_symbolic(__entry->type, XFS_LI_TYPE_DESC), - __print_flags(__entry->flags, "|", XFS_LI_FLAGS)) -) - -TRACE_EVENT(xfs_log_force, - TP_PROTO(struct xfs_mount *mp, xfs_lsn_t lsn, unsigned long caller_ip), - TP_ARGS(mp, lsn, caller_ip), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_lsn_t, lsn) - __field(unsigned long, caller_ip) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->lsn = lsn; - __entry->caller_ip = caller_ip; - ), - TP_printk("dev %d:%d lsn 0x%llx caller %ps", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->lsn, (void *)__entry->caller_ip) -) - -#define DEFINE_LOG_ITEM_EVENT(name) \ -DEFINE_EVENT(xfs_log_item_class, name, \ - TP_PROTO(struct xfs_log_item *lip), \ - TP_ARGS(lip)) -DEFINE_LOG_ITEM_EVENT(xfs_ail_push); -DEFINE_LOG_ITEM_EVENT(xfs_ail_pinned); -DEFINE_LOG_ITEM_EVENT(xfs_ail_locked); -DEFINE_LOG_ITEM_EVENT(xfs_ail_flushing); - -DECLARE_EVENT_CLASS(xfs_ail_class, - TP_PROTO(struct xfs_log_item *lip, xfs_lsn_t old_lsn, xfs_lsn_t new_lsn), - TP_ARGS(lip, old_lsn, new_lsn), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(void *, lip) - __field(uint, type) - __field(uint, flags) - __field(xfs_lsn_t, old_lsn) - __field(xfs_lsn_t, new_lsn) - ), - TP_fast_assign( - __entry->dev = lip->li_mountp->m_super->s_dev; - __entry->lip = lip; - __entry->type = lip->li_type; - __entry->flags = lip->li_flags; - __entry->old_lsn = old_lsn; - __entry->new_lsn = new_lsn; - ), - TP_printk("dev %d:%d lip 0x%p old lsn %d/%d new lsn %d/%d type %s flags %s", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->lip, - CYCLE_LSN(__entry->old_lsn), BLOCK_LSN(__entry->old_lsn), - CYCLE_LSN(__entry->new_lsn), BLOCK_LSN(__entry->new_lsn), - __print_symbolic(__entry->type, XFS_LI_TYPE_DESC), - __print_flags(__entry->flags, "|", XFS_LI_FLAGS)) -) - -#define DEFINE_AIL_EVENT(name) \ -DEFINE_EVENT(xfs_ail_class, name, \ - TP_PROTO(struct xfs_log_item *lip, xfs_lsn_t old_lsn, xfs_lsn_t new_lsn), \ - TP_ARGS(lip, old_lsn, new_lsn)) -DEFINE_AIL_EVENT(xfs_ail_insert); -DEFINE_AIL_EVENT(xfs_ail_move); -DEFINE_AIL_EVENT(xfs_ail_delete); - -TRACE_EVENT(xfs_log_assign_tail_lsn, - TP_PROTO(struct xlog *log, xfs_lsn_t new_lsn), - TP_ARGS(log, new_lsn), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_lsn_t, new_lsn) - __field(xfs_lsn_t, old_lsn) - __field(xfs_lsn_t, last_sync_lsn) - ), - TP_fast_assign( - __entry->dev = log->l_mp->m_super->s_dev; - __entry->new_lsn = new_lsn; - __entry->old_lsn = atomic64_read(&log->l_tail_lsn); - __entry->last_sync_lsn = atomic64_read(&log->l_last_sync_lsn); - ), - TP_printk("dev %d:%d new tail lsn %d/%d, old lsn %d/%d, last sync %d/%d", - MAJOR(__entry->dev), MINOR(__entry->dev), - CYCLE_LSN(__entry->new_lsn), BLOCK_LSN(__entry->new_lsn), - CYCLE_LSN(__entry->old_lsn), BLOCK_LSN(__entry->old_lsn), - CYCLE_LSN(__entry->last_sync_lsn), BLOCK_LSN(__entry->last_sync_lsn)) -) - -DECLARE_EVENT_CLASS(xfs_file_class, - TP_PROTO(struct xfs_inode *ip, size_t count, loff_t offset), - TP_ARGS(ip, count, offset), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(xfs_fsize_t, size) - __field(loff_t, offset) - __field(size_t, count) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->size = ip->i_d.di_size; - __entry->offset = offset; - __entry->count = count; - ), - TP_printk("dev %d:%d ino 0x%llx size 0x%llx offset 0x%llx count 0x%zx", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->size, - __entry->offset, - __entry->count) -) - -#define DEFINE_RW_EVENT(name) \ -DEFINE_EVENT(xfs_file_class, name, \ - TP_PROTO(struct xfs_inode *ip, size_t count, loff_t offset), \ - TP_ARGS(ip, count, offset)) -DEFINE_RW_EVENT(xfs_file_buffered_read); -DEFINE_RW_EVENT(xfs_file_direct_read); -DEFINE_RW_EVENT(xfs_file_dax_read); -DEFINE_RW_EVENT(xfs_file_buffered_write); -DEFINE_RW_EVENT(xfs_file_direct_write); -DEFINE_RW_EVENT(xfs_file_dax_write); - -DECLARE_EVENT_CLASS(xfs_page_class, - TP_PROTO(struct inode *inode, struct page *page, unsigned long off, - unsigned int len), - TP_ARGS(inode, page, off, len), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(pgoff_t, pgoff) - __field(loff_t, size) - __field(unsigned long, offset) - __field(unsigned int, length) - __field(int, delalloc) - __field(int, unwritten) - ), - TP_fast_assign( - int delalloc = -1, unwritten = -1; - - if (page_has_buffers(page)) - xfs_count_page_state(page, &delalloc, &unwritten); - __entry->dev = inode->i_sb->s_dev; - __entry->ino = XFS_I(inode)->i_ino; - __entry->pgoff = page_offset(page); - __entry->size = i_size_read(inode); - __entry->offset = off; - __entry->length = len; - __entry->delalloc = delalloc; - __entry->unwritten = unwritten; - ), - TP_printk("dev %d:%d ino 0x%llx pgoff 0x%lx size 0x%llx offset %lx " - "length %x delalloc %d unwritten %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->pgoff, - __entry->size, - __entry->offset, - __entry->length, - __entry->delalloc, - __entry->unwritten) -) - -#define DEFINE_PAGE_EVENT(name) \ -DEFINE_EVENT(xfs_page_class, name, \ - TP_PROTO(struct inode *inode, struct page *page, unsigned long off, \ - unsigned int len), \ - TP_ARGS(inode, page, off, len)) -DEFINE_PAGE_EVENT(xfs_writepage); -DEFINE_PAGE_EVENT(xfs_releasepage); -DEFINE_PAGE_EVENT(xfs_invalidatepage); - -DECLARE_EVENT_CLASS(xfs_readpage_class, - TP_PROTO(struct inode *inode, int nr_pages), - TP_ARGS(inode, nr_pages), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(int, nr_pages) - ), - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->nr_pages = nr_pages; - ), - TP_printk("dev %d:%d ino 0x%llx nr_pages %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->nr_pages) -) - -#define DEFINE_READPAGE_EVENT(name) \ -DEFINE_EVENT(xfs_readpage_class, name, \ - TP_PROTO(struct inode *inode, int nr_pages), \ - TP_ARGS(inode, nr_pages)) -DEFINE_READPAGE_EVENT(xfs_vm_readpage); -DEFINE_READPAGE_EVENT(xfs_vm_readpages); - -DECLARE_EVENT_CLASS(xfs_imap_class, - TP_PROTO(struct xfs_inode *ip, xfs_off_t offset, ssize_t count, - int type, struct xfs_bmbt_irec *irec), - TP_ARGS(ip, offset, count, type, irec), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(loff_t, size) - __field(loff_t, offset) - __field(size_t, count) - __field(int, type) - __field(xfs_fileoff_t, startoff) - __field(xfs_fsblock_t, startblock) - __field(xfs_filblks_t, blockcount) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->size = ip->i_d.di_size; - __entry->offset = offset; - __entry->count = count; - __entry->type = type; - __entry->startoff = irec ? irec->br_startoff : 0; - __entry->startblock = irec ? irec->br_startblock : 0; - __entry->blockcount = irec ? irec->br_blockcount : 0; - ), - TP_printk("dev %d:%d ino 0x%llx size 0x%llx offset 0x%llx count %zd " - "type %s startoff 0x%llx startblock %lld blockcount 0x%llx", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->size, - __entry->offset, - __entry->count, - __print_symbolic(__entry->type, XFS_IO_TYPES), - __entry->startoff, - (__int64_t)__entry->startblock, - __entry->blockcount) -) - -#define DEFINE_IOMAP_EVENT(name) \ -DEFINE_EVENT(xfs_imap_class, name, \ - TP_PROTO(struct xfs_inode *ip, xfs_off_t offset, ssize_t count, \ - int type, struct xfs_bmbt_irec *irec), \ - TP_ARGS(ip, offset, count, type, irec)) -DEFINE_IOMAP_EVENT(xfs_map_blocks_found); -DEFINE_IOMAP_EVENT(xfs_map_blocks_alloc); -DEFINE_IOMAP_EVENT(xfs_get_blocks_found); -DEFINE_IOMAP_EVENT(xfs_get_blocks_alloc); -DEFINE_IOMAP_EVENT(xfs_get_blocks_map_direct); -DEFINE_IOMAP_EVENT(xfs_iomap_alloc); -DEFINE_IOMAP_EVENT(xfs_iomap_found); - -DECLARE_EVENT_CLASS(xfs_simple_io_class, - TP_PROTO(struct xfs_inode *ip, xfs_off_t offset, ssize_t count), - TP_ARGS(ip, offset, count), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(loff_t, isize) - __field(loff_t, disize) - __field(loff_t, offset) - __field(size_t, count) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->isize = VFS_I(ip)->i_size; - __entry->disize = ip->i_d.di_size; - __entry->offset = offset; - __entry->count = count; - ), - TP_printk("dev %d:%d ino 0x%llx isize 0x%llx disize 0x%llx " - "offset 0x%llx count %zd", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->isize, - __entry->disize, - __entry->offset, - __entry->count) -); - -#define DEFINE_SIMPLE_IO_EVENT(name) \ -DEFINE_EVENT(xfs_simple_io_class, name, \ - TP_PROTO(struct xfs_inode *ip, xfs_off_t offset, ssize_t count), \ - TP_ARGS(ip, offset, count)) -DEFINE_SIMPLE_IO_EVENT(xfs_delalloc_enospc); -DEFINE_SIMPLE_IO_EVENT(xfs_unwritten_convert); -DEFINE_SIMPLE_IO_EVENT(xfs_get_blocks_notfound); -DEFINE_SIMPLE_IO_EVENT(xfs_setfilesize); -DEFINE_SIMPLE_IO_EVENT(xfs_zero_eof); -DEFINE_SIMPLE_IO_EVENT(xfs_end_io_direct_write); -DEFINE_SIMPLE_IO_EVENT(xfs_end_io_direct_write_unwritten); -DEFINE_SIMPLE_IO_EVENT(xfs_end_io_direct_write_append); - -DECLARE_EVENT_CLASS(xfs_itrunc_class, - TP_PROTO(struct xfs_inode *ip, xfs_fsize_t new_size), - TP_ARGS(ip, new_size), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(xfs_fsize_t, size) - __field(xfs_fsize_t, new_size) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->size = ip->i_d.di_size; - __entry->new_size = new_size; - ), - TP_printk("dev %d:%d ino 0x%llx size 0x%llx new_size 0x%llx", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->size, - __entry->new_size) -) - -#define DEFINE_ITRUNC_EVENT(name) \ -DEFINE_EVENT(xfs_itrunc_class, name, \ - TP_PROTO(struct xfs_inode *ip, xfs_fsize_t new_size), \ - TP_ARGS(ip, new_size)) -DEFINE_ITRUNC_EVENT(xfs_itruncate_extents_start); -DEFINE_ITRUNC_EVENT(xfs_itruncate_extents_end); - -TRACE_EVENT(xfs_pagecache_inval, - TP_PROTO(struct xfs_inode *ip, xfs_off_t start, xfs_off_t finish), - TP_ARGS(ip, start, finish), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(xfs_fsize_t, size) - __field(xfs_off_t, start) - __field(xfs_off_t, finish) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->size = ip->i_d.di_size; - __entry->start = start; - __entry->finish = finish; - ), - TP_printk("dev %d:%d ino 0x%llx size 0x%llx start 0x%llx finish 0x%llx", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->size, - __entry->start, - __entry->finish) -); - -TRACE_EVENT(xfs_bunmap, - TP_PROTO(struct xfs_inode *ip, xfs_fileoff_t bno, xfs_filblks_t len, - int flags, unsigned long caller_ip), - TP_ARGS(ip, bno, len, flags, caller_ip), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(xfs_fsize_t, size) - __field(xfs_fileoff_t, bno) - __field(xfs_filblks_t, len) - __field(unsigned long, caller_ip) - __field(int, flags) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->size = ip->i_d.di_size; - __entry->bno = bno; - __entry->len = len; - __entry->caller_ip = caller_ip; - __entry->flags = flags; - ), - TP_printk("dev %d:%d ino 0x%llx size 0x%llx bno 0x%llx len 0x%llx" - "flags %s caller %ps", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->size, - __entry->bno, - __entry->len, - __print_flags(__entry->flags, "|", XFS_BMAPI_FLAGS), - (void *)__entry->caller_ip) - -); - -DECLARE_EVENT_CLASS(xfs_extent_busy_class, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, - xfs_agblock_t agbno, xfs_extlen_t len), - TP_ARGS(mp, agno, agbno, len), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(xfs_agblock_t, agbno) - __field(xfs_extlen_t, len) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->agbno = agbno; - __entry->len = len; - ), - TP_printk("dev %d:%d agno %u agbno %u len %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno, - __entry->agbno, - __entry->len) -); -#define DEFINE_BUSY_EVENT(name) \ -DEFINE_EVENT(xfs_extent_busy_class, name, \ - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \ - xfs_agblock_t agbno, xfs_extlen_t len), \ - TP_ARGS(mp, agno, agbno, len)) -DEFINE_BUSY_EVENT(xfs_extent_busy); -DEFINE_BUSY_EVENT(xfs_extent_busy_enomem); -DEFINE_BUSY_EVENT(xfs_extent_busy_force); -DEFINE_BUSY_EVENT(xfs_extent_busy_reuse); -DEFINE_BUSY_EVENT(xfs_extent_busy_clear); - -TRACE_EVENT(xfs_extent_busy_trim, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, - xfs_agblock_t agbno, xfs_extlen_t len, - xfs_agblock_t tbno, xfs_extlen_t tlen), - TP_ARGS(mp, agno, agbno, len, tbno, tlen), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(xfs_agblock_t, agbno) - __field(xfs_extlen_t, len) - __field(xfs_agblock_t, tbno) - __field(xfs_extlen_t, tlen) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->agbno = agbno; - __entry->len = len; - __entry->tbno = tbno; - __entry->tlen = tlen; - ), - TP_printk("dev %d:%d agno %u agbno %u len %u tbno %u tlen %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno, - __entry->agbno, - __entry->len, - __entry->tbno, - __entry->tlen) -); - -TRACE_EVENT(xfs_trans_commit_lsn, - TP_PROTO(struct xfs_trans *trans), - TP_ARGS(trans), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(struct xfs_trans *, tp) - __field(xfs_lsn_t, lsn) - ), - TP_fast_assign( - __entry->dev = trans->t_mountp->m_super->s_dev; - __entry->tp = trans; - __entry->lsn = trans->t_commit_lsn; - ), - TP_printk("dev %d:%d trans 0x%p commit_lsn 0x%llx", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->tp, - __entry->lsn) -); - -TRACE_EVENT(xfs_agf, - TP_PROTO(struct xfs_mount *mp, struct xfs_agf *agf, int flags, - unsigned long caller_ip), - TP_ARGS(mp, agf, flags, caller_ip), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(int, flags) - __field(__u32, length) - __field(__u32, bno_root) - __field(__u32, cnt_root) - __field(__u32, bno_level) - __field(__u32, cnt_level) - __field(__u32, flfirst) - __field(__u32, fllast) - __field(__u32, flcount) - __field(__u32, freeblks) - __field(__u32, longest) - __field(unsigned long, caller_ip) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = be32_to_cpu(agf->agf_seqno), - __entry->flags = flags; - __entry->length = be32_to_cpu(agf->agf_length), - __entry->bno_root = be32_to_cpu(agf->agf_roots[XFS_BTNUM_BNO]), - __entry->cnt_root = be32_to_cpu(agf->agf_roots[XFS_BTNUM_CNT]), - __entry->bno_level = - be32_to_cpu(agf->agf_levels[XFS_BTNUM_BNO]), - __entry->cnt_level = - be32_to_cpu(agf->agf_levels[XFS_BTNUM_CNT]), - __entry->flfirst = be32_to_cpu(agf->agf_flfirst), - __entry->fllast = be32_to_cpu(agf->agf_fllast), - __entry->flcount = be32_to_cpu(agf->agf_flcount), - __entry->freeblks = be32_to_cpu(agf->agf_freeblks), - __entry->longest = be32_to_cpu(agf->agf_longest); - __entry->caller_ip = caller_ip; - ), - TP_printk("dev %d:%d agno %u flags %s length %u roots b %u c %u " - "levels b %u c %u flfirst %u fllast %u flcount %u " - "freeblks %u longest %u caller %ps", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno, - __print_flags(__entry->flags, "|", XFS_AGF_FLAGS), - __entry->length, - __entry->bno_root, - __entry->cnt_root, - __entry->bno_level, - __entry->cnt_level, - __entry->flfirst, - __entry->fllast, - __entry->flcount, - __entry->freeblks, - __entry->longest, - (void *)__entry->caller_ip) -); - -TRACE_EVENT(xfs_free_extent, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, xfs_agblock_t agbno, - xfs_extlen_t len, enum xfs_ag_resv_type resv, int haveleft, - int haveright), - TP_ARGS(mp, agno, agbno, len, resv, haveleft, haveright), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(xfs_agblock_t, agbno) - __field(xfs_extlen_t, len) - __field(int, resv) - __field(int, haveleft) - __field(int, haveright) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->agbno = agbno; - __entry->len = len; - __entry->resv = resv; - __entry->haveleft = haveleft; - __entry->haveright = haveright; - ), - TP_printk("dev %d:%d agno %u agbno %u len %u resv %d %s", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno, - __entry->agbno, - __entry->len, - __entry->resv, - __entry->haveleft ? - (__entry->haveright ? "both" : "left") : - (__entry->haveright ? "right" : "none")) - -); - -DECLARE_EVENT_CLASS(xfs_alloc_class, - TP_PROTO(struct xfs_alloc_arg *args), - TP_ARGS(args), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(xfs_agblock_t, agbno) - __field(xfs_extlen_t, minlen) - __field(xfs_extlen_t, maxlen) - __field(xfs_extlen_t, mod) - __field(xfs_extlen_t, prod) - __field(xfs_extlen_t, minleft) - __field(xfs_extlen_t, total) - __field(xfs_extlen_t, alignment) - __field(xfs_extlen_t, minalignslop) - __field(xfs_extlen_t, len) - __field(short, type) - __field(short, otype) - __field(char, wasdel) - __field(char, wasfromfl) - __field(int, resv) - __field(int, datatype) - __field(xfs_fsblock_t, firstblock) - ), - TP_fast_assign( - __entry->dev = args->mp->m_super->s_dev; - __entry->agno = args->agno; - __entry->agbno = args->agbno; - __entry->minlen = args->minlen; - __entry->maxlen = args->maxlen; - __entry->mod = args->mod; - __entry->prod = args->prod; - __entry->minleft = args->minleft; - __entry->total = args->total; - __entry->alignment = args->alignment; - __entry->minalignslop = args->minalignslop; - __entry->len = args->len; - __entry->type = args->type; - __entry->otype = args->otype; - __entry->wasdel = args->wasdel; - __entry->wasfromfl = args->wasfromfl; - __entry->resv = args->resv; - __entry->datatype = args->datatype; - __entry->firstblock = args->firstblock; - ), - TP_printk("dev %d:%d agno %u agbno %u minlen %u maxlen %u mod %u " - "prod %u minleft %u total %u alignment %u minalignslop %u " - "len %u type %s otype %s wasdel %d wasfromfl %d resv %d " - "datatype 0x%x firstblock 0x%llx", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno, - __entry->agbno, - __entry->minlen, - __entry->maxlen, - __entry->mod, - __entry->prod, - __entry->minleft, - __entry->total, - __entry->alignment, - __entry->minalignslop, - __entry->len, - __print_symbolic(__entry->type, XFS_ALLOC_TYPES), - __print_symbolic(__entry->otype, XFS_ALLOC_TYPES), - __entry->wasdel, - __entry->wasfromfl, - __entry->resv, - __entry->datatype, - (unsigned long long)__entry->firstblock) -) - -#define DEFINE_ALLOC_EVENT(name) \ -DEFINE_EVENT(xfs_alloc_class, name, \ - TP_PROTO(struct xfs_alloc_arg *args), \ - TP_ARGS(args)) -DEFINE_ALLOC_EVENT(xfs_alloc_exact_done); -DEFINE_ALLOC_EVENT(xfs_alloc_exact_notfound); -DEFINE_ALLOC_EVENT(xfs_alloc_exact_error); -DEFINE_ALLOC_EVENT(xfs_alloc_near_nominleft); -DEFINE_ALLOC_EVENT(xfs_alloc_near_first); -DEFINE_ALLOC_EVENT(xfs_alloc_near_greater); -DEFINE_ALLOC_EVENT(xfs_alloc_near_lesser); -DEFINE_ALLOC_EVENT(xfs_alloc_near_error); -DEFINE_ALLOC_EVENT(xfs_alloc_near_noentry); -DEFINE_ALLOC_EVENT(xfs_alloc_near_busy); -DEFINE_ALLOC_EVENT(xfs_alloc_size_neither); -DEFINE_ALLOC_EVENT(xfs_alloc_size_noentry); -DEFINE_ALLOC_EVENT(xfs_alloc_size_nominleft); -DEFINE_ALLOC_EVENT(xfs_alloc_size_done); -DEFINE_ALLOC_EVENT(xfs_alloc_size_error); -DEFINE_ALLOC_EVENT(xfs_alloc_size_busy); -DEFINE_ALLOC_EVENT(xfs_alloc_small_freelist); -DEFINE_ALLOC_EVENT(xfs_alloc_small_notenough); -DEFINE_ALLOC_EVENT(xfs_alloc_small_done); -DEFINE_ALLOC_EVENT(xfs_alloc_small_error); -DEFINE_ALLOC_EVENT(xfs_alloc_vextent_badargs); -DEFINE_ALLOC_EVENT(xfs_alloc_vextent_nofix); -DEFINE_ALLOC_EVENT(xfs_alloc_vextent_noagbp); -DEFINE_ALLOC_EVENT(xfs_alloc_vextent_loopfailed); -DEFINE_ALLOC_EVENT(xfs_alloc_vextent_allfailed); - -DECLARE_EVENT_CLASS(xfs_da_class, - TP_PROTO(struct xfs_da_args *args), - TP_ARGS(args), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __dynamic_array(char, name, args->namelen) - __field(int, namelen) - __field(xfs_dahash_t, hashval) - __field(xfs_ino_t, inumber) - __field(int, op_flags) - ), - TP_fast_assign( - __entry->dev = VFS_I(args->dp)->i_sb->s_dev; - __entry->ino = args->dp->i_ino; - if (args->namelen) - memcpy(__get_str(name), args->name, args->namelen); - __entry->namelen = args->namelen; - __entry->hashval = args->hashval; - __entry->inumber = args->inumber; - __entry->op_flags = args->op_flags; - ), - TP_printk("dev %d:%d ino 0x%llx name %.*s namelen %d hashval 0x%x " - "inumber 0x%llx op_flags %s", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->namelen, - __entry->namelen ? __get_str(name) : NULL, - __entry->namelen, - __entry->hashval, - __entry->inumber, - __print_flags(__entry->op_flags, "|", XFS_DA_OP_FLAGS)) -) - -#define DEFINE_DIR2_EVENT(name) \ -DEFINE_EVENT(xfs_da_class, name, \ - TP_PROTO(struct xfs_da_args *args), \ - TP_ARGS(args)) -DEFINE_DIR2_EVENT(xfs_dir2_sf_addname); -DEFINE_DIR2_EVENT(xfs_dir2_sf_create); -DEFINE_DIR2_EVENT(xfs_dir2_sf_lookup); -DEFINE_DIR2_EVENT(xfs_dir2_sf_replace); -DEFINE_DIR2_EVENT(xfs_dir2_sf_removename); -DEFINE_DIR2_EVENT(xfs_dir2_sf_toino4); -DEFINE_DIR2_EVENT(xfs_dir2_sf_toino8); -DEFINE_DIR2_EVENT(xfs_dir2_sf_to_block); -DEFINE_DIR2_EVENT(xfs_dir2_block_addname); -DEFINE_DIR2_EVENT(xfs_dir2_block_lookup); -DEFINE_DIR2_EVENT(xfs_dir2_block_replace); -DEFINE_DIR2_EVENT(xfs_dir2_block_removename); -DEFINE_DIR2_EVENT(xfs_dir2_block_to_sf); -DEFINE_DIR2_EVENT(xfs_dir2_block_to_leaf); -DEFINE_DIR2_EVENT(xfs_dir2_leaf_addname); -DEFINE_DIR2_EVENT(xfs_dir2_leaf_lookup); -DEFINE_DIR2_EVENT(xfs_dir2_leaf_replace); -DEFINE_DIR2_EVENT(xfs_dir2_leaf_removename); -DEFINE_DIR2_EVENT(xfs_dir2_leaf_to_block); -DEFINE_DIR2_EVENT(xfs_dir2_leaf_to_node); -DEFINE_DIR2_EVENT(xfs_dir2_node_addname); -DEFINE_DIR2_EVENT(xfs_dir2_node_lookup); -DEFINE_DIR2_EVENT(xfs_dir2_node_replace); -DEFINE_DIR2_EVENT(xfs_dir2_node_removename); -DEFINE_DIR2_EVENT(xfs_dir2_node_to_leaf); - -DECLARE_EVENT_CLASS(xfs_attr_class, - TP_PROTO(struct xfs_da_args *args), - TP_ARGS(args), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __dynamic_array(char, name, args->namelen) - __field(int, namelen) - __field(int, valuelen) - __field(xfs_dahash_t, hashval) - __field(int, op_flags) - ), - TP_fast_assign( - __entry->dev = VFS_I(args->dp)->i_sb->s_dev; - __entry->ino = args->dp->i_ino; - if (args->namelen) - memcpy(__get_str(name), args->name, args->namelen); - __entry->namelen = args->namelen; - __entry->valuelen = args->valuelen; - __entry->hashval = args->hashval; - __entry->op_flags = args->op_flags; - ), - TP_printk("dev %d:%d ino 0x%llx name %.*s namelen %d valuelen %d " - "hashval 0x%x op_flags %s", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->namelen, - __entry->namelen ? __get_str(name) : NULL, - __entry->namelen, - __entry->valuelen, - __entry->hashval, - __print_flags(__entry->op_flags, "|", XFS_DA_OP_FLAGS)) -) - -#define DEFINE_ATTR_EVENT(name) \ -DEFINE_EVENT(xfs_attr_class, name, \ - TP_PROTO(struct xfs_da_args *args), \ - TP_ARGS(args)) -DEFINE_ATTR_EVENT(xfs_attr_sf_add); -DEFINE_ATTR_EVENT(xfs_attr_sf_addname); -DEFINE_ATTR_EVENT(xfs_attr_sf_create); -DEFINE_ATTR_EVENT(xfs_attr_sf_lookup); -DEFINE_ATTR_EVENT(xfs_attr_sf_remove); -DEFINE_ATTR_EVENT(xfs_attr_sf_removename); -DEFINE_ATTR_EVENT(xfs_attr_sf_to_leaf); - -DEFINE_ATTR_EVENT(xfs_attr_leaf_add); -DEFINE_ATTR_EVENT(xfs_attr_leaf_add_old); -DEFINE_ATTR_EVENT(xfs_attr_leaf_add_new); -DEFINE_ATTR_EVENT(xfs_attr_leaf_add_work); -DEFINE_ATTR_EVENT(xfs_attr_leaf_addname); -DEFINE_ATTR_EVENT(xfs_attr_leaf_create); -DEFINE_ATTR_EVENT(xfs_attr_leaf_compact); -DEFINE_ATTR_EVENT(xfs_attr_leaf_get); -DEFINE_ATTR_EVENT(xfs_attr_leaf_lookup); -DEFINE_ATTR_EVENT(xfs_attr_leaf_replace); -DEFINE_ATTR_EVENT(xfs_attr_leaf_remove); -DEFINE_ATTR_EVENT(xfs_attr_leaf_removename); -DEFINE_ATTR_EVENT(xfs_attr_leaf_split); -DEFINE_ATTR_EVENT(xfs_attr_leaf_split_before); -DEFINE_ATTR_EVENT(xfs_attr_leaf_split_after); -DEFINE_ATTR_EVENT(xfs_attr_leaf_clearflag); -DEFINE_ATTR_EVENT(xfs_attr_leaf_setflag); -DEFINE_ATTR_EVENT(xfs_attr_leaf_flipflags); -DEFINE_ATTR_EVENT(xfs_attr_leaf_to_sf); -DEFINE_ATTR_EVENT(xfs_attr_leaf_to_node); -DEFINE_ATTR_EVENT(xfs_attr_leaf_rebalance); -DEFINE_ATTR_EVENT(xfs_attr_leaf_unbalance); -DEFINE_ATTR_EVENT(xfs_attr_leaf_toosmall); - -DEFINE_ATTR_EVENT(xfs_attr_node_addname); -DEFINE_ATTR_EVENT(xfs_attr_node_get); -DEFINE_ATTR_EVENT(xfs_attr_node_lookup); -DEFINE_ATTR_EVENT(xfs_attr_node_replace); -DEFINE_ATTR_EVENT(xfs_attr_node_removename); - -DEFINE_ATTR_EVENT(xfs_attr_fillstate); -DEFINE_ATTR_EVENT(xfs_attr_refillstate); - -DEFINE_ATTR_EVENT(xfs_attr_rmtval_get); -DEFINE_ATTR_EVENT(xfs_attr_rmtval_set); -DEFINE_ATTR_EVENT(xfs_attr_rmtval_remove); - -#define DEFINE_DA_EVENT(name) \ -DEFINE_EVENT(xfs_da_class, name, \ - TP_PROTO(struct xfs_da_args *args), \ - TP_ARGS(args)) -DEFINE_DA_EVENT(xfs_da_split); -DEFINE_DA_EVENT(xfs_da_join); -DEFINE_DA_EVENT(xfs_da_link_before); -DEFINE_DA_EVENT(xfs_da_link_after); -DEFINE_DA_EVENT(xfs_da_unlink_back); -DEFINE_DA_EVENT(xfs_da_unlink_forward); -DEFINE_DA_EVENT(xfs_da_root_split); -DEFINE_DA_EVENT(xfs_da_root_join); -DEFINE_DA_EVENT(xfs_da_node_add); -DEFINE_DA_EVENT(xfs_da_node_create); -DEFINE_DA_EVENT(xfs_da_node_split); -DEFINE_DA_EVENT(xfs_da_node_remove); -DEFINE_DA_EVENT(xfs_da_node_rebalance); -DEFINE_DA_EVENT(xfs_da_node_unbalance); -DEFINE_DA_EVENT(xfs_da_node_toosmall); -DEFINE_DA_EVENT(xfs_da_swap_lastblock); -DEFINE_DA_EVENT(xfs_da_grow_inode); -DEFINE_DA_EVENT(xfs_da_shrink_inode); -DEFINE_DA_EVENT(xfs_da_fixhashpath); -DEFINE_DA_EVENT(xfs_da_path_shift); - -DECLARE_EVENT_CLASS(xfs_dir2_space_class, - TP_PROTO(struct xfs_da_args *args, int idx), - TP_ARGS(args, idx), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(int, op_flags) - __field(int, idx) - ), - TP_fast_assign( - __entry->dev = VFS_I(args->dp)->i_sb->s_dev; - __entry->ino = args->dp->i_ino; - __entry->op_flags = args->op_flags; - __entry->idx = idx; - ), - TP_printk("dev %d:%d ino 0x%llx op_flags %s index %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __print_flags(__entry->op_flags, "|", XFS_DA_OP_FLAGS), - __entry->idx) -) - -#define DEFINE_DIR2_SPACE_EVENT(name) \ -DEFINE_EVENT(xfs_dir2_space_class, name, \ - TP_PROTO(struct xfs_da_args *args, int idx), \ - TP_ARGS(args, idx)) -DEFINE_DIR2_SPACE_EVENT(xfs_dir2_leafn_add); -DEFINE_DIR2_SPACE_EVENT(xfs_dir2_leafn_remove); -DEFINE_DIR2_SPACE_EVENT(xfs_dir2_grow_inode); -DEFINE_DIR2_SPACE_EVENT(xfs_dir2_shrink_inode); - -TRACE_EVENT(xfs_dir2_leafn_moveents, - TP_PROTO(struct xfs_da_args *args, int src_idx, int dst_idx, int count), - TP_ARGS(args, src_idx, dst_idx, count), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(int, op_flags) - __field(int, src_idx) - __field(int, dst_idx) - __field(int, count) - ), - TP_fast_assign( - __entry->dev = VFS_I(args->dp)->i_sb->s_dev; - __entry->ino = args->dp->i_ino; - __entry->op_flags = args->op_flags; - __entry->src_idx = src_idx; - __entry->dst_idx = dst_idx; - __entry->count = count; - ), - TP_printk("dev %d:%d ino 0x%llx op_flags %s " - "src_idx %d dst_idx %d count %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __print_flags(__entry->op_flags, "|", XFS_DA_OP_FLAGS), - __entry->src_idx, - __entry->dst_idx, - __entry->count) -); - -#define XFS_SWAPEXT_INODES \ - { 0, "target" }, \ - { 1, "temp" } - -#define XFS_INODE_FORMAT_STR \ - { 0, "invalid" }, \ - { 1, "local" }, \ - { 2, "extent" }, \ - { 3, "btree" } - -DECLARE_EVENT_CLASS(xfs_swap_extent_class, - TP_PROTO(struct xfs_inode *ip, int which), - TP_ARGS(ip, which), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(int, which) - __field(xfs_ino_t, ino) - __field(int, format) - __field(int, nex) - __field(int, broot_size) - __field(int, fork_off) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->which = which; - __entry->ino = ip->i_ino; - __entry->format = ip->i_d.di_format; - __entry->nex = ip->i_d.di_nextents; - __entry->broot_size = ip->i_df.if_broot_bytes; - __entry->fork_off = XFS_IFORK_BOFF(ip); - ), - TP_printk("dev %d:%d ino 0x%llx (%s), %s format, num_extents %d, " - "broot size %d, fork offset %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __print_symbolic(__entry->which, XFS_SWAPEXT_INODES), - __print_symbolic(__entry->format, XFS_INODE_FORMAT_STR), - __entry->nex, - __entry->broot_size, - __entry->fork_off) -) - -#define DEFINE_SWAPEXT_EVENT(name) \ -DEFINE_EVENT(xfs_swap_extent_class, name, \ - TP_PROTO(struct xfs_inode *ip, int which), \ - TP_ARGS(ip, which)) - -DEFINE_SWAPEXT_EVENT(xfs_swap_extent_before); -DEFINE_SWAPEXT_EVENT(xfs_swap_extent_after); - -TRACE_EVENT(xfs_log_recover_record, - TP_PROTO(struct xlog *log, struct xlog_rec_header *rhead, int pass), - TP_ARGS(log, rhead, pass), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_lsn_t, lsn) - __field(int, len) - __field(int, num_logops) - __field(int, pass) - ), - TP_fast_assign( - __entry->dev = log->l_mp->m_super->s_dev; - __entry->lsn = be64_to_cpu(rhead->h_lsn); - __entry->len = be32_to_cpu(rhead->h_len); - __entry->num_logops = be32_to_cpu(rhead->h_num_logops); - __entry->pass = pass; - ), - TP_printk("dev %d:%d lsn 0x%llx len 0x%x num_logops 0x%x pass %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->lsn, __entry->len, __entry->num_logops, - __entry->pass) -) - -DECLARE_EVENT_CLASS(xfs_log_recover_item_class, - TP_PROTO(struct xlog *log, struct xlog_recover *trans, - struct xlog_recover_item *item, int pass), - TP_ARGS(log, trans, item, pass), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(unsigned long, item) - __field(xlog_tid_t, tid) - __field(xfs_lsn_t, lsn) - __field(int, type) - __field(int, pass) - __field(int, count) - __field(int, total) - ), - TP_fast_assign( - __entry->dev = log->l_mp->m_super->s_dev; - __entry->item = (unsigned long)item; - __entry->tid = trans->r_log_tid; - __entry->lsn = trans->r_lsn; - __entry->type = ITEM_TYPE(item); - __entry->pass = pass; - __entry->count = item->ri_cnt; - __entry->total = item->ri_total; - ), - TP_printk("dev %d:%d tid 0x%x lsn 0x%llx, pass %d, item 0x%p, " - "item type %s item region count/total %d/%d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->tid, - __entry->lsn, - __entry->pass, - (void *)__entry->item, - __print_symbolic(__entry->type, XFS_LI_TYPE_DESC), - __entry->count, - __entry->total) -) - -#define DEFINE_LOG_RECOVER_ITEM(name) \ -DEFINE_EVENT(xfs_log_recover_item_class, name, \ - TP_PROTO(struct xlog *log, struct xlog_recover *trans, \ - struct xlog_recover_item *item, int pass), \ - TP_ARGS(log, trans, item, pass)) - -DEFINE_LOG_RECOVER_ITEM(xfs_log_recover_item_add); -DEFINE_LOG_RECOVER_ITEM(xfs_log_recover_item_add_cont); -DEFINE_LOG_RECOVER_ITEM(xfs_log_recover_item_reorder_head); -DEFINE_LOG_RECOVER_ITEM(xfs_log_recover_item_reorder_tail); -DEFINE_LOG_RECOVER_ITEM(xfs_log_recover_item_recover); - -DECLARE_EVENT_CLASS(xfs_log_recover_buf_item_class, - TP_PROTO(struct xlog *log, struct xfs_buf_log_format *buf_f), - TP_ARGS(log, buf_f), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(__int64_t, blkno) - __field(unsigned short, len) - __field(unsigned short, flags) - __field(unsigned short, size) - __field(unsigned int, map_size) - ), - TP_fast_assign( - __entry->dev = log->l_mp->m_super->s_dev; - __entry->blkno = buf_f->blf_blkno; - __entry->len = buf_f->blf_len; - __entry->flags = buf_f->blf_flags; - __entry->size = buf_f->blf_size; - __entry->map_size = buf_f->blf_map_size; - ), - TP_printk("dev %d:%d blkno 0x%llx, len %u, flags 0x%x, size %d, " - "map_size %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->blkno, - __entry->len, - __entry->flags, - __entry->size, - __entry->map_size) -) - -#define DEFINE_LOG_RECOVER_BUF_ITEM(name) \ -DEFINE_EVENT(xfs_log_recover_buf_item_class, name, \ - TP_PROTO(struct xlog *log, struct xfs_buf_log_format *buf_f), \ - TP_ARGS(log, buf_f)) - -DEFINE_LOG_RECOVER_BUF_ITEM(xfs_log_recover_buf_not_cancel); -DEFINE_LOG_RECOVER_BUF_ITEM(xfs_log_recover_buf_cancel); -DEFINE_LOG_RECOVER_BUF_ITEM(xfs_log_recover_buf_cancel_add); -DEFINE_LOG_RECOVER_BUF_ITEM(xfs_log_recover_buf_cancel_ref_inc); -DEFINE_LOG_RECOVER_BUF_ITEM(xfs_log_recover_buf_recover); -DEFINE_LOG_RECOVER_BUF_ITEM(xfs_log_recover_buf_skip); -DEFINE_LOG_RECOVER_BUF_ITEM(xfs_log_recover_buf_inode_buf); -DEFINE_LOG_RECOVER_BUF_ITEM(xfs_log_recover_buf_reg_buf); -DEFINE_LOG_RECOVER_BUF_ITEM(xfs_log_recover_buf_dquot_buf); - -DECLARE_EVENT_CLASS(xfs_log_recover_ino_item_class, - TP_PROTO(struct xlog *log, struct xfs_inode_log_format *in_f), - TP_ARGS(log, in_f), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(unsigned short, size) - __field(int, fields) - __field(unsigned short, asize) - __field(unsigned short, dsize) - __field(__int64_t, blkno) - __field(int, len) - __field(int, boffset) - ), - TP_fast_assign( - __entry->dev = log->l_mp->m_super->s_dev; - __entry->ino = in_f->ilf_ino; - __entry->size = in_f->ilf_size; - __entry->fields = in_f->ilf_fields; - __entry->asize = in_f->ilf_asize; - __entry->dsize = in_f->ilf_dsize; - __entry->blkno = in_f->ilf_blkno; - __entry->len = in_f->ilf_len; - __entry->boffset = in_f->ilf_boffset; - ), - TP_printk("dev %d:%d ino 0x%llx, size %u, fields 0x%x, asize %d, " - "dsize %d, blkno 0x%llx, len %d, boffset %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->size, - __entry->fields, - __entry->asize, - __entry->dsize, - __entry->blkno, - __entry->len, - __entry->boffset) -) -#define DEFINE_LOG_RECOVER_INO_ITEM(name) \ -DEFINE_EVENT(xfs_log_recover_ino_item_class, name, \ - TP_PROTO(struct xlog *log, struct xfs_inode_log_format *in_f), \ - TP_ARGS(log, in_f)) - -DEFINE_LOG_RECOVER_INO_ITEM(xfs_log_recover_inode_recover); -DEFINE_LOG_RECOVER_INO_ITEM(xfs_log_recover_inode_cancel); -DEFINE_LOG_RECOVER_INO_ITEM(xfs_log_recover_inode_skip); - -DECLARE_EVENT_CLASS(xfs_log_recover_icreate_item_class, - TP_PROTO(struct xlog *log, struct xfs_icreate_log *in_f), - TP_ARGS(log, in_f), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(xfs_agblock_t, agbno) - __field(unsigned int, count) - __field(unsigned int, isize) - __field(xfs_agblock_t, length) - __field(unsigned int, gen) - ), - TP_fast_assign( - __entry->dev = log->l_mp->m_super->s_dev; - __entry->agno = be32_to_cpu(in_f->icl_ag); - __entry->agbno = be32_to_cpu(in_f->icl_agbno); - __entry->count = be32_to_cpu(in_f->icl_count); - __entry->isize = be32_to_cpu(in_f->icl_isize); - __entry->length = be32_to_cpu(in_f->icl_length); - __entry->gen = be32_to_cpu(in_f->icl_gen); - ), - TP_printk("dev %d:%d agno %u agbno %u count %u isize %u length %u " - "gen %u", MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno, __entry->agbno, __entry->count, __entry->isize, - __entry->length, __entry->gen) -) -#define DEFINE_LOG_RECOVER_ICREATE_ITEM(name) \ -DEFINE_EVENT(xfs_log_recover_icreate_item_class, name, \ - TP_PROTO(struct xlog *log, struct xfs_icreate_log *in_f), \ - TP_ARGS(log, in_f)) - -DEFINE_LOG_RECOVER_ICREATE_ITEM(xfs_log_recover_icreate_cancel); -DEFINE_LOG_RECOVER_ICREATE_ITEM(xfs_log_recover_icreate_recover); - -DECLARE_EVENT_CLASS(xfs_discard_class, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, - xfs_agblock_t agbno, xfs_extlen_t len), - TP_ARGS(mp, agno, agbno, len), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(xfs_agblock_t, agbno) - __field(xfs_extlen_t, len) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->agbno = agbno; - __entry->len = len; - ), - TP_printk("dev %d:%d agno %u agbno %u len %u\n", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno, - __entry->agbno, - __entry->len) -) - -#define DEFINE_DISCARD_EVENT(name) \ -DEFINE_EVENT(xfs_discard_class, name, \ - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \ - xfs_agblock_t agbno, xfs_extlen_t len), \ - TP_ARGS(mp, agno, agbno, len)) -DEFINE_DISCARD_EVENT(xfs_discard_extent); -DEFINE_DISCARD_EVENT(xfs_discard_toosmall); -DEFINE_DISCARD_EVENT(xfs_discard_exclude); -DEFINE_DISCARD_EVENT(xfs_discard_busy); - -/* btree cursor events */ -DECLARE_EVENT_CLASS(xfs_btree_cur_class, - TP_PROTO(struct xfs_btree_cur *cur, int level, struct xfs_buf *bp), - TP_ARGS(cur, level, bp), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_btnum_t, btnum) - __field(int, level) - __field(int, nlevels) - __field(int, ptr) - __field(xfs_daddr_t, daddr) - ), - TP_fast_assign( - __entry->dev = cur->bc_mp->m_super->s_dev; - __entry->btnum = cur->bc_btnum; - __entry->level = level; - __entry->nlevels = cur->bc_nlevels; - __entry->ptr = cur->bc_ptrs[level]; - __entry->daddr = bp ? bp->b_bn : -1; - ), - TP_printk("dev %d:%d btnum %d level %d/%d ptr %d daddr 0x%llx", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->btnum, - __entry->level, - __entry->nlevels, - __entry->ptr, - (unsigned long long)__entry->daddr) -) - -#define DEFINE_BTREE_CUR_EVENT(name) \ -DEFINE_EVENT(xfs_btree_cur_class, name, \ - TP_PROTO(struct xfs_btree_cur *cur, int level, struct xfs_buf *bp), \ - TP_ARGS(cur, level, bp)) -DEFINE_BTREE_CUR_EVENT(xfs_btree_updkeys); -DEFINE_BTREE_CUR_EVENT(xfs_btree_overlapped_query_range); - -/* deferred ops */ -struct xfs_defer_pending; -struct xfs_defer_intake; -struct xfs_defer_ops; - -DECLARE_EVENT_CLASS(xfs_defer_class, - TP_PROTO(struct xfs_mount *mp, struct xfs_defer_ops *dop), - TP_ARGS(mp, dop), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(void *, dop) - __field(bool, committed) - __field(bool, low) - ), - TP_fast_assign( - __entry->dev = mp ? mp->m_super->s_dev : 0; - __entry->dop = dop; - __entry->committed = dop->dop_committed; - __entry->low = dop->dop_low; - ), - TP_printk("dev %d:%d ops %p committed %d low %d\n", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->dop, - __entry->committed, - __entry->low) -) -#define DEFINE_DEFER_EVENT(name) \ -DEFINE_EVENT(xfs_defer_class, name, \ - TP_PROTO(struct xfs_mount *mp, struct xfs_defer_ops *dop), \ - TP_ARGS(mp, dop)) - -DECLARE_EVENT_CLASS(xfs_defer_error_class, - TP_PROTO(struct xfs_mount *mp, struct xfs_defer_ops *dop, int error), - TP_ARGS(mp, dop, error), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(void *, dop) - __field(bool, committed) - __field(bool, low) - __field(int, error) - ), - TP_fast_assign( - __entry->dev = mp ? mp->m_super->s_dev : 0; - __entry->dop = dop; - __entry->committed = dop->dop_committed; - __entry->low = dop->dop_low; - __entry->error = error; - ), - TP_printk("dev %d:%d ops %p committed %d low %d err %d\n", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->dop, - __entry->committed, - __entry->low, - __entry->error) -) -#define DEFINE_DEFER_ERROR_EVENT(name) \ -DEFINE_EVENT(xfs_defer_error_class, name, \ - TP_PROTO(struct xfs_mount *mp, struct xfs_defer_ops *dop, int error), \ - TP_ARGS(mp, dop, error)) - -DECLARE_EVENT_CLASS(xfs_defer_pending_class, - TP_PROTO(struct xfs_mount *mp, struct xfs_defer_pending *dfp), - TP_ARGS(mp, dfp), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(int, type) - __field(void *, intent) - __field(bool, committed) - __field(int, nr) - ), - TP_fast_assign( - __entry->dev = mp ? mp->m_super->s_dev : 0; - __entry->type = dfp->dfp_type->type; - __entry->intent = dfp->dfp_intent; - __entry->committed = dfp->dfp_done != NULL; - __entry->nr = dfp->dfp_count; - ), - TP_printk("dev %d:%d optype %d intent %p committed %d nr %d\n", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->type, - __entry->intent, - __entry->committed, - __entry->nr) -) -#define DEFINE_DEFER_PENDING_EVENT(name) \ -DEFINE_EVENT(xfs_defer_pending_class, name, \ - TP_PROTO(struct xfs_mount *mp, struct xfs_defer_pending *dfp), \ - TP_ARGS(mp, dfp)) - -DECLARE_EVENT_CLASS(xfs_phys_extent_deferred_class, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, - int type, xfs_agblock_t agbno, xfs_extlen_t len), - TP_ARGS(mp, agno, type, agbno, len), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(int, type) - __field(xfs_agblock_t, agbno) - __field(xfs_extlen_t, len) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->type = type; - __entry->agbno = agbno; - __entry->len = len; - ), - TP_printk("dev %d:%d op %d agno %u agbno %u len %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->type, - __entry->agno, - __entry->agbno, - __entry->len) -); -#define DEFINE_PHYS_EXTENT_DEFERRED_EVENT(name) \ -DEFINE_EVENT(xfs_phys_extent_deferred_class, name, \ - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \ - int type, \ - xfs_agblock_t bno, \ - xfs_extlen_t len), \ - TP_ARGS(mp, agno, type, bno, len)) - -DECLARE_EVENT_CLASS(xfs_map_extent_deferred_class, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, - int op, - xfs_agblock_t agbno, - xfs_ino_t ino, - int whichfork, - xfs_fileoff_t offset, - xfs_filblks_t len, - xfs_exntst_t state), - TP_ARGS(mp, agno, op, agbno, ino, whichfork, offset, len, state), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(xfs_ino_t, ino) - __field(xfs_agblock_t, agbno) - __field(int, whichfork) - __field(xfs_fileoff_t, l_loff) - __field(xfs_filblks_t, l_len) - __field(xfs_exntst_t, l_state) - __field(int, op) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->ino = ino; - __entry->agbno = agbno; - __entry->whichfork = whichfork; - __entry->l_loff = offset; - __entry->l_len = len; - __entry->l_state = state; - __entry->op = op; - ), - TP_printk("dev %d:%d op %d agno %u agbno %u owner %lld %s offset %llu len %llu state %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->op, - __entry->agno, - __entry->agbno, - __entry->ino, - __entry->whichfork == XFS_ATTR_FORK ? "attr" : "data", - __entry->l_loff, - __entry->l_len, - __entry->l_state) -); -#define DEFINE_MAP_EXTENT_DEFERRED_EVENT(name) \ -DEFINE_EVENT(xfs_map_extent_deferred_class, name, \ - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \ - int op, \ - xfs_agblock_t agbno, \ - xfs_ino_t ino, \ - int whichfork, \ - xfs_fileoff_t offset, \ - xfs_filblks_t len, \ - xfs_exntst_t state), \ - TP_ARGS(mp, agno, op, agbno, ino, whichfork, offset, len, state)) - -DEFINE_DEFER_EVENT(xfs_defer_init); -DEFINE_DEFER_EVENT(xfs_defer_cancel); -DEFINE_DEFER_EVENT(xfs_defer_trans_roll); -DEFINE_DEFER_EVENT(xfs_defer_trans_abort); -DEFINE_DEFER_EVENT(xfs_defer_finish); -DEFINE_DEFER_EVENT(xfs_defer_finish_done); - -DEFINE_DEFER_ERROR_EVENT(xfs_defer_trans_roll_error); -DEFINE_DEFER_ERROR_EVENT(xfs_defer_finish_error); -DEFINE_DEFER_ERROR_EVENT(xfs_defer_op_finish_error); - -DEFINE_DEFER_PENDING_EVENT(xfs_defer_intake_work); -DEFINE_DEFER_PENDING_EVENT(xfs_defer_intake_cancel); -DEFINE_DEFER_PENDING_EVENT(xfs_defer_pending_commit); -DEFINE_DEFER_PENDING_EVENT(xfs_defer_pending_cancel); -DEFINE_DEFER_PENDING_EVENT(xfs_defer_pending_finish); -DEFINE_DEFER_PENDING_EVENT(xfs_defer_pending_abort); - -#define DEFINE_BMAP_FREE_DEFERRED_EVENT DEFINE_PHYS_EXTENT_DEFERRED_EVENT -DEFINE_BMAP_FREE_DEFERRED_EVENT(xfs_bmap_free_defer); -DEFINE_BMAP_FREE_DEFERRED_EVENT(xfs_bmap_free_deferred); - -/* rmap tracepoints */ -DECLARE_EVENT_CLASS(xfs_rmap_class, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, - xfs_agblock_t agbno, xfs_extlen_t len, bool unwritten, - struct xfs_owner_info *oinfo), - TP_ARGS(mp, agno, agbno, len, unwritten, oinfo), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(xfs_agblock_t, agbno) - __field(xfs_extlen_t, len) - __field(uint64_t, owner) - __field(uint64_t, offset) - __field(unsigned long, flags) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->agbno = agbno; - __entry->len = len; - __entry->owner = oinfo->oi_owner; - __entry->offset = oinfo->oi_offset; - __entry->flags = oinfo->oi_flags; - if (unwritten) - __entry->flags |= XFS_RMAP_UNWRITTEN; - ), - TP_printk("dev %d:%d agno %u agbno %u len %u owner %lld offset %llu flags 0x%lx", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno, - __entry->agbno, - __entry->len, - __entry->owner, - __entry->offset, - __entry->flags) -); -#define DEFINE_RMAP_EVENT(name) \ -DEFINE_EVENT(xfs_rmap_class, name, \ - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \ - xfs_agblock_t agbno, xfs_extlen_t len, bool unwritten, \ - struct xfs_owner_info *oinfo), \ - TP_ARGS(mp, agno, agbno, len, unwritten, oinfo)) - -/* simple AG-based error/%ip tracepoint class */ -DECLARE_EVENT_CLASS(xfs_ag_error_class, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, int error, - unsigned long caller_ip), - TP_ARGS(mp, agno, error, caller_ip), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(int, error) - __field(unsigned long, caller_ip) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->error = error; - __entry->caller_ip = caller_ip; - ), - TP_printk("dev %d:%d agno %u error %d caller %ps", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno, - __entry->error, - (char *)__entry->caller_ip) -); - -#define DEFINE_AG_ERROR_EVENT(name) \ -DEFINE_EVENT(xfs_ag_error_class, name, \ - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, int error, \ - unsigned long caller_ip), \ - TP_ARGS(mp, agno, error, caller_ip)) - -DEFINE_RMAP_EVENT(xfs_rmap_unmap); -DEFINE_RMAP_EVENT(xfs_rmap_unmap_done); -DEFINE_AG_ERROR_EVENT(xfs_rmap_unmap_error); -DEFINE_RMAP_EVENT(xfs_rmap_map); -DEFINE_RMAP_EVENT(xfs_rmap_map_done); -DEFINE_AG_ERROR_EVENT(xfs_rmap_map_error); -DEFINE_RMAP_EVENT(xfs_rmap_convert); -DEFINE_RMAP_EVENT(xfs_rmap_convert_done); -DEFINE_AG_ERROR_EVENT(xfs_rmap_convert_error); -DEFINE_AG_ERROR_EVENT(xfs_rmap_convert_state); - -DECLARE_EVENT_CLASS(xfs_rmapbt_class, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, - xfs_agblock_t agbno, xfs_extlen_t len, - uint64_t owner, uint64_t offset, unsigned int flags), - TP_ARGS(mp, agno, agbno, len, owner, offset, flags), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(xfs_agblock_t, agbno) - __field(xfs_extlen_t, len) - __field(uint64_t, owner) - __field(uint64_t, offset) - __field(unsigned int, flags) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->agbno = agbno; - __entry->len = len; - __entry->owner = owner; - __entry->offset = offset; - __entry->flags = flags; - ), - TP_printk("dev %d:%d agno %u agbno %u len %u owner %lld offset %llu flags 0x%x", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno, - __entry->agbno, - __entry->len, - __entry->owner, - __entry->offset, - __entry->flags) -); -#define DEFINE_RMAPBT_EVENT(name) \ -DEFINE_EVENT(xfs_rmapbt_class, name, \ - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \ - xfs_agblock_t agbno, xfs_extlen_t len, \ - uint64_t owner, uint64_t offset, unsigned int flags), \ - TP_ARGS(mp, agno, agbno, len, owner, offset, flags)) - -#define DEFINE_RMAP_DEFERRED_EVENT DEFINE_MAP_EXTENT_DEFERRED_EVENT -DEFINE_RMAP_DEFERRED_EVENT(xfs_rmap_defer); -DEFINE_RMAP_DEFERRED_EVENT(xfs_rmap_deferred); - -DEFINE_BUSY_EVENT(xfs_rmapbt_alloc_block); -DEFINE_BUSY_EVENT(xfs_rmapbt_free_block); -DEFINE_RMAPBT_EVENT(xfs_rmap_update); -DEFINE_RMAPBT_EVENT(xfs_rmap_insert); -DEFINE_RMAPBT_EVENT(xfs_rmap_delete); -DEFINE_AG_ERROR_EVENT(xfs_rmap_insert_error); -DEFINE_AG_ERROR_EVENT(xfs_rmap_delete_error); -DEFINE_AG_ERROR_EVENT(xfs_rmap_update_error); - -DEFINE_RMAPBT_EVENT(xfs_rmap_find_left_neighbor_candidate); -DEFINE_RMAPBT_EVENT(xfs_rmap_find_left_neighbor_query); -DEFINE_RMAPBT_EVENT(xfs_rmap_lookup_le_range_candidate); -DEFINE_RMAPBT_EVENT(xfs_rmap_lookup_le_range); -DEFINE_RMAPBT_EVENT(xfs_rmap_lookup_le_range_result); -DEFINE_RMAPBT_EVENT(xfs_rmap_find_right_neighbor_result); -DEFINE_RMAPBT_EVENT(xfs_rmap_find_left_neighbor_result); - -/* deferred bmbt updates */ -#define DEFINE_BMAP_DEFERRED_EVENT DEFINE_RMAP_DEFERRED_EVENT -DEFINE_BMAP_DEFERRED_EVENT(xfs_bmap_defer); -DEFINE_BMAP_DEFERRED_EVENT(xfs_bmap_deferred); - -/* per-AG reservation */ -DECLARE_EVENT_CLASS(xfs_ag_resv_class, - TP_PROTO(struct xfs_perag *pag, enum xfs_ag_resv_type resv, - xfs_extlen_t len), - TP_ARGS(pag, resv, len), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(int, resv) - __field(xfs_extlen_t, freeblks) - __field(xfs_extlen_t, flcount) - __field(xfs_extlen_t, reserved) - __field(xfs_extlen_t, asked) - __field(xfs_extlen_t, len) - ), - TP_fast_assign( - struct xfs_ag_resv *r = xfs_perag_resv(pag, resv); - - __entry->dev = pag->pag_mount->m_super->s_dev; - __entry->agno = pag->pag_agno; - __entry->resv = resv; - __entry->freeblks = pag->pagf_freeblks; - __entry->flcount = pag->pagf_flcount; - __entry->reserved = r ? r->ar_reserved : 0; - __entry->asked = r ? r->ar_asked : 0; - __entry->len = len; - ), - TP_printk("dev %d:%d agno %u resv %d freeblks %u flcount %u resv %u ask %u len %u\n", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno, - __entry->resv, - __entry->freeblks, - __entry->flcount, - __entry->reserved, - __entry->asked, - __entry->len) -) -#define DEFINE_AG_RESV_EVENT(name) \ -DEFINE_EVENT(xfs_ag_resv_class, name, \ - TP_PROTO(struct xfs_perag *pag, enum xfs_ag_resv_type type, \ - xfs_extlen_t len), \ - TP_ARGS(pag, type, len)) - -/* per-AG reservation tracepoints */ -DEFINE_AG_RESV_EVENT(xfs_ag_resv_init); -DEFINE_AG_RESV_EVENT(xfs_ag_resv_free); -DEFINE_AG_RESV_EVENT(xfs_ag_resv_alloc_extent); -DEFINE_AG_RESV_EVENT(xfs_ag_resv_free_extent); -DEFINE_AG_RESV_EVENT(xfs_ag_resv_critical); -DEFINE_AG_RESV_EVENT(xfs_ag_resv_needed); - -DEFINE_AG_ERROR_EVENT(xfs_ag_resv_free_error); -DEFINE_AG_ERROR_EVENT(xfs_ag_resv_init_error); - -/* refcount tracepoint classes */ - -/* reuse the discard trace class for agbno/aglen-based traces */ -#define DEFINE_AG_EXTENT_EVENT(name) DEFINE_DISCARD_EVENT(name) - -/* ag btree lookup tracepoint class */ -#define XFS_AG_BTREE_CMP_FORMAT_STR \ - { XFS_LOOKUP_EQ, "eq" }, \ - { XFS_LOOKUP_LE, "le" }, \ - { XFS_LOOKUP_GE, "ge" } -DECLARE_EVENT_CLASS(xfs_ag_btree_lookup_class, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, - xfs_agblock_t agbno, xfs_lookup_t dir), - TP_ARGS(mp, agno, agbno, dir), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(xfs_agblock_t, agbno) - __field(xfs_lookup_t, dir) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->agbno = agbno; - __entry->dir = dir; - ), - TP_printk("dev %d:%d agno %u agbno %u cmp %s(%d)\n", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno, - __entry->agbno, - __print_symbolic(__entry->dir, XFS_AG_BTREE_CMP_FORMAT_STR), - __entry->dir) -) - -#define DEFINE_AG_BTREE_LOOKUP_EVENT(name) \ -DEFINE_EVENT(xfs_ag_btree_lookup_class, name, \ - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \ - xfs_agblock_t agbno, xfs_lookup_t dir), \ - TP_ARGS(mp, agno, agbno, dir)) - -/* single-rcext tracepoint class */ -DECLARE_EVENT_CLASS(xfs_refcount_extent_class, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, - struct xfs_refcount_irec *irec), - TP_ARGS(mp, agno, irec), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(xfs_agblock_t, startblock) - __field(xfs_extlen_t, blockcount) - __field(xfs_nlink_t, refcount) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->startblock = irec->rc_startblock; - __entry->blockcount = irec->rc_blockcount; - __entry->refcount = irec->rc_refcount; - ), - TP_printk("dev %d:%d agno %u agbno %u len %u refcount %u\n", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno, - __entry->startblock, - __entry->blockcount, - __entry->refcount) -) - -#define DEFINE_REFCOUNT_EXTENT_EVENT(name) \ -DEFINE_EVENT(xfs_refcount_extent_class, name, \ - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \ - struct xfs_refcount_irec *irec), \ - TP_ARGS(mp, agno, irec)) - -/* single-rcext and an agbno tracepoint class */ -DECLARE_EVENT_CLASS(xfs_refcount_extent_at_class, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, - struct xfs_refcount_irec *irec, xfs_agblock_t agbno), - TP_ARGS(mp, agno, irec, agbno), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(xfs_agblock_t, startblock) - __field(xfs_extlen_t, blockcount) - __field(xfs_nlink_t, refcount) - __field(xfs_agblock_t, agbno) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->startblock = irec->rc_startblock; - __entry->blockcount = irec->rc_blockcount; - __entry->refcount = irec->rc_refcount; - __entry->agbno = agbno; - ), - TP_printk("dev %d:%d agno %u agbno %u len %u refcount %u @ agbno %u\n", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno, - __entry->startblock, - __entry->blockcount, - __entry->refcount, - __entry->agbno) -) - -#define DEFINE_REFCOUNT_EXTENT_AT_EVENT(name) \ -DEFINE_EVENT(xfs_refcount_extent_at_class, name, \ - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \ - struct xfs_refcount_irec *irec, xfs_agblock_t agbno), \ - TP_ARGS(mp, agno, irec, agbno)) - -/* double-rcext tracepoint class */ -DECLARE_EVENT_CLASS(xfs_refcount_double_extent_class, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, - struct xfs_refcount_irec *i1, struct xfs_refcount_irec *i2), - TP_ARGS(mp, agno, i1, i2), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(xfs_agblock_t, i1_startblock) - __field(xfs_extlen_t, i1_blockcount) - __field(xfs_nlink_t, i1_refcount) - __field(xfs_agblock_t, i2_startblock) - __field(xfs_extlen_t, i2_blockcount) - __field(xfs_nlink_t, i2_refcount) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->i1_startblock = i1->rc_startblock; - __entry->i1_blockcount = i1->rc_blockcount; - __entry->i1_refcount = i1->rc_refcount; - __entry->i2_startblock = i2->rc_startblock; - __entry->i2_blockcount = i2->rc_blockcount; - __entry->i2_refcount = i2->rc_refcount; - ), - TP_printk("dev %d:%d agno %u agbno %u len %u refcount %u -- " - "agbno %u len %u refcount %u\n", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno, - __entry->i1_startblock, - __entry->i1_blockcount, - __entry->i1_refcount, - __entry->i2_startblock, - __entry->i2_blockcount, - __entry->i2_refcount) -) - -#define DEFINE_REFCOUNT_DOUBLE_EXTENT_EVENT(name) \ -DEFINE_EVENT(xfs_refcount_double_extent_class, name, \ - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \ - struct xfs_refcount_irec *i1, struct xfs_refcount_irec *i2), \ - TP_ARGS(mp, agno, i1, i2)) - -/* double-rcext and an agbno tracepoint class */ -DECLARE_EVENT_CLASS(xfs_refcount_double_extent_at_class, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, - struct xfs_refcount_irec *i1, struct xfs_refcount_irec *i2, - xfs_agblock_t agbno), - TP_ARGS(mp, agno, i1, i2, agbno), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(xfs_agblock_t, i1_startblock) - __field(xfs_extlen_t, i1_blockcount) - __field(xfs_nlink_t, i1_refcount) - __field(xfs_agblock_t, i2_startblock) - __field(xfs_extlen_t, i2_blockcount) - __field(xfs_nlink_t, i2_refcount) - __field(xfs_agblock_t, agbno) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->i1_startblock = i1->rc_startblock; - __entry->i1_blockcount = i1->rc_blockcount; - __entry->i1_refcount = i1->rc_refcount; - __entry->i2_startblock = i2->rc_startblock; - __entry->i2_blockcount = i2->rc_blockcount; - __entry->i2_refcount = i2->rc_refcount; - __entry->agbno = agbno; - ), - TP_printk("dev %d:%d agno %u agbno %u len %u refcount %u -- " - "agbno %u len %u refcount %u @ agbno %u\n", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno, - __entry->i1_startblock, - __entry->i1_blockcount, - __entry->i1_refcount, - __entry->i2_startblock, - __entry->i2_blockcount, - __entry->i2_refcount, - __entry->agbno) -) - -#define DEFINE_REFCOUNT_DOUBLE_EXTENT_AT_EVENT(name) \ -DEFINE_EVENT(xfs_refcount_double_extent_at_class, name, \ - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \ - struct xfs_refcount_irec *i1, struct xfs_refcount_irec *i2, \ - xfs_agblock_t agbno), \ - TP_ARGS(mp, agno, i1, i2, agbno)) - -/* triple-rcext tracepoint class */ -DECLARE_EVENT_CLASS(xfs_refcount_triple_extent_class, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, - struct xfs_refcount_irec *i1, struct xfs_refcount_irec *i2, - struct xfs_refcount_irec *i3), - TP_ARGS(mp, agno, i1, i2, i3), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(xfs_agblock_t, i1_startblock) - __field(xfs_extlen_t, i1_blockcount) - __field(xfs_nlink_t, i1_refcount) - __field(xfs_agblock_t, i2_startblock) - __field(xfs_extlen_t, i2_blockcount) - __field(xfs_nlink_t, i2_refcount) - __field(xfs_agblock_t, i3_startblock) - __field(xfs_extlen_t, i3_blockcount) - __field(xfs_nlink_t, i3_refcount) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->i1_startblock = i1->rc_startblock; - __entry->i1_blockcount = i1->rc_blockcount; - __entry->i1_refcount = i1->rc_refcount; - __entry->i2_startblock = i2->rc_startblock; - __entry->i2_blockcount = i2->rc_blockcount; - __entry->i2_refcount = i2->rc_refcount; - __entry->i3_startblock = i3->rc_startblock; - __entry->i3_blockcount = i3->rc_blockcount; - __entry->i3_refcount = i3->rc_refcount; - ), - TP_printk("dev %d:%d agno %u agbno %u len %u refcount %u -- " - "agbno %u len %u refcount %u -- " - "agbno %u len %u refcount %u\n", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->agno, - __entry->i1_startblock, - __entry->i1_blockcount, - __entry->i1_refcount, - __entry->i2_startblock, - __entry->i2_blockcount, - __entry->i2_refcount, - __entry->i3_startblock, - __entry->i3_blockcount, - __entry->i3_refcount) -); - -#define DEFINE_REFCOUNT_TRIPLE_EXTENT_EVENT(name) \ -DEFINE_EVENT(xfs_refcount_triple_extent_class, name, \ - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, \ - struct xfs_refcount_irec *i1, struct xfs_refcount_irec *i2, \ - struct xfs_refcount_irec *i3), \ - TP_ARGS(mp, agno, i1, i2, i3)) - -/* refcount btree tracepoints */ -DEFINE_BUSY_EVENT(xfs_refcountbt_alloc_block); -DEFINE_BUSY_EVENT(xfs_refcountbt_free_block); -DEFINE_AG_BTREE_LOOKUP_EVENT(xfs_refcount_lookup); -DEFINE_REFCOUNT_EXTENT_EVENT(xfs_refcount_get); -DEFINE_REFCOUNT_EXTENT_EVENT(xfs_refcount_update); -DEFINE_REFCOUNT_EXTENT_EVENT(xfs_refcount_insert); -DEFINE_REFCOUNT_EXTENT_EVENT(xfs_refcount_delete); -DEFINE_AG_ERROR_EVENT(xfs_refcount_insert_error); -DEFINE_AG_ERROR_EVENT(xfs_refcount_delete_error); -DEFINE_AG_ERROR_EVENT(xfs_refcount_update_error); - -/* refcount adjustment tracepoints */ -DEFINE_AG_EXTENT_EVENT(xfs_refcount_increase); -DEFINE_AG_EXTENT_EVENT(xfs_refcount_decrease); -DEFINE_AG_EXTENT_EVENT(xfs_refcount_cow_increase); -DEFINE_AG_EXTENT_EVENT(xfs_refcount_cow_decrease); -DEFINE_REFCOUNT_TRIPLE_EXTENT_EVENT(xfs_refcount_merge_center_extents); -DEFINE_REFCOUNT_EXTENT_EVENT(xfs_refcount_modify_extent); -DEFINE_REFCOUNT_EXTENT_EVENT(xfs_refcount_recover_extent); -DEFINE_REFCOUNT_EXTENT_AT_EVENT(xfs_refcount_split_extent); -DEFINE_REFCOUNT_DOUBLE_EXTENT_EVENT(xfs_refcount_merge_left_extent); -DEFINE_REFCOUNT_DOUBLE_EXTENT_EVENT(xfs_refcount_merge_right_extent); -DEFINE_REFCOUNT_DOUBLE_EXTENT_AT_EVENT(xfs_refcount_find_left_extent); -DEFINE_REFCOUNT_DOUBLE_EXTENT_AT_EVENT(xfs_refcount_find_right_extent); -DEFINE_AG_ERROR_EVENT(xfs_refcount_adjust_error); -DEFINE_AG_ERROR_EVENT(xfs_refcount_adjust_cow_error); -DEFINE_AG_ERROR_EVENT(xfs_refcount_merge_center_extents_error); -DEFINE_AG_ERROR_EVENT(xfs_refcount_modify_extent_error); -DEFINE_AG_ERROR_EVENT(xfs_refcount_split_extent_error); -DEFINE_AG_ERROR_EVENT(xfs_refcount_merge_left_extent_error); -DEFINE_AG_ERROR_EVENT(xfs_refcount_merge_right_extent_error); -DEFINE_AG_ERROR_EVENT(xfs_refcount_find_left_extent_error); -DEFINE_AG_ERROR_EVENT(xfs_refcount_find_right_extent_error); - -/* reflink helpers */ -DEFINE_AG_EXTENT_EVENT(xfs_refcount_find_shared); -DEFINE_AG_EXTENT_EVENT(xfs_refcount_find_shared_result); -DEFINE_AG_ERROR_EVENT(xfs_refcount_find_shared_error); -#define DEFINE_REFCOUNT_DEFERRED_EVENT DEFINE_PHYS_EXTENT_DEFERRED_EVENT -DEFINE_REFCOUNT_DEFERRED_EVENT(xfs_refcount_defer); -DEFINE_REFCOUNT_DEFERRED_EVENT(xfs_refcount_deferred); - -TRACE_EVENT(xfs_refcount_finish_one_leftover, - TP_PROTO(struct xfs_mount *mp, xfs_agnumber_t agno, - int type, xfs_agblock_t agbno, xfs_extlen_t len, - xfs_agblock_t new_agbno, xfs_extlen_t new_len), - TP_ARGS(mp, agno, type, agbno, len, new_agbno, new_len), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_agnumber_t, agno) - __field(int, type) - __field(xfs_agblock_t, agbno) - __field(xfs_extlen_t, len) - __field(xfs_agblock_t, new_agbno) - __field(xfs_extlen_t, new_len) - ), - TP_fast_assign( - __entry->dev = mp->m_super->s_dev; - __entry->agno = agno; - __entry->type = type; - __entry->agbno = agbno; - __entry->len = len; - __entry->new_agbno = new_agbno; - __entry->new_len = new_len; - ), - TP_printk("dev %d:%d type %d agno %u agbno %u len %u new_agbno %u new_len %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->type, - __entry->agno, - __entry->agbno, - __entry->len, - __entry->new_agbno, - __entry->new_len) -); - -/* simple inode-based error/%ip tracepoint class */ -DECLARE_EVENT_CLASS(xfs_inode_error_class, - TP_PROTO(struct xfs_inode *ip, int error, unsigned long caller_ip), - TP_ARGS(ip, error, caller_ip), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(int, error) - __field(unsigned long, caller_ip) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->error = error; - __entry->caller_ip = caller_ip; - ), - TP_printk("dev %d:%d ino %llx error %d caller %ps", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->error, - (char *)__entry->caller_ip) -); - -#define DEFINE_INODE_ERROR_EVENT(name) \ -DEFINE_EVENT(xfs_inode_error_class, name, \ - TP_PROTO(struct xfs_inode *ip, int error, \ - unsigned long caller_ip), \ - TP_ARGS(ip, error, caller_ip)) - -/* reflink allocator */ -TRACE_EVENT(xfs_bmap_remap_alloc, - TP_PROTO(struct xfs_inode *ip, xfs_fsblock_t fsbno, - xfs_extlen_t len), - TP_ARGS(ip, fsbno, len), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(xfs_fsblock_t, fsbno) - __field(xfs_extlen_t, len) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->fsbno = fsbno; - __entry->len = len; - ), - TP_printk("dev %d:%d ino 0x%llx fsbno 0x%llx len %x", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->fsbno, - __entry->len) -); -DEFINE_INODE_ERROR_EVENT(xfs_bmap_remap_alloc_error); - -/* reflink tracepoint classes */ - -/* two-file io tracepoint class */ -DECLARE_EVENT_CLASS(xfs_double_io_class, - TP_PROTO(struct xfs_inode *src, xfs_off_t soffset, xfs_off_t len, - struct xfs_inode *dest, xfs_off_t doffset), - TP_ARGS(src, soffset, len, dest, doffset), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, src_ino) - __field(loff_t, src_isize) - __field(loff_t, src_disize) - __field(loff_t, src_offset) - __field(size_t, len) - __field(xfs_ino_t, dest_ino) - __field(loff_t, dest_isize) - __field(loff_t, dest_disize) - __field(loff_t, dest_offset) - ), - TP_fast_assign( - __entry->dev = VFS_I(src)->i_sb->s_dev; - __entry->src_ino = src->i_ino; - __entry->src_isize = VFS_I(src)->i_size; - __entry->src_disize = src->i_d.di_size; - __entry->src_offset = soffset; - __entry->len = len; - __entry->dest_ino = dest->i_ino; - __entry->dest_isize = VFS_I(dest)->i_size; - __entry->dest_disize = dest->i_d.di_size; - __entry->dest_offset = doffset; - ), - TP_printk("dev %d:%d count %zd " - "ino 0x%llx isize 0x%llx disize 0x%llx offset 0x%llx -> " - "ino 0x%llx isize 0x%llx disize 0x%llx offset 0x%llx", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->len, - __entry->src_ino, - __entry->src_isize, - __entry->src_disize, - __entry->src_offset, - __entry->dest_ino, - __entry->dest_isize, - __entry->dest_disize, - __entry->dest_offset) -) - -#define DEFINE_DOUBLE_IO_EVENT(name) \ -DEFINE_EVENT(xfs_double_io_class, name, \ - TP_PROTO(struct xfs_inode *src, xfs_off_t soffset, xfs_off_t len, \ - struct xfs_inode *dest, xfs_off_t doffset), \ - TP_ARGS(src, soffset, len, dest, doffset)) - -/* two-file vfs io tracepoint class */ -DECLARE_EVENT_CLASS(xfs_double_vfs_io_class, - TP_PROTO(struct inode *src, u64 soffset, u64 len, - struct inode *dest, u64 doffset), - TP_ARGS(src, soffset, len, dest, doffset), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(unsigned long, src_ino) - __field(loff_t, src_isize) - __field(loff_t, src_offset) - __field(size_t, len) - __field(unsigned long, dest_ino) - __field(loff_t, dest_isize) - __field(loff_t, dest_offset) - ), - TP_fast_assign( - __entry->dev = src->i_sb->s_dev; - __entry->src_ino = src->i_ino; - __entry->src_isize = i_size_read(src); - __entry->src_offset = soffset; - __entry->len = len; - __entry->dest_ino = dest->i_ino; - __entry->dest_isize = i_size_read(dest); - __entry->dest_offset = doffset; - ), - TP_printk("dev %d:%d count %zd " - "ino 0x%lx isize 0x%llx offset 0x%llx -> " - "ino 0x%lx isize 0x%llx offset 0x%llx", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->len, - __entry->src_ino, - __entry->src_isize, - __entry->src_offset, - __entry->dest_ino, - __entry->dest_isize, - __entry->dest_offset) -) - -#define DEFINE_DOUBLE_VFS_IO_EVENT(name) \ -DEFINE_EVENT(xfs_double_vfs_io_class, name, \ - TP_PROTO(struct inode *src, u64 soffset, u64 len, \ - struct inode *dest, u64 doffset), \ - TP_ARGS(src, soffset, len, dest, doffset)) - -/* CoW write tracepoint */ -DECLARE_EVENT_CLASS(xfs_copy_on_write_class, - TP_PROTO(struct xfs_inode *ip, xfs_fileoff_t lblk, xfs_fsblock_t pblk, - xfs_extlen_t len, xfs_fsblock_t new_pblk), - TP_ARGS(ip, lblk, pblk, len, new_pblk), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(xfs_fileoff_t, lblk) - __field(xfs_fsblock_t, pblk) - __field(xfs_extlen_t, len) - __field(xfs_fsblock_t, new_pblk) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->lblk = lblk; - __entry->pblk = pblk; - __entry->len = len; - __entry->new_pblk = new_pblk; - ), - TP_printk("dev %d:%d ino 0x%llx lblk 0x%llx pblk 0x%llx " - "len 0x%x new_pblk %llu", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->lblk, - __entry->pblk, - __entry->len, - __entry->new_pblk) -) - -#define DEFINE_COW_EVENT(name) \ -DEFINE_EVENT(xfs_copy_on_write_class, name, \ - TP_PROTO(struct xfs_inode *ip, xfs_fileoff_t lblk, xfs_fsblock_t pblk, \ - xfs_extlen_t len, xfs_fsblock_t new_pblk), \ - TP_ARGS(ip, lblk, pblk, len, new_pblk)) - -/* inode/irec events */ -DECLARE_EVENT_CLASS(xfs_inode_irec_class, - TP_PROTO(struct xfs_inode *ip, struct xfs_bmbt_irec *irec), - TP_ARGS(ip, irec), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(xfs_fileoff_t, lblk) - __field(xfs_extlen_t, len) - __field(xfs_fsblock_t, pblk) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->lblk = irec->br_startoff; - __entry->len = irec->br_blockcount; - __entry->pblk = irec->br_startblock; - ), - TP_printk("dev %d:%d ino 0x%llx lblk 0x%llx len 0x%x pblk %llu", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->lblk, - __entry->len, - __entry->pblk) -); -#define DEFINE_INODE_IREC_EVENT(name) \ -DEFINE_EVENT(xfs_inode_irec_class, name, \ - TP_PROTO(struct xfs_inode *ip, struct xfs_bmbt_irec *irec), \ - TP_ARGS(ip, irec)) - -/* refcount/reflink tracepoint definitions */ - -/* reflink tracepoints */ -DEFINE_INODE_EVENT(xfs_reflink_set_inode_flag); -DEFINE_INODE_EVENT(xfs_reflink_unset_inode_flag); -DEFINE_ITRUNC_EVENT(xfs_reflink_update_inode_size); -DEFINE_IOMAP_EVENT(xfs_reflink_remap_imap); -TRACE_EVENT(xfs_reflink_remap_blocks_loop, - TP_PROTO(struct xfs_inode *src, xfs_fileoff_t soffset, - xfs_filblks_t len, struct xfs_inode *dest, - xfs_fileoff_t doffset), - TP_ARGS(src, soffset, len, dest, doffset), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, src_ino) - __field(xfs_fileoff_t, src_lblk) - __field(xfs_filblks_t, len) - __field(xfs_ino_t, dest_ino) - __field(xfs_fileoff_t, dest_lblk) - ), - TP_fast_assign( - __entry->dev = VFS_I(src)->i_sb->s_dev; - __entry->src_ino = src->i_ino; - __entry->src_lblk = soffset; - __entry->len = len; - __entry->dest_ino = dest->i_ino; - __entry->dest_lblk = doffset; - ), - TP_printk("dev %d:%d len 0x%llx " - "ino 0x%llx offset 0x%llx blocks -> " - "ino 0x%llx offset 0x%llx blocks", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->len, - __entry->src_ino, - __entry->src_lblk, - __entry->dest_ino, - __entry->dest_lblk) -); -TRACE_EVENT(xfs_reflink_punch_range, - TP_PROTO(struct xfs_inode *ip, xfs_fileoff_t lblk, - xfs_extlen_t len), - TP_ARGS(ip, lblk, len), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(xfs_fileoff_t, lblk) - __field(xfs_extlen_t, len) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->lblk = lblk; - __entry->len = len; - ), - TP_printk("dev %d:%d ino 0x%llx lblk 0x%llx len 0x%x", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->lblk, - __entry->len) -); -TRACE_EVENT(xfs_reflink_remap, - TP_PROTO(struct xfs_inode *ip, xfs_fileoff_t lblk, - xfs_extlen_t len, xfs_fsblock_t new_pblk), - TP_ARGS(ip, lblk, len, new_pblk), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(xfs_ino_t, ino) - __field(xfs_fileoff_t, lblk) - __field(xfs_extlen_t, len) - __field(xfs_fsblock_t, new_pblk) - ), - TP_fast_assign( - __entry->dev = VFS_I(ip)->i_sb->s_dev; - __entry->ino = ip->i_ino; - __entry->lblk = lblk; - __entry->len = len; - __entry->new_pblk = new_pblk; - ), - TP_printk("dev %d:%d ino 0x%llx lblk 0x%llx len 0x%x new_pblk %llu", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, - __entry->lblk, - __entry->len, - __entry->new_pblk) -); -DEFINE_DOUBLE_IO_EVENT(xfs_reflink_remap_range); -DEFINE_INODE_ERROR_EVENT(xfs_reflink_remap_range_error); -DEFINE_INODE_ERROR_EVENT(xfs_reflink_set_inode_flag_error); -DEFINE_INODE_ERROR_EVENT(xfs_reflink_update_inode_size_error); -DEFINE_INODE_ERROR_EVENT(xfs_reflink_reflink_main_loop_error); -DEFINE_INODE_ERROR_EVENT(xfs_reflink_read_iomap_error); -DEFINE_INODE_ERROR_EVENT(xfs_reflink_remap_blocks_error); -DEFINE_INODE_ERROR_EVENT(xfs_reflink_remap_extent_error); - -/* dedupe tracepoints */ -DEFINE_DOUBLE_IO_EVENT(xfs_reflink_compare_extents); -DEFINE_INODE_ERROR_EVENT(xfs_reflink_compare_extents_error); - -/* ioctl tracepoints */ -DEFINE_DOUBLE_VFS_IO_EVENT(xfs_ioctl_reflink); -DEFINE_DOUBLE_VFS_IO_EVENT(xfs_ioctl_clone_range); -DEFINE_DOUBLE_VFS_IO_EVENT(xfs_ioctl_file_extent_same); -TRACE_EVENT(xfs_ioctl_clone, - TP_PROTO(struct inode *src, struct inode *dest), - TP_ARGS(src, dest), - TP_STRUCT__entry( - __field(dev_t, dev) - __field(unsigned long, src_ino) - __field(loff_t, src_isize) - __field(unsigned long, dest_ino) - __field(loff_t, dest_isize) - ), - TP_fast_assign( - __entry->dev = src->i_sb->s_dev; - __entry->src_ino = src->i_ino; - __entry->src_isize = i_size_read(src); - __entry->dest_ino = dest->i_ino; - __entry->dest_isize = i_size_read(dest); - ), - TP_printk("dev %d:%d " - "ino 0x%lx isize 0x%llx -> " - "ino 0x%lx isize 0x%llx\n", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->src_ino, - __entry->src_isize, - __entry->dest_ino, - __entry->dest_isize) -); - -/* unshare tracepoints */ -DEFINE_SIMPLE_IO_EVENT(xfs_reflink_unshare); -DEFINE_SIMPLE_IO_EVENT(xfs_reflink_cow_eof_block); -DEFINE_PAGE_EVENT(xfs_reflink_unshare_page); -DEFINE_INODE_ERROR_EVENT(xfs_reflink_unshare_error); -DEFINE_INODE_ERROR_EVENT(xfs_reflink_cow_eof_block_error); -DEFINE_INODE_ERROR_EVENT(xfs_reflink_dirty_page_error); - -/* copy on write */ -DEFINE_INODE_IREC_EVENT(xfs_reflink_trim_around_shared); -DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_alloc); -DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_found); -DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_enospc); - -DEFINE_RW_EVENT(xfs_reflink_reserve_cow); -DEFINE_RW_EVENT(xfs_reflink_allocate_cow_range); - -DEFINE_INODE_IREC_EVENT(xfs_reflink_bounce_dio_write); -DEFINE_IOMAP_EVENT(xfs_reflink_find_cow_mapping); -DEFINE_INODE_IREC_EVENT(xfs_reflink_trim_irec); - -DEFINE_SIMPLE_IO_EVENT(xfs_reflink_cancel_cow_range); -DEFINE_SIMPLE_IO_EVENT(xfs_reflink_end_cow); -DEFINE_INODE_IREC_EVENT(xfs_reflink_cow_remap); - -DEFINE_INODE_ERROR_EVENT(xfs_reflink_allocate_cow_range_error); -DEFINE_INODE_ERROR_EVENT(xfs_reflink_cancel_cow_range_error); -DEFINE_INODE_ERROR_EVENT(xfs_reflink_end_cow_error); - -DEFINE_COW_EVENT(xfs_reflink_fork_buf); -DEFINE_COW_EVENT(xfs_reflink_finish_fork_buf); -DEFINE_INODE_ERROR_EVENT(xfs_reflink_fork_buf_error); -DEFINE_INODE_ERROR_EVENT(xfs_reflink_finish_fork_buf_error); - -DEFINE_INODE_EVENT(xfs_reflink_cancel_pending_cow); -DEFINE_INODE_IREC_EVENT(xfs_reflink_cancel_cow); -DEFINE_INODE_ERROR_EVENT(xfs_reflink_cancel_pending_cow_error); - -/* rmap swapext tracepoints */ -DEFINE_INODE_IREC_EVENT(xfs_swap_extent_rmap_remap); -DEFINE_INODE_IREC_EVENT(xfs_swap_extent_rmap_remap_piece); -DEFINE_INODE_ERROR_EVENT(xfs_swap_extent_rmap_error); - -#endif /* _TRACE_XFS_H */ - -#undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH . -#define TRACE_INCLUDE_FILE xfs_trace -#include diff --git a/src/linux/fs/xfs/xfs_trans.c b/src/linux/fs/xfs/xfs_trans.c deleted file mode 100644 index 70f42ea..0000000 --- a/src/linux/fs/xfs/xfs_trans.c +++ /dev/null @@ -1,1082 +0,0 @@ -/* - * Copyright (c) 2000-2003,2005 Silicon Graphics, Inc. - * Copyright (C) 2010 Red Hat, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_inode.h" -#include "xfs_extent_busy.h" -#include "xfs_quota.h" -#include "xfs_trans.h" -#include "xfs_trans_priv.h" -#include "xfs_log.h" -#include "xfs_trace.h" -#include "xfs_error.h" - -kmem_zone_t *xfs_trans_zone; -kmem_zone_t *xfs_log_item_desc_zone; - -/* - * Initialize the precomputed transaction reservation values - * in the mount structure. - */ -void -xfs_trans_init( - struct xfs_mount *mp) -{ - xfs_trans_resv_calc(mp, M_RES(mp)); -} - -/* - * Free the transaction structure. If there is more clean up - * to do when the structure is freed, add it here. - */ -STATIC void -xfs_trans_free( - struct xfs_trans *tp) -{ - xfs_extent_busy_sort(&tp->t_busy); - xfs_extent_busy_clear(tp->t_mountp, &tp->t_busy, false); - - atomic_dec(&tp->t_mountp->m_active_trans); - if (!(tp->t_flags & XFS_TRANS_NO_WRITECOUNT)) - sb_end_intwrite(tp->t_mountp->m_super); - xfs_trans_free_dqinfo(tp); - kmem_zone_free(xfs_trans_zone, tp); -} - -/* - * This is called to create a new transaction which will share the - * permanent log reservation of the given transaction. The remaining - * unused block and rt extent reservations are also inherited. This - * implies that the original transaction is no longer allowed to allocate - * blocks. Locks and log items, however, are no inherited. They must - * be added to the new transaction explicitly. - */ -STATIC xfs_trans_t * -xfs_trans_dup( - xfs_trans_t *tp) -{ - xfs_trans_t *ntp; - - ntp = kmem_zone_zalloc(xfs_trans_zone, KM_SLEEP); - - /* - * Initialize the new transaction structure. - */ - ntp->t_magic = XFS_TRANS_HEADER_MAGIC; - ntp->t_mountp = tp->t_mountp; - INIT_LIST_HEAD(&ntp->t_items); - INIT_LIST_HEAD(&ntp->t_busy); - - ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES); - ASSERT(tp->t_ticket != NULL); - - ntp->t_flags = XFS_TRANS_PERM_LOG_RES | - (tp->t_flags & XFS_TRANS_RESERVE) | - (tp->t_flags & XFS_TRANS_NO_WRITECOUNT); - /* We gave our writer reference to the new transaction */ - tp->t_flags |= XFS_TRANS_NO_WRITECOUNT; - ntp->t_ticket = xfs_log_ticket_get(tp->t_ticket); - ntp->t_blk_res = tp->t_blk_res - tp->t_blk_res_used; - tp->t_blk_res = tp->t_blk_res_used; - ntp->t_rtx_res = tp->t_rtx_res - tp->t_rtx_res_used; - tp->t_rtx_res = tp->t_rtx_res_used; - ntp->t_pflags = tp->t_pflags; - - xfs_trans_dup_dqinfo(tp, ntp); - - atomic_inc(&tp->t_mountp->m_active_trans); - return ntp; -} - -/* - * This is called to reserve free disk blocks and log space for the - * given transaction. This must be done before allocating any resources - * within the transaction. - * - * This will return ENOSPC if there are not enough blocks available. - * It will sleep waiting for available log space. - * The only valid value for the flags parameter is XFS_RES_LOG_PERM, which - * is used by long running transactions. If any one of the reservations - * fails then they will all be backed out. - * - * This does not do quota reservations. That typically is done by the - * caller afterwards. - */ -static int -xfs_trans_reserve( - struct xfs_trans *tp, - struct xfs_trans_res *resp, - uint blocks, - uint rtextents) -{ - int error = 0; - bool rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; - - /* Mark this thread as being in a transaction */ - current_set_flags_nested(&tp->t_pflags, PF_FSTRANS); - - /* - * Attempt to reserve the needed disk blocks by decrementing - * the number needed from the number available. This will - * fail if the count would go below zero. - */ - if (blocks > 0) { - error = xfs_mod_fdblocks(tp->t_mountp, -((int64_t)blocks), rsvd); - if (error != 0) { - current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); - return -ENOSPC; - } - tp->t_blk_res += blocks; - } - - /* - * Reserve the log space needed for this transaction. - */ - if (resp->tr_logres > 0) { - bool permanent = false; - - ASSERT(tp->t_log_res == 0 || - tp->t_log_res == resp->tr_logres); - ASSERT(tp->t_log_count == 0 || - tp->t_log_count == resp->tr_logcount); - - if (resp->tr_logflags & XFS_TRANS_PERM_LOG_RES) { - tp->t_flags |= XFS_TRANS_PERM_LOG_RES; - permanent = true; - } else { - ASSERT(tp->t_ticket == NULL); - ASSERT(!(tp->t_flags & XFS_TRANS_PERM_LOG_RES)); - } - - if (tp->t_ticket != NULL) { - ASSERT(resp->tr_logflags & XFS_TRANS_PERM_LOG_RES); - error = xfs_log_regrant(tp->t_mountp, tp->t_ticket); - } else { - error = xfs_log_reserve(tp->t_mountp, - resp->tr_logres, - resp->tr_logcount, - &tp->t_ticket, XFS_TRANSACTION, - permanent); - } - - if (error) - goto undo_blocks; - - tp->t_log_res = resp->tr_logres; - tp->t_log_count = resp->tr_logcount; - } - - /* - * Attempt to reserve the needed realtime extents by decrementing - * the number needed from the number available. This will - * fail if the count would go below zero. - */ - if (rtextents > 0) { - error = xfs_mod_frextents(tp->t_mountp, -((int64_t)rtextents)); - if (error) { - error = -ENOSPC; - goto undo_log; - } - tp->t_rtx_res += rtextents; - } - - return 0; - - /* - * Error cases jump to one of these labels to undo any - * reservations which have already been performed. - */ -undo_log: - if (resp->tr_logres > 0) { - xfs_log_done(tp->t_mountp, tp->t_ticket, NULL, false); - tp->t_ticket = NULL; - tp->t_log_res = 0; - tp->t_flags &= ~XFS_TRANS_PERM_LOG_RES; - } - -undo_blocks: - if (blocks > 0) { - xfs_mod_fdblocks(tp->t_mountp, (int64_t)blocks, rsvd); - tp->t_blk_res = 0; - } - - current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); - - return error; -} - -int -xfs_trans_alloc( - struct xfs_mount *mp, - struct xfs_trans_res *resp, - uint blocks, - uint rtextents, - uint flags, - struct xfs_trans **tpp) -{ - struct xfs_trans *tp; - int error; - - if (!(flags & XFS_TRANS_NO_WRITECOUNT)) - sb_start_intwrite(mp->m_super); - - WARN_ON(mp->m_super->s_writers.frozen == SB_FREEZE_COMPLETE); - atomic_inc(&mp->m_active_trans); - - tp = kmem_zone_zalloc(xfs_trans_zone, - (flags & XFS_TRANS_NOFS) ? KM_NOFS : KM_SLEEP); - tp->t_magic = XFS_TRANS_HEADER_MAGIC; - tp->t_flags = flags; - tp->t_mountp = mp; - INIT_LIST_HEAD(&tp->t_items); - INIT_LIST_HEAD(&tp->t_busy); - - error = xfs_trans_reserve(tp, resp, blocks, rtextents); - if (error) { - xfs_trans_cancel(tp); - return error; - } - - *tpp = tp; - return 0; -} - -/* - * Record the indicated change to the given field for application - * to the file system's superblock when the transaction commits. - * For now, just store the change in the transaction structure. - * - * Mark the transaction structure to indicate that the superblock - * needs to be updated before committing. - * - * Because we may not be keeping track of allocated/free inodes and - * used filesystem blocks in the superblock, we do not mark the - * superblock dirty in this transaction if we modify these fields. - * We still need to update the transaction deltas so that they get - * applied to the incore superblock, but we don't want them to - * cause the superblock to get locked and logged if these are the - * only fields in the superblock that the transaction modifies. - */ -void -xfs_trans_mod_sb( - xfs_trans_t *tp, - uint field, - int64_t delta) -{ - uint32_t flags = (XFS_TRANS_DIRTY|XFS_TRANS_SB_DIRTY); - xfs_mount_t *mp = tp->t_mountp; - - switch (field) { - case XFS_TRANS_SB_ICOUNT: - tp->t_icount_delta += delta; - if (xfs_sb_version_haslazysbcount(&mp->m_sb)) - flags &= ~XFS_TRANS_SB_DIRTY; - break; - case XFS_TRANS_SB_IFREE: - tp->t_ifree_delta += delta; - if (xfs_sb_version_haslazysbcount(&mp->m_sb)) - flags &= ~XFS_TRANS_SB_DIRTY; - break; - case XFS_TRANS_SB_FDBLOCKS: - /* - * Track the number of blocks allocated in the - * transaction. Make sure it does not exceed the - * number reserved. - */ - if (delta < 0) { - tp->t_blk_res_used += (uint)-delta; - ASSERT(tp->t_blk_res_used <= tp->t_blk_res); - } - tp->t_fdblocks_delta += delta; - if (xfs_sb_version_haslazysbcount(&mp->m_sb)) - flags &= ~XFS_TRANS_SB_DIRTY; - break; - case XFS_TRANS_SB_RES_FDBLOCKS: - /* - * The allocation has already been applied to the - * in-core superblock's counter. This should only - * be applied to the on-disk superblock. - */ - tp->t_res_fdblocks_delta += delta; - if (xfs_sb_version_haslazysbcount(&mp->m_sb)) - flags &= ~XFS_TRANS_SB_DIRTY; - break; - case XFS_TRANS_SB_FREXTENTS: - /* - * Track the number of blocks allocated in the - * transaction. Make sure it does not exceed the - * number reserved. - */ - if (delta < 0) { - tp->t_rtx_res_used += (uint)-delta; - ASSERT(tp->t_rtx_res_used <= tp->t_rtx_res); - } - tp->t_frextents_delta += delta; - break; - case XFS_TRANS_SB_RES_FREXTENTS: - /* - * The allocation has already been applied to the - * in-core superblock's counter. This should only - * be applied to the on-disk superblock. - */ - ASSERT(delta < 0); - tp->t_res_frextents_delta += delta; - break; - case XFS_TRANS_SB_DBLOCKS: - ASSERT(delta > 0); - tp->t_dblocks_delta += delta; - break; - case XFS_TRANS_SB_AGCOUNT: - ASSERT(delta > 0); - tp->t_agcount_delta += delta; - break; - case XFS_TRANS_SB_IMAXPCT: - tp->t_imaxpct_delta += delta; - break; - case XFS_TRANS_SB_REXTSIZE: - tp->t_rextsize_delta += delta; - break; - case XFS_TRANS_SB_RBMBLOCKS: - tp->t_rbmblocks_delta += delta; - break; - case XFS_TRANS_SB_RBLOCKS: - tp->t_rblocks_delta += delta; - break; - case XFS_TRANS_SB_REXTENTS: - tp->t_rextents_delta += delta; - break; - case XFS_TRANS_SB_REXTSLOG: - tp->t_rextslog_delta += delta; - break; - default: - ASSERT(0); - return; - } - - tp->t_flags |= flags; -} - -/* - * xfs_trans_apply_sb_deltas() is called from the commit code - * to bring the superblock buffer into the current transaction - * and modify it as requested by earlier calls to xfs_trans_mod_sb(). - * - * For now we just look at each field allowed to change and change - * it if necessary. - */ -STATIC void -xfs_trans_apply_sb_deltas( - xfs_trans_t *tp) -{ - xfs_dsb_t *sbp; - xfs_buf_t *bp; - int whole = 0; - - bp = xfs_trans_getsb(tp, tp->t_mountp, 0); - sbp = XFS_BUF_TO_SBP(bp); - - /* - * Check that superblock mods match the mods made to AGF counters. - */ - ASSERT((tp->t_fdblocks_delta + tp->t_res_fdblocks_delta) == - (tp->t_ag_freeblks_delta + tp->t_ag_flist_delta + - tp->t_ag_btree_delta)); - - /* - * Only update the superblock counters if we are logging them - */ - if (!xfs_sb_version_haslazysbcount(&(tp->t_mountp->m_sb))) { - if (tp->t_icount_delta) - be64_add_cpu(&sbp->sb_icount, tp->t_icount_delta); - if (tp->t_ifree_delta) - be64_add_cpu(&sbp->sb_ifree, tp->t_ifree_delta); - if (tp->t_fdblocks_delta) - be64_add_cpu(&sbp->sb_fdblocks, tp->t_fdblocks_delta); - if (tp->t_res_fdblocks_delta) - be64_add_cpu(&sbp->sb_fdblocks, tp->t_res_fdblocks_delta); - } - - if (tp->t_frextents_delta) - be64_add_cpu(&sbp->sb_frextents, tp->t_frextents_delta); - if (tp->t_res_frextents_delta) - be64_add_cpu(&sbp->sb_frextents, tp->t_res_frextents_delta); - - if (tp->t_dblocks_delta) { - be64_add_cpu(&sbp->sb_dblocks, tp->t_dblocks_delta); - whole = 1; - } - if (tp->t_agcount_delta) { - be32_add_cpu(&sbp->sb_agcount, tp->t_agcount_delta); - whole = 1; - } - if (tp->t_imaxpct_delta) { - sbp->sb_imax_pct += tp->t_imaxpct_delta; - whole = 1; - } - if (tp->t_rextsize_delta) { - be32_add_cpu(&sbp->sb_rextsize, tp->t_rextsize_delta); - whole = 1; - } - if (tp->t_rbmblocks_delta) { - be32_add_cpu(&sbp->sb_rbmblocks, tp->t_rbmblocks_delta); - whole = 1; - } - if (tp->t_rblocks_delta) { - be64_add_cpu(&sbp->sb_rblocks, tp->t_rblocks_delta); - whole = 1; - } - if (tp->t_rextents_delta) { - be64_add_cpu(&sbp->sb_rextents, tp->t_rextents_delta); - whole = 1; - } - if (tp->t_rextslog_delta) { - sbp->sb_rextslog += tp->t_rextslog_delta; - whole = 1; - } - - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_SB_BUF); - if (whole) - /* - * Log the whole thing, the fields are noncontiguous. - */ - xfs_trans_log_buf(tp, bp, 0, sizeof(xfs_dsb_t) - 1); - else - /* - * Since all the modifiable fields are contiguous, we - * can get away with this. - */ - xfs_trans_log_buf(tp, bp, offsetof(xfs_dsb_t, sb_icount), - offsetof(xfs_dsb_t, sb_frextents) + - sizeof(sbp->sb_frextents) - 1); -} - -STATIC int -xfs_sb_mod8( - uint8_t *field, - int8_t delta) -{ - int8_t counter = *field; - - counter += delta; - if (counter < 0) { - ASSERT(0); - return -EINVAL; - } - *field = counter; - return 0; -} - -STATIC int -xfs_sb_mod32( - uint32_t *field, - int32_t delta) -{ - int32_t counter = *field; - - counter += delta; - if (counter < 0) { - ASSERT(0); - return -EINVAL; - } - *field = counter; - return 0; -} - -STATIC int -xfs_sb_mod64( - uint64_t *field, - int64_t delta) -{ - int64_t counter = *field; - - counter += delta; - if (counter < 0) { - ASSERT(0); - return -EINVAL; - } - *field = counter; - return 0; -} - -/* - * xfs_trans_unreserve_and_mod_sb() is called to release unused reservations - * and apply superblock counter changes to the in-core superblock. The - * t_res_fdblocks_delta and t_res_frextents_delta fields are explicitly NOT - * applied to the in-core superblock. The idea is that that has already been - * done. - * - * If we are not logging superblock counters, then the inode allocated/free and - * used block counts are not updated in the on disk superblock. In this case, - * XFS_TRANS_SB_DIRTY will not be set when the transaction is updated but we - * still need to update the incore superblock with the changes. - */ -void -xfs_trans_unreserve_and_mod_sb( - struct xfs_trans *tp) -{ - struct xfs_mount *mp = tp->t_mountp; - bool rsvd = (tp->t_flags & XFS_TRANS_RESERVE) != 0; - int64_t blkdelta = 0; - int64_t rtxdelta = 0; - int64_t idelta = 0; - int64_t ifreedelta = 0; - int error; - - /* calculate deltas */ - if (tp->t_blk_res > 0) - blkdelta = tp->t_blk_res; - if ((tp->t_fdblocks_delta != 0) && - (xfs_sb_version_haslazysbcount(&mp->m_sb) || - (tp->t_flags & XFS_TRANS_SB_DIRTY))) - blkdelta += tp->t_fdblocks_delta; - - if (tp->t_rtx_res > 0) - rtxdelta = tp->t_rtx_res; - if ((tp->t_frextents_delta != 0) && - (tp->t_flags & XFS_TRANS_SB_DIRTY)) - rtxdelta += tp->t_frextents_delta; - - if (xfs_sb_version_haslazysbcount(&mp->m_sb) || - (tp->t_flags & XFS_TRANS_SB_DIRTY)) { - idelta = tp->t_icount_delta; - ifreedelta = tp->t_ifree_delta; - } - - /* apply the per-cpu counters */ - if (blkdelta) { - error = xfs_mod_fdblocks(mp, blkdelta, rsvd); - if (error) - goto out; - } - - if (idelta) { - error = xfs_mod_icount(mp, idelta); - if (error) - goto out_undo_fdblocks; - } - - if (ifreedelta) { - error = xfs_mod_ifree(mp, ifreedelta); - if (error) - goto out_undo_icount; - } - - if (rtxdelta == 0 && !(tp->t_flags & XFS_TRANS_SB_DIRTY)) - return; - - /* apply remaining deltas */ - spin_lock(&mp->m_sb_lock); - if (rtxdelta) { - error = xfs_sb_mod64(&mp->m_sb.sb_frextents, rtxdelta); - if (error) - goto out_undo_ifree; - } - - if (tp->t_dblocks_delta != 0) { - error = xfs_sb_mod64(&mp->m_sb.sb_dblocks, tp->t_dblocks_delta); - if (error) - goto out_undo_frextents; - } - if (tp->t_agcount_delta != 0) { - error = xfs_sb_mod32(&mp->m_sb.sb_agcount, tp->t_agcount_delta); - if (error) - goto out_undo_dblocks; - } - if (tp->t_imaxpct_delta != 0) { - error = xfs_sb_mod8(&mp->m_sb.sb_imax_pct, tp->t_imaxpct_delta); - if (error) - goto out_undo_agcount; - } - if (tp->t_rextsize_delta != 0) { - error = xfs_sb_mod32(&mp->m_sb.sb_rextsize, - tp->t_rextsize_delta); - if (error) - goto out_undo_imaxpct; - } - if (tp->t_rbmblocks_delta != 0) { - error = xfs_sb_mod32(&mp->m_sb.sb_rbmblocks, - tp->t_rbmblocks_delta); - if (error) - goto out_undo_rextsize; - } - if (tp->t_rblocks_delta != 0) { - error = xfs_sb_mod64(&mp->m_sb.sb_rblocks, tp->t_rblocks_delta); - if (error) - goto out_undo_rbmblocks; - } - if (tp->t_rextents_delta != 0) { - error = xfs_sb_mod64(&mp->m_sb.sb_rextents, - tp->t_rextents_delta); - if (error) - goto out_undo_rblocks; - } - if (tp->t_rextslog_delta != 0) { - error = xfs_sb_mod8(&mp->m_sb.sb_rextslog, - tp->t_rextslog_delta); - if (error) - goto out_undo_rextents; - } - spin_unlock(&mp->m_sb_lock); - return; - -out_undo_rextents: - if (tp->t_rextents_delta) - xfs_sb_mod64(&mp->m_sb.sb_rextents, -tp->t_rextents_delta); -out_undo_rblocks: - if (tp->t_rblocks_delta) - xfs_sb_mod64(&mp->m_sb.sb_rblocks, -tp->t_rblocks_delta); -out_undo_rbmblocks: - if (tp->t_rbmblocks_delta) - xfs_sb_mod32(&mp->m_sb.sb_rbmblocks, -tp->t_rbmblocks_delta); -out_undo_rextsize: - if (tp->t_rextsize_delta) - xfs_sb_mod32(&mp->m_sb.sb_rextsize, -tp->t_rextsize_delta); -out_undo_imaxpct: - if (tp->t_rextsize_delta) - xfs_sb_mod8(&mp->m_sb.sb_imax_pct, -tp->t_imaxpct_delta); -out_undo_agcount: - if (tp->t_agcount_delta) - xfs_sb_mod32(&mp->m_sb.sb_agcount, -tp->t_agcount_delta); -out_undo_dblocks: - if (tp->t_dblocks_delta) - xfs_sb_mod64(&mp->m_sb.sb_dblocks, -tp->t_dblocks_delta); -out_undo_frextents: - if (rtxdelta) - xfs_sb_mod64(&mp->m_sb.sb_frextents, -rtxdelta); -out_undo_ifree: - spin_unlock(&mp->m_sb_lock); - if (ifreedelta) - xfs_mod_ifree(mp, -ifreedelta); -out_undo_icount: - if (idelta) - xfs_mod_icount(mp, -idelta); -out_undo_fdblocks: - if (blkdelta) - xfs_mod_fdblocks(mp, -blkdelta, rsvd); -out: - ASSERT(error == 0); - return; -} - -/* - * Add the given log item to the transaction's list of log items. - * - * The log item will now point to its new descriptor with its li_desc field. - */ -void -xfs_trans_add_item( - struct xfs_trans *tp, - struct xfs_log_item *lip) -{ - struct xfs_log_item_desc *lidp; - - ASSERT(lip->li_mountp == tp->t_mountp); - ASSERT(lip->li_ailp == tp->t_mountp->m_ail); - - lidp = kmem_zone_zalloc(xfs_log_item_desc_zone, KM_SLEEP | KM_NOFS); - - lidp->lid_item = lip; - lidp->lid_flags = 0; - list_add_tail(&lidp->lid_trans, &tp->t_items); - - lip->li_desc = lidp; -} - -STATIC void -xfs_trans_free_item_desc( - struct xfs_log_item_desc *lidp) -{ - list_del_init(&lidp->lid_trans); - kmem_zone_free(xfs_log_item_desc_zone, lidp); -} - -/* - * Unlink and free the given descriptor. - */ -void -xfs_trans_del_item( - struct xfs_log_item *lip) -{ - xfs_trans_free_item_desc(lip->li_desc); - lip->li_desc = NULL; -} - -/* - * Unlock all of the items of a transaction and free all the descriptors - * of that transaction. - */ -void -xfs_trans_free_items( - struct xfs_trans *tp, - xfs_lsn_t commit_lsn, - bool abort) -{ - struct xfs_log_item_desc *lidp, *next; - - list_for_each_entry_safe(lidp, next, &tp->t_items, lid_trans) { - struct xfs_log_item *lip = lidp->lid_item; - - lip->li_desc = NULL; - - if (commit_lsn != NULLCOMMITLSN) - lip->li_ops->iop_committing(lip, commit_lsn); - if (abort) - lip->li_flags |= XFS_LI_ABORTED; - lip->li_ops->iop_unlock(lip); - - xfs_trans_free_item_desc(lidp); - } -} - -static inline void -xfs_log_item_batch_insert( - struct xfs_ail *ailp, - struct xfs_ail_cursor *cur, - struct xfs_log_item **log_items, - int nr_items, - xfs_lsn_t commit_lsn) -{ - int i; - - spin_lock(&ailp->xa_lock); - /* xfs_trans_ail_update_bulk drops ailp->xa_lock */ - xfs_trans_ail_update_bulk(ailp, cur, log_items, nr_items, commit_lsn); - - for (i = 0; i < nr_items; i++) { - struct xfs_log_item *lip = log_items[i]; - - lip->li_ops->iop_unpin(lip, 0); - } -} - -/* - * Bulk operation version of xfs_trans_committed that takes a log vector of - * items to insert into the AIL. This uses bulk AIL insertion techniques to - * minimise lock traffic. - * - * If we are called with the aborted flag set, it is because a log write during - * a CIL checkpoint commit has failed. In this case, all the items in the - * checkpoint have already gone through iop_commited and iop_unlock, which - * means that checkpoint commit abort handling is treated exactly the same - * as an iclog write error even though we haven't started any IO yet. Hence in - * this case all we need to do is iop_committed processing, followed by an - * iop_unpin(aborted) call. - * - * The AIL cursor is used to optimise the insert process. If commit_lsn is not - * at the end of the AIL, the insert cursor avoids the need to walk - * the AIL to find the insertion point on every xfs_log_item_batch_insert() - * call. This saves a lot of needless list walking and is a net win, even - * though it slightly increases that amount of AIL lock traffic to set it up - * and tear it down. - */ -void -xfs_trans_committed_bulk( - struct xfs_ail *ailp, - struct xfs_log_vec *log_vector, - xfs_lsn_t commit_lsn, - int aborted) -{ -#define LOG_ITEM_BATCH_SIZE 32 - struct xfs_log_item *log_items[LOG_ITEM_BATCH_SIZE]; - struct xfs_log_vec *lv; - struct xfs_ail_cursor cur; - int i = 0; - - spin_lock(&ailp->xa_lock); - xfs_trans_ail_cursor_last(ailp, &cur, commit_lsn); - spin_unlock(&ailp->xa_lock); - - /* unpin all the log items */ - for (lv = log_vector; lv; lv = lv->lv_next ) { - struct xfs_log_item *lip = lv->lv_item; - xfs_lsn_t item_lsn; - - if (aborted) - lip->li_flags |= XFS_LI_ABORTED; - item_lsn = lip->li_ops->iop_committed(lip, commit_lsn); - - /* item_lsn of -1 means the item needs no further processing */ - if (XFS_LSN_CMP(item_lsn, (xfs_lsn_t)-1) == 0) - continue; - - /* - * if we are aborting the operation, no point in inserting the - * object into the AIL as we are in a shutdown situation. - */ - if (aborted) { - ASSERT(XFS_FORCED_SHUTDOWN(ailp->xa_mount)); - lip->li_ops->iop_unpin(lip, 1); - continue; - } - - if (item_lsn != commit_lsn) { - - /* - * Not a bulk update option due to unusual item_lsn. - * Push into AIL immediately, rechecking the lsn once - * we have the ail lock. Then unpin the item. This does - * not affect the AIL cursor the bulk insert path is - * using. - */ - spin_lock(&ailp->xa_lock); - if (XFS_LSN_CMP(item_lsn, lip->li_lsn) > 0) - xfs_trans_ail_update(ailp, lip, item_lsn); - else - spin_unlock(&ailp->xa_lock); - lip->li_ops->iop_unpin(lip, 0); - continue; - } - - /* Item is a candidate for bulk AIL insert. */ - log_items[i++] = lv->lv_item; - if (i >= LOG_ITEM_BATCH_SIZE) { - xfs_log_item_batch_insert(ailp, &cur, log_items, - LOG_ITEM_BATCH_SIZE, commit_lsn); - i = 0; - } - } - - /* make sure we insert the remainder! */ - if (i) - xfs_log_item_batch_insert(ailp, &cur, log_items, i, commit_lsn); - - spin_lock(&ailp->xa_lock); - xfs_trans_ail_cursor_done(&cur); - spin_unlock(&ailp->xa_lock); -} - -/* - * Commit the given transaction to the log. - * - * XFS disk error handling mechanism is not based on a typical - * transaction abort mechanism. Logically after the filesystem - * gets marked 'SHUTDOWN', we can't let any new transactions - * be durable - ie. committed to disk - because some metadata might - * be inconsistent. In such cases, this returns an error, and the - * caller may assume that all locked objects joined to the transaction - * have already been unlocked as if the commit had succeeded. - * Do not reference the transaction structure after this call. - */ -static int -__xfs_trans_commit( - struct xfs_trans *tp, - bool regrant) -{ - struct xfs_mount *mp = tp->t_mountp; - xfs_lsn_t commit_lsn = -1; - int error = 0; - int sync = tp->t_flags & XFS_TRANS_SYNC; - - /* - * If there is nothing to be logged by the transaction, - * then unlock all of the items associated with the - * transaction and free the transaction structure. - * Also make sure to return any reserved blocks to - * the free pool. - */ - if (!(tp->t_flags & XFS_TRANS_DIRTY)) - goto out_unreserve; - - if (XFS_FORCED_SHUTDOWN(mp)) { - error = -EIO; - goto out_unreserve; - } - - ASSERT(tp->t_ticket != NULL); - - /* - * If we need to update the superblock, then do it now. - */ - if (tp->t_flags & XFS_TRANS_SB_DIRTY) - xfs_trans_apply_sb_deltas(tp); - xfs_trans_apply_dquot_deltas(tp); - - xfs_log_commit_cil(mp, tp, &commit_lsn, regrant); - - current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); - xfs_trans_free(tp); - - /* - * If the transaction needs to be synchronous, then force the - * log out now and wait for it. - */ - if (sync) { - error = _xfs_log_force_lsn(mp, commit_lsn, XFS_LOG_SYNC, NULL); - XFS_STATS_INC(mp, xs_trans_sync); - } else { - XFS_STATS_INC(mp, xs_trans_async); - } - - return error; - -out_unreserve: - xfs_trans_unreserve_and_mod_sb(tp); - - /* - * It is indeed possible for the transaction to be not dirty but - * the dqinfo portion to be. All that means is that we have some - * (non-persistent) quota reservations that need to be unreserved. - */ - xfs_trans_unreserve_and_mod_dquots(tp); - if (tp->t_ticket) { - commit_lsn = xfs_log_done(mp, tp->t_ticket, NULL, regrant); - if (commit_lsn == -1 && !error) - error = -EIO; - } - current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); - xfs_trans_free_items(tp, NULLCOMMITLSN, !!error); - xfs_trans_free(tp); - - XFS_STATS_INC(mp, xs_trans_empty); - return error; -} - -int -xfs_trans_commit( - struct xfs_trans *tp) -{ - return __xfs_trans_commit(tp, false); -} - -/* - * Unlock all of the transaction's items and free the transaction. - * The transaction must not have modified any of its items, because - * there is no way to restore them to their previous state. - * - * If the transaction has made a log reservation, make sure to release - * it as well. - */ -void -xfs_trans_cancel( - struct xfs_trans *tp) -{ - struct xfs_mount *mp = tp->t_mountp; - bool dirty = (tp->t_flags & XFS_TRANS_DIRTY); - - /* - * See if the caller is relying on us to shut down the - * filesystem. This happens in paths where we detect - * corruption and decide to give up. - */ - if (dirty && !XFS_FORCED_SHUTDOWN(mp)) { - XFS_ERROR_REPORT("xfs_trans_cancel", XFS_ERRLEVEL_LOW, mp); - xfs_force_shutdown(mp, SHUTDOWN_CORRUPT_INCORE); - } -#ifdef DEBUG - if (!dirty && !XFS_FORCED_SHUTDOWN(mp)) { - struct xfs_log_item_desc *lidp; - - list_for_each_entry(lidp, &tp->t_items, lid_trans) - ASSERT(!(lidp->lid_item->li_type == XFS_LI_EFD)); - } -#endif - xfs_trans_unreserve_and_mod_sb(tp); - xfs_trans_unreserve_and_mod_dquots(tp); - - if (tp->t_ticket) - xfs_log_done(mp, tp->t_ticket, NULL, false); - - /* mark this thread as no longer being in a transaction */ - current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); - - xfs_trans_free_items(tp, NULLCOMMITLSN, dirty); - xfs_trans_free(tp); -} - -/* - * Roll from one trans in the sequence of PERMANENT transactions to - * the next: permanent transactions are only flushed out when - * committed with xfs_trans_commit(), but we still want as soon - * as possible to let chunks of it go to the log. So we commit the - * chunk we've been working on and get a new transaction to continue. - */ -int -__xfs_trans_roll( - struct xfs_trans **tpp, - struct xfs_inode *dp, - int *committed) -{ - struct xfs_trans *trans; - struct xfs_trans_res tres; - int error; - - *committed = 0; - - /* - * Ensure that the inode is always logged. - */ - trans = *tpp; - if (dp) - xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE); - - /* - * Copy the critical parameters from one trans to the next. - */ - tres.tr_logres = trans->t_log_res; - tres.tr_logcount = trans->t_log_count; - *tpp = xfs_trans_dup(trans); - - /* - * Commit the current transaction. - * If this commit failed, then it'd just unlock those items that - * are not marked ihold. That also means that a filesystem shutdown - * is in progress. The caller takes the responsibility to cancel - * the duplicate transaction that gets returned. - */ - error = __xfs_trans_commit(trans, true); - if (error) - return error; - - *committed = 1; - trans = *tpp; - - /* - * Reserve space in the log for th next transaction. - * This also pushes items in the "AIL", the list of logged items, - * out to disk if they are taking up space at the tail of the log - * that we want to use. This requires that either nothing be locked - * across this call, or that anything that is locked be logged in - * the prior and the next transactions. - */ - tres.tr_logflags = XFS_TRANS_PERM_LOG_RES; - error = xfs_trans_reserve(trans, &tres, 0, 0); - /* - * Ensure that the inode is in the new transaction and locked. - */ - if (error) - return error; - - if (dp) - xfs_trans_ijoin(trans, dp, 0); - return 0; -} - -int -xfs_trans_roll( - struct xfs_trans **tpp, - struct xfs_inode *dp) -{ - int committed; - return __xfs_trans_roll(tpp, dp, &committed); -} diff --git a/src/linux/fs/xfs/xfs_trans.h b/src/linux/fs/xfs/xfs_trans.h deleted file mode 100644 index 61b7fbd..0000000 --- a/src/linux/fs/xfs/xfs_trans.h +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_TRANS_H__ -#define __XFS_TRANS_H__ - -/* kernel only transaction subsystem defines */ - -struct xfs_buf; -struct xfs_buftarg; -struct xfs_efd_log_item; -struct xfs_efi_log_item; -struct xfs_inode; -struct xfs_item_ops; -struct xfs_log_iovec; -struct xfs_log_item_desc; -struct xfs_mount; -struct xfs_trans; -struct xfs_trans_res; -struct xfs_dquot_acct; -struct xfs_busy_extent; -struct xfs_rud_log_item; -struct xfs_rui_log_item; -struct xfs_btree_cur; -struct xfs_cui_log_item; -struct xfs_cud_log_item; -struct xfs_defer_ops; -struct xfs_bui_log_item; -struct xfs_bud_log_item; - -typedef struct xfs_log_item { - struct list_head li_ail; /* AIL pointers */ - xfs_lsn_t li_lsn; /* last on-disk lsn */ - struct xfs_log_item_desc *li_desc; /* ptr to current desc*/ - struct xfs_mount *li_mountp; /* ptr to fs mount */ - struct xfs_ail *li_ailp; /* ptr to AIL */ - uint li_type; /* item type */ - uint li_flags; /* misc flags */ - struct xfs_log_item *li_bio_list; /* buffer item list */ - void (*li_cb)(struct xfs_buf *, - struct xfs_log_item *); - /* buffer item iodone */ - /* callback func */ - const struct xfs_item_ops *li_ops; /* function list */ - - /* delayed logging */ - struct list_head li_cil; /* CIL pointers */ - struct xfs_log_vec *li_lv; /* active log vector */ - struct xfs_log_vec *li_lv_shadow; /* standby vector */ - xfs_lsn_t li_seq; /* CIL commit seq */ -} xfs_log_item_t; - -#define XFS_LI_IN_AIL 0x1 -#define XFS_LI_ABORTED 0x2 - -#define XFS_LI_FLAGS \ - { XFS_LI_IN_AIL, "IN_AIL" }, \ - { XFS_LI_ABORTED, "ABORTED" } - -struct xfs_item_ops { - void (*iop_size)(xfs_log_item_t *, int *, int *); - void (*iop_format)(xfs_log_item_t *, struct xfs_log_vec *); - void (*iop_pin)(xfs_log_item_t *); - void (*iop_unpin)(xfs_log_item_t *, int remove); - uint (*iop_push)(struct xfs_log_item *, struct list_head *); - void (*iop_unlock)(xfs_log_item_t *); - xfs_lsn_t (*iop_committed)(xfs_log_item_t *, xfs_lsn_t); - void (*iop_committing)(xfs_log_item_t *, xfs_lsn_t); -}; - -void xfs_log_item_init(struct xfs_mount *mp, struct xfs_log_item *item, - int type, const struct xfs_item_ops *ops); - -/* - * Return values for the iop_push() routines. - */ -#define XFS_ITEM_SUCCESS 0 -#define XFS_ITEM_PINNED 1 -#define XFS_ITEM_LOCKED 2 -#define XFS_ITEM_FLUSHING 3 - - -/* - * This is the structure maintained for every active transaction. - */ -typedef struct xfs_trans { - unsigned int t_magic; /* magic number */ - unsigned int t_log_res; /* amt of log space resvd */ - unsigned int t_log_count; /* count for perm log res */ - unsigned int t_blk_res; /* # of blocks resvd */ - unsigned int t_blk_res_used; /* # of resvd blocks used */ - unsigned int t_rtx_res; /* # of rt extents resvd */ - unsigned int t_rtx_res_used; /* # of resvd rt extents used */ - struct xlog_ticket *t_ticket; /* log mgr ticket */ - xfs_lsn_t t_lsn; /* log seq num of start of - * transaction. */ - xfs_lsn_t t_commit_lsn; /* log seq num of end of - * transaction. */ - struct xfs_mount *t_mountp; /* ptr to fs mount struct */ - struct xfs_dquot_acct *t_dqinfo; /* acctg info for dquots */ - unsigned int t_flags; /* misc flags */ - int64_t t_icount_delta; /* superblock icount change */ - int64_t t_ifree_delta; /* superblock ifree change */ - int64_t t_fdblocks_delta; /* superblock fdblocks chg */ - int64_t t_res_fdblocks_delta; /* on-disk only chg */ - int64_t t_frextents_delta;/* superblock freextents chg*/ - int64_t t_res_frextents_delta; /* on-disk only chg */ -#if defined(DEBUG) || defined(XFS_WARN) - int64_t t_ag_freeblks_delta; /* debugging counter */ - int64_t t_ag_flist_delta; /* debugging counter */ - int64_t t_ag_btree_delta; /* debugging counter */ -#endif - int64_t t_dblocks_delta;/* superblock dblocks change */ - int64_t t_agcount_delta;/* superblock agcount change */ - int64_t t_imaxpct_delta;/* superblock imaxpct change */ - int64_t t_rextsize_delta;/* superblock rextsize chg */ - int64_t t_rbmblocks_delta;/* superblock rbmblocks chg */ - int64_t t_rblocks_delta;/* superblock rblocks change */ - int64_t t_rextents_delta;/* superblocks rextents chg */ - int64_t t_rextslog_delta;/* superblocks rextslog chg */ - struct list_head t_items; /* log item descriptors */ - struct list_head t_busy; /* list of busy extents */ - unsigned long t_pflags; /* saved process flags state */ -} xfs_trans_t; - -/* - * XFS transaction mechanism exported interfaces that are - * actually macros. - */ -#define xfs_trans_set_sync(tp) ((tp)->t_flags |= XFS_TRANS_SYNC) - -#if defined(DEBUG) || defined(XFS_WARN) -#define xfs_trans_agblocks_delta(tp, d) ((tp)->t_ag_freeblks_delta += (int64_t)d) -#define xfs_trans_agflist_delta(tp, d) ((tp)->t_ag_flist_delta += (int64_t)d) -#define xfs_trans_agbtree_delta(tp, d) ((tp)->t_ag_btree_delta += (int64_t)d) -#else -#define xfs_trans_agblocks_delta(tp, d) -#define xfs_trans_agflist_delta(tp, d) -#define xfs_trans_agbtree_delta(tp, d) -#endif - -/* - * XFS transaction mechanism exported interfaces. - */ -int xfs_trans_alloc(struct xfs_mount *mp, struct xfs_trans_res *resp, - uint blocks, uint rtextents, uint flags, - struct xfs_trans **tpp); -void xfs_trans_mod_sb(xfs_trans_t *, uint, int64_t); - -struct xfs_buf *xfs_trans_get_buf_map(struct xfs_trans *tp, - struct xfs_buftarg *target, - struct xfs_buf_map *map, int nmaps, - uint flags); - -static inline struct xfs_buf * -xfs_trans_get_buf( - struct xfs_trans *tp, - struct xfs_buftarg *target, - xfs_daddr_t blkno, - int numblks, - uint flags) -{ - DEFINE_SINGLE_BUF_MAP(map, blkno, numblks); - return xfs_trans_get_buf_map(tp, target, &map, 1, flags); -} - -int xfs_trans_read_buf_map(struct xfs_mount *mp, - struct xfs_trans *tp, - struct xfs_buftarg *target, - struct xfs_buf_map *map, int nmaps, - xfs_buf_flags_t flags, - struct xfs_buf **bpp, - const struct xfs_buf_ops *ops); - -static inline int -xfs_trans_read_buf( - struct xfs_mount *mp, - struct xfs_trans *tp, - struct xfs_buftarg *target, - xfs_daddr_t blkno, - int numblks, - xfs_buf_flags_t flags, - struct xfs_buf **bpp, - const struct xfs_buf_ops *ops) -{ - DEFINE_SINGLE_BUF_MAP(map, blkno, numblks); - return xfs_trans_read_buf_map(mp, tp, target, &map, 1, - flags, bpp, ops); -} - -struct xfs_buf *xfs_trans_getsb(xfs_trans_t *, struct xfs_mount *, int); - -void xfs_trans_brelse(xfs_trans_t *, struct xfs_buf *); -void xfs_trans_bjoin(xfs_trans_t *, struct xfs_buf *); -void xfs_trans_bhold(xfs_trans_t *, struct xfs_buf *); -void xfs_trans_bhold_release(xfs_trans_t *, struct xfs_buf *); -void xfs_trans_binval(xfs_trans_t *, struct xfs_buf *); -void xfs_trans_inode_buf(xfs_trans_t *, struct xfs_buf *); -void xfs_trans_stale_inode_buf(xfs_trans_t *, struct xfs_buf *); -void xfs_trans_ordered_buf(xfs_trans_t *, struct xfs_buf *); -void xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint); -void xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *); -void xfs_trans_ichgtime(struct xfs_trans *, struct xfs_inode *, int); -void xfs_trans_ijoin(struct xfs_trans *, struct xfs_inode *, uint); -void xfs_trans_log_buf(xfs_trans_t *, struct xfs_buf *, uint, uint); -void xfs_trans_log_inode(xfs_trans_t *, struct xfs_inode *, uint); - -void xfs_extent_free_init_defer_op(void); -struct xfs_efd_log_item *xfs_trans_get_efd(struct xfs_trans *, - struct xfs_efi_log_item *, - uint); -int xfs_trans_free_extent(struct xfs_trans *, - struct xfs_efd_log_item *, xfs_fsblock_t, - xfs_extlen_t, struct xfs_owner_info *); -int xfs_trans_commit(struct xfs_trans *); -int __xfs_trans_roll(struct xfs_trans **, struct xfs_inode *, int *); -int xfs_trans_roll(struct xfs_trans **, struct xfs_inode *); -void xfs_trans_cancel(xfs_trans_t *); -int xfs_trans_ail_init(struct xfs_mount *); -void xfs_trans_ail_destroy(struct xfs_mount *); - -void xfs_trans_buf_set_type(struct xfs_trans *, struct xfs_buf *, - enum xfs_blft); -void xfs_trans_buf_copy_type(struct xfs_buf *dst_bp, - struct xfs_buf *src_bp); - -extern kmem_zone_t *xfs_trans_zone; -extern kmem_zone_t *xfs_log_item_desc_zone; - -/* rmap updates */ -enum xfs_rmap_intent_type; - -void xfs_rmap_update_init_defer_op(void); -struct xfs_rud_log_item *xfs_trans_get_rud(struct xfs_trans *tp, - struct xfs_rui_log_item *ruip); -int xfs_trans_log_finish_rmap_update(struct xfs_trans *tp, - struct xfs_rud_log_item *rudp, enum xfs_rmap_intent_type type, - __uint64_t owner, int whichfork, xfs_fileoff_t startoff, - xfs_fsblock_t startblock, xfs_filblks_t blockcount, - xfs_exntst_t state, struct xfs_btree_cur **pcur); - -/* refcount updates */ -enum xfs_refcount_intent_type; - -void xfs_refcount_update_init_defer_op(void); -struct xfs_cud_log_item *xfs_trans_get_cud(struct xfs_trans *tp, - struct xfs_cui_log_item *cuip); -int xfs_trans_log_finish_refcount_update(struct xfs_trans *tp, - struct xfs_cud_log_item *cudp, struct xfs_defer_ops *dfops, - enum xfs_refcount_intent_type type, xfs_fsblock_t startblock, - xfs_extlen_t blockcount, xfs_fsblock_t *new_fsb, - xfs_extlen_t *new_len, struct xfs_btree_cur **pcur); - -/* mapping updates */ -enum xfs_bmap_intent_type; - -void xfs_bmap_update_init_defer_op(void); -struct xfs_bud_log_item *xfs_trans_get_bud(struct xfs_trans *tp, - struct xfs_bui_log_item *buip); -int xfs_trans_log_finish_bmap_update(struct xfs_trans *tp, - struct xfs_bud_log_item *rudp, struct xfs_defer_ops *dfops, - enum xfs_bmap_intent_type type, struct xfs_inode *ip, - int whichfork, xfs_fileoff_t startoff, xfs_fsblock_t startblock, - xfs_filblks_t blockcount, xfs_exntst_t state); - -#endif /* __XFS_TRANS_H__ */ diff --git a/src/linux/fs/xfs/xfs_trans_ail.c b/src/linux/fs/xfs/xfs_trans_ail.c deleted file mode 100644 index d6c9c3e..0000000 --- a/src/linux/fs/xfs/xfs_trans_ail.c +++ /dev/null @@ -1,795 +0,0 @@ -/* - * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. - * Copyright (c) 2008 Dave Chinner - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_trans.h" -#include "xfs_trans_priv.h" -#include "xfs_trace.h" -#include "xfs_error.h" -#include "xfs_log.h" - -#ifdef DEBUG -/* - * Check that the list is sorted as it should be. - */ -STATIC void -xfs_ail_check( - struct xfs_ail *ailp, - xfs_log_item_t *lip) -{ - xfs_log_item_t *prev_lip; - - if (list_empty(&ailp->xa_ail)) - return; - - /* - * Check the next and previous entries are valid. - */ - ASSERT((lip->li_flags & XFS_LI_IN_AIL) != 0); - prev_lip = list_entry(lip->li_ail.prev, xfs_log_item_t, li_ail); - if (&prev_lip->li_ail != &ailp->xa_ail) - ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) <= 0); - - prev_lip = list_entry(lip->li_ail.next, xfs_log_item_t, li_ail); - if (&prev_lip->li_ail != &ailp->xa_ail) - ASSERT(XFS_LSN_CMP(prev_lip->li_lsn, lip->li_lsn) >= 0); - - -} -#else /* !DEBUG */ -#define xfs_ail_check(a,l) -#endif /* DEBUG */ - -/* - * Return a pointer to the last item in the AIL. If the AIL is empty, then - * return NULL. - */ -static xfs_log_item_t * -xfs_ail_max( - struct xfs_ail *ailp) -{ - if (list_empty(&ailp->xa_ail)) - return NULL; - - return list_entry(ailp->xa_ail.prev, xfs_log_item_t, li_ail); -} - -/* - * Return a pointer to the item which follows the given item in the AIL. If - * the given item is the last item in the list, then return NULL. - */ -static xfs_log_item_t * -xfs_ail_next( - struct xfs_ail *ailp, - xfs_log_item_t *lip) -{ - if (lip->li_ail.next == &ailp->xa_ail) - return NULL; - - return list_first_entry(&lip->li_ail, xfs_log_item_t, li_ail); -} - -/* - * This is called by the log manager code to determine the LSN of the tail of - * the log. This is exactly the LSN of the first item in the AIL. If the AIL - * is empty, then this function returns 0. - * - * We need the AIL lock in order to get a coherent read of the lsn of the last - * item in the AIL. - */ -xfs_lsn_t -xfs_ail_min_lsn( - struct xfs_ail *ailp) -{ - xfs_lsn_t lsn = 0; - xfs_log_item_t *lip; - - spin_lock(&ailp->xa_lock); - lip = xfs_ail_min(ailp); - if (lip) - lsn = lip->li_lsn; - spin_unlock(&ailp->xa_lock); - - return lsn; -} - -/* - * Return the maximum lsn held in the AIL, or zero if the AIL is empty. - */ -static xfs_lsn_t -xfs_ail_max_lsn( - struct xfs_ail *ailp) -{ - xfs_lsn_t lsn = 0; - xfs_log_item_t *lip; - - spin_lock(&ailp->xa_lock); - lip = xfs_ail_max(ailp); - if (lip) - lsn = lip->li_lsn; - spin_unlock(&ailp->xa_lock); - - return lsn; -} - -/* - * The cursor keeps track of where our current traversal is up to by tracking - * the next item in the list for us. However, for this to be safe, removing an - * object from the AIL needs to invalidate any cursor that points to it. hence - * the traversal cursor needs to be linked to the struct xfs_ail so that - * deletion can search all the active cursors for invalidation. - */ -STATIC void -xfs_trans_ail_cursor_init( - struct xfs_ail *ailp, - struct xfs_ail_cursor *cur) -{ - cur->item = NULL; - list_add_tail(&cur->list, &ailp->xa_cursors); -} - -/* - * Get the next item in the traversal and advance the cursor. If the cursor - * was invalidated (indicated by a lip of 1), restart the traversal. - */ -struct xfs_log_item * -xfs_trans_ail_cursor_next( - struct xfs_ail *ailp, - struct xfs_ail_cursor *cur) -{ - struct xfs_log_item *lip = cur->item; - - if ((uintptr_t)lip & 1) - lip = xfs_ail_min(ailp); - if (lip) - cur->item = xfs_ail_next(ailp, lip); - return lip; -} - -/* - * When the traversal is complete, we need to remove the cursor from the list - * of traversing cursors. - */ -void -xfs_trans_ail_cursor_done( - struct xfs_ail_cursor *cur) -{ - cur->item = NULL; - list_del_init(&cur->list); -} - -/* - * Invalidate any cursor that is pointing to this item. This is called when an - * item is removed from the AIL. Any cursor pointing to this object is now - * invalid and the traversal needs to be terminated so it doesn't reference a - * freed object. We set the low bit of the cursor item pointer so we can - * distinguish between an invalidation and the end of the list when getting the - * next item from the cursor. - */ -STATIC void -xfs_trans_ail_cursor_clear( - struct xfs_ail *ailp, - struct xfs_log_item *lip) -{ - struct xfs_ail_cursor *cur; - - list_for_each_entry(cur, &ailp->xa_cursors, list) { - if (cur->item == lip) - cur->item = (struct xfs_log_item *) - ((uintptr_t)cur->item | 1); - } -} - -/* - * Find the first item in the AIL with the given @lsn by searching in ascending - * LSN order and initialise the cursor to point to the next item for a - * ascending traversal. Pass a @lsn of zero to initialise the cursor to the - * first item in the AIL. Returns NULL if the list is empty. - */ -xfs_log_item_t * -xfs_trans_ail_cursor_first( - struct xfs_ail *ailp, - struct xfs_ail_cursor *cur, - xfs_lsn_t lsn) -{ - xfs_log_item_t *lip; - - xfs_trans_ail_cursor_init(ailp, cur); - - if (lsn == 0) { - lip = xfs_ail_min(ailp); - goto out; - } - - list_for_each_entry(lip, &ailp->xa_ail, li_ail) { - if (XFS_LSN_CMP(lip->li_lsn, lsn) >= 0) - goto out; - } - return NULL; - -out: - if (lip) - cur->item = xfs_ail_next(ailp, lip); - return lip; -} - -static struct xfs_log_item * -__xfs_trans_ail_cursor_last( - struct xfs_ail *ailp, - xfs_lsn_t lsn) -{ - xfs_log_item_t *lip; - - list_for_each_entry_reverse(lip, &ailp->xa_ail, li_ail) { - if (XFS_LSN_CMP(lip->li_lsn, lsn) <= 0) - return lip; - } - return NULL; -} - -/* - * Find the last item in the AIL with the given @lsn by searching in descending - * LSN order and initialise the cursor to point to that item. If there is no - * item with the value of @lsn, then it sets the cursor to the last item with an - * LSN lower than @lsn. Returns NULL if the list is empty. - */ -struct xfs_log_item * -xfs_trans_ail_cursor_last( - struct xfs_ail *ailp, - struct xfs_ail_cursor *cur, - xfs_lsn_t lsn) -{ - xfs_trans_ail_cursor_init(ailp, cur); - cur->item = __xfs_trans_ail_cursor_last(ailp, lsn); - return cur->item; -} - -/* - * Splice the log item list into the AIL at the given LSN. We splice to the - * tail of the given LSN to maintain insert order for push traversals. The - * cursor is optional, allowing repeated updates to the same LSN to avoid - * repeated traversals. This should not be called with an empty list. - */ -static void -xfs_ail_splice( - struct xfs_ail *ailp, - struct xfs_ail_cursor *cur, - struct list_head *list, - xfs_lsn_t lsn) -{ - struct xfs_log_item *lip; - - ASSERT(!list_empty(list)); - - /* - * Use the cursor to determine the insertion point if one is - * provided. If not, or if the one we got is not valid, - * find the place in the AIL where the items belong. - */ - lip = cur ? cur->item : NULL; - if (!lip || (uintptr_t)lip & 1) - lip = __xfs_trans_ail_cursor_last(ailp, lsn); - - /* - * If a cursor is provided, we know we're processing the AIL - * in lsn order, and future items to be spliced in will - * follow the last one being inserted now. Update the - * cursor to point to that last item, now while we have a - * reliable pointer to it. - */ - if (cur) - cur->item = list_entry(list->prev, struct xfs_log_item, li_ail); - - /* - * Finally perform the splice. Unless the AIL was empty, - * lip points to the item in the AIL _after_ which the new - * items should go. If lip is null the AIL was empty, so - * the new items go at the head of the AIL. - */ - if (lip) - list_splice(list, &lip->li_ail); - else - list_splice(list, &ailp->xa_ail); -} - -/* - * Delete the given item from the AIL. Return a pointer to the item. - */ -static void -xfs_ail_delete( - struct xfs_ail *ailp, - xfs_log_item_t *lip) -{ - xfs_ail_check(ailp, lip); - list_del(&lip->li_ail); - xfs_trans_ail_cursor_clear(ailp, lip); -} - -static long -xfsaild_push( - struct xfs_ail *ailp) -{ - xfs_mount_t *mp = ailp->xa_mount; - struct xfs_ail_cursor cur; - xfs_log_item_t *lip; - xfs_lsn_t lsn; - xfs_lsn_t target; - long tout; - int stuck = 0; - int flushing = 0; - int count = 0; - - /* - * If we encountered pinned items or did not finish writing out all - * buffers the last time we ran, force the log first and wait for it - * before pushing again. - */ - if (ailp->xa_log_flush && ailp->xa_last_pushed_lsn == 0 && - (!list_empty_careful(&ailp->xa_buf_list) || - xfs_ail_min_lsn(ailp))) { - ailp->xa_log_flush = 0; - - XFS_STATS_INC(mp, xs_push_ail_flush); - xfs_log_force(mp, XFS_LOG_SYNC); - } - - spin_lock(&ailp->xa_lock); - - /* barrier matches the xa_target update in xfs_ail_push() */ - smp_rmb(); - target = ailp->xa_target; - ailp->xa_target_prev = target; - - lip = xfs_trans_ail_cursor_first(ailp, &cur, ailp->xa_last_pushed_lsn); - if (!lip) { - /* - * If the AIL is empty or our push has reached the end we are - * done now. - */ - xfs_trans_ail_cursor_done(&cur); - spin_unlock(&ailp->xa_lock); - goto out_done; - } - - XFS_STATS_INC(mp, xs_push_ail); - - lsn = lip->li_lsn; - while ((XFS_LSN_CMP(lip->li_lsn, target) <= 0)) { - int lock_result; - - /* - * Note that iop_push may unlock and reacquire the AIL lock. We - * rely on the AIL cursor implementation to be able to deal with - * the dropped lock. - */ - lock_result = lip->li_ops->iop_push(lip, &ailp->xa_buf_list); - switch (lock_result) { - case XFS_ITEM_SUCCESS: - XFS_STATS_INC(mp, xs_push_ail_success); - trace_xfs_ail_push(lip); - - ailp->xa_last_pushed_lsn = lsn; - break; - - case XFS_ITEM_FLUSHING: - /* - * The item or its backing buffer is already beeing - * flushed. The typical reason for that is that an - * inode buffer is locked because we already pushed the - * updates to it as part of inode clustering. - * - * We do not want to to stop flushing just because lots - * of items are already beeing flushed, but we need to - * re-try the flushing relatively soon if most of the - * AIL is beeing flushed. - */ - XFS_STATS_INC(mp, xs_push_ail_flushing); - trace_xfs_ail_flushing(lip); - - flushing++; - ailp->xa_last_pushed_lsn = lsn; - break; - - case XFS_ITEM_PINNED: - XFS_STATS_INC(mp, xs_push_ail_pinned); - trace_xfs_ail_pinned(lip); - - stuck++; - ailp->xa_log_flush++; - break; - case XFS_ITEM_LOCKED: - XFS_STATS_INC(mp, xs_push_ail_locked); - trace_xfs_ail_locked(lip); - - stuck++; - break; - default: - ASSERT(0); - break; - } - - count++; - - /* - * Are there too many items we can't do anything with? - * - * If we we are skipping too many items because we can't flush - * them or they are already being flushed, we back off and - * given them time to complete whatever operation is being - * done. i.e. remove pressure from the AIL while we can't make - * progress so traversals don't slow down further inserts and - * removals to/from the AIL. - * - * The value of 100 is an arbitrary magic number based on - * observation. - */ - if (stuck > 100) - break; - - lip = xfs_trans_ail_cursor_next(ailp, &cur); - if (lip == NULL) - break; - lsn = lip->li_lsn; - } - xfs_trans_ail_cursor_done(&cur); - spin_unlock(&ailp->xa_lock); - - if (xfs_buf_delwri_submit_nowait(&ailp->xa_buf_list)) - ailp->xa_log_flush++; - - if (!count || XFS_LSN_CMP(lsn, target) >= 0) { -out_done: - /* - * We reached the target or the AIL is empty, so wait a bit - * longer for I/O to complete and remove pushed items from the - * AIL before we start the next scan from the start of the AIL. - */ - tout = 50; - ailp->xa_last_pushed_lsn = 0; - } else if (((stuck + flushing) * 100) / count > 90) { - /* - * Either there is a lot of contention on the AIL or we are - * stuck due to operations in progress. "Stuck" in this case - * is defined as >90% of the items we tried to push were stuck. - * - * Backoff a bit more to allow some I/O to complete before - * restarting from the start of the AIL. This prevents us from - * spinning on the same items, and if they are pinned will all - * the restart to issue a log force to unpin the stuck items. - */ - tout = 20; - ailp->xa_last_pushed_lsn = 0; - } else { - /* - * Assume we have more work to do in a short while. - */ - tout = 10; - } - - return tout; -} - -static int -xfsaild( - void *data) -{ - struct xfs_ail *ailp = data; - long tout = 0; /* milliseconds */ - - current->flags |= PF_MEMALLOC; - set_freezable(); - - while (!kthread_should_stop()) { - if (tout && tout <= 20) - __set_current_state(TASK_KILLABLE); - else - __set_current_state(TASK_INTERRUPTIBLE); - - spin_lock(&ailp->xa_lock); - - /* - * Idle if the AIL is empty and we are not racing with a target - * update. We check the AIL after we set the task to a sleep - * state to guarantee that we either catch an xa_target update - * or that a wake_up resets the state to TASK_RUNNING. - * Otherwise, we run the risk of sleeping indefinitely. - * - * The barrier matches the xa_target update in xfs_ail_push(). - */ - smp_rmb(); - if (!xfs_ail_min(ailp) && - ailp->xa_target == ailp->xa_target_prev) { - spin_unlock(&ailp->xa_lock); - freezable_schedule(); - tout = 0; - continue; - } - spin_unlock(&ailp->xa_lock); - - if (tout) - freezable_schedule_timeout(msecs_to_jiffies(tout)); - - __set_current_state(TASK_RUNNING); - - try_to_freeze(); - - tout = xfsaild_push(ailp); - } - - return 0; -} - -/* - * This routine is called to move the tail of the AIL forward. It does this by - * trying to flush items in the AIL whose lsns are below the given - * threshold_lsn. - * - * The push is run asynchronously in a workqueue, which means the caller needs - * to handle waiting on the async flush for space to become available. - * We don't want to interrupt any push that is in progress, hence we only queue - * work if we set the pushing bit approriately. - * - * We do this unlocked - we only need to know whether there is anything in the - * AIL at the time we are called. We don't need to access the contents of - * any of the objects, so the lock is not needed. - */ -void -xfs_ail_push( - struct xfs_ail *ailp, - xfs_lsn_t threshold_lsn) -{ - xfs_log_item_t *lip; - - lip = xfs_ail_min(ailp); - if (!lip || XFS_FORCED_SHUTDOWN(ailp->xa_mount) || - XFS_LSN_CMP(threshold_lsn, ailp->xa_target) <= 0) - return; - - /* - * Ensure that the new target is noticed in push code before it clears - * the XFS_AIL_PUSHING_BIT. - */ - smp_wmb(); - xfs_trans_ail_copy_lsn(ailp, &ailp->xa_target, &threshold_lsn); - smp_wmb(); - - wake_up_process(ailp->xa_task); -} - -/* - * Push out all items in the AIL immediately - */ -void -xfs_ail_push_all( - struct xfs_ail *ailp) -{ - xfs_lsn_t threshold_lsn = xfs_ail_max_lsn(ailp); - - if (threshold_lsn) - xfs_ail_push(ailp, threshold_lsn); -} - -/* - * Push out all items in the AIL immediately and wait until the AIL is empty. - */ -void -xfs_ail_push_all_sync( - struct xfs_ail *ailp) -{ - struct xfs_log_item *lip; - DEFINE_WAIT(wait); - - spin_lock(&ailp->xa_lock); - while ((lip = xfs_ail_max(ailp)) != NULL) { - prepare_to_wait(&ailp->xa_empty, &wait, TASK_UNINTERRUPTIBLE); - ailp->xa_target = lip->li_lsn; - wake_up_process(ailp->xa_task); - spin_unlock(&ailp->xa_lock); - schedule(); - spin_lock(&ailp->xa_lock); - } - spin_unlock(&ailp->xa_lock); - - finish_wait(&ailp->xa_empty, &wait); -} - -/* - * xfs_trans_ail_update - bulk AIL insertion operation. - * - * @xfs_trans_ail_update takes an array of log items that all need to be - * positioned at the same LSN in the AIL. If an item is not in the AIL, it will - * be added. Otherwise, it will be repositioned by removing it and re-adding - * it to the AIL. If we move the first item in the AIL, update the log tail to - * match the new minimum LSN in the AIL. - * - * This function takes the AIL lock once to execute the update operations on - * all the items in the array, and as such should not be called with the AIL - * lock held. As a result, once we have the AIL lock, we need to check each log - * item LSN to confirm it needs to be moved forward in the AIL. - * - * To optimise the insert operation, we delete all the items from the AIL in - * the first pass, moving them into a temporary list, then splice the temporary - * list into the correct position in the AIL. This avoids needing to do an - * insert operation on every item. - * - * This function must be called with the AIL lock held. The lock is dropped - * before returning. - */ -void -xfs_trans_ail_update_bulk( - struct xfs_ail *ailp, - struct xfs_ail_cursor *cur, - struct xfs_log_item **log_items, - int nr_items, - xfs_lsn_t lsn) __releases(ailp->xa_lock) -{ - xfs_log_item_t *mlip; - int mlip_changed = 0; - int i; - LIST_HEAD(tmp); - - ASSERT(nr_items > 0); /* Not required, but true. */ - mlip = xfs_ail_min(ailp); - - for (i = 0; i < nr_items; i++) { - struct xfs_log_item *lip = log_items[i]; - if (lip->li_flags & XFS_LI_IN_AIL) { - /* check if we really need to move the item */ - if (XFS_LSN_CMP(lsn, lip->li_lsn) <= 0) - continue; - - trace_xfs_ail_move(lip, lip->li_lsn, lsn); - xfs_ail_delete(ailp, lip); - if (mlip == lip) - mlip_changed = 1; - } else { - lip->li_flags |= XFS_LI_IN_AIL; - trace_xfs_ail_insert(lip, 0, lsn); - } - lip->li_lsn = lsn; - list_add(&lip->li_ail, &tmp); - } - - if (!list_empty(&tmp)) - xfs_ail_splice(ailp, cur, &tmp, lsn); - - if (mlip_changed) { - if (!XFS_FORCED_SHUTDOWN(ailp->xa_mount)) - xlog_assign_tail_lsn_locked(ailp->xa_mount); - spin_unlock(&ailp->xa_lock); - - xfs_log_space_wake(ailp->xa_mount); - } else { - spin_unlock(&ailp->xa_lock); - } -} - -/* - * xfs_trans_ail_delete_bulk - remove multiple log items from the AIL - * - * @xfs_trans_ail_delete_bulk takes an array of log items that all need to - * removed from the AIL. The caller is already holding the AIL lock, and done - * all the checks necessary to ensure the items passed in via @log_items are - * ready for deletion. This includes checking that the items are in the AIL. - * - * For each log item to be removed, unlink it from the AIL, clear the IN_AIL - * flag from the item and reset the item's lsn to 0. If we remove the first - * item in the AIL, update the log tail to match the new minimum LSN in the - * AIL. - * - * This function will not drop the AIL lock until all items are removed from - * the AIL to minimise the amount of lock traffic on the AIL. This does not - * greatly increase the AIL hold time, but does significantly reduce the amount - * of traffic on the lock, especially during IO completion. - * - * This function must be called with the AIL lock held. The lock is dropped - * before returning. - */ -void -xfs_trans_ail_delete_bulk( - struct xfs_ail *ailp, - struct xfs_log_item **log_items, - int nr_items, - int shutdown_type) __releases(ailp->xa_lock) -{ - xfs_log_item_t *mlip; - int mlip_changed = 0; - int i; - - mlip = xfs_ail_min(ailp); - - for (i = 0; i < nr_items; i++) { - struct xfs_log_item *lip = log_items[i]; - if (!(lip->li_flags & XFS_LI_IN_AIL)) { - struct xfs_mount *mp = ailp->xa_mount; - - spin_unlock(&ailp->xa_lock); - if (!XFS_FORCED_SHUTDOWN(mp)) { - xfs_alert_tag(mp, XFS_PTAG_AILDELETE, - "%s: attempting to delete a log item that is not in the AIL", - __func__); - xfs_force_shutdown(mp, shutdown_type); - } - return; - } - - trace_xfs_ail_delete(lip, mlip->li_lsn, lip->li_lsn); - xfs_ail_delete(ailp, lip); - lip->li_flags &= ~XFS_LI_IN_AIL; - lip->li_lsn = 0; - if (mlip == lip) - mlip_changed = 1; - } - - if (mlip_changed) { - if (!XFS_FORCED_SHUTDOWN(ailp->xa_mount)) - xlog_assign_tail_lsn_locked(ailp->xa_mount); - if (list_empty(&ailp->xa_ail)) - wake_up_all(&ailp->xa_empty); - spin_unlock(&ailp->xa_lock); - - xfs_log_space_wake(ailp->xa_mount); - } else { - spin_unlock(&ailp->xa_lock); - } -} - -int -xfs_trans_ail_init( - xfs_mount_t *mp) -{ - struct xfs_ail *ailp; - - ailp = kmem_zalloc(sizeof(struct xfs_ail), KM_MAYFAIL); - if (!ailp) - return -ENOMEM; - - ailp->xa_mount = mp; - INIT_LIST_HEAD(&ailp->xa_ail); - INIT_LIST_HEAD(&ailp->xa_cursors); - spin_lock_init(&ailp->xa_lock); - INIT_LIST_HEAD(&ailp->xa_buf_list); - init_waitqueue_head(&ailp->xa_empty); - - ailp->xa_task = kthread_run(xfsaild, ailp, "xfsaild/%s", - ailp->xa_mount->m_fsname); - if (IS_ERR(ailp->xa_task)) - goto out_free_ailp; - - mp->m_ail = ailp; - return 0; - -out_free_ailp: - kmem_free(ailp); - return -ENOMEM; -} - -void -xfs_trans_ail_destroy( - xfs_mount_t *mp) -{ - struct xfs_ail *ailp = mp->m_ail; - - kthread_stop(ailp->xa_task); - kmem_free(ailp); -} diff --git a/src/linux/fs/xfs/xfs_trans_bmap.c b/src/linux/fs/xfs/xfs_trans_bmap.c deleted file mode 100644 index 6408e7d..0000000 --- a/src/linux/fs/xfs/xfs_trans_bmap.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_trans.h" -#include "xfs_trans_priv.h" -#include "xfs_bmap_item.h" -#include "xfs_alloc.h" -#include "xfs_bmap.h" -#include "xfs_inode.h" - -/* - * This routine is called to allocate a "bmap update done" - * log item. - */ -struct xfs_bud_log_item * -xfs_trans_get_bud( - struct xfs_trans *tp, - struct xfs_bui_log_item *buip) -{ - struct xfs_bud_log_item *budp; - - budp = xfs_bud_init(tp->t_mountp, buip); - xfs_trans_add_item(tp, &budp->bud_item); - return budp; -} - -/* - * Finish an bmap update and log it to the BUD. Note that the - * transaction is marked dirty regardless of whether the bmap update - * succeeds or fails to support the BUI/BUD lifecycle rules. - */ -int -xfs_trans_log_finish_bmap_update( - struct xfs_trans *tp, - struct xfs_bud_log_item *budp, - struct xfs_defer_ops *dop, - enum xfs_bmap_intent_type type, - struct xfs_inode *ip, - int whichfork, - xfs_fileoff_t startoff, - xfs_fsblock_t startblock, - xfs_filblks_t blockcount, - xfs_exntst_t state) -{ - int error; - - error = xfs_bmap_finish_one(tp, dop, ip, type, whichfork, startoff, - startblock, blockcount, state); - - /* - * Mark the transaction dirty, even on error. This ensures the - * transaction is aborted, which: - * - * 1.) releases the BUI and frees the BUD - * 2.) shuts down the filesystem - */ - tp->t_flags |= XFS_TRANS_DIRTY; - budp->bud_item.li_desc->lid_flags |= XFS_LID_DIRTY; - - return error; -} - -/* Sort bmap intents by inode. */ -static int -xfs_bmap_update_diff_items( - void *priv, - struct list_head *a, - struct list_head *b) -{ - struct xfs_bmap_intent *ba; - struct xfs_bmap_intent *bb; - - ba = container_of(a, struct xfs_bmap_intent, bi_list); - bb = container_of(b, struct xfs_bmap_intent, bi_list); - return ba->bi_owner->i_ino - bb->bi_owner->i_ino; -} - -/* Get an BUI. */ -STATIC void * -xfs_bmap_update_create_intent( - struct xfs_trans *tp, - unsigned int count) -{ - struct xfs_bui_log_item *buip; - - ASSERT(count == XFS_BUI_MAX_FAST_EXTENTS); - ASSERT(tp != NULL); - - buip = xfs_bui_init(tp->t_mountp); - ASSERT(buip != NULL); - - /* - * Get a log_item_desc to point at the new item. - */ - xfs_trans_add_item(tp, &buip->bui_item); - return buip; -} - -/* Set the map extent flags for this mapping. */ -static void -xfs_trans_set_bmap_flags( - struct xfs_map_extent *bmap, - enum xfs_bmap_intent_type type, - int whichfork, - xfs_exntst_t state) -{ - bmap->me_flags = 0; - switch (type) { - case XFS_BMAP_MAP: - case XFS_BMAP_UNMAP: - bmap->me_flags = type; - break; - default: - ASSERT(0); - } - if (state == XFS_EXT_UNWRITTEN) - bmap->me_flags |= XFS_BMAP_EXTENT_UNWRITTEN; - if (whichfork == XFS_ATTR_FORK) - bmap->me_flags |= XFS_BMAP_EXTENT_ATTR_FORK; -} - -/* Log bmap updates in the intent item. */ -STATIC void -xfs_bmap_update_log_item( - struct xfs_trans *tp, - void *intent, - struct list_head *item) -{ - struct xfs_bui_log_item *buip = intent; - struct xfs_bmap_intent *bmap; - uint next_extent; - struct xfs_map_extent *map; - - bmap = container_of(item, struct xfs_bmap_intent, bi_list); - - tp->t_flags |= XFS_TRANS_DIRTY; - buip->bui_item.li_desc->lid_flags |= XFS_LID_DIRTY; - - /* - * atomic_inc_return gives us the value after the increment; - * we want to use it as an array index so we need to subtract 1 from - * it. - */ - next_extent = atomic_inc_return(&buip->bui_next_extent) - 1; - ASSERT(next_extent < buip->bui_format.bui_nextents); - map = &buip->bui_format.bui_extents[next_extent]; - map->me_owner = bmap->bi_owner->i_ino; - map->me_startblock = bmap->bi_bmap.br_startblock; - map->me_startoff = bmap->bi_bmap.br_startoff; - map->me_len = bmap->bi_bmap.br_blockcount; - xfs_trans_set_bmap_flags(map, bmap->bi_type, bmap->bi_whichfork, - bmap->bi_bmap.br_state); -} - -/* Get an BUD so we can process all the deferred rmap updates. */ -STATIC void * -xfs_bmap_update_create_done( - struct xfs_trans *tp, - void *intent, - unsigned int count) -{ - return xfs_trans_get_bud(tp, intent); -} - -/* Process a deferred rmap update. */ -STATIC int -xfs_bmap_update_finish_item( - struct xfs_trans *tp, - struct xfs_defer_ops *dop, - struct list_head *item, - void *done_item, - void **state) -{ - struct xfs_bmap_intent *bmap; - int error; - - bmap = container_of(item, struct xfs_bmap_intent, bi_list); - error = xfs_trans_log_finish_bmap_update(tp, done_item, dop, - bmap->bi_type, - bmap->bi_owner, bmap->bi_whichfork, - bmap->bi_bmap.br_startoff, - bmap->bi_bmap.br_startblock, - bmap->bi_bmap.br_blockcount, - bmap->bi_bmap.br_state); - kmem_free(bmap); - return error; -} - -/* Abort all pending BUIs. */ -STATIC void -xfs_bmap_update_abort_intent( - void *intent) -{ - xfs_bui_release(intent); -} - -/* Cancel a deferred rmap update. */ -STATIC void -xfs_bmap_update_cancel_item( - struct list_head *item) -{ - struct xfs_bmap_intent *bmap; - - bmap = container_of(item, struct xfs_bmap_intent, bi_list); - kmem_free(bmap); -} - -static const struct xfs_defer_op_type xfs_bmap_update_defer_type = { - .type = XFS_DEFER_OPS_TYPE_BMAP, - .max_items = XFS_BUI_MAX_FAST_EXTENTS, - .diff_items = xfs_bmap_update_diff_items, - .create_intent = xfs_bmap_update_create_intent, - .abort_intent = xfs_bmap_update_abort_intent, - .log_item = xfs_bmap_update_log_item, - .create_done = xfs_bmap_update_create_done, - .finish_item = xfs_bmap_update_finish_item, - .cancel_item = xfs_bmap_update_cancel_item, -}; - -/* Register the deferred op type. */ -void -xfs_bmap_update_init_defer_op(void) -{ - xfs_defer_init_op_type(&xfs_bmap_update_defer_type); -} diff --git a/src/linux/fs/xfs/xfs_trans_buf.c b/src/linux/fs/xfs/xfs_trans_buf.c deleted file mode 100644 index 8ee29ca..0000000 --- a/src/linux/fs/xfs/xfs_trans_buf.c +++ /dev/null @@ -1,802 +0,0 @@ -/* - * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_buf_item.h" -#include "xfs_trans_priv.h" -#include "xfs_error.h" -#include "xfs_trace.h" - -/* - * Check to see if a buffer matching the given parameters is already - * a part of the given transaction. - */ -STATIC struct xfs_buf * -xfs_trans_buf_item_match( - struct xfs_trans *tp, - struct xfs_buftarg *target, - struct xfs_buf_map *map, - int nmaps) -{ - struct xfs_log_item_desc *lidp; - struct xfs_buf_log_item *blip; - int len = 0; - int i; - - for (i = 0; i < nmaps; i++) - len += map[i].bm_len; - - list_for_each_entry(lidp, &tp->t_items, lid_trans) { - blip = (struct xfs_buf_log_item *)lidp->lid_item; - if (blip->bli_item.li_type == XFS_LI_BUF && - blip->bli_buf->b_target == target && - XFS_BUF_ADDR(blip->bli_buf) == map[0].bm_bn && - blip->bli_buf->b_length == len) { - ASSERT(blip->bli_buf->b_map_count == nmaps); - return blip->bli_buf; - } - } - - return NULL; -} - -/* - * Add the locked buffer to the transaction. - * - * The buffer must be locked, and it cannot be associated with any - * transaction. - * - * If the buffer does not yet have a buf log item associated with it, - * then allocate one for it. Then add the buf item to the transaction. - */ -STATIC void -_xfs_trans_bjoin( - struct xfs_trans *tp, - struct xfs_buf *bp, - int reset_recur) -{ - struct xfs_buf_log_item *bip; - - ASSERT(bp->b_transp == NULL); - - /* - * The xfs_buf_log_item pointer is stored in b_fsprivate. If - * it doesn't have one yet, then allocate one and initialize it. - * The checks to see if one is there are in xfs_buf_item_init(). - */ - xfs_buf_item_init(bp, tp->t_mountp); - bip = bp->b_fspriv; - ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); - ASSERT(!(bip->__bli_format.blf_flags & XFS_BLF_CANCEL)); - ASSERT(!(bip->bli_flags & XFS_BLI_LOGGED)); - if (reset_recur) - bip->bli_recur = 0; - - /* - * Take a reference for this transaction on the buf item. - */ - atomic_inc(&bip->bli_refcount); - - /* - * Get a log_item_desc to point at the new item. - */ - xfs_trans_add_item(tp, &bip->bli_item); - - /* - * Initialize b_fsprivate2 so we can find it with incore_match() - * in xfs_trans_get_buf() and friends above. - */ - bp->b_transp = tp; - -} - -void -xfs_trans_bjoin( - struct xfs_trans *tp, - struct xfs_buf *bp) -{ - _xfs_trans_bjoin(tp, bp, 0); - trace_xfs_trans_bjoin(bp->b_fspriv); -} - -/* - * Get and lock the buffer for the caller if it is not already - * locked within the given transaction. If it is already locked - * within the transaction, just increment its lock recursion count - * and return a pointer to it. - * - * If the transaction pointer is NULL, make this just a normal - * get_buf() call. - */ -struct xfs_buf * -xfs_trans_get_buf_map( - struct xfs_trans *tp, - struct xfs_buftarg *target, - struct xfs_buf_map *map, - int nmaps, - xfs_buf_flags_t flags) -{ - xfs_buf_t *bp; - xfs_buf_log_item_t *bip; - - if (!tp) - return xfs_buf_get_map(target, map, nmaps, flags); - - /* - * If we find the buffer in the cache with this transaction - * pointer in its b_fsprivate2 field, then we know we already - * have it locked. In this case we just increment the lock - * recursion count and return the buffer to the caller. - */ - bp = xfs_trans_buf_item_match(tp, target, map, nmaps); - if (bp != NULL) { - ASSERT(xfs_buf_islocked(bp)); - if (XFS_FORCED_SHUTDOWN(tp->t_mountp)) { - xfs_buf_stale(bp); - bp->b_flags |= XBF_DONE; - } - - ASSERT(bp->b_transp == tp); - bip = bp->b_fspriv; - ASSERT(bip != NULL); - ASSERT(atomic_read(&bip->bli_refcount) > 0); - bip->bli_recur++; - trace_xfs_trans_get_buf_recur(bip); - return bp; - } - - bp = xfs_buf_get_map(target, map, nmaps, flags); - if (bp == NULL) { - return NULL; - } - - ASSERT(!bp->b_error); - - _xfs_trans_bjoin(tp, bp, 1); - trace_xfs_trans_get_buf(bp->b_fspriv); - return bp; -} - -/* - * Get and lock the superblock buffer of this file system for the - * given transaction. - * - * We don't need to use incore_match() here, because the superblock - * buffer is a private buffer which we keep a pointer to in the - * mount structure. - */ -xfs_buf_t * -xfs_trans_getsb(xfs_trans_t *tp, - struct xfs_mount *mp, - int flags) -{ - xfs_buf_t *bp; - xfs_buf_log_item_t *bip; - - /* - * Default to just trying to lock the superblock buffer - * if tp is NULL. - */ - if (tp == NULL) - return xfs_getsb(mp, flags); - - /* - * If the superblock buffer already has this transaction - * pointer in its b_fsprivate2 field, then we know we already - * have it locked. In this case we just increment the lock - * recursion count and return the buffer to the caller. - */ - bp = mp->m_sb_bp; - if (bp->b_transp == tp) { - bip = bp->b_fspriv; - ASSERT(bip != NULL); - ASSERT(atomic_read(&bip->bli_refcount) > 0); - bip->bli_recur++; - trace_xfs_trans_getsb_recur(bip); - return bp; - } - - bp = xfs_getsb(mp, flags); - if (bp == NULL) - return NULL; - - _xfs_trans_bjoin(tp, bp, 1); - trace_xfs_trans_getsb(bp->b_fspriv); - return bp; -} - -/* - * Get and lock the buffer for the caller if it is not already - * locked within the given transaction. If it has not yet been - * read in, read it from disk. If it is already locked - * within the transaction and already read in, just increment its - * lock recursion count and return a pointer to it. - * - * If the transaction pointer is NULL, make this just a normal - * read_buf() call. - */ -int -xfs_trans_read_buf_map( - struct xfs_mount *mp, - struct xfs_trans *tp, - struct xfs_buftarg *target, - struct xfs_buf_map *map, - int nmaps, - xfs_buf_flags_t flags, - struct xfs_buf **bpp, - const struct xfs_buf_ops *ops) -{ - struct xfs_buf *bp = NULL; - struct xfs_buf_log_item *bip; - int error; - - *bpp = NULL; - /* - * If we find the buffer in the cache with this transaction - * pointer in its b_fsprivate2 field, then we know we already - * have it locked. If it is already read in we just increment - * the lock recursion count and return the buffer to the caller. - * If the buffer is not yet read in, then we read it in, increment - * the lock recursion count, and return it to the caller. - */ - if (tp) - bp = xfs_trans_buf_item_match(tp, target, map, nmaps); - if (bp) { - ASSERT(xfs_buf_islocked(bp)); - ASSERT(bp->b_transp == tp); - ASSERT(bp->b_fspriv != NULL); - ASSERT(!bp->b_error); - ASSERT(bp->b_flags & XBF_DONE); - - /* - * We never locked this buf ourselves, so we shouldn't - * brelse it either. Just get out. - */ - if (XFS_FORCED_SHUTDOWN(mp)) { - trace_xfs_trans_read_buf_shut(bp, _RET_IP_); - return -EIO; - } - - bip = bp->b_fspriv; - bip->bli_recur++; - - ASSERT(atomic_read(&bip->bli_refcount) > 0); - trace_xfs_trans_read_buf_recur(bip); - *bpp = bp; - return 0; - } - - bp = xfs_buf_read_map(target, map, nmaps, flags, ops); - if (!bp) { - if (!(flags & XBF_TRYLOCK)) - return -ENOMEM; - return tp ? 0 : -EAGAIN; - } - - /* - * If we've had a read error, then the contents of the buffer are - * invalid and should not be used. To ensure that a followup read tries - * to pull the buffer from disk again, we clear the XBF_DONE flag and - * mark the buffer stale. This ensures that anyone who has a current - * reference to the buffer will interpret it's contents correctly and - * future cache lookups will also treat it as an empty, uninitialised - * buffer. - */ - if (bp->b_error) { - error = bp->b_error; - if (!XFS_FORCED_SHUTDOWN(mp)) - xfs_buf_ioerror_alert(bp, __func__); - bp->b_flags &= ~XBF_DONE; - xfs_buf_stale(bp); - - if (tp && (tp->t_flags & XFS_TRANS_DIRTY)) - xfs_force_shutdown(tp->t_mountp, SHUTDOWN_META_IO_ERROR); - xfs_buf_relse(bp); - - /* bad CRC means corrupted metadata */ - if (error == -EFSBADCRC) - error = -EFSCORRUPTED; - return error; - } - - if (XFS_FORCED_SHUTDOWN(mp)) { - xfs_buf_relse(bp); - trace_xfs_trans_read_buf_shut(bp, _RET_IP_); - return -EIO; - } - - if (tp) { - _xfs_trans_bjoin(tp, bp, 1); - trace_xfs_trans_read_buf(bp->b_fspriv); - } - *bpp = bp; - return 0; - -} - -/* - * Release the buffer bp which was previously acquired with one of the - * xfs_trans_... buffer allocation routines if the buffer has not - * been modified within this transaction. If the buffer is modified - * within this transaction, do decrement the recursion count but do - * not release the buffer even if the count goes to 0. If the buffer is not - * modified within the transaction, decrement the recursion count and - * release the buffer if the recursion count goes to 0. - * - * If the buffer is to be released and it was not modified before - * this transaction began, then free the buf_log_item associated with it. - * - * If the transaction pointer is NULL, make this just a normal - * brelse() call. - */ -void -xfs_trans_brelse(xfs_trans_t *tp, - xfs_buf_t *bp) -{ - xfs_buf_log_item_t *bip; - - /* - * Default to a normal brelse() call if the tp is NULL. - */ - if (tp == NULL) { - ASSERT(bp->b_transp == NULL); - xfs_buf_relse(bp); - return; - } - - ASSERT(bp->b_transp == tp); - bip = bp->b_fspriv; - ASSERT(bip->bli_item.li_type == XFS_LI_BUF); - ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); - ASSERT(!(bip->__bli_format.blf_flags & XFS_BLF_CANCEL)); - ASSERT(atomic_read(&bip->bli_refcount) > 0); - - trace_xfs_trans_brelse(bip); - - /* - * If the release is just for a recursive lock, - * then decrement the count and return. - */ - if (bip->bli_recur > 0) { - bip->bli_recur--; - return; - } - - /* - * If the buffer is dirty within this transaction, we can't - * release it until we commit. - */ - if (bip->bli_item.li_desc->lid_flags & XFS_LID_DIRTY) - return; - - /* - * If the buffer has been invalidated, then we can't release - * it until the transaction commits to disk unless it is re-dirtied - * as part of this transaction. This prevents us from pulling - * the item from the AIL before we should. - */ - if (bip->bli_flags & XFS_BLI_STALE) - return; - - ASSERT(!(bip->bli_flags & XFS_BLI_LOGGED)); - - /* - * Free up the log item descriptor tracking the released item. - */ - xfs_trans_del_item(&bip->bli_item); - - /* - * Clear the hold flag in the buf log item if it is set. - * We wouldn't want the next user of the buffer to - * get confused. - */ - if (bip->bli_flags & XFS_BLI_HOLD) { - bip->bli_flags &= ~XFS_BLI_HOLD; - } - - /* - * Drop our reference to the buf log item. - */ - atomic_dec(&bip->bli_refcount); - - /* - * If the buf item is not tracking data in the log, then - * we must free it before releasing the buffer back to the - * free pool. Before releasing the buffer to the free pool, - * clear the transaction pointer in b_fsprivate2 to dissolve - * its relation to this transaction. - */ - if (!xfs_buf_item_dirty(bip)) { -/*** - ASSERT(bp->b_pincount == 0); -***/ - ASSERT(atomic_read(&bip->bli_refcount) == 0); - ASSERT(!(bip->bli_item.li_flags & XFS_LI_IN_AIL)); - ASSERT(!(bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF)); - xfs_buf_item_relse(bp); - } - - bp->b_transp = NULL; - xfs_buf_relse(bp); -} - -/* - * Mark the buffer as not needing to be unlocked when the buf item's - * iop_unlock() routine is called. The buffer must already be locked - * and associated with the given transaction. - */ -/* ARGSUSED */ -void -xfs_trans_bhold(xfs_trans_t *tp, - xfs_buf_t *bp) -{ - xfs_buf_log_item_t *bip = bp->b_fspriv; - - ASSERT(bp->b_transp == tp); - ASSERT(bip != NULL); - ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); - ASSERT(!(bip->__bli_format.blf_flags & XFS_BLF_CANCEL)); - ASSERT(atomic_read(&bip->bli_refcount) > 0); - - bip->bli_flags |= XFS_BLI_HOLD; - trace_xfs_trans_bhold(bip); -} - -/* - * Cancel the previous buffer hold request made on this buffer - * for this transaction. - */ -void -xfs_trans_bhold_release(xfs_trans_t *tp, - xfs_buf_t *bp) -{ - xfs_buf_log_item_t *bip = bp->b_fspriv; - - ASSERT(bp->b_transp == tp); - ASSERT(bip != NULL); - ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); - ASSERT(!(bip->__bli_format.blf_flags & XFS_BLF_CANCEL)); - ASSERT(atomic_read(&bip->bli_refcount) > 0); - ASSERT(bip->bli_flags & XFS_BLI_HOLD); - - bip->bli_flags &= ~XFS_BLI_HOLD; - trace_xfs_trans_bhold_release(bip); -} - -/* - * This is called to mark bytes first through last inclusive of the given - * buffer as needing to be logged when the transaction is committed. - * The buffer must already be associated with the given transaction. - * - * First and last are numbers relative to the beginning of this buffer, - * so the first byte in the buffer is numbered 0 regardless of the - * value of b_blkno. - */ -void -xfs_trans_log_buf(xfs_trans_t *tp, - xfs_buf_t *bp, - uint first, - uint last) -{ - xfs_buf_log_item_t *bip = bp->b_fspriv; - - ASSERT(bp->b_transp == tp); - ASSERT(bip != NULL); - ASSERT(first <= last && last < BBTOB(bp->b_length)); - ASSERT(bp->b_iodone == NULL || - bp->b_iodone == xfs_buf_iodone_callbacks); - - /* - * Mark the buffer as needing to be written out eventually, - * and set its iodone function to remove the buffer's buf log - * item from the AIL and free it when the buffer is flushed - * to disk. See xfs_buf_attach_iodone() for more details - * on li_cb and xfs_buf_iodone_callbacks(). - * If we end up aborting this transaction, we trap this buffer - * inside the b_bdstrat callback so that this won't get written to - * disk. - */ - bp->b_flags |= XBF_DONE; - - ASSERT(atomic_read(&bip->bli_refcount) > 0); - bp->b_iodone = xfs_buf_iodone_callbacks; - bip->bli_item.li_cb = xfs_buf_iodone; - - trace_xfs_trans_log_buf(bip); - - /* - * If we invalidated the buffer within this transaction, then - * cancel the invalidation now that we're dirtying the buffer - * again. There are no races with the code in xfs_buf_item_unpin(), - * because we have a reference to the buffer this entire time. - */ - if (bip->bli_flags & XFS_BLI_STALE) { - bip->bli_flags &= ~XFS_BLI_STALE; - ASSERT(bp->b_flags & XBF_STALE); - bp->b_flags &= ~XBF_STALE; - bip->__bli_format.blf_flags &= ~XFS_BLF_CANCEL; - } - - tp->t_flags |= XFS_TRANS_DIRTY; - bip->bli_item.li_desc->lid_flags |= XFS_LID_DIRTY; - - /* - * If we have an ordered buffer we are not logging any dirty range but - * it still needs to be marked dirty and that it has been logged. - */ - bip->bli_flags |= XFS_BLI_DIRTY | XFS_BLI_LOGGED; - if (!(bip->bli_flags & XFS_BLI_ORDERED)) - xfs_buf_item_log(bip, first, last); -} - - -/* - * Invalidate a buffer that is being used within a transaction. - * - * Typically this is because the blocks in the buffer are being freed, so we - * need to prevent it from being written out when we're done. Allowing it - * to be written again might overwrite data in the free blocks if they are - * reallocated to a file. - * - * We prevent the buffer from being written out by marking it stale. We can't - * get rid of the buf log item at this point because the buffer may still be - * pinned by another transaction. If that is the case, then we'll wait until - * the buffer is committed to disk for the last time (we can tell by the ref - * count) and free it in xfs_buf_item_unpin(). Until that happens we will - * keep the buffer locked so that the buffer and buf log item are not reused. - * - * We also set the XFS_BLF_CANCEL flag in the buf log format structure and log - * the buf item. This will be used at recovery time to determine that copies - * of the buffer in the log before this should not be replayed. - * - * We mark the item descriptor and the transaction dirty so that we'll hold - * the buffer until after the commit. - * - * Since we're invalidating the buffer, we also clear the state about which - * parts of the buffer have been logged. We also clear the flag indicating - * that this is an inode buffer since the data in the buffer will no longer - * be valid. - * - * We set the stale bit in the buffer as well since we're getting rid of it. - */ -void -xfs_trans_binval( - xfs_trans_t *tp, - xfs_buf_t *bp) -{ - xfs_buf_log_item_t *bip = bp->b_fspriv; - int i; - - ASSERT(bp->b_transp == tp); - ASSERT(bip != NULL); - ASSERT(atomic_read(&bip->bli_refcount) > 0); - - trace_xfs_trans_binval(bip); - - if (bip->bli_flags & XFS_BLI_STALE) { - /* - * If the buffer is already invalidated, then - * just return. - */ - ASSERT(bp->b_flags & XBF_STALE); - ASSERT(!(bip->bli_flags & (XFS_BLI_LOGGED | XFS_BLI_DIRTY))); - ASSERT(!(bip->__bli_format.blf_flags & XFS_BLF_INODE_BUF)); - ASSERT(!(bip->__bli_format.blf_flags & XFS_BLFT_MASK)); - ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL); - ASSERT(bip->bli_item.li_desc->lid_flags & XFS_LID_DIRTY); - ASSERT(tp->t_flags & XFS_TRANS_DIRTY); - return; - } - - xfs_buf_stale(bp); - - bip->bli_flags |= XFS_BLI_STALE; - bip->bli_flags &= ~(XFS_BLI_INODE_BUF | XFS_BLI_LOGGED | XFS_BLI_DIRTY); - bip->__bli_format.blf_flags &= ~XFS_BLF_INODE_BUF; - bip->__bli_format.blf_flags |= XFS_BLF_CANCEL; - bip->__bli_format.blf_flags &= ~XFS_BLFT_MASK; - for (i = 0; i < bip->bli_format_count; i++) { - memset(bip->bli_formats[i].blf_data_map, 0, - (bip->bli_formats[i].blf_map_size * sizeof(uint))); - } - bip->bli_item.li_desc->lid_flags |= XFS_LID_DIRTY; - tp->t_flags |= XFS_TRANS_DIRTY; -} - -/* - * This call is used to indicate that the buffer contains on-disk inodes which - * must be handled specially during recovery. They require special handling - * because only the di_next_unlinked from the inodes in the buffer should be - * recovered. The rest of the data in the buffer is logged via the inodes - * themselves. - * - * All we do is set the XFS_BLI_INODE_BUF flag in the items flags so it can be - * transferred to the buffer's log format structure so that we'll know what to - * do at recovery time. - */ -void -xfs_trans_inode_buf( - xfs_trans_t *tp, - xfs_buf_t *bp) -{ - xfs_buf_log_item_t *bip = bp->b_fspriv; - - ASSERT(bp->b_transp == tp); - ASSERT(bip != NULL); - ASSERT(atomic_read(&bip->bli_refcount) > 0); - - bip->bli_flags |= XFS_BLI_INODE_BUF; - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DINO_BUF); -} - -/* - * This call is used to indicate that the buffer is going to - * be staled and was an inode buffer. This means it gets - * special processing during unpin - where any inodes - * associated with the buffer should be removed from ail. - * There is also special processing during recovery, - * any replay of the inodes in the buffer needs to be - * prevented as the buffer may have been reused. - */ -void -xfs_trans_stale_inode_buf( - xfs_trans_t *tp, - xfs_buf_t *bp) -{ - xfs_buf_log_item_t *bip = bp->b_fspriv; - - ASSERT(bp->b_transp == tp); - ASSERT(bip != NULL); - ASSERT(atomic_read(&bip->bli_refcount) > 0); - - bip->bli_flags |= XFS_BLI_STALE_INODE; - bip->bli_item.li_cb = xfs_buf_iodone; - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DINO_BUF); -} - -/* - * Mark the buffer as being one which contains newly allocated - * inodes. We need to make sure that even if this buffer is - * relogged as an 'inode buf' we still recover all of the inode - * images in the face of a crash. This works in coordination with - * xfs_buf_item_committed() to ensure that the buffer remains in the - * AIL at its original location even after it has been relogged. - */ -/* ARGSUSED */ -void -xfs_trans_inode_alloc_buf( - xfs_trans_t *tp, - xfs_buf_t *bp) -{ - xfs_buf_log_item_t *bip = bp->b_fspriv; - - ASSERT(bp->b_transp == tp); - ASSERT(bip != NULL); - ASSERT(atomic_read(&bip->bli_refcount) > 0); - - bip->bli_flags |= XFS_BLI_INODE_ALLOC_BUF; - xfs_trans_buf_set_type(tp, bp, XFS_BLFT_DINO_BUF); -} - -/* - * Mark the buffer as ordered for this transaction. This means - * that the contents of the buffer are not recorded in the transaction - * but it is tracked in the AIL as though it was. This allows us - * to record logical changes in transactions rather than the physical - * changes we make to the buffer without changing writeback ordering - * constraints of metadata buffers. - */ -void -xfs_trans_ordered_buf( - struct xfs_trans *tp, - struct xfs_buf *bp) -{ - struct xfs_buf_log_item *bip = bp->b_fspriv; - - ASSERT(bp->b_transp == tp); - ASSERT(bip != NULL); - ASSERT(atomic_read(&bip->bli_refcount) > 0); - - bip->bli_flags |= XFS_BLI_ORDERED; - trace_xfs_buf_item_ordered(bip); -} - -/* - * Set the type of the buffer for log recovery so that it can correctly identify - * and hence attach the correct buffer ops to the buffer after replay. - */ -void -xfs_trans_buf_set_type( - struct xfs_trans *tp, - struct xfs_buf *bp, - enum xfs_blft type) -{ - struct xfs_buf_log_item *bip = bp->b_fspriv; - - if (!tp) - return; - - ASSERT(bp->b_transp == tp); - ASSERT(bip != NULL); - ASSERT(atomic_read(&bip->bli_refcount) > 0); - - xfs_blft_to_flags(&bip->__bli_format, type); -} - -void -xfs_trans_buf_copy_type( - struct xfs_buf *dst_bp, - struct xfs_buf *src_bp) -{ - struct xfs_buf_log_item *sbip = src_bp->b_fspriv; - struct xfs_buf_log_item *dbip = dst_bp->b_fspriv; - enum xfs_blft type; - - type = xfs_blft_from_flags(&sbip->__bli_format); - xfs_blft_to_flags(&dbip->__bli_format, type); -} - -/* - * Similar to xfs_trans_inode_buf(), this marks the buffer as a cluster of - * dquots. However, unlike in inode buffer recovery, dquot buffers get - * recovered in their entirety. (Hence, no XFS_BLI_DQUOT_ALLOC_BUF flag). - * The only thing that makes dquot buffers different from regular - * buffers is that we must not replay dquot bufs when recovering - * if a _corresponding_ quotaoff has happened. We also have to distinguish - * between usr dquot bufs and grp dquot bufs, because usr and grp quotas - * can be turned off independently. - */ -/* ARGSUSED */ -void -xfs_trans_dquot_buf( - xfs_trans_t *tp, - xfs_buf_t *bp, - uint type) -{ - struct xfs_buf_log_item *bip = bp->b_fspriv; - - ASSERT(type == XFS_BLF_UDQUOT_BUF || - type == XFS_BLF_PDQUOT_BUF || - type == XFS_BLF_GDQUOT_BUF); - - bip->__bli_format.blf_flags |= type; - - switch (type) { - case XFS_BLF_UDQUOT_BUF: - type = XFS_BLFT_UDQUOT_BUF; - break; - case XFS_BLF_PDQUOT_BUF: - type = XFS_BLFT_PDQUOT_BUF; - break; - case XFS_BLF_GDQUOT_BUF: - type = XFS_BLFT_GDQUOT_BUF; - break; - default: - type = XFS_BLFT_UNKNOWN_BUF; - break; - } - - xfs_trans_buf_set_type(tp, bp, type); -} diff --git a/src/linux/fs/xfs/xfs_trans_extfree.c b/src/linux/fs/xfs/xfs_trans_extfree.c deleted file mode 100644 index ab43864..0000000 --- a/src/linux/fs/xfs/xfs_trans_extfree.c +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (c) 2000,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_bit.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_trans.h" -#include "xfs_trans_priv.h" -#include "xfs_extfree_item.h" -#include "xfs_alloc.h" -#include "xfs_bmap.h" -#include "xfs_trace.h" - -/* - * This routine is called to allocate an "extent free done" - * log item that will hold nextents worth of extents. The - * caller must use all nextents extents, because we are not - * flexible about this at all. - */ -struct xfs_efd_log_item * -xfs_trans_get_efd(struct xfs_trans *tp, - struct xfs_efi_log_item *efip, - uint nextents) -{ - struct xfs_efd_log_item *efdp; - - ASSERT(tp != NULL); - ASSERT(nextents > 0); - - efdp = xfs_efd_init(tp->t_mountp, efip, nextents); - ASSERT(efdp != NULL); - - /* - * Get a log_item_desc to point at the new item. - */ - xfs_trans_add_item(tp, &efdp->efd_item); - return efdp; -} - -/* - * Free an extent and log it to the EFD. Note that the transaction is marked - * dirty regardless of whether the extent free succeeds or fails to support the - * EFI/EFD lifecycle rules. - */ -int -xfs_trans_free_extent( - struct xfs_trans *tp, - struct xfs_efd_log_item *efdp, - xfs_fsblock_t start_block, - xfs_extlen_t ext_len, - struct xfs_owner_info *oinfo) -{ - struct xfs_mount *mp = tp->t_mountp; - uint next_extent; - xfs_agnumber_t agno = XFS_FSB_TO_AGNO(mp, start_block); - xfs_agblock_t agbno = XFS_FSB_TO_AGBNO(mp, start_block); - struct xfs_extent *extp; - int error; - - trace_xfs_bmap_free_deferred(tp->t_mountp, agno, 0, agbno, ext_len); - - error = xfs_free_extent(tp, start_block, ext_len, oinfo, - XFS_AG_RESV_NONE); - - /* - * Mark the transaction dirty, even on error. This ensures the - * transaction is aborted, which: - * - * 1.) releases the EFI and frees the EFD - * 2.) shuts down the filesystem - */ - tp->t_flags |= XFS_TRANS_DIRTY; - efdp->efd_item.li_desc->lid_flags |= XFS_LID_DIRTY; - - next_extent = efdp->efd_next_extent; - ASSERT(next_extent < efdp->efd_format.efd_nextents); - extp = &(efdp->efd_format.efd_extents[next_extent]); - extp->ext_start = start_block; - extp->ext_len = ext_len; - efdp->efd_next_extent++; - - return error; -} - -/* Sort bmap items by AG. */ -static int -xfs_extent_free_diff_items( - void *priv, - struct list_head *a, - struct list_head *b) -{ - struct xfs_mount *mp = priv; - struct xfs_extent_free_item *ra; - struct xfs_extent_free_item *rb; - - ra = container_of(a, struct xfs_extent_free_item, xefi_list); - rb = container_of(b, struct xfs_extent_free_item, xefi_list); - return XFS_FSB_TO_AGNO(mp, ra->xefi_startblock) - - XFS_FSB_TO_AGNO(mp, rb->xefi_startblock); -} - -/* Get an EFI. */ -STATIC void * -xfs_extent_free_create_intent( - struct xfs_trans *tp, - unsigned int count) -{ - struct xfs_efi_log_item *efip; - - ASSERT(tp != NULL); - ASSERT(count > 0); - - efip = xfs_efi_init(tp->t_mountp, count); - ASSERT(efip != NULL); - - /* - * Get a log_item_desc to point at the new item. - */ - xfs_trans_add_item(tp, &efip->efi_item); - return efip; -} - -/* Log a free extent to the intent item. */ -STATIC void -xfs_extent_free_log_item( - struct xfs_trans *tp, - void *intent, - struct list_head *item) -{ - struct xfs_efi_log_item *efip = intent; - struct xfs_extent_free_item *free; - uint next_extent; - struct xfs_extent *extp; - - free = container_of(item, struct xfs_extent_free_item, xefi_list); - - tp->t_flags |= XFS_TRANS_DIRTY; - efip->efi_item.li_desc->lid_flags |= XFS_LID_DIRTY; - - /* - * atomic_inc_return gives us the value after the increment; - * we want to use it as an array index so we need to subtract 1 from - * it. - */ - next_extent = atomic_inc_return(&efip->efi_next_extent) - 1; - ASSERT(next_extent < efip->efi_format.efi_nextents); - extp = &efip->efi_format.efi_extents[next_extent]; - extp->ext_start = free->xefi_startblock; - extp->ext_len = free->xefi_blockcount; -} - -/* Get an EFD so we can process all the free extents. */ -STATIC void * -xfs_extent_free_create_done( - struct xfs_trans *tp, - void *intent, - unsigned int count) -{ - return xfs_trans_get_efd(tp, intent, count); -} - -/* Process a free extent. */ -STATIC int -xfs_extent_free_finish_item( - struct xfs_trans *tp, - struct xfs_defer_ops *dop, - struct list_head *item, - void *done_item, - void **state) -{ - struct xfs_extent_free_item *free; - int error; - - free = container_of(item, struct xfs_extent_free_item, xefi_list); - error = xfs_trans_free_extent(tp, done_item, - free->xefi_startblock, - free->xefi_blockcount, - &free->xefi_oinfo); - kmem_free(free); - return error; -} - -/* Abort all pending EFIs. */ -STATIC void -xfs_extent_free_abort_intent( - void *intent) -{ - xfs_efi_release(intent); -} - -/* Cancel a free extent. */ -STATIC void -xfs_extent_free_cancel_item( - struct list_head *item) -{ - struct xfs_extent_free_item *free; - - free = container_of(item, struct xfs_extent_free_item, xefi_list); - kmem_free(free); -} - -static const struct xfs_defer_op_type xfs_extent_free_defer_type = { - .type = XFS_DEFER_OPS_TYPE_FREE, - .max_items = XFS_EFI_MAX_FAST_EXTENTS, - .diff_items = xfs_extent_free_diff_items, - .create_intent = xfs_extent_free_create_intent, - .abort_intent = xfs_extent_free_abort_intent, - .log_item = xfs_extent_free_log_item, - .create_done = xfs_extent_free_create_done, - .finish_item = xfs_extent_free_finish_item, - .cancel_item = xfs_extent_free_cancel_item, -}; - -/* Register the deferred op type. */ -void -xfs_extent_free_init_defer_op(void) -{ - xfs_defer_init_op_type(&xfs_extent_free_defer_type); -} diff --git a/src/linux/fs/xfs/xfs_trans_inode.c b/src/linux/fs/xfs/xfs_trans_inode.c deleted file mode 100644 index dab8daa..0000000 --- a/src/linux/fs/xfs/xfs_trans_inode.c +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2000,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_inode.h" -#include "xfs_trans.h" -#include "xfs_trans_priv.h" -#include "xfs_inode_item.h" -#include "xfs_trace.h" - -/* - * Add a locked inode to the transaction. - * - * The inode must be locked, and it cannot be associated with any transaction. - * If lock_flags is non-zero the inode will be unlocked on transaction commit. - */ -void -xfs_trans_ijoin( - struct xfs_trans *tp, - struct xfs_inode *ip, - uint lock_flags) -{ - xfs_inode_log_item_t *iip; - - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - if (ip->i_itemp == NULL) - xfs_inode_item_init(ip, ip->i_mount); - iip = ip->i_itemp; - - ASSERT(iip->ili_lock_flags == 0); - iip->ili_lock_flags = lock_flags; - - /* - * Get a log_item_desc to point at the new item. - */ - xfs_trans_add_item(tp, &iip->ili_item); -} - -/* - * Transactional inode timestamp update. Requires the inode to be locked and - * joined to the transaction supplied. Relies on the transaction subsystem to - * track dirty state and update/writeback the inode accordingly. - */ -void -xfs_trans_ichgtime( - struct xfs_trans *tp, - struct xfs_inode *ip, - int flags) -{ - struct inode *inode = VFS_I(ip); - struct timespec tv; - - ASSERT(tp); - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - - tv = current_time(inode); - - if (flags & XFS_ICHGTIME_MOD) - inode->i_mtime = tv; - if (flags & XFS_ICHGTIME_CHG) - inode->i_ctime = tv; -} - -/* - * This is called to mark the fields indicated in fieldmask as needing - * to be logged when the transaction is committed. The inode must - * already be associated with the given transaction. - * - * The values for fieldmask are defined in xfs_inode_item.h. We always - * log all of the core inode if any of it has changed, and we always log - * all of the inline data/extents/b-tree root if any of them has changed. - */ -void -xfs_trans_log_inode( - xfs_trans_t *tp, - xfs_inode_t *ip, - uint flags) -{ - ASSERT(ip->i_itemp != NULL); - ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); - - /* - * Record the specific change for fdatasync optimisation. This - * allows fdatasync to skip log forces for inodes that are only - * timestamp dirty. We do this before the change count so that - * the core being logged in this case does not impact on fdatasync - * behaviour. - */ - ip->i_itemp->ili_fsync_fields |= flags; - - /* - * First time we log the inode in a transaction, bump the inode change - * counter if it is configured for this to occur. We don't use - * inode_inc_version() because there is no need for extra locking around - * i_version as we already hold the inode locked exclusively for - * metadata modification. - */ - if (!(ip->i_itemp->ili_item.li_desc->lid_flags & XFS_LID_DIRTY) && - IS_I_VERSION(VFS_I(ip))) { - VFS_I(ip)->i_version++; - flags |= XFS_ILOG_CORE; - } - - tp->t_flags |= XFS_TRANS_DIRTY; - ip->i_itemp->ili_item.li_desc->lid_flags |= XFS_LID_DIRTY; - - /* - * Always OR in the bits from the ili_last_fields field. - * This is to coordinate with the xfs_iflush() and xfs_iflush_done() - * routines in the eventual clearing of the ili_fields bits. - * See the big comment in xfs_iflush() for an explanation of - * this coordination mechanism. - */ - flags |= ip->i_itemp->ili_last_fields; - ip->i_itemp->ili_fields |= flags; -} diff --git a/src/linux/fs/xfs/xfs_trans_priv.h b/src/linux/fs/xfs/xfs_trans_priv.h deleted file mode 100644 index 49931b7..0000000 --- a/src/linux/fs/xfs/xfs_trans_priv.h +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2000,2002,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_TRANS_PRIV_H__ -#define __XFS_TRANS_PRIV_H__ - -struct xfs_log_item; -struct xfs_log_item_desc; -struct xfs_mount; -struct xfs_trans; -struct xfs_ail; -struct xfs_log_vec; - - -void xfs_trans_init(struct xfs_mount *); -void xfs_trans_add_item(struct xfs_trans *, struct xfs_log_item *); -void xfs_trans_del_item(struct xfs_log_item *); -void xfs_trans_free_items(struct xfs_trans *tp, xfs_lsn_t commit_lsn, - bool abort); -void xfs_trans_unreserve_and_mod_sb(struct xfs_trans *tp); - -void xfs_trans_committed_bulk(struct xfs_ail *ailp, struct xfs_log_vec *lv, - xfs_lsn_t commit_lsn, int aborted); -/* - * AIL traversal cursor. - * - * Rather than using a generation number for detecting changes in the ail, use - * a cursor that is protected by the ail lock. The aild cursor exists in the - * struct xfs_ail, but other traversals can declare it on the stack and link it - * to the ail list. - * - * When an object is deleted from or moved int the AIL, the cursor list is - * searched to see if the object is a designated cursor item. If it is, it is - * deleted from the cursor so that the next time the cursor is used traversal - * will return to the start. - * - * This means a traversal colliding with a removal will cause a restart of the - * list scan, rather than any insertion or deletion anywhere in the list. The - * low bit of the item pointer is set if the cursor has been invalidated so - * that we can tell the difference between invalidation and reaching the end - * of the list to trigger traversal restarts. - */ -struct xfs_ail_cursor { - struct list_head list; - struct xfs_log_item *item; -}; - -/* - * Private AIL structures. - * - * Eventually we need to drive the locking in here as well. - */ -struct xfs_ail { - struct xfs_mount *xa_mount; - struct task_struct *xa_task; - struct list_head xa_ail; - xfs_lsn_t xa_target; - xfs_lsn_t xa_target_prev; - struct list_head xa_cursors; - spinlock_t xa_lock; - xfs_lsn_t xa_last_pushed_lsn; - int xa_log_flush; - struct list_head xa_buf_list; - wait_queue_head_t xa_empty; -}; - -/* - * From xfs_trans_ail.c - */ -void xfs_trans_ail_update_bulk(struct xfs_ail *ailp, - struct xfs_ail_cursor *cur, - struct xfs_log_item **log_items, int nr_items, - xfs_lsn_t lsn) __releases(ailp->xa_lock); -/* - * Return a pointer to the first item in the AIL. If the AIL is empty, then - * return NULL. - */ -static inline struct xfs_log_item * -xfs_ail_min( - struct xfs_ail *ailp) -{ - return list_first_entry_or_null(&ailp->xa_ail, struct xfs_log_item, - li_ail); -} - -static inline void -xfs_trans_ail_update( - struct xfs_ail *ailp, - struct xfs_log_item *lip, - xfs_lsn_t lsn) __releases(ailp->xa_lock) -{ - xfs_trans_ail_update_bulk(ailp, NULL, &lip, 1, lsn); -} - -void xfs_trans_ail_delete_bulk(struct xfs_ail *ailp, - struct xfs_log_item **log_items, int nr_items, - int shutdown_type) - __releases(ailp->xa_lock); -static inline void -xfs_trans_ail_delete( - struct xfs_ail *ailp, - xfs_log_item_t *lip, - int shutdown_type) __releases(ailp->xa_lock) -{ - xfs_trans_ail_delete_bulk(ailp, &lip, 1, shutdown_type); -} - -static inline void -xfs_trans_ail_remove( - struct xfs_log_item *lip, - int shutdown_type) -{ - struct xfs_ail *ailp = lip->li_ailp; - - spin_lock(&ailp->xa_lock); - /* xfs_trans_ail_delete() drops the AIL lock */ - if (lip->li_flags & XFS_LI_IN_AIL) - xfs_trans_ail_delete(ailp, lip, shutdown_type); - else - spin_unlock(&ailp->xa_lock); -} - -void xfs_ail_push(struct xfs_ail *, xfs_lsn_t); -void xfs_ail_push_all(struct xfs_ail *); -void xfs_ail_push_all_sync(struct xfs_ail *); -struct xfs_log_item *xfs_ail_min(struct xfs_ail *ailp); -xfs_lsn_t xfs_ail_min_lsn(struct xfs_ail *ailp); - -struct xfs_log_item * xfs_trans_ail_cursor_first(struct xfs_ail *ailp, - struct xfs_ail_cursor *cur, - xfs_lsn_t lsn); -struct xfs_log_item * xfs_trans_ail_cursor_last(struct xfs_ail *ailp, - struct xfs_ail_cursor *cur, - xfs_lsn_t lsn); -struct xfs_log_item * xfs_trans_ail_cursor_next(struct xfs_ail *ailp, - struct xfs_ail_cursor *cur); -void xfs_trans_ail_cursor_done(struct xfs_ail_cursor *cur); - -#if BITS_PER_LONG != 64 -static inline void -xfs_trans_ail_copy_lsn( - struct xfs_ail *ailp, - xfs_lsn_t *dst, - xfs_lsn_t *src) -{ - ASSERT(sizeof(xfs_lsn_t) == 8); /* don't lock if it shrinks */ - spin_lock(&ailp->xa_lock); - *dst = *src; - spin_unlock(&ailp->xa_lock); -} -#else -static inline void -xfs_trans_ail_copy_lsn( - struct xfs_ail *ailp, - xfs_lsn_t *dst, - xfs_lsn_t *src) -{ - ASSERT(sizeof(xfs_lsn_t) == 8); - *dst = *src; -} -#endif -#endif /* __XFS_TRANS_PRIV_H__ */ diff --git a/src/linux/fs/xfs/xfs_trans_refcount.c b/src/linux/fs/xfs/xfs_trans_refcount.c deleted file mode 100644 index 94c1877..0000000 --- a/src/linux/fs/xfs/xfs_trans_refcount.c +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_trans.h" -#include "xfs_trans_priv.h" -#include "xfs_refcount_item.h" -#include "xfs_alloc.h" -#include "xfs_refcount.h" - -/* - * This routine is called to allocate a "refcount update done" - * log item. - */ -struct xfs_cud_log_item * -xfs_trans_get_cud( - struct xfs_trans *tp, - struct xfs_cui_log_item *cuip) -{ - struct xfs_cud_log_item *cudp; - - cudp = xfs_cud_init(tp->t_mountp, cuip); - xfs_trans_add_item(tp, &cudp->cud_item); - return cudp; -} - -/* - * Finish an refcount update and log it to the CUD. Note that the - * transaction is marked dirty regardless of whether the refcount - * update succeeds or fails to support the CUI/CUD lifecycle rules. - */ -int -xfs_trans_log_finish_refcount_update( - struct xfs_trans *tp, - struct xfs_cud_log_item *cudp, - struct xfs_defer_ops *dop, - enum xfs_refcount_intent_type type, - xfs_fsblock_t startblock, - xfs_extlen_t blockcount, - xfs_fsblock_t *new_fsb, - xfs_extlen_t *new_len, - struct xfs_btree_cur **pcur) -{ - int error; - - error = xfs_refcount_finish_one(tp, dop, type, startblock, - blockcount, new_fsb, new_len, pcur); - - /* - * Mark the transaction dirty, even on error. This ensures the - * transaction is aborted, which: - * - * 1.) releases the CUI and frees the CUD - * 2.) shuts down the filesystem - */ - tp->t_flags |= XFS_TRANS_DIRTY; - cudp->cud_item.li_desc->lid_flags |= XFS_LID_DIRTY; - - return error; -} - -/* Sort refcount intents by AG. */ -static int -xfs_refcount_update_diff_items( - void *priv, - struct list_head *a, - struct list_head *b) -{ - struct xfs_mount *mp = priv; - struct xfs_refcount_intent *ra; - struct xfs_refcount_intent *rb; - - ra = container_of(a, struct xfs_refcount_intent, ri_list); - rb = container_of(b, struct xfs_refcount_intent, ri_list); - return XFS_FSB_TO_AGNO(mp, ra->ri_startblock) - - XFS_FSB_TO_AGNO(mp, rb->ri_startblock); -} - -/* Get an CUI. */ -STATIC void * -xfs_refcount_update_create_intent( - struct xfs_trans *tp, - unsigned int count) -{ - struct xfs_cui_log_item *cuip; - - ASSERT(tp != NULL); - ASSERT(count > 0); - - cuip = xfs_cui_init(tp->t_mountp, count); - ASSERT(cuip != NULL); - - /* - * Get a log_item_desc to point at the new item. - */ - xfs_trans_add_item(tp, &cuip->cui_item); - return cuip; -} - -/* Set the phys extent flags for this reverse mapping. */ -static void -xfs_trans_set_refcount_flags( - struct xfs_phys_extent *refc, - enum xfs_refcount_intent_type type) -{ - refc->pe_flags = 0; - switch (type) { - case XFS_REFCOUNT_INCREASE: - case XFS_REFCOUNT_DECREASE: - case XFS_REFCOUNT_ALLOC_COW: - case XFS_REFCOUNT_FREE_COW: - refc->pe_flags |= type; - break; - default: - ASSERT(0); - } -} - -/* Log refcount updates in the intent item. */ -STATIC void -xfs_refcount_update_log_item( - struct xfs_trans *tp, - void *intent, - struct list_head *item) -{ - struct xfs_cui_log_item *cuip = intent; - struct xfs_refcount_intent *refc; - uint next_extent; - struct xfs_phys_extent *ext; - - refc = container_of(item, struct xfs_refcount_intent, ri_list); - - tp->t_flags |= XFS_TRANS_DIRTY; - cuip->cui_item.li_desc->lid_flags |= XFS_LID_DIRTY; - - /* - * atomic_inc_return gives us the value after the increment; - * we want to use it as an array index so we need to subtract 1 from - * it. - */ - next_extent = atomic_inc_return(&cuip->cui_next_extent) - 1; - ASSERT(next_extent < cuip->cui_format.cui_nextents); - ext = &cuip->cui_format.cui_extents[next_extent]; - ext->pe_startblock = refc->ri_startblock; - ext->pe_len = refc->ri_blockcount; - xfs_trans_set_refcount_flags(ext, refc->ri_type); -} - -/* Get an CUD so we can process all the deferred refcount updates. */ -STATIC void * -xfs_refcount_update_create_done( - struct xfs_trans *tp, - void *intent, - unsigned int count) -{ - return xfs_trans_get_cud(tp, intent); -} - -/* Process a deferred refcount update. */ -STATIC int -xfs_refcount_update_finish_item( - struct xfs_trans *tp, - struct xfs_defer_ops *dop, - struct list_head *item, - void *done_item, - void **state) -{ - struct xfs_refcount_intent *refc; - xfs_fsblock_t new_fsb; - xfs_extlen_t new_aglen; - int error; - - refc = container_of(item, struct xfs_refcount_intent, ri_list); - error = xfs_trans_log_finish_refcount_update(tp, done_item, dop, - refc->ri_type, - refc->ri_startblock, - refc->ri_blockcount, - &new_fsb, &new_aglen, - (struct xfs_btree_cur **)state); - /* Did we run out of reservation? Requeue what we didn't finish. */ - if (!error && new_aglen > 0) { - ASSERT(refc->ri_type == XFS_REFCOUNT_INCREASE || - refc->ri_type == XFS_REFCOUNT_DECREASE); - refc->ri_startblock = new_fsb; - refc->ri_blockcount = new_aglen; - return -EAGAIN; - } - kmem_free(refc); - return error; -} - -/* Clean up after processing deferred refcounts. */ -STATIC void -xfs_refcount_update_finish_cleanup( - struct xfs_trans *tp, - void *state, - int error) -{ - struct xfs_btree_cur *rcur = state; - - xfs_refcount_finish_one_cleanup(tp, rcur, error); -} - -/* Abort all pending CUIs. */ -STATIC void -xfs_refcount_update_abort_intent( - void *intent) -{ - xfs_cui_release(intent); -} - -/* Cancel a deferred refcount update. */ -STATIC void -xfs_refcount_update_cancel_item( - struct list_head *item) -{ - struct xfs_refcount_intent *refc; - - refc = container_of(item, struct xfs_refcount_intent, ri_list); - kmem_free(refc); -} - -static const struct xfs_defer_op_type xfs_refcount_update_defer_type = { - .type = XFS_DEFER_OPS_TYPE_REFCOUNT, - .max_items = XFS_CUI_MAX_FAST_EXTENTS, - .diff_items = xfs_refcount_update_diff_items, - .create_intent = xfs_refcount_update_create_intent, - .abort_intent = xfs_refcount_update_abort_intent, - .log_item = xfs_refcount_update_log_item, - .create_done = xfs_refcount_update_create_done, - .finish_item = xfs_refcount_update_finish_item, - .finish_cleanup = xfs_refcount_update_finish_cleanup, - .cancel_item = xfs_refcount_update_cancel_item, -}; - -/* Register the deferred op type. */ -void -xfs_refcount_update_init_defer_op(void) -{ - xfs_defer_init_op_type(&xfs_refcount_update_defer_type); -} diff --git a/src/linux/fs/xfs/xfs_trans_rmap.c b/src/linux/fs/xfs/xfs_trans_rmap.c deleted file mode 100644 index 9ead064..0000000 --- a/src/linux/fs/xfs/xfs_trans_rmap.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright (C) 2016 Oracle. All Rights Reserved. - * - * Author: Darrick J. Wong - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ -#include "xfs.h" -#include "xfs_fs.h" -#include "xfs_shared.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_defer.h" -#include "xfs_trans.h" -#include "xfs_trans_priv.h" -#include "xfs_rmap_item.h" -#include "xfs_alloc.h" -#include "xfs_rmap.h" - -/* Set the map extent flags for this reverse mapping. */ -static void -xfs_trans_set_rmap_flags( - struct xfs_map_extent *rmap, - enum xfs_rmap_intent_type type, - int whichfork, - xfs_exntst_t state) -{ - rmap->me_flags = 0; - if (state == XFS_EXT_UNWRITTEN) - rmap->me_flags |= XFS_RMAP_EXTENT_UNWRITTEN; - if (whichfork == XFS_ATTR_FORK) - rmap->me_flags |= XFS_RMAP_EXTENT_ATTR_FORK; - switch (type) { - case XFS_RMAP_MAP: - rmap->me_flags |= XFS_RMAP_EXTENT_MAP; - break; - case XFS_RMAP_MAP_SHARED: - rmap->me_flags |= XFS_RMAP_EXTENT_MAP_SHARED; - break; - case XFS_RMAP_UNMAP: - rmap->me_flags |= XFS_RMAP_EXTENT_UNMAP; - break; - case XFS_RMAP_UNMAP_SHARED: - rmap->me_flags |= XFS_RMAP_EXTENT_UNMAP_SHARED; - break; - case XFS_RMAP_CONVERT: - rmap->me_flags |= XFS_RMAP_EXTENT_CONVERT; - break; - case XFS_RMAP_CONVERT_SHARED: - rmap->me_flags |= XFS_RMAP_EXTENT_CONVERT_SHARED; - break; - case XFS_RMAP_ALLOC: - rmap->me_flags |= XFS_RMAP_EXTENT_ALLOC; - break; - case XFS_RMAP_FREE: - rmap->me_flags |= XFS_RMAP_EXTENT_FREE; - break; - default: - ASSERT(0); - } -} - -struct xfs_rud_log_item * -xfs_trans_get_rud( - struct xfs_trans *tp, - struct xfs_rui_log_item *ruip) -{ - struct xfs_rud_log_item *rudp; - - rudp = xfs_rud_init(tp->t_mountp, ruip); - xfs_trans_add_item(tp, &rudp->rud_item); - return rudp; -} - -/* - * Finish an rmap update and log it to the RUD. Note that the transaction is - * marked dirty regardless of whether the rmap update succeeds or fails to - * support the RUI/RUD lifecycle rules. - */ -int -xfs_trans_log_finish_rmap_update( - struct xfs_trans *tp, - struct xfs_rud_log_item *rudp, - enum xfs_rmap_intent_type type, - __uint64_t owner, - int whichfork, - xfs_fileoff_t startoff, - xfs_fsblock_t startblock, - xfs_filblks_t blockcount, - xfs_exntst_t state, - struct xfs_btree_cur **pcur) -{ - int error; - - error = xfs_rmap_finish_one(tp, type, owner, whichfork, startoff, - startblock, blockcount, state, pcur); - - /* - * Mark the transaction dirty, even on error. This ensures the - * transaction is aborted, which: - * - * 1.) releases the RUI and frees the RUD - * 2.) shuts down the filesystem - */ - tp->t_flags |= XFS_TRANS_DIRTY; - rudp->rud_item.li_desc->lid_flags |= XFS_LID_DIRTY; - - return error; -} - -/* Sort rmap intents by AG. */ -static int -xfs_rmap_update_diff_items( - void *priv, - struct list_head *a, - struct list_head *b) -{ - struct xfs_mount *mp = priv; - struct xfs_rmap_intent *ra; - struct xfs_rmap_intent *rb; - - ra = container_of(a, struct xfs_rmap_intent, ri_list); - rb = container_of(b, struct xfs_rmap_intent, ri_list); - return XFS_FSB_TO_AGNO(mp, ra->ri_bmap.br_startblock) - - XFS_FSB_TO_AGNO(mp, rb->ri_bmap.br_startblock); -} - -/* Get an RUI. */ -STATIC void * -xfs_rmap_update_create_intent( - struct xfs_trans *tp, - unsigned int count) -{ - struct xfs_rui_log_item *ruip; - - ASSERT(tp != NULL); - ASSERT(count > 0); - - ruip = xfs_rui_init(tp->t_mountp, count); - ASSERT(ruip != NULL); - - /* - * Get a log_item_desc to point at the new item. - */ - xfs_trans_add_item(tp, &ruip->rui_item); - return ruip; -} - -/* Log rmap updates in the intent item. */ -STATIC void -xfs_rmap_update_log_item( - struct xfs_trans *tp, - void *intent, - struct list_head *item) -{ - struct xfs_rui_log_item *ruip = intent; - struct xfs_rmap_intent *rmap; - uint next_extent; - struct xfs_map_extent *map; - - rmap = container_of(item, struct xfs_rmap_intent, ri_list); - - tp->t_flags |= XFS_TRANS_DIRTY; - ruip->rui_item.li_desc->lid_flags |= XFS_LID_DIRTY; - - /* - * atomic_inc_return gives us the value after the increment; - * we want to use it as an array index so we need to subtract 1 from - * it. - */ - next_extent = atomic_inc_return(&ruip->rui_next_extent) - 1; - ASSERT(next_extent < ruip->rui_format.rui_nextents); - map = &ruip->rui_format.rui_extents[next_extent]; - map->me_owner = rmap->ri_owner; - map->me_startblock = rmap->ri_bmap.br_startblock; - map->me_startoff = rmap->ri_bmap.br_startoff; - map->me_len = rmap->ri_bmap.br_blockcount; - xfs_trans_set_rmap_flags(map, rmap->ri_type, rmap->ri_whichfork, - rmap->ri_bmap.br_state); -} - -/* Get an RUD so we can process all the deferred rmap updates. */ -STATIC void * -xfs_rmap_update_create_done( - struct xfs_trans *tp, - void *intent, - unsigned int count) -{ - return xfs_trans_get_rud(tp, intent); -} - -/* Process a deferred rmap update. */ -STATIC int -xfs_rmap_update_finish_item( - struct xfs_trans *tp, - struct xfs_defer_ops *dop, - struct list_head *item, - void *done_item, - void **state) -{ - struct xfs_rmap_intent *rmap; - int error; - - rmap = container_of(item, struct xfs_rmap_intent, ri_list); - error = xfs_trans_log_finish_rmap_update(tp, done_item, - rmap->ri_type, - rmap->ri_owner, rmap->ri_whichfork, - rmap->ri_bmap.br_startoff, - rmap->ri_bmap.br_startblock, - rmap->ri_bmap.br_blockcount, - rmap->ri_bmap.br_state, - (struct xfs_btree_cur **)state); - kmem_free(rmap); - return error; -} - -/* Clean up after processing deferred rmaps. */ -STATIC void -xfs_rmap_update_finish_cleanup( - struct xfs_trans *tp, - void *state, - int error) -{ - struct xfs_btree_cur *rcur = state; - - xfs_rmap_finish_one_cleanup(tp, rcur, error); -} - -/* Abort all pending RUIs. */ -STATIC void -xfs_rmap_update_abort_intent( - void *intent) -{ - xfs_rui_release(intent); -} - -/* Cancel a deferred rmap update. */ -STATIC void -xfs_rmap_update_cancel_item( - struct list_head *item) -{ - struct xfs_rmap_intent *rmap; - - rmap = container_of(item, struct xfs_rmap_intent, ri_list); - kmem_free(rmap); -} - -static const struct xfs_defer_op_type xfs_rmap_update_defer_type = { - .type = XFS_DEFER_OPS_TYPE_RMAP, - .max_items = XFS_RUI_MAX_FAST_EXTENTS, - .diff_items = xfs_rmap_update_diff_items, - .create_intent = xfs_rmap_update_create_intent, - .abort_intent = xfs_rmap_update_abort_intent, - .log_item = xfs_rmap_update_log_item, - .create_done = xfs_rmap_update_create_done, - .finish_item = xfs_rmap_update_finish_item, - .finish_cleanup = xfs_rmap_update_finish_cleanup, - .cancel_item = xfs_rmap_update_cancel_item, -}; - -/* Register the deferred op type. */ -void -xfs_rmap_update_init_defer_op(void) -{ - xfs_defer_init_op_type(&xfs_rmap_update_defer_type); -} diff --git a/src/linux/fs/xfs/xfs_xattr.c b/src/linux/fs/xfs/xfs_xattr.c deleted file mode 100644 index 6290093..0000000 --- a/src/linux/fs/xfs/xfs_xattr.c +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (C) 2008 Christoph Hellwig. - * Portions Copyright (C) 2000-2008 Silicon Graphics, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include "xfs.h" -#include "xfs_format.h" -#include "xfs_log_format.h" -#include "xfs_trans_resv.h" -#include "xfs_mount.h" -#include "xfs_da_format.h" -#include "xfs_inode.h" -#include "xfs_attr.h" -#include "xfs_attr_leaf.h" -#include "xfs_acl.h" - -#include -#include - - -static int -xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused, - struct inode *inode, const char *name, void *value, size_t size) -{ - int xflags = handler->flags; - struct xfs_inode *ip = XFS_I(inode); - int error, asize = size; - - /* Convert Linux syscall to XFS internal ATTR flags */ - if (!size) { - xflags |= ATTR_KERNOVAL; - value = NULL; - } - - error = xfs_attr_get(ip, (unsigned char *)name, value, &asize, xflags); - if (error) - return error; - return asize; -} - -void -xfs_forget_acl( - struct inode *inode, - const char *name, - int xflags) -{ - /* - * Invalidate any cached ACLs if the user has bypassed the ACL - * interface. We don't validate the content whatsoever so it is caller - * responsibility to provide data in valid format and ensure i_mode is - * consistent. - */ - if (xflags & ATTR_ROOT) { -#ifdef CONFIG_XFS_POSIX_ACL - if (!strcmp(name, SGI_ACL_FILE)) - forget_cached_acl(inode, ACL_TYPE_ACCESS); - else if (!strcmp(name, SGI_ACL_DEFAULT)) - forget_cached_acl(inode, ACL_TYPE_DEFAULT); -#endif - } -} - -static int -xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused, - struct inode *inode, const char *name, const void *value, - size_t size, int flags) -{ - int xflags = handler->flags; - struct xfs_inode *ip = XFS_I(inode); - int error; - - /* Convert Linux syscall to XFS internal ATTR flags */ - if (flags & XATTR_CREATE) - xflags |= ATTR_CREATE; - if (flags & XATTR_REPLACE) - xflags |= ATTR_REPLACE; - - if (!value) - return xfs_attr_remove(ip, (unsigned char *)name, xflags); - error = xfs_attr_set(ip, (unsigned char *)name, - (void *)value, size, xflags); - if (!error) - xfs_forget_acl(inode, name, xflags); - - return error; -} - -static const struct xattr_handler xfs_xattr_user_handler = { - .prefix = XATTR_USER_PREFIX, - .flags = 0, /* no flags implies user namespace */ - .get = xfs_xattr_get, - .set = xfs_xattr_set, -}; - -static const struct xattr_handler xfs_xattr_trusted_handler = { - .prefix = XATTR_TRUSTED_PREFIX, - .flags = ATTR_ROOT, - .get = xfs_xattr_get, - .set = xfs_xattr_set, -}; - -static const struct xattr_handler xfs_xattr_security_handler = { - .prefix = XATTR_SECURITY_PREFIX, - .flags = ATTR_SECURE, - .get = xfs_xattr_get, - .set = xfs_xattr_set, -}; - -const struct xattr_handler *xfs_xattr_handlers[] = { - &xfs_xattr_user_handler, - &xfs_xattr_trusted_handler, - &xfs_xattr_security_handler, -#ifdef CONFIG_XFS_POSIX_ACL - &posix_acl_access_xattr_handler, - &posix_acl_default_xattr_handler, -#endif - NULL -}; - -static int -__xfs_xattr_put_listent( - struct xfs_attr_list_context *context, - char *prefix, - int prefix_len, - unsigned char *name, - int namelen) -{ - char *offset; - int arraytop; - - if (!context->alist) - goto compute_size; - - arraytop = context->count + prefix_len + namelen + 1; - if (arraytop > context->firstu) { - context->count = -1; /* insufficient space */ - context->seen_enough = 1; - return 0; - } - offset = (char *)context->alist + context->count; - strncpy(offset, prefix, prefix_len); - offset += prefix_len; - strncpy(offset, (char *)name, namelen); /* real name */ - offset += namelen; - *offset = '\0'; - -compute_size: - context->count += prefix_len + namelen + 1; - return 0; -} - -static int -xfs_xattr_put_listent( - struct xfs_attr_list_context *context, - int flags, - unsigned char *name, - int namelen, - int valuelen) -{ - char *prefix; - int prefix_len; - - ASSERT(context->count >= 0); - - if (flags & XFS_ATTR_ROOT) { -#ifdef CONFIG_XFS_POSIX_ACL - if (namelen == SGI_ACL_FILE_SIZE && - strncmp(name, SGI_ACL_FILE, - SGI_ACL_FILE_SIZE) == 0) { - int ret = __xfs_xattr_put_listent( - context, XATTR_SYSTEM_PREFIX, - XATTR_SYSTEM_PREFIX_LEN, - XATTR_POSIX_ACL_ACCESS, - strlen(XATTR_POSIX_ACL_ACCESS)); - if (ret) - return ret; - } else if (namelen == SGI_ACL_DEFAULT_SIZE && - strncmp(name, SGI_ACL_DEFAULT, - SGI_ACL_DEFAULT_SIZE) == 0) { - int ret = __xfs_xattr_put_listent( - context, XATTR_SYSTEM_PREFIX, - XATTR_SYSTEM_PREFIX_LEN, - XATTR_POSIX_ACL_DEFAULT, - strlen(XATTR_POSIX_ACL_DEFAULT)); - if (ret) - return ret; - } -#endif - - /* - * Only show root namespace entries if we are actually allowed to - * see them. - */ - if (!capable(CAP_SYS_ADMIN)) - return 0; - - prefix = XATTR_TRUSTED_PREFIX; - prefix_len = XATTR_TRUSTED_PREFIX_LEN; - } else if (flags & XFS_ATTR_SECURE) { - prefix = XATTR_SECURITY_PREFIX; - prefix_len = XATTR_SECURITY_PREFIX_LEN; - } else { - prefix = XATTR_USER_PREFIX; - prefix_len = XATTR_USER_PREFIX_LEN; - } - - return __xfs_xattr_put_listent(context, prefix, prefix_len, name, - namelen); -} - -ssize_t -xfs_vn_listxattr( - struct dentry *dentry, - char *data, - size_t size) -{ - struct xfs_attr_list_context context; - struct attrlist_cursor_kern cursor = { 0 }; - struct inode *inode = d_inode(dentry); - int error; - - /* - * First read the regular on-disk attributes. - */ - memset(&context, 0, sizeof(context)); - context.dp = XFS_I(inode); - context.cursor = &cursor; - context.resynch = 1; - context.alist = size ? data : NULL; - context.bufsize = size; - context.firstu = context.bufsize; - context.put_listent = xfs_xattr_put_listent; - - error = xfs_attr_list_int(&context); - if (error) - return error; - if (context.count < 0) - return -ERANGE; - - return context.count; -} diff --git a/src/linux/include/acpi/acbuffer.h b/src/linux/include/acpi/acbuffer.h deleted file mode 100644 index cd20d55..0000000 --- a/src/linux/include/acpi/acbuffer.h +++ /dev/null @@ -1,244 +0,0 @@ -/****************************************************************************** - * - * Name: acbuffer.h - Support for buffers returned by ACPI predefined names - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACBUFFER_H__ -#define __ACBUFFER_H__ - -/* - * Contains buffer structures for these predefined names: - * _FDE, _GRT, _GTM, _PLD, _SRT - */ - -/* - * Note: C bitfields are not used for this reason: - * - * "Bitfields are great and easy to read, but unfortunately the C language - * does not specify the layout of bitfields in memory, which means they are - * essentially useless for dealing with packed data in on-disk formats or - * binary wire protocols." (Or ACPI tables and buffers.) "If you ask me, - * this decision was a design error in C. Ritchie could have picked an order - * and stuck with it." Norman Ramsey. - * See http://stackoverflow.com/a/1053662/41661 - */ - -/* _FDE return value */ - -struct acpi_fde_info { - u32 floppy0; - u32 floppy1; - u32 floppy2; - u32 floppy3; - u32 tape; -}; - -/* - * _GRT return value - * _SRT input value - */ -struct acpi_grt_info { - u16 year; - u8 month; - u8 day; - u8 hour; - u8 minute; - u8 second; - u8 valid; - u16 milliseconds; - u16 timezone; - u8 daylight; - u8 reserved[3]; -}; - -/* _GTM return value */ - -struct acpi_gtm_info { - u32 pio_speed0; - u32 dma_speed0; - u32 pio_speed1; - u32 dma_speed1; - u32 flags; -}; - -/* - * Formatted _PLD return value. The minimum size is a package containing - * one buffer. - * Revision 1: Buffer is 16 bytes (128 bits) - * Revision 2: Buffer is 20 bytes (160 bits) - * - * Note: This structure is returned from the acpi_decode_pld_buffer - * interface. - */ -struct acpi_pld_info { - u8 revision; - u8 ignore_color; - u8 red; - u8 green; - u8 blue; - u16 width; - u16 height; - u8 user_visible; - u8 dock; - u8 lid; - u8 panel; - u8 vertical_position; - u8 horizontal_position; - u8 shape; - u8 group_orientation; - u8 group_token; - u8 group_position; - u8 bay; - u8 ejectable; - u8 ospm_eject_required; - u8 cabinet_number; - u8 card_cage_number; - u8 reference; - u8 rotation; - u8 order; - u8 reserved; - u16 vertical_offset; - u16 horizontal_offset; -}; - -/* - * Macros to: - * 1) Convert a _PLD buffer to internal struct acpi_pld_info format - ACPI_PLD_GET* - * (Used by acpi_decode_pld_buffer) - * 2) Construct a _PLD buffer - ACPI_PLD_SET* - * (Intended for BIOS use only) - */ -#define ACPI_PLD_REV1_BUFFER_SIZE 16 /* For Revision 1 of the buffer (From ACPI spec) */ -#define ACPI_PLD_REV2_BUFFER_SIZE 20 /* For Revision 2 of the buffer (From ACPI spec) */ -#define ACPI_PLD_BUFFER_SIZE 20 /* For Revision 2 of the buffer (From ACPI spec) */ - -/* First 32-bit dword, bits 0:32 */ - -#define ACPI_PLD_GET_REVISION(dword) ACPI_GET_BITS (dword, 0, ACPI_7BIT_MASK) -#define ACPI_PLD_SET_REVISION(dword,value) ACPI_SET_BITS (dword, 0, ACPI_7BIT_MASK, value) /* Offset 0, Len 7 */ - -#define ACPI_PLD_GET_IGNORE_COLOR(dword) ACPI_GET_BITS (dword, 7, ACPI_1BIT_MASK) -#define ACPI_PLD_SET_IGNORE_COLOR(dword,value) ACPI_SET_BITS (dword, 7, ACPI_1BIT_MASK, value) /* Offset 7, Len 1 */ - -#define ACPI_PLD_GET_RED(dword) ACPI_GET_BITS (dword, 8, ACPI_8BIT_MASK) -#define ACPI_PLD_SET_RED(dword,value) ACPI_SET_BITS (dword, 8, ACPI_8BIT_MASK, value) /* Offset 8, Len 8 */ - -#define ACPI_PLD_GET_GREEN(dword) ACPI_GET_BITS (dword, 16, ACPI_8BIT_MASK) -#define ACPI_PLD_SET_GREEN(dword,value) ACPI_SET_BITS (dword, 16, ACPI_8BIT_MASK, value) /* Offset 16, Len 8 */ - -#define ACPI_PLD_GET_BLUE(dword) ACPI_GET_BITS (dword, 24, ACPI_8BIT_MASK) -#define ACPI_PLD_SET_BLUE(dword,value) ACPI_SET_BITS (dword, 24, ACPI_8BIT_MASK, value) /* Offset 24, Len 8 */ - -/* Second 32-bit dword, bits 33:63 */ - -#define ACPI_PLD_GET_WIDTH(dword) ACPI_GET_BITS (dword, 0, ACPI_16BIT_MASK) -#define ACPI_PLD_SET_WIDTH(dword,value) ACPI_SET_BITS (dword, 0, ACPI_16BIT_MASK, value) /* Offset 32+0=32, Len 16 */ - -#define ACPI_PLD_GET_HEIGHT(dword) ACPI_GET_BITS (dword, 16, ACPI_16BIT_MASK) -#define ACPI_PLD_SET_HEIGHT(dword,value) ACPI_SET_BITS (dword, 16, ACPI_16BIT_MASK, value) /* Offset 32+16=48, Len 16 */ - -/* Third 32-bit dword, bits 64:95 */ - -#define ACPI_PLD_GET_USER_VISIBLE(dword) ACPI_GET_BITS (dword, 0, ACPI_1BIT_MASK) -#define ACPI_PLD_SET_USER_VISIBLE(dword,value) ACPI_SET_BITS (dword, 0, ACPI_1BIT_MASK, value) /* Offset 64+0=64, Len 1 */ - -#define ACPI_PLD_GET_DOCK(dword) ACPI_GET_BITS (dword, 1, ACPI_1BIT_MASK) -#define ACPI_PLD_SET_DOCK(dword,value) ACPI_SET_BITS (dword, 1, ACPI_1BIT_MASK, value) /* Offset 64+1=65, Len 1 */ - -#define ACPI_PLD_GET_LID(dword) ACPI_GET_BITS (dword, 2, ACPI_1BIT_MASK) -#define ACPI_PLD_SET_LID(dword,value) ACPI_SET_BITS (dword, 2, ACPI_1BIT_MASK, value) /* Offset 64+2=66, Len 1 */ - -#define ACPI_PLD_GET_PANEL(dword) ACPI_GET_BITS (dword, 3, ACPI_3BIT_MASK) -#define ACPI_PLD_SET_PANEL(dword,value) ACPI_SET_BITS (dword, 3, ACPI_3BIT_MASK, value) /* Offset 64+3=67, Len 3 */ - -#define ACPI_PLD_GET_VERTICAL(dword) ACPI_GET_BITS (dword, 6, ACPI_2BIT_MASK) -#define ACPI_PLD_SET_VERTICAL(dword,value) ACPI_SET_BITS (dword, 6, ACPI_2BIT_MASK, value) /* Offset 64+6=70, Len 2 */ - -#define ACPI_PLD_GET_HORIZONTAL(dword) ACPI_GET_BITS (dword, 8, ACPI_2BIT_MASK) -#define ACPI_PLD_SET_HORIZONTAL(dword,value) ACPI_SET_BITS (dword, 8, ACPI_2BIT_MASK, value) /* Offset 64+8=72, Len 2 */ - -#define ACPI_PLD_GET_SHAPE(dword) ACPI_GET_BITS (dword, 10, ACPI_4BIT_MASK) -#define ACPI_PLD_SET_SHAPE(dword,value) ACPI_SET_BITS (dword, 10, ACPI_4BIT_MASK, value) /* Offset 64+10=74, Len 4 */ - -#define ACPI_PLD_GET_ORIENTATION(dword) ACPI_GET_BITS (dword, 14, ACPI_1BIT_MASK) -#define ACPI_PLD_SET_ORIENTATION(dword,value) ACPI_SET_BITS (dword, 14, ACPI_1BIT_MASK, value) /* Offset 64+14=78, Len 1 */ - -#define ACPI_PLD_GET_TOKEN(dword) ACPI_GET_BITS (dword, 15, ACPI_8BIT_MASK) -#define ACPI_PLD_SET_TOKEN(dword,value) ACPI_SET_BITS (dword, 15, ACPI_8BIT_MASK, value) /* Offset 64+15=79, Len 8 */ - -#define ACPI_PLD_GET_POSITION(dword) ACPI_GET_BITS (dword, 23, ACPI_8BIT_MASK) -#define ACPI_PLD_SET_POSITION(dword,value) ACPI_SET_BITS (dword, 23, ACPI_8BIT_MASK, value) /* Offset 64+23=87, Len 8 */ - -#define ACPI_PLD_GET_BAY(dword) ACPI_GET_BITS (dword, 31, ACPI_1BIT_MASK) -#define ACPI_PLD_SET_BAY(dword,value) ACPI_SET_BITS (dword, 31, ACPI_1BIT_MASK, value) /* Offset 64+31=95, Len 1 */ - -/* Fourth 32-bit dword, bits 96:127 */ - -#define ACPI_PLD_GET_EJECTABLE(dword) ACPI_GET_BITS (dword, 0, ACPI_1BIT_MASK) -#define ACPI_PLD_SET_EJECTABLE(dword,value) ACPI_SET_BITS (dword, 0, ACPI_1BIT_MASK, value) /* Offset 96+0=96, Len 1 */ - -#define ACPI_PLD_GET_OSPM_EJECT(dword) ACPI_GET_BITS (dword, 1, ACPI_1BIT_MASK) -#define ACPI_PLD_SET_OSPM_EJECT(dword,value) ACPI_SET_BITS (dword, 1, ACPI_1BIT_MASK, value) /* Offset 96+1=97, Len 1 */ - -#define ACPI_PLD_GET_CABINET(dword) ACPI_GET_BITS (dword, 2, ACPI_8BIT_MASK) -#define ACPI_PLD_SET_CABINET(dword,value) ACPI_SET_BITS (dword, 2, ACPI_8BIT_MASK, value) /* Offset 96+2=98, Len 8 */ - -#define ACPI_PLD_GET_CARD_CAGE(dword) ACPI_GET_BITS (dword, 10, ACPI_8BIT_MASK) -#define ACPI_PLD_SET_CARD_CAGE(dword,value) ACPI_SET_BITS (dword, 10, ACPI_8BIT_MASK, value) /* Offset 96+10=106, Len 8 */ - -#define ACPI_PLD_GET_REFERENCE(dword) ACPI_GET_BITS (dword, 18, ACPI_1BIT_MASK) -#define ACPI_PLD_SET_REFERENCE(dword,value) ACPI_SET_BITS (dword, 18, ACPI_1BIT_MASK, value) /* Offset 96+18=114, Len 1 */ - -#define ACPI_PLD_GET_ROTATION(dword) ACPI_GET_BITS (dword, 19, ACPI_4BIT_MASK) -#define ACPI_PLD_SET_ROTATION(dword,value) ACPI_SET_BITS (dword, 19, ACPI_4BIT_MASK, value) /* Offset 96+19=115, Len 4 */ - -#define ACPI_PLD_GET_ORDER(dword) ACPI_GET_BITS (dword, 23, ACPI_5BIT_MASK) -#define ACPI_PLD_SET_ORDER(dword,value) ACPI_SET_BITS (dword, 23, ACPI_5BIT_MASK, value) /* Offset 96+23=119, Len 5 */ - -/* Fifth 32-bit dword, bits 128:159 (Revision 2 of _PLD only) */ - -#define ACPI_PLD_GET_VERT_OFFSET(dword) ACPI_GET_BITS (dword, 0, ACPI_16BIT_MASK) -#define ACPI_PLD_SET_VERT_OFFSET(dword,value) ACPI_SET_BITS (dword, 0, ACPI_16BIT_MASK, value) /* Offset 128+0=128, Len 16 */ - -#define ACPI_PLD_GET_HORIZ_OFFSET(dword) ACPI_GET_BITS (dword, 16, ACPI_16BIT_MASK) -#define ACPI_PLD_SET_HORIZ_OFFSET(dword,value) ACPI_SET_BITS (dword, 16, ACPI_16BIT_MASK, value) /* Offset 128+16=144, Len 16 */ - -#endif /* ACBUFFER_H */ diff --git a/src/linux/include/acpi/acconfig.h b/src/linux/include/acpi/acconfig.h deleted file mode 100644 index 12c2882..0000000 --- a/src/linux/include/acpi/acconfig.h +++ /dev/null @@ -1,250 +0,0 @@ -/****************************************************************************** - * - * Name: acconfig.h - Global configuration constants - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef _ACCONFIG_H -#define _ACCONFIG_H - -/****************************************************************************** - * - * Configuration options - * - *****************************************************************************/ - -/* - * ACPI_DEBUG_OUTPUT - This switch enables all the debug facilities of the - * ACPI subsystem. This includes the DEBUG_PRINT output - * statements. When disabled, all DEBUG_PRINT - * statements are compiled out. - * - * ACPI_APPLICATION - Use this switch if the subsystem is going to be run - * at the application level. - * - */ - -/* - * OS name, used for the _OS object. The _OS object is essentially obsolete, - * but there is a large base of ASL/AML code in existing machines that check - * for the string below. The use of this string usually guarantees that - * the ASL will execute down the most tested code path. Also, there is some - * code that will not execute the _OSI method unless _OS matches the string - * below. Therefore, change this string at your own risk. - */ -#define ACPI_OS_NAME "Microsoft Windows NT" - -/* Maximum objects in the various object caches */ - -#define ACPI_MAX_STATE_CACHE_DEPTH 96 /* State objects */ -#define ACPI_MAX_PARSE_CACHE_DEPTH 96 /* Parse tree objects */ -#define ACPI_MAX_EXTPARSE_CACHE_DEPTH 96 /* Parse tree objects */ -#define ACPI_MAX_OBJECT_CACHE_DEPTH 96 /* Interpreter operand objects */ -#define ACPI_MAX_NAMESPACE_CACHE_DEPTH 96 /* Namespace objects */ - -/* - * Should the subsystem abort the loading of an ACPI table if the - * table checksum is incorrect? - */ -#ifndef ACPI_CHECKSUM_ABORT -#define ACPI_CHECKSUM_ABORT FALSE -#endif - -/* - * Generate a version of ACPICA that only supports "reduced hardware" - * platforms (as defined in ACPI 5.0). Set to TRUE to generate a specialized - * version of ACPICA that ONLY supports the ACPI 5.0 "reduced hardware" - * model. In other words, no ACPI hardware is supported. - * - * If TRUE, this means no support for the following: - * PM Event and Control registers - * SCI interrupt (and handler) - * Fixed Events - * General Purpose Events (GPEs) - * Global Lock - * ACPI PM timer - * FACS table (Waking vectors and Global Lock) - */ -#ifndef ACPI_REDUCED_HARDWARE -#define ACPI_REDUCED_HARDWARE FALSE -#endif - -/****************************************************************************** - * - * Subsystem Constants - * - *****************************************************************************/ - -/* Version of ACPI supported */ - -#define ACPI_CA_SUPPORT_LEVEL 5 - -/* Maximum count for a semaphore object */ - -#define ACPI_MAX_SEMAPHORE_COUNT 256 - -/* Maximum object reference count (detects object deletion issues) */ - -#define ACPI_MAX_REFERENCE_COUNT 0x1000 - -/* Default page size for use in mapping memory for operation regions */ - -#define ACPI_DEFAULT_PAGE_SIZE 4096 /* Must be power of 2 */ - -/* owner_id tracking. 8 entries allows for 255 owner_ids */ - -#define ACPI_NUM_OWNERID_MASKS 8 - -/* Size of the root table array is increased by this increment */ - -#define ACPI_ROOT_TABLE_SIZE_INCREMENT 4 - -/* Maximum sleep allowed via Sleep() operator */ - -#define ACPI_MAX_SLEEP 2000 /* 2000 millisec == two seconds */ - -/* Address Range lists are per-space_id (Memory and I/O only) */ - -#define ACPI_ADDRESS_RANGE_MAX 2 - -/* Maximum number of While() loops before abort */ - -#define ACPI_MAX_LOOP_COUNT 0xFFFF - -/****************************************************************************** - * - * ACPI Specification constants (Do not change unless the specification changes) - * - *****************************************************************************/ - -/* Method info (in WALK_STATE), containing local variables and argumetns */ - -#define ACPI_METHOD_NUM_LOCALS 8 -#define ACPI_METHOD_MAX_LOCAL 7 - -#define ACPI_METHOD_NUM_ARGS 7 -#define ACPI_METHOD_MAX_ARG 6 - -/* - * Operand Stack (in WALK_STATE), Must be large enough to contain METHOD_MAX_ARG - */ -#define ACPI_OBJ_NUM_OPERANDS 8 -#define ACPI_OBJ_MAX_OPERAND 7 - -/* Number of elements in the Result Stack frame, can be an arbitrary value */ - -#define ACPI_RESULTS_FRAME_OBJ_NUM 8 - -/* - * Maximal number of elements the Result Stack can contain, - * it may be an arbitray value not exceeding the types of - * result_size and result_count (now u8). - */ -#define ACPI_RESULTS_OBJ_NUM_MAX 255 - -/* Constants used in searching for the RSDP in low memory */ - -#define ACPI_EBDA_PTR_LOCATION 0x0000040E /* Physical Address */ -#define ACPI_EBDA_PTR_LENGTH 2 -#define ACPI_EBDA_WINDOW_SIZE 1024 -#define ACPI_HI_RSDP_WINDOW_BASE 0x000E0000 /* Physical Address */ -#define ACPI_HI_RSDP_WINDOW_SIZE 0x00020000 -#define ACPI_RSDP_SCAN_STEP 16 - -/* Operation regions */ - -#define ACPI_USER_REGION_BEGIN 0x80 - -/* Maximum space_ids for Operation Regions */ - -#define ACPI_MAX_ADDRESS_SPACE 255 -#define ACPI_NUM_DEFAULT_SPACES 4 - -/* Array sizes. Used for range checking also */ - -#define ACPI_MAX_MATCH_OPCODE 5 - -/* RSDP checksums */ - -#define ACPI_RSDP_CHECKSUM_LENGTH 20 -#define ACPI_RSDP_XCHECKSUM_LENGTH 36 - -/* SMBus, GSBus and IPMI bidirectional buffer size */ - -#define ACPI_SMBUS_BUFFER_SIZE 34 -#define ACPI_GSBUS_BUFFER_SIZE 34 -#define ACPI_IPMI_BUFFER_SIZE 66 - -/* _sx_d and _sx_w control methods */ - -#define ACPI_NUM_sx_d_METHODS 4 -#define ACPI_NUM_sx_w_METHODS 5 - -/****************************************************************************** - * - * Miscellaneous constants - * - *****************************************************************************/ - -/* UUID constants */ - -#define UUID_BUFFER_LENGTH 16 /* Length of UUID in memory */ -#define UUID_STRING_LENGTH 36 /* Total length of a UUID string */ - -/* Positions for required hyphens (dashes) in UUID strings */ - -#define UUID_HYPHEN1_OFFSET 8 -#define UUID_HYPHEN2_OFFSET 13 -#define UUID_HYPHEN3_OFFSET 18 -#define UUID_HYPHEN4_OFFSET 23 - -/****************************************************************************** - * - * ACPI AML Debugger - * - *****************************************************************************/ - -#define ACPI_DEBUGGER_MAX_ARGS ACPI_METHOD_NUM_ARGS + 4 /* Max command line arguments */ -#define ACPI_DB_LINE_BUFFER_SIZE 512 - -#define ACPI_DEBUGGER_COMMAND_PROMPT '-' -#define ACPI_DEBUGGER_EXECUTE_PROMPT '%' - -#endif /* _ACCONFIG_H */ diff --git a/src/linux/include/acpi/acexcep.h b/src/linux/include/acpi/acexcep.h deleted file mode 100644 index 2c39634..0000000 --- a/src/linux/include/acpi/acexcep.h +++ /dev/null @@ -1,388 +0,0 @@ -/****************************************************************************** - * - * Name: acexcep.h - Exception codes returned by the ACPI subsystem - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACEXCEP_H__ -#define __ACEXCEP_H__ - -/* This module contains all possible exception codes for acpi_status */ - -/* - * Exception code classes - */ -#define AE_CODE_ENVIRONMENTAL 0x0000 /* General ACPICA environment */ -#define AE_CODE_PROGRAMMER 0x1000 /* External ACPICA interface caller */ -#define AE_CODE_ACPI_TABLES 0x2000 /* ACPI tables */ -#define AE_CODE_AML 0x3000 /* From executing AML code */ -#define AE_CODE_CONTROL 0x4000 /* Internal control codes */ - -#define AE_CODE_MAX 0x4000 -#define AE_CODE_MASK 0xF000 - -/* - * Macros to insert the exception code classes - */ -#define EXCEP_ENV(code) ((acpi_status) (code | AE_CODE_ENVIRONMENTAL)) -#define EXCEP_PGM(code) ((acpi_status) (code | AE_CODE_PROGRAMMER)) -#define EXCEP_TBL(code) ((acpi_status) (code | AE_CODE_ACPI_TABLES)) -#define EXCEP_AML(code) ((acpi_status) (code | AE_CODE_AML)) -#define EXCEP_CTL(code) ((acpi_status) (code | AE_CODE_CONTROL)) - -/* - * Exception info table. The "Description" field is used only by the - * ACPICA help application (acpihelp). - */ -struct acpi_exception_info { - char *name; - -#ifdef ACPI_HELP_APP - char *description; -#endif -}; - -#ifdef ACPI_HELP_APP -#define EXCEP_TXT(name,description) {name, description} -#else -#define EXCEP_TXT(name,description) {name} -#endif - -/* - * Success is always zero, failure is non-zero - */ -#define ACPI_SUCCESS(a) (!(a)) -#define ACPI_FAILURE(a) (a) - -#define ACPI_SKIP(a) (a == AE_CTRL_SKIP) -#define AE_OK (acpi_status) 0x0000 - -/* - * Environmental exceptions - */ -#define AE_ERROR EXCEP_ENV (0x0001) -#define AE_NO_ACPI_TABLES EXCEP_ENV (0x0002) -#define AE_NO_NAMESPACE EXCEP_ENV (0x0003) -#define AE_NO_MEMORY EXCEP_ENV (0x0004) -#define AE_NOT_FOUND EXCEP_ENV (0x0005) -#define AE_NOT_EXIST EXCEP_ENV (0x0006) -#define AE_ALREADY_EXISTS EXCEP_ENV (0x0007) -#define AE_TYPE EXCEP_ENV (0x0008) -#define AE_NULL_OBJECT EXCEP_ENV (0x0009) -#define AE_NULL_ENTRY EXCEP_ENV (0x000A) -#define AE_BUFFER_OVERFLOW EXCEP_ENV (0x000B) -#define AE_STACK_OVERFLOW EXCEP_ENV (0x000C) -#define AE_STACK_UNDERFLOW EXCEP_ENV (0x000D) -#define AE_NOT_IMPLEMENTED EXCEP_ENV (0x000E) -#define AE_SUPPORT EXCEP_ENV (0x000F) -#define AE_LIMIT EXCEP_ENV (0x0010) -#define AE_TIME EXCEP_ENV (0x0011) -#define AE_ACQUIRE_DEADLOCK EXCEP_ENV (0x0012) -#define AE_RELEASE_DEADLOCK EXCEP_ENV (0x0013) -#define AE_NOT_ACQUIRED EXCEP_ENV (0x0014) -#define AE_ALREADY_ACQUIRED EXCEP_ENV (0x0015) -#define AE_NO_HARDWARE_RESPONSE EXCEP_ENV (0x0016) -#define AE_NO_GLOBAL_LOCK EXCEP_ENV (0x0017) -#define AE_ABORT_METHOD EXCEP_ENV (0x0018) -#define AE_SAME_HANDLER EXCEP_ENV (0x0019) -#define AE_NO_HANDLER EXCEP_ENV (0x001A) -#define AE_OWNER_ID_LIMIT EXCEP_ENV (0x001B) -#define AE_NOT_CONFIGURED EXCEP_ENV (0x001C) -#define AE_ACCESS EXCEP_ENV (0x001D) -#define AE_IO_ERROR EXCEP_ENV (0x001E) - -#define AE_CODE_ENV_MAX 0x001E - -/* - * Programmer exceptions - */ -#define AE_BAD_PARAMETER EXCEP_PGM (0x0001) -#define AE_BAD_CHARACTER EXCEP_PGM (0x0002) -#define AE_BAD_PATHNAME EXCEP_PGM (0x0003) -#define AE_BAD_DATA EXCEP_PGM (0x0004) -#define AE_BAD_HEX_CONSTANT EXCEP_PGM (0x0005) -#define AE_BAD_OCTAL_CONSTANT EXCEP_PGM (0x0006) -#define AE_BAD_DECIMAL_CONSTANT EXCEP_PGM (0x0007) -#define AE_MISSING_ARGUMENTS EXCEP_PGM (0x0008) -#define AE_BAD_ADDRESS EXCEP_PGM (0x0009) - -#define AE_CODE_PGM_MAX 0x0009 - -/* - * Acpi table exceptions - */ -#define AE_BAD_SIGNATURE EXCEP_TBL (0x0001) -#define AE_BAD_HEADER EXCEP_TBL (0x0002) -#define AE_BAD_CHECKSUM EXCEP_TBL (0x0003) -#define AE_BAD_VALUE EXCEP_TBL (0x0004) -#define AE_INVALID_TABLE_LENGTH EXCEP_TBL (0x0005) - -#define AE_CODE_TBL_MAX 0x0005 - -/* - * AML exceptions. These are caused by problems with - * the actual AML byte stream - */ -#define AE_AML_BAD_OPCODE EXCEP_AML (0x0001) -#define AE_AML_NO_OPERAND EXCEP_AML (0x0002) -#define AE_AML_OPERAND_TYPE EXCEP_AML (0x0003) -#define AE_AML_OPERAND_VALUE EXCEP_AML (0x0004) -#define AE_AML_UNINITIALIZED_LOCAL EXCEP_AML (0x0005) -#define AE_AML_UNINITIALIZED_ARG EXCEP_AML (0x0006) -#define AE_AML_UNINITIALIZED_ELEMENT EXCEP_AML (0x0007) -#define AE_AML_NUMERIC_OVERFLOW EXCEP_AML (0x0008) -#define AE_AML_REGION_LIMIT EXCEP_AML (0x0009) -#define AE_AML_BUFFER_LIMIT EXCEP_AML (0x000A) -#define AE_AML_PACKAGE_LIMIT EXCEP_AML (0x000B) -#define AE_AML_DIVIDE_BY_ZERO EXCEP_AML (0x000C) -#define AE_AML_BAD_NAME EXCEP_AML (0x000D) -#define AE_AML_NAME_NOT_FOUND EXCEP_AML (0x000E) -#define AE_AML_INTERNAL EXCEP_AML (0x000F) -#define AE_AML_INVALID_SPACE_ID EXCEP_AML (0x0010) -#define AE_AML_STRING_LIMIT EXCEP_AML (0x0011) -#define AE_AML_NO_RETURN_VALUE EXCEP_AML (0x0012) -#define AE_AML_METHOD_LIMIT EXCEP_AML (0x0013) -#define AE_AML_NOT_OWNER EXCEP_AML (0x0014) -#define AE_AML_MUTEX_ORDER EXCEP_AML (0x0015) -#define AE_AML_MUTEX_NOT_ACQUIRED EXCEP_AML (0x0016) -#define AE_AML_INVALID_RESOURCE_TYPE EXCEP_AML (0x0017) -#define AE_AML_INVALID_INDEX EXCEP_AML (0x0018) -#define AE_AML_REGISTER_LIMIT EXCEP_AML (0x0019) -#define AE_AML_NO_WHILE EXCEP_AML (0x001A) -#define AE_AML_ALIGNMENT EXCEP_AML (0x001B) -#define AE_AML_NO_RESOURCE_END_TAG EXCEP_AML (0x001C) -#define AE_AML_BAD_RESOURCE_VALUE EXCEP_AML (0x001D) -#define AE_AML_CIRCULAR_REFERENCE EXCEP_AML (0x001E) -#define AE_AML_BAD_RESOURCE_LENGTH EXCEP_AML (0x001F) -#define AE_AML_ILLEGAL_ADDRESS EXCEP_AML (0x0020) -#define AE_AML_INFINITE_LOOP EXCEP_AML (0x0021) -#define AE_AML_UNINITIALIZED_NODE EXCEP_AML (0x0022) -#define AE_AML_TARGET_TYPE EXCEP_AML (0x0023) - -#define AE_CODE_AML_MAX 0x0023 - -/* - * Internal exceptions used for control - */ -#define AE_CTRL_RETURN_VALUE EXCEP_CTL (0x0001) -#define AE_CTRL_PENDING EXCEP_CTL (0x0002) -#define AE_CTRL_TERMINATE EXCEP_CTL (0x0003) -#define AE_CTRL_TRUE EXCEP_CTL (0x0004) -#define AE_CTRL_FALSE EXCEP_CTL (0x0005) -#define AE_CTRL_DEPTH EXCEP_CTL (0x0006) -#define AE_CTRL_END EXCEP_CTL (0x0007) -#define AE_CTRL_TRANSFER EXCEP_CTL (0x0008) -#define AE_CTRL_BREAK EXCEP_CTL (0x0009) -#define AE_CTRL_CONTINUE EXCEP_CTL (0x000A) -#define AE_CTRL_SKIP EXCEP_CTL (0x000B) -#define AE_CTRL_PARSE_CONTINUE EXCEP_CTL (0x000C) -#define AE_CTRL_PARSE_PENDING EXCEP_CTL (0x000D) - -#define AE_CODE_CTRL_MAX 0x000D - -/* Exception strings for acpi_format_exception */ - -#ifdef ACPI_DEFINE_EXCEPTION_TABLE - -/* - * String versions of the exception codes above - * These strings must match the corresponding defines exactly - */ -static const struct acpi_exception_info acpi_gbl_exception_names_env[] = { - EXCEP_TXT("AE_OK", "No error"), - EXCEP_TXT("AE_ERROR", "Unspecified error"), - EXCEP_TXT("AE_NO_ACPI_TABLES", "ACPI tables could not be found"), - EXCEP_TXT("AE_NO_NAMESPACE", "A namespace has not been loaded"), - EXCEP_TXT("AE_NO_MEMORY", "Insufficient dynamic memory"), - EXCEP_TXT("AE_NOT_FOUND", "A requested entity is not found"), - EXCEP_TXT("AE_NOT_EXIST", "A required entity does not exist"), - EXCEP_TXT("AE_ALREADY_EXISTS", "An entity already exists"), - EXCEP_TXT("AE_TYPE", "The object type is incorrect"), - EXCEP_TXT("AE_NULL_OBJECT", "A required object was missing"), - EXCEP_TXT("AE_NULL_ENTRY", "The requested object does not exist"), - EXCEP_TXT("AE_BUFFER_OVERFLOW", "The buffer provided is too small"), - EXCEP_TXT("AE_STACK_OVERFLOW", "An internal stack overflowed"), - EXCEP_TXT("AE_STACK_UNDERFLOW", "An internal stack underflowed"), - EXCEP_TXT("AE_NOT_IMPLEMENTED", "The feature is not implemented"), - EXCEP_TXT("AE_SUPPORT", "The feature is not supported"), - EXCEP_TXT("AE_LIMIT", "A predefined limit was exceeded"), - EXCEP_TXT("AE_TIME", "A time limit or timeout expired"), - EXCEP_TXT("AE_ACQUIRE_DEADLOCK", - "Internal error, attempt was made to acquire a mutex in improper order"), - EXCEP_TXT("AE_RELEASE_DEADLOCK", - "Internal error, attempt was made to release a mutex in improper order"), - EXCEP_TXT("AE_NOT_ACQUIRED", - "An attempt to release a mutex or Global Lock without a previous acquire"), - EXCEP_TXT("AE_ALREADY_ACQUIRED", - "Internal error, attempt was made to acquire a mutex twice"), - EXCEP_TXT("AE_NO_HARDWARE_RESPONSE", - "Hardware did not respond after an I/O operation"), - EXCEP_TXT("AE_NO_GLOBAL_LOCK", "There is no FACS Global Lock"), - EXCEP_TXT("AE_ABORT_METHOD", "A control method was aborted"), - EXCEP_TXT("AE_SAME_HANDLER", - "Attempt was made to install the same handler that is already installed"), - EXCEP_TXT("AE_NO_HANDLER", - "A handler for the operation is not installed"), - EXCEP_TXT("AE_OWNER_ID_LIMIT", - "There are no more Owner IDs available for ACPI tables or control methods"), - EXCEP_TXT("AE_NOT_CONFIGURED", - "The interface is not part of the current subsystem configuration"), - EXCEP_TXT("AE_ACCESS", "Permission denied for the requested operation"), - EXCEP_TXT("AE_IO_ERROR", "An I/O error occurred") -}; - -static const struct acpi_exception_info acpi_gbl_exception_names_pgm[] = { - EXCEP_TXT(NULL, NULL), - EXCEP_TXT("AE_BAD_PARAMETER", "A parameter is out of range or invalid"), - EXCEP_TXT("AE_BAD_CHARACTER", - "An invalid character was found in a name"), - EXCEP_TXT("AE_BAD_PATHNAME", - "An invalid character was found in a pathname"), - EXCEP_TXT("AE_BAD_DATA", - "A package or buffer contained incorrect data"), - EXCEP_TXT("AE_BAD_HEX_CONSTANT", "Invalid character in a Hex constant"), - EXCEP_TXT("AE_BAD_OCTAL_CONSTANT", - "Invalid character in an Octal constant"), - EXCEP_TXT("AE_BAD_DECIMAL_CONSTANT", - "Invalid character in a Decimal constant"), - EXCEP_TXT("AE_MISSING_ARGUMENTS", - "Too few arguments were passed to a control method"), - EXCEP_TXT("AE_BAD_ADDRESS", "An illegal null I/O address") -}; - -static const struct acpi_exception_info acpi_gbl_exception_names_tbl[] = { - EXCEP_TXT(NULL, NULL), - EXCEP_TXT("AE_BAD_SIGNATURE", "An ACPI table has an invalid signature"), - EXCEP_TXT("AE_BAD_HEADER", "Invalid field in an ACPI table header"), - EXCEP_TXT("AE_BAD_CHECKSUM", "An ACPI table checksum is not correct"), - EXCEP_TXT("AE_BAD_VALUE", "An invalid value was found in a table"), - EXCEP_TXT("AE_INVALID_TABLE_LENGTH", - "The FADT or FACS has improper length") -}; - -static const struct acpi_exception_info acpi_gbl_exception_names_aml[] = { - EXCEP_TXT(NULL, NULL), - EXCEP_TXT("AE_AML_BAD_OPCODE", "Invalid AML opcode encountered"), - EXCEP_TXT("AE_AML_NO_OPERAND", "A required operand is missing"), - EXCEP_TXT("AE_AML_OPERAND_TYPE", - "An operand of an incorrect type was encountered"), - EXCEP_TXT("AE_AML_OPERAND_VALUE", - "The operand had an inappropriate or invalid value"), - EXCEP_TXT("AE_AML_UNINITIALIZED_LOCAL", - "Method tried to use an uninitialized local variable"), - EXCEP_TXT("AE_AML_UNINITIALIZED_ARG", - "Method tried to use an uninitialized argument"), - EXCEP_TXT("AE_AML_UNINITIALIZED_ELEMENT", - "Method tried to use an empty package element"), - EXCEP_TXT("AE_AML_NUMERIC_OVERFLOW", - "Overflow during BCD conversion or other"), - EXCEP_TXT("AE_AML_REGION_LIMIT", - "Tried to access beyond the end of an Operation Region"), - EXCEP_TXT("AE_AML_BUFFER_LIMIT", - "Tried to access beyond the end of a buffer"), - EXCEP_TXT("AE_AML_PACKAGE_LIMIT", - "Tried to access beyond the end of a package"), - EXCEP_TXT("AE_AML_DIVIDE_BY_ZERO", - "During execution of AML Divide operator"), - EXCEP_TXT("AE_AML_BAD_NAME", - "An ACPI name contains invalid character(s)"), - EXCEP_TXT("AE_AML_NAME_NOT_FOUND", - "Could not resolve a named reference"), - EXCEP_TXT("AE_AML_INTERNAL", "An internal error within the interprete"), - EXCEP_TXT("AE_AML_INVALID_SPACE_ID", - "An Operation Region SpaceID is invalid"), - EXCEP_TXT("AE_AML_STRING_LIMIT", - "String is longer than 200 characters"), - EXCEP_TXT("AE_AML_NO_RETURN_VALUE", - "A method did not return a required value"), - EXCEP_TXT("AE_AML_METHOD_LIMIT", - "A control method reached the maximum reentrancy limit of 255"), - EXCEP_TXT("AE_AML_NOT_OWNER", - "A thread tried to release a mutex that it does not own"), - EXCEP_TXT("AE_AML_MUTEX_ORDER", "Mutex SyncLevel release mismatch"), - EXCEP_TXT("AE_AML_MUTEX_NOT_ACQUIRED", - "Attempt to release a mutex that was not previously acquired"), - EXCEP_TXT("AE_AML_INVALID_RESOURCE_TYPE", - "Invalid resource type in resource list"), - EXCEP_TXT("AE_AML_INVALID_INDEX", - "Invalid Argx or Localx (x too large)"), - EXCEP_TXT("AE_AML_REGISTER_LIMIT", - "Bank value or Index value beyond range of register"), - EXCEP_TXT("AE_AML_NO_WHILE", "Break or Continue without a While"), - EXCEP_TXT("AE_AML_ALIGNMENT", - "Non-aligned memory transfer on platform that does not support this"), - EXCEP_TXT("AE_AML_NO_RESOURCE_END_TAG", - "No End Tag in a resource list"), - EXCEP_TXT("AE_AML_BAD_RESOURCE_VALUE", - "Invalid value of a resource element"), - EXCEP_TXT("AE_AML_CIRCULAR_REFERENCE", - "Two references refer to each other"), - EXCEP_TXT("AE_AML_BAD_RESOURCE_LENGTH", - "The length of a Resource Descriptor in the AML is incorrect"), - EXCEP_TXT("AE_AML_ILLEGAL_ADDRESS", - "A memory, I/O, or PCI configuration address is invalid"), - EXCEP_TXT("AE_AML_INFINITE_LOOP", - "An apparent infinite AML While loop, method was aborted"), - EXCEP_TXT("AE_AML_UNINITIALIZED_NODE", - "A namespace node is uninitialized or unresolved"), - EXCEP_TXT("AE_AML_TARGET_TYPE", - "A target operand of an incorrect type was encountered") -}; - -static const struct acpi_exception_info acpi_gbl_exception_names_ctrl[] = { - EXCEP_TXT(NULL, NULL), - EXCEP_TXT("AE_CTRL_RETURN_VALUE", "A Method returned a value"), - EXCEP_TXT("AE_CTRL_PENDING", "Method is calling another method"), - EXCEP_TXT("AE_CTRL_TERMINATE", "Terminate the executing method"), - EXCEP_TXT("AE_CTRL_TRUE", "An If or While predicate result"), - EXCEP_TXT("AE_CTRL_FALSE", "An If or While predicate result"), - EXCEP_TXT("AE_CTRL_DEPTH", "Maximum search depth has been reached"), - EXCEP_TXT("AE_CTRL_END", "An If or While predicate is false"), - EXCEP_TXT("AE_CTRL_TRANSFER", "Transfer control to called method"), - EXCEP_TXT("AE_CTRL_BREAK", "A Break has been executed"), - EXCEP_TXT("AE_CTRL_CONTINUE", "A Continue has been executed"), - EXCEP_TXT("AE_CTRL_SKIP", "Not currently used"), - EXCEP_TXT("AE_CTRL_PARSE_CONTINUE", "Used to skip over bad opcodes"), - EXCEP_TXT("AE_CTRL_PARSE_PENDING", "Used to implement AML While loops") -}; - -#endif /* EXCEPTION_TABLE */ - -#endif /* __ACEXCEP_H__ */ diff --git a/src/linux/include/acpi/acnames.h b/src/linux/include/acpi/acnames.h deleted file mode 100644 index be779db..0000000 --- a/src/linux/include/acpi/acnames.h +++ /dev/null @@ -1,92 +0,0 @@ -/****************************************************************************** - * - * Name: acnames.h - Global names and strings - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACNAMES_H__ -#define __ACNAMES_H__ - -/* Method names - these methods can appear anywhere in the namespace */ - -#define METHOD_NAME__ADR "_ADR" -#define METHOD_NAME__AEI "_AEI" -#define METHOD_NAME__BBN "_BBN" -#define METHOD_NAME__CBA "_CBA" -#define METHOD_NAME__CID "_CID" -#define METHOD_NAME__CLS "_CLS" -#define METHOD_NAME__CRS "_CRS" -#define METHOD_NAME__DDN "_DDN" -#define METHOD_NAME__HID "_HID" -#define METHOD_NAME__INI "_INI" -#define METHOD_NAME__PLD "_PLD" -#define METHOD_NAME__DSD "_DSD" -#define METHOD_NAME__PRS "_PRS" -#define METHOD_NAME__PRT "_PRT" -#define METHOD_NAME__PRW "_PRW" -#define METHOD_NAME__PS0 "_PS0" -#define METHOD_NAME__PS1 "_PS1" -#define METHOD_NAME__PS2 "_PS2" -#define METHOD_NAME__PS3 "_PS3" -#define METHOD_NAME__REG "_REG" -#define METHOD_NAME__SB_ "_SB_" -#define METHOD_NAME__SEG "_SEG" -#define METHOD_NAME__SRS "_SRS" -#define METHOD_NAME__STA "_STA" -#define METHOD_NAME__SUB "_SUB" -#define METHOD_NAME__UID "_UID" - -/* Method names - these methods must appear at the namespace root */ - -#define METHOD_PATHNAME__PTS "\\_PTS" -#define METHOD_PATHNAME__SST "\\_SI._SST" -#define METHOD_PATHNAME__WAK "\\_WAK" - -/* Definitions of the predefined namespace names */ - -#define ACPI_UNKNOWN_NAME (u32) 0x3F3F3F3F /* Unknown name is "????" */ -#define ACPI_ROOT_NAME (u32) 0x5F5F5F5C /* Root name is "\___" */ - -#define ACPI_PREFIX_MIXED (u32) 0x69706341 /* "Acpi" */ -#define ACPI_PREFIX_LOWER (u32) 0x69706361 /* "acpi" */ - -#define ACPI_NS_ROOT_PATH "\\" - -#endif /* __ACNAMES_H__ */ diff --git a/src/linux/include/acpi/acoutput.h b/src/linux/include/acpi/acoutput.h deleted file mode 100644 index 48eb4dd..0000000 --- a/src/linux/include/acpi/acoutput.h +++ /dev/null @@ -1,491 +0,0 @@ -/****************************************************************************** - * - * Name: acoutput.h -- debug output - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACOUTPUT_H__ -#define __ACOUTPUT_H__ - -/* - * Debug levels and component IDs. These are used to control the - * granularity of the output of the ACPI_DEBUG_PRINT macro -- on a - * per-component basis and a per-exception-type basis. - */ - -/* Component IDs are used in the global "DebugLayer" */ - -#define ACPI_UTILITIES 0x00000001 -#define ACPI_HARDWARE 0x00000002 -#define ACPI_EVENTS 0x00000004 -#define ACPI_TABLES 0x00000008 -#define ACPI_NAMESPACE 0x00000010 -#define ACPI_PARSER 0x00000020 -#define ACPI_DISPATCHER 0x00000040 -#define ACPI_EXECUTER 0x00000080 -#define ACPI_RESOURCES 0x00000100 -#define ACPI_CA_DEBUGGER 0x00000200 -#define ACPI_OS_SERVICES 0x00000400 -#define ACPI_CA_DISASSEMBLER 0x00000800 - -/* Component IDs for ACPI tools and utilities */ - -#define ACPI_COMPILER 0x00001000 -#define ACPI_TOOLS 0x00002000 -#define ACPI_EXAMPLE 0x00004000 -#define ACPI_DRIVER 0x00008000 -#define DT_COMPILER 0x00010000 -#define ASL_PREPROCESSOR 0x00020000 - -#define ACPI_ALL_COMPONENTS 0x0001FFFF -#define ACPI_COMPONENT_DEFAULT (ACPI_ALL_COMPONENTS) - -/* Component IDs reserved for ACPI drivers */ - -#define ACPI_ALL_DRIVERS 0xFFFF0000 - -/* - * Raw debug output levels, do not use these in the ACPI_DEBUG_PRINT macros - */ -#define ACPI_LV_INIT 0x00000001 -#define ACPI_LV_DEBUG_OBJECT 0x00000002 -#define ACPI_LV_INFO 0x00000004 -#define ACPI_LV_REPAIR 0x00000008 -#define ACPI_LV_TRACE_POINT 0x00000010 -#define ACPI_LV_ALL_EXCEPTIONS 0x0000001F - -/* Trace verbosity level 1 [Standard Trace Level] */ - -#define ACPI_LV_INIT_NAMES 0x00000020 -#define ACPI_LV_PARSE 0x00000040 -#define ACPI_LV_LOAD 0x00000080 -#define ACPI_LV_DISPATCH 0x00000100 -#define ACPI_LV_EXEC 0x00000200 -#define ACPI_LV_NAMES 0x00000400 -#define ACPI_LV_OPREGION 0x00000800 -#define ACPI_LV_BFIELD 0x00001000 -#define ACPI_LV_TABLES 0x00002000 -#define ACPI_LV_VALUES 0x00004000 -#define ACPI_LV_OBJECTS 0x00008000 -#define ACPI_LV_RESOURCES 0x00010000 -#define ACPI_LV_USER_REQUESTS 0x00020000 -#define ACPI_LV_PACKAGE 0x00040000 -#define ACPI_LV_VERBOSITY1 0x0007FF40 | ACPI_LV_ALL_EXCEPTIONS - -/* Trace verbosity level 2 [Function tracing and memory allocation] */ - -#define ACPI_LV_ALLOCATIONS 0x00100000 -#define ACPI_LV_FUNCTIONS 0x00200000 -#define ACPI_LV_OPTIMIZATIONS 0x00400000 -#define ACPI_LV_VERBOSITY2 0x00700000 | ACPI_LV_VERBOSITY1 -#define ACPI_LV_ALL ACPI_LV_VERBOSITY2 - -/* Trace verbosity level 3 [Threading, I/O, and Interrupts] */ - -#define ACPI_LV_MUTEX 0x01000000 -#define ACPI_LV_THREADS 0x02000000 -#define ACPI_LV_IO 0x04000000 -#define ACPI_LV_INTERRUPTS 0x08000000 -#define ACPI_LV_VERBOSITY3 0x0F000000 | ACPI_LV_VERBOSITY2 - -/* Exceptionally verbose output -- also used in the global "DebugLevel" */ - -#define ACPI_LV_AML_DISASSEMBLE 0x10000000 -#define ACPI_LV_VERBOSE_INFO 0x20000000 -#define ACPI_LV_FULL_TABLES 0x40000000 -#define ACPI_LV_EVENTS 0x80000000 -#define ACPI_LV_VERBOSE 0xF0000000 - -/* - * Debug level macros that are used in the DEBUG_PRINT macros - */ -#define ACPI_DEBUG_LEVEL(dl) (u32) dl,ACPI_DEBUG_PARAMETERS - -/* - * Exception level -- used in the global "DebugLevel" - * - * Note: For errors, use the ACPI_ERROR or ACPI_EXCEPTION interfaces. - * For warnings, use ACPI_WARNING. - */ -#define ACPI_DB_INIT ACPI_DEBUG_LEVEL (ACPI_LV_INIT) -#define ACPI_DB_DEBUG_OBJECT ACPI_DEBUG_LEVEL (ACPI_LV_DEBUG_OBJECT) -#define ACPI_DB_INFO ACPI_DEBUG_LEVEL (ACPI_LV_INFO) -#define ACPI_DB_REPAIR ACPI_DEBUG_LEVEL (ACPI_LV_REPAIR) -#define ACPI_DB_TRACE_POINT ACPI_DEBUG_LEVEL (ACPI_LV_TRACE_POINT) -#define ACPI_DB_ALL_EXCEPTIONS ACPI_DEBUG_LEVEL (ACPI_LV_ALL_EXCEPTIONS) - -/* Trace level -- also used in the global "DebugLevel" */ - -#define ACPI_DB_INIT_NAMES ACPI_DEBUG_LEVEL (ACPI_LV_INIT_NAMES) -#define ACPI_DB_THREADS ACPI_DEBUG_LEVEL (ACPI_LV_THREADS) -#define ACPI_DB_PARSE ACPI_DEBUG_LEVEL (ACPI_LV_PARSE) -#define ACPI_DB_DISPATCH ACPI_DEBUG_LEVEL (ACPI_LV_DISPATCH) -#define ACPI_DB_LOAD ACPI_DEBUG_LEVEL (ACPI_LV_LOAD) -#define ACPI_DB_EXEC ACPI_DEBUG_LEVEL (ACPI_LV_EXEC) -#define ACPI_DB_NAMES ACPI_DEBUG_LEVEL (ACPI_LV_NAMES) -#define ACPI_DB_OPREGION ACPI_DEBUG_LEVEL (ACPI_LV_OPREGION) -#define ACPI_DB_BFIELD ACPI_DEBUG_LEVEL (ACPI_LV_BFIELD) -#define ACPI_DB_TABLES ACPI_DEBUG_LEVEL (ACPI_LV_TABLES) -#define ACPI_DB_FUNCTIONS ACPI_DEBUG_LEVEL (ACPI_LV_FUNCTIONS) -#define ACPI_DB_OPTIMIZATIONS ACPI_DEBUG_LEVEL (ACPI_LV_OPTIMIZATIONS) -#define ACPI_DB_VALUES ACPI_DEBUG_LEVEL (ACPI_LV_VALUES) -#define ACPI_DB_OBJECTS ACPI_DEBUG_LEVEL (ACPI_LV_OBJECTS) -#define ACPI_DB_ALLOCATIONS ACPI_DEBUG_LEVEL (ACPI_LV_ALLOCATIONS) -#define ACPI_DB_RESOURCES ACPI_DEBUG_LEVEL (ACPI_LV_RESOURCES) -#define ACPI_DB_IO ACPI_DEBUG_LEVEL (ACPI_LV_IO) -#define ACPI_DB_INTERRUPTS ACPI_DEBUG_LEVEL (ACPI_LV_INTERRUPTS) -#define ACPI_DB_USER_REQUESTS ACPI_DEBUG_LEVEL (ACPI_LV_USER_REQUESTS) -#define ACPI_DB_PACKAGE ACPI_DEBUG_LEVEL (ACPI_LV_PACKAGE) -#define ACPI_DB_MUTEX ACPI_DEBUG_LEVEL (ACPI_LV_MUTEX) -#define ACPI_DB_EVENTS ACPI_DEBUG_LEVEL (ACPI_LV_EVENTS) - -#define ACPI_DB_ALL ACPI_DEBUG_LEVEL (ACPI_LV_ALL) - -/* Defaults for debug_level, debug and normal */ - -#define ACPI_DEBUG_DEFAULT (ACPI_LV_INFO | ACPI_LV_REPAIR) -#define ACPI_NORMAL_DEFAULT (ACPI_LV_INIT | ACPI_LV_DEBUG_OBJECT | ACPI_LV_REPAIR) -#define ACPI_DEBUG_ALL (ACPI_LV_AML_DISASSEMBLE | ACPI_LV_ALL_EXCEPTIONS | ACPI_LV_ALL) - -/* - * Global trace flags - */ -#define ACPI_TRACE_ENABLED ((u32) 4) -#define ACPI_TRACE_ONESHOT ((u32) 2) -#define ACPI_TRACE_OPCODE ((u32) 1) - -/* Defaults for trace debugging level/layer */ - -#define ACPI_TRACE_LEVEL_ALL ACPI_LV_ALL -#define ACPI_TRACE_LAYER_ALL 0x000001FF -#define ACPI_TRACE_LEVEL_DEFAULT ACPI_LV_TRACE_POINT -#define ACPI_TRACE_LAYER_DEFAULT ACPI_EXECUTER - -#if defined (ACPI_DEBUG_OUTPUT) || !defined (ACPI_NO_ERROR_MESSAGES) -/* - * The module name is used primarily for error and debug messages. - * The __FILE__ macro is not very useful for this, because it - * usually includes the entire pathname to the module making the - * debug output difficult to read. - */ -#define ACPI_MODULE_NAME(name) static const char ACPI_UNUSED_VAR _acpi_module_name[] = name; -#else -/* - * For the no-debug and no-error-msg cases, we must at least define - * a null module name. - */ -#define ACPI_MODULE_NAME(name) -#define _acpi_module_name "" -#endif - -/* - * Ascii error messages can be configured out - */ -#ifndef ACPI_NO_ERROR_MESSAGES -#define AE_INFO _acpi_module_name, __LINE__ - -/* - * Error reporting. Callers module and line number are inserted by AE_INFO, - * the plist contains a set of parens to allow variable-length lists. - * These macros are used for both the debug and non-debug versions of the code. - */ -#define ACPI_INFO(plist) acpi_info plist -#define ACPI_WARNING(plist) acpi_warning plist -#define ACPI_EXCEPTION(plist) acpi_exception plist -#define ACPI_ERROR(plist) acpi_error plist -#define ACPI_BIOS_WARNING(plist) acpi_bios_warning plist -#define ACPI_BIOS_ERROR(plist) acpi_bios_error plist -#define ACPI_DEBUG_OBJECT(obj,l,i) acpi_ex_do_debug_object(obj,l,i) - -#else - -/* No error messages */ - -#define ACPI_INFO(plist) -#define ACPI_WARNING(plist) -#define ACPI_EXCEPTION(plist) -#define ACPI_ERROR(plist) -#define ACPI_BIOS_WARNING(plist) -#define ACPI_BIOS_ERROR(plist) -#define ACPI_DEBUG_OBJECT(obj,l,i) - -#endif /* ACPI_NO_ERROR_MESSAGES */ - -/* - * Debug macros that are conditionally compiled - */ -#ifdef ACPI_DEBUG_OUTPUT - -/* - * If ACPI_GET_FUNCTION_NAME was not defined in the compiler-dependent header, - * define it now. This is the case where there the compiler does not support - * a __func__ macro or equivalent. - */ -#ifndef ACPI_GET_FUNCTION_NAME -#define ACPI_GET_FUNCTION_NAME _acpi_function_name - -/* - * The Name parameter should be the procedure name as a non-quoted string. - * The function name is also used by the function exit macros below. - * Note: (const char) is used to be compatible with the debug interfaces - * and macros such as __func__. - */ -#define ACPI_FUNCTION_NAME(name) static const char _acpi_function_name[] = #name; - -#else -/* Compiler supports __func__ (or equivalent) -- Ignore this macro */ - -#define ACPI_FUNCTION_NAME(name) -#endif /* ACPI_GET_FUNCTION_NAME */ - -/* - * Common parameters used for debug output functions: - * line number, function name, module(file) name, component ID - */ -#define ACPI_DEBUG_PARAMETERS \ - __LINE__, ACPI_GET_FUNCTION_NAME, _acpi_module_name, _COMPONENT - -/* Check if debug output is currently dynamically enabled */ - -#define ACPI_IS_DEBUG_ENABLED(level, component) \ - ((level & acpi_dbg_level) && (component & acpi_dbg_layer)) - -/* - * Master debug print macros - * Print message if and only if: - * 1) Debug print for the current component is enabled - * 2) Debug error level or trace level for the print statement is enabled - * - * November 2012: Moved the runtime check for whether to actually emit the - * debug message outside of the print function itself. This improves overall - * performance at a relatively small code cost. Implementation involves the - * use of variadic macros supported by C99. - * - * Note: the ACPI_DO_WHILE0 macro is used to prevent some compilers from - * complaining about these constructs. On other compilers the do...while - * adds some extra code, so this feature is optional. - */ -#ifdef ACPI_USE_DO_WHILE_0 -#define ACPI_DO_WHILE0(a) do a while(0) -#else -#define ACPI_DO_WHILE0(a) a -#endif - -/* DEBUG_PRINT functions */ - -#ifndef COMPILER_VA_MACRO - -#define ACPI_DEBUG_PRINT(plist) acpi_debug_print plist -#define ACPI_DEBUG_PRINT_RAW(plist) acpi_debug_print_raw plist - -#else - -/* Helper macros for DEBUG_PRINT */ - -#define ACPI_DO_DEBUG_PRINT(function, level, line, filename, modulename, component, ...) \ - ACPI_DO_WHILE0 ({ \ - if (ACPI_IS_DEBUG_ENABLED (level, component)) \ - { \ - function (level, line, filename, modulename, component, __VA_ARGS__); \ - } \ - }) - -#define ACPI_ACTUAL_DEBUG(level, line, filename, modulename, component, ...) \ - ACPI_DO_DEBUG_PRINT (acpi_debug_print, level, line, \ - filename, modulename, component, __VA_ARGS__) - -#define ACPI_ACTUAL_DEBUG_RAW(level, line, filename, modulename, component, ...) \ - ACPI_DO_DEBUG_PRINT (acpi_debug_print_raw, level, line, \ - filename, modulename, component, __VA_ARGS__) - -#define ACPI_DEBUG_PRINT(plist) ACPI_ACTUAL_DEBUG plist -#define ACPI_DEBUG_PRINT_RAW(plist) ACPI_ACTUAL_DEBUG_RAW plist - -#endif - -/* - * Function entry tracing - * - * The name of the function is emitted as a local variable that is - * intended to be used by both the entry trace and the exit trace. - */ - -/* Helper macro */ - -#define ACPI_TRACE_ENTRY(name, function, type, param) \ - ACPI_FUNCTION_NAME (name) \ - function (ACPI_DEBUG_PARAMETERS, (type) (param)) - -/* The actual entry trace macros */ - -#define ACPI_FUNCTION_TRACE(name) \ - ACPI_FUNCTION_NAME(name) \ - acpi_ut_trace (ACPI_DEBUG_PARAMETERS) - -#define ACPI_FUNCTION_TRACE_PTR(name, pointer) \ - ACPI_TRACE_ENTRY (name, acpi_ut_trace_ptr, void *, pointer) - -#define ACPI_FUNCTION_TRACE_U32(name, value) \ - ACPI_TRACE_ENTRY (name, acpi_ut_trace_u32, u32, value) - -#define ACPI_FUNCTION_TRACE_STR(name, string) \ - ACPI_TRACE_ENTRY (name, acpi_ut_trace_str, const char *, string) - -#define ACPI_FUNCTION_ENTRY() \ - acpi_ut_track_stack_ptr() - -/* - * Function exit tracing - * - * These macros include a return statement. This is usually considered - * bad form, but having a separate exit macro before the actual return - * is very ugly and difficult to maintain. - * - * One of the FUNCTION_TRACE macros above must be used in conjunction - * with these macros so that "_AcpiFunctionName" is defined. - * - * There are two versions of most of the return macros. The default version is - * safer, since it avoids side-effects by guaranteeing that the argument will - * not be evaluated twice. - * - * A less-safe version of the macros is provided for optional use if the - * compiler uses excessive CPU stack (for example, this may happen in the - * debug case if code optimzation is disabled.) - */ - -/* Exit trace helper macro */ - -#ifndef ACPI_SIMPLE_RETURN_MACROS - -#define ACPI_TRACE_EXIT(function, type, param) \ - ACPI_DO_WHILE0 ({ \ - register type _param = (type) (param); \ - function (ACPI_DEBUG_PARAMETERS, _param); \ - return (_param); \ - }) - -#else /* Use original less-safe macros */ - -#define ACPI_TRACE_EXIT(function, type, param) \ - ACPI_DO_WHILE0 ({ \ - function (ACPI_DEBUG_PARAMETERS, (type) (param)); \ - return (param); \ - }) - -#endif /* ACPI_SIMPLE_RETURN_MACROS */ - -/* The actual exit macros */ - -#define return_VOID \ - ACPI_DO_WHILE0 ({ \ - acpi_ut_exit (ACPI_DEBUG_PARAMETERS); \ - return; \ - }) - -#define return_ACPI_STATUS(status) \ - ACPI_TRACE_EXIT (acpi_ut_status_exit, acpi_status, status) - -#define return_PTR(pointer) \ - ACPI_TRACE_EXIT (acpi_ut_ptr_exit, void *, pointer) - -#define return_STR(string) \ - ACPI_TRACE_EXIT (acpi_ut_str_exit, const char *, string) - -#define return_VALUE(value) \ - ACPI_TRACE_EXIT (acpi_ut_value_exit, u64, value) - -#define return_UINT32(value) \ - ACPI_TRACE_EXIT (acpi_ut_value_exit, u32, value) - -#define return_UINT8(value) \ - ACPI_TRACE_EXIT (acpi_ut_value_exit, u8, value) - -/* Conditional execution */ - -#define ACPI_DEBUG_EXEC(a) a -#define ACPI_DEBUG_ONLY_MEMBERS(a) a; -#define _VERBOSE_STRUCTURES - -/* Various object display routines for debug */ - -#define ACPI_DUMP_STACK_ENTRY(a) acpi_ex_dump_operand((a), 0) -#define ACPI_DUMP_OPERANDS(a, b ,c) acpi_ex_dump_operands(a, b, c) -#define ACPI_DUMP_ENTRY(a, b) acpi_ns_dump_entry (a, b) -#define ACPI_DUMP_PATHNAME(a, b, c, d) acpi_ns_dump_pathname(a, b, c, d) -#define ACPI_DUMP_BUFFER(a, b) acpi_ut_debug_dump_buffer((u8 *) a, b, DB_BYTE_DISPLAY, _COMPONENT) - -#define ACPI_TRACE_POINT(a, b, c, d) acpi_trace_point (a, b, c, d) - -#else /* ACPI_DEBUG_OUTPUT */ -/* - * This is the non-debug case -- make everything go away, - * leaving no executable debug code! - */ -#define ACPI_DEBUG_PRINT(pl) -#define ACPI_DEBUG_PRINT_RAW(pl) -#define ACPI_DEBUG_EXEC(a) -#define ACPI_DEBUG_ONLY_MEMBERS(a) -#define ACPI_FUNCTION_NAME(a) -#define ACPI_FUNCTION_TRACE(a) -#define ACPI_FUNCTION_TRACE_PTR(a, b) -#define ACPI_FUNCTION_TRACE_U32(a, b) -#define ACPI_FUNCTION_TRACE_STR(a, b) -#define ACPI_FUNCTION_ENTRY() -#define ACPI_DUMP_STACK_ENTRY(a) -#define ACPI_DUMP_OPERANDS(a, b, c) -#define ACPI_DUMP_ENTRY(a, b) -#define ACPI_DUMP_PATHNAME(a, b, c, d) -#define ACPI_DUMP_BUFFER(a, b) -#define ACPI_IS_DEBUG_ENABLED(level, component) 0 -#define ACPI_TRACE_POINT(a, b, c, d) - -/* Return macros must have a return statement at the minimum */ - -#define return_VOID return -#define return_ACPI_STATUS(s) return(s) -#define return_PTR(s) return(s) -#define return_STR(s) return(s) -#define return_VALUE(s) return(s) -#define return_UINT8(s) return(s) -#define return_UINT32(s) return(s) - -#endif /* ACPI_DEBUG_OUTPUT */ - -#endif /* __ACOUTPUT_H__ */ diff --git a/src/linux/include/acpi/acpi.h b/src/linux/include/acpi/acpi.h deleted file mode 100644 index 82803ae..0000000 --- a/src/linux/include/acpi/acpi.h +++ /dev/null @@ -1,67 +0,0 @@ -/****************************************************************************** - * - * Name: acpi.h - Master public include file used to interface to ACPICA - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACPI_H__ -#define __ACPI_H__ - -/* - * Public include files for use by code that will interface to ACPICA. - * - * Information includes the ACPICA data types, names, exceptions, and - * external interface prototypes. Also included are the definitions for - * all ACPI tables (FADT, MADT, etc.) - * - * Note: The order of these include files is important. - */ -#include /* Environment-specific items */ -#include /* Common ACPI names and strings */ -#include /* ACPICA data types and structures */ -#include /* ACPICA exceptions */ -#include /* ACPI table definitions */ -#include /* Error output and Debug macros */ -#include /* Resource Descriptor structs */ -#include /* OSL interfaces (ACPICA-to-OS) */ -#include /* ACPI core subsystem external interfaces */ -#include /* Extra environment-specific items */ - -#endif /* __ACPI_H__ */ diff --git a/src/linux/include/acpi/acpiosxf.h b/src/linux/include/acpi/acpiosxf.h deleted file mode 100644 index f3414c8..0000000 --- a/src/linux/include/acpi/acpiosxf.h +++ /dev/null @@ -1,425 +0,0 @@ -/****************************************************************************** - * - * Name: acpiosxf.h - All interfaces to the OS Services Layer (OSL). These - * interfaces must be implemented by OSL to interface the - * ACPI components to the host operating system. - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACPIOSXF_H__ -#define __ACPIOSXF_H__ - -#include -#include - -/* Types for acpi_os_execute */ - -typedef enum { - OSL_GLOBAL_LOCK_HANDLER, - OSL_NOTIFY_HANDLER, - OSL_GPE_HANDLER, - OSL_DEBUGGER_MAIN_THREAD, - OSL_DEBUGGER_EXEC_THREAD, - OSL_EC_POLL_HANDLER, - OSL_EC_BURST_HANDLER -} acpi_execute_type; - -#define ACPI_NO_UNIT_LIMIT ((u32) -1) -#define ACPI_MUTEX_SEM 1 - -/* Functions for acpi_os_signal */ - -#define ACPI_SIGNAL_FATAL 0 -#define ACPI_SIGNAL_BREAKPOINT 1 - -struct acpi_signal_fatal_info { - u32 type; - u32 code; - u32 argument; -}; - -/* - * OSL Initialization and shutdown primitives - */ -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize -acpi_status acpi_os_initialize(void); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate -acpi_status acpi_os_terminate(void); -#endif - -/* - * ACPI Table interfaces - */ -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_root_pointer -acpi_physical_address acpi_os_get_root_pointer(void); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_predefined_override -acpi_status -acpi_os_predefined_override(const struct acpi_predefined_names *init_val, - acpi_string *new_val); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_table_override -acpi_status -acpi_os_table_override(struct acpi_table_header *existing_table, - struct acpi_table_header **new_table); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_physical_table_override -acpi_status -acpi_os_physical_table_override(struct acpi_table_header *existing_table, - acpi_physical_address *new_address, - u32 *new_table_length); -#endif - -/* - * Spinlock primitives - */ -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_create_lock -acpi_status acpi_os_create_lock(acpi_spinlock * out_handle); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_delete_lock -void acpi_os_delete_lock(acpi_spinlock handle); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_acquire_lock -acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock handle); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_release_lock -void acpi_os_release_lock(acpi_spinlock handle, acpi_cpu_flags flags); -#endif - -/* - * Semaphore primitives - */ -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_create_semaphore -acpi_status -acpi_os_create_semaphore(u32 max_units, - u32 initial_units, acpi_semaphore * out_handle); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_delete_semaphore -acpi_status acpi_os_delete_semaphore(acpi_semaphore handle); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_semaphore -acpi_status -acpi_os_wait_semaphore(acpi_semaphore handle, u32 units, u16 timeout); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_signal_semaphore -acpi_status acpi_os_signal_semaphore(acpi_semaphore handle, u32 units); -#endif - -/* - * Mutex primitives. May be configured to use semaphores instead via - * ACPI_MUTEX_TYPE (see platform/acenv.h) - */ -#if (ACPI_MUTEX_TYPE != ACPI_BINARY_SEMAPHORE) - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_create_mutex -acpi_status acpi_os_create_mutex(acpi_mutex * out_handle); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_delete_mutex -void acpi_os_delete_mutex(acpi_mutex handle); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_acquire_mutex -acpi_status acpi_os_acquire_mutex(acpi_mutex handle, u16 timeout); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_release_mutex -void acpi_os_release_mutex(acpi_mutex handle); -#endif - -#endif - -/* - * Memory allocation and mapping - */ -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_allocate -void *acpi_os_allocate(acpi_size size); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_allocate_zeroed -void *acpi_os_allocate_zeroed(acpi_size size); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_free -void acpi_os_free(void *memory); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_map_memory -void *acpi_os_map_memory(acpi_physical_address where, acpi_size length); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_unmap_memory -void acpi_os_unmap_memory(void *logical_address, acpi_size size); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_physical_address -acpi_status -acpi_os_get_physical_address(void *logical_address, - acpi_physical_address *physical_address); -#endif - -/* - * Memory/Object Cache - */ -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_create_cache -acpi_status -acpi_os_create_cache(char *cache_name, - u16 object_size, - u16 max_depth, acpi_cache_t ** return_cache); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_delete_cache -acpi_status acpi_os_delete_cache(acpi_cache_t * cache); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_purge_cache -acpi_status acpi_os_purge_cache(acpi_cache_t * cache); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_acquire_object -void *acpi_os_acquire_object(acpi_cache_t * cache); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_release_object -acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object); -#endif - -/* - * Interrupt handlers - */ -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_install_interrupt_handler -acpi_status -acpi_os_install_interrupt_handler(u32 interrupt_number, - acpi_osd_handler service_routine, - void *context); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_remove_interrupt_handler -acpi_status -acpi_os_remove_interrupt_handler(u32 interrupt_number, - acpi_osd_handler service_routine); -#endif - -/* - * Threads and Scheduling - */ -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_thread_id -acpi_thread_id acpi_os_get_thread_id(void); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_execute -acpi_status -acpi_os_execute(acpi_execute_type type, - acpi_osd_exec_callback function, void *context); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_events_complete -void acpi_os_wait_events_complete(void); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_sleep -void acpi_os_sleep(u64 milliseconds); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_stall -void acpi_os_stall(u32 microseconds); -#endif - -/* - * Platform and hardware-independent I/O interfaces - */ -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_read_port -acpi_status acpi_os_read_port(acpi_io_address address, u32 *value, u32 width); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_write_port -acpi_status acpi_os_write_port(acpi_io_address address, u32 value, u32 width); -#endif - -/* - * Platform and hardware-independent physical memory interfaces - */ -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_read_memory -acpi_status -acpi_os_read_memory(acpi_physical_address address, u64 *value, u32 width); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_write_memory -acpi_status -acpi_os_write_memory(acpi_physical_address address, u64 value, u32 width); -#endif - -/* - * Platform and hardware-independent PCI configuration space access - * Note: Can't use "Register" as a parameter, changed to "Reg" -- - * certain compilers complain. - */ -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_read_pci_configuration -acpi_status -acpi_os_read_pci_configuration(struct acpi_pci_id *pci_id, - u32 reg, u64 *value, u32 width); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_write_pci_configuration -acpi_status -acpi_os_write_pci_configuration(struct acpi_pci_id *pci_id, - u32 reg, u64 value, u32 width); -#endif - -/* - * Miscellaneous - */ -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_readable -u8 acpi_os_readable(void *pointer, acpi_size length); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_writable -u8 acpi_os_writable(void *pointer, acpi_size length); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_timer -u64 acpi_os_get_timer(void); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_signal -acpi_status acpi_os_signal(u32 function, void *info); -#endif - -/* - * Debug print routines - */ -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_printf -void ACPI_INTERNAL_VAR_XFACE acpi_os_printf(const char *format, ...); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_vprintf -void acpi_os_vprintf(const char *format, va_list args); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_redirect_output -void acpi_os_redirect_output(void *destination); -#endif - -/* - * Debug IO - */ -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_line -acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_command_signals -acpi_status acpi_os_initialize_command_signals(void); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_command_signals -void acpi_os_terminate_command_signals(void); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_wait_command_ready -acpi_status acpi_os_wait_command_ready(void); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_notify_command_complete -acpi_status acpi_os_notify_command_complete(void); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_trace_point -void -acpi_os_trace_point(acpi_trace_event_type type, - u8 begin, u8 *aml, char *pathname); -#endif - -/* - * Obtain ACPI table(s) - */ -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_name -acpi_status -acpi_os_get_table_by_name(char *signature, - u32 instance, - struct acpi_table_header **table, - acpi_physical_address *address); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_index -acpi_status -acpi_os_get_table_by_index(u32 index, - struct acpi_table_header **table, - u32 *instance, acpi_physical_address *address); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_address -acpi_status -acpi_os_get_table_by_address(acpi_physical_address address, - struct acpi_table_header **table); -#endif - -/* - * Directory manipulation - */ -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_open_directory -void *acpi_os_open_directory(char *pathname, - char *wildcard_spec, char requested_file_type); -#endif - -/* requeste_file_type values */ - -#define REQUEST_FILE_ONLY 0 -#define REQUEST_DIR_ONLY 1 - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_next_filename -char *acpi_os_get_next_filename(void *dir_handle); -#endif - -#ifndef ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_close_directory -void acpi_os_close_directory(void *dir_handle); -#endif - -#endif /* __ACPIOSXF_H__ */ diff --git a/src/linux/include/acpi/acpixf.h b/src/linux/include/acpi/acpixf.h deleted file mode 100644 index c7b3a13..0000000 --- a/src/linux/include/acpi/acpixf.h +++ /dev/null @@ -1,980 +0,0 @@ -/****************************************************************************** - * - * Name: acpixf.h - External interfaces to the ACPI subsystem - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACXFACE_H__ -#define __ACXFACE_H__ - -/* Current ACPICA subsystem version in YYYYMMDD format */ - -#define ACPI_CA_VERSION 0x20160831 - -#include -#include -#include -#include - -/***************************************************************************** - * - * Macros used for ACPICA globals and configuration - * - ****************************************************************************/ - -/* - * Ensure that global variables are defined and initialized only once. - * - * The use of these macros allows for a single list of globals (here) - * in order to simplify maintenance of the code. - */ -#ifdef DEFINE_ACPI_GLOBALS -#define ACPI_GLOBAL(type,name) \ - extern type name; \ - type name - -#define ACPI_INIT_GLOBAL(type,name,value) \ - type name=value - -#else -#ifndef ACPI_GLOBAL -#define ACPI_GLOBAL(type,name) \ - extern type name -#endif - -#ifndef ACPI_INIT_GLOBAL -#define ACPI_INIT_GLOBAL(type,name,value) \ - extern type name -#endif -#endif - -/* - * These macros configure the various ACPICA interfaces. They are - * useful for generating stub inline functions for features that are - * configured out of the current kernel or ACPICA application. - */ -#ifndef ACPI_EXTERNAL_RETURN_STATUS -#define ACPI_EXTERNAL_RETURN_STATUS(prototype) \ - prototype; -#endif - -#ifndef ACPI_EXTERNAL_RETURN_OK -#define ACPI_EXTERNAL_RETURN_OK(prototype) \ - prototype; -#endif - -#ifndef ACPI_EXTERNAL_RETURN_VOID -#define ACPI_EXTERNAL_RETURN_VOID(prototype) \ - prototype; -#endif - -#ifndef ACPI_EXTERNAL_RETURN_UINT32 -#define ACPI_EXTERNAL_RETURN_UINT32(prototype) \ - prototype; -#endif - -#ifndef ACPI_EXTERNAL_RETURN_PTR -#define ACPI_EXTERNAL_RETURN_PTR(prototype) \ - prototype; -#endif - -/***************************************************************************** - * - * Public globals and runtime configuration options - * - ****************************************************************************/ - -/* - * Enable "slack mode" of the AML interpreter? Default is FALSE, and the - * interpreter strictly follows the ACPI specification. Setting to TRUE - * allows the interpreter to ignore certain errors and/or bad AML constructs. - * - * Currently, these features are enabled by this flag: - * - * 1) Allow "implicit return" of last value in a control method - * 2) Allow access beyond the end of an operation region - * 3) Allow access to uninitialized locals/args (auto-init to integer 0) - * 4) Allow ANY object type to be a source operand for the Store() operator - * 5) Allow unresolved references (invalid target name) in package objects - * 6) Enable warning messages for behavior that is not ACPI spec compliant - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_interpreter_slack, FALSE); - -/* - * Automatically serialize all methods that create named objects? Default - * is TRUE, meaning that all non_serialized methods are scanned once at - * table load time to determine those that create named objects. Methods - * that create named objects are marked Serialized in order to prevent - * possible run-time problems if they are entered by more than one thread. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_auto_serialize_methods, TRUE); - -/* - * Create the predefined _OSI method in the namespace? Default is TRUE - * because ACPICA is fully compatible with other ACPI implementations. - * Changing this will revert ACPICA (and machine ASL) to pre-OSI behavior. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_create_osi_method, TRUE); - -/* - * Optionally use default values for the ACPI register widths. Set this to - * TRUE to use the defaults, if an FADT contains incorrect widths/lengths. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_use_default_register_widths, TRUE); - -/* - * Whether or not to verify the table checksum before installation. Set - * this to TRUE to verify the table checksum before install it to the table - * manager. Note that enabling this option causes errors to happen in some - * OSPMs during early initialization stages. Default behavior is to do such - * verification. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_verify_table_checksum, TRUE); - -/* - * Optionally enable output from the AML Debug Object. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_enable_aml_debug_object, FALSE); - -/* - * Optionally copy the entire DSDT to local memory (instead of simply - * mapping it.) There are some BIOSs that corrupt or replace the original - * DSDT, creating the need for this option. Default is FALSE, do not copy - * the DSDT. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_copy_dsdt_locally, FALSE); - -/* - * Optionally ignore an XSDT if present and use the RSDT instead. - * Although the ACPI specification requires that an XSDT be used instead - * of the RSDT, the XSDT has been found to be corrupt or ill-formed on - * some machines. Default behavior is to use the XSDT if present. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_do_not_use_xsdt, FALSE); - -/* - * Optionally support group module level code. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_group_module_level_code, TRUE); - -/* - * Optionally support module level code by parsing the entire table as - * a term_list. Default is FALSE, do not execute entire table until some - * lock order issues are fixed. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_parse_table_as_term_list, FALSE); - -/* - * Optionally use 32-bit FADT addresses if and when there is a conflict - * (address mismatch) between the 32-bit and 64-bit versions of the - * address. Although ACPICA adheres to the ACPI specification which - * requires the use of the corresponding 64-bit address if it is non-zero, - * some machines have been found to have a corrupted non-zero 64-bit - * address. Default is FALSE, do not favor the 32-bit addresses. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_fadt_addresses, FALSE); - -/* - * Optionally use 32-bit FACS table addresses. - * It is reported that some platforms fail to resume from system suspending - * if 64-bit FACS table address is selected: - * https://bugzilla.kernel.org/show_bug.cgi?id=74021 - * Default is TRUE, favor the 32-bit addresses. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_use32_bit_facs_addresses, TRUE); - -/* - * Optionally truncate I/O addresses to 16 bits. Provides compatibility - * with other ACPI implementations. NOTE: During ACPICA initialization, - * this value is set to TRUE if any Windows OSI strings have been - * requested by the BIOS. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_truncate_io_addresses, FALSE); - -/* - * Disable runtime checking and repair of values returned by control methods. - * Use only if the repair is causing a problem on a particular machine. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_auto_repair, FALSE); - -/* - * Optionally do not install any SSDTs from the RSDT/XSDT during initialization. - * This can be useful for debugging ACPI problems on some machines. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_disable_ssdt_table_install, FALSE); - -/* - * Optionally enable runtime namespace override. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_runtime_namespace_override, TRUE); - -/* - * We keep track of the latest version of Windows that has been requested by - * the BIOS. ACPI 5.0. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_osi_data, 0); - -/* - * ACPI 5.0 introduces the concept of a "reduced hardware platform", meaning - * that the ACPI hardware is no longer required. A flag in the FADT indicates - * a reduced HW machine, and that flag is duplicated here for convenience. - */ -ACPI_INIT_GLOBAL(u8, acpi_gbl_reduced_hardware, FALSE); - -/* - * This mechanism is used to trace a specified AML method. The method is - * traced each time it is executed. - */ -ACPI_INIT_GLOBAL(u32, acpi_gbl_trace_flags, 0); -ACPI_INIT_GLOBAL(const char *, acpi_gbl_trace_method_name, NULL); -ACPI_INIT_GLOBAL(u32, acpi_gbl_trace_dbg_level, ACPI_TRACE_LEVEL_DEFAULT); -ACPI_INIT_GLOBAL(u32, acpi_gbl_trace_dbg_layer, ACPI_TRACE_LAYER_DEFAULT); - -/* - * Runtime configuration of debug output control masks. We want the debug - * switches statically initialized so they are already set when the debugger - * is entered. - */ -ACPI_INIT_GLOBAL(u32, acpi_dbg_level, ACPI_DEBUG_DEFAULT); -ACPI_INIT_GLOBAL(u32, acpi_dbg_layer, 0); - -/* Optionally enable timer output with Debug Object output */ - -ACPI_INIT_GLOBAL(u8, acpi_gbl_display_debug_timer, FALSE); - -/* - * Debugger command handshake globals. Host OSes need to access these - * variables to implement their own command handshake mechanism. - */ -#ifdef ACPI_DEBUGGER -ACPI_INIT_GLOBAL(u8, acpi_gbl_method_executing, FALSE); -ACPI_GLOBAL(char, acpi_gbl_db_line_buf[ACPI_DB_LINE_BUFFER_SIZE]); -#endif - -/* - * Other miscellaneous globals - */ -ACPI_GLOBAL(struct acpi_table_fadt, acpi_gbl_FADT); -ACPI_GLOBAL(u32, acpi_current_gpe_count); -ACPI_GLOBAL(u8, acpi_gbl_system_awake_and_running); - -/***************************************************************************** - * - * ACPICA public interface configuration. - * - * Interfaces that are configured out of the ACPICA build are replaced - * by inlined stubs by default. - * - ****************************************************************************/ - -/* - * Hardware-reduced prototypes (default: Not hardware reduced). - * - * All ACPICA hardware-related interfaces that use these macros will be - * configured out of the ACPICA build if the ACPI_REDUCED_HARDWARE flag - * is set to TRUE. - * - * Note: This static build option for reduced hardware is intended to - * reduce ACPICA code size if desired or necessary. However, even if this - * option is not specified, the runtime behavior of ACPICA is dependent - * on the actual FADT reduced hardware flag (HW_REDUCED_ACPI). If set, - * the flag will enable similar behavior -- ACPICA will not attempt - * to access any ACPI-relate hardware (SCI, GPEs, Fixed Events, etc.) - */ -#if (!ACPI_REDUCED_HARDWARE) -#define ACPI_HW_DEPENDENT_RETURN_STATUS(prototype) \ - ACPI_EXTERNAL_RETURN_STATUS(prototype) - -#define ACPI_HW_DEPENDENT_RETURN_OK(prototype) \ - ACPI_EXTERNAL_RETURN_OK(prototype) - -#define ACPI_HW_DEPENDENT_RETURN_VOID(prototype) \ - ACPI_EXTERNAL_RETURN_VOID(prototype) - -#else -#define ACPI_HW_DEPENDENT_RETURN_STATUS(prototype) \ - static ACPI_INLINE prototype {return(AE_NOT_CONFIGURED);} - -#define ACPI_HW_DEPENDENT_RETURN_OK(prototype) \ - static ACPI_INLINE prototype {return(AE_OK);} - -#define ACPI_HW_DEPENDENT_RETURN_VOID(prototype) \ - static ACPI_INLINE prototype {return;} - -#endif /* !ACPI_REDUCED_HARDWARE */ - -/* - * Error message prototypes (default: error messages enabled). - * - * All interfaces related to error and warning messages - * will be configured out of the ACPICA build if the - * ACPI_NO_ERROR_MESSAGE flag is defined. - */ -#ifndef ACPI_NO_ERROR_MESSAGES -#define ACPI_MSG_DEPENDENT_RETURN_VOID(prototype) \ - prototype; - -#else -#define ACPI_MSG_DEPENDENT_RETURN_VOID(prototype) \ - static ACPI_INLINE prototype {return;} - -#endif /* ACPI_NO_ERROR_MESSAGES */ - -/* - * Debugging output prototypes (default: no debug output). - * - * All interfaces related to debug output messages - * will be configured out of the ACPICA build unless the - * ACPI_DEBUG_OUTPUT flag is defined. - */ -#ifdef ACPI_DEBUG_OUTPUT -#define ACPI_DBG_DEPENDENT_RETURN_VOID(prototype) \ - prototype; - -#else -#define ACPI_DBG_DEPENDENT_RETURN_VOID(prototype) \ - static ACPI_INLINE prototype {return;} - -#endif /* ACPI_DEBUG_OUTPUT */ - -/* - * Application prototypes - * - * All interfaces used by application will be configured - * out of the ACPICA build unless the ACPI_APPLICATION - * flag is defined. - */ -#ifdef ACPI_APPLICATION -#define ACPI_APP_DEPENDENT_RETURN_VOID(prototype) \ - prototype; - -#else -#define ACPI_APP_DEPENDENT_RETURN_VOID(prototype) \ - static ACPI_INLINE prototype {return;} - -#endif /* ACPI_APPLICATION */ - -/* - * Debugger prototypes - * - * All interfaces used by debugger will be configured - * out of the ACPICA build unless the ACPI_DEBUGGER - * flag is defined. - */ -#ifdef ACPI_DEBUGGER -#define ACPI_DBR_DEPENDENT_RETURN_OK(prototype) \ - ACPI_EXTERNAL_RETURN_OK(prototype) - -#define ACPI_DBR_DEPENDENT_RETURN_VOID(prototype) \ - ACPI_EXTERNAL_RETURN_VOID(prototype) - -#else -#define ACPI_DBR_DEPENDENT_RETURN_OK(prototype) \ - static ACPI_INLINE prototype {return(AE_OK);} - -#define ACPI_DBR_DEPENDENT_RETURN_VOID(prototype) \ - static ACPI_INLINE prototype {return;} - -#endif /* ACPI_DEBUGGER */ - -/***************************************************************************** - * - * ACPICA public interface prototypes - * - ****************************************************************************/ - -/* - * Initialization - */ -ACPI_EXTERNAL_RETURN_STATUS(acpi_status ACPI_INIT_FUNCTION - acpi_initialize_tables(struct acpi_table_desc - *initial_storage, - u32 initial_table_count, - u8 allow_resize)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status ACPI_INIT_FUNCTION - acpi_initialize_subsystem(void)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status ACPI_INIT_FUNCTION - acpi_enable_subsystem(u32 flags)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status ACPI_INIT_FUNCTION - acpi_initialize_objects(u32 flags)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status ACPI_INIT_FUNCTION - acpi_terminate(void)) - -/* - * Miscellaneous global interfaces - */ -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable(void)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable(void)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_subsystem_status(void)) - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_system_info(struct acpi_buffer - *ret_buffer)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_statistics(struct acpi_statistics *stats)) -ACPI_EXTERNAL_RETURN_PTR(const char - *acpi_format_exception(acpi_status exception)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_purge_cached_objects(void)) - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_install_interface(acpi_string interface_name)) - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_remove_interface(acpi_string interface_name)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_update_interfaces(u8 action)) - -ACPI_EXTERNAL_RETURN_UINT32(u32 - acpi_check_address_range(acpi_adr_space_type - space_id, - acpi_physical_address - address, acpi_size length, - u8 warn)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_decode_pld_buffer(u8 *in_buffer, - acpi_size length, - struct acpi_pld_info - **return_buffer)) - -/* - * ACPI table load/unload interfaces - */ -ACPI_EXTERNAL_RETURN_STATUS(acpi_status ACPI_INIT_FUNCTION - acpi_install_table(acpi_physical_address address, - u8 physical)) - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_load_table(struct acpi_table_header *table)) - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_unload_parent_table(acpi_handle object)) - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status ACPI_INIT_FUNCTION - acpi_load_tables(void)) - -/* - * ACPI table manipulation interfaces - */ -ACPI_EXTERNAL_RETURN_STATUS(acpi_status ACPI_INIT_FUNCTION - acpi_reallocate_root_table(void)) - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status ACPI_INIT_FUNCTION - acpi_find_root_pointer(acpi_physical_address - *rsdp_address)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_table_header(acpi_string signature, - u32 instance, - struct acpi_table_header - *out_table_header)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_table(acpi_string signature, u32 instance, - struct acpi_table_header - **out_table)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_table_by_index(u32 table_index, - struct acpi_table_header - **out_table)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_install_table_handler(acpi_table_handler - handler, void *context)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_remove_table_handler(acpi_table_handler - handler)) - -/* - * Namespace and name interfaces - */ -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_walk_namespace(acpi_object_type type, - acpi_handle start_object, - u32 max_depth, - acpi_walk_callback - descending_callback, - acpi_walk_callback - ascending_callback, - void *context, - void **return_value)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_devices(const char *HID, - acpi_walk_callback user_function, - void *context, - void **return_value)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_name(acpi_handle object, u32 name_type, - struct acpi_buffer *ret_path_ptr)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_handle(acpi_handle parent, - acpi_string pathname, - acpi_handle *ret_handle)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_attach_data(acpi_handle object, - acpi_object_handler handler, - void *data)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_detach_data(acpi_handle object, - acpi_object_handler handler)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_data(acpi_handle object, - acpi_object_handler handler, - void **data)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_debug_trace(const char *name, u32 debug_level, - u32 debug_layer, u32 flags)) - -/* - * Object manipulation and enumeration - */ -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_evaluate_object(acpi_handle object, - acpi_string pathname, - struct acpi_object_list - *parameter_objects, - struct acpi_buffer - *return_object_buffer)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_evaluate_object_typed(acpi_handle object, - acpi_string pathname, - struct acpi_object_list - *external_params, - struct acpi_buffer - *return_buffer, - acpi_object_type - return_type)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_object_info(acpi_handle object, - struct acpi_device_info - **return_buffer)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_install_method(u8 *buffer)) - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_next_object(acpi_object_type type, - acpi_handle parent, - acpi_handle child, - acpi_handle *out_handle)) - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_type(acpi_handle object, - acpi_object_type *out_type)) - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_parent(acpi_handle object, - acpi_handle *out_handle)) - -/* - * Handler interfaces - */ -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_install_initialization_handler - (acpi_init_handler handler, u32 function)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_install_sci_handler(acpi_sci_handler - address, - void *context)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_remove_sci_handler(acpi_sci_handler - address)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_install_global_event_handler - (acpi_gbl_event_handler handler, - void *context)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_install_fixed_event_handler(u32 - acpi_event, - acpi_event_handler - handler, - void - *context)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_remove_fixed_event_handler(u32 acpi_event, - acpi_event_handler - handler)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_install_gpe_handler(acpi_handle - gpe_device, - u32 gpe_number, - u32 type, - acpi_gpe_handler - address, - void *context)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_install_gpe_raw_handler(acpi_handle - gpe_device, - u32 gpe_number, - u32 type, - acpi_gpe_handler - address, - void *context)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_remove_gpe_handler(acpi_handle gpe_device, - u32 gpe_number, - acpi_gpe_handler - address)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_install_notify_handler(acpi_handle device, - u32 handler_type, - acpi_notify_handler - handler, - void *context)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_remove_notify_handler(acpi_handle device, - u32 handler_type, - acpi_notify_handler - handler)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_install_address_space_handler(acpi_handle - device, - acpi_adr_space_type - space_id, - acpi_adr_space_handler - handler, - acpi_adr_space_setup - setup, - void *context)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_remove_address_space_handler(acpi_handle - device, - acpi_adr_space_type - space_id, - acpi_adr_space_handler - handler)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_install_exception_handler - (acpi_exception_handler handler)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_install_interface_handler - (acpi_interface_handler handler)) - -/* - * Global Lock interfaces - */ -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_acquire_global_lock(u16 timeout, - u32 *handle)) - -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_release_global_lock(u32 handle)) - -/* - * Interfaces to AML mutex objects - */ -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_acquire_mutex(acpi_handle handle, - acpi_string pathname, - u16 timeout)) - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_release_mutex(acpi_handle handle, - acpi_string pathname)) - -/* - * Fixed Event interfaces - */ -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_enable_event(u32 event, u32 flags)) - -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_disable_event(u32 event, u32 flags)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_clear_event(u32 event)) - -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_get_event_status(u32 event, - acpi_event_status - *event_status)) - -/* - * General Purpose Event (GPE) Interfaces - */ -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_update_all_gpes(void)) - -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_enable_gpe(acpi_handle gpe_device, - u32 gpe_number)) - -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_disable_gpe(acpi_handle gpe_device, - u32 gpe_number)) - -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_clear_gpe(acpi_handle gpe_device, - u32 gpe_number)) - -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_set_gpe(acpi_handle gpe_device, - u32 gpe_number, u8 action)) - -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_finish_gpe(acpi_handle gpe_device, - u32 gpe_number)) - -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_mask_gpe(acpi_handle gpe_device, - u32 gpe_number, u8 is_masked)) - -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_mark_gpe_for_wake(acpi_handle gpe_device, - u32 gpe_number)) - -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_setup_gpe_for_wake(acpi_handle - parent_device, - acpi_handle gpe_device, - u32 gpe_number)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_set_gpe_wake_mask(acpi_handle gpe_device, - u32 gpe_number, - u8 action)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_get_gpe_status(acpi_handle gpe_device, - u32 gpe_number, - acpi_event_status - *event_status)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_disable_all_gpes(void)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_runtime_gpes(void)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enable_all_wakeup_gpes(void)) - -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_get_gpe_device(u32 gpe_index, - acpi_handle *gpe_device)) - -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_install_gpe_block(acpi_handle gpe_device, - struct - acpi_generic_address - *gpe_block_address, - u32 register_count, - u32 interrupt_number)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_remove_gpe_block(acpi_handle gpe_device)) - -/* - * Resource interfaces - */ -typedef -acpi_status (*acpi_walk_resource_callback) (struct acpi_resource * resource, - void *context); - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_vendor_resource(acpi_handle device, - char *name, - struct acpi_vendor_uuid - *uuid, - struct acpi_buffer - *ret_buffer)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_current_resources(acpi_handle device, - struct acpi_buffer - *ret_buffer)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_possible_resources(acpi_handle device, - struct acpi_buffer - *ret_buffer)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_event_resources(acpi_handle device_handle, - struct acpi_buffer - *ret_buffer)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_walk_resource_buffer(struct acpi_buffer - *buffer, - acpi_walk_resource_callback - user_function, - void *context)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_walk_resources(acpi_handle device, char *name, - acpi_walk_resource_callback - user_function, void *context)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_set_current_resources(acpi_handle device, - struct acpi_buffer - *in_buffer)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_irq_routing_table(acpi_handle device, - struct acpi_buffer - *ret_buffer)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_resource_to_address64(struct acpi_resource - *resource, - struct - acpi_resource_address64 - *out)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_buffer_to_resource(u8 *aml_buffer, - u16 aml_buffer_length, - struct acpi_resource - **resource_ptr)) - -/* - * Hardware (ACPI device) interfaces - */ -ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_reset(void)) - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_read(u64 *value, - struct acpi_generic_address *reg)) - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_write(u64 value, - struct acpi_generic_address *reg)) - -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_read_bit_register(u32 register_id, - u32 *return_value)) - -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_write_bit_register(u32 register_id, - u32 value)) - -/* - * Sleep/Wake interfaces - */ -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_sleep_type_data(u8 sleep_state, - u8 *slp_typ_a, - u8 *slp_typ_b)) - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_enter_sleep_state_prep(u8 sleep_state)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_enter_sleep_state(u8 sleep_state)) - -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_enter_sleep_state_s4bios(void)) - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_leave_sleep_state_prep(u8 sleep_state)) -ACPI_EXTERNAL_RETURN_STATUS(acpi_status acpi_leave_sleep_state(u8 sleep_state)) - -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_set_firmware_waking_vector - (acpi_physical_address physical_address, - acpi_physical_address physical_address64)) -/* - * ACPI Timer interfaces - */ -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_get_timer_resolution(u32 *resolution)) -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status acpi_get_timer(u32 *ticks)) - -ACPI_HW_DEPENDENT_RETURN_STATUS(acpi_status - acpi_get_timer_duration(u32 start_ticks, - u32 end_ticks, - u32 *time_elapsed)) - -/* - * Error/Warning output - */ -ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(3) - void ACPI_INTERNAL_VAR_XFACE - acpi_error(const char *module_name, - u32 line_number, - const char *format, ...)) -ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(4) - void ACPI_INTERNAL_VAR_XFACE - acpi_exception(const char *module_name, - u32 line_number, - acpi_status status, - const char *format, ...)) -ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(3) - void ACPI_INTERNAL_VAR_XFACE - acpi_warning(const char *module_name, - u32 line_number, - const char *format, ...)) -ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(1) - void ACPI_INTERNAL_VAR_XFACE - acpi_info(const char *format, ...)) -ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(3) - void ACPI_INTERNAL_VAR_XFACE - acpi_bios_error(const char *module_name, - u32 line_number, - const char *format, ...)) -ACPI_MSG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(3) - void ACPI_INTERNAL_VAR_XFACE - acpi_bios_warning(const char *module_name, - u32 line_number, - const char *format, ...)) - -/* - * Debug output - */ -ACPI_DBG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(6) - void ACPI_INTERNAL_VAR_XFACE - acpi_debug_print(u32 requested_debug_level, - u32 line_number, - const char *function_name, - const char *module_name, - u32 component_id, - const char *format, ...)) -ACPI_DBG_DEPENDENT_RETURN_VOID(ACPI_PRINTF_LIKE(6) - void ACPI_INTERNAL_VAR_XFACE - acpi_debug_print_raw(u32 requested_debug_level, - u32 line_number, - const char *function_name, - const char *module_name, - u32 component_id, - const char *format, ...)) - -ACPI_DBG_DEPENDENT_RETURN_VOID(void - acpi_trace_point(acpi_trace_event_type type, - u8 begin, - u8 *aml, char *pathname)) - -acpi_status acpi_initialize_debugger(void); - -void acpi_terminate_debugger(void); - -/* - * Divergences - */ -ACPI_GLOBAL(u8, acpi_gbl_permanent_mmap); - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_table_with_size(acpi_string signature, - u32 instance, - struct acpi_table_header - **out_table, - acpi_size *tbl_size)) - -ACPI_EXTERNAL_RETURN_STATUS(acpi_status - acpi_get_data_full(acpi_handle object, - acpi_object_handler handler, - void **data, - void (*callback)(void *))) - -void acpi_run_debugger(char *batch_buffer); - -void acpi_set_debugger_thread_id(acpi_thread_id thread_id); - -#endif /* __ACXFACE_H__ */ diff --git a/src/linux/include/acpi/acrestyp.h b/src/linux/include/acpi/acrestyp.h deleted file mode 100644 index 16c1892..0000000 --- a/src/linux/include/acpi/acrestyp.h +++ /dev/null @@ -1,622 +0,0 @@ -/****************************************************************************** - * - * Name: acrestyp.h - Defines, types, and structures for resource descriptors - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACRESTYP_H__ -#define __ACRESTYP_H__ - -/* - * Definitions for Resource Attributes - */ -typedef u16 acpi_rs_length; /* Resource Length field is fixed at 16 bits */ -typedef u32 acpi_rsdesc_size; /* Max Resource Descriptor size is (Length+3) = (64K-1)+3 */ - -/* - * Memory Attributes - */ -#define ACPI_READ_ONLY_MEMORY (u8) 0x00 -#define ACPI_READ_WRITE_MEMORY (u8) 0x01 - -#define ACPI_NON_CACHEABLE_MEMORY (u8) 0x00 -#define ACPI_CACHABLE_MEMORY (u8) 0x01 -#define ACPI_WRITE_COMBINING_MEMORY (u8) 0x02 -#define ACPI_PREFETCHABLE_MEMORY (u8) 0x03 - -/*! [Begin] no source code translation */ -/* - * IO Attributes - * The ISA IO ranges are: n000-n0FFh, n400-n4FFh, n800-n8FFh, nC00-nCFFh. - * The non-ISA IO ranges are: n100-n3FFh, n500-n7FFh, n900-nBFFh, nCD0-nFFFh. - */ -/*! [End] no source code translation !*/ - -#define ACPI_NON_ISA_ONLY_RANGES (u8) 0x01 -#define ACPI_ISA_ONLY_RANGES (u8) 0x02 -#define ACPI_ENTIRE_RANGE (ACPI_NON_ISA_ONLY_RANGES | ACPI_ISA_ONLY_RANGES) - -/* Type of translation - 1=Sparse, 0=Dense */ - -#define ACPI_SPARSE_TRANSLATION (u8) 0x01 - -/* - * IO Port Descriptor Decode - */ -#define ACPI_DECODE_10 (u8) 0x00 /* 10-bit IO address decode */ -#define ACPI_DECODE_16 (u8) 0x01 /* 16-bit IO address decode */ - -/* - * Interrupt attributes - used in multiple descriptors - */ - -/* Triggering */ - -#define ACPI_LEVEL_SENSITIVE (u8) 0x00 -#define ACPI_EDGE_SENSITIVE (u8) 0x01 - -/* Polarity */ - -#define ACPI_ACTIVE_HIGH (u8) 0x00 -#define ACPI_ACTIVE_LOW (u8) 0x01 -#define ACPI_ACTIVE_BOTH (u8) 0x02 - -/* Sharing */ - -#define ACPI_EXCLUSIVE (u8) 0x00 -#define ACPI_SHARED (u8) 0x01 - -/* Wake */ - -#define ACPI_NOT_WAKE_CAPABLE (u8) 0x00 -#define ACPI_WAKE_CAPABLE (u8) 0x01 - -/* - * DMA Attributes - */ -#define ACPI_COMPATIBILITY (u8) 0x00 -#define ACPI_TYPE_A (u8) 0x01 -#define ACPI_TYPE_B (u8) 0x02 -#define ACPI_TYPE_F (u8) 0x03 - -#define ACPI_NOT_BUS_MASTER (u8) 0x00 -#define ACPI_BUS_MASTER (u8) 0x01 - -#define ACPI_TRANSFER_8 (u8) 0x00 -#define ACPI_TRANSFER_8_16 (u8) 0x01 -#define ACPI_TRANSFER_16 (u8) 0x02 - -/* - * Start Dependent Functions Priority definitions - */ -#define ACPI_GOOD_CONFIGURATION (u8) 0x00 -#define ACPI_ACCEPTABLE_CONFIGURATION (u8) 0x01 -#define ACPI_SUB_OPTIMAL_CONFIGURATION (u8) 0x02 - -/* - * 16, 32 and 64-bit Address Descriptor resource types - */ -#define ACPI_MEMORY_RANGE (u8) 0x00 -#define ACPI_IO_RANGE (u8) 0x01 -#define ACPI_BUS_NUMBER_RANGE (u8) 0x02 - -#define ACPI_ADDRESS_NOT_FIXED (u8) 0x00 -#define ACPI_ADDRESS_FIXED (u8) 0x01 - -#define ACPI_POS_DECODE (u8) 0x00 -#define ACPI_SUB_DECODE (u8) 0x01 - -/* Producer/Consumer */ - -#define ACPI_PRODUCER (u8) 0x00 -#define ACPI_CONSUMER (u8) 0x01 - -/* - * If possible, pack the following structures to byte alignment - */ -#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED -#pragma pack(1) -#endif - -/* UUID data structures for use in vendor-defined resource descriptors */ - -struct acpi_uuid { - u8 data[ACPI_UUID_LENGTH]; -}; - -struct acpi_vendor_uuid { - u8 subtype; - u8 data[ACPI_UUID_LENGTH]; -}; - -/* - * Structures used to describe device resources - */ -struct acpi_resource_irq { - u8 descriptor_length; - u8 triggering; - u8 polarity; - u8 sharable; - u8 wake_capable; - u8 interrupt_count; - u8 interrupts[1]; -}; - -struct acpi_resource_dma { - u8 type; - u8 bus_master; - u8 transfer; - u8 channel_count; - u8 channels[1]; -}; - -struct acpi_resource_start_dependent { - u8 descriptor_length; - u8 compatibility_priority; - u8 performance_robustness; -}; - -/* - * The END_DEPENDENT_FUNCTIONS_RESOURCE struct is not - * needed because it has no fields - */ - -struct acpi_resource_io { - u8 io_decode; - u8 alignment; - u8 address_length; - u16 minimum; - u16 maximum; -}; - -struct acpi_resource_fixed_io { - u16 address; - u8 address_length; -}; - -struct acpi_resource_fixed_dma { - u16 request_lines; - u16 channels; - u8 width; -}; - -/* Values for Width field above */ - -#define ACPI_DMA_WIDTH8 0 -#define ACPI_DMA_WIDTH16 1 -#define ACPI_DMA_WIDTH32 2 -#define ACPI_DMA_WIDTH64 3 -#define ACPI_DMA_WIDTH128 4 -#define ACPI_DMA_WIDTH256 5 - -struct acpi_resource_vendor { - u16 byte_length; - u8 byte_data[1]; -}; - -/* Vendor resource with UUID info (introduced in ACPI 3.0) */ - -struct acpi_resource_vendor_typed { - u16 byte_length; - u8 uuid_subtype; - u8 uuid[ACPI_UUID_LENGTH]; - u8 byte_data[1]; -}; - -struct acpi_resource_end_tag { - u8 checksum; -}; - -struct acpi_resource_memory24 { - u8 write_protect; - u16 minimum; - u16 maximum; - u16 alignment; - u16 address_length; -}; - -struct acpi_resource_memory32 { - u8 write_protect; - u32 minimum; - u32 maximum; - u32 alignment; - u32 address_length; -}; - -struct acpi_resource_fixed_memory32 { - u8 write_protect; - u32 address; - u32 address_length; -}; - -struct acpi_memory_attribute { - u8 write_protect; - u8 caching; - u8 range_type; - u8 translation; -}; - -struct acpi_io_attribute { - u8 range_type; - u8 translation; - u8 translation_type; - u8 reserved1; -}; - -union acpi_resource_attribute { - struct acpi_memory_attribute mem; - struct acpi_io_attribute io; - - /* Used for the *word_space macros */ - - u8 type_specific; -}; - -struct acpi_resource_source { - u8 index; - u16 string_length; - char *string_ptr; -}; - -/* Fields common to all address descriptors, 16/32/64 bit */ - -#define ACPI_RESOURCE_ADDRESS_COMMON \ - u8 resource_type; \ - u8 producer_consumer; \ - u8 decode; \ - u8 min_address_fixed; \ - u8 max_address_fixed; \ - union acpi_resource_attribute info; - -struct acpi_address16_attribute { - u16 granularity; - u16 minimum; - u16 maximum; - u16 translation_offset; - u16 address_length; -}; - -struct acpi_address32_attribute { - u32 granularity; - u32 minimum; - u32 maximum; - u32 translation_offset; - u32 address_length; -}; - -struct acpi_address64_attribute { - u64 granularity; - u64 minimum; - u64 maximum; - u64 translation_offset; - u64 address_length; -}; - -struct acpi_resource_address { -ACPI_RESOURCE_ADDRESS_COMMON}; - -struct acpi_resource_address16 { - ACPI_RESOURCE_ADDRESS_COMMON struct acpi_address16_attribute address; - struct acpi_resource_source resource_source; -}; - -struct acpi_resource_address32 { - ACPI_RESOURCE_ADDRESS_COMMON struct acpi_address32_attribute address; - struct acpi_resource_source resource_source; -}; - -struct acpi_resource_address64 { - ACPI_RESOURCE_ADDRESS_COMMON struct acpi_address64_attribute address; - struct acpi_resource_source resource_source; -}; - -struct acpi_resource_extended_address64 { - ACPI_RESOURCE_ADDRESS_COMMON u8 revision_ID; - struct acpi_address64_attribute address; - u64 type_specific; -}; - -struct acpi_resource_extended_irq { - u8 producer_consumer; - u8 triggering; - u8 polarity; - u8 sharable; - u8 wake_capable; - u8 interrupt_count; - struct acpi_resource_source resource_source; - u32 interrupts[1]; -}; - -struct acpi_resource_generic_register { - u8 space_id; - u8 bit_width; - u8 bit_offset; - u8 access_size; - u64 address; -}; - -struct acpi_resource_gpio { - u8 revision_id; - u8 connection_type; - u8 producer_consumer; /* For values, see Producer/Consumer above */ - u8 pin_config; - u8 sharable; /* For values, see Interrupt Attributes above */ - u8 wake_capable; /* For values, see Interrupt Attributes above */ - u8 io_restriction; - u8 triggering; /* For values, see Interrupt Attributes above */ - u8 polarity; /* For values, see Interrupt Attributes above */ - u16 drive_strength; - u16 debounce_timeout; - u16 pin_table_length; - u16 vendor_length; - struct acpi_resource_source resource_source; - u16 *pin_table; - u8 *vendor_data; -}; - -/* Values for GPIO connection_type field above */ - -#define ACPI_RESOURCE_GPIO_TYPE_INT 0 -#define ACPI_RESOURCE_GPIO_TYPE_IO 1 - -/* Values for pin_config field above */ - -#define ACPI_PIN_CONFIG_DEFAULT 0 -#define ACPI_PIN_CONFIG_PULLUP 1 -#define ACPI_PIN_CONFIG_PULLDOWN 2 -#define ACPI_PIN_CONFIG_NOPULL 3 - -/* Values for io_restriction field above */ - -#define ACPI_IO_RESTRICT_NONE 0 -#define ACPI_IO_RESTRICT_INPUT 1 -#define ACPI_IO_RESTRICT_OUTPUT 2 -#define ACPI_IO_RESTRICT_NONE_PRESERVE 3 - -/* Common structure for I2C, SPI, and UART serial descriptors */ - -#define ACPI_RESOURCE_SERIAL_COMMON \ - u8 revision_id; \ - u8 type; \ - u8 producer_consumer; /* For values, see Producer/Consumer above */\ - u8 slave_mode; \ - u8 connection_sharing; \ - u8 type_revision_id; \ - u16 type_data_length; \ - u16 vendor_length; \ - struct acpi_resource_source resource_source; \ - u8 *vendor_data; - -struct acpi_resource_common_serialbus { -ACPI_RESOURCE_SERIAL_COMMON}; - -/* Values for the Type field above */ - -#define ACPI_RESOURCE_SERIAL_TYPE_I2C 1 -#define ACPI_RESOURCE_SERIAL_TYPE_SPI 2 -#define ACPI_RESOURCE_SERIAL_TYPE_UART 3 - -/* Values for slave_mode field above */ - -#define ACPI_CONTROLLER_INITIATED 0 -#define ACPI_DEVICE_INITIATED 1 - -struct acpi_resource_i2c_serialbus { - ACPI_RESOURCE_SERIAL_COMMON u8 access_mode; - u16 slave_address; - u32 connection_speed; -}; - -/* Values for access_mode field above */ - -#define ACPI_I2C_7BIT_MODE 0 -#define ACPI_I2C_10BIT_MODE 1 - -struct acpi_resource_spi_serialbus { - ACPI_RESOURCE_SERIAL_COMMON u8 wire_mode; - u8 device_polarity; - u8 data_bit_length; - u8 clock_phase; - u8 clock_polarity; - u16 device_selection; - u32 connection_speed; -}; - -/* Values for wire_mode field above */ - -#define ACPI_SPI_4WIRE_MODE 0 -#define ACPI_SPI_3WIRE_MODE 1 - -/* Values for device_polarity field above */ - -#define ACPI_SPI_ACTIVE_LOW 0 -#define ACPI_SPI_ACTIVE_HIGH 1 - -/* Values for clock_phase field above */ - -#define ACPI_SPI_FIRST_PHASE 0 -#define ACPI_SPI_SECOND_PHASE 1 - -/* Values for clock_polarity field above */ - -#define ACPI_SPI_START_LOW 0 -#define ACPI_SPI_START_HIGH 1 - -struct acpi_resource_uart_serialbus { - ACPI_RESOURCE_SERIAL_COMMON u8 endian; - u8 data_bits; - u8 stop_bits; - u8 flow_control; - u8 parity; - u8 lines_enabled; - u16 rx_fifo_size; - u16 tx_fifo_size; - u32 default_baud_rate; -}; - -/* Values for Endian field above */ - -#define ACPI_UART_LITTLE_ENDIAN 0 -#define ACPI_UART_BIG_ENDIAN 1 - -/* Values for data_bits field above */ - -#define ACPI_UART_5_DATA_BITS 0 -#define ACPI_UART_6_DATA_BITS 1 -#define ACPI_UART_7_DATA_BITS 2 -#define ACPI_UART_8_DATA_BITS 3 -#define ACPI_UART_9_DATA_BITS 4 - -/* Values for stop_bits field above */ - -#define ACPI_UART_NO_STOP_BITS 0 -#define ACPI_UART_1_STOP_BIT 1 -#define ACPI_UART_1P5_STOP_BITS 2 -#define ACPI_UART_2_STOP_BITS 3 - -/* Values for flow_control field above */ - -#define ACPI_UART_FLOW_CONTROL_NONE 0 -#define ACPI_UART_FLOW_CONTROL_HW 1 -#define ACPI_UART_FLOW_CONTROL_XON_XOFF 2 - -/* Values for Parity field above */ - -#define ACPI_UART_PARITY_NONE 0 -#define ACPI_UART_PARITY_EVEN 1 -#define ACPI_UART_PARITY_ODD 2 -#define ACPI_UART_PARITY_MARK 3 -#define ACPI_UART_PARITY_SPACE 4 - -/* Values for lines_enabled bitfield above */ - -#define ACPI_UART_CARRIER_DETECT (1<<2) -#define ACPI_UART_RING_INDICATOR (1<<3) -#define ACPI_UART_DATA_SET_READY (1<<4) -#define ACPI_UART_DATA_TERMINAL_READY (1<<5) -#define ACPI_UART_CLEAR_TO_SEND (1<<6) -#define ACPI_UART_REQUEST_TO_SEND (1<<7) - -/* ACPI_RESOURCE_TYPEs */ - -#define ACPI_RESOURCE_TYPE_IRQ 0 -#define ACPI_RESOURCE_TYPE_DMA 1 -#define ACPI_RESOURCE_TYPE_START_DEPENDENT 2 -#define ACPI_RESOURCE_TYPE_END_DEPENDENT 3 -#define ACPI_RESOURCE_TYPE_IO 4 -#define ACPI_RESOURCE_TYPE_FIXED_IO 5 -#define ACPI_RESOURCE_TYPE_VENDOR 6 -#define ACPI_RESOURCE_TYPE_END_TAG 7 -#define ACPI_RESOURCE_TYPE_MEMORY24 8 -#define ACPI_RESOURCE_TYPE_MEMORY32 9 -#define ACPI_RESOURCE_TYPE_FIXED_MEMORY32 10 -#define ACPI_RESOURCE_TYPE_ADDRESS16 11 -#define ACPI_RESOURCE_TYPE_ADDRESS32 12 -#define ACPI_RESOURCE_TYPE_ADDRESS64 13 -#define ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64 14 /* ACPI 3.0 */ -#define ACPI_RESOURCE_TYPE_EXTENDED_IRQ 15 -#define ACPI_RESOURCE_TYPE_GENERIC_REGISTER 16 -#define ACPI_RESOURCE_TYPE_GPIO 17 /* ACPI 5.0 */ -#define ACPI_RESOURCE_TYPE_FIXED_DMA 18 /* ACPI 5.0 */ -#define ACPI_RESOURCE_TYPE_SERIAL_BUS 19 /* ACPI 5.0 */ -#define ACPI_RESOURCE_TYPE_MAX 19 - -/* Master union for resource descriptors */ - -union acpi_resource_data { - struct acpi_resource_irq irq; - struct acpi_resource_dma dma; - struct acpi_resource_start_dependent start_dpf; - struct acpi_resource_io io; - struct acpi_resource_fixed_io fixed_io; - struct acpi_resource_fixed_dma fixed_dma; - struct acpi_resource_vendor vendor; - struct acpi_resource_vendor_typed vendor_typed; - struct acpi_resource_end_tag end_tag; - struct acpi_resource_memory24 memory24; - struct acpi_resource_memory32 memory32; - struct acpi_resource_fixed_memory32 fixed_memory32; - struct acpi_resource_address16 address16; - struct acpi_resource_address32 address32; - struct acpi_resource_address64 address64; - struct acpi_resource_extended_address64 ext_address64; - struct acpi_resource_extended_irq extended_irq; - struct acpi_resource_generic_register generic_reg; - struct acpi_resource_gpio gpio; - struct acpi_resource_i2c_serialbus i2c_serial_bus; - struct acpi_resource_spi_serialbus spi_serial_bus; - struct acpi_resource_uart_serialbus uart_serial_bus; - struct acpi_resource_common_serialbus common_serial_bus; - - /* Common fields */ - - struct acpi_resource_address address; /* Common 16/32/64 address fields */ -}; - -/* Common resource header */ - -struct acpi_resource { - u32 type; - u32 length; - union acpi_resource_data data; -}; - -/* restore default alignment */ - -#pragma pack() - -#define ACPI_RS_SIZE_NO_DATA 8 /* Id + Length fields */ -#define ACPI_RS_SIZE_MIN (u32) ACPI_ROUND_UP_TO_NATIVE_WORD (12) -#define ACPI_RS_SIZE(type) (u32) (ACPI_RS_SIZE_NO_DATA + sizeof (type)) - -/* Macro for walking resource templates with multiple descriptors */ - -#define ACPI_NEXT_RESOURCE(res) \ - ACPI_ADD_PTR (struct acpi_resource, (res), (res)->length) - -struct acpi_pci_routing_table { - u32 length; - u32 pin; - u64 address; /* here for 64-bit alignment */ - u32 source_index; - char source[4]; /* pad to 64 bits so sizeof() works in all cases */ -}; - -#endif /* __ACRESTYP_H__ */ diff --git a/src/linux/include/acpi/actbl.h b/src/linux/include/acpi/actbl.h deleted file mode 100644 index c19700e..0000000 --- a/src/linux/include/acpi/actbl.h +++ /dev/null @@ -1,418 +0,0 @@ -/****************************************************************************** - * - * Name: actbl.h - Basic ACPI Table Definitions - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACTBL_H__ -#define __ACTBL_H__ - -/******************************************************************************* - * - * Fundamental ACPI tables - * - * This file contains definitions for the ACPI tables that are directly consumed - * by ACPICA. All other tables are consumed by the OS-dependent ACPI-related - * device drivers and other OS support code. - * - * The RSDP and FACS do not use the common ACPI table header. All other ACPI - * tables use the header. - * - ******************************************************************************/ - -/* - * Values for description table header signatures for tables defined in this - * file. Useful because they make it more difficult to inadvertently type in - * the wrong signature. - */ -#define ACPI_SIG_DSDT "DSDT" /* Differentiated System Description Table */ -#define ACPI_SIG_FADT "FACP" /* Fixed ACPI Description Table */ -#define ACPI_SIG_FACS "FACS" /* Firmware ACPI Control Structure */ -#define ACPI_SIG_OSDT "OSDT" /* Override System Description Table */ -#define ACPI_SIG_PSDT "PSDT" /* Persistent System Description Table */ -#define ACPI_SIG_RSDP "RSD PTR " /* Root System Description Pointer */ -#define ACPI_SIG_RSDT "RSDT" /* Root System Description Table */ -#define ACPI_SIG_XSDT "XSDT" /* Extended System Description Table */ -#define ACPI_SIG_SSDT "SSDT" /* Secondary System Description Table */ -#define ACPI_RSDP_NAME "RSDP" /* Short name for RSDP, not signature */ - -/* - * All tables and structures must be byte-packed to match the ACPI - * specification, since the tables are provided by the system BIOS - */ -#pragma pack(1) - -/* - * Note: C bitfields are not used for this reason: - * - * "Bitfields are great and easy to read, but unfortunately the C language - * does not specify the layout of bitfields in memory, which means they are - * essentially useless for dealing with packed data in on-disk formats or - * binary wire protocols." (Or ACPI tables and buffers.) "If you ask me, - * this decision was a design error in C. Ritchie could have picked an order - * and stuck with it." Norman Ramsey. - * See http://stackoverflow.com/a/1053662/41661 - */ - -/******************************************************************************* - * - * Master ACPI Table Header. This common header is used by all ACPI tables - * except the RSDP and FACS. - * - ******************************************************************************/ - -struct acpi_table_header { - char signature[ACPI_NAME_SIZE]; /* ASCII table signature */ - u32 length; /* Length of table in bytes, including this header */ - u8 revision; /* ACPI Specification minor version number */ - u8 checksum; /* To make sum of entire table == 0 */ - char oem_id[ACPI_OEM_ID_SIZE]; /* ASCII OEM identification */ - char oem_table_id[ACPI_OEM_TABLE_ID_SIZE]; /* ASCII OEM table identification */ - u32 oem_revision; /* OEM revision number */ - char asl_compiler_id[ACPI_NAME_SIZE]; /* ASCII ASL compiler vendor ID */ - u32 asl_compiler_revision; /* ASL compiler version */ -}; - -/******************************************************************************* - * - * GAS - Generic Address Structure (ACPI 2.0+) - * - * Note: Since this structure is used in the ACPI tables, it is byte aligned. - * If misaligned access is not supported by the hardware, accesses to the - * 64-bit Address field must be performed with care. - * - ******************************************************************************/ - -struct acpi_generic_address { - u8 space_id; /* Address space where struct or register exists */ - u8 bit_width; /* Size in bits of given register */ - u8 bit_offset; /* Bit offset within the register */ - u8 access_width; /* Minimum Access size (ACPI 3.0) */ - u64 address; /* 64-bit address of struct or register */ -}; - -/******************************************************************************* - * - * RSDP - Root System Description Pointer (Signature is "RSD PTR ") - * Version 2 - * - ******************************************************************************/ - -struct acpi_table_rsdp { - char signature[8]; /* ACPI signature, contains "RSD PTR " */ - u8 checksum; /* ACPI 1.0 checksum */ - char oem_id[ACPI_OEM_ID_SIZE]; /* OEM identification */ - u8 revision; /* Must be (0) for ACPI 1.0 or (2) for ACPI 2.0+ */ - u32 rsdt_physical_address; /* 32-bit physical address of the RSDT */ - u32 length; /* Table length in bytes, including header (ACPI 2.0+) */ - u64 xsdt_physical_address; /* 64-bit physical address of the XSDT (ACPI 2.0+) */ - u8 extended_checksum; /* Checksum of entire table (ACPI 2.0+) */ - u8 reserved[3]; /* Reserved, must be zero */ -}; - -/* Standalone struct for the ACPI 1.0 RSDP */ - -struct acpi_rsdp_common { - char signature[8]; - u8 checksum; - char oem_id[ACPI_OEM_ID_SIZE]; - u8 revision; - u32 rsdt_physical_address; -}; - -/* Standalone struct for the extended part of the RSDP (ACPI 2.0+) */ - -struct acpi_rsdp_extension { - u32 length; - u64 xsdt_physical_address; - u8 extended_checksum; - u8 reserved[3]; -}; - -/******************************************************************************* - * - * RSDT/XSDT - Root System Description Tables - * Version 1 (both) - * - ******************************************************************************/ - -struct acpi_table_rsdt { - struct acpi_table_header header; /* Common ACPI table header */ - u32 table_offset_entry[1]; /* Array of pointers to ACPI tables */ -}; - -struct acpi_table_xsdt { - struct acpi_table_header header; /* Common ACPI table header */ - u64 table_offset_entry[1]; /* Array of pointers to ACPI tables */ -}; - -#define ACPI_RSDT_ENTRY_SIZE (sizeof (u32)) -#define ACPI_XSDT_ENTRY_SIZE (sizeof (u64)) - -/******************************************************************************* - * - * FACS - Firmware ACPI Control Structure (FACS) - * - ******************************************************************************/ - -struct acpi_table_facs { - char signature[4]; /* ASCII table signature */ - u32 length; /* Length of structure, in bytes */ - u32 hardware_signature; /* Hardware configuration signature */ - u32 firmware_waking_vector; /* 32-bit physical address of the Firmware Waking Vector */ - u32 global_lock; /* Global Lock for shared hardware resources */ - u32 flags; - u64 xfirmware_waking_vector; /* 64-bit version of the Firmware Waking Vector (ACPI 2.0+) */ - u8 version; /* Version of this table (ACPI 2.0+) */ - u8 reserved[3]; /* Reserved, must be zero */ - u32 ospm_flags; /* Flags to be set by OSPM (ACPI 4.0) */ - u8 reserved1[24]; /* Reserved, must be zero */ -}; - -/* Masks for global_lock flag field above */ - -#define ACPI_GLOCK_PENDING (1) /* 00: Pending global lock ownership */ -#define ACPI_GLOCK_OWNED (1<<1) /* 01: Global lock is owned */ - -/* Masks for Flags field above */ - -#define ACPI_FACS_S4_BIOS_PRESENT (1) /* 00: S4BIOS support is present */ -#define ACPI_FACS_64BIT_WAKE (1<<1) /* 01: 64-bit wake vector supported (ACPI 4.0) */ - -/* Masks for ospm_flags field above */ - -#define ACPI_FACS_64BIT_ENVIRONMENT (1) /* 00: 64-bit wake environment is required (ACPI 4.0) */ - -/******************************************************************************* - * - * FADT - Fixed ACPI Description Table (Signature "FACP") - * Version 6 - * - ******************************************************************************/ - -/* Fields common to all versions of the FADT */ - -struct acpi_table_fadt { - struct acpi_table_header header; /* Common ACPI table header */ - u32 facs; /* 32-bit physical address of FACS */ - u32 dsdt; /* 32-bit physical address of DSDT */ - u8 model; /* System Interrupt Model (ACPI 1.0) - not used in ACPI 2.0+ */ - u8 preferred_profile; /* Conveys preferred power management profile to OSPM. */ - u16 sci_interrupt; /* System vector of SCI interrupt */ - u32 smi_command; /* 32-bit Port address of SMI command port */ - u8 acpi_enable; /* Value to write to SMI_CMD to enable ACPI */ - u8 acpi_disable; /* Value to write to SMI_CMD to disable ACPI */ - u8 s4_bios_request; /* Value to write to SMI_CMD to enter S4BIOS state */ - u8 pstate_control; /* Processor performance state control */ - u32 pm1a_event_block; /* 32-bit port address of Power Mgt 1a Event Reg Blk */ - u32 pm1b_event_block; /* 32-bit port address of Power Mgt 1b Event Reg Blk */ - u32 pm1a_control_block; /* 32-bit port address of Power Mgt 1a Control Reg Blk */ - u32 pm1b_control_block; /* 32-bit port address of Power Mgt 1b Control Reg Blk */ - u32 pm2_control_block; /* 32-bit port address of Power Mgt 2 Control Reg Blk */ - u32 pm_timer_block; /* 32-bit port address of Power Mgt Timer Ctrl Reg Blk */ - u32 gpe0_block; /* 32-bit port address of General Purpose Event 0 Reg Blk */ - u32 gpe1_block; /* 32-bit port address of General Purpose Event 1 Reg Blk */ - u8 pm1_event_length; /* Byte Length of ports at pm1x_event_block */ - u8 pm1_control_length; /* Byte Length of ports at pm1x_control_block */ - u8 pm2_control_length; /* Byte Length of ports at pm2_control_block */ - u8 pm_timer_length; /* Byte Length of ports at pm_timer_block */ - u8 gpe0_block_length; /* Byte Length of ports at gpe0_block */ - u8 gpe1_block_length; /* Byte Length of ports at gpe1_block */ - u8 gpe1_base; /* Offset in GPE number space where GPE1 events start */ - u8 cst_control; /* Support for the _CST object and C-States change notification */ - u16 c2_latency; /* Worst case HW latency to enter/exit C2 state */ - u16 c3_latency; /* Worst case HW latency to enter/exit C3 state */ - u16 flush_size; /* Processor memory cache line width, in bytes */ - u16 flush_stride; /* Number of flush strides that need to be read */ - u8 duty_offset; /* Processor duty cycle index in processor P_CNT reg */ - u8 duty_width; /* Processor duty cycle value bit width in P_CNT register */ - u8 day_alarm; /* Index to day-of-month alarm in RTC CMOS RAM */ - u8 month_alarm; /* Index to month-of-year alarm in RTC CMOS RAM */ - u8 century; /* Index to century in RTC CMOS RAM */ - u16 boot_flags; /* IA-PC Boot Architecture Flags (see below for individual flags) */ - u8 reserved; /* Reserved, must be zero */ - u32 flags; /* Miscellaneous flag bits (see below for individual flags) */ - struct acpi_generic_address reset_register; /* 64-bit address of the Reset register */ - u8 reset_value; /* Value to write to the reset_register port to reset the system */ - u16 arm_boot_flags; /* ARM-Specific Boot Flags (see below for individual flags) (ACPI 5.1) */ - u8 minor_revision; /* FADT Minor Revision (ACPI 5.1) */ - u64 Xfacs; /* 64-bit physical address of FACS */ - u64 Xdsdt; /* 64-bit physical address of DSDT */ - struct acpi_generic_address xpm1a_event_block; /* 64-bit Extended Power Mgt 1a Event Reg Blk address */ - struct acpi_generic_address xpm1b_event_block; /* 64-bit Extended Power Mgt 1b Event Reg Blk address */ - struct acpi_generic_address xpm1a_control_block; /* 64-bit Extended Power Mgt 1a Control Reg Blk address */ - struct acpi_generic_address xpm1b_control_block; /* 64-bit Extended Power Mgt 1b Control Reg Blk address */ - struct acpi_generic_address xpm2_control_block; /* 64-bit Extended Power Mgt 2 Control Reg Blk address */ - struct acpi_generic_address xpm_timer_block; /* 64-bit Extended Power Mgt Timer Ctrl Reg Blk address */ - struct acpi_generic_address xgpe0_block; /* 64-bit Extended General Purpose Event 0 Reg Blk address */ - struct acpi_generic_address xgpe1_block; /* 64-bit Extended General Purpose Event 1 Reg Blk address */ - struct acpi_generic_address sleep_control; /* 64-bit Sleep Control register (ACPI 5.0) */ - struct acpi_generic_address sleep_status; /* 64-bit Sleep Status register (ACPI 5.0) */ - u64 hypervisor_id; /* Hypervisor Vendor ID (ACPI 6.0) */ -}; - -/* Masks for FADT IA-PC Boot Architecture Flags (boot_flags) [Vx]=Introduced in this FADT revision */ - -#define ACPI_FADT_LEGACY_DEVICES (1) /* 00: [V2] System has LPC or ISA bus devices */ -#define ACPI_FADT_8042 (1<<1) /* 01: [V3] System has an 8042 controller on port 60/64 */ -#define ACPI_FADT_NO_VGA (1<<2) /* 02: [V4] It is not safe to probe for VGA hardware */ -#define ACPI_FADT_NO_MSI (1<<3) /* 03: [V4] Message Signaled Interrupts (MSI) must not be enabled */ -#define ACPI_FADT_NO_ASPM (1<<4) /* 04: [V4] PCIe ASPM control must not be enabled */ -#define ACPI_FADT_NO_CMOS_RTC (1<<5) /* 05: [V5] No CMOS real-time clock present */ - -#define FADT2_REVISION_ID 3 - -/* Masks for FADT ARM Boot Architecture Flags (arm_boot_flags) ACPI 5.1 */ - -#define ACPI_FADT_PSCI_COMPLIANT (1) /* 00: [V5+] PSCI 0.2+ is implemented */ -#define ACPI_FADT_PSCI_USE_HVC (1<<1) /* 01: [V5+] HVC must be used instead of SMC as the PSCI conduit */ - -/* Masks for FADT flags */ - -#define ACPI_FADT_WBINVD (1) /* 00: [V1] The WBINVD instruction works properly */ -#define ACPI_FADT_WBINVD_FLUSH (1<<1) /* 01: [V1] WBINVD flushes but does not invalidate caches */ -#define ACPI_FADT_C1_SUPPORTED (1<<2) /* 02: [V1] All processors support C1 state */ -#define ACPI_FADT_C2_MP_SUPPORTED (1<<3) /* 03: [V1] C2 state works on MP system */ -#define ACPI_FADT_POWER_BUTTON (1<<4) /* 04: [V1] Power button is handled as a control method device */ -#define ACPI_FADT_SLEEP_BUTTON (1<<5) /* 05: [V1] Sleep button is handled as a control method device */ -#define ACPI_FADT_FIXED_RTC (1<<6) /* 06: [V1] RTC wakeup status is not in fixed register space */ -#define ACPI_FADT_S4_RTC_WAKE (1<<7) /* 07: [V1] RTC alarm can wake system from S4 */ -#define ACPI_FADT_32BIT_TIMER (1<<8) /* 08: [V1] ACPI timer width is 32-bit (0=24-bit) */ -#define ACPI_FADT_DOCKING_SUPPORTED (1<<9) /* 09: [V1] Docking supported */ -#define ACPI_FADT_RESET_REGISTER (1<<10) /* 10: [V2] System reset via the FADT RESET_REG supported */ -#define ACPI_FADT_SEALED_CASE (1<<11) /* 11: [V3] No internal expansion capabilities and case is sealed */ -#define ACPI_FADT_HEADLESS (1<<12) /* 12: [V3] No local video capabilities or local input devices */ -#define ACPI_FADT_SLEEP_TYPE (1<<13) /* 13: [V3] Must execute native instruction after writing SLP_TYPx register */ -#define ACPI_FADT_PCI_EXPRESS_WAKE (1<<14) /* 14: [V4] System supports PCIEXP_WAKE (STS/EN) bits (ACPI 3.0) */ -#define ACPI_FADT_PLATFORM_CLOCK (1<<15) /* 15: [V4] OSPM should use platform-provided timer (ACPI 3.0) */ -#define ACPI_FADT_S4_RTC_VALID (1<<16) /* 16: [V4] Contents of RTC_STS valid after S4 wake (ACPI 3.0) */ -#define ACPI_FADT_REMOTE_POWER_ON (1<<17) /* 17: [V4] System is compatible with remote power on (ACPI 3.0) */ -#define ACPI_FADT_APIC_CLUSTER (1<<18) /* 18: [V4] All local APICs must use cluster model (ACPI 3.0) */ -#define ACPI_FADT_APIC_PHYSICAL (1<<19) /* 19: [V4] All local xAPICs must use physical dest mode (ACPI 3.0) */ -#define ACPI_FADT_HW_REDUCED (1<<20) /* 20: [V5] ACPI hardware is not implemented (ACPI 5.0) */ -#define ACPI_FADT_LOW_POWER_S0 (1<<21) /* 21: [V5] S0 power savings are equal or better than S3 (ACPI 5.0) */ - -/* Values for preferred_profile (Preferred Power Management Profiles) */ - -enum acpi_preferred_pm_profiles { - PM_UNSPECIFIED = 0, - PM_DESKTOP = 1, - PM_MOBILE = 2, - PM_WORKSTATION = 3, - PM_ENTERPRISE_SERVER = 4, - PM_SOHO_SERVER = 5, - PM_APPLIANCE_PC = 6, - PM_PERFORMANCE_SERVER = 7, - PM_TABLET = 8 -}; - -/* Values for sleep_status and sleep_control registers (V5+ FADT) */ - -#define ACPI_X_WAKE_STATUS 0x80 -#define ACPI_X_SLEEP_TYPE_MASK 0x1C -#define ACPI_X_SLEEP_TYPE_POSITION 0x02 -#define ACPI_X_SLEEP_ENABLE 0x20 - -/* Reset to default packing */ - -#pragma pack() - -/* - * Internal table-related structures - */ -union acpi_name_union { - u32 integer; - char ascii[4]; -}; - -/* Internal ACPI Table Descriptor. One per ACPI table. */ - -struct acpi_table_desc { - acpi_physical_address address; - struct acpi_table_header *pointer; - u32 length; /* Length fixed at 32 bits (fixed in table header) */ - union acpi_name_union signature; - acpi_owner_id owner_id; - u8 flags; -}; - -/* Masks for Flags field above */ - -#define ACPI_TABLE_ORIGIN_EXTERNAL_VIRTUAL (0) /* Virtual address, external maintained */ -#define ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL (1) /* Physical address, internally mapped */ -#define ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL (2) /* Virtual address, internallly allocated */ -#define ACPI_TABLE_ORIGIN_MASK (3) -#define ACPI_TABLE_IS_LOADED (8) - -/* - * Get the remaining ACPI tables - */ -#include -#include -#include - -/* Macros used to generate offsets to specific table fields */ - -#define ACPI_FADT_OFFSET(f) (u16) ACPI_OFFSET (struct acpi_table_fadt, f) - -/* - * Sizes of the various flavors of FADT. We need to look closely - * at the FADT length because the version number essentially tells - * us nothing because of many BIOS bugs where the version does not - * match the expected length. In other words, the length of the - * FADT is the bottom line as to what the version really is. - * - * For reference, the values below are as follows: - * FADT V1 size: 0x074 - * FADT V2 size: 0x084 - * FADT V3 size: 0x0F4 - * FADT V4 size: 0x0F4 - * FADT V5 size: 0x10C - * FADT V6 size: 0x114 - */ -#define ACPI_FADT_V1_SIZE (u32) (ACPI_FADT_OFFSET (flags) + 4) -#define ACPI_FADT_V2_SIZE (u32) (ACPI_FADT_OFFSET (minor_revision) + 1) -#define ACPI_FADT_V3_SIZE (u32) (ACPI_FADT_OFFSET (sleep_control)) -#define ACPI_FADT_V5_SIZE (u32) (ACPI_FADT_OFFSET (hypervisor_id)) -#define ACPI_FADT_V6_SIZE (u32) (sizeof (struct acpi_table_fadt)) - -#define ACPI_FADT_CONFORMANCE "ACPI 6.1 (FADT version 6)" - -#endif /* __ACTBL_H__ */ diff --git a/src/linux/include/acpi/actbl1.h b/src/linux/include/acpi/actbl1.h deleted file mode 100644 index 796d6ba..0000000 --- a/src/linux/include/acpi/actbl1.h +++ /dev/null @@ -1,1271 +0,0 @@ -/****************************************************************************** - * - * Name: actbl1.h - Additional ACPI table definitions - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACTBL1_H__ -#define __ACTBL1_H__ - -/******************************************************************************* - * - * Additional ACPI Tables (1) - * - * These tables are not consumed directly by the ACPICA subsystem, but are - * included here to support device drivers and the AML disassembler. - * - * The tables in this file are fully defined within the ACPI specification. - * - ******************************************************************************/ - -/* - * Values for description table header signatures for tables defined in this - * file. Useful because they make it more difficult to inadvertently type in - * the wrong signature. - */ -#define ACPI_SIG_BERT "BERT" /* Boot Error Record Table */ -#define ACPI_SIG_CPEP "CPEP" /* Corrected Platform Error Polling table */ -#define ACPI_SIG_ECDT "ECDT" /* Embedded Controller Boot Resources Table */ -#define ACPI_SIG_EINJ "EINJ" /* Error Injection table */ -#define ACPI_SIG_ERST "ERST" /* Error Record Serialization Table */ -#define ACPI_SIG_HEST "HEST" /* Hardware Error Source Table */ -#define ACPI_SIG_MADT "APIC" /* Multiple APIC Description Table */ -#define ACPI_SIG_MSCT "MSCT" /* Maximum System Characteristics Table */ -#define ACPI_SIG_SBST "SBST" /* Smart Battery Specification Table */ -#define ACPI_SIG_SLIT "SLIT" /* System Locality Distance Information Table */ -#define ACPI_SIG_SRAT "SRAT" /* System Resource Affinity Table */ -#define ACPI_SIG_NFIT "NFIT" /* NVDIMM Firmware Interface Table */ - -/* - * All tables must be byte-packed to match the ACPI specification, since - * the tables are provided by the system BIOS. - */ -#pragma pack(1) - -/* - * Note: C bitfields are not used for this reason: - * - * "Bitfields are great and easy to read, but unfortunately the C language - * does not specify the layout of bitfields in memory, which means they are - * essentially useless for dealing with packed data in on-disk formats or - * binary wire protocols." (Or ACPI tables and buffers.) "If you ask me, - * this decision was a design error in C. Ritchie could have picked an order - * and stuck with it." Norman Ramsey. - * See http://stackoverflow.com/a/1053662/41661 - */ - -/******************************************************************************* - * - * Common subtable headers - * - ******************************************************************************/ - -/* Generic subtable header (used in MADT, SRAT, etc.) */ - -struct acpi_subtable_header { - u8 type; - u8 length; -}; - -/* Subtable header for WHEA tables (EINJ, ERST, WDAT) */ - -struct acpi_whea_header { - u8 action; - u8 instruction; - u8 flags; - u8 reserved; - struct acpi_generic_address register_region; - u64 value; /* Value used with Read/Write register */ - u64 mask; /* Bitmask required for this register instruction */ -}; - -/******************************************************************************* - * - * BERT - Boot Error Record Table (ACPI 4.0) - * Version 1 - * - ******************************************************************************/ - -struct acpi_table_bert { - struct acpi_table_header header; /* Common ACPI table header */ - u32 region_length; /* Length of the boot error region */ - u64 address; /* Physical address of the error region */ -}; - -/* Boot Error Region (not a subtable, pointed to by Address field above) */ - -struct acpi_bert_region { - u32 block_status; /* Type of error information */ - u32 raw_data_offset; /* Offset to raw error data */ - u32 raw_data_length; /* Length of raw error data */ - u32 data_length; /* Length of generic error data */ - u32 error_severity; /* Severity code */ -}; - -/* Values for block_status flags above */ - -#define ACPI_BERT_UNCORRECTABLE (1) -#define ACPI_BERT_CORRECTABLE (1<<1) -#define ACPI_BERT_MULTIPLE_UNCORRECTABLE (1<<2) -#define ACPI_BERT_MULTIPLE_CORRECTABLE (1<<3) -#define ACPI_BERT_ERROR_ENTRY_COUNT (0xFF<<4) /* 8 bits, error count */ - -/* Values for error_severity above */ - -enum acpi_bert_error_severity { - ACPI_BERT_ERROR_CORRECTABLE = 0, - ACPI_BERT_ERROR_FATAL = 1, - ACPI_BERT_ERROR_CORRECTED = 2, - ACPI_BERT_ERROR_NONE = 3, - ACPI_BERT_ERROR_RESERVED = 4 /* 4 and greater are reserved */ -}; - -/* - * Note: The generic error data that follows the error_severity field above - * uses the struct acpi_hest_generic_data defined under the HEST table below - */ - -/******************************************************************************* - * - * CPEP - Corrected Platform Error Polling table (ACPI 4.0) - * Version 1 - * - ******************************************************************************/ - -struct acpi_table_cpep { - struct acpi_table_header header; /* Common ACPI table header */ - u64 reserved; -}; - -/* Subtable */ - -struct acpi_cpep_polling { - struct acpi_subtable_header header; - u8 id; /* Processor ID */ - u8 eid; /* Processor EID */ - u32 interval; /* Polling interval (msec) */ -}; - -/******************************************************************************* - * - * ECDT - Embedded Controller Boot Resources Table - * Version 1 - * - ******************************************************************************/ - -struct acpi_table_ecdt { - struct acpi_table_header header; /* Common ACPI table header */ - struct acpi_generic_address control; /* Address of EC command/status register */ - struct acpi_generic_address data; /* Address of EC data register */ - u32 uid; /* Unique ID - must be same as the EC _UID method */ - u8 gpe; /* The GPE for the EC */ - u8 id[1]; /* Full namepath of the EC in the ACPI namespace */ -}; - -/******************************************************************************* - * - * EINJ - Error Injection Table (ACPI 4.0) - * Version 1 - * - ******************************************************************************/ - -struct acpi_table_einj { - struct acpi_table_header header; /* Common ACPI table header */ - u32 header_length; - u8 flags; - u8 reserved[3]; - u32 entries; -}; - -/* EINJ Injection Instruction Entries (actions) */ - -struct acpi_einj_entry { - struct acpi_whea_header whea_header; /* Common header for WHEA tables */ -}; - -/* Masks for Flags field above */ - -#define ACPI_EINJ_PRESERVE (1) - -/* Values for Action field above */ - -enum acpi_einj_actions { - ACPI_EINJ_BEGIN_OPERATION = 0, - ACPI_EINJ_GET_TRIGGER_TABLE = 1, - ACPI_EINJ_SET_ERROR_TYPE = 2, - ACPI_EINJ_GET_ERROR_TYPE = 3, - ACPI_EINJ_END_OPERATION = 4, - ACPI_EINJ_EXECUTE_OPERATION = 5, - ACPI_EINJ_CHECK_BUSY_STATUS = 6, - ACPI_EINJ_GET_COMMAND_STATUS = 7, - ACPI_EINJ_SET_ERROR_TYPE_WITH_ADDRESS = 8, - ACPI_EINJ_GET_EXECUTE_TIMINGS = 9, - ACPI_EINJ_ACTION_RESERVED = 10, /* 10 and greater are reserved */ - ACPI_EINJ_TRIGGER_ERROR = 0xFF /* Except for this value */ -}; - -/* Values for Instruction field above */ - -enum acpi_einj_instructions { - ACPI_EINJ_READ_REGISTER = 0, - ACPI_EINJ_READ_REGISTER_VALUE = 1, - ACPI_EINJ_WRITE_REGISTER = 2, - ACPI_EINJ_WRITE_REGISTER_VALUE = 3, - ACPI_EINJ_NOOP = 4, - ACPI_EINJ_FLUSH_CACHELINE = 5, - ACPI_EINJ_INSTRUCTION_RESERVED = 6 /* 6 and greater are reserved */ -}; - -struct acpi_einj_error_type_with_addr { - u32 error_type; - u32 vendor_struct_offset; - u32 flags; - u32 apic_id; - u64 address; - u64 range; - u32 pcie_id; -}; - -struct acpi_einj_vendor { - u32 length; - u32 pcie_id; - u16 vendor_id; - u16 device_id; - u8 revision_id; - u8 reserved[3]; -}; - -/* EINJ Trigger Error Action Table */ - -struct acpi_einj_trigger { - u32 header_size; - u32 revision; - u32 table_size; - u32 entry_count; -}; - -/* Command status return values */ - -enum acpi_einj_command_status { - ACPI_EINJ_SUCCESS = 0, - ACPI_EINJ_FAILURE = 1, - ACPI_EINJ_INVALID_ACCESS = 2, - ACPI_EINJ_STATUS_RESERVED = 3 /* 3 and greater are reserved */ -}; - -/* Error types returned from ACPI_EINJ_GET_ERROR_TYPE (bitfield) */ - -#define ACPI_EINJ_PROCESSOR_CORRECTABLE (1) -#define ACPI_EINJ_PROCESSOR_UNCORRECTABLE (1<<1) -#define ACPI_EINJ_PROCESSOR_FATAL (1<<2) -#define ACPI_EINJ_MEMORY_CORRECTABLE (1<<3) -#define ACPI_EINJ_MEMORY_UNCORRECTABLE (1<<4) -#define ACPI_EINJ_MEMORY_FATAL (1<<5) -#define ACPI_EINJ_PCIX_CORRECTABLE (1<<6) -#define ACPI_EINJ_PCIX_UNCORRECTABLE (1<<7) -#define ACPI_EINJ_PCIX_FATAL (1<<8) -#define ACPI_EINJ_PLATFORM_CORRECTABLE (1<<9) -#define ACPI_EINJ_PLATFORM_UNCORRECTABLE (1<<10) -#define ACPI_EINJ_PLATFORM_FATAL (1<<11) -#define ACPI_EINJ_VENDOR_DEFINED (1<<31) - -/******************************************************************************* - * - * ERST - Error Record Serialization Table (ACPI 4.0) - * Version 1 - * - ******************************************************************************/ - -struct acpi_table_erst { - struct acpi_table_header header; /* Common ACPI table header */ - u32 header_length; - u32 reserved; - u32 entries; -}; - -/* ERST Serialization Entries (actions) */ - -struct acpi_erst_entry { - struct acpi_whea_header whea_header; /* Common header for WHEA tables */ -}; - -/* Masks for Flags field above */ - -#define ACPI_ERST_PRESERVE (1) - -/* Values for Action field above */ - -enum acpi_erst_actions { - ACPI_ERST_BEGIN_WRITE = 0, - ACPI_ERST_BEGIN_READ = 1, - ACPI_ERST_BEGIN_CLEAR = 2, - ACPI_ERST_END = 3, - ACPI_ERST_SET_RECORD_OFFSET = 4, - ACPI_ERST_EXECUTE_OPERATION = 5, - ACPI_ERST_CHECK_BUSY_STATUS = 6, - ACPI_ERST_GET_COMMAND_STATUS = 7, - ACPI_ERST_GET_RECORD_ID = 8, - ACPI_ERST_SET_RECORD_ID = 9, - ACPI_ERST_GET_RECORD_COUNT = 10, - ACPI_ERST_BEGIN_DUMMY_WRIITE = 11, - ACPI_ERST_NOT_USED = 12, - ACPI_ERST_GET_ERROR_RANGE = 13, - ACPI_ERST_GET_ERROR_LENGTH = 14, - ACPI_ERST_GET_ERROR_ATTRIBUTES = 15, - ACPI_ERST_EXECUTE_TIMINGS = 16, - ACPI_ERST_ACTION_RESERVED = 17 /* 17 and greater are reserved */ -}; - -/* Values for Instruction field above */ - -enum acpi_erst_instructions { - ACPI_ERST_READ_REGISTER = 0, - ACPI_ERST_READ_REGISTER_VALUE = 1, - ACPI_ERST_WRITE_REGISTER = 2, - ACPI_ERST_WRITE_REGISTER_VALUE = 3, - ACPI_ERST_NOOP = 4, - ACPI_ERST_LOAD_VAR1 = 5, - ACPI_ERST_LOAD_VAR2 = 6, - ACPI_ERST_STORE_VAR1 = 7, - ACPI_ERST_ADD = 8, - ACPI_ERST_SUBTRACT = 9, - ACPI_ERST_ADD_VALUE = 10, - ACPI_ERST_SUBTRACT_VALUE = 11, - ACPI_ERST_STALL = 12, - ACPI_ERST_STALL_WHILE_TRUE = 13, - ACPI_ERST_SKIP_NEXT_IF_TRUE = 14, - ACPI_ERST_GOTO = 15, - ACPI_ERST_SET_SRC_ADDRESS_BASE = 16, - ACPI_ERST_SET_DST_ADDRESS_BASE = 17, - ACPI_ERST_MOVE_DATA = 18, - ACPI_ERST_INSTRUCTION_RESERVED = 19 /* 19 and greater are reserved */ -}; - -/* Command status return values */ - -enum acpi_erst_command_status { - ACPI_ERST_SUCESS = 0, - ACPI_ERST_NO_SPACE = 1, - ACPI_ERST_NOT_AVAILABLE = 2, - ACPI_ERST_FAILURE = 3, - ACPI_ERST_RECORD_EMPTY = 4, - ACPI_ERST_NOT_FOUND = 5, - ACPI_ERST_STATUS_RESERVED = 6 /* 6 and greater are reserved */ -}; - -/* Error Record Serialization Information */ - -struct acpi_erst_info { - u16 signature; /* Should be "ER" */ - u8 data[48]; -}; - -/******************************************************************************* - * - * HEST - Hardware Error Source Table (ACPI 4.0) - * Version 1 - * - ******************************************************************************/ - -struct acpi_table_hest { - struct acpi_table_header header; /* Common ACPI table header */ - u32 error_source_count; -}; - -/* HEST subtable header */ - -struct acpi_hest_header { - u16 type; - u16 source_id; -}; - -/* Values for Type field above for subtables */ - -enum acpi_hest_types { - ACPI_HEST_TYPE_IA32_CHECK = 0, - ACPI_HEST_TYPE_IA32_CORRECTED_CHECK = 1, - ACPI_HEST_TYPE_IA32_NMI = 2, - ACPI_HEST_TYPE_NOT_USED3 = 3, - ACPI_HEST_TYPE_NOT_USED4 = 4, - ACPI_HEST_TYPE_NOT_USED5 = 5, - ACPI_HEST_TYPE_AER_ROOT_PORT = 6, - ACPI_HEST_TYPE_AER_ENDPOINT = 7, - ACPI_HEST_TYPE_AER_BRIDGE = 8, - ACPI_HEST_TYPE_GENERIC_ERROR = 9, - ACPI_HEST_TYPE_GENERIC_ERROR_V2 = 10, - ACPI_HEST_TYPE_RESERVED = 11 /* 11 and greater are reserved */ -}; - -/* - * HEST substructures contained in subtables - */ - -/* - * IA32 Error Bank(s) - Follows the struct acpi_hest_ia_machine_check and - * struct acpi_hest_ia_corrected structures. - */ -struct acpi_hest_ia_error_bank { - u8 bank_number; - u8 clear_status_on_init; - u8 status_format; - u8 reserved; - u32 control_register; - u64 control_data; - u32 status_register; - u32 address_register; - u32 misc_register; -}; - -/* Common HEST sub-structure for PCI/AER structures below (6,7,8) */ - -struct acpi_hest_aer_common { - u16 reserved1; - u8 flags; - u8 enabled; - u32 records_to_preallocate; - u32 max_sections_per_record; - u32 bus; /* Bus and Segment numbers */ - u16 device; - u16 function; - u16 device_control; - u16 reserved2; - u32 uncorrectable_mask; - u32 uncorrectable_severity; - u32 correctable_mask; - u32 advanced_capabilities; -}; - -/* Masks for HEST Flags fields */ - -#define ACPI_HEST_FIRMWARE_FIRST (1) -#define ACPI_HEST_GLOBAL (1<<1) - -/* - * Macros to access the bus/segment numbers in Bus field above: - * Bus number is encoded in bits 7:0 - * Segment number is encoded in bits 23:8 - */ -#define ACPI_HEST_BUS(bus) ((bus) & 0xFF) -#define ACPI_HEST_SEGMENT(bus) (((bus) >> 8) & 0xFFFF) - -/* Hardware Error Notification */ - -struct acpi_hest_notify { - u8 type; - u8 length; - u16 config_write_enable; - u32 poll_interval; - u32 vector; - u32 polling_threshold_value; - u32 polling_threshold_window; - u32 error_threshold_value; - u32 error_threshold_window; -}; - -/* Values for Notify Type field above */ - -enum acpi_hest_notify_types { - ACPI_HEST_NOTIFY_POLLED = 0, - ACPI_HEST_NOTIFY_EXTERNAL = 1, - ACPI_HEST_NOTIFY_LOCAL = 2, - ACPI_HEST_NOTIFY_SCI = 3, - ACPI_HEST_NOTIFY_NMI = 4, - ACPI_HEST_NOTIFY_CMCI = 5, /* ACPI 5.0 */ - ACPI_HEST_NOTIFY_MCE = 6, /* ACPI 5.0 */ - ACPI_HEST_NOTIFY_GPIO = 7, /* ACPI 6.0 */ - ACPI_HEST_NOTIFY_SEA = 8, /* ACPI 6.1 */ - ACPI_HEST_NOTIFY_SEI = 9, /* ACPI 6.1 */ - ACPI_HEST_NOTIFY_GSIV = 10, /* ACPI 6.1 */ - ACPI_HEST_NOTIFY_RESERVED = 11 /* 11 and greater are reserved */ -}; - -/* Values for config_write_enable bitfield above */ - -#define ACPI_HEST_TYPE (1) -#define ACPI_HEST_POLL_INTERVAL (1<<1) -#define ACPI_HEST_POLL_THRESHOLD_VALUE (1<<2) -#define ACPI_HEST_POLL_THRESHOLD_WINDOW (1<<3) -#define ACPI_HEST_ERR_THRESHOLD_VALUE (1<<4) -#define ACPI_HEST_ERR_THRESHOLD_WINDOW (1<<5) - -/* - * HEST subtables - */ - -/* 0: IA32 Machine Check Exception */ - -struct acpi_hest_ia_machine_check { - struct acpi_hest_header header; - u16 reserved1; - u8 flags; - u8 enabled; - u32 records_to_preallocate; - u32 max_sections_per_record; - u64 global_capability_data; - u64 global_control_data; - u8 num_hardware_banks; - u8 reserved3[7]; -}; - -/* 1: IA32 Corrected Machine Check */ - -struct acpi_hest_ia_corrected { - struct acpi_hest_header header; - u16 reserved1; - u8 flags; - u8 enabled; - u32 records_to_preallocate; - u32 max_sections_per_record; - struct acpi_hest_notify notify; - u8 num_hardware_banks; - u8 reserved2[3]; -}; - -/* 2: IA32 Non-Maskable Interrupt */ - -struct acpi_hest_ia_nmi { - struct acpi_hest_header header; - u32 reserved; - u32 records_to_preallocate; - u32 max_sections_per_record; - u32 max_raw_data_length; -}; - -/* 3,4,5: Not used */ - -/* 6: PCI Express Root Port AER */ - -struct acpi_hest_aer_root { - struct acpi_hest_header header; - struct acpi_hest_aer_common aer; - u32 root_error_command; -}; - -/* 7: PCI Express AER (AER Endpoint) */ - -struct acpi_hest_aer { - struct acpi_hest_header header; - struct acpi_hest_aer_common aer; -}; - -/* 8: PCI Express/PCI-X Bridge AER */ - -struct acpi_hest_aer_bridge { - struct acpi_hest_header header; - struct acpi_hest_aer_common aer; - u32 uncorrectable_mask2; - u32 uncorrectable_severity2; - u32 advanced_capabilities2; -}; - -/* 9: Generic Hardware Error Source */ - -struct acpi_hest_generic { - struct acpi_hest_header header; - u16 related_source_id; - u8 reserved; - u8 enabled; - u32 records_to_preallocate; - u32 max_sections_per_record; - u32 max_raw_data_length; - struct acpi_generic_address error_status_address; - struct acpi_hest_notify notify; - u32 error_block_length; -}; - -/* 10: Generic Hardware Error Source, version 2 */ - -struct acpi_hest_generic_v2 { - struct acpi_hest_header header; - u16 related_source_id; - u8 reserved; - u8 enabled; - u32 records_to_preallocate; - u32 max_sections_per_record; - u32 max_raw_data_length; - struct acpi_generic_address error_status_address; - struct acpi_hest_notify notify; - u32 error_block_length; - struct acpi_generic_address read_ack_register; - u64 read_ack_preserve; - u64 read_ack_write; -}; - -/* Generic Error Status block */ - -struct acpi_hest_generic_status { - u32 block_status; - u32 raw_data_offset; - u32 raw_data_length; - u32 data_length; - u32 error_severity; -}; - -/* Values for block_status flags above */ - -#define ACPI_HEST_UNCORRECTABLE (1) -#define ACPI_HEST_CORRECTABLE (1<<1) -#define ACPI_HEST_MULTIPLE_UNCORRECTABLE (1<<2) -#define ACPI_HEST_MULTIPLE_CORRECTABLE (1<<3) -#define ACPI_HEST_ERROR_ENTRY_COUNT (0xFF<<4) /* 8 bits, error count */ - -/* Generic Error Data entry */ - -struct acpi_hest_generic_data { - u8 section_type[16]; - u32 error_severity; - u16 revision; - u8 validation_bits; - u8 flags; - u32 error_data_length; - u8 fru_id[16]; - u8 fru_text[20]; -}; - -/* Extension for revision 0x0300 */ - -struct acpi_hest_generic_data_v300 { - u8 section_type[16]; - u32 error_severity; - u16 revision; - u8 validation_bits; - u8 flags; - u32 error_data_length; - u8 fru_id[16]; - u8 fru_text[20]; - u64 time_stamp; -}; - -/* Values for error_severity above */ - -#define ACPI_HEST_GEN_ERROR_RECOVERABLE 0 -#define ACPI_HEST_GEN_ERROR_FATAL 1 -#define ACPI_HEST_GEN_ERROR_CORRECTED 2 -#define ACPI_HEST_GEN_ERROR_NONE 3 - -/* Flags for validation_bits above */ - -#define ACPI_HEST_GEN_VALID_FRU_ID (1) -#define ACPI_HEST_GEN_VALID_FRU_STRING (1<<1) -#define ACPI_HEST_GEN_VALID_TIMESTAMP (1<<2) - -/******************************************************************************* - * - * MADT - Multiple APIC Description Table - * Version 3 - * - ******************************************************************************/ - -struct acpi_table_madt { - struct acpi_table_header header; /* Common ACPI table header */ - u32 address; /* Physical address of local APIC */ - u32 flags; -}; - -/* Masks for Flags field above */ - -#define ACPI_MADT_PCAT_COMPAT (1) /* 00: System also has dual 8259s */ - -/* Values for PCATCompat flag */ - -#define ACPI_MADT_DUAL_PIC 0 -#define ACPI_MADT_MULTIPLE_APIC 1 - -/* Values for MADT subtable type in struct acpi_subtable_header */ - -enum acpi_madt_type { - ACPI_MADT_TYPE_LOCAL_APIC = 0, - ACPI_MADT_TYPE_IO_APIC = 1, - ACPI_MADT_TYPE_INTERRUPT_OVERRIDE = 2, - ACPI_MADT_TYPE_NMI_SOURCE = 3, - ACPI_MADT_TYPE_LOCAL_APIC_NMI = 4, - ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE = 5, - ACPI_MADT_TYPE_IO_SAPIC = 6, - ACPI_MADT_TYPE_LOCAL_SAPIC = 7, - ACPI_MADT_TYPE_INTERRUPT_SOURCE = 8, - ACPI_MADT_TYPE_LOCAL_X2APIC = 9, - ACPI_MADT_TYPE_LOCAL_X2APIC_NMI = 10, - ACPI_MADT_TYPE_GENERIC_INTERRUPT = 11, - ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR = 12, - ACPI_MADT_TYPE_GENERIC_MSI_FRAME = 13, - ACPI_MADT_TYPE_GENERIC_REDISTRIBUTOR = 14, - ACPI_MADT_TYPE_GENERIC_TRANSLATOR = 15, - ACPI_MADT_TYPE_RESERVED = 16 /* 16 and greater are reserved */ -}; - -/* - * MADT Subtables, correspond to Type in struct acpi_subtable_header - */ - -/* 0: Processor Local APIC */ - -struct acpi_madt_local_apic { - struct acpi_subtable_header header; - u8 processor_id; /* ACPI processor id */ - u8 id; /* Processor's local APIC id */ - u32 lapic_flags; -}; - -/* 1: IO APIC */ - -struct acpi_madt_io_apic { - struct acpi_subtable_header header; - u8 id; /* I/O APIC ID */ - u8 reserved; /* reserved - must be zero */ - u32 address; /* APIC physical address */ - u32 global_irq_base; /* Global system interrupt where INTI lines start */ -}; - -/* 2: Interrupt Override */ - -struct acpi_madt_interrupt_override { - struct acpi_subtable_header header; - u8 bus; /* 0 - ISA */ - u8 source_irq; /* Interrupt source (IRQ) */ - u32 global_irq; /* Global system interrupt */ - u16 inti_flags; -}; - -/* 3: NMI Source */ - -struct acpi_madt_nmi_source { - struct acpi_subtable_header header; - u16 inti_flags; - u32 global_irq; /* Global system interrupt */ -}; - -/* 4: Local APIC NMI */ - -struct acpi_madt_local_apic_nmi { - struct acpi_subtable_header header; - u8 processor_id; /* ACPI processor id */ - u16 inti_flags; - u8 lint; /* LINTn to which NMI is connected */ -}; - -/* 5: Address Override */ - -struct acpi_madt_local_apic_override { - struct acpi_subtable_header header; - u16 reserved; /* Reserved, must be zero */ - u64 address; /* APIC physical address */ -}; - -/* 6: I/O Sapic */ - -struct acpi_madt_io_sapic { - struct acpi_subtable_header header; - u8 id; /* I/O SAPIC ID */ - u8 reserved; /* Reserved, must be zero */ - u32 global_irq_base; /* Global interrupt for SAPIC start */ - u64 address; /* SAPIC physical address */ -}; - -/* 7: Local Sapic */ - -struct acpi_madt_local_sapic { - struct acpi_subtable_header header; - u8 processor_id; /* ACPI processor id */ - u8 id; /* SAPIC ID */ - u8 eid; /* SAPIC EID */ - u8 reserved[3]; /* Reserved, must be zero */ - u32 lapic_flags; - u32 uid; /* Numeric UID - ACPI 3.0 */ - char uid_string[1]; /* String UID - ACPI 3.0 */ -}; - -/* 8: Platform Interrupt Source */ - -struct acpi_madt_interrupt_source { - struct acpi_subtable_header header; - u16 inti_flags; - u8 type; /* 1=PMI, 2=INIT, 3=corrected */ - u8 id; /* Processor ID */ - u8 eid; /* Processor EID */ - u8 io_sapic_vector; /* Vector value for PMI interrupts */ - u32 global_irq; /* Global system interrupt */ - u32 flags; /* Interrupt Source Flags */ -}; - -/* Masks for Flags field above */ - -#define ACPI_MADT_CPEI_OVERRIDE (1) - -/* 9: Processor Local X2APIC (ACPI 4.0) */ - -struct acpi_madt_local_x2apic { - struct acpi_subtable_header header; - u16 reserved; /* reserved - must be zero */ - u32 local_apic_id; /* Processor x2APIC ID */ - u32 lapic_flags; - u32 uid; /* ACPI processor UID */ -}; - -/* 10: Local X2APIC NMI (ACPI 4.0) */ - -struct acpi_madt_local_x2apic_nmi { - struct acpi_subtable_header header; - u16 inti_flags; - u32 uid; /* ACPI processor UID */ - u8 lint; /* LINTn to which NMI is connected */ - u8 reserved[3]; /* reserved - must be zero */ -}; - -/* 11: Generic Interrupt (ACPI 5.0 + ACPI 6.0 changes) */ - -struct acpi_madt_generic_interrupt { - struct acpi_subtable_header header; - u16 reserved; /* reserved - must be zero */ - u32 cpu_interface_number; - u32 uid; - u32 flags; - u32 parking_version; - u32 performance_interrupt; - u64 parked_address; - u64 base_address; - u64 gicv_base_address; - u64 gich_base_address; - u32 vgic_interrupt; - u64 gicr_base_address; - u64 arm_mpidr; - u8 efficiency_class; - u8 reserved2[3]; -}; - -/* Masks for Flags field above */ - -/* ACPI_MADT_ENABLED (1) Processor is usable if set */ -#define ACPI_MADT_PERFORMANCE_IRQ_MODE (1<<1) /* 01: Performance Interrupt Mode */ -#define ACPI_MADT_VGIC_IRQ_MODE (1<<2) /* 02: VGIC Maintenance Interrupt mode */ - -/* 12: Generic Distributor (ACPI 5.0 + ACPI 6.0 changes) */ - -struct acpi_madt_generic_distributor { - struct acpi_subtable_header header; - u16 reserved; /* reserved - must be zero */ - u32 gic_id; - u64 base_address; - u32 global_irq_base; - u8 version; - u8 reserved2[3]; /* reserved - must be zero */ -}; - -/* Values for Version field above */ - -enum acpi_madt_gic_version { - ACPI_MADT_GIC_VERSION_NONE = 0, - ACPI_MADT_GIC_VERSION_V1 = 1, - ACPI_MADT_GIC_VERSION_V2 = 2, - ACPI_MADT_GIC_VERSION_V3 = 3, - ACPI_MADT_GIC_VERSION_V4 = 4, - ACPI_MADT_GIC_VERSION_RESERVED = 5 /* 5 and greater are reserved */ -}; - -/* 13: Generic MSI Frame (ACPI 5.1) */ - -struct acpi_madt_generic_msi_frame { - struct acpi_subtable_header header; - u16 reserved; /* reserved - must be zero */ - u32 msi_frame_id; - u64 base_address; - u32 flags; - u16 spi_count; - u16 spi_base; -}; - -/* Masks for Flags field above */ - -#define ACPI_MADT_OVERRIDE_SPI_VALUES (1) - -/* 14: Generic Redistributor (ACPI 5.1) */ - -struct acpi_madt_generic_redistributor { - struct acpi_subtable_header header; - u16 reserved; /* reserved - must be zero */ - u64 base_address; - u32 length; -}; - -/* 15: Generic Translator (ACPI 6.0) */ - -struct acpi_madt_generic_translator { - struct acpi_subtable_header header; - u16 reserved; /* reserved - must be zero */ - u32 translation_id; - u64 base_address; - u32 reserved2; -}; - -/* - * Common flags fields for MADT subtables - */ - -/* MADT Local APIC flags */ - -#define ACPI_MADT_ENABLED (1) /* 00: Processor is usable if set */ - -/* MADT MPS INTI flags (inti_flags) */ - -#define ACPI_MADT_POLARITY_MASK (3) /* 00-01: Polarity of APIC I/O input signals */ -#define ACPI_MADT_TRIGGER_MASK (3<<2) /* 02-03: Trigger mode of APIC input signals */ - -/* Values for MPS INTI flags */ - -#define ACPI_MADT_POLARITY_CONFORMS 0 -#define ACPI_MADT_POLARITY_ACTIVE_HIGH 1 -#define ACPI_MADT_POLARITY_RESERVED 2 -#define ACPI_MADT_POLARITY_ACTIVE_LOW 3 - -#define ACPI_MADT_TRIGGER_CONFORMS (0) -#define ACPI_MADT_TRIGGER_EDGE (1<<2) -#define ACPI_MADT_TRIGGER_RESERVED (2<<2) -#define ACPI_MADT_TRIGGER_LEVEL (3<<2) - -/******************************************************************************* - * - * MSCT - Maximum System Characteristics Table (ACPI 4.0) - * Version 1 - * - ******************************************************************************/ - -struct acpi_table_msct { - struct acpi_table_header header; /* Common ACPI table header */ - u32 proximity_offset; /* Location of proximity info struct(s) */ - u32 max_proximity_domains; /* Max number of proximity domains */ - u32 max_clock_domains; /* Max number of clock domains */ - u64 max_address; /* Max physical address in system */ -}; - -/* subtable - Maximum Proximity Domain Information. Version 1 */ - -struct acpi_msct_proximity { - u8 revision; - u8 length; - u32 range_start; /* Start of domain range */ - u32 range_end; /* End of domain range */ - u32 processor_capacity; - u64 memory_capacity; /* In bytes */ -}; - -/******************************************************************************* - * - * NFIT - NVDIMM Interface Table (ACPI 6.0+) - * Version 1 - * - ******************************************************************************/ - -struct acpi_table_nfit { - struct acpi_table_header header; /* Common ACPI table header */ - u32 reserved; /* Reserved, must be zero */ -}; - -/* Subtable header for NFIT */ - -struct acpi_nfit_header { - u16 type; - u16 length; -}; - -/* Values for subtable type in struct acpi_nfit_header */ - -enum acpi_nfit_type { - ACPI_NFIT_TYPE_SYSTEM_ADDRESS = 0, - ACPI_NFIT_TYPE_MEMORY_MAP = 1, - ACPI_NFIT_TYPE_INTERLEAVE = 2, - ACPI_NFIT_TYPE_SMBIOS = 3, - ACPI_NFIT_TYPE_CONTROL_REGION = 4, - ACPI_NFIT_TYPE_DATA_REGION = 5, - ACPI_NFIT_TYPE_FLUSH_ADDRESS = 6, - ACPI_NFIT_TYPE_RESERVED = 7 /* 7 and greater are reserved */ -}; - -/* - * NFIT Subtables - */ - -/* 0: System Physical Address Range Structure */ - -struct acpi_nfit_system_address { - struct acpi_nfit_header header; - u16 range_index; - u16 flags; - u32 reserved; /* Reseved, must be zero */ - u32 proximity_domain; - u8 range_guid[16]; - u64 address; - u64 length; - u64 memory_mapping; -}; - -/* Flags */ - -#define ACPI_NFIT_ADD_ONLINE_ONLY (1) /* 00: Add/Online Operation Only */ -#define ACPI_NFIT_PROXIMITY_VALID (1<<1) /* 01: Proximity Domain Valid */ - -/* Range Type GUIDs appear in the include/acuuid.h file */ - -/* 1: Memory Device to System Address Range Map Structure */ - -struct acpi_nfit_memory_map { - struct acpi_nfit_header header; - u32 device_handle; - u16 physical_id; - u16 region_id; - u16 range_index; - u16 region_index; - u64 region_size; - u64 region_offset; - u64 address; - u16 interleave_index; - u16 interleave_ways; - u16 flags; - u16 reserved; /* Reserved, must be zero */ -}; - -/* Flags */ - -#define ACPI_NFIT_MEM_SAVE_FAILED (1) /* 00: Last SAVE to Memory Device failed */ -#define ACPI_NFIT_MEM_RESTORE_FAILED (1<<1) /* 01: Last RESTORE from Memory Device failed */ -#define ACPI_NFIT_MEM_FLUSH_FAILED (1<<2) /* 02: Platform flush failed */ -#define ACPI_NFIT_MEM_NOT_ARMED (1<<3) /* 03: Memory Device is not armed */ -#define ACPI_NFIT_MEM_HEALTH_OBSERVED (1<<4) /* 04: Memory Device observed SMART/health events */ -#define ACPI_NFIT_MEM_HEALTH_ENABLED (1<<5) /* 05: SMART/health events enabled */ -#define ACPI_NFIT_MEM_MAP_FAILED (1<<6) /* 06: Mapping to SPA failed */ - -/* 2: Interleave Structure */ - -struct acpi_nfit_interleave { - struct acpi_nfit_header header; - u16 interleave_index; - u16 reserved; /* Reserved, must be zero */ - u32 line_count; - u32 line_size; - u32 line_offset[1]; /* Variable length */ -}; - -/* 3: SMBIOS Management Information Structure */ - -struct acpi_nfit_smbios { - struct acpi_nfit_header header; - u32 reserved; /* Reserved, must be zero */ - u8 data[1]; /* Variable length */ -}; - -/* 4: NVDIMM Control Region Structure */ - -struct acpi_nfit_control_region { - struct acpi_nfit_header header; - u16 region_index; - u16 vendor_id; - u16 device_id; - u16 revision_id; - u16 subsystem_vendor_id; - u16 subsystem_device_id; - u16 subsystem_revision_id; - u8 valid_fields; - u8 manufacturing_location; - u16 manufacturing_date; - u8 reserved[2]; /* Reserved, must be zero */ - u32 serial_number; - u16 code; - u16 windows; - u64 window_size; - u64 command_offset; - u64 command_size; - u64 status_offset; - u64 status_size; - u16 flags; - u8 reserved1[6]; /* Reserved, must be zero */ -}; - -/* Flags */ - -#define ACPI_NFIT_CONTROL_BUFFERED (1) /* Block Data Windows implementation is buffered */ - -/* valid_fields bits */ - -#define ACPI_NFIT_CONTROL_MFG_INFO_VALID (1) /* Manufacturing fields are valid */ - -/* 5: NVDIMM Block Data Window Region Structure */ - -struct acpi_nfit_data_region { - struct acpi_nfit_header header; - u16 region_index; - u16 windows; - u64 offset; - u64 size; - u64 capacity; - u64 start_address; -}; - -/* 6: Flush Hint Address Structure */ - -struct acpi_nfit_flush_address { - struct acpi_nfit_header header; - u32 device_handle; - u16 hint_count; - u8 reserved[6]; /* Reserved, must be zero */ - u64 hint_address[1]; /* Variable length */ -}; - -/******************************************************************************* - * - * SBST - Smart Battery Specification Table - * Version 1 - * - ******************************************************************************/ - -struct acpi_table_sbst { - struct acpi_table_header header; /* Common ACPI table header */ - u32 warning_level; - u32 low_level; - u32 critical_level; -}; - -/******************************************************************************* - * - * SLIT - System Locality Distance Information Table - * Version 1 - * - ******************************************************************************/ - -struct acpi_table_slit { - struct acpi_table_header header; /* Common ACPI table header */ - u64 locality_count; - u8 entry[1]; /* Real size = localities^2 */ -}; - -/******************************************************************************* - * - * SRAT - System Resource Affinity Table - * Version 3 - * - ******************************************************************************/ - -struct acpi_table_srat { - struct acpi_table_header header; /* Common ACPI table header */ - u32 table_revision; /* Must be value '1' */ - u64 reserved; /* Reserved, must be zero */ -}; - -/* Values for subtable type in struct acpi_subtable_header */ - -enum acpi_srat_type { - ACPI_SRAT_TYPE_CPU_AFFINITY = 0, - ACPI_SRAT_TYPE_MEMORY_AFFINITY = 1, - ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY = 2, - ACPI_SRAT_TYPE_GICC_AFFINITY = 3, - ACPI_SRAT_TYPE_RESERVED = 4 /* 4 and greater are reserved */ -}; - -/* - * SRAT Subtables, correspond to Type in struct acpi_subtable_header - */ - -/* 0: Processor Local APIC/SAPIC Affinity */ - -struct acpi_srat_cpu_affinity { - struct acpi_subtable_header header; - u8 proximity_domain_lo; - u8 apic_id; - u32 flags; - u8 local_sapic_eid; - u8 proximity_domain_hi[3]; - u32 clock_domain; -}; - -/* Flags */ - -#define ACPI_SRAT_CPU_USE_AFFINITY (1) /* 00: Use affinity structure */ - -/* 1: Memory Affinity */ - -struct acpi_srat_mem_affinity { - struct acpi_subtable_header header; - u32 proximity_domain; - u16 reserved; /* Reserved, must be zero */ - u64 base_address; - u64 length; - u32 reserved1; - u32 flags; - u64 reserved2; /* Reserved, must be zero */ -}; - -/* Flags */ - -#define ACPI_SRAT_MEM_ENABLED (1) /* 00: Use affinity structure */ -#define ACPI_SRAT_MEM_HOT_PLUGGABLE (1<<1) /* 01: Memory region is hot pluggable */ -#define ACPI_SRAT_MEM_NON_VOLATILE (1<<2) /* 02: Memory region is non-volatile */ - -/* 2: Processor Local X2_APIC Affinity (ACPI 4.0) */ - -struct acpi_srat_x2apic_cpu_affinity { - struct acpi_subtable_header header; - u16 reserved; /* Reserved, must be zero */ - u32 proximity_domain; - u32 apic_id; - u32 flags; - u32 clock_domain; - u32 reserved2; -}; - -/* Flags for struct acpi_srat_cpu_affinity and struct acpi_srat_x2apic_cpu_affinity */ - -#define ACPI_SRAT_CPU_ENABLED (1) /* 00: Use affinity structure */ - -/* 3: GICC Affinity (ACPI 5.1) */ - -struct acpi_srat_gicc_affinity { - struct acpi_subtable_header header; - u32 proximity_domain; - u32 acpi_processor_uid; - u32 flags; - u32 clock_domain; -}; - -/* Flags for struct acpi_srat_gicc_affinity */ - -#define ACPI_SRAT_GICC_ENABLED (1) /* 00: Use affinity structure */ - -/* Reset to default packing */ - -#pragma pack() - -#endif /* __ACTBL1_H__ */ diff --git a/src/linux/include/acpi/actbl2.h b/src/linux/include/acpi/actbl2.h deleted file mode 100644 index c93dbad..0000000 --- a/src/linux/include/acpi/actbl2.h +++ /dev/null @@ -1,1494 +0,0 @@ -/****************************************************************************** - * - * Name: actbl2.h - ACPI Table Definitions (tables not in ACPI spec) - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACTBL2_H__ -#define __ACTBL2_H__ - -/******************************************************************************* - * - * Additional ACPI Tables (2) - * - * These tables are not consumed directly by the ACPICA subsystem, but are - * included here to support device drivers and the AML disassembler. - * - * Generally, the tables in this file are defined by third-party specifications, - * and are not defined directly by the ACPI specification itself. - * - ******************************************************************************/ - -/* - * Values for description table header signatures for tables defined in this - * file. Useful because they make it more difficult to inadvertently type in - * the wrong signature. - */ -#define ACPI_SIG_ASF "ASF!" /* Alert Standard Format table */ -#define ACPI_SIG_BOOT "BOOT" /* Simple Boot Flag Table */ -#define ACPI_SIG_CSRT "CSRT" /* Core System Resource Table */ -#define ACPI_SIG_DBG2 "DBG2" /* Debug Port table type 2 */ -#define ACPI_SIG_DBGP "DBGP" /* Debug Port table */ -#define ACPI_SIG_DMAR "DMAR" /* DMA Remapping table */ -#define ACPI_SIG_HPET "HPET" /* High Precision Event Timer table */ -#define ACPI_SIG_IBFT "IBFT" /* iSCSI Boot Firmware Table */ -#define ACPI_SIG_IORT "IORT" /* IO Remapping Table */ -#define ACPI_SIG_IVRS "IVRS" /* I/O Virtualization Reporting Structure */ -#define ACPI_SIG_LPIT "LPIT" /* Low Power Idle Table */ -#define ACPI_SIG_MCFG "MCFG" /* PCI Memory Mapped Configuration table */ -#define ACPI_SIG_MCHI "MCHI" /* Management Controller Host Interface table */ -#define ACPI_SIG_MSDM "MSDM" /* Microsoft Data Management Table */ -#define ACPI_SIG_MTMR "MTMR" /* MID Timer table */ -#define ACPI_SIG_SLIC "SLIC" /* Software Licensing Description Table */ -#define ACPI_SIG_SPCR "SPCR" /* Serial Port Console Redirection table */ -#define ACPI_SIG_SPMI "SPMI" /* Server Platform Management Interface table */ -#define ACPI_SIG_TCPA "TCPA" /* Trusted Computing Platform Alliance table */ -#define ACPI_SIG_TPM2 "TPM2" /* Trusted Platform Module 2.0 H/W interface table */ -#define ACPI_SIG_UEFI "UEFI" /* Uefi Boot Optimization Table */ -#define ACPI_SIG_VRTC "VRTC" /* Virtual Real Time Clock Table */ -#define ACPI_SIG_WAET "WAET" /* Windows ACPI Emulated devices Table */ -#define ACPI_SIG_WDAT "WDAT" /* Watchdog Action Table */ -#define ACPI_SIG_WDDT "WDDT" /* Watchdog Timer Description Table */ -#define ACPI_SIG_WDRT "WDRT" /* Watchdog Resource Table */ - -#ifdef ACPI_UNDEFINED_TABLES -/* - * These tables have been seen in the field, but no definition has been found - */ -#define ACPI_SIG_ATKG "ATKG" -#define ACPI_SIG_GSCI "GSCI" /* GMCH SCI table */ -#define ACPI_SIG_IEIT "IEIT" -#endif - -/* - * All tables must be byte-packed to match the ACPI specification, since - * the tables are provided by the system BIOS. - */ -#pragma pack(1) - -/* - * Note: C bitfields are not used for this reason: - * - * "Bitfields are great and easy to read, but unfortunately the C language - * does not specify the layout of bitfields in memory, which means they are - * essentially useless for dealing with packed data in on-disk formats or - * binary wire protocols." (Or ACPI tables and buffers.) "If you ask me, - * this decision was a design error in C. Ritchie could have picked an order - * and stuck with it." Norman Ramsey. - * See http://stackoverflow.com/a/1053662/41661 - */ - -/******************************************************************************* - * - * ASF - Alert Standard Format table (Signature "ASF!") - * Revision 0x10 - * - * Conforms to the Alert Standard Format Specification V2.0, 23 April 2003 - * - ******************************************************************************/ - -struct acpi_table_asf { - struct acpi_table_header header; /* Common ACPI table header */ -}; - -/* ASF subtable header */ - -struct acpi_asf_header { - u8 type; - u8 reserved; - u16 length; -}; - -/* Values for Type field above */ - -enum acpi_asf_type { - ACPI_ASF_TYPE_INFO = 0, - ACPI_ASF_TYPE_ALERT = 1, - ACPI_ASF_TYPE_CONTROL = 2, - ACPI_ASF_TYPE_BOOT = 3, - ACPI_ASF_TYPE_ADDRESS = 4, - ACPI_ASF_TYPE_RESERVED = 5 -}; - -/* - * ASF subtables - */ - -/* 0: ASF Information */ - -struct acpi_asf_info { - struct acpi_asf_header header; - u8 min_reset_value; - u8 min_poll_interval; - u16 system_id; - u32 mfg_id; - u8 flags; - u8 reserved2[3]; -}; - -/* Masks for Flags field above */ - -#define ACPI_ASF_SMBUS_PROTOCOLS (1) - -/* 1: ASF Alerts */ - -struct acpi_asf_alert { - struct acpi_asf_header header; - u8 assert_mask; - u8 deassert_mask; - u8 alerts; - u8 data_length; -}; - -struct acpi_asf_alert_data { - u8 address; - u8 command; - u8 mask; - u8 value; - u8 sensor_type; - u8 type; - u8 offset; - u8 source_type; - u8 severity; - u8 sensor_number; - u8 entity; - u8 instance; -}; - -/* 2: ASF Remote Control */ - -struct acpi_asf_remote { - struct acpi_asf_header header; - u8 controls; - u8 data_length; - u16 reserved2; -}; - -struct acpi_asf_control_data { - u8 function; - u8 address; - u8 command; - u8 value; -}; - -/* 3: ASF RMCP Boot Options */ - -struct acpi_asf_rmcp { - struct acpi_asf_header header; - u8 capabilities[7]; - u8 completion_code; - u32 enterprise_id; - u8 command; - u16 parameter; - u16 boot_options; - u16 oem_parameters; -}; - -/* 4: ASF Address */ - -struct acpi_asf_address { - struct acpi_asf_header header; - u8 eprom_address; - u8 devices; -}; - -/******************************************************************************* - * - * BOOT - Simple Boot Flag Table - * Version 1 - * - * Conforms to the "Simple Boot Flag Specification", Version 2.1 - * - ******************************************************************************/ - -struct acpi_table_boot { - struct acpi_table_header header; /* Common ACPI table header */ - u8 cmos_index; /* Index in CMOS RAM for the boot register */ - u8 reserved[3]; -}; - -/******************************************************************************* - * - * CSRT - Core System Resource Table - * Version 0 - * - * Conforms to the "Core System Resource Table (CSRT)", November 14, 2011 - * - ******************************************************************************/ - -struct acpi_table_csrt { - struct acpi_table_header header; /* Common ACPI table header */ -}; - -/* Resource Group subtable */ - -struct acpi_csrt_group { - u32 length; - u32 vendor_id; - u32 subvendor_id; - u16 device_id; - u16 subdevice_id; - u16 revision; - u16 reserved; - u32 shared_info_length; - - /* Shared data immediately follows (Length = shared_info_length) */ -}; - -/* Shared Info subtable */ - -struct acpi_csrt_shared_info { - u16 major_version; - u16 minor_version; - u32 mmio_base_low; - u32 mmio_base_high; - u32 gsi_interrupt; - u8 interrupt_polarity; - u8 interrupt_mode; - u8 num_channels; - u8 dma_address_width; - u16 base_request_line; - u16 num_handshake_signals; - u32 max_block_size; - - /* Resource descriptors immediately follow (Length = Group length - shared_info_length) */ -}; - -/* Resource Descriptor subtable */ - -struct acpi_csrt_descriptor { - u32 length; - u16 type; - u16 subtype; - u32 uid; - - /* Resource-specific information immediately follows */ -}; - -/* Resource Types */ - -#define ACPI_CSRT_TYPE_INTERRUPT 0x0001 -#define ACPI_CSRT_TYPE_TIMER 0x0002 -#define ACPI_CSRT_TYPE_DMA 0x0003 - -/* Resource Subtypes */ - -#define ACPI_CSRT_XRUPT_LINE 0x0000 -#define ACPI_CSRT_XRUPT_CONTROLLER 0x0001 -#define ACPI_CSRT_TIMER 0x0000 -#define ACPI_CSRT_DMA_CHANNEL 0x0000 -#define ACPI_CSRT_DMA_CONTROLLER 0x0001 - -/******************************************************************************* - * - * DBG2 - Debug Port Table 2 - * Version 0 (Both main table and subtables) - * - * Conforms to "Microsoft Debug Port Table 2 (DBG2)", December 10, 2015 - * - ******************************************************************************/ - -struct acpi_table_dbg2 { - struct acpi_table_header header; /* Common ACPI table header */ - u32 info_offset; - u32 info_count; -}; - -struct acpi_dbg2_header { - u32 info_offset; - u32 info_count; -}; - -/* Debug Device Information Subtable */ - -struct acpi_dbg2_device { - u8 revision; - u16 length; - u8 register_count; /* Number of base_address registers */ - u16 namepath_length; - u16 namepath_offset; - u16 oem_data_length; - u16 oem_data_offset; - u16 port_type; - u16 port_subtype; - u16 reserved; - u16 base_address_offset; - u16 address_size_offset; - /* - * Data that follows: - * base_address (required) - Each in 12-byte Generic Address Structure format. - * address_size (required) - Array of u32 sizes corresponding to each base_address register. - * Namepath (required) - Null terminated string. Single dot if not supported. - * oem_data (optional) - Length is oem_data_length. - */ -}; - -/* Types for port_type field above */ - -#define ACPI_DBG2_SERIAL_PORT 0x8000 -#define ACPI_DBG2_1394_PORT 0x8001 -#define ACPI_DBG2_USB_PORT 0x8002 -#define ACPI_DBG2_NET_PORT 0x8003 - -/* Subtypes for port_subtype field above */ - -#define ACPI_DBG2_16550_COMPATIBLE 0x0000 -#define ACPI_DBG2_16550_SUBSET 0x0001 -#define ACPI_DBG2_ARM_PL011 0x0003 -#define ACPI_DBG2_ARM_SBSA_32BIT 0x000D -#define ACPI_DBG2_ARM_SBSA_GENERIC 0x000E -#define ACPI_DBG2_ARM_DCC 0x000F -#define ACPI_DBG2_BCM2835 0x0010 - -#define ACPI_DBG2_1394_STANDARD 0x0000 - -#define ACPI_DBG2_USB_XHCI 0x0000 -#define ACPI_DBG2_USB_EHCI 0x0001 - -/******************************************************************************* - * - * DBGP - Debug Port table - * Version 1 - * - * Conforms to the "Debug Port Specification", Version 1.00, 2/9/2000 - * - ******************************************************************************/ - -struct acpi_table_dbgp { - struct acpi_table_header header; /* Common ACPI table header */ - u8 type; /* 0=full 16550, 1=subset of 16550 */ - u8 reserved[3]; - struct acpi_generic_address debug_port; -}; - -/******************************************************************************* - * - * DMAR - DMA Remapping table - * Version 1 - * - * Conforms to "Intel Virtualization Technology for Directed I/O", - * Version 2.3, October 2014 - * - ******************************************************************************/ - -struct acpi_table_dmar { - struct acpi_table_header header; /* Common ACPI table header */ - u8 width; /* Host Address Width */ - u8 flags; - u8 reserved[10]; -}; - -/* Masks for Flags field above */ - -#define ACPI_DMAR_INTR_REMAP (1) -#define ACPI_DMAR_X2APIC_OPT_OUT (1<<1) -#define ACPI_DMAR_X2APIC_MODE (1<<2) - -/* DMAR subtable header */ - -struct acpi_dmar_header { - u16 type; - u16 length; -}; - -/* Values for subtable type in struct acpi_dmar_header */ - -enum acpi_dmar_type { - ACPI_DMAR_TYPE_HARDWARE_UNIT = 0, - ACPI_DMAR_TYPE_RESERVED_MEMORY = 1, - ACPI_DMAR_TYPE_ROOT_ATS = 2, - ACPI_DMAR_TYPE_HARDWARE_AFFINITY = 3, - ACPI_DMAR_TYPE_NAMESPACE = 4, - ACPI_DMAR_TYPE_RESERVED = 5 /* 5 and greater are reserved */ -}; - -/* DMAR Device Scope structure */ - -struct acpi_dmar_device_scope { - u8 entry_type; - u8 length; - u16 reserved; - u8 enumeration_id; - u8 bus; -}; - -/* Values for entry_type in struct acpi_dmar_device_scope - device types */ - -enum acpi_dmar_scope_type { - ACPI_DMAR_SCOPE_TYPE_NOT_USED = 0, - ACPI_DMAR_SCOPE_TYPE_ENDPOINT = 1, - ACPI_DMAR_SCOPE_TYPE_BRIDGE = 2, - ACPI_DMAR_SCOPE_TYPE_IOAPIC = 3, - ACPI_DMAR_SCOPE_TYPE_HPET = 4, - ACPI_DMAR_SCOPE_TYPE_NAMESPACE = 5, - ACPI_DMAR_SCOPE_TYPE_RESERVED = 6 /* 6 and greater are reserved */ -}; - -struct acpi_dmar_pci_path { - u8 device; - u8 function; -}; - -/* - * DMAR Subtables, correspond to Type in struct acpi_dmar_header - */ - -/* 0: Hardware Unit Definition */ - -struct acpi_dmar_hardware_unit { - struct acpi_dmar_header header; - u8 flags; - u8 reserved; - u16 segment; - u64 address; /* Register Base Address */ -}; - -/* Masks for Flags field above */ - -#define ACPI_DMAR_INCLUDE_ALL (1) - -/* 1: Reserved Memory Defininition */ - -struct acpi_dmar_reserved_memory { - struct acpi_dmar_header header; - u16 reserved; - u16 segment; - u64 base_address; /* 4K aligned base address */ - u64 end_address; /* 4K aligned limit address */ -}; - -/* Masks for Flags field above */ - -#define ACPI_DMAR_ALLOW_ALL (1) - -/* 2: Root Port ATS Capability Reporting Structure */ - -struct acpi_dmar_atsr { - struct acpi_dmar_header header; - u8 flags; - u8 reserved; - u16 segment; -}; - -/* Masks for Flags field above */ - -#define ACPI_DMAR_ALL_PORTS (1) - -/* 3: Remapping Hardware Static Affinity Structure */ - -struct acpi_dmar_rhsa { - struct acpi_dmar_header header; - u32 reserved; - u64 base_address; - u32 proximity_domain; -}; - -/* 4: ACPI Namespace Device Declaration Structure */ - -struct acpi_dmar_andd { - struct acpi_dmar_header header; - u8 reserved[3]; - u8 device_number; - char device_name[1]; -}; - -/******************************************************************************* - * - * HPET - High Precision Event Timer table - * Version 1 - * - * Conforms to "IA-PC HPET (High Precision Event Timers) Specification", - * Version 1.0a, October 2004 - * - ******************************************************************************/ - -struct acpi_table_hpet { - struct acpi_table_header header; /* Common ACPI table header */ - u32 id; /* Hardware ID of event timer block */ - struct acpi_generic_address address; /* Address of event timer block */ - u8 sequence; /* HPET sequence number */ - u16 minimum_tick; /* Main counter min tick, periodic mode */ - u8 flags; -}; - -/* Masks for Flags field above */ - -#define ACPI_HPET_PAGE_PROTECT_MASK (3) - -/* Values for Page Protect flags */ - -enum acpi_hpet_page_protect { - ACPI_HPET_NO_PAGE_PROTECT = 0, - ACPI_HPET_PAGE_PROTECT4 = 1, - ACPI_HPET_PAGE_PROTECT64 = 2 -}; - -/******************************************************************************* - * - * IBFT - Boot Firmware Table - * Version 1 - * - * Conforms to "iSCSI Boot Firmware Table (iBFT) as Defined in ACPI 3.0b - * Specification", Version 1.01, March 1, 2007 - * - * Note: It appears that this table is not intended to appear in the RSDT/XSDT. - * Therefore, it is not currently supported by the disassembler. - * - ******************************************************************************/ - -struct acpi_table_ibft { - struct acpi_table_header header; /* Common ACPI table header */ - u8 reserved[12]; -}; - -/* IBFT common subtable header */ - -struct acpi_ibft_header { - u8 type; - u8 version; - u16 length; - u8 index; - u8 flags; -}; - -/* Values for Type field above */ - -enum acpi_ibft_type { - ACPI_IBFT_TYPE_NOT_USED = 0, - ACPI_IBFT_TYPE_CONTROL = 1, - ACPI_IBFT_TYPE_INITIATOR = 2, - ACPI_IBFT_TYPE_NIC = 3, - ACPI_IBFT_TYPE_TARGET = 4, - ACPI_IBFT_TYPE_EXTENSIONS = 5, - ACPI_IBFT_TYPE_RESERVED = 6 /* 6 and greater are reserved */ -}; - -/* IBFT subtables */ - -struct acpi_ibft_control { - struct acpi_ibft_header header; - u16 extensions; - u16 initiator_offset; - u16 nic0_offset; - u16 target0_offset; - u16 nic1_offset; - u16 target1_offset; -}; - -struct acpi_ibft_initiator { - struct acpi_ibft_header header; - u8 sns_server[16]; - u8 slp_server[16]; - u8 primary_server[16]; - u8 secondary_server[16]; - u16 name_length; - u16 name_offset; -}; - -struct acpi_ibft_nic { - struct acpi_ibft_header header; - u8 ip_address[16]; - u8 subnet_mask_prefix; - u8 origin; - u8 gateway[16]; - u8 primary_dns[16]; - u8 secondary_dns[16]; - u8 dhcp[16]; - u16 vlan; - u8 mac_address[6]; - u16 pci_address; - u16 name_length; - u16 name_offset; -}; - -struct acpi_ibft_target { - struct acpi_ibft_header header; - u8 target_ip_address[16]; - u16 target_ip_socket; - u8 target_boot_lun[8]; - u8 chap_type; - u8 nic_association; - u16 target_name_length; - u16 target_name_offset; - u16 chap_name_length; - u16 chap_name_offset; - u16 chap_secret_length; - u16 chap_secret_offset; - u16 reverse_chap_name_length; - u16 reverse_chap_name_offset; - u16 reverse_chap_secret_length; - u16 reverse_chap_secret_offset; -}; - -/******************************************************************************* - * - * IORT - IO Remapping Table - * - * Conforms to "IO Remapping Table System Software on ARM Platforms", - * Document number: ARM DEN 0049B, October 2015 - * - ******************************************************************************/ - -struct acpi_table_iort { - struct acpi_table_header header; - u32 node_count; - u32 node_offset; - u32 reserved; -}; - -/* - * IORT subtables - */ -struct acpi_iort_node { - u8 type; - u16 length; - u8 revision; - u32 reserved; - u32 mapping_count; - u32 mapping_offset; - char node_data[1]; -}; - -/* Values for subtable Type above */ - -enum acpi_iort_node_type { - ACPI_IORT_NODE_ITS_GROUP = 0x00, - ACPI_IORT_NODE_NAMED_COMPONENT = 0x01, - ACPI_IORT_NODE_PCI_ROOT_COMPLEX = 0x02, - ACPI_IORT_NODE_SMMU = 0x03, - ACPI_IORT_NODE_SMMU_V3 = 0x04 -}; - -struct acpi_iort_id_mapping { - u32 input_base; /* Lowest value in input range */ - u32 id_count; /* Number of IDs */ - u32 output_base; /* Lowest value in output range */ - u32 output_reference; /* A reference to the output node */ - u32 flags; -}; - -/* Masks for Flags field above for IORT subtable */ - -#define ACPI_IORT_ID_SINGLE_MAPPING (1) - -struct acpi_iort_memory_access { - u32 cache_coherency; - u8 hints; - u16 reserved; - u8 memory_flags; -}; - -/* Values for cache_coherency field above */ - -#define ACPI_IORT_NODE_COHERENT 0x00000001 /* The device node is fully coherent */ -#define ACPI_IORT_NODE_NOT_COHERENT 0x00000000 /* The device node is not coherent */ - -/* Masks for Hints field above */ - -#define ACPI_IORT_HT_TRANSIENT (1) -#define ACPI_IORT_HT_WRITE (1<<1) -#define ACPI_IORT_HT_READ (1<<2) -#define ACPI_IORT_HT_OVERRIDE (1<<3) - -/* Masks for memory_flags field above */ - -#define ACPI_IORT_MF_COHERENCY (1) -#define ACPI_IORT_MF_ATTRIBUTES (1<<1) - -/* - * IORT node specific subtables - */ -struct acpi_iort_its_group { - u32 its_count; - u32 identifiers[1]; /* GIC ITS identifier arrary */ -}; - -struct acpi_iort_named_component { - u32 node_flags; - u64 memory_properties; /* Memory access properties */ - u8 memory_address_limit; /* Memory address size limit */ - char device_name[1]; /* Path of namespace object */ -}; - -struct acpi_iort_root_complex { - u64 memory_properties; /* Memory access properties */ - u32 ats_attribute; - u32 pci_segment_number; -}; - -/* Values for ats_attribute field above */ - -#define ACPI_IORT_ATS_SUPPORTED 0x00000001 /* The root complex supports ATS */ -#define ACPI_IORT_ATS_UNSUPPORTED 0x00000000 /* The root complex doesn't support ATS */ - -struct acpi_iort_smmu { - u64 base_address; /* SMMU base address */ - u64 span; /* Length of memory range */ - u32 model; - u32 flags; - u32 global_interrupt_offset; - u32 context_interrupt_count; - u32 context_interrupt_offset; - u32 pmu_interrupt_count; - u32 pmu_interrupt_offset; - u64 interrupts[1]; /* Interrupt array */ -}; - -/* Values for Model field above */ - -#define ACPI_IORT_SMMU_V1 0x00000000 /* Generic SMMUv1 */ -#define ACPI_IORT_SMMU_V2 0x00000001 /* Generic SMMUv2 */ -#define ACPI_IORT_SMMU_CORELINK_MMU400 0x00000002 /* ARM Corelink MMU-400 */ -#define ACPI_IORT_SMMU_CORELINK_MMU500 0x00000003 /* ARM Corelink MMU-500 */ - -/* Masks for Flags field above */ - -#define ACPI_IORT_SMMU_DVM_SUPPORTED (1) -#define ACPI_IORT_SMMU_COHERENT_WALK (1<<1) - -struct acpi_iort_smmu_v3 { - u64 base_address; /* SMMUv3 base address */ - u32 flags; - u32 reserved; - u64 vatos_address; - u32 model; /* O: generic SMMUv3 */ - u32 event_gsiv; - u32 pri_gsiv; - u32 gerr_gsiv; - u32 sync_gsiv; -}; - -/* Masks for Flags field above */ - -#define ACPI_IORT_SMMU_V3_COHACC_OVERRIDE (1) -#define ACPI_IORT_SMMU_V3_HTTU_OVERRIDE (1<<1) - -/******************************************************************************* - * - * IVRS - I/O Virtualization Reporting Structure - * Version 1 - * - * Conforms to "AMD I/O Virtualization Technology (IOMMU) Specification", - * Revision 1.26, February 2009. - * - ******************************************************************************/ - -struct acpi_table_ivrs { - struct acpi_table_header header; /* Common ACPI table header */ - u32 info; /* Common virtualization info */ - u64 reserved; -}; - -/* Values for Info field above */ - -#define ACPI_IVRS_PHYSICAL_SIZE 0x00007F00 /* 7 bits, physical address size */ -#define ACPI_IVRS_VIRTUAL_SIZE 0x003F8000 /* 7 bits, virtual address size */ -#define ACPI_IVRS_ATS_RESERVED 0x00400000 /* ATS address translation range reserved */ - -/* IVRS subtable header */ - -struct acpi_ivrs_header { - u8 type; /* Subtable type */ - u8 flags; - u16 length; /* Subtable length */ - u16 device_id; /* ID of IOMMU */ -}; - -/* Values for subtable Type above */ - -enum acpi_ivrs_type { - ACPI_IVRS_TYPE_HARDWARE = 0x10, - ACPI_IVRS_TYPE_MEMORY1 = 0x20, - ACPI_IVRS_TYPE_MEMORY2 = 0x21, - ACPI_IVRS_TYPE_MEMORY3 = 0x22 -}; - -/* Masks for Flags field above for IVHD subtable */ - -#define ACPI_IVHD_TT_ENABLE (1) -#define ACPI_IVHD_PASS_PW (1<<1) -#define ACPI_IVHD_RES_PASS_PW (1<<2) -#define ACPI_IVHD_ISOC (1<<3) -#define ACPI_IVHD_IOTLB (1<<4) - -/* Masks for Flags field above for IVMD subtable */ - -#define ACPI_IVMD_UNITY (1) -#define ACPI_IVMD_READ (1<<1) -#define ACPI_IVMD_WRITE (1<<2) -#define ACPI_IVMD_EXCLUSION_RANGE (1<<3) - -/* - * IVRS subtables, correspond to Type in struct acpi_ivrs_header - */ - -/* 0x10: I/O Virtualization Hardware Definition Block (IVHD) */ - -struct acpi_ivrs_hardware { - struct acpi_ivrs_header header; - u16 capability_offset; /* Offset for IOMMU control fields */ - u64 base_address; /* IOMMU control registers */ - u16 pci_segment_group; - u16 info; /* MSI number and unit ID */ - u32 reserved; -}; - -/* Masks for Info field above */ - -#define ACPI_IVHD_MSI_NUMBER_MASK 0x001F /* 5 bits, MSI message number */ -#define ACPI_IVHD_UNIT_ID_MASK 0x1F00 /* 5 bits, unit_ID */ - -/* - * Device Entries for IVHD subtable, appear after struct acpi_ivrs_hardware structure. - * Upper two bits of the Type field are the (encoded) length of the structure. - * Currently, only 4 and 8 byte entries are defined. 16 and 32 byte entries - * are reserved for future use but not defined. - */ -struct acpi_ivrs_de_header { - u8 type; - u16 id; - u8 data_setting; -}; - -/* Length of device entry is in the top two bits of Type field above */ - -#define ACPI_IVHD_ENTRY_LENGTH 0xC0 - -/* Values for device entry Type field above */ - -enum acpi_ivrs_device_entry_type { - /* 4-byte device entries, all use struct acpi_ivrs_device4 */ - - ACPI_IVRS_TYPE_PAD4 = 0, - ACPI_IVRS_TYPE_ALL = 1, - ACPI_IVRS_TYPE_SELECT = 2, - ACPI_IVRS_TYPE_START = 3, - ACPI_IVRS_TYPE_END = 4, - - /* 8-byte device entries */ - - ACPI_IVRS_TYPE_PAD8 = 64, - ACPI_IVRS_TYPE_NOT_USED = 65, - ACPI_IVRS_TYPE_ALIAS_SELECT = 66, /* Uses struct acpi_ivrs_device8a */ - ACPI_IVRS_TYPE_ALIAS_START = 67, /* Uses struct acpi_ivrs_device8a */ - ACPI_IVRS_TYPE_EXT_SELECT = 70, /* Uses struct acpi_ivrs_device8b */ - ACPI_IVRS_TYPE_EXT_START = 71, /* Uses struct acpi_ivrs_device8b */ - ACPI_IVRS_TYPE_SPECIAL = 72 /* Uses struct acpi_ivrs_device8c */ -}; - -/* Values for Data field above */ - -#define ACPI_IVHD_INIT_PASS (1) -#define ACPI_IVHD_EINT_PASS (1<<1) -#define ACPI_IVHD_NMI_PASS (1<<2) -#define ACPI_IVHD_SYSTEM_MGMT (3<<4) -#define ACPI_IVHD_LINT0_PASS (1<<6) -#define ACPI_IVHD_LINT1_PASS (1<<7) - -/* Types 0-4: 4-byte device entry */ - -struct acpi_ivrs_device4 { - struct acpi_ivrs_de_header header; -}; - -/* Types 66-67: 8-byte device entry */ - -struct acpi_ivrs_device8a { - struct acpi_ivrs_de_header header; - u8 reserved1; - u16 used_id; - u8 reserved2; -}; - -/* Types 70-71: 8-byte device entry */ - -struct acpi_ivrs_device8b { - struct acpi_ivrs_de_header header; - u32 extended_data; -}; - -/* Values for extended_data above */ - -#define ACPI_IVHD_ATS_DISABLED (1<<31) - -/* Type 72: 8-byte device entry */ - -struct acpi_ivrs_device8c { - struct acpi_ivrs_de_header header; - u8 handle; - u16 used_id; - u8 variety; -}; - -/* Values for Variety field above */ - -#define ACPI_IVHD_IOAPIC 1 -#define ACPI_IVHD_HPET 2 - -/* 0x20, 0x21, 0x22: I/O Virtualization Memory Definition Block (IVMD) */ - -struct acpi_ivrs_memory { - struct acpi_ivrs_header header; - u16 aux_data; - u64 reserved; - u64 start_address; - u64 memory_length; -}; - -/******************************************************************************* - * - * LPIT - Low Power Idle Table - * - * Conforms to "ACPI Low Power Idle Table (LPIT)" July 2014. - * - ******************************************************************************/ - -struct acpi_table_lpit { - struct acpi_table_header header; /* Common ACPI table header */ -}; - -/* LPIT subtable header */ - -struct acpi_lpit_header { - u32 type; /* Subtable type */ - u32 length; /* Subtable length */ - u16 unique_id; - u16 reserved; - u32 flags; -}; - -/* Values for subtable Type above */ - -enum acpi_lpit_type { - ACPI_LPIT_TYPE_NATIVE_CSTATE = 0x00, - ACPI_LPIT_TYPE_RESERVED = 0x01 /* 1 and above are reserved */ -}; - -/* Masks for Flags field above */ - -#define ACPI_LPIT_STATE_DISABLED (1) -#define ACPI_LPIT_NO_COUNTER (1<<1) - -/* - * LPIT subtables, correspond to Type in struct acpi_lpit_header - */ - -/* 0x00: Native C-state instruction based LPI structure */ - -struct acpi_lpit_native { - struct acpi_lpit_header header; - struct acpi_generic_address entry_trigger; - u32 residency; - u32 latency; - struct acpi_generic_address residency_counter; - u64 counter_frequency; -}; - -/******************************************************************************* - * - * MCFG - PCI Memory Mapped Configuration table and subtable - * Version 1 - * - * Conforms to "PCI Firmware Specification", Revision 3.0, June 20, 2005 - * - ******************************************************************************/ - -struct acpi_table_mcfg { - struct acpi_table_header header; /* Common ACPI table header */ - u8 reserved[8]; -}; - -/* Subtable */ - -struct acpi_mcfg_allocation { - u64 address; /* Base address, processor-relative */ - u16 pci_segment; /* PCI segment group number */ - u8 start_bus_number; /* Starting PCI Bus number */ - u8 end_bus_number; /* Final PCI Bus number */ - u32 reserved; -}; - -/******************************************************************************* - * - * MCHI - Management Controller Host Interface Table - * Version 1 - * - * Conforms to "Management Component Transport Protocol (MCTP) Host - * Interface Specification", Revision 1.0.0a, October 13, 2009 - * - ******************************************************************************/ - -struct acpi_table_mchi { - struct acpi_table_header header; /* Common ACPI table header */ - u8 interface_type; - u8 protocol; - u64 protocol_data; - u8 interrupt_type; - u8 gpe; - u8 pci_device_flag; - u32 global_interrupt; - struct acpi_generic_address control_register; - u8 pci_segment; - u8 pci_bus; - u8 pci_device; - u8 pci_function; -}; - -/******************************************************************************* - * - * MSDM - Microsoft Data Management table - * - * Conforms to "Microsoft Software Licensing Tables (SLIC and MSDM)", - * November 29, 2011. Copyright 2011 Microsoft - * - ******************************************************************************/ - -/* Basic MSDM table is only the common ACPI header */ - -struct acpi_table_msdm { - struct acpi_table_header header; /* Common ACPI table header */ -}; - -/******************************************************************************* - * - * MTMR - MID Timer Table - * Version 1 - * - * Conforms to "Simple Firmware Interface Specification", - * Draft 0.8.2, Oct 19, 2010 - * NOTE: The ACPI MTMR is equivalent to the SFI MTMR table. - * - ******************************************************************************/ - -struct acpi_table_mtmr { - struct acpi_table_header header; /* Common ACPI table header */ -}; - -/* MTMR entry */ - -struct acpi_mtmr_entry { - struct acpi_generic_address physical_address; - u32 frequency; - u32 irq; -}; - -/******************************************************************************* - * - * SLIC - Software Licensing Description Table - * - * Conforms to "Microsoft Software Licensing Tables (SLIC and MSDM)", - * November 29, 2011. Copyright 2011 Microsoft - * - ******************************************************************************/ - -/* Basic SLIC table is only the common ACPI header */ - -struct acpi_table_slic { - struct acpi_table_header header; /* Common ACPI table header */ -}; - -/******************************************************************************* - * - * SPCR - Serial Port Console Redirection table - * Version 2 - * - * Conforms to "Serial Port Console Redirection Table", - * Version 1.03, August 10, 2015 - * - ******************************************************************************/ - -struct acpi_table_spcr { - struct acpi_table_header header; /* Common ACPI table header */ - u8 interface_type; /* 0=full 16550, 1=subset of 16550 */ - u8 reserved[3]; - struct acpi_generic_address serial_port; - u8 interrupt_type; - u8 pc_interrupt; - u32 interrupt; - u8 baud_rate; - u8 parity; - u8 stop_bits; - u8 flow_control; - u8 terminal_type; - u8 reserved1; - u16 pci_device_id; - u16 pci_vendor_id; - u8 pci_bus; - u8 pci_device; - u8 pci_function; - u32 pci_flags; - u8 pci_segment; - u32 reserved2; -}; - -/* Masks for pci_flags field above */ - -#define ACPI_SPCR_DO_NOT_DISABLE (1) - -/* Values for Interface Type: See the definition of the DBG2 table */ - -/******************************************************************************* - * - * SPMI - Server Platform Management Interface table - * Version 5 - * - * Conforms to "Intelligent Platform Management Interface Specification - * Second Generation v2.0", Document Revision 1.0, February 12, 2004 with - * June 12, 2009 markup. - * - ******************************************************************************/ - -struct acpi_table_spmi { - struct acpi_table_header header; /* Common ACPI table header */ - u8 interface_type; - u8 reserved; /* Must be 1 */ - u16 spec_revision; /* Version of IPMI */ - u8 interrupt_type; - u8 gpe_number; /* GPE assigned */ - u8 reserved1; - u8 pci_device_flag; - u32 interrupt; - struct acpi_generic_address ipmi_register; - u8 pci_segment; - u8 pci_bus; - u8 pci_device; - u8 pci_function; - u8 reserved2; -}; - -/* Values for interface_type above */ - -enum acpi_spmi_interface_types { - ACPI_SPMI_NOT_USED = 0, - ACPI_SPMI_KEYBOARD = 1, - ACPI_SPMI_SMI = 2, - ACPI_SPMI_BLOCK_TRANSFER = 3, - ACPI_SPMI_SMBUS = 4, - ACPI_SPMI_RESERVED = 5 /* 5 and above are reserved */ -}; - -/******************************************************************************* - * - * TCPA - Trusted Computing Platform Alliance table - * Version 2 - * - * Conforms to "TCG ACPI Specification, Family 1.2 and 2.0", - * December 19, 2014 - * - * NOTE: There are two versions of the table with the same signature -- - * the client version and the server version. The common platform_class - * field is used to differentiate the two types of tables. - * - ******************************************************************************/ - -struct acpi_table_tcpa_hdr { - struct acpi_table_header header; /* Common ACPI table header */ - u16 platform_class; -}; - -/* - * Values for platform_class above. - * This is how the client and server subtables are differentiated - */ -#define ACPI_TCPA_CLIENT_TABLE 0 -#define ACPI_TCPA_SERVER_TABLE 1 - -struct acpi_table_tcpa_client { - u32 minimum_log_length; /* Minimum length for the event log area */ - u64 log_address; /* Address of the event log area */ -}; - -struct acpi_table_tcpa_server { - u16 reserved; - u64 minimum_log_length; /* Minimum length for the event log area */ - u64 log_address; /* Address of the event log area */ - u16 spec_revision; - u8 device_flags; - u8 interrupt_flags; - u8 gpe_number; - u8 reserved2[3]; - u32 global_interrupt; - struct acpi_generic_address address; - u32 reserved3; - struct acpi_generic_address config_address; - u8 group; - u8 bus; /* PCI Bus/Segment/Function numbers */ - u8 device; - u8 function; -}; - -/* Values for device_flags above */ - -#define ACPI_TCPA_PCI_DEVICE (1) -#define ACPI_TCPA_BUS_PNP (1<<1) -#define ACPI_TCPA_ADDRESS_VALID (1<<2) - -/* Values for interrupt_flags above */ - -#define ACPI_TCPA_INTERRUPT_MODE (1) -#define ACPI_TCPA_INTERRUPT_POLARITY (1<<1) -#define ACPI_TCPA_SCI_VIA_GPE (1<<2) -#define ACPI_TCPA_GLOBAL_INTERRUPT (1<<3) - -/******************************************************************************* - * - * TPM2 - Trusted Platform Module (TPM) 2.0 Hardware Interface Table - * Version 4 - * - * Conforms to "TCG ACPI Specification, Family 1.2 and 2.0", - * December 19, 2014 - * - ******************************************************************************/ - -struct acpi_table_tpm2 { - struct acpi_table_header header; /* Common ACPI table header */ - u16 platform_class; - u16 reserved; - u64 control_address; - u32 start_method; - - /* Platform-specific data follows */ -}; - -/* Values for start_method above */ - -#define ACPI_TPM2_NOT_ALLOWED 0 -#define ACPI_TPM2_START_METHOD 2 -#define ACPI_TPM2_MEMORY_MAPPED 6 -#define ACPI_TPM2_COMMAND_BUFFER 7 -#define ACPI_TPM2_COMMAND_BUFFER_WITH_START_METHOD 8 - -/******************************************************************************* - * - * UEFI - UEFI Boot optimization Table - * Version 1 - * - * Conforms to "Unified Extensible Firmware Interface Specification", - * Version 2.3, May 8, 2009 - * - ******************************************************************************/ - -struct acpi_table_uefi { - struct acpi_table_header header; /* Common ACPI table header */ - u8 identifier[16]; /* UUID identifier */ - u16 data_offset; /* Offset of remaining data in table */ -}; - -/******************************************************************************* - * - * VRTC - Virtual Real Time Clock Table - * Version 1 - * - * Conforms to "Simple Firmware Interface Specification", - * Draft 0.8.2, Oct 19, 2010 - * NOTE: The ACPI VRTC is equivalent to The SFI MRTC table. - * - ******************************************************************************/ - -struct acpi_table_vrtc { - struct acpi_table_header header; /* Common ACPI table header */ -}; - -/* VRTC entry */ - -struct acpi_vrtc_entry { - struct acpi_generic_address physical_address; - u32 irq; -}; - -/******************************************************************************* - * - * WAET - Windows ACPI Emulated devices Table - * Version 1 - * - * Conforms to "Windows ACPI Emulated Devices Table", version 1.0, April 6, 2009 - * - ******************************************************************************/ - -struct acpi_table_waet { - struct acpi_table_header header; /* Common ACPI table header */ - u32 flags; -}; - -/* Masks for Flags field above */ - -#define ACPI_WAET_RTC_NO_ACK (1) /* RTC requires no int acknowledge */ -#define ACPI_WAET_TIMER_ONE_READ (1<<1) /* PM timer requires only one read */ - -/******************************************************************************* - * - * WDAT - Watchdog Action Table - * Version 1 - * - * Conforms to "Hardware Watchdog Timers Design Specification", - * Copyright 2006 Microsoft Corporation. - * - ******************************************************************************/ - -struct acpi_table_wdat { - struct acpi_table_header header; /* Common ACPI table header */ - u32 header_length; /* Watchdog Header Length */ - u16 pci_segment; /* PCI Segment number */ - u8 pci_bus; /* PCI Bus number */ - u8 pci_device; /* PCI Device number */ - u8 pci_function; /* PCI Function number */ - u8 reserved[3]; - u32 timer_period; /* Period of one timer count (msec) */ - u32 max_count; /* Maximum counter value supported */ - u32 min_count; /* Minimum counter value */ - u8 flags; - u8 reserved2[3]; - u32 entries; /* Number of watchdog entries that follow */ -}; - -/* Masks for Flags field above */ - -#define ACPI_WDAT_ENABLED (1) -#define ACPI_WDAT_STOPPED 0x80 - -/* WDAT Instruction Entries (actions) */ - -struct acpi_wdat_entry { - u8 action; - u8 instruction; - u16 reserved; - struct acpi_generic_address register_region; - u32 value; /* Value used with Read/Write register */ - u32 mask; /* Bitmask required for this register instruction */ -}; - -/* Values for Action field above */ - -enum acpi_wdat_actions { - ACPI_WDAT_RESET = 1, - ACPI_WDAT_GET_CURRENT_COUNTDOWN = 4, - ACPI_WDAT_GET_COUNTDOWN = 5, - ACPI_WDAT_SET_COUNTDOWN = 6, - ACPI_WDAT_GET_RUNNING_STATE = 8, - ACPI_WDAT_SET_RUNNING_STATE = 9, - ACPI_WDAT_GET_STOPPED_STATE = 10, - ACPI_WDAT_SET_STOPPED_STATE = 11, - ACPI_WDAT_GET_REBOOT = 16, - ACPI_WDAT_SET_REBOOT = 17, - ACPI_WDAT_GET_SHUTDOWN = 18, - ACPI_WDAT_SET_SHUTDOWN = 19, - ACPI_WDAT_GET_STATUS = 32, - ACPI_WDAT_SET_STATUS = 33, - ACPI_WDAT_ACTION_RESERVED = 34 /* 34 and greater are reserved */ -}; - -/* Values for Instruction field above */ - -enum acpi_wdat_instructions { - ACPI_WDAT_READ_VALUE = 0, - ACPI_WDAT_READ_COUNTDOWN = 1, - ACPI_WDAT_WRITE_VALUE = 2, - ACPI_WDAT_WRITE_COUNTDOWN = 3, - ACPI_WDAT_INSTRUCTION_RESERVED = 4, /* 4 and greater are reserved */ - ACPI_WDAT_PRESERVE_REGISTER = 0x80 /* Except for this value */ -}; - -/******************************************************************************* - * - * WDDT - Watchdog Descriptor Table - * Version 1 - * - * Conforms to "Using the Intel ICH Family Watchdog Timer (WDT)", - * Version 001, September 2002 - * - ******************************************************************************/ - -struct acpi_table_wddt { - struct acpi_table_header header; /* Common ACPI table header */ - u16 spec_version; - u16 table_version; - u16 pci_vendor_id; - struct acpi_generic_address address; - u16 max_count; /* Maximum counter value supported */ - u16 min_count; /* Minimum counter value supported */ - u16 period; - u16 status; - u16 capability; -}; - -/* Flags for Status field above */ - -#define ACPI_WDDT_AVAILABLE (1) -#define ACPI_WDDT_ACTIVE (1<<1) -#define ACPI_WDDT_TCO_OS_OWNED (1<<2) -#define ACPI_WDDT_USER_RESET (1<<11) -#define ACPI_WDDT_WDT_RESET (1<<12) -#define ACPI_WDDT_POWER_FAIL (1<<13) -#define ACPI_WDDT_UNKNOWN_RESET (1<<14) - -/* Flags for Capability field above */ - -#define ACPI_WDDT_AUTO_RESET (1) -#define ACPI_WDDT_ALERT_SUPPORT (1<<1) - -/******************************************************************************* - * - * WDRT - Watchdog Resource Table - * Version 1 - * - * Conforms to "Watchdog Timer Hardware Requirements for Windows Server 2003", - * Version 1.01, August 28, 2006 - * - ******************************************************************************/ - -struct acpi_table_wdrt { - struct acpi_table_header header; /* Common ACPI table header */ - struct acpi_generic_address control_register; - struct acpi_generic_address count_register; - u16 pci_device_id; - u16 pci_vendor_id; - u8 pci_bus; /* PCI Bus number */ - u8 pci_device; /* PCI Device number */ - u8 pci_function; /* PCI Function number */ - u8 pci_segment; /* PCI Segment number */ - u16 max_count; /* Maximum counter value supported */ - u8 units; -}; - -/* Reset to default packing */ - -#pragma pack() - -#endif /* __ACTBL2_H__ */ diff --git a/src/linux/include/acpi/actbl3.h b/src/linux/include/acpi/actbl3.h deleted file mode 100644 index ebc1f4f..0000000 --- a/src/linux/include/acpi/actbl3.h +++ /dev/null @@ -1,788 +0,0 @@ -/****************************************************************************** - * - * Name: actbl3.h - ACPI Table Definitions - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACTBL3_H__ -#define __ACTBL3_H__ - -/******************************************************************************* - * - * Additional ACPI Tables (3) - * - * These tables are not consumed directly by the ACPICA subsystem, but are - * included here to support device drivers and the AML disassembler. - * - * In general, the tables in this file are fully defined within the ACPI - * specification. - * - ******************************************************************************/ - -/* - * Values for description table header signatures for tables defined in this - * file. Useful because they make it more difficult to inadvertently type in - * the wrong signature. - */ -#define ACPI_SIG_BGRT "BGRT" /* Boot Graphics Resource Table */ -#define ACPI_SIG_DRTM "DRTM" /* Dynamic Root of Trust for Measurement table */ -#define ACPI_SIG_FPDT "FPDT" /* Firmware Performance Data Table */ -#define ACPI_SIG_GTDT "GTDT" /* Generic Timer Description Table */ -#define ACPI_SIG_MPST "MPST" /* Memory Power State Table */ -#define ACPI_SIG_PCCT "PCCT" /* Platform Communications Channel Table */ -#define ACPI_SIG_PMTT "PMTT" /* Platform Memory Topology Table */ -#define ACPI_SIG_RASF "RASF" /* RAS Feature table */ -#define ACPI_SIG_STAO "STAO" /* Status Override table */ -#define ACPI_SIG_WPBT "WPBT" /* Windows Platform Binary Table */ -#define ACPI_SIG_XENV "XENV" /* Xen Environment table */ - -#define ACPI_SIG_S3PT "S3PT" /* S3 Performance (sub)Table */ -#define ACPI_SIG_PCCS "PCC" /* PCC Shared Memory Region */ - -/* Reserved table signatures */ - -#define ACPI_SIG_MATR "MATR" /* Memory Address Translation Table */ -#define ACPI_SIG_MSDM "MSDM" /* Microsoft Data Management Table */ - -/* - * All tables must be byte-packed to match the ACPI specification, since - * the tables are provided by the system BIOS. - */ -#pragma pack(1) - -/* - * Note: C bitfields are not used for this reason: - * - * "Bitfields are great and easy to read, but unfortunately the C language - * does not specify the layout of bitfields in memory, which means they are - * essentially useless for dealing with packed data in on-disk formats or - * binary wire protocols." (Or ACPI tables and buffers.) "If you ask me, - * this decision was a design error in C. Ritchie could have picked an order - * and stuck with it." Norman Ramsey. - * See http://stackoverflow.com/a/1053662/41661 - */ - -/******************************************************************************* - * - * BGRT - Boot Graphics Resource Table (ACPI 5.0) - * Version 1 - * - ******************************************************************************/ - -struct acpi_table_bgrt { - struct acpi_table_header header; /* Common ACPI table header */ - u16 version; - u8 status; - u8 image_type; - u64 image_address; - u32 image_offset_x; - u32 image_offset_y; -}; - -/******************************************************************************* - * - * DRTM - Dynamic Root of Trust for Measurement table - * Conforms to "TCG D-RTM Architecture" June 17 2013, Version 1.0.0 - * Table version 1 - * - ******************************************************************************/ - -struct acpi_table_drtm { - struct acpi_table_header header; /* Common ACPI table header */ - u64 entry_base_address; - u64 entry_length; - u32 entry_address32; - u64 entry_address64; - u64 exit_address; - u64 log_area_address; - u32 log_area_length; - u64 arch_dependent_address; - u32 flags; -}; - -/* Flag Definitions for above */ - -#define ACPI_DRTM_ACCESS_ALLOWED (1) -#define ACPI_DRTM_ENABLE_GAP_CODE (1<<1) -#define ACPI_DRTM_INCOMPLETE_MEASUREMENTS (1<<2) -#define ACPI_DRTM_AUTHORITY_ORDER (1<<3) - -/* 1) Validated Tables List (64-bit addresses) */ - -struct acpi_drtm_vtable_list { - u32 validated_table_count; - u64 validated_tables[1]; -}; - -/* 2) Resources List (of Resource Descriptors) */ - -/* Resource Descriptor */ - -struct acpi_drtm_resource { - u8 size[7]; - u8 type; - u64 address; -}; - -struct acpi_drtm_resource_list { - u32 resource_count; - struct acpi_drtm_resource resources[1]; -}; - -/* 3) Platform-specific Identifiers List */ - -struct acpi_drtm_dps_id { - u32 dps_id_length; - u8 dps_id[16]; -}; - -/******************************************************************************* - * - * FPDT - Firmware Performance Data Table (ACPI 5.0) - * Version 1 - * - ******************************************************************************/ - -struct acpi_table_fpdt { - struct acpi_table_header header; /* Common ACPI table header */ -}; - -/* FPDT subtable header (Performance Record Structure) */ - -struct acpi_fpdt_header { - u16 type; - u8 length; - u8 revision; -}; - -/* Values for Type field above */ - -enum acpi_fpdt_type { - ACPI_FPDT_TYPE_BOOT = 0, - ACPI_FPDT_TYPE_S3PERF = 1 -}; - -/* - * FPDT subtables - */ - -/* 0: Firmware Basic Boot Performance Record */ - -struct acpi_fpdt_boot_pointer { - struct acpi_fpdt_header header; - u8 reserved[4]; - u64 address; -}; - -/* 1: S3 Performance Table Pointer Record */ - -struct acpi_fpdt_s3pt_pointer { - struct acpi_fpdt_header header; - u8 reserved[4]; - u64 address; -}; - -/* - * S3PT - S3 Performance Table. This table is pointed to by the - * S3 Pointer Record above. - */ -struct acpi_table_s3pt { - u8 signature[4]; /* "S3PT" */ - u32 length; -}; - -/* - * S3PT Subtables (Not part of the actual FPDT) - */ - -/* Values for Type field in S3PT header */ - -enum acpi_s3pt_type { - ACPI_S3PT_TYPE_RESUME = 0, - ACPI_S3PT_TYPE_SUSPEND = 1, - ACPI_FPDT_BOOT_PERFORMANCE = 2 -}; - -struct acpi_s3pt_resume { - struct acpi_fpdt_header header; - u32 resume_count; - u64 full_resume; - u64 average_resume; -}; - -struct acpi_s3pt_suspend { - struct acpi_fpdt_header header; - u64 suspend_start; - u64 suspend_end; -}; - -/* - * FPDT Boot Performance Record (Not part of the actual FPDT) - */ -struct acpi_fpdt_boot { - struct acpi_fpdt_header header; - u8 reserved[4]; - u64 reset_end; - u64 load_start; - u64 startup_start; - u64 exit_services_entry; - u64 exit_services_exit; -}; - -/******************************************************************************* - * - * GTDT - Generic Timer Description Table (ACPI 5.1) - * Version 2 - * - ******************************************************************************/ - -struct acpi_table_gtdt { - struct acpi_table_header header; /* Common ACPI table header */ - u64 counter_block_addresss; - u32 reserved; - u32 secure_el1_interrupt; - u32 secure_el1_flags; - u32 non_secure_el1_interrupt; - u32 non_secure_el1_flags; - u32 virtual_timer_interrupt; - u32 virtual_timer_flags; - u32 non_secure_el2_interrupt; - u32 non_secure_el2_flags; - u64 counter_read_block_address; - u32 platform_timer_count; - u32 platform_timer_offset; -}; - -/* Flag Definitions: Timer Block Physical Timers and Virtual timers */ - -#define ACPI_GTDT_INTERRUPT_MODE (1) -#define ACPI_GTDT_INTERRUPT_POLARITY (1<<1) -#define ACPI_GTDT_ALWAYS_ON (1<<2) - -/* Common GTDT subtable header */ - -struct acpi_gtdt_header { - u8 type; - u16 length; -}; - -/* Values for GTDT subtable type above */ - -enum acpi_gtdt_type { - ACPI_GTDT_TYPE_TIMER_BLOCK = 0, - ACPI_GTDT_TYPE_WATCHDOG = 1, - ACPI_GTDT_TYPE_RESERVED = 2 /* 2 and greater are reserved */ -}; - -/* GTDT Subtables, correspond to Type in struct acpi_gtdt_header */ - -/* 0: Generic Timer Block */ - -struct acpi_gtdt_timer_block { - struct acpi_gtdt_header header; - u8 reserved; - u64 block_address; - u32 timer_count; - u32 timer_offset; -}; - -/* Timer Sub-Structure, one per timer */ - -struct acpi_gtdt_timer_entry { - u8 frame_number; - u8 reserved[3]; - u64 base_address; - u64 el0_base_address; - u32 timer_interrupt; - u32 timer_flags; - u32 virtual_timer_interrupt; - u32 virtual_timer_flags; - u32 common_flags; -}; - -/* Flag Definitions: timer_flags and virtual_timer_flags above */ - -#define ACPI_GTDT_GT_IRQ_MODE (1) -#define ACPI_GTDT_GT_IRQ_POLARITY (1<<1) - -/* Flag Definitions: common_flags above */ - -#define ACPI_GTDT_GT_IS_SECURE_TIMER (1) -#define ACPI_GTDT_GT_ALWAYS_ON (1<<1) - -/* 1: SBSA Generic Watchdog Structure */ - -struct acpi_gtdt_watchdog { - struct acpi_gtdt_header header; - u8 reserved; - u64 refresh_frame_address; - u64 control_frame_address; - u32 timer_interrupt; - u32 timer_flags; -}; - -/* Flag Definitions: timer_flags above */ - -#define ACPI_GTDT_WATCHDOG_IRQ_MODE (1) -#define ACPI_GTDT_WATCHDOG_IRQ_POLARITY (1<<1) -#define ACPI_GTDT_WATCHDOG_SECURE (1<<2) - -/******************************************************************************* - * - * MPST - Memory Power State Table (ACPI 5.0) - * Version 1 - * - ******************************************************************************/ - -#define ACPI_MPST_CHANNEL_INFO \ - u8 channel_id; \ - u8 reserved1[3]; \ - u16 power_node_count; \ - u16 reserved2; - -/* Main table */ - -struct acpi_table_mpst { - struct acpi_table_header header; /* Common ACPI table header */ - ACPI_MPST_CHANNEL_INFO /* Platform Communication Channel */ -}; - -/* Memory Platform Communication Channel Info */ - -struct acpi_mpst_channel { - ACPI_MPST_CHANNEL_INFO /* Platform Communication Channel */ -}; - -/* Memory Power Node Structure */ - -struct acpi_mpst_power_node { - u8 flags; - u8 reserved1; - u16 node_id; - u32 length; - u64 range_address; - u64 range_length; - u32 num_power_states; - u32 num_physical_components; -}; - -/* Values for Flags field above */ - -#define ACPI_MPST_ENABLED 1 -#define ACPI_MPST_POWER_MANAGED 2 -#define ACPI_MPST_HOT_PLUG_CAPABLE 4 - -/* Memory Power State Structure (follows POWER_NODE above) */ - -struct acpi_mpst_power_state { - u8 power_state; - u8 info_index; -}; - -/* Physical Component ID Structure (follows POWER_STATE above) */ - -struct acpi_mpst_component { - u16 component_id; -}; - -/* Memory Power State Characteristics Structure (follows all POWER_NODEs) */ - -struct acpi_mpst_data_hdr { - u16 characteristics_count; - u16 reserved; -}; - -struct acpi_mpst_power_data { - u8 structure_id; - u8 flags; - u16 reserved1; - u32 average_power; - u32 power_saving; - u64 exit_latency; - u64 reserved2; -}; - -/* Values for Flags field above */ - -#define ACPI_MPST_PRESERVE 1 -#define ACPI_MPST_AUTOENTRY 2 -#define ACPI_MPST_AUTOEXIT 4 - -/* Shared Memory Region (not part of an ACPI table) */ - -struct acpi_mpst_shared { - u32 signature; - u16 pcc_command; - u16 pcc_status; - u32 command_register; - u32 status_register; - u32 power_state_id; - u32 power_node_id; - u64 energy_consumed; - u64 average_power; -}; - -/******************************************************************************* - * - * PCCT - Platform Communications Channel Table (ACPI 5.0) - * Version 1 - * - ******************************************************************************/ - -struct acpi_table_pcct { - struct acpi_table_header header; /* Common ACPI table header */ - u32 flags; - u64 reserved; -}; - -/* Values for Flags field above */ - -#define ACPI_PCCT_DOORBELL 1 - -/* Values for subtable type in struct acpi_subtable_header */ - -enum acpi_pcct_type { - ACPI_PCCT_TYPE_GENERIC_SUBSPACE = 0, - ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE = 1, - ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE_TYPE2 = 2, /* ACPI 6.1 */ - ACPI_PCCT_TYPE_RESERVED = 3 /* 3 and greater are reserved */ -}; - -/* - * PCCT Subtables, correspond to Type in struct acpi_subtable_header - */ - -/* 0: Generic Communications Subspace */ - -struct acpi_pcct_subspace { - struct acpi_subtable_header header; - u8 reserved[6]; - u64 base_address; - u64 length; - struct acpi_generic_address doorbell_register; - u64 preserve_mask; - u64 write_mask; - u32 latency; - u32 max_access_rate; - u16 min_turnaround_time; -}; - -/* 1: HW-reduced Communications Subspace (ACPI 5.1) */ - -struct acpi_pcct_hw_reduced { - struct acpi_subtable_header header; - u32 doorbell_interrupt; - u8 flags; - u8 reserved; - u64 base_address; - u64 length; - struct acpi_generic_address doorbell_register; - u64 preserve_mask; - u64 write_mask; - u32 latency; - u32 max_access_rate; - u16 min_turnaround_time; -}; - -/* 2: HW-reduced Communications Subspace Type 2 (ACPI 6.1) */ - -struct acpi_pcct_hw_reduced_type2 { - struct acpi_subtable_header header; - u32 doorbell_interrupt; - u8 flags; - u8 reserved; - u64 base_address; - u64 length; - struct acpi_generic_address doorbell_register; - u64 preserve_mask; - u64 write_mask; - u32 latency; - u32 max_access_rate; - u16 min_turnaround_time; - struct acpi_generic_address doorbell_ack_register; - u64 ack_preserve_mask; - u64 ack_write_mask; -}; - -/* Values for doorbell flags above */ - -#define ACPI_PCCT_INTERRUPT_POLARITY (1) -#define ACPI_PCCT_INTERRUPT_MODE (1<<1) - -/* - * PCC memory structures (not part of the ACPI table) - */ - -/* Shared Memory Region */ - -struct acpi_pcct_shared_memory { - u32 signature; - u16 command; - u16 status; -}; - -/******************************************************************************* - * - * PMTT - Platform Memory Topology Table (ACPI 5.0) - * Version 1 - * - ******************************************************************************/ - -struct acpi_table_pmtt { - struct acpi_table_header header; /* Common ACPI table header */ - u32 reserved; -}; - -/* Common header for PMTT subtables that follow main table */ - -struct acpi_pmtt_header { - u8 type; - u8 reserved1; - u16 length; - u16 flags; - u16 reserved2; -}; - -/* Values for Type field above */ - -#define ACPI_PMTT_TYPE_SOCKET 0 -#define ACPI_PMTT_TYPE_CONTROLLER 1 -#define ACPI_PMTT_TYPE_DIMM 2 -#define ACPI_PMTT_TYPE_RESERVED 3 /* 0x03-0xFF are reserved */ - -/* Values for Flags field above */ - -#define ACPI_PMTT_TOP_LEVEL 0x0001 -#define ACPI_PMTT_PHYSICAL 0x0002 -#define ACPI_PMTT_MEMORY_TYPE 0x000C - -/* - * PMTT subtables, correspond to Type in struct acpi_pmtt_header - */ - -/* 0: Socket Structure */ - -struct acpi_pmtt_socket { - struct acpi_pmtt_header header; - u16 socket_id; - u16 reserved; -}; - -/* 1: Memory Controller subtable */ - -struct acpi_pmtt_controller { - struct acpi_pmtt_header header; - u32 read_latency; - u32 write_latency; - u32 read_bandwidth; - u32 write_bandwidth; - u16 access_width; - u16 alignment; - u16 reserved; - u16 domain_count; -}; - -/* 1a: Proximity Domain substructure */ - -struct acpi_pmtt_domain { - u32 proximity_domain; -}; - -/* 2: Physical Component Identifier (DIMM) */ - -struct acpi_pmtt_physical_component { - struct acpi_pmtt_header header; - u16 component_id; - u16 reserved; - u32 memory_size; - u32 bios_handle; -}; - -/******************************************************************************* - * - * RASF - RAS Feature Table (ACPI 5.0) - * Version 1 - * - ******************************************************************************/ - -struct acpi_table_rasf { - struct acpi_table_header header; /* Common ACPI table header */ - u8 channel_id[12]; -}; - -/* RASF Platform Communication Channel Shared Memory Region */ - -struct acpi_rasf_shared_memory { - u32 signature; - u16 command; - u16 status; - u16 version; - u8 capabilities[16]; - u8 set_capabilities[16]; - u16 num_parameter_blocks; - u32 set_capabilities_status; -}; - -/* RASF Parameter Block Structure Header */ - -struct acpi_rasf_parameter_block { - u16 type; - u16 version; - u16 length; -}; - -/* RASF Parameter Block Structure for PATROL_SCRUB */ - -struct acpi_rasf_patrol_scrub_parameter { - struct acpi_rasf_parameter_block header; - u16 patrol_scrub_command; - u64 requested_address_range[2]; - u64 actual_address_range[2]; - u16 flags; - u8 requested_speed; -}; - -/* Masks for Flags and Speed fields above */ - -#define ACPI_RASF_SCRUBBER_RUNNING 1 -#define ACPI_RASF_SPEED (7<<1) -#define ACPI_RASF_SPEED_SLOW (0<<1) -#define ACPI_RASF_SPEED_MEDIUM (4<<1) -#define ACPI_RASF_SPEED_FAST (7<<1) - -/* Channel Commands */ - -enum acpi_rasf_commands { - ACPI_RASF_EXECUTE_RASF_COMMAND = 1 -}; - -/* Platform RAS Capabilities */ - -enum acpi_rasf_capabiliities { - ACPI_HW_PATROL_SCRUB_SUPPORTED = 0, - ACPI_SW_PATROL_SCRUB_EXPOSED = 1 -}; - -/* Patrol Scrub Commands */ - -enum acpi_rasf_patrol_scrub_commands { - ACPI_RASF_GET_PATROL_PARAMETERS = 1, - ACPI_RASF_START_PATROL_SCRUBBER = 2, - ACPI_RASF_STOP_PATROL_SCRUBBER = 3 -}; - -/* Channel Command flags */ - -#define ACPI_RASF_GENERATE_SCI (1<<15) - -/* Status values */ - -enum acpi_rasf_status { - ACPI_RASF_SUCCESS = 0, - ACPI_RASF_NOT_VALID = 1, - ACPI_RASF_NOT_SUPPORTED = 2, - ACPI_RASF_BUSY = 3, - ACPI_RASF_FAILED = 4, - ACPI_RASF_ABORTED = 5, - ACPI_RASF_INVALID_DATA = 6 -}; - -/* Status flags */ - -#define ACPI_RASF_COMMAND_COMPLETE (1) -#define ACPI_RASF_SCI_DOORBELL (1<<1) -#define ACPI_RASF_ERROR (1<<2) -#define ACPI_RASF_STATUS (0x1F<<3) - -/******************************************************************************* - * - * STAO - Status Override Table (_STA override) - ACPI 6.0 - * Version 1 - * - * Conforms to "ACPI Specification for Status Override Table" - * 6 January 2015 - * - ******************************************************************************/ - -struct acpi_table_stao { - struct acpi_table_header header; /* Common ACPI table header */ - u8 ignore_uart; -}; - -/******************************************************************************* - * - * WPBT - Windows Platform Environment Table (ACPI 6.0) - * Version 1 - * - * Conforms to "Windows Platform Binary Table (WPBT)" 29 November 2011 - * - ******************************************************************************/ - -struct acpi_table_wpbt { - struct acpi_table_header header; /* Common ACPI table header */ - u32 handoff_size; - u64 handoff_address; - u8 layout; - u8 type; - u16 arguments_length; -}; - -/******************************************************************************* - * - * XENV - Xen Environment Table (ACPI 6.0) - * Version 1 - * - * Conforms to "ACPI Specification for Xen Environment Table" 4 January 2015 - * - ******************************************************************************/ - -struct acpi_table_xenv { - struct acpi_table_header header; /* Common ACPI table header */ - u64 grant_table_address; - u64 grant_table_size; - u32 event_interrupt; - u8 event_flags; -}; - -/* Reset to default packing */ - -#pragma pack() - -#endif /* __ACTBL3_H__ */ diff --git a/src/linux/include/acpi/actypes.h b/src/linux/include/acpi/actypes.h deleted file mode 100644 index 1d798ab..0000000 --- a/src/linux/include/acpi/actypes.h +++ /dev/null @@ -1,1293 +0,0 @@ -/****************************************************************************** - * - * Name: actypes.h - Common data types for the entire ACPI subsystem - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACTYPES_H__ -#define __ACTYPES_H__ - -/* acpisrc:struct_defs -- for acpisrc conversion */ - -/* - * ACPI_MACHINE_WIDTH must be specified in an OS- or compiler-dependent header - * and must be either 32 or 64. 16-bit ACPICA is no longer supported, as of - * 12/2006. - */ -#ifndef ACPI_MACHINE_WIDTH -#error ACPI_MACHINE_WIDTH not defined -#endif - -/* - * Data type ranges - * Note: These macros are designed to be compiler independent as well as - * working around problems that some 32-bit compilers have with 64-bit - * constants. - */ -#define ACPI_UINT8_MAX (u8) (~((u8) 0)) /* 0xFF */ -#define ACPI_UINT16_MAX (u16)(~((u16) 0)) /* 0xFFFF */ -#define ACPI_UINT32_MAX (u32)(~((u32) 0)) /* 0xFFFFFFFF */ -#define ACPI_UINT64_MAX (u64)(~((u64) 0)) /* 0xFFFFFFFFFFFFFFFF */ -#define ACPI_ASCII_MAX 0x7F - -/* - * Architecture-specific ACPICA Subsystem Data Types - * - * The goal of these types is to provide source code portability across - * 16-bit, 32-bit, and 64-bit targets. - * - * 1) The following types are of fixed size for all targets (16/32/64): - * - * u8 Logical boolean - * - * u8 8-bit (1 byte) unsigned value - * u16 16-bit (2 byte) unsigned value - * u32 32-bit (4 byte) unsigned value - * u64 64-bit (8 byte) unsigned value - * - * s16 16-bit (2 byte) signed value - * s32 32-bit (4 byte) signed value - * s64 64-bit (8 byte) signed value - * - * COMPILER_DEPENDENT_UINT64/s64 - These types are defined in the - * compiler-dependent header(s) and were introduced because there is no common - * 64-bit integer type across the various compilation models, as shown in - * the table below. - * - * Datatype LP64 ILP64 LLP64 ILP32 LP32 16bit - * char 8 8 8 8 8 8 - * short 16 16 16 16 16 16 - * _int32 32 - * int 32 64 32 32 16 16 - * long 64 64 32 32 32 32 - * long long 64 64 - * pointer 64 64 64 32 32 32 - * - * Note: ILP64 and LP32 are currently not supported. - * - * - * 2) These types represent the native word size of the target mode of the - * processor, and may be 16-bit, 32-bit, or 64-bit as required. They are - * usually used for memory allocation, efficient loop counters, and array - * indexes. The types are similar to the size_t type in the C library and are - * required because there is no C type that consistently represents the native - * data width. acpi_size is needed because there is no guarantee that a - * kernel-level C library is present. - * - * acpi_size 16/32/64-bit unsigned value - * acpi_native_int 16/32/64-bit signed value - */ - -/******************************************************************************* - * - * Common types for all compilers, all targets - * - ******************************************************************************/ - -#ifndef ACPI_USE_SYSTEM_INTTYPES - -typedef unsigned char u8; -typedef unsigned short u16; -typedef short s16; -typedef COMPILER_DEPENDENT_UINT64 u64; -typedef COMPILER_DEPENDENT_INT64 s64; - -#endif /* ACPI_USE_SYSTEM_INTTYPES */ - -/* - * Value returned by acpi_os_get_thread_id. There is no standard "thread_id" - * across operating systems or even the various UNIX systems. Since ACPICA - * only needs the thread ID as a unique thread identifier, we use a u64 - * as the only common data type - it will accommodate any type of pointer or - * any type of integer. It is up to the host-dependent OSL to cast the - * native thread ID type to a u64 (in acpi_os_get_thread_id). - */ -#define acpi_thread_id u64 - -/******************************************************************************* - * - * Types specific to 64-bit targets - * - ******************************************************************************/ - -#if ACPI_MACHINE_WIDTH == 64 - -#ifndef ACPI_USE_SYSTEM_INTTYPES - -typedef unsigned int u32; -typedef int s32; - -#endif /* ACPI_USE_SYSTEM_INTTYPES */ - -typedef s64 acpi_native_int; - -typedef u64 acpi_size; -typedef u64 acpi_io_address; -typedef u64 acpi_physical_address; - -#define ACPI_MAX_PTR ACPI_UINT64_MAX -#define ACPI_SIZE_MAX ACPI_UINT64_MAX - -#define ACPI_USE_NATIVE_DIVIDE /* Has native 64-bit integer support */ - -/* - * In the case of the Itanium Processor Family (IPF), the hardware does not - * support misaligned memory transfers. Set the MISALIGNMENT_NOT_SUPPORTED flag - * to indicate that special precautions must be taken to avoid alignment faults. - * (IA64 or ia64 is currently used by existing compilers to indicate IPF.) - * - * Note: EM64T and other X86-64 processors support misaligned transfers, - * so there is no need to define this flag. - */ -#if defined (__IA64__) || defined (__ia64__) -#define ACPI_MISALIGNMENT_NOT_SUPPORTED -#endif - -/******************************************************************************* - * - * Types specific to 32-bit targets - * - ******************************************************************************/ - -#elif ACPI_MACHINE_WIDTH == 32 - -#ifndef ACPI_USE_SYSTEM_INTTYPES - -typedef unsigned int u32; -typedef int s32; - -#endif /* ACPI_USE_SYSTEM_INTTYPES */ - -typedef s32 acpi_native_int; - -typedef u32 acpi_size; - -#ifdef ACPI_32BIT_PHYSICAL_ADDRESS - -/* - * OSPMs can define this to shrink the size of the structures for 32-bit - * none PAE environment. ASL compiler may always define this to generate - * 32-bit OSPM compliant tables. - */ -typedef u32 acpi_io_address; -typedef u32 acpi_physical_address; - -#else /* ACPI_32BIT_PHYSICAL_ADDRESS */ - -/* - * It is reported that, after some calculations, the physical addresses can - * wrap over the 32-bit boundary on 32-bit PAE environment. - * https://bugzilla.kernel.org/show_bug.cgi?id=87971 - */ -typedef u64 acpi_io_address; -typedef u64 acpi_physical_address; - -#endif /* ACPI_32BIT_PHYSICAL_ADDRESS */ - -#define ACPI_MAX_PTR ACPI_UINT32_MAX -#define ACPI_SIZE_MAX ACPI_UINT32_MAX - -#else - -/* ACPI_MACHINE_WIDTH must be either 64 or 32 */ - -#error unknown ACPI_MACHINE_WIDTH -#endif - -/******************************************************************************* - * - * OS-dependent types - * - * If the defaults below are not appropriate for the host system, they can - * be defined in the OS-specific header, and this will take precedence. - * - ******************************************************************************/ - -/* Flags for acpi_os_acquire_lock/acpi_os_release_lock */ - -#ifndef acpi_cpu_flags -#define acpi_cpu_flags acpi_size -#endif - -/* Object returned from acpi_os_create_cache */ - -#ifndef acpi_cache_t -#ifdef ACPI_USE_LOCAL_CACHE -#define acpi_cache_t struct acpi_memory_list -#else -#define acpi_cache_t void * -#endif -#endif - -/* - * Synchronization objects - Mutexes, Semaphores, and spin_locks - */ -#if (ACPI_MUTEX_TYPE == ACPI_BINARY_SEMAPHORE) -/* - * These macros are used if the host OS does not support a mutex object. - * Map the OSL Mutex interfaces to binary semaphores. - */ -#define acpi_mutex acpi_semaphore -#define acpi_os_create_mutex(out_handle) acpi_os_create_semaphore (1, 1, out_handle) -#define acpi_os_delete_mutex(handle) (void) acpi_os_delete_semaphore (handle) -#define acpi_os_acquire_mutex(handle,time) acpi_os_wait_semaphore (handle, 1, time) -#define acpi_os_release_mutex(handle) (void) acpi_os_signal_semaphore (handle, 1) -#endif - -/* Configurable types for synchronization objects */ - -#ifndef acpi_spinlock -#define acpi_spinlock void * -#endif - -#ifndef acpi_semaphore -#define acpi_semaphore void * -#endif - -#ifndef acpi_mutex -#define acpi_mutex void * -#endif - -/******************************************************************************* - * - * Compiler-dependent types - * - * If the defaults below are not appropriate for the host compiler, they can - * be defined in the compiler-specific header, and this will take precedence. - * - ******************************************************************************/ - -/* Use C99 uintptr_t for pointer casting if available, "void *" otherwise */ - -#ifndef acpi_uintptr_t -#define acpi_uintptr_t void * -#endif - -/* - * ACPI_PRINTF_LIKE is used to tag functions as "printf-like" because - * some compilers can catch printf format string problems - */ -#ifndef ACPI_PRINTF_LIKE -#define ACPI_PRINTF_LIKE(c) -#endif - -/* - * Some compilers complain about unused variables. Sometimes we don't want to - * use all the variables (for example, _acpi_module_name). This allows us - * to tell the compiler in a per-variable manner that a variable - * is unused - */ -#ifndef ACPI_UNUSED_VAR -#define ACPI_UNUSED_VAR -#endif - -/* - * All ACPICA external functions that are available to the rest of the kernel - * are tagged with thes macros which can be defined as appropriate for the host. - * - * Notes: - * ACPI_EXPORT_SYMBOL_INIT is used for initialization and termination - * interfaces that may need special processing. - * ACPI_EXPORT_SYMBOL is used for all other public external functions. - */ -#ifndef ACPI_EXPORT_SYMBOL_INIT -#define ACPI_EXPORT_SYMBOL_INIT(symbol) -#endif - -#ifndef ACPI_EXPORT_SYMBOL -#define ACPI_EXPORT_SYMBOL(symbol) -#endif - -/* - * Compiler/Clibrary-dependent debug initialization. Used for ACPICA - * utilities only. - */ -#ifndef ACPI_DEBUG_INITIALIZE -#define ACPI_DEBUG_INITIALIZE() -#endif - -/******************************************************************************* - * - * Configuration - * - ******************************************************************************/ - -#ifdef ACPI_NO_MEM_ALLOCATIONS - -#define ACPI_ALLOCATE(a) NULL -#define ACPI_ALLOCATE_ZEROED(a) NULL -#define ACPI_FREE(a) -#define ACPI_MEM_TRACKING(a) - -#else /* ACPI_NO_MEM_ALLOCATIONS */ - -#ifdef ACPI_DBG_TRACK_ALLOCATIONS -/* - * Memory allocation tracking (used by acpi_exec to detect memory leaks) - */ -#define ACPI_MEM_PARAMETERS _COMPONENT, _acpi_module_name, __LINE__ -#define ACPI_ALLOCATE(a) acpi_ut_allocate_and_track ((acpi_size) (a), ACPI_MEM_PARAMETERS) -#define ACPI_ALLOCATE_ZEROED(a) acpi_ut_allocate_zeroed_and_track ((acpi_size) (a), ACPI_MEM_PARAMETERS) -#define ACPI_FREE(a) acpi_ut_free_and_track (a, ACPI_MEM_PARAMETERS) -#define ACPI_MEM_TRACKING(a) a - -#else -/* - * Normal memory allocation directly via the OS services layer - */ -#define ACPI_ALLOCATE(a) acpi_os_allocate ((acpi_size) (a)) -#define ACPI_ALLOCATE_ZEROED(a) acpi_os_allocate_zeroed ((acpi_size) (a)) -#define ACPI_FREE(a) acpi_os_free (a) -#define ACPI_MEM_TRACKING(a) - -#endif /* ACPI_DBG_TRACK_ALLOCATIONS */ - -#endif /* ACPI_NO_MEM_ALLOCATIONS */ - -/****************************************************************************** - * - * ACPI Specification constants (Do not change unless the specification changes) - * - *****************************************************************************/ - -/* Number of distinct FADT-based GPE register blocks (GPE0 and GPE1) */ - -#define ACPI_MAX_GPE_BLOCKS 2 - -/* Default ACPI register widths */ - -#define ACPI_GPE_REGISTER_WIDTH 8 -#define ACPI_PM1_REGISTER_WIDTH 16 -#define ACPI_PM2_REGISTER_WIDTH 8 -#define ACPI_PM_TIMER_WIDTH 32 -#define ACPI_RESET_REGISTER_WIDTH 8 - -/* Names within the namespace are 4 bytes long */ - -#define ACPI_NAME_SIZE 4 -#define ACPI_PATH_SEGMENT_LENGTH 5 /* 4 chars for name + 1 char for separator */ -#define ACPI_PATH_SEPARATOR '.' - -/* Sizes for ACPI table headers */ - -#define ACPI_OEM_ID_SIZE 6 -#define ACPI_OEM_TABLE_ID_SIZE 8 - -/* ACPI/PNP hardware IDs */ - -#define PCI_ROOT_HID_STRING "PNP0A03" -#define PCI_EXPRESS_ROOT_HID_STRING "PNP0A08" - -/* PM Timer ticks per second (HZ) */ - -#define ACPI_PM_TIMER_FREQUENCY 3579545 - -/******************************************************************************* - * - * Independent types - * - ******************************************************************************/ - -/* Logical defines and NULL */ - -#ifdef FALSE -#undef FALSE -#endif -#define FALSE (1 == 0) - -#ifdef TRUE -#undef TRUE -#endif -#define TRUE (1 == 1) - -#ifndef NULL -#define NULL (void *) 0 -#endif - -/* - * Miscellaneous types - */ -typedef u32 acpi_status; /* All ACPI Exceptions */ -typedef u32 acpi_name; /* 4-byte ACPI name */ -typedef char *acpi_string; /* Null terminated ASCII string */ -typedef void *acpi_handle; /* Actually a ptr to a NS Node */ - -/* Time constants for timer calculations */ - -#define ACPI_MSEC_PER_SEC 1000L - -#define ACPI_USEC_PER_MSEC 1000L -#define ACPI_USEC_PER_SEC 1000000L - -#define ACPI_100NSEC_PER_USEC 10L -#define ACPI_100NSEC_PER_MSEC 10000L -#define ACPI_100NSEC_PER_SEC 10000000L - -#define ACPI_NSEC_PER_USEC 1000L -#define ACPI_NSEC_PER_MSEC 1000000L -#define ACPI_NSEC_PER_SEC 1000000000L - -/* Owner IDs are used to track namespace nodes for selective deletion */ - -typedef u8 acpi_owner_id; -#define ACPI_OWNER_ID_MAX 0xFF - -#define ACPI_INTEGER_BIT_SIZE 64 -#define ACPI_MAX_DECIMAL_DIGITS 20 /* 2^64 = 18,446,744,073,709,551,616 */ -#define ACPI_MAX64_DECIMAL_DIGITS 20 -#define ACPI_MAX32_DECIMAL_DIGITS 10 -#define ACPI_MAX16_DECIMAL_DIGITS 5 -#define ACPI_MAX8_DECIMAL_DIGITS 3 - -/* - * Constants with special meanings - */ -#define ACPI_ROOT_OBJECT ACPI_ADD_PTR (acpi_handle, NULL, ACPI_MAX_PTR) -#define ACPI_WAIT_FOREVER 0xFFFF /* u16, as per ACPI spec */ -#define ACPI_DO_NOT_WAIT 0 - -/* - * Obsolete: Acpi integer width. In ACPI version 1 (1996), integers are 32 bits. - * In ACPI version 2 (2000) and later, integers are 64 bits. Note that this - * pertains to the ACPI integer type only, not to other integers used in the - * implementation of the ACPICA subsystem. - * - * 01/2010: This type is obsolete and has been removed from the entire ACPICA - * code base. It remains here for compatibility with device drivers that use - * the type. However, it will be removed in the future. - */ -typedef u64 acpi_integer; -#define ACPI_INTEGER_MAX ACPI_UINT64_MAX - -/******************************************************************************* - * - * Commonly used macros - * - ******************************************************************************/ - -/* Data manipulation */ - -#define ACPI_LOBYTE(integer) ((u8) (u16)(integer)) -#define ACPI_HIBYTE(integer) ((u8) (((u16)(integer)) >> 8)) -#define ACPI_LOWORD(integer) ((u16) (u32)(integer)) -#define ACPI_HIWORD(integer) ((u16)(((u32)(integer)) >> 16)) -#define ACPI_LODWORD(integer64) ((u32) (u64)(integer64)) -#define ACPI_HIDWORD(integer64) ((u32)(((u64)(integer64)) >> 32)) - -#define ACPI_SET_BIT(target,bit) ((target) |= (bit)) -#define ACPI_CLEAR_BIT(target,bit) ((target) &= ~(bit)) -#define ACPI_MIN(a,b) (((a)<(b))?(a):(b)) -#define ACPI_MAX(a,b) (((a)>(b))?(a):(b)) - -/* Size calculation */ - -#define ACPI_ARRAY_LENGTH(x) (sizeof(x) / sizeof((x)[0])) - -/* Pointer manipulation */ - -#define ACPI_CAST_PTR(t, p) ((t *) (acpi_uintptr_t) (p)) -#define ACPI_CAST_INDIRECT_PTR(t, p) ((t **) (acpi_uintptr_t) (p)) -#define ACPI_ADD_PTR(t, a, b) ACPI_CAST_PTR (t, (ACPI_CAST_PTR (u8, (a)) + (acpi_size)(b))) -#define ACPI_SUB_PTR(t, a, b) ACPI_CAST_PTR (t, (ACPI_CAST_PTR (u8, (a)) - (acpi_size)(b))) -#define ACPI_PTR_DIFF(a, b) (acpi_size) (ACPI_CAST_PTR (u8, (a)) - ACPI_CAST_PTR (u8, (b))) - -/* Pointer/Integer type conversions */ - -#define ACPI_TO_POINTER(i) ACPI_ADD_PTR (void, (void *) NULL,(acpi_size) i) -#define ACPI_TO_INTEGER(p) ACPI_PTR_DIFF (p, (void *) NULL) -#define ACPI_OFFSET(d, f) ACPI_PTR_DIFF (&(((d *) 0)->f), (void *) NULL) -#define ACPI_PHYSADDR_TO_PTR(i) ACPI_TO_POINTER(i) -#define ACPI_PTR_TO_PHYSADDR(i) ACPI_TO_INTEGER(i) - -/* Optimizations for 4-character (32-bit) acpi_name manipulation */ - -#ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED -#define ACPI_COMPARE_NAME(a,b) (*ACPI_CAST_PTR (u32, (a)) == *ACPI_CAST_PTR (u32, (b))) -#define ACPI_MOVE_NAME(dest,src) (*ACPI_CAST_PTR (u32, (dest)) = *ACPI_CAST_PTR (u32, (src))) -#else -#define ACPI_COMPARE_NAME(a,b) (!strncmp (ACPI_CAST_PTR (char, (a)), ACPI_CAST_PTR (char, (b)), ACPI_NAME_SIZE)) -#define ACPI_MOVE_NAME(dest,src) (strncpy (ACPI_CAST_PTR (char, (dest)), ACPI_CAST_PTR (char, (src)), ACPI_NAME_SIZE)) -#endif - -/* Support for the special RSDP signature (8 characters) */ - -#define ACPI_VALIDATE_RSDP_SIG(a) (!strncmp (ACPI_CAST_PTR (char, (a)), ACPI_SIG_RSDP, 8)) -#define ACPI_MAKE_RSDP_SIG(dest) (memcpy (ACPI_CAST_PTR (char, (dest)), ACPI_SIG_RSDP, 8)) - -/******************************************************************************* - * - * Miscellaneous constants - * - ******************************************************************************/ - -/* - * Initialization sequence - */ -#define ACPI_FULL_INITIALIZATION 0x00 -#define ACPI_NO_ADDRESS_SPACE_INIT 0x01 -#define ACPI_NO_HARDWARE_INIT 0x02 -#define ACPI_NO_EVENT_INIT 0x04 -#define ACPI_NO_HANDLER_INIT 0x08 -#define ACPI_NO_ACPI_ENABLE 0x10 -#define ACPI_NO_DEVICE_INIT 0x20 -#define ACPI_NO_OBJECT_INIT 0x40 -#define ACPI_NO_FACS_INIT 0x80 - -/* - * Initialization state - */ -#define ACPI_SUBSYSTEM_INITIALIZE 0x01 -#define ACPI_INITIALIZED_OK 0x02 - -/* - * Power state values - */ -#define ACPI_STATE_UNKNOWN (u8) 0xFF - -#define ACPI_STATE_S0 (u8) 0 -#define ACPI_STATE_S1 (u8) 1 -#define ACPI_STATE_S2 (u8) 2 -#define ACPI_STATE_S3 (u8) 3 -#define ACPI_STATE_S4 (u8) 4 -#define ACPI_STATE_S5 (u8) 5 -#define ACPI_S_STATES_MAX ACPI_STATE_S5 -#define ACPI_S_STATE_COUNT 6 - -#define ACPI_STATE_D0 (u8) 0 -#define ACPI_STATE_D1 (u8) 1 -#define ACPI_STATE_D2 (u8) 2 -#define ACPI_STATE_D3_HOT (u8) 3 -#define ACPI_STATE_D3 (u8) 4 -#define ACPI_STATE_D3_COLD ACPI_STATE_D3 -#define ACPI_D_STATES_MAX ACPI_STATE_D3 -#define ACPI_D_STATE_COUNT 5 - -#define ACPI_STATE_C0 (u8) 0 -#define ACPI_STATE_C1 (u8) 1 -#define ACPI_STATE_C2 (u8) 2 -#define ACPI_STATE_C3 (u8) 3 -#define ACPI_C_STATES_MAX ACPI_STATE_C3 -#define ACPI_C_STATE_COUNT 4 - -/* - * Sleep type invalid value - */ -#define ACPI_SLEEP_TYPE_MAX 0x7 -#define ACPI_SLEEP_TYPE_INVALID 0xFF - -/* - * Standard notify values - */ -#define ACPI_NOTIFY_BUS_CHECK (u8) 0x00 -#define ACPI_NOTIFY_DEVICE_CHECK (u8) 0x01 -#define ACPI_NOTIFY_DEVICE_WAKE (u8) 0x02 -#define ACPI_NOTIFY_EJECT_REQUEST (u8) 0x03 -#define ACPI_NOTIFY_DEVICE_CHECK_LIGHT (u8) 0x04 -#define ACPI_NOTIFY_FREQUENCY_MISMATCH (u8) 0x05 -#define ACPI_NOTIFY_BUS_MODE_MISMATCH (u8) 0x06 -#define ACPI_NOTIFY_POWER_FAULT (u8) 0x07 -#define ACPI_NOTIFY_CAPABILITIES_CHECK (u8) 0x08 -#define ACPI_NOTIFY_DEVICE_PLD_CHECK (u8) 0x09 -#define ACPI_NOTIFY_RESERVED (u8) 0x0A -#define ACPI_NOTIFY_LOCALITY_UPDATE (u8) 0x0B -#define ACPI_NOTIFY_SHUTDOWN_REQUEST (u8) 0x0C -#define ACPI_NOTIFY_AFFINITY_UPDATE (u8) 0x0D - -#define ACPI_GENERIC_NOTIFY_MAX 0x0D -#define ACPI_SPECIFIC_NOTIFY_MAX 0x84 - -/* - * Types associated with ACPI names and objects. The first group of - * values (up to ACPI_TYPE_EXTERNAL_MAX) correspond to the definition - * of the ACPI object_type() operator (See the ACPI Spec). Therefore, - * only add to the first group if the spec changes. - * - * NOTE: Types must be kept in sync with the global acpi_ns_properties - * and acpi_ns_type_names arrays. - */ -typedef u32 acpi_object_type; - -#define ACPI_TYPE_ANY 0x00 -#define ACPI_TYPE_INTEGER 0x01 /* Byte/Word/Dword/Zero/One/Ones */ -#define ACPI_TYPE_STRING 0x02 -#define ACPI_TYPE_BUFFER 0x03 -#define ACPI_TYPE_PACKAGE 0x04 /* byte_const, multiple data_term/Constant/super_name */ -#define ACPI_TYPE_FIELD_UNIT 0x05 -#define ACPI_TYPE_DEVICE 0x06 /* Name, multiple Node */ -#define ACPI_TYPE_EVENT 0x07 -#define ACPI_TYPE_METHOD 0x08 /* Name, byte_const, multiple Code */ -#define ACPI_TYPE_MUTEX 0x09 -#define ACPI_TYPE_REGION 0x0A -#define ACPI_TYPE_POWER 0x0B /* Name,byte_const,word_const,multi Node */ -#define ACPI_TYPE_PROCESSOR 0x0C /* Name,byte_const,Dword_const,byte_const,multi nm_o */ -#define ACPI_TYPE_THERMAL 0x0D /* Name, multiple Node */ -#define ACPI_TYPE_BUFFER_FIELD 0x0E -#define ACPI_TYPE_DDB_HANDLE 0x0F -#define ACPI_TYPE_DEBUG_OBJECT 0x10 - -#define ACPI_TYPE_EXTERNAL_MAX 0x10 -#define ACPI_NUM_TYPES (ACPI_TYPE_EXTERNAL_MAX + 1) - -/* - * These are object types that do not map directly to the ACPI - * object_type() operator. They are used for various internal purposes only. - * If new predefined ACPI_TYPEs are added (via the ACPI specification), these - * internal types must move upwards. (There is code that depends on these - * values being contiguous with the external types above.) - */ -#define ACPI_TYPE_LOCAL_REGION_FIELD 0x11 -#define ACPI_TYPE_LOCAL_BANK_FIELD 0x12 -#define ACPI_TYPE_LOCAL_INDEX_FIELD 0x13 -#define ACPI_TYPE_LOCAL_REFERENCE 0x14 /* Arg#, Local#, Name, Debug, ref_of, Index */ -#define ACPI_TYPE_LOCAL_ALIAS 0x15 -#define ACPI_TYPE_LOCAL_METHOD_ALIAS 0x16 -#define ACPI_TYPE_LOCAL_NOTIFY 0x17 -#define ACPI_TYPE_LOCAL_ADDRESS_HANDLER 0x18 -#define ACPI_TYPE_LOCAL_RESOURCE 0x19 -#define ACPI_TYPE_LOCAL_RESOURCE_FIELD 0x1A -#define ACPI_TYPE_LOCAL_SCOPE 0x1B /* 1 Name, multiple object_list Nodes */ - -#define ACPI_TYPE_NS_NODE_MAX 0x1B /* Last typecode used within a NS Node */ -#define ACPI_TOTAL_TYPES (ACPI_TYPE_NS_NODE_MAX + 1) - -/* - * These are special object types that never appear in - * a Namespace node, only in an object of union acpi_operand_object - */ -#define ACPI_TYPE_LOCAL_EXTRA 0x1C -#define ACPI_TYPE_LOCAL_DATA 0x1D - -#define ACPI_TYPE_LOCAL_MAX 0x1D - -/* All types above here are invalid */ - -#define ACPI_TYPE_INVALID 0x1E -#define ACPI_TYPE_NOT_FOUND 0xFF - -#define ACPI_NUM_NS_TYPES (ACPI_TYPE_INVALID + 1) - -/* - * All I/O - */ -#define ACPI_READ 0 -#define ACPI_WRITE 1 -#define ACPI_IO_MASK 1 - -/* - * Event Types: Fixed & General Purpose - */ -typedef u32 acpi_event_type; - -/* - * Fixed events - */ -#define ACPI_EVENT_PMTIMER 0 -#define ACPI_EVENT_GLOBAL 1 -#define ACPI_EVENT_POWER_BUTTON 2 -#define ACPI_EVENT_SLEEP_BUTTON 3 -#define ACPI_EVENT_RTC 4 -#define ACPI_EVENT_MAX 4 -#define ACPI_NUM_FIXED_EVENTS ACPI_EVENT_MAX + 1 - -/* - * Event status - Per event - * ------------- - * The encoding of acpi_event_status is illustrated below. - * Note that a set bit (1) indicates the property is TRUE - * (e.g. if bit 0 is set then the event is enabled). - * +-------------+-+-+-+-+-+-+ - * | Bits 31:6 |5|4|3|2|1|0| - * +-------------+-+-+-+-+-+-+ - * | | | | | | | - * | | | | | | +- Enabled? - * | | | | | +--- Enabled for wake? - * | | | | +----- Status bit set? - * | | | +------- Enable bit set? - * | | +--------- Has a handler? - * | +----------- Masked? - * +----------------- - */ -typedef u32 acpi_event_status; - -#define ACPI_EVENT_FLAG_DISABLED (acpi_event_status) 0x00 -#define ACPI_EVENT_FLAG_ENABLED (acpi_event_status) 0x01 -#define ACPI_EVENT_FLAG_WAKE_ENABLED (acpi_event_status) 0x02 -#define ACPI_EVENT_FLAG_STATUS_SET (acpi_event_status) 0x04 -#define ACPI_EVENT_FLAG_ENABLE_SET (acpi_event_status) 0x08 -#define ACPI_EVENT_FLAG_HAS_HANDLER (acpi_event_status) 0x10 -#define ACPI_EVENT_FLAG_MASKED (acpi_event_status) 0x20 -#define ACPI_EVENT_FLAG_SET ACPI_EVENT_FLAG_STATUS_SET - -/* Actions for acpi_set_gpe, acpi_gpe_wakeup, acpi_hw_low_set_gpe */ - -#define ACPI_GPE_ENABLE 0 -#define ACPI_GPE_DISABLE 1 -#define ACPI_GPE_CONDITIONAL_ENABLE 2 - -/* - * GPE info flags - Per GPE - * +---+-+-+-+---+ - * |7:6|5|4|3|2:0| - * +---+-+-+-+---+ - * | | | | | - * | | | | +-- Type of dispatch:to method, handler, notify, or none - * | | | +----- Interrupt type: edge or level triggered - * | | +------- Is a Wake GPE - * | +--------- Is GPE masked by the software GPE masking machanism - * +------------ - */ -#define ACPI_GPE_DISPATCH_NONE (u8) 0x00 -#define ACPI_GPE_DISPATCH_METHOD (u8) 0x01 -#define ACPI_GPE_DISPATCH_HANDLER (u8) 0x02 -#define ACPI_GPE_DISPATCH_NOTIFY (u8) 0x03 -#define ACPI_GPE_DISPATCH_RAW_HANDLER (u8) 0x04 -#define ACPI_GPE_DISPATCH_MASK (u8) 0x07 -#define ACPI_GPE_DISPATCH_TYPE(flags) ((u8) ((flags) & ACPI_GPE_DISPATCH_MASK)) - -#define ACPI_GPE_LEVEL_TRIGGERED (u8) 0x08 -#define ACPI_GPE_EDGE_TRIGGERED (u8) 0x00 -#define ACPI_GPE_XRUPT_TYPE_MASK (u8) 0x08 - -#define ACPI_GPE_CAN_WAKE (u8) 0x10 - -/* - * Flags for GPE and Lock interfaces - */ -#define ACPI_NOT_ISR 0x1 -#define ACPI_ISR 0x0 - -/* Notify types */ - -#define ACPI_SYSTEM_NOTIFY 0x1 -#define ACPI_DEVICE_NOTIFY 0x2 -#define ACPI_ALL_NOTIFY (ACPI_SYSTEM_NOTIFY | ACPI_DEVICE_NOTIFY) -#define ACPI_MAX_NOTIFY_HANDLER_TYPE 0x3 -#define ACPI_NUM_NOTIFY_TYPES 2 - -#define ACPI_MAX_SYS_NOTIFY 0x7F -#define ACPI_MAX_DEVICE_SPECIFIC_NOTIFY 0xBF - -#define ACPI_SYSTEM_HANDLER_LIST 0 /* Used as index, must be SYSTEM_NOTIFY -1 */ -#define ACPI_DEVICE_HANDLER_LIST 1 /* Used as index, must be DEVICE_NOTIFY -1 */ - -/* Address Space (Operation Region) Types */ - -typedef u8 acpi_adr_space_type; - -#define ACPI_ADR_SPACE_SYSTEM_MEMORY (acpi_adr_space_type) 0 -#define ACPI_ADR_SPACE_SYSTEM_IO (acpi_adr_space_type) 1 -#define ACPI_ADR_SPACE_PCI_CONFIG (acpi_adr_space_type) 2 -#define ACPI_ADR_SPACE_EC (acpi_adr_space_type) 3 -#define ACPI_ADR_SPACE_SMBUS (acpi_adr_space_type) 4 -#define ACPI_ADR_SPACE_CMOS (acpi_adr_space_type) 5 -#define ACPI_ADR_SPACE_PCI_BAR_TARGET (acpi_adr_space_type) 6 -#define ACPI_ADR_SPACE_IPMI (acpi_adr_space_type) 7 -#define ACPI_ADR_SPACE_GPIO (acpi_adr_space_type) 8 -#define ACPI_ADR_SPACE_GSBUS (acpi_adr_space_type) 9 -#define ACPI_ADR_SPACE_PLATFORM_COMM (acpi_adr_space_type) 10 - -#define ACPI_NUM_PREDEFINED_REGIONS 11 - -/* - * Special Address Spaces - * - * Note: A Data Table region is a special type of operation region - * that has its own AML opcode. However, internally, the AML - * interpreter simply creates an operation region with an an address - * space type of ACPI_ADR_SPACE_DATA_TABLE. - */ -#define ACPI_ADR_SPACE_DATA_TABLE (acpi_adr_space_type) 0x7E /* Internal to ACPICA only */ -#define ACPI_ADR_SPACE_FIXED_HARDWARE (acpi_adr_space_type) 0x7F - -/* Values for _REG connection code */ - -#define ACPI_REG_DISCONNECT 0 -#define ACPI_REG_CONNECT 1 - -/* - * bit_register IDs - * - * These values are intended to be used by the hardware interfaces - * and are mapped to individual bitfields defined within the ACPI - * registers. See the acpi_gbl_bit_register_info global table in utglobal.c - * for this mapping. - */ - -/* PM1 Status register */ - -#define ACPI_BITREG_TIMER_STATUS 0x00 -#define ACPI_BITREG_BUS_MASTER_STATUS 0x01 -#define ACPI_BITREG_GLOBAL_LOCK_STATUS 0x02 -#define ACPI_BITREG_POWER_BUTTON_STATUS 0x03 -#define ACPI_BITREG_SLEEP_BUTTON_STATUS 0x04 -#define ACPI_BITREG_RT_CLOCK_STATUS 0x05 -#define ACPI_BITREG_WAKE_STATUS 0x06 -#define ACPI_BITREG_PCIEXP_WAKE_STATUS 0x07 - -/* PM1 Enable register */ - -#define ACPI_BITREG_TIMER_ENABLE 0x08 -#define ACPI_BITREG_GLOBAL_LOCK_ENABLE 0x09 -#define ACPI_BITREG_POWER_BUTTON_ENABLE 0x0A -#define ACPI_BITREG_SLEEP_BUTTON_ENABLE 0x0B -#define ACPI_BITREG_RT_CLOCK_ENABLE 0x0C -#define ACPI_BITREG_PCIEXP_WAKE_DISABLE 0x0D - -/* PM1 Control register */ - -#define ACPI_BITREG_SCI_ENABLE 0x0E -#define ACPI_BITREG_BUS_MASTER_RLD 0x0F -#define ACPI_BITREG_GLOBAL_LOCK_RELEASE 0x10 -#define ACPI_BITREG_SLEEP_TYPE 0x11 -#define ACPI_BITREG_SLEEP_ENABLE 0x12 - -/* PM2 Control register */ - -#define ACPI_BITREG_ARB_DISABLE 0x13 - -#define ACPI_BITREG_MAX 0x13 -#define ACPI_NUM_BITREG ACPI_BITREG_MAX + 1 - -/* Status register values. A 1 clears a status bit. 0 = no effect */ - -#define ACPI_CLEAR_STATUS 1 - -/* Enable and Control register values */ - -#define ACPI_ENABLE_EVENT 1 -#define ACPI_DISABLE_EVENT 0 - -/* Sleep function dispatch */ - -typedef acpi_status (*acpi_sleep_function) (u8 sleep_state); - -struct acpi_sleep_functions { - acpi_sleep_function legacy_function; - acpi_sleep_function extended_function; -}; - -/* - * External ACPI object definition - */ - -/* - * Note: Type == ACPI_TYPE_ANY (0) is used to indicate a NULL package element - * or an unresolved named reference. - */ -union acpi_object { - acpi_object_type type; /* See definition of acpi_ns_type for values */ - struct { - acpi_object_type type; /* ACPI_TYPE_INTEGER */ - u64 value; /* The actual number */ - } integer; - - struct { - acpi_object_type type; /* ACPI_TYPE_STRING */ - u32 length; /* # of bytes in string, excluding trailing null */ - char *pointer; /* points to the string value */ - } string; - - struct { - acpi_object_type type; /* ACPI_TYPE_BUFFER */ - u32 length; /* # of bytes in buffer */ - u8 *pointer; /* points to the buffer */ - } buffer; - - struct { - acpi_object_type type; /* ACPI_TYPE_PACKAGE */ - u32 count; /* # of elements in package */ - union acpi_object *elements; /* Pointer to an array of ACPI_OBJECTs */ - } package; - - struct { - acpi_object_type type; /* ACPI_TYPE_LOCAL_REFERENCE */ - acpi_object_type actual_type; /* Type associated with the Handle */ - acpi_handle handle; /* object reference */ - } reference; - - struct { - acpi_object_type type; /* ACPI_TYPE_PROCESSOR */ - u32 proc_id; - acpi_io_address pblk_address; - u32 pblk_length; - } processor; - - struct { - acpi_object_type type; /* ACPI_TYPE_POWER */ - u32 system_level; - u32 resource_order; - } power_resource; -}; - -/* - * List of objects, used as a parameter list for control method evaluation - */ -struct acpi_object_list { - u32 count; - union acpi_object *pointer; -}; - -/* - * Miscellaneous common Data Structures used by the interfaces - */ -#define ACPI_NO_BUFFER 0 - -#ifdef ACPI_NO_MEM_ALLOCATIONS - -#define ACPI_ALLOCATE_BUFFER (acpi_size) (0) -#define ACPI_ALLOCATE_LOCAL_BUFFER (acpi_size) (0) - -#else /* ACPI_NO_MEM_ALLOCATIONS */ - -#define ACPI_ALLOCATE_BUFFER (acpi_size) (-1) /* Let ACPICA allocate buffer */ -#define ACPI_ALLOCATE_LOCAL_BUFFER (acpi_size) (-2) /* For internal use only (enables tracking) */ - -#endif /* ACPI_NO_MEM_ALLOCATIONS */ - -struct acpi_buffer { - acpi_size length; /* Length in bytes of the buffer */ - void *pointer; /* pointer to buffer */ -}; - -/* - * name_type for acpi_get_name - */ -#define ACPI_FULL_PATHNAME 0 -#define ACPI_SINGLE_NAME 1 -#define ACPI_FULL_PATHNAME_NO_TRAILING 2 -#define ACPI_NAME_TYPE_MAX 2 - -/* - * Predefined Namespace items - */ -struct acpi_predefined_names { - const char *name; - u8 type; - char *val; -}; - -/* - * Structure and flags for acpi_get_system_info - */ -#define ACPI_SYS_MODE_UNKNOWN 0x0000 -#define ACPI_SYS_MODE_ACPI 0x0001 -#define ACPI_SYS_MODE_LEGACY 0x0002 -#define ACPI_SYS_MODES_MASK 0x0003 - -/* - * System info returned by acpi_get_system_info() - */ -struct acpi_system_info { - u32 acpi_ca_version; - u32 flags; - u32 timer_resolution; - u32 reserved1; - u32 reserved2; - u32 debug_level; - u32 debug_layer; -}; - -/* - * System statistics returned by acpi_get_statistics() - */ -struct acpi_statistics { - u32 sci_count; - u32 gpe_count; - u32 fixed_event_count[ACPI_NUM_FIXED_EVENTS]; - u32 method_count; -}; - -/* - * Types specific to the OS service interfaces - */ -typedef u32 - (ACPI_SYSTEM_XFACE * acpi_osd_handler) (void *context); - -typedef void - (ACPI_SYSTEM_XFACE * acpi_osd_exec_callback) (void *context); - -/* - * Various handlers and callback procedures - */ -typedef -u32 (*acpi_sci_handler) (void *context); - -typedef -void (*acpi_gbl_event_handler) (u32 event_type, - acpi_handle device, - u32 event_number, void *context); - -#define ACPI_EVENT_TYPE_GPE 0 -#define ACPI_EVENT_TYPE_FIXED 1 - -typedef -u32(*acpi_event_handler) (void *context); - -typedef -u32 (*acpi_gpe_handler) (acpi_handle gpe_device, u32 gpe_number, void *context); - -typedef -void (*acpi_notify_handler) (acpi_handle device, u32 value, void *context); - -typedef -void (*acpi_object_handler) (acpi_handle object, void *data); - -typedef -acpi_status (*acpi_init_handler) (acpi_handle object, u32 function); - -#define ACPI_INIT_DEVICE_INI 1 - -typedef -acpi_status (*acpi_exception_handler) (acpi_status aml_status, - acpi_name name, - u16 opcode, - u32 aml_offset, void *context); - -/* Table Event handler (Load, load_table, etc.) and types */ - -typedef -acpi_status (*acpi_table_handler) (u32 event, void *table, void *context); - -/* Table Event Types */ - -#define ACPI_TABLE_EVENT_LOAD 0x0 -#define ACPI_TABLE_EVENT_UNLOAD 0x1 -#define ACPI_TABLE_EVENT_INSTALL 0x2 -#define ACPI_TABLE_EVENT_UNINSTALL 0x3 -#define ACPI_NUM_TABLE_EVENTS 4 - -/* Address Spaces (For Operation Regions) */ - -typedef -acpi_status (*acpi_adr_space_handler) (u32 function, - acpi_physical_address address, - u32 bit_width, - u64 *value, - void *handler_context, - void *region_context); - -#define ACPI_DEFAULT_HANDLER NULL - -/* Special Context data for generic_serial_bus/general_purpose_io (ACPI 5.0) */ - -struct acpi_connection_info { - u8 *connection; - u16 length; - u8 access_length; -}; - -typedef -acpi_status (*acpi_adr_space_setup) (acpi_handle region_handle, - u32 function, - void *handler_context, - void **region_context); - -#define ACPI_REGION_ACTIVATE 0 -#define ACPI_REGION_DEACTIVATE 1 - -typedef -acpi_status (*acpi_walk_callback) (acpi_handle object, - u32 nesting_level, - void *context, void **return_value); - -typedef -u32 (*acpi_interface_handler) (acpi_string interface_name, u32 supported); - -/* Interrupt handler return values */ - -#define ACPI_INTERRUPT_NOT_HANDLED 0x00 -#define ACPI_INTERRUPT_HANDLED 0x01 - -/* GPE handler return values */ - -#define ACPI_REENABLE_GPE 0x80 - -/* Length of 32-bit EISAID values when converted back to a string */ - -#define ACPI_EISAID_STRING_SIZE 8 /* Includes null terminator */ - -/* Length of UUID (string) values */ - -#define ACPI_UUID_LENGTH 16 - -/* Length of 3-byte PCI class code values when converted back to a string */ - -#define ACPI_PCICLS_STRING_SIZE 7 /* Includes null terminator */ - -/* Structures used for device/processor HID, UID, CID */ - -struct acpi_pnp_device_id { - u32 length; /* Length of string + null */ - char *string; -}; - -struct acpi_pnp_device_id_list { - u32 count; /* Number of IDs in Ids array */ - u32 list_size; /* Size of list, including ID strings */ - struct acpi_pnp_device_id ids[1]; /* ID array */ -}; - -/* - * Structure returned from acpi_get_object_info. - * Optimized for both 32- and 64-bit builds - */ -struct acpi_device_info { - u32 info_size; /* Size of info, including ID strings */ - u32 name; /* ACPI object Name */ - acpi_object_type type; /* ACPI object Type */ - u8 param_count; /* If a method, required parameter count */ - u16 valid; /* Indicates which optional fields are valid */ - u8 flags; /* Miscellaneous info */ - u8 highest_dstates[4]; /* _sx_d values: 0xFF indicates not valid */ - u8 lowest_dstates[5]; /* _sx_w values: 0xFF indicates not valid */ - u32 current_status; /* _STA value */ - u64 address; /* _ADR value */ - struct acpi_pnp_device_id hardware_id; /* _HID value */ - struct acpi_pnp_device_id unique_id; /* _UID value */ - struct acpi_pnp_device_id class_code; /* _CLS value */ - struct acpi_pnp_device_id_list compatible_id_list; /* _CID list */ -}; - -/* Values for Flags field above (acpi_get_object_info) */ - -#define ACPI_PCI_ROOT_BRIDGE 0x01 - -/* Flags for Valid field above (acpi_get_object_info) */ - -#define ACPI_VALID_STA 0x0001 -#define ACPI_VALID_ADR 0x0002 -#define ACPI_VALID_HID 0x0004 -#define ACPI_VALID_UID 0x0008 -#define ACPI_VALID_CID 0x0020 -#define ACPI_VALID_CLS 0x0040 -#define ACPI_VALID_SXDS 0x0100 -#define ACPI_VALID_SXWS 0x0200 - -/* Flags for _STA method */ - -#define ACPI_STA_DEVICE_PRESENT 0x01 -#define ACPI_STA_DEVICE_ENABLED 0x02 -#define ACPI_STA_DEVICE_UI 0x04 -#define ACPI_STA_DEVICE_FUNCTIONING 0x08 -#define ACPI_STA_DEVICE_OK 0x08 /* Synonym */ -#define ACPI_STA_BATTERY_PRESENT 0x10 - -/* Context structs for address space handlers */ - -struct acpi_pci_id { - u16 segment; - u16 bus; - u16 device; - u16 function; -}; - -struct acpi_mem_space_context { - u32 length; - acpi_physical_address address; - acpi_physical_address mapped_physical_address; - u8 *mapped_logical_address; - acpi_size mapped_length; -}; - -/* - * struct acpi_memory_list is used only if the ACPICA local cache is enabled - */ -struct acpi_memory_list { - const char *list_name; - void *list_head; - u16 object_size; - u16 max_depth; - u16 current_depth; - -#ifdef ACPI_DBG_TRACK_ALLOCATIONS - - /* Statistics for debug memory tracking only */ - - u32 total_allocated; - u32 total_freed; - u32 max_occupied; - u32 total_size; - u32 current_total_size; - u32 requests; - u32 hits; -#endif -}; - -/* Definitions of trace event types */ - -typedef enum { - ACPI_TRACE_AML_METHOD, - ACPI_TRACE_AML_OPCODE, - ACPI_TRACE_AML_REGION -} acpi_trace_event_type; - -/* Definitions of _OSI support */ - -#define ACPI_VENDOR_STRINGS 0x01 -#define ACPI_FEATURE_STRINGS 0x02 -#define ACPI_ENABLE_INTERFACES 0x00 -#define ACPI_DISABLE_INTERFACES 0x04 - -#define ACPI_DISABLE_ALL_VENDOR_STRINGS (ACPI_DISABLE_INTERFACES | ACPI_VENDOR_STRINGS) -#define ACPI_DISABLE_ALL_FEATURE_STRINGS (ACPI_DISABLE_INTERFACES | ACPI_FEATURE_STRINGS) -#define ACPI_DISABLE_ALL_STRINGS (ACPI_DISABLE_INTERFACES | ACPI_VENDOR_STRINGS | ACPI_FEATURE_STRINGS) -#define ACPI_ENABLE_ALL_VENDOR_STRINGS (ACPI_ENABLE_INTERFACES | ACPI_VENDOR_STRINGS) -#define ACPI_ENABLE_ALL_FEATURE_STRINGS (ACPI_ENABLE_INTERFACES | ACPI_FEATURE_STRINGS) -#define ACPI_ENABLE_ALL_STRINGS (ACPI_ENABLE_INTERFACES | ACPI_VENDOR_STRINGS | ACPI_FEATURE_STRINGS) - -#define ACPI_OSI_WIN_2000 0x01 -#define ACPI_OSI_WIN_XP 0x02 -#define ACPI_OSI_WIN_XP_SP1 0x03 -#define ACPI_OSI_WINSRV_2003 0x04 -#define ACPI_OSI_WIN_XP_SP2 0x05 -#define ACPI_OSI_WINSRV_2003_SP1 0x06 -#define ACPI_OSI_WIN_VISTA 0x07 -#define ACPI_OSI_WINSRV_2008 0x08 -#define ACPI_OSI_WIN_VISTA_SP1 0x09 -#define ACPI_OSI_WIN_VISTA_SP2 0x0A -#define ACPI_OSI_WIN_7 0x0B -#define ACPI_OSI_WIN_8 0x0C -#define ACPI_OSI_WIN_10 0x0D - -/* Definitions of getopt */ - -#define ACPI_OPT_END -1 - -#endif /* __ACTYPES_H__ */ diff --git a/src/linux/include/acpi/platform/acenv.h b/src/linux/include/acpi/platform/acenv.h deleted file mode 100644 index 34cce72..0000000 --- a/src/linux/include/acpi/platform/acenv.h +++ /dev/null @@ -1,384 +0,0 @@ -/****************************************************************************** - * - * Name: acenv.h - Host and compiler configuration - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACENV_H__ -#define __ACENV_H__ - -/* - * Environment configuration. The purpose of this file is to interface ACPICA - * to the local environment. This includes compiler-specific, OS-specific, - * and machine-specific configuration. - */ - -/* Types for ACPI_MUTEX_TYPE */ - -#define ACPI_BINARY_SEMAPHORE 0 -#define ACPI_OSL_MUTEX 1 - -/* Types for DEBUGGER_THREADING */ - -#define DEBUGGER_SINGLE_THREADED 0 -#define DEBUGGER_MULTI_THREADED 1 - -/****************************************************************************** - * - * Configuration for ACPI tools and utilities - * - *****************************************************************************/ - -/* Common application configuration. All single threaded except for acpi_exec. */ - -#if (defined ACPI_ASL_COMPILER) || \ - (defined ACPI_BIN_APP) || \ - (defined ACPI_DUMP_APP) || \ - (defined ACPI_HELP_APP) || \ - (defined ACPI_NAMES_APP) || \ - (defined ACPI_SRC_APP) || \ - (defined ACPI_XTRACT_APP) || \ - (defined ACPI_EXAMPLE_APP) -#define ACPI_APPLICATION -#define ACPI_SINGLE_THREADED -#define USE_NATIVE_ALLOCATE_ZEROED -#endif - -/* iASL configuration */ - -#ifdef ACPI_ASL_COMPILER -#define ACPI_DEBUG_OUTPUT -#define ACPI_CONSTANT_EVAL_ONLY -#define ACPI_LARGE_NAMESPACE_NODE -#define ACPI_DATA_TABLE_DISASSEMBLY -#define ACPI_32BIT_PHYSICAL_ADDRESS -#define ACPI_DISASSEMBLER 1 -#endif - -/* acpi_exec configuration. Multithreaded with full AML debugger */ - -#ifdef ACPI_EXEC_APP -#define ACPI_APPLICATION -#define ACPI_FULL_DEBUG -#define ACPI_MUTEX_DEBUG -#define ACPI_DBG_TRACK_ALLOCATIONS -#endif - -/* acpi_help configuration. Error messages disabled. */ - -#ifdef ACPI_HELP_APP -#define ACPI_NO_ERROR_MESSAGES -#endif - -/* acpi_names configuration. Debug output enabled. */ - -#ifdef ACPI_NAMES_APP -#define ACPI_DEBUG_OUTPUT -#endif - -/* acpi_exec/acpi_names/Example configuration. Native RSDP used. */ - -#if (defined ACPI_EXEC_APP) || \ - (defined ACPI_EXAMPLE_APP) || \ - (defined ACPI_NAMES_APP) -#define ACPI_USE_NATIVE_RSDP_POINTER -#endif - -/* acpi_dump configuration. Native mapping used if provided by the host */ - -#ifdef ACPI_DUMP_APP -#define ACPI_USE_NATIVE_MEMORY_MAPPING -#endif - -/* acpi_names/Example configuration. Hardware disabled */ - -#if (defined ACPI_EXAMPLE_APP) || \ - (defined ACPI_NAMES_APP) -#define ACPI_REDUCED_HARDWARE 1 -#endif - -/* Linkable ACPICA library. Two versions, one with full debug. */ - -#ifdef ACPI_LIBRARY -#define ACPI_USE_LOCAL_CACHE -#define ACPI_DEBUGGER 1 -#define ACPI_DISASSEMBLER 1 - -#ifdef _DEBUG -#define ACPI_DEBUG_OUTPUT -#endif -#endif - -/* Common for all ACPICA applications */ - -#ifdef ACPI_APPLICATION -#define ACPI_USE_LOCAL_CACHE -#endif - -/* Common debug/disassembler support */ - -#ifdef ACPI_FULL_DEBUG -#define ACPI_DEBUG_OUTPUT -#define ACPI_DEBUGGER 1 -#define ACPI_DISASSEMBLER 1 -#endif - - -/*! [Begin] no source code translation */ - -/****************************************************************************** - * - * Host configuration files. The compiler configuration files are included - * first. - * - *****************************************************************************/ - -#if defined(__GNUC__) && !defined(__INTEL_COMPILER) -#include - -#elif defined(_MSC_VER) -#include "acmsvc.h" - -#elif defined(__INTEL_COMPILER) -#include "acintel.h" - -#endif - -#if defined(_LINUX) || defined(__linux__) -#include - -#elif defined(_APPLE) || defined(__APPLE__) -#include "acmacosx.h" - -#elif defined(__DragonFly__) -#include "acdragonfly.h" - -#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) -#include "acfreebsd.h" - -#elif defined(__NetBSD__) -#include "acnetbsd.h" - -#elif defined(__sun) -#include "acsolaris.h" - -#elif defined(MODESTO) -#include "acmodesto.h" - -#elif defined(NETWARE) -#include "acnetware.h" - -#elif defined(_CYGWIN) -#include "accygwin.h" - -#elif defined(WIN32) -#include "acwin.h" - -#elif defined(WIN64) -#include "acwin64.h" - -#elif defined(_WRS_LIB_BUILD) -#include "acvxworks.h" - -#elif defined(__OS2__) -#include "acos2.h" - -#elif defined(__HAIKU__) -#include "achaiku.h" - -#elif defined(__QNX__) -#include "acqnx.h" - -/* - * EFI applications can be built with -nostdlib, in this case, it must be - * included after including all other host environmental definitions, in - * order to override the definitions. - */ -#elif defined(_AED_EFI) || defined(_GNU_EFI) || defined(_EDK2_EFI) -#include "acefi.h" - -#else - -/* Unknown environment */ - -#error Unknown target environment -#endif - -/*! [End] no source code translation !*/ - -/****************************************************************************** - * - * Setup defaults for the required symbols that were not defined in one of - * the host/compiler files above. - * - *****************************************************************************/ - -/* 64-bit data types */ - -#ifndef COMPILER_DEPENDENT_INT64 -#define COMPILER_DEPENDENT_INT64 long long -#endif - -#ifndef COMPILER_DEPENDENT_UINT64 -#define COMPILER_DEPENDENT_UINT64 unsigned long long -#endif - -/* Type of mutex supported by host. Default is binary semaphores. */ -#ifndef ACPI_MUTEX_TYPE -#define ACPI_MUTEX_TYPE ACPI_BINARY_SEMAPHORE -#endif - -/* Global Lock acquire/release */ - -#ifndef ACPI_ACQUIRE_GLOBAL_LOCK -#define ACPI_ACQUIRE_GLOBAL_LOCK(Glptr, acquired) acquired = 1 -#endif - -#ifndef ACPI_RELEASE_GLOBAL_LOCK -#define ACPI_RELEASE_GLOBAL_LOCK(Glptr, pending) pending = 0 -#endif - -/* Flush CPU cache - used when going to sleep. Wbinvd or similar. */ - -#ifndef ACPI_FLUSH_CPU_CACHE -#define ACPI_FLUSH_CPU_CACHE() -#endif - -/* "inline" keywords - configurable since inline is not standardized */ - -#ifndef ACPI_INLINE -#define ACPI_INLINE -#endif - -/* - * Configurable calling conventions: - * - * ACPI_SYSTEM_XFACE - Interfaces to host OS (handlers, threads) - * ACPI_EXTERNAL_XFACE - External ACPI interfaces - * ACPI_INTERNAL_XFACE - Internal ACPI interfaces - * ACPI_INTERNAL_VAR_XFACE - Internal variable-parameter list interfaces - */ -#ifndef ACPI_SYSTEM_XFACE -#define ACPI_SYSTEM_XFACE -#endif - -#ifndef ACPI_EXTERNAL_XFACE -#define ACPI_EXTERNAL_XFACE -#endif - -#ifndef ACPI_INTERNAL_XFACE -#define ACPI_INTERNAL_XFACE -#endif - -#ifndef ACPI_INTERNAL_VAR_XFACE -#define ACPI_INTERNAL_VAR_XFACE -#endif - -/* - * Debugger threading model - * Use single threaded if the entire subsystem is contained in an application - * Use multiple threaded when the subsystem is running in the kernel. - * - * By default the model is single threaded if ACPI_APPLICATION is set, - * multi-threaded if ACPI_APPLICATION is not set. - */ -#ifndef DEBUGGER_THREADING -#if !defined (ACPI_APPLICATION) || defined (ACPI_EXEC_APP) -#define DEBUGGER_THREADING DEBUGGER_MULTI_THREADED - -#else -#define DEBUGGER_THREADING DEBUGGER_SINGLE_THREADED -#endif -#endif /* !DEBUGGER_THREADING */ - -/****************************************************************************** - * - * C library configuration - * - *****************************************************************************/ - -/* - * ACPI_USE_SYSTEM_CLIBRARY - Define this if linking to an actual C library. - * Otherwise, local versions of string/memory functions will be used. - * ACPI_USE_STANDARD_HEADERS - Define this if linking to a C library and - * the standard header files may be used. Defining this implies that - * ACPI_USE_SYSTEM_CLIBRARY has been defined. - * - * The ACPICA subsystem only uses low level C library functions that do not - * call operating system services and may therefore be inlined in the code. - * - * It may be necessary to tailor these include files to the target - * generation environment. - */ - -/* Use the standard C library headers. We want to keep these to a minimum. */ - -#ifdef ACPI_USE_STANDARD_HEADERS - -/* Use the standard headers from the standard locations */ - -#include -#include -#include -#ifdef ACPI_APPLICATION -#include -#include -#include -#include -#include -#endif - -#endif /* ACPI_USE_STANDARD_HEADERS */ - -#ifdef ACPI_APPLICATION -#define ACPI_FILE FILE * -#define ACPI_FILE_OUT stdout -#define ACPI_FILE_ERR stderr -#else -#define ACPI_FILE void * -#define ACPI_FILE_OUT NULL -#define ACPI_FILE_ERR NULL -#endif /* ACPI_APPLICATION */ - -#ifndef ACPI_INIT_FUNCTION -#define ACPI_INIT_FUNCTION -#endif - -#endif /* __ACENV_H__ */ diff --git a/src/linux/include/acpi/platform/acenvex.h b/src/linux/include/acpi/platform/acenvex.h deleted file mode 100644 index b3171b9..0000000 --- a/src/linux/include/acpi/platform/acenvex.h +++ /dev/null @@ -1,82 +0,0 @@ -/****************************************************************************** - * - * Name: acenvex.h - Extra host and compiler configuration - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACENVEX_H__ -#define __ACENVEX_H__ - -/*! [Begin] no source code translation */ - -/****************************************************************************** - * - * Extra host configuration files. All ACPICA headers are included before - * including these files. - * - *****************************************************************************/ - -#if defined(_LINUX) || defined(__linux__) -#include - -#elif defined(__DragonFly__) -#include "acdragonflyex.h" - -/* - * EFI applications can be built with -nostdlib, in this case, it must be - * included after including all other host environmental definitions, in - * order to override the definitions. - */ -#elif defined(_AED_EFI) || defined(_GNU_EFI) || defined(_EDK2_EFI) -#include "acefiex.h" - -#endif - -#if defined(__GNUC__) && !defined(__INTEL_COMPILER) -#include "acgccex.h" - -#elif defined(_MSC_VER) -#include "acmsvcex.h" - -#endif - -/*! [End] no source code translation !*/ - -#endif /* __ACENVEX_H__ */ diff --git a/src/linux/include/acpi/platform/acgcc.h b/src/linux/include/acpi/platform/acgcc.h deleted file mode 100644 index 8f66aaa..0000000 --- a/src/linux/include/acpi/platform/acgcc.h +++ /dev/null @@ -1,77 +0,0 @@ -/****************************************************************************** - * - * Name: acgcc.h - GCC specific defines, etc. - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACGCC_H__ -#define __ACGCC_H__ - -/* - * Use compiler specific is a good practice for even when - * -nostdinc is specified (i.e., ACPI_USE_STANDARD_HEADERS undefined. - */ -#include - -#define ACPI_INLINE __inline__ - -/* Function name is used for debug output. Non-ANSI, compiler-dependent */ - -#define ACPI_GET_FUNCTION_NAME __func__ - -/* - * This macro is used to tag functions as "printf-like" because - * some compilers (like GCC) can catch printf format string problems. - */ -#define ACPI_PRINTF_LIKE(c) __attribute__ ((__format__ (__printf__, c, c+1))) - -/* - * Some compilers complain about unused variables. Sometimes we don't want to - * use all the variables (for example, _acpi_module_name). This allows us - * to tell the compiler warning in a per-variable manner that a variable - * is unused. - */ -#define ACPI_UNUSED_VAR __attribute__ ((unused)) - -/* GCC supports __VA_ARGS__ in macros */ - -#define COMPILER_VA_MACRO 1 - -#endif /* __ACGCC_H__ */ diff --git a/src/linux/include/acpi/platform/acgccex.h b/src/linux/include/acpi/platform/acgccex.h deleted file mode 100644 index 46ead2c..0000000 --- a/src/linux/include/acpi/platform/acgccex.h +++ /dev/null @@ -1,58 +0,0 @@ -/****************************************************************************** - * - * Name: acgccex.h - Extra GCC specific defines, etc. - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACGCCEX_H__ -#define __ACGCCEX_H__ - -/* - * Some versions of gcc implement strchr() with a buggy macro. So, - * undef it here. Prevents error messages of this form (usually from the - * file getopt.c): - * - * error: logical '&&' with non-zero constant will always evaluate as true - */ -#ifdef strchr -#undef strchr -#endif - -#endif /* __ACGCCEX_H__ */ diff --git a/src/linux/include/acpi/platform/aclinux.h b/src/linux/include/acpi/platform/aclinux.h deleted file mode 100644 index e861a24..0000000 --- a/src/linux/include/acpi/platform/aclinux.h +++ /dev/null @@ -1,221 +0,0 @@ -/****************************************************************************** - * - * Name: aclinux.h - OS specific defines, etc. for Linux - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACLINUX_H__ -#define __ACLINUX_H__ - -#ifdef __KERNEL__ - -/* ACPICA external files should not include ACPICA headers directly. */ - -#if !defined(BUILDING_ACPICA) && !defined(_LINUX_ACPI_H) -#error "Please don't include directly, include instead." -#endif - -#endif - -/* Common (in-kernel/user-space) ACPICA configuration */ - -#define ACPI_USE_SYSTEM_CLIBRARY -#define ACPI_USE_DO_WHILE_0 - -#ifdef __KERNEL__ - -#define ACPI_USE_SYSTEM_INTTYPES - -/* Kernel specific ACPICA configuration */ - -#ifdef CONFIG_ACPI_REDUCED_HARDWARE_ONLY -#define ACPI_REDUCED_HARDWARE 1 -#endif - -#ifdef CONFIG_ACPI_DEBUGGER -#define ACPI_DEBUGGER -#endif - -#ifdef CONFIG_ACPI_DEBUG -#define ACPI_MUTEX_DEBUG -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef EXPORT_ACPI_INTERFACES -#include -#endif -#ifdef CONFIG_ACPI -#include -#endif - -#define ACPI_INIT_FUNCTION __init - -#ifndef CONFIG_ACPI - -/* External globals for __KERNEL__, stubs is needed */ - -#define ACPI_GLOBAL(t,a) -#define ACPI_INIT_GLOBAL(t,a,b) - -/* Generating stubs for configurable ACPICA macros */ - -#define ACPI_NO_MEM_ALLOCATIONS - -/* Generating stubs for configurable ACPICA functions */ - -#define ACPI_NO_ERROR_MESSAGES -#undef ACPI_DEBUG_OUTPUT - -/* External interface for __KERNEL__, stub is needed */ - -#define ACPI_EXTERNAL_RETURN_STATUS(prototype) \ - static ACPI_INLINE prototype {return(AE_NOT_CONFIGURED);} -#define ACPI_EXTERNAL_RETURN_OK(prototype) \ - static ACPI_INLINE prototype {return(AE_OK);} -#define ACPI_EXTERNAL_RETURN_VOID(prototype) \ - static ACPI_INLINE prototype {return;} -#define ACPI_EXTERNAL_RETURN_UINT32(prototype) \ - static ACPI_INLINE prototype {return(0);} -#define ACPI_EXTERNAL_RETURN_PTR(prototype) \ - static ACPI_INLINE prototype {return(NULL);} - -#endif /* CONFIG_ACPI */ - -/* Host-dependent types and defines for in-kernel ACPICA */ - -#define ACPI_MACHINE_WIDTH BITS_PER_LONG -#define ACPI_EXPORT_SYMBOL(symbol) EXPORT_SYMBOL(symbol); -#define strtoul simple_strtoul - -#define acpi_cache_t struct kmem_cache -#define acpi_spinlock spinlock_t * -#define acpi_cpu_flags unsigned long - -/* Use native linux version of acpi_os_allocate_zeroed */ - -#define USE_NATIVE_ALLOCATE_ZEROED - -/* - * Overrides for in-kernel ACPICA - */ -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_allocate -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_allocate_zeroed -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_free -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_acquire_object -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_thread_id -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_create_lock - -/* - * OSL interfaces used by debugger/disassembler - */ -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_readable -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_writable -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_initialize_command_signals -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_terminate_command_signals - -/* - * OSL interfaces used by utilities - */ -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_redirect_output -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_name -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_index -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_table_by_address -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_open_directory -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_get_next_filename -#define ACPI_USE_ALTERNATE_PROTOTYPE_acpi_os_close_directory - -#define ACPI_MSG_ERROR KERN_ERR "ACPI Error: " -#define ACPI_MSG_EXCEPTION KERN_ERR "ACPI Exception: " -#define ACPI_MSG_WARNING KERN_WARNING "ACPI Warning: " -#define ACPI_MSG_INFO KERN_INFO "ACPI: " - -#define ACPI_MSG_BIOS_ERROR KERN_ERR "ACPI BIOS Error (bug): " -#define ACPI_MSG_BIOS_WARNING KERN_WARNING "ACPI BIOS Warning (bug): " - -#else /* !__KERNEL__ */ - -#define ACPI_USE_STANDARD_HEADERS - -#ifdef ACPI_USE_STANDARD_HEADERS -#include -#endif - -/* Define/disable kernel-specific declarators */ - -#ifndef __init -#define __init -#endif -#ifndef __iomem -#define __iomem -#endif - -/* Host-dependent types and defines for user-space ACPICA */ - -#define ACPI_FLUSH_CPU_CACHE() -#define ACPI_CAST_PTHREAD_T(pthread) ((acpi_thread_id) (pthread)) - -#if defined(__ia64__) || defined(__x86_64__) ||\ - defined(__aarch64__) || defined(__PPC64__) -#define ACPI_MACHINE_WIDTH 64 -#define COMPILER_DEPENDENT_INT64 long -#define COMPILER_DEPENDENT_UINT64 unsigned long -#else -#define ACPI_MACHINE_WIDTH 32 -#define COMPILER_DEPENDENT_INT64 long long -#define COMPILER_DEPENDENT_UINT64 unsigned long long -#define ACPI_USE_NATIVE_DIVIDE -#endif - -#ifndef __cdecl -#define __cdecl -#endif - -#endif /* __KERNEL__ */ - -#endif /* __ACLINUX_H__ */ diff --git a/src/linux/include/acpi/platform/aclinuxex.h b/src/linux/include/acpi/platform/aclinuxex.h deleted file mode 100644 index a5509d8..0000000 --- a/src/linux/include/acpi/platform/aclinuxex.h +++ /dev/null @@ -1,149 +0,0 @@ -/****************************************************************************** - * - * Name: aclinuxex.h - Extra OS specific defines, etc. for Linux - * - *****************************************************************************/ - -/* - * Copyright (C) 2000 - 2016, Intel Corp. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions, and the following disclaimer, - * without modification. - * 2. Redistributions in binary form must reproduce at minimum a disclaimer - * substantially similar to the "NO WARRANTY" disclaimer below - * ("Disclaimer") and any redistribution must be conditioned upon - * including a substantially similar Disclaimer requirement for further - * binary redistribution. - * 3. Neither the names of the above-listed copyright holders nor the names - * of any contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License ("GPL") version 2 as published by the Free - * Software Foundation. - * - * NO WARRANTY - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGES. - */ - -#ifndef __ACLINUXEX_H__ -#define __ACLINUXEX_H__ - -#ifdef __KERNEL__ - -#ifndef ACPI_USE_NATIVE_DIVIDE - -#ifndef ACPI_DIV_64_BY_32 -#define ACPI_DIV_64_BY_32(n_hi, n_lo, d32, q32, r32) \ - do { \ - u64 (__n) = ((u64) n_hi) << 32 | (n_lo); \ - (r32) = do_div ((__n), (d32)); \ - (q32) = (u32) (__n); \ - } while (0) -#endif - -#ifndef ACPI_SHIFT_RIGHT_64 -#define ACPI_SHIFT_RIGHT_64(n_hi, n_lo) \ - do { \ - (n_lo) >>= 1; \ - (n_lo) |= (((n_hi) & 1) << 31); \ - (n_hi) >>= 1; \ - } while (0) -#endif - -#endif - -/* - * Overrides for in-kernel ACPICA - */ -acpi_status ACPI_INIT_FUNCTION acpi_os_initialize(void); - -acpi_status acpi_os_terminate(void); - -/* - * The irqs_disabled() check is for resume from RAM. - * Interrupts are off during resume, just like they are for boot. - * However, boot has (system_state != SYSTEM_RUNNING) - * to quiet __might_sleep() in kmalloc() and resume does not. - */ -static inline void *acpi_os_allocate(acpi_size size) -{ - return kmalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL); -} - -static inline void *acpi_os_allocate_zeroed(acpi_size size) -{ - return kzalloc(size, irqs_disabled()? GFP_ATOMIC : GFP_KERNEL); -} - -static inline void acpi_os_free(void *memory) -{ - kfree(memory); -} - -static inline void *acpi_os_acquire_object(acpi_cache_t * cache) -{ - return kmem_cache_zalloc(cache, - irqs_disabled()? GFP_ATOMIC : GFP_KERNEL); -} - -static inline acpi_thread_id acpi_os_get_thread_id(void) -{ - return (acpi_thread_id) (unsigned long)current; -} - -/* - * When lockdep is enabled, the spin_lock_init() macro stringifies it's - * argument and uses that as a name for the lock in debugging. - * By executing spin_lock_init() in a macro the key changes from "lock" for - * all locks to the name of the argument of acpi_os_create_lock(), which - * prevents lockdep from reporting false positives for ACPICA locks. - */ -#define acpi_os_create_lock(__handle) \ - ({ \ - spinlock_t *lock = ACPI_ALLOCATE(sizeof(*lock)); \ - if (lock) { \ - *(__handle) = lock; \ - spin_lock_init(*(__handle)); \ - } \ - lock ? AE_OK : AE_NO_MEMORY; \ - }) - -static inline u8 acpi_os_readable(void *pointer, acpi_size length) -{ - return TRUE; -} - -static inline acpi_status acpi_os_initialize_command_signals(void) -{ - return AE_OK; -} - -static inline void acpi_os_terminate_command_signals(void) -{ - return; -} - -/* - * OSL interfaces added by Linux - */ -void early_acpi_os_unmap_memory(void __iomem * virt, acpi_size size); - -#endif /* __KERNEL__ */ - -#endif /* __ACLINUXEX_H__ */ diff --git a/src/linux/include/asm-generic/4level-fixup.h b/src/linux/include/asm-generic/4level-fixup.h deleted file mode 100644 index 5bdab6b..0000000 --- a/src/linux/include/asm-generic/4level-fixup.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef _4LEVEL_FIXUP_H -#define _4LEVEL_FIXUP_H - -#define __ARCH_HAS_4LEVEL_HACK -#define __PAGETABLE_PUD_FOLDED - -#define PUD_SHIFT PGDIR_SHIFT -#define PUD_SIZE PGDIR_SIZE -#define PUD_MASK PGDIR_MASK -#define PTRS_PER_PUD 1 - -#define pud_t pgd_t - -#define pmd_alloc(mm, pud, address) \ - ((unlikely(pgd_none(*(pud))) && __pmd_alloc(mm, pud, address))? \ - NULL: pmd_offset(pud, address)) - -#define pud_alloc(mm, pgd, address) (pgd) -#define pud_offset(pgd, start) (pgd) -#define pud_none(pud) 0 -#define pud_bad(pud) 0 -#define pud_present(pud) 1 -#define pud_ERROR(pud) do { } while (0) -#define pud_clear(pud) pgd_clear(pud) -#define pud_val(pud) pgd_val(pud) -#define pud_populate(mm, pud, pmd) pgd_populate(mm, pud, pmd) -#define pud_page(pud) pgd_page(pud) -#define pud_page_vaddr(pud) pgd_page_vaddr(pud) - -#undef pud_free_tlb -#define pud_free_tlb(tlb, x, addr) do { } while (0) -#define pud_free(mm, x) do { } while (0) -#define __pud_free_tlb(tlb, x, addr) do { } while (0) - -#undef pud_addr_end -#define pud_addr_end(addr, end) (end) - -#endif diff --git a/src/linux/include/asm-generic/atomic-long.h b/src/linux/include/asm-generic/atomic-long.h deleted file mode 100644 index 288cc9e..0000000 --- a/src/linux/include/asm-generic/atomic-long.h +++ /dev/null @@ -1,246 +0,0 @@ -#ifndef _ASM_GENERIC_ATOMIC_LONG_H -#define _ASM_GENERIC_ATOMIC_LONG_H -/* - * Copyright (C) 2005 Silicon Graphics, Inc. - * Christoph Lameter - * - * Allows to provide arch independent atomic definitions without the need to - * edit all arch specific atomic.h files. - */ - -#include - -/* - * Suppport for atomic_long_t - * - * Casts for parameters are avoided for existing atomic functions in order to - * avoid issues with cast-as-lval under gcc 4.x and other limitations that the - * macros of a platform may have. - */ - -#if BITS_PER_LONG == 64 - -typedef atomic64_t atomic_long_t; - -#define ATOMIC_LONG_INIT(i) ATOMIC64_INIT(i) -#define ATOMIC_LONG_PFX(x) atomic64 ## x - -#else - -typedef atomic_t atomic_long_t; - -#define ATOMIC_LONG_INIT(i) ATOMIC_INIT(i) -#define ATOMIC_LONG_PFX(x) atomic ## x - -#endif - -#define ATOMIC_LONG_READ_OP(mo) \ -static inline long atomic_long_read##mo(const atomic_long_t *l) \ -{ \ - ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; \ - \ - return (long)ATOMIC_LONG_PFX(_read##mo)(v); \ -} -ATOMIC_LONG_READ_OP() -ATOMIC_LONG_READ_OP(_acquire) - -#undef ATOMIC_LONG_READ_OP - -#define ATOMIC_LONG_SET_OP(mo) \ -static inline void atomic_long_set##mo(atomic_long_t *l, long i) \ -{ \ - ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; \ - \ - ATOMIC_LONG_PFX(_set##mo)(v, i); \ -} -ATOMIC_LONG_SET_OP() -ATOMIC_LONG_SET_OP(_release) - -#undef ATOMIC_LONG_SET_OP - -#define ATOMIC_LONG_ADD_SUB_OP(op, mo) \ -static inline long \ -atomic_long_##op##_return##mo(long i, atomic_long_t *l) \ -{ \ - ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; \ - \ - return (long)ATOMIC_LONG_PFX(_##op##_return##mo)(i, v); \ -} -ATOMIC_LONG_ADD_SUB_OP(add,) -ATOMIC_LONG_ADD_SUB_OP(add, _relaxed) -ATOMIC_LONG_ADD_SUB_OP(add, _acquire) -ATOMIC_LONG_ADD_SUB_OP(add, _release) -ATOMIC_LONG_ADD_SUB_OP(sub,) -ATOMIC_LONG_ADD_SUB_OP(sub, _relaxed) -ATOMIC_LONG_ADD_SUB_OP(sub, _acquire) -ATOMIC_LONG_ADD_SUB_OP(sub, _release) - -#undef ATOMIC_LONG_ADD_SUB_OP - -#define atomic_long_cmpxchg_relaxed(l, old, new) \ - (ATOMIC_LONG_PFX(_cmpxchg_relaxed)((ATOMIC_LONG_PFX(_t) *)(l), \ - (old), (new))) -#define atomic_long_cmpxchg_acquire(l, old, new) \ - (ATOMIC_LONG_PFX(_cmpxchg_acquire)((ATOMIC_LONG_PFX(_t) *)(l), \ - (old), (new))) -#define atomic_long_cmpxchg_release(l, old, new) \ - (ATOMIC_LONG_PFX(_cmpxchg_release)((ATOMIC_LONG_PFX(_t) *)(l), \ - (old), (new))) -#define atomic_long_cmpxchg(l, old, new) \ - (ATOMIC_LONG_PFX(_cmpxchg)((ATOMIC_LONG_PFX(_t) *)(l), (old), (new))) - -#define atomic_long_xchg_relaxed(v, new) \ - (ATOMIC_LONG_PFX(_xchg_relaxed)((ATOMIC_LONG_PFX(_t) *)(v), (new))) -#define atomic_long_xchg_acquire(v, new) \ - (ATOMIC_LONG_PFX(_xchg_acquire)((ATOMIC_LONG_PFX(_t) *)(v), (new))) -#define atomic_long_xchg_release(v, new) \ - (ATOMIC_LONG_PFX(_xchg_release)((ATOMIC_LONG_PFX(_t) *)(v), (new))) -#define atomic_long_xchg(v, new) \ - (ATOMIC_LONG_PFX(_xchg)((ATOMIC_LONG_PFX(_t) *)(v), (new))) - -static __always_inline void atomic_long_inc(atomic_long_t *l) -{ - ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; - - ATOMIC_LONG_PFX(_inc)(v); -} - -static __always_inline void atomic_long_dec(atomic_long_t *l) -{ - ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; - - ATOMIC_LONG_PFX(_dec)(v); -} - -#define ATOMIC_LONG_FETCH_OP(op, mo) \ -static inline long \ -atomic_long_fetch_##op##mo(long i, atomic_long_t *l) \ -{ \ - ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; \ - \ - return (long)ATOMIC_LONG_PFX(_fetch_##op##mo)(i, v); \ -} - -ATOMIC_LONG_FETCH_OP(add, ) -ATOMIC_LONG_FETCH_OP(add, _relaxed) -ATOMIC_LONG_FETCH_OP(add, _acquire) -ATOMIC_LONG_FETCH_OP(add, _release) -ATOMIC_LONG_FETCH_OP(sub, ) -ATOMIC_LONG_FETCH_OP(sub, _relaxed) -ATOMIC_LONG_FETCH_OP(sub, _acquire) -ATOMIC_LONG_FETCH_OP(sub, _release) -ATOMIC_LONG_FETCH_OP(and, ) -ATOMIC_LONG_FETCH_OP(and, _relaxed) -ATOMIC_LONG_FETCH_OP(and, _acquire) -ATOMIC_LONG_FETCH_OP(and, _release) -ATOMIC_LONG_FETCH_OP(andnot, ) -ATOMIC_LONG_FETCH_OP(andnot, _relaxed) -ATOMIC_LONG_FETCH_OP(andnot, _acquire) -ATOMIC_LONG_FETCH_OP(andnot, _release) -ATOMIC_LONG_FETCH_OP(or, ) -ATOMIC_LONG_FETCH_OP(or, _relaxed) -ATOMIC_LONG_FETCH_OP(or, _acquire) -ATOMIC_LONG_FETCH_OP(or, _release) -ATOMIC_LONG_FETCH_OP(xor, ) -ATOMIC_LONG_FETCH_OP(xor, _relaxed) -ATOMIC_LONG_FETCH_OP(xor, _acquire) -ATOMIC_LONG_FETCH_OP(xor, _release) - -#undef ATOMIC_LONG_FETCH_OP - -#define ATOMIC_LONG_FETCH_INC_DEC_OP(op, mo) \ -static inline long \ -atomic_long_fetch_##op##mo(atomic_long_t *l) \ -{ \ - ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; \ - \ - return (long)ATOMIC_LONG_PFX(_fetch_##op##mo)(v); \ -} - -ATOMIC_LONG_FETCH_INC_DEC_OP(inc,) -ATOMIC_LONG_FETCH_INC_DEC_OP(inc, _relaxed) -ATOMIC_LONG_FETCH_INC_DEC_OP(inc, _acquire) -ATOMIC_LONG_FETCH_INC_DEC_OP(inc, _release) -ATOMIC_LONG_FETCH_INC_DEC_OP(dec,) -ATOMIC_LONG_FETCH_INC_DEC_OP(dec, _relaxed) -ATOMIC_LONG_FETCH_INC_DEC_OP(dec, _acquire) -ATOMIC_LONG_FETCH_INC_DEC_OP(dec, _release) - -#undef ATOMIC_LONG_FETCH_INC_DEC_OP - -#define ATOMIC_LONG_OP(op) \ -static __always_inline void \ -atomic_long_##op(long i, atomic_long_t *l) \ -{ \ - ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; \ - \ - ATOMIC_LONG_PFX(_##op)(i, v); \ -} - -ATOMIC_LONG_OP(add) -ATOMIC_LONG_OP(sub) -ATOMIC_LONG_OP(and) -ATOMIC_LONG_OP(andnot) -ATOMIC_LONG_OP(or) -ATOMIC_LONG_OP(xor) - -#undef ATOMIC_LONG_OP - -static inline int atomic_long_sub_and_test(long i, atomic_long_t *l) -{ - ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; - - return ATOMIC_LONG_PFX(_sub_and_test)(i, v); -} - -static inline int atomic_long_dec_and_test(atomic_long_t *l) -{ - ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; - - return ATOMIC_LONG_PFX(_dec_and_test)(v); -} - -static inline int atomic_long_inc_and_test(atomic_long_t *l) -{ - ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; - - return ATOMIC_LONG_PFX(_inc_and_test)(v); -} - -static inline int atomic_long_add_negative(long i, atomic_long_t *l) -{ - ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; - - return ATOMIC_LONG_PFX(_add_negative)(i, v); -} - -#define ATOMIC_LONG_INC_DEC_OP(op, mo) \ -static inline long \ -atomic_long_##op##_return##mo(atomic_long_t *l) \ -{ \ - ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; \ - \ - return (long)ATOMIC_LONG_PFX(_##op##_return##mo)(v); \ -} -ATOMIC_LONG_INC_DEC_OP(inc,) -ATOMIC_LONG_INC_DEC_OP(inc, _relaxed) -ATOMIC_LONG_INC_DEC_OP(inc, _acquire) -ATOMIC_LONG_INC_DEC_OP(inc, _release) -ATOMIC_LONG_INC_DEC_OP(dec,) -ATOMIC_LONG_INC_DEC_OP(dec, _relaxed) -ATOMIC_LONG_INC_DEC_OP(dec, _acquire) -ATOMIC_LONG_INC_DEC_OP(dec, _release) - -#undef ATOMIC_LONG_INC_DEC_OP - -static inline long atomic_long_add_unless(atomic_long_t *l, long a, long u) -{ - ATOMIC_LONG_PFX(_t) *v = (ATOMIC_LONG_PFX(_t) *)l; - - return (long)ATOMIC_LONG_PFX(_add_unless)(v, a, u); -} - -#define atomic_long_inc_not_zero(l) \ - ATOMIC_LONG_PFX(_inc_not_zero)((ATOMIC_LONG_PFX(_t) *)(l)) - -#endif /* _ASM_GENERIC_ATOMIC_LONG_H */ diff --git a/src/linux/include/asm-generic/atomic.h b/src/linux/include/asm-generic/atomic.h deleted file mode 100644 index 9ed8b98..0000000 --- a/src/linux/include/asm-generic/atomic.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Generic C implementation of atomic counter operations. Usable on - * UP systems only. Do not include in machine independent code. - * - * Originally implemented for MN10300. - * - * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ -#ifndef __ASM_GENERIC_ATOMIC_H -#define __ASM_GENERIC_ATOMIC_H - -#include -#include - -/* - * atomic_$op() - $op integer to atomic variable - * @i: integer value to $op - * @v: pointer to the atomic variable - * - * Atomically $ops @i to @v. Does not strictly guarantee a memory-barrier, use - * smp_mb__{before,after}_atomic(). - */ - -/* - * atomic_$op_return() - $op interer to atomic variable and returns the result - * @i: integer value to $op - * @v: pointer to the atomic variable - * - * Atomically $ops @i to @v. Does imply a full memory barrier. - */ - -#ifdef CONFIG_SMP - -/* we can build all atomic primitives from cmpxchg */ - -#define ATOMIC_OP(op, c_op) \ -static inline void atomic_##op(int i, atomic_t *v) \ -{ \ - int c, old; \ - \ - c = v->counter; \ - while ((old = cmpxchg(&v->counter, c, c c_op i)) != c) \ - c = old; \ -} - -#define ATOMIC_OP_RETURN(op, c_op) \ -static inline int atomic_##op##_return(int i, atomic_t *v) \ -{ \ - int c, old; \ - \ - c = v->counter; \ - while ((old = cmpxchg(&v->counter, c, c c_op i)) != c) \ - c = old; \ - \ - return c c_op i; \ -} - -#define ATOMIC_FETCH_OP(op, c_op) \ -static inline int atomic_fetch_##op(int i, atomic_t *v) \ -{ \ - int c, old; \ - \ - c = v->counter; \ - while ((old = cmpxchg(&v->counter, c, c c_op i)) != c) \ - c = old; \ - \ - return c; \ -} - -#else - -#include - -#define ATOMIC_OP(op, c_op) \ -static inline void atomic_##op(int i, atomic_t *v) \ -{ \ - unsigned long flags; \ - \ - raw_local_irq_save(flags); \ - v->counter = v->counter c_op i; \ - raw_local_irq_restore(flags); \ -} - -#define ATOMIC_OP_RETURN(op, c_op) \ -static inline int atomic_##op##_return(int i, atomic_t *v) \ -{ \ - unsigned long flags; \ - int ret; \ - \ - raw_local_irq_save(flags); \ - ret = (v->counter = v->counter c_op i); \ - raw_local_irq_restore(flags); \ - \ - return ret; \ -} - -#define ATOMIC_FETCH_OP(op, c_op) \ -static inline int atomic_fetch_##op(int i, atomic_t *v) \ -{ \ - unsigned long flags; \ - int ret; \ - \ - raw_local_irq_save(flags); \ - ret = v->counter; \ - v->counter = v->counter c_op i; \ - raw_local_irq_restore(flags); \ - \ - return ret; \ -} - -#endif /* CONFIG_SMP */ - -#ifndef atomic_add_return -ATOMIC_OP_RETURN(add, +) -#endif - -#ifndef atomic_sub_return -ATOMIC_OP_RETURN(sub, -) -#endif - -#ifndef atomic_fetch_add -ATOMIC_FETCH_OP(add, +) -#endif - -#ifndef atomic_fetch_sub -ATOMIC_FETCH_OP(sub, -) -#endif - -#ifndef atomic_fetch_and -ATOMIC_FETCH_OP(and, &) -#endif - -#ifndef atomic_fetch_or -ATOMIC_FETCH_OP(or, |) -#endif - -#ifndef atomic_fetch_xor -ATOMIC_FETCH_OP(xor, ^) -#endif - -#ifndef atomic_and -ATOMIC_OP(and, &) -#endif - -#ifndef atomic_or -ATOMIC_OP(or, |) -#endif - -#ifndef atomic_xor -ATOMIC_OP(xor, ^) -#endif - -#undef ATOMIC_FETCH_OP -#undef ATOMIC_OP_RETURN -#undef ATOMIC_OP - -/* - * Atomic operations that C can't guarantee us. Useful for - * resource counting etc.. - */ - -#define ATOMIC_INIT(i) { (i) } - -/** - * atomic_read - read atomic variable - * @v: pointer of type atomic_t - * - * Atomically reads the value of @v. - */ -#ifndef atomic_read -#define atomic_read(v) READ_ONCE((v)->counter) -#endif - -/** - * atomic_set - set atomic variable - * @v: pointer of type atomic_t - * @i: required value - * - * Atomically sets the value of @v to @i. - */ -#define atomic_set(v, i) WRITE_ONCE(((v)->counter), (i)) - -#include - -static inline int atomic_add_negative(int i, atomic_t *v) -{ - return atomic_add_return(i, v) < 0; -} - -static inline void atomic_add(int i, atomic_t *v) -{ - atomic_add_return(i, v); -} - -static inline void atomic_sub(int i, atomic_t *v) -{ - atomic_sub_return(i, v); -} - -static inline void atomic_inc(atomic_t *v) -{ - atomic_add_return(1, v); -} - -static inline void atomic_dec(atomic_t *v) -{ - atomic_sub_return(1, v); -} - -#define atomic_dec_return(v) atomic_sub_return(1, (v)) -#define atomic_inc_return(v) atomic_add_return(1, (v)) - -#define atomic_sub_and_test(i, v) (atomic_sub_return((i), (v)) == 0) -#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0) -#define atomic_inc_and_test(v) (atomic_inc_return(v) == 0) - -#define atomic_xchg(ptr, v) (xchg(&(ptr)->counter, (v))) -#define atomic_cmpxchg(v, old, new) (cmpxchg(&((v)->counter), (old), (new))) - -static inline int __atomic_add_unless(atomic_t *v, int a, int u) -{ - int c, old; - c = atomic_read(v); - while (c != u && (old = atomic_cmpxchg(v, c, c + a)) != c) - c = old; - return c; -} - -#endif /* __ASM_GENERIC_ATOMIC_H */ diff --git a/src/linux/include/asm-generic/atomic64.h b/src/linux/include/asm-generic/atomic64.h deleted file mode 100644 index 78f10da..0000000 --- a/src/linux/include/asm-generic/atomic64.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Generic implementation of 64-bit atomics using spinlocks, - * useful on processors that don't have 64-bit atomic instructions. - * - * Copyright © 2009 Paul Mackerras, IBM Corp. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _ASM_GENERIC_ATOMIC64_H -#define _ASM_GENERIC_ATOMIC64_H - -#ifndef CONFIG_64BIT -typedef struct { - long long counter; -} atomic64_t; -#endif - -#define ATOMIC64_INIT(i) { (i) } - -extern long long atomic64_read(const atomic64_t *v); -extern void atomic64_set(atomic64_t *v, long long i); - -#define ATOMIC64_OP(op) \ -extern void atomic64_##op(long long a, atomic64_t *v); - -#define ATOMIC64_OP_RETURN(op) \ -extern long long atomic64_##op##_return(long long a, atomic64_t *v); - -#define ATOMIC64_FETCH_OP(op) \ -extern long long atomic64_fetch_##op(long long a, atomic64_t *v); - -#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_OP_RETURN(op) ATOMIC64_FETCH_OP(op) - -ATOMIC64_OPS(add) -ATOMIC64_OPS(sub) - -#undef ATOMIC64_OPS -#define ATOMIC64_OPS(op) ATOMIC64_OP(op) ATOMIC64_FETCH_OP(op) - -ATOMIC64_OPS(and) -ATOMIC64_OPS(or) -ATOMIC64_OPS(xor) - -#undef ATOMIC64_OPS -#undef ATOMIC64_FETCH_OP -#undef ATOMIC64_OP_RETURN -#undef ATOMIC64_OP - -extern long long atomic64_dec_if_positive(atomic64_t *v); -extern long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n); -extern long long atomic64_xchg(atomic64_t *v, long long new); -extern int atomic64_add_unless(atomic64_t *v, long long a, long long u); - -#define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0) -#define atomic64_inc(v) atomic64_add(1LL, (v)) -#define atomic64_inc_return(v) atomic64_add_return(1LL, (v)) -#define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0) -#define atomic64_sub_and_test(a, v) (atomic64_sub_return((a), (v)) == 0) -#define atomic64_dec(v) atomic64_sub(1LL, (v)) -#define atomic64_dec_return(v) atomic64_sub_return(1LL, (v)) -#define atomic64_dec_and_test(v) (atomic64_dec_return((v)) == 0) -#define atomic64_inc_not_zero(v) atomic64_add_unless((v), 1LL, 0LL) - -#endif /* _ASM_GENERIC_ATOMIC64_H */ diff --git a/src/linux/include/asm-generic/barrier.h b/src/linux/include/asm-generic/barrier.h deleted file mode 100644 index fe297b5..0000000 --- a/src/linux/include/asm-generic/barrier.h +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Generic barrier definitions, originally based on MN10300 definitions. - * - * It should be possible to use these on really simple architectures, - * but it serves more as a starting point for new ports. - * - * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ -#ifndef __ASM_GENERIC_BARRIER_H -#define __ASM_GENERIC_BARRIER_H - -#ifndef __ASSEMBLY__ - -#include - -#ifndef nop -#define nop() asm volatile ("nop") -#endif - -/* - * Force strict CPU ordering. And yes, this is required on UP too when we're - * talking to devices. - * - * Fall back to compiler barriers if nothing better is provided. - */ - -#ifndef mb -#define mb() barrier() -#endif - -#ifndef rmb -#define rmb() mb() -#endif - -#ifndef wmb -#define wmb() mb() -#endif - -#ifndef dma_rmb -#define dma_rmb() rmb() -#endif - -#ifndef dma_wmb -#define dma_wmb() wmb() -#endif - -#ifndef read_barrier_depends -#define read_barrier_depends() do { } while (0) -#endif - -#ifndef __smp_mb -#define __smp_mb() mb() -#endif - -#ifndef __smp_rmb -#define __smp_rmb() rmb() -#endif - -#ifndef __smp_wmb -#define __smp_wmb() wmb() -#endif - -#ifndef __smp_read_barrier_depends -#define __smp_read_barrier_depends() read_barrier_depends() -#endif - -#ifdef CONFIG_SMP - -#ifndef smp_mb -#define smp_mb() __smp_mb() -#endif - -#ifndef smp_rmb -#define smp_rmb() __smp_rmb() -#endif - -#ifndef smp_wmb -#define smp_wmb() __smp_wmb() -#endif - -#ifndef smp_read_barrier_depends -#define smp_read_barrier_depends() __smp_read_barrier_depends() -#endif - -#else /* !CONFIG_SMP */ - -#ifndef smp_mb -#define smp_mb() barrier() -#endif - -#ifndef smp_rmb -#define smp_rmb() barrier() -#endif - -#ifndef smp_wmb -#define smp_wmb() barrier() -#endif - -#ifndef smp_read_barrier_depends -#define smp_read_barrier_depends() do { } while (0) -#endif - -#endif /* CONFIG_SMP */ - -#ifndef __smp_store_mb -#define __smp_store_mb(var, value) do { WRITE_ONCE(var, value); __smp_mb(); } while (0) -#endif - -#ifndef __smp_mb__before_atomic -#define __smp_mb__before_atomic() __smp_mb() -#endif - -#ifndef __smp_mb__after_atomic -#define __smp_mb__after_atomic() __smp_mb() -#endif - -#ifndef __smp_store_release -#define __smp_store_release(p, v) \ -do { \ - compiletime_assert_atomic_type(*p); \ - __smp_mb(); \ - WRITE_ONCE(*p, v); \ -} while (0) -#endif - -#ifndef __smp_load_acquire -#define __smp_load_acquire(p) \ -({ \ - typeof(*p) ___p1 = READ_ONCE(*p); \ - compiletime_assert_atomic_type(*p); \ - __smp_mb(); \ - ___p1; \ -}) -#endif - -#ifdef CONFIG_SMP - -#ifndef smp_store_mb -#define smp_store_mb(var, value) __smp_store_mb(var, value) -#endif - -#ifndef smp_mb__before_atomic -#define smp_mb__before_atomic() __smp_mb__before_atomic() -#endif - -#ifndef smp_mb__after_atomic -#define smp_mb__after_atomic() __smp_mb__after_atomic() -#endif - -#ifndef smp_store_release -#define smp_store_release(p, v) __smp_store_release(p, v) -#endif - -#ifndef smp_load_acquire -#define smp_load_acquire(p) __smp_load_acquire(p) -#endif - -#else /* !CONFIG_SMP */ - -#ifndef smp_store_mb -#define smp_store_mb(var, value) do { WRITE_ONCE(var, value); barrier(); } while (0) -#endif - -#ifndef smp_mb__before_atomic -#define smp_mb__before_atomic() barrier() -#endif - -#ifndef smp_mb__after_atomic -#define smp_mb__after_atomic() barrier() -#endif - -#ifndef smp_store_release -#define smp_store_release(p, v) \ -do { \ - compiletime_assert_atomic_type(*p); \ - barrier(); \ - WRITE_ONCE(*p, v); \ -} while (0) -#endif - -#ifndef smp_load_acquire -#define smp_load_acquire(p) \ -({ \ - typeof(*p) ___p1 = READ_ONCE(*p); \ - compiletime_assert_atomic_type(*p); \ - barrier(); \ - ___p1; \ -}) -#endif - -#endif /* CONFIG_SMP */ - -/* Barriers for virtual machine guests when talking to an SMP host */ -#define virt_mb() __smp_mb() -#define virt_rmb() __smp_rmb() -#define virt_wmb() __smp_wmb() -#define virt_read_barrier_depends() __smp_read_barrier_depends() -#define virt_store_mb(var, value) __smp_store_mb(var, value) -#define virt_mb__before_atomic() __smp_mb__before_atomic() -#define virt_mb__after_atomic() __smp_mb__after_atomic() -#define virt_store_release(p, v) __smp_store_release(p, v) -#define virt_load_acquire(p) __smp_load_acquire(p) - -/** - * smp_acquire__after_ctrl_dep() - Provide ACQUIRE ordering after a control dependency - * - * A control dependency provides a LOAD->STORE order, the additional RMB - * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order, - * aka. (load)-ACQUIRE. - * - * Architectures that do not do load speculation can have this be barrier(). - */ -#ifndef smp_acquire__after_ctrl_dep -#define smp_acquire__after_ctrl_dep() smp_rmb() -#endif - -/** - * smp_cond_load_acquire() - (Spin) wait for cond with ACQUIRE ordering - * @ptr: pointer to the variable to wait on - * @cond: boolean expression to wait for - * - * Equivalent to using smp_load_acquire() on the condition variable but employs - * the control dependency of the wait to reduce the barrier on many platforms. - * - * Due to C lacking lambda expressions we load the value of *ptr into a - * pre-named variable @VAL to be used in @cond. - */ -#ifndef smp_cond_load_acquire -#define smp_cond_load_acquire(ptr, cond_expr) ({ \ - typeof(ptr) __PTR = (ptr); \ - typeof(*ptr) VAL; \ - for (;;) { \ - VAL = READ_ONCE(*__PTR); \ - if (cond_expr) \ - break; \ - cpu_relax(); \ - } \ - smp_acquire__after_ctrl_dep(); \ - VAL; \ -}) -#endif - -#endif /* !__ASSEMBLY__ */ -#endif /* __ASM_GENERIC_BARRIER_H */ diff --git a/src/linux/include/asm-generic/bitops.h b/src/linux/include/asm-generic/bitops.h deleted file mode 100644 index dcdcacf..0000000 --- a/src/linux/include/asm-generic/bitops.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef __ASM_GENERIC_BITOPS_H -#define __ASM_GENERIC_BITOPS_H - -/* - * For the benefit of those who are trying to port Linux to another - * architecture, here are some C-language equivalents. You should - * recode these in the native assembly language, if at all possible. - * - * C language equivalents written by Theodore Ts'o, 9/26/92 - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifndef _LINUX_BITOPS_H -#error only can be included directly -#endif - -#include -#include -#include -#include - -#include -#include -#include -#include - -#endif /* __ASM_GENERIC_BITOPS_H */ diff --git a/src/linux/include/asm-generic/bitops/__ffs.h b/src/linux/include/asm-generic/bitops/__ffs.h deleted file mode 100644 index 937d7c4..0000000 --- a/src/linux/include/asm-generic/bitops/__ffs.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef _ASM_GENERIC_BITOPS___FFS_H_ -#define _ASM_GENERIC_BITOPS___FFS_H_ - -#include - -/** - * __ffs - find first bit in word. - * @word: The word to search - * - * Undefined if no bit exists, so code should check against 0 first. - */ -static __always_inline unsigned long __ffs(unsigned long word) -{ - int num = 0; - -#if BITS_PER_LONG == 64 - if ((word & 0xffffffff) == 0) { - num += 32; - word >>= 32; - } -#endif - if ((word & 0xffff) == 0) { - num += 16; - word >>= 16; - } - if ((word & 0xff) == 0) { - num += 8; - word >>= 8; - } - if ((word & 0xf) == 0) { - num += 4; - word >>= 4; - } - if ((word & 0x3) == 0) { - num += 2; - word >>= 2; - } - if ((word & 0x1) == 0) - num += 1; - return num; -} - -#endif /* _ASM_GENERIC_BITOPS___FFS_H_ */ diff --git a/src/linux/include/asm-generic/bitops/__fls.h b/src/linux/include/asm-generic/bitops/__fls.h deleted file mode 100644 index a60a7cc..0000000 --- a/src/linux/include/asm-generic/bitops/__fls.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef _ASM_GENERIC_BITOPS___FLS_H_ -#define _ASM_GENERIC_BITOPS___FLS_H_ - -#include - -/** - * __fls - find last (most-significant) set bit in a long word - * @word: the word to search - * - * Undefined if no set bit exists, so code should check against 0 first. - */ -static __always_inline unsigned long __fls(unsigned long word) -{ - int num = BITS_PER_LONG - 1; - -#if BITS_PER_LONG == 64 - if (!(word & (~0ul << 32))) { - num -= 32; - word <<= 32; - } -#endif - if (!(word & (~0ul << (BITS_PER_LONG-16)))) { - num -= 16; - word <<= 16; - } - if (!(word & (~0ul << (BITS_PER_LONG-8)))) { - num -= 8; - word <<= 8; - } - if (!(word & (~0ul << (BITS_PER_LONG-4)))) { - num -= 4; - word <<= 4; - } - if (!(word & (~0ul << (BITS_PER_LONG-2)))) { - num -= 2; - word <<= 2; - } - if (!(word & (~0ul << (BITS_PER_LONG-1)))) - num -= 1; - return num; -} - -#endif /* _ASM_GENERIC_BITOPS___FLS_H_ */ diff --git a/src/linux/include/asm-generic/bitops/arch_hweight.h b/src/linux/include/asm-generic/bitops/arch_hweight.h deleted file mode 100644 index 6a211f4..0000000 --- a/src/linux/include/asm-generic/bitops/arch_hweight.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _ASM_GENERIC_BITOPS_ARCH_HWEIGHT_H_ -#define _ASM_GENERIC_BITOPS_ARCH_HWEIGHT_H_ - -#include - -static inline unsigned int __arch_hweight32(unsigned int w) -{ - return __sw_hweight32(w); -} - -static inline unsigned int __arch_hweight16(unsigned int w) -{ - return __sw_hweight16(w); -} - -static inline unsigned int __arch_hweight8(unsigned int w) -{ - return __sw_hweight8(w); -} - -static inline unsigned long __arch_hweight64(__u64 w) -{ - return __sw_hweight64(w); -} -#endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */ diff --git a/src/linux/include/asm-generic/bitops/atomic.h b/src/linux/include/asm-generic/bitops/atomic.h deleted file mode 100644 index 4967351..0000000 --- a/src/linux/include/asm-generic/bitops/atomic.h +++ /dev/null @@ -1,189 +0,0 @@ -#ifndef _ASM_GENERIC_BITOPS_ATOMIC_H_ -#define _ASM_GENERIC_BITOPS_ATOMIC_H_ - -#include -#include - -#ifdef CONFIG_SMP -#include -#include /* we use L1_CACHE_BYTES */ - -/* Use an array of spinlocks for our atomic_ts. - * Hash function to index into a different SPINLOCK. - * Since "a" is usually an address, use one spinlock per cacheline. - */ -# define ATOMIC_HASH_SIZE 4 -# define ATOMIC_HASH(a) (&(__atomic_hash[ (((unsigned long) a)/L1_CACHE_BYTES) & (ATOMIC_HASH_SIZE-1) ])) - -extern arch_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned; - -/* Can't use raw_spin_lock_irq because of #include problems, so - * this is the substitute */ -#define _atomic_spin_lock_irqsave(l,f) do { \ - arch_spinlock_t *s = ATOMIC_HASH(l); \ - local_irq_save(f); \ - arch_spin_lock(s); \ -} while(0) - -#define _atomic_spin_unlock_irqrestore(l,f) do { \ - arch_spinlock_t *s = ATOMIC_HASH(l); \ - arch_spin_unlock(s); \ - local_irq_restore(f); \ -} while(0) - - -#else -# define _atomic_spin_lock_irqsave(l,f) do { local_irq_save(f); } while (0) -# define _atomic_spin_unlock_irqrestore(l,f) do { local_irq_restore(f); } while (0) -#endif - -/* - * NMI events can occur at any time, including when interrupts have been - * disabled by *_irqsave(). So you can get NMI events occurring while a - * *_bit function is holding a spin lock. If the NMI handler also wants - * to do bit manipulation (and they do) then you can get a deadlock - * between the original caller of *_bit() and the NMI handler. - * - * by Keith Owens - */ - -/** - * set_bit - Atomically set a bit in memory - * @nr: the bit to set - * @addr: the address to start counting from - * - * This function is atomic and may not be reordered. See __set_bit() - * if you do not require the atomic guarantees. - * - * Note: there are no guarantees that this function will not be reordered - * on non x86 architectures, so if you are writing portable code, - * make sure not to rely on its reordering guarantees. - * - * Note that @nr may be almost arbitrarily large; this function is not - * restricted to acting on a single-word quantity. - */ -static inline void set_bit(int nr, volatile unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - unsigned long flags; - - _atomic_spin_lock_irqsave(p, flags); - *p |= mask; - _atomic_spin_unlock_irqrestore(p, flags); -} - -/** - * clear_bit - Clears a bit in memory - * @nr: Bit to clear - * @addr: Address to start counting from - * - * clear_bit() is atomic and may not be reordered. However, it does - * not contain a memory barrier, so if it is used for locking purposes, - * you should call smp_mb__before_atomic() and/or smp_mb__after_atomic() - * in order to ensure changes are visible on other processors. - */ -static inline void clear_bit(int nr, volatile unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - unsigned long flags; - - _atomic_spin_lock_irqsave(p, flags); - *p &= ~mask; - _atomic_spin_unlock_irqrestore(p, flags); -} - -/** - * change_bit - Toggle a bit in memory - * @nr: Bit to change - * @addr: Address to start counting from - * - * change_bit() is atomic and may not be reordered. It may be - * reordered on other architectures than x86. - * Note that @nr may be almost arbitrarily large; this function is not - * restricted to acting on a single-word quantity. - */ -static inline void change_bit(int nr, volatile unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - unsigned long flags; - - _atomic_spin_lock_irqsave(p, flags); - *p ^= mask; - _atomic_spin_unlock_irqrestore(p, flags); -} - -/** - * test_and_set_bit - Set a bit and return its old value - * @nr: Bit to set - * @addr: Address to count from - * - * This operation is atomic and cannot be reordered. - * It may be reordered on other architectures than x86. - * It also implies a memory barrier. - */ -static inline int test_and_set_bit(int nr, volatile unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - unsigned long old; - unsigned long flags; - - _atomic_spin_lock_irqsave(p, flags); - old = *p; - *p = old | mask; - _atomic_spin_unlock_irqrestore(p, flags); - - return (old & mask) != 0; -} - -/** - * test_and_clear_bit - Clear a bit and return its old value - * @nr: Bit to clear - * @addr: Address to count from - * - * This operation is atomic and cannot be reordered. - * It can be reorderdered on other architectures other than x86. - * It also implies a memory barrier. - */ -static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - unsigned long old; - unsigned long flags; - - _atomic_spin_lock_irqsave(p, flags); - old = *p; - *p = old & ~mask; - _atomic_spin_unlock_irqrestore(p, flags); - - return (old & mask) != 0; -} - -/** - * test_and_change_bit - Change a bit and return its old value - * @nr: Bit to change - * @addr: Address to count from - * - * This operation is atomic and cannot be reordered. - * It also implies a memory barrier. - */ -static inline int test_and_change_bit(int nr, volatile unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - unsigned long old; - unsigned long flags; - - _atomic_spin_lock_irqsave(p, flags); - old = *p; - *p = old ^ mask; - _atomic_spin_unlock_irqrestore(p, flags); - - return (old & mask) != 0; -} - -#endif /* _ASM_GENERIC_BITOPS_ATOMIC_H */ diff --git a/src/linux/include/asm-generic/bitops/const_hweight.h b/src/linux/include/asm-generic/bitops/const_hweight.h deleted file mode 100644 index 0a7e066..0000000 --- a/src/linux/include/asm-generic/bitops/const_hweight.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef _ASM_GENERIC_BITOPS_CONST_HWEIGHT_H_ -#define _ASM_GENERIC_BITOPS_CONST_HWEIGHT_H_ - -/* - * Compile time versions of __arch_hweightN() - */ -#define __const_hweight8(w) \ - ((unsigned int) \ - ((!!((w) & (1ULL << 0))) + \ - (!!((w) & (1ULL << 1))) + \ - (!!((w) & (1ULL << 2))) + \ - (!!((w) & (1ULL << 3))) + \ - (!!((w) & (1ULL << 4))) + \ - (!!((w) & (1ULL << 5))) + \ - (!!((w) & (1ULL << 6))) + \ - (!!((w) & (1ULL << 7))))) - -#define __const_hweight16(w) (__const_hweight8(w) + __const_hweight8((w) >> 8 )) -#define __const_hweight32(w) (__const_hweight16(w) + __const_hweight16((w) >> 16)) -#define __const_hweight64(w) (__const_hweight32(w) + __const_hweight32((w) >> 32)) - -/* - * Generic interface. - */ -#define hweight8(w) (__builtin_constant_p(w) ? __const_hweight8(w) : __arch_hweight8(w)) -#define hweight16(w) (__builtin_constant_p(w) ? __const_hweight16(w) : __arch_hweight16(w)) -#define hweight32(w) (__builtin_constant_p(w) ? __const_hweight32(w) : __arch_hweight32(w)) -#define hweight64(w) (__builtin_constant_p(w) ? __const_hweight64(w) : __arch_hweight64(w)) - -/* - * Interface for known constant arguments - */ -#define HWEIGHT8(w) (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + __const_hweight8(w)) -#define HWEIGHT16(w) (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + __const_hweight16(w)) -#define HWEIGHT32(w) (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + __const_hweight32(w)) -#define HWEIGHT64(w) (BUILD_BUG_ON_ZERO(!__builtin_constant_p(w)) + __const_hweight64(w)) - -/* - * Type invariant interface to the compile time constant hweight functions. - */ -#define HWEIGHT(w) HWEIGHT64((u64)w) - -#endif /* _ASM_GENERIC_BITOPS_CONST_HWEIGHT_H_ */ diff --git a/src/linux/include/asm-generic/bitops/ext2-atomic.h b/src/linux/include/asm-generic/bitops/ext2-atomic.h deleted file mode 100644 index 87f0f10..0000000 --- a/src/linux/include/asm-generic/bitops/ext2-atomic.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef _ASM_GENERIC_BITOPS_EXT2_ATOMIC_H_ -#define _ASM_GENERIC_BITOPS_EXT2_ATOMIC_H_ - -/* - * Spinlock based version of ext2 atomic bitops - */ - -#define ext2_set_bit_atomic(lock, nr, addr) \ - ({ \ - int ret; \ - spin_lock(lock); \ - ret = __test_and_set_bit_le(nr, addr); \ - spin_unlock(lock); \ - ret; \ - }) - -#define ext2_clear_bit_atomic(lock, nr, addr) \ - ({ \ - int ret; \ - spin_lock(lock); \ - ret = __test_and_clear_bit_le(nr, addr); \ - spin_unlock(lock); \ - ret; \ - }) - -#endif /* _ASM_GENERIC_BITOPS_EXT2_ATOMIC_H_ */ diff --git a/src/linux/include/asm-generic/bitops/ffs.h b/src/linux/include/asm-generic/bitops/ffs.h deleted file mode 100644 index fbbb43a..0000000 --- a/src/linux/include/asm-generic/bitops/ffs.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _ASM_GENERIC_BITOPS_FFS_H_ -#define _ASM_GENERIC_BITOPS_FFS_H_ - -/** - * ffs - find first bit set - * @x: the word to search - * - * This is defined the same way as - * the libc and compiler builtin ffs routines, therefore - * differs in spirit from the above ffz (man ffs). - */ -static inline int ffs(int x) -{ - int r = 1; - - if (!x) - return 0; - if (!(x & 0xffff)) { - x >>= 16; - r += 16; - } - if (!(x & 0xff)) { - x >>= 8; - r += 8; - } - if (!(x & 0xf)) { - x >>= 4; - r += 4; - } - if (!(x & 3)) { - x >>= 2; - r += 2; - } - if (!(x & 1)) { - x >>= 1; - r += 1; - } - return r; -} - -#endif /* _ASM_GENERIC_BITOPS_FFS_H_ */ diff --git a/src/linux/include/asm-generic/bitops/ffz.h b/src/linux/include/asm-generic/bitops/ffz.h deleted file mode 100644 index 6744bd4..0000000 --- a/src/linux/include/asm-generic/bitops/ffz.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _ASM_GENERIC_BITOPS_FFZ_H_ -#define _ASM_GENERIC_BITOPS_FFZ_H_ - -/* - * ffz - find first zero in word. - * @word: The word to search - * - * Undefined if no zero exists, so code should check against ~0UL first. - */ -#define ffz(x) __ffs(~(x)) - -#endif /* _ASM_GENERIC_BITOPS_FFZ_H_ */ diff --git a/src/linux/include/asm-generic/bitops/find.h b/src/linux/include/asm-generic/bitops/find.h deleted file mode 100644 index 998d4d5..0000000 --- a/src/linux/include/asm-generic/bitops/find.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef _ASM_GENERIC_BITOPS_FIND_H_ -#define _ASM_GENERIC_BITOPS_FIND_H_ - -#ifndef find_next_bit -/** - * find_next_bit - find the next set bit in a memory region - * @addr: The address to base the search on - * @offset: The bitnumber to start searching at - * @size: The bitmap size in bits - * - * Returns the bit number for the next set bit - * If no bits are set, returns @size. - */ -extern unsigned long find_next_bit(const unsigned long *addr, unsigned long - size, unsigned long offset); -#endif - -#ifndef find_next_zero_bit -/** - * find_next_zero_bit - find the next cleared bit in a memory region - * @addr: The address to base the search on - * @offset: The bitnumber to start searching at - * @size: The bitmap size in bits - * - * Returns the bit number of the next zero bit - * If no bits are zero, returns @size. - */ -extern unsigned long find_next_zero_bit(const unsigned long *addr, unsigned - long size, unsigned long offset); -#endif - -#ifdef CONFIG_GENERIC_FIND_FIRST_BIT - -/** - * find_first_bit - find the first set bit in a memory region - * @addr: The address to start the search at - * @size: The maximum number of bits to search - * - * Returns the bit number of the first set bit. - * If no bits are set, returns @size. - */ -extern unsigned long find_first_bit(const unsigned long *addr, - unsigned long size); - -/** - * find_first_zero_bit - find the first cleared bit in a memory region - * @addr: The address to start the search at - * @size: The maximum number of bits to search - * - * Returns the bit number of the first cleared bit. - * If no bits are zero, returns @size. - */ -extern unsigned long find_first_zero_bit(const unsigned long *addr, - unsigned long size); -#else /* CONFIG_GENERIC_FIND_FIRST_BIT */ - -#define find_first_bit(addr, size) find_next_bit((addr), (size), 0) -#define find_first_zero_bit(addr, size) find_next_zero_bit((addr), (size), 0) - -#endif /* CONFIG_GENERIC_FIND_FIRST_BIT */ - -#endif /*_ASM_GENERIC_BITOPS_FIND_H_ */ diff --git a/src/linux/include/asm-generic/bitops/fls.h b/src/linux/include/asm-generic/bitops/fls.h deleted file mode 100644 index 0576d1f..0000000 --- a/src/linux/include/asm-generic/bitops/fls.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _ASM_GENERIC_BITOPS_FLS_H_ -#define _ASM_GENERIC_BITOPS_FLS_H_ - -/** - * fls - find last (most-significant) bit set - * @x: the word to search - * - * This is defined the same way as ffs. - * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32. - */ - -static __always_inline int fls(int x) -{ - int r = 32; - - if (!x) - return 0; - if (!(x & 0xffff0000u)) { - x <<= 16; - r -= 16; - } - if (!(x & 0xff000000u)) { - x <<= 8; - r -= 8; - } - if (!(x & 0xf0000000u)) { - x <<= 4; - r -= 4; - } - if (!(x & 0xc0000000u)) { - x <<= 2; - r -= 2; - } - if (!(x & 0x80000000u)) { - x <<= 1; - r -= 1; - } - return r; -} - -#endif /* _ASM_GENERIC_BITOPS_FLS_H_ */ diff --git a/src/linux/include/asm-generic/bitops/fls64.h b/src/linux/include/asm-generic/bitops/fls64.h deleted file mode 100644 index b097cf8..0000000 --- a/src/linux/include/asm-generic/bitops/fls64.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef _ASM_GENERIC_BITOPS_FLS64_H_ -#define _ASM_GENERIC_BITOPS_FLS64_H_ - -#include - -/** - * fls64 - find last set bit in a 64-bit word - * @x: the word to search - * - * This is defined in a similar way as the libc and compiler builtin - * ffsll, but returns the position of the most significant set bit. - * - * fls64(value) returns 0 if value is 0 or the position of the last - * set bit if value is nonzero. The last (most significant) bit is - * at position 64. - */ -#if BITS_PER_LONG == 32 -static __always_inline int fls64(__u64 x) -{ - __u32 h = x >> 32; - if (h) - return fls(h) + 32; - return fls(x); -} -#elif BITS_PER_LONG == 64 -static __always_inline int fls64(__u64 x) -{ - if (x == 0) - return 0; - return __fls(x) + 1; -} -#else -#error BITS_PER_LONG not 32 or 64 -#endif - -#endif /* _ASM_GENERIC_BITOPS_FLS64_H_ */ diff --git a/src/linux/include/asm-generic/bitops/hweight.h b/src/linux/include/asm-generic/bitops/hweight.h deleted file mode 100644 index a94d651..0000000 --- a/src/linux/include/asm-generic/bitops/hweight.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _ASM_GENERIC_BITOPS_HWEIGHT_H_ -#define _ASM_GENERIC_BITOPS_HWEIGHT_H_ - -#include -#include - -#endif /* _ASM_GENERIC_BITOPS_HWEIGHT_H_ */ diff --git a/src/linux/include/asm-generic/bitops/le.h b/src/linux/include/asm-generic/bitops/le.h deleted file mode 100644 index 6173154..0000000 --- a/src/linux/include/asm-generic/bitops/le.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef _ASM_GENERIC_BITOPS_LE_H_ -#define _ASM_GENERIC_BITOPS_LE_H_ - -#include -#include - -#if defined(__LITTLE_ENDIAN) - -#define BITOP_LE_SWIZZLE 0 - -static inline unsigned long find_next_zero_bit_le(const void *addr, - unsigned long size, unsigned long offset) -{ - return find_next_zero_bit(addr, size, offset); -} - -static inline unsigned long find_next_bit_le(const void *addr, - unsigned long size, unsigned long offset) -{ - return find_next_bit(addr, size, offset); -} - -static inline unsigned long find_first_zero_bit_le(const void *addr, - unsigned long size) -{ - return find_first_zero_bit(addr, size); -} - -#elif defined(__BIG_ENDIAN) - -#define BITOP_LE_SWIZZLE ((BITS_PER_LONG-1) & ~0x7) - -#ifndef find_next_zero_bit_le -extern unsigned long find_next_zero_bit_le(const void *addr, - unsigned long size, unsigned long offset); -#endif - -#ifndef find_next_bit_le -extern unsigned long find_next_bit_le(const void *addr, - unsigned long size, unsigned long offset); -#endif - -#ifndef find_first_zero_bit_le -#define find_first_zero_bit_le(addr, size) \ - find_next_zero_bit_le((addr), (size), 0) -#endif - -#else -#error "Please fix " -#endif - -static inline int test_bit_le(int nr, const void *addr) -{ - return test_bit(nr ^ BITOP_LE_SWIZZLE, addr); -} - -static inline void set_bit_le(int nr, void *addr) -{ - set_bit(nr ^ BITOP_LE_SWIZZLE, addr); -} - -static inline void clear_bit_le(int nr, void *addr) -{ - clear_bit(nr ^ BITOP_LE_SWIZZLE, addr); -} - -static inline void __set_bit_le(int nr, void *addr) -{ - __set_bit(nr ^ BITOP_LE_SWIZZLE, addr); -} - -static inline void __clear_bit_le(int nr, void *addr) -{ - __clear_bit(nr ^ BITOP_LE_SWIZZLE, addr); -} - -static inline int test_and_set_bit_le(int nr, void *addr) -{ - return test_and_set_bit(nr ^ BITOP_LE_SWIZZLE, addr); -} - -static inline int test_and_clear_bit_le(int nr, void *addr) -{ - return test_and_clear_bit(nr ^ BITOP_LE_SWIZZLE, addr); -} - -static inline int __test_and_set_bit_le(int nr, void *addr) -{ - return __test_and_set_bit(nr ^ BITOP_LE_SWIZZLE, addr); -} - -static inline int __test_and_clear_bit_le(int nr, void *addr) -{ - return __test_and_clear_bit(nr ^ BITOP_LE_SWIZZLE, addr); -} - -#endif /* _ASM_GENERIC_BITOPS_LE_H_ */ diff --git a/src/linux/include/asm-generic/bitops/lock.h b/src/linux/include/asm-generic/bitops/lock.h deleted file mode 100644 index 8ef0ccb..0000000 --- a/src/linux/include/asm-generic/bitops/lock.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _ASM_GENERIC_BITOPS_LOCK_H_ -#define _ASM_GENERIC_BITOPS_LOCK_H_ - -/** - * test_and_set_bit_lock - Set a bit and return its old value, for lock - * @nr: Bit to set - * @addr: Address to count from - * - * This operation is atomic and provides acquire barrier semantics. - * It can be used to implement bit locks. - */ -#define test_and_set_bit_lock(nr, addr) test_and_set_bit(nr, addr) - -/** - * clear_bit_unlock - Clear a bit in memory, for unlock - * @nr: the bit to set - * @addr: the address to start counting from - * - * This operation is atomic and provides release barrier semantics. - */ -#define clear_bit_unlock(nr, addr) \ -do { \ - smp_mb__before_atomic(); \ - clear_bit(nr, addr); \ -} while (0) - -/** - * __clear_bit_unlock - Clear a bit in memory, for unlock - * @nr: the bit to set - * @addr: the address to start counting from - * - * A weaker form of clear_bit_unlock() as used by __bit_lock_unlock(). If all - * the bits in the word are protected by this lock some archs can use weaker - * ops to safely unlock. - * - * See for example x86's implementation. - */ -#define __clear_bit_unlock(nr, addr) \ -do { \ - smp_mb__before_atomic(); \ - clear_bit(nr, addr); \ -} while (0) - -#endif /* _ASM_GENERIC_BITOPS_LOCK_H_ */ - diff --git a/src/linux/include/asm-generic/bitops/non-atomic.h b/src/linux/include/asm-generic/bitops/non-atomic.h deleted file mode 100644 index 697cc2b..0000000 --- a/src/linux/include/asm-generic/bitops/non-atomic.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ -#define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ - -#include - -/** - * __set_bit - Set a bit in memory - * @nr: the bit to set - * @addr: the address to start counting from - * - * Unlike set_bit(), this function is non-atomic and may be reordered. - * If it's called on the same region of memory simultaneously, the effect - * may be that only one operation succeeds. - */ -static inline void __set_bit(int nr, volatile unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - - *p |= mask; -} - -static inline void __clear_bit(int nr, volatile unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - - *p &= ~mask; -} - -/** - * __change_bit - Toggle a bit in memory - * @nr: the bit to change - * @addr: the address to start counting from - * - * Unlike change_bit(), this function is non-atomic and may be reordered. - * If it's called on the same region of memory simultaneously, the effect - * may be that only one operation succeeds. - */ -static inline void __change_bit(int nr, volatile unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - - *p ^= mask; -} - -/** - * __test_and_set_bit - Set a bit and return its old value - * @nr: Bit to set - * @addr: Address to count from - * - * This operation is non-atomic and can be reordered. - * If two examples of this operation race, one can appear to succeed - * but actually fail. You must protect multiple accesses with a lock. - */ -static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - unsigned long old = *p; - - *p = old | mask; - return (old & mask) != 0; -} - -/** - * __test_and_clear_bit - Clear a bit and return its old value - * @nr: Bit to clear - * @addr: Address to count from - * - * This operation is non-atomic and can be reordered. - * If two examples of this operation race, one can appear to succeed - * but actually fail. You must protect multiple accesses with a lock. - */ -static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - unsigned long old = *p; - - *p = old & ~mask; - return (old & mask) != 0; -} - -/* WARNING: non atomic and it can be reordered! */ -static inline int __test_and_change_bit(int nr, - volatile unsigned long *addr) -{ - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - unsigned long old = *p; - - *p = old ^ mask; - return (old & mask) != 0; -} - -/** - * test_bit - Determine whether a bit is set - * @nr: bit number to test - * @addr: Address to start counting from - */ -static inline int test_bit(int nr, const volatile unsigned long *addr) -{ - return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); -} - -#endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ diff --git a/src/linux/include/asm-generic/bitops/sched.h b/src/linux/include/asm-generic/bitops/sched.h deleted file mode 100644 index 604fab7..0000000 --- a/src/linux/include/asm-generic/bitops/sched.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _ASM_GENERIC_BITOPS_SCHED_H_ -#define _ASM_GENERIC_BITOPS_SCHED_H_ - -#include /* unlikely() */ -#include - -/* - * Every architecture must define this function. It's the fastest - * way of searching a 100-bit bitmap. It's guaranteed that at least - * one of the 100 bits is cleared. - */ -static inline int sched_find_first_bit(const unsigned long *b) -{ -#if BITS_PER_LONG == 64 - if (b[0]) - return __ffs(b[0]); - return __ffs(b[1]) + 64; -#elif BITS_PER_LONG == 32 - if (b[0]) - return __ffs(b[0]); - if (b[1]) - return __ffs(b[1]) + 32; - if (b[2]) - return __ffs(b[2]) + 64; - return __ffs(b[3]) + 96; -#else -#error BITS_PER_LONG not defined -#endif -} - -#endif /* _ASM_GENERIC_BITOPS_SCHED_H_ */ diff --git a/src/linux/include/asm-generic/bug.h b/src/linux/include/asm-generic/bug.h deleted file mode 100644 index 6f96247..0000000 --- a/src/linux/include/asm-generic/bug.h +++ /dev/null @@ -1,220 +0,0 @@ -#ifndef _ASM_GENERIC_BUG_H -#define _ASM_GENERIC_BUG_H - -#include - -#ifdef CONFIG_GENERIC_BUG -#define BUGFLAG_WARNING (1 << 0) -#define BUGFLAG_TAINT(taint) (BUGFLAG_WARNING | ((taint) << 8)) -#define BUG_GET_TAINT(bug) ((bug)->flags >> 8) -#endif - -#ifndef __ASSEMBLY__ -#include - -#ifdef CONFIG_BUG - -#ifdef CONFIG_GENERIC_BUG -struct bug_entry { -#ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS - unsigned long bug_addr; -#else - signed int bug_addr_disp; -#endif -#ifdef CONFIG_DEBUG_BUGVERBOSE -#ifndef CONFIG_GENERIC_BUG_RELATIVE_POINTERS - const char *file; -#else - signed int file_disp; -#endif - unsigned short line; -#endif - unsigned short flags; -}; -#endif /* CONFIG_GENERIC_BUG */ - -/* - * Don't use BUG() or BUG_ON() unless there's really no way out; one - * example might be detecting data structure corruption in the middle - * of an operation that can't be backed out of. If the (sub)system - * can somehow continue operating, perhaps with reduced functionality, - * it's probably not BUG-worthy. - * - * If you're tempted to BUG(), think again: is completely giving up - * really the *only* solution? There are usually better options, where - * users don't need to reboot ASAP and can mostly shut down cleanly. - */ -#ifndef HAVE_ARCH_BUG -#define BUG() do { \ - printk("BUG: failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); \ - panic("BUG!"); \ -} while (0) -#endif - -#ifndef HAVE_ARCH_BUG_ON -#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while (0) -#endif - -/* - * WARN(), WARN_ON(), WARN_ON_ONCE, and so on can be used to report - * significant issues that need prompt attention if they should ever - * appear at runtime. Use the versions with printk format strings - * to provide better diagnostics. - */ -#ifndef __WARN_TAINT -extern __printf(3, 4) -void warn_slowpath_fmt(const char *file, const int line, - const char *fmt, ...); -extern __printf(4, 5) -void warn_slowpath_fmt_taint(const char *file, const int line, unsigned taint, - const char *fmt, ...); -extern void warn_slowpath_null(const char *file, const int line); -#define WANT_WARN_ON_SLOWPATH -#define __WARN() warn_slowpath_null(__FILE__, __LINE__) -#define __WARN_printf(arg...) warn_slowpath_fmt(__FILE__, __LINE__, arg) -#define __WARN_printf_taint(taint, arg...) \ - warn_slowpath_fmt_taint(__FILE__, __LINE__, taint, arg) -#else -#define __WARN() __WARN_TAINT(TAINT_WARN) -#define __WARN_printf(arg...) do { printk(arg); __WARN(); } while (0) -#define __WARN_printf_taint(taint, arg...) \ - do { printk(arg); __WARN_TAINT(taint); } while (0) -#endif - -/* used internally by panic.c */ -struct warn_args; - -void __warn(const char *file, int line, void *caller, unsigned taint, - struct pt_regs *regs, struct warn_args *args); - -#ifndef WARN_ON -#define WARN_ON(condition) ({ \ - int __ret_warn_on = !!(condition); \ - if (unlikely(__ret_warn_on)) \ - __WARN(); \ - unlikely(__ret_warn_on); \ -}) -#endif - -#ifndef WARN -#define WARN(condition, format...) ({ \ - int __ret_warn_on = !!(condition); \ - if (unlikely(__ret_warn_on)) \ - __WARN_printf(format); \ - unlikely(__ret_warn_on); \ -}) -#endif - -#define WARN_TAINT(condition, taint, format...) ({ \ - int __ret_warn_on = !!(condition); \ - if (unlikely(__ret_warn_on)) \ - __WARN_printf_taint(taint, format); \ - unlikely(__ret_warn_on); \ -}) - -#define WARN_ON_ONCE(condition) ({ \ - static bool __section(.data.unlikely) __warned; \ - int __ret_warn_once = !!(condition); \ - \ - if (unlikely(__ret_warn_once && !__warned)) { \ - __warned = true; \ - WARN_ON(1); \ - } \ - unlikely(__ret_warn_once); \ -}) - -#define WARN_ONCE(condition, format...) ({ \ - static bool __section(.data.unlikely) __warned; \ - int __ret_warn_once = !!(condition); \ - \ - if (unlikely(__ret_warn_once && !__warned)) { \ - __warned = true; \ - WARN(1, format); \ - } \ - unlikely(__ret_warn_once); \ -}) - -#define WARN_TAINT_ONCE(condition, taint, format...) ({ \ - static bool __section(.data.unlikely) __warned; \ - int __ret_warn_once = !!(condition); \ - \ - if (unlikely(__ret_warn_once && !__warned)) { \ - __warned = true; \ - WARN_TAINT(1, taint, format); \ - } \ - unlikely(__ret_warn_once); \ -}) - -#else /* !CONFIG_BUG */ -#ifndef HAVE_ARCH_BUG -#define BUG() do {} while (1) -#endif - -#ifndef HAVE_ARCH_BUG_ON -#define BUG_ON(condition) do { if (condition) BUG(); } while (0) -#endif - -#ifndef HAVE_ARCH_WARN_ON -#define WARN_ON(condition) ({ \ - int __ret_warn_on = !!(condition); \ - unlikely(__ret_warn_on); \ -}) -#endif - -#ifndef WARN -#define WARN(condition, format...) ({ \ - int __ret_warn_on = !!(condition); \ - no_printk(format); \ - unlikely(__ret_warn_on); \ -}) -#endif - -#define WARN_ON_ONCE(condition) WARN_ON(condition) -#define WARN_ONCE(condition, format...) WARN(condition, format) -#define WARN_TAINT(condition, taint, format...) WARN(condition, format) -#define WARN_TAINT_ONCE(condition, taint, format...) WARN(condition, format) - -#endif - -/* - * WARN_ON_SMP() is for cases that the warning is either - * meaningless for !SMP or may even cause failures. - * This is usually used for cases that we have - * WARN_ON(!spin_is_locked(&lock)) checks, as spin_is_locked() - * returns 0 for uniprocessor settings. - * It can also be used with values that are only defined - * on SMP: - * - * struct foo { - * [...] - * #ifdef CONFIG_SMP - * int bar; - * #endif - * }; - * - * void func(struct foo *zoot) - * { - * WARN_ON_SMP(!zoot->bar); - * - * For CONFIG_SMP, WARN_ON_SMP() should act the same as WARN_ON(), - * and should be a nop and return false for uniprocessor. - * - * if (WARN_ON_SMP(x)) returns true only when CONFIG_SMP is set - * and x is true. - */ -#ifdef CONFIG_SMP -# define WARN_ON_SMP(x) WARN_ON(x) -#else -/* - * Use of ({0;}) because WARN_ON_SMP(x) may be used either as - * a stand alone line statement or as a condition in an if () - * statement. - * A simple "0" would cause gcc to give a "statement has no effect" - * warning. - */ -# define WARN_ON_SMP(x) ({0;}) -#endif - -#endif /* __ASSEMBLY__ */ - -#endif diff --git a/src/linux/include/asm-generic/bugs.h b/src/linux/include/asm-generic/bugs.h deleted file mode 100644 index 6c4f62e..0000000 --- a/src/linux/include/asm-generic/bugs.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __ASM_GENERIC_BUGS_H -#define __ASM_GENERIC_BUGS_H -/* - * This file is included by 'init/main.c' to check for - * architecture-dependent bugs. - */ - -static inline void check_bugs(void) { } - -#endif /* __ASM_GENERIC_BUGS_H */ diff --git a/src/linux/include/asm-generic/cache.h b/src/linux/include/asm-generic/cache.h deleted file mode 100644 index 1bfcfe5..0000000 --- a/src/linux/include/asm-generic/cache.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __ASM_GENERIC_CACHE_H -#define __ASM_GENERIC_CACHE_H -/* - * 32 bytes appears to be the most common cache line size, - * so make that the default here. Architectures with larger - * cache lines need to provide their own cache.h. - */ - -#define L1_CACHE_SHIFT 5 -#define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) - -#endif /* __ASM_GENERIC_CACHE_H */ diff --git a/src/linux/include/asm-generic/cacheflush.h b/src/linux/include/asm-generic/cacheflush.h deleted file mode 100644 index 87bc536..0000000 --- a/src/linux/include/asm-generic/cacheflush.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __ASM_CACHEFLUSH_H -#define __ASM_CACHEFLUSH_H - -/* Keep includes the same across arches. */ -#include - -/* - * The cache doesn't need to be flushed when TLB entries change when - * the cache is mapped to physical memory, not virtual memory - */ -#define flush_cache_all() do { } while (0) -#define flush_cache_mm(mm) do { } while (0) -#define flush_cache_dup_mm(mm) do { } while (0) -#define flush_cache_range(vma, start, end) do { } while (0) -#define flush_cache_page(vma, vmaddr, pfn) do { } while (0) -#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 0 -#define flush_dcache_page(page) do { } while (0) -#define flush_dcache_mmap_lock(mapping) do { } while (0) -#define flush_dcache_mmap_unlock(mapping) do { } while (0) -#define flush_icache_range(start, end) do { } while (0) -#define flush_icache_page(vma,pg) do { } while (0) -#define flush_icache_user_range(vma,pg,adr,len) do { } while (0) -#define flush_cache_vmap(start, end) do { } while (0) -#define flush_cache_vunmap(start, end) do { } while (0) - -#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ - do { \ - memcpy(dst, src, len); \ - flush_icache_user_range(vma, page, vaddr, len); \ - } while (0) -#define copy_from_user_page(vma, page, vaddr, dst, src, len) \ - memcpy(dst, src, len) - -#endif /* __ASM_CACHEFLUSH_H */ diff --git a/src/linux/include/asm-generic/checksum.h b/src/linux/include/asm-generic/checksum.h deleted file mode 100644 index 3150cbd..0000000 --- a/src/linux/include/asm-generic/checksum.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef __ASM_GENERIC_CHECKSUM_H -#define __ASM_GENERIC_CHECKSUM_H - -/* - * computes the checksum of a memory block at buff, length len, - * and adds in "sum" (32-bit) - * - * returns a 32-bit number suitable for feeding into itself - * or csum_tcpudp_magic - * - * this function must be called with even lengths, except - * for the last fragment, which may be odd - * - * it's best to have buff aligned on a 32-bit boundary - */ -extern __wsum csum_partial(const void *buff, int len, __wsum sum); - -/* - * the same as csum_partial, but copies from src while it - * checksums - * - * here even more important to align src and dst on a 32-bit (or even - * better 64-bit) boundary - */ -extern __wsum csum_partial_copy(const void *src, void *dst, int len, __wsum sum); - -/* - * the same as csum_partial_copy, but copies from user space. - * - * here even more important to align src and dst on a 32-bit (or even - * better 64-bit) boundary - */ -extern __wsum csum_partial_copy_from_user(const void __user *src, void *dst, - int len, __wsum sum, int *csum_err); - -#ifndef csum_partial_copy_nocheck -#define csum_partial_copy_nocheck(src, dst, len, sum) \ - csum_partial_copy((src), (dst), (len), (sum)) -#endif - -#ifndef ip_fast_csum -/* - * This is a version of ip_compute_csum() optimized for IP headers, - * which always checksum on 4 octet boundaries. - */ -extern __sum16 ip_fast_csum(const void *iph, unsigned int ihl); -#endif - -#ifndef csum_fold -/* - * Fold a partial checksum - */ -static inline __sum16 csum_fold(__wsum csum) -{ - u32 sum = (__force u32)csum; - sum = (sum & 0xffff) + (sum >> 16); - sum = (sum & 0xffff) + (sum >> 16); - return (__force __sum16)~sum; -} -#endif - -#ifndef csum_tcpudp_nofold -/* - * computes the checksum of the TCP/UDP pseudo-header - * returns a 16-bit checksum, already complemented - */ -extern __wsum -csum_tcpudp_nofold(__be32 saddr, __be32 daddr, __u32 len, - __u8 proto, __wsum sum); -#endif - -#ifndef csum_tcpudp_magic -static inline __sum16 -csum_tcpudp_magic(__be32 saddr, __be32 daddr, __u32 len, - __u8 proto, __wsum sum) -{ - return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum)); -} -#endif - -/* - * this routine is used for miscellaneous IP-like checksums, mainly - * in icmp.c - */ -extern __sum16 ip_compute_csum(const void *buff, int len); - -#endif /* __ASM_GENERIC_CHECKSUM_H */ diff --git a/src/linux/include/asm-generic/cmpxchg-local.h b/src/linux/include/asm-generic/cmpxchg-local.h deleted file mode 100644 index 70bef78..0000000 --- a/src/linux/include/asm-generic/cmpxchg-local.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef __ASM_GENERIC_CMPXCHG_LOCAL_H -#define __ASM_GENERIC_CMPXCHG_LOCAL_H - -#include -#include - -extern unsigned long wrong_size_cmpxchg(volatile void *ptr) - __noreturn; - -/* - * Generic version of __cmpxchg_local (disables interrupts). Takes an unsigned - * long parameter, supporting various types of architectures. - */ -static inline unsigned long __cmpxchg_local_generic(volatile void *ptr, - unsigned long old, unsigned long new, int size) -{ - unsigned long flags, prev; - - /* - * Sanity checking, compile-time. - */ - if (size == 8 && sizeof(unsigned long) != 8) - wrong_size_cmpxchg(ptr); - - raw_local_irq_save(flags); - switch (size) { - case 1: prev = *(u8 *)ptr; - if (prev == old) - *(u8 *)ptr = (u8)new; - break; - case 2: prev = *(u16 *)ptr; - if (prev == old) - *(u16 *)ptr = (u16)new; - break; - case 4: prev = *(u32 *)ptr; - if (prev == old) - *(u32 *)ptr = (u32)new; - break; - case 8: prev = *(u64 *)ptr; - if (prev == old) - *(u64 *)ptr = (u64)new; - break; - default: - wrong_size_cmpxchg(ptr); - } - raw_local_irq_restore(flags); - return prev; -} - -/* - * Generic version of __cmpxchg64_local. Takes an u64 parameter. - */ -static inline u64 __cmpxchg64_local_generic(volatile void *ptr, - u64 old, u64 new) -{ - u64 prev; - unsigned long flags; - - raw_local_irq_save(flags); - prev = *(u64 *)ptr; - if (prev == old) - *(u64 *)ptr = new; - raw_local_irq_restore(flags); - return prev; -} - -#endif diff --git a/src/linux/include/asm-generic/cmpxchg.h b/src/linux/include/asm-generic/cmpxchg.h deleted file mode 100644 index e5f9080..0000000 --- a/src/linux/include/asm-generic/cmpxchg.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Generic UP xchg and cmpxchg using interrupt disablement. Does not - * support SMP. - */ - -#ifndef __ASM_GENERIC_CMPXCHG_H -#define __ASM_GENERIC_CMPXCHG_H - -#ifdef CONFIG_SMP -#error "Cannot use generic cmpxchg on SMP" -#endif - -#include -#include - -#ifndef xchg - -/* - * This function doesn't exist, so you'll get a linker error if - * something tries to do an invalidly-sized xchg(). - */ -extern void __xchg_called_with_bad_pointer(void); - -static inline -unsigned long __xchg(unsigned long x, volatile void *ptr, int size) -{ - unsigned long ret, flags; - - switch (size) { - case 1: -#ifdef __xchg_u8 - return __xchg_u8(x, ptr); -#else - local_irq_save(flags); - ret = *(volatile u8 *)ptr; - *(volatile u8 *)ptr = x; - local_irq_restore(flags); - return ret; -#endif /* __xchg_u8 */ - - case 2: -#ifdef __xchg_u16 - return __xchg_u16(x, ptr); -#else - local_irq_save(flags); - ret = *(volatile u16 *)ptr; - *(volatile u16 *)ptr = x; - local_irq_restore(flags); - return ret; -#endif /* __xchg_u16 */ - - case 4: -#ifdef __xchg_u32 - return __xchg_u32(x, ptr); -#else - local_irq_save(flags); - ret = *(volatile u32 *)ptr; - *(volatile u32 *)ptr = x; - local_irq_restore(flags); - return ret; -#endif /* __xchg_u32 */ - -#ifdef CONFIG_64BIT - case 8: -#ifdef __xchg_u64 - return __xchg_u64(x, ptr); -#else - local_irq_save(flags); - ret = *(volatile u64 *)ptr; - *(volatile u64 *)ptr = x; - local_irq_restore(flags); - return ret; -#endif /* __xchg_u64 */ -#endif /* CONFIG_64BIT */ - - default: - __xchg_called_with_bad_pointer(); - return x; - } -} - -#define xchg(ptr, x) ({ \ - ((__typeof__(*(ptr))) \ - __xchg((unsigned long)(x), (ptr), sizeof(*(ptr)))); \ -}) - -#endif /* xchg */ - -/* - * Atomic compare and exchange. - */ -#include - -#ifndef cmpxchg_local -#define cmpxchg_local(ptr, o, n) ({ \ - ((__typeof__(*(ptr)))__cmpxchg_local_generic((ptr), (unsigned long)(o),\ - (unsigned long)(n), sizeof(*(ptr)))); \ -}) -#endif - -#ifndef cmpxchg64_local -#define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n)) -#endif - -#define cmpxchg(ptr, o, n) cmpxchg_local((ptr), (o), (n)) -#define cmpxchg64(ptr, o, n) cmpxchg64_local((ptr), (o), (n)) - -#endif /* __ASM_GENERIC_CMPXCHG_H */ diff --git a/src/linux/include/asm-generic/cputime.h b/src/linux/include/asm-generic/cputime.h deleted file mode 100644 index 5196943..0000000 --- a/src/linux/include/asm-generic/cputime.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _ASM_GENERIC_CPUTIME_H -#define _ASM_GENERIC_CPUTIME_H - -#include -#include - -#ifndef CONFIG_VIRT_CPU_ACCOUNTING -# include -#endif - -#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN -# include -#endif - -#endif diff --git a/src/linux/include/asm-generic/cputime_jiffies.h b/src/linux/include/asm-generic/cputime_jiffies.h deleted file mode 100644 index fe386fc..0000000 --- a/src/linux/include/asm-generic/cputime_jiffies.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef _ASM_GENERIC_CPUTIME_JIFFIES_H -#define _ASM_GENERIC_CPUTIME_JIFFIES_H - -typedef unsigned long __nocast cputime_t; - -#define cmpxchg_cputime(ptr, old, new) cmpxchg(ptr, old, new) - -#define cputime_one_jiffy jiffies_to_cputime(1) -#define cputime_to_jiffies(__ct) (__force unsigned long)(__ct) -#define cputime_to_scaled(__ct) (__ct) -#define jiffies_to_cputime(__hz) (__force cputime_t)(__hz) - -typedef u64 __nocast cputime64_t; - -#define cputime64_to_jiffies64(__ct) (__force u64)(__ct) -#define jiffies64_to_cputime64(__jif) (__force cputime64_t)(__jif) - - -/* - * Convert nanoseconds <-> cputime - */ -#define cputime_to_nsecs(__ct) \ - jiffies_to_nsecs(cputime_to_jiffies(__ct)) -#define nsecs_to_cputime64(__nsec) \ - jiffies64_to_cputime64(nsecs_to_jiffies64(__nsec)) -#define nsecs_to_cputime(__nsec) \ - jiffies_to_cputime(nsecs_to_jiffies(__nsec)) - - -/* - * Convert cputime to microseconds and back. - */ -#define cputime_to_usecs(__ct) \ - jiffies_to_usecs(cputime_to_jiffies(__ct)) -#define usecs_to_cputime(__usec) \ - jiffies_to_cputime(usecs_to_jiffies(__usec)) -#define usecs_to_cputime64(__usec) \ - jiffies64_to_cputime64(nsecs_to_jiffies64((__usec) * 1000)) - -/* - * Convert cputime to seconds and back. - */ -#define cputime_to_secs(jif) (cputime_to_jiffies(jif) / HZ) -#define secs_to_cputime(sec) jiffies_to_cputime((sec) * HZ) - -/* - * Convert cputime to timespec and back. - */ -#define timespec_to_cputime(__val) \ - jiffies_to_cputime(timespec_to_jiffies(__val)) -#define cputime_to_timespec(__ct,__val) \ - jiffies_to_timespec(cputime_to_jiffies(__ct),__val) - -/* - * Convert cputime to timeval and back. - */ -#define timeval_to_cputime(__val) \ - jiffies_to_cputime(timeval_to_jiffies(__val)) -#define cputime_to_timeval(__ct,__val) \ - jiffies_to_timeval(cputime_to_jiffies(__ct),__val) - -/* - * Convert cputime to clock and back. - */ -#define cputime_to_clock_t(__ct) \ - jiffies_to_clock_t(cputime_to_jiffies(__ct)) -#define clock_t_to_cputime(__x) \ - jiffies_to_cputime(clock_t_to_jiffies(__x)) - -/* - * Convert cputime64 to clock. - */ -#define cputime64_to_clock_t(__ct) \ - jiffies_64_to_clock_t(cputime64_to_jiffies64(__ct)) - -#endif diff --git a/src/linux/include/asm-generic/current.h b/src/linux/include/asm-generic/current.h deleted file mode 100644 index 5e86f6a..0000000 --- a/src/linux/include/asm-generic/current.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __ASM_GENERIC_CURRENT_H -#define __ASM_GENERIC_CURRENT_H - -#include - -#define get_current() (current_thread_info()->task) -#define current get_current() - -#endif /* __ASM_GENERIC_CURRENT_H */ diff --git a/src/linux/include/asm-generic/delay.h b/src/linux/include/asm-generic/delay.h deleted file mode 100644 index 0f79054..0000000 --- a/src/linux/include/asm-generic/delay.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef __ASM_GENERIC_DELAY_H -#define __ASM_GENERIC_DELAY_H - -/* Undefined functions to get compile-time errors */ -extern void __bad_udelay(void); -extern void __bad_ndelay(void); - -extern void __udelay(unsigned long usecs); -extern void __ndelay(unsigned long nsecs); -extern void __const_udelay(unsigned long xloops); -extern void __delay(unsigned long loops); - -/* - * The weird n/20000 thing suppresses a "comparison is always false due to - * limited range of data type" warning with non-const 8-bit arguments. - */ - -/* 0x10c7 is 2**32 / 1000000 (rounded up) */ -#define udelay(n) \ - ({ \ - if (__builtin_constant_p(n)) { \ - if ((n) / 20000 >= 1) \ - __bad_udelay(); \ - else \ - __const_udelay((n) * 0x10c7ul); \ - } else { \ - __udelay(n); \ - } \ - }) - -/* 0x5 is 2**32 / 1000000000 (rounded up) */ -#define ndelay(n) \ - ({ \ - if (__builtin_constant_p(n)) { \ - if ((n) / 20000 >= 1) \ - __bad_ndelay(); \ - else \ - __const_udelay((n) * 5ul); \ - } else { \ - __ndelay(n); \ - } \ - }) - -#endif /* __ASM_GENERIC_DELAY_H */ diff --git a/src/linux/include/asm-generic/device.h b/src/linux/include/asm-generic/device.h deleted file mode 100644 index d7c76bb..0000000 --- a/src/linux/include/asm-generic/device.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Arch specific extensions to struct device - * - * This file is released under the GPLv2 - */ -#ifndef _ASM_GENERIC_DEVICE_H -#define _ASM_GENERIC_DEVICE_H - -struct dev_archdata { -}; - -struct pdev_archdata { -}; - -#endif /* _ASM_GENERIC_DEVICE_H */ diff --git a/src/linux/include/asm-generic/div64.h b/src/linux/include/asm-generic/div64.h deleted file mode 100644 index 163f779..0000000 --- a/src/linux/include/asm-generic/div64.h +++ /dev/null @@ -1,234 +0,0 @@ -#ifndef _ASM_GENERIC_DIV64_H -#define _ASM_GENERIC_DIV64_H -/* - * Copyright (C) 2003 Bernardo Innocenti - * Based on former asm-ppc/div64.h and asm-m68knommu/div64.h - * - * Optimization for constant divisors on 32-bit machines: - * Copyright (C) 2006-2015 Nicolas Pitre - * - * The semantics of do_div() are: - * - * uint32_t do_div(uint64_t *n, uint32_t base) - * { - * uint32_t remainder = *n % base; - * *n = *n / base; - * return remainder; - * } - * - * NOTE: macro parameter n is evaluated multiple times, - * beware of side effects! - */ - -#include -#include - -#if BITS_PER_LONG == 64 - -# define do_div(n,base) ({ \ - uint32_t __base = (base); \ - uint32_t __rem; \ - __rem = ((uint64_t)(n)) % __base; \ - (n) = ((uint64_t)(n)) / __base; \ - __rem; \ - }) - -#elif BITS_PER_LONG == 32 - -#include - -/* - * If the divisor happens to be constant, we determine the appropriate - * inverse at compile time to turn the division into a few inline - * multiplications which ought to be much faster. And yet only if compiling - * with a sufficiently recent gcc version to perform proper 64-bit constant - * propagation. - * - * (It is unfortunate that gcc doesn't perform all this internally.) - */ - -#ifndef __div64_const32_is_OK -#define __div64_const32_is_OK (__GNUC__ >= 4) -#endif - -#define __div64_const32(n, ___b) \ -({ \ - /* \ - * Multiplication by reciprocal of b: n / b = n * (p / b) / p \ - * \ - * We rely on the fact that most of this code gets optimized \ - * away at compile time due to constant propagation and only \ - * a few multiplication instructions should remain. \ - * Hence this monstrous macro (static inline doesn't always \ - * do the trick here). \ - */ \ - uint64_t ___res, ___x, ___t, ___m, ___n = (n); \ - uint32_t ___p, ___bias; \ - \ - /* determine MSB of b */ \ - ___p = 1 << ilog2(___b); \ - \ - /* compute m = ((p << 64) + b - 1) / b */ \ - ___m = (~0ULL / ___b) * ___p; \ - ___m += (((~0ULL % ___b + 1) * ___p) + ___b - 1) / ___b; \ - \ - /* one less than the dividend with highest result */ \ - ___x = ~0ULL / ___b * ___b - 1; \ - \ - /* test our ___m with res = m * x / (p << 64) */ \ - ___res = ((___m & 0xffffffff) * (___x & 0xffffffff)) >> 32; \ - ___t = ___res += (___m & 0xffffffff) * (___x >> 32); \ - ___res += (___x & 0xffffffff) * (___m >> 32); \ - ___t = (___res < ___t) ? (1ULL << 32) : 0; \ - ___res = (___res >> 32) + ___t; \ - ___res += (___m >> 32) * (___x >> 32); \ - ___res /= ___p; \ - \ - /* Now sanitize and optimize what we've got. */ \ - if (~0ULL % (___b / (___b & -___b)) == 0) { \ - /* special case, can be simplified to ... */ \ - ___n /= (___b & -___b); \ - ___m = ~0ULL / (___b / (___b & -___b)); \ - ___p = 1; \ - ___bias = 1; \ - } else if (___res != ___x / ___b) { \ - /* \ - * We can't get away without a bias to compensate \ - * for bit truncation errors. To avoid it we'd need an \ - * additional bit to represent m which would overflow \ - * a 64-bit variable. \ - * \ - * Instead we do m = p / b and n / b = (n * m + m) / p. \ - */ \ - ___bias = 1; \ - /* Compute m = (p << 64) / b */ \ - ___m = (~0ULL / ___b) * ___p; \ - ___m += ((~0ULL % ___b + 1) * ___p) / ___b; \ - } else { \ - /* \ - * Reduce m / p, and try to clear bit 31 of m when \ - * possible, otherwise that'll need extra overflow \ - * handling later. \ - */ \ - uint32_t ___bits = -(___m & -___m); \ - ___bits |= ___m >> 32; \ - ___bits = (~___bits) << 1; \ - /* \ - * If ___bits == 0 then setting bit 31 is unavoidable. \ - * Simply apply the maximum possible reduction in that \ - * case. Otherwise the MSB of ___bits indicates the \ - * best reduction we should apply. \ - */ \ - if (!___bits) { \ - ___p /= (___m & -___m); \ - ___m /= (___m & -___m); \ - } else { \ - ___p >>= ilog2(___bits); \ - ___m >>= ilog2(___bits); \ - } \ - /* No bias needed. */ \ - ___bias = 0; \ - } \ - \ - /* \ - * Now we have a combination of 2 conditions: \ - * \ - * 1) whether or not we need to apply a bias, and \ - * \ - * 2) whether or not there might be an overflow in the cross \ - * product determined by (___m & ((1 << 63) | (1 << 31))). \ - * \ - * Select the best way to do (m_bias + m * n) / (1 << 64). \ - * From now on there will be actual runtime code generated. \ - */ \ - ___res = __arch_xprod_64(___m, ___n, ___bias); \ - \ - ___res /= ___p; \ -}) - -#ifndef __arch_xprod_64 -/* - * Default C implementation for __arch_xprod_64() - * - * Prototype: uint64_t __arch_xprod_64(const uint64_t m, uint64_t n, bool bias) - * Semantic: retval = ((bias ? m : 0) + m * n) >> 64 - * - * The product is a 128-bit value, scaled down to 64 bits. - * Assuming constant propagation to optimize away unused conditional code. - * Architectures may provide their own optimized assembly implementation. - */ -static inline uint64_t __arch_xprod_64(const uint64_t m, uint64_t n, bool bias) -{ - uint32_t m_lo = m; - uint32_t m_hi = m >> 32; - uint32_t n_lo = n; - uint32_t n_hi = n >> 32; - uint64_t res, tmp; - - if (!bias) { - res = ((uint64_t)m_lo * n_lo) >> 32; - } else if (!(m & ((1ULL << 63) | (1ULL << 31)))) { - /* there can't be any overflow here */ - res = (m + (uint64_t)m_lo * n_lo) >> 32; - } else { - res = m + (uint64_t)m_lo * n_lo; - tmp = (res < m) ? (1ULL << 32) : 0; - res = (res >> 32) + tmp; - } - - if (!(m & ((1ULL << 63) | (1ULL << 31)))) { - /* there can't be any overflow here */ - res += (uint64_t)m_lo * n_hi; - res += (uint64_t)m_hi * n_lo; - res >>= 32; - } else { - tmp = res += (uint64_t)m_lo * n_hi; - res += (uint64_t)m_hi * n_lo; - tmp = (res < tmp) ? (1ULL << 32) : 0; - res = (res >> 32) + tmp; - } - - res += (uint64_t)m_hi * n_hi; - - return res; -} -#endif - -#ifndef __div64_32 -extern uint32_t __div64_32(uint64_t *dividend, uint32_t divisor); -#endif - -/* The unnecessary pointer compare is there - * to check for type safety (n must be 64bit) - */ -# define do_div(n,base) ({ \ - uint32_t __base = (base); \ - uint32_t __rem; \ - (void)(((typeof((n)) *)0) == ((uint64_t *)0)); \ - if (__builtin_constant_p(__base) && \ - is_power_of_2(__base)) { \ - __rem = (n) & (__base - 1); \ - (n) >>= ilog2(__base); \ - } else if (__div64_const32_is_OK && \ - __builtin_constant_p(__base) && \ - __base != 0) { \ - uint32_t __res_lo, __n_lo = (n); \ - (n) = __div64_const32(n, __base); \ - /* the remainder can be computed with 32-bit regs */ \ - __res_lo = (n); \ - __rem = __n_lo - __res_lo * __base; \ - } else if (likely(((n) >> 32) == 0)) { \ - __rem = (uint32_t)(n) % __base; \ - (n) = (uint32_t)(n) / __base; \ - } else \ - __rem = __div64_32(&(n), __base); \ - __rem; \ - }) - -#else /* BITS_PER_LONG == ?? */ - -# error do_div() does not yet support the C64 - -#endif /* BITS_PER_LONG */ - -#endif /* _ASM_GENERIC_DIV64_H */ diff --git a/src/linux/include/asm-generic/dma.h b/src/linux/include/asm-generic/dma.h deleted file mode 100644 index 9dfc3a7..0000000 --- a/src/linux/include/asm-generic/dma.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __ASM_GENERIC_DMA_H -#define __ASM_GENERIC_DMA_H -/* - * This file traditionally describes the i8237 PC style DMA controller. - * Most architectures don't have these any more and can get the minimal - * implementation from kernel/dma.c by not defining MAX_DMA_CHANNELS. - * - * Some code relies on seeing MAX_DMA_ADDRESS though. - */ -#define MAX_DMA_ADDRESS PAGE_OFFSET - -extern int request_dma(unsigned int dmanr, const char *device_id); -extern void free_dma(unsigned int dmanr); - -#endif /* __ASM_GENERIC_DMA_H */ diff --git a/src/linux/include/asm-generic/emergency-restart.h b/src/linux/include/asm-generic/emergency-restart.h deleted file mode 100644 index 0d68a1e..0000000 --- a/src/linux/include/asm-generic/emergency-restart.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _ASM_GENERIC_EMERGENCY_RESTART_H -#define _ASM_GENERIC_EMERGENCY_RESTART_H - -static inline void machine_emergency_restart(void) -{ - machine_restart(NULL); -} - -#endif /* _ASM_GENERIC_EMERGENCY_RESTART_H */ diff --git a/src/linux/include/asm-generic/exec.h b/src/linux/include/asm-generic/exec.h deleted file mode 100644 index 567766b..0000000 --- a/src/linux/include/asm-generic/exec.h +++ /dev/null @@ -1,19 +0,0 @@ -/* Generic process execution definitions, based on MN10300 definitions. - * - * It should be possible to use these on really simple architectures, - * but it serves more as a starting point for new ports. - * - * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ -#ifndef __ASM_GENERIC_EXEC_H -#define __ASM_GENERIC_EXEC_H - -#define arch_align_stack(x) (x) - -#endif /* __ASM_GENERIC_EXEC_H */ diff --git a/src/linux/include/asm-generic/ftrace.h b/src/linux/include/asm-generic/ftrace.h deleted file mode 100644 index 51abba9..0000000 --- a/src/linux/include/asm-generic/ftrace.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * linux/include/asm-generic/ftrace.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef __ASM_GENERIC_FTRACE_H__ -#define __ASM_GENERIC_FTRACE_H__ - -/* - * Not all architectures need their own ftrace.h, the most - * common definitions are already in linux/ftrace.h. - */ - -#endif /* __ASM_GENERIC_FTRACE_H__ */ diff --git a/src/linux/include/asm-generic/getorder.h b/src/linux/include/asm-generic/getorder.h deleted file mode 100644 index 65e4468..0000000 --- a/src/linux/include/asm-generic/getorder.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef __ASM_GENERIC_GETORDER_H -#define __ASM_GENERIC_GETORDER_H - -#ifndef __ASSEMBLY__ - -#include -#include - -/* - * Runtime evaluation of get_order() - */ -static inline __attribute_const__ -int __get_order(unsigned long size) -{ - int order; - - size--; - size >>= PAGE_SHIFT; -#if BITS_PER_LONG == 32 - order = fls(size); -#else - order = fls64(size); -#endif - return order; -} - -/** - * get_order - Determine the allocation order of a memory size - * @size: The size for which to get the order - * - * Determine the allocation order of a particular sized block of memory. This - * is on a logarithmic scale, where: - * - * 0 -> 2^0 * PAGE_SIZE and below - * 1 -> 2^1 * PAGE_SIZE to 2^0 * PAGE_SIZE + 1 - * 2 -> 2^2 * PAGE_SIZE to 2^1 * PAGE_SIZE + 1 - * 3 -> 2^3 * PAGE_SIZE to 2^2 * PAGE_SIZE + 1 - * 4 -> 2^4 * PAGE_SIZE to 2^3 * PAGE_SIZE + 1 - * ... - * - * The order returned is used to find the smallest allocation granule required - * to hold an object of the specified size. - * - * The result is undefined if the size is 0. - * - * This function may be used to initialise variables with compile time - * evaluations of constants. - */ -#define get_order(n) \ -( \ - __builtin_constant_p(n) ? ( \ - ((n) == 0UL) ? BITS_PER_LONG - PAGE_SHIFT : \ - (((n) < (1UL << PAGE_SHIFT)) ? 0 : \ - ilog2((n) - 1) - PAGE_SHIFT + 1) \ - ) : \ - __get_order(n) \ -) - -#endif /* __ASSEMBLY__ */ - -#endif /* __ASM_GENERIC_GETORDER_H */ diff --git a/src/linux/include/asm-generic/hardirq.h b/src/linux/include/asm-generic/hardirq.h deleted file mode 100644 index 04d0a97..0000000 --- a/src/linux/include/asm-generic/hardirq.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __ASM_GENERIC_HARDIRQ_H -#define __ASM_GENERIC_HARDIRQ_H - -#include -#include - -typedef struct { - unsigned int __softirq_pending; -} ____cacheline_aligned irq_cpustat_t; - -#include /* Standard mappings for irq_cpustat_t above */ -#include - -#ifndef ack_bad_irq -static inline void ack_bad_irq(unsigned int irq) -{ - printk(KERN_CRIT "unexpected IRQ trap at vector %02x\n", irq); -} -#endif - -#endif /* __ASM_GENERIC_HARDIRQ_H */ diff --git a/src/linux/include/asm-generic/hw_irq.h b/src/linux/include/asm-generic/hw_irq.h deleted file mode 100644 index 89036d7..0000000 --- a/src/linux/include/asm-generic/hw_irq.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __ASM_GENERIC_HW_IRQ_H -#define __ASM_GENERIC_HW_IRQ_H -/* - * hw_irq.h has internal declarations for the low-level interrupt - * controller, like the original i8259A. - * In general, this is not needed for new architectures. - */ - -#endif /* __ASM_GENERIC_HW_IRQ_H */ diff --git a/src/linux/include/asm-generic/int-ll64.h b/src/linux/include/asm-generic/int-ll64.h deleted file mode 100644 index 4cd8485..0000000 --- a/src/linux/include/asm-generic/int-ll64.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * asm-generic/int-ll64.h - * - * Integer declarations for architectures which use "long long" - * for 64-bit types. - */ -#ifndef _ASM_GENERIC_INT_LL64_H -#define _ASM_GENERIC_INT_LL64_H - -#include - - -#ifndef __ASSEMBLY__ - -typedef signed char s8; -typedef unsigned char u8; - -typedef signed short s16; -typedef unsigned short u16; - -typedef signed int s32; -typedef unsigned int u32; - -typedef signed long long s64; -typedef unsigned long long u64; - -#define S8_C(x) x -#define U8_C(x) x ## U -#define S16_C(x) x -#define U16_C(x) x ## U -#define S32_C(x) x -#define U32_C(x) x ## U -#define S64_C(x) x ## LL -#define U64_C(x) x ## ULL - -#else /* __ASSEMBLY__ */ - -#define S8_C(x) x -#define U8_C(x) x -#define S16_C(x) x -#define U16_C(x) x -#define S32_C(x) x -#define U32_C(x) x -#define S64_C(x) x -#define U64_C(x) x - -#endif /* __ASSEMBLY__ */ - -#endif /* _ASM_GENERIC_INT_LL64_H */ diff --git a/src/linux/include/asm-generic/io.h b/src/linux/include/asm-generic/io.h deleted file mode 100644 index 7ef015e..0000000 --- a/src/linux/include/asm-generic/io.h +++ /dev/null @@ -1,985 +0,0 @@ -/* Generic I/O port emulation, based on MN10300 code - * - * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ -#ifndef __ASM_GENERIC_IO_H -#define __ASM_GENERIC_IO_H - -#include /* I/O is all done through memory accesses */ -#include /* for memset() and memcpy() */ -#include - -#ifdef CONFIG_GENERIC_IOMAP -#include -#endif - -#include - -#ifndef mmiowb -#define mmiowb() do {} while (0) -#endif - -/* - * __raw_{read,write}{b,w,l,q}() access memory in native endianness. - * - * On some architectures memory mapped IO needs to be accessed differently. - * On the simple architectures, we just read/write the memory location - * directly. - */ - -#ifndef __raw_readb -#define __raw_readb __raw_readb -static inline u8 __raw_readb(const volatile void __iomem *addr) -{ - return *(const volatile u8 __force *)addr; -} -#endif - -#ifndef __raw_readw -#define __raw_readw __raw_readw -static inline u16 __raw_readw(const volatile void __iomem *addr) -{ - return *(const volatile u16 __force *)addr; -} -#endif - -#ifndef __raw_readl -#define __raw_readl __raw_readl -static inline u32 __raw_readl(const volatile void __iomem *addr) -{ - return *(const volatile u32 __force *)addr; -} -#endif - -#ifdef CONFIG_64BIT -#ifndef __raw_readq -#define __raw_readq __raw_readq -static inline u64 __raw_readq(const volatile void __iomem *addr) -{ - return *(const volatile u64 __force *)addr; -} -#endif -#endif /* CONFIG_64BIT */ - -#ifndef __raw_writeb -#define __raw_writeb __raw_writeb -static inline void __raw_writeb(u8 value, volatile void __iomem *addr) -{ - *(volatile u8 __force *)addr = value; -} -#endif - -#ifndef __raw_writew -#define __raw_writew __raw_writew -static inline void __raw_writew(u16 value, volatile void __iomem *addr) -{ - *(volatile u16 __force *)addr = value; -} -#endif - -#ifndef __raw_writel -#define __raw_writel __raw_writel -static inline void __raw_writel(u32 value, volatile void __iomem *addr) -{ - *(volatile u32 __force *)addr = value; -} -#endif - -#ifdef CONFIG_64BIT -#ifndef __raw_writeq -#define __raw_writeq __raw_writeq -static inline void __raw_writeq(u64 value, volatile void __iomem *addr) -{ - *(volatile u64 __force *)addr = value; -} -#endif -#endif /* CONFIG_64BIT */ - -/* - * {read,write}{b,w,l,q}() access little endian memory and return result in - * native endianness. - */ - -#ifndef readb -#define readb readb -static inline u8 readb(const volatile void __iomem *addr) -{ - return __raw_readb(addr); -} -#endif - -#ifndef readw -#define readw readw -static inline u16 readw(const volatile void __iomem *addr) -{ - return __le16_to_cpu(__raw_readw(addr)); -} -#endif - -#ifndef readl -#define readl readl -static inline u32 readl(const volatile void __iomem *addr) -{ - return __le32_to_cpu(__raw_readl(addr)); -} -#endif - -#ifdef CONFIG_64BIT -#ifndef readq -#define readq readq -static inline u64 readq(const volatile void __iomem *addr) -{ - return __le64_to_cpu(__raw_readq(addr)); -} -#endif -#endif /* CONFIG_64BIT */ - -#ifndef writeb -#define writeb writeb -static inline void writeb(u8 value, volatile void __iomem *addr) -{ - __raw_writeb(value, addr); -} -#endif - -#ifndef writew -#define writew writew -static inline void writew(u16 value, volatile void __iomem *addr) -{ - __raw_writew(cpu_to_le16(value), addr); -} -#endif - -#ifndef writel -#define writel writel -static inline void writel(u32 value, volatile void __iomem *addr) -{ - __raw_writel(__cpu_to_le32(value), addr); -} -#endif - -#ifdef CONFIG_64BIT -#ifndef writeq -#define writeq writeq -static inline void writeq(u64 value, volatile void __iomem *addr) -{ - __raw_writeq(__cpu_to_le64(value), addr); -} -#endif -#endif /* CONFIG_64BIT */ - -/* - * {read,write}{b,w,l,q}_relaxed() are like the regular version, but - * are not guaranteed to provide ordering against spinlocks or memory - * accesses. - */ -#ifndef readb_relaxed -#define readb_relaxed readb -#endif - -#ifndef readw_relaxed -#define readw_relaxed readw -#endif - -#ifndef readl_relaxed -#define readl_relaxed readl -#endif - -#if defined(readq) && !defined(readq_relaxed) -#define readq_relaxed readq -#endif - -#ifndef writeb_relaxed -#define writeb_relaxed writeb -#endif - -#ifndef writew_relaxed -#define writew_relaxed writew -#endif - -#ifndef writel_relaxed -#define writel_relaxed writel -#endif - -#if defined(writeq) && !defined(writeq_relaxed) -#define writeq_relaxed writeq -#endif - -/* - * {read,write}s{b,w,l,q}() repeatedly access the same memory address in - * native endianness in 8-, 16-, 32- or 64-bit chunks (@count times). - */ -#ifndef readsb -#define readsb readsb -static inline void readsb(const volatile void __iomem *addr, void *buffer, - unsigned int count) -{ - if (count) { - u8 *buf = buffer; - - do { - u8 x = __raw_readb(addr); - *buf++ = x; - } while (--count); - } -} -#endif - -#ifndef readsw -#define readsw readsw -static inline void readsw(const volatile void __iomem *addr, void *buffer, - unsigned int count) -{ - if (count) { - u16 *buf = buffer; - - do { - u16 x = __raw_readw(addr); - *buf++ = x; - } while (--count); - } -} -#endif - -#ifndef readsl -#define readsl readsl -static inline void readsl(const volatile void __iomem *addr, void *buffer, - unsigned int count) -{ - if (count) { - u32 *buf = buffer; - - do { - u32 x = __raw_readl(addr); - *buf++ = x; - } while (--count); - } -} -#endif - -#ifdef CONFIG_64BIT -#ifndef readsq -#define readsq readsq -static inline void readsq(const volatile void __iomem *addr, void *buffer, - unsigned int count) -{ - if (count) { - u64 *buf = buffer; - - do { - u64 x = __raw_readq(addr); - *buf++ = x; - } while (--count); - } -} -#endif -#endif /* CONFIG_64BIT */ - -#ifndef writesb -#define writesb writesb -static inline void writesb(volatile void __iomem *addr, const void *buffer, - unsigned int count) -{ - if (count) { - const u8 *buf = buffer; - - do { - __raw_writeb(*buf++, addr); - } while (--count); - } -} -#endif - -#ifndef writesw -#define writesw writesw -static inline void writesw(volatile void __iomem *addr, const void *buffer, - unsigned int count) -{ - if (count) { - const u16 *buf = buffer; - - do { - __raw_writew(*buf++, addr); - } while (--count); - } -} -#endif - -#ifndef writesl -#define writesl writesl -static inline void writesl(volatile void __iomem *addr, const void *buffer, - unsigned int count) -{ - if (count) { - const u32 *buf = buffer; - - do { - __raw_writel(*buf++, addr); - } while (--count); - } -} -#endif - -#ifdef CONFIG_64BIT -#ifndef writesq -#define writesq writesq -static inline void writesq(volatile void __iomem *addr, const void *buffer, - unsigned int count) -{ - if (count) { - const u64 *buf = buffer; - - do { - __raw_writeq(*buf++, addr); - } while (--count); - } -} -#endif -#endif /* CONFIG_64BIT */ - -#ifndef PCI_IOBASE -#define PCI_IOBASE ((void __iomem *)0) -#endif - -#ifndef IO_SPACE_LIMIT -#define IO_SPACE_LIMIT 0xffff -#endif - -/* - * {in,out}{b,w,l}() access little endian I/O. {in,out}{b,w,l}_p() can be - * implemented on hardware that needs an additional delay for I/O accesses to - * take effect. - */ - -#ifndef inb -#define inb inb -static inline u8 inb(unsigned long addr) -{ - return readb(PCI_IOBASE + addr); -} -#endif - -#ifndef inw -#define inw inw -static inline u16 inw(unsigned long addr) -{ - return readw(PCI_IOBASE + addr); -} -#endif - -#ifndef inl -#define inl inl -static inline u32 inl(unsigned long addr) -{ - return readl(PCI_IOBASE + addr); -} -#endif - -#ifndef outb -#define outb outb -static inline void outb(u8 value, unsigned long addr) -{ - writeb(value, PCI_IOBASE + addr); -} -#endif - -#ifndef outw -#define outw outw -static inline void outw(u16 value, unsigned long addr) -{ - writew(value, PCI_IOBASE + addr); -} -#endif - -#ifndef outl -#define outl outl -static inline void outl(u32 value, unsigned long addr) -{ - writel(value, PCI_IOBASE + addr); -} -#endif - -#ifndef inb_p -#define inb_p inb_p -static inline u8 inb_p(unsigned long addr) -{ - return inb(addr); -} -#endif - -#ifndef inw_p -#define inw_p inw_p -static inline u16 inw_p(unsigned long addr) -{ - return inw(addr); -} -#endif - -#ifndef inl_p -#define inl_p inl_p -static inline u32 inl_p(unsigned long addr) -{ - return inl(addr); -} -#endif - -#ifndef outb_p -#define outb_p outb_p -static inline void outb_p(u8 value, unsigned long addr) -{ - outb(value, addr); -} -#endif - -#ifndef outw_p -#define outw_p outw_p -static inline void outw_p(u16 value, unsigned long addr) -{ - outw(value, addr); -} -#endif - -#ifndef outl_p -#define outl_p outl_p -static inline void outl_p(u32 value, unsigned long addr) -{ - outl(value, addr); -} -#endif - -/* - * {in,out}s{b,w,l}{,_p}() are variants of the above that repeatedly access a - * single I/O port multiple times. - */ - -#ifndef insb -#define insb insb -static inline void insb(unsigned long addr, void *buffer, unsigned int count) -{ - readsb(PCI_IOBASE + addr, buffer, count); -} -#endif - -#ifndef insw -#define insw insw -static inline void insw(unsigned long addr, void *buffer, unsigned int count) -{ - readsw(PCI_IOBASE + addr, buffer, count); -} -#endif - -#ifndef insl -#define insl insl -static inline void insl(unsigned long addr, void *buffer, unsigned int count) -{ - readsl(PCI_IOBASE + addr, buffer, count); -} -#endif - -#ifndef outsb -#define outsb outsb -static inline void outsb(unsigned long addr, const void *buffer, - unsigned int count) -{ - writesb(PCI_IOBASE + addr, buffer, count); -} -#endif - -#ifndef outsw -#define outsw outsw -static inline void outsw(unsigned long addr, const void *buffer, - unsigned int count) -{ - writesw(PCI_IOBASE + addr, buffer, count); -} -#endif - -#ifndef outsl -#define outsl outsl -static inline void outsl(unsigned long addr, const void *buffer, - unsigned int count) -{ - writesl(PCI_IOBASE + addr, buffer, count); -} -#endif - -#ifndef insb_p -#define insb_p insb_p -static inline void insb_p(unsigned long addr, void *buffer, unsigned int count) -{ - insb(addr, buffer, count); -} -#endif - -#ifndef insw_p -#define insw_p insw_p -static inline void insw_p(unsigned long addr, void *buffer, unsigned int count) -{ - insw(addr, buffer, count); -} -#endif - -#ifndef insl_p -#define insl_p insl_p -static inline void insl_p(unsigned long addr, void *buffer, unsigned int count) -{ - insl(addr, buffer, count); -} -#endif - -#ifndef outsb_p -#define outsb_p outsb_p -static inline void outsb_p(unsigned long addr, const void *buffer, - unsigned int count) -{ - outsb(addr, buffer, count); -} -#endif - -#ifndef outsw_p -#define outsw_p outsw_p -static inline void outsw_p(unsigned long addr, const void *buffer, - unsigned int count) -{ - outsw(addr, buffer, count); -} -#endif - -#ifndef outsl_p -#define outsl_p outsl_p -static inline void outsl_p(unsigned long addr, const void *buffer, - unsigned int count) -{ - outsl(addr, buffer, count); -} -#endif - -#ifndef CONFIG_GENERIC_IOMAP -#ifndef ioread8 -#define ioread8 ioread8 -static inline u8 ioread8(const volatile void __iomem *addr) -{ - return readb(addr); -} -#endif - -#ifndef ioread16 -#define ioread16 ioread16 -static inline u16 ioread16(const volatile void __iomem *addr) -{ - return readw(addr); -} -#endif - -#ifndef ioread32 -#define ioread32 ioread32 -static inline u32 ioread32(const volatile void __iomem *addr) -{ - return readl(addr); -} -#endif - -#ifdef CONFIG_64BIT -#ifndef ioread64 -#define ioread64 ioread64 -static inline u64 ioread64(const volatile void __iomem *addr) -{ - return readq(addr); -} -#endif -#endif /* CONFIG_64BIT */ - -#ifndef iowrite8 -#define iowrite8 iowrite8 -static inline void iowrite8(u8 value, volatile void __iomem *addr) -{ - writeb(value, addr); -} -#endif - -#ifndef iowrite16 -#define iowrite16 iowrite16 -static inline void iowrite16(u16 value, volatile void __iomem *addr) -{ - writew(value, addr); -} -#endif - -#ifndef iowrite32 -#define iowrite32 iowrite32 -static inline void iowrite32(u32 value, volatile void __iomem *addr) -{ - writel(value, addr); -} -#endif - -#ifdef CONFIG_64BIT -#ifndef iowrite64 -#define iowrite64 iowrite64 -static inline void iowrite64(u64 value, volatile void __iomem *addr) -{ - writeq(value, addr); -} -#endif -#endif /* CONFIG_64BIT */ - -#ifndef ioread16be -#define ioread16be ioread16be -static inline u16 ioread16be(const volatile void __iomem *addr) -{ - return swab16(readw(addr)); -} -#endif - -#ifndef ioread32be -#define ioread32be ioread32be -static inline u32 ioread32be(const volatile void __iomem *addr) -{ - return swab32(readl(addr)); -} -#endif - -#ifdef CONFIG_64BIT -#ifndef ioread64be -#define ioread64be ioread64be -static inline u64 ioread64be(const volatile void __iomem *addr) -{ - return swab64(readq(addr)); -} -#endif -#endif /* CONFIG_64BIT */ - -#ifndef iowrite16be -#define iowrite16be iowrite16be -static inline void iowrite16be(u16 value, void volatile __iomem *addr) -{ - writew(swab16(value), addr); -} -#endif - -#ifndef iowrite32be -#define iowrite32be iowrite32be -static inline void iowrite32be(u32 value, volatile void __iomem *addr) -{ - writel(swab32(value), addr); -} -#endif - -#ifdef CONFIG_64BIT -#ifndef iowrite64be -#define iowrite64be iowrite64be -static inline void iowrite64be(u64 value, volatile void __iomem *addr) -{ - writeq(swab64(value), addr); -} -#endif -#endif /* CONFIG_64BIT */ - -#ifndef ioread8_rep -#define ioread8_rep ioread8_rep -static inline void ioread8_rep(const volatile void __iomem *addr, void *buffer, - unsigned int count) -{ - readsb(addr, buffer, count); -} -#endif - -#ifndef ioread16_rep -#define ioread16_rep ioread16_rep -static inline void ioread16_rep(const volatile void __iomem *addr, - void *buffer, unsigned int count) -{ - readsw(addr, buffer, count); -} -#endif - -#ifndef ioread32_rep -#define ioread32_rep ioread32_rep -static inline void ioread32_rep(const volatile void __iomem *addr, - void *buffer, unsigned int count) -{ - readsl(addr, buffer, count); -} -#endif - -#ifdef CONFIG_64BIT -#ifndef ioread64_rep -#define ioread64_rep ioread64_rep -static inline void ioread64_rep(const volatile void __iomem *addr, - void *buffer, unsigned int count) -{ - readsq(addr, buffer, count); -} -#endif -#endif /* CONFIG_64BIT */ - -#ifndef iowrite8_rep -#define iowrite8_rep iowrite8_rep -static inline void iowrite8_rep(volatile void __iomem *addr, - const void *buffer, - unsigned int count) -{ - writesb(addr, buffer, count); -} -#endif - -#ifndef iowrite16_rep -#define iowrite16_rep iowrite16_rep -static inline void iowrite16_rep(volatile void __iomem *addr, - const void *buffer, - unsigned int count) -{ - writesw(addr, buffer, count); -} -#endif - -#ifndef iowrite32_rep -#define iowrite32_rep iowrite32_rep -static inline void iowrite32_rep(volatile void __iomem *addr, - const void *buffer, - unsigned int count) -{ - writesl(addr, buffer, count); -} -#endif - -#ifdef CONFIG_64BIT -#ifndef iowrite64_rep -#define iowrite64_rep iowrite64_rep -static inline void iowrite64_rep(volatile void __iomem *addr, - const void *buffer, - unsigned int count) -{ - writesq(addr, buffer, count); -} -#endif -#endif /* CONFIG_64BIT */ -#endif /* CONFIG_GENERIC_IOMAP */ - -#ifdef __KERNEL__ - -#include -#define __io_virt(x) ((void __force *)(x)) - -#ifndef CONFIG_GENERIC_IOMAP -struct pci_dev; -extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max); - -#ifndef pci_iounmap -#define pci_iounmap pci_iounmap -static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p) -{ -} -#endif -#endif /* CONFIG_GENERIC_IOMAP */ - -/* - * Change virtual addresses to physical addresses and vv. - * These are pretty trivial - */ -#ifndef virt_to_phys -#define virt_to_phys virt_to_phys -static inline unsigned long virt_to_phys(volatile void *address) -{ - return __pa((unsigned long)address); -} -#endif - -#ifndef phys_to_virt -#define phys_to_virt phys_to_virt -static inline void *phys_to_virt(unsigned long address) -{ - return __va(address); -} -#endif - -/** - * DOC: ioremap() and ioremap_*() variants - * - * If you have an IOMMU your architecture is expected to have both ioremap() - * and iounmap() implemented otherwise the asm-generic helpers will provide a - * direct mapping. - * - * There are ioremap_*() call variants, if you have no IOMMU we naturally will - * default to direct mapping for all of them, you can override these defaults. - * If you have an IOMMU you are highly encouraged to provide your own - * ioremap variant implementation as there currently is no safe architecture - * agnostic default. To avoid possible improper behaviour default asm-generic - * ioremap_*() variants all return NULL when an IOMMU is available. If you've - * defined your own ioremap_*() variant you must then declare your own - * ioremap_*() variant as defined to itself to avoid the default NULL return. - */ - -#ifdef CONFIG_MMU - -#ifndef ioremap_uc -#define ioremap_uc ioremap_uc -static inline void __iomem *ioremap_uc(phys_addr_t offset, size_t size) -{ - return NULL; -} -#endif - -#else /* !CONFIG_MMU */ - -/* - * Change "struct page" to physical address. - * - * This implementation is for the no-MMU case only... if you have an MMU - * you'll need to provide your own definitions. - */ - -#ifndef ioremap -#define ioremap ioremap -static inline void __iomem *ioremap(phys_addr_t offset, size_t size) -{ - return (void __iomem *)(unsigned long)offset; -} -#endif - -#ifndef __ioremap -#define __ioremap __ioremap -static inline void __iomem *__ioremap(phys_addr_t offset, size_t size, - unsigned long flags) -{ - return ioremap(offset, size); -} -#endif - -#ifndef ioremap_nocache -#define ioremap_nocache ioremap_nocache -static inline void __iomem *ioremap_nocache(phys_addr_t offset, size_t size) -{ - return ioremap(offset, size); -} -#endif - -#ifndef ioremap_uc -#define ioremap_uc ioremap_uc -static inline void __iomem *ioremap_uc(phys_addr_t offset, size_t size) -{ - return ioremap_nocache(offset, size); -} -#endif - -#ifndef ioremap_wc -#define ioremap_wc ioremap_wc -static inline void __iomem *ioremap_wc(phys_addr_t offset, size_t size) -{ - return ioremap_nocache(offset, size); -} -#endif - -#ifndef ioremap_wt -#define ioremap_wt ioremap_wt -static inline void __iomem *ioremap_wt(phys_addr_t offset, size_t size) -{ - return ioremap_nocache(offset, size); -} -#endif - -#ifndef iounmap -#define iounmap iounmap - -static inline void iounmap(void __iomem *addr) -{ -} -#endif -#endif /* CONFIG_MMU */ - -#ifdef CONFIG_HAS_IOPORT_MAP -#ifndef CONFIG_GENERIC_IOMAP -#ifndef ioport_map -#define ioport_map ioport_map -static inline void __iomem *ioport_map(unsigned long port, unsigned int nr) -{ - return PCI_IOBASE + (port & IO_SPACE_LIMIT); -} -#endif - -#ifndef ioport_unmap -#define ioport_unmap ioport_unmap -static inline void ioport_unmap(void __iomem *p) -{ -} -#endif -#else /* CONFIG_GENERIC_IOMAP */ -extern void __iomem *ioport_map(unsigned long port, unsigned int nr); -extern void ioport_unmap(void __iomem *p); -#endif /* CONFIG_GENERIC_IOMAP */ -#endif /* CONFIG_HAS_IOPORT_MAP */ - -#ifndef xlate_dev_kmem_ptr -#define xlate_dev_kmem_ptr xlate_dev_kmem_ptr -static inline void *xlate_dev_kmem_ptr(void *addr) -{ - return addr; -} -#endif - -#ifndef xlate_dev_mem_ptr -#define xlate_dev_mem_ptr xlate_dev_mem_ptr -static inline void *xlate_dev_mem_ptr(phys_addr_t addr) -{ - return __va(addr); -} -#endif - -#ifndef unxlate_dev_mem_ptr -#define unxlate_dev_mem_ptr unxlate_dev_mem_ptr -static inline void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr) -{ -} -#endif - -#ifdef CONFIG_VIRT_TO_BUS -#ifndef virt_to_bus -static inline unsigned long virt_to_bus(void *address) -{ - return (unsigned long)address; -} - -static inline void *bus_to_virt(unsigned long address) -{ - return (void *)address; -} -#endif -#endif - -#ifndef memset_io -#define memset_io memset_io -static inline void memset_io(volatile void __iomem *addr, int value, - size_t size) -{ - memset(__io_virt(addr), value, size); -} -#endif - -#ifndef memcpy_fromio -#define memcpy_fromio memcpy_fromio -static inline void memcpy_fromio(void *buffer, - const volatile void __iomem *addr, - size_t size) -{ - memcpy(buffer, __io_virt(addr), size); -} -#endif - -#ifndef memcpy_toio -#define memcpy_toio memcpy_toio -static inline void memcpy_toio(volatile void __iomem *addr, const void *buffer, - size_t size) -{ - memcpy(__io_virt(addr), buffer, size); -} -#endif - -#endif /* __KERNEL__ */ - -#endif /* __ASM_GENERIC_IO_H */ diff --git a/src/linux/include/asm-generic/ioctl.h b/src/linux/include/asm-generic/ioctl.h deleted file mode 100644 index 297fb0d..0000000 --- a/src/linux/include/asm-generic/ioctl.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _ASM_GENERIC_IOCTL_H -#define _ASM_GENERIC_IOCTL_H - -#include - -#ifdef __CHECKER__ -#define _IOC_TYPECHECK(t) (sizeof(t)) -#else -/* provoke compile error for invalid uses of size argument */ -extern unsigned int __invalid_size_argument_for_IOC; -#define _IOC_TYPECHECK(t) \ - ((sizeof(t) == sizeof(t[1]) && \ - sizeof(t) < (1 << _IOC_SIZEBITS)) ? \ - sizeof(t) : __invalid_size_argument_for_IOC) -#endif - -#endif /* _ASM_GENERIC_IOCTL_H */ diff --git a/src/linux/include/asm-generic/irq_regs.h b/src/linux/include/asm-generic/irq_regs.h deleted file mode 100644 index 6bf9355..0000000 --- a/src/linux/include/asm-generic/irq_regs.h +++ /dev/null @@ -1,37 +0,0 @@ -/* Fallback per-CPU frame pointer holder - * - * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _ASM_GENERIC_IRQ_REGS_H -#define _ASM_GENERIC_IRQ_REGS_H - -#include - -/* - * Per-cpu current frame pointer - the location of the last exception frame on - * the stack - */ -DECLARE_PER_CPU(struct pt_regs *, __irq_regs); - -static inline struct pt_regs *get_irq_regs(void) -{ - return __this_cpu_read(__irq_regs); -} - -static inline struct pt_regs *set_irq_regs(struct pt_regs *new_regs) -{ - struct pt_regs *old_regs; - - old_regs = __this_cpu_read(__irq_regs); - __this_cpu_write(__irq_regs, new_regs); - return old_regs; -} - -#endif /* _ASM_GENERIC_IRQ_REGS_H */ diff --git a/src/linux/include/asm-generic/irq_work.h b/src/linux/include/asm-generic/irq_work.h deleted file mode 100644 index a44f452..0000000 --- a/src/linux/include/asm-generic/irq_work.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __ASM_IRQ_WORK_H -#define __ASM_IRQ_WORK_H - -static inline bool arch_irq_work_has_interrupt(void) -{ - return false; -} - -#endif /* __ASM_IRQ_WORK_H */ - diff --git a/src/linux/include/asm-generic/irqflags.h b/src/linux/include/asm-generic/irqflags.h deleted file mode 100644 index 1f40d00..0000000 --- a/src/linux/include/asm-generic/irqflags.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef __ASM_GENERIC_IRQFLAGS_H -#define __ASM_GENERIC_IRQFLAGS_H - -/* - * All architectures should implement at least the first two functions, - * usually inline assembly will be the best way. - */ -#ifndef ARCH_IRQ_DISABLED -#define ARCH_IRQ_DISABLED 0 -#define ARCH_IRQ_ENABLED 1 -#endif - -/* read interrupt enabled status */ -#ifndef arch_local_save_flags -unsigned long arch_local_save_flags(void); -#endif - -/* set interrupt enabled status */ -#ifndef arch_local_irq_restore -void arch_local_irq_restore(unsigned long flags); -#endif - -/* get status and disable interrupts */ -#ifndef arch_local_irq_save -static inline unsigned long arch_local_irq_save(void) -{ - unsigned long flags; - flags = arch_local_save_flags(); - arch_local_irq_restore(ARCH_IRQ_DISABLED); - return flags; -} -#endif - -/* test flags */ -#ifndef arch_irqs_disabled_flags -static inline int arch_irqs_disabled_flags(unsigned long flags) -{ - return flags == ARCH_IRQ_DISABLED; -} -#endif - -/* unconditionally enable interrupts */ -#ifndef arch_local_irq_enable -static inline void arch_local_irq_enable(void) -{ - arch_local_irq_restore(ARCH_IRQ_ENABLED); -} -#endif - -/* unconditionally disable interrupts */ -#ifndef arch_local_irq_disable -static inline void arch_local_irq_disable(void) -{ - arch_local_irq_restore(ARCH_IRQ_DISABLED); -} -#endif - -/* test hardware interrupt enable bit */ -#ifndef arch_irqs_disabled -static inline int arch_irqs_disabled(void) -{ - return arch_irqs_disabled_flags(arch_local_save_flags()); -} -#endif - -#endif /* __ASM_GENERIC_IRQFLAGS_H */ diff --git a/src/linux/include/asm-generic/kdebug.h b/src/linux/include/asm-generic/kdebug.h deleted file mode 100644 index d181449..0000000 --- a/src/linux/include/asm-generic/kdebug.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _ASM_GENERIC_KDEBUG_H -#define _ASM_GENERIC_KDEBUG_H - -enum die_val { - DIE_UNUSED, - DIE_OOPS = 1, -}; - -#endif /* _ASM_GENERIC_KDEBUG_H */ diff --git a/src/linux/include/asm-generic/kmap_types.h b/src/linux/include/asm-generic/kmap_types.h deleted file mode 100644 index 90f99c7..0000000 --- a/src/linux/include/asm-generic/kmap_types.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _ASM_GENERIC_KMAP_TYPES_H -#define _ASM_GENERIC_KMAP_TYPES_H - -#ifdef __WITH_KM_FENCE -# define KM_TYPE_NR 41 -#else -# define KM_TYPE_NR 20 -#endif - -#endif diff --git a/src/linux/include/asm-generic/linkage.h b/src/linux/include/asm-generic/linkage.h deleted file mode 100644 index fef7a01..0000000 --- a/src/linux/include/asm-generic/linkage.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __ASM_GENERIC_LINKAGE_H -#define __ASM_GENERIC_LINKAGE_H -/* - * linux/linkage.h provides reasonable defaults. - * an architecture can override them by providing its own version. - */ - -#endif /* __ASM_GENERIC_LINKAGE_H */ diff --git a/src/linux/include/asm-generic/local.h b/src/linux/include/asm-generic/local.h deleted file mode 100644 index 9ceb03b..0000000 --- a/src/linux/include/asm-generic/local.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef _ASM_GENERIC_LOCAL_H -#define _ASM_GENERIC_LOCAL_H - -#include -#include -#include - -/* - * A signed long type for operations which are atomic for a single CPU. - * Usually used in combination with per-cpu variables. - * - * This is the default implementation, which uses atomic_long_t. Which is - * rather pointless. The whole point behind local_t is that some processors - * can perform atomic adds and subtracts in a manner which is atomic wrt IRQs - * running on this CPU. local_t allows exploitation of such capabilities. - */ - -/* Implement in terms of atomics. */ - -/* Don't use typedef: don't want them to be mixed with atomic_t's. */ -typedef struct -{ - atomic_long_t a; -} local_t; - -#define LOCAL_INIT(i) { ATOMIC_LONG_INIT(i) } - -#define local_read(l) atomic_long_read(&(l)->a) -#define local_set(l,i) atomic_long_set((&(l)->a),(i)) -#define local_inc(l) atomic_long_inc(&(l)->a) -#define local_dec(l) atomic_long_dec(&(l)->a) -#define local_add(i,l) atomic_long_add((i),(&(l)->a)) -#define local_sub(i,l) atomic_long_sub((i),(&(l)->a)) - -#define local_sub_and_test(i, l) atomic_long_sub_and_test((i), (&(l)->a)) -#define local_dec_and_test(l) atomic_long_dec_and_test(&(l)->a) -#define local_inc_and_test(l) atomic_long_inc_and_test(&(l)->a) -#define local_add_negative(i, l) atomic_long_add_negative((i), (&(l)->a)) -#define local_add_return(i, l) atomic_long_add_return((i), (&(l)->a)) -#define local_sub_return(i, l) atomic_long_sub_return((i), (&(l)->a)) -#define local_inc_return(l) atomic_long_inc_return(&(l)->a) - -#define local_cmpxchg(l, o, n) atomic_long_cmpxchg((&(l)->a), (o), (n)) -#define local_xchg(l, n) atomic_long_xchg((&(l)->a), (n)) -#define local_add_unless(l, _a, u) atomic_long_add_unless((&(l)->a), (_a), (u)) -#define local_inc_not_zero(l) atomic_long_inc_not_zero(&(l)->a) - -/* Non-atomic variants, ie. preemption disabled and won't be touched - * in interrupt, etc. Some archs can optimize this case well. */ -#define __local_inc(l) local_set((l), local_read(l) + 1) -#define __local_dec(l) local_set((l), local_read(l) - 1) -#define __local_add(i,l) local_set((l), local_read(l) + (i)) -#define __local_sub(i,l) local_set((l), local_read(l) - (i)) - -#endif /* _ASM_GENERIC_LOCAL_H */ diff --git a/src/linux/include/asm-generic/memory_model.h b/src/linux/include/asm-generic/memory_model.h deleted file mode 100644 index 5148150..0000000 --- a/src/linux/include/asm-generic/memory_model.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef __ASM_MEMORY_MODEL_H -#define __ASM_MEMORY_MODEL_H - -#include - -#ifndef __ASSEMBLY__ - -#if defined(CONFIG_FLATMEM) - -#ifndef ARCH_PFN_OFFSET -#define ARCH_PFN_OFFSET (0UL) -#endif - -#elif defined(CONFIG_DISCONTIGMEM) - -#ifndef arch_pfn_to_nid -#define arch_pfn_to_nid(pfn) pfn_to_nid(pfn) -#endif - -#ifndef arch_local_page_offset -#define arch_local_page_offset(pfn, nid) \ - ((pfn) - NODE_DATA(nid)->node_start_pfn) -#endif - -#endif /* CONFIG_DISCONTIGMEM */ - -/* - * supports 3 memory models. - */ -#if defined(CONFIG_FLATMEM) - -#define __pfn_to_page(pfn) (mem_map + ((pfn) - ARCH_PFN_OFFSET)) -#define __page_to_pfn(page) ((unsigned long)((page) - mem_map) + \ - ARCH_PFN_OFFSET) -#elif defined(CONFIG_DISCONTIGMEM) - -#define __pfn_to_page(pfn) \ -({ unsigned long __pfn = (pfn); \ - unsigned long __nid = arch_pfn_to_nid(__pfn); \ - NODE_DATA(__nid)->node_mem_map + arch_local_page_offset(__pfn, __nid);\ -}) - -#define __page_to_pfn(pg) \ -({ const struct page *__pg = (pg); \ - struct pglist_data *__pgdat = NODE_DATA(page_to_nid(__pg)); \ - (unsigned long)(__pg - __pgdat->node_mem_map) + \ - __pgdat->node_start_pfn; \ -}) - -#elif defined(CONFIG_SPARSEMEM_VMEMMAP) - -/* memmap is virtually contiguous. */ -#define __pfn_to_page(pfn) (vmemmap + (pfn)) -#define __page_to_pfn(page) (unsigned long)((page) - vmemmap) - -#elif defined(CONFIG_SPARSEMEM) -/* - * Note: section's mem_map is encoded to reflect its start_pfn. - * section[i].section_mem_map == mem_map's address - start_pfn; - */ -#define __page_to_pfn(pg) \ -({ const struct page *__pg = (pg); \ - int __sec = page_to_section(__pg); \ - (unsigned long)(__pg - __section_mem_map_addr(__nr_to_section(__sec))); \ -}) - -#define __pfn_to_page(pfn) \ -({ unsigned long __pfn = (pfn); \ - struct mem_section *__sec = __pfn_to_section(__pfn); \ - __section_mem_map_addr(__sec) + __pfn; \ -}) -#endif /* CONFIG_FLATMEM/DISCONTIGMEM/SPARSEMEM */ - -/* - * Convert a physical address to a Page Frame Number and back - */ -#define __phys_to_pfn(paddr) PHYS_PFN(paddr) -#define __pfn_to_phys(pfn) PFN_PHYS(pfn) - -#define page_to_pfn __page_to_pfn -#define pfn_to_page __pfn_to_page - -#endif /* __ASSEMBLY__ */ - -#endif diff --git a/src/linux/include/asm-generic/mm_hooks.h b/src/linux/include/asm-generic/mm_hooks.h deleted file mode 100644 index cc5d9a1..0000000 --- a/src/linux/include/asm-generic/mm_hooks.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Define generic no-op hooks for arch_dup_mmap, arch_exit_mmap - * and arch_unmap to be included in asm-FOO/mmu_context.h for any - * arch FOO which doesn't need to hook these. - */ -#ifndef _ASM_GENERIC_MM_HOOKS_H -#define _ASM_GENERIC_MM_HOOKS_H - -static inline void arch_dup_mmap(struct mm_struct *oldmm, - struct mm_struct *mm) -{ -} - -static inline void arch_exit_mmap(struct mm_struct *mm) -{ -} - -static inline void arch_unmap(struct mm_struct *mm, - struct vm_area_struct *vma, - unsigned long start, unsigned long end) -{ -} - -static inline void arch_bprm_mm_init(struct mm_struct *mm, - struct vm_area_struct *vma) -{ -} - -static inline bool arch_vma_access_permitted(struct vm_area_struct *vma, - bool write, bool execute, bool foreign) -{ - /* by default, allow everything */ - return true; -} - -static inline bool arch_pte_access_permitted(pte_t pte, bool write) -{ - /* by default, allow everything */ - return true; -} -#endif /* _ASM_GENERIC_MM_HOOKS_H */ diff --git a/src/linux/include/asm-generic/mmu.h b/src/linux/include/asm-generic/mmu.h deleted file mode 100644 index 0ed3f1c..0000000 --- a/src/linux/include/asm-generic/mmu.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef __ASM_GENERIC_MMU_H -#define __ASM_GENERIC_MMU_H - -/* - * This is the mmu.h header for nommu implementations. - * Architectures with an MMU need something more complex. - */ -#ifndef __ASSEMBLY__ -typedef struct { - unsigned long end_brk; - -#ifdef CONFIG_BINFMT_ELF_FDPIC - unsigned long exec_fdpic_loadmap; - unsigned long interp_fdpic_loadmap; -#endif -} mm_context_t; -#endif - -#endif /* __ASM_GENERIC_MMU_H */ diff --git a/src/linux/include/asm-generic/mmu_context.h b/src/linux/include/asm-generic/mmu_context.h deleted file mode 100644 index a7eec91..0000000 --- a/src/linux/include/asm-generic/mmu_context.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef __ASM_GENERIC_MMU_CONTEXT_H -#define __ASM_GENERIC_MMU_CONTEXT_H - -/* - * Generic hooks for NOMMU architectures, which do not need to do - * anything special here. - */ - -#include - -struct task_struct; -struct mm_struct; - -static inline void enter_lazy_tlb(struct mm_struct *mm, - struct task_struct *tsk) -{ -} - -static inline int init_new_context(struct task_struct *tsk, - struct mm_struct *mm) -{ - return 0; -} - -static inline void destroy_context(struct mm_struct *mm) -{ -} - -static inline void deactivate_mm(struct task_struct *task, - struct mm_struct *mm) -{ -} - -static inline void switch_mm(struct mm_struct *prev, - struct mm_struct *next, - struct task_struct *tsk) -{ -} - -static inline void activate_mm(struct mm_struct *prev_mm, - struct mm_struct *next_mm) -{ -} - -#endif /* __ASM_GENERIC_MMU_CONTEXT_H */ diff --git a/src/linux/include/asm-generic/module.h b/src/linux/include/asm-generic/module.h deleted file mode 100644 index 14dc41d..0000000 --- a/src/linux/include/asm-generic/module.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef __ASM_GENERIC_MODULE_H -#define __ASM_GENERIC_MODULE_H - -/* - * Many architectures just need a simple module - * loader without arch specific data. - */ -#ifndef CONFIG_HAVE_MOD_ARCH_SPECIFIC -struct mod_arch_specific -{ -}; -#endif - -#ifdef CONFIG_64BIT -#define Elf_Shdr Elf64_Shdr -#define Elf_Phdr Elf64_Phdr -#define Elf_Sym Elf64_Sym -#define Elf_Dyn Elf64_Dyn -#define Elf_Ehdr Elf64_Ehdr -#define Elf_Addr Elf64_Addr -#ifdef CONFIG_MODULES_USE_ELF_REL -#define Elf_Rel Elf64_Rel -#endif -#ifdef CONFIG_MODULES_USE_ELF_RELA -#define Elf_Rela Elf64_Rela -#endif -#define ELF_R_TYPE(X) ELF64_R_TYPE(X) -#define ELF_R_SYM(X) ELF64_R_SYM(X) - -#else /* CONFIG_64BIT */ - -#define Elf_Shdr Elf32_Shdr -#define Elf_Phdr Elf32_Phdr -#define Elf_Sym Elf32_Sym -#define Elf_Dyn Elf32_Dyn -#define Elf_Ehdr Elf32_Ehdr -#define Elf_Addr Elf32_Addr -#ifdef CONFIG_MODULES_USE_ELF_REL -#define Elf_Rel Elf32_Rel -#endif -#ifdef CONFIG_MODULES_USE_ELF_RELA -#define Elf_Rela Elf32_Rela -#endif -#define ELF_R_TYPE(X) ELF32_R_TYPE(X) -#define ELF_R_SYM(X) ELF32_R_SYM(X) -#endif - -#endif /* __ASM_GENERIC_MODULE_H */ diff --git a/src/linux/include/asm-generic/mutex-dec.h b/src/linux/include/asm-generic/mutex-dec.h deleted file mode 100644 index c54829d..0000000 --- a/src/linux/include/asm-generic/mutex-dec.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * include/asm-generic/mutex-dec.h - * - * Generic implementation of the mutex fastpath, based on atomic - * decrement/increment. - */ -#ifndef _ASM_GENERIC_MUTEX_DEC_H -#define _ASM_GENERIC_MUTEX_DEC_H - -/** - * __mutex_fastpath_lock - try to take the lock by moving the count - * from 1 to a 0 value - * @count: pointer of type atomic_t - * @fail_fn: function to call if the original value was not 1 - * - * Change the count from 1 to a value lower than 1, and call if - * it wasn't 1 originally. This function MUST leave the value lower than - * 1 even when the "1" assertion wasn't true. - */ -static inline void -__mutex_fastpath_lock(atomic_t *count, void (*fail_fn)(atomic_t *)) -{ - if (unlikely(atomic_dec_return_acquire(count) < 0)) - fail_fn(count); -} - -/** - * __mutex_fastpath_lock_retval - try to take the lock by moving the count - * from 1 to a 0 value - * @count: pointer of type atomic_t - * - * Change the count from 1 to a value lower than 1. This function returns 0 - * if the fastpath succeeds, or -1 otherwise. - */ -static inline int -__mutex_fastpath_lock_retval(atomic_t *count) -{ - if (unlikely(atomic_dec_return_acquire(count) < 0)) - return -1; - return 0; -} - -/** - * __mutex_fastpath_unlock - try to promote the count from 0 to 1 - * @count: pointer of type atomic_t - * @fail_fn: function to call if the original value was not 0 - * - * Try to promote the count from 0 to 1. If it wasn't 0, call . - * In the failure case, this function is allowed to either set the value to - * 1, or to set it to a value lower than 1. - * - * If the implementation sets it to a value of lower than 1, then the - * __mutex_slowpath_needs_to_unlock() macro needs to return 1, it needs - * to return 0 otherwise. - */ -static inline void -__mutex_fastpath_unlock(atomic_t *count, void (*fail_fn)(atomic_t *)) -{ - if (unlikely(atomic_inc_return_release(count) <= 0)) - fail_fn(count); -} - -#define __mutex_slowpath_needs_to_unlock() 1 - -/** - * __mutex_fastpath_trylock - try to acquire the mutex, without waiting - * - * @count: pointer of type atomic_t - * @fail_fn: fallback function - * - * Change the count from 1 to a value lower than 1, and return 0 (failure) - * if it wasn't 1 originally, or return 1 (success) otherwise. This function - * MUST leave the value lower than 1 even when the "1" assertion wasn't true. - * Additionally, if the value was < 0 originally, this function must not leave - * it to 0 on failure. - * - * If the architecture has no effective trylock variant, it should call the - * spinlock-based trylock variant unconditionally. - */ -static inline int -__mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) -{ - if (likely(atomic_read(count) == 1 && atomic_cmpxchg_acquire(count, 1, 0) == 1)) - return 1; - return 0; -} - -#endif diff --git a/src/linux/include/asm-generic/page.h b/src/linux/include/asm-generic/page.h deleted file mode 100644 index 67cfb7d..0000000 --- a/src/linux/include/asm-generic/page.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef __ASM_GENERIC_PAGE_H -#define __ASM_GENERIC_PAGE_H -/* - * Generic page.h implementation, for NOMMU architectures. - * This provides the dummy definitions for the memory management. - */ - -#ifdef CONFIG_MMU -#error need to prove a real asm/page.h -#endif - - -/* PAGE_SHIFT determines the page size */ - -#define PAGE_SHIFT 12 -#ifdef __ASSEMBLY__ -#define PAGE_SIZE (1 << PAGE_SHIFT) -#else -#define PAGE_SIZE (1UL << PAGE_SHIFT) -#endif -#define PAGE_MASK (~(PAGE_SIZE-1)) - -#include - -#ifndef __ASSEMBLY__ - -#define clear_page(page) memset((page), 0, PAGE_SIZE) -#define copy_page(to,from) memcpy((to), (from), PAGE_SIZE) - -#define clear_user_page(page, vaddr, pg) clear_page(page) -#define copy_user_page(to, from, vaddr, pg) copy_page(to, from) - -/* - * These are used to make use of C type-checking.. - */ -typedef struct { - unsigned long pte; -} pte_t; -typedef struct { - unsigned long pmd[16]; -} pmd_t; -typedef struct { - unsigned long pgd; -} pgd_t; -typedef struct { - unsigned long pgprot; -} pgprot_t; -typedef struct page *pgtable_t; - -#define pte_val(x) ((x).pte) -#define pmd_val(x) ((&x)->pmd[0]) -#define pgd_val(x) ((x).pgd) -#define pgprot_val(x) ((x).pgprot) - -#define __pte(x) ((pte_t) { (x) } ) -#define __pmd(x) ((pmd_t) { (x) } ) -#define __pgd(x) ((pgd_t) { (x) } ) -#define __pgprot(x) ((pgprot_t) { (x) } ) - -extern unsigned long memory_start; -extern unsigned long memory_end; - -#endif /* !__ASSEMBLY__ */ - -#ifdef CONFIG_KERNEL_RAM_BASE_ADDRESS -#define PAGE_OFFSET (CONFIG_KERNEL_RAM_BASE_ADDRESS) -#else -#define PAGE_OFFSET (0) -#endif - -#ifndef ARCH_PFN_OFFSET -#define ARCH_PFN_OFFSET (PAGE_OFFSET >> PAGE_SHIFT) -#endif - -#ifndef __ASSEMBLY__ - -#define __va(x) ((void *)((unsigned long) (x))) -#define __pa(x) ((unsigned long) (x)) - -#define virt_to_pfn(kaddr) (__pa(kaddr) >> PAGE_SHIFT) -#define pfn_to_virt(pfn) __va((pfn) << PAGE_SHIFT) - -#define virt_to_page(addr) pfn_to_page(virt_to_pfn(addr)) -#define page_to_virt(page) pfn_to_virt(page_to_pfn(page)) - -#ifndef page_to_phys -#define page_to_phys(page) ((dma_addr_t)page_to_pfn(page) << PAGE_SHIFT) -#endif - -#define pfn_valid(pfn) ((pfn) >= ARCH_PFN_OFFSET && ((pfn) - ARCH_PFN_OFFSET) < max_mapnr) - -#define virt_addr_valid(kaddr) (((void *)(kaddr) >= (void *)PAGE_OFFSET) && \ - ((void *)(kaddr) < (void *)memory_end)) - -#endif /* __ASSEMBLY__ */ - -#include -#include - -#endif /* __ASM_GENERIC_PAGE_H */ diff --git a/src/linux/include/asm-generic/param.h b/src/linux/include/asm-generic/param.h deleted file mode 100644 index 04e715b..0000000 --- a/src/linux/include/asm-generic/param.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __ASM_GENERIC_PARAM_H -#define __ASM_GENERIC_PARAM_H - -#include - -# undef HZ -# define HZ CONFIG_HZ /* Internal kernel timer frequency */ -# define USER_HZ 100 /* some user interfaces are */ -# define CLOCKS_PER_SEC (USER_HZ) /* in "ticks" like times() */ -#endif /* __ASM_GENERIC_PARAM_H */ diff --git a/src/linux/include/asm-generic/pci.h b/src/linux/include/asm-generic/pci.h deleted file mode 100644 index f24bc51..0000000 --- a/src/linux/include/asm-generic/pci.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * linux/include/asm-generic/pci.h - * - * Copyright (C) 2003 Russell King - */ -#ifndef _ASM_GENERIC_PCI_H -#define _ASM_GENERIC_PCI_H - -#ifndef HAVE_ARCH_PCI_GET_LEGACY_IDE_IRQ -static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel) -{ - return channel ? 15 : 14; -} -#endif /* HAVE_ARCH_PCI_GET_LEGACY_IDE_IRQ */ - -/* - * By default, assume that no iommu is in use and that the PCI - * space is mapped to address physical 0. - */ -#ifndef PCI_DMA_BUS_IS_PHYS -#define PCI_DMA_BUS_IS_PHYS (1) -#endif - -#endif /* _ASM_GENERIC_PCI_H */ diff --git a/src/linux/include/asm-generic/pci_iomap.h b/src/linux/include/asm-generic/pci_iomap.h deleted file mode 100644 index b1e17fc..0000000 --- a/src/linux/include/asm-generic/pci_iomap.h +++ /dev/null @@ -1,59 +0,0 @@ -/* Generic I/O port emulation, based on MN10300 code - * - * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ -#ifndef __ASM_GENERIC_PCI_IOMAP_H -#define __ASM_GENERIC_PCI_IOMAP_H - -struct pci_dev; -#ifdef CONFIG_PCI -/* Create a virtual mapping cookie for a PCI BAR (memory or IO) */ -extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max); -extern void __iomem *pci_iomap_wc(struct pci_dev *dev, int bar, unsigned long max); -extern void __iomem *pci_iomap_range(struct pci_dev *dev, int bar, - unsigned long offset, - unsigned long maxlen); -extern void __iomem *pci_iomap_wc_range(struct pci_dev *dev, int bar, - unsigned long offset, - unsigned long maxlen); -/* Create a virtual mapping cookie for a port on a given PCI device. - * Do not call this directly, it exists to make it easier for architectures - * to override */ -#ifdef CONFIG_NO_GENERIC_PCI_IOPORT_MAP -extern void __iomem *__pci_ioport_map(struct pci_dev *dev, unsigned long port, - unsigned int nr); -#else -#define __pci_ioport_map(dev, port, nr) ioport_map((port), (nr)) -#endif - -#elif defined(CONFIG_GENERIC_PCI_IOMAP) -static inline void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max) -{ - return NULL; -} - -static inline void __iomem *pci_iomap_wc(struct pci_dev *dev, int bar, unsigned long max) -{ - return NULL; -} -static inline void __iomem *pci_iomap_range(struct pci_dev *dev, int bar, - unsigned long offset, - unsigned long maxlen) -{ - return NULL; -} -static inline void __iomem *pci_iomap_wc_range(struct pci_dev *dev, int bar, - unsigned long offset, - unsigned long maxlen) -{ - return NULL; -} -#endif - -#endif /* __ASM_GENERIC_IO_H */ diff --git a/src/linux/include/asm-generic/percpu.h b/src/linux/include/asm-generic/percpu.h deleted file mode 100644 index 0504ef8..0000000 --- a/src/linux/include/asm-generic/percpu.h +++ /dev/null @@ -1,427 +0,0 @@ -#ifndef _ASM_GENERIC_PERCPU_H_ -#define _ASM_GENERIC_PERCPU_H_ - -#include -#include -#include - -#ifdef CONFIG_SMP - -/* - * per_cpu_offset() is the offset that has to be added to a - * percpu variable to get to the instance for a certain processor. - * - * Most arches use the __per_cpu_offset array for those offsets but - * some arches have their own ways of determining the offset (x86_64, s390). - */ -#ifndef __per_cpu_offset -extern unsigned long __per_cpu_offset[NR_CPUS]; - -#define per_cpu_offset(x) (__per_cpu_offset[x]) -#endif - -/* - * Determine the offset for the currently active processor. - * An arch may define __my_cpu_offset to provide a more effective - * means of obtaining the offset to the per cpu variables of the - * current processor. - */ -#ifndef __my_cpu_offset -#define __my_cpu_offset per_cpu_offset(raw_smp_processor_id()) -#endif -#ifdef CONFIG_DEBUG_PREEMPT -#define my_cpu_offset per_cpu_offset(smp_processor_id()) -#else -#define my_cpu_offset __my_cpu_offset -#endif - -/* - * Arch may define arch_raw_cpu_ptr() to provide more efficient address - * translations for raw_cpu_ptr(). - */ -#ifndef arch_raw_cpu_ptr -#define arch_raw_cpu_ptr(ptr) SHIFT_PERCPU_PTR(ptr, __my_cpu_offset) -#endif - -#ifdef CONFIG_HAVE_SETUP_PER_CPU_AREA -extern void setup_per_cpu_areas(void); -#endif - -#endif /* SMP */ - -#ifndef PER_CPU_BASE_SECTION -#ifdef CONFIG_SMP -#define PER_CPU_BASE_SECTION ".data..percpu" -#else -#define PER_CPU_BASE_SECTION ".data" -#endif -#endif - -#ifndef PER_CPU_ATTRIBUTES -#define PER_CPU_ATTRIBUTES -#endif - -#ifndef PER_CPU_DEF_ATTRIBUTES -#define PER_CPU_DEF_ATTRIBUTES -#endif - -#define raw_cpu_generic_read(pcp) \ -({ \ - *raw_cpu_ptr(&(pcp)); \ -}) - -#define raw_cpu_generic_to_op(pcp, val, op) \ -do { \ - *raw_cpu_ptr(&(pcp)) op val; \ -} while (0) - -#define raw_cpu_generic_add_return(pcp, val) \ -({ \ - typeof(&(pcp)) __p = raw_cpu_ptr(&(pcp)); \ - \ - *__p += val; \ - *__p; \ -}) - -#define raw_cpu_generic_xchg(pcp, nval) \ -({ \ - typeof(&(pcp)) __p = raw_cpu_ptr(&(pcp)); \ - typeof(pcp) __ret; \ - __ret = *__p; \ - *__p = nval; \ - __ret; \ -}) - -#define raw_cpu_generic_cmpxchg(pcp, oval, nval) \ -({ \ - typeof(&(pcp)) __p = raw_cpu_ptr(&(pcp)); \ - typeof(pcp) __ret; \ - __ret = *__p; \ - if (__ret == (oval)) \ - *__p = nval; \ - __ret; \ -}) - -#define raw_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) \ -({ \ - typeof(&(pcp1)) __p1 = raw_cpu_ptr(&(pcp1)); \ - typeof(&(pcp2)) __p2 = raw_cpu_ptr(&(pcp2)); \ - int __ret = 0; \ - if (*__p1 == (oval1) && *__p2 == (oval2)) { \ - *__p1 = nval1; \ - *__p2 = nval2; \ - __ret = 1; \ - } \ - (__ret); \ -}) - -#define this_cpu_generic_read(pcp) \ -({ \ - typeof(pcp) __ret; \ - preempt_disable_notrace(); \ - __ret = raw_cpu_generic_read(pcp); \ - preempt_enable_notrace(); \ - __ret; \ -}) - -#define this_cpu_generic_to_op(pcp, val, op) \ -do { \ - unsigned long __flags; \ - raw_local_irq_save(__flags); \ - raw_cpu_generic_to_op(pcp, val, op); \ - raw_local_irq_restore(__flags); \ -} while (0) - - -#define this_cpu_generic_add_return(pcp, val) \ -({ \ - typeof(pcp) __ret; \ - unsigned long __flags; \ - raw_local_irq_save(__flags); \ - __ret = raw_cpu_generic_add_return(pcp, val); \ - raw_local_irq_restore(__flags); \ - __ret; \ -}) - -#define this_cpu_generic_xchg(pcp, nval) \ -({ \ - typeof(pcp) __ret; \ - unsigned long __flags; \ - raw_local_irq_save(__flags); \ - __ret = raw_cpu_generic_xchg(pcp, nval); \ - raw_local_irq_restore(__flags); \ - __ret; \ -}) - -#define this_cpu_generic_cmpxchg(pcp, oval, nval) \ -({ \ - typeof(pcp) __ret; \ - unsigned long __flags; \ - raw_local_irq_save(__flags); \ - __ret = raw_cpu_generic_cmpxchg(pcp, oval, nval); \ - raw_local_irq_restore(__flags); \ - __ret; \ -}) - -#define this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) \ -({ \ - int __ret; \ - unsigned long __flags; \ - raw_local_irq_save(__flags); \ - __ret = raw_cpu_generic_cmpxchg_double(pcp1, pcp2, \ - oval1, oval2, nval1, nval2); \ - raw_local_irq_restore(__flags); \ - __ret; \ -}) - -#ifndef raw_cpu_read_1 -#define raw_cpu_read_1(pcp) raw_cpu_generic_read(pcp) -#endif -#ifndef raw_cpu_read_2 -#define raw_cpu_read_2(pcp) raw_cpu_generic_read(pcp) -#endif -#ifndef raw_cpu_read_4 -#define raw_cpu_read_4(pcp) raw_cpu_generic_read(pcp) -#endif -#ifndef raw_cpu_read_8 -#define raw_cpu_read_8(pcp) raw_cpu_generic_read(pcp) -#endif - -#ifndef raw_cpu_write_1 -#define raw_cpu_write_1(pcp, val) raw_cpu_generic_to_op(pcp, val, =) -#endif -#ifndef raw_cpu_write_2 -#define raw_cpu_write_2(pcp, val) raw_cpu_generic_to_op(pcp, val, =) -#endif -#ifndef raw_cpu_write_4 -#define raw_cpu_write_4(pcp, val) raw_cpu_generic_to_op(pcp, val, =) -#endif -#ifndef raw_cpu_write_8 -#define raw_cpu_write_8(pcp, val) raw_cpu_generic_to_op(pcp, val, =) -#endif - -#ifndef raw_cpu_add_1 -#define raw_cpu_add_1(pcp, val) raw_cpu_generic_to_op(pcp, val, +=) -#endif -#ifndef raw_cpu_add_2 -#define raw_cpu_add_2(pcp, val) raw_cpu_generic_to_op(pcp, val, +=) -#endif -#ifndef raw_cpu_add_4 -#define raw_cpu_add_4(pcp, val) raw_cpu_generic_to_op(pcp, val, +=) -#endif -#ifndef raw_cpu_add_8 -#define raw_cpu_add_8(pcp, val) raw_cpu_generic_to_op(pcp, val, +=) -#endif - -#ifndef raw_cpu_and_1 -#define raw_cpu_and_1(pcp, val) raw_cpu_generic_to_op(pcp, val, &=) -#endif -#ifndef raw_cpu_and_2 -#define raw_cpu_and_2(pcp, val) raw_cpu_generic_to_op(pcp, val, &=) -#endif -#ifndef raw_cpu_and_4 -#define raw_cpu_and_4(pcp, val) raw_cpu_generic_to_op(pcp, val, &=) -#endif -#ifndef raw_cpu_and_8 -#define raw_cpu_and_8(pcp, val) raw_cpu_generic_to_op(pcp, val, &=) -#endif - -#ifndef raw_cpu_or_1 -#define raw_cpu_or_1(pcp, val) raw_cpu_generic_to_op(pcp, val, |=) -#endif -#ifndef raw_cpu_or_2 -#define raw_cpu_or_2(pcp, val) raw_cpu_generic_to_op(pcp, val, |=) -#endif -#ifndef raw_cpu_or_4 -#define raw_cpu_or_4(pcp, val) raw_cpu_generic_to_op(pcp, val, |=) -#endif -#ifndef raw_cpu_or_8 -#define raw_cpu_or_8(pcp, val) raw_cpu_generic_to_op(pcp, val, |=) -#endif - -#ifndef raw_cpu_add_return_1 -#define raw_cpu_add_return_1(pcp, val) raw_cpu_generic_add_return(pcp, val) -#endif -#ifndef raw_cpu_add_return_2 -#define raw_cpu_add_return_2(pcp, val) raw_cpu_generic_add_return(pcp, val) -#endif -#ifndef raw_cpu_add_return_4 -#define raw_cpu_add_return_4(pcp, val) raw_cpu_generic_add_return(pcp, val) -#endif -#ifndef raw_cpu_add_return_8 -#define raw_cpu_add_return_8(pcp, val) raw_cpu_generic_add_return(pcp, val) -#endif - -#ifndef raw_cpu_xchg_1 -#define raw_cpu_xchg_1(pcp, nval) raw_cpu_generic_xchg(pcp, nval) -#endif -#ifndef raw_cpu_xchg_2 -#define raw_cpu_xchg_2(pcp, nval) raw_cpu_generic_xchg(pcp, nval) -#endif -#ifndef raw_cpu_xchg_4 -#define raw_cpu_xchg_4(pcp, nval) raw_cpu_generic_xchg(pcp, nval) -#endif -#ifndef raw_cpu_xchg_8 -#define raw_cpu_xchg_8(pcp, nval) raw_cpu_generic_xchg(pcp, nval) -#endif - -#ifndef raw_cpu_cmpxchg_1 -#define raw_cpu_cmpxchg_1(pcp, oval, nval) \ - raw_cpu_generic_cmpxchg(pcp, oval, nval) -#endif -#ifndef raw_cpu_cmpxchg_2 -#define raw_cpu_cmpxchg_2(pcp, oval, nval) \ - raw_cpu_generic_cmpxchg(pcp, oval, nval) -#endif -#ifndef raw_cpu_cmpxchg_4 -#define raw_cpu_cmpxchg_4(pcp, oval, nval) \ - raw_cpu_generic_cmpxchg(pcp, oval, nval) -#endif -#ifndef raw_cpu_cmpxchg_8 -#define raw_cpu_cmpxchg_8(pcp, oval, nval) \ - raw_cpu_generic_cmpxchg(pcp, oval, nval) -#endif - -#ifndef raw_cpu_cmpxchg_double_1 -#define raw_cpu_cmpxchg_double_1(pcp1, pcp2, oval1, oval2, nval1, nval2) \ - raw_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) -#endif -#ifndef raw_cpu_cmpxchg_double_2 -#define raw_cpu_cmpxchg_double_2(pcp1, pcp2, oval1, oval2, nval1, nval2) \ - raw_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) -#endif -#ifndef raw_cpu_cmpxchg_double_4 -#define raw_cpu_cmpxchg_double_4(pcp1, pcp2, oval1, oval2, nval1, nval2) \ - raw_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) -#endif -#ifndef raw_cpu_cmpxchg_double_8 -#define raw_cpu_cmpxchg_double_8(pcp1, pcp2, oval1, oval2, nval1, nval2) \ - raw_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) -#endif - -#ifndef this_cpu_read_1 -#define this_cpu_read_1(pcp) this_cpu_generic_read(pcp) -#endif -#ifndef this_cpu_read_2 -#define this_cpu_read_2(pcp) this_cpu_generic_read(pcp) -#endif -#ifndef this_cpu_read_4 -#define this_cpu_read_4(pcp) this_cpu_generic_read(pcp) -#endif -#ifndef this_cpu_read_8 -#define this_cpu_read_8(pcp) this_cpu_generic_read(pcp) -#endif - -#ifndef this_cpu_write_1 -#define this_cpu_write_1(pcp, val) this_cpu_generic_to_op(pcp, val, =) -#endif -#ifndef this_cpu_write_2 -#define this_cpu_write_2(pcp, val) this_cpu_generic_to_op(pcp, val, =) -#endif -#ifndef this_cpu_write_4 -#define this_cpu_write_4(pcp, val) this_cpu_generic_to_op(pcp, val, =) -#endif -#ifndef this_cpu_write_8 -#define this_cpu_write_8(pcp, val) this_cpu_generic_to_op(pcp, val, =) -#endif - -#ifndef this_cpu_add_1 -#define this_cpu_add_1(pcp, val) this_cpu_generic_to_op(pcp, val, +=) -#endif -#ifndef this_cpu_add_2 -#define this_cpu_add_2(pcp, val) this_cpu_generic_to_op(pcp, val, +=) -#endif -#ifndef this_cpu_add_4 -#define this_cpu_add_4(pcp, val) this_cpu_generic_to_op(pcp, val, +=) -#endif -#ifndef this_cpu_add_8 -#define this_cpu_add_8(pcp, val) this_cpu_generic_to_op(pcp, val, +=) -#endif - -#ifndef this_cpu_and_1 -#define this_cpu_and_1(pcp, val) this_cpu_generic_to_op(pcp, val, &=) -#endif -#ifndef this_cpu_and_2 -#define this_cpu_and_2(pcp, val) this_cpu_generic_to_op(pcp, val, &=) -#endif -#ifndef this_cpu_and_4 -#define this_cpu_and_4(pcp, val) this_cpu_generic_to_op(pcp, val, &=) -#endif -#ifndef this_cpu_and_8 -#define this_cpu_and_8(pcp, val) this_cpu_generic_to_op(pcp, val, &=) -#endif - -#ifndef this_cpu_or_1 -#define this_cpu_or_1(pcp, val) this_cpu_generic_to_op(pcp, val, |=) -#endif -#ifndef this_cpu_or_2 -#define this_cpu_or_2(pcp, val) this_cpu_generic_to_op(pcp, val, |=) -#endif -#ifndef this_cpu_or_4 -#define this_cpu_or_4(pcp, val) this_cpu_generic_to_op(pcp, val, |=) -#endif -#ifndef this_cpu_or_8 -#define this_cpu_or_8(pcp, val) this_cpu_generic_to_op(pcp, val, |=) -#endif - -#ifndef this_cpu_add_return_1 -#define this_cpu_add_return_1(pcp, val) this_cpu_generic_add_return(pcp, val) -#endif -#ifndef this_cpu_add_return_2 -#define this_cpu_add_return_2(pcp, val) this_cpu_generic_add_return(pcp, val) -#endif -#ifndef this_cpu_add_return_4 -#define this_cpu_add_return_4(pcp, val) this_cpu_generic_add_return(pcp, val) -#endif -#ifndef this_cpu_add_return_8 -#define this_cpu_add_return_8(pcp, val) this_cpu_generic_add_return(pcp, val) -#endif - -#ifndef this_cpu_xchg_1 -#define this_cpu_xchg_1(pcp, nval) this_cpu_generic_xchg(pcp, nval) -#endif -#ifndef this_cpu_xchg_2 -#define this_cpu_xchg_2(pcp, nval) this_cpu_generic_xchg(pcp, nval) -#endif -#ifndef this_cpu_xchg_4 -#define this_cpu_xchg_4(pcp, nval) this_cpu_generic_xchg(pcp, nval) -#endif -#ifndef this_cpu_xchg_8 -#define this_cpu_xchg_8(pcp, nval) this_cpu_generic_xchg(pcp, nval) -#endif - -#ifndef this_cpu_cmpxchg_1 -#define this_cpu_cmpxchg_1(pcp, oval, nval) \ - this_cpu_generic_cmpxchg(pcp, oval, nval) -#endif -#ifndef this_cpu_cmpxchg_2 -#define this_cpu_cmpxchg_2(pcp, oval, nval) \ - this_cpu_generic_cmpxchg(pcp, oval, nval) -#endif -#ifndef this_cpu_cmpxchg_4 -#define this_cpu_cmpxchg_4(pcp, oval, nval) \ - this_cpu_generic_cmpxchg(pcp, oval, nval) -#endif -#ifndef this_cpu_cmpxchg_8 -#define this_cpu_cmpxchg_8(pcp, oval, nval) \ - this_cpu_generic_cmpxchg(pcp, oval, nval) -#endif - -#ifndef this_cpu_cmpxchg_double_1 -#define this_cpu_cmpxchg_double_1(pcp1, pcp2, oval1, oval2, nval1, nval2) \ - this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) -#endif -#ifndef this_cpu_cmpxchg_double_2 -#define this_cpu_cmpxchg_double_2(pcp1, pcp2, oval1, oval2, nval1, nval2) \ - this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) -#endif -#ifndef this_cpu_cmpxchg_double_4 -#define this_cpu_cmpxchg_double_4(pcp1, pcp2, oval1, oval2, nval1, nval2) \ - this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) -#endif -#ifndef this_cpu_cmpxchg_double_8 -#define this_cpu_cmpxchg_double_8(pcp1, pcp2, oval1, oval2, nval1, nval2) \ - this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) -#endif - -#endif /* _ASM_GENERIC_PERCPU_H_ */ diff --git a/src/linux/include/asm-generic/pgalloc.h b/src/linux/include/asm-generic/pgalloc.h deleted file mode 100644 index 9e429d0..0000000 --- a/src/linux/include/asm-generic/pgalloc.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __ASM_GENERIC_PGALLOC_H -#define __ASM_GENERIC_PGALLOC_H -/* - * an empty file is enough for a nommu architecture - */ -#ifdef CONFIG_MMU -#error need to implement an architecture specific asm/pgalloc.h -#endif - -#define check_pgt_cache() do { } while (0) - -#endif /* __ASM_GENERIC_PGALLOC_H */ diff --git a/src/linux/include/asm-generic/pgtable.h b/src/linux/include/asm-generic/pgtable.h deleted file mode 100644 index c4f8fd2..0000000 --- a/src/linux/include/asm-generic/pgtable.h +++ /dev/null @@ -1,820 +0,0 @@ -#ifndef _ASM_GENERIC_PGTABLE_H -#define _ASM_GENERIC_PGTABLE_H - -#include - -#ifndef __ASSEMBLY__ -#ifdef CONFIG_MMU - -#include -#include -#include - -#if 4 - defined(__PAGETABLE_PUD_FOLDED) - defined(__PAGETABLE_PMD_FOLDED) != \ - CONFIG_PGTABLE_LEVELS -#error CONFIG_PGTABLE_LEVELS is not consistent with __PAGETABLE_{PUD,PMD}_FOLDED -#endif - -/* - * On almost all architectures and configurations, 0 can be used as the - * upper ceiling to free_pgtables(): on many architectures it has the same - * effect as using TASK_SIZE. However, there is one configuration which - * must impose a more careful limit, to avoid freeing kernel pgtables. - */ -#ifndef USER_PGTABLES_CEILING -#define USER_PGTABLES_CEILING 0UL -#endif - -#ifndef __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS -extern int ptep_set_access_flags(struct vm_area_struct *vma, - unsigned long address, pte_t *ptep, - pte_t entry, int dirty); -#endif - -#ifndef __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -extern int pmdp_set_access_flags(struct vm_area_struct *vma, - unsigned long address, pmd_t *pmdp, - pmd_t entry, int dirty); -#else -static inline int pmdp_set_access_flags(struct vm_area_struct *vma, - unsigned long address, pmd_t *pmdp, - pmd_t entry, int dirty) -{ - BUILD_BUG(); - return 0; -} -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ -#endif - -#ifndef __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG -static inline int ptep_test_and_clear_young(struct vm_area_struct *vma, - unsigned long address, - pte_t *ptep) -{ - pte_t pte = *ptep; - int r = 1; - if (!pte_young(pte)) - r = 0; - else - set_pte_at(vma->vm_mm, address, ptep, pte_mkold(pte)); - return r; -} -#endif - -#ifndef __HAVE_ARCH_PMDP_TEST_AND_CLEAR_YOUNG -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, - unsigned long address, - pmd_t *pmdp) -{ - pmd_t pmd = *pmdp; - int r = 1; - if (!pmd_young(pmd)) - r = 0; - else - set_pmd_at(vma->vm_mm, address, pmdp, pmd_mkold(pmd)); - return r; -} -#else -static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma, - unsigned long address, - pmd_t *pmdp) -{ - BUILD_BUG(); - return 0; -} -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ -#endif - -#ifndef __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH -int ptep_clear_flush_young(struct vm_area_struct *vma, - unsigned long address, pte_t *ptep); -#endif - -#ifndef __HAVE_ARCH_PMDP_CLEAR_YOUNG_FLUSH -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -extern int pmdp_clear_flush_young(struct vm_area_struct *vma, - unsigned long address, pmd_t *pmdp); -#else -/* - * Despite relevant to THP only, this API is called from generic rmap code - * under PageTransHuge(), hence needs a dummy implementation for !THP - */ -static inline int pmdp_clear_flush_young(struct vm_area_struct *vma, - unsigned long address, pmd_t *pmdp) -{ - BUILD_BUG(); - return 0; -} -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ -#endif - -#ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR -static inline pte_t ptep_get_and_clear(struct mm_struct *mm, - unsigned long address, - pte_t *ptep) -{ - pte_t pte = *ptep; - pte_clear(mm, address, ptep); - return pte; -} -#endif - -#ifndef __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -static inline pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm, - unsigned long address, - pmd_t *pmdp) -{ - pmd_t pmd = *pmdp; - pmd_clear(pmdp); - return pmd; -} -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ -#endif - -#ifndef __HAVE_ARCH_PMDP_HUGE_GET_AND_CLEAR_FULL -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -static inline pmd_t pmdp_huge_get_and_clear_full(struct mm_struct *mm, - unsigned long address, pmd_t *pmdp, - int full) -{ - return pmdp_huge_get_and_clear(mm, address, pmdp); -} -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ -#endif - -#ifndef __HAVE_ARCH_PTEP_GET_AND_CLEAR_FULL -static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm, - unsigned long address, pte_t *ptep, - int full) -{ - pte_t pte; - pte = ptep_get_and_clear(mm, address, ptep); - return pte; -} -#endif - -/* - * Some architectures may be able to avoid expensive synchronization - * primitives when modifications are made to PTE's which are already - * not present, or in the process of an address space destruction. - */ -#ifndef __HAVE_ARCH_PTE_CLEAR_NOT_PRESENT_FULL -static inline void pte_clear_not_present_full(struct mm_struct *mm, - unsigned long address, - pte_t *ptep, - int full) -{ - pte_clear(mm, address, ptep); -} -#endif - -#ifndef __HAVE_ARCH_PTEP_CLEAR_FLUSH -extern pte_t ptep_clear_flush(struct vm_area_struct *vma, - unsigned long address, - pte_t *ptep); -#endif - -#ifndef __HAVE_ARCH_PMDP_HUGE_CLEAR_FLUSH -extern pmd_t pmdp_huge_clear_flush(struct vm_area_struct *vma, - unsigned long address, - pmd_t *pmdp); -#endif - -#ifndef __HAVE_ARCH_PTEP_SET_WRPROTECT -struct mm_struct; -static inline void ptep_set_wrprotect(struct mm_struct *mm, unsigned long address, pte_t *ptep) -{ - pte_t old_pte = *ptep; - set_pte_at(mm, address, ptep, pte_wrprotect(old_pte)); -} -#endif - -#ifndef __HAVE_ARCH_PMDP_SET_WRPROTECT -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -static inline void pmdp_set_wrprotect(struct mm_struct *mm, - unsigned long address, pmd_t *pmdp) -{ - pmd_t old_pmd = *pmdp; - set_pmd_at(mm, address, pmdp, pmd_wrprotect(old_pmd)); -} -#else -static inline void pmdp_set_wrprotect(struct mm_struct *mm, - unsigned long address, pmd_t *pmdp) -{ - BUILD_BUG(); -} -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ -#endif - -#ifndef pmdp_collapse_flush -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -extern pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, - unsigned long address, pmd_t *pmdp); -#else -static inline pmd_t pmdp_collapse_flush(struct vm_area_struct *vma, - unsigned long address, - pmd_t *pmdp) -{ - BUILD_BUG(); - return *pmdp; -} -#define pmdp_collapse_flush pmdp_collapse_flush -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ -#endif - -#ifndef __HAVE_ARCH_PGTABLE_DEPOSIT -extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp, - pgtable_t pgtable); -#endif - -#ifndef __HAVE_ARCH_PGTABLE_WITHDRAW -extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp); -#endif - -#ifndef __HAVE_ARCH_PMDP_INVALIDATE -extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address, - pmd_t *pmdp); -#endif - -#ifndef __HAVE_ARCH_PMDP_HUGE_SPLIT_PREPARE -static inline void pmdp_huge_split_prepare(struct vm_area_struct *vma, - unsigned long address, pmd_t *pmdp) -{ - -} -#endif - -#ifndef __HAVE_ARCH_PTE_SAME -static inline int pte_same(pte_t pte_a, pte_t pte_b) -{ - return pte_val(pte_a) == pte_val(pte_b); -} -#endif - -#ifndef __HAVE_ARCH_PTE_UNUSED -/* - * Some architectures provide facilities to virtualization guests - * so that they can flag allocated pages as unused. This allows the - * host to transparently reclaim unused pages. This function returns - * whether the pte's page is unused. - */ -static inline int pte_unused(pte_t pte) -{ - return 0; -} -#endif - -#ifndef __HAVE_ARCH_PMD_SAME -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b) -{ - return pmd_val(pmd_a) == pmd_val(pmd_b); -} -#else /* CONFIG_TRANSPARENT_HUGEPAGE */ -static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b) -{ - BUILD_BUG(); - return 0; -} -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ -#endif - -#ifndef __HAVE_ARCH_PGD_OFFSET_GATE -#define pgd_offset_gate(mm, addr) pgd_offset(mm, addr) -#endif - -#ifndef __HAVE_ARCH_MOVE_PTE -#define move_pte(pte, prot, old_addr, new_addr) (pte) -#endif - -#ifndef pte_accessible -# define pte_accessible(mm, pte) ((void)(pte), 1) -#endif - -#ifndef flush_tlb_fix_spurious_fault -#define flush_tlb_fix_spurious_fault(vma, address) flush_tlb_page(vma, address) -#endif - -#ifndef pgprot_noncached -#define pgprot_noncached(prot) (prot) -#endif - -#ifndef pgprot_writecombine -#define pgprot_writecombine pgprot_noncached -#endif - -#ifndef pgprot_writethrough -#define pgprot_writethrough pgprot_noncached -#endif - -#ifndef pgprot_device -#define pgprot_device pgprot_noncached -#endif - -#ifndef pgprot_modify -#define pgprot_modify pgprot_modify -static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot) -{ - if (pgprot_val(oldprot) == pgprot_val(pgprot_noncached(oldprot))) - newprot = pgprot_noncached(newprot); - if (pgprot_val(oldprot) == pgprot_val(pgprot_writecombine(oldprot))) - newprot = pgprot_writecombine(newprot); - if (pgprot_val(oldprot) == pgprot_val(pgprot_device(oldprot))) - newprot = pgprot_device(newprot); - return newprot; -} -#endif - -/* - * When walking page tables, get the address of the next boundary, - * or the end address of the range if that comes earlier. Although no - * vma end wraps to 0, rounded up __boundary may wrap to 0 throughout. - */ - -#define pgd_addr_end(addr, end) \ -({ unsigned long __boundary = ((addr) + PGDIR_SIZE) & PGDIR_MASK; \ - (__boundary - 1 < (end) - 1)? __boundary: (end); \ -}) - -#ifndef pud_addr_end -#define pud_addr_end(addr, end) \ -({ unsigned long __boundary = ((addr) + PUD_SIZE) & PUD_MASK; \ - (__boundary - 1 < (end) - 1)? __boundary: (end); \ -}) -#endif - -#ifndef pmd_addr_end -#define pmd_addr_end(addr, end) \ -({ unsigned long __boundary = ((addr) + PMD_SIZE) & PMD_MASK; \ - (__boundary - 1 < (end) - 1)? __boundary: (end); \ -}) -#endif - -/* - * When walking page tables, we usually want to skip any p?d_none entries; - * and any p?d_bad entries - reporting the error before resetting to none. - * Do the tests inline, but report and clear the bad entry in mm/memory.c. - */ -void pgd_clear_bad(pgd_t *); -void pud_clear_bad(pud_t *); -void pmd_clear_bad(pmd_t *); - -static inline int pgd_none_or_clear_bad(pgd_t *pgd) -{ - if (pgd_none(*pgd)) - return 1; - if (unlikely(pgd_bad(*pgd))) { - pgd_clear_bad(pgd); - return 1; - } - return 0; -} - -static inline int pud_none_or_clear_bad(pud_t *pud) -{ - if (pud_none(*pud)) - return 1; - if (unlikely(pud_bad(*pud))) { - pud_clear_bad(pud); - return 1; - } - return 0; -} - -static inline int pmd_none_or_clear_bad(pmd_t *pmd) -{ - if (pmd_none(*pmd)) - return 1; - if (unlikely(pmd_bad(*pmd))) { - pmd_clear_bad(pmd); - return 1; - } - return 0; -} - -static inline pte_t __ptep_modify_prot_start(struct mm_struct *mm, - unsigned long addr, - pte_t *ptep) -{ - /* - * Get the current pte state, but zero it out to make it - * non-present, preventing the hardware from asynchronously - * updating it. - */ - return ptep_get_and_clear(mm, addr, ptep); -} - -static inline void __ptep_modify_prot_commit(struct mm_struct *mm, - unsigned long addr, - pte_t *ptep, pte_t pte) -{ - /* - * The pte is non-present, so there's no hardware state to - * preserve. - */ - set_pte_at(mm, addr, ptep, pte); -} - -#ifndef __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION -/* - * Start a pte protection read-modify-write transaction, which - * protects against asynchronous hardware modifications to the pte. - * The intention is not to prevent the hardware from making pte - * updates, but to prevent any updates it may make from being lost. - * - * This does not protect against other software modifications of the - * pte; the appropriate pte lock must be held over the transation. - * - * Note that this interface is intended to be batchable, meaning that - * ptep_modify_prot_commit may not actually update the pte, but merely - * queue the update to be done at some later time. The update must be - * actually committed before the pte lock is released, however. - */ -static inline pte_t ptep_modify_prot_start(struct mm_struct *mm, - unsigned long addr, - pte_t *ptep) -{ - return __ptep_modify_prot_start(mm, addr, ptep); -} - -/* - * Commit an update to a pte, leaving any hardware-controlled bits in - * the PTE unmodified. - */ -static inline void ptep_modify_prot_commit(struct mm_struct *mm, - unsigned long addr, - pte_t *ptep, pte_t pte) -{ - __ptep_modify_prot_commit(mm, addr, ptep, pte); -} -#endif /* __HAVE_ARCH_PTEP_MODIFY_PROT_TRANSACTION */ -#endif /* CONFIG_MMU */ - -/* - * A facility to provide lazy MMU batching. This allows PTE updates and - * page invalidations to be delayed until a call to leave lazy MMU mode - * is issued. Some architectures may benefit from doing this, and it is - * beneficial for both shadow and direct mode hypervisors, which may batch - * the PTE updates which happen during this window. Note that using this - * interface requires that read hazards be removed from the code. A read - * hazard could result in the direct mode hypervisor case, since the actual - * write to the page tables may not yet have taken place, so reads though - * a raw PTE pointer after it has been modified are not guaranteed to be - * up to date. This mode can only be entered and left under the protection of - * the page table locks for all page tables which may be modified. In the UP - * case, this is required so that preemption is disabled, and in the SMP case, - * it must synchronize the delayed page table writes properly on other CPUs. - */ -#ifndef __HAVE_ARCH_ENTER_LAZY_MMU_MODE -#define arch_enter_lazy_mmu_mode() do {} while (0) -#define arch_leave_lazy_mmu_mode() do {} while (0) -#define arch_flush_lazy_mmu_mode() do {} while (0) -#endif - -/* - * A facility to provide batching of the reload of page tables and - * other process state with the actual context switch code for - * paravirtualized guests. By convention, only one of the batched - * update (lazy) modes (CPU, MMU) should be active at any given time, - * entry should never be nested, and entry and exits should always be - * paired. This is for sanity of maintaining and reasoning about the - * kernel code. In this case, the exit (end of the context switch) is - * in architecture-specific code, and so doesn't need a generic - * definition. - */ -#ifndef __HAVE_ARCH_START_CONTEXT_SWITCH -#define arch_start_context_switch(prev) do {} while (0) -#endif - -#ifndef CONFIG_HAVE_ARCH_SOFT_DIRTY -static inline int pte_soft_dirty(pte_t pte) -{ - return 0; -} - -static inline int pmd_soft_dirty(pmd_t pmd) -{ - return 0; -} - -static inline pte_t pte_mksoft_dirty(pte_t pte) -{ - return pte; -} - -static inline pmd_t pmd_mksoft_dirty(pmd_t pmd) -{ - return pmd; -} - -static inline pte_t pte_clear_soft_dirty(pte_t pte) -{ - return pte; -} - -static inline pmd_t pmd_clear_soft_dirty(pmd_t pmd) -{ - return pmd; -} - -static inline pte_t pte_swp_mksoft_dirty(pte_t pte) -{ - return pte; -} - -static inline int pte_swp_soft_dirty(pte_t pte) -{ - return 0; -} - -static inline pte_t pte_swp_clear_soft_dirty(pte_t pte) -{ - return pte; -} -#endif - -#ifndef __HAVE_PFNMAP_TRACKING -/* - * Interfaces that can be used by architecture code to keep track of - * memory type of pfn mappings specified by the remap_pfn_range, - * vm_insert_pfn. - */ - -/* - * track_pfn_remap is called when a _new_ pfn mapping is being established - * by remap_pfn_range() for physical range indicated by pfn and size. - */ -static inline int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot, - unsigned long pfn, unsigned long addr, - unsigned long size) -{ - return 0; -} - -/* - * track_pfn_insert is called when a _new_ single pfn is established - * by vm_insert_pfn(). - */ -static inline int track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot, - pfn_t pfn) -{ - return 0; -} - -/* - * track_pfn_copy is called when vma that is covering the pfnmap gets - * copied through copy_page_range(). - */ -static inline int track_pfn_copy(struct vm_area_struct *vma) -{ - return 0; -} - -/* - * untrack_pfn is called while unmapping a pfnmap for a region. - * untrack can be called for a specific region indicated by pfn and size or - * can be for the entire vma (in which case pfn, size are zero). - */ -static inline void untrack_pfn(struct vm_area_struct *vma, - unsigned long pfn, unsigned long size) -{ -} - -/* - * untrack_pfn_moved is called while mremapping a pfnmap for a new region. - */ -static inline void untrack_pfn_moved(struct vm_area_struct *vma) -{ -} -#else -extern int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot, - unsigned long pfn, unsigned long addr, - unsigned long size); -extern int track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot, - pfn_t pfn); -extern int track_pfn_copy(struct vm_area_struct *vma); -extern void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn, - unsigned long size); -extern void untrack_pfn_moved(struct vm_area_struct *vma); -#endif - -#ifdef __HAVE_COLOR_ZERO_PAGE -static inline int is_zero_pfn(unsigned long pfn) -{ - extern unsigned long zero_pfn; - unsigned long offset_from_zero_pfn = pfn - zero_pfn; - return offset_from_zero_pfn <= (zero_page_mask >> PAGE_SHIFT); -} - -#define my_zero_pfn(addr) page_to_pfn(ZERO_PAGE(addr)) - -#else -static inline int is_zero_pfn(unsigned long pfn) -{ - extern unsigned long zero_pfn; - return pfn == zero_pfn; -} - -static inline unsigned long my_zero_pfn(unsigned long addr) -{ - extern unsigned long zero_pfn; - return zero_pfn; -} -#endif - -#ifdef CONFIG_MMU - -#ifndef CONFIG_TRANSPARENT_HUGEPAGE -static inline int pmd_trans_huge(pmd_t pmd) -{ - return 0; -} -#ifndef __HAVE_ARCH_PMD_WRITE -static inline int pmd_write(pmd_t pmd) -{ - BUG(); - return 0; -} -#endif /* __HAVE_ARCH_PMD_WRITE */ -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ - -#ifndef pmd_read_atomic -static inline pmd_t pmd_read_atomic(pmd_t *pmdp) -{ - /* - * Depend on compiler for an atomic pmd read. NOTE: this is - * only going to work, if the pmdval_t isn't larger than - * an unsigned long. - */ - return *pmdp; -} -#endif - -#ifndef pmd_move_must_withdraw -static inline int pmd_move_must_withdraw(spinlock_t *new_pmd_ptl, - spinlock_t *old_pmd_ptl) -{ - /* - * With split pmd lock we also need to move preallocated - * PTE page table if new_pmd is on different PMD page table. - */ - return new_pmd_ptl != old_pmd_ptl; -} -#endif - -/* - * This function is meant to be used by sites walking pagetables with - * the mmap_sem hold in read mode to protect against MADV_DONTNEED and - * transhuge page faults. MADV_DONTNEED can convert a transhuge pmd - * into a null pmd and the transhuge page fault can convert a null pmd - * into an hugepmd or into a regular pmd (if the hugepage allocation - * fails). While holding the mmap_sem in read mode the pmd becomes - * stable and stops changing under us only if it's not null and not a - * transhuge pmd. When those races occurs and this function makes a - * difference vs the standard pmd_none_or_clear_bad, the result is - * undefined so behaving like if the pmd was none is safe (because it - * can return none anyway). The compiler level barrier() is critically - * important to compute the two checks atomically on the same pmdval. - * - * For 32bit kernels with a 64bit large pmd_t this automatically takes - * care of reading the pmd atomically to avoid SMP race conditions - * against pmd_populate() when the mmap_sem is hold for reading by the - * caller (a special atomic read not done by "gcc" as in the generic - * version above, is also needed when THP is disabled because the page - * fault can populate the pmd from under us). - */ -static inline int pmd_none_or_trans_huge_or_clear_bad(pmd_t *pmd) -{ - pmd_t pmdval = pmd_read_atomic(pmd); - /* - * The barrier will stabilize the pmdval in a register or on - * the stack so that it will stop changing under the code. - * - * When CONFIG_TRANSPARENT_HUGEPAGE=y on x86 32bit PAE, - * pmd_read_atomic is allowed to return a not atomic pmdval - * (for example pointing to an hugepage that has never been - * mapped in the pmd). The below checks will only care about - * the low part of the pmd with 32bit PAE x86 anyway, with the - * exception of pmd_none(). So the important thing is that if - * the low part of the pmd is found null, the high part will - * be also null or the pmd_none() check below would be - * confused. - */ -#ifdef CONFIG_TRANSPARENT_HUGEPAGE - barrier(); -#endif - if (pmd_none(pmdval) || pmd_trans_huge(pmdval)) - return 1; - if (unlikely(pmd_bad(pmdval))) { - pmd_clear_bad(pmd); - return 1; - } - return 0; -} - -/* - * This is a noop if Transparent Hugepage Support is not built into - * the kernel. Otherwise it is equivalent to - * pmd_none_or_trans_huge_or_clear_bad(), and shall only be called in - * places that already verified the pmd is not none and they want to - * walk ptes while holding the mmap sem in read mode (write mode don't - * need this). If THP is not enabled, the pmd can't go away under the - * code even if MADV_DONTNEED runs, but if THP is enabled we need to - * run a pmd_trans_unstable before walking the ptes after - * split_huge_page_pmd returns (because it may have run when the pmd - * become null, but then a page fault can map in a THP and not a - * regular page). - */ -static inline int pmd_trans_unstable(pmd_t *pmd) -{ -#ifdef CONFIG_TRANSPARENT_HUGEPAGE - return pmd_none_or_trans_huge_or_clear_bad(pmd); -#else - return 0; -#endif -} - -#ifndef CONFIG_NUMA_BALANCING -/* - * Technically a PTE can be PROTNONE even when not doing NUMA balancing but - * the only case the kernel cares is for NUMA balancing and is only ever set - * when the VMA is accessible. For PROT_NONE VMAs, the PTEs are not marked - * _PAGE_PROTNONE so by by default, implement the helper as "always no". It - * is the responsibility of the caller to distinguish between PROT_NONE - * protections and NUMA hinting fault protections. - */ -static inline int pte_protnone(pte_t pte) -{ - return 0; -} - -static inline int pmd_protnone(pmd_t pmd) -{ - return 0; -} -#endif /* CONFIG_NUMA_BALANCING */ - -#endif /* CONFIG_MMU */ - -#ifdef CONFIG_HAVE_ARCH_HUGE_VMAP -int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot); -int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot); -int pud_clear_huge(pud_t *pud); -int pmd_clear_huge(pmd_t *pmd); -#else /* !CONFIG_HAVE_ARCH_HUGE_VMAP */ -static inline int pud_set_huge(pud_t *pud, phys_addr_t addr, pgprot_t prot) -{ - return 0; -} -static inline int pmd_set_huge(pmd_t *pmd, phys_addr_t addr, pgprot_t prot) -{ - return 0; -} -static inline int pud_clear_huge(pud_t *pud) -{ - return 0; -} -static inline int pmd_clear_huge(pmd_t *pmd) -{ - return 0; -} -#endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */ - -#ifndef __HAVE_ARCH_FLUSH_PMD_TLB_RANGE -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -/* - * ARCHes with special requirements for evicting THP backing TLB entries can - * implement this. Otherwise also, it can help optimize normal TLB flush in - * THP regime. stock flush_tlb_range() typically has optimization to nuke the - * entire TLB TLB if flush span is greater than a threshold, which will - * likely be true for a single huge page. Thus a single thp flush will - * invalidate the entire TLB which is not desitable. - * e.g. see arch/arc: flush_pmd_tlb_range - */ -#define flush_pmd_tlb_range(vma, addr, end) flush_tlb_range(vma, addr, end) -#else -#define flush_pmd_tlb_range(vma, addr, end) BUILD_BUG() -#endif -#endif - -struct file; -int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn, - unsigned long size, pgprot_t *vma_prot); -#endif /* !__ASSEMBLY__ */ - -#ifndef io_remap_pfn_range -#define io_remap_pfn_range remap_pfn_range -#endif - -#ifndef has_transparent_hugepage -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -#define has_transparent_hugepage() 1 -#else -#define has_transparent_hugepage() 0 -#endif -#endif - -#endif /* _ASM_GENERIC_PGTABLE_H */ diff --git a/src/linux/include/asm-generic/preempt.h b/src/linux/include/asm-generic/preempt.h deleted file mode 100644 index c1cde35..0000000 --- a/src/linux/include/asm-generic/preempt.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef __ASM_PREEMPT_H -#define __ASM_PREEMPT_H - -#include - -#define PREEMPT_ENABLED (0) - -static __always_inline int preempt_count(void) -{ - return READ_ONCE(current_thread_info()->preempt_count); -} - -static __always_inline volatile int *preempt_count_ptr(void) -{ - return ¤t_thread_info()->preempt_count; -} - -static __always_inline void preempt_count_set(int pc) -{ - *preempt_count_ptr() = pc; -} - -/* - * must be macros to avoid header recursion hell - */ -#define init_task_preempt_count(p) do { \ - task_thread_info(p)->preempt_count = FORK_PREEMPT_COUNT; \ -} while (0) - -#define init_idle_preempt_count(p, cpu) do { \ - task_thread_info(p)->preempt_count = PREEMPT_ENABLED; \ -} while (0) - -static __always_inline void set_preempt_need_resched(void) -{ -} - -static __always_inline void clear_preempt_need_resched(void) -{ -} - -static __always_inline bool test_preempt_need_resched(void) -{ - return false; -} - -/* - * The various preempt_count add/sub methods - */ - -static __always_inline void __preempt_count_add(int val) -{ - *preempt_count_ptr() += val; -} - -static __always_inline void __preempt_count_sub(int val) -{ - *preempt_count_ptr() -= val; -} - -static __always_inline bool __preempt_count_dec_and_test(void) -{ - /* - * Because of load-store architectures cannot do per-cpu atomic - * operations; we cannot use PREEMPT_NEED_RESCHED because it might get - * lost. - */ - return !--*preempt_count_ptr() && tif_need_resched(); -} - -/* - * Returns true when we need to resched and can (barring IRQ state). - */ -static __always_inline bool should_resched(int preempt_offset) -{ - return unlikely(preempt_count() == preempt_offset && - tif_need_resched()); -} - -#ifdef CONFIG_PREEMPT -extern asmlinkage void preempt_schedule(void); -#define __preempt_schedule() preempt_schedule() -extern asmlinkage void preempt_schedule_notrace(void); -#define __preempt_schedule_notrace() preempt_schedule_notrace() -#endif /* CONFIG_PREEMPT */ - -#endif /* __ASM_PREEMPT_H */ diff --git a/src/linux/include/asm-generic/resource.h b/src/linux/include/asm-generic/resource.h deleted file mode 100644 index 5e752b9..0000000 --- a/src/linux/include/asm-generic/resource.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _ASM_GENERIC_RESOURCE_H -#define _ASM_GENERIC_RESOURCE_H - -#include - - -/* - * boot-time rlimit defaults for the init task: - */ -#define INIT_RLIMITS \ -{ \ - [RLIMIT_CPU] = { RLIM_INFINITY, RLIM_INFINITY }, \ - [RLIMIT_FSIZE] = { RLIM_INFINITY, RLIM_INFINITY }, \ - [RLIMIT_DATA] = { RLIM_INFINITY, RLIM_INFINITY }, \ - [RLIMIT_STACK] = { _STK_LIM, RLIM_INFINITY }, \ - [RLIMIT_CORE] = { 0, RLIM_INFINITY }, \ - [RLIMIT_RSS] = { RLIM_INFINITY, RLIM_INFINITY }, \ - [RLIMIT_NPROC] = { 0, 0 }, \ - [RLIMIT_NOFILE] = { INR_OPEN_CUR, INR_OPEN_MAX }, \ - [RLIMIT_MEMLOCK] = { MLOCK_LIMIT, MLOCK_LIMIT }, \ - [RLIMIT_AS] = { RLIM_INFINITY, RLIM_INFINITY }, \ - [RLIMIT_LOCKS] = { RLIM_INFINITY, RLIM_INFINITY }, \ - [RLIMIT_SIGPENDING] = { 0, 0 }, \ - [RLIMIT_MSGQUEUE] = { MQ_BYTES_MAX, MQ_BYTES_MAX }, \ - [RLIMIT_NICE] = { 0, 0 }, \ - [RLIMIT_RTPRIO] = { 0, 0 }, \ - [RLIMIT_RTTIME] = { RLIM_INFINITY, RLIM_INFINITY }, \ -} - -#endif diff --git a/src/linux/include/asm-generic/sections.h b/src/linux/include/asm-generic/sections.h deleted file mode 100644 index 4df64a1..0000000 --- a/src/linux/include/asm-generic/sections.h +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef _ASM_GENERIC_SECTIONS_H_ -#define _ASM_GENERIC_SECTIONS_H_ - -/* References to section boundaries */ - -#include -#include - -/* - * Usage guidelines: - * _text, _data: architecture specific, don't use them in arch-independent code - * [_stext, _etext]: contains .text.* sections, may also contain .rodata.* - * and/or .init.* sections - * [_sdata, _edata]: contains .data.* sections, may also contain .rodata.* - * and/or .init.* sections. - * [__start_rodata, __end_rodata]: contains .rodata.* sections - * [__start_data_ro_after_init, __end_data_ro_after_init]: - * contains data.ro_after_init section - * [__init_begin, __init_end]: contains .init.* sections, but .init.text.* - * may be out of this range on some architectures. - * [_sinittext, _einittext]: contains .init.text.* sections - * [__bss_start, __bss_stop]: contains BSS sections - * - * Following global variables are optional and may be unavailable on some - * architectures and/or kernel configurations. - * _text, _data - * __kprobes_text_start, __kprobes_text_end - * __entry_text_start, __entry_text_end - * __ctors_start, __ctors_end - */ -extern char _text[], _stext[], _etext[]; -extern char _data[], _sdata[], _edata[]; -extern char __bss_start[], __bss_stop[]; -extern char __init_begin[], __init_end[]; -extern char _sinittext[], _einittext[]; -extern char __start_data_ro_after_init[], __end_data_ro_after_init[]; -extern char _end[]; -extern char __per_cpu_load[], __per_cpu_start[], __per_cpu_end[]; -extern char __kprobes_text_start[], __kprobes_text_end[]; -extern char __entry_text_start[], __entry_text_end[]; -extern char __start_rodata[], __end_rodata[]; - -/* Start and end of .ctors section - used for constructor calls. */ -extern char __ctors_start[], __ctors_end[]; - -extern __visible const void __nosave_begin, __nosave_end; - -/* function descriptor handling (if any). Override - * in asm/sections.h */ -#ifndef dereference_function_descriptor -#define dereference_function_descriptor(p) (p) -#endif - -/* random extra sections (if any). Override - * in asm/sections.h */ -#ifndef arch_is_kernel_text -static inline int arch_is_kernel_text(unsigned long addr) -{ - return 0; -} -#endif - -#ifndef arch_is_kernel_data -static inline int arch_is_kernel_data(unsigned long addr) -{ - return 0; -} -#endif - -/** - * memory_contains - checks if an object is contained within a memory region - * @begin: virtual address of the beginning of the memory region - * @end: virtual address of the end of the memory region - * @virt: virtual address of the memory object - * @size: size of the memory object - * - * Returns: true if the object specified by @virt and @size is entirely - * contained within the memory region defined by @begin and @end, false - * otherwise. - */ -static inline bool memory_contains(void *begin, void *end, void *virt, - size_t size) -{ - return virt >= begin && virt + size <= end; -} - -/** - * memory_intersects - checks if the region occupied by an object intersects - * with another memory region - * @begin: virtual address of the beginning of the memory regien - * @end: virtual address of the end of the memory region - * @virt: virtual address of the memory object - * @size: size of the memory object - * - * Returns: true if an object's memory region, specified by @virt and @size, - * intersects with the region specified by @begin and @end, false otherwise. - */ -static inline bool memory_intersects(void *begin, void *end, void *virt, - size_t size) -{ - void *vend = virt + size; - - return (virt >= begin && virt < end) || (vend >= begin && vend < end); -} - -/** - * init_section_contains - checks if an object is contained within the init - * section - * @virt: virtual address of the memory object - * @size: size of the memory object - * - * Returns: true if the object specified by @virt and @size is entirely - * contained within the init section, false otherwise. - */ -static inline bool init_section_contains(void *virt, size_t size) -{ - return memory_contains(__init_begin, __init_end, virt, size); -} - -/** - * init_section_intersects - checks if the region occupied by an object - * intersects with the init section - * @virt: virtual address of the memory object - * @size: size of the memory object - * - * Returns: true if an object's memory region, specified by @virt and @size, - * intersects with the init section, false otherwise. - */ -static inline bool init_section_intersects(void *virt, size_t size) -{ - return memory_intersects(__init_begin, __init_end, virt, size); -} - -#endif /* _ASM_GENERIC_SECTIONS_H_ */ diff --git a/src/linux/include/asm-generic/segment.h b/src/linux/include/asm-generic/segment.h deleted file mode 100644 index 5580eac..0000000 --- a/src/linux/include/asm-generic/segment.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __ASM_GENERIC_SEGMENT_H -#define __ASM_GENERIC_SEGMENT_H -/* - * Only here because we have some old header files that expect it... - * - * New architectures probably don't want to have their own version. - */ - -#endif /* __ASM_GENERIC_SEGMENT_H */ diff --git a/src/linux/include/asm-generic/siginfo.h b/src/linux/include/asm-generic/siginfo.h deleted file mode 100644 index a2508a8..0000000 --- a/src/linux/include/asm-generic/siginfo.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _ASM_GENERIC_SIGINFO_H -#define _ASM_GENERIC_SIGINFO_H - -#include - -#define __SI_MASK 0xffff0000u -#define __SI_KILL (0 << 16) -#define __SI_TIMER (1 << 16) -#define __SI_POLL (2 << 16) -#define __SI_FAULT (3 << 16) -#define __SI_CHLD (4 << 16) -#define __SI_RT (5 << 16) -#define __SI_MESGQ (6 << 16) -#define __SI_SYS (7 << 16) -#define __SI_CODE(T,N) ((T) | ((N) & 0xffff)) - -struct siginfo; -void do_schedule_next_timer(struct siginfo *info); - -extern int copy_siginfo_to_user(struct siginfo __user *to, const struct siginfo *from); - -#endif diff --git a/src/linux/include/asm-generic/signal.h b/src/linux/include/asm-generic/signal.h deleted file mode 100644 index d840c90..0000000 --- a/src/linux/include/asm-generic/signal.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __ASM_GENERIC_SIGNAL_H -#define __ASM_GENERIC_SIGNAL_H - -#include - -#ifndef __ASSEMBLY__ -#ifdef SA_RESTORER -#endif - -#include -#undef __HAVE_ARCH_SIG_BITOPS - -#endif /* __ASSEMBLY__ */ -#endif /* _ASM_GENERIC_SIGNAL_H */ diff --git a/src/linux/include/asm-generic/statfs.h b/src/linux/include/asm-generic/statfs.h deleted file mode 100644 index 4b934e9..0000000 --- a/src/linux/include/asm-generic/statfs.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _GENERIC_STATFS_H -#define _GENERIC_STATFS_H - -#include - -typedef __kernel_fsid_t fsid_t; -#endif diff --git a/src/linux/include/asm-generic/string.h b/src/linux/include/asm-generic/string.h deleted file mode 100644 index de5e020..0000000 --- a/src/linux/include/asm-generic/string.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __ASM_GENERIC_STRING_H -#define __ASM_GENERIC_STRING_H -/* - * The kernel provides all required functions in lib/string.c - * - * Architectures probably want to provide at least their own optimized - * memcpy and memset functions though. - */ - -#endif /* __ASM_GENERIC_STRING_H */ diff --git a/src/linux/include/asm-generic/switch_to.h b/src/linux/include/asm-generic/switch_to.h deleted file mode 100644 index 052c4ac..0000000 --- a/src/linux/include/asm-generic/switch_to.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Generic task switch macro wrapper, based on MN10300 definitions. - * - * It should be possible to use these on really simple architectures, - * but it serves more as a starting point for new ports. - * - * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ -#ifndef __ASM_GENERIC_SWITCH_TO_H -#define __ASM_GENERIC_SWITCH_TO_H - -#include - -/* - * Context switching is now performed out-of-line in switch_to.S - */ -extern struct task_struct *__switch_to(struct task_struct *, - struct task_struct *); - -#define switch_to(prev, next, last) \ - do { \ - ((last) = __switch_to((prev), (next))); \ - } while (0) - -#endif /* __ASM_GENERIC_SWITCH_TO_H */ diff --git a/src/linux/include/asm-generic/syscalls.h b/src/linux/include/asm-generic/syscalls.h deleted file mode 100644 index 1f74be5..0000000 --- a/src/linux/include/asm-generic/syscalls.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __ASM_GENERIC_SYSCALLS_H -#define __ASM_GENERIC_SYSCALLS_H - -#include -#include - -/* - * Calling conventions for these system calls can differ, so - * it's possible to override them. - */ - -#ifndef sys_mmap2 -asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); -#endif - -#ifndef sys_mmap -asmlinkage long sys_mmap(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, off_t pgoff); -#endif - -#ifndef sys_rt_sigreturn -asmlinkage long sys_rt_sigreturn(struct pt_regs *regs); -#endif - -#endif /* __ASM_GENERIC_SYSCALLS_H */ diff --git a/src/linux/include/asm-generic/termios.h b/src/linux/include/asm-generic/termios.h deleted file mode 100644 index 4fa6fe0..0000000 --- a/src/linux/include/asm-generic/termios.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef _ASM_GENERIC_TERMIOS_H -#define _ASM_GENERIC_TERMIOS_H - - -#include -#include - -/* intr=^C quit=^\ erase=del kill=^U - eof=^D vtime=\0 vmin=\1 sxtc=\0 - start=^Q stop=^S susp=^Z eol=\0 - reprint=^R discard=^U werase=^W lnext=^V - eol2=\0 -*/ -#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" - -/* - * Translate a "termio" structure into a "termios". Ugh. - */ -static inline int user_termio_to_kernel_termios(struct ktermios *termios, - const struct termio __user *termio) -{ - unsigned short tmp; - - if (get_user(tmp, &termio->c_iflag) < 0) - goto fault; - termios->c_iflag = (0xffff0000 & termios->c_iflag) | tmp; - - if (get_user(tmp, &termio->c_oflag) < 0) - goto fault; - termios->c_oflag = (0xffff0000 & termios->c_oflag) | tmp; - - if (get_user(tmp, &termio->c_cflag) < 0) - goto fault; - termios->c_cflag = (0xffff0000 & termios->c_cflag) | tmp; - - if (get_user(tmp, &termio->c_lflag) < 0) - goto fault; - termios->c_lflag = (0xffff0000 & termios->c_lflag) | tmp; - - if (get_user(termios->c_line, &termio->c_line) < 0) - goto fault; - - if (copy_from_user(termios->c_cc, termio->c_cc, NCC) != 0) - goto fault; - - return 0; - - fault: - return -EFAULT; -} - -/* - * Translate a "termios" structure into a "termio". Ugh. - */ -static inline int kernel_termios_to_user_termio(struct termio __user *termio, - struct ktermios *termios) -{ - if (put_user(termios->c_iflag, &termio->c_iflag) < 0 || - put_user(termios->c_oflag, &termio->c_oflag) < 0 || - put_user(termios->c_cflag, &termio->c_cflag) < 0 || - put_user(termios->c_lflag, &termio->c_lflag) < 0 || - put_user(termios->c_line, &termio->c_line) < 0 || - copy_to_user(termio->c_cc, termios->c_cc, NCC) != 0) - return -EFAULT; - - return 0; -} - -#ifdef TCGETS2 -static inline int user_termios_to_kernel_termios(struct ktermios *k, - struct termios2 __user *u) -{ - return copy_from_user(k, u, sizeof(struct termios2)); -} - -static inline int kernel_termios_to_user_termios(struct termios2 __user *u, - struct ktermios *k) -{ - return copy_to_user(u, k, sizeof(struct termios2)); -} - -static inline int user_termios_to_kernel_termios_1(struct ktermios *k, - struct termios __user *u) -{ - return copy_from_user(k, u, sizeof(struct termios)); -} - -static inline int kernel_termios_to_user_termios_1(struct termios __user *u, - struct ktermios *k) -{ - return copy_to_user(u, k, sizeof(struct termios)); -} -#else /* TCGETS2 */ -static inline int user_termios_to_kernel_termios(struct ktermios *k, - struct termios __user *u) -{ - return copy_from_user(k, u, sizeof(struct termios)); -} - -static inline int kernel_termios_to_user_termios(struct termios __user *u, - struct ktermios *k) -{ - return copy_to_user(u, k, sizeof(struct termios)); -} -#endif /* TCGETS2 */ - -#endif /* _ASM_GENERIC_TERMIOS_H */ diff --git a/src/linux/include/asm-generic/timex.h b/src/linux/include/asm-generic/timex.h deleted file mode 100644 index b2243cb..0000000 --- a/src/linux/include/asm-generic/timex.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __ASM_GENERIC_TIMEX_H -#define __ASM_GENERIC_TIMEX_H - -/* - * If you have a cycle counter, return the value here. - */ -typedef unsigned long cycles_t; -#ifndef get_cycles -static inline cycles_t get_cycles(void) -{ - return 0; -} -#endif - -/* - * Architectures are encouraged to implement read_current_timer - * and define this in order to avoid the expensive delay loop - * calibration during boot. - */ -#undef ARCH_HAS_READ_CURRENT_TIMER - -#endif /* __ASM_GENERIC_TIMEX_H */ diff --git a/src/linux/include/asm-generic/tlb.h b/src/linux/include/asm-generic/tlb.h deleted file mode 100644 index c6d6671..0000000 --- a/src/linux/include/asm-generic/tlb.h +++ /dev/null @@ -1,258 +0,0 @@ -/* include/asm-generic/tlb.h - * - * Generic TLB shootdown code - * - * Copyright 2001 Red Hat, Inc. - * Based on code from mm/memory.c Copyright Linus Torvalds and others. - * - * Copyright 2011 Red Hat, Inc., Peter Zijlstra - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _ASM_GENERIC__TLB_H -#define _ASM_GENERIC__TLB_H - -#include -#include -#include - -#ifdef CONFIG_HAVE_RCU_TABLE_FREE -/* - * Semi RCU freeing of the page directories. - * - * This is needed by some architectures to implement software pagetable walkers. - * - * gup_fast() and other software pagetable walkers do a lockless page-table - * walk and therefore needs some synchronization with the freeing of the page - * directories. The chosen means to accomplish that is by disabling IRQs over - * the walk. - * - * Architectures that use IPIs to flush TLBs will then automagically DTRT, - * since we unlink the page, flush TLBs, free the page. Since the disabling of - * IRQs delays the completion of the TLB flush we can never observe an already - * freed page. - * - * Architectures that do not have this (PPC) need to delay the freeing by some - * other means, this is that means. - * - * What we do is batch the freed directory pages (tables) and RCU free them. - * We use the sched RCU variant, as that guarantees that IRQ/preempt disabling - * holds off grace periods. - * - * However, in order to batch these pages we need to allocate storage, this - * allocation is deep inside the MM code and can thus easily fail on memory - * pressure. To guarantee progress we fall back to single table freeing, see - * the implementation of tlb_remove_table_one(). - * - */ -struct mmu_table_batch { - struct rcu_head rcu; - unsigned int nr; - void *tables[0]; -}; - -#define MAX_TABLE_BATCH \ - ((PAGE_SIZE - sizeof(struct mmu_table_batch)) / sizeof(void *)) - -extern void tlb_table_flush(struct mmu_gather *tlb); -extern void tlb_remove_table(struct mmu_gather *tlb, void *table); - -#endif - -/* - * If we can't allocate a page to make a big batch of page pointers - * to work on, then just handle a few from the on-stack structure. - */ -#define MMU_GATHER_BUNDLE 8 - -struct mmu_gather_batch { - struct mmu_gather_batch *next; - unsigned int nr; - unsigned int max; - struct page *pages[0]; -}; - -#define MAX_GATHER_BATCH \ - ((PAGE_SIZE - sizeof(struct mmu_gather_batch)) / sizeof(void *)) - -/* - * Limit the maximum number of mmu_gather batches to reduce a risk of soft - * lockups for non-preemptible kernels on huge machines when a lot of memory - * is zapped during unmapping. - * 10K pages freed at once should be safe even without a preemption point. - */ -#define MAX_GATHER_BATCH_COUNT (10000UL/MAX_GATHER_BATCH) - -/* struct mmu_gather is an opaque type used by the mm code for passing around - * any data needed by arch specific code for tlb_remove_page. - */ -struct mmu_gather { - struct mm_struct *mm; -#ifdef CONFIG_HAVE_RCU_TABLE_FREE - struct mmu_table_batch *batch; -#endif - unsigned long start; - unsigned long end; - /* we are in the middle of an operation to clear - * a full mm and can make some optimizations */ - unsigned int fullmm : 1, - /* we have performed an operation which - * requires a complete flush of the tlb */ - need_flush_all : 1; - - struct mmu_gather_batch *active; - struct mmu_gather_batch local; - struct page *__pages[MMU_GATHER_BUNDLE]; - unsigned int batch_count; - /* - * __tlb_adjust_range will track the new addr here, - * that that we can adjust the range after the flush - */ - unsigned long addr; - int page_size; -}; - -#define HAVE_GENERIC_MMU_GATHER - -void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long start, unsigned long end); -void tlb_flush_mmu(struct mmu_gather *tlb); -void tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, - unsigned long end); -extern bool __tlb_remove_page_size(struct mmu_gather *tlb, struct page *page, - int page_size); - -static inline void __tlb_adjust_range(struct mmu_gather *tlb, - unsigned long address) -{ - tlb->start = min(tlb->start, address); - tlb->end = max(tlb->end, address + PAGE_SIZE); - /* - * Track the last address with which we adjusted the range. This - * will be used later to adjust again after a mmu_flush due to - * failed __tlb_remove_page - */ - tlb->addr = address; -} - -static inline void __tlb_reset_range(struct mmu_gather *tlb) -{ - if (tlb->fullmm) { - tlb->start = tlb->end = ~0; - } else { - tlb->start = TASK_SIZE; - tlb->end = 0; - } -} - -static inline void tlb_remove_page_size(struct mmu_gather *tlb, - struct page *page, int page_size) -{ - if (__tlb_remove_page_size(tlb, page, page_size)) { - tlb_flush_mmu(tlb); - tlb->page_size = page_size; - __tlb_adjust_range(tlb, tlb->addr); - __tlb_remove_page_size(tlb, page, page_size); - } -} - -static bool __tlb_remove_page(struct mmu_gather *tlb, struct page *page) -{ - return __tlb_remove_page_size(tlb, page, PAGE_SIZE); -} - -/* tlb_remove_page - * Similar to __tlb_remove_page but will call tlb_flush_mmu() itself when - * required. - */ -static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page) -{ - return tlb_remove_page_size(tlb, page, PAGE_SIZE); -} - -static inline bool __tlb_remove_pte_page(struct mmu_gather *tlb, struct page *page) -{ - /* active->nr should be zero when we call this */ - VM_BUG_ON_PAGE(tlb->active->nr, page); - tlb->page_size = PAGE_SIZE; - __tlb_adjust_range(tlb, tlb->addr); - return __tlb_remove_page(tlb, page); -} - -/* - * In the case of tlb vma handling, we can optimise these away in the - * case where we're doing a full MM flush. When we're doing a munmap, - * the vmas are adjusted to only cover the region to be torn down. - */ -#ifndef tlb_start_vma -#define tlb_start_vma(tlb, vma) do { } while (0) -#endif - -#define __tlb_end_vma(tlb, vma) \ - do { \ - if (!tlb->fullmm && tlb->end) { \ - tlb_flush(tlb); \ - __tlb_reset_range(tlb); \ - } \ - } while (0) - -#ifndef tlb_end_vma -#define tlb_end_vma __tlb_end_vma -#endif - -#ifndef __tlb_remove_tlb_entry -#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0) -#endif - -/** - * tlb_remove_tlb_entry - remember a pte unmapping for later tlb invalidation. - * - * Record the fact that pte's were really unmapped by updating the range, - * so we can later optimise away the tlb invalidate. This helps when - * userspace is unmapping already-unmapped pages, which happens quite a lot. - */ -#define tlb_remove_tlb_entry(tlb, ptep, address) \ - do { \ - __tlb_adjust_range(tlb, address); \ - __tlb_remove_tlb_entry(tlb, ptep, address); \ - } while (0) - -/** - * tlb_remove_pmd_tlb_entry - remember a pmd mapping for later tlb invalidation - * This is a nop so far, because only x86 needs it. - */ -#ifndef __tlb_remove_pmd_tlb_entry -#define __tlb_remove_pmd_tlb_entry(tlb, pmdp, address) do {} while (0) -#endif - -#define tlb_remove_pmd_tlb_entry(tlb, pmdp, address) \ - do { \ - __tlb_adjust_range(tlb, address); \ - __tlb_remove_pmd_tlb_entry(tlb, pmdp, address); \ - } while (0) - -#define pte_free_tlb(tlb, ptep, address) \ - do { \ - __tlb_adjust_range(tlb, address); \ - __pte_free_tlb(tlb, ptep, address); \ - } while (0) - -#ifndef __ARCH_HAS_4LEVEL_HACK -#define pud_free_tlb(tlb, pudp, address) \ - do { \ - __tlb_adjust_range(tlb, address); \ - __pud_free_tlb(tlb, pudp, address); \ - } while (0) -#endif - -#define pmd_free_tlb(tlb, pmdp, address) \ - do { \ - __tlb_adjust_range(tlb, address); \ - __pmd_free_tlb(tlb, pmdp, address); \ - } while (0) - -#define tlb_migrate_finish(mm) do {} while (0) - -#endif /* _ASM_GENERIC__TLB_H */ diff --git a/src/linux/include/asm-generic/tlbflush.h b/src/linux/include/asm-generic/tlbflush.h deleted file mode 100644 index d6d0a88..0000000 --- a/src/linux/include/asm-generic/tlbflush.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __ASM_GENERIC_TLBFLUSH_H -#define __ASM_GENERIC_TLBFLUSH_H -/* - * This is a dummy tlbflush implementation that can be used on all - * nommu architectures. - * If you have an MMU, you need to write your own functions. - */ -#ifdef CONFIG_MMU -#error need to implement an architecture specific asm/tlbflush.h -#endif - -#include - -static inline void flush_tlb_mm(struct mm_struct *mm) -{ - BUG(); -} - - -#endif /* __ASM_GENERIC_TLBFLUSH_H */ diff --git a/src/linux/include/asm-generic/topology.h b/src/linux/include/asm-generic/topology.h deleted file mode 100644 index fc824e2..0000000 --- a/src/linux/include/asm-generic/topology.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * linux/include/asm-generic/topology.h - * - * Written by: Matthew Dobson, IBM Corporation - * - * Copyright (C) 2002, IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - */ -#ifndef _ASM_GENERIC_TOPOLOGY_H -#define _ASM_GENERIC_TOPOLOGY_H - -#ifndef CONFIG_NUMA - -/* Other architectures wishing to use this simple topology API should fill - in the below functions as appropriate in their own file. */ -#ifndef cpu_to_node -#define cpu_to_node(cpu) ((void)(cpu),0) -#endif -#ifndef set_numa_node -#define set_numa_node(node) -#endif -#ifndef set_cpu_numa_node -#define set_cpu_numa_node(cpu, node) -#endif -#ifndef cpu_to_mem -#define cpu_to_mem(cpu) ((void)(cpu),0) -#endif - -#ifndef parent_node -#define parent_node(node) ((void)(node),0) -#endif -#ifndef cpumask_of_node -#define cpumask_of_node(node) ((void)node, cpu_online_mask) -#endif -#ifndef pcibus_to_node -#define pcibus_to_node(bus) ((void)(bus), -1) -#endif - -#ifndef cpumask_of_pcibus -#define cpumask_of_pcibus(bus) (pcibus_to_node(bus) == -1 ? \ - cpu_all_mask : \ - cpumask_of_node(pcibus_to_node(bus))) -#endif - -#endif /* CONFIG_NUMA */ - -#if !defined(CONFIG_NUMA) || !defined(CONFIG_HAVE_MEMORYLESS_NODES) - -#ifndef set_numa_mem -#define set_numa_mem(node) -#endif -#ifndef set_cpu_numa_mem -#define set_cpu_numa_mem(cpu, node) -#endif - -#endif /* !CONFIG_NUMA || !CONFIG_HAVE_MEMORYLESS_NODES */ - -#endif /* _ASM_GENERIC_TOPOLOGY_H */ diff --git a/src/linux/include/asm-generic/trace_clock.h b/src/linux/include/asm-generic/trace_clock.h deleted file mode 100644 index 6726f1b..0000000 --- a/src/linux/include/asm-generic/trace_clock.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _ASM_GENERIC_TRACE_CLOCK_H -#define _ASM_GENERIC_TRACE_CLOCK_H -/* - * Arch-specific trace clocks. - */ - -/* - * Additional trace clocks added to the trace_clocks - * array in kernel/trace/trace.c - * None if the architecture has not defined it. - */ -#ifndef ARCH_TRACE_CLOCKS -# define ARCH_TRACE_CLOCKS -#endif - -#endif /* _ASM_GENERIC_TRACE_CLOCK_H */ diff --git a/src/linux/include/asm-generic/uaccess.h b/src/linux/include/asm-generic/uaccess.h deleted file mode 100644 index cc6bb31..0000000 --- a/src/linux/include/asm-generic/uaccess.h +++ /dev/null @@ -1,351 +0,0 @@ -#ifndef __ASM_GENERIC_UACCESS_H -#define __ASM_GENERIC_UACCESS_H - -/* - * User space memory access functions, these should work - * on any machine that has kernel and user data in the same - * address space, e.g. all NOMMU machines. - */ -#include -#include - -#include - -#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) - -#ifndef KERNEL_DS -#define KERNEL_DS MAKE_MM_SEG(~0UL) -#endif - -#ifndef USER_DS -#define USER_DS MAKE_MM_SEG(TASK_SIZE - 1) -#endif - -#ifndef get_fs -#define get_ds() (KERNEL_DS) -#define get_fs() (current_thread_info()->addr_limit) - -static inline void set_fs(mm_segment_t fs) -{ - current_thread_info()->addr_limit = fs; -} -#endif - -#ifndef segment_eq -#define segment_eq(a, b) ((a).seg == (b).seg) -#endif - -#define VERIFY_READ 0 -#define VERIFY_WRITE 1 - -#define access_ok(type, addr, size) __access_ok((unsigned long)(addr),(size)) - -/* - * The architecture should really override this if possible, at least - * doing a check on the get_fs() - */ -#ifndef __access_ok -static inline int __access_ok(unsigned long addr, unsigned long size) -{ - return 1; -} -#endif - -/* - * The exception table consists of pairs of addresses: the first is the - * address of an instruction that is allowed to fault, and the second is - * the address at which the program should continue. No registers are - * modified, so it is entirely up to the continuation code to figure out - * what to do. - * - * All the routines below use bits of fixup code that are out of line - * with the main instruction path. This means when everything is well, - * we don't even have to jump over them. Further, they do not intrude - * on our cache or tlb entries. - */ - -struct exception_table_entry -{ - unsigned long insn, fixup; -}; - -/* - * architectures with an MMU should override these two - */ -#ifndef __copy_from_user -static inline __must_check long __copy_from_user(void *to, - const void __user * from, unsigned long n) -{ - if (__builtin_constant_p(n)) { - switch(n) { - case 1: - *(u8 *)to = *(u8 __force *)from; - return 0; - case 2: - *(u16 *)to = *(u16 __force *)from; - return 0; - case 4: - *(u32 *)to = *(u32 __force *)from; - return 0; -#ifdef CONFIG_64BIT - case 8: - *(u64 *)to = *(u64 __force *)from; - return 0; -#endif - default: - break; - } - } - - memcpy(to, (const void __force *)from, n); - return 0; -} -#endif - -#ifndef __copy_to_user -static inline __must_check long __copy_to_user(void __user *to, - const void *from, unsigned long n) -{ - if (__builtin_constant_p(n)) { - switch(n) { - case 1: - *(u8 __force *)to = *(u8 *)from; - return 0; - case 2: - *(u16 __force *)to = *(u16 *)from; - return 0; - case 4: - *(u32 __force *)to = *(u32 *)from; - return 0; -#ifdef CONFIG_64BIT - case 8: - *(u64 __force *)to = *(u64 *)from; - return 0; -#endif - default: - break; - } - } - - memcpy((void __force *)to, from, n); - return 0; -} -#endif - -/* - * These are the main single-value transfer routines. They automatically - * use the right size if we just have the right pointer type. - * This version just falls back to copy_{from,to}_user, which should - * provide a fast-path for small values. - */ -#define __put_user(x, ptr) \ -({ \ - __typeof__(*(ptr)) __x = (x); \ - int __pu_err = -EFAULT; \ - __chk_user_ptr(ptr); \ - switch (sizeof (*(ptr))) { \ - case 1: \ - case 2: \ - case 4: \ - case 8: \ - __pu_err = __put_user_fn(sizeof (*(ptr)), \ - ptr, &__x); \ - break; \ - default: \ - __put_user_bad(); \ - break; \ - } \ - __pu_err; \ -}) - -#define put_user(x, ptr) \ -({ \ - void *__p = (ptr); \ - might_fault(); \ - access_ok(VERIFY_WRITE, __p, sizeof(*ptr)) ? \ - __put_user((x), ((__typeof__(*(ptr)) *)__p)) : \ - -EFAULT; \ -}) - -#ifndef __put_user_fn - -static inline int __put_user_fn(size_t size, void __user *ptr, void *x) -{ - size = __copy_to_user(ptr, x, size); - return size ? -EFAULT : size; -} - -#define __put_user_fn(sz, u, k) __put_user_fn(sz, u, k) - -#endif - -extern int __put_user_bad(void) __attribute__((noreturn)); - -#define __get_user(x, ptr) \ -({ \ - int __gu_err = -EFAULT; \ - __chk_user_ptr(ptr); \ - switch (sizeof(*(ptr))) { \ - case 1: { \ - unsigned char __x; \ - __gu_err = __get_user_fn(sizeof (*(ptr)), \ - ptr, &__x); \ - (x) = *(__force __typeof__(*(ptr)) *) &__x; \ - break; \ - }; \ - case 2: { \ - unsigned short __x; \ - __gu_err = __get_user_fn(sizeof (*(ptr)), \ - ptr, &__x); \ - (x) = *(__force __typeof__(*(ptr)) *) &__x; \ - break; \ - }; \ - case 4: { \ - unsigned int __x; \ - __gu_err = __get_user_fn(sizeof (*(ptr)), \ - ptr, &__x); \ - (x) = *(__force __typeof__(*(ptr)) *) &__x; \ - break; \ - }; \ - case 8: { \ - unsigned long long __x; \ - __gu_err = __get_user_fn(sizeof (*(ptr)), \ - ptr, &__x); \ - (x) = *(__force __typeof__(*(ptr)) *) &__x; \ - break; \ - }; \ - default: \ - __get_user_bad(); \ - break; \ - } \ - __gu_err; \ -}) - -#define get_user(x, ptr) \ -({ \ - const void *__p = (ptr); \ - might_fault(); \ - access_ok(VERIFY_READ, __p, sizeof(*ptr)) ? \ - __get_user((x), (__typeof__(*(ptr)) *)__p) : \ - ((x) = (__typeof__(*(ptr)))0,-EFAULT); \ -}) - -#ifndef __get_user_fn -static inline int __get_user_fn(size_t size, const void __user *ptr, void *x) -{ - size_t n = __copy_from_user(x, ptr, size); - if (unlikely(n)) { - memset(x + (size - n), 0, n); - return -EFAULT; - } - return 0; -} - -#define __get_user_fn(sz, u, k) __get_user_fn(sz, u, k) - -#endif - -extern int __get_user_bad(void) __attribute__((noreturn)); - -#ifndef __copy_from_user_inatomic -#define __copy_from_user_inatomic __copy_from_user -#endif - -#ifndef __copy_to_user_inatomic -#define __copy_to_user_inatomic __copy_to_user -#endif - -static inline long copy_from_user(void *to, - const void __user * from, unsigned long n) -{ - unsigned long res = n; - might_fault(); - if (likely(access_ok(VERIFY_READ, from, n))) - res = __copy_from_user(to, from, n); - if (unlikely(res)) - memset(to + (n - res), 0, res); - return res; -} - -static inline long copy_to_user(void __user *to, - const void *from, unsigned long n) -{ - might_fault(); - if (access_ok(VERIFY_WRITE, to, n)) - return __copy_to_user(to, from, n); - else - return n; -} - -/* - * Copy a null terminated string from userspace. - */ -#ifndef __strncpy_from_user -static inline long -__strncpy_from_user(char *dst, const char __user *src, long count) -{ - char *tmp; - strncpy(dst, (const char __force *)src, count); - for (tmp = dst; *tmp && count > 0; tmp++, count--) - ; - return (tmp - dst); -} -#endif - -static inline long -strncpy_from_user(char *dst, const char __user *src, long count) -{ - if (!access_ok(VERIFY_READ, src, 1)) - return -EFAULT; - return __strncpy_from_user(dst, src, count); -} - -/* - * Return the size of a string (including the ending 0) - * - * Return 0 on exception, a value greater than N if too long - */ -#ifndef __strnlen_user -#define __strnlen_user(s, n) (strnlen((s), (n)) + 1) -#endif - -/* - * Unlike strnlen, strnlen_user includes the nul terminator in - * its returned count. Callers should check for a returned value - * greater than N as an indication the string is too long. - */ -static inline long strnlen_user(const char __user *src, long n) -{ - if (!access_ok(VERIFY_READ, src, 1)) - return 0; - return __strnlen_user(src, n); -} - -static inline long strlen_user(const char __user *src) -{ - return strnlen_user(src, 32767); -} - -/* - * Zero Userspace - */ -#ifndef __clear_user -static inline __must_check unsigned long -__clear_user(void __user *to, unsigned long n) -{ - memset((void __force *)to, 0, n); - return 0; -} -#endif - -static inline __must_check unsigned long -clear_user(void __user *to, unsigned long n) -{ - might_fault(); - if (!access_ok(VERIFY_WRITE, to, n)) - return n; - - return __clear_user(to, n); -} - -#endif /* __ASM_GENERIC_UACCESS_H */ diff --git a/src/linux/include/asm-generic/unaligned.h b/src/linux/include/asm-generic/unaligned.h deleted file mode 100644 index 1ac0972..0000000 --- a/src/linux/include/asm-generic/unaligned.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef __ASM_GENERIC_UNALIGNED_H -#define __ASM_GENERIC_UNALIGNED_H - -/* - * This is the most generic implementation of unaligned accesses - * and should work almost anywhere. - */ -#include - -/* Set by the arch if it can handle unaligned accesses in hardware. */ -#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS -# include -#endif - -#if defined(__LITTLE_ENDIAN) -# ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS -# include -# include -# endif -# include -# define get_unaligned __get_unaligned_le -# define put_unaligned __put_unaligned_le -#elif defined(__BIG_ENDIAN) -# ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS -# include -# include -# endif -# include -# define get_unaligned __get_unaligned_be -# define put_unaligned __put_unaligned_be -#else -# error need to define endianess -#endif - -#endif /* __ASM_GENERIC_UNALIGNED_H */ diff --git a/src/linux/include/asm-generic/unistd.h b/src/linux/include/asm-generic/unistd.h deleted file mode 100644 index cccc86e..0000000 --- a/src/linux/include/asm-generic/unistd.h +++ /dev/null @@ -1,12 +0,0 @@ -#include -#include - -/* - * These are required system calls, we should - * invert the logic eventually and let them - * be selected by default. - */ -#if __BITS_PER_LONG == 32 -#define __ARCH_WANT_STAT64 -#define __ARCH_WANT_SYS_LLSEEK -#endif diff --git a/src/linux/include/asm-generic/vmlinux.lds.h b/src/linux/include/asm-generic/vmlinux.lds.h deleted file mode 100644 index 9499360..0000000 --- a/src/linux/include/asm-generic/vmlinux.lds.h +++ /dev/null @@ -1,888 +0,0 @@ -/* - * Helper macros to support writing architecture specific - * linker scripts. - * - * A minimal linker scripts has following content: - * [This is a sample, architectures may have special requiriements] - * - * OUTPUT_FORMAT(...) - * OUTPUT_ARCH(...) - * ENTRY(...) - * SECTIONS - * { - * . = START; - * __init_begin = .; - * HEAD_TEXT_SECTION - * INIT_TEXT_SECTION(PAGE_SIZE) - * INIT_DATA_SECTION(...) - * PERCPU_SECTION(CACHELINE_SIZE) - * __init_end = .; - * - * _stext = .; - * TEXT_SECTION = 0 - * _etext = .; - * - * _sdata = .; - * RO_DATA_SECTION(PAGE_SIZE) - * RW_DATA_SECTION(...) - * _edata = .; - * - * EXCEPTION_TABLE(...) - * NOTES - * - * BSS_SECTION(0, 0, 0) - * _end = .; - * - * STABS_DEBUG - * DWARF_DEBUG - * - * DISCARDS // must be the last - * } - * - * [__init_begin, __init_end] is the init section that may be freed after init - * // __init_begin and __init_end should be page aligned, so that we can - * // free the whole .init memory - * [_stext, _etext] is the text section - * [_sdata, _edata] is the data section - * - * Some of the included output section have their own set of constants. - * Examples are: [__initramfs_start, __initramfs_end] for initramfs and - * [__nosave_begin, __nosave_end] for the nosave data - */ - -#ifndef LOAD_OFFSET -#define LOAD_OFFSET 0 -#endif - -#include - -/* Align . to a 8 byte boundary equals to maximum function alignment. */ -#define ALIGN_FUNCTION() . = ALIGN(8) - -/* - * Align to a 32 byte boundary equal to the - * alignment gcc 4.5 uses for a struct - */ -#define STRUCT_ALIGNMENT 32 -#define STRUCT_ALIGN() . = ALIGN(STRUCT_ALIGNMENT) - -/* The actual configuration determine if the init/exit sections - * are handled as text/data or they can be discarded (which - * often happens at runtime) - */ -#ifdef CONFIG_HOTPLUG_CPU -#define CPU_KEEP(sec) *(.cpu##sec) -#define CPU_DISCARD(sec) -#else -#define CPU_KEEP(sec) -#define CPU_DISCARD(sec) *(.cpu##sec) -#endif - -#if defined(CONFIG_MEMORY_HOTPLUG) -#define MEM_KEEP(sec) *(.mem##sec) -#define MEM_DISCARD(sec) -#else -#define MEM_KEEP(sec) -#define MEM_DISCARD(sec) *(.mem##sec) -#endif - -#ifdef CONFIG_FTRACE_MCOUNT_RECORD -#define MCOUNT_REC() . = ALIGN(8); \ - VMLINUX_SYMBOL(__start_mcount_loc) = .; \ - *(__mcount_loc) \ - VMLINUX_SYMBOL(__stop_mcount_loc) = .; -#else -#define MCOUNT_REC() -#endif - -#ifdef CONFIG_TRACE_BRANCH_PROFILING -#define LIKELY_PROFILE() VMLINUX_SYMBOL(__start_annotated_branch_profile) = .; \ - *(_ftrace_annotated_branch) \ - VMLINUX_SYMBOL(__stop_annotated_branch_profile) = .; -#else -#define LIKELY_PROFILE() -#endif - -#ifdef CONFIG_PROFILE_ALL_BRANCHES -#define BRANCH_PROFILE() VMLINUX_SYMBOL(__start_branch_profile) = .; \ - *(_ftrace_branch) \ - VMLINUX_SYMBOL(__stop_branch_profile) = .; -#else -#define BRANCH_PROFILE() -#endif - -#ifdef CONFIG_KPROBES -#define KPROBE_BLACKLIST() . = ALIGN(8); \ - VMLINUX_SYMBOL(__start_kprobe_blacklist) = .; \ - *(_kprobe_blacklist) \ - VMLINUX_SYMBOL(__stop_kprobe_blacklist) = .; -#else -#define KPROBE_BLACKLIST() -#endif - -#ifdef CONFIG_EVENT_TRACING -#define FTRACE_EVENTS() . = ALIGN(8); \ - VMLINUX_SYMBOL(__start_ftrace_events) = .; \ - *(_ftrace_events) \ - VMLINUX_SYMBOL(__stop_ftrace_events) = .; \ - VMLINUX_SYMBOL(__start_ftrace_enum_maps) = .; \ - *(_ftrace_enum_map) \ - VMLINUX_SYMBOL(__stop_ftrace_enum_maps) = .; -#else -#define FTRACE_EVENTS() -#endif - -#ifdef CONFIG_TRACING -#define TRACE_PRINTKS() VMLINUX_SYMBOL(__start___trace_bprintk_fmt) = .; \ - *(__trace_printk_fmt) /* Trace_printk fmt' pointer */ \ - VMLINUX_SYMBOL(__stop___trace_bprintk_fmt) = .; -#define TRACEPOINT_STR() VMLINUX_SYMBOL(__start___tracepoint_str) = .; \ - *(__tracepoint_str) /* Trace_printk fmt' pointer */ \ - VMLINUX_SYMBOL(__stop___tracepoint_str) = .; -#else -#define TRACE_PRINTKS() -#define TRACEPOINT_STR() -#endif - -#ifdef CONFIG_FTRACE_SYSCALLS -#define TRACE_SYSCALLS() . = ALIGN(8); \ - VMLINUX_SYMBOL(__start_syscalls_metadata) = .; \ - *(__syscalls_metadata) \ - VMLINUX_SYMBOL(__stop_syscalls_metadata) = .; -#else -#define TRACE_SYSCALLS() -#endif - -#ifdef CONFIG_SERIAL_EARLYCON -#define EARLYCON_TABLE() STRUCT_ALIGN(); \ - VMLINUX_SYMBOL(__earlycon_table) = .; \ - *(__earlycon_table) \ - VMLINUX_SYMBOL(__earlycon_table_end) = .; -#else -#define EARLYCON_TABLE() -#endif - -#define ___OF_TABLE(cfg, name) _OF_TABLE_##cfg(name) -#define __OF_TABLE(cfg, name) ___OF_TABLE(cfg, name) -#define OF_TABLE(cfg, name) __OF_TABLE(IS_ENABLED(cfg), name) -#define _OF_TABLE_0(name) -#define _OF_TABLE_1(name) \ - . = ALIGN(8); \ - VMLINUX_SYMBOL(__##name##_of_table) = .; \ - *(__##name##_of_table) \ - *(__##name##_of_table_end) - -#define CLKSRC_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc) -#define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip) -#define CLK_OF_TABLES() OF_TABLE(CONFIG_COMMON_CLK, clk) -#define IOMMU_OF_TABLES() OF_TABLE(CONFIG_OF_IOMMU, iommu) -#define RESERVEDMEM_OF_TABLES() OF_TABLE(CONFIG_OF_RESERVED_MEM, reservedmem) -#define CPU_METHOD_OF_TABLES() OF_TABLE(CONFIG_SMP, cpu_method) -#define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method) - -#ifdef CONFIG_ACPI -#define ACPI_PROBE_TABLE(name) \ - . = ALIGN(8); \ - VMLINUX_SYMBOL(__##name##_acpi_probe_table) = .; \ - *(__##name##_acpi_probe_table) \ - VMLINUX_SYMBOL(__##name##_acpi_probe_table_end) = .; -#else -#define ACPI_PROBE_TABLE(name) -#endif - -#define KERNEL_DTB() \ - STRUCT_ALIGN(); \ - VMLINUX_SYMBOL(__dtb_start) = .; \ - *(.dtb.init.rodata) \ - VMLINUX_SYMBOL(__dtb_end) = .; - -/* - * .data section - * LD_DEAD_CODE_DATA_ELIMINATION option enables -fdata-sections generates - * .data.identifier which needs to be pulled in with .data, but don't want to - * pull in .data..stuff which has its own requirements. Same for bss. - */ -#define DATA_DATA \ - *(.data .data.[0-9a-zA-Z_]*) \ - *(.ref.data) \ - *(.data..shared_aligned) /* percpu related */ \ - MEM_KEEP(init.data) \ - MEM_KEEP(exit.data) \ - *(.data.unlikely) \ - STRUCT_ALIGN(); \ - *(__tracepoints) \ - /* implement dynamic printk debug */ \ - . = ALIGN(8); \ - VMLINUX_SYMBOL(__start___jump_table) = .; \ - *(__jump_table) \ - VMLINUX_SYMBOL(__stop___jump_table) = .; \ - . = ALIGN(8); \ - VMLINUX_SYMBOL(__start___verbose) = .; \ - *(__verbose) \ - VMLINUX_SYMBOL(__stop___verbose) = .; \ - LIKELY_PROFILE() \ - BRANCH_PROFILE() \ - TRACE_PRINTKS() \ - TRACEPOINT_STR() - -/* - * Data section helpers - */ -#define NOSAVE_DATA \ - . = ALIGN(PAGE_SIZE); \ - VMLINUX_SYMBOL(__nosave_begin) = .; \ - *(.data..nosave) \ - . = ALIGN(PAGE_SIZE); \ - VMLINUX_SYMBOL(__nosave_end) = .; - -#define PAGE_ALIGNED_DATA(page_align) \ - . = ALIGN(page_align); \ - *(.data..page_aligned) - -#define READ_MOSTLY_DATA(align) \ - . = ALIGN(align); \ - *(.data..read_mostly) \ - . = ALIGN(align); - -#define CACHELINE_ALIGNED_DATA(align) \ - . = ALIGN(align); \ - *(.data..cacheline_aligned) - -#define INIT_TASK_DATA(align) \ - . = ALIGN(align); \ - VMLINUX_SYMBOL(__start_init_task) = .; \ - *(.data..init_task) \ - VMLINUX_SYMBOL(__end_init_task) = .; - -/* - * Allow architectures to handle ro_after_init data on their - * own by defining an empty RO_AFTER_INIT_DATA. - */ -#ifndef RO_AFTER_INIT_DATA -#define RO_AFTER_INIT_DATA \ - __start_data_ro_after_init = .; \ - *(.data..ro_after_init) \ - __end_data_ro_after_init = .; -#endif - -/* - * Read only Data - */ - -#ifndef RODATA_SECTION -#define RODATA_SECTION .rodata -#endif - -#define RO_DATA_SECTION(align) \ - . = ALIGN((align)); \ - RODATA_SECTION : AT(ADDR(RODATA_SECTION) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start_rodata) = .; \ - *(RODATA_SECTION) *(RODATA_SECTION.*) \ - RO_AFTER_INIT_DATA /* Read only after init */ \ - *(__vermagic) /* Kernel version magic */ \ - . = ALIGN(8); \ - VMLINUX_SYMBOL(__start___tracepoints_ptrs) = .; \ - *(__tracepoints_ptrs) /* Tracepoints: pointer array */\ - VMLINUX_SYMBOL(__stop___tracepoints_ptrs) = .; \ - *(__tracepoints_strings)/* Tracepoints: strings */ \ - } \ - \ - .rodata1 : AT(ADDR(.rodata1) - LOAD_OFFSET) { \ - *(.rodata1) \ - } \ - \ - BUG_TABLE \ - \ - /* PCI quirks */ \ - .pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start_pci_fixups_early) = .; \ - *(.pci_fixup_early) \ - VMLINUX_SYMBOL(__end_pci_fixups_early) = .; \ - VMLINUX_SYMBOL(__start_pci_fixups_header) = .; \ - *(.pci_fixup_header) \ - VMLINUX_SYMBOL(__end_pci_fixups_header) = .; \ - VMLINUX_SYMBOL(__start_pci_fixups_final) = .; \ - *(.pci_fixup_final) \ - VMLINUX_SYMBOL(__end_pci_fixups_final) = .; \ - VMLINUX_SYMBOL(__start_pci_fixups_enable) = .; \ - *(.pci_fixup_enable) \ - VMLINUX_SYMBOL(__end_pci_fixups_enable) = .; \ - VMLINUX_SYMBOL(__start_pci_fixups_resume) = .; \ - *(.pci_fixup_resume) \ - VMLINUX_SYMBOL(__end_pci_fixups_resume) = .; \ - VMLINUX_SYMBOL(__start_pci_fixups_resume_early) = .; \ - *(.pci_fixup_resume_early) \ - VMLINUX_SYMBOL(__end_pci_fixups_resume_early) = .; \ - VMLINUX_SYMBOL(__start_pci_fixups_suspend) = .; \ - *(.pci_fixup_suspend) \ - VMLINUX_SYMBOL(__end_pci_fixups_suspend) = .; \ - VMLINUX_SYMBOL(__start_pci_fixups_suspend_late) = .; \ - *(.pci_fixup_suspend_late) \ - VMLINUX_SYMBOL(__end_pci_fixups_suspend_late) = .; \ - } \ - \ - /* Built-in firmware blobs */ \ - .builtin_fw : AT(ADDR(.builtin_fw) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start_builtin_fw) = .; \ - *(.builtin_fw) \ - VMLINUX_SYMBOL(__end_builtin_fw) = .; \ - } \ - \ - TRACEDATA \ - \ - /* Kernel symbol table: Normal symbols */ \ - __ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start___ksymtab) = .; \ - KEEP(*(SORT(___ksymtab+*))) \ - VMLINUX_SYMBOL(__stop___ksymtab) = .; \ - } \ - \ - /* Kernel symbol table: GPL-only symbols */ \ - __ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \ - KEEP(*(SORT(___ksymtab_gpl+*))) \ - VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \ - } \ - \ - /* Kernel symbol table: Normal unused symbols */ \ - __ksymtab_unused : AT(ADDR(__ksymtab_unused) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start___ksymtab_unused) = .; \ - KEEP(*(SORT(___ksymtab_unused+*))) \ - VMLINUX_SYMBOL(__stop___ksymtab_unused) = .; \ - } \ - \ - /* Kernel symbol table: GPL-only unused symbols */ \ - __ksymtab_unused_gpl : AT(ADDR(__ksymtab_unused_gpl) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start___ksymtab_unused_gpl) = .; \ - KEEP(*(SORT(___ksymtab_unused_gpl+*))) \ - VMLINUX_SYMBOL(__stop___ksymtab_unused_gpl) = .; \ - } \ - \ - /* Kernel symbol table: GPL-future-only symbols */ \ - __ksymtab_gpl_future : AT(ADDR(__ksymtab_gpl_future) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start___ksymtab_gpl_future) = .; \ - KEEP(*(SORT(___ksymtab_gpl_future+*))) \ - VMLINUX_SYMBOL(__stop___ksymtab_gpl_future) = .; \ - } \ - \ - /* Kernel symbol table: Normal symbols */ \ - __kcrctab : AT(ADDR(__kcrctab) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start___kcrctab) = .; \ - KEEP(*(SORT(___kcrctab+*))) \ - VMLINUX_SYMBOL(__stop___kcrctab) = .; \ - } \ - \ - /* Kernel symbol table: GPL-only symbols */ \ - __kcrctab_gpl : AT(ADDR(__kcrctab_gpl) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start___kcrctab_gpl) = .; \ - KEEP(*(SORT(___kcrctab_gpl+*))) \ - VMLINUX_SYMBOL(__stop___kcrctab_gpl) = .; \ - } \ - \ - /* Kernel symbol table: Normal unused symbols */ \ - __kcrctab_unused : AT(ADDR(__kcrctab_unused) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start___kcrctab_unused) = .; \ - KEEP(*(SORT(___kcrctab_unused+*))) \ - VMLINUX_SYMBOL(__stop___kcrctab_unused) = .; \ - } \ - \ - /* Kernel symbol table: GPL-only unused symbols */ \ - __kcrctab_unused_gpl : AT(ADDR(__kcrctab_unused_gpl) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start___kcrctab_unused_gpl) = .; \ - KEEP(*(SORT(___kcrctab_unused_gpl+*))) \ - VMLINUX_SYMBOL(__stop___kcrctab_unused_gpl) = .; \ - } \ - \ - /* Kernel symbol table: GPL-future-only symbols */ \ - __kcrctab_gpl_future : AT(ADDR(__kcrctab_gpl_future) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start___kcrctab_gpl_future) = .; \ - KEEP(*(SORT(___kcrctab_gpl_future+*))) \ - VMLINUX_SYMBOL(__stop___kcrctab_gpl_future) = .; \ - } \ - \ - /* Kernel symbol table: strings */ \ - __ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \ - KEEP(*(__ksymtab_strings)) \ - } \ - \ - /* __*init sections */ \ - __init_rodata : AT(ADDR(__init_rodata) - LOAD_OFFSET) { \ - *(.ref.rodata) \ - MEM_KEEP(init.rodata) \ - MEM_KEEP(exit.rodata) \ - } \ - \ - /* Built-in module parameters. */ \ - __param : AT(ADDR(__param) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start___param) = .; \ - *(__param) \ - VMLINUX_SYMBOL(__stop___param) = .; \ - } \ - \ - /* Built-in module versions. */ \ - __modver : AT(ADDR(__modver) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start___modver) = .; \ - *(__modver) \ - VMLINUX_SYMBOL(__stop___modver) = .; \ - . = ALIGN((align)); \ - VMLINUX_SYMBOL(__end_rodata) = .; \ - } \ - . = ALIGN((align)); - -/* RODATA & RO_DATA provided for backward compatibility. - * All archs are supposed to use RO_DATA() */ -#define RODATA RO_DATA_SECTION(4096) -#define RO_DATA(align) RO_DATA_SECTION(align) - -#define SECURITY_INIT \ - .security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__security_initcall_start) = .; \ - KEEP(*(.security_initcall.init)) \ - VMLINUX_SYMBOL(__security_initcall_end) = .; \ - } - -/* .text section. Map to function alignment to avoid address changes - * during second ld run in second ld pass when generating System.map - * LD_DEAD_CODE_DATA_ELIMINATION option enables -ffunction-sections generates - * .text.identifier which needs to be pulled in with .text , but some - * architectures define .text.foo which is not intended to be pulled in here. - * Those enabling LD_DEAD_CODE_DATA_ELIMINATION must ensure they don't have - * conflicting section names, and must pull in .text.[0-9a-zA-Z_]* */ -#define TEXT_TEXT \ - ALIGN_FUNCTION(); \ - *(.text.hot .text .text.fixup .text.unlikely) \ - *(.ref.text) \ - MEM_KEEP(init.text) \ - MEM_KEEP(exit.text) \ - - -/* sched.text is aling to function alignment to secure we have same - * address even at second ld pass when generating System.map */ -#define SCHED_TEXT \ - ALIGN_FUNCTION(); \ - VMLINUX_SYMBOL(__sched_text_start) = .; \ - *(.sched.text) \ - VMLINUX_SYMBOL(__sched_text_end) = .; - -/* spinlock.text is aling to function alignment to secure we have same - * address even at second ld pass when generating System.map */ -#define LOCK_TEXT \ - ALIGN_FUNCTION(); \ - VMLINUX_SYMBOL(__lock_text_start) = .; \ - *(.spinlock.text) \ - VMLINUX_SYMBOL(__lock_text_end) = .; - -#define CPUIDLE_TEXT \ - ALIGN_FUNCTION(); \ - VMLINUX_SYMBOL(__cpuidle_text_start) = .; \ - *(.cpuidle.text) \ - VMLINUX_SYMBOL(__cpuidle_text_end) = .; - -#define KPROBES_TEXT \ - ALIGN_FUNCTION(); \ - VMLINUX_SYMBOL(__kprobes_text_start) = .; \ - *(.kprobes.text) \ - VMLINUX_SYMBOL(__kprobes_text_end) = .; - -#define ENTRY_TEXT \ - ALIGN_FUNCTION(); \ - VMLINUX_SYMBOL(__entry_text_start) = .; \ - *(.entry.text) \ - VMLINUX_SYMBOL(__entry_text_end) = .; - -#if defined(CONFIG_FUNCTION_GRAPH_TRACER) || defined(CONFIG_KASAN) -#define IRQENTRY_TEXT \ - ALIGN_FUNCTION(); \ - VMLINUX_SYMBOL(__irqentry_text_start) = .; \ - *(.irqentry.text) \ - VMLINUX_SYMBOL(__irqentry_text_end) = .; -#else -#define IRQENTRY_TEXT -#endif - -#if defined(CONFIG_FUNCTION_GRAPH_TRACER) || defined(CONFIG_KASAN) -#define SOFTIRQENTRY_TEXT \ - ALIGN_FUNCTION(); \ - VMLINUX_SYMBOL(__softirqentry_text_start) = .; \ - *(.softirqentry.text) \ - VMLINUX_SYMBOL(__softirqentry_text_end) = .; -#else -#define SOFTIRQENTRY_TEXT -#endif - -/* Section used for early init (in .S files) */ -#define HEAD_TEXT *(.head.text) - -#define HEAD_TEXT_SECTION \ - .head.text : AT(ADDR(.head.text) - LOAD_OFFSET) { \ - HEAD_TEXT \ - } - -/* - * Exception table - */ -#define EXCEPTION_TABLE(align) \ - . = ALIGN(align); \ - __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start___ex_table) = .; \ - *(__ex_table) \ - VMLINUX_SYMBOL(__stop___ex_table) = .; \ - } - -/* - * Init task - */ -#define INIT_TASK_DATA_SECTION(align) \ - . = ALIGN(align); \ - .data..init_task : AT(ADDR(.data..init_task) - LOAD_OFFSET) { \ - INIT_TASK_DATA(align) \ - } - -#ifdef CONFIG_CONSTRUCTORS -#define KERNEL_CTORS() . = ALIGN(8); \ - VMLINUX_SYMBOL(__ctors_start) = .; \ - *(.ctors) \ - *(SORT(.init_array.*)) \ - *(.init_array) \ - VMLINUX_SYMBOL(__ctors_end) = .; -#else -#define KERNEL_CTORS() -#endif - -/* init and exit section handling */ -#define INIT_DATA \ - KEEP(*(SORT(___kentry+*))) \ - *(.init.data) \ - MEM_DISCARD(init.data) \ - KERNEL_CTORS() \ - MCOUNT_REC() \ - *(.init.rodata) \ - FTRACE_EVENTS() \ - TRACE_SYSCALLS() \ - KPROBE_BLACKLIST() \ - MEM_DISCARD(init.rodata) \ - CLK_OF_TABLES() \ - RESERVEDMEM_OF_TABLES() \ - CLKSRC_OF_TABLES() \ - IOMMU_OF_TABLES() \ - CPU_METHOD_OF_TABLES() \ - CPUIDLE_METHOD_OF_TABLES() \ - KERNEL_DTB() \ - IRQCHIP_OF_MATCH_TABLE() \ - ACPI_PROBE_TABLE(irqchip) \ - ACPI_PROBE_TABLE(clksrc) \ - EARLYCON_TABLE() - -#define INIT_TEXT \ - *(.init.text) \ - *(.text.startup) \ - MEM_DISCARD(init.text) - -#define EXIT_DATA \ - *(.exit.data) \ - *(.fini_array) \ - *(.dtors) \ - MEM_DISCARD(exit.data) \ - MEM_DISCARD(exit.rodata) - -#define EXIT_TEXT \ - *(.exit.text) \ - *(.text.exit) \ - MEM_DISCARD(exit.text) - -#define EXIT_CALL \ - *(.exitcall.exit) - -/* - * bss (Block Started by Symbol) - uninitialized data - * zeroed during startup - */ -#define SBSS(sbss_align) \ - . = ALIGN(sbss_align); \ - .sbss : AT(ADDR(.sbss) - LOAD_OFFSET) { \ - *(.sbss) \ - *(.scommon) \ - } - -/* - * Allow archectures to redefine BSS_FIRST_SECTIONS to add extra - * sections to the front of bss. - */ -#ifndef BSS_FIRST_SECTIONS -#define BSS_FIRST_SECTIONS -#endif - -#define BSS(bss_align) \ - . = ALIGN(bss_align); \ - .bss : AT(ADDR(.bss) - LOAD_OFFSET) { \ - BSS_FIRST_SECTIONS \ - *(.bss..page_aligned) \ - *(.dynbss) \ - *(.bss .bss.[0-9a-zA-Z_]*) \ - *(COMMON) \ - } - -/* - * DWARF debug sections. - * Symbols in the DWARF debugging sections are relative to - * the beginning of the section so we begin them at 0. - */ -#define DWARF_DEBUG \ - /* DWARF 1 */ \ - .debug 0 : { *(.debug) } \ - .line 0 : { *(.line) } \ - /* GNU DWARF 1 extensions */ \ - .debug_srcinfo 0 : { *(.debug_srcinfo) } \ - .debug_sfnames 0 : { *(.debug_sfnames) } \ - /* DWARF 1.1 and DWARF 2 */ \ - .debug_aranges 0 : { *(.debug_aranges) } \ - .debug_pubnames 0 : { *(.debug_pubnames) } \ - /* DWARF 2 */ \ - .debug_info 0 : { *(.debug_info \ - .gnu.linkonce.wi.*) } \ - .debug_abbrev 0 : { *(.debug_abbrev) } \ - .debug_line 0 : { *(.debug_line) } \ - .debug_frame 0 : { *(.debug_frame) } \ - .debug_str 0 : { *(.debug_str) } \ - .debug_loc 0 : { *(.debug_loc) } \ - .debug_macinfo 0 : { *(.debug_macinfo) } \ - /* SGI/MIPS DWARF 2 extensions */ \ - .debug_weaknames 0 : { *(.debug_weaknames) } \ - .debug_funcnames 0 : { *(.debug_funcnames) } \ - .debug_typenames 0 : { *(.debug_typenames) } \ - .debug_varnames 0 : { *(.debug_varnames) } \ - - /* Stabs debugging sections. */ -#define STABS_DEBUG \ - .stab 0 : { *(.stab) } \ - .stabstr 0 : { *(.stabstr) } \ - .stab.excl 0 : { *(.stab.excl) } \ - .stab.exclstr 0 : { *(.stab.exclstr) } \ - .stab.index 0 : { *(.stab.index) } \ - .stab.indexstr 0 : { *(.stab.indexstr) } \ - .comment 0 : { *(.comment) } - -#ifdef CONFIG_GENERIC_BUG -#define BUG_TABLE \ - . = ALIGN(8); \ - __bug_table : AT(ADDR(__bug_table) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start___bug_table) = .; \ - *(__bug_table) \ - VMLINUX_SYMBOL(__stop___bug_table) = .; \ - } -#else -#define BUG_TABLE -#endif - -#ifdef CONFIG_PM_TRACE -#define TRACEDATA \ - . = ALIGN(4); \ - .tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__tracedata_start) = .; \ - *(.tracedata) \ - VMLINUX_SYMBOL(__tracedata_end) = .; \ - } -#else -#define TRACEDATA -#endif - -#define NOTES \ - .notes : AT(ADDR(.notes) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__start_notes) = .; \ - *(.note.*) \ - VMLINUX_SYMBOL(__stop_notes) = .; \ - } - -#define INIT_SETUP(initsetup_align) \ - . = ALIGN(initsetup_align); \ - VMLINUX_SYMBOL(__setup_start) = .; \ - *(.init.setup) \ - VMLINUX_SYMBOL(__setup_end) = .; - -#define INIT_CALLS_LEVEL(level) \ - VMLINUX_SYMBOL(__initcall##level##_start) = .; \ - KEEP(*(.initcall##level##.init)) \ - KEEP(*(.initcall##level##s.init)) \ - -#define INIT_CALLS \ - VMLINUX_SYMBOL(__initcall_start) = .; \ - KEEP(*(.initcallearly.init)) \ - INIT_CALLS_LEVEL(0) \ - INIT_CALLS_LEVEL(1) \ - INIT_CALLS_LEVEL(2) \ - INIT_CALLS_LEVEL(3) \ - INIT_CALLS_LEVEL(4) \ - INIT_CALLS_LEVEL(5) \ - INIT_CALLS_LEVEL(rootfs) \ - INIT_CALLS_LEVEL(6) \ - INIT_CALLS_LEVEL(7) \ - VMLINUX_SYMBOL(__initcall_end) = .; - -#define CON_INITCALL \ - VMLINUX_SYMBOL(__con_initcall_start) = .; \ - KEEP(*(.con_initcall.init)) \ - VMLINUX_SYMBOL(__con_initcall_end) = .; - -#define SECURITY_INITCALL \ - VMLINUX_SYMBOL(__security_initcall_start) = .; \ - KEEP(*(.security_initcall.init)) \ - VMLINUX_SYMBOL(__security_initcall_end) = .; - -#ifdef CONFIG_BLK_DEV_INITRD -#define INIT_RAM_FS \ - . = ALIGN(4); \ - VMLINUX_SYMBOL(__initramfs_start) = .; \ - KEEP(*(.init.ramfs)) \ - . = ALIGN(8); \ - KEEP(*(.init.ramfs.info)) -#else -#define INIT_RAM_FS -#endif - -/* - * Default discarded sections. - * - * Some archs want to discard exit text/data at runtime rather than - * link time due to cross-section references such as alt instructions, - * bug table, eh_frame, etc. DISCARDS must be the last of output - * section definitions so that such archs put those in earlier section - * definitions. - */ -#define DISCARDS \ - /DISCARD/ : { \ - EXIT_TEXT \ - EXIT_DATA \ - EXIT_CALL \ - *(.discard) \ - *(.discard.*) \ - } - -/** - * PERCPU_INPUT - the percpu input sections - * @cacheline: cacheline size - * - * The core percpu section names and core symbols which do not rely - * directly upon load addresses. - * - * @cacheline is used to align subsections to avoid false cacheline - * sharing between subsections for different purposes. - */ -#define PERCPU_INPUT(cacheline) \ - VMLINUX_SYMBOL(__per_cpu_start) = .; \ - *(.data..percpu..first) \ - . = ALIGN(PAGE_SIZE); \ - *(.data..percpu..page_aligned) \ - . = ALIGN(cacheline); \ - *(.data..percpu..read_mostly) \ - . = ALIGN(cacheline); \ - *(.data..percpu) \ - *(.data..percpu..shared_aligned) \ - VMLINUX_SYMBOL(__per_cpu_end) = .; - -/** - * PERCPU_VADDR - define output section for percpu area - * @cacheline: cacheline size - * @vaddr: explicit base address (optional) - * @phdr: destination PHDR (optional) - * - * Macro which expands to output section for percpu area. - * - * @cacheline is used to align subsections to avoid false cacheline - * sharing between subsections for different purposes. - * - * If @vaddr is not blank, it specifies explicit base address and all - * percpu symbols will be offset from the given address. If blank, - * @vaddr always equals @laddr + LOAD_OFFSET. - * - * @phdr defines the output PHDR to use if not blank. Be warned that - * output PHDR is sticky. If @phdr is specified, the next output - * section in the linker script will go there too. @phdr should have - * a leading colon. - * - * Note that this macros defines __per_cpu_load as an absolute symbol. - * If there is no need to put the percpu section at a predetermined - * address, use PERCPU_SECTION. - */ -#define PERCPU_VADDR(cacheline, vaddr, phdr) \ - VMLINUX_SYMBOL(__per_cpu_load) = .; \ - .data..percpu vaddr : AT(VMLINUX_SYMBOL(__per_cpu_load) \ - - LOAD_OFFSET) { \ - PERCPU_INPUT(cacheline) \ - } phdr \ - . = VMLINUX_SYMBOL(__per_cpu_load) + SIZEOF(.data..percpu); - -/** - * PERCPU_SECTION - define output section for percpu area, simple version - * @cacheline: cacheline size - * - * Align to PAGE_SIZE and outputs output section for percpu area. This - * macro doesn't manipulate @vaddr or @phdr and __per_cpu_load and - * __per_cpu_start will be identical. - * - * This macro is equivalent to ALIGN(PAGE_SIZE); PERCPU_VADDR(@cacheline,,) - * except that __per_cpu_load is defined as a relative symbol against - * .data..percpu which is required for relocatable x86_32 configuration. - */ -#define PERCPU_SECTION(cacheline) \ - . = ALIGN(PAGE_SIZE); \ - .data..percpu : AT(ADDR(.data..percpu) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(__per_cpu_load) = .; \ - PERCPU_INPUT(cacheline) \ - } - - -/* - * Definition of the high level *_SECTION macros - * They will fit only a subset of the architectures - */ - - -/* - * Writeable data. - * All sections are combined in a single .data section. - * The sections following CONSTRUCTORS are arranged so their - * typical alignment matches. - * A cacheline is typical/always less than a PAGE_SIZE so - * the sections that has this restriction (or similar) - * is located before the ones requiring PAGE_SIZE alignment. - * NOSAVE_DATA starts and ends with a PAGE_SIZE alignment which - * matches the requirement of PAGE_ALIGNED_DATA. - * - * use 0 as page_align if page_aligned data is not used */ -#define RW_DATA_SECTION(cacheline, pagealigned, inittask) \ - . = ALIGN(PAGE_SIZE); \ - .data : AT(ADDR(.data) - LOAD_OFFSET) { \ - INIT_TASK_DATA(inittask) \ - NOSAVE_DATA \ - PAGE_ALIGNED_DATA(pagealigned) \ - CACHELINE_ALIGNED_DATA(cacheline) \ - READ_MOSTLY_DATA(cacheline) \ - DATA_DATA \ - CONSTRUCTORS \ - } - -#define INIT_TEXT_SECTION(inittext_align) \ - . = ALIGN(inittext_align); \ - .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { \ - VMLINUX_SYMBOL(_sinittext) = .; \ - INIT_TEXT \ - VMLINUX_SYMBOL(_einittext) = .; \ - } - -#define INIT_DATA_SECTION(initsetup_align) \ - .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { \ - INIT_DATA \ - INIT_SETUP(initsetup_align) \ - INIT_CALLS \ - CON_INITCALL \ - SECURITY_INITCALL \ - INIT_RAM_FS \ - } - -#define BSS_SECTION(sbss_align, bss_align, stop_align) \ - . = ALIGN(sbss_align); \ - VMLINUX_SYMBOL(__bss_start) = .; \ - SBSS(sbss_align) \ - BSS(bss_align) \ - . = ALIGN(stop_align); \ - VMLINUX_SYMBOL(__bss_stop) = .; diff --git a/src/linux/include/asm-generic/word-at-a-time.h b/src/linux/include/asm-generic/word-at-a-time.h deleted file mode 100644 index 011dde0..0000000 --- a/src/linux/include/asm-generic/word-at-a-time.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef _ASM_WORD_AT_A_TIME_H -#define _ASM_WORD_AT_A_TIME_H - -#include -#include - -#ifdef __BIG_ENDIAN - -struct word_at_a_time { - const unsigned long high_bits, low_bits; -}; - -#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0xfe) + 1, REPEAT_BYTE(0x7f) } - -/* Bit set in the bytes that have a zero */ -static inline long prep_zero_mask(unsigned long val, unsigned long rhs, const struct word_at_a_time *c) -{ - unsigned long mask = (val & c->low_bits) + c->low_bits; - return ~(mask | rhs); -} - -#define create_zero_mask(mask) (mask) - -static inline long find_zero(unsigned long mask) -{ - long byte = 0; -#ifdef CONFIG_64BIT - if (mask >> 32) - mask >>= 32; - else - byte = 4; -#endif - if (mask >> 16) - mask >>= 16; - else - byte += 2; - return (mask >> 8) ? byte : byte + 1; -} - -static inline bool has_zero(unsigned long val, unsigned long *data, const struct word_at_a_time *c) -{ - unsigned long rhs = val | c->low_bits; - *data = rhs; - return (val + c->high_bits) & ~rhs; -} - -#ifndef zero_bytemask -#define zero_bytemask(mask) (~1ul << __fls(mask)) -#endif - -#else - -/* - * The optimal byte mask counting is probably going to be something - * that is architecture-specific. If you have a reliably fast - * bit count instruction, that might be better than the multiply - * and shift, for example. - */ -struct word_at_a_time { - const unsigned long one_bits, high_bits; -}; - -#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) } - -#ifdef CONFIG_64BIT - -/* - * Jan Achrenius on G+: microoptimized version of - * the simpler "(mask & ONEBYTES) * ONEBYTES >> 56" - * that works for the bytemasks without having to - * mask them first. - */ -static inline long count_masked_bytes(unsigned long mask) -{ - return mask*0x0001020304050608ul >> 56; -} - -#else /* 32-bit case */ - -/* Carl Chatfield / Jan Achrenius G+ version for 32-bit */ -static inline long count_masked_bytes(long mask) -{ - /* (000000 0000ff 00ffff ffffff) -> ( 1 1 2 3 ) */ - long a = (0x0ff0001+mask) >> 23; - /* Fix the 1 for 00 case */ - return a & mask; -} - -#endif - -/* Return nonzero if it has a zero */ -static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c) -{ - unsigned long mask = ((a - c->one_bits) & ~a) & c->high_bits; - *bits = mask; - return mask; -} - -static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c) -{ - return bits; -} - -static inline unsigned long create_zero_mask(unsigned long bits) -{ - bits = (bits - 1) & ~bits; - return bits >> 7; -} - -/* The mask we created is directly usable as a bytemask */ -#define zero_bytemask(mask) (mask) - -static inline unsigned long find_zero(unsigned long mask) -{ - return count_masked_bytes(mask); -} - -#endif /* __BIG_ENDIAN */ - -#endif /* _ASM_WORD_AT_A_TIME_H */ diff --git a/src/linux/include/asm-generic/xor.h b/src/linux/include/asm-generic/xor.h deleted file mode 100644 index b4d8432..0000000 --- a/src/linux/include/asm-generic/xor.h +++ /dev/null @@ -1,718 +0,0 @@ -/* - * include/asm-generic/xor.h - * - * Generic optimized RAID-5 checksumming functions. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * You should have received a copy of the GNU General Public License - * (for example /usr/src/linux/COPYING); if not, write to the Free - * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include - -static void -xor_8regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) -{ - long lines = bytes / (sizeof (long)) / 8; - - do { - p1[0] ^= p2[0]; - p1[1] ^= p2[1]; - p1[2] ^= p2[2]; - p1[3] ^= p2[3]; - p1[4] ^= p2[4]; - p1[5] ^= p2[5]; - p1[6] ^= p2[6]; - p1[7] ^= p2[7]; - p1 += 8; - p2 += 8; - } while (--lines > 0); -} - -static void -xor_8regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, - unsigned long *p3) -{ - long lines = bytes / (sizeof (long)) / 8; - - do { - p1[0] ^= p2[0] ^ p3[0]; - p1[1] ^= p2[1] ^ p3[1]; - p1[2] ^= p2[2] ^ p3[2]; - p1[3] ^= p2[3] ^ p3[3]; - p1[4] ^= p2[4] ^ p3[4]; - p1[5] ^= p2[5] ^ p3[5]; - p1[6] ^= p2[6] ^ p3[6]; - p1[7] ^= p2[7] ^ p3[7]; - p1 += 8; - p2 += 8; - p3 += 8; - } while (--lines > 0); -} - -static void -xor_8regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, - unsigned long *p3, unsigned long *p4) -{ - long lines = bytes / (sizeof (long)) / 8; - - do { - p1[0] ^= p2[0] ^ p3[0] ^ p4[0]; - p1[1] ^= p2[1] ^ p3[1] ^ p4[1]; - p1[2] ^= p2[2] ^ p3[2] ^ p4[2]; - p1[3] ^= p2[3] ^ p3[3] ^ p4[3]; - p1[4] ^= p2[4] ^ p3[4] ^ p4[4]; - p1[5] ^= p2[5] ^ p3[5] ^ p4[5]; - p1[6] ^= p2[6] ^ p3[6] ^ p4[6]; - p1[7] ^= p2[7] ^ p3[7] ^ p4[7]; - p1 += 8; - p2 += 8; - p3 += 8; - p4 += 8; - } while (--lines > 0); -} - -static void -xor_8regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, - unsigned long *p3, unsigned long *p4, unsigned long *p5) -{ - long lines = bytes / (sizeof (long)) / 8; - - do { - p1[0] ^= p2[0] ^ p3[0] ^ p4[0] ^ p5[0]; - p1[1] ^= p2[1] ^ p3[1] ^ p4[1] ^ p5[1]; - p1[2] ^= p2[2] ^ p3[2] ^ p4[2] ^ p5[2]; - p1[3] ^= p2[3] ^ p3[3] ^ p4[3] ^ p5[3]; - p1[4] ^= p2[4] ^ p3[4] ^ p4[4] ^ p5[4]; - p1[5] ^= p2[5] ^ p3[5] ^ p4[5] ^ p5[5]; - p1[6] ^= p2[6] ^ p3[6] ^ p4[6] ^ p5[6]; - p1[7] ^= p2[7] ^ p3[7] ^ p4[7] ^ p5[7]; - p1 += 8; - p2 += 8; - p3 += 8; - p4 += 8; - p5 += 8; - } while (--lines > 0); -} - -static void -xor_32regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) -{ - long lines = bytes / (sizeof (long)) / 8; - - do { - register long d0, d1, d2, d3, d4, d5, d6, d7; - d0 = p1[0]; /* Pull the stuff into registers */ - d1 = p1[1]; /* ... in bursts, if possible. */ - d2 = p1[2]; - d3 = p1[3]; - d4 = p1[4]; - d5 = p1[5]; - d6 = p1[6]; - d7 = p1[7]; - d0 ^= p2[0]; - d1 ^= p2[1]; - d2 ^= p2[2]; - d3 ^= p2[3]; - d4 ^= p2[4]; - d5 ^= p2[5]; - d6 ^= p2[6]; - d7 ^= p2[7]; - p1[0] = d0; /* Store the result (in bursts) */ - p1[1] = d1; - p1[2] = d2; - p1[3] = d3; - p1[4] = d4; - p1[5] = d5; - p1[6] = d6; - p1[7] = d7; - p1 += 8; - p2 += 8; - } while (--lines > 0); -} - -static void -xor_32regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, - unsigned long *p3) -{ - long lines = bytes / (sizeof (long)) / 8; - - do { - register long d0, d1, d2, d3, d4, d5, d6, d7; - d0 = p1[0]; /* Pull the stuff into registers */ - d1 = p1[1]; /* ... in bursts, if possible. */ - d2 = p1[2]; - d3 = p1[3]; - d4 = p1[4]; - d5 = p1[5]; - d6 = p1[6]; - d7 = p1[7]; - d0 ^= p2[0]; - d1 ^= p2[1]; - d2 ^= p2[2]; - d3 ^= p2[3]; - d4 ^= p2[4]; - d5 ^= p2[5]; - d6 ^= p2[6]; - d7 ^= p2[7]; - d0 ^= p3[0]; - d1 ^= p3[1]; - d2 ^= p3[2]; - d3 ^= p3[3]; - d4 ^= p3[4]; - d5 ^= p3[5]; - d6 ^= p3[6]; - d7 ^= p3[7]; - p1[0] = d0; /* Store the result (in bursts) */ - p1[1] = d1; - p1[2] = d2; - p1[3] = d3; - p1[4] = d4; - p1[5] = d5; - p1[6] = d6; - p1[7] = d7; - p1 += 8; - p2 += 8; - p3 += 8; - } while (--lines > 0); -} - -static void -xor_32regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, - unsigned long *p3, unsigned long *p4) -{ - long lines = bytes / (sizeof (long)) / 8; - - do { - register long d0, d1, d2, d3, d4, d5, d6, d7; - d0 = p1[0]; /* Pull the stuff into registers */ - d1 = p1[1]; /* ... in bursts, if possible. */ - d2 = p1[2]; - d3 = p1[3]; - d4 = p1[4]; - d5 = p1[5]; - d6 = p1[6]; - d7 = p1[7]; - d0 ^= p2[0]; - d1 ^= p2[1]; - d2 ^= p2[2]; - d3 ^= p2[3]; - d4 ^= p2[4]; - d5 ^= p2[5]; - d6 ^= p2[6]; - d7 ^= p2[7]; - d0 ^= p3[0]; - d1 ^= p3[1]; - d2 ^= p3[2]; - d3 ^= p3[3]; - d4 ^= p3[4]; - d5 ^= p3[5]; - d6 ^= p3[6]; - d7 ^= p3[7]; - d0 ^= p4[0]; - d1 ^= p4[1]; - d2 ^= p4[2]; - d3 ^= p4[3]; - d4 ^= p4[4]; - d5 ^= p4[5]; - d6 ^= p4[6]; - d7 ^= p4[7]; - p1[0] = d0; /* Store the result (in bursts) */ - p1[1] = d1; - p1[2] = d2; - p1[3] = d3; - p1[4] = d4; - p1[5] = d5; - p1[6] = d6; - p1[7] = d7; - p1 += 8; - p2 += 8; - p3 += 8; - p4 += 8; - } while (--lines > 0); -} - -static void -xor_32regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, - unsigned long *p3, unsigned long *p4, unsigned long *p5) -{ - long lines = bytes / (sizeof (long)) / 8; - - do { - register long d0, d1, d2, d3, d4, d5, d6, d7; - d0 = p1[0]; /* Pull the stuff into registers */ - d1 = p1[1]; /* ... in bursts, if possible. */ - d2 = p1[2]; - d3 = p1[3]; - d4 = p1[4]; - d5 = p1[5]; - d6 = p1[6]; - d7 = p1[7]; - d0 ^= p2[0]; - d1 ^= p2[1]; - d2 ^= p2[2]; - d3 ^= p2[3]; - d4 ^= p2[4]; - d5 ^= p2[5]; - d6 ^= p2[6]; - d7 ^= p2[7]; - d0 ^= p3[0]; - d1 ^= p3[1]; - d2 ^= p3[2]; - d3 ^= p3[3]; - d4 ^= p3[4]; - d5 ^= p3[5]; - d6 ^= p3[6]; - d7 ^= p3[7]; - d0 ^= p4[0]; - d1 ^= p4[1]; - d2 ^= p4[2]; - d3 ^= p4[3]; - d4 ^= p4[4]; - d5 ^= p4[5]; - d6 ^= p4[6]; - d7 ^= p4[7]; - d0 ^= p5[0]; - d1 ^= p5[1]; - d2 ^= p5[2]; - d3 ^= p5[3]; - d4 ^= p5[4]; - d5 ^= p5[5]; - d6 ^= p5[6]; - d7 ^= p5[7]; - p1[0] = d0; /* Store the result (in bursts) */ - p1[1] = d1; - p1[2] = d2; - p1[3] = d3; - p1[4] = d4; - p1[5] = d5; - p1[6] = d6; - p1[7] = d7; - p1 += 8; - p2 += 8; - p3 += 8; - p4 += 8; - p5 += 8; - } while (--lines > 0); -} - -static void -xor_8regs_p_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) -{ - long lines = bytes / (sizeof (long)) / 8 - 1; - prefetchw(p1); - prefetch(p2); - - do { - prefetchw(p1+8); - prefetch(p2+8); - once_more: - p1[0] ^= p2[0]; - p1[1] ^= p2[1]; - p1[2] ^= p2[2]; - p1[3] ^= p2[3]; - p1[4] ^= p2[4]; - p1[5] ^= p2[5]; - p1[6] ^= p2[6]; - p1[7] ^= p2[7]; - p1 += 8; - p2 += 8; - } while (--lines > 0); - if (lines == 0) - goto once_more; -} - -static void -xor_8regs_p_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, - unsigned long *p3) -{ - long lines = bytes / (sizeof (long)) / 8 - 1; - prefetchw(p1); - prefetch(p2); - prefetch(p3); - - do { - prefetchw(p1+8); - prefetch(p2+8); - prefetch(p3+8); - once_more: - p1[0] ^= p2[0] ^ p3[0]; - p1[1] ^= p2[1] ^ p3[1]; - p1[2] ^= p2[2] ^ p3[2]; - p1[3] ^= p2[3] ^ p3[3]; - p1[4] ^= p2[4] ^ p3[4]; - p1[5] ^= p2[5] ^ p3[5]; - p1[6] ^= p2[6] ^ p3[6]; - p1[7] ^= p2[7] ^ p3[7]; - p1 += 8; - p2 += 8; - p3 += 8; - } while (--lines > 0); - if (lines == 0) - goto once_more; -} - -static void -xor_8regs_p_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, - unsigned long *p3, unsigned long *p4) -{ - long lines = bytes / (sizeof (long)) / 8 - 1; - - prefetchw(p1); - prefetch(p2); - prefetch(p3); - prefetch(p4); - - do { - prefetchw(p1+8); - prefetch(p2+8); - prefetch(p3+8); - prefetch(p4+8); - once_more: - p1[0] ^= p2[0] ^ p3[0] ^ p4[0]; - p1[1] ^= p2[1] ^ p3[1] ^ p4[1]; - p1[2] ^= p2[2] ^ p3[2] ^ p4[2]; - p1[3] ^= p2[3] ^ p3[3] ^ p4[3]; - p1[4] ^= p2[4] ^ p3[4] ^ p4[4]; - p1[5] ^= p2[5] ^ p3[5] ^ p4[5]; - p1[6] ^= p2[6] ^ p3[6] ^ p4[6]; - p1[7] ^= p2[7] ^ p3[7] ^ p4[7]; - p1 += 8; - p2 += 8; - p3 += 8; - p4 += 8; - } while (--lines > 0); - if (lines == 0) - goto once_more; -} - -static void -xor_8regs_p_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, - unsigned long *p3, unsigned long *p4, unsigned long *p5) -{ - long lines = bytes / (sizeof (long)) / 8 - 1; - - prefetchw(p1); - prefetch(p2); - prefetch(p3); - prefetch(p4); - prefetch(p5); - - do { - prefetchw(p1+8); - prefetch(p2+8); - prefetch(p3+8); - prefetch(p4+8); - prefetch(p5+8); - once_more: - p1[0] ^= p2[0] ^ p3[0] ^ p4[0] ^ p5[0]; - p1[1] ^= p2[1] ^ p3[1] ^ p4[1] ^ p5[1]; - p1[2] ^= p2[2] ^ p3[2] ^ p4[2] ^ p5[2]; - p1[3] ^= p2[3] ^ p3[3] ^ p4[3] ^ p5[3]; - p1[4] ^= p2[4] ^ p3[4] ^ p4[4] ^ p5[4]; - p1[5] ^= p2[5] ^ p3[5] ^ p4[5] ^ p5[5]; - p1[6] ^= p2[6] ^ p3[6] ^ p4[6] ^ p5[6]; - p1[7] ^= p2[7] ^ p3[7] ^ p4[7] ^ p5[7]; - p1 += 8; - p2 += 8; - p3 += 8; - p4 += 8; - p5 += 8; - } while (--lines > 0); - if (lines == 0) - goto once_more; -} - -static void -xor_32regs_p_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) -{ - long lines = bytes / (sizeof (long)) / 8 - 1; - - prefetchw(p1); - prefetch(p2); - - do { - register long d0, d1, d2, d3, d4, d5, d6, d7; - - prefetchw(p1+8); - prefetch(p2+8); - once_more: - d0 = p1[0]; /* Pull the stuff into registers */ - d1 = p1[1]; /* ... in bursts, if possible. */ - d2 = p1[2]; - d3 = p1[3]; - d4 = p1[4]; - d5 = p1[5]; - d6 = p1[6]; - d7 = p1[7]; - d0 ^= p2[0]; - d1 ^= p2[1]; - d2 ^= p2[2]; - d3 ^= p2[3]; - d4 ^= p2[4]; - d5 ^= p2[5]; - d6 ^= p2[6]; - d7 ^= p2[7]; - p1[0] = d0; /* Store the result (in bursts) */ - p1[1] = d1; - p1[2] = d2; - p1[3] = d3; - p1[4] = d4; - p1[5] = d5; - p1[6] = d6; - p1[7] = d7; - p1 += 8; - p2 += 8; - } while (--lines > 0); - if (lines == 0) - goto once_more; -} - -static void -xor_32regs_p_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, - unsigned long *p3) -{ - long lines = bytes / (sizeof (long)) / 8 - 1; - - prefetchw(p1); - prefetch(p2); - prefetch(p3); - - do { - register long d0, d1, d2, d3, d4, d5, d6, d7; - - prefetchw(p1+8); - prefetch(p2+8); - prefetch(p3+8); - once_more: - d0 = p1[0]; /* Pull the stuff into registers */ - d1 = p1[1]; /* ... in bursts, if possible. */ - d2 = p1[2]; - d3 = p1[3]; - d4 = p1[4]; - d5 = p1[5]; - d6 = p1[6]; - d7 = p1[7]; - d0 ^= p2[0]; - d1 ^= p2[1]; - d2 ^= p2[2]; - d3 ^= p2[3]; - d4 ^= p2[4]; - d5 ^= p2[5]; - d6 ^= p2[6]; - d7 ^= p2[7]; - d0 ^= p3[0]; - d1 ^= p3[1]; - d2 ^= p3[2]; - d3 ^= p3[3]; - d4 ^= p3[4]; - d5 ^= p3[5]; - d6 ^= p3[6]; - d7 ^= p3[7]; - p1[0] = d0; /* Store the result (in bursts) */ - p1[1] = d1; - p1[2] = d2; - p1[3] = d3; - p1[4] = d4; - p1[5] = d5; - p1[6] = d6; - p1[7] = d7; - p1 += 8; - p2 += 8; - p3 += 8; - } while (--lines > 0); - if (lines == 0) - goto once_more; -} - -static void -xor_32regs_p_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, - unsigned long *p3, unsigned long *p4) -{ - long lines = bytes / (sizeof (long)) / 8 - 1; - - prefetchw(p1); - prefetch(p2); - prefetch(p3); - prefetch(p4); - - do { - register long d0, d1, d2, d3, d4, d5, d6, d7; - - prefetchw(p1+8); - prefetch(p2+8); - prefetch(p3+8); - prefetch(p4+8); - once_more: - d0 = p1[0]; /* Pull the stuff into registers */ - d1 = p1[1]; /* ... in bursts, if possible. */ - d2 = p1[2]; - d3 = p1[3]; - d4 = p1[4]; - d5 = p1[5]; - d6 = p1[6]; - d7 = p1[7]; - d0 ^= p2[0]; - d1 ^= p2[1]; - d2 ^= p2[2]; - d3 ^= p2[3]; - d4 ^= p2[4]; - d5 ^= p2[5]; - d6 ^= p2[6]; - d7 ^= p2[7]; - d0 ^= p3[0]; - d1 ^= p3[1]; - d2 ^= p3[2]; - d3 ^= p3[3]; - d4 ^= p3[4]; - d5 ^= p3[5]; - d6 ^= p3[6]; - d7 ^= p3[7]; - d0 ^= p4[0]; - d1 ^= p4[1]; - d2 ^= p4[2]; - d3 ^= p4[3]; - d4 ^= p4[4]; - d5 ^= p4[5]; - d6 ^= p4[6]; - d7 ^= p4[7]; - p1[0] = d0; /* Store the result (in bursts) */ - p1[1] = d1; - p1[2] = d2; - p1[3] = d3; - p1[4] = d4; - p1[5] = d5; - p1[6] = d6; - p1[7] = d7; - p1 += 8; - p2 += 8; - p3 += 8; - p4 += 8; - } while (--lines > 0); - if (lines == 0) - goto once_more; -} - -static void -xor_32regs_p_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, - unsigned long *p3, unsigned long *p4, unsigned long *p5) -{ - long lines = bytes / (sizeof (long)) / 8 - 1; - - prefetchw(p1); - prefetch(p2); - prefetch(p3); - prefetch(p4); - prefetch(p5); - - do { - register long d0, d1, d2, d3, d4, d5, d6, d7; - - prefetchw(p1+8); - prefetch(p2+8); - prefetch(p3+8); - prefetch(p4+8); - prefetch(p5+8); - once_more: - d0 = p1[0]; /* Pull the stuff into registers */ - d1 = p1[1]; /* ... in bursts, if possible. */ - d2 = p1[2]; - d3 = p1[3]; - d4 = p1[4]; - d5 = p1[5]; - d6 = p1[6]; - d7 = p1[7]; - d0 ^= p2[0]; - d1 ^= p2[1]; - d2 ^= p2[2]; - d3 ^= p2[3]; - d4 ^= p2[4]; - d5 ^= p2[5]; - d6 ^= p2[6]; - d7 ^= p2[7]; - d0 ^= p3[0]; - d1 ^= p3[1]; - d2 ^= p3[2]; - d3 ^= p3[3]; - d4 ^= p3[4]; - d5 ^= p3[5]; - d6 ^= p3[6]; - d7 ^= p3[7]; - d0 ^= p4[0]; - d1 ^= p4[1]; - d2 ^= p4[2]; - d3 ^= p4[3]; - d4 ^= p4[4]; - d5 ^= p4[5]; - d6 ^= p4[6]; - d7 ^= p4[7]; - d0 ^= p5[0]; - d1 ^= p5[1]; - d2 ^= p5[2]; - d3 ^= p5[3]; - d4 ^= p5[4]; - d5 ^= p5[5]; - d6 ^= p5[6]; - d7 ^= p5[7]; - p1[0] = d0; /* Store the result (in bursts) */ - p1[1] = d1; - p1[2] = d2; - p1[3] = d3; - p1[4] = d4; - p1[5] = d5; - p1[6] = d6; - p1[7] = d7; - p1 += 8; - p2 += 8; - p3 += 8; - p4 += 8; - p5 += 8; - } while (--lines > 0); - if (lines == 0) - goto once_more; -} - -static struct xor_block_template xor_block_8regs = { - .name = "8regs", - .do_2 = xor_8regs_2, - .do_3 = xor_8regs_3, - .do_4 = xor_8regs_4, - .do_5 = xor_8regs_5, -}; - -static struct xor_block_template xor_block_32regs = { - .name = "32regs", - .do_2 = xor_32regs_2, - .do_3 = xor_32regs_3, - .do_4 = xor_32regs_4, - .do_5 = xor_32regs_5, -}; - -static struct xor_block_template xor_block_8regs_p __maybe_unused = { - .name = "8regs_prefetch", - .do_2 = xor_8regs_p_2, - .do_3 = xor_8regs_p_3, - .do_4 = xor_8regs_p_4, - .do_5 = xor_8regs_p_5, -}; - -static struct xor_block_template xor_block_32regs_p __maybe_unused = { - .name = "32regs_prefetch", - .do_2 = xor_32regs_p_2, - .do_3 = xor_32regs_p_3, - .do_4 = xor_32regs_p_4, - .do_5 = xor_32regs_p_5, -}; - -#define XOR_TRY_TEMPLATES \ - do { \ - xor_speed(&xor_block_8regs); \ - xor_speed(&xor_block_8regs_p); \ - xor_speed(&xor_block_32regs); \ - xor_speed(&xor_block_32regs_p); \ - } while (0) diff --git a/src/linux/include/crypto/aead.h b/src/linux/include/crypto/aead.h deleted file mode 100644 index 12f8432..0000000 --- a/src/linux/include/crypto/aead.h +++ /dev/null @@ -1,536 +0,0 @@ -/* - * AEAD: Authenticated Encryption with Associated Data - * - * Copyright (c) 2007-2015 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#ifndef _CRYPTO_AEAD_H -#define _CRYPTO_AEAD_H - -#include -#include -#include - -/** - * DOC: Authenticated Encryption With Associated Data (AEAD) Cipher API - * - * The AEAD cipher API is used with the ciphers of type CRYPTO_ALG_TYPE_AEAD - * (listed as type "aead" in /proc/crypto) - * - * The most prominent examples for this type of encryption is GCM and CCM. - * However, the kernel supports other types of AEAD ciphers which are defined - * with the following cipher string: - * - * authenc(keyed message digest, block cipher) - * - * For example: authenc(hmac(sha256), cbc(aes)) - * - * The example code provided for the symmetric key cipher operation - * applies here as well. Naturally all *skcipher* symbols must be exchanged - * the *aead* pendants discussed in the following. In addition, for the AEAD - * operation, the aead_request_set_ad function must be used to set the - * pointer to the associated data memory location before performing the - * encryption or decryption operation. In case of an encryption, the associated - * data memory is filled during the encryption operation. For decryption, the - * associated data memory must contain data that is used to verify the integrity - * of the decrypted data. Another deviation from the asynchronous block cipher - * operation is that the caller should explicitly check for -EBADMSG of the - * crypto_aead_decrypt. That error indicates an authentication error, i.e. - * a breach in the integrity of the message. In essence, that -EBADMSG error - * code is the key bonus an AEAD cipher has over "standard" block chaining - * modes. - * - * Memory Structure: - * - * To support the needs of the most prominent user of AEAD ciphers, namely - * IPSEC, the AEAD ciphers have a special memory layout the caller must adhere - * to. - * - * The scatter list pointing to the input data must contain: - * - * * for RFC4106 ciphers, the concatenation of - * associated authentication data || IV || plaintext or ciphertext. Note, the - * same IV (buffer) is also set with the aead_request_set_crypt call. Note, - * the API call of aead_request_set_ad must provide the length of the AAD and - * the IV. The API call of aead_request_set_crypt only points to the size of - * the input plaintext or ciphertext. - * - * * for "normal" AEAD ciphers, the concatenation of - * associated authentication data || plaintext or ciphertext. - * - * It is important to note that if multiple scatter gather list entries form - * the input data mentioned above, the first entry must not point to a NULL - * buffer. If there is any potential where the AAD buffer can be NULL, the - * calling code must contain a precaution to ensure that this does not result - * in the first scatter gather list entry pointing to a NULL buffer. - */ - -struct crypto_aead; - -/** - * struct aead_request - AEAD request - * @base: Common attributes for async crypto requests - * @assoclen: Length in bytes of associated data for authentication - * @cryptlen: Length of data to be encrypted or decrypted - * @iv: Initialisation vector - * @src: Source data - * @dst: Destination data - * @__ctx: Start of private context data - */ -struct aead_request { - struct crypto_async_request base; - - unsigned int assoclen; - unsigned int cryptlen; - - u8 *iv; - - struct scatterlist *src; - struct scatterlist *dst; - - void *__ctx[] CRYPTO_MINALIGN_ATTR; -}; - -/** - * struct aead_alg - AEAD cipher definition - * @maxauthsize: Set the maximum authentication tag size supported by the - * transformation. A transformation may support smaller tag sizes. - * As the authentication tag is a message digest to ensure the - * integrity of the encrypted data, a consumer typically wants the - * largest authentication tag possible as defined by this - * variable. - * @setauthsize: Set authentication size for the AEAD transformation. This - * function is used to specify the consumer requested size of the - * authentication tag to be either generated by the transformation - * during encryption or the size of the authentication tag to be - * supplied during the decryption operation. This function is also - * responsible for checking the authentication tag size for - * validity. - * @setkey: see struct skcipher_alg - * @encrypt: see struct skcipher_alg - * @decrypt: see struct skcipher_alg - * @geniv: see struct skcipher_alg - * @ivsize: see struct skcipher_alg - * @chunksize: see struct skcipher_alg - * @init: Initialize the cryptographic transformation object. This function - * is used to initialize the cryptographic transformation object. - * This function is called only once at the instantiation time, right - * after the transformation context was allocated. In case the - * cryptographic hardware has some special requirements which need to - * be handled by software, this function shall check for the precise - * requirement of the transformation and put any software fallbacks - * in place. - * @exit: Deinitialize the cryptographic transformation object. This is a - * counterpart to @init, used to remove various changes set in - * @init. - * @base: Definition of a generic crypto cipher algorithm. - * - * All fields except @ivsize is mandatory and must be filled. - */ -struct aead_alg { - int (*setkey)(struct crypto_aead *tfm, const u8 *key, - unsigned int keylen); - int (*setauthsize)(struct crypto_aead *tfm, unsigned int authsize); - int (*encrypt)(struct aead_request *req); - int (*decrypt)(struct aead_request *req); - int (*init)(struct crypto_aead *tfm); - void (*exit)(struct crypto_aead *tfm); - - const char *geniv; - - unsigned int ivsize; - unsigned int maxauthsize; - unsigned int chunksize; - - struct crypto_alg base; -}; - -struct crypto_aead { - unsigned int authsize; - unsigned int reqsize; - - struct crypto_tfm base; -}; - -static inline struct crypto_aead *__crypto_aead_cast(struct crypto_tfm *tfm) -{ - return container_of(tfm, struct crypto_aead, base); -} - -/** - * crypto_alloc_aead() - allocate AEAD cipher handle - * @alg_name: is the cra_name / name or cra_driver_name / driver name of the - * AEAD cipher - * @type: specifies the type of the cipher - * @mask: specifies the mask for the cipher - * - * Allocate a cipher handle for an AEAD. The returned struct - * crypto_aead is the cipher handle that is required for any subsequent - * API invocation for that AEAD. - * - * Return: allocated cipher handle in case of success; IS_ERR() is true in case - * of an error, PTR_ERR() returns the error code. - */ -struct crypto_aead *crypto_alloc_aead(const char *alg_name, u32 type, u32 mask); - -static inline struct crypto_tfm *crypto_aead_tfm(struct crypto_aead *tfm) -{ - return &tfm->base; -} - -/** - * crypto_free_aead() - zeroize and free aead handle - * @tfm: cipher handle to be freed - */ -static inline void crypto_free_aead(struct crypto_aead *tfm) -{ - crypto_destroy_tfm(tfm, crypto_aead_tfm(tfm)); -} - -static inline struct aead_alg *crypto_aead_alg(struct crypto_aead *tfm) -{ - return container_of(crypto_aead_tfm(tfm)->__crt_alg, - struct aead_alg, base); -} - -static inline unsigned int crypto_aead_alg_ivsize(struct aead_alg *alg) -{ - return alg->ivsize; -} - -/** - * crypto_aead_ivsize() - obtain IV size - * @tfm: cipher handle - * - * The size of the IV for the aead referenced by the cipher handle is - * returned. This IV size may be zero if the cipher does not need an IV. - * - * Return: IV size in bytes - */ -static inline unsigned int crypto_aead_ivsize(struct crypto_aead *tfm) -{ - return crypto_aead_alg_ivsize(crypto_aead_alg(tfm)); -} - -/** - * crypto_aead_authsize() - obtain maximum authentication data size - * @tfm: cipher handle - * - * The maximum size of the authentication data for the AEAD cipher referenced - * by the AEAD cipher handle is returned. The authentication data size may be - * zero if the cipher implements a hard-coded maximum. - * - * The authentication data may also be known as "tag value". - * - * Return: authentication data size / tag size in bytes - */ -static inline unsigned int crypto_aead_authsize(struct crypto_aead *tfm) -{ - return tfm->authsize; -} - -/** - * crypto_aead_blocksize() - obtain block size of cipher - * @tfm: cipher handle - * - * The block size for the AEAD referenced with the cipher handle is returned. - * The caller may use that information to allocate appropriate memory for the - * data returned by the encryption or decryption operation - * - * Return: block size of cipher - */ -static inline unsigned int crypto_aead_blocksize(struct crypto_aead *tfm) -{ - return crypto_tfm_alg_blocksize(crypto_aead_tfm(tfm)); -} - -static inline unsigned int crypto_aead_alignmask(struct crypto_aead *tfm) -{ - return crypto_tfm_alg_alignmask(crypto_aead_tfm(tfm)); -} - -static inline u32 crypto_aead_get_flags(struct crypto_aead *tfm) -{ - return crypto_tfm_get_flags(crypto_aead_tfm(tfm)); -} - -static inline void crypto_aead_set_flags(struct crypto_aead *tfm, u32 flags) -{ - crypto_tfm_set_flags(crypto_aead_tfm(tfm), flags); -} - -static inline void crypto_aead_clear_flags(struct crypto_aead *tfm, u32 flags) -{ - crypto_tfm_clear_flags(crypto_aead_tfm(tfm), flags); -} - -/** - * crypto_aead_setkey() - set key for cipher - * @tfm: cipher handle - * @key: buffer holding the key - * @keylen: length of the key in bytes - * - * The caller provided key is set for the AEAD referenced by the cipher - * handle. - * - * Note, the key length determines the cipher type. Many block ciphers implement - * different cipher modes depending on the key size, such as AES-128 vs AES-192 - * vs. AES-256. When providing a 16 byte key for an AES cipher handle, AES-128 - * is performed. - * - * Return: 0 if the setting of the key was successful; < 0 if an error occurred - */ -int crypto_aead_setkey(struct crypto_aead *tfm, - const u8 *key, unsigned int keylen); - -/** - * crypto_aead_setauthsize() - set authentication data size - * @tfm: cipher handle - * @authsize: size of the authentication data / tag in bytes - * - * Set the authentication data size / tag size. AEAD requires an authentication - * tag (or MAC) in addition to the associated data. - * - * Return: 0 if the setting of the key was successful; < 0 if an error occurred - */ -int crypto_aead_setauthsize(struct crypto_aead *tfm, unsigned int authsize); - -static inline struct crypto_aead *crypto_aead_reqtfm(struct aead_request *req) -{ - return __crypto_aead_cast(req->base.tfm); -} - -/** - * crypto_aead_encrypt() - encrypt plaintext - * @req: reference to the aead_request handle that holds all information - * needed to perform the cipher operation - * - * Encrypt plaintext data using the aead_request handle. That data structure - * and how it is filled with data is discussed with the aead_request_* - * functions. - * - * IMPORTANT NOTE The encryption operation creates the authentication data / - * tag. That data is concatenated with the created ciphertext. - * The ciphertext memory size is therefore the given number of - * block cipher blocks + the size defined by the - * crypto_aead_setauthsize invocation. The caller must ensure - * that sufficient memory is available for the ciphertext and - * the authentication tag. - * - * Return: 0 if the cipher operation was successful; < 0 if an error occurred - */ -static inline int crypto_aead_encrypt(struct aead_request *req) -{ - return crypto_aead_alg(crypto_aead_reqtfm(req))->encrypt(req); -} - -/** - * crypto_aead_decrypt() - decrypt ciphertext - * @req: reference to the ablkcipher_request handle that holds all information - * needed to perform the cipher operation - * - * Decrypt ciphertext data using the aead_request handle. That data structure - * and how it is filled with data is discussed with the aead_request_* - * functions. - * - * IMPORTANT NOTE The caller must concatenate the ciphertext followed by the - * authentication data / tag. That authentication data / tag - * must have the size defined by the crypto_aead_setauthsize - * invocation. - * - * - * Return: 0 if the cipher operation was successful; -EBADMSG: The AEAD - * cipher operation performs the authentication of the data during the - * decryption operation. Therefore, the function returns this error if - * the authentication of the ciphertext was unsuccessful (i.e. the - * integrity of the ciphertext or the associated data was violated); - * < 0 if an error occurred. - */ -static inline int crypto_aead_decrypt(struct aead_request *req) -{ - struct crypto_aead *aead = crypto_aead_reqtfm(req); - - if (req->cryptlen < crypto_aead_authsize(aead)) - return -EINVAL; - - return crypto_aead_alg(aead)->decrypt(req); -} - -/** - * DOC: Asynchronous AEAD Request Handle - * - * The aead_request data structure contains all pointers to data required for - * the AEAD cipher operation. This includes the cipher handle (which can be - * used by multiple aead_request instances), pointer to plaintext and - * ciphertext, asynchronous callback function, etc. It acts as a handle to the - * aead_request_* API calls in a similar way as AEAD handle to the - * crypto_aead_* API calls. - */ - -/** - * crypto_aead_reqsize() - obtain size of the request data structure - * @tfm: cipher handle - * - * Return: number of bytes - */ -static inline unsigned int crypto_aead_reqsize(struct crypto_aead *tfm) -{ - return tfm->reqsize; -} - -/** - * aead_request_set_tfm() - update cipher handle reference in request - * @req: request handle to be modified - * @tfm: cipher handle that shall be added to the request handle - * - * Allow the caller to replace the existing aead handle in the request - * data structure with a different one. - */ -static inline void aead_request_set_tfm(struct aead_request *req, - struct crypto_aead *tfm) -{ - req->base.tfm = crypto_aead_tfm(tfm); -} - -/** - * aead_request_alloc() - allocate request data structure - * @tfm: cipher handle to be registered with the request - * @gfp: memory allocation flag that is handed to kmalloc by the API call. - * - * Allocate the request data structure that must be used with the AEAD - * encrypt and decrypt API calls. During the allocation, the provided aead - * handle is registered in the request data structure. - * - * Return: allocated request handle in case of success, or NULL if out of memory - */ -static inline struct aead_request *aead_request_alloc(struct crypto_aead *tfm, - gfp_t gfp) -{ - struct aead_request *req; - - req = kmalloc(sizeof(*req) + crypto_aead_reqsize(tfm), gfp); - - if (likely(req)) - aead_request_set_tfm(req, tfm); - - return req; -} - -/** - * aead_request_free() - zeroize and free request data structure - * @req: request data structure cipher handle to be freed - */ -static inline void aead_request_free(struct aead_request *req) -{ - kzfree(req); -} - -/** - * aead_request_set_callback() - set asynchronous callback function - * @req: request handle - * @flags: specify zero or an ORing of the flags - * CRYPTO_TFM_REQ_MAY_BACKLOG the request queue may back log and - * increase the wait queue beyond the initial maximum size; - * CRYPTO_TFM_REQ_MAY_SLEEP the request processing may sleep - * @compl: callback function pointer to be registered with the request handle - * @data: The data pointer refers to memory that is not used by the kernel - * crypto API, but provided to the callback function for it to use. Here, - * the caller can provide a reference to memory the callback function can - * operate on. As the callback function is invoked asynchronously to the - * related functionality, it may need to access data structures of the - * related functionality which can be referenced using this pointer. The - * callback function can access the memory via the "data" field in the - * crypto_async_request data structure provided to the callback function. - * - * Setting the callback function that is triggered once the cipher operation - * completes - * - * The callback function is registered with the aead_request handle and - * must comply with the following template - * - * void callback_function(struct crypto_async_request *req, int error) - */ -static inline void aead_request_set_callback(struct aead_request *req, - u32 flags, - crypto_completion_t compl, - void *data) -{ - req->base.complete = compl; - req->base.data = data; - req->base.flags = flags; -} - -/** - * aead_request_set_crypt - set data buffers - * @req: request handle - * @src: source scatter / gather list - * @dst: destination scatter / gather list - * @cryptlen: number of bytes to process from @src - * @iv: IV for the cipher operation which must comply with the IV size defined - * by crypto_aead_ivsize() - * - * Setting the source data and destination data scatter / gather lists which - * hold the associated data concatenated with the plaintext or ciphertext. See - * below for the authentication tag. - * - * For encryption, the source is treated as the plaintext and the - * destination is the ciphertext. For a decryption operation, the use is - * reversed - the source is the ciphertext and the destination is the plaintext. - * - * For both src/dst the layout is associated data, plain/cipher text, - * authentication tag. - * - * The content of the AD in the destination buffer after processing - * will either be untouched, or it will contain a copy of the AD - * from the source buffer. In order to ensure that it always has - * a copy of the AD, the user must copy the AD over either before - * or after processing. Of course this is not relevant if the user - * is doing in-place processing where src == dst. - * - * IMPORTANT NOTE AEAD requires an authentication tag (MAC). For decryption, - * the caller must concatenate the ciphertext followed by the - * authentication tag and provide the entire data stream to the - * decryption operation (i.e. the data length used for the - * initialization of the scatterlist and the data length for the - * decryption operation is identical). For encryption, however, - * the authentication tag is created while encrypting the data. - * The destination buffer must hold sufficient space for the - * ciphertext and the authentication tag while the encryption - * invocation must only point to the plaintext data size. The - * following code snippet illustrates the memory usage - * buffer = kmalloc(ptbuflen + (enc ? authsize : 0)); - * sg_init_one(&sg, buffer, ptbuflen + (enc ? authsize : 0)); - * aead_request_set_crypt(req, &sg, &sg, ptbuflen, iv); - */ -static inline void aead_request_set_crypt(struct aead_request *req, - struct scatterlist *src, - struct scatterlist *dst, - unsigned int cryptlen, u8 *iv) -{ - req->src = src; - req->dst = dst; - req->cryptlen = cryptlen; - req->iv = iv; -} - -/** - * aead_request_set_ad - set associated data information - * @req: request handle - * @assoclen: number of bytes in associated data - * - * Setting the AD information. This function sets the length of - * the associated data. - */ -static inline void aead_request_set_ad(struct aead_request *req, - unsigned int assoclen) -{ - req->assoclen = assoclen; -} - -#endif /* _CRYPTO_AEAD_H */ diff --git a/src/linux/include/crypto/aes.h b/src/linux/include/crypto/aes.h deleted file mode 100644 index 7524ba3..0000000 --- a/src/linux/include/crypto/aes.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Common values for AES algorithms - */ - -#ifndef _CRYPTO_AES_H -#define _CRYPTO_AES_H - -#include -#include - -#define AES_MIN_KEY_SIZE 16 -#define AES_MAX_KEY_SIZE 32 -#define AES_KEYSIZE_128 16 -#define AES_KEYSIZE_192 24 -#define AES_KEYSIZE_256 32 -#define AES_BLOCK_SIZE 16 -#define AES_MAX_KEYLENGTH (15 * 16) -#define AES_MAX_KEYLENGTH_U32 (AES_MAX_KEYLENGTH / sizeof(u32)) - -/* - * Please ensure that the first two fields are 16-byte aligned - * relative to the start of the structure, i.e., don't move them! - */ -struct crypto_aes_ctx { - u32 key_enc[AES_MAX_KEYLENGTH_U32]; - u32 key_dec[AES_MAX_KEYLENGTH_U32]; - u32 key_length; -}; - -extern const u32 crypto_ft_tab[4][256]; -extern const u32 crypto_fl_tab[4][256]; -extern const u32 crypto_it_tab[4][256]; -extern const u32 crypto_il_tab[4][256]; - -int crypto_aes_set_key(struct crypto_tfm *tfm, const u8 *in_key, - unsigned int key_len); -int crypto_aes_expand_key(struct crypto_aes_ctx *ctx, const u8 *in_key, - unsigned int key_len); -#endif diff --git a/src/linux/include/crypto/akcipher.h b/src/linux/include/crypto/akcipher.h deleted file mode 100644 index c37cc59..0000000 --- a/src/linux/include/crypto/akcipher.h +++ /dev/null @@ -1,386 +0,0 @@ -/* - * Public Key Encryption - * - * Copyright (c) 2015, Intel Corporation - * Authors: Tadeusz Struk - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ -#ifndef _CRYPTO_AKCIPHER_H -#define _CRYPTO_AKCIPHER_H -#include - -/** - * struct akcipher_request - public key request - * - * @base: Common attributes for async crypto requests - * @src: Source data - * @dst: Destination data - * @src_len: Size of the input buffer - * @dst_len: Size of the output buffer. It needs to be at least - * as big as the expected result depending on the operation - * After operation it will be updated with the actual size of the - * result. - * In case of error where the dst sgl size was insufficient, - * it will be updated to the size required for the operation. - * @__ctx: Start of private context data - */ -struct akcipher_request { - struct crypto_async_request base; - struct scatterlist *src; - struct scatterlist *dst; - unsigned int src_len; - unsigned int dst_len; - void *__ctx[] CRYPTO_MINALIGN_ATTR; -}; - -/** - * struct crypto_akcipher - user-instantiated objects which encapsulate - * algorithms and core processing logic - * - * @base: Common crypto API algorithm data structure - */ -struct crypto_akcipher { - struct crypto_tfm base; -}; - -/** - * struct akcipher_alg - generic public key algorithm - * - * @sign: Function performs a sign operation as defined by public key - * algorithm. In case of error, where the dst_len was insufficient, - * the req->dst_len will be updated to the size required for the - * operation - * @verify: Function performs a sign operation as defined by public key - * algorithm. In case of error, where the dst_len was insufficient, - * the req->dst_len will be updated to the size required for the - * operation - * @encrypt: Function performs an encrypt operation as defined by public key - * algorithm. In case of error, where the dst_len was insufficient, - * the req->dst_len will be updated to the size required for the - * operation - * @decrypt: Function performs a decrypt operation as defined by public key - * algorithm. In case of error, where the dst_len was insufficient, - * the req->dst_len will be updated to the size required for the - * operation - * @set_pub_key: Function invokes the algorithm specific set public key - * function, which knows how to decode and interpret - * the BER encoded public key - * @set_priv_key: Function invokes the algorithm specific set private key - * function, which knows how to decode and interpret - * the BER encoded private key - * @max_size: Function returns dest buffer size required for a given key. - * @init: Initialize the cryptographic transformation object. - * This function is used to initialize the cryptographic - * transformation object. This function is called only once at - * the instantiation time, right after the transformation context - * was allocated. In case the cryptographic hardware has some - * special requirements which need to be handled by software, this - * function shall check for the precise requirement of the - * transformation and put any software fallbacks in place. - * @exit: Deinitialize the cryptographic transformation object. This is a - * counterpart to @init, used to remove various changes set in - * @init. - * - * @reqsize: Request context size required by algorithm implementation - * @base: Common crypto API algorithm data structure - */ -struct akcipher_alg { - int (*sign)(struct akcipher_request *req); - int (*verify)(struct akcipher_request *req); - int (*encrypt)(struct akcipher_request *req); - int (*decrypt)(struct akcipher_request *req); - int (*set_pub_key)(struct crypto_akcipher *tfm, const void *key, - unsigned int keylen); - int (*set_priv_key)(struct crypto_akcipher *tfm, const void *key, - unsigned int keylen); - int (*max_size)(struct crypto_akcipher *tfm); - int (*init)(struct crypto_akcipher *tfm); - void (*exit)(struct crypto_akcipher *tfm); - - unsigned int reqsize; - struct crypto_alg base; -}; - -/** - * DOC: Generic Public Key API - * - * The Public Key API is used with the algorithms of type - * CRYPTO_ALG_TYPE_AKCIPHER (listed as type "akcipher" in /proc/crypto) - */ - -/** - * crypto_alloc_akcipher() - allocate AKCIPHER tfm handle - * @alg_name: is the cra_name / name or cra_driver_name / driver name of the - * public key algorithm e.g. "rsa" - * @type: specifies the type of the algorithm - * @mask: specifies the mask for the algorithm - * - * Allocate a handle for public key algorithm. The returned struct - * crypto_akcipher is the handle that is required for any subsequent - * API invocation for the public key operations. - * - * Return: allocated handle in case of success; IS_ERR() is true in case - * of an error, PTR_ERR() returns the error code. - */ -struct crypto_akcipher *crypto_alloc_akcipher(const char *alg_name, u32 type, - u32 mask); - -static inline struct crypto_tfm *crypto_akcipher_tfm( - struct crypto_akcipher *tfm) -{ - return &tfm->base; -} - -static inline struct akcipher_alg *__crypto_akcipher_alg(struct crypto_alg *alg) -{ - return container_of(alg, struct akcipher_alg, base); -} - -static inline struct crypto_akcipher *__crypto_akcipher_tfm( - struct crypto_tfm *tfm) -{ - return container_of(tfm, struct crypto_akcipher, base); -} - -static inline struct akcipher_alg *crypto_akcipher_alg( - struct crypto_akcipher *tfm) -{ - return __crypto_akcipher_alg(crypto_akcipher_tfm(tfm)->__crt_alg); -} - -static inline unsigned int crypto_akcipher_reqsize(struct crypto_akcipher *tfm) -{ - return crypto_akcipher_alg(tfm)->reqsize; -} - -static inline void akcipher_request_set_tfm(struct akcipher_request *req, - struct crypto_akcipher *tfm) -{ - req->base.tfm = crypto_akcipher_tfm(tfm); -} - -static inline struct crypto_akcipher *crypto_akcipher_reqtfm( - struct akcipher_request *req) -{ - return __crypto_akcipher_tfm(req->base.tfm); -} - -/** - * crypto_free_akcipher() - free AKCIPHER tfm handle - * - * @tfm: AKCIPHER tfm handle allocated with crypto_alloc_akcipher() - */ -static inline void crypto_free_akcipher(struct crypto_akcipher *tfm) -{ - crypto_destroy_tfm(tfm, crypto_akcipher_tfm(tfm)); -} - -/** - * akcipher_request_alloc() - allocates public key request - * - * @tfm: AKCIPHER tfm handle allocated with crypto_alloc_akcipher() - * @gfp: allocation flags - * - * Return: allocated handle in case of success or NULL in case of an error. - */ -static inline struct akcipher_request *akcipher_request_alloc( - struct crypto_akcipher *tfm, gfp_t gfp) -{ - struct akcipher_request *req; - - req = kmalloc(sizeof(*req) + crypto_akcipher_reqsize(tfm), gfp); - if (likely(req)) - akcipher_request_set_tfm(req, tfm); - - return req; -} - -/** - * akcipher_request_free() - zeroize and free public key request - * - * @req: request to free - */ -static inline void akcipher_request_free(struct akcipher_request *req) -{ - kzfree(req); -} - -/** - * akcipher_request_set_callback() - Sets an asynchronous callback. - * - * Callback will be called when an asynchronous operation on a given - * request is finished. - * - * @req: request that the callback will be set for - * @flgs: specify for instance if the operation may backlog - * @cmpl: callback which will be called - * @data: private data used by the caller - */ -static inline void akcipher_request_set_callback(struct akcipher_request *req, - u32 flgs, - crypto_completion_t cmpl, - void *data) -{ - req->base.complete = cmpl; - req->base.data = data; - req->base.flags = flgs; -} - -/** - * akcipher_request_set_crypt() - Sets request parameters - * - * Sets parameters required by crypto operation - * - * @req: public key request - * @src: ptr to input scatter list - * @dst: ptr to output scatter list - * @src_len: size of the src input scatter list to be processed - * @dst_len: size of the dst output scatter list - */ -static inline void akcipher_request_set_crypt(struct akcipher_request *req, - struct scatterlist *src, - struct scatterlist *dst, - unsigned int src_len, - unsigned int dst_len) -{ - req->src = src; - req->dst = dst; - req->src_len = src_len; - req->dst_len = dst_len; -} - -/** - * crypto_akcipher_maxsize() - Get len for output buffer - * - * Function returns the dest buffer size required for a given key - * - * @tfm: AKCIPHER tfm handle allocated with crypto_alloc_akcipher() - * - * Return: minimum len for output buffer or error code in key hasn't been set - */ -static inline int crypto_akcipher_maxsize(struct crypto_akcipher *tfm) -{ - struct akcipher_alg *alg = crypto_akcipher_alg(tfm); - - return alg->max_size(tfm); -} - -/** - * crypto_akcipher_encrypt() - Invoke public key encrypt operation - * - * Function invokes the specific public key encrypt operation for a given - * public key algorithm - * - * @req: asymmetric key request - * - * Return: zero on success; error code in case of error - */ -static inline int crypto_akcipher_encrypt(struct akcipher_request *req) -{ - struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); - struct akcipher_alg *alg = crypto_akcipher_alg(tfm); - - return alg->encrypt(req); -} - -/** - * crypto_akcipher_decrypt() - Invoke public key decrypt operation - * - * Function invokes the specific public key decrypt operation for a given - * public key algorithm - * - * @req: asymmetric key request - * - * Return: zero on success; error code in case of error - */ -static inline int crypto_akcipher_decrypt(struct akcipher_request *req) -{ - struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); - struct akcipher_alg *alg = crypto_akcipher_alg(tfm); - - return alg->decrypt(req); -} - -/** - * crypto_akcipher_sign() - Invoke public key sign operation - * - * Function invokes the specific public key sign operation for a given - * public key algorithm - * - * @req: asymmetric key request - * - * Return: zero on success; error code in case of error - */ -static inline int crypto_akcipher_sign(struct akcipher_request *req) -{ - struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); - struct akcipher_alg *alg = crypto_akcipher_alg(tfm); - - return alg->sign(req); -} - -/** - * crypto_akcipher_verify() - Invoke public key verify operation - * - * Function invokes the specific public key verify operation for a given - * public key algorithm - * - * @req: asymmetric key request - * - * Return: zero on success; error code in case of error - */ -static inline int crypto_akcipher_verify(struct akcipher_request *req) -{ - struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); - struct akcipher_alg *alg = crypto_akcipher_alg(tfm); - - return alg->verify(req); -} - -/** - * crypto_akcipher_set_pub_key() - Invoke set public key operation - * - * Function invokes the algorithm specific set key function, which knows - * how to decode and interpret the encoded key - * - * @tfm: tfm handle - * @key: BER encoded public key - * @keylen: length of the key - * - * Return: zero on success; error code in case of error - */ -static inline int crypto_akcipher_set_pub_key(struct crypto_akcipher *tfm, - const void *key, - unsigned int keylen) -{ - struct akcipher_alg *alg = crypto_akcipher_alg(tfm); - - return alg->set_pub_key(tfm, key, keylen); -} - -/** - * crypto_akcipher_set_priv_key() - Invoke set private key operation - * - * Function invokes the algorithm specific set key function, which knows - * how to decode and interpret the encoded key - * - * @tfm: tfm handle - * @key: BER encoded private key - * @keylen: length of the key - * - * Return: zero on success; error code in case of error - */ -static inline int crypto_akcipher_set_priv_key(struct crypto_akcipher *tfm, - const void *key, - unsigned int keylen) -{ - struct akcipher_alg *alg = crypto_akcipher_alg(tfm); - - return alg->set_priv_key(tfm, key, keylen); -} -#endif diff --git a/src/linux/include/crypto/algapi.h b/src/linux/include/crypto/algapi.h deleted file mode 100644 index 404e955..0000000 --- a/src/linux/include/crypto/algapi.h +++ /dev/null @@ -1,381 +0,0 @@ -/* - * Cryptographic API for algorithms (i.e., low-level API). - * - * Copyright (c) 2006 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ -#ifndef _CRYPTO_ALGAPI_H -#define _CRYPTO_ALGAPI_H - -#include -#include -#include -#include - -struct crypto_aead; -struct crypto_instance; -struct module; -struct rtattr; -struct seq_file; - -struct crypto_type { - unsigned int (*ctxsize)(struct crypto_alg *alg, u32 type, u32 mask); - unsigned int (*extsize)(struct crypto_alg *alg); - int (*init)(struct crypto_tfm *tfm, u32 type, u32 mask); - int (*init_tfm)(struct crypto_tfm *tfm); - void (*show)(struct seq_file *m, struct crypto_alg *alg); - int (*report)(struct sk_buff *skb, struct crypto_alg *alg); - struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask); - void (*free)(struct crypto_instance *inst); - - unsigned int type; - unsigned int maskclear; - unsigned int maskset; - unsigned int tfmsize; -}; - -struct crypto_instance { - struct crypto_alg alg; - - struct crypto_template *tmpl; - struct hlist_node list; - - void *__ctx[] CRYPTO_MINALIGN_ATTR; -}; - -struct crypto_template { - struct list_head list; - struct hlist_head instances; - struct module *module; - - struct crypto_instance *(*alloc)(struct rtattr **tb); - void (*free)(struct crypto_instance *inst); - int (*create)(struct crypto_template *tmpl, struct rtattr **tb); - - char name[CRYPTO_MAX_ALG_NAME]; -}; - -struct crypto_spawn { - struct list_head list; - struct crypto_alg *alg; - struct crypto_instance *inst; - const struct crypto_type *frontend; - u32 mask; -}; - -struct crypto_queue { - struct list_head list; - struct list_head *backlog; - - unsigned int qlen; - unsigned int max_qlen; -}; - -struct scatter_walk { - struct scatterlist *sg; - unsigned int offset; -}; - -struct blkcipher_walk { - union { - struct { - struct page *page; - unsigned long offset; - } phys; - - struct { - u8 *page; - u8 *addr; - } virt; - } src, dst; - - struct scatter_walk in; - unsigned int nbytes; - - struct scatter_walk out; - unsigned int total; - - void *page; - u8 *buffer; - u8 *iv; - unsigned int ivsize; - - int flags; - unsigned int walk_blocksize; - unsigned int cipher_blocksize; - unsigned int alignmask; -}; - -struct ablkcipher_walk { - struct { - struct page *page; - unsigned int offset; - } src, dst; - - struct scatter_walk in; - unsigned int nbytes; - struct scatter_walk out; - unsigned int total; - struct list_head buffers; - u8 *iv_buffer; - u8 *iv; - int flags; - unsigned int blocksize; -}; - -extern const struct crypto_type crypto_ablkcipher_type; -extern const struct crypto_type crypto_blkcipher_type; - -void crypto_mod_put(struct crypto_alg *alg); - -int crypto_register_template(struct crypto_template *tmpl); -void crypto_unregister_template(struct crypto_template *tmpl); -struct crypto_template *crypto_lookup_template(const char *name); - -int crypto_register_instance(struct crypto_template *tmpl, - struct crypto_instance *inst); -int crypto_unregister_instance(struct crypto_instance *inst); - -int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg, - struct crypto_instance *inst, u32 mask); -int crypto_init_spawn2(struct crypto_spawn *spawn, struct crypto_alg *alg, - struct crypto_instance *inst, - const struct crypto_type *frontend); -int crypto_grab_spawn(struct crypto_spawn *spawn, const char *name, - u32 type, u32 mask); - -void crypto_drop_spawn(struct crypto_spawn *spawn); -struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type, - u32 mask); -void *crypto_spawn_tfm2(struct crypto_spawn *spawn); - -static inline void crypto_set_spawn(struct crypto_spawn *spawn, - struct crypto_instance *inst) -{ - spawn->inst = inst; -} - -struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb); -int crypto_check_attr_type(struct rtattr **tb, u32 type); -const char *crypto_attr_alg_name(struct rtattr *rta); -struct crypto_alg *crypto_attr_alg2(struct rtattr *rta, - const struct crypto_type *frontend, - u32 type, u32 mask); - -static inline struct crypto_alg *crypto_attr_alg(struct rtattr *rta, - u32 type, u32 mask) -{ - return crypto_attr_alg2(rta, NULL, type, mask); -} - -int crypto_attr_u32(struct rtattr *rta, u32 *num); -int crypto_inst_setname(struct crypto_instance *inst, const char *name, - struct crypto_alg *alg); -void *crypto_alloc_instance2(const char *name, struct crypto_alg *alg, - unsigned int head); -struct crypto_instance *crypto_alloc_instance(const char *name, - struct crypto_alg *alg); - -void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen); -int crypto_enqueue_request(struct crypto_queue *queue, - struct crypto_async_request *request); -struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue); -int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm); -static inline unsigned int crypto_queue_len(struct crypto_queue *queue) -{ - return queue->qlen; -} - -/* These functions require the input/output to be aligned as u32. */ -void crypto_inc(u8 *a, unsigned int size); -void crypto_xor(u8 *dst, const u8 *src, unsigned int size); - -int blkcipher_walk_done(struct blkcipher_desc *desc, - struct blkcipher_walk *walk, int err); -int blkcipher_walk_virt(struct blkcipher_desc *desc, - struct blkcipher_walk *walk); -int blkcipher_walk_phys(struct blkcipher_desc *desc, - struct blkcipher_walk *walk); -int blkcipher_walk_virt_block(struct blkcipher_desc *desc, - struct blkcipher_walk *walk, - unsigned int blocksize); -int blkcipher_aead_walk_virt_block(struct blkcipher_desc *desc, - struct blkcipher_walk *walk, - struct crypto_aead *tfm, - unsigned int blocksize); - -int ablkcipher_walk_done(struct ablkcipher_request *req, - struct ablkcipher_walk *walk, int err); -int ablkcipher_walk_phys(struct ablkcipher_request *req, - struct ablkcipher_walk *walk); -void __ablkcipher_walk_complete(struct ablkcipher_walk *walk); - -static inline void *crypto_tfm_ctx_aligned(struct crypto_tfm *tfm) -{ - return PTR_ALIGN(crypto_tfm_ctx(tfm), - crypto_tfm_alg_alignmask(tfm) + 1); -} - -static inline struct crypto_instance *crypto_tfm_alg_instance( - struct crypto_tfm *tfm) -{ - return container_of(tfm->__crt_alg, struct crypto_instance, alg); -} - -static inline void *crypto_instance_ctx(struct crypto_instance *inst) -{ - return inst->__ctx; -} - -static inline struct ablkcipher_alg *crypto_ablkcipher_alg( - struct crypto_ablkcipher *tfm) -{ - return &crypto_ablkcipher_tfm(tfm)->__crt_alg->cra_ablkcipher; -} - -static inline void *crypto_ablkcipher_ctx(struct crypto_ablkcipher *tfm) -{ - return crypto_tfm_ctx(&tfm->base); -} - -static inline void *crypto_ablkcipher_ctx_aligned(struct crypto_ablkcipher *tfm) -{ - return crypto_tfm_ctx_aligned(&tfm->base); -} - -static inline struct crypto_blkcipher *crypto_spawn_blkcipher( - struct crypto_spawn *spawn) -{ - u32 type = CRYPTO_ALG_TYPE_BLKCIPHER; - u32 mask = CRYPTO_ALG_TYPE_MASK; - - return __crypto_blkcipher_cast(crypto_spawn_tfm(spawn, type, mask)); -} - -static inline void *crypto_blkcipher_ctx(struct crypto_blkcipher *tfm) -{ - return crypto_tfm_ctx(&tfm->base); -} - -static inline void *crypto_blkcipher_ctx_aligned(struct crypto_blkcipher *tfm) -{ - return crypto_tfm_ctx_aligned(&tfm->base); -} - -static inline struct crypto_cipher *crypto_spawn_cipher( - struct crypto_spawn *spawn) -{ - u32 type = CRYPTO_ALG_TYPE_CIPHER; - u32 mask = CRYPTO_ALG_TYPE_MASK; - - return __crypto_cipher_cast(crypto_spawn_tfm(spawn, type, mask)); -} - -static inline struct cipher_alg *crypto_cipher_alg(struct crypto_cipher *tfm) -{ - return &crypto_cipher_tfm(tfm)->__crt_alg->cra_cipher; -} - -static inline void blkcipher_walk_init(struct blkcipher_walk *walk, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - walk->in.sg = src; - walk->out.sg = dst; - walk->total = nbytes; -} - -static inline void ablkcipher_walk_init(struct ablkcipher_walk *walk, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - walk->in.sg = src; - walk->out.sg = dst; - walk->total = nbytes; - INIT_LIST_HEAD(&walk->buffers); -} - -static inline void ablkcipher_walk_complete(struct ablkcipher_walk *walk) -{ - if (unlikely(!list_empty(&walk->buffers))) - __ablkcipher_walk_complete(walk); -} - -static inline struct crypto_async_request *crypto_get_backlog( - struct crypto_queue *queue) -{ - return queue->backlog == &queue->list ? NULL : - container_of(queue->backlog, struct crypto_async_request, list); -} - -static inline int ablkcipher_enqueue_request(struct crypto_queue *queue, - struct ablkcipher_request *request) -{ - return crypto_enqueue_request(queue, &request->base); -} - -static inline struct ablkcipher_request *ablkcipher_dequeue_request( - struct crypto_queue *queue) -{ - return ablkcipher_request_cast(crypto_dequeue_request(queue)); -} - -static inline void *ablkcipher_request_ctx(struct ablkcipher_request *req) -{ - return req->__ctx; -} - -static inline int ablkcipher_tfm_in_queue(struct crypto_queue *queue, - struct crypto_ablkcipher *tfm) -{ - return crypto_tfm_in_queue(queue, crypto_ablkcipher_tfm(tfm)); -} - -static inline struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, - u32 type, u32 mask) -{ - return crypto_attr_alg(tb[1], type, mask); -} - -/* - * Returns CRYPTO_ALG_ASYNC if type/mask requires the use of sync algorithms. - * Otherwise returns zero. - */ -static inline int crypto_requires_sync(u32 type, u32 mask) -{ - return (type ^ CRYPTO_ALG_ASYNC) & mask & CRYPTO_ALG_ASYNC; -} - -noinline unsigned long __crypto_memneq(const void *a, const void *b, size_t size); - -/** - * crypto_memneq - Compare two areas of memory without leaking - * timing information. - * - * @a: One area of memory - * @b: Another area of memory - * @size: The size of the area. - * - * Returns 0 when data is equal, 1 otherwise. - */ -static inline int crypto_memneq(const void *a, const void *b, size_t size) -{ - return __crypto_memneq(a, b, size) != 0UL ? 1 : 0; -} - -static inline void crypto_yield(u32 flags) -{ -#if !defined(CONFIG_PREEMPT) || defined(CONFIG_PREEMPT_VOLUNTARY) - if (flags & CRYPTO_TFM_REQ_MAY_SLEEP) - cond_resched(); -#endif -} - -#endif /* _CRYPTO_ALGAPI_H */ diff --git a/src/linux/include/crypto/chacha20.h b/src/linux/include/crypto/chacha20.h deleted file mode 100644 index 20d20f6..0000000 --- a/src/linux/include/crypto/chacha20.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * Common values for the ChaCha20 algorithm - */ - -#ifndef _CRYPTO_CHACHA20_H -#define _CRYPTO_CHACHA20_H - -#include -#include - -#define CHACHA20_IV_SIZE 16 -#define CHACHA20_KEY_SIZE 32 -#define CHACHA20_BLOCK_SIZE 64 - -struct chacha20_ctx { - u32 key[8]; -}; - -void chacha20_block(u32 *state, void *stream); -void crypto_chacha20_init(u32 *state, struct chacha20_ctx *ctx, u8 *iv); -int crypto_chacha20_setkey(struct crypto_tfm *tfm, const u8 *key, - unsigned int keysize); -int crypto_chacha20_crypt(struct blkcipher_desc *desc, struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes); - -#endif diff --git a/src/linux/include/crypto/crypto_wq.h b/src/linux/include/crypto/crypto_wq.h deleted file mode 100644 index a7d252d..0000000 --- a/src/linux/include/crypto/crypto_wq.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef CRYPTO_WQ_H -#define CRYPTO_WQ_H - -#include - -extern struct workqueue_struct *kcrypto_wq; -#endif diff --git a/src/linux/include/crypto/drbg.h b/src/linux/include/crypto/drbg.h deleted file mode 100644 index 22f884c..0000000 --- a/src/linux/include/crypto/drbg.h +++ /dev/null @@ -1,285 +0,0 @@ -/* - * DRBG based on NIST SP800-90A - * - * Copyright Stephan Mueller , 2014 - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, and the entire permission notice in its entirety, - * including the disclaimer of warranties. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * ALTERNATIVELY, this product may be distributed under the terms of - * the GNU General Public License, in which case the provisions of the GPL are - * required INSTEAD OF the above restrictions. (This clause is - * necessary due to a potential bad interaction between the GPL and - * the restrictions contained in a BSD-style copyright.) - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF - * WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - * USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - */ - -#ifndef _DRBG_H -#define _DRBG_H - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Concatenation Helper and string operation helper - * - * SP800-90A requires the concatenation of different data. To avoid copying - * buffers around or allocate additional memory, the following data structure - * is used to point to the original memory with its size. In addition, it - * is used to build a linked list. The linked list defines the concatenation - * of individual buffers. The order of memory block referenced in that - * linked list determines the order of concatenation. - */ -struct drbg_string { - const unsigned char *buf; - size_t len; - struct list_head list; -}; - -static inline void drbg_string_fill(struct drbg_string *string, - const unsigned char *buf, size_t len) -{ - string->buf = buf; - string->len = len; - INIT_LIST_HEAD(&string->list); -} - -struct drbg_state; -typedef uint32_t drbg_flag_t; - -struct drbg_core { - drbg_flag_t flags; /* flags for the cipher */ - __u8 statelen; /* maximum state length */ - __u8 blocklen_bytes; /* block size of output in bytes */ - char cra_name[CRYPTO_MAX_ALG_NAME]; /* mapping to kernel crypto API */ - /* kernel crypto API backend cipher name */ - char backend_cra_name[CRYPTO_MAX_ALG_NAME]; -}; - -struct drbg_state_ops { - int (*update)(struct drbg_state *drbg, struct list_head *seed, - int reseed); - int (*generate)(struct drbg_state *drbg, - unsigned char *buf, unsigned int buflen, - struct list_head *addtl); - int (*crypto_init)(struct drbg_state *drbg); - int (*crypto_fini)(struct drbg_state *drbg); - -}; - -struct drbg_test_data { - struct drbg_string *testentropy; /* TEST PARAMETER: test entropy */ -}; - -struct drbg_state { - struct mutex drbg_mutex; /* lock around DRBG */ - unsigned char *V; /* internal state 10.1.1.1 1a) */ - unsigned char *Vbuf; - /* hash: static value 10.1.1.1 1b) hmac / ctr: key */ - unsigned char *C; - unsigned char *Cbuf; - /* Number of RNG requests since last reseed -- 10.1.1.1 1c) */ - size_t reseed_ctr; - size_t reseed_threshold; - /* some memory the DRBG can use for its operation */ - unsigned char *scratchpad; - unsigned char *scratchpadbuf; - void *priv_data; /* Cipher handle */ - - struct crypto_skcipher *ctr_handle; /* CTR mode cipher handle */ - struct skcipher_request *ctr_req; /* CTR mode request handle */ - __u8 *ctr_null_value_buf; /* CTR mode unaligned buffer */ - __u8 *ctr_null_value; /* CTR mode aligned zero buf */ - __u8 *outscratchpadbuf; /* CTR mode output scratchpad */ - __u8 *outscratchpad; /* CTR mode aligned outbuf */ - struct completion ctr_completion; /* CTR mode async handler */ - int ctr_async_err; /* CTR mode async error */ - - bool seeded; /* DRBG fully seeded? */ - bool pr; /* Prediction resistance enabled? */ - struct work_struct seed_work; /* asynchronous seeding support */ - struct crypto_rng *jent; - const struct drbg_state_ops *d_ops; - const struct drbg_core *core; - struct drbg_string test_data; - struct random_ready_callback random_ready; -}; - -static inline __u8 drbg_statelen(struct drbg_state *drbg) -{ - if (drbg && drbg->core) - return drbg->core->statelen; - return 0; -} - -static inline __u8 drbg_blocklen(struct drbg_state *drbg) -{ - if (drbg && drbg->core) - return drbg->core->blocklen_bytes; - return 0; -} - -static inline __u8 drbg_keylen(struct drbg_state *drbg) -{ - if (drbg && drbg->core) - return (drbg->core->statelen - drbg->core->blocklen_bytes); - return 0; -} - -static inline size_t drbg_max_request_bytes(struct drbg_state *drbg) -{ - /* SP800-90A requires the limit 2**19 bits, but we return bytes */ - return (1 << 16); -} - -static inline size_t drbg_max_addtl(struct drbg_state *drbg) -{ - /* SP800-90A requires 2**35 bytes additional info str / pers str */ -#if (__BITS_PER_LONG == 32) - /* - * SP800-90A allows smaller maximum numbers to be returned -- we - * return SIZE_MAX - 1 to allow the verification of the enforcement - * of this value in drbg_healthcheck_sanity. - */ - return (SIZE_MAX - 1); -#else - return (1UL<<35); -#endif -} - -static inline size_t drbg_max_requests(struct drbg_state *drbg) -{ - /* SP800-90A requires 2**48 maximum requests before reseeding */ -#if (__BITS_PER_LONG == 32) - return SIZE_MAX; -#else - return (1UL<<48); -#endif -} - -/* - * This is a wrapper to the kernel crypto API function of - * crypto_rng_generate() to allow the caller to provide additional data. - * - * @drng DRBG handle -- see crypto_rng_get_bytes - * @outbuf output buffer -- see crypto_rng_get_bytes - * @outlen length of output buffer -- see crypto_rng_get_bytes - * @addtl_input additional information string input buffer - * @addtllen length of additional information string buffer - * - * return - * see crypto_rng_get_bytes - */ -static inline int crypto_drbg_get_bytes_addtl(struct crypto_rng *drng, - unsigned char *outbuf, unsigned int outlen, - struct drbg_string *addtl) -{ - return crypto_rng_generate(drng, addtl->buf, addtl->len, - outbuf, outlen); -} - -/* - * TEST code - * - * This is a wrapper to the kernel crypto API function of - * crypto_rng_generate() to allow the caller to provide additional data and - * allow furnishing of test_data - * - * @drng DRBG handle -- see crypto_rng_get_bytes - * @outbuf output buffer -- see crypto_rng_get_bytes - * @outlen length of output buffer -- see crypto_rng_get_bytes - * @addtl_input additional information string input buffer - * @addtllen length of additional information string buffer - * @test_data filled test data - * - * return - * see crypto_rng_get_bytes - */ -static inline int crypto_drbg_get_bytes_addtl_test(struct crypto_rng *drng, - unsigned char *outbuf, unsigned int outlen, - struct drbg_string *addtl, - struct drbg_test_data *test_data) -{ - crypto_rng_set_entropy(drng, test_data->testentropy->buf, - test_data->testentropy->len); - return crypto_rng_generate(drng, addtl->buf, addtl->len, - outbuf, outlen); -} - -/* - * TEST code - * - * This is a wrapper to the kernel crypto API function of - * crypto_rng_reset() to allow the caller to provide test_data - * - * @drng DRBG handle -- see crypto_rng_reset - * @pers personalization string input buffer - * @perslen length of additional information string buffer - * @test_data filled test data - * - * return - * see crypto_rng_reset - */ -static inline int crypto_drbg_reset_test(struct crypto_rng *drng, - struct drbg_string *pers, - struct drbg_test_data *test_data) -{ - crypto_rng_set_entropy(drng, test_data->testentropy->buf, - test_data->testentropy->len); - return crypto_rng_reset(drng, pers->buf, pers->len); -} - -/* DRBG type flags */ -#define DRBG_CTR ((drbg_flag_t)1<<0) -#define DRBG_HMAC ((drbg_flag_t)1<<1) -#define DRBG_HASH ((drbg_flag_t)1<<2) -#define DRBG_TYPE_MASK (DRBG_CTR | DRBG_HMAC | DRBG_HASH) -/* DRBG strength flags */ -#define DRBG_STRENGTH128 ((drbg_flag_t)1<<3) -#define DRBG_STRENGTH192 ((drbg_flag_t)1<<4) -#define DRBG_STRENGTH256 ((drbg_flag_t)1<<5) -#define DRBG_STRENGTH_MASK (DRBG_STRENGTH128 | DRBG_STRENGTH192 | \ - DRBG_STRENGTH256) - -enum drbg_prefixes { - DRBG_PREFIX0 = 0x00, - DRBG_PREFIX1, - DRBG_PREFIX2, - DRBG_PREFIX3 -}; - -#endif /* _DRBG_H */ diff --git a/src/linux/include/crypto/hash.h b/src/linux/include/crypto/hash.h deleted file mode 100644 index 2660588..0000000 --- a/src/linux/include/crypto/hash.h +++ /dev/null @@ -1,919 +0,0 @@ -/* - * Hash: Hash algorithms under the crypto API - * - * Copyright (c) 2008 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#ifndef _CRYPTO_HASH_H -#define _CRYPTO_HASH_H - -#include -#include - -struct crypto_ahash; - -/** - * DOC: Message Digest Algorithm Definitions - * - * These data structures define modular message digest algorithm - * implementations, managed via crypto_register_ahash(), - * crypto_register_shash(), crypto_unregister_ahash() and - * crypto_unregister_shash(). - */ - -/** - * struct hash_alg_common - define properties of message digest - * @digestsize: Size of the result of the transformation. A buffer of this size - * must be available to the @final and @finup calls, so they can - * store the resulting hash into it. For various predefined sizes, - * search include/crypto/ using - * git grep _DIGEST_SIZE include/crypto. - * @statesize: Size of the block for partial state of the transformation. A - * buffer of this size must be passed to the @export function as it - * will save the partial state of the transformation into it. On the - * other side, the @import function will load the state from a - * buffer of this size as well. - * @base: Start of data structure of cipher algorithm. The common data - * structure of crypto_alg contains information common to all ciphers. - * The hash_alg_common data structure now adds the hash-specific - * information. - */ -struct hash_alg_common { - unsigned int digestsize; - unsigned int statesize; - - struct crypto_alg base; -}; - -struct ahash_request { - struct crypto_async_request base; - - unsigned int nbytes; - struct scatterlist *src; - u8 *result; - - /* This field may only be used by the ahash API code. */ - void *priv; - - void *__ctx[] CRYPTO_MINALIGN_ATTR; -}; - -#define AHASH_REQUEST_ON_STACK(name, ahash) \ - char __##name##_desc[sizeof(struct ahash_request) + \ - crypto_ahash_reqsize(ahash)] CRYPTO_MINALIGN_ATTR; \ - struct ahash_request *name = (void *)__##name##_desc - -/** - * struct ahash_alg - asynchronous message digest definition - * @init: Initialize the transformation context. Intended only to initialize the - * state of the HASH transformation at the beginning. This shall fill in - * the internal structures used during the entire duration of the whole - * transformation. No data processing happens at this point. - * @update: Push a chunk of data into the driver for transformation. This - * function actually pushes blocks of data from upper layers into the - * driver, which then passes those to the hardware as seen fit. This - * function must not finalize the HASH transformation by calculating the - * final message digest as this only adds more data into the - * transformation. This function shall not modify the transformation - * context, as this function may be called in parallel with the same - * transformation object. Data processing can happen synchronously - * [SHASH] or asynchronously [AHASH] at this point. - * @final: Retrieve result from the driver. This function finalizes the - * transformation and retrieves the resulting hash from the driver and - * pushes it back to upper layers. No data processing happens at this - * point. - * @finup: Combination of @update and @final. This function is effectively a - * combination of @update and @final calls issued in sequence. As some - * hardware cannot do @update and @final separately, this callback was - * added to allow such hardware to be used at least by IPsec. Data - * processing can happen synchronously [SHASH] or asynchronously [AHASH] - * at this point. - * @digest: Combination of @init and @update and @final. This function - * effectively behaves as the entire chain of operations, @init, - * @update and @final issued in sequence. Just like @finup, this was - * added for hardware which cannot do even the @finup, but can only do - * the whole transformation in one run. Data processing can happen - * synchronously [SHASH] or asynchronously [AHASH] at this point. - * @setkey: Set optional key used by the hashing algorithm. Intended to push - * optional key used by the hashing algorithm from upper layers into - * the driver. This function can store the key in the transformation - * context or can outright program it into the hardware. In the former - * case, one must be careful to program the key into the hardware at - * appropriate time and one must be careful that .setkey() can be - * called multiple times during the existence of the transformation - * object. Not all hashing algorithms do implement this function as it - * is only needed for keyed message digests. SHAx/MDx/CRCx do NOT - * implement this function. HMAC(MDx)/HMAC(SHAx)/CMAC(AES) do implement - * this function. This function must be called before any other of the - * @init, @update, @final, @finup, @digest is called. No data - * processing happens at this point. - * @export: Export partial state of the transformation. This function dumps the - * entire state of the ongoing transformation into a provided block of - * data so it can be @import 'ed back later on. This is useful in case - * you want to save partial result of the transformation after - * processing certain amount of data and reload this partial result - * multiple times later on for multiple re-use. No data processing - * happens at this point. - * @import: Import partial state of the transformation. This function loads the - * entire state of the ongoing transformation from a provided block of - * data so the transformation can continue from this point onward. No - * data processing happens at this point. - * @halg: see struct hash_alg_common - */ -struct ahash_alg { - int (*init)(struct ahash_request *req); - int (*update)(struct ahash_request *req); - int (*final)(struct ahash_request *req); - int (*finup)(struct ahash_request *req); - int (*digest)(struct ahash_request *req); - int (*export)(struct ahash_request *req, void *out); - int (*import)(struct ahash_request *req, const void *in); - int (*setkey)(struct crypto_ahash *tfm, const u8 *key, - unsigned int keylen); - - struct hash_alg_common halg; -}; - -struct shash_desc { - struct crypto_shash *tfm; - u32 flags; - - void *__ctx[] CRYPTO_MINALIGN_ATTR; -}; - -#define SHASH_DESC_ON_STACK(shash, ctx) \ - char __##shash##_desc[sizeof(struct shash_desc) + \ - crypto_shash_descsize(ctx)] CRYPTO_MINALIGN_ATTR; \ - struct shash_desc *shash = (struct shash_desc *)__##shash##_desc - -/** - * struct shash_alg - synchronous message digest definition - * @init: see struct ahash_alg - * @update: see struct ahash_alg - * @final: see struct ahash_alg - * @finup: see struct ahash_alg - * @digest: see struct ahash_alg - * @export: see struct ahash_alg - * @import: see struct ahash_alg - * @setkey: see struct ahash_alg - * @digestsize: see struct ahash_alg - * @statesize: see struct ahash_alg - * @descsize: Size of the operational state for the message digest. This state - * size is the memory size that needs to be allocated for - * shash_desc.__ctx - * @base: internally used - */ -struct shash_alg { - int (*init)(struct shash_desc *desc); - int (*update)(struct shash_desc *desc, const u8 *data, - unsigned int len); - int (*final)(struct shash_desc *desc, u8 *out); - int (*finup)(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *out); - int (*digest)(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *out); - int (*export)(struct shash_desc *desc, void *out); - int (*import)(struct shash_desc *desc, const void *in); - int (*setkey)(struct crypto_shash *tfm, const u8 *key, - unsigned int keylen); - - unsigned int descsize; - - /* These fields must match hash_alg_common. */ - unsigned int digestsize - __attribute__ ((aligned(__alignof__(struct hash_alg_common)))); - unsigned int statesize; - - struct crypto_alg base; -}; - -struct crypto_ahash { - int (*init)(struct ahash_request *req); - int (*update)(struct ahash_request *req); - int (*final)(struct ahash_request *req); - int (*finup)(struct ahash_request *req); - int (*digest)(struct ahash_request *req); - int (*export)(struct ahash_request *req, void *out); - int (*import)(struct ahash_request *req, const void *in); - int (*setkey)(struct crypto_ahash *tfm, const u8 *key, - unsigned int keylen); - - unsigned int reqsize; - bool has_setkey; - struct crypto_tfm base; -}; - -struct crypto_shash { - unsigned int descsize; - struct crypto_tfm base; -}; - -/** - * DOC: Asynchronous Message Digest API - * - * The asynchronous message digest API is used with the ciphers of type - * CRYPTO_ALG_TYPE_AHASH (listed as type "ahash" in /proc/crypto) - * - * The asynchronous cipher operation discussion provided for the - * CRYPTO_ALG_TYPE_ABLKCIPHER API applies here as well. - */ - -static inline struct crypto_ahash *__crypto_ahash_cast(struct crypto_tfm *tfm) -{ - return container_of(tfm, struct crypto_ahash, base); -} - -/** - * crypto_alloc_ahash() - allocate ahash cipher handle - * @alg_name: is the cra_name / name or cra_driver_name / driver name of the - * ahash cipher - * @type: specifies the type of the cipher - * @mask: specifies the mask for the cipher - * - * Allocate a cipher handle for an ahash. The returned struct - * crypto_ahash is the cipher handle that is required for any subsequent - * API invocation for that ahash. - * - * Return: allocated cipher handle in case of success; IS_ERR() is true in case - * of an error, PTR_ERR() returns the error code. - */ -struct crypto_ahash *crypto_alloc_ahash(const char *alg_name, u32 type, - u32 mask); - -static inline struct crypto_tfm *crypto_ahash_tfm(struct crypto_ahash *tfm) -{ - return &tfm->base; -} - -/** - * crypto_free_ahash() - zeroize and free the ahash handle - * @tfm: cipher handle to be freed - */ -static inline void crypto_free_ahash(struct crypto_ahash *tfm) -{ - crypto_destroy_tfm(tfm, crypto_ahash_tfm(tfm)); -} - -/** - * crypto_has_ahash() - Search for the availability of an ahash. - * @alg_name: is the cra_name / name or cra_driver_name / driver name of the - * ahash - * @type: specifies the type of the ahash - * @mask: specifies the mask for the ahash - * - * Return: true when the ahash is known to the kernel crypto API; false - * otherwise - */ -int crypto_has_ahash(const char *alg_name, u32 type, u32 mask); - -static inline const char *crypto_ahash_alg_name(struct crypto_ahash *tfm) -{ - return crypto_tfm_alg_name(crypto_ahash_tfm(tfm)); -} - -static inline const char *crypto_ahash_driver_name(struct crypto_ahash *tfm) -{ - return crypto_tfm_alg_driver_name(crypto_ahash_tfm(tfm)); -} - -static inline unsigned int crypto_ahash_alignmask( - struct crypto_ahash *tfm) -{ - return crypto_tfm_alg_alignmask(crypto_ahash_tfm(tfm)); -} - -/** - * crypto_ahash_blocksize() - obtain block size for cipher - * @tfm: cipher handle - * - * The block size for the message digest cipher referenced with the cipher - * handle is returned. - * - * Return: block size of cipher - */ -static inline unsigned int crypto_ahash_blocksize(struct crypto_ahash *tfm) -{ - return crypto_tfm_alg_blocksize(crypto_ahash_tfm(tfm)); -} - -static inline struct hash_alg_common *__crypto_hash_alg_common( - struct crypto_alg *alg) -{ - return container_of(alg, struct hash_alg_common, base); -} - -static inline struct hash_alg_common *crypto_hash_alg_common( - struct crypto_ahash *tfm) -{ - return __crypto_hash_alg_common(crypto_ahash_tfm(tfm)->__crt_alg); -} - -/** - * crypto_ahash_digestsize() - obtain message digest size - * @tfm: cipher handle - * - * The size for the message digest created by the message digest cipher - * referenced with the cipher handle is returned. - * - * - * Return: message digest size of cipher - */ -static inline unsigned int crypto_ahash_digestsize(struct crypto_ahash *tfm) -{ - return crypto_hash_alg_common(tfm)->digestsize; -} - -static inline unsigned int crypto_ahash_statesize(struct crypto_ahash *tfm) -{ - return crypto_hash_alg_common(tfm)->statesize; -} - -static inline u32 crypto_ahash_get_flags(struct crypto_ahash *tfm) -{ - return crypto_tfm_get_flags(crypto_ahash_tfm(tfm)); -} - -static inline void crypto_ahash_set_flags(struct crypto_ahash *tfm, u32 flags) -{ - crypto_tfm_set_flags(crypto_ahash_tfm(tfm), flags); -} - -static inline void crypto_ahash_clear_flags(struct crypto_ahash *tfm, u32 flags) -{ - crypto_tfm_clear_flags(crypto_ahash_tfm(tfm), flags); -} - -/** - * crypto_ahash_reqtfm() - obtain cipher handle from request - * @req: asynchronous request handle that contains the reference to the ahash - * cipher handle - * - * Return the ahash cipher handle that is registered with the asynchronous - * request handle ahash_request. - * - * Return: ahash cipher handle - */ -static inline struct crypto_ahash *crypto_ahash_reqtfm( - struct ahash_request *req) -{ - return __crypto_ahash_cast(req->base.tfm); -} - -/** - * crypto_ahash_reqsize() - obtain size of the request data structure - * @tfm: cipher handle - * - * Return the size of the ahash state size. With the crypto_ahash_export - * function, the caller can export the state into a buffer whose size is - * defined with this function. - * - * Return: size of the ahash state - */ -static inline unsigned int crypto_ahash_reqsize(struct crypto_ahash *tfm) -{ - return tfm->reqsize; -} - -static inline void *ahash_request_ctx(struct ahash_request *req) -{ - return req->__ctx; -} - -/** - * crypto_ahash_setkey - set key for cipher handle - * @tfm: cipher handle - * @key: buffer holding the key - * @keylen: length of the key in bytes - * - * The caller provided key is set for the ahash cipher. The cipher - * handle must point to a keyed hash in order for this function to succeed. - * - * Return: 0 if the setting of the key was successful; < 0 if an error occurred - */ -int crypto_ahash_setkey(struct crypto_ahash *tfm, const u8 *key, - unsigned int keylen); - -static inline bool crypto_ahash_has_setkey(struct crypto_ahash *tfm) -{ - return tfm->has_setkey; -} - -/** - * crypto_ahash_finup() - update and finalize message digest - * @req: reference to the ahash_request handle that holds all information - * needed to perform the cipher operation - * - * This function is a "short-hand" for the function calls of - * crypto_ahash_update and crypto_shash_final. The parameters have the same - * meaning as discussed for those separate functions. - * - * Return: 0 if the message digest creation was successful; < 0 if an error - * occurred - */ -int crypto_ahash_finup(struct ahash_request *req); - -/** - * crypto_ahash_final() - calculate message digest - * @req: reference to the ahash_request handle that holds all information - * needed to perform the cipher operation - * - * Finalize the message digest operation and create the message digest - * based on all data added to the cipher handle. The message digest is placed - * into the output buffer registered with the ahash_request handle. - * - * Return: 0 if the message digest creation was successful; < 0 if an error - * occurred - */ -int crypto_ahash_final(struct ahash_request *req); - -/** - * crypto_ahash_digest() - calculate message digest for a buffer - * @req: reference to the ahash_request handle that holds all information - * needed to perform the cipher operation - * - * This function is a "short-hand" for the function calls of crypto_ahash_init, - * crypto_ahash_update and crypto_ahash_final. The parameters have the same - * meaning as discussed for those separate three functions. - * - * Return: 0 if the message digest creation was successful; < 0 if an error - * occurred - */ -int crypto_ahash_digest(struct ahash_request *req); - -/** - * crypto_ahash_export() - extract current message digest state - * @req: reference to the ahash_request handle whose state is exported - * @out: output buffer of sufficient size that can hold the hash state - * - * This function exports the hash state of the ahash_request handle into the - * caller-allocated output buffer out which must have sufficient size (e.g. by - * calling crypto_ahash_reqsize). - * - * Return: 0 if the export was successful; < 0 if an error occurred - */ -static inline int crypto_ahash_export(struct ahash_request *req, void *out) -{ - return crypto_ahash_reqtfm(req)->export(req, out); -} - -/** - * crypto_ahash_import() - import message digest state - * @req: reference to ahash_request handle the state is imported into - * @in: buffer holding the state - * - * This function imports the hash state into the ahash_request handle from the - * input buffer. That buffer should have been generated with the - * crypto_ahash_export function. - * - * Return: 0 if the import was successful; < 0 if an error occurred - */ -static inline int crypto_ahash_import(struct ahash_request *req, const void *in) -{ - return crypto_ahash_reqtfm(req)->import(req, in); -} - -/** - * crypto_ahash_init() - (re)initialize message digest handle - * @req: ahash_request handle that already is initialized with all necessary - * data using the ahash_request_* API functions - * - * The call (re-)initializes the message digest referenced by the ahash_request - * handle. Any potentially existing state created by previous operations is - * discarded. - * - * Return: 0 if the message digest initialization was successful; < 0 if an - * error occurred - */ -static inline int crypto_ahash_init(struct ahash_request *req) -{ - return crypto_ahash_reqtfm(req)->init(req); -} - -/** - * crypto_ahash_update() - add data to message digest for processing - * @req: ahash_request handle that was previously initialized with the - * crypto_ahash_init call. - * - * Updates the message digest state of the &ahash_request handle. The input data - * is pointed to by the scatter/gather list registered in the &ahash_request - * handle - * - * Return: 0 if the message digest update was successful; < 0 if an error - * occurred - */ -static inline int crypto_ahash_update(struct ahash_request *req) -{ - return crypto_ahash_reqtfm(req)->update(req); -} - -/** - * DOC: Asynchronous Hash Request Handle - * - * The &ahash_request data structure contains all pointers to data - * required for the asynchronous cipher operation. This includes the cipher - * handle (which can be used by multiple &ahash_request instances), pointer - * to plaintext and the message digest output buffer, asynchronous callback - * function, etc. It acts as a handle to the ahash_request_* API calls in a - * similar way as ahash handle to the crypto_ahash_* API calls. - */ - -/** - * ahash_request_set_tfm() - update cipher handle reference in request - * @req: request handle to be modified - * @tfm: cipher handle that shall be added to the request handle - * - * Allow the caller to replace the existing ahash handle in the request - * data structure with a different one. - */ -static inline void ahash_request_set_tfm(struct ahash_request *req, - struct crypto_ahash *tfm) -{ - req->base.tfm = crypto_ahash_tfm(tfm); -} - -/** - * ahash_request_alloc() - allocate request data structure - * @tfm: cipher handle to be registered with the request - * @gfp: memory allocation flag that is handed to kmalloc by the API call. - * - * Allocate the request data structure that must be used with the ahash - * message digest API calls. During - * the allocation, the provided ahash handle - * is registered in the request data structure. - * - * Return: allocated request handle in case of success, or NULL if out of memory - */ -static inline struct ahash_request *ahash_request_alloc( - struct crypto_ahash *tfm, gfp_t gfp) -{ - struct ahash_request *req; - - req = kmalloc(sizeof(struct ahash_request) + - crypto_ahash_reqsize(tfm), gfp); - - if (likely(req)) - ahash_request_set_tfm(req, tfm); - - return req; -} - -/** - * ahash_request_free() - zeroize and free the request data structure - * @req: request data structure cipher handle to be freed - */ -static inline void ahash_request_free(struct ahash_request *req) -{ - kzfree(req); -} - -static inline void ahash_request_zero(struct ahash_request *req) -{ - memzero_explicit(req, sizeof(*req) + - crypto_ahash_reqsize(crypto_ahash_reqtfm(req))); -} - -static inline struct ahash_request *ahash_request_cast( - struct crypto_async_request *req) -{ - return container_of(req, struct ahash_request, base); -} - -/** - * ahash_request_set_callback() - set asynchronous callback function - * @req: request handle - * @flags: specify zero or an ORing of the flags - * CRYPTO_TFM_REQ_MAY_BACKLOG the request queue may back log and - * increase the wait queue beyond the initial maximum size; - * CRYPTO_TFM_REQ_MAY_SLEEP the request processing may sleep - * @compl: callback function pointer to be registered with the request handle - * @data: The data pointer refers to memory that is not used by the kernel - * crypto API, but provided to the callback function for it to use. Here, - * the caller can provide a reference to memory the callback function can - * operate on. As the callback function is invoked asynchronously to the - * related functionality, it may need to access data structures of the - * related functionality which can be referenced using this pointer. The - * callback function can access the memory via the "data" field in the - * &crypto_async_request data structure provided to the callback function. - * - * This function allows setting the callback function that is triggered once - * the cipher operation completes. - * - * The callback function is registered with the &ahash_request handle and - * must comply with the following template - * - * void callback_function(struct crypto_async_request *req, int error) - */ -static inline void ahash_request_set_callback(struct ahash_request *req, - u32 flags, - crypto_completion_t compl, - void *data) -{ - req->base.complete = compl; - req->base.data = data; - req->base.flags = flags; -} - -/** - * ahash_request_set_crypt() - set data buffers - * @req: ahash_request handle to be updated - * @src: source scatter/gather list - * @result: buffer that is filled with the message digest -- the caller must - * ensure that the buffer has sufficient space by, for example, calling - * crypto_ahash_digestsize() - * @nbytes: number of bytes to process from the source scatter/gather list - * - * By using this call, the caller references the source scatter/gather list. - * The source scatter/gather list points to the data the message digest is to - * be calculated for. - */ -static inline void ahash_request_set_crypt(struct ahash_request *req, - struct scatterlist *src, u8 *result, - unsigned int nbytes) -{ - req->src = src; - req->nbytes = nbytes; - req->result = result; -} - -/** - * DOC: Synchronous Message Digest API - * - * The synchronous message digest API is used with the ciphers of type - * CRYPTO_ALG_TYPE_SHASH (listed as type "shash" in /proc/crypto) - * - * The message digest API is able to maintain state information for the - * caller. - * - * The synchronous message digest API can store user-related context in in its - * shash_desc request data structure. - */ - -/** - * crypto_alloc_shash() - allocate message digest handle - * @alg_name: is the cra_name / name or cra_driver_name / driver name of the - * message digest cipher - * @type: specifies the type of the cipher - * @mask: specifies the mask for the cipher - * - * Allocate a cipher handle for a message digest. The returned &struct - * crypto_shash is the cipher handle that is required for any subsequent - * API invocation for that message digest. - * - * Return: allocated cipher handle in case of success; IS_ERR() is true in case - * of an error, PTR_ERR() returns the error code. - */ -struct crypto_shash *crypto_alloc_shash(const char *alg_name, u32 type, - u32 mask); - -static inline struct crypto_tfm *crypto_shash_tfm(struct crypto_shash *tfm) -{ - return &tfm->base; -} - -/** - * crypto_free_shash() - zeroize and free the message digest handle - * @tfm: cipher handle to be freed - */ -static inline void crypto_free_shash(struct crypto_shash *tfm) -{ - crypto_destroy_tfm(tfm, crypto_shash_tfm(tfm)); -} - -static inline const char *crypto_shash_alg_name(struct crypto_shash *tfm) -{ - return crypto_tfm_alg_name(crypto_shash_tfm(tfm)); -} - -static inline const char *crypto_shash_driver_name(struct crypto_shash *tfm) -{ - return crypto_tfm_alg_driver_name(crypto_shash_tfm(tfm)); -} - -static inline unsigned int crypto_shash_alignmask( - struct crypto_shash *tfm) -{ - return crypto_tfm_alg_alignmask(crypto_shash_tfm(tfm)); -} - -/** - * crypto_shash_blocksize() - obtain block size for cipher - * @tfm: cipher handle - * - * The block size for the message digest cipher referenced with the cipher - * handle is returned. - * - * Return: block size of cipher - */ -static inline unsigned int crypto_shash_blocksize(struct crypto_shash *tfm) -{ - return crypto_tfm_alg_blocksize(crypto_shash_tfm(tfm)); -} - -static inline struct shash_alg *__crypto_shash_alg(struct crypto_alg *alg) -{ - return container_of(alg, struct shash_alg, base); -} - -static inline struct shash_alg *crypto_shash_alg(struct crypto_shash *tfm) -{ - return __crypto_shash_alg(crypto_shash_tfm(tfm)->__crt_alg); -} - -/** - * crypto_shash_digestsize() - obtain message digest size - * @tfm: cipher handle - * - * The size for the message digest created by the message digest cipher - * referenced with the cipher handle is returned. - * - * Return: digest size of cipher - */ -static inline unsigned int crypto_shash_digestsize(struct crypto_shash *tfm) -{ - return crypto_shash_alg(tfm)->digestsize; -} - -static inline unsigned int crypto_shash_statesize(struct crypto_shash *tfm) -{ - return crypto_shash_alg(tfm)->statesize; -} - -static inline u32 crypto_shash_get_flags(struct crypto_shash *tfm) -{ - return crypto_tfm_get_flags(crypto_shash_tfm(tfm)); -} - -static inline void crypto_shash_set_flags(struct crypto_shash *tfm, u32 flags) -{ - crypto_tfm_set_flags(crypto_shash_tfm(tfm), flags); -} - -static inline void crypto_shash_clear_flags(struct crypto_shash *tfm, u32 flags) -{ - crypto_tfm_clear_flags(crypto_shash_tfm(tfm), flags); -} - -/** - * crypto_shash_descsize() - obtain the operational state size - * @tfm: cipher handle - * - * The size of the operational state the cipher needs during operation is - * returned for the hash referenced with the cipher handle. This size is - * required to calculate the memory requirements to allow the caller allocating - * sufficient memory for operational state. - * - * The operational state is defined with struct shash_desc where the size of - * that data structure is to be calculated as - * sizeof(struct shash_desc) + crypto_shash_descsize(alg) - * - * Return: size of the operational state - */ -static inline unsigned int crypto_shash_descsize(struct crypto_shash *tfm) -{ - return tfm->descsize; -} - -static inline void *shash_desc_ctx(struct shash_desc *desc) -{ - return desc->__ctx; -} - -/** - * crypto_shash_setkey() - set key for message digest - * @tfm: cipher handle - * @key: buffer holding the key - * @keylen: length of the key in bytes - * - * The caller provided key is set for the keyed message digest cipher. The - * cipher handle must point to a keyed message digest cipher in order for this - * function to succeed. - * - * Return: 0 if the setting of the key was successful; < 0 if an error occurred - */ -int crypto_shash_setkey(struct crypto_shash *tfm, const u8 *key, - unsigned int keylen); - -/** - * crypto_shash_digest() - calculate message digest for buffer - * @desc: see crypto_shash_final() - * @data: see crypto_shash_update() - * @len: see crypto_shash_update() - * @out: see crypto_shash_final() - * - * This function is a "short-hand" for the function calls of crypto_shash_init, - * crypto_shash_update and crypto_shash_final. The parameters have the same - * meaning as discussed for those separate three functions. - * - * Return: 0 if the message digest creation was successful; < 0 if an error - * occurred - */ -int crypto_shash_digest(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *out); - -/** - * crypto_shash_export() - extract operational state for message digest - * @desc: reference to the operational state handle whose state is exported - * @out: output buffer of sufficient size that can hold the hash state - * - * This function exports the hash state of the operational state handle into the - * caller-allocated output buffer out which must have sufficient size (e.g. by - * calling crypto_shash_descsize). - * - * Return: 0 if the export creation was successful; < 0 if an error occurred - */ -static inline int crypto_shash_export(struct shash_desc *desc, void *out) -{ - return crypto_shash_alg(desc->tfm)->export(desc, out); -} - -/** - * crypto_shash_import() - import operational state - * @desc: reference to the operational state handle the state imported into - * @in: buffer holding the state - * - * This function imports the hash state into the operational state handle from - * the input buffer. That buffer should have been generated with the - * crypto_ahash_export function. - * - * Return: 0 if the import was successful; < 0 if an error occurred - */ -static inline int crypto_shash_import(struct shash_desc *desc, const void *in) -{ - return crypto_shash_alg(desc->tfm)->import(desc, in); -} - -/** - * crypto_shash_init() - (re)initialize message digest - * @desc: operational state handle that is already filled - * - * The call (re-)initializes the message digest referenced by the - * operational state handle. Any potentially existing state created by - * previous operations is discarded. - * - * Return: 0 if the message digest initialization was successful; < 0 if an - * error occurred - */ -static inline int crypto_shash_init(struct shash_desc *desc) -{ - return crypto_shash_alg(desc->tfm)->init(desc); -} - -/** - * crypto_shash_update() - add data to message digest for processing - * @desc: operational state handle that is already initialized - * @data: input data to be added to the message digest - * @len: length of the input data - * - * Updates the message digest state of the operational state handle. - * - * Return: 0 if the message digest update was successful; < 0 if an error - * occurred - */ -int crypto_shash_update(struct shash_desc *desc, const u8 *data, - unsigned int len); - -/** - * crypto_shash_final() - calculate message digest - * @desc: operational state handle that is already filled with data - * @out: output buffer filled with the message digest - * - * Finalize the message digest operation and create the message digest - * based on all data added to the cipher handle. The message digest is placed - * into the output buffer. The caller must ensure that the output buffer is - * large enough by using crypto_shash_digestsize. - * - * Return: 0 if the message digest creation was successful; < 0 if an error - * occurred - */ -int crypto_shash_final(struct shash_desc *desc, u8 *out); - -/** - * crypto_shash_finup() - calculate message digest of buffer - * @desc: see crypto_shash_final() - * @data: see crypto_shash_update() - * @len: see crypto_shash_update() - * @out: see crypto_shash_final() - * - * This function is a "short-hand" for the function calls of - * crypto_shash_update and crypto_shash_final. The parameters have the same - * meaning as discussed for those separate functions. - * - * Return: 0 if the message digest creation was successful; < 0 if an error - * occurred - */ -int crypto_shash_finup(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *out); - -static inline void shash_desc_zero(struct shash_desc *desc) -{ - memzero_explicit(desc, - sizeof(*desc) + crypto_shash_descsize(desc->tfm)); -} - -#endif /* _CRYPTO_HASH_H */ diff --git a/src/linux/include/crypto/internal/aead.h b/src/linux/include/crypto/internal/aead.h deleted file mode 100644 index 6ad8e31..0000000 --- a/src/linux/include/crypto/internal/aead.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - * AEAD: Authenticated Encryption with Associated Data - * - * Copyright (c) 2007-2015 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#ifndef _CRYPTO_INTERNAL_AEAD_H -#define _CRYPTO_INTERNAL_AEAD_H - -#include -#include -#include -#include - -struct rtattr; - -struct aead_instance { - void (*free)(struct aead_instance *inst); - union { - struct { - char head[offsetof(struct aead_alg, base)]; - struct crypto_instance base; - } s; - struct aead_alg alg; - }; -}; - -struct crypto_aead_spawn { - struct crypto_spawn base; -}; - -struct aead_queue { - struct crypto_queue base; -}; - -static inline void *crypto_aead_ctx(struct crypto_aead *tfm) -{ - return crypto_tfm_ctx(&tfm->base); -} - -static inline struct crypto_instance *aead_crypto_instance( - struct aead_instance *inst) -{ - return container_of(&inst->alg.base, struct crypto_instance, alg); -} - -static inline struct aead_instance *aead_instance(struct crypto_instance *inst) -{ - return container_of(&inst->alg, struct aead_instance, alg.base); -} - -static inline struct aead_instance *aead_alg_instance(struct crypto_aead *aead) -{ - return aead_instance(crypto_tfm_alg_instance(&aead->base)); -} - -static inline void *aead_instance_ctx(struct aead_instance *inst) -{ - return crypto_instance_ctx(aead_crypto_instance(inst)); -} - -static inline void *aead_request_ctx(struct aead_request *req) -{ - return req->__ctx; -} - -static inline void aead_request_complete(struct aead_request *req, int err) -{ - req->base.complete(&req->base, err); -} - -static inline u32 aead_request_flags(struct aead_request *req) -{ - return req->base.flags; -} - -static inline struct aead_request *aead_request_cast( - struct crypto_async_request *req) -{ - return container_of(req, struct aead_request, base); -} - -static inline void crypto_set_aead_spawn( - struct crypto_aead_spawn *spawn, struct crypto_instance *inst) -{ - crypto_set_spawn(&spawn->base, inst); -} - -int crypto_grab_aead(struct crypto_aead_spawn *spawn, const char *name, - u32 type, u32 mask); - -static inline void crypto_drop_aead(struct crypto_aead_spawn *spawn) -{ - crypto_drop_spawn(&spawn->base); -} - -static inline struct aead_alg *crypto_spawn_aead_alg( - struct crypto_aead_spawn *spawn) -{ - return container_of(spawn->base.alg, struct aead_alg, base); -} - -static inline struct crypto_aead *crypto_spawn_aead( - struct crypto_aead_spawn *spawn) -{ - return crypto_spawn_tfm2(&spawn->base); -} - -static inline void crypto_aead_set_reqsize(struct crypto_aead *aead, - unsigned int reqsize) -{ - aead->reqsize = reqsize; -} - -static inline unsigned int crypto_aead_alg_maxauthsize(struct aead_alg *alg) -{ - return alg->maxauthsize; -} - -static inline unsigned int crypto_aead_maxauthsize(struct crypto_aead *aead) -{ - return crypto_aead_alg_maxauthsize(crypto_aead_alg(aead)); -} - -static inline void aead_init_queue(struct aead_queue *queue, - unsigned int max_qlen) -{ - crypto_init_queue(&queue->base, max_qlen); -} - -static inline int aead_enqueue_request(struct aead_queue *queue, - struct aead_request *request) -{ - return crypto_enqueue_request(&queue->base, &request->base); -} - -static inline struct aead_request *aead_dequeue_request( - struct aead_queue *queue) -{ - struct crypto_async_request *req; - - req = crypto_dequeue_request(&queue->base); - - return req ? container_of(req, struct aead_request, base) : NULL; -} - -static inline struct aead_request *aead_get_backlog(struct aead_queue *queue) -{ - struct crypto_async_request *req; - - req = crypto_get_backlog(&queue->base); - - return req ? container_of(req, struct aead_request, base) : NULL; -} - -static inline unsigned int crypto_aead_alg_chunksize(struct aead_alg *alg) -{ - return alg->chunksize; -} - -/** - * crypto_aead_chunksize() - obtain chunk size - * @tfm: cipher handle - * - * The block size is set to one for ciphers such as CCM. However, - * you still need to provide incremental updates in multiples of - * the underlying block size as the IV does not have sub-block - * granularity. This is known in this API as the chunk size. - * - * Return: chunk size in bytes - */ -static inline unsigned int crypto_aead_chunksize(struct crypto_aead *tfm) -{ - return crypto_aead_alg_chunksize(crypto_aead_alg(tfm)); -} - -int crypto_register_aead(struct aead_alg *alg); -void crypto_unregister_aead(struct aead_alg *alg); -int crypto_register_aeads(struct aead_alg *algs, int count); -void crypto_unregister_aeads(struct aead_alg *algs, int count); -int aead_register_instance(struct crypto_template *tmpl, - struct aead_instance *inst); - -#endif /* _CRYPTO_INTERNAL_AEAD_H */ - diff --git a/src/linux/include/crypto/internal/akcipher.h b/src/linux/include/crypto/internal/akcipher.h deleted file mode 100644 index 479a007..0000000 --- a/src/linux/include/crypto/internal/akcipher.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Public Key Encryption - * - * Copyright (c) 2015, Intel Corporation - * Authors: Tadeusz Struk - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ -#ifndef _CRYPTO_AKCIPHER_INT_H -#define _CRYPTO_AKCIPHER_INT_H -#include -#include - -struct akcipher_instance { - void (*free)(struct akcipher_instance *inst); - union { - struct { - char head[offsetof(struct akcipher_alg, base)]; - struct crypto_instance base; - } s; - struct akcipher_alg alg; - }; -}; - -struct crypto_akcipher_spawn { - struct crypto_spawn base; -}; - -/* - * Transform internal helpers. - */ -static inline void *akcipher_request_ctx(struct akcipher_request *req) -{ - return req->__ctx; -} - -static inline void *akcipher_tfm_ctx(struct crypto_akcipher *tfm) -{ - return tfm->base.__crt_ctx; -} - -static inline void akcipher_request_complete(struct akcipher_request *req, - int err) -{ - req->base.complete(&req->base, err); -} - -static inline const char *akcipher_alg_name(struct crypto_akcipher *tfm) -{ - return crypto_akcipher_tfm(tfm)->__crt_alg->cra_name; -} - -static inline struct crypto_instance *akcipher_crypto_instance( - struct akcipher_instance *inst) -{ - return container_of(&inst->alg.base, struct crypto_instance, alg); -} - -static inline struct akcipher_instance *akcipher_instance( - struct crypto_instance *inst) -{ - return container_of(&inst->alg, struct akcipher_instance, alg.base); -} - -static inline struct akcipher_instance *akcipher_alg_instance( - struct crypto_akcipher *akcipher) -{ - return akcipher_instance(crypto_tfm_alg_instance(&akcipher->base)); -} - -static inline void *akcipher_instance_ctx(struct akcipher_instance *inst) -{ - return crypto_instance_ctx(akcipher_crypto_instance(inst)); -} - -static inline void crypto_set_akcipher_spawn( - struct crypto_akcipher_spawn *spawn, - struct crypto_instance *inst) -{ - crypto_set_spawn(&spawn->base, inst); -} - -int crypto_grab_akcipher(struct crypto_akcipher_spawn *spawn, const char *name, - u32 type, u32 mask); - -static inline struct crypto_akcipher *crypto_spawn_akcipher( - struct crypto_akcipher_spawn *spawn) -{ - return crypto_spawn_tfm2(&spawn->base); -} - -static inline void crypto_drop_akcipher(struct crypto_akcipher_spawn *spawn) -{ - crypto_drop_spawn(&spawn->base); -} - -static inline struct akcipher_alg *crypto_spawn_akcipher_alg( - struct crypto_akcipher_spawn *spawn) -{ - return container_of(spawn->base.alg, struct akcipher_alg, base); -} - -/** - * crypto_register_akcipher() -- Register public key algorithm - * - * Function registers an implementation of a public key verify algorithm - * - * @alg: algorithm definition - * - * Return: zero on success; error code in case of error - */ -int crypto_register_akcipher(struct akcipher_alg *alg); - -/** - * crypto_unregister_akcipher() -- Unregister public key algorithm - * - * Function unregisters an implementation of a public key verify algorithm - * - * @alg: algorithm definition - */ -void crypto_unregister_akcipher(struct akcipher_alg *alg); - -/** - * akcipher_register_instance() -- Unregister public key template instance - * - * Function registers an implementation of an asymmetric key algorithm - * created from a template - * - * @tmpl: the template from which the algorithm was created - * @inst: the template instance - */ -int akcipher_register_instance(struct crypto_template *tmpl, - struct akcipher_instance *inst); -#endif diff --git a/src/linux/include/crypto/internal/geniv.h b/src/linux/include/crypto/internal/geniv.h deleted file mode 100644 index 2bcfb93..0000000 --- a/src/linux/include/crypto/internal/geniv.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * geniv: IV generation - * - * Copyright (c) 2015 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#ifndef _CRYPTO_INTERNAL_GENIV_H -#define _CRYPTO_INTERNAL_GENIV_H - -#include -#include -#include - -struct aead_geniv_ctx { - spinlock_t lock; - struct crypto_aead *child; - struct crypto_skcipher *sknull; - u8 salt[] __attribute__ ((aligned(__alignof__(u32)))); -}; - -struct aead_instance *aead_geniv_alloc(struct crypto_template *tmpl, - struct rtattr **tb, u32 type, u32 mask); -void aead_geniv_free(struct aead_instance *inst); -int aead_init_geniv(struct crypto_aead *tfm); -void aead_exit_geniv(struct crypto_aead *tfm); - -#endif /* _CRYPTO_INTERNAL_GENIV_H */ diff --git a/src/linux/include/crypto/internal/hash.h b/src/linux/include/crypto/internal/hash.h deleted file mode 100644 index 1d4f365..0000000 --- a/src/linux/include/crypto/internal/hash.h +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Hash algorithms. - * - * Copyright (c) 2008 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#ifndef _CRYPTO_INTERNAL_HASH_H -#define _CRYPTO_INTERNAL_HASH_H - -#include -#include - -struct ahash_request; -struct scatterlist; - -struct crypto_hash_walk { - char *data; - - unsigned int offset; - unsigned int alignmask; - - struct page *pg; - unsigned int entrylen; - - unsigned int total; - struct scatterlist *sg; - - unsigned int flags; -}; - -struct ahash_instance { - struct ahash_alg alg; -}; - -struct shash_instance { - struct shash_alg alg; -}; - -struct crypto_ahash_spawn { - struct crypto_spawn base; -}; - -struct crypto_shash_spawn { - struct crypto_spawn base; -}; - -extern const struct crypto_type crypto_ahash_type; - -int crypto_hash_walk_done(struct crypto_hash_walk *walk, int err); -int crypto_hash_walk_first(struct ahash_request *req, - struct crypto_hash_walk *walk); -int crypto_ahash_walk_first(struct ahash_request *req, - struct crypto_hash_walk *walk); - -static inline int crypto_ahash_walk_done(struct crypto_hash_walk *walk, - int err) -{ - return crypto_hash_walk_done(walk, err); -} - -static inline int crypto_hash_walk_last(struct crypto_hash_walk *walk) -{ - return !(walk->entrylen | walk->total); -} - -static inline int crypto_ahash_walk_last(struct crypto_hash_walk *walk) -{ - return crypto_hash_walk_last(walk); -} - -int crypto_register_ahash(struct ahash_alg *alg); -int crypto_unregister_ahash(struct ahash_alg *alg); -int ahash_register_instance(struct crypto_template *tmpl, - struct ahash_instance *inst); -void ahash_free_instance(struct crypto_instance *inst); - -int crypto_init_ahash_spawn(struct crypto_ahash_spawn *spawn, - struct hash_alg_common *alg, - struct crypto_instance *inst); - -static inline void crypto_drop_ahash(struct crypto_ahash_spawn *spawn) -{ - crypto_drop_spawn(&spawn->base); -} - -struct hash_alg_common *ahash_attr_alg(struct rtattr *rta, u32 type, u32 mask); - -int crypto_register_shash(struct shash_alg *alg); -int crypto_unregister_shash(struct shash_alg *alg); -int crypto_register_shashes(struct shash_alg *algs, int count); -int crypto_unregister_shashes(struct shash_alg *algs, int count); -int shash_register_instance(struct crypto_template *tmpl, - struct shash_instance *inst); -void shash_free_instance(struct crypto_instance *inst); - -int crypto_init_shash_spawn(struct crypto_shash_spawn *spawn, - struct shash_alg *alg, - struct crypto_instance *inst); - -static inline void crypto_drop_shash(struct crypto_shash_spawn *spawn) -{ - crypto_drop_spawn(&spawn->base); -} - -struct shash_alg *shash_attr_alg(struct rtattr *rta, u32 type, u32 mask); - -int shash_ahash_update(struct ahash_request *req, struct shash_desc *desc); -int shash_ahash_finup(struct ahash_request *req, struct shash_desc *desc); -int shash_ahash_digest(struct ahash_request *req, struct shash_desc *desc); - -int ahash_mcryptd_update(struct ahash_request *desc); -int ahash_mcryptd_final(struct ahash_request *desc); -int ahash_mcryptd_finup(struct ahash_request *desc); -int ahash_mcryptd_digest(struct ahash_request *desc); - -int crypto_init_shash_ops_async(struct crypto_tfm *tfm); - -static inline void *crypto_ahash_ctx(struct crypto_ahash *tfm) -{ - return crypto_tfm_ctx(crypto_ahash_tfm(tfm)); -} - -static inline struct ahash_alg *__crypto_ahash_alg(struct crypto_alg *alg) -{ - return container_of(__crypto_hash_alg_common(alg), struct ahash_alg, - halg); -} - -static inline void crypto_ahash_set_reqsize(struct crypto_ahash *tfm, - unsigned int reqsize) -{ - tfm->reqsize = reqsize; -} - -static inline struct crypto_instance *ahash_crypto_instance( - struct ahash_instance *inst) -{ - return container_of(&inst->alg.halg.base, struct crypto_instance, alg); -} - -static inline struct ahash_instance *ahash_instance( - struct crypto_instance *inst) -{ - return container_of(&inst->alg, struct ahash_instance, alg.halg.base); -} - -static inline void *ahash_instance_ctx(struct ahash_instance *inst) -{ - return crypto_instance_ctx(ahash_crypto_instance(inst)); -} - -static inline unsigned int ahash_instance_headroom(void) -{ - return sizeof(struct ahash_alg) - sizeof(struct crypto_alg); -} - -static inline struct ahash_instance *ahash_alloc_instance( - const char *name, struct crypto_alg *alg) -{ - return crypto_alloc_instance2(name, alg, ahash_instance_headroom()); -} - -static inline struct crypto_ahash *crypto_spawn_ahash( - struct crypto_ahash_spawn *spawn) -{ - return crypto_spawn_tfm2(&spawn->base); -} - -static inline int ahash_enqueue_request(struct crypto_queue *queue, - struct ahash_request *request) -{ - return crypto_enqueue_request(queue, &request->base); -} - -static inline struct ahash_request *ahash_dequeue_request( - struct crypto_queue *queue) -{ - return ahash_request_cast(crypto_dequeue_request(queue)); -} - -static inline int ahash_tfm_in_queue(struct crypto_queue *queue, - struct crypto_ahash *tfm) -{ - return crypto_tfm_in_queue(queue, crypto_ahash_tfm(tfm)); -} - -static inline void *crypto_shash_ctx(struct crypto_shash *tfm) -{ - return crypto_tfm_ctx(&tfm->base); -} - -static inline struct crypto_instance *shash_crypto_instance( - struct shash_instance *inst) -{ - return container_of(&inst->alg.base, struct crypto_instance, alg); -} - -static inline struct shash_instance *shash_instance( - struct crypto_instance *inst) -{ - return container_of(__crypto_shash_alg(&inst->alg), - struct shash_instance, alg); -} - -static inline void *shash_instance_ctx(struct shash_instance *inst) -{ - return crypto_instance_ctx(shash_crypto_instance(inst)); -} - -static inline struct shash_instance *shash_alloc_instance( - const char *name, struct crypto_alg *alg) -{ - return crypto_alloc_instance2(name, alg, - sizeof(struct shash_alg) - sizeof(*alg)); -} - -static inline struct crypto_shash *crypto_spawn_shash( - struct crypto_shash_spawn *spawn) -{ - return crypto_spawn_tfm2(&spawn->base); -} - -static inline void *crypto_shash_ctx_aligned(struct crypto_shash *tfm) -{ - return crypto_tfm_ctx_aligned(&tfm->base); -} - -static inline struct crypto_shash *__crypto_shash_cast(struct crypto_tfm *tfm) -{ - return container_of(tfm, struct crypto_shash, base); -} - -#endif /* _CRYPTO_INTERNAL_HASH_H */ - diff --git a/src/linux/include/crypto/internal/kpp.h b/src/linux/include/crypto/internal/kpp.h deleted file mode 100644 index ad3acf3..0000000 --- a/src/linux/include/crypto/internal/kpp.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Key-agreement Protocol Primitives (KPP) - * - * Copyright (c) 2016, Intel Corporation - * Authors: Salvatore Benedetto - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ -#ifndef _CRYPTO_KPP_INT_H -#define _CRYPTO_KPP_INT_H -#include -#include - -/* - * Transform internal helpers. - */ -static inline void *kpp_request_ctx(struct kpp_request *req) -{ - return req->__ctx; -} - -static inline void *kpp_tfm_ctx(struct crypto_kpp *tfm) -{ - return tfm->base.__crt_ctx; -} - -static inline void kpp_request_complete(struct kpp_request *req, int err) -{ - req->base.complete(&req->base, err); -} - -static inline const char *kpp_alg_name(struct crypto_kpp *tfm) -{ - return crypto_kpp_tfm(tfm)->__crt_alg->cra_name; -} - -/** - * crypto_register_kpp() -- Register key-agreement protocol primitives algorithm - * - * Function registers an implementation of a key-agreement protocol primitive - * algorithm - * - * @alg: algorithm definition - * - * Return: zero on success; error code in case of error - */ -int crypto_register_kpp(struct kpp_alg *alg); - -/** - * crypto_unregister_kpp() -- Unregister key-agreement protocol primitive - * algorithm - * - * Function unregisters an implementation of a key-agreement protocol primitive - * algorithm - * - * @alg: algorithm definition - */ -void crypto_unregister_kpp(struct kpp_alg *alg); - -#endif diff --git a/src/linux/include/crypto/internal/rng.h b/src/linux/include/crypto/internal/rng.h deleted file mode 100644 index a52ef34..0000000 --- a/src/linux/include/crypto/internal/rng.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * RNG: Random Number Generator algorithms under the crypto API - * - * Copyright (c) 2008 Neil Horman - * Copyright (c) 2015 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#ifndef _CRYPTO_INTERNAL_RNG_H -#define _CRYPTO_INTERNAL_RNG_H - -#include -#include - -int crypto_register_rng(struct rng_alg *alg); -void crypto_unregister_rng(struct rng_alg *alg); -int crypto_register_rngs(struct rng_alg *algs, int count); -void crypto_unregister_rngs(struct rng_alg *algs, int count); - -#if defined(CONFIG_CRYPTO_RNG) || defined(CONFIG_CRYPTO_RNG_MODULE) -int crypto_del_default_rng(void); -#else -static inline int crypto_del_default_rng(void) -{ - return 0; -} -#endif - -static inline void *crypto_rng_ctx(struct crypto_rng *tfm) -{ - return crypto_tfm_ctx(&tfm->base); -} - -static inline void crypto_rng_set_entropy(struct crypto_rng *tfm, - const u8 *data, unsigned int len) -{ - crypto_rng_alg(tfm)->set_ent(tfm, data, len); -} - -#endif diff --git a/src/linux/include/crypto/internal/skcipher.h b/src/linux/include/crypto/internal/skcipher.h deleted file mode 100644 index a21a95e..0000000 --- a/src/linux/include/crypto/internal/skcipher.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Symmetric key ciphers. - * - * Copyright (c) 2007 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#ifndef _CRYPTO_INTERNAL_SKCIPHER_H -#define _CRYPTO_INTERNAL_SKCIPHER_H - -#include -#include -#include - -struct rtattr; - -struct skcipher_instance { - void (*free)(struct skcipher_instance *inst); - union { - struct { - char head[offsetof(struct skcipher_alg, base)]; - struct crypto_instance base; - } s; - struct skcipher_alg alg; - }; -}; - -struct crypto_skcipher_spawn { - struct crypto_spawn base; -}; - -extern const struct crypto_type crypto_givcipher_type; - -static inline struct crypto_instance *skcipher_crypto_instance( - struct skcipher_instance *inst) -{ - return &inst->s.base; -} - -static inline struct skcipher_instance *skcipher_alg_instance( - struct crypto_skcipher *skcipher) -{ - return container_of(crypto_skcipher_alg(skcipher), - struct skcipher_instance, alg); -} - -static inline void *skcipher_instance_ctx(struct skcipher_instance *inst) -{ - return crypto_instance_ctx(skcipher_crypto_instance(inst)); -} - -static inline void skcipher_request_complete(struct skcipher_request *req, int err) -{ - req->base.complete(&req->base, err); -} - -static inline void crypto_set_skcipher_spawn( - struct crypto_skcipher_spawn *spawn, struct crypto_instance *inst) -{ - crypto_set_spawn(&spawn->base, inst); -} - -int crypto_grab_skcipher(struct crypto_skcipher_spawn *spawn, const char *name, - u32 type, u32 mask); - -static inline int crypto_grab_skcipher2(struct crypto_skcipher_spawn *spawn, - const char *name, u32 type, u32 mask) -{ - return crypto_grab_skcipher(spawn, name, type, mask); -} - -struct crypto_alg *crypto_lookup_skcipher(const char *name, u32 type, u32 mask); - -static inline void crypto_drop_skcipher(struct crypto_skcipher_spawn *spawn) -{ - crypto_drop_spawn(&spawn->base); -} - -static inline struct skcipher_alg *crypto_skcipher_spawn_alg( - struct crypto_skcipher_spawn *spawn) -{ - return container_of(spawn->base.alg, struct skcipher_alg, base); -} - -static inline struct skcipher_alg *crypto_spawn_skcipher_alg( - struct crypto_skcipher_spawn *spawn) -{ - return crypto_skcipher_spawn_alg(spawn); -} - -static inline struct crypto_skcipher *crypto_spawn_skcipher( - struct crypto_skcipher_spawn *spawn) -{ - return crypto_spawn_tfm2(&spawn->base); -} - -static inline struct crypto_skcipher *crypto_spawn_skcipher2( - struct crypto_skcipher_spawn *spawn) -{ - return crypto_spawn_skcipher(spawn); -} - -static inline void crypto_skcipher_set_reqsize( - struct crypto_skcipher *skcipher, unsigned int reqsize) -{ - skcipher->reqsize = reqsize; -} - -int crypto_register_skcipher(struct skcipher_alg *alg); -void crypto_unregister_skcipher(struct skcipher_alg *alg); -int crypto_register_skciphers(struct skcipher_alg *algs, int count); -void crypto_unregister_skciphers(struct skcipher_alg *algs, int count); -int skcipher_register_instance(struct crypto_template *tmpl, - struct skcipher_instance *inst); - -static inline void ablkcipher_request_complete(struct ablkcipher_request *req, - int err) -{ - req->base.complete(&req->base, err); -} - -static inline u32 ablkcipher_request_flags(struct ablkcipher_request *req) -{ - return req->base.flags; -} - -static inline void *crypto_skcipher_ctx(struct crypto_skcipher *tfm) -{ - return crypto_tfm_ctx(&tfm->base); -} - -static inline void *skcipher_request_ctx(struct skcipher_request *req) -{ - return req->__ctx; -} - -static inline u32 skcipher_request_flags(struct skcipher_request *req) -{ - return req->base.flags; -} - -static inline unsigned int crypto_skcipher_alg_min_keysize( - struct skcipher_alg *alg) -{ - if ((alg->base.cra_flags & CRYPTO_ALG_TYPE_MASK) == - CRYPTO_ALG_TYPE_BLKCIPHER) - return alg->base.cra_blkcipher.min_keysize; - - if (alg->base.cra_ablkcipher.encrypt) - return alg->base.cra_ablkcipher.min_keysize; - - return alg->min_keysize; -} - -static inline unsigned int crypto_skcipher_alg_max_keysize( - struct skcipher_alg *alg) -{ - if ((alg->base.cra_flags & CRYPTO_ALG_TYPE_MASK) == - CRYPTO_ALG_TYPE_BLKCIPHER) - return alg->base.cra_blkcipher.max_keysize; - - if (alg->base.cra_ablkcipher.encrypt) - return alg->base.cra_ablkcipher.max_keysize; - - return alg->max_keysize; -} - -#endif /* _CRYPTO_INTERNAL_SKCIPHER_H */ - diff --git a/src/linux/include/crypto/kpp.h b/src/linux/include/crypto/kpp.h deleted file mode 100644 index 30791f7..0000000 --- a/src/linux/include/crypto/kpp.h +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Key-agreement Protocol Primitives (KPP) - * - * Copyright (c) 2016, Intel Corporation - * Authors: Salvatore Benedetto - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#ifndef _CRYPTO_KPP_ -#define _CRYPTO_KPP_ -#include - -/** - * struct kpp_request - * - * @base: Common attributes for async crypto requests - * @src: Source data - * @dst: Destination data - * @src_len: Size of the input buffer - * @dst_len: Size of the output buffer. It needs to be at least - * as big as the expected result depending on the operation - * After operation it will be updated with the actual size of the - * result. In case of error where the dst sgl size was insufficient, - * it will be updated to the size required for the operation. - * @__ctx: Start of private context data - */ -struct kpp_request { - struct crypto_async_request base; - struct scatterlist *src; - struct scatterlist *dst; - unsigned int src_len; - unsigned int dst_len; - void *__ctx[] CRYPTO_MINALIGN_ATTR; -}; - -/** - * struct crypto_kpp - user-instantiated object which encapsulate - * algorithms and core processing logic - * - * @base: Common crypto API algorithm data structure - */ -struct crypto_kpp { - struct crypto_tfm base; -}; - -/** - * struct kpp_alg - generic key-agreement protocol primitives - * - * @set_secret: Function invokes the protocol specific function to - * store the secret private key along with parameters. - * The implementation knows how to decode thie buffer - * @generate_public_key: Function generate the public key to be sent to the - * counterpart. In case of error, where output is not big - * enough req->dst_len will be updated to the size - * required - * @compute_shared_secret: Function compute the shared secret as defined by - * the algorithm. The result is given back to the user. - * In case of error, where output is not big enough, - * req->dst_len will be updated to the size required - * @max_size: Function returns the size of the output buffer - * @init: Initialize the object. This is called only once at - * instantiation time. In case the cryptographic hardware - * needs to be initialized. Software fallback should be - * put in place here. - * @exit: Undo everything @init did. - * - * @reqsize: Request context size required by algorithm - * implementation - * @base Common crypto API algorithm data structure - */ -struct kpp_alg { - int (*set_secret)(struct crypto_kpp *tfm, void *buffer, - unsigned int len); - int (*generate_public_key)(struct kpp_request *req); - int (*compute_shared_secret)(struct kpp_request *req); - - int (*max_size)(struct crypto_kpp *tfm); - - int (*init)(struct crypto_kpp *tfm); - void (*exit)(struct crypto_kpp *tfm); - - unsigned int reqsize; - struct crypto_alg base; -}; - -/** - * DOC: Generic Key-agreement Protocol Primitevs API - * - * The KPP API is used with the algorithm type - * CRYPTO_ALG_TYPE_KPP (listed as type "kpp" in /proc/crypto) - */ - -/** - * crypto_alloc_kpp() - allocate KPP tfm handle - * @alg_name: is the name of the kpp algorithm (e.g. "dh", "ecdh") - * @type: specifies the type of the algorithm - * @mask: specifies the mask for the algorithm - * - * Allocate a handle for kpp algorithm. The returned struct crypto_kpp - * is requeried for any following API invocation - * - * Return: allocated handle in case of success; IS_ERR() is true in case of - * an error, PTR_ERR() returns the error code. - */ -struct crypto_kpp *crypto_alloc_kpp(const char *alg_name, u32 type, u32 mask); - -static inline struct crypto_tfm *crypto_kpp_tfm(struct crypto_kpp *tfm) -{ - return &tfm->base; -} - -static inline struct kpp_alg *__crypto_kpp_alg(struct crypto_alg *alg) -{ - return container_of(alg, struct kpp_alg, base); -} - -static inline struct crypto_kpp *__crypto_kpp_tfm(struct crypto_tfm *tfm) -{ - return container_of(tfm, struct crypto_kpp, base); -} - -static inline struct kpp_alg *crypto_kpp_alg(struct crypto_kpp *tfm) -{ - return __crypto_kpp_alg(crypto_kpp_tfm(tfm)->__crt_alg); -} - -static inline unsigned int crypto_kpp_reqsize(struct crypto_kpp *tfm) -{ - return crypto_kpp_alg(tfm)->reqsize; -} - -static inline void kpp_request_set_tfm(struct kpp_request *req, - struct crypto_kpp *tfm) -{ - req->base.tfm = crypto_kpp_tfm(tfm); -} - -static inline struct crypto_kpp *crypto_kpp_reqtfm(struct kpp_request *req) -{ - return __crypto_kpp_tfm(req->base.tfm); -} - -/** - * crypto_free_kpp() - free KPP tfm handle - * - * @tfm: KPP tfm handle allocated with crypto_alloc_kpp() - */ -static inline void crypto_free_kpp(struct crypto_kpp *tfm) -{ - crypto_destroy_tfm(tfm, crypto_kpp_tfm(tfm)); -} - -/** - * kpp_request_alloc() - allocates kpp request - * - * @tfm: KPP tfm handle allocated with crypto_alloc_kpp() - * @gfp: allocation flags - * - * Return: allocated handle in case of success or NULL in case of an error. - */ -static inline struct kpp_request *kpp_request_alloc(struct crypto_kpp *tfm, - gfp_t gfp) -{ - struct kpp_request *req; - - req = kmalloc(sizeof(*req) + crypto_kpp_reqsize(tfm), gfp); - if (likely(req)) - kpp_request_set_tfm(req, tfm); - - return req; -} - -/** - * kpp_request_free() - zeroize and free kpp request - * - * @req: request to free - */ -static inline void kpp_request_free(struct kpp_request *req) -{ - kzfree(req); -} - -/** - * kpp_request_set_callback() - Sets an asynchronous callback. - * - * Callback will be called when an asynchronous operation on a given - * request is finished. - * - * @req: request that the callback will be set for - * @flgs: specify for instance if the operation may backlog - * @cmpl: callback which will be called - * @data: private data used by the caller - */ -static inline void kpp_request_set_callback(struct kpp_request *req, - u32 flgs, - crypto_completion_t cmpl, - void *data) -{ - req->base.complete = cmpl; - req->base.data = data; - req->base.flags = flgs; -} - -/** - * kpp_request_set_input() - Sets input buffer - * - * Sets parameters required by generate_public_key - * - * @req: kpp request - * @input: ptr to input scatter list - * @input_len: size of the input scatter list - */ -static inline void kpp_request_set_input(struct kpp_request *req, - struct scatterlist *input, - unsigned int input_len) -{ - req->src = input; - req->src_len = input_len; -} - -/** - * kpp_request_set_output() - Sets output buffer - * - * Sets parameters required by kpp operation - * - * @req: kpp request - * @output: ptr to output scatter list - * @output_len: size of the output scatter list - */ -static inline void kpp_request_set_output(struct kpp_request *req, - struct scatterlist *output, - unsigned int output_len) -{ - req->dst = output; - req->dst_len = output_len; -} - -enum { - CRYPTO_KPP_SECRET_TYPE_UNKNOWN, - CRYPTO_KPP_SECRET_TYPE_DH, - CRYPTO_KPP_SECRET_TYPE_ECDH, -}; - -/** - * struct kpp_secret - small header for packing secret buffer - * - * @type: define type of secret. Each kpp type will define its own - * @len: specify the len of the secret, include the header, that - * follows the struct - */ -struct kpp_secret { - unsigned short type; - unsigned short len; -}; - -/** - * crypto_kpp_set_secret() - Invoke kpp operation - * - * Function invokes the specific kpp operation for a given alg. - * - * @tfm: tfm handle - * - * Return: zero on success; error code in case of error - */ -static inline int crypto_kpp_set_secret(struct crypto_kpp *tfm, void *buffer, - unsigned int len) -{ - struct kpp_alg *alg = crypto_kpp_alg(tfm); - - return alg->set_secret(tfm, buffer, len); -} - -/** - * crypto_kpp_generate_public_key() - Invoke kpp operation - * - * Function invokes the specific kpp operation for generating the public part - * for a given kpp algorithm - * - * @req: kpp key request - * - * Return: zero on success; error code in case of error - */ -static inline int crypto_kpp_generate_public_key(struct kpp_request *req) -{ - struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); - struct kpp_alg *alg = crypto_kpp_alg(tfm); - - return alg->generate_public_key(req); -} - -/** - * crypto_kpp_compute_shared_secret() - Invoke kpp operation - * - * Function invokes the specific kpp operation for computing the shared secret - * for a given kpp algorithm. - * - * @req: kpp key request - * - * Return: zero on success; error code in case of error - */ -static inline int crypto_kpp_compute_shared_secret(struct kpp_request *req) -{ - struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); - struct kpp_alg *alg = crypto_kpp_alg(tfm); - - return alg->compute_shared_secret(req); -} - -/** - * crypto_kpp_maxsize() - Get len for output buffer - * - * Function returns the output buffer size required - * - * @tfm: KPP tfm handle allocated with crypto_alloc_kpp() - * - * Return: minimum len for output buffer or error code if key hasn't been set - */ -static inline int crypto_kpp_maxsize(struct crypto_kpp *tfm) -{ - struct kpp_alg *alg = crypto_kpp_alg(tfm); - - return alg->max_size(tfm); -} - -#endif diff --git a/src/linux/include/crypto/null.h b/src/linux/include/crypto/null.h deleted file mode 100644 index 3f0c59f..0000000 --- a/src/linux/include/crypto/null.h +++ /dev/null @@ -1,24 +0,0 @@ -/* Values for NULL algorithms */ - -#ifndef _CRYPTO_NULL_H -#define _CRYPTO_NULL_H - -#define NULL_KEY_SIZE 0 -#define NULL_BLOCK_SIZE 1 -#define NULL_DIGEST_SIZE 0 -#define NULL_IV_SIZE 0 - -struct crypto_skcipher *crypto_get_default_null_skcipher(void); -void crypto_put_default_null_skcipher(void); - -static inline struct crypto_skcipher *crypto_get_default_null_skcipher2(void) -{ - return crypto_get_default_null_skcipher(); -} - -static inline void crypto_put_default_null_skcipher2(void) -{ - crypto_put_default_null_skcipher(); -} - -#endif diff --git a/src/linux/include/crypto/rng.h b/src/linux/include/crypto/rng.h deleted file mode 100644 index b95ede3..0000000 --- a/src/linux/include/crypto/rng.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * RNG: Random Number Generator algorithms under the crypto API - * - * Copyright (c) 2008 Neil Horman - * Copyright (c) 2015 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#ifndef _CRYPTO_RNG_H -#define _CRYPTO_RNG_H - -#include - -struct crypto_rng; - -/** - * struct rng_alg - random number generator definition - * - * @generate: The function defined by this variable obtains a - * random number. The random number generator transform - * must generate the random number out of the context - * provided with this call, plus any additional data - * if provided to the call. - * @seed: Seed or reseed the random number generator. With the - * invocation of this function call, the random number - * generator shall become ready for generation. If the - * random number generator requires a seed for setting - * up a new state, the seed must be provided by the - * consumer while invoking this function. The required - * size of the seed is defined with @seedsize . - * @set_ent: Set entropy that would otherwise be obtained from - * entropy source. Internal use only. - * @seedsize: The seed size required for a random number generator - * initialization defined with this variable. Some - * random number generators does not require a seed - * as the seeding is implemented internally without - * the need of support by the consumer. In this case, - * the seed size is set to zero. - * @base: Common crypto API algorithm data structure. - */ -struct rng_alg { - int (*generate)(struct crypto_rng *tfm, - const u8 *src, unsigned int slen, - u8 *dst, unsigned int dlen); - int (*seed)(struct crypto_rng *tfm, const u8 *seed, unsigned int slen); - void (*set_ent)(struct crypto_rng *tfm, const u8 *data, - unsigned int len); - - unsigned int seedsize; - - struct crypto_alg base; -}; - -struct crypto_rng { - struct crypto_tfm base; -}; - -extern struct crypto_rng *crypto_default_rng; - -int crypto_get_default_rng(void); -void crypto_put_default_rng(void); - -/** - * DOC: Random number generator API - * - * The random number generator API is used with the ciphers of type - * CRYPTO_ALG_TYPE_RNG (listed as type "rng" in /proc/crypto) - */ - -/** - * crypto_alloc_rng() -- allocate RNG handle - * @alg_name: is the cra_name / name or cra_driver_name / driver name of the - * message digest cipher - * @type: specifies the type of the cipher - * @mask: specifies the mask for the cipher - * - * Allocate a cipher handle for a random number generator. The returned struct - * crypto_rng is the cipher handle that is required for any subsequent - * API invocation for that random number generator. - * - * For all random number generators, this call creates a new private copy of - * the random number generator that does not share a state with other - * instances. The only exception is the "krng" random number generator which - * is a kernel crypto API use case for the get_random_bytes() function of the - * /dev/random driver. - * - * Return: allocated cipher handle in case of success; IS_ERR() is true in case - * of an error, PTR_ERR() returns the error code. - */ -struct crypto_rng *crypto_alloc_rng(const char *alg_name, u32 type, u32 mask); - -static inline struct crypto_tfm *crypto_rng_tfm(struct crypto_rng *tfm) -{ - return &tfm->base; -} - -/** - * crypto_rng_alg - obtain name of RNG - * @tfm: cipher handle - * - * Return the generic name (cra_name) of the initialized random number generator - * - * Return: generic name string - */ -static inline struct rng_alg *crypto_rng_alg(struct crypto_rng *tfm) -{ - return container_of(crypto_rng_tfm(tfm)->__crt_alg, - struct rng_alg, base); -} - -/** - * crypto_free_rng() - zeroize and free RNG handle - * @tfm: cipher handle to be freed - */ -static inline void crypto_free_rng(struct crypto_rng *tfm) -{ - crypto_destroy_tfm(tfm, crypto_rng_tfm(tfm)); -} - -/** - * crypto_rng_generate() - get random number - * @tfm: cipher handle - * @src: Input buffer holding additional data, may be NULL - * @slen: Length of additional data - * @dst: output buffer holding the random numbers - * @dlen: length of the output buffer - * - * This function fills the caller-allocated buffer with random - * numbers using the random number generator referenced by the - * cipher handle. - * - * Return: 0 function was successful; < 0 if an error occurred - */ -static inline int crypto_rng_generate(struct crypto_rng *tfm, - const u8 *src, unsigned int slen, - u8 *dst, unsigned int dlen) -{ - return crypto_rng_alg(tfm)->generate(tfm, src, slen, dst, dlen); -} - -/** - * crypto_rng_get_bytes() - get random number - * @tfm: cipher handle - * @rdata: output buffer holding the random numbers - * @dlen: length of the output buffer - * - * This function fills the caller-allocated buffer with random numbers using the - * random number generator referenced by the cipher handle. - * - * Return: 0 function was successful; < 0 if an error occurred - */ -static inline int crypto_rng_get_bytes(struct crypto_rng *tfm, - u8 *rdata, unsigned int dlen) -{ - return crypto_rng_generate(tfm, NULL, 0, rdata, dlen); -} - -/** - * crypto_rng_reset() - re-initialize the RNG - * @tfm: cipher handle - * @seed: seed input data - * @slen: length of the seed input data - * - * The reset function completely re-initializes the random number generator - * referenced by the cipher handle by clearing the current state. The new state - * is initialized with the caller provided seed or automatically, depending - * on the random number generator type (the ANSI X9.31 RNG requires - * caller-provided seed, the SP800-90A DRBGs perform an automatic seeding). - * The seed is provided as a parameter to this function call. The provided seed - * should have the length of the seed size defined for the random number - * generator as defined by crypto_rng_seedsize. - * - * Return: 0 if the setting of the key was successful; < 0 if an error occurred - */ -int crypto_rng_reset(struct crypto_rng *tfm, const u8 *seed, - unsigned int slen); - -/** - * crypto_rng_seedsize() - obtain seed size of RNG - * @tfm: cipher handle - * - * The function returns the seed size for the random number generator - * referenced by the cipher handle. This value may be zero if the random - * number generator does not implement or require a reseeding. For example, - * the SP800-90A DRBGs implement an automated reseeding after reaching a - * pre-defined threshold. - * - * Return: seed size for the random number generator - */ -static inline int crypto_rng_seedsize(struct crypto_rng *tfm) -{ - return crypto_rng_alg(tfm)->seedsize; -} - -#endif diff --git a/src/linux/include/crypto/scatterwalk.h b/src/linux/include/crypto/scatterwalk.h deleted file mode 100644 index 880e6be..0000000 --- a/src/linux/include/crypto/scatterwalk.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Cryptographic scatter and gather helpers. - * - * Copyright (c) 2002 James Morris - * Copyright (c) 2002 Adam J. Richter - * Copyright (c) 2004 Jean-Luc Cooke - * Copyright (c) 2007 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#ifndef _CRYPTO_SCATTERWALK_H -#define _CRYPTO_SCATTERWALK_H - -#include -#include -#include -#include - -static inline void scatterwalk_crypto_chain(struct scatterlist *head, - struct scatterlist *sg, - int chain, int num) -{ - if (chain) { - head->length += sg->length; - sg = sg_next(sg); - } - - if (sg) - sg_chain(head, num, sg); - else - sg_mark_end(head); -} - -static inline unsigned long scatterwalk_samebuf(struct scatter_walk *walk_in, - struct scatter_walk *walk_out) -{ - return !(((sg_page(walk_in->sg) - sg_page(walk_out->sg)) << PAGE_SHIFT) + - (int)(walk_in->offset - walk_out->offset)); -} - -static inline unsigned int scatterwalk_pagelen(struct scatter_walk *walk) -{ - unsigned int len = walk->sg->offset + walk->sg->length - walk->offset; - unsigned int len_this_page = offset_in_page(~walk->offset) + 1; - return len_this_page > len ? len : len_this_page; -} - -static inline unsigned int scatterwalk_clamp(struct scatter_walk *walk, - unsigned int nbytes) -{ - unsigned int len_this_page = scatterwalk_pagelen(walk); - return nbytes > len_this_page ? len_this_page : nbytes; -} - -static inline void scatterwalk_advance(struct scatter_walk *walk, - unsigned int nbytes) -{ - walk->offset += nbytes; -} - -static inline unsigned int scatterwalk_aligned(struct scatter_walk *walk, - unsigned int alignmask) -{ - return !(walk->offset & alignmask); -} - -static inline struct page *scatterwalk_page(struct scatter_walk *walk) -{ - return sg_page(walk->sg) + (walk->offset >> PAGE_SHIFT); -} - -static inline void scatterwalk_unmap(void *vaddr) -{ - kunmap_atomic(vaddr); -} - -static inline void scatterwalk_start(struct scatter_walk *walk, - struct scatterlist *sg) -{ - walk->sg = sg; - walk->offset = sg->offset; -} - -static inline void *scatterwalk_map(struct scatter_walk *walk) -{ - return kmap_atomic(scatterwalk_page(walk)) + - offset_in_page(walk->offset); -} - -static inline void scatterwalk_pagedone(struct scatter_walk *walk, int out, - unsigned int more) -{ - if (out) { - struct page *page; - - page = sg_page(walk->sg) + ((walk->offset - 1) >> PAGE_SHIFT); - /* Test ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE first as - * PageSlab cannot be optimised away per se due to - * use of volatile pointer. - */ - if (ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE && !PageSlab(page)) - flush_dcache_page(page); - } - - if (more && walk->offset >= walk->sg->offset + walk->sg->length) - scatterwalk_start(walk, sg_next(walk->sg)); -} - -static inline void scatterwalk_done(struct scatter_walk *walk, int out, - int more) -{ - if (!more || walk->offset >= walk->sg->offset + walk->sg->length || - !(walk->offset & (PAGE_SIZE - 1))) - scatterwalk_pagedone(walk, out, more); -} - -void scatterwalk_copychunks(void *buf, struct scatter_walk *walk, - size_t nbytes, int out); -void *scatterwalk_map(struct scatter_walk *walk); - -void scatterwalk_map_and_copy(void *buf, struct scatterlist *sg, - unsigned int start, unsigned int nbytes, int out); - -struct scatterlist *scatterwalk_ffwd(struct scatterlist dst[2], - struct scatterlist *src, - unsigned int len); - -#endif /* _CRYPTO_SCATTERWALK_H */ diff --git a/src/linux/include/crypto/sha.h b/src/linux/include/crypto/sha.h deleted file mode 100644 index c94d3eb..0000000 --- a/src/linux/include/crypto/sha.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Common values for SHA algorithms - */ - -#ifndef _CRYPTO_SHA_H -#define _CRYPTO_SHA_H - -#include - -#define SHA1_DIGEST_SIZE 20 -#define SHA1_BLOCK_SIZE 64 - -#define SHA224_DIGEST_SIZE 28 -#define SHA224_BLOCK_SIZE 64 - -#define SHA256_DIGEST_SIZE 32 -#define SHA256_BLOCK_SIZE 64 - -#define SHA384_DIGEST_SIZE 48 -#define SHA384_BLOCK_SIZE 128 - -#define SHA512_DIGEST_SIZE 64 -#define SHA512_BLOCK_SIZE 128 - -#define SHA1_H0 0x67452301UL -#define SHA1_H1 0xefcdab89UL -#define SHA1_H2 0x98badcfeUL -#define SHA1_H3 0x10325476UL -#define SHA1_H4 0xc3d2e1f0UL - -#define SHA224_H0 0xc1059ed8UL -#define SHA224_H1 0x367cd507UL -#define SHA224_H2 0x3070dd17UL -#define SHA224_H3 0xf70e5939UL -#define SHA224_H4 0xffc00b31UL -#define SHA224_H5 0x68581511UL -#define SHA224_H6 0x64f98fa7UL -#define SHA224_H7 0xbefa4fa4UL - -#define SHA256_H0 0x6a09e667UL -#define SHA256_H1 0xbb67ae85UL -#define SHA256_H2 0x3c6ef372UL -#define SHA256_H3 0xa54ff53aUL -#define SHA256_H4 0x510e527fUL -#define SHA256_H5 0x9b05688cUL -#define SHA256_H6 0x1f83d9abUL -#define SHA256_H7 0x5be0cd19UL - -#define SHA384_H0 0xcbbb9d5dc1059ed8ULL -#define SHA384_H1 0x629a292a367cd507ULL -#define SHA384_H2 0x9159015a3070dd17ULL -#define SHA384_H3 0x152fecd8f70e5939ULL -#define SHA384_H4 0x67332667ffc00b31ULL -#define SHA384_H5 0x8eb44a8768581511ULL -#define SHA384_H6 0xdb0c2e0d64f98fa7ULL -#define SHA384_H7 0x47b5481dbefa4fa4ULL - -#define SHA512_H0 0x6a09e667f3bcc908ULL -#define SHA512_H1 0xbb67ae8584caa73bULL -#define SHA512_H2 0x3c6ef372fe94f82bULL -#define SHA512_H3 0xa54ff53a5f1d36f1ULL -#define SHA512_H4 0x510e527fade682d1ULL -#define SHA512_H5 0x9b05688c2b3e6c1fULL -#define SHA512_H6 0x1f83d9abfb41bd6bULL -#define SHA512_H7 0x5be0cd19137e2179ULL - -extern const u8 sha1_zero_message_hash[SHA1_DIGEST_SIZE]; - -extern const u8 sha224_zero_message_hash[SHA224_DIGEST_SIZE]; - -extern const u8 sha256_zero_message_hash[SHA256_DIGEST_SIZE]; - -struct sha1_state { - u32 state[SHA1_DIGEST_SIZE / 4]; - u64 count; - u8 buffer[SHA1_BLOCK_SIZE]; -}; - -struct sha256_state { - u32 state[SHA256_DIGEST_SIZE / 4]; - u64 count; - u8 buf[SHA256_BLOCK_SIZE]; -}; - -struct sha512_state { - u64 state[SHA512_DIGEST_SIZE / 8]; - u64 count[2]; - u8 buf[SHA512_BLOCK_SIZE]; -}; - -struct shash_desc; - -extern int crypto_sha1_update(struct shash_desc *desc, const u8 *data, - unsigned int len); - -extern int crypto_sha1_finup(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *hash); - -extern int crypto_sha256_update(struct shash_desc *desc, const u8 *data, - unsigned int len); - -extern int crypto_sha256_finup(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *hash); - -extern int crypto_sha512_update(struct shash_desc *desc, const u8 *data, - unsigned int len); - -extern int crypto_sha512_finup(struct shash_desc *desc, const u8 *data, - unsigned int len, u8 *hash); -#endif diff --git a/src/linux/include/crypto/sha256_base.h b/src/linux/include/crypto/sha256_base.h deleted file mode 100644 index d1f2195..0000000 --- a/src/linux/include/crypto/sha256_base.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * sha256_base.h - core logic for SHA-256 implementations - * - * Copyright (C) 2015 Linaro Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include - -#include - -typedef void (sha256_block_fn)(struct sha256_state *sst, u8 const *src, - int blocks); - -static inline int sha224_base_init(struct shash_desc *desc) -{ - struct sha256_state *sctx = shash_desc_ctx(desc); - - sctx->state[0] = SHA224_H0; - sctx->state[1] = SHA224_H1; - sctx->state[2] = SHA224_H2; - sctx->state[3] = SHA224_H3; - sctx->state[4] = SHA224_H4; - sctx->state[5] = SHA224_H5; - sctx->state[6] = SHA224_H6; - sctx->state[7] = SHA224_H7; - sctx->count = 0; - - return 0; -} - -static inline int sha256_base_init(struct shash_desc *desc) -{ - struct sha256_state *sctx = shash_desc_ctx(desc); - - sctx->state[0] = SHA256_H0; - sctx->state[1] = SHA256_H1; - sctx->state[2] = SHA256_H2; - sctx->state[3] = SHA256_H3; - sctx->state[4] = SHA256_H4; - sctx->state[5] = SHA256_H5; - sctx->state[6] = SHA256_H6; - sctx->state[7] = SHA256_H7; - sctx->count = 0; - - return 0; -} - -static inline int sha256_base_do_update(struct shash_desc *desc, - const u8 *data, - unsigned int len, - sha256_block_fn *block_fn) -{ - struct sha256_state *sctx = shash_desc_ctx(desc); - unsigned int partial = sctx->count % SHA256_BLOCK_SIZE; - - sctx->count += len; - - if (unlikely((partial + len) >= SHA256_BLOCK_SIZE)) { - int blocks; - - if (partial) { - int p = SHA256_BLOCK_SIZE - partial; - - memcpy(sctx->buf + partial, data, p); - data += p; - len -= p; - - block_fn(sctx, sctx->buf, 1); - } - - blocks = len / SHA256_BLOCK_SIZE; - len %= SHA256_BLOCK_SIZE; - - if (blocks) { - block_fn(sctx, data, blocks); - data += blocks * SHA256_BLOCK_SIZE; - } - partial = 0; - } - if (len) - memcpy(sctx->buf + partial, data, len); - - return 0; -} - -static inline int sha256_base_do_finalize(struct shash_desc *desc, - sha256_block_fn *block_fn) -{ - const int bit_offset = SHA256_BLOCK_SIZE - sizeof(__be64); - struct sha256_state *sctx = shash_desc_ctx(desc); - __be64 *bits = (__be64 *)(sctx->buf + bit_offset); - unsigned int partial = sctx->count % SHA256_BLOCK_SIZE; - - sctx->buf[partial++] = 0x80; - if (partial > bit_offset) { - memset(sctx->buf + partial, 0x0, SHA256_BLOCK_SIZE - partial); - partial = 0; - - block_fn(sctx, sctx->buf, 1); - } - - memset(sctx->buf + partial, 0x0, bit_offset - partial); - *bits = cpu_to_be64(sctx->count << 3); - block_fn(sctx, sctx->buf, 1); - - return 0; -} - -static inline int sha256_base_finish(struct shash_desc *desc, u8 *out) -{ - unsigned int digest_size = crypto_shash_digestsize(desc->tfm); - struct sha256_state *sctx = shash_desc_ctx(desc); - __be32 *digest = (__be32 *)out; - int i; - - for (i = 0; digest_size > 0; i++, digest_size -= sizeof(__be32)) - put_unaligned_be32(sctx->state[i], digest++); - - *sctx = (struct sha256_state){}; - return 0; -} diff --git a/src/linux/include/crypto/skcipher.h b/src/linux/include/crypto/skcipher.h deleted file mode 100644 index cc4d98a..0000000 --- a/src/linux/include/crypto/skcipher.h +++ /dev/null @@ -1,578 +0,0 @@ -/* - * Symmetric key ciphers. - * - * Copyright (c) 2007-2015 Herbert Xu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#ifndef _CRYPTO_SKCIPHER_H -#define _CRYPTO_SKCIPHER_H - -#include -#include -#include - -/** - * struct skcipher_request - Symmetric key cipher request - * @cryptlen: Number of bytes to encrypt or decrypt - * @iv: Initialisation Vector - * @src: Source SG list - * @dst: Destination SG list - * @base: Underlying async request request - * @__ctx: Start of private context data - */ -struct skcipher_request { - unsigned int cryptlen; - - u8 *iv; - - struct scatterlist *src; - struct scatterlist *dst; - - struct crypto_async_request base; - - void *__ctx[] CRYPTO_MINALIGN_ATTR; -}; - -/** - * struct skcipher_givcrypt_request - Crypto request with IV generation - * @seq: Sequence number for IV generation - * @giv: Space for generated IV - * @creq: The crypto request itself - */ -struct skcipher_givcrypt_request { - u64 seq; - u8 *giv; - - struct ablkcipher_request creq; -}; - -struct crypto_skcipher { - int (*setkey)(struct crypto_skcipher *tfm, const u8 *key, - unsigned int keylen); - int (*encrypt)(struct skcipher_request *req); - int (*decrypt)(struct skcipher_request *req); - - unsigned int ivsize; - unsigned int reqsize; - unsigned int keysize; - - struct crypto_tfm base; -}; - -/** - * struct skcipher_alg - symmetric key cipher definition - * @min_keysize: Minimum key size supported by the transformation. This is the - * smallest key length supported by this transformation algorithm. - * This must be set to one of the pre-defined values as this is - * not hardware specific. Possible values for this field can be - * found via git grep "_MIN_KEY_SIZE" include/crypto/ - * @max_keysize: Maximum key size supported by the transformation. This is the - * largest key length supported by this transformation algorithm. - * This must be set to one of the pre-defined values as this is - * not hardware specific. Possible values for this field can be - * found via git grep "_MAX_KEY_SIZE" include/crypto/ - * @setkey: Set key for the transformation. This function is used to either - * program a supplied key into the hardware or store the key in the - * transformation context for programming it later. Note that this - * function does modify the transformation context. This function can - * be called multiple times during the existence of the transformation - * object, so one must make sure the key is properly reprogrammed into - * the hardware. This function is also responsible for checking the key - * length for validity. In case a software fallback was put in place in - * the @cra_init call, this function might need to use the fallback if - * the algorithm doesn't support all of the key sizes. - * @encrypt: Encrypt a scatterlist of blocks. This function is used to encrypt - * the supplied scatterlist containing the blocks of data. The crypto - * API consumer is responsible for aligning the entries of the - * scatterlist properly and making sure the chunks are correctly - * sized. In case a software fallback was put in place in the - * @cra_init call, this function might need to use the fallback if - * the algorithm doesn't support all of the key sizes. In case the - * key was stored in transformation context, the key might need to be - * re-programmed into the hardware in this function. This function - * shall not modify the transformation context, as this function may - * be called in parallel with the same transformation object. - * @decrypt: Decrypt a single block. This is a reverse counterpart to @encrypt - * and the conditions are exactly the same. - * @init: Initialize the cryptographic transformation object. This function - * is used to initialize the cryptographic transformation object. - * This function is called only once at the instantiation time, right - * after the transformation context was allocated. In case the - * cryptographic hardware has some special requirements which need to - * be handled by software, this function shall check for the precise - * requirement of the transformation and put any software fallbacks - * in place. - * @exit: Deinitialize the cryptographic transformation object. This is a - * counterpart to @init, used to remove various changes set in - * @init. - * @ivsize: IV size applicable for transformation. The consumer must provide an - * IV of exactly that size to perform the encrypt or decrypt operation. - * @chunksize: Equal to the block size except for stream ciphers such as - * CTR where it is set to the underlying block size. - * @base: Definition of a generic crypto algorithm. - * - * All fields except @ivsize are mandatory and must be filled. - */ -struct skcipher_alg { - int (*setkey)(struct crypto_skcipher *tfm, const u8 *key, - unsigned int keylen); - int (*encrypt)(struct skcipher_request *req); - int (*decrypt)(struct skcipher_request *req); - int (*init)(struct crypto_skcipher *tfm); - void (*exit)(struct crypto_skcipher *tfm); - - unsigned int min_keysize; - unsigned int max_keysize; - unsigned int ivsize; - unsigned int chunksize; - - struct crypto_alg base; -}; - -#define SKCIPHER_REQUEST_ON_STACK(name, tfm) \ - char __##name##_desc[sizeof(struct skcipher_request) + \ - crypto_skcipher_reqsize(tfm)] CRYPTO_MINALIGN_ATTR; \ - struct skcipher_request *name = (void *)__##name##_desc - -/** - * DOC: Symmetric Key Cipher API - * - * Symmetric key cipher API is used with the ciphers of type - * CRYPTO_ALG_TYPE_SKCIPHER (listed as type "skcipher" in /proc/crypto). - * - * Asynchronous cipher operations imply that the function invocation for a - * cipher request returns immediately before the completion of the operation. - * The cipher request is scheduled as a separate kernel thread and therefore - * load-balanced on the different CPUs via the process scheduler. To allow - * the kernel crypto API to inform the caller about the completion of a cipher - * request, the caller must provide a callback function. That function is - * invoked with the cipher handle when the request completes. - * - * To support the asynchronous operation, additional information than just the - * cipher handle must be supplied to the kernel crypto API. That additional - * information is given by filling in the skcipher_request data structure. - * - * For the symmetric key cipher API, the state is maintained with the tfm - * cipher handle. A single tfm can be used across multiple calls and in - * parallel. For asynchronous block cipher calls, context data supplied and - * only used by the caller can be referenced the request data structure in - * addition to the IV used for the cipher request. The maintenance of such - * state information would be important for a crypto driver implementer to - * have, because when calling the callback function upon completion of the - * cipher operation, that callback function may need some information about - * which operation just finished if it invoked multiple in parallel. This - * state information is unused by the kernel crypto API. - */ - -static inline struct crypto_skcipher *__crypto_skcipher_cast( - struct crypto_tfm *tfm) -{ - return container_of(tfm, struct crypto_skcipher, base); -} - -/** - * crypto_alloc_skcipher() - allocate symmetric key cipher handle - * @alg_name: is the cra_name / name or cra_driver_name / driver name of the - * skcipher cipher - * @type: specifies the type of the cipher - * @mask: specifies the mask for the cipher - * - * Allocate a cipher handle for an skcipher. The returned struct - * crypto_skcipher is the cipher handle that is required for any subsequent - * API invocation for that skcipher. - * - * Return: allocated cipher handle in case of success; IS_ERR() is true in case - * of an error, PTR_ERR() returns the error code. - */ -struct crypto_skcipher *crypto_alloc_skcipher(const char *alg_name, - u32 type, u32 mask); - -static inline struct crypto_tfm *crypto_skcipher_tfm( - struct crypto_skcipher *tfm) -{ - return &tfm->base; -} - -/** - * crypto_free_skcipher() - zeroize and free cipher handle - * @tfm: cipher handle to be freed - */ -static inline void crypto_free_skcipher(struct crypto_skcipher *tfm) -{ - crypto_destroy_tfm(tfm, crypto_skcipher_tfm(tfm)); -} - -/** - * crypto_has_skcipher() - Search for the availability of an skcipher. - * @alg_name: is the cra_name / name or cra_driver_name / driver name of the - * skcipher - * @type: specifies the type of the cipher - * @mask: specifies the mask for the cipher - * - * Return: true when the skcipher is known to the kernel crypto API; false - * otherwise - */ -static inline int crypto_has_skcipher(const char *alg_name, u32 type, - u32 mask) -{ - return crypto_has_alg(alg_name, crypto_skcipher_type(type), - crypto_skcipher_mask(mask)); -} - -/** - * crypto_has_skcipher2() - Search for the availability of an skcipher. - * @alg_name: is the cra_name / name or cra_driver_name / driver name of the - * skcipher - * @type: specifies the type of the skcipher - * @mask: specifies the mask for the skcipher - * - * Return: true when the skcipher is known to the kernel crypto API; false - * otherwise - */ -int crypto_has_skcipher2(const char *alg_name, u32 type, u32 mask); - -static inline const char *crypto_skcipher_driver_name( - struct crypto_skcipher *tfm) -{ - return crypto_tfm_alg_driver_name(crypto_skcipher_tfm(tfm)); -} - -static inline struct skcipher_alg *crypto_skcipher_alg( - struct crypto_skcipher *tfm) -{ - return container_of(crypto_skcipher_tfm(tfm)->__crt_alg, - struct skcipher_alg, base); -} - -static inline unsigned int crypto_skcipher_alg_ivsize(struct skcipher_alg *alg) -{ - if ((alg->base.cra_flags & CRYPTO_ALG_TYPE_MASK) == - CRYPTO_ALG_TYPE_BLKCIPHER) - return alg->base.cra_blkcipher.ivsize; - - if (alg->base.cra_ablkcipher.encrypt) - return alg->base.cra_ablkcipher.ivsize; - - return alg->ivsize; -} - -/** - * crypto_skcipher_ivsize() - obtain IV size - * @tfm: cipher handle - * - * The size of the IV for the skcipher referenced by the cipher handle is - * returned. This IV size may be zero if the cipher does not need an IV. - * - * Return: IV size in bytes - */ -static inline unsigned int crypto_skcipher_ivsize(struct crypto_skcipher *tfm) -{ - return tfm->ivsize; -} - -static inline unsigned int crypto_skcipher_alg_chunksize( - struct skcipher_alg *alg) -{ - if ((alg->base.cra_flags & CRYPTO_ALG_TYPE_MASK) == - CRYPTO_ALG_TYPE_BLKCIPHER) - return alg->base.cra_blocksize; - - if (alg->base.cra_ablkcipher.encrypt) - return alg->base.cra_blocksize; - - return alg->chunksize; -} - -/** - * crypto_skcipher_chunksize() - obtain chunk size - * @tfm: cipher handle - * - * The block size is set to one for ciphers such as CTR. However, - * you still need to provide incremental updates in multiples of - * the underlying block size as the IV does not have sub-block - * granularity. This is known in this API as the chunk size. - * - * Return: chunk size in bytes - */ -static inline unsigned int crypto_skcipher_chunksize( - struct crypto_skcipher *tfm) -{ - return crypto_skcipher_alg_chunksize(crypto_skcipher_alg(tfm)); -} - -/** - * crypto_skcipher_blocksize() - obtain block size of cipher - * @tfm: cipher handle - * - * The block size for the skcipher referenced with the cipher handle is - * returned. The caller may use that information to allocate appropriate - * memory for the data returned by the encryption or decryption operation - * - * Return: block size of cipher - */ -static inline unsigned int crypto_skcipher_blocksize( - struct crypto_skcipher *tfm) -{ - return crypto_tfm_alg_blocksize(crypto_skcipher_tfm(tfm)); -} - -static inline unsigned int crypto_skcipher_alignmask( - struct crypto_skcipher *tfm) -{ - return crypto_tfm_alg_alignmask(crypto_skcipher_tfm(tfm)); -} - -static inline u32 crypto_skcipher_get_flags(struct crypto_skcipher *tfm) -{ - return crypto_tfm_get_flags(crypto_skcipher_tfm(tfm)); -} - -static inline void crypto_skcipher_set_flags(struct crypto_skcipher *tfm, - u32 flags) -{ - crypto_tfm_set_flags(crypto_skcipher_tfm(tfm), flags); -} - -static inline void crypto_skcipher_clear_flags(struct crypto_skcipher *tfm, - u32 flags) -{ - crypto_tfm_clear_flags(crypto_skcipher_tfm(tfm), flags); -} - -/** - * crypto_skcipher_setkey() - set key for cipher - * @tfm: cipher handle - * @key: buffer holding the key - * @keylen: length of the key in bytes - * - * The caller provided key is set for the skcipher referenced by the cipher - * handle. - * - * Note, the key length determines the cipher type. Many block ciphers implement - * different cipher modes depending on the key size, such as AES-128 vs AES-192 - * vs. AES-256. When providing a 16 byte key for an AES cipher handle, AES-128 - * is performed. - * - * Return: 0 if the setting of the key was successful; < 0 if an error occurred - */ -static inline int crypto_skcipher_setkey(struct crypto_skcipher *tfm, - const u8 *key, unsigned int keylen) -{ - return tfm->setkey(tfm, key, keylen); -} - -static inline bool crypto_skcipher_has_setkey(struct crypto_skcipher *tfm) -{ - return tfm->keysize; -} - -static inline unsigned int crypto_skcipher_default_keysize( - struct crypto_skcipher *tfm) -{ - return tfm->keysize; -} - -/** - * crypto_skcipher_reqtfm() - obtain cipher handle from request - * @req: skcipher_request out of which the cipher handle is to be obtained - * - * Return the crypto_skcipher handle when furnishing an skcipher_request - * data structure. - * - * Return: crypto_skcipher handle - */ -static inline struct crypto_skcipher *crypto_skcipher_reqtfm( - struct skcipher_request *req) -{ - return __crypto_skcipher_cast(req->base.tfm); -} - -/** - * crypto_skcipher_encrypt() - encrypt plaintext - * @req: reference to the skcipher_request handle that holds all information - * needed to perform the cipher operation - * - * Encrypt plaintext data using the skcipher_request handle. That data - * structure and how it is filled with data is discussed with the - * skcipher_request_* functions. - * - * Return: 0 if the cipher operation was successful; < 0 if an error occurred - */ -static inline int crypto_skcipher_encrypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - - return tfm->encrypt(req); -} - -/** - * crypto_skcipher_decrypt() - decrypt ciphertext - * @req: reference to the skcipher_request handle that holds all information - * needed to perform the cipher operation - * - * Decrypt ciphertext data using the skcipher_request handle. That data - * structure and how it is filled with data is discussed with the - * skcipher_request_* functions. - * - * Return: 0 if the cipher operation was successful; < 0 if an error occurred - */ -static inline int crypto_skcipher_decrypt(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - - return tfm->decrypt(req); -} - -/** - * DOC: Symmetric Key Cipher Request Handle - * - * The skcipher_request data structure contains all pointers to data - * required for the symmetric key cipher operation. This includes the cipher - * handle (which can be used by multiple skcipher_request instances), pointer - * to plaintext and ciphertext, asynchronous callback function, etc. It acts - * as a handle to the skcipher_request_* API calls in a similar way as - * skcipher handle to the crypto_skcipher_* API calls. - */ - -/** - * crypto_skcipher_reqsize() - obtain size of the request data structure - * @tfm: cipher handle - * - * Return: number of bytes - */ -static inline unsigned int crypto_skcipher_reqsize(struct crypto_skcipher *tfm) -{ - return tfm->reqsize; -} - -/** - * skcipher_request_set_tfm() - update cipher handle reference in request - * @req: request handle to be modified - * @tfm: cipher handle that shall be added to the request handle - * - * Allow the caller to replace the existing skcipher handle in the request - * data structure with a different one. - */ -static inline void skcipher_request_set_tfm(struct skcipher_request *req, - struct crypto_skcipher *tfm) -{ - req->base.tfm = crypto_skcipher_tfm(tfm); -} - -static inline struct skcipher_request *skcipher_request_cast( - struct crypto_async_request *req) -{ - return container_of(req, struct skcipher_request, base); -} - -/** - * skcipher_request_alloc() - allocate request data structure - * @tfm: cipher handle to be registered with the request - * @gfp: memory allocation flag that is handed to kmalloc by the API call. - * - * Allocate the request data structure that must be used with the skcipher - * encrypt and decrypt API calls. During the allocation, the provided skcipher - * handle is registered in the request data structure. - * - * Return: allocated request handle in case of success, or NULL if out of memory - */ -static inline struct skcipher_request *skcipher_request_alloc( - struct crypto_skcipher *tfm, gfp_t gfp) -{ - struct skcipher_request *req; - - req = kmalloc(sizeof(struct skcipher_request) + - crypto_skcipher_reqsize(tfm), gfp); - - if (likely(req)) - skcipher_request_set_tfm(req, tfm); - - return req; -} - -/** - * skcipher_request_free() - zeroize and free request data structure - * @req: request data structure cipher handle to be freed - */ -static inline void skcipher_request_free(struct skcipher_request *req) -{ - kzfree(req); -} - -static inline void skcipher_request_zero(struct skcipher_request *req) -{ - struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req); - - memzero_explicit(req, sizeof(*req) + crypto_skcipher_reqsize(tfm)); -} - -/** - * skcipher_request_set_callback() - set asynchronous callback function - * @req: request handle - * @flags: specify zero or an ORing of the flags - * CRYPTO_TFM_REQ_MAY_BACKLOG the request queue may back log and - * increase the wait queue beyond the initial maximum size; - * CRYPTO_TFM_REQ_MAY_SLEEP the request processing may sleep - * @compl: callback function pointer to be registered with the request handle - * @data: The data pointer refers to memory that is not used by the kernel - * crypto API, but provided to the callback function for it to use. Here, - * the caller can provide a reference to memory the callback function can - * operate on. As the callback function is invoked asynchronously to the - * related functionality, it may need to access data structures of the - * related functionality which can be referenced using this pointer. The - * callback function can access the memory via the "data" field in the - * crypto_async_request data structure provided to the callback function. - * - * This function allows setting the callback function that is triggered once the - * cipher operation completes. - * - * The callback function is registered with the skcipher_request handle and - * must comply with the following template - * - * void callback_function(struct crypto_async_request *req, int error) - */ -static inline void skcipher_request_set_callback(struct skcipher_request *req, - u32 flags, - crypto_completion_t compl, - void *data) -{ - req->base.complete = compl; - req->base.data = data; - req->base.flags = flags; -} - -/** - * skcipher_request_set_crypt() - set data buffers - * @req: request handle - * @src: source scatter / gather list - * @dst: destination scatter / gather list - * @cryptlen: number of bytes to process from @src - * @iv: IV for the cipher operation which must comply with the IV size defined - * by crypto_skcipher_ivsize - * - * This function allows setting of the source data and destination data - * scatter / gather lists. - * - * For encryption, the source is treated as the plaintext and the - * destination is the ciphertext. For a decryption operation, the use is - * reversed - the source is the ciphertext and the destination is the plaintext. - */ -static inline void skcipher_request_set_crypt( - struct skcipher_request *req, - struct scatterlist *src, struct scatterlist *dst, - unsigned int cryptlen, void *iv) -{ - req->src = src; - req->dst = dst; - req->cryptlen = cryptlen; - req->iv = iv; -} - -#endif /* _CRYPTO_SKCIPHER_H */ - diff --git a/src/linux/include/dt-bindings/input/linux-event-codes.h b/src/linux/include/dt-bindings/input/linux-event-codes.h deleted file mode 120000 index 693bbcd..0000000 --- a/src/linux/include/dt-bindings/input/linux-event-codes.h +++ /dev/null @@ -1 +0,0 @@ -../../uapi/linux/input-event-codes.h \ No newline at end of file diff --git a/src/linux/include/linux/acct.h b/src/linux/include/linux/acct.h deleted file mode 100644 index dccc2d4..0000000 --- a/src/linux/include/linux/acct.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * BSD Process Accounting for Linux - Definitions - * - * Author: Marco van Wieringen (mvw@planets.elm.net) - * - * This header file contains the definitions needed to implement - * BSD-style process accounting. The kernel accounting code and all - * user-level programs that try to do something useful with the - * process accounting log must include this file. - * - * Copyright (C) 1995 - 1997 Marco van Wieringen - ELM Consultancy B.V. - * - */ -#ifndef _LINUX_ACCT_H -#define _LINUX_ACCT_H - -#include - - - -#ifdef CONFIG_BSD_PROCESS_ACCT -struct vfsmount; -struct super_block; -struct pacct_struct; -struct pid_namespace; -extern int acct_parm[]; /* for sysctl */ -extern void acct_collect(long exitcode, int group_dead); -extern void acct_process(void); -extern void acct_exit_ns(struct pid_namespace *); -#else -#define acct_collect(x,y) do { } while (0) -#define acct_process() do { } while (0) -#define acct_exit_ns(ns) do { } while (0) -#endif - -/* - * ACCT_VERSION numbers as yet defined: - * 0: old format (until 2.6.7) with 16 bit uid/gid - * 1: extended variant (binary compatible on M68K) - * 2: extended variant (binary compatible on everything except M68K) - * 3: new binary incompatible format (64 bytes) - * 4: new binary incompatible format (128 bytes) - * 5: new binary incompatible format (128 bytes, second half) - * - */ - -#undef ACCT_VERSION -#undef AHZ - -#ifdef CONFIG_BSD_PROCESS_ACCT_V3 -#define ACCT_VERSION 3 -#define AHZ 100 -typedef struct acct_v3 acct_t; -#else -#ifdef CONFIG_M68K -#define ACCT_VERSION 1 -#else -#define ACCT_VERSION 2 -#endif -#define AHZ (USER_HZ) -typedef struct acct acct_t; -#endif - -#include -/* - * Yet another set of HZ to *HZ helper functions. - * See for the original. - */ - -static inline u32 jiffies_to_AHZ(unsigned long x) -{ -#if (TICK_NSEC % (NSEC_PER_SEC / AHZ)) == 0 -# if HZ < AHZ - return x * (AHZ / HZ); -# else - return x / (HZ / AHZ); -# endif -#else - u64 tmp = (u64)x * TICK_NSEC; - do_div(tmp, (NSEC_PER_SEC / AHZ)); - return (long)tmp; -#endif -} - -static inline u64 nsec_to_AHZ(u64 x) -{ -#if (NSEC_PER_SEC % AHZ) == 0 - do_div(x, (NSEC_PER_SEC / AHZ)); -#elif (AHZ % 512) == 0 - x *= AHZ/512; - do_div(x, (NSEC_PER_SEC / 512)); -#else - /* - * max relative error 5.7e-8 (1.8s per year) for AHZ <= 1024, - * overflow after 64.99 years. - * exact for AHZ=60, 72, 90, 120, 144, 180, 300, 600, 900, ... - */ - x *= 9; - do_div(x, (unsigned long)((9ull * NSEC_PER_SEC + (AHZ/2)) - / AHZ)); -#endif - return x; -} - -#endif /* _LINUX_ACCT_H */ diff --git a/src/linux/include/linux/acpi.h b/src/linux/include/linux/acpi.h deleted file mode 100644 index 61a3d90..0000000 --- a/src/linux/include/linux/acpi.h +++ /dev/null @@ -1,1126 +0,0 @@ -/* - * acpi.h - ACPI Interface - * - * Copyright (C) 2001 Paul Diefenbaugh - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#ifndef _LINUX_ACPI_H -#define _LINUX_ACPI_H - -#include -#include /* for struct resource */ -#include -#include -#include - -#ifndef _LINUX -#define _LINUX -#endif -#include - -#ifdef CONFIG_ACPI - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -static inline acpi_handle acpi_device_handle(struct acpi_device *adev) -{ - return adev ? adev->handle : NULL; -} - -#define ACPI_COMPANION(dev) to_acpi_device_node((dev)->fwnode) -#define ACPI_COMPANION_SET(dev, adev) set_primary_fwnode(dev, (adev) ? \ - acpi_fwnode_handle(adev) : NULL) -#define ACPI_HANDLE(dev) acpi_device_handle(ACPI_COMPANION(dev)) - -/** - * ACPI_DEVICE_CLASS - macro used to describe an ACPI device with - * the PCI-defined class-code information - * - * @_cls : the class, subclass, prog-if triple for this device - * @_msk : the class mask for this device - * - * This macro is used to create a struct acpi_device_id that matches a - * specific PCI class. The .id and .driver_data fields will be left - * initialized with the default value. - */ -#define ACPI_DEVICE_CLASS(_cls, _msk) .cls = (_cls), .cls_msk = (_msk), - -static inline bool has_acpi_companion(struct device *dev) -{ - return is_acpi_device_node(dev->fwnode); -} - -static inline void acpi_preset_companion(struct device *dev, - struct acpi_device *parent, u64 addr) -{ - ACPI_COMPANION_SET(dev, acpi_find_child_device(parent, addr, NULL)); -} - -static inline const char *acpi_dev_name(struct acpi_device *adev) -{ - return dev_name(&adev->dev); -} - -struct device *acpi_get_first_physical_node(struct acpi_device *adev); - -enum acpi_irq_model_id { - ACPI_IRQ_MODEL_PIC = 0, - ACPI_IRQ_MODEL_IOAPIC, - ACPI_IRQ_MODEL_IOSAPIC, - ACPI_IRQ_MODEL_PLATFORM, - ACPI_IRQ_MODEL_GIC, - ACPI_IRQ_MODEL_COUNT -}; - -extern enum acpi_irq_model_id acpi_irq_model; - -enum acpi_interrupt_id { - ACPI_INTERRUPT_PMI = 1, - ACPI_INTERRUPT_INIT, - ACPI_INTERRUPT_CPEI, - ACPI_INTERRUPT_COUNT -}; - -#define ACPI_SPACE_MEM 0 - -enum acpi_address_range_id { - ACPI_ADDRESS_RANGE_MEMORY = 1, - ACPI_ADDRESS_RANGE_RESERVED = 2, - ACPI_ADDRESS_RANGE_ACPI = 3, - ACPI_ADDRESS_RANGE_NVS = 4, - ACPI_ADDRESS_RANGE_COUNT -}; - - -/* Table Handlers */ - -typedef int (*acpi_tbl_table_handler)(struct acpi_table_header *table); - -typedef int (*acpi_tbl_entry_handler)(struct acpi_subtable_header *header, - const unsigned long end); - -/* Debugger support */ - -struct acpi_debugger_ops { - int (*create_thread)(acpi_osd_exec_callback function, void *context); - ssize_t (*write_log)(const char *msg); - ssize_t (*read_cmd)(char *buffer, size_t length); - int (*wait_command_ready)(bool single_step, char *buffer, size_t length); - int (*notify_command_complete)(void); -}; - -struct acpi_debugger { - const struct acpi_debugger_ops *ops; - struct module *owner; - struct mutex lock; -}; - -#ifdef CONFIG_ACPI_DEBUGGER -int __init acpi_debugger_init(void); -int acpi_register_debugger(struct module *owner, - const struct acpi_debugger_ops *ops); -void acpi_unregister_debugger(const struct acpi_debugger_ops *ops); -int acpi_debugger_create_thread(acpi_osd_exec_callback function, void *context); -ssize_t acpi_debugger_write_log(const char *msg); -ssize_t acpi_debugger_read_cmd(char *buffer, size_t buffer_length); -int acpi_debugger_wait_command_ready(void); -int acpi_debugger_notify_command_complete(void); -#else -static inline int acpi_debugger_init(void) -{ - return -ENODEV; -} - -static inline int acpi_register_debugger(struct module *owner, - const struct acpi_debugger_ops *ops) -{ - return -ENODEV; -} - -static inline void acpi_unregister_debugger(const struct acpi_debugger_ops *ops) -{ -} - -static inline int acpi_debugger_create_thread(acpi_osd_exec_callback function, - void *context) -{ - return -ENODEV; -} - -static inline int acpi_debugger_write_log(const char *msg) -{ - return -ENODEV; -} - -static inline int acpi_debugger_read_cmd(char *buffer, u32 buffer_length) -{ - return -ENODEV; -} - -static inline int acpi_debugger_wait_command_ready(void) -{ - return -ENODEV; -} - -static inline int acpi_debugger_notify_command_complete(void) -{ - return -ENODEV; -} -#endif - -#define BAD_MADT_ENTRY(entry, end) ( \ - (!entry) || (unsigned long)entry + sizeof(*entry) > end || \ - ((struct acpi_subtable_header *)entry)->length < sizeof(*entry)) - -struct acpi_subtable_proc { - int id; - acpi_tbl_entry_handler handler; - int count; -}; - -char * __acpi_map_table (unsigned long phys_addr, unsigned long size); -void __acpi_unmap_table(char *map, unsigned long size); -int early_acpi_boot_init(void); -int acpi_boot_init (void); -void acpi_boot_table_init (void); -int acpi_mps_check (void); -int acpi_numa_init (void); - -int acpi_table_init (void); -int acpi_table_parse(char *id, acpi_tbl_table_handler handler); -int __init acpi_parse_entries(char *id, unsigned long table_size, - acpi_tbl_entry_handler handler, - struct acpi_table_header *table_header, - int entry_id, unsigned int max_entries); -int __init acpi_table_parse_entries(char *id, unsigned long table_size, - int entry_id, - acpi_tbl_entry_handler handler, - unsigned int max_entries); -int __init acpi_table_parse_entries(char *id, unsigned long table_size, - int entry_id, - acpi_tbl_entry_handler handler, - unsigned int max_entries); -int __init acpi_table_parse_entries_array(char *id, unsigned long table_size, - struct acpi_subtable_proc *proc, int proc_num, - unsigned int max_entries); -int acpi_table_parse_madt(enum acpi_madt_type id, - acpi_tbl_entry_handler handler, - unsigned int max_entries); -int acpi_parse_mcfg (struct acpi_table_header *header); -void acpi_table_print_madt_entry (struct acpi_subtable_header *madt); - -/* the following numa functions are architecture-dependent */ -void acpi_numa_slit_init (struct acpi_table_slit *slit); - -#if defined(CONFIG_X86) || defined(CONFIG_IA64) -void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa); -#else -static inline void -acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa) { } -#endif - -void acpi_numa_x2apic_affinity_init(struct acpi_srat_x2apic_cpu_affinity *pa); - -#ifdef CONFIG_ARM64 -void acpi_numa_gicc_affinity_init(struct acpi_srat_gicc_affinity *pa); -#else -static inline void -acpi_numa_gicc_affinity_init(struct acpi_srat_gicc_affinity *pa) { } -#endif - -int acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma); - -#ifndef PHYS_CPUID_INVALID -typedef u32 phys_cpuid_t; -#define PHYS_CPUID_INVALID (phys_cpuid_t)(-1) -#endif - -static inline bool invalid_logical_cpuid(u32 cpuid) -{ - return (int)cpuid < 0; -} - -static inline bool invalid_phys_cpuid(phys_cpuid_t phys_id) -{ - return phys_id == PHYS_CPUID_INVALID; -} - -/* Validate the processor object's proc_id */ -bool acpi_processor_validate_proc_id(int proc_id); - -#ifdef CONFIG_ACPI_HOTPLUG_CPU -/* Arch dependent functions for cpu hotplug support */ -int acpi_map_cpu(acpi_handle handle, phys_cpuid_t physid, int *pcpu); -int acpi_unmap_cpu(int cpu); -int acpi_map_cpu2node(acpi_handle handle, int cpu, int physid); -#endif /* CONFIG_ACPI_HOTPLUG_CPU */ - -void acpi_set_processor_mapping(void); - -#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC -int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr); -#endif - -int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base); -int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base); -int acpi_ioapic_registered(acpi_handle handle, u32 gsi_base); -void acpi_irq_stats_init(void); -extern u32 acpi_irq_handled; -extern u32 acpi_irq_not_handled; -extern unsigned int acpi_sci_irq; -extern bool acpi_no_s5; -#define INVALID_ACPI_IRQ ((unsigned)-1) -static inline bool acpi_sci_irq_valid(void) -{ - return acpi_sci_irq != INVALID_ACPI_IRQ; -} - -extern int sbf_port; -extern unsigned long acpi_realmode_flags; - -int acpi_register_gsi (struct device *dev, u32 gsi, int triggering, int polarity); -int acpi_gsi_to_irq (u32 gsi, unsigned int *irq); -int acpi_isa_irq_to_gsi (unsigned isa_irq, u32 *gsi); - -void acpi_set_irq_model(enum acpi_irq_model_id model, - struct fwnode_handle *fwnode); - -#ifdef CONFIG_X86_IO_APIC -extern int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity); -#else -#define acpi_get_override_irq(gsi, trigger, polarity) (-1) -#endif -/* - * This function undoes the effect of one call to acpi_register_gsi(). - * If this matches the last registration, any IRQ resources for gsi - * are freed. - */ -void acpi_unregister_gsi (u32 gsi); - -struct pci_dev; - -int acpi_pci_irq_enable (struct pci_dev *dev); -void acpi_penalize_isa_irq(int irq, int active); -bool acpi_isa_irq_available(int irq); -void acpi_penalize_sci_irq(int irq, int trigger, int polarity); -void acpi_pci_irq_disable (struct pci_dev *dev); - -extern int ec_read(u8 addr, u8 *val); -extern int ec_write(u8 addr, u8 val); -extern int ec_transaction(u8 command, - const u8 *wdata, unsigned wdata_len, - u8 *rdata, unsigned rdata_len); -extern acpi_handle ec_get_handle(void); - -extern bool acpi_is_pnp_device(struct acpi_device *); - -#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE) - -typedef void (*wmi_notify_handler) (u32 value, void *context); - -extern acpi_status wmi_evaluate_method(const char *guid, u8 instance, - u32 method_id, - const struct acpi_buffer *in, - struct acpi_buffer *out); -extern acpi_status wmi_query_block(const char *guid, u8 instance, - struct acpi_buffer *out); -extern acpi_status wmi_set_block(const char *guid, u8 instance, - const struct acpi_buffer *in); -extern acpi_status wmi_install_notify_handler(const char *guid, - wmi_notify_handler handler, void *data); -extern acpi_status wmi_remove_notify_handler(const char *guid); -extern acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out); -extern bool wmi_has_guid(const char *guid); - -#endif /* CONFIG_ACPI_WMI */ - -#define ACPI_VIDEO_OUTPUT_SWITCHING 0x0001 -#define ACPI_VIDEO_DEVICE_POSTING 0x0002 -#define ACPI_VIDEO_ROM_AVAILABLE 0x0004 -#define ACPI_VIDEO_BACKLIGHT 0x0008 -#define ACPI_VIDEO_BACKLIGHT_FORCE_VENDOR 0x0010 -#define ACPI_VIDEO_BACKLIGHT_FORCE_VIDEO 0x0020 -#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VENDOR 0x0040 -#define ACPI_VIDEO_OUTPUT_SWITCHING_FORCE_VIDEO 0x0080 -#define ACPI_VIDEO_BACKLIGHT_DMI_VENDOR 0x0100 -#define ACPI_VIDEO_BACKLIGHT_DMI_VIDEO 0x0200 -#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VENDOR 0x0400 -#define ACPI_VIDEO_OUTPUT_SWITCHING_DMI_VIDEO 0x0800 - -extern char acpi_video_backlight_string[]; -extern long acpi_is_video_device(acpi_handle handle); -extern int acpi_blacklisted(void); -extern void acpi_osi_setup(char *str); -extern bool acpi_osi_is_win8(void); - -#ifdef CONFIG_ACPI_NUMA -int acpi_map_pxm_to_online_node(int pxm); -int acpi_get_node(acpi_handle handle); -#else -static inline int acpi_map_pxm_to_online_node(int pxm) -{ - return 0; -} -static inline int acpi_get_node(acpi_handle handle) -{ - return 0; -} -#endif -extern int acpi_paddr_to_node(u64 start_addr, u64 size); - -extern int pnpacpi_disabled; - -#define PXM_INVAL (-1) - -bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res); -bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res); -bool acpi_dev_resource_address_space(struct acpi_resource *ares, - struct resource_win *win); -bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares, - struct resource_win *win); -unsigned long acpi_dev_irq_flags(u8 triggering, u8 polarity, u8 shareable); -unsigned int acpi_dev_get_irq_type(int triggering, int polarity); -bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index, - struct resource *res); - -void acpi_dev_free_resource_list(struct list_head *list); -int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list, - int (*preproc)(struct acpi_resource *, void *), - void *preproc_data); -int acpi_dev_filter_resource_type(struct acpi_resource *ares, - unsigned long types); - -static inline int acpi_dev_filter_resource_type_cb(struct acpi_resource *ares, - void *arg) -{ - return acpi_dev_filter_resource_type(ares, (unsigned long)arg); -} - -int acpi_check_resource_conflict(const struct resource *res); - -int acpi_check_region(resource_size_t start, resource_size_t n, - const char *name); - -int acpi_resources_are_enforced(void); - -#ifdef CONFIG_HIBERNATION -void __init acpi_no_s4_hw_signature(void); -#endif - -#ifdef CONFIG_PM_SLEEP -void __init acpi_old_suspend_ordering(void); -void __init acpi_nvs_nosave(void); -void __init acpi_nvs_nosave_s3(void); -#endif /* CONFIG_PM_SLEEP */ - -struct acpi_osc_context { - char *uuid_str; /* UUID string */ - int rev; - struct acpi_buffer cap; /* list of DWORD capabilities */ - struct acpi_buffer ret; /* free by caller if success */ -}; - -acpi_status acpi_str_to_uuid(char *str, u8 *uuid); -acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context); - -/* Indexes into _OSC Capabilities Buffer (DWORDs 2 & 3 are device-specific) */ -#define OSC_QUERY_DWORD 0 /* DWORD 1 */ -#define OSC_SUPPORT_DWORD 1 /* DWORD 2 */ -#define OSC_CONTROL_DWORD 2 /* DWORD 3 */ - -/* _OSC Capabilities DWORD 1: Query/Control and Error Returns (generic) */ -#define OSC_QUERY_ENABLE 0x00000001 /* input */ -#define OSC_REQUEST_ERROR 0x00000002 /* return */ -#define OSC_INVALID_UUID_ERROR 0x00000004 /* return */ -#define OSC_INVALID_REVISION_ERROR 0x00000008 /* return */ -#define OSC_CAPABILITIES_MASK_ERROR 0x00000010 /* return */ - -/* Platform-Wide Capabilities _OSC: Capabilities DWORD 2: Support Field */ -#define OSC_SB_PAD_SUPPORT 0x00000001 -#define OSC_SB_PPC_OST_SUPPORT 0x00000002 -#define OSC_SB_PR3_SUPPORT 0x00000004 -#define OSC_SB_HOTPLUG_OST_SUPPORT 0x00000008 -#define OSC_SB_APEI_SUPPORT 0x00000010 -#define OSC_SB_CPC_SUPPORT 0x00000020 -#define OSC_SB_CPCV2_SUPPORT 0x00000040 -#define OSC_SB_PCLPI_SUPPORT 0x00000080 -#define OSC_SB_OSLPI_SUPPORT 0x00000100 - -extern bool osc_sb_apei_support_acked; -extern bool osc_pc_lpi_support_confirmed; - -/* PCI Host Bridge _OSC: Capabilities DWORD 2: Support Field */ -#define OSC_PCI_EXT_CONFIG_SUPPORT 0x00000001 -#define OSC_PCI_ASPM_SUPPORT 0x00000002 -#define OSC_PCI_CLOCK_PM_SUPPORT 0x00000004 -#define OSC_PCI_SEGMENT_GROUPS_SUPPORT 0x00000008 -#define OSC_PCI_MSI_SUPPORT 0x00000010 -#define OSC_PCI_SUPPORT_MASKS 0x0000001f - -/* PCI Host Bridge _OSC: Capabilities DWORD 3: Control Field */ -#define OSC_PCI_EXPRESS_NATIVE_HP_CONTROL 0x00000001 -#define OSC_PCI_SHPC_NATIVE_HP_CONTROL 0x00000002 -#define OSC_PCI_EXPRESS_PME_CONTROL 0x00000004 -#define OSC_PCI_EXPRESS_AER_CONTROL 0x00000008 -#define OSC_PCI_EXPRESS_CAPABILITY_CONTROL 0x00000010 -#define OSC_PCI_CONTROL_MASKS 0x0000001f - -#define ACPI_GSB_ACCESS_ATTRIB_QUICK 0x00000002 -#define ACPI_GSB_ACCESS_ATTRIB_SEND_RCV 0x00000004 -#define ACPI_GSB_ACCESS_ATTRIB_BYTE 0x00000006 -#define ACPI_GSB_ACCESS_ATTRIB_WORD 0x00000008 -#define ACPI_GSB_ACCESS_ATTRIB_BLOCK 0x0000000A -#define ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE 0x0000000B -#define ACPI_GSB_ACCESS_ATTRIB_WORD_CALL 0x0000000C -#define ACPI_GSB_ACCESS_ATTRIB_BLOCK_CALL 0x0000000D -#define ACPI_GSB_ACCESS_ATTRIB_RAW_BYTES 0x0000000E -#define ACPI_GSB_ACCESS_ATTRIB_RAW_PROCESS 0x0000000F - -extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, - u32 *mask, u32 req); - -/* Enable _OST when all relevant hotplug operations are enabled */ -#if defined(CONFIG_ACPI_HOTPLUG_CPU) && \ - defined(CONFIG_ACPI_HOTPLUG_MEMORY) && \ - defined(CONFIG_ACPI_CONTAINER) -#define ACPI_HOTPLUG_OST -#endif - -/* _OST Source Event Code (OSPM Action) */ -#define ACPI_OST_EC_OSPM_SHUTDOWN 0x100 -#define ACPI_OST_EC_OSPM_EJECT 0x103 -#define ACPI_OST_EC_OSPM_INSERTION 0x200 - -/* _OST General Processing Status Code */ -#define ACPI_OST_SC_SUCCESS 0x0 -#define ACPI_OST_SC_NON_SPECIFIC_FAILURE 0x1 -#define ACPI_OST_SC_UNRECOGNIZED_NOTIFY 0x2 - -/* _OST OS Shutdown Processing (0x100) Status Code */ -#define ACPI_OST_SC_OS_SHUTDOWN_DENIED 0x80 -#define ACPI_OST_SC_OS_SHUTDOWN_IN_PROGRESS 0x81 -#define ACPI_OST_SC_OS_SHUTDOWN_COMPLETED 0x82 -#define ACPI_OST_SC_OS_SHUTDOWN_NOT_SUPPORTED 0x83 - -/* _OST Ejection Request (0x3, 0x103) Status Code */ -#define ACPI_OST_SC_EJECT_NOT_SUPPORTED 0x80 -#define ACPI_OST_SC_DEVICE_IN_USE 0x81 -#define ACPI_OST_SC_DEVICE_BUSY 0x82 -#define ACPI_OST_SC_EJECT_DEPENDENCY_BUSY 0x83 -#define ACPI_OST_SC_EJECT_IN_PROGRESS 0x84 - -/* _OST Insertion Request (0x200) Status Code */ -#define ACPI_OST_SC_INSERT_IN_PROGRESS 0x80 -#define ACPI_OST_SC_DRIVER_LOAD_FAILURE 0x81 -#define ACPI_OST_SC_INSERT_NOT_SUPPORTED 0x82 - -extern void acpi_early_init(void); -extern void acpi_subsystem_init(void); - -extern int acpi_nvs_register(__u64 start, __u64 size); - -extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *), - void *data); - -const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, - const struct device *dev); - -extern bool acpi_driver_match_device(struct device *dev, - const struct device_driver *drv); -int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *); -int acpi_device_modalias(struct device *, char *, int); -void acpi_walk_dep_device_list(acpi_handle handle); - -struct platform_device *acpi_create_platform_device(struct acpi_device *, - struct property_entry *); -#define ACPI_PTR(_ptr) (_ptr) - -static inline void acpi_device_set_enumerated(struct acpi_device *adev) -{ - adev->flags.visited = true; -} - -static inline void acpi_device_clear_enumerated(struct acpi_device *adev) -{ - adev->flags.visited = false; -} - -enum acpi_reconfig_event { - ACPI_RECONFIG_DEVICE_ADD = 0, - ACPI_RECONFIG_DEVICE_REMOVE, -}; - -int acpi_reconfig_notifier_register(struct notifier_block *nb); -int acpi_reconfig_notifier_unregister(struct notifier_block *nb); - -#else /* !CONFIG_ACPI */ - -#define acpi_disabled 1 - -#define ACPI_COMPANION(dev) (NULL) -#define ACPI_COMPANION_SET(dev, adev) do { } while (0) -#define ACPI_HANDLE(dev) (NULL) -#define ACPI_DEVICE_CLASS(_cls, _msk) .cls = (0), .cls_msk = (0), - -struct fwnode_handle; - -static inline bool acpi_dev_found(const char *hid) -{ - return false; -} - -static inline bool is_acpi_node(struct fwnode_handle *fwnode) -{ - return false; -} - -static inline bool is_acpi_device_node(struct fwnode_handle *fwnode) -{ - return false; -} - -static inline struct acpi_device *to_acpi_device_node(struct fwnode_handle *fwnode) -{ - return NULL; -} - -static inline bool is_acpi_data_node(struct fwnode_handle *fwnode) -{ - return false; -} - -static inline struct acpi_data_node *to_acpi_data_node(struct fwnode_handle *fwnode) -{ - return NULL; -} - -static inline bool acpi_data_node_match(struct fwnode_handle *fwnode, - const char *name) -{ - return false; -} - -static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev) -{ - return NULL; -} - -static inline bool has_acpi_companion(struct device *dev) -{ - return false; -} - -static inline void acpi_preset_companion(struct device *dev, - struct acpi_device *parent, u64 addr) -{ -} - -static inline const char *acpi_dev_name(struct acpi_device *adev) -{ - return NULL; -} - -static inline struct device *acpi_get_first_physical_node(struct acpi_device *adev) -{ - return NULL; -} - -static inline void acpi_early_init(void) { } -static inline void acpi_subsystem_init(void) { } - -static inline int early_acpi_boot_init(void) -{ - return 0; -} -static inline int acpi_boot_init(void) -{ - return 0; -} - -static inline void acpi_boot_table_init(void) -{ - return; -} - -static inline int acpi_mps_check(void) -{ - return 0; -} - -static inline int acpi_check_resource_conflict(struct resource *res) -{ - return 0; -} - -static inline int acpi_check_region(resource_size_t start, resource_size_t n, - const char *name) -{ - return 0; -} - -struct acpi_table_header; -static inline int acpi_table_parse(char *id, - int (*handler)(struct acpi_table_header *)) -{ - return -ENODEV; -} - -static inline int acpi_nvs_register(__u64 start, __u64 size) -{ - return 0; -} - -static inline int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *), - void *data) -{ - return 0; -} - -struct acpi_device_id; - -static inline const struct acpi_device_id *acpi_match_device( - const struct acpi_device_id *ids, const struct device *dev) -{ - return NULL; -} - -static inline bool acpi_driver_match_device(struct device *dev, - const struct device_driver *drv) -{ - return false; -} - -static inline union acpi_object *acpi_evaluate_dsm(acpi_handle handle, - const u8 *uuid, - int rev, int func, - union acpi_object *argv4) -{ - return NULL; -} - -static inline int acpi_device_uevent_modalias(struct device *dev, - struct kobj_uevent_env *env) -{ - return -ENODEV; -} - -static inline int acpi_device_modalias(struct device *dev, - char *buf, int size) -{ - return -ENODEV; -} - -static inline bool acpi_dma_supported(struct acpi_device *adev) -{ - return false; -} - -static inline enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev) -{ - return DEV_DMA_NOT_SUPPORTED; -} - -#define ACPI_PTR(_ptr) (NULL) - -static inline void acpi_device_set_enumerated(struct acpi_device *adev) -{ -} - -static inline void acpi_device_clear_enumerated(struct acpi_device *adev) -{ -} - -static inline int acpi_reconfig_notifier_register(struct notifier_block *nb) -{ - return -EINVAL; -} - -static inline int acpi_reconfig_notifier_unregister(struct notifier_block *nb) -{ - return -EINVAL; -} - -#endif /* !CONFIG_ACPI */ - -#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC -int acpi_ioapic_add(acpi_handle root); -#else -static inline int acpi_ioapic_add(acpi_handle root) { return 0; } -#endif - -#ifdef CONFIG_ACPI -void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state, - u32 pm1a_ctrl, u32 pm1b_ctrl)); - -acpi_status acpi_os_prepare_sleep(u8 sleep_state, - u32 pm1a_control, u32 pm1b_control); - -void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state, - u32 val_a, u32 val_b)); - -acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, - u32 val_a, u32 val_b); - -#ifdef CONFIG_X86 -void arch_reserve_mem_area(acpi_physical_address addr, size_t size); -#else -static inline void arch_reserve_mem_area(acpi_physical_address addr, - size_t size) -{ -} -#endif /* CONFIG_X86 */ -#else -#define acpi_os_set_prepare_sleep(func, pm1a_ctrl, pm1b_ctrl) do { } while (0) -#endif - -#if defined(CONFIG_ACPI) && defined(CONFIG_PM) -int acpi_dev_runtime_suspend(struct device *dev); -int acpi_dev_runtime_resume(struct device *dev); -int acpi_subsys_runtime_suspend(struct device *dev); -int acpi_subsys_runtime_resume(struct device *dev); -struct acpi_device *acpi_dev_pm_get_node(struct device *dev); -int acpi_dev_pm_attach(struct device *dev, bool power_on); -#else -static inline int acpi_dev_runtime_suspend(struct device *dev) { return 0; } -static inline int acpi_dev_runtime_resume(struct device *dev) { return 0; } -static inline int acpi_subsys_runtime_suspend(struct device *dev) { return 0; } -static inline int acpi_subsys_runtime_resume(struct device *dev) { return 0; } -static inline struct acpi_device *acpi_dev_pm_get_node(struct device *dev) -{ - return NULL; -} -static inline int acpi_dev_pm_attach(struct device *dev, bool power_on) -{ - return -ENODEV; -} -#endif - -#if defined(CONFIG_ACPI) && defined(CONFIG_PM_SLEEP) -int acpi_dev_suspend_late(struct device *dev); -int acpi_dev_resume_early(struct device *dev); -int acpi_subsys_prepare(struct device *dev); -void acpi_subsys_complete(struct device *dev); -int acpi_subsys_suspend_late(struct device *dev); -int acpi_subsys_resume_early(struct device *dev); -int acpi_subsys_suspend(struct device *dev); -int acpi_subsys_freeze(struct device *dev); -#else -static inline int acpi_dev_suspend_late(struct device *dev) { return 0; } -static inline int acpi_dev_resume_early(struct device *dev) { return 0; } -static inline int acpi_subsys_prepare(struct device *dev) { return 0; } -static inline void acpi_subsys_complete(struct device *dev) {} -static inline int acpi_subsys_suspend_late(struct device *dev) { return 0; } -static inline int acpi_subsys_resume_early(struct device *dev) { return 0; } -static inline int acpi_subsys_suspend(struct device *dev) { return 0; } -static inline int acpi_subsys_freeze(struct device *dev) { return 0; } -#endif - -#ifdef CONFIG_ACPI -__printf(3, 4) -void acpi_handle_printk(const char *level, acpi_handle handle, - const char *fmt, ...); -#else /* !CONFIG_ACPI */ -static inline __printf(3, 4) void -acpi_handle_printk(const char *level, void *handle, const char *fmt, ...) {} -#endif /* !CONFIG_ACPI */ - -#if defined(CONFIG_ACPI) && defined(CONFIG_DYNAMIC_DEBUG) -__printf(3, 4) -void __acpi_handle_debug(struct _ddebug *descriptor, acpi_handle handle, const char *fmt, ...); -#else -#define __acpi_handle_debug(descriptor, handle, fmt, ...) \ - acpi_handle_printk(KERN_DEBUG, handle, fmt, ##__VA_ARGS__); -#endif - -/* - * acpi_handle_: Print message with ACPI prefix and object path - * - * These interfaces acquire the global namespace mutex to obtain an object - * path. In interrupt context, it shows the object path as . - */ -#define acpi_handle_emerg(handle, fmt, ...) \ - acpi_handle_printk(KERN_EMERG, handle, fmt, ##__VA_ARGS__) -#define acpi_handle_alert(handle, fmt, ...) \ - acpi_handle_printk(KERN_ALERT, handle, fmt, ##__VA_ARGS__) -#define acpi_handle_crit(handle, fmt, ...) \ - acpi_handle_printk(KERN_CRIT, handle, fmt, ##__VA_ARGS__) -#define acpi_handle_err(handle, fmt, ...) \ - acpi_handle_printk(KERN_ERR, handle, fmt, ##__VA_ARGS__) -#define acpi_handle_warn(handle, fmt, ...) \ - acpi_handle_printk(KERN_WARNING, handle, fmt, ##__VA_ARGS__) -#define acpi_handle_notice(handle, fmt, ...) \ - acpi_handle_printk(KERN_NOTICE, handle, fmt, ##__VA_ARGS__) -#define acpi_handle_info(handle, fmt, ...) \ - acpi_handle_printk(KERN_INFO, handle, fmt, ##__VA_ARGS__) - -#if defined(DEBUG) -#define acpi_handle_debug(handle, fmt, ...) \ - acpi_handle_printk(KERN_DEBUG, handle, fmt, ##__VA_ARGS__) -#else -#if defined(CONFIG_DYNAMIC_DEBUG) -#define acpi_handle_debug(handle, fmt, ...) \ -do { \ - DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ - if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT)) \ - __acpi_handle_debug(&descriptor, handle, pr_fmt(fmt), \ - ##__VA_ARGS__); \ -} while (0) -#else -#define acpi_handle_debug(handle, fmt, ...) \ -({ \ - if (0) \ - acpi_handle_printk(KERN_DEBUG, handle, fmt, ##__VA_ARGS__); \ - 0; \ -}) -#endif -#endif - -struct acpi_gpio_params { - unsigned int crs_entry_index; - unsigned int line_index; - bool active_low; -}; - -struct acpi_gpio_mapping { - const char *name; - const struct acpi_gpio_params *data; - unsigned int size; -}; - -#if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB) -int acpi_dev_add_driver_gpios(struct acpi_device *adev, - const struct acpi_gpio_mapping *gpios); - -static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) -{ - if (adev) - adev->driver_gpios = NULL; -} - -int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index); -#else -static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev, - const struct acpi_gpio_mapping *gpios) -{ - return -ENXIO; -} -static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) {} - -static inline int acpi_dev_gpio_irq_get(struct acpi_device *adev, int index) -{ - return -ENXIO; -} -#endif - -/* Device properties */ - -#define MAX_ACPI_REFERENCE_ARGS 8 -struct acpi_reference_args { - struct acpi_device *adev; - size_t nargs; - u64 args[MAX_ACPI_REFERENCE_ARGS]; -}; - -#ifdef CONFIG_ACPI -int acpi_dev_get_property(struct acpi_device *adev, const char *name, - acpi_object_type type, const union acpi_object **obj); -int __acpi_node_get_property_reference(struct fwnode_handle *fwnode, - const char *name, size_t index, size_t num_args, - struct acpi_reference_args *args); - -static inline int acpi_node_get_property_reference(struct fwnode_handle *fwnode, - const char *name, size_t index, - struct acpi_reference_args *args) -{ - return __acpi_node_get_property_reference(fwnode, name, index, - MAX_ACPI_REFERENCE_ARGS, args); -} - -int acpi_node_prop_get(struct fwnode_handle *fwnode, const char *propname, - void **valptr); -int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname, - enum dev_prop_type proptype, void *val); -int acpi_node_prop_read(struct fwnode_handle *fwnode, const char *propname, - enum dev_prop_type proptype, void *val, size_t nval); -int acpi_dev_prop_read(struct acpi_device *adev, const char *propname, - enum dev_prop_type proptype, void *val, size_t nval); - -struct fwnode_handle *acpi_get_next_subnode(struct device *dev, - struct fwnode_handle *subnode); - -struct acpi_probe_entry; -typedef bool (*acpi_probe_entry_validate_subtbl)(struct acpi_subtable_header *, - struct acpi_probe_entry *); - -#define ACPI_TABLE_ID_LEN 5 - -/** - * struct acpi_probe_entry - boot-time probing entry - * @id: ACPI table name - * @type: Optional subtable type to match - * (if @id contains subtables) - * @subtable_valid: Optional callback to check the validity of - * the subtable - * @probe_table: Callback to the driver being probed when table - * match is successful - * @probe_subtbl: Callback to the driver being probed when table and - * subtable match (and optional callback is successful) - * @driver_data: Sideband data provided back to the driver - */ -struct acpi_probe_entry { - __u8 id[ACPI_TABLE_ID_LEN]; - __u8 type; - acpi_probe_entry_validate_subtbl subtable_valid; - union { - acpi_tbl_table_handler probe_table; - acpi_tbl_entry_handler probe_subtbl; - }; - kernel_ulong_t driver_data; -}; - -#define ACPI_DECLARE_PROBE_ENTRY(table, name, table_id, subtable, valid, data, fn) \ - static const struct acpi_probe_entry __acpi_probe_##name \ - __used __section(__##table##_acpi_probe_table) \ - = { \ - .id = table_id, \ - .type = subtable, \ - .subtable_valid = valid, \ - .probe_table = (acpi_tbl_table_handler)fn, \ - .driver_data = data, \ - } - -#define ACPI_PROBE_TABLE(name) __##name##_acpi_probe_table -#define ACPI_PROBE_TABLE_END(name) __##name##_acpi_probe_table_end - -int __acpi_probe_device_table(struct acpi_probe_entry *start, int nr); - -#define acpi_probe_device_table(t) \ - ({ \ - extern struct acpi_probe_entry ACPI_PROBE_TABLE(t), \ - ACPI_PROBE_TABLE_END(t); \ - __acpi_probe_device_table(&ACPI_PROBE_TABLE(t), \ - (&ACPI_PROBE_TABLE_END(t) - \ - &ACPI_PROBE_TABLE(t))); \ - }) -#else -static inline int acpi_dev_get_property(struct acpi_device *adev, - const char *name, acpi_object_type type, - const union acpi_object **obj) -{ - return -ENXIO; -} - -static inline int -__acpi_node_get_property_reference(struct fwnode_handle *fwnode, - const char *name, size_t index, size_t num_args, - struct acpi_reference_args *args) -{ - return -ENXIO; -} - -static inline int acpi_node_get_property_reference(struct fwnode_handle *fwnode, - const char *name, size_t index, - struct acpi_reference_args *args) -{ - return -ENXIO; -} - -static inline int acpi_node_prop_get(struct fwnode_handle *fwnode, - const char *propname, - void **valptr) -{ - return -ENXIO; -} - -static inline int acpi_dev_prop_get(struct acpi_device *adev, - const char *propname, - void **valptr) -{ - return -ENXIO; -} - -static inline int acpi_dev_prop_read_single(struct acpi_device *adev, - const char *propname, - enum dev_prop_type proptype, - void *val) -{ - return -ENXIO; -} - -static inline int acpi_node_prop_read(struct fwnode_handle *fwnode, - const char *propname, - enum dev_prop_type proptype, - void *val, size_t nval) -{ - return -ENXIO; -} - -static inline int acpi_dev_prop_read(struct acpi_device *adev, - const char *propname, - enum dev_prop_type proptype, - void *val, size_t nval) -{ - return -ENXIO; -} - -static inline struct fwnode_handle *acpi_get_next_subnode(struct device *dev, - struct fwnode_handle *subnode) -{ - return NULL; -} - -#define ACPI_DECLARE_PROBE_ENTRY(table, name, table_id, subtable, valid, data, fn) \ - static const void * __acpi_table_##name[] \ - __attribute__((unused)) \ - = { (void *) table_id, \ - (void *) subtable, \ - (void *) valid, \ - (void *) fn, \ - (void *) data } - -#define acpi_probe_device_table(t) ({ int __r = 0; __r;}) -#endif - -#ifdef CONFIG_ACPI_TABLE_UPGRADE -void acpi_table_upgrade(void); -#else -static inline void acpi_table_upgrade(void) { } -#endif - -#if defined(CONFIG_ACPI) && defined(CONFIG_ACPI_WATCHDOG) -extern bool acpi_has_watchdog(void); -#else -static inline bool acpi_has_watchdog(void) { return false; } -#endif - -#ifdef CONFIG_ACPI_SPCR_TABLE -int parse_spcr(bool earlycon); -#else -static inline int parse_spcr(bool earlycon) { return 0; } -#endif - -#endif /*_LINUX_ACPI_H*/ diff --git a/src/linux/include/linux/aio.h b/src/linux/include/linux/aio.h deleted file mode 100644 index 9eb42db..0000000 --- a/src/linux/include/linux/aio.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef __LINUX__AIO_H -#define __LINUX__AIO_H - -#include - -struct kioctx; -struct kiocb; -struct mm_struct; - -#define KIOCB_KEY 0 - -typedef int (kiocb_cancel_fn)(struct kiocb *); - -/* prototypes */ -#ifdef CONFIG_AIO -extern void exit_aio(struct mm_struct *mm); -extern long do_io_submit(aio_context_t ctx_id, long nr, - struct iocb __user *__user *iocbpp, bool compat); -void kiocb_set_cancel_fn(struct kiocb *req, kiocb_cancel_fn *cancel); -#else -static inline void exit_aio(struct mm_struct *mm) { } -static inline long do_io_submit(aio_context_t ctx_id, long nr, - struct iocb __user * __user *iocbpp, - bool compat) { return 0; } -static inline void kiocb_set_cancel_fn(struct kiocb *req, - kiocb_cancel_fn *cancel) { } -#endif /* CONFIG_AIO */ - -/* for sysctl: */ -extern unsigned long aio_nr; -extern unsigned long aio_max_nr; - -#endif /* __LINUX__AIO_H */ diff --git a/src/linux/include/linux/alarmtimer.h b/src/linux/include/linux/alarmtimer.h deleted file mode 100644 index 9d80312..0000000 --- a/src/linux/include/linux/alarmtimer.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef _LINUX_ALARMTIMER_H -#define _LINUX_ALARMTIMER_H - -#include -#include -#include -#include - -enum alarmtimer_type { - ALARM_REALTIME, - ALARM_BOOTTIME, - - ALARM_NUMTYPE, -}; - -enum alarmtimer_restart { - ALARMTIMER_NORESTART, - ALARMTIMER_RESTART, -}; - - -#define ALARMTIMER_STATE_INACTIVE 0x00 -#define ALARMTIMER_STATE_ENQUEUED 0x01 - -/** - * struct alarm - Alarm timer structure - * @node: timerqueue node for adding to the event list this value - * also includes the expiration time. - * @timer: hrtimer used to schedule events while running - * @function: Function pointer to be executed when the timer fires. - * @type: Alarm type (BOOTTIME/REALTIME). - * @state: Flag that represents if the alarm is set to fire or not. - * @data: Internal data value. - */ -struct alarm { - struct timerqueue_node node; - struct hrtimer timer; - enum alarmtimer_restart (*function)(struct alarm *, ktime_t now); - enum alarmtimer_type type; - int state; - void *data; -}; - -void alarm_init(struct alarm *alarm, enum alarmtimer_type type, - enum alarmtimer_restart (*function)(struct alarm *, ktime_t)); -void alarm_start(struct alarm *alarm, ktime_t start); -void alarm_start_relative(struct alarm *alarm, ktime_t start); -void alarm_restart(struct alarm *alarm); -int alarm_try_to_cancel(struct alarm *alarm); -int alarm_cancel(struct alarm *alarm); - -u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval); -u64 alarm_forward_now(struct alarm *alarm, ktime_t interval); -ktime_t alarm_expires_remaining(const struct alarm *alarm); - -/* Provide way to access the rtc device being used by alarmtimers */ -struct rtc_device *alarmtimer_get_rtcdev(void); - -#endif diff --git a/src/linux/include/linux/anon_inodes.h b/src/linux/include/linux/anon_inodes.h deleted file mode 100644 index 8013a45..0000000 --- a/src/linux/include/linux/anon_inodes.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * include/linux/anon_inodes.h - * - * Copyright (C) 2007 Davide Libenzi - * - */ - -#ifndef _LINUX_ANON_INODES_H -#define _LINUX_ANON_INODES_H - -struct file_operations; - -struct file *anon_inode_getfile(const char *name, - const struct file_operations *fops, - void *priv, int flags); -int anon_inode_getfd(const char *name, const struct file_operations *fops, - void *priv, int flags); - -#endif /* _LINUX_ANON_INODES_H */ - diff --git a/src/linux/include/linux/assoc_array.h b/src/linux/include/linux/assoc_array.h deleted file mode 100644 index a89df3b..0000000 --- a/src/linux/include/linux/assoc_array.h +++ /dev/null @@ -1,92 +0,0 @@ -/* Generic associative array implementation. - * - * See Documentation/assoc_array.txt for information. - * - * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ - -#ifndef _LINUX_ASSOC_ARRAY_H -#define _LINUX_ASSOC_ARRAY_H - -#ifdef CONFIG_ASSOCIATIVE_ARRAY - -#include - -#define ASSOC_ARRAY_KEY_CHUNK_SIZE BITS_PER_LONG /* Key data retrieved in chunks of this size */ - -/* - * Generic associative array. - */ -struct assoc_array { - struct assoc_array_ptr *root; /* The node at the root of the tree */ - unsigned long nr_leaves_on_tree; -}; - -/* - * Operations on objects and index keys for use by array manipulation routines. - */ -struct assoc_array_ops { - /* Method to get a chunk of an index key from caller-supplied data */ - unsigned long (*get_key_chunk)(const void *index_key, int level); - - /* Method to get a piece of an object's index key */ - unsigned long (*get_object_key_chunk)(const void *object, int level); - - /* Is this the object we're looking for? */ - bool (*compare_object)(const void *object, const void *index_key); - - /* How different is an object from an index key, to a bit position in - * their keys? (or -1 if they're the same) - */ - int (*diff_objects)(const void *object, const void *index_key); - - /* Method to free an object. */ - void (*free_object)(void *object); -}; - -/* - * Access and manipulation functions. - */ -struct assoc_array_edit; - -static inline void assoc_array_init(struct assoc_array *array) -{ - array->root = NULL; - array->nr_leaves_on_tree = 0; -} - -extern int assoc_array_iterate(const struct assoc_array *array, - int (*iterator)(const void *object, - void *iterator_data), - void *iterator_data); -extern void *assoc_array_find(const struct assoc_array *array, - const struct assoc_array_ops *ops, - const void *index_key); -extern void assoc_array_destroy(struct assoc_array *array, - const struct assoc_array_ops *ops); -extern struct assoc_array_edit *assoc_array_insert(struct assoc_array *array, - const struct assoc_array_ops *ops, - const void *index_key, - void *object); -extern void assoc_array_insert_set_object(struct assoc_array_edit *edit, - void *object); -extern struct assoc_array_edit *assoc_array_delete(struct assoc_array *array, - const struct assoc_array_ops *ops, - const void *index_key); -extern struct assoc_array_edit *assoc_array_clear(struct assoc_array *array, - const struct assoc_array_ops *ops); -extern void assoc_array_apply_edit(struct assoc_array_edit *edit); -extern void assoc_array_cancel_edit(struct assoc_array_edit *edit); -extern int assoc_array_gc(struct assoc_array *array, - const struct assoc_array_ops *ops, - bool (*iterator)(void *object, void *iterator_data), - void *iterator_data); - -#endif /* CONFIG_ASSOCIATIVE_ARRAY */ -#endif /* _LINUX_ASSOC_ARRAY_H */ diff --git a/src/linux/include/linux/async.h b/src/linux/include/linux/async.h deleted file mode 100644 index 6b0226b..0000000 --- a/src/linux/include/linux/async.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * async.h: Asynchronous function calls for boot performance - * - * (C) Copyright 2009 Intel Corporation - * Author: Arjan van de Ven - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; version 2 - * of the License. - */ -#ifndef __ASYNC_H__ -#define __ASYNC_H__ - -#include -#include - -typedef u64 async_cookie_t; -typedef void (*async_func_t) (void *data, async_cookie_t cookie); -struct async_domain { - struct list_head pending; - unsigned registered:1; -}; - -/* - * domain participates in global async_synchronize_full - */ -#define ASYNC_DOMAIN(_name) \ - struct async_domain _name = { .pending = LIST_HEAD_INIT(_name.pending), \ - .registered = 1 } - -/* - * domain is free to go out of scope as soon as all pending work is - * complete, this domain does not participate in async_synchronize_full - */ -#define ASYNC_DOMAIN_EXCLUSIVE(_name) \ - struct async_domain _name = { .pending = LIST_HEAD_INIT(_name.pending), \ - .registered = 0 } - -extern async_cookie_t async_schedule(async_func_t func, void *data); -extern async_cookie_t async_schedule_domain(async_func_t func, void *data, - struct async_domain *domain); -void async_unregister_domain(struct async_domain *domain); -extern void async_synchronize_full(void); -extern void async_synchronize_full_domain(struct async_domain *domain); -extern void async_synchronize_cookie(async_cookie_t cookie); -extern void async_synchronize_cookie_domain(async_cookie_t cookie, - struct async_domain *domain); -extern bool current_is_async(void); -#endif diff --git a/src/linux/include/linux/atalk.h b/src/linux/include/linux/atalk.h deleted file mode 100644 index 73fd8b7..0000000 --- a/src/linux/include/linux/atalk.h +++ /dev/null @@ -1,168 +0,0 @@ -#ifndef __LINUX_ATALK_H__ -#define __LINUX_ATALK_H__ - - -#include -#include - -struct atalk_route { - struct net_device *dev; - struct atalk_addr target; - struct atalk_addr gateway; - int flags; - struct atalk_route *next; -}; - -/** - * struct atalk_iface - AppleTalk Interface - * @dev - Network device associated with this interface - * @address - Our address - * @status - What are we doing? - * @nets - Associated direct netrange - * @next - next element in the list of interfaces - */ -struct atalk_iface { - struct net_device *dev; - struct atalk_addr address; - int status; -#define ATIF_PROBE 1 /* Probing for an address */ -#define ATIF_PROBE_FAIL 2 /* Probe collided */ - struct atalk_netrange nets; - struct atalk_iface *next; -}; - -struct atalk_sock { - /* struct sock has to be the first member of atalk_sock */ - struct sock sk; - __be16 dest_net; - __be16 src_net; - unsigned char dest_node; - unsigned char src_node; - unsigned char dest_port; - unsigned char src_port; -}; - -static inline struct atalk_sock *at_sk(struct sock *sk) -{ - return (struct atalk_sock *)sk; -} - -struct ddpehdr { - __be16 deh_len_hops; /* lower 10 bits are length, next 4 - hops */ - __be16 deh_sum; - __be16 deh_dnet; - __be16 deh_snet; - __u8 deh_dnode; - __u8 deh_snode; - __u8 deh_dport; - __u8 deh_sport; - /* And netatalk apps expect to stick the type in themselves */ -}; - -static __inline__ struct ddpehdr *ddp_hdr(struct sk_buff *skb) -{ - return (struct ddpehdr *)skb_transport_header(skb); -} - -/* AppleTalk AARP headers */ -struct elapaarp { - __be16 hw_type; -#define AARP_HW_TYPE_ETHERNET 1 -#define AARP_HW_TYPE_TOKENRING 2 - __be16 pa_type; - __u8 hw_len; - __u8 pa_len; -#define AARP_PA_ALEN 4 - __be16 function; -#define AARP_REQUEST 1 -#define AARP_REPLY 2 -#define AARP_PROBE 3 - __u8 hw_src[ETH_ALEN]; - __u8 pa_src_zero; - __be16 pa_src_net; - __u8 pa_src_node; - __u8 hw_dst[ETH_ALEN]; - __u8 pa_dst_zero; - __be16 pa_dst_net; - __u8 pa_dst_node; -} __attribute__ ((packed)); - -static __inline__ struct elapaarp *aarp_hdr(struct sk_buff *skb) -{ - return (struct elapaarp *)skb_transport_header(skb); -} - -/* Not specified - how long till we drop a resolved entry */ -#define AARP_EXPIRY_TIME (5 * 60 * HZ) -/* Size of hash table */ -#define AARP_HASH_SIZE 16 -/* Fast retransmission timer when resolving */ -#define AARP_TICK_TIME (HZ / 5) -/* Send 10 requests then give up (2 seconds) */ -#define AARP_RETRANSMIT_LIMIT 10 -/* - * Some value bigger than total retransmit time + a bit for last reply to - * appear and to stop continual requests - */ -#define AARP_RESOLVE_TIME (10 * HZ) - -extern struct datalink_proto *ddp_dl, *aarp_dl; -extern void aarp_proto_init(void); - -/* Inter module exports */ - -/* Give a device find its atif control structure */ -static inline struct atalk_iface *atalk_find_dev(struct net_device *dev) -{ - return dev->atalk_ptr; -} - -extern struct atalk_addr *atalk_find_dev_addr(struct net_device *dev); -extern struct net_device *atrtr_get_dev(struct atalk_addr *sa); -extern int aarp_send_ddp(struct net_device *dev, - struct sk_buff *skb, - struct atalk_addr *sa, void *hwaddr); -extern void aarp_device_down(struct net_device *dev); -extern void aarp_probe_network(struct atalk_iface *atif); -extern int aarp_proxy_probe_network(struct atalk_iface *atif, - struct atalk_addr *sa); -extern void aarp_proxy_remove(struct net_device *dev, - struct atalk_addr *sa); - -extern void aarp_cleanup_module(void); - -extern struct hlist_head atalk_sockets; -extern rwlock_t atalk_sockets_lock; - -extern struct atalk_route *atalk_routes; -extern rwlock_t atalk_routes_lock; - -extern struct atalk_iface *atalk_interfaces; -extern rwlock_t atalk_interfaces_lock; - -extern struct atalk_route atrtr_default; - -extern const struct file_operations atalk_seq_arp_fops; - -extern int sysctl_aarp_expiry_time; -extern int sysctl_aarp_tick_time; -extern int sysctl_aarp_retransmit_limit; -extern int sysctl_aarp_resolve_time; - -#ifdef CONFIG_SYSCTL -extern void atalk_register_sysctl(void); -extern void atalk_unregister_sysctl(void); -#else -#define atalk_register_sysctl() do { } while(0) -#define atalk_unregister_sysctl() do { } while(0) -#endif - -#ifdef CONFIG_PROC_FS -extern int atalk_proc_init(void); -extern void atalk_proc_exit(void); -#else -#define atalk_proc_init() ({ 0; }) -#define atalk_proc_exit() do { } while(0) -#endif /* CONFIG_PROC_FS */ - -#endif /* __LINUX_ATALK_H__ */ diff --git a/src/linux/include/linux/atomic.h b/src/linux/include/linux/atomic.h deleted file mode 100644 index e71835b..0000000 --- a/src/linux/include/linux/atomic.h +++ /dev/null @@ -1,1028 +0,0 @@ -/* Atomic operations usable in machine independent code */ -#ifndef _LINUX_ATOMIC_H -#define _LINUX_ATOMIC_H -#include -#include - -/* - * Relaxed variants of xchg, cmpxchg and some atomic operations. - * - * We support four variants: - * - * - Fully ordered: The default implementation, no suffix required. - * - Acquire: Provides ACQUIRE semantics, _acquire suffix. - * - Release: Provides RELEASE semantics, _release suffix. - * - Relaxed: No ordering guarantees, _relaxed suffix. - * - * For compound atomics performing both a load and a store, ACQUIRE - * semantics apply only to the load and RELEASE semantics only to the - * store portion of the operation. Note that a failed cmpxchg_acquire - * does -not- imply any memory ordering constraints. - * - * See Documentation/memory-barriers.txt for ACQUIRE/RELEASE definitions. - */ - -#ifndef atomic_read_acquire -#define atomic_read_acquire(v) smp_load_acquire(&(v)->counter) -#endif - -#ifndef atomic_set_release -#define atomic_set_release(v, i) smp_store_release(&(v)->counter, (i)) -#endif - -/* - * The idea here is to build acquire/release variants by adding explicit - * barriers on top of the relaxed variant. In the case where the relaxed - * variant is already fully ordered, no additional barriers are needed. - * - * Besides, if an arch has a special barrier for acquire/release, it could - * implement its own __atomic_op_* and use the same framework for building - * variants - */ -#ifndef __atomic_op_acquire -#define __atomic_op_acquire(op, args...) \ -({ \ - typeof(op##_relaxed(args)) __ret = op##_relaxed(args); \ - smp_mb__after_atomic(); \ - __ret; \ -}) -#endif - -#ifndef __atomic_op_release -#define __atomic_op_release(op, args...) \ -({ \ - smp_mb__before_atomic(); \ - op##_relaxed(args); \ -}) -#endif - -#ifndef __atomic_op_fence -#define __atomic_op_fence(op, args...) \ -({ \ - typeof(op##_relaxed(args)) __ret; \ - smp_mb__before_atomic(); \ - __ret = op##_relaxed(args); \ - smp_mb__after_atomic(); \ - __ret; \ -}) -#endif - -/* atomic_add_return_relaxed */ -#ifndef atomic_add_return_relaxed -#define atomic_add_return_relaxed atomic_add_return -#define atomic_add_return_acquire atomic_add_return -#define atomic_add_return_release atomic_add_return - -#else /* atomic_add_return_relaxed */ - -#ifndef atomic_add_return_acquire -#define atomic_add_return_acquire(...) \ - __atomic_op_acquire(atomic_add_return, __VA_ARGS__) -#endif - -#ifndef atomic_add_return_release -#define atomic_add_return_release(...) \ - __atomic_op_release(atomic_add_return, __VA_ARGS__) -#endif - -#ifndef atomic_add_return -#define atomic_add_return(...) \ - __atomic_op_fence(atomic_add_return, __VA_ARGS__) -#endif -#endif /* atomic_add_return_relaxed */ - -/* atomic_inc_return_relaxed */ -#ifndef atomic_inc_return_relaxed -#define atomic_inc_return_relaxed atomic_inc_return -#define atomic_inc_return_acquire atomic_inc_return -#define atomic_inc_return_release atomic_inc_return - -#else /* atomic_inc_return_relaxed */ - -#ifndef atomic_inc_return_acquire -#define atomic_inc_return_acquire(...) \ - __atomic_op_acquire(atomic_inc_return, __VA_ARGS__) -#endif - -#ifndef atomic_inc_return_release -#define atomic_inc_return_release(...) \ - __atomic_op_release(atomic_inc_return, __VA_ARGS__) -#endif - -#ifndef atomic_inc_return -#define atomic_inc_return(...) \ - __atomic_op_fence(atomic_inc_return, __VA_ARGS__) -#endif -#endif /* atomic_inc_return_relaxed */ - -/* atomic_sub_return_relaxed */ -#ifndef atomic_sub_return_relaxed -#define atomic_sub_return_relaxed atomic_sub_return -#define atomic_sub_return_acquire atomic_sub_return -#define atomic_sub_return_release atomic_sub_return - -#else /* atomic_sub_return_relaxed */ - -#ifndef atomic_sub_return_acquire -#define atomic_sub_return_acquire(...) \ - __atomic_op_acquire(atomic_sub_return, __VA_ARGS__) -#endif - -#ifndef atomic_sub_return_release -#define atomic_sub_return_release(...) \ - __atomic_op_release(atomic_sub_return, __VA_ARGS__) -#endif - -#ifndef atomic_sub_return -#define atomic_sub_return(...) \ - __atomic_op_fence(atomic_sub_return, __VA_ARGS__) -#endif -#endif /* atomic_sub_return_relaxed */ - -/* atomic_dec_return_relaxed */ -#ifndef atomic_dec_return_relaxed -#define atomic_dec_return_relaxed atomic_dec_return -#define atomic_dec_return_acquire atomic_dec_return -#define atomic_dec_return_release atomic_dec_return - -#else /* atomic_dec_return_relaxed */ - -#ifndef atomic_dec_return_acquire -#define atomic_dec_return_acquire(...) \ - __atomic_op_acquire(atomic_dec_return, __VA_ARGS__) -#endif - -#ifndef atomic_dec_return_release -#define atomic_dec_return_release(...) \ - __atomic_op_release(atomic_dec_return, __VA_ARGS__) -#endif - -#ifndef atomic_dec_return -#define atomic_dec_return(...) \ - __atomic_op_fence(atomic_dec_return, __VA_ARGS__) -#endif -#endif /* atomic_dec_return_relaxed */ - - -/* atomic_fetch_add_relaxed */ -#ifndef atomic_fetch_add_relaxed -#define atomic_fetch_add_relaxed atomic_fetch_add -#define atomic_fetch_add_acquire atomic_fetch_add -#define atomic_fetch_add_release atomic_fetch_add - -#else /* atomic_fetch_add_relaxed */ - -#ifndef atomic_fetch_add_acquire -#define atomic_fetch_add_acquire(...) \ - __atomic_op_acquire(atomic_fetch_add, __VA_ARGS__) -#endif - -#ifndef atomic_fetch_add_release -#define atomic_fetch_add_release(...) \ - __atomic_op_release(atomic_fetch_add, __VA_ARGS__) -#endif - -#ifndef atomic_fetch_add -#define atomic_fetch_add(...) \ - __atomic_op_fence(atomic_fetch_add, __VA_ARGS__) -#endif -#endif /* atomic_fetch_add_relaxed */ - -/* atomic_fetch_inc_relaxed */ -#ifndef atomic_fetch_inc_relaxed - -#ifndef atomic_fetch_inc -#define atomic_fetch_inc(v) atomic_fetch_add(1, (v)) -#define atomic_fetch_inc_relaxed(v) atomic_fetch_add_relaxed(1, (v)) -#define atomic_fetch_inc_acquire(v) atomic_fetch_add_acquire(1, (v)) -#define atomic_fetch_inc_release(v) atomic_fetch_add_release(1, (v)) -#else /* atomic_fetch_inc */ -#define atomic_fetch_inc_relaxed atomic_fetch_inc -#define atomic_fetch_inc_acquire atomic_fetch_inc -#define atomic_fetch_inc_release atomic_fetch_inc -#endif /* atomic_fetch_inc */ - -#else /* atomic_fetch_inc_relaxed */ - -#ifndef atomic_fetch_inc_acquire -#define atomic_fetch_inc_acquire(...) \ - __atomic_op_acquire(atomic_fetch_inc, __VA_ARGS__) -#endif - -#ifndef atomic_fetch_inc_release -#define atomic_fetch_inc_release(...) \ - __atomic_op_release(atomic_fetch_inc, __VA_ARGS__) -#endif - -#ifndef atomic_fetch_inc -#define atomic_fetch_inc(...) \ - __atomic_op_fence(atomic_fetch_inc, __VA_ARGS__) -#endif -#endif /* atomic_fetch_inc_relaxed */ - -/* atomic_fetch_sub_relaxed */ -#ifndef atomic_fetch_sub_relaxed -#define atomic_fetch_sub_relaxed atomic_fetch_sub -#define atomic_fetch_sub_acquire atomic_fetch_sub -#define atomic_fetch_sub_release atomic_fetch_sub - -#else /* atomic_fetch_sub_relaxed */ - -#ifndef atomic_fetch_sub_acquire -#define atomic_fetch_sub_acquire(...) \ - __atomic_op_acquire(atomic_fetch_sub, __VA_ARGS__) -#endif - -#ifndef atomic_fetch_sub_release -#define atomic_fetch_sub_release(...) \ - __atomic_op_release(atomic_fetch_sub, __VA_ARGS__) -#endif - -#ifndef atomic_fetch_sub -#define atomic_fetch_sub(...) \ - __atomic_op_fence(atomic_fetch_sub, __VA_ARGS__) -#endif -#endif /* atomic_fetch_sub_relaxed */ - -/* atomic_fetch_dec_relaxed */ -#ifndef atomic_fetch_dec_relaxed - -#ifndef atomic_fetch_dec -#define atomic_fetch_dec(v) atomic_fetch_sub(1, (v)) -#define atomic_fetch_dec_relaxed(v) atomic_fetch_sub_relaxed(1, (v)) -#define atomic_fetch_dec_acquire(v) atomic_fetch_sub_acquire(1, (v)) -#define atomic_fetch_dec_release(v) atomic_fetch_sub_release(1, (v)) -#else /* atomic_fetch_dec */ -#define atomic_fetch_dec_relaxed atomic_fetch_dec -#define atomic_fetch_dec_acquire atomic_fetch_dec -#define atomic_fetch_dec_release atomic_fetch_dec -#endif /* atomic_fetch_dec */ - -#else /* atomic_fetch_dec_relaxed */ - -#ifndef atomic_fetch_dec_acquire -#define atomic_fetch_dec_acquire(...) \ - __atomic_op_acquire(atomic_fetch_dec, __VA_ARGS__) -#endif - -#ifndef atomic_fetch_dec_release -#define atomic_fetch_dec_release(...) \ - __atomic_op_release(atomic_fetch_dec, __VA_ARGS__) -#endif - -#ifndef atomic_fetch_dec -#define atomic_fetch_dec(...) \ - __atomic_op_fence(atomic_fetch_dec, __VA_ARGS__) -#endif -#endif /* atomic_fetch_dec_relaxed */ - -/* atomic_fetch_or_relaxed */ -#ifndef atomic_fetch_or_relaxed -#define atomic_fetch_or_relaxed atomic_fetch_or -#define atomic_fetch_or_acquire atomic_fetch_or -#define atomic_fetch_or_release atomic_fetch_or - -#else /* atomic_fetch_or_relaxed */ - -#ifndef atomic_fetch_or_acquire -#define atomic_fetch_or_acquire(...) \ - __atomic_op_acquire(atomic_fetch_or, __VA_ARGS__) -#endif - -#ifndef atomic_fetch_or_release -#define atomic_fetch_or_release(...) \ - __atomic_op_release(atomic_fetch_or, __VA_ARGS__) -#endif - -#ifndef atomic_fetch_or -#define atomic_fetch_or(...) \ - __atomic_op_fence(atomic_fetch_or, __VA_ARGS__) -#endif -#endif /* atomic_fetch_or_relaxed */ - -/* atomic_fetch_and_relaxed */ -#ifndef atomic_fetch_and_relaxed -#define atomic_fetch_and_relaxed atomic_fetch_and -#define atomic_fetch_and_acquire atomic_fetch_and -#define atomic_fetch_and_release atomic_fetch_and - -#else /* atomic_fetch_and_relaxed */ - -#ifndef atomic_fetch_and_acquire -#define atomic_fetch_and_acquire(...) \ - __atomic_op_acquire(atomic_fetch_and, __VA_ARGS__) -#endif - -#ifndef atomic_fetch_and_release -#define atomic_fetch_and_release(...) \ - __atomic_op_release(atomic_fetch_and, __VA_ARGS__) -#endif - -#ifndef atomic_fetch_and -#define atomic_fetch_and(...) \ - __atomic_op_fence(atomic_fetch_and, __VA_ARGS__) -#endif -#endif /* atomic_fetch_and_relaxed */ - -#ifdef atomic_andnot -/* atomic_fetch_andnot_relaxed */ -#ifndef atomic_fetch_andnot_relaxed -#define atomic_fetch_andnot_relaxed atomic_fetch_andnot -#define atomic_fetch_andnot_acquire atomic_fetch_andnot -#define atomic_fetch_andnot_release atomic_fetch_andnot - -#else /* atomic_fetch_andnot_relaxed */ - -#ifndef atomic_fetch_andnot_acquire -#define atomic_fetch_andnot_acquire(...) \ - __atomic_op_acquire(atomic_fetch_andnot, __VA_ARGS__) -#endif - -#ifndef atomic_fetch_andnot_release -#define atomic_fetch_andnot_release(...) \ - __atomic_op_release(atomic_fetch_andnot, __VA_ARGS__) -#endif - -#ifndef atomic_fetch_andnot -#define atomic_fetch_andnot(...) \ - __atomic_op_fence(atomic_fetch_andnot, __VA_ARGS__) -#endif -#endif /* atomic_fetch_andnot_relaxed */ -#endif /* atomic_andnot */ - -/* atomic_fetch_xor_relaxed */ -#ifndef atomic_fetch_xor_relaxed -#define atomic_fetch_xor_relaxed atomic_fetch_xor -#define atomic_fetch_xor_acquire atomic_fetch_xor -#define atomic_fetch_xor_release atomic_fetch_xor - -#else /* atomic_fetch_xor_relaxed */ - -#ifndef atomic_fetch_xor_acquire -#define atomic_fetch_xor_acquire(...) \ - __atomic_op_acquire(atomic_fetch_xor, __VA_ARGS__) -#endif - -#ifndef atomic_fetch_xor_release -#define atomic_fetch_xor_release(...) \ - __atomic_op_release(atomic_fetch_xor, __VA_ARGS__) -#endif - -#ifndef atomic_fetch_xor -#define atomic_fetch_xor(...) \ - __atomic_op_fence(atomic_fetch_xor, __VA_ARGS__) -#endif -#endif /* atomic_fetch_xor_relaxed */ - - -/* atomic_xchg_relaxed */ -#ifndef atomic_xchg_relaxed -#define atomic_xchg_relaxed atomic_xchg -#define atomic_xchg_acquire atomic_xchg -#define atomic_xchg_release atomic_xchg - -#else /* atomic_xchg_relaxed */ - -#ifndef atomic_xchg_acquire -#define atomic_xchg_acquire(...) \ - __atomic_op_acquire(atomic_xchg, __VA_ARGS__) -#endif - -#ifndef atomic_xchg_release -#define atomic_xchg_release(...) \ - __atomic_op_release(atomic_xchg, __VA_ARGS__) -#endif - -#ifndef atomic_xchg -#define atomic_xchg(...) \ - __atomic_op_fence(atomic_xchg, __VA_ARGS__) -#endif -#endif /* atomic_xchg_relaxed */ - -/* atomic_cmpxchg_relaxed */ -#ifndef atomic_cmpxchg_relaxed -#define atomic_cmpxchg_relaxed atomic_cmpxchg -#define atomic_cmpxchg_acquire atomic_cmpxchg -#define atomic_cmpxchg_release atomic_cmpxchg - -#else /* atomic_cmpxchg_relaxed */ - -#ifndef atomic_cmpxchg_acquire -#define atomic_cmpxchg_acquire(...) \ - __atomic_op_acquire(atomic_cmpxchg, __VA_ARGS__) -#endif - -#ifndef atomic_cmpxchg_release -#define atomic_cmpxchg_release(...) \ - __atomic_op_release(atomic_cmpxchg, __VA_ARGS__) -#endif - -#ifndef atomic_cmpxchg -#define atomic_cmpxchg(...) \ - __atomic_op_fence(atomic_cmpxchg, __VA_ARGS__) -#endif -#endif /* atomic_cmpxchg_relaxed */ - -/* cmpxchg_relaxed */ -#ifndef cmpxchg_relaxed -#define cmpxchg_relaxed cmpxchg -#define cmpxchg_acquire cmpxchg -#define cmpxchg_release cmpxchg - -#else /* cmpxchg_relaxed */ - -#ifndef cmpxchg_acquire -#define cmpxchg_acquire(...) \ - __atomic_op_acquire(cmpxchg, __VA_ARGS__) -#endif - -#ifndef cmpxchg_release -#define cmpxchg_release(...) \ - __atomic_op_release(cmpxchg, __VA_ARGS__) -#endif - -#ifndef cmpxchg -#define cmpxchg(...) \ - __atomic_op_fence(cmpxchg, __VA_ARGS__) -#endif -#endif /* cmpxchg_relaxed */ - -/* cmpxchg64_relaxed */ -#ifndef cmpxchg64_relaxed -#define cmpxchg64_relaxed cmpxchg64 -#define cmpxchg64_acquire cmpxchg64 -#define cmpxchg64_release cmpxchg64 - -#else /* cmpxchg64_relaxed */ - -#ifndef cmpxchg64_acquire -#define cmpxchg64_acquire(...) \ - __atomic_op_acquire(cmpxchg64, __VA_ARGS__) -#endif - -#ifndef cmpxchg64_release -#define cmpxchg64_release(...) \ - __atomic_op_release(cmpxchg64, __VA_ARGS__) -#endif - -#ifndef cmpxchg64 -#define cmpxchg64(...) \ - __atomic_op_fence(cmpxchg64, __VA_ARGS__) -#endif -#endif /* cmpxchg64_relaxed */ - -/* xchg_relaxed */ -#ifndef xchg_relaxed -#define xchg_relaxed xchg -#define xchg_acquire xchg -#define xchg_release xchg - -#else /* xchg_relaxed */ - -#ifndef xchg_acquire -#define xchg_acquire(...) __atomic_op_acquire(xchg, __VA_ARGS__) -#endif - -#ifndef xchg_release -#define xchg_release(...) __atomic_op_release(xchg, __VA_ARGS__) -#endif - -#ifndef xchg -#define xchg(...) __atomic_op_fence(xchg, __VA_ARGS__) -#endif -#endif /* xchg_relaxed */ - -/** - * atomic_add_unless - add unless the number is already a given value - * @v: pointer of type atomic_t - * @a: the amount to add to v... - * @u: ...unless v is equal to u. - * - * Atomically adds @a to @v, so long as @v was not already @u. - * Returns non-zero if @v was not @u, and zero otherwise. - */ -static inline int atomic_add_unless(atomic_t *v, int a, int u) -{ - return __atomic_add_unless(v, a, u) != u; -} - -/** - * atomic_inc_not_zero - increment unless the number is zero - * @v: pointer of type atomic_t - * - * Atomically increments @v by 1, so long as @v is non-zero. - * Returns non-zero if @v was non-zero, and zero otherwise. - */ -#ifndef atomic_inc_not_zero -#define atomic_inc_not_zero(v) atomic_add_unless((v), 1, 0) -#endif - -#ifndef atomic_andnot -static inline void atomic_andnot(int i, atomic_t *v) -{ - atomic_and(~i, v); -} - -static inline int atomic_fetch_andnot(int i, atomic_t *v) -{ - return atomic_fetch_and(~i, v); -} - -static inline int atomic_fetch_andnot_relaxed(int i, atomic_t *v) -{ - return atomic_fetch_and_relaxed(~i, v); -} - -static inline int atomic_fetch_andnot_acquire(int i, atomic_t *v) -{ - return atomic_fetch_and_acquire(~i, v); -} - -static inline int atomic_fetch_andnot_release(int i, atomic_t *v) -{ - return atomic_fetch_and_release(~i, v); -} -#endif - -/** - * atomic_inc_not_zero_hint - increment if not null - * @v: pointer of type atomic_t - * @hint: probable value of the atomic before the increment - * - * This version of atomic_inc_not_zero() gives a hint of probable - * value of the atomic. This helps processor to not read the memory - * before doing the atomic read/modify/write cycle, lowering - * number of bus transactions on some arches. - * - * Returns: 0 if increment was not done, 1 otherwise. - */ -#ifndef atomic_inc_not_zero_hint -static inline int atomic_inc_not_zero_hint(atomic_t *v, int hint) -{ - int val, c = hint; - - /* sanity test, should be removed by compiler if hint is a constant */ - if (!hint) - return atomic_inc_not_zero(v); - - do { - val = atomic_cmpxchg(v, c, c + 1); - if (val == c) - return 1; - c = val; - } while (c); - - return 0; -} -#endif - -#ifndef atomic_inc_unless_negative -static inline int atomic_inc_unless_negative(atomic_t *p) -{ - int v, v1; - for (v = 0; v >= 0; v = v1) { - v1 = atomic_cmpxchg(p, v, v + 1); - if (likely(v1 == v)) - return 1; - } - return 0; -} -#endif - -#ifndef atomic_dec_unless_positive -static inline int atomic_dec_unless_positive(atomic_t *p) -{ - int v, v1; - for (v = 0; v <= 0; v = v1) { - v1 = atomic_cmpxchg(p, v, v - 1); - if (likely(v1 == v)) - return 1; - } - return 0; -} -#endif - -/* - * atomic_dec_if_positive - decrement by 1 if old value positive - * @v: pointer of type atomic_t - * - * The function returns the old value of *v minus 1, even if - * the atomic variable, v, was not decremented. - */ -#ifndef atomic_dec_if_positive -static inline int atomic_dec_if_positive(atomic_t *v) -{ - int c, old, dec; - c = atomic_read(v); - for (;;) { - dec = c - 1; - if (unlikely(dec < 0)) - break; - old = atomic_cmpxchg((v), c, dec); - if (likely(old == c)) - break; - c = old; - } - return dec; -} -#endif - -#ifdef CONFIG_GENERIC_ATOMIC64 -#include -#endif - -#ifndef atomic64_read_acquire -#define atomic64_read_acquire(v) smp_load_acquire(&(v)->counter) -#endif - -#ifndef atomic64_set_release -#define atomic64_set_release(v, i) smp_store_release(&(v)->counter, (i)) -#endif - -/* atomic64_add_return_relaxed */ -#ifndef atomic64_add_return_relaxed -#define atomic64_add_return_relaxed atomic64_add_return -#define atomic64_add_return_acquire atomic64_add_return -#define atomic64_add_return_release atomic64_add_return - -#else /* atomic64_add_return_relaxed */ - -#ifndef atomic64_add_return_acquire -#define atomic64_add_return_acquire(...) \ - __atomic_op_acquire(atomic64_add_return, __VA_ARGS__) -#endif - -#ifndef atomic64_add_return_release -#define atomic64_add_return_release(...) \ - __atomic_op_release(atomic64_add_return, __VA_ARGS__) -#endif - -#ifndef atomic64_add_return -#define atomic64_add_return(...) \ - __atomic_op_fence(atomic64_add_return, __VA_ARGS__) -#endif -#endif /* atomic64_add_return_relaxed */ - -/* atomic64_inc_return_relaxed */ -#ifndef atomic64_inc_return_relaxed -#define atomic64_inc_return_relaxed atomic64_inc_return -#define atomic64_inc_return_acquire atomic64_inc_return -#define atomic64_inc_return_release atomic64_inc_return - -#else /* atomic64_inc_return_relaxed */ - -#ifndef atomic64_inc_return_acquire -#define atomic64_inc_return_acquire(...) \ - __atomic_op_acquire(atomic64_inc_return, __VA_ARGS__) -#endif - -#ifndef atomic64_inc_return_release -#define atomic64_inc_return_release(...) \ - __atomic_op_release(atomic64_inc_return, __VA_ARGS__) -#endif - -#ifndef atomic64_inc_return -#define atomic64_inc_return(...) \ - __atomic_op_fence(atomic64_inc_return, __VA_ARGS__) -#endif -#endif /* atomic64_inc_return_relaxed */ - - -/* atomic64_sub_return_relaxed */ -#ifndef atomic64_sub_return_relaxed -#define atomic64_sub_return_relaxed atomic64_sub_return -#define atomic64_sub_return_acquire atomic64_sub_return -#define atomic64_sub_return_release atomic64_sub_return - -#else /* atomic64_sub_return_relaxed */ - -#ifndef atomic64_sub_return_acquire -#define atomic64_sub_return_acquire(...) \ - __atomic_op_acquire(atomic64_sub_return, __VA_ARGS__) -#endif - -#ifndef atomic64_sub_return_release -#define atomic64_sub_return_release(...) \ - __atomic_op_release(atomic64_sub_return, __VA_ARGS__) -#endif - -#ifndef atomic64_sub_return -#define atomic64_sub_return(...) \ - __atomic_op_fence(atomic64_sub_return, __VA_ARGS__) -#endif -#endif /* atomic64_sub_return_relaxed */ - -/* atomic64_dec_return_relaxed */ -#ifndef atomic64_dec_return_relaxed -#define atomic64_dec_return_relaxed atomic64_dec_return -#define atomic64_dec_return_acquire atomic64_dec_return -#define atomic64_dec_return_release atomic64_dec_return - -#else /* atomic64_dec_return_relaxed */ - -#ifndef atomic64_dec_return_acquire -#define atomic64_dec_return_acquire(...) \ - __atomic_op_acquire(atomic64_dec_return, __VA_ARGS__) -#endif - -#ifndef atomic64_dec_return_release -#define atomic64_dec_return_release(...) \ - __atomic_op_release(atomic64_dec_return, __VA_ARGS__) -#endif - -#ifndef atomic64_dec_return -#define atomic64_dec_return(...) \ - __atomic_op_fence(atomic64_dec_return, __VA_ARGS__) -#endif -#endif /* atomic64_dec_return_relaxed */ - - -/* atomic64_fetch_add_relaxed */ -#ifndef atomic64_fetch_add_relaxed -#define atomic64_fetch_add_relaxed atomic64_fetch_add -#define atomic64_fetch_add_acquire atomic64_fetch_add -#define atomic64_fetch_add_release atomic64_fetch_add - -#else /* atomic64_fetch_add_relaxed */ - -#ifndef atomic64_fetch_add_acquire -#define atomic64_fetch_add_acquire(...) \ - __atomic_op_acquire(atomic64_fetch_add, __VA_ARGS__) -#endif - -#ifndef atomic64_fetch_add_release -#define atomic64_fetch_add_release(...) \ - __atomic_op_release(atomic64_fetch_add, __VA_ARGS__) -#endif - -#ifndef atomic64_fetch_add -#define atomic64_fetch_add(...) \ - __atomic_op_fence(atomic64_fetch_add, __VA_ARGS__) -#endif -#endif /* atomic64_fetch_add_relaxed */ - -/* atomic64_fetch_inc_relaxed */ -#ifndef atomic64_fetch_inc_relaxed - -#ifndef atomic64_fetch_inc -#define atomic64_fetch_inc(v) atomic64_fetch_add(1, (v)) -#define atomic64_fetch_inc_relaxed(v) atomic64_fetch_add_relaxed(1, (v)) -#define atomic64_fetch_inc_acquire(v) atomic64_fetch_add_acquire(1, (v)) -#define atomic64_fetch_inc_release(v) atomic64_fetch_add_release(1, (v)) -#else /* atomic64_fetch_inc */ -#define atomic64_fetch_inc_relaxed atomic64_fetch_inc -#define atomic64_fetch_inc_acquire atomic64_fetch_inc -#define atomic64_fetch_inc_release atomic64_fetch_inc -#endif /* atomic64_fetch_inc */ - -#else /* atomic64_fetch_inc_relaxed */ - -#ifndef atomic64_fetch_inc_acquire -#define atomic64_fetch_inc_acquire(...) \ - __atomic_op_acquire(atomic64_fetch_inc, __VA_ARGS__) -#endif - -#ifndef atomic64_fetch_inc_release -#define atomic64_fetch_inc_release(...) \ - __atomic_op_release(atomic64_fetch_inc, __VA_ARGS__) -#endif - -#ifndef atomic64_fetch_inc -#define atomic64_fetch_inc(...) \ - __atomic_op_fence(atomic64_fetch_inc, __VA_ARGS__) -#endif -#endif /* atomic64_fetch_inc_relaxed */ - -/* atomic64_fetch_sub_relaxed */ -#ifndef atomic64_fetch_sub_relaxed -#define atomic64_fetch_sub_relaxed atomic64_fetch_sub -#define atomic64_fetch_sub_acquire atomic64_fetch_sub -#define atomic64_fetch_sub_release atomic64_fetch_sub - -#else /* atomic64_fetch_sub_relaxed */ - -#ifndef atomic64_fetch_sub_acquire -#define atomic64_fetch_sub_acquire(...) \ - __atomic_op_acquire(atomic64_fetch_sub, __VA_ARGS__) -#endif - -#ifndef atomic64_fetch_sub_release -#define atomic64_fetch_sub_release(...) \ - __atomic_op_release(atomic64_fetch_sub, __VA_ARGS__) -#endif - -#ifndef atomic64_fetch_sub -#define atomic64_fetch_sub(...) \ - __atomic_op_fence(atomic64_fetch_sub, __VA_ARGS__) -#endif -#endif /* atomic64_fetch_sub_relaxed */ - -/* atomic64_fetch_dec_relaxed */ -#ifndef atomic64_fetch_dec_relaxed - -#ifndef atomic64_fetch_dec -#define atomic64_fetch_dec(v) atomic64_fetch_sub(1, (v)) -#define atomic64_fetch_dec_relaxed(v) atomic64_fetch_sub_relaxed(1, (v)) -#define atomic64_fetch_dec_acquire(v) atomic64_fetch_sub_acquire(1, (v)) -#define atomic64_fetch_dec_release(v) atomic64_fetch_sub_release(1, (v)) -#else /* atomic64_fetch_dec */ -#define atomic64_fetch_dec_relaxed atomic64_fetch_dec -#define atomic64_fetch_dec_acquire atomic64_fetch_dec -#define atomic64_fetch_dec_release atomic64_fetch_dec -#endif /* atomic64_fetch_dec */ - -#else /* atomic64_fetch_dec_relaxed */ - -#ifndef atomic64_fetch_dec_acquire -#define atomic64_fetch_dec_acquire(...) \ - __atomic_op_acquire(atomic64_fetch_dec, __VA_ARGS__) -#endif - -#ifndef atomic64_fetch_dec_release -#define atomic64_fetch_dec_release(...) \ - __atomic_op_release(atomic64_fetch_dec, __VA_ARGS__) -#endif - -#ifndef atomic64_fetch_dec -#define atomic64_fetch_dec(...) \ - __atomic_op_fence(atomic64_fetch_dec, __VA_ARGS__) -#endif -#endif /* atomic64_fetch_dec_relaxed */ - -/* atomic64_fetch_or_relaxed */ -#ifndef atomic64_fetch_or_relaxed -#define atomic64_fetch_or_relaxed atomic64_fetch_or -#define atomic64_fetch_or_acquire atomic64_fetch_or -#define atomic64_fetch_or_release atomic64_fetch_or - -#else /* atomic64_fetch_or_relaxed */ - -#ifndef atomic64_fetch_or_acquire -#define atomic64_fetch_or_acquire(...) \ - __atomic_op_acquire(atomic64_fetch_or, __VA_ARGS__) -#endif - -#ifndef atomic64_fetch_or_release -#define atomic64_fetch_or_release(...) \ - __atomic_op_release(atomic64_fetch_or, __VA_ARGS__) -#endif - -#ifndef atomic64_fetch_or -#define atomic64_fetch_or(...) \ - __atomic_op_fence(atomic64_fetch_or, __VA_ARGS__) -#endif -#endif /* atomic64_fetch_or_relaxed */ - -/* atomic64_fetch_and_relaxed */ -#ifndef atomic64_fetch_and_relaxed -#define atomic64_fetch_and_relaxed atomic64_fetch_and -#define atomic64_fetch_and_acquire atomic64_fetch_and -#define atomic64_fetch_and_release atomic64_fetch_and - -#else /* atomic64_fetch_and_relaxed */ - -#ifndef atomic64_fetch_and_acquire -#define atomic64_fetch_and_acquire(...) \ - __atomic_op_acquire(atomic64_fetch_and, __VA_ARGS__) -#endif - -#ifndef atomic64_fetch_and_release -#define atomic64_fetch_and_release(...) \ - __atomic_op_release(atomic64_fetch_and, __VA_ARGS__) -#endif - -#ifndef atomic64_fetch_and -#define atomic64_fetch_and(...) \ - __atomic_op_fence(atomic64_fetch_and, __VA_ARGS__) -#endif -#endif /* atomic64_fetch_and_relaxed */ - -#ifdef atomic64_andnot -/* atomic64_fetch_andnot_relaxed */ -#ifndef atomic64_fetch_andnot_relaxed -#define atomic64_fetch_andnot_relaxed atomic64_fetch_andnot -#define atomic64_fetch_andnot_acquire atomic64_fetch_andnot -#define atomic64_fetch_andnot_release atomic64_fetch_andnot - -#else /* atomic64_fetch_andnot_relaxed */ - -#ifndef atomic64_fetch_andnot_acquire -#define atomic64_fetch_andnot_acquire(...) \ - __atomic_op_acquire(atomic64_fetch_andnot, __VA_ARGS__) -#endif - -#ifndef atomic64_fetch_andnot_release -#define atomic64_fetch_andnot_release(...) \ - __atomic_op_release(atomic64_fetch_andnot, __VA_ARGS__) -#endif - -#ifndef atomic64_fetch_andnot -#define atomic64_fetch_andnot(...) \ - __atomic_op_fence(atomic64_fetch_andnot, __VA_ARGS__) -#endif -#endif /* atomic64_fetch_andnot_relaxed */ -#endif /* atomic64_andnot */ - -/* atomic64_fetch_xor_relaxed */ -#ifndef atomic64_fetch_xor_relaxed -#define atomic64_fetch_xor_relaxed atomic64_fetch_xor -#define atomic64_fetch_xor_acquire atomic64_fetch_xor -#define atomic64_fetch_xor_release atomic64_fetch_xor - -#else /* atomic64_fetch_xor_relaxed */ - -#ifndef atomic64_fetch_xor_acquire -#define atomic64_fetch_xor_acquire(...) \ - __atomic_op_acquire(atomic64_fetch_xor, __VA_ARGS__) -#endif - -#ifndef atomic64_fetch_xor_release -#define atomic64_fetch_xor_release(...) \ - __atomic_op_release(atomic64_fetch_xor, __VA_ARGS__) -#endif - -#ifndef atomic64_fetch_xor -#define atomic64_fetch_xor(...) \ - __atomic_op_fence(atomic64_fetch_xor, __VA_ARGS__) -#endif -#endif /* atomic64_fetch_xor_relaxed */ - - -/* atomic64_xchg_relaxed */ -#ifndef atomic64_xchg_relaxed -#define atomic64_xchg_relaxed atomic64_xchg -#define atomic64_xchg_acquire atomic64_xchg -#define atomic64_xchg_release atomic64_xchg - -#else /* atomic64_xchg_relaxed */ - -#ifndef atomic64_xchg_acquire -#define atomic64_xchg_acquire(...) \ - __atomic_op_acquire(atomic64_xchg, __VA_ARGS__) -#endif - -#ifndef atomic64_xchg_release -#define atomic64_xchg_release(...) \ - __atomic_op_release(atomic64_xchg, __VA_ARGS__) -#endif - -#ifndef atomic64_xchg -#define atomic64_xchg(...) \ - __atomic_op_fence(atomic64_xchg, __VA_ARGS__) -#endif -#endif /* atomic64_xchg_relaxed */ - -/* atomic64_cmpxchg_relaxed */ -#ifndef atomic64_cmpxchg_relaxed -#define atomic64_cmpxchg_relaxed atomic64_cmpxchg -#define atomic64_cmpxchg_acquire atomic64_cmpxchg -#define atomic64_cmpxchg_release atomic64_cmpxchg - -#else /* atomic64_cmpxchg_relaxed */ - -#ifndef atomic64_cmpxchg_acquire -#define atomic64_cmpxchg_acquire(...) \ - __atomic_op_acquire(atomic64_cmpxchg, __VA_ARGS__) -#endif - -#ifndef atomic64_cmpxchg_release -#define atomic64_cmpxchg_release(...) \ - __atomic_op_release(atomic64_cmpxchg, __VA_ARGS__) -#endif - -#ifndef atomic64_cmpxchg -#define atomic64_cmpxchg(...) \ - __atomic_op_fence(atomic64_cmpxchg, __VA_ARGS__) -#endif -#endif /* atomic64_cmpxchg_relaxed */ - -#ifndef atomic64_andnot -static inline void atomic64_andnot(long long i, atomic64_t *v) -{ - atomic64_and(~i, v); -} - -static inline long long atomic64_fetch_andnot(long long i, atomic64_t *v) -{ - return atomic64_fetch_and(~i, v); -} - -static inline long long atomic64_fetch_andnot_relaxed(long long i, atomic64_t *v) -{ - return atomic64_fetch_and_relaxed(~i, v); -} - -static inline long long atomic64_fetch_andnot_acquire(long long i, atomic64_t *v) -{ - return atomic64_fetch_and_acquire(~i, v); -} - -static inline long long atomic64_fetch_andnot_release(long long i, atomic64_t *v) -{ - return atomic64_fetch_and_release(~i, v); -} -#endif - -#include - -#endif /* _LINUX_ATOMIC_H */ diff --git a/src/linux/include/linux/attribute_container.h b/src/linux/include/linux/attribute_container.h deleted file mode 100644 index 896c689..0000000 --- a/src/linux/include/linux/attribute_container.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * attribute_container.h - a generic container for all classes - * - * Copyright (c) 2005 - James Bottomley - * - * This file is licensed under GPLv2 - */ - -#ifndef _ATTRIBUTE_CONTAINER_H_ -#define _ATTRIBUTE_CONTAINER_H_ - -#include -#include - -struct device; - -struct attribute_container { - struct list_head node; - struct klist containers; - struct class *class; - const struct attribute_group *grp; - struct device_attribute **attrs; - int (*match)(struct attribute_container *, struct device *); -#define ATTRIBUTE_CONTAINER_NO_CLASSDEVS 0x01 - unsigned long flags; -}; - -static inline int -attribute_container_no_classdevs(struct attribute_container *atc) -{ - return atc->flags & ATTRIBUTE_CONTAINER_NO_CLASSDEVS; -} - -static inline void -attribute_container_set_no_classdevs(struct attribute_container *atc) -{ - atc->flags |= ATTRIBUTE_CONTAINER_NO_CLASSDEVS; -} - -int attribute_container_register(struct attribute_container *cont); -int __must_check attribute_container_unregister(struct attribute_container *cont); -void attribute_container_create_device(struct device *dev, - int (*fn)(struct attribute_container *, - struct device *, - struct device *)); -void attribute_container_add_device(struct device *dev, - int (*fn)(struct attribute_container *, - struct device *, - struct device *)); -void attribute_container_remove_device(struct device *dev, - void (*fn)(struct attribute_container *, - struct device *, - struct device *)); -void attribute_container_device_trigger(struct device *dev, - int (*fn)(struct attribute_container *, - struct device *, - struct device *)); -void attribute_container_trigger(struct device *dev, - int (*fn)(struct attribute_container *, - struct device *)); -int attribute_container_add_attrs(struct device *classdev); -int attribute_container_add_class_device(struct device *classdev); -int attribute_container_add_class_device_adapter(struct attribute_container *cont, - struct device *dev, - struct device *classdev); -void attribute_container_remove_attrs(struct device *classdev); -void attribute_container_class_device_del(struct device *classdev); -struct attribute_container *attribute_container_classdev_to_container(struct device *); -struct device *attribute_container_find_class_device(struct attribute_container *, struct device *); -struct device_attribute **attribute_container_classdev_to_attrs(const struct device *classdev); - -#endif diff --git a/src/linux/include/linux/audit.h b/src/linux/include/linux/audit.h deleted file mode 100644 index 9d4443f..0000000 --- a/src/linux/include/linux/audit.h +++ /dev/null @@ -1,560 +0,0 @@ -/* audit.h -- Auditing support - * - * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Written by Rickard E. (Rik) Faith - * - */ -#ifndef _LINUX_AUDIT_H_ -#define _LINUX_AUDIT_H_ - -#include -#include -#include - -#define AUDIT_INO_UNSET ((unsigned long)-1) -#define AUDIT_DEV_UNSET ((dev_t)-1) - -struct audit_sig_info { - uid_t uid; - pid_t pid; - char ctx[0]; -}; - -struct audit_buffer; -struct audit_context; -struct inode; -struct netlink_skb_parms; -struct path; -struct linux_binprm; -struct mq_attr; -struct mqstat; -struct audit_watch; -struct audit_tree; -struct sk_buff; - -struct audit_krule { - u32 pflags; - u32 flags; - u32 listnr; - u32 action; - u32 mask[AUDIT_BITMASK_SIZE]; - u32 buflen; /* for data alloc on list rules */ - u32 field_count; - char *filterkey; /* ties events to rules */ - struct audit_field *fields; - struct audit_field *arch_f; /* quick access to arch field */ - struct audit_field *inode_f; /* quick access to an inode field */ - struct audit_watch *watch; /* associated watch */ - struct audit_tree *tree; /* associated watched tree */ - struct audit_fsnotify_mark *exe; - struct list_head rlist; /* entry in audit_{watch,tree}.rules list */ - struct list_head list; /* for AUDIT_LIST* purposes only */ - u64 prio; -}; - -/* Flag to indicate legacy AUDIT_LOGINUID unset usage */ -#define AUDIT_LOGINUID_LEGACY 0x1 - -struct audit_field { - u32 type; - union { - u32 val; - kuid_t uid; - kgid_t gid; - struct { - char *lsm_str; - void *lsm_rule; - }; - }; - u32 op; -}; - -extern int is_audit_feature_set(int which); - -extern int __init audit_register_class(int class, unsigned *list); -extern int audit_classify_syscall(int abi, unsigned syscall); -extern int audit_classify_arch(int arch); -/* only for compat system calls */ -extern unsigned compat_write_class[]; -extern unsigned compat_read_class[]; -extern unsigned compat_dir_class[]; -extern unsigned compat_chattr_class[]; -extern unsigned compat_signal_class[]; - -extern int audit_classify_compat_syscall(int abi, unsigned syscall); - -/* audit_names->type values */ -#define AUDIT_TYPE_UNKNOWN 0 /* we don't know yet */ -#define AUDIT_TYPE_NORMAL 1 /* a "normal" audit record */ -#define AUDIT_TYPE_PARENT 2 /* a parent audit record */ -#define AUDIT_TYPE_CHILD_DELETE 3 /* a child being deleted */ -#define AUDIT_TYPE_CHILD_CREATE 4 /* a child being created */ - -/* maximized args number that audit_socketcall can process */ -#define AUDITSC_ARGS 6 - -/* bit values for ->signal->audit_tty */ -#define AUDIT_TTY_ENABLE BIT(0) -#define AUDIT_TTY_LOG_PASSWD BIT(1) - -struct filename; - -extern void audit_log_session_info(struct audit_buffer *ab); - -#ifdef CONFIG_AUDIT -/* These are defined in audit.c */ - /* Public API */ -extern __printf(4, 5) -void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type, - const char *fmt, ...); - -extern struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask, int type); -extern __printf(2, 3) -void audit_log_format(struct audit_buffer *ab, const char *fmt, ...); -extern void audit_log_end(struct audit_buffer *ab); -extern bool audit_string_contains_control(const char *string, - size_t len); -extern void audit_log_n_hex(struct audit_buffer *ab, - const unsigned char *buf, - size_t len); -extern void audit_log_n_string(struct audit_buffer *ab, - const char *buf, - size_t n); -extern void audit_log_n_untrustedstring(struct audit_buffer *ab, - const char *string, - size_t n); -extern void audit_log_untrustedstring(struct audit_buffer *ab, - const char *string); -extern void audit_log_d_path(struct audit_buffer *ab, - const char *prefix, - const struct path *path); -extern void audit_log_key(struct audit_buffer *ab, - char *key); -extern void audit_log_link_denied(const char *operation, - struct path *link); -extern void audit_log_lost(const char *message); -#ifdef CONFIG_SECURITY -extern void audit_log_secctx(struct audit_buffer *ab, u32 secid); -#else -static inline void audit_log_secctx(struct audit_buffer *ab, u32 secid) -{ } -#endif - -extern int audit_log_task_context(struct audit_buffer *ab); -extern void audit_log_task_info(struct audit_buffer *ab, - struct task_struct *tsk); - -extern int audit_update_lsm_rules(void); - - /* Private API (for audit.c only) */ -extern int audit_rule_change(int type, __u32 portid, int seq, - void *data, size_t datasz); -extern int audit_list_rules_send(struct sk_buff *request_skb, int seq); - -extern u32 audit_enabled; -#else /* CONFIG_AUDIT */ -static inline __printf(4, 5) -void audit_log(struct audit_context *ctx, gfp_t gfp_mask, int type, - const char *fmt, ...) -{ } -static inline struct audit_buffer *audit_log_start(struct audit_context *ctx, - gfp_t gfp_mask, int type) -{ - return NULL; -} -static inline __printf(2, 3) -void audit_log_format(struct audit_buffer *ab, const char *fmt, ...) -{ } -static inline void audit_log_end(struct audit_buffer *ab) -{ } -static inline void audit_log_n_hex(struct audit_buffer *ab, - const unsigned char *buf, size_t len) -{ } -static inline void audit_log_n_string(struct audit_buffer *ab, - const char *buf, size_t n) -{ } -static inline void audit_log_n_untrustedstring(struct audit_buffer *ab, - const char *string, size_t n) -{ } -static inline void audit_log_untrustedstring(struct audit_buffer *ab, - const char *string) -{ } -static inline void audit_log_d_path(struct audit_buffer *ab, - const char *prefix, - const struct path *path) -{ } -static inline void audit_log_key(struct audit_buffer *ab, char *key) -{ } -static inline void audit_log_link_denied(const char *string, - const struct path *link) -{ } -static inline void audit_log_secctx(struct audit_buffer *ab, u32 secid) -{ } -static inline int audit_log_task_context(struct audit_buffer *ab) -{ - return 0; -} -static inline void audit_log_task_info(struct audit_buffer *ab, - struct task_struct *tsk) -{ } -#define audit_enabled 0 -#endif /* CONFIG_AUDIT */ - -#ifdef CONFIG_AUDIT_COMPAT_GENERIC -#define audit_is_compat(arch) (!((arch) & __AUDIT_ARCH_64BIT)) -#else -#define audit_is_compat(arch) false -#endif - -#ifdef CONFIG_AUDITSYSCALL -#include /* for syscall_get_arch() */ - -/* These are defined in auditsc.c */ - /* Public API */ -extern int audit_alloc(struct task_struct *task); -extern void __audit_free(struct task_struct *task); -extern void __audit_syscall_entry(int major, unsigned long a0, unsigned long a1, - unsigned long a2, unsigned long a3); -extern void __audit_syscall_exit(int ret_success, long ret_value); -extern struct filename *__audit_reusename(const __user char *uptr); -extern void __audit_getname(struct filename *name); - -#define AUDIT_INODE_PARENT 1 /* dentry represents the parent */ -#define AUDIT_INODE_HIDDEN 2 /* audit record should be hidden */ -extern void __audit_inode(struct filename *name, const struct dentry *dentry, - unsigned int flags); -extern void __audit_file(const struct file *); -extern void __audit_inode_child(struct inode *parent, - const struct dentry *dentry, - const unsigned char type); -extern void __audit_seccomp(unsigned long syscall, long signr, int code); -extern void __audit_ptrace(struct task_struct *t); - -static inline bool audit_dummy_context(void) -{ - void *p = current->audit_context; - return !p || *(int *)p; -} -static inline void audit_free(struct task_struct *task) -{ - if (unlikely(task->audit_context)) - __audit_free(task); -} -static inline void audit_syscall_entry(int major, unsigned long a0, - unsigned long a1, unsigned long a2, - unsigned long a3) -{ - if (unlikely(current->audit_context)) - __audit_syscall_entry(major, a0, a1, a2, a3); -} -static inline void audit_syscall_exit(void *pt_regs) -{ - if (unlikely(current->audit_context)) { - int success = is_syscall_success(pt_regs); - long return_code = regs_return_value(pt_regs); - - __audit_syscall_exit(success, return_code); - } -} -static inline struct filename *audit_reusename(const __user char *name) -{ - if (unlikely(!audit_dummy_context())) - return __audit_reusename(name); - return NULL; -} -static inline void audit_getname(struct filename *name) -{ - if (unlikely(!audit_dummy_context())) - __audit_getname(name); -} -static inline void audit_inode(struct filename *name, - const struct dentry *dentry, - unsigned int parent) { - if (unlikely(!audit_dummy_context())) { - unsigned int flags = 0; - if (parent) - flags |= AUDIT_INODE_PARENT; - __audit_inode(name, dentry, flags); - } -} -static inline void audit_file(struct file *file) -{ - if (unlikely(!audit_dummy_context())) - __audit_file(file); -} -static inline void audit_inode_parent_hidden(struct filename *name, - const struct dentry *dentry) -{ - if (unlikely(!audit_dummy_context())) - __audit_inode(name, dentry, - AUDIT_INODE_PARENT | AUDIT_INODE_HIDDEN); -} -static inline void audit_inode_child(struct inode *parent, - const struct dentry *dentry, - const unsigned char type) { - if (unlikely(!audit_dummy_context())) - __audit_inode_child(parent, dentry, type); -} -void audit_core_dumps(long signr); - -static inline void audit_seccomp(unsigned long syscall, long signr, int code) -{ - if (!audit_enabled) - return; - - /* Force a record to be reported if a signal was delivered. */ - if (signr || unlikely(!audit_dummy_context())) - __audit_seccomp(syscall, signr, code); -} - -static inline void audit_ptrace(struct task_struct *t) -{ - if (unlikely(!audit_dummy_context())) - __audit_ptrace(t); -} - - /* Private API (for audit.c only) */ -extern unsigned int audit_serial(void); -extern int auditsc_get_stamp(struct audit_context *ctx, - struct timespec *t, unsigned int *serial); -extern int audit_set_loginuid(kuid_t loginuid); - -static inline kuid_t audit_get_loginuid(struct task_struct *tsk) -{ - return tsk->loginuid; -} - -static inline unsigned int audit_get_sessionid(struct task_struct *tsk) -{ - return tsk->sessionid; -} - -extern void __audit_ipc_obj(struct kern_ipc_perm *ipcp); -extern void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode); -extern void __audit_bprm(struct linux_binprm *bprm); -extern int __audit_socketcall(int nargs, unsigned long *args); -extern int __audit_sockaddr(int len, void *addr); -extern void __audit_fd_pair(int fd1, int fd2); -extern void __audit_mq_open(int oflag, umode_t mode, struct mq_attr *attr); -extern void __audit_mq_sendrecv(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout); -extern void __audit_mq_notify(mqd_t mqdes, const struct sigevent *notification); -extern void __audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat); -extern int __audit_log_bprm_fcaps(struct linux_binprm *bprm, - const struct cred *new, - const struct cred *old); -extern void __audit_log_capset(const struct cred *new, const struct cred *old); -extern void __audit_mmap_fd(int fd, int flags); - -static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp) -{ - if (unlikely(!audit_dummy_context())) - __audit_ipc_obj(ipcp); -} -static inline void audit_fd_pair(int fd1, int fd2) -{ - if (unlikely(!audit_dummy_context())) - __audit_fd_pair(fd1, fd2); -} -static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode) -{ - if (unlikely(!audit_dummy_context())) - __audit_ipc_set_perm(qbytes, uid, gid, mode); -} -static inline void audit_bprm(struct linux_binprm *bprm) -{ - if (unlikely(!audit_dummy_context())) - __audit_bprm(bprm); -} -static inline int audit_socketcall(int nargs, unsigned long *args) -{ - if (unlikely(!audit_dummy_context())) - return __audit_socketcall(nargs, args); - return 0; -} -static inline int audit_sockaddr(int len, void *addr) -{ - if (unlikely(!audit_dummy_context())) - return __audit_sockaddr(len, addr); - return 0; -} -static inline void audit_mq_open(int oflag, umode_t mode, struct mq_attr *attr) -{ - if (unlikely(!audit_dummy_context())) - __audit_mq_open(oflag, mode, attr); -} -static inline void audit_mq_sendrecv(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec *abs_timeout) -{ - if (unlikely(!audit_dummy_context())) - __audit_mq_sendrecv(mqdes, msg_len, msg_prio, abs_timeout); -} -static inline void audit_mq_notify(mqd_t mqdes, const struct sigevent *notification) -{ - if (unlikely(!audit_dummy_context())) - __audit_mq_notify(mqdes, notification); -} -static inline void audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat) -{ - if (unlikely(!audit_dummy_context())) - __audit_mq_getsetattr(mqdes, mqstat); -} - -static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm, - const struct cred *new, - const struct cred *old) -{ - if (unlikely(!audit_dummy_context())) - return __audit_log_bprm_fcaps(bprm, new, old); - return 0; -} - -static inline void audit_log_capset(const struct cred *new, - const struct cred *old) -{ - if (unlikely(!audit_dummy_context())) - __audit_log_capset(new, old); -} - -static inline void audit_mmap_fd(int fd, int flags) -{ - if (unlikely(!audit_dummy_context())) - __audit_mmap_fd(fd, flags); -} - -extern int audit_n_rules; -extern int audit_signals; -#else /* CONFIG_AUDITSYSCALL */ -static inline int audit_alloc(struct task_struct *task) -{ - return 0; -} -static inline void audit_free(struct task_struct *task) -{ } -static inline void audit_syscall_entry(int major, unsigned long a0, - unsigned long a1, unsigned long a2, - unsigned long a3) -{ } -static inline void audit_syscall_exit(void *pt_regs) -{ } -static inline bool audit_dummy_context(void) -{ - return true; -} -static inline struct filename *audit_reusename(const __user char *name) -{ - return NULL; -} -static inline void audit_getname(struct filename *name) -{ } -static inline void __audit_inode(struct filename *name, - const struct dentry *dentry, - unsigned int flags) -{ } -static inline void __audit_inode_child(struct inode *parent, - const struct dentry *dentry, - const unsigned char type) -{ } -static inline void audit_inode(struct filename *name, - const struct dentry *dentry, - unsigned int parent) -{ } -static inline void audit_file(struct file *file) -{ -} -static inline void audit_inode_parent_hidden(struct filename *name, - const struct dentry *dentry) -{ } -static inline void audit_inode_child(struct inode *parent, - const struct dentry *dentry, - const unsigned char type) -{ } -static inline void audit_core_dumps(long signr) -{ } -static inline void __audit_seccomp(unsigned long syscall, long signr, int code) -{ } -static inline void audit_seccomp(unsigned long syscall, long signr, int code) -{ } -static inline int auditsc_get_stamp(struct audit_context *ctx, - struct timespec *t, unsigned int *serial) -{ - return 0; -} -static inline kuid_t audit_get_loginuid(struct task_struct *tsk) -{ - return INVALID_UID; -} -static inline unsigned int audit_get_sessionid(struct task_struct *tsk) -{ - return -1; -} -static inline void audit_ipc_obj(struct kern_ipc_perm *ipcp) -{ } -static inline void audit_ipc_set_perm(unsigned long qbytes, uid_t uid, - gid_t gid, umode_t mode) -{ } -static inline void audit_bprm(struct linux_binprm *bprm) -{ } -static inline int audit_socketcall(int nargs, unsigned long *args) -{ - return 0; -} -static inline void audit_fd_pair(int fd1, int fd2) -{ } -static inline int audit_sockaddr(int len, void *addr) -{ - return 0; -} -static inline void audit_mq_open(int oflag, umode_t mode, struct mq_attr *attr) -{ } -static inline void audit_mq_sendrecv(mqd_t mqdes, size_t msg_len, - unsigned int msg_prio, - const struct timespec *abs_timeout) -{ } -static inline void audit_mq_notify(mqd_t mqdes, - const struct sigevent *notification) -{ } -static inline void audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat) -{ } -static inline int audit_log_bprm_fcaps(struct linux_binprm *bprm, - const struct cred *new, - const struct cred *old) -{ - return 0; -} -static inline void audit_log_capset(const struct cred *new, - const struct cred *old) -{ } -static inline void audit_mmap_fd(int fd, int flags) -{ } -static inline void audit_ptrace(struct task_struct *t) -{ } -#define audit_n_rules 0 -#define audit_signals 0 -#endif /* CONFIG_AUDITSYSCALL */ - -static inline bool audit_loginuid_set(struct task_struct *tsk) -{ - return uid_valid(audit_get_loginuid(tsk)); -} - -static inline void audit_log_string(struct audit_buffer *ab, const char *buf) -{ - audit_log_n_string(ab, buf, strlen(buf)); -} - -#endif diff --git a/src/linux/include/linux/auxvec.h b/src/linux/include/linux/auxvec.h deleted file mode 100644 index 3e0fbe4..0000000 --- a/src/linux/include/linux/auxvec.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _LINUX_AUXVEC_H -#define _LINUX_AUXVEC_H - -#include - -#define AT_VECTOR_SIZE_BASE 20 /* NEW_AUX_ENT entries in auxiliary table */ - /* number of "#define AT_.*" above, minus {AT_NULL, AT_IGNORE, AT_NOTELF} */ -#endif /* _LINUX_AUXVEC_H */ diff --git a/src/linux/include/linux/average.h b/src/linux/include/linux/average.h deleted file mode 100644 index d04aa58..0000000 --- a/src/linux/include/linux/average.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _LINUX_AVERAGE_H -#define _LINUX_AVERAGE_H - -/* Exponentially weighted moving average (EWMA) */ - -#define DECLARE_EWMA(name, _factor, _weight) \ - struct ewma_##name { \ - unsigned long internal; \ - }; \ - static inline void ewma_##name##_init(struct ewma_##name *e) \ - { \ - BUILD_BUG_ON(!__builtin_constant_p(_factor)); \ - BUILD_BUG_ON(!__builtin_constant_p(_weight)); \ - BUILD_BUG_ON_NOT_POWER_OF_2(_factor); \ - BUILD_BUG_ON_NOT_POWER_OF_2(_weight); \ - e->internal = 0; \ - } \ - static inline unsigned long \ - ewma_##name##_read(struct ewma_##name *e) \ - { \ - BUILD_BUG_ON(!__builtin_constant_p(_factor)); \ - BUILD_BUG_ON(!__builtin_constant_p(_weight)); \ - BUILD_BUG_ON_NOT_POWER_OF_2(_factor); \ - BUILD_BUG_ON_NOT_POWER_OF_2(_weight); \ - return e->internal >> ilog2(_factor); \ - } \ - static inline void ewma_##name##_add(struct ewma_##name *e, \ - unsigned long val) \ - { \ - unsigned long internal = ACCESS_ONCE(e->internal); \ - unsigned long weight = ilog2(_weight); \ - unsigned long factor = ilog2(_factor); \ - \ - BUILD_BUG_ON(!__builtin_constant_p(_factor)); \ - BUILD_BUG_ON(!__builtin_constant_p(_weight)); \ - BUILD_BUG_ON_NOT_POWER_OF_2(_factor); \ - BUILD_BUG_ON_NOT_POWER_OF_2(_weight); \ - \ - ACCESS_ONCE(e->internal) = internal ? \ - (((internal << weight) - internal) + \ - (val << factor)) >> weight : \ - (val << factor); \ - } - -#endif /* _LINUX_AVERAGE_H */ diff --git a/src/linux/include/linux/backing-dev-defs.h b/src/linux/include/linux/backing-dev-defs.h deleted file mode 100644 index c357f27..0000000 --- a/src/linux/include/linux/backing-dev-defs.h +++ /dev/null @@ -1,260 +0,0 @@ -#ifndef __LINUX_BACKING_DEV_DEFS_H -#define __LINUX_BACKING_DEV_DEFS_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct page; -struct device; -struct dentry; - -/* - * Bits in bdi_writeback.state - */ -enum wb_state { - WB_registered, /* bdi_register() was done */ - WB_writeback_running, /* Writeback is in progress */ - WB_has_dirty_io, /* Dirty inodes on ->b_{dirty|io|more_io} */ -}; - -enum wb_congested_state { - WB_async_congested, /* The async (write) queue is getting full */ - WB_sync_congested, /* The sync queue is getting full */ -}; - -typedef int (congested_fn)(void *, int); - -enum wb_stat_item { - WB_RECLAIMABLE, - WB_WRITEBACK, - WB_DIRTIED, - WB_WRITTEN, - NR_WB_STAT_ITEMS -}; - -#define WB_STAT_BATCH (8*(1+ilog2(nr_cpu_ids))) - -/* - * For cgroup writeback, multiple wb's may map to the same blkcg. Those - * wb's can operate mostly independently but should share the congested - * state. To facilitate such sharing, the congested state is tracked using - * the following struct which is created on demand, indexed by blkcg ID on - * its bdi, and refcounted. - */ -struct bdi_writeback_congested { - unsigned long state; /* WB_[a]sync_congested flags */ - atomic_t refcnt; /* nr of attached wb's and blkg */ - -#ifdef CONFIG_CGROUP_WRITEBACK - struct backing_dev_info *bdi; /* the associated bdi */ - int blkcg_id; /* ID of the associated blkcg */ - struct rb_node rb_node; /* on bdi->cgwb_congestion_tree */ -#endif -}; - -/* - * Each wb (bdi_writeback) can perform writeback operations, is measured - * and throttled, independently. Without cgroup writeback, each bdi - * (bdi_writeback) is served by its embedded bdi->wb. - * - * On the default hierarchy, blkcg implicitly enables memcg. This allows - * using memcg's page ownership for attributing writeback IOs, and every - * memcg - blkcg combination can be served by its own wb by assigning a - * dedicated wb to each memcg, which enables isolation across different - * cgroups and propagation of IO back pressure down from the IO layer upto - * the tasks which are generating the dirty pages to be written back. - * - * A cgroup wb is indexed on its bdi by the ID of the associated memcg, - * refcounted with the number of inodes attached to it, and pins the memcg - * and the corresponding blkcg. As the corresponding blkcg for a memcg may - * change as blkcg is disabled and enabled higher up in the hierarchy, a wb - * is tested for blkcg after lookup and removed from index on mismatch so - * that a new wb for the combination can be created. - */ -struct bdi_writeback { - struct backing_dev_info *bdi; /* our parent bdi */ - - unsigned long state; /* Always use atomic bitops on this */ - unsigned long last_old_flush; /* last old data flush */ - - struct list_head b_dirty; /* dirty inodes */ - struct list_head b_io; /* parked for writeback */ - struct list_head b_more_io; /* parked for more writeback */ - struct list_head b_dirty_time; /* time stamps are dirty */ - spinlock_t list_lock; /* protects the b_* lists */ - - struct percpu_counter stat[NR_WB_STAT_ITEMS]; - - struct bdi_writeback_congested *congested; - - unsigned long bw_time_stamp; /* last time write bw is updated */ - unsigned long dirtied_stamp; - unsigned long written_stamp; /* pages written at bw_time_stamp */ - unsigned long write_bandwidth; /* the estimated write bandwidth */ - unsigned long avg_write_bandwidth; /* further smoothed write bw, > 0 */ - - /* - * The base dirty throttle rate, re-calculated on every 200ms. - * All the bdi tasks' dirty rate will be curbed under it. - * @dirty_ratelimit tracks the estimated @balanced_dirty_ratelimit - * in small steps and is much more smooth/stable than the latter. - */ - unsigned long dirty_ratelimit; - unsigned long balanced_dirty_ratelimit; - - struct fprop_local_percpu completions; - int dirty_exceeded; - - spinlock_t work_lock; /* protects work_list & dwork scheduling */ - struct list_head work_list; - struct delayed_work dwork; /* work item used for writeback */ - - struct list_head bdi_node; /* anchored at bdi->wb_list */ - -#ifdef CONFIG_CGROUP_WRITEBACK - struct percpu_ref refcnt; /* used only for !root wb's */ - struct fprop_local_percpu memcg_completions; - struct cgroup_subsys_state *memcg_css; /* the associated memcg */ - struct cgroup_subsys_state *blkcg_css; /* and blkcg */ - struct list_head memcg_node; /* anchored at memcg->cgwb_list */ - struct list_head blkcg_node; /* anchored at blkcg->cgwb_list */ - - union { - struct work_struct release_work; - struct rcu_head rcu; - }; -#endif -}; - -struct backing_dev_info { - struct list_head bdi_list; - unsigned long ra_pages; /* max readahead in PAGE_SIZE units */ - unsigned int capabilities; /* Device capabilities */ - congested_fn *congested_fn; /* Function pointer if device is md/dm */ - void *congested_data; /* Pointer to aux data for congested func */ - - char *name; - - unsigned int min_ratio; - unsigned int max_ratio, max_prop_frac; - - /* - * Sum of avg_write_bw of wbs with dirty inodes. > 0 if there are - * any dirty wbs, which is depended upon by bdi_has_dirty(). - */ - atomic_long_t tot_write_bandwidth; - - struct bdi_writeback wb; /* the root writeback info for this bdi */ - struct list_head wb_list; /* list of all wbs */ -#ifdef CONFIG_CGROUP_WRITEBACK - struct radix_tree_root cgwb_tree; /* radix tree of active cgroup wbs */ - struct rb_root cgwb_congested_tree; /* their congested states */ - atomic_t usage_cnt; /* counts both cgwbs and cgwb_contested's */ -#else - struct bdi_writeback_congested *wb_congested; -#endif - wait_queue_head_t wb_waitq; - - struct device *dev; - struct device *owner; - - struct timer_list laptop_mode_wb_timer; - -#ifdef CONFIG_DEBUG_FS - struct dentry *debug_dir; - struct dentry *debug_stats; -#endif -}; - -enum { - BLK_RW_ASYNC = 0, - BLK_RW_SYNC = 1, -}; - -void clear_wb_congested(struct bdi_writeback_congested *congested, int sync); -void set_wb_congested(struct bdi_writeback_congested *congested, int sync); - -static inline void clear_bdi_congested(struct backing_dev_info *bdi, int sync) -{ - clear_wb_congested(bdi->wb.congested, sync); -} - -static inline void set_bdi_congested(struct backing_dev_info *bdi, int sync) -{ - set_wb_congested(bdi->wb.congested, sync); -} - -#ifdef CONFIG_CGROUP_WRITEBACK - -/** - * wb_tryget - try to increment a wb's refcount - * @wb: bdi_writeback to get - */ -static inline bool wb_tryget(struct bdi_writeback *wb) -{ - if (wb != &wb->bdi->wb) - return percpu_ref_tryget(&wb->refcnt); - return true; -} - -/** - * wb_get - increment a wb's refcount - * @wb: bdi_writeback to get - */ -static inline void wb_get(struct bdi_writeback *wb) -{ - if (wb != &wb->bdi->wb) - percpu_ref_get(&wb->refcnt); -} - -/** - * wb_put - decrement a wb's refcount - * @wb: bdi_writeback to put - */ -static inline void wb_put(struct bdi_writeback *wb) -{ - if (wb != &wb->bdi->wb) - percpu_ref_put(&wb->refcnt); -} - -/** - * wb_dying - is a wb dying? - * @wb: bdi_writeback of interest - * - * Returns whether @wb is unlinked and being drained. - */ -static inline bool wb_dying(struct bdi_writeback *wb) -{ - return percpu_ref_is_dying(&wb->refcnt); -} - -#else /* CONFIG_CGROUP_WRITEBACK */ - -static inline bool wb_tryget(struct bdi_writeback *wb) -{ - return true; -} - -static inline void wb_get(struct bdi_writeback *wb) -{ -} - -static inline void wb_put(struct bdi_writeback *wb) -{ -} - -static inline bool wb_dying(struct bdi_writeback *wb) -{ - return false; -} - -#endif /* CONFIG_CGROUP_WRITEBACK */ - -#endif /* __LINUX_BACKING_DEV_DEFS_H */ diff --git a/src/linux/include/linux/backing-dev.h b/src/linux/include/linux/backing-dev.h deleted file mode 100644 index 43b93a9..0000000 --- a/src/linux/include/linux/backing-dev.h +++ /dev/null @@ -1,518 +0,0 @@ -/* - * include/linux/backing-dev.h - * - * low-level device information and state which is propagated up through - * to high-level code. - */ - -#ifndef _LINUX_BACKING_DEV_H -#define _LINUX_BACKING_DEV_H - -#include -#include -#include -#include -#include -#include -#include -#include - -int __must_check bdi_init(struct backing_dev_info *bdi); -void bdi_exit(struct backing_dev_info *bdi); - -__printf(3, 4) -int bdi_register(struct backing_dev_info *bdi, struct device *parent, - const char *fmt, ...); -int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev); -int bdi_register_owner(struct backing_dev_info *bdi, struct device *owner); -void bdi_unregister(struct backing_dev_info *bdi); - -int __must_check bdi_setup_and_register(struct backing_dev_info *, char *); -void bdi_destroy(struct backing_dev_info *bdi); - -void wb_start_writeback(struct bdi_writeback *wb, long nr_pages, - bool range_cyclic, enum wb_reason reason); -void wb_start_background_writeback(struct bdi_writeback *wb); -void wb_workfn(struct work_struct *work); -void wb_wakeup_delayed(struct bdi_writeback *wb); - -extern spinlock_t bdi_lock; -extern struct list_head bdi_list; - -extern struct workqueue_struct *bdi_wq; - -static inline bool wb_has_dirty_io(struct bdi_writeback *wb) -{ - return test_bit(WB_has_dirty_io, &wb->state); -} - -static inline bool bdi_has_dirty_io(struct backing_dev_info *bdi) -{ - /* - * @bdi->tot_write_bandwidth is guaranteed to be > 0 if there are - * any dirty wbs. See wb_update_write_bandwidth(). - */ - return atomic_long_read(&bdi->tot_write_bandwidth); -} - -static inline void __add_wb_stat(struct bdi_writeback *wb, - enum wb_stat_item item, s64 amount) -{ - __percpu_counter_add(&wb->stat[item], amount, WB_STAT_BATCH); -} - -static inline void __inc_wb_stat(struct bdi_writeback *wb, - enum wb_stat_item item) -{ - __add_wb_stat(wb, item, 1); -} - -static inline void inc_wb_stat(struct bdi_writeback *wb, enum wb_stat_item item) -{ - unsigned long flags; - - local_irq_save(flags); - __inc_wb_stat(wb, item); - local_irq_restore(flags); -} - -static inline void __dec_wb_stat(struct bdi_writeback *wb, - enum wb_stat_item item) -{ - __add_wb_stat(wb, item, -1); -} - -static inline void dec_wb_stat(struct bdi_writeback *wb, enum wb_stat_item item) -{ - unsigned long flags; - - local_irq_save(flags); - __dec_wb_stat(wb, item); - local_irq_restore(flags); -} - -static inline s64 wb_stat(struct bdi_writeback *wb, enum wb_stat_item item) -{ - return percpu_counter_read_positive(&wb->stat[item]); -} - -static inline s64 __wb_stat_sum(struct bdi_writeback *wb, - enum wb_stat_item item) -{ - return percpu_counter_sum_positive(&wb->stat[item]); -} - -static inline s64 wb_stat_sum(struct bdi_writeback *wb, enum wb_stat_item item) -{ - s64 sum; - unsigned long flags; - - local_irq_save(flags); - sum = __wb_stat_sum(wb, item); - local_irq_restore(flags); - - return sum; -} - -extern void wb_writeout_inc(struct bdi_writeback *wb); - -/* - * maximal error of a stat counter. - */ -static inline unsigned long wb_stat_error(struct bdi_writeback *wb) -{ -#ifdef CONFIG_SMP - return nr_cpu_ids * WB_STAT_BATCH; -#else - return 1; -#endif -} - -int bdi_set_min_ratio(struct backing_dev_info *bdi, unsigned int min_ratio); -int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned int max_ratio); - -/* - * Flags in backing_dev_info::capability - * - * The first three flags control whether dirty pages will contribute to the - * VM's accounting and whether writepages() should be called for dirty pages - * (something that would not, for example, be appropriate for ramfs) - * - * WARNING: these flags are closely related and should not normally be - * used separately. The BDI_CAP_NO_ACCT_AND_WRITEBACK combines these - * three flags into a single convenience macro. - * - * BDI_CAP_NO_ACCT_DIRTY: Dirty pages shouldn't contribute to accounting - * BDI_CAP_NO_WRITEBACK: Don't write pages back - * BDI_CAP_NO_ACCT_WB: Don't automatically account writeback pages - * BDI_CAP_STRICTLIMIT: Keep number of dirty pages below bdi threshold. - * - * BDI_CAP_CGROUP_WRITEBACK: Supports cgroup-aware writeback. - */ -#define BDI_CAP_NO_ACCT_DIRTY 0x00000001 -#define BDI_CAP_NO_WRITEBACK 0x00000002 -#define BDI_CAP_NO_ACCT_WB 0x00000004 -#define BDI_CAP_STABLE_WRITES 0x00000008 -#define BDI_CAP_STRICTLIMIT 0x00000010 -#define BDI_CAP_CGROUP_WRITEBACK 0x00000020 - -#define BDI_CAP_NO_ACCT_AND_WRITEBACK \ - (BDI_CAP_NO_WRITEBACK | BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_ACCT_WB) - -extern struct backing_dev_info noop_backing_dev_info; - -/** - * writeback_in_progress - determine whether there is writeback in progress - * @wb: bdi_writeback of interest - * - * Determine whether there is writeback waiting to be handled against a - * bdi_writeback. - */ -static inline bool writeback_in_progress(struct bdi_writeback *wb) -{ - return test_bit(WB_writeback_running, &wb->state); -} - -static inline struct backing_dev_info *inode_to_bdi(struct inode *inode) -{ - struct super_block *sb; - - if (!inode) - return &noop_backing_dev_info; - - sb = inode->i_sb; -#ifdef CONFIG_BLOCK - if (sb_is_blkdev_sb(sb)) - return blk_get_backing_dev_info(I_BDEV(inode)); -#endif - return sb->s_bdi; -} - -static inline int wb_congested(struct bdi_writeback *wb, int cong_bits) -{ - struct backing_dev_info *bdi = wb->bdi; - - if (bdi->congested_fn) - return bdi->congested_fn(bdi->congested_data, cong_bits); - return wb->congested->state & cong_bits; -} - -long congestion_wait(int sync, long timeout); -long wait_iff_congested(struct pglist_data *pgdat, int sync, long timeout); -int pdflush_proc_obsolete(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); - -static inline bool bdi_cap_stable_pages_required(struct backing_dev_info *bdi) -{ - return bdi->capabilities & BDI_CAP_STABLE_WRITES; -} - -static inline bool bdi_cap_writeback_dirty(struct backing_dev_info *bdi) -{ - return !(bdi->capabilities & BDI_CAP_NO_WRITEBACK); -} - -static inline bool bdi_cap_account_dirty(struct backing_dev_info *bdi) -{ - return !(bdi->capabilities & BDI_CAP_NO_ACCT_DIRTY); -} - -static inline bool bdi_cap_account_writeback(struct backing_dev_info *bdi) -{ - /* Paranoia: BDI_CAP_NO_WRITEBACK implies BDI_CAP_NO_ACCT_WB */ - return !(bdi->capabilities & (BDI_CAP_NO_ACCT_WB | - BDI_CAP_NO_WRITEBACK)); -} - -static inline bool mapping_cap_writeback_dirty(struct address_space *mapping) -{ - return bdi_cap_writeback_dirty(inode_to_bdi(mapping->host)); -} - -static inline bool mapping_cap_account_dirty(struct address_space *mapping) -{ - return bdi_cap_account_dirty(inode_to_bdi(mapping->host)); -} - -static inline int bdi_sched_wait(void *word) -{ - schedule(); - return 0; -} - -#ifdef CONFIG_CGROUP_WRITEBACK - -struct bdi_writeback_congested * -wb_congested_get_create(struct backing_dev_info *bdi, int blkcg_id, gfp_t gfp); -void wb_congested_put(struct bdi_writeback_congested *congested); -struct bdi_writeback *wb_get_create(struct backing_dev_info *bdi, - struct cgroup_subsys_state *memcg_css, - gfp_t gfp); -void wb_memcg_offline(struct mem_cgroup *memcg); -void wb_blkcg_offline(struct blkcg *blkcg); -int inode_congested(struct inode *inode, int cong_bits); - -/** - * inode_cgwb_enabled - test whether cgroup writeback is enabled on an inode - * @inode: inode of interest - * - * cgroup writeback requires support from both the bdi and filesystem. - * Also, both memcg and iocg have to be on the default hierarchy. Test - * whether all conditions are met. - * - * Note that the test result may change dynamically on the same inode - * depending on how memcg and iocg are configured. - */ -static inline bool inode_cgwb_enabled(struct inode *inode) -{ - struct backing_dev_info *bdi = inode_to_bdi(inode); - - return cgroup_subsys_on_dfl(memory_cgrp_subsys) && - cgroup_subsys_on_dfl(io_cgrp_subsys) && - bdi_cap_account_dirty(bdi) && - (bdi->capabilities & BDI_CAP_CGROUP_WRITEBACK) && - (inode->i_sb->s_iflags & SB_I_CGROUPWB); -} - -/** - * wb_find_current - find wb for %current on a bdi - * @bdi: bdi of interest - * - * Find the wb of @bdi which matches both the memcg and blkcg of %current. - * Must be called under rcu_read_lock() which protects the returend wb. - * NULL if not found. - */ -static inline struct bdi_writeback *wb_find_current(struct backing_dev_info *bdi) -{ - struct cgroup_subsys_state *memcg_css; - struct bdi_writeback *wb; - - memcg_css = task_css(current, memory_cgrp_id); - if (!memcg_css->parent) - return &bdi->wb; - - wb = radix_tree_lookup(&bdi->cgwb_tree, memcg_css->id); - - /* - * %current's blkcg equals the effective blkcg of its memcg. No - * need to use the relatively expensive cgroup_get_e_css(). - */ - if (likely(wb && wb->blkcg_css == task_css(current, io_cgrp_id))) - return wb; - return NULL; -} - -/** - * wb_get_create_current - get or create wb for %current on a bdi - * @bdi: bdi of interest - * @gfp: allocation mask - * - * Equivalent to wb_get_create() on %current's memcg. This function is - * called from a relatively hot path and optimizes the common cases using - * wb_find_current(). - */ -static inline struct bdi_writeback * -wb_get_create_current(struct backing_dev_info *bdi, gfp_t gfp) -{ - struct bdi_writeback *wb; - - rcu_read_lock(); - wb = wb_find_current(bdi); - if (wb && unlikely(!wb_tryget(wb))) - wb = NULL; - rcu_read_unlock(); - - if (unlikely(!wb)) { - struct cgroup_subsys_state *memcg_css; - - memcg_css = task_get_css(current, memory_cgrp_id); - wb = wb_get_create(bdi, memcg_css, gfp); - css_put(memcg_css); - } - return wb; -} - -/** - * inode_to_wb_is_valid - test whether an inode has a wb associated - * @inode: inode of interest - * - * Returns %true if @inode has a wb associated. May be called without any - * locking. - */ -static inline bool inode_to_wb_is_valid(struct inode *inode) -{ - return inode->i_wb; -} - -/** - * inode_to_wb - determine the wb of an inode - * @inode: inode of interest - * - * Returns the wb @inode is currently associated with. The caller must be - * holding either @inode->i_lock, @inode->i_mapping->tree_lock, or the - * associated wb's list_lock. - */ -static inline struct bdi_writeback *inode_to_wb(struct inode *inode) -{ -#ifdef CONFIG_LOCKDEP - WARN_ON_ONCE(debug_locks && - (!lockdep_is_held(&inode->i_lock) && - !lockdep_is_held(&inode->i_mapping->tree_lock) && - !lockdep_is_held(&inode->i_wb->list_lock))); -#endif - return inode->i_wb; -} - -/** - * unlocked_inode_to_wb_begin - begin unlocked inode wb access transaction - * @inode: target inode - * @lockedp: temp bool output param, to be passed to the end function - * - * The caller wants to access the wb associated with @inode but isn't - * holding inode->i_lock, mapping->tree_lock or wb->list_lock. This - * function determines the wb associated with @inode and ensures that the - * association doesn't change until the transaction is finished with - * unlocked_inode_to_wb_end(). - * - * The caller must call unlocked_inode_to_wb_end() with *@lockdep - * afterwards and can't sleep during transaction. IRQ may or may not be - * disabled on return. - */ -static inline struct bdi_writeback * -unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp) -{ - rcu_read_lock(); - - /* - * Paired with store_release in inode_switch_wb_work_fn() and - * ensures that we see the new wb if we see cleared I_WB_SWITCH. - */ - *lockedp = smp_load_acquire(&inode->i_state) & I_WB_SWITCH; - - if (unlikely(*lockedp)) - spin_lock_irq(&inode->i_mapping->tree_lock); - - /* - * Protected by either !I_WB_SWITCH + rcu_read_lock() or tree_lock. - * inode_to_wb() will bark. Deref directly. - */ - return inode->i_wb; -} - -/** - * unlocked_inode_to_wb_end - end inode wb access transaction - * @inode: target inode - * @locked: *@lockedp from unlocked_inode_to_wb_begin() - */ -static inline void unlocked_inode_to_wb_end(struct inode *inode, bool locked) -{ - if (unlikely(locked)) - spin_unlock_irq(&inode->i_mapping->tree_lock); - - rcu_read_unlock(); -} - -#else /* CONFIG_CGROUP_WRITEBACK */ - -static inline bool inode_cgwb_enabled(struct inode *inode) -{ - return false; -} - -static inline struct bdi_writeback_congested * -wb_congested_get_create(struct backing_dev_info *bdi, int blkcg_id, gfp_t gfp) -{ - atomic_inc(&bdi->wb_congested->refcnt); - return bdi->wb_congested; -} - -static inline void wb_congested_put(struct bdi_writeback_congested *congested) -{ - if (atomic_dec_and_test(&congested->refcnt)) - kfree(congested); -} - -static inline struct bdi_writeback *wb_find_current(struct backing_dev_info *bdi) -{ - return &bdi->wb; -} - -static inline struct bdi_writeback * -wb_get_create_current(struct backing_dev_info *bdi, gfp_t gfp) -{ - return &bdi->wb; -} - -static inline bool inode_to_wb_is_valid(struct inode *inode) -{ - return true; -} - -static inline struct bdi_writeback *inode_to_wb(struct inode *inode) -{ - return &inode_to_bdi(inode)->wb; -} - -static inline struct bdi_writeback * -unlocked_inode_to_wb_begin(struct inode *inode, bool *lockedp) -{ - return inode_to_wb(inode); -} - -static inline void unlocked_inode_to_wb_end(struct inode *inode, bool locked) -{ -} - -static inline void wb_memcg_offline(struct mem_cgroup *memcg) -{ -} - -static inline void wb_blkcg_offline(struct blkcg *blkcg) -{ -} - -static inline int inode_congested(struct inode *inode, int cong_bits) -{ - return wb_congested(&inode_to_bdi(inode)->wb, cong_bits); -} - -#endif /* CONFIG_CGROUP_WRITEBACK */ - -static inline int inode_read_congested(struct inode *inode) -{ - return inode_congested(inode, 1 << WB_sync_congested); -} - -static inline int inode_write_congested(struct inode *inode) -{ - return inode_congested(inode, 1 << WB_async_congested); -} - -static inline int inode_rw_congested(struct inode *inode) -{ - return inode_congested(inode, (1 << WB_sync_congested) | - (1 << WB_async_congested)); -} - -static inline int bdi_congested(struct backing_dev_info *bdi, int cong_bits) -{ - return wb_congested(&bdi->wb, cong_bits); -} - -static inline int bdi_read_congested(struct backing_dev_info *bdi) -{ - return bdi_congested(bdi, 1 << WB_sync_congested); -} - -static inline int bdi_write_congested(struct backing_dev_info *bdi) -{ - return bdi_congested(bdi, 1 << WB_async_congested); -} - -static inline int bdi_rw_congested(struct backing_dev_info *bdi) -{ - return bdi_congested(bdi, (1 << WB_sync_congested) | - (1 << WB_async_congested)); -} - -#endif /* _LINUX_BACKING_DEV_H */ diff --git a/src/linux/include/linux/badblocks.h b/src/linux/include/linux/badblocks.h deleted file mode 100644 index c3bdf8c..0000000 --- a/src/linux/include/linux/badblocks.h +++ /dev/null @@ -1,65 +0,0 @@ -#ifndef _LINUX_BADBLOCKS_H -#define _LINUX_BADBLOCKS_H - -#include -#include -#include -#include -#include - -#define BB_LEN_MASK (0x00000000000001FFULL) -#define BB_OFFSET_MASK (0x7FFFFFFFFFFFFE00ULL) -#define BB_ACK_MASK (0x8000000000000000ULL) -#define BB_MAX_LEN 512 -#define BB_OFFSET(x) (((x) & BB_OFFSET_MASK) >> 9) -#define BB_LEN(x) (((x) & BB_LEN_MASK) + 1) -#define BB_ACK(x) (!!((x) & BB_ACK_MASK)) -#define BB_MAKE(a, l, ack) (((a)<<9) | ((l)-1) | ((u64)(!!(ack)) << 63)) - -/* Bad block numbers are stored sorted in a single page. - * 64bits is used for each block or extent. - * 54 bits are sector number, 9 bits are extent size, - * 1 bit is an 'acknowledged' flag. - */ -#define MAX_BADBLOCKS (PAGE_SIZE/8) - -struct badblocks { - struct device *dev; /* set by devm_init_badblocks */ - int count; /* count of bad blocks */ - int unacked_exist; /* there probably are unacknowledged - * bad blocks. This is only cleared - * when a read discovers none - */ - int shift; /* shift from sectors to block size - * a -ve shift means badblocks are - * disabled.*/ - u64 *page; /* badblock list */ - int changed; - seqlock_t lock; - sector_t sector; - sector_t size; /* in sectors */ -}; - -int badblocks_check(struct badblocks *bb, sector_t s, int sectors, - sector_t *first_bad, int *bad_sectors); -int badblocks_set(struct badblocks *bb, sector_t s, int sectors, - int acknowledged); -int badblocks_clear(struct badblocks *bb, sector_t s, int sectors); -void ack_all_badblocks(struct badblocks *bb); -ssize_t badblocks_show(struct badblocks *bb, char *page, int unack); -ssize_t badblocks_store(struct badblocks *bb, const char *page, size_t len, - int unack); -int badblocks_init(struct badblocks *bb, int enable); -void badblocks_exit(struct badblocks *bb); -struct device; -int devm_init_badblocks(struct device *dev, struct badblocks *bb); -static inline void devm_exit_badblocks(struct device *dev, struct badblocks *bb) -{ - if (bb->dev != dev) { - dev_WARN_ONCE(dev, 1, "%s: badblocks instance not associated\n", - __func__); - return; - } - badblocks_exit(bb); -} -#endif diff --git a/src/linux/include/linux/balloon_compaction.h b/src/linux/include/linux/balloon_compaction.h deleted file mode 100644 index 79542b2..0000000 --- a/src/linux/include/linux/balloon_compaction.h +++ /dev/null @@ -1,195 +0,0 @@ -/* - * include/linux/balloon_compaction.h - * - * Common interface definitions for making balloon pages movable by compaction. - * - * Despite being perfectly possible to perform ballooned pages migration, they - * make a special corner case to compaction scans because balloon pages are not - * enlisted at any LRU list like the other pages we do compact / migrate. - * - * As the page isolation scanning step a compaction thread does is a lockless - * procedure (from a page standpoint), it might bring some racy situations while - * performing balloon page compaction. In order to sort out these racy scenarios - * and safely perform balloon's page compaction and migration we must, always, - * ensure following these three simple rules: - * - * i. when updating a balloon's page ->mapping element, strictly do it under - * the following lock order, independently of the far superior - * locking scheme (lru_lock, balloon_lock): - * +-page_lock(page); - * +--spin_lock_irq(&b_dev_info->pages_lock); - * ... page->mapping updates here ... - * - * ii. before isolating or dequeueing a balloon page from the balloon device - * pages list, the page reference counter must be raised by one and the - * extra refcount must be dropped when the page is enqueued back into - * the balloon device page list, thus a balloon page keeps its reference - * counter raised only while it is under our special handling; - * - * iii. after the lockless scan step have selected a potential balloon page for - * isolation, re-test the PageBalloon mark and the PagePrivate flag - * under the proper page lock, to ensure isolating a valid balloon page - * (not yet isolated, nor under release procedure) - * - * iv. isolation or dequeueing procedure must clear PagePrivate flag under - * page lock together with removing page from balloon device page list. - * - * The functions provided by this interface are placed to help on coping with - * the aforementioned balloon page corner case, as well as to ensure the simple - * set of exposed rules are satisfied while we are dealing with balloon pages - * compaction / migration. - * - * Copyright (C) 2012, Red Hat, Inc. Rafael Aquini - */ -#ifndef _LINUX_BALLOON_COMPACTION_H -#define _LINUX_BALLOON_COMPACTION_H -#include -#include -#include -#include -#include -#include - -/* - * Balloon device information descriptor. - * This struct is used to allow the common balloon compaction interface - * procedures to find the proper balloon device holding memory pages they'll - * have to cope for page compaction / migration, as well as it serves the - * balloon driver as a page book-keeper for its registered balloon devices. - */ -struct balloon_dev_info { - unsigned long isolated_pages; /* # of isolated pages for migration */ - spinlock_t pages_lock; /* Protection to pages list */ - struct list_head pages; /* Pages enqueued & handled to Host */ - int (*migratepage)(struct balloon_dev_info *, struct page *newpage, - struct page *page, enum migrate_mode mode); - struct inode *inode; -}; - -extern struct page *balloon_page_enqueue(struct balloon_dev_info *b_dev_info); -extern struct page *balloon_page_dequeue(struct balloon_dev_info *b_dev_info); - -static inline void balloon_devinfo_init(struct balloon_dev_info *balloon) -{ - balloon->isolated_pages = 0; - spin_lock_init(&balloon->pages_lock); - INIT_LIST_HEAD(&balloon->pages); - balloon->migratepage = NULL; - balloon->inode = NULL; -} - -#ifdef CONFIG_BALLOON_COMPACTION -extern const struct address_space_operations balloon_aops; -extern bool balloon_page_isolate(struct page *page, - isolate_mode_t mode); -extern void balloon_page_putback(struct page *page); -extern int balloon_page_migrate(struct address_space *mapping, - struct page *newpage, - struct page *page, enum migrate_mode mode); - -/* - * balloon_page_insert - insert a page into the balloon's page list and make - * the page->private assignment accordingly. - * @balloon : pointer to balloon device - * @page : page to be assigned as a 'balloon page' - * - * Caller must ensure the page is locked and the spin_lock protecting balloon - * pages list is held before inserting a page into the balloon device. - */ -static inline void balloon_page_insert(struct balloon_dev_info *balloon, - struct page *page) -{ - __SetPageBalloon(page); - __SetPageMovable(page, balloon->inode->i_mapping); - set_page_private(page, (unsigned long)balloon); - list_add(&page->lru, &balloon->pages); -} - -/* - * balloon_page_delete - delete a page from balloon's page list and clear - * the page->private assignement accordingly. - * @page : page to be released from balloon's page list - * - * Caller must ensure the page is locked and the spin_lock protecting balloon - * pages list is held before deleting a page from the balloon device. - */ -static inline void balloon_page_delete(struct page *page) -{ - __ClearPageBalloon(page); - __ClearPageMovable(page); - set_page_private(page, 0); - /* - * No touch page.lru field once @page has been isolated - * because VM is using the field. - */ - if (!PageIsolated(page)) - list_del(&page->lru); -} - -/* - * balloon_page_device - get the b_dev_info descriptor for the balloon device - * that enqueues the given page. - */ -static inline struct balloon_dev_info *balloon_page_device(struct page *page) -{ - return (struct balloon_dev_info *)page_private(page); -} - -static inline gfp_t balloon_mapping_gfp_mask(void) -{ - return GFP_HIGHUSER_MOVABLE; -} - -#else /* !CONFIG_BALLOON_COMPACTION */ - -static inline void balloon_page_insert(struct balloon_dev_info *balloon, - struct page *page) -{ - __SetPageBalloon(page); - list_add(&page->lru, &balloon->pages); -} - -static inline void balloon_page_delete(struct page *page) -{ - __ClearPageBalloon(page); - list_del(&page->lru); -} - -static inline bool __is_movable_balloon_page(struct page *page) -{ - return false; -} - -static inline bool balloon_page_movable(struct page *page) -{ - return false; -} - -static inline bool isolated_balloon_page(struct page *page) -{ - return false; -} - -static inline bool balloon_page_isolate(struct page *page) -{ - return false; -} - -static inline void balloon_page_putback(struct page *page) -{ - return; -} - -static inline int balloon_page_migrate(struct page *newpage, - struct page *page, enum migrate_mode mode) -{ - return 0; -} - -static inline gfp_t balloon_mapping_gfp_mask(void) -{ - return GFP_HIGHUSER; -} - -#endif /* CONFIG_BALLOON_COMPACTION */ -#endif /* _LINUX_BALLOON_COMPACTION_H */ diff --git a/src/linux/include/linux/bcd.h b/src/linux/include/linux/bcd.h deleted file mode 100644 index 18fff11..0000000 --- a/src/linux/include/linux/bcd.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _BCD_H -#define _BCD_H - -#include - -#define bcd2bin(x) \ - (__builtin_constant_p((u8 )(x)) ? \ - const_bcd2bin(x) : \ - _bcd2bin(x)) - -#define bin2bcd(x) \ - (__builtin_constant_p((u8 )(x)) ? \ - const_bin2bcd(x) : \ - _bin2bcd(x)) - -#define const_bcd2bin(x) (((x) & 0x0f) + ((x) >> 4) * 10) -#define const_bin2bcd(x) ((((x) / 10) << 4) + (x) % 10) - -unsigned _bcd2bin(unsigned char val) __attribute_const__; -unsigned char _bin2bcd(unsigned val) __attribute_const__; - -#endif /* _BCD_H */ diff --git a/src/linux/include/linux/binfmts.h b/src/linux/include/linux/binfmts.h deleted file mode 100644 index 1303b57..0000000 --- a/src/linux/include/linux/binfmts.h +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef _LINUX_BINFMTS_H -#define _LINUX_BINFMTS_H - -#include -#include -#include -#include - -#define CORENAME_MAX_SIZE 128 - -/* - * This structure is used to hold the arguments that are used when loading binaries. - */ -struct linux_binprm { - char buf[BINPRM_BUF_SIZE]; -#ifdef CONFIG_MMU - struct vm_area_struct *vma; - unsigned long vma_pages; -#else -# define MAX_ARG_PAGES 32 - struct page *page[MAX_ARG_PAGES]; -#endif - struct mm_struct *mm; - unsigned long p; /* current top of mem */ - unsigned int - cred_prepared:1,/* true if creds already prepared (multiple - * preps happen for interpreters) */ - cap_effective:1;/* true if has elevated effective capabilities, - * false if not; except for init which inherits - * its parent's caps anyway */ -#ifdef __alpha__ - unsigned int taso:1; -#endif - unsigned int recursion_depth; /* only for search_binary_handler() */ - struct file * file; - struct cred *cred; /* new credentials */ - int unsafe; /* how unsafe this exec is (mask of LSM_UNSAFE_*) */ - unsigned int per_clear; /* bits to clear in current->personality */ - int argc, envc; - const char * filename; /* Name of binary as seen by procps */ - const char * interp; /* Name of the binary really executed. Most - of the time same as filename, but could be - different for binfmt_{misc,script} */ - unsigned interp_flags; - unsigned interp_data; - unsigned long loader, exec; -}; - -#define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0 -#define BINPRM_FLAGS_ENFORCE_NONDUMP (1 << BINPRM_FLAGS_ENFORCE_NONDUMP_BIT) - -/* fd of the binary should be passed to the interpreter */ -#define BINPRM_FLAGS_EXECFD_BIT 1 -#define BINPRM_FLAGS_EXECFD (1 << BINPRM_FLAGS_EXECFD_BIT) - -/* filename of the binary will be inaccessible after exec */ -#define BINPRM_FLAGS_PATH_INACCESSIBLE_BIT 2 -#define BINPRM_FLAGS_PATH_INACCESSIBLE (1 << BINPRM_FLAGS_PATH_INACCESSIBLE_BIT) - -/* Function parameter for binfmt->coredump */ -struct coredump_params { - const siginfo_t *siginfo; - struct pt_regs *regs; - struct file *file; - unsigned long limit; - unsigned long mm_flags; - loff_t written; - loff_t pos; -}; - -/* - * This structure defines the functions that are used to load the binary formats that - * linux accepts. - */ -struct linux_binfmt { - struct list_head lh; - struct module *module; - int (*load_binary)(struct linux_binprm *); - int (*load_shlib)(struct file *); - int (*core_dump)(struct coredump_params *cprm); - unsigned long min_coredump; /* minimal dump size */ -}; - -extern void __register_binfmt(struct linux_binfmt *fmt, int insert); - -/* Registration of default binfmt handlers */ -static inline void register_binfmt(struct linux_binfmt *fmt) -{ - __register_binfmt(fmt, 0); -} -/* Same as above, but adds a new binfmt at the top of the list */ -static inline void insert_binfmt(struct linux_binfmt *fmt) -{ - __register_binfmt(fmt, 1); -} - -extern void unregister_binfmt(struct linux_binfmt *); - -extern int prepare_binprm(struct linux_binprm *); -extern int __must_check remove_arg_zero(struct linux_binprm *); -extern int search_binary_handler(struct linux_binprm *); -extern int flush_old_exec(struct linux_binprm * bprm); -extern void setup_new_exec(struct linux_binprm * bprm); -extern void would_dump(struct linux_binprm *, struct file *); - -extern int suid_dumpable; - -/* Stack area protections */ -#define EXSTACK_DEFAULT 0 /* Whatever the arch defaults to */ -#define EXSTACK_DISABLE_X 1 /* Disable executable stacks */ -#define EXSTACK_ENABLE_X 2 /* Enable executable stacks */ - -extern int setup_arg_pages(struct linux_binprm * bprm, - unsigned long stack_top, - int executable_stack); -extern int transfer_args_to_stack(struct linux_binprm *bprm, - unsigned long *sp_location); -extern int bprm_change_interp(char *interp, struct linux_binprm *bprm); -extern int copy_strings_kernel(int argc, const char *const *argv, - struct linux_binprm *bprm); -extern int prepare_bprm_creds(struct linux_binprm *bprm); -extern void install_exec_creds(struct linux_binprm *bprm); -extern void set_binfmt(struct linux_binfmt *new); -extern ssize_t read_code(struct file *, unsigned long, loff_t, size_t); - -#endif /* _LINUX_BINFMTS_H */ diff --git a/src/linux/include/linux/bio.h b/src/linux/include/linux/bio.h deleted file mode 100644 index 97cb48f..0000000 --- a/src/linux/include/linux/bio.h +++ /dev/null @@ -1,805 +0,0 @@ -/* - * Copyright (C) 2001 Jens Axboe - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public Licens - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- - */ -#ifndef __LINUX_BIO_H -#define __LINUX_BIO_H - -#include -#include -#include -#include - -#ifdef CONFIG_BLOCK - -#include - -/* struct bio, bio_vec and BIO_* flags are defined in blk_types.h */ -#include - -#define BIO_DEBUG - -#ifdef BIO_DEBUG -#define BIO_BUG_ON BUG_ON -#else -#define BIO_BUG_ON -#endif - -#define BIO_MAX_PAGES 256 - -#define bio_prio(bio) (bio)->bi_ioprio -#define bio_set_prio(bio, prio) ((bio)->bi_ioprio = prio) - -#define bio_iter_iovec(bio, iter) \ - bvec_iter_bvec((bio)->bi_io_vec, (iter)) - -#define bio_iter_page(bio, iter) \ - bvec_iter_page((bio)->bi_io_vec, (iter)) -#define bio_iter_len(bio, iter) \ - bvec_iter_len((bio)->bi_io_vec, (iter)) -#define bio_iter_offset(bio, iter) \ - bvec_iter_offset((bio)->bi_io_vec, (iter)) - -#define bio_page(bio) bio_iter_page((bio), (bio)->bi_iter) -#define bio_offset(bio) bio_iter_offset((bio), (bio)->bi_iter) -#define bio_iovec(bio) bio_iter_iovec((bio), (bio)->bi_iter) - -#define bio_multiple_segments(bio) \ - ((bio)->bi_iter.bi_size != bio_iovec(bio).bv_len) -#define bio_sectors(bio) ((bio)->bi_iter.bi_size >> 9) -#define bio_end_sector(bio) ((bio)->bi_iter.bi_sector + bio_sectors((bio))) - -/* - * Check whether this bio carries any data or not. A NULL bio is allowed. - */ -static inline bool bio_has_data(struct bio *bio) -{ - if (bio && - bio->bi_iter.bi_size && - bio_op(bio) != REQ_OP_DISCARD && - bio_op(bio) != REQ_OP_SECURE_ERASE) - return true; - - return false; -} - -static inline bool bio_no_advance_iter(struct bio *bio) -{ - return bio_op(bio) == REQ_OP_DISCARD || - bio_op(bio) == REQ_OP_SECURE_ERASE || - bio_op(bio) == REQ_OP_WRITE_SAME; -} - -static inline bool bio_is_rw(struct bio *bio) -{ - if (!bio_has_data(bio)) - return false; - - if (bio_no_advance_iter(bio)) - return false; - - return true; -} - -static inline bool bio_mergeable(struct bio *bio) -{ - if (bio->bi_opf & REQ_NOMERGE_FLAGS) - return false; - - return true; -} - -static inline unsigned int bio_cur_bytes(struct bio *bio) -{ - if (bio_has_data(bio)) - return bio_iovec(bio).bv_len; - else /* dataless requests such as discard */ - return bio->bi_iter.bi_size; -} - -static inline void *bio_data(struct bio *bio) -{ - if (bio_has_data(bio)) - return page_address(bio_page(bio)) + bio_offset(bio); - - return NULL; -} - -/* - * will die - */ -#define bio_to_phys(bio) (page_to_phys(bio_page((bio))) + (unsigned long) bio_offset((bio))) -#define bvec_to_phys(bv) (page_to_phys((bv)->bv_page) + (unsigned long) (bv)->bv_offset) - -/* - * queues that have highmem support enabled may still need to revert to - * PIO transfers occasionally and thus map high pages temporarily. For - * permanent PIO fall back, user is probably better off disabling highmem - * I/O completely on that queue (see ide-dma for example) - */ -#define __bio_kmap_atomic(bio, iter) \ - (kmap_atomic(bio_iter_iovec((bio), (iter)).bv_page) + \ - bio_iter_iovec((bio), (iter)).bv_offset) - -#define __bio_kunmap_atomic(addr) kunmap_atomic(addr) - -/* - * merge helpers etc - */ - -/* Default implementation of BIOVEC_PHYS_MERGEABLE */ -#define __BIOVEC_PHYS_MERGEABLE(vec1, vec2) \ - ((bvec_to_phys((vec1)) + (vec1)->bv_len) == bvec_to_phys((vec2))) - -/* - * allow arch override, for eg virtualized architectures (put in asm/io.h) - */ -#ifndef BIOVEC_PHYS_MERGEABLE -#define BIOVEC_PHYS_MERGEABLE(vec1, vec2) \ - __BIOVEC_PHYS_MERGEABLE(vec1, vec2) -#endif - -#define __BIO_SEG_BOUNDARY(addr1, addr2, mask) \ - (((addr1) | (mask)) == (((addr2) - 1) | (mask))) -#define BIOVEC_SEG_BOUNDARY(q, b1, b2) \ - __BIO_SEG_BOUNDARY(bvec_to_phys((b1)), bvec_to_phys((b2)) + (b2)->bv_len, queue_segment_boundary((q))) - -/* - * drivers should _never_ use the all version - the bio may have been split - * before it got to the driver and the driver won't own all of it - */ -#define bio_for_each_segment_all(bvl, bio, i) \ - for (i = 0, bvl = (bio)->bi_io_vec; i < (bio)->bi_vcnt; i++, bvl++) - -static inline void bio_advance_iter(struct bio *bio, struct bvec_iter *iter, - unsigned bytes) -{ - iter->bi_sector += bytes >> 9; - - if (bio_no_advance_iter(bio)) - iter->bi_size -= bytes; - else - bvec_iter_advance(bio->bi_io_vec, iter, bytes); -} - -#define __bio_for_each_segment(bvl, bio, iter, start) \ - for (iter = (start); \ - (iter).bi_size && \ - ((bvl = bio_iter_iovec((bio), (iter))), 1); \ - bio_advance_iter((bio), &(iter), (bvl).bv_len)) - -#define bio_for_each_segment(bvl, bio, iter) \ - __bio_for_each_segment(bvl, bio, iter, (bio)->bi_iter) - -#define bio_iter_last(bvec, iter) ((iter).bi_size == (bvec).bv_len) - -static inline unsigned bio_segments(struct bio *bio) -{ - unsigned segs = 0; - struct bio_vec bv; - struct bvec_iter iter; - - /* - * We special case discard/write same, because they interpret bi_size - * differently: - */ - - if (bio_op(bio) == REQ_OP_DISCARD) - return 1; - - if (bio_op(bio) == REQ_OP_SECURE_ERASE) - return 1; - - if (bio_op(bio) == REQ_OP_WRITE_SAME) - return 1; - - bio_for_each_segment(bv, bio, iter) - segs++; - - return segs; -} - -/* - * get a reference to a bio, so it won't disappear. the intended use is - * something like: - * - * bio_get(bio); - * submit_bio(rw, bio); - * if (bio->bi_flags ...) - * do_something - * bio_put(bio); - * - * without the bio_get(), it could potentially complete I/O before submit_bio - * returns. and then bio would be freed memory when if (bio->bi_flags ...) - * runs - */ -static inline void bio_get(struct bio *bio) -{ - bio->bi_flags |= (1 << BIO_REFFED); - smp_mb__before_atomic(); - atomic_inc(&bio->__bi_cnt); -} - -static inline void bio_cnt_set(struct bio *bio, unsigned int count) -{ - if (count != 1) { - bio->bi_flags |= (1 << BIO_REFFED); - smp_mb__before_atomic(); - } - atomic_set(&bio->__bi_cnt, count); -} - -static inline bool bio_flagged(struct bio *bio, unsigned int bit) -{ - return (bio->bi_flags & (1U << bit)) != 0; -} - -static inline void bio_set_flag(struct bio *bio, unsigned int bit) -{ - bio->bi_flags |= (1U << bit); -} - -static inline void bio_clear_flag(struct bio *bio, unsigned int bit) -{ - bio->bi_flags &= ~(1U << bit); -} - -static inline void bio_get_first_bvec(struct bio *bio, struct bio_vec *bv) -{ - *bv = bio_iovec(bio); -} - -static inline void bio_get_last_bvec(struct bio *bio, struct bio_vec *bv) -{ - struct bvec_iter iter = bio->bi_iter; - int idx; - - if (unlikely(!bio_multiple_segments(bio))) { - *bv = bio_iovec(bio); - return; - } - - bio_advance_iter(bio, &iter, iter.bi_size); - - if (!iter.bi_bvec_done) - idx = iter.bi_idx - 1; - else /* in the middle of bvec */ - idx = iter.bi_idx; - - *bv = bio->bi_io_vec[idx]; - - /* - * iter.bi_bvec_done records actual length of the last bvec - * if this bio ends in the middle of one io vector - */ - if (iter.bi_bvec_done) - bv->bv_len = iter.bi_bvec_done; -} - -enum bip_flags { - BIP_BLOCK_INTEGRITY = 1 << 0, /* block layer owns integrity data */ - BIP_MAPPED_INTEGRITY = 1 << 1, /* ref tag has been remapped */ - BIP_CTRL_NOCHECK = 1 << 2, /* disable HBA integrity checking */ - BIP_DISK_NOCHECK = 1 << 3, /* disable disk integrity checking */ - BIP_IP_CHECKSUM = 1 << 4, /* IP checksum */ -}; - -/* - * bio integrity payload - */ -struct bio_integrity_payload { - struct bio *bip_bio; /* parent bio */ - - struct bvec_iter bip_iter; - - bio_end_io_t *bip_end_io; /* saved I/O completion fn */ - - unsigned short bip_slab; /* slab the bip came from */ - unsigned short bip_vcnt; /* # of integrity bio_vecs */ - unsigned short bip_max_vcnt; /* integrity bio_vec slots */ - unsigned short bip_flags; /* control flags */ - - struct work_struct bip_work; /* I/O completion */ - - struct bio_vec *bip_vec; - struct bio_vec bip_inline_vecs[0];/* embedded bvec array */ -}; - -#if defined(CONFIG_BLK_DEV_INTEGRITY) - -static inline struct bio_integrity_payload *bio_integrity(struct bio *bio) -{ - if (bio->bi_opf & REQ_INTEGRITY) - return bio->bi_integrity; - - return NULL; -} - -static inline bool bio_integrity_flagged(struct bio *bio, enum bip_flags flag) -{ - struct bio_integrity_payload *bip = bio_integrity(bio); - - if (bip) - return bip->bip_flags & flag; - - return false; -} - -static inline sector_t bip_get_seed(struct bio_integrity_payload *bip) -{ - return bip->bip_iter.bi_sector; -} - -static inline void bip_set_seed(struct bio_integrity_payload *bip, - sector_t seed) -{ - bip->bip_iter.bi_sector = seed; -} - -#endif /* CONFIG_BLK_DEV_INTEGRITY */ - -extern void bio_trim(struct bio *bio, int offset, int size); -extern struct bio *bio_split(struct bio *bio, int sectors, - gfp_t gfp, struct bio_set *bs); - -/** - * bio_next_split - get next @sectors from a bio, splitting if necessary - * @bio: bio to split - * @sectors: number of sectors to split from the front of @bio - * @gfp: gfp mask - * @bs: bio set to allocate from - * - * Returns a bio representing the next @sectors of @bio - if the bio is smaller - * than @sectors, returns the original bio unchanged. - */ -static inline struct bio *bio_next_split(struct bio *bio, int sectors, - gfp_t gfp, struct bio_set *bs) -{ - if (sectors >= bio_sectors(bio)) - return bio; - - return bio_split(bio, sectors, gfp, bs); -} - -extern struct bio_set *bioset_create(unsigned int, unsigned int); -extern struct bio_set *bioset_create_nobvec(unsigned int, unsigned int); -extern void bioset_free(struct bio_set *); -extern mempool_t *biovec_create_pool(int pool_entries); - -extern struct bio *bio_alloc_bioset(gfp_t, int, struct bio_set *); -extern void bio_put(struct bio *); - -extern void __bio_clone_fast(struct bio *, struct bio *); -extern struct bio *bio_clone_fast(struct bio *, gfp_t, struct bio_set *); -extern struct bio *bio_clone_bioset(struct bio *, gfp_t, struct bio_set *bs); - -extern struct bio_set *fs_bio_set; - -static inline struct bio *bio_alloc(gfp_t gfp_mask, unsigned int nr_iovecs) -{ - return bio_alloc_bioset(gfp_mask, nr_iovecs, fs_bio_set); -} - -static inline struct bio *bio_clone(struct bio *bio, gfp_t gfp_mask) -{ - return bio_clone_bioset(bio, gfp_mask, fs_bio_set); -} - -static inline struct bio *bio_kmalloc(gfp_t gfp_mask, unsigned int nr_iovecs) -{ - return bio_alloc_bioset(gfp_mask, nr_iovecs, NULL); -} - -static inline struct bio *bio_clone_kmalloc(struct bio *bio, gfp_t gfp_mask) -{ - return bio_clone_bioset(bio, gfp_mask, NULL); - -} - -extern void bio_endio(struct bio *); - -static inline void bio_io_error(struct bio *bio) -{ - bio->bi_error = -EIO; - bio_endio(bio); -} - -struct request_queue; -extern int bio_phys_segments(struct request_queue *, struct bio *); - -extern int submit_bio_wait(struct bio *bio); -extern void bio_advance(struct bio *, unsigned); - -extern void bio_init(struct bio *); -extern void bio_reset(struct bio *); -void bio_chain(struct bio *, struct bio *); - -extern int bio_add_page(struct bio *, struct page *, unsigned int,unsigned int); -extern int bio_add_pc_page(struct request_queue *, struct bio *, struct page *, - unsigned int, unsigned int); -struct rq_map_data; -extern struct bio *bio_map_user_iov(struct request_queue *, - const struct iov_iter *, gfp_t); -extern void bio_unmap_user(struct bio *); -extern struct bio *bio_map_kern(struct request_queue *, void *, unsigned int, - gfp_t); -extern struct bio *bio_copy_kern(struct request_queue *, void *, unsigned int, - gfp_t, int); -extern void bio_set_pages_dirty(struct bio *bio); -extern void bio_check_pages_dirty(struct bio *bio); - -void generic_start_io_acct(int rw, unsigned long sectors, - struct hd_struct *part); -void generic_end_io_acct(int rw, struct hd_struct *part, - unsigned long start_time); - -#ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE -# error "You should define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE for your platform" -#endif -#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE -extern void bio_flush_dcache_pages(struct bio *bi); -#else -static inline void bio_flush_dcache_pages(struct bio *bi) -{ -} -#endif - -extern void bio_copy_data(struct bio *dst, struct bio *src); -extern int bio_alloc_pages(struct bio *bio, gfp_t gfp); -extern void bio_free_pages(struct bio *bio); - -extern struct bio *bio_copy_user_iov(struct request_queue *, - struct rq_map_data *, - const struct iov_iter *, - gfp_t); -extern int bio_uncopy_user(struct bio *); -void zero_fill_bio(struct bio *bio); -extern struct bio_vec *bvec_alloc(gfp_t, int, unsigned long *, mempool_t *); -extern void bvec_free(mempool_t *, struct bio_vec *, unsigned int); -extern unsigned int bvec_nr_vecs(unsigned short idx); - -#ifdef CONFIG_BLK_CGROUP -int bio_associate_blkcg(struct bio *bio, struct cgroup_subsys_state *blkcg_css); -int bio_associate_current(struct bio *bio); -void bio_disassociate_task(struct bio *bio); -void bio_clone_blkcg_association(struct bio *dst, struct bio *src); -#else /* CONFIG_BLK_CGROUP */ -static inline int bio_associate_blkcg(struct bio *bio, - struct cgroup_subsys_state *blkcg_css) { return 0; } -static inline int bio_associate_current(struct bio *bio) { return -ENOENT; } -static inline void bio_disassociate_task(struct bio *bio) { } -static inline void bio_clone_blkcg_association(struct bio *dst, - struct bio *src) { } -#endif /* CONFIG_BLK_CGROUP */ - -#ifdef CONFIG_HIGHMEM -/* - * remember never ever reenable interrupts between a bvec_kmap_irq and - * bvec_kunmap_irq! - */ -static inline char *bvec_kmap_irq(struct bio_vec *bvec, unsigned long *flags) -{ - unsigned long addr; - - /* - * might not be a highmem page, but the preempt/irq count - * balancing is a lot nicer this way - */ - local_irq_save(*flags); - addr = (unsigned long) kmap_atomic(bvec->bv_page); - - BUG_ON(addr & ~PAGE_MASK); - - return (char *) addr + bvec->bv_offset; -} - -static inline void bvec_kunmap_irq(char *buffer, unsigned long *flags) -{ - unsigned long ptr = (unsigned long) buffer & PAGE_MASK; - - kunmap_atomic((void *) ptr); - local_irq_restore(*flags); -} - -#else -static inline char *bvec_kmap_irq(struct bio_vec *bvec, unsigned long *flags) -{ - return page_address(bvec->bv_page) + bvec->bv_offset; -} - -static inline void bvec_kunmap_irq(char *buffer, unsigned long *flags) -{ - *flags = 0; -} -#endif - -static inline char *__bio_kmap_irq(struct bio *bio, struct bvec_iter iter, - unsigned long *flags) -{ - return bvec_kmap_irq(&bio_iter_iovec(bio, iter), flags); -} -#define __bio_kunmap_irq(buf, flags) bvec_kunmap_irq(buf, flags) - -#define bio_kmap_irq(bio, flags) \ - __bio_kmap_irq((bio), (bio)->bi_iter, (flags)) -#define bio_kunmap_irq(buf,flags) __bio_kunmap_irq(buf, flags) - -/* - * BIO list management for use by remapping drivers (e.g. DM or MD) and loop. - * - * A bio_list anchors a singly-linked list of bios chained through the bi_next - * member of the bio. The bio_list also caches the last list member to allow - * fast access to the tail. - */ -struct bio_list { - struct bio *head; - struct bio *tail; -}; - -static inline int bio_list_empty(const struct bio_list *bl) -{ - return bl->head == NULL; -} - -static inline void bio_list_init(struct bio_list *bl) -{ - bl->head = bl->tail = NULL; -} - -#define BIO_EMPTY_LIST { NULL, NULL } - -#define bio_list_for_each(bio, bl) \ - for (bio = (bl)->head; bio; bio = bio->bi_next) - -static inline unsigned bio_list_size(const struct bio_list *bl) -{ - unsigned sz = 0; - struct bio *bio; - - bio_list_for_each(bio, bl) - sz++; - - return sz; -} - -static inline void bio_list_add(struct bio_list *bl, struct bio *bio) -{ - bio->bi_next = NULL; - - if (bl->tail) - bl->tail->bi_next = bio; - else - bl->head = bio; - - bl->tail = bio; -} - -static inline void bio_list_add_head(struct bio_list *bl, struct bio *bio) -{ - bio->bi_next = bl->head; - - bl->head = bio; - - if (!bl->tail) - bl->tail = bio; -} - -static inline void bio_list_merge(struct bio_list *bl, struct bio_list *bl2) -{ - if (!bl2->head) - return; - - if (bl->tail) - bl->tail->bi_next = bl2->head; - else - bl->head = bl2->head; - - bl->tail = bl2->tail; -} - -static inline void bio_list_merge_head(struct bio_list *bl, - struct bio_list *bl2) -{ - if (!bl2->head) - return; - - if (bl->head) - bl2->tail->bi_next = bl->head; - else - bl->tail = bl2->tail; - - bl->head = bl2->head; -} - -static inline struct bio *bio_list_peek(struct bio_list *bl) -{ - return bl->head; -} - -static inline struct bio *bio_list_pop(struct bio_list *bl) -{ - struct bio *bio = bl->head; - - if (bio) { - bl->head = bl->head->bi_next; - if (!bl->head) - bl->tail = NULL; - - bio->bi_next = NULL; - } - - return bio; -} - -static inline struct bio *bio_list_get(struct bio_list *bl) -{ - struct bio *bio = bl->head; - - bl->head = bl->tail = NULL; - - return bio; -} - -/* - * Increment chain count for the bio. Make sure the CHAIN flag update - * is visible before the raised count. - */ -static inline void bio_inc_remaining(struct bio *bio) -{ - bio_set_flag(bio, BIO_CHAIN); - smp_mb__before_atomic(); - atomic_inc(&bio->__bi_remaining); -} - -/* - * bio_set is used to allow other portions of the IO system to - * allocate their own private memory pools for bio and iovec structures. - * These memory pools in turn all allocate from the bio_slab - * and the bvec_slabs[]. - */ -#define BIO_POOL_SIZE 2 - -struct bio_set { - struct kmem_cache *bio_slab; - unsigned int front_pad; - - mempool_t *bio_pool; - mempool_t *bvec_pool; -#if defined(CONFIG_BLK_DEV_INTEGRITY) - mempool_t *bio_integrity_pool; - mempool_t *bvec_integrity_pool; -#endif - - /* - * Deadlock avoidance for stacking block drivers: see comments in - * bio_alloc_bioset() for details - */ - spinlock_t rescue_lock; - struct bio_list rescue_list; - struct work_struct rescue_work; - struct workqueue_struct *rescue_workqueue; -}; - -struct biovec_slab { - int nr_vecs; - char *name; - struct kmem_cache *slab; -}; - -/* - * a small number of entries is fine, not going to be performance critical. - * basically we just need to survive - */ -#define BIO_SPLIT_ENTRIES 2 - -#if defined(CONFIG_BLK_DEV_INTEGRITY) - -#define bip_for_each_vec(bvl, bip, iter) \ - for_each_bvec(bvl, (bip)->bip_vec, iter, (bip)->bip_iter) - -#define bio_for_each_integrity_vec(_bvl, _bio, _iter) \ - for_each_bio(_bio) \ - bip_for_each_vec(_bvl, _bio->bi_integrity, _iter) - -extern struct bio_integrity_payload *bio_integrity_alloc(struct bio *, gfp_t, unsigned int); -extern void bio_integrity_free(struct bio *); -extern int bio_integrity_add_page(struct bio *, struct page *, unsigned int, unsigned int); -extern bool bio_integrity_enabled(struct bio *bio); -extern int bio_integrity_prep(struct bio *); -extern void bio_integrity_endio(struct bio *); -extern void bio_integrity_advance(struct bio *, unsigned int); -extern void bio_integrity_trim(struct bio *, unsigned int, unsigned int); -extern int bio_integrity_clone(struct bio *, struct bio *, gfp_t); -extern int bioset_integrity_create(struct bio_set *, int); -extern void bioset_integrity_free(struct bio_set *); -extern void bio_integrity_init(void); - -#else /* CONFIG_BLK_DEV_INTEGRITY */ - -static inline void *bio_integrity(struct bio *bio) -{ - return NULL; -} - -static inline bool bio_integrity_enabled(struct bio *bio) -{ - return false; -} - -static inline int bioset_integrity_create(struct bio_set *bs, int pool_size) -{ - return 0; -} - -static inline void bioset_integrity_free (struct bio_set *bs) -{ - return; -} - -static inline int bio_integrity_prep(struct bio *bio) -{ - return 0; -} - -static inline void bio_integrity_free(struct bio *bio) -{ - return; -} - -static inline int bio_integrity_clone(struct bio *bio, struct bio *bio_src, - gfp_t gfp_mask) -{ - return 0; -} - -static inline void bio_integrity_advance(struct bio *bio, - unsigned int bytes_done) -{ - return; -} - -static inline void bio_integrity_trim(struct bio *bio, unsigned int offset, - unsigned int sectors) -{ - return; -} - -static inline void bio_integrity_init(void) -{ - return; -} - -static inline bool bio_integrity_flagged(struct bio *bio, enum bip_flags flag) -{ - return false; -} - -static inline void *bio_integrity_alloc(struct bio * bio, gfp_t gfp, - unsigned int nr) -{ - return ERR_PTR(-EINVAL); -} - -static inline int bio_integrity_add_page(struct bio *bio, struct page *page, - unsigned int len, unsigned int offset) -{ - return 0; -} - -#endif /* CONFIG_BLK_DEV_INTEGRITY */ - -#endif /* CONFIG_BLOCK */ -#endif /* __LINUX_BIO_H */ diff --git a/src/linux/include/linux/bit_spinlock.h b/src/linux/include/linux/bit_spinlock.h deleted file mode 100644 index 3b5bafc..0000000 --- a/src/linux/include/linux/bit_spinlock.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef __LINUX_BIT_SPINLOCK_H -#define __LINUX_BIT_SPINLOCK_H - -#include -#include -#include -#include - -/* - * bit-based spin_lock() - * - * Don't use this unless you really need to: spin_lock() and spin_unlock() - * are significantly faster. - */ -static inline void bit_spin_lock(int bitnum, unsigned long *addr) -{ - /* - * Assuming the lock is uncontended, this never enters - * the body of the outer loop. If it is contended, then - * within the inner loop a non-atomic test is used to - * busywait with less bus contention for a good time to - * attempt to acquire the lock bit. - */ - preempt_disable(); -#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) - while (unlikely(test_and_set_bit_lock(bitnum, addr))) { - preempt_enable(); - do { - cpu_relax(); - } while (test_bit(bitnum, addr)); - preempt_disable(); - } -#endif - __acquire(bitlock); -} - -/* - * Return true if it was acquired - */ -static inline int bit_spin_trylock(int bitnum, unsigned long *addr) -{ - preempt_disable(); -#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) - if (unlikely(test_and_set_bit_lock(bitnum, addr))) { - preempt_enable(); - return 0; - } -#endif - __acquire(bitlock); - return 1; -} - -/* - * bit-based spin_unlock() - */ -static inline void bit_spin_unlock(int bitnum, unsigned long *addr) -{ -#ifdef CONFIG_DEBUG_SPINLOCK - BUG_ON(!test_bit(bitnum, addr)); -#endif -#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) - clear_bit_unlock(bitnum, addr); -#endif - preempt_enable(); - __release(bitlock); -} - -/* - * bit-based spin_unlock() - * non-atomic version, which can be used eg. if the bit lock itself is - * protecting the rest of the flags in the word. - */ -static inline void __bit_spin_unlock(int bitnum, unsigned long *addr) -{ -#ifdef CONFIG_DEBUG_SPINLOCK - BUG_ON(!test_bit(bitnum, addr)); -#endif -#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) - __clear_bit_unlock(bitnum, addr); -#endif - preempt_enable(); - __release(bitlock); -} - -/* - * Return true if the lock is held. - */ -static inline int bit_spin_is_locked(int bitnum, unsigned long *addr) -{ -#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) - return test_bit(bitnum, addr); -#elif defined CONFIG_PREEMPT_COUNT - return preempt_count(); -#else - return 1; -#endif -} - -#endif /* __LINUX_BIT_SPINLOCK_H */ - diff --git a/src/linux/include/linux/bitmap.h b/src/linux/include/linux/bitmap.h deleted file mode 100644 index 3b77588..0000000 --- a/src/linux/include/linux/bitmap.h +++ /dev/null @@ -1,362 +0,0 @@ -#ifndef __LINUX_BITMAP_H -#define __LINUX_BITMAP_H - -#ifndef __ASSEMBLY__ - -#include -#include -#include -#include - -/* - * bitmaps provide bit arrays that consume one or more unsigned - * longs. The bitmap interface and available operations are listed - * here, in bitmap.h - * - * Function implementations generic to all architectures are in - * lib/bitmap.c. Functions implementations that are architecture - * specific are in various include/asm-/bitops.h headers - * and other arch/ specific files. - * - * See lib/bitmap.c for more details. - */ - -/* - * The available bitmap operations and their rough meaning in the - * case that the bitmap is a single unsigned long are thus: - * - * Note that nbits should be always a compile time evaluable constant. - * Otherwise many inlines will generate horrible code. - * - * bitmap_zero(dst, nbits) *dst = 0UL - * bitmap_fill(dst, nbits) *dst = ~0UL - * bitmap_copy(dst, src, nbits) *dst = *src - * bitmap_and(dst, src1, src2, nbits) *dst = *src1 & *src2 - * bitmap_or(dst, src1, src2, nbits) *dst = *src1 | *src2 - * bitmap_xor(dst, src1, src2, nbits) *dst = *src1 ^ *src2 - * bitmap_andnot(dst, src1, src2, nbits) *dst = *src1 & ~(*src2) - * bitmap_complement(dst, src, nbits) *dst = ~(*src) - * bitmap_equal(src1, src2, nbits) Are *src1 and *src2 equal? - * bitmap_intersects(src1, src2, nbits) Do *src1 and *src2 overlap? - * bitmap_subset(src1, src2, nbits) Is *src1 a subset of *src2? - * bitmap_empty(src, nbits) Are all bits zero in *src? - * bitmap_full(src, nbits) Are all bits set in *src? - * bitmap_weight(src, nbits) Hamming Weight: number set bits - * bitmap_set(dst, pos, nbits) Set specified bit area - * bitmap_clear(dst, pos, nbits) Clear specified bit area - * bitmap_find_next_zero_area(buf, len, pos, n, mask) Find bit free area - * bitmap_find_next_zero_area_off(buf, len, pos, n, mask) as above - * bitmap_shift_right(dst, src, n, nbits) *dst = *src >> n - * bitmap_shift_left(dst, src, n, nbits) *dst = *src << n - * bitmap_remap(dst, src, old, new, nbits) *dst = map(old, new)(src) - * bitmap_bitremap(oldbit, old, new, nbits) newbit = map(old, new)(oldbit) - * bitmap_onto(dst, orig, relmap, nbits) *dst = orig relative to relmap - * bitmap_fold(dst, orig, sz, nbits) dst bits = orig bits mod sz - * bitmap_parse(buf, buflen, dst, nbits) Parse bitmap dst from kernel buf - * bitmap_parse_user(ubuf, ulen, dst, nbits) Parse bitmap dst from user buf - * bitmap_parselist(buf, dst, nbits) Parse bitmap dst from kernel buf - * bitmap_parselist_user(buf, dst, nbits) Parse bitmap dst from user buf - * bitmap_find_free_region(bitmap, bits, order) Find and allocate bit region - * bitmap_release_region(bitmap, pos, order) Free specified bit region - * bitmap_allocate_region(bitmap, pos, order) Allocate specified bit region - * bitmap_from_u32array(dst, nbits, buf, nwords) *dst = *buf (nwords 32b words) - * bitmap_to_u32array(buf, nwords, src, nbits) *buf = *dst (nwords 32b words) - */ - -/* - * Also the following operations in asm/bitops.h apply to bitmaps. - * - * set_bit(bit, addr) *addr |= bit - * clear_bit(bit, addr) *addr &= ~bit - * change_bit(bit, addr) *addr ^= bit - * test_bit(bit, addr) Is bit set in *addr? - * test_and_set_bit(bit, addr) Set bit and return old value - * test_and_clear_bit(bit, addr) Clear bit and return old value - * test_and_change_bit(bit, addr) Change bit and return old value - * find_first_zero_bit(addr, nbits) Position first zero bit in *addr - * find_first_bit(addr, nbits) Position first set bit in *addr - * find_next_zero_bit(addr, nbits, bit) Position next zero bit in *addr >= bit - * find_next_bit(addr, nbits, bit) Position next set bit in *addr >= bit - */ - -/* - * The DECLARE_BITMAP(name,bits) macro, in linux/types.h, can be used - * to declare an array named 'name' of just enough unsigned longs to - * contain all bit positions from 0 to 'bits' - 1. - */ - -/* - * lib/bitmap.c provides these functions: - */ - -extern int __bitmap_empty(const unsigned long *bitmap, unsigned int nbits); -extern int __bitmap_full(const unsigned long *bitmap, unsigned int nbits); -extern int __bitmap_equal(const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int nbits); -extern void __bitmap_complement(unsigned long *dst, const unsigned long *src, - unsigned int nbits); -extern void __bitmap_shift_right(unsigned long *dst, const unsigned long *src, - unsigned int shift, unsigned int nbits); -extern void __bitmap_shift_left(unsigned long *dst, const unsigned long *src, - unsigned int shift, unsigned int nbits); -extern int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int nbits); -extern void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int nbits); -extern void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int nbits); -extern int __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int nbits); -extern int __bitmap_intersects(const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int nbits); -extern int __bitmap_subset(const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int nbits); -extern int __bitmap_weight(const unsigned long *bitmap, unsigned int nbits); - -extern void bitmap_set(unsigned long *map, unsigned int start, int len); -extern void bitmap_clear(unsigned long *map, unsigned int start, int len); - -extern unsigned long bitmap_find_next_zero_area_off(unsigned long *map, - unsigned long size, - unsigned long start, - unsigned int nr, - unsigned long align_mask, - unsigned long align_offset); - -/** - * bitmap_find_next_zero_area - find a contiguous aligned zero area - * @map: The address to base the search on - * @size: The bitmap size in bits - * @start: The bitnumber to start searching at - * @nr: The number of zeroed bits we're looking for - * @align_mask: Alignment mask for zero area - * - * The @align_mask should be one less than a power of 2; the effect is that - * the bit offset of all zero areas this function finds is multiples of that - * power of 2. A @align_mask of 0 means no alignment is required. - */ -static inline unsigned long -bitmap_find_next_zero_area(unsigned long *map, - unsigned long size, - unsigned long start, - unsigned int nr, - unsigned long align_mask) -{ - return bitmap_find_next_zero_area_off(map, size, start, nr, - align_mask, 0); -} - -extern int __bitmap_parse(const char *buf, unsigned int buflen, int is_user, - unsigned long *dst, int nbits); -extern int bitmap_parse_user(const char __user *ubuf, unsigned int ulen, - unsigned long *dst, int nbits); -extern int bitmap_parselist(const char *buf, unsigned long *maskp, - int nmaskbits); -extern int bitmap_parselist_user(const char __user *ubuf, unsigned int ulen, - unsigned long *dst, int nbits); -extern void bitmap_remap(unsigned long *dst, const unsigned long *src, - const unsigned long *old, const unsigned long *new, unsigned int nbits); -extern int bitmap_bitremap(int oldbit, - const unsigned long *old, const unsigned long *new, int bits); -extern void bitmap_onto(unsigned long *dst, const unsigned long *orig, - const unsigned long *relmap, unsigned int bits); -extern void bitmap_fold(unsigned long *dst, const unsigned long *orig, - unsigned int sz, unsigned int nbits); -extern int bitmap_find_free_region(unsigned long *bitmap, unsigned int bits, int order); -extern void bitmap_release_region(unsigned long *bitmap, unsigned int pos, int order); -extern int bitmap_allocate_region(unsigned long *bitmap, unsigned int pos, int order); -extern unsigned int bitmap_from_u32array(unsigned long *bitmap, - unsigned int nbits, - const u32 *buf, - unsigned int nwords); -extern unsigned int bitmap_to_u32array(u32 *buf, - unsigned int nwords, - const unsigned long *bitmap, - unsigned int nbits); -#ifdef __BIG_ENDIAN -extern void bitmap_copy_le(unsigned long *dst, const unsigned long *src, unsigned int nbits); -#else -#define bitmap_copy_le bitmap_copy -#endif -extern unsigned int bitmap_ord_to_pos(const unsigned long *bitmap, unsigned int ord, unsigned int nbits); -extern int bitmap_print_to_pagebuf(bool list, char *buf, - const unsigned long *maskp, int nmaskbits); - -#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1))) -#define BITMAP_LAST_WORD_MASK(nbits) (~0UL >> (-(nbits) & (BITS_PER_LONG - 1))) - -#define small_const_nbits(nbits) \ - (__builtin_constant_p(nbits) && (nbits) <= BITS_PER_LONG) - -static inline void bitmap_zero(unsigned long *dst, unsigned int nbits) -{ - if (small_const_nbits(nbits)) - *dst = 0UL; - else { - unsigned int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); - memset(dst, 0, len); - } -} - -static inline void bitmap_fill(unsigned long *dst, unsigned int nbits) -{ - unsigned int nlongs = BITS_TO_LONGS(nbits); - if (!small_const_nbits(nbits)) { - unsigned int len = (nlongs - 1) * sizeof(unsigned long); - memset(dst, 0xff, len); - } - dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits); -} - -static inline void bitmap_copy(unsigned long *dst, const unsigned long *src, - unsigned int nbits) -{ - if (small_const_nbits(nbits)) - *dst = *src; - else { - unsigned int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long); - memcpy(dst, src, len); - } -} - -static inline int bitmap_and(unsigned long *dst, const unsigned long *src1, - const unsigned long *src2, unsigned int nbits) -{ - if (small_const_nbits(nbits)) - return (*dst = *src1 & *src2 & BITMAP_LAST_WORD_MASK(nbits)) != 0; - return __bitmap_and(dst, src1, src2, nbits); -} - -static inline void bitmap_or(unsigned long *dst, const unsigned long *src1, - const unsigned long *src2, unsigned int nbits) -{ - if (small_const_nbits(nbits)) - *dst = *src1 | *src2; - else - __bitmap_or(dst, src1, src2, nbits); -} - -static inline void bitmap_xor(unsigned long *dst, const unsigned long *src1, - const unsigned long *src2, unsigned int nbits) -{ - if (small_const_nbits(nbits)) - *dst = *src1 ^ *src2; - else - __bitmap_xor(dst, src1, src2, nbits); -} - -static inline int bitmap_andnot(unsigned long *dst, const unsigned long *src1, - const unsigned long *src2, unsigned int nbits) -{ - if (small_const_nbits(nbits)) - return (*dst = *src1 & ~(*src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0; - return __bitmap_andnot(dst, src1, src2, nbits); -} - -static inline void bitmap_complement(unsigned long *dst, const unsigned long *src, - unsigned int nbits) -{ - if (small_const_nbits(nbits)) - *dst = ~(*src); - else - __bitmap_complement(dst, src, nbits); -} - -static inline int bitmap_equal(const unsigned long *src1, - const unsigned long *src2, unsigned int nbits) -{ - if (small_const_nbits(nbits)) - return !((*src1 ^ *src2) & BITMAP_LAST_WORD_MASK(nbits)); -#ifdef CONFIG_S390 - if (__builtin_constant_p(nbits) && (nbits % BITS_PER_LONG) == 0) - return !memcmp(src1, src2, nbits / 8); -#endif - return __bitmap_equal(src1, src2, nbits); -} - -static inline int bitmap_intersects(const unsigned long *src1, - const unsigned long *src2, unsigned int nbits) -{ - if (small_const_nbits(nbits)) - return ((*src1 & *src2) & BITMAP_LAST_WORD_MASK(nbits)) != 0; - else - return __bitmap_intersects(src1, src2, nbits); -} - -static inline int bitmap_subset(const unsigned long *src1, - const unsigned long *src2, unsigned int nbits) -{ - if (small_const_nbits(nbits)) - return ! ((*src1 & ~(*src2)) & BITMAP_LAST_WORD_MASK(nbits)); - else - return __bitmap_subset(src1, src2, nbits); -} - -static inline int bitmap_empty(const unsigned long *src, unsigned nbits) -{ - if (small_const_nbits(nbits)) - return ! (*src & BITMAP_LAST_WORD_MASK(nbits)); - - return find_first_bit(src, nbits) == nbits; -} - -static inline int bitmap_full(const unsigned long *src, unsigned int nbits) -{ - if (small_const_nbits(nbits)) - return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits)); - - return find_first_zero_bit(src, nbits) == nbits; -} - -static __always_inline int bitmap_weight(const unsigned long *src, unsigned int nbits) -{ - if (small_const_nbits(nbits)) - return hweight_long(*src & BITMAP_LAST_WORD_MASK(nbits)); - return __bitmap_weight(src, nbits); -} - -static inline void bitmap_shift_right(unsigned long *dst, const unsigned long *src, - unsigned int shift, int nbits) -{ - if (small_const_nbits(nbits)) - *dst = (*src & BITMAP_LAST_WORD_MASK(nbits)) >> shift; - else - __bitmap_shift_right(dst, src, shift, nbits); -} - -static inline void bitmap_shift_left(unsigned long *dst, const unsigned long *src, - unsigned int shift, unsigned int nbits) -{ - if (small_const_nbits(nbits)) - *dst = (*src << shift) & BITMAP_LAST_WORD_MASK(nbits); - else - __bitmap_shift_left(dst, src, shift, nbits); -} - -static inline int bitmap_parse(const char *buf, unsigned int buflen, - unsigned long *maskp, int nmaskbits) -{ - return __bitmap_parse(buf, buflen, 0, maskp, nmaskbits); -} - -/* - * bitmap_from_u64 - Check and swap words within u64. - * @mask: source bitmap - * @dst: destination bitmap - * - * In 32-bit Big Endian kernel, when using (u32 *)(&val)[*] - * to read u64 mask, we will get the wrong word. - * That is "(u32 *)(&val)[0]" gets the upper 32 bits, - * but we expect the lower 32-bits of u64. - */ -static inline void bitmap_from_u64(unsigned long *dst, u64 mask) -{ - dst[0] = mask & ULONG_MAX; - - if (sizeof(mask) > sizeof(unsigned long)) - dst[1] = mask >> 32; -} - -#endif /* __ASSEMBLY__ */ - -#endif /* __LINUX_BITMAP_H */ diff --git a/src/linux/include/linux/bitops.h b/src/linux/include/linux/bitops.h deleted file mode 100644 index a83c822..0000000 --- a/src/linux/include/linux/bitops.h +++ /dev/null @@ -1,275 +0,0 @@ -#ifndef _LINUX_BITOPS_H -#define _LINUX_BITOPS_H -#include - -#ifdef __KERNEL__ -#define BIT(nr) (1UL << (nr)) -#define BIT_ULL(nr) (1ULL << (nr)) -#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) -#define BIT_WORD(nr) ((nr) / BITS_PER_LONG) -#define BIT_ULL_MASK(nr) (1ULL << ((nr) % BITS_PER_LONG_LONG)) -#define BIT_ULL_WORD(nr) ((nr) / BITS_PER_LONG_LONG) -#define BITS_PER_BYTE 8 -#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long)) -#endif - -/* - * Create a contiguous bitmask starting at bit position @l and ending at - * position @h. For example - * GENMASK_ULL(39, 21) gives us the 64bit vector 0x000000ffffe00000. - */ -#define GENMASK(h, l) \ - (((~0UL) << (l)) & (~0UL >> (BITS_PER_LONG - 1 - (h)))) - -#define GENMASK_ULL(h, l) \ - (((~0ULL) << (l)) & (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h)))) - -extern unsigned int __sw_hweight8(unsigned int w); -extern unsigned int __sw_hweight16(unsigned int w); -extern unsigned int __sw_hweight32(unsigned int w); -extern unsigned long __sw_hweight64(__u64 w); - -/* - * Include this here because some architectures need generic_ffs/fls in - * scope - */ -#include - -#define for_each_set_bit(bit, addr, size) \ - for ((bit) = find_first_bit((addr), (size)); \ - (bit) < (size); \ - (bit) = find_next_bit((addr), (size), (bit) + 1)) - -/* same as for_each_set_bit() but use bit as value to start with */ -#define for_each_set_bit_from(bit, addr, size) \ - for ((bit) = find_next_bit((addr), (size), (bit)); \ - (bit) < (size); \ - (bit) = find_next_bit((addr), (size), (bit) + 1)) - -#define for_each_clear_bit(bit, addr, size) \ - for ((bit) = find_first_zero_bit((addr), (size)); \ - (bit) < (size); \ - (bit) = find_next_zero_bit((addr), (size), (bit) + 1)) - -/* same as for_each_clear_bit() but use bit as value to start with */ -#define for_each_clear_bit_from(bit, addr, size) \ - for ((bit) = find_next_zero_bit((addr), (size), (bit)); \ - (bit) < (size); \ - (bit) = find_next_zero_bit((addr), (size), (bit) + 1)) - -static inline int get_bitmask_order(unsigned int count) -{ - int order; - - order = fls(count); - return order; /* We could be slightly more clever with -1 here... */ -} - -static __always_inline unsigned long hweight_long(unsigned long w) -{ - return sizeof(w) == 4 ? hweight32(w) : hweight64(w); -} - -/** - * rol64 - rotate a 64-bit value left - * @word: value to rotate - * @shift: bits to roll - */ -static inline __u64 rol64(__u64 word, unsigned int shift) -{ - return (word << shift) | (word >> (64 - shift)); -} - -/** - * ror64 - rotate a 64-bit value right - * @word: value to rotate - * @shift: bits to roll - */ -static inline __u64 ror64(__u64 word, unsigned int shift) -{ - return (word >> shift) | (word << (64 - shift)); -} - -/** - * rol32 - rotate a 32-bit value left - * @word: value to rotate - * @shift: bits to roll - */ -static inline __u32 rol32(__u32 word, unsigned int shift) -{ - return (word << shift) | (word >> ((-shift) & 31)); -} - -/** - * ror32 - rotate a 32-bit value right - * @word: value to rotate - * @shift: bits to roll - */ -static inline __u32 ror32(__u32 word, unsigned int shift) -{ - return (word >> shift) | (word << (32 - shift)); -} - -/** - * rol16 - rotate a 16-bit value left - * @word: value to rotate - * @shift: bits to roll - */ -static inline __u16 rol16(__u16 word, unsigned int shift) -{ - return (word << shift) | (word >> (16 - shift)); -} - -/** - * ror16 - rotate a 16-bit value right - * @word: value to rotate - * @shift: bits to roll - */ -static inline __u16 ror16(__u16 word, unsigned int shift) -{ - return (word >> shift) | (word << (16 - shift)); -} - -/** - * rol8 - rotate an 8-bit value left - * @word: value to rotate - * @shift: bits to roll - */ -static inline __u8 rol8(__u8 word, unsigned int shift) -{ - return (word << shift) | (word >> (8 - shift)); -} - -/** - * ror8 - rotate an 8-bit value right - * @word: value to rotate - * @shift: bits to roll - */ -static inline __u8 ror8(__u8 word, unsigned int shift) -{ - return (word >> shift) | (word << (8 - shift)); -} - -/** - * sign_extend32 - sign extend a 32-bit value using specified bit as sign-bit - * @value: value to sign extend - * @index: 0 based bit index (0<=index<32) to sign bit - * - * This is safe to use for 16- and 8-bit types as well. - */ -static inline __s32 sign_extend32(__u32 value, int index) -{ - __u8 shift = 31 - index; - return (__s32)(value << shift) >> shift; -} - -/** - * sign_extend64 - sign extend a 64-bit value using specified bit as sign-bit - * @value: value to sign extend - * @index: 0 based bit index (0<=index<64) to sign bit - */ -static inline __s64 sign_extend64(__u64 value, int index) -{ - __u8 shift = 63 - index; - return (__s64)(value << shift) >> shift; -} - -static inline unsigned fls_long(unsigned long l) -{ - if (sizeof(l) == 4) - return fls(l); - return fls64(l); -} - -static inline int get_count_order(unsigned int count) -{ - int order; - - order = fls(count) - 1; - if (count & (count - 1)) - order++; - return order; -} - -/** - * get_count_order_long - get order after rounding @l up to power of 2 - * @l: parameter - * - * it is same as get_count_order() but with long type parameter - */ -static inline int get_count_order_long(unsigned long l) -{ - if (l == 0UL) - return -1; - else if (l & (l - 1UL)) - return (int)fls_long(l); - else - return (int)fls_long(l) - 1; -} - -/** - * __ffs64 - find first set bit in a 64 bit word - * @word: The 64 bit word - * - * On 64 bit arches this is a synomyn for __ffs - * The result is not defined if no bits are set, so check that @word - * is non-zero before calling this. - */ -static inline unsigned long __ffs64(u64 word) -{ -#if BITS_PER_LONG == 32 - if (((u32)word) == 0UL) - return __ffs((u32)(word >> 32)) + 32; -#elif BITS_PER_LONG != 64 -#error BITS_PER_LONG not 32 or 64 -#endif - return __ffs((unsigned long)word); -} - -#ifdef __KERNEL__ - -#ifndef set_mask_bits -#define set_mask_bits(ptr, _mask, _bits) \ -({ \ - const typeof(*ptr) mask = (_mask), bits = (_bits); \ - typeof(*ptr) old, new; \ - \ - do { \ - old = ACCESS_ONCE(*ptr); \ - new = (old & ~mask) | bits; \ - } while (cmpxchg(ptr, old, new) != old); \ - \ - new; \ -}) -#endif - -#ifndef bit_clear_unless -#define bit_clear_unless(ptr, _clear, _test) \ -({ \ - const typeof(*ptr) clear = (_clear), test = (_test); \ - typeof(*ptr) old, new; \ - \ - do { \ - old = ACCESS_ONCE(*ptr); \ - new = old & ~clear; \ - } while (!(old & test) && \ - cmpxchg(ptr, old, new) != old); \ - \ - !(old & test); \ -}) -#endif - -#ifndef find_last_bit -/** - * find_last_bit - find the last set bit in a memory region - * @addr: The address to start the search at - * @size: The number of bits to search - * - * Returns the bit number of the last set bit, or size. - */ -extern unsigned long find_last_bit(const unsigned long *addr, - unsigned long size); -#endif - -#endif /* __KERNEL__ */ -#endif diff --git a/src/linux/include/linux/bitrev.h b/src/linux/include/linux/bitrev.h deleted file mode 100644 index fb790b8..0000000 --- a/src/linux/include/linux/bitrev.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef _LINUX_BITREV_H -#define _LINUX_BITREV_H - -#include - -#ifdef CONFIG_HAVE_ARCH_BITREVERSE -#include - -#define __bitrev32 __arch_bitrev32 -#define __bitrev16 __arch_bitrev16 -#define __bitrev8 __arch_bitrev8 - -#else -extern u8 const byte_rev_table[256]; -static inline u8 __bitrev8(u8 byte) -{ - return byte_rev_table[byte]; -} - -static inline u16 __bitrev16(u16 x) -{ - return (__bitrev8(x & 0xff) << 8) | __bitrev8(x >> 8); -} - -static inline u32 __bitrev32(u32 x) -{ - return (__bitrev16(x & 0xffff) << 16) | __bitrev16(x >> 16); -} - -#endif /* CONFIG_HAVE_ARCH_BITREVERSE */ - -#define __constant_bitrev32(x) \ -({ \ - u32 __x = x; \ - __x = (__x >> 16) | (__x << 16); \ - __x = ((__x & (u32)0xFF00FF00UL) >> 8) | ((__x & (u32)0x00FF00FFUL) << 8); \ - __x = ((__x & (u32)0xF0F0F0F0UL) >> 4) | ((__x & (u32)0x0F0F0F0FUL) << 4); \ - __x = ((__x & (u32)0xCCCCCCCCUL) >> 2) | ((__x & (u32)0x33333333UL) << 2); \ - __x = ((__x & (u32)0xAAAAAAAAUL) >> 1) | ((__x & (u32)0x55555555UL) << 1); \ - __x; \ -}) - -#define __constant_bitrev16(x) \ -({ \ - u16 __x = x; \ - __x = (__x >> 8) | (__x << 8); \ - __x = ((__x & (u16)0xF0F0U) >> 4) | ((__x & (u16)0x0F0FU) << 4); \ - __x = ((__x & (u16)0xCCCCU) >> 2) | ((__x & (u16)0x3333U) << 2); \ - __x = ((__x & (u16)0xAAAAU) >> 1) | ((__x & (u16)0x5555U) << 1); \ - __x; \ -}) - -#define __constant_bitrev8(x) \ -({ \ - u8 __x = x; \ - __x = (__x >> 4) | (__x << 4); \ - __x = ((__x & (u8)0xCCU) >> 2) | ((__x & (u8)0x33U) << 2); \ - __x = ((__x & (u8)0xAAU) >> 1) | ((__x & (u8)0x55U) << 1); \ - __x; \ -}) - -#define bitrev32(x) \ -({ \ - u32 __x = x; \ - __builtin_constant_p(__x) ? \ - __constant_bitrev32(__x) : \ - __bitrev32(__x); \ -}) - -#define bitrev16(x) \ -({ \ - u16 __x = x; \ - __builtin_constant_p(__x) ? \ - __constant_bitrev16(__x) : \ - __bitrev16(__x); \ - }) - -#define bitrev8(x) \ -({ \ - u8 __x = x; \ - __builtin_constant_p(__x) ? \ - __constant_bitrev8(__x) : \ - __bitrev8(__x) ; \ - }) -#endif /* _LINUX_BITREV_H */ diff --git a/src/linux/include/linux/blk-cgroup.h b/src/linux/include/linux/blk-cgroup.h deleted file mode 100644 index 3bf5d33..0000000 --- a/src/linux/include/linux/blk-cgroup.h +++ /dev/null @@ -1,778 +0,0 @@ -#ifndef _BLK_CGROUP_H -#define _BLK_CGROUP_H -/* - * Common Block IO controller cgroup interface - * - * Based on ideas and code from CFQ, CFS and BFQ: - * Copyright (C) 2003 Jens Axboe - * - * Copyright (C) 2008 Fabio Checconi - * Paolo Valente - * - * Copyright (C) 2009 Vivek Goyal - * Nauman Rafique - */ - -#include -#include -#include -#include -#include -#include - -/* percpu_counter batch for blkg_[rw]stats, per-cpu drift doesn't matter */ -#define BLKG_STAT_CPU_BATCH (INT_MAX / 2) - -/* Max limits for throttle policy */ -#define THROTL_IOPS_MAX UINT_MAX - -#ifdef CONFIG_BLK_CGROUP - -enum blkg_rwstat_type { - BLKG_RWSTAT_READ, - BLKG_RWSTAT_WRITE, - BLKG_RWSTAT_SYNC, - BLKG_RWSTAT_ASYNC, - - BLKG_RWSTAT_NR, - BLKG_RWSTAT_TOTAL = BLKG_RWSTAT_NR, -}; - -struct blkcg_gq; - -struct blkcg { - struct cgroup_subsys_state css; - spinlock_t lock; - - struct radix_tree_root blkg_tree; - struct blkcg_gq __rcu *blkg_hint; - struct hlist_head blkg_list; - - struct blkcg_policy_data *cpd[BLKCG_MAX_POLS]; - - struct list_head all_blkcgs_node; -#ifdef CONFIG_CGROUP_WRITEBACK - struct list_head cgwb_list; -#endif -}; - -/* - * blkg_[rw]stat->aux_cnt is excluded for local stats but included for - * recursive. Used to carry stats of dead children, and, for blkg_rwstat, - * to carry result values from read and sum operations. - */ -struct blkg_stat { - struct percpu_counter cpu_cnt; - atomic64_t aux_cnt; -}; - -struct blkg_rwstat { - struct percpu_counter cpu_cnt[BLKG_RWSTAT_NR]; - atomic64_t aux_cnt[BLKG_RWSTAT_NR]; -}; - -/* - * A blkcg_gq (blkg) is association between a block cgroup (blkcg) and a - * request_queue (q). This is used by blkcg policies which need to track - * information per blkcg - q pair. - * - * There can be multiple active blkcg policies and each blkg:policy pair is - * represented by a blkg_policy_data which is allocated and freed by each - * policy's pd_alloc/free_fn() methods. A policy can allocate private data - * area by allocating larger data structure which embeds blkg_policy_data - * at the beginning. - */ -struct blkg_policy_data { - /* the blkg and policy id this per-policy data belongs to */ - struct blkcg_gq *blkg; - int plid; -}; - -/* - * Policies that need to keep per-blkcg data which is independent from any - * request_queue associated to it should implement cpd_alloc/free_fn() - * methods. A policy can allocate private data area by allocating larger - * data structure which embeds blkcg_policy_data at the beginning. - * cpd_init() is invoked to let each policy handle per-blkcg data. - */ -struct blkcg_policy_data { - /* the blkcg and policy id this per-policy data belongs to */ - struct blkcg *blkcg; - int plid; -}; - -/* association between a blk cgroup and a request queue */ -struct blkcg_gq { - /* Pointer to the associated request_queue */ - struct request_queue *q; - struct list_head q_node; - struct hlist_node blkcg_node; - struct blkcg *blkcg; - - /* - * Each blkg gets congested separately and the congestion state is - * propagated to the matching bdi_writeback_congested. - */ - struct bdi_writeback_congested *wb_congested; - - /* all non-root blkcg_gq's are guaranteed to have access to parent */ - struct blkcg_gq *parent; - - /* request allocation list for this blkcg-q pair */ - struct request_list rl; - - /* reference count */ - atomic_t refcnt; - - /* is this blkg online? protected by both blkcg and q locks */ - bool online; - - struct blkg_rwstat stat_bytes; - struct blkg_rwstat stat_ios; - - struct blkg_policy_data *pd[BLKCG_MAX_POLS]; - - struct rcu_head rcu_head; -}; - -typedef struct blkcg_policy_data *(blkcg_pol_alloc_cpd_fn)(gfp_t gfp); -typedef void (blkcg_pol_init_cpd_fn)(struct blkcg_policy_data *cpd); -typedef void (blkcg_pol_free_cpd_fn)(struct blkcg_policy_data *cpd); -typedef void (blkcg_pol_bind_cpd_fn)(struct blkcg_policy_data *cpd); -typedef struct blkg_policy_data *(blkcg_pol_alloc_pd_fn)(gfp_t gfp, int node); -typedef void (blkcg_pol_init_pd_fn)(struct blkg_policy_data *pd); -typedef void (blkcg_pol_online_pd_fn)(struct blkg_policy_data *pd); -typedef void (blkcg_pol_offline_pd_fn)(struct blkg_policy_data *pd); -typedef void (blkcg_pol_free_pd_fn)(struct blkg_policy_data *pd); -typedef void (blkcg_pol_reset_pd_stats_fn)(struct blkg_policy_data *pd); - -struct blkcg_policy { - int plid; - /* cgroup files for the policy */ - struct cftype *dfl_cftypes; - struct cftype *legacy_cftypes; - - /* operations */ - blkcg_pol_alloc_cpd_fn *cpd_alloc_fn; - blkcg_pol_init_cpd_fn *cpd_init_fn; - blkcg_pol_free_cpd_fn *cpd_free_fn; - blkcg_pol_bind_cpd_fn *cpd_bind_fn; - - blkcg_pol_alloc_pd_fn *pd_alloc_fn; - blkcg_pol_init_pd_fn *pd_init_fn; - blkcg_pol_online_pd_fn *pd_online_fn; - blkcg_pol_offline_pd_fn *pd_offline_fn; - blkcg_pol_free_pd_fn *pd_free_fn; - blkcg_pol_reset_pd_stats_fn *pd_reset_stats_fn; -}; - -extern struct blkcg blkcg_root; -extern struct cgroup_subsys_state * const blkcg_root_css; - -struct blkcg_gq *blkg_lookup_slowpath(struct blkcg *blkcg, - struct request_queue *q, bool update_hint); -struct blkcg_gq *blkg_lookup_create(struct blkcg *blkcg, - struct request_queue *q); -int blkcg_init_queue(struct request_queue *q); -void blkcg_drain_queue(struct request_queue *q); -void blkcg_exit_queue(struct request_queue *q); - -/* Blkio controller policy registration */ -int blkcg_policy_register(struct blkcg_policy *pol); -void blkcg_policy_unregister(struct blkcg_policy *pol); -int blkcg_activate_policy(struct request_queue *q, - const struct blkcg_policy *pol); -void blkcg_deactivate_policy(struct request_queue *q, - const struct blkcg_policy *pol); - -const char *blkg_dev_name(struct blkcg_gq *blkg); -void blkcg_print_blkgs(struct seq_file *sf, struct blkcg *blkcg, - u64 (*prfill)(struct seq_file *, - struct blkg_policy_data *, int), - const struct blkcg_policy *pol, int data, - bool show_total); -u64 __blkg_prfill_u64(struct seq_file *sf, struct blkg_policy_data *pd, u64 v); -u64 __blkg_prfill_rwstat(struct seq_file *sf, struct blkg_policy_data *pd, - const struct blkg_rwstat *rwstat); -u64 blkg_prfill_stat(struct seq_file *sf, struct blkg_policy_data *pd, int off); -u64 blkg_prfill_rwstat(struct seq_file *sf, struct blkg_policy_data *pd, - int off); -int blkg_print_stat_bytes(struct seq_file *sf, void *v); -int blkg_print_stat_ios(struct seq_file *sf, void *v); -int blkg_print_stat_bytes_recursive(struct seq_file *sf, void *v); -int blkg_print_stat_ios_recursive(struct seq_file *sf, void *v); - -u64 blkg_stat_recursive_sum(struct blkcg_gq *blkg, - struct blkcg_policy *pol, int off); -struct blkg_rwstat blkg_rwstat_recursive_sum(struct blkcg_gq *blkg, - struct blkcg_policy *pol, int off); - -struct blkg_conf_ctx { - struct gendisk *disk; - struct blkcg_gq *blkg; - char *body; -}; - -int blkg_conf_prep(struct blkcg *blkcg, const struct blkcg_policy *pol, - char *input, struct blkg_conf_ctx *ctx); -void blkg_conf_finish(struct blkg_conf_ctx *ctx); - - -static inline struct blkcg *css_to_blkcg(struct cgroup_subsys_state *css) -{ - return css ? container_of(css, struct blkcg, css) : NULL; -} - -static inline struct blkcg *task_blkcg(struct task_struct *tsk) -{ - return css_to_blkcg(task_css(tsk, io_cgrp_id)); -} - -static inline struct blkcg *bio_blkcg(struct bio *bio) -{ - if (bio && bio->bi_css) - return css_to_blkcg(bio->bi_css); - return task_blkcg(current); -} - -static inline struct cgroup_subsys_state * -task_get_blkcg_css(struct task_struct *task) -{ - return task_get_css(task, io_cgrp_id); -} - -/** - * blkcg_parent - get the parent of a blkcg - * @blkcg: blkcg of interest - * - * Return the parent blkcg of @blkcg. Can be called anytime. - */ -static inline struct blkcg *blkcg_parent(struct blkcg *blkcg) -{ - return css_to_blkcg(blkcg->css.parent); -} - -/** - * __blkg_lookup - internal version of blkg_lookup() - * @blkcg: blkcg of interest - * @q: request_queue of interest - * @update_hint: whether to update lookup hint with the result or not - * - * This is internal version and shouldn't be used by policy - * implementations. Looks up blkgs for the @blkcg - @q pair regardless of - * @q's bypass state. If @update_hint is %true, the caller should be - * holding @q->queue_lock and lookup hint is updated on success. - */ -static inline struct blkcg_gq *__blkg_lookup(struct blkcg *blkcg, - struct request_queue *q, - bool update_hint) -{ - struct blkcg_gq *blkg; - - if (blkcg == &blkcg_root) - return q->root_blkg; - - blkg = rcu_dereference(blkcg->blkg_hint); - if (blkg && blkg->q == q) - return blkg; - - return blkg_lookup_slowpath(blkcg, q, update_hint); -} - -/** - * blkg_lookup - lookup blkg for the specified blkcg - q pair - * @blkcg: blkcg of interest - * @q: request_queue of interest - * - * Lookup blkg for the @blkcg - @q pair. This function should be called - * under RCU read lock and is guaranteed to return %NULL if @q is bypassing - * - see blk_queue_bypass_start() for details. - */ -static inline struct blkcg_gq *blkg_lookup(struct blkcg *blkcg, - struct request_queue *q) -{ - WARN_ON_ONCE(!rcu_read_lock_held()); - - if (unlikely(blk_queue_bypass(q))) - return NULL; - return __blkg_lookup(blkcg, q, false); -} - -/** - * blkg_to_pdata - get policy private data - * @blkg: blkg of interest - * @pol: policy of interest - * - * Return pointer to private data associated with the @blkg-@pol pair. - */ -static inline struct blkg_policy_data *blkg_to_pd(struct blkcg_gq *blkg, - struct blkcg_policy *pol) -{ - return blkg ? blkg->pd[pol->plid] : NULL; -} - -static inline struct blkcg_policy_data *blkcg_to_cpd(struct blkcg *blkcg, - struct blkcg_policy *pol) -{ - return blkcg ? blkcg->cpd[pol->plid] : NULL; -} - -/** - * pdata_to_blkg - get blkg associated with policy private data - * @pd: policy private data of interest - * - * @pd is policy private data. Determine the blkg it's associated with. - */ -static inline struct blkcg_gq *pd_to_blkg(struct blkg_policy_data *pd) -{ - return pd ? pd->blkg : NULL; -} - -static inline struct blkcg *cpd_to_blkcg(struct blkcg_policy_data *cpd) -{ - return cpd ? cpd->blkcg : NULL; -} - -/** - * blkg_path - format cgroup path of blkg - * @blkg: blkg of interest - * @buf: target buffer - * @buflen: target buffer length - * - * Format the path of the cgroup of @blkg into @buf. - */ -static inline int blkg_path(struct blkcg_gq *blkg, char *buf, int buflen) -{ - return cgroup_path(blkg->blkcg->css.cgroup, buf, buflen); -} - -/** - * blkg_get - get a blkg reference - * @blkg: blkg to get - * - * The caller should be holding an existing reference. - */ -static inline void blkg_get(struct blkcg_gq *blkg) -{ - WARN_ON_ONCE(atomic_read(&blkg->refcnt) <= 0); - atomic_inc(&blkg->refcnt); -} - -void __blkg_release_rcu(struct rcu_head *rcu); - -/** - * blkg_put - put a blkg reference - * @blkg: blkg to put - */ -static inline void blkg_put(struct blkcg_gq *blkg) -{ - WARN_ON_ONCE(atomic_read(&blkg->refcnt) <= 0); - if (atomic_dec_and_test(&blkg->refcnt)) - call_rcu(&blkg->rcu_head, __blkg_release_rcu); -} - -/** - * blkg_for_each_descendant_pre - pre-order walk of a blkg's descendants - * @d_blkg: loop cursor pointing to the current descendant - * @pos_css: used for iteration - * @p_blkg: target blkg to walk descendants of - * - * Walk @c_blkg through the descendants of @p_blkg. Must be used with RCU - * read locked. If called under either blkcg or queue lock, the iteration - * is guaranteed to include all and only online blkgs. The caller may - * update @pos_css by calling css_rightmost_descendant() to skip subtree. - * @p_blkg is included in the iteration and the first node to be visited. - */ -#define blkg_for_each_descendant_pre(d_blkg, pos_css, p_blkg) \ - css_for_each_descendant_pre((pos_css), &(p_blkg)->blkcg->css) \ - if (((d_blkg) = __blkg_lookup(css_to_blkcg(pos_css), \ - (p_blkg)->q, false))) - -/** - * blkg_for_each_descendant_post - post-order walk of a blkg's descendants - * @d_blkg: loop cursor pointing to the current descendant - * @pos_css: used for iteration - * @p_blkg: target blkg to walk descendants of - * - * Similar to blkg_for_each_descendant_pre() but performs post-order - * traversal instead. Synchronization rules are the same. @p_blkg is - * included in the iteration and the last node to be visited. - */ -#define blkg_for_each_descendant_post(d_blkg, pos_css, p_blkg) \ - css_for_each_descendant_post((pos_css), &(p_blkg)->blkcg->css) \ - if (((d_blkg) = __blkg_lookup(css_to_blkcg(pos_css), \ - (p_blkg)->q, false))) - -/** - * blk_get_rl - get request_list to use - * @q: request_queue of interest - * @bio: bio which will be attached to the allocated request (may be %NULL) - * - * The caller wants to allocate a request from @q to use for @bio. Find - * the request_list to use and obtain a reference on it. Should be called - * under queue_lock. This function is guaranteed to return non-%NULL - * request_list. - */ -static inline struct request_list *blk_get_rl(struct request_queue *q, - struct bio *bio) -{ - struct blkcg *blkcg; - struct blkcg_gq *blkg; - - rcu_read_lock(); - - blkcg = bio_blkcg(bio); - - /* bypass blkg lookup and use @q->root_rl directly for root */ - if (blkcg == &blkcg_root) - goto root_rl; - - /* - * Try to use blkg->rl. blkg lookup may fail under memory pressure - * or if either the blkcg or queue is going away. Fall back to - * root_rl in such cases. - */ - blkg = blkg_lookup(blkcg, q); - if (unlikely(!blkg)) - goto root_rl; - - blkg_get(blkg); - rcu_read_unlock(); - return &blkg->rl; -root_rl: - rcu_read_unlock(); - return &q->root_rl; -} - -/** - * blk_put_rl - put request_list - * @rl: request_list to put - * - * Put the reference acquired by blk_get_rl(). Should be called under - * queue_lock. - */ -static inline void blk_put_rl(struct request_list *rl) -{ - if (rl->blkg->blkcg != &blkcg_root) - blkg_put(rl->blkg); -} - -/** - * blk_rq_set_rl - associate a request with a request_list - * @rq: request of interest - * @rl: target request_list - * - * Associate @rq with @rl so that accounting and freeing can know the - * request_list @rq came from. - */ -static inline void blk_rq_set_rl(struct request *rq, struct request_list *rl) -{ - rq->rl = rl; -} - -/** - * blk_rq_rl - return the request_list a request came from - * @rq: request of interest - * - * Return the request_list @rq is allocated from. - */ -static inline struct request_list *blk_rq_rl(struct request *rq) -{ - return rq->rl; -} - -struct request_list *__blk_queue_next_rl(struct request_list *rl, - struct request_queue *q); -/** - * blk_queue_for_each_rl - iterate through all request_lists of a request_queue - * - * Should be used under queue_lock. - */ -#define blk_queue_for_each_rl(rl, q) \ - for ((rl) = &(q)->root_rl; (rl); (rl) = __blk_queue_next_rl((rl), (q))) - -static inline int blkg_stat_init(struct blkg_stat *stat, gfp_t gfp) -{ - int ret; - - ret = percpu_counter_init(&stat->cpu_cnt, 0, gfp); - if (ret) - return ret; - - atomic64_set(&stat->aux_cnt, 0); - return 0; -} - -static inline void blkg_stat_exit(struct blkg_stat *stat) -{ - percpu_counter_destroy(&stat->cpu_cnt); -} - -/** - * blkg_stat_add - add a value to a blkg_stat - * @stat: target blkg_stat - * @val: value to add - * - * Add @val to @stat. The caller must ensure that IRQ on the same CPU - * don't re-enter this function for the same counter. - */ -static inline void blkg_stat_add(struct blkg_stat *stat, uint64_t val) -{ - __percpu_counter_add(&stat->cpu_cnt, val, BLKG_STAT_CPU_BATCH); -} - -/** - * blkg_stat_read - read the current value of a blkg_stat - * @stat: blkg_stat to read - */ -static inline uint64_t blkg_stat_read(struct blkg_stat *stat) -{ - return percpu_counter_sum_positive(&stat->cpu_cnt); -} - -/** - * blkg_stat_reset - reset a blkg_stat - * @stat: blkg_stat to reset - */ -static inline void blkg_stat_reset(struct blkg_stat *stat) -{ - percpu_counter_set(&stat->cpu_cnt, 0); - atomic64_set(&stat->aux_cnt, 0); -} - -/** - * blkg_stat_add_aux - add a blkg_stat into another's aux count - * @to: the destination blkg_stat - * @from: the source - * - * Add @from's count including the aux one to @to's aux count. - */ -static inline void blkg_stat_add_aux(struct blkg_stat *to, - struct blkg_stat *from) -{ - atomic64_add(blkg_stat_read(from) + atomic64_read(&from->aux_cnt), - &to->aux_cnt); -} - -static inline int blkg_rwstat_init(struct blkg_rwstat *rwstat, gfp_t gfp) -{ - int i, ret; - - for (i = 0; i < BLKG_RWSTAT_NR; i++) { - ret = percpu_counter_init(&rwstat->cpu_cnt[i], 0, gfp); - if (ret) { - while (--i >= 0) - percpu_counter_destroy(&rwstat->cpu_cnt[i]); - return ret; - } - atomic64_set(&rwstat->aux_cnt[i], 0); - } - return 0; -} - -static inline void blkg_rwstat_exit(struct blkg_rwstat *rwstat) -{ - int i; - - for (i = 0; i < BLKG_RWSTAT_NR; i++) - percpu_counter_destroy(&rwstat->cpu_cnt[i]); -} - -/** - * blkg_rwstat_add - add a value to a blkg_rwstat - * @rwstat: target blkg_rwstat - * @op: REQ_OP - * @op_flags: rq_flag_bits - * @val: value to add - * - * Add @val to @rwstat. The counters are chosen according to @rw. The - * caller is responsible for synchronizing calls to this function. - */ -static inline void blkg_rwstat_add(struct blkg_rwstat *rwstat, - int op, int op_flags, uint64_t val) -{ - struct percpu_counter *cnt; - - if (op_is_write(op)) - cnt = &rwstat->cpu_cnt[BLKG_RWSTAT_WRITE]; - else - cnt = &rwstat->cpu_cnt[BLKG_RWSTAT_READ]; - - __percpu_counter_add(cnt, val, BLKG_STAT_CPU_BATCH); - - if (op_flags & REQ_SYNC) - cnt = &rwstat->cpu_cnt[BLKG_RWSTAT_SYNC]; - else - cnt = &rwstat->cpu_cnt[BLKG_RWSTAT_ASYNC]; - - __percpu_counter_add(cnt, val, BLKG_STAT_CPU_BATCH); -} - -/** - * blkg_rwstat_read - read the current values of a blkg_rwstat - * @rwstat: blkg_rwstat to read - * - * Read the current snapshot of @rwstat and return it in the aux counts. - */ -static inline struct blkg_rwstat blkg_rwstat_read(struct blkg_rwstat *rwstat) -{ - struct blkg_rwstat result; - int i; - - for (i = 0; i < BLKG_RWSTAT_NR; i++) - atomic64_set(&result.aux_cnt[i], - percpu_counter_sum_positive(&rwstat->cpu_cnt[i])); - return result; -} - -/** - * blkg_rwstat_total - read the total count of a blkg_rwstat - * @rwstat: blkg_rwstat to read - * - * Return the total count of @rwstat regardless of the IO direction. This - * function can be called without synchronization and takes care of u64 - * atomicity. - */ -static inline uint64_t blkg_rwstat_total(struct blkg_rwstat *rwstat) -{ - struct blkg_rwstat tmp = blkg_rwstat_read(rwstat); - - return atomic64_read(&tmp.aux_cnt[BLKG_RWSTAT_READ]) + - atomic64_read(&tmp.aux_cnt[BLKG_RWSTAT_WRITE]); -} - -/** - * blkg_rwstat_reset - reset a blkg_rwstat - * @rwstat: blkg_rwstat to reset - */ -static inline void blkg_rwstat_reset(struct blkg_rwstat *rwstat) -{ - int i; - - for (i = 0; i < BLKG_RWSTAT_NR; i++) { - percpu_counter_set(&rwstat->cpu_cnt[i], 0); - atomic64_set(&rwstat->aux_cnt[i], 0); - } -} - -/** - * blkg_rwstat_add_aux - add a blkg_rwstat into another's aux count - * @to: the destination blkg_rwstat - * @from: the source - * - * Add @from's count including the aux one to @to's aux count. - */ -static inline void blkg_rwstat_add_aux(struct blkg_rwstat *to, - struct blkg_rwstat *from) -{ - struct blkg_rwstat v = blkg_rwstat_read(from); - int i; - - for (i = 0; i < BLKG_RWSTAT_NR; i++) - atomic64_add(atomic64_read(&v.aux_cnt[i]) + - atomic64_read(&from->aux_cnt[i]), - &to->aux_cnt[i]); -} - -#ifdef CONFIG_BLK_DEV_THROTTLING -extern bool blk_throtl_bio(struct request_queue *q, struct blkcg_gq *blkg, - struct bio *bio); -#else -static inline bool blk_throtl_bio(struct request_queue *q, struct blkcg_gq *blkg, - struct bio *bio) { return false; } -#endif - -static inline bool blkcg_bio_issue_check(struct request_queue *q, - struct bio *bio) -{ - struct blkcg *blkcg; - struct blkcg_gq *blkg; - bool throtl = false; - - rcu_read_lock(); - blkcg = bio_blkcg(bio); - - blkg = blkg_lookup(blkcg, q); - if (unlikely(!blkg)) { - spin_lock_irq(q->queue_lock); - blkg = blkg_lookup_create(blkcg, q); - if (IS_ERR(blkg)) - blkg = NULL; - spin_unlock_irq(q->queue_lock); - } - - throtl = blk_throtl_bio(q, blkg, bio); - - if (!throtl) { - blkg = blkg ?: q->root_blkg; - blkg_rwstat_add(&blkg->stat_bytes, bio_op(bio), bio->bi_opf, - bio->bi_iter.bi_size); - blkg_rwstat_add(&blkg->stat_ios, bio_op(bio), bio->bi_opf, 1); - } - - rcu_read_unlock(); - return !throtl; -} - -#else /* CONFIG_BLK_CGROUP */ - -struct blkcg { -}; - -struct blkg_policy_data { -}; - -struct blkcg_policy_data { -}; - -struct blkcg_gq { -}; - -struct blkcg_policy { -}; - -#define blkcg_root_css ((struct cgroup_subsys_state *)ERR_PTR(-EINVAL)) - -static inline struct cgroup_subsys_state * -task_get_blkcg_css(struct task_struct *task) -{ - return NULL; -} - -#ifdef CONFIG_BLOCK - -static inline struct blkcg_gq *blkg_lookup(struct blkcg *blkcg, void *key) { return NULL; } -static inline int blkcg_init_queue(struct request_queue *q) { return 0; } -static inline void blkcg_drain_queue(struct request_queue *q) { } -static inline void blkcg_exit_queue(struct request_queue *q) { } -static inline int blkcg_policy_register(struct blkcg_policy *pol) { return 0; } -static inline void blkcg_policy_unregister(struct blkcg_policy *pol) { } -static inline int blkcg_activate_policy(struct request_queue *q, - const struct blkcg_policy *pol) { return 0; } -static inline void blkcg_deactivate_policy(struct request_queue *q, - const struct blkcg_policy *pol) { } - -static inline struct blkcg *bio_blkcg(struct bio *bio) { return NULL; } - -static inline struct blkg_policy_data *blkg_to_pd(struct blkcg_gq *blkg, - struct blkcg_policy *pol) { return NULL; } -static inline struct blkcg_gq *pd_to_blkg(struct blkg_policy_data *pd) { return NULL; } -static inline char *blkg_path(struct blkcg_gq *blkg) { return NULL; } -static inline void blkg_get(struct blkcg_gq *blkg) { } -static inline void blkg_put(struct blkcg_gq *blkg) { } - -static inline struct request_list *blk_get_rl(struct request_queue *q, - struct bio *bio) { return &q->root_rl; } -static inline void blk_put_rl(struct request_list *rl) { } -static inline void blk_rq_set_rl(struct request *rq, struct request_list *rl) { } -static inline struct request_list *blk_rq_rl(struct request *rq) { return &rq->q->root_rl; } - -static inline bool blkcg_bio_issue_check(struct request_queue *q, - struct bio *bio) { return true; } - -#define blk_queue_for_each_rl(rl, q) \ - for ((rl) = &(q)->root_rl; (rl); (rl) = NULL) - -#endif /* CONFIG_BLOCK */ -#endif /* CONFIG_BLK_CGROUP */ -#endif /* _BLK_CGROUP_H */ diff --git a/src/linux/include/linux/blk-mq.h b/src/linux/include/linux/blk-mq.h deleted file mode 100644 index 535ab2e..0000000 --- a/src/linux/include/linux/blk-mq.h +++ /dev/null @@ -1,263 +0,0 @@ -#ifndef BLK_MQ_H -#define BLK_MQ_H - -#include -#include - -struct blk_mq_tags; -struct blk_flush_queue; - -struct blk_mq_hw_ctx { - struct { - spinlock_t lock; - struct list_head dispatch; - unsigned long state; /* BLK_MQ_S_* flags */ - } ____cacheline_aligned_in_smp; - - struct work_struct run_work; - cpumask_var_t cpumask; - int next_cpu; - int next_cpu_batch; - - unsigned long flags; /* BLK_MQ_F_* flags */ - - struct request_queue *queue; - struct blk_flush_queue *fq; - - void *driver_data; - - struct sbitmap ctx_map; - - struct blk_mq_ctx **ctxs; - unsigned int nr_ctx; - - atomic_t wait_index; - - struct blk_mq_tags *tags; - - unsigned long queued; - unsigned long run; -#define BLK_MQ_MAX_DISPATCH_ORDER 7 - unsigned long dispatched[BLK_MQ_MAX_DISPATCH_ORDER]; - - unsigned int numa_node; - unsigned int queue_num; - - atomic_t nr_active; - - struct delayed_work delay_work; - - struct hlist_node cpuhp_dead; - struct kobject kobj; - - unsigned long poll_considered; - unsigned long poll_invoked; - unsigned long poll_success; -}; - -struct blk_mq_tag_set { - unsigned int *mq_map; - struct blk_mq_ops *ops; - unsigned int nr_hw_queues; - unsigned int queue_depth; /* max hw supported */ - unsigned int reserved_tags; - unsigned int cmd_size; /* per-request extra data */ - int numa_node; - unsigned int timeout; - unsigned int flags; /* BLK_MQ_F_* */ - void *driver_data; - - struct blk_mq_tags **tags; - - struct mutex tag_list_lock; - struct list_head tag_list; -}; - -struct blk_mq_queue_data { - struct request *rq; - struct list_head *list; - bool last; -}; - -typedef int (queue_rq_fn)(struct blk_mq_hw_ctx *, const struct blk_mq_queue_data *); -typedef enum blk_eh_timer_return (timeout_fn)(struct request *, bool); -typedef int (init_hctx_fn)(struct blk_mq_hw_ctx *, void *, unsigned int); -typedef void (exit_hctx_fn)(struct blk_mq_hw_ctx *, unsigned int); -typedef int (init_request_fn)(void *, struct request *, unsigned int, - unsigned int, unsigned int); -typedef void (exit_request_fn)(void *, struct request *, unsigned int, - unsigned int); -typedef int (reinit_request_fn)(void *, struct request *); - -typedef void (busy_iter_fn)(struct blk_mq_hw_ctx *, struct request *, void *, - bool); -typedef void (busy_tag_iter_fn)(struct request *, void *, bool); -typedef int (poll_fn)(struct blk_mq_hw_ctx *, unsigned int); -typedef int (map_queues_fn)(struct blk_mq_tag_set *set); - - -struct blk_mq_ops { - /* - * Queue request - */ - queue_rq_fn *queue_rq; - - /* - * Called on request timeout - */ - timeout_fn *timeout; - - /* - * Called to poll for completion of a specific tag. - */ - poll_fn *poll; - - softirq_done_fn *complete; - - /* - * Called when the block layer side of a hardware queue has been - * set up, allowing the driver to allocate/init matching structures. - * Ditto for exit/teardown. - */ - init_hctx_fn *init_hctx; - exit_hctx_fn *exit_hctx; - - /* - * Called for every command allocated by the block layer to allow - * the driver to set up driver specific data. - * - * Tag greater than or equal to queue_depth is for setting up - * flush request. - * - * Ditto for exit/teardown. - */ - init_request_fn *init_request; - exit_request_fn *exit_request; - reinit_request_fn *reinit_request; - - map_queues_fn *map_queues; -}; - -enum { - BLK_MQ_RQ_QUEUE_OK = 0, /* queued fine */ - BLK_MQ_RQ_QUEUE_BUSY = 1, /* requeue IO for later */ - BLK_MQ_RQ_QUEUE_ERROR = 2, /* end IO with error */ - - BLK_MQ_F_SHOULD_MERGE = 1 << 0, - BLK_MQ_F_TAG_SHARED = 1 << 1, - BLK_MQ_F_SG_MERGE = 1 << 2, - BLK_MQ_F_DEFER_ISSUE = 1 << 4, - BLK_MQ_F_BLOCKING = 1 << 5, - BLK_MQ_F_ALLOC_POLICY_START_BIT = 8, - BLK_MQ_F_ALLOC_POLICY_BITS = 1, - - BLK_MQ_S_STOPPED = 0, - BLK_MQ_S_TAG_ACTIVE = 1, - - BLK_MQ_MAX_DEPTH = 10240, - - BLK_MQ_CPU_WORK_BATCH = 8, -}; -#define BLK_MQ_FLAG_TO_ALLOC_POLICY(flags) \ - ((flags >> BLK_MQ_F_ALLOC_POLICY_START_BIT) & \ - ((1 << BLK_MQ_F_ALLOC_POLICY_BITS) - 1)) -#define BLK_ALLOC_POLICY_TO_MQ_FLAG(policy) \ - ((policy & ((1 << BLK_MQ_F_ALLOC_POLICY_BITS) - 1)) \ - << BLK_MQ_F_ALLOC_POLICY_START_BIT) - -struct request_queue *blk_mq_init_queue(struct blk_mq_tag_set *); -struct request_queue *blk_mq_init_allocated_queue(struct blk_mq_tag_set *set, - struct request_queue *q); -int blk_mq_register_dev(struct device *, struct request_queue *); -void blk_mq_unregister_dev(struct device *, struct request_queue *); - -int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set); -void blk_mq_free_tag_set(struct blk_mq_tag_set *set); - -void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule); - -void blk_mq_insert_request(struct request *, bool, bool, bool); -void blk_mq_free_request(struct request *rq); -void blk_mq_free_hctx_request(struct blk_mq_hw_ctx *, struct request *rq); -bool blk_mq_can_queue(struct blk_mq_hw_ctx *); - -enum { - BLK_MQ_REQ_NOWAIT = (1 << 0), /* return when out of requests */ - BLK_MQ_REQ_RESERVED = (1 << 1), /* allocate from reserved pool */ -}; - -struct request *blk_mq_alloc_request(struct request_queue *q, int rw, - unsigned int flags); -struct request *blk_mq_alloc_request_hctx(struct request_queue *q, int op, - unsigned int flags, unsigned int hctx_idx); -struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag); - -enum { - BLK_MQ_UNIQUE_TAG_BITS = 16, - BLK_MQ_UNIQUE_TAG_MASK = (1 << BLK_MQ_UNIQUE_TAG_BITS) - 1, -}; - -u32 blk_mq_unique_tag(struct request *rq); - -static inline u16 blk_mq_unique_tag_to_hwq(u32 unique_tag) -{ - return unique_tag >> BLK_MQ_UNIQUE_TAG_BITS; -} - -static inline u16 blk_mq_unique_tag_to_tag(u32 unique_tag) -{ - return unique_tag & BLK_MQ_UNIQUE_TAG_MASK; -} - - -int blk_mq_request_started(struct request *rq); -void blk_mq_start_request(struct request *rq); -void blk_mq_end_request(struct request *rq, int error); -void __blk_mq_end_request(struct request *rq, int error); - -void blk_mq_requeue_request(struct request *rq); -void blk_mq_add_to_requeue_list(struct request *rq, bool at_head); -void blk_mq_cancel_requeue_work(struct request_queue *q); -void blk_mq_kick_requeue_list(struct request_queue *q); -void blk_mq_delay_kick_requeue_list(struct request_queue *q, unsigned long msecs); -void blk_mq_abort_requeue_list(struct request_queue *q); -void blk_mq_complete_request(struct request *rq, int error); - -void blk_mq_stop_hw_queue(struct blk_mq_hw_ctx *hctx); -void blk_mq_start_hw_queue(struct blk_mq_hw_ctx *hctx); -void blk_mq_stop_hw_queues(struct request_queue *q); -void blk_mq_start_hw_queues(struct request_queue *q); -void blk_mq_start_stopped_hw_queues(struct request_queue *q, bool async); -void blk_mq_run_hw_queues(struct request_queue *q, bool async); -void blk_mq_delay_queue(struct blk_mq_hw_ctx *hctx, unsigned long msecs); -void blk_mq_tagset_busy_iter(struct blk_mq_tag_set *tagset, - busy_tag_iter_fn *fn, void *priv); -void blk_mq_freeze_queue(struct request_queue *q); -void blk_mq_unfreeze_queue(struct request_queue *q); -void blk_mq_freeze_queue_start(struct request_queue *q); -int blk_mq_reinit_tagset(struct blk_mq_tag_set *set); - -void blk_mq_update_nr_hw_queues(struct blk_mq_tag_set *set, int nr_hw_queues); - -/* - * Driver command data is immediately after the request. So subtract request - * size to get back to the original request, add request size to get the PDU. - */ -static inline struct request *blk_mq_rq_from_pdu(void *pdu) -{ - return pdu - sizeof(struct request); -} -static inline void *blk_mq_rq_to_pdu(struct request *rq) -{ - return rq + 1; -} - -#define queue_for_each_hw_ctx(q, hctx, i) \ - for ((i) = 0; (i) < (q)->nr_hw_queues && \ - ({ hctx = (q)->queue_hw_ctx[i]; 1; }); (i)++) - -#define hctx_for_each_ctx(hctx, ctx, i) \ - for ((i) = 0; (i) < (hctx)->nr_ctx && \ - ({ ctx = (hctx)->ctxs[(i)]; 1; }); (i)++) - -#endif diff --git a/src/linux/include/linux/blk_types.h b/src/linux/include/linux/blk_types.h deleted file mode 100644 index cd395ec..0000000 --- a/src/linux/include/linux/blk_types.h +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Block data types and constants. Directly include this file only to - * break include dependency loop. - */ -#ifndef __LINUX_BLK_TYPES_H -#define __LINUX_BLK_TYPES_H - -#include -#include - -struct bio_set; -struct bio; -struct bio_integrity_payload; -struct page; -struct block_device; -struct io_context; -struct cgroup_subsys_state; -typedef void (bio_end_io_t) (struct bio *); - -#ifdef CONFIG_BLOCK -/* - * main unit of I/O for the block layer and lower layers (ie drivers and - * stacking drivers) - */ -struct bio { - struct bio *bi_next; /* request queue link */ - struct block_device *bi_bdev; - int bi_error; - unsigned int bi_opf; /* bottom bits req flags, - * top bits REQ_OP. Use - * accessors. - */ - unsigned short bi_flags; /* status, command, etc */ - unsigned short bi_ioprio; - - struct bvec_iter bi_iter; - - /* Number of segments in this BIO after - * physical address coalescing is performed. - */ - unsigned int bi_phys_segments; - - /* - * To keep track of the max segment size, we account for the - * sizes of the first and last mergeable segments in this bio. - */ - unsigned int bi_seg_front_size; - unsigned int bi_seg_back_size; - - atomic_t __bi_remaining; - - bio_end_io_t *bi_end_io; - - void *bi_private; -#ifdef CONFIG_BLK_CGROUP - /* - * Optional ioc and css associated with this bio. Put on bio - * release. Read comment on top of bio_associate_current(). - */ - struct io_context *bi_ioc; - struct cgroup_subsys_state *bi_css; -#endif - union { -#if defined(CONFIG_BLK_DEV_INTEGRITY) - struct bio_integrity_payload *bi_integrity; /* data integrity */ -#endif - }; - - unsigned short bi_vcnt; /* how many bio_vec's */ - - /* - * Everything starting with bi_max_vecs will be preserved by bio_reset() - */ - - unsigned short bi_max_vecs; /* max bvl_vecs we can hold */ - - atomic_t __bi_cnt; /* pin count */ - - struct bio_vec *bi_io_vec; /* the actual vec list */ - - struct bio_set *bi_pool; - - /* - * We can inline a number of vecs at the end of the bio, to avoid - * double allocations for a small number of bio_vecs. This member - * MUST obviously be kept at the very end of the bio. - */ - struct bio_vec bi_inline_vecs[0]; -}; - -#define BIO_OP_SHIFT (8 * FIELD_SIZEOF(struct bio, bi_opf) - REQ_OP_BITS) -#define bio_flags(bio) ((bio)->bi_opf & ((1 << BIO_OP_SHIFT) - 1)) -#define bio_op(bio) ((bio)->bi_opf >> BIO_OP_SHIFT) - -#define bio_set_op_attrs(bio, op, op_flags) do { \ - if (__builtin_constant_p(op)) \ - BUILD_BUG_ON((op) + 0U >= (1U << REQ_OP_BITS)); \ - else \ - WARN_ON_ONCE((op) + 0U >= (1U << REQ_OP_BITS)); \ - if (__builtin_constant_p(op_flags)) \ - BUILD_BUG_ON((op_flags) + 0U >= (1U << BIO_OP_SHIFT)); \ - else \ - WARN_ON_ONCE((op_flags) + 0U >= (1U << BIO_OP_SHIFT)); \ - (bio)->bi_opf = bio_flags(bio); \ - (bio)->bi_opf |= (((op) + 0U) << BIO_OP_SHIFT); \ - (bio)->bi_opf |= (op_flags); \ -} while (0) - -#define BIO_RESET_BYTES offsetof(struct bio, bi_max_vecs) - -/* - * bio flags - */ -#define BIO_SEG_VALID 1 /* bi_phys_segments valid */ -#define BIO_CLONED 2 /* doesn't own data */ -#define BIO_BOUNCED 3 /* bio is a bounce bio */ -#define BIO_USER_MAPPED 4 /* contains user pages */ -#define BIO_NULL_MAPPED 5 /* contains invalid user pages */ -#define BIO_QUIET 6 /* Make BIO Quiet */ -#define BIO_CHAIN 7 /* chained bio, ->bi_remaining in effect */ -#define BIO_REFFED 8 /* bio has elevated ->bi_cnt */ - -/* - * Flags starting here get preserved by bio_reset() - this includes - * BVEC_POOL_IDX() - */ -#define BIO_RESET_BITS 10 - -/* - * We support 6 different bvec pools, the last one is magic in that it - * is backed by a mempool. - */ -#define BVEC_POOL_NR 6 -#define BVEC_POOL_MAX (BVEC_POOL_NR - 1) - -/* - * Top 4 bits of bio flags indicate the pool the bvecs came from. We add - * 1 to the actual index so that 0 indicates that there are no bvecs to be - * freed. - */ -#define BVEC_POOL_BITS (4) -#define BVEC_POOL_OFFSET (16 - BVEC_POOL_BITS) -#define BVEC_POOL_IDX(bio) ((bio)->bi_flags >> BVEC_POOL_OFFSET) - -#endif /* CONFIG_BLOCK */ - -/* - * Request flags. For use in the cmd_flags field of struct request, and in - * bi_opf of struct bio. Note that some flags are only valid in either one. - */ -enum rq_flag_bits { - /* common flags */ - __REQ_FAILFAST_DEV, /* no driver retries of device errors */ - __REQ_FAILFAST_TRANSPORT, /* no driver retries of transport errors */ - __REQ_FAILFAST_DRIVER, /* no driver retries of driver errors */ - - __REQ_SYNC, /* request is sync (sync write or read) */ - __REQ_META, /* metadata io request */ - __REQ_PRIO, /* boost priority in cfq */ - - __REQ_NOIDLE, /* don't anticipate more IO after this one */ - __REQ_INTEGRITY, /* I/O includes block integrity payload */ - __REQ_FUA, /* forced unit access */ - __REQ_PREFLUSH, /* request for cache flush */ - - /* bio only flags */ - __REQ_RAHEAD, /* read ahead, can fail anytime */ - __REQ_THROTTLED, /* This bio has already been subjected to - * throttling rules. Don't do it again. */ - - /* request only flags */ - __REQ_SORTED, /* elevator knows about this request */ - __REQ_SOFTBARRIER, /* may not be passed by ioscheduler */ - __REQ_NOMERGE, /* don't touch this for merging */ - __REQ_STARTED, /* drive already may have started this one */ - __REQ_DONTPREP, /* don't call prep for this one */ - __REQ_QUEUED, /* uses queueing */ - __REQ_ELVPRIV, /* elevator private data attached */ - __REQ_FAILED, /* set if the request failed */ - __REQ_QUIET, /* don't worry about errors */ - __REQ_PREEMPT, /* set for "ide_preempt" requests and also - for requests for which the SCSI "quiesce" - state must be ignored. */ - __REQ_ALLOCED, /* request came from our alloc pool */ - __REQ_COPY_USER, /* contains copies of user pages */ - __REQ_FLUSH_SEQ, /* request for flush sequence */ - __REQ_IO_STAT, /* account I/O stat */ - __REQ_MIXED_MERGE, /* merge of different types, fail separately */ - __REQ_PM, /* runtime pm request */ - __REQ_HASHED, /* on IO scheduler merge hash */ - __REQ_MQ_INFLIGHT, /* track inflight for MQ */ - __REQ_NR_BITS, /* stops here */ -}; - -#define REQ_FAILFAST_DEV (1ULL << __REQ_FAILFAST_DEV) -#define REQ_FAILFAST_TRANSPORT (1ULL << __REQ_FAILFAST_TRANSPORT) -#define REQ_FAILFAST_DRIVER (1ULL << __REQ_FAILFAST_DRIVER) -#define REQ_SYNC (1ULL << __REQ_SYNC) -#define REQ_META (1ULL << __REQ_META) -#define REQ_PRIO (1ULL << __REQ_PRIO) -#define REQ_NOIDLE (1ULL << __REQ_NOIDLE) -#define REQ_INTEGRITY (1ULL << __REQ_INTEGRITY) - -#define REQ_FAILFAST_MASK \ - (REQ_FAILFAST_DEV | REQ_FAILFAST_TRANSPORT | REQ_FAILFAST_DRIVER) -#define REQ_COMMON_MASK \ - (REQ_FAILFAST_MASK | REQ_SYNC | REQ_META | REQ_PRIO | REQ_NOIDLE | \ - REQ_PREFLUSH | REQ_FUA | REQ_INTEGRITY | REQ_NOMERGE) -#define REQ_CLONE_MASK REQ_COMMON_MASK - -/* This mask is used for both bio and request merge checking */ -#define REQ_NOMERGE_FLAGS \ - (REQ_NOMERGE | REQ_STARTED | REQ_SOFTBARRIER | REQ_PREFLUSH | REQ_FUA | REQ_FLUSH_SEQ) - -#define REQ_RAHEAD (1ULL << __REQ_RAHEAD) -#define REQ_THROTTLED (1ULL << __REQ_THROTTLED) - -#define REQ_SORTED (1ULL << __REQ_SORTED) -#define REQ_SOFTBARRIER (1ULL << __REQ_SOFTBARRIER) -#define REQ_FUA (1ULL << __REQ_FUA) -#define REQ_NOMERGE (1ULL << __REQ_NOMERGE) -#define REQ_STARTED (1ULL << __REQ_STARTED) -#define REQ_DONTPREP (1ULL << __REQ_DONTPREP) -#define REQ_QUEUED (1ULL << __REQ_QUEUED) -#define REQ_ELVPRIV (1ULL << __REQ_ELVPRIV) -#define REQ_FAILED (1ULL << __REQ_FAILED) -#define REQ_QUIET (1ULL << __REQ_QUIET) -#define REQ_PREEMPT (1ULL << __REQ_PREEMPT) -#define REQ_ALLOCED (1ULL << __REQ_ALLOCED) -#define REQ_COPY_USER (1ULL << __REQ_COPY_USER) -#define REQ_PREFLUSH (1ULL << __REQ_PREFLUSH) -#define REQ_FLUSH_SEQ (1ULL << __REQ_FLUSH_SEQ) -#define REQ_IO_STAT (1ULL << __REQ_IO_STAT) -#define REQ_MIXED_MERGE (1ULL << __REQ_MIXED_MERGE) -#define REQ_PM (1ULL << __REQ_PM) -#define REQ_HASHED (1ULL << __REQ_HASHED) -#define REQ_MQ_INFLIGHT (1ULL << __REQ_MQ_INFLIGHT) - -enum req_op { - REQ_OP_READ, - REQ_OP_WRITE, - REQ_OP_DISCARD, /* request to discard sectors */ - REQ_OP_SECURE_ERASE, /* request to securely erase sectors */ - REQ_OP_WRITE_SAME, /* write same block many times */ - REQ_OP_FLUSH, /* request for cache flush */ -}; - -#define REQ_OP_BITS 3 - -typedef unsigned int blk_qc_t; -#define BLK_QC_T_NONE -1U -#define BLK_QC_T_SHIFT 16 - -static inline bool blk_qc_t_valid(blk_qc_t cookie) -{ - return cookie != BLK_QC_T_NONE; -} - -static inline blk_qc_t blk_tag_to_qc_t(unsigned int tag, unsigned int queue_num) -{ - return tag | (queue_num << BLK_QC_T_SHIFT); -} - -static inline unsigned int blk_qc_t_to_queue_num(blk_qc_t cookie) -{ - return cookie >> BLK_QC_T_SHIFT; -} - -static inline unsigned int blk_qc_t_to_tag(blk_qc_t cookie) -{ - return cookie & ((1u << BLK_QC_T_SHIFT) - 1); -} - -#endif /* __LINUX_BLK_TYPES_H */ diff --git a/src/linux/include/linux/blkdev.h b/src/linux/include/linux/blkdev.h deleted file mode 100644 index c47c358..0000000 --- a/src/linux/include/linux/blkdev.h +++ /dev/null @@ -1,1750 +0,0 @@ -#ifndef _LINUX_BLKDEV_H -#define _LINUX_BLKDEV_H - -#include - -#ifdef CONFIG_BLOCK - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct module; -struct scsi_ioctl_command; - -struct request_queue; -struct elevator_queue; -struct blk_trace; -struct request; -struct sg_io_hdr; -struct bsg_job; -struct blkcg_gq; -struct blk_flush_queue; -struct pr_ops; - -#define BLKDEV_MIN_RQ 4 -#define BLKDEV_MAX_RQ 128 /* Default maximum */ - -/* - * Maximum number of blkcg policies allowed to be registered concurrently. - * Defined here to simplify include dependency. - */ -#define BLKCG_MAX_POLS 2 - -typedef void (rq_end_io_fn)(struct request *, int); - -#define BLK_RL_SYNCFULL (1U << 0) -#define BLK_RL_ASYNCFULL (1U << 1) - -struct request_list { - struct request_queue *q; /* the queue this rl belongs to */ -#ifdef CONFIG_BLK_CGROUP - struct blkcg_gq *blkg; /* blkg this request pool belongs to */ -#endif - /* - * count[], starved[], and wait[] are indexed by - * BLK_RW_SYNC/BLK_RW_ASYNC - */ - int count[2]; - int starved[2]; - mempool_t *rq_pool; - wait_queue_head_t wait[2]; - unsigned int flags; -}; - -/* - * request command types - */ -enum rq_cmd_type_bits { - REQ_TYPE_FS = 1, /* fs request */ - REQ_TYPE_BLOCK_PC, /* scsi command */ - REQ_TYPE_DRV_PRIV, /* driver defined types from here */ -}; - -#define BLK_MAX_CDB 16 - -/* - * Try to put the fields that are referenced together in the same cacheline. - * - * If you modify this structure, make sure to update blk_rq_init() and - * especially blk_mq_rq_ctx_init() to take care of the added fields. - */ -struct request { - struct list_head queuelist; - union { - struct call_single_data csd; - u64 fifo_time; - }; - - struct request_queue *q; - struct blk_mq_ctx *mq_ctx; - - int cpu; - unsigned cmd_type; - u64 cmd_flags; - unsigned long atomic_flags; - - /* the following two fields are internal, NEVER access directly */ - unsigned int __data_len; /* total data len */ - sector_t __sector; /* sector cursor */ - - struct bio *bio; - struct bio *biotail; - - /* - * The hash is used inside the scheduler, and killed once the - * request reaches the dispatch list. The ipi_list is only used - * to queue the request for softirq completion, which is long - * after the request has been unhashed (and even removed from - * the dispatch list). - */ - union { - struct hlist_node hash; /* merge hash */ - struct list_head ipi_list; - }; - - /* - * The rb_node is only used inside the io scheduler, requests - * are pruned when moved to the dispatch queue. So let the - * completion_data share space with the rb_node. - */ - union { - struct rb_node rb_node; /* sort/lookup */ - void *completion_data; - }; - - /* - * Three pointers are available for the IO schedulers, if they need - * more they have to dynamically allocate it. Flush requests are - * never put on the IO scheduler. So let the flush fields share - * space with the elevator data. - */ - union { - struct { - struct io_cq *icq; - void *priv[2]; - } elv; - - struct { - unsigned int seq; - struct list_head list; - rq_end_io_fn *saved_end_io; - } flush; - }; - - struct gendisk *rq_disk; - struct hd_struct *part; - unsigned long start_time; -#ifdef CONFIG_BLK_CGROUP - struct request_list *rl; /* rl this rq is alloced from */ - unsigned long long start_time_ns; - unsigned long long io_start_time_ns; /* when passed to hardware */ -#endif - /* Number of scatter-gather DMA addr+len pairs after - * physical address coalescing is performed. - */ - unsigned short nr_phys_segments; -#if defined(CONFIG_BLK_DEV_INTEGRITY) - unsigned short nr_integrity_segments; -#endif - - unsigned short ioprio; - - void *special; /* opaque pointer available for LLD use */ - - int tag; - int errors; - - /* - * when request is used as a packet command carrier - */ - unsigned char __cmd[BLK_MAX_CDB]; - unsigned char *cmd; - unsigned short cmd_len; - - unsigned int extra_len; /* length of alignment and padding */ - unsigned int sense_len; - unsigned int resid_len; /* residual count */ - void *sense; - - unsigned long deadline; - struct list_head timeout_list; - unsigned int timeout; - int retries; - - /* - * completion callback. - */ - rq_end_io_fn *end_io; - void *end_io_data; - - /* for bidi */ - struct request *next_rq; -}; - -#define REQ_OP_SHIFT (8 * sizeof(u64) - REQ_OP_BITS) -#define req_op(req) ((req)->cmd_flags >> REQ_OP_SHIFT) - -#define req_set_op(req, op) do { \ - WARN_ON(op >= (1 << REQ_OP_BITS)); \ - (req)->cmd_flags &= ((1ULL << REQ_OP_SHIFT) - 1); \ - (req)->cmd_flags |= ((u64) (op) << REQ_OP_SHIFT); \ -} while (0) - -#define req_set_op_attrs(req, op, flags) do { \ - req_set_op(req, op); \ - (req)->cmd_flags |= flags; \ -} while (0) - -static inline unsigned short req_get_ioprio(struct request *req) -{ - return req->ioprio; -} - -#include - -struct blk_queue_ctx; - -typedef void (request_fn_proc) (struct request_queue *q); -typedef blk_qc_t (make_request_fn) (struct request_queue *q, struct bio *bio); -typedef int (prep_rq_fn) (struct request_queue *, struct request *); -typedef void (unprep_rq_fn) (struct request_queue *, struct request *); - -struct bio_vec; -typedef void (softirq_done_fn)(struct request *); -typedef int (dma_drain_needed_fn)(struct request *); -typedef int (lld_busy_fn) (struct request_queue *q); -typedef int (bsg_job_fn) (struct bsg_job *); - -enum blk_eh_timer_return { - BLK_EH_NOT_HANDLED, - BLK_EH_HANDLED, - BLK_EH_RESET_TIMER, -}; - -typedef enum blk_eh_timer_return (rq_timed_out_fn)(struct request *); - -enum blk_queue_state { - Queue_down, - Queue_up, -}; - -struct blk_queue_tag { - struct request **tag_index; /* map of busy tags */ - unsigned long *tag_map; /* bit map of free/busy tags */ - int busy; /* current depth */ - int max_depth; /* what we will send to device */ - int real_max_depth; /* what the array can hold */ - atomic_t refcnt; /* map can be shared */ - int alloc_policy; /* tag allocation policy */ - int next_tag; /* next tag */ -}; -#define BLK_TAG_ALLOC_FIFO 0 /* allocate starting from 0 */ -#define BLK_TAG_ALLOC_RR 1 /* allocate starting from last allocated tag */ - -#define BLK_SCSI_MAX_CMDS (256) -#define BLK_SCSI_CMD_PER_LONG (BLK_SCSI_MAX_CMDS / (sizeof(long) * 8)) - -struct queue_limits { - unsigned long bounce_pfn; - unsigned long seg_boundary_mask; - unsigned long virt_boundary_mask; - - unsigned int max_hw_sectors; - unsigned int max_dev_sectors; - unsigned int chunk_sectors; - unsigned int max_sectors; - unsigned int max_segment_size; - unsigned int physical_block_size; - unsigned int alignment_offset; - unsigned int io_min; - unsigned int io_opt; - unsigned int max_discard_sectors; - unsigned int max_hw_discard_sectors; - unsigned int max_write_same_sectors; - unsigned int discard_granularity; - unsigned int discard_alignment; - - unsigned short logical_block_size; - unsigned short max_segments; - unsigned short max_integrity_segments; - - unsigned char misaligned; - unsigned char discard_misaligned; - unsigned char cluster; - unsigned char discard_zeroes_data; - unsigned char raid_partial_stripes_expensive; -}; - -struct request_queue { - /* - * Together with queue_head for cacheline sharing - */ - struct list_head queue_head; - struct request *last_merge; - struct elevator_queue *elevator; - int nr_rqs[2]; /* # allocated [a]sync rqs */ - int nr_rqs_elvpriv; /* # allocated rqs w/ elvpriv */ - - /* - * If blkcg is not used, @q->root_rl serves all requests. If blkcg - * is used, root blkg allocates from @q->root_rl and all other - * blkgs from their own blkg->rl. Which one to use should be - * determined using bio_request_list(). - */ - struct request_list root_rl; - - request_fn_proc *request_fn; - make_request_fn *make_request_fn; - prep_rq_fn *prep_rq_fn; - unprep_rq_fn *unprep_rq_fn; - softirq_done_fn *softirq_done_fn; - rq_timed_out_fn *rq_timed_out_fn; - dma_drain_needed_fn *dma_drain_needed; - lld_busy_fn *lld_busy_fn; - - struct blk_mq_ops *mq_ops; - - unsigned int *mq_map; - - /* sw queues */ - struct blk_mq_ctx __percpu *queue_ctx; - unsigned int nr_queues; - - /* hw dispatch queues */ - struct blk_mq_hw_ctx **queue_hw_ctx; - unsigned int nr_hw_queues; - - /* - * Dispatch queue sorting - */ - sector_t end_sector; - struct request *boundary_rq; - - /* - * Delayed queue handling - */ - struct delayed_work delay_work; - - struct backing_dev_info backing_dev_info; - - /* - * The queue owner gets to use this for whatever they like. - * ll_rw_blk doesn't touch it. - */ - void *queuedata; - - /* - * various queue flags, see QUEUE_* below - */ - unsigned long queue_flags; - - /* - * ida allocated id for this queue. Used to index queues from - * ioctx. - */ - int id; - - /* - * queue needs bounce pages for pages above this limit - */ - gfp_t bounce_gfp; - - /* - * protects queue structures from reentrancy. ->__queue_lock should - * _never_ be used directly, it is queue private. always use - * ->queue_lock. - */ - spinlock_t __queue_lock; - spinlock_t *queue_lock; - - /* - * queue kobject - */ - struct kobject kobj; - - /* - * mq queue kobject - */ - struct kobject mq_kobj; - -#ifdef CONFIG_BLK_DEV_INTEGRITY - struct blk_integrity integrity; -#endif /* CONFIG_BLK_DEV_INTEGRITY */ - -#ifdef CONFIG_PM - struct device *dev; - int rpm_status; - unsigned int nr_pending; -#endif - - /* - * queue settings - */ - unsigned long nr_requests; /* Max # of requests */ - unsigned int nr_congestion_on; - unsigned int nr_congestion_off; - unsigned int nr_batching; - - unsigned int dma_drain_size; - void *dma_drain_buffer; - unsigned int dma_pad_mask; - unsigned int dma_alignment; - - struct blk_queue_tag *queue_tags; - struct list_head tag_busy_list; - - unsigned int nr_sorted; - unsigned int in_flight[2]; - /* - * Number of active block driver functions for which blk_drain_queue() - * must wait. Must be incremented around functions that unlock the - * queue_lock internally, e.g. scsi_request_fn(). - */ - unsigned int request_fn_active; - - unsigned int rq_timeout; - struct timer_list timeout; - struct work_struct timeout_work; - struct list_head timeout_list; - - struct list_head icq_list; -#ifdef CONFIG_BLK_CGROUP - DECLARE_BITMAP (blkcg_pols, BLKCG_MAX_POLS); - struct blkcg_gq *root_blkg; - struct list_head blkg_list; -#endif - - struct queue_limits limits; - - /* - * sg stuff - */ - unsigned int sg_timeout; - unsigned int sg_reserved_size; - int node; -#ifdef CONFIG_BLK_DEV_IO_TRACE - struct blk_trace *blk_trace; -#endif - /* - * for flush operations - */ - struct blk_flush_queue *fq; - - struct list_head requeue_list; - spinlock_t requeue_lock; - struct delayed_work requeue_work; - - struct mutex sysfs_lock; - - int bypass_depth; - atomic_t mq_freeze_depth; - -#if defined(CONFIG_BLK_DEV_BSG) - bsg_job_fn *bsg_job_fn; - int bsg_job_size; - struct bsg_class_device bsg_dev; -#endif - -#ifdef CONFIG_BLK_DEV_THROTTLING - /* Throttle data */ - struct throtl_data *td; -#endif - struct rcu_head rcu_head; - wait_queue_head_t mq_freeze_wq; - struct percpu_ref q_usage_counter; - struct list_head all_q_node; - - struct blk_mq_tag_set *tag_set; - struct list_head tag_set_list; - struct bio_set *bio_split; - - bool mq_sysfs_init_done; -}; - -#define QUEUE_FLAG_QUEUED 1 /* uses generic tag queueing */ -#define QUEUE_FLAG_STOPPED 2 /* queue is stopped */ -#define QUEUE_FLAG_SYNCFULL 3 /* read queue has been filled */ -#define QUEUE_FLAG_ASYNCFULL 4 /* write queue has been filled */ -#define QUEUE_FLAG_DYING 5 /* queue being torn down */ -#define QUEUE_FLAG_BYPASS 6 /* act as dumb FIFO queue */ -#define QUEUE_FLAG_BIDI 7 /* queue supports bidi requests */ -#define QUEUE_FLAG_NOMERGES 8 /* disable merge attempts */ -#define QUEUE_FLAG_SAME_COMP 9 /* complete on same CPU-group */ -#define QUEUE_FLAG_FAIL_IO 10 /* fake timeout */ -#define QUEUE_FLAG_STACKABLE 11 /* supports request stacking */ -#define QUEUE_FLAG_NONROT 12 /* non-rotational device (SSD) */ -#define QUEUE_FLAG_VIRT QUEUE_FLAG_NONROT /* paravirt device */ -#define QUEUE_FLAG_IO_STAT 13 /* do IO stats */ -#define QUEUE_FLAG_DISCARD 14 /* supports DISCARD */ -#define QUEUE_FLAG_NOXMERGES 15 /* No extended merges */ -#define QUEUE_FLAG_ADD_RANDOM 16 /* Contributes to random pool */ -#define QUEUE_FLAG_SECERASE 17 /* supports secure erase */ -#define QUEUE_FLAG_SAME_FORCE 18 /* force complete on same CPU */ -#define QUEUE_FLAG_DEAD 19 /* queue tear-down finished */ -#define QUEUE_FLAG_INIT_DONE 20 /* queue is initialized */ -#define QUEUE_FLAG_NO_SG_MERGE 21 /* don't attempt to merge SG segments*/ -#define QUEUE_FLAG_POLL 22 /* IO polling enabled if set */ -#define QUEUE_FLAG_WC 23 /* Write back caching */ -#define QUEUE_FLAG_FUA 24 /* device supports FUA writes */ -#define QUEUE_FLAG_FLUSH_NQ 25 /* flush not queueuable */ -#define QUEUE_FLAG_DAX 26 /* device supports DAX */ - -#define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ - (1 << QUEUE_FLAG_STACKABLE) | \ - (1 << QUEUE_FLAG_SAME_COMP) | \ - (1 << QUEUE_FLAG_ADD_RANDOM)) - -#define QUEUE_FLAG_MQ_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ - (1 << QUEUE_FLAG_STACKABLE) | \ - (1 << QUEUE_FLAG_SAME_COMP) | \ - (1 << QUEUE_FLAG_POLL)) - -static inline void queue_lockdep_assert_held(struct request_queue *q) -{ - if (q->queue_lock) - lockdep_assert_held(q->queue_lock); -} - -static inline void queue_flag_set_unlocked(unsigned int flag, - struct request_queue *q) -{ - __set_bit(flag, &q->queue_flags); -} - -static inline int queue_flag_test_and_clear(unsigned int flag, - struct request_queue *q) -{ - queue_lockdep_assert_held(q); - - if (test_bit(flag, &q->queue_flags)) { - __clear_bit(flag, &q->queue_flags); - return 1; - } - - return 0; -} - -static inline int queue_flag_test_and_set(unsigned int flag, - struct request_queue *q) -{ - queue_lockdep_assert_held(q); - - if (!test_bit(flag, &q->queue_flags)) { - __set_bit(flag, &q->queue_flags); - return 0; - } - - return 1; -} - -static inline void queue_flag_set(unsigned int flag, struct request_queue *q) -{ - queue_lockdep_assert_held(q); - __set_bit(flag, &q->queue_flags); -} - -static inline void queue_flag_clear_unlocked(unsigned int flag, - struct request_queue *q) -{ - __clear_bit(flag, &q->queue_flags); -} - -static inline int queue_in_flight(struct request_queue *q) -{ - return q->in_flight[0] + q->in_flight[1]; -} - -static inline void queue_flag_clear(unsigned int flag, struct request_queue *q) -{ - queue_lockdep_assert_held(q); - __clear_bit(flag, &q->queue_flags); -} - -#define blk_queue_tagged(q) test_bit(QUEUE_FLAG_QUEUED, &(q)->queue_flags) -#define blk_queue_stopped(q) test_bit(QUEUE_FLAG_STOPPED, &(q)->queue_flags) -#define blk_queue_dying(q) test_bit(QUEUE_FLAG_DYING, &(q)->queue_flags) -#define blk_queue_dead(q) test_bit(QUEUE_FLAG_DEAD, &(q)->queue_flags) -#define blk_queue_bypass(q) test_bit(QUEUE_FLAG_BYPASS, &(q)->queue_flags) -#define blk_queue_init_done(q) test_bit(QUEUE_FLAG_INIT_DONE, &(q)->queue_flags) -#define blk_queue_nomerges(q) test_bit(QUEUE_FLAG_NOMERGES, &(q)->queue_flags) -#define blk_queue_noxmerges(q) \ - test_bit(QUEUE_FLAG_NOXMERGES, &(q)->queue_flags) -#define blk_queue_nonrot(q) test_bit(QUEUE_FLAG_NONROT, &(q)->queue_flags) -#define blk_queue_io_stat(q) test_bit(QUEUE_FLAG_IO_STAT, &(q)->queue_flags) -#define blk_queue_add_random(q) test_bit(QUEUE_FLAG_ADD_RANDOM, &(q)->queue_flags) -#define blk_queue_stackable(q) \ - test_bit(QUEUE_FLAG_STACKABLE, &(q)->queue_flags) -#define blk_queue_discard(q) test_bit(QUEUE_FLAG_DISCARD, &(q)->queue_flags) -#define blk_queue_secure_erase(q) \ - (test_bit(QUEUE_FLAG_SECERASE, &(q)->queue_flags)) -#define blk_queue_dax(q) test_bit(QUEUE_FLAG_DAX, &(q)->queue_flags) - -#define blk_noretry_request(rq) \ - ((rq)->cmd_flags & (REQ_FAILFAST_DEV|REQ_FAILFAST_TRANSPORT| \ - REQ_FAILFAST_DRIVER)) - -#define blk_account_rq(rq) \ - (((rq)->cmd_flags & REQ_STARTED) && \ - ((rq)->cmd_type == REQ_TYPE_FS)) - -#define blk_rq_cpu_valid(rq) ((rq)->cpu != -1) -#define blk_bidi_rq(rq) ((rq)->next_rq != NULL) -/* rq->queuelist of dequeued request must be list_empty() */ -#define blk_queued_rq(rq) (!list_empty(&(rq)->queuelist)) - -#define list_entry_rq(ptr) list_entry((ptr), struct request, queuelist) - -#define rq_data_dir(rq) (op_is_write(req_op(rq)) ? WRITE : READ) - -/* - * Driver can handle struct request, if it either has an old style - * request_fn defined, or is blk-mq based. - */ -static inline bool queue_is_rq_based(struct request_queue *q) -{ - return q->request_fn || q->mq_ops; -} - -static inline unsigned int blk_queue_cluster(struct request_queue *q) -{ - return q->limits.cluster; -} - -/* - * We regard a request as sync, if either a read or a sync write - */ -static inline bool rw_is_sync(int op, unsigned int rw_flags) -{ - return op == REQ_OP_READ || (rw_flags & REQ_SYNC); -} - -static inline bool rq_is_sync(struct request *rq) -{ - return rw_is_sync(req_op(rq), rq->cmd_flags); -} - -static inline bool blk_rl_full(struct request_list *rl, bool sync) -{ - unsigned int flag = sync ? BLK_RL_SYNCFULL : BLK_RL_ASYNCFULL; - - return rl->flags & flag; -} - -static inline void blk_set_rl_full(struct request_list *rl, bool sync) -{ - unsigned int flag = sync ? BLK_RL_SYNCFULL : BLK_RL_ASYNCFULL; - - rl->flags |= flag; -} - -static inline void blk_clear_rl_full(struct request_list *rl, bool sync) -{ - unsigned int flag = sync ? BLK_RL_SYNCFULL : BLK_RL_ASYNCFULL; - - rl->flags &= ~flag; -} - -static inline bool rq_mergeable(struct request *rq) -{ - if (rq->cmd_type != REQ_TYPE_FS) - return false; - - if (req_op(rq) == REQ_OP_FLUSH) - return false; - - if (rq->cmd_flags & REQ_NOMERGE_FLAGS) - return false; - - return true; -} - -static inline bool blk_write_same_mergeable(struct bio *a, struct bio *b) -{ - if (bio_data(a) == bio_data(b)) - return true; - - return false; -} - -/* - * q->prep_rq_fn return values - */ -enum { - BLKPREP_OK, /* serve it */ - BLKPREP_KILL, /* fatal error, kill, return -EIO */ - BLKPREP_DEFER, /* leave on queue */ - BLKPREP_INVALID, /* invalid command, kill, return -EREMOTEIO */ -}; - -extern unsigned long blk_max_low_pfn, blk_max_pfn; - -/* - * standard bounce addresses: - * - * BLK_BOUNCE_HIGH : bounce all highmem pages - * BLK_BOUNCE_ANY : don't bounce anything - * BLK_BOUNCE_ISA : bounce pages above ISA DMA boundary - */ - -#if BITS_PER_LONG == 32 -#define BLK_BOUNCE_HIGH ((u64)blk_max_low_pfn << PAGE_SHIFT) -#else -#define BLK_BOUNCE_HIGH -1ULL -#endif -#define BLK_BOUNCE_ANY (-1ULL) -#define BLK_BOUNCE_ISA (DMA_BIT_MASK(24)) - -/* - * default timeout for SG_IO if none specified - */ -#define BLK_DEFAULT_SG_TIMEOUT (60 * HZ) -#define BLK_MIN_SG_TIMEOUT (7 * HZ) - -#ifdef CONFIG_BOUNCE -extern int init_emergency_isa_pool(void); -extern void blk_queue_bounce(struct request_queue *q, struct bio **bio); -#else -static inline int init_emergency_isa_pool(void) -{ - return 0; -} -static inline void blk_queue_bounce(struct request_queue *q, struct bio **bio) -{ -} -#endif /* CONFIG_MMU */ - -struct rq_map_data { - struct page **pages; - int page_order; - int nr_entries; - unsigned long offset; - int null_mapped; - int from_user; -}; - -struct req_iterator { - struct bvec_iter iter; - struct bio *bio; -}; - -/* This should not be used directly - use rq_for_each_segment */ -#define for_each_bio(_bio) \ - for (; _bio; _bio = _bio->bi_next) -#define __rq_for_each_bio(_bio, rq) \ - if ((rq->bio)) \ - for (_bio = (rq)->bio; _bio; _bio = _bio->bi_next) - -#define rq_for_each_segment(bvl, _rq, _iter) \ - __rq_for_each_bio(_iter.bio, _rq) \ - bio_for_each_segment(bvl, _iter.bio, _iter.iter) - -#define rq_iter_last(bvec, _iter) \ - (_iter.bio->bi_next == NULL && \ - bio_iter_last(bvec, _iter.iter)) - -#ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE -# error "You should define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE for your platform" -#endif -#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE -extern void rq_flush_dcache_pages(struct request *rq); -#else -static inline void rq_flush_dcache_pages(struct request *rq) -{ -} -#endif - -#ifdef CONFIG_PRINTK -#define vfs_msg(sb, level, fmt, ...) \ - __vfs_msg(sb, level, fmt, ##__VA_ARGS__) -#else -#define vfs_msg(sb, level, fmt, ...) \ -do { \ - no_printk(fmt, ##__VA_ARGS__); \ - __vfs_msg(sb, "", " "); \ -} while (0) -#endif - -extern int blk_register_queue(struct gendisk *disk); -extern void blk_unregister_queue(struct gendisk *disk); -extern blk_qc_t generic_make_request(struct bio *bio); -extern void blk_rq_init(struct request_queue *q, struct request *rq); -extern void blk_put_request(struct request *); -extern void __blk_put_request(struct request_queue *, struct request *); -extern struct request *blk_get_request(struct request_queue *, int, gfp_t); -extern void blk_rq_set_block_pc(struct request *); -extern void blk_requeue_request(struct request_queue *, struct request *); -extern void blk_add_request_payload(struct request *rq, struct page *page, - int offset, unsigned int len); -extern int blk_lld_busy(struct request_queue *q); -extern int blk_rq_prep_clone(struct request *rq, struct request *rq_src, - struct bio_set *bs, gfp_t gfp_mask, - int (*bio_ctr)(struct bio *, struct bio *, void *), - void *data); -extern void blk_rq_unprep_clone(struct request *rq); -extern int blk_insert_cloned_request(struct request_queue *q, - struct request *rq); -extern int blk_rq_append_bio(struct request *rq, struct bio *bio); -extern void blk_delay_queue(struct request_queue *, unsigned long); -extern void blk_queue_split(struct request_queue *, struct bio **, - struct bio_set *); -extern void blk_recount_segments(struct request_queue *, struct bio *); -extern int scsi_verify_blk_ioctl(struct block_device *, unsigned int); -extern int scsi_cmd_blk_ioctl(struct block_device *, fmode_t, - unsigned int, void __user *); -extern int scsi_cmd_ioctl(struct request_queue *, struct gendisk *, fmode_t, - unsigned int, void __user *); -extern int sg_scsi_ioctl(struct request_queue *, struct gendisk *, fmode_t, - struct scsi_ioctl_command __user *); - -extern int blk_queue_enter(struct request_queue *q, bool nowait); -extern void blk_queue_exit(struct request_queue *q); -extern void blk_start_queue(struct request_queue *q); -extern void blk_start_queue_async(struct request_queue *q); -extern void blk_stop_queue(struct request_queue *q); -extern void blk_sync_queue(struct request_queue *q); -extern void __blk_stop_queue(struct request_queue *q); -extern void __blk_run_queue(struct request_queue *q); -extern void __blk_run_queue_uncond(struct request_queue *q); -extern void blk_run_queue(struct request_queue *); -extern void blk_run_queue_async(struct request_queue *q); -extern int blk_rq_map_user(struct request_queue *, struct request *, - struct rq_map_data *, void __user *, unsigned long, - gfp_t); -extern int blk_rq_unmap_user(struct bio *); -extern int blk_rq_map_kern(struct request_queue *, struct request *, void *, unsigned int, gfp_t); -extern int blk_rq_map_user_iov(struct request_queue *, struct request *, - struct rq_map_data *, const struct iov_iter *, - gfp_t); -extern int blk_execute_rq(struct request_queue *, struct gendisk *, - struct request *, int); -extern void blk_execute_rq_nowait(struct request_queue *, struct gendisk *, - struct request *, int, rq_end_io_fn *); - -bool blk_poll(struct request_queue *q, blk_qc_t cookie); - -static inline struct request_queue *bdev_get_queue(struct block_device *bdev) -{ - return bdev->bd_disk->queue; /* this is never NULL */ -} - -/* - * blk_rq_pos() : the current sector - * blk_rq_bytes() : bytes left in the entire request - * blk_rq_cur_bytes() : bytes left in the current segment - * blk_rq_err_bytes() : bytes left till the next error boundary - * blk_rq_sectors() : sectors left in the entire request - * blk_rq_cur_sectors() : sectors left in the current segment - */ -static inline sector_t blk_rq_pos(const struct request *rq) -{ - return rq->__sector; -} - -static inline unsigned int blk_rq_bytes(const struct request *rq) -{ - return rq->__data_len; -} - -static inline int blk_rq_cur_bytes(const struct request *rq) -{ - return rq->bio ? bio_cur_bytes(rq->bio) : 0; -} - -extern unsigned int blk_rq_err_bytes(const struct request *rq); - -static inline unsigned int blk_rq_sectors(const struct request *rq) -{ - return blk_rq_bytes(rq) >> 9; -} - -static inline unsigned int blk_rq_cur_sectors(const struct request *rq) -{ - return blk_rq_cur_bytes(rq) >> 9; -} - -static inline unsigned int blk_queue_get_max_sectors(struct request_queue *q, - int op) -{ - if (unlikely(op == REQ_OP_DISCARD || op == REQ_OP_SECURE_ERASE)) - return min(q->limits.max_discard_sectors, UINT_MAX >> 9); - - if (unlikely(op == REQ_OP_WRITE_SAME)) - return q->limits.max_write_same_sectors; - - return q->limits.max_sectors; -} - -/* - * Return maximum size of a request at given offset. Only valid for - * file system requests. - */ -static inline unsigned int blk_max_size_offset(struct request_queue *q, - sector_t offset) -{ - if (!q->limits.chunk_sectors) - return q->limits.max_sectors; - - return q->limits.chunk_sectors - - (offset & (q->limits.chunk_sectors - 1)); -} - -static inline unsigned int blk_rq_get_max_sectors(struct request *rq, - sector_t offset) -{ - struct request_queue *q = rq->q; - - if (unlikely(rq->cmd_type != REQ_TYPE_FS)) - return q->limits.max_hw_sectors; - - if (!q->limits.chunk_sectors || - req_op(rq) == REQ_OP_DISCARD || - req_op(rq) == REQ_OP_SECURE_ERASE) - return blk_queue_get_max_sectors(q, req_op(rq)); - - return min(blk_max_size_offset(q, offset), - blk_queue_get_max_sectors(q, req_op(rq))); -} - -static inline unsigned int blk_rq_count_bios(struct request *rq) -{ - unsigned int nr_bios = 0; - struct bio *bio; - - __rq_for_each_bio(bio, rq) - nr_bios++; - - return nr_bios; -} - -/* - * Request issue related functions. - */ -extern struct request *blk_peek_request(struct request_queue *q); -extern void blk_start_request(struct request *rq); -extern struct request *blk_fetch_request(struct request_queue *q); - -/* - * Request completion related functions. - * - * blk_update_request() completes given number of bytes and updates - * the request without completing it. - * - * blk_end_request() and friends. __blk_end_request() must be called - * with the request queue spinlock acquired. - * - * Several drivers define their own end_request and call - * blk_end_request() for parts of the original function. - * This prevents code duplication in drivers. - */ -extern bool blk_update_request(struct request *rq, int error, - unsigned int nr_bytes); -extern void blk_finish_request(struct request *rq, int error); -extern bool blk_end_request(struct request *rq, int error, - unsigned int nr_bytes); -extern void blk_end_request_all(struct request *rq, int error); -extern bool blk_end_request_cur(struct request *rq, int error); -extern bool blk_end_request_err(struct request *rq, int error); -extern bool __blk_end_request(struct request *rq, int error, - unsigned int nr_bytes); -extern void __blk_end_request_all(struct request *rq, int error); -extern bool __blk_end_request_cur(struct request *rq, int error); -extern bool __blk_end_request_err(struct request *rq, int error); - -extern void blk_complete_request(struct request *); -extern void __blk_complete_request(struct request *); -extern void blk_abort_request(struct request *); -extern void blk_unprep_request(struct request *); - -/* - * Access functions for manipulating queue properties - */ -extern struct request_queue *blk_init_queue_node(request_fn_proc *rfn, - spinlock_t *lock, int node_id); -extern struct request_queue *blk_init_queue(request_fn_proc *, spinlock_t *); -extern struct request_queue *blk_init_allocated_queue(struct request_queue *, - request_fn_proc *, spinlock_t *); -extern void blk_cleanup_queue(struct request_queue *); -extern void blk_queue_make_request(struct request_queue *, make_request_fn *); -extern void blk_queue_bounce_limit(struct request_queue *, u64); -extern void blk_queue_max_hw_sectors(struct request_queue *, unsigned int); -extern void blk_queue_chunk_sectors(struct request_queue *, unsigned int); -extern void blk_queue_max_segments(struct request_queue *, unsigned short); -extern void blk_queue_max_segment_size(struct request_queue *, unsigned int); -extern void blk_queue_max_discard_sectors(struct request_queue *q, - unsigned int max_discard_sectors); -extern void blk_queue_max_write_same_sectors(struct request_queue *q, - unsigned int max_write_same_sectors); -extern void blk_queue_logical_block_size(struct request_queue *, unsigned short); -extern void blk_queue_physical_block_size(struct request_queue *, unsigned int); -extern void blk_queue_alignment_offset(struct request_queue *q, - unsigned int alignment); -extern void blk_limits_io_min(struct queue_limits *limits, unsigned int min); -extern void blk_queue_io_min(struct request_queue *q, unsigned int min); -extern void blk_limits_io_opt(struct queue_limits *limits, unsigned int opt); -extern void blk_queue_io_opt(struct request_queue *q, unsigned int opt); -extern void blk_set_default_limits(struct queue_limits *lim); -extern void blk_set_stacking_limits(struct queue_limits *lim); -extern int blk_stack_limits(struct queue_limits *t, struct queue_limits *b, - sector_t offset); -extern int bdev_stack_limits(struct queue_limits *t, struct block_device *bdev, - sector_t offset); -extern void disk_stack_limits(struct gendisk *disk, struct block_device *bdev, - sector_t offset); -extern void blk_queue_stack_limits(struct request_queue *t, struct request_queue *b); -extern void blk_queue_dma_pad(struct request_queue *, unsigned int); -extern void blk_queue_update_dma_pad(struct request_queue *, unsigned int); -extern int blk_queue_dma_drain(struct request_queue *q, - dma_drain_needed_fn *dma_drain_needed, - void *buf, unsigned int size); -extern void blk_queue_lld_busy(struct request_queue *q, lld_busy_fn *fn); -extern void blk_queue_segment_boundary(struct request_queue *, unsigned long); -extern void blk_queue_virt_boundary(struct request_queue *, unsigned long); -extern void blk_queue_prep_rq(struct request_queue *, prep_rq_fn *pfn); -extern void blk_queue_unprep_rq(struct request_queue *, unprep_rq_fn *ufn); -extern void blk_queue_dma_alignment(struct request_queue *, int); -extern void blk_queue_update_dma_alignment(struct request_queue *, int); -extern void blk_queue_softirq_done(struct request_queue *, softirq_done_fn *); -extern void blk_queue_rq_timed_out(struct request_queue *, rq_timed_out_fn *); -extern void blk_queue_rq_timeout(struct request_queue *, unsigned int); -extern void blk_queue_flush_queueable(struct request_queue *q, bool queueable); -extern void blk_queue_write_cache(struct request_queue *q, bool enabled, bool fua); -extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev); - -extern int blk_rq_map_sg(struct request_queue *, struct request *, struct scatterlist *); -extern void blk_dump_rq_flags(struct request *, char *); -extern long nr_blockdev_pages(void); - -bool __must_check blk_get_queue(struct request_queue *); -struct request_queue *blk_alloc_queue(gfp_t); -struct request_queue *blk_alloc_queue_node(gfp_t, int); -extern void blk_put_queue(struct request_queue *); -extern void blk_set_queue_dying(struct request_queue *); - -/* - * block layer runtime pm functions - */ -#ifdef CONFIG_PM -extern void blk_pm_runtime_init(struct request_queue *q, struct device *dev); -extern int blk_pre_runtime_suspend(struct request_queue *q); -extern void blk_post_runtime_suspend(struct request_queue *q, int err); -extern void blk_pre_runtime_resume(struct request_queue *q); -extern void blk_post_runtime_resume(struct request_queue *q, int err); -extern void blk_set_runtime_active(struct request_queue *q); -#else -static inline void blk_pm_runtime_init(struct request_queue *q, - struct device *dev) {} -static inline int blk_pre_runtime_suspend(struct request_queue *q) -{ - return -ENOSYS; -} -static inline void blk_post_runtime_suspend(struct request_queue *q, int err) {} -static inline void blk_pre_runtime_resume(struct request_queue *q) {} -static inline void blk_post_runtime_resume(struct request_queue *q, int err) {} -extern inline void blk_set_runtime_active(struct request_queue *q) {} -#endif - -/* - * blk_plug permits building a queue of related requests by holding the I/O - * fragments for a short period. This allows merging of sequential requests - * into single larger request. As the requests are moved from a per-task list to - * the device's request_queue in a batch, this results in improved scalability - * as the lock contention for request_queue lock is reduced. - * - * It is ok not to disable preemption when adding the request to the plug list - * or when attempting a merge, because blk_schedule_flush_list() will only flush - * the plug list when the task sleeps by itself. For details, please see - * schedule() where blk_schedule_flush_plug() is called. - */ -struct blk_plug { - struct list_head list; /* requests */ - struct list_head mq_list; /* blk-mq requests */ - struct list_head cb_list; /* md requires an unplug callback */ -}; -#define BLK_MAX_REQUEST_COUNT 16 - -struct blk_plug_cb; -typedef void (*blk_plug_cb_fn)(struct blk_plug_cb *, bool); -struct blk_plug_cb { - struct list_head list; - blk_plug_cb_fn callback; - void *data; -}; -extern struct blk_plug_cb *blk_check_plugged(blk_plug_cb_fn unplug, - void *data, int size); -extern void blk_start_plug(struct blk_plug *); -extern void blk_finish_plug(struct blk_plug *); -extern void blk_flush_plug_list(struct blk_plug *, bool); - -static inline void blk_flush_plug(struct task_struct *tsk) -{ - struct blk_plug *plug = tsk->plug; - - if (plug) - blk_flush_plug_list(plug, false); -} - -static inline void blk_schedule_flush_plug(struct task_struct *tsk) -{ - struct blk_plug *plug = tsk->plug; - - if (plug) - blk_flush_plug_list(plug, true); -} - -static inline bool blk_needs_flush_plug(struct task_struct *tsk) -{ - struct blk_plug *plug = tsk->plug; - - return plug && - (!list_empty(&plug->list) || - !list_empty(&plug->mq_list) || - !list_empty(&plug->cb_list)); -} - -/* - * tag stuff - */ -extern int blk_queue_start_tag(struct request_queue *, struct request *); -extern struct request *blk_queue_find_tag(struct request_queue *, int); -extern void blk_queue_end_tag(struct request_queue *, struct request *); -extern int blk_queue_init_tags(struct request_queue *, int, struct blk_queue_tag *, int); -extern void blk_queue_free_tags(struct request_queue *); -extern int blk_queue_resize_tags(struct request_queue *, int); -extern void blk_queue_invalidate_tags(struct request_queue *); -extern struct blk_queue_tag *blk_init_tags(int, int); -extern void blk_free_tags(struct blk_queue_tag *); - -static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt, - int tag) -{ - if (unlikely(bqt == NULL || tag >= bqt->real_max_depth)) - return NULL; - return bqt->tag_index[tag]; -} - - -#define BLKDEV_DISCARD_SECURE (1 << 0) /* issue a secure erase */ -#define BLKDEV_DISCARD_ZERO (1 << 1) /* must reliably zero data */ - -extern int blkdev_issue_flush(struct block_device *, gfp_t, sector_t *); -extern int blkdev_issue_discard(struct block_device *bdev, sector_t sector, - sector_t nr_sects, gfp_t gfp_mask, unsigned long flags); -extern int __blkdev_issue_discard(struct block_device *bdev, sector_t sector, - sector_t nr_sects, gfp_t gfp_mask, int flags, - struct bio **biop); -extern int blkdev_issue_write_same(struct block_device *bdev, sector_t sector, - sector_t nr_sects, gfp_t gfp_mask, struct page *page); -extern int blkdev_issue_zeroout(struct block_device *bdev, sector_t sector, - sector_t nr_sects, gfp_t gfp_mask, bool discard); -static inline int sb_issue_discard(struct super_block *sb, sector_t block, - sector_t nr_blocks, gfp_t gfp_mask, unsigned long flags) -{ - return blkdev_issue_discard(sb->s_bdev, block << (sb->s_blocksize_bits - 9), - nr_blocks << (sb->s_blocksize_bits - 9), - gfp_mask, flags); -} -static inline int sb_issue_zeroout(struct super_block *sb, sector_t block, - sector_t nr_blocks, gfp_t gfp_mask) -{ - return blkdev_issue_zeroout(sb->s_bdev, - block << (sb->s_blocksize_bits - 9), - nr_blocks << (sb->s_blocksize_bits - 9), - gfp_mask, true); -} - -extern int blk_verify_command(unsigned char *cmd, fmode_t has_write_perm); - -enum blk_default_limits { - BLK_MAX_SEGMENTS = 128, - BLK_SAFE_MAX_SECTORS = 255, - BLK_DEF_MAX_SECTORS = 2560, - BLK_MAX_SEGMENT_SIZE = 65536, - BLK_SEG_BOUNDARY_MASK = 0xFFFFFFFFUL, -}; - -#define blkdev_entry_to_request(entry) list_entry((entry), struct request, queuelist) - -static inline unsigned long queue_bounce_pfn(struct request_queue *q) -{ - return q->limits.bounce_pfn; -} - -static inline unsigned long queue_segment_boundary(struct request_queue *q) -{ - return q->limits.seg_boundary_mask; -} - -static inline unsigned long queue_virt_boundary(struct request_queue *q) -{ - return q->limits.virt_boundary_mask; -} - -static inline unsigned int queue_max_sectors(struct request_queue *q) -{ - return q->limits.max_sectors; -} - -static inline unsigned int queue_max_hw_sectors(struct request_queue *q) -{ - return q->limits.max_hw_sectors; -} - -static inline unsigned short queue_max_segments(struct request_queue *q) -{ - return q->limits.max_segments; -} - -static inline unsigned int queue_max_segment_size(struct request_queue *q) -{ - return q->limits.max_segment_size; -} - -static inline unsigned short queue_logical_block_size(struct request_queue *q) -{ - int retval = 512; - - if (q && q->limits.logical_block_size) - retval = q->limits.logical_block_size; - - return retval; -} - -static inline unsigned short bdev_logical_block_size(struct block_device *bdev) -{ - return queue_logical_block_size(bdev_get_queue(bdev)); -} - -static inline unsigned int queue_physical_block_size(struct request_queue *q) -{ - return q->limits.physical_block_size; -} - -static inline unsigned int bdev_physical_block_size(struct block_device *bdev) -{ - return queue_physical_block_size(bdev_get_queue(bdev)); -} - -static inline unsigned int queue_io_min(struct request_queue *q) -{ - return q->limits.io_min; -} - -static inline int bdev_io_min(struct block_device *bdev) -{ - return queue_io_min(bdev_get_queue(bdev)); -} - -static inline unsigned int queue_io_opt(struct request_queue *q) -{ - return q->limits.io_opt; -} - -static inline int bdev_io_opt(struct block_device *bdev) -{ - return queue_io_opt(bdev_get_queue(bdev)); -} - -static inline int queue_alignment_offset(struct request_queue *q) -{ - if (q->limits.misaligned) - return -1; - - return q->limits.alignment_offset; -} - -static inline int queue_limit_alignment_offset(struct queue_limits *lim, sector_t sector) -{ - unsigned int granularity = max(lim->physical_block_size, lim->io_min); - unsigned int alignment = sector_div(sector, granularity >> 9) << 9; - - return (granularity + lim->alignment_offset - alignment) % granularity; -} - -static inline int bdev_alignment_offset(struct block_device *bdev) -{ - struct request_queue *q = bdev_get_queue(bdev); - - if (q->limits.misaligned) - return -1; - - if (bdev != bdev->bd_contains) - return bdev->bd_part->alignment_offset; - - return q->limits.alignment_offset; -} - -static inline int queue_discard_alignment(struct request_queue *q) -{ - if (q->limits.discard_misaligned) - return -1; - - return q->limits.discard_alignment; -} - -static inline int queue_limit_discard_alignment(struct queue_limits *lim, sector_t sector) -{ - unsigned int alignment, granularity, offset; - - if (!lim->max_discard_sectors) - return 0; - - /* Why are these in bytes, not sectors? */ - alignment = lim->discard_alignment >> 9; - granularity = lim->discard_granularity >> 9; - if (!granularity) - return 0; - - /* Offset of the partition start in 'granularity' sectors */ - offset = sector_div(sector, granularity); - - /* And why do we do this modulus *again* in blkdev_issue_discard()? */ - offset = (granularity + alignment - offset) % granularity; - - /* Turn it back into bytes, gaah */ - return offset << 9; -} - -static inline int bdev_discard_alignment(struct block_device *bdev) -{ - struct request_queue *q = bdev_get_queue(bdev); - - if (bdev != bdev->bd_contains) - return bdev->bd_part->discard_alignment; - - return q->limits.discard_alignment; -} - -static inline unsigned int queue_discard_zeroes_data(struct request_queue *q) -{ - if (q->limits.max_discard_sectors && q->limits.discard_zeroes_data == 1) - return 1; - - return 0; -} - -static inline unsigned int bdev_discard_zeroes_data(struct block_device *bdev) -{ - return queue_discard_zeroes_data(bdev_get_queue(bdev)); -} - -static inline unsigned int bdev_write_same(struct block_device *bdev) -{ - struct request_queue *q = bdev_get_queue(bdev); - - if (q) - return q->limits.max_write_same_sectors; - - return 0; -} - -static inline int queue_dma_alignment(struct request_queue *q) -{ - return q ? q->dma_alignment : 511; -} - -static inline int blk_rq_aligned(struct request_queue *q, unsigned long addr, - unsigned int len) -{ - unsigned int alignment = queue_dma_alignment(q) | q->dma_pad_mask; - return !(addr & alignment) && !(len & alignment); -} - -/* assumes size > 256 */ -static inline unsigned int blksize_bits(unsigned int size) -{ - unsigned int bits = 8; - do { - bits++; - size >>= 1; - } while (size > 256); - return bits; -} - -static inline unsigned int block_size(struct block_device *bdev) -{ - return bdev->bd_block_size; -} - -static inline bool queue_flush_queueable(struct request_queue *q) -{ - return !test_bit(QUEUE_FLAG_FLUSH_NQ, &q->queue_flags); -} - -typedef struct {struct page *v;} Sector; - -unsigned char *read_dev_sector(struct block_device *, sector_t, Sector *); - -static inline void put_dev_sector(Sector p) -{ - put_page(p.v); -} - -static inline bool __bvec_gap_to_prev(struct request_queue *q, - struct bio_vec *bprv, unsigned int offset) -{ - return offset || - ((bprv->bv_offset + bprv->bv_len) & queue_virt_boundary(q)); -} - -/* - * Check if adding a bio_vec after bprv with offset would create a gap in - * the SG list. Most drivers don't care about this, but some do. - */ -static inline bool bvec_gap_to_prev(struct request_queue *q, - struct bio_vec *bprv, unsigned int offset) -{ - if (!queue_virt_boundary(q)) - return false; - return __bvec_gap_to_prev(q, bprv, offset); -} - -static inline bool bio_will_gap(struct request_queue *q, struct bio *prev, - struct bio *next) -{ - if (bio_has_data(prev) && queue_virt_boundary(q)) { - struct bio_vec pb, nb; - - bio_get_last_bvec(prev, &pb); - bio_get_first_bvec(next, &nb); - - return __bvec_gap_to_prev(q, &pb, nb.bv_offset); - } - - return false; -} - -static inline bool req_gap_back_merge(struct request *req, struct bio *bio) -{ - return bio_will_gap(req->q, req->biotail, bio); -} - -static inline bool req_gap_front_merge(struct request *req, struct bio *bio) -{ - return bio_will_gap(req->q, bio, req->bio); -} - -int kblockd_schedule_work(struct work_struct *work); -int kblockd_schedule_work_on(int cpu, struct work_struct *work); -int kblockd_schedule_delayed_work(struct delayed_work *dwork, unsigned long delay); -int kblockd_schedule_delayed_work_on(int cpu, struct delayed_work *dwork, unsigned long delay); - -#ifdef CONFIG_BLK_CGROUP -/* - * This should not be using sched_clock(). A real patch is in progress - * to fix this up, until that is in place we need to disable preemption - * around sched_clock() in this function and set_io_start_time_ns(). - */ -static inline void set_start_time_ns(struct request *req) -{ - preempt_disable(); - req->start_time_ns = sched_clock(); - preempt_enable(); -} - -static inline void set_io_start_time_ns(struct request *req) -{ - preempt_disable(); - req->io_start_time_ns = sched_clock(); - preempt_enable(); -} - -static inline uint64_t rq_start_time_ns(struct request *req) -{ - return req->start_time_ns; -} - -static inline uint64_t rq_io_start_time_ns(struct request *req) -{ - return req->io_start_time_ns; -} -#else -static inline void set_start_time_ns(struct request *req) {} -static inline void set_io_start_time_ns(struct request *req) {} -static inline uint64_t rq_start_time_ns(struct request *req) -{ - return 0; -} -static inline uint64_t rq_io_start_time_ns(struct request *req) -{ - return 0; -} -#endif - -#define MODULE_ALIAS_BLOCKDEV(major,minor) \ - MODULE_ALIAS("block-major-" __stringify(major) "-" __stringify(minor)) -#define MODULE_ALIAS_BLOCKDEV_MAJOR(major) \ - MODULE_ALIAS("block-major-" __stringify(major) "-*") - -#if defined(CONFIG_BLK_DEV_INTEGRITY) - -enum blk_integrity_flags { - BLK_INTEGRITY_VERIFY = 1 << 0, - BLK_INTEGRITY_GENERATE = 1 << 1, - BLK_INTEGRITY_DEVICE_CAPABLE = 1 << 2, - BLK_INTEGRITY_IP_CHECKSUM = 1 << 3, -}; - -struct blk_integrity_iter { - void *prot_buf; - void *data_buf; - sector_t seed; - unsigned int data_size; - unsigned short interval; - const char *disk_name; -}; - -typedef int (integrity_processing_fn) (struct blk_integrity_iter *); - -struct blk_integrity_profile { - integrity_processing_fn *generate_fn; - integrity_processing_fn *verify_fn; - const char *name; -}; - -extern void blk_integrity_register(struct gendisk *, struct blk_integrity *); -extern void blk_integrity_unregister(struct gendisk *); -extern int blk_integrity_compare(struct gendisk *, struct gendisk *); -extern int blk_rq_map_integrity_sg(struct request_queue *, struct bio *, - struct scatterlist *); -extern int blk_rq_count_integrity_sg(struct request_queue *, struct bio *); -extern bool blk_integrity_merge_rq(struct request_queue *, struct request *, - struct request *); -extern bool blk_integrity_merge_bio(struct request_queue *, struct request *, - struct bio *); - -static inline struct blk_integrity *blk_get_integrity(struct gendisk *disk) -{ - struct blk_integrity *bi = &disk->queue->integrity; - - if (!bi->profile) - return NULL; - - return bi; -} - -static inline -struct blk_integrity *bdev_get_integrity(struct block_device *bdev) -{ - return blk_get_integrity(bdev->bd_disk); -} - -static inline bool blk_integrity_rq(struct request *rq) -{ - return rq->cmd_flags & REQ_INTEGRITY; -} - -static inline void blk_queue_max_integrity_segments(struct request_queue *q, - unsigned int segs) -{ - q->limits.max_integrity_segments = segs; -} - -static inline unsigned short -queue_max_integrity_segments(struct request_queue *q) -{ - return q->limits.max_integrity_segments; -} - -static inline bool integrity_req_gap_back_merge(struct request *req, - struct bio *next) -{ - struct bio_integrity_payload *bip = bio_integrity(req->bio); - struct bio_integrity_payload *bip_next = bio_integrity(next); - - return bvec_gap_to_prev(req->q, &bip->bip_vec[bip->bip_vcnt - 1], - bip_next->bip_vec[0].bv_offset); -} - -static inline bool integrity_req_gap_front_merge(struct request *req, - struct bio *bio) -{ - struct bio_integrity_payload *bip = bio_integrity(bio); - struct bio_integrity_payload *bip_next = bio_integrity(req->bio); - - return bvec_gap_to_prev(req->q, &bip->bip_vec[bip->bip_vcnt - 1], - bip_next->bip_vec[0].bv_offset); -} - -#else /* CONFIG_BLK_DEV_INTEGRITY */ - -struct bio; -struct block_device; -struct gendisk; -struct blk_integrity; - -static inline int blk_integrity_rq(struct request *rq) -{ - return 0; -} -static inline int blk_rq_count_integrity_sg(struct request_queue *q, - struct bio *b) -{ - return 0; -} -static inline int blk_rq_map_integrity_sg(struct request_queue *q, - struct bio *b, - struct scatterlist *s) -{ - return 0; -} -static inline struct blk_integrity *bdev_get_integrity(struct block_device *b) -{ - return NULL; -} -static inline struct blk_integrity *blk_get_integrity(struct gendisk *disk) -{ - return NULL; -} -static inline int blk_integrity_compare(struct gendisk *a, struct gendisk *b) -{ - return 0; -} -static inline void blk_integrity_register(struct gendisk *d, - struct blk_integrity *b) -{ -} -static inline void blk_integrity_unregister(struct gendisk *d) -{ -} -static inline void blk_queue_max_integrity_segments(struct request_queue *q, - unsigned int segs) -{ -} -static inline unsigned short queue_max_integrity_segments(struct request_queue *q) -{ - return 0; -} -static inline bool blk_integrity_merge_rq(struct request_queue *rq, - struct request *r1, - struct request *r2) -{ - return true; -} -static inline bool blk_integrity_merge_bio(struct request_queue *rq, - struct request *r, - struct bio *b) -{ - return true; -} - -static inline bool integrity_req_gap_back_merge(struct request *req, - struct bio *next) -{ - return false; -} -static inline bool integrity_req_gap_front_merge(struct request *req, - struct bio *bio) -{ - return false; -} - -#endif /* CONFIG_BLK_DEV_INTEGRITY */ - -/** - * struct blk_dax_ctl - control and output parameters for ->direct_access - * @sector: (input) offset relative to a block_device - * @addr: (output) kernel virtual address for @sector populated by driver - * @pfn: (output) page frame number for @addr populated by driver - * @size: (input) number of bytes requested - */ -struct blk_dax_ctl { - sector_t sector; - void *addr; - long size; - pfn_t pfn; -}; - -struct block_device_operations { - int (*open) (struct block_device *, fmode_t); - void (*release) (struct gendisk *, fmode_t); - int (*rw_page)(struct block_device *, sector_t, struct page *, bool); - int (*ioctl) (struct block_device *, fmode_t, unsigned, unsigned long); - int (*compat_ioctl) (struct block_device *, fmode_t, unsigned, unsigned long); - long (*direct_access)(struct block_device *, sector_t, void **, pfn_t *, - long); - unsigned int (*check_events) (struct gendisk *disk, - unsigned int clearing); - /* ->media_changed() is DEPRECATED, use ->check_events() instead */ - int (*media_changed) (struct gendisk *); - void (*unlock_native_capacity) (struct gendisk *); - int (*revalidate_disk) (struct gendisk *); - int (*getgeo)(struct block_device *, struct hd_geometry *); - /* this callback is with swap_lock and sometimes page table lock held */ - void (*swap_slot_free_notify) (struct block_device *, unsigned long); - struct module *owner; - const struct pr_ops *pr_ops; -}; - -extern int __blkdev_driver_ioctl(struct block_device *, fmode_t, unsigned int, - unsigned long); -extern int bdev_read_page(struct block_device *, sector_t, struct page *); -extern int bdev_write_page(struct block_device *, sector_t, struct page *, - struct writeback_control *); -extern long bdev_direct_access(struct block_device *, struct blk_dax_ctl *); -extern int bdev_dax_supported(struct super_block *, int); -extern bool bdev_dax_capable(struct block_device *); -#else /* CONFIG_BLOCK */ - -struct block_device; - -/* - * stubs for when the block layer is configured out - */ -#define buffer_heads_over_limit 0 - -static inline long nr_blockdev_pages(void) -{ - return 0; -} - -struct blk_plug { -}; - -static inline void blk_start_plug(struct blk_plug *plug) -{ -} - -static inline void blk_finish_plug(struct blk_plug *plug) -{ -} - -static inline void blk_flush_plug(struct task_struct *task) -{ -} - -static inline void blk_schedule_flush_plug(struct task_struct *task) -{ -} - - -static inline bool blk_needs_flush_plug(struct task_struct *tsk) -{ - return false; -} - -static inline int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask, - sector_t *error_sector) -{ - return 0; -} - -#endif /* CONFIG_BLOCK */ - -#endif diff --git a/src/linux/include/linux/blkpg.h b/src/linux/include/linux/blkpg.h deleted file mode 100644 index bef124f..0000000 --- a/src/linux/include/linux/blkpg.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _LINUX_BLKPG_H -#define _LINUX_BLKPG_H - -/* - * Partition table and disk geometry handling - */ - -#include -#include - -#ifdef CONFIG_COMPAT -/* For 32-bit/64-bit compatibility of struct blkpg_ioctl_arg */ -struct blkpg_compat_ioctl_arg { - compat_int_t op; - compat_int_t flags; - compat_int_t datalen; - compat_uptr_t data; -}; -#endif - -#endif /* _LINUX_BLKPG_H */ diff --git a/src/linux/include/linux/blktrace_api.h b/src/linux/include/linux/blktrace_api.h deleted file mode 100644 index cceb72f..0000000 --- a/src/linux/include/linux/blktrace_api.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef BLKTRACE_H -#define BLKTRACE_H - -#include -#include -#include -#include -#include - -#if defined(CONFIG_BLK_DEV_IO_TRACE) - -#include - -struct blk_trace { - int trace_state; - struct rchan *rchan; - unsigned long __percpu *sequence; - unsigned char __percpu *msg_data; - u16 act_mask; - u64 start_lba; - u64 end_lba; - u32 pid; - u32 dev; - struct dentry *dir; - struct dentry *dropped_file; - struct dentry *msg_file; - struct list_head running_list; - atomic_t dropped; -}; - -extern int blk_trace_ioctl(struct block_device *, unsigned, char __user *); -extern void blk_trace_shutdown(struct request_queue *); -extern int do_blk_trace_setup(struct request_queue *q, char *name, - dev_t dev, struct block_device *bdev, - struct blk_user_trace_setup *buts); -extern __printf(2, 3) -void __trace_note_message(struct blk_trace *, const char *fmt, ...); - -/** - * blk_add_trace_msg - Add a (simple) message to the blktrace stream - * @q: queue the io is for - * @fmt: format to print message in - * args... Variable argument list for format - * - * Description: - * Records a (simple) message onto the blktrace stream. - * - * NOTE: BLK_TN_MAX_MSG characters are output at most. - * NOTE: Can not use 'static inline' due to presence of var args... - * - **/ -#define blk_add_trace_msg(q, fmt, ...) \ - do { \ - struct blk_trace *bt = (q)->blk_trace; \ - if (unlikely(bt)) \ - __trace_note_message(bt, fmt, ##__VA_ARGS__); \ - } while (0) -#define BLK_TN_MAX_MSG 128 - -static inline bool blk_trace_note_message_enabled(struct request_queue *q) -{ - struct blk_trace *bt = q->blk_trace; - if (likely(!bt)) - return false; - return bt->act_mask & BLK_TC_NOTIFY; -} - -extern void blk_add_driver_data(struct request_queue *q, struct request *rq, - void *data, size_t len); -extern int blk_trace_setup(struct request_queue *q, char *name, dev_t dev, - struct block_device *bdev, - char __user *arg); -extern int blk_trace_startstop(struct request_queue *q, int start); -extern int blk_trace_remove(struct request_queue *q); -extern void blk_trace_remove_sysfs(struct device *dev); -extern int blk_trace_init_sysfs(struct device *dev); - -extern struct attribute_group blk_trace_attr_group; - -#else /* !CONFIG_BLK_DEV_IO_TRACE */ -# define blk_trace_ioctl(bdev, cmd, arg) (-ENOTTY) -# define blk_trace_shutdown(q) do { } while (0) -# define do_blk_trace_setup(q, name, dev, bdev, buts) (-ENOTTY) -# define blk_add_driver_data(q, rq, data, len) do {} while (0) -# define blk_trace_setup(q, name, dev, bdev, arg) (-ENOTTY) -# define blk_trace_startstop(q, start) (-ENOTTY) -# define blk_trace_remove(q) (-ENOTTY) -# define blk_add_trace_msg(q, fmt, ...) do { } while (0) -# define blk_trace_remove_sysfs(dev) do { } while (0) -# define blk_trace_note_message_enabled(q) (false) -static inline int blk_trace_init_sysfs(struct device *dev) -{ - return 0; -} - -#endif /* CONFIG_BLK_DEV_IO_TRACE */ - -#ifdef CONFIG_COMPAT - -struct compat_blk_user_trace_setup { - char name[BLKTRACE_BDEV_SIZE]; - u16 act_mask; - u32 buf_size; - u32 buf_nr; - compat_u64 start_lba; - compat_u64 end_lba; - u32 pid; -}; -#define BLKTRACESETUP32 _IOWR(0x12, 115, struct compat_blk_user_trace_setup) - -#endif - -#if defined(CONFIG_EVENT_TRACING) && defined(CONFIG_BLOCK) - -static inline int blk_cmd_buf_len(struct request *rq) -{ - return (rq->cmd_type == REQ_TYPE_BLOCK_PC) ? rq->cmd_len * 3 : 1; -} - -extern void blk_dump_cmd(char *buf, struct request *rq); -extern void blk_fill_rwbs(char *rwbs, int op, u32 rw, int bytes); - -#endif /* CONFIG_EVENT_TRACING && CONFIG_BLOCK */ - -#endif diff --git a/src/linux/include/linux/blockgroup_lock.h b/src/linux/include/linux/blockgroup_lock.h deleted file mode 100644 index 225bdb7..0000000 --- a/src/linux/include/linux/blockgroup_lock.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef _LINUX_BLOCKGROUP_LOCK_H -#define _LINUX_BLOCKGROUP_LOCK_H -/* - * Per-blockgroup locking for ext2 and ext3. - * - * Simple hashed spinlocking. - */ - -#include -#include - -#ifdef CONFIG_SMP -#define NR_BG_LOCKS (4 << ilog2(NR_CPUS < 32 ? NR_CPUS : 32)) -#else -#define NR_BG_LOCKS 1 -#endif - -struct bgl_lock { - spinlock_t lock; -} ____cacheline_aligned_in_smp; - -struct blockgroup_lock { - struct bgl_lock locks[NR_BG_LOCKS]; -}; - -static inline void bgl_lock_init(struct blockgroup_lock *bgl) -{ - int i; - - for (i = 0; i < NR_BG_LOCKS; i++) - spin_lock_init(&bgl->locks[i].lock); -} - -static inline spinlock_t * -bgl_lock_ptr(struct blockgroup_lock *bgl, unsigned int block_group) -{ - return &bgl->locks[block_group & (NR_BG_LOCKS-1)].lock; -} - -#endif diff --git a/src/linux/include/linux/bootmem.h b/src/linux/include/linux/bootmem.h deleted file mode 100644 index 962164d..0000000 --- a/src/linux/include/linux/bootmem.h +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Discontiguous memory support, Kanoj Sarcar, SGI, Nov 1999 - */ -#ifndef _LINUX_BOOTMEM_H -#define _LINUX_BOOTMEM_H - -#include -#include -#include -#include - -/* - * simple boot-time physical memory area allocator. - */ - -extern unsigned long max_low_pfn; -extern unsigned long min_low_pfn; - -/* - * highest page - */ -extern unsigned long max_pfn; -/* - * highest possible page - */ -extern unsigned long long max_possible_pfn; - -#ifndef CONFIG_NO_BOOTMEM -/* - * node_bootmem_map is a map pointer - the bits represent all physical - * memory pages (including holes) on the node. - */ -typedef struct bootmem_data { - unsigned long node_min_pfn; - unsigned long node_low_pfn; - void *node_bootmem_map; - unsigned long last_end_off; - unsigned long hint_idx; - struct list_head list; -} bootmem_data_t; - -extern bootmem_data_t bootmem_node_data[]; -#endif - -extern unsigned long bootmem_bootmap_pages(unsigned long); - -extern unsigned long init_bootmem_node(pg_data_t *pgdat, - unsigned long freepfn, - unsigned long startpfn, - unsigned long endpfn); -extern unsigned long init_bootmem(unsigned long addr, unsigned long memend); - -extern unsigned long free_all_bootmem(void); -extern void reset_node_managed_pages(pg_data_t *pgdat); -extern void reset_all_zones_managed_pages(void); - -extern void free_bootmem_node(pg_data_t *pgdat, - unsigned long addr, - unsigned long size); -extern void free_bootmem(unsigned long physaddr, unsigned long size); -extern void free_bootmem_late(unsigned long physaddr, unsigned long size); - -/* - * Flags for reserve_bootmem (also if CONFIG_HAVE_ARCH_BOOTMEM_NODE, - * the architecture-specific code should honor this). - * - * If flags is BOOTMEM_DEFAULT, then the return value is always 0 (success). - * If flags contains BOOTMEM_EXCLUSIVE, then -EBUSY is returned if the memory - * already was reserved. - */ -#define BOOTMEM_DEFAULT 0 -#define BOOTMEM_EXCLUSIVE (1<<0) - -extern int reserve_bootmem(unsigned long addr, - unsigned long size, - int flags); -extern int reserve_bootmem_node(pg_data_t *pgdat, - unsigned long physaddr, - unsigned long size, - int flags); - -extern void *__alloc_bootmem(unsigned long size, - unsigned long align, - unsigned long goal); -extern void *__alloc_bootmem_nopanic(unsigned long size, - unsigned long align, - unsigned long goal) __malloc; -extern void *__alloc_bootmem_node(pg_data_t *pgdat, - unsigned long size, - unsigned long align, - unsigned long goal) __malloc; -void *__alloc_bootmem_node_high(pg_data_t *pgdat, - unsigned long size, - unsigned long align, - unsigned long goal) __malloc; -extern void *__alloc_bootmem_node_nopanic(pg_data_t *pgdat, - unsigned long size, - unsigned long align, - unsigned long goal) __malloc; -void *___alloc_bootmem_node_nopanic(pg_data_t *pgdat, - unsigned long size, - unsigned long align, - unsigned long goal, - unsigned long limit) __malloc; -extern void *__alloc_bootmem_low(unsigned long size, - unsigned long align, - unsigned long goal) __malloc; -void *__alloc_bootmem_low_nopanic(unsigned long size, - unsigned long align, - unsigned long goal) __malloc; -extern void *__alloc_bootmem_low_node(pg_data_t *pgdat, - unsigned long size, - unsigned long align, - unsigned long goal) __malloc; - -#ifdef CONFIG_NO_BOOTMEM -/* We are using top down, so it is safe to use 0 here */ -#define BOOTMEM_LOW_LIMIT 0 -#else -#define BOOTMEM_LOW_LIMIT __pa(MAX_DMA_ADDRESS) -#endif - -#ifndef ARCH_LOW_ADDRESS_LIMIT -#define ARCH_LOW_ADDRESS_LIMIT 0xffffffffUL -#endif - -#define alloc_bootmem(x) \ - __alloc_bootmem(x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT) -#define alloc_bootmem_align(x, align) \ - __alloc_bootmem(x, align, BOOTMEM_LOW_LIMIT) -#define alloc_bootmem_nopanic(x) \ - __alloc_bootmem_nopanic(x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT) -#define alloc_bootmem_pages(x) \ - __alloc_bootmem(x, PAGE_SIZE, BOOTMEM_LOW_LIMIT) -#define alloc_bootmem_pages_nopanic(x) \ - __alloc_bootmem_nopanic(x, PAGE_SIZE, BOOTMEM_LOW_LIMIT) -#define alloc_bootmem_node(pgdat, x) \ - __alloc_bootmem_node(pgdat, x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT) -#define alloc_bootmem_node_nopanic(pgdat, x) \ - __alloc_bootmem_node_nopanic(pgdat, x, SMP_CACHE_BYTES, BOOTMEM_LOW_LIMIT) -#define alloc_bootmem_pages_node(pgdat, x) \ - __alloc_bootmem_node(pgdat, x, PAGE_SIZE, BOOTMEM_LOW_LIMIT) -#define alloc_bootmem_pages_node_nopanic(pgdat, x) \ - __alloc_bootmem_node_nopanic(pgdat, x, PAGE_SIZE, BOOTMEM_LOW_LIMIT) - -#define alloc_bootmem_low(x) \ - __alloc_bootmem_low(x, SMP_CACHE_BYTES, 0) -#define alloc_bootmem_low_pages_nopanic(x) \ - __alloc_bootmem_low_nopanic(x, PAGE_SIZE, 0) -#define alloc_bootmem_low_pages(x) \ - __alloc_bootmem_low(x, PAGE_SIZE, 0) -#define alloc_bootmem_low_pages_node(pgdat, x) \ - __alloc_bootmem_low_node(pgdat, x, PAGE_SIZE, 0) - - -#if defined(CONFIG_HAVE_MEMBLOCK) && defined(CONFIG_NO_BOOTMEM) - -/* FIXME: use MEMBLOCK_ALLOC_* variants here */ -#define BOOTMEM_ALLOC_ACCESSIBLE 0 -#define BOOTMEM_ALLOC_ANYWHERE (~(phys_addr_t)0) - -/* FIXME: Move to memblock.h at a point where we remove nobootmem.c */ -void *memblock_virt_alloc_try_nid_nopanic(phys_addr_t size, - phys_addr_t align, phys_addr_t min_addr, - phys_addr_t max_addr, int nid); -void *memblock_virt_alloc_try_nid(phys_addr_t size, phys_addr_t align, - phys_addr_t min_addr, phys_addr_t max_addr, int nid); -void __memblock_free_early(phys_addr_t base, phys_addr_t size); -void __memblock_free_late(phys_addr_t base, phys_addr_t size); - -static inline void * __init memblock_virt_alloc( - phys_addr_t size, phys_addr_t align) -{ - return memblock_virt_alloc_try_nid(size, align, BOOTMEM_LOW_LIMIT, - BOOTMEM_ALLOC_ACCESSIBLE, - NUMA_NO_NODE); -} - -static inline void * __init memblock_virt_alloc_nopanic( - phys_addr_t size, phys_addr_t align) -{ - return memblock_virt_alloc_try_nid_nopanic(size, align, - BOOTMEM_LOW_LIMIT, - BOOTMEM_ALLOC_ACCESSIBLE, - NUMA_NO_NODE); -} - -static inline void * __init memblock_virt_alloc_low( - phys_addr_t size, phys_addr_t align) -{ - return memblock_virt_alloc_try_nid(size, align, - BOOTMEM_LOW_LIMIT, - ARCH_LOW_ADDRESS_LIMIT, - NUMA_NO_NODE); -} -static inline void * __init memblock_virt_alloc_low_nopanic( - phys_addr_t size, phys_addr_t align) -{ - return memblock_virt_alloc_try_nid_nopanic(size, align, - BOOTMEM_LOW_LIMIT, - ARCH_LOW_ADDRESS_LIMIT, - NUMA_NO_NODE); -} - -static inline void * __init memblock_virt_alloc_from_nopanic( - phys_addr_t size, phys_addr_t align, phys_addr_t min_addr) -{ - return memblock_virt_alloc_try_nid_nopanic(size, align, min_addr, - BOOTMEM_ALLOC_ACCESSIBLE, - NUMA_NO_NODE); -} - -static inline void * __init memblock_virt_alloc_node( - phys_addr_t size, int nid) -{ - return memblock_virt_alloc_try_nid(size, 0, BOOTMEM_LOW_LIMIT, - BOOTMEM_ALLOC_ACCESSIBLE, nid); -} - -static inline void * __init memblock_virt_alloc_node_nopanic( - phys_addr_t size, int nid) -{ - return memblock_virt_alloc_try_nid_nopanic(size, 0, BOOTMEM_LOW_LIMIT, - BOOTMEM_ALLOC_ACCESSIBLE, - nid); -} - -static inline void __init memblock_free_early( - phys_addr_t base, phys_addr_t size) -{ - __memblock_free_early(base, size); -} - -static inline void __init memblock_free_early_nid( - phys_addr_t base, phys_addr_t size, int nid) -{ - __memblock_free_early(base, size); -} - -static inline void __init memblock_free_late( - phys_addr_t base, phys_addr_t size) -{ - __memblock_free_late(base, size); -} - -#else - -#define BOOTMEM_ALLOC_ACCESSIBLE 0 - - -/* Fall back to all the existing bootmem APIs */ -static inline void * __init memblock_virt_alloc( - phys_addr_t size, phys_addr_t align) -{ - if (!align) - align = SMP_CACHE_BYTES; - return __alloc_bootmem(size, align, BOOTMEM_LOW_LIMIT); -} - -static inline void * __init memblock_virt_alloc_nopanic( - phys_addr_t size, phys_addr_t align) -{ - if (!align) - align = SMP_CACHE_BYTES; - return __alloc_bootmem_nopanic(size, align, BOOTMEM_LOW_LIMIT); -} - -static inline void * __init memblock_virt_alloc_low( - phys_addr_t size, phys_addr_t align) -{ - if (!align) - align = SMP_CACHE_BYTES; - return __alloc_bootmem_low(size, align, 0); -} - -static inline void * __init memblock_virt_alloc_low_nopanic( - phys_addr_t size, phys_addr_t align) -{ - if (!align) - align = SMP_CACHE_BYTES; - return __alloc_bootmem_low_nopanic(size, align, 0); -} - -static inline void * __init memblock_virt_alloc_from_nopanic( - phys_addr_t size, phys_addr_t align, phys_addr_t min_addr) -{ - return __alloc_bootmem_nopanic(size, align, min_addr); -} - -static inline void * __init memblock_virt_alloc_node( - phys_addr_t size, int nid) -{ - return __alloc_bootmem_node(NODE_DATA(nid), size, SMP_CACHE_BYTES, - BOOTMEM_LOW_LIMIT); -} - -static inline void * __init memblock_virt_alloc_node_nopanic( - phys_addr_t size, int nid) -{ - return __alloc_bootmem_node_nopanic(NODE_DATA(nid), size, - SMP_CACHE_BYTES, - BOOTMEM_LOW_LIMIT); -} - -static inline void * __init memblock_virt_alloc_try_nid(phys_addr_t size, - phys_addr_t align, phys_addr_t min_addr, phys_addr_t max_addr, int nid) -{ - return __alloc_bootmem_node_high(NODE_DATA(nid), size, align, - min_addr); -} - -static inline void * __init memblock_virt_alloc_try_nid_nopanic( - phys_addr_t size, phys_addr_t align, - phys_addr_t min_addr, phys_addr_t max_addr, int nid) -{ - return ___alloc_bootmem_node_nopanic(NODE_DATA(nid), size, align, - min_addr, max_addr); -} - -static inline void __init memblock_free_early( - phys_addr_t base, phys_addr_t size) -{ - free_bootmem(base, size); -} - -static inline void __init memblock_free_early_nid( - phys_addr_t base, phys_addr_t size, int nid) -{ - free_bootmem_node(NODE_DATA(nid), base, size); -} - -static inline void __init memblock_free_late( - phys_addr_t base, phys_addr_t size) -{ - free_bootmem_late(base, size); -} -#endif /* defined(CONFIG_HAVE_MEMBLOCK) && defined(CONFIG_NO_BOOTMEM) */ - -#ifdef CONFIG_HAVE_ARCH_ALLOC_REMAP -extern void *alloc_remap(int nid, unsigned long size); -#else -static inline void *alloc_remap(int nid, unsigned long size) -{ - return NULL; -} -#endif /* CONFIG_HAVE_ARCH_ALLOC_REMAP */ - -extern void *alloc_large_system_hash(const char *tablename, - unsigned long bucketsize, - unsigned long numentries, - int scale, - int flags, - unsigned int *_hash_shift, - unsigned int *_hash_mask, - unsigned long low_limit, - unsigned long high_limit); - -#define HASH_EARLY 0x00000001 /* Allocating during early boot? */ -#define HASH_SMALL 0x00000002 /* sub-page allocation allowed, min - * shift passed via *_hash_shift */ - -/* Only NUMA needs hash distribution. 64bit NUMA architectures have - * sufficient vmalloc space. - */ -#ifdef CONFIG_NUMA -#define HASHDIST_DEFAULT IS_ENABLED(CONFIG_64BIT) -extern int hashdist; /* Distribute hashes across NUMA nodes? */ -#else -#define hashdist (0) -#endif - - -#endif /* _LINUX_BOOTMEM_H */ diff --git a/src/linux/include/linux/bottom_half.h b/src/linux/include/linux/bottom_half.h deleted file mode 100644 index 8fdcb78..0000000 --- a/src/linux/include/linux/bottom_half.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _LINUX_BH_H -#define _LINUX_BH_H - -#include - -#ifdef CONFIG_TRACE_IRQFLAGS -extern void __local_bh_disable_ip(unsigned long ip, unsigned int cnt); -#else -static __always_inline void __local_bh_disable_ip(unsigned long ip, unsigned int cnt) -{ - preempt_count_add(cnt); - barrier(); -} -#endif - -static inline void local_bh_disable(void) -{ - __local_bh_disable_ip(_THIS_IP_, SOFTIRQ_DISABLE_OFFSET); -} - -extern void _local_bh_enable(void); -extern void __local_bh_enable_ip(unsigned long ip, unsigned int cnt); - -static inline void local_bh_enable_ip(unsigned long ip) -{ - __local_bh_enable_ip(ip, SOFTIRQ_DISABLE_OFFSET); -} - -static inline void local_bh_enable(void) -{ - __local_bh_enable_ip(_THIS_IP_, SOFTIRQ_DISABLE_OFFSET); -} - -#endif /* _LINUX_BH_H */ diff --git a/src/linux/include/linux/bpf.h b/src/linux/include/linux/bpf.h deleted file mode 100644 index c201017..0000000 --- a/src/linux/include/linux/bpf.h +++ /dev/null @@ -1,335 +0,0 @@ -/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - */ -#ifndef _LINUX_BPF_H -#define _LINUX_BPF_H 1 - -#include -#include -#include -#include -#include - -struct perf_event; -struct bpf_map; - -/* map is generic key/value storage optionally accesible by eBPF programs */ -struct bpf_map_ops { - /* funcs callable from userspace (via syscall) */ - struct bpf_map *(*map_alloc)(union bpf_attr *attr); - void (*map_release)(struct bpf_map *map, struct file *map_file); - void (*map_free)(struct bpf_map *map); - int (*map_get_next_key)(struct bpf_map *map, void *key, void *next_key); - - /* funcs callable from userspace and from eBPF programs */ - void *(*map_lookup_elem)(struct bpf_map *map, void *key); - int (*map_update_elem)(struct bpf_map *map, void *key, void *value, u64 flags); - int (*map_delete_elem)(struct bpf_map *map, void *key); - - /* funcs called by prog_array and perf_event_array map */ - void *(*map_fd_get_ptr)(struct bpf_map *map, struct file *map_file, - int fd); - void (*map_fd_put_ptr)(void *ptr); -}; - -struct bpf_map { - atomic_t refcnt; - enum bpf_map_type map_type; - u32 key_size; - u32 value_size; - u32 max_entries; - u32 map_flags; - u32 pages; - struct user_struct *user; - const struct bpf_map_ops *ops; - struct work_struct work; - atomic_t usercnt; -}; - -struct bpf_map_type_list { - struct list_head list_node; - const struct bpf_map_ops *ops; - enum bpf_map_type type; -}; - -/* function argument constraints */ -enum bpf_arg_type { - ARG_DONTCARE = 0, /* unused argument in helper function */ - - /* the following constraints used to prototype - * bpf_map_lookup/update/delete_elem() functions - */ - ARG_CONST_MAP_PTR, /* const argument used as pointer to bpf_map */ - ARG_PTR_TO_MAP_KEY, /* pointer to stack used as map key */ - ARG_PTR_TO_MAP_VALUE, /* pointer to stack used as map value */ - - /* the following constraints used to prototype bpf_memcmp() and other - * functions that access data on eBPF program stack - */ - ARG_PTR_TO_STACK, /* any pointer to eBPF program stack */ - ARG_PTR_TO_RAW_STACK, /* any pointer to eBPF program stack, area does not - * need to be initialized, helper function must fill - * all bytes or clear them in error case. - */ - - ARG_CONST_STACK_SIZE, /* number of bytes accessed from stack */ - ARG_CONST_STACK_SIZE_OR_ZERO, /* number of bytes accessed from stack or 0 */ - - ARG_PTR_TO_CTX, /* pointer to context */ - ARG_ANYTHING, /* any (initialized) argument is ok */ -}; - -/* type of values returned from helper functions */ -enum bpf_return_type { - RET_INTEGER, /* function returns integer */ - RET_VOID, /* function doesn't return anything */ - RET_PTR_TO_MAP_VALUE_OR_NULL, /* returns a pointer to map elem value or NULL */ -}; - -/* eBPF function prototype used by verifier to allow BPF_CALLs from eBPF programs - * to in-kernel helper functions and for adjusting imm32 field in BPF_CALL - * instructions after verifying - */ -struct bpf_func_proto { - u64 (*func)(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); - bool gpl_only; - bool pkt_access; - enum bpf_return_type ret_type; - enum bpf_arg_type arg1_type; - enum bpf_arg_type arg2_type; - enum bpf_arg_type arg3_type; - enum bpf_arg_type arg4_type; - enum bpf_arg_type arg5_type; -}; - -/* bpf_context is intentionally undefined structure. Pointer to bpf_context is - * the first argument to eBPF programs. - * For socket filters: 'struct bpf_context *' == 'struct sk_buff *' - */ -struct bpf_context; - -enum bpf_access_type { - BPF_READ = 1, - BPF_WRITE = 2 -}; - -/* types of values stored in eBPF registers */ -enum bpf_reg_type { - NOT_INIT = 0, /* nothing was written into register */ - UNKNOWN_VALUE, /* reg doesn't contain a valid pointer */ - PTR_TO_CTX, /* reg points to bpf_context */ - CONST_PTR_TO_MAP, /* reg points to struct bpf_map */ - PTR_TO_MAP_VALUE, /* reg points to map element value */ - PTR_TO_MAP_VALUE_OR_NULL,/* points to map elem value or NULL */ - FRAME_PTR, /* reg == frame_pointer */ - PTR_TO_STACK, /* reg == frame_pointer + imm */ - CONST_IMM, /* constant integer value */ - - /* PTR_TO_PACKET represents: - * skb->data - * skb->data + imm - * skb->data + (u16) var - * skb->data + (u16) var + imm - * if (range > 0) then [ptr, ptr + range - off) is safe to access - * if (id > 0) means that some 'var' was added - * if (off > 0) menas that 'imm' was added - */ - PTR_TO_PACKET, - PTR_TO_PACKET_END, /* skb->data + headlen */ - - /* PTR_TO_MAP_VALUE_ADJ is used for doing pointer math inside of a map - * elem value. We only allow this if we can statically verify that - * access from this register are going to fall within the size of the - * map element. - */ - PTR_TO_MAP_VALUE_ADJ, -}; - -struct bpf_prog; - -struct bpf_verifier_ops { - /* return eBPF function prototype for verification */ - const struct bpf_func_proto *(*get_func_proto)(enum bpf_func_id func_id); - - /* return true if 'size' wide access at offset 'off' within bpf_context - * with 'type' (read or write) is allowed - */ - bool (*is_valid_access)(int off, int size, enum bpf_access_type type, - enum bpf_reg_type *reg_type); - int (*gen_prologue)(struct bpf_insn *insn, bool direct_write, - const struct bpf_prog *prog); - u32 (*convert_ctx_access)(enum bpf_access_type type, int dst_reg, - int src_reg, int ctx_off, - struct bpf_insn *insn, struct bpf_prog *prog); -}; - -struct bpf_prog_type_list { - struct list_head list_node; - const struct bpf_verifier_ops *ops; - enum bpf_prog_type type; -}; - -struct bpf_prog_aux { - atomic_t refcnt; - u32 used_map_cnt; - u32 max_ctx_offset; - const struct bpf_verifier_ops *ops; - struct bpf_map **used_maps; - struct bpf_prog *prog; - struct user_struct *user; - union { - struct work_struct work; - struct rcu_head rcu; - }; -}; - -struct bpf_array { - struct bpf_map map; - u32 elem_size; - /* 'ownership' of prog_array is claimed by the first program that - * is going to use this map or by the first program which FD is stored - * in the map to make sure that all callers and callees have the same - * prog_type and JITed flag - */ - enum bpf_prog_type owner_prog_type; - bool owner_jited; - union { - char value[0] __aligned(8); - void *ptrs[0] __aligned(8); - void __percpu *pptrs[0] __aligned(8); - }; -}; - -#define MAX_TAIL_CALL_CNT 32 - -struct bpf_event_entry { - struct perf_event *event; - struct file *perf_file; - struct file *map_file; - struct rcu_head rcu; -}; - -u64 bpf_tail_call(u64 ctx, u64 r2, u64 index, u64 r4, u64 r5); -u64 bpf_get_stackid(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); - -bool bpf_prog_array_compatible(struct bpf_array *array, const struct bpf_prog *fp); - -const struct bpf_func_proto *bpf_get_trace_printk_proto(void); - -typedef unsigned long (*bpf_ctx_copy_t)(void *dst, const void *src, - unsigned long off, unsigned long len); - -u64 bpf_event_output(struct bpf_map *map, u64 flags, void *meta, u64 meta_size, - void *ctx, u64 ctx_size, bpf_ctx_copy_t ctx_copy); - -#ifdef CONFIG_BPF_SYSCALL -DECLARE_PER_CPU(int, bpf_prog_active); - -void bpf_register_prog_type(struct bpf_prog_type_list *tl); -void bpf_register_map_type(struct bpf_map_type_list *tl); - -struct bpf_prog *bpf_prog_get(u32 ufd); -struct bpf_prog *bpf_prog_get_type(u32 ufd, enum bpf_prog_type type); -struct bpf_prog *bpf_prog_add(struct bpf_prog *prog, int i); -struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog); -void bpf_prog_put(struct bpf_prog *prog); - -struct bpf_map *bpf_map_get_with_uref(u32 ufd); -struct bpf_map *__bpf_map_get(struct fd f); -struct bpf_map *bpf_map_inc(struct bpf_map *map, bool uref); -void bpf_map_put_with_uref(struct bpf_map *map); -void bpf_map_put(struct bpf_map *map); -int bpf_map_precharge_memlock(u32 pages); - -extern int sysctl_unprivileged_bpf_disabled; - -int bpf_map_new_fd(struct bpf_map *map); -int bpf_prog_new_fd(struct bpf_prog *prog); - -int bpf_obj_pin_user(u32 ufd, const char __user *pathname); -int bpf_obj_get_user(const char __user *pathname); - -int bpf_percpu_hash_copy(struct bpf_map *map, void *key, void *value); -int bpf_percpu_array_copy(struct bpf_map *map, void *key, void *value); -int bpf_percpu_hash_update(struct bpf_map *map, void *key, void *value, - u64 flags); -int bpf_percpu_array_update(struct bpf_map *map, void *key, void *value, - u64 flags); - -int bpf_stackmap_copy(struct bpf_map *map, void *key, void *value); - -int bpf_fd_array_map_update_elem(struct bpf_map *map, struct file *map_file, - void *key, void *value, u64 map_flags); -void bpf_fd_array_map_clear(struct bpf_map *map); - -/* memcpy that is used with 8-byte aligned pointers, power-of-8 size and - * forced to use 'long' read/writes to try to atomically copy long counters. - * Best-effort only. No barriers here, since it _will_ race with concurrent - * updates from BPF programs. Called from bpf syscall and mostly used with - * size 8 or 16 bytes, so ask compiler to inline it. - */ -static inline void bpf_long_memcpy(void *dst, const void *src, u32 size) -{ - const long *lsrc = src; - long *ldst = dst; - - size /= sizeof(long); - while (size--) - *ldst++ = *lsrc++; -} - -/* verify correctness of eBPF program */ -int bpf_check(struct bpf_prog **fp, union bpf_attr *attr); -#else -static inline void bpf_register_prog_type(struct bpf_prog_type_list *tl) -{ -} - -static inline struct bpf_prog *bpf_prog_get(u32 ufd) -{ - return ERR_PTR(-EOPNOTSUPP); -} - -static inline struct bpf_prog *bpf_prog_get_type(u32 ufd, - enum bpf_prog_type type) -{ - return ERR_PTR(-EOPNOTSUPP); -} -static inline struct bpf_prog *bpf_prog_add(struct bpf_prog *prog, int i) -{ - return ERR_PTR(-EOPNOTSUPP); -} - -static inline void bpf_prog_put(struct bpf_prog *prog) -{ -} -static inline struct bpf_prog *bpf_prog_inc(struct bpf_prog *prog) -{ - return ERR_PTR(-EOPNOTSUPP); -} -#endif /* CONFIG_BPF_SYSCALL */ - -/* verifier prototypes for helper functions called from eBPF programs */ -extern const struct bpf_func_proto bpf_map_lookup_elem_proto; -extern const struct bpf_func_proto bpf_map_update_elem_proto; -extern const struct bpf_func_proto bpf_map_delete_elem_proto; - -extern const struct bpf_func_proto bpf_get_prandom_u32_proto; -extern const struct bpf_func_proto bpf_get_smp_processor_id_proto; -extern const struct bpf_func_proto bpf_tail_call_proto; -extern const struct bpf_func_proto bpf_ktime_get_ns_proto; -extern const struct bpf_func_proto bpf_get_current_pid_tgid_proto; -extern const struct bpf_func_proto bpf_get_current_uid_gid_proto; -extern const struct bpf_func_proto bpf_get_current_comm_proto; -extern const struct bpf_func_proto bpf_skb_vlan_push_proto; -extern const struct bpf_func_proto bpf_skb_vlan_pop_proto; -extern const struct bpf_func_proto bpf_get_stackid_proto; - -/* Shared helpers among cBPF and eBPF. */ -void bpf_user_rnd_init_once(void); -u64 bpf_user_rnd_u32(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); - -#endif /* _LINUX_BPF_H */ diff --git a/src/linux/include/linux/bsearch.h b/src/linux/include/linux/bsearch.h deleted file mode 100644 index 90b1aa8..0000000 --- a/src/linux/include/linux/bsearch.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _LINUX_BSEARCH_H -#define _LINUX_BSEARCH_H - -#include - -void *bsearch(const void *key, const void *base, size_t num, size_t size, - int (*cmp)(const void *key, const void *elt)); - -#endif /* _LINUX_BSEARCH_H */ diff --git a/src/linux/include/linux/bsg.h b/src/linux/include/linux/bsg.h deleted file mode 100644 index 7173f6e..0000000 --- a/src/linux/include/linux/bsg.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef BSG_H -#define BSG_H - -#include - - -#if defined(CONFIG_BLK_DEV_BSG) -struct bsg_class_device { - struct device *class_dev; - struct device *parent; - int minor; - struct request_queue *queue; - struct kref ref; - void (*release)(struct device *); -}; - -extern int bsg_register_queue(struct request_queue *q, - struct device *parent, const char *name, - void (*release)(struct device *)); -extern void bsg_unregister_queue(struct request_queue *); -#else -static inline int bsg_register_queue(struct request_queue *q, - struct device *parent, const char *name, - void (*release)(struct device *)) -{ - return 0; -} -static inline void bsg_unregister_queue(struct request_queue *q) -{ -} -#endif - -#endif diff --git a/src/linux/include/linux/btrfs.h b/src/linux/include/linux/btrfs.h deleted file mode 100644 index 22d7991..0000000 --- a/src/linux/include/linux/btrfs.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _LINUX_BTRFS_H -#define _LINUX_BTRFS_H - -#include - -#endif /* _LINUX_BTRFS_H */ diff --git a/src/linux/include/linux/buffer_head.h b/src/linux/include/linux/buffer_head.h deleted file mode 100644 index ebbacd1..0000000 --- a/src/linux/include/linux/buffer_head.h +++ /dev/null @@ -1,405 +0,0 @@ -/* - * include/linux/buffer_head.h - * - * Everything to do with buffer_heads. - */ - -#ifndef _LINUX_BUFFER_HEAD_H -#define _LINUX_BUFFER_HEAD_H - -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_BLOCK - -enum bh_state_bits { - BH_Uptodate, /* Contains valid data */ - BH_Dirty, /* Is dirty */ - BH_Lock, /* Is locked */ - BH_Req, /* Has been submitted for I/O */ - BH_Uptodate_Lock,/* Used by the first bh in a page, to serialise - * IO completion of other buffers in the page - */ - - BH_Mapped, /* Has a disk mapping */ - BH_New, /* Disk mapping was newly created by get_block */ - BH_Async_Read, /* Is under end_buffer_async_read I/O */ - BH_Async_Write, /* Is under end_buffer_async_write I/O */ - BH_Delay, /* Buffer is not yet allocated on disk */ - BH_Boundary, /* Block is followed by a discontiguity */ - BH_Write_EIO, /* I/O error on write */ - BH_Unwritten, /* Buffer is allocated on disk but not written */ - BH_Quiet, /* Buffer Error Prinks to be quiet */ - BH_Meta, /* Buffer contains metadata */ - BH_Prio, /* Buffer should be submitted with REQ_PRIO */ - BH_Defer_Completion, /* Defer AIO completion to workqueue */ - - BH_PrivateStart,/* not a state bit, but the first bit available - * for private allocation by other entities - */ -}; - -#define MAX_BUF_PER_PAGE (PAGE_SIZE / 512) - -struct page; -struct buffer_head; -struct address_space; -typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate); - -/* - * Historically, a buffer_head was used to map a single block - * within a page, and of course as the unit of I/O through the - * filesystem and block layers. Nowadays the basic I/O unit - * is the bio, and buffer_heads are used for extracting block - * mappings (via a get_block_t call), for tracking state within - * a page (via a page_mapping) and for wrapping bio submission - * for backward compatibility reasons (e.g. submit_bh). - */ -struct buffer_head { - unsigned long b_state; /* buffer state bitmap (see above) */ - struct buffer_head *b_this_page;/* circular list of page's buffers */ - struct page *b_page; /* the page this bh is mapped to */ - - sector_t b_blocknr; /* start block number */ - size_t b_size; /* size of mapping */ - char *b_data; /* pointer to data within the page */ - - struct block_device *b_bdev; - bh_end_io_t *b_end_io; /* I/O completion */ - void *b_private; /* reserved for b_end_io */ - struct list_head b_assoc_buffers; /* associated with another mapping */ - struct address_space *b_assoc_map; /* mapping this buffer is - associated with */ - atomic_t b_count; /* users using this buffer_head */ -}; - -/* - * macro tricks to expand the set_buffer_foo(), clear_buffer_foo() - * and buffer_foo() functions. - */ -#define BUFFER_FNS(bit, name) \ -static __always_inline void set_buffer_##name(struct buffer_head *bh) \ -{ \ - set_bit(BH_##bit, &(bh)->b_state); \ -} \ -static __always_inline void clear_buffer_##name(struct buffer_head *bh) \ -{ \ - clear_bit(BH_##bit, &(bh)->b_state); \ -} \ -static __always_inline int buffer_##name(const struct buffer_head *bh) \ -{ \ - return test_bit(BH_##bit, &(bh)->b_state); \ -} - -/* - * test_set_buffer_foo() and test_clear_buffer_foo() - */ -#define TAS_BUFFER_FNS(bit, name) \ -static __always_inline int test_set_buffer_##name(struct buffer_head *bh) \ -{ \ - return test_and_set_bit(BH_##bit, &(bh)->b_state); \ -} \ -static __always_inline int test_clear_buffer_##name(struct buffer_head *bh) \ -{ \ - return test_and_clear_bit(BH_##bit, &(bh)->b_state); \ -} \ - -/* - * Emit the buffer bitops functions. Note that there are also functions - * of the form "mark_buffer_foo()". These are higher-level functions which - * do something in addition to setting a b_state bit. - */ -BUFFER_FNS(Uptodate, uptodate) -BUFFER_FNS(Dirty, dirty) -TAS_BUFFER_FNS(Dirty, dirty) -BUFFER_FNS(Lock, locked) -BUFFER_FNS(Req, req) -TAS_BUFFER_FNS(Req, req) -BUFFER_FNS(Mapped, mapped) -BUFFER_FNS(New, new) -BUFFER_FNS(Async_Read, async_read) -BUFFER_FNS(Async_Write, async_write) -BUFFER_FNS(Delay, delay) -BUFFER_FNS(Boundary, boundary) -BUFFER_FNS(Write_EIO, write_io_error) -BUFFER_FNS(Unwritten, unwritten) -BUFFER_FNS(Meta, meta) -BUFFER_FNS(Prio, prio) -BUFFER_FNS(Defer_Completion, defer_completion) - -#define bh_offset(bh) ((unsigned long)(bh)->b_data & ~PAGE_MASK) - -/* If we *know* page->private refers to buffer_heads */ -#define page_buffers(page) \ - ({ \ - BUG_ON(!PagePrivate(page)); \ - ((struct buffer_head *)page_private(page)); \ - }) -#define page_has_buffers(page) PagePrivate(page) - -void buffer_check_dirty_writeback(struct page *page, - bool *dirty, bool *writeback); - -/* - * Declarations - */ - -void mark_buffer_dirty(struct buffer_head *bh); -void init_buffer(struct buffer_head *, bh_end_io_t *, void *); -void touch_buffer(struct buffer_head *bh); -void set_bh_page(struct buffer_head *bh, - struct page *page, unsigned long offset); -int try_to_free_buffers(struct page *); -struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size, - int retry); -void create_empty_buffers(struct page *, unsigned long, - unsigned long b_state); -void end_buffer_read_sync(struct buffer_head *bh, int uptodate); -void end_buffer_write_sync(struct buffer_head *bh, int uptodate); -void end_buffer_async_write(struct buffer_head *bh, int uptodate); - -/* Things to do with buffers at mapping->private_list */ -void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode); -int inode_has_buffers(struct inode *); -void invalidate_inode_buffers(struct inode *); -int remove_inode_buffers(struct inode *inode); -int sync_mapping_buffers(struct address_space *mapping); -void unmap_underlying_metadata(struct block_device *bdev, sector_t block); - -void mark_buffer_async_write(struct buffer_head *bh); -void __wait_on_buffer(struct buffer_head *); -wait_queue_head_t *bh_waitq_head(struct buffer_head *bh); -struct buffer_head *__find_get_block(struct block_device *bdev, sector_t block, - unsigned size); -struct buffer_head *__getblk_gfp(struct block_device *bdev, sector_t block, - unsigned size, gfp_t gfp); -void __brelse(struct buffer_head *); -void __bforget(struct buffer_head *); -void __breadahead(struct block_device *, sector_t block, unsigned int size); -struct buffer_head *__bread_gfp(struct block_device *, - sector_t block, unsigned size, gfp_t gfp); -void invalidate_bh_lrus(void); -struct buffer_head *alloc_buffer_head(gfp_t gfp_flags); -void free_buffer_head(struct buffer_head * bh); -void unlock_buffer(struct buffer_head *bh); -void __lock_buffer(struct buffer_head *bh); -void ll_rw_block(int, int, int, struct buffer_head * bh[]); -int sync_dirty_buffer(struct buffer_head *bh); -int __sync_dirty_buffer(struct buffer_head *bh, int op_flags); -void write_dirty_buffer(struct buffer_head *bh, int op_flags); -int _submit_bh(int op, int op_flags, struct buffer_head *bh, - unsigned long bio_flags); -int submit_bh(int, int, struct buffer_head *); -void write_boundary_block(struct block_device *bdev, - sector_t bblock, unsigned blocksize); -int bh_uptodate_or_lock(struct buffer_head *bh); -int bh_submit_read(struct buffer_head *bh); - -extern int buffer_heads_over_limit; - -/* - * Generic address_space_operations implementations for buffer_head-backed - * address_spaces. - */ -void block_invalidatepage(struct page *page, unsigned int offset, - unsigned int length); -int block_write_full_page(struct page *page, get_block_t *get_block, - struct writeback_control *wbc); -int __block_write_full_page(struct inode *inode, struct page *page, - get_block_t *get_block, struct writeback_control *wbc, - bh_end_io_t *handler); -int block_read_full_page(struct page*, get_block_t*); -int block_is_partially_uptodate(struct page *page, unsigned long from, - unsigned long count); -int block_write_begin(struct address_space *mapping, loff_t pos, unsigned len, - unsigned flags, struct page **pagep, get_block_t *get_block); -int __block_write_begin(struct page *page, loff_t pos, unsigned len, - get_block_t *get_block); -int block_write_end(struct file *, struct address_space *, - loff_t, unsigned, unsigned, - struct page *, void *); -int generic_write_end(struct file *, struct address_space *, - loff_t, unsigned, unsigned, - struct page *, void *); -void page_zero_new_buffers(struct page *page, unsigned from, unsigned to); -int cont_write_begin(struct file *, struct address_space *, loff_t, - unsigned, unsigned, struct page **, void **, - get_block_t *, loff_t *); -int generic_cont_expand_simple(struct inode *inode, loff_t size); -int block_commit_write(struct page *page, unsigned from, unsigned to); -int block_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, - get_block_t get_block); -/* Convert errno to return value from ->page_mkwrite() call */ -static inline int block_page_mkwrite_return(int err) -{ - if (err == 0) - return VM_FAULT_LOCKED; - if (err == -EFAULT) - return VM_FAULT_NOPAGE; - if (err == -ENOMEM) - return VM_FAULT_OOM; - if (err == -EAGAIN) - return VM_FAULT_RETRY; - /* -ENOSPC, -EDQUOT, -EIO ... */ - return VM_FAULT_SIGBUS; -} -sector_t generic_block_bmap(struct address_space *, sector_t, get_block_t *); -int block_truncate_page(struct address_space *, loff_t, get_block_t *); -int nobh_write_begin(struct address_space *, loff_t, unsigned, unsigned, - struct page **, void **, get_block_t*); -int nobh_write_end(struct file *, struct address_space *, - loff_t, unsigned, unsigned, - struct page *, void *); -int nobh_truncate_page(struct address_space *, loff_t, get_block_t *); -int nobh_writepage(struct page *page, get_block_t *get_block, - struct writeback_control *wbc); - -void buffer_init(void); - -/* - * inline definitions - */ - -static inline void attach_page_buffers(struct page *page, - struct buffer_head *head) -{ - get_page(page); - SetPagePrivate(page); - set_page_private(page, (unsigned long)head); -} - -static inline void get_bh(struct buffer_head *bh) -{ - atomic_inc(&bh->b_count); -} - -static inline void put_bh(struct buffer_head *bh) -{ - smp_mb__before_atomic(); - atomic_dec(&bh->b_count); -} - -static inline void brelse(struct buffer_head *bh) -{ - if (bh) - __brelse(bh); -} - -static inline void bforget(struct buffer_head *bh) -{ - if (bh) - __bforget(bh); -} - -static inline struct buffer_head * -sb_bread(struct super_block *sb, sector_t block) -{ - return __bread_gfp(sb->s_bdev, block, sb->s_blocksize, __GFP_MOVABLE); -} - -static inline struct buffer_head * -sb_bread_unmovable(struct super_block *sb, sector_t block) -{ - return __bread_gfp(sb->s_bdev, block, sb->s_blocksize, 0); -} - -static inline void -sb_breadahead(struct super_block *sb, sector_t block) -{ - __breadahead(sb->s_bdev, block, sb->s_blocksize); -} - -static inline struct buffer_head * -sb_getblk(struct super_block *sb, sector_t block) -{ - return __getblk_gfp(sb->s_bdev, block, sb->s_blocksize, __GFP_MOVABLE); -} - - -static inline struct buffer_head * -sb_getblk_gfp(struct super_block *sb, sector_t block, gfp_t gfp) -{ - return __getblk_gfp(sb->s_bdev, block, sb->s_blocksize, gfp); -} - -static inline struct buffer_head * -sb_find_get_block(struct super_block *sb, sector_t block) -{ - return __find_get_block(sb->s_bdev, block, sb->s_blocksize); -} - -static inline void -map_bh(struct buffer_head *bh, struct super_block *sb, sector_t block) -{ - set_buffer_mapped(bh); - bh->b_bdev = sb->s_bdev; - bh->b_blocknr = block; - bh->b_size = sb->s_blocksize; -} - -static inline void wait_on_buffer(struct buffer_head *bh) -{ - might_sleep(); - if (buffer_locked(bh)) - __wait_on_buffer(bh); -} - -static inline int trylock_buffer(struct buffer_head *bh) -{ - return likely(!test_and_set_bit_lock(BH_Lock, &bh->b_state)); -} - -static inline void lock_buffer(struct buffer_head *bh) -{ - might_sleep(); - if (!trylock_buffer(bh)) - __lock_buffer(bh); -} - -static inline struct buffer_head *getblk_unmovable(struct block_device *bdev, - sector_t block, - unsigned size) -{ - return __getblk_gfp(bdev, block, size, 0); -} - -static inline struct buffer_head *__getblk(struct block_device *bdev, - sector_t block, - unsigned size) -{ - return __getblk_gfp(bdev, block, size, __GFP_MOVABLE); -} - -/** - * __bread() - reads a specified block and returns the bh - * @bdev: the block_device to read from - * @block: number of block - * @size: size (in bytes) to read - * - * Reads a specified block, and returns buffer head that contains it. - * The page cache is allocated from movable area so that it can be migrated. - * It returns NULL if the block was unreadable. - */ -static inline struct buffer_head * -__bread(struct block_device *bdev, sector_t block, unsigned size) -{ - return __bread_gfp(bdev, block, size, __GFP_MOVABLE); -} - -extern int __set_page_dirty_buffers(struct page *page); - -#else /* CONFIG_BLOCK */ - -static inline void buffer_init(void) {} -static inline int try_to_free_buffers(struct page *page) { return 1; } -static inline int inode_has_buffers(struct inode *inode) { return 0; } -static inline void invalidate_inode_buffers(struct inode *inode) {} -static inline int remove_inode_buffers(struct inode *inode) { return 1; } -static inline int sync_mapping_buffers(struct address_space *mapping) { return 0; } - -#endif /* CONFIG_BLOCK */ -#endif /* _LINUX_BUFFER_HEAD_H */ diff --git a/src/linux/include/linux/bug.h b/src/linux/include/linux/bug.h deleted file mode 100644 index 292d6a1..0000000 --- a/src/linux/include/linux/bug.h +++ /dev/null @@ -1,124 +0,0 @@ -#ifndef _LINUX_BUG_H -#define _LINUX_BUG_H - -#include -#include - -enum bug_trap_type { - BUG_TRAP_TYPE_NONE = 0, - BUG_TRAP_TYPE_WARN = 1, - BUG_TRAP_TYPE_BUG = 2, -}; - -struct pt_regs; - -#ifdef __CHECKER__ -#define __BUILD_BUG_ON_NOT_POWER_OF_2(n) (0) -#define BUILD_BUG_ON_NOT_POWER_OF_2(n) (0) -#define BUILD_BUG_ON_ZERO(e) (0) -#define BUILD_BUG_ON_NULL(e) ((void*)0) -#define BUILD_BUG_ON_INVALID(e) (0) -#define BUILD_BUG_ON_MSG(cond, msg) (0) -#define BUILD_BUG_ON(condition) (0) -#define BUILD_BUG() (0) -#define MAYBE_BUILD_BUG_ON(cond) (0) -#else /* __CHECKER__ */ - -/* Force a compilation error if a constant expression is not a power of 2 */ -#define __BUILD_BUG_ON_NOT_POWER_OF_2(n) \ - BUILD_BUG_ON(((n) & ((n) - 1)) != 0) -#define BUILD_BUG_ON_NOT_POWER_OF_2(n) \ - BUILD_BUG_ON((n) == 0 || (((n) & ((n) - 1)) != 0)) - -/* Force a compilation error if condition is true, but also produce a - result (of value 0 and type size_t), so the expression can be used - e.g. in a structure initializer (or where-ever else comma expressions - aren't permitted). */ -#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) -#define BUILD_BUG_ON_NULL(e) ((void *)sizeof(struct { int:-!!(e); })) - -/* - * BUILD_BUG_ON_INVALID() permits the compiler to check the validity of the - * expression but avoids the generation of any code, even if that expression - * has side-effects. - */ -#define BUILD_BUG_ON_INVALID(e) ((void)(sizeof((__force long)(e)))) - -/** - * BUILD_BUG_ON_MSG - break compile if a condition is true & emit supplied - * error message. - * @condition: the condition which the compiler should know is false. - * - * See BUILD_BUG_ON for description. - */ -#define BUILD_BUG_ON_MSG(cond, msg) compiletime_assert(!(cond), msg) - -/** - * BUILD_BUG_ON - break compile if a condition is true. - * @condition: the condition which the compiler should know is false. - * - * If you have some code which relies on certain constants being equal, or - * some other compile-time-evaluated condition, you should use BUILD_BUG_ON to - * detect if someone changes it. - * - * The implementation uses gcc's reluctance to create a negative array, but gcc - * (as of 4.4) only emits that error for obvious cases (e.g. not arguments to - * inline functions). Luckily, in 4.3 they added the "error" function - * attribute just for this type of case. Thus, we use a negative sized array - * (should always create an error on gcc versions older than 4.4) and then call - * an undefined function with the error attribute (should always create an - * error on gcc 4.3 and later). If for some reason, neither creates a - * compile-time error, we'll still have a link-time error, which is harder to - * track down. - */ -#ifndef __OPTIMIZE__ -#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) -#else -#define BUILD_BUG_ON(condition) \ - BUILD_BUG_ON_MSG(condition, "BUILD_BUG_ON failed: " #condition) -#endif - -/** - * BUILD_BUG - break compile if used. - * - * If you have some code that you expect the compiler to eliminate at - * build time, you should use BUILD_BUG to detect if it is - * unexpectedly used. - */ -#define BUILD_BUG() BUILD_BUG_ON_MSG(1, "BUILD_BUG failed") - -#define MAYBE_BUILD_BUG_ON(cond) \ - do { \ - if (__builtin_constant_p((cond))) \ - BUILD_BUG_ON(cond); \ - else \ - BUG_ON(cond); \ - } while (0) - -#endif /* __CHECKER__ */ - -#ifdef CONFIG_GENERIC_BUG -#include - -static inline int is_warning_bug(const struct bug_entry *bug) -{ - return bug->flags & BUGFLAG_WARNING; -} - -const struct bug_entry *find_bug(unsigned long bugaddr); - -enum bug_trap_type report_bug(unsigned long bug_addr, struct pt_regs *regs); - -/* These are defined by the architecture */ -int is_valid_bugaddr(unsigned long addr); - -#else /* !CONFIG_GENERIC_BUG */ - -static inline enum bug_trap_type report_bug(unsigned long bug_addr, - struct pt_regs *regs) -{ - return BUG_TRAP_TYPE_BUG; -} - -#endif /* CONFIG_GENERIC_BUG */ -#endif /* _LINUX_BUG_H */ diff --git a/src/linux/include/linux/bvec.h b/src/linux/include/linux/bvec.h deleted file mode 100644 index 89b65b8..0000000 --- a/src/linux/include/linux/bvec.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * bvec iterator - * - * Copyright (C) 2001 Ming Lei - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public Licens - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111- - */ -#ifndef __LINUX_BVEC_ITER_H -#define __LINUX_BVEC_ITER_H - -#include -#include - -/* - * was unsigned short, but we might as well be ready for > 64kB I/O pages - */ -struct bio_vec { - struct page *bv_page; - unsigned int bv_len; - unsigned int bv_offset; -}; - -struct bvec_iter { - sector_t bi_sector; /* device address in 512 byte - sectors */ - unsigned int bi_size; /* residual I/O count */ - - unsigned int bi_idx; /* current index into bvl_vec */ - - unsigned int bi_bvec_done; /* number of bytes completed in - current bvec */ -}; - -/* - * various member access, note that bio_data should of course not be used - * on highmem page vectors - */ -#define __bvec_iter_bvec(bvec, iter) (&(bvec)[(iter).bi_idx]) - -#define bvec_iter_page(bvec, iter) \ - (__bvec_iter_bvec((bvec), (iter))->bv_page) - -#define bvec_iter_len(bvec, iter) \ - min((iter).bi_size, \ - __bvec_iter_bvec((bvec), (iter))->bv_len - (iter).bi_bvec_done) - -#define bvec_iter_offset(bvec, iter) \ - (__bvec_iter_bvec((bvec), (iter))->bv_offset + (iter).bi_bvec_done) - -#define bvec_iter_bvec(bvec, iter) \ -((struct bio_vec) { \ - .bv_page = bvec_iter_page((bvec), (iter)), \ - .bv_len = bvec_iter_len((bvec), (iter)), \ - .bv_offset = bvec_iter_offset((bvec), (iter)), \ -}) - -static inline void bvec_iter_advance(const struct bio_vec *bv, - struct bvec_iter *iter, - unsigned bytes) -{ - WARN_ONCE(bytes > iter->bi_size, - "Attempted to advance past end of bvec iter\n"); - - while (bytes) { - unsigned iter_len = bvec_iter_len(bv, *iter); - unsigned len = min(bytes, iter_len); - - bytes -= len; - iter->bi_size -= len; - iter->bi_bvec_done += len; - - if (iter->bi_bvec_done == __bvec_iter_bvec(bv, *iter)->bv_len) { - iter->bi_bvec_done = 0; - iter->bi_idx++; - } - } -} - -#define for_each_bvec(bvl, bio_vec, iter, start) \ - for (iter = (start); \ - (iter).bi_size && \ - ((bvl = bvec_iter_bvec((bio_vec), (iter))), 1); \ - bvec_iter_advance((bio_vec), &(iter), (bvl).bv_len)) - -#endif /* __LINUX_BVEC_ITER_H */ diff --git a/src/linux/include/linux/byteorder/generic.h b/src/linux/include/linux/byteorder/generic.h deleted file mode 100644 index 89f67c1..0000000 --- a/src/linux/include/linux/byteorder/generic.h +++ /dev/null @@ -1,173 +0,0 @@ -#ifndef _LINUX_BYTEORDER_GENERIC_H -#define _LINUX_BYTEORDER_GENERIC_H - -/* - * linux/byteorder/generic.h - * Generic Byte-reordering support - * - * The "... p" macros, like le64_to_cpup, can be used with pointers - * to unaligned data, but there will be a performance penalty on - * some architectures. Use get_unaligned for unaligned data. - * - * Francois-Rene Rideau 19970707 - * gathered all the good ideas from all asm-foo/byteorder.h into one file, - * cleaned them up. - * I hope it is compliant with non-GCC compilers. - * I decided to put __BYTEORDER_HAS_U64__ in byteorder.h, - * because I wasn't sure it would be ok to put it in types.h - * Upgraded it to 2.1.43 - * Francois-Rene Rideau 19971012 - * Upgraded it to 2.1.57 - * to please Linus T., replaced huge #ifdef's between little/big endian - * by nestedly #include'd files. - * Francois-Rene Rideau 19971205 - * Made it to 2.1.71; now a facelift: - * Put files under include/linux/byteorder/ - * Split swab from generic support. - * - * TODO: - * = Regular kernel maintainers could also replace all these manual - * byteswap macros that remain, disseminated among drivers, - * after some grep or the sources... - * = Linus might want to rename all these macros and files to fit his taste, - * to fit his personal naming scheme. - * = it seems that a few drivers would also appreciate - * nybble swapping support... - * = every architecture could add their byteswap macro in asm/byteorder.h - * see how some architectures already do (i386, alpha, ppc, etc) - * = cpu_to_beXX and beXX_to_cpu might some day need to be well - * distinguished throughout the kernel. This is not the case currently, - * since little endian, big endian, and pdp endian machines needn't it. - * But this might be the case for, say, a port of Linux to 20/21 bit - * architectures (and F21 Linux addict around?). - */ - -/* - * The following macros are to be defined by : - * - * Conversion of long and short int between network and host format - * ntohl(__u32 x) - * ntohs(__u16 x) - * htonl(__u32 x) - * htons(__u16 x) - * It seems that some programs (which? where? or perhaps a standard? POSIX?) - * might like the above to be functions, not macros (why?). - * if that's true, then detect them, and take measures. - * Anyway, the measure is: define only ___ntohl as a macro instead, - * and in a separate file, have - * unsigned long inline ntohl(x){return ___ntohl(x);} - * - * The same for constant arguments - * __constant_ntohl(__u32 x) - * __constant_ntohs(__u16 x) - * __constant_htonl(__u32 x) - * __constant_htons(__u16 x) - * - * Conversion of XX-bit integers (16- 32- or 64-) - * between native CPU format and little/big endian format - * 64-bit stuff only defined for proper architectures - * cpu_to_[bl]eXX(__uXX x) - * [bl]eXX_to_cpu(__uXX x) - * - * The same, but takes a pointer to the value to convert - * cpu_to_[bl]eXXp(__uXX x) - * [bl]eXX_to_cpup(__uXX x) - * - * The same, but change in situ - * cpu_to_[bl]eXXs(__uXX x) - * [bl]eXX_to_cpus(__uXX x) - * - * See asm-foo/byteorder.h for examples of how to provide - * architecture-optimized versions - * - */ - -#define cpu_to_le64 __cpu_to_le64 -#define le64_to_cpu __le64_to_cpu -#define cpu_to_le32 __cpu_to_le32 -#define le32_to_cpu __le32_to_cpu -#define cpu_to_le16 __cpu_to_le16 -#define le16_to_cpu __le16_to_cpu -#define cpu_to_be64 __cpu_to_be64 -#define be64_to_cpu __be64_to_cpu -#define cpu_to_be32 __cpu_to_be32 -#define be32_to_cpu __be32_to_cpu -#define cpu_to_be16 __cpu_to_be16 -#define be16_to_cpu __be16_to_cpu -#define cpu_to_le64p __cpu_to_le64p -#define le64_to_cpup __le64_to_cpup -#define cpu_to_le32p __cpu_to_le32p -#define le32_to_cpup __le32_to_cpup -#define cpu_to_le16p __cpu_to_le16p -#define le16_to_cpup __le16_to_cpup -#define cpu_to_be64p __cpu_to_be64p -#define be64_to_cpup __be64_to_cpup -#define cpu_to_be32p __cpu_to_be32p -#define be32_to_cpup __be32_to_cpup -#define cpu_to_be16p __cpu_to_be16p -#define be16_to_cpup __be16_to_cpup -#define cpu_to_le64s __cpu_to_le64s -#define le64_to_cpus __le64_to_cpus -#define cpu_to_le32s __cpu_to_le32s -#define le32_to_cpus __le32_to_cpus -#define cpu_to_le16s __cpu_to_le16s -#define le16_to_cpus __le16_to_cpus -#define cpu_to_be64s __cpu_to_be64s -#define be64_to_cpus __be64_to_cpus -#define cpu_to_be32s __cpu_to_be32s -#define be32_to_cpus __be32_to_cpus -#define cpu_to_be16s __cpu_to_be16s -#define be16_to_cpus __be16_to_cpus - -/* - * They have to be macros in order to do the constant folding - * correctly - if the argument passed into a inline function - * it is no longer constant according to gcc.. - */ - -#undef ntohl -#undef ntohs -#undef htonl -#undef htons - -#define ___htonl(x) __cpu_to_be32(x) -#define ___htons(x) __cpu_to_be16(x) -#define ___ntohl(x) __be32_to_cpu(x) -#define ___ntohs(x) __be16_to_cpu(x) - -#define htonl(x) ___htonl(x) -#define ntohl(x) ___ntohl(x) -#define htons(x) ___htons(x) -#define ntohs(x) ___ntohs(x) - -static inline void le16_add_cpu(__le16 *var, u16 val) -{ - *var = cpu_to_le16(le16_to_cpu(*var) + val); -} - -static inline void le32_add_cpu(__le32 *var, u32 val) -{ - *var = cpu_to_le32(le32_to_cpu(*var) + val); -} - -static inline void le64_add_cpu(__le64 *var, u64 val) -{ - *var = cpu_to_le64(le64_to_cpu(*var) + val); -} - -static inline void be16_add_cpu(__be16 *var, u16 val) -{ - *var = cpu_to_be16(be16_to_cpu(*var) + val); -} - -static inline void be32_add_cpu(__be32 *var, u32 val) -{ - *var = cpu_to_be32(be32_to_cpu(*var) + val); -} - -static inline void be64_add_cpu(__be64 *var, u64 val) -{ - *var = cpu_to_be64(be64_to_cpu(*var) + val); -} - -#endif /* _LINUX_BYTEORDER_GENERIC_H */ diff --git a/src/linux/include/linux/byteorder/little_endian.h b/src/linux/include/linux/byteorder/little_endian.h deleted file mode 100644 index 0805737..0000000 --- a/src/linux/include/linux/byteorder/little_endian.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _LINUX_BYTEORDER_LITTLE_ENDIAN_H -#define _LINUX_BYTEORDER_LITTLE_ENDIAN_H - -#include - -#include -#endif /* _LINUX_BYTEORDER_LITTLE_ENDIAN_H */ diff --git a/src/linux/include/linux/cache.h b/src/linux/include/linux/cache.h deleted file mode 100644 index 1be04f8..0000000 --- a/src/linux/include/linux/cache.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef __LINUX_CACHE_H -#define __LINUX_CACHE_H - -#include -#include - -#ifndef L1_CACHE_ALIGN -#define L1_CACHE_ALIGN(x) __ALIGN_KERNEL(x, L1_CACHE_BYTES) -#endif - -#ifndef SMP_CACHE_BYTES -#define SMP_CACHE_BYTES L1_CACHE_BYTES -#endif - -/* - * __read_mostly is used to keep rarely changing variables out of frequently - * updated cachelines. If an architecture doesn't support it, ignore the - * hint. - */ -#ifndef __read_mostly -#define __read_mostly -#endif - -/* - * __ro_after_init is used to mark things that are read-only after init (i.e. - * after mark_rodata_ro() has been called). These are effectively read-only, - * but may get written to during init, so can't live in .rodata (via "const"). - */ -#ifndef __ro_after_init -#define __ro_after_init __attribute__((__section__(".data..ro_after_init"))) -#endif - -#ifndef ____cacheline_aligned -#define ____cacheline_aligned __attribute__((__aligned__(SMP_CACHE_BYTES))) -#endif - -#ifndef ____cacheline_aligned_in_smp -#ifdef CONFIG_SMP -#define ____cacheline_aligned_in_smp ____cacheline_aligned -#else -#define ____cacheline_aligned_in_smp -#endif /* CONFIG_SMP */ -#endif - -#ifndef __cacheline_aligned -#define __cacheline_aligned \ - __attribute__((__aligned__(SMP_CACHE_BYTES), \ - __section__(".data..cacheline_aligned"))) -#endif /* __cacheline_aligned */ - -#ifndef __cacheline_aligned_in_smp -#ifdef CONFIG_SMP -#define __cacheline_aligned_in_smp __cacheline_aligned -#else -#define __cacheline_aligned_in_smp -#endif /* CONFIG_SMP */ -#endif - -/* - * The maximum alignment needed for some critical structures - * These could be inter-node cacheline sizes/L3 cacheline - * size etc. Define this in asm/cache.h for your arch - */ -#ifndef INTERNODE_CACHE_SHIFT -#define INTERNODE_CACHE_SHIFT L1_CACHE_SHIFT -#endif - -#if !defined(____cacheline_internodealigned_in_smp) -#if defined(CONFIG_SMP) -#define ____cacheline_internodealigned_in_smp \ - __attribute__((__aligned__(1 << (INTERNODE_CACHE_SHIFT)))) -#else -#define ____cacheline_internodealigned_in_smp -#endif -#endif - -#ifndef CONFIG_ARCH_HAS_CACHE_LINE_SIZE -#define cache_line_size() L1_CACHE_BYTES -#endif - -#endif /* __LINUX_CACHE_H */ diff --git a/src/linux/include/linux/cacheinfo.h b/src/linux/include/linux/cacheinfo.h deleted file mode 100644 index 2189935..0000000 --- a/src/linux/include/linux/cacheinfo.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef _LINUX_CACHEINFO_H -#define _LINUX_CACHEINFO_H - -#include -#include -#include - -struct device_node; -struct attribute; - -enum cache_type { - CACHE_TYPE_NOCACHE = 0, - CACHE_TYPE_INST = BIT(0), - CACHE_TYPE_DATA = BIT(1), - CACHE_TYPE_SEPARATE = CACHE_TYPE_INST | CACHE_TYPE_DATA, - CACHE_TYPE_UNIFIED = BIT(2), -}; - -/** - * struct cacheinfo - represent a cache leaf node - * @type: type of the cache - data, inst or unified - * @level: represents the hierarchy in the multi-level cache - * @coherency_line_size: size of each cache line usually representing - * the minimum amount of data that gets transferred from memory - * @number_of_sets: total number of sets, a set is a collection of cache - * lines sharing the same index - * @ways_of_associativity: number of ways in which a particular memory - * block can be placed in the cache - * @physical_line_partition: number of physical cache lines sharing the - * same cachetag - * @size: Total size of the cache - * @shared_cpu_map: logical cpumask representing all the cpus sharing - * this cache node - * @attributes: bitfield representing various cache attributes - * @of_node: if devicetree is used, this represents either the cpu node in - * case there's no explicit cache node or the cache node itself in the - * device tree - * @disable_sysfs: indicates whether this node is visible to the user via - * sysfs or not - * @priv: pointer to any private data structure specific to particular - * cache design - * - * While @of_node, @disable_sysfs and @priv are used for internal book - * keeping, the remaining members form the core properties of the cache - */ -struct cacheinfo { - enum cache_type type; - unsigned int level; - unsigned int coherency_line_size; - unsigned int number_of_sets; - unsigned int ways_of_associativity; - unsigned int physical_line_partition; - unsigned int size; - cpumask_t shared_cpu_map; - unsigned int attributes; -#define CACHE_WRITE_THROUGH BIT(0) -#define CACHE_WRITE_BACK BIT(1) -#define CACHE_WRITE_POLICY_MASK \ - (CACHE_WRITE_THROUGH | CACHE_WRITE_BACK) -#define CACHE_READ_ALLOCATE BIT(2) -#define CACHE_WRITE_ALLOCATE BIT(3) -#define CACHE_ALLOCATE_POLICY_MASK \ - (CACHE_READ_ALLOCATE | CACHE_WRITE_ALLOCATE) - - struct device_node *of_node; - bool disable_sysfs; - void *priv; -}; - -struct cpu_cacheinfo { - struct cacheinfo *info_list; - unsigned int num_levels; - unsigned int num_leaves; -}; - -/* - * Helpers to make sure "func" is executed on the cpu whose cache - * attributes are being detected - */ -#define DEFINE_SMP_CALL_CACHE_FUNCTION(func) \ -static inline void _##func(void *ret) \ -{ \ - int cpu = smp_processor_id(); \ - *(int *)ret = __##func(cpu); \ -} \ - \ -int func(unsigned int cpu) \ -{ \ - int ret; \ - smp_call_function_single(cpu, _##func, &ret, true); \ - return ret; \ -} - -struct cpu_cacheinfo *get_cpu_cacheinfo(unsigned int cpu); -int init_cache_level(unsigned int cpu); -int populate_cache_leaves(unsigned int cpu); - -const struct attribute_group *cache_get_priv_group(struct cacheinfo *this_leaf); - -#endif /* _LINUX_CACHEINFO_H */ diff --git a/src/linux/include/linux/capability.h b/src/linux/include/linux/capability.h deleted file mode 100644 index dbc21c7..0000000 --- a/src/linux/include/linux/capability.h +++ /dev/null @@ -1,249 +0,0 @@ -/* - * This is - * - * Andrew G. Morgan - * Alexander Kjeldaas - * with help from Aleph1, Roland Buresund and Andrew Main. - * - * See here for the libcap library ("POSIX draft" compliance): - * - * ftp://www.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.6/ - */ -#ifndef _LINUX_CAPABILITY_H -#define _LINUX_CAPABILITY_H - -#include - - -#define _KERNEL_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_3 -#define _KERNEL_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_3 - -extern int file_caps_enabled; - -typedef struct kernel_cap_struct { - __u32 cap[_KERNEL_CAPABILITY_U32S]; -} kernel_cap_t; - -/* exact same as vfs_cap_data but in cpu endian and always filled completely */ -struct cpu_vfs_cap_data { - __u32 magic_etc; - kernel_cap_t permitted; - kernel_cap_t inheritable; -}; - -#define _USER_CAP_HEADER_SIZE (sizeof(struct __user_cap_header_struct)) -#define _KERNEL_CAP_T_SIZE (sizeof(kernel_cap_t)) - - -struct file; -struct inode; -struct dentry; -struct task_struct; -struct user_namespace; - -extern const kernel_cap_t __cap_empty_set; -extern const kernel_cap_t __cap_init_eff_set; - -/* - * Internal kernel functions only - */ - -#define CAP_FOR_EACH_U32(__capi) \ - for (__capi = 0; __capi < _KERNEL_CAPABILITY_U32S; ++__capi) - -/* - * CAP_FS_MASK and CAP_NFSD_MASKS: - * - * The fs mask is all the privileges that fsuid==0 historically meant. - * At one time in the past, that included CAP_MKNOD and CAP_LINUX_IMMUTABLE. - * - * It has never meant setting security.* and trusted.* xattrs. - * - * We could also define fsmask as follows: - * 1. CAP_FS_MASK is the privilege to bypass all fs-related DAC permissions - * 2. The security.* and trusted.* xattrs are fs-related MAC permissions - */ - -# define CAP_FS_MASK_B0 (CAP_TO_MASK(CAP_CHOWN) \ - | CAP_TO_MASK(CAP_MKNOD) \ - | CAP_TO_MASK(CAP_DAC_OVERRIDE) \ - | CAP_TO_MASK(CAP_DAC_READ_SEARCH) \ - | CAP_TO_MASK(CAP_FOWNER) \ - | CAP_TO_MASK(CAP_FSETID)) - -# define CAP_FS_MASK_B1 (CAP_TO_MASK(CAP_MAC_OVERRIDE)) - -#if _KERNEL_CAPABILITY_U32S != 2 -# error Fix up hand-coded capability macro initializers -#else /* HAND-CODED capability initializers */ - -#define CAP_LAST_U32 ((_KERNEL_CAPABILITY_U32S) - 1) -#define CAP_LAST_U32_VALID_MASK (CAP_TO_MASK(CAP_LAST_CAP + 1) -1) - -# define CAP_EMPTY_SET ((kernel_cap_t){{ 0, 0 }}) -# define CAP_FULL_SET ((kernel_cap_t){{ ~0, CAP_LAST_U32_VALID_MASK }}) -# define CAP_FS_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \ - | CAP_TO_MASK(CAP_LINUX_IMMUTABLE), \ - CAP_FS_MASK_B1 } }) -# define CAP_NFSD_SET ((kernel_cap_t){{ CAP_FS_MASK_B0 \ - | CAP_TO_MASK(CAP_SYS_RESOURCE), \ - CAP_FS_MASK_B1 } }) - -#endif /* _KERNEL_CAPABILITY_U32S != 2 */ - -# define cap_clear(c) do { (c) = __cap_empty_set; } while (0) - -#define cap_raise(c, flag) ((c).cap[CAP_TO_INDEX(flag)] |= CAP_TO_MASK(flag)) -#define cap_lower(c, flag) ((c).cap[CAP_TO_INDEX(flag)] &= ~CAP_TO_MASK(flag)) -#define cap_raised(c, flag) ((c).cap[CAP_TO_INDEX(flag)] & CAP_TO_MASK(flag)) - -#define CAP_BOP_ALL(c, a, b, OP) \ -do { \ - unsigned __capi; \ - CAP_FOR_EACH_U32(__capi) { \ - c.cap[__capi] = a.cap[__capi] OP b.cap[__capi]; \ - } \ -} while (0) - -#define CAP_UOP_ALL(c, a, OP) \ -do { \ - unsigned __capi; \ - CAP_FOR_EACH_U32(__capi) { \ - c.cap[__capi] = OP a.cap[__capi]; \ - } \ -} while (0) - -static inline kernel_cap_t cap_combine(const kernel_cap_t a, - const kernel_cap_t b) -{ - kernel_cap_t dest; - CAP_BOP_ALL(dest, a, b, |); - return dest; -} - -static inline kernel_cap_t cap_intersect(const kernel_cap_t a, - const kernel_cap_t b) -{ - kernel_cap_t dest; - CAP_BOP_ALL(dest, a, b, &); - return dest; -} - -static inline kernel_cap_t cap_drop(const kernel_cap_t a, - const kernel_cap_t drop) -{ - kernel_cap_t dest; - CAP_BOP_ALL(dest, a, drop, &~); - return dest; -} - -static inline kernel_cap_t cap_invert(const kernel_cap_t c) -{ - kernel_cap_t dest; - CAP_UOP_ALL(dest, c, ~); - return dest; -} - -static inline bool cap_isclear(const kernel_cap_t a) -{ - unsigned __capi; - CAP_FOR_EACH_U32(__capi) { - if (a.cap[__capi] != 0) - return false; - } - return true; -} - -/* - * Check if "a" is a subset of "set". - * return true if ALL of the capabilities in "a" are also in "set" - * cap_issubset(0101, 1111) will return true - * return false if ANY of the capabilities in "a" are not in "set" - * cap_issubset(1111, 0101) will return false - */ -static inline bool cap_issubset(const kernel_cap_t a, const kernel_cap_t set) -{ - kernel_cap_t dest; - dest = cap_drop(a, set); - return cap_isclear(dest); -} - -/* Used to decide between falling back on the old suser() or fsuser(). */ - -static inline kernel_cap_t cap_drop_fs_set(const kernel_cap_t a) -{ - const kernel_cap_t __cap_fs_set = CAP_FS_SET; - return cap_drop(a, __cap_fs_set); -} - -static inline kernel_cap_t cap_raise_fs_set(const kernel_cap_t a, - const kernel_cap_t permitted) -{ - const kernel_cap_t __cap_fs_set = CAP_FS_SET; - return cap_combine(a, - cap_intersect(permitted, __cap_fs_set)); -} - -static inline kernel_cap_t cap_drop_nfsd_set(const kernel_cap_t a) -{ - const kernel_cap_t __cap_fs_set = CAP_NFSD_SET; - return cap_drop(a, __cap_fs_set); -} - -static inline kernel_cap_t cap_raise_nfsd_set(const kernel_cap_t a, - const kernel_cap_t permitted) -{ - const kernel_cap_t __cap_nfsd_set = CAP_NFSD_SET; - return cap_combine(a, - cap_intersect(permitted, __cap_nfsd_set)); -} - -#ifdef CONFIG_MULTIUSER -extern bool has_capability(struct task_struct *t, int cap); -extern bool has_ns_capability(struct task_struct *t, - struct user_namespace *ns, int cap); -extern bool has_capability_noaudit(struct task_struct *t, int cap); -extern bool has_ns_capability_noaudit(struct task_struct *t, - struct user_namespace *ns, int cap); -extern bool capable(int cap); -extern bool ns_capable(struct user_namespace *ns, int cap); -extern bool ns_capable_noaudit(struct user_namespace *ns, int cap); -#else -static inline bool has_capability(struct task_struct *t, int cap) -{ - return true; -} -static inline bool has_ns_capability(struct task_struct *t, - struct user_namespace *ns, int cap) -{ - return true; -} -static inline bool has_capability_noaudit(struct task_struct *t, int cap) -{ - return true; -} -static inline bool has_ns_capability_noaudit(struct task_struct *t, - struct user_namespace *ns, int cap) -{ - return true; -} -static inline bool capable(int cap) -{ - return true; -} -static inline bool ns_capable(struct user_namespace *ns, int cap) -{ - return true; -} -static inline bool ns_capable_noaudit(struct user_namespace *ns, int cap) -{ - return true; -} -#endif /* CONFIG_MULTIUSER */ -extern bool capable_wrt_inode_uidgid(const struct inode *inode, int cap); -extern bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap); - -/* audit system wants to get cap info from files as well */ -extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps); - -#endif /* !_LINUX_CAPABILITY_H */ diff --git a/src/linux/include/linux/cdev.h b/src/linux/include/linux/cdev.h deleted file mode 100644 index f876361..0000000 --- a/src/linux/include/linux/cdev.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef _LINUX_CDEV_H -#define _LINUX_CDEV_H - -#include -#include -#include - -struct file_operations; -struct inode; -struct module; - -struct cdev { - struct kobject kobj; - struct module *owner; - const struct file_operations *ops; - struct list_head list; - dev_t dev; - unsigned int count; -}; - -void cdev_init(struct cdev *, const struct file_operations *); - -struct cdev *cdev_alloc(void); - -void cdev_put(struct cdev *p); - -int cdev_add(struct cdev *, dev_t, unsigned); - -void cdev_del(struct cdev *); - -void cd_forget(struct inode *); - -#endif diff --git a/src/linux/include/linux/cdrom.h b/src/linux/include/linux/cdrom.h deleted file mode 100644 index 8609d57..0000000 --- a/src/linux/include/linux/cdrom.h +++ /dev/null @@ -1,314 +0,0 @@ -/* - * -- - * General header file for linux CD-ROM drivers - * Copyright (C) 1992 David Giller, rafetmad@oxy.edu - * 1994, 1995 Eberhard Mönkeberg, emoenke@gwdg.de - * 1996 David van Leeuwen, david@tm.tno.nl - * 1997, 1998 Erik Andersen, andersee@debian.org - * 1998-2002 Jens Axboe, axboe@suse.de - */ -#ifndef _LINUX_CDROM_H -#define _LINUX_CDROM_H - -#include /* not really needed, later.. */ -#include -#include - -struct packet_command -{ - unsigned char cmd[CDROM_PACKET_SIZE]; - unsigned char *buffer; - unsigned int buflen; - int stat; - struct request_sense *sense; - unsigned char data_direction; - int quiet; - int timeout; - void *reserved[1]; -}; - -/* - * _OLD will use PIO transfer on atapi devices, _BPC_* will use DMA - */ -#define CDDA_OLD 0 /* old style */ -#define CDDA_BPC_SINGLE 1 /* single frame block pc */ -#define CDDA_BPC_FULL 2 /* multi frame block pc */ - -/* Uniform cdrom data structures for cdrom.c */ -struct cdrom_device_info { - struct cdrom_device_ops *ops; /* link to device_ops */ - struct list_head list; /* linked list of all device_info */ - struct gendisk *disk; /* matching block layer disk */ - void *handle; /* driver-dependent data */ -/* specifications */ - int mask; /* mask of capability: disables them */ - int speed; /* maximum speed for reading data */ - int capacity; /* number of discs in jukebox */ -/* device-related storage */ - unsigned int options : 30; /* options flags */ - unsigned mc_flags : 2; /* media change buffer flags */ - unsigned int vfs_events; /* cached events for vfs path */ - unsigned int ioctl_events; /* cached events for ioctl path */ - int use_count; /* number of times device opened */ - char name[20]; /* name of the device type */ -/* per-device flags */ - __u8 sanyo_slot : 2; /* Sanyo 3 CD changer support */ - __u8 keeplocked : 1; /* CDROM_LOCKDOOR status */ - __u8 reserved : 5; /* not used yet */ - int cdda_method; /* see flags */ - __u8 last_sense; - __u8 media_written; /* dirty flag, DVD+RW bookkeeping */ - unsigned short mmc3_profile; /* current MMC3 profile */ - int for_data; - int (*exit)(struct cdrom_device_info *); - int mrw_mode_page; -}; - -struct cdrom_device_ops { -/* routines */ - int (*open) (struct cdrom_device_info *, int); - void (*release) (struct cdrom_device_info *); - int (*drive_status) (struct cdrom_device_info *, int); - unsigned int (*check_events) (struct cdrom_device_info *cdi, - unsigned int clearing, int slot); - int (*media_changed) (struct cdrom_device_info *, int); - int (*tray_move) (struct cdrom_device_info *, int); - int (*lock_door) (struct cdrom_device_info *, int); - int (*select_speed) (struct cdrom_device_info *, int); - int (*select_disc) (struct cdrom_device_info *, int); - int (*get_last_session) (struct cdrom_device_info *, - struct cdrom_multisession *); - int (*get_mcn) (struct cdrom_device_info *, - struct cdrom_mcn *); - /* hard reset device */ - int (*reset) (struct cdrom_device_info *); - /* play stuff */ - int (*audio_ioctl) (struct cdrom_device_info *,unsigned int, void *); - -/* driver specifications */ - const int capability; /* capability flags */ - int n_minors; /* number of active minor devices */ - /* handle uniform packets for scsi type devices (scsi,atapi) */ - int (*generic_packet) (struct cdrom_device_info *, - struct packet_command *); -}; - -/* the general block_device operations structure: */ -extern int cdrom_open(struct cdrom_device_info *cdi, struct block_device *bdev, - fmode_t mode); -extern void cdrom_release(struct cdrom_device_info *cdi, fmode_t mode); -extern int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev, - fmode_t mode, unsigned int cmd, unsigned long arg); -extern unsigned int cdrom_check_events(struct cdrom_device_info *cdi, - unsigned int clearing); -extern int cdrom_media_changed(struct cdrom_device_info *); - -extern int register_cdrom(struct cdrom_device_info *cdi); -extern void unregister_cdrom(struct cdrom_device_info *cdi); - -typedef struct { - int data; - int audio; - int cdi; - int xa; - long error; -} tracktype; - -extern int cdrom_get_last_written(struct cdrom_device_info *cdi, long *last_written); -extern int cdrom_number_of_slots(struct cdrom_device_info *cdi); -extern int cdrom_mode_select(struct cdrom_device_info *cdi, - struct packet_command *cgc); -extern int cdrom_mode_sense(struct cdrom_device_info *cdi, - struct packet_command *cgc, - int page_code, int page_control); -extern void init_cdrom_command(struct packet_command *cgc, - void *buffer, int len, int type); - -/* The SCSI spec says there could be 256 slots. */ -#define CDROM_MAX_SLOTS 256 - -struct cdrom_mechstat_header { -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 fault : 1; - __u8 changer_state : 2; - __u8 curslot : 5; - __u8 mech_state : 3; - __u8 door_open : 1; - __u8 reserved1 : 4; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 curslot : 5; - __u8 changer_state : 2; - __u8 fault : 1; - __u8 reserved1 : 4; - __u8 door_open : 1; - __u8 mech_state : 3; -#endif - __u8 curlba[3]; - __u8 nslots; - __u16 slot_tablelen; -}; - -struct cdrom_slot { -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 disc_present : 1; - __u8 reserved1 : 6; - __u8 change : 1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 change : 1; - __u8 reserved1 : 6; - __u8 disc_present : 1; -#endif - __u8 reserved2[3]; -}; - -struct cdrom_changer_info { - struct cdrom_mechstat_header hdr; - struct cdrom_slot slots[CDROM_MAX_SLOTS]; -}; - -typedef enum { - mechtype_caddy = 0, - mechtype_tray = 1, - mechtype_popup = 2, - mechtype_individual_changer = 4, - mechtype_cartridge_changer = 5 -} mechtype_t; - -typedef struct { -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 ps : 1; - __u8 reserved1 : 1; - __u8 page_code : 6; - __u8 page_length; - __u8 reserved2 : 1; - __u8 bufe : 1; - __u8 ls_v : 1; - __u8 test_write : 1; - __u8 write_type : 4; - __u8 multi_session : 2; /* or border, DVD */ - __u8 fp : 1; - __u8 copy : 1; - __u8 track_mode : 4; - __u8 reserved3 : 4; - __u8 data_block_type : 4; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 page_code : 6; - __u8 reserved1 : 1; - __u8 ps : 1; - __u8 page_length; - __u8 write_type : 4; - __u8 test_write : 1; - __u8 ls_v : 1; - __u8 bufe : 1; - __u8 reserved2 : 1; - __u8 track_mode : 4; - __u8 copy : 1; - __u8 fp : 1; - __u8 multi_session : 2; /* or border, DVD */ - __u8 data_block_type : 4; - __u8 reserved3 : 4; -#endif - __u8 link_size; - __u8 reserved4; -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 reserved5 : 2; - __u8 app_code : 6; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 app_code : 6; - __u8 reserved5 : 2; -#endif - __u8 session_format; - __u8 reserved6; - __be32 packet_size; - __u16 audio_pause; - __u8 mcn[16]; - __u8 isrc[16]; - __u8 subhdr0; - __u8 subhdr1; - __u8 subhdr2; - __u8 subhdr3; -} __attribute__((packed)) write_param_page; - -struct modesel_head -{ - __u8 reserved1; - __u8 medium; - __u8 reserved2; - __u8 block_desc_length; - __u8 density; - __u8 number_of_blocks_hi; - __u8 number_of_blocks_med; - __u8 number_of_blocks_lo; - __u8 reserved3; - __u8 block_length_hi; - __u8 block_length_med; - __u8 block_length_lo; -}; - -typedef struct { - __u16 report_key_length; - __u8 reserved1; - __u8 reserved2; -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 type_code : 2; - __u8 vra : 3; - __u8 ucca : 3; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 ucca : 3; - __u8 vra : 3; - __u8 type_code : 2; -#endif - __u8 region_mask; - __u8 rpc_scheme; - __u8 reserved3; -} rpc_state_t; - -struct event_header { - __be16 data_len; -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 nea : 1; - __u8 reserved1 : 4; - __u8 notification_class : 3; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 notification_class : 3; - __u8 reserved1 : 4; - __u8 nea : 1; -#endif - __u8 supp_event_class; -}; - -struct media_event_desc { -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 reserved1 : 4; - __u8 media_event_code : 4; - __u8 reserved2 : 6; - __u8 media_present : 1; - __u8 door_open : 1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 media_event_code : 4; - __u8 reserved1 : 4; - __u8 door_open : 1; - __u8 media_present : 1; - __u8 reserved2 : 6; -#endif - __u8 start_slot; - __u8 end_slot; -}; - -extern int cdrom_get_media_event(struct cdrom_device_info *cdi, struct media_event_desc *med); - -static inline void lba_to_msf(int lba, u8 *m, u8 *s, u8 *f) -{ - lba += CD_MSF_OFFSET; - lba &= 0xffffff; /* negative lbas use only 24 bits */ - *m = lba / (CD_SECS * CD_FRAMES); - lba %= (CD_SECS * CD_FRAMES); - *s = lba / CD_FRAMES; - *f = lba % CD_FRAMES; -} - -static inline int msf_to_lba(u8 m, u8 s, u8 f) -{ - return (((m * CD_SECS) + s) * CD_FRAMES + f) - CD_MSF_OFFSET; -} -#endif /* _LINUX_CDROM_H */ diff --git a/src/linux/include/linux/cgroup-defs.h b/src/linux/include/linux/cgroup-defs.h deleted file mode 100644 index 5b17de6..0000000 --- a/src/linux/include/linux/cgroup-defs.h +++ /dev/null @@ -1,668 +0,0 @@ -/* - * linux/cgroup-defs.h - basic definitions for cgroup - * - * This file provides basic type and interface. Include this file directly - * only if necessary to avoid cyclic dependencies. - */ -#ifndef _LINUX_CGROUP_DEFS_H -#define _LINUX_CGROUP_DEFS_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_CGROUPS - -struct cgroup; -struct cgroup_root; -struct cgroup_subsys; -struct cgroup_taskset; -struct kernfs_node; -struct kernfs_ops; -struct kernfs_open_file; -struct seq_file; - -#define MAX_CGROUP_TYPE_NAMELEN 32 -#define MAX_CGROUP_ROOT_NAMELEN 64 -#define MAX_CFTYPE_NAME 64 - -/* define the enumeration of all cgroup subsystems */ -#define SUBSYS(_x) _x ## _cgrp_id, -enum cgroup_subsys_id { -#include - CGROUP_SUBSYS_COUNT, -}; -#undef SUBSYS - -/* bits in struct cgroup_subsys_state flags field */ -enum { - CSS_NO_REF = (1 << 0), /* no reference counting for this css */ - CSS_ONLINE = (1 << 1), /* between ->css_online() and ->css_offline() */ - CSS_RELEASED = (1 << 2), /* refcnt reached zero, released */ - CSS_VISIBLE = (1 << 3), /* css is visible to userland */ -}; - -/* bits in struct cgroup flags field */ -enum { - /* Control Group requires release notifications to userspace */ - CGRP_NOTIFY_ON_RELEASE, - /* - * Clone the parent's configuration when creating a new child - * cpuset cgroup. For historical reasons, this option can be - * specified at mount time and thus is implemented here. - */ - CGRP_CPUSET_CLONE_CHILDREN, -}; - -/* cgroup_root->flags */ -enum { - CGRP_ROOT_NOPREFIX = (1 << 1), /* mounted subsystems have no named prefix */ - CGRP_ROOT_XATTR = (1 << 2), /* supports extended attributes */ -}; - -/* cftype->flags */ -enum { - CFTYPE_ONLY_ON_ROOT = (1 << 0), /* only create on root cgrp */ - CFTYPE_NOT_ON_ROOT = (1 << 1), /* don't create on root cgrp */ - CFTYPE_NO_PREFIX = (1 << 3), /* (DON'T USE FOR NEW FILES) no subsys prefix */ - CFTYPE_WORLD_WRITABLE = (1 << 4), /* (DON'T USE FOR NEW FILES) S_IWUGO */ - - /* internal flags, do not use outside cgroup core proper */ - __CFTYPE_ONLY_ON_DFL = (1 << 16), /* only on default hierarchy */ - __CFTYPE_NOT_ON_DFL = (1 << 17), /* not on default hierarchy */ -}; - -/* - * cgroup_file is the handle for a file instance created in a cgroup which - * is used, for example, to generate file changed notifications. This can - * be obtained by setting cftype->file_offset. - */ -struct cgroup_file { - /* do not access any fields from outside cgroup core */ - struct kernfs_node *kn; -}; - -/* - * Per-subsystem/per-cgroup state maintained by the system. This is the - * fundamental structural building block that controllers deal with. - * - * Fields marked with "PI:" are public and immutable and may be accessed - * directly without synchronization. - */ -struct cgroup_subsys_state { - /* PI: the cgroup that this css is attached to */ - struct cgroup *cgroup; - - /* PI: the cgroup subsystem that this css is attached to */ - struct cgroup_subsys *ss; - - /* reference count - access via css_[try]get() and css_put() */ - struct percpu_ref refcnt; - - /* PI: the parent css */ - struct cgroup_subsys_state *parent; - - /* siblings list anchored at the parent's ->children */ - struct list_head sibling; - struct list_head children; - - /* - * PI: Subsys-unique ID. 0 is unused and root is always 1. The - * matching css can be looked up using css_from_id(). - */ - int id; - - unsigned int flags; - - /* - * Monotonically increasing unique serial number which defines a - * uniform order among all csses. It's guaranteed that all - * ->children lists are in the ascending order of ->serial_nr and - * used to allow interrupting and resuming iterations. - */ - u64 serial_nr; - - /* - * Incremented by online self and children. Used to guarantee that - * parents are not offlined before their children. - */ - atomic_t online_cnt; - - /* percpu_ref killing and RCU release */ - struct rcu_head rcu_head; - struct work_struct destroy_work; -}; - -/* - * A css_set is a structure holding pointers to a set of - * cgroup_subsys_state objects. This saves space in the task struct - * object and speeds up fork()/exit(), since a single inc/dec and a - * list_add()/del() can bump the reference count on the entire cgroup - * set for a task. - */ -struct css_set { - /* Reference count */ - atomic_t refcount; - - /* - * List running through all cgroup groups in the same hash - * slot. Protected by css_set_lock - */ - struct hlist_node hlist; - - /* - * Lists running through all tasks using this cgroup group. - * mg_tasks lists tasks which belong to this cset but are in the - * process of being migrated out or in. Protected by - * css_set_rwsem, but, during migration, once tasks are moved to - * mg_tasks, it can be read safely while holding cgroup_mutex. - */ - struct list_head tasks; - struct list_head mg_tasks; - - /* - * List of cgrp_cset_links pointing at cgroups referenced from this - * css_set. Protected by css_set_lock. - */ - struct list_head cgrp_links; - - /* the default cgroup associated with this css_set */ - struct cgroup *dfl_cgrp; - - /* - * Set of subsystem states, one for each subsystem. This array is - * immutable after creation apart from the init_css_set during - * subsystem registration (at boot time). - */ - struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT]; - - /* - * List of csets participating in the on-going migration either as - * source or destination. Protected by cgroup_mutex. - */ - struct list_head mg_preload_node; - struct list_head mg_node; - - /* - * If this cset is acting as the source of migration the following - * two fields are set. mg_src_cgrp and mg_dst_cgrp are - * respectively the source and destination cgroups of the on-going - * migration. mg_dst_cset is the destination cset the target tasks - * on this cset should be migrated to. Protected by cgroup_mutex. - */ - struct cgroup *mg_src_cgrp; - struct cgroup *mg_dst_cgrp; - struct css_set *mg_dst_cset; - - /* - * On the default hierarhcy, ->subsys[ssid] may point to a css - * attached to an ancestor instead of the cgroup this css_set is - * associated with. The following node is anchored at - * ->subsys[ssid]->cgroup->e_csets[ssid] and provides a way to - * iterate through all css's attached to a given cgroup. - */ - struct list_head e_cset_node[CGROUP_SUBSYS_COUNT]; - - /* all css_task_iters currently walking this cset */ - struct list_head task_iters; - - /* dead and being drained, ignore for migration */ - bool dead; - - /* For RCU-protected deletion */ - struct rcu_head rcu_head; -}; - -struct cgroup { - /* self css with NULL ->ss, points back to this cgroup */ - struct cgroup_subsys_state self; - - unsigned long flags; /* "unsigned long" so bitops work */ - - /* - * idr allocated in-hierarchy ID. - * - * ID 0 is not used, the ID of the root cgroup is always 1, and a - * new cgroup will be assigned with a smallest available ID. - * - * Allocating/Removing ID must be protected by cgroup_mutex. - */ - int id; - - /* - * The depth this cgroup is at. The root is at depth zero and each - * step down the hierarchy increments the level. This along with - * ancestor_ids[] can determine whether a given cgroup is a - * descendant of another without traversing the hierarchy. - */ - int level; - - /* - * Each non-empty css_set associated with this cgroup contributes - * one to populated_cnt. All children with non-zero popuplated_cnt - * of their own contribute one. The count is zero iff there's no - * task in this cgroup or its subtree. - */ - int populated_cnt; - - struct kernfs_node *kn; /* cgroup kernfs entry */ - struct cgroup_file procs_file; /* handle for "cgroup.procs" */ - struct cgroup_file events_file; /* handle for "cgroup.events" */ - - /* - * The bitmask of subsystems enabled on the child cgroups. - * ->subtree_control is the one configured through - * "cgroup.subtree_control" while ->child_ss_mask is the effective - * one which may have more subsystems enabled. Controller knobs - * are made available iff it's enabled in ->subtree_control. - */ - u16 subtree_control; - u16 subtree_ss_mask; - u16 old_subtree_control; - u16 old_subtree_ss_mask; - - /* Private pointers for each registered subsystem */ - struct cgroup_subsys_state __rcu *subsys[CGROUP_SUBSYS_COUNT]; - - struct cgroup_root *root; - - /* - * List of cgrp_cset_links pointing at css_sets with tasks in this - * cgroup. Protected by css_set_lock. - */ - struct list_head cset_links; - - /* - * On the default hierarchy, a css_set for a cgroup with some - * susbsys disabled will point to css's which are associated with - * the closest ancestor which has the subsys enabled. The - * following lists all css_sets which point to this cgroup's css - * for the given subsystem. - */ - struct list_head e_csets[CGROUP_SUBSYS_COUNT]; - - /* - * list of pidlists, up to two for each namespace (one for procs, one - * for tasks); created on demand. - */ - struct list_head pidlists; - struct mutex pidlist_mutex; - - /* used to wait for offlining of csses */ - wait_queue_head_t offline_waitq; - - /* used to schedule release agent */ - struct work_struct release_agent_work; - - /* ids of the ancestors at each level including self */ - int ancestor_ids[]; -}; - -/* - * A cgroup_root represents the root of a cgroup hierarchy, and may be - * associated with a kernfs_root to form an active hierarchy. This is - * internal to cgroup core. Don't access directly from controllers. - */ -struct cgroup_root { - struct kernfs_root *kf_root; - - /* The bitmask of subsystems attached to this hierarchy */ - unsigned int subsys_mask; - - /* Unique id for this hierarchy. */ - int hierarchy_id; - - /* The root cgroup. Root is destroyed on its release. */ - struct cgroup cgrp; - - /* for cgrp->ancestor_ids[0] */ - int cgrp_ancestor_id_storage; - - /* Number of cgroups in the hierarchy, used only for /proc/cgroups */ - atomic_t nr_cgrps; - - /* A list running through the active hierarchies */ - struct list_head root_list; - - /* Hierarchy-specific flags */ - unsigned int flags; - - /* IDs for cgroups in this hierarchy */ - struct idr cgroup_idr; - - /* The path to use for release notifications. */ - char release_agent_path[PATH_MAX]; - - /* The name for this hierarchy - may be empty */ - char name[MAX_CGROUP_ROOT_NAMELEN]; -}; - -/* - * struct cftype: handler definitions for cgroup control files - * - * When reading/writing to a file: - * - the cgroup to use is file->f_path.dentry->d_parent->d_fsdata - * - the 'cftype' of the file is file->f_path.dentry->d_fsdata - */ -struct cftype { - /* - * By convention, the name should begin with the name of the - * subsystem, followed by a period. Zero length string indicates - * end of cftype array. - */ - char name[MAX_CFTYPE_NAME]; - unsigned long private; - - /* - * The maximum length of string, excluding trailing nul, that can - * be passed to write. If < PAGE_SIZE-1, PAGE_SIZE-1 is assumed. - */ - size_t max_write_len; - - /* CFTYPE_* flags */ - unsigned int flags; - - /* - * If non-zero, should contain the offset from the start of css to - * a struct cgroup_file field. cgroup will record the handle of - * the created file into it. The recorded handle can be used as - * long as the containing css remains accessible. - */ - unsigned int file_offset; - - /* - * Fields used for internal bookkeeping. Initialized automatically - * during registration. - */ - struct cgroup_subsys *ss; /* NULL for cgroup core files */ - struct list_head node; /* anchored at ss->cfts */ - struct kernfs_ops *kf_ops; - - /* - * read_u64() is a shortcut for the common case of returning a - * single integer. Use it in place of read() - */ - u64 (*read_u64)(struct cgroup_subsys_state *css, struct cftype *cft); - /* - * read_s64() is a signed version of read_u64() - */ - s64 (*read_s64)(struct cgroup_subsys_state *css, struct cftype *cft); - - /* generic seq_file read interface */ - int (*seq_show)(struct seq_file *sf, void *v); - - /* optional ops, implement all or none */ - void *(*seq_start)(struct seq_file *sf, loff_t *ppos); - void *(*seq_next)(struct seq_file *sf, void *v, loff_t *ppos); - void (*seq_stop)(struct seq_file *sf, void *v); - - /* - * write_u64() is a shortcut for the common case of accepting - * a single integer (as parsed by simple_strtoull) from - * userspace. Use in place of write(); return 0 or error. - */ - int (*write_u64)(struct cgroup_subsys_state *css, struct cftype *cft, - u64 val); - /* - * write_s64() is a signed version of write_u64() - */ - int (*write_s64)(struct cgroup_subsys_state *css, struct cftype *cft, - s64 val); - - /* - * write() is the generic write callback which maps directly to - * kernfs write operation and overrides all other operations. - * Maximum write size is determined by ->max_write_len. Use - * of_css/cft() to access the associated css and cft. - */ - ssize_t (*write)(struct kernfs_open_file *of, - char *buf, size_t nbytes, loff_t off); - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lock_class_key lockdep_key; -#endif -}; - -/* - * Control Group subsystem type. - * See Documentation/cgroups/cgroups.txt for details - */ -struct cgroup_subsys { - struct cgroup_subsys_state *(*css_alloc)(struct cgroup_subsys_state *parent_css); - int (*css_online)(struct cgroup_subsys_state *css); - void (*css_offline)(struct cgroup_subsys_state *css); - void (*css_released)(struct cgroup_subsys_state *css); - void (*css_free)(struct cgroup_subsys_state *css); - void (*css_reset)(struct cgroup_subsys_state *css); - - int (*can_attach)(struct cgroup_taskset *tset); - void (*cancel_attach)(struct cgroup_taskset *tset); - void (*attach)(struct cgroup_taskset *tset); - void (*post_attach)(void); - int (*can_fork)(struct task_struct *task); - void (*cancel_fork)(struct task_struct *task); - void (*fork)(struct task_struct *task); - void (*exit)(struct task_struct *task); - void (*free)(struct task_struct *task); - void (*bind)(struct cgroup_subsys_state *root_css); - - bool early_init:1; - - /* - * If %true, the controller, on the default hierarchy, doesn't show - * up in "cgroup.controllers" or "cgroup.subtree_control", is - * implicitly enabled on all cgroups on the default hierarchy, and - * bypasses the "no internal process" constraint. This is for - * utility type controllers which is transparent to userland. - * - * An implicit controller can be stolen from the default hierarchy - * anytime and thus must be okay with offline csses from previous - * hierarchies coexisting with csses for the current one. - */ - bool implicit_on_dfl:1; - - /* - * If %false, this subsystem is properly hierarchical - - * configuration, resource accounting and restriction on a parent - * cgroup cover those of its children. If %true, hierarchy support - * is broken in some ways - some subsystems ignore hierarchy - * completely while others are only implemented half-way. - * - * It's now disallowed to create nested cgroups if the subsystem is - * broken and cgroup core will emit a warning message on such - * cases. Eventually, all subsystems will be made properly - * hierarchical and this will go away. - */ - bool broken_hierarchy:1; - bool warned_broken_hierarchy:1; - - /* the following two fields are initialized automtically during boot */ - int id; - const char *name; - - /* optional, initialized automatically during boot if not set */ - const char *legacy_name; - - /* link to parent, protected by cgroup_lock() */ - struct cgroup_root *root; - - /* idr for css->id */ - struct idr css_idr; - - /* - * List of cftypes. Each entry is the first entry of an array - * terminated by zero length name. - */ - struct list_head cfts; - - /* - * Base cftypes which are automatically registered. The two can - * point to the same array. - */ - struct cftype *dfl_cftypes; /* for the default hierarchy */ - struct cftype *legacy_cftypes; /* for the legacy hierarchies */ - - /* - * A subsystem may depend on other subsystems. When such subsystem - * is enabled on a cgroup, the depended-upon subsystems are enabled - * together if available. Subsystems enabled due to dependency are - * not visible to userland until explicitly enabled. The following - * specifies the mask of subsystems that this one depends on. - */ - unsigned int depends_on; -}; - -extern struct percpu_rw_semaphore cgroup_threadgroup_rwsem; - -/** - * cgroup_threadgroup_change_begin - threadgroup exclusion for cgroups - * @tsk: target task - * - * Called from threadgroup_change_begin() and allows cgroup operations to - * synchronize against threadgroup changes using a percpu_rw_semaphore. - */ -static inline void cgroup_threadgroup_change_begin(struct task_struct *tsk) -{ - percpu_down_read(&cgroup_threadgroup_rwsem); -} - -/** - * cgroup_threadgroup_change_end - threadgroup exclusion for cgroups - * @tsk: target task - * - * Called from threadgroup_change_end(). Counterpart of - * cgroup_threadcgroup_change_begin(). - */ -static inline void cgroup_threadgroup_change_end(struct task_struct *tsk) -{ - percpu_up_read(&cgroup_threadgroup_rwsem); -} - -#else /* CONFIG_CGROUPS */ - -#define CGROUP_SUBSYS_COUNT 0 - -static inline void cgroup_threadgroup_change_begin(struct task_struct *tsk) {} -static inline void cgroup_threadgroup_change_end(struct task_struct *tsk) {} - -#endif /* CONFIG_CGROUPS */ - -#ifdef CONFIG_SOCK_CGROUP_DATA - -/* - * sock_cgroup_data is embedded at sock->sk_cgrp_data and contains - * per-socket cgroup information except for memcg association. - * - * On legacy hierarchies, net_prio and net_cls controllers directly set - * attributes on each sock which can then be tested by the network layer. - * On the default hierarchy, each sock is associated with the cgroup it was - * created in and the networking layer can match the cgroup directly. - * - * To avoid carrying all three cgroup related fields separately in sock, - * sock_cgroup_data overloads (prioidx, classid) and the cgroup pointer. - * On boot, sock_cgroup_data records the cgroup that the sock was created - * in so that cgroup2 matches can be made; however, once either net_prio or - * net_cls starts being used, the area is overriden to carry prioidx and/or - * classid. The two modes are distinguished by whether the lowest bit is - * set. Clear bit indicates cgroup pointer while set bit prioidx and - * classid. - * - * While userland may start using net_prio or net_cls at any time, once - * either is used, cgroup2 matching no longer works. There is no reason to - * mix the two and this is in line with how legacy and v2 compatibility is - * handled. On mode switch, cgroup references which are already being - * pointed to by socks may be leaked. While this can be remedied by adding - * synchronization around sock_cgroup_data, given that the number of leaked - * cgroups is bound and highly unlikely to be high, this seems to be the - * better trade-off. - */ -struct sock_cgroup_data { - union { -#ifdef __LITTLE_ENDIAN - struct { - u8 is_data; - u8 padding; - u16 prioidx; - u32 classid; - } __packed; -#else - struct { - u32 classid; - u16 prioidx; - u8 padding; - u8 is_data; - } __packed; -#endif - u64 val; - }; -}; - -/* - * There's a theoretical window where the following accessors race with - * updaters and return part of the previous pointer as the prioidx or - * classid. Such races are short-lived and the result isn't critical. - */ -static inline u16 sock_cgroup_prioidx(struct sock_cgroup_data *skcd) -{ - /* fallback to 1 which is always the ID of the root cgroup */ - return (skcd->is_data & 1) ? skcd->prioidx : 1; -} - -static inline u32 sock_cgroup_classid(struct sock_cgroup_data *skcd) -{ - /* fallback to 0 which is the unconfigured default classid */ - return (skcd->is_data & 1) ? skcd->classid : 0; -} - -/* - * If invoked concurrently, the updaters may clobber each other. The - * caller is responsible for synchronization. - */ -static inline void sock_cgroup_set_prioidx(struct sock_cgroup_data *skcd, - u16 prioidx) -{ - struct sock_cgroup_data skcd_buf = {{ .val = READ_ONCE(skcd->val) }}; - - if (sock_cgroup_prioidx(&skcd_buf) == prioidx) - return; - - if (!(skcd_buf.is_data & 1)) { - skcd_buf.val = 0; - skcd_buf.is_data = 1; - } - - skcd_buf.prioidx = prioidx; - WRITE_ONCE(skcd->val, skcd_buf.val); /* see sock_cgroup_ptr() */ -} - -static inline void sock_cgroup_set_classid(struct sock_cgroup_data *skcd, - u32 classid) -{ - struct sock_cgroup_data skcd_buf = {{ .val = READ_ONCE(skcd->val) }}; - - if (sock_cgroup_classid(&skcd_buf) == classid) - return; - - if (!(skcd_buf.is_data & 1)) { - skcd_buf.val = 0; - skcd_buf.is_data = 1; - } - - skcd_buf.classid = classid; - WRITE_ONCE(skcd->val, skcd_buf.val); /* see sock_cgroup_ptr() */ -} - -#else /* CONFIG_SOCK_CGROUP_DATA */ - -struct sock_cgroup_data { -}; - -#endif /* CONFIG_SOCK_CGROUP_DATA */ - -#endif /* _LINUX_CGROUP_DEFS_H */ diff --git a/src/linux/include/linux/cgroup.h b/src/linux/include/linux/cgroup.h deleted file mode 100644 index c83c23f..0000000 --- a/src/linux/include/linux/cgroup.h +++ /dev/null @@ -1,687 +0,0 @@ -#ifndef _LINUX_CGROUP_H -#define _LINUX_CGROUP_H -/* - * cgroup interface - * - * Copyright (C) 2003 BULL SA - * Copyright (C) 2004-2006 Silicon Graphics, Inc. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef CONFIG_CGROUPS - -/* - * All weight knobs on the default hierarhcy should use the following min, - * default and max values. The default value is the logarithmic center of - * MIN and MAX and allows 100x to be expressed in both directions. - */ -#define CGROUP_WEIGHT_MIN 1 -#define CGROUP_WEIGHT_DFL 100 -#define CGROUP_WEIGHT_MAX 10000 - -/* a css_task_iter should be treated as an opaque object */ -struct css_task_iter { - struct cgroup_subsys *ss; - - struct list_head *cset_pos; - struct list_head *cset_head; - - struct list_head *task_pos; - struct list_head *tasks_head; - struct list_head *mg_tasks_head; - - struct css_set *cur_cset; - struct task_struct *cur_task; - struct list_head iters_node; /* css_set->task_iters */ -}; - -extern struct cgroup_root cgrp_dfl_root; -extern struct css_set init_css_set; - -#define SUBSYS(_x) extern struct cgroup_subsys _x ## _cgrp_subsys; -#include -#undef SUBSYS - -#define SUBSYS(_x) \ - extern struct static_key_true _x ## _cgrp_subsys_enabled_key; \ - extern struct static_key_true _x ## _cgrp_subsys_on_dfl_key; -#include -#undef SUBSYS - -/** - * cgroup_subsys_enabled - fast test on whether a subsys is enabled - * @ss: subsystem in question - */ -#define cgroup_subsys_enabled(ss) \ - static_branch_likely(&ss ## _enabled_key) - -/** - * cgroup_subsys_on_dfl - fast test on whether a subsys is on default hierarchy - * @ss: subsystem in question - */ -#define cgroup_subsys_on_dfl(ss) \ - static_branch_likely(&ss ## _on_dfl_key) - -bool css_has_online_children(struct cgroup_subsys_state *css); -struct cgroup_subsys_state *css_from_id(int id, struct cgroup_subsys *ss); -struct cgroup_subsys_state *cgroup_get_e_css(struct cgroup *cgroup, - struct cgroup_subsys *ss); -struct cgroup_subsys_state *css_tryget_online_from_dir(struct dentry *dentry, - struct cgroup_subsys *ss); - -struct cgroup *cgroup_get_from_path(const char *path); -struct cgroup *cgroup_get_from_fd(int fd); - -int cgroup_attach_task_all(struct task_struct *from, struct task_struct *); -int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from); - -int cgroup_add_dfl_cftypes(struct cgroup_subsys *ss, struct cftype *cfts); -int cgroup_add_legacy_cftypes(struct cgroup_subsys *ss, struct cftype *cfts); -int cgroup_rm_cftypes(struct cftype *cfts); -void cgroup_file_notify(struct cgroup_file *cfile); - -int task_cgroup_path(struct task_struct *task, char *buf, size_t buflen); -int cgroupstats_build(struct cgroupstats *stats, struct dentry *dentry); -int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *tsk); - -void cgroup_fork(struct task_struct *p); -extern int cgroup_can_fork(struct task_struct *p); -extern void cgroup_cancel_fork(struct task_struct *p); -extern void cgroup_post_fork(struct task_struct *p); -void cgroup_exit(struct task_struct *p); -void cgroup_free(struct task_struct *p); - -int cgroup_init_early(void); -int cgroup_init(void); - -/* - * Iteration helpers and macros. - */ - -struct cgroup_subsys_state *css_next_child(struct cgroup_subsys_state *pos, - struct cgroup_subsys_state *parent); -struct cgroup_subsys_state *css_next_descendant_pre(struct cgroup_subsys_state *pos, - struct cgroup_subsys_state *css); -struct cgroup_subsys_state *css_rightmost_descendant(struct cgroup_subsys_state *pos); -struct cgroup_subsys_state *css_next_descendant_post(struct cgroup_subsys_state *pos, - struct cgroup_subsys_state *css); - -struct task_struct *cgroup_taskset_first(struct cgroup_taskset *tset, - struct cgroup_subsys_state **dst_cssp); -struct task_struct *cgroup_taskset_next(struct cgroup_taskset *tset, - struct cgroup_subsys_state **dst_cssp); - -void css_task_iter_start(struct cgroup_subsys_state *css, - struct css_task_iter *it); -struct task_struct *css_task_iter_next(struct css_task_iter *it); -void css_task_iter_end(struct css_task_iter *it); - -/** - * css_for_each_child - iterate through children of a css - * @pos: the css * to use as the loop cursor - * @parent: css whose children to walk - * - * Walk @parent's children. Must be called under rcu_read_lock(). - * - * If a subsystem synchronizes ->css_online() and the start of iteration, a - * css which finished ->css_online() is guaranteed to be visible in the - * future iterations and will stay visible until the last reference is put. - * A css which hasn't finished ->css_online() or already finished - * ->css_offline() may show up during traversal. It's each subsystem's - * responsibility to synchronize against on/offlining. - * - * It is allowed to temporarily drop RCU read lock during iteration. The - * caller is responsible for ensuring that @pos remains accessible until - * the start of the next iteration by, for example, bumping the css refcnt. - */ -#define css_for_each_child(pos, parent) \ - for ((pos) = css_next_child(NULL, (parent)); (pos); \ - (pos) = css_next_child((pos), (parent))) - -/** - * css_for_each_descendant_pre - pre-order walk of a css's descendants - * @pos: the css * to use as the loop cursor - * @root: css whose descendants to walk - * - * Walk @root's descendants. @root is included in the iteration and the - * first node to be visited. Must be called under rcu_read_lock(). - * - * If a subsystem synchronizes ->css_online() and the start of iteration, a - * css which finished ->css_online() is guaranteed to be visible in the - * future iterations and will stay visible until the last reference is put. - * A css which hasn't finished ->css_online() or already finished - * ->css_offline() may show up during traversal. It's each subsystem's - * responsibility to synchronize against on/offlining. - * - * For example, the following guarantees that a descendant can't escape - * state updates of its ancestors. - * - * my_online(@css) - * { - * Lock @css's parent and @css; - * Inherit state from the parent; - * Unlock both. - * } - * - * my_update_state(@css) - * { - * css_for_each_descendant_pre(@pos, @css) { - * Lock @pos; - * if (@pos == @css) - * Update @css's state; - * else - * Verify @pos is alive and inherit state from its parent; - * Unlock @pos; - * } - * } - * - * As long as the inheriting step, including checking the parent state, is - * enclosed inside @pos locking, double-locking the parent isn't necessary - * while inheriting. The state update to the parent is guaranteed to be - * visible by walking order and, as long as inheriting operations to the - * same @pos are atomic to each other, multiple updates racing each other - * still result in the correct state. It's guaranateed that at least one - * inheritance happens for any css after the latest update to its parent. - * - * If checking parent's state requires locking the parent, each inheriting - * iteration should lock and unlock both @pos->parent and @pos. - * - * Alternatively, a subsystem may choose to use a single global lock to - * synchronize ->css_online() and ->css_offline() against tree-walking - * operations. - * - * It is allowed to temporarily drop RCU read lock during iteration. The - * caller is responsible for ensuring that @pos remains accessible until - * the start of the next iteration by, for example, bumping the css refcnt. - */ -#define css_for_each_descendant_pre(pos, css) \ - for ((pos) = css_next_descendant_pre(NULL, (css)); (pos); \ - (pos) = css_next_descendant_pre((pos), (css))) - -/** - * css_for_each_descendant_post - post-order walk of a css's descendants - * @pos: the css * to use as the loop cursor - * @css: css whose descendants to walk - * - * Similar to css_for_each_descendant_pre() but performs post-order - * traversal instead. @root is included in the iteration and the last - * node to be visited. - * - * If a subsystem synchronizes ->css_online() and the start of iteration, a - * css which finished ->css_online() is guaranteed to be visible in the - * future iterations and will stay visible until the last reference is put. - * A css which hasn't finished ->css_online() or already finished - * ->css_offline() may show up during traversal. It's each subsystem's - * responsibility to synchronize against on/offlining. - * - * Note that the walk visibility guarantee example described in pre-order - * walk doesn't apply the same to post-order walks. - */ -#define css_for_each_descendant_post(pos, css) \ - for ((pos) = css_next_descendant_post(NULL, (css)); (pos); \ - (pos) = css_next_descendant_post((pos), (css))) - -/** - * cgroup_taskset_for_each - iterate cgroup_taskset - * @task: the loop cursor - * @dst_css: the destination css - * @tset: taskset to iterate - * - * @tset may contain multiple tasks and they may belong to multiple - * processes. - * - * On the v2 hierarchy, there may be tasks from multiple processes and they - * may not share the source or destination csses. - * - * On traditional hierarchies, when there are multiple tasks in @tset, if a - * task of a process is in @tset, all tasks of the process are in @tset. - * Also, all are guaranteed to share the same source and destination csses. - * - * Iteration is not in any specific order. - */ -#define cgroup_taskset_for_each(task, dst_css, tset) \ - for ((task) = cgroup_taskset_first((tset), &(dst_css)); \ - (task); \ - (task) = cgroup_taskset_next((tset), &(dst_css))) - -/** - * cgroup_taskset_for_each_leader - iterate group leaders in a cgroup_taskset - * @leader: the loop cursor - * @dst_css: the destination css - * @tset: takset to iterate - * - * Iterate threadgroup leaders of @tset. For single-task migrations, @tset - * may not contain any. - */ -#define cgroup_taskset_for_each_leader(leader, dst_css, tset) \ - for ((leader) = cgroup_taskset_first((tset), &(dst_css)); \ - (leader); \ - (leader) = cgroup_taskset_next((tset), &(dst_css))) \ - if ((leader) != (leader)->group_leader) \ - ; \ - else - -/* - * Inline functions. - */ - -/** - * css_get - obtain a reference on the specified css - * @css: target css - * - * The caller must already have a reference. - */ -static inline void css_get(struct cgroup_subsys_state *css) -{ - if (!(css->flags & CSS_NO_REF)) - percpu_ref_get(&css->refcnt); -} - -/** - * css_get_many - obtain references on the specified css - * @css: target css - * @n: number of references to get - * - * The caller must already have a reference. - */ -static inline void css_get_many(struct cgroup_subsys_state *css, unsigned int n) -{ - if (!(css->flags & CSS_NO_REF)) - percpu_ref_get_many(&css->refcnt, n); -} - -/** - * css_tryget - try to obtain a reference on the specified css - * @css: target css - * - * Obtain a reference on @css unless it already has reached zero and is - * being released. This function doesn't care whether @css is on or - * offline. The caller naturally needs to ensure that @css is accessible - * but doesn't have to be holding a reference on it - IOW, RCU protected - * access is good enough for this function. Returns %true if a reference - * count was successfully obtained; %false otherwise. - */ -static inline bool css_tryget(struct cgroup_subsys_state *css) -{ - if (!(css->flags & CSS_NO_REF)) - return percpu_ref_tryget(&css->refcnt); - return true; -} - -/** - * css_tryget_online - try to obtain a reference on the specified css if online - * @css: target css - * - * Obtain a reference on @css if it's online. The caller naturally needs - * to ensure that @css is accessible but doesn't have to be holding a - * reference on it - IOW, RCU protected access is good enough for this - * function. Returns %true if a reference count was successfully obtained; - * %false otherwise. - */ -static inline bool css_tryget_online(struct cgroup_subsys_state *css) -{ - if (!(css->flags & CSS_NO_REF)) - return percpu_ref_tryget_live(&css->refcnt); - return true; -} - -/** - * css_put - put a css reference - * @css: target css - * - * Put a reference obtained via css_get() and css_tryget_online(). - */ -static inline void css_put(struct cgroup_subsys_state *css) -{ - if (!(css->flags & CSS_NO_REF)) - percpu_ref_put(&css->refcnt); -} - -/** - * css_put_many - put css references - * @css: target css - * @n: number of references to put - * - * Put references obtained via css_get() and css_tryget_online(). - */ -static inline void css_put_many(struct cgroup_subsys_state *css, unsigned int n) -{ - if (!(css->flags & CSS_NO_REF)) - percpu_ref_put_many(&css->refcnt, n); -} - -static inline void cgroup_put(struct cgroup *cgrp) -{ - css_put(&cgrp->self); -} - -/** - * task_css_set_check - obtain a task's css_set with extra access conditions - * @task: the task to obtain css_set for - * @__c: extra condition expression to be passed to rcu_dereference_check() - * - * A task's css_set is RCU protected, initialized and exited while holding - * task_lock(), and can only be modified while holding both cgroup_mutex - * and task_lock() while the task is alive. This macro verifies that the - * caller is inside proper critical section and returns @task's css_set. - * - * The caller can also specify additional allowed conditions via @__c, such - * as locks used during the cgroup_subsys::attach() methods. - */ -#ifdef CONFIG_PROVE_RCU -extern struct mutex cgroup_mutex; -extern spinlock_t css_set_lock; -#define task_css_set_check(task, __c) \ - rcu_dereference_check((task)->cgroups, \ - lockdep_is_held(&cgroup_mutex) || \ - lockdep_is_held(&css_set_lock) || \ - ((task)->flags & PF_EXITING) || (__c)) -#else -#define task_css_set_check(task, __c) \ - rcu_dereference((task)->cgroups) -#endif - -/** - * task_css_check - obtain css for (task, subsys) w/ extra access conds - * @task: the target task - * @subsys_id: the target subsystem ID - * @__c: extra condition expression to be passed to rcu_dereference_check() - * - * Return the cgroup_subsys_state for the (@task, @subsys_id) pair. The - * synchronization rules are the same as task_css_set_check(). - */ -#define task_css_check(task, subsys_id, __c) \ - task_css_set_check((task), (__c))->subsys[(subsys_id)] - -/** - * task_css_set - obtain a task's css_set - * @task: the task to obtain css_set for - * - * See task_css_set_check(). - */ -static inline struct css_set *task_css_set(struct task_struct *task) -{ - return task_css_set_check(task, false); -} - -/** - * task_css - obtain css for (task, subsys) - * @task: the target task - * @subsys_id: the target subsystem ID - * - * See task_css_check(). - */ -static inline struct cgroup_subsys_state *task_css(struct task_struct *task, - int subsys_id) -{ - return task_css_check(task, subsys_id, false); -} - -/** - * task_get_css - find and get the css for (task, subsys) - * @task: the target task - * @subsys_id: the target subsystem ID - * - * Find the css for the (@task, @subsys_id) combination, increment a - * reference on and return it. This function is guaranteed to return a - * valid css. - */ -static inline struct cgroup_subsys_state * -task_get_css(struct task_struct *task, int subsys_id) -{ - struct cgroup_subsys_state *css; - - rcu_read_lock(); - while (true) { - css = task_css(task, subsys_id); - if (likely(css_tryget_online(css))) - break; - cpu_relax(); - } - rcu_read_unlock(); - return css; -} - -/** - * task_css_is_root - test whether a task belongs to the root css - * @task: the target task - * @subsys_id: the target subsystem ID - * - * Test whether @task belongs to the root css on the specified subsystem. - * May be invoked in any context. - */ -static inline bool task_css_is_root(struct task_struct *task, int subsys_id) -{ - return task_css_check(task, subsys_id, true) == - init_css_set.subsys[subsys_id]; -} - -static inline struct cgroup *task_cgroup(struct task_struct *task, - int subsys_id) -{ - return task_css(task, subsys_id)->cgroup; -} - -/** - * cgroup_is_descendant - test ancestry - * @cgrp: the cgroup to be tested - * @ancestor: possible ancestor of @cgrp - * - * Test whether @cgrp is a descendant of @ancestor. It also returns %true - * if @cgrp == @ancestor. This function is safe to call as long as @cgrp - * and @ancestor are accessible. - */ -static inline bool cgroup_is_descendant(struct cgroup *cgrp, - struct cgroup *ancestor) -{ - if (cgrp->root != ancestor->root || cgrp->level < ancestor->level) - return false; - return cgrp->ancestor_ids[ancestor->level] == ancestor->id; -} - -/** - * task_under_cgroup_hierarchy - test task's membership of cgroup ancestry - * @task: the task to be tested - * @ancestor: possible ancestor of @task's cgroup - * - * Tests whether @task's default cgroup hierarchy is a descendant of @ancestor. - * It follows all the same rules as cgroup_is_descendant, and only applies - * to the default hierarchy. - */ -static inline bool task_under_cgroup_hierarchy(struct task_struct *task, - struct cgroup *ancestor) -{ - struct css_set *cset = task_css_set(task); - - return cgroup_is_descendant(cset->dfl_cgrp, ancestor); -} - -/* no synchronization, the result can only be used as a hint */ -static inline bool cgroup_is_populated(struct cgroup *cgrp) -{ - return cgrp->populated_cnt; -} - -/* returns ino associated with a cgroup */ -static inline ino_t cgroup_ino(struct cgroup *cgrp) -{ - return cgrp->kn->ino; -} - -/* cft/css accessors for cftype->write() operation */ -static inline struct cftype *of_cft(struct kernfs_open_file *of) -{ - return of->kn->priv; -} - -struct cgroup_subsys_state *of_css(struct kernfs_open_file *of); - -/* cft/css accessors for cftype->seq_*() operations */ -static inline struct cftype *seq_cft(struct seq_file *seq) -{ - return of_cft(seq->private); -} - -static inline struct cgroup_subsys_state *seq_css(struct seq_file *seq) -{ - return of_css(seq->private); -} - -/* - * Name / path handling functions. All are thin wrappers around the kernfs - * counterparts and can be called under any context. - */ - -static inline int cgroup_name(struct cgroup *cgrp, char *buf, size_t buflen) -{ - return kernfs_name(cgrp->kn, buf, buflen); -} - -static inline int cgroup_path(struct cgroup *cgrp, char *buf, size_t buflen) -{ - return kernfs_path(cgrp->kn, buf, buflen); -} - -static inline void pr_cont_cgroup_name(struct cgroup *cgrp) -{ - pr_cont_kernfs_name(cgrp->kn); -} - -static inline void pr_cont_cgroup_path(struct cgroup *cgrp) -{ - pr_cont_kernfs_path(cgrp->kn); -} - -#else /* !CONFIG_CGROUPS */ - -struct cgroup_subsys_state; -struct cgroup; - -static inline void css_put(struct cgroup_subsys_state *css) {} -static inline int cgroup_attach_task_all(struct task_struct *from, - struct task_struct *t) { return 0; } -static inline int cgroupstats_build(struct cgroupstats *stats, - struct dentry *dentry) { return -EINVAL; } - -static inline void cgroup_fork(struct task_struct *p) {} -static inline int cgroup_can_fork(struct task_struct *p) { return 0; } -static inline void cgroup_cancel_fork(struct task_struct *p) {} -static inline void cgroup_post_fork(struct task_struct *p) {} -static inline void cgroup_exit(struct task_struct *p) {} -static inline void cgroup_free(struct task_struct *p) {} - -static inline int cgroup_init_early(void) { return 0; } -static inline int cgroup_init(void) { return 0; } - -static inline bool task_under_cgroup_hierarchy(struct task_struct *task, - struct cgroup *ancestor) -{ - return true; -} -#endif /* !CONFIG_CGROUPS */ - -/* - * sock->sk_cgrp_data handling. For more info, see sock_cgroup_data - * definition in cgroup-defs.h. - */ -#ifdef CONFIG_SOCK_CGROUP_DATA - -#if defined(CONFIG_CGROUP_NET_PRIO) || defined(CONFIG_CGROUP_NET_CLASSID) -extern spinlock_t cgroup_sk_update_lock; -#endif - -void cgroup_sk_alloc_disable(void); -void cgroup_sk_alloc(struct sock_cgroup_data *skcd); -void cgroup_sk_free(struct sock_cgroup_data *skcd); - -static inline struct cgroup *sock_cgroup_ptr(struct sock_cgroup_data *skcd) -{ -#if defined(CONFIG_CGROUP_NET_PRIO) || defined(CONFIG_CGROUP_NET_CLASSID) - unsigned long v; - - /* - * @skcd->val is 64bit but the following is safe on 32bit too as we - * just need the lower ulong to be written and read atomically. - */ - v = READ_ONCE(skcd->val); - - if (v & 1) - return &cgrp_dfl_root.cgrp; - - return (struct cgroup *)(unsigned long)v ?: &cgrp_dfl_root.cgrp; -#else - return (struct cgroup *)(unsigned long)skcd->val; -#endif -} - -#else /* CONFIG_CGROUP_DATA */ - -static inline void cgroup_sk_alloc(struct sock_cgroup_data *skcd) {} -static inline void cgroup_sk_free(struct sock_cgroup_data *skcd) {} - -#endif /* CONFIG_CGROUP_DATA */ - -struct cgroup_namespace { - atomic_t count; - struct ns_common ns; - struct user_namespace *user_ns; - struct ucounts *ucounts; - struct css_set *root_cset; -}; - -extern struct cgroup_namespace init_cgroup_ns; - -#ifdef CONFIG_CGROUPS - -void free_cgroup_ns(struct cgroup_namespace *ns); - -struct cgroup_namespace *copy_cgroup_ns(unsigned long flags, - struct user_namespace *user_ns, - struct cgroup_namespace *old_ns); - -int cgroup_path_ns(struct cgroup *cgrp, char *buf, size_t buflen, - struct cgroup_namespace *ns); - -#else /* !CONFIG_CGROUPS */ - -static inline void free_cgroup_ns(struct cgroup_namespace *ns) { } -static inline struct cgroup_namespace * -copy_cgroup_ns(unsigned long flags, struct user_namespace *user_ns, - struct cgroup_namespace *old_ns) -{ - return old_ns; -} - -#endif /* !CONFIG_CGROUPS */ - -static inline void get_cgroup_ns(struct cgroup_namespace *ns) -{ - if (ns) - atomic_inc(&ns->count); -} - -static inline void put_cgroup_ns(struct cgroup_namespace *ns) -{ - if (ns && atomic_dec_and_test(&ns->count)) - free_cgroup_ns(ns); -} - -#endif /* _LINUX_CGROUP_H */ diff --git a/src/linux/include/linux/cleancache.h b/src/linux/include/linux/cleancache.h deleted file mode 100644 index fccf7f4..0000000 --- a/src/linux/include/linux/cleancache.h +++ /dev/null @@ -1,123 +0,0 @@ -#ifndef _LINUX_CLEANCACHE_H -#define _LINUX_CLEANCACHE_H - -#include -#include -#include - -#define CLEANCACHE_NO_POOL -1 -#define CLEANCACHE_NO_BACKEND -2 -#define CLEANCACHE_NO_BACKEND_SHARED -3 - -#define CLEANCACHE_KEY_MAX 6 - -/* - * cleancache requires every file with a page in cleancache to have a - * unique key unless/until the file is removed/truncated. For some - * filesystems, the inode number is unique, but for "modern" filesystems - * an exportable filehandle is required (see exportfs.h) - */ -struct cleancache_filekey { - union { - ino_t ino; - __u32 fh[CLEANCACHE_KEY_MAX]; - u32 key[CLEANCACHE_KEY_MAX]; - } u; -}; - -struct cleancache_ops { - int (*init_fs)(size_t); - int (*init_shared_fs)(char *uuid, size_t); - int (*get_page)(int, struct cleancache_filekey, - pgoff_t, struct page *); - void (*put_page)(int, struct cleancache_filekey, - pgoff_t, struct page *); - void (*invalidate_page)(int, struct cleancache_filekey, pgoff_t); - void (*invalidate_inode)(int, struct cleancache_filekey); - void (*invalidate_fs)(int); -}; - -extern int cleancache_register_ops(const struct cleancache_ops *ops); -extern void __cleancache_init_fs(struct super_block *); -extern void __cleancache_init_shared_fs(struct super_block *); -extern int __cleancache_get_page(struct page *); -extern void __cleancache_put_page(struct page *); -extern void __cleancache_invalidate_page(struct address_space *, struct page *); -extern void __cleancache_invalidate_inode(struct address_space *); -extern void __cleancache_invalidate_fs(struct super_block *); - -#ifdef CONFIG_CLEANCACHE -#define cleancache_enabled (1) -static inline bool cleancache_fs_enabled_mapping(struct address_space *mapping) -{ - return mapping->host->i_sb->cleancache_poolid >= 0; -} -static inline bool cleancache_fs_enabled(struct page *page) -{ - return cleancache_fs_enabled_mapping(page->mapping); -} -#else -#define cleancache_enabled (0) -#define cleancache_fs_enabled(_page) (0) -#define cleancache_fs_enabled_mapping(_page) (0) -#endif - -/* - * The shim layer provided by these inline functions allows the compiler - * to reduce all cleancache hooks to nothingness if CONFIG_CLEANCACHE - * is disabled, to a single global variable check if CONFIG_CLEANCACHE - * is enabled but no cleancache "backend" has dynamically enabled it, - * and, for the most frequent cleancache ops, to a single global variable - * check plus a superblock element comparison if CONFIG_CLEANCACHE is enabled - * and a cleancache backend has dynamically enabled cleancache, but the - * filesystem referenced by that cleancache op has not enabled cleancache. - * As a result, CONFIG_CLEANCACHE can be enabled by default with essentially - * no measurable performance impact. - */ - -static inline void cleancache_init_fs(struct super_block *sb) -{ - if (cleancache_enabled) - __cleancache_init_fs(sb); -} - -static inline void cleancache_init_shared_fs(struct super_block *sb) -{ - if (cleancache_enabled) - __cleancache_init_shared_fs(sb); -} - -static inline int cleancache_get_page(struct page *page) -{ - if (cleancache_enabled && cleancache_fs_enabled(page)) - return __cleancache_get_page(page); - return -1; -} - -static inline void cleancache_put_page(struct page *page) -{ - if (cleancache_enabled && cleancache_fs_enabled(page)) - __cleancache_put_page(page); -} - -static inline void cleancache_invalidate_page(struct address_space *mapping, - struct page *page) -{ - /* careful... page->mapping is NULL sometimes when this is called */ - if (cleancache_enabled && cleancache_fs_enabled_mapping(mapping)) - __cleancache_invalidate_page(mapping, page); -} - -static inline void cleancache_invalidate_inode(struct address_space *mapping) -{ - if (cleancache_enabled && cleancache_fs_enabled_mapping(mapping)) - __cleancache_invalidate_inode(mapping); -} - -static inline void cleancache_invalidate_fs(struct super_block *sb) -{ - if (cleancache_enabled) - __cleancache_invalidate_fs(sb); -} - -#endif /* _LINUX_CLEANCACHE_H */ diff --git a/src/linux/include/linux/clk-provider.h b/src/linux/include/linux/clk-provider.h deleted file mode 100644 index a428aec..0000000 --- a/src/linux/include/linux/clk-provider.h +++ /dev/null @@ -1,916 +0,0 @@ -/* - * linux/include/linux/clk-provider.h - * - * Copyright (c) 2010-2011 Jeremy Kerr - * Copyright (C) 2011-2012 Linaro Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef __LINUX_CLK_PROVIDER_H -#define __LINUX_CLK_PROVIDER_H - -#include -#include - -#ifdef CONFIG_COMMON_CLK - -/* - * flags used across common struct clk. these flags should only affect the - * top-level framework. custom flags for dealing with hardware specifics - * belong in struct clk_foo - */ -#define CLK_SET_RATE_GATE BIT(0) /* must be gated across rate change */ -#define CLK_SET_PARENT_GATE BIT(1) /* must be gated across re-parent */ -#define CLK_SET_RATE_PARENT BIT(2) /* propagate rate change up one level */ -#define CLK_IGNORE_UNUSED BIT(3) /* do not gate even if unused */ - /* unused */ -#define CLK_IS_BASIC BIT(5) /* Basic clk, can't do a to_clk_foo() */ -#define CLK_GET_RATE_NOCACHE BIT(6) /* do not use the cached clk rate */ -#define CLK_SET_RATE_NO_REPARENT BIT(7) /* don't re-parent on rate change */ -#define CLK_GET_ACCURACY_NOCACHE BIT(8) /* do not use the cached clk accuracy */ -#define CLK_RECALC_NEW_RATES BIT(9) /* recalc rates after notifications */ -#define CLK_SET_RATE_UNGATE BIT(10) /* clock needs to run to set rate */ -#define CLK_IS_CRITICAL BIT(11) /* do not gate, ever */ -/* parents need enable during gate/ungate, set rate and re-parent */ -#define CLK_OPS_PARENT_ENABLE BIT(12) - -struct clk; -struct clk_hw; -struct clk_core; -struct dentry; - -/** - * struct clk_rate_request - Structure encoding the clk constraints that - * a clock user might require. - * - * @rate: Requested clock rate. This field will be adjusted by - * clock drivers according to hardware capabilities. - * @min_rate: Minimum rate imposed by clk users. - * @max_rate: Maximum rate imposed by clk users. - * @best_parent_rate: The best parent rate a parent can provide to fulfill the - * requested constraints. - * @best_parent_hw: The most appropriate parent clock that fulfills the - * requested constraints. - * - */ -struct clk_rate_request { - unsigned long rate; - unsigned long min_rate; - unsigned long max_rate; - unsigned long best_parent_rate; - struct clk_hw *best_parent_hw; -}; - -/** - * struct clk_ops - Callback operations for hardware clocks; these are to - * be provided by the clock implementation, and will be called by drivers - * through the clk_* api. - * - * @prepare: Prepare the clock for enabling. This must not return until - * the clock is fully prepared, and it's safe to call clk_enable. - * This callback is intended to allow clock implementations to - * do any initialisation that may sleep. Called with - * prepare_lock held. - * - * @unprepare: Release the clock from its prepared state. This will typically - * undo any work done in the @prepare callback. Called with - * prepare_lock held. - * - * @is_prepared: Queries the hardware to determine if the clock is prepared. - * This function is allowed to sleep. Optional, if this op is not - * set then the prepare count will be used. - * - * @unprepare_unused: Unprepare the clock atomically. Only called from - * clk_disable_unused for prepare clocks with special needs. - * Called with prepare mutex held. This function may sleep. - * - * @enable: Enable the clock atomically. This must not return until the - * clock is generating a valid clock signal, usable by consumer - * devices. Called with enable_lock held. This function must not - * sleep. - * - * @disable: Disable the clock atomically. Called with enable_lock held. - * This function must not sleep. - * - * @is_enabled: Queries the hardware to determine if the clock is enabled. - * This function must not sleep. Optional, if this op is not - * set then the enable count will be used. - * - * @disable_unused: Disable the clock atomically. Only called from - * clk_disable_unused for gate clocks with special needs. - * Called with enable_lock held. This function must not - * sleep. - * - * @recalc_rate Recalculate the rate of this clock, by querying hardware. The - * parent rate is an input parameter. It is up to the caller to - * ensure that the prepare_mutex is held across this call. - * Returns the calculated rate. Optional, but recommended - if - * this op is not set then clock rate will be initialized to 0. - * - * @round_rate: Given a target rate as input, returns the closest rate actually - * supported by the clock. The parent rate is an input/output - * parameter. - * - * @determine_rate: Given a target rate as input, returns the closest rate - * actually supported by the clock, and optionally the parent clock - * that should be used to provide the clock rate. - * - * @set_parent: Change the input source of this clock; for clocks with multiple - * possible parents specify a new parent by passing in the index - * as a u8 corresponding to the parent in either the .parent_names - * or .parents arrays. This function in affect translates an - * array index into the value programmed into the hardware. - * Returns 0 on success, -EERROR otherwise. - * - * @get_parent: Queries the hardware to determine the parent of a clock. The - * return value is a u8 which specifies the index corresponding to - * the parent clock. This index can be applied to either the - * .parent_names or .parents arrays. In short, this function - * translates the parent value read from hardware into an array - * index. Currently only called when the clock is initialized by - * __clk_init. This callback is mandatory for clocks with - * multiple parents. It is optional (and unnecessary) for clocks - * with 0 or 1 parents. - * - * @set_rate: Change the rate of this clock. The requested rate is specified - * by the second argument, which should typically be the return - * of .round_rate call. The third argument gives the parent rate - * which is likely helpful for most .set_rate implementation. - * Returns 0 on success, -EERROR otherwise. - * - * @set_rate_and_parent: Change the rate and the parent of this clock. The - * requested rate is specified by the second argument, which - * should typically be the return of .round_rate call. The - * third argument gives the parent rate which is likely helpful - * for most .set_rate_and_parent implementation. The fourth - * argument gives the parent index. This callback is optional (and - * unnecessary) for clocks with 0 or 1 parents as well as - * for clocks that can tolerate switching the rate and the parent - * separately via calls to .set_parent and .set_rate. - * Returns 0 on success, -EERROR otherwise. - * - * @recalc_accuracy: Recalculate the accuracy of this clock. The clock accuracy - * is expressed in ppb (parts per billion). The parent accuracy is - * an input parameter. - * Returns the calculated accuracy. Optional - if this op is not - * set then clock accuracy will be initialized to parent accuracy - * or 0 (perfect clock) if clock has no parent. - * - * @get_phase: Queries the hardware to get the current phase of a clock. - * Returned values are 0-359 degrees on success, negative - * error codes on failure. - * - * @set_phase: Shift the phase this clock signal in degrees specified - * by the second argument. Valid values for degrees are - * 0-359. Return 0 on success, otherwise -EERROR. - * - * @init: Perform platform-specific initialization magic. - * This is not not used by any of the basic clock types. - * Please consider other ways of solving initialization problems - * before using this callback, as its use is discouraged. - * - * @debug_init: Set up type-specific debugfs entries for this clock. This - * is called once, after the debugfs directory entry for this - * clock has been created. The dentry pointer representing that - * directory is provided as an argument. Called with - * prepare_lock held. Returns 0 on success, -EERROR otherwise. - * - * - * The clk_enable/clk_disable and clk_prepare/clk_unprepare pairs allow - * implementations to split any work between atomic (enable) and sleepable - * (prepare) contexts. If enabling a clock requires code that might sleep, - * this must be done in clk_prepare. Clock enable code that will never be - * called in a sleepable context may be implemented in clk_enable. - * - * Typically, drivers will call clk_prepare when a clock may be needed later - * (eg. when a device is opened), and clk_enable when the clock is actually - * required (eg. from an interrupt). Note that clk_prepare MUST have been - * called before clk_enable. - */ -struct clk_ops { - int (*prepare)(struct clk_hw *hw); - void (*unprepare)(struct clk_hw *hw); - int (*is_prepared)(struct clk_hw *hw); - void (*unprepare_unused)(struct clk_hw *hw); - int (*enable)(struct clk_hw *hw); - void (*disable)(struct clk_hw *hw); - int (*is_enabled)(struct clk_hw *hw); - void (*disable_unused)(struct clk_hw *hw); - unsigned long (*recalc_rate)(struct clk_hw *hw, - unsigned long parent_rate); - long (*round_rate)(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate); - int (*determine_rate)(struct clk_hw *hw, - struct clk_rate_request *req); - int (*set_parent)(struct clk_hw *hw, u8 index); - u8 (*get_parent)(struct clk_hw *hw); - int (*set_rate)(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate); - int (*set_rate_and_parent)(struct clk_hw *hw, - unsigned long rate, - unsigned long parent_rate, u8 index); - unsigned long (*recalc_accuracy)(struct clk_hw *hw, - unsigned long parent_accuracy); - int (*get_phase)(struct clk_hw *hw); - int (*set_phase)(struct clk_hw *hw, int degrees); - void (*init)(struct clk_hw *hw); - int (*debug_init)(struct clk_hw *hw, struct dentry *dentry); -}; - -/** - * struct clk_init_data - holds init data that's common to all clocks and is - * shared between the clock provider and the common clock framework. - * - * @name: clock name - * @ops: operations this clock supports - * @parent_names: array of string names for all possible parents - * @num_parents: number of possible parents - * @flags: framework-level hints and quirks - */ -struct clk_init_data { - const char *name; - const struct clk_ops *ops; - const char * const *parent_names; - u8 num_parents; - unsigned long flags; -}; - -/** - * struct clk_hw - handle for traversing from a struct clk to its corresponding - * hardware-specific structure. struct clk_hw should be declared within struct - * clk_foo and then referenced by the struct clk instance that uses struct - * clk_foo's clk_ops - * - * @core: pointer to the struct clk_core instance that points back to this - * struct clk_hw instance - * - * @clk: pointer to the per-user struct clk instance that can be used to call - * into the clk API - * - * @init: pointer to struct clk_init_data that contains the init data shared - * with the common clock framework. - */ -struct clk_hw { - struct clk_core *core; - struct clk *clk; - const struct clk_init_data *init; -}; - -/* - * DOC: Basic clock implementations common to many platforms - * - * Each basic clock hardware type is comprised of a structure describing the - * clock hardware, implementations of the relevant callbacks in struct clk_ops, - * unique flags for that hardware type, a registration function and an - * alternative macro for static initialization - */ - -/** - * struct clk_fixed_rate - fixed-rate clock - * @hw: handle between common and hardware-specific interfaces - * @fixed_rate: constant frequency of clock - */ -struct clk_fixed_rate { - struct clk_hw hw; - unsigned long fixed_rate; - unsigned long fixed_accuracy; - u8 flags; -}; - -#define to_clk_fixed_rate(_hw) container_of(_hw, struct clk_fixed_rate, hw) - -extern const struct clk_ops clk_fixed_rate_ops; -struct clk *clk_register_fixed_rate(struct device *dev, const char *name, - const char *parent_name, unsigned long flags, - unsigned long fixed_rate); -struct clk_hw *clk_hw_register_fixed_rate(struct device *dev, const char *name, - const char *parent_name, unsigned long flags, - unsigned long fixed_rate); -struct clk *clk_register_fixed_rate_with_accuracy(struct device *dev, - const char *name, const char *parent_name, unsigned long flags, - unsigned long fixed_rate, unsigned long fixed_accuracy); -void clk_unregister_fixed_rate(struct clk *clk); -struct clk_hw *clk_hw_register_fixed_rate_with_accuracy(struct device *dev, - const char *name, const char *parent_name, unsigned long flags, - unsigned long fixed_rate, unsigned long fixed_accuracy); -void clk_hw_unregister_fixed_rate(struct clk_hw *hw); - -void of_fixed_clk_setup(struct device_node *np); - -/** - * struct clk_gate - gating clock - * - * @hw: handle between common and hardware-specific interfaces - * @reg: register controlling gate - * @bit_idx: single bit controlling gate - * @flags: hardware-specific flags - * @lock: register lock - * - * Clock which can gate its output. Implements .enable & .disable - * - * Flags: - * CLK_GATE_SET_TO_DISABLE - by default this clock sets the bit at bit_idx to - * enable the clock. Setting this flag does the opposite: setting the bit - * disable the clock and clearing it enables the clock - * CLK_GATE_HIWORD_MASK - The gate settings are only in lower 16-bit - * of this register, and mask of gate bits are in higher 16-bit of this - * register. While setting the gate bits, higher 16-bit should also be - * updated to indicate changing gate bits. - */ -struct clk_gate { - struct clk_hw hw; - void __iomem *reg; - u8 bit_idx; - u8 flags; - spinlock_t *lock; -}; - -#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw) - -#define CLK_GATE_SET_TO_DISABLE BIT(0) -#define CLK_GATE_HIWORD_MASK BIT(1) - -extern const struct clk_ops clk_gate_ops; -struct clk *clk_register_gate(struct device *dev, const char *name, - const char *parent_name, unsigned long flags, - void __iomem *reg, u8 bit_idx, - u8 clk_gate_flags, spinlock_t *lock); -struct clk_hw *clk_hw_register_gate(struct device *dev, const char *name, - const char *parent_name, unsigned long flags, - void __iomem *reg, u8 bit_idx, - u8 clk_gate_flags, spinlock_t *lock); -void clk_unregister_gate(struct clk *clk); -void clk_hw_unregister_gate(struct clk_hw *hw); - -struct clk_div_table { - unsigned int val; - unsigned int div; -}; - -/** - * struct clk_divider - adjustable divider clock - * - * @hw: handle between common and hardware-specific interfaces - * @reg: register containing the divider - * @shift: shift to the divider bit field - * @width: width of the divider bit field - * @table: array of value/divider pairs, last entry should have div = 0 - * @lock: register lock - * - * Clock with an adjustable divider affecting its output frequency. Implements - * .recalc_rate, .set_rate and .round_rate - * - * Flags: - * CLK_DIVIDER_ONE_BASED - by default the divisor is the value read from the - * register plus one. If CLK_DIVIDER_ONE_BASED is set then the divider is - * the raw value read from the register, with the value of zero considered - * invalid, unless CLK_DIVIDER_ALLOW_ZERO is set. - * CLK_DIVIDER_POWER_OF_TWO - clock divisor is 2 raised to the value read from - * the hardware register - * CLK_DIVIDER_ALLOW_ZERO - Allow zero divisors. For dividers which have - * CLK_DIVIDER_ONE_BASED set, it is possible to end up with a zero divisor. - * Some hardware implementations gracefully handle this case and allow a - * zero divisor by not modifying their input clock - * (divide by one / bypass). - * CLK_DIVIDER_HIWORD_MASK - The divider settings are only in lower 16-bit - * of this register, and mask of divider bits are in higher 16-bit of this - * register. While setting the divider bits, higher 16-bit should also be - * updated to indicate changing divider bits. - * CLK_DIVIDER_ROUND_CLOSEST - Makes the best calculated divider to be rounded - * to the closest integer instead of the up one. - * CLK_DIVIDER_READ_ONLY - The divider settings are preconfigured and should - * not be changed by the clock framework. - * CLK_DIVIDER_MAX_AT_ZERO - For dividers which are like CLK_DIVIDER_ONE_BASED - * except when the value read from the register is zero, the divisor is - * 2^width of the field. - */ -struct clk_divider { - struct clk_hw hw; - void __iomem *reg; - u8 shift; - u8 width; - u8 flags; - const struct clk_div_table *table; - spinlock_t *lock; -}; - -#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) - -#define CLK_DIVIDER_ONE_BASED BIT(0) -#define CLK_DIVIDER_POWER_OF_TWO BIT(1) -#define CLK_DIVIDER_ALLOW_ZERO BIT(2) -#define CLK_DIVIDER_HIWORD_MASK BIT(3) -#define CLK_DIVIDER_ROUND_CLOSEST BIT(4) -#define CLK_DIVIDER_READ_ONLY BIT(5) -#define CLK_DIVIDER_MAX_AT_ZERO BIT(6) - -extern const struct clk_ops clk_divider_ops; -extern const struct clk_ops clk_divider_ro_ops; - -unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, - unsigned int val, const struct clk_div_table *table, - unsigned long flags); -long divider_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *prate, const struct clk_div_table *table, - u8 width, unsigned long flags); -int divider_get_val(unsigned long rate, unsigned long parent_rate, - const struct clk_div_table *table, u8 width, - unsigned long flags); - -struct clk *clk_register_divider(struct device *dev, const char *name, - const char *parent_name, unsigned long flags, - void __iomem *reg, u8 shift, u8 width, - u8 clk_divider_flags, spinlock_t *lock); -struct clk_hw *clk_hw_register_divider(struct device *dev, const char *name, - const char *parent_name, unsigned long flags, - void __iomem *reg, u8 shift, u8 width, - u8 clk_divider_flags, spinlock_t *lock); -struct clk *clk_register_divider_table(struct device *dev, const char *name, - const char *parent_name, unsigned long flags, - void __iomem *reg, u8 shift, u8 width, - u8 clk_divider_flags, const struct clk_div_table *table, - spinlock_t *lock); -struct clk_hw *clk_hw_register_divider_table(struct device *dev, - const char *name, const char *parent_name, unsigned long flags, - void __iomem *reg, u8 shift, u8 width, - u8 clk_divider_flags, const struct clk_div_table *table, - spinlock_t *lock); -void clk_unregister_divider(struct clk *clk); -void clk_hw_unregister_divider(struct clk_hw *hw); - -/** - * struct clk_mux - multiplexer clock - * - * @hw: handle between common and hardware-specific interfaces - * @reg: register controlling multiplexer - * @shift: shift to multiplexer bit field - * @width: width of mutliplexer bit field - * @flags: hardware-specific flags - * @lock: register lock - * - * Clock with multiple selectable parents. Implements .get_parent, .set_parent - * and .recalc_rate - * - * Flags: - * CLK_MUX_INDEX_ONE - register index starts at 1, not 0 - * CLK_MUX_INDEX_BIT - register index is a single bit (power of two) - * CLK_MUX_HIWORD_MASK - The mux settings are only in lower 16-bit of this - * register, and mask of mux bits are in higher 16-bit of this register. - * While setting the mux bits, higher 16-bit should also be updated to - * indicate changing mux bits. - * CLK_MUX_ROUND_CLOSEST - Use the parent rate that is closest to the desired - * frequency. - */ -struct clk_mux { - struct clk_hw hw; - void __iomem *reg; - u32 *table; - u32 mask; - u8 shift; - u8 flags; - spinlock_t *lock; -}; - -#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw) - -#define CLK_MUX_INDEX_ONE BIT(0) -#define CLK_MUX_INDEX_BIT BIT(1) -#define CLK_MUX_HIWORD_MASK BIT(2) -#define CLK_MUX_READ_ONLY BIT(3) /* mux can't be changed */ -#define CLK_MUX_ROUND_CLOSEST BIT(4) - -extern const struct clk_ops clk_mux_ops; -extern const struct clk_ops clk_mux_ro_ops; - -struct clk *clk_register_mux(struct device *dev, const char *name, - const char * const *parent_names, u8 num_parents, - unsigned long flags, - void __iomem *reg, u8 shift, u8 width, - u8 clk_mux_flags, spinlock_t *lock); -struct clk_hw *clk_hw_register_mux(struct device *dev, const char *name, - const char * const *parent_names, u8 num_parents, - unsigned long flags, - void __iomem *reg, u8 shift, u8 width, - u8 clk_mux_flags, spinlock_t *lock); - -struct clk *clk_register_mux_table(struct device *dev, const char *name, - const char * const *parent_names, u8 num_parents, - unsigned long flags, - void __iomem *reg, u8 shift, u32 mask, - u8 clk_mux_flags, u32 *table, spinlock_t *lock); -struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name, - const char * const *parent_names, u8 num_parents, - unsigned long flags, - void __iomem *reg, u8 shift, u32 mask, - u8 clk_mux_flags, u32 *table, spinlock_t *lock); - -void clk_unregister_mux(struct clk *clk); -void clk_hw_unregister_mux(struct clk_hw *hw); - -void of_fixed_factor_clk_setup(struct device_node *node); - -/** - * struct clk_fixed_factor - fixed multiplier and divider clock - * - * @hw: handle between common and hardware-specific interfaces - * @mult: multiplier - * @div: divider - * - * Clock with a fixed multiplier and divider. The output frequency is the - * parent clock rate divided by div and multiplied by mult. - * Implements .recalc_rate, .set_rate and .round_rate - */ - -struct clk_fixed_factor { - struct clk_hw hw; - unsigned int mult; - unsigned int div; -}; - -#define to_clk_fixed_factor(_hw) container_of(_hw, struct clk_fixed_factor, hw) - -extern const struct clk_ops clk_fixed_factor_ops; -struct clk *clk_register_fixed_factor(struct device *dev, const char *name, - const char *parent_name, unsigned long flags, - unsigned int mult, unsigned int div); -void clk_unregister_fixed_factor(struct clk *clk); -struct clk_hw *clk_hw_register_fixed_factor(struct device *dev, - const char *name, const char *parent_name, unsigned long flags, - unsigned int mult, unsigned int div); -void clk_hw_unregister_fixed_factor(struct clk_hw *hw); - -/** - * struct clk_fractional_divider - adjustable fractional divider clock - * - * @hw: handle between common and hardware-specific interfaces - * @reg: register containing the divider - * @mshift: shift to the numerator bit field - * @mwidth: width of the numerator bit field - * @nshift: shift to the denominator bit field - * @nwidth: width of the denominator bit field - * @lock: register lock - * - * Clock with adjustable fractional divider affecting its output frequency. - */ -struct clk_fractional_divider { - struct clk_hw hw; - void __iomem *reg; - u8 mshift; - u8 mwidth; - u32 mmask; - u8 nshift; - u8 nwidth; - u32 nmask; - u8 flags; - spinlock_t *lock; -}; - -#define to_clk_fd(_hw) container_of(_hw, struct clk_fractional_divider, hw) - -extern const struct clk_ops clk_fractional_divider_ops; -struct clk *clk_register_fractional_divider(struct device *dev, - const char *name, const char *parent_name, unsigned long flags, - void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth, - u8 clk_divider_flags, spinlock_t *lock); -struct clk_hw *clk_hw_register_fractional_divider(struct device *dev, - const char *name, const char *parent_name, unsigned long flags, - void __iomem *reg, u8 mshift, u8 mwidth, u8 nshift, u8 nwidth, - u8 clk_divider_flags, spinlock_t *lock); -void clk_hw_unregister_fractional_divider(struct clk_hw *hw); - -/** - * struct clk_multiplier - adjustable multiplier clock - * - * @hw: handle between common and hardware-specific interfaces - * @reg: register containing the multiplier - * @shift: shift to the multiplier bit field - * @width: width of the multiplier bit field - * @lock: register lock - * - * Clock with an adjustable multiplier affecting its output frequency. - * Implements .recalc_rate, .set_rate and .round_rate - * - * Flags: - * CLK_MULTIPLIER_ZERO_BYPASS - By default, the multiplier is the value read - * from the register, with 0 being a valid value effectively - * zeroing the output clock rate. If CLK_MULTIPLIER_ZERO_BYPASS is - * set, then a null multiplier will be considered as a bypass, - * leaving the parent rate unmodified. - * CLK_MULTIPLIER_ROUND_CLOSEST - Makes the best calculated divider to be - * rounded to the closest integer instead of the down one. - */ -struct clk_multiplier { - struct clk_hw hw; - void __iomem *reg; - u8 shift; - u8 width; - u8 flags; - spinlock_t *lock; -}; - -#define to_clk_multiplier(_hw) container_of(_hw, struct clk_multiplier, hw) - -#define CLK_MULTIPLIER_ZERO_BYPASS BIT(0) -#define CLK_MULTIPLIER_ROUND_CLOSEST BIT(1) - -extern const struct clk_ops clk_multiplier_ops; - -/*** - * struct clk_composite - aggregate clock of mux, divider and gate clocks - * - * @hw: handle between common and hardware-specific interfaces - * @mux_hw: handle between composite and hardware-specific mux clock - * @rate_hw: handle between composite and hardware-specific rate clock - * @gate_hw: handle between composite and hardware-specific gate clock - * @mux_ops: clock ops for mux - * @rate_ops: clock ops for rate - * @gate_ops: clock ops for gate - */ -struct clk_composite { - struct clk_hw hw; - struct clk_ops ops; - - struct clk_hw *mux_hw; - struct clk_hw *rate_hw; - struct clk_hw *gate_hw; - - const struct clk_ops *mux_ops; - const struct clk_ops *rate_ops; - const struct clk_ops *gate_ops; -}; - -#define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw) - -struct clk *clk_register_composite(struct device *dev, const char *name, - const char * const *parent_names, int num_parents, - struct clk_hw *mux_hw, const struct clk_ops *mux_ops, - struct clk_hw *rate_hw, const struct clk_ops *rate_ops, - struct clk_hw *gate_hw, const struct clk_ops *gate_ops, - unsigned long flags); -void clk_unregister_composite(struct clk *clk); -struct clk_hw *clk_hw_register_composite(struct device *dev, const char *name, - const char * const *parent_names, int num_parents, - struct clk_hw *mux_hw, const struct clk_ops *mux_ops, - struct clk_hw *rate_hw, const struct clk_ops *rate_ops, - struct clk_hw *gate_hw, const struct clk_ops *gate_ops, - unsigned long flags); -void clk_hw_unregister_composite(struct clk_hw *hw); - -/*** - * struct clk_gpio_gate - gpio gated clock - * - * @hw: handle between common and hardware-specific interfaces - * @gpiod: gpio descriptor - * - * Clock with a gpio control for enabling and disabling the parent clock. - * Implements .enable, .disable and .is_enabled - */ - -struct clk_gpio { - struct clk_hw hw; - struct gpio_desc *gpiod; -}; - -#define to_clk_gpio(_hw) container_of(_hw, struct clk_gpio, hw) - -extern const struct clk_ops clk_gpio_gate_ops; -struct clk *clk_register_gpio_gate(struct device *dev, const char *name, - const char *parent_name, unsigned gpio, bool active_low, - unsigned long flags); -struct clk_hw *clk_hw_register_gpio_gate(struct device *dev, const char *name, - const char *parent_name, unsigned gpio, bool active_low, - unsigned long flags); -void clk_hw_unregister_gpio_gate(struct clk_hw *hw); - -/** - * struct clk_gpio_mux - gpio controlled clock multiplexer - * - * @hw: see struct clk_gpio - * @gpiod: gpio descriptor to select the parent of this clock multiplexer - * - * Clock with a gpio control for selecting the parent clock. - * Implements .get_parent, .set_parent and .determine_rate - */ - -extern const struct clk_ops clk_gpio_mux_ops; -struct clk *clk_register_gpio_mux(struct device *dev, const char *name, - const char * const *parent_names, u8 num_parents, unsigned gpio, - bool active_low, unsigned long flags); -struct clk_hw *clk_hw_register_gpio_mux(struct device *dev, const char *name, - const char * const *parent_names, u8 num_parents, unsigned gpio, - bool active_low, unsigned long flags); -void clk_hw_unregister_gpio_mux(struct clk_hw *hw); - -/** - * clk_register - allocate a new clock, register it and return an opaque cookie - * @dev: device that is registering this clock - * @hw: link to hardware-specific clock data - * - * clk_register is the primary interface for populating the clock tree with new - * clock nodes. It returns a pointer to the newly allocated struct clk which - * cannot be dereferenced by driver code but may be used in conjuction with the - * rest of the clock API. In the event of an error clk_register will return an - * error code; drivers must test for an error code after calling clk_register. - */ -struct clk *clk_register(struct device *dev, struct clk_hw *hw); -struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw); - -int __must_check clk_hw_register(struct device *dev, struct clk_hw *hw); -int __must_check devm_clk_hw_register(struct device *dev, struct clk_hw *hw); - -void clk_unregister(struct clk *clk); -void devm_clk_unregister(struct device *dev, struct clk *clk); - -void clk_hw_unregister(struct clk_hw *hw); -void devm_clk_hw_unregister(struct device *dev, struct clk_hw *hw); - -/* helper functions */ -const char *__clk_get_name(const struct clk *clk); -const char *clk_hw_get_name(const struct clk_hw *hw); -struct clk_hw *__clk_get_hw(struct clk *clk); -unsigned int clk_hw_get_num_parents(const struct clk_hw *hw); -struct clk_hw *clk_hw_get_parent(const struct clk_hw *hw); -struct clk_hw *clk_hw_get_parent_by_index(const struct clk_hw *hw, - unsigned int index); -unsigned int __clk_get_enable_count(struct clk *clk); -unsigned long clk_hw_get_rate(const struct clk_hw *hw); -unsigned long __clk_get_flags(struct clk *clk); -unsigned long clk_hw_get_flags(const struct clk_hw *hw); -bool clk_hw_is_prepared(const struct clk_hw *hw); -bool clk_hw_is_enabled(const struct clk_hw *hw); -bool __clk_is_enabled(struct clk *clk); -struct clk *__clk_lookup(const char *name); -int __clk_mux_determine_rate(struct clk_hw *hw, - struct clk_rate_request *req); -int __clk_determine_rate(struct clk_hw *core, struct clk_rate_request *req); -int __clk_mux_determine_rate_closest(struct clk_hw *hw, - struct clk_rate_request *req); -void clk_hw_reparent(struct clk_hw *hw, struct clk_hw *new_parent); -void clk_hw_set_rate_range(struct clk_hw *hw, unsigned long min_rate, - unsigned long max_rate); - -static inline void __clk_hw_set_clk(struct clk_hw *dst, struct clk_hw *src) -{ - dst->clk = src->clk; - dst->core = src->core; -} - -/* - * FIXME clock api without lock protection - */ -unsigned long clk_hw_round_rate(struct clk_hw *hw, unsigned long rate); - -struct of_device_id; - -typedef void (*of_clk_init_cb_t)(struct device_node *); - -struct clk_onecell_data { - struct clk **clks; - unsigned int clk_num; -}; - -struct clk_hw_onecell_data { - unsigned int num; - struct clk_hw *hws[]; -}; - -extern struct of_device_id __clk_of_table; - -#define CLK_OF_DECLARE(name, compat, fn) OF_DECLARE_1(clk, name, compat, fn) - -/* - * Use this macro when you have a driver that requires two initialization - * routines, one at of_clk_init(), and one at platform device probe - */ -#define CLK_OF_DECLARE_DRIVER(name, compat, fn) \ - static void __init name##_of_clk_init_driver(struct device_node *np) \ - { \ - of_node_clear_flag(np, OF_POPULATED); \ - fn(np); \ - } \ - OF_DECLARE_1(clk, name, compat, name##_of_clk_init_driver) - -#ifdef CONFIG_OF -int of_clk_add_provider(struct device_node *np, - struct clk *(*clk_src_get)(struct of_phandle_args *args, - void *data), - void *data); -int of_clk_add_hw_provider(struct device_node *np, - struct clk_hw *(*get)(struct of_phandle_args *clkspec, - void *data), - void *data); -void of_clk_del_provider(struct device_node *np); -struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec, - void *data); -struct clk_hw *of_clk_hw_simple_get(struct of_phandle_args *clkspec, - void *data); -struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data); -struct clk_hw *of_clk_hw_onecell_get(struct of_phandle_args *clkspec, - void *data); -unsigned int of_clk_get_parent_count(struct device_node *np); -int of_clk_parent_fill(struct device_node *np, const char **parents, - unsigned int size); -const char *of_clk_get_parent_name(struct device_node *np, int index); -int of_clk_detect_critical(struct device_node *np, int index, - unsigned long *flags); -void of_clk_init(const struct of_device_id *matches); - -#else /* !CONFIG_OF */ - -static inline int of_clk_add_provider(struct device_node *np, - struct clk *(*clk_src_get)(struct of_phandle_args *args, - void *data), - void *data) -{ - return 0; -} -static inline int of_clk_add_hw_provider(struct device_node *np, - struct clk_hw *(*get)(struct of_phandle_args *clkspec, - void *data), - void *data) -{ - return 0; -} -static inline void of_clk_del_provider(struct device_node *np) {} -static inline struct clk *of_clk_src_simple_get( - struct of_phandle_args *clkspec, void *data) -{ - return ERR_PTR(-ENOENT); -} -static inline struct clk_hw * -of_clk_hw_simple_get(struct of_phandle_args *clkspec, void *data) -{ - return ERR_PTR(-ENOENT); -} -static inline struct clk *of_clk_src_onecell_get( - struct of_phandle_args *clkspec, void *data) -{ - return ERR_PTR(-ENOENT); -} -static inline struct clk_hw * -of_clk_hw_onecell_get(struct of_phandle_args *clkspec, void *data) -{ - return ERR_PTR(-ENOENT); -} -static inline unsigned int of_clk_get_parent_count(struct device_node *np) -{ - return 0; -} -static inline int of_clk_parent_fill(struct device_node *np, - const char **parents, unsigned int size) -{ - return 0; -} -static inline const char *of_clk_get_parent_name(struct device_node *np, - int index) -{ - return NULL; -} -static inline int of_clk_detect_critical(struct device_node *np, int index, - unsigned long *flags) -{ - return 0; -} -static inline void of_clk_init(const struct of_device_id *matches) {} -#endif /* CONFIG_OF */ - -/* - * wrap access to peripherals in accessor routines - * for improved portability across platforms - */ - -#if IS_ENABLED(CONFIG_PPC) - -static inline u32 clk_readl(u32 __iomem *reg) -{ - return ioread32be(reg); -} - -static inline void clk_writel(u32 val, u32 __iomem *reg) -{ - iowrite32be(val, reg); -} - -#else /* platform dependent I/O accessors */ - -static inline u32 clk_readl(u32 __iomem *reg) -{ - return readl(reg); -} - -static inline void clk_writel(u32 val, u32 __iomem *reg) -{ - writel(val, reg); -} - -#endif /* platform dependent I/O accessors */ - -#ifdef CONFIG_DEBUG_FS -struct dentry *clk_debugfs_add_file(struct clk_hw *hw, char *name, umode_t mode, - void *data, const struct file_operations *fops); -#endif - -#endif /* CONFIG_COMMON_CLK */ -#endif /* CLK_PROVIDER_H */ diff --git a/src/linux/include/linux/clk.h b/src/linux/include/linux/clk.h deleted file mode 100644 index 123c027..0000000 --- a/src/linux/include/linux/clk.h +++ /dev/null @@ -1,523 +0,0 @@ -/* - * linux/include/linux/clk.h - * - * Copyright (C) 2004 ARM Limited. - * Written by Deep Blue Solutions Limited. - * Copyright (C) 2011-2012 Linaro Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef __LINUX_CLK_H -#define __LINUX_CLK_H - -#include -#include -#include - -struct device; - -struct clk; - -/** - * DOC: clk notifier callback types - * - * PRE_RATE_CHANGE - called immediately before the clk rate is changed, - * to indicate that the rate change will proceed. Drivers must - * immediately terminate any operations that will be affected by the - * rate change. Callbacks may either return NOTIFY_DONE, NOTIFY_OK, - * NOTIFY_STOP or NOTIFY_BAD. - * - * ABORT_RATE_CHANGE: called if the rate change failed for some reason - * after PRE_RATE_CHANGE. In this case, all registered notifiers on - * the clk will be called with ABORT_RATE_CHANGE. Callbacks must - * always return NOTIFY_DONE or NOTIFY_OK. - * - * POST_RATE_CHANGE - called after the clk rate change has successfully - * completed. Callbacks must always return NOTIFY_DONE or NOTIFY_OK. - * - */ -#define PRE_RATE_CHANGE BIT(0) -#define POST_RATE_CHANGE BIT(1) -#define ABORT_RATE_CHANGE BIT(2) - -/** - * struct clk_notifier - associate a clk with a notifier - * @clk: struct clk * to associate the notifier with - * @notifier_head: a blocking_notifier_head for this clk - * @node: linked list pointers - * - * A list of struct clk_notifier is maintained by the notifier code. - * An entry is created whenever code registers the first notifier on a - * particular @clk. Future notifiers on that @clk are added to the - * @notifier_head. - */ -struct clk_notifier { - struct clk *clk; - struct srcu_notifier_head notifier_head; - struct list_head node; -}; - -/** - * struct clk_notifier_data - rate data to pass to the notifier callback - * @clk: struct clk * being changed - * @old_rate: previous rate of this clk - * @new_rate: new rate of this clk - * - * For a pre-notifier, old_rate is the clk's rate before this rate - * change, and new_rate is what the rate will be in the future. For a - * post-notifier, old_rate and new_rate are both set to the clk's - * current rate (this was done to optimize the implementation). - */ -struct clk_notifier_data { - struct clk *clk; - unsigned long old_rate; - unsigned long new_rate; -}; - -#ifdef CONFIG_COMMON_CLK - -/** - * clk_notifier_register: register a clock rate-change notifier callback - * @clk: clock whose rate we are interested in - * @nb: notifier block with callback function pointer - * - * ProTip: debugging across notifier chains can be frustrating. Make sure that - * your notifier callback function prints a nice big warning in case of - * failure. - */ -int clk_notifier_register(struct clk *clk, struct notifier_block *nb); - -/** - * clk_notifier_unregister: unregister a clock rate-change notifier callback - * @clk: clock whose rate we are no longer interested in - * @nb: notifier block which will be unregistered - */ -int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb); - -/** - * clk_get_accuracy - obtain the clock accuracy in ppb (parts per billion) - * for a clock source. - * @clk: clock source - * - * This gets the clock source accuracy expressed in ppb. - * A perfect clock returns 0. - */ -long clk_get_accuracy(struct clk *clk); - -/** - * clk_set_phase - adjust the phase shift of a clock signal - * @clk: clock signal source - * @degrees: number of degrees the signal is shifted - * - * Shifts the phase of a clock signal by the specified degrees. Returns 0 on - * success, -EERROR otherwise. - */ -int clk_set_phase(struct clk *clk, int degrees); - -/** - * clk_get_phase - return the phase shift of a clock signal - * @clk: clock signal source - * - * Returns the phase shift of a clock node in degrees, otherwise returns - * -EERROR. - */ -int clk_get_phase(struct clk *clk); - -/** - * clk_is_match - check if two clk's point to the same hardware clock - * @p: clk compared against q - * @q: clk compared against p - * - * Returns true if the two struct clk pointers both point to the same hardware - * clock node. Put differently, returns true if struct clk *p and struct clk *q - * share the same struct clk_core object. - * - * Returns false otherwise. Note that two NULL clks are treated as matching. - */ -bool clk_is_match(const struct clk *p, const struct clk *q); - -#else - -static inline int clk_notifier_register(struct clk *clk, - struct notifier_block *nb) -{ - return -ENOTSUPP; -} - -static inline int clk_notifier_unregister(struct clk *clk, - struct notifier_block *nb) -{ - return -ENOTSUPP; -} - -static inline long clk_get_accuracy(struct clk *clk) -{ - return -ENOTSUPP; -} - -static inline long clk_set_phase(struct clk *clk, int phase) -{ - return -ENOTSUPP; -} - -static inline long clk_get_phase(struct clk *clk) -{ - return -ENOTSUPP; -} - -static inline bool clk_is_match(const struct clk *p, const struct clk *q) -{ - return p == q; -} - -#endif - -/** - * clk_prepare - prepare a clock source - * @clk: clock source - * - * This prepares the clock source for use. - * - * Must not be called from within atomic context. - */ -#ifdef CONFIG_HAVE_CLK_PREPARE -int clk_prepare(struct clk *clk); -#else -static inline int clk_prepare(struct clk *clk) -{ - might_sleep(); - return 0; -} -#endif - -/** - * clk_unprepare - undo preparation of a clock source - * @clk: clock source - * - * This undoes a previously prepared clock. The caller must balance - * the number of prepare and unprepare calls. - * - * Must not be called from within atomic context. - */ -#ifdef CONFIG_HAVE_CLK_PREPARE -void clk_unprepare(struct clk *clk); -#else -static inline void clk_unprepare(struct clk *clk) -{ - might_sleep(); -} -#endif - -#ifdef CONFIG_HAVE_CLK -/** - * clk_get - lookup and obtain a reference to a clock producer. - * @dev: device for clock "consumer" - * @id: clock consumer ID - * - * Returns a struct clk corresponding to the clock producer, or - * valid IS_ERR() condition containing errno. The implementation - * uses @dev and @id to determine the clock consumer, and thereby - * the clock producer. (IOW, @id may be identical strings, but - * clk_get may return different clock producers depending on @dev.) - * - * Drivers must assume that the clock source is not enabled. - * - * clk_get should not be called from within interrupt context. - */ -struct clk *clk_get(struct device *dev, const char *id); - -/** - * devm_clk_get - lookup and obtain a managed reference to a clock producer. - * @dev: device for clock "consumer" - * @id: clock consumer ID - * - * Returns a struct clk corresponding to the clock producer, or - * valid IS_ERR() condition containing errno. The implementation - * uses @dev and @id to determine the clock consumer, and thereby - * the clock producer. (IOW, @id may be identical strings, but - * clk_get may return different clock producers depending on @dev.) - * - * Drivers must assume that the clock source is not enabled. - * - * devm_clk_get should not be called from within interrupt context. - * - * The clock will automatically be freed when the device is unbound - * from the bus. - */ -struct clk *devm_clk_get(struct device *dev, const char *id); - -/** - * clk_enable - inform the system when the clock source should be running. - * @clk: clock source - * - * If the clock can not be enabled/disabled, this should return success. - * - * May be called from atomic contexts. - * - * Returns success (0) or negative errno. - */ -int clk_enable(struct clk *clk); - -/** - * clk_disable - inform the system when the clock source is no longer required. - * @clk: clock source - * - * Inform the system that a clock source is no longer required by - * a driver and may be shut down. - * - * May be called from atomic contexts. - * - * Implementation detail: if the clock source is shared between - * multiple drivers, clk_enable() calls must be balanced by the - * same number of clk_disable() calls for the clock source to be - * disabled. - */ -void clk_disable(struct clk *clk); - -/** - * clk_get_rate - obtain the current clock rate (in Hz) for a clock source. - * This is only valid once the clock source has been enabled. - * @clk: clock source - */ -unsigned long clk_get_rate(struct clk *clk); - -/** - * clk_put - "free" the clock source - * @clk: clock source - * - * Note: drivers must ensure that all clk_enable calls made on this - * clock source are balanced by clk_disable calls prior to calling - * this function. - * - * clk_put should not be called from within interrupt context. - */ -void clk_put(struct clk *clk); - -/** - * devm_clk_put - "free" a managed clock source - * @dev: device used to acquire the clock - * @clk: clock source acquired with devm_clk_get() - * - * Note: drivers must ensure that all clk_enable calls made on this - * clock source are balanced by clk_disable calls prior to calling - * this function. - * - * clk_put should not be called from within interrupt context. - */ -void devm_clk_put(struct device *dev, struct clk *clk); - -/* - * The remaining APIs are optional for machine class support. - */ - - -/** - * clk_round_rate - adjust a rate to the exact rate a clock can provide - * @clk: clock source - * @rate: desired clock rate in Hz - * - * This answers the question "if I were to pass @rate to clk_set_rate(), - * what clock rate would I end up with?" without changing the hardware - * in any way. In other words: - * - * rate = clk_round_rate(clk, r); - * - * and: - * - * clk_set_rate(clk, r); - * rate = clk_get_rate(clk); - * - * are equivalent except the former does not modify the clock hardware - * in any way. - * - * Returns rounded clock rate in Hz, or negative errno. - */ -long clk_round_rate(struct clk *clk, unsigned long rate); - -/** - * clk_set_rate - set the clock rate for a clock source - * @clk: clock source - * @rate: desired clock rate in Hz - * - * Returns success (0) or negative errno. - */ -int clk_set_rate(struct clk *clk, unsigned long rate); - -/** - * clk_has_parent - check if a clock is a possible parent for another - * @clk: clock source - * @parent: parent clock source - * - * This function can be used in drivers that need to check that a clock can be - * the parent of another without actually changing the parent. - * - * Returns true if @parent is a possible parent for @clk, false otherwise. - */ -bool clk_has_parent(struct clk *clk, struct clk *parent); - -/** - * clk_set_rate_range - set a rate range for a clock source - * @clk: clock source - * @min: desired minimum clock rate in Hz, inclusive - * @max: desired maximum clock rate in Hz, inclusive - * - * Returns success (0) or negative errno. - */ -int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max); - -/** - * clk_set_min_rate - set a minimum clock rate for a clock source - * @clk: clock source - * @rate: desired minimum clock rate in Hz, inclusive - * - * Returns success (0) or negative errno. - */ -int clk_set_min_rate(struct clk *clk, unsigned long rate); - -/** - * clk_set_max_rate - set a maximum clock rate for a clock source - * @clk: clock source - * @rate: desired maximum clock rate in Hz, inclusive - * - * Returns success (0) or negative errno. - */ -int clk_set_max_rate(struct clk *clk, unsigned long rate); - -/** - * clk_set_parent - set the parent clock source for this clock - * @clk: clock source - * @parent: parent clock source - * - * Returns success (0) or negative errno. - */ -int clk_set_parent(struct clk *clk, struct clk *parent); - -/** - * clk_get_parent - get the parent clock source for this clock - * @clk: clock source - * - * Returns struct clk corresponding to parent clock source, or - * valid IS_ERR() condition containing errno. - */ -struct clk *clk_get_parent(struct clk *clk); - -/** - * clk_get_sys - get a clock based upon the device name - * @dev_id: device name - * @con_id: connection ID - * - * Returns a struct clk corresponding to the clock producer, or - * valid IS_ERR() condition containing errno. The implementation - * uses @dev_id and @con_id to determine the clock consumer, and - * thereby the clock producer. In contrast to clk_get() this function - * takes the device name instead of the device itself for identification. - * - * Drivers must assume that the clock source is not enabled. - * - * clk_get_sys should not be called from within interrupt context. - */ -struct clk *clk_get_sys(const char *dev_id, const char *con_id); - -#else /* !CONFIG_HAVE_CLK */ - -static inline struct clk *clk_get(struct device *dev, const char *id) -{ - return NULL; -} - -static inline struct clk *devm_clk_get(struct device *dev, const char *id) -{ - return NULL; -} - -static inline void clk_put(struct clk *clk) {} - -static inline void devm_clk_put(struct device *dev, struct clk *clk) {} - -static inline int clk_enable(struct clk *clk) -{ - return 0; -} - -static inline void clk_disable(struct clk *clk) {} - -static inline unsigned long clk_get_rate(struct clk *clk) -{ - return 0; -} - -static inline int clk_set_rate(struct clk *clk, unsigned long rate) -{ - return 0; -} - -static inline long clk_round_rate(struct clk *clk, unsigned long rate) -{ - return 0; -} - -static inline bool clk_has_parent(struct clk *clk, struct clk *parent) -{ - return true; -} - -static inline int clk_set_parent(struct clk *clk, struct clk *parent) -{ - return 0; -} - -static inline struct clk *clk_get_parent(struct clk *clk) -{ - return NULL; -} - -static inline struct clk *clk_get_sys(const char *dev_id, const char *con_id) -{ - return NULL; -} -#endif - -/* clk_prepare_enable helps cases using clk_enable in non-atomic context. */ -static inline int clk_prepare_enable(struct clk *clk) -{ - int ret; - - ret = clk_prepare(clk); - if (ret) - return ret; - ret = clk_enable(clk); - if (ret) - clk_unprepare(clk); - - return ret; -} - -/* clk_disable_unprepare helps cases using clk_disable in non-atomic context. */ -static inline void clk_disable_unprepare(struct clk *clk) -{ - clk_disable(clk); - clk_unprepare(clk); -} - -struct device_node; -struct of_phandle_args; - -#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) -struct clk *of_clk_get(struct device_node *np, int index); -struct clk *of_clk_get_by_name(struct device_node *np, const char *name); -struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec); -#else -static inline struct clk *of_clk_get(struct device_node *np, int index) -{ - return ERR_PTR(-ENOENT); -} -static inline struct clk *of_clk_get_by_name(struct device_node *np, - const char *name) -{ - return ERR_PTR(-ENOENT); -} -#endif - -#endif diff --git a/src/linux/include/linux/clk/clk-conf.h b/src/linux/include/linux/clk/clk-conf.h deleted file mode 100644 index e0c3623..0000000 --- a/src/linux/include/linux/clk/clk-conf.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2014 Samsung Electronics Co., Ltd. - * Sylwester Nawrocki - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include - -struct device_node; - -#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) -int of_clk_set_defaults(struct device_node *node, bool clk_supplier); -#else -static inline int of_clk_set_defaults(struct device_node *node, - bool clk_supplier) -{ - return 0; -} -#endif diff --git a/src/linux/include/linux/clockchips.h b/src/linux/include/linux/clockchips.h deleted file mode 100644 index 0d442e3..0000000 --- a/src/linux/include/linux/clockchips.h +++ /dev/null @@ -1,227 +0,0 @@ -/* linux/include/linux/clockchips.h - * - * This file contains the structure definitions for clockchips. - * - * If you are not a clockchip, or the time of day code, you should - * not be including this file! - */ -#ifndef _LINUX_CLOCKCHIPS_H -#define _LINUX_CLOCKCHIPS_H - -#ifdef CONFIG_GENERIC_CLOCKEVENTS - -# include -# include -# include -# include - -struct clock_event_device; -struct module; - -/* - * Possible states of a clock event device. - * - * DETACHED: Device is not used by clockevents core. Initial state or can be - * reached from SHUTDOWN. - * SHUTDOWN: Device is powered-off. Can be reached from PERIODIC or ONESHOT. - * PERIODIC: Device is programmed to generate events periodically. Can be - * reached from DETACHED or SHUTDOWN. - * ONESHOT: Device is programmed to generate event only once. Can be reached - * from DETACHED or SHUTDOWN. - * ONESHOT_STOPPED: Device was programmed in ONESHOT mode and is temporarily - * stopped. - */ -enum clock_event_state { - CLOCK_EVT_STATE_DETACHED, - CLOCK_EVT_STATE_SHUTDOWN, - CLOCK_EVT_STATE_PERIODIC, - CLOCK_EVT_STATE_ONESHOT, - CLOCK_EVT_STATE_ONESHOT_STOPPED, -}; - -/* - * Clock event features - */ -# define CLOCK_EVT_FEAT_PERIODIC 0x000001 -# define CLOCK_EVT_FEAT_ONESHOT 0x000002 -# define CLOCK_EVT_FEAT_KTIME 0x000004 - -/* - * x86(64) specific (mis)features: - * - * - Clockevent source stops in C3 State and needs broadcast support. - * - Local APIC timer is used as a dummy device. - */ -# define CLOCK_EVT_FEAT_C3STOP 0x000008 -# define CLOCK_EVT_FEAT_DUMMY 0x000010 - -/* - * Core shall set the interrupt affinity dynamically in broadcast mode - */ -# define CLOCK_EVT_FEAT_DYNIRQ 0x000020 -# define CLOCK_EVT_FEAT_PERCPU 0x000040 - -/* - * Clockevent device is based on a hrtimer for broadcast - */ -# define CLOCK_EVT_FEAT_HRTIMER 0x000080 - -/** - * struct clock_event_device - clock event device descriptor - * @event_handler: Assigned by the framework to be called by the low - * level handler of the event source - * @set_next_event: set next event function using a clocksource delta - * @set_next_ktime: set next event function using a direct ktime value - * @next_event: local storage for the next event in oneshot mode - * @max_delta_ns: maximum delta value in ns - * @min_delta_ns: minimum delta value in ns - * @mult: nanosecond to cycles multiplier - * @shift: nanoseconds to cycles divisor (power of two) - * @state_use_accessors:current state of the device, assigned by the core code - * @features: features - * @retries: number of forced programming retries - * @set_state_periodic: switch state to periodic - * @set_state_oneshot: switch state to oneshot - * @set_state_oneshot_stopped: switch state to oneshot_stopped - * @set_state_shutdown: switch state to shutdown - * @tick_resume: resume clkevt device - * @broadcast: function to broadcast events - * @min_delta_ticks: minimum delta value in ticks stored for reconfiguration - * @max_delta_ticks: maximum delta value in ticks stored for reconfiguration - * @name: ptr to clock event name - * @rating: variable to rate clock event devices - * @irq: IRQ number (only for non CPU local devices) - * @bound_on: Bound on CPU - * @cpumask: cpumask to indicate for which CPUs this device works - * @list: list head for the management code - * @owner: module reference - */ -struct clock_event_device { - void (*event_handler)(struct clock_event_device *); - int (*set_next_event)(unsigned long evt, struct clock_event_device *); - int (*set_next_ktime)(ktime_t expires, struct clock_event_device *); - ktime_t next_event; - u64 max_delta_ns; - u64 min_delta_ns; - u32 mult; - u32 shift; - enum clock_event_state state_use_accessors; - unsigned int features; - unsigned long retries; - - int (*set_state_periodic)(struct clock_event_device *); - int (*set_state_oneshot)(struct clock_event_device *); - int (*set_state_oneshot_stopped)(struct clock_event_device *); - int (*set_state_shutdown)(struct clock_event_device *); - int (*tick_resume)(struct clock_event_device *); - - void (*broadcast)(const struct cpumask *mask); - void (*suspend)(struct clock_event_device *); - void (*resume)(struct clock_event_device *); - unsigned long min_delta_ticks; - unsigned long max_delta_ticks; - - const char *name; - int rating; - int irq; - int bound_on; - const struct cpumask *cpumask; - struct list_head list; - struct module *owner; -} ____cacheline_aligned; - -/* Helpers to verify state of a clockevent device */ -static inline bool clockevent_state_detached(struct clock_event_device *dev) -{ - return dev->state_use_accessors == CLOCK_EVT_STATE_DETACHED; -} - -static inline bool clockevent_state_shutdown(struct clock_event_device *dev) -{ - return dev->state_use_accessors == CLOCK_EVT_STATE_SHUTDOWN; -} - -static inline bool clockevent_state_periodic(struct clock_event_device *dev) -{ - return dev->state_use_accessors == CLOCK_EVT_STATE_PERIODIC; -} - -static inline bool clockevent_state_oneshot(struct clock_event_device *dev) -{ - return dev->state_use_accessors == CLOCK_EVT_STATE_ONESHOT; -} - -static inline bool clockevent_state_oneshot_stopped(struct clock_event_device *dev) -{ - return dev->state_use_accessors == CLOCK_EVT_STATE_ONESHOT_STOPPED; -} - -/* - * Calculate a multiplication factor for scaled math, which is used to convert - * nanoseconds based values to clock ticks: - * - * clock_ticks = (nanoseconds * factor) >> shift. - * - * div_sc is the rearranged equation to calculate a factor from a given clock - * ticks / nanoseconds ratio: - * - * factor = (clock_ticks << shift) / nanoseconds - */ -static inline unsigned long -div_sc(unsigned long ticks, unsigned long nsec, int shift) -{ - u64 tmp = ((u64)ticks) << shift; - - do_div(tmp, nsec); - - return (unsigned long) tmp; -} - -/* Clock event layer functions */ -extern u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt); -extern void clockevents_register_device(struct clock_event_device *dev); -extern int clockevents_unbind_device(struct clock_event_device *ced, int cpu); - -extern void clockevents_config(struct clock_event_device *dev, u32 freq); -extern void clockevents_config_and_register(struct clock_event_device *dev, - u32 freq, unsigned long min_delta, - unsigned long max_delta); - -extern int clockevents_update_freq(struct clock_event_device *ce, u32 freq); - -static inline void -clockevents_calc_mult_shift(struct clock_event_device *ce, u32 freq, u32 maxsec) -{ - return clocks_calc_mult_shift(&ce->mult, &ce->shift, NSEC_PER_SEC, freq, maxsec); -} - -extern void clockevents_suspend(void); -extern void clockevents_resume(void); - -# ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST -# ifdef CONFIG_ARCH_HAS_TICK_BROADCAST -extern void tick_broadcast(const struct cpumask *mask); -# else -# define tick_broadcast NULL -# endif -extern int tick_receive_broadcast(void); -# endif - -# if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_TICK_ONESHOT) -extern void tick_setup_hrtimer_broadcast(void); -extern int tick_check_broadcast_expired(void); -# else -static inline int tick_check_broadcast_expired(void) { return 0; } -static inline void tick_setup_hrtimer_broadcast(void) { } -# endif - -#else /* !CONFIG_GENERIC_CLOCKEVENTS: */ - -static inline void clockevents_suspend(void) { } -static inline void clockevents_resume(void) { } -static inline int tick_check_broadcast_expired(void) { return 0; } -static inline void tick_setup_hrtimer_broadcast(void) { } - -#endif /* !CONFIG_GENERIC_CLOCKEVENTS */ - -#endif /* _LINUX_CLOCKCHIPS_H */ diff --git a/src/linux/include/linux/clocksource.h b/src/linux/include/linux/clocksource.h deleted file mode 100644 index 0839818..0000000 --- a/src/linux/include/linux/clocksource.h +++ /dev/null @@ -1,258 +0,0 @@ -/* linux/include/linux/clocksource.h - * - * This file contains the structure definitions for clocksources. - * - * If you are not a clocksource, or timekeeping code, you should - * not be including this file! - */ -#ifndef _LINUX_CLOCKSOURCE_H -#define _LINUX_CLOCKSOURCE_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct clocksource; -struct module; - -#ifdef CONFIG_ARCH_CLOCKSOURCE_DATA -#include -#endif - -/** - * struct clocksource - hardware abstraction for a free running counter - * Provides mostly state-free accessors to the underlying hardware. - * This is the structure used for system time. - * - * @name: ptr to clocksource name - * @list: list head for registration - * @rating: rating value for selection (higher is better) - * To avoid rating inflation the following - * list should give you a guide as to how - * to assign your clocksource a rating - * 1-99: Unfit for real use - * Only available for bootup and testing purposes. - * 100-199: Base level usability. - * Functional for real use, but not desired. - * 200-299: Good. - * A correct and usable clocksource. - * 300-399: Desired. - * A reasonably fast and accurate clocksource. - * 400-499: Perfect - * The ideal clocksource. A must-use where - * available. - * @read: returns a cycle value, passes clocksource as argument - * @enable: optional function to enable the clocksource - * @disable: optional function to disable the clocksource - * @mask: bitmask for two's complement - * subtraction of non 64 bit counters - * @mult: cycle to nanosecond multiplier - * @shift: cycle to nanosecond divisor (power of two) - * @max_idle_ns: max idle time permitted by the clocksource (nsecs) - * @maxadj: maximum adjustment value to mult (~11%) - * @max_cycles: maximum safe cycle value which won't overflow on multiplication - * @flags: flags describing special properties - * @archdata: arch-specific data - * @suspend: suspend function for the clocksource, if necessary - * @resume: resume function for the clocksource, if necessary - * @owner: module reference, must be set by clocksource in modules - * - * Note: This struct is not used in hotpathes of the timekeeping code - * because the timekeeper caches the hot path fields in its own data - * structure, so no line cache alignment is required, - * - * The pointer to the clocksource itself is handed to the read - * callback. If you need extra information there you can wrap struct - * clocksource into your own struct. Depending on the amount of - * information you need you should consider to cache line align that - * structure. - */ -struct clocksource { - cycle_t (*read)(struct clocksource *cs); - cycle_t mask; - u32 mult; - u32 shift; - u64 max_idle_ns; - u32 maxadj; -#ifdef CONFIG_ARCH_CLOCKSOURCE_DATA - struct arch_clocksource_data archdata; -#endif - u64 max_cycles; - const char *name; - struct list_head list; - int rating; - int (*enable)(struct clocksource *cs); - void (*disable)(struct clocksource *cs); - unsigned long flags; - void (*suspend)(struct clocksource *cs); - void (*resume)(struct clocksource *cs); - - /* private: */ -#ifdef CONFIG_CLOCKSOURCE_WATCHDOG - /* Watchdog related data, used by the framework */ - struct list_head wd_list; - cycle_t cs_last; - cycle_t wd_last; -#endif - struct module *owner; -}; - -/* - * Clock source flags bits:: - */ -#define CLOCK_SOURCE_IS_CONTINUOUS 0x01 -#define CLOCK_SOURCE_MUST_VERIFY 0x02 - -#define CLOCK_SOURCE_WATCHDOG 0x10 -#define CLOCK_SOURCE_VALID_FOR_HRES 0x20 -#define CLOCK_SOURCE_UNSTABLE 0x40 -#define CLOCK_SOURCE_SUSPEND_NONSTOP 0x80 -#define CLOCK_SOURCE_RESELECT 0x100 - -/* simplify initialization of mask field */ -#define CLOCKSOURCE_MASK(bits) (cycle_t)((bits) < 64 ? ((1ULL<<(bits))-1) : -1) - -static inline u32 clocksource_freq2mult(u32 freq, u32 shift_constant, u64 from) -{ - /* freq = cyc/from - * mult/2^shift = ns/cyc - * mult = ns/cyc * 2^shift - * mult = from/freq * 2^shift - * mult = from * 2^shift / freq - * mult = (from<> shift; -} - - -extern int clocksource_unregister(struct clocksource*); -extern void clocksource_touch_watchdog(void); -extern void clocksource_change_rating(struct clocksource *cs, int rating); -extern void clocksource_suspend(void); -extern void clocksource_resume(void); -extern struct clocksource * __init clocksource_default_clock(void); -extern void clocksource_mark_unstable(struct clocksource *cs); - -extern u64 -clocks_calc_max_nsecs(u32 mult, u32 shift, u32 maxadj, u64 mask, u64 *max_cycles); -extern void -clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 minsec); - -/* - * Don't call __clocksource_register_scale directly, use - * clocksource_register_hz/khz - */ -extern int -__clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq); -extern void -__clocksource_update_freq_scale(struct clocksource *cs, u32 scale, u32 freq); - -/* - * Don't call this unless you are a default clocksource - * (AKA: jiffies) and absolutely have to. - */ -static inline int __clocksource_register(struct clocksource *cs) -{ - return __clocksource_register_scale(cs, 1, 0); -} - -static inline int clocksource_register_hz(struct clocksource *cs, u32 hz) -{ - return __clocksource_register_scale(cs, 1, hz); -} - -static inline int clocksource_register_khz(struct clocksource *cs, u32 khz) -{ - return __clocksource_register_scale(cs, 1000, khz); -} - -static inline void __clocksource_update_freq_hz(struct clocksource *cs, u32 hz) -{ - __clocksource_update_freq_scale(cs, 1, hz); -} - -static inline void __clocksource_update_freq_khz(struct clocksource *cs, u32 khz) -{ - __clocksource_update_freq_scale(cs, 1000, khz); -} - - -extern int timekeeping_notify(struct clocksource *clock); - -extern cycle_t clocksource_mmio_readl_up(struct clocksource *); -extern cycle_t clocksource_mmio_readl_down(struct clocksource *); -extern cycle_t clocksource_mmio_readw_up(struct clocksource *); -extern cycle_t clocksource_mmio_readw_down(struct clocksource *); - -extern int clocksource_mmio_init(void __iomem *, const char *, - unsigned long, int, unsigned, cycle_t (*)(struct clocksource *)); - -extern int clocksource_i8253_init(void); - -#define CLOCKSOURCE_OF_DECLARE(name, compat, fn) \ - OF_DECLARE_1_RET(clksrc, name, compat, fn) - -#ifdef CONFIG_CLKSRC_PROBE -extern void clocksource_probe(void); -#else -static inline void clocksource_probe(void) {} -#endif - -#define CLOCKSOURCE_ACPI_DECLARE(name, table_id, fn) \ - ACPI_DECLARE_PROBE_ENTRY(clksrc, name, table_id, 0, NULL, 0, fn) - -#endif /* _LINUX_CLOCKSOURCE_H */ diff --git a/src/linux/include/linux/cma.h b/src/linux/include/linux/cma.h deleted file mode 100644 index 29f9e77..0000000 --- a/src/linux/include/linux/cma.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef __CMA_H__ -#define __CMA_H__ - -/* - * There is always at least global CMA area and a few optional - * areas configured in kernel .config. - */ -#ifdef CONFIG_CMA_AREAS -#define MAX_CMA_AREAS (1 + CONFIG_CMA_AREAS) - -#else -#define MAX_CMA_AREAS (0) - -#endif - -struct cma; - -extern unsigned long totalcma_pages; -extern phys_addr_t cma_get_base(const struct cma *cma); -extern unsigned long cma_get_size(const struct cma *cma); - -extern int __init cma_declare_contiguous(phys_addr_t base, - phys_addr_t size, phys_addr_t limit, - phys_addr_t alignment, unsigned int order_per_bit, - bool fixed, struct cma **res_cma); -extern int cma_init_reserved_mem(phys_addr_t base, phys_addr_t size, - unsigned int order_per_bit, - struct cma **res_cma); -extern struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align); -extern bool cma_release(struct cma *cma, const struct page *pages, unsigned int count); -#endif diff --git a/src/linux/include/linux/cn_proc.h b/src/linux/include/linux/cn_proc.h deleted file mode 100644 index 1d5b02a..0000000 --- a/src/linux/include/linux/cn_proc.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * cn_proc.h - process events connector - * - * Copyright (C) Matt Helsley, IBM Corp. 2005 - * Based on cn_fork.h by Nguyen Anh Quynh and Guillaume Thouvenin - * Copyright (C) 2005 Nguyen Anh Quynh - * Copyright (C) 2005 Guillaume Thouvenin - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ -#ifndef CN_PROC_H -#define CN_PROC_H - -#include - -#ifdef CONFIG_PROC_EVENTS -void proc_fork_connector(struct task_struct *task); -void proc_exec_connector(struct task_struct *task); -void proc_id_connector(struct task_struct *task, int which_id); -void proc_sid_connector(struct task_struct *task); -void proc_ptrace_connector(struct task_struct *task, int which_id); -void proc_comm_connector(struct task_struct *task); -void proc_coredump_connector(struct task_struct *task); -void proc_exit_connector(struct task_struct *task); -#else -static inline void proc_fork_connector(struct task_struct *task) -{} - -static inline void proc_exec_connector(struct task_struct *task) -{} - -static inline void proc_id_connector(struct task_struct *task, - int which_id) -{} - -static inline void proc_sid_connector(struct task_struct *task) -{} - -static inline void proc_comm_connector(struct task_struct *task) -{} - -static inline void proc_ptrace_connector(struct task_struct *task, - int ptrace_id) -{} - -static inline void proc_coredump_connector(struct task_struct *task) -{} - -static inline void proc_exit_connector(struct task_struct *task) -{} -#endif /* CONFIG_PROC_EVENTS */ -#endif /* CN_PROC_H */ diff --git a/src/linux/include/linux/compaction.h b/src/linux/include/linux/compaction.h deleted file mode 100644 index 0d84158..0000000 --- a/src/linux/include/linux/compaction.h +++ /dev/null @@ -1,246 +0,0 @@ -#ifndef _LINUX_COMPACTION_H -#define _LINUX_COMPACTION_H - -/* - * Determines how hard direct compaction should try to succeed. - * Lower value means higher priority, analogically to reclaim priority. - */ -enum compact_priority { - COMPACT_PRIO_SYNC_FULL, - MIN_COMPACT_PRIORITY = COMPACT_PRIO_SYNC_FULL, - COMPACT_PRIO_SYNC_LIGHT, - MIN_COMPACT_COSTLY_PRIORITY = COMPACT_PRIO_SYNC_LIGHT, - DEF_COMPACT_PRIORITY = COMPACT_PRIO_SYNC_LIGHT, - COMPACT_PRIO_ASYNC, - INIT_COMPACT_PRIORITY = COMPACT_PRIO_ASYNC -}; - -/* Return values for compact_zone() and try_to_compact_pages() */ -/* When adding new states, please adjust include/trace/events/compaction.h */ -enum compact_result { - /* For more detailed tracepoint output - internal to compaction */ - COMPACT_NOT_SUITABLE_ZONE, - /* - * compaction didn't start as it was not possible or direct reclaim - * was more suitable - */ - COMPACT_SKIPPED, - /* compaction didn't start as it was deferred due to past failures */ - COMPACT_DEFERRED, - - /* compaction not active last round */ - COMPACT_INACTIVE = COMPACT_DEFERRED, - - /* For more detailed tracepoint output - internal to compaction */ - COMPACT_NO_SUITABLE_PAGE, - /* compaction should continue to another pageblock */ - COMPACT_CONTINUE, - - /* - * The full zone was compacted scanned but wasn't successfull to compact - * suitable pages. - */ - COMPACT_COMPLETE, - /* - * direct compaction has scanned part of the zone but wasn't successfull - * to compact suitable pages. - */ - COMPACT_PARTIAL_SKIPPED, - - /* compaction terminated prematurely due to lock contentions */ - COMPACT_CONTENDED, - - /* - * direct compaction terminated after concluding that the allocation - * should now succeed - */ - COMPACT_SUCCESS, -}; - -struct alloc_context; /* in mm/internal.h */ - -/* - * Number of free order-0 pages that should be available above given watermark - * to make sure compaction has reasonable chance of not running out of free - * pages that it needs to isolate as migration target during its work. - */ -static inline unsigned long compact_gap(unsigned int order) -{ - /* - * Although all the isolations for migration are temporary, compaction - * free scanner may have up to 1 << order pages on its list and then - * try to split an (order - 1) free page. At that point, a gap of - * 1 << order might not be enough, so it's safer to require twice that - * amount. Note that the number of pages on the list is also - * effectively limited by COMPACT_CLUSTER_MAX, as that's the maximum - * that the migrate scanner can have isolated on migrate list, and free - * scanner is only invoked when the number of isolated free pages is - * lower than that. But it's not worth to complicate the formula here - * as a bigger gap for higher orders than strictly necessary can also - * improve chances of compaction success. - */ - return 2UL << order; -} - -#ifdef CONFIG_COMPACTION -extern int sysctl_compact_memory; -extern int sysctl_compaction_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *length, loff_t *ppos); -extern int sysctl_extfrag_threshold; -extern int sysctl_extfrag_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *length, loff_t *ppos); -extern int sysctl_compact_unevictable_allowed; - -extern int fragmentation_index(struct zone *zone, unsigned int order); -extern enum compact_result try_to_compact_pages(gfp_t gfp_mask, - unsigned int order, unsigned int alloc_flags, - const struct alloc_context *ac, enum compact_priority prio); -extern void reset_isolation_suitable(pg_data_t *pgdat); -extern enum compact_result compaction_suitable(struct zone *zone, int order, - unsigned int alloc_flags, int classzone_idx); - -extern void defer_compaction(struct zone *zone, int order); -extern bool compaction_deferred(struct zone *zone, int order); -extern void compaction_defer_reset(struct zone *zone, int order, - bool alloc_success); -extern bool compaction_restarting(struct zone *zone, int order); - -/* Compaction has made some progress and retrying makes sense */ -static inline bool compaction_made_progress(enum compact_result result) -{ - /* - * Even though this might sound confusing this in fact tells us - * that the compaction successfully isolated and migrated some - * pageblocks. - */ - if (result == COMPACT_SUCCESS) - return true; - - return false; -} - -/* Compaction has failed and it doesn't make much sense to keep retrying. */ -static inline bool compaction_failed(enum compact_result result) -{ - /* All zones were scanned completely and still not result. */ - if (result == COMPACT_COMPLETE) - return true; - - return false; -} - -/* - * Compaction has backed off for some reason. It might be throttling or - * lock contention. Retrying is still worthwhile. - */ -static inline bool compaction_withdrawn(enum compact_result result) -{ - /* - * Compaction backed off due to watermark checks for order-0 - * so the regular reclaim has to try harder and reclaim something. - */ - if (result == COMPACT_SKIPPED) - return true; - - /* - * If compaction is deferred for high-order allocations, it is - * because sync compaction recently failed. If this is the case - * and the caller requested a THP allocation, we do not want - * to heavily disrupt the system, so we fail the allocation - * instead of entering direct reclaim. - */ - if (result == COMPACT_DEFERRED) - return true; - - /* - * If compaction in async mode encounters contention or blocks higher - * priority task we back off early rather than cause stalls. - */ - if (result == COMPACT_CONTENDED) - return true; - - /* - * Page scanners have met but we haven't scanned full zones so this - * is a back off in fact. - */ - if (result == COMPACT_PARTIAL_SKIPPED) - return true; - - return false; -} - - -bool compaction_zonelist_suitable(struct alloc_context *ac, int order, - int alloc_flags); - -extern int kcompactd_run(int nid); -extern void kcompactd_stop(int nid); -extern void wakeup_kcompactd(pg_data_t *pgdat, int order, int classzone_idx); - -#else -static inline void reset_isolation_suitable(pg_data_t *pgdat) -{ -} - -static inline enum compact_result compaction_suitable(struct zone *zone, int order, - int alloc_flags, int classzone_idx) -{ - return COMPACT_SKIPPED; -} - -static inline void defer_compaction(struct zone *zone, int order) -{ -} - -static inline bool compaction_deferred(struct zone *zone, int order) -{ - return true; -} - -static inline bool compaction_made_progress(enum compact_result result) -{ - return false; -} - -static inline bool compaction_failed(enum compact_result result) -{ - return false; -} - -static inline bool compaction_withdrawn(enum compact_result result) -{ - return true; -} - -static inline int kcompactd_run(int nid) -{ - return 0; -} -static inline void kcompactd_stop(int nid) -{ -} - -static inline void wakeup_kcompactd(pg_data_t *pgdat, int order, int classzone_idx) -{ -} - -#endif /* CONFIG_COMPACTION */ - -#if defined(CONFIG_COMPACTION) && defined(CONFIG_SYSFS) && defined(CONFIG_NUMA) -struct node; -extern int compaction_register_node(struct node *node); -extern void compaction_unregister_node(struct node *node); - -#else - -static inline int compaction_register_node(struct node *node) -{ - return 0; -} - -static inline void compaction_unregister_node(struct node *node) -{ -} -#endif /* CONFIG_COMPACTION && CONFIG_SYSFS && CONFIG_NUMA */ - -#endif /* _LINUX_COMPACTION_H */ diff --git a/src/linux/include/linux/compat.h b/src/linux/include/linux/compat.h deleted file mode 100644 index 6360939..0000000 --- a/src/linux/include/linux/compat.h +++ /dev/null @@ -1,741 +0,0 @@ -#ifndef _LINUX_COMPAT_H -#define _LINUX_COMPAT_H -/* - * These are the type definitions for the architecture specific - * syscall compatibility layer. - */ - -#include - -#ifdef CONFIG_COMPAT - -#include -#include /* for HZ */ -#include -#include -#include -#include -#include /* for aio_context_t */ -#include - -#include -#include -#include - -#ifndef COMPAT_USE_64BIT_TIME -#define COMPAT_USE_64BIT_TIME 0 -#endif - -#ifndef __SC_DELOUSE -#define __SC_DELOUSE(t,v) ((t)(unsigned long)(v)) -#endif - -#define COMPAT_SYSCALL_DEFINE0(name) \ - asmlinkage long compat_sys_##name(void) - -#define COMPAT_SYSCALL_DEFINE1(name, ...) \ - COMPAT_SYSCALL_DEFINEx(1, _##name, __VA_ARGS__) -#define COMPAT_SYSCALL_DEFINE2(name, ...) \ - COMPAT_SYSCALL_DEFINEx(2, _##name, __VA_ARGS__) -#define COMPAT_SYSCALL_DEFINE3(name, ...) \ - COMPAT_SYSCALL_DEFINEx(3, _##name, __VA_ARGS__) -#define COMPAT_SYSCALL_DEFINE4(name, ...) \ - COMPAT_SYSCALL_DEFINEx(4, _##name, __VA_ARGS__) -#define COMPAT_SYSCALL_DEFINE5(name, ...) \ - COMPAT_SYSCALL_DEFINEx(5, _##name, __VA_ARGS__) -#define COMPAT_SYSCALL_DEFINE6(name, ...) \ - COMPAT_SYSCALL_DEFINEx(6, _##name, __VA_ARGS__) - -#define COMPAT_SYSCALL_DEFINEx(x, name, ...) \ - asmlinkage long compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))\ - __attribute__((alias(__stringify(compat_SyS##name)))); \ - static inline long C_SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ - asmlinkage long compat_SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__));\ - asmlinkage long compat_SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__))\ - { \ - return C_SYSC##name(__MAP(x,__SC_DELOUSE,__VA_ARGS__)); \ - } \ - static inline long C_SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)) - -#ifndef compat_user_stack_pointer -#define compat_user_stack_pointer() current_user_stack_pointer() -#endif -#ifndef compat_sigaltstack /* we'll need that for MIPS */ -typedef struct compat_sigaltstack { - compat_uptr_t ss_sp; - int ss_flags; - compat_size_t ss_size; -} compat_stack_t; -#endif - -#define compat_jiffies_to_clock_t(x) \ - (((unsigned long)(x) * COMPAT_USER_HZ) / HZ) - -typedef __compat_uid32_t compat_uid_t; -typedef __compat_gid32_t compat_gid_t; - -typedef compat_ulong_t compat_aio_context_t; - -struct compat_sel_arg_struct; -struct rusage; - -struct compat_itimerspec { - struct compat_timespec it_interval; - struct compat_timespec it_value; -}; - -struct compat_utimbuf { - compat_time_t actime; - compat_time_t modtime; -}; - -struct compat_itimerval { - struct compat_timeval it_interval; - struct compat_timeval it_value; -}; - -struct compat_tms { - compat_clock_t tms_utime; - compat_clock_t tms_stime; - compat_clock_t tms_cutime; - compat_clock_t tms_cstime; -}; - -struct compat_timex { - compat_uint_t modes; - compat_long_t offset; - compat_long_t freq; - compat_long_t maxerror; - compat_long_t esterror; - compat_int_t status; - compat_long_t constant; - compat_long_t precision; - compat_long_t tolerance; - struct compat_timeval time; - compat_long_t tick; - compat_long_t ppsfreq; - compat_long_t jitter; - compat_int_t shift; - compat_long_t stabil; - compat_long_t jitcnt; - compat_long_t calcnt; - compat_long_t errcnt; - compat_long_t stbcnt; - compat_int_t tai; - - compat_int_t:32; compat_int_t:32; compat_int_t:32; compat_int_t:32; - compat_int_t:32; compat_int_t:32; compat_int_t:32; compat_int_t:32; - compat_int_t:32; compat_int_t:32; compat_int_t:32; -}; - -#define _COMPAT_NSIG_WORDS (_COMPAT_NSIG / _COMPAT_NSIG_BPW) - -typedef struct { - compat_sigset_word sig[_COMPAT_NSIG_WORDS]; -} compat_sigset_t; - -struct compat_sigaction { -#ifndef __ARCH_HAS_IRIX_SIGACTION - compat_uptr_t sa_handler; - compat_ulong_t sa_flags; -#else - compat_uint_t sa_flags; - compat_uptr_t sa_handler; -#endif -#ifdef __ARCH_HAS_SA_RESTORER - compat_uptr_t sa_restorer; -#endif - compat_sigset_t sa_mask __packed; -}; - -/* - * These functions operate on 32- or 64-bit specs depending on - * COMPAT_USE_64BIT_TIME, hence the void user pointer arguments. - */ -extern int compat_get_timespec(struct timespec *, const void __user *); -extern int compat_put_timespec(const struct timespec *, void __user *); -extern int compat_get_timeval(struct timeval *, const void __user *); -extern int compat_put_timeval(const struct timeval *, void __user *); - -/* - * This function convert a timespec if necessary and returns a *user - * space* pointer. If no conversion is necessary, it returns the - * initial pointer. NULL is a legitimate argument and will always - * output NULL. - */ -extern int compat_convert_timespec(struct timespec __user **, - const void __user *); - -struct compat_iovec { - compat_uptr_t iov_base; - compat_size_t iov_len; -}; - -struct compat_rlimit { - compat_ulong_t rlim_cur; - compat_ulong_t rlim_max; -}; - -struct compat_rusage { - struct compat_timeval ru_utime; - struct compat_timeval ru_stime; - compat_long_t ru_maxrss; - compat_long_t ru_ixrss; - compat_long_t ru_idrss; - compat_long_t ru_isrss; - compat_long_t ru_minflt; - compat_long_t ru_majflt; - compat_long_t ru_nswap; - compat_long_t ru_inblock; - compat_long_t ru_oublock; - compat_long_t ru_msgsnd; - compat_long_t ru_msgrcv; - compat_long_t ru_nsignals; - compat_long_t ru_nvcsw; - compat_long_t ru_nivcsw; -}; - -extern int put_compat_rusage(const struct rusage *, - struct compat_rusage __user *); - -struct compat_siginfo; - -extern asmlinkage long compat_sys_waitid(int, compat_pid_t, - struct compat_siginfo __user *, int, - struct compat_rusage __user *); - -struct compat_dirent { - u32 d_ino; - compat_off_t d_off; - u16 d_reclen; - char d_name[256]; -}; - -struct compat_ustat { - compat_daddr_t f_tfree; - compat_ino_t f_tinode; - char f_fname[6]; - char f_fpack[6]; -}; - -#define COMPAT_SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE/sizeof(int)) - 3) - -typedef struct compat_sigevent { - compat_sigval_t sigev_value; - compat_int_t sigev_signo; - compat_int_t sigev_notify; - union { - compat_int_t _pad[COMPAT_SIGEV_PAD_SIZE]; - compat_int_t _tid; - - struct { - compat_uptr_t _function; - compat_uptr_t _attribute; - } _sigev_thread; - } _sigev_un; -} compat_sigevent_t; - -struct compat_ifmap { - compat_ulong_t mem_start; - compat_ulong_t mem_end; - unsigned short base_addr; - unsigned char irq; - unsigned char dma; - unsigned char port; -}; - -struct compat_if_settings { - unsigned int type; /* Type of physical device or protocol */ - unsigned int size; /* Size of the data allocated by the caller */ - compat_uptr_t ifs_ifsu; /* union of pointers */ -}; - -struct compat_ifreq { - union { - char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - } ifr_ifrn; - union { - struct sockaddr ifru_addr; - struct sockaddr ifru_dstaddr; - struct sockaddr ifru_broadaddr; - struct sockaddr ifru_netmask; - struct sockaddr ifru_hwaddr; - short ifru_flags; - compat_int_t ifru_ivalue; - compat_int_t ifru_mtu; - struct compat_ifmap ifru_map; - char ifru_slave[IFNAMSIZ]; /* Just fits the size */ - char ifru_newname[IFNAMSIZ]; - compat_caddr_t ifru_data; - struct compat_if_settings ifru_settings; - } ifr_ifru; -}; - -struct compat_ifconf { - compat_int_t ifc_len; /* size of buffer */ - compat_caddr_t ifcbuf; -}; - -struct compat_robust_list { - compat_uptr_t next; -}; - -struct compat_robust_list_head { - struct compat_robust_list list; - compat_long_t futex_offset; - compat_uptr_t list_op_pending; -}; - -#ifdef CONFIG_COMPAT_OLD_SIGACTION -struct compat_old_sigaction { - compat_uptr_t sa_handler; - compat_old_sigset_t sa_mask; - compat_ulong_t sa_flags; - compat_uptr_t sa_restorer; -}; -#endif - -struct compat_statfs; -struct compat_statfs64; -struct compat_old_linux_dirent; -struct compat_linux_dirent; -struct linux_dirent64; -struct compat_msghdr; -struct compat_mmsghdr; -struct compat_sysinfo; -struct compat_sysctl_args; -struct compat_kexec_segment; -struct compat_mq_attr; -struct compat_msgbuf; - -extern void compat_exit_robust_list(struct task_struct *curr); - -asmlinkage long -compat_sys_set_robust_list(struct compat_robust_list_head __user *head, - compat_size_t len); -asmlinkage long -compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr, - compat_size_t __user *len_ptr); - -asmlinkage long compat_sys_ipc(u32, int, int, u32, compat_uptr_t, u32); -asmlinkage long compat_sys_shmat(int shmid, compat_uptr_t shmaddr, int shmflg); -asmlinkage long compat_sys_semctl(int semid, int semnum, int cmd, int arg); -asmlinkage long compat_sys_msgsnd(int msqid, compat_uptr_t msgp, - compat_ssize_t msgsz, int msgflg); -asmlinkage long compat_sys_msgrcv(int msqid, compat_uptr_t msgp, - compat_ssize_t msgsz, compat_long_t msgtyp, int msgflg); -long compat_sys_msgctl(int first, int second, void __user *uptr); -long compat_sys_shmctl(int first, int second, void __user *uptr); -long compat_sys_semtimedop(int semid, struct sembuf __user *tsems, - unsigned nsems, const struct compat_timespec __user *timeout); -asmlinkage long compat_sys_keyctl(u32 option, - u32 arg2, u32 arg3, u32 arg4, u32 arg5); -asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u32); - -asmlinkage ssize_t compat_sys_readv(compat_ulong_t fd, - const struct compat_iovec __user *vec, compat_ulong_t vlen); -asmlinkage ssize_t compat_sys_writev(compat_ulong_t fd, - const struct compat_iovec __user *vec, compat_ulong_t vlen); -asmlinkage ssize_t compat_sys_preadv(compat_ulong_t fd, - const struct compat_iovec __user *vec, - compat_ulong_t vlen, u32 pos_low, u32 pos_high); -asmlinkage ssize_t compat_sys_pwritev(compat_ulong_t fd, - const struct compat_iovec __user *vec, - compat_ulong_t vlen, u32 pos_low, u32 pos_high); -asmlinkage ssize_t compat_sys_preadv2(compat_ulong_t fd, - const struct compat_iovec __user *vec, - compat_ulong_t vlen, u32 pos_low, u32 pos_high, int flags); -asmlinkage ssize_t compat_sys_pwritev2(compat_ulong_t fd, - const struct compat_iovec __user *vec, - compat_ulong_t vlen, u32 pos_low, u32 pos_high, int flags); - -#ifdef __ARCH_WANT_COMPAT_SYS_PREADV64 -asmlinkage long compat_sys_preadv64(unsigned long fd, - const struct compat_iovec __user *vec, - unsigned long vlen, loff_t pos); -#endif - -#ifdef __ARCH_WANT_COMPAT_SYS_PWRITEV64 -asmlinkage long compat_sys_pwritev64(unsigned long fd, - const struct compat_iovec __user *vec, - unsigned long vlen, loff_t pos); -#endif - -asmlinkage long compat_sys_lseek(unsigned int, compat_off_t, unsigned int); - -asmlinkage long compat_sys_execve(const char __user *filename, const compat_uptr_t __user *argv, - const compat_uptr_t __user *envp); -asmlinkage long compat_sys_execveat(int dfd, const char __user *filename, - const compat_uptr_t __user *argv, - const compat_uptr_t __user *envp, int flags); - -asmlinkage long compat_sys_select(int n, compat_ulong_t __user *inp, - compat_ulong_t __user *outp, compat_ulong_t __user *exp, - struct compat_timeval __user *tvp); - -asmlinkage long compat_sys_old_select(struct compat_sel_arg_struct __user *arg); - -asmlinkage long compat_sys_wait4(compat_pid_t pid, - compat_uint_t __user *stat_addr, int options, - struct compat_rusage __user *ru); - -#define BITS_PER_COMPAT_LONG (8*sizeof(compat_long_t)) - -#define BITS_TO_COMPAT_LONGS(bits) \ - (((bits)+BITS_PER_COMPAT_LONG-1)/BITS_PER_COMPAT_LONG) - -long compat_get_bitmap(unsigned long *mask, const compat_ulong_t __user *umask, - unsigned long bitmap_size); -long compat_put_bitmap(compat_ulong_t __user *umask, unsigned long *mask, - unsigned long bitmap_size); -int copy_siginfo_from_user32(siginfo_t *to, struct compat_siginfo __user *from); -int copy_siginfo_to_user32(struct compat_siginfo __user *to, const siginfo_t *from); -int get_compat_sigevent(struct sigevent *event, - const struct compat_sigevent __user *u_event); -long compat_sys_rt_tgsigqueueinfo(compat_pid_t tgid, compat_pid_t pid, int sig, - struct compat_siginfo __user *uinfo); -#ifdef CONFIG_COMPAT_OLD_SIGACTION -asmlinkage long compat_sys_sigaction(int sig, - const struct compat_old_sigaction __user *act, - struct compat_old_sigaction __user *oact); -#endif - -static inline int compat_timeval_compare(struct compat_timeval *lhs, - struct compat_timeval *rhs) -{ - if (lhs->tv_sec < rhs->tv_sec) - return -1; - if (lhs->tv_sec > rhs->tv_sec) - return 1; - return lhs->tv_usec - rhs->tv_usec; -} - -static inline int compat_timespec_compare(struct compat_timespec *lhs, - struct compat_timespec *rhs) -{ - if (lhs->tv_sec < rhs->tv_sec) - return -1; - if (lhs->tv_sec > rhs->tv_sec) - return 1; - return lhs->tv_nsec - rhs->tv_nsec; -} - -extern int get_compat_itimerspec(struct itimerspec *dst, - const struct compat_itimerspec __user *src); -extern int put_compat_itimerspec(struct compat_itimerspec __user *dst, - const struct itimerspec *src); - -asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv, - struct timezone __user *tz); -asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, - struct timezone __user *tz); - -asmlinkage long compat_sys_adjtimex(struct compat_timex __user *utp); - -extern void sigset_from_compat(sigset_t *set, const compat_sigset_t *compat); -extern void sigset_to_compat(compat_sigset_t *compat, const sigset_t *set); - -asmlinkage long compat_sys_migrate_pages(compat_pid_t pid, - compat_ulong_t maxnode, const compat_ulong_t __user *old_nodes, - const compat_ulong_t __user *new_nodes); - -extern int compat_ptrace_request(struct task_struct *child, - compat_long_t request, - compat_ulong_t addr, compat_ulong_t data); - -extern long compat_arch_ptrace(struct task_struct *child, compat_long_t request, - compat_ulong_t addr, compat_ulong_t data); -asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid, - compat_long_t addr, compat_long_t data); - -asmlinkage long compat_sys_lookup_dcookie(u32, u32, char __user *, compat_size_t); -/* - * epoll (fs/eventpoll.c) compat bits follow ... - */ -struct epoll_event; /* fortunately, this one is fixed-layout */ -asmlinkage long compat_sys_epoll_pwait(int epfd, - struct epoll_event __user *events, - int maxevents, int timeout, - const compat_sigset_t __user *sigmask, - compat_size_t sigsetsize); - -asmlinkage long compat_sys_utime(const char __user *filename, - struct compat_utimbuf __user *t); -asmlinkage long compat_sys_utimensat(unsigned int dfd, - const char __user *filename, - struct compat_timespec __user *t, - int flags); - -asmlinkage long compat_sys_time(compat_time_t __user *tloc); -asmlinkage long compat_sys_stime(compat_time_t __user *tptr); -asmlinkage long compat_sys_signalfd(int ufd, - const compat_sigset_t __user *sigmask, - compat_size_t sigsetsize); -asmlinkage long compat_sys_timerfd_settime(int ufd, int flags, - const struct compat_itimerspec __user *utmr, - struct compat_itimerspec __user *otmr); -asmlinkage long compat_sys_timerfd_gettime(int ufd, - struct compat_itimerspec __user *otmr); - -asmlinkage long compat_sys_move_pages(pid_t pid, compat_ulong_t nr_pages, - __u32 __user *pages, - const int __user *nodes, - int __user *status, - int flags); -asmlinkage long compat_sys_futimesat(unsigned int dfd, - const char __user *filename, - struct compat_timeval __user *t); -asmlinkage long compat_sys_utimes(const char __user *filename, - struct compat_timeval __user *t); -asmlinkage long compat_sys_newstat(const char __user *filename, - struct compat_stat __user *statbuf); -asmlinkage long compat_sys_newlstat(const char __user *filename, - struct compat_stat __user *statbuf); -asmlinkage long compat_sys_newfstatat(unsigned int dfd, - const char __user *filename, - struct compat_stat __user *statbuf, - int flag); -asmlinkage long compat_sys_newfstat(unsigned int fd, - struct compat_stat __user *statbuf); -asmlinkage long compat_sys_statfs(const char __user *pathname, - struct compat_statfs __user *buf); -asmlinkage long compat_sys_fstatfs(unsigned int fd, - struct compat_statfs __user *buf); -asmlinkage long compat_sys_statfs64(const char __user *pathname, - compat_size_t sz, - struct compat_statfs64 __user *buf); -asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, - struct compat_statfs64 __user *buf); -asmlinkage long compat_sys_fcntl64(unsigned int fd, unsigned int cmd, - compat_ulong_t arg); -asmlinkage long compat_sys_fcntl(unsigned int fd, unsigned int cmd, - compat_ulong_t arg); -asmlinkage long compat_sys_io_setup(unsigned nr_reqs, u32 __user *ctx32p); -asmlinkage long compat_sys_io_getevents(compat_aio_context_t ctx_id, - compat_long_t min_nr, - compat_long_t nr, - struct io_event __user *events, - struct compat_timespec __user *timeout); -asmlinkage long compat_sys_io_submit(compat_aio_context_t ctx_id, int nr, - u32 __user *iocb); -asmlinkage long compat_sys_mount(const char __user *dev_name, - const char __user *dir_name, - const char __user *type, compat_ulong_t flags, - const void __user *data); -asmlinkage long compat_sys_old_readdir(unsigned int fd, - struct compat_old_linux_dirent __user *, - unsigned int count); -asmlinkage long compat_sys_getdents(unsigned int fd, - struct compat_linux_dirent __user *dirent, - unsigned int count); -#ifdef __ARCH_WANT_COMPAT_SYS_GETDENTS64 -asmlinkage long compat_sys_getdents64(unsigned int fd, - struct linux_dirent64 __user *dirent, - unsigned int count); -#endif -asmlinkage long compat_sys_vmsplice(int fd, const struct compat_iovec __user *, - unsigned int nr_segs, unsigned int flags); -asmlinkage long compat_sys_open(const char __user *filename, int flags, - umode_t mode); -asmlinkage long compat_sys_openat(int dfd, const char __user *filename, - int flags, umode_t mode); -asmlinkage long compat_sys_open_by_handle_at(int mountdirfd, - struct file_handle __user *handle, - int flags); -asmlinkage long compat_sys_truncate(const char __user *, compat_off_t); -asmlinkage long compat_sys_ftruncate(unsigned int, compat_ulong_t); -asmlinkage long compat_sys_pselect6(int n, compat_ulong_t __user *inp, - compat_ulong_t __user *outp, - compat_ulong_t __user *exp, - struct compat_timespec __user *tsp, - void __user *sig); -asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds, - unsigned int nfds, - struct compat_timespec __user *tsp, - const compat_sigset_t __user *sigmask, - compat_size_t sigsetsize); -asmlinkage long compat_sys_signalfd4(int ufd, - const compat_sigset_t __user *sigmask, - compat_size_t sigsetsize, int flags); -asmlinkage long compat_sys_get_mempolicy(int __user *policy, - compat_ulong_t __user *nmask, - compat_ulong_t maxnode, - compat_ulong_t addr, - compat_ulong_t flags); -asmlinkage long compat_sys_set_mempolicy(int mode, compat_ulong_t __user *nmask, - compat_ulong_t maxnode); -asmlinkage long compat_sys_mbind(compat_ulong_t start, compat_ulong_t len, - compat_ulong_t mode, - compat_ulong_t __user *nmask, - compat_ulong_t maxnode, compat_ulong_t flags); - -asmlinkage long compat_sys_setsockopt(int fd, int level, int optname, - char __user *optval, unsigned int optlen); -asmlinkage long compat_sys_sendmsg(int fd, struct compat_msghdr __user *msg, - unsigned flags); -asmlinkage long compat_sys_sendmmsg(int fd, struct compat_mmsghdr __user *mmsg, - unsigned vlen, unsigned int flags); -asmlinkage long compat_sys_recvmsg(int fd, struct compat_msghdr __user *msg, - unsigned int flags); -asmlinkage long compat_sys_recv(int fd, void __user *buf, compat_size_t len, - unsigned flags); -asmlinkage long compat_sys_recvfrom(int fd, void __user *buf, compat_size_t len, - unsigned flags, struct sockaddr __user *addr, - int __user *addrlen); -asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg, - unsigned vlen, unsigned int flags, - struct compat_timespec __user *timeout); -asmlinkage long compat_sys_nanosleep(struct compat_timespec __user *rqtp, - struct compat_timespec __user *rmtp); -asmlinkage long compat_sys_getitimer(int which, - struct compat_itimerval __user *it); -asmlinkage long compat_sys_setitimer(int which, - struct compat_itimerval __user *in, - struct compat_itimerval __user *out); -asmlinkage long compat_sys_times(struct compat_tms __user *tbuf); -asmlinkage long compat_sys_setrlimit(unsigned int resource, - struct compat_rlimit __user *rlim); -asmlinkage long compat_sys_getrlimit(unsigned int resource, - struct compat_rlimit __user *rlim); -asmlinkage long compat_sys_getrusage(int who, struct compat_rusage __user *ru); -asmlinkage long compat_sys_sched_setaffinity(compat_pid_t pid, - unsigned int len, - compat_ulong_t __user *user_mask_ptr); -asmlinkage long compat_sys_sched_getaffinity(compat_pid_t pid, - unsigned int len, - compat_ulong_t __user *user_mask_ptr); -asmlinkage long compat_sys_timer_create(clockid_t which_clock, - struct compat_sigevent __user *timer_event_spec, - timer_t __user *created_timer_id); -asmlinkage long compat_sys_timer_settime(timer_t timer_id, int flags, - struct compat_itimerspec __user *new, - struct compat_itimerspec __user *old); -asmlinkage long compat_sys_timer_gettime(timer_t timer_id, - struct compat_itimerspec __user *setting); -asmlinkage long compat_sys_clock_settime(clockid_t which_clock, - struct compat_timespec __user *tp); -asmlinkage long compat_sys_clock_gettime(clockid_t which_clock, - struct compat_timespec __user *tp); -asmlinkage long compat_sys_clock_adjtime(clockid_t which_clock, - struct compat_timex __user *tp); -asmlinkage long compat_sys_clock_getres(clockid_t which_clock, - struct compat_timespec __user *tp); -asmlinkage long compat_sys_clock_nanosleep(clockid_t which_clock, int flags, - struct compat_timespec __user *rqtp, - struct compat_timespec __user *rmtp); -asmlinkage long compat_sys_rt_sigtimedwait(compat_sigset_t __user *uthese, - struct compat_siginfo __user *uinfo, - struct compat_timespec __user *uts, compat_size_t sigsetsize); -asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, - compat_size_t sigsetsize); -asmlinkage long compat_sys_rt_sigprocmask(int how, compat_sigset_t __user *set, - compat_sigset_t __user *oset, - compat_size_t sigsetsize); -asmlinkage long compat_sys_rt_sigpending(compat_sigset_t __user *uset, - compat_size_t sigsetsize); -#ifndef CONFIG_ODD_RT_SIGACTION -asmlinkage long compat_sys_rt_sigaction(int, - const struct compat_sigaction __user *, - struct compat_sigaction __user *, - compat_size_t); -#endif -asmlinkage long compat_sys_rt_sigqueueinfo(compat_pid_t pid, int sig, - struct compat_siginfo __user *uinfo); -asmlinkage long compat_sys_sysinfo(struct compat_sysinfo __user *info); -asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, - compat_ulong_t arg); -asmlinkage long compat_sys_futex(u32 __user *uaddr, int op, u32 val, - struct compat_timespec __user *utime, u32 __user *uaddr2, - u32 val3); -asmlinkage long compat_sys_getsockopt(int fd, int level, int optname, - char __user *optval, int __user *optlen); -asmlinkage long compat_sys_kexec_load(compat_ulong_t entry, - compat_ulong_t nr_segments, - struct compat_kexec_segment __user *, - compat_ulong_t flags); -asmlinkage long compat_sys_mq_getsetattr(mqd_t mqdes, - const struct compat_mq_attr __user *u_mqstat, - struct compat_mq_attr __user *u_omqstat); -asmlinkage long compat_sys_mq_notify(mqd_t mqdes, - const struct compat_sigevent __user *u_notification); -asmlinkage long compat_sys_mq_open(const char __user *u_name, - int oflag, compat_mode_t mode, - struct compat_mq_attr __user *u_attr); -asmlinkage long compat_sys_mq_timedsend(mqd_t mqdes, - const char __user *u_msg_ptr, - compat_size_t msg_len, unsigned int msg_prio, - const struct compat_timespec __user *u_abs_timeout); -asmlinkage ssize_t compat_sys_mq_timedreceive(mqd_t mqdes, - char __user *u_msg_ptr, - compat_size_t msg_len, unsigned int __user *u_msg_prio, - const struct compat_timespec __user *u_abs_timeout); -asmlinkage long compat_sys_socketcall(int call, u32 __user *args); -asmlinkage long compat_sys_sysctl(struct compat_sysctl_args __user *args); - -extern ssize_t compat_rw_copy_check_uvector(int type, - const struct compat_iovec __user *uvector, - unsigned long nr_segs, - unsigned long fast_segs, struct iovec *fast_pointer, - struct iovec **ret_pointer); - -extern void __user *compat_alloc_user_space(unsigned long len); - -asmlinkage ssize_t compat_sys_process_vm_readv(compat_pid_t pid, - const struct compat_iovec __user *lvec, - compat_ulong_t liovcnt, const struct compat_iovec __user *rvec, - compat_ulong_t riovcnt, compat_ulong_t flags); -asmlinkage ssize_t compat_sys_process_vm_writev(compat_pid_t pid, - const struct compat_iovec __user *lvec, - compat_ulong_t liovcnt, const struct compat_iovec __user *rvec, - compat_ulong_t riovcnt, compat_ulong_t flags); - -asmlinkage long compat_sys_sendfile(int out_fd, int in_fd, - compat_off_t __user *offset, compat_size_t count); -asmlinkage long compat_sys_sendfile64(int out_fd, int in_fd, - compat_loff_t __user *offset, compat_size_t count); -asmlinkage long compat_sys_sigaltstack(const compat_stack_t __user *uss_ptr, - compat_stack_t __user *uoss_ptr); - -#ifdef __ARCH_WANT_SYS_SIGPENDING -asmlinkage long compat_sys_sigpending(compat_old_sigset_t __user *set); -#endif - -#ifdef __ARCH_WANT_SYS_SIGPROCMASK -asmlinkage long compat_sys_sigprocmask(int how, compat_old_sigset_t __user *nset, - compat_old_sigset_t __user *oset); -#endif - -int compat_restore_altstack(const compat_stack_t __user *uss); -int __compat_save_altstack(compat_stack_t __user *, unsigned long); -#define compat_save_altstack_ex(uss, sp) do { \ - compat_stack_t __user *__uss = uss; \ - struct task_struct *t = current; \ - put_user_ex(ptr_to_compat((void __user *)t->sas_ss_sp), &__uss->ss_sp); \ - put_user_ex(sas_ss_flags(sp), &__uss->ss_flags); \ - put_user_ex(t->sas_ss_size, &__uss->ss_size); \ -} while (0); - -asmlinkage long compat_sys_sched_rr_get_interval(compat_pid_t pid, - struct compat_timespec __user *interval); - -asmlinkage long compat_sys_fanotify_mark(int, unsigned int, __u32, __u32, - int, const char __user *); - -/* - * For most but not all architectures, "am I in a compat syscall?" and - * "am I a compat task?" are the same question. For architectures on which - * they aren't the same question, arch code can override in_compat_syscall. - */ - -#ifndef in_compat_syscall -static inline bool in_compat_syscall(void) { return is_compat_task(); } -#endif - -#else - -#define is_compat_task() (0) -static inline bool in_compat_syscall(void) { return false; } - -#endif /* CONFIG_COMPAT */ - -#endif /* _LINUX_COMPAT_H */ diff --git a/src/linux/include/linux/compiler-gcc.h b/src/linux/include/linux/compiler-gcc.h deleted file mode 100644 index 60c9e6c..0000000 --- a/src/linux/include/linux/compiler-gcc.h +++ /dev/null @@ -1,301 +0,0 @@ -#ifndef __LINUX_COMPILER_H -#error "Please don't include directly, include instead." -#endif - -/* - * Common definitions for all gcc versions go here. - */ -#define GCC_VERSION (__GNUC__ * 10000 \ - + __GNUC_MINOR__ * 100 \ - + __GNUC_PATCHLEVEL__) - -/* Optimization barrier */ - -/* The "volatile" is due to gcc bugs */ -#define barrier() __asm__ __volatile__("": : :"memory") -/* - * This version is i.e. to prevent dead stores elimination on @ptr - * where gcc and llvm may behave differently when otherwise using - * normal barrier(): while gcc behavior gets along with a normal - * barrier(), llvm needs an explicit input variable to be assumed - * clobbered. The issue is as follows: while the inline asm might - * access any memory it wants, the compiler could have fit all of - * @ptr into memory registers instead, and since @ptr never escaped - * from that, it proofed that the inline asm wasn't touching any of - * it. This version works well with both compilers, i.e. we're telling - * the compiler that the inline asm absolutely may see the contents - * of @ptr. See also: https://llvm.org/bugs/show_bug.cgi?id=15495 - */ -#define barrier_data(ptr) __asm__ __volatile__("": :"r"(ptr) :"memory") - -/* - * This macro obfuscates arithmetic on a variable address so that gcc - * shouldn't recognize the original var, and make assumptions about it. - * - * This is needed because the C standard makes it undefined to do - * pointer arithmetic on "objects" outside their boundaries and the - * gcc optimizers assume this is the case. In particular they - * assume such arithmetic does not wrap. - * - * A miscompilation has been observed because of this on PPC. - * To work around it we hide the relationship of the pointer and the object - * using this macro. - * - * Versions of the ppc64 compiler before 4.1 had a bug where use of - * RELOC_HIDE could trash r30. The bug can be worked around by changing - * the inline assembly constraint from =g to =r, in this particular - * case either is valid. - */ -#define RELOC_HIDE(ptr, off) \ -({ \ - unsigned long __ptr; \ - __asm__ ("" : "=r"(__ptr) : "0"(ptr)); \ - (typeof(ptr)) (__ptr + (off)); \ -}) - -/* Make the optimizer believe the variable can be manipulated arbitrarily. */ -#define OPTIMIZER_HIDE_VAR(var) \ - __asm__ ("" : "=r" (var) : "0" (var)) - -#ifdef __CHECKER__ -#define __must_be_array(a) 0 -#else -/* &a[0] degrades to a pointer: a different type from an array */ -#define __must_be_array(a) BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0])) -#endif - -/* - * Force always-inline if the user requests it so via the .config, - * or if gcc is too old: - */ -#if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) || \ - !defined(CONFIG_OPTIMIZE_INLINING) || (__GNUC__ < 4) -#define inline inline __attribute__((always_inline)) notrace -#define __inline__ __inline__ __attribute__((always_inline)) notrace -#define __inline __inline __attribute__((always_inline)) notrace -#else -/* A lot of inline functions can cause havoc with function tracing */ -#define inline inline notrace -#define __inline__ __inline__ notrace -#define __inline __inline notrace -#endif - -#define __always_inline inline __attribute__((always_inline)) -#define noinline __attribute__((noinline)) - -#define __deprecated __attribute__((deprecated)) -#define __packed __attribute__((packed)) -#define __weak __attribute__((weak)) -#define __alias(symbol) __attribute__((alias(#symbol))) - -/* - * it doesn't make sense on ARM (currently the only user of __naked) - * to trace naked functions because then mcount is called without - * stack and frame pointer being set up and there is no chance to - * restore the lr register to the value before mcount was called. - * - * The asm() bodies of naked functions often depend on standard calling - * conventions, therefore they must be noinline and noclone. - * - * GCC 4.[56] currently fail to enforce this, so we must do so ourselves. - * See GCC PR44290. - */ -#define __naked __attribute__((naked)) noinline __noclone notrace - -#define __noreturn __attribute__((noreturn)) - -/* - * From the GCC manual: - * - * Many functions have no effects except the return value and their - * return value depends only on the parameters and/or global - * variables. Such a function can be subject to common subexpression - * elimination and loop optimization just as an arithmetic operator - * would be. - * [...] - */ -#define __pure __attribute__((pure)) -#define __aligned(x) __attribute__((aligned(x))) -#ifdef __MINGW32__ -#define __printf(a, b) __attribute__((format(gnu_printf, a, b))) -#else -#define __printf(a, b) __attribute__((format(printf, a, b))) -#endif -#define __scanf(a, b) __attribute__((format(scanf, a, b))) -#define __attribute_const__ __attribute__((__const__)) -#define __maybe_unused __attribute__((unused)) -#define __always_unused __attribute__((unused)) - -/* gcc version specific checks */ - -#if GCC_VERSION < 30200 -# error Sorry, your compiler is too old - please upgrade it. -#endif - -#if GCC_VERSION < 30300 -# define __used __attribute__((__unused__)) -#else -# define __used __attribute__((__used__)) -#endif - -#ifdef CONFIG_GCOV_KERNEL -# if GCC_VERSION < 30400 -# error "GCOV profiling support for gcc versions below 3.4 not included" -# endif /* __GNUC_MINOR__ */ -#endif /* CONFIG_GCOV_KERNEL */ - -#if GCC_VERSION >= 30400 -#define __must_check __attribute__((warn_unused_result)) -#define __malloc __attribute__((__malloc__)) -#endif - -#if GCC_VERSION >= 40000 - -/* GCC 4.1.[01] miscompiles __weak */ -#ifdef __KERNEL__ -# if GCC_VERSION >= 40100 && GCC_VERSION <= 40101 -# error Your version of gcc miscompiles the __weak directive -# endif -#endif - -#define __used __attribute__((__used__)) -#define __compiler_offsetof(a, b) \ - __builtin_offsetof(a, b) - -#if GCC_VERSION >= 40100 -# define __compiletime_object_size(obj) __builtin_object_size(obj, 0) -#endif - -#if GCC_VERSION >= 40300 -/* Mark functions as cold. gcc will assume any path leading to a call - * to them will be unlikely. This means a lot of manual unlikely()s - * are unnecessary now for any paths leading to the usual suspects - * like BUG(), printk(), panic() etc. [but let's keep them for now for - * older compilers] - * - * Early snapshots of gcc 4.3 don't support this and we can't detect this - * in the preprocessor, but we can live with this because they're unreleased. - * Maketime probing would be overkill here. - * - * gcc also has a __attribute__((__hot__)) to move hot functions into - * a special section, but I don't see any sense in this right now in - * the kernel context - */ -#define __cold __attribute__((__cold__)) - -#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__) - -#ifndef __CHECKER__ -# define __compiletime_warning(message) __attribute__((warning(message))) -# define __compiletime_error(message) __attribute__((error(message))) -#endif /* __CHECKER__ */ -#endif /* GCC_VERSION >= 40300 */ - -#if GCC_VERSION >= 40500 - -#ifndef __CHECKER__ -#ifdef LATENT_ENTROPY_PLUGIN -#define __latent_entropy __attribute__((latent_entropy)) -#endif -#endif - -/* - * Mark a position in code as unreachable. This can be used to - * suppress control flow warnings after asm blocks that transfer - * control elsewhere. - * - * Early snapshots of gcc 4.5 don't support this and we can't detect - * this in the preprocessor, but we can live with this because they're - * unreleased. Really, we need to have autoconf for the kernel. - */ -#define unreachable() __builtin_unreachable() - -/* Mark a function definition as prohibited from being cloned. */ -#define __noclone __attribute__((__noclone__, __optimize__("no-tracer"))) - -#endif /* GCC_VERSION >= 40500 */ - -#if GCC_VERSION >= 40600 -/* - * When used with Link Time Optimization, gcc can optimize away C functions or - * variables which are referenced only from assembly code. __visible tells the - * optimizer that something else uses this function or variable, thus preventing - * this. - */ -#define __visible __attribute__((externally_visible)) -#endif - - -#if GCC_VERSION >= 40900 && !defined(__CHECKER__) -/* - * __assume_aligned(n, k): Tell the optimizer that the returned - * pointer can be assumed to be k modulo n. The second argument is - * optional (default 0), so we use a variadic macro to make the - * shorthand. - * - * Beware: Do not apply this to functions which may return - * ERR_PTRs. Also, it is probably unwise to apply it to functions - * returning extra information in the low bits (but in that case the - * compiler should see some alignment anyway, when the return value is - * massaged by 'flags = ptr & 3; ptr &= ~3;'). - */ -#define __assume_aligned(a, ...) __attribute__((__assume_aligned__(a, ## __VA_ARGS__))) -#endif - -/* - * GCC 'asm goto' miscompiles certain code sequences: - * - * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670 - * - * Work it around via a compiler barrier quirk suggested by Jakub Jelinek. - * - * (asm goto is automatically volatile - the naming reflects this.) - */ -#define asm_volatile_goto(x...) do { asm goto(x); asm (""); } while (0) - -/* - * sparse (__CHECKER__) pretends to be gcc, but can't do constant - * folding in __builtin_bswap*() (yet), so don't set these for it. - */ -#if defined(CONFIG_ARCH_USE_BUILTIN_BSWAP) && !defined(__CHECKER__) -#if GCC_VERSION >= 40400 -#define __HAVE_BUILTIN_BSWAP32__ -#define __HAVE_BUILTIN_BSWAP64__ -#endif -#if GCC_VERSION >= 40800 -#define __HAVE_BUILTIN_BSWAP16__ -#endif -#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP && !__CHECKER__ */ - -#if GCC_VERSION >= 70000 -#define KASAN_ABI_VERSION 5 -#elif GCC_VERSION >= 50000 -#define KASAN_ABI_VERSION 4 -#elif GCC_VERSION >= 40902 -#define KASAN_ABI_VERSION 3 -#endif - -#if GCC_VERSION >= 40902 -/* - * Tell the compiler that address safety instrumentation (KASAN) - * should not be applied to that function. - * Conflicts with inlining: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67368 - */ -#define __no_sanitize_address __attribute__((no_sanitize_address)) -#endif - -#endif /* gcc version >= 40000 specific checks */ - -#if !defined(__noclone) -#define __noclone /* not needed */ -#endif - -#if !defined(__no_sanitize_address) -#define __no_sanitize_address -#endif - -/* - * A trick to suppress uninitialized variable warning without generating any - * code - */ -#define uninitialized_var(x) x = x diff --git a/src/linux/include/linux/compiler.h b/src/linux/include/linux/compiler.h deleted file mode 100644 index cf0fa5d..0000000 --- a/src/linux/include/linux/compiler.h +++ /dev/null @@ -1,577 +0,0 @@ -#ifndef __LINUX_COMPILER_H -#define __LINUX_COMPILER_H - -#ifndef __ASSEMBLY__ - -#ifdef __CHECKER__ -# define __user __attribute__((noderef, address_space(1))) -# define __kernel __attribute__((address_space(0))) -# define __safe __attribute__((safe)) -# define __force __attribute__((force)) -# define __nocast __attribute__((nocast)) -# define __iomem __attribute__((noderef, address_space(2))) -# define __must_hold(x) __attribute__((context(x,1,1))) -# define __acquires(x) __attribute__((context(x,0,1))) -# define __releases(x) __attribute__((context(x,1,0))) -# define __acquire(x) __context__(x,1) -# define __release(x) __context__(x,-1) -# define __cond_lock(x,c) ((c) ? ({ __acquire(x); 1; }) : 0) -# define __percpu __attribute__((noderef, address_space(3))) -#ifdef CONFIG_SPARSE_RCU_POINTER -# define __rcu __attribute__((noderef, address_space(4))) -#else /* CONFIG_SPARSE_RCU_POINTER */ -# define __rcu -#endif /* CONFIG_SPARSE_RCU_POINTER */ -# define __private __attribute__((noderef)) -extern void __chk_user_ptr(const volatile void __user *); -extern void __chk_io_ptr(const volatile void __iomem *); -# define ACCESS_PRIVATE(p, member) (*((typeof((p)->member) __force *) &(p)->member)) -#else /* __CHECKER__ */ -# define __user -# define __kernel -# define __safe -# define __force -# define __nocast -# define __iomem -# define __chk_user_ptr(x) (void)0 -# define __chk_io_ptr(x) (void)0 -# define __builtin_warning(x, y...) (1) -# define __must_hold(x) -# define __acquires(x) -# define __releases(x) -# define __acquire(x) (void)0 -# define __release(x) (void)0 -# define __cond_lock(x,c) (c) -# define __percpu -# define __rcu -# define __private -# define ACCESS_PRIVATE(p, member) ((p)->member) -#endif /* __CHECKER__ */ - -/* Indirect macros required for expanded argument pasting, eg. __LINE__. */ -#define ___PASTE(a,b) a##b -#define __PASTE(a,b) ___PASTE(a,b) - -#ifdef __KERNEL__ - -#ifdef __GNUC__ -#include -#endif - -#if defined(CC_USING_HOTPATCH) && !defined(__CHECKER__) -#define notrace __attribute__((hotpatch(0,0))) -#else -#define notrace __attribute__((no_instrument_function)) -#endif - -/* Intel compiler defines __GNUC__. So we will overwrite implementations - * coming from above header files here - */ -#ifdef __INTEL_COMPILER -# include -#endif - -/* Clang compiler defines __GNUC__. So we will overwrite implementations - * coming from above header files here - */ -#ifdef __clang__ -#include -#endif - -/* - * Generic compiler-dependent macros required for kernel - * build go below this comment. Actual compiler/compiler version - * specific implementations come from the above header files - */ - -struct ftrace_branch_data { - const char *func; - const char *file; - unsigned line; - union { - struct { - unsigned long correct; - unsigned long incorrect; - }; - struct { - unsigned long miss; - unsigned long hit; - }; - unsigned long miss_hit[2]; - }; -}; - -/* - * Note: DISABLE_BRANCH_PROFILING can be used by special lowlevel code - * to disable branch tracing on a per file basis. - */ -#if defined(CONFIG_TRACE_BRANCH_PROFILING) \ - && !defined(DISABLE_BRANCH_PROFILING) && !defined(__CHECKER__) -void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect); - -#define likely_notrace(x) __builtin_expect(!!(x), 1) -#define unlikely_notrace(x) __builtin_expect(!!(x), 0) - -#define __branch_check__(x, expect) ({ \ - int ______r; \ - static struct ftrace_branch_data \ - __attribute__((__aligned__(4))) \ - __attribute__((section("_ftrace_annotated_branch"))) \ - ______f = { \ - .func = __func__, \ - .file = __FILE__, \ - .line = __LINE__, \ - }; \ - ______r = likely_notrace(x); \ - ftrace_likely_update(&______f, ______r, expect); \ - ______r; \ - }) - -/* - * Using __builtin_constant_p(x) to ignore cases where the return - * value is always the same. This idea is taken from a similar patch - * written by Daniel Walker. - */ -# ifndef likely -# define likely(x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 1)) -# endif -# ifndef unlikely -# define unlikely(x) (__builtin_constant_p(x) ? !!(x) : __branch_check__(x, 0)) -# endif - -#ifdef CONFIG_PROFILE_ALL_BRANCHES -/* - * "Define 'is'", Bill Clinton - * "Define 'if'", Steven Rostedt - */ -#define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) ) -#define __trace_if(cond) \ - if (__builtin_constant_p(!!(cond)) ? !!(cond) : \ - ({ \ - int ______r; \ - static struct ftrace_branch_data \ - __attribute__((__aligned__(4))) \ - __attribute__((section("_ftrace_branch"))) \ - ______f = { \ - .func = __func__, \ - .file = __FILE__, \ - .line = __LINE__, \ - }; \ - ______r = !!(cond); \ - ______f.miss_hit[______r]++; \ - ______r; \ - })) -#endif /* CONFIG_PROFILE_ALL_BRANCHES */ - -#else -# define likely(x) __builtin_expect(!!(x), 1) -# define unlikely(x) __builtin_expect(!!(x), 0) -#endif - -/* Optimization barrier */ -#ifndef barrier -# define barrier() __memory_barrier() -#endif - -#ifndef barrier_data -# define barrier_data(ptr) barrier() -#endif - -/* Unreachable code */ -#ifndef unreachable -# define unreachable() do { } while (1) -#endif - -/* - * KENTRY - kernel entry point - * This can be used to annotate symbols (functions or data) that are used - * without their linker symbol being referenced explicitly. For example, - * interrupt vector handlers, or functions in the kernel image that are found - * programatically. - * - * Not required for symbols exported with EXPORT_SYMBOL, or initcalls. Those - * are handled in their own way (with KEEP() in linker scripts). - * - * KENTRY can be avoided if the symbols in question are marked as KEEP() in the - * linker script. For example an architecture could KEEP() its entire - * boot/exception vector code rather than annotate each function and data. - */ -#ifndef KENTRY -# define KENTRY(sym) \ - extern typeof(sym) sym; \ - static const unsigned long __kentry_##sym \ - __used \ - __attribute__((section("___kentry" "+" #sym ), used)) \ - = (unsigned long)&sym; -#endif - -#ifndef RELOC_HIDE -# define RELOC_HIDE(ptr, off) \ - ({ unsigned long __ptr; \ - __ptr = (unsigned long) (ptr); \ - (typeof(ptr)) (__ptr + (off)); }) -#endif - -#ifndef OPTIMIZER_HIDE_VAR -#define OPTIMIZER_HIDE_VAR(var) barrier() -#endif - -/* Not-quite-unique ID. */ -#ifndef __UNIQUE_ID -# define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__) -#endif - -#include - -#define __READ_ONCE_SIZE \ -({ \ - switch (size) { \ - case 1: *(__u8 *)res = *(volatile __u8 *)p; break; \ - case 2: *(__u16 *)res = *(volatile __u16 *)p; break; \ - case 4: *(__u32 *)res = *(volatile __u32 *)p; break; \ - case 8: *(__u64 *)res = *(volatile __u64 *)p; break; \ - default: \ - barrier(); \ - __builtin_memcpy((void *)res, (const void *)p, size); \ - barrier(); \ - } \ -}) - -static __always_inline -void __read_once_size(const volatile void *p, void *res, int size) -{ - __READ_ONCE_SIZE; -} - -#ifdef CONFIG_KASAN -/* - * This function is not 'inline' because __no_sanitize_address confilcts - * with inlining. Attempt to inline it may cause a build failure. - * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67368 - * '__maybe_unused' allows us to avoid defined-but-not-used warnings. - */ -static __no_sanitize_address __maybe_unused -void __read_once_size_nocheck(const volatile void *p, void *res, int size) -{ - __READ_ONCE_SIZE; -} -#else -static __always_inline -void __read_once_size_nocheck(const volatile void *p, void *res, int size) -{ - __READ_ONCE_SIZE; -} -#endif - -static __always_inline void __write_once_size(volatile void *p, void *res, int size) -{ - switch (size) { - case 1: *(volatile __u8 *)p = *(__u8 *)res; break; - case 2: *(volatile __u16 *)p = *(__u16 *)res; break; - case 4: *(volatile __u32 *)p = *(__u32 *)res; break; - case 8: *(volatile __u64 *)p = *(__u64 *)res; break; - default: - barrier(); - __builtin_memcpy((void *)p, (const void *)res, size); - barrier(); - } -} - -/* - * Prevent the compiler from merging or refetching reads or writes. The - * compiler is also forbidden from reordering successive instances of - * READ_ONCE, WRITE_ONCE and ACCESS_ONCE (see below), but only when the - * compiler is aware of some particular ordering. One way to make the - * compiler aware of ordering is to put the two invocations of READ_ONCE, - * WRITE_ONCE or ACCESS_ONCE() in different C statements. - * - * In contrast to ACCESS_ONCE these two macros will also work on aggregate - * data types like structs or unions. If the size of the accessed data - * type exceeds the word size of the machine (e.g., 32 bits or 64 bits) - * READ_ONCE() and WRITE_ONCE() will fall back to memcpy(). There's at - * least two memcpy()s: one for the __builtin_memcpy() and then one for - * the macro doing the copy of variable - '__u' allocated on the stack. - * - * Their two major use cases are: (1) Mediating communication between - * process-level code and irq/NMI handlers, all running on the same CPU, - * and (2) Ensuring that the compiler does not fold, spindle, or otherwise - * mutilate accesses that either do not require ordering or that interact - * with an explicit memory barrier or atomic instruction that provides the - * required ordering. - */ - -#define __READ_ONCE(x, check) \ -({ \ - union { typeof(x) __val; char __c[1]; } __u; \ - if (check) \ - __read_once_size(&(x), __u.__c, sizeof(x)); \ - else \ - __read_once_size_nocheck(&(x), __u.__c, sizeof(x)); \ - __u.__val; \ -}) -#define READ_ONCE(x) __READ_ONCE(x, 1) - -/* - * Use READ_ONCE_NOCHECK() instead of READ_ONCE() if you need - * to hide memory access from KASAN. - */ -#define READ_ONCE_NOCHECK(x) __READ_ONCE(x, 0) - -#define WRITE_ONCE(x, val) \ -({ \ - union { typeof(x) __val; char __c[1]; } __u = \ - { .__val = (__force typeof(x)) (val) }; \ - __write_once_size(&(x), __u.__c, sizeof(x)); \ - __u.__val; \ -}) - -#endif /* __KERNEL__ */ - -#endif /* __ASSEMBLY__ */ - -#ifdef __KERNEL__ -/* - * Allow us to mark functions as 'deprecated' and have gcc emit a nice - * warning for each use, in hopes of speeding the functions removal. - * Usage is: - * int __deprecated foo(void) - */ -#ifndef __deprecated -# define __deprecated /* unimplemented */ -#endif - -#ifdef MODULE -#define __deprecated_for_modules __deprecated -#else -#define __deprecated_for_modules -#endif - -#ifndef __must_check -#define __must_check -#endif - -#ifndef CONFIG_ENABLE_MUST_CHECK -#undef __must_check -#define __must_check -#endif -#ifndef CONFIG_ENABLE_WARN_DEPRECATED -#undef __deprecated -#undef __deprecated_for_modules -#define __deprecated -#define __deprecated_for_modules -#endif - -#ifndef __malloc -#define __malloc -#endif - -/* - * Allow us to avoid 'defined but not used' warnings on functions and data, - * as well as force them to be emitted to the assembly file. - * - * As of gcc 3.4, static functions that are not marked with attribute((used)) - * may be elided from the assembly file. As of gcc 3.4, static data not so - * marked will not be elided, but this may change in a future gcc version. - * - * NOTE: Because distributions shipped with a backported unit-at-a-time - * compiler in gcc 3.3, we must define __used to be __attribute__((used)) - * for gcc >=3.3 instead of 3.4. - * - * In prior versions of gcc, such functions and data would be emitted, but - * would be warned about except with attribute((unused)). - * - * Mark functions that are referenced only in inline assembly as __used so - * the code is emitted even though it appears to be unreferenced. - */ -#ifndef __used -# define __used /* unimplemented */ -#endif - -#ifndef __maybe_unused -# define __maybe_unused /* unimplemented */ -#endif - -#ifndef __always_unused -# define __always_unused /* unimplemented */ -#endif - -#ifndef noinline -#define noinline -#endif - -/* - * Rather then using noinline to prevent stack consumption, use - * noinline_for_stack instead. For documentation reasons. - */ -#define noinline_for_stack noinline - -#ifndef __always_inline -#define __always_inline inline -#endif - -#endif /* __KERNEL__ */ - -/* - * From the GCC manual: - * - * Many functions do not examine any values except their arguments, - * and have no effects except the return value. Basically this is - * just slightly more strict class than the `pure' attribute above, - * since function is not allowed to read global memory. - * - * Note that a function that has pointer arguments and examines the - * data pointed to must _not_ be declared `const'. Likewise, a - * function that calls a non-`const' function usually must not be - * `const'. It does not make sense for a `const' function to return - * `void'. - */ -#ifndef __attribute_const__ -# define __attribute_const__ /* unimplemented */ -#endif - -#ifndef __latent_entropy -# define __latent_entropy -#endif - -/* - * Tell gcc if a function is cold. The compiler will assume any path - * directly leading to the call is unlikely. - */ - -#ifndef __cold -#define __cold -#endif - -/* Simple shorthand for a section definition */ -#ifndef __section -# define __section(S) __attribute__ ((__section__(#S))) -#endif - -#ifndef __visible -#define __visible -#endif - -/* - * Assume alignment of return value. - */ -#ifndef __assume_aligned -#define __assume_aligned(a, ...) -#endif - - -/* Are two types/vars the same type (ignoring qualifiers)? */ -#ifndef __same_type -# define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) -#endif - -/* Is this type a native word size -- useful for atomic operations */ -#ifndef __native_word -# define __native_word(t) (sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long)) -#endif - -/* Compile time object size, -1 for unknown */ -#ifndef __compiletime_object_size -# define __compiletime_object_size(obj) -1 -#endif -#ifndef __compiletime_warning -# define __compiletime_warning(message) -#endif -#ifndef __compiletime_error -# define __compiletime_error(message) -/* - * Sparse complains of variable sized arrays due to the temporary variable in - * __compiletime_assert. Unfortunately we can't just expand it out to make - * sparse see a constant array size without breaking compiletime_assert on old - * versions of GCC (e.g. 4.2.4), so hide the array from sparse altogether. - */ -# ifndef __CHECKER__ -# define __compiletime_error_fallback(condition) \ - do { ((void)sizeof(char[1 - 2 * condition])); } while (0) -# endif -#endif -#ifndef __compiletime_error_fallback -# define __compiletime_error_fallback(condition) do { } while (0) -#endif - -#define __compiletime_assert(condition, msg, prefix, suffix) \ - do { \ - bool __cond = !(condition); \ - extern void prefix ## suffix(void) __compiletime_error(msg); \ - if (__cond) \ - prefix ## suffix(); \ - __compiletime_error_fallback(__cond); \ - } while (0) - -#define _compiletime_assert(condition, msg, prefix, suffix) \ - __compiletime_assert(condition, msg, prefix, suffix) - -/** - * compiletime_assert - break build and emit msg if condition is false - * @condition: a compile-time constant condition to check - * @msg: a message to emit if condition is false - * - * In tradition of POSIX assert, this macro will break the build if the - * supplied condition is *false*, emitting the supplied error message if the - * compiler has support to do so. - */ -#define compiletime_assert(condition, msg) \ - _compiletime_assert(condition, msg, __compiletime_assert_, __LINE__) - -#define compiletime_assert_atomic_type(t) \ - compiletime_assert(__native_word(t), \ - "Need native word sized stores/loads for atomicity.") - -/* - * Prevent the compiler from merging or refetching accesses. The compiler - * is also forbidden from reordering successive instances of ACCESS_ONCE(), - * but only when the compiler is aware of some particular ordering. One way - * to make the compiler aware of ordering is to put the two invocations of - * ACCESS_ONCE() in different C statements. - * - * ACCESS_ONCE will only work on scalar types. For union types, ACCESS_ONCE - * on a union member will work as long as the size of the member matches the - * size of the union and the size is smaller than word size. - * - * The major use cases of ACCESS_ONCE used to be (1) Mediating communication - * between process-level code and irq/NMI handlers, all running on the same CPU, - * and (2) Ensuring that the compiler does not fold, spindle, or otherwise - * mutilate accesses that either do not require ordering or that interact - * with an explicit memory barrier or atomic instruction that provides the - * required ordering. - * - * If possible use READ_ONCE()/WRITE_ONCE() instead. - */ -#define __ACCESS_ONCE(x) ({ \ - __maybe_unused typeof(x) __var = (__force typeof(x)) 0; \ - (volatile typeof(x) *)&(x); }) -#define ACCESS_ONCE(x) (*__ACCESS_ONCE(x)) - -/** - * lockless_dereference() - safely load a pointer for later dereference - * @p: The pointer to load - * - * Similar to rcu_dereference(), but for situations where the pointed-to - * object's lifetime is managed by something other than RCU. That - * "something other" might be reference counting or simple immortality. - * - * The seemingly unused variable ___typecheck_p validates that @p is - * indeed a pointer type by using a pointer to typeof(*p) as the type. - * Taking a pointer to typeof(*p) again is needed in case p is void *. - */ -#define lockless_dereference(p) \ -({ \ - typeof(p) _________p1 = READ_ONCE(p); \ - typeof(*(p)) *___typecheck_p __maybe_unused; \ - smp_read_barrier_depends(); /* Dependency order vs. p above. */ \ - (_________p1); \ -}) - -/* Ignore/forbid kprobes attach on very low level functions marked by this attribute: */ -#ifdef CONFIG_KPROBES -# define __kprobes __attribute__((__section__(".kprobes.text"))) -# define nokprobe_inline __always_inline -#else -# define __kprobes -# define nokprobe_inline inline -#endif -#endif /* __LINUX_COMPILER_H */ diff --git a/src/linux/include/linux/completion.h b/src/linux/include/linux/completion.h deleted file mode 100644 index 5d5aaae..0000000 --- a/src/linux/include/linux/completion.h +++ /dev/null @@ -1,109 +0,0 @@ -#ifndef __LINUX_COMPLETION_H -#define __LINUX_COMPLETION_H - -/* - * (C) Copyright 2001 Linus Torvalds - * - * Atomic wait-for-completion handler data structures. - * See kernel/sched/completion.c for details. - */ - -#include - -/* - * struct completion - structure used to maintain state for a "completion" - * - * This is the opaque structure used to maintain the state for a "completion". - * Completions currently use a FIFO to queue threads that have to wait for - * the "completion" event. - * - * See also: complete(), wait_for_completion() (and friends _timeout, - * _interruptible, _interruptible_timeout, and _killable), init_completion(), - * reinit_completion(), and macros DECLARE_COMPLETION(), - * DECLARE_COMPLETION_ONSTACK(). - */ -struct completion { - unsigned int done; - wait_queue_head_t wait; -}; - -#define COMPLETION_INITIALIZER(work) \ - { 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) } - -#define COMPLETION_INITIALIZER_ONSTACK(work) \ - ({ init_completion(&work); work; }) - -/** - * DECLARE_COMPLETION - declare and initialize a completion structure - * @work: identifier for the completion structure - * - * This macro declares and initializes a completion structure. Generally used - * for static declarations. You should use the _ONSTACK variant for automatic - * variables. - */ -#define DECLARE_COMPLETION(work) \ - struct completion work = COMPLETION_INITIALIZER(work) - -/* - * Lockdep needs to run a non-constant initializer for on-stack - * completions - so we use the _ONSTACK() variant for those that - * are on the kernel stack: - */ -/** - * DECLARE_COMPLETION_ONSTACK - declare and initialize a completion structure - * @work: identifier for the completion structure - * - * This macro declares and initializes a completion structure on the kernel - * stack. - */ -#ifdef CONFIG_LOCKDEP -# define DECLARE_COMPLETION_ONSTACK(work) \ - struct completion work = COMPLETION_INITIALIZER_ONSTACK(work) -#else -# define DECLARE_COMPLETION_ONSTACK(work) DECLARE_COMPLETION(work) -#endif - -/** - * init_completion - Initialize a dynamically allocated completion - * @x: pointer to completion structure that is to be initialized - * - * This inline function will initialize a dynamically created completion - * structure. - */ -static inline void init_completion(struct completion *x) -{ - x->done = 0; - init_waitqueue_head(&x->wait); -} - -/** - * reinit_completion - reinitialize a completion structure - * @x: pointer to completion structure that is to be reinitialized - * - * This inline function should be used to reinitialize a completion structure so it can - * be reused. This is especially important after complete_all() is used. - */ -static inline void reinit_completion(struct completion *x) -{ - x->done = 0; -} - -extern void wait_for_completion(struct completion *); -extern void wait_for_completion_io(struct completion *); -extern int wait_for_completion_interruptible(struct completion *x); -extern int wait_for_completion_killable(struct completion *x); -extern unsigned long wait_for_completion_timeout(struct completion *x, - unsigned long timeout); -extern unsigned long wait_for_completion_io_timeout(struct completion *x, - unsigned long timeout); -extern long wait_for_completion_interruptible_timeout( - struct completion *x, unsigned long timeout); -extern long wait_for_completion_killable_timeout( - struct completion *x, unsigned long timeout); -extern bool try_wait_for_completion(struct completion *x); -extern bool completion_done(struct completion *x); - -extern void complete(struct completion *); -extern void complete_all(struct completion *); - -#endif diff --git a/src/linux/include/linux/component.h b/src/linux/include/linux/component.h deleted file mode 100644 index a559eeb..0000000 --- a/src/linux/include/linux/component.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef COMPONENT_H -#define COMPONENT_H - -#include - -struct device; - -struct component_ops { - int (*bind)(struct device *comp, struct device *master, - void *master_data); - void (*unbind)(struct device *comp, struct device *master, - void *master_data); -}; - -int component_add(struct device *, const struct component_ops *); -void component_del(struct device *, const struct component_ops *); - -int component_bind_all(struct device *master, void *master_data); -void component_unbind_all(struct device *master, void *master_data); - -struct master; - -struct component_master_ops { - int (*bind)(struct device *master); - void (*unbind)(struct device *master); -}; - -void component_master_del(struct device *, - const struct component_master_ops *); - -struct component_match; - -int component_master_add_with_match(struct device *, - const struct component_master_ops *, struct component_match *); -void component_match_add_release(struct device *master, - struct component_match **matchptr, - void (*release)(struct device *, void *), - int (*compare)(struct device *, void *), void *compare_data); - -static inline void component_match_add(struct device *master, - struct component_match **matchptr, - int (*compare)(struct device *, void *), void *compare_data) -{ - component_match_add_release(master, matchptr, NULL, compare, - compare_data); -} - -#endif diff --git a/src/linux/include/linux/console.h b/src/linux/include/linux/console.h deleted file mode 100644 index d530c46..0000000 --- a/src/linux/include/linux/console.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * linux/include/linux/console.h - * - * Copyright (C) 1993 Hamish Macdonald - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - * - * Changed: - * 10-Mar-94: Arno Griffioen: Conversion for vt100 emulator port from PC LINUX - */ - -#ifndef _LINUX_CONSOLE_H_ -#define _LINUX_CONSOLE_H_ 1 - -#include - -struct vc_data; -struct console_font_op; -struct console_font; -struct module; -struct tty_struct; - -/* - * this is what the terminal answers to a ESC-Z or csi0c query. - */ -#define VT100ID "\033[?1;2c" -#define VT102ID "\033[?6c" - -/** - * struct consw - callbacks for consoles - * - * @con_set_palette: sets the palette of the console to @table (optional) - * @con_scrolldelta: the contents of the console should be scrolled by @lines. - * Invoked by user. (optional) - */ -struct consw { - struct module *owner; - const char *(*con_startup)(void); - void (*con_init)(struct vc_data *, int); - void (*con_deinit)(struct vc_data *); - void (*con_clear)(struct vc_data *, int, int, int, int); - void (*con_putc)(struct vc_data *, int, int, int); - void (*con_putcs)(struct vc_data *, const unsigned short *, int, int, int); - void (*con_cursor)(struct vc_data *, int); - int (*con_scroll)(struct vc_data *, int, int, int, int); - int (*con_switch)(struct vc_data *); - int (*con_blank)(struct vc_data *, int, int); - int (*con_font_set)(struct vc_data *, struct console_font *, unsigned); - int (*con_font_get)(struct vc_data *, struct console_font *); - int (*con_font_default)(struct vc_data *, struct console_font *, char *); - int (*con_font_copy)(struct vc_data *, int); - int (*con_resize)(struct vc_data *, unsigned int, unsigned int, - unsigned int); - void (*con_set_palette)(struct vc_data *, - const unsigned char *table); - void (*con_scrolldelta)(struct vc_data *, int lines); - int (*con_set_origin)(struct vc_data *); - void (*con_save_screen)(struct vc_data *); - u8 (*con_build_attr)(struct vc_data *, u8, u8, u8, u8, u8, u8); - void (*con_invert_region)(struct vc_data *, u16 *, int); - u16 *(*con_screen_pos)(struct vc_data *, int); - unsigned long (*con_getxy)(struct vc_data *, unsigned long, int *, int *); - /* - * Prepare the console for the debugger. This includes, but is not - * limited to, unblanking the console, loading an appropriate - * palette, and allowing debugger generated output. - */ - int (*con_debug_enter)(struct vc_data *); - /* - * Restore the console to its pre-debug state as closely as possible. - */ - int (*con_debug_leave)(struct vc_data *); -}; - -extern const struct consw *conswitchp; - -extern const struct consw dummy_con; /* dummy console buffer */ -extern const struct consw vga_con; /* VGA text console */ -extern const struct consw newport_con; /* SGI Newport console */ -extern const struct consw prom_con; /* SPARC PROM console */ - -int con_is_bound(const struct consw *csw); -int do_unregister_con_driver(const struct consw *csw); -int do_take_over_console(const struct consw *sw, int first, int last, int deflt); -void give_up_console(const struct consw *sw); -#ifdef CONFIG_HW_CONSOLE -int con_debug_enter(struct vc_data *vc); -int con_debug_leave(void); -#else -static inline int con_debug_enter(struct vc_data *vc) -{ - return 0; -} -static inline int con_debug_leave(void) -{ - return 0; -} -#endif - -/* scroll */ -#define SM_UP (1) -#define SM_DOWN (2) - -/* cursor */ -#define CM_DRAW (1) -#define CM_ERASE (2) -#define CM_MOVE (3) - -/* - * The interface for a console, or any other device that wants to capture - * console messages (printer driver?) - * - * If a console driver is marked CON_BOOT then it will be auto-unregistered - * when the first real console is registered. This is for early-printk drivers. - */ - -#define CON_PRINTBUFFER (1) -#define CON_CONSDEV (2) /* Last on the command line */ -#define CON_ENABLED (4) -#define CON_BOOT (8) -#define CON_ANYTIME (16) /* Safe to call when cpu is offline */ -#define CON_BRL (32) /* Used for a braille device */ -#define CON_EXTENDED (64) /* Use the extended output format a la /dev/kmsg */ - -struct console { - char name[16]; - void (*write)(struct console *, const char *, unsigned); - int (*read)(struct console *, char *, unsigned); - struct tty_driver *(*device)(struct console *, int *); - void (*unblank)(void); - int (*setup)(struct console *, char *); - int (*match)(struct console *, char *name, int idx, char *options); - short flags; - short index; - int cflag; - void *data; - struct console *next; -}; - -/* - * for_each_console() allows you to iterate on each console - */ -#define for_each_console(con) \ - for (con = console_drivers; con != NULL; con = con->next) - -extern int console_set_on_cmdline; -extern struct console *early_console; - -extern int add_preferred_console(char *name, int idx, char *options); -extern void register_console(struct console *); -extern int unregister_console(struct console *); -extern struct console *console_drivers; -extern void console_lock(void); -extern int console_trylock(void); -extern void console_unlock(void); -extern void console_conditional_schedule(void); -extern void console_unblank(void); -extern void console_flush_on_panic(void); -extern struct tty_driver *console_device(int *); -extern void console_stop(struct console *); -extern void console_start(struct console *); -extern int is_console_locked(void); -extern int braille_register_console(struct console *, int index, - char *console_options, char *braille_options); -extern int braille_unregister_console(struct console *); -#ifdef CONFIG_TTY -extern void console_sysfs_notify(void); -#else -static inline void console_sysfs_notify(void) -{ } -#endif -extern bool console_suspend_enabled; - -/* Suspend and resume console messages over PM events */ -extern void suspend_console(void); -extern void resume_console(void); - -int mda_console_init(void); -void prom_con_init(void); - -void vcs_make_sysfs(int index); -void vcs_remove_sysfs(int index); - -/* Some debug stub to catch some of the obvious races in the VT code */ -#if 1 -#define WARN_CONSOLE_UNLOCKED() WARN_ON(!is_console_locked() && !oops_in_progress) -#else -#define WARN_CONSOLE_UNLOCKED() -#endif - -/* VESA Blanking Levels */ -#define VESA_NO_BLANKING 0 -#define VESA_VSYNC_SUSPEND 1 -#define VESA_HSYNC_SUSPEND 2 -#define VESA_POWERDOWN 3 - -#ifdef CONFIG_VGA_CONSOLE -extern bool vgacon_text_force(void); -#else -static inline bool vgacon_text_force(void) { return false; } -#endif - -#endif /* _LINUX_CONSOLE_H */ diff --git a/src/linux/include/linux/console_struct.h b/src/linux/include/linux/console_struct.h deleted file mode 100644 index 6fd3c90..0000000 --- a/src/linux/include/linux/console_struct.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * console_struct.h - * - * Data structure describing single virtual console except for data - * used by vt.c. - * - * Fields marked with [#] must be set by the low-level driver. - * Fields marked with [!] can be changed by the low-level driver - * to achieve effects such as fast scrolling by changing the origin. - */ - -#ifndef _LINUX_CONSOLE_STRUCT_H -#define _LINUX_CONSOLE_STRUCT_H - -#include -#include -#include - -struct vt_struct; -struct uni_pagedir; - -#define NPAR 16 - -/* - * Example: vc_data of a console that was scrolled 3 lines down. - * - * Console buffer - * vc_screenbuf ---------> +----------------------+-. - * | initializing W | \ - * | initializing X | | - * | initializing Y | > scroll-back area - * | initializing Z | | - * | | / - * vc_visible_origin ---> ^+----------------------+-: - * (changes by scroll) || Welcome to linux | \ - * || | | - * vc_rows --->< | login: root | | visible on console - * || password: | > (vc_screenbuf_size is - * vc_origin -----------> || | | vc_size_row * vc_rows) - * (start when no scroll) || Last login: 12:28 | / - * v+----------------------+-: - * | Have a lot of fun... | \ - * vc_pos -----------------|--------v | > scroll-front area - * | ~ # cat_ | / - * vc_scr_end -----------> +----------------------+-: - * (vc_origin + | | \ EMPTY, to be filled by - * vc_screenbuf_size) | | / vc_video_erase_char - * +----------------------+-' - * <---- 2 * vc_cols -----> - * <---- vc_size_row -----> - * - * Note that every character in the console buffer is accompanied with an - * attribute in the buffer right after the character. This is not depicted - * in the figure. - */ -struct vc_data { - struct tty_port port; /* Upper level data */ - - unsigned short vc_num; /* Console number */ - unsigned int vc_cols; /* [#] Console size */ - unsigned int vc_rows; - unsigned int vc_size_row; /* Bytes per row */ - unsigned int vc_scan_lines; /* # of scan lines */ - unsigned long vc_origin; /* [!] Start of real screen */ - unsigned long vc_scr_end; /* [!] End of real screen */ - unsigned long vc_visible_origin; /* [!] Top of visible window */ - unsigned int vc_top, vc_bottom; /* Scrolling region */ - const struct consw *vc_sw; - unsigned short *vc_screenbuf; /* In-memory character/attribute buffer */ - unsigned int vc_screenbuf_size; - unsigned char vc_mode; /* KD_TEXT, ... */ - /* attributes for all characters on screen */ - unsigned char vc_attr; /* Current attributes */ - unsigned char vc_def_color; /* Default colors */ - unsigned char vc_color; /* Foreground & background */ - unsigned char vc_s_color; /* Saved foreground & background */ - unsigned char vc_ulcolor; /* Color for underline mode */ - unsigned char vc_itcolor; - unsigned char vc_halfcolor; /* Color for half intensity mode */ - /* cursor */ - unsigned int vc_cursor_type; - unsigned short vc_complement_mask; /* [#] Xor mask for mouse pointer */ - unsigned short vc_s_complement_mask; /* Saved mouse pointer mask */ - unsigned int vc_x, vc_y; /* Cursor position */ - unsigned int vc_saved_x, vc_saved_y; - unsigned long vc_pos; /* Cursor address */ - /* fonts */ - unsigned short vc_hi_font_mask; /* [#] Attribute set for upper 256 chars of font or 0 if not supported */ - struct console_font vc_font; /* Current VC font set */ - unsigned short vc_video_erase_char; /* Background erase character */ - /* VT terminal data */ - unsigned int vc_state; /* Escape sequence parser state */ - unsigned int vc_npar,vc_par[NPAR]; /* Parameters of current escape sequence */ - /* data for manual vt switching */ - struct vt_mode vt_mode; - struct pid *vt_pid; - int vt_newvt; - wait_queue_head_t paste_wait; - /* mode flags */ - unsigned int vc_charset : 1; /* Character set G0 / G1 */ - unsigned int vc_s_charset : 1; /* Saved character set */ - unsigned int vc_disp_ctrl : 1; /* Display chars < 32? */ - unsigned int vc_toggle_meta : 1; /* Toggle high bit? */ - unsigned int vc_decscnm : 1; /* Screen Mode */ - unsigned int vc_decom : 1; /* Origin Mode */ - unsigned int vc_decawm : 1; /* Autowrap Mode */ - unsigned int vc_deccm : 1; /* Cursor Visible */ - unsigned int vc_decim : 1; /* Insert Mode */ - /* attribute flags */ - unsigned int vc_intensity : 2; /* 0=half-bright, 1=normal, 2=bold */ - unsigned int vc_italic:1; - unsigned int vc_underline : 1; - unsigned int vc_blink : 1; - unsigned int vc_reverse : 1; - unsigned int vc_s_intensity : 2; /* saved rendition */ - unsigned int vc_s_italic:1; - unsigned int vc_s_underline : 1; - unsigned int vc_s_blink : 1; - unsigned int vc_s_reverse : 1; - /* misc */ - unsigned int vc_ques : 1; - unsigned int vc_need_wrap : 1; - unsigned int vc_can_do_color : 1; - unsigned int vc_report_mouse : 2; - unsigned char vc_utf : 1; /* Unicode UTF-8 encoding */ - unsigned char vc_utf_count; - int vc_utf_char; - unsigned int vc_tab_stop[8]; /* Tab stops. 256 columns. */ - unsigned char vc_palette[16*3]; /* Colour palette for VGA+ */ - unsigned short * vc_translate; - unsigned char vc_G0_charset; - unsigned char vc_G1_charset; - unsigned char vc_saved_G0; - unsigned char vc_saved_G1; - unsigned int vc_resize_user; /* resize request from user */ - unsigned int vc_bell_pitch; /* Console bell pitch */ - unsigned int vc_bell_duration; /* Console bell duration */ - unsigned short vc_cur_blink_ms; /* Cursor blink duration */ - struct vc_data **vc_display_fg; /* [!] Ptr to var holding fg console for this display */ - struct uni_pagedir *vc_uni_pagedir; - struct uni_pagedir **vc_uni_pagedir_loc; /* [!] Location of uni_pagedir variable for this console */ - bool vc_panic_force_write; /* when oops/panic this VC can accept forced output/blanking */ - /* additional information is in vt_kern.h */ -}; - -struct vc { - struct vc_data *d; - struct work_struct SAK_work; - - /* might add scrmem, vt_struct, kbd at some time, - to have everything in one place - the disadvantage - would be that vc_cons etc can no longer be static */ -}; - -extern struct vc vc_cons [MAX_NR_CONSOLES]; -extern void vc_SAK(struct work_struct *work); - -#define CUR_DEF 0 -#define CUR_NONE 1 -#define CUR_UNDERLINE 2 -#define CUR_LOWER_THIRD 3 -#define CUR_LOWER_HALF 4 -#define CUR_TWO_THIRDS 5 -#define CUR_BLOCK 6 -#define CUR_HWMASK 0x0f -#define CUR_SWMASK 0xfff0 - -#define CUR_DEFAULT CUR_UNDERLINE - -static inline bool con_is_visible(const struct vc_data *vc) -{ - return *vc->vc_display_fg == vc; -} - -#endif /* _LINUX_CONSOLE_STRUCT_H */ diff --git a/src/linux/include/linux/consolemap.h b/src/linux/include/linux/consolemap.h deleted file mode 100644 index c4811da..0000000 --- a/src/linux/include/linux/consolemap.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * consolemap.h - * - * Interface between console.c, selection.c and consolemap.c - */ -#ifndef __LINUX_CONSOLEMAP_H__ -#define __LINUX_CONSOLEMAP_H__ - -#define LAT1_MAP 0 -#define GRAF_MAP 1 -#define IBMPC_MAP 2 -#define USER_MAP 3 - -#include - -#ifdef CONFIG_CONSOLE_TRANSLATIONS -struct vc_data; - -extern u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode); -extern unsigned short *set_translate(int m, struct vc_data *vc); -extern int conv_uni_to_pc(struct vc_data *conp, long ucs); -extern u32 conv_8bit_to_uni(unsigned char c); -extern int conv_uni_to_8bit(u32 uni); -void console_map_init(void); -#else -#define inverse_translate(conp, glyph, uni) ((uint16_t)glyph) -#define set_translate(m, vc) ((unsigned short *)NULL) -#define conv_uni_to_pc(conp, ucs) ((int) (ucs > 0xff ? -1: ucs)) -#define conv_8bit_to_uni(c) ((uint32_t)(c)) -#define conv_uni_to_8bit(c) ((int) ((c) & 0xff)) -#define console_map_init(c) do { ; } while (0) -#endif /* CONFIG_CONSOLE_TRANSLATIONS */ - -#endif /* __LINUX_CONSOLEMAP_H__ */ diff --git a/src/linux/include/linux/container.h b/src/linux/include/linux/container.h deleted file mode 100644 index 3c03e6f..0000000 --- a/src/linux/include/linux/container.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Definitions for container bus type. - * - * Copyright (C) 2013, Intel Corporation - * Author: Rafael J. Wysocki - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include - -/* drivers/base/power/container.c */ -extern struct bus_type container_subsys; - -struct container_dev { - struct device dev; - int (*offline)(struct container_dev *cdev); -}; - -static inline struct container_dev *to_container_dev(struct device *dev) -{ - return container_of(dev, struct container_dev, dev); -} diff --git a/src/linux/include/linux/context_tracking.h b/src/linux/include/linux/context_tracking.h deleted file mode 100644 index c78fc27..0000000 --- a/src/linux/include/linux/context_tracking.h +++ /dev/null @@ -1,174 +0,0 @@ -#ifndef _LINUX_CONTEXT_TRACKING_H -#define _LINUX_CONTEXT_TRACKING_H - -#include -#include -#include -#include - - -#ifdef CONFIG_CONTEXT_TRACKING -extern void context_tracking_cpu_set(int cpu); - -/* Called with interrupts disabled. */ -extern void __context_tracking_enter(enum ctx_state state); -extern void __context_tracking_exit(enum ctx_state state); - -extern void context_tracking_enter(enum ctx_state state); -extern void context_tracking_exit(enum ctx_state state); -extern void context_tracking_user_enter(void); -extern void context_tracking_user_exit(void); - -static inline void user_enter(void) -{ - if (context_tracking_is_enabled()) - context_tracking_enter(CONTEXT_USER); - -} -static inline void user_exit(void) -{ - if (context_tracking_is_enabled()) - context_tracking_exit(CONTEXT_USER); -} - -/* Called with interrupts disabled. */ -static inline void user_enter_irqoff(void) -{ - if (context_tracking_is_enabled()) - __context_tracking_enter(CONTEXT_USER); - -} -static inline void user_exit_irqoff(void) -{ - if (context_tracking_is_enabled()) - __context_tracking_exit(CONTEXT_USER); -} - -static inline enum ctx_state exception_enter(void) -{ - enum ctx_state prev_ctx; - - if (!context_tracking_is_enabled()) - return 0; - - prev_ctx = this_cpu_read(context_tracking.state); - if (prev_ctx != CONTEXT_KERNEL) - context_tracking_exit(prev_ctx); - - return prev_ctx; -} - -static inline void exception_exit(enum ctx_state prev_ctx) -{ - if (context_tracking_is_enabled()) { - if (prev_ctx != CONTEXT_KERNEL) - context_tracking_enter(prev_ctx); - } -} - - -/** - * ct_state() - return the current context tracking state if known - * - * Returns the current cpu's context tracking state if context tracking - * is enabled. If context tracking is disabled, returns - * CONTEXT_DISABLED. This should be used primarily for debugging. - */ -static inline enum ctx_state ct_state(void) -{ - return context_tracking_is_enabled() ? - this_cpu_read(context_tracking.state) : CONTEXT_DISABLED; -} -#else -static inline void user_enter(void) { } -static inline void user_exit(void) { } -static inline void user_enter_irqoff(void) { } -static inline void user_exit_irqoff(void) { } -static inline enum ctx_state exception_enter(void) { return 0; } -static inline void exception_exit(enum ctx_state prev_ctx) { } -static inline enum ctx_state ct_state(void) { return CONTEXT_DISABLED; } -#endif /* !CONFIG_CONTEXT_TRACKING */ - -#define CT_WARN_ON(cond) WARN_ON(context_tracking_is_enabled() && (cond)) - -#ifdef CONFIG_CONTEXT_TRACKING_FORCE -extern void context_tracking_init(void); -#else -static inline void context_tracking_init(void) { } -#endif /* CONFIG_CONTEXT_TRACKING_FORCE */ - - -#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN -/* must be called with irqs disabled */ -static inline void guest_enter_irqoff(void) -{ - if (vtime_accounting_cpu_enabled()) - vtime_guest_enter(current); - else - current->flags |= PF_VCPU; - - if (context_tracking_is_enabled()) - __context_tracking_enter(CONTEXT_GUEST); - - /* KVM does not hold any references to rcu protected data when it - * switches CPU into a guest mode. In fact switching to a guest mode - * is very similar to exiting to userspace from rcu point of view. In - * addition CPU may stay in a guest mode for quite a long time (up to - * one time slice). Lets treat guest mode as quiescent state, just like - * we do with user-mode execution. - */ - if (!context_tracking_cpu_is_enabled()) - rcu_virt_note_context_switch(smp_processor_id()); -} - -static inline void guest_exit_irqoff(void) -{ - if (context_tracking_is_enabled()) - __context_tracking_exit(CONTEXT_GUEST); - - if (vtime_accounting_cpu_enabled()) - vtime_guest_exit(current); - else - current->flags &= ~PF_VCPU; -} - -#else -static inline void guest_enter_irqoff(void) -{ - /* - * This is running in ioctl context so its safe - * to assume that it's the stime pending cputime - * to flush. - */ - vtime_account_system(current); - current->flags |= PF_VCPU; - rcu_virt_note_context_switch(smp_processor_id()); -} - -static inline void guest_exit_irqoff(void) -{ - /* Flush the guest cputime we spent on the guest */ - vtime_account_system(current); - current->flags &= ~PF_VCPU; -} -#endif /* CONFIG_VIRT_CPU_ACCOUNTING_GEN */ - -static inline void guest_enter(void) -{ - unsigned long flags; - - local_irq_save(flags); - guest_enter_irqoff(); - local_irq_restore(flags); -} - -static inline void guest_exit(void) -{ - unsigned long flags; - - local_irq_save(flags); - guest_exit_irqoff(); - local_irq_restore(flags); -} - -#endif diff --git a/src/linux/include/linux/context_tracking_state.h b/src/linux/include/linux/context_tracking_state.h deleted file mode 100644 index 1d34fe6..0000000 --- a/src/linux/include/linux/context_tracking_state.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef _LINUX_CONTEXT_TRACKING_STATE_H -#define _LINUX_CONTEXT_TRACKING_STATE_H - -#include -#include - -struct context_tracking { - /* - * When active is false, probes are unset in order - * to minimize overhead: TIF flags are cleared - * and calls to user_enter/exit are ignored. This - * may be further optimized using static keys. - */ - bool active; - int recursion; - enum ctx_state { - CONTEXT_DISABLED = -1, /* returned by ct_state() if unknown */ - CONTEXT_KERNEL = 0, - CONTEXT_USER, - CONTEXT_GUEST, - } state; -}; - -#ifdef CONFIG_CONTEXT_TRACKING -extern struct static_key_false context_tracking_enabled; -DECLARE_PER_CPU(struct context_tracking, context_tracking); - -static inline bool context_tracking_is_enabled(void) -{ - return static_branch_unlikely(&context_tracking_enabled); -} - -static inline bool context_tracking_cpu_is_enabled(void) -{ - return __this_cpu_read(context_tracking.active); -} - -static inline bool context_tracking_in_user(void) -{ - return __this_cpu_read(context_tracking.state) == CONTEXT_USER; -} -#else -static inline bool context_tracking_in_user(void) { return false; } -static inline bool context_tracking_active(void) { return false; } -static inline bool context_tracking_is_enabled(void) { return false; } -static inline bool context_tracking_cpu_is_enabled(void) { return false; } -#endif /* CONFIG_CONTEXT_TRACKING */ - -#endif diff --git a/src/linux/include/linux/coredump.h b/src/linux/include/linux/coredump.h deleted file mode 100644 index d016a12..0000000 --- a/src/linux/include/linux/coredump.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _LINUX_COREDUMP_H -#define _LINUX_COREDUMP_H - -#include -#include -#include -#include - -/* - * These are the only things you should do on a core-file: use only these - * functions to write out all the necessary info. - */ -struct coredump_params; -extern int dump_skip(struct coredump_params *cprm, size_t nr); -extern int dump_emit(struct coredump_params *cprm, const void *addr, int nr); -extern int dump_align(struct coredump_params *cprm, int align); -#ifdef CONFIG_COREDUMP -extern void do_coredump(const siginfo_t *siginfo); -#else -static inline void do_coredump(const siginfo_t *siginfo) {} -#endif - -#endif /* _LINUX_COREDUMP_H */ diff --git a/src/linux/include/linux/cpu.h b/src/linux/include/linux/cpu.h deleted file mode 100644 index 84206a3..0000000 --- a/src/linux/include/linux/cpu.h +++ /dev/null @@ -1,258 +0,0 @@ -/* - * include/linux/cpu.h - generic cpu definition - * - * This is mainly for topological representation. We define the - * basic 'struct cpu' here, which can be embedded in per-arch - * definitions of processors. - * - * Basic handling of the devices is done in drivers/base/cpu.c - * - * CPUs are exported via sysfs in the devices/system/cpu - * directory. - */ -#ifndef _LINUX_CPU_H_ -#define _LINUX_CPU_H_ - -#include -#include -#include -#include - -struct device; -struct device_node; -struct attribute_group; - -struct cpu { - int node_id; /* The node which contains the CPU */ - int hotpluggable; /* creates sysfs control file if hotpluggable */ - struct device dev; -}; - -extern void boot_cpu_init(void); -extern void boot_cpu_state_init(void); - -extern int register_cpu(struct cpu *cpu, int num); -extern struct device *get_cpu_device(unsigned cpu); -extern bool cpu_is_hotpluggable(unsigned cpu); -extern bool arch_match_cpu_phys_id(int cpu, u64 phys_id); -extern bool arch_find_n_match_cpu_physical_id(struct device_node *cpun, - int cpu, unsigned int *thread); - -extern int cpu_add_dev_attr(struct device_attribute *attr); -extern void cpu_remove_dev_attr(struct device_attribute *attr); - -extern int cpu_add_dev_attr_group(struct attribute_group *attrs); -extern void cpu_remove_dev_attr_group(struct attribute_group *attrs); - -extern __printf(4, 5) -struct device *cpu_device_create(struct device *parent, void *drvdata, - const struct attribute_group **groups, - const char *fmt, ...); -#ifdef CONFIG_HOTPLUG_CPU -extern void unregister_cpu(struct cpu *cpu); -extern ssize_t arch_cpu_probe(const char *, size_t); -extern ssize_t arch_cpu_release(const char *, size_t); -#endif -struct notifier_block; - -#define CPU_ONLINE 0x0002 /* CPU (unsigned)v is up */ -#define CPU_UP_PREPARE 0x0003 /* CPU (unsigned)v coming up */ -#define CPU_UP_CANCELED 0x0004 /* CPU (unsigned)v NOT coming up */ -#define CPU_DOWN_PREPARE 0x0005 /* CPU (unsigned)v going down */ -#define CPU_DOWN_FAILED 0x0006 /* CPU (unsigned)v NOT going down */ -#define CPU_DEAD 0x0007 /* CPU (unsigned)v dead */ -#define CPU_POST_DEAD 0x0009 /* CPU (unsigned)v dead, cpu_hotplug - * lock is dropped */ -#define CPU_BROKEN 0x000B /* CPU (unsigned)v did not die properly, - * perhaps due to preemption. */ - -/* Used for CPU hotplug events occurring while tasks are frozen due to a suspend - * operation in progress - */ -#define CPU_TASKS_FROZEN 0x0010 - -#define CPU_ONLINE_FROZEN (CPU_ONLINE | CPU_TASKS_FROZEN) -#define CPU_UP_PREPARE_FROZEN (CPU_UP_PREPARE | CPU_TASKS_FROZEN) -#define CPU_UP_CANCELED_FROZEN (CPU_UP_CANCELED | CPU_TASKS_FROZEN) -#define CPU_DOWN_PREPARE_FROZEN (CPU_DOWN_PREPARE | CPU_TASKS_FROZEN) -#define CPU_DOWN_FAILED_FROZEN (CPU_DOWN_FAILED | CPU_TASKS_FROZEN) -#define CPU_DEAD_FROZEN (CPU_DEAD | CPU_TASKS_FROZEN) - -#ifdef CONFIG_SMP -extern bool cpuhp_tasks_frozen; -/* Need to know about CPUs going up/down? */ -#if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) -#define cpu_notifier(fn, pri) { \ - static struct notifier_block fn##_nb = \ - { .notifier_call = fn, .priority = pri }; \ - register_cpu_notifier(&fn##_nb); \ -} - -#define __cpu_notifier(fn, pri) { \ - static struct notifier_block fn##_nb = \ - { .notifier_call = fn, .priority = pri }; \ - __register_cpu_notifier(&fn##_nb); \ -} -#else /* #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) */ -#define cpu_notifier(fn, pri) do { (void)(fn); } while (0) -#define __cpu_notifier(fn, pri) do { (void)(fn); } while (0) -#endif /* #else #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) */ - -#ifdef CONFIG_HOTPLUG_CPU -extern int register_cpu_notifier(struct notifier_block *nb); -extern int __register_cpu_notifier(struct notifier_block *nb); -extern void unregister_cpu_notifier(struct notifier_block *nb); -extern void __unregister_cpu_notifier(struct notifier_block *nb); -#else - -#ifndef MODULE -extern int register_cpu_notifier(struct notifier_block *nb); -extern int __register_cpu_notifier(struct notifier_block *nb); -#else -static inline int register_cpu_notifier(struct notifier_block *nb) -{ - return 0; -} - -static inline int __register_cpu_notifier(struct notifier_block *nb) -{ - return 0; -} -#endif - -static inline void unregister_cpu_notifier(struct notifier_block *nb) -{ -} - -static inline void __unregister_cpu_notifier(struct notifier_block *nb) -{ -} -#endif - -int cpu_up(unsigned int cpu); -void notify_cpu_starting(unsigned int cpu); -extern void cpu_maps_update_begin(void); -extern void cpu_maps_update_done(void); - -#define cpu_notifier_register_begin cpu_maps_update_begin -#define cpu_notifier_register_done cpu_maps_update_done - -#else /* CONFIG_SMP */ -#define cpuhp_tasks_frozen 0 - -#define cpu_notifier(fn, pri) do { (void)(fn); } while (0) -#define __cpu_notifier(fn, pri) do { (void)(fn); } while (0) - -static inline int register_cpu_notifier(struct notifier_block *nb) -{ - return 0; -} - -static inline int __register_cpu_notifier(struct notifier_block *nb) -{ - return 0; -} - -static inline void unregister_cpu_notifier(struct notifier_block *nb) -{ -} - -static inline void __unregister_cpu_notifier(struct notifier_block *nb) -{ -} - -static inline void cpu_maps_update_begin(void) -{ -} - -static inline void cpu_maps_update_done(void) -{ -} - -static inline void cpu_notifier_register_begin(void) -{ -} - -static inline void cpu_notifier_register_done(void) -{ -} - -#endif /* CONFIG_SMP */ -extern struct bus_type cpu_subsys; - -#ifdef CONFIG_HOTPLUG_CPU -/* Stop CPUs going up and down. */ - -extern void cpu_hotplug_begin(void); -extern void cpu_hotplug_done(void); -extern void get_online_cpus(void); -extern void put_online_cpus(void); -extern void cpu_hotplug_disable(void); -extern void cpu_hotplug_enable(void); -#define hotcpu_notifier(fn, pri) cpu_notifier(fn, pri) -#define __hotcpu_notifier(fn, pri) __cpu_notifier(fn, pri) -#define register_hotcpu_notifier(nb) register_cpu_notifier(nb) -#define __register_hotcpu_notifier(nb) __register_cpu_notifier(nb) -#define unregister_hotcpu_notifier(nb) unregister_cpu_notifier(nb) -#define __unregister_hotcpu_notifier(nb) __unregister_cpu_notifier(nb) -void clear_tasks_mm_cpumask(int cpu); -int cpu_down(unsigned int cpu); - -#else /* CONFIG_HOTPLUG_CPU */ - -static inline void cpu_hotplug_begin(void) {} -static inline void cpu_hotplug_done(void) {} -#define get_online_cpus() do { } while (0) -#define put_online_cpus() do { } while (0) -#define cpu_hotplug_disable() do { } while (0) -#define cpu_hotplug_enable() do { } while (0) -#define hotcpu_notifier(fn, pri) do { (void)(fn); } while (0) -#define __hotcpu_notifier(fn, pri) do { (void)(fn); } while (0) -/* These aren't inline functions due to a GCC bug. */ -#define register_hotcpu_notifier(nb) ({ (void)(nb); 0; }) -#define __register_hotcpu_notifier(nb) ({ (void)(nb); 0; }) -#define unregister_hotcpu_notifier(nb) ({ (void)(nb); }) -#define __unregister_hotcpu_notifier(nb) ({ (void)(nb); }) -#endif /* CONFIG_HOTPLUG_CPU */ - -#ifdef CONFIG_PM_SLEEP_SMP -extern int freeze_secondary_cpus(int primary); -static inline int disable_nonboot_cpus(void) -{ - return freeze_secondary_cpus(0); -} -extern void enable_nonboot_cpus(void); -#else /* !CONFIG_PM_SLEEP_SMP */ -static inline int disable_nonboot_cpus(void) { return 0; } -static inline void enable_nonboot_cpus(void) {} -#endif /* !CONFIG_PM_SLEEP_SMP */ - -void cpu_startup_entry(enum cpuhp_state state); - -void cpu_idle_poll_ctrl(bool enable); - -/* Attach to any functions which should be considered cpuidle. */ -#define __cpuidle __attribute__((__section__(".cpuidle.text"))) - -bool cpu_in_idle(unsigned long pc); - -void arch_cpu_idle(void); -void arch_cpu_idle_prepare(void); -void arch_cpu_idle_enter(void); -void arch_cpu_idle_exit(void); -void arch_cpu_idle_dead(void); - -int cpu_report_state(int cpu); -int cpu_check_up_prepare(int cpu); -void cpu_set_state_online(int cpu); -#ifdef CONFIG_HOTPLUG_CPU -bool cpu_wait_death(unsigned int cpu, int seconds); -bool cpu_report_death(void); -void cpuhp_report_idle_dead(void); -#else -static inline void cpuhp_report_idle_dead(void) { } -#endif /* #ifdef CONFIG_HOTPLUG_CPU */ - -void cpu_yield_to_irqs(void); - -#endif /* _LINUX_CPU_H_ */ diff --git a/src/linux/include/linux/cpu_rmap.h b/src/linux/include/linux/cpu_rmap.h deleted file mode 100644 index bdd18ca..0000000 --- a/src/linux/include/linux/cpu_rmap.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef __LINUX_CPU_RMAP_H -#define __LINUX_CPU_RMAP_H - -/* - * cpu_rmap.c: CPU affinity reverse-map support - * Copyright 2011 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. - */ - -#include -#include -#include -#include - -/** - * struct cpu_rmap - CPU affinity reverse-map - * @refcount: kref for object - * @size: Number of objects to be reverse-mapped - * @used: Number of objects added - * @obj: Pointer to array of object pointers - * @near: For each CPU, the index and distance to the nearest object, - * based on affinity masks - */ -struct cpu_rmap { - struct kref refcount; - u16 size, used; - void **obj; - struct { - u16 index; - u16 dist; - } near[0]; -}; -#define CPU_RMAP_DIST_INF 0xffff - -extern struct cpu_rmap *alloc_cpu_rmap(unsigned int size, gfp_t flags); -extern int cpu_rmap_put(struct cpu_rmap *rmap); - -extern int cpu_rmap_add(struct cpu_rmap *rmap, void *obj); -extern int cpu_rmap_update(struct cpu_rmap *rmap, u16 index, - const struct cpumask *affinity); - -static inline u16 cpu_rmap_lookup_index(struct cpu_rmap *rmap, unsigned int cpu) -{ - return rmap->near[cpu].index; -} - -static inline void *cpu_rmap_lookup_obj(struct cpu_rmap *rmap, unsigned int cpu) -{ - return rmap->obj[rmap->near[cpu].index]; -} - -/** - * alloc_irq_cpu_rmap - allocate CPU affinity reverse-map for IRQs - * @size: Number of objects to be mapped - * - * Must be called in process context. - */ -static inline struct cpu_rmap *alloc_irq_cpu_rmap(unsigned int size) -{ - return alloc_cpu_rmap(size, GFP_KERNEL); -} -extern void free_irq_cpu_rmap(struct cpu_rmap *rmap); - -extern int irq_cpu_rmap_add(struct cpu_rmap *rmap, int irq); - -#endif /* __LINUX_CPU_RMAP_H */ diff --git a/src/linux/include/linux/cpufeature.h b/src/linux/include/linux/cpufeature.h deleted file mode 100644 index 986c06c..0000000 --- a/src/linux/include/linux/cpufeature.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2014 Linaro Ltd. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef __LINUX_CPUFEATURE_H -#define __LINUX_CPUFEATURE_H - -#ifdef CONFIG_GENERIC_CPU_AUTOPROBE - -#include -#include -#include - -/* - * Macros imported from : - * - cpu_feature(x) ordinal value of feature called 'x' - * - cpu_have_feature(u32 n) whether feature #n is available - * - MAX_CPU_FEATURES upper bound for feature ordinal values - * Optional: - * - CPU_FEATURE_TYPEFMT format string fragment for printing the cpu type - * - CPU_FEATURE_TYPEVAL set of values matching the format string above - */ - -#ifndef CPU_FEATURE_TYPEFMT -#define CPU_FEATURE_TYPEFMT "%s" -#endif - -#ifndef CPU_FEATURE_TYPEVAL -#define CPU_FEATURE_TYPEVAL ELF_PLATFORM -#endif - -/* - * Use module_cpu_feature_match(feature, module_init_function) to - * declare that - * a) the module shall be probed upon discovery of CPU feature 'feature' - * (typically at boot time using udev) - * b) the module must not be loaded if CPU feature 'feature' is not present - * (not even by manual insmod). - * - * For a list of legal values for 'feature', please consult the file - * 'asm/cpufeature.h' of your favorite architecture. - */ -#define module_cpu_feature_match(x, __initfunc) \ -static struct cpu_feature const cpu_feature_match_ ## x[] = \ - { { .feature = cpu_feature(x) }, { } }; \ -MODULE_DEVICE_TABLE(cpu, cpu_feature_match_ ## x); \ - \ -static int __init cpu_feature_match_ ## x ## _init(void) \ -{ \ - if (!cpu_have_feature(cpu_feature(x))) \ - return -ENODEV; \ - return __initfunc(); \ -} \ -module_init(cpu_feature_match_ ## x ## _init) - -#endif -#endif diff --git a/src/linux/include/linux/cpuhotplug.h b/src/linux/include/linux/cpuhotplug.h deleted file mode 100644 index afe641c..0000000 --- a/src/linux/include/linux/cpuhotplug.h +++ /dev/null @@ -1,307 +0,0 @@ -#ifndef __CPUHOTPLUG_H -#define __CPUHOTPLUG_H - -#include - -enum cpuhp_state { - CPUHP_OFFLINE, - CPUHP_CREATE_THREADS, - CPUHP_PERF_PREPARE, - CPUHP_PERF_X86_PREPARE, - CPUHP_PERF_X86_UNCORE_PREP, - CPUHP_PERF_X86_AMD_UNCORE_PREP, - CPUHP_PERF_X86_RAPL_PREP, - CPUHP_PERF_BFIN, - CPUHP_PERF_POWER, - CPUHP_PERF_SUPERH, - CPUHP_X86_HPET_DEAD, - CPUHP_X86_APB_DEAD, - CPUHP_VIRT_NET_DEAD, - CPUHP_SLUB_DEAD, - CPUHP_MM_WRITEBACK_DEAD, - CPUHP_SOFTIRQ_DEAD, - CPUHP_NET_MVNETA_DEAD, - CPUHP_CPUIDLE_DEAD, - CPUHP_ARM64_FPSIMD_DEAD, - CPUHP_ARM_OMAP_WAKE_DEAD, - CPUHP_IRQ_POLL_DEAD, - CPUHP_BLOCK_SOFTIRQ_DEAD, - CPUHP_VIRT_SCSI_DEAD, - CPUHP_ACPI_CPUDRV_DEAD, - CPUHP_S390_PFAULT_DEAD, - CPUHP_BLK_MQ_DEAD, - CPUHP_WORKQUEUE_PREP, - CPUHP_POWER_NUMA_PREPARE, - CPUHP_HRTIMERS_PREPARE, - CPUHP_PROFILE_PREPARE, - CPUHP_X2APIC_PREPARE, - CPUHP_SMPCFD_PREPARE, - CPUHP_RELAY_PREPARE, - CPUHP_SLAB_PREPARE, - CPUHP_MD_RAID5_PREPARE, - CPUHP_RCUTREE_PREP, - CPUHP_CPUIDLE_COUPLED_PREPARE, - CPUHP_POWERPC_PMAC_PREPARE, - CPUHP_POWERPC_MMU_CTX_PREPARE, - CPUHP_XEN_PREPARE, - CPUHP_XEN_EVTCHN_PREPARE, - CPUHP_NOTIFY_PREPARE, - CPUHP_ARM_SHMOBILE_SCU_PREPARE, - CPUHP_SH_SH3X_PREPARE, - CPUHP_BLK_MQ_PREPARE, - CPUHP_TIMERS_DEAD, - CPUHP_NOTF_ERR_INJ_PREPARE, - CPUHP_MIPS_SOC_PREPARE, - CPUHP_BRINGUP_CPU, - CPUHP_AP_IDLE_DEAD, - CPUHP_AP_OFFLINE, - CPUHP_AP_SCHED_STARTING, - CPUHP_AP_RCUTREE_DYING, - CPUHP_AP_IRQ_GIC_STARTING, - CPUHP_AP_IRQ_GICV3_STARTING, - CPUHP_AP_IRQ_HIP04_STARTING, - CPUHP_AP_IRQ_ARMADA_XP_STARTING, - CPUHP_AP_IRQ_ARMADA_CASC_STARTING, - CPUHP_AP_IRQ_BCM2836_STARTING, - CPUHP_AP_ARM_MVEBU_COHERENCY, - CPUHP_AP_PERF_X86_UNCORE_STARTING, - CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING, - CPUHP_AP_PERF_X86_STARTING, - CPUHP_AP_PERF_X86_AMD_IBS_STARTING, - CPUHP_AP_PERF_X86_CQM_STARTING, - CPUHP_AP_PERF_X86_CSTATE_STARTING, - CPUHP_AP_PERF_XTENSA_STARTING, - CPUHP_AP_PERF_METAG_STARTING, - CPUHP_AP_MIPS_OP_LOONGSON3_STARTING, - CPUHP_AP_ARM_VFP_STARTING, - CPUHP_AP_ARM64_DEBUG_MONITORS_STARTING, - CPUHP_AP_PERF_ARM_HW_BREAKPOINT_STARTING, - CPUHP_AP_PERF_ARM_STARTING, - CPUHP_AP_ARM_L2X0_STARTING, - CPUHP_AP_ARM_ARCH_TIMER_STARTING, - CPUHP_AP_ARM_GLOBAL_TIMER_STARTING, - CPUHP_AP_DUMMY_TIMER_STARTING, - CPUHP_AP_JCORE_TIMER_STARTING, - CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING, - CPUHP_AP_ARM_TWD_STARTING, - CPUHP_AP_METAG_TIMER_STARTING, - CPUHP_AP_QCOM_TIMER_STARTING, - CPUHP_AP_ARMADA_TIMER_STARTING, - CPUHP_AP_MARCO_TIMER_STARTING, - CPUHP_AP_MIPS_GIC_TIMER_STARTING, - CPUHP_AP_ARC_TIMER_STARTING, - CPUHP_AP_KVM_STARTING, - CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING, - CPUHP_AP_KVM_ARM_VGIC_STARTING, - CPUHP_AP_KVM_ARM_TIMER_STARTING, - CPUHP_AP_ARM_XEN_STARTING, - CPUHP_AP_ARM_CORESIGHT_STARTING, - CPUHP_AP_ARM_CORESIGHT4_STARTING, - CPUHP_AP_ARM64_ISNDEP_STARTING, - CPUHP_AP_SMPCFD_DYING, - CPUHP_AP_X86_TBOOT_DYING, - CPUHP_AP_ONLINE, - CPUHP_TEARDOWN_CPU, - CPUHP_AP_ONLINE_IDLE, - CPUHP_AP_SMPBOOT_THREADS, - CPUHP_AP_X86_VDSO_VMA_ONLINE, - CPUHP_AP_PERF_ONLINE, - CPUHP_AP_PERF_X86_ONLINE, - CPUHP_AP_PERF_X86_UNCORE_ONLINE, - CPUHP_AP_PERF_X86_AMD_UNCORE_ONLINE, - CPUHP_AP_PERF_X86_AMD_POWER_ONLINE, - CPUHP_AP_PERF_X86_RAPL_ONLINE, - CPUHP_AP_PERF_X86_CQM_ONLINE, - CPUHP_AP_PERF_X86_CSTATE_ONLINE, - CPUHP_AP_PERF_S390_CF_ONLINE, - CPUHP_AP_PERF_S390_SF_ONLINE, - CPUHP_AP_PERF_ARM_CCI_ONLINE, - CPUHP_AP_PERF_ARM_CCN_ONLINE, - CPUHP_AP_PERF_ARM_L2X0_ONLINE, - CPUHP_AP_WORKQUEUE_ONLINE, - CPUHP_AP_RCUTREE_ONLINE, - CPUHP_AP_NOTIFY_ONLINE, - CPUHP_AP_ONLINE_DYN, - CPUHP_AP_ONLINE_DYN_END = CPUHP_AP_ONLINE_DYN + 30, - CPUHP_AP_X86_HPET_ONLINE, - CPUHP_AP_X86_KVM_CLK_ONLINE, - CPUHP_AP_ACTIVE, - CPUHP_ONLINE, -}; - -int __cpuhp_setup_state(enum cpuhp_state state, const char *name, bool invoke, - int (*startup)(unsigned int cpu), - int (*teardown)(unsigned int cpu), bool multi_instance); - -/** - * cpuhp_setup_state - Setup hotplug state callbacks with calling the callbacks - * @state: The state for which the calls are installed - * @name: Name of the callback (will be used in debug output) - * @startup: startup callback function - * @teardown: teardown callback function - * - * Installs the callback functions and invokes the startup callback on - * the present cpus which have already reached the @state. - */ -static inline int cpuhp_setup_state(enum cpuhp_state state, - const char *name, - int (*startup)(unsigned int cpu), - int (*teardown)(unsigned int cpu)) -{ - return __cpuhp_setup_state(state, name, true, startup, teardown, false); -} - -/** - * cpuhp_setup_state_nocalls - Setup hotplug state callbacks without calling the - * callbacks - * @state: The state for which the calls are installed - * @name: Name of the callback. - * @startup: startup callback function - * @teardown: teardown callback function - * - * Same as @cpuhp_setup_state except that no calls are executed are invoked - * during installation of this callback. NOP if SMP=n or HOTPLUG_CPU=n. - */ -static inline int cpuhp_setup_state_nocalls(enum cpuhp_state state, - const char *name, - int (*startup)(unsigned int cpu), - int (*teardown)(unsigned int cpu)) -{ - return __cpuhp_setup_state(state, name, false, startup, teardown, - false); -} - -/** - * cpuhp_setup_state_multi - Add callbacks for multi state - * @state: The state for which the calls are installed - * @name: Name of the callback. - * @startup: startup callback function - * @teardown: teardown callback function - * - * Sets the internal multi_instance flag and prepares a state to work as a multi - * instance callback. No callbacks are invoked at this point. The callbacks are - * invoked once an instance for this state are registered via - * @cpuhp_state_add_instance or @cpuhp_state_add_instance_nocalls. - */ -static inline int cpuhp_setup_state_multi(enum cpuhp_state state, - const char *name, - int (*startup)(unsigned int cpu, - struct hlist_node *node), - int (*teardown)(unsigned int cpu, - struct hlist_node *node)) -{ - return __cpuhp_setup_state(state, name, false, - (void *) startup, - (void *) teardown, true); -} - -int __cpuhp_state_add_instance(enum cpuhp_state state, struct hlist_node *node, - bool invoke); - -/** - * cpuhp_state_add_instance - Add an instance for a state and invoke startup - * callback. - * @state: The state for which the instance is installed - * @node: The node for this individual state. - * - * Installs the instance for the @state and invokes the startup callback on - * the present cpus which have already reached the @state. The @state must have - * been earlier marked as multi-instance by @cpuhp_setup_state_multi. - */ -static inline int cpuhp_state_add_instance(enum cpuhp_state state, - struct hlist_node *node) -{ - return __cpuhp_state_add_instance(state, node, true); -} - -/** - * cpuhp_state_add_instance_nocalls - Add an instance for a state without - * invoking the startup callback. - * @state: The state for which the instance is installed - * @node: The node for this individual state. - * - * Installs the instance for the @state The @state must have been earlier - * marked as multi-instance by @cpuhp_setup_state_multi. - */ -static inline int cpuhp_state_add_instance_nocalls(enum cpuhp_state state, - struct hlist_node *node) -{ - return __cpuhp_state_add_instance(state, node, false); -} - -void __cpuhp_remove_state(enum cpuhp_state state, bool invoke); - -/** - * cpuhp_remove_state - Remove hotplug state callbacks and invoke the teardown - * @state: The state for which the calls are removed - * - * Removes the callback functions and invokes the teardown callback on - * the present cpus which have already reached the @state. - */ -static inline void cpuhp_remove_state(enum cpuhp_state state) -{ - __cpuhp_remove_state(state, true); -} - -/** - * cpuhp_remove_state_nocalls - Remove hotplug state callbacks without invoking - * teardown - * @state: The state for which the calls are removed - */ -static inline void cpuhp_remove_state_nocalls(enum cpuhp_state state) -{ - __cpuhp_remove_state(state, false); -} - -/** - * cpuhp_remove_multi_state - Remove hotplug multi state callback - * @state: The state for which the calls are removed - * - * Removes the callback functions from a multi state. This is the reverse of - * cpuhp_setup_state_multi(). All instances should have been removed before - * invoking this function. - */ -static inline void cpuhp_remove_multi_state(enum cpuhp_state state) -{ - __cpuhp_remove_state(state, false); -} - -int __cpuhp_state_remove_instance(enum cpuhp_state state, - struct hlist_node *node, bool invoke); - -/** - * cpuhp_state_remove_instance - Remove hotplug instance from state and invoke - * the teardown callback - * @state: The state from which the instance is removed - * @node: The node for this individual state. - * - * Removes the instance and invokes the teardown callback on the present cpus - * which have already reached the @state. - */ -static inline int cpuhp_state_remove_instance(enum cpuhp_state state, - struct hlist_node *node) -{ - return __cpuhp_state_remove_instance(state, node, true); -} - -/** - * cpuhp_state_remove_instance_nocalls - Remove hotplug instance from state - * without invoking the reatdown callback - * @state: The state from which the instance is removed - * @node: The node for this individual state. - * - * Removes the instance without invoking the teardown callback. - */ -static inline int cpuhp_state_remove_instance_nocalls(enum cpuhp_state state, - struct hlist_node *node) -{ - return __cpuhp_state_remove_instance(state, node, false); -} - -#ifdef CONFIG_SMP -void cpuhp_online_idle(enum cpuhp_state state); -#else -static inline void cpuhp_online_idle(enum cpuhp_state state) { } -#endif - -#endif diff --git a/src/linux/include/linux/cpuidle.h b/src/linux/include/linux/cpuidle.h deleted file mode 100644 index bb31373..0000000 --- a/src/linux/include/linux/cpuidle.h +++ /dev/null @@ -1,273 +0,0 @@ -/* - * cpuidle.h - a generic framework for CPU idle power management - * - * (C) 2007 Venkatesh Pallipadi - * Shaohua Li - * Adam Belay - * - * This code is licenced under the GPL. - */ - -#ifndef _LINUX_CPUIDLE_H -#define _LINUX_CPUIDLE_H - -#include -#include -#include - -#define CPUIDLE_STATE_MAX 10 -#define CPUIDLE_NAME_LEN 16 -#define CPUIDLE_DESC_LEN 32 - -struct module; - -struct cpuidle_device; -struct cpuidle_driver; - - -/**************************** - * CPUIDLE DEVICE INTERFACE * - ****************************/ - -struct cpuidle_state_usage { - unsigned long long disable; - unsigned long long usage; - unsigned long long time; /* in US */ -}; - -struct cpuidle_state { - char name[CPUIDLE_NAME_LEN]; - char desc[CPUIDLE_DESC_LEN]; - - unsigned int flags; - unsigned int exit_latency; /* in US */ - int power_usage; /* in mW */ - unsigned int target_residency; /* in US */ - bool disabled; /* disabled on all CPUs */ - - int (*enter) (struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index); - - int (*enter_dead) (struct cpuidle_device *dev, int index); - - /* - * CPUs execute ->enter_freeze with the local tick or entire timekeeping - * suspended, so it must not re-enable interrupts at any point (even - * temporarily) or attempt to change states of clock event devices. - */ - void (*enter_freeze) (struct cpuidle_device *dev, - struct cpuidle_driver *drv, - int index); -}; - -/* Idle State Flags */ -#define CPUIDLE_FLAG_COUPLED (0x02) /* state applies to multiple cpus */ -#define CPUIDLE_FLAG_TIMER_STOP (0x04) /* timer is stopped on this state */ - -#define CPUIDLE_DRIVER_FLAGS_MASK (0xFFFF0000) - -struct cpuidle_device_kobj; -struct cpuidle_state_kobj; -struct cpuidle_driver_kobj; - -struct cpuidle_device { - unsigned int registered:1; - unsigned int enabled:1; - unsigned int cpu; - - int last_residency; - struct cpuidle_state_usage states_usage[CPUIDLE_STATE_MAX]; - struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX]; - struct cpuidle_driver_kobj *kobj_driver; - struct cpuidle_device_kobj *kobj_dev; - struct list_head device_list; - -#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED - cpumask_t coupled_cpus; - struct cpuidle_coupled *coupled; -#endif -}; - -DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices); -DECLARE_PER_CPU(struct cpuidle_device, cpuidle_dev); - -/** - * cpuidle_get_last_residency - retrieves the last state's residency time - * @dev: the target CPU - */ -static inline int cpuidle_get_last_residency(struct cpuidle_device *dev) -{ - return dev->last_residency; -} - - -/**************************** - * CPUIDLE DRIVER INTERFACE * - ****************************/ - -struct cpuidle_driver { - const char *name; - struct module *owner; - int refcnt; - - /* used by the cpuidle framework to setup the broadcast timer */ - unsigned int bctimer:1; - /* states array must be ordered in decreasing power consumption */ - struct cpuidle_state states[CPUIDLE_STATE_MAX]; - int state_count; - int safe_state_index; - - /* the driver handles the cpus in cpumask */ - struct cpumask *cpumask; -}; - -#ifdef CONFIG_CPU_IDLE -extern void disable_cpuidle(void); -extern bool cpuidle_not_available(struct cpuidle_driver *drv, - struct cpuidle_device *dev); - -extern int cpuidle_select(struct cpuidle_driver *drv, - struct cpuidle_device *dev); -extern int cpuidle_enter(struct cpuidle_driver *drv, - struct cpuidle_device *dev, int index); -extern void cpuidle_reflect(struct cpuidle_device *dev, int index); - -extern int cpuidle_register_driver(struct cpuidle_driver *drv); -extern struct cpuidle_driver *cpuidle_get_driver(void); -extern struct cpuidle_driver *cpuidle_driver_ref(void); -extern void cpuidle_driver_unref(void); -extern void cpuidle_unregister_driver(struct cpuidle_driver *drv); -extern int cpuidle_register_device(struct cpuidle_device *dev); -extern void cpuidle_unregister_device(struct cpuidle_device *dev); -extern int cpuidle_register(struct cpuidle_driver *drv, - const struct cpumask *const coupled_cpus); -extern void cpuidle_unregister(struct cpuidle_driver *drv); -extern void cpuidle_pause_and_lock(void); -extern void cpuidle_resume_and_unlock(void); -extern void cpuidle_pause(void); -extern void cpuidle_resume(void); -extern int cpuidle_enable_device(struct cpuidle_device *dev); -extern void cpuidle_disable_device(struct cpuidle_device *dev); -extern int cpuidle_play_dead(void); - -extern struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev); -static inline struct cpuidle_device *cpuidle_get_device(void) -{return __this_cpu_read(cpuidle_devices); } -#else -static inline void disable_cpuidle(void) { } -static inline bool cpuidle_not_available(struct cpuidle_driver *drv, - struct cpuidle_device *dev) -{return true; } -static inline int cpuidle_select(struct cpuidle_driver *drv, - struct cpuidle_device *dev) -{return -ENODEV; } -static inline int cpuidle_enter(struct cpuidle_driver *drv, - struct cpuidle_device *dev, int index) -{return -ENODEV; } -static inline void cpuidle_reflect(struct cpuidle_device *dev, int index) { } -static inline int cpuidle_register_driver(struct cpuidle_driver *drv) -{return -ENODEV; } -static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; } -static inline struct cpuidle_driver *cpuidle_driver_ref(void) {return NULL; } -static inline void cpuidle_driver_unref(void) {} -static inline void cpuidle_unregister_driver(struct cpuidle_driver *drv) { } -static inline int cpuidle_register_device(struct cpuidle_device *dev) -{return -ENODEV; } -static inline void cpuidle_unregister_device(struct cpuidle_device *dev) { } -static inline int cpuidle_register(struct cpuidle_driver *drv, - const struct cpumask *const coupled_cpus) -{return -ENODEV; } -static inline void cpuidle_unregister(struct cpuidle_driver *drv) { } -static inline void cpuidle_pause_and_lock(void) { } -static inline void cpuidle_resume_and_unlock(void) { } -static inline void cpuidle_pause(void) { } -static inline void cpuidle_resume(void) { } -static inline int cpuidle_enable_device(struct cpuidle_device *dev) -{return -ENODEV; } -static inline void cpuidle_disable_device(struct cpuidle_device *dev) { } -static inline int cpuidle_play_dead(void) {return -ENODEV; } -static inline struct cpuidle_driver *cpuidle_get_cpu_driver( - struct cpuidle_device *dev) {return NULL; } -static inline struct cpuidle_device *cpuidle_get_device(void) {return NULL; } -#endif - -#if defined(CONFIG_CPU_IDLE) && defined(CONFIG_SUSPEND) -extern int cpuidle_find_deepest_state(struct cpuidle_driver *drv, - struct cpuidle_device *dev); -extern int cpuidle_enter_freeze(struct cpuidle_driver *drv, - struct cpuidle_device *dev); -#else -static inline int cpuidle_find_deepest_state(struct cpuidle_driver *drv, - struct cpuidle_device *dev) -{return -ENODEV; } -static inline int cpuidle_enter_freeze(struct cpuidle_driver *drv, - struct cpuidle_device *dev) -{return -ENODEV; } -#endif - -/* kernel/sched/idle.c */ -extern void sched_idle_set_state(struct cpuidle_state *idle_state); -extern void default_idle_call(void); - -#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED -void cpuidle_coupled_parallel_barrier(struct cpuidle_device *dev, atomic_t *a); -#else -static inline void cpuidle_coupled_parallel_barrier(struct cpuidle_device *dev, atomic_t *a) -{ -} -#endif - -/****************************** - * CPUIDLE GOVERNOR INTERFACE * - ******************************/ - -struct cpuidle_governor { - char name[CPUIDLE_NAME_LEN]; - struct list_head governor_list; - unsigned int rating; - - int (*enable) (struct cpuidle_driver *drv, - struct cpuidle_device *dev); - void (*disable) (struct cpuidle_driver *drv, - struct cpuidle_device *dev); - - int (*select) (struct cpuidle_driver *drv, - struct cpuidle_device *dev); - void (*reflect) (struct cpuidle_device *dev, int index); - - struct module *owner; -}; - -#ifdef CONFIG_CPU_IDLE -extern int cpuidle_register_governor(struct cpuidle_governor *gov); -#else -static inline int cpuidle_register_governor(struct cpuidle_governor *gov) -{return 0;} -#endif - -#ifdef CONFIG_ARCH_HAS_CPU_RELAX -#define CPUIDLE_DRIVER_STATE_START 1 -#else -#define CPUIDLE_DRIVER_STATE_START 0 -#endif - -#define CPU_PM_CPU_IDLE_ENTER(low_level_idle_enter, idx) \ -({ \ - int __ret; \ - \ - if (!idx) { \ - cpu_do_idle(); \ - return idx; \ - } \ - \ - __ret = cpu_pm_enter(); \ - if (!__ret) { \ - __ret = low_level_idle_enter(idx); \ - cpu_pm_exit(); \ - } \ - \ - __ret ? -1 : idx; \ -}) - -#endif /* _LINUX_CPUIDLE_H */ diff --git a/src/linux/include/linux/cpumask.h b/src/linux/include/linux/cpumask.h deleted file mode 100644 index da7fbf1..0000000 --- a/src/linux/include/linux/cpumask.h +++ /dev/null @@ -1,855 +0,0 @@ -#ifndef __LINUX_CPUMASK_H -#define __LINUX_CPUMASK_H - -/* - * Cpumasks provide a bitmap suitable for representing the - * set of CPU's in a system, one bit position per CPU number. In general, - * only nr_cpu_ids (<= NR_CPUS) bits are valid. - */ -#include -#include -#include -#include - -/* Don't assign or return these: may not be this big! */ -typedef struct cpumask { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t; - -/** - * cpumask_bits - get the bits in a cpumask - * @maskp: the struct cpumask * - * - * You should only assume nr_cpu_ids bits of this mask are valid. This is - * a macro so it's const-correct. - */ -#define cpumask_bits(maskp) ((maskp)->bits) - -/** - * cpumask_pr_args - printf args to output a cpumask - * @maskp: cpumask to be printed - * - * Can be used to provide arguments for '%*pb[l]' when printing a cpumask. - */ -#define cpumask_pr_args(maskp) nr_cpu_ids, cpumask_bits(maskp) - -#if NR_CPUS == 1 -#define nr_cpu_ids 1 -#else -extern int nr_cpu_ids; -#endif - -#ifdef CONFIG_CPUMASK_OFFSTACK -/* Assuming NR_CPUS is huge, a runtime limit is more efficient. Also, - * not all bits may be allocated. */ -#define nr_cpumask_bits nr_cpu_ids -#else -#define nr_cpumask_bits NR_CPUS -#endif - -/* - * The following particular system cpumasks and operations manage - * possible, present, active and online cpus. - * - * cpu_possible_mask- has bit 'cpu' set iff cpu is populatable - * cpu_present_mask - has bit 'cpu' set iff cpu is populated - * cpu_online_mask - has bit 'cpu' set iff cpu available to scheduler - * cpu_active_mask - has bit 'cpu' set iff cpu available to migration - * - * If !CONFIG_HOTPLUG_CPU, present == possible, and active == online. - * - * The cpu_possible_mask is fixed at boot time, as the set of CPU id's - * that it is possible might ever be plugged in at anytime during the - * life of that system boot. The cpu_present_mask is dynamic(*), - * representing which CPUs are currently plugged in. And - * cpu_online_mask is the dynamic subset of cpu_present_mask, - * indicating those CPUs available for scheduling. - * - * If HOTPLUG is enabled, then cpu_possible_mask is forced to have - * all NR_CPUS bits set, otherwise it is just the set of CPUs that - * ACPI reports present at boot. - * - * If HOTPLUG is enabled, then cpu_present_mask varies dynamically, - * depending on what ACPI reports as currently plugged in, otherwise - * cpu_present_mask is just a copy of cpu_possible_mask. - * - * (*) Well, cpu_present_mask is dynamic in the hotplug case. If not - * hotplug, it's a copy of cpu_possible_mask, hence fixed at boot. - * - * Subtleties: - * 1) UP arch's (NR_CPUS == 1, CONFIG_SMP not defined) hardcode - * assumption that their single CPU is online. The UP - * cpu_{online,possible,present}_masks are placebos. Changing them - * will have no useful affect on the following num_*_cpus() - * and cpu_*() macros in the UP case. This ugliness is a UP - * optimization - don't waste any instructions or memory references - * asking if you're online or how many CPUs there are if there is - * only one CPU. - */ - -extern struct cpumask __cpu_possible_mask; -extern struct cpumask __cpu_online_mask; -extern struct cpumask __cpu_present_mask; -extern struct cpumask __cpu_active_mask; -#define cpu_possible_mask ((const struct cpumask *)&__cpu_possible_mask) -#define cpu_online_mask ((const struct cpumask *)&__cpu_online_mask) -#define cpu_present_mask ((const struct cpumask *)&__cpu_present_mask) -#define cpu_active_mask ((const struct cpumask *)&__cpu_active_mask) - -#if NR_CPUS > 1 -#define num_online_cpus() cpumask_weight(cpu_online_mask) -#define num_possible_cpus() cpumask_weight(cpu_possible_mask) -#define num_present_cpus() cpumask_weight(cpu_present_mask) -#define num_active_cpus() cpumask_weight(cpu_active_mask) -#define cpu_online(cpu) cpumask_test_cpu((cpu), cpu_online_mask) -#define cpu_possible(cpu) cpumask_test_cpu((cpu), cpu_possible_mask) -#define cpu_present(cpu) cpumask_test_cpu((cpu), cpu_present_mask) -#define cpu_active(cpu) cpumask_test_cpu((cpu), cpu_active_mask) -#else -#define num_online_cpus() 1U -#define num_possible_cpus() 1U -#define num_present_cpus() 1U -#define num_active_cpus() 1U -#define cpu_online(cpu) ((cpu) == 0) -#define cpu_possible(cpu) ((cpu) == 0) -#define cpu_present(cpu) ((cpu) == 0) -#define cpu_active(cpu) ((cpu) == 0) -#endif - -/* verify cpu argument to cpumask_* operators */ -static inline unsigned int cpumask_check(unsigned int cpu) -{ -#ifdef CONFIG_DEBUG_PER_CPU_MAPS - WARN_ON_ONCE(cpu >= nr_cpumask_bits); -#endif /* CONFIG_DEBUG_PER_CPU_MAPS */ - return cpu; -} - -#if NR_CPUS == 1 -/* Uniprocessor. Assume all masks are "1". */ -static inline unsigned int cpumask_first(const struct cpumask *srcp) -{ - return 0; -} - -/* Valid inputs for n are -1 and 0. */ -static inline unsigned int cpumask_next(int n, const struct cpumask *srcp) -{ - return n+1; -} - -static inline unsigned int cpumask_next_zero(int n, const struct cpumask *srcp) -{ - return n+1; -} - -static inline unsigned int cpumask_next_and(int n, - const struct cpumask *srcp, - const struct cpumask *andp) -{ - return n+1; -} - -/* cpu must be a valid cpu, ie 0, so there's no other choice. */ -static inline unsigned int cpumask_any_but(const struct cpumask *mask, - unsigned int cpu) -{ - return 1; -} - -static inline unsigned int cpumask_local_spread(unsigned int i, int node) -{ - return 0; -} - -#define for_each_cpu(cpu, mask) \ - for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask) -#define for_each_cpu_not(cpu, mask) \ - for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask) -#define for_each_cpu_and(cpu, mask, and) \ - for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask, (void)and) -#else -/** - * cpumask_first - get the first cpu in a cpumask - * @srcp: the cpumask pointer - * - * Returns >= nr_cpu_ids if no cpus set. - */ -static inline unsigned int cpumask_first(const struct cpumask *srcp) -{ - return find_first_bit(cpumask_bits(srcp), nr_cpumask_bits); -} - -/** - * cpumask_next - get the next cpu in a cpumask - * @n: the cpu prior to the place to search (ie. return will be > @n) - * @srcp: the cpumask pointer - * - * Returns >= nr_cpu_ids if no further cpus set. - */ -static inline unsigned int cpumask_next(int n, const struct cpumask *srcp) -{ - /* -1 is a legal arg here. */ - if (n != -1) - cpumask_check(n); - return find_next_bit(cpumask_bits(srcp), nr_cpumask_bits, n+1); -} - -/** - * cpumask_next_zero - get the next unset cpu in a cpumask - * @n: the cpu prior to the place to search (ie. return will be > @n) - * @srcp: the cpumask pointer - * - * Returns >= nr_cpu_ids if no further cpus unset. - */ -static inline unsigned int cpumask_next_zero(int n, const struct cpumask *srcp) -{ - /* -1 is a legal arg here. */ - if (n != -1) - cpumask_check(n); - return find_next_zero_bit(cpumask_bits(srcp), nr_cpumask_bits, n+1); -} - -int cpumask_next_and(int n, const struct cpumask *, const struct cpumask *); -int cpumask_any_but(const struct cpumask *mask, unsigned int cpu); -unsigned int cpumask_local_spread(unsigned int i, int node); - -/** - * for_each_cpu - iterate over every cpu in a mask - * @cpu: the (optionally unsigned) integer iterator - * @mask: the cpumask pointer - * - * After the loop, cpu is >= nr_cpu_ids. - */ -#define for_each_cpu(cpu, mask) \ - for ((cpu) = -1; \ - (cpu) = cpumask_next((cpu), (mask)), \ - (cpu) < nr_cpu_ids;) - -/** - * for_each_cpu_not - iterate over every cpu in a complemented mask - * @cpu: the (optionally unsigned) integer iterator - * @mask: the cpumask pointer - * - * After the loop, cpu is >= nr_cpu_ids. - */ -#define for_each_cpu_not(cpu, mask) \ - for ((cpu) = -1; \ - (cpu) = cpumask_next_zero((cpu), (mask)), \ - (cpu) < nr_cpu_ids;) - -/** - * for_each_cpu_and - iterate over every cpu in both masks - * @cpu: the (optionally unsigned) integer iterator - * @mask: the first cpumask pointer - * @and: the second cpumask pointer - * - * This saves a temporary CPU mask in many places. It is equivalent to: - * struct cpumask tmp; - * cpumask_and(&tmp, &mask, &and); - * for_each_cpu(cpu, &tmp) - * ... - * - * After the loop, cpu is >= nr_cpu_ids. - */ -#define for_each_cpu_and(cpu, mask, and) \ - for ((cpu) = -1; \ - (cpu) = cpumask_next_and((cpu), (mask), (and)), \ - (cpu) < nr_cpu_ids;) -#endif /* SMP */ - -#define CPU_BITS_NONE \ -{ \ - [0 ... BITS_TO_LONGS(NR_CPUS)-1] = 0UL \ -} - -#define CPU_BITS_CPU0 \ -{ \ - [0] = 1UL \ -} - -/** - * cpumask_set_cpu - set a cpu in a cpumask - * @cpu: cpu number (< nr_cpu_ids) - * @dstp: the cpumask pointer - */ -static inline void cpumask_set_cpu(unsigned int cpu, struct cpumask *dstp) -{ - set_bit(cpumask_check(cpu), cpumask_bits(dstp)); -} - -/** - * cpumask_clear_cpu - clear a cpu in a cpumask - * @cpu: cpu number (< nr_cpu_ids) - * @dstp: the cpumask pointer - */ -static inline void cpumask_clear_cpu(int cpu, struct cpumask *dstp) -{ - clear_bit(cpumask_check(cpu), cpumask_bits(dstp)); -} - -/** - * cpumask_test_cpu - test for a cpu in a cpumask - * @cpu: cpu number (< nr_cpu_ids) - * @cpumask: the cpumask pointer - * - * Returns 1 if @cpu is set in @cpumask, else returns 0 - */ -static inline int cpumask_test_cpu(int cpu, const struct cpumask *cpumask) -{ - return test_bit(cpumask_check(cpu), cpumask_bits((cpumask))); -} - -/** - * cpumask_test_and_set_cpu - atomically test and set a cpu in a cpumask - * @cpu: cpu number (< nr_cpu_ids) - * @cpumask: the cpumask pointer - * - * Returns 1 if @cpu is set in old bitmap of @cpumask, else returns 0 - * - * test_and_set_bit wrapper for cpumasks. - */ -static inline int cpumask_test_and_set_cpu(int cpu, struct cpumask *cpumask) -{ - return test_and_set_bit(cpumask_check(cpu), cpumask_bits(cpumask)); -} - -/** - * cpumask_test_and_clear_cpu - atomically test and clear a cpu in a cpumask - * @cpu: cpu number (< nr_cpu_ids) - * @cpumask: the cpumask pointer - * - * Returns 1 if @cpu is set in old bitmap of @cpumask, else returns 0 - * - * test_and_clear_bit wrapper for cpumasks. - */ -static inline int cpumask_test_and_clear_cpu(int cpu, struct cpumask *cpumask) -{ - return test_and_clear_bit(cpumask_check(cpu), cpumask_bits(cpumask)); -} - -/** - * cpumask_setall - set all cpus (< nr_cpu_ids) in a cpumask - * @dstp: the cpumask pointer - */ -static inline void cpumask_setall(struct cpumask *dstp) -{ - bitmap_fill(cpumask_bits(dstp), nr_cpumask_bits); -} - -/** - * cpumask_clear - clear all cpus (< nr_cpu_ids) in a cpumask - * @dstp: the cpumask pointer - */ -static inline void cpumask_clear(struct cpumask *dstp) -{ - bitmap_zero(cpumask_bits(dstp), nr_cpumask_bits); -} - -/** - * cpumask_and - *dstp = *src1p & *src2p - * @dstp: the cpumask result - * @src1p: the first input - * @src2p: the second input - * - * If *@dstp is empty, returns 0, else returns 1 - */ -static inline int cpumask_and(struct cpumask *dstp, - const struct cpumask *src1p, - const struct cpumask *src2p) -{ - return bitmap_and(cpumask_bits(dstp), cpumask_bits(src1p), - cpumask_bits(src2p), nr_cpumask_bits); -} - -/** - * cpumask_or - *dstp = *src1p | *src2p - * @dstp: the cpumask result - * @src1p: the first input - * @src2p: the second input - */ -static inline void cpumask_or(struct cpumask *dstp, const struct cpumask *src1p, - const struct cpumask *src2p) -{ - bitmap_or(cpumask_bits(dstp), cpumask_bits(src1p), - cpumask_bits(src2p), nr_cpumask_bits); -} - -/** - * cpumask_xor - *dstp = *src1p ^ *src2p - * @dstp: the cpumask result - * @src1p: the first input - * @src2p: the second input - */ -static inline void cpumask_xor(struct cpumask *dstp, - const struct cpumask *src1p, - const struct cpumask *src2p) -{ - bitmap_xor(cpumask_bits(dstp), cpumask_bits(src1p), - cpumask_bits(src2p), nr_cpumask_bits); -} - -/** - * cpumask_andnot - *dstp = *src1p & ~*src2p - * @dstp: the cpumask result - * @src1p: the first input - * @src2p: the second input - * - * If *@dstp is empty, returns 0, else returns 1 - */ -static inline int cpumask_andnot(struct cpumask *dstp, - const struct cpumask *src1p, - const struct cpumask *src2p) -{ - return bitmap_andnot(cpumask_bits(dstp), cpumask_bits(src1p), - cpumask_bits(src2p), nr_cpumask_bits); -} - -/** - * cpumask_complement - *dstp = ~*srcp - * @dstp: the cpumask result - * @srcp: the input to invert - */ -static inline void cpumask_complement(struct cpumask *dstp, - const struct cpumask *srcp) -{ - bitmap_complement(cpumask_bits(dstp), cpumask_bits(srcp), - nr_cpumask_bits); -} - -/** - * cpumask_equal - *src1p == *src2p - * @src1p: the first input - * @src2p: the second input - */ -static inline bool cpumask_equal(const struct cpumask *src1p, - const struct cpumask *src2p) -{ - return bitmap_equal(cpumask_bits(src1p), cpumask_bits(src2p), - nr_cpumask_bits); -} - -/** - * cpumask_intersects - (*src1p & *src2p) != 0 - * @src1p: the first input - * @src2p: the second input - */ -static inline bool cpumask_intersects(const struct cpumask *src1p, - const struct cpumask *src2p) -{ - return bitmap_intersects(cpumask_bits(src1p), cpumask_bits(src2p), - nr_cpumask_bits); -} - -/** - * cpumask_subset - (*src1p & ~*src2p) == 0 - * @src1p: the first input - * @src2p: the second input - * - * Returns 1 if *@src1p is a subset of *@src2p, else returns 0 - */ -static inline int cpumask_subset(const struct cpumask *src1p, - const struct cpumask *src2p) -{ - return bitmap_subset(cpumask_bits(src1p), cpumask_bits(src2p), - nr_cpumask_bits); -} - -/** - * cpumask_empty - *srcp == 0 - * @srcp: the cpumask to that all cpus < nr_cpu_ids are clear. - */ -static inline bool cpumask_empty(const struct cpumask *srcp) -{ - return bitmap_empty(cpumask_bits(srcp), nr_cpumask_bits); -} - -/** - * cpumask_full - *srcp == 0xFFFFFFFF... - * @srcp: the cpumask to that all cpus < nr_cpu_ids are set. - */ -static inline bool cpumask_full(const struct cpumask *srcp) -{ - return bitmap_full(cpumask_bits(srcp), nr_cpumask_bits); -} - -/** - * cpumask_weight - Count of bits in *srcp - * @srcp: the cpumask to count bits (< nr_cpu_ids) in. - */ -static inline unsigned int cpumask_weight(const struct cpumask *srcp) -{ - return bitmap_weight(cpumask_bits(srcp), nr_cpumask_bits); -} - -/** - * cpumask_shift_right - *dstp = *srcp >> n - * @dstp: the cpumask result - * @srcp: the input to shift - * @n: the number of bits to shift by - */ -static inline void cpumask_shift_right(struct cpumask *dstp, - const struct cpumask *srcp, int n) -{ - bitmap_shift_right(cpumask_bits(dstp), cpumask_bits(srcp), n, - nr_cpumask_bits); -} - -/** - * cpumask_shift_left - *dstp = *srcp << n - * @dstp: the cpumask result - * @srcp: the input to shift - * @n: the number of bits to shift by - */ -static inline void cpumask_shift_left(struct cpumask *dstp, - const struct cpumask *srcp, int n) -{ - bitmap_shift_left(cpumask_bits(dstp), cpumask_bits(srcp), n, - nr_cpumask_bits); -} - -/** - * cpumask_copy - *dstp = *srcp - * @dstp: the result - * @srcp: the input cpumask - */ -static inline void cpumask_copy(struct cpumask *dstp, - const struct cpumask *srcp) -{ - bitmap_copy(cpumask_bits(dstp), cpumask_bits(srcp), nr_cpumask_bits); -} - -/** - * cpumask_any - pick a "random" cpu from *srcp - * @srcp: the input cpumask - * - * Returns >= nr_cpu_ids if no cpus set. - */ -#define cpumask_any(srcp) cpumask_first(srcp) - -/** - * cpumask_first_and - return the first cpu from *srcp1 & *srcp2 - * @src1p: the first input - * @src2p: the second input - * - * Returns >= nr_cpu_ids if no cpus set in both. See also cpumask_next_and(). - */ -#define cpumask_first_and(src1p, src2p) cpumask_next_and(-1, (src1p), (src2p)) - -/** - * cpumask_any_and - pick a "random" cpu from *mask1 & *mask2 - * @mask1: the first input cpumask - * @mask2: the second input cpumask - * - * Returns >= nr_cpu_ids if no cpus set. - */ -#define cpumask_any_and(mask1, mask2) cpumask_first_and((mask1), (mask2)) - -/** - * cpumask_of - the cpumask containing just a given cpu - * @cpu: the cpu (<= nr_cpu_ids) - */ -#define cpumask_of(cpu) (get_cpu_mask(cpu)) - -/** - * cpumask_parse_user - extract a cpumask from a user string - * @buf: the buffer to extract from - * @len: the length of the buffer - * @dstp: the cpumask to set. - * - * Returns -errno, or 0 for success. - */ -static inline int cpumask_parse_user(const char __user *buf, int len, - struct cpumask *dstp) -{ - return bitmap_parse_user(buf, len, cpumask_bits(dstp), nr_cpu_ids); -} - -/** - * cpumask_parselist_user - extract a cpumask from a user string - * @buf: the buffer to extract from - * @len: the length of the buffer - * @dstp: the cpumask to set. - * - * Returns -errno, or 0 for success. - */ -static inline int cpumask_parselist_user(const char __user *buf, int len, - struct cpumask *dstp) -{ - return bitmap_parselist_user(buf, len, cpumask_bits(dstp), - nr_cpu_ids); -} - -/** - * cpumask_parse - extract a cpumask from a string - * @buf: the buffer to extract from - * @dstp: the cpumask to set. - * - * Returns -errno, or 0 for success. - */ -static inline int cpumask_parse(const char *buf, struct cpumask *dstp) -{ - char *nl = strchr(buf, '\n'); - unsigned int len = nl ? (unsigned int)(nl - buf) : strlen(buf); - - return bitmap_parse(buf, len, cpumask_bits(dstp), nr_cpu_ids); -} - -/** - * cpulist_parse - extract a cpumask from a user string of ranges - * @buf: the buffer to extract from - * @dstp: the cpumask to set. - * - * Returns -errno, or 0 for success. - */ -static inline int cpulist_parse(const char *buf, struct cpumask *dstp) -{ - return bitmap_parselist(buf, cpumask_bits(dstp), nr_cpu_ids); -} - -/** - * cpumask_size - size to allocate for a 'struct cpumask' in bytes - */ -static inline size_t cpumask_size(void) -{ - return BITS_TO_LONGS(nr_cpumask_bits) * sizeof(long); -} - -/* - * cpumask_var_t: struct cpumask for stack usage. - * - * Oh, the wicked games we play! In order to make kernel coding a - * little more difficult, we typedef cpumask_var_t to an array or a - * pointer: doing &mask on an array is a noop, so it still works. - * - * ie. - * cpumask_var_t tmpmask; - * if (!alloc_cpumask_var(&tmpmask, GFP_KERNEL)) - * return -ENOMEM; - * - * ... use 'tmpmask' like a normal struct cpumask * ... - * - * free_cpumask_var(tmpmask); - * - * - * However, one notable exception is there. alloc_cpumask_var() allocates - * only nr_cpumask_bits bits (in the other hand, real cpumask_t always has - * NR_CPUS bits). Therefore you don't have to dereference cpumask_var_t. - * - * cpumask_var_t tmpmask; - * if (!alloc_cpumask_var(&tmpmask, GFP_KERNEL)) - * return -ENOMEM; - * - * var = *tmpmask; - * - * This code makes NR_CPUS length memcopy and brings to a memory corruption. - * cpumask_copy() provide safe copy functionality. - * - * Note that there is another evil here: If you define a cpumask_var_t - * as a percpu variable then the way to obtain the address of the cpumask - * structure differently influences what this_cpu_* operation needs to be - * used. Please use this_cpu_cpumask_var_t in those cases. The direct use - * of this_cpu_ptr() or this_cpu_read() will lead to failures when the - * other type of cpumask_var_t implementation is configured. - */ -#ifdef CONFIG_CPUMASK_OFFSTACK -typedef struct cpumask *cpumask_var_t; - -#define this_cpu_cpumask_var_ptr(x) this_cpu_read(x) - -bool alloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags, int node); -bool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags); -bool zalloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags, int node); -bool zalloc_cpumask_var(cpumask_var_t *mask, gfp_t flags); -void alloc_bootmem_cpumask_var(cpumask_var_t *mask); -void free_cpumask_var(cpumask_var_t mask); -void free_bootmem_cpumask_var(cpumask_var_t mask); - -#else -typedef struct cpumask cpumask_var_t[1]; - -#define this_cpu_cpumask_var_ptr(x) this_cpu_ptr(x) - -static inline bool alloc_cpumask_var(cpumask_var_t *mask, gfp_t flags) -{ - return true; -} - -static inline bool alloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags, - int node) -{ - return true; -} - -static inline bool zalloc_cpumask_var(cpumask_var_t *mask, gfp_t flags) -{ - cpumask_clear(*mask); - return true; -} - -static inline bool zalloc_cpumask_var_node(cpumask_var_t *mask, gfp_t flags, - int node) -{ - cpumask_clear(*mask); - return true; -} - -static inline void alloc_bootmem_cpumask_var(cpumask_var_t *mask) -{ -} - -static inline void free_cpumask_var(cpumask_var_t mask) -{ -} - -static inline void free_bootmem_cpumask_var(cpumask_var_t mask) -{ -} -#endif /* CONFIG_CPUMASK_OFFSTACK */ - -/* It's common to want to use cpu_all_mask in struct member initializers, - * so it has to refer to an address rather than a pointer. */ -extern const DECLARE_BITMAP(cpu_all_bits, NR_CPUS); -#define cpu_all_mask to_cpumask(cpu_all_bits) - -/* First bits of cpu_bit_bitmap are in fact unset. */ -#define cpu_none_mask to_cpumask(cpu_bit_bitmap[0]) - -#define for_each_possible_cpu(cpu) for_each_cpu((cpu), cpu_possible_mask) -#define for_each_online_cpu(cpu) for_each_cpu((cpu), cpu_online_mask) -#define for_each_present_cpu(cpu) for_each_cpu((cpu), cpu_present_mask) - -/* Wrappers for arch boot code to manipulate normally-constant masks */ -void init_cpu_present(const struct cpumask *src); -void init_cpu_possible(const struct cpumask *src); -void init_cpu_online(const struct cpumask *src); - -static inline void -set_cpu_possible(unsigned int cpu, bool possible) -{ - if (possible) - cpumask_set_cpu(cpu, &__cpu_possible_mask); - else - cpumask_clear_cpu(cpu, &__cpu_possible_mask); -} - -static inline void -set_cpu_present(unsigned int cpu, bool present) -{ - if (present) - cpumask_set_cpu(cpu, &__cpu_present_mask); - else - cpumask_clear_cpu(cpu, &__cpu_present_mask); -} - -static inline void -set_cpu_online(unsigned int cpu, bool online) -{ - if (online) - cpumask_set_cpu(cpu, &__cpu_online_mask); - else - cpumask_clear_cpu(cpu, &__cpu_online_mask); -} - -static inline void -set_cpu_active(unsigned int cpu, bool active) -{ - if (active) - cpumask_set_cpu(cpu, &__cpu_active_mask); - else - cpumask_clear_cpu(cpu, &__cpu_active_mask); -} - - -/** - * to_cpumask - convert an NR_CPUS bitmap to a struct cpumask * - * @bitmap: the bitmap - * - * There are a few places where cpumask_var_t isn't appropriate and - * static cpumasks must be used (eg. very early boot), yet we don't - * expose the definition of 'struct cpumask'. - * - * This does the conversion, and can be used as a constant initializer. - */ -#define to_cpumask(bitmap) \ - ((struct cpumask *)(1 ? (bitmap) \ - : (void *)sizeof(__check_is_bitmap(bitmap)))) - -static inline int __check_is_bitmap(const unsigned long *bitmap) -{ - return 1; -} - -/* - * Special-case data structure for "single bit set only" constant CPU masks. - * - * We pre-generate all the 64 (or 32) possible bit positions, with enough - * padding to the left and the right, and return the constant pointer - * appropriately offset. - */ -extern const unsigned long - cpu_bit_bitmap[BITS_PER_LONG+1][BITS_TO_LONGS(NR_CPUS)]; - -static inline const struct cpumask *get_cpu_mask(unsigned int cpu) -{ - const unsigned long *p = cpu_bit_bitmap[1 + cpu % BITS_PER_LONG]; - p -= cpu / BITS_PER_LONG; - return to_cpumask(p); -} - -#define cpu_is_offline(cpu) unlikely(!cpu_online(cpu)) - -#if NR_CPUS <= BITS_PER_LONG -#define CPU_BITS_ALL \ -{ \ - [BITS_TO_LONGS(NR_CPUS)-1] = BITMAP_LAST_WORD_MASK(NR_CPUS) \ -} - -#else /* NR_CPUS > BITS_PER_LONG */ - -#define CPU_BITS_ALL \ -{ \ - [0 ... BITS_TO_LONGS(NR_CPUS)-2] = ~0UL, \ - [BITS_TO_LONGS(NR_CPUS)-1] = BITMAP_LAST_WORD_MASK(NR_CPUS) \ -} -#endif /* NR_CPUS > BITS_PER_LONG */ - -/** - * cpumap_print_to_pagebuf - copies the cpumask into the buffer either - * as comma-separated list of cpus or hex values of cpumask - * @list: indicates whether the cpumap must be list - * @mask: the cpumask to copy - * @buf: the buffer to copy into - * - * Returns the length of the (null-terminated) @buf string, zero if - * nothing is copied. - */ -static inline ssize_t -cpumap_print_to_pagebuf(bool list, char *buf, const struct cpumask *mask) -{ - return bitmap_print_to_pagebuf(list, buf, cpumask_bits(mask), - nr_cpu_ids); -} - -#if NR_CPUS <= BITS_PER_LONG -#define CPU_MASK_ALL \ -(cpumask_t) { { \ - [BITS_TO_LONGS(NR_CPUS)-1] = BITMAP_LAST_WORD_MASK(NR_CPUS) \ -} } -#else -#define CPU_MASK_ALL \ -(cpumask_t) { { \ - [0 ... BITS_TO_LONGS(NR_CPUS)-2] = ~0UL, \ - [BITS_TO_LONGS(NR_CPUS)-1] = BITMAP_LAST_WORD_MASK(NR_CPUS) \ -} } -#endif /* NR_CPUS > BITS_PER_LONG */ - -#define CPU_MASK_NONE \ -(cpumask_t) { { \ - [0 ... BITS_TO_LONGS(NR_CPUS)-1] = 0UL \ -} } - -#define CPU_MASK_CPU0 \ -(cpumask_t) { { \ - [0] = 1UL \ -} } - -#endif /* __LINUX_CPUMASK_H */ diff --git a/src/linux/include/linux/cpuset.h b/src/linux/include/linux/cpuset.h deleted file mode 100644 index bfc204e..0000000 --- a/src/linux/include/linux/cpuset.h +++ /dev/null @@ -1,262 +0,0 @@ -#ifndef _LINUX_CPUSET_H -#define _LINUX_CPUSET_H -/* - * cpuset interface - * - * Copyright (C) 2003 BULL SA - * Copyright (C) 2004-2006 Silicon Graphics, Inc. - * - */ - -#include -#include -#include -#include -#include - -#ifdef CONFIG_CPUSETS - -extern struct static_key_false cpusets_enabled_key; -static inline bool cpusets_enabled(void) -{ - return static_branch_unlikely(&cpusets_enabled_key); -} - -static inline int nr_cpusets(void) -{ - /* jump label reference count + the top-level cpuset */ - return static_key_count(&cpusets_enabled_key.key) + 1; -} - -static inline void cpuset_inc(void) -{ - static_branch_inc(&cpusets_enabled_key); -} - -static inline void cpuset_dec(void) -{ - static_branch_dec(&cpusets_enabled_key); -} - -extern int cpuset_init(void); -extern void cpuset_init_smp(void); -extern void cpuset_update_active_cpus(bool cpu_online); -extern void cpuset_cpus_allowed(struct task_struct *p, struct cpumask *mask); -extern void cpuset_cpus_allowed_fallback(struct task_struct *p); -extern nodemask_t cpuset_mems_allowed(struct task_struct *p); -#define cpuset_current_mems_allowed (current->mems_allowed) -void cpuset_init_current_mems_allowed(void); -int cpuset_nodemask_valid_mems_allowed(nodemask_t *nodemask); - -extern bool __cpuset_node_allowed(int node, gfp_t gfp_mask); - -static inline bool cpuset_node_allowed(int node, gfp_t gfp_mask) -{ - if (cpusets_enabled()) - return __cpuset_node_allowed(node, gfp_mask); - return true; -} - -static inline bool __cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask) -{ - return __cpuset_node_allowed(zone_to_nid(z), gfp_mask); -} - -static inline bool cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask) -{ - if (cpusets_enabled()) - return __cpuset_zone_allowed(z, gfp_mask); - return true; -} - -extern int cpuset_mems_allowed_intersects(const struct task_struct *tsk1, - const struct task_struct *tsk2); - -#define cpuset_memory_pressure_bump() \ - do { \ - if (cpuset_memory_pressure_enabled) \ - __cpuset_memory_pressure_bump(); \ - } while (0) -extern int cpuset_memory_pressure_enabled; -extern void __cpuset_memory_pressure_bump(void); - -extern void cpuset_task_status_allowed(struct seq_file *m, - struct task_struct *task); -extern int proc_cpuset_show(struct seq_file *m, struct pid_namespace *ns, - struct pid *pid, struct task_struct *tsk); - -extern int cpuset_mem_spread_node(void); -extern int cpuset_slab_spread_node(void); - -static inline int cpuset_do_page_mem_spread(void) -{ - return task_spread_page(current); -} - -static inline int cpuset_do_slab_mem_spread(void) -{ - return task_spread_slab(current); -} - -extern int current_cpuset_is_being_rebound(void); - -extern void rebuild_sched_domains(void); - -extern void cpuset_print_current_mems_allowed(void); - -/* - * read_mems_allowed_begin is required when making decisions involving - * mems_allowed such as during page allocation. mems_allowed can be updated in - * parallel and depending on the new value an operation can fail potentially - * causing process failure. A retry loop with read_mems_allowed_begin and - * read_mems_allowed_retry prevents these artificial failures. - */ -static inline unsigned int read_mems_allowed_begin(void) -{ - if (!cpusets_enabled()) - return 0; - - return read_seqcount_begin(¤t->mems_allowed_seq); -} - -/* - * If this returns true, the operation that took place after - * read_mems_allowed_begin may have failed artificially due to a concurrent - * update of mems_allowed. It is up to the caller to retry the operation if - * appropriate. - */ -static inline bool read_mems_allowed_retry(unsigned int seq) -{ - if (!cpusets_enabled()) - return false; - - return read_seqcount_retry(¤t->mems_allowed_seq, seq); -} - -static inline void set_mems_allowed(nodemask_t nodemask) -{ - unsigned long flags; - - task_lock(current); - local_irq_save(flags); - write_seqcount_begin(¤t->mems_allowed_seq); - current->mems_allowed = nodemask; - write_seqcount_end(¤t->mems_allowed_seq); - local_irq_restore(flags); - task_unlock(current); -} - -#else /* !CONFIG_CPUSETS */ - -static inline bool cpusets_enabled(void) { return false; } - -static inline int cpuset_init(void) { return 0; } -static inline void cpuset_init_smp(void) {} - -static inline void cpuset_update_active_cpus(bool cpu_online) -{ - partition_sched_domains(1, NULL, NULL); -} - -static inline void cpuset_cpus_allowed(struct task_struct *p, - struct cpumask *mask) -{ - cpumask_copy(mask, cpu_possible_mask); -} - -static inline void cpuset_cpus_allowed_fallback(struct task_struct *p) -{ -} - -static inline nodemask_t cpuset_mems_allowed(struct task_struct *p) -{ - return node_possible_map; -} - -#define cpuset_current_mems_allowed (node_states[N_MEMORY]) -static inline void cpuset_init_current_mems_allowed(void) {} - -static inline int cpuset_nodemask_valid_mems_allowed(nodemask_t *nodemask) -{ - return 1; -} - -static inline bool cpuset_node_allowed(int node, gfp_t gfp_mask) -{ - return true; -} - -static inline bool __cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask) -{ - return true; -} - -static inline bool cpuset_zone_allowed(struct zone *z, gfp_t gfp_mask) -{ - return true; -} - -static inline int cpuset_mems_allowed_intersects(const struct task_struct *tsk1, - const struct task_struct *tsk2) -{ - return 1; -} - -static inline void cpuset_memory_pressure_bump(void) {} - -static inline void cpuset_task_status_allowed(struct seq_file *m, - struct task_struct *task) -{ -} - -static inline int cpuset_mem_spread_node(void) -{ - return 0; -} - -static inline int cpuset_slab_spread_node(void) -{ - return 0; -} - -static inline int cpuset_do_page_mem_spread(void) -{ - return 0; -} - -static inline int cpuset_do_slab_mem_spread(void) -{ - return 0; -} - -static inline int current_cpuset_is_being_rebound(void) -{ - return 0; -} - -static inline void rebuild_sched_domains(void) -{ - partition_sched_domains(1, NULL, NULL); -} - -static inline void cpuset_print_current_mems_allowed(void) -{ -} - -static inline void set_mems_allowed(nodemask_t nodemask) -{ -} - -static inline unsigned int read_mems_allowed_begin(void) -{ - return 0; -} - -static inline bool read_mems_allowed_retry(unsigned int seq) -{ - return false; -} - -#endif /* !CONFIG_CPUSETS */ - -#endif /* _LINUX_CPUSET_H */ diff --git a/src/linux/include/linux/cputime.h b/src/linux/include/linux/cputime.h deleted file mode 100644 index f2eb2ee..0000000 --- a/src/linux/include/linux/cputime.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __LINUX_CPUTIME_H -#define __LINUX_CPUTIME_H - -#include - -#ifndef cputime_to_nsecs -# define cputime_to_nsecs(__ct) \ - (cputime_to_usecs(__ct) * NSEC_PER_USEC) -#endif - -#ifndef nsecs_to_cputime -# define nsecs_to_cputime(__nsecs) \ - usecs_to_cputime((__nsecs) / NSEC_PER_USEC) -#endif - -#endif /* __LINUX_CPUTIME_H */ diff --git a/src/linux/include/linux/crash_dump.h b/src/linux/include/linux/crash_dump.h deleted file mode 100644 index 3873697..0000000 --- a/src/linux/include/linux/crash_dump.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef LINUX_CRASH_DUMP_H -#define LINUX_CRASH_DUMP_H - -#ifdef CONFIG_CRASH_DUMP -#include -#include -#include - -#include /* for pgprot_t */ - -#define ELFCORE_ADDR_MAX (-1ULL) -#define ELFCORE_ADDR_ERR (-2ULL) - -extern unsigned long long elfcorehdr_addr; -extern unsigned long long elfcorehdr_size; - -extern int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size); -extern void elfcorehdr_free(unsigned long long addr); -extern ssize_t elfcorehdr_read(char *buf, size_t count, u64 *ppos); -extern ssize_t elfcorehdr_read_notes(char *buf, size_t count, u64 *ppos); -extern int remap_oldmem_pfn_range(struct vm_area_struct *vma, - unsigned long from, unsigned long pfn, - unsigned long size, pgprot_t prot); - -extern ssize_t copy_oldmem_page(unsigned long, char *, size_t, - unsigned long, int); -void vmcore_cleanup(void); - -/* Architecture code defines this if there are other possible ELF - * machine types, e.g. on bi-arch capable hardware. */ -#ifndef vmcore_elf_check_arch_cross -#define vmcore_elf_check_arch_cross(x) 0 -#endif - -/* - * Architecture code can redefine this if there are any special checks - * needed for 32-bit ELF or 64-bit ELF vmcores. In case of 32-bit - * only architecture, vmcore_elf64_check_arch can be set to zero. - */ -#ifndef vmcore_elf32_check_arch -#define vmcore_elf32_check_arch(x) elf_check_arch(x) -#endif - -#ifndef vmcore_elf64_check_arch -#define vmcore_elf64_check_arch(x) (elf_check_arch(x) || vmcore_elf_check_arch_cross(x)) -#endif - -/* - * is_kdump_kernel() checks whether this kernel is booting after a panic of - * previous kernel or not. This is determined by checking if previous kernel - * has passed the elf core header address on command line. - * - * This is not just a test if CONFIG_CRASH_DUMP is enabled or not. It will - * return 1 if CONFIG_CRASH_DUMP=y and if kernel is booting after a panic of - * previous kernel. - */ - -static inline int is_kdump_kernel(void) -{ - return (elfcorehdr_addr != ELFCORE_ADDR_MAX) ? 1 : 0; -} - -/* is_vmcore_usable() checks if the kernel is booting after a panic and - * the vmcore region is usable. - * - * This makes use of the fact that due to alignment -2ULL is not - * a valid pointer, much in the vain of IS_ERR(), except - * dealing directly with an unsigned long long rather than a pointer. - */ - -static inline int is_vmcore_usable(void) -{ - return is_kdump_kernel() && elfcorehdr_addr != ELFCORE_ADDR_ERR ? 1 : 0; -} - -/* vmcore_unusable() marks the vmcore as unusable, - * without disturbing the logic of is_kdump_kernel() - */ - -static inline void vmcore_unusable(void) -{ - if (is_kdump_kernel()) - elfcorehdr_addr = ELFCORE_ADDR_ERR; -} - -#define HAVE_OLDMEM_PFN_IS_RAM 1 -extern int register_oldmem_pfn_is_ram(int (*fn)(unsigned long pfn)); -extern void unregister_oldmem_pfn_is_ram(void); - -#else /* !CONFIG_CRASH_DUMP */ -static inline int is_kdump_kernel(void) { return 0; } -#endif /* CONFIG_CRASH_DUMP */ - -extern unsigned long saved_max_pfn; -#endif /* LINUX_CRASHDUMP_H */ diff --git a/src/linux/include/linux/crc-ccitt.h b/src/linux/include/linux/crc-ccitt.h deleted file mode 100644 index f52696a..0000000 --- a/src/linux/include/linux/crc-ccitt.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _LINUX_CRC_CCITT_H -#define _LINUX_CRC_CCITT_H - -#include - -extern u16 const crc_ccitt_table[256]; - -extern u16 crc_ccitt(u16 crc, const u8 *buffer, size_t len); - -static inline u16 crc_ccitt_byte(u16 crc, const u8 c) -{ - return (crc >> 8) ^ crc_ccitt_table[(crc ^ c) & 0xff]; -} - -#endif /* _LINUX_CRC_CCITT_H */ diff --git a/src/linux/include/linux/crc16.h b/src/linux/include/linux/crc16.h deleted file mode 100644 index 9443c08..0000000 --- a/src/linux/include/linux/crc16.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * crc16.h - CRC-16 routine - * - * Implements the standard CRC-16: - * Width 16 - * Poly 0x8005 (x^16 + x^15 + x^2 + 1) - * Init 0 - * - * Copyright (c) 2005 Ben Gardner - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. - */ - -#ifndef __CRC16_H -#define __CRC16_H - -#include - -extern u16 const crc16_table[256]; - -extern u16 crc16(u16 crc, const u8 *buffer, size_t len); - -static inline u16 crc16_byte(u16 crc, const u8 data) -{ - return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff]; -} - -#endif /* __CRC16_H */ - diff --git a/src/linux/include/linux/crc32.h b/src/linux/include/linux/crc32.h deleted file mode 100644 index 9e8a032..0000000 --- a/src/linux/include/linux/crc32.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * crc32.h - * See linux/lib/crc32.c for license and changes - */ -#ifndef _LINUX_CRC32_H -#define _LINUX_CRC32_H - -#include -#include - -u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len); -u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len); - -/** - * crc32_le_combine - Combine two crc32 check values into one. For two - * sequences of bytes, seq1 and seq2 with lengths len1 - * and len2, crc32_le() check values were calculated - * for each, crc1 and crc2. - * - * @crc1: crc32 of the first block - * @crc2: crc32 of the second block - * @len2: length of the second block - * - * Return: The crc32_le() check value of seq1 and seq2 concatenated, - * requiring only crc1, crc2, and len2. Note: If seq_full denotes - * the concatenated memory area of seq1 with seq2, and crc_full - * the crc32_le() value of seq_full, then crc_full == - * crc32_le_combine(crc1, crc2, len2) when crc_full was seeded - * with the same initializer as crc1, and crc2 seed was 0. See - * also crc32_combine_test(). - */ -u32 __attribute_const__ crc32_le_shift(u32 crc, size_t len); - -static inline u32 crc32_le_combine(u32 crc1, u32 crc2, size_t len2) -{ - return crc32_le_shift(crc1, len2) ^ crc2; -} - -u32 __pure __crc32c_le(u32 crc, unsigned char const *p, size_t len); - -/** - * __crc32c_le_combine - Combine two crc32c check values into one. For two - * sequences of bytes, seq1 and seq2 with lengths len1 - * and len2, __crc32c_le() check values were calculated - * for each, crc1 and crc2. - * - * @crc1: crc32c of the first block - * @crc2: crc32c of the second block - * @len2: length of the second block - * - * Return: The __crc32c_le() check value of seq1 and seq2 concatenated, - * requiring only crc1, crc2, and len2. Note: If seq_full denotes - * the concatenated memory area of seq1 with seq2, and crc_full - * the __crc32c_le() value of seq_full, then crc_full == - * __crc32c_le_combine(crc1, crc2, len2) when crc_full was - * seeded with the same initializer as crc1, and crc2 seed - * was 0. See also crc32c_combine_test(). - */ -u32 __attribute_const__ __crc32c_le_shift(u32 crc, size_t len); - -static inline u32 __crc32c_le_combine(u32 crc1, u32 crc2, size_t len2) -{ - return __crc32c_le_shift(crc1, len2) ^ crc2; -} - -#define crc32(seed, data, length) crc32_le(seed, (unsigned char const *)(data), length) - -/* - * Helpers for hash table generation of ethernet nics: - * - * Ethernet sends the least significant bit of a byte first, thus crc32_le - * is used. The output of crc32_le is bit reversed [most significant bit - * is in bit nr 0], thus it must be reversed before use. Except for - * nics that bit swap the result internally... - */ -#define ether_crc(length, data) bitrev32(crc32_le(~0, data, length)) -#define ether_crc_le(length, data) crc32_le(~0, data, length) - -#endif /* _LINUX_CRC32_H */ diff --git a/src/linux/include/linux/crc32c.h b/src/linux/include/linux/crc32c.h deleted file mode 100644 index bd8b44d..0000000 --- a/src/linux/include/linux/crc32c.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _LINUX_CRC32C_H -#define _LINUX_CRC32C_H - -#include - -extern u32 crc32c(u32 crc, const void *address, unsigned int length); - -/* This macro exists for backwards-compatibility. */ -#define crc32c_le crc32c - -#endif /* _LINUX_CRC32C_H */ diff --git a/src/linux/include/linux/cred.h b/src/linux/include/linux/cred.h deleted file mode 100644 index f0e70a1..0000000 --- a/src/linux/include/linux/cred.h +++ /dev/null @@ -1,402 +0,0 @@ -/* Credentials management - see Documentation/security/credentials.txt - * - * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ - -#ifndef _LINUX_CRED_H -#define _LINUX_CRED_H - -#include -#include -#include -#include -#include -#include - -struct user_struct; -struct cred; -struct inode; - -/* - * COW Supplementary groups list - */ -struct group_info { - atomic_t usage; - int ngroups; - kgid_t gid[0]; -}; - -/** - * get_group_info - Get a reference to a group info structure - * @group_info: The group info to reference - * - * This gets a reference to a set of supplementary groups. - * - * If the caller is accessing a task's credentials, they must hold the RCU read - * lock when reading. - */ -static inline struct group_info *get_group_info(struct group_info *gi) -{ - atomic_inc(&gi->usage); - return gi; -} - -/** - * put_group_info - Release a reference to a group info structure - * @group_info: The group info to release - */ -#define put_group_info(group_info) \ -do { \ - if (atomic_dec_and_test(&(group_info)->usage)) \ - groups_free(group_info); \ -} while (0) - -extern struct group_info init_groups; -#ifdef CONFIG_MULTIUSER -extern struct group_info *groups_alloc(int); -extern void groups_free(struct group_info *); - -extern int in_group_p(kgid_t); -extern int in_egroup_p(kgid_t); -#else -static inline void groups_free(struct group_info *group_info) -{ -} - -static inline int in_group_p(kgid_t grp) -{ - return 1; -} -static inline int in_egroup_p(kgid_t grp) -{ - return 1; -} -#endif -extern int set_current_groups(struct group_info *); -extern void set_groups(struct cred *, struct group_info *); -extern int groups_search(const struct group_info *, kgid_t); -extern bool may_setgroups(void); - -/* - * The security context of a task - * - * The parts of the context break down into two categories: - * - * (1) The objective context of a task. These parts are used when some other - * task is attempting to affect this one. - * - * (2) The subjective context. These details are used when the task is acting - * upon another object, be that a file, a task, a key or whatever. - * - * Note that some members of this structure belong to both categories - the - * LSM security pointer for instance. - * - * A task has two security pointers. task->real_cred points to the objective - * context that defines that task's actual details. The objective part of this - * context is used whenever that task is acted upon. - * - * task->cred points to the subjective context that defines the details of how - * that task is going to act upon another object. This may be overridden - * temporarily to point to another security context, but normally points to the - * same context as task->real_cred. - */ -struct cred { - atomic_t usage; -#ifdef CONFIG_DEBUG_CREDENTIALS - atomic_t subscribers; /* number of processes subscribed */ - void *put_addr; - unsigned magic; -#define CRED_MAGIC 0x43736564 -#define CRED_MAGIC_DEAD 0x44656144 -#endif - kuid_t uid; /* real UID of the task */ - kgid_t gid; /* real GID of the task */ - kuid_t suid; /* saved UID of the task */ - kgid_t sgid; /* saved GID of the task */ - kuid_t euid; /* effective UID of the task */ - kgid_t egid; /* effective GID of the task */ - kuid_t fsuid; /* UID for VFS ops */ - kgid_t fsgid; /* GID for VFS ops */ - unsigned securebits; /* SUID-less security management */ - kernel_cap_t cap_inheritable; /* caps our children can inherit */ - kernel_cap_t cap_permitted; /* caps we're permitted */ - kernel_cap_t cap_effective; /* caps we can actually use */ - kernel_cap_t cap_bset; /* capability bounding set */ - kernel_cap_t cap_ambient; /* Ambient capability set */ -#ifdef CONFIG_KEYS - unsigned char jit_keyring; /* default keyring to attach requested - * keys to */ - struct key __rcu *session_keyring; /* keyring inherited over fork */ - struct key *process_keyring; /* keyring private to this process */ - struct key *thread_keyring; /* keyring private to this thread */ - struct key *request_key_auth; /* assumed request_key authority */ -#endif -#ifdef CONFIG_SECURITY - void *security; /* subjective LSM security */ -#endif - struct user_struct *user; /* real user ID subscription */ - struct user_namespace *user_ns; /* user_ns the caps and keyrings are relative to. */ - struct group_info *group_info; /* supplementary groups for euid/fsgid */ - struct rcu_head rcu; /* RCU deletion hook */ -}; - -extern void __put_cred(struct cred *); -extern void exit_creds(struct task_struct *); -extern int copy_creds(struct task_struct *, unsigned long); -extern const struct cred *get_task_cred(struct task_struct *); -extern struct cred *cred_alloc_blank(void); -extern struct cred *prepare_creds(void); -extern struct cred *prepare_exec_creds(void); -extern int commit_creds(struct cred *); -extern void abort_creds(struct cred *); -extern const struct cred *override_creds(const struct cred *); -extern void revert_creds(const struct cred *); -extern struct cred *prepare_kernel_cred(struct task_struct *); -extern int change_create_files_as(struct cred *, struct inode *); -extern int set_security_override(struct cred *, u32); -extern int set_security_override_from_ctx(struct cred *, const char *); -extern int set_create_files_as(struct cred *, struct inode *); -extern void __init cred_init(void); - -/* - * check for validity of credentials - */ -#ifdef CONFIG_DEBUG_CREDENTIALS -extern void __invalid_creds(const struct cred *, const char *, unsigned); -extern void __validate_process_creds(struct task_struct *, - const char *, unsigned); - -extern bool creds_are_invalid(const struct cred *cred); - -static inline void __validate_creds(const struct cred *cred, - const char *file, unsigned line) -{ - if (unlikely(creds_are_invalid(cred))) - __invalid_creds(cred, file, line); -} - -#define validate_creds(cred) \ -do { \ - __validate_creds((cred), __FILE__, __LINE__); \ -} while(0) - -#define validate_process_creds() \ -do { \ - __validate_process_creds(current, __FILE__, __LINE__); \ -} while(0) - -extern void validate_creds_for_do_exit(struct task_struct *); -#else -static inline void validate_creds(const struct cred *cred) -{ -} -static inline void validate_creds_for_do_exit(struct task_struct *tsk) -{ -} -static inline void validate_process_creds(void) -{ -} -#endif - -static inline bool cap_ambient_invariant_ok(const struct cred *cred) -{ - return cap_issubset(cred->cap_ambient, - cap_intersect(cred->cap_permitted, - cred->cap_inheritable)); -} - -/** - * get_new_cred - Get a reference on a new set of credentials - * @cred: The new credentials to reference - * - * Get a reference on the specified set of new credentials. The caller must - * release the reference. - */ -static inline struct cred *get_new_cred(struct cred *cred) -{ - atomic_inc(&cred->usage); - return cred; -} - -/** - * get_cred - Get a reference on a set of credentials - * @cred: The credentials to reference - * - * Get a reference on the specified set of credentials. The caller must - * release the reference. - * - * This is used to deal with a committed set of credentials. Although the - * pointer is const, this will temporarily discard the const and increment the - * usage count. The purpose of this is to attempt to catch at compile time the - * accidental alteration of a set of credentials that should be considered - * immutable. - */ -static inline const struct cred *get_cred(const struct cred *cred) -{ - struct cred *nonconst_cred = (struct cred *) cred; - validate_creds(cred); - return get_new_cred(nonconst_cred); -} - -/** - * put_cred - Release a reference to a set of credentials - * @cred: The credentials to release - * - * Release a reference to a set of credentials, deleting them when the last ref - * is released. - * - * This takes a const pointer to a set of credentials because the credentials - * on task_struct are attached by const pointers to prevent accidental - * alteration of otherwise immutable credential sets. - */ -static inline void put_cred(const struct cred *_cred) -{ - struct cred *cred = (struct cred *) _cred; - - validate_creds(cred); - if (atomic_dec_and_test(&(cred)->usage)) - __put_cred(cred); -} - -/** - * current_cred - Access the current task's subjective credentials - * - * Access the subjective credentials of the current task. RCU-safe, - * since nobody else can modify it. - */ -#define current_cred() \ - rcu_dereference_protected(current->cred, 1) - -/** - * current_real_cred - Access the current task's objective credentials - * - * Access the objective credentials of the current task. RCU-safe, - * since nobody else can modify it. - */ -#define current_real_cred() \ - rcu_dereference_protected(current->real_cred, 1) - -/** - * __task_cred - Access a task's objective credentials - * @task: The task to query - * - * Access the objective credentials of a task. The caller must hold the RCU - * readlock. - * - * The result of this function should not be passed directly to get_cred(); - * rather get_task_cred() should be used instead. - */ -#define __task_cred(task) \ - rcu_dereference((task)->real_cred) - -/** - * get_current_cred - Get the current task's subjective credentials - * - * Get the subjective credentials of the current task, pinning them so that - * they can't go away. Accessing the current task's credentials directly is - * not permitted. - */ -#define get_current_cred() \ - (get_cred(current_cred())) - -/** - * get_current_user - Get the current task's user_struct - * - * Get the user record of the current task, pinning it so that it can't go - * away. - */ -#define get_current_user() \ -({ \ - struct user_struct *__u; \ - const struct cred *__cred; \ - __cred = current_cred(); \ - __u = get_uid(__cred->user); \ - __u; \ -}) - -/** - * get_current_groups - Get the current task's supplementary group list - * - * Get the supplementary group list of the current task, pinning it so that it - * can't go away. - */ -#define get_current_groups() \ -({ \ - struct group_info *__groups; \ - const struct cred *__cred; \ - __cred = current_cred(); \ - __groups = get_group_info(__cred->group_info); \ - __groups; \ -}) - -#define task_cred_xxx(task, xxx) \ -({ \ - __typeof__(((struct cred *)NULL)->xxx) ___val; \ - rcu_read_lock(); \ - ___val = __task_cred((task))->xxx; \ - rcu_read_unlock(); \ - ___val; \ -}) - -#define task_uid(task) (task_cred_xxx((task), uid)) -#define task_euid(task) (task_cred_xxx((task), euid)) - -#define current_cred_xxx(xxx) \ -({ \ - current_cred()->xxx; \ -}) - -#define current_uid() (current_cred_xxx(uid)) -#define current_gid() (current_cred_xxx(gid)) -#define current_euid() (current_cred_xxx(euid)) -#define current_egid() (current_cred_xxx(egid)) -#define current_suid() (current_cred_xxx(suid)) -#define current_sgid() (current_cred_xxx(sgid)) -#define current_fsuid() (current_cred_xxx(fsuid)) -#define current_fsgid() (current_cred_xxx(fsgid)) -#define current_cap() (current_cred_xxx(cap_effective)) -#define current_user() (current_cred_xxx(user)) -#define current_security() (current_cred_xxx(security)) - -extern struct user_namespace init_user_ns; -#ifdef CONFIG_USER_NS -#define current_user_ns() (current_cred_xxx(user_ns)) -#else -static inline struct user_namespace *current_user_ns(void) -{ - return &init_user_ns; -} -#endif - - -#define current_uid_gid(_uid, _gid) \ -do { \ - const struct cred *__cred; \ - __cred = current_cred(); \ - *(_uid) = __cred->uid; \ - *(_gid) = __cred->gid; \ -} while(0) - -#define current_euid_egid(_euid, _egid) \ -do { \ - const struct cred *__cred; \ - __cred = current_cred(); \ - *(_euid) = __cred->euid; \ - *(_egid) = __cred->egid; \ -} while(0) - -#define current_fsuid_fsgid(_fsuid, _fsgid) \ -do { \ - const struct cred *__cred; \ - __cred = current_cred(); \ - *(_fsuid) = __cred->fsuid; \ - *(_fsgid) = __cred->fsgid; \ -} while(0) - -#endif /* _LINUX_CRED_H */ diff --git a/src/linux/include/linux/crypto.h b/src/linux/include/linux/crypto.h deleted file mode 100644 index 7cee555..0000000 --- a/src/linux/include/linux/crypto.h +++ /dev/null @@ -1,1605 +0,0 @@ -/* - * Scatterlist Cryptographic API. - * - * Copyright (c) 2002 James Morris - * Copyright (c) 2002 David S. Miller (davem@redhat.com) - * Copyright (c) 2005 Herbert Xu - * - * Portions derived from Cryptoapi, by Alexander Kjeldaas - * and Nettle, by Niels Möller. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ -#ifndef _LINUX_CRYPTO_H -#define _LINUX_CRYPTO_H - -#include -#include -#include -#include -#include -#include -#include - -/* - * Autoloaded crypto modules should only use a prefixed name to avoid allowing - * arbitrary modules to be loaded. Loading from userspace may still need the - * unprefixed names, so retains those aliases as well. - * This uses __MODULE_INFO directly instead of MODULE_ALIAS because pre-4.3 - * gcc (e.g. avr32 toolchain) uses __LINE__ for uniqueness, and this macro - * expands twice on the same line. Instead, use a separate base name for the - * alias. - */ -#define MODULE_ALIAS_CRYPTO(name) \ - __MODULE_INFO(alias, alias_userspace, name); \ - __MODULE_INFO(alias, alias_crypto, "crypto-" name) - -/* - * Algorithm masks and types. - */ -#define CRYPTO_ALG_TYPE_MASK 0x0000000f -#define CRYPTO_ALG_TYPE_CIPHER 0x00000001 -#define CRYPTO_ALG_TYPE_COMPRESS 0x00000002 -#define CRYPTO_ALG_TYPE_AEAD 0x00000003 -#define CRYPTO_ALG_TYPE_BLKCIPHER 0x00000004 -#define CRYPTO_ALG_TYPE_ABLKCIPHER 0x00000005 -#define CRYPTO_ALG_TYPE_SKCIPHER 0x00000005 -#define CRYPTO_ALG_TYPE_GIVCIPHER 0x00000006 -#define CRYPTO_ALG_TYPE_KPP 0x00000008 -#define CRYPTO_ALG_TYPE_RNG 0x0000000c -#define CRYPTO_ALG_TYPE_AKCIPHER 0x0000000d -#define CRYPTO_ALG_TYPE_DIGEST 0x0000000e -#define CRYPTO_ALG_TYPE_HASH 0x0000000e -#define CRYPTO_ALG_TYPE_SHASH 0x0000000e -#define CRYPTO_ALG_TYPE_AHASH 0x0000000f - -#define CRYPTO_ALG_TYPE_HASH_MASK 0x0000000e -#define CRYPTO_ALG_TYPE_AHASH_MASK 0x0000000e -#define CRYPTO_ALG_TYPE_BLKCIPHER_MASK 0x0000000c - -#define CRYPTO_ALG_LARVAL 0x00000010 -#define CRYPTO_ALG_DEAD 0x00000020 -#define CRYPTO_ALG_DYING 0x00000040 -#define CRYPTO_ALG_ASYNC 0x00000080 - -/* - * Set this bit if and only if the algorithm requires another algorithm of - * the same type to handle corner cases. - */ -#define CRYPTO_ALG_NEED_FALLBACK 0x00000100 - -/* - * This bit is set for symmetric key ciphers that have already been wrapped - * with a generic IV generator to prevent them from being wrapped again. - */ -#define CRYPTO_ALG_GENIV 0x00000200 - -/* - * Set if the algorithm has passed automated run-time testing. Note that - * if there is no run-time testing for a given algorithm it is considered - * to have passed. - */ - -#define CRYPTO_ALG_TESTED 0x00000400 - -/* - * Set if the algorithm is an instance that is build from templates. - */ -#define CRYPTO_ALG_INSTANCE 0x00000800 - -/* Set this bit if the algorithm provided is hardware accelerated but - * not available to userspace via instruction set or so. - */ -#define CRYPTO_ALG_KERN_DRIVER_ONLY 0x00001000 - -/* - * Mark a cipher as a service implementation only usable by another - * cipher and never by a normal user of the kernel crypto API - */ -#define CRYPTO_ALG_INTERNAL 0x00002000 - -/* - * Transform masks and values (for crt_flags). - */ -#define CRYPTO_TFM_REQ_MASK 0x000fff00 -#define CRYPTO_TFM_RES_MASK 0xfff00000 - -#define CRYPTO_TFM_REQ_WEAK_KEY 0x00000100 -#define CRYPTO_TFM_REQ_MAY_SLEEP 0x00000200 -#define CRYPTO_TFM_REQ_MAY_BACKLOG 0x00000400 -#define CRYPTO_TFM_RES_WEAK_KEY 0x00100000 -#define CRYPTO_TFM_RES_BAD_KEY_LEN 0x00200000 -#define CRYPTO_TFM_RES_BAD_KEY_SCHED 0x00400000 -#define CRYPTO_TFM_RES_BAD_BLOCK_LEN 0x00800000 -#define CRYPTO_TFM_RES_BAD_FLAGS 0x01000000 - -/* - * Miscellaneous stuff. - */ -#define CRYPTO_MAX_ALG_NAME 64 - -/* - * The macro CRYPTO_MINALIGN_ATTR (along with the void * type in the actual - * declaration) is used to ensure that the crypto_tfm context structure is - * aligned correctly for the given architecture so that there are no alignment - * faults for C data types. In particular, this is required on platforms such - * as arm where pointers are 32-bit aligned but there are data types such as - * u64 which require 64-bit alignment. - */ -#define CRYPTO_MINALIGN ARCH_KMALLOC_MINALIGN - -#define CRYPTO_MINALIGN_ATTR __attribute__ ((__aligned__(CRYPTO_MINALIGN))) - -struct scatterlist; -struct crypto_ablkcipher; -struct crypto_async_request; -struct crypto_blkcipher; -struct crypto_tfm; -struct crypto_type; -struct skcipher_givcrypt_request; - -typedef void (*crypto_completion_t)(struct crypto_async_request *req, int err); - -/** - * DOC: Block Cipher Context Data Structures - * - * These data structures define the operating context for each block cipher - * type. - */ - -struct crypto_async_request { - struct list_head list; - crypto_completion_t complete; - void *data; - struct crypto_tfm *tfm; - - u32 flags; -}; - -struct ablkcipher_request { - struct crypto_async_request base; - - unsigned int nbytes; - - void *info; - - struct scatterlist *src; - struct scatterlist *dst; - - void *__ctx[] CRYPTO_MINALIGN_ATTR; -}; - -struct blkcipher_desc { - struct crypto_blkcipher *tfm; - void *info; - u32 flags; -}; - -struct cipher_desc { - struct crypto_tfm *tfm; - void (*crfn)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); - unsigned int (*prfn)(const struct cipher_desc *desc, u8 *dst, - const u8 *src, unsigned int nbytes); - void *info; -}; - -/** - * DOC: Block Cipher Algorithm Definitions - * - * These data structures define modular crypto algorithm implementations, - * managed via crypto_register_alg() and crypto_unregister_alg(). - */ - -/** - * struct ablkcipher_alg - asynchronous block cipher definition - * @min_keysize: Minimum key size supported by the transformation. This is the - * smallest key length supported by this transformation algorithm. - * This must be set to one of the pre-defined values as this is - * not hardware specific. Possible values for this field can be - * found via git grep "_MIN_KEY_SIZE" include/crypto/ - * @max_keysize: Maximum key size supported by the transformation. This is the - * largest key length supported by this transformation algorithm. - * This must be set to one of the pre-defined values as this is - * not hardware specific. Possible values for this field can be - * found via git grep "_MAX_KEY_SIZE" include/crypto/ - * @setkey: Set key for the transformation. This function is used to either - * program a supplied key into the hardware or store the key in the - * transformation context for programming it later. Note that this - * function does modify the transformation context. This function can - * be called multiple times during the existence of the transformation - * object, so one must make sure the key is properly reprogrammed into - * the hardware. This function is also responsible for checking the key - * length for validity. In case a software fallback was put in place in - * the @cra_init call, this function might need to use the fallback if - * the algorithm doesn't support all of the key sizes. - * @encrypt: Encrypt a scatterlist of blocks. This function is used to encrypt - * the supplied scatterlist containing the blocks of data. The crypto - * API consumer is responsible for aligning the entries of the - * scatterlist properly and making sure the chunks are correctly - * sized. In case a software fallback was put in place in the - * @cra_init call, this function might need to use the fallback if - * the algorithm doesn't support all of the key sizes. In case the - * key was stored in transformation context, the key might need to be - * re-programmed into the hardware in this function. This function - * shall not modify the transformation context, as this function may - * be called in parallel with the same transformation object. - * @decrypt: Decrypt a single block. This is a reverse counterpart to @encrypt - * and the conditions are exactly the same. - * @givencrypt: Update the IV for encryption. With this function, a cipher - * implementation may provide the function on how to update the IV - * for encryption. - * @givdecrypt: Update the IV for decryption. This is the reverse of - * @givencrypt . - * @geniv: The transformation implementation may use an "IV generator" provided - * by the kernel crypto API. Several use cases have a predefined - * approach how IVs are to be updated. For such use cases, the kernel - * crypto API provides ready-to-use implementations that can be - * referenced with this variable. - * @ivsize: IV size applicable for transformation. The consumer must provide an - * IV of exactly that size to perform the encrypt or decrypt operation. - * - * All fields except @givencrypt , @givdecrypt , @geniv and @ivsize are - * mandatory and must be filled. - */ -struct ablkcipher_alg { - int (*setkey)(struct crypto_ablkcipher *tfm, const u8 *key, - unsigned int keylen); - int (*encrypt)(struct ablkcipher_request *req); - int (*decrypt)(struct ablkcipher_request *req); - int (*givencrypt)(struct skcipher_givcrypt_request *req); - int (*givdecrypt)(struct skcipher_givcrypt_request *req); - - const char *geniv; - - unsigned int min_keysize; - unsigned int max_keysize; - unsigned int ivsize; -}; - -/** - * struct blkcipher_alg - synchronous block cipher definition - * @min_keysize: see struct ablkcipher_alg - * @max_keysize: see struct ablkcipher_alg - * @setkey: see struct ablkcipher_alg - * @encrypt: see struct ablkcipher_alg - * @decrypt: see struct ablkcipher_alg - * @geniv: see struct ablkcipher_alg - * @ivsize: see struct ablkcipher_alg - * - * All fields except @geniv and @ivsize are mandatory and must be filled. - */ -struct blkcipher_alg { - int (*setkey)(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen); - int (*encrypt)(struct blkcipher_desc *desc, - struct scatterlist *dst, struct scatterlist *src, - unsigned int nbytes); - int (*decrypt)(struct blkcipher_desc *desc, - struct scatterlist *dst, struct scatterlist *src, - unsigned int nbytes); - - const char *geniv; - - unsigned int min_keysize; - unsigned int max_keysize; - unsigned int ivsize; -}; - -/** - * struct cipher_alg - single-block symmetric ciphers definition - * @cia_min_keysize: Minimum key size supported by the transformation. This is - * the smallest key length supported by this transformation - * algorithm. This must be set to one of the pre-defined - * values as this is not hardware specific. Possible values - * for this field can be found via git grep "_MIN_KEY_SIZE" - * include/crypto/ - * @cia_max_keysize: Maximum key size supported by the transformation. This is - * the largest key length supported by this transformation - * algorithm. This must be set to one of the pre-defined values - * as this is not hardware specific. Possible values for this - * field can be found via git grep "_MAX_KEY_SIZE" - * include/crypto/ - * @cia_setkey: Set key for the transformation. This function is used to either - * program a supplied key into the hardware or store the key in the - * transformation context for programming it later. Note that this - * function does modify the transformation context. This function - * can be called multiple times during the existence of the - * transformation object, so one must make sure the key is properly - * reprogrammed into the hardware. This function is also - * responsible for checking the key length for validity. - * @cia_encrypt: Encrypt a single block. This function is used to encrypt a - * single block of data, which must be @cra_blocksize big. This - * always operates on a full @cra_blocksize and it is not possible - * to encrypt a block of smaller size. The supplied buffers must - * therefore also be at least of @cra_blocksize size. Both the - * input and output buffers are always aligned to @cra_alignmask. - * In case either of the input or output buffer supplied by user - * of the crypto API is not aligned to @cra_alignmask, the crypto - * API will re-align the buffers. The re-alignment means that a - * new buffer will be allocated, the data will be copied into the - * new buffer, then the processing will happen on the new buffer, - * then the data will be copied back into the original buffer and - * finally the new buffer will be freed. In case a software - * fallback was put in place in the @cra_init call, this function - * might need to use the fallback if the algorithm doesn't support - * all of the key sizes. In case the key was stored in - * transformation context, the key might need to be re-programmed - * into the hardware in this function. This function shall not - * modify the transformation context, as this function may be - * called in parallel with the same transformation object. - * @cia_decrypt: Decrypt a single block. This is a reverse counterpart to - * @cia_encrypt, and the conditions are exactly the same. - * - * All fields are mandatory and must be filled. - */ -struct cipher_alg { - unsigned int cia_min_keysize; - unsigned int cia_max_keysize; - int (*cia_setkey)(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen); - void (*cia_encrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); - void (*cia_decrypt)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); -}; - -struct compress_alg { - int (*coa_compress)(struct crypto_tfm *tfm, const u8 *src, - unsigned int slen, u8 *dst, unsigned int *dlen); - int (*coa_decompress)(struct crypto_tfm *tfm, const u8 *src, - unsigned int slen, u8 *dst, unsigned int *dlen); -}; - - -#define cra_ablkcipher cra_u.ablkcipher -#define cra_blkcipher cra_u.blkcipher -#define cra_cipher cra_u.cipher -#define cra_compress cra_u.compress - -/** - * struct crypto_alg - definition of a cryptograpic cipher algorithm - * @cra_flags: Flags describing this transformation. See include/linux/crypto.h - * CRYPTO_ALG_* flags for the flags which go in here. Those are - * used for fine-tuning the description of the transformation - * algorithm. - * @cra_blocksize: Minimum block size of this transformation. The size in bytes - * of the smallest possible unit which can be transformed with - * this algorithm. The users must respect this value. - * In case of HASH transformation, it is possible for a smaller - * block than @cra_blocksize to be passed to the crypto API for - * transformation, in case of any other transformation type, an - * error will be returned upon any attempt to transform smaller - * than @cra_blocksize chunks. - * @cra_ctxsize: Size of the operational context of the transformation. This - * value informs the kernel crypto API about the memory size - * needed to be allocated for the transformation context. - * @cra_alignmask: Alignment mask for the input and output data buffer. The data - * buffer containing the input data for the algorithm must be - * aligned to this alignment mask. The data buffer for the - * output data must be aligned to this alignment mask. Note that - * the Crypto API will do the re-alignment in software, but - * only under special conditions and there is a performance hit. - * The re-alignment happens at these occasions for different - * @cra_u types: cipher -- For both input data and output data - * buffer; ahash -- For output hash destination buf; shash -- - * For output hash destination buf. - * This is needed on hardware which is flawed by design and - * cannot pick data from arbitrary addresses. - * @cra_priority: Priority of this transformation implementation. In case - * multiple transformations with same @cra_name are available to - * the Crypto API, the kernel will use the one with highest - * @cra_priority. - * @cra_name: Generic name (usable by multiple implementations) of the - * transformation algorithm. This is the name of the transformation - * itself. This field is used by the kernel when looking up the - * providers of particular transformation. - * @cra_driver_name: Unique name of the transformation provider. This is the - * name of the provider of the transformation. This can be any - * arbitrary value, but in the usual case, this contains the - * name of the chip or provider and the name of the - * transformation algorithm. - * @cra_type: Type of the cryptographic transformation. This is a pointer to - * struct crypto_type, which implements callbacks common for all - * transformation types. There are multiple options: - * &crypto_blkcipher_type, &crypto_ablkcipher_type, - * &crypto_ahash_type, &crypto_rng_type. - * This field might be empty. In that case, there are no common - * callbacks. This is the case for: cipher, compress, shash. - * @cra_u: Callbacks implementing the transformation. This is a union of - * multiple structures. Depending on the type of transformation selected - * by @cra_type and @cra_flags above, the associated structure must be - * filled with callbacks. This field might be empty. This is the case - * for ahash, shash. - * @cra_init: Initialize the cryptographic transformation object. This function - * is used to initialize the cryptographic transformation object. - * This function is called only once at the instantiation time, right - * after the transformation context was allocated. In case the - * cryptographic hardware has some special requirements which need to - * be handled by software, this function shall check for the precise - * requirement of the transformation and put any software fallbacks - * in place. - * @cra_exit: Deinitialize the cryptographic transformation object. This is a - * counterpart to @cra_init, used to remove various changes set in - * @cra_init. - * @cra_module: Owner of this transformation implementation. Set to THIS_MODULE - * @cra_list: internally used - * @cra_users: internally used - * @cra_refcnt: internally used - * @cra_destroy: internally used - * - * The struct crypto_alg describes a generic Crypto API algorithm and is common - * for all of the transformations. Any variable not documented here shall not - * be used by a cipher implementation as it is internal to the Crypto API. - */ -struct crypto_alg { - struct list_head cra_list; - struct list_head cra_users; - - u32 cra_flags; - unsigned int cra_blocksize; - unsigned int cra_ctxsize; - unsigned int cra_alignmask; - - int cra_priority; - atomic_t cra_refcnt; - - char cra_name[CRYPTO_MAX_ALG_NAME]; - char cra_driver_name[CRYPTO_MAX_ALG_NAME]; - - const struct crypto_type *cra_type; - - union { - struct ablkcipher_alg ablkcipher; - struct blkcipher_alg blkcipher; - struct cipher_alg cipher; - struct compress_alg compress; - } cra_u; - - int (*cra_init)(struct crypto_tfm *tfm); - void (*cra_exit)(struct crypto_tfm *tfm); - void (*cra_destroy)(struct crypto_alg *alg); - - struct module *cra_module; -} CRYPTO_MINALIGN_ATTR; - -/* - * Algorithm registration interface. - */ -int crypto_register_alg(struct crypto_alg *alg); -int crypto_unregister_alg(struct crypto_alg *alg); -int crypto_register_algs(struct crypto_alg *algs, int count); -int crypto_unregister_algs(struct crypto_alg *algs, int count); - -/* - * Algorithm query interface. - */ -int crypto_has_alg(const char *name, u32 type, u32 mask); - -/* - * Transforms: user-instantiated objects which encapsulate algorithms - * and core processing logic. Managed via crypto_alloc_*() and - * crypto_free_*(), as well as the various helpers below. - */ - -struct ablkcipher_tfm { - int (*setkey)(struct crypto_ablkcipher *tfm, const u8 *key, - unsigned int keylen); - int (*encrypt)(struct ablkcipher_request *req); - int (*decrypt)(struct ablkcipher_request *req); - - struct crypto_ablkcipher *base; - - unsigned int ivsize; - unsigned int reqsize; -}; - -struct blkcipher_tfm { - void *iv; - int (*setkey)(struct crypto_tfm *tfm, const u8 *key, - unsigned int keylen); - int (*encrypt)(struct blkcipher_desc *desc, struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes); - int (*decrypt)(struct blkcipher_desc *desc, struct scatterlist *dst, - struct scatterlist *src, unsigned int nbytes); -}; - -struct cipher_tfm { - int (*cit_setkey)(struct crypto_tfm *tfm, - const u8 *key, unsigned int keylen); - void (*cit_encrypt_one)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); - void (*cit_decrypt_one)(struct crypto_tfm *tfm, u8 *dst, const u8 *src); -}; - -struct compress_tfm { - int (*cot_compress)(struct crypto_tfm *tfm, - const u8 *src, unsigned int slen, - u8 *dst, unsigned int *dlen); - int (*cot_decompress)(struct crypto_tfm *tfm, - const u8 *src, unsigned int slen, - u8 *dst, unsigned int *dlen); -}; - -#define crt_ablkcipher crt_u.ablkcipher -#define crt_blkcipher crt_u.blkcipher -#define crt_cipher crt_u.cipher -#define crt_compress crt_u.compress - -struct crypto_tfm { - - u32 crt_flags; - - union { - struct ablkcipher_tfm ablkcipher; - struct blkcipher_tfm blkcipher; - struct cipher_tfm cipher; - struct compress_tfm compress; - } crt_u; - - void (*exit)(struct crypto_tfm *tfm); - - struct crypto_alg *__crt_alg; - - void *__crt_ctx[] CRYPTO_MINALIGN_ATTR; -}; - -struct crypto_ablkcipher { - struct crypto_tfm base; -}; - -struct crypto_blkcipher { - struct crypto_tfm base; -}; - -struct crypto_cipher { - struct crypto_tfm base; -}; - -struct crypto_comp { - struct crypto_tfm base; -}; - -enum { - CRYPTOA_UNSPEC, - CRYPTOA_ALG, - CRYPTOA_TYPE, - CRYPTOA_U32, - __CRYPTOA_MAX, -}; - -#define CRYPTOA_MAX (__CRYPTOA_MAX - 1) - -/* Maximum number of (rtattr) parameters for each template. */ -#define CRYPTO_MAX_ATTRS 32 - -struct crypto_attr_alg { - char name[CRYPTO_MAX_ALG_NAME]; -}; - -struct crypto_attr_type { - u32 type; - u32 mask; -}; - -struct crypto_attr_u32 { - u32 num; -}; - -/* - * Transform user interface. - */ - -struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask); -void crypto_destroy_tfm(void *mem, struct crypto_tfm *tfm); - -static inline void crypto_free_tfm(struct crypto_tfm *tfm) -{ - return crypto_destroy_tfm(tfm, tfm); -} - -int alg_test(const char *driver, const char *alg, u32 type, u32 mask); - -/* - * Transform helpers which query the underlying algorithm. - */ -static inline const char *crypto_tfm_alg_name(struct crypto_tfm *tfm) -{ - return tfm->__crt_alg->cra_name; -} - -static inline const char *crypto_tfm_alg_driver_name(struct crypto_tfm *tfm) -{ - return tfm->__crt_alg->cra_driver_name; -} - -static inline int crypto_tfm_alg_priority(struct crypto_tfm *tfm) -{ - return tfm->__crt_alg->cra_priority; -} - -static inline u32 crypto_tfm_alg_type(struct crypto_tfm *tfm) -{ - return tfm->__crt_alg->cra_flags & CRYPTO_ALG_TYPE_MASK; -} - -static inline unsigned int crypto_tfm_alg_blocksize(struct crypto_tfm *tfm) -{ - return tfm->__crt_alg->cra_blocksize; -} - -static inline unsigned int crypto_tfm_alg_alignmask(struct crypto_tfm *tfm) -{ - return tfm->__crt_alg->cra_alignmask; -} - -static inline u32 crypto_tfm_get_flags(struct crypto_tfm *tfm) -{ - return tfm->crt_flags; -} - -static inline void crypto_tfm_set_flags(struct crypto_tfm *tfm, u32 flags) -{ - tfm->crt_flags |= flags; -} - -static inline void crypto_tfm_clear_flags(struct crypto_tfm *tfm, u32 flags) -{ - tfm->crt_flags &= ~flags; -} - -static inline void *crypto_tfm_ctx(struct crypto_tfm *tfm) -{ - return tfm->__crt_ctx; -} - -static inline unsigned int crypto_tfm_ctx_alignment(void) -{ - struct crypto_tfm *tfm; - return __alignof__(tfm->__crt_ctx); -} - -/* - * API wrappers. - */ -static inline struct crypto_ablkcipher *__crypto_ablkcipher_cast( - struct crypto_tfm *tfm) -{ - return (struct crypto_ablkcipher *)tfm; -} - -static inline u32 crypto_skcipher_type(u32 type) -{ - type &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); - type |= CRYPTO_ALG_TYPE_BLKCIPHER; - return type; -} - -static inline u32 crypto_skcipher_mask(u32 mask) -{ - mask &= ~(CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV); - mask |= CRYPTO_ALG_TYPE_BLKCIPHER_MASK; - return mask; -} - -/** - * DOC: Asynchronous Block Cipher API - * - * Asynchronous block cipher API is used with the ciphers of type - * CRYPTO_ALG_TYPE_ABLKCIPHER (listed as type "ablkcipher" in /proc/crypto). - * - * Asynchronous cipher operations imply that the function invocation for a - * cipher request returns immediately before the completion of the operation. - * The cipher request is scheduled as a separate kernel thread and therefore - * load-balanced on the different CPUs via the process scheduler. To allow - * the kernel crypto API to inform the caller about the completion of a cipher - * request, the caller must provide a callback function. That function is - * invoked with the cipher handle when the request completes. - * - * To support the asynchronous operation, additional information than just the - * cipher handle must be supplied to the kernel crypto API. That additional - * information is given by filling in the ablkcipher_request data structure. - * - * For the asynchronous block cipher API, the state is maintained with the tfm - * cipher handle. A single tfm can be used across multiple calls and in - * parallel. For asynchronous block cipher calls, context data supplied and - * only used by the caller can be referenced the request data structure in - * addition to the IV used for the cipher request. The maintenance of such - * state information would be important for a crypto driver implementer to - * have, because when calling the callback function upon completion of the - * cipher operation, that callback function may need some information about - * which operation just finished if it invoked multiple in parallel. This - * state information is unused by the kernel crypto API. - */ - -static inline struct crypto_tfm *crypto_ablkcipher_tfm( - struct crypto_ablkcipher *tfm) -{ - return &tfm->base; -} - -/** - * crypto_free_ablkcipher() - zeroize and free cipher handle - * @tfm: cipher handle to be freed - */ -static inline void crypto_free_ablkcipher(struct crypto_ablkcipher *tfm) -{ - crypto_free_tfm(crypto_ablkcipher_tfm(tfm)); -} - -/** - * crypto_has_ablkcipher() - Search for the availability of an ablkcipher. - * @alg_name: is the cra_name / name or cra_driver_name / driver name of the - * ablkcipher - * @type: specifies the type of the cipher - * @mask: specifies the mask for the cipher - * - * Return: true when the ablkcipher is known to the kernel crypto API; false - * otherwise - */ -static inline int crypto_has_ablkcipher(const char *alg_name, u32 type, - u32 mask) -{ - return crypto_has_alg(alg_name, crypto_skcipher_type(type), - crypto_skcipher_mask(mask)); -} - -static inline struct ablkcipher_tfm *crypto_ablkcipher_crt( - struct crypto_ablkcipher *tfm) -{ - return &crypto_ablkcipher_tfm(tfm)->crt_ablkcipher; -} - -/** - * crypto_ablkcipher_ivsize() - obtain IV size - * @tfm: cipher handle - * - * The size of the IV for the ablkcipher referenced by the cipher handle is - * returned. This IV size may be zero if the cipher does not need an IV. - * - * Return: IV size in bytes - */ -static inline unsigned int crypto_ablkcipher_ivsize( - struct crypto_ablkcipher *tfm) -{ - return crypto_ablkcipher_crt(tfm)->ivsize; -} - -/** - * crypto_ablkcipher_blocksize() - obtain block size of cipher - * @tfm: cipher handle - * - * The block size for the ablkcipher referenced with the cipher handle is - * returned. The caller may use that information to allocate appropriate - * memory for the data returned by the encryption or decryption operation - * - * Return: block size of cipher - */ -static inline unsigned int crypto_ablkcipher_blocksize( - struct crypto_ablkcipher *tfm) -{ - return crypto_tfm_alg_blocksize(crypto_ablkcipher_tfm(tfm)); -} - -static inline unsigned int crypto_ablkcipher_alignmask( - struct crypto_ablkcipher *tfm) -{ - return crypto_tfm_alg_alignmask(crypto_ablkcipher_tfm(tfm)); -} - -static inline u32 crypto_ablkcipher_get_flags(struct crypto_ablkcipher *tfm) -{ - return crypto_tfm_get_flags(crypto_ablkcipher_tfm(tfm)); -} - -static inline void crypto_ablkcipher_set_flags(struct crypto_ablkcipher *tfm, - u32 flags) -{ - crypto_tfm_set_flags(crypto_ablkcipher_tfm(tfm), flags); -} - -static inline void crypto_ablkcipher_clear_flags(struct crypto_ablkcipher *tfm, - u32 flags) -{ - crypto_tfm_clear_flags(crypto_ablkcipher_tfm(tfm), flags); -} - -/** - * crypto_ablkcipher_setkey() - set key for cipher - * @tfm: cipher handle - * @key: buffer holding the key - * @keylen: length of the key in bytes - * - * The caller provided key is set for the ablkcipher referenced by the cipher - * handle. - * - * Note, the key length determines the cipher type. Many block ciphers implement - * different cipher modes depending on the key size, such as AES-128 vs AES-192 - * vs. AES-256. When providing a 16 byte key for an AES cipher handle, AES-128 - * is performed. - * - * Return: 0 if the setting of the key was successful; < 0 if an error occurred - */ -static inline int crypto_ablkcipher_setkey(struct crypto_ablkcipher *tfm, - const u8 *key, unsigned int keylen) -{ - struct ablkcipher_tfm *crt = crypto_ablkcipher_crt(tfm); - - return crt->setkey(crt->base, key, keylen); -} - -/** - * crypto_ablkcipher_reqtfm() - obtain cipher handle from request - * @req: ablkcipher_request out of which the cipher handle is to be obtained - * - * Return the crypto_ablkcipher handle when furnishing an ablkcipher_request - * data structure. - * - * Return: crypto_ablkcipher handle - */ -static inline struct crypto_ablkcipher *crypto_ablkcipher_reqtfm( - struct ablkcipher_request *req) -{ - return __crypto_ablkcipher_cast(req->base.tfm); -} - -/** - * crypto_ablkcipher_encrypt() - encrypt plaintext - * @req: reference to the ablkcipher_request handle that holds all information - * needed to perform the cipher operation - * - * Encrypt plaintext data using the ablkcipher_request handle. That data - * structure and how it is filled with data is discussed with the - * ablkcipher_request_* functions. - * - * Return: 0 if the cipher operation was successful; < 0 if an error occurred - */ -static inline int crypto_ablkcipher_encrypt(struct ablkcipher_request *req) -{ - struct ablkcipher_tfm *crt = - crypto_ablkcipher_crt(crypto_ablkcipher_reqtfm(req)); - return crt->encrypt(req); -} - -/** - * crypto_ablkcipher_decrypt() - decrypt ciphertext - * @req: reference to the ablkcipher_request handle that holds all information - * needed to perform the cipher operation - * - * Decrypt ciphertext data using the ablkcipher_request handle. That data - * structure and how it is filled with data is discussed with the - * ablkcipher_request_* functions. - * - * Return: 0 if the cipher operation was successful; < 0 if an error occurred - */ -static inline int crypto_ablkcipher_decrypt(struct ablkcipher_request *req) -{ - struct ablkcipher_tfm *crt = - crypto_ablkcipher_crt(crypto_ablkcipher_reqtfm(req)); - return crt->decrypt(req); -} - -/** - * DOC: Asynchronous Cipher Request Handle - * - * The ablkcipher_request data structure contains all pointers to data - * required for the asynchronous cipher operation. This includes the cipher - * handle (which can be used by multiple ablkcipher_request instances), pointer - * to plaintext and ciphertext, asynchronous callback function, etc. It acts - * as a handle to the ablkcipher_request_* API calls in a similar way as - * ablkcipher handle to the crypto_ablkcipher_* API calls. - */ - -/** - * crypto_ablkcipher_reqsize() - obtain size of the request data structure - * @tfm: cipher handle - * - * Return: number of bytes - */ -static inline unsigned int crypto_ablkcipher_reqsize( - struct crypto_ablkcipher *tfm) -{ - return crypto_ablkcipher_crt(tfm)->reqsize; -} - -/** - * ablkcipher_request_set_tfm() - update cipher handle reference in request - * @req: request handle to be modified - * @tfm: cipher handle that shall be added to the request handle - * - * Allow the caller to replace the existing ablkcipher handle in the request - * data structure with a different one. - */ -static inline void ablkcipher_request_set_tfm( - struct ablkcipher_request *req, struct crypto_ablkcipher *tfm) -{ - req->base.tfm = crypto_ablkcipher_tfm(crypto_ablkcipher_crt(tfm)->base); -} - -static inline struct ablkcipher_request *ablkcipher_request_cast( - struct crypto_async_request *req) -{ - return container_of(req, struct ablkcipher_request, base); -} - -/** - * ablkcipher_request_alloc() - allocate request data structure - * @tfm: cipher handle to be registered with the request - * @gfp: memory allocation flag that is handed to kmalloc by the API call. - * - * Allocate the request data structure that must be used with the ablkcipher - * encrypt and decrypt API calls. During the allocation, the provided ablkcipher - * handle is registered in the request data structure. - * - * Return: allocated request handle in case of success, or NULL if out of memory - */ -static inline struct ablkcipher_request *ablkcipher_request_alloc( - struct crypto_ablkcipher *tfm, gfp_t gfp) -{ - struct ablkcipher_request *req; - - req = kmalloc(sizeof(struct ablkcipher_request) + - crypto_ablkcipher_reqsize(tfm), gfp); - - if (likely(req)) - ablkcipher_request_set_tfm(req, tfm); - - return req; -} - -/** - * ablkcipher_request_free() - zeroize and free request data structure - * @req: request data structure cipher handle to be freed - */ -static inline void ablkcipher_request_free(struct ablkcipher_request *req) -{ - kzfree(req); -} - -/** - * ablkcipher_request_set_callback() - set asynchronous callback function - * @req: request handle - * @flags: specify zero or an ORing of the flags - * CRYPTO_TFM_REQ_MAY_BACKLOG the request queue may back log and - * increase the wait queue beyond the initial maximum size; - * CRYPTO_TFM_REQ_MAY_SLEEP the request processing may sleep - * @compl: callback function pointer to be registered with the request handle - * @data: The data pointer refers to memory that is not used by the kernel - * crypto API, but provided to the callback function for it to use. Here, - * the caller can provide a reference to memory the callback function can - * operate on. As the callback function is invoked asynchronously to the - * related functionality, it may need to access data structures of the - * related functionality which can be referenced using this pointer. The - * callback function can access the memory via the "data" field in the - * crypto_async_request data structure provided to the callback function. - * - * This function allows setting the callback function that is triggered once the - * cipher operation completes. - * - * The callback function is registered with the ablkcipher_request handle and - * must comply with the following template - * - * void callback_function(struct crypto_async_request *req, int error) - */ -static inline void ablkcipher_request_set_callback( - struct ablkcipher_request *req, - u32 flags, crypto_completion_t compl, void *data) -{ - req->base.complete = compl; - req->base.data = data; - req->base.flags = flags; -} - -/** - * ablkcipher_request_set_crypt() - set data buffers - * @req: request handle - * @src: source scatter / gather list - * @dst: destination scatter / gather list - * @nbytes: number of bytes to process from @src - * @iv: IV for the cipher operation which must comply with the IV size defined - * by crypto_ablkcipher_ivsize - * - * This function allows setting of the source data and destination data - * scatter / gather lists. - * - * For encryption, the source is treated as the plaintext and the - * destination is the ciphertext. For a decryption operation, the use is - * reversed - the source is the ciphertext and the destination is the plaintext. - */ -static inline void ablkcipher_request_set_crypt( - struct ablkcipher_request *req, - struct scatterlist *src, struct scatterlist *dst, - unsigned int nbytes, void *iv) -{ - req->src = src; - req->dst = dst; - req->nbytes = nbytes; - req->info = iv; -} - -/** - * DOC: Synchronous Block Cipher API - * - * The synchronous block cipher API is used with the ciphers of type - * CRYPTO_ALG_TYPE_BLKCIPHER (listed as type "blkcipher" in /proc/crypto) - * - * Synchronous calls, have a context in the tfm. But since a single tfm can be - * used in multiple calls and in parallel, this info should not be changeable - * (unless a lock is used). This applies, for example, to the symmetric key. - * However, the IV is changeable, so there is an iv field in blkcipher_tfm - * structure for synchronous blkcipher api. So, its the only state info that can - * be kept for synchronous calls without using a big lock across a tfm. - * - * The block cipher API allows the use of a complete cipher, i.e. a cipher - * consisting of a template (a block chaining mode) and a single block cipher - * primitive (e.g. AES). - * - * The plaintext data buffer and the ciphertext data buffer are pointed to - * by using scatter/gather lists. The cipher operation is performed - * on all segments of the provided scatter/gather lists. - * - * The kernel crypto API supports a cipher operation "in-place" which means that - * the caller may provide the same scatter/gather list for the plaintext and - * cipher text. After the completion of the cipher operation, the plaintext - * data is replaced with the ciphertext data in case of an encryption and vice - * versa for a decryption. The caller must ensure that the scatter/gather lists - * for the output data point to sufficiently large buffers, i.e. multiples of - * the block size of the cipher. - */ - -static inline struct crypto_blkcipher *__crypto_blkcipher_cast( - struct crypto_tfm *tfm) -{ - return (struct crypto_blkcipher *)tfm; -} - -static inline struct crypto_blkcipher *crypto_blkcipher_cast( - struct crypto_tfm *tfm) -{ - BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_BLKCIPHER); - return __crypto_blkcipher_cast(tfm); -} - -/** - * crypto_alloc_blkcipher() - allocate synchronous block cipher handle - * @alg_name: is the cra_name / name or cra_driver_name / driver name of the - * blkcipher cipher - * @type: specifies the type of the cipher - * @mask: specifies the mask for the cipher - * - * Allocate a cipher handle for a block cipher. The returned struct - * crypto_blkcipher is the cipher handle that is required for any subsequent - * API invocation for that block cipher. - * - * Return: allocated cipher handle in case of success; IS_ERR() is true in case - * of an error, PTR_ERR() returns the error code. - */ -static inline struct crypto_blkcipher *crypto_alloc_blkcipher( - const char *alg_name, u32 type, u32 mask) -{ - type &= ~CRYPTO_ALG_TYPE_MASK; - type |= CRYPTO_ALG_TYPE_BLKCIPHER; - mask |= CRYPTO_ALG_TYPE_MASK; - - return __crypto_blkcipher_cast(crypto_alloc_base(alg_name, type, mask)); -} - -static inline struct crypto_tfm *crypto_blkcipher_tfm( - struct crypto_blkcipher *tfm) -{ - return &tfm->base; -} - -/** - * crypto_free_blkcipher() - zeroize and free the block cipher handle - * @tfm: cipher handle to be freed - */ -static inline void crypto_free_blkcipher(struct crypto_blkcipher *tfm) -{ - crypto_free_tfm(crypto_blkcipher_tfm(tfm)); -} - -/** - * crypto_has_blkcipher() - Search for the availability of a block cipher - * @alg_name: is the cra_name / name or cra_driver_name / driver name of the - * block cipher - * @type: specifies the type of the cipher - * @mask: specifies the mask for the cipher - * - * Return: true when the block cipher is known to the kernel crypto API; false - * otherwise - */ -static inline int crypto_has_blkcipher(const char *alg_name, u32 type, u32 mask) -{ - type &= ~CRYPTO_ALG_TYPE_MASK; - type |= CRYPTO_ALG_TYPE_BLKCIPHER; - mask |= CRYPTO_ALG_TYPE_MASK; - - return crypto_has_alg(alg_name, type, mask); -} - -/** - * crypto_blkcipher_name() - return the name / cra_name from the cipher handle - * @tfm: cipher handle - * - * Return: The character string holding the name of the cipher - */ -static inline const char *crypto_blkcipher_name(struct crypto_blkcipher *tfm) -{ - return crypto_tfm_alg_name(crypto_blkcipher_tfm(tfm)); -} - -static inline struct blkcipher_tfm *crypto_blkcipher_crt( - struct crypto_blkcipher *tfm) -{ - return &crypto_blkcipher_tfm(tfm)->crt_blkcipher; -} - -static inline struct blkcipher_alg *crypto_blkcipher_alg( - struct crypto_blkcipher *tfm) -{ - return &crypto_blkcipher_tfm(tfm)->__crt_alg->cra_blkcipher; -} - -/** - * crypto_blkcipher_ivsize() - obtain IV size - * @tfm: cipher handle - * - * The size of the IV for the block cipher referenced by the cipher handle is - * returned. This IV size may be zero if the cipher does not need an IV. - * - * Return: IV size in bytes - */ -static inline unsigned int crypto_blkcipher_ivsize(struct crypto_blkcipher *tfm) -{ - return crypto_blkcipher_alg(tfm)->ivsize; -} - -/** - * crypto_blkcipher_blocksize() - obtain block size of cipher - * @tfm: cipher handle - * - * The block size for the block cipher referenced with the cipher handle is - * returned. The caller may use that information to allocate appropriate - * memory for the data returned by the encryption or decryption operation. - * - * Return: block size of cipher - */ -static inline unsigned int crypto_blkcipher_blocksize( - struct crypto_blkcipher *tfm) -{ - return crypto_tfm_alg_blocksize(crypto_blkcipher_tfm(tfm)); -} - -static inline unsigned int crypto_blkcipher_alignmask( - struct crypto_blkcipher *tfm) -{ - return crypto_tfm_alg_alignmask(crypto_blkcipher_tfm(tfm)); -} - -static inline u32 crypto_blkcipher_get_flags(struct crypto_blkcipher *tfm) -{ - return crypto_tfm_get_flags(crypto_blkcipher_tfm(tfm)); -} - -static inline void crypto_blkcipher_set_flags(struct crypto_blkcipher *tfm, - u32 flags) -{ - crypto_tfm_set_flags(crypto_blkcipher_tfm(tfm), flags); -} - -static inline void crypto_blkcipher_clear_flags(struct crypto_blkcipher *tfm, - u32 flags) -{ - crypto_tfm_clear_flags(crypto_blkcipher_tfm(tfm), flags); -} - -/** - * crypto_blkcipher_setkey() - set key for cipher - * @tfm: cipher handle - * @key: buffer holding the key - * @keylen: length of the key in bytes - * - * The caller provided key is set for the block cipher referenced by the cipher - * handle. - * - * Note, the key length determines the cipher type. Many block ciphers implement - * different cipher modes depending on the key size, such as AES-128 vs AES-192 - * vs. AES-256. When providing a 16 byte key for an AES cipher handle, AES-128 - * is performed. - * - * Return: 0 if the setting of the key was successful; < 0 if an error occurred - */ -static inline int crypto_blkcipher_setkey(struct crypto_blkcipher *tfm, - const u8 *key, unsigned int keylen) -{ - return crypto_blkcipher_crt(tfm)->setkey(crypto_blkcipher_tfm(tfm), - key, keylen); -} - -/** - * crypto_blkcipher_encrypt() - encrypt plaintext - * @desc: reference to the block cipher handle with meta data - * @dst: scatter/gather list that is filled by the cipher operation with the - * ciphertext - * @src: scatter/gather list that holds the plaintext - * @nbytes: number of bytes of the plaintext to encrypt. - * - * Encrypt plaintext data using the IV set by the caller with a preceding - * call of crypto_blkcipher_set_iv. - * - * The blkcipher_desc data structure must be filled by the caller and can - * reside on the stack. The caller must fill desc as follows: desc.tfm is filled - * with the block cipher handle; desc.flags is filled with either - * CRYPTO_TFM_REQ_MAY_SLEEP or 0. - * - * Return: 0 if the cipher operation was successful; < 0 if an error occurred - */ -static inline int crypto_blkcipher_encrypt(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - desc->info = crypto_blkcipher_crt(desc->tfm)->iv; - return crypto_blkcipher_crt(desc->tfm)->encrypt(desc, dst, src, nbytes); -} - -/** - * crypto_blkcipher_encrypt_iv() - encrypt plaintext with dedicated IV - * @desc: reference to the block cipher handle with meta data - * @dst: scatter/gather list that is filled by the cipher operation with the - * ciphertext - * @src: scatter/gather list that holds the plaintext - * @nbytes: number of bytes of the plaintext to encrypt. - * - * Encrypt plaintext data with the use of an IV that is solely used for this - * cipher operation. Any previously set IV is not used. - * - * The blkcipher_desc data structure must be filled by the caller and can - * reside on the stack. The caller must fill desc as follows: desc.tfm is filled - * with the block cipher handle; desc.info is filled with the IV to be used for - * the current operation; desc.flags is filled with either - * CRYPTO_TFM_REQ_MAY_SLEEP or 0. - * - * Return: 0 if the cipher operation was successful; < 0 if an error occurred - */ -static inline int crypto_blkcipher_encrypt_iv(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - return crypto_blkcipher_crt(desc->tfm)->encrypt(desc, dst, src, nbytes); -} - -/** - * crypto_blkcipher_decrypt() - decrypt ciphertext - * @desc: reference to the block cipher handle with meta data - * @dst: scatter/gather list that is filled by the cipher operation with the - * plaintext - * @src: scatter/gather list that holds the ciphertext - * @nbytes: number of bytes of the ciphertext to decrypt. - * - * Decrypt ciphertext data using the IV set by the caller with a preceding - * call of crypto_blkcipher_set_iv. - * - * The blkcipher_desc data structure must be filled by the caller as documented - * for the crypto_blkcipher_encrypt call above. - * - * Return: 0 if the cipher operation was successful; < 0 if an error occurred - * - */ -static inline int crypto_blkcipher_decrypt(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - desc->info = crypto_blkcipher_crt(desc->tfm)->iv; - return crypto_blkcipher_crt(desc->tfm)->decrypt(desc, dst, src, nbytes); -} - -/** - * crypto_blkcipher_decrypt_iv() - decrypt ciphertext with dedicated IV - * @desc: reference to the block cipher handle with meta data - * @dst: scatter/gather list that is filled by the cipher operation with the - * plaintext - * @src: scatter/gather list that holds the ciphertext - * @nbytes: number of bytes of the ciphertext to decrypt. - * - * Decrypt ciphertext data with the use of an IV that is solely used for this - * cipher operation. Any previously set IV is not used. - * - * The blkcipher_desc data structure must be filled by the caller as documented - * for the crypto_blkcipher_encrypt_iv call above. - * - * Return: 0 if the cipher operation was successful; < 0 if an error occurred - */ -static inline int crypto_blkcipher_decrypt_iv(struct blkcipher_desc *desc, - struct scatterlist *dst, - struct scatterlist *src, - unsigned int nbytes) -{ - return crypto_blkcipher_crt(desc->tfm)->decrypt(desc, dst, src, nbytes); -} - -/** - * crypto_blkcipher_set_iv() - set IV for cipher - * @tfm: cipher handle - * @src: buffer holding the IV - * @len: length of the IV in bytes - * - * The caller provided IV is set for the block cipher referenced by the cipher - * handle. - */ -static inline void crypto_blkcipher_set_iv(struct crypto_blkcipher *tfm, - const u8 *src, unsigned int len) -{ - memcpy(crypto_blkcipher_crt(tfm)->iv, src, len); -} - -/** - * crypto_blkcipher_get_iv() - obtain IV from cipher - * @tfm: cipher handle - * @dst: buffer filled with the IV - * @len: length of the buffer dst - * - * The caller can obtain the IV set for the block cipher referenced by the - * cipher handle and store it into the user-provided buffer. If the buffer - * has an insufficient space, the IV is truncated to fit the buffer. - */ -static inline void crypto_blkcipher_get_iv(struct crypto_blkcipher *tfm, - u8 *dst, unsigned int len) -{ - memcpy(dst, crypto_blkcipher_crt(tfm)->iv, len); -} - -/** - * DOC: Single Block Cipher API - * - * The single block cipher API is used with the ciphers of type - * CRYPTO_ALG_TYPE_CIPHER (listed as type "cipher" in /proc/crypto). - * - * Using the single block cipher API calls, operations with the basic cipher - * primitive can be implemented. These cipher primitives exclude any block - * chaining operations including IV handling. - * - * The purpose of this single block cipher API is to support the implementation - * of templates or other concepts that only need to perform the cipher operation - * on one block at a time. Templates invoke the underlying cipher primitive - * block-wise and process either the input or the output data of these cipher - * operations. - */ - -static inline struct crypto_cipher *__crypto_cipher_cast(struct crypto_tfm *tfm) -{ - return (struct crypto_cipher *)tfm; -} - -static inline struct crypto_cipher *crypto_cipher_cast(struct crypto_tfm *tfm) -{ - BUG_ON(crypto_tfm_alg_type(tfm) != CRYPTO_ALG_TYPE_CIPHER); - return __crypto_cipher_cast(tfm); -} - -/** - * crypto_alloc_cipher() - allocate single block cipher handle - * @alg_name: is the cra_name / name or cra_driver_name / driver name of the - * single block cipher - * @type: specifies the type of the cipher - * @mask: specifies the mask for the cipher - * - * Allocate a cipher handle for a single block cipher. The returned struct - * crypto_cipher is the cipher handle that is required for any subsequent API - * invocation for that single block cipher. - * - * Return: allocated cipher handle in case of success; IS_ERR() is true in case - * of an error, PTR_ERR() returns the error code. - */ -static inline struct crypto_cipher *crypto_alloc_cipher(const char *alg_name, - u32 type, u32 mask) -{ - type &= ~CRYPTO_ALG_TYPE_MASK; - type |= CRYPTO_ALG_TYPE_CIPHER; - mask |= CRYPTO_ALG_TYPE_MASK; - - return __crypto_cipher_cast(crypto_alloc_base(alg_name, type, mask)); -} - -static inline struct crypto_tfm *crypto_cipher_tfm(struct crypto_cipher *tfm) -{ - return &tfm->base; -} - -/** - * crypto_free_cipher() - zeroize and free the single block cipher handle - * @tfm: cipher handle to be freed - */ -static inline void crypto_free_cipher(struct crypto_cipher *tfm) -{ - crypto_free_tfm(crypto_cipher_tfm(tfm)); -} - -/** - * crypto_has_cipher() - Search for the availability of a single block cipher - * @alg_name: is the cra_name / name or cra_driver_name / driver name of the - * single block cipher - * @type: specifies the type of the cipher - * @mask: specifies the mask for the cipher - * - * Return: true when the single block cipher is known to the kernel crypto API; - * false otherwise - */ -static inline int crypto_has_cipher(const char *alg_name, u32 type, u32 mask) -{ - type &= ~CRYPTO_ALG_TYPE_MASK; - type |= CRYPTO_ALG_TYPE_CIPHER; - mask |= CRYPTO_ALG_TYPE_MASK; - - return crypto_has_alg(alg_name, type, mask); -} - -static inline struct cipher_tfm *crypto_cipher_crt(struct crypto_cipher *tfm) -{ - return &crypto_cipher_tfm(tfm)->crt_cipher; -} - -/** - * crypto_cipher_blocksize() - obtain block size for cipher - * @tfm: cipher handle - * - * The block size for the single block cipher referenced with the cipher handle - * tfm is returned. The caller may use that information to allocate appropriate - * memory for the data returned by the encryption or decryption operation - * - * Return: block size of cipher - */ -static inline unsigned int crypto_cipher_blocksize(struct crypto_cipher *tfm) -{ - return crypto_tfm_alg_blocksize(crypto_cipher_tfm(tfm)); -} - -static inline unsigned int crypto_cipher_alignmask(struct crypto_cipher *tfm) -{ - return crypto_tfm_alg_alignmask(crypto_cipher_tfm(tfm)); -} - -static inline u32 crypto_cipher_get_flags(struct crypto_cipher *tfm) -{ - return crypto_tfm_get_flags(crypto_cipher_tfm(tfm)); -} - -static inline void crypto_cipher_set_flags(struct crypto_cipher *tfm, - u32 flags) -{ - crypto_tfm_set_flags(crypto_cipher_tfm(tfm), flags); -} - -static inline void crypto_cipher_clear_flags(struct crypto_cipher *tfm, - u32 flags) -{ - crypto_tfm_clear_flags(crypto_cipher_tfm(tfm), flags); -} - -/** - * crypto_cipher_setkey() - set key for cipher - * @tfm: cipher handle - * @key: buffer holding the key - * @keylen: length of the key in bytes - * - * The caller provided key is set for the single block cipher referenced by the - * cipher handle. - * - * Note, the key length determines the cipher type. Many block ciphers implement - * different cipher modes depending on the key size, such as AES-128 vs AES-192 - * vs. AES-256. When providing a 16 byte key for an AES cipher handle, AES-128 - * is performed. - * - * Return: 0 if the setting of the key was successful; < 0 if an error occurred - */ -static inline int crypto_cipher_setkey(struct crypto_cipher *tfm, - const u8 *key, unsigned int keylen) -{ - return crypto_cipher_crt(tfm)->cit_setkey(crypto_cipher_tfm(tfm), - key, keylen); -} - -/** - * crypto_cipher_encrypt_one() - encrypt one block of plaintext - * @tfm: cipher handle - * @dst: points to the buffer that will be filled with the ciphertext - * @src: buffer holding the plaintext to be encrypted - * - * Invoke the encryption operation of one block. The caller must ensure that - * the plaintext and ciphertext buffers are at least one block in size. - */ -static inline void crypto_cipher_encrypt_one(struct crypto_cipher *tfm, - u8 *dst, const u8 *src) -{ - crypto_cipher_crt(tfm)->cit_encrypt_one(crypto_cipher_tfm(tfm), - dst, src); -} - -/** - * crypto_cipher_decrypt_one() - decrypt one block of ciphertext - * @tfm: cipher handle - * @dst: points to the buffer that will be filled with the plaintext - * @src: buffer holding the ciphertext to be decrypted - * - * Invoke the decryption operation of one block. The caller must ensure that - * the plaintext and ciphertext buffers are at least one block in size. - */ -static inline void crypto_cipher_decrypt_one(struct crypto_cipher *tfm, - u8 *dst, const u8 *src) -{ - crypto_cipher_crt(tfm)->cit_decrypt_one(crypto_cipher_tfm(tfm), - dst, src); -} - -static inline struct crypto_comp *__crypto_comp_cast(struct crypto_tfm *tfm) -{ - return (struct crypto_comp *)tfm; -} - -static inline struct crypto_comp *crypto_comp_cast(struct crypto_tfm *tfm) -{ - BUG_ON((crypto_tfm_alg_type(tfm) ^ CRYPTO_ALG_TYPE_COMPRESS) & - CRYPTO_ALG_TYPE_MASK); - return __crypto_comp_cast(tfm); -} - -static inline struct crypto_comp *crypto_alloc_comp(const char *alg_name, - u32 type, u32 mask) -{ - type &= ~CRYPTO_ALG_TYPE_MASK; - type |= CRYPTO_ALG_TYPE_COMPRESS; - mask |= CRYPTO_ALG_TYPE_MASK; - - return __crypto_comp_cast(crypto_alloc_base(alg_name, type, mask)); -} - -static inline struct crypto_tfm *crypto_comp_tfm(struct crypto_comp *tfm) -{ - return &tfm->base; -} - -static inline void crypto_free_comp(struct crypto_comp *tfm) -{ - crypto_free_tfm(crypto_comp_tfm(tfm)); -} - -static inline int crypto_has_comp(const char *alg_name, u32 type, u32 mask) -{ - type &= ~CRYPTO_ALG_TYPE_MASK; - type |= CRYPTO_ALG_TYPE_COMPRESS; - mask |= CRYPTO_ALG_TYPE_MASK; - - return crypto_has_alg(alg_name, type, mask); -} - -static inline const char *crypto_comp_name(struct crypto_comp *tfm) -{ - return crypto_tfm_alg_name(crypto_comp_tfm(tfm)); -} - -static inline struct compress_tfm *crypto_comp_crt(struct crypto_comp *tfm) -{ - return &crypto_comp_tfm(tfm)->crt_compress; -} - -static inline int crypto_comp_compress(struct crypto_comp *tfm, - const u8 *src, unsigned int slen, - u8 *dst, unsigned int *dlen) -{ - return crypto_comp_crt(tfm)->cot_compress(crypto_comp_tfm(tfm), - src, slen, dst, dlen); -} - -static inline int crypto_comp_decompress(struct crypto_comp *tfm, - const u8 *src, unsigned int slen, - u8 *dst, unsigned int *dlen) -{ - return crypto_comp_crt(tfm)->cot_decompress(crypto_comp_tfm(tfm), - src, slen, dst, dlen); -} - -#endif /* _LINUX_CRYPTO_H */ - diff --git a/src/linux/include/linux/cryptohash.h b/src/linux/include/linux/cryptohash.h deleted file mode 100644 index f475428..0000000 --- a/src/linux/include/linux/cryptohash.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __CRYPTOHASH_H -#define __CRYPTOHASH_H - -#include - -#define SHA_DIGEST_WORDS 5 -#define SHA_MESSAGE_BYTES (512 /*bits*/ / 8) -#define SHA_WORKSPACE_WORDS 16 - -void sha_init(__u32 *buf); -void sha_transform(__u32 *digest, const char *data, __u32 *W); - -#define MD5_DIGEST_WORDS 4 -#define MD5_MESSAGE_BYTES 64 - -void md5_transform(__u32 *hash, __u32 const *in); - -__u32 half_md4_transform(__u32 buf[4], __u32 const in[8]); - -#endif diff --git a/src/linux/include/linux/ctype.h b/src/linux/include/linux/ctype.h deleted file mode 100644 index f13e4ff..0000000 --- a/src/linux/include/linux/ctype.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef _LINUX_CTYPE_H -#define _LINUX_CTYPE_H - -/* - * NOTE! This ctype does not handle EOF like the standard C - * library is required to. - */ - -#define _U 0x01 /* upper */ -#define _L 0x02 /* lower */ -#define _D 0x04 /* digit */ -#define _C 0x08 /* cntrl */ -#define _P 0x10 /* punct */ -#define _S 0x20 /* white space (space/lf/tab) */ -#define _X 0x40 /* hex digit */ -#define _SP 0x80 /* hard space (0x20) */ - -extern const unsigned char _ctype[]; - -#define __ismask(x) (_ctype[(int)(unsigned char)(x)]) - -#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0) -#define isalpha(c) ((__ismask(c)&(_U|_L)) != 0) -#define iscntrl(c) ((__ismask(c)&(_C)) != 0) -static inline int isdigit(int c) -{ - return '0' <= c && c <= '9'; -} -#define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0) -#define islower(c) ((__ismask(c)&(_L)) != 0) -#define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0) -#define ispunct(c) ((__ismask(c)&(_P)) != 0) -/* Note: isspace() must return false for %NUL-terminator */ -#define isspace(c) ((__ismask(c)&(_S)) != 0) -#define isupper(c) ((__ismask(c)&(_U)) != 0) -#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0) - -#define isascii(c) (((unsigned char)(c))<=0x7f) -#define toascii(c) (((unsigned char)(c))&0x7f) - -static inline unsigned char __tolower(unsigned char c) -{ - if (isupper(c)) - c -= 'A'-'a'; - return c; -} - -static inline unsigned char __toupper(unsigned char c) -{ - if (islower(c)) - c -= 'a'-'A'; - return c; -} - -#define tolower(c) __tolower(c) -#define toupper(c) __toupper(c) - -/* - * Fast implementation of tolower() for internal usage. Do not use in your - * code. - */ -static inline char _tolower(const char c) -{ - return c | 0x20; -} - -/* Fast check for octal digit */ -static inline int isodigit(const char c) -{ - return c >= '0' && c <= '7'; -} - -#endif diff --git a/src/linux/include/linux/dax.h b/src/linux/include/linux/dax.h deleted file mode 100644 index add6c4b..0000000 --- a/src/linux/include/linux/dax.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef _LINUX_DAX_H -#define _LINUX_DAX_H - -#include -#include -#include -#include - -struct iomap_ops; - -/* We use lowest available exceptional entry bit for locking */ -#define RADIX_DAX_ENTRY_LOCK (1 << RADIX_TREE_EXCEPTIONAL_SHIFT) - -ssize_t iomap_dax_rw(struct kiocb *iocb, struct iov_iter *iter, - struct iomap_ops *ops); -ssize_t dax_do_io(struct kiocb *, struct inode *, struct iov_iter *, - get_block_t, dio_iodone_t, int flags); -int dax_zero_page_range(struct inode *, loff_t from, unsigned len, get_block_t); -int dax_truncate_page(struct inode *, loff_t from, get_block_t); -int iomap_dax_fault(struct vm_area_struct *vma, struct vm_fault *vmf, - struct iomap_ops *ops); -int dax_fault(struct vm_area_struct *, struct vm_fault *, get_block_t); -int dax_delete_mapping_entry(struct address_space *mapping, pgoff_t index); -void dax_wake_mapping_entry_waiter(struct address_space *mapping, - pgoff_t index, bool wake_all); - -#ifdef CONFIG_FS_DAX -struct page *read_dax_sector(struct block_device *bdev, sector_t n); -void dax_unlock_mapping_entry(struct address_space *mapping, pgoff_t index); -int __dax_zero_page_range(struct block_device *bdev, sector_t sector, - unsigned int offset, unsigned int length); -#else -static inline struct page *read_dax_sector(struct block_device *bdev, - sector_t n) -{ - return ERR_PTR(-ENXIO); -} -/* Shouldn't ever be called when dax is disabled. */ -static inline void dax_unlock_mapping_entry(struct address_space *mapping, - pgoff_t index) -{ - BUG(); -} -static inline int __dax_zero_page_range(struct block_device *bdev, - sector_t sector, unsigned int offset, unsigned int length) -{ - return -ENXIO; -} -#endif - -#if defined(CONFIG_TRANSPARENT_HUGEPAGE) -int dax_pmd_fault(struct vm_area_struct *, unsigned long addr, pmd_t *, - unsigned int flags, get_block_t); -#else -static inline int dax_pmd_fault(struct vm_area_struct *vma, unsigned long addr, - pmd_t *pmd, unsigned int flags, get_block_t gb) -{ - return VM_FAULT_FALLBACK; -} -#endif -int dax_pfn_mkwrite(struct vm_area_struct *, struct vm_fault *); -#define dax_mkwrite(vma, vmf, gb) dax_fault(vma, vmf, gb) - -static inline bool vma_is_dax(struct vm_area_struct *vma) -{ - return vma->vm_file && IS_DAX(vma->vm_file->f_mapping->host); -} - -static inline bool dax_mapping(struct address_space *mapping) -{ - return mapping->host && IS_DAX(mapping->host); -} - -struct writeback_control; -int dax_writeback_mapping_range(struct address_space *mapping, - struct block_device *bdev, struct writeback_control *wbc); -#endif diff --git a/src/linux/include/linux/dcache.h b/src/linux/include/linux/dcache.h deleted file mode 100644 index 5beed7b..0000000 --- a/src/linux/include/linux/dcache.h +++ /dev/null @@ -1,594 +0,0 @@ -#ifndef __LINUX_DCACHE_H -#define __LINUX_DCACHE_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct path; -struct vfsmount; - -/* - * linux/include/linux/dcache.h - * - * Dirent cache data structures - * - * (C) Copyright 1997 Thomas Schoebel-Theuer, - * with heavy changes by Linus Torvalds - */ - -#define IS_ROOT(x) ((x) == (x)->d_parent) - -/* The hash is always the low bits of hash_len */ -#ifdef __LITTLE_ENDIAN - #define HASH_LEN_DECLARE u32 hash; u32 len - #define bytemask_from_count(cnt) (~(~0ul << (cnt)*8)) -#else - #define HASH_LEN_DECLARE u32 len; u32 hash - #define bytemask_from_count(cnt) (~(~0ul >> (cnt)*8)) -#endif - -/* - * "quick string" -- eases parameter passing, but more importantly - * saves "metadata" about the string (ie length and the hash). - * - * hash comes first so it snuggles against d_parent in the - * dentry. - */ -struct qstr { - union { - struct { - HASH_LEN_DECLARE; - }; - u64 hash_len; - }; - const unsigned char *name; -}; - -#define QSTR_INIT(n,l) { { { .len = l } }, .name = n } - -struct dentry_stat_t { - long nr_dentry; - long nr_unused; - long age_limit; /* age in seconds */ - long want_pages; /* pages requested by system */ - long dummy[2]; -}; -extern struct dentry_stat_t dentry_stat; - -/* - * Try to keep struct dentry aligned on 64 byte cachelines (this will - * give reasonable cacheline footprint with larger lines without the - * large memory footprint increase). - */ -#ifdef CONFIG_64BIT -# define DNAME_INLINE_LEN 32 /* 192 bytes */ -#else -# ifdef CONFIG_SMP -# define DNAME_INLINE_LEN 36 /* 128 bytes */ -# else -# define DNAME_INLINE_LEN 40 /* 128 bytes */ -# endif -#endif - -#define d_lock d_lockref.lock - -struct dentry { - /* RCU lookup touched fields */ - unsigned int d_flags; /* protected by d_lock */ - seqcount_t d_seq; /* per dentry seqlock */ - struct hlist_bl_node d_hash; /* lookup hash list */ - struct dentry *d_parent; /* parent directory */ - struct qstr d_name; - struct inode *d_inode; /* Where the name belongs to - NULL is - * negative */ - unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */ - - /* Ref lookup also touches following */ - struct lockref d_lockref; /* per-dentry lock and refcount */ - const struct dentry_operations *d_op; - struct super_block *d_sb; /* The root of the dentry tree */ - unsigned long d_time; /* used by d_revalidate */ - void *d_fsdata; /* fs-specific data */ - - union { - struct list_head d_lru; /* LRU list */ - wait_queue_head_t *d_wait; /* in-lookup ones only */ - }; - struct list_head d_child; /* child of parent list */ - struct list_head d_subdirs; /* our children */ - /* - * d_alias and d_rcu can share memory - */ - union { - struct hlist_node d_alias; /* inode alias list */ - struct hlist_bl_node d_in_lookup_hash; /* only for in-lookup ones */ - struct rcu_head d_rcu; - } d_u; -}; - -/* - * dentry->d_lock spinlock nesting subclasses: - * - * 0: normal - * 1: nested - */ -enum dentry_d_lock_class -{ - DENTRY_D_LOCK_NORMAL, /* implicitly used by plain spin_lock() APIs. */ - DENTRY_D_LOCK_NESTED -}; - -struct dentry_operations { - int (*d_revalidate)(struct dentry *, unsigned int); - int (*d_weak_revalidate)(struct dentry *, unsigned int); - int (*d_hash)(const struct dentry *, struct qstr *); - int (*d_compare)(const struct dentry *, - unsigned int, const char *, const struct qstr *); - int (*d_delete)(const struct dentry *); - int (*d_init)(struct dentry *); - void (*d_release)(struct dentry *); - void (*d_prune)(struct dentry *); - void (*d_iput)(struct dentry *, struct inode *); - char *(*d_dname)(struct dentry *, char *, int); - struct vfsmount *(*d_automount)(struct path *); - int (*d_manage)(struct dentry *, bool); - struct dentry *(*d_real)(struct dentry *, const struct inode *, - unsigned int); -} ____cacheline_aligned; - -/* - * Locking rules for dentry_operations callbacks are to be found in - * Documentation/filesystems/Locking. Keep it updated! - * - * FUrther descriptions are found in Documentation/filesystems/vfs.txt. - * Keep it updated too! - */ - -/* d_flags entries */ -#define DCACHE_OP_HASH 0x00000001 -#define DCACHE_OP_COMPARE 0x00000002 -#define DCACHE_OP_REVALIDATE 0x00000004 -#define DCACHE_OP_DELETE 0x00000008 -#define DCACHE_OP_PRUNE 0x00000010 - -#define DCACHE_DISCONNECTED 0x00000020 - /* This dentry is possibly not currently connected to the dcache tree, in - * which case its parent will either be itself, or will have this flag as - * well. nfsd will not use a dentry with this bit set, but will first - * endeavour to clear the bit either by discovering that it is connected, - * or by performing lookup operations. Any filesystem which supports - * nfsd_operations MUST have a lookup function which, if it finds a - * directory inode with a DCACHE_DISCONNECTED dentry, will d_move that - * dentry into place and return that dentry rather than the passed one, - * typically using d_splice_alias. */ - -#define DCACHE_REFERENCED 0x00000040 /* Recently used, don't discard. */ -#define DCACHE_RCUACCESS 0x00000080 /* Entry has ever been RCU-visible */ - -#define DCACHE_CANT_MOUNT 0x00000100 -#define DCACHE_GENOCIDE 0x00000200 -#define DCACHE_SHRINK_LIST 0x00000400 - -#define DCACHE_OP_WEAK_REVALIDATE 0x00000800 - -#define DCACHE_NFSFS_RENAMED 0x00001000 - /* this dentry has been "silly renamed" and has to be deleted on the last - * dput() */ -#define DCACHE_COOKIE 0x00002000 /* For use by dcookie subsystem */ -#define DCACHE_FSNOTIFY_PARENT_WATCHED 0x00004000 - /* Parent inode is watched by some fsnotify listener */ - -#define DCACHE_DENTRY_KILLED 0x00008000 - -#define DCACHE_MOUNTED 0x00010000 /* is a mountpoint */ -#define DCACHE_NEED_AUTOMOUNT 0x00020000 /* handle automount on this dir */ -#define DCACHE_MANAGE_TRANSIT 0x00040000 /* manage transit from this dirent */ -#define DCACHE_MANAGED_DENTRY \ - (DCACHE_MOUNTED|DCACHE_NEED_AUTOMOUNT|DCACHE_MANAGE_TRANSIT) - -#define DCACHE_LRU_LIST 0x00080000 - -#define DCACHE_ENTRY_TYPE 0x00700000 -#define DCACHE_MISS_TYPE 0x00000000 /* Negative dentry (maybe fallthru to nowhere) */ -#define DCACHE_WHITEOUT_TYPE 0x00100000 /* Whiteout dentry (stop pathwalk) */ -#define DCACHE_DIRECTORY_TYPE 0x00200000 /* Normal directory */ -#define DCACHE_AUTODIR_TYPE 0x00300000 /* Lookupless directory (presumed automount) */ -#define DCACHE_REGULAR_TYPE 0x00400000 /* Regular file type (or fallthru to such) */ -#define DCACHE_SPECIAL_TYPE 0x00500000 /* Other file type (or fallthru to such) */ -#define DCACHE_SYMLINK_TYPE 0x00600000 /* Symlink (or fallthru to such) */ - -#define DCACHE_MAY_FREE 0x00800000 -#define DCACHE_FALLTHRU 0x01000000 /* Fall through to lower layer */ -#define DCACHE_ENCRYPTED_WITH_KEY 0x02000000 /* dir is encrypted with a valid key */ -#define DCACHE_OP_REAL 0x04000000 - -#define DCACHE_PAR_LOOKUP 0x10000000 /* being looked up (with parent locked shared) */ -#define DCACHE_DENTRY_CURSOR 0x20000000 - -extern seqlock_t rename_lock; - -/* - * These are the low-level FS interfaces to the dcache.. - */ -extern void d_instantiate(struct dentry *, struct inode *); -extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *); -extern int d_instantiate_no_diralias(struct dentry *, struct inode *); -extern void __d_drop(struct dentry *dentry); -extern void d_drop(struct dentry *dentry); -extern void d_delete(struct dentry *); -extern void d_set_d_op(struct dentry *dentry, const struct dentry_operations *op); - -/* allocate/de-allocate */ -extern struct dentry * d_alloc(struct dentry *, const struct qstr *); -extern struct dentry * d_alloc_pseudo(struct super_block *, const struct qstr *); -extern struct dentry * d_alloc_parallel(struct dentry *, const struct qstr *, - wait_queue_head_t *); -extern struct dentry * d_splice_alias(struct inode *, struct dentry *); -extern struct dentry * d_add_ci(struct dentry *, struct inode *, struct qstr *); -extern struct dentry * d_exact_alias(struct dentry *, struct inode *); -extern struct dentry *d_find_any_alias(struct inode *inode); -extern struct dentry * d_obtain_alias(struct inode *); -extern struct dentry * d_obtain_root(struct inode *); -extern void shrink_dcache_sb(struct super_block *); -extern void shrink_dcache_parent(struct dentry *); -extern void shrink_dcache_for_umount(struct super_block *); -extern void d_invalidate(struct dentry *); - -/* only used at mount-time */ -extern struct dentry * d_make_root(struct inode *); - -/* - the ramfs-type tree */ -extern void d_genocide(struct dentry *); - -extern void d_tmpfile(struct dentry *, struct inode *); - -extern struct dentry *d_find_alias(struct inode *); -extern void d_prune_aliases(struct inode *); - -/* test whether we have any submounts in a subdir tree */ -extern int have_submounts(struct dentry *); - -/* - * This adds the entry to the hash queues. - */ -extern void d_rehash(struct dentry *); - -extern void d_add(struct dentry *, struct inode *); - -extern void dentry_update_name_case(struct dentry *, const struct qstr *); - -/* used for rename() and baskets */ -extern void d_move(struct dentry *, struct dentry *); -extern void d_exchange(struct dentry *, struct dentry *); -extern struct dentry *d_ancestor(struct dentry *, struct dentry *); - -/* appendix may either be NULL or be used for transname suffixes */ -extern struct dentry *d_lookup(const struct dentry *, const struct qstr *); -extern struct dentry *d_hash_and_lookup(struct dentry *, struct qstr *); -extern struct dentry *__d_lookup(const struct dentry *, const struct qstr *); -extern struct dentry *__d_lookup_rcu(const struct dentry *parent, - const struct qstr *name, unsigned *seq); - -static inline unsigned d_count(const struct dentry *dentry) -{ - return dentry->d_lockref.count; -} - -/* - * helper function for dentry_operations.d_dname() members - */ -extern __printf(4, 5) -char *dynamic_dname(struct dentry *, char *, int, const char *, ...); -extern char *simple_dname(struct dentry *, char *, int); - -extern char *__d_path(const struct path *, const struct path *, char *, int); -extern char *d_absolute_path(const struct path *, char *, int); -extern char *d_path(const struct path *, char *, int); -extern char *dentry_path_raw(struct dentry *, char *, int); -extern char *dentry_path(struct dentry *, char *, int); - -/* Allocation counts.. */ - -/** - * dget, dget_dlock - get a reference to a dentry - * @dentry: dentry to get a reference to - * - * Given a dentry or %NULL pointer increment the reference count - * if appropriate and return the dentry. A dentry will not be - * destroyed when it has references. - */ -static inline struct dentry *dget_dlock(struct dentry *dentry) -{ - if (dentry) - dentry->d_lockref.count++; - return dentry; -} - -static inline struct dentry *dget(struct dentry *dentry) -{ - if (dentry) - lockref_get(&dentry->d_lockref); - return dentry; -} - -extern struct dentry *dget_parent(struct dentry *dentry); - -/** - * d_unhashed - is dentry hashed - * @dentry: entry to check - * - * Returns true if the dentry passed is not currently hashed. - */ - -static inline int d_unhashed(const struct dentry *dentry) -{ - return hlist_bl_unhashed(&dentry->d_hash); -} - -static inline int d_unlinked(const struct dentry *dentry) -{ - return d_unhashed(dentry) && !IS_ROOT(dentry); -} - -static inline int cant_mount(const struct dentry *dentry) -{ - return (dentry->d_flags & DCACHE_CANT_MOUNT); -} - -static inline void dont_mount(struct dentry *dentry) -{ - spin_lock(&dentry->d_lock); - dentry->d_flags |= DCACHE_CANT_MOUNT; - spin_unlock(&dentry->d_lock); -} - -extern void __d_lookup_done(struct dentry *); - -static inline int d_in_lookup(struct dentry *dentry) -{ - return dentry->d_flags & DCACHE_PAR_LOOKUP; -} - -static inline void d_lookup_done(struct dentry *dentry) -{ - if (unlikely(d_in_lookup(dentry))) { - spin_lock(&dentry->d_lock); - __d_lookup_done(dentry); - spin_unlock(&dentry->d_lock); - } -} - -extern void dput(struct dentry *); - -static inline bool d_managed(const struct dentry *dentry) -{ - return dentry->d_flags & DCACHE_MANAGED_DENTRY; -} - -static inline bool d_mountpoint(const struct dentry *dentry) -{ - return dentry->d_flags & DCACHE_MOUNTED; -} - -/* - * Directory cache entry type accessor functions. - */ -static inline unsigned __d_entry_type(const struct dentry *dentry) -{ - return dentry->d_flags & DCACHE_ENTRY_TYPE; -} - -static inline bool d_is_miss(const struct dentry *dentry) -{ - return __d_entry_type(dentry) == DCACHE_MISS_TYPE; -} - -static inline bool d_is_whiteout(const struct dentry *dentry) -{ - return __d_entry_type(dentry) == DCACHE_WHITEOUT_TYPE; -} - -static inline bool d_can_lookup(const struct dentry *dentry) -{ - return __d_entry_type(dentry) == DCACHE_DIRECTORY_TYPE; -} - -static inline bool d_is_autodir(const struct dentry *dentry) -{ - return __d_entry_type(dentry) == DCACHE_AUTODIR_TYPE; -} - -static inline bool d_is_dir(const struct dentry *dentry) -{ - return d_can_lookup(dentry) || d_is_autodir(dentry); -} - -static inline bool d_is_symlink(const struct dentry *dentry) -{ - return __d_entry_type(dentry) == DCACHE_SYMLINK_TYPE; -} - -static inline bool d_is_reg(const struct dentry *dentry) -{ - return __d_entry_type(dentry) == DCACHE_REGULAR_TYPE; -} - -static inline bool d_is_special(const struct dentry *dentry) -{ - return __d_entry_type(dentry) == DCACHE_SPECIAL_TYPE; -} - -static inline bool d_is_file(const struct dentry *dentry) -{ - return d_is_reg(dentry) || d_is_special(dentry); -} - -static inline bool d_is_negative(const struct dentry *dentry) -{ - // TODO: check d_is_whiteout(dentry) also. - return d_is_miss(dentry); -} - -static inline bool d_is_positive(const struct dentry *dentry) -{ - return !d_is_negative(dentry); -} - -/** - * d_really_is_negative - Determine if a dentry is really negative (ignoring fallthroughs) - * @dentry: The dentry in question - * - * Returns true if the dentry represents either an absent name or a name that - * doesn't map to an inode (ie. ->d_inode is NULL). The dentry could represent - * a true miss, a whiteout that isn't represented by a 0,0 chardev or a - * fallthrough marker in an opaque directory. - * - * Note! (1) This should be used *only* by a filesystem to examine its own - * dentries. It should not be used to look at some other filesystem's - * dentries. (2) It should also be used in combination with d_inode() to get - * the inode. (3) The dentry may have something attached to ->d_lower and the - * type field of the flags may be set to something other than miss or whiteout. - */ -static inline bool d_really_is_negative(const struct dentry *dentry) -{ - return dentry->d_inode == NULL; -} - -/** - * d_really_is_positive - Determine if a dentry is really positive (ignoring fallthroughs) - * @dentry: The dentry in question - * - * Returns true if the dentry represents a name that maps to an inode - * (ie. ->d_inode is not NULL). The dentry might still represent a whiteout if - * that is represented on medium as a 0,0 chardev. - * - * Note! (1) This should be used *only* by a filesystem to examine its own - * dentries. It should not be used to look at some other filesystem's - * dentries. (2) It should also be used in combination with d_inode() to get - * the inode. - */ -static inline bool d_really_is_positive(const struct dentry *dentry) -{ - return dentry->d_inode != NULL; -} - -static inline int simple_positive(struct dentry *dentry) -{ - return d_really_is_positive(dentry) && !d_unhashed(dentry); -} - -extern void d_set_fallthru(struct dentry *dentry); - -static inline bool d_is_fallthru(const struct dentry *dentry) -{ - return dentry->d_flags & DCACHE_FALLTHRU; -} - - -extern int sysctl_vfs_cache_pressure; - -static inline unsigned long vfs_pressure_ratio(unsigned long val) -{ - return mult_frac(val, sysctl_vfs_cache_pressure, 100); -} - -/** - * d_inode - Get the actual inode of this dentry - * @dentry: The dentry to query - * - * This is the helper normal filesystems should use to get at their own inodes - * in their own dentries and ignore the layering superimposed upon them. - */ -static inline struct inode *d_inode(const struct dentry *dentry) -{ - return dentry->d_inode; -} - -/** - * d_inode_rcu - Get the actual inode of this dentry with ACCESS_ONCE() - * @dentry: The dentry to query - * - * This is the helper normal filesystems should use to get at their own inodes - * in their own dentries and ignore the layering superimposed upon them. - */ -static inline struct inode *d_inode_rcu(const struct dentry *dentry) -{ - return ACCESS_ONCE(dentry->d_inode); -} - -/** - * d_backing_inode - Get upper or lower inode we should be using - * @upper: The upper layer - * - * This is the helper that should be used to get at the inode that will be used - * if this dentry were to be opened as a file. The inode may be on the upper - * dentry or it may be on a lower dentry pinned by the upper. - * - * Normal filesystems should not use this to access their own inodes. - */ -static inline struct inode *d_backing_inode(const struct dentry *upper) -{ - struct inode *inode = upper->d_inode; - - return inode; -} - -/** - * d_backing_dentry - Get upper or lower dentry we should be using - * @upper: The upper layer - * - * This is the helper that should be used to get the dentry of the inode that - * will be used if this dentry were opened as a file. It may be the upper - * dentry or it may be a lower dentry pinned by the upper. - * - * Normal filesystems should not use this to access their own dentries. - */ -static inline struct dentry *d_backing_dentry(struct dentry *upper) -{ - return upper; -} - -/** - * d_real - Return the real dentry - * @dentry: the dentry to query - * @inode: inode to select the dentry from multiple layers (can be NULL) - * @flags: open flags to control copy-up behavior - * - * If dentry is on an union/overlay, then return the underlying, real dentry. - * Otherwise return the dentry itself. - * - * See also: Documentation/filesystems/vfs.txt - */ -static inline struct dentry *d_real(struct dentry *dentry, - const struct inode *inode, - unsigned int flags) -{ - if (unlikely(dentry->d_flags & DCACHE_OP_REAL)) - return dentry->d_op->d_real(dentry, inode, flags); - else - return dentry; -} - -/** - * d_real_inode - Return the real inode - * @dentry: The dentry to query - * - * If dentry is on an union/overlay, then return the underlying, real inode. - * Otherwise return d_inode(). - */ -static inline struct inode *d_real_inode(const struct dentry *dentry) -{ - /* This usage of d_real() results in const dentry */ - return d_backing_inode(d_real((struct dentry *) dentry, NULL, 0)); -} - - -#endif /* __LINUX_DCACHE_H */ diff --git a/src/linux/include/linux/dccp.h b/src/linux/include/linux/dccp.h deleted file mode 100644 index 61d042b..0000000 --- a/src/linux/include/linux/dccp.h +++ /dev/null @@ -1,324 +0,0 @@ -#ifndef _LINUX_DCCP_H -#define _LINUX_DCCP_H - - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -enum dccp_state { - DCCP_OPEN = TCP_ESTABLISHED, - DCCP_REQUESTING = TCP_SYN_SENT, - DCCP_LISTEN = TCP_LISTEN, - DCCP_RESPOND = TCP_SYN_RECV, - /* - * States involved in closing a DCCP connection: - * 1) ACTIVE_CLOSEREQ is entered by a server sending a CloseReq. - * - * 2) CLOSING can have three different meanings (RFC 4340, 8.3): - * a. Client has performed active-close, has sent a Close to the server - * from state OPEN or PARTOPEN, and is waiting for the final Reset - * (in this case, SOCK_DONE == 1). - * b. Client is asked to perform passive-close, by receiving a CloseReq - * in (PART)OPEN state. It sends a Close and waits for final Reset - * (in this case, SOCK_DONE == 0). - * c. Server performs an active-close as in (a), keeps TIMEWAIT state. - * - * 3) The following intermediate states are employed to give passively - * closing nodes a chance to process their unread data: - * - PASSIVE_CLOSE (from OPEN => CLOSED) and - * - PASSIVE_CLOSEREQ (from (PART)OPEN to CLOSING; case (b) above). - */ - DCCP_ACTIVE_CLOSEREQ = TCP_FIN_WAIT1, - DCCP_PASSIVE_CLOSE = TCP_CLOSE_WAIT, /* any node receiving a Close */ - DCCP_CLOSING = TCP_CLOSING, - DCCP_TIME_WAIT = TCP_TIME_WAIT, - DCCP_CLOSED = TCP_CLOSE, - DCCP_NEW_SYN_RECV = TCP_NEW_SYN_RECV, - DCCP_PARTOPEN = TCP_MAX_STATES, - DCCP_PASSIVE_CLOSEREQ, /* clients receiving CloseReq */ - DCCP_MAX_STATES -}; - -enum { - DCCPF_OPEN = TCPF_ESTABLISHED, - DCCPF_REQUESTING = TCPF_SYN_SENT, - DCCPF_LISTEN = TCPF_LISTEN, - DCCPF_RESPOND = TCPF_SYN_RECV, - DCCPF_ACTIVE_CLOSEREQ = TCPF_FIN_WAIT1, - DCCPF_CLOSING = TCPF_CLOSING, - DCCPF_TIME_WAIT = TCPF_TIME_WAIT, - DCCPF_CLOSED = TCPF_CLOSE, - DCCPF_NEW_SYN_RECV = TCPF_NEW_SYN_RECV, - DCCPF_PARTOPEN = (1 << DCCP_PARTOPEN), -}; - -static inline struct dccp_hdr *dccp_hdr(const struct sk_buff *skb) -{ - return (struct dccp_hdr *)skb_transport_header(skb); -} - -static inline struct dccp_hdr *dccp_zeroed_hdr(struct sk_buff *skb, int headlen) -{ - skb_push(skb, headlen); - skb_reset_transport_header(skb); - return memset(skb_transport_header(skb), 0, headlen); -} - -static inline struct dccp_hdr_ext *dccp_hdrx(const struct dccp_hdr *dh) -{ - return (struct dccp_hdr_ext *)((unsigned char *)dh + sizeof(*dh)); -} - -static inline unsigned int __dccp_basic_hdr_len(const struct dccp_hdr *dh) -{ - return sizeof(*dh) + (dh->dccph_x ? sizeof(struct dccp_hdr_ext) : 0); -} - -static inline unsigned int dccp_basic_hdr_len(const struct sk_buff *skb) -{ - const struct dccp_hdr *dh = dccp_hdr(skb); - return __dccp_basic_hdr_len(dh); -} - -static inline __u64 dccp_hdr_seq(const struct dccp_hdr *dh) -{ - __u64 seq_nr = ntohs(dh->dccph_seq); - - if (dh->dccph_x != 0) - seq_nr = (seq_nr << 32) + ntohl(dccp_hdrx(dh)->dccph_seq_low); - else - seq_nr += (u32)dh->dccph_seq2 << 16; - - return seq_nr; -} - -static inline struct dccp_hdr_request *dccp_hdr_request(struct sk_buff *skb) -{ - return (struct dccp_hdr_request *)(skb_transport_header(skb) + - dccp_basic_hdr_len(skb)); -} - -static inline struct dccp_hdr_ack_bits *dccp_hdr_ack_bits(const struct sk_buff *skb) -{ - return (struct dccp_hdr_ack_bits *)(skb_transport_header(skb) + - dccp_basic_hdr_len(skb)); -} - -static inline u64 dccp_hdr_ack_seq(const struct sk_buff *skb) -{ - const struct dccp_hdr_ack_bits *dhack = dccp_hdr_ack_bits(skb); - return ((u64)ntohs(dhack->dccph_ack_nr_high) << 32) + ntohl(dhack->dccph_ack_nr_low); -} - -static inline struct dccp_hdr_response *dccp_hdr_response(struct sk_buff *skb) -{ - return (struct dccp_hdr_response *)(skb_transport_header(skb) + - dccp_basic_hdr_len(skb)); -} - -static inline struct dccp_hdr_reset *dccp_hdr_reset(struct sk_buff *skb) -{ - return (struct dccp_hdr_reset *)(skb_transport_header(skb) + - dccp_basic_hdr_len(skb)); -} - -static inline unsigned int __dccp_hdr_len(const struct dccp_hdr *dh) -{ - return __dccp_basic_hdr_len(dh) + - dccp_packet_hdr_len(dh->dccph_type); -} - -static inline unsigned int dccp_hdr_len(const struct sk_buff *skb) -{ - return __dccp_hdr_len(dccp_hdr(skb)); -} - -/** - * struct dccp_request_sock - represent DCCP-specific connection request - * @dreq_inet_rsk: structure inherited from - * @dreq_iss: initial sequence number, sent on the first Response (RFC 4340, 7.1) - * @dreq_gss: greatest sequence number sent (for retransmitted Responses) - * @dreq_isr: initial sequence number received in the first Request - * @dreq_gsr: greatest sequence number received (for retransmitted Request(s)) - * @dreq_service: service code present on the Request (there is just one) - * @dreq_featneg: feature negotiation options for this connection - * The following two fields are analogous to the ones in dccp_sock: - * @dreq_timestamp_echo: last received timestamp to echo (13.1) - * @dreq_timestamp_echo: the time of receiving the last @dreq_timestamp_echo - */ -struct dccp_request_sock { - struct inet_request_sock dreq_inet_rsk; - __u64 dreq_iss; - __u64 dreq_gss; - __u64 dreq_isr; - __u64 dreq_gsr; - __be32 dreq_service; - struct list_head dreq_featneg; - __u32 dreq_timestamp_echo; - __u32 dreq_timestamp_time; -}; - -static inline struct dccp_request_sock *dccp_rsk(const struct request_sock *req) -{ - return (struct dccp_request_sock *)req; -} - -extern struct inet_timewait_death_row dccp_death_row; - -extern int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, - struct sk_buff *skb); - -struct dccp_options_received { - u64 dccpor_ndp:48; - u32 dccpor_timestamp; - u32 dccpor_timestamp_echo; - u32 dccpor_elapsed_time; -}; - -struct ccid; - -enum dccp_role { - DCCP_ROLE_UNDEFINED, - DCCP_ROLE_LISTEN, - DCCP_ROLE_CLIENT, - DCCP_ROLE_SERVER, -}; - -struct dccp_service_list { - __u32 dccpsl_nr; - __be32 dccpsl_list[0]; -}; - -#define DCCP_SERVICE_INVALID_VALUE htonl((__u32)-1) -#define DCCP_SERVICE_CODE_IS_ABSENT 0 - -static inline bool dccp_list_has_service(const struct dccp_service_list *sl, - const __be32 service) -{ - if (likely(sl != NULL)) { - u32 i = sl->dccpsl_nr; - while (i--) - if (sl->dccpsl_list[i] == service) - return true; - } - return false; -} - -struct dccp_ackvec; - -/** - * struct dccp_sock - DCCP socket state - * - * @dccps_swl - sequence number window low - * @dccps_swh - sequence number window high - * @dccps_awl - acknowledgement number window low - * @dccps_awh - acknowledgement number window high - * @dccps_iss - initial sequence number sent - * @dccps_isr - initial sequence number received - * @dccps_osr - first OPEN sequence number received - * @dccps_gss - greatest sequence number sent - * @dccps_gsr - greatest valid sequence number received - * @dccps_gar - greatest valid ack number received on a non-Sync; initialized to %dccps_iss - * @dccps_service - first (passive sock) or unique (active sock) service code - * @dccps_service_list - second .. last service code on passive socket - * @dccps_timestamp_echo - latest timestamp received on a TIMESTAMP option - * @dccps_timestamp_time - time of receiving latest @dccps_timestamp_echo - * @dccps_l_ack_ratio - feature-local Ack Ratio - * @dccps_r_ack_ratio - feature-remote Ack Ratio - * @dccps_l_seq_win - local Sequence Window (influences ack number validity) - * @dccps_r_seq_win - remote Sequence Window (influences seq number validity) - * @dccps_pcslen - sender partial checksum coverage (via sockopt) - * @dccps_pcrlen - receiver partial checksum coverage (via sockopt) - * @dccps_send_ndp_count - local Send NDP Count feature (7.7.2) - * @dccps_ndp_count - number of Non Data Packets since last data packet - * @dccps_mss_cache - current value of MSS (path MTU minus header sizes) - * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4) - * @dccps_featneg - tracks feature-negotiation state (mostly during handshake) - * @dccps_hc_rx_ackvec - rx half connection ack vector - * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection) - * @dccps_hc_tx_ccid - CCID used for the sender (or sending half-connection) - * @dccps_options_received - parsed set of retrieved options - * @dccps_qpolicy - TX dequeueing policy, one of %dccp_packet_dequeueing_policy - * @dccps_tx_qlen - maximum length of the TX queue - * @dccps_role - role of this sock, one of %dccp_role - * @dccps_hc_rx_insert_options - receiver wants to add options when acking - * @dccps_hc_tx_insert_options - sender wants to add options when sending - * @dccps_server_timewait - server holds timewait state on close (RFC 4340, 8.3) - * @dccps_sync_scheduled - flag which signals "send out-of-band message soon" - * @dccps_xmitlet - tasklet scheduled by the TX CCID to dequeue data packets - * @dccps_xmit_timer - used by the TX CCID to delay sending (rate-based pacing) - * @dccps_syn_rtt - RTT sample from Request/Response exchange (in usecs) - */ -struct dccp_sock { - /* inet_connection_sock has to be the first member of dccp_sock */ - struct inet_connection_sock dccps_inet_connection; -#define dccps_syn_rtt dccps_inet_connection.icsk_ack.lrcvtime - __u64 dccps_swl; - __u64 dccps_swh; - __u64 dccps_awl; - __u64 dccps_awh; - __u64 dccps_iss; - __u64 dccps_isr; - __u64 dccps_osr; - __u64 dccps_gss; - __u64 dccps_gsr; - __u64 dccps_gar; - __be32 dccps_service; - __u32 dccps_mss_cache; - struct dccp_service_list *dccps_service_list; - __u32 dccps_timestamp_echo; - __u32 dccps_timestamp_time; - __u16 dccps_l_ack_ratio; - __u16 dccps_r_ack_ratio; - __u64 dccps_l_seq_win:48; - __u64 dccps_r_seq_win:48; - __u8 dccps_pcslen:4; - __u8 dccps_pcrlen:4; - __u8 dccps_send_ndp_count:1; - __u64 dccps_ndp_count:48; - unsigned long dccps_rate_last; - struct list_head dccps_featneg; - struct dccp_ackvec *dccps_hc_rx_ackvec; - struct ccid *dccps_hc_rx_ccid; - struct ccid *dccps_hc_tx_ccid; - struct dccp_options_received dccps_options_received; - __u8 dccps_qpolicy; - __u32 dccps_tx_qlen; - enum dccp_role dccps_role:2; - __u8 dccps_hc_rx_insert_options:1; - __u8 dccps_hc_tx_insert_options:1; - __u8 dccps_server_timewait:1; - __u8 dccps_sync_scheduled:1; - struct tasklet_struct dccps_xmitlet; - struct timer_list dccps_xmit_timer; -}; - -static inline struct dccp_sock *dccp_sk(const struct sock *sk) -{ - return (struct dccp_sock *)sk; -} - -static inline const char *dccp_role(const struct sock *sk) -{ - switch (dccp_sk(sk)->dccps_role) { - case DCCP_ROLE_UNDEFINED: return "undefined"; - case DCCP_ROLE_LISTEN: return "listen"; - case DCCP_ROLE_SERVER: return "server"; - case DCCP_ROLE_CLIENT: return "client"; - } - return NULL; -} - -extern void dccp_syn_ack_timeout(const struct request_sock *req); - -#endif /* _LINUX_DCCP_H */ diff --git a/src/linux/include/linux/dcookies.h b/src/linux/include/linux/dcookies.h deleted file mode 100644 index 5ac3bdd..0000000 --- a/src/linux/include/linux/dcookies.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * dcookies.h - * - * Persistent cookie-path mappings - * - * Copyright 2002 John Levon - */ - -#ifndef DCOOKIES_H -#define DCOOKIES_H - - -#ifdef CONFIG_PROFILING - -#include -#include - -struct dcookie_user; -struct path; - -/** - * dcookie_register - register a user of dcookies - * - * Register as a dcookie user. Returns %NULL on failure. - */ -struct dcookie_user * dcookie_register(void); - -/** - * dcookie_unregister - unregister a user of dcookies - * - * Unregister as a dcookie user. This may invalidate - * any dcookie values returned from get_dcookie(). - */ -void dcookie_unregister(struct dcookie_user * user); - -/** - * get_dcookie - acquire a dcookie - * - * Convert the given dentry/vfsmount pair into - * a cookie value. - * - * Returns -EINVAL if no living task has registered as a - * dcookie user. - * - * Returns 0 on success, with *cookie filled in - */ -int get_dcookie(struct path *path, unsigned long *cookie); - -#else - -static inline struct dcookie_user * dcookie_register(void) -{ - return NULL; -} - -static inline void dcookie_unregister(struct dcookie_user * user) -{ - return; -} - -static inline int get_dcookie(struct path *path, unsigned long *cookie) -{ - return -ENOSYS; -} - -#endif /* CONFIG_PROFILING */ - -#endif /* DCOOKIES_H */ diff --git a/src/linux/include/linux/debug_locks.h b/src/linux/include/linux/debug_locks.h deleted file mode 100644 index 822c135..0000000 --- a/src/linux/include/linux/debug_locks.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef __LINUX_DEBUG_LOCKING_H -#define __LINUX_DEBUG_LOCKING_H - -#include -#include -#include - -struct task_struct; - -extern int debug_locks; -extern int debug_locks_silent; - - -static inline int __debug_locks_off(void) -{ - return xchg(&debug_locks, 0); -} - -/* - * Generic 'turn off all lock debugging' function: - */ -extern int debug_locks_off(void); - -#define DEBUG_LOCKS_WARN_ON(c) \ -({ \ - int __ret = 0; \ - \ - if (!oops_in_progress && unlikely(c)) { \ - if (debug_locks_off() && !debug_locks_silent) \ - WARN(1, "DEBUG_LOCKS_WARN_ON(%s)", #c); \ - __ret = 1; \ - } \ - __ret; \ -}) - -#ifdef CONFIG_SMP -# define SMP_DEBUG_LOCKS_WARN_ON(c) DEBUG_LOCKS_WARN_ON(c) -#else -# define SMP_DEBUG_LOCKS_WARN_ON(c) do { } while (0) -#endif - -#ifdef CONFIG_DEBUG_LOCKING_API_SELFTESTS - extern void locking_selftest(void); -#else -# define locking_selftest() do { } while (0) -#endif - -struct task_struct; - -#ifdef CONFIG_LOCKDEP -extern void debug_show_all_locks(void); -extern void debug_show_held_locks(struct task_struct *task); -extern void debug_check_no_locks_freed(const void *from, unsigned long len); -extern void debug_check_no_locks_held(void); -#else -static inline void debug_show_all_locks(void) -{ -} - -static inline void debug_show_held_locks(struct task_struct *task) -{ -} - -static inline void -debug_check_no_locks_freed(const void *from, unsigned long len) -{ -} - -static inline void -debug_check_no_locks_held(void) -{ -} -#endif - -#endif diff --git a/src/linux/include/linux/debugfs.h b/src/linux/include/linux/debugfs.h deleted file mode 100644 index 4d3f0d1..0000000 --- a/src/linux/include/linux/debugfs.h +++ /dev/null @@ -1,377 +0,0 @@ -/* - * debugfs.h - a tiny little debug file system - * - * Copyright (C) 2004 Greg Kroah-Hartman - * Copyright (C) 2004 IBM Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * debugfs is for people to use instead of /proc or /sys. - * See Documentation/DocBook/filesystems for more details. - */ - -#ifndef _DEBUGFS_H_ -#define _DEBUGFS_H_ - -#include -#include - -#include -#include - -struct device; -struct file_operations; -struct srcu_struct; - -struct debugfs_blob_wrapper { - void *data; - unsigned long size; -}; - -struct debugfs_reg32 { - char *name; - unsigned long offset; -}; - -struct debugfs_regset32 { - const struct debugfs_reg32 *regs; - int nregs; - void __iomem *base; -}; - -extern struct dentry *arch_debugfs_dir; - -extern struct srcu_struct debugfs_srcu; - -/** - * debugfs_real_fops - getter for the real file operation - * @filp: a pointer to a struct file - * - * Must only be called under the protection established by - * debugfs_use_file_start(). - */ -static inline const struct file_operations *debugfs_real_fops(struct file *filp) - __must_hold(&debugfs_srcu) -{ - /* - * Neither the pointer to the struct file_operations, nor its - * contents ever change -- srcu_dereference() is not needed here. - */ - return filp->f_path.dentry->d_fsdata; -} - -#if defined(CONFIG_DEBUG_FS) - -struct dentry *debugfs_create_file(const char *name, umode_t mode, - struct dentry *parent, void *data, - const struct file_operations *fops); -struct dentry *debugfs_create_file_unsafe(const char *name, umode_t mode, - struct dentry *parent, void *data, - const struct file_operations *fops); - -struct dentry *debugfs_create_file_size(const char *name, umode_t mode, - struct dentry *parent, void *data, - const struct file_operations *fops, - loff_t file_size); - -struct dentry *debugfs_create_dir(const char *name, struct dentry *parent); - -struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent, - const char *dest); - -struct dentry *debugfs_create_automount(const char *name, - struct dentry *parent, - struct vfsmount *(*f)(void *), - void *data); - -void debugfs_remove(struct dentry *dentry); -void debugfs_remove_recursive(struct dentry *dentry); - -int debugfs_use_file_start(const struct dentry *dentry, int *srcu_idx) - __acquires(&debugfs_srcu); - -void debugfs_use_file_finish(int srcu_idx) __releases(&debugfs_srcu); - -ssize_t debugfs_attr_read(struct file *file, char __user *buf, - size_t len, loff_t *ppos); -ssize_t debugfs_attr_write(struct file *file, const char __user *buf, - size_t len, loff_t *ppos); - -#define DEFINE_DEBUGFS_ATTRIBUTE(__fops, __get, __set, __fmt) \ -static int __fops ## _open(struct inode *inode, struct file *file) \ -{ \ - __simple_attr_check_format(__fmt, 0ull); \ - return simple_attr_open(inode, file, __get, __set, __fmt); \ -} \ -static const struct file_operations __fops = { \ - .owner = THIS_MODULE, \ - .open = __fops ## _open, \ - .release = simple_attr_release, \ - .read = debugfs_attr_read, \ - .write = debugfs_attr_write, \ - .llseek = generic_file_llseek, \ -} - -struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, - struct dentry *new_dir, const char *new_name); - -struct dentry *debugfs_create_u8(const char *name, umode_t mode, - struct dentry *parent, u8 *value); -struct dentry *debugfs_create_u16(const char *name, umode_t mode, - struct dentry *parent, u16 *value); -struct dentry *debugfs_create_u32(const char *name, umode_t mode, - struct dentry *parent, u32 *value); -struct dentry *debugfs_create_u64(const char *name, umode_t mode, - struct dentry *parent, u64 *value); -struct dentry *debugfs_create_ulong(const char *name, umode_t mode, - struct dentry *parent, unsigned long *value); -struct dentry *debugfs_create_x8(const char *name, umode_t mode, - struct dentry *parent, u8 *value); -struct dentry *debugfs_create_x16(const char *name, umode_t mode, - struct dentry *parent, u16 *value); -struct dentry *debugfs_create_x32(const char *name, umode_t mode, - struct dentry *parent, u32 *value); -struct dentry *debugfs_create_x64(const char *name, umode_t mode, - struct dentry *parent, u64 *value); -struct dentry *debugfs_create_size_t(const char *name, umode_t mode, - struct dentry *parent, size_t *value); -struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode, - struct dentry *parent, atomic_t *value); -struct dentry *debugfs_create_bool(const char *name, umode_t mode, - struct dentry *parent, bool *value); - -struct dentry *debugfs_create_blob(const char *name, umode_t mode, - struct dentry *parent, - struct debugfs_blob_wrapper *blob); - -struct dentry *debugfs_create_regset32(const char *name, umode_t mode, - struct dentry *parent, - struct debugfs_regset32 *regset); - -void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs, - int nregs, void __iomem *base, char *prefix); - -struct dentry *debugfs_create_u32_array(const char *name, umode_t mode, - struct dentry *parent, - u32 *array, u32 elements); - -struct dentry *debugfs_create_devm_seqfile(struct device *dev, const char *name, - struct dentry *parent, - int (*read_fn)(struct seq_file *s, - void *data)); - -bool debugfs_initialized(void); - -ssize_t debugfs_read_file_bool(struct file *file, char __user *user_buf, - size_t count, loff_t *ppos); - -ssize_t debugfs_write_file_bool(struct file *file, const char __user *user_buf, - size_t count, loff_t *ppos); - -#else - -#include - -/* - * We do not return NULL from these functions if CONFIG_DEBUG_FS is not enabled - * so users have a chance to detect if there was a real error or not. We don't - * want to duplicate the design decision mistakes of procfs and devfs again. - */ - -static inline struct dentry *debugfs_create_file(const char *name, umode_t mode, - struct dentry *parent, void *data, - const struct file_operations *fops) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *debugfs_create_file_size(const char *name, umode_t mode, - struct dentry *parent, void *data, - const struct file_operations *fops, - loff_t file_size) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *debugfs_create_dir(const char *name, - struct dentry *parent) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *debugfs_create_symlink(const char *name, - struct dentry *parent, - const char *dest) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *debugfs_create_automount(const char *name, - struct dentry *parent, - struct vfsmount *(*f)(void *), - void *data) -{ - return ERR_PTR(-ENODEV); -} - -static inline void debugfs_remove(struct dentry *dentry) -{ } - -static inline void debugfs_remove_recursive(struct dentry *dentry) -{ } - -static inline int debugfs_use_file_start(const struct dentry *dentry, - int *srcu_idx) - __acquires(&debugfs_srcu) -{ - return 0; -} - -static inline void debugfs_use_file_finish(int srcu_idx) - __releases(&debugfs_srcu) -{ } - -#define DEFINE_DEBUGFS_ATTRIBUTE(__fops, __get, __set, __fmt) \ - static const struct file_operations __fops = { 0 } - -static inline struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry, - struct dentry *new_dir, char *new_name) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *debugfs_create_u8(const char *name, umode_t mode, - struct dentry *parent, - u8 *value) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *debugfs_create_u16(const char *name, umode_t mode, - struct dentry *parent, - u16 *value) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *debugfs_create_u32(const char *name, umode_t mode, - struct dentry *parent, - u32 *value) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *debugfs_create_u64(const char *name, umode_t mode, - struct dentry *parent, - u64 *value) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *debugfs_create_x8(const char *name, umode_t mode, - struct dentry *parent, - u8 *value) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *debugfs_create_x16(const char *name, umode_t mode, - struct dentry *parent, - u16 *value) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *debugfs_create_x32(const char *name, umode_t mode, - struct dentry *parent, - u32 *value) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *debugfs_create_x64(const char *name, umode_t mode, - struct dentry *parent, - u64 *value) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *debugfs_create_size_t(const char *name, umode_t mode, - struct dentry *parent, - size_t *value) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode, - struct dentry *parent, atomic_t *value) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *debugfs_create_bool(const char *name, umode_t mode, - struct dentry *parent, - bool *value) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *debugfs_create_blob(const char *name, umode_t mode, - struct dentry *parent, - struct debugfs_blob_wrapper *blob) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *debugfs_create_regset32(const char *name, - umode_t mode, struct dentry *parent, - struct debugfs_regset32 *regset) -{ - return ERR_PTR(-ENODEV); -} - -static inline void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs, - int nregs, void __iomem *base, char *prefix) -{ -} - -static inline bool debugfs_initialized(void) -{ - return false; -} - -static inline struct dentry *debugfs_create_u32_array(const char *name, umode_t mode, - struct dentry *parent, - u32 *array, u32 elements) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *debugfs_create_devm_seqfile(struct device *dev, - const char *name, - struct dentry *parent, - int (*read_fn)(struct seq_file *s, - void *data)) -{ - return ERR_PTR(-ENODEV); -} - -static inline ssize_t debugfs_read_file_bool(struct file *file, - char __user *user_buf, - size_t count, loff_t *ppos) -{ - return -ENODEV; -} - -static inline ssize_t debugfs_write_file_bool(struct file *file, - const char __user *user_buf, - size_t count, loff_t *ppos) -{ - return -ENODEV; -} - -#endif - -#endif diff --git a/src/linux/include/linux/debugobjects.h b/src/linux/include/linux/debugobjects.h deleted file mode 100644 index d82bf19..0000000 --- a/src/linux/include/linux/debugobjects.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef _LINUX_DEBUGOBJECTS_H -#define _LINUX_DEBUGOBJECTS_H - -#include -#include - -enum debug_obj_state { - ODEBUG_STATE_NONE, - ODEBUG_STATE_INIT, - ODEBUG_STATE_INACTIVE, - ODEBUG_STATE_ACTIVE, - ODEBUG_STATE_DESTROYED, - ODEBUG_STATE_NOTAVAILABLE, - ODEBUG_STATE_MAX, -}; - -struct debug_obj_descr; - -/** - * struct debug_obj - representaion of an tracked object - * @node: hlist node to link the object into the tracker list - * @state: tracked object state - * @astate: current active state - * @object: pointer to the real object - * @descr: pointer to an object type specific debug description structure - */ -struct debug_obj { - struct hlist_node node; - enum debug_obj_state state; - unsigned int astate; - void *object; - struct debug_obj_descr *descr; -}; - -/** - * struct debug_obj_descr - object type specific debug description structure - * - * @name: name of the object typee - * @debug_hint: function returning address, which have associated - * kernel symbol, to allow identify the object - * @is_static_object: return true if the obj is static, otherwise return false - * @fixup_init: fixup function, which is called when the init check - * fails. All fixup functions must return true if fixup - * was successful, otherwise return false - * @fixup_activate: fixup function, which is called when the activate check - * fails - * @fixup_destroy: fixup function, which is called when the destroy check - * fails - * @fixup_free: fixup function, which is called when the free check - * fails - * @fixup_assert_init: fixup function, which is called when the assert_init - * check fails - */ -struct debug_obj_descr { - const char *name; - void *(*debug_hint)(void *addr); - bool (*is_static_object)(void *addr); - bool (*fixup_init)(void *addr, enum debug_obj_state state); - bool (*fixup_activate)(void *addr, enum debug_obj_state state); - bool (*fixup_destroy)(void *addr, enum debug_obj_state state); - bool (*fixup_free)(void *addr, enum debug_obj_state state); - bool (*fixup_assert_init)(void *addr, enum debug_obj_state state); -}; - -#ifdef CONFIG_DEBUG_OBJECTS -extern void debug_object_init (void *addr, struct debug_obj_descr *descr); -extern void -debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr); -extern int debug_object_activate (void *addr, struct debug_obj_descr *descr); -extern void debug_object_deactivate(void *addr, struct debug_obj_descr *descr); -extern void debug_object_destroy (void *addr, struct debug_obj_descr *descr); -extern void debug_object_free (void *addr, struct debug_obj_descr *descr); -extern void debug_object_assert_init(void *addr, struct debug_obj_descr *descr); - -/* - * Active state: - * - Set at 0 upon initialization. - * - Must return to 0 before deactivation. - */ -extern void -debug_object_active_state(void *addr, struct debug_obj_descr *descr, - unsigned int expect, unsigned int next); - -extern void debug_objects_early_init(void); -extern void debug_objects_mem_init(void); -#else -static inline void -debug_object_init (void *addr, struct debug_obj_descr *descr) { } -static inline void -debug_object_init_on_stack(void *addr, struct debug_obj_descr *descr) { } -static inline int -debug_object_activate (void *addr, struct debug_obj_descr *descr) { return 0; } -static inline void -debug_object_deactivate(void *addr, struct debug_obj_descr *descr) { } -static inline void -debug_object_destroy (void *addr, struct debug_obj_descr *descr) { } -static inline void -debug_object_free (void *addr, struct debug_obj_descr *descr) { } -static inline void -debug_object_assert_init(void *addr, struct debug_obj_descr *descr) { } - -static inline void debug_objects_early_init(void) { } -static inline void debug_objects_mem_init(void) { } -#endif - -#ifdef CONFIG_DEBUG_OBJECTS_FREE -extern void debug_check_no_obj_freed(const void *address, unsigned long size); -#else -static inline void -debug_check_no_obj_freed(const void *address, unsigned long size) { } -#endif - -#endif diff --git a/src/linux/include/linux/decompress/bunzip2.h b/src/linux/include/linux/decompress/bunzip2.h deleted file mode 100644 index 4d683df..0000000 --- a/src/linux/include/linux/decompress/bunzip2.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef DECOMPRESS_BUNZIP2_H -#define DECOMPRESS_BUNZIP2_H - -int bunzip2(unsigned char *inbuf, long len, - long (*fill)(void*, unsigned long), - long (*flush)(void*, unsigned long), - unsigned char *output, - long *pos, - void(*error)(char *x)); -#endif diff --git a/src/linux/include/linux/decompress/generic.h b/src/linux/include/linux/decompress/generic.h deleted file mode 100644 index 1fcfd64..0000000 --- a/src/linux/include/linux/decompress/generic.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef DECOMPRESS_GENERIC_H -#define DECOMPRESS_GENERIC_H - -typedef int (*decompress_fn) (unsigned char *inbuf, long len, - long (*fill)(void*, unsigned long), - long (*flush)(void*, unsigned long), - unsigned char *outbuf, - long *posp, - void(*error)(char *x)); - -/* inbuf - input buffer - *len - len of pre-read data in inbuf - *fill - function to fill inbuf when empty - *flush - function to write out outbuf - *outbuf - output buffer - *posp - if non-null, input position (number of bytes read) will be - * returned here - * - *If len != 0, inbuf should contain all the necessary input data, and fill - *should be NULL - *If len = 0, inbuf can be NULL, in which case the decompressor will allocate - *the input buffer. If inbuf != NULL it must be at least XXX_IOBUF_SIZE bytes. - *fill will be called (repeatedly...) to read data, at most XXX_IOBUF_SIZE - *bytes should be read per call. Replace XXX with the appropriate decompressor - *name, i.e. LZMA_IOBUF_SIZE. - * - *If flush = NULL, outbuf must be large enough to buffer all the expected - *output. If flush != NULL, the output buffer will be allocated by the - *decompressor (outbuf = NULL), and the flush function will be called to - *flush the output buffer at the appropriate time (decompressor and stream - *dependent). - */ - - -/* Utility routine to detect the decompression method */ -decompress_fn decompress_method(const unsigned char *inbuf, long len, - const char **name); - -#endif diff --git a/src/linux/include/linux/decompress/inflate.h b/src/linux/include/linux/decompress/inflate.h deleted file mode 100644 index e4f411f..0000000 --- a/src/linux/include/linux/decompress/inflate.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef LINUX_DECOMPRESS_INFLATE_H -#define LINUX_DECOMPRESS_INFLATE_H - -int gunzip(unsigned char *inbuf, long len, - long (*fill)(void*, unsigned long), - long (*flush)(void*, unsigned long), - unsigned char *output, - long *pos, - void(*error_fn)(char *x)); -#endif diff --git a/src/linux/include/linux/decompress/unlz4.h b/src/linux/include/linux/decompress/unlz4.h deleted file mode 100644 index 3273c2f..0000000 --- a/src/linux/include/linux/decompress/unlz4.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef DECOMPRESS_UNLZ4_H -#define DECOMPRESS_UNLZ4_H - -int unlz4(unsigned char *inbuf, long len, - long (*fill)(void*, unsigned long), - long (*flush)(void*, unsigned long), - unsigned char *output, - long *pos, - void(*error)(char *x)); -#endif diff --git a/src/linux/include/linux/decompress/unlzma.h b/src/linux/include/linux/decompress/unlzma.h deleted file mode 100644 index 8a891a1..0000000 --- a/src/linux/include/linux/decompress/unlzma.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef DECOMPRESS_UNLZMA_H -#define DECOMPRESS_UNLZMA_H - -int unlzma(unsigned char *, long, - long (*fill)(void*, unsigned long), - long (*flush)(void*, unsigned long), - unsigned char *output, - long *posp, - void(*error)(char *x) - ); - -#endif diff --git a/src/linux/include/linux/decompress/unlzo.h b/src/linux/include/linux/decompress/unlzo.h deleted file mode 100644 index af18f95..0000000 --- a/src/linux/include/linux/decompress/unlzo.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef DECOMPRESS_UNLZO_H -#define DECOMPRESS_UNLZO_H - -int unlzo(unsigned char *inbuf, long len, - long (*fill)(void*, unsigned long), - long (*flush)(void*, unsigned long), - unsigned char *output, - long *pos, - void(*error)(char *x)); -#endif diff --git a/src/linux/include/linux/decompress/unxz.h b/src/linux/include/linux/decompress/unxz.h deleted file mode 100644 index f764e2a..0000000 --- a/src/linux/include/linux/decompress/unxz.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Wrapper for decompressing XZ-compressed kernel, initramfs, and initrd - * - * Author: Lasse Collin - * - * This file has been put into the public domain. - * You can do whatever you want with this file. - */ - -#ifndef DECOMPRESS_UNXZ_H -#define DECOMPRESS_UNXZ_H - -int unxz(unsigned char *in, long in_size, - long (*fill)(void *dest, unsigned long size), - long (*flush)(void *src, unsigned long size), - unsigned char *out, long *in_used, - void (*error)(char *x)); - -#endif diff --git a/src/linux/include/linux/delay.h b/src/linux/include/linux/delay.h deleted file mode 100644 index a6ecb34..0000000 --- a/src/linux/include/linux/delay.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef _LINUX_DELAY_H -#define _LINUX_DELAY_H - -/* - * Copyright (C) 1993 Linus Torvalds - * - * Delay routines, using a pre-computed "loops_per_jiffy" value. - */ - -#include - -extern unsigned long loops_per_jiffy; - -#include - -/* - * Using udelay() for intervals greater than a few milliseconds can - * risk overflow for high loops_per_jiffy (high bogomips) machines. The - * mdelay() provides a wrapper to prevent this. For delays greater - * than MAX_UDELAY_MS milliseconds, the wrapper is used. Architecture - * specific values can be defined in asm-???/delay.h as an override. - * The 2nd mdelay() definition ensures GCC will optimize away the - * while loop for the common cases where n <= MAX_UDELAY_MS -- Paul G. - */ - -#ifndef MAX_UDELAY_MS -#define MAX_UDELAY_MS 5 -#endif - -#ifndef mdelay -#define mdelay(n) (\ - (__builtin_constant_p(n) && (n)<=MAX_UDELAY_MS) ? udelay((n)*1000) : \ - ({unsigned long __ms=(n); while (__ms--) udelay(1000);})) -#endif - -#ifndef ndelay -static inline void ndelay(unsigned long x) -{ - udelay(DIV_ROUND_UP(x, 1000)); -} -#define ndelay(x) ndelay(x) -#endif - -extern unsigned long lpj_fine; -void calibrate_delay(void); -void msleep(unsigned int msecs); -unsigned long msleep_interruptible(unsigned int msecs); -void usleep_range(unsigned long min, unsigned long max); - -static inline void ssleep(unsigned int seconds) -{ - msleep(seconds * 1000); -} - -#endif /* defined(_LINUX_DELAY_H) */ diff --git a/src/linux/include/linux/delayacct.h b/src/linux/include/linux/delayacct.h deleted file mode 100644 index 6cee17c..0000000 --- a/src/linux/include/linux/delayacct.h +++ /dev/null @@ -1,153 +0,0 @@ -/* delayacct.h - per-task delay accounting - * - * Copyright (C) Shailabh Nagar, IBM Corp. 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - */ - -#ifndef _LINUX_DELAYACCT_H -#define _LINUX_DELAYACCT_H - -#include -#include - -/* - * Per-task flags relevant to delay accounting - * maintained privately to avoid exhausting similar flags in sched.h:PF_* - * Used to set current->delays->flags - */ -#define DELAYACCT_PF_SWAPIN 0x00000001 /* I am doing a swapin */ -#define DELAYACCT_PF_BLKIO 0x00000002 /* I am waiting on IO */ - -#ifdef CONFIG_TASK_DELAY_ACCT - -extern int delayacct_on; /* Delay accounting turned on/off */ -extern struct kmem_cache *delayacct_cache; -extern void delayacct_init(void); -extern void __delayacct_tsk_init(struct task_struct *); -extern void __delayacct_tsk_exit(struct task_struct *); -extern void __delayacct_blkio_start(void); -extern void __delayacct_blkio_end(void); -extern int __delayacct_add_tsk(struct taskstats *, struct task_struct *); -extern __u64 __delayacct_blkio_ticks(struct task_struct *); -extern void __delayacct_freepages_start(void); -extern void __delayacct_freepages_end(void); - -static inline int delayacct_is_task_waiting_on_io(struct task_struct *p) -{ - if (p->delays) - return (p->delays->flags & DELAYACCT_PF_BLKIO); - else - return 0; -} - -static inline void delayacct_set_flag(int flag) -{ - if (current->delays) - current->delays->flags |= flag; -} - -static inline void delayacct_clear_flag(int flag) -{ - if (current->delays) - current->delays->flags &= ~flag; -} - -static inline void delayacct_tsk_init(struct task_struct *tsk) -{ - /* reinitialize in case parent's non-null pointer was dup'ed*/ - tsk->delays = NULL; - if (delayacct_on) - __delayacct_tsk_init(tsk); -} - -/* Free tsk->delays. Called from bad fork and __put_task_struct - * where there's no risk of tsk->delays being accessed elsewhere - */ -static inline void delayacct_tsk_free(struct task_struct *tsk) -{ - if (tsk->delays) - kmem_cache_free(delayacct_cache, tsk->delays); - tsk->delays = NULL; -} - -static inline void delayacct_blkio_start(void) -{ - delayacct_set_flag(DELAYACCT_PF_BLKIO); - if (current->delays) - __delayacct_blkio_start(); -} - -static inline void delayacct_blkio_end(void) -{ - if (current->delays) - __delayacct_blkio_end(); - delayacct_clear_flag(DELAYACCT_PF_BLKIO); -} - -static inline int delayacct_add_tsk(struct taskstats *d, - struct task_struct *tsk) -{ - if (!delayacct_on || !tsk->delays) - return 0; - return __delayacct_add_tsk(d, tsk); -} - -static inline __u64 delayacct_blkio_ticks(struct task_struct *tsk) -{ - if (tsk->delays) - return __delayacct_blkio_ticks(tsk); - return 0; -} - -static inline void delayacct_freepages_start(void) -{ - if (current->delays) - __delayacct_freepages_start(); -} - -static inline void delayacct_freepages_end(void) -{ - if (current->delays) - __delayacct_freepages_end(); -} - -#else -static inline void delayacct_set_flag(int flag) -{} -static inline void delayacct_clear_flag(int flag) -{} -static inline void delayacct_init(void) -{} -static inline void delayacct_tsk_init(struct task_struct *tsk) -{} -static inline void delayacct_tsk_free(struct task_struct *tsk) -{} -static inline void delayacct_blkio_start(void) -{} -static inline void delayacct_blkio_end(void) -{} -static inline int delayacct_add_tsk(struct taskstats *d, - struct task_struct *tsk) -{ return 0; } -static inline __u64 delayacct_blkio_ticks(struct task_struct *tsk) -{ return 0; } -static inline int delayacct_is_task_waiting_on_io(struct task_struct *p) -{ return 0; } -static inline void delayacct_freepages_start(void) -{} -static inline void delayacct_freepages_end(void) -{} - -#endif /* CONFIG_TASK_DELAY_ACCT */ - -#endif diff --git a/src/linux/include/linux/delayed_call.h b/src/linux/include/linux/delayed_call.h deleted file mode 100644 index f7fa76a..0000000 --- a/src/linux/include/linux/delayed_call.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _DELAYED_CALL_H -#define _DELAYED_CALL_H - -/* - * Poor man's closures; I wish we could've done them sanely polymorphic, - * but... - */ - -struct delayed_call { - void (*fn)(void *); - void *arg; -}; - -#define DEFINE_DELAYED_CALL(name) struct delayed_call name = {NULL, NULL} - -/* I really wish we had closures with sane typechecking... */ -static inline void set_delayed_call(struct delayed_call *call, - void (*fn)(void *), void *arg) -{ - call->fn = fn; - call->arg = arg; -} - -static inline void do_delayed_call(struct delayed_call *call) -{ - if (call->fn) - call->fn(call->arg); -} - -static inline void clear_delayed_call(struct delayed_call *call) -{ - call->fn = NULL; -} -#endif diff --git a/src/linux/include/linux/device.h b/src/linux/include/linux/device.h deleted file mode 100644 index bc41e87..0000000 --- a/src/linux/include/linux/device.h +++ /dev/null @@ -1,1382 +0,0 @@ -/* - * device.h - generic, centralized driver model - * - * Copyright (c) 2001-2003 Patrick Mochel - * Copyright (c) 2004-2009 Greg Kroah-Hartman - * Copyright (c) 2008-2009 Novell Inc. - * - * This file is released under the GPLv2 - * - * See Documentation/driver-model/ for more information. - */ - -#ifndef _DEVICE_H_ -#define _DEVICE_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct device; -struct device_private; -struct device_driver; -struct driver_private; -struct module; -struct class; -struct subsys_private; -struct bus_type; -struct device_node; -struct fwnode_handle; -struct iommu_ops; -struct iommu_group; -struct iommu_fwspec; - -struct bus_attribute { - struct attribute attr; - ssize_t (*show)(struct bus_type *bus, char *buf); - ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count); -}; - -#define BUS_ATTR(_name, _mode, _show, _store) \ - struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store) -#define BUS_ATTR_RW(_name) \ - struct bus_attribute bus_attr_##_name = __ATTR_RW(_name) -#define BUS_ATTR_RO(_name) \ - struct bus_attribute bus_attr_##_name = __ATTR_RO(_name) - -extern int __must_check bus_create_file(struct bus_type *, - struct bus_attribute *); -extern void bus_remove_file(struct bus_type *, struct bus_attribute *); - -/** - * struct bus_type - The bus type of the device - * - * @name: The name of the bus. - * @dev_name: Used for subsystems to enumerate devices like ("foo%u", dev->id). - * @dev_root: Default device to use as the parent. - * @dev_attrs: Default attributes of the devices on the bus. - * @bus_groups: Default attributes of the bus. - * @dev_groups: Default attributes of the devices on the bus. - * @drv_groups: Default attributes of the device drivers on the bus. - * @match: Called, perhaps multiple times, whenever a new device or driver - * is added for this bus. It should return a positive value if the - * given device can be handled by the given driver and zero - * otherwise. It may also return error code if determining that - * the driver supports the device is not possible. In case of - * -EPROBE_DEFER it will queue the device for deferred probing. - * @uevent: Called when a device is added, removed, or a few other things - * that generate uevents to add the environment variables. - * @probe: Called when a new device or driver add to this bus, and callback - * the specific driver's probe to initial the matched device. - * @remove: Called when a device removed from this bus. - * @shutdown: Called at shut-down time to quiesce the device. - * - * @online: Called to put the device back online (after offlining it). - * @offline: Called to put the device offline for hot-removal. May fail. - * - * @suspend: Called when a device on this bus wants to go to sleep mode. - * @resume: Called to bring a device on this bus out of sleep mode. - * @pm: Power management operations of this bus, callback the specific - * device driver's pm-ops. - * @iommu_ops: IOMMU specific operations for this bus, used to attach IOMMU - * driver implementations to a bus and allow the driver to do - * bus-specific setup - * @p: The private data of the driver core, only the driver core can - * touch this. - * @lock_key: Lock class key for use by the lock validator - * - * A bus is a channel between the processor and one or more devices. For the - * purposes of the device model, all devices are connected via a bus, even if - * it is an internal, virtual, "platform" bus. Buses can plug into each other. - * A USB controller is usually a PCI device, for example. The device model - * represents the actual connections between buses and the devices they control. - * A bus is represented by the bus_type structure. It contains the name, the - * default attributes, the bus' methods, PM operations, and the driver core's - * private data. - */ -struct bus_type { - const char *name; - const char *dev_name; - struct device *dev_root; - struct device_attribute *dev_attrs; /* use dev_groups instead */ - const struct attribute_group **bus_groups; - const struct attribute_group **dev_groups; - const struct attribute_group **drv_groups; - - int (*match)(struct device *dev, struct device_driver *drv); - int (*uevent)(struct device *dev, struct kobj_uevent_env *env); - int (*probe)(struct device *dev); - int (*remove)(struct device *dev); - void (*shutdown)(struct device *dev); - - int (*online)(struct device *dev); - int (*offline)(struct device *dev); - - int (*suspend)(struct device *dev, pm_message_t state); - int (*resume)(struct device *dev); - - const struct dev_pm_ops *pm; - - const struct iommu_ops *iommu_ops; - - struct subsys_private *p; - struct lock_class_key lock_key; -}; - -extern int __must_check bus_register(struct bus_type *bus); - -extern void bus_unregister(struct bus_type *bus); - -extern int __must_check bus_rescan_devices(struct bus_type *bus); - -/* iterator helpers for buses */ -struct subsys_dev_iter { - struct klist_iter ki; - const struct device_type *type; -}; -void subsys_dev_iter_init(struct subsys_dev_iter *iter, - struct bus_type *subsys, - struct device *start, - const struct device_type *type); -struct device *subsys_dev_iter_next(struct subsys_dev_iter *iter); -void subsys_dev_iter_exit(struct subsys_dev_iter *iter); - -int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, - int (*fn)(struct device *dev, void *data)); -struct device *bus_find_device(struct bus_type *bus, struct device *start, - void *data, - int (*match)(struct device *dev, void *data)); -struct device *bus_find_device_by_name(struct bus_type *bus, - struct device *start, - const char *name); -struct device *subsys_find_device_by_id(struct bus_type *bus, unsigned int id, - struct device *hint); -int bus_for_each_drv(struct bus_type *bus, struct device_driver *start, - void *data, int (*fn)(struct device_driver *, void *)); -void bus_sort_breadthfirst(struct bus_type *bus, - int (*compare)(const struct device *a, - const struct device *b)); -/* - * Bus notifiers: Get notified of addition/removal of devices - * and binding/unbinding of drivers to devices. - * In the long run, it should be a replacement for the platform - * notify hooks. - */ -struct notifier_block; - -extern int bus_register_notifier(struct bus_type *bus, - struct notifier_block *nb); -extern int bus_unregister_notifier(struct bus_type *bus, - struct notifier_block *nb); - -/* All 4 notifers below get called with the target struct device * - * as an argument. Note that those functions are likely to be called - * with the device lock held in the core, so be careful. - */ -#define BUS_NOTIFY_ADD_DEVICE 0x00000001 /* device added */ -#define BUS_NOTIFY_DEL_DEVICE 0x00000002 /* device to be removed */ -#define BUS_NOTIFY_REMOVED_DEVICE 0x00000003 /* device removed */ -#define BUS_NOTIFY_BIND_DRIVER 0x00000004 /* driver about to be - bound */ -#define BUS_NOTIFY_BOUND_DRIVER 0x00000005 /* driver bound to device */ -#define BUS_NOTIFY_UNBIND_DRIVER 0x00000006 /* driver about to be - unbound */ -#define BUS_NOTIFY_UNBOUND_DRIVER 0x00000007 /* driver is unbound - from the device */ -#define BUS_NOTIFY_DRIVER_NOT_BOUND 0x00000008 /* driver fails to be bound */ - -extern struct kset *bus_get_kset(struct bus_type *bus); -extern struct klist *bus_get_device_klist(struct bus_type *bus); - -/** - * enum probe_type - device driver probe type to try - * Device drivers may opt in for special handling of their - * respective probe routines. This tells the core what to - * expect and prefer. - * - * @PROBE_DEFAULT_STRATEGY: Used by drivers that work equally well - * whether probed synchronously or asynchronously. - * @PROBE_PREFER_ASYNCHRONOUS: Drivers for "slow" devices which - * probing order is not essential for booting the system may - * opt into executing their probes asynchronously. - * @PROBE_FORCE_SYNCHRONOUS: Use this to annotate drivers that need - * their probe routines to run synchronously with driver and - * device registration (with the exception of -EPROBE_DEFER - * handling - re-probing always ends up being done asynchronously). - * - * Note that the end goal is to switch the kernel to use asynchronous - * probing by default, so annotating drivers with - * %PROBE_PREFER_ASYNCHRONOUS is a temporary measure that allows us - * to speed up boot process while we are validating the rest of the - * drivers. - */ -enum probe_type { - PROBE_DEFAULT_STRATEGY, - PROBE_PREFER_ASYNCHRONOUS, - PROBE_FORCE_SYNCHRONOUS, -}; - -/** - * struct device_driver - The basic device driver structure - * @name: Name of the device driver. - * @bus: The bus which the device of this driver belongs to. - * @owner: The module owner. - * @mod_name: Used for built-in modules. - * @suppress_bind_attrs: Disables bind/unbind via sysfs. - * @probe_type: Type of the probe (synchronous or asynchronous) to use. - * @of_match_table: The open firmware table. - * @acpi_match_table: The ACPI match table. - * @probe: Called to query the existence of a specific device, - * whether this driver can work with it, and bind the driver - * to a specific device. - * @remove: Called when the device is removed from the system to - * unbind a device from this driver. - * @shutdown: Called at shut-down time to quiesce the device. - * @suspend: Called to put the device to sleep mode. Usually to a - * low power state. - * @resume: Called to bring a device from sleep mode. - * @groups: Default attributes that get created by the driver core - * automatically. - * @pm: Power management operations of the device which matched - * this driver. - * @p: Driver core's private data, no one other than the driver - * core can touch this. - * - * The device driver-model tracks all of the drivers known to the system. - * The main reason for this tracking is to enable the driver core to match - * up drivers with new devices. Once drivers are known objects within the - * system, however, a number of other things become possible. Device drivers - * can export information and configuration variables that are independent - * of any specific device. - */ -struct device_driver { - const char *name; - struct bus_type *bus; - - struct module *owner; - const char *mod_name; /* used for built-in modules */ - - bool suppress_bind_attrs; /* disables bind/unbind via sysfs */ - enum probe_type probe_type; - - const struct of_device_id *of_match_table; - const struct acpi_device_id *acpi_match_table; - - int (*probe) (struct device *dev); - int (*remove) (struct device *dev); - void (*shutdown) (struct device *dev); - int (*suspend) (struct device *dev, pm_message_t state); - int (*resume) (struct device *dev); - const struct attribute_group **groups; - - const struct dev_pm_ops *pm; - - struct driver_private *p; -}; - - -extern int __must_check driver_register(struct device_driver *drv); -extern void driver_unregister(struct device_driver *drv); - -extern struct device_driver *driver_find(const char *name, - struct bus_type *bus); -extern int driver_probe_done(void); -extern void wait_for_device_probe(void); - - -/* sysfs interface for exporting driver attributes */ - -struct driver_attribute { - struct attribute attr; - ssize_t (*show)(struct device_driver *driver, char *buf); - ssize_t (*store)(struct device_driver *driver, const char *buf, - size_t count); -}; - -#define DRIVER_ATTR(_name, _mode, _show, _store) \ - struct driver_attribute driver_attr_##_name = __ATTR(_name, _mode, _show, _store) -#define DRIVER_ATTR_RW(_name) \ - struct driver_attribute driver_attr_##_name = __ATTR_RW(_name) -#define DRIVER_ATTR_RO(_name) \ - struct driver_attribute driver_attr_##_name = __ATTR_RO(_name) -#define DRIVER_ATTR_WO(_name) \ - struct driver_attribute driver_attr_##_name = __ATTR_WO(_name) - -extern int __must_check driver_create_file(struct device_driver *driver, - const struct driver_attribute *attr); -extern void driver_remove_file(struct device_driver *driver, - const struct driver_attribute *attr); - -extern int __must_check driver_for_each_device(struct device_driver *drv, - struct device *start, - void *data, - int (*fn)(struct device *dev, - void *)); -struct device *driver_find_device(struct device_driver *drv, - struct device *start, void *data, - int (*match)(struct device *dev, void *data)); - -/** - * struct subsys_interface - interfaces to device functions - * @name: name of the device function - * @subsys: subsytem of the devices to attach to - * @node: the list of functions registered at the subsystem - * @add_dev: device hookup to device function handler - * @remove_dev: device hookup to device function handler - * - * Simple interfaces attached to a subsystem. Multiple interfaces can - * attach to a subsystem and its devices. Unlike drivers, they do not - * exclusively claim or control devices. Interfaces usually represent - * a specific functionality of a subsystem/class of devices. - */ -struct subsys_interface { - const char *name; - struct bus_type *subsys; - struct list_head node; - int (*add_dev)(struct device *dev, struct subsys_interface *sif); - void (*remove_dev)(struct device *dev, struct subsys_interface *sif); -}; - -int subsys_interface_register(struct subsys_interface *sif); -void subsys_interface_unregister(struct subsys_interface *sif); - -int subsys_system_register(struct bus_type *subsys, - const struct attribute_group **groups); -int subsys_virtual_register(struct bus_type *subsys, - const struct attribute_group **groups); - -/** - * struct class - device classes - * @name: Name of the class. - * @owner: The module owner. - * @class_attrs: Default attributes of this class. - * @dev_groups: Default attributes of the devices that belong to the class. - * @dev_kobj: The kobject that represents this class and links it into the hierarchy. - * @dev_uevent: Called when a device is added, removed from this class, or a - * few other things that generate uevents to add the environment - * variables. - * @devnode: Callback to provide the devtmpfs. - * @class_release: Called to release this class. - * @dev_release: Called to release the device. - * @suspend: Used to put the device to sleep mode, usually to a low power - * state. - * @resume: Used to bring the device from the sleep mode. - * @ns_type: Callbacks so sysfs can detemine namespaces. - * @namespace: Namespace of the device belongs to this class. - * @pm: The default device power management operations of this class. - * @p: The private data of the driver core, no one other than the - * driver core can touch this. - * - * A class is a higher-level view of a device that abstracts out low-level - * implementation details. Drivers may see a SCSI disk or an ATA disk, but, - * at the class level, they are all simply disks. Classes allow user space - * to work with devices based on what they do, rather than how they are - * connected or how they work. - */ -struct class { - const char *name; - struct module *owner; - - struct class_attribute *class_attrs; - const struct attribute_group **dev_groups; - struct kobject *dev_kobj; - - int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env); - char *(*devnode)(struct device *dev, umode_t *mode); - - void (*class_release)(struct class *class); - void (*dev_release)(struct device *dev); - - int (*suspend)(struct device *dev, pm_message_t state); - int (*resume)(struct device *dev); - - const struct kobj_ns_type_operations *ns_type; - const void *(*namespace)(struct device *dev); - - const struct dev_pm_ops *pm; - - struct subsys_private *p; -}; - -struct class_dev_iter { - struct klist_iter ki; - const struct device_type *type; -}; - -extern struct kobject *sysfs_dev_block_kobj; -extern struct kobject *sysfs_dev_char_kobj; -extern int __must_check __class_register(struct class *class, - struct lock_class_key *key); -extern void class_unregister(struct class *class); - -/* This is a #define to keep the compiler from merging different - * instances of the __key variable */ -#define class_register(class) \ -({ \ - static struct lock_class_key __key; \ - __class_register(class, &__key); \ -}) - -struct class_compat; -struct class_compat *class_compat_register(const char *name); -void class_compat_unregister(struct class_compat *cls); -int class_compat_create_link(struct class_compat *cls, struct device *dev, - struct device *device_link); -void class_compat_remove_link(struct class_compat *cls, struct device *dev, - struct device *device_link); - -extern void class_dev_iter_init(struct class_dev_iter *iter, - struct class *class, - struct device *start, - const struct device_type *type); -extern struct device *class_dev_iter_next(struct class_dev_iter *iter); -extern void class_dev_iter_exit(struct class_dev_iter *iter); - -extern int class_for_each_device(struct class *class, struct device *start, - void *data, - int (*fn)(struct device *dev, void *data)); -extern struct device *class_find_device(struct class *class, - struct device *start, const void *data, - int (*match)(struct device *, const void *)); - -struct class_attribute { - struct attribute attr; - ssize_t (*show)(struct class *class, struct class_attribute *attr, - char *buf); - ssize_t (*store)(struct class *class, struct class_attribute *attr, - const char *buf, size_t count); -}; - -#define CLASS_ATTR(_name, _mode, _show, _store) \ - struct class_attribute class_attr_##_name = __ATTR(_name, _mode, _show, _store) -#define CLASS_ATTR_RW(_name) \ - struct class_attribute class_attr_##_name = __ATTR_RW(_name) -#define CLASS_ATTR_RO(_name) \ - struct class_attribute class_attr_##_name = __ATTR_RO(_name) - -extern int __must_check class_create_file_ns(struct class *class, - const struct class_attribute *attr, - const void *ns); -extern void class_remove_file_ns(struct class *class, - const struct class_attribute *attr, - const void *ns); - -static inline int __must_check class_create_file(struct class *class, - const struct class_attribute *attr) -{ - return class_create_file_ns(class, attr, NULL); -} - -static inline void class_remove_file(struct class *class, - const struct class_attribute *attr) -{ - return class_remove_file_ns(class, attr, NULL); -} - -/* Simple class attribute that is just a static string */ -struct class_attribute_string { - struct class_attribute attr; - char *str; -}; - -/* Currently read-only only */ -#define _CLASS_ATTR_STRING(_name, _mode, _str) \ - { __ATTR(_name, _mode, show_class_attr_string, NULL), _str } -#define CLASS_ATTR_STRING(_name, _mode, _str) \ - struct class_attribute_string class_attr_##_name = \ - _CLASS_ATTR_STRING(_name, _mode, _str) - -extern ssize_t show_class_attr_string(struct class *class, struct class_attribute *attr, - char *buf); - -struct class_interface { - struct list_head node; - struct class *class; - - int (*add_dev) (struct device *, struct class_interface *); - void (*remove_dev) (struct device *, struct class_interface *); -}; - -extern int __must_check class_interface_register(struct class_interface *); -extern void class_interface_unregister(struct class_interface *); - -extern struct class * __must_check __class_create(struct module *owner, - const char *name, - struct lock_class_key *key); -extern void class_destroy(struct class *cls); - -/* This is a #define to keep the compiler from merging different - * instances of the __key variable */ -#define class_create(owner, name) \ -({ \ - static struct lock_class_key __key; \ - __class_create(owner, name, &__key); \ -}) - -/* - * The type of device, "struct device" is embedded in. A class - * or bus can contain devices of different types - * like "partitions" and "disks", "mouse" and "event". - * This identifies the device type and carries type-specific - * information, equivalent to the kobj_type of a kobject. - * If "name" is specified, the uevent will contain it in - * the DEVTYPE variable. - */ -struct device_type { - const char *name; - const struct attribute_group **groups; - int (*uevent)(struct device *dev, struct kobj_uevent_env *env); - char *(*devnode)(struct device *dev, umode_t *mode, - kuid_t *uid, kgid_t *gid); - void (*release)(struct device *dev); - - const struct dev_pm_ops *pm; -}; - -/* interface for exporting device attributes */ -struct device_attribute { - struct attribute attr; - ssize_t (*show)(struct device *dev, struct device_attribute *attr, - char *buf); - ssize_t (*store)(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count); -}; - -struct dev_ext_attribute { - struct device_attribute attr; - void *var; -}; - -ssize_t device_show_ulong(struct device *dev, struct device_attribute *attr, - char *buf); -ssize_t device_store_ulong(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count); -ssize_t device_show_int(struct device *dev, struct device_attribute *attr, - char *buf); -ssize_t device_store_int(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count); -ssize_t device_show_bool(struct device *dev, struct device_attribute *attr, - char *buf); -ssize_t device_store_bool(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count); - -#define DEVICE_ATTR(_name, _mode, _show, _store) \ - struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store) -#define DEVICE_ATTR_RW(_name) \ - struct device_attribute dev_attr_##_name = __ATTR_RW(_name) -#define DEVICE_ATTR_RO(_name) \ - struct device_attribute dev_attr_##_name = __ATTR_RO(_name) -#define DEVICE_ATTR_WO(_name) \ - struct device_attribute dev_attr_##_name = __ATTR_WO(_name) -#define DEVICE_ULONG_ATTR(_name, _mode, _var) \ - struct dev_ext_attribute dev_attr_##_name = \ - { __ATTR(_name, _mode, device_show_ulong, device_store_ulong), &(_var) } -#define DEVICE_INT_ATTR(_name, _mode, _var) \ - struct dev_ext_attribute dev_attr_##_name = \ - { __ATTR(_name, _mode, device_show_int, device_store_int), &(_var) } -#define DEVICE_BOOL_ATTR(_name, _mode, _var) \ - struct dev_ext_attribute dev_attr_##_name = \ - { __ATTR(_name, _mode, device_show_bool, device_store_bool), &(_var) } -#define DEVICE_ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) \ - struct device_attribute dev_attr_##_name = \ - __ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) - -extern int device_create_file(struct device *device, - const struct device_attribute *entry); -extern void device_remove_file(struct device *dev, - const struct device_attribute *attr); -extern bool device_remove_file_self(struct device *dev, - const struct device_attribute *attr); -extern int __must_check device_create_bin_file(struct device *dev, - const struct bin_attribute *attr); -extern void device_remove_bin_file(struct device *dev, - const struct bin_attribute *attr); - -/* device resource management */ -typedef void (*dr_release_t)(struct device *dev, void *res); -typedef int (*dr_match_t)(struct device *dev, void *res, void *match_data); - -#ifdef CONFIG_DEBUG_DEVRES -extern void *__devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, - int nid, const char *name) __malloc; -#define devres_alloc(release, size, gfp) \ - __devres_alloc_node(release, size, gfp, NUMA_NO_NODE, #release) -#define devres_alloc_node(release, size, gfp, nid) \ - __devres_alloc_node(release, size, gfp, nid, #release) -#else -extern void *devres_alloc_node(dr_release_t release, size_t size, gfp_t gfp, - int nid) __malloc; -static inline void *devres_alloc(dr_release_t release, size_t size, gfp_t gfp) -{ - return devres_alloc_node(release, size, gfp, NUMA_NO_NODE); -} -#endif - -extern void devres_for_each_res(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data, - void (*fn)(struct device *, void *, void *), - void *data); -extern void devres_free(void *res); -extern void devres_add(struct device *dev, void *res); -extern void *devres_find(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data); -extern void *devres_get(struct device *dev, void *new_res, - dr_match_t match, void *match_data); -extern void *devres_remove(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data); -extern int devres_destroy(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data); -extern int devres_release(struct device *dev, dr_release_t release, - dr_match_t match, void *match_data); - -/* devres group */ -extern void * __must_check devres_open_group(struct device *dev, void *id, - gfp_t gfp); -extern void devres_close_group(struct device *dev, void *id); -extern void devres_remove_group(struct device *dev, void *id); -extern int devres_release_group(struct device *dev, void *id); - -/* managed devm_k.alloc/kfree for device drivers */ -extern void *devm_kmalloc(struct device *dev, size_t size, gfp_t gfp) __malloc; -extern __printf(3, 0) -char *devm_kvasprintf(struct device *dev, gfp_t gfp, const char *fmt, - va_list ap) __malloc; -extern __printf(3, 4) -char *devm_kasprintf(struct device *dev, gfp_t gfp, const char *fmt, ...) __malloc; -static inline void *devm_kzalloc(struct device *dev, size_t size, gfp_t gfp) -{ - return devm_kmalloc(dev, size, gfp | __GFP_ZERO); -} -static inline void *devm_kmalloc_array(struct device *dev, - size_t n, size_t size, gfp_t flags) -{ - if (size != 0 && n > SIZE_MAX / size) - return NULL; - return devm_kmalloc(dev, n * size, flags); -} -static inline void *devm_kcalloc(struct device *dev, - size_t n, size_t size, gfp_t flags) -{ - return devm_kmalloc_array(dev, n, size, flags | __GFP_ZERO); -} -extern void devm_kfree(struct device *dev, void *p); -extern char *devm_kstrdup(struct device *dev, const char *s, gfp_t gfp) __malloc; -extern void *devm_kmemdup(struct device *dev, const void *src, size_t len, - gfp_t gfp); - -extern unsigned long devm_get_free_pages(struct device *dev, - gfp_t gfp_mask, unsigned int order); -extern void devm_free_pages(struct device *dev, unsigned long addr); - -void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res); - -/* allows to add/remove a custom action to devres stack */ -int devm_add_action(struct device *dev, void (*action)(void *), void *data); -void devm_remove_action(struct device *dev, void (*action)(void *), void *data); - -static inline int devm_add_action_or_reset(struct device *dev, - void (*action)(void *), void *data) -{ - int ret; - - ret = devm_add_action(dev, action, data); - if (ret) - action(data); - - return ret; -} - -struct device_dma_parameters { - /* - * a low level driver may set these to teach IOMMU code about - * sg limitations. - */ - unsigned int max_segment_size; - unsigned long segment_boundary_mask; -}; - -/** - * struct device - The basic device structure - * @parent: The device's "parent" device, the device to which it is attached. - * In most cases, a parent device is some sort of bus or host - * controller. If parent is NULL, the device, is a top-level device, - * which is not usually what you want. - * @p: Holds the private data of the driver core portions of the device. - * See the comment of the struct device_private for detail. - * @kobj: A top-level, abstract class from which other classes are derived. - * @init_name: Initial name of the device. - * @type: The type of device. - * This identifies the device type and carries type-specific - * information. - * @mutex: Mutex to synchronize calls to its driver. - * @bus: Type of bus device is on. - * @driver: Which driver has allocated this - * @platform_data: Platform data specific to the device. - * Example: For devices on custom boards, as typical of embedded - * and SOC based hardware, Linux often uses platform_data to point - * to board-specific structures describing devices and how they - * are wired. That can include what ports are available, chip - * variants, which GPIO pins act in what additional roles, and so - * on. This shrinks the "Board Support Packages" (BSPs) and - * minimizes board-specific #ifdefs in drivers. - * @driver_data: Private pointer for driver specific info. - * @power: For device power management. - * See Documentation/power/devices.txt for details. - * @pm_domain: Provide callbacks that are executed during system suspend, - * hibernation, system resume and during runtime PM transitions - * along with subsystem-level and driver-level callbacks. - * @pins: For device pin management. - * See Documentation/pinctrl.txt for details. - * @msi_list: Hosts MSI descriptors - * @msi_domain: The generic MSI domain this device is using. - * @numa_node: NUMA node this device is close to. - * @dma_mask: Dma mask (if dma'ble device). - * @coherent_dma_mask: Like dma_mask, but for alloc_coherent mapping as not all - * hardware supports 64-bit addresses for consistent allocations - * such descriptors. - * @dma_pfn_offset: offset of DMA memory range relatively of RAM - * @dma_parms: A low level driver may set these to teach IOMMU code about - * segment limitations. - * @dma_pools: Dma pools (if dma'ble device). - * @dma_mem: Internal for coherent mem override. - * @cma_area: Contiguous memory area for dma allocations - * @archdata: For arch-specific additions. - * @of_node: Associated device tree node. - * @fwnode: Associated device node supplied by platform firmware. - * @devt: For creating the sysfs "dev". - * @id: device instance - * @devres_lock: Spinlock to protect the resource of the device. - * @devres_head: The resources list of the device. - * @knode_class: The node used to add the device to the class list. - * @class: The class of the device. - * @groups: Optional attribute groups. - * @release: Callback to free the device after all references have - * gone away. This should be set by the allocator of the - * device (i.e. the bus driver that discovered the device). - * @iommu_group: IOMMU group the device belongs to. - * @iommu_fwspec: IOMMU-specific properties supplied by firmware. - * - * @offline_disabled: If set, the device is permanently online. - * @offline: Set after successful invocation of bus type's .offline(). - * - * At the lowest level, every device in a Linux system is represented by an - * instance of struct device. The device structure contains the information - * that the device model core needs to model the system. Most subsystems, - * however, track additional information about the devices they host. As a - * result, it is rare for devices to be represented by bare device structures; - * instead, that structure, like kobject structures, is usually embedded within - * a higher-level representation of the device. - */ -struct device { - struct device *parent; - - struct device_private *p; - - struct kobject kobj; - const char *init_name; /* initial name of the device */ - const struct device_type *type; - - struct mutex mutex; /* mutex to synchronize calls to - * its driver. - */ - - struct bus_type *bus; /* type of bus device is on */ - struct device_driver *driver; /* which driver has allocated this - device */ - void *platform_data; /* Platform specific data, device - core doesn't touch it */ - void *driver_data; /* Driver data, set and get with - dev_set/get_drvdata */ - struct dev_pm_info power; - struct dev_pm_domain *pm_domain; - -#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN - struct irq_domain *msi_domain; -#endif -#ifdef CONFIG_PINCTRL - struct dev_pin_info *pins; -#endif -#ifdef CONFIG_GENERIC_MSI_IRQ - struct list_head msi_list; -#endif - -#ifdef CONFIG_NUMA - int numa_node; /* NUMA node this device is close to */ -#endif - u64 *dma_mask; /* dma mask (if dma'able device) */ - u64 coherent_dma_mask;/* Like dma_mask, but for - alloc_coherent mappings as - not all hardware supports - 64 bit addresses for consistent - allocations such descriptors. */ - unsigned long dma_pfn_offset; - - struct device_dma_parameters *dma_parms; - - struct list_head dma_pools; /* dma pools (if dma'ble) */ - - struct dma_coherent_mem *dma_mem; /* internal for coherent mem - override */ -#ifdef CONFIG_DMA_CMA - struct cma *cma_area; /* contiguous memory area for dma - allocations */ -#endif - /* arch specific additions */ - struct dev_archdata archdata; - - struct device_node *of_node; /* associated device tree node */ - struct fwnode_handle *fwnode; /* firmware device node */ - - dev_t devt; /* dev_t, creates the sysfs "dev" */ - u32 id; /* device instance */ - - spinlock_t devres_lock; - struct list_head devres_head; - - struct klist_node knode_class; - struct class *class; - const struct attribute_group **groups; /* optional groups */ - - void (*release)(struct device *dev); - struct iommu_group *iommu_group; - struct iommu_fwspec *iommu_fwspec; - - bool offline_disabled:1; - bool offline:1; -}; - -static inline struct device *kobj_to_dev(struct kobject *kobj) -{ - return container_of(kobj, struct device, kobj); -} - -/* Get the wakeup routines, which depend on struct device */ -#include - -static inline const char *dev_name(const struct device *dev) -{ - /* Use the init name until the kobject becomes available */ - if (dev->init_name) - return dev->init_name; - - return kobject_name(&dev->kobj); -} - -extern __printf(2, 3) -int dev_set_name(struct device *dev, const char *name, ...); - -#ifdef CONFIG_NUMA -static inline int dev_to_node(struct device *dev) -{ - return dev->numa_node; -} -static inline void set_dev_node(struct device *dev, int node) -{ - dev->numa_node = node; -} -#else -static inline int dev_to_node(struct device *dev) -{ - return -1; -} -static inline void set_dev_node(struct device *dev, int node) -{ -} -#endif - -static inline struct irq_domain *dev_get_msi_domain(const struct device *dev) -{ -#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN - return dev->msi_domain; -#else - return NULL; -#endif -} - -static inline void dev_set_msi_domain(struct device *dev, struct irq_domain *d) -{ -#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN - dev->msi_domain = d; -#endif -} - -static inline void *dev_get_drvdata(const struct device *dev) -{ - return dev->driver_data; -} - -static inline void dev_set_drvdata(struct device *dev, void *data) -{ - dev->driver_data = data; -} - -static inline struct pm_subsys_data *dev_to_psd(struct device *dev) -{ - return dev ? dev->power.subsys_data : NULL; -} - -static inline unsigned int dev_get_uevent_suppress(const struct device *dev) -{ - return dev->kobj.uevent_suppress; -} - -static inline void dev_set_uevent_suppress(struct device *dev, int val) -{ - dev->kobj.uevent_suppress = val; -} - -static inline int device_is_registered(struct device *dev) -{ - return dev->kobj.state_in_sysfs; -} - -static inline void device_enable_async_suspend(struct device *dev) -{ - if (!dev->power.is_prepared) - dev->power.async_suspend = true; -} - -static inline void device_disable_async_suspend(struct device *dev) -{ - if (!dev->power.is_prepared) - dev->power.async_suspend = false; -} - -static inline bool device_async_suspend_enabled(struct device *dev) -{ - return !!dev->power.async_suspend; -} - -static inline void dev_pm_syscore_device(struct device *dev, bool val) -{ -#ifdef CONFIG_PM_SLEEP - dev->power.syscore = val; -#endif -} - -static inline void device_lock(struct device *dev) -{ - mutex_lock(&dev->mutex); -} - -static inline int device_lock_interruptible(struct device *dev) -{ - return mutex_lock_interruptible(&dev->mutex); -} - -static inline int device_trylock(struct device *dev) -{ - return mutex_trylock(&dev->mutex); -} - -static inline void device_unlock(struct device *dev) -{ - mutex_unlock(&dev->mutex); -} - -static inline void device_lock_assert(struct device *dev) -{ - lockdep_assert_held(&dev->mutex); -} - -static inline struct device_node *dev_of_node(struct device *dev) -{ - if (!IS_ENABLED(CONFIG_OF)) - return NULL; - return dev->of_node; -} - -void driver_init(void); - -/* - * High level routines for use by the bus drivers - */ -extern int __must_check device_register(struct device *dev); -extern void device_unregister(struct device *dev); -extern void device_initialize(struct device *dev); -extern int __must_check device_add(struct device *dev); -extern void device_del(struct device *dev); -extern int device_for_each_child(struct device *dev, void *data, - int (*fn)(struct device *dev, void *data)); -extern int device_for_each_child_reverse(struct device *dev, void *data, - int (*fn)(struct device *dev, void *data)); -extern struct device *device_find_child(struct device *dev, void *data, - int (*match)(struct device *dev, void *data)); -extern int device_rename(struct device *dev, const char *new_name); -extern int device_move(struct device *dev, struct device *new_parent, - enum dpm_order dpm_order); -extern const char *device_get_devnode(struct device *dev, - umode_t *mode, kuid_t *uid, kgid_t *gid, - const char **tmp); - -static inline bool device_supports_offline(struct device *dev) -{ - return dev->bus && dev->bus->offline && dev->bus->online; -} - -extern void lock_device_hotplug(void); -extern void unlock_device_hotplug(void); -extern int lock_device_hotplug_sysfs(void); -extern int device_offline(struct device *dev); -extern int device_online(struct device *dev); -extern void set_primary_fwnode(struct device *dev, struct fwnode_handle *fwnode); -extern void set_secondary_fwnode(struct device *dev, struct fwnode_handle *fwnode); - -/* - * Root device objects for grouping under /sys/devices - */ -extern struct device *__root_device_register(const char *name, - struct module *owner); - -/* This is a macro to avoid include problems with THIS_MODULE */ -#define root_device_register(name) \ - __root_device_register(name, THIS_MODULE) - -extern void root_device_unregister(struct device *root); - -static inline void *dev_get_platdata(const struct device *dev) -{ - return dev->platform_data; -} - -/* - * Manual binding of a device to driver. See drivers/base/bus.c - * for information on use. - */ -extern int __must_check device_bind_driver(struct device *dev); -extern void device_release_driver(struct device *dev); -extern int __must_check device_attach(struct device *dev); -extern int __must_check driver_attach(struct device_driver *drv); -extern void device_initial_probe(struct device *dev); -extern int __must_check device_reprobe(struct device *dev); - -extern bool device_is_bound(struct device *dev); - -/* - * Easy functions for dynamically creating devices on the fly - */ -extern __printf(5, 0) -struct device *device_create_vargs(struct class *cls, struct device *parent, - dev_t devt, void *drvdata, - const char *fmt, va_list vargs); -extern __printf(5, 6) -struct device *device_create(struct class *cls, struct device *parent, - dev_t devt, void *drvdata, - const char *fmt, ...); -extern __printf(6, 7) -struct device *device_create_with_groups(struct class *cls, - struct device *parent, dev_t devt, void *drvdata, - const struct attribute_group **groups, - const char *fmt, ...); -extern void device_destroy(struct class *cls, dev_t devt); - -/* - * Platform "fixup" functions - allow the platform to have their say - * about devices and actions that the general device layer doesn't - * know about. - */ -/* Notify platform of device discovery */ -extern int (*platform_notify)(struct device *dev); - -extern int (*platform_notify_remove)(struct device *dev); - - -/* - * get_device - atomically increment the reference count for the device. - * - */ -extern struct device *get_device(struct device *dev); -extern void put_device(struct device *dev); - -#ifdef CONFIG_DEVTMPFS -extern int devtmpfs_create_node(struct device *dev); -extern int devtmpfs_delete_node(struct device *dev); -extern int devtmpfs_mount(const char *mntdir); -#else -static inline int devtmpfs_create_node(struct device *dev) { return 0; } -static inline int devtmpfs_delete_node(struct device *dev) { return 0; } -static inline int devtmpfs_mount(const char *mountpoint) { return 0; } -#endif - -/* drivers/base/power/shutdown.c */ -extern void device_shutdown(void); - -/* debugging and troubleshooting/diagnostic helpers. */ -extern const char *dev_driver_string(const struct device *dev); - - -#ifdef CONFIG_PRINTK - -extern __printf(3, 0) -int dev_vprintk_emit(int level, const struct device *dev, - const char *fmt, va_list args); -extern __printf(3, 4) -int dev_printk_emit(int level, const struct device *dev, const char *fmt, ...); - -extern __printf(3, 4) -void dev_printk(const char *level, const struct device *dev, - const char *fmt, ...); -extern __printf(2, 3) -void dev_emerg(const struct device *dev, const char *fmt, ...); -extern __printf(2, 3) -void dev_alert(const struct device *dev, const char *fmt, ...); -extern __printf(2, 3) -void dev_crit(const struct device *dev, const char *fmt, ...); -extern __printf(2, 3) -void dev_err(const struct device *dev, const char *fmt, ...); -extern __printf(2, 3) -void dev_warn(const struct device *dev, const char *fmt, ...); -extern __printf(2, 3) -void dev_notice(const struct device *dev, const char *fmt, ...); -extern __printf(2, 3) -void _dev_info(const struct device *dev, const char *fmt, ...); - -#else - -static inline __printf(3, 0) -int dev_vprintk_emit(int level, const struct device *dev, - const char *fmt, va_list args) -{ return 0; } -static inline __printf(3, 4) -int dev_printk_emit(int level, const struct device *dev, const char *fmt, ...) -{ return 0; } - -static inline void __dev_printk(const char *level, const struct device *dev, - struct va_format *vaf) -{} -static inline __printf(3, 4) -void dev_printk(const char *level, const struct device *dev, - const char *fmt, ...) -{} - -static inline __printf(2, 3) -void dev_emerg(const struct device *dev, const char *fmt, ...) -{} -static inline __printf(2, 3) -void dev_crit(const struct device *dev, const char *fmt, ...) -{} -static inline __printf(2, 3) -void dev_alert(const struct device *dev, const char *fmt, ...) -{} -static inline __printf(2, 3) -void dev_err(const struct device *dev, const char *fmt, ...) -{} -static inline __printf(2, 3) -void dev_warn(const struct device *dev, const char *fmt, ...) -{} -static inline __printf(2, 3) -void dev_notice(const struct device *dev, const char *fmt, ...) -{} -static inline __printf(2, 3) -void _dev_info(const struct device *dev, const char *fmt, ...) -{} - -#endif - -/* - * Stupid hackaround for existing uses of non-printk uses dev_info - * - * Note that the definition of dev_info below is actually _dev_info - * and a macro is used to avoid redefining dev_info - */ - -#define dev_info(dev, fmt, arg...) _dev_info(dev, fmt, ##arg) - -#if defined(CONFIG_DYNAMIC_DEBUG) -#define dev_dbg(dev, format, ...) \ -do { \ - dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \ -} while (0) -#elif defined(DEBUG) -#define dev_dbg(dev, format, arg...) \ - dev_printk(KERN_DEBUG, dev, format, ##arg) -#else -#define dev_dbg(dev, format, arg...) \ -({ \ - if (0) \ - dev_printk(KERN_DEBUG, dev, format, ##arg); \ -}) -#endif - -#ifdef CONFIG_PRINTK -#define dev_level_once(dev_level, dev, fmt, ...) \ -do { \ - static bool __print_once __read_mostly; \ - \ - if (!__print_once) { \ - __print_once = true; \ - dev_level(dev, fmt, ##__VA_ARGS__); \ - } \ -} while (0) -#else -#define dev_level_once(dev_level, dev, fmt, ...) \ -do { \ - if (0) \ - dev_level(dev, fmt, ##__VA_ARGS__); \ -} while (0) -#endif - -#define dev_emerg_once(dev, fmt, ...) \ - dev_level_once(dev_emerg, dev, fmt, ##__VA_ARGS__) -#define dev_alert_once(dev, fmt, ...) \ - dev_level_once(dev_alert, dev, fmt, ##__VA_ARGS__) -#define dev_crit_once(dev, fmt, ...) \ - dev_level_once(dev_crit, dev, fmt, ##__VA_ARGS__) -#define dev_err_once(dev, fmt, ...) \ - dev_level_once(dev_err, dev, fmt, ##__VA_ARGS__) -#define dev_warn_once(dev, fmt, ...) \ - dev_level_once(dev_warn, dev, fmt, ##__VA_ARGS__) -#define dev_notice_once(dev, fmt, ...) \ - dev_level_once(dev_notice, dev, fmt, ##__VA_ARGS__) -#define dev_info_once(dev, fmt, ...) \ - dev_level_once(dev_info, dev, fmt, ##__VA_ARGS__) -#define dev_dbg_once(dev, fmt, ...) \ - dev_level_once(dev_dbg, dev, fmt, ##__VA_ARGS__) - -#define dev_level_ratelimited(dev_level, dev, fmt, ...) \ -do { \ - static DEFINE_RATELIMIT_STATE(_rs, \ - DEFAULT_RATELIMIT_INTERVAL, \ - DEFAULT_RATELIMIT_BURST); \ - if (__ratelimit(&_rs)) \ - dev_level(dev, fmt, ##__VA_ARGS__); \ -} while (0) - -#define dev_emerg_ratelimited(dev, fmt, ...) \ - dev_level_ratelimited(dev_emerg, dev, fmt, ##__VA_ARGS__) -#define dev_alert_ratelimited(dev, fmt, ...) \ - dev_level_ratelimited(dev_alert, dev, fmt, ##__VA_ARGS__) -#define dev_crit_ratelimited(dev, fmt, ...) \ - dev_level_ratelimited(dev_crit, dev, fmt, ##__VA_ARGS__) -#define dev_err_ratelimited(dev, fmt, ...) \ - dev_level_ratelimited(dev_err, dev, fmt, ##__VA_ARGS__) -#define dev_warn_ratelimited(dev, fmt, ...) \ - dev_level_ratelimited(dev_warn, dev, fmt, ##__VA_ARGS__) -#define dev_notice_ratelimited(dev, fmt, ...) \ - dev_level_ratelimited(dev_notice, dev, fmt, ##__VA_ARGS__) -#define dev_info_ratelimited(dev, fmt, ...) \ - dev_level_ratelimited(dev_info, dev, fmt, ##__VA_ARGS__) -#if defined(CONFIG_DYNAMIC_DEBUG) -/* descriptor check is first to prevent flooding with "callbacks suppressed" */ -#define dev_dbg_ratelimited(dev, fmt, ...) \ -do { \ - static DEFINE_RATELIMIT_STATE(_rs, \ - DEFAULT_RATELIMIT_INTERVAL, \ - DEFAULT_RATELIMIT_BURST); \ - DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ - if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT) && \ - __ratelimit(&_rs)) \ - __dynamic_dev_dbg(&descriptor, dev, fmt, \ - ##__VA_ARGS__); \ -} while (0) -#elif defined(DEBUG) -#define dev_dbg_ratelimited(dev, fmt, ...) \ -do { \ - static DEFINE_RATELIMIT_STATE(_rs, \ - DEFAULT_RATELIMIT_INTERVAL, \ - DEFAULT_RATELIMIT_BURST); \ - if (__ratelimit(&_rs)) \ - dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__); \ -} while (0) -#else -#define dev_dbg_ratelimited(dev, fmt, ...) \ -do { \ - if (0) \ - dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__); \ -} while (0) -#endif - -#ifdef VERBOSE_DEBUG -#define dev_vdbg dev_dbg -#else -#define dev_vdbg(dev, format, arg...) \ -({ \ - if (0) \ - dev_printk(KERN_DEBUG, dev, format, ##arg); \ -}) -#endif - -/* - * dev_WARN*() acts like dev_printk(), but with the key difference of - * using WARN/WARN_ONCE to include file/line information and a backtrace. - */ -#define dev_WARN(dev, format, arg...) \ - WARN(1, "%s %s: " format, dev_driver_string(dev), dev_name(dev), ## arg); - -#define dev_WARN_ONCE(dev, condition, format, arg...) \ - WARN_ONCE(condition, "%s %s: " format, \ - dev_driver_string(dev), dev_name(dev), ## arg) - -/* Create alias, so I can be autoloaded. */ -#define MODULE_ALIAS_CHARDEV(major,minor) \ - MODULE_ALIAS("char-major-" __stringify(major) "-" __stringify(minor)) -#define MODULE_ALIAS_CHARDEV_MAJOR(major) \ - MODULE_ALIAS("char-major-" __stringify(major) "-*") - -#ifdef CONFIG_SYSFS_DEPRECATED -extern long sysfs_deprecated; -#else -#define sysfs_deprecated 0 -#endif - -/** - * module_driver() - Helper macro for drivers that don't do anything - * special in module init/exit. This eliminates a lot of boilerplate. - * Each module may only use this macro once, and calling it replaces - * module_init() and module_exit(). - * - * @__driver: driver name - * @__register: register function for this driver type - * @__unregister: unregister function for this driver type - * @...: Additional arguments to be passed to __register and __unregister. - * - * Use this macro to construct bus specific macros for registering - * drivers, and do not use it on its own. - */ -#define module_driver(__driver, __register, __unregister, ...) \ -static int __init __driver##_init(void) \ -{ \ - return __register(&(__driver) , ##__VA_ARGS__); \ -} \ -module_init(__driver##_init); \ -static void __exit __driver##_exit(void) \ -{ \ - __unregister(&(__driver) , ##__VA_ARGS__); \ -} \ -module_exit(__driver##_exit); - -/** - * builtin_driver() - Helper macro for drivers that don't do anything - * special in init and have no exit. This eliminates some boilerplate. - * Each driver may only use this macro once, and calling it replaces - * device_initcall (or in some cases, the legacy __initcall). This is - * meant to be a direct parallel of module_driver() above but without - * the __exit stuff that is not used for builtin cases. - * - * @__driver: driver name - * @__register: register function for this driver type - * @...: Additional arguments to be passed to __register - * - * Use this macro to construct bus specific macros for registering - * drivers, and do not use it on its own. - */ -#define builtin_driver(__driver, __register, ...) \ -static int __init __driver##_init(void) \ -{ \ - return __register(&(__driver) , ##__VA_ARGS__); \ -} \ -device_initcall(__driver##_init); - -#endif /* _DEVICE_H_ */ diff --git a/src/linux/include/linux/device_cgroup.h b/src/linux/include/linux/device_cgroup.h deleted file mode 100644 index 8b64221..0000000 --- a/src/linux/include/linux/device_cgroup.h +++ /dev/null @@ -1,19 +0,0 @@ -#include - -#ifdef CONFIG_CGROUP_DEVICE -extern int __devcgroup_inode_permission(struct inode *inode, int mask); -extern int devcgroup_inode_mknod(int mode, dev_t dev); -static inline int devcgroup_inode_permission(struct inode *inode, int mask) -{ - if (likely(!inode->i_rdev)) - return 0; - if (!S_ISBLK(inode->i_mode) && !S_ISCHR(inode->i_mode)) - return 0; - return __devcgroup_inode_permission(inode, mask); -} -#else -static inline int devcgroup_inode_permission(struct inode *inode, int mask) -{ return 0; } -static inline int devcgroup_inode_mknod(int mode, dev_t dev) -{ return 0; } -#endif diff --git a/src/linux/include/linux/devpts_fs.h b/src/linux/include/linux/devpts_fs.h deleted file mode 100644 index 277ab9a..0000000 --- a/src/linux/include/linux/devpts_fs.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- linux-c -*- --------------------------------------------------------- * - * - * linux/include/linux/devpts_fs.h - * - * Copyright 1998-2004 H. Peter Anvin -- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * ------------------------------------------------------------------------- */ - -#ifndef _LINUX_DEVPTS_FS_H -#define _LINUX_DEVPTS_FS_H - -#include - -#ifdef CONFIG_UNIX98_PTYS - -struct pts_fs_info; - -struct pts_fs_info *devpts_acquire(struct file *); -void devpts_release(struct pts_fs_info *); - -int devpts_new_index(struct pts_fs_info *); -void devpts_kill_index(struct pts_fs_info *, int); - -/* mknod in devpts */ -struct dentry *devpts_pty_new(struct pts_fs_info *, int, void *); -/* get private structure */ -void *devpts_get_priv(struct dentry *); -/* unlink */ -void devpts_pty_kill(struct dentry *); - -#endif - - -#endif /* _LINUX_DEVPTS_FS_H */ diff --git a/src/linux/include/linux/dirent.h b/src/linux/include/linux/dirent.h deleted file mode 100644 index f072fb8..0000000 --- a/src/linux/include/linux/dirent.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _LINUX_DIRENT_H -#define _LINUX_DIRENT_H - -struct linux_dirent64 { - u64 d_ino; - s64 d_off; - unsigned short d_reclen; - unsigned char d_type; - char d_name[0]; -}; - -#endif diff --git a/src/linux/include/linux/dma-debug.h b/src/linux/include/linux/dma-debug.h deleted file mode 100644 index c7d844f..0000000 --- a/src/linux/include/linux/dma-debug.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 2008 Advanced Micro Devices, Inc. - * - * Author: Joerg Roedel - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __DMA_DEBUG_H -#define __DMA_DEBUG_H - -#include - -struct device; -struct scatterlist; -struct bus_type; - -#ifdef CONFIG_DMA_API_DEBUG - -extern void dma_debug_add_bus(struct bus_type *bus); - -extern void dma_debug_init(u32 num_entries); - -extern int dma_debug_resize_entries(u32 num_entries); - -extern void debug_dma_map_page(struct device *dev, struct page *page, - size_t offset, size_t size, - int direction, dma_addr_t dma_addr, - bool map_single); - -extern void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr); - -extern void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, - size_t size, int direction, bool map_single); - -extern void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, - int nents, int mapped_ents, int direction); - -extern void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist, - int nelems, int dir); - -extern void debug_dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t dma_addr, void *virt); - -extern void debug_dma_free_coherent(struct device *dev, size_t size, - void *virt, dma_addr_t addr); - -extern void debug_dma_map_resource(struct device *dev, phys_addr_t addr, - size_t size, int direction, - dma_addr_t dma_addr); - -extern void debug_dma_unmap_resource(struct device *dev, dma_addr_t dma_addr, - size_t size, int direction); - -extern void debug_dma_sync_single_for_cpu(struct device *dev, - dma_addr_t dma_handle, size_t size, - int direction); - -extern void debug_dma_sync_single_for_device(struct device *dev, - dma_addr_t dma_handle, - size_t size, int direction); - -extern void debug_dma_sync_single_range_for_cpu(struct device *dev, - dma_addr_t dma_handle, - unsigned long offset, - size_t size, - int direction); - -extern void debug_dma_sync_single_range_for_device(struct device *dev, - dma_addr_t dma_handle, - unsigned long offset, - size_t size, int direction); - -extern void debug_dma_sync_sg_for_cpu(struct device *dev, - struct scatterlist *sg, - int nelems, int direction); - -extern void debug_dma_sync_sg_for_device(struct device *dev, - struct scatterlist *sg, - int nelems, int direction); - -extern void debug_dma_dump_mappings(struct device *dev); - -extern void debug_dma_assert_idle(struct page *page); - -#else /* CONFIG_DMA_API_DEBUG */ - -static inline void dma_debug_add_bus(struct bus_type *bus) -{ -} - -static inline void dma_debug_init(u32 num_entries) -{ -} - -static inline int dma_debug_resize_entries(u32 num_entries) -{ - return 0; -} - -static inline void debug_dma_map_page(struct device *dev, struct page *page, - size_t offset, size_t size, - int direction, dma_addr_t dma_addr, - bool map_single) -{ -} - -static inline void debug_dma_mapping_error(struct device *dev, - dma_addr_t dma_addr) -{ -} - -static inline void debug_dma_unmap_page(struct device *dev, dma_addr_t addr, - size_t size, int direction, - bool map_single) -{ -} - -static inline void debug_dma_map_sg(struct device *dev, struct scatterlist *sg, - int nents, int mapped_ents, int direction) -{ -} - -static inline void debug_dma_unmap_sg(struct device *dev, - struct scatterlist *sglist, - int nelems, int dir) -{ -} - -static inline void debug_dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t dma_addr, void *virt) -{ -} - -static inline void debug_dma_free_coherent(struct device *dev, size_t size, - void *virt, dma_addr_t addr) -{ -} - -static inline void debug_dma_map_resource(struct device *dev, phys_addr_t addr, - size_t size, int direction, - dma_addr_t dma_addr) -{ -} - -static inline void debug_dma_unmap_resource(struct device *dev, - dma_addr_t dma_addr, size_t size, - int direction) -{ -} - -static inline void debug_dma_sync_single_for_cpu(struct device *dev, - dma_addr_t dma_handle, - size_t size, int direction) -{ -} - -static inline void debug_dma_sync_single_for_device(struct device *dev, - dma_addr_t dma_handle, - size_t size, int direction) -{ -} - -static inline void debug_dma_sync_single_range_for_cpu(struct device *dev, - dma_addr_t dma_handle, - unsigned long offset, - size_t size, - int direction) -{ -} - -static inline void debug_dma_sync_single_range_for_device(struct device *dev, - dma_addr_t dma_handle, - unsigned long offset, - size_t size, - int direction) -{ -} - -static inline void debug_dma_sync_sg_for_cpu(struct device *dev, - struct scatterlist *sg, - int nelems, int direction) -{ -} - -static inline void debug_dma_sync_sg_for_device(struct device *dev, - struct scatterlist *sg, - int nelems, int direction) -{ -} - -static inline void debug_dma_dump_mappings(struct device *dev) -{ -} - -static inline void debug_dma_assert_idle(struct page *page) -{ -} - -#endif /* CONFIG_DMA_API_DEBUG */ - -#endif /* __DMA_DEBUG_H */ diff --git a/src/linux/include/linux/dma-direction.h b/src/linux/include/linux/dma-direction.h deleted file mode 100644 index 95b6a82..0000000 --- a/src/linux/include/linux/dma-direction.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _LINUX_DMA_DIRECTION_H -#define _LINUX_DMA_DIRECTION_H -/* - * These definitions mirror those in pci.h, so they can be used - * interchangeably with their PCI_ counterparts. - */ -enum dma_data_direction { - DMA_BIDIRECTIONAL = 0, - DMA_TO_DEVICE = 1, - DMA_FROM_DEVICE = 2, - DMA_NONE = 3, -}; -#endif diff --git a/src/linux/include/linux/dma-mapping.h b/src/linux/include/linux/dma-mapping.h deleted file mode 100644 index 08528af..0000000 --- a/src/linux/include/linux/dma-mapping.h +++ /dev/null @@ -1,783 +0,0 @@ -#ifndef _LINUX_DMA_MAPPING_H -#define _LINUX_DMA_MAPPING_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * List of possible attributes associated with a DMA mapping. The semantics - * of each attribute should be defined in Documentation/DMA-attributes.txt. - * - * DMA_ATTR_WRITE_BARRIER: DMA to a memory region with this attribute - * forces all pending DMA writes to complete. - */ -#define DMA_ATTR_WRITE_BARRIER (1UL << 0) -/* - * DMA_ATTR_WEAK_ORDERING: Specifies that reads and writes to the mapping - * may be weakly ordered, that is that reads and writes may pass each other. - */ -#define DMA_ATTR_WEAK_ORDERING (1UL << 1) -/* - * DMA_ATTR_WRITE_COMBINE: Specifies that writes to the mapping may be - * buffered to improve performance. - */ -#define DMA_ATTR_WRITE_COMBINE (1UL << 2) -/* - * DMA_ATTR_NON_CONSISTENT: Lets the platform to choose to return either - * consistent or non-consistent memory as it sees fit. - */ -#define DMA_ATTR_NON_CONSISTENT (1UL << 3) -/* - * DMA_ATTR_NO_KERNEL_MAPPING: Lets the platform to avoid creating a kernel - * virtual mapping for the allocated buffer. - */ -#define DMA_ATTR_NO_KERNEL_MAPPING (1UL << 4) -/* - * DMA_ATTR_SKIP_CPU_SYNC: Allows platform code to skip synchronization of - * the CPU cache for the given buffer assuming that it has been already - * transferred to 'device' domain. - */ -#define DMA_ATTR_SKIP_CPU_SYNC (1UL << 5) -/* - * DMA_ATTR_FORCE_CONTIGUOUS: Forces contiguous allocation of the buffer - * in physical memory. - */ -#define DMA_ATTR_FORCE_CONTIGUOUS (1UL << 6) -/* - * DMA_ATTR_ALLOC_SINGLE_PAGES: This is a hint to the DMA-mapping subsystem - * that it's probably not worth the time to try to allocate memory to in a way - * that gives better TLB efficiency. - */ -#define DMA_ATTR_ALLOC_SINGLE_PAGES (1UL << 7) -/* - * DMA_ATTR_NO_WARN: This tells the DMA-mapping subsystem to suppress - * allocation failure reports (similarly to __GFP_NOWARN). - */ -#define DMA_ATTR_NO_WARN (1UL << 8) - -/* - * A dma_addr_t can hold any valid DMA or bus address for the platform. - * It can be given to a device to use as a DMA source or target. A CPU cannot - * reference a dma_addr_t directly because there may be translation between - * its physical address space and the bus address space. - */ -struct dma_map_ops { - void* (*alloc)(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp, - unsigned long attrs); - void (*free)(struct device *dev, size_t size, - void *vaddr, dma_addr_t dma_handle, - unsigned long attrs); - int (*mmap)(struct device *, struct vm_area_struct *, - void *, dma_addr_t, size_t, - unsigned long attrs); - - int (*get_sgtable)(struct device *dev, struct sg_table *sgt, void *, - dma_addr_t, size_t, unsigned long attrs); - - dma_addr_t (*map_page)(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction dir, - unsigned long attrs); - void (*unmap_page)(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction dir, - unsigned long attrs); - /* - * map_sg returns 0 on error and a value > 0 on success. - * It should never return a value < 0. - */ - int (*map_sg)(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction dir, - unsigned long attrs); - void (*unmap_sg)(struct device *dev, - struct scatterlist *sg, int nents, - enum dma_data_direction dir, - unsigned long attrs); - dma_addr_t (*map_resource)(struct device *dev, phys_addr_t phys_addr, - size_t size, enum dma_data_direction dir, - unsigned long attrs); - void (*unmap_resource)(struct device *dev, dma_addr_t dma_handle, - size_t size, enum dma_data_direction dir, - unsigned long attrs); - void (*sync_single_for_cpu)(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction dir); - void (*sync_single_for_device)(struct device *dev, - dma_addr_t dma_handle, size_t size, - enum dma_data_direction dir); - void (*sync_sg_for_cpu)(struct device *dev, - struct scatterlist *sg, int nents, - enum dma_data_direction dir); - void (*sync_sg_for_device)(struct device *dev, - struct scatterlist *sg, int nents, - enum dma_data_direction dir); - int (*mapping_error)(struct device *dev, dma_addr_t dma_addr); - int (*dma_supported)(struct device *dev, u64 mask); - int (*set_dma_mask)(struct device *dev, u64 mask); -#ifdef ARCH_HAS_DMA_GET_REQUIRED_MASK - u64 (*get_required_mask)(struct device *dev); -#endif - int is_phys; -}; - -extern struct dma_map_ops dma_noop_ops; - -#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : ((1ULL<<(n))-1)) - -#define DMA_MASK_NONE 0x0ULL - -static inline int valid_dma_direction(int dma_direction) -{ - return ((dma_direction == DMA_BIDIRECTIONAL) || - (dma_direction == DMA_TO_DEVICE) || - (dma_direction == DMA_FROM_DEVICE)); -} - -static inline int is_device_dma_capable(struct device *dev) -{ - return dev->dma_mask != NULL && *dev->dma_mask != DMA_MASK_NONE; -} - -#ifdef CONFIG_HAVE_GENERIC_DMA_COHERENT -/* - * These three functions are only for dma allocator. - * Don't use them in device drivers. - */ -int dma_alloc_from_coherent(struct device *dev, ssize_t size, - dma_addr_t *dma_handle, void **ret); -int dma_release_from_coherent(struct device *dev, int order, void *vaddr); - -int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma, - void *cpu_addr, size_t size, int *ret); -#else -#define dma_alloc_from_coherent(dev, size, handle, ret) (0) -#define dma_release_from_coherent(dev, order, vaddr) (0) -#define dma_mmap_from_coherent(dev, vma, vaddr, order, ret) (0) -#endif /* CONFIG_HAVE_GENERIC_DMA_COHERENT */ - -#ifdef CONFIG_HAS_DMA -#include -#else -/* - * Define the dma api to allow compilation but not linking of - * dma dependent code. Code that depends on the dma-mapping - * API needs to set 'depends on HAS_DMA' in its Kconfig - */ -extern struct dma_map_ops bad_dma_ops; -static inline struct dma_map_ops *get_dma_ops(struct device *dev) -{ - return &bad_dma_ops; -} -#endif - -static inline dma_addr_t dma_map_single_attrs(struct device *dev, void *ptr, - size_t size, - enum dma_data_direction dir, - unsigned long attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - dma_addr_t addr; - - kmemcheck_mark_initialized(ptr, size); - BUG_ON(!valid_dma_direction(dir)); - addr = ops->map_page(dev, virt_to_page(ptr), - offset_in_page(ptr), size, - dir, attrs); - debug_dma_map_page(dev, virt_to_page(ptr), - offset_in_page(ptr), size, - dir, addr, true); - return addr; -} - -static inline void dma_unmap_single_attrs(struct device *dev, dma_addr_t addr, - size_t size, - enum dma_data_direction dir, - unsigned long attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - BUG_ON(!valid_dma_direction(dir)); - if (ops->unmap_page) - ops->unmap_page(dev, addr, size, dir, attrs); - debug_dma_unmap_page(dev, addr, size, dir, true); -} - -/* - * dma_maps_sg_attrs returns 0 on error and > 0 on success. - * It should never return a value < 0. - */ -static inline int dma_map_sg_attrs(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction dir, - unsigned long attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - int i, ents; - struct scatterlist *s; - - for_each_sg(sg, s, nents, i) - kmemcheck_mark_initialized(sg_virt(s), s->length); - BUG_ON(!valid_dma_direction(dir)); - ents = ops->map_sg(dev, sg, nents, dir, attrs); - BUG_ON(ents < 0); - debug_dma_map_sg(dev, sg, nents, ents, dir); - - return ents; -} - -static inline void dma_unmap_sg_attrs(struct device *dev, struct scatterlist *sg, - int nents, enum dma_data_direction dir, - unsigned long attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - BUG_ON(!valid_dma_direction(dir)); - debug_dma_unmap_sg(dev, sg, nents, dir); - if (ops->unmap_sg) - ops->unmap_sg(dev, sg, nents, dir, attrs); -} - -static inline dma_addr_t dma_map_page(struct device *dev, struct page *page, - size_t offset, size_t size, - enum dma_data_direction dir) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - dma_addr_t addr; - - kmemcheck_mark_initialized(page_address(page) + offset, size); - BUG_ON(!valid_dma_direction(dir)); - addr = ops->map_page(dev, page, offset, size, dir, 0); - debug_dma_map_page(dev, page, offset, size, dir, addr, false); - - return addr; -} - -static inline void dma_unmap_page(struct device *dev, dma_addr_t addr, - size_t size, enum dma_data_direction dir) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - BUG_ON(!valid_dma_direction(dir)); - if (ops->unmap_page) - ops->unmap_page(dev, addr, size, dir, 0); - debug_dma_unmap_page(dev, addr, size, dir, false); -} - -static inline dma_addr_t dma_map_resource(struct device *dev, - phys_addr_t phys_addr, - size_t size, - enum dma_data_direction dir, - unsigned long attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - dma_addr_t addr; - - BUG_ON(!valid_dma_direction(dir)); - - /* Don't allow RAM to be mapped */ - BUG_ON(pfn_valid(PHYS_PFN(phys_addr))); - - addr = phys_addr; - if (ops->map_resource) - addr = ops->map_resource(dev, phys_addr, size, dir, attrs); - - debug_dma_map_resource(dev, phys_addr, size, dir, addr); - - return addr; -} - -static inline void dma_unmap_resource(struct device *dev, dma_addr_t addr, - size_t size, enum dma_data_direction dir, - unsigned long attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - BUG_ON(!valid_dma_direction(dir)); - if (ops->unmap_resource) - ops->unmap_resource(dev, addr, size, dir, attrs); - debug_dma_unmap_resource(dev, addr, size, dir); -} - -static inline void dma_sync_single_for_cpu(struct device *dev, dma_addr_t addr, - size_t size, - enum dma_data_direction dir) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - BUG_ON(!valid_dma_direction(dir)); - if (ops->sync_single_for_cpu) - ops->sync_single_for_cpu(dev, addr, size, dir); - debug_dma_sync_single_for_cpu(dev, addr, size, dir); -} - -static inline void dma_sync_single_for_device(struct device *dev, - dma_addr_t addr, size_t size, - enum dma_data_direction dir) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - BUG_ON(!valid_dma_direction(dir)); - if (ops->sync_single_for_device) - ops->sync_single_for_device(dev, addr, size, dir); - debug_dma_sync_single_for_device(dev, addr, size, dir); -} - -static inline void dma_sync_single_range_for_cpu(struct device *dev, - dma_addr_t addr, - unsigned long offset, - size_t size, - enum dma_data_direction dir) -{ - const struct dma_map_ops *ops = get_dma_ops(dev); - - BUG_ON(!valid_dma_direction(dir)); - if (ops->sync_single_for_cpu) - ops->sync_single_for_cpu(dev, addr + offset, size, dir); - debug_dma_sync_single_range_for_cpu(dev, addr, offset, size, dir); -} - -static inline void dma_sync_single_range_for_device(struct device *dev, - dma_addr_t addr, - unsigned long offset, - size_t size, - enum dma_data_direction dir) -{ - const struct dma_map_ops *ops = get_dma_ops(dev); - - BUG_ON(!valid_dma_direction(dir)); - if (ops->sync_single_for_device) - ops->sync_single_for_device(dev, addr + offset, size, dir); - debug_dma_sync_single_range_for_device(dev, addr, offset, size, dir); -} - -static inline void -dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, - int nelems, enum dma_data_direction dir) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - BUG_ON(!valid_dma_direction(dir)); - if (ops->sync_sg_for_cpu) - ops->sync_sg_for_cpu(dev, sg, nelems, dir); - debug_dma_sync_sg_for_cpu(dev, sg, nelems, dir); -} - -static inline void -dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, - int nelems, enum dma_data_direction dir) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - BUG_ON(!valid_dma_direction(dir)); - if (ops->sync_sg_for_device) - ops->sync_sg_for_device(dev, sg, nelems, dir); - debug_dma_sync_sg_for_device(dev, sg, nelems, dir); - -} - -#define dma_map_single(d, a, s, r) dma_map_single_attrs(d, a, s, r, 0) -#define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, 0) -#define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, 0) -#define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, 0) - -extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, - void *cpu_addr, dma_addr_t dma_addr, size_t size); - -void *dma_common_contiguous_remap(struct page *page, size_t size, - unsigned long vm_flags, - pgprot_t prot, const void *caller); - -void *dma_common_pages_remap(struct page **pages, size_t size, - unsigned long vm_flags, pgprot_t prot, - const void *caller); -void dma_common_free_remap(void *cpu_addr, size_t size, unsigned long vm_flags); - -/** - * dma_mmap_attrs - map a coherent DMA allocation into user space - * @dev: valid struct device pointer, or NULL for ISA and EISA-like devices - * @vma: vm_area_struct describing requested user mapping - * @cpu_addr: kernel CPU-view address returned from dma_alloc_attrs - * @handle: device-view address returned from dma_alloc_attrs - * @size: size of memory originally requested in dma_alloc_attrs - * @attrs: attributes of mapping properties requested in dma_alloc_attrs - * - * Map a coherent DMA buffer previously allocated by dma_alloc_attrs - * into user space. The coherent DMA buffer must not be freed by the - * driver until the user space mapping has been released. - */ -static inline int -dma_mmap_attrs(struct device *dev, struct vm_area_struct *vma, void *cpu_addr, - dma_addr_t dma_addr, size_t size, unsigned long attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - BUG_ON(!ops); - if (ops->mmap) - return ops->mmap(dev, vma, cpu_addr, dma_addr, size, attrs); - return dma_common_mmap(dev, vma, cpu_addr, dma_addr, size); -} - -#define dma_mmap_coherent(d, v, c, h, s) dma_mmap_attrs(d, v, c, h, s, 0) - -int -dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, - void *cpu_addr, dma_addr_t dma_addr, size_t size); - -static inline int -dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, void *cpu_addr, - dma_addr_t dma_addr, size_t size, - unsigned long attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - BUG_ON(!ops); - if (ops->get_sgtable) - return ops->get_sgtable(dev, sgt, cpu_addr, dma_addr, size, - attrs); - return dma_common_get_sgtable(dev, sgt, cpu_addr, dma_addr, size); -} - -#define dma_get_sgtable(d, t, v, h, s) dma_get_sgtable_attrs(d, t, v, h, s, 0) - -#ifndef arch_dma_alloc_attrs -#define arch_dma_alloc_attrs(dev, flag) (true) -#endif - -static inline void *dma_alloc_attrs(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag, - unsigned long attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - void *cpu_addr; - - BUG_ON(!ops); - - if (dma_alloc_from_coherent(dev, size, dma_handle, &cpu_addr)) - return cpu_addr; - - if (!arch_dma_alloc_attrs(&dev, &flag)) - return NULL; - if (!ops->alloc) - return NULL; - - cpu_addr = ops->alloc(dev, size, dma_handle, flag, attrs); - debug_dma_alloc_coherent(dev, size, *dma_handle, cpu_addr); - return cpu_addr; -} - -static inline void dma_free_attrs(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle, - unsigned long attrs) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - BUG_ON(!ops); - WARN_ON(irqs_disabled()); - - if (dma_release_from_coherent(dev, get_order(size), cpu_addr)) - return; - - if (!ops->free || !cpu_addr) - return; - - debug_dma_free_coherent(dev, size, cpu_addr, dma_handle); - ops->free(dev, size, cpu_addr, dma_handle, attrs); -} - -static inline void *dma_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag) -{ - return dma_alloc_attrs(dev, size, dma_handle, flag, 0); -} - -static inline void dma_free_coherent(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle) -{ - return dma_free_attrs(dev, size, cpu_addr, dma_handle, 0); -} - -static inline void *dma_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp) -{ - return dma_alloc_attrs(dev, size, dma_handle, gfp, - DMA_ATTR_NON_CONSISTENT); -} - -static inline void dma_free_noncoherent(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_handle) -{ - dma_free_attrs(dev, size, cpu_addr, dma_handle, - DMA_ATTR_NON_CONSISTENT); -} - -static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - debug_dma_mapping_error(dev, dma_addr); - - if (get_dma_ops(dev)->mapping_error) - return get_dma_ops(dev)->mapping_error(dev, dma_addr); - -#ifdef DMA_ERROR_CODE - return dma_addr == DMA_ERROR_CODE; -#else - return 0; -#endif -} - -#ifndef HAVE_ARCH_DMA_SUPPORTED -static inline int dma_supported(struct device *dev, u64 mask) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - if (!ops) - return 0; - if (!ops->dma_supported) - return 1; - return ops->dma_supported(dev, mask); -} -#endif - -#ifndef HAVE_ARCH_DMA_SET_MASK -static inline int dma_set_mask(struct device *dev, u64 mask) -{ - struct dma_map_ops *ops = get_dma_ops(dev); - - if (ops->set_dma_mask) - return ops->set_dma_mask(dev, mask); - - if (!dev->dma_mask || !dma_supported(dev, mask)) - return -EIO; - *dev->dma_mask = mask; - return 0; -} -#endif - -static inline u64 dma_get_mask(struct device *dev) -{ - if (dev && dev->dma_mask && *dev->dma_mask) - return *dev->dma_mask; - return DMA_BIT_MASK(32); -} - -#ifdef CONFIG_ARCH_HAS_DMA_SET_COHERENT_MASK -int dma_set_coherent_mask(struct device *dev, u64 mask); -#else -static inline int dma_set_coherent_mask(struct device *dev, u64 mask) -{ - if (!dma_supported(dev, mask)) - return -EIO; - dev->coherent_dma_mask = mask; - return 0; -} -#endif - -/* - * Set both the DMA mask and the coherent DMA mask to the same thing. - * Note that we don't check the return value from dma_set_coherent_mask() - * as the DMA API guarantees that the coherent DMA mask can be set to - * the same or smaller than the streaming DMA mask. - */ -static inline int dma_set_mask_and_coherent(struct device *dev, u64 mask) -{ - int rc = dma_set_mask(dev, mask); - if (rc == 0) - dma_set_coherent_mask(dev, mask); - return rc; -} - -/* - * Similar to the above, except it deals with the case where the device - * does not have dev->dma_mask appropriately setup. - */ -static inline int dma_coerce_mask_and_coherent(struct device *dev, u64 mask) -{ - dev->dma_mask = &dev->coherent_dma_mask; - return dma_set_mask_and_coherent(dev, mask); -} - -extern u64 dma_get_required_mask(struct device *dev); - -#ifndef arch_setup_dma_ops -static inline void arch_setup_dma_ops(struct device *dev, u64 dma_base, - u64 size, const struct iommu_ops *iommu, - bool coherent) { } -#endif - -#ifndef arch_teardown_dma_ops -static inline void arch_teardown_dma_ops(struct device *dev) { } -#endif - -static inline unsigned int dma_get_max_seg_size(struct device *dev) -{ - if (dev->dma_parms && dev->dma_parms->max_segment_size) - return dev->dma_parms->max_segment_size; - return SZ_64K; -} - -static inline unsigned int dma_set_max_seg_size(struct device *dev, - unsigned int size) -{ - if (dev->dma_parms) { - dev->dma_parms->max_segment_size = size; - return 0; - } - return -EIO; -} - -static inline unsigned long dma_get_seg_boundary(struct device *dev) -{ - if (dev->dma_parms && dev->dma_parms->segment_boundary_mask) - return dev->dma_parms->segment_boundary_mask; - return DMA_BIT_MASK(32); -} - -static inline int dma_set_seg_boundary(struct device *dev, unsigned long mask) -{ - if (dev->dma_parms) { - dev->dma_parms->segment_boundary_mask = mask; - return 0; - } - return -EIO; -} - -#ifndef dma_max_pfn -static inline unsigned long dma_max_pfn(struct device *dev) -{ - return *dev->dma_mask >> PAGE_SHIFT; -} -#endif - -static inline void *dma_zalloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t flag) -{ - void *ret = dma_alloc_coherent(dev, size, dma_handle, - flag | __GFP_ZERO); - return ret; -} - -#ifdef CONFIG_HAS_DMA -static inline int dma_get_cache_alignment(void) -{ -#ifdef ARCH_DMA_MINALIGN - return ARCH_DMA_MINALIGN; -#endif - return 1; -} -#endif - -/* flags for the coherent memory api */ -#define DMA_MEMORY_MAP 0x01 -#define DMA_MEMORY_IO 0x02 -#define DMA_MEMORY_INCLUDES_CHILDREN 0x04 -#define DMA_MEMORY_EXCLUSIVE 0x08 - -#ifdef CONFIG_HAVE_GENERIC_DMA_COHERENT -int dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, - dma_addr_t device_addr, size_t size, int flags); -void dma_release_declared_memory(struct device *dev); -void *dma_mark_declared_memory_occupied(struct device *dev, - dma_addr_t device_addr, size_t size); -#else -static inline int -dma_declare_coherent_memory(struct device *dev, phys_addr_t phys_addr, - dma_addr_t device_addr, size_t size, int flags) -{ - return 0; -} - -static inline void -dma_release_declared_memory(struct device *dev) -{ -} - -static inline void * -dma_mark_declared_memory_occupied(struct device *dev, - dma_addr_t device_addr, size_t size) -{ - return ERR_PTR(-EBUSY); -} -#endif /* CONFIG_HAVE_GENERIC_DMA_COHERENT */ - -/* - * Managed DMA API - */ -extern void *dmam_alloc_coherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp); -extern void dmam_free_coherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle); -extern void *dmam_alloc_noncoherent(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp); -extern void dmam_free_noncoherent(struct device *dev, size_t size, void *vaddr, - dma_addr_t dma_handle); -#ifdef CONFIG_HAVE_GENERIC_DMA_COHERENT -extern int dmam_declare_coherent_memory(struct device *dev, - phys_addr_t phys_addr, - dma_addr_t device_addr, size_t size, - int flags); -extern void dmam_release_declared_memory(struct device *dev); -#else /* CONFIG_HAVE_GENERIC_DMA_COHERENT */ -static inline int dmam_declare_coherent_memory(struct device *dev, - phys_addr_t phys_addr, dma_addr_t device_addr, - size_t size, gfp_t gfp) -{ - return 0; -} - -static inline void dmam_release_declared_memory(struct device *dev) -{ -} -#endif /* CONFIG_HAVE_GENERIC_DMA_COHERENT */ - -static inline void *dma_alloc_wc(struct device *dev, size_t size, - dma_addr_t *dma_addr, gfp_t gfp) -{ - return dma_alloc_attrs(dev, size, dma_addr, gfp, - DMA_ATTR_WRITE_COMBINE); -} -#ifndef dma_alloc_writecombine -#define dma_alloc_writecombine dma_alloc_wc -#endif - -static inline void dma_free_wc(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_addr) -{ - return dma_free_attrs(dev, size, cpu_addr, dma_addr, - DMA_ATTR_WRITE_COMBINE); -} -#ifndef dma_free_writecombine -#define dma_free_writecombine dma_free_wc -#endif - -static inline int dma_mmap_wc(struct device *dev, - struct vm_area_struct *vma, - void *cpu_addr, dma_addr_t dma_addr, - size_t size) -{ - return dma_mmap_attrs(dev, vma, cpu_addr, dma_addr, size, - DMA_ATTR_WRITE_COMBINE); -} -#ifndef dma_mmap_writecombine -#define dma_mmap_writecombine dma_mmap_wc -#endif - -#if defined(CONFIG_NEED_DMA_MAP_STATE) || defined(CONFIG_DMA_API_DEBUG) -#define DEFINE_DMA_UNMAP_ADDR(ADDR_NAME) dma_addr_t ADDR_NAME -#define DEFINE_DMA_UNMAP_LEN(LEN_NAME) __u32 LEN_NAME -#define dma_unmap_addr(PTR, ADDR_NAME) ((PTR)->ADDR_NAME) -#define dma_unmap_addr_set(PTR, ADDR_NAME, VAL) (((PTR)->ADDR_NAME) = (VAL)) -#define dma_unmap_len(PTR, LEN_NAME) ((PTR)->LEN_NAME) -#define dma_unmap_len_set(PTR, LEN_NAME, VAL) (((PTR)->LEN_NAME) = (VAL)) -#else -#define DEFINE_DMA_UNMAP_ADDR(ADDR_NAME) -#define DEFINE_DMA_UNMAP_LEN(LEN_NAME) -#define dma_unmap_addr(PTR, ADDR_NAME) (0) -#define dma_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0) -#define dma_unmap_len(PTR, LEN_NAME) (0) -#define dma_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0) -#endif - -#endif diff --git a/src/linux/include/linux/dmaengine.h b/src/linux/include/linux/dmaengine.h deleted file mode 100644 index cc535a4..0000000 --- a/src/linux/include/linux/dmaengine.h +++ /dev/null @@ -1,1418 +0,0 @@ -/* - * Copyright(c) 2004 - 2006 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * The full GNU General Public License is included in this distribution in the - * file called COPYING. - */ -#ifndef LINUX_DMAENGINE_H -#define LINUX_DMAENGINE_H - -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * typedef dma_cookie_t - an opaque DMA cookie - * - * if dma_cookie_t is >0 it's a DMA request cookie, <0 it's an error code - */ -typedef s32 dma_cookie_t; -#define DMA_MIN_COOKIE 1 - -static inline int dma_submit_error(dma_cookie_t cookie) -{ - return cookie < 0 ? cookie : 0; -} - -/** - * enum dma_status - DMA transaction status - * @DMA_COMPLETE: transaction completed - * @DMA_IN_PROGRESS: transaction not yet processed - * @DMA_PAUSED: transaction is paused - * @DMA_ERROR: transaction failed - */ -enum dma_status { - DMA_COMPLETE, - DMA_IN_PROGRESS, - DMA_PAUSED, - DMA_ERROR, -}; - -/** - * enum dma_transaction_type - DMA transaction types/indexes - * - * Note: The DMA_ASYNC_TX capability is not to be set by drivers. It is - * automatically set as dma devices are registered. - */ -enum dma_transaction_type { - DMA_MEMCPY, - DMA_XOR, - DMA_PQ, - DMA_XOR_VAL, - DMA_PQ_VAL, - DMA_MEMSET, - DMA_MEMSET_SG, - DMA_INTERRUPT, - DMA_SG, - DMA_PRIVATE, - DMA_ASYNC_TX, - DMA_SLAVE, - DMA_CYCLIC, - DMA_INTERLEAVE, -/* last transaction type for creation of the capabilities mask */ - DMA_TX_TYPE_END, -}; - -/** - * enum dma_transfer_direction - dma transfer mode and direction indicator - * @DMA_MEM_TO_MEM: Async/Memcpy mode - * @DMA_MEM_TO_DEV: Slave mode & From Memory to Device - * @DMA_DEV_TO_MEM: Slave mode & From Device to Memory - * @DMA_DEV_TO_DEV: Slave mode & From Device to Device - */ -enum dma_transfer_direction { - DMA_MEM_TO_MEM, - DMA_MEM_TO_DEV, - DMA_DEV_TO_MEM, - DMA_DEV_TO_DEV, - DMA_TRANS_NONE, -}; - -/** - * Interleaved Transfer Request - * ---------------------------- - * A chunk is collection of contiguous bytes to be transfered. - * The gap(in bytes) between two chunks is called inter-chunk-gap(ICG). - * ICGs may or maynot change between chunks. - * A FRAME is the smallest series of contiguous {chunk,icg} pairs, - * that when repeated an integral number of times, specifies the transfer. - * A transfer template is specification of a Frame, the number of times - * it is to be repeated and other per-transfer attributes. - * - * Practically, a client driver would have ready a template for each - * type of transfer it is going to need during its lifetime and - * set only 'src_start' and 'dst_start' before submitting the requests. - * - * - * | Frame-1 | Frame-2 | ~ | Frame-'numf' | - * |====....==.===...=...|====....==.===...=...| ~ |====....==.===...=...| - * - * == Chunk size - * ... ICG - */ - -/** - * struct data_chunk - Element of scatter-gather list that makes a frame. - * @size: Number of bytes to read from source. - * size_dst := fn(op, size_src), so doesn't mean much for destination. - * @icg: Number of bytes to jump after last src/dst address of this - * chunk and before first src/dst address for next chunk. - * Ignored for dst(assumed 0), if dst_inc is true and dst_sgl is false. - * Ignored for src(assumed 0), if src_inc is true and src_sgl is false. - * @dst_icg: Number of bytes to jump after last dst address of this - * chunk and before the first dst address for next chunk. - * Ignored if dst_inc is true and dst_sgl is false. - * @src_icg: Number of bytes to jump after last src address of this - * chunk and before the first src address for next chunk. - * Ignored if src_inc is true and src_sgl is false. - */ -struct data_chunk { - size_t size; - size_t icg; - size_t dst_icg; - size_t src_icg; -}; - -/** - * struct dma_interleaved_template - Template to convey DMAC the transfer pattern - * and attributes. - * @src_start: Bus address of source for the first chunk. - * @dst_start: Bus address of destination for the first chunk. - * @dir: Specifies the type of Source and Destination. - * @src_inc: If the source address increments after reading from it. - * @dst_inc: If the destination address increments after writing to it. - * @src_sgl: If the 'icg' of sgl[] applies to Source (scattered read). - * Otherwise, source is read contiguously (icg ignored). - * Ignored if src_inc is false. - * @dst_sgl: If the 'icg' of sgl[] applies to Destination (scattered write). - * Otherwise, destination is filled contiguously (icg ignored). - * Ignored if dst_inc is false. - * @numf: Number of frames in this template. - * @frame_size: Number of chunks in a frame i.e, size of sgl[]. - * @sgl: Array of {chunk,icg} pairs that make up a frame. - */ -struct dma_interleaved_template { - dma_addr_t src_start; - dma_addr_t dst_start; - enum dma_transfer_direction dir; - bool src_inc; - bool dst_inc; - bool src_sgl; - bool dst_sgl; - size_t numf; - size_t frame_size; - struct data_chunk sgl[0]; -}; - -/** - * enum dma_ctrl_flags - DMA flags to augment operation preparation, - * control completion, and communicate status. - * @DMA_PREP_INTERRUPT - trigger an interrupt (callback) upon completion of - * this transaction - * @DMA_CTRL_ACK - if clear, the descriptor cannot be reused until the client - * acknowledges receipt, i.e. has has a chance to establish any dependency - * chains - * @DMA_PREP_PQ_DISABLE_P - prevent generation of P while generating Q - * @DMA_PREP_PQ_DISABLE_Q - prevent generation of Q while generating P - * @DMA_PREP_CONTINUE - indicate to a driver that it is reusing buffers as - * sources that were the result of a previous operation, in the case of a PQ - * operation it continues the calculation with new sources - * @DMA_PREP_FENCE - tell the driver that subsequent operations depend - * on the result of this operation - * @DMA_CTRL_REUSE: client can reuse the descriptor and submit again till - * cleared or freed - */ -enum dma_ctrl_flags { - DMA_PREP_INTERRUPT = (1 << 0), - DMA_CTRL_ACK = (1 << 1), - DMA_PREP_PQ_DISABLE_P = (1 << 2), - DMA_PREP_PQ_DISABLE_Q = (1 << 3), - DMA_PREP_CONTINUE = (1 << 4), - DMA_PREP_FENCE = (1 << 5), - DMA_CTRL_REUSE = (1 << 6), -}; - -/** - * enum sum_check_bits - bit position of pq_check_flags - */ -enum sum_check_bits { - SUM_CHECK_P = 0, - SUM_CHECK_Q = 1, -}; - -/** - * enum pq_check_flags - result of async_{xor,pq}_zero_sum operations - * @SUM_CHECK_P_RESULT - 1 if xor zero sum error, 0 otherwise - * @SUM_CHECK_Q_RESULT - 1 if reed-solomon zero sum error, 0 otherwise - */ -enum sum_check_flags { - SUM_CHECK_P_RESULT = (1 << SUM_CHECK_P), - SUM_CHECK_Q_RESULT = (1 << SUM_CHECK_Q), -}; - - -/** - * dma_cap_mask_t - capabilities bitmap modeled after cpumask_t. - * See linux/cpumask.h - */ -typedef struct { DECLARE_BITMAP(bits, DMA_TX_TYPE_END); } dma_cap_mask_t; - -/** - * struct dma_chan_percpu - the per-CPU part of struct dma_chan - * @memcpy_count: transaction counter - * @bytes_transferred: byte counter - */ - -struct dma_chan_percpu { - /* stats */ - unsigned long memcpy_count; - unsigned long bytes_transferred; -}; - -/** - * struct dma_router - DMA router structure - * @dev: pointer to the DMA router device - * @route_free: function to be called when the route can be disconnected - */ -struct dma_router { - struct device *dev; - void (*route_free)(struct device *dev, void *route_data); -}; - -/** - * struct dma_chan - devices supply DMA channels, clients use them - * @device: ptr to the dma device who supplies this channel, always !%NULL - * @cookie: last cookie value returned to client - * @completed_cookie: last completed cookie for this channel - * @chan_id: channel ID for sysfs - * @dev: class device for sysfs - * @device_node: used to add this to the device chan list - * @local: per-cpu pointer to a struct dma_chan_percpu - * @client_count: how many clients are using this channel - * @table_count: number of appearances in the mem-to-mem allocation table - * @router: pointer to the DMA router structure - * @route_data: channel specific data for the router - * @private: private data for certain client-channel associations - */ -struct dma_chan { - struct dma_device *device; - dma_cookie_t cookie; - dma_cookie_t completed_cookie; - - /* sysfs */ - int chan_id; - struct dma_chan_dev *dev; - - struct list_head device_node; - struct dma_chan_percpu __percpu *local; - int client_count; - int table_count; - - /* DMA router */ - struct dma_router *router; - void *route_data; - - void *private; -}; - -/** - * struct dma_chan_dev - relate sysfs device node to backing channel device - * @chan: driver channel device - * @device: sysfs device - * @dev_id: parent dma_device dev_id - * @idr_ref: reference count to gate release of dma_device dev_id - */ -struct dma_chan_dev { - struct dma_chan *chan; - struct device device; - int dev_id; - atomic_t *idr_ref; -}; - -/** - * enum dma_slave_buswidth - defines bus width of the DMA slave - * device, source or target buses - */ -enum dma_slave_buswidth { - DMA_SLAVE_BUSWIDTH_UNDEFINED = 0, - DMA_SLAVE_BUSWIDTH_1_BYTE = 1, - DMA_SLAVE_BUSWIDTH_2_BYTES = 2, - DMA_SLAVE_BUSWIDTH_3_BYTES = 3, - DMA_SLAVE_BUSWIDTH_4_BYTES = 4, - DMA_SLAVE_BUSWIDTH_8_BYTES = 8, - DMA_SLAVE_BUSWIDTH_16_BYTES = 16, - DMA_SLAVE_BUSWIDTH_32_BYTES = 32, - DMA_SLAVE_BUSWIDTH_64_BYTES = 64, -}; - -/** - * struct dma_slave_config - dma slave channel runtime config - * @direction: whether the data shall go in or out on this slave - * channel, right now. DMA_MEM_TO_DEV and DMA_DEV_TO_MEM are - * legal values. DEPRECATED, drivers should use the direction argument - * to the device_prep_slave_sg and device_prep_dma_cyclic functions or - * the dir field in the dma_interleaved_template structure. - * @src_addr: this is the physical address where DMA slave data - * should be read (RX), if the source is memory this argument is - * ignored. - * @dst_addr: this is the physical address where DMA slave data - * should be written (TX), if the source is memory this argument - * is ignored. - * @src_addr_width: this is the width in bytes of the source (RX) - * register where DMA data shall be read. If the source - * is memory this may be ignored depending on architecture. - * Legal values: 1, 2, 4, 8. - * @dst_addr_width: same as src_addr_width but for destination - * target (TX) mutatis mutandis. - * @src_maxburst: the maximum number of words (note: words, as in - * units of the src_addr_width member, not bytes) that can be sent - * in one burst to the device. Typically something like half the - * FIFO depth on I/O peripherals so you don't overflow it. This - * may or may not be applicable on memory sources. - * @dst_maxburst: same as src_maxburst but for destination target - * mutatis mutandis. - * @device_fc: Flow Controller Settings. Only valid for slave channels. Fill - * with 'true' if peripheral should be flow controller. Direction will be - * selected at Runtime. - * @slave_id: Slave requester id. Only valid for slave channels. The dma - * slave peripheral will have unique id as dma requester which need to be - * pass as slave config. - * - * This struct is passed in as configuration data to a DMA engine - * in order to set up a certain channel for DMA transport at runtime. - * The DMA device/engine has to provide support for an additional - * callback in the dma_device structure, device_config and this struct - * will then be passed in as an argument to the function. - * - * The rationale for adding configuration information to this struct is as - * follows: if it is likely that more than one DMA slave controllers in - * the world will support the configuration option, then make it generic. - * If not: if it is fixed so that it be sent in static from the platform - * data, then prefer to do that. - */ -struct dma_slave_config { - enum dma_transfer_direction direction; - phys_addr_t src_addr; - phys_addr_t dst_addr; - enum dma_slave_buswidth src_addr_width; - enum dma_slave_buswidth dst_addr_width; - u32 src_maxburst; - u32 dst_maxburst; - bool device_fc; - unsigned int slave_id; -}; - -/** - * enum dma_residue_granularity - Granularity of the reported transfer residue - * @DMA_RESIDUE_GRANULARITY_DESCRIPTOR: Residue reporting is not support. The - * DMA channel is only able to tell whether a descriptor has been completed or - * not, which means residue reporting is not supported by this channel. The - * residue field of the dma_tx_state field will always be 0. - * @DMA_RESIDUE_GRANULARITY_SEGMENT: Residue is updated after each successfully - * completed segment of the transfer (For cyclic transfers this is after each - * period). This is typically implemented by having the hardware generate an - * interrupt after each transferred segment and then the drivers updates the - * outstanding residue by the size of the segment. Another possibility is if - * the hardware supports scatter-gather and the segment descriptor has a field - * which gets set after the segment has been completed. The driver then counts - * the number of segments without the flag set to compute the residue. - * @DMA_RESIDUE_GRANULARITY_BURST: Residue is updated after each transferred - * burst. This is typically only supported if the hardware has a progress - * register of some sort (E.g. a register with the current read/write address - * or a register with the amount of bursts/beats/bytes that have been - * transferred or still need to be transferred). - */ -enum dma_residue_granularity { - DMA_RESIDUE_GRANULARITY_DESCRIPTOR = 0, - DMA_RESIDUE_GRANULARITY_SEGMENT = 1, - DMA_RESIDUE_GRANULARITY_BURST = 2, -}; - -/* struct dma_slave_caps - expose capabilities of a slave channel only - * - * @src_addr_widths: bit mask of src addr widths the channel supports - * @dst_addr_widths: bit mask of dstn addr widths the channel supports - * @directions: bit mask of slave direction the channel supported - * since the enum dma_transfer_direction is not defined as bits for each - * type of direction, the dma controller should fill (1 << ) and same - * should be checked by controller as well - * @max_burst: max burst capability per-transfer - * @cmd_pause: true, if pause and thereby resume is supported - * @cmd_terminate: true, if terminate cmd is supported - * @residue_granularity: granularity of the reported transfer residue - * @descriptor_reuse: if a descriptor can be reused by client and - * resubmitted multiple times - */ -struct dma_slave_caps { - u32 src_addr_widths; - u32 dst_addr_widths; - u32 directions; - u32 max_burst; - bool cmd_pause; - bool cmd_terminate; - enum dma_residue_granularity residue_granularity; - bool descriptor_reuse; -}; - -static inline const char *dma_chan_name(struct dma_chan *chan) -{ - return dev_name(&chan->dev->device); -} - -void dma_chan_cleanup(struct kref *kref); - -/** - * typedef dma_filter_fn - callback filter for dma_request_channel - * @chan: channel to be reviewed - * @filter_param: opaque parameter passed through dma_request_channel - * - * When this optional parameter is specified in a call to dma_request_channel a - * suitable channel is passed to this routine for further dispositioning before - * being returned. Where 'suitable' indicates a non-busy channel that - * satisfies the given capability mask. It returns 'true' to indicate that the - * channel is suitable. - */ -typedef bool (*dma_filter_fn)(struct dma_chan *chan, void *filter_param); - -typedef void (*dma_async_tx_callback)(void *dma_async_param); - -enum dmaengine_tx_result { - DMA_TRANS_NOERROR = 0, /* SUCCESS */ - DMA_TRANS_READ_FAILED, /* Source DMA read failed */ - DMA_TRANS_WRITE_FAILED, /* Destination DMA write failed */ - DMA_TRANS_ABORTED, /* Op never submitted / aborted */ -}; - -struct dmaengine_result { - enum dmaengine_tx_result result; - u32 residue; -}; - -typedef void (*dma_async_tx_callback_result)(void *dma_async_param, - const struct dmaengine_result *result); - -struct dmaengine_unmap_data { - u8 map_cnt; - u8 to_cnt; - u8 from_cnt; - u8 bidi_cnt; - struct device *dev; - struct kref kref; - size_t len; - dma_addr_t addr[0]; -}; - -/** - * struct dma_async_tx_descriptor - async transaction descriptor - * ---dma generic offload fields--- - * @cookie: tracking cookie for this transaction, set to -EBUSY if - * this tx is sitting on a dependency list - * @flags: flags to augment operation preparation, control completion, and - * communicate status - * @phys: physical address of the descriptor - * @chan: target channel for this operation - * @tx_submit: accept the descriptor, assign ordered cookie and mark the - * descriptor pending. To be pushed on .issue_pending() call - * @callback: routine to call after this operation is complete - * @callback_param: general parameter to pass to the callback routine - * ---async_tx api specific fields--- - * @next: at completion submit this descriptor - * @parent: pointer to the next level up in the dependency chain - * @lock: protect the parent and next pointers - */ -struct dma_async_tx_descriptor { - dma_cookie_t cookie; - enum dma_ctrl_flags flags; /* not a 'long' to pack with cookie */ - dma_addr_t phys; - struct dma_chan *chan; - dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx); - int (*desc_free)(struct dma_async_tx_descriptor *tx); - dma_async_tx_callback callback; - dma_async_tx_callback_result callback_result; - void *callback_param; - struct dmaengine_unmap_data *unmap; -#ifdef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH - struct dma_async_tx_descriptor *next; - struct dma_async_tx_descriptor *parent; - spinlock_t lock; -#endif -}; - -#ifdef CONFIG_DMA_ENGINE -static inline void dma_set_unmap(struct dma_async_tx_descriptor *tx, - struct dmaengine_unmap_data *unmap) -{ - kref_get(&unmap->kref); - tx->unmap = unmap; -} - -struct dmaengine_unmap_data * -dmaengine_get_unmap_data(struct device *dev, int nr, gfp_t flags); -void dmaengine_unmap_put(struct dmaengine_unmap_data *unmap); -#else -static inline void dma_set_unmap(struct dma_async_tx_descriptor *tx, - struct dmaengine_unmap_data *unmap) -{ -} -static inline struct dmaengine_unmap_data * -dmaengine_get_unmap_data(struct device *dev, int nr, gfp_t flags) -{ - return NULL; -} -static inline void dmaengine_unmap_put(struct dmaengine_unmap_data *unmap) -{ -} -#endif - -static inline void dma_descriptor_unmap(struct dma_async_tx_descriptor *tx) -{ - if (tx->unmap) { - dmaengine_unmap_put(tx->unmap); - tx->unmap = NULL; - } -} - -#ifndef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH -static inline void txd_lock(struct dma_async_tx_descriptor *txd) -{ -} -static inline void txd_unlock(struct dma_async_tx_descriptor *txd) -{ -} -static inline void txd_chain(struct dma_async_tx_descriptor *txd, struct dma_async_tx_descriptor *next) -{ - BUG(); -} -static inline void txd_clear_parent(struct dma_async_tx_descriptor *txd) -{ -} -static inline void txd_clear_next(struct dma_async_tx_descriptor *txd) -{ -} -static inline struct dma_async_tx_descriptor *txd_next(struct dma_async_tx_descriptor *txd) -{ - return NULL; -} -static inline struct dma_async_tx_descriptor *txd_parent(struct dma_async_tx_descriptor *txd) -{ - return NULL; -} - -#else -static inline void txd_lock(struct dma_async_tx_descriptor *txd) -{ - spin_lock_bh(&txd->lock); -} -static inline void txd_unlock(struct dma_async_tx_descriptor *txd) -{ - spin_unlock_bh(&txd->lock); -} -static inline void txd_chain(struct dma_async_tx_descriptor *txd, struct dma_async_tx_descriptor *next) -{ - txd->next = next; - next->parent = txd; -} -static inline void txd_clear_parent(struct dma_async_tx_descriptor *txd) -{ - txd->parent = NULL; -} -static inline void txd_clear_next(struct dma_async_tx_descriptor *txd) -{ - txd->next = NULL; -} -static inline struct dma_async_tx_descriptor *txd_parent(struct dma_async_tx_descriptor *txd) -{ - return txd->parent; -} -static inline struct dma_async_tx_descriptor *txd_next(struct dma_async_tx_descriptor *txd) -{ - return txd->next; -} -#endif - -/** - * struct dma_tx_state - filled in to report the status of - * a transfer. - * @last: last completed DMA cookie - * @used: last issued DMA cookie (i.e. the one in progress) - * @residue: the remaining number of bytes left to transmit - * on the selected transfer for states DMA_IN_PROGRESS and - * DMA_PAUSED if this is implemented in the driver, else 0 - */ -struct dma_tx_state { - dma_cookie_t last; - dma_cookie_t used; - u32 residue; -}; - -/** - * enum dmaengine_alignment - defines alignment of the DMA async tx - * buffers - */ -enum dmaengine_alignment { - DMAENGINE_ALIGN_1_BYTE = 0, - DMAENGINE_ALIGN_2_BYTES = 1, - DMAENGINE_ALIGN_4_BYTES = 2, - DMAENGINE_ALIGN_8_BYTES = 3, - DMAENGINE_ALIGN_16_BYTES = 4, - DMAENGINE_ALIGN_32_BYTES = 5, - DMAENGINE_ALIGN_64_BYTES = 6, -}; - -/** - * struct dma_slave_map - associates slave device and it's slave channel with - * parameter to be used by a filter function - * @devname: name of the device - * @slave: slave channel name - * @param: opaque parameter to pass to struct dma_filter.fn - */ -struct dma_slave_map { - const char *devname; - const char *slave; - void *param; -}; - -/** - * struct dma_filter - information for slave device/channel to filter_fn/param - * mapping - * @fn: filter function callback - * @mapcnt: number of slave device/channel in the map - * @map: array of channel to filter mapping data - */ -struct dma_filter { - dma_filter_fn fn; - int mapcnt; - const struct dma_slave_map *map; -}; - -/** - * struct dma_device - info on the entity supplying DMA services - * @chancnt: how many DMA channels are supported - * @privatecnt: how many DMA channels are requested by dma_request_channel - * @channels: the list of struct dma_chan - * @global_node: list_head for global dma_device_list - * @filter: information for device/slave to filter function/param mapping - * @cap_mask: one or more dma_capability flags - * @max_xor: maximum number of xor sources, 0 if no capability - * @max_pq: maximum number of PQ sources and PQ-continue capability - * @copy_align: alignment shift for memcpy operations - * @xor_align: alignment shift for xor operations - * @pq_align: alignment shift for pq operations - * @fill_align: alignment shift for memset operations - * @dev_id: unique device ID - * @dev: struct device reference for dma mapping api - * @src_addr_widths: bit mask of src addr widths the device supports - * @dst_addr_widths: bit mask of dst addr widths the device supports - * @directions: bit mask of slave direction the device supports since - * the enum dma_transfer_direction is not defined as bits for - * each type of direction, the dma controller should fill (1 << - * ) and same should be checked by controller as well - * @max_burst: max burst capability per-transfer - * @residue_granularity: granularity of the transfer residue reported - * by tx_status - * @device_alloc_chan_resources: allocate resources and return the - * number of allocated descriptors - * @device_free_chan_resources: release DMA channel's resources - * @device_prep_dma_memcpy: prepares a memcpy operation - * @device_prep_dma_xor: prepares a xor operation - * @device_prep_dma_xor_val: prepares a xor validation operation - * @device_prep_dma_pq: prepares a pq operation - * @device_prep_dma_pq_val: prepares a pqzero_sum operation - * @device_prep_dma_memset: prepares a memset operation - * @device_prep_dma_memset_sg: prepares a memset operation over a scatter list - * @device_prep_dma_interrupt: prepares an end of chain interrupt operation - * @device_prep_slave_sg: prepares a slave dma operation - * @device_prep_dma_cyclic: prepare a cyclic dma operation suitable for audio. - * The function takes a buffer of size buf_len. The callback function will - * be called after period_len bytes have been transferred. - * @device_prep_interleaved_dma: Transfer expression in a generic way. - * @device_prep_dma_imm_data: DMA's 8 byte immediate data to the dst address - * @device_config: Pushes a new configuration to a channel, return 0 or an error - * code - * @device_pause: Pauses any transfer happening on a channel. Returns - * 0 or an error code - * @device_resume: Resumes any transfer on a channel previously - * paused. Returns 0 or an error code - * @device_terminate_all: Aborts all transfers on a channel. Returns 0 - * or an error code - * @device_synchronize: Synchronizes the termination of a transfers to the - * current context. - * @device_tx_status: poll for transaction completion, the optional - * txstate parameter can be supplied with a pointer to get a - * struct with auxiliary transfer status information, otherwise the call - * will just return a simple status code - * @device_issue_pending: push pending transactions to hardware - * @descriptor_reuse: a submitted transfer can be resubmitted after completion - */ -struct dma_device { - - unsigned int chancnt; - unsigned int privatecnt; - struct list_head channels; - struct list_head global_node; - struct dma_filter filter; - dma_cap_mask_t cap_mask; - unsigned short max_xor; - unsigned short max_pq; - enum dmaengine_alignment copy_align; - enum dmaengine_alignment xor_align; - enum dmaengine_alignment pq_align; - enum dmaengine_alignment fill_align; - #define DMA_HAS_PQ_CONTINUE (1 << 15) - - int dev_id; - struct device *dev; - - u32 src_addr_widths; - u32 dst_addr_widths; - u32 directions; - u32 max_burst; - bool descriptor_reuse; - enum dma_residue_granularity residue_granularity; - - int (*device_alloc_chan_resources)(struct dma_chan *chan); - void (*device_free_chan_resources)(struct dma_chan *chan); - - struct dma_async_tx_descriptor *(*device_prep_dma_memcpy)( - struct dma_chan *chan, dma_addr_t dst, dma_addr_t src, - size_t len, unsigned long flags); - struct dma_async_tx_descriptor *(*device_prep_dma_xor)( - struct dma_chan *chan, dma_addr_t dst, dma_addr_t *src, - unsigned int src_cnt, size_t len, unsigned long flags); - struct dma_async_tx_descriptor *(*device_prep_dma_xor_val)( - struct dma_chan *chan, dma_addr_t *src, unsigned int src_cnt, - size_t len, enum sum_check_flags *result, unsigned long flags); - struct dma_async_tx_descriptor *(*device_prep_dma_pq)( - struct dma_chan *chan, dma_addr_t *dst, dma_addr_t *src, - unsigned int src_cnt, const unsigned char *scf, - size_t len, unsigned long flags); - struct dma_async_tx_descriptor *(*device_prep_dma_pq_val)( - struct dma_chan *chan, dma_addr_t *pq, dma_addr_t *src, - unsigned int src_cnt, const unsigned char *scf, size_t len, - enum sum_check_flags *pqres, unsigned long flags); - struct dma_async_tx_descriptor *(*device_prep_dma_memset)( - struct dma_chan *chan, dma_addr_t dest, int value, size_t len, - unsigned long flags); - struct dma_async_tx_descriptor *(*device_prep_dma_memset_sg)( - struct dma_chan *chan, struct scatterlist *sg, - unsigned int nents, int value, unsigned long flags); - struct dma_async_tx_descriptor *(*device_prep_dma_interrupt)( - struct dma_chan *chan, unsigned long flags); - struct dma_async_tx_descriptor *(*device_prep_dma_sg)( - struct dma_chan *chan, - struct scatterlist *dst_sg, unsigned int dst_nents, - struct scatterlist *src_sg, unsigned int src_nents, - unsigned long flags); - - struct dma_async_tx_descriptor *(*device_prep_slave_sg)( - struct dma_chan *chan, struct scatterlist *sgl, - unsigned int sg_len, enum dma_transfer_direction direction, - unsigned long flags, void *context); - struct dma_async_tx_descriptor *(*device_prep_dma_cyclic)( - struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, - size_t period_len, enum dma_transfer_direction direction, - unsigned long flags); - struct dma_async_tx_descriptor *(*device_prep_interleaved_dma)( - struct dma_chan *chan, struct dma_interleaved_template *xt, - unsigned long flags); - struct dma_async_tx_descriptor *(*device_prep_dma_imm_data)( - struct dma_chan *chan, dma_addr_t dst, u64 data, - unsigned long flags); - - int (*device_config)(struct dma_chan *chan, - struct dma_slave_config *config); - int (*device_pause)(struct dma_chan *chan); - int (*device_resume)(struct dma_chan *chan); - int (*device_terminate_all)(struct dma_chan *chan); - void (*device_synchronize)(struct dma_chan *chan); - - enum dma_status (*device_tx_status)(struct dma_chan *chan, - dma_cookie_t cookie, - struct dma_tx_state *txstate); - void (*device_issue_pending)(struct dma_chan *chan); -}; - -static inline int dmaengine_slave_config(struct dma_chan *chan, - struct dma_slave_config *config) -{ - if (chan->device->device_config) - return chan->device->device_config(chan, config); - - return -ENOSYS; -} - -static inline bool is_slave_direction(enum dma_transfer_direction direction) -{ - return (direction == DMA_MEM_TO_DEV) || (direction == DMA_DEV_TO_MEM); -} - -static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_single( - struct dma_chan *chan, dma_addr_t buf, size_t len, - enum dma_transfer_direction dir, unsigned long flags) -{ - struct scatterlist sg; - sg_init_table(&sg, 1); - sg_dma_address(&sg) = buf; - sg_dma_len(&sg) = len; - - if (!chan || !chan->device || !chan->device->device_prep_slave_sg) - return NULL; - - return chan->device->device_prep_slave_sg(chan, &sg, 1, - dir, flags, NULL); -} - -static inline struct dma_async_tx_descriptor *dmaengine_prep_slave_sg( - struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, - enum dma_transfer_direction dir, unsigned long flags) -{ - if (!chan || !chan->device || !chan->device->device_prep_slave_sg) - return NULL; - - return chan->device->device_prep_slave_sg(chan, sgl, sg_len, - dir, flags, NULL); -} - -#ifdef CONFIG_RAPIDIO_DMA_ENGINE -struct rio_dma_ext; -static inline struct dma_async_tx_descriptor *dmaengine_prep_rio_sg( - struct dma_chan *chan, struct scatterlist *sgl, unsigned int sg_len, - enum dma_transfer_direction dir, unsigned long flags, - struct rio_dma_ext *rio_ext) -{ - if (!chan || !chan->device || !chan->device->device_prep_slave_sg) - return NULL; - - return chan->device->device_prep_slave_sg(chan, sgl, sg_len, - dir, flags, rio_ext); -} -#endif - -static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic( - struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, - size_t period_len, enum dma_transfer_direction dir, - unsigned long flags) -{ - if (!chan || !chan->device || !chan->device->device_prep_dma_cyclic) - return NULL; - - return chan->device->device_prep_dma_cyclic(chan, buf_addr, buf_len, - period_len, dir, flags); -} - -static inline struct dma_async_tx_descriptor *dmaengine_prep_interleaved_dma( - struct dma_chan *chan, struct dma_interleaved_template *xt, - unsigned long flags) -{ - if (!chan || !chan->device || !chan->device->device_prep_interleaved_dma) - return NULL; - - return chan->device->device_prep_interleaved_dma(chan, xt, flags); -} - -static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_memset( - struct dma_chan *chan, dma_addr_t dest, int value, size_t len, - unsigned long flags) -{ - if (!chan || !chan->device || !chan->device->device_prep_dma_memset) - return NULL; - - return chan->device->device_prep_dma_memset(chan, dest, value, - len, flags); -} - -static inline struct dma_async_tx_descriptor *dmaengine_prep_dma_sg( - struct dma_chan *chan, - struct scatterlist *dst_sg, unsigned int dst_nents, - struct scatterlist *src_sg, unsigned int src_nents, - unsigned long flags) -{ - if (!chan || !chan->device || !chan->device->device_prep_dma_sg) - return NULL; - - return chan->device->device_prep_dma_sg(chan, dst_sg, dst_nents, - src_sg, src_nents, flags); -} - -/** - * dmaengine_terminate_all() - Terminate all active DMA transfers - * @chan: The channel for which to terminate the transfers - * - * This function is DEPRECATED use either dmaengine_terminate_sync() or - * dmaengine_terminate_async() instead. - */ -static inline int dmaengine_terminate_all(struct dma_chan *chan) -{ - if (chan->device->device_terminate_all) - return chan->device->device_terminate_all(chan); - - return -ENOSYS; -} - -/** - * dmaengine_terminate_async() - Terminate all active DMA transfers - * @chan: The channel for which to terminate the transfers - * - * Calling this function will terminate all active and pending descriptors - * that have previously been submitted to the channel. It is not guaranteed - * though that the transfer for the active descriptor has stopped when the - * function returns. Furthermore it is possible the complete callback of a - * submitted transfer is still running when this function returns. - * - * dmaengine_synchronize() needs to be called before it is safe to free - * any memory that is accessed by previously submitted descriptors or before - * freeing any resources accessed from within the completion callback of any - * perviously submitted descriptors. - * - * This function can be called from atomic context as well as from within a - * complete callback of a descriptor submitted on the same channel. - * - * If none of the two conditions above apply consider using - * dmaengine_terminate_sync() instead. - */ -static inline int dmaengine_terminate_async(struct dma_chan *chan) -{ - if (chan->device->device_terminate_all) - return chan->device->device_terminate_all(chan); - - return -EINVAL; -} - -/** - * dmaengine_synchronize() - Synchronize DMA channel termination - * @chan: The channel to synchronize - * - * Synchronizes to the DMA channel termination to the current context. When this - * function returns it is guaranteed that all transfers for previously issued - * descriptors have stopped and and it is safe to free the memory assoicated - * with them. Furthermore it is guaranteed that all complete callback functions - * for a previously submitted descriptor have finished running and it is safe to - * free resources accessed from within the complete callbacks. - * - * The behavior of this function is undefined if dma_async_issue_pending() has - * been called between dmaengine_terminate_async() and this function. - * - * This function must only be called from non-atomic context and must not be - * called from within a complete callback of a descriptor submitted on the same - * channel. - */ -static inline void dmaengine_synchronize(struct dma_chan *chan) -{ - might_sleep(); - - if (chan->device->device_synchronize) - chan->device->device_synchronize(chan); -} - -/** - * dmaengine_terminate_sync() - Terminate all active DMA transfers - * @chan: The channel for which to terminate the transfers - * - * Calling this function will terminate all active and pending transfers - * that have previously been submitted to the channel. It is similar to - * dmaengine_terminate_async() but guarantees that the DMA transfer has actually - * stopped and that all complete callbacks have finished running when the - * function returns. - * - * This function must only be called from non-atomic context and must not be - * called from within a complete callback of a descriptor submitted on the same - * channel. - */ -static inline int dmaengine_terminate_sync(struct dma_chan *chan) -{ - int ret; - - ret = dmaengine_terminate_async(chan); - if (ret) - return ret; - - dmaengine_synchronize(chan); - - return 0; -} - -static inline int dmaengine_pause(struct dma_chan *chan) -{ - if (chan->device->device_pause) - return chan->device->device_pause(chan); - - return -ENOSYS; -} - -static inline int dmaengine_resume(struct dma_chan *chan) -{ - if (chan->device->device_resume) - return chan->device->device_resume(chan); - - return -ENOSYS; -} - -static inline enum dma_status dmaengine_tx_status(struct dma_chan *chan, - dma_cookie_t cookie, struct dma_tx_state *state) -{ - return chan->device->device_tx_status(chan, cookie, state); -} - -static inline dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc) -{ - return desc->tx_submit(desc); -} - -static inline bool dmaengine_check_align(enum dmaengine_alignment align, - size_t off1, size_t off2, size_t len) -{ - size_t mask; - - if (!align) - return true; - mask = (1 << align) - 1; - if (mask & (off1 | off2 | len)) - return false; - return true; -} - -static inline bool is_dma_copy_aligned(struct dma_device *dev, size_t off1, - size_t off2, size_t len) -{ - return dmaengine_check_align(dev->copy_align, off1, off2, len); -} - -static inline bool is_dma_xor_aligned(struct dma_device *dev, size_t off1, - size_t off2, size_t len) -{ - return dmaengine_check_align(dev->xor_align, off1, off2, len); -} - -static inline bool is_dma_pq_aligned(struct dma_device *dev, size_t off1, - size_t off2, size_t len) -{ - return dmaengine_check_align(dev->pq_align, off1, off2, len); -} - -static inline bool is_dma_fill_aligned(struct dma_device *dev, size_t off1, - size_t off2, size_t len) -{ - return dmaengine_check_align(dev->fill_align, off1, off2, len); -} - -static inline void -dma_set_maxpq(struct dma_device *dma, int maxpq, int has_pq_continue) -{ - dma->max_pq = maxpq; - if (has_pq_continue) - dma->max_pq |= DMA_HAS_PQ_CONTINUE; -} - -static inline bool dmaf_continue(enum dma_ctrl_flags flags) -{ - return (flags & DMA_PREP_CONTINUE) == DMA_PREP_CONTINUE; -} - -static inline bool dmaf_p_disabled_continue(enum dma_ctrl_flags flags) -{ - enum dma_ctrl_flags mask = DMA_PREP_CONTINUE | DMA_PREP_PQ_DISABLE_P; - - return (flags & mask) == mask; -} - -static inline bool dma_dev_has_pq_continue(struct dma_device *dma) -{ - return (dma->max_pq & DMA_HAS_PQ_CONTINUE) == DMA_HAS_PQ_CONTINUE; -} - -static inline unsigned short dma_dev_to_maxpq(struct dma_device *dma) -{ - return dma->max_pq & ~DMA_HAS_PQ_CONTINUE; -} - -/* dma_maxpq - reduce maxpq in the face of continued operations - * @dma - dma device with PQ capability - * @flags - to check if DMA_PREP_CONTINUE and DMA_PREP_PQ_DISABLE_P are set - * - * When an engine does not support native continuation we need 3 extra - * source slots to reuse P and Q with the following coefficients: - * 1/ {00} * P : remove P from Q', but use it as a source for P' - * 2/ {01} * Q : use Q to continue Q' calculation - * 3/ {00} * Q : subtract Q from P' to cancel (2) - * - * In the case where P is disabled we only need 1 extra source: - * 1/ {01} * Q : use Q to continue Q' calculation - */ -static inline int dma_maxpq(struct dma_device *dma, enum dma_ctrl_flags flags) -{ - if (dma_dev_has_pq_continue(dma) || !dmaf_continue(flags)) - return dma_dev_to_maxpq(dma); - else if (dmaf_p_disabled_continue(flags)) - return dma_dev_to_maxpq(dma) - 1; - else if (dmaf_continue(flags)) - return dma_dev_to_maxpq(dma) - 3; - BUG(); -} - -static inline size_t dmaengine_get_icg(bool inc, bool sgl, size_t icg, - size_t dir_icg) -{ - if (inc) { - if (dir_icg) - return dir_icg; - else if (sgl) - return icg; - } - - return 0; -} - -static inline size_t dmaengine_get_dst_icg(struct dma_interleaved_template *xt, - struct data_chunk *chunk) -{ - return dmaengine_get_icg(xt->dst_inc, xt->dst_sgl, - chunk->icg, chunk->dst_icg); -} - -static inline size_t dmaengine_get_src_icg(struct dma_interleaved_template *xt, - struct data_chunk *chunk) -{ - return dmaengine_get_icg(xt->src_inc, xt->src_sgl, - chunk->icg, chunk->src_icg); -} - -/* --- public DMA engine API --- */ - -#ifdef CONFIG_DMA_ENGINE -void dmaengine_get(void); -void dmaengine_put(void); -#else -static inline void dmaengine_get(void) -{ -} -static inline void dmaengine_put(void) -{ -} -#endif - -#ifdef CONFIG_ASYNC_TX_DMA -#define async_dmaengine_get() dmaengine_get() -#define async_dmaengine_put() dmaengine_put() -#ifndef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH -#define async_dma_find_channel(type) dma_find_channel(DMA_ASYNC_TX) -#else -#define async_dma_find_channel(type) dma_find_channel(type) -#endif /* CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH */ -#else -static inline void async_dmaengine_get(void) -{ -} -static inline void async_dmaengine_put(void) -{ -} -static inline struct dma_chan * -async_dma_find_channel(enum dma_transaction_type type) -{ - return NULL; -} -#endif /* CONFIG_ASYNC_TX_DMA */ -void dma_async_tx_descriptor_init(struct dma_async_tx_descriptor *tx, - struct dma_chan *chan); - -static inline void async_tx_ack(struct dma_async_tx_descriptor *tx) -{ - tx->flags |= DMA_CTRL_ACK; -} - -static inline void async_tx_clear_ack(struct dma_async_tx_descriptor *tx) -{ - tx->flags &= ~DMA_CTRL_ACK; -} - -static inline bool async_tx_test_ack(struct dma_async_tx_descriptor *tx) -{ - return (tx->flags & DMA_CTRL_ACK) == DMA_CTRL_ACK; -} - -#define dma_cap_set(tx, mask) __dma_cap_set((tx), &(mask)) -static inline void -__dma_cap_set(enum dma_transaction_type tx_type, dma_cap_mask_t *dstp) -{ - set_bit(tx_type, dstp->bits); -} - -#define dma_cap_clear(tx, mask) __dma_cap_clear((tx), &(mask)) -static inline void -__dma_cap_clear(enum dma_transaction_type tx_type, dma_cap_mask_t *dstp) -{ - clear_bit(tx_type, dstp->bits); -} - -#define dma_cap_zero(mask) __dma_cap_zero(&(mask)) -static inline void __dma_cap_zero(dma_cap_mask_t *dstp) -{ - bitmap_zero(dstp->bits, DMA_TX_TYPE_END); -} - -#define dma_has_cap(tx, mask) __dma_has_cap((tx), &(mask)) -static inline int -__dma_has_cap(enum dma_transaction_type tx_type, dma_cap_mask_t *srcp) -{ - return test_bit(tx_type, srcp->bits); -} - -#define for_each_dma_cap_mask(cap, mask) \ - for_each_set_bit(cap, mask.bits, DMA_TX_TYPE_END) - -/** - * dma_async_issue_pending - flush pending transactions to HW - * @chan: target DMA channel - * - * This allows drivers to push copies to HW in batches, - * reducing MMIO writes where possible. - */ -static inline void dma_async_issue_pending(struct dma_chan *chan) -{ - chan->device->device_issue_pending(chan); -} - -/** - * dma_async_is_tx_complete - poll for transaction completion - * @chan: DMA channel - * @cookie: transaction identifier to check status of - * @last: returns last completed cookie, can be NULL - * @used: returns last issued cookie, can be NULL - * - * If @last and @used are passed in, upon return they reflect the driver - * internal state and can be used with dma_async_is_complete() to check - * the status of multiple cookies without re-checking hardware state. - */ -static inline enum dma_status dma_async_is_tx_complete(struct dma_chan *chan, - dma_cookie_t cookie, dma_cookie_t *last, dma_cookie_t *used) -{ - struct dma_tx_state state; - enum dma_status status; - - status = chan->device->device_tx_status(chan, cookie, &state); - if (last) - *last = state.last; - if (used) - *used = state.used; - return status; -} - -/** - * dma_async_is_complete - test a cookie against chan state - * @cookie: transaction identifier to test status of - * @last_complete: last know completed transaction - * @last_used: last cookie value handed out - * - * dma_async_is_complete() is used in dma_async_is_tx_complete() - * the test logic is separated for lightweight testing of multiple cookies - */ -static inline enum dma_status dma_async_is_complete(dma_cookie_t cookie, - dma_cookie_t last_complete, dma_cookie_t last_used) -{ - if (last_complete <= last_used) { - if ((cookie <= last_complete) || (cookie > last_used)) - return DMA_COMPLETE; - } else { - if ((cookie <= last_complete) && (cookie > last_used)) - return DMA_COMPLETE; - } - return DMA_IN_PROGRESS; -} - -static inline void -dma_set_tx_state(struct dma_tx_state *st, dma_cookie_t last, dma_cookie_t used, u32 residue) -{ - if (st) { - st->last = last; - st->used = used; - st->residue = residue; - } -} - -#ifdef CONFIG_DMA_ENGINE -struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type); -enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie); -enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx); -void dma_issue_pending_all(void); -struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, - dma_filter_fn fn, void *fn_param); -struct dma_chan *dma_request_slave_channel(struct device *dev, const char *name); - -struct dma_chan *dma_request_chan(struct device *dev, const char *name); -struct dma_chan *dma_request_chan_by_mask(const dma_cap_mask_t *mask); - -void dma_release_channel(struct dma_chan *chan); -int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps); -#else -static inline struct dma_chan *dma_find_channel(enum dma_transaction_type tx_type) -{ - return NULL; -} -static inline enum dma_status dma_sync_wait(struct dma_chan *chan, dma_cookie_t cookie) -{ - return DMA_COMPLETE; -} -static inline enum dma_status dma_wait_for_async_tx(struct dma_async_tx_descriptor *tx) -{ - return DMA_COMPLETE; -} -static inline void dma_issue_pending_all(void) -{ -} -static inline struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, - dma_filter_fn fn, void *fn_param) -{ - return NULL; -} -static inline struct dma_chan *dma_request_slave_channel(struct device *dev, - const char *name) -{ - return NULL; -} -static inline struct dma_chan *dma_request_chan(struct device *dev, - const char *name) -{ - return ERR_PTR(-ENODEV); -} -static inline struct dma_chan *dma_request_chan_by_mask( - const dma_cap_mask_t *mask) -{ - return ERR_PTR(-ENODEV); -} -static inline void dma_release_channel(struct dma_chan *chan) -{ -} -static inline int dma_get_slave_caps(struct dma_chan *chan, - struct dma_slave_caps *caps) -{ - return -ENXIO; -} -#endif - -#define dma_request_slave_channel_reason(dev, name) dma_request_chan(dev, name) - -static inline int dmaengine_desc_set_reuse(struct dma_async_tx_descriptor *tx) -{ - struct dma_slave_caps caps; - - dma_get_slave_caps(tx->chan, &caps); - - if (caps.descriptor_reuse) { - tx->flags |= DMA_CTRL_REUSE; - return 0; - } else { - return -EPERM; - } -} - -static inline void dmaengine_desc_clear_reuse(struct dma_async_tx_descriptor *tx) -{ - tx->flags &= ~DMA_CTRL_REUSE; -} - -static inline bool dmaengine_desc_test_reuse(struct dma_async_tx_descriptor *tx) -{ - return (tx->flags & DMA_CTRL_REUSE) == DMA_CTRL_REUSE; -} - -static inline int dmaengine_desc_free(struct dma_async_tx_descriptor *desc) -{ - /* this is supported for reusable desc, so check that */ - if (dmaengine_desc_test_reuse(desc)) - return desc->desc_free(desc); - else - return -EPERM; -} - -/* --- DMA device --- */ - -int dma_async_device_register(struct dma_device *device); -void dma_async_device_unregister(struct dma_device *device); -void dma_run_dependencies(struct dma_async_tx_descriptor *tx); -struct dma_chan *dma_get_slave_channel(struct dma_chan *chan); -struct dma_chan *dma_get_any_slave_channel(struct dma_device *device); -#define dma_request_channel(mask, x, y) __dma_request_channel(&(mask), x, y) -#define dma_request_slave_channel_compat(mask, x, y, dev, name) \ - __dma_request_slave_channel_compat(&(mask), x, y, dev, name) - -static inline struct dma_chan -*__dma_request_slave_channel_compat(const dma_cap_mask_t *mask, - dma_filter_fn fn, void *fn_param, - struct device *dev, const char *name) -{ - struct dma_chan *chan; - - chan = dma_request_slave_channel(dev, name); - if (chan) - return chan; - - if (!fn || !fn_param) - return NULL; - - return __dma_request_channel(mask, fn, fn_param); -} -#endif /* DMAENGINE_H */ diff --git a/src/linux/include/linux/dmapool.h b/src/linux/include/linux/dmapool.h deleted file mode 100644 index 53ba737..0000000 --- a/src/linux/include/linux/dmapool.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * include/linux/dmapool.h - * - * Allocation pools for DMAable (coherent) memory. - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#ifndef LINUX_DMAPOOL_H -#define LINUX_DMAPOOL_H - -#include -#include - -struct device; - -struct dma_pool *dma_pool_create(const char *name, struct device *dev, - size_t size, size_t align, size_t allocation); - -void dma_pool_destroy(struct dma_pool *pool); - -void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, - dma_addr_t *handle); - -static inline void *dma_pool_zalloc(struct dma_pool *pool, gfp_t mem_flags, - dma_addr_t *handle) -{ - return dma_pool_alloc(pool, mem_flags | __GFP_ZERO, handle); -} - -void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t addr); - -/* - * Managed DMA pool - */ -struct dma_pool *dmam_pool_create(const char *name, struct device *dev, - size_t size, size_t align, size_t allocation); -void dmam_pool_destroy(struct dma_pool *pool); - -#endif - diff --git a/src/linux/include/linux/dmi.h b/src/linux/include/linux/dmi.h deleted file mode 100644 index 5e9c74c..0000000 --- a/src/linux/include/linux/dmi.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef __DMI_H__ -#define __DMI_H__ - -#include -#include -#include - -/* enum dmi_field is in mod_devicetable.h */ - -enum dmi_device_type { - DMI_DEV_TYPE_ANY = 0, - DMI_DEV_TYPE_OTHER, - DMI_DEV_TYPE_UNKNOWN, - DMI_DEV_TYPE_VIDEO, - DMI_DEV_TYPE_SCSI, - DMI_DEV_TYPE_ETHERNET, - DMI_DEV_TYPE_TOKENRING, - DMI_DEV_TYPE_SOUND, - DMI_DEV_TYPE_PATA, - DMI_DEV_TYPE_SATA, - DMI_DEV_TYPE_SAS, - DMI_DEV_TYPE_IPMI = -1, - DMI_DEV_TYPE_OEM_STRING = -2, - DMI_DEV_TYPE_DEV_ONBOARD = -3, - DMI_DEV_TYPE_DEV_SLOT = -4, -}; - -enum dmi_entry_type { - DMI_ENTRY_BIOS = 0, - DMI_ENTRY_SYSTEM, - DMI_ENTRY_BASEBOARD, - DMI_ENTRY_CHASSIS, - DMI_ENTRY_PROCESSOR, - DMI_ENTRY_MEM_CONTROLLER, - DMI_ENTRY_MEM_MODULE, - DMI_ENTRY_CACHE, - DMI_ENTRY_PORT_CONNECTOR, - DMI_ENTRY_SYSTEM_SLOT, - DMI_ENTRY_ONBOARD_DEVICE, - DMI_ENTRY_OEMSTRINGS, - DMI_ENTRY_SYSCONF, - DMI_ENTRY_BIOS_LANG, - DMI_ENTRY_GROUP_ASSOC, - DMI_ENTRY_SYSTEM_EVENT_LOG, - DMI_ENTRY_PHYS_MEM_ARRAY, - DMI_ENTRY_MEM_DEVICE, - DMI_ENTRY_32_MEM_ERROR, - DMI_ENTRY_MEM_ARRAY_MAPPED_ADDR, - DMI_ENTRY_MEM_DEV_MAPPED_ADDR, - DMI_ENTRY_BUILTIN_POINTING_DEV, - DMI_ENTRY_PORTABLE_BATTERY, - DMI_ENTRY_SYSTEM_RESET, - DMI_ENTRY_HW_SECURITY, - DMI_ENTRY_SYSTEM_POWER_CONTROLS, - DMI_ENTRY_VOLTAGE_PROBE, - DMI_ENTRY_COOLING_DEV, - DMI_ENTRY_TEMP_PROBE, - DMI_ENTRY_ELECTRICAL_CURRENT_PROBE, - DMI_ENTRY_OOB_REMOTE_ACCESS, - DMI_ENTRY_BIS_ENTRY, - DMI_ENTRY_SYSTEM_BOOT, - DMI_ENTRY_MGMT_DEV, - DMI_ENTRY_MGMT_DEV_COMPONENT, - DMI_ENTRY_MGMT_DEV_THRES, - DMI_ENTRY_MEM_CHANNEL, - DMI_ENTRY_IPMI_DEV, - DMI_ENTRY_SYS_POWER_SUPPLY, - DMI_ENTRY_ADDITIONAL, - DMI_ENTRY_ONBOARD_DEV_EXT, - DMI_ENTRY_MGMT_CONTROLLER_HOST, - DMI_ENTRY_INACTIVE = 126, - DMI_ENTRY_END_OF_TABLE = 127, -}; - -struct dmi_header { - u8 type; - u8 length; - u16 handle; -} __packed; - -struct dmi_device { - struct list_head list; - int type; - const char *name; - void *device_data; /* Type specific data */ -}; - -#ifdef CONFIG_DMI - -struct dmi_dev_onboard { - struct dmi_device dev; - int instance; - int segment; - int bus; - int devfn; -}; - -extern struct kobject *dmi_kobj; -extern int dmi_check_system(const struct dmi_system_id *list); -const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list); -extern const char * dmi_get_system_info(int field); -extern const struct dmi_device * dmi_find_device(int type, const char *name, - const struct dmi_device *from); -extern void dmi_scan_machine(void); -extern void dmi_memdev_walk(void); -extern void dmi_set_dump_stack_arch_desc(void); -extern bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp); -extern int dmi_name_in_vendors(const char *str); -extern int dmi_name_in_serial(const char *str); -extern int dmi_available; -extern int dmi_walk(void (*decode)(const struct dmi_header *, void *), - void *private_data); -extern bool dmi_match(enum dmi_field f, const char *str); -extern void dmi_memdev_name(u16 handle, const char **bank, const char **device); - -#else - -static inline int dmi_check_system(const struct dmi_system_id *list) { return 0; } -static inline const char * dmi_get_system_info(int field) { return NULL; } -static inline const struct dmi_device * dmi_find_device(int type, const char *name, - const struct dmi_device *from) { return NULL; } -static inline void dmi_scan_machine(void) { return; } -static inline void dmi_memdev_walk(void) { } -static inline void dmi_set_dump_stack_arch_desc(void) { } -static inline bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp) -{ - if (yearp) - *yearp = 0; - if (monthp) - *monthp = 0; - if (dayp) - *dayp = 0; - return false; -} -static inline int dmi_name_in_vendors(const char *s) { return 0; } -static inline int dmi_name_in_serial(const char *s) { return 0; } -#define dmi_available 0 -static inline int dmi_walk(void (*decode)(const struct dmi_header *, void *), - void *private_data) { return -1; } -static inline bool dmi_match(enum dmi_field f, const char *str) - { return false; } -static inline void dmi_memdev_name(u16 handle, const char **bank, - const char **device) { } -static inline const struct dmi_system_id * - dmi_first_match(const struct dmi_system_id *list) { return NULL; } - -#endif - -#endif /* __DMI_H__ */ diff --git a/src/linux/include/linux/dnotify.h b/src/linux/include/linux/dnotify.h deleted file mode 100644 index 3290555..0000000 --- a/src/linux/include/linux/dnotify.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef _LINUX_DNOTIFY_H -#define _LINUX_DNOTIFY_H -/* - * Directory notification for Linux - * - * Copyright (C) 2000,2002 Stephen Rothwell - */ - -#include - -struct dnotify_struct { - struct dnotify_struct * dn_next; - __u32 dn_mask; - int dn_fd; - struct file * dn_filp; - fl_owner_t dn_owner; -}; - -#ifdef __KERNEL__ - - -#ifdef CONFIG_DNOTIFY - -#define DNOTIFY_ALL_EVENTS (FS_DELETE | FS_DELETE_CHILD |\ - FS_MODIFY | FS_MODIFY_CHILD |\ - FS_ACCESS | FS_ACCESS_CHILD |\ - FS_ATTRIB | FS_ATTRIB_CHILD |\ - FS_CREATE | FS_DN_RENAME |\ - FS_MOVED_FROM | FS_MOVED_TO) - -extern int dir_notify_enable; -extern void dnotify_flush(struct file *, fl_owner_t); -extern int fcntl_dirnotify(int, struct file *, unsigned long); - -#else - -static inline void dnotify_flush(struct file *filp, fl_owner_t id) -{ -} - -static inline int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) -{ - return -EINVAL; -} - -#endif /* CONFIG_DNOTIFY */ - -#endif /* __KERNEL __ */ - -#endif /* _LINUX_DNOTIFY_H */ diff --git a/src/linux/include/linux/dqblk_qtree.h b/src/linux/include/linux/dqblk_qtree.h deleted file mode 100644 index 0de21e9..0000000 --- a/src/linux/include/linux/dqblk_qtree.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Definitions of structures and functions for quota formats using trie - */ - -#ifndef _LINUX_DQBLK_QTREE_H -#define _LINUX_DQBLK_QTREE_H - -#include - -/* Numbers of blocks needed for updates - we count with the smallest - * possible block size (1024) */ -#define QTREE_INIT_ALLOC 4 -#define QTREE_INIT_REWRITE 2 -#define QTREE_DEL_ALLOC 0 -#define QTREE_DEL_REWRITE 6 - -struct dquot; -struct kqid; - -/* Operations */ -struct qtree_fmt_operations { - void (*mem2disk_dqblk)(void *disk, struct dquot *dquot); /* Convert given entry from in memory format to disk one */ - void (*disk2mem_dqblk)(struct dquot *dquot, void *disk); /* Convert given entry from disk format to in memory one */ - int (*is_id)(void *disk, struct dquot *dquot); /* Is this structure for given id? */ -}; - -/* Inmemory copy of version specific information */ -struct qtree_mem_dqinfo { - struct super_block *dqi_sb; /* Sb quota is on */ - int dqi_type; /* Quota type */ - unsigned int dqi_blocks; /* # of blocks in quota file */ - unsigned int dqi_free_blk; /* First block in list of free blocks */ - unsigned int dqi_free_entry; /* First block with free entry */ - unsigned int dqi_blocksize_bits; /* Block size of quota file */ - unsigned int dqi_entry_size; /* Size of quota entry in quota file */ - unsigned int dqi_usable_bs; /* Space usable in block for quota data */ - unsigned int dqi_qtree_depth; /* Precomputed depth of quota tree */ - const struct qtree_fmt_operations *dqi_ops; /* Operations for entry manipulation */ -}; - -int qtree_write_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot); -int qtree_read_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot); -int qtree_delete_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot); -int qtree_release_dquot(struct qtree_mem_dqinfo *info, struct dquot *dquot); -int qtree_entry_unused(struct qtree_mem_dqinfo *info, char *disk); -static inline int qtree_depth(struct qtree_mem_dqinfo *info) -{ - unsigned int epb = info->dqi_usable_bs >> 2; - unsigned long long entries = epb; - int i; - - for (i = 1; entries < (1ULL << 32); i++) - entries *= epb; - return i; -} -int qtree_get_next_id(struct qtree_mem_dqinfo *info, struct kqid *qid); - -#endif /* _LINUX_DQBLK_QTREE_H */ diff --git a/src/linux/include/linux/dqblk_v1.h b/src/linux/include/linux/dqblk_v1.h deleted file mode 100644 index c0d4d1e..0000000 --- a/src/linux/include/linux/dqblk_v1.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * File with in-memory structures of old quota format - */ - -#ifndef _LINUX_DQBLK_V1_H -#define _LINUX_DQBLK_V1_H - -/* Numbers of blocks needed for updates */ -#define V1_INIT_ALLOC 1 -#define V1_INIT_REWRITE 1 -#define V1_DEL_ALLOC 0 -#define V1_DEL_REWRITE 2 - -#endif /* _LINUX_DQBLK_V1_H */ diff --git a/src/linux/include/linux/dqblk_v2.h b/src/linux/include/linux/dqblk_v2.h deleted file mode 100644 index 18000a5..0000000 --- a/src/linux/include/linux/dqblk_v2.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Definitions for vfsv0 quota format - */ - -#ifndef _LINUX_DQBLK_V2_H -#define _LINUX_DQBLK_V2_H - -#include - -/* Numbers of blocks needed for updates */ -#define V2_INIT_ALLOC QTREE_INIT_ALLOC -#define V2_INIT_REWRITE QTREE_INIT_REWRITE -#define V2_DEL_ALLOC QTREE_DEL_ALLOC -#define V2_DEL_REWRITE QTREE_DEL_REWRITE - -#endif /* _LINUX_DQBLK_V2_H */ diff --git a/src/linux/include/linux/dynamic_debug.h b/src/linux/include/linux/dynamic_debug.h deleted file mode 100644 index 546d680..0000000 --- a/src/linux/include/linux/dynamic_debug.h +++ /dev/null @@ -1,185 +0,0 @@ -#ifndef _DYNAMIC_DEBUG_H -#define _DYNAMIC_DEBUG_H - -#if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_JUMP_LABEL) -#include -#endif - -/* - * An instance of this structure is created in a special - * ELF section at every dynamic debug callsite. At runtime, - * the special section is treated as an array of these. - */ -struct _ddebug { - /* - * These fields are used to drive the user interface - * for selecting and displaying debug callsites. - */ - const char *modname; - const char *function; - const char *filename; - const char *format; - unsigned int lineno:18; - /* - * The flags field controls the behaviour at the callsite. - * The bits here are changed dynamically when the user - * writes commands to /dynamic_debug/control - */ -#define _DPRINTK_FLAGS_NONE 0 -#define _DPRINTK_FLAGS_PRINT (1<<0) /* printk() a message using the format */ -#define _DPRINTK_FLAGS_INCL_MODNAME (1<<1) -#define _DPRINTK_FLAGS_INCL_FUNCNAME (1<<2) -#define _DPRINTK_FLAGS_INCL_LINENO (1<<3) -#define _DPRINTK_FLAGS_INCL_TID (1<<4) -#if defined DEBUG -#define _DPRINTK_FLAGS_DEFAULT _DPRINTK_FLAGS_PRINT -#else -#define _DPRINTK_FLAGS_DEFAULT 0 -#endif - unsigned int flags:8; -#ifdef HAVE_JUMP_LABEL - union { - struct static_key_true dd_key_true; - struct static_key_false dd_key_false; - } key; -#endif -} __attribute__((aligned(8))); - - -int ddebug_add_module(struct _ddebug *tab, unsigned int n, - const char *modname); - -#if defined(CONFIG_DYNAMIC_DEBUG) -extern int ddebug_remove_module(const char *mod_name); -extern __printf(2, 3) -void __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...); - -extern int ddebug_dyndbg_module_param_cb(char *param, char *val, - const char *modname); - -struct device; - -extern __printf(3, 4) -void __dynamic_dev_dbg(struct _ddebug *descriptor, const struct device *dev, - const char *fmt, ...); - -struct net_device; - -extern __printf(3, 4) -void __dynamic_netdev_dbg(struct _ddebug *descriptor, - const struct net_device *dev, - const char *fmt, ...); - -#define DEFINE_DYNAMIC_DEBUG_METADATA_KEY(name, fmt, key, init) \ - static struct _ddebug __aligned(8) \ - __attribute__((section("__verbose"))) name = { \ - .modname = KBUILD_MODNAME, \ - .function = __func__, \ - .filename = __FILE__, \ - .format = (fmt), \ - .lineno = __LINE__, \ - .flags = _DPRINTK_FLAGS_DEFAULT, \ - dd_key_init(key, init) \ - } - -#ifdef HAVE_JUMP_LABEL - -#define dd_key_init(key, init) key = (init) - -#ifdef DEBUG -#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt) \ - DEFINE_DYNAMIC_DEBUG_METADATA_KEY(name, fmt, .key.dd_key_true, \ - (STATIC_KEY_TRUE_INIT)) - -#define DYNAMIC_DEBUG_BRANCH(descriptor) \ - static_branch_likely(&descriptor.key.dd_key_true) -#else -#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt) \ - DEFINE_DYNAMIC_DEBUG_METADATA_KEY(name, fmt, .key.dd_key_false, \ - (STATIC_KEY_FALSE_INIT)) - -#define DYNAMIC_DEBUG_BRANCH(descriptor) \ - static_branch_unlikely(&descriptor.key.dd_key_false) -#endif - -#else - -#define dd_key_init(key, init) - -#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt) \ - DEFINE_DYNAMIC_DEBUG_METADATA_KEY(name, fmt, 0, 0) - -#ifdef DEBUG -#define DYNAMIC_DEBUG_BRANCH(descriptor) \ - likely(descriptor.flags & _DPRINTK_FLAGS_PRINT) -#else -#define DYNAMIC_DEBUG_BRANCH(descriptor) \ - unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT) -#endif - -#endif - -#define dynamic_pr_debug(fmt, ...) \ -do { \ - DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ - if (DYNAMIC_DEBUG_BRANCH(descriptor)) \ - __dynamic_pr_debug(&descriptor, pr_fmt(fmt), \ - ##__VA_ARGS__); \ -} while (0) - -#define dynamic_dev_dbg(dev, fmt, ...) \ -do { \ - DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ - if (DYNAMIC_DEBUG_BRANCH(descriptor)) \ - __dynamic_dev_dbg(&descriptor, dev, fmt, \ - ##__VA_ARGS__); \ -} while (0) - -#define dynamic_netdev_dbg(dev, fmt, ...) \ -do { \ - DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ - if (DYNAMIC_DEBUG_BRANCH(descriptor)) \ - __dynamic_netdev_dbg(&descriptor, dev, fmt, \ - ##__VA_ARGS__); \ -} while (0) - -#define dynamic_hex_dump(prefix_str, prefix_type, rowsize, \ - groupsize, buf, len, ascii) \ -do { \ - DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, \ - __builtin_constant_p(prefix_str) ? prefix_str : "hexdump");\ - if (DYNAMIC_DEBUG_BRANCH(descriptor)) \ - print_hex_dump(KERN_DEBUG, prefix_str, \ - prefix_type, rowsize, groupsize, \ - buf, len, ascii); \ -} while (0) - -#else - -#include -#include - -static inline int ddebug_remove_module(const char *mod) -{ - return 0; -} - -static inline int ddebug_dyndbg_module_param_cb(char *param, char *val, - const char *modname) -{ - if (strstr(param, "dyndbg")) { - /* avoid pr_warn(), which wants pr_fmt() fully defined */ - printk(KERN_WARNING "dyndbg param is supported only in " - "CONFIG_DYNAMIC_DEBUG builds\n"); - return 0; /* allow and ignore */ - } - return -EINVAL; -} - -#define dynamic_pr_debug(fmt, ...) \ - do { if (0) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); } while (0) -#define dynamic_dev_dbg(dev, fmt, ...) \ - do { if (0) dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__); } while (0) -#endif - -#endif diff --git a/src/linux/include/linux/dynamic_queue_limits.h b/src/linux/include/linux/dynamic_queue_limits.h deleted file mode 100644 index a4be703..0000000 --- a/src/linux/include/linux/dynamic_queue_limits.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Dynamic queue limits (dql) - Definitions - * - * Copyright (c) 2011, Tom Herbert - * - * This header file contains the definitions for dynamic queue limits (dql). - * dql would be used in conjunction with a producer/consumer type queue - * (possibly a HW queue). Such a queue would have these general properties: - * - * 1) Objects are queued up to some limit specified as number of objects. - * 2) Periodically a completion process executes which retires consumed - * objects. - * 3) Starvation occurs when limit has been reached, all queued data has - * actually been consumed, but completion processing has not yet run - * so queuing new data is blocked. - * 4) Minimizing the amount of queued data is desirable. - * - * The goal of dql is to calculate the limit as the minimum number of objects - * needed to prevent starvation. - * - * The primary functions of dql are: - * dql_queued - called when objects are enqueued to record number of objects - * dql_avail - returns how many objects are available to be queued based - * on the object limit and how many objects are already enqueued - * dql_completed - called at completion time to indicate how many objects - * were retired from the queue - * - * The dql implementation does not implement any locking for the dql data - * structures, the higher layer should provide this. dql_queued should - * be serialized to prevent concurrent execution of the function; this - * is also true for dql_completed. However, dql_queued and dlq_completed can - * be executed concurrently (i.e. they can be protected by different locks). - */ - -#ifndef _LINUX_DQL_H -#define _LINUX_DQL_H - -#ifdef __KERNEL__ - -struct dql { - /* Fields accessed in enqueue path (dql_queued) */ - unsigned int num_queued; /* Total ever queued */ - unsigned int adj_limit; /* limit + num_completed */ - unsigned int last_obj_cnt; /* Count at last queuing */ - - /* Fields accessed only by completion path (dql_completed) */ - - unsigned int limit ____cacheline_aligned_in_smp; /* Current limit */ - unsigned int num_completed; /* Total ever completed */ - - unsigned int prev_ovlimit; /* Previous over limit */ - unsigned int prev_num_queued; /* Previous queue total */ - unsigned int prev_last_obj_cnt; /* Previous queuing cnt */ - - unsigned int lowest_slack; /* Lowest slack found */ - unsigned long slack_start_time; /* Time slacks seen */ - - /* Configuration */ - unsigned int max_limit; /* Max limit */ - unsigned int min_limit; /* Minimum limit */ - unsigned int slack_hold_time; /* Time to measure slack */ -}; - -/* Set some static maximums */ -#define DQL_MAX_OBJECT (UINT_MAX / 16) -#define DQL_MAX_LIMIT ((UINT_MAX / 2) - DQL_MAX_OBJECT) - -/* - * Record number of objects queued. Assumes that caller has already checked - * availability in the queue with dql_avail. - */ -static inline void dql_queued(struct dql *dql, unsigned int count) -{ - BUG_ON(count > DQL_MAX_OBJECT); - - dql->last_obj_cnt = count; - - /* We want to force a write first, so that cpu do not attempt - * to get cache line containing last_obj_cnt, num_queued, adj_limit - * in Shared state, but directly does a Request For Ownership - * It is only a hint, we use barrier() only. - */ - barrier(); - - dql->num_queued += count; -} - -/* Returns how many objects can be queued, < 0 indicates over limit. */ -static inline int dql_avail(const struct dql *dql) -{ - return ACCESS_ONCE(dql->adj_limit) - ACCESS_ONCE(dql->num_queued); -} - -/* Record number of completed objects and recalculate the limit. */ -void dql_completed(struct dql *dql, unsigned int count); - -/* Reset dql state */ -void dql_reset(struct dql *dql); - -/* Initialize dql state */ -int dql_init(struct dql *dql, unsigned hold_time); - -#endif /* _KERNEL_ */ - -#endif /* _LINUX_DQL_H */ diff --git a/src/linux/include/linux/earlycpio.h b/src/linux/include/linux/earlycpio.h deleted file mode 100644 index 111f46d..0000000 --- a/src/linux/include/linux/earlycpio.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef _LINUX_EARLYCPIO_H -#define _LINUX_EARLYCPIO_H - -#include - -#define MAX_CPIO_FILE_NAME 18 - -struct cpio_data { - void *data; - size_t size; - char name[MAX_CPIO_FILE_NAME]; -}; - -struct cpio_data find_cpio_data(const char *path, void *data, size_t len, - long *offset); - -#endif /* _LINUX_EARLYCPIO_H */ diff --git a/src/linux/include/linux/efi.h b/src/linux/include/linux/efi.h deleted file mode 100644 index 2d08948..0000000 --- a/src/linux/include/linux/efi.h +++ /dev/null @@ -1,1496 +0,0 @@ -#ifndef _LINUX_EFI_H -#define _LINUX_EFI_H - -/* - * Extensible Firmware Interface - * Based on 'Extensible Firmware Interface Specification' version 0.9, April 30, 1999 - * - * Copyright (C) 1999 VA Linux Systems - * Copyright (C) 1999 Walt Drummond - * Copyright (C) 1999, 2002-2003 Hewlett-Packard Co. - * David Mosberger-Tang - * Stephane Eranian - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define EFI_SUCCESS 0 -#define EFI_LOAD_ERROR ( 1 | (1UL << (BITS_PER_LONG-1))) -#define EFI_INVALID_PARAMETER ( 2 | (1UL << (BITS_PER_LONG-1))) -#define EFI_UNSUPPORTED ( 3 | (1UL << (BITS_PER_LONG-1))) -#define EFI_BAD_BUFFER_SIZE ( 4 | (1UL << (BITS_PER_LONG-1))) -#define EFI_BUFFER_TOO_SMALL ( 5 | (1UL << (BITS_PER_LONG-1))) -#define EFI_NOT_READY ( 6 | (1UL << (BITS_PER_LONG-1))) -#define EFI_DEVICE_ERROR ( 7 | (1UL << (BITS_PER_LONG-1))) -#define EFI_WRITE_PROTECTED ( 8 | (1UL << (BITS_PER_LONG-1))) -#define EFI_OUT_OF_RESOURCES ( 9 | (1UL << (BITS_PER_LONG-1))) -#define EFI_NOT_FOUND (14 | (1UL << (BITS_PER_LONG-1))) -#define EFI_ABORTED (21 | (1UL << (BITS_PER_LONG-1))) -#define EFI_SECURITY_VIOLATION (26 | (1UL << (BITS_PER_LONG-1))) - -typedef unsigned long efi_status_t; -typedef u8 efi_bool_t; -typedef u16 efi_char16_t; /* UNICODE character */ -typedef u64 efi_physical_addr_t; -typedef void *efi_handle_t; - -typedef uuid_le efi_guid_t; - -#define EFI_GUID(a,b,c,d0,d1,d2,d3,d4,d5,d6,d7) \ - UUID_LE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) - -/* - * Generic EFI table header - */ -typedef struct { - u64 signature; - u32 revision; - u32 headersize; - u32 crc32; - u32 reserved; -} efi_table_hdr_t; - -/* - * Memory map descriptor: - */ - -/* Memory types: */ -#define EFI_RESERVED_TYPE 0 -#define EFI_LOADER_CODE 1 -#define EFI_LOADER_DATA 2 -#define EFI_BOOT_SERVICES_CODE 3 -#define EFI_BOOT_SERVICES_DATA 4 -#define EFI_RUNTIME_SERVICES_CODE 5 -#define EFI_RUNTIME_SERVICES_DATA 6 -#define EFI_CONVENTIONAL_MEMORY 7 -#define EFI_UNUSABLE_MEMORY 8 -#define EFI_ACPI_RECLAIM_MEMORY 9 -#define EFI_ACPI_MEMORY_NVS 10 -#define EFI_MEMORY_MAPPED_IO 11 -#define EFI_MEMORY_MAPPED_IO_PORT_SPACE 12 -#define EFI_PAL_CODE 13 -#define EFI_PERSISTENT_MEMORY 14 -#define EFI_MAX_MEMORY_TYPE 15 - -/* Attribute values: */ -#define EFI_MEMORY_UC ((u64)0x0000000000000001ULL) /* uncached */ -#define EFI_MEMORY_WC ((u64)0x0000000000000002ULL) /* write-coalescing */ -#define EFI_MEMORY_WT ((u64)0x0000000000000004ULL) /* write-through */ -#define EFI_MEMORY_WB ((u64)0x0000000000000008ULL) /* write-back */ -#define EFI_MEMORY_UCE ((u64)0x0000000000000010ULL) /* uncached, exported */ -#define EFI_MEMORY_WP ((u64)0x0000000000001000ULL) /* write-protect */ -#define EFI_MEMORY_RP ((u64)0x0000000000002000ULL) /* read-protect */ -#define EFI_MEMORY_XP ((u64)0x0000000000004000ULL) /* execute-protect */ -#define EFI_MEMORY_NV ((u64)0x0000000000008000ULL) /* non-volatile */ -#define EFI_MEMORY_MORE_RELIABLE \ - ((u64)0x0000000000010000ULL) /* higher reliability */ -#define EFI_MEMORY_RO ((u64)0x0000000000020000ULL) /* read-only */ -#define EFI_MEMORY_RUNTIME ((u64)0x8000000000000000ULL) /* range requires runtime mapping */ -#define EFI_MEMORY_DESCRIPTOR_VERSION 1 - -#define EFI_PAGE_SHIFT 12 -#define EFI_PAGE_SIZE (1UL << EFI_PAGE_SHIFT) - -typedef struct { - u32 type; - u32 pad; - u64 phys_addr; - u64 virt_addr; - u64 num_pages; - u64 attribute; -} efi_memory_desc_t; - -typedef struct { - efi_guid_t guid; - u32 headersize; - u32 flags; - u32 imagesize; -} efi_capsule_header_t; - -struct efi_boot_memmap { - efi_memory_desc_t **map; - unsigned long *map_size; - unsigned long *desc_size; - u32 *desc_ver; - unsigned long *key_ptr; - unsigned long *buff_size; -}; - -/* - * EFI capsule flags - */ -#define EFI_CAPSULE_PERSIST_ACROSS_RESET 0x00010000 -#define EFI_CAPSULE_POPULATE_SYSTEM_TABLE 0x00020000 -#define EFI_CAPSULE_INITIATE_RESET 0x00040000 - -/* - * Allocation types for calls to boottime->allocate_pages. - */ -#define EFI_ALLOCATE_ANY_PAGES 0 -#define EFI_ALLOCATE_MAX_ADDRESS 1 -#define EFI_ALLOCATE_ADDRESS 2 -#define EFI_MAX_ALLOCATE_TYPE 3 - -typedef int (*efi_freemem_callback_t) (u64 start, u64 end, void *arg); - -/* - * Types and defines for Time Services - */ -#define EFI_TIME_ADJUST_DAYLIGHT 0x1 -#define EFI_TIME_IN_DAYLIGHT 0x2 -#define EFI_UNSPECIFIED_TIMEZONE 0x07ff - -typedef struct { - u16 year; - u8 month; - u8 day; - u8 hour; - u8 minute; - u8 second; - u8 pad1; - u32 nanosecond; - s16 timezone; - u8 daylight; - u8 pad2; -} efi_time_t; - -typedef struct { - u32 resolution; - u32 accuracy; - u8 sets_to_zero; -} efi_time_cap_t; - -typedef struct { - efi_table_hdr_t hdr; - u32 raise_tpl; - u32 restore_tpl; - u32 allocate_pages; - u32 free_pages; - u32 get_memory_map; - u32 allocate_pool; - u32 free_pool; - u32 create_event; - u32 set_timer; - u32 wait_for_event; - u32 signal_event; - u32 close_event; - u32 check_event; - u32 install_protocol_interface; - u32 reinstall_protocol_interface; - u32 uninstall_protocol_interface; - u32 handle_protocol; - u32 __reserved; - u32 register_protocol_notify; - u32 locate_handle; - u32 locate_device_path; - u32 install_configuration_table; - u32 load_image; - u32 start_image; - u32 exit; - u32 unload_image; - u32 exit_boot_services; - u32 get_next_monotonic_count; - u32 stall; - u32 set_watchdog_timer; - u32 connect_controller; - u32 disconnect_controller; - u32 open_protocol; - u32 close_protocol; - u32 open_protocol_information; - u32 protocols_per_handle; - u32 locate_handle_buffer; - u32 locate_protocol; - u32 install_multiple_protocol_interfaces; - u32 uninstall_multiple_protocol_interfaces; - u32 calculate_crc32; - u32 copy_mem; - u32 set_mem; - u32 create_event_ex; -} __packed efi_boot_services_32_t; - -typedef struct { - efi_table_hdr_t hdr; - u64 raise_tpl; - u64 restore_tpl; - u64 allocate_pages; - u64 free_pages; - u64 get_memory_map; - u64 allocate_pool; - u64 free_pool; - u64 create_event; - u64 set_timer; - u64 wait_for_event; - u64 signal_event; - u64 close_event; - u64 check_event; - u64 install_protocol_interface; - u64 reinstall_protocol_interface; - u64 uninstall_protocol_interface; - u64 handle_protocol; - u64 __reserved; - u64 register_protocol_notify; - u64 locate_handle; - u64 locate_device_path; - u64 install_configuration_table; - u64 load_image; - u64 start_image; - u64 exit; - u64 unload_image; - u64 exit_boot_services; - u64 get_next_monotonic_count; - u64 stall; - u64 set_watchdog_timer; - u64 connect_controller; - u64 disconnect_controller; - u64 open_protocol; - u64 close_protocol; - u64 open_protocol_information; - u64 protocols_per_handle; - u64 locate_handle_buffer; - u64 locate_protocol; - u64 install_multiple_protocol_interfaces; - u64 uninstall_multiple_protocol_interfaces; - u64 calculate_crc32; - u64 copy_mem; - u64 set_mem; - u64 create_event_ex; -} __packed efi_boot_services_64_t; - -/* - * EFI Boot Services table - */ -typedef struct { - efi_table_hdr_t hdr; - void *raise_tpl; - void *restore_tpl; - efi_status_t (*allocate_pages)(int, int, unsigned long, - efi_physical_addr_t *); - efi_status_t (*free_pages)(efi_physical_addr_t, unsigned long); - efi_status_t (*get_memory_map)(unsigned long *, void *, unsigned long *, - unsigned long *, u32 *); - efi_status_t (*allocate_pool)(int, unsigned long, void **); - efi_status_t (*free_pool)(void *); - void *create_event; - void *set_timer; - void *wait_for_event; - void *signal_event; - void *close_event; - void *check_event; - void *install_protocol_interface; - void *reinstall_protocol_interface; - void *uninstall_protocol_interface; - efi_status_t (*handle_protocol)(efi_handle_t, efi_guid_t *, void **); - void *__reserved; - void *register_protocol_notify; - efi_status_t (*locate_handle)(int, efi_guid_t *, void *, - unsigned long *, efi_handle_t *); - void *locate_device_path; - efi_status_t (*install_configuration_table)(efi_guid_t *, void *); - void *load_image; - void *start_image; - void *exit; - void *unload_image; - efi_status_t (*exit_boot_services)(efi_handle_t, unsigned long); - void *get_next_monotonic_count; - void *stall; - void *set_watchdog_timer; - void *connect_controller; - void *disconnect_controller; - void *open_protocol; - void *close_protocol; - void *open_protocol_information; - void *protocols_per_handle; - void *locate_handle_buffer; - efi_status_t (*locate_protocol)(efi_guid_t *, void *, void **); - void *install_multiple_protocol_interfaces; - void *uninstall_multiple_protocol_interfaces; - void *calculate_crc32; - void *copy_mem; - void *set_mem; - void *create_event_ex; -} efi_boot_services_t; - -typedef enum { - EfiPciIoWidthUint8, - EfiPciIoWidthUint16, - EfiPciIoWidthUint32, - EfiPciIoWidthUint64, - EfiPciIoWidthFifoUint8, - EfiPciIoWidthFifoUint16, - EfiPciIoWidthFifoUint32, - EfiPciIoWidthFifoUint64, - EfiPciIoWidthFillUint8, - EfiPciIoWidthFillUint16, - EfiPciIoWidthFillUint32, - EfiPciIoWidthFillUint64, - EfiPciIoWidthMaximum -} EFI_PCI_IO_PROTOCOL_WIDTH; - -typedef enum { - EfiPciIoAttributeOperationGet, - EfiPciIoAttributeOperationSet, - EfiPciIoAttributeOperationEnable, - EfiPciIoAttributeOperationDisable, - EfiPciIoAttributeOperationSupported, - EfiPciIoAttributeOperationMaximum -} EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION; - -typedef struct { - u32 read; - u32 write; -} efi_pci_io_protocol_access_32_t; - -typedef struct { - u64 read; - u64 write; -} efi_pci_io_protocol_access_64_t; - -typedef struct { - void *read; - void *write; -} efi_pci_io_protocol_access_t; - -typedef struct { - u32 poll_mem; - u32 poll_io; - efi_pci_io_protocol_access_32_t mem; - efi_pci_io_protocol_access_32_t io; - efi_pci_io_protocol_access_32_t pci; - u32 copy_mem; - u32 map; - u32 unmap; - u32 allocate_buffer; - u32 free_buffer; - u32 flush; - u32 get_location; - u32 attributes; - u32 get_bar_attributes; - u32 set_bar_attributes; - uint64_t romsize; - void *romimage; -} efi_pci_io_protocol_32; - -typedef struct { - u64 poll_mem; - u64 poll_io; - efi_pci_io_protocol_access_64_t mem; - efi_pci_io_protocol_access_64_t io; - efi_pci_io_protocol_access_64_t pci; - u64 copy_mem; - u64 map; - u64 unmap; - u64 allocate_buffer; - u64 free_buffer; - u64 flush; - u64 get_location; - u64 attributes; - u64 get_bar_attributes; - u64 set_bar_attributes; - uint64_t romsize; - void *romimage; -} efi_pci_io_protocol_64; - -typedef struct { - void *poll_mem; - void *poll_io; - efi_pci_io_protocol_access_t mem; - efi_pci_io_protocol_access_t io; - efi_pci_io_protocol_access_t pci; - void *copy_mem; - void *map; - void *unmap; - void *allocate_buffer; - void *free_buffer; - void *flush; - void *get_location; - void *attributes; - void *get_bar_attributes; - void *set_bar_attributes; - uint64_t romsize; - void *romimage; -} efi_pci_io_protocol; - -#define EFI_PCI_IO_ATTRIBUTE_ISA_MOTHERBOARD_IO 0x0001 -#define EFI_PCI_IO_ATTRIBUTE_ISA_IO 0x0002 -#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO 0x0004 -#define EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY 0x0008 -#define EFI_PCI_IO_ATTRIBUTE_VGA_IO 0x0010 -#define EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO 0x0020 -#define EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO 0x0040 -#define EFI_PCI_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x0080 -#define EFI_PCI_IO_ATTRIBUTE_IO 0x0100 -#define EFI_PCI_IO_ATTRIBUTE_MEMORY 0x0200 -#define EFI_PCI_IO_ATTRIBUTE_BUS_MASTER 0x0400 -#define EFI_PCI_IO_ATTRIBUTE_MEMORY_CACHED 0x0800 -#define EFI_PCI_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000 -#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_DEVICE 0x2000 -#define EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM 0x4000 -#define EFI_PCI_IO_ATTRIBUTE_DUAL_ADDRESS_CYCLE 0x8000 -#define EFI_PCI_IO_ATTRIBUTE_ISA_IO_16 0x10000 -#define EFI_PCI_IO_ATTRIBUTE_VGA_PALETTE_IO_16 0x20000 -#define EFI_PCI_IO_ATTRIBUTE_VGA_IO_16 0x40000 - -/* - * Types and defines for EFI ResetSystem - */ -#define EFI_RESET_COLD 0 -#define EFI_RESET_WARM 1 -#define EFI_RESET_SHUTDOWN 2 - -/* - * EFI Runtime Services table - */ -#define EFI_RUNTIME_SERVICES_SIGNATURE ((u64)0x5652453544e5552ULL) -#define EFI_RUNTIME_SERVICES_REVISION 0x00010000 - -typedef struct { - efi_table_hdr_t hdr; - u32 get_time; - u32 set_time; - u32 get_wakeup_time; - u32 set_wakeup_time; - u32 set_virtual_address_map; - u32 convert_pointer; - u32 get_variable; - u32 get_next_variable; - u32 set_variable; - u32 get_next_high_mono_count; - u32 reset_system; - u32 update_capsule; - u32 query_capsule_caps; - u32 query_variable_info; -} efi_runtime_services_32_t; - -typedef struct { - efi_table_hdr_t hdr; - u64 get_time; - u64 set_time; - u64 get_wakeup_time; - u64 set_wakeup_time; - u64 set_virtual_address_map; - u64 convert_pointer; - u64 get_variable; - u64 get_next_variable; - u64 set_variable; - u64 get_next_high_mono_count; - u64 reset_system; - u64 update_capsule; - u64 query_capsule_caps; - u64 query_variable_info; -} efi_runtime_services_64_t; - -typedef struct { - efi_table_hdr_t hdr; - void *get_time; - void *set_time; - void *get_wakeup_time; - void *set_wakeup_time; - void *set_virtual_address_map; - void *convert_pointer; - void *get_variable; - void *get_next_variable; - void *set_variable; - void *get_next_high_mono_count; - void *reset_system; - void *update_capsule; - void *query_capsule_caps; - void *query_variable_info; -} efi_runtime_services_t; - -typedef efi_status_t efi_get_time_t (efi_time_t *tm, efi_time_cap_t *tc); -typedef efi_status_t efi_set_time_t (efi_time_t *tm); -typedef efi_status_t efi_get_wakeup_time_t (efi_bool_t *enabled, efi_bool_t *pending, - efi_time_t *tm); -typedef efi_status_t efi_set_wakeup_time_t (efi_bool_t enabled, efi_time_t *tm); -typedef efi_status_t efi_get_variable_t (efi_char16_t *name, efi_guid_t *vendor, u32 *attr, - unsigned long *data_size, void *data); -typedef efi_status_t efi_get_next_variable_t (unsigned long *name_size, efi_char16_t *name, - efi_guid_t *vendor); -typedef efi_status_t efi_set_variable_t (efi_char16_t *name, efi_guid_t *vendor, - u32 attr, unsigned long data_size, - void *data); -typedef efi_status_t efi_get_next_high_mono_count_t (u32 *count); -typedef void efi_reset_system_t (int reset_type, efi_status_t status, - unsigned long data_size, efi_char16_t *data); -typedef efi_status_t efi_set_virtual_address_map_t (unsigned long memory_map_size, - unsigned long descriptor_size, - u32 descriptor_version, - efi_memory_desc_t *virtual_map); -typedef efi_status_t efi_query_variable_info_t(u32 attr, - u64 *storage_space, - u64 *remaining_space, - u64 *max_variable_size); -typedef efi_status_t efi_update_capsule_t(efi_capsule_header_t **capsules, - unsigned long count, - unsigned long sg_list); -typedef efi_status_t efi_query_capsule_caps_t(efi_capsule_header_t **capsules, - unsigned long count, - u64 *max_size, - int *reset_type); -typedef efi_status_t efi_query_variable_store_t(u32 attributes, - unsigned long size, - bool nonblocking); - -void efi_native_runtime_setup(void); - -/* - * EFI Configuration Table and GUID definitions - * - * These are all defined in a single line to make them easier to - * grep for and to see them at a glance - while still having a - * similar structure to the definitions in the spec. - * - * Here's how they are structured: - * - * GUID: 12345678-1234-1234-1234-123456789012 - * Spec: - * #define EFI_SOME_PROTOCOL_GUID \ - * {0x12345678,0x1234,0x1234,\ - * {0x12,0x34,0x12,0x34,0x56,0x78,0x90,0x12}} - * Here: - * #define SOME_PROTOCOL_GUID EFI_GUID(0x12345678, 0x1234, 0x1234, 0x12, 0x34, 0x12, 0x34, 0x56, 0x78, 0x90, 0x12) - * ^ tabs ^extra space - * - * Note that the 'extra space' separates the values at the same place - * where the UEFI SPEC breaks the line. - */ -#define NULL_GUID EFI_GUID(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00) -#define MPS_TABLE_GUID EFI_GUID(0xeb9d2d2f, 0x2d88, 0x11d3, 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) -#define ACPI_TABLE_GUID EFI_GUID(0xeb9d2d30, 0x2d88, 0x11d3, 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) -#define ACPI_20_TABLE_GUID EFI_GUID(0x8868e871, 0xe4f1, 0x11d3, 0xbc, 0x22, 0x00, 0x80, 0xc7, 0x3c, 0x88, 0x81) -#define SMBIOS_TABLE_GUID EFI_GUID(0xeb9d2d31, 0x2d88, 0x11d3, 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) -#define SMBIOS3_TABLE_GUID EFI_GUID(0xf2fd1544, 0x9794, 0x4a2c, 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94) -#define SAL_SYSTEM_TABLE_GUID EFI_GUID(0xeb9d2d32, 0x2d88, 0x11d3, 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) -#define HCDP_TABLE_GUID EFI_GUID(0xf951938d, 0x620b, 0x42ef, 0x82, 0x79, 0xa8, 0x4b, 0x79, 0x61, 0x78, 0x98) -#define UGA_IO_PROTOCOL_GUID EFI_GUID(0x61a4d49e, 0x6f68, 0x4f1b, 0xb9, 0x22, 0xa8, 0x6e, 0xed, 0x0b, 0x07, 0xa2) -#define EFI_GLOBAL_VARIABLE_GUID EFI_GUID(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c) -#define UV_SYSTEM_TABLE_GUID EFI_GUID(0x3b13a7d4, 0x633e, 0x11dd, 0x93, 0xec, 0xda, 0x25, 0x56, 0xd8, 0x95, 0x93) -#define LINUX_EFI_CRASH_GUID EFI_GUID(0xcfc8fc79, 0xbe2e, 0x4ddc, 0x97, 0xf0, 0x9f, 0x98, 0xbf, 0xe2, 0x98, 0xa0) -#define LOADED_IMAGE_PROTOCOL_GUID EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2, 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) -#define EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID EFI_GUID(0x9042a9de, 0x23dc, 0x4a38, 0x96, 0xfb, 0x7a, 0xde, 0xd0, 0x80, 0x51, 0x6a) -#define EFI_UGA_PROTOCOL_GUID EFI_GUID(0x982c298b, 0xf4fa, 0x41cb, 0xb8, 0x38, 0x77, 0xaa, 0x68, 0x8f, 0xb8, 0x39) -#define EFI_PCI_IO_PROTOCOL_GUID EFI_GUID(0x4cf5b200, 0x68b8, 0x4ca5, 0x9e, 0xec, 0xb2, 0x3e, 0x3f, 0x50, 0x02, 0x9a) -#define EFI_FILE_INFO_ID EFI_GUID(0x09576e92, 0x6d3f, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) -#define EFI_SYSTEM_RESOURCE_TABLE_GUID EFI_GUID(0xb122a263, 0x3661, 0x4f68, 0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80) -#define EFI_FILE_SYSTEM_GUID EFI_GUID(0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b) -#define DEVICE_TREE_GUID EFI_GUID(0xb1b621d5, 0xf19c, 0x41a5, 0x83, 0x0b, 0xd9, 0x15, 0x2c, 0x69, 0xaa, 0xe0) -#define EFI_PROPERTIES_TABLE_GUID EFI_GUID(0x880aaca3, 0x4adc, 0x4a04, 0x90, 0x79, 0xb7, 0x47, 0x34, 0x08, 0x25, 0xe5) -#define EFI_RNG_PROTOCOL_GUID EFI_GUID(0x3152bca5, 0xeade, 0x433d, 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44) -#define EFI_MEMORY_ATTRIBUTES_TABLE_GUID EFI_GUID(0xdcfa911d, 0x26eb, 0x469f, 0xa2, 0x20, 0x38, 0xb7, 0xdc, 0x46, 0x12, 0x20) -#define EFI_CONSOLE_OUT_DEVICE_GUID EFI_GUID(0xd3b36f2c, 0xd551, 0x11d4, 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d) - -/* - * This GUID is used to pass to the kernel proper the struct screen_info - * structure that was populated by the stub based on the GOP protocol instance - * associated with ConOut - */ -#define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID EFI_GUID(0xe03fc20a, 0x85dc, 0x406e, 0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95) -#define LINUX_EFI_LOADER_ENTRY_GUID EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf, 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f) - -typedef struct { - efi_guid_t guid; - u64 table; -} efi_config_table_64_t; - -typedef struct { - efi_guid_t guid; - u32 table; -} efi_config_table_32_t; - -typedef struct { - efi_guid_t guid; - unsigned long table; -} efi_config_table_t; - -typedef struct { - efi_guid_t guid; - const char *name; - unsigned long *ptr; -} efi_config_table_type_t; - -#define EFI_SYSTEM_TABLE_SIGNATURE ((u64)0x5453595320494249ULL) - -#define EFI_2_30_SYSTEM_TABLE_REVISION ((2 << 16) | (30)) -#define EFI_2_20_SYSTEM_TABLE_REVISION ((2 << 16) | (20)) -#define EFI_2_10_SYSTEM_TABLE_REVISION ((2 << 16) | (10)) -#define EFI_2_00_SYSTEM_TABLE_REVISION ((2 << 16) | (00)) -#define EFI_1_10_SYSTEM_TABLE_REVISION ((1 << 16) | (10)) -#define EFI_1_02_SYSTEM_TABLE_REVISION ((1 << 16) | (02)) - -typedef struct { - efi_table_hdr_t hdr; - u64 fw_vendor; /* physical addr of CHAR16 vendor string */ - u32 fw_revision; - u32 __pad1; - u64 con_in_handle; - u64 con_in; - u64 con_out_handle; - u64 con_out; - u64 stderr_handle; - u64 stderr; - u64 runtime; - u64 boottime; - u32 nr_tables; - u32 __pad2; - u64 tables; -} efi_system_table_64_t; - -typedef struct { - efi_table_hdr_t hdr; - u32 fw_vendor; /* physical addr of CHAR16 vendor string */ - u32 fw_revision; - u32 con_in_handle; - u32 con_in; - u32 con_out_handle; - u32 con_out; - u32 stderr_handle; - u32 stderr; - u32 runtime; - u32 boottime; - u32 nr_tables; - u32 tables; -} efi_system_table_32_t; - -typedef struct { - efi_table_hdr_t hdr; - unsigned long fw_vendor; /* physical addr of CHAR16 vendor string */ - u32 fw_revision; - unsigned long con_in_handle; - unsigned long con_in; - unsigned long con_out_handle; - unsigned long con_out; - unsigned long stderr_handle; - unsigned long stderr; - efi_runtime_services_t *runtime; - efi_boot_services_t *boottime; - unsigned long nr_tables; - unsigned long tables; -} efi_system_table_t; - -/* - * Architecture independent structure for describing a memory map for the - * benefit of efi_memmap_init_early(), saving us the need to pass four - * parameters. - */ -struct efi_memory_map_data { - phys_addr_t phys_map; - unsigned long size; - unsigned long desc_version; - unsigned long desc_size; -}; - -struct efi_memory_map { - phys_addr_t phys_map; - void *map; - void *map_end; - int nr_map; - unsigned long desc_version; - unsigned long desc_size; - bool late; -}; - -struct efi_mem_range { - struct range range; - u64 attribute; -}; - -struct efi_fdt_params { - u64 system_table; - u64 mmap; - u32 mmap_size; - u32 desc_size; - u32 desc_ver; -}; - -typedef struct { - u32 revision; - u32 parent_handle; - u32 system_table; - u32 device_handle; - u32 file_path; - u32 reserved; - u32 load_options_size; - u32 load_options; - u32 image_base; - __aligned_u64 image_size; - unsigned int image_code_type; - unsigned int image_data_type; - unsigned long unload; -} efi_loaded_image_32_t; - -typedef struct { - u32 revision; - u64 parent_handle; - u64 system_table; - u64 device_handle; - u64 file_path; - u64 reserved; - u32 load_options_size; - u64 load_options; - u64 image_base; - __aligned_u64 image_size; - unsigned int image_code_type; - unsigned int image_data_type; - unsigned long unload; -} efi_loaded_image_64_t; - -typedef struct { - u32 revision; - void *parent_handle; - efi_system_table_t *system_table; - void *device_handle; - void *file_path; - void *reserved; - u32 load_options_size; - void *load_options; - void *image_base; - __aligned_u64 image_size; - unsigned int image_code_type; - unsigned int image_data_type; - unsigned long unload; -} efi_loaded_image_t; - - -typedef struct { - u64 size; - u64 file_size; - u64 phys_size; - efi_time_t create_time; - efi_time_t last_access_time; - efi_time_t modification_time; - __aligned_u64 attribute; - efi_char16_t filename[1]; -} efi_file_info_t; - -typedef struct { - u64 revision; - u32 open; - u32 close; - u32 delete; - u32 read; - u32 write; - u32 get_position; - u32 set_position; - u32 get_info; - u32 set_info; - u32 flush; -} efi_file_handle_32_t; - -typedef struct { - u64 revision; - u64 open; - u64 close; - u64 delete; - u64 read; - u64 write; - u64 get_position; - u64 set_position; - u64 get_info; - u64 set_info; - u64 flush; -} efi_file_handle_64_t; - -typedef struct _efi_file_handle { - u64 revision; - efi_status_t (*open)(struct _efi_file_handle *, - struct _efi_file_handle **, - efi_char16_t *, u64, u64); - efi_status_t (*close)(struct _efi_file_handle *); - void *delete; - efi_status_t (*read)(struct _efi_file_handle *, unsigned long *, - void *); - void *write; - void *get_position; - void *set_position; - efi_status_t (*get_info)(struct _efi_file_handle *, efi_guid_t *, - unsigned long *, void *); - void *set_info; - void *flush; -} efi_file_handle_t; - -typedef struct _efi_file_io_interface { - u64 revision; - int (*open_volume)(struct _efi_file_io_interface *, - efi_file_handle_t **); -} efi_file_io_interface_t; - -#define EFI_FILE_MODE_READ 0x0000000000000001 -#define EFI_FILE_MODE_WRITE 0x0000000000000002 -#define EFI_FILE_MODE_CREATE 0x8000000000000000 - -typedef struct { - u32 version; - u32 length; - u64 memory_protection_attribute; -} efi_properties_table_t; - -#define EFI_PROPERTIES_TABLE_VERSION 0x00010000 -#define EFI_PROPERTIES_RUNTIME_MEMORY_PROTECTION_NON_EXECUTABLE_PE_DATA 0x1 - -#define EFI_INVALID_TABLE_ADDR (~0UL) - -typedef struct { - u32 version; - u32 num_entries; - u32 desc_size; - u32 reserved; - efi_memory_desc_t entry[0]; -} efi_memory_attributes_table_t; - -/* - * All runtime access to EFI goes through this structure: - */ -extern struct efi { - efi_system_table_t *systab; /* EFI system table */ - unsigned int runtime_version; /* Runtime services version */ - unsigned long mps; /* MPS table */ - unsigned long acpi; /* ACPI table (IA64 ext 0.71) */ - unsigned long acpi20; /* ACPI table (ACPI 2.0) */ - unsigned long smbios; /* SMBIOS table (32 bit entry point) */ - unsigned long smbios3; /* SMBIOS table (64 bit entry point) */ - unsigned long sal_systab; /* SAL system table */ - unsigned long boot_info; /* boot info table */ - unsigned long hcdp; /* HCDP table */ - unsigned long uga; /* UGA table */ - unsigned long uv_systab; /* UV system table */ - unsigned long fw_vendor; /* fw_vendor */ - unsigned long runtime; /* runtime table */ - unsigned long config_table; /* config tables */ - unsigned long esrt; /* ESRT table */ - unsigned long properties_table; /* properties table */ - unsigned long mem_attr_table; /* memory attributes table */ - efi_get_time_t *get_time; - efi_set_time_t *set_time; - efi_get_wakeup_time_t *get_wakeup_time; - efi_set_wakeup_time_t *set_wakeup_time; - efi_get_variable_t *get_variable; - efi_get_next_variable_t *get_next_variable; - efi_set_variable_t *set_variable; - efi_set_variable_t *set_variable_nonblocking; - efi_query_variable_info_t *query_variable_info; - efi_query_variable_info_t *query_variable_info_nonblocking; - efi_update_capsule_t *update_capsule; - efi_query_capsule_caps_t *query_capsule_caps; - efi_get_next_high_mono_count_t *get_next_high_mono_count; - efi_reset_system_t *reset_system; - efi_set_virtual_address_map_t *set_virtual_address_map; - struct efi_memory_map memmap; - unsigned long flags; -} efi; - -static inline int -efi_guidcmp (efi_guid_t left, efi_guid_t right) -{ - return memcmp(&left, &right, sizeof (efi_guid_t)); -} - -static inline char * -efi_guid_to_str(efi_guid_t *guid, char *out) -{ - sprintf(out, "%pUl", guid->b); - return out; -} - -extern void efi_init (void); -extern void *efi_get_pal_addr (void); -extern void efi_map_pal_code (void); -extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg); -extern void efi_gettimeofday (struct timespec64 *ts); -extern void efi_enter_virtual_mode (void); /* switch EFI to virtual mode, if possible */ -#ifdef CONFIG_X86 -extern void efi_late_init(void); -extern void efi_free_boot_services(void); -extern efi_status_t efi_query_variable_store(u32 attributes, - unsigned long size, - bool nonblocking); -extern void efi_find_mirror(void); -#else -static inline void efi_late_init(void) {} -static inline void efi_free_boot_services(void) {} - -static inline efi_status_t efi_query_variable_store(u32 attributes, - unsigned long size, - bool nonblocking) -{ - return EFI_SUCCESS; -} -#endif -extern void __iomem *efi_lookup_mapped_addr(u64 phys_addr); - -extern int __init efi_memmap_init_early(struct efi_memory_map_data *data); -extern int __init efi_memmap_init_late(phys_addr_t addr, unsigned long size); -extern void __init efi_memmap_unmap(void); -extern int __init efi_memmap_install(phys_addr_t addr, unsigned int nr_map); -extern int __init efi_memmap_split_count(efi_memory_desc_t *md, - struct range *range); -extern void __init efi_memmap_insert(struct efi_memory_map *old_memmap, - void *buf, struct efi_mem_range *mem); - -extern int efi_config_init(efi_config_table_type_t *arch_tables); -#ifdef CONFIG_EFI_ESRT -extern void __init efi_esrt_init(void); -#else -static inline void efi_esrt_init(void) { } -#endif -extern int efi_config_parse_tables(void *config_tables, int count, int sz, - efi_config_table_type_t *arch_tables); -extern u64 efi_get_iobase (void); -extern u32 efi_mem_type (unsigned long phys_addr); -extern u64 efi_mem_attributes (unsigned long phys_addr); -extern u64 efi_mem_attribute (unsigned long phys_addr, unsigned long size); -extern int __init efi_uart_console_only (void); -extern u64 efi_mem_desc_end(efi_memory_desc_t *md); -extern int efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md); -extern void efi_mem_reserve(phys_addr_t addr, u64 size); -extern void efi_initialize_iomem_resources(struct resource *code_resource, - struct resource *data_resource, struct resource *bss_resource); -extern void efi_reserve_boot_services(void); -extern int efi_get_fdt_params(struct efi_fdt_params *params); -extern struct kobject *efi_kobj; - -extern int efi_reboot_quirk_mode; -extern bool efi_poweroff_required(void); - -#ifdef CONFIG_EFI_FAKE_MEMMAP -extern void __init efi_fake_memmap(void); -#else -static inline void efi_fake_memmap(void) { } -#endif - -/* - * efi_memattr_perm_setter - arch specific callback function passed into - * efi_memattr_apply_permissions() that updates the - * mapping permissions described by the second - * argument in the page tables referred to by the - * first argument. - */ -typedef int (*efi_memattr_perm_setter)(struct mm_struct *, efi_memory_desc_t *); - -extern int efi_memattr_init(void); -extern int efi_memattr_apply_permissions(struct mm_struct *mm, - efi_memattr_perm_setter fn); - -/* Iterate through an efi_memory_map */ -#define for_each_efi_memory_desc_in_map(m, md) \ - for ((md) = (m)->map; \ - (md) && ((void *)(md) + (m)->desc_size) <= (m)->map_end; \ - (md) = (void *)(md) + (m)->desc_size) - -/** - * for_each_efi_memory_desc - iterate over descriptors in efi.memmap - * @md: the efi_memory_desc_t * iterator - * - * Once the loop finishes @md must not be accessed. - */ -#define for_each_efi_memory_desc(md) \ - for_each_efi_memory_desc_in_map(&efi.memmap, md) - -/* - * Format an EFI memory descriptor's type and attributes to a user-provided - * character buffer, as per snprintf(), and return the buffer. - */ -char * __init efi_md_typeattr_format(char *buf, size_t size, - const efi_memory_desc_t *md); - -/** - * efi_range_is_wc - check the WC bit on an address range - * @start: starting kvirt address - * @len: length of range - * - * Consult the EFI memory map and make sure it's ok to set this range WC. - * Returns true or false. - */ -static inline int efi_range_is_wc(unsigned long start, unsigned long len) -{ - unsigned long i; - - for (i = 0; i < len; i += (1UL << EFI_PAGE_SHIFT)) { - unsigned long paddr = __pa(start + i); - if (!(efi_mem_attributes(paddr) & EFI_MEMORY_WC)) - return 0; - } - /* The range checked out */ - return 1; -} - -#ifdef CONFIG_EFI_PCDP -extern int __init efi_setup_pcdp_console(char *); -#endif - -/* - * We play games with efi_enabled so that the compiler will, if - * possible, remove EFI-related code altogether. - */ -#define EFI_BOOT 0 /* Were we booted from EFI? */ -#define EFI_CONFIG_TABLES 2 /* Can we use EFI config tables? */ -#define EFI_RUNTIME_SERVICES 3 /* Can we use runtime services? */ -#define EFI_MEMMAP 4 /* Can we use EFI memory map? */ -#define EFI_64BIT 5 /* Is the firmware 64-bit? */ -#define EFI_PARAVIRT 6 /* Access is via a paravirt interface */ -#define EFI_ARCH_1 7 /* First arch-specific bit */ -#define EFI_DBG 8 /* Print additional debug info at runtime */ -#define EFI_NX_PE_DATA 9 /* Can runtime data regions be mapped non-executable? */ - -#ifdef CONFIG_EFI -/* - * Test whether the above EFI_* bits are enabled. - */ -static inline bool efi_enabled(int feature) -{ - return test_bit(feature, &efi.flags) != 0; -} -extern void efi_reboot(enum reboot_mode reboot_mode, const char *__unused); -#else -static inline bool efi_enabled(int feature) -{ - return false; -} -static inline void -efi_reboot(enum reboot_mode reboot_mode, const char *__unused) {} - -static inline bool -efi_capsule_pending(int *reset_type) -{ - return false; -} -#endif - -extern int efi_status_to_err(efi_status_t status); - -/* - * Variable Attributes - */ -#define EFI_VARIABLE_NON_VOLATILE 0x0000000000000001 -#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x0000000000000002 -#define EFI_VARIABLE_RUNTIME_ACCESS 0x0000000000000004 -#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x0000000000000008 -#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x0000000000000010 -#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x0000000000000020 -#define EFI_VARIABLE_APPEND_WRITE 0x0000000000000040 - -#define EFI_VARIABLE_MASK (EFI_VARIABLE_NON_VOLATILE | \ - EFI_VARIABLE_BOOTSERVICE_ACCESS | \ - EFI_VARIABLE_RUNTIME_ACCESS | \ - EFI_VARIABLE_HARDWARE_ERROR_RECORD | \ - EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | \ - EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \ - EFI_VARIABLE_APPEND_WRITE) -/* - * Length of a GUID string (strlen("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee")) - * not including trailing NUL - */ -#define EFI_VARIABLE_GUID_LEN UUID_STRING_LEN - -/* - * The type of search to perform when calling boottime->locate_handle - */ -#define EFI_LOCATE_ALL_HANDLES 0 -#define EFI_LOCATE_BY_REGISTER_NOTIFY 1 -#define EFI_LOCATE_BY_PROTOCOL 2 - -/* - * EFI Device Path information - */ -#define EFI_DEV_HW 0x01 -#define EFI_DEV_PCI 1 -#define EFI_DEV_PCCARD 2 -#define EFI_DEV_MEM_MAPPED 3 -#define EFI_DEV_VENDOR 4 -#define EFI_DEV_CONTROLLER 5 -#define EFI_DEV_ACPI 0x02 -#define EFI_DEV_BASIC_ACPI 1 -#define EFI_DEV_EXPANDED_ACPI 2 -#define EFI_DEV_MSG 0x03 -#define EFI_DEV_MSG_ATAPI 1 -#define EFI_DEV_MSG_SCSI 2 -#define EFI_DEV_MSG_FC 3 -#define EFI_DEV_MSG_1394 4 -#define EFI_DEV_MSG_USB 5 -#define EFI_DEV_MSG_USB_CLASS 15 -#define EFI_DEV_MSG_I20 6 -#define EFI_DEV_MSG_MAC 11 -#define EFI_DEV_MSG_IPV4 12 -#define EFI_DEV_MSG_IPV6 13 -#define EFI_DEV_MSG_INFINIBAND 9 -#define EFI_DEV_MSG_UART 14 -#define EFI_DEV_MSG_VENDOR 10 -#define EFI_DEV_MEDIA 0x04 -#define EFI_DEV_MEDIA_HARD_DRIVE 1 -#define EFI_DEV_MEDIA_CDROM 2 -#define EFI_DEV_MEDIA_VENDOR 3 -#define EFI_DEV_MEDIA_FILE 4 -#define EFI_DEV_MEDIA_PROTOCOL 5 -#define EFI_DEV_BIOS_BOOT 0x05 -#define EFI_DEV_END_PATH 0x7F -#define EFI_DEV_END_PATH2 0xFF -#define EFI_DEV_END_INSTANCE 0x01 -#define EFI_DEV_END_ENTIRE 0xFF - -struct efi_generic_dev_path { - u8 type; - u8 sub_type; - u16 length; -} __attribute ((packed)); - -static inline void memrange_efi_to_native(u64 *addr, u64 *npages) -{ - *npages = PFN_UP(*addr + (*npages<kobj); -} - -int efivars_register(struct efivars *efivars, - const struct efivar_operations *ops, - struct kobject *kobject); -int efivars_unregister(struct efivars *efivars); -struct kobject *efivars_kobject(void); - -int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *), - void *data, bool duplicates, struct list_head *head); - -int efivar_entry_add(struct efivar_entry *entry, struct list_head *head); -int efivar_entry_remove(struct efivar_entry *entry); - -int __efivar_entry_delete(struct efivar_entry *entry); -int efivar_entry_delete(struct efivar_entry *entry); - -int efivar_entry_size(struct efivar_entry *entry, unsigned long *size); -int __efivar_entry_get(struct efivar_entry *entry, u32 *attributes, - unsigned long *size, void *data); -int efivar_entry_get(struct efivar_entry *entry, u32 *attributes, - unsigned long *size, void *data); -int efivar_entry_set(struct efivar_entry *entry, u32 attributes, - unsigned long size, void *data, struct list_head *head); -int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, - unsigned long *size, void *data, bool *set); -int efivar_entry_set_safe(efi_char16_t *name, efi_guid_t vendor, u32 attributes, - bool block, unsigned long size, void *data); - -int efivar_entry_iter_begin(void); -void efivar_entry_iter_end(void); - -int __efivar_entry_iter(int (*func)(struct efivar_entry *, void *), - struct list_head *head, void *data, - struct efivar_entry **prev); -int efivar_entry_iter(int (*func)(struct efivar_entry *, void *), - struct list_head *head, void *data); - -struct efivar_entry *efivar_entry_find(efi_char16_t *name, efi_guid_t guid, - struct list_head *head, bool remove); - -bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, - unsigned long data_size); -bool efivar_variable_is_removable(efi_guid_t vendor, const char *name, - size_t len); - -extern struct work_struct efivar_work; -void efivar_run_worker(void); - -#if defined(CONFIG_EFI_VARS) || defined(CONFIG_EFI_VARS_MODULE) -int efivars_sysfs_init(void); - -#define EFIVARS_DATA_SIZE_MAX 1024 - -#endif /* CONFIG_EFI_VARS */ -extern bool efi_capsule_pending(int *reset_type); - -extern int efi_capsule_supported(efi_guid_t guid, u32 flags, - size_t size, int *reset); - -extern int efi_capsule_update(efi_capsule_header_t *capsule, - struct page **pages); - -#ifdef CONFIG_EFI_RUNTIME_MAP -int efi_runtime_map_init(struct kobject *); -int efi_get_runtime_map_size(void); -int efi_get_runtime_map_desc_size(void); -int efi_runtime_map_copy(void *buf, size_t bufsz); -#else -static inline int efi_runtime_map_init(struct kobject *kobj) -{ - return 0; -} - -static inline int efi_get_runtime_map_size(void) -{ - return 0; -} - -static inline int efi_get_runtime_map_desc_size(void) -{ - return 0; -} - -static inline int efi_runtime_map_copy(void *buf, size_t bufsz) -{ - return 0; -} - -#endif - -/* prototypes shared between arch specific and generic stub code */ - -#define pr_efi(sys_table, msg) efi_printk(sys_table, "EFI stub: "msg) -#define pr_efi_err(sys_table, msg) efi_printk(sys_table, "EFI stub: ERROR: "msg) - -void efi_printk(efi_system_table_t *sys_table_arg, char *str); - -void efi_free(efi_system_table_t *sys_table_arg, unsigned long size, - unsigned long addr); - -char *efi_convert_cmdline(efi_system_table_t *sys_table_arg, - efi_loaded_image_t *image, int *cmd_line_len); - -efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg, - struct efi_boot_memmap *map); - -efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg, - unsigned long size, unsigned long align, - unsigned long *addr); - -efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg, - unsigned long size, unsigned long align, - unsigned long *addr, unsigned long max); - -efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg, - unsigned long *image_addr, - unsigned long image_size, - unsigned long alloc_size, - unsigned long preferred_addr, - unsigned long alignment); - -efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg, - efi_loaded_image_t *image, - char *cmd_line, char *option_string, - unsigned long max_addr, - unsigned long *load_addr, - unsigned long *load_size); - -efi_status_t efi_parse_options(char *cmdline); - -efi_status_t efi_setup_gop(efi_system_table_t *sys_table_arg, - struct screen_info *si, efi_guid_t *proto, - unsigned long size); - -bool efi_runtime_disabled(void); -extern void efi_call_virt_check_flags(unsigned long flags, const char *call); - -/* - * Arch code can implement the following three template macros, avoiding - * reptition for the void/non-void return cases of {__,}efi_call_virt(): - * - * * arch_efi_call_virt_setup() - * - * Sets up the environment for the call (e.g. switching page tables, - * allowing kernel-mode use of floating point, if required). - * - * * arch_efi_call_virt() - * - * Performs the call. The last expression in the macro must be the call - * itself, allowing the logic to be shared by the void and non-void - * cases. - * - * * arch_efi_call_virt_teardown() - * - * Restores the usual kernel environment once the call has returned. - */ - -#define efi_call_virt_pointer(p, f, args...) \ -({ \ - efi_status_t __s; \ - unsigned long __flags; \ - \ - arch_efi_call_virt_setup(); \ - \ - local_save_flags(__flags); \ - __s = arch_efi_call_virt(p, f, args); \ - efi_call_virt_check_flags(__flags, __stringify(f)); \ - \ - arch_efi_call_virt_teardown(); \ - \ - __s; \ -}) - -#define __efi_call_virt_pointer(p, f, args...) \ -({ \ - unsigned long __flags; \ - \ - arch_efi_call_virt_setup(); \ - \ - local_save_flags(__flags); \ - arch_efi_call_virt(p, f, args); \ - efi_call_virt_check_flags(__flags, __stringify(f)); \ - \ - arch_efi_call_virt_teardown(); \ -}) - -typedef efi_status_t (*efi_exit_boot_map_processing)( - efi_system_table_t *sys_table_arg, - struct efi_boot_memmap *map, - void *priv); - -efi_status_t efi_exit_boot_services(efi_system_table_t *sys_table, - void *handle, - struct efi_boot_memmap *map, - void *priv, - efi_exit_boot_map_processing priv_func); -#endif /* _LINUX_EFI_H */ diff --git a/src/linux/include/linux/elevator.h b/src/linux/include/linux/elevator.h deleted file mode 100644 index e7f358d..0000000 --- a/src/linux/include/linux/elevator.h +++ /dev/null @@ -1,219 +0,0 @@ -#ifndef _LINUX_ELEVATOR_H -#define _LINUX_ELEVATOR_H - -#include -#include - -#ifdef CONFIG_BLOCK - -struct io_cq; -struct elevator_type; - -typedef int (elevator_merge_fn) (struct request_queue *, struct request **, - struct bio *); - -typedef void (elevator_merge_req_fn) (struct request_queue *, struct request *, struct request *); - -typedef void (elevator_merged_fn) (struct request_queue *, struct request *, int); - -typedef int (elevator_allow_bio_merge_fn) (struct request_queue *, - struct request *, struct bio *); - -typedef int (elevator_allow_rq_merge_fn) (struct request_queue *, - struct request *, struct request *); - -typedef void (elevator_bio_merged_fn) (struct request_queue *, - struct request *, struct bio *); - -typedef int (elevator_dispatch_fn) (struct request_queue *, int); - -typedef void (elevator_add_req_fn) (struct request_queue *, struct request *); -typedef struct request *(elevator_request_list_fn) (struct request_queue *, struct request *); -typedef void (elevator_completed_req_fn) (struct request_queue *, struct request *); -typedef int (elevator_may_queue_fn) (struct request_queue *, int, int); - -typedef void (elevator_init_icq_fn) (struct io_cq *); -typedef void (elevator_exit_icq_fn) (struct io_cq *); -typedef int (elevator_set_req_fn) (struct request_queue *, struct request *, - struct bio *, gfp_t); -typedef void (elevator_put_req_fn) (struct request *); -typedef void (elevator_activate_req_fn) (struct request_queue *, struct request *); -typedef void (elevator_deactivate_req_fn) (struct request_queue *, struct request *); - -typedef int (elevator_init_fn) (struct request_queue *, - struct elevator_type *e); -typedef void (elevator_exit_fn) (struct elevator_queue *); -typedef void (elevator_registered_fn) (struct request_queue *); - -struct elevator_ops -{ - elevator_merge_fn *elevator_merge_fn; - elevator_merged_fn *elevator_merged_fn; - elevator_merge_req_fn *elevator_merge_req_fn; - elevator_allow_bio_merge_fn *elevator_allow_bio_merge_fn; - elevator_allow_rq_merge_fn *elevator_allow_rq_merge_fn; - elevator_bio_merged_fn *elevator_bio_merged_fn; - - elevator_dispatch_fn *elevator_dispatch_fn; - elevator_add_req_fn *elevator_add_req_fn; - elevator_activate_req_fn *elevator_activate_req_fn; - elevator_deactivate_req_fn *elevator_deactivate_req_fn; - - elevator_completed_req_fn *elevator_completed_req_fn; - - elevator_request_list_fn *elevator_former_req_fn; - elevator_request_list_fn *elevator_latter_req_fn; - - elevator_init_icq_fn *elevator_init_icq_fn; /* see iocontext.h */ - elevator_exit_icq_fn *elevator_exit_icq_fn; /* ditto */ - - elevator_set_req_fn *elevator_set_req_fn; - elevator_put_req_fn *elevator_put_req_fn; - - elevator_may_queue_fn *elevator_may_queue_fn; - - elevator_init_fn *elevator_init_fn; - elevator_exit_fn *elevator_exit_fn; - elevator_registered_fn *elevator_registered_fn; -}; - -#define ELV_NAME_MAX (16) - -struct elv_fs_entry { - struct attribute attr; - ssize_t (*show)(struct elevator_queue *, char *); - ssize_t (*store)(struct elevator_queue *, const char *, size_t); -}; - -/* - * identifies an elevator type, such as AS or deadline - */ -struct elevator_type -{ - /* managed by elevator core */ - struct kmem_cache *icq_cache; - - /* fields provided by elevator implementation */ - struct elevator_ops ops; - size_t icq_size; /* see iocontext.h */ - size_t icq_align; /* ditto */ - struct elv_fs_entry *elevator_attrs; - char elevator_name[ELV_NAME_MAX]; - struct module *elevator_owner; - - /* managed by elevator core */ - char icq_cache_name[ELV_NAME_MAX + 5]; /* elvname + "_io_cq" */ - struct list_head list; -}; - -#define ELV_HASH_BITS 6 - -/* - * each queue has an elevator_queue associated with it - */ -struct elevator_queue -{ - struct elevator_type *type; - void *elevator_data; - struct kobject kobj; - struct mutex sysfs_lock; - unsigned int registered:1; - DECLARE_HASHTABLE(hash, ELV_HASH_BITS); -}; - -/* - * block elevator interface - */ -extern void elv_dispatch_sort(struct request_queue *, struct request *); -extern void elv_dispatch_add_tail(struct request_queue *, struct request *); -extern void elv_add_request(struct request_queue *, struct request *, int); -extern void __elv_add_request(struct request_queue *, struct request *, int); -extern int elv_merge(struct request_queue *, struct request **, struct bio *); -extern void elv_merge_requests(struct request_queue *, struct request *, - struct request *); -extern void elv_merged_request(struct request_queue *, struct request *, int); -extern void elv_bio_merged(struct request_queue *q, struct request *, - struct bio *); -extern void elv_requeue_request(struct request_queue *, struct request *); -extern struct request *elv_former_request(struct request_queue *, struct request *); -extern struct request *elv_latter_request(struct request_queue *, struct request *); -extern int elv_register_queue(struct request_queue *q); -extern void elv_unregister_queue(struct request_queue *q); -extern int elv_may_queue(struct request_queue *, int, int); -extern void elv_completed_request(struct request_queue *, struct request *); -extern int elv_set_request(struct request_queue *q, struct request *rq, - struct bio *bio, gfp_t gfp_mask); -extern void elv_put_request(struct request_queue *, struct request *); -extern void elv_drain_elevator(struct request_queue *); - -/* - * io scheduler registration - */ -extern void __init load_default_elevator_module(void); -extern int elv_register(struct elevator_type *); -extern void elv_unregister(struct elevator_type *); - -/* - * io scheduler sysfs switching - */ -extern ssize_t elv_iosched_show(struct request_queue *, char *); -extern ssize_t elv_iosched_store(struct request_queue *, const char *, size_t); - -extern int elevator_init(struct request_queue *, char *); -extern void elevator_exit(struct elevator_queue *); -extern int elevator_change(struct request_queue *, const char *); -extern bool elv_bio_merge_ok(struct request *, struct bio *); -extern struct elevator_queue *elevator_alloc(struct request_queue *, - struct elevator_type *); - -/* - * Helper functions. - */ -extern struct request *elv_rb_former_request(struct request_queue *, struct request *); -extern struct request *elv_rb_latter_request(struct request_queue *, struct request *); - -/* - * rb support functions. - */ -extern void elv_rb_add(struct rb_root *, struct request *); -extern void elv_rb_del(struct rb_root *, struct request *); -extern struct request *elv_rb_find(struct rb_root *, sector_t); - -/* - * Return values from elevator merger - */ -#define ELEVATOR_NO_MERGE 0 -#define ELEVATOR_FRONT_MERGE 1 -#define ELEVATOR_BACK_MERGE 2 - -/* - * Insertion selection - */ -#define ELEVATOR_INSERT_FRONT 1 -#define ELEVATOR_INSERT_BACK 2 -#define ELEVATOR_INSERT_SORT 3 -#define ELEVATOR_INSERT_REQUEUE 4 -#define ELEVATOR_INSERT_FLUSH 5 -#define ELEVATOR_INSERT_SORT_MERGE 6 - -/* - * return values from elevator_may_queue_fn - */ -enum { - ELV_MQUEUE_MAY, - ELV_MQUEUE_NO, - ELV_MQUEUE_MUST, -}; - -#define rq_end_sector(rq) (blk_rq_pos(rq) + blk_rq_sectors(rq)) -#define rb_entry_rq(node) rb_entry((node), struct request, rb_node) - -#define rq_entry_fifo(ptr) list_entry((ptr), struct request, queuelist) -#define rq_fifo_clear(rq) list_del_init(&(rq)->queuelist) - -#else /* CONFIG_BLOCK */ - -static inline void load_default_elevator_module(void) { } - -#endif /* CONFIG_BLOCK */ -#endif diff --git a/src/linux/include/linux/elf.h b/src/linux/include/linux/elf.h deleted file mode 100644 index 20fa8d8..0000000 --- a/src/linux/include/linux/elf.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef _LINUX_ELF_H -#define _LINUX_ELF_H - -#include -#include - -#ifndef elf_read_implies_exec - /* Executables for which elf_read_implies_exec() returns TRUE will - have the READ_IMPLIES_EXEC personality flag set automatically. - Override in asm/elf.h as needed. */ -# define elf_read_implies_exec(ex, have_pt_gnu_stack) 0 -#endif -#ifndef SET_PERSONALITY -#define SET_PERSONALITY(ex) \ - set_personality(PER_LINUX | (current->personality & (~PER_MASK))) -#endif - -#ifndef SET_PERSONALITY2 -#define SET_PERSONALITY2(ex, state) \ - SET_PERSONALITY(ex) -#endif - -#if ELF_CLASS == ELFCLASS32 - -extern Elf32_Dyn _DYNAMIC []; -#define elfhdr elf32_hdr -#define elf_phdr elf32_phdr -#define elf_shdr elf32_shdr -#define elf_note elf32_note -#define elf_addr_t Elf32_Off -#define Elf_Half Elf32_Half - -#else - -extern Elf64_Dyn _DYNAMIC []; -#define elfhdr elf64_hdr -#define elf_phdr elf64_phdr -#define elf_shdr elf64_shdr -#define elf_note elf64_note -#define elf_addr_t Elf64_Off -#define Elf_Half Elf64_Half - -#endif - -/* Optional callbacks to write extra ELF notes. */ -struct file; -struct coredump_params; - -#ifndef ARCH_HAVE_EXTRA_ELF_NOTES -static inline int elf_coredump_extra_notes_size(void) { return 0; } -static inline int elf_coredump_extra_notes_write(struct coredump_params *cprm) { return 0; } -#else -extern int elf_coredump_extra_notes_size(void); -extern int elf_coredump_extra_notes_write(struct coredump_params *cprm); -#endif -#endif /* _LINUX_ELF_H */ diff --git a/src/linux/include/linux/err.h b/src/linux/include/linux/err.h deleted file mode 100644 index 1e35588..0000000 --- a/src/linux/include/linux/err.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef _LINUX_ERR_H -#define _LINUX_ERR_H - -#include -#include - -#include - -/* - * Kernel pointers have redundant information, so we can use a - * scheme where we can return either an error code or a normal - * pointer with the same return value. - * - * This should be a per-architecture thing, to allow different - * error and pointer decisions. - */ -#define MAX_ERRNO 4095 - -#ifndef __ASSEMBLY__ - -#define IS_ERR_VALUE(x) unlikely((unsigned long)(void *)(x) >= (unsigned long)-MAX_ERRNO) - -static inline void * __must_check ERR_PTR(long error) -{ - return (void *) error; -} - -static inline long __must_check PTR_ERR(__force const void *ptr) -{ - return (long) ptr; -} - -static inline bool __must_check IS_ERR(__force const void *ptr) -{ - return IS_ERR_VALUE((unsigned long)ptr); -} - -static inline bool __must_check IS_ERR_OR_NULL(__force const void *ptr) -{ - return unlikely(!ptr) || IS_ERR_VALUE((unsigned long)ptr); -} - -/** - * ERR_CAST - Explicitly cast an error-valued pointer to another pointer type - * @ptr: The pointer to cast. - * - * Explicitly cast an error-valued pointer to another pointer type in such a - * way as to make it clear that's what's going on. - */ -static inline void * __must_check ERR_CAST(__force const void *ptr) -{ - /* cast away the const */ - return (void *) ptr; -} - -static inline int __must_check PTR_ERR_OR_ZERO(__force const void *ptr) -{ - if (IS_ERR(ptr)) - return PTR_ERR(ptr); - else - return 0; -} - -/* Deprecated */ -#define PTR_RET(p) PTR_ERR_OR_ZERO(p) - -#endif - -#endif /* _LINUX_ERR_H */ diff --git a/src/linux/include/linux/errno.h b/src/linux/include/linux/errno.h deleted file mode 100644 index 7ce9fb1..0000000 --- a/src/linux/include/linux/errno.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef _LINUX_ERRNO_H -#define _LINUX_ERRNO_H - -#include - - -/* - * These should never be seen by user programs. To return one of ERESTART* - * codes, signal_pending() MUST be set. Note that ptrace can observe these - * at syscall exit tracing, but they will never be left for the debugged user - * process to see. - */ -#define ERESTARTSYS 512 -#define ERESTARTNOINTR 513 -#define ERESTARTNOHAND 514 /* restart if no handler.. */ -#define ENOIOCTLCMD 515 /* No ioctl command */ -#define ERESTART_RESTARTBLOCK 516 /* restart by calling sys_restart_syscall */ -#define EPROBE_DEFER 517 /* Driver requests probe retry */ -#define EOPENSTALE 518 /* open found a stale dentry */ - -/* Defined for the NFSv3 protocol */ -#define EBADHANDLE 521 /* Illegal NFS file handle */ -#define ENOTSYNC 522 /* Update synchronization mismatch */ -#define EBADCOOKIE 523 /* Cookie is stale */ -#define ENOTSUPP 524 /* Operation is not supported */ -#define ETOOSMALL 525 /* Buffer or request is too small */ -#define ESERVERFAULT 526 /* An untranslatable error occurred */ -#define EBADTYPE 527 /* Type not supported by server */ -#define EJUKEBOX 528 /* Request initiated, but will not complete before timeout */ -#define EIOCBQUEUED 529 /* iocb queued, will get completion event */ -#define ERECALLCONFLICT 530 /* conflict with recalled state */ - -#endif diff --git a/src/linux/include/linux/errqueue.h b/src/linux/include/linux/errqueue.h deleted file mode 100644 index 9ca23fc..0000000 --- a/src/linux/include/linux/errqueue.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _LINUX_ERRQUEUE_H -#define _LINUX_ERRQUEUE_H 1 - - -#include -#if IS_ENABLED(CONFIG_IPV6) -#include -#endif -#include - -#define SKB_EXT_ERR(skb) ((struct sock_exterr_skb *) ((skb)->cb)) - -struct sock_exterr_skb { - union { - struct inet_skb_parm h4; -#if IS_ENABLED(CONFIG_IPV6) - struct inet6_skb_parm h6; -#endif - } header; - struct sock_extended_err ee; - u16 addr_offset; - __be16 port; -}; - -#endif diff --git a/src/linux/include/linux/etherdevice.h b/src/linux/include/linux/etherdevice.h deleted file mode 100644 index 6fec9e8..0000000 --- a/src/linux/include/linux/etherdevice.h +++ /dev/null @@ -1,476 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. NET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the Ethernet handlers. - * - * Version: @(#)eth.h 1.0.4 05/13/93 - * - * Authors: Ross Biro - * Fred N. van Kempen, - * - * Relocated to include/linux where it belongs by Alan Cox - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ -#ifndef _LINUX_ETHERDEVICE_H -#define _LINUX_ETHERDEVICE_H - -#include -#include -#include -#include -#include - -#ifdef __KERNEL__ -struct device; -int eth_platform_get_mac_address(struct device *dev, u8 *mac_addr); -unsigned char *arch_get_platform_get_mac_address(void); -u32 eth_get_headlen(void *data, unsigned int max_len); -__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev); -extern const struct header_ops eth_header_ops; - -int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, - const void *daddr, const void *saddr, unsigned len); -int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr); -int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh, - __be16 type); -void eth_header_cache_update(struct hh_cache *hh, const struct net_device *dev, - const unsigned char *haddr); -int eth_prepare_mac_addr_change(struct net_device *dev, void *p); -void eth_commit_mac_addr_change(struct net_device *dev, void *p); -int eth_mac_addr(struct net_device *dev, void *p); -int eth_change_mtu(struct net_device *dev, int new_mtu); -int eth_validate_addr(struct net_device *dev); - -struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs, - unsigned int rxqs); -#define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1) -#define alloc_etherdev_mq(sizeof_priv, count) alloc_etherdev_mqs(sizeof_priv, count, count) - -struct sk_buff **eth_gro_receive(struct sk_buff **head, - struct sk_buff *skb); -int eth_gro_complete(struct sk_buff *skb, int nhoff); - -/* Reserved Ethernet Addresses per IEEE 802.1Q */ -static const u8 eth_reserved_addr_base[ETH_ALEN] __aligned(2) = -{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; - -/** - * is_link_local_ether_addr - Determine if given Ethernet address is link-local - * @addr: Pointer to a six-byte array containing the Ethernet address - * - * Return true if address is link local reserved addr (01:80:c2:00:00:0X) per - * IEEE 802.1Q 8.6.3 Frame filtering. - * - * Please note: addr must be aligned to u16. - */ -static inline bool is_link_local_ether_addr(const u8 *addr) -{ - __be16 *a = (__be16 *)addr; - static const __be16 *b = (const __be16 *)eth_reserved_addr_base; - static const __be16 m = cpu_to_be16(0xfff0); - -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) - return (((*(const u32 *)addr) ^ (*(const u32 *)b)) | - (__force int)((a[2] ^ b[2]) & m)) == 0; -#else - return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | ((a[2] ^ b[2]) & m)) == 0; -#endif -} - -/** - * is_zero_ether_addr - Determine if give Ethernet address is all zeros. - * @addr: Pointer to a six-byte array containing the Ethernet address - * - * Return true if the address is all zeroes. - * - * Please note: addr must be aligned to u16. - */ -static inline bool is_zero_ether_addr(const u8 *addr) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) - return ((*(const u32 *)addr) | (*(const u16 *)(addr + 4))) == 0; -#else - return (*(const u16 *)(addr + 0) | - *(const u16 *)(addr + 2) | - *(const u16 *)(addr + 4)) == 0; -#endif -} - -/** - * is_multicast_ether_addr - Determine if the Ethernet address is a multicast. - * @addr: Pointer to a six-byte array containing the Ethernet address - * - * Return true if the address is a multicast address. - * By definition the broadcast address is also a multicast address. - */ -static inline bool is_multicast_ether_addr(const u8 *addr) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) - u32 a = *(const u32 *)addr; -#else - u16 a = *(const u16 *)addr; -#endif -#ifdef __BIG_ENDIAN - return 0x01 & (a >> ((sizeof(a) * 8) - 8)); -#else - return 0x01 & a; -#endif -} - -static inline bool is_multicast_ether_addr_64bits(const u8 addr[6+2]) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 -#ifdef __BIG_ENDIAN - return 0x01 & ((*(const u64 *)addr) >> 56); -#else - return 0x01 & (*(const u64 *)addr); -#endif -#else - return is_multicast_ether_addr(addr); -#endif -} - -/** - * is_local_ether_addr - Determine if the Ethernet address is locally-assigned one (IEEE 802). - * @addr: Pointer to a six-byte array containing the Ethernet address - * - * Return true if the address is a local address. - */ -static inline bool is_local_ether_addr(const u8 *addr) -{ - return 0x02 & addr[0]; -} - -/** - * is_broadcast_ether_addr - Determine if the Ethernet address is broadcast - * @addr: Pointer to a six-byte array containing the Ethernet address - * - * Return true if the address is the broadcast address. - * - * Please note: addr must be aligned to u16. - */ -static inline bool is_broadcast_ether_addr(const u8 *addr) -{ - return (*(const u16 *)(addr + 0) & - *(const u16 *)(addr + 2) & - *(const u16 *)(addr + 4)) == 0xffff; -} - -/** - * is_unicast_ether_addr - Determine if the Ethernet address is unicast - * @addr: Pointer to a six-byte array containing the Ethernet address - * - * Return true if the address is a unicast address. - */ -static inline bool is_unicast_ether_addr(const u8 *addr) -{ - return !is_multicast_ether_addr(addr); -} - -/** - * is_valid_ether_addr - Determine if the given Ethernet address is valid - * @addr: Pointer to a six-byte array containing the Ethernet address - * - * Check that the Ethernet address (MAC) is not 00:00:00:00:00:00, is not - * a multicast address, and is not FF:FF:FF:FF:FF:FF. - * - * Return true if the address is valid. - * - * Please note: addr must be aligned to u16. - */ -static inline bool is_valid_ether_addr(const u8 *addr) -{ - /* FF:FF:FF:FF:FF:FF is a multicast address so we don't need to - * explicitly check for it here. */ - return !is_multicast_ether_addr(addr) && !is_zero_ether_addr(addr); -} - -/** - * eth_proto_is_802_3 - Determine if a given Ethertype/length is a protocol - * @proto: Ethertype/length value to be tested - * - * Check that the value from the Ethertype/length field is a valid Ethertype. - * - * Return true if the valid is an 802.3 supported Ethertype. - */ -static inline bool eth_proto_is_802_3(__be16 proto) -{ -#ifndef __BIG_ENDIAN - /* if CPU is little endian mask off bits representing LSB */ - proto &= htons(0xFF00); -#endif - /* cast both to u16 and compare since LSB can be ignored */ - return (__force u16)proto >= (__force u16)htons(ETH_P_802_3_MIN); -} - -/** - * eth_random_addr - Generate software assigned random Ethernet address - * @addr: Pointer to a six-byte array containing the Ethernet address - * - * Generate a random Ethernet address (MAC) that is not multicast - * and has the local assigned bit set. - */ -static inline void eth_random_addr(u8 *addr) -{ - get_random_bytes(addr, ETH_ALEN); - addr[0] &= 0xfe; /* clear multicast bit */ - addr[0] |= 0x02; /* set local assignment bit (IEEE802) */ -} - -#define random_ether_addr(addr) eth_random_addr(addr) - -/** - * eth_broadcast_addr - Assign broadcast address - * @addr: Pointer to a six-byte array containing the Ethernet address - * - * Assign the broadcast address to the given address array. - */ -static inline void eth_broadcast_addr(u8 *addr) -{ - memset(addr, 0xff, ETH_ALEN); -} - -/** - * eth_zero_addr - Assign zero address - * @addr: Pointer to a six-byte array containing the Ethernet address - * - * Assign the zero address to the given address array. - */ -static inline void eth_zero_addr(u8 *addr) -{ - memset(addr, 0x00, ETH_ALEN); -} - -/** - * eth_hw_addr_random - Generate software assigned random Ethernet and - * set device flag - * @dev: pointer to net_device structure - * - * Generate a random Ethernet address (MAC) to be used by a net device - * and set addr_assign_type so the state can be read by sysfs and be - * used by userspace. - */ -static inline void eth_hw_addr_random(struct net_device *dev) -{ - dev->addr_assign_type = NET_ADDR_RANDOM; - eth_random_addr(dev->dev_addr); -} - -/** - * ether_addr_copy - Copy an Ethernet address - * @dst: Pointer to a six-byte array Ethernet address destination - * @src: Pointer to a six-byte array Ethernet address source - * - * Please note: dst & src must both be aligned to u16. - */ -static inline void ether_addr_copy(u8 *dst, const u8 *src) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) - *(u32 *)dst = *(const u32 *)src; - *(u16 *)(dst + 4) = *(const u16 *)(src + 4); -#else - u16 *a = (u16 *)dst; - const u16 *b = (const u16 *)src; - - a[0] = b[0]; - a[1] = b[1]; - a[2] = b[2]; -#endif -} - -/** - * eth_hw_addr_inherit - Copy dev_addr from another net_device - * @dst: pointer to net_device to copy dev_addr to - * @src: pointer to net_device to copy dev_addr from - * - * Copy the Ethernet address from one net_device to another along with - * the address attributes (addr_assign_type). - */ -static inline void eth_hw_addr_inherit(struct net_device *dst, - struct net_device *src) -{ - dst->addr_assign_type = src->addr_assign_type; - ether_addr_copy(dst->dev_addr, src->dev_addr); -} - -/** - * ether_addr_equal - Compare two Ethernet addresses - * @addr1: Pointer to a six-byte array containing the Ethernet address - * @addr2: Pointer other six-byte array containing the Ethernet address - * - * Compare two Ethernet addresses, returns true if equal - * - * Please note: addr1 & addr2 must both be aligned to u16. - */ -static inline bool ether_addr_equal(const u8 *addr1, const u8 *addr2) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) - u32 fold = ((*(const u32 *)addr1) ^ (*(const u32 *)addr2)) | - ((*(const u16 *)(addr1 + 4)) ^ (*(const u16 *)(addr2 + 4))); - - return fold == 0; -#else - const u16 *a = (const u16 *)addr1; - const u16 *b = (const u16 *)addr2; - - return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) == 0; -#endif -} - -/** - * ether_addr_equal_64bits - Compare two Ethernet addresses - * @addr1: Pointer to an array of 8 bytes - * @addr2: Pointer to an other array of 8 bytes - * - * Compare two Ethernet addresses, returns true if equal, false otherwise. - * - * The function doesn't need any conditional branches and possibly uses - * word memory accesses on CPU allowing cheap unaligned memory reads. - * arrays = { byte1, byte2, byte3, byte4, byte5, byte6, pad1, pad2 } - * - * Please note that alignment of addr1 & addr2 are only guaranteed to be 16 bits. - */ - -static inline bool ether_addr_equal_64bits(const u8 addr1[6+2], - const u8 addr2[6+2]) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 - u64 fold = (*(const u64 *)addr1) ^ (*(const u64 *)addr2); - -#ifdef __BIG_ENDIAN - return (fold >> 16) == 0; -#else - return (fold << 16) == 0; -#endif -#else - return ether_addr_equal(addr1, addr2); -#endif -} - -/** - * ether_addr_equal_unaligned - Compare two not u16 aligned Ethernet addresses - * @addr1: Pointer to a six-byte array containing the Ethernet address - * @addr2: Pointer other six-byte array containing the Ethernet address - * - * Compare two Ethernet addresses, returns true if equal - * - * Please note: Use only when any Ethernet address may not be u16 aligned. - */ -static inline bool ether_addr_equal_unaligned(const u8 *addr1, const u8 *addr2) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) - return ether_addr_equal(addr1, addr2); -#else - return memcmp(addr1, addr2, ETH_ALEN) == 0; -#endif -} - -/** - * ether_addr_equal_masked - Compare two Ethernet addresses with a mask - * @addr1: Pointer to a six-byte array containing the 1st Ethernet address - * @addr2: Pointer to a six-byte array containing the 2nd Ethernet address - * @mask: Pointer to a six-byte array containing the Ethernet address bitmask - * - * Compare two Ethernet addresses with a mask, returns true if for every bit - * set in the bitmask the equivalent bits in the ethernet addresses are equal. - * Using a mask with all bits set is a slower ether_addr_equal. - */ -static inline bool ether_addr_equal_masked(const u8 *addr1, const u8 *addr2, - const u8 *mask) -{ - int i; - - for (i = 0; i < ETH_ALEN; i++) { - if ((addr1[i] ^ addr2[i]) & mask[i]) - return false; - } - - return true; -} - -/** - * is_etherdev_addr - Tell if given Ethernet address belongs to the device. - * @dev: Pointer to a device structure - * @addr: Pointer to a six-byte array containing the Ethernet address - * - * Compare passed address with all addresses of the device. Return true if the - * address if one of the device addresses. - * - * Note that this function calls ether_addr_equal_64bits() so take care of - * the right padding. - */ -static inline bool is_etherdev_addr(const struct net_device *dev, - const u8 addr[6 + 2]) -{ - struct netdev_hw_addr *ha; - bool res = false; - - rcu_read_lock(); - for_each_dev_addr(dev, ha) { - res = ether_addr_equal_64bits(addr, ha->addr); - if (res) - break; - } - rcu_read_unlock(); - return res; -} -#endif /* __KERNEL__ */ - -/** - * compare_ether_header - Compare two Ethernet headers - * @a: Pointer to Ethernet header - * @b: Pointer to Ethernet header - * - * Compare two Ethernet headers, returns 0 if equal. - * This assumes that the network header (i.e., IP header) is 4-byte - * aligned OR the platform can handle unaligned access. This is the - * case for all packets coming into netif_receive_skb or similar - * entry points. - */ - -static inline unsigned long compare_ether_header(const void *a, const void *b) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 - unsigned long fold; - - /* - * We want to compare 14 bytes: - * [a0 ... a13] ^ [b0 ... b13] - * Use two long XOR, ORed together, with an overlap of two bytes. - * [a0 a1 a2 a3 a4 a5 a6 a7 ] ^ [b0 b1 b2 b3 b4 b5 b6 b7 ] | - * [a6 a7 a8 a9 a10 a11 a12 a13] ^ [b6 b7 b8 b9 b10 b11 b12 b13] - * This means the [a6 a7] ^ [b6 b7] part is done two times. - */ - fold = *(unsigned long *)a ^ *(unsigned long *)b; - fold |= *(unsigned long *)(a + 6) ^ *(unsigned long *)(b + 6); - return fold; -#else - u32 *a32 = (u32 *)((u8 *)a + 2); - u32 *b32 = (u32 *)((u8 *)b + 2); - - return (*(u16 *)a ^ *(u16 *)b) | (a32[0] ^ b32[0]) | - (a32[1] ^ b32[1]) | (a32[2] ^ b32[2]); -#endif -} - -/** - * eth_skb_pad - Pad buffer to mininum number of octets for Ethernet frame - * @skb: Buffer to pad - * - * An Ethernet frame should have a minimum size of 60 bytes. This function - * takes short frames and pads them with zeros up to the 60 byte limit. - */ -static inline int eth_skb_pad(struct sk_buff *skb) -{ - return skb_put_padto(skb, ETH_ZLEN); -} - -#endif /* _LINUX_ETHERDEVICE_H */ diff --git a/src/linux/include/linux/ethtool.h b/src/linux/include/linux/ethtool.h deleted file mode 100644 index 9ded8c6..0000000 --- a/src/linux/include/linux/ethtool.h +++ /dev/null @@ -1,376 +0,0 @@ -/* - * ethtool.h: Defines for Linux ethtool. - * - * Copyright (C) 1998 David S. Miller (davem@redhat.com) - * Copyright 2001 Jeff Garzik - * Portions Copyright 2001 Sun Microsystems (thockin@sun.com) - * Portions Copyright 2002 Intel (eli.kupermann@intel.com, - * christopher.leech@intel.com, - * scott.feldman@intel.com) - * Portions Copyright (C) Sun Microsystems 2008 - */ -#ifndef _LINUX_ETHTOOL_H -#define _LINUX_ETHTOOL_H - -#include -#include -#include - -#ifdef CONFIG_COMPAT - -struct compat_ethtool_rx_flow_spec { - u32 flow_type; - union ethtool_flow_union h_u; - struct ethtool_flow_ext h_ext; - union ethtool_flow_union m_u; - struct ethtool_flow_ext m_ext; - compat_u64 ring_cookie; - u32 location; -}; - -struct compat_ethtool_rxnfc { - u32 cmd; - u32 flow_type; - compat_u64 data; - struct compat_ethtool_rx_flow_spec fs; - u32 rule_cnt; - u32 rule_locs[0]; -}; - -#endif /* CONFIG_COMPAT */ - -#include - -/** - * enum ethtool_phys_id_state - indicator state for physical identification - * @ETHTOOL_ID_INACTIVE: Physical ID indicator should be deactivated - * @ETHTOOL_ID_ACTIVE: Physical ID indicator should be activated - * @ETHTOOL_ID_ON: LED should be turned on (used iff %ETHTOOL_ID_ACTIVE - * is not supported) - * @ETHTOOL_ID_OFF: LED should be turned off (used iff %ETHTOOL_ID_ACTIVE - * is not supported) - */ -enum ethtool_phys_id_state { - ETHTOOL_ID_INACTIVE, - ETHTOOL_ID_ACTIVE, - ETHTOOL_ID_ON, - ETHTOOL_ID_OFF -}; - -enum { - ETH_RSS_HASH_TOP_BIT, /* Configurable RSS hash function - Toeplitz */ - ETH_RSS_HASH_XOR_BIT, /* Configurable RSS hash function - Xor */ - - /* - * Add your fresh new hash function bits above and remember to update - * rss_hash_func_strings[] in ethtool.c - */ - ETH_RSS_HASH_FUNCS_COUNT -}; - -#define __ETH_RSS_HASH_BIT(bit) ((u32)1 << (bit)) -#define __ETH_RSS_HASH(name) __ETH_RSS_HASH_BIT(ETH_RSS_HASH_##name##_BIT) - -#define ETH_RSS_HASH_TOP __ETH_RSS_HASH(TOP) -#define ETH_RSS_HASH_XOR __ETH_RSS_HASH(XOR) - -#define ETH_RSS_HASH_UNKNOWN 0 -#define ETH_RSS_HASH_NO_CHANGE 0 - -struct net_device; - -/* Some generic methods drivers may use in their ethtool_ops */ -u32 ethtool_op_get_link(struct net_device *dev); -int ethtool_op_get_ts_info(struct net_device *dev, struct ethtool_ts_info *eti); - -/** - * ethtool_rxfh_indir_default - get default value for RX flow hash indirection - * @index: Index in RX flow hash indirection table - * @n_rx_rings: Number of RX rings to use - * - * This function provides the default policy for RX flow hash indirection. - */ -static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings) -{ - return index % n_rx_rings; -} - -/* number of link mode bits/ulongs handled internally by kernel */ -#define __ETHTOOL_LINK_MODE_MASK_NBITS \ - (__ETHTOOL_LINK_MODE_LAST + 1) - -/* declare a link mode bitmap */ -#define __ETHTOOL_DECLARE_LINK_MODE_MASK(name) \ - DECLARE_BITMAP(name, __ETHTOOL_LINK_MODE_MASK_NBITS) - -/* drivers must ignore base.cmd and base.link_mode_masks_nwords - * fields, but they are allowed to overwrite them (will be ignored). - */ -struct ethtool_link_ksettings { - struct ethtool_link_settings base; - struct { - __ETHTOOL_DECLARE_LINK_MODE_MASK(supported); - __ETHTOOL_DECLARE_LINK_MODE_MASK(advertising); - __ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertising); - } link_modes; -}; - -/** - * ethtool_link_ksettings_zero_link_mode - clear link_ksettings link mode mask - * @ptr : pointer to struct ethtool_link_ksettings - * @name : one of supported/advertising/lp_advertising - */ -#define ethtool_link_ksettings_zero_link_mode(ptr, name) \ - bitmap_zero((ptr)->link_modes.name, __ETHTOOL_LINK_MODE_MASK_NBITS) - -/** - * ethtool_link_ksettings_add_link_mode - set bit in link_ksettings - * link mode mask - * @ptr : pointer to struct ethtool_link_ksettings - * @name : one of supported/advertising/lp_advertising - * @mode : one of the ETHTOOL_LINK_MODE_*_BIT - * (not atomic, no bound checking) - */ -#define ethtool_link_ksettings_add_link_mode(ptr, name, mode) \ - __set_bit(ETHTOOL_LINK_MODE_ ## mode ## _BIT, (ptr)->link_modes.name) - -/** - * ethtool_link_ksettings_test_link_mode - test bit in ksettings link mode mask - * @ptr : pointer to struct ethtool_link_ksettings - * @name : one of supported/advertising/lp_advertising - * @mode : one of the ETHTOOL_LINK_MODE_*_BIT - * (not atomic, no bound checking) - * - * Returns true/false. - */ -#define ethtool_link_ksettings_test_link_mode(ptr, name, mode) \ - test_bit(ETHTOOL_LINK_MODE_ ## mode ## _BIT, (ptr)->link_modes.name) - -extern int -__ethtool_get_link_ksettings(struct net_device *dev, - struct ethtool_link_ksettings *link_ksettings); - -void ethtool_convert_legacy_u32_to_link_mode(unsigned long *dst, - u32 legacy_u32); - -/* return false if src had higher bits set. lower bits always updated. */ -bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32, - const unsigned long *src); - -/** - * struct ethtool_ops - optional netdev operations - * @get_settings: DEPRECATED, use %get_link_ksettings/%set_link_ksettings - * API. Get various device settings including Ethernet link - * settings. The @cmd parameter is expected to have been cleared - * before get_settings is called. Returns a negative error code - * or zero. - * @set_settings: DEPRECATED, use %get_link_ksettings/%set_link_ksettings - * API. Set various device settings including Ethernet link - * settings. Returns a negative error code or zero. - * @get_drvinfo: Report driver/device information. Should only set the - * @driver, @version, @fw_version and @bus_info fields. If not - * implemented, the @driver and @bus_info fields will be filled in - * according to the netdev's parent device. - * @get_regs_len: Get buffer length required for @get_regs - * @get_regs: Get device registers - * @get_wol: Report whether Wake-on-Lan is enabled - * @set_wol: Turn Wake-on-Lan on or off. Returns a negative error code - * or zero. - * @get_msglevel: Report driver message level. This should be the value - * of the @msg_enable field used by netif logging functions. - * @set_msglevel: Set driver message level - * @nway_reset: Restart autonegotiation. Returns a negative error code - * or zero. - * @get_link: Report whether physical link is up. Will only be called if - * the netdev is up. Should usually be set to ethtool_op_get_link(), - * which uses netif_carrier_ok(). - * @get_eeprom: Read data from the device EEPROM. - * Should fill in the magic field. Don't need to check len for zero - * or wraparound. Fill in the data argument with the eeprom values - * from offset to offset + len. Update len to the amount read. - * Returns an error or zero. - * @set_eeprom: Write data to the device EEPROM. - * Should validate the magic field. Don't need to check len for zero - * or wraparound. Update len to the amount written. Returns an error - * or zero. - * @get_coalesce: Get interrupt coalescing parameters. Returns a negative - * error code or zero. - * @set_coalesce: Set interrupt coalescing parameters. Returns a negative - * error code or zero. - * @get_ringparam: Report ring sizes - * @set_ringparam: Set ring sizes. Returns a negative error code or zero. - * @get_pauseparam: Report pause parameters - * @set_pauseparam: Set pause parameters. Returns a negative error code - * or zero. - * @self_test: Run specified self-tests - * @get_strings: Return a set of strings that describe the requested objects - * @set_phys_id: Identify the physical devices, e.g. by flashing an LED - * attached to it. The implementation may update the indicator - * asynchronously or synchronously, but in either case it must return - * quickly. It is initially called with the argument %ETHTOOL_ID_ACTIVE, - * and must either activate asynchronous updates and return zero, return - * a negative error or return a positive frequency for synchronous - * indication (e.g. 1 for one on/off cycle per second). If it returns - * a frequency then it will be called again at intervals with the - * argument %ETHTOOL_ID_ON or %ETHTOOL_ID_OFF and should set the state of - * the indicator accordingly. Finally, it is called with the argument - * %ETHTOOL_ID_INACTIVE and must deactivate the indicator. Returns a - * negative error code or zero. - * @get_ethtool_stats: Return extended statistics about the device. - * This is only useful if the device maintains statistics not - * included in &struct rtnl_link_stats64. - * @begin: Function to be called before any other operation. Returns a - * negative error code or zero. - * @complete: Function to be called after any other operation except - * @begin. Will be called even if the other operation failed. - * @get_priv_flags: Report driver-specific feature flags. - * @set_priv_flags: Set driver-specific feature flags. Returns a negative - * error code or zero. - * @get_sset_count: Get number of strings that @get_strings will write. - * @get_rxnfc: Get RX flow classification rules. Returns a negative - * error code or zero. - * @set_rxnfc: Set RX flow classification rules. Returns a negative - * error code or zero. - * @flash_device: Write a firmware image to device's flash memory. - * Returns a negative error code or zero. - * @reset: Reset (part of) the device, as specified by a bitmask of - * flags from &enum ethtool_reset_flags. Returns a negative - * error code or zero. - * @get_rxfh_key_size: Get the size of the RX flow hash key. - * Returns zero if not supported for this specific device. - * @get_rxfh_indir_size: Get the size of the RX flow hash indirection table. - * Returns zero if not supported for this specific device. - * @get_rxfh: Get the contents of the RX flow hash indirection table, hash key - * and/or hash function. - * Returns a negative error code or zero. - * @set_rxfh: Set the contents of the RX flow hash indirection table, hash - * key, and/or hash function. Arguments which are set to %NULL or zero - * will remain unchanged. - * Returns a negative error code or zero. An error code must be returned - * if at least one unsupported change was requested. - * @get_channels: Get number of channels. - * @set_channels: Set number of channels. Returns a negative error code or - * zero. - * @get_dump_flag: Get dump flag indicating current dump length, version, - * and flag of the device. - * @get_dump_data: Get dump data. - * @set_dump: Set dump specific flags to the device. - * @get_ts_info: Get the time stamping and PTP hardware clock capabilities. - * Drivers supporting transmit time stamps in software should set this to - * ethtool_op_get_ts_info(). - * @get_module_info: Get the size and type of the eeprom contained within - * a plug-in module. - * @get_module_eeprom: Get the eeprom information from the plug-in module - * @get_eee: Get Energy-Efficient (EEE) supported and status. - * @set_eee: Set EEE status (enable/disable) as well as LPI timers. - * @get_per_queue_coalesce: Get interrupt coalescing parameters per queue. - * It must check that the given queue number is valid. If neither a RX nor - * a TX queue has this number, return -EINVAL. If only a RX queue or a TX - * queue has this number, set the inapplicable fields to ~0 and return 0. - * Returns a negative error code or zero. - * @set_per_queue_coalesce: Set interrupt coalescing parameters per queue. - * It must check that the given queue number is valid. If neither a RX nor - * a TX queue has this number, return -EINVAL. If only a RX queue or a TX - * queue has this number, ignore the inapplicable fields. - * Returns a negative error code or zero. - * @get_link_ksettings: When defined, takes precedence over the - * %get_settings method. Get various device settings - * including Ethernet link settings. The %cmd and - * %link_mode_masks_nwords fields should be ignored (use - * %__ETHTOOL_LINK_MODE_MASK_NBITS instead of the latter), any - * change to them will be overwritten by kernel. Returns a - * negative error code or zero. - * @set_link_ksettings: When defined, takes precedence over the - * %set_settings method. Set various device settings including - * Ethernet link settings. The %cmd and %link_mode_masks_nwords - * fields should be ignored (use %__ETHTOOL_LINK_MODE_MASK_NBITS - * instead of the latter), any change to them will be overwritten - * by kernel. Returns a negative error code or zero. - * - * All operations are optional (i.e. the function pointer may be set - * to %NULL) and callers must take this into account. Callers must - * hold the RTNL lock. - * - * See the structures used by these operations for further documentation. - * Note that for all operations using a structure ending with a zero- - * length array, the array is allocated separately in the kernel and - * is passed to the driver as an additional parameter. - * - * See &struct net_device and &struct net_device_ops for documentation - * of the generic netdev features interface. - */ -struct ethtool_ops { - int (*get_settings)(struct net_device *, struct ethtool_cmd *); - int (*set_settings)(struct net_device *, struct ethtool_cmd *); - void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *); - int (*get_regs_len)(struct net_device *); - void (*get_regs)(struct net_device *, struct ethtool_regs *, void *); - void (*get_wol)(struct net_device *, struct ethtool_wolinfo *); - int (*set_wol)(struct net_device *, struct ethtool_wolinfo *); - u32 (*get_msglevel)(struct net_device *); - void (*set_msglevel)(struct net_device *, u32); - int (*nway_reset)(struct net_device *); - u32 (*get_link)(struct net_device *); - int (*get_eeprom_len)(struct net_device *); - int (*get_eeprom)(struct net_device *, - struct ethtool_eeprom *, u8 *); - int (*set_eeprom)(struct net_device *, - struct ethtool_eeprom *, u8 *); - int (*get_coalesce)(struct net_device *, struct ethtool_coalesce *); - int (*set_coalesce)(struct net_device *, struct ethtool_coalesce *); - void (*get_ringparam)(struct net_device *, - struct ethtool_ringparam *); - int (*set_ringparam)(struct net_device *, - struct ethtool_ringparam *); - void (*get_pauseparam)(struct net_device *, - struct ethtool_pauseparam*); - int (*set_pauseparam)(struct net_device *, - struct ethtool_pauseparam*); - void (*self_test)(struct net_device *, struct ethtool_test *, u64 *); - void (*get_strings)(struct net_device *, u32 stringset, u8 *); - int (*set_phys_id)(struct net_device *, enum ethtool_phys_id_state); - void (*get_ethtool_stats)(struct net_device *, - struct ethtool_stats *, u64 *); - int (*begin)(struct net_device *); - void (*complete)(struct net_device *); - u32 (*get_priv_flags)(struct net_device *); - int (*set_priv_flags)(struct net_device *, u32); - int (*get_sset_count)(struct net_device *, int); - int (*get_rxnfc)(struct net_device *, - struct ethtool_rxnfc *, u32 *rule_locs); - int (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *); - int (*flash_device)(struct net_device *, struct ethtool_flash *); - int (*reset)(struct net_device *, u32 *); - u32 (*get_rxfh_key_size)(struct net_device *); - u32 (*get_rxfh_indir_size)(struct net_device *); - int (*get_rxfh)(struct net_device *, u32 *indir, u8 *key, - u8 *hfunc); - int (*set_rxfh)(struct net_device *, const u32 *indir, - const u8 *key, const u8 hfunc); - void (*get_channels)(struct net_device *, struct ethtool_channels *); - int (*set_channels)(struct net_device *, struct ethtool_channels *); - int (*get_dump_flag)(struct net_device *, struct ethtool_dump *); - int (*get_dump_data)(struct net_device *, - struct ethtool_dump *, void *); - int (*set_dump)(struct net_device *, struct ethtool_dump *); - int (*get_ts_info)(struct net_device *, struct ethtool_ts_info *); - int (*get_module_info)(struct net_device *, - struct ethtool_modinfo *); - int (*get_module_eeprom)(struct net_device *, - struct ethtool_eeprom *, u8 *); - int (*get_eee)(struct net_device *, struct ethtool_eee *); - int (*set_eee)(struct net_device *, struct ethtool_eee *); - int (*get_tunable)(struct net_device *, - const struct ethtool_tunable *, void *); - int (*set_tunable)(struct net_device *, - const struct ethtool_tunable *, const void *); - int (*get_per_queue_coalesce)(struct net_device *, u32, - struct ethtool_coalesce *); - int (*set_per_queue_coalesce)(struct net_device *, u32, - struct ethtool_coalesce *); - int (*get_link_ksettings)(struct net_device *, - struct ethtool_link_ksettings *); - int (*set_link_ksettings)(struct net_device *, - const struct ethtool_link_ksettings *); -}; -#endif /* _LINUX_ETHTOOL_H */ diff --git a/src/linux/include/linux/eventfd.h b/src/linux/include/linux/eventfd.h deleted file mode 100644 index ff0b981..0000000 --- a/src/linux/include/linux/eventfd.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * include/linux/eventfd.h - * - * Copyright (C) 2007 Davide Libenzi - * - */ - -#ifndef _LINUX_EVENTFD_H -#define _LINUX_EVENTFD_H - -#include -#include - -/* - * CAREFUL: Check include/uapi/asm-generic/fcntl.h when defining - * new flags, since they might collide with O_* ones. We want - * to re-use O_* flags that couldn't possibly have a meaning - * from eventfd, in order to leave a free define-space for - * shared O_* flags. - */ -#define EFD_SEMAPHORE (1 << 0) -#define EFD_CLOEXEC O_CLOEXEC -#define EFD_NONBLOCK O_NONBLOCK - -#define EFD_SHARED_FCNTL_FLAGS (O_CLOEXEC | O_NONBLOCK) -#define EFD_FLAGS_SET (EFD_SHARED_FCNTL_FLAGS | EFD_SEMAPHORE) - -struct file; - -#ifdef CONFIG_EVENTFD - -struct file *eventfd_file_create(unsigned int count, int flags); -struct eventfd_ctx *eventfd_ctx_get(struct eventfd_ctx *ctx); -void eventfd_ctx_put(struct eventfd_ctx *ctx); -struct file *eventfd_fget(int fd); -struct eventfd_ctx *eventfd_ctx_fdget(int fd); -struct eventfd_ctx *eventfd_ctx_fileget(struct file *file); -__u64 eventfd_signal(struct eventfd_ctx *ctx, __u64 n); -ssize_t eventfd_ctx_read(struct eventfd_ctx *ctx, int no_wait, __u64 *cnt); -int eventfd_ctx_remove_wait_queue(struct eventfd_ctx *ctx, wait_queue_t *wait, - __u64 *cnt); - -#else /* CONFIG_EVENTFD */ - -/* - * Ugly ugly ugly error layer to support modules that uses eventfd but - * pretend to work in !CONFIG_EVENTFD configurations. Namely, AIO. - */ -static inline struct file *eventfd_file_create(unsigned int count, int flags) -{ - return ERR_PTR(-ENOSYS); -} - -static inline struct eventfd_ctx *eventfd_ctx_fdget(int fd) -{ - return ERR_PTR(-ENOSYS); -} - -static inline int eventfd_signal(struct eventfd_ctx *ctx, int n) -{ - return -ENOSYS; -} - -static inline void eventfd_ctx_put(struct eventfd_ctx *ctx) -{ - -} - -static inline ssize_t eventfd_ctx_read(struct eventfd_ctx *ctx, int no_wait, - __u64 *cnt) -{ - return -ENOSYS; -} - -static inline int eventfd_ctx_remove_wait_queue(struct eventfd_ctx *ctx, - wait_queue_t *wait, __u64 *cnt) -{ - return -ENOSYS; -} - -#endif - -#endif /* _LINUX_EVENTFD_H */ - diff --git a/src/linux/include/linux/eventpoll.h b/src/linux/include/linux/eventpoll.h deleted file mode 100644 index 6daf6d4..0000000 --- a/src/linux/include/linux/eventpoll.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * include/linux/eventpoll.h ( Efficient event polling implementation ) - * Copyright (C) 2001,...,2006 Davide Libenzi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Davide Libenzi - * - */ -#ifndef _LINUX_EVENTPOLL_H -#define _LINUX_EVENTPOLL_H - -#include - - -/* Forward declarations to avoid compiler errors */ -struct file; - - -#ifdef CONFIG_EPOLL - -/* Used to initialize the epoll bits inside the "struct file" */ -static inline void eventpoll_init_file(struct file *file) -{ - INIT_LIST_HEAD(&file->f_ep_links); - INIT_LIST_HEAD(&file->f_tfile_llink); -} - - -/* Used to release the epoll bits inside the "struct file" */ -void eventpoll_release_file(struct file *file); - -/* - * This is called from inside fs/file_table.c:__fput() to unlink files - * from the eventpoll interface. We need to have this facility to cleanup - * correctly files that are closed without being removed from the eventpoll - * interface. - */ -static inline void eventpoll_release(struct file *file) -{ - - /* - * Fast check to avoid the get/release of the semaphore. Since - * we're doing this outside the semaphore lock, it might return - * false negatives, but we don't care. It'll help in 99.99% of cases - * to avoid the semaphore lock. False positives simply cannot happen - * because the file in on the way to be removed and nobody ( but - * eventpoll ) has still a reference to this file. - */ - if (likely(list_empty(&file->f_ep_links))) - return; - - /* - * The file is being closed while it is still linked to an epoll - * descriptor. We need to handle this by correctly unlinking it - * from its containers. - */ - eventpoll_release_file(file); -} - -#else - -static inline void eventpoll_init_file(struct file *file) {} -static inline void eventpoll_release(struct file *file) {} - -#endif - -#endif /* #ifndef _LINUX_EVENTPOLL_H */ diff --git a/src/linux/include/linux/evm.h b/src/linux/include/linux/evm.h deleted file mode 100644 index 35ed9a8..0000000 --- a/src/linux/include/linux/evm.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * evm.h - * - * Copyright (c) 2009 IBM Corporation - * Author: Mimi Zohar - */ - -#ifndef _LINUX_EVM_H -#define _LINUX_EVM_H - -#include -#include - -struct integrity_iint_cache; - -#ifdef CONFIG_EVM -extern int evm_set_key(void *key, size_t keylen); -extern enum integrity_status evm_verifyxattr(struct dentry *dentry, - const char *xattr_name, - void *xattr_value, - size_t xattr_value_len, - struct integrity_iint_cache *iint); -extern int evm_inode_setattr(struct dentry *dentry, struct iattr *attr); -extern void evm_inode_post_setattr(struct dentry *dentry, int ia_valid); -extern int evm_inode_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size); -extern void evm_inode_post_setxattr(struct dentry *dentry, - const char *xattr_name, - const void *xattr_value, - size_t xattr_value_len); -extern int evm_inode_removexattr(struct dentry *dentry, const char *xattr_name); -extern void evm_inode_post_removexattr(struct dentry *dentry, - const char *xattr_name); -extern int evm_inode_init_security(struct inode *inode, - const struct xattr *xattr_array, - struct xattr *evm); -#ifdef CONFIG_FS_POSIX_ACL -extern int posix_xattr_acl(const char *xattrname); -#else -static inline int posix_xattr_acl(const char *xattrname) -{ - return 0; -} -#endif -#else - -static inline int evm_set_key(void *key, size_t keylen) -{ - return -EOPNOTSUPP; -} - -#ifdef CONFIG_INTEGRITY -static inline enum integrity_status evm_verifyxattr(struct dentry *dentry, - const char *xattr_name, - void *xattr_value, - size_t xattr_value_len, - struct integrity_iint_cache *iint) -{ - return INTEGRITY_UNKNOWN; -} -#endif - -static inline int evm_inode_setattr(struct dentry *dentry, struct iattr *attr) -{ - return 0; -} - -static inline void evm_inode_post_setattr(struct dentry *dentry, int ia_valid) -{ - return; -} - -static inline int evm_inode_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size) -{ - return 0; -} - -static inline void evm_inode_post_setxattr(struct dentry *dentry, - const char *xattr_name, - const void *xattr_value, - size_t xattr_value_len) -{ - return; -} - -static inline int evm_inode_removexattr(struct dentry *dentry, - const char *xattr_name) -{ - return 0; -} - -static inline void evm_inode_post_removexattr(struct dentry *dentry, - const char *xattr_name) -{ - return; -} - -static inline int evm_inode_init_security(struct inode *inode, - const struct xattr *xattr_array, - struct xattr *evm) -{ - return 0; -} - -#endif /* CONFIG_EVM */ -#endif /* LINUX_EVM_H */ diff --git a/src/linux/include/linux/export.h b/src/linux/include/linux/export.h deleted file mode 100644 index 2a0f61f..0000000 --- a/src/linux/include/linux/export.h +++ /dev/null @@ -1,126 +0,0 @@ -#ifndef _LINUX_EXPORT_H -#define _LINUX_EXPORT_H - -/* - * Export symbols from the kernel to modules. Forked from module.h - * to reduce the amount of pointless cruft we feed to gcc when only - * exporting a simple symbol or two. - * - * Try not to add #includes here. It slows compilation and makes kernel - * hackers place grumpy comments in header files. - */ - -/* Some toolchains use a `_' prefix for all user symbols. */ -#ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX -#define __VMLINUX_SYMBOL(x) _##x -#define __VMLINUX_SYMBOL_STR(x) "_" #x -#else -#define __VMLINUX_SYMBOL(x) x -#define __VMLINUX_SYMBOL_STR(x) #x -#endif - -/* Indirect, so macros are expanded before pasting. */ -#define VMLINUX_SYMBOL(x) __VMLINUX_SYMBOL(x) -#define VMLINUX_SYMBOL_STR(x) __VMLINUX_SYMBOL_STR(x) - -#ifndef __ASSEMBLY__ -struct kernel_symbol -{ - unsigned long value; - const char *name; -}; - -#ifdef MODULE -extern struct module __this_module; -#define THIS_MODULE (&__this_module) -#else -#define THIS_MODULE ((struct module *)0) -#endif - -#ifdef CONFIG_MODULES - -#if defined(__KERNEL__) && !defined(__GENKSYMS__) -#ifdef CONFIG_MODVERSIONS -/* Mark the CRC weak since genksyms apparently decides not to - * generate a checksums for some symbols */ -#define __CRC_SYMBOL(sym, sec) \ - extern __visible void *__crc_##sym __attribute__((weak)); \ - static const unsigned long __kcrctab_##sym \ - __used \ - __attribute__((section("___kcrctab" sec "+" #sym), used)) \ - = (unsigned long) &__crc_##sym; -#else -#define __CRC_SYMBOL(sym, sec) -#endif - -/* For every exported symbol, place a struct in the __ksymtab section */ -#define ___EXPORT_SYMBOL(sym, sec) \ - extern typeof(sym) sym; \ - __CRC_SYMBOL(sym, sec) \ - static const char __kstrtab_##sym[] \ - __attribute__((section("__ksymtab_strings"), aligned(1))) \ - = VMLINUX_SYMBOL_STR(sym); \ - static const struct kernel_symbol __ksymtab_##sym \ - __used \ - __attribute__((section("___ksymtab" sec "+" #sym), used)) \ - = { (unsigned long)&sym, __kstrtab_##sym } - -#if defined(__KSYM_DEPS__) - -/* - * For fine grained build dependencies, we want to tell the build system - * about each possible exported symbol even if they're not actually exported. - * We use a string pattern that is unlikely to be valid code that the build - * system filters out from the preprocessor output (see ksym_dep_filter - * in scripts/Kbuild.include). - */ -#define __EXPORT_SYMBOL(sym, sec) === __KSYM_##sym === - -#elif defined(CONFIG_TRIM_UNUSED_KSYMS) - -#include - -#define __EXPORT_SYMBOL(sym, sec) \ - __cond_export_sym(sym, sec, __is_defined(__KSYM_##sym)) -#define __cond_export_sym(sym, sec, conf) \ - ___cond_export_sym(sym, sec, conf) -#define ___cond_export_sym(sym, sec, enabled) \ - __cond_export_sym_##enabled(sym, sec) -#define __cond_export_sym_1(sym, sec) ___EXPORT_SYMBOL(sym, sec) -#define __cond_export_sym_0(sym, sec) /* nothing */ - -#else -#define __EXPORT_SYMBOL ___EXPORT_SYMBOL -#endif - -#define EXPORT_SYMBOL(sym) \ - __EXPORT_SYMBOL(sym, "") - -#define EXPORT_SYMBOL_GPL(sym) \ - __EXPORT_SYMBOL(sym, "_gpl") - -#define EXPORT_SYMBOL_GPL_FUTURE(sym) \ - __EXPORT_SYMBOL(sym, "_gpl_future") - -#ifdef CONFIG_UNUSED_SYMBOLS -#define EXPORT_UNUSED_SYMBOL(sym) __EXPORT_SYMBOL(sym, "_unused") -#define EXPORT_UNUSED_SYMBOL_GPL(sym) __EXPORT_SYMBOL(sym, "_unused_gpl") -#else -#define EXPORT_UNUSED_SYMBOL(sym) -#define EXPORT_UNUSED_SYMBOL_GPL(sym) -#endif - -#endif /* __GENKSYMS__ */ - -#else /* !CONFIG_MODULES... */ - -#define EXPORT_SYMBOL(sym) -#define EXPORT_SYMBOL_GPL(sym) -#define EXPORT_SYMBOL_GPL_FUTURE(sym) -#define EXPORT_UNUSED_SYMBOL(sym) -#define EXPORT_UNUSED_SYMBOL_GPL(sym) - -#endif /* CONFIG_MODULES */ -#endif /* !__ASSEMBLY__ */ - -#endif /* _LINUX_EXPORT_H */ diff --git a/src/linux/include/linux/exportfs.h b/src/linux/include/linux/exportfs.h deleted file mode 100644 index 5ab958c..0000000 --- a/src/linux/include/linux/exportfs.h +++ /dev/null @@ -1,230 +0,0 @@ -#ifndef LINUX_EXPORTFS_H -#define LINUX_EXPORTFS_H 1 - -#include - -struct dentry; -struct iattr; -struct inode; -struct iomap; -struct super_block; -struct vfsmount; - -/* limit the handle size to NFSv4 handle size now */ -#define MAX_HANDLE_SZ 128 - -/* - * The fileid_type identifies how the file within the filesystem is encoded. - * In theory this is freely set and parsed by the filesystem, but we try to - * stick to conventions so we can share some generic code and don't confuse - * sniffers like ethereal/wireshark. - * - * The filesystem must not use the value '0' or '0xff'. - */ -enum fid_type { - /* - * The root, or export point, of the filesystem. - * (Never actually passed down to the filesystem. - */ - FILEID_ROOT = 0, - - /* - * 32bit inode number, 32 bit generation number. - */ - FILEID_INO32_GEN = 1, - - /* - * 32bit inode number, 32 bit generation number, - * 32 bit parent directory inode number. - */ - FILEID_INO32_GEN_PARENT = 2, - - /* - * 64 bit object ID, 64 bit root object ID, - * 32 bit generation number. - */ - FILEID_BTRFS_WITHOUT_PARENT = 0x4d, - - /* - * 64 bit object ID, 64 bit root object ID, - * 32 bit generation number, - * 64 bit parent object ID, 32 bit parent generation. - */ - FILEID_BTRFS_WITH_PARENT = 0x4e, - - /* - * 64 bit object ID, 64 bit root object ID, - * 32 bit generation number, - * 64 bit parent object ID, 32 bit parent generation, - * 64 bit parent root object ID. - */ - FILEID_BTRFS_WITH_PARENT_ROOT = 0x4f, - - /* - * 32 bit block number, 16 bit partition reference, - * 16 bit unused, 32 bit generation number. - */ - FILEID_UDF_WITHOUT_PARENT = 0x51, - - /* - * 32 bit block number, 16 bit partition reference, - * 16 bit unused, 32 bit generation number, - * 32 bit parent block number, 32 bit parent generation number - */ - FILEID_UDF_WITH_PARENT = 0x52, - - /* - * 64 bit checkpoint number, 64 bit inode number, - * 32 bit generation number. - */ - FILEID_NILFS_WITHOUT_PARENT = 0x61, - - /* - * 64 bit checkpoint number, 64 bit inode number, - * 32 bit generation number, 32 bit parent generation. - * 64 bit parent inode number. - */ - FILEID_NILFS_WITH_PARENT = 0x62, - - /* - * 32 bit generation number, 40 bit i_pos. - */ - FILEID_FAT_WITHOUT_PARENT = 0x71, - - /* - * 32 bit generation number, 40 bit i_pos, - * 32 bit parent generation number, 40 bit parent i_pos - */ - FILEID_FAT_WITH_PARENT = 0x72, - - /* - * 128 bit child FID (struct lu_fid) - * 128 bit parent FID (struct lu_fid) - */ - FILEID_LUSTRE = 0x97, - - /* - * Filesystems must not use 0xff file ID. - */ - FILEID_INVALID = 0xff, -}; - -struct fid { - union { - struct { - u32 ino; - u32 gen; - u32 parent_ino; - u32 parent_gen; - } i32; - struct { - u32 block; - u16 partref; - u16 parent_partref; - u32 generation; - u32 parent_block; - u32 parent_generation; - } udf; - __u32 raw[0]; - }; -}; - -/** - * struct export_operations - for nfsd to communicate with file systems - * @encode_fh: encode a file handle fragment from a dentry - * @fh_to_dentry: find the implied object and get a dentry for it - * @fh_to_parent: find the implied object's parent and get a dentry for it - * @get_name: find the name for a given inode in a given directory - * @get_parent: find the parent of a given directory - * @commit_metadata: commit metadata changes to stable storage - * - * See Documentation/filesystems/nfs/Exporting for details on how to use - * this interface correctly. - * - * encode_fh: - * @encode_fh should store in the file handle fragment @fh (using at most - * @max_len bytes) information that can be used by @decode_fh to recover the - * file referred to by the &struct dentry @de. If the @connectable flag is - * set, the encode_fh() should store sufficient information so that a good - * attempt can be made to find not only the file but also it's place in the - * filesystem. This typically means storing a reference to de->d_parent in - * the filehandle fragment. encode_fh() should return the fileid_type on - * success and on error returns 255 (if the space needed to encode fh is - * greater than @max_len*4 bytes). On error @max_len contains the minimum - * size(in 4 byte unit) needed to encode the file handle. - * - * fh_to_dentry: - * @fh_to_dentry is given a &struct super_block (@sb) and a file handle - * fragment (@fh, @fh_len). It should return a &struct dentry which refers - * to the same file that the file handle fragment refers to. If it cannot, - * it should return a %NULL pointer if the file cannot be found, or an - * %ERR_PTR error code of %ENOMEM if a memory allocation failure occurred. - * Any other error code is treated like %NULL, and will cause an %ESTALE error - * for callers of exportfs_decode_fh(). - * Any suitable dentry can be returned including, if necessary, a new dentry - * created with d_alloc_root. The caller can then find any other extant - * dentries by following the d_alias links. - * - * fh_to_parent: - * Same as @fh_to_dentry, except that it returns a pointer to the parent - * dentry if it was encoded into the filehandle fragment by @encode_fh. - * - * get_name: - * @get_name should find a name for the given @child in the given @parent - * directory. The name should be stored in the @name (with the - * understanding that it is already pointing to a a %NAME_MAX+1 sized - * buffer. get_name() should return %0 on success, a negative error code - * or error. @get_name will be called without @parent->i_mutex held. - * - * get_parent: - * @get_parent should find the parent directory for the given @child which - * is also a directory. In the event that it cannot be found, or storage - * space cannot be allocated, a %ERR_PTR should be returned. - * - * commit_metadata: - * @commit_metadata should commit metadata changes to stable storage. - * - * Locking rules: - * get_parent is called with child->d_inode->i_mutex down - * get_name is not (which is possibly inconsistent) - */ - -struct export_operations { - int (*encode_fh)(struct inode *inode, __u32 *fh, int *max_len, - struct inode *parent); - struct dentry * (*fh_to_dentry)(struct super_block *sb, struct fid *fid, - int fh_len, int fh_type); - struct dentry * (*fh_to_parent)(struct super_block *sb, struct fid *fid, - int fh_len, int fh_type); - int (*get_name)(struct dentry *parent, char *name, - struct dentry *child); - struct dentry * (*get_parent)(struct dentry *child); - int (*commit_metadata)(struct inode *inode); - - int (*get_uuid)(struct super_block *sb, u8 *buf, u32 *len, u64 *offset); - int (*map_blocks)(struct inode *inode, loff_t offset, - u64 len, struct iomap *iomap, - bool write, u32 *device_generation); - int (*commit_blocks)(struct inode *inode, struct iomap *iomaps, - int nr_iomaps, struct iattr *iattr); -}; - -extern int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid, - int *max_len, struct inode *parent); -extern int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, - int *max_len, int connectable); -extern struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid, - int fh_len, int fileid_type, int (*acceptable)(void *, struct dentry *), - void *context); - -/* - * Generic helpers for filesystems. - */ -extern struct dentry *generic_fh_to_dentry(struct super_block *sb, - struct fid *fid, int fh_len, int fh_type, - struct inode *(*get_inode) (struct super_block *sb, u64 ino, u32 gen)); -extern struct dentry *generic_fh_to_parent(struct super_block *sb, - struct fid *fid, int fh_len, int fh_type, - struct inode *(*get_inode) (struct super_block *sb, u64 ino, u32 gen)); - -#endif /* LINUX_EXPORTFS_H */ diff --git a/src/linux/include/linux/extable.h b/src/linux/include/linux/extable.h deleted file mode 100644 index 7effea4..0000000 --- a/src/linux/include/linux/extable.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _LINUX_EXTABLE_H -#define _LINUX_EXTABLE_H - -#include /* for NULL */ - -struct module; -struct exception_table_entry; - -const struct exception_table_entry * -search_extable(const struct exception_table_entry *first, - const struct exception_table_entry *last, - unsigned long value); -void sort_extable(struct exception_table_entry *start, - struct exception_table_entry *finish); -void sort_main_extable(void); -void trim_init_extable(struct module *m); - -/* Given an address, look for it in the exception tables */ -const struct exception_table_entry *search_exception_tables(unsigned long add); - -#ifdef CONFIG_MODULES -/* For extable.c to search modules' exception tables. */ -const struct exception_table_entry *search_module_extables(unsigned long addr); -#else -static inline const struct exception_table_entry * -search_module_extables(unsigned long addr) -{ - return NULL; -} -#endif /*CONFIG_MODULES*/ - -#endif /* _LINUX_EXTABLE_H */ diff --git a/src/linux/include/linux/falloc.h b/src/linux/include/linux/falloc.h deleted file mode 100644 index 7494dc6..0000000 --- a/src/linux/include/linux/falloc.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _FALLOC_H_ -#define _FALLOC_H_ - -#include - - -/* - * Space reservation ioctls and argument structure - * are designed to be compatible with the legacy XFS ioctls. - */ -struct space_resv { - __s16 l_type; - __s16 l_whence; - __s64 l_start; - __s64 l_len; /* len == 0 means until end of file */ - __s32 l_sysid; - __u32 l_pid; - __s32 l_pad[4]; /* reserved area */ -}; - -#define FS_IOC_RESVSP _IOW('X', 40, struct space_resv) -#define FS_IOC_RESVSP64 _IOW('X', 42, struct space_resv) - -#define FALLOC_FL_SUPPORTED_MASK (FALLOC_FL_KEEP_SIZE | \ - FALLOC_FL_PUNCH_HOLE | \ - FALLOC_FL_COLLAPSE_RANGE | \ - FALLOC_FL_ZERO_RANGE | \ - FALLOC_FL_INSERT_RANGE | \ - FALLOC_FL_UNSHARE_RANGE) - -#endif /* _FALLOC_H_ */ diff --git a/src/linux/include/linux/fault-inject.h b/src/linux/include/linux/fault-inject.h deleted file mode 100644 index 9f4956d..0000000 --- a/src/linux/include/linux/fault-inject.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef _LINUX_FAULT_INJECT_H -#define _LINUX_FAULT_INJECT_H - -#ifdef CONFIG_FAULT_INJECTION - -#include -#include -#include -#include - -/* - * For explanation of the elements of this struct, see - * Documentation/fault-injection/fault-injection.txt - */ -struct fault_attr { - unsigned long probability; - unsigned long interval; - atomic_t times; - atomic_t space; - unsigned long verbose; - bool task_filter; - unsigned long stacktrace_depth; - unsigned long require_start; - unsigned long require_end; - unsigned long reject_start; - unsigned long reject_end; - - unsigned long count; - struct ratelimit_state ratelimit_state; - struct dentry *dname; -}; - -#define FAULT_ATTR_INITIALIZER { \ - .interval = 1, \ - .times = ATOMIC_INIT(1), \ - .require_end = ULONG_MAX, \ - .stacktrace_depth = 32, \ - .ratelimit_state = RATELIMIT_STATE_INIT_DISABLED, \ - .verbose = 2, \ - .dname = NULL, \ - } - -#define DECLARE_FAULT_ATTR(name) struct fault_attr name = FAULT_ATTR_INITIALIZER -int setup_fault_attr(struct fault_attr *attr, char *str); -bool should_fail(struct fault_attr *attr, ssize_t size); - -#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS - -struct dentry *fault_create_debugfs_attr(const char *name, - struct dentry *parent, struct fault_attr *attr); - -#else /* CONFIG_FAULT_INJECTION_DEBUG_FS */ - -static inline struct dentry *fault_create_debugfs_attr(const char *name, - struct dentry *parent, struct fault_attr *attr) -{ - return ERR_PTR(-ENODEV); -} - -#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ - -#endif /* CONFIG_FAULT_INJECTION */ - -#ifdef CONFIG_FAILSLAB -extern bool should_failslab(struct kmem_cache *s, gfp_t gfpflags); -#else -static inline bool should_failslab(struct kmem_cache *s, gfp_t gfpflags) -{ - return false; -} -#endif /* CONFIG_FAILSLAB */ - -#endif /* _LINUX_FAULT_INJECT_H */ diff --git a/src/linux/include/linux/fcntl.h b/src/linux/include/linux/fcntl.h deleted file mode 100644 index 76ce329..0000000 --- a/src/linux/include/linux/fcntl.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _LINUX_FCNTL_H -#define _LINUX_FCNTL_H - -#include - - -#ifndef force_o_largefile -#define force_o_largefile() (BITS_PER_LONG != 32) -#endif - -#if BITS_PER_LONG == 32 -#define IS_GETLK32(cmd) ((cmd) == F_GETLK) -#define IS_SETLK32(cmd) ((cmd) == F_SETLK) -#define IS_SETLKW32(cmd) ((cmd) == F_SETLKW) -#define IS_GETLK64(cmd) ((cmd) == F_GETLK64) -#define IS_SETLK64(cmd) ((cmd) == F_SETLK64) -#define IS_SETLKW64(cmd) ((cmd) == F_SETLKW64) -#else -#define IS_GETLK32(cmd) (0) -#define IS_SETLK32(cmd) (0) -#define IS_SETLKW32(cmd) (0) -#define IS_GETLK64(cmd) ((cmd) == F_GETLK) -#define IS_SETLK64(cmd) ((cmd) == F_SETLK) -#define IS_SETLKW64(cmd) ((cmd) == F_SETLKW) -#endif /* BITS_PER_LONG == 32 */ - -#define IS_GETLK(cmd) (IS_GETLK32(cmd) || IS_GETLK64(cmd)) -#define IS_SETLK(cmd) (IS_SETLK32(cmd) || IS_SETLK64(cmd)) -#define IS_SETLKW(cmd) (IS_SETLKW32(cmd) || IS_SETLKW64(cmd)) - -#endif diff --git a/src/linux/include/linux/fd.h b/src/linux/include/linux/fd.h deleted file mode 100644 index 69275bc..0000000 --- a/src/linux/include/linux/fd.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _LINUX_FD_H -#define _LINUX_FD_H - -#include - -#ifdef CONFIG_COMPAT -#include - -struct compat_floppy_struct { - compat_uint_t size; - compat_uint_t sect; - compat_uint_t head; - compat_uint_t track; - compat_uint_t stretch; - unsigned char gap; - unsigned char rate; - unsigned char spec1; - unsigned char fmt_gap; - const compat_caddr_t name; -}; - -#define FDGETPRM32 _IOR(2, 0x04, struct compat_floppy_struct) -#endif -#endif diff --git a/src/linux/include/linux/fddidevice.h b/src/linux/include/linux/fddidevice.h deleted file mode 100644 index 9a79f01..0000000 --- a/src/linux/include/linux/fddidevice.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the FDDI handlers. - * - * Version: @(#)fddidevice.h 1.0.0 08/12/96 - * - * Author: Lawrence V. Stefani, - * - * fddidevice.h is based on previous trdevice.h work by - * Ross Biro - * Fred N. van Kempen, - * Alan Cox, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_FDDIDEVICE_H -#define _LINUX_FDDIDEVICE_H - -#include - -#ifdef __KERNEL__ -__be16 fddi_type_trans(struct sk_buff *skb, struct net_device *dev); -int fddi_change_mtu(struct net_device *dev, int new_mtu); -struct net_device *alloc_fddidev(int sizeof_priv); -#endif - -#endif /* _LINUX_FDDIDEVICE_H */ diff --git a/src/linux/include/linux/fdtable.h b/src/linux/include/linux/fdtable.h deleted file mode 100644 index 6e84b2c..0000000 --- a/src/linux/include/linux/fdtable.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * descriptor table internals; you almost certainly want file.h instead. - */ - -#ifndef __LINUX_FDTABLE_H -#define __LINUX_FDTABLE_H - -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * The default fd array needs to be at least BITS_PER_LONG, - * as this is the granularity returned by copy_fdset(). - */ -#define NR_OPEN_DEFAULT BITS_PER_LONG - -struct fdtable { - unsigned int max_fds; - struct file __rcu **fd; /* current fd array */ - unsigned long *close_on_exec; - unsigned long *open_fds; - unsigned long *full_fds_bits; - struct rcu_head rcu; -}; - -static inline bool close_on_exec(unsigned int fd, const struct fdtable *fdt) -{ - return test_bit(fd, fdt->close_on_exec); -} - -static inline bool fd_is_open(unsigned int fd, const struct fdtable *fdt) -{ - return test_bit(fd, fdt->open_fds); -} - -/* - * Open file table structure - */ -struct files_struct { - /* - * read mostly part - */ - atomic_t count; - bool resize_in_progress; - wait_queue_head_t resize_wait; - - struct fdtable __rcu *fdt; - struct fdtable fdtab; - /* - * written part on a separate cache line in SMP - */ - spinlock_t file_lock ____cacheline_aligned_in_smp; - unsigned int next_fd; - unsigned long close_on_exec_init[1]; - unsigned long open_fds_init[1]; - unsigned long full_fds_bits_init[1]; - struct file __rcu * fd_array[NR_OPEN_DEFAULT]; -}; - -struct file_operations; -struct vfsmount; -struct dentry; - -#define rcu_dereference_check_fdtable(files, fdtfd) \ - rcu_dereference_check((fdtfd), lockdep_is_held(&(files)->file_lock)) - -#define files_fdtable(files) \ - rcu_dereference_check_fdtable((files), (files)->fdt) - -/* - * The caller must ensure that fd table isn't shared or hold rcu or file lock - */ -static inline struct file *__fcheck_files(struct files_struct *files, unsigned int fd) -{ - struct fdtable *fdt = rcu_dereference_raw(files->fdt); - - if (fd < fdt->max_fds) - return rcu_dereference_raw(fdt->fd[fd]); - return NULL; -} - -static inline struct file *fcheck_files(struct files_struct *files, unsigned int fd) -{ - RCU_LOCKDEP_WARN(!rcu_read_lock_held() && - !lockdep_is_held(&files->file_lock), - "suspicious rcu_dereference_check() usage"); - return __fcheck_files(files, fd); -} - -/* - * Check whether the specified fd has an open file. - */ -#define fcheck(fd) fcheck_files(current->files, fd) - -struct task_struct; - -struct files_struct *get_files_struct(struct task_struct *); -void put_files_struct(struct files_struct *fs); -void reset_files_struct(struct files_struct *); -int unshare_files(struct files_struct **); -struct files_struct *dup_fd(struct files_struct *, int *) __latent_entropy; -void do_close_on_exec(struct files_struct *); -int iterate_fd(struct files_struct *, unsigned, - int (*)(const void *, struct file *, unsigned), - const void *); - -extern int __alloc_fd(struct files_struct *files, - unsigned start, unsigned end, unsigned flags); -extern void __fd_install(struct files_struct *files, - unsigned int fd, struct file *file); -extern int __close_fd(struct files_struct *files, - unsigned int fd); - -extern struct kmem_cache *files_cachep; - -#endif /* __LINUX_FDTABLE_H */ diff --git a/src/linux/include/linux/file.h b/src/linux/include/linux/file.h deleted file mode 100644 index 7444f5f..0000000 --- a/src/linux/include/linux/file.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Wrapper functions for accessing the file_struct fd array. - */ - -#ifndef __LINUX_FILE_H -#define __LINUX_FILE_H - -#include -#include -#include - -struct file; - -extern void fput(struct file *); - -struct file_operations; -struct vfsmount; -struct dentry; -struct path; -extern struct file *alloc_file(struct path *, fmode_t mode, - const struct file_operations *fop); - -static inline void fput_light(struct file *file, int fput_needed) -{ - if (fput_needed) - fput(file); -} - -struct fd { - struct file *file; - unsigned int flags; -}; -#define FDPUT_FPUT 1 -#define FDPUT_POS_UNLOCK 2 - -static inline void fdput(struct fd fd) -{ - if (fd.flags & FDPUT_FPUT) - fput(fd.file); -} - -extern struct file *fget(unsigned int fd); -extern struct file *fget_raw(unsigned int fd); -extern unsigned long __fdget(unsigned int fd); -extern unsigned long __fdget_raw(unsigned int fd); -extern unsigned long __fdget_pos(unsigned int fd); -extern void __f_unlock_pos(struct file *); - -static inline struct fd __to_fd(unsigned long v) -{ - return (struct fd){(struct file *)(v & ~3),v & 3}; -} - -static inline struct fd fdget(unsigned int fd) -{ - return __to_fd(__fdget(fd)); -} - -static inline struct fd fdget_raw(unsigned int fd) -{ - return __to_fd(__fdget_raw(fd)); -} - -static inline struct fd fdget_pos(int fd) -{ - return __to_fd(__fdget_pos(fd)); -} - -static inline void fdput_pos(struct fd f) -{ - if (f.flags & FDPUT_POS_UNLOCK) - __f_unlock_pos(f.file); - fdput(f); -} - -extern int f_dupfd(unsigned int from, struct file *file, unsigned flags); -extern int replace_fd(unsigned fd, struct file *file, unsigned flags); -extern void set_close_on_exec(unsigned int fd, int flag); -extern bool get_close_on_exec(unsigned int fd); -extern void put_filp(struct file *); -extern int get_unused_fd_flags(unsigned flags); -extern void put_unused_fd(unsigned int fd); - -extern void fd_install(unsigned int fd, struct file *file); - -extern void flush_delayed_fput(void); -extern void __fput_sync(struct file *); - -#endif /* __LINUX_FILE_H */ diff --git a/src/linux/include/linux/filter.h b/src/linux/include/linux/filter.h deleted file mode 100644 index 1f09c52..0000000 --- a/src/linux/include/linux/filter.h +++ /dev/null @@ -1,737 +0,0 @@ -/* - * Linux Socket Filter Data Structures - */ -#ifndef __LINUX_FILTER_H__ -#define __LINUX_FILTER_H__ - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include - -struct sk_buff; -struct sock; -struct seccomp_data; -struct bpf_prog_aux; - -/* ArgX, context and stack frame pointer register positions. Note, - * Arg1, Arg2, Arg3, etc are used as argument mappings of function - * calls in BPF_CALL instruction. - */ -#define BPF_REG_ARG1 BPF_REG_1 -#define BPF_REG_ARG2 BPF_REG_2 -#define BPF_REG_ARG3 BPF_REG_3 -#define BPF_REG_ARG4 BPF_REG_4 -#define BPF_REG_ARG5 BPF_REG_5 -#define BPF_REG_CTX BPF_REG_6 -#define BPF_REG_FP BPF_REG_10 - -/* Additional register mappings for converted user programs. */ -#define BPF_REG_A BPF_REG_0 -#define BPF_REG_X BPF_REG_7 -#define BPF_REG_TMP BPF_REG_8 - -/* Kernel hidden auxiliary/helper register for hardening step. - * Only used by eBPF JITs. It's nothing more than a temporary - * register that JITs use internally, only that here it's part - * of eBPF instructions that have been rewritten for blinding - * constants. See JIT pre-step in bpf_jit_blind_constants(). - */ -#define BPF_REG_AX MAX_BPF_REG -#define MAX_BPF_JIT_REG (MAX_BPF_REG + 1) - -/* BPF program can access up to 512 bytes of stack space. */ -#define MAX_BPF_STACK 512 - -/* Helper macros for filter block array initializers. */ - -/* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */ - -#define BPF_ALU64_REG(OP, DST, SRC) \ - ((struct bpf_insn) { \ - .code = BPF_ALU64 | BPF_OP(OP) | BPF_X, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = 0 }) - -#define BPF_ALU32_REG(OP, DST, SRC) \ - ((struct bpf_insn) { \ - .code = BPF_ALU | BPF_OP(OP) | BPF_X, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = 0 }) - -/* ALU ops on immediates, bpf_add|sub|...: dst_reg += imm32 */ - -#define BPF_ALU64_IMM(OP, DST, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_ALU64 | BPF_OP(OP) | BPF_K, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = 0, \ - .imm = IMM }) - -#define BPF_ALU32_IMM(OP, DST, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_ALU | BPF_OP(OP) | BPF_K, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = 0, \ - .imm = IMM }) - -/* Endianess conversion, cpu_to_{l,b}e(), {l,b}e_to_cpu() */ - -#define BPF_ENDIAN(TYPE, DST, LEN) \ - ((struct bpf_insn) { \ - .code = BPF_ALU | BPF_END | BPF_SRC(TYPE), \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = 0, \ - .imm = LEN }) - -/* Short form of mov, dst_reg = src_reg */ - -#define BPF_MOV64_REG(DST, SRC) \ - ((struct bpf_insn) { \ - .code = BPF_ALU64 | BPF_MOV | BPF_X, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = 0 }) - -#define BPF_MOV32_REG(DST, SRC) \ - ((struct bpf_insn) { \ - .code = BPF_ALU | BPF_MOV | BPF_X, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = 0 }) - -/* Short form of mov, dst_reg = imm32 */ - -#define BPF_MOV64_IMM(DST, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_ALU64 | BPF_MOV | BPF_K, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = 0, \ - .imm = IMM }) - -#define BPF_MOV32_IMM(DST, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_ALU | BPF_MOV | BPF_K, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = 0, \ - .imm = IMM }) - -/* BPF_LD_IMM64 macro encodes single 'load 64-bit immediate' insn */ -#define BPF_LD_IMM64(DST, IMM) \ - BPF_LD_IMM64_RAW(DST, 0, IMM) - -#define BPF_LD_IMM64_RAW(DST, SRC, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_LD | BPF_DW | BPF_IMM, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = (__u32) (IMM) }), \ - ((struct bpf_insn) { \ - .code = 0, /* zero is reserved opcode */ \ - .dst_reg = 0, \ - .src_reg = 0, \ - .off = 0, \ - .imm = ((__u64) (IMM)) >> 32 }) - -/* pseudo BPF_LD_IMM64 insn used to refer to process-local map_fd */ -#define BPF_LD_MAP_FD(DST, MAP_FD) \ - BPF_LD_IMM64_RAW(DST, BPF_PSEUDO_MAP_FD, MAP_FD) - -/* Short form of mov based on type, BPF_X: dst_reg = src_reg, BPF_K: dst_reg = imm32 */ - -#define BPF_MOV64_RAW(TYPE, DST, SRC, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_ALU64 | BPF_MOV | BPF_SRC(TYPE), \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = IMM }) - -#define BPF_MOV32_RAW(TYPE, DST, SRC, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_ALU | BPF_MOV | BPF_SRC(TYPE), \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = IMM }) - -/* Direct packet access, R0 = *(uint *) (skb->data + imm32) */ - -#define BPF_LD_ABS(SIZE, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_LD | BPF_SIZE(SIZE) | BPF_ABS, \ - .dst_reg = 0, \ - .src_reg = 0, \ - .off = 0, \ - .imm = IMM }) - -/* Indirect packet access, R0 = *(uint *) (skb->data + src_reg + imm32) */ - -#define BPF_LD_IND(SIZE, SRC, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_LD | BPF_SIZE(SIZE) | BPF_IND, \ - .dst_reg = 0, \ - .src_reg = SRC, \ - .off = 0, \ - .imm = IMM }) - -/* Memory load, dst_reg = *(uint *) (src_reg + off16) */ - -#define BPF_LDX_MEM(SIZE, DST, SRC, OFF) \ - ((struct bpf_insn) { \ - .code = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = OFF, \ - .imm = 0 }) - -/* Memory store, *(uint *) (dst_reg + off16) = src_reg */ - -#define BPF_STX_MEM(SIZE, DST, SRC, OFF) \ - ((struct bpf_insn) { \ - .code = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = OFF, \ - .imm = 0 }) - -/* Atomic memory add, *(uint *)(dst_reg + off16) += src_reg */ - -#define BPF_STX_XADD(SIZE, DST, SRC, OFF) \ - ((struct bpf_insn) { \ - .code = BPF_STX | BPF_SIZE(SIZE) | BPF_XADD, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = OFF, \ - .imm = 0 }) - -/* Memory store, *(uint *) (dst_reg + off16) = imm32 */ - -#define BPF_ST_MEM(SIZE, DST, OFF, IMM) \ - ((struct bpf_insn) { \ - .code = BPF_ST | BPF_SIZE(SIZE) | BPF_MEM, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = OFF, \ - .imm = IMM }) - -/* Conditional jumps against registers, if (dst_reg 'op' src_reg) goto pc + off16 */ - -#define BPF_JMP_REG(OP, DST, SRC, OFF) \ - ((struct bpf_insn) { \ - .code = BPF_JMP | BPF_OP(OP) | BPF_X, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = OFF, \ - .imm = 0 }) - -/* Conditional jumps against immediates, if (dst_reg 'op' imm32) goto pc + off16 */ - -#define BPF_JMP_IMM(OP, DST, IMM, OFF) \ - ((struct bpf_insn) { \ - .code = BPF_JMP | BPF_OP(OP) | BPF_K, \ - .dst_reg = DST, \ - .src_reg = 0, \ - .off = OFF, \ - .imm = IMM }) - -/* Function call */ - -#define BPF_EMIT_CALL(FUNC) \ - ((struct bpf_insn) { \ - .code = BPF_JMP | BPF_CALL, \ - .dst_reg = 0, \ - .src_reg = 0, \ - .off = 0, \ - .imm = ((FUNC) - __bpf_call_base) }) - -/* Raw code statement block */ - -#define BPF_RAW_INSN(CODE, DST, SRC, OFF, IMM) \ - ((struct bpf_insn) { \ - .code = CODE, \ - .dst_reg = DST, \ - .src_reg = SRC, \ - .off = OFF, \ - .imm = IMM }) - -/* Program exit */ - -#define BPF_EXIT_INSN() \ - ((struct bpf_insn) { \ - .code = BPF_JMP | BPF_EXIT, \ - .dst_reg = 0, \ - .src_reg = 0, \ - .off = 0, \ - .imm = 0 }) - -/* Internal classic blocks for direct assignment */ - -#define __BPF_STMT(CODE, K) \ - ((struct sock_filter) BPF_STMT(CODE, K)) - -#define __BPF_JUMP(CODE, K, JT, JF) \ - ((struct sock_filter) BPF_JUMP(CODE, K, JT, JF)) - -#define bytes_to_bpf_size(bytes) \ -({ \ - int bpf_size = -EINVAL; \ - \ - if (bytes == sizeof(u8)) \ - bpf_size = BPF_B; \ - else if (bytes == sizeof(u16)) \ - bpf_size = BPF_H; \ - else if (bytes == sizeof(u32)) \ - bpf_size = BPF_W; \ - else if (bytes == sizeof(u64)) \ - bpf_size = BPF_DW; \ - \ - bpf_size; \ -}) - -#define BPF_SIZEOF(type) \ - ({ \ - const int __size = bytes_to_bpf_size(sizeof(type)); \ - BUILD_BUG_ON(__size < 0); \ - __size; \ - }) - -#define BPF_FIELD_SIZEOF(type, field) \ - ({ \ - const int __size = bytes_to_bpf_size(FIELD_SIZEOF(type, field)); \ - BUILD_BUG_ON(__size < 0); \ - __size; \ - }) - -#define __BPF_MAP_0(m, v, ...) v -#define __BPF_MAP_1(m, v, t, a, ...) m(t, a) -#define __BPF_MAP_2(m, v, t, a, ...) m(t, a), __BPF_MAP_1(m, v, __VA_ARGS__) -#define __BPF_MAP_3(m, v, t, a, ...) m(t, a), __BPF_MAP_2(m, v, __VA_ARGS__) -#define __BPF_MAP_4(m, v, t, a, ...) m(t, a), __BPF_MAP_3(m, v, __VA_ARGS__) -#define __BPF_MAP_5(m, v, t, a, ...) m(t, a), __BPF_MAP_4(m, v, __VA_ARGS__) - -#define __BPF_REG_0(...) __BPF_PAD(5) -#define __BPF_REG_1(...) __BPF_MAP(1, __VA_ARGS__), __BPF_PAD(4) -#define __BPF_REG_2(...) __BPF_MAP(2, __VA_ARGS__), __BPF_PAD(3) -#define __BPF_REG_3(...) __BPF_MAP(3, __VA_ARGS__), __BPF_PAD(2) -#define __BPF_REG_4(...) __BPF_MAP(4, __VA_ARGS__), __BPF_PAD(1) -#define __BPF_REG_5(...) __BPF_MAP(5, __VA_ARGS__) - -#define __BPF_MAP(n, ...) __BPF_MAP_##n(__VA_ARGS__) -#define __BPF_REG(n, ...) __BPF_REG_##n(__VA_ARGS__) - -#define __BPF_CAST(t, a) \ - (__force t) \ - (__force \ - typeof(__builtin_choose_expr(sizeof(t) == sizeof(unsigned long), \ - (unsigned long)0, (t)0))) a -#define __BPF_V void -#define __BPF_N - -#define __BPF_DECL_ARGS(t, a) t a -#define __BPF_DECL_REGS(t, a) u64 a - -#define __BPF_PAD(n) \ - __BPF_MAP(n, __BPF_DECL_ARGS, __BPF_N, u64, __ur_1, u64, __ur_2, \ - u64, __ur_3, u64, __ur_4, u64, __ur_5) - -#define BPF_CALL_x(x, name, ...) \ - static __always_inline \ - u64 ____##name(__BPF_MAP(x, __BPF_DECL_ARGS, __BPF_V, __VA_ARGS__)); \ - u64 name(__BPF_REG(x, __BPF_DECL_REGS, __BPF_N, __VA_ARGS__)); \ - u64 name(__BPF_REG(x, __BPF_DECL_REGS, __BPF_N, __VA_ARGS__)) \ - { \ - return ____##name(__BPF_MAP(x,__BPF_CAST,__BPF_N,__VA_ARGS__));\ - } \ - static __always_inline \ - u64 ____##name(__BPF_MAP(x, __BPF_DECL_ARGS, __BPF_V, __VA_ARGS__)) - -#define BPF_CALL_0(name, ...) BPF_CALL_x(0, name, __VA_ARGS__) -#define BPF_CALL_1(name, ...) BPF_CALL_x(1, name, __VA_ARGS__) -#define BPF_CALL_2(name, ...) BPF_CALL_x(2, name, __VA_ARGS__) -#define BPF_CALL_3(name, ...) BPF_CALL_x(3, name, __VA_ARGS__) -#define BPF_CALL_4(name, ...) BPF_CALL_x(4, name, __VA_ARGS__) -#define BPF_CALL_5(name, ...) BPF_CALL_x(5, name, __VA_ARGS__) - -#ifdef CONFIG_COMPAT -/* A struct sock_filter is architecture independent. */ -struct compat_sock_fprog { - u16 len; - compat_uptr_t filter; /* struct sock_filter * */ -}; -#endif - -struct sock_fprog_kern { - u16 len; - struct sock_filter *filter; -}; - -struct bpf_binary_header { - unsigned int pages; - u8 image[]; -}; - -struct bpf_prog { - u16 pages; /* Number of allocated pages */ - kmemcheck_bitfield_begin(meta); - u16 jited:1, /* Is our filter JIT'ed? */ - gpl_compatible:1, /* Is filter GPL compatible? */ - cb_access:1, /* Is control block accessed? */ - dst_needed:1; /* Do we need dst entry? */ - kmemcheck_bitfield_end(meta); - u32 len; /* Number of filter blocks */ - enum bpf_prog_type type; /* Type of BPF program */ - struct bpf_prog_aux *aux; /* Auxiliary fields */ - struct sock_fprog_kern *orig_prog; /* Original BPF program */ - unsigned int (*bpf_func)(const struct sk_buff *skb, - const struct bpf_insn *filter); - /* Instructions for interpreter */ - union { - struct sock_filter insns[0]; - struct bpf_insn insnsi[0]; - }; -}; - -struct sk_filter { - atomic_t refcnt; - struct rcu_head rcu; - struct bpf_prog *prog; -}; - -#define BPF_PROG_RUN(filter, ctx) (*filter->bpf_func)(ctx, filter->insnsi) - -#define BPF_SKB_CB_LEN QDISC_CB_PRIV_LEN - -struct bpf_skb_data_end { - struct qdisc_skb_cb qdisc_cb; - void *data_end; -}; - -struct xdp_buff { - void *data; - void *data_end; -}; - -/* compute the linear packet data range [data, data_end) which - * will be accessed by cls_bpf and act_bpf programs - */ -static inline void bpf_compute_data_end(struct sk_buff *skb) -{ - struct bpf_skb_data_end *cb = (struct bpf_skb_data_end *)skb->cb; - - BUILD_BUG_ON(sizeof(*cb) > FIELD_SIZEOF(struct sk_buff, cb)); - cb->data_end = skb->data + skb_headlen(skb); -} - -static inline u8 *bpf_skb_cb(struct sk_buff *skb) -{ - /* eBPF programs may read/write skb->cb[] area to transfer meta - * data between tail calls. Since this also needs to work with - * tc, that scratch memory is mapped to qdisc_skb_cb's data area. - * - * In some socket filter cases, the cb unfortunately needs to be - * saved/restored so that protocol specific skb->cb[] data won't - * be lost. In any case, due to unpriviledged eBPF programs - * attached to sockets, we need to clear the bpf_skb_cb() area - * to not leak previous contents to user space. - */ - BUILD_BUG_ON(FIELD_SIZEOF(struct __sk_buff, cb) != BPF_SKB_CB_LEN); - BUILD_BUG_ON(FIELD_SIZEOF(struct __sk_buff, cb) != - FIELD_SIZEOF(struct qdisc_skb_cb, data)); - - return qdisc_skb_cb(skb)->data; -} - -static inline u32 bpf_prog_run_save_cb(const struct bpf_prog *prog, - struct sk_buff *skb) -{ - u8 *cb_data = bpf_skb_cb(skb); - u8 cb_saved[BPF_SKB_CB_LEN]; - u32 res; - - if (unlikely(prog->cb_access)) { - memcpy(cb_saved, cb_data, sizeof(cb_saved)); - memset(cb_data, 0, sizeof(cb_saved)); - } - - res = BPF_PROG_RUN(prog, skb); - - if (unlikely(prog->cb_access)) - memcpy(cb_data, cb_saved, sizeof(cb_saved)); - - return res; -} - -static inline u32 bpf_prog_run_clear_cb(const struct bpf_prog *prog, - struct sk_buff *skb) -{ - u8 *cb_data = bpf_skb_cb(skb); - - if (unlikely(prog->cb_access)) - memset(cb_data, 0, BPF_SKB_CB_LEN); - - return BPF_PROG_RUN(prog, skb); -} - -static inline u32 bpf_prog_run_xdp(const struct bpf_prog *prog, - struct xdp_buff *xdp) -{ - u32 ret; - - rcu_read_lock(); - ret = BPF_PROG_RUN(prog, (void *)xdp); - rcu_read_unlock(); - - return ret; -} - -static inline unsigned int bpf_prog_size(unsigned int proglen) -{ - return max(sizeof(struct bpf_prog), - offsetof(struct bpf_prog, insns[proglen])); -} - -static inline bool bpf_prog_was_classic(const struct bpf_prog *prog) -{ - /* When classic BPF programs have been loaded and the arch - * does not have a classic BPF JIT (anymore), they have been - * converted via bpf_migrate_filter() to eBPF and thus always - * have an unspec program type. - */ - return prog->type == BPF_PROG_TYPE_UNSPEC; -} - -#define bpf_classic_proglen(fprog) (fprog->len * sizeof(fprog->filter[0])) - -#ifdef CONFIG_DEBUG_SET_MODULE_RONX -static inline void bpf_prog_lock_ro(struct bpf_prog *fp) -{ - set_memory_ro((unsigned long)fp, fp->pages); -} - -static inline void bpf_prog_unlock_ro(struct bpf_prog *fp) -{ - set_memory_rw((unsigned long)fp, fp->pages); -} -#else -static inline void bpf_prog_lock_ro(struct bpf_prog *fp) -{ -} - -static inline void bpf_prog_unlock_ro(struct bpf_prog *fp) -{ -} -#endif /* CONFIG_DEBUG_SET_MODULE_RONX */ - -int sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap); -static inline int sk_filter(struct sock *sk, struct sk_buff *skb) -{ - return sk_filter_trim_cap(sk, skb, 1); -} - -struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err); -void bpf_prog_free(struct bpf_prog *fp); - -struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags); -struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size, - gfp_t gfp_extra_flags); -void __bpf_prog_free(struct bpf_prog *fp); - -static inline void bpf_prog_unlock_free(struct bpf_prog *fp) -{ - bpf_prog_unlock_ro(fp); - __bpf_prog_free(fp); -} - -typedef int (*bpf_aux_classic_check_t)(struct sock_filter *filter, - unsigned int flen); - -int bpf_prog_create(struct bpf_prog **pfp, struct sock_fprog_kern *fprog); -int bpf_prog_create_from_user(struct bpf_prog **pfp, struct sock_fprog *fprog, - bpf_aux_classic_check_t trans, bool save_orig); -void bpf_prog_destroy(struct bpf_prog *fp); - -int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk); -int sk_attach_bpf(u32 ufd, struct sock *sk); -int sk_reuseport_attach_filter(struct sock_fprog *fprog, struct sock *sk); -int sk_reuseport_attach_bpf(u32 ufd, struct sock *sk); -int sk_detach_filter(struct sock *sk); -int sk_get_filter(struct sock *sk, struct sock_filter __user *filter, - unsigned int len); - -bool sk_filter_charge(struct sock *sk, struct sk_filter *fp); -void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp); - -u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5); - -struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog); -bool bpf_helper_changes_skb_data(void *func); - -struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off, - const struct bpf_insn *patch, u32 len); -void bpf_warn_invalid_xdp_action(u32 act); - -#ifdef CONFIG_BPF_JIT -extern int bpf_jit_enable; -extern int bpf_jit_harden; - -typedef void (*bpf_jit_fill_hole_t)(void *area, unsigned int size); - -struct bpf_binary_header * -bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr, - unsigned int alignment, - bpf_jit_fill_hole_t bpf_fill_ill_insns); -void bpf_jit_binary_free(struct bpf_binary_header *hdr); - -void bpf_jit_compile(struct bpf_prog *fp); -void bpf_jit_free(struct bpf_prog *fp); - -struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *fp); -void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other); - -static inline void bpf_jit_dump(unsigned int flen, unsigned int proglen, - u32 pass, void *image) -{ - pr_err("flen=%u proglen=%u pass=%u image=%pK from=%s pid=%d\n", flen, - proglen, pass, image, current->comm, task_pid_nr(current)); - - if (image) - print_hex_dump(KERN_ERR, "JIT code: ", DUMP_PREFIX_OFFSET, - 16, 1, image, proglen, false); -} - -static inline bool bpf_jit_is_ebpf(void) -{ -# ifdef CONFIG_HAVE_EBPF_JIT - return true; -# else - return false; -# endif -} - -static inline bool bpf_jit_blinding_enabled(void) -{ - /* These are the prerequisites, should someone ever have the - * idea to call blinding outside of them, we make sure to - * bail out. - */ - if (!bpf_jit_is_ebpf()) - return false; - if (!bpf_jit_enable) - return false; - if (!bpf_jit_harden) - return false; - if (bpf_jit_harden == 1 && capable(CAP_SYS_ADMIN)) - return false; - - return true; -} -#else -static inline void bpf_jit_compile(struct bpf_prog *fp) -{ -} - -static inline void bpf_jit_free(struct bpf_prog *fp) -{ - bpf_prog_unlock_free(fp); -} -#endif /* CONFIG_BPF_JIT */ - -#define BPF_ANC BIT(15) - -static inline bool bpf_needs_clear_a(const struct sock_filter *first) -{ - switch (first->code) { - case BPF_RET | BPF_K: - case BPF_LD | BPF_W | BPF_LEN: - return false; - - case BPF_LD | BPF_W | BPF_ABS: - case BPF_LD | BPF_H | BPF_ABS: - case BPF_LD | BPF_B | BPF_ABS: - if (first->k == SKF_AD_OFF + SKF_AD_ALU_XOR_X) - return true; - return false; - - default: - return true; - } -} - -static inline u16 bpf_anc_helper(const struct sock_filter *ftest) -{ - BUG_ON(ftest->code & BPF_ANC); - - switch (ftest->code) { - case BPF_LD | BPF_W | BPF_ABS: - case BPF_LD | BPF_H | BPF_ABS: - case BPF_LD | BPF_B | BPF_ABS: -#define BPF_ANCILLARY(CODE) case SKF_AD_OFF + SKF_AD_##CODE: \ - return BPF_ANC | SKF_AD_##CODE - switch (ftest->k) { - BPF_ANCILLARY(PROTOCOL); - BPF_ANCILLARY(PKTTYPE); - BPF_ANCILLARY(IFINDEX); - BPF_ANCILLARY(NLATTR); - BPF_ANCILLARY(NLATTR_NEST); - BPF_ANCILLARY(MARK); - BPF_ANCILLARY(QUEUE); - BPF_ANCILLARY(HATYPE); - BPF_ANCILLARY(RXHASH); - BPF_ANCILLARY(CPU); - BPF_ANCILLARY(ALU_XOR_X); - BPF_ANCILLARY(VLAN_TAG); - BPF_ANCILLARY(VLAN_TAG_PRESENT); - BPF_ANCILLARY(PAY_OFFSET); - BPF_ANCILLARY(RANDOM); - BPF_ANCILLARY(VLAN_TPID); - } - /* Fallthrough. */ - default: - return ftest->code; - } -} - -void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, - int k, unsigned int size); - -static inline void *bpf_load_pointer(const struct sk_buff *skb, int k, - unsigned int size, void *buffer) -{ - if (k >= 0) - return skb_header_pointer(skb, k, size, buffer); - - return bpf_internal_load_pointer_neg_helper(skb, k, size); -} - -static inline int bpf_tell_extensions(void) -{ - return SKF_AD_MAX; -} - -#endif /* __LINUX_FILTER_H__ */ diff --git a/src/linux/include/linux/fips.h b/src/linux/include/linux/fips.h deleted file mode 100644 index f8fb07b..0000000 --- a/src/linux/include/linux/fips.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _FIPS_H -#define _FIPS_H - -#ifdef CONFIG_CRYPTO_FIPS -extern int fips_enabled; -#else -#define fips_enabled 0 -#endif - -#endif diff --git a/src/linux/include/linux/flex_array.h b/src/linux/include/linux/flex_array.h deleted file mode 100644 index b6efb0c..0000000 --- a/src/linux/include/linux/flex_array.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef _FLEX_ARRAY_H -#define _FLEX_ARRAY_H - -#include -#include -#include - -#define FLEX_ARRAY_PART_SIZE PAGE_SIZE -#define FLEX_ARRAY_BASE_SIZE PAGE_SIZE - -struct flex_array_part; - -/* - * This is meant to replace cases where an array-like - * structure has gotten too big to fit into kmalloc() - * and the developer is getting tempted to use - * vmalloc(). - */ - -struct flex_array { - union { - struct { - int element_size; - int total_nr_elements; - int elems_per_part; - struct reciprocal_value reciprocal_elems; - struct flex_array_part *parts[]; - }; - /* - * This little trick makes sure that - * sizeof(flex_array) == PAGE_SIZE - */ - char padding[FLEX_ARRAY_BASE_SIZE]; - }; -}; - -/* Number of bytes left in base struct flex_array, excluding metadata */ -#define FLEX_ARRAY_BASE_BYTES_LEFT \ - (FLEX_ARRAY_BASE_SIZE - offsetof(struct flex_array, parts)) - -/* Number of pointers in base to struct flex_array_part pages */ -#define FLEX_ARRAY_NR_BASE_PTRS \ - (FLEX_ARRAY_BASE_BYTES_LEFT / sizeof(struct flex_array_part *)) - -/* Number of elements of size that fit in struct flex_array_part */ -#define FLEX_ARRAY_ELEMENTS_PER_PART(size) \ - (FLEX_ARRAY_PART_SIZE / size) - -/* - * Defines a statically allocated flex array and ensures its parameters are - * valid. - */ -#define DEFINE_FLEX_ARRAY(__arrayname, __element_size, __total) \ - struct flex_array __arrayname = { { { \ - .element_size = (__element_size), \ - .total_nr_elements = (__total), \ - } } }; \ - static inline void __arrayname##_invalid_parameter(void) \ - { \ - BUILD_BUG_ON((__total) > FLEX_ARRAY_NR_BASE_PTRS * \ - FLEX_ARRAY_ELEMENTS_PER_PART(__element_size)); \ - } - -struct flex_array *flex_array_alloc(int element_size, unsigned int total, - gfp_t flags); -int flex_array_prealloc(struct flex_array *fa, unsigned int start, - unsigned int nr_elements, gfp_t flags); -void flex_array_free(struct flex_array *fa); -void flex_array_free_parts(struct flex_array *fa); -int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src, - gfp_t flags); -int flex_array_clear(struct flex_array *fa, unsigned int element_nr); -void *flex_array_get(struct flex_array *fa, unsigned int element_nr); -int flex_array_shrink(struct flex_array *fa); - -#define flex_array_put_ptr(fa, nr, src, gfp) \ - flex_array_put(fa, nr, (void *)&(src), gfp) - -void *flex_array_get_ptr(struct flex_array *fa, unsigned int element_nr); - -#endif /* _FLEX_ARRAY_H */ diff --git a/src/linux/include/linux/flex_proportions.h b/src/linux/include/linux/flex_proportions.h deleted file mode 100644 index 0d348e0..0000000 --- a/src/linux/include/linux/flex_proportions.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Floating proportions with flexible aging period - * - * Copyright (C) 2011, SUSE, Jan Kara - */ - -#ifndef _LINUX_FLEX_PROPORTIONS_H -#define _LINUX_FLEX_PROPORTIONS_H - -#include -#include -#include -#include - -/* - * When maximum proportion of some event type is specified, this is the - * precision with which we allow limitting. Note that this creates an upper - * bound on the number of events per period like - * ULLONG_MAX >> FPROP_FRAC_SHIFT. - */ -#define FPROP_FRAC_SHIFT 10 -#define FPROP_FRAC_BASE (1UL << FPROP_FRAC_SHIFT) - -/* - * ---- Global proportion definitions ---- - */ -struct fprop_global { - /* Number of events in the current period */ - struct percpu_counter events; - /* Current period */ - unsigned int period; - /* Synchronization with period transitions */ - seqcount_t sequence; -}; - -int fprop_global_init(struct fprop_global *p, gfp_t gfp); -void fprop_global_destroy(struct fprop_global *p); -bool fprop_new_period(struct fprop_global *p, int periods); - -/* - * ---- SINGLE ---- - */ -struct fprop_local_single { - /* the local events counter */ - unsigned long events; - /* Period in which we last updated events */ - unsigned int period; - raw_spinlock_t lock; /* Protect period and numerator */ -}; - -#define INIT_FPROP_LOCAL_SINGLE(name) \ -{ .lock = __RAW_SPIN_LOCK_UNLOCKED(name.lock), \ -} - -int fprop_local_init_single(struct fprop_local_single *pl); -void fprop_local_destroy_single(struct fprop_local_single *pl); -void __fprop_inc_single(struct fprop_global *p, struct fprop_local_single *pl); -void fprop_fraction_single(struct fprop_global *p, - struct fprop_local_single *pl, unsigned long *numerator, - unsigned long *denominator); - -static inline -void fprop_inc_single(struct fprop_global *p, struct fprop_local_single *pl) -{ - unsigned long flags; - - local_irq_save(flags); - __fprop_inc_single(p, pl); - local_irq_restore(flags); -} - -/* - * ---- PERCPU ---- - */ -struct fprop_local_percpu { - /* the local events counter */ - struct percpu_counter events; - /* Period in which we last updated events */ - unsigned int period; - raw_spinlock_t lock; /* Protect period and numerator */ -}; - -int fprop_local_init_percpu(struct fprop_local_percpu *pl, gfp_t gfp); -void fprop_local_destroy_percpu(struct fprop_local_percpu *pl); -void __fprop_inc_percpu(struct fprop_global *p, struct fprop_local_percpu *pl); -void __fprop_inc_percpu_max(struct fprop_global *p, struct fprop_local_percpu *pl, - int max_frac); -void fprop_fraction_percpu(struct fprop_global *p, - struct fprop_local_percpu *pl, unsigned long *numerator, - unsigned long *denominator); - -static inline -void fprop_inc_percpu(struct fprop_global *p, struct fprop_local_percpu *pl) -{ - unsigned long flags; - - local_irq_save(flags); - __fprop_inc_percpu(p, pl); - local_irq_restore(flags); -} - -#endif diff --git a/src/linux/include/linux/frame.h b/src/linux/include/linux/frame.h deleted file mode 100644 index e6baaba..0000000 --- a/src/linux/include/linux/frame.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _LINUX_FRAME_H -#define _LINUX_FRAME_H - -#ifdef CONFIG_STACK_VALIDATION -/* - * This macro marks the given function's stack frame as "non-standard", which - * tells objtool to ignore the function when doing stack metadata validation. - * It should only be used in special cases where you're 100% sure it won't - * affect the reliability of frame pointers and kernel stack traces. - * - * For more information, see tools/objtool/Documentation/stack-validation.txt. - */ -#define STACK_FRAME_NON_STANDARD(func) \ - static void __used __section(__func_stack_frame_non_standard) \ - *__func_stack_frame_non_standard_##func = func - -#else /* !CONFIG_STACK_VALIDATION */ - -#define STACK_FRAME_NON_STANDARD(func) - -#endif /* CONFIG_STACK_VALIDATION */ - -#endif /* _LINUX_FRAME_H */ diff --git a/src/linux/include/linux/freezer.h b/src/linux/include/linux/freezer.h deleted file mode 100644 index dd03e83..0000000 --- a/src/linux/include/linux/freezer.h +++ /dev/null @@ -1,301 +0,0 @@ -/* Freezer declarations */ - -#ifndef FREEZER_H_INCLUDED -#define FREEZER_H_INCLUDED - -#include -#include -#include -#include - -#ifdef CONFIG_FREEZER -extern atomic_t system_freezing_cnt; /* nr of freezing conds in effect */ -extern bool pm_freezing; /* PM freezing in effect */ -extern bool pm_nosig_freezing; /* PM nosig freezing in effect */ - -/* - * Timeout for stopping processes - */ -extern unsigned int freeze_timeout_msecs; - -/* - * Check if a process has been frozen - */ -static inline bool frozen(struct task_struct *p) -{ - return p->flags & PF_FROZEN; -} - -extern bool freezing_slow_path(struct task_struct *p); - -/* - * Check if there is a request to freeze a process - */ -static inline bool freezing(struct task_struct *p) -{ - if (likely(!atomic_read(&system_freezing_cnt))) - return false; - return freezing_slow_path(p); -} - -/* Takes and releases task alloc lock using task_lock() */ -extern void __thaw_task(struct task_struct *t); - -extern bool __refrigerator(bool check_kthr_stop); -extern int freeze_processes(void); -extern int freeze_kernel_threads(void); -extern void thaw_processes(void); -extern void thaw_kernel_threads(void); - -/* - * DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION - * If try_to_freeze causes a lockdep warning it means the caller may deadlock - */ -static inline bool try_to_freeze_unsafe(void) -{ - might_sleep(); - if (likely(!freezing(current))) - return false; - return __refrigerator(false); -} - -static inline bool try_to_freeze(void) -{ - if (!(current->flags & PF_NOFREEZE)) - debug_check_no_locks_held(); - return try_to_freeze_unsafe(); -} - -extern bool freeze_task(struct task_struct *p); -extern bool set_freezable(void); - -#ifdef CONFIG_CGROUP_FREEZER -extern bool cgroup_freezing(struct task_struct *task); -#else /* !CONFIG_CGROUP_FREEZER */ -static inline bool cgroup_freezing(struct task_struct *task) -{ - return false; -} -#endif /* !CONFIG_CGROUP_FREEZER */ - -/* - * The PF_FREEZER_SKIP flag should be set by a vfork parent right before it - * calls wait_for_completion(&vfork) and reset right after it returns from this - * function. Next, the parent should call try_to_freeze() to freeze itself - * appropriately in case the child has exited before the freezing of tasks is - * complete. However, we don't want kernel threads to be frozen in unexpected - * places, so we allow them to block freeze_processes() instead or to set - * PF_NOFREEZE if needed. Fortunately, in the ____call_usermodehelper() case the - * parent won't really block freeze_processes(), since ____call_usermodehelper() - * (the child) does a little before exec/exit and it can't be frozen before - * waking up the parent. - */ - - -/** - * freezer_do_not_count - tell freezer to ignore %current - * - * Tell freezers to ignore the current task when determining whether the - * target frozen state is reached. IOW, the current task will be - * considered frozen enough by freezers. - * - * The caller shouldn't do anything which isn't allowed for a frozen task - * until freezer_cont() is called. Usually, freezer[_do_not]_count() pair - * wrap a scheduling operation and nothing much else. - */ -static inline void freezer_do_not_count(void) -{ - current->flags |= PF_FREEZER_SKIP; -} - -/** - * freezer_count - tell freezer to stop ignoring %current - * - * Undo freezer_do_not_count(). It tells freezers that %current should be - * considered again and tries to freeze if freezing condition is already in - * effect. - */ -static inline void freezer_count(void) -{ - current->flags &= ~PF_FREEZER_SKIP; - /* - * If freezing is in progress, the following paired with smp_mb() - * in freezer_should_skip() ensures that either we see %true - * freezing() or freezer_should_skip() sees !PF_FREEZER_SKIP. - */ - smp_mb(); - try_to_freeze(); -} - -/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */ -static inline void freezer_count_unsafe(void) -{ - current->flags &= ~PF_FREEZER_SKIP; - smp_mb(); - try_to_freeze_unsafe(); -} - -/** - * freezer_should_skip - whether to skip a task when determining frozen - * state is reached - * @p: task in quesion - * - * This function is used by freezers after establishing %true freezing() to - * test whether a task should be skipped when determining the target frozen - * state is reached. IOW, if this function returns %true, @p is considered - * frozen enough. - */ -static inline bool freezer_should_skip(struct task_struct *p) -{ - /* - * The following smp_mb() paired with the one in freezer_count() - * ensures that either freezer_count() sees %true freezing() or we - * see cleared %PF_FREEZER_SKIP and return %false. This makes it - * impossible for a task to slip frozen state testing after - * clearing %PF_FREEZER_SKIP. - */ - smp_mb(); - return p->flags & PF_FREEZER_SKIP; -} - -/* - * These functions are intended to be used whenever you want allow a sleeping - * task to be frozen. Note that neither return any clear indication of - * whether a freeze event happened while in this function. - */ - -/* Like schedule(), but should not block the freezer. */ -static inline void freezable_schedule(void) -{ - freezer_do_not_count(); - schedule(); - freezer_count(); -} - -/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */ -static inline void freezable_schedule_unsafe(void) -{ - freezer_do_not_count(); - schedule(); - freezer_count_unsafe(); -} - -/* - * Like freezable_schedule_timeout(), but should not block the freezer. Do not - * call this with locks held. - */ -static inline long freezable_schedule_timeout(long timeout) -{ - long __retval; - freezer_do_not_count(); - __retval = schedule_timeout(timeout); - freezer_count(); - return __retval; -} - -/* - * Like schedule_timeout_interruptible(), but should not block the freezer. Do not - * call this with locks held. - */ -static inline long freezable_schedule_timeout_interruptible(long timeout) -{ - long __retval; - freezer_do_not_count(); - __retval = schedule_timeout_interruptible(timeout); - freezer_count(); - return __retval; -} - -/* Like schedule_timeout_killable(), but should not block the freezer. */ -static inline long freezable_schedule_timeout_killable(long timeout) -{ - long __retval; - freezer_do_not_count(); - __retval = schedule_timeout_killable(timeout); - freezer_count(); - return __retval; -} - -/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */ -static inline long freezable_schedule_timeout_killable_unsafe(long timeout) -{ - long __retval; - freezer_do_not_count(); - __retval = schedule_timeout_killable(timeout); - freezer_count_unsafe(); - return __retval; -} - -/* - * Like schedule_hrtimeout_range(), but should not block the freezer. Do not - * call this with locks held. - */ -static inline int freezable_schedule_hrtimeout_range(ktime_t *expires, - u64 delta, const enum hrtimer_mode mode) -{ - int __retval; - freezer_do_not_count(); - __retval = schedule_hrtimeout_range(expires, delta, mode); - freezer_count(); - return __retval; -} - -/* - * Freezer-friendly wrappers around wait_event_interruptible(), - * wait_event_killable() and wait_event_interruptible_timeout(), originally - * defined in - */ - -/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */ -#define wait_event_freezekillable_unsafe(wq, condition) \ -({ \ - int __retval; \ - freezer_do_not_count(); \ - __retval = wait_event_killable(wq, (condition)); \ - freezer_count_unsafe(); \ - __retval; \ -}) - -#else /* !CONFIG_FREEZER */ -static inline bool frozen(struct task_struct *p) { return false; } -static inline bool freezing(struct task_struct *p) { return false; } -static inline void __thaw_task(struct task_struct *t) {} - -static inline bool __refrigerator(bool check_kthr_stop) { return false; } -static inline int freeze_processes(void) { return -ENOSYS; } -static inline int freeze_kernel_threads(void) { return -ENOSYS; } -static inline void thaw_processes(void) {} -static inline void thaw_kernel_threads(void) {} - -static inline bool try_to_freeze_nowarn(void) { return false; } -static inline bool try_to_freeze(void) { return false; } - -static inline void freezer_do_not_count(void) {} -static inline void freezer_count(void) {} -static inline int freezer_should_skip(struct task_struct *p) { return 0; } -static inline void set_freezable(void) {} - -#define freezable_schedule() schedule() - -#define freezable_schedule_unsafe() schedule() - -#define freezable_schedule_timeout(timeout) schedule_timeout(timeout) - -#define freezable_schedule_timeout_interruptible(timeout) \ - schedule_timeout_interruptible(timeout) - -#define freezable_schedule_timeout_killable(timeout) \ - schedule_timeout_killable(timeout) - -#define freezable_schedule_timeout_killable_unsafe(timeout) \ - schedule_timeout_killable(timeout) - -#define freezable_schedule_hrtimeout_range(expires, delta, mode) \ - schedule_hrtimeout_range(expires, delta, mode) - -#define wait_event_freezekillable_unsafe(wq, condition) \ - wait_event_killable(wq, condition) - -#endif /* !CONFIG_FREEZER */ - -#endif /* FREEZER_H_INCLUDED */ diff --git a/src/linux/include/linux/fs.h b/src/linux/include/linux/fs.h deleted file mode 100644 index dc0478c..0000000 --- a/src/linux/include/linux/fs.h +++ /dev/null @@ -1,3212 +0,0 @@ -#ifndef _LINUX_FS_H -#define _LINUX_FS_H - -#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 -#include -#include -#include - -#include -#include - -struct backing_dev_info; -struct bdi_writeback; -struct export_operations; -struct hd_geometry; -struct iovec; -struct kiocb; -struct kobject; -struct pipe_inode_info; -struct poll_table_struct; -struct kstatfs; -struct vm_area_struct; -struct vfsmount; -struct cred; -struct swap_info_struct; -struct seq_file; -struct workqueue_struct; -struct iov_iter; -struct fscrypt_info; -struct fscrypt_operations; - -extern void __init inode_init(void); -extern void __init inode_init_early(void); -extern void __init files_init(void); -extern void __init files_maxfiles_init(void); - -extern struct files_stat_struct files_stat; -extern unsigned long get_max_files(void); -extern unsigned int sysctl_nr_open; -extern struct inodes_stat_t inodes_stat; -extern int leases_enable, lease_break_time; -extern int sysctl_protected_symlinks; -extern int sysctl_protected_hardlinks; - -struct buffer_head; -typedef int (get_block_t)(struct inode *inode, sector_t iblock, - struct buffer_head *bh_result, int create); -typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, - ssize_t bytes, void *private); - -#define MAY_EXEC 0x00000001 -#define MAY_WRITE 0x00000002 -#define MAY_READ 0x00000004 -#define MAY_APPEND 0x00000008 -#define MAY_ACCESS 0x00000010 -#define MAY_OPEN 0x00000020 -#define MAY_CHDIR 0x00000040 -/* called from RCU mode, don't block */ -#define MAY_NOT_BLOCK 0x00000080 - -/* - * flags in file.f_mode. Note that FMODE_READ and FMODE_WRITE must correspond - * to O_WRONLY and O_RDWR via the strange trick in __dentry_open() - */ - -/* file is open for reading */ -#define FMODE_READ ((__force fmode_t)0x1) -/* file is open for writing */ -#define FMODE_WRITE ((__force fmode_t)0x2) -/* file is seekable */ -#define FMODE_LSEEK ((__force fmode_t)0x4) -/* file can be accessed using pread */ -#define FMODE_PREAD ((__force fmode_t)0x8) -/* file can be accessed using pwrite */ -#define FMODE_PWRITE ((__force fmode_t)0x10) -/* File is opened for execution with sys_execve / sys_uselib */ -#define FMODE_EXEC ((__force fmode_t)0x20) -/* File is opened with O_NDELAY (only set for block devices) */ -#define FMODE_NDELAY ((__force fmode_t)0x40) -/* File is opened with O_EXCL (only set for block devices) */ -#define FMODE_EXCL ((__force fmode_t)0x80) -/* File is opened using open(.., 3, ..) and is writeable only for ioctls - (specialy hack for floppy.c) */ -#define FMODE_WRITE_IOCTL ((__force fmode_t)0x100) -/* 32bit hashes as llseek() offset (for directories) */ -#define FMODE_32BITHASH ((__force fmode_t)0x200) -/* 64bit hashes as llseek() offset (for directories) */ -#define FMODE_64BITHASH ((__force fmode_t)0x400) - -/* - * Don't update ctime and mtime. - * - * Currently a special hack for the XFS open_by_handle ioctl, but we'll - * hopefully graduate it to a proper O_CMTIME flag supported by open(2) soon. - */ -#define FMODE_NOCMTIME ((__force fmode_t)0x800) - -/* Expect random access pattern */ -#define FMODE_RANDOM ((__force fmode_t)0x1000) - -/* File is huge (eg. /dev/kmem): treat loff_t as unsigned */ -#define FMODE_UNSIGNED_OFFSET ((__force fmode_t)0x2000) - -/* File is opened with O_PATH; almost nothing can be done with it */ -#define FMODE_PATH ((__force fmode_t)0x4000) - -/* File needs atomic accesses to f_pos */ -#define FMODE_ATOMIC_POS ((__force fmode_t)0x8000) -/* Write access to underlying fs */ -#define FMODE_WRITER ((__force fmode_t)0x10000) -/* Has read method(s) */ -#define FMODE_CAN_READ ((__force fmode_t)0x20000) -/* Has write method(s) */ -#define FMODE_CAN_WRITE ((__force fmode_t)0x40000) - -/* File was opened by fanotify and shouldn't generate fanotify events */ -#define FMODE_NONOTIFY ((__force fmode_t)0x4000000) - -/* - * Flag for rw_copy_check_uvector and compat_rw_copy_check_uvector - * that indicates that they should check the contents of the iovec are - * valid, but not check the memory that the iovec elements - * points too. - */ -#define CHECK_IOVEC_ONLY -1 - -/* - * The below are the various read and write flags that we support. Some of - * them include behavioral modifiers that send information down to the - * block layer and IO scheduler. They should be used along with a req_op. - * Terminology: - * - * The block layer uses device plugging to defer IO a little bit, in - * the hope that we will see more IO very shortly. This increases - * coalescing of adjacent IO and thus reduces the number of IOs we - * have to send to the device. It also allows for better queuing, - * if the IO isn't mergeable. If the caller is going to be waiting - * for the IO, then he must ensure that the device is unplugged so - * that the IO is dispatched to the driver. - * - * All IO is handled async in Linux. This is fine for background - * writes, but for reads or writes that someone waits for completion - * on, we want to notify the block layer and IO scheduler so that they - * know about it. That allows them to make better scheduling - * decisions. So when the below references 'sync' and 'async', it - * is referencing this priority hint. - * - * With that in mind, the available types are: - * - * READ A normal read operation. Device will be plugged. - * READ_SYNC A synchronous read. Device is not plugged, caller can - * immediately wait on this read without caring about - * unplugging. - * WRITE A normal async write. Device will be plugged. - * WRITE_SYNC Synchronous write. Identical to WRITE, but passes down - * the hint that someone will be waiting on this IO - * shortly. The write equivalent of READ_SYNC. - * WRITE_ODIRECT Special case write for O_DIRECT only. - * WRITE_FLUSH Like WRITE_SYNC but with preceding cache flush. - * WRITE_FUA Like WRITE_SYNC but data is guaranteed to be on - * non-volatile media on completion. - * WRITE_FLUSH_FUA Combination of WRITE_FLUSH and FUA. The IO is preceded - * by a cache flush and data is guaranteed to be on - * non-volatile media on completion. - * - */ -#define RW_MASK REQ_OP_WRITE - -#define READ REQ_OP_READ -#define WRITE REQ_OP_WRITE - -#define READ_SYNC REQ_SYNC -#define WRITE_SYNC (REQ_SYNC | REQ_NOIDLE) -#define WRITE_ODIRECT REQ_SYNC -#define WRITE_FLUSH (REQ_SYNC | REQ_NOIDLE | REQ_PREFLUSH) -#define WRITE_FUA (REQ_SYNC | REQ_NOIDLE | REQ_FUA) -#define WRITE_FLUSH_FUA (REQ_SYNC | REQ_NOIDLE | REQ_PREFLUSH | REQ_FUA) - -/* - * Attribute flags. These should be or-ed together to figure out what - * has been changed! - */ -#define ATTR_MODE (1 << 0) -#define ATTR_UID (1 << 1) -#define ATTR_GID (1 << 2) -#define ATTR_SIZE (1 << 3) -#define ATTR_ATIME (1 << 4) -#define ATTR_MTIME (1 << 5) -#define ATTR_CTIME (1 << 6) -#define ATTR_ATIME_SET (1 << 7) -#define ATTR_MTIME_SET (1 << 8) -#define ATTR_FORCE (1 << 9) /* Not a change, but a change it */ -#define ATTR_ATTR_FLAG (1 << 10) -#define ATTR_KILL_SUID (1 << 11) -#define ATTR_KILL_SGID (1 << 12) -#define ATTR_FILE (1 << 13) -#define ATTR_KILL_PRIV (1 << 14) -#define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */ -#define ATTR_TIMES_SET (1 << 16) -#define ATTR_TOUCH (1 << 17) - -/* - * Whiteout is represented by a char device. The following constants define the - * mode and device number to use. - */ -#define WHITEOUT_MODE 0 -#define WHITEOUT_DEV 0 - -/* - * This is the Inode Attributes structure, used for notify_change(). It - * uses the above definitions as flags, to know which values have changed. - * Also, in this manner, a Filesystem can look at only the values it cares - * about. Basically, these are the attributes that the VFS layer can - * request to change from the FS layer. - * - * Derek Atkins 94-10-20 - */ -struct iattr { - unsigned int ia_valid; - umode_t ia_mode; - kuid_t ia_uid; - kgid_t ia_gid; - loff_t ia_size; - struct timespec ia_atime; - struct timespec ia_mtime; - struct timespec ia_ctime; - - /* - * Not an attribute, but an auxiliary info for filesystems wanting to - * implement an ftruncate() like method. NOTE: filesystem should - * check for (ia_valid & ATTR_FILE), and not for (ia_file != NULL). - */ - struct file *ia_file; -}; - -/* - * Includes for diskquotas. - */ -#include - -/* - * Maximum number of layers of fs stack. Needs to be limited to - * prevent kernel stack overflow - */ -#define FILESYSTEM_MAX_STACK_DEPTH 2 - -/** - * enum positive_aop_returns - aop return codes with specific semantics - * - * @AOP_WRITEPAGE_ACTIVATE: Informs the caller that page writeback has - * completed, that the page is still locked, and - * should be considered active. The VM uses this hint - * to return the page to the active list -- it won't - * be a candidate for writeback again in the near - * future. Other callers must be careful to unlock - * the page if they get this return. Returned by - * writepage(); - * - * @AOP_TRUNCATED_PAGE: The AOP method that was handed a locked page has - * unlocked it and the page might have been truncated. - * The caller should back up to acquiring a new page and - * trying again. The aop will be taking reasonable - * precautions not to livelock. If the caller held a page - * reference, it should drop it before retrying. Returned - * by readpage(). - * - * address_space_operation functions return these large constants to indicate - * special semantics to the caller. These are much larger than the bytes in a - * page to allow for functions that return the number of bytes operated on in a - * given page. - */ - -enum positive_aop_returns { - AOP_WRITEPAGE_ACTIVATE = 0x80000, - AOP_TRUNCATED_PAGE = 0x80001, -}; - -#define AOP_FLAG_UNINTERRUPTIBLE 0x0001 /* will not do a short write */ -#define AOP_FLAG_CONT_EXPAND 0x0002 /* called from cont_expand */ -#define AOP_FLAG_NOFS 0x0004 /* used by filesystem to direct - * helper code (eg buffer layer) - * to clear GFP_FS from alloc */ - -/* - * oh the beauties of C type declarations. - */ -struct page; -struct address_space; -struct writeback_control; - -#define IOCB_EVENTFD (1 << 0) -#define IOCB_APPEND (1 << 1) -#define IOCB_DIRECT (1 << 2) -#define IOCB_HIPRI (1 << 3) -#define IOCB_DSYNC (1 << 4) -#define IOCB_SYNC (1 << 5) -#define IOCB_WRITE (1 << 6) - -struct kiocb { - struct file *ki_filp; - loff_t ki_pos; - void (*ki_complete)(struct kiocb *iocb, long ret, long ret2); - void *private; - int ki_flags; -}; - -static inline bool is_sync_kiocb(struct kiocb *kiocb) -{ - return kiocb->ki_complete == NULL; -} - -static inline int iocb_flags(struct file *file); - -static inline void init_sync_kiocb(struct kiocb *kiocb, struct file *filp) -{ - *kiocb = (struct kiocb) { - .ki_filp = filp, - .ki_flags = iocb_flags(filp), - }; -} - -/* - * "descriptor" for what we're up to with a read. - * This allows us to use the same read code yet - * have multiple different users of the data that - * we read from a file. - * - * The simplest case just copies the data to user - * mode. - */ -typedef struct { - size_t written; - size_t count; - union { - char __user *buf; - void *data; - } arg; - int error; -} read_descriptor_t; - -typedef int (*read_actor_t)(read_descriptor_t *, struct page *, - unsigned long, unsigned long); - -struct address_space_operations { - int (*writepage)(struct page *page, struct writeback_control *wbc); - int (*readpage)(struct file *, struct page *); - - /* Write back some dirty pages from this mapping. */ - int (*writepages)(struct address_space *, struct writeback_control *); - - /* Set a page dirty. Return true if this dirtied it */ - int (*set_page_dirty)(struct page *page); - - int (*readpages)(struct file *filp, struct address_space *mapping, - struct list_head *pages, unsigned nr_pages); - - int (*write_begin)(struct file *, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata); - int (*write_end)(struct file *, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata); - - /* Unfortunately this kludge is needed for FIBMAP. Don't use it */ - sector_t (*bmap)(struct address_space *, sector_t); - void (*invalidatepage) (struct page *, unsigned int, unsigned int); - int (*releasepage) (struct page *, gfp_t); - void (*freepage)(struct page *); - ssize_t (*direct_IO)(struct kiocb *, struct iov_iter *iter); - /* - * migrate the contents of a page to the specified target. If - * migrate_mode is MIGRATE_ASYNC, it must not block. - */ - int (*migratepage) (struct address_space *, - struct page *, struct page *, enum migrate_mode); - bool (*isolate_page)(struct page *, isolate_mode_t); - void (*putback_page)(struct page *); - int (*launder_page) (struct page *); - int (*is_partially_uptodate) (struct page *, unsigned long, - unsigned long); - void (*is_dirty_writeback) (struct page *, bool *, bool *); - int (*error_remove_page)(struct address_space *, struct page *); - - /* swapfile support */ - int (*swap_activate)(struct swap_info_struct *sis, struct file *file, - sector_t *span); - void (*swap_deactivate)(struct file *file); -}; - -extern const struct address_space_operations empty_aops; - -/* - * pagecache_write_begin/pagecache_write_end must be used by general code - * to write into the pagecache. - */ -int pagecache_write_begin(struct file *, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata); - -int pagecache_write_end(struct file *, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata); - -struct address_space { - struct inode *host; /* owner: inode, block_device */ - struct radix_tree_root page_tree; /* radix tree of all pages */ - spinlock_t tree_lock; /* and lock protecting it */ - atomic_t i_mmap_writable;/* count VM_SHARED mappings */ - struct rb_root i_mmap; /* tree of private and shared mappings */ - struct rw_semaphore i_mmap_rwsem; /* protect tree, count, list */ - /* Protected by tree_lock together with the radix tree */ - unsigned long nrpages; /* number of total pages */ - /* number of shadow or DAX exceptional entries */ - unsigned long nrexceptional; - pgoff_t writeback_index;/* writeback starts here */ - const struct address_space_operations *a_ops; /* methods */ - unsigned long flags; /* error bits */ - spinlock_t private_lock; /* for use by the address_space */ - gfp_t gfp_mask; /* implicit gfp mask for allocations */ - struct list_head private_list; /* ditto */ - void *private_data; /* ditto */ -} __attribute__((aligned(sizeof(long)))); - /* - * On most architectures that alignment is already the case; but - * must be enforced here for CRIS, to let the least significant bit - * of struct page's "mapping" pointer be used for PAGE_MAPPING_ANON. - */ -struct request_queue; - -struct block_device { - dev_t bd_dev; /* not a kdev_t - it's a search key */ - int bd_openers; - struct inode * bd_inode; /* will die */ - struct super_block * bd_super; - struct mutex bd_mutex; /* open/close mutex */ - void * bd_claiming; - void * bd_holder; - int bd_holders; - bool bd_write_holder; -#ifdef CONFIG_SYSFS - struct list_head bd_holder_disks; -#endif - struct block_device * bd_contains; - unsigned bd_block_size; - struct hd_struct * bd_part; - /* number of times partitions within this device have been opened. */ - unsigned bd_part_count; - int bd_invalidated; - struct gendisk * bd_disk; - struct request_queue * bd_queue; - struct list_head bd_list; - /* - * Private data. You must have bd_claim'ed the block_device - * to use this. NOTE: bd_claim allows an owner to claim - * the same device multiple times, the owner must take special - * care to not mess up bd_private for that case. - */ - unsigned long bd_private; - - /* The counter of freeze processes */ - int bd_fsfreeze_count; - /* Mutex for freeze */ - struct mutex bd_fsfreeze_mutex; -}; - -/* - * Radix-tree tags, for tagging dirty and writeback pages within the pagecache - * radix trees - */ -#define PAGECACHE_TAG_DIRTY 0 -#define PAGECACHE_TAG_WRITEBACK 1 -#define PAGECACHE_TAG_TOWRITE 2 - -int mapping_tagged(struct address_space *mapping, int tag); - -static inline void i_mmap_lock_write(struct address_space *mapping) -{ - down_write(&mapping->i_mmap_rwsem); -} - -static inline void i_mmap_unlock_write(struct address_space *mapping) -{ - up_write(&mapping->i_mmap_rwsem); -} - -static inline void i_mmap_lock_read(struct address_space *mapping) -{ - down_read(&mapping->i_mmap_rwsem); -} - -static inline void i_mmap_unlock_read(struct address_space *mapping) -{ - up_read(&mapping->i_mmap_rwsem); -} - -/* - * Might pages of this file be mapped into userspace? - */ -static inline int mapping_mapped(struct address_space *mapping) -{ - return !RB_EMPTY_ROOT(&mapping->i_mmap); -} - -/* - * Might pages of this file have been modified in userspace? - * Note that i_mmap_writable counts all VM_SHARED vmas: do_mmap_pgoff - * marks vma as VM_SHARED if it is shared, and the file was opened for - * writing i.e. vma may be mprotected writable even if now readonly. - * - * If i_mmap_writable is negative, no new writable mappings are allowed. You - * can only deny writable mappings, if none exists right now. - */ -static inline int mapping_writably_mapped(struct address_space *mapping) -{ - return atomic_read(&mapping->i_mmap_writable) > 0; -} - -static inline int mapping_map_writable(struct address_space *mapping) -{ - return atomic_inc_unless_negative(&mapping->i_mmap_writable) ? - 0 : -EPERM; -} - -static inline void mapping_unmap_writable(struct address_space *mapping) -{ - atomic_dec(&mapping->i_mmap_writable); -} - -static inline int mapping_deny_writable(struct address_space *mapping) -{ - return atomic_dec_unless_positive(&mapping->i_mmap_writable) ? - 0 : -EBUSY; -} - -static inline void mapping_allow_writable(struct address_space *mapping) -{ - atomic_inc(&mapping->i_mmap_writable); -} - -/* - * Use sequence counter to get consistent i_size on 32-bit processors. - */ -#if BITS_PER_LONG==32 && defined(CONFIG_SMP) -#include -#define __NEED_I_SIZE_ORDERED -#define i_size_ordered_init(inode) seqcount_init(&inode->i_size_seqcount) -#else -#define i_size_ordered_init(inode) do { } while (0) -#endif - -struct posix_acl; -#define ACL_NOT_CACHED ((void *)(-1)) -#define ACL_DONT_CACHE ((void *)(-3)) - -static inline struct posix_acl * -uncached_acl_sentinel(struct task_struct *task) -{ - return (void *)task + 1; -} - -static inline bool -is_uncached_acl(struct posix_acl *acl) -{ - return (long)acl & 1; -} - -#define IOP_FASTPERM 0x0001 -#define IOP_LOOKUP 0x0002 -#define IOP_NOFOLLOW 0x0004 -#define IOP_XATTR 0x0008 - -/* - * Keep mostly read-only and often accessed (especially for - * the RCU path lookup and 'stat' data) fields at the beginning - * of the 'struct inode' - */ -struct inode { - umode_t i_mode; - unsigned short i_opflags; - kuid_t i_uid; - kgid_t i_gid; - unsigned int i_flags; - -#ifdef CONFIG_FS_POSIX_ACL - struct posix_acl *i_acl; - struct posix_acl *i_default_acl; -#endif - - const struct inode_operations *i_op; - struct super_block *i_sb; - struct address_space *i_mapping; - -#ifdef CONFIG_SECURITY - void *i_security; -#endif - - /* Stat data, not accessed from path walking */ - unsigned long i_ino; - /* - * Filesystems may only read i_nlink directly. They shall use the - * following functions for modification: - * - * (set|clear|inc|drop)_nlink - * inode_(inc|dec)_link_count - */ - union { - const unsigned int i_nlink; - unsigned int __i_nlink; - }; - dev_t i_rdev; - loff_t i_size; - struct timespec i_atime; - struct timespec i_mtime; - struct timespec i_ctime; - spinlock_t i_lock; /* i_blocks, i_bytes, maybe i_size */ - unsigned short i_bytes; - unsigned int i_blkbits; - blkcnt_t i_blocks; - -#ifdef __NEED_I_SIZE_ORDERED - seqcount_t i_size_seqcount; -#endif - - /* Misc */ - unsigned long i_state; - struct rw_semaphore i_rwsem; - - unsigned long dirtied_when; /* jiffies of first dirtying */ - unsigned long dirtied_time_when; - - struct hlist_node i_hash; - struct list_head i_io_list; /* backing dev IO list */ -#ifdef CONFIG_CGROUP_WRITEBACK - struct bdi_writeback *i_wb; /* the associated cgroup wb */ - - /* foreign inode detection, see wbc_detach_inode() */ - int i_wb_frn_winner; - u16 i_wb_frn_avg_time; - u16 i_wb_frn_history; -#endif - struct list_head i_lru; /* inode LRU list */ - struct list_head i_sb_list; - struct list_head i_wb_list; /* backing dev writeback list */ - union { - struct hlist_head i_dentry; - struct rcu_head i_rcu; - }; - u64 i_version; - atomic_t i_count; - atomic_t i_dio_count; - atomic_t i_writecount; -#ifdef CONFIG_IMA - atomic_t i_readcount; /* struct files open RO */ -#endif - const struct file_operations *i_fop; /* former ->i_op->default_file_ops */ - struct file_lock_context *i_flctx; - struct address_space i_data; - struct list_head i_devices; - union { - struct pipe_inode_info *i_pipe; - struct block_device *i_bdev; - struct cdev *i_cdev; - char *i_link; - unsigned i_dir_seq; - }; - - __u32 i_generation; - -#ifdef CONFIG_FSNOTIFY - __u32 i_fsnotify_mask; /* all events this inode cares about */ - struct hlist_head i_fsnotify_marks; -#endif - -#if IS_ENABLED(CONFIG_FS_ENCRYPTION) - struct fscrypt_info *i_crypt_info; -#endif - - void *i_private; /* fs or device private pointer */ -}; - -static inline int inode_unhashed(struct inode *inode) -{ - return hlist_unhashed(&inode->i_hash); -} - -/* - * inode->i_mutex nesting subclasses for the lock validator: - * - * 0: the object of the current VFS operation - * 1: parent - * 2: child/target - * 3: xattr - * 4: second non-directory - * 5: second parent (when locking independent directories in rename) - * - * I_MUTEX_NONDIR2 is for certain operations (such as rename) which lock two - * non-directories at once. - * - * The locking order between these classes is - * parent[2] -> child -> grandchild -> normal -> xattr -> second non-directory - */ -enum inode_i_mutex_lock_class -{ - I_MUTEX_NORMAL, - I_MUTEX_PARENT, - I_MUTEX_CHILD, - I_MUTEX_XATTR, - I_MUTEX_NONDIR2, - I_MUTEX_PARENT2, -}; - -static inline void inode_lock(struct inode *inode) -{ - down_write(&inode->i_rwsem); -} - -static inline void inode_unlock(struct inode *inode) -{ - up_write(&inode->i_rwsem); -} - -static inline void inode_lock_shared(struct inode *inode) -{ - down_read(&inode->i_rwsem); -} - -static inline void inode_unlock_shared(struct inode *inode) -{ - up_read(&inode->i_rwsem); -} - -static inline int inode_trylock(struct inode *inode) -{ - return down_write_trylock(&inode->i_rwsem); -} - -static inline int inode_trylock_shared(struct inode *inode) -{ - return down_read_trylock(&inode->i_rwsem); -} - -static inline int inode_is_locked(struct inode *inode) -{ - return rwsem_is_locked(&inode->i_rwsem); -} - -static inline void inode_lock_nested(struct inode *inode, unsigned subclass) -{ - down_write_nested(&inode->i_rwsem, subclass); -} - -void lock_two_nondirectories(struct inode *, struct inode*); -void unlock_two_nondirectories(struct inode *, struct inode*); - -/* - * NOTE: in a 32bit arch with a preemptable kernel and - * an UP compile the i_size_read/write must be atomic - * with respect to the local cpu (unlike with preempt disabled), - * but they don't need to be atomic with respect to other cpus like in - * true SMP (so they need either to either locally disable irq around - * the read or for example on x86 they can be still implemented as a - * cmpxchg8b without the need of the lock prefix). For SMP compiles - * and 64bit archs it makes no difference if preempt is enabled or not. - */ -static inline loff_t i_size_read(const struct inode *inode) -{ -#if BITS_PER_LONG==32 && defined(CONFIG_SMP) - loff_t i_size; - unsigned int seq; - - do { - seq = read_seqcount_begin(&inode->i_size_seqcount); - i_size = inode->i_size; - } while (read_seqcount_retry(&inode->i_size_seqcount, seq)); - return i_size; -#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPT) - loff_t i_size; - - preempt_disable(); - i_size = inode->i_size; - preempt_enable(); - return i_size; -#else - return inode->i_size; -#endif -} - -/* - * NOTE: unlike i_size_read(), i_size_write() does need locking around it - * (normally i_mutex), otherwise on 32bit/SMP an update of i_size_seqcount - * can be lost, resulting in subsequent i_size_read() calls spinning forever. - */ -static inline void i_size_write(struct inode *inode, loff_t i_size) -{ -#if BITS_PER_LONG==32 && defined(CONFIG_SMP) - preempt_disable(); - write_seqcount_begin(&inode->i_size_seqcount); - inode->i_size = i_size; - write_seqcount_end(&inode->i_size_seqcount); - preempt_enable(); -#elif BITS_PER_LONG==32 && defined(CONFIG_PREEMPT) - preempt_disable(); - inode->i_size = i_size; - preempt_enable(); -#else - inode->i_size = i_size; -#endif -} - -static inline unsigned iminor(const struct inode *inode) -{ - return MINOR(inode->i_rdev); -} - -static inline unsigned imajor(const struct inode *inode) -{ - return MAJOR(inode->i_rdev); -} - -extern struct block_device *I_BDEV(struct inode *inode); - -struct fown_struct { - rwlock_t lock; /* protects pid, uid, euid fields */ - struct pid *pid; /* pid or -pgrp where SIGIO should be sent */ - enum pid_type pid_type; /* Kind of process group SIGIO should be sent to */ - kuid_t uid, euid; /* uid/euid of process setting the owner */ - int signum; /* posix.1b rt signal to be delivered on IO */ -}; - -/* - * Track a single file's readahead state - */ -struct file_ra_state { - pgoff_t start; /* where readahead started */ - unsigned int size; /* # of readahead pages */ - unsigned int async_size; /* do asynchronous readahead when - there are only # of pages ahead */ - - unsigned int ra_pages; /* Maximum readahead window */ - unsigned int mmap_miss; /* Cache miss stat for mmap accesses */ - loff_t prev_pos; /* Cache last read() position */ -}; - -/* - * Check if @index falls in the readahead windows. - */ -static inline int ra_has_index(struct file_ra_state *ra, pgoff_t index) -{ - return (index >= ra->start && - index < ra->start + ra->size); -} - -struct file { - union { - struct llist_node fu_llist; - struct rcu_head fu_rcuhead; - } f_u; - struct path f_path; - struct inode *f_inode; /* cached value */ - const struct file_operations *f_op; - - /* - * Protects f_ep_links, f_flags. - * Must not be taken from IRQ context. - */ - spinlock_t f_lock; - atomic_long_t f_count; - unsigned int f_flags; - fmode_t f_mode; - struct mutex f_pos_lock; - loff_t f_pos; - struct fown_struct f_owner; - const struct cred *f_cred; - struct file_ra_state f_ra; - - u64 f_version; -#ifdef CONFIG_SECURITY - void *f_security; -#endif - /* needed for tty driver, and maybe others */ - void *private_data; - -#ifdef CONFIG_EPOLL - /* Used by fs/eventpoll.c to link all the hooks to this file */ - struct list_head f_ep_links; - struct list_head f_tfile_llink; -#endif /* #ifdef CONFIG_EPOLL */ - struct address_space *f_mapping; -} __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */ - -struct file_handle { - __u32 handle_bytes; - int handle_type; - /* file identifier */ - unsigned char f_handle[0]; -}; - -static inline struct file *get_file(struct file *f) -{ - atomic_long_inc(&f->f_count); - return f; -} -#define get_file_rcu(x) atomic_long_inc_not_zero(&(x)->f_count) -#define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1) -#define file_count(x) atomic_long_read(&(x)->f_count) - -#define MAX_NON_LFS ((1UL<<31) - 1) - -/* Page cache limit. The filesystems should put that into their s_maxbytes - limits, otherwise bad things can happen in VM. */ -#if BITS_PER_LONG==32 -#define MAX_LFS_FILESIZE (((loff_t)PAGE_SIZE << (BITS_PER_LONG-1))-1) -#elif BITS_PER_LONG==64 -#define MAX_LFS_FILESIZE ((loff_t)0x7fffffffffffffffLL) -#endif - -#define FL_POSIX 1 -#define FL_FLOCK 2 -#define FL_DELEG 4 /* NFSv4 delegation */ -#define FL_ACCESS 8 /* not trying to lock, just looking */ -#define FL_EXISTS 16 /* when unlocking, test for existence */ -#define FL_LEASE 32 /* lease held on this file */ -#define FL_CLOSE 64 /* unlock on close */ -#define FL_SLEEP 128 /* A blocking lock */ -#define FL_DOWNGRADE_PENDING 256 /* Lease is being downgraded */ -#define FL_UNLOCK_PENDING 512 /* Lease is being broken */ -#define FL_OFDLCK 1024 /* lock is "owned" by struct file */ -#define FL_LAYOUT 2048 /* outstanding pNFS layout */ - -/* - * Special return value from posix_lock_file() and vfs_lock_file() for - * asynchronous locking. - */ -#define FILE_LOCK_DEFERRED 1 - -/* legacy typedef, should eventually be removed */ -typedef void *fl_owner_t; - -struct file_lock; - -struct file_lock_operations { - void (*fl_copy_lock)(struct file_lock *, struct file_lock *); - void (*fl_release_private)(struct file_lock *); -}; - -struct lock_manager_operations { - int (*lm_compare_owner)(struct file_lock *, struct file_lock *); - unsigned long (*lm_owner_key)(struct file_lock *); - fl_owner_t (*lm_get_owner)(fl_owner_t); - void (*lm_put_owner)(fl_owner_t); - void (*lm_notify)(struct file_lock *); /* unblock callback */ - int (*lm_grant)(struct file_lock *, int); - bool (*lm_break)(struct file_lock *); - int (*lm_change)(struct file_lock *, int, struct list_head *); - void (*lm_setup)(struct file_lock *, void **); -}; - -struct lock_manager { - struct list_head list; - /* - * NFSv4 and up also want opens blocked during the grace period; - * NLM doesn't care: - */ - bool block_opens; -}; - -struct net; -void locks_start_grace(struct net *, struct lock_manager *); -void locks_end_grace(struct lock_manager *); -int locks_in_grace(struct net *); -int opens_in_grace(struct net *); - -/* that will die - we need it for nfs_lock_info */ -#include - -/* - * struct file_lock represents a generic "file lock". It's used to represent - * POSIX byte range locks, BSD (flock) locks, and leases. It's important to - * note that the same struct is used to represent both a request for a lock and - * the lock itself, but the same object is never used for both. - * - * FIXME: should we create a separate "struct lock_request" to help distinguish - * these two uses? - * - * The varous i_flctx lists are ordered by: - * - * 1) lock owner - * 2) lock range start - * 3) lock range end - * - * Obviously, the last two criteria only matter for POSIX locks. - */ -struct file_lock { - struct file_lock *fl_next; /* singly linked list for this inode */ - struct list_head fl_list; /* link into file_lock_context */ - struct hlist_node fl_link; /* node in global lists */ - struct list_head fl_block; /* circular list of blocked processes */ - fl_owner_t fl_owner; - unsigned int fl_flags; - unsigned char fl_type; - unsigned int fl_pid; - int fl_link_cpu; /* what cpu's list is this on? */ - struct pid *fl_nspid; - wait_queue_head_t fl_wait; - struct file *fl_file; - loff_t fl_start; - loff_t fl_end; - - struct fasync_struct * fl_fasync; /* for lease break notifications */ - /* for lease breaks: */ - unsigned long fl_break_time; - unsigned long fl_downgrade_time; - - const struct file_lock_operations *fl_ops; /* Callbacks for filesystems */ - const struct lock_manager_operations *fl_lmops; /* Callbacks for lockmanagers */ - union { - struct nfs_lock_info nfs_fl; - struct nfs4_lock_info nfs4_fl; - struct { - struct list_head link; /* link in AFS vnode's pending_locks list */ - int state; /* state of grant or error if -ve */ - } afs; - } fl_u; -}; - -struct file_lock_context { - spinlock_t flc_lock; - struct list_head flc_flock; - struct list_head flc_posix; - struct list_head flc_lease; -}; - -/* The following constant reflects the upper bound of the file/locking space */ -#ifndef OFFSET_MAX -#define INT_LIMIT(x) (~((x)1 << (sizeof(x)*8 - 1))) -#define OFFSET_MAX INT_LIMIT(loff_t) -#define OFFT_OFFSET_MAX INT_LIMIT(off_t) -#endif - -#include - -extern void send_sigio(struct fown_struct *fown, int fd, int band); - -/* - * Return the inode to use for locking - * - * For overlayfs this should be the overlay inode, not the real inode returned - * by file_inode(). For any other fs file_inode(filp) and locks_inode(filp) are - * equal. - */ -static inline struct inode *locks_inode(const struct file *f) -{ - return f->f_path.dentry->d_inode; -} - -#ifdef CONFIG_FILE_LOCKING -extern int fcntl_getlk(struct file *, unsigned int, struct flock __user *); -extern int fcntl_setlk(unsigned int, struct file *, unsigned int, - struct flock __user *); - -#if BITS_PER_LONG == 32 -extern int fcntl_getlk64(struct file *, unsigned int, struct flock64 __user *); -extern int fcntl_setlk64(unsigned int, struct file *, unsigned int, - struct flock64 __user *); -#endif - -extern int fcntl_setlease(unsigned int fd, struct file *filp, long arg); -extern int fcntl_getlease(struct file *filp); - -/* fs/locks.c */ -void locks_free_lock_context(struct inode *inode); -void locks_free_lock(struct file_lock *fl); -extern void locks_init_lock(struct file_lock *); -extern struct file_lock * locks_alloc_lock(void); -extern void locks_copy_lock(struct file_lock *, struct file_lock *); -extern void locks_copy_conflock(struct file_lock *, struct file_lock *); -extern void locks_remove_posix(struct file *, fl_owner_t); -extern void locks_remove_file(struct file *); -extern void locks_release_private(struct file_lock *); -extern void posix_test_lock(struct file *, struct file_lock *); -extern int posix_lock_file(struct file *, struct file_lock *, struct file_lock *); -extern int posix_unblock_lock(struct file_lock *); -extern int vfs_test_lock(struct file *, struct file_lock *); -extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *); -extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl); -extern int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl); -extern int __break_lease(struct inode *inode, unsigned int flags, unsigned int type); -extern void lease_get_mtime(struct inode *, struct timespec *time); -extern int generic_setlease(struct file *, long, struct file_lock **, void **priv); -extern int vfs_setlease(struct file *, long, struct file_lock **, void **); -extern int lease_modify(struct file_lock *, int, struct list_head *); -struct files_struct; -extern void show_fd_locks(struct seq_file *f, - struct file *filp, struct files_struct *files); -#else /* !CONFIG_FILE_LOCKING */ -static inline int fcntl_getlk(struct file *file, unsigned int cmd, - struct flock __user *user) -{ - return -EINVAL; -} - -static inline int fcntl_setlk(unsigned int fd, struct file *file, - unsigned int cmd, struct flock __user *user) -{ - return -EACCES; -} - -#if BITS_PER_LONG == 32 -static inline int fcntl_getlk64(struct file *file, unsigned int cmd, - struct flock64 __user *user) -{ - return -EINVAL; -} - -static inline int fcntl_setlk64(unsigned int fd, struct file *file, - unsigned int cmd, struct flock64 __user *user) -{ - return -EACCES; -} -#endif -static inline int fcntl_setlease(unsigned int fd, struct file *filp, long arg) -{ - return -EINVAL; -} - -static inline int fcntl_getlease(struct file *filp) -{ - return F_UNLCK; -} - -static inline void -locks_free_lock_context(struct inode *inode) -{ -} - -static inline void locks_init_lock(struct file_lock *fl) -{ - return; -} - -static inline void locks_copy_conflock(struct file_lock *new, struct file_lock *fl) -{ - return; -} - -static inline void locks_copy_lock(struct file_lock *new, struct file_lock *fl) -{ - return; -} - -static inline void locks_remove_posix(struct file *filp, fl_owner_t owner) -{ - return; -} - -static inline void locks_remove_file(struct file *filp) -{ - return; -} - -static inline void posix_test_lock(struct file *filp, struct file_lock *fl) -{ - return; -} - -static inline int posix_lock_file(struct file *filp, struct file_lock *fl, - struct file_lock *conflock) -{ - return -ENOLCK; -} - -static inline int posix_unblock_lock(struct file_lock *waiter) -{ - return -ENOENT; -} - -static inline int vfs_test_lock(struct file *filp, struct file_lock *fl) -{ - return 0; -} - -static inline int vfs_lock_file(struct file *filp, unsigned int cmd, - struct file_lock *fl, struct file_lock *conf) -{ - return -ENOLCK; -} - -static inline int vfs_cancel_lock(struct file *filp, struct file_lock *fl) -{ - return 0; -} - -static inline int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl) -{ - return -ENOLCK; -} - -static inline int __break_lease(struct inode *inode, unsigned int mode, unsigned int type) -{ - return 0; -} - -static inline void lease_get_mtime(struct inode *inode, struct timespec *time) -{ - return; -} - -static inline int generic_setlease(struct file *filp, long arg, - struct file_lock **flp, void **priv) -{ - return -EINVAL; -} - -static inline int vfs_setlease(struct file *filp, long arg, - struct file_lock **lease, void **priv) -{ - return -EINVAL; -} - -static inline int lease_modify(struct file_lock *fl, int arg, - struct list_head *dispose) -{ - return -EINVAL; -} - -struct files_struct; -static inline void show_fd_locks(struct seq_file *f, - struct file *filp, struct files_struct *files) {} -#endif /* !CONFIG_FILE_LOCKING */ - -static inline struct inode *file_inode(const struct file *f) -{ - return f->f_inode; -} - -static inline struct dentry *file_dentry(const struct file *file) -{ - return d_real(file->f_path.dentry, file_inode(file), 0); -} - -static inline int locks_lock_file_wait(struct file *filp, struct file_lock *fl) -{ - return locks_lock_inode_wait(locks_inode(filp), fl); -} - -struct fasync_struct { - spinlock_t fa_lock; - int magic; - int fa_fd; - struct fasync_struct *fa_next; /* singly linked list */ - struct file *fa_file; - struct rcu_head fa_rcu; -}; - -#define FASYNC_MAGIC 0x4601 - -/* SMP safe fasync helpers: */ -extern int fasync_helper(int, struct file *, int, struct fasync_struct **); -extern struct fasync_struct *fasync_insert_entry(int, struct file *, struct fasync_struct **, struct fasync_struct *); -extern int fasync_remove_entry(struct file *, struct fasync_struct **); -extern struct fasync_struct *fasync_alloc(void); -extern void fasync_free(struct fasync_struct *); - -/* can be called from interrupts */ -extern void kill_fasync(struct fasync_struct **, int, int); - -extern void __f_setown(struct file *filp, struct pid *, enum pid_type, int force); -extern void f_setown(struct file *filp, unsigned long arg, int force); -extern void f_delown(struct file *filp); -extern pid_t f_getown(struct file *filp); -extern int send_sigurg(struct fown_struct *fown); - -struct mm_struct; - -/* - * Umount options - */ - -#define MNT_FORCE 0x00000001 /* Attempt to forcibily umount */ -#define MNT_DETACH 0x00000002 /* Just detach from the tree */ -#define MNT_EXPIRE 0x00000004 /* Mark for expiry */ -#define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */ -#define UMOUNT_UNUSED 0x80000000 /* Flag guaranteed to be unused */ - -/* sb->s_iflags */ -#define SB_I_CGROUPWB 0x00000001 /* cgroup-aware writeback enabled */ -#define SB_I_NOEXEC 0x00000002 /* Ignore executables on this fs */ -#define SB_I_NODEV 0x00000004 /* Ignore devices on this fs */ - -/* sb->s_iflags to limit user namespace mounts */ -#define SB_I_USERNS_VISIBLE 0x00000010 /* fstype already mounted */ - -/* Possible states of 'frozen' field */ -enum { - SB_UNFROZEN = 0, /* FS is unfrozen */ - SB_FREEZE_WRITE = 1, /* Writes, dir ops, ioctls frozen */ - SB_FREEZE_PAGEFAULT = 2, /* Page faults stopped as well */ - SB_FREEZE_FS = 3, /* For internal FS use (e.g. to stop - * internal threads if needed) */ - SB_FREEZE_COMPLETE = 4, /* ->freeze_fs finished successfully */ -}; - -#define SB_FREEZE_LEVELS (SB_FREEZE_COMPLETE - 1) - -struct sb_writers { - int frozen; /* Is sb frozen? */ - wait_queue_head_t wait_unfrozen; /* for get_super_thawed() */ - struct percpu_rw_semaphore rw_sem[SB_FREEZE_LEVELS]; -}; - -struct super_block { - struct list_head s_list; /* Keep this first */ - dev_t s_dev; /* search index; _not_ kdev_t */ - unsigned char s_blocksize_bits; - unsigned long s_blocksize; - loff_t s_maxbytes; /* Max file size */ - struct file_system_type *s_type; - const struct super_operations *s_op; - const struct dquot_operations *dq_op; - const struct quotactl_ops *s_qcop; - const struct export_operations *s_export_op; - unsigned long s_flags; - unsigned long s_iflags; /* internal SB_I_* flags */ - unsigned long s_magic; - struct dentry *s_root; - struct rw_semaphore s_umount; - int s_count; - atomic_t s_active; -#ifdef CONFIG_SECURITY - void *s_security; -#endif - const struct xattr_handler **s_xattr; - - const struct fscrypt_operations *s_cop; - - struct hlist_bl_head s_anon; /* anonymous dentries for (nfs) exporting */ - struct list_head s_mounts; /* list of mounts; _not_ for fs use */ - struct block_device *s_bdev; - struct backing_dev_info *s_bdi; - struct mtd_info *s_mtd; - struct hlist_node s_instances; - unsigned int s_quota_types; /* Bitmask of supported quota types */ - struct quota_info s_dquot; /* Diskquota specific options */ - - struct sb_writers s_writers; - - char s_id[32]; /* Informational name */ - u8 s_uuid[16]; /* UUID */ - - void *s_fs_info; /* Filesystem private info */ - unsigned int s_max_links; - fmode_t s_mode; - - /* Granularity of c/m/atime in ns. - Cannot be worse than a second */ - u32 s_time_gran; - - /* - * The next field is for VFS *only*. No filesystems have any business - * even looking at it. You had been warned. - */ - struct mutex s_vfs_rename_mutex; /* Kludge */ - - /* - * Filesystem subtype. If non-empty the filesystem type field - * in /proc/mounts will be "type.subtype" - */ - char *s_subtype; - - /* - * Saved mount options for lazy filesystems using - * generic_show_options() - */ - char __rcu *s_options; - const struct dentry_operations *s_d_op; /* default d_op for dentries */ - - /* - * Saved pool identifier for cleancache (-1 means none) - */ - int cleancache_poolid; - - struct shrinker s_shrink; /* per-sb shrinker handle */ - - /* Number of inodes with nlink == 0 but still referenced */ - atomic_long_t s_remove_count; - - /* Being remounted read-only */ - int s_readonly_remount; - - /* AIO completions deferred from interrupt context */ - struct workqueue_struct *s_dio_done_wq; - struct hlist_head s_pins; - - /* - * Owning user namespace and default context in which to - * interpret filesystem uids, gids, quotas, device nodes, - * xattrs and security labels. - */ - struct user_namespace *s_user_ns; - - /* - * Keep the lru lists last in the structure so they always sit on their - * own individual cachelines. - */ - struct list_lru s_dentry_lru ____cacheline_aligned_in_smp; - struct list_lru s_inode_lru ____cacheline_aligned_in_smp; - struct rcu_head rcu; - struct work_struct destroy_work; - - struct mutex s_sync_lock; /* sync serialisation lock */ - - /* - * Indicates how deep in a filesystem stack this SB is - */ - int s_stack_depth; - - /* s_inode_list_lock protects s_inodes */ - spinlock_t s_inode_list_lock ____cacheline_aligned_in_smp; - struct list_head s_inodes; /* all inodes */ - - spinlock_t s_inode_wblist_lock; - struct list_head s_inodes_wb; /* writeback inodes */ -}; - -/* Helper functions so that in most cases filesystems will - * not need to deal directly with kuid_t and kgid_t and can - * instead deal with the raw numeric values that are stored - * in the filesystem. - */ -static inline uid_t i_uid_read(const struct inode *inode) -{ - return from_kuid(inode->i_sb->s_user_ns, inode->i_uid); -} - -static inline gid_t i_gid_read(const struct inode *inode) -{ - return from_kgid(inode->i_sb->s_user_ns, inode->i_gid); -} - -static inline void i_uid_write(struct inode *inode, uid_t uid) -{ - inode->i_uid = make_kuid(inode->i_sb->s_user_ns, uid); -} - -static inline void i_gid_write(struct inode *inode, gid_t gid) -{ - inode->i_gid = make_kgid(inode->i_sb->s_user_ns, gid); -} - -extern struct timespec current_fs_time(struct super_block *sb); -extern struct timespec current_time(struct inode *inode); - -/* - * Snapshotting support. - */ - -void __sb_end_write(struct super_block *sb, int level); -int __sb_start_write(struct super_block *sb, int level, bool wait); - -#define __sb_writers_acquired(sb, lev) \ - percpu_rwsem_acquire(&(sb)->s_writers.rw_sem[(lev)-1], 1, _THIS_IP_) -#define __sb_writers_release(sb, lev) \ - percpu_rwsem_release(&(sb)->s_writers.rw_sem[(lev)-1], 1, _THIS_IP_) - -/** - * sb_end_write - drop write access to a superblock - * @sb: the super we wrote to - * - * Decrement number of writers to the filesystem. Wake up possible waiters - * wanting to freeze the filesystem. - */ -static inline void sb_end_write(struct super_block *sb) -{ - __sb_end_write(sb, SB_FREEZE_WRITE); -} - -/** - * sb_end_pagefault - drop write access to a superblock from a page fault - * @sb: the super we wrote to - * - * Decrement number of processes handling write page fault to the filesystem. - * Wake up possible waiters wanting to freeze the filesystem. - */ -static inline void sb_end_pagefault(struct super_block *sb) -{ - __sb_end_write(sb, SB_FREEZE_PAGEFAULT); -} - -/** - * sb_end_intwrite - drop write access to a superblock for internal fs purposes - * @sb: the super we wrote to - * - * Decrement fs-internal number of writers to the filesystem. Wake up possible - * waiters wanting to freeze the filesystem. - */ -static inline void sb_end_intwrite(struct super_block *sb) -{ - __sb_end_write(sb, SB_FREEZE_FS); -} - -/** - * sb_start_write - get write access to a superblock - * @sb: the super we write to - * - * When a process wants to write data or metadata to a file system (i.e. dirty - * a page or an inode), it should embed the operation in a sb_start_write() - - * sb_end_write() pair to get exclusion against file system freezing. This - * function increments number of writers preventing freezing. If the file - * system is already frozen, the function waits until the file system is - * thawed. - * - * Since freeze protection behaves as a lock, users have to preserve - * ordering of freeze protection and other filesystem locks. Generally, - * freeze protection should be the outermost lock. In particular, we have: - * - * sb_start_write - * -> i_mutex (write path, truncate, directory ops, ...) - * -> s_umount (freeze_super, thaw_super) - */ -static inline void sb_start_write(struct super_block *sb) -{ - __sb_start_write(sb, SB_FREEZE_WRITE, true); -} - -static inline int sb_start_write_trylock(struct super_block *sb) -{ - return __sb_start_write(sb, SB_FREEZE_WRITE, false); -} - -/** - * sb_start_pagefault - get write access to a superblock from a page fault - * @sb: the super we write to - * - * When a process starts handling write page fault, it should embed the - * operation into sb_start_pagefault() - sb_end_pagefault() pair to get - * exclusion against file system freezing. This is needed since the page fault - * is going to dirty a page. This function increments number of running page - * faults preventing freezing. If the file system is already frozen, the - * function waits until the file system is thawed. - * - * Since page fault freeze protection behaves as a lock, users have to preserve - * ordering of freeze protection and other filesystem locks. It is advised to - * put sb_start_pagefault() close to mmap_sem in lock ordering. Page fault - * handling code implies lock dependency: - * - * mmap_sem - * -> sb_start_pagefault - */ -static inline void sb_start_pagefault(struct super_block *sb) -{ - __sb_start_write(sb, SB_FREEZE_PAGEFAULT, true); -} - -/* - * sb_start_intwrite - get write access to a superblock for internal fs purposes - * @sb: the super we write to - * - * This is the third level of protection against filesystem freezing. It is - * free for use by a filesystem. The only requirement is that it must rank - * below sb_start_pagefault. - * - * For example filesystem can call sb_start_intwrite() when starting a - * transaction which somewhat eases handling of freezing for internal sources - * of filesystem changes (internal fs threads, discarding preallocation on file - * close, etc.). - */ -static inline void sb_start_intwrite(struct super_block *sb) -{ - __sb_start_write(sb, SB_FREEZE_FS, true); -} - - -extern bool inode_owner_or_capable(const struct inode *inode); - -/* - * VFS helper functions.. - */ -extern int vfs_create(struct inode *, struct dentry *, umode_t, bool); -extern int vfs_mkdir(struct inode *, struct dentry *, umode_t); -extern int vfs_mknod(struct inode *, struct dentry *, umode_t, dev_t); -extern int vfs_symlink(struct inode *, struct dentry *, const char *); -extern int vfs_link(struct dentry *, struct inode *, struct dentry *, struct inode **); -extern int vfs_rmdir(struct inode *, struct dentry *); -extern int vfs_unlink(struct inode *, struct dentry *, struct inode **); -extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *, struct inode **, unsigned int); -extern int vfs_whiteout(struct inode *, struct dentry *); - -/* - * VFS file helper functions. - */ -extern void inode_init_owner(struct inode *inode, const struct inode *dir, - umode_t mode); -extern bool may_open_dev(const struct path *path); -/* - * VFS FS_IOC_FIEMAP helper definitions. - */ -struct fiemap_extent_info { - unsigned int fi_flags; /* Flags as passed from user */ - unsigned int fi_extents_mapped; /* Number of mapped extents */ - unsigned int fi_extents_max; /* Size of fiemap_extent array */ - struct fiemap_extent __user *fi_extents_start; /* Start of - fiemap_extent array */ -}; -int fiemap_fill_next_extent(struct fiemap_extent_info *info, u64 logical, - u64 phys, u64 len, u32 flags); -int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags); - -/* - * File types - * - * NOTE! These match bits 12..15 of stat.st_mode - * (ie "(i_mode >> 12) & 15"). - */ -#define DT_UNKNOWN 0 -#define DT_FIFO 1 -#define DT_CHR 2 -#define DT_DIR 4 -#define DT_BLK 6 -#define DT_REG 8 -#define DT_LNK 10 -#define DT_SOCK 12 -#define DT_WHT 14 - -/* - * This is the "filldir" function type, used by readdir() to let - * the kernel specify what kind of dirent layout it wants to have. - * This allows the kernel to read directories into kernel space or - * to have different dirent layouts depending on the binary type. - */ -struct dir_context; -typedef int (*filldir_t)(struct dir_context *, const char *, int, loff_t, u64, - unsigned); - -struct dir_context { - const filldir_t actor; - loff_t pos; -}; - -struct block_device_operations; - -/* These macros are for out of kernel modules to test that - * the kernel supports the unlocked_ioctl and compat_ioctl - * fields in struct file_operations. */ -#define HAVE_COMPAT_IOCTL 1 -#define HAVE_UNLOCKED_IOCTL 1 - -/* - * These flags let !MMU mmap() govern direct device mapping vs immediate - * copying more easily for MAP_PRIVATE, especially for ROM filesystems. - * - * NOMMU_MAP_COPY: Copy can be mapped (MAP_PRIVATE) - * NOMMU_MAP_DIRECT: Can be mapped directly (MAP_SHARED) - * NOMMU_MAP_READ: Can be mapped for reading - * NOMMU_MAP_WRITE: Can be mapped for writing - * NOMMU_MAP_EXEC: Can be mapped for execution - */ -#define NOMMU_MAP_COPY 0x00000001 -#define NOMMU_MAP_DIRECT 0x00000008 -#define NOMMU_MAP_READ VM_MAYREAD -#define NOMMU_MAP_WRITE VM_MAYWRITE -#define NOMMU_MAP_EXEC VM_MAYEXEC - -#define NOMMU_VMFLAGS \ - (NOMMU_MAP_READ | NOMMU_MAP_WRITE | NOMMU_MAP_EXEC) - - -struct iov_iter; - -struct file_operations { - struct module *owner; - loff_t (*llseek) (struct file *, loff_t, int); - ssize_t (*read) (struct file *, char __user *, size_t, loff_t *); - ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); - ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); - ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); - int (*iterate) (struct file *, struct dir_context *); - int (*iterate_shared) (struct file *, struct dir_context *); - unsigned int (*poll) (struct file *, struct poll_table_struct *); - long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); - long (*compat_ioctl) (struct file *, unsigned int, unsigned long); - int (*mmap) (struct file *, struct vm_area_struct *); - int (*open) (struct inode *, struct file *); - int (*flush) (struct file *, fl_owner_t id); - int (*release) (struct inode *, struct file *); - int (*fsync) (struct file *, loff_t, loff_t, int datasync); - int (*fasync) (int, struct file *, int); - int (*lock) (struct file *, int, struct file_lock *); - ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); - unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); - int (*check_flags)(int); - int (*flock) (struct file *, int, struct file_lock *); - ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); - ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); - int (*setlease)(struct file *, long, struct file_lock **, void **); - long (*fallocate)(struct file *file, int mode, loff_t offset, - loff_t len); - void (*show_fdinfo)(struct seq_file *m, struct file *f); -#ifndef CONFIG_MMU - unsigned (*mmap_capabilities)(struct file *); -#endif - ssize_t (*copy_file_range)(struct file *, loff_t, struct file *, - loff_t, size_t, unsigned int); - int (*clone_file_range)(struct file *, loff_t, struct file *, loff_t, - u64); - ssize_t (*dedupe_file_range)(struct file *, u64, u64, struct file *, - u64); -}; - -struct inode_operations { - struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int); - const char * (*get_link) (struct dentry *, struct inode *, struct delayed_call *); - int (*permission) (struct inode *, int); - struct posix_acl * (*get_acl)(struct inode *, int); - - int (*readlink) (struct dentry *, char __user *,int); - - int (*create) (struct inode *,struct dentry *, umode_t, bool); - int (*link) (struct dentry *,struct inode *,struct dentry *); - int (*unlink) (struct inode *,struct dentry *); - int (*symlink) (struct inode *,struct dentry *,const char *); - int (*mkdir) (struct inode *,struct dentry *,umode_t); - int (*rmdir) (struct inode *,struct dentry *); - int (*mknod) (struct inode *,struct dentry *,umode_t,dev_t); - int (*rename) (struct inode *, struct dentry *, - struct inode *, struct dentry *, unsigned int); - int (*setattr) (struct dentry *, struct iattr *); - int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); - ssize_t (*listxattr) (struct dentry *, char *, size_t); - int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, - u64 len); - int (*update_time)(struct inode *, struct timespec *, int); - int (*atomic_open)(struct inode *, struct dentry *, - struct file *, unsigned open_flag, - umode_t create_mode, int *opened); - int (*tmpfile) (struct inode *, struct dentry *, umode_t); - int (*set_acl)(struct inode *, struct posix_acl *, int); -} ____cacheline_aligned; - -ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector, - unsigned long nr_segs, unsigned long fast_segs, - struct iovec *fast_pointer, - struct iovec **ret_pointer); - -extern ssize_t __vfs_read(struct file *, char __user *, size_t, loff_t *); -extern ssize_t __vfs_write(struct file *, const char __user *, size_t, loff_t *); -extern ssize_t vfs_read(struct file *, char __user *, size_t, loff_t *); -extern ssize_t vfs_write(struct file *, const char __user *, size_t, loff_t *); -extern ssize_t vfs_readv(struct file *, const struct iovec __user *, - unsigned long, loff_t *, int); -extern ssize_t vfs_writev(struct file *, const struct iovec __user *, - unsigned long, loff_t *, int); -extern ssize_t vfs_copy_file_range(struct file *, loff_t , struct file *, - loff_t, size_t, unsigned int); -extern int vfs_clone_file_range(struct file *file_in, loff_t pos_in, - struct file *file_out, loff_t pos_out, u64 len); -extern int vfs_dedupe_file_range(struct file *file, - struct file_dedupe_range *same); - -struct super_operations { - struct inode *(*alloc_inode)(struct super_block *sb); - void (*destroy_inode)(struct inode *); - - void (*dirty_inode) (struct inode *, int flags); - int (*write_inode) (struct inode *, struct writeback_control *wbc); - int (*drop_inode) (struct inode *); - void (*evict_inode) (struct inode *); - void (*put_super) (struct super_block *); - int (*sync_fs)(struct super_block *sb, int wait); - int (*freeze_super) (struct super_block *); - int (*freeze_fs) (struct super_block *); - int (*thaw_super) (struct super_block *); - int (*unfreeze_fs) (struct super_block *); - int (*statfs) (struct dentry *, struct kstatfs *); - int (*remount_fs) (struct super_block *, int *, char *); - void (*umount_begin) (struct super_block *); - - int (*show_options)(struct seq_file *, struct dentry *); - int (*show_devname)(struct seq_file *, struct dentry *); - int (*show_path)(struct seq_file *, struct dentry *); - int (*show_stats)(struct seq_file *, struct dentry *); -#ifdef CONFIG_QUOTA - ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t); - ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); - struct dquot **(*get_dquots)(struct inode *); -#endif - int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t); - long (*nr_cached_objects)(struct super_block *, - struct shrink_control *); - long (*free_cached_objects)(struct super_block *, - struct shrink_control *); -}; - -/* - * Inode flags - they have no relation to superblock flags now - */ -#define S_SYNC 1 /* Writes are synced at once */ -#define S_NOATIME 2 /* Do not update access times */ -#define S_APPEND 4 /* Append-only file */ -#define S_IMMUTABLE 8 /* Immutable file */ -#define S_DEAD 16 /* removed, but still open directory */ -#define S_NOQUOTA 32 /* Inode is not counted to quota */ -#define S_DIRSYNC 64 /* Directory modifications are synchronous */ -#define S_NOCMTIME 128 /* Do not update file c/mtime */ -#define S_SWAPFILE 256 /* Do not truncate: swapon got its bmaps */ -#define S_PRIVATE 512 /* Inode is fs-internal */ -#define S_IMA 1024 /* Inode has an associated IMA struct */ -#define S_AUTOMOUNT 2048 /* Automount/referral quasi-directory */ -#define S_NOSEC 4096 /* no suid or xattr security attributes */ -#ifdef CONFIG_FS_DAX -#define S_DAX 8192 /* Direct Access, avoiding the page cache */ -#else -#define S_DAX 0 /* Make all the DAX code disappear */ -#endif - -/* - * Note that nosuid etc flags are inode-specific: setting some file-system - * flags just means all the inodes inherit those flags by default. It might be - * possible to override it selectively if you really wanted to with some - * ioctl() that is not currently implemented. - * - * Exception: MS_RDONLY is always applied to the entire file system. - * - * Unfortunately, it is possible to change a filesystems flags with it mounted - * with files in use. This means that all of the inodes will not have their - * i_flags updated. Hence, i_flags no longer inherit the superblock mount - * flags, so these have to be checked separately. -- rmk@arm.uk.linux.org - */ -#define __IS_FLG(inode, flg) ((inode)->i_sb->s_flags & (flg)) - -#define IS_RDONLY(inode) ((inode)->i_sb->s_flags & MS_RDONLY) -#define IS_SYNC(inode) (__IS_FLG(inode, MS_SYNCHRONOUS) || \ - ((inode)->i_flags & S_SYNC)) -#define IS_DIRSYNC(inode) (__IS_FLG(inode, MS_SYNCHRONOUS|MS_DIRSYNC) || \ - ((inode)->i_flags & (S_SYNC|S_DIRSYNC))) -#define IS_MANDLOCK(inode) __IS_FLG(inode, MS_MANDLOCK) -#define IS_NOATIME(inode) __IS_FLG(inode, MS_RDONLY|MS_NOATIME) -#define IS_I_VERSION(inode) __IS_FLG(inode, MS_I_VERSION) - -#define IS_NOQUOTA(inode) ((inode)->i_flags & S_NOQUOTA) -#define IS_APPEND(inode) ((inode)->i_flags & S_APPEND) -#define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE) -#define IS_POSIXACL(inode) __IS_FLG(inode, MS_POSIXACL) - -#define IS_DEADDIR(inode) ((inode)->i_flags & S_DEAD) -#define IS_NOCMTIME(inode) ((inode)->i_flags & S_NOCMTIME) -#define IS_SWAPFILE(inode) ((inode)->i_flags & S_SWAPFILE) -#define IS_PRIVATE(inode) ((inode)->i_flags & S_PRIVATE) -#define IS_IMA(inode) ((inode)->i_flags & S_IMA) -#define IS_AUTOMOUNT(inode) ((inode)->i_flags & S_AUTOMOUNT) -#define IS_NOSEC(inode) ((inode)->i_flags & S_NOSEC) -#define IS_DAX(inode) ((inode)->i_flags & S_DAX) - -#define IS_WHITEOUT(inode) (S_ISCHR(inode->i_mode) && \ - (inode)->i_rdev == WHITEOUT_DEV) - -static inline bool HAS_UNMAPPED_ID(struct inode *inode) -{ - return !uid_valid(inode->i_uid) || !gid_valid(inode->i_gid); -} - -/* - * Inode state bits. Protected by inode->i_lock - * - * Three bits determine the dirty state of the inode, I_DIRTY_SYNC, - * I_DIRTY_DATASYNC and I_DIRTY_PAGES. - * - * Four bits define the lifetime of an inode. Initially, inodes are I_NEW, - * until that flag is cleared. I_WILL_FREE, I_FREEING and I_CLEAR are set at - * various stages of removing an inode. - * - * Two bits are used for locking and completion notification, I_NEW and I_SYNC. - * - * I_DIRTY_SYNC Inode is dirty, but doesn't have to be written on - * fdatasync(). i_atime is the usual cause. - * I_DIRTY_DATASYNC Data-related inode changes pending. We keep track of - * these changes separately from I_DIRTY_SYNC so that we - * don't have to write inode on fdatasync() when only - * mtime has changed in it. - * I_DIRTY_PAGES Inode has dirty pages. Inode itself may be clean. - * I_NEW Serves as both a mutex and completion notification. - * New inodes set I_NEW. If two processes both create - * the same inode, one of them will release its inode and - * wait for I_NEW to be released before returning. - * Inodes in I_WILL_FREE, I_FREEING or I_CLEAR state can - * also cause waiting on I_NEW, without I_NEW actually - * being set. find_inode() uses this to prevent returning - * nearly-dead inodes. - * I_WILL_FREE Must be set when calling write_inode_now() if i_count - * is zero. I_FREEING must be set when I_WILL_FREE is - * cleared. - * I_FREEING Set when inode is about to be freed but still has dirty - * pages or buffers attached or the inode itself is still - * dirty. - * I_CLEAR Added by clear_inode(). In this state the inode is - * clean and can be destroyed. Inode keeps I_FREEING. - * - * Inodes that are I_WILL_FREE, I_FREEING or I_CLEAR are - * prohibited for many purposes. iget() must wait for - * the inode to be completely released, then create it - * anew. Other functions will just ignore such inodes, - * if appropriate. I_NEW is used for waiting. - * - * I_SYNC Writeback of inode is running. The bit is set during - * data writeback, and cleared with a wakeup on the bit - * address once it is done. The bit is also used to pin - * the inode in memory for flusher thread. - * - * I_REFERENCED Marks the inode as recently references on the LRU list. - * - * I_DIO_WAKEUP Never set. Only used as a key for wait_on_bit(). - * - * I_WB_SWITCH Cgroup bdi_writeback switching in progress. Used to - * synchronize competing switching instances and to tell - * wb stat updates to grab mapping->tree_lock. See - * inode_switch_wb_work_fn() for details. - * - * Q: What is the difference between I_WILL_FREE and I_FREEING? - */ -#define I_DIRTY_SYNC (1 << 0) -#define I_DIRTY_DATASYNC (1 << 1) -#define I_DIRTY_PAGES (1 << 2) -#define __I_NEW 3 -#define I_NEW (1 << __I_NEW) -#define I_WILL_FREE (1 << 4) -#define I_FREEING (1 << 5) -#define I_CLEAR (1 << 6) -#define __I_SYNC 7 -#define I_SYNC (1 << __I_SYNC) -#define I_REFERENCED (1 << 8) -#define __I_DIO_WAKEUP 9 -#define I_DIO_WAKEUP (1 << __I_DIO_WAKEUP) -#define I_LINKABLE (1 << 10) -#define I_DIRTY_TIME (1 << 11) -#define __I_DIRTY_TIME_EXPIRED 12 -#define I_DIRTY_TIME_EXPIRED (1 << __I_DIRTY_TIME_EXPIRED) -#define I_WB_SWITCH (1 << 13) - -#define I_DIRTY (I_DIRTY_SYNC | I_DIRTY_DATASYNC | I_DIRTY_PAGES) -#define I_DIRTY_ALL (I_DIRTY | I_DIRTY_TIME) - -extern void __mark_inode_dirty(struct inode *, int); -static inline void mark_inode_dirty(struct inode *inode) -{ - __mark_inode_dirty(inode, I_DIRTY); -} - -static inline void mark_inode_dirty_sync(struct inode *inode) -{ - __mark_inode_dirty(inode, I_DIRTY_SYNC); -} - -extern void inc_nlink(struct inode *inode); -extern void drop_nlink(struct inode *inode); -extern void clear_nlink(struct inode *inode); -extern void set_nlink(struct inode *inode, unsigned int nlink); - -static inline void inode_inc_link_count(struct inode *inode) -{ - inc_nlink(inode); - mark_inode_dirty(inode); -} - -static inline void inode_dec_link_count(struct inode *inode) -{ - drop_nlink(inode); - mark_inode_dirty(inode); -} - -/** - * inode_inc_iversion - increments i_version - * @inode: inode that need to be updated - * - * Every time the inode is modified, the i_version field will be incremented. - * The filesystem has to be mounted with i_version flag - */ - -static inline void inode_inc_iversion(struct inode *inode) -{ - spin_lock(&inode->i_lock); - inode->i_version++; - spin_unlock(&inode->i_lock); -} - -enum file_time_flags { - S_ATIME = 1, - S_MTIME = 2, - S_CTIME = 4, - S_VERSION = 8, -}; - -extern void touch_atime(const struct path *); -static inline void file_accessed(struct file *file) -{ - if (!(file->f_flags & O_NOATIME)) - touch_atime(&file->f_path); -} - -int sync_inode(struct inode *inode, struct writeback_control *wbc); -int sync_inode_metadata(struct inode *inode, int wait); - -struct file_system_type { - const char *name; - int fs_flags; -#define FS_REQUIRES_DEV 1 -#define FS_BINARY_MOUNTDATA 2 -#define FS_HAS_SUBTYPE 4 -#define FS_USERNS_MOUNT 8 /* Can be mounted by userns root */ -#define FS_RENAME_DOES_D_MOVE 32768 /* FS will handle d_move() during rename() internally. */ - struct dentry *(*mount) (struct file_system_type *, int, - const char *, void *); - void (*kill_sb) (struct super_block *); - struct module *owner; - struct file_system_type * next; - struct hlist_head fs_supers; - - struct lock_class_key s_lock_key; - struct lock_class_key s_umount_key; - struct lock_class_key s_vfs_rename_key; - struct lock_class_key s_writers_key[SB_FREEZE_LEVELS]; - - struct lock_class_key i_lock_key; - struct lock_class_key i_mutex_key; - struct lock_class_key i_mutex_dir_key; -}; - -#define MODULE_ALIAS_FS(NAME) MODULE_ALIAS("fs-" NAME) - -extern struct dentry *mount_ns(struct file_system_type *fs_type, - int flags, void *data, void *ns, struct user_namespace *user_ns, - int (*fill_super)(struct super_block *, void *, int)); -extern struct dentry *mount_bdev(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data, - int (*fill_super)(struct super_block *, void *, int)); -extern struct dentry *mount_single(struct file_system_type *fs_type, - int flags, void *data, - int (*fill_super)(struct super_block *, void *, int)); -extern struct dentry *mount_nodev(struct file_system_type *fs_type, - int flags, void *data, - int (*fill_super)(struct super_block *, void *, int)); -extern struct dentry *mount_subtree(struct vfsmount *mnt, const char *path); -void generic_shutdown_super(struct super_block *sb); -void kill_block_super(struct super_block *sb); -void kill_anon_super(struct super_block *sb); -void kill_litter_super(struct super_block *sb); -void deactivate_super(struct super_block *sb); -void deactivate_locked_super(struct super_block *sb); -int set_anon_super(struct super_block *s, void *data); -int get_anon_bdev(dev_t *); -void free_anon_bdev(dev_t); -struct super_block *sget_userns(struct file_system_type *type, - int (*test)(struct super_block *,void *), - int (*set)(struct super_block *,void *), - int flags, struct user_namespace *user_ns, - void *data); -struct super_block *sget(struct file_system_type *type, - int (*test)(struct super_block *,void *), - int (*set)(struct super_block *,void *), - int flags, void *data); -extern struct dentry *mount_pseudo_xattr(struct file_system_type *, char *, - const struct super_operations *ops, - const struct xattr_handler **xattr, - const struct dentry_operations *dops, - unsigned long); - -static inline struct dentry * -mount_pseudo(struct file_system_type *fs_type, char *name, - const struct super_operations *ops, - const struct dentry_operations *dops, unsigned long magic) -{ - return mount_pseudo_xattr(fs_type, name, ops, NULL, dops, magic); -} - -/* Alas, no aliases. Too much hassle with bringing module.h everywhere */ -#define fops_get(fops) \ - (((fops) && try_module_get((fops)->owner) ? (fops) : NULL)) -#define fops_put(fops) \ - do { if (fops) module_put((fops)->owner); } while(0) -/* - * This one is to be used *ONLY* from ->open() instances. - * fops must be non-NULL, pinned down *and* module dependencies - * should be sufficient to pin the caller down as well. - */ -#define replace_fops(f, fops) \ - do { \ - struct file *__file = (f); \ - fops_put(__file->f_op); \ - BUG_ON(!(__file->f_op = (fops))); \ - } while(0) - -extern int register_filesystem(struct file_system_type *); -extern int unregister_filesystem(struct file_system_type *); -extern struct vfsmount *kern_mount_data(struct file_system_type *, void *data); -#define kern_mount(type) kern_mount_data(type, NULL) -extern void kern_unmount(struct vfsmount *mnt); -extern int may_umount_tree(struct vfsmount *); -extern int may_umount(struct vfsmount *); -extern long do_mount(const char *, const char __user *, - const char *, unsigned long, void *); -extern struct vfsmount *collect_mounts(struct path *); -extern void drop_collected_mounts(struct vfsmount *); -extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *, - struct vfsmount *); -extern int vfs_statfs(struct path *, struct kstatfs *); -extern int user_statfs(const char __user *, struct kstatfs *); -extern int fd_statfs(int, struct kstatfs *); -extern int vfs_ustat(dev_t, struct kstatfs *); -extern int freeze_super(struct super_block *super); -extern int thaw_super(struct super_block *super); -extern bool our_mnt(struct vfsmount *mnt); - -extern int current_umask(void); - -extern void ihold(struct inode * inode); -extern void iput(struct inode *); -extern int generic_update_time(struct inode *, struct timespec *, int); - -/* /sys/fs */ -extern struct kobject *fs_kobj; - -#define MAX_RW_COUNT (INT_MAX & PAGE_MASK) - -#ifdef CONFIG_MANDATORY_FILE_LOCKING -extern int locks_mandatory_locked(struct file *); -extern int locks_mandatory_area(struct inode *, struct file *, loff_t, loff_t, unsigned char); - -/* - * Candidates for mandatory locking have the setgid bit set - * but no group execute bit - an otherwise meaningless combination. - */ - -static inline int __mandatory_lock(struct inode *ino) -{ - return (ino->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID; -} - -/* - * ... and these candidates should be on MS_MANDLOCK mounted fs, - * otherwise these will be advisory locks - */ - -static inline int mandatory_lock(struct inode *ino) -{ - return IS_MANDLOCK(ino) && __mandatory_lock(ino); -} - -static inline int locks_verify_locked(struct file *file) -{ - if (mandatory_lock(locks_inode(file))) - return locks_mandatory_locked(file); - return 0; -} - -static inline int locks_verify_truncate(struct inode *inode, - struct file *f, - loff_t size) -{ - if (!inode->i_flctx || !mandatory_lock(inode)) - return 0; - - if (size < inode->i_size) { - return locks_mandatory_area(inode, f, size, inode->i_size - 1, - F_WRLCK); - } else { - return locks_mandatory_area(inode, f, inode->i_size, size - 1, - F_WRLCK); - } -} - -#else /* !CONFIG_MANDATORY_FILE_LOCKING */ - -static inline int locks_mandatory_locked(struct file *file) -{ - return 0; -} - -static inline int locks_mandatory_area(struct inode *inode, struct file *filp, - loff_t start, loff_t end, unsigned char type) -{ - return 0; -} - -static inline int __mandatory_lock(struct inode *inode) -{ - return 0; -} - -static inline int mandatory_lock(struct inode *inode) -{ - return 0; -} - -static inline int locks_verify_locked(struct file *file) -{ - return 0; -} - -static inline int locks_verify_truncate(struct inode *inode, struct file *filp, - size_t size) -{ - return 0; -} - -#endif /* CONFIG_MANDATORY_FILE_LOCKING */ - - -#ifdef CONFIG_FILE_LOCKING -static inline int break_lease(struct inode *inode, unsigned int mode) -{ - /* - * Since this check is lockless, we must ensure that any refcounts - * taken are done before checking i_flctx->flc_lease. Otherwise, we - * could end up racing with tasks trying to set a new lease on this - * file. - */ - smp_mb(); - if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) - return __break_lease(inode, mode, FL_LEASE); - return 0; -} - -static inline int break_deleg(struct inode *inode, unsigned int mode) -{ - /* - * Since this check is lockless, we must ensure that any refcounts - * taken are done before checking i_flctx->flc_lease. Otherwise, we - * could end up racing with tasks trying to set a new lease on this - * file. - */ - smp_mb(); - if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) - return __break_lease(inode, mode, FL_DELEG); - return 0; -} - -static inline int try_break_deleg(struct inode *inode, struct inode **delegated_inode) -{ - int ret; - - ret = break_deleg(inode, O_WRONLY|O_NONBLOCK); - if (ret == -EWOULDBLOCK && delegated_inode) { - *delegated_inode = inode; - ihold(inode); - } - return ret; -} - -static inline int break_deleg_wait(struct inode **delegated_inode) -{ - int ret; - - ret = break_deleg(*delegated_inode, O_WRONLY); - iput(*delegated_inode); - *delegated_inode = NULL; - return ret; -} - -static inline int break_layout(struct inode *inode, bool wait) -{ - smp_mb(); - if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease)) - return __break_lease(inode, - wait ? O_WRONLY : O_WRONLY | O_NONBLOCK, - FL_LAYOUT); - return 0; -} - -#else /* !CONFIG_FILE_LOCKING */ -static inline int break_lease(struct inode *inode, unsigned int mode) -{ - return 0; -} - -static inline int break_deleg(struct inode *inode, unsigned int mode) -{ - return 0; -} - -static inline int try_break_deleg(struct inode *inode, struct inode **delegated_inode) -{ - return 0; -} - -static inline int break_deleg_wait(struct inode **delegated_inode) -{ - BUG(); - return 0; -} - -static inline int break_layout(struct inode *inode, bool wait) -{ - return 0; -} - -#endif /* CONFIG_FILE_LOCKING */ - -/* fs/open.c */ -struct audit_names; -struct filename { - const char *name; /* pointer to actual string */ - const __user char *uptr; /* original userland pointer */ - struct audit_names *aname; - int refcnt; - const char iname[]; -}; - -extern long vfs_truncate(const struct path *, loff_t); -extern int do_truncate(struct dentry *, loff_t start, unsigned int time_attrs, - struct file *filp); -extern int vfs_fallocate(struct file *file, int mode, loff_t offset, - loff_t len); -extern long do_sys_open(int dfd, const char __user *filename, int flags, - umode_t mode); -extern struct file *file_open_name(struct filename *, int, umode_t); -extern struct file *filp_open(const char *, int, umode_t); -extern struct file *file_open_root(struct dentry *, struct vfsmount *, - const char *, int, umode_t); -extern struct file * dentry_open(const struct path *, int, const struct cred *); -extern int filp_close(struct file *, fl_owner_t id); - -extern struct filename *getname_flags(const char __user *, int, int *); -extern struct filename *getname(const char __user *); -extern struct filename *getname_kernel(const char *); -extern void putname(struct filename *name); - -enum { - FILE_CREATED = 1, - FILE_OPENED = 2 -}; -extern int finish_open(struct file *file, struct dentry *dentry, - int (*open)(struct inode *, struct file *), - int *opened); -extern int finish_no_open(struct file *file, struct dentry *dentry); - -/* fs/ioctl.c */ - -extern int ioctl_preallocate(struct file *filp, void __user *argp); - -/* fs/dcache.c */ -extern void __init vfs_caches_init_early(void); -extern void __init vfs_caches_init(void); - -extern struct kmem_cache *names_cachep; - -#define __getname() kmem_cache_alloc(names_cachep, GFP_KERNEL) -#define __putname(name) kmem_cache_free(names_cachep, (void *)(name)) - -#ifdef CONFIG_BLOCK -extern int register_blkdev(unsigned int, const char *); -extern void unregister_blkdev(unsigned int, const char *); -extern struct block_device *bdget(dev_t); -extern struct block_device *bdgrab(struct block_device *bdev); -extern void bd_set_size(struct block_device *, loff_t size); -extern void bd_forget(struct inode *inode); -extern void bdput(struct block_device *); -extern void invalidate_bdev(struct block_device *); -extern void iterate_bdevs(void (*)(struct block_device *, void *), void *); -extern int sync_blockdev(struct block_device *bdev); -extern void kill_bdev(struct block_device *); -extern struct super_block *freeze_bdev(struct block_device *); -extern void emergency_thaw_all(void); -extern int thaw_bdev(struct block_device *bdev, struct super_block *sb); -extern int fsync_bdev(struct block_device *); - -extern struct super_block *blockdev_superblock; - -static inline bool sb_is_blkdev_sb(struct super_block *sb) -{ - return sb == blockdev_superblock; -} -#else -static inline void bd_forget(struct inode *inode) {} -static inline int sync_blockdev(struct block_device *bdev) { return 0; } -static inline void kill_bdev(struct block_device *bdev) {} -static inline void invalidate_bdev(struct block_device *bdev) {} - -static inline struct super_block *freeze_bdev(struct block_device *sb) -{ - return NULL; -} - -static inline int thaw_bdev(struct block_device *bdev, struct super_block *sb) -{ - return 0; -} - -static inline void iterate_bdevs(void (*f)(struct block_device *, void *), void *arg) -{ -} - -static inline bool sb_is_blkdev_sb(struct super_block *sb) -{ - return false; -} -#endif -extern int sync_filesystem(struct super_block *); -extern const struct file_operations def_blk_fops; -extern const struct file_operations def_chr_fops; -#ifdef CONFIG_BLOCK -extern int ioctl_by_bdev(struct block_device *, unsigned, unsigned long); -extern int blkdev_ioctl(struct block_device *, fmode_t, unsigned, unsigned long); -extern long compat_blkdev_ioctl(struct file *, unsigned, unsigned long); -extern int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder); -extern struct block_device *blkdev_get_by_path(const char *path, fmode_t mode, - void *holder); -extern struct block_device *blkdev_get_by_dev(dev_t dev, fmode_t mode, - void *holder); -extern void blkdev_put(struct block_device *bdev, fmode_t mode); -extern int __blkdev_reread_part(struct block_device *bdev); -extern int blkdev_reread_part(struct block_device *bdev); - -#ifdef CONFIG_SYSFS -extern int bd_link_disk_holder(struct block_device *bdev, struct gendisk *disk); -extern void bd_unlink_disk_holder(struct block_device *bdev, - struct gendisk *disk); -#else -static inline int bd_link_disk_holder(struct block_device *bdev, - struct gendisk *disk) -{ - return 0; -} -static inline void bd_unlink_disk_holder(struct block_device *bdev, - struct gendisk *disk) -{ -} -#endif -#endif - -/* fs/char_dev.c */ -#define CHRDEV_MAJOR_HASH_SIZE 255 -/* Marks the bottom of the first segment of free char majors */ -#define CHRDEV_MAJOR_DYN_END 234 -extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, const char *); -extern int register_chrdev_region(dev_t, unsigned, const char *); -extern int __register_chrdev(unsigned int major, unsigned int baseminor, - unsigned int count, const char *name, - const struct file_operations *fops); -extern void __unregister_chrdev(unsigned int major, unsigned int baseminor, - unsigned int count, const char *name); -extern void unregister_chrdev_region(dev_t, unsigned); -extern void chrdev_show(struct seq_file *,off_t); - -static inline int register_chrdev(unsigned int major, const char *name, - const struct file_operations *fops) -{ - return __register_chrdev(major, 0, 256, name, fops); -} - -static inline void unregister_chrdev(unsigned int major, const char *name) -{ - __unregister_chrdev(major, 0, 256, name); -} - -/* fs/block_dev.c */ -#define BDEVNAME_SIZE 32 /* Largest string for a blockdev identifier */ -#define BDEVT_SIZE 10 /* Largest string for MAJ:MIN for blkdev */ - -#ifdef CONFIG_BLOCK -#define BLKDEV_MAJOR_HASH_SIZE 255 -extern const char *__bdevname(dev_t, char *buffer); -extern const char *bdevname(struct block_device *bdev, char *buffer); -extern struct block_device *lookup_bdev(const char *); -extern void blkdev_show(struct seq_file *,off_t); - -#else -#define BLKDEV_MAJOR_HASH_SIZE 0 -#endif - -extern void init_special_inode(struct inode *, umode_t, dev_t); - -/* Invalid inode operations -- fs/bad_inode.c */ -extern void make_bad_inode(struct inode *); -extern bool is_bad_inode(struct inode *); - -#ifdef CONFIG_BLOCK -static inline bool op_is_write(unsigned int op) -{ - return op == REQ_OP_READ ? false : true; -} - -/* - * return data direction, READ or WRITE - */ -static inline int bio_data_dir(struct bio *bio) -{ - return op_is_write(bio_op(bio)) ? WRITE : READ; -} - -extern void check_disk_size_change(struct gendisk *disk, - struct block_device *bdev); -extern int revalidate_disk(struct gendisk *); -extern int check_disk_change(struct block_device *); -extern int __invalidate_device(struct block_device *, bool); -extern int invalidate_partition(struct gendisk *, int); -#endif -unsigned long invalidate_mapping_pages(struct address_space *mapping, - pgoff_t start, pgoff_t end); - -static inline void invalidate_remote_inode(struct inode *inode) -{ - if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || - S_ISLNK(inode->i_mode)) - invalidate_mapping_pages(inode->i_mapping, 0, -1); -} -extern int invalidate_inode_pages2(struct address_space *mapping); -extern int invalidate_inode_pages2_range(struct address_space *mapping, - pgoff_t start, pgoff_t end); -extern int write_inode_now(struct inode *, int); -extern int filemap_fdatawrite(struct address_space *); -extern int filemap_flush(struct address_space *); -extern int filemap_fdatawait(struct address_space *); -extern void filemap_fdatawait_keep_errors(struct address_space *); -extern int filemap_fdatawait_range(struct address_space *, loff_t lstart, - loff_t lend); -extern int filemap_write_and_wait(struct address_space *mapping); -extern int filemap_write_and_wait_range(struct address_space *mapping, - loff_t lstart, loff_t lend); -extern int __filemap_fdatawrite_range(struct address_space *mapping, - loff_t start, loff_t end, int sync_mode); -extern int filemap_fdatawrite_range(struct address_space *mapping, - loff_t start, loff_t end); -extern int filemap_check_errors(struct address_space *mapping); - -extern int vfs_fsync_range(struct file *file, loff_t start, loff_t end, - int datasync); -extern int vfs_fsync(struct file *file, int datasync); - -/* - * Sync the bytes written if this was a synchronous write. Expect ki_pos - * to already be updated for the write, and will return either the amount - * of bytes passed in, or an error if syncing the file failed. - */ -static inline ssize_t generic_write_sync(struct kiocb *iocb, ssize_t count) -{ - if (iocb->ki_flags & IOCB_DSYNC) { - int ret = vfs_fsync_range(iocb->ki_filp, - iocb->ki_pos - count, iocb->ki_pos - 1, - (iocb->ki_flags & IOCB_SYNC) ? 0 : 1); - if (ret) - return ret; - } - - return count; -} - -extern void emergency_sync(void); -extern void emergency_remount(void); -#ifdef CONFIG_BLOCK -extern sector_t bmap(struct inode *, sector_t); -#endif -extern int notify_change(struct dentry *, struct iattr *, struct inode **); -extern int inode_permission(struct inode *, int); -extern int __inode_permission(struct inode *, int); -extern int generic_permission(struct inode *, int); -extern int __check_sticky(struct inode *dir, struct inode *inode); - -static inline bool execute_ok(struct inode *inode) -{ - return (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode); -} - -static inline void file_start_write(struct file *file) -{ - if (!S_ISREG(file_inode(file)->i_mode)) - return; - __sb_start_write(file_inode(file)->i_sb, SB_FREEZE_WRITE, true); -} - -static inline bool file_start_write_trylock(struct file *file) -{ - if (!S_ISREG(file_inode(file)->i_mode)) - return true; - return __sb_start_write(file_inode(file)->i_sb, SB_FREEZE_WRITE, false); -} - -static inline void file_end_write(struct file *file) -{ - if (!S_ISREG(file_inode(file)->i_mode)) - return; - __sb_end_write(file_inode(file)->i_sb, SB_FREEZE_WRITE); -} - -/* - * get_write_access() gets write permission for a file. - * put_write_access() releases this write permission. - * This is used for regular files. - * We cannot support write (and maybe mmap read-write shared) accesses and - * MAP_DENYWRITE mmappings simultaneously. The i_writecount field of an inode - * can have the following values: - * 0: no writers, no VM_DENYWRITE mappings - * < 0: (-i_writecount) vm_area_structs with VM_DENYWRITE set exist - * > 0: (i_writecount) users are writing to the file. - * - * Normally we operate on that counter with atomic_{inc,dec} and it's safe - * except for the cases where we don't hold i_writecount yet. Then we need to - * use {get,deny}_write_access() - these functions check the sign and refuse - * to do the change if sign is wrong. - */ -static inline int get_write_access(struct inode *inode) -{ - return atomic_inc_unless_negative(&inode->i_writecount) ? 0 : -ETXTBSY; -} -static inline int deny_write_access(struct file *file) -{ - struct inode *inode = file_inode(file); - return atomic_dec_unless_positive(&inode->i_writecount) ? 0 : -ETXTBSY; -} -static inline void put_write_access(struct inode * inode) -{ - atomic_dec(&inode->i_writecount); -} -static inline void allow_write_access(struct file *file) -{ - if (file) - atomic_inc(&file_inode(file)->i_writecount); -} -static inline bool inode_is_open_for_write(const struct inode *inode) -{ - return atomic_read(&inode->i_writecount) > 0; -} - -#ifdef CONFIG_IMA -static inline void i_readcount_dec(struct inode *inode) -{ - BUG_ON(!atomic_read(&inode->i_readcount)); - atomic_dec(&inode->i_readcount); -} -static inline void i_readcount_inc(struct inode *inode) -{ - atomic_inc(&inode->i_readcount); -} -#else -static inline void i_readcount_dec(struct inode *inode) -{ - return; -} -static inline void i_readcount_inc(struct inode *inode) -{ - return; -} -#endif -extern int do_pipe_flags(int *, int); - -#define __kernel_read_file_id(id) \ - id(UNKNOWN, unknown) \ - id(FIRMWARE, firmware) \ - id(FIRMWARE_PREALLOC_BUFFER, firmware) \ - id(MODULE, kernel-module) \ - id(KEXEC_IMAGE, kexec-image) \ - id(KEXEC_INITRAMFS, kexec-initramfs) \ - id(POLICY, security-policy) \ - id(MAX_ID, ) - -#define __fid_enumify(ENUM, dummy) READING_ ## ENUM, -#define __fid_stringify(dummy, str) #str, - -enum kernel_read_file_id { - __kernel_read_file_id(__fid_enumify) -}; - -static const char * const kernel_read_file_str[] = { - __kernel_read_file_id(__fid_stringify) -}; - -static inline const char *kernel_read_file_id_str(enum kernel_read_file_id id) -{ - if (id < 0 || id >= READING_MAX_ID) - return kernel_read_file_str[READING_UNKNOWN]; - - return kernel_read_file_str[id]; -} - -extern int kernel_read(struct file *, loff_t, char *, unsigned long); -extern int kernel_read_file(struct file *, void **, loff_t *, loff_t, - enum kernel_read_file_id); -extern int kernel_read_file_from_path(char *, void **, loff_t *, loff_t, - enum kernel_read_file_id); -extern int kernel_read_file_from_fd(int, void **, loff_t *, loff_t, - enum kernel_read_file_id); -extern ssize_t kernel_write(struct file *, const char *, size_t, loff_t); -extern ssize_t __kernel_write(struct file *, const char *, size_t, loff_t *); -extern struct file * open_exec(const char *); - -/* fs/dcache.c -- generic fs support functions */ -extern bool is_subdir(struct dentry *, struct dentry *); -extern bool path_is_under(struct path *, struct path *); - -extern char *file_path(struct file *, char *, int); - -#include - -/* needed for stackable file system support */ -extern loff_t default_llseek(struct file *file, loff_t offset, int whence); - -extern loff_t vfs_llseek(struct file *file, loff_t offset, int whence); - -extern int inode_init_always(struct super_block *, struct inode *); -extern void inode_init_once(struct inode *); -extern void address_space_init_once(struct address_space *mapping); -extern struct inode * igrab(struct inode *); -extern ino_t iunique(struct super_block *, ino_t); -extern int inode_needs_sync(struct inode *inode); -extern int generic_delete_inode(struct inode *inode); -static inline int generic_drop_inode(struct inode *inode) -{ - return !inode->i_nlink || inode_unhashed(inode); -} - -extern struct inode *ilookup5_nowait(struct super_block *sb, - unsigned long hashval, int (*test)(struct inode *, void *), - void *data); -extern struct inode *ilookup5(struct super_block *sb, unsigned long hashval, - int (*test)(struct inode *, void *), void *data); -extern struct inode *ilookup(struct super_block *sb, unsigned long ino); - -extern struct inode * iget5_locked(struct super_block *, unsigned long, int (*test)(struct inode *, void *), int (*set)(struct inode *, void *), void *); -extern struct inode * iget_locked(struct super_block *, unsigned long); -extern struct inode *find_inode_nowait(struct super_block *, - unsigned long, - int (*match)(struct inode *, - unsigned long, void *), - void *data); -extern int insert_inode_locked4(struct inode *, unsigned long, int (*test)(struct inode *, void *), void *); -extern int insert_inode_locked(struct inode *); -#ifdef CONFIG_DEBUG_LOCK_ALLOC -extern void lockdep_annotate_inode_mutex_key(struct inode *inode); -#else -static inline void lockdep_annotate_inode_mutex_key(struct inode *inode) { }; -#endif -extern void unlock_new_inode(struct inode *); -extern unsigned int get_next_ino(void); - -extern void __iget(struct inode * inode); -extern void iget_failed(struct inode *); -extern void clear_inode(struct inode *); -extern void __destroy_inode(struct inode *); -extern struct inode *new_inode_pseudo(struct super_block *sb); -extern struct inode *new_inode(struct super_block *sb); -extern void free_inode_nonrcu(struct inode *inode); -extern int should_remove_suid(struct dentry *); -extern int file_remove_privs(struct file *); - -extern void __insert_inode_hash(struct inode *, unsigned long hashval); -static inline void insert_inode_hash(struct inode *inode) -{ - __insert_inode_hash(inode, inode->i_ino); -} - -extern void __remove_inode_hash(struct inode *); -static inline void remove_inode_hash(struct inode *inode) -{ - if (!inode_unhashed(inode) && !hlist_fake(&inode->i_hash)) - __remove_inode_hash(inode); -} - -extern void inode_sb_list_add(struct inode *inode); - -#ifdef CONFIG_BLOCK -extern blk_qc_t submit_bio(struct bio *); -extern int bdev_read_only(struct block_device *); -#endif -extern int set_blocksize(struct block_device *, int); -extern int sb_set_blocksize(struct super_block *, int); -extern int sb_min_blocksize(struct super_block *, int); - -extern int generic_file_mmap(struct file *, struct vm_area_struct *); -extern int generic_file_readonly_mmap(struct file *, struct vm_area_struct *); -extern ssize_t generic_write_checks(struct kiocb *, struct iov_iter *); -extern ssize_t generic_file_read_iter(struct kiocb *, struct iov_iter *); -extern ssize_t __generic_file_write_iter(struct kiocb *, struct iov_iter *); -extern ssize_t generic_file_write_iter(struct kiocb *, struct iov_iter *); -extern ssize_t generic_file_direct_write(struct kiocb *, struct iov_iter *); -extern ssize_t generic_perform_write(struct file *, struct iov_iter *, loff_t); - -ssize_t vfs_iter_read(struct file *file, struct iov_iter *iter, loff_t *ppos); -ssize_t vfs_iter_write(struct file *file, struct iov_iter *iter, loff_t *ppos); - -/* fs/block_dev.c */ -extern ssize_t blkdev_read_iter(struct kiocb *iocb, struct iov_iter *to); -extern ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from); -extern int blkdev_fsync(struct file *filp, loff_t start, loff_t end, - int datasync); -extern void block_sync_page(struct page *page); - -/* fs/splice.c */ -extern ssize_t generic_file_splice_read(struct file *, loff_t *, - struct pipe_inode_info *, size_t, unsigned int); -extern ssize_t iter_file_splice_write(struct pipe_inode_info *, - struct file *, loff_t *, size_t, unsigned int); -extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, - struct file *out, loff_t *, size_t len, unsigned int flags); -extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, - loff_t *opos, size_t len, unsigned int flags); - - -extern void -file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping); -extern loff_t noop_llseek(struct file *file, loff_t offset, int whence); -extern loff_t no_llseek(struct file *file, loff_t offset, int whence); -extern loff_t vfs_setpos(struct file *file, loff_t offset, loff_t maxsize); -extern loff_t generic_file_llseek(struct file *file, loff_t offset, int whence); -extern loff_t generic_file_llseek_size(struct file *file, loff_t offset, - int whence, loff_t maxsize, loff_t eof); -extern loff_t fixed_size_llseek(struct file *file, loff_t offset, - int whence, loff_t size); -extern loff_t no_seek_end_llseek_size(struct file *, loff_t, int, loff_t); -extern loff_t no_seek_end_llseek(struct file *, loff_t, int); -extern int generic_file_open(struct inode * inode, struct file * filp); -extern int nonseekable_open(struct inode * inode, struct file * filp); - -#ifdef CONFIG_BLOCK -typedef void (dio_submit_t)(struct bio *bio, struct inode *inode, - loff_t file_offset); - -enum { - /* need locking between buffered and direct access */ - DIO_LOCKING = 0x01, - - /* filesystem does not support filling holes */ - DIO_SKIP_HOLES = 0x02, - - /* filesystem can handle aio writes beyond i_size */ - DIO_ASYNC_EXTEND = 0x04, - - /* inode/fs/bdev does not need truncate protection */ - DIO_SKIP_DIO_COUNT = 0x08, -}; - -void dio_end_io(struct bio *bio, int error); - -ssize_t __blockdev_direct_IO(struct kiocb *iocb, struct inode *inode, - struct block_device *bdev, struct iov_iter *iter, - get_block_t get_block, - dio_iodone_t end_io, dio_submit_t submit_io, - int flags); - -static inline ssize_t blockdev_direct_IO(struct kiocb *iocb, - struct inode *inode, - struct iov_iter *iter, - get_block_t get_block) -{ - return __blockdev_direct_IO(iocb, inode, inode->i_sb->s_bdev, iter, - get_block, NULL, NULL, DIO_LOCKING | DIO_SKIP_HOLES); -} -#endif - -void inode_dio_wait(struct inode *inode); - -/* - * inode_dio_begin - signal start of a direct I/O requests - * @inode: inode the direct I/O happens on - * - * This is called once we've finished processing a direct I/O request, - * and is used to wake up callers waiting for direct I/O to be quiesced. - */ -static inline void inode_dio_begin(struct inode *inode) -{ - atomic_inc(&inode->i_dio_count); -} - -/* - * inode_dio_end - signal finish of a direct I/O requests - * @inode: inode the direct I/O happens on - * - * This is called once we've finished processing a direct I/O request, - * and is used to wake up callers waiting for direct I/O to be quiesced. - */ -static inline void inode_dio_end(struct inode *inode) -{ - if (atomic_dec_and_test(&inode->i_dio_count)) - wake_up_bit(&inode->i_state, __I_DIO_WAKEUP); -} - -extern void inode_set_flags(struct inode *inode, unsigned int flags, - unsigned int mask); - -extern const struct file_operations generic_ro_fops; - -#define special_file(m) (S_ISCHR(m)||S_ISBLK(m)||S_ISFIFO(m)||S_ISSOCK(m)) - -extern int readlink_copy(char __user *, int, const char *); -extern int page_readlink(struct dentry *, char __user *, int); -extern const char *page_get_link(struct dentry *, struct inode *, - struct delayed_call *); -extern void page_put_link(void *); -extern int __page_symlink(struct inode *inode, const char *symname, int len, - int nofs); -extern int page_symlink(struct inode *inode, const char *symname, int len); -extern const struct inode_operations page_symlink_inode_operations; -extern void kfree_link(void *); -extern int generic_readlink(struct dentry *, char __user *, int); -extern void generic_fillattr(struct inode *, struct kstat *); -int vfs_getattr_nosec(struct path *path, struct kstat *stat); -extern int vfs_getattr(struct path *, struct kstat *); -void __inode_add_bytes(struct inode *inode, loff_t bytes); -void inode_add_bytes(struct inode *inode, loff_t bytes); -void __inode_sub_bytes(struct inode *inode, loff_t bytes); -void inode_sub_bytes(struct inode *inode, loff_t bytes); -loff_t inode_get_bytes(struct inode *inode); -void inode_set_bytes(struct inode *inode, loff_t bytes); -const char *simple_get_link(struct dentry *, struct inode *, - struct delayed_call *); -extern const struct inode_operations simple_symlink_inode_operations; - -extern int iterate_dir(struct file *, struct dir_context *); - -extern int vfs_stat(const char __user *, struct kstat *); -extern int vfs_lstat(const char __user *, struct kstat *); -extern int vfs_fstat(unsigned int, struct kstat *); -extern int vfs_fstatat(int , const char __user *, struct kstat *, int); -extern const char *vfs_get_link(struct dentry *, struct delayed_call *); - -extern int __generic_block_fiemap(struct inode *inode, - struct fiemap_extent_info *fieinfo, - loff_t start, loff_t len, - get_block_t *get_block); -extern int generic_block_fiemap(struct inode *inode, - struct fiemap_extent_info *fieinfo, u64 start, - u64 len, get_block_t *get_block); - -extern void get_filesystem(struct file_system_type *fs); -extern void put_filesystem(struct file_system_type *fs); -extern struct file_system_type *get_fs_type(const char *name); -extern struct super_block *get_super(struct block_device *); -extern struct super_block *get_super_thawed(struct block_device *); -extern struct super_block *get_active_super(struct block_device *bdev); -extern void drop_super(struct super_block *sb); -extern void iterate_supers(void (*)(struct super_block *, void *), void *); -extern void iterate_supers_type(struct file_system_type *, - void (*)(struct super_block *, void *), void *); - -extern int dcache_dir_open(struct inode *, struct file *); -extern int dcache_dir_close(struct inode *, struct file *); -extern loff_t dcache_dir_lseek(struct file *, loff_t, int); -extern int dcache_readdir(struct file *, struct dir_context *); -extern int simple_setattr(struct dentry *, struct iattr *); -extern int simple_getattr(struct vfsmount *, struct dentry *, struct kstat *); -extern int simple_statfs(struct dentry *, struct kstatfs *); -extern int simple_open(struct inode *inode, struct file *file); -extern int simple_link(struct dentry *, struct inode *, struct dentry *); -extern int simple_unlink(struct inode *, struct dentry *); -extern int simple_rmdir(struct inode *, struct dentry *); -extern int simple_rename(struct inode *, struct dentry *, - struct inode *, struct dentry *, unsigned int); -extern int noop_fsync(struct file *, loff_t, loff_t, int); -extern int simple_empty(struct dentry *); -extern int simple_readpage(struct file *file, struct page *page); -extern int simple_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata); -extern int simple_write_end(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata); -extern int always_delete_dentry(const struct dentry *); -extern struct inode *alloc_anon_inode(struct super_block *); -extern int simple_nosetlease(struct file *, long, struct file_lock **, void **); -extern const struct dentry_operations simple_dentry_operations; - -extern struct dentry *simple_lookup(struct inode *, struct dentry *, unsigned int flags); -extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *); -extern const struct file_operations simple_dir_operations; -extern const struct inode_operations simple_dir_inode_operations; -extern void make_empty_dir_inode(struct inode *inode); -extern bool is_empty_dir_inode(struct inode *inode); -struct tree_descr { char *name; const struct file_operations *ops; int mode; }; -struct dentry *d_alloc_name(struct dentry *, const char *); -extern int simple_fill_super(struct super_block *, unsigned long, struct tree_descr *); -extern int simple_pin_fs(struct file_system_type *, struct vfsmount **mount, int *count); -extern void simple_release_fs(struct vfsmount **mount, int *count); - -extern ssize_t simple_read_from_buffer(void __user *to, size_t count, - loff_t *ppos, const void *from, size_t available); -extern ssize_t simple_write_to_buffer(void *to, size_t available, loff_t *ppos, - const void __user *from, size_t count); - -extern int __generic_file_fsync(struct file *, loff_t, loff_t, int); -extern int generic_file_fsync(struct file *, loff_t, loff_t, int); - -extern int generic_check_addressable(unsigned, u64); - -#ifdef CONFIG_MIGRATION -extern int buffer_migrate_page(struct address_space *, - struct page *, struct page *, - enum migrate_mode); -#else -#define buffer_migrate_page NULL -#endif - -extern int setattr_prepare(struct dentry *, struct iattr *); -extern int inode_newsize_ok(const struct inode *, loff_t offset); -extern void setattr_copy(struct inode *inode, const struct iattr *attr); - -extern int file_update_time(struct file *file); - -extern int generic_show_options(struct seq_file *m, struct dentry *root); -extern void save_mount_options(struct super_block *sb, char *options); -extern void replace_mount_options(struct super_block *sb, char *options); - -static inline bool io_is_direct(struct file *filp) -{ - return (filp->f_flags & O_DIRECT) || IS_DAX(filp->f_mapping->host); -} - -static inline int iocb_flags(struct file *file) -{ - int res = 0; - if (file->f_flags & O_APPEND) - res |= IOCB_APPEND; - if (io_is_direct(file)) - res |= IOCB_DIRECT; - if ((file->f_flags & O_DSYNC) || IS_SYNC(file->f_mapping->host)) - res |= IOCB_DSYNC; - if (file->f_flags & __O_SYNC) - res |= IOCB_SYNC; - return res; -} - -static inline ino_t parent_ino(struct dentry *dentry) -{ - ino_t res; - - /* - * Don't strictly need d_lock here? If the parent ino could change - * then surely we'd have a deeper race in the caller? - */ - spin_lock(&dentry->d_lock); - res = dentry->d_parent->d_inode->i_ino; - spin_unlock(&dentry->d_lock); - return res; -} - -/* Transaction based IO helpers */ - -/* - * An argresp is stored in an allocated page and holds the - * size of the argument or response, along with its content - */ -struct simple_transaction_argresp { - ssize_t size; - char data[0]; -}; - -#define SIMPLE_TRANSACTION_LIMIT (PAGE_SIZE - sizeof(struct simple_transaction_argresp)) - -char *simple_transaction_get(struct file *file, const char __user *buf, - size_t size); -ssize_t simple_transaction_read(struct file *file, char __user *buf, - size_t size, loff_t *pos); -int simple_transaction_release(struct inode *inode, struct file *file); - -void simple_transaction_set(struct file *file, size_t n); - -/* - * simple attribute files - * - * These attributes behave similar to those in sysfs: - * - * Writing to an attribute immediately sets a value, an open file can be - * written to multiple times. - * - * Reading from an attribute creates a buffer from the value that might get - * read with multiple read calls. When the attribute has been read - * completely, no further read calls are possible until the file is opened - * again. - * - * All attributes contain a text representation of a numeric value - * that are accessed with the get() and set() functions. - */ -#define DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \ -static int __fops ## _open(struct inode *inode, struct file *file) \ -{ \ - __simple_attr_check_format(__fmt, 0ull); \ - return simple_attr_open(inode, file, __get, __set, __fmt); \ -} \ -static const struct file_operations __fops = { \ - .owner = THIS_MODULE, \ - .open = __fops ## _open, \ - .release = simple_attr_release, \ - .read = simple_attr_read, \ - .write = simple_attr_write, \ - .llseek = generic_file_llseek, \ -} - -static inline __printf(1, 2) -void __simple_attr_check_format(const char *fmt, ...) -{ - /* don't do anything, just let the compiler check the arguments; */ -} - -int simple_attr_open(struct inode *inode, struct file *file, - int (*get)(void *, u64 *), int (*set)(void *, u64), - const char *fmt); -int simple_attr_release(struct inode *inode, struct file *file); -ssize_t simple_attr_read(struct file *file, char __user *buf, - size_t len, loff_t *ppos); -ssize_t simple_attr_write(struct file *file, const char __user *buf, - size_t len, loff_t *ppos); - -struct ctl_table; -int proc_nr_files(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); -int proc_nr_dentry(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); -int proc_nr_inodes(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); -int __init get_filesystem_list(char *buf); - -#define __FMODE_EXEC ((__force int) FMODE_EXEC) -#define __FMODE_NONOTIFY ((__force int) FMODE_NONOTIFY) - -#define ACC_MODE(x) ("\004\002\006\006"[(x)&O_ACCMODE]) -#define OPEN_FMODE(flag) ((__force fmode_t)(((flag + 1) & O_ACCMODE) | \ - (flag & __FMODE_NONOTIFY))) - -static inline bool is_sxid(umode_t mode) -{ - return (mode & S_ISUID) || ((mode & S_ISGID) && (mode & S_IXGRP)); -} - -static inline int check_sticky(struct inode *dir, struct inode *inode) -{ - if (!(dir->i_mode & S_ISVTX)) - return 0; - - return __check_sticky(dir, inode); -} - -static inline void inode_has_no_xattr(struct inode *inode) -{ - if (!is_sxid(inode->i_mode) && (inode->i_sb->s_flags & MS_NOSEC)) - inode->i_flags |= S_NOSEC; -} - -static inline bool is_root_inode(struct inode *inode) -{ - return inode == inode->i_sb->s_root->d_inode; -} - -static inline bool dir_emit(struct dir_context *ctx, - const char *name, int namelen, - u64 ino, unsigned type) -{ - return ctx->actor(ctx, name, namelen, ctx->pos, ino, type) == 0; -} -static inline bool dir_emit_dot(struct file *file, struct dir_context *ctx) -{ - return ctx->actor(ctx, ".", 1, ctx->pos, - file->f_path.dentry->d_inode->i_ino, DT_DIR) == 0; -} -static inline bool dir_emit_dotdot(struct file *file, struct dir_context *ctx) -{ - return ctx->actor(ctx, "..", 2, ctx->pos, - parent_ino(file->f_path.dentry), DT_DIR) == 0; -} -static inline bool dir_emit_dots(struct file *file, struct dir_context *ctx) -{ - if (ctx->pos == 0) { - if (!dir_emit_dot(file, ctx)) - return false; - ctx->pos = 1; - } - if (ctx->pos == 1) { - if (!dir_emit_dotdot(file, ctx)) - return false; - ctx->pos = 2; - } - return true; -} -static inline bool dir_relax(struct inode *inode) -{ - inode_unlock(inode); - inode_lock(inode); - return !IS_DEADDIR(inode); -} - -static inline bool dir_relax_shared(struct inode *inode) -{ - inode_unlock_shared(inode); - inode_lock_shared(inode); - return !IS_DEADDIR(inode); -} - -extern bool path_noexec(const struct path *path); -extern void inode_nohighmem(struct inode *inode); - -#endif /* _LINUX_FS_H */ diff --git a/src/linux/include/linux/fs_pin.h b/src/linux/include/linux/fs_pin.h deleted file mode 100644 index 3886b3b..0000000 --- a/src/linux/include/linux/fs_pin.h +++ /dev/null @@ -1,24 +0,0 @@ -#include - -struct fs_pin { - wait_queue_head_t wait; - int done; - struct hlist_node s_list; - struct hlist_node m_list; - void (*kill)(struct fs_pin *); -}; - -struct vfsmount; - -static inline void init_fs_pin(struct fs_pin *p, void (*kill)(struct fs_pin *)) -{ - init_waitqueue_head(&p->wait); - INIT_HLIST_NODE(&p->s_list); - INIT_HLIST_NODE(&p->m_list); - p->kill = kill; -} - -void pin_remove(struct fs_pin *); -void pin_insert_group(struct fs_pin *, struct vfsmount *, struct hlist_head *); -void pin_insert(struct fs_pin *, struct vfsmount *); -void pin_kill(struct fs_pin *); diff --git a/src/linux/include/linux/fs_stack.h b/src/linux/include/linux/fs_stack.h deleted file mode 100644 index da317c7..0000000 --- a/src/linux/include/linux/fs_stack.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _LINUX_FS_STACK_H -#define _LINUX_FS_STACK_H - -/* This file defines generic functions used primarily by stackable - * filesystems; none of these functions require i_mutex to be held. - */ - -#include - -/* externs for fs/stack.c */ -extern void fsstack_copy_attr_all(struct inode *dest, const struct inode *src); -extern void fsstack_copy_inode_size(struct inode *dst, struct inode *src); - -/* inlines */ -static inline void fsstack_copy_attr_atime(struct inode *dest, - const struct inode *src) -{ - dest->i_atime = src->i_atime; -} - -static inline void fsstack_copy_attr_times(struct inode *dest, - const struct inode *src) -{ - dest->i_atime = src->i_atime; - dest->i_mtime = src->i_mtime; - dest->i_ctime = src->i_ctime; -} - -#endif /* _LINUX_FS_STACK_H */ diff --git a/src/linux/include/linux/fs_struct.h b/src/linux/include/linux/fs_struct.h deleted file mode 100644 index 0efc3e6..0000000 --- a/src/linux/include/linux/fs_struct.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef _LINUX_FS_STRUCT_H -#define _LINUX_FS_STRUCT_H - -#include -#include -#include - -struct fs_struct { - int users; - spinlock_t lock; - seqcount_t seq; - int umask; - int in_exec; - struct path root, pwd; -}; - -extern struct kmem_cache *fs_cachep; - -extern void exit_fs(struct task_struct *); -extern void set_fs_root(struct fs_struct *, const struct path *); -extern void set_fs_pwd(struct fs_struct *, const struct path *); -extern struct fs_struct *copy_fs_struct(struct fs_struct *); -extern void free_fs_struct(struct fs_struct *); -extern int unshare_fs_struct(void); - -static inline void get_fs_root(struct fs_struct *fs, struct path *root) -{ - spin_lock(&fs->lock); - *root = fs->root; - path_get(root); - spin_unlock(&fs->lock); -} - -static inline void get_fs_pwd(struct fs_struct *fs, struct path *pwd) -{ - spin_lock(&fs->lock); - *pwd = fs->pwd; - path_get(pwd); - spin_unlock(&fs->lock); -} - -extern bool current_chrooted(void); - -#endif /* _LINUX_FS_STRUCT_H */ diff --git a/src/linux/include/linux/fscache-cache.h b/src/linux/include/linux/fscache-cache.h deleted file mode 100644 index 13ba552..0000000 --- a/src/linux/include/linux/fscache-cache.h +++ /dev/null @@ -1,553 +0,0 @@ -/* General filesystem caching backing cache interface - * - * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * NOTE!!! See: - * - * Documentation/filesystems/caching/backend-api.txt - * - * for a description of the cache backend interface declared here. - */ - -#ifndef _LINUX_FSCACHE_CACHE_H -#define _LINUX_FSCACHE_CACHE_H - -#include -#include -#include - -#define NR_MAXCACHES BITS_PER_LONG - -struct fscache_cache; -struct fscache_cache_ops; -struct fscache_object; -struct fscache_operation; - -/* - * cache tag definition - */ -struct fscache_cache_tag { - struct list_head link; - struct fscache_cache *cache; /* cache referred to by this tag */ - unsigned long flags; -#define FSCACHE_TAG_RESERVED 0 /* T if tag is reserved for a cache */ - atomic_t usage; - char name[0]; /* tag name */ -}; - -/* - * cache definition - */ -struct fscache_cache { - const struct fscache_cache_ops *ops; - struct fscache_cache_tag *tag; /* tag representing this cache */ - struct kobject *kobj; /* system representation of this cache */ - struct list_head link; /* link in list of caches */ - size_t max_index_size; /* maximum size of index data */ - char identifier[36]; /* cache label */ - - /* node management */ - struct work_struct op_gc; /* operation garbage collector */ - struct list_head object_list; /* list of data/index objects */ - struct list_head op_gc_list; /* list of ops to be deleted */ - spinlock_t object_list_lock; - spinlock_t op_gc_list_lock; - atomic_t object_count; /* no. of live objects in this cache */ - struct fscache_object *fsdef; /* object for the fsdef index */ - unsigned long flags; -#define FSCACHE_IOERROR 0 /* cache stopped on I/O error */ -#define FSCACHE_CACHE_WITHDRAWN 1 /* cache has been withdrawn */ -}; - -extern wait_queue_head_t fscache_cache_cleared_wq; - -/* - * operation to be applied to a cache object - * - retrieval initiation operations are done in the context of the process - * that issued them, and not in an async thread pool - */ -typedef void (*fscache_operation_release_t)(struct fscache_operation *op); -typedef void (*fscache_operation_processor_t)(struct fscache_operation *op); -typedef void (*fscache_operation_cancel_t)(struct fscache_operation *op); - -enum fscache_operation_state { - FSCACHE_OP_ST_BLANK, /* Op is not yet submitted */ - FSCACHE_OP_ST_INITIALISED, /* Op is initialised */ - FSCACHE_OP_ST_PENDING, /* Op is blocked from running */ - FSCACHE_OP_ST_IN_PROGRESS, /* Op is in progress */ - FSCACHE_OP_ST_COMPLETE, /* Op is complete */ - FSCACHE_OP_ST_CANCELLED, /* Op has been cancelled */ - FSCACHE_OP_ST_DEAD /* Op is now dead */ -}; - -struct fscache_operation { - struct work_struct work; /* record for async ops */ - struct list_head pend_link; /* link in object->pending_ops */ - struct fscache_object *object; /* object to be operated upon */ - - unsigned long flags; -#define FSCACHE_OP_TYPE 0x000f /* operation type */ -#define FSCACHE_OP_ASYNC 0x0001 /* - async op, processor may sleep for disk */ -#define FSCACHE_OP_MYTHREAD 0x0002 /* - processing is done be issuing thread, not pool */ -#define FSCACHE_OP_WAITING 4 /* cleared when op is woken */ -#define FSCACHE_OP_EXCLUSIVE 5 /* exclusive op, other ops must wait */ -#define FSCACHE_OP_DEC_READ_CNT 6 /* decrement object->n_reads on destruction */ -#define FSCACHE_OP_UNUSE_COOKIE 7 /* call fscache_unuse_cookie() on completion */ -#define FSCACHE_OP_KEEP_FLAGS 0x00f0 /* flags to keep when repurposing an op */ - - enum fscache_operation_state state; - atomic_t usage; - unsigned debug_id; /* debugging ID */ - - /* operation processor callback - * - can be NULL if FSCACHE_OP_WAITING is going to be used to perform - * the op in a non-pool thread */ - fscache_operation_processor_t processor; - - /* Operation cancellation cleanup (optional) */ - fscache_operation_cancel_t cancel; - - /* operation releaser */ - fscache_operation_release_t release; -}; - -extern atomic_t fscache_op_debug_id; -extern void fscache_op_work_func(struct work_struct *work); - -extern void fscache_enqueue_operation(struct fscache_operation *); -extern void fscache_op_complete(struct fscache_operation *, bool); -extern void fscache_put_operation(struct fscache_operation *); -extern void fscache_operation_init(struct fscache_operation *, - fscache_operation_processor_t, - fscache_operation_cancel_t, - fscache_operation_release_t); - -/* - * data read operation - */ -struct fscache_retrieval { - struct fscache_operation op; - struct fscache_cookie *cookie; /* The netfs cookie */ - struct address_space *mapping; /* netfs pages */ - fscache_rw_complete_t end_io_func; /* function to call on I/O completion */ - void *context; /* netfs read context (pinned) */ - struct list_head to_do; /* list of things to be done by the backend */ - unsigned long start_time; /* time at which retrieval started */ - atomic_t n_pages; /* number of pages to be retrieved */ -}; - -typedef int (*fscache_page_retrieval_func_t)(struct fscache_retrieval *op, - struct page *page, - gfp_t gfp); - -typedef int (*fscache_pages_retrieval_func_t)(struct fscache_retrieval *op, - struct list_head *pages, - unsigned *nr_pages, - gfp_t gfp); - -/** - * fscache_get_retrieval - Get an extra reference on a retrieval operation - * @op: The retrieval operation to get a reference on - * - * Get an extra reference on a retrieval operation. - */ -static inline -struct fscache_retrieval *fscache_get_retrieval(struct fscache_retrieval *op) -{ - atomic_inc(&op->op.usage); - return op; -} - -/** - * fscache_enqueue_retrieval - Enqueue a retrieval operation for processing - * @op: The retrieval operation affected - * - * Enqueue a retrieval operation for processing by the FS-Cache thread pool. - */ -static inline void fscache_enqueue_retrieval(struct fscache_retrieval *op) -{ - fscache_enqueue_operation(&op->op); -} - -/** - * fscache_retrieval_complete - Record (partial) completion of a retrieval - * @op: The retrieval operation affected - * @n_pages: The number of pages to account for - */ -static inline void fscache_retrieval_complete(struct fscache_retrieval *op, - int n_pages) -{ - atomic_sub(n_pages, &op->n_pages); - if (atomic_read(&op->n_pages) <= 0) - fscache_op_complete(&op->op, true); -} - -/** - * fscache_put_retrieval - Drop a reference to a retrieval operation - * @op: The retrieval operation affected - * - * Drop a reference to a retrieval operation. - */ -static inline void fscache_put_retrieval(struct fscache_retrieval *op) -{ - fscache_put_operation(&op->op); -} - -/* - * cached page storage work item - * - used to do three things: - * - batch writes to the cache - * - do cache writes asynchronously - * - defer writes until cache object lookup completion - */ -struct fscache_storage { - struct fscache_operation op; - pgoff_t store_limit; /* don't write more than this */ -}; - -/* - * cache operations - */ -struct fscache_cache_ops { - /* name of cache provider */ - const char *name; - - /* allocate an object record for a cookie */ - struct fscache_object *(*alloc_object)(struct fscache_cache *cache, - struct fscache_cookie *cookie); - - /* look up the object for a cookie - * - return -ETIMEDOUT to be requeued - */ - int (*lookup_object)(struct fscache_object *object); - - /* finished looking up */ - void (*lookup_complete)(struct fscache_object *object); - - /* increment the usage count on this object (may fail if unmounting) */ - struct fscache_object *(*grab_object)(struct fscache_object *object); - - /* pin an object in the cache */ - int (*pin_object)(struct fscache_object *object); - - /* unpin an object in the cache */ - void (*unpin_object)(struct fscache_object *object); - - /* check the consistency between the backing cache and the FS-Cache - * cookie */ - int (*check_consistency)(struct fscache_operation *op); - - /* store the updated auxiliary data on an object */ - void (*update_object)(struct fscache_object *object); - - /* Invalidate an object */ - void (*invalidate_object)(struct fscache_operation *op); - - /* discard the resources pinned by an object and effect retirement if - * necessary */ - void (*drop_object)(struct fscache_object *object); - - /* dispose of a reference to an object */ - void (*put_object)(struct fscache_object *object); - - /* sync a cache */ - void (*sync_cache)(struct fscache_cache *cache); - - /* notification that the attributes of a non-index object (such as - * i_size) have changed */ - int (*attr_changed)(struct fscache_object *object); - - /* reserve space for an object's data and associated metadata */ - int (*reserve_space)(struct fscache_object *object, loff_t i_size); - - /* request a backing block for a page be read or allocated in the - * cache */ - fscache_page_retrieval_func_t read_or_alloc_page; - - /* request backing blocks for a list of pages be read or allocated in - * the cache */ - fscache_pages_retrieval_func_t read_or_alloc_pages; - - /* request a backing block for a page be allocated in the cache so that - * it can be written directly */ - fscache_page_retrieval_func_t allocate_page; - - /* request backing blocks for pages be allocated in the cache so that - * they can be written directly */ - fscache_pages_retrieval_func_t allocate_pages; - - /* write a page to its backing block in the cache */ - int (*write_page)(struct fscache_storage *op, struct page *page); - - /* detach backing block from a page (optional) - * - must release the cookie lock before returning - * - may sleep - */ - void (*uncache_page)(struct fscache_object *object, - struct page *page); - - /* dissociate a cache from all the pages it was backing */ - void (*dissociate_pages)(struct fscache_cache *cache); -}; - -extern struct fscache_cookie fscache_fsdef_index; - -/* - * Event list for fscache_object::{event_mask,events} - */ -enum { - FSCACHE_OBJECT_EV_NEW_CHILD, /* T if object has a new child */ - FSCACHE_OBJECT_EV_PARENT_READY, /* T if object's parent is ready */ - FSCACHE_OBJECT_EV_UPDATE, /* T if object should be updated */ - FSCACHE_OBJECT_EV_INVALIDATE, /* T if cache requested object invalidation */ - FSCACHE_OBJECT_EV_CLEARED, /* T if accessors all gone */ - FSCACHE_OBJECT_EV_ERROR, /* T if fatal error occurred during processing */ - FSCACHE_OBJECT_EV_KILL, /* T if netfs relinquished or cache withdrew object */ - NR_FSCACHE_OBJECT_EVENTS -}; - -#define FSCACHE_OBJECT_EVENTS_MASK ((1UL << NR_FSCACHE_OBJECT_EVENTS) - 1) - -/* - * States for object state machine. - */ -struct fscache_transition { - unsigned long events; - const struct fscache_state *transit_to; -}; - -struct fscache_state { - char name[24]; - char short_name[8]; - const struct fscache_state *(*work)(struct fscache_object *object, - int event); - const struct fscache_transition transitions[]; -}; - -/* - * on-disk cache file or index handle - */ -struct fscache_object { - const struct fscache_state *state; /* Object state machine state */ - const struct fscache_transition *oob_table; /* OOB state transition table */ - int debug_id; /* debugging ID */ - int n_children; /* number of child objects */ - int n_ops; /* number of extant ops on object */ - int n_obj_ops; /* number of object ops outstanding on object */ - int n_in_progress; /* number of ops in progress */ - int n_exclusive; /* number of exclusive ops queued or in progress */ - atomic_t n_reads; /* number of read ops in progress */ - spinlock_t lock; /* state and operations lock */ - - unsigned long lookup_jif; /* time at which lookup started */ - unsigned long oob_event_mask; /* OOB events this object is interested in */ - unsigned long event_mask; /* events this object is interested in */ - unsigned long events; /* events to be processed by this object - * (order is important - using fls) */ - - unsigned long flags; -#define FSCACHE_OBJECT_LOCK 0 /* T if object is busy being processed */ -#define FSCACHE_OBJECT_PENDING_WRITE 1 /* T if object has pending write */ -#define FSCACHE_OBJECT_WAITING 2 /* T if object is waiting on its parent */ -#define FSCACHE_OBJECT_IS_LIVE 3 /* T if object is not withdrawn or relinquished */ -#define FSCACHE_OBJECT_IS_LOOKED_UP 4 /* T if object has been looked up */ -#define FSCACHE_OBJECT_IS_AVAILABLE 5 /* T if object has become active */ -#define FSCACHE_OBJECT_RETIRED 6 /* T if object was retired on relinquishment */ -#define FSCACHE_OBJECT_KILLED_BY_CACHE 7 /* T if object was killed by the cache */ - - struct list_head cache_link; /* link in cache->object_list */ - struct hlist_node cookie_link; /* link in cookie->backing_objects */ - struct fscache_cache *cache; /* cache that supplied this object */ - struct fscache_cookie *cookie; /* netfs's file/index object */ - struct fscache_object *parent; /* parent object */ - struct work_struct work; /* attention scheduling record */ - struct list_head dependents; /* FIFO of dependent objects */ - struct list_head dep_link; /* link in parent's dependents list */ - struct list_head pending_ops; /* unstarted operations on this object */ -#ifdef CONFIG_FSCACHE_OBJECT_LIST - struct rb_node objlist_link; /* link in global object list */ -#endif - pgoff_t store_limit; /* current storage limit */ - loff_t store_limit_l; /* current storage limit */ -}; - -extern void fscache_object_init(struct fscache_object *, struct fscache_cookie *, - struct fscache_cache *); -extern void fscache_object_destroy(struct fscache_object *); - -extern void fscache_object_lookup_negative(struct fscache_object *object); -extern void fscache_obtained_object(struct fscache_object *object); - -static inline bool fscache_object_is_live(struct fscache_object *object) -{ - return test_bit(FSCACHE_OBJECT_IS_LIVE, &object->flags); -} - -static inline bool fscache_object_is_dying(struct fscache_object *object) -{ - return !fscache_object_is_live(object); -} - -static inline bool fscache_object_is_available(struct fscache_object *object) -{ - return test_bit(FSCACHE_OBJECT_IS_AVAILABLE, &object->flags); -} - -static inline bool fscache_cache_is_broken(struct fscache_object *object) -{ - return test_bit(FSCACHE_IOERROR, &object->cache->flags); -} - -static inline bool fscache_object_is_active(struct fscache_object *object) -{ - return fscache_object_is_available(object) && - fscache_object_is_live(object) && - !fscache_cache_is_broken(object); -} - -/** - * fscache_object_destroyed - Note destruction of an object in a cache - * @cache: The cache from which the object came - * - * Note the destruction and deallocation of an object record in a cache. - */ -static inline void fscache_object_destroyed(struct fscache_cache *cache) -{ - if (atomic_dec_and_test(&cache->object_count)) - wake_up_all(&fscache_cache_cleared_wq); -} - -/** - * fscache_object_lookup_error - Note an object encountered an error - * @object: The object on which the error was encountered - * - * Note that an object encountered a fatal error (usually an I/O error) and - * that it should be withdrawn as soon as possible. - */ -static inline void fscache_object_lookup_error(struct fscache_object *object) -{ - set_bit(FSCACHE_OBJECT_EV_ERROR, &object->events); -} - -/** - * fscache_set_store_limit - Set the maximum size to be stored in an object - * @object: The object to set the maximum on - * @i_size: The limit to set in bytes - * - * Set the maximum size an object is permitted to reach, implying the highest - * byte that may be written. Intended to be called by the attr_changed() op. - * - * See Documentation/filesystems/caching/backend-api.txt for a complete - * description. - */ -static inline -void fscache_set_store_limit(struct fscache_object *object, loff_t i_size) -{ - object->store_limit_l = i_size; - object->store_limit = i_size >> PAGE_SHIFT; - if (i_size & ~PAGE_MASK) - object->store_limit++; -} - -/** - * fscache_end_io - End a retrieval operation on a page - * @op: The FS-Cache operation covering the retrieval - * @page: The page that was to be fetched - * @error: The error code (0 if successful) - * - * Note the end of an operation to retrieve a page, as covered by a particular - * operation record. - */ -static inline void fscache_end_io(struct fscache_retrieval *op, - struct page *page, int error) -{ - op->end_io_func(page, op->context, error); -} - -static inline void __fscache_use_cookie(struct fscache_cookie *cookie) -{ - atomic_inc(&cookie->n_active); -} - -/** - * fscache_use_cookie - Request usage of cookie attached to an object - * @object: Object description - * - * Request usage of the cookie attached to an object. NULL is returned if the - * relinquishment had reduced the cookie usage count to 0. - */ -static inline bool fscache_use_cookie(struct fscache_object *object) -{ - struct fscache_cookie *cookie = object->cookie; - return atomic_inc_not_zero(&cookie->n_active) != 0; -} - -static inline bool __fscache_unuse_cookie(struct fscache_cookie *cookie) -{ - return atomic_dec_and_test(&cookie->n_active); -} - -static inline void __fscache_wake_unused_cookie(struct fscache_cookie *cookie) -{ - wake_up_atomic_t(&cookie->n_active); -} - -/** - * fscache_unuse_cookie - Cease usage of cookie attached to an object - * @object: Object description - * - * Cease usage of the cookie attached to an object. When the users count - * reaches zero then the cookie relinquishment will be permitted to proceed. - */ -static inline void fscache_unuse_cookie(struct fscache_object *object) -{ - struct fscache_cookie *cookie = object->cookie; - if (__fscache_unuse_cookie(cookie)) - __fscache_wake_unused_cookie(cookie); -} - -/* - * out-of-line cache backend functions - */ -extern __printf(3, 4) -void fscache_init_cache(struct fscache_cache *cache, - const struct fscache_cache_ops *ops, - const char *idfmt, ...); - -extern int fscache_add_cache(struct fscache_cache *cache, - struct fscache_object *fsdef, - const char *tagname); -extern void fscache_withdraw_cache(struct fscache_cache *cache); - -extern void fscache_io_error(struct fscache_cache *cache); - -extern void fscache_mark_page_cached(struct fscache_retrieval *op, - struct page *page); - -extern void fscache_mark_pages_cached(struct fscache_retrieval *op, - struct pagevec *pagevec); - -extern bool fscache_object_sleep_till_congested(signed long *timeoutp); - -extern enum fscache_checkaux fscache_check_aux(struct fscache_object *object, - const void *data, - uint16_t datalen); - -extern void fscache_object_retrying_stale(struct fscache_object *object); - -enum fscache_why_object_killed { - FSCACHE_OBJECT_IS_STALE, - FSCACHE_OBJECT_NO_SPACE, - FSCACHE_OBJECT_WAS_RETIRED, - FSCACHE_OBJECT_WAS_CULLED, -}; -extern void fscache_object_mark_killed(struct fscache_object *object, - enum fscache_why_object_killed why); - -#endif /* _LINUX_FSCACHE_CACHE_H */ diff --git a/src/linux/include/linux/fscache.h b/src/linux/include/linux/fscache.h deleted file mode 100644 index 115bb81..0000000 --- a/src/linux/include/linux/fscache.h +++ /dev/null @@ -1,832 +0,0 @@ -/* General filesystem caching interface - * - * Copyright (C) 2004-2007 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * NOTE!!! See: - * - * Documentation/filesystems/caching/netfs-api.txt - * - * for a description of the network filesystem interface declared here. - */ - -#ifndef _LINUX_FSCACHE_H -#define _LINUX_FSCACHE_H - -#include -#include -#include -#include - -#if defined(CONFIG_FSCACHE) || defined(CONFIG_FSCACHE_MODULE) -#define fscache_available() (1) -#define fscache_cookie_valid(cookie) (cookie) -#else -#define fscache_available() (0) -#define fscache_cookie_valid(cookie) (0) -#endif - - -/* - * overload PG_private_2 to give us PG_fscache - this is used to indicate that - * a page is currently backed by a local disk cache - */ -#define PageFsCache(page) PagePrivate2((page)) -#define SetPageFsCache(page) SetPagePrivate2((page)) -#define ClearPageFsCache(page) ClearPagePrivate2((page)) -#define TestSetPageFsCache(page) TestSetPagePrivate2((page)) -#define TestClearPageFsCache(page) TestClearPagePrivate2((page)) - -/* pattern used to fill dead space in an index entry */ -#define FSCACHE_INDEX_DEADFILL_PATTERN 0x79 - -struct pagevec; -struct fscache_cache_tag; -struct fscache_cookie; -struct fscache_netfs; - -typedef void (*fscache_rw_complete_t)(struct page *page, - void *context, - int error); - -/* result of index entry consultation */ -enum fscache_checkaux { - FSCACHE_CHECKAUX_OKAY, /* entry okay as is */ - FSCACHE_CHECKAUX_NEEDS_UPDATE, /* entry requires update */ - FSCACHE_CHECKAUX_OBSOLETE, /* entry requires deletion */ -}; - -/* - * fscache cookie definition - */ -struct fscache_cookie_def { - /* name of cookie type */ - char name[16]; - - /* cookie type */ - uint8_t type; -#define FSCACHE_COOKIE_TYPE_INDEX 0 -#define FSCACHE_COOKIE_TYPE_DATAFILE 1 - - /* select the cache into which to insert an entry in this index - * - optional - * - should return a cache identifier or NULL to cause the cache to be - * inherited from the parent if possible or the first cache picked - * for a non-index file if not - */ - struct fscache_cache_tag *(*select_cache)( - const void *parent_netfs_data, - const void *cookie_netfs_data); - - /* get an index key - * - should store the key data in the buffer - * - should return the amount of data stored - * - not permitted to return an error - * - the netfs data from the cookie being used as the source is - * presented - */ - uint16_t (*get_key)(const void *cookie_netfs_data, - void *buffer, - uint16_t bufmax); - - /* get certain file attributes from the netfs data - * - this function can be absent for an index - * - not permitted to return an error - * - the netfs data from the cookie being used as the source is - * presented - */ - void (*get_attr)(const void *cookie_netfs_data, uint64_t *size); - - /* get the auxiliary data from netfs data - * - this function can be absent if the index carries no state data - * - should store the auxiliary data in the buffer - * - should return the amount of amount stored - * - not permitted to return an error - * - the netfs data from the cookie being used as the source is - * presented - */ - uint16_t (*get_aux)(const void *cookie_netfs_data, - void *buffer, - uint16_t bufmax); - - /* consult the netfs about the state of an object - * - this function can be absent if the index carries no state data - * - the netfs data from the cookie being used as the target is - * presented, as is the auxiliary data - */ - enum fscache_checkaux (*check_aux)(void *cookie_netfs_data, - const void *data, - uint16_t datalen); - - /* get an extra reference on a read context - * - this function can be absent if the completion function doesn't - * require a context - */ - void (*get_context)(void *cookie_netfs_data, void *context); - - /* release an extra reference on a read context - * - this function can be absent if the completion function doesn't - * require a context - */ - void (*put_context)(void *cookie_netfs_data, void *context); - - /* indicate page that now have cache metadata retained - * - this function should mark the specified page as now being cached - * - the page will have been marked with PG_fscache before this is - * called, so this is optional - */ - void (*mark_page_cached)(void *cookie_netfs_data, - struct address_space *mapping, - struct page *page); - - /* indicate the cookie is no longer cached - * - this function is called when the backing store currently caching - * a cookie is removed - * - the netfs should use this to clean up any markers indicating - * cached pages - * - this is mandatory for any object that may have data - */ - void (*now_uncached)(void *cookie_netfs_data); -}; - -/* - * fscache cached network filesystem type - * - name, version and ops must be filled in before registration - * - all other fields will be set during registration - */ -struct fscache_netfs { - uint32_t version; /* indexing version */ - const char *name; /* filesystem name */ - struct fscache_cookie *primary_index; - struct list_head link; /* internal link */ -}; - -/* - * data file or index object cookie - * - a file will only appear in one cache - * - a request to cache a file may or may not be honoured, subject to - * constraints such as disk space - * - indices are created on disk just-in-time - */ -struct fscache_cookie { - atomic_t usage; /* number of users of this cookie */ - atomic_t n_children; /* number of children of this cookie */ - atomic_t n_active; /* number of active users of netfs ptrs */ - spinlock_t lock; - spinlock_t stores_lock; /* lock on page store tree */ - struct hlist_head backing_objects; /* object(s) backing this file/index */ - const struct fscache_cookie_def *def; /* definition */ - struct fscache_cookie *parent; /* parent of this entry */ - void *netfs_data; /* back pointer to netfs */ - struct radix_tree_root stores; /* pages to be stored on this cookie */ -#define FSCACHE_COOKIE_PENDING_TAG 0 /* pages tag: pending write to cache */ -#define FSCACHE_COOKIE_STORING_TAG 1 /* pages tag: writing to cache */ - - unsigned long flags; -#define FSCACHE_COOKIE_LOOKING_UP 0 /* T if non-index cookie being looked up still */ -#define FSCACHE_COOKIE_NO_DATA_YET 1 /* T if new object with no cached data yet */ -#define FSCACHE_COOKIE_UNAVAILABLE 2 /* T if cookie is unavailable (error, etc) */ -#define FSCACHE_COOKIE_INVALIDATING 3 /* T if cookie is being invalidated */ -#define FSCACHE_COOKIE_RELINQUISHED 4 /* T if cookie has been relinquished */ -#define FSCACHE_COOKIE_ENABLED 5 /* T if cookie is enabled */ -#define FSCACHE_COOKIE_ENABLEMENT_LOCK 6 /* T if cookie is being en/disabled */ -}; - -static inline bool fscache_cookie_enabled(struct fscache_cookie *cookie) -{ - return test_bit(FSCACHE_COOKIE_ENABLED, &cookie->flags); -} - -/* - * slow-path functions for when there is actually caching available, and the - * netfs does actually have a valid token - * - these are not to be called directly - * - these are undefined symbols when FS-Cache is not configured and the - * optimiser takes care of not using them - */ -extern int __fscache_register_netfs(struct fscache_netfs *); -extern void __fscache_unregister_netfs(struct fscache_netfs *); -extern struct fscache_cache_tag *__fscache_lookup_cache_tag(const char *); -extern void __fscache_release_cache_tag(struct fscache_cache_tag *); - -extern struct fscache_cookie *__fscache_acquire_cookie( - struct fscache_cookie *, - const struct fscache_cookie_def *, - void *, bool); -extern void __fscache_relinquish_cookie(struct fscache_cookie *, bool); -extern int __fscache_check_consistency(struct fscache_cookie *); -extern void __fscache_update_cookie(struct fscache_cookie *); -extern int __fscache_attr_changed(struct fscache_cookie *); -extern void __fscache_invalidate(struct fscache_cookie *); -extern void __fscache_wait_on_invalidate(struct fscache_cookie *); -extern int __fscache_read_or_alloc_page(struct fscache_cookie *, - struct page *, - fscache_rw_complete_t, - void *, - gfp_t); -extern int __fscache_read_or_alloc_pages(struct fscache_cookie *, - struct address_space *, - struct list_head *, - unsigned *, - fscache_rw_complete_t, - void *, - gfp_t); -extern int __fscache_alloc_page(struct fscache_cookie *, struct page *, gfp_t); -extern int __fscache_write_page(struct fscache_cookie *, struct page *, gfp_t); -extern void __fscache_uncache_page(struct fscache_cookie *, struct page *); -extern bool __fscache_check_page_write(struct fscache_cookie *, struct page *); -extern void __fscache_wait_on_page_write(struct fscache_cookie *, struct page *); -extern bool __fscache_maybe_release_page(struct fscache_cookie *, struct page *, - gfp_t); -extern void __fscache_uncache_all_inode_pages(struct fscache_cookie *, - struct inode *); -extern void __fscache_readpages_cancel(struct fscache_cookie *cookie, - struct list_head *pages); -extern void __fscache_disable_cookie(struct fscache_cookie *, bool); -extern void __fscache_enable_cookie(struct fscache_cookie *, - bool (*)(void *), void *); - -/** - * fscache_register_netfs - Register a filesystem as desiring caching services - * @netfs: The description of the filesystem - * - * Register a filesystem as desiring caching services if they're available. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -int fscache_register_netfs(struct fscache_netfs *netfs) -{ - if (fscache_available()) - return __fscache_register_netfs(netfs); - else - return 0; -} - -/** - * fscache_unregister_netfs - Indicate that a filesystem no longer desires - * caching services - * @netfs: The description of the filesystem - * - * Indicate that a filesystem no longer desires caching services for the - * moment. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -void fscache_unregister_netfs(struct fscache_netfs *netfs) -{ - if (fscache_available()) - __fscache_unregister_netfs(netfs); -} - -/** - * fscache_lookup_cache_tag - Look up a cache tag - * @name: The name of the tag to search for - * - * Acquire a specific cache referral tag that can be used to select a specific - * cache in which to cache an index. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -struct fscache_cache_tag *fscache_lookup_cache_tag(const char *name) -{ - if (fscache_available()) - return __fscache_lookup_cache_tag(name); - else - return NULL; -} - -/** - * fscache_release_cache_tag - Release a cache tag - * @tag: The tag to release - * - * Release a reference to a cache referral tag previously looked up. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -void fscache_release_cache_tag(struct fscache_cache_tag *tag) -{ - if (fscache_available()) - __fscache_release_cache_tag(tag); -} - -/** - * fscache_acquire_cookie - Acquire a cookie to represent a cache object - * @parent: The cookie that's to be the parent of this one - * @def: A description of the cache object, including callback operations - * @netfs_data: An arbitrary piece of data to be kept in the cookie to - * represent the cache object to the netfs - * @enable: Whether or not to enable a data cookie immediately - * - * This function is used to inform FS-Cache about part of an index hierarchy - * that can be used to locate files. This is done by requesting a cookie for - * each index in the path to the file. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -struct fscache_cookie *fscache_acquire_cookie( - struct fscache_cookie *parent, - const struct fscache_cookie_def *def, - void *netfs_data, - bool enable) -{ - if (fscache_cookie_valid(parent) && fscache_cookie_enabled(parent)) - return __fscache_acquire_cookie(parent, def, netfs_data, - enable); - else - return NULL; -} - -/** - * fscache_relinquish_cookie - Return the cookie to the cache, maybe discarding - * it - * @cookie: The cookie being returned - * @retire: True if the cache object the cookie represents is to be discarded - * - * This function returns a cookie to the cache, forcibly discarding the - * associated cache object if retire is set to true. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -void fscache_relinquish_cookie(struct fscache_cookie *cookie, bool retire) -{ - if (fscache_cookie_valid(cookie)) - __fscache_relinquish_cookie(cookie, retire); -} - -/** - * fscache_check_consistency - Request that if the cache is updated - * @cookie: The cookie representing the cache object - * - * Request an consistency check from fscache, which passes the request - * to the backing cache. - * - * Returns 0 if consistent and -ESTALE if inconsistent. May also - * return -ENOMEM and -ERESTARTSYS. - */ -static inline -int fscache_check_consistency(struct fscache_cookie *cookie) -{ - if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) - return __fscache_check_consistency(cookie); - else - return 0; -} - -/** - * fscache_update_cookie - Request that a cache object be updated - * @cookie: The cookie representing the cache object - * - * Request an update of the index data for the cache object associated with the - * cookie. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -void fscache_update_cookie(struct fscache_cookie *cookie) -{ - if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) - __fscache_update_cookie(cookie); -} - -/** - * fscache_pin_cookie - Pin a data-storage cache object in its cache - * @cookie: The cookie representing the cache object - * - * Permit data-storage cache objects to be pinned in the cache. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -int fscache_pin_cookie(struct fscache_cookie *cookie) -{ - return -ENOBUFS; -} - -/** - * fscache_pin_cookie - Unpin a data-storage cache object in its cache - * @cookie: The cookie representing the cache object - * - * Permit data-storage cache objects to be unpinned from the cache. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -void fscache_unpin_cookie(struct fscache_cookie *cookie) -{ -} - -/** - * fscache_attr_changed - Notify cache that an object's attributes changed - * @cookie: The cookie representing the cache object - * - * Send a notification to the cache indicating that an object's attributes have - * changed. This includes the data size. These attributes will be obtained - * through the get_attr() cookie definition op. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -int fscache_attr_changed(struct fscache_cookie *cookie) -{ - if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) - return __fscache_attr_changed(cookie); - else - return -ENOBUFS; -} - -/** - * fscache_invalidate - Notify cache that an object needs invalidation - * @cookie: The cookie representing the cache object - * - * Notify the cache that an object is needs to be invalidated and that it - * should abort any retrievals or stores it is doing on the cache. The object - * is then marked non-caching until such time as the invalidation is complete. - * - * This can be called with spinlocks held. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -void fscache_invalidate(struct fscache_cookie *cookie) -{ - if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) - __fscache_invalidate(cookie); -} - -/** - * fscache_wait_on_invalidate - Wait for invalidation to complete - * @cookie: The cookie representing the cache object - * - * Wait for the invalidation of an object to complete. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -void fscache_wait_on_invalidate(struct fscache_cookie *cookie) -{ - if (fscache_cookie_valid(cookie)) - __fscache_wait_on_invalidate(cookie); -} - -/** - * fscache_reserve_space - Reserve data space for a cached object - * @cookie: The cookie representing the cache object - * @i_size: The amount of space to be reserved - * - * Reserve an amount of space in the cache for the cache object attached to a - * cookie so that a write to that object within the space can always be - * honoured. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -int fscache_reserve_space(struct fscache_cookie *cookie, loff_t size) -{ - return -ENOBUFS; -} - -/** - * fscache_read_or_alloc_page - Read a page from the cache or allocate a block - * in which to store it - * @cookie: The cookie representing the cache object - * @page: The netfs page to fill if possible - * @end_io_func: The callback to invoke when and if the page is filled - * @context: An arbitrary piece of data to pass on to end_io_func() - * @gfp: The conditions under which memory allocation should be made - * - * Read a page from the cache, or if that's not possible make a potential - * one-block reservation in the cache into which the page may be stored once - * fetched from the server. - * - * If the page is not backed by the cache object, or if it there's some reason - * it can't be, -ENOBUFS will be returned and nothing more will be done for - * that page. - * - * Else, if that page is backed by the cache, a read will be initiated directly - * to the netfs's page and 0 will be returned by this function. The - * end_io_func() callback will be invoked when the operation terminates on a - * completion or failure. Note that the callback may be invoked before the - * return. - * - * Else, if the page is unbacked, -ENODATA is returned and a block may have - * been allocated in the cache. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -int fscache_read_or_alloc_page(struct fscache_cookie *cookie, - struct page *page, - fscache_rw_complete_t end_io_func, - void *context, - gfp_t gfp) -{ - if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) - return __fscache_read_or_alloc_page(cookie, page, end_io_func, - context, gfp); - else - return -ENOBUFS; -} - -/** - * fscache_read_or_alloc_pages - Read pages from the cache and/or allocate - * blocks in which to store them - * @cookie: The cookie representing the cache object - * @mapping: The netfs inode mapping to which the pages will be attached - * @pages: A list of potential netfs pages to be filled - * @nr_pages: Number of pages to be read and/or allocated - * @end_io_func: The callback to invoke when and if each page is filled - * @context: An arbitrary piece of data to pass on to end_io_func() - * @gfp: The conditions under which memory allocation should be made - * - * Read a set of pages from the cache, or if that's not possible, attempt to - * make a potential one-block reservation for each page in the cache into which - * that page may be stored once fetched from the server. - * - * If some pages are not backed by the cache object, or if it there's some - * reason they can't be, -ENOBUFS will be returned and nothing more will be - * done for that pages. - * - * Else, if some of the pages are backed by the cache, a read will be initiated - * directly to the netfs's page and 0 will be returned by this function. The - * end_io_func() callback will be invoked when the operation terminates on a - * completion or failure. Note that the callback may be invoked before the - * return. - * - * Else, if a page is unbacked, -ENODATA is returned and a block may have - * been allocated in the cache. - * - * Because the function may want to return all of -ENOBUFS, -ENODATA and 0 in - * regard to different pages, the return values are prioritised in that order. - * Any pages submitted for reading are removed from the pages list. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -int fscache_read_or_alloc_pages(struct fscache_cookie *cookie, - struct address_space *mapping, - struct list_head *pages, - unsigned *nr_pages, - fscache_rw_complete_t end_io_func, - void *context, - gfp_t gfp) -{ - if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) - return __fscache_read_or_alloc_pages(cookie, mapping, pages, - nr_pages, end_io_func, - context, gfp); - else - return -ENOBUFS; -} - -/** - * fscache_alloc_page - Allocate a block in which to store a page - * @cookie: The cookie representing the cache object - * @page: The netfs page to allocate a page for - * @gfp: The conditions under which memory allocation should be made - * - * Request Allocation a block in the cache in which to store a netfs page - * without retrieving any contents from the cache. - * - * If the page is not backed by a file then -ENOBUFS will be returned and - * nothing more will be done, and no reservation will be made. - * - * Else, a block will be allocated if one wasn't already, and 0 will be - * returned - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -int fscache_alloc_page(struct fscache_cookie *cookie, - struct page *page, - gfp_t gfp) -{ - if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) - return __fscache_alloc_page(cookie, page, gfp); - else - return -ENOBUFS; -} - -/** - * fscache_readpages_cancel - Cancel read/alloc on pages - * @cookie: The cookie representing the inode's cache object. - * @pages: The netfs pages that we canceled write on in readpages() - * - * Uncache/unreserve the pages reserved earlier in readpages() via - * fscache_readpages_or_alloc() and similar. In most successful caches in - * readpages() this doesn't do anything. In cases when the underlying netfs's - * readahead failed we need to clean up the pagelist (unmark and uncache). - * - * This function may sleep as it may have to clean up disk state. - */ -static inline -void fscache_readpages_cancel(struct fscache_cookie *cookie, - struct list_head *pages) -{ - if (fscache_cookie_valid(cookie)) - __fscache_readpages_cancel(cookie, pages); -} - -/** - * fscache_write_page - Request storage of a page in the cache - * @cookie: The cookie representing the cache object - * @page: The netfs page to store - * @gfp: The conditions under which memory allocation should be made - * - * Request the contents of the netfs page be written into the cache. This - * request may be ignored if no cache block is currently allocated, in which - * case it will return -ENOBUFS. - * - * If a cache block was already allocated, a write will be initiated and 0 will - * be returned. The PG_fscache_write page bit is set immediately and will then - * be cleared at the completion of the write to indicate the success or failure - * of the operation. Note that the completion may happen before the return. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -int fscache_write_page(struct fscache_cookie *cookie, - struct page *page, - gfp_t gfp) -{ - if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) - return __fscache_write_page(cookie, page, gfp); - else - return -ENOBUFS; -} - -/** - * fscache_uncache_page - Indicate that caching is no longer required on a page - * @cookie: The cookie representing the cache object - * @page: The netfs page that was being cached. - * - * Tell the cache that we no longer want a page to be cached and that it should - * remove any knowledge of the netfs page it may have. - * - * Note that this cannot cancel any outstanding I/O operations between this - * page and the cache. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -void fscache_uncache_page(struct fscache_cookie *cookie, - struct page *page) -{ - if (fscache_cookie_valid(cookie)) - __fscache_uncache_page(cookie, page); -} - -/** - * fscache_check_page_write - Ask if a page is being writing to the cache - * @cookie: The cookie representing the cache object - * @page: The netfs page that is being cached. - * - * Ask the cache if a page is being written to the cache. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -bool fscache_check_page_write(struct fscache_cookie *cookie, - struct page *page) -{ - if (fscache_cookie_valid(cookie)) - return __fscache_check_page_write(cookie, page); - return false; -} - -/** - * fscache_wait_on_page_write - Wait for a page to complete writing to the cache - * @cookie: The cookie representing the cache object - * @page: The netfs page that is being cached. - * - * Ask the cache to wake us up when a page is no longer being written to the - * cache. - * - * See Documentation/filesystems/caching/netfs-api.txt for a complete - * description. - */ -static inline -void fscache_wait_on_page_write(struct fscache_cookie *cookie, - struct page *page) -{ - if (fscache_cookie_valid(cookie)) - __fscache_wait_on_page_write(cookie, page); -} - -/** - * fscache_maybe_release_page - Consider releasing a page, cancelling a store - * @cookie: The cookie representing the cache object - * @page: The netfs page that is being cached. - * @gfp: The gfp flags passed to releasepage() - * - * Consider releasing a page for the vmscan algorithm, on behalf of the netfs's - * releasepage() call. A storage request on the page may cancelled if it is - * not currently being processed. - * - * The function returns true if the page no longer has a storage request on it, - * and false if a storage request is left in place. If true is returned, the - * page will have been passed to fscache_uncache_page(). If false is returned - * the page cannot be freed yet. - */ -static inline -bool fscache_maybe_release_page(struct fscache_cookie *cookie, - struct page *page, - gfp_t gfp) -{ - if (fscache_cookie_valid(cookie) && PageFsCache(page)) - return __fscache_maybe_release_page(cookie, page, gfp); - return false; -} - -/** - * fscache_uncache_all_inode_pages - Uncache all an inode's pages - * @cookie: The cookie representing the inode's cache object. - * @inode: The inode to uncache pages from. - * - * Uncache all the pages in an inode that are marked PG_fscache, assuming them - * to be associated with the given cookie. - * - * This function may sleep. It will wait for pages that are being written out - * and will wait whilst the PG_fscache mark is removed by the cache. - */ -static inline -void fscache_uncache_all_inode_pages(struct fscache_cookie *cookie, - struct inode *inode) -{ - if (fscache_cookie_valid(cookie)) - __fscache_uncache_all_inode_pages(cookie, inode); -} - -/** - * fscache_disable_cookie - Disable a cookie - * @cookie: The cookie representing the cache object - * @invalidate: Invalidate the backing object - * - * Disable a cookie from accepting further alloc, read, write, invalidate, - * update or acquire operations. Outstanding operations can still be waited - * upon and pages can still be uncached and the cookie relinquished. - * - * This will not return until all outstanding operations have completed. - * - * If @invalidate is set, then the backing object will be invalidated and - * detached, otherwise it will just be detached. - */ -static inline -void fscache_disable_cookie(struct fscache_cookie *cookie, bool invalidate) -{ - if (fscache_cookie_valid(cookie) && fscache_cookie_enabled(cookie)) - __fscache_disable_cookie(cookie, invalidate); -} - -/** - * fscache_enable_cookie - Reenable a cookie - * @cookie: The cookie representing the cache object - * @can_enable: A function to permit enablement once lock is held - * @data: Data for can_enable() - * - * Reenable a previously disabled cookie, allowing it to accept further alloc, - * read, write, invalidate, update or acquire operations. An attempt will be - * made to immediately reattach the cookie to a backing object. - * - * The can_enable() function is called (if not NULL) once the enablement lock - * is held to rule on whether enablement is still permitted to go ahead. - */ -static inline -void fscache_enable_cookie(struct fscache_cookie *cookie, - bool (*can_enable)(void *data), - void *data) -{ - if (fscache_cookie_valid(cookie) && !fscache_cookie_enabled(cookie)) - __fscache_enable_cookie(cookie, can_enable, data); -} - -#endif /* _LINUX_FSCACHE_H */ diff --git a/src/linux/include/linux/fscrypto.h b/src/linux/include/linux/fscrypto.h deleted file mode 100644 index ff8b11b..0000000 --- a/src/linux/include/linux/fscrypto.h +++ /dev/null @@ -1,411 +0,0 @@ -/* - * General per-file encryption definition - * - * Copyright (C) 2015, Google, Inc. - * - * Written by Michael Halcrow, 2015. - * Modified by Jaegeuk Kim, 2015. - */ - -#ifndef _LINUX_FSCRYPTO_H -#define _LINUX_FSCRYPTO_H - -#include -#include -#include -#include -#include -#include -#include - -#define FS_KEY_DERIVATION_NONCE_SIZE 16 -#define FS_ENCRYPTION_CONTEXT_FORMAT_V1 1 - -#define FS_POLICY_FLAGS_PAD_4 0x00 -#define FS_POLICY_FLAGS_PAD_8 0x01 -#define FS_POLICY_FLAGS_PAD_16 0x02 -#define FS_POLICY_FLAGS_PAD_32 0x03 -#define FS_POLICY_FLAGS_PAD_MASK 0x03 -#define FS_POLICY_FLAGS_VALID 0x03 - -/* Encryption algorithms */ -#define FS_ENCRYPTION_MODE_INVALID 0 -#define FS_ENCRYPTION_MODE_AES_256_XTS 1 -#define FS_ENCRYPTION_MODE_AES_256_GCM 2 -#define FS_ENCRYPTION_MODE_AES_256_CBC 3 -#define FS_ENCRYPTION_MODE_AES_256_CTS 4 - -/** - * Encryption context for inode - * - * Protector format: - * 1 byte: Protector format (1 = this version) - * 1 byte: File contents encryption mode - * 1 byte: File names encryption mode - * 1 byte: Flags - * 8 bytes: Master Key descriptor - * 16 bytes: Encryption Key derivation nonce - */ -struct fscrypt_context { - u8 format; - u8 contents_encryption_mode; - u8 filenames_encryption_mode; - u8 flags; - u8 master_key_descriptor[FS_KEY_DESCRIPTOR_SIZE]; - u8 nonce[FS_KEY_DERIVATION_NONCE_SIZE]; -} __packed; - -/* Encryption parameters */ -#define FS_XTS_TWEAK_SIZE 16 -#define FS_AES_128_ECB_KEY_SIZE 16 -#define FS_AES_256_GCM_KEY_SIZE 32 -#define FS_AES_256_CBC_KEY_SIZE 32 -#define FS_AES_256_CTS_KEY_SIZE 32 -#define FS_AES_256_XTS_KEY_SIZE 64 -#define FS_MAX_KEY_SIZE 64 - -#define FS_KEY_DESC_PREFIX "fscrypt:" -#define FS_KEY_DESC_PREFIX_SIZE 8 - -/* This is passed in from userspace into the kernel keyring */ -struct fscrypt_key { - u32 mode; - u8 raw[FS_MAX_KEY_SIZE]; - u32 size; -} __packed; - -struct fscrypt_info { - u8 ci_data_mode; - u8 ci_filename_mode; - u8 ci_flags; - struct crypto_skcipher *ci_ctfm; - struct key *ci_keyring_key; - u8 ci_master_key[FS_KEY_DESCRIPTOR_SIZE]; -}; - -#define FS_CTX_REQUIRES_FREE_ENCRYPT_FL 0x00000001 -#define FS_WRITE_PATH_FL 0x00000002 - -struct fscrypt_ctx { - union { - struct { - struct page *bounce_page; /* Ciphertext page */ - struct page *control_page; /* Original page */ - } w; - struct { - struct bio *bio; - struct work_struct work; - } r; - struct list_head free_list; /* Free list */ - }; - u8 flags; /* Flags */ - u8 mode; /* Encryption mode for tfm */ -}; - -struct fscrypt_completion_result { - struct completion completion; - int res; -}; - -#define DECLARE_FS_COMPLETION_RESULT(ecr) \ - struct fscrypt_completion_result ecr = { \ - COMPLETION_INITIALIZER((ecr).completion), 0 } - -#define FS_FNAME_NUM_SCATTER_ENTRIES 4 -#define FS_CRYPTO_BLOCK_SIZE 16 -#define FS_FNAME_CRYPTO_DIGEST_SIZE 32 - -/** - * For encrypted symlinks, the ciphertext length is stored at the beginning - * of the string in little-endian format. - */ -struct fscrypt_symlink_data { - __le16 len; - char encrypted_path[1]; -} __packed; - -/** - * This function is used to calculate the disk space required to - * store a filename of length l in encrypted symlink format. - */ -static inline u32 fscrypt_symlink_data_len(u32 l) -{ - if (l < FS_CRYPTO_BLOCK_SIZE) - l = FS_CRYPTO_BLOCK_SIZE; - return (l + sizeof(struct fscrypt_symlink_data) - 1); -} - -struct fscrypt_str { - unsigned char *name; - u32 len; -}; - -struct fscrypt_name { - const struct qstr *usr_fname; - struct fscrypt_str disk_name; - u32 hash; - u32 minor_hash; - struct fscrypt_str crypto_buf; -}; - -#define FSTR_INIT(n, l) { .name = n, .len = l } -#define FSTR_TO_QSTR(f) QSTR_INIT((f)->name, (f)->len) -#define fname_name(p) ((p)->disk_name.name) -#define fname_len(p) ((p)->disk_name.len) - -/* - * crypto opertions for filesystems - */ -struct fscrypt_operations { - int (*get_context)(struct inode *, void *, size_t); - int (*key_prefix)(struct inode *, u8 **); - int (*prepare_context)(struct inode *); - int (*set_context)(struct inode *, const void *, size_t, void *); - int (*dummy_context)(struct inode *); - bool (*is_encrypted)(struct inode *); - bool (*empty_dir)(struct inode *); - unsigned (*max_namelen)(struct inode *); -}; - -static inline bool fscrypt_dummy_context_enabled(struct inode *inode) -{ - if (inode->i_sb->s_cop->dummy_context && - inode->i_sb->s_cop->dummy_context(inode)) - return true; - return false; -} - -static inline bool fscrypt_valid_contents_enc_mode(u32 mode) -{ - return (mode == FS_ENCRYPTION_MODE_AES_256_XTS); -} - -static inline bool fscrypt_valid_filenames_enc_mode(u32 mode) -{ - return (mode == FS_ENCRYPTION_MODE_AES_256_CTS); -} - -static inline bool fscrypt_is_dot_dotdot(const struct qstr *str) -{ - if (str->len == 1 && str->name[0] == '.') - return true; - - if (str->len == 2 && str->name[0] == '.' && str->name[1] == '.') - return true; - - return false; -} - -static inline struct page *fscrypt_control_page(struct page *page) -{ -#if IS_ENABLED(CONFIG_FS_ENCRYPTION) - return ((struct fscrypt_ctx *)page_private(page))->w.control_page; -#else - WARN_ON_ONCE(1); - return ERR_PTR(-EINVAL); -#endif -} - -static inline int fscrypt_has_encryption_key(struct inode *inode) -{ -#if IS_ENABLED(CONFIG_FS_ENCRYPTION) - return (inode->i_crypt_info != NULL); -#else - return 0; -#endif -} - -static inline void fscrypt_set_encrypted_dentry(struct dentry *dentry) -{ -#if IS_ENABLED(CONFIG_FS_ENCRYPTION) - spin_lock(&dentry->d_lock); - dentry->d_flags |= DCACHE_ENCRYPTED_WITH_KEY; - spin_unlock(&dentry->d_lock); -#endif -} - -#if IS_ENABLED(CONFIG_FS_ENCRYPTION) -extern const struct dentry_operations fscrypt_d_ops; -#endif - -static inline void fscrypt_set_d_op(struct dentry *dentry) -{ -#if IS_ENABLED(CONFIG_FS_ENCRYPTION) - d_set_d_op(dentry, &fscrypt_d_ops); -#endif -} - -#if IS_ENABLED(CONFIG_FS_ENCRYPTION) -/* crypto.c */ -extern struct kmem_cache *fscrypt_info_cachep; -int fscrypt_initialize(void); - -extern struct fscrypt_ctx *fscrypt_get_ctx(struct inode *, gfp_t); -extern void fscrypt_release_ctx(struct fscrypt_ctx *); -extern struct page *fscrypt_encrypt_page(struct inode *, struct page *, gfp_t); -extern int fscrypt_decrypt_page(struct page *); -extern void fscrypt_decrypt_bio_pages(struct fscrypt_ctx *, struct bio *); -extern void fscrypt_pullback_bio_page(struct page **, bool); -extern void fscrypt_restore_control_page(struct page *); -extern int fscrypt_zeroout_range(struct inode *, pgoff_t, sector_t, - unsigned int); -/* policy.c */ -extern int fscrypt_process_policy(struct file *, const struct fscrypt_policy *); -extern int fscrypt_get_policy(struct inode *, struct fscrypt_policy *); -extern int fscrypt_has_permitted_context(struct inode *, struct inode *); -extern int fscrypt_inherit_context(struct inode *, struct inode *, - void *, bool); -/* keyinfo.c */ -extern int get_crypt_info(struct inode *); -extern int fscrypt_get_encryption_info(struct inode *); -extern void fscrypt_put_encryption_info(struct inode *, struct fscrypt_info *); - -/* fname.c */ -extern int fscrypt_setup_filename(struct inode *, const struct qstr *, - int lookup, struct fscrypt_name *); -extern void fscrypt_free_filename(struct fscrypt_name *); -extern u32 fscrypt_fname_encrypted_size(struct inode *, u32); -extern int fscrypt_fname_alloc_buffer(struct inode *, u32, - struct fscrypt_str *); -extern void fscrypt_fname_free_buffer(struct fscrypt_str *); -extern int fscrypt_fname_disk_to_usr(struct inode *, u32, u32, - const struct fscrypt_str *, struct fscrypt_str *); -extern int fscrypt_fname_usr_to_disk(struct inode *, const struct qstr *, - struct fscrypt_str *); -#endif - -/* crypto.c */ -static inline struct fscrypt_ctx *fscrypt_notsupp_get_ctx(struct inode *i, - gfp_t f) -{ - return ERR_PTR(-EOPNOTSUPP); -} - -static inline void fscrypt_notsupp_release_ctx(struct fscrypt_ctx *c) -{ - return; -} - -static inline struct page *fscrypt_notsupp_encrypt_page(struct inode *i, - struct page *p, gfp_t f) -{ - return ERR_PTR(-EOPNOTSUPP); -} - -static inline int fscrypt_notsupp_decrypt_page(struct page *p) -{ - return -EOPNOTSUPP; -} - -static inline void fscrypt_notsupp_decrypt_bio_pages(struct fscrypt_ctx *c, - struct bio *b) -{ - return; -} - -static inline void fscrypt_notsupp_pullback_bio_page(struct page **p, bool b) -{ - return; -} - -static inline void fscrypt_notsupp_restore_control_page(struct page *p) -{ - return; -} - -static inline int fscrypt_notsupp_zeroout_range(struct inode *i, pgoff_t p, - sector_t s, unsigned int f) -{ - return -EOPNOTSUPP; -} - -/* policy.c */ -static inline int fscrypt_notsupp_process_policy(struct file *f, - const struct fscrypt_policy *p) -{ - return -EOPNOTSUPP; -} - -static inline int fscrypt_notsupp_get_policy(struct inode *i, - struct fscrypt_policy *p) -{ - return -EOPNOTSUPP; -} - -static inline int fscrypt_notsupp_has_permitted_context(struct inode *p, - struct inode *i) -{ - return 0; -} - -static inline int fscrypt_notsupp_inherit_context(struct inode *p, - struct inode *i, void *v, bool b) -{ - return -EOPNOTSUPP; -} - -/* keyinfo.c */ -static inline int fscrypt_notsupp_get_encryption_info(struct inode *i) -{ - return -EOPNOTSUPP; -} - -static inline void fscrypt_notsupp_put_encryption_info(struct inode *i, - struct fscrypt_info *f) -{ - return; -} - - /* fname.c */ -static inline int fscrypt_notsupp_setup_filename(struct inode *dir, - const struct qstr *iname, - int lookup, struct fscrypt_name *fname) -{ - if (dir->i_sb->s_cop->is_encrypted(dir)) - return -EOPNOTSUPP; - - memset(fname, 0, sizeof(struct fscrypt_name)); - fname->usr_fname = iname; - fname->disk_name.name = (unsigned char *)iname->name; - fname->disk_name.len = iname->len; - return 0; -} - -static inline void fscrypt_notsupp_free_filename(struct fscrypt_name *fname) -{ - return; -} - -static inline u32 fscrypt_notsupp_fname_encrypted_size(struct inode *i, u32 s) -{ - /* never happens */ - WARN_ON(1); - return 0; -} - -static inline int fscrypt_notsupp_fname_alloc_buffer(struct inode *inode, - u32 ilen, struct fscrypt_str *crypto_str) -{ - return -EOPNOTSUPP; -} - -static inline void fscrypt_notsupp_fname_free_buffer(struct fscrypt_str *c) -{ - return; -} - -static inline int fscrypt_notsupp_fname_disk_to_usr(struct inode *inode, - u32 hash, u32 minor_hash, - const struct fscrypt_str *iname, - struct fscrypt_str *oname) -{ - return -EOPNOTSUPP; -} - -static inline int fscrypt_notsupp_fname_usr_to_disk(struct inode *inode, - const struct qstr *iname, - struct fscrypt_str *oname) -{ - return -EOPNOTSUPP; -} -#endif /* _LINUX_FSCRYPTO_H */ diff --git a/src/linux/include/linux/fsnotify.h b/src/linux/include/linux/fsnotify.h deleted file mode 100644 index b8bcc05..0000000 --- a/src/linux/include/linux/fsnotify.h +++ /dev/null @@ -1,327 +0,0 @@ -#ifndef _LINUX_FS_NOTIFY_H -#define _LINUX_FS_NOTIFY_H - -/* - * include/linux/fsnotify.h - generic hooks for filesystem notification, to - * reduce in-source duplication from both dnotify and inotify. - * - * We don't compile any of this away in some complicated menagerie of ifdefs. - * Instead, we rely on the code inside to optimize away as needed. - * - * (C) Copyright 2005 Robert Love - */ - -#include -#include -#include -#include - -/* Notify this dentry's parent about a child's events. */ -static inline int fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask) -{ - if (!dentry) - dentry = path->dentry; - - return __fsnotify_parent(path, dentry, mask); -} - -/* simple call site for access decisions */ -static inline int fsnotify_perm(struct file *file, int mask) -{ - struct path *path = &file->f_path; - /* - * Do not use file_inode() here or anywhere in this file to get the - * inode. That would break *notity on overlayfs. - */ - struct inode *inode = path->dentry->d_inode; - __u32 fsnotify_mask = 0; - int ret; - - if (file->f_mode & FMODE_NONOTIFY) - return 0; - if (!(mask & (MAY_READ | MAY_OPEN))) - return 0; - if (mask & MAY_OPEN) - fsnotify_mask = FS_OPEN_PERM; - else if (mask & MAY_READ) - fsnotify_mask = FS_ACCESS_PERM; - else - BUG(); - - ret = fsnotify_parent(path, NULL, fsnotify_mask); - if (ret) - return ret; - - return fsnotify(inode, fsnotify_mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); -} - -/* - * fsnotify_link_count - inode's link count changed - */ -static inline void fsnotify_link_count(struct inode *inode) -{ - fsnotify(inode, FS_ATTRIB, inode, FSNOTIFY_EVENT_INODE, NULL, 0); -} - -/* - * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir - */ -static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, - const unsigned char *old_name, - int isdir, struct inode *target, struct dentry *moved) -{ - struct inode *source = moved->d_inode; - u32 fs_cookie = fsnotify_get_cookie(); - __u32 old_dir_mask = (FS_EVENT_ON_CHILD | FS_MOVED_FROM); - __u32 new_dir_mask = (FS_EVENT_ON_CHILD | FS_MOVED_TO); - const unsigned char *new_name = moved->d_name.name; - - if (old_dir == new_dir) - old_dir_mask |= FS_DN_RENAME; - - if (isdir) { - old_dir_mask |= FS_ISDIR; - new_dir_mask |= FS_ISDIR; - } - - fsnotify(old_dir, old_dir_mask, source, FSNOTIFY_EVENT_INODE, old_name, - fs_cookie); - fsnotify(new_dir, new_dir_mask, source, FSNOTIFY_EVENT_INODE, new_name, - fs_cookie); - - if (target) - fsnotify_link_count(target); - - if (source) - fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE, NULL, 0); - audit_inode_child(new_dir, moved, AUDIT_TYPE_CHILD_CREATE); -} - -/* - * fsnotify_inode_delete - and inode is being evicted from cache, clean up is needed - */ -static inline void fsnotify_inode_delete(struct inode *inode) -{ - __fsnotify_inode_delete(inode); -} - -/* - * fsnotify_vfsmount_delete - a vfsmount is being destroyed, clean up is needed - */ -static inline void fsnotify_vfsmount_delete(struct vfsmount *mnt) -{ - __fsnotify_vfsmount_delete(mnt); -} - -/* - * fsnotify_nameremove - a filename was removed from a directory - */ -static inline void fsnotify_nameremove(struct dentry *dentry, int isdir) -{ - __u32 mask = FS_DELETE; - - if (isdir) - mask |= FS_ISDIR; - - fsnotify_parent(NULL, dentry, mask); -} - -/* - * fsnotify_inoderemove - an inode is going away - */ -static inline void fsnotify_inoderemove(struct inode *inode) -{ - fsnotify(inode, FS_DELETE_SELF, inode, FSNOTIFY_EVENT_INODE, NULL, 0); - __fsnotify_inode_delete(inode); -} - -/* - * fsnotify_create - 'name' was linked in - */ -static inline void fsnotify_create(struct inode *inode, struct dentry *dentry) -{ - audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE); - - fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0); -} - -/* - * fsnotify_link - new hardlink in 'inode' directory - * Note: We have to pass also the linked inode ptr as some filesystems leave - * new_dentry->d_inode NULL and instantiate inode pointer later - */ -static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct dentry *new_dentry) -{ - fsnotify_link_count(inode); - audit_inode_child(dir, new_dentry, AUDIT_TYPE_CHILD_CREATE); - - fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, new_dentry->d_name.name, 0); -} - -/* - * fsnotify_mkdir - directory 'name' was created - */ -static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry) -{ - __u32 mask = (FS_CREATE | FS_ISDIR); - struct inode *d_inode = dentry->d_inode; - - audit_inode_child(inode, dentry, AUDIT_TYPE_CHILD_CREATE); - - fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0); -} - -/* - * fsnotify_access - file was read - */ -static inline void fsnotify_access(struct file *file) -{ - struct path *path = &file->f_path; - struct inode *inode = path->dentry->d_inode; - __u32 mask = FS_ACCESS; - - if (S_ISDIR(inode->i_mode)) - mask |= FS_ISDIR; - - if (!(file->f_mode & FMODE_NONOTIFY)) { - fsnotify_parent(path, NULL, mask); - fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); - } -} - -/* - * fsnotify_modify - file was modified - */ -static inline void fsnotify_modify(struct file *file) -{ - struct path *path = &file->f_path; - struct inode *inode = path->dentry->d_inode; - __u32 mask = FS_MODIFY; - - if (S_ISDIR(inode->i_mode)) - mask |= FS_ISDIR; - - if (!(file->f_mode & FMODE_NONOTIFY)) { - fsnotify_parent(path, NULL, mask); - fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); - } -} - -/* - * fsnotify_open - file was opened - */ -static inline void fsnotify_open(struct file *file) -{ - struct path *path = &file->f_path; - struct inode *inode = path->dentry->d_inode; - __u32 mask = FS_OPEN; - - if (S_ISDIR(inode->i_mode)) - mask |= FS_ISDIR; - - fsnotify_parent(path, NULL, mask); - fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); -} - -/* - * fsnotify_close - file was closed - */ -static inline void fsnotify_close(struct file *file) -{ - struct path *path = &file->f_path; - struct inode *inode = path->dentry->d_inode; - fmode_t mode = file->f_mode; - __u32 mask = (mode & FMODE_WRITE) ? FS_CLOSE_WRITE : FS_CLOSE_NOWRITE; - - if (S_ISDIR(inode->i_mode)) - mask |= FS_ISDIR; - - if (!(file->f_mode & FMODE_NONOTIFY)) { - fsnotify_parent(path, NULL, mask); - fsnotify(inode, mask, path, FSNOTIFY_EVENT_PATH, NULL, 0); - } -} - -/* - * fsnotify_xattr - extended attributes were changed - */ -static inline void fsnotify_xattr(struct dentry *dentry) -{ - struct inode *inode = dentry->d_inode; - __u32 mask = FS_ATTRIB; - - if (S_ISDIR(inode->i_mode)) - mask |= FS_ISDIR; - - fsnotify_parent(NULL, dentry, mask); - fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0); -} - -/* - * fsnotify_change - notify_change event. file was modified and/or metadata - * was changed. - */ -static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid) -{ - struct inode *inode = dentry->d_inode; - __u32 mask = 0; - - if (ia_valid & ATTR_UID) - mask |= FS_ATTRIB; - if (ia_valid & ATTR_GID) - mask |= FS_ATTRIB; - if (ia_valid & ATTR_SIZE) - mask |= FS_MODIFY; - - /* both times implies a utime(s) call */ - if ((ia_valid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME)) - mask |= FS_ATTRIB; - else if (ia_valid & ATTR_ATIME) - mask |= FS_ACCESS; - else if (ia_valid & ATTR_MTIME) - mask |= FS_MODIFY; - - if (ia_valid & ATTR_MODE) - mask |= FS_ATTRIB; - - if (mask) { - if (S_ISDIR(inode->i_mode)) - mask |= FS_ISDIR; - - fsnotify_parent(NULL, dentry, mask); - fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0); - } -} - -#if defined(CONFIG_FSNOTIFY) /* notify helpers */ - -/* - * fsnotify_oldname_init - save off the old filename before we change it - */ -static inline const unsigned char *fsnotify_oldname_init(const unsigned char *name) -{ - return kstrdup(name, GFP_KERNEL); -} - -/* - * fsnotify_oldname_free - free the name we got from fsnotify_oldname_init - */ -static inline void fsnotify_oldname_free(const unsigned char *old_name) -{ - kfree(old_name); -} - -#else /* CONFIG_FSNOTIFY */ - -static inline const char *fsnotify_oldname_init(const unsigned char *name) -{ - return NULL; -} - -static inline void fsnotify_oldname_free(const unsigned char *old_name) -{ -} - -#endif /* CONFIG_FSNOTIFY */ - -#endif /* _LINUX_FS_NOTIFY_H */ diff --git a/src/linux/include/linux/fsnotify_backend.h b/src/linux/include/linux/fsnotify_backend.h deleted file mode 100644 index 79467b2..0000000 --- a/src/linux/include/linux/fsnotify_backend.h +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Filesystem access notification for Linux - * - * Copyright (C) 2008 Red Hat, Inc., Eric Paris - */ - -#ifndef __LINUX_FSNOTIFY_BACKEND_H -#define __LINUX_FSNOTIFY_BACKEND_H - -#ifdef __KERNEL__ - -#include /* inotify uses this */ -#include /* struct inode */ -#include -#include /* struct path */ -#include -#include -#include - -/* - * IN_* from inotfy.h lines up EXACTLY with FS_*, this is so we can easily - * convert between them. dnotify only needs conversion at watch creation - * so no perf loss there. fanotify isn't defined yet, so it can use the - * wholes if it needs more events. - */ -#define FS_ACCESS 0x00000001 /* File was accessed */ -#define FS_MODIFY 0x00000002 /* File was modified */ -#define FS_ATTRIB 0x00000004 /* Metadata changed */ -#define FS_CLOSE_WRITE 0x00000008 /* Writtable file was closed */ -#define FS_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */ -#define FS_OPEN 0x00000020 /* File was opened */ -#define FS_MOVED_FROM 0x00000040 /* File was moved from X */ -#define FS_MOVED_TO 0x00000080 /* File was moved to Y */ -#define FS_CREATE 0x00000100 /* Subfile was created */ -#define FS_DELETE 0x00000200 /* Subfile was deleted */ -#define FS_DELETE_SELF 0x00000400 /* Self was deleted */ -#define FS_MOVE_SELF 0x00000800 /* Self was moved */ - -#define FS_UNMOUNT 0x00002000 /* inode on umount fs */ -#define FS_Q_OVERFLOW 0x00004000 /* Event queued overflowed */ -#define FS_IN_IGNORED 0x00008000 /* last inotify event here */ - -#define FS_OPEN_PERM 0x00010000 /* open event in an permission hook */ -#define FS_ACCESS_PERM 0x00020000 /* access event in a permissions hook */ - -#define FS_EXCL_UNLINK 0x04000000 /* do not send events if object is unlinked */ -#define FS_ISDIR 0x40000000 /* event occurred against dir */ -#define FS_IN_ONESHOT 0x80000000 /* only send event once */ - -#define FS_DN_RENAME 0x10000000 /* file renamed */ -#define FS_DN_MULTISHOT 0x20000000 /* dnotify multishot */ - -/* This inode cares about things that happen to its children. Always set for - * dnotify and inotify. */ -#define FS_EVENT_ON_CHILD 0x08000000 - -/* This is a list of all events that may get sent to a parernt based on fs event - * happening to inodes inside that directory */ -#define FS_EVENTS_POSS_ON_CHILD (FS_ACCESS | FS_MODIFY | FS_ATTRIB |\ - FS_CLOSE_WRITE | FS_CLOSE_NOWRITE | FS_OPEN |\ - FS_MOVED_FROM | FS_MOVED_TO | FS_CREATE |\ - FS_DELETE | FS_OPEN_PERM | FS_ACCESS_PERM) - -#define FS_MOVE (FS_MOVED_FROM | FS_MOVED_TO) - -#define ALL_FSNOTIFY_PERM_EVENTS (FS_OPEN_PERM | FS_ACCESS_PERM) - -#define ALL_FSNOTIFY_EVENTS (FS_ACCESS | FS_MODIFY | FS_ATTRIB | \ - FS_CLOSE_WRITE | FS_CLOSE_NOWRITE | FS_OPEN | \ - FS_MOVED_FROM | FS_MOVED_TO | FS_CREATE | \ - FS_DELETE | FS_DELETE_SELF | FS_MOVE_SELF | \ - FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \ - FS_OPEN_PERM | FS_ACCESS_PERM | FS_EXCL_UNLINK | \ - FS_ISDIR | FS_IN_ONESHOT | FS_DN_RENAME | \ - FS_DN_MULTISHOT | FS_EVENT_ON_CHILD) - -struct fsnotify_group; -struct fsnotify_event; -struct fsnotify_mark; -struct fsnotify_event_private_data; -struct fsnotify_fname; - -/* - * Each group much define these ops. The fsnotify infrastructure will call - * these operations for each relevant group. - * - * handle_event - main call for a group to handle an fs event - * free_group_priv - called when a group refcnt hits 0 to clean up the private union - * freeing_mark - called when a mark is being destroyed for some reason. The group - * MUST be holding a reference on each mark and that reference must be - * dropped in this function. inotify uses this function to send - * userspace messages that marks have been removed. - */ -struct fsnotify_ops { - int (*handle_event)(struct fsnotify_group *group, - struct inode *inode, - struct fsnotify_mark *inode_mark, - struct fsnotify_mark *vfsmount_mark, - u32 mask, void *data, int data_type, - const unsigned char *file_name, u32 cookie); - void (*free_group_priv)(struct fsnotify_group *group); - void (*freeing_mark)(struct fsnotify_mark *mark, struct fsnotify_group *group); - void (*free_event)(struct fsnotify_event *event); -}; - -/* - * all of the information about the original object we want to now send to - * a group. If you want to carry more info from the accessing task to the - * listener this structure is where you need to be adding fields. - */ -struct fsnotify_event { - struct list_head list; - /* inode may ONLY be dereferenced during handle_event(). */ - struct inode *inode; /* either the inode the event happened to or its parent */ - u32 mask; /* the type of access, bitwise OR for FS_* event types */ -}; - -/* - * A group is a "thing" that wants to receive notification about filesystem - * events. The mask holds the subset of event types this group cares about. - * refcnt on a group is up to the implementor and at any moment if it goes 0 - * everything will be cleaned up. - */ -struct fsnotify_group { - /* - * How the refcnt is used is up to each group. When the refcnt hits 0 - * fsnotify will clean up all of the resources associated with this group. - * As an example, the dnotify group will always have a refcnt=1 and that - * will never change. Inotify, on the other hand, has a group per - * inotify_init() and the refcnt will hit 0 only when that fd has been - * closed. - */ - atomic_t refcnt; /* things with interest in this group */ - - const struct fsnotify_ops *ops; /* how this group handles things */ - - /* needed to send notification to userspace */ - spinlock_t notification_lock; /* protect the notification_list */ - struct list_head notification_list; /* list of event_holder this group needs to send to userspace */ - wait_queue_head_t notification_waitq; /* read() on the notification file blocks on this waitq */ - unsigned int q_len; /* events on the queue */ - unsigned int max_events; /* maximum events allowed on the list */ - /* - * Valid fsnotify group priorities. Events are send in order from highest - * priority to lowest priority. We default to the lowest priority. - */ - #define FS_PRIO_0 0 /* normal notifiers, no permissions */ - #define FS_PRIO_1 1 /* fanotify content based access control */ - #define FS_PRIO_2 2 /* fanotify pre-content access */ - unsigned int priority; - bool shutdown; /* group is being shut down, don't queue more events */ - - /* stores all fastpath marks assoc with this group so they can be cleaned on unregister */ - struct mutex mark_mutex; /* protect marks_list */ - atomic_t num_marks; /* 1 for each mark and 1 for not being - * past the point of no return when freeing - * a group */ - struct list_head marks_list; /* all inode marks for this group */ - - struct fasync_struct *fsn_fa; /* async notification */ - - struct fsnotify_event *overflow_event; /* Event we queue when the - * notification list is too - * full */ - - /* groups can define private fields here or use the void *private */ - union { - void *private; -#ifdef CONFIG_INOTIFY_USER - struct inotify_group_private_data { - spinlock_t idr_lock; - struct idr idr; - struct user_struct *user; - } inotify_data; -#endif -#ifdef CONFIG_FANOTIFY - struct fanotify_group_private_data { -#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS - /* allows a group to block waiting for a userspace response */ - struct list_head access_list; - wait_queue_head_t access_waitq; -#endif /* CONFIG_FANOTIFY_ACCESS_PERMISSIONS */ - int f_flags; - unsigned int max_marks; - struct user_struct *user; - } fanotify_data; -#endif /* CONFIG_FANOTIFY */ - }; -}; - -/* when calling fsnotify tell it if the data is a path or inode */ -#define FSNOTIFY_EVENT_NONE 0 -#define FSNOTIFY_EVENT_PATH 1 -#define FSNOTIFY_EVENT_INODE 2 - -/* - * A mark is simply an object attached to an in core inode which allows an - * fsnotify listener to indicate they are either no longer interested in events - * of a type matching mask or only interested in those events. - * - * These are flushed when an inode is evicted from core and may be flushed - * when the inode is modified (as seen by fsnotify_access). Some fsnotify - * users (such as dnotify) will flush these when the open fd is closed and not - * at inode eviction or modification. - * - * Text in brackets is showing the lock(s) protecting modifications of a - * particular entry. obj_lock means either inode->i_lock or - * mnt->mnt_root->d_lock depending on the mark type. - */ -struct fsnotify_mark { - /* Mask this mark is for [mark->lock, group->mark_mutex] */ - __u32 mask; - /* We hold one for presence in g_list. Also one ref for each 'thing' - * in kernel that found and may be using this mark. */ - atomic_t refcnt; - /* Group this mark is for. Set on mark creation, stable until last ref - * is dropped */ - struct fsnotify_group *group; - /* List of marks by group->i_fsnotify_marks. Also reused for queueing - * mark into destroy_list when it's waiting for the end of SRCU period - * before it can be freed. [group->mark_mutex] */ - struct list_head g_list; - /* Protects inode / mnt pointers, flags, masks */ - spinlock_t lock; - /* List of marks for inode / vfsmount [obj_lock] */ - struct hlist_node obj_list; - union { /* Object pointer [mark->lock, group->mark_mutex] */ - struct inode *inode; /* inode this mark is associated with */ - struct vfsmount *mnt; /* vfsmount this mark is associated with */ - }; - /* Events types to ignore [mark->lock, group->mark_mutex] */ - __u32 ignored_mask; -#define FSNOTIFY_MARK_FLAG_INODE 0x01 -#define FSNOTIFY_MARK_FLAG_VFSMOUNT 0x02 -#define FSNOTIFY_MARK_FLAG_OBJECT_PINNED 0x04 -#define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x08 -#define FSNOTIFY_MARK_FLAG_ALIVE 0x10 -#define FSNOTIFY_MARK_FLAG_ATTACHED 0x20 - unsigned int flags; /* flags [mark->lock] */ - void (*free_mark)(struct fsnotify_mark *mark); /* called on final put+free */ -}; - -#ifdef CONFIG_FSNOTIFY - -/* called from the vfs helpers */ - -/* main fsnotify call to send events */ -extern int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, - const unsigned char *name, u32 cookie); -extern int __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask); -extern void __fsnotify_inode_delete(struct inode *inode); -extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt); -extern u32 fsnotify_get_cookie(void); - -static inline int fsnotify_inode_watches_children(struct inode *inode) -{ - /* FS_EVENT_ON_CHILD is set if the inode may care */ - if (!(inode->i_fsnotify_mask & FS_EVENT_ON_CHILD)) - return 0; - /* this inode might care about child events, does it care about the - * specific set of events that can happen on a child? */ - return inode->i_fsnotify_mask & FS_EVENTS_POSS_ON_CHILD; -} - -/* - * Update the dentry with a flag indicating the interest of its parent to receive - * filesystem events when those events happens to this dentry->d_inode. - */ -static inline void fsnotify_update_flags(struct dentry *dentry) -{ - assert_spin_locked(&dentry->d_lock); - - /* - * Serialisation of setting PARENT_WATCHED on the dentries is provided - * by d_lock. If inotify_inode_watched changes after we have taken - * d_lock, the following __fsnotify_update_child_dentry_flags call will - * find our entry, so it will spin until we complete here, and update - * us with the new state. - */ - if (fsnotify_inode_watches_children(dentry->d_parent->d_inode)) - dentry->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED; - else - dentry->d_flags &= ~DCACHE_FSNOTIFY_PARENT_WATCHED; -} - -/* called from fsnotify listeners, such as fanotify or dnotify */ - -/* create a new group */ -extern struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops); -/* get reference to a group */ -extern void fsnotify_get_group(struct fsnotify_group *group); -/* drop reference on a group from fsnotify_alloc_group */ -extern void fsnotify_put_group(struct fsnotify_group *group); -/* group destruction begins, stop queuing new events */ -extern void fsnotify_group_stop_queueing(struct fsnotify_group *group); -/* destroy group */ -extern void fsnotify_destroy_group(struct fsnotify_group *group); -/* fasync handler function */ -extern int fsnotify_fasync(int fd, struct file *file, int on); -/* Free event from memory */ -extern void fsnotify_destroy_event(struct fsnotify_group *group, - struct fsnotify_event *event); -/* attach the event to the group notification queue */ -extern int fsnotify_add_event(struct fsnotify_group *group, - struct fsnotify_event *event, - int (*merge)(struct list_head *, - struct fsnotify_event *)); -/* true if the group notification queue is empty */ -extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group); -/* return, but do not dequeue the first event on the notification queue */ -extern struct fsnotify_event *fsnotify_peek_first_event(struct fsnotify_group *group); -/* return AND dequeue the first event on the notification queue */ -extern struct fsnotify_event *fsnotify_remove_first_event(struct fsnotify_group *group); - -/* functions used to manipulate the marks attached to inodes */ - -/* run all marks associated with a vfsmount and update mnt->mnt_fsnotify_mask */ -extern void fsnotify_recalc_vfsmount_mask(struct vfsmount *mnt); -/* run all marks associated with an inode and update inode->i_fsnotify_mask */ -extern void fsnotify_recalc_inode_mask(struct inode *inode); -extern void fsnotify_init_mark(struct fsnotify_mark *mark, void (*free_mark)(struct fsnotify_mark *mark)); -/* find (and take a reference) to a mark associated with group and inode */ -extern struct fsnotify_mark *fsnotify_find_inode_mark(struct fsnotify_group *group, struct inode *inode); -/* find (and take a reference) to a mark associated with group and vfsmount */ -extern struct fsnotify_mark *fsnotify_find_vfsmount_mark(struct fsnotify_group *group, struct vfsmount *mnt); -/* copy the values from old into new */ -extern void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old); -/* set the ignored_mask of a mark */ -extern void fsnotify_set_mark_ignored_mask_locked(struct fsnotify_mark *mark, __u32 mask); -/* set the mask of a mark (might pin the object into memory */ -extern void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask); -/* attach the mark to both the group and the inode */ -extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group, - struct inode *inode, struct vfsmount *mnt, int allow_dups); -extern int fsnotify_add_mark_locked(struct fsnotify_mark *mark, struct fsnotify_group *group, - struct inode *inode, struct vfsmount *mnt, int allow_dups); -/* given a group and a mark, flag mark to be freed when all references are dropped */ -extern void fsnotify_destroy_mark(struct fsnotify_mark *mark, - struct fsnotify_group *group); -/* detach mark from inode / mount list, group list, drop inode reference */ -extern void fsnotify_detach_mark(struct fsnotify_mark *mark); -/* free mark */ -extern void fsnotify_free_mark(struct fsnotify_mark *mark); -/* run all the marks in a group, and clear all of the vfsmount marks */ -extern void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group); -/* run all the marks in a group, and clear all of the inode marks */ -extern void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group); -/* run all the marks in a group, and clear all of the marks where mark->flags & flags is true*/ -extern void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, unsigned int flags); -extern void fsnotify_get_mark(struct fsnotify_mark *mark); -extern void fsnotify_put_mark(struct fsnotify_mark *mark); -extern void fsnotify_unmount_inodes(struct super_block *sb); - -/* put here because inotify does some weird stuff when destroying watches */ -extern void fsnotify_init_event(struct fsnotify_event *event, - struct inode *to_tell, u32 mask); - -#else - -static inline int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, - const unsigned char *name, u32 cookie) -{ - return 0; -} - -static inline int __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask) -{ - return 0; -} - -static inline void __fsnotify_inode_delete(struct inode *inode) -{} - -static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt) -{} - -static inline void fsnotify_update_flags(struct dentry *dentry) -{} - -static inline u32 fsnotify_get_cookie(void) -{ - return 0; -} - -static inline void fsnotify_unmount_inodes(struct super_block *sb) -{} - -#endif /* CONFIG_FSNOTIFY */ - -#endif /* __KERNEL __ */ - -#endif /* __LINUX_FSNOTIFY_BACKEND_H */ diff --git a/src/linux/include/linux/ftrace.h b/src/linux/include/linux/ftrace.h deleted file mode 100644 index b3d34d3..0000000 --- a/src/linux/include/linux/ftrace.h +++ /dev/null @@ -1,962 +0,0 @@ -/* - * Ftrace header. For implementation details beyond the random comments - * scattered below, see: Documentation/trace/ftrace-design.txt - */ - -#ifndef _LINUX_FTRACE_H -#define _LINUX_FTRACE_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * If the arch supports passing the variable contents of - * function_trace_op as the third parameter back from the - * mcount call, then the arch should define this as 1. - */ -#ifndef ARCH_SUPPORTS_FTRACE_OPS -#define ARCH_SUPPORTS_FTRACE_OPS 0 -#endif - -/* - * If the arch's mcount caller does not support all of ftrace's - * features, then it must call an indirect function that - * does. Or at least does enough to prevent any unwelcomed side effects. - */ -#if !ARCH_SUPPORTS_FTRACE_OPS -# define FTRACE_FORCE_LIST_FUNC 1 -#else -# define FTRACE_FORCE_LIST_FUNC 0 -#endif - -/* Main tracing buffer and events set up */ -#ifdef CONFIG_TRACING -void trace_init(void); -#else -static inline void trace_init(void) { } -#endif - -struct module; -struct ftrace_hash; - -#ifdef CONFIG_FUNCTION_TRACER - -extern int ftrace_enabled; -extern int -ftrace_enable_sysctl(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos); - -struct ftrace_ops; - -typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip, - struct ftrace_ops *op, struct pt_regs *regs); - -ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops); - -/* - * FTRACE_OPS_FL_* bits denote the state of ftrace_ops struct and are - * set in the flags member. - * CONTROL, SAVE_REGS, SAVE_REGS_IF_SUPPORTED, RECURSION_SAFE, STUB and - * IPMODIFY are a kind of attribute flags which can be set only before - * registering the ftrace_ops, and can not be modified while registered. - * Changing those attribute flags after regsitering ftrace_ops will - * cause unexpected results. - * - * ENABLED - set/unset when ftrace_ops is registered/unregistered - * DYNAMIC - set when ftrace_ops is registered to denote dynamically - * allocated ftrace_ops which need special care - * PER_CPU - set manualy by ftrace_ops user to denote the ftrace_ops - * could be controlled by following calls: - * ftrace_function_local_enable - * ftrace_function_local_disable - * SAVE_REGS - The ftrace_ops wants regs saved at each function called - * and passed to the callback. If this flag is set, but the - * architecture does not support passing regs - * (CONFIG_DYNAMIC_FTRACE_WITH_REGS is not defined), then the - * ftrace_ops will fail to register, unless the next flag - * is set. - * SAVE_REGS_IF_SUPPORTED - This is the same as SAVE_REGS, but if the - * handler can handle an arch that does not save regs - * (the handler tests if regs == NULL), then it can set - * this flag instead. It will not fail registering the ftrace_ops - * but, the regs field will be NULL if the arch does not support - * passing regs to the handler. - * Note, if this flag is set, the SAVE_REGS flag will automatically - * get set upon registering the ftrace_ops, if the arch supports it. - * RECURSION_SAFE - The ftrace_ops can set this to tell the ftrace infrastructure - * that the call back has its own recursion protection. If it does - * not set this, then the ftrace infrastructure will add recursion - * protection for the caller. - * STUB - The ftrace_ops is just a place holder. - * INITIALIZED - The ftrace_ops has already been initialized (first use time - * register_ftrace_function() is called, it will initialized the ops) - * DELETED - The ops are being deleted, do not let them be registered again. - * ADDING - The ops is in the process of being added. - * REMOVING - The ops is in the process of being removed. - * MODIFYING - The ops is in the process of changing its filter functions. - * ALLOC_TRAMP - A dynamic trampoline was allocated by the core code. - * The arch specific code sets this flag when it allocated a - * trampoline. This lets the arch know that it can update the - * trampoline in case the callback function changes. - * The ftrace_ops trampoline can be set by the ftrace users, and - * in such cases the arch must not modify it. Only the arch ftrace - * core code should set this flag. - * IPMODIFY - The ops can modify the IP register. This can only be set with - * SAVE_REGS. If another ops with this flag set is already registered - * for any of the functions that this ops will be registered for, then - * this ops will fail to register or set_filter_ip. - * PID - Is affected by set_ftrace_pid (allows filtering on those pids) - */ -enum { - FTRACE_OPS_FL_ENABLED = 1 << 0, - FTRACE_OPS_FL_DYNAMIC = 1 << 1, - FTRACE_OPS_FL_PER_CPU = 1 << 2, - FTRACE_OPS_FL_SAVE_REGS = 1 << 3, - FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED = 1 << 4, - FTRACE_OPS_FL_RECURSION_SAFE = 1 << 5, - FTRACE_OPS_FL_STUB = 1 << 6, - FTRACE_OPS_FL_INITIALIZED = 1 << 7, - FTRACE_OPS_FL_DELETED = 1 << 8, - FTRACE_OPS_FL_ADDING = 1 << 9, - FTRACE_OPS_FL_REMOVING = 1 << 10, - FTRACE_OPS_FL_MODIFYING = 1 << 11, - FTRACE_OPS_FL_ALLOC_TRAMP = 1 << 12, - FTRACE_OPS_FL_IPMODIFY = 1 << 13, - FTRACE_OPS_FL_PID = 1 << 14, - FTRACE_OPS_FL_RCU = 1 << 15, -}; - -#ifdef CONFIG_DYNAMIC_FTRACE -/* The hash used to know what functions callbacks trace */ -struct ftrace_ops_hash { - struct ftrace_hash *notrace_hash; - struct ftrace_hash *filter_hash; - struct mutex regex_lock; -}; -#endif - -/* - * Note, ftrace_ops can be referenced outside of RCU protection, unless - * the RCU flag is set. If ftrace_ops is allocated and not part of kernel - * core data, the unregistering of it will perform a scheduling on all CPUs - * to make sure that there are no more users. Depending on the load of the - * system that may take a bit of time. - * - * Any private data added must also take care not to be freed and if private - * data is added to a ftrace_ops that is in core code, the user of the - * ftrace_ops must perform a schedule_on_each_cpu() before freeing it. - */ -struct ftrace_ops { - ftrace_func_t func; - struct ftrace_ops *next; - unsigned long flags; - void *private; - ftrace_func_t saved_func; - int __percpu *disabled; -#ifdef CONFIG_DYNAMIC_FTRACE - struct ftrace_ops_hash local_hash; - struct ftrace_ops_hash *func_hash; - struct ftrace_ops_hash old_hash; - unsigned long trampoline; - unsigned long trampoline_size; -#endif -}; - -/* - * Type of the current tracing. - */ -enum ftrace_tracing_type_t { - FTRACE_TYPE_ENTER = 0, /* Hook the call of the function */ - FTRACE_TYPE_RETURN, /* Hook the return of the function */ -}; - -/* Current tracing type, default is FTRACE_TYPE_ENTER */ -extern enum ftrace_tracing_type_t ftrace_tracing_type; - -/* - * The ftrace_ops must be a static and should also - * be read_mostly. These functions do modify read_mostly variables - * so use them sparely. Never free an ftrace_op or modify the - * next pointer after it has been registered. Even after unregistering - * it, the next pointer may still be used internally. - */ -int register_ftrace_function(struct ftrace_ops *ops); -int unregister_ftrace_function(struct ftrace_ops *ops); -void clear_ftrace_function(void); - -/** - * ftrace_function_local_enable - enable ftrace_ops on current cpu - * - * This function enables tracing on current cpu by decreasing - * the per cpu control variable. - * It must be called with preemption disabled and only on ftrace_ops - * registered with FTRACE_OPS_FL_PER_CPU. If called without preemption - * disabled, this_cpu_ptr will complain when CONFIG_DEBUG_PREEMPT is enabled. - */ -static inline void ftrace_function_local_enable(struct ftrace_ops *ops) -{ - if (WARN_ON_ONCE(!(ops->flags & FTRACE_OPS_FL_PER_CPU))) - return; - - (*this_cpu_ptr(ops->disabled))--; -} - -/** - * ftrace_function_local_disable - disable ftrace_ops on current cpu - * - * This function disables tracing on current cpu by increasing - * the per cpu control variable. - * It must be called with preemption disabled and only on ftrace_ops - * registered with FTRACE_OPS_FL_PER_CPU. If called without preemption - * disabled, this_cpu_ptr will complain when CONFIG_DEBUG_PREEMPT is enabled. - */ -static inline void ftrace_function_local_disable(struct ftrace_ops *ops) -{ - if (WARN_ON_ONCE(!(ops->flags & FTRACE_OPS_FL_PER_CPU))) - return; - - (*this_cpu_ptr(ops->disabled))++; -} - -/** - * ftrace_function_local_disabled - returns ftrace_ops disabled value - * on current cpu - * - * This function returns value of ftrace_ops::disabled on current cpu. - * It must be called with preemption disabled and only on ftrace_ops - * registered with FTRACE_OPS_FL_PER_CPU. If called without preemption - * disabled, this_cpu_ptr will complain when CONFIG_DEBUG_PREEMPT is enabled. - */ -static inline int ftrace_function_local_disabled(struct ftrace_ops *ops) -{ - WARN_ON_ONCE(!(ops->flags & FTRACE_OPS_FL_PER_CPU)); - return *this_cpu_ptr(ops->disabled); -} - -extern void ftrace_stub(unsigned long a0, unsigned long a1, - struct ftrace_ops *op, struct pt_regs *regs); - -#else /* !CONFIG_FUNCTION_TRACER */ -/* - * (un)register_ftrace_function must be a macro since the ops parameter - * must not be evaluated. - */ -#define register_ftrace_function(ops) ({ 0; }) -#define unregister_ftrace_function(ops) ({ 0; }) -static inline int ftrace_nr_registered_ops(void) -{ - return 0; -} -static inline void clear_ftrace_function(void) { } -static inline void ftrace_kill(void) { } -#endif /* CONFIG_FUNCTION_TRACER */ - -#ifdef CONFIG_STACK_TRACER - -#define STACK_TRACE_ENTRIES 500 - -struct stack_trace; - -extern unsigned stack_trace_index[]; -extern struct stack_trace stack_trace_max; -extern unsigned long stack_trace_max_size; -extern arch_spinlock_t stack_trace_max_lock; - -extern int stack_tracer_enabled; -void stack_trace_print(void); -int -stack_trace_sysctl(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos); -#endif - -struct ftrace_func_command { - struct list_head list; - char *name; - int (*func)(struct ftrace_hash *hash, - char *func, char *cmd, - char *params, int enable); -}; - -#ifdef CONFIG_DYNAMIC_FTRACE - -int ftrace_arch_code_modify_prepare(void); -int ftrace_arch_code_modify_post_process(void); - -struct dyn_ftrace; - -enum ftrace_bug_type { - FTRACE_BUG_UNKNOWN, - FTRACE_BUG_INIT, - FTRACE_BUG_NOP, - FTRACE_BUG_CALL, - FTRACE_BUG_UPDATE, -}; -extern enum ftrace_bug_type ftrace_bug_type; - -/* - * Archs can set this to point to a variable that holds the value that was - * expected at the call site before calling ftrace_bug(). - */ -extern const void *ftrace_expected; - -void ftrace_bug(int err, struct dyn_ftrace *rec); - -struct seq_file; - -struct ftrace_probe_ops { - void (*func)(unsigned long ip, - unsigned long parent_ip, - void **data); - int (*init)(struct ftrace_probe_ops *ops, - unsigned long ip, void **data); - void (*free)(struct ftrace_probe_ops *ops, - unsigned long ip, void **data); - int (*print)(struct seq_file *m, - unsigned long ip, - struct ftrace_probe_ops *ops, - void *data); -}; - -extern int -register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, - void *data); -extern void -unregister_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops, - void *data); -extern void -unregister_ftrace_function_probe_func(char *glob, struct ftrace_probe_ops *ops); -extern void unregister_ftrace_function_probe_all(char *glob); - -extern int ftrace_text_reserved(const void *start, const void *end); - -extern int ftrace_nr_registered_ops(void); - -bool is_ftrace_trampoline(unsigned long addr); - -/* - * The dyn_ftrace record's flags field is split into two parts. - * the first part which is '0-FTRACE_REF_MAX' is a counter of - * the number of callbacks that have registered the function that - * the dyn_ftrace descriptor represents. - * - * The second part is a mask: - * ENABLED - the function is being traced - * REGS - the record wants the function to save regs - * REGS_EN - the function is set up to save regs. - * IPMODIFY - the record allows for the IP address to be changed. - * DISABLED - the record is not ready to be touched yet - * - * When a new ftrace_ops is registered and wants a function to save - * pt_regs, the rec->flag REGS is set. When the function has been - * set up to save regs, the REG_EN flag is set. Once a function - * starts saving regs it will do so until all ftrace_ops are removed - * from tracing that function. - */ -enum { - FTRACE_FL_ENABLED = (1UL << 31), - FTRACE_FL_REGS = (1UL << 30), - FTRACE_FL_REGS_EN = (1UL << 29), - FTRACE_FL_TRAMP = (1UL << 28), - FTRACE_FL_TRAMP_EN = (1UL << 27), - FTRACE_FL_IPMODIFY = (1UL << 26), - FTRACE_FL_DISABLED = (1UL << 25), -}; - -#define FTRACE_REF_MAX_SHIFT 25 -#define FTRACE_FL_BITS 7 -#define FTRACE_FL_MASKED_BITS ((1UL << FTRACE_FL_BITS) - 1) -#define FTRACE_FL_MASK (FTRACE_FL_MASKED_BITS << FTRACE_REF_MAX_SHIFT) -#define FTRACE_REF_MAX ((1UL << FTRACE_REF_MAX_SHIFT) - 1) - -#define ftrace_rec_count(rec) ((rec)->flags & ~FTRACE_FL_MASK) - -struct dyn_ftrace { - unsigned long ip; /* address of mcount call-site */ - unsigned long flags; - struct dyn_arch_ftrace arch; -}; - -int ftrace_force_update(void); -int ftrace_set_filter_ip(struct ftrace_ops *ops, unsigned long ip, - int remove, int reset); -int ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf, - int len, int reset); -int ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf, - int len, int reset); -void ftrace_set_global_filter(unsigned char *buf, int len, int reset); -void ftrace_set_global_notrace(unsigned char *buf, int len, int reset); -void ftrace_free_filter(struct ftrace_ops *ops); - -int register_ftrace_command(struct ftrace_func_command *cmd); -int unregister_ftrace_command(struct ftrace_func_command *cmd); - -enum { - FTRACE_UPDATE_CALLS = (1 << 0), - FTRACE_DISABLE_CALLS = (1 << 1), - FTRACE_UPDATE_TRACE_FUNC = (1 << 2), - FTRACE_START_FUNC_RET = (1 << 3), - FTRACE_STOP_FUNC_RET = (1 << 4), -}; - -/* - * The FTRACE_UPDATE_* enum is used to pass information back - * from the ftrace_update_record() and ftrace_test_record() - * functions. These are called by the code update routines - * to find out what is to be done for a given function. - * - * IGNORE - The function is already what we want it to be - * MAKE_CALL - Start tracing the function - * MODIFY_CALL - Stop saving regs for the function - * MAKE_NOP - Stop tracing the function - */ -enum { - FTRACE_UPDATE_IGNORE, - FTRACE_UPDATE_MAKE_CALL, - FTRACE_UPDATE_MODIFY_CALL, - FTRACE_UPDATE_MAKE_NOP, -}; - -enum { - FTRACE_ITER_FILTER = (1 << 0), - FTRACE_ITER_NOTRACE = (1 << 1), - FTRACE_ITER_PRINTALL = (1 << 2), - FTRACE_ITER_DO_HASH = (1 << 3), - FTRACE_ITER_HASH = (1 << 4), - FTRACE_ITER_ENABLED = (1 << 5), -}; - -void arch_ftrace_update_code(int command); - -struct ftrace_rec_iter; - -struct ftrace_rec_iter *ftrace_rec_iter_start(void); -struct ftrace_rec_iter *ftrace_rec_iter_next(struct ftrace_rec_iter *iter); -struct dyn_ftrace *ftrace_rec_iter_record(struct ftrace_rec_iter *iter); - -#define for_ftrace_rec_iter(iter) \ - for (iter = ftrace_rec_iter_start(); \ - iter; \ - iter = ftrace_rec_iter_next(iter)) - - -int ftrace_update_record(struct dyn_ftrace *rec, int enable); -int ftrace_test_record(struct dyn_ftrace *rec, int enable); -void ftrace_run_stop_machine(int command); -unsigned long ftrace_location(unsigned long ip); -unsigned long ftrace_location_range(unsigned long start, unsigned long end); -unsigned long ftrace_get_addr_new(struct dyn_ftrace *rec); -unsigned long ftrace_get_addr_curr(struct dyn_ftrace *rec); - -extern ftrace_func_t ftrace_trace_function; - -int ftrace_regex_open(struct ftrace_ops *ops, int flag, - struct inode *inode, struct file *file); -ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf, - size_t cnt, loff_t *ppos); -ssize_t ftrace_notrace_write(struct file *file, const char __user *ubuf, - size_t cnt, loff_t *ppos); -int ftrace_regex_release(struct inode *inode, struct file *file); - -void __init -ftrace_set_early_filter(struct ftrace_ops *ops, char *buf, int enable); - -/* defined in arch */ -extern int ftrace_ip_converted(unsigned long ip); -extern int ftrace_dyn_arch_init(void); -extern void ftrace_replace_code(int enable); -extern int ftrace_update_ftrace_func(ftrace_func_t func); -extern void ftrace_caller(void); -extern void ftrace_regs_caller(void); -extern void ftrace_call(void); -extern void ftrace_regs_call(void); -extern void mcount_call(void); - -void ftrace_modify_all_code(int command); - -#ifndef FTRACE_ADDR -#define FTRACE_ADDR ((unsigned long)ftrace_caller) -#endif - -#ifndef FTRACE_GRAPH_ADDR -#define FTRACE_GRAPH_ADDR ((unsigned long)ftrace_graph_caller) -#endif - -#ifndef FTRACE_REGS_ADDR -#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS -# define FTRACE_REGS_ADDR ((unsigned long)ftrace_regs_caller) -#else -# define FTRACE_REGS_ADDR FTRACE_ADDR -#endif -#endif - -/* - * If an arch would like functions that are only traced - * by the function graph tracer to jump directly to its own - * trampoline, then they can define FTRACE_GRAPH_TRAMP_ADDR - * to be that address to jump to. - */ -#ifndef FTRACE_GRAPH_TRAMP_ADDR -#define FTRACE_GRAPH_TRAMP_ADDR ((unsigned long) 0) -#endif - -#ifdef CONFIG_FUNCTION_GRAPH_TRACER -extern void ftrace_graph_caller(void); -extern int ftrace_enable_ftrace_graph_caller(void); -extern int ftrace_disable_ftrace_graph_caller(void); -#else -static inline int ftrace_enable_ftrace_graph_caller(void) { return 0; } -static inline int ftrace_disable_ftrace_graph_caller(void) { return 0; } -#endif - -/** - * ftrace_make_nop - convert code into nop - * @mod: module structure if called by module load initialization - * @rec: the mcount call site record - * @addr: the address that the call site should be calling - * - * This is a very sensitive operation and great care needs - * to be taken by the arch. The operation should carefully - * read the location, check to see if what is read is indeed - * what we expect it to be, and then on success of the compare, - * it should write to the location. - * - * The code segment at @rec->ip should be a caller to @addr - * - * Return must be: - * 0 on success - * -EFAULT on error reading the location - * -EINVAL on a failed compare of the contents - * -EPERM on error writing to the location - * Any other value will be considered a failure. - */ -extern int ftrace_make_nop(struct module *mod, - struct dyn_ftrace *rec, unsigned long addr); - -/** - * ftrace_make_call - convert a nop call site into a call to addr - * @rec: the mcount call site record - * @addr: the address that the call site should call - * - * This is a very sensitive operation and great care needs - * to be taken by the arch. The operation should carefully - * read the location, check to see if what is read is indeed - * what we expect it to be, and then on success of the compare, - * it should write to the location. - * - * The code segment at @rec->ip should be a nop - * - * Return must be: - * 0 on success - * -EFAULT on error reading the location - * -EINVAL on a failed compare of the contents - * -EPERM on error writing to the location - * Any other value will be considered a failure. - */ -extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr); - -#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS -/** - * ftrace_modify_call - convert from one addr to another (no nop) - * @rec: the mcount call site record - * @old_addr: the address expected to be currently called to - * @addr: the address to change to - * - * This is a very sensitive operation and great care needs - * to be taken by the arch. The operation should carefully - * read the location, check to see if what is read is indeed - * what we expect it to be, and then on success of the compare, - * it should write to the location. - * - * The code segment at @rec->ip should be a caller to @old_addr - * - * Return must be: - * 0 on success - * -EFAULT on error reading the location - * -EINVAL on a failed compare of the contents - * -EPERM on error writing to the location - * Any other value will be considered a failure. - */ -extern int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, - unsigned long addr); -#else -/* Should never be called */ -static inline int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, - unsigned long addr) -{ - return -EINVAL; -} -#endif - -/* May be defined in arch */ -extern int ftrace_arch_read_dyn_info(char *buf, int size); - -extern int skip_trace(unsigned long ip); -extern void ftrace_module_init(struct module *mod); -extern void ftrace_module_enable(struct module *mod); -extern void ftrace_release_mod(struct module *mod); - -extern void ftrace_disable_daemon(void); -extern void ftrace_enable_daemon(void); -#else /* CONFIG_DYNAMIC_FTRACE */ -static inline int skip_trace(unsigned long ip) { return 0; } -static inline int ftrace_force_update(void) { return 0; } -static inline void ftrace_disable_daemon(void) { } -static inline void ftrace_enable_daemon(void) { } -static inline void ftrace_module_init(struct module *mod) { } -static inline void ftrace_module_enable(struct module *mod) { } -static inline void ftrace_release_mod(struct module *mod) { } -static inline __init int register_ftrace_command(struct ftrace_func_command *cmd) -{ - return -EINVAL; -} -static inline __init int unregister_ftrace_command(char *cmd_name) -{ - return -EINVAL; -} -static inline int ftrace_text_reserved(const void *start, const void *end) -{ - return 0; -} -static inline unsigned long ftrace_location(unsigned long ip) -{ - return 0; -} - -/* - * Again users of functions that have ftrace_ops may not - * have them defined when ftrace is not enabled, but these - * functions may still be called. Use a macro instead of inline. - */ -#define ftrace_regex_open(ops, flag, inod, file) ({ -ENODEV; }) -#define ftrace_set_early_filter(ops, buf, enable) do { } while (0) -#define ftrace_set_filter_ip(ops, ip, remove, reset) ({ -ENODEV; }) -#define ftrace_set_filter(ops, buf, len, reset) ({ -ENODEV; }) -#define ftrace_set_notrace(ops, buf, len, reset) ({ -ENODEV; }) -#define ftrace_free_filter(ops) do { } while (0) - -static inline ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf, - size_t cnt, loff_t *ppos) { return -ENODEV; } -static inline ssize_t ftrace_notrace_write(struct file *file, const char __user *ubuf, - size_t cnt, loff_t *ppos) { return -ENODEV; } -static inline int -ftrace_regex_release(struct inode *inode, struct file *file) { return -ENODEV; } - -static inline bool is_ftrace_trampoline(unsigned long addr) -{ - return false; -} -#endif /* CONFIG_DYNAMIC_FTRACE */ - -/* totally disable ftrace - can not re-enable after this */ -void ftrace_kill(void); - -static inline void tracer_disable(void) -{ -#ifdef CONFIG_FUNCTION_TRACER - ftrace_enabled = 0; -#endif -} - -/* - * Ftrace disable/restore without lock. Some synchronization mechanism - * must be used to prevent ftrace_enabled to be changed between - * disable/restore. - */ -static inline int __ftrace_enabled_save(void) -{ -#ifdef CONFIG_FUNCTION_TRACER - int saved_ftrace_enabled = ftrace_enabled; - ftrace_enabled = 0; - return saved_ftrace_enabled; -#else - return 0; -#endif -} - -static inline void __ftrace_enabled_restore(int enabled) -{ -#ifdef CONFIG_FUNCTION_TRACER - ftrace_enabled = enabled; -#endif -} - -/* All archs should have this, but we define it for consistency */ -#ifndef ftrace_return_address0 -# define ftrace_return_address0 __builtin_return_address(0) -#endif - -/* Archs may use other ways for ADDR1 and beyond */ -#ifndef ftrace_return_address -# ifdef CONFIG_FRAME_POINTER -# define ftrace_return_address(n) __builtin_return_address(n) -# else -# define ftrace_return_address(n) 0UL -# endif -#endif - -#define CALLER_ADDR0 ((unsigned long)ftrace_return_address0) -#define CALLER_ADDR1 ((unsigned long)ftrace_return_address(1)) -#define CALLER_ADDR2 ((unsigned long)ftrace_return_address(2)) -#define CALLER_ADDR3 ((unsigned long)ftrace_return_address(3)) -#define CALLER_ADDR4 ((unsigned long)ftrace_return_address(4)) -#define CALLER_ADDR5 ((unsigned long)ftrace_return_address(5)) -#define CALLER_ADDR6 ((unsigned long)ftrace_return_address(6)) - -static inline unsigned long get_lock_parent_ip(void) -{ - unsigned long addr = CALLER_ADDR0; - - if (!in_lock_functions(addr)) - return addr; - addr = CALLER_ADDR1; - if (!in_lock_functions(addr)) - return addr; - return CALLER_ADDR2; -} - -#ifdef CONFIG_IRQSOFF_TRACER - extern void time_hardirqs_on(unsigned long a0, unsigned long a1); - extern void time_hardirqs_off(unsigned long a0, unsigned long a1); -#else - static inline void time_hardirqs_on(unsigned long a0, unsigned long a1) { } - static inline void time_hardirqs_off(unsigned long a0, unsigned long a1) { } -#endif - -#ifdef CONFIG_PREEMPT_TRACER - extern void trace_preempt_on(unsigned long a0, unsigned long a1); - extern void trace_preempt_off(unsigned long a0, unsigned long a1); -#else -/* - * Use defines instead of static inlines because some arches will make code out - * of the CALLER_ADDR, when we really want these to be a real nop. - */ -# define trace_preempt_on(a0, a1) do { } while (0) -# define trace_preempt_off(a0, a1) do { } while (0) -#endif - -#ifdef CONFIG_FTRACE_MCOUNT_RECORD -extern void ftrace_init(void); -#else -static inline void ftrace_init(void) { } -#endif - -/* - * Structure that defines an entry function trace. - * It's already packed but the attribute "packed" is needed - * to remove extra padding at the end. - */ -struct ftrace_graph_ent { - unsigned long func; /* Current function */ - int depth; -} __packed; - -/* - * Structure that defines a return function trace. - * It's already packed but the attribute "packed" is needed - * to remove extra padding at the end. - */ -struct ftrace_graph_ret { - unsigned long func; /* Current function */ - /* Number of functions that overran the depth limit for current task */ - unsigned long overrun; - unsigned long long calltime; - unsigned long long rettime; - int depth; -} __packed; - -/* Type of the callback handlers for tracing function graph*/ -typedef void (*trace_func_graph_ret_t)(struct ftrace_graph_ret *); /* return */ -typedef int (*trace_func_graph_ent_t)(struct ftrace_graph_ent *); /* entry */ - -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - -/* for init task */ -#define INIT_FTRACE_GRAPH .ret_stack = NULL, - -/* - * Stack of return addresses for functions - * of a thread. - * Used in struct thread_info - */ -struct ftrace_ret_stack { - unsigned long ret; - unsigned long func; - unsigned long long calltime; -#ifdef CONFIG_FUNCTION_PROFILER - unsigned long long subtime; -#endif -#ifdef HAVE_FUNCTION_GRAPH_FP_TEST - unsigned long fp; -#endif -#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR - unsigned long *retp; -#endif -}; - -/* - * Primary handler of a function return. - * It relays on ftrace_return_to_handler. - * Defined in entry_32/64.S - */ -extern void return_to_handler(void); - -extern int -ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth, - unsigned long frame_pointer, unsigned long *retp); - -unsigned long ftrace_graph_ret_addr(struct task_struct *task, int *idx, - unsigned long ret, unsigned long *retp); - -/* - * Sometimes we don't want to trace a function with the function - * graph tracer but we want them to keep traced by the usual function - * tracer if the function graph tracer is not configured. - */ -#define __notrace_funcgraph notrace - -#define FTRACE_NOTRACE_DEPTH 65536 -#define FTRACE_RETFUNC_DEPTH 50 -#define FTRACE_RETSTACK_ALLOC_SIZE 32 -extern int register_ftrace_graph(trace_func_graph_ret_t retfunc, - trace_func_graph_ent_t entryfunc); - -extern bool ftrace_graph_is_dead(void); -extern void ftrace_graph_stop(void); - -/* The current handlers in use */ -extern trace_func_graph_ret_t ftrace_graph_return; -extern trace_func_graph_ent_t ftrace_graph_entry; - -extern void unregister_ftrace_graph(void); - -extern void ftrace_graph_init_task(struct task_struct *t); -extern void ftrace_graph_exit_task(struct task_struct *t); -extern void ftrace_graph_init_idle_task(struct task_struct *t, int cpu); - -static inline int task_curr_ret_stack(struct task_struct *t) -{ - return t->curr_ret_stack; -} - -static inline void pause_graph_tracing(void) -{ - atomic_inc(¤t->tracing_graph_pause); -} - -static inline void unpause_graph_tracing(void) -{ - atomic_dec(¤t->tracing_graph_pause); -} -#else /* !CONFIG_FUNCTION_GRAPH_TRACER */ - -#define __notrace_funcgraph -#define INIT_FTRACE_GRAPH - -static inline void ftrace_graph_init_task(struct task_struct *t) { } -static inline void ftrace_graph_exit_task(struct task_struct *t) { } -static inline void ftrace_graph_init_idle_task(struct task_struct *t, int cpu) { } - -static inline int register_ftrace_graph(trace_func_graph_ret_t retfunc, - trace_func_graph_ent_t entryfunc) -{ - return -1; -} -static inline void unregister_ftrace_graph(void) { } - -static inline int task_curr_ret_stack(struct task_struct *tsk) -{ - return -1; -} - -static inline unsigned long -ftrace_graph_ret_addr(struct task_struct *task, int *idx, unsigned long ret, - unsigned long *retp) -{ - return ret; -} - -static inline void pause_graph_tracing(void) { } -static inline void unpause_graph_tracing(void) { } -#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ - -#ifdef CONFIG_TRACING - -/* flags for current->trace */ -enum { - TSK_TRACE_FL_TRACE_BIT = 0, - TSK_TRACE_FL_GRAPH_BIT = 1, -}; -enum { - TSK_TRACE_FL_TRACE = 1 << TSK_TRACE_FL_TRACE_BIT, - TSK_TRACE_FL_GRAPH = 1 << TSK_TRACE_FL_GRAPH_BIT, -}; - -static inline void set_tsk_trace_trace(struct task_struct *tsk) -{ - set_bit(TSK_TRACE_FL_TRACE_BIT, &tsk->trace); -} - -static inline void clear_tsk_trace_trace(struct task_struct *tsk) -{ - clear_bit(TSK_TRACE_FL_TRACE_BIT, &tsk->trace); -} - -static inline int test_tsk_trace_trace(struct task_struct *tsk) -{ - return tsk->trace & TSK_TRACE_FL_TRACE; -} - -static inline void set_tsk_trace_graph(struct task_struct *tsk) -{ - set_bit(TSK_TRACE_FL_GRAPH_BIT, &tsk->trace); -} - -static inline void clear_tsk_trace_graph(struct task_struct *tsk) -{ - clear_bit(TSK_TRACE_FL_GRAPH_BIT, &tsk->trace); -} - -static inline int test_tsk_trace_graph(struct task_struct *tsk) -{ - return tsk->trace & TSK_TRACE_FL_GRAPH; -} - -enum ftrace_dump_mode; - -extern enum ftrace_dump_mode ftrace_dump_on_oops; -extern int tracepoint_printk; - -extern void disable_trace_on_warning(void); -extern int __disable_trace_on_warning; - -#ifdef CONFIG_PREEMPT -#define INIT_TRACE_RECURSION .trace_recursion = 0, -#endif - -#else /* CONFIG_TRACING */ -static inline void disable_trace_on_warning(void) { } -#endif /* CONFIG_TRACING */ - -#ifndef INIT_TRACE_RECURSION -#define INIT_TRACE_RECURSION -#endif - -#ifdef CONFIG_FTRACE_SYSCALLS - -unsigned long arch_syscall_addr(int nr); - -#endif /* CONFIG_FTRACE_SYSCALLS */ - -#endif /* _LINUX_FTRACE_H */ diff --git a/src/linux/include/linux/ftrace_irq.h b/src/linux/include/linux/ftrace_irq.h deleted file mode 100644 index 4ec2c9b..0000000 --- a/src/linux/include/linux/ftrace_irq.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef _LINUX_FTRACE_IRQ_H -#define _LINUX_FTRACE_IRQ_H - - -#ifdef CONFIG_FTRACE_NMI_ENTER -extern void arch_ftrace_nmi_enter(void); -extern void arch_ftrace_nmi_exit(void); -#else -static inline void arch_ftrace_nmi_enter(void) { } -static inline void arch_ftrace_nmi_exit(void) { } -#endif - -#ifdef CONFIG_HWLAT_TRACER -extern bool trace_hwlat_callback_enabled; -extern void trace_hwlat_callback(bool enter); -#endif - -static inline void ftrace_nmi_enter(void) -{ -#ifdef CONFIG_HWLAT_TRACER - if (trace_hwlat_callback_enabled) - trace_hwlat_callback(true); -#endif - arch_ftrace_nmi_enter(); -} - -static inline void ftrace_nmi_exit(void) -{ - arch_ftrace_nmi_exit(); -#ifdef CONFIG_HWLAT_TRACER - if (trace_hwlat_callback_enabled) - trace_hwlat_callback(false); -#endif -} - -#endif /* _LINUX_FTRACE_IRQ_H */ diff --git a/src/linux/include/linux/futex.h b/src/linux/include/linux/futex.h deleted file mode 100644 index 6435f46..0000000 --- a/src/linux/include/linux/futex.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef _LINUX_FUTEX_H -#define _LINUX_FUTEX_H - -#include - -struct inode; -struct mm_struct; -struct task_struct; -union ktime; - -long do_futex(u32 __user *uaddr, int op, u32 val, union ktime *timeout, - u32 __user *uaddr2, u32 val2, u32 val3); - -extern int -handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi); - -/* - * Futexes are matched on equal values of this key. - * The key type depends on whether it's a shared or private mapping. - * Don't rearrange members without looking at hash_futex(). - * - * offset is aligned to a multiple of sizeof(u32) (== 4) by definition. - * We use the two low order bits of offset to tell what is the kind of key : - * 00 : Private process futex (PTHREAD_PROCESS_PRIVATE) - * (no reference on an inode or mm) - * 01 : Shared futex (PTHREAD_PROCESS_SHARED) - * mapped on a file (reference on the underlying inode) - * 10 : Shared futex (PTHREAD_PROCESS_SHARED) - * (but private mapping on an mm, and reference taken on it) -*/ - -#define FUT_OFF_INODE 1 /* We set bit 0 if key has a reference on inode */ -#define FUT_OFF_MMSHARED 2 /* We set bit 1 if key has a reference on mm */ - -union futex_key { - struct { - unsigned long pgoff; - struct inode *inode; - int offset; - } shared; - struct { - unsigned long address; - struct mm_struct *mm; - int offset; - } private; - struct { - unsigned long word; - void *ptr; - int offset; - } both; -}; - -#define FUTEX_KEY_INIT (union futex_key) { .both = { .ptr = NULL } } - -#ifdef CONFIG_FUTEX -extern void exit_robust_list(struct task_struct *curr); -extern void exit_pi_state_list(struct task_struct *curr); -#ifdef CONFIG_HAVE_FUTEX_CMPXCHG -#define futex_cmpxchg_enabled 1 -#else -extern int futex_cmpxchg_enabled; -#endif -#else -static inline void exit_robust_list(struct task_struct *curr) -{ -} -static inline void exit_pi_state_list(struct task_struct *curr) -{ -} -#endif -#endif diff --git a/src/linux/include/linux/fwnode.h b/src/linux/include/linux/fwnode.h deleted file mode 100644 index 8516717..0000000 --- a/src/linux/include/linux/fwnode.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * fwnode.h - Firmware device node object handle type definition. - * - * Copyright (C) 2015, Intel Corporation - * Author: Rafael J. Wysocki - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _LINUX_FWNODE_H_ -#define _LINUX_FWNODE_H_ - -enum fwnode_type { - FWNODE_INVALID = 0, - FWNODE_OF, - FWNODE_ACPI, - FWNODE_ACPI_DATA, - FWNODE_PDATA, - FWNODE_IRQCHIP, -}; - -struct fwnode_handle { - enum fwnode_type type; - struct fwnode_handle *secondary; -}; - -#endif diff --git a/src/linux/include/linux/gcd.h b/src/linux/include/linux/gcd.h deleted file mode 100644 index 69f5e8a..0000000 --- a/src/linux/include/linux/gcd.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _GCD_H -#define _GCD_H - -#include - -unsigned long gcd(unsigned long a, unsigned long b) __attribute_const__; - -#endif /* _GCD_H */ diff --git a/src/linux/include/linux/genetlink.h b/src/linux/include/linux/genetlink.h deleted file mode 100644 index a4c61cb..0000000 --- a/src/linux/include/linux/genetlink.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef __LINUX_GENERIC_NETLINK_H -#define __LINUX_GENERIC_NETLINK_H - -#include - - -/* All generic netlink requests are serialized by a global lock. */ -extern void genl_lock(void); -extern void genl_unlock(void); -#ifdef CONFIG_LOCKDEP -extern bool lockdep_genl_is_held(void); -#endif - -/* for synchronisation between af_netlink and genetlink */ -extern atomic_t genl_sk_destructing_cnt; -extern wait_queue_head_t genl_sk_destructing_waitq; - -/** - * rcu_dereference_genl - rcu_dereference with debug checking - * @p: The pointer to read, prior to dereferencing - * - * Do an rcu_dereference(p), but check caller either holds rcu_read_lock() - * or genl mutex. Note : Please prefer genl_dereference() or rcu_dereference() - */ -#define rcu_dereference_genl(p) \ - rcu_dereference_check(p, lockdep_genl_is_held()) - -/** - * genl_dereference - fetch RCU pointer when updates are prevented by genl mutex - * @p: The pointer to read, prior to dereferencing - * - * Return the value of the specified RCU-protected pointer, but omit - * both the smp_read_barrier_depends() and the ACCESS_ONCE(), because - * caller holds genl mutex. - */ -#define genl_dereference(p) \ - rcu_dereference_protected(p, lockdep_genl_is_held()) - -#define MODULE_ALIAS_GENL_FAMILY(family)\ - MODULE_ALIAS_NET_PF_PROTO_NAME(PF_NETLINK, NETLINK_GENERIC, "-family-" family) - -#endif /* __LINUX_GENERIC_NETLINK_H */ diff --git a/src/linux/include/linux/genhd.h b/src/linux/include/linux/genhd.h deleted file mode 100644 index e0341af..0000000 --- a/src/linux/include/linux/genhd.h +++ /dev/null @@ -1,757 +0,0 @@ -#ifndef _LINUX_GENHD_H -#define _LINUX_GENHD_H - -/* - * genhd.h Copyright (C) 1992 Drew Eckhardt - * Generic hard disk header file by - * Drew Eckhardt - * - * - */ - -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_BLOCK - -#define dev_to_disk(device) container_of((device), struct gendisk, part0.__dev) -#define dev_to_part(device) container_of((device), struct hd_struct, __dev) -#define disk_to_dev(disk) (&(disk)->part0.__dev) -#define part_to_dev(part) (&((part)->__dev)) - -extern struct device_type part_type; -extern struct kobject *block_depr; -extern struct class block_class; - -enum { -/* These three have identical behaviour; use the second one if DOS FDISK gets - confused about extended/logical partitions starting past cylinder 1023. */ - DOS_EXTENDED_PARTITION = 5, - LINUX_EXTENDED_PARTITION = 0x85, - WIN98_EXTENDED_PARTITION = 0x0f, - - SUN_WHOLE_DISK = DOS_EXTENDED_PARTITION, - - LINUX_SWAP_PARTITION = 0x82, - LINUX_DATA_PARTITION = 0x83, - LINUX_LVM_PARTITION = 0x8e, - LINUX_RAID_PARTITION = 0xfd, /* autodetect RAID partition */ - - SOLARIS_X86_PARTITION = LINUX_SWAP_PARTITION, - NEW_SOLARIS_X86_PARTITION = 0xbf, - - DM6_AUX1PARTITION = 0x51, /* no DDO: use xlated geom */ - DM6_AUX3PARTITION = 0x53, /* no DDO: use xlated geom */ - DM6_PARTITION = 0x54, /* has DDO: use xlated geom & offset */ - EZD_PARTITION = 0x55, /* EZ-DRIVE */ - - FREEBSD_PARTITION = 0xa5, /* FreeBSD Partition ID */ - OPENBSD_PARTITION = 0xa6, /* OpenBSD Partition ID */ - NETBSD_PARTITION = 0xa9, /* NetBSD Partition ID */ - BSDI_PARTITION = 0xb7, /* BSDI Partition ID */ - MINIX_PARTITION = 0x81, /* Minix Partition ID */ - UNIXWARE_PARTITION = 0x63, /* Same as GNU_HURD and SCO Unix */ -}; - -#define DISK_MAX_PARTS 256 -#define DISK_NAME_LEN 32 - -#include -#include -#include -#include -#include -#include - -struct partition { - unsigned char boot_ind; /* 0x80 - active */ - unsigned char head; /* starting head */ - unsigned char sector; /* starting sector */ - unsigned char cyl; /* starting cylinder */ - unsigned char sys_ind; /* What partition type */ - unsigned char end_head; /* end head */ - unsigned char end_sector; /* end sector */ - unsigned char end_cyl; /* end cylinder */ - __le32 start_sect; /* starting sector counting from 0 */ - __le32 nr_sects; /* nr of sectors in partition */ -} __attribute__((packed)); - -struct disk_stats { - unsigned long sectors[2]; /* READs and WRITEs */ - unsigned long ios[2]; - unsigned long merges[2]; - unsigned long ticks[2]; - unsigned long io_ticks; - unsigned long time_in_queue; -}; - -#define PARTITION_META_INFO_VOLNAMELTH 64 -/* - * Enough for the string representation of any kind of UUID plus NULL. - * EFI UUID is 36 characters. MSDOS UUID is 11 characters. - */ -#define PARTITION_META_INFO_UUIDLTH (UUID_STRING_LEN + 1) - -struct partition_meta_info { - char uuid[PARTITION_META_INFO_UUIDLTH]; - u8 volname[PARTITION_META_INFO_VOLNAMELTH]; -}; - -struct hd_struct { - sector_t start_sect; - /* - * nr_sects is protected by sequence counter. One might extend a - * partition while IO is happening to it and update of nr_sects - * can be non-atomic on 32bit machines with 64bit sector_t. - */ - sector_t nr_sects; - seqcount_t nr_sects_seq; - sector_t alignment_offset; - unsigned int discard_alignment; - struct device __dev; - struct kobject *holder_dir; - int policy, partno; - struct partition_meta_info *info; -#ifdef CONFIG_FAIL_MAKE_REQUEST - int make_it_fail; -#endif - unsigned long stamp; - atomic_t in_flight[2]; -#ifdef CONFIG_SMP - struct disk_stats __percpu *dkstats; -#else - struct disk_stats dkstats; -#endif - struct percpu_ref ref; - struct rcu_head rcu_head; -}; - -#define GENHD_FL_REMOVABLE 1 -/* 2 is unused */ -#define GENHD_FL_MEDIA_CHANGE_NOTIFY 4 -#define GENHD_FL_CD 8 -#define GENHD_FL_UP 16 -#define GENHD_FL_SUPPRESS_PARTITION_INFO 32 -#define GENHD_FL_EXT_DEVT 64 /* allow extended devt */ -#define GENHD_FL_NATIVE_CAPACITY 128 -#define GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE 256 -#define GENHD_FL_NO_PART_SCAN 512 - -enum { - DISK_EVENT_MEDIA_CHANGE = 1 << 0, /* media changed */ - DISK_EVENT_EJECT_REQUEST = 1 << 1, /* eject requested */ -}; - -#define BLK_SCSI_MAX_CMDS (256) -#define BLK_SCSI_CMD_PER_LONG (BLK_SCSI_MAX_CMDS / (sizeof(long) * 8)) - -struct blk_scsi_cmd_filter { - unsigned long read_ok[BLK_SCSI_CMD_PER_LONG]; - unsigned long write_ok[BLK_SCSI_CMD_PER_LONG]; - struct kobject kobj; -}; - -struct disk_part_tbl { - struct rcu_head rcu_head; - int len; - struct hd_struct __rcu *last_lookup; - struct hd_struct __rcu *part[]; -}; - -struct disk_events; -struct badblocks; - -#if defined(CONFIG_BLK_DEV_INTEGRITY) - -struct blk_integrity { - struct blk_integrity_profile *profile; - unsigned char flags; - unsigned char tuple_size; - unsigned char interval_exp; - unsigned char tag_size; -}; - -#endif /* CONFIG_BLK_DEV_INTEGRITY */ - -struct gendisk { - /* major, first_minor and minors are input parameters only, - * don't use directly. Use disk_devt() and disk_max_parts(). - */ - int major; /* major number of driver */ - int first_minor; - int minors; /* maximum number of minors, =1 for - * disks that can't be partitioned. */ - - char disk_name[DISK_NAME_LEN]; /* name of major driver */ - char *(*devnode)(struct gendisk *gd, umode_t *mode); - - unsigned int events; /* supported events */ - unsigned int async_events; /* async events, subset of all */ - - /* Array of pointers to partitions indexed by partno. - * Protected with matching bdev lock but stat and other - * non-critical accesses use RCU. Always access through - * helpers. - */ - struct disk_part_tbl __rcu *part_tbl; - struct hd_struct part0; - - const struct block_device_operations *fops; - struct request_queue *queue; - void *private_data; - - int flags; - struct kobject *slave_dir; - - struct timer_rand_state *random; - atomic_t sync_io; /* RAID */ - struct disk_events *ev; -#ifdef CONFIG_BLK_DEV_INTEGRITY - struct kobject integrity_kobj; -#endif /* CONFIG_BLK_DEV_INTEGRITY */ - int node_id; - struct badblocks *bb; -}; - -static inline struct gendisk *part_to_disk(struct hd_struct *part) -{ - if (likely(part)) { - if (part->partno) - return dev_to_disk(part_to_dev(part)->parent); - else - return dev_to_disk(part_to_dev(part)); - } - return NULL; -} - -static inline int blk_part_pack_uuid(const u8 *uuid_str, u8 *to) -{ - uuid_be_to_bin(uuid_str, (uuid_be *)to); - return 0; -} - -static inline int disk_max_parts(struct gendisk *disk) -{ - if (disk->flags & GENHD_FL_EXT_DEVT) - return DISK_MAX_PARTS; - return disk->minors; -} - -static inline bool disk_part_scan_enabled(struct gendisk *disk) -{ - return disk_max_parts(disk) > 1 && - !(disk->flags & GENHD_FL_NO_PART_SCAN); -} - -static inline dev_t disk_devt(struct gendisk *disk) -{ - return disk_to_dev(disk)->devt; -} - -static inline dev_t part_devt(struct hd_struct *part) -{ - return part_to_dev(part)->devt; -} - -extern struct hd_struct *disk_get_part(struct gendisk *disk, int partno); - -static inline void disk_put_part(struct hd_struct *part) -{ - if (likely(part)) - put_device(part_to_dev(part)); -} - -/* - * Smarter partition iterator without context limits. - */ -#define DISK_PITER_REVERSE (1 << 0) /* iterate in the reverse direction */ -#define DISK_PITER_INCL_EMPTY (1 << 1) /* include 0-sized parts */ -#define DISK_PITER_INCL_PART0 (1 << 2) /* include partition 0 */ -#define DISK_PITER_INCL_EMPTY_PART0 (1 << 3) /* include empty partition 0 */ - -struct disk_part_iter { - struct gendisk *disk; - struct hd_struct *part; - int idx; - unsigned int flags; -}; - -extern void disk_part_iter_init(struct disk_part_iter *piter, - struct gendisk *disk, unsigned int flags); -extern struct hd_struct *disk_part_iter_next(struct disk_part_iter *piter); -extern void disk_part_iter_exit(struct disk_part_iter *piter); - -extern struct hd_struct *disk_map_sector_rcu(struct gendisk *disk, - sector_t sector); - -/* - * Macros to operate on percpu disk statistics: - * - * {disk|part|all}_stat_{add|sub|inc|dec}() modify the stat counters - * and should be called between disk_stat_lock() and - * disk_stat_unlock(). - * - * part_stat_read() can be called at any time. - * - * part_stat_{add|set_all}() and {init|free}_part_stats are for - * internal use only. - */ -#ifdef CONFIG_SMP -#define part_stat_lock() ({ rcu_read_lock(); get_cpu(); }) -#define part_stat_unlock() do { put_cpu(); rcu_read_unlock(); } while (0) - -#define __part_stat_add(cpu, part, field, addnd) \ - (per_cpu_ptr((part)->dkstats, (cpu))->field += (addnd)) - -#define part_stat_read(part, field) \ -({ \ - typeof((part)->dkstats->field) res = 0; \ - unsigned int _cpu; \ - for_each_possible_cpu(_cpu) \ - res += per_cpu_ptr((part)->dkstats, _cpu)->field; \ - res; \ -}) - -static inline void part_stat_set_all(struct hd_struct *part, int value) -{ - int i; - - for_each_possible_cpu(i) - memset(per_cpu_ptr(part->dkstats, i), value, - sizeof(struct disk_stats)); -} - -static inline int init_part_stats(struct hd_struct *part) -{ - part->dkstats = alloc_percpu(struct disk_stats); - if (!part->dkstats) - return 0; - return 1; -} - -static inline void free_part_stats(struct hd_struct *part) -{ - free_percpu(part->dkstats); -} - -#else /* !CONFIG_SMP */ -#define part_stat_lock() ({ rcu_read_lock(); 0; }) -#define part_stat_unlock() rcu_read_unlock() - -#define __part_stat_add(cpu, part, field, addnd) \ - ((part)->dkstats.field += addnd) - -#define part_stat_read(part, field) ((part)->dkstats.field) - -static inline void part_stat_set_all(struct hd_struct *part, int value) -{ - memset(&part->dkstats, value, sizeof(struct disk_stats)); -} - -static inline int init_part_stats(struct hd_struct *part) -{ - return 1; -} - -static inline void free_part_stats(struct hd_struct *part) -{ -} - -#endif /* CONFIG_SMP */ - -#define part_stat_add(cpu, part, field, addnd) do { \ - __part_stat_add((cpu), (part), field, addnd); \ - if ((part)->partno) \ - __part_stat_add((cpu), &part_to_disk((part))->part0, \ - field, addnd); \ -} while (0) - -#define part_stat_dec(cpu, gendiskp, field) \ - part_stat_add(cpu, gendiskp, field, -1) -#define part_stat_inc(cpu, gendiskp, field) \ - part_stat_add(cpu, gendiskp, field, 1) -#define part_stat_sub(cpu, gendiskp, field, subnd) \ - part_stat_add(cpu, gendiskp, field, -subnd) - -static inline void part_inc_in_flight(struct hd_struct *part, int rw) -{ - atomic_inc(&part->in_flight[rw]); - if (part->partno) - atomic_inc(&part_to_disk(part)->part0.in_flight[rw]); -} - -static inline void part_dec_in_flight(struct hd_struct *part, int rw) -{ - atomic_dec(&part->in_flight[rw]); - if (part->partno) - atomic_dec(&part_to_disk(part)->part0.in_flight[rw]); -} - -static inline int part_in_flight(struct hd_struct *part) -{ - return atomic_read(&part->in_flight[0]) + atomic_read(&part->in_flight[1]); -} - -static inline struct partition_meta_info *alloc_part_info(struct gendisk *disk) -{ - if (disk) - return kzalloc_node(sizeof(struct partition_meta_info), - GFP_KERNEL, disk->node_id); - return kzalloc(sizeof(struct partition_meta_info), GFP_KERNEL); -} - -static inline void free_part_info(struct hd_struct *part) -{ - kfree(part->info); -} - -/* block/blk-core.c */ -extern void part_round_stats(int cpu, struct hd_struct *part); - -/* block/genhd.c */ -extern void device_add_disk(struct device *parent, struct gendisk *disk); -static inline void add_disk(struct gendisk *disk) -{ - device_add_disk(NULL, disk); -} - -extern void del_gendisk(struct gendisk *gp); -extern struct gendisk *get_gendisk(dev_t dev, int *partno); -extern struct block_device *bdget_disk(struct gendisk *disk, int partno); - -extern void set_device_ro(struct block_device *bdev, int flag); -extern void set_disk_ro(struct gendisk *disk, int flag); - -static inline int get_disk_ro(struct gendisk *disk) -{ - return disk->part0.policy; -} - -extern void disk_block_events(struct gendisk *disk); -extern void disk_unblock_events(struct gendisk *disk); -extern void disk_flush_events(struct gendisk *disk, unsigned int mask); -extern unsigned int disk_clear_events(struct gendisk *disk, unsigned int mask); - -/* drivers/char/random.c */ -extern void add_disk_randomness(struct gendisk *disk) __latent_entropy; -extern void rand_initialize_disk(struct gendisk *disk); - -static inline sector_t get_start_sect(struct block_device *bdev) -{ - return bdev->bd_part->start_sect; -} -static inline sector_t get_capacity(struct gendisk *disk) -{ - return disk->part0.nr_sects; -} -static inline void set_capacity(struct gendisk *disk, sector_t size) -{ - disk->part0.nr_sects = size; -} - -#ifdef CONFIG_SOLARIS_X86_PARTITION - -#define SOLARIS_X86_NUMSLICE 16 -#define SOLARIS_X86_VTOC_SANE (0x600DDEEEUL) - -struct solaris_x86_slice { - __le16 s_tag; /* ID tag of partition */ - __le16 s_flag; /* permission flags */ - __le32 s_start; /* start sector no of partition */ - __le32 s_size; /* # of blocks in partition */ -}; - -struct solaris_x86_vtoc { - unsigned int v_bootinfo[3]; /* info needed by mboot (unsupported) */ - __le32 v_sanity; /* to verify vtoc sanity */ - __le32 v_version; /* layout version */ - char v_volume[8]; /* volume name */ - __le16 v_sectorsz; /* sector size in bytes */ - __le16 v_nparts; /* number of partitions */ - unsigned int v_reserved[10]; /* free space */ - struct solaris_x86_slice - v_slice[SOLARIS_X86_NUMSLICE]; /* slice headers */ - unsigned int timestamp[SOLARIS_X86_NUMSLICE]; /* timestamp (unsupported) */ - char v_asciilabel[128]; /* for compatibility */ -}; - -#endif /* CONFIG_SOLARIS_X86_PARTITION */ - -#ifdef CONFIG_BSD_DISKLABEL -/* - * BSD disklabel support by Yossi Gottlieb - * updated by Marc Espie - */ - -/* check against BSD src/sys/sys/disklabel.h for consistency */ - -#define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */ -#define BSD_MAXPARTITIONS 16 -#define OPENBSD_MAXPARTITIONS 16 -#define BSD_FS_UNUSED 0 /* disklabel unused partition entry ID */ -struct bsd_disklabel { - __le32 d_magic; /* the magic number */ - __s16 d_type; /* drive type */ - __s16 d_subtype; /* controller/d_type specific */ - char d_typename[16]; /* type name, e.g. "eagle" */ - char d_packname[16]; /* pack identifier */ - __u32 d_secsize; /* # of bytes per sector */ - __u32 d_nsectors; /* # of data sectors per track */ - __u32 d_ntracks; /* # of tracks per cylinder */ - __u32 d_ncylinders; /* # of data cylinders per unit */ - __u32 d_secpercyl; /* # of data sectors per cylinder */ - __u32 d_secperunit; /* # of data sectors per unit */ - __u16 d_sparespertrack; /* # of spare sectors per track */ - __u16 d_sparespercyl; /* # of spare sectors per cylinder */ - __u32 d_acylinders; /* # of alt. cylinders per unit */ - __u16 d_rpm; /* rotational speed */ - __u16 d_interleave; /* hardware sector interleave */ - __u16 d_trackskew; /* sector 0 skew, per track */ - __u16 d_cylskew; /* sector 0 skew, per cylinder */ - __u32 d_headswitch; /* head switch time, usec */ - __u32 d_trkseek; /* track-to-track seek, usec */ - __u32 d_flags; /* generic flags */ -#define NDDATA 5 - __u32 d_drivedata[NDDATA]; /* drive-type specific information */ -#define NSPARE 5 - __u32 d_spare[NSPARE]; /* reserved for future use */ - __le32 d_magic2; /* the magic number (again) */ - __le16 d_checksum; /* xor of data incl. partitions */ - - /* filesystem and partition information: */ - __le16 d_npartitions; /* number of partitions in following */ - __le32 d_bbsize; /* size of boot area at sn0, bytes */ - __le32 d_sbsize; /* max size of fs superblock, bytes */ - struct bsd_partition { /* the partition table */ - __le32 p_size; /* number of sectors in partition */ - __le32 p_offset; /* starting sector */ - __le32 p_fsize; /* filesystem basic fragment size */ - __u8 p_fstype; /* filesystem type, see below */ - __u8 p_frag; /* filesystem fragments per block */ - __le16 p_cpg; /* filesystem cylinders per group */ - } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */ -}; - -#endif /* CONFIG_BSD_DISKLABEL */ - -#ifdef CONFIG_UNIXWARE_DISKLABEL -/* - * Unixware slices support by Andrzej Krzysztofowicz - * and Krzysztof G. Baranowski - */ - -#define UNIXWARE_DISKMAGIC (0xCA5E600DUL) /* The disk magic number */ -#define UNIXWARE_DISKMAGIC2 (0x600DDEEEUL) /* The slice table magic nr */ -#define UNIXWARE_NUMSLICE 16 -#define UNIXWARE_FS_UNUSED 0 /* Unused slice entry ID */ - -struct unixware_slice { - __le16 s_label; /* label */ - __le16 s_flags; /* permission flags */ - __le32 start_sect; /* starting sector */ - __le32 nr_sects; /* number of sectors in slice */ -}; - -struct unixware_disklabel { - __le32 d_type; /* drive type */ - __le32 d_magic; /* the magic number */ - __le32 d_version; /* version number */ - char d_serial[12]; /* serial number of the device */ - __le32 d_ncylinders; /* # of data cylinders per device */ - __le32 d_ntracks; /* # of tracks per cylinder */ - __le32 d_nsectors; /* # of data sectors per track */ - __le32 d_secsize; /* # of bytes per sector */ - __le32 d_part_start; /* # of first sector of this partition */ - __le32 d_unknown1[12]; /* ? */ - __le32 d_alt_tbl; /* byte offset of alternate table */ - __le32 d_alt_len; /* byte length of alternate table */ - __le32 d_phys_cyl; /* # of physical cylinders per device */ - __le32 d_phys_trk; /* # of physical tracks per cylinder */ - __le32 d_phys_sec; /* # of physical sectors per track */ - __le32 d_phys_bytes; /* # of physical bytes per sector */ - __le32 d_unknown2; /* ? */ - __le32 d_unknown3; /* ? */ - __le32 d_pad[8]; /* pad */ - - struct unixware_vtoc { - __le32 v_magic; /* the magic number */ - __le32 v_version; /* version number */ - char v_name[8]; /* volume name */ - __le16 v_nslices; /* # of slices */ - __le16 v_unknown1; /* ? */ - __le32 v_reserved[10]; /* reserved */ - struct unixware_slice - v_slice[UNIXWARE_NUMSLICE]; /* slice headers */ - } vtoc; - -}; /* 408 */ - -#endif /* CONFIG_UNIXWARE_DISKLABEL */ - -#ifdef CONFIG_MINIX_SUBPARTITION -# define MINIX_NR_SUBPARTITIONS 4 -#endif /* CONFIG_MINIX_SUBPARTITION */ - -#define ADDPART_FLAG_NONE 0 -#define ADDPART_FLAG_RAID 1 -#define ADDPART_FLAG_WHOLEDISK 2 - -extern int blk_alloc_devt(struct hd_struct *part, dev_t *devt); -extern void blk_free_devt(dev_t devt); -extern dev_t blk_lookup_devt(const char *name, int partno); -extern char *disk_name (struct gendisk *hd, int partno, char *buf); - -extern int disk_expand_part_tbl(struct gendisk *disk, int target); -extern int rescan_partitions(struct gendisk *disk, struct block_device *bdev); -extern int invalidate_partitions(struct gendisk *disk, struct block_device *bdev); -extern struct hd_struct * __must_check add_partition(struct gendisk *disk, - int partno, sector_t start, - sector_t len, int flags, - struct partition_meta_info - *info); -extern void __delete_partition(struct percpu_ref *); -extern void delete_partition(struct gendisk *, int); -extern void printk_all_partitions(void); - -extern struct gendisk *alloc_disk_node(int minors, int node_id); -extern struct gendisk *alloc_disk(int minors); -extern struct kobject *get_disk(struct gendisk *disk); -extern void put_disk(struct gendisk *disk); -extern void blk_register_region(dev_t devt, unsigned long range, - struct module *module, - struct kobject *(*probe)(dev_t, int *, void *), - int (*lock)(dev_t, void *), - void *data); -extern void blk_unregister_region(dev_t devt, unsigned long range); - -extern ssize_t part_size_show(struct device *dev, - struct device_attribute *attr, char *buf); -extern ssize_t part_stat_show(struct device *dev, - struct device_attribute *attr, char *buf); -extern ssize_t part_inflight_show(struct device *dev, - struct device_attribute *attr, char *buf); -#ifdef CONFIG_FAIL_MAKE_REQUEST -extern ssize_t part_fail_show(struct device *dev, - struct device_attribute *attr, char *buf); -extern ssize_t part_fail_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count); -#endif /* CONFIG_FAIL_MAKE_REQUEST */ - -static inline int hd_ref_init(struct hd_struct *part) -{ - if (percpu_ref_init(&part->ref, __delete_partition, 0, - GFP_KERNEL)) - return -ENOMEM; - return 0; -} - -static inline void hd_struct_get(struct hd_struct *part) -{ - percpu_ref_get(&part->ref); -} - -static inline int hd_struct_try_get(struct hd_struct *part) -{ - return percpu_ref_tryget_live(&part->ref); -} - -static inline void hd_struct_put(struct hd_struct *part) -{ - percpu_ref_put(&part->ref); -} - -static inline void hd_struct_kill(struct hd_struct *part) -{ - percpu_ref_kill(&part->ref); -} - -static inline void hd_free_part(struct hd_struct *part) -{ - free_part_stats(part); - free_part_info(part); - percpu_ref_exit(&part->ref); -} - -/* - * Any access of part->nr_sects which is not protected by partition - * bd_mutex or gendisk bdev bd_mutex, should be done using this - * accessor function. - * - * Code written along the lines of i_size_read() and i_size_write(). - * CONFIG_PREEMPT case optimizes the case of UP kernel with preemption - * on. - */ -static inline sector_t part_nr_sects_read(struct hd_struct *part) -{ -#if BITS_PER_LONG==32 && defined(CONFIG_LBDAF) && defined(CONFIG_SMP) - sector_t nr_sects; - unsigned seq; - do { - seq = read_seqcount_begin(&part->nr_sects_seq); - nr_sects = part->nr_sects; - } while (read_seqcount_retry(&part->nr_sects_seq, seq)); - return nr_sects; -#elif BITS_PER_LONG==32 && defined(CONFIG_LBDAF) && defined(CONFIG_PREEMPT) - sector_t nr_sects; - - preempt_disable(); - nr_sects = part->nr_sects; - preempt_enable(); - return nr_sects; -#else - return part->nr_sects; -#endif -} - -/* - * Should be called with mutex lock held (typically bd_mutex) of partition - * to provide mutual exlusion among writers otherwise seqcount might be - * left in wrong state leaving the readers spinning infinitely. - */ -static inline void part_nr_sects_write(struct hd_struct *part, sector_t size) -{ -#if BITS_PER_LONG==32 && defined(CONFIG_LBDAF) && defined(CONFIG_SMP) - write_seqcount_begin(&part->nr_sects_seq); - part->nr_sects = size; - write_seqcount_end(&part->nr_sects_seq); -#elif BITS_PER_LONG==32 && defined(CONFIG_LBDAF) && defined(CONFIG_PREEMPT) - preempt_disable(); - part->nr_sects = size; - preempt_enable(); -#else - part->nr_sects = size; -#endif -} - -#if defined(CONFIG_BLK_DEV_INTEGRITY) -extern void blk_integrity_add(struct gendisk *); -extern void blk_integrity_del(struct gendisk *); -extern void blk_integrity_revalidate(struct gendisk *); -#else /* CONFIG_BLK_DEV_INTEGRITY */ -static inline void blk_integrity_add(struct gendisk *disk) { } -static inline void blk_integrity_del(struct gendisk *disk) { } -static inline void blk_integrity_revalidate(struct gendisk *disk) { } -#endif /* CONFIG_BLK_DEV_INTEGRITY */ - -#else /* CONFIG_BLOCK */ - -static inline void printk_all_partitions(void) { } - -static inline dev_t blk_lookup_devt(const char *name, int partno) -{ - dev_t devt = MKDEV(0, 0); - return devt; -} - -static inline int blk_part_pack_uuid(const u8 *uuid_str, u8 *to) -{ - return -EINVAL; -} -#endif /* CONFIG_BLOCK */ - -#endif /* _LINUX_GENHD_H */ diff --git a/src/linux/include/linux/getcpu.h b/src/linux/include/linux/getcpu.h deleted file mode 100644 index c7372d7..0000000 --- a/src/linux/include/linux/getcpu.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _LINUX_GETCPU_H -#define _LINUX_GETCPU_H 1 - -/* Cache for getcpu() to speed it up. Results might be a short time - out of date, but will be faster. - - User programs should not refer to the contents of this structure. - I repeat they should not refer to it. If they do they will break - in future kernels. - - It is only a private cache for vgetcpu(). It will change in future kernels. - The user program must store this information per thread (__thread) - If you want 100% accurate information pass NULL instead. */ -struct getcpu_cache { - unsigned long blob[128 / sizeof(long)]; -}; - -#endif diff --git a/src/linux/include/linux/gfp.h b/src/linux/include/linux/gfp.h deleted file mode 100644 index f8041f9..0000000 --- a/src/linux/include/linux/gfp.h +++ /dev/null @@ -1,559 +0,0 @@ -#ifndef __LINUX_GFP_H -#define __LINUX_GFP_H - -#include -#include -#include -#include -#include - -struct vm_area_struct; - -/* - * In case of changes, please don't forget to update - * include/trace/events/mmflags.h and tools/perf/builtin-kmem.c - */ - -/* Plain integer GFP bitmasks. Do not use this directly. */ -#define ___GFP_DMA 0x01u -#define ___GFP_HIGHMEM 0x02u -#define ___GFP_DMA32 0x04u -#define ___GFP_MOVABLE 0x08u -#define ___GFP_RECLAIMABLE 0x10u -#define ___GFP_HIGH 0x20u -#define ___GFP_IO 0x40u -#define ___GFP_FS 0x80u -#define ___GFP_COLD 0x100u -#define ___GFP_NOWARN 0x200u -#define ___GFP_REPEAT 0x400u -#define ___GFP_NOFAIL 0x800u -#define ___GFP_NORETRY 0x1000u -#define ___GFP_MEMALLOC 0x2000u -#define ___GFP_COMP 0x4000u -#define ___GFP_ZERO 0x8000u -#define ___GFP_NOMEMALLOC 0x10000u -#define ___GFP_HARDWALL 0x20000u -#define ___GFP_THISNODE 0x40000u -#define ___GFP_ATOMIC 0x80000u -#define ___GFP_ACCOUNT 0x100000u -#define ___GFP_NOTRACK 0x200000u -#define ___GFP_DIRECT_RECLAIM 0x400000u -#define ___GFP_OTHER_NODE 0x800000u -#define ___GFP_WRITE 0x1000000u -#define ___GFP_KSWAPD_RECLAIM 0x2000000u -/* If the above are modified, __GFP_BITS_SHIFT may need updating */ - -/* - * Physical address zone modifiers (see linux/mmzone.h - low four bits) - * - * Do not put any conditional on these. If necessary modify the definitions - * without the underscores and use them consistently. The definitions here may - * be used in bit comparisons. - */ -#define __GFP_DMA ((__force gfp_t)___GFP_DMA) -#define __GFP_HIGHMEM ((__force gfp_t)___GFP_HIGHMEM) -#define __GFP_DMA32 ((__force gfp_t)___GFP_DMA32) -#define __GFP_MOVABLE ((__force gfp_t)___GFP_MOVABLE) /* ZONE_MOVABLE allowed */ -#define GFP_ZONEMASK (__GFP_DMA|__GFP_HIGHMEM|__GFP_DMA32|__GFP_MOVABLE) - -/* - * Page mobility and placement hints - * - * These flags provide hints about how mobile the page is. Pages with similar - * mobility are placed within the same pageblocks to minimise problems due - * to external fragmentation. - * - * __GFP_MOVABLE (also a zone modifier) indicates that the page can be - * moved by page migration during memory compaction or can be reclaimed. - * - * __GFP_RECLAIMABLE is used for slab allocations that specify - * SLAB_RECLAIM_ACCOUNT and whose pages can be freed via shrinkers. - * - * __GFP_WRITE indicates the caller intends to dirty the page. Where possible, - * these pages will be spread between local zones to avoid all the dirty - * pages being in one zone (fair zone allocation policy). - * - * __GFP_HARDWALL enforces the cpuset memory allocation policy. - * - * __GFP_THISNODE forces the allocation to be satisified from the requested - * node with no fallbacks or placement policy enforcements. - * - * __GFP_ACCOUNT causes the allocation to be accounted to kmemcg. - */ -#define __GFP_RECLAIMABLE ((__force gfp_t)___GFP_RECLAIMABLE) -#define __GFP_WRITE ((__force gfp_t)___GFP_WRITE) -#define __GFP_HARDWALL ((__force gfp_t)___GFP_HARDWALL) -#define __GFP_THISNODE ((__force gfp_t)___GFP_THISNODE) -#define __GFP_ACCOUNT ((__force gfp_t)___GFP_ACCOUNT) - -/* - * Watermark modifiers -- controls access to emergency reserves - * - * __GFP_HIGH indicates that the caller is high-priority and that granting - * the request is necessary before the system can make forward progress. - * For example, creating an IO context to clean pages. - * - * __GFP_ATOMIC indicates that the caller cannot reclaim or sleep and is - * high priority. Users are typically interrupt handlers. This may be - * used in conjunction with __GFP_HIGH - * - * __GFP_MEMALLOC allows access to all memory. This should only be used when - * the caller guarantees the allocation will allow more memory to be freed - * very shortly e.g. process exiting or swapping. Users either should - * be the MM or co-ordinating closely with the VM (e.g. swap over NFS). - * - * __GFP_NOMEMALLOC is used to explicitly forbid access to emergency reserves. - * This takes precedence over the __GFP_MEMALLOC flag if both are set. - */ -#define __GFP_ATOMIC ((__force gfp_t)___GFP_ATOMIC) -#define __GFP_HIGH ((__force gfp_t)___GFP_HIGH) -#define __GFP_MEMALLOC ((__force gfp_t)___GFP_MEMALLOC) -#define __GFP_NOMEMALLOC ((__force gfp_t)___GFP_NOMEMALLOC) - -/* - * Reclaim modifiers - * - * __GFP_IO can start physical IO. - * - * __GFP_FS can call down to the low-level FS. Clearing the flag avoids the - * allocator recursing into the filesystem which might already be holding - * locks. - * - * __GFP_DIRECT_RECLAIM indicates that the caller may enter direct reclaim. - * This flag can be cleared to avoid unnecessary delays when a fallback - * option is available. - * - * __GFP_KSWAPD_RECLAIM indicates that the caller wants to wake kswapd when - * the low watermark is reached and have it reclaim pages until the high - * watermark is reached. A caller may wish to clear this flag when fallback - * options are available and the reclaim is likely to disrupt the system. The - * canonical example is THP allocation where a fallback is cheap but - * reclaim/compaction may cause indirect stalls. - * - * __GFP_RECLAIM is shorthand to allow/forbid both direct and kswapd reclaim. - * - * __GFP_REPEAT: Try hard to allocate the memory, but the allocation attempt - * _might_ fail. This depends upon the particular VM implementation. - * - * __GFP_NOFAIL: The VM implementation _must_ retry infinitely: the caller - * cannot handle allocation failures. New users should be evaluated carefully - * (and the flag should be used only when there is no reasonable failure - * policy) but it is definitely preferable to use the flag rather than - * opencode endless loop around allocator. - * - * __GFP_NORETRY: The VM implementation must not retry indefinitely and will - * return NULL when direct reclaim and memory compaction have failed to allow - * the allocation to succeed. The OOM killer is not called with the current - * implementation. - */ -#define __GFP_IO ((__force gfp_t)___GFP_IO) -#define __GFP_FS ((__force gfp_t)___GFP_FS) -#define __GFP_DIRECT_RECLAIM ((__force gfp_t)___GFP_DIRECT_RECLAIM) /* Caller can reclaim */ -#define __GFP_KSWAPD_RECLAIM ((__force gfp_t)___GFP_KSWAPD_RECLAIM) /* kswapd can wake */ -#define __GFP_RECLAIM ((__force gfp_t)(___GFP_DIRECT_RECLAIM|___GFP_KSWAPD_RECLAIM)) -#define __GFP_REPEAT ((__force gfp_t)___GFP_REPEAT) -#define __GFP_NOFAIL ((__force gfp_t)___GFP_NOFAIL) -#define __GFP_NORETRY ((__force gfp_t)___GFP_NORETRY) - -/* - * Action modifiers - * - * __GFP_COLD indicates that the caller does not expect to be used in the near - * future. Where possible, a cache-cold page will be returned. - * - * __GFP_NOWARN suppresses allocation failure reports. - * - * __GFP_COMP address compound page metadata. - * - * __GFP_ZERO returns a zeroed page on success. - * - * __GFP_NOTRACK avoids tracking with kmemcheck. - * - * __GFP_NOTRACK_FALSE_POSITIVE is an alias of __GFP_NOTRACK. It's a means of - * distinguishing in the source between false positives and allocations that - * cannot be supported (e.g. page tables). - * - * __GFP_OTHER_NODE is for allocations that are on a remote node but that - * should not be accounted for as a remote allocation in vmstat. A - * typical user would be khugepaged collapsing a huge page on a remote - * node. - */ -#define __GFP_COLD ((__force gfp_t)___GFP_COLD) -#define __GFP_NOWARN ((__force gfp_t)___GFP_NOWARN) -#define __GFP_COMP ((__force gfp_t)___GFP_COMP) -#define __GFP_ZERO ((__force gfp_t)___GFP_ZERO) -#define __GFP_NOTRACK ((__force gfp_t)___GFP_NOTRACK) -#define __GFP_NOTRACK_FALSE_POSITIVE (__GFP_NOTRACK) -#define __GFP_OTHER_NODE ((__force gfp_t)___GFP_OTHER_NODE) - -/* Room for N __GFP_FOO bits */ -#define __GFP_BITS_SHIFT 26 -#define __GFP_BITS_MASK ((__force gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) - -/* - * Useful GFP flag combinations that are commonly used. It is recommended - * that subsystems start with one of these combinations and then set/clear - * __GFP_FOO flags as necessary. - * - * GFP_ATOMIC users can not sleep and need the allocation to succeed. A lower - * watermark is applied to allow access to "atomic reserves" - * - * GFP_KERNEL is typical for kernel-internal allocations. The caller requires - * ZONE_NORMAL or a lower zone for direct access but can direct reclaim. - * - * GFP_KERNEL_ACCOUNT is the same as GFP_KERNEL, except the allocation is - * accounted to kmemcg. - * - * GFP_NOWAIT is for kernel allocations that should not stall for direct - * reclaim, start physical IO or use any filesystem callback. - * - * GFP_NOIO will use direct reclaim to discard clean pages or slab pages - * that do not require the starting of any physical IO. - * - * GFP_NOFS will use direct reclaim but will not use any filesystem interfaces. - * - * GFP_USER is for userspace allocations that also need to be directly - * accessibly by the kernel or hardware. It is typically used by hardware - * for buffers that are mapped to userspace (e.g. graphics) that hardware - * still must DMA to. cpuset limits are enforced for these allocations. - * - * GFP_DMA exists for historical reasons and should be avoided where possible. - * The flags indicates that the caller requires that the lowest zone be - * used (ZONE_DMA or 16M on x86-64). Ideally, this would be removed but - * it would require careful auditing as some users really require it and - * others use the flag to avoid lowmem reserves in ZONE_DMA and treat the - * lowest zone as a type of emergency reserve. - * - * GFP_DMA32 is similar to GFP_DMA except that the caller requires a 32-bit - * address. - * - * GFP_HIGHUSER is for userspace allocations that may be mapped to userspace, - * do not need to be directly accessible by the kernel but that cannot - * move once in use. An example may be a hardware allocation that maps - * data directly into userspace but has no addressing limitations. - * - * GFP_HIGHUSER_MOVABLE is for userspace allocations that the kernel does not - * need direct access to but can use kmap() when access is required. They - * are expected to be movable via page reclaim or page migration. Typically, - * pages on the LRU would also be allocated with GFP_HIGHUSER_MOVABLE. - * - * GFP_TRANSHUGE and GFP_TRANSHUGE_LIGHT are used for THP allocations. They are - * compound allocations that will generally fail quickly if memory is not - * available and will not wake kswapd/kcompactd on failure. The _LIGHT - * version does not attempt reclaim/compaction at all and is by default used - * in page fault path, while the non-light is used by khugepaged. - */ -#define GFP_ATOMIC (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM) -#define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS) -#define GFP_KERNEL_ACCOUNT (GFP_KERNEL | __GFP_ACCOUNT) -#define GFP_NOWAIT (__GFP_KSWAPD_RECLAIM) -#define GFP_NOIO (__GFP_RECLAIM) -#define GFP_NOFS (__GFP_RECLAIM | __GFP_IO) -#define GFP_TEMPORARY (__GFP_RECLAIM | __GFP_IO | __GFP_FS | \ - __GFP_RECLAIMABLE) -#define GFP_USER (__GFP_RECLAIM | __GFP_IO | __GFP_FS | __GFP_HARDWALL) -#define GFP_DMA __GFP_DMA -#define GFP_DMA32 __GFP_DMA32 -#define GFP_HIGHUSER (GFP_USER | __GFP_HIGHMEM) -#define GFP_HIGHUSER_MOVABLE (GFP_HIGHUSER | __GFP_MOVABLE) -#define GFP_TRANSHUGE_LIGHT ((GFP_HIGHUSER_MOVABLE | __GFP_COMP | \ - __GFP_NOMEMALLOC | __GFP_NOWARN) & ~__GFP_RECLAIM) -#define GFP_TRANSHUGE (GFP_TRANSHUGE_LIGHT | __GFP_DIRECT_RECLAIM) - -/* Convert GFP flags to their corresponding migrate type */ -#define GFP_MOVABLE_MASK (__GFP_RECLAIMABLE|__GFP_MOVABLE) -#define GFP_MOVABLE_SHIFT 3 - -static inline int gfpflags_to_migratetype(const gfp_t gfp_flags) -{ - VM_WARN_ON((gfp_flags & GFP_MOVABLE_MASK) == GFP_MOVABLE_MASK); - BUILD_BUG_ON((1UL << GFP_MOVABLE_SHIFT) != ___GFP_MOVABLE); - BUILD_BUG_ON((___GFP_MOVABLE >> GFP_MOVABLE_SHIFT) != MIGRATE_MOVABLE); - - if (unlikely(page_group_by_mobility_disabled)) - return MIGRATE_UNMOVABLE; - - /* Group based on mobility */ - return (gfp_flags & GFP_MOVABLE_MASK) >> GFP_MOVABLE_SHIFT; -} -#undef GFP_MOVABLE_MASK -#undef GFP_MOVABLE_SHIFT - -static inline bool gfpflags_allow_blocking(const gfp_t gfp_flags) -{ - return !!(gfp_flags & __GFP_DIRECT_RECLAIM); -} - -#ifdef CONFIG_HIGHMEM -#define OPT_ZONE_HIGHMEM ZONE_HIGHMEM -#else -#define OPT_ZONE_HIGHMEM ZONE_NORMAL -#endif - -#ifdef CONFIG_ZONE_DMA -#define OPT_ZONE_DMA ZONE_DMA -#else -#define OPT_ZONE_DMA ZONE_NORMAL -#endif - -#ifdef CONFIG_ZONE_DMA32 -#define OPT_ZONE_DMA32 ZONE_DMA32 -#else -#define OPT_ZONE_DMA32 ZONE_NORMAL -#endif - -/* - * GFP_ZONE_TABLE is a word size bitstring that is used for looking up the - * zone to use given the lowest 4 bits of gfp_t. Entries are ZONE_SHIFT long - * and there are 16 of them to cover all possible combinations of - * __GFP_DMA, __GFP_DMA32, __GFP_MOVABLE and __GFP_HIGHMEM. - * - * The zone fallback order is MOVABLE=>HIGHMEM=>NORMAL=>DMA32=>DMA. - * But GFP_MOVABLE is not only a zone specifier but also an allocation - * policy. Therefore __GFP_MOVABLE plus another zone selector is valid. - * Only 1 bit of the lowest 3 bits (DMA,DMA32,HIGHMEM) can be set to "1". - * - * bit result - * ================= - * 0x0 => NORMAL - * 0x1 => DMA or NORMAL - * 0x2 => HIGHMEM or NORMAL - * 0x3 => BAD (DMA+HIGHMEM) - * 0x4 => DMA32 or DMA or NORMAL - * 0x5 => BAD (DMA+DMA32) - * 0x6 => BAD (HIGHMEM+DMA32) - * 0x7 => BAD (HIGHMEM+DMA32+DMA) - * 0x8 => NORMAL (MOVABLE+0) - * 0x9 => DMA or NORMAL (MOVABLE+DMA) - * 0xa => MOVABLE (Movable is valid only if HIGHMEM is set too) - * 0xb => BAD (MOVABLE+HIGHMEM+DMA) - * 0xc => DMA32 (MOVABLE+DMA32) - * 0xd => BAD (MOVABLE+DMA32+DMA) - * 0xe => BAD (MOVABLE+DMA32+HIGHMEM) - * 0xf => BAD (MOVABLE+DMA32+HIGHMEM+DMA) - * - * GFP_ZONES_SHIFT must be <= 2 on 32 bit platforms. - */ - -#if defined(CONFIG_ZONE_DEVICE) && (MAX_NR_ZONES-1) <= 4 -/* ZONE_DEVICE is not a valid GFP zone specifier */ -#define GFP_ZONES_SHIFT 2 -#else -#define GFP_ZONES_SHIFT ZONES_SHIFT -#endif - -#if 16 * GFP_ZONES_SHIFT > BITS_PER_LONG -#error GFP_ZONES_SHIFT too large to create GFP_ZONE_TABLE integer -#endif - -#define GFP_ZONE_TABLE ( \ - (ZONE_NORMAL << 0 * GFP_ZONES_SHIFT) \ - | (OPT_ZONE_DMA << ___GFP_DMA * GFP_ZONES_SHIFT) \ - | (OPT_ZONE_HIGHMEM << ___GFP_HIGHMEM * GFP_ZONES_SHIFT) \ - | (OPT_ZONE_DMA32 << ___GFP_DMA32 * GFP_ZONES_SHIFT) \ - | (ZONE_NORMAL << ___GFP_MOVABLE * GFP_ZONES_SHIFT) \ - | (OPT_ZONE_DMA << (___GFP_MOVABLE | ___GFP_DMA) * GFP_ZONES_SHIFT) \ - | (ZONE_MOVABLE << (___GFP_MOVABLE | ___GFP_HIGHMEM) * GFP_ZONES_SHIFT)\ - | (OPT_ZONE_DMA32 << (___GFP_MOVABLE | ___GFP_DMA32) * GFP_ZONES_SHIFT)\ -) - -/* - * GFP_ZONE_BAD is a bitmap for all combinations of __GFP_DMA, __GFP_DMA32 - * __GFP_HIGHMEM and __GFP_MOVABLE that are not permitted. One flag per - * entry starting with bit 0. Bit is set if the combination is not - * allowed. - */ -#define GFP_ZONE_BAD ( \ - 1 << (___GFP_DMA | ___GFP_HIGHMEM) \ - | 1 << (___GFP_DMA | ___GFP_DMA32) \ - | 1 << (___GFP_DMA32 | ___GFP_HIGHMEM) \ - | 1 << (___GFP_DMA | ___GFP_DMA32 | ___GFP_HIGHMEM) \ - | 1 << (___GFP_MOVABLE | ___GFP_HIGHMEM | ___GFP_DMA) \ - | 1 << (___GFP_MOVABLE | ___GFP_DMA32 | ___GFP_DMA) \ - | 1 << (___GFP_MOVABLE | ___GFP_DMA32 | ___GFP_HIGHMEM) \ - | 1 << (___GFP_MOVABLE | ___GFP_DMA32 | ___GFP_DMA | ___GFP_HIGHMEM) \ -) - -static inline enum zone_type gfp_zone(gfp_t flags) -{ - enum zone_type z; - int bit = (__force int) (flags & GFP_ZONEMASK); - - z = (GFP_ZONE_TABLE >> (bit * GFP_ZONES_SHIFT)) & - ((1 << GFP_ZONES_SHIFT) - 1); - VM_BUG_ON((GFP_ZONE_BAD >> bit) & 1); - return z; -} - -/* - * There is only one page-allocator function, and two main namespaces to - * it. The alloc_page*() variants return 'struct page *' and as such - * can allocate highmem pages, the *get*page*() variants return - * virtual kernel addresses to the allocated page(s). - */ - -static inline int gfp_zonelist(gfp_t flags) -{ -#ifdef CONFIG_NUMA - if (unlikely(flags & __GFP_THISNODE)) - return ZONELIST_NOFALLBACK; -#endif - return ZONELIST_FALLBACK; -} - -/* - * We get the zone list from the current node and the gfp_mask. - * This zone list contains a maximum of MAXNODES*MAX_NR_ZONES zones. - * There are two zonelists per node, one for all zones with memory and - * one containing just zones from the node the zonelist belongs to. - * - * For the normal case of non-DISCONTIGMEM systems the NODE_DATA() gets - * optimized to &contig_page_data at compile-time. - */ -static inline struct zonelist *node_zonelist(int nid, gfp_t flags) -{ - return NODE_DATA(nid)->node_zonelists + gfp_zonelist(flags); -} - -#ifndef HAVE_ARCH_FREE_PAGE -static inline void arch_free_page(struct page *page, int order) { } -#endif -#ifndef HAVE_ARCH_ALLOC_PAGE -static inline void arch_alloc_page(struct page *page, int order) { } -#endif - -struct page * -__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, - struct zonelist *zonelist, nodemask_t *nodemask); - -static inline struct page * -__alloc_pages(gfp_t gfp_mask, unsigned int order, - struct zonelist *zonelist) -{ - return __alloc_pages_nodemask(gfp_mask, order, zonelist, NULL); -} - -/* - * Allocate pages, preferring the node given as nid. The node must be valid and - * online. For more general interface, see alloc_pages_node(). - */ -static inline struct page * -__alloc_pages_node(int nid, gfp_t gfp_mask, unsigned int order) -{ - VM_BUG_ON(nid < 0 || nid >= MAX_NUMNODES); - VM_WARN_ON(!node_online(nid)); - - return __alloc_pages(gfp_mask, order, node_zonelist(nid, gfp_mask)); -} - -/* - * Allocate pages, preferring the node given as nid. When nid == NUMA_NO_NODE, - * prefer the current CPU's closest node. Otherwise node must be valid and - * online. - */ -static inline struct page *alloc_pages_node(int nid, gfp_t gfp_mask, - unsigned int order) -{ - if (nid == NUMA_NO_NODE) - nid = numa_mem_id(); - - return __alloc_pages_node(nid, gfp_mask, order); -} - -#ifdef CONFIG_NUMA -extern struct page *alloc_pages_current(gfp_t gfp_mask, unsigned order); - -static inline struct page * -alloc_pages(gfp_t gfp_mask, unsigned int order) -{ - return alloc_pages_current(gfp_mask, order); -} -extern struct page *alloc_pages_vma(gfp_t gfp_mask, int order, - struct vm_area_struct *vma, unsigned long addr, - int node, bool hugepage); -#define alloc_hugepage_vma(gfp_mask, vma, addr, order) \ - alloc_pages_vma(gfp_mask, order, vma, addr, numa_node_id(), true) -#else -#define alloc_pages(gfp_mask, order) \ - alloc_pages_node(numa_node_id(), gfp_mask, order) -#define alloc_pages_vma(gfp_mask, order, vma, addr, node, false)\ - alloc_pages(gfp_mask, order) -#define alloc_hugepage_vma(gfp_mask, vma, addr, order) \ - alloc_pages(gfp_mask, order) -#endif -#define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0) -#define alloc_page_vma(gfp_mask, vma, addr) \ - alloc_pages_vma(gfp_mask, 0, vma, addr, numa_node_id(), false) -#define alloc_page_vma_node(gfp_mask, vma, addr, node) \ - alloc_pages_vma(gfp_mask, 0, vma, addr, node, false) - -extern unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order); -extern unsigned long get_zeroed_page(gfp_t gfp_mask); - -void *alloc_pages_exact(size_t size, gfp_t gfp_mask); -void free_pages_exact(void *virt, size_t size); -void * __meminit alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask); - -#define __get_free_page(gfp_mask) \ - __get_free_pages((gfp_mask), 0) - -#define __get_dma_pages(gfp_mask, order) \ - __get_free_pages((gfp_mask) | GFP_DMA, (order)) - -extern void __free_pages(struct page *page, unsigned int order); -extern void free_pages(unsigned long addr, unsigned int order); -extern void free_hot_cold_page(struct page *page, bool cold); -extern void free_hot_cold_page_list(struct list_head *list, bool cold); - -struct page_frag_cache; -extern void *__alloc_page_frag(struct page_frag_cache *nc, - unsigned int fragsz, gfp_t gfp_mask); -extern void __free_page_frag(void *addr); - -#define __free_page(page) __free_pages((page), 0) -#define free_page(addr) free_pages((addr), 0) - -void page_alloc_init(void); -void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp); -void drain_all_pages(struct zone *zone); -void drain_local_pages(struct zone *zone); - -void page_alloc_init_late(void); - -/* - * gfp_allowed_mask is set to GFP_BOOT_MASK during early boot to restrict what - * GFP flags are used before interrupts are enabled. Once interrupts are - * enabled, it is set to __GFP_BITS_MASK while the system is running. During - * hibernation, it is used by PM to avoid I/O during memory allocation while - * devices are suspended. - */ -extern gfp_t gfp_allowed_mask; - -/* Returns true if the gfp_mask allows use of ALLOC_NO_WATERMARK */ -bool gfp_pfmemalloc_allowed(gfp_t gfp_mask); - -extern void pm_restrict_gfp_mask(void); -extern void pm_restore_gfp_mask(void); - -#ifdef CONFIG_PM_SLEEP -extern bool pm_suspended_storage(void); -#else -static inline bool pm_suspended_storage(void) -{ - return false; -} -#endif /* CONFIG_PM_SLEEP */ - -#if (defined(CONFIG_MEMORY_ISOLATION) && defined(CONFIG_COMPACTION)) || defined(CONFIG_CMA) -/* The below functions must be run on a range from a single zone. */ -extern int alloc_contig_range(unsigned long start, unsigned long end, - unsigned migratetype); -extern void free_contig_range(unsigned long pfn, unsigned nr_pages); -#endif - -#ifdef CONFIG_CMA -/* CMA stuff */ -extern void init_cma_reserved_pageblock(struct page *page); -#endif - -#endif /* __LINUX_GFP_H */ diff --git a/src/linux/include/linux/hardirq.h b/src/linux/include/linux/hardirq.h deleted file mode 100644 index c683996..0000000 --- a/src/linux/include/linux/hardirq.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef LINUX_HARDIRQ_H -#define LINUX_HARDIRQ_H - -#include -#include -#include -#include -#include - - -extern void synchronize_irq(unsigned int irq); -extern bool synchronize_hardirq(unsigned int irq); - -#if defined(CONFIG_TINY_RCU) - -static inline void rcu_nmi_enter(void) -{ -} - -static inline void rcu_nmi_exit(void) -{ -} - -#else -extern void rcu_nmi_enter(void); -extern void rcu_nmi_exit(void); -#endif - -/* - * It is safe to do non-atomic ops on ->hardirq_context, - * because NMI handlers may not preempt and the ops are - * always balanced, so the interrupted value of ->hardirq_context - * will always be restored. - */ -#define __irq_enter() \ - do { \ - account_irq_enter_time(current); \ - preempt_count_add(HARDIRQ_OFFSET); \ - trace_hardirq_enter(); \ - } while (0) - -/* - * Enter irq context (on NO_HZ, update jiffies): - */ -extern void irq_enter(void); - -/* - * Exit irq context without processing softirqs: - */ -#define __irq_exit() \ - do { \ - trace_hardirq_exit(); \ - account_irq_exit_time(current); \ - preempt_count_sub(HARDIRQ_OFFSET); \ - } while (0) - -/* - * Exit irq context and process softirqs if needed: - */ -extern void irq_exit(void); - -#define nmi_enter() \ - do { \ - printk_nmi_enter(); \ - lockdep_off(); \ - ftrace_nmi_enter(); \ - BUG_ON(in_nmi()); \ - preempt_count_add(NMI_OFFSET + HARDIRQ_OFFSET); \ - rcu_nmi_enter(); \ - trace_hardirq_enter(); \ - } while (0) - -#define nmi_exit() \ - do { \ - trace_hardirq_exit(); \ - rcu_nmi_exit(); \ - BUG_ON(!in_nmi()); \ - preempt_count_sub(NMI_OFFSET + HARDIRQ_OFFSET); \ - ftrace_nmi_exit(); \ - lockdep_on(); \ - printk_nmi_exit(); \ - } while (0) - -#endif /* LINUX_HARDIRQ_H */ diff --git a/src/linux/include/linux/hash.h b/src/linux/include/linux/hash.h deleted file mode 100644 index ad6fa21..0000000 --- a/src/linux/include/linux/hash.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef _LINUX_HASH_H -#define _LINUX_HASH_H -/* Fast hashing routine for ints, longs and pointers. - (C) 2002 Nadia Yvette Chambers, IBM */ - -#include -#include - -/* - * The "GOLDEN_RATIO_PRIME" is used in ifs/btrfs/brtfs_inode.h and - * fs/inode.c. It's not actually prime any more (the previous primes - * were actively bad for hashing), but the name remains. - */ -#if BITS_PER_LONG == 32 -#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_32 -#define hash_long(val, bits) hash_32(val, bits) -#elif BITS_PER_LONG == 64 -#define hash_long(val, bits) hash_64(val, bits) -#define GOLDEN_RATIO_PRIME GOLDEN_RATIO_64 -#else -#error Wordsize not 32 or 64 -#endif - -/* - * This hash multiplies the input by a large odd number and takes the - * high bits. Since multiplication propagates changes to the most - * significant end only, it is essential that the high bits of the - * product be used for the hash value. - * - * Chuck Lever verified the effectiveness of this technique: - * http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf - * - * Although a random odd number will do, it turns out that the golden - * ratio phi = (sqrt(5)-1)/2, or its negative, has particularly nice - * properties. (See Knuth vol 3, section 6.4, exercise 9.) - * - * These are the negative, (1 - phi) = phi**2 = (3 - sqrt(5))/2, - * which is very slightly easier to multiply by and makes no - * difference to the hash distribution. - */ -#define GOLDEN_RATIO_32 0x61C88647 -#define GOLDEN_RATIO_64 0x61C8864680B583EBull - -#ifdef CONFIG_HAVE_ARCH_HASH -/* This header may use the GOLDEN_RATIO_xx constants */ -#include -#endif - -/* - * The _generic versions exist only so lib/test_hash.c can compare - * the arch-optimized versions with the generic. - * - * Note that if you change these, any that aren't updated - * to match need to have their HAVE_ARCH_* define values updated so the - * self-test will not false-positive. - */ -#ifndef HAVE_ARCH__HASH_32 -#define __hash_32 __hash_32_generic -#endif -static inline u32 __hash_32_generic(u32 val) -{ - return val * GOLDEN_RATIO_32; -} - -#ifndef HAVE_ARCH_HASH_32 -#define hash_32 hash_32_generic -#endif -static inline u32 hash_32_generic(u32 val, unsigned int bits) -{ - /* High bits are more random, so use them. */ - return __hash_32(val) >> (32 - bits); -} - -#ifndef HAVE_ARCH_HASH_64 -#define hash_64 hash_64_generic -#endif -static __always_inline u32 hash_64_generic(u64 val, unsigned int bits) -{ -#if BITS_PER_LONG == 64 - /* 64x64-bit multiply is efficient on all 64-bit processors */ - return val * GOLDEN_RATIO_64 >> (64 - bits); -#else - /* Hash 64 bits using only 32x32-bit multiply. */ - return hash_32((u32)val ^ __hash_32(val >> 32), bits); -#endif -} - -static inline u32 hash_ptr(const void *ptr, unsigned int bits) -{ - return hash_long((unsigned long)ptr, bits); -} - -/* This really should be called fold32_ptr; it does no hashing to speak of. */ -static inline u32 hash32_ptr(const void *ptr) -{ - unsigned long val = (unsigned long)ptr; - -#if BITS_PER_LONG == 64 - val ^= (val >> 32); -#endif - return (u32)val; -} - -#endif /* _LINUX_HASH_H */ diff --git a/src/linux/include/linux/hashtable.h b/src/linux/include/linux/hashtable.h deleted file mode 100644 index 661e5c2..0000000 --- a/src/linux/include/linux/hashtable.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Statically sized hash table implementation - * (C) 2012 Sasha Levin - */ - -#ifndef _LINUX_HASHTABLE_H -#define _LINUX_HASHTABLE_H - -#include -#include -#include -#include -#include - -#define DEFINE_HASHTABLE(name, bits) \ - struct hlist_head name[1 << (bits)] = \ - { [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT } - -#define DEFINE_READ_MOSTLY_HASHTABLE(name, bits) \ - struct hlist_head name[1 << (bits)] __read_mostly = \ - { [0 ... ((1 << (bits)) - 1)] = HLIST_HEAD_INIT } - -#define DECLARE_HASHTABLE(name, bits) \ - struct hlist_head name[1 << (bits)] - -#define HASH_SIZE(name) (ARRAY_SIZE(name)) -#define HASH_BITS(name) ilog2(HASH_SIZE(name)) - -/* Use hash_32 when possible to allow for fast 32bit hashing in 64bit kernels. */ -#define hash_min(val, bits) \ - (sizeof(val) <= 4 ? hash_32(val, bits) : hash_long(val, bits)) - -static inline void __hash_init(struct hlist_head *ht, unsigned int sz) -{ - unsigned int i; - - for (i = 0; i < sz; i++) - INIT_HLIST_HEAD(&ht[i]); -} - -/** - * hash_init - initialize a hash table - * @hashtable: hashtable to be initialized - * - * Calculates the size of the hashtable from the given parameter, otherwise - * same as hash_init_size. - * - * This has to be a macro since HASH_BITS() will not work on pointers since - * it calculates the size during preprocessing. - */ -#define hash_init(hashtable) __hash_init(hashtable, HASH_SIZE(hashtable)) - -/** - * hash_add - add an object to a hashtable - * @hashtable: hashtable to add to - * @node: the &struct hlist_node of the object to be added - * @key: the key of the object to be added - */ -#define hash_add(hashtable, node, key) \ - hlist_add_head(node, &hashtable[hash_min(key, HASH_BITS(hashtable))]) - -/** - * hash_add_rcu - add an object to a rcu enabled hashtable - * @hashtable: hashtable to add to - * @node: the &struct hlist_node of the object to be added - * @key: the key of the object to be added - */ -#define hash_add_rcu(hashtable, node, key) \ - hlist_add_head_rcu(node, &hashtable[hash_min(key, HASH_BITS(hashtable))]) - -/** - * hash_hashed - check whether an object is in any hashtable - * @node: the &struct hlist_node of the object to be checked - */ -static inline bool hash_hashed(struct hlist_node *node) -{ - return !hlist_unhashed(node); -} - -static inline bool __hash_empty(struct hlist_head *ht, unsigned int sz) -{ - unsigned int i; - - for (i = 0; i < sz; i++) - if (!hlist_empty(&ht[i])) - return false; - - return true; -} - -/** - * hash_empty - check whether a hashtable is empty - * @hashtable: hashtable to check - * - * This has to be a macro since HASH_BITS() will not work on pointers since - * it calculates the size during preprocessing. - */ -#define hash_empty(hashtable) __hash_empty(hashtable, HASH_SIZE(hashtable)) - -/** - * hash_del - remove an object from a hashtable - * @node: &struct hlist_node of the object to remove - */ -static inline void hash_del(struct hlist_node *node) -{ - hlist_del_init(node); -} - -/** - * hash_del_rcu - remove an object from a rcu enabled hashtable - * @node: &struct hlist_node of the object to remove - */ -static inline void hash_del_rcu(struct hlist_node *node) -{ - hlist_del_init_rcu(node); -} - -/** - * hash_for_each - iterate over a hashtable - * @name: hashtable to iterate - * @bkt: integer to use as bucket loop cursor - * @obj: the type * to use as a loop cursor for each entry - * @member: the name of the hlist_node within the struct - */ -#define hash_for_each(name, bkt, obj, member) \ - for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\ - (bkt)++)\ - hlist_for_each_entry(obj, &name[bkt], member) - -/** - * hash_for_each_rcu - iterate over a rcu enabled hashtable - * @name: hashtable to iterate - * @bkt: integer to use as bucket loop cursor - * @obj: the type * to use as a loop cursor for each entry - * @member: the name of the hlist_node within the struct - */ -#define hash_for_each_rcu(name, bkt, obj, member) \ - for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\ - (bkt)++)\ - hlist_for_each_entry_rcu(obj, &name[bkt], member) - -/** - * hash_for_each_safe - iterate over a hashtable safe against removal of - * hash entry - * @name: hashtable to iterate - * @bkt: integer to use as bucket loop cursor - * @tmp: a &struct used for temporary storage - * @obj: the type * to use as a loop cursor for each entry - * @member: the name of the hlist_node within the struct - */ -#define hash_for_each_safe(name, bkt, tmp, obj, member) \ - for ((bkt) = 0, obj = NULL; obj == NULL && (bkt) < HASH_SIZE(name);\ - (bkt)++)\ - hlist_for_each_entry_safe(obj, tmp, &name[bkt], member) - -/** - * hash_for_each_possible - iterate over all possible objects hashing to the - * same bucket - * @name: hashtable to iterate - * @obj: the type * to use as a loop cursor for each entry - * @member: the name of the hlist_node within the struct - * @key: the key of the objects to iterate over - */ -#define hash_for_each_possible(name, obj, member, key) \ - hlist_for_each_entry(obj, &name[hash_min(key, HASH_BITS(name))], member) - -/** - * hash_for_each_possible_rcu - iterate over all possible objects hashing to the - * same bucket in an rcu enabled hashtable - * in a rcu enabled hashtable - * @name: hashtable to iterate - * @obj: the type * to use as a loop cursor for each entry - * @member: the name of the hlist_node within the struct - * @key: the key of the objects to iterate over - */ -#define hash_for_each_possible_rcu(name, obj, member, key) \ - hlist_for_each_entry_rcu(obj, &name[hash_min(key, HASH_BITS(name))],\ - member) - -/** - * hash_for_each_possible_rcu_notrace - iterate over all possible objects hashing - * to the same bucket in an rcu enabled hashtable in a rcu enabled hashtable - * @name: hashtable to iterate - * @obj: the type * to use as a loop cursor for each entry - * @member: the name of the hlist_node within the struct - * @key: the key of the objects to iterate over - * - * This is the same as hash_for_each_possible_rcu() except that it does - * not do any RCU debugging or tracing. - */ -#define hash_for_each_possible_rcu_notrace(name, obj, member, key) \ - hlist_for_each_entry_rcu_notrace(obj, \ - &name[hash_min(key, HASH_BITS(name))], member) - -/** - * hash_for_each_possible_safe - iterate over all possible objects hashing to the - * same bucket safe against removals - * @name: hashtable to iterate - * @obj: the type * to use as a loop cursor for each entry - * @tmp: a &struct used for temporary storage - * @member: the name of the hlist_node within the struct - * @key: the key of the objects to iterate over - */ -#define hash_for_each_possible_safe(name, obj, tmp, member, key) \ - hlist_for_each_entry_safe(obj, tmp,\ - &name[hash_min(key, HASH_BITS(name))], member) - - -#endif diff --git a/src/linux/include/linux/hid-debug.h b/src/linux/include/linux/hid-debug.h deleted file mode 100644 index 8663f21..0000000 --- a/src/linux/include/linux/hid-debug.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef __HID_DEBUG_H -#define __HID_DEBUG_H - -/* - * Copyright (c) 2007-2009 Jiri Kosina - */ - -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - */ - -#ifdef CONFIG_DEBUG_FS - -#define HID_DEBUG_BUFSIZE 512 - -void hid_dump_input(struct hid_device *, struct hid_usage *, __s32); -void hid_dump_report(struct hid_device *, int , u8 *, int); -void hid_dump_device(struct hid_device *, struct seq_file *); -void hid_dump_field(struct hid_field *, int, struct seq_file *); -char *hid_resolv_usage(unsigned, struct seq_file *); -void hid_debug_register(struct hid_device *, const char *); -void hid_debug_unregister(struct hid_device *); -void hid_debug_init(void); -void hid_debug_exit(void); -void hid_debug_event(struct hid_device *, char *); - - -struct hid_debug_list { - char *hid_debug_buf; - int head; - int tail; - struct fasync_struct *fasync; - struct hid_device *hdev; - struct list_head node; - struct mutex read_mutex; -}; - -#else - -#define hid_dump_input(a,b,c) do { } while (0) -#define hid_dump_report(a,b,c,d) do { } while (0) -#define hid_dump_device(a,b) do { } while (0) -#define hid_dump_field(a,b,c) do { } while (0) -#define hid_resolv_usage(a,b) do { } while (0) -#define hid_debug_register(a, b) do { } while (0) -#define hid_debug_unregister(a) do { } while (0) -#define hid_debug_init() do { } while (0) -#define hid_debug_exit() do { } while (0) -#define hid_debug_event(a,b) do { } while (0) - -#endif - -#endif - diff --git a/src/linux/include/linux/hid.h b/src/linux/include/linux/hid.h deleted file mode 100644 index b2ec827..0000000 --- a/src/linux/include/linux/hid.h +++ /dev/null @@ -1,1154 +0,0 @@ -/* - * Copyright (c) 1999 Andreas Gal - * Copyright (c) 2000-2001 Vojtech Pavlik - * Copyright (c) 2006-2007 Jiri Kosina - */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ -#ifndef __HID_H -#define __HID_H - - -#include -#include -#include -#include /* hid_device_id */ -#include -#include -#include -#include -#include -#include - -/* - * We parse each description item into this structure. Short items data - * values are expanded to 32-bit signed int, long items contain a pointer - * into the data area. - */ - -struct hid_item { - unsigned format; - __u8 size; - __u8 type; - __u8 tag; - union { - __u8 u8; - __s8 s8; - __u16 u16; - __s16 s16; - __u32 u32; - __s32 s32; - __u8 *longdata; - } data; -}; - -/* - * HID report item format - */ - -#define HID_ITEM_FORMAT_SHORT 0 -#define HID_ITEM_FORMAT_LONG 1 - -/* - * Special tag indicating long items - */ - -#define HID_ITEM_TAG_LONG 15 - -/* - * HID report descriptor item type (prefix bit 2,3) - */ - -#define HID_ITEM_TYPE_MAIN 0 -#define HID_ITEM_TYPE_GLOBAL 1 -#define HID_ITEM_TYPE_LOCAL 2 -#define HID_ITEM_TYPE_RESERVED 3 - -/* - * HID report descriptor main item tags - */ - -#define HID_MAIN_ITEM_TAG_INPUT 8 -#define HID_MAIN_ITEM_TAG_OUTPUT 9 -#define HID_MAIN_ITEM_TAG_FEATURE 11 -#define HID_MAIN_ITEM_TAG_BEGIN_COLLECTION 10 -#define HID_MAIN_ITEM_TAG_END_COLLECTION 12 - -/* - * HID report descriptor main item contents - */ - -#define HID_MAIN_ITEM_CONSTANT 0x001 -#define HID_MAIN_ITEM_VARIABLE 0x002 -#define HID_MAIN_ITEM_RELATIVE 0x004 -#define HID_MAIN_ITEM_WRAP 0x008 -#define HID_MAIN_ITEM_NONLINEAR 0x010 -#define HID_MAIN_ITEM_NO_PREFERRED 0x020 -#define HID_MAIN_ITEM_NULL_STATE 0x040 -#define HID_MAIN_ITEM_VOLATILE 0x080 -#define HID_MAIN_ITEM_BUFFERED_BYTE 0x100 - -/* - * HID report descriptor collection item types - */ - -#define HID_COLLECTION_PHYSICAL 0 -#define HID_COLLECTION_APPLICATION 1 -#define HID_COLLECTION_LOGICAL 2 - -/* - * HID report descriptor global item tags - */ - -#define HID_GLOBAL_ITEM_TAG_USAGE_PAGE 0 -#define HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM 1 -#define HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM 2 -#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM 3 -#define HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM 4 -#define HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT 5 -#define HID_GLOBAL_ITEM_TAG_UNIT 6 -#define HID_GLOBAL_ITEM_TAG_REPORT_SIZE 7 -#define HID_GLOBAL_ITEM_TAG_REPORT_ID 8 -#define HID_GLOBAL_ITEM_TAG_REPORT_COUNT 9 -#define HID_GLOBAL_ITEM_TAG_PUSH 10 -#define HID_GLOBAL_ITEM_TAG_POP 11 - -/* - * HID report descriptor local item tags - */ - -#define HID_LOCAL_ITEM_TAG_USAGE 0 -#define HID_LOCAL_ITEM_TAG_USAGE_MINIMUM 1 -#define HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM 2 -#define HID_LOCAL_ITEM_TAG_DESIGNATOR_INDEX 3 -#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MINIMUM 4 -#define HID_LOCAL_ITEM_TAG_DESIGNATOR_MAXIMUM 5 -#define HID_LOCAL_ITEM_TAG_STRING_INDEX 7 -#define HID_LOCAL_ITEM_TAG_STRING_MINIMUM 8 -#define HID_LOCAL_ITEM_TAG_STRING_MAXIMUM 9 -#define HID_LOCAL_ITEM_TAG_DELIMITER 10 - -/* - * HID usage tables - */ - -#define HID_USAGE_PAGE 0xffff0000 - -#define HID_UP_UNDEFINED 0x00000000 -#define HID_UP_GENDESK 0x00010000 -#define HID_UP_SIMULATION 0x00020000 -#define HID_UP_GENDEVCTRLS 0x00060000 -#define HID_UP_KEYBOARD 0x00070000 -#define HID_UP_LED 0x00080000 -#define HID_UP_BUTTON 0x00090000 -#define HID_UP_ORDINAL 0x000a0000 -#define HID_UP_TELEPHONY 0x000b0000 -#define HID_UP_CONSUMER 0x000c0000 -#define HID_UP_DIGITIZER 0x000d0000 -#define HID_UP_PID 0x000f0000 -#define HID_UP_HPVENDOR 0xff7f0000 -#define HID_UP_HPVENDOR2 0xff010000 -#define HID_UP_MSVENDOR 0xff000000 -#define HID_UP_CUSTOM 0x00ff0000 -#define HID_UP_LOGIVENDOR 0xffbc0000 -#define HID_UP_LOGIVENDOR2 0xff090000 -#define HID_UP_LOGIVENDOR3 0xff430000 -#define HID_UP_LNVENDOR 0xffa00000 -#define HID_UP_SENSOR 0x00200000 - -#define HID_USAGE 0x0000ffff - -#define HID_GD_POINTER 0x00010001 -#define HID_GD_MOUSE 0x00010002 -#define HID_GD_JOYSTICK 0x00010004 -#define HID_GD_GAMEPAD 0x00010005 -#define HID_GD_KEYBOARD 0x00010006 -#define HID_GD_KEYPAD 0x00010007 -#define HID_GD_MULTIAXIS 0x00010008 -#define HID_GD_X 0x00010030 -#define HID_GD_Y 0x00010031 -#define HID_GD_Z 0x00010032 -#define HID_GD_RX 0x00010033 -#define HID_GD_RY 0x00010034 -#define HID_GD_RZ 0x00010035 -#define HID_GD_SLIDER 0x00010036 -#define HID_GD_DIAL 0x00010037 -#define HID_GD_WHEEL 0x00010038 -#define HID_GD_HATSWITCH 0x00010039 -#define HID_GD_BUFFER 0x0001003a -#define HID_GD_BYTECOUNT 0x0001003b -#define HID_GD_MOTION 0x0001003c -#define HID_GD_START 0x0001003d -#define HID_GD_SELECT 0x0001003e -#define HID_GD_VX 0x00010040 -#define HID_GD_VY 0x00010041 -#define HID_GD_VZ 0x00010042 -#define HID_GD_VBRX 0x00010043 -#define HID_GD_VBRY 0x00010044 -#define HID_GD_VBRZ 0x00010045 -#define HID_GD_VNO 0x00010046 -#define HID_GD_FEATURE 0x00010047 -#define HID_GD_SYSTEM_CONTROL 0x00010080 -#define HID_GD_UP 0x00010090 -#define HID_GD_DOWN 0x00010091 -#define HID_GD_RIGHT 0x00010092 -#define HID_GD_LEFT 0x00010093 - -#define HID_DC_BATTERYSTRENGTH 0x00060020 - -#define HID_CP_CONSUMER_CONTROL 0x000c0001 - -#define HID_DG_DIGITIZER 0x000d0001 -#define HID_DG_PEN 0x000d0002 -#define HID_DG_LIGHTPEN 0x000d0003 -#define HID_DG_TOUCHSCREEN 0x000d0004 -#define HID_DG_TOUCHPAD 0x000d0005 -#define HID_DG_STYLUS 0x000d0020 -#define HID_DG_PUCK 0x000d0021 -#define HID_DG_FINGER 0x000d0022 -#define HID_DG_TIPPRESSURE 0x000d0030 -#define HID_DG_BARRELPRESSURE 0x000d0031 -#define HID_DG_INRANGE 0x000d0032 -#define HID_DG_TOUCH 0x000d0033 -#define HID_DG_UNTOUCH 0x000d0034 -#define HID_DG_TAP 0x000d0035 -#define HID_DG_TABLETFUNCTIONKEY 0x000d0039 -#define HID_DG_PROGRAMCHANGEKEY 0x000d003a -#define HID_DG_INVERT 0x000d003c -#define HID_DG_TIPSWITCH 0x000d0042 -#define HID_DG_TIPSWITCH2 0x000d0043 -#define HID_DG_BARRELSWITCH 0x000d0044 -#define HID_DG_ERASER 0x000d0045 -#define HID_DG_TABLETPICK 0x000d0046 - -#define HID_CP_CONSUMERCONTROL 0x000c0001 -#define HID_CP_NUMERICKEYPAD 0x000c0002 -#define HID_CP_PROGRAMMABLEBUTTONS 0x000c0003 -#define HID_CP_MICROPHONE 0x000c0004 -#define HID_CP_HEADPHONE 0x000c0005 -#define HID_CP_GRAPHICEQUALIZER 0x000c0006 -#define HID_CP_FUNCTIONBUTTONS 0x000c0036 -#define HID_CP_SELECTION 0x000c0080 -#define HID_CP_MEDIASELECTION 0x000c0087 -#define HID_CP_SELECTDISC 0x000c00ba -#define HID_CP_PLAYBACKSPEED 0x000c00f1 -#define HID_CP_PROXIMITY 0x000c0109 -#define HID_CP_SPEAKERSYSTEM 0x000c0160 -#define HID_CP_CHANNELLEFT 0x000c0161 -#define HID_CP_CHANNELRIGHT 0x000c0162 -#define HID_CP_CHANNELCENTER 0x000c0163 -#define HID_CP_CHANNELFRONT 0x000c0164 -#define HID_CP_CHANNELCENTERFRONT 0x000c0165 -#define HID_CP_CHANNELSIDE 0x000c0166 -#define HID_CP_CHANNELSURROUND 0x000c0167 -#define HID_CP_CHANNELLOWFREQUENCYENHANCEMENT 0x000c0168 -#define HID_CP_CHANNELTOP 0x000c0169 -#define HID_CP_CHANNELUNKNOWN 0x000c016a -#define HID_CP_APPLICATIONLAUNCHBUTTONS 0x000c0180 -#define HID_CP_GENERICGUIAPPLICATIONCONTROLS 0x000c0200 - -#define HID_DG_CONFIDENCE 0x000d0047 -#define HID_DG_WIDTH 0x000d0048 -#define HID_DG_HEIGHT 0x000d0049 -#define HID_DG_CONTACTID 0x000d0051 -#define HID_DG_INPUTMODE 0x000d0052 -#define HID_DG_DEVICEINDEX 0x000d0053 -#define HID_DG_CONTACTCOUNT 0x000d0054 -#define HID_DG_CONTACTMAX 0x000d0055 -#define HID_DG_BUTTONTYPE 0x000d0059 -#define HID_DG_BARRELSWITCH2 0x000d005a -#define HID_DG_TOOLSERIALNUMBER 0x000d005b - -/* - * HID report types --- Ouch! HID spec says 1 2 3! - */ - -#define HID_INPUT_REPORT 0 -#define HID_OUTPUT_REPORT 1 -#define HID_FEATURE_REPORT 2 - -#define HID_REPORT_TYPES 3 - -/* - * HID connect requests - */ - -#define HID_CONNECT_HIDINPUT 0x01 -#define HID_CONNECT_HIDINPUT_FORCE 0x02 -#define HID_CONNECT_HIDRAW 0x04 -#define HID_CONNECT_HIDDEV 0x08 -#define HID_CONNECT_HIDDEV_FORCE 0x10 -#define HID_CONNECT_FF 0x20 -#define HID_CONNECT_DRIVER 0x40 -#define HID_CONNECT_DEFAULT (HID_CONNECT_HIDINPUT|HID_CONNECT_HIDRAW| \ - HID_CONNECT_HIDDEV|HID_CONNECT_FF) - -/* - * HID device quirks. - */ - -/* - * Increase this if you need to configure more HID quirks at module load time - */ -#define MAX_USBHID_BOOT_QUIRKS 4 - -#define HID_QUIRK_INVERT 0x00000001 -#define HID_QUIRK_NOTOUCH 0x00000002 -#define HID_QUIRK_IGNORE 0x00000004 -#define HID_QUIRK_NOGET 0x00000008 -#define HID_QUIRK_HIDDEV_FORCE 0x00000010 -#define HID_QUIRK_BADPAD 0x00000020 -#define HID_QUIRK_MULTI_INPUT 0x00000040 -#define HID_QUIRK_HIDINPUT_FORCE 0x00000080 -#define HID_QUIRK_NO_EMPTY_INPUT 0x00000100 -#define HID_QUIRK_NO_INIT_INPUT_REPORTS 0x00000200 -#define HID_QUIRK_ALWAYS_POLL 0x00000400 -#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 -#define HID_QUIRK_SKIP_OUTPUT_REPORT_ID 0x00020000 -#define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP 0x00040000 -#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000 -#define HID_QUIRK_NO_INIT_REPORTS 0x20000000 -#define HID_QUIRK_NO_IGNORE 0x40000000 -#define HID_QUIRK_NO_INPUT_SYNC 0x80000000 - -/* - * HID device groups - * - * Note: HID_GROUP_ANY is declared in linux/mod_devicetable.h - * and has a value of 0x0000 - */ -#define HID_GROUP_GENERIC 0x0001 -#define HID_GROUP_MULTITOUCH 0x0002 -#define HID_GROUP_SENSOR_HUB 0x0003 -#define HID_GROUP_MULTITOUCH_WIN_8 0x0004 - -/* - * Vendor specific HID device groups - */ -#define HID_GROUP_RMI 0x0100 -#define HID_GROUP_WACOM 0x0101 -#define HID_GROUP_LOGITECH_DJ_DEVICE 0x0102 - -/* - * This is the global environment of the parser. This information is - * persistent for main-items. The global environment can be saved and - * restored with PUSH/POP statements. - */ - -struct hid_global { - unsigned usage_page; - __s32 logical_minimum; - __s32 logical_maximum; - __s32 physical_minimum; - __s32 physical_maximum; - __s32 unit_exponent; - unsigned unit; - unsigned report_id; - unsigned report_size; - unsigned report_count; -}; - -/* - * This is the local environment. It is persistent up the next main-item. - */ - -#define HID_MAX_USAGES 12288 -#define HID_DEFAULT_NUM_COLLECTIONS 16 - -struct hid_local { - unsigned usage[HID_MAX_USAGES]; /* usage array */ - unsigned collection_index[HID_MAX_USAGES]; /* collection index array */ - unsigned usage_index; - unsigned usage_minimum; - unsigned delimiter_depth; - unsigned delimiter_branch; -}; - -/* - * This is the collection stack. We climb up the stack to determine - * application and function of each field. - */ - -struct hid_collection { - unsigned type; - unsigned usage; - unsigned level; -}; - -struct hid_usage { - unsigned hid; /* hid usage code */ - unsigned collection_index; /* index into collection array */ - unsigned usage_index; /* index into usage array */ - /* hidinput data */ - __u16 code; /* input driver code */ - __u8 type; /* input driver type */ - __s8 hat_min; /* hat switch fun */ - __s8 hat_max; /* ditto */ - __s8 hat_dir; /* ditto */ -}; - -struct hid_input; - -struct hid_field { - unsigned physical; /* physical usage for this field */ - unsigned logical; /* logical usage for this field */ - unsigned application; /* application usage for this field */ - struct hid_usage *usage; /* usage table for this function */ - unsigned maxusage; /* maximum usage index */ - unsigned flags; /* main-item flags (i.e. volatile,array,constant) */ - unsigned report_offset; /* bit offset in the report */ - unsigned report_size; /* size of this field in the report */ - unsigned report_count; /* number of this field in the report */ - unsigned report_type; /* (input,output,feature) */ - __s32 *value; /* last known value(s) */ - __s32 logical_minimum; - __s32 logical_maximum; - __s32 physical_minimum; - __s32 physical_maximum; - __s32 unit_exponent; - unsigned unit; - struct hid_report *report; /* associated report */ - unsigned index; /* index into report->field[] */ - /* hidinput data */ - struct hid_input *hidinput; /* associated input structure */ - __u16 dpad; /* dpad input code */ -}; - -#define HID_MAX_FIELDS 256 - -struct hid_report { - struct list_head list; - unsigned id; /* id of this report */ - unsigned type; /* report type */ - struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */ - unsigned maxfield; /* maximum valid field index */ - unsigned size; /* size of the report (bits) */ - struct hid_device *device; /* associated device */ -}; - -#define HID_MAX_IDS 256 - -struct hid_report_enum { - unsigned numbered; - struct list_head report_list; - struct hid_report *report_id_hash[HID_MAX_IDS]; -}; - -#define HID_MIN_BUFFER_SIZE 64 /* make sure there is at least a packet size of space */ -#define HID_MAX_BUFFER_SIZE 4096 /* 4kb */ -#define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */ -#define HID_OUTPUT_FIFO_SIZE 64 - -struct hid_control_fifo { - unsigned char dir; - struct hid_report *report; - char *raw_report; -}; - -struct hid_output_fifo { - struct hid_report *report; - char *raw_report; -}; - -#define HID_CLAIMED_INPUT 1 -#define HID_CLAIMED_HIDDEV 2 -#define HID_CLAIMED_HIDRAW 4 -#define HID_CLAIMED_DRIVER 8 - -#define HID_STAT_ADDED 1 -#define HID_STAT_PARSED 2 - -struct hid_input { - struct list_head list; - struct hid_report *report; - struct input_dev *input; -}; - -enum hid_type { - HID_TYPE_OTHER = 0, - HID_TYPE_USBMOUSE, - HID_TYPE_USBNONE -}; - -struct hid_driver; -struct hid_ll_driver; - -struct hid_device { /* device report descriptor */ - __u8 *dev_rdesc; - unsigned dev_rsize; - __u8 *rdesc; - unsigned rsize; - struct hid_collection *collection; /* List of HID collections */ - unsigned collection_size; /* Number of allocated hid_collections */ - unsigned maxcollection; /* Number of parsed collections */ - unsigned maxapplication; /* Number of applications */ - __u16 bus; /* BUS ID */ - __u16 group; /* Report group */ - __u32 vendor; /* Vendor ID */ - __u32 product; /* Product ID */ - __u32 version; /* HID version */ - enum hid_type type; /* device type (mouse, kbd, ...) */ - unsigned country; /* HID country */ - struct hid_report_enum report_enum[HID_REPORT_TYPES]; - struct work_struct led_work; /* delayed LED worker */ - - struct semaphore driver_lock; /* protects the current driver, except during input */ - struct semaphore driver_input_lock; /* protects the current driver */ - struct device dev; /* device */ - struct hid_driver *driver; - struct hid_ll_driver *ll_driver; - -#ifdef CONFIG_HID_BATTERY_STRENGTH - /* - * Power supply information for HID devices which report - * battery strength. power_supply was successfully registered if - * battery is non-NULL. - */ - struct power_supply *battery; - __s32 battery_min; - __s32 battery_max; - __s32 battery_report_type; - __s32 battery_report_id; -#endif - - unsigned int status; /* see STAT flags above */ - unsigned claimed; /* Claimed by hidinput, hiddev? */ - unsigned quirks; /* Various quirks the device can pull on us */ - bool io_started; /* Protected by driver_lock. If IO has started */ - - struct list_head inputs; /* The list of inputs */ - void *hiddev; /* The hiddev structure */ - void *hidraw; - int minor; /* Hiddev minor number */ - - int open; /* is the device open by anyone? */ - char name[128]; /* Device name */ - char phys[64]; /* Device physical location */ - char uniq[64]; /* Device unique identifier (serial #) */ - - void *driver_data; - - /* temporary hid_ff handling (until moved to the drivers) */ - int (*ff_init)(struct hid_device *); - - /* hiddev event handler */ - int (*hiddev_connect)(struct hid_device *, unsigned int); - void (*hiddev_disconnect)(struct hid_device *); - void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field, - struct hid_usage *, __s32); - void (*hiddev_report_event) (struct hid_device *, struct hid_report *); - - /* debugging support via debugfs */ - unsigned short debug; - struct dentry *debug_dir; - struct dentry *debug_rdesc; - struct dentry *debug_events; - struct list_head debug_list; - spinlock_t debug_list_lock; - wait_queue_head_t debug_wait; -}; - -#define to_hid_device(pdev) \ - container_of(pdev, struct hid_device, dev) - -static inline void *hid_get_drvdata(struct hid_device *hdev) -{ - return dev_get_drvdata(&hdev->dev); -} - -static inline void hid_set_drvdata(struct hid_device *hdev, void *data) -{ - dev_set_drvdata(&hdev->dev, data); -} - -#define HID_GLOBAL_STACK_SIZE 4 -#define HID_COLLECTION_STACK_SIZE 4 - -#define HID_SCAN_FLAG_MT_WIN_8 BIT(0) -#define HID_SCAN_FLAG_VENDOR_SPECIFIC BIT(1) -#define HID_SCAN_FLAG_GD_POINTER BIT(2) - -struct hid_parser { - struct hid_global global; - struct hid_global global_stack[HID_GLOBAL_STACK_SIZE]; - unsigned global_stack_ptr; - struct hid_local local; - unsigned collection_stack[HID_COLLECTION_STACK_SIZE]; - unsigned collection_stack_ptr; - struct hid_device *device; - unsigned scan_flags; -}; - -struct hid_class_descriptor { - __u8 bDescriptorType; - __le16 wDescriptorLength; -} __attribute__ ((packed)); - -struct hid_descriptor { - __u8 bLength; - __u8 bDescriptorType; - __le16 bcdHID; - __u8 bCountryCode; - __u8 bNumDescriptors; - - struct hid_class_descriptor desc[1]; -} __attribute__ ((packed)); - -#define HID_DEVICE(b, g, ven, prod) \ - .bus = (b), .group = (g), .vendor = (ven), .product = (prod) -#define HID_USB_DEVICE(ven, prod) \ - .bus = BUS_USB, .vendor = (ven), .product = (prod) -#define HID_BLUETOOTH_DEVICE(ven, prod) \ - .bus = BUS_BLUETOOTH, .vendor = (ven), .product = (prod) -#define HID_I2C_DEVICE(ven, prod) \ - .bus = BUS_I2C, .vendor = (ven), .product = (prod) - -#define HID_REPORT_ID(rep) \ - .report_type = (rep) -#define HID_USAGE_ID(uhid, utype, ucode) \ - .usage_hid = (uhid), .usage_type = (utype), .usage_code = (ucode) -/* we don't want to catch types and codes equal to 0 */ -#define HID_TERMINATOR (HID_ANY_ID - 1) - -struct hid_report_id { - __u32 report_type; -}; -struct hid_usage_id { - __u32 usage_hid; - __u32 usage_type; - __u32 usage_code; -}; - -/** - * struct hid_driver - * @name: driver name (e.g. "Footech_bar-wheel") - * @id_table: which devices is this driver for (must be non-NULL for probe - * to be called) - * @dyn_list: list of dynamically added device ids - * @dyn_lock: lock protecting @dyn_list - * @probe: new device inserted - * @remove: device removed (NULL if not a hot-plug capable driver) - * @report_table: on which reports to call raw_event (NULL means all) - * @raw_event: if report in report_table, this hook is called (NULL means nop) - * @usage_table: on which events to call event (NULL means all) - * @event: if usage in usage_table, this hook is called (NULL means nop) - * @report: this hook is called after parsing a report (NULL means nop) - * @report_fixup: called before report descriptor parsing (NULL means nop) - * @input_mapping: invoked on input registering before mapping an usage - * @input_mapped: invoked on input registering after mapping an usage - * @input_configured: invoked just before the device is registered - * @feature_mapping: invoked on feature registering - * @suspend: invoked on suspend (NULL means nop) - * @resume: invoked on resume if device was not reset (NULL means nop) - * @reset_resume: invoked on resume if device was reset (NULL means nop) - * - * probe should return -errno on error, or 0 on success. During probe, - * input will not be passed to raw_event unless hid_device_io_start is - * called. - * - * raw_event and event should return 0 on no action performed, 1 when no - * further processing should be done and negative on error - * - * input_mapping shall return a negative value to completely ignore this usage - * (e.g. doubled or invalid usage), zero to continue with parsing of this - * usage by generic code (no special handling needed) or positive to skip - * generic parsing (needed special handling which was done in the hook already) - * input_mapped shall return negative to inform the layer that this usage - * should not be considered for further processing or zero to notify that - * no processing was performed and should be done in a generic manner - * Both these functions may be NULL which means the same behavior as returning - * zero from them. - */ -struct hid_driver { - char *name; - const struct hid_device_id *id_table; - - struct list_head dyn_list; - spinlock_t dyn_lock; - - int (*probe)(struct hid_device *dev, const struct hid_device_id *id); - void (*remove)(struct hid_device *dev); - - const struct hid_report_id *report_table; - int (*raw_event)(struct hid_device *hdev, struct hid_report *report, - u8 *data, int size); - const struct hid_usage_id *usage_table; - int (*event)(struct hid_device *hdev, struct hid_field *field, - struct hid_usage *usage, __s32 value); - void (*report)(struct hid_device *hdev, struct hid_report *report); - - __u8 *(*report_fixup)(struct hid_device *hdev, __u8 *buf, - unsigned int *size); - - int (*input_mapping)(struct hid_device *hdev, - struct hid_input *hidinput, struct hid_field *field, - struct hid_usage *usage, unsigned long **bit, int *max); - int (*input_mapped)(struct hid_device *hdev, - struct hid_input *hidinput, struct hid_field *field, - struct hid_usage *usage, unsigned long **bit, int *max); - int (*input_configured)(struct hid_device *hdev, - struct hid_input *hidinput); - void (*feature_mapping)(struct hid_device *hdev, - struct hid_field *field, - struct hid_usage *usage); -#ifdef CONFIG_PM - int (*suspend)(struct hid_device *hdev, pm_message_t message); - int (*resume)(struct hid_device *hdev); - int (*reset_resume)(struct hid_device *hdev); -#endif -/* private: */ - struct device_driver driver; -}; - -#define to_hid_driver(pdrv) \ - container_of(pdrv, struct hid_driver, driver) - -/** - * hid_ll_driver - low level driver callbacks - * @start: called on probe to start the device - * @stop: called on remove - * @open: called by input layer on open - * @close: called by input layer on close - * @parse: this method is called only once to parse the device data, - * shouldn't allocate anything to not leak memory - * @request: send report request to device (e.g. feature report) - * @wait: wait for buffered io to complete (send/recv reports) - * @raw_request: send raw report request to device (e.g. feature report) - * @output_report: send output report to device - * @idle: send idle request to device - */ -struct hid_ll_driver { - int (*start)(struct hid_device *hdev); - void (*stop)(struct hid_device *hdev); - - int (*open)(struct hid_device *hdev); - void (*close)(struct hid_device *hdev); - - int (*power)(struct hid_device *hdev, int level); - - int (*parse)(struct hid_device *hdev); - - void (*request)(struct hid_device *hdev, - struct hid_report *report, int reqtype); - - int (*wait)(struct hid_device *hdev); - - int (*raw_request) (struct hid_device *hdev, unsigned char reportnum, - __u8 *buf, size_t len, unsigned char rtype, - int reqtype); - - int (*output_report) (struct hid_device *hdev, __u8 *buf, size_t len); - - int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype); -}; - -#define PM_HINT_FULLON 1<<5 -#define PM_HINT_NORMAL 1<<1 - -/* Applications from HID Usage Tables 4/8/99 Version 1.1 */ -/* We ignore a few input applications that are not widely used */ -#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001) || ((a >= 0x000d0002) && (a <= 0x000d0006))) - -/* HID core API */ - -extern int hid_debug; - -extern bool hid_ignore(struct hid_device *); -extern int hid_add_device(struct hid_device *); -extern void hid_destroy_device(struct hid_device *); - -extern int __must_check __hid_register_driver(struct hid_driver *, - struct module *, const char *mod_name); - -/* use a define to avoid include chaining to get THIS_MODULE & friends */ -#define hid_register_driver(driver) \ - __hid_register_driver(driver, THIS_MODULE, KBUILD_MODNAME) - -extern void hid_unregister_driver(struct hid_driver *); - -/** - * module_hid_driver() - Helper macro for registering a HID driver - * @__hid_driver: hid_driver struct - * - * Helper macro for HID drivers which do not do anything special in module - * init/exit. This eliminates a lot of boilerplate. Each module may only - * use this macro once, and calling it replaces module_init() and module_exit() - */ -#define module_hid_driver(__hid_driver) \ - module_driver(__hid_driver, hid_register_driver, \ - hid_unregister_driver) - -extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); -extern void hidinput_report_event(struct hid_device *hid, struct hid_report *report); -extern int hidinput_connect(struct hid_device *hid, unsigned int force); -extern void hidinput_disconnect(struct hid_device *); - -int hid_set_field(struct hid_field *, unsigned, __s32); -int hid_input_report(struct hid_device *, int type, u8 *, int, int); -int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field); -struct hid_field *hidinput_get_led_field(struct hid_device *hid); -unsigned int hidinput_count_leds(struct hid_device *hid); -__s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code); -void hid_output_report(struct hid_report *report, __u8 *data); -void __hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype); -u8 *hid_alloc_report_buf(struct hid_report *report, gfp_t flags); -struct hid_device *hid_allocate_device(void); -struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id); -int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size); -struct hid_report *hid_validate_values(struct hid_device *hid, - unsigned int type, unsigned int id, - unsigned int field_index, - unsigned int report_counts); -int hid_open_report(struct hid_device *device); -int hid_check_keys_pressed(struct hid_device *hid); -int hid_connect(struct hid_device *hid, unsigned int connect_mask); -void hid_disconnect(struct hid_device *hid); -const struct hid_device_id *hid_match_id(struct hid_device *hdev, - const struct hid_device_id *id); -s32 hid_snto32(__u32 value, unsigned n); -__u32 hid_field_extract(const struct hid_device *hid, __u8 *report, - unsigned offset, unsigned n); - -/** - * hid_device_io_start - enable HID input during probe, remove - * - * @hid - the device - * - * This should only be called during probe or remove and only be - * called by the thread calling probe or remove. It will allow - * incoming packets to be delivered to the driver. - */ -static inline void hid_device_io_start(struct hid_device *hid) { - if (hid->io_started) { - dev_warn(&hid->dev, "io already started\n"); - return; - } - hid->io_started = true; - up(&hid->driver_input_lock); -} - -/** - * hid_device_io_stop - disable HID input during probe, remove - * - * @hid - the device - * - * Should only be called after hid_device_io_start. It will prevent - * incoming packets from going to the driver for the duration of - * probe, remove. If called during probe, packets will still go to the - * driver after probe is complete. This function should only be called - * by the thread calling probe or remove. - */ -static inline void hid_device_io_stop(struct hid_device *hid) { - if (!hid->io_started) { - dev_warn(&hid->dev, "io already stopped\n"); - return; - } - hid->io_started = false; - down(&hid->driver_input_lock); -} - -/** - * hid_map_usage - map usage input bits - * - * @hidinput: hidinput which we are interested in - * @usage: usage to fill in - * @bit: pointer to input->{}bit (out parameter) - * @max: maximal valid usage->code to consider later (out parameter) - * @type: input event type (EV_KEY, EV_REL, ...) - * @c: code which corresponds to this usage and type - */ -static inline void hid_map_usage(struct hid_input *hidinput, - struct hid_usage *usage, unsigned long **bit, int *max, - __u8 type, __u16 c) -{ - struct input_dev *input = hidinput->input; - - usage->type = type; - usage->code = c; - - switch (type) { - case EV_ABS: - *bit = input->absbit; - *max = ABS_MAX; - break; - case EV_REL: - *bit = input->relbit; - *max = REL_MAX; - break; - case EV_KEY: - *bit = input->keybit; - *max = KEY_MAX; - break; - case EV_LED: - *bit = input->ledbit; - *max = LED_MAX; - break; - } -} - -/** - * hid_map_usage_clear - map usage input bits and clear the input bit - * - * The same as hid_map_usage, except the @c bit is also cleared in supported - * bits (@bit). - */ -static inline void hid_map_usage_clear(struct hid_input *hidinput, - struct hid_usage *usage, unsigned long **bit, int *max, - __u8 type, __u16 c) -{ - hid_map_usage(hidinput, usage, bit, max, type, c); - clear_bit(c, *bit); -} - -/** - * hid_parse - parse HW reports - * - * @hdev: hid device - * - * Call this from probe after you set up the device (if needed). Your - * report_fixup will be called (if non-NULL) after reading raw report from - * device before passing it to hid layer for real parsing. - */ -static inline int __must_check hid_parse(struct hid_device *hdev) -{ - return hid_open_report(hdev); -} - -/** - * hid_hw_start - start underlaying HW - * - * @hdev: hid device - * @connect_mask: which outputs to connect, see HID_CONNECT_* - * - * Call this in probe function *after* hid_parse. This will setup HW buffers - * and start the device (if not deffered to device open). hid_hw_stop must be - * called if this was successful. - */ -static inline int __must_check hid_hw_start(struct hid_device *hdev, - unsigned int connect_mask) -{ - int ret = hdev->ll_driver->start(hdev); - if (ret || !connect_mask) - return ret; - ret = hid_connect(hdev, connect_mask); - if (ret) - hdev->ll_driver->stop(hdev); - return ret; -} - -/** - * hid_hw_stop - stop underlaying HW - * - * @hdev: hid device - * - * This is usually called from remove function or from probe when something - * failed and hid_hw_start was called already. - */ -static inline void hid_hw_stop(struct hid_device *hdev) -{ - hid_disconnect(hdev); - hdev->ll_driver->stop(hdev); -} - -/** - * hid_hw_open - signal underlaying HW to start delivering events - * - * @hdev: hid device - * - * Tell underlying HW to start delivering events from the device. - * This function should be called sometime after successful call - * to hid_hiw_start(). - */ -static inline int __must_check hid_hw_open(struct hid_device *hdev) -{ - return hdev->ll_driver->open(hdev); -} - -/** - * hid_hw_close - signal underlaying HW to stop delivering events - * - * @hdev: hid device - * - * This function indicates that we are not interested in the events - * from this device anymore. Delivery of events may or may not stop, - * depending on the number of users still outstanding. - */ -static inline void hid_hw_close(struct hid_device *hdev) -{ - hdev->ll_driver->close(hdev); -} - -/** - * hid_hw_power - requests underlying HW to go into given power mode - * - * @hdev: hid device - * @level: requested power level (one of %PM_HINT_* defines) - * - * This function requests underlying hardware to enter requested power - * mode. - */ - -static inline int hid_hw_power(struct hid_device *hdev, int level) -{ - return hdev->ll_driver->power ? hdev->ll_driver->power(hdev, level) : 0; -} - - -/** - * hid_hw_request - send report request to device - * - * @hdev: hid device - * @report: report to send - * @reqtype: hid request type - */ -static inline void hid_hw_request(struct hid_device *hdev, - struct hid_report *report, int reqtype) -{ - if (hdev->ll_driver->request) - return hdev->ll_driver->request(hdev, report, reqtype); - - __hid_request(hdev, report, reqtype); -} - -/** - * hid_hw_raw_request - send report request to device - * - * @hdev: hid device - * @reportnum: report ID - * @buf: in/out data to transfer - * @len: length of buf - * @rtype: HID report type - * @reqtype: HID_REQ_GET_REPORT or HID_REQ_SET_REPORT - * - * @return: count of data transfered, negative if error - * - * Same behavior as hid_hw_request, but with raw buffers instead. - */ -static inline int hid_hw_raw_request(struct hid_device *hdev, - unsigned char reportnum, __u8 *buf, - size_t len, unsigned char rtype, int reqtype) -{ - if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf) - return -EINVAL; - - return hdev->ll_driver->raw_request(hdev, reportnum, buf, len, - rtype, reqtype); -} - -/** - * hid_hw_output_report - send output report to device - * - * @hdev: hid device - * @buf: raw data to transfer - * @len: length of buf - * - * @return: count of data transfered, negative if error - */ -static inline int hid_hw_output_report(struct hid_device *hdev, __u8 *buf, - size_t len) -{ - if (len < 1 || len > HID_MAX_BUFFER_SIZE || !buf) - return -EINVAL; - - if (hdev->ll_driver->output_report) - return hdev->ll_driver->output_report(hdev, buf, len); - - return -ENOSYS; -} - -/** - * hid_hw_idle - send idle request to device - * - * @hdev: hid device - * @report: report to control - * @idle: idle state - * @reqtype: hid request type - */ -static inline int hid_hw_idle(struct hid_device *hdev, int report, int idle, - int reqtype) -{ - if (hdev->ll_driver->idle) - return hdev->ll_driver->idle(hdev, report, idle, reqtype); - - return 0; -} - -/** - * hid_hw_wait - wait for buffered io to complete - * - * @hdev: hid device - */ -static inline void hid_hw_wait(struct hid_device *hdev) -{ - if (hdev->ll_driver->wait) - hdev->ll_driver->wait(hdev); -} - -/** - * hid_report_len - calculate the report length - * - * @report: the report we want to know the length - */ -static inline int hid_report_len(struct hid_report *report) -{ - /* equivalent to DIV_ROUND_UP(report->size, 8) + !!(report->id > 0) */ - return ((report->size - 1) >> 3) + 1 + (report->id > 0); -} - -int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size, - int interrupt); - -/* HID quirks API */ -u32 usbhid_lookup_quirk(const u16 idVendor, const u16 idProduct); -int usbhid_quirks_init(char **quirks_param); -void usbhid_quirks_exit(void); - -#ifdef CONFIG_HID_PID -int hid_pidff_init(struct hid_device *hid); -#else -#define hid_pidff_init NULL -#endif - -#define dbg_hid(format, arg...) \ -do { \ - if (hid_debug) \ - printk(KERN_DEBUG "%s: " format, __FILE__, ##arg); \ -} while (0) - -#define hid_printk(level, hid, fmt, arg...) \ - dev_printk(level, &(hid)->dev, fmt, ##arg) -#define hid_emerg(hid, fmt, arg...) \ - dev_emerg(&(hid)->dev, fmt, ##arg) -#define hid_crit(hid, fmt, arg...) \ - dev_crit(&(hid)->dev, fmt, ##arg) -#define hid_alert(hid, fmt, arg...) \ - dev_alert(&(hid)->dev, fmt, ##arg) -#define hid_err(hid, fmt, arg...) \ - dev_err(&(hid)->dev, fmt, ##arg) -#define hid_notice(hid, fmt, arg...) \ - dev_notice(&(hid)->dev, fmt, ##arg) -#define hid_warn(hid, fmt, arg...) \ - dev_warn(&(hid)->dev, fmt, ##arg) -#define hid_info(hid, fmt, arg...) \ - dev_info(&(hid)->dev, fmt, ##arg) -#define hid_dbg(hid, fmt, arg...) \ - dev_dbg(&(hid)->dev, fmt, ##arg) - -#endif diff --git a/src/linux/include/linux/hiddev.h b/src/linux/include/linux/hiddev.h deleted file mode 100644 index a5dd814..0000000 --- a/src/linux/include/linux/hiddev.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 1999-2000 Vojtech Pavlik - * - * Sponsored by SuSE - */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ -#ifndef _HIDDEV_H -#define _HIDDEV_H - -#include - - -/* - * In-kernel definitions. - */ - -struct hid_device; -struct hid_usage; -struct hid_field; -struct hid_report; - -#ifdef CONFIG_USB_HIDDEV -int hiddev_connect(struct hid_device *hid, unsigned int force); -void hiddev_disconnect(struct hid_device *); -void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, - struct hid_usage *usage, __s32 value); -void hiddev_report_event(struct hid_device *hid, struct hid_report *report); -#else -static inline int hiddev_connect(struct hid_device *hid, - unsigned int force) -{ return -1; } -static inline void hiddev_disconnect(struct hid_device *hid) { } -static inline void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, - struct hid_usage *usage, __s32 value) { } -static inline void hiddev_report_event(struct hid_device *hid, struct hid_report *report) { } -#endif - -#endif diff --git a/src/linux/include/linux/hidraw.h b/src/linux/include/linux/hidraw.h deleted file mode 100644 index ddf5261..0000000 --- a/src/linux/include/linux/hidraw.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2007 Jiri Kosina - */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef _HIDRAW_H -#define _HIDRAW_H - -#include - - -struct hidraw { - unsigned int minor; - int exist; - int open; - wait_queue_head_t wait; - struct hid_device *hid; - struct device *dev; - spinlock_t list_lock; - struct list_head list; -}; - -struct hidraw_report { - __u8 *value; - int len; -}; - -struct hidraw_list { - struct hidraw_report buffer[HIDRAW_BUFFER_SIZE]; - int head; - int tail; - struct fasync_struct *fasync; - struct hidraw *hidraw; - struct list_head node; - struct mutex read_mutex; -}; - -#ifdef CONFIG_HIDRAW -int hidraw_init(void); -void hidraw_exit(void); -int hidraw_report_event(struct hid_device *, u8 *, int); -int hidraw_connect(struct hid_device *); -void hidraw_disconnect(struct hid_device *); -#else -static inline int hidraw_init(void) { return 0; } -static inline void hidraw_exit(void) { } -static inline int hidraw_report_event(struct hid_device *hid, u8 *data, int len) { return 0; } -static inline int hidraw_connect(struct hid_device *hid) { return -1; } -static inline void hidraw_disconnect(struct hid_device *hid) { } -#endif - -#endif diff --git a/src/linux/include/linux/highmem.h b/src/linux/include/linux/highmem.h deleted file mode 100644 index bb3f329..0000000 --- a/src/linux/include/linux/highmem.h +++ /dev/null @@ -1,250 +0,0 @@ -#ifndef _LINUX_HIGHMEM_H -#define _LINUX_HIGHMEM_H - -#include -#include -#include -#include -#include -#include - -#include - -#ifndef ARCH_HAS_FLUSH_ANON_PAGE -static inline void flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr) -{ -} -#endif - -#ifndef ARCH_HAS_FLUSH_KERNEL_DCACHE_PAGE -static inline void flush_kernel_dcache_page(struct page *page) -{ -} -static inline void flush_kernel_vmap_range(void *vaddr, int size) -{ -} -static inline void invalidate_kernel_vmap_range(void *vaddr, int size) -{ -} -#endif - -#include - -#ifdef CONFIG_HIGHMEM -#include - -/* declarations for linux/mm/highmem.c */ -unsigned int nr_free_highpages(void); -extern unsigned long totalhigh_pages; - -void kmap_flush_unused(void); - -struct page *kmap_to_page(void *addr); - -#else /* CONFIG_HIGHMEM */ - -static inline unsigned int nr_free_highpages(void) { return 0; } - -static inline struct page *kmap_to_page(void *addr) -{ - return virt_to_page(addr); -} - -#define totalhigh_pages 0UL - -#ifndef ARCH_HAS_KMAP -static inline void *kmap(struct page *page) -{ - might_sleep(); - return page_address(page); -} - -static inline void kunmap(struct page *page) -{ -} - -static inline void *kmap_atomic(struct page *page) -{ - preempt_disable(); - pagefault_disable(); - return page_address(page); -} -#define kmap_atomic_prot(page, prot) kmap_atomic(page) - -static inline void __kunmap_atomic(void *addr) -{ - pagefault_enable(); - preempt_enable(); -} - -#define kmap_atomic_pfn(pfn) kmap_atomic(pfn_to_page(pfn)) - -#define kmap_flush_unused() do {} while(0) -#endif - -#endif /* CONFIG_HIGHMEM */ - -#if defined(CONFIG_HIGHMEM) || defined(CONFIG_X86_32) - -DECLARE_PER_CPU(int, __kmap_atomic_idx); - -static inline int kmap_atomic_idx_push(void) -{ - int idx = __this_cpu_inc_return(__kmap_atomic_idx) - 1; - -#ifdef CONFIG_DEBUG_HIGHMEM - WARN_ON_ONCE(in_irq() && !irqs_disabled()); - BUG_ON(idx >= KM_TYPE_NR); -#endif - return idx; -} - -static inline int kmap_atomic_idx(void) -{ - return __this_cpu_read(__kmap_atomic_idx) - 1; -} - -static inline void kmap_atomic_idx_pop(void) -{ -#ifdef CONFIG_DEBUG_HIGHMEM - int idx = __this_cpu_dec_return(__kmap_atomic_idx); - - BUG_ON(idx < 0); -#else - __this_cpu_dec(__kmap_atomic_idx); -#endif -} - -#endif - -/* - * Prevent people trying to call kunmap_atomic() as if it were kunmap() - * kunmap_atomic() should get the return value of kmap_atomic, not the page. - */ -#define kunmap_atomic(addr) \ -do { \ - BUILD_BUG_ON(__same_type((addr), struct page *)); \ - __kunmap_atomic(addr); \ -} while (0) - - -/* when CONFIG_HIGHMEM is not set these will be plain clear/copy_page */ -#ifndef clear_user_highpage -static inline void clear_user_highpage(struct page *page, unsigned long vaddr) -{ - void *addr = kmap_atomic(page); - clear_user_page(addr, vaddr, page); - kunmap_atomic(addr); -} -#endif - -#ifndef __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE -/** - * __alloc_zeroed_user_highpage - Allocate a zeroed HIGHMEM page for a VMA with caller-specified movable GFP flags - * @movableflags: The GFP flags related to the pages future ability to move like __GFP_MOVABLE - * @vma: The VMA the page is to be allocated for - * @vaddr: The virtual address the page will be inserted into - * - * This function will allocate a page for a VMA but the caller is expected - * to specify via movableflags whether the page will be movable in the - * future or not - * - * An architecture may override this function by defining - * __HAVE_ARCH_ALLOC_ZEROED_USER_HIGHPAGE and providing their own - * implementation. - */ -static inline struct page * -__alloc_zeroed_user_highpage(gfp_t movableflags, - struct vm_area_struct *vma, - unsigned long vaddr) -{ - struct page *page = alloc_page_vma(GFP_HIGHUSER | movableflags, - vma, vaddr); - - if (page) - clear_user_highpage(page, vaddr); - - return page; -} -#endif - -/** - * alloc_zeroed_user_highpage_movable - Allocate a zeroed HIGHMEM page for a VMA that the caller knows can move - * @vma: The VMA the page is to be allocated for - * @vaddr: The virtual address the page will be inserted into - * - * This function will allocate a page for a VMA that the caller knows will - * be able to migrate in the future using move_pages() or reclaimed - */ -static inline struct page * -alloc_zeroed_user_highpage_movable(struct vm_area_struct *vma, - unsigned long vaddr) -{ - return __alloc_zeroed_user_highpage(__GFP_MOVABLE, vma, vaddr); -} - -static inline void clear_highpage(struct page *page) -{ - void *kaddr = kmap_atomic(page); - clear_page(kaddr); - kunmap_atomic(kaddr); -} - -static inline void zero_user_segments(struct page *page, - unsigned start1, unsigned end1, - unsigned start2, unsigned end2) -{ - void *kaddr = kmap_atomic(page); - - BUG_ON(end1 > PAGE_SIZE || end2 > PAGE_SIZE); - - if (end1 > start1) - memset(kaddr + start1, 0, end1 - start1); - - if (end2 > start2) - memset(kaddr + start2, 0, end2 - start2); - - kunmap_atomic(kaddr); - flush_dcache_page(page); -} - -static inline void zero_user_segment(struct page *page, - unsigned start, unsigned end) -{ - zero_user_segments(page, start, end, 0, 0); -} - -static inline void zero_user(struct page *page, - unsigned start, unsigned size) -{ - zero_user_segments(page, start, start + size, 0, 0); -} - -#ifndef __HAVE_ARCH_COPY_USER_HIGHPAGE - -static inline void copy_user_highpage(struct page *to, struct page *from, - unsigned long vaddr, struct vm_area_struct *vma) -{ - char *vfrom, *vto; - - vfrom = kmap_atomic(from); - vto = kmap_atomic(to); - copy_user_page(vto, vfrom, vaddr, to); - kunmap_atomic(vto); - kunmap_atomic(vfrom); -} - -#endif - -static inline void copy_highpage(struct page *to, struct page *from) -{ - char *vfrom, *vto; - - vfrom = kmap_atomic(from); - vto = kmap_atomic(to); - copy_page(vto, vfrom); - kunmap_atomic(vto); - kunmap_atomic(vfrom); -} - -#endif /* _LINUX_HIGHMEM_H */ diff --git a/src/linux/include/linux/highuid.h b/src/linux/include/linux/highuid.h deleted file mode 100644 index 434e562..0000000 --- a/src/linux/include/linux/highuid.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef _LINUX_HIGHUID_H -#define _LINUX_HIGHUID_H - -#include - -/* - * general notes: - * - * CONFIG_UID16 is defined if the given architecture needs to - * support backwards compatibility for old system calls. - * - * kernel code should use uid_t and gid_t at all times when dealing with - * kernel-private data. - * - * old_uid_t and old_gid_t should only be different if CONFIG_UID16 is - * defined, else the platform should provide dummy typedefs for them - * such that they are equivalent to __kernel_{u,g}id_t. - * - * uid16_t and gid16_t are used on all architectures. (when dealing - * with structures hard coded to 16 bits, such as in filesystems) - */ - - -/* - * This is the "overflow" UID and GID. They are used to signify uid/gid - * overflow to old programs when they request uid/gid information but are - * using the old 16 bit interfaces. - * When you run a libc5 program, it will think that all highuid files or - * processes are owned by this uid/gid. - * The idea is that it's better to do so than possibly return 0 in lieu of - * 65536, etc. - */ - -extern int overflowuid; -extern int overflowgid; - -extern void __bad_uid(void); -extern void __bad_gid(void); - -#define DEFAULT_OVERFLOWUID 65534 -#define DEFAULT_OVERFLOWGID 65534 - -#ifdef CONFIG_UID16 - -/* prevent uid mod 65536 effect by returning a default value for high UIDs */ -#define high2lowuid(uid) ((uid) & ~0xFFFF ? (old_uid_t)overflowuid : (old_uid_t)(uid)) -#define high2lowgid(gid) ((gid) & ~0xFFFF ? (old_gid_t)overflowgid : (old_gid_t)(gid)) -/* - * -1 is different in 16 bits than it is in 32 bits - * these macros are used by chown(), setreuid(), ..., - */ -#define low2highuid(uid) ((uid) == (old_uid_t)-1 ? (uid_t)-1 : (uid_t)(uid)) -#define low2highgid(gid) ((gid) == (old_gid_t)-1 ? (gid_t)-1 : (gid_t)(gid)) - -#define __convert_uid(size, uid) \ - (size >= sizeof(uid) ? (uid) : high2lowuid(uid)) -#define __convert_gid(size, gid) \ - (size >= sizeof(gid) ? (gid) : high2lowgid(gid)) - - -#else - -#define __convert_uid(size, uid) (uid) -#define __convert_gid(size, gid) (gid) - -#endif /* !CONFIG_UID16 */ - -/* uid/gid input should be always 32bit uid_t */ -#define SET_UID(var, uid) do { (var) = __convert_uid(sizeof(var), (uid)); } while (0) -#define SET_GID(var, gid) do { (var) = __convert_gid(sizeof(var), (gid)); } while (0) - -/* - * Everything below this line is needed on all architectures, to deal with - * filesystems that only store 16 bits of the UID/GID, etc. - */ - -/* - * This is the UID and GID that will get written to disk if a filesystem - * only supports 16-bit UIDs and the kernel has a high UID/GID to write - */ -extern int fs_overflowuid; -extern int fs_overflowgid; - -#define DEFAULT_FS_OVERFLOWUID 65534 -#define DEFAULT_FS_OVERFLOWGID 65534 - -/* - * Since these macros are used in architectures that only need limited - * 16-bit UID back compatibility, we won't use old_uid_t and old_gid_t - */ -#define fs_high2lowuid(uid) ((uid) & ~0xFFFF ? (uid16_t)fs_overflowuid : (uid16_t)(uid)) -#define fs_high2lowgid(gid) ((gid) & ~0xFFFF ? (gid16_t)fs_overflowgid : (gid16_t)(gid)) - -#define low_16_bits(x) ((x) & 0xFFFF) -#define high_16_bits(x) (((x) & 0xFFFF0000) >> 16) - -#endif /* _LINUX_HIGHUID_H */ diff --git a/src/linux/include/linux/hrtimer.h b/src/linux/include/linux/hrtimer.h deleted file mode 100644 index 5e00f80..0000000 --- a/src/linux/include/linux/hrtimer.h +++ /dev/null @@ -1,504 +0,0 @@ -/* - * include/linux/hrtimer.h - * - * hrtimers - High-resolution kernel timers - * - * Copyright(C) 2005, Thomas Gleixner - * Copyright(C) 2005, Red Hat, Inc., Ingo Molnar - * - * data type definitions, declarations, prototypes - * - * Started by: Thomas Gleixner and Ingo Molnar - * - * For licencing details see kernel-base/COPYING - */ -#ifndef _LINUX_HRTIMER_H -#define _LINUX_HRTIMER_H - -#include -#include -#include -#include -#include -#include -#include -#include - -struct hrtimer_clock_base; -struct hrtimer_cpu_base; - -/* - * Mode arguments of xxx_hrtimer functions: - */ -enum hrtimer_mode { - HRTIMER_MODE_ABS = 0x0, /* Time value is absolute */ - HRTIMER_MODE_REL = 0x1, /* Time value is relative to now */ - HRTIMER_MODE_PINNED = 0x02, /* Timer is bound to CPU */ - HRTIMER_MODE_ABS_PINNED = 0x02, - HRTIMER_MODE_REL_PINNED = 0x03, -}; - -/* - * Return values for the callback function - */ -enum hrtimer_restart { - HRTIMER_NORESTART, /* Timer is not restarted */ - HRTIMER_RESTART, /* Timer must be restarted */ -}; - -/* - * Values to track state of the timer - * - * Possible states: - * - * 0x00 inactive - * 0x01 enqueued into rbtree - * - * The callback state is not part of the timer->state because clearing it would - * mean touching the timer after the callback, this makes it impossible to free - * the timer from the callback function. - * - * Therefore we track the callback state in: - * - * timer->base->cpu_base->running == timer - * - * On SMP it is possible to have a "callback function running and enqueued" - * status. It happens for example when a posix timer expired and the callback - * queued a signal. Between dropping the lock which protects the posix timer - * and reacquiring the base lock of the hrtimer, another CPU can deliver the - * signal and rearm the timer. - * - * All state transitions are protected by cpu_base->lock. - */ -#define HRTIMER_STATE_INACTIVE 0x00 -#define HRTIMER_STATE_ENQUEUED 0x01 - -/** - * struct hrtimer - the basic hrtimer structure - * @node: timerqueue node, which also manages node.expires, - * the absolute expiry time in the hrtimers internal - * representation. The time is related to the clock on - * which the timer is based. Is setup by adding - * slack to the _softexpires value. For non range timers - * identical to _softexpires. - * @_softexpires: the absolute earliest expiry time of the hrtimer. - * The time which was given as expiry time when the timer - * was armed. - * @function: timer expiry callback function - * @base: pointer to the timer base (per cpu and per clock) - * @state: state information (See bit values above) - * @is_rel: Set if the timer was armed relative - * @start_pid: timer statistics field to store the pid of the task which - * started the timer - * @start_site: timer statistics field to store the site where the timer - * was started - * @start_comm: timer statistics field to store the name of the process which - * started the timer - * - * The hrtimer structure must be initialized by hrtimer_init() - */ -struct hrtimer { - struct timerqueue_node node; - ktime_t _softexpires; - enum hrtimer_restart (*function)(struct hrtimer *); - struct hrtimer_clock_base *base; - u8 state; - u8 is_rel; -#ifdef CONFIG_TIMER_STATS - int start_pid; - void *start_site; - char start_comm[16]; -#endif -}; - -/** - * struct hrtimer_sleeper - simple sleeper structure - * @timer: embedded timer structure - * @task: task to wake up - * - * task is set to NULL, when the timer expires. - */ -struct hrtimer_sleeper { - struct hrtimer timer; - struct task_struct *task; -}; - -#ifdef CONFIG_64BIT -# define HRTIMER_CLOCK_BASE_ALIGN 64 -#else -# define HRTIMER_CLOCK_BASE_ALIGN 32 -#endif - -/** - * struct hrtimer_clock_base - the timer base for a specific clock - * @cpu_base: per cpu clock base - * @index: clock type index for per_cpu support when moving a - * timer to a base on another cpu. - * @clockid: clock id for per_cpu support - * @active: red black tree root node for the active timers - * @get_time: function to retrieve the current time of the clock - * @offset: offset of this clock to the monotonic base - */ -struct hrtimer_clock_base { - struct hrtimer_cpu_base *cpu_base; - int index; - clockid_t clockid; - struct timerqueue_head active; - ktime_t (*get_time)(void); - ktime_t offset; -} __attribute__((__aligned__(HRTIMER_CLOCK_BASE_ALIGN))); - -enum hrtimer_base_type { - HRTIMER_BASE_MONOTONIC, - HRTIMER_BASE_REALTIME, - HRTIMER_BASE_BOOTTIME, - HRTIMER_BASE_TAI, - HRTIMER_MAX_CLOCK_BASES, -}; - -/* - * struct hrtimer_cpu_base - the per cpu clock bases - * @lock: lock protecting the base and associated clock bases - * and timers - * @seq: seqcount around __run_hrtimer - * @running: pointer to the currently running hrtimer - * @cpu: cpu number - * @active_bases: Bitfield to mark bases with active timers - * @clock_was_set_seq: Sequence counter of clock was set events - * @migration_enabled: The migration of hrtimers to other cpus is enabled - * @nohz_active: The nohz functionality is enabled - * @expires_next: absolute time of the next event which was scheduled - * via clock_set_next_event() - * @next_timer: Pointer to the first expiring timer - * @in_hrtirq: hrtimer_interrupt() is currently executing - * @hres_active: State of high resolution mode - * @hang_detected: The last hrtimer interrupt detected a hang - * @nr_events: Total number of hrtimer interrupt events - * @nr_retries: Total number of hrtimer interrupt retries - * @nr_hangs: Total number of hrtimer interrupt hangs - * @max_hang_time: Maximum time spent in hrtimer_interrupt - * @clock_base: array of clock bases for this cpu - * - * Note: next_timer is just an optimization for __remove_hrtimer(). - * Do not dereference the pointer because it is not reliable on - * cross cpu removals. - */ -struct hrtimer_cpu_base { - raw_spinlock_t lock; - seqcount_t seq; - struct hrtimer *running; - unsigned int cpu; - unsigned int active_bases; - unsigned int clock_was_set_seq; - bool migration_enabled; - bool nohz_active; -#ifdef CONFIG_HIGH_RES_TIMERS - unsigned int in_hrtirq : 1, - hres_active : 1, - hang_detected : 1; - ktime_t expires_next; - struct hrtimer *next_timer; - unsigned int nr_events; - unsigned int nr_retries; - unsigned int nr_hangs; - unsigned int max_hang_time; -#endif - struct hrtimer_clock_base clock_base[HRTIMER_MAX_CLOCK_BASES]; -} ____cacheline_aligned; - -static inline void hrtimer_set_expires(struct hrtimer *timer, ktime_t time) -{ - BUILD_BUG_ON(sizeof(struct hrtimer_clock_base) > HRTIMER_CLOCK_BASE_ALIGN); - - timer->node.expires = time; - timer->_softexpires = time; -} - -static inline void hrtimer_set_expires_range(struct hrtimer *timer, ktime_t time, ktime_t delta) -{ - timer->_softexpires = time; - timer->node.expires = ktime_add_safe(time, delta); -} - -static inline void hrtimer_set_expires_range_ns(struct hrtimer *timer, ktime_t time, u64 delta) -{ - timer->_softexpires = time; - timer->node.expires = ktime_add_safe(time, ns_to_ktime(delta)); -} - -static inline void hrtimer_set_expires_tv64(struct hrtimer *timer, s64 tv64) -{ - timer->node.expires.tv64 = tv64; - timer->_softexpires.tv64 = tv64; -} - -static inline void hrtimer_add_expires(struct hrtimer *timer, ktime_t time) -{ - timer->node.expires = ktime_add_safe(timer->node.expires, time); - timer->_softexpires = ktime_add_safe(timer->_softexpires, time); -} - -static inline void hrtimer_add_expires_ns(struct hrtimer *timer, u64 ns) -{ - timer->node.expires = ktime_add_ns(timer->node.expires, ns); - timer->_softexpires = ktime_add_ns(timer->_softexpires, ns); -} - -static inline ktime_t hrtimer_get_expires(const struct hrtimer *timer) -{ - return timer->node.expires; -} - -static inline ktime_t hrtimer_get_softexpires(const struct hrtimer *timer) -{ - return timer->_softexpires; -} - -static inline s64 hrtimer_get_expires_tv64(const struct hrtimer *timer) -{ - return timer->node.expires.tv64; -} -static inline s64 hrtimer_get_softexpires_tv64(const struct hrtimer *timer) -{ - return timer->_softexpires.tv64; -} - -static inline s64 hrtimer_get_expires_ns(const struct hrtimer *timer) -{ - return ktime_to_ns(timer->node.expires); -} - -static inline ktime_t hrtimer_expires_remaining(const struct hrtimer *timer) -{ - return ktime_sub(timer->node.expires, timer->base->get_time()); -} - -static inline ktime_t hrtimer_cb_get_time(struct hrtimer *timer) -{ - return timer->base->get_time(); -} - -#ifdef CONFIG_HIGH_RES_TIMERS -struct clock_event_device; - -extern void hrtimer_interrupt(struct clock_event_device *dev); - -static inline int hrtimer_is_hres_active(struct hrtimer *timer) -{ - return timer->base->cpu_base->hres_active; -} - -extern void hrtimer_peek_ahead_timers(void); - -/* - * The resolution of the clocks. The resolution value is returned in - * the clock_getres() system call to give application programmers an - * idea of the (in)accuracy of timers. Timer values are rounded up to - * this resolution values. - */ -# define HIGH_RES_NSEC 1 -# define KTIME_HIGH_RES (ktime_t) { .tv64 = HIGH_RES_NSEC } -# define MONOTONIC_RES_NSEC HIGH_RES_NSEC -# define KTIME_MONOTONIC_RES KTIME_HIGH_RES - -extern void clock_was_set_delayed(void); - -extern unsigned int hrtimer_resolution; - -#else - -# define MONOTONIC_RES_NSEC LOW_RES_NSEC -# define KTIME_MONOTONIC_RES KTIME_LOW_RES - -#define hrtimer_resolution (unsigned int)LOW_RES_NSEC - -static inline void hrtimer_peek_ahead_timers(void) { } - -static inline int hrtimer_is_hres_active(struct hrtimer *timer) -{ - return 0; -} - -static inline void clock_was_set_delayed(void) { } - -#endif - -static inline ktime_t -__hrtimer_expires_remaining_adjusted(const struct hrtimer *timer, ktime_t now) -{ - ktime_t rem = ktime_sub(timer->node.expires, now); - - /* - * Adjust relative timers for the extra we added in - * hrtimer_start_range_ns() to prevent short timeouts. - */ - if (IS_ENABLED(CONFIG_TIME_LOW_RES) && timer->is_rel) - rem.tv64 -= hrtimer_resolution; - return rem; -} - -static inline ktime_t -hrtimer_expires_remaining_adjusted(const struct hrtimer *timer) -{ - return __hrtimer_expires_remaining_adjusted(timer, - timer->base->get_time()); -} - -extern void clock_was_set(void); -#ifdef CONFIG_TIMERFD -extern void timerfd_clock_was_set(void); -#else -static inline void timerfd_clock_was_set(void) { } -#endif -extern void hrtimers_resume(void); - -DECLARE_PER_CPU(struct tick_device, tick_cpu_device); - - -/* Exported timer functions: */ - -/* Initialize timers: */ -extern void hrtimer_init(struct hrtimer *timer, clockid_t which_clock, - enum hrtimer_mode mode); - -#ifdef CONFIG_DEBUG_OBJECTS_TIMERS -extern void hrtimer_init_on_stack(struct hrtimer *timer, clockid_t which_clock, - enum hrtimer_mode mode); - -extern void destroy_hrtimer_on_stack(struct hrtimer *timer); -#else -static inline void hrtimer_init_on_stack(struct hrtimer *timer, - clockid_t which_clock, - enum hrtimer_mode mode) -{ - hrtimer_init(timer, which_clock, mode); -} -static inline void destroy_hrtimer_on_stack(struct hrtimer *timer) { } -#endif - -/* Basic timer operations: */ -extern void hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, - u64 range_ns, const enum hrtimer_mode mode); - -/** - * hrtimer_start - (re)start an hrtimer on the current CPU - * @timer: the timer to be added - * @tim: expiry time - * @mode: expiry mode: absolute (HRTIMER_MODE_ABS) or - * relative (HRTIMER_MODE_REL) - */ -static inline void hrtimer_start(struct hrtimer *timer, ktime_t tim, - const enum hrtimer_mode mode) -{ - hrtimer_start_range_ns(timer, tim, 0, mode); -} - -extern int hrtimer_cancel(struct hrtimer *timer); -extern int hrtimer_try_to_cancel(struct hrtimer *timer); - -static inline void hrtimer_start_expires(struct hrtimer *timer, - enum hrtimer_mode mode) -{ - u64 delta; - ktime_t soft, hard; - soft = hrtimer_get_softexpires(timer); - hard = hrtimer_get_expires(timer); - delta = ktime_to_ns(ktime_sub(hard, soft)); - hrtimer_start_range_ns(timer, soft, delta, mode); -} - -static inline void hrtimer_restart(struct hrtimer *timer) -{ - hrtimer_start_expires(timer, HRTIMER_MODE_ABS); -} - -/* Query timers: */ -extern ktime_t __hrtimer_get_remaining(const struct hrtimer *timer, bool adjust); - -static inline ktime_t hrtimer_get_remaining(const struct hrtimer *timer) -{ - return __hrtimer_get_remaining(timer, false); -} - -extern u64 hrtimer_get_next_event(void); - -extern bool hrtimer_active(const struct hrtimer *timer); - -/* - * Helper function to check, whether the timer is on one of the queues - */ -static inline int hrtimer_is_queued(struct hrtimer *timer) -{ - return timer->state & HRTIMER_STATE_ENQUEUED; -} - -/* - * Helper function to check, whether the timer is running the callback - * function - */ -static inline int hrtimer_callback_running(struct hrtimer *timer) -{ - return timer->base->cpu_base->running == timer; -} - -/* Forward a hrtimer so it expires after now: */ -extern u64 -hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval); - -/** - * hrtimer_forward_now - forward the timer expiry so it expires after now - * @timer: hrtimer to forward - * @interval: the interval to forward - * - * Forward the timer expiry so it will expire after the current time - * of the hrtimer clock base. Returns the number of overruns. - * - * Can be safely called from the callback function of @timer. If - * called from other contexts @timer must neither be enqueued nor - * running the callback and the caller needs to take care of - * serialization. - * - * Note: This only updates the timer expiry value and does not requeue - * the timer. - */ -static inline u64 hrtimer_forward_now(struct hrtimer *timer, - ktime_t interval) -{ - return hrtimer_forward(timer, timer->base->get_time(), interval); -} - -/* Precise sleep: */ -extern long hrtimer_nanosleep(struct timespec *rqtp, - struct timespec __user *rmtp, - const enum hrtimer_mode mode, - const clockid_t clockid); -extern long hrtimer_nanosleep_restart(struct restart_block *restart_block); - -extern void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, - struct task_struct *tsk); - -extern int schedule_hrtimeout_range(ktime_t *expires, u64 delta, - const enum hrtimer_mode mode); -extern int schedule_hrtimeout_range_clock(ktime_t *expires, - u64 delta, - const enum hrtimer_mode mode, - int clock); -extern int schedule_hrtimeout(ktime_t *expires, const enum hrtimer_mode mode); - -/* Soft interrupt function to run the hrtimer queues: */ -extern void hrtimer_run_queues(void); - -/* Bootup initialization: */ -extern void __init hrtimers_init(void); - -/* Show pending timers: */ -extern void sysrq_timer_list_show(void); - -int hrtimers_prepare_cpu(unsigned int cpu); -#ifdef CONFIG_HOTPLUG_CPU -int hrtimers_dead_cpu(unsigned int cpu); -#else -#define hrtimers_dead_cpu NULL -#endif - -#endif diff --git a/src/linux/include/linux/huge_mm.h b/src/linux/include/linux/huge_mm.h deleted file mode 100644 index e35e6de..0000000 --- a/src/linux/include/linux/huge_mm.h +++ /dev/null @@ -1,235 +0,0 @@ -#ifndef _LINUX_HUGE_MM_H -#define _LINUX_HUGE_MM_H - -extern int do_huge_pmd_anonymous_page(struct fault_env *fe); -extern int copy_huge_pmd(struct mm_struct *dst_mm, struct mm_struct *src_mm, - pmd_t *dst_pmd, pmd_t *src_pmd, unsigned long addr, - struct vm_area_struct *vma); -extern void huge_pmd_set_accessed(struct fault_env *fe, pmd_t orig_pmd); -extern int do_huge_pmd_wp_page(struct fault_env *fe, pmd_t orig_pmd); -extern struct page *follow_trans_huge_pmd(struct vm_area_struct *vma, - unsigned long addr, - pmd_t *pmd, - unsigned int flags); -extern bool madvise_free_huge_pmd(struct mmu_gather *tlb, - struct vm_area_struct *vma, - pmd_t *pmd, unsigned long addr, unsigned long next); -extern int zap_huge_pmd(struct mmu_gather *tlb, - struct vm_area_struct *vma, - pmd_t *pmd, unsigned long addr); -extern int mincore_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, - unsigned long addr, unsigned long end, - unsigned char *vec); -extern bool move_huge_pmd(struct vm_area_struct *vma, unsigned long old_addr, - unsigned long new_addr, unsigned long old_end, - pmd_t *old_pmd, pmd_t *new_pmd, bool *need_flush); -extern int change_huge_pmd(struct vm_area_struct *vma, pmd_t *pmd, - unsigned long addr, pgprot_t newprot, - int prot_numa); -int vmf_insert_pfn_pmd(struct vm_area_struct *, unsigned long addr, pmd_t *, - pfn_t pfn, bool write); -enum transparent_hugepage_flag { - TRANSPARENT_HUGEPAGE_FLAG, - TRANSPARENT_HUGEPAGE_REQ_MADV_FLAG, - TRANSPARENT_HUGEPAGE_DEFRAG_DIRECT_FLAG, - TRANSPARENT_HUGEPAGE_DEFRAG_KSWAPD_FLAG, - TRANSPARENT_HUGEPAGE_DEFRAG_REQ_MADV_FLAG, - TRANSPARENT_HUGEPAGE_DEFRAG_KHUGEPAGED_FLAG, - TRANSPARENT_HUGEPAGE_USE_ZERO_PAGE_FLAG, -#ifdef CONFIG_DEBUG_VM - TRANSPARENT_HUGEPAGE_DEBUG_COW_FLAG, -#endif -}; - -struct kobject; -struct kobj_attribute; - -extern ssize_t single_hugepage_flag_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count, - enum transparent_hugepage_flag flag); -extern ssize_t single_hugepage_flag_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf, - enum transparent_hugepage_flag flag); -extern struct kobj_attribute shmem_enabled_attr; - -#define HPAGE_PMD_ORDER (HPAGE_PMD_SHIFT-PAGE_SHIFT) -#define HPAGE_PMD_NR (1<vm_flags & VM_HUGEPAGE))) && \ - !((__vma)->vm_flags & VM_NOHUGEPAGE) && \ - !is_vma_temporary_stack(__vma)) -#define transparent_hugepage_use_zero_page() \ - (transparent_hugepage_flags & \ - (1<vm_mm->mmap_sem), vma); - if (pmd_trans_huge(*pmd) || pmd_devmap(*pmd)) - return __pmd_trans_huge_lock(pmd, vma); - else - return NULL; -} -static inline int hpage_nr_pages(struct page *page) -{ - if (unlikely(PageTransHuge(page))) - return HPAGE_PMD_NR; - return 1; -} - -extern int do_huge_pmd_numa_page(struct fault_env *fe, pmd_t orig_pmd); - -extern struct page *huge_zero_page; - -static inline bool is_huge_zero_page(struct page *page) -{ - return ACCESS_ONCE(huge_zero_page) == page; -} - -static inline bool is_huge_zero_pmd(pmd_t pmd) -{ - return is_huge_zero_page(pmd_page(pmd)); -} - -struct page *mm_get_huge_zero_page(struct mm_struct *mm); -void mm_put_huge_zero_page(struct mm_struct *mm); - -#define mk_huge_pmd(page, prot) pmd_mkhuge(mk_pmd(page, prot)) - -#else /* CONFIG_TRANSPARENT_HUGEPAGE */ -#define HPAGE_PMD_SHIFT ({ BUILD_BUG(); 0; }) -#define HPAGE_PMD_MASK ({ BUILD_BUG(); 0; }) -#define HPAGE_PMD_SIZE ({ BUILD_BUG(); 0; }) - -#define hpage_nr_pages(x) 1 - -#define transparent_hugepage_enabled(__vma) 0 - -static inline void prep_transhuge_page(struct page *page) {} - -#define transparent_hugepage_flags 0UL - -#define thp_get_unmapped_area NULL - -static inline int -split_huge_page_to_list(struct page *page, struct list_head *list) -{ - return 0; -} -static inline int split_huge_page(struct page *page) -{ - return 0; -} -static inline void deferred_split_huge_page(struct page *page) {} -#define split_huge_pmd(__vma, __pmd, __address) \ - do { } while (0) - -static inline void split_huge_pmd_address(struct vm_area_struct *vma, - unsigned long address, bool freeze, struct page *page) {} - -static inline int hugepage_madvise(struct vm_area_struct *vma, - unsigned long *vm_flags, int advice) -{ - BUG(); - return 0; -} -static inline void vma_adjust_trans_huge(struct vm_area_struct *vma, - unsigned long start, - unsigned long end, - long adjust_next) -{ -} -static inline spinlock_t *pmd_trans_huge_lock(pmd_t *pmd, - struct vm_area_struct *vma) -{ - return NULL; -} - -static inline int do_huge_pmd_numa_page(struct fault_env *fe, pmd_t orig_pmd) -{ - return 0; -} - -static inline bool is_huge_zero_page(struct page *page) -{ - return false; -} - -static inline void mm_put_huge_zero_page(struct mm_struct *mm) -{ - return; -} - -static inline struct page *follow_devmap_pmd(struct vm_area_struct *vma, - unsigned long addr, pmd_t *pmd, int flags) -{ - return NULL; -} -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ - -#endif /* _LINUX_HUGE_MM_H */ diff --git a/src/linux/include/linux/hugetlb.h b/src/linux/include/linux/hugetlb.h deleted file mode 100644 index 48c76d6..0000000 --- a/src/linux/include/linux/hugetlb.h +++ /dev/null @@ -1,549 +0,0 @@ -#ifndef _LINUX_HUGETLB_H -#define _LINUX_HUGETLB_H - -#include -#include -#include -#include -#include -#include -#include -#include - -struct ctl_table; -struct user_struct; -struct mmu_gather; - -#ifdef CONFIG_HUGETLB_PAGE - -#include -#include -#include - -struct hugepage_subpool { - spinlock_t lock; - long count; - long max_hpages; /* Maximum huge pages or -1 if no maximum. */ - long used_hpages; /* Used count against maximum, includes */ - /* both alloced and reserved pages. */ - struct hstate *hstate; - long min_hpages; /* Minimum huge pages or -1 if no minimum. */ - long rsv_hpages; /* Pages reserved against global pool to */ - /* sasitfy minimum size. */ -}; - -struct resv_map { - struct kref refs; - spinlock_t lock; - struct list_head regions; - long adds_in_progress; - struct list_head region_cache; - long region_cache_count; -}; -extern struct resv_map *resv_map_alloc(void); -void resv_map_release(struct kref *ref); - -extern spinlock_t hugetlb_lock; -extern int hugetlb_max_hstate __read_mostly; -#define for_each_hstate(h) \ - for ((h) = hstates; (h) < &hstates[hugetlb_max_hstate]; (h)++) - -struct hugepage_subpool *hugepage_new_subpool(struct hstate *h, long max_hpages, - long min_hpages); -void hugepage_put_subpool(struct hugepage_subpool *spool); - -void reset_vma_resv_huge_pages(struct vm_area_struct *vma); -int hugetlb_sysctl_handler(struct ctl_table *, int, void __user *, size_t *, loff_t *); -int hugetlb_overcommit_handler(struct ctl_table *, int, void __user *, size_t *, loff_t *); -int hugetlb_treat_movable_handler(struct ctl_table *, int, void __user *, size_t *, loff_t *); - -#ifdef CONFIG_NUMA -int hugetlb_mempolicy_sysctl_handler(struct ctl_table *, int, - void __user *, size_t *, loff_t *); -#endif - -int copy_hugetlb_page_range(struct mm_struct *, struct mm_struct *, struct vm_area_struct *); -long follow_hugetlb_page(struct mm_struct *, struct vm_area_struct *, - struct page **, struct vm_area_struct **, - unsigned long *, unsigned long *, long, unsigned int); -void unmap_hugepage_range(struct vm_area_struct *, - unsigned long, unsigned long, struct page *); -void __unmap_hugepage_range_final(struct mmu_gather *tlb, - struct vm_area_struct *vma, - unsigned long start, unsigned long end, - struct page *ref_page); -void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma, - unsigned long start, unsigned long end, - struct page *ref_page); -void hugetlb_report_meminfo(struct seq_file *); -int hugetlb_report_node_meminfo(int, char *); -void hugetlb_show_meminfo(void); -unsigned long hugetlb_total_pages(void); -int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, - unsigned long address, unsigned int flags); -int hugetlb_reserve_pages(struct inode *inode, long from, long to, - struct vm_area_struct *vma, - vm_flags_t vm_flags); -long hugetlb_unreserve_pages(struct inode *inode, long start, long end, - long freed); -int dequeue_hwpoisoned_huge_page(struct page *page); -bool isolate_huge_page(struct page *page, struct list_head *list); -void putback_active_hugepage(struct page *page); -void free_huge_page(struct page *page); -void hugetlb_fix_reserve_counts(struct inode *inode); -extern struct mutex *hugetlb_fault_mutex_table; -u32 hugetlb_fault_mutex_hash(struct hstate *h, struct mm_struct *mm, - struct vm_area_struct *vma, - struct address_space *mapping, - pgoff_t idx, unsigned long address); - -pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud); - -extern int hugepages_treat_as_movable; -extern int sysctl_hugetlb_shm_group; -extern struct list_head huge_boot_pages; - -/* arch callbacks */ - -pte_t *huge_pte_alloc(struct mm_struct *mm, - unsigned long addr, unsigned long sz); -pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr); -int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep); -struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address, - int write); -struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address, - pmd_t *pmd, int flags); -struct page *follow_huge_pud(struct mm_struct *mm, unsigned long address, - pud_t *pud, int flags); -int pmd_huge(pmd_t pmd); -int pud_huge(pud_t pmd); -unsigned long hugetlb_change_protection(struct vm_area_struct *vma, - unsigned long address, unsigned long end, pgprot_t newprot); - -#else /* !CONFIG_HUGETLB_PAGE */ - -static inline void reset_vma_resv_huge_pages(struct vm_area_struct *vma) -{ -} - -static inline unsigned long hugetlb_total_pages(void) -{ - return 0; -} - -#define follow_hugetlb_page(m,v,p,vs,a,b,i,w) ({ BUG(); 0; }) -#define follow_huge_addr(mm, addr, write) ERR_PTR(-EINVAL) -#define copy_hugetlb_page_range(src, dst, vma) ({ BUG(); 0; }) -static inline void hugetlb_report_meminfo(struct seq_file *m) -{ -} -#define hugetlb_report_node_meminfo(n, buf) 0 -static inline void hugetlb_show_meminfo(void) -{ -} -#define follow_huge_pmd(mm, addr, pmd, flags) NULL -#define follow_huge_pud(mm, addr, pud, flags) NULL -#define prepare_hugepage_range(file, addr, len) (-EINVAL) -#define pmd_huge(x) 0 -#define pud_huge(x) 0 -#define is_hugepage_only_range(mm, addr, len) 0 -#define hugetlb_free_pgd_range(tlb, addr, end, floor, ceiling) ({BUG(); 0; }) -#define hugetlb_fault(mm, vma, addr, flags) ({ BUG(); 0; }) -#define huge_pte_offset(mm, address) 0 -static inline int dequeue_hwpoisoned_huge_page(struct page *page) -{ - return 0; -} - -static inline bool isolate_huge_page(struct page *page, struct list_head *list) -{ - return false; -} -#define putback_active_hugepage(p) do {} while (0) - -static inline unsigned long hugetlb_change_protection(struct vm_area_struct *vma, - unsigned long address, unsigned long end, pgprot_t newprot) -{ - return 0; -} - -static inline void __unmap_hugepage_range_final(struct mmu_gather *tlb, - struct vm_area_struct *vma, unsigned long start, - unsigned long end, struct page *ref_page) -{ - BUG(); -} - -static inline void __unmap_hugepage_range(struct mmu_gather *tlb, - struct vm_area_struct *vma, unsigned long start, - unsigned long end, struct page *ref_page) -{ - BUG(); -} - -#endif /* !CONFIG_HUGETLB_PAGE */ -/* - * hugepages at page global directory. If arch support - * hugepages at pgd level, they need to define this. - */ -#ifndef pgd_huge -#define pgd_huge(x) 0 -#endif - -#ifndef pgd_write -static inline int pgd_write(pgd_t pgd) -{ - BUG(); - return 0; -} -#endif - -#ifndef pud_write -static inline int pud_write(pud_t pud) -{ - BUG(); - return 0; -} -#endif - -#ifndef is_hugepd -/* - * Some architectures requires a hugepage directory format that is - * required to support multiple hugepage sizes. For example - * a4fe3ce76 "powerpc/mm: Allow more flexible layouts for hugepage pagetables" - * introduced the same on powerpc. This allows for a more flexible hugepage - * pagetable layout. - */ -typedef struct { unsigned long pd; } hugepd_t; -#define is_hugepd(hugepd) (0) -#define __hugepd(x) ((hugepd_t) { (x) }) -static inline int gup_huge_pd(hugepd_t hugepd, unsigned long addr, - unsigned pdshift, unsigned long end, - int write, struct page **pages, int *nr) -{ - return 0; -} -#else -extern int gup_huge_pd(hugepd_t hugepd, unsigned long addr, - unsigned pdshift, unsigned long end, - int write, struct page **pages, int *nr); -#endif - -#define HUGETLB_ANON_FILE "anon_hugepage" - -enum { - /* - * The file will be used as an shm file so shmfs accounting rules - * apply - */ - HUGETLB_SHMFS_INODE = 1, - /* - * The file is being created on the internal vfs mount and shmfs - * accounting rules do not apply - */ - HUGETLB_ANONHUGE_INODE = 2, -}; - -#ifdef CONFIG_HUGETLBFS -struct hugetlbfs_sb_info { - long max_inodes; /* inodes allowed */ - long free_inodes; /* inodes free */ - spinlock_t stat_lock; - struct hstate *hstate; - struct hugepage_subpool *spool; -}; - -static inline struct hugetlbfs_sb_info *HUGETLBFS_SB(struct super_block *sb) -{ - return sb->s_fs_info; -} - -extern const struct file_operations hugetlbfs_file_operations; -extern const struct vm_operations_struct hugetlb_vm_ops; -struct file *hugetlb_file_setup(const char *name, size_t size, vm_flags_t acct, - struct user_struct **user, int creat_flags, - int page_size_log); - -static inline bool is_file_hugepages(struct file *file) -{ - if (file->f_op == &hugetlbfs_file_operations) - return true; - - return is_file_shm_hugepages(file); -} - - -#else /* !CONFIG_HUGETLBFS */ - -#define is_file_hugepages(file) false -static inline struct file * -hugetlb_file_setup(const char *name, size_t size, vm_flags_t acctflag, - struct user_struct **user, int creat_flags, - int page_size_log) -{ - return ERR_PTR(-ENOSYS); -} - -#endif /* !CONFIG_HUGETLBFS */ - -#ifdef HAVE_ARCH_HUGETLB_UNMAPPED_AREA -unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, - unsigned long len, unsigned long pgoff, - unsigned long flags); -#endif /* HAVE_ARCH_HUGETLB_UNMAPPED_AREA */ - -#ifdef CONFIG_HUGETLB_PAGE - -#define HSTATE_NAME_LEN 32 -/* Defines one hugetlb page size */ -struct hstate { - int next_nid_to_alloc; - int next_nid_to_free; - unsigned int order; - unsigned long mask; - unsigned long max_huge_pages; - unsigned long nr_huge_pages; - unsigned long free_huge_pages; - unsigned long resv_huge_pages; - unsigned long surplus_huge_pages; - unsigned long nr_overcommit_huge_pages; - struct list_head hugepage_activelist; - struct list_head hugepage_freelists[MAX_NUMNODES]; - unsigned int nr_huge_pages_node[MAX_NUMNODES]; - unsigned int free_huge_pages_node[MAX_NUMNODES]; - unsigned int surplus_huge_pages_node[MAX_NUMNODES]; -#ifdef CONFIG_CGROUP_HUGETLB - /* cgroup control files */ - struct cftype cgroup_files[5]; -#endif - char name[HSTATE_NAME_LEN]; -}; - -struct huge_bootmem_page { - struct list_head list; - struct hstate *hstate; -#ifdef CONFIG_HIGHMEM - phys_addr_t phys; -#endif -}; - -struct page *alloc_huge_page(struct vm_area_struct *vma, - unsigned long addr, int avoid_reserve); -struct page *alloc_huge_page_node(struct hstate *h, int nid); -struct page *alloc_huge_page_noerr(struct vm_area_struct *vma, - unsigned long addr, int avoid_reserve); -int huge_add_to_page_cache(struct page *page, struct address_space *mapping, - pgoff_t idx); - -/* arch callback */ -int __init alloc_bootmem_huge_page(struct hstate *h); - -void __init hugetlb_bad_size(void); -void __init hugetlb_add_hstate(unsigned order); -struct hstate *size_to_hstate(unsigned long size); - -#ifndef HUGE_MAX_HSTATE -#define HUGE_MAX_HSTATE 1 -#endif - -extern struct hstate hstates[HUGE_MAX_HSTATE]; -extern unsigned int default_hstate_idx; - -#define default_hstate (hstates[default_hstate_idx]) - -static inline struct hstate *hstate_inode(struct inode *i) -{ - return HUGETLBFS_SB(i->i_sb)->hstate; -} - -static inline struct hstate *hstate_file(struct file *f) -{ - return hstate_inode(file_inode(f)); -} - -static inline struct hstate *hstate_sizelog(int page_size_log) -{ - if (!page_size_log) - return &default_hstate; - - return size_to_hstate(1UL << page_size_log); -} - -static inline struct hstate *hstate_vma(struct vm_area_struct *vma) -{ - return hstate_file(vma->vm_file); -} - -static inline unsigned long huge_page_size(struct hstate *h) -{ - return (unsigned long)PAGE_SIZE << h->order; -} - -extern unsigned long vma_kernel_pagesize(struct vm_area_struct *vma); - -extern unsigned long vma_mmu_pagesize(struct vm_area_struct *vma); - -static inline unsigned long huge_page_mask(struct hstate *h) -{ - return h->mask; -} - -static inline unsigned int huge_page_order(struct hstate *h) -{ - return h->order; -} - -static inline unsigned huge_page_shift(struct hstate *h) -{ - return h->order + PAGE_SHIFT; -} - -static inline bool hstate_is_gigantic(struct hstate *h) -{ - return huge_page_order(h) >= MAX_ORDER; -} - -static inline unsigned int pages_per_huge_page(struct hstate *h) -{ - return 1 << h->order; -} - -static inline unsigned int blocks_per_huge_page(struct hstate *h) -{ - return huge_page_size(h) / 512; -} - -#include - -#ifndef arch_make_huge_pte -static inline pte_t arch_make_huge_pte(pte_t entry, struct vm_area_struct *vma, - struct page *page, int writable) -{ - return entry; -} -#endif - -static inline struct hstate *page_hstate(struct page *page) -{ - VM_BUG_ON_PAGE(!PageHuge(page), page); - return size_to_hstate(PAGE_SIZE << compound_order(page)); -} - -static inline unsigned hstate_index_to_shift(unsigned index) -{ - return hstates[index].order + PAGE_SHIFT; -} - -static inline int hstate_index(struct hstate *h) -{ - return h - hstates; -} - -pgoff_t __basepage_index(struct page *page); - -/* Return page->index in PAGE_SIZE units */ -static inline pgoff_t basepage_index(struct page *page) -{ - if (!PageCompound(page)) - return page->index; - - return __basepage_index(page); -} - -extern int dissolve_free_huge_pages(unsigned long start_pfn, - unsigned long end_pfn); -static inline bool hugepage_migration_supported(struct hstate *h) -{ -#ifdef CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION - return huge_page_shift(h) == PMD_SHIFT; -#else - return false; -#endif -} - -static inline spinlock_t *huge_pte_lockptr(struct hstate *h, - struct mm_struct *mm, pte_t *pte) -{ - if (huge_page_size(h) == PMD_SIZE) - return pmd_lockptr(mm, (pmd_t *) pte); - VM_BUG_ON(huge_page_size(h) == PAGE_SIZE); - return &mm->page_table_lock; -} - -#ifndef hugepages_supported -/* - * Some platform decide whether they support huge pages at boot - * time. Some of them, such as powerpc, set HPAGE_SHIFT to 0 - * when there is no such support - */ -#define hugepages_supported() (HPAGE_SHIFT != 0) -#endif - -void hugetlb_report_usage(struct seq_file *m, struct mm_struct *mm); - -static inline void hugetlb_count_add(long l, struct mm_struct *mm) -{ - atomic_long_add(l, &mm->hugetlb_usage); -} - -static inline void hugetlb_count_sub(long l, struct mm_struct *mm) -{ - atomic_long_sub(l, &mm->hugetlb_usage); -} -#else /* CONFIG_HUGETLB_PAGE */ -struct hstate {}; -#define alloc_huge_page(v, a, r) NULL -#define alloc_huge_page_node(h, nid) NULL -#define alloc_huge_page_noerr(v, a, r) NULL -#define alloc_bootmem_huge_page(h) NULL -#define hstate_file(f) NULL -#define hstate_sizelog(s) NULL -#define hstate_vma(v) NULL -#define hstate_inode(i) NULL -#define page_hstate(page) NULL -#define huge_page_size(h) PAGE_SIZE -#define huge_page_mask(h) PAGE_MASK -#define vma_kernel_pagesize(v) PAGE_SIZE -#define vma_mmu_pagesize(v) PAGE_SIZE -#define huge_page_order(h) 0 -#define huge_page_shift(h) PAGE_SHIFT -static inline unsigned int pages_per_huge_page(struct hstate *h) -{ - return 1; -} -#define hstate_index_to_shift(index) 0 -#define hstate_index(h) 0 - -static inline pgoff_t basepage_index(struct page *page) -{ - return page->index; -} -#define dissolve_free_huge_pages(s, e) 0 -#define hugepage_migration_supported(h) false - -static inline spinlock_t *huge_pte_lockptr(struct hstate *h, - struct mm_struct *mm, pte_t *pte) -{ - return &mm->page_table_lock; -} - -static inline void hugetlb_report_usage(struct seq_file *f, struct mm_struct *m) -{ -} - -static inline void hugetlb_count_sub(long l, struct mm_struct *mm) -{ -} -#endif /* CONFIG_HUGETLB_PAGE */ - -static inline spinlock_t *huge_pte_lock(struct hstate *h, - struct mm_struct *mm, pte_t *pte) -{ - spinlock_t *ptl; - - ptl = huge_pte_lockptr(h, mm, pte); - spin_lock(ptl); - return ptl; -} - -#endif /* _LINUX_HUGETLB_H */ diff --git a/src/linux/include/linux/hugetlb_inline.h b/src/linux/include/linux/hugetlb_inline.h deleted file mode 100644 index a4e7ca0..0000000 --- a/src/linux/include/linux/hugetlb_inline.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _LINUX_HUGETLB_INLINE_H -#define _LINUX_HUGETLB_INLINE_H - -#ifdef CONFIG_HUGETLB_PAGE - -#include - -static inline bool is_vm_hugetlb_page(struct vm_area_struct *vma) -{ - return !!(vma->vm_flags & VM_HUGETLB); -} - -#else - -static inline bool is_vm_hugetlb_page(struct vm_area_struct *vma) -{ - return false; -} - -#endif - -#endif diff --git a/src/linux/include/linux/hw_breakpoint.h b/src/linux/include/linux/hw_breakpoint.h deleted file mode 100644 index 0464c85..0000000 --- a/src/linux/include/linux/hw_breakpoint.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef _LINUX_HW_BREAKPOINT_H -#define _LINUX_HW_BREAKPOINT_H - -#include -#include - -#ifdef CONFIG_HAVE_HW_BREAKPOINT - -extern int __init init_hw_breakpoint(void); - -static inline void hw_breakpoint_init(struct perf_event_attr *attr) -{ - memset(attr, 0, sizeof(*attr)); - - attr->type = PERF_TYPE_BREAKPOINT; - attr->size = sizeof(*attr); - /* - * As it's for in-kernel or ptrace use, we want it to be pinned - * and to call its callback every hits. - */ - attr->pinned = 1; - attr->sample_period = 1; -} - -static inline void ptrace_breakpoint_init(struct perf_event_attr *attr) -{ - hw_breakpoint_init(attr); - attr->exclude_kernel = 1; -} - -static inline unsigned long hw_breakpoint_addr(struct perf_event *bp) -{ - return bp->attr.bp_addr; -} - -static inline int hw_breakpoint_type(struct perf_event *bp) -{ - return bp->attr.bp_type; -} - -static inline unsigned long hw_breakpoint_len(struct perf_event *bp) -{ - return bp->attr.bp_len; -} - -extern struct perf_event * -register_user_hw_breakpoint(struct perf_event_attr *attr, - perf_overflow_handler_t triggered, - void *context, - struct task_struct *tsk); - -/* FIXME: only change from the attr, and don't unregister */ -extern int -modify_user_hw_breakpoint(struct perf_event *bp, struct perf_event_attr *attr); - -/* - * Kernel breakpoints are not associated with any particular thread. - */ -extern struct perf_event * -register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, - perf_overflow_handler_t triggered, - void *context, - int cpu); - -extern struct perf_event * __percpu * -register_wide_hw_breakpoint(struct perf_event_attr *attr, - perf_overflow_handler_t triggered, - void *context); - -extern int register_perf_hw_breakpoint(struct perf_event *bp); -extern int __register_perf_hw_breakpoint(struct perf_event *bp); -extern void unregister_hw_breakpoint(struct perf_event *bp); -extern void unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events); - -extern int dbg_reserve_bp_slot(struct perf_event *bp); -extern int dbg_release_bp_slot(struct perf_event *bp); -extern int reserve_bp_slot(struct perf_event *bp); -extern void release_bp_slot(struct perf_event *bp); - -extern void flush_ptrace_hw_breakpoint(struct task_struct *tsk); - -static inline struct arch_hw_breakpoint *counter_arch_bp(struct perf_event *bp) -{ - return &bp->hw.info; -} - -#else /* !CONFIG_HAVE_HW_BREAKPOINT */ - -static inline int __init init_hw_breakpoint(void) { return 0; } - -static inline struct perf_event * -register_user_hw_breakpoint(struct perf_event_attr *attr, - perf_overflow_handler_t triggered, - void *context, - struct task_struct *tsk) { return NULL; } -static inline int -modify_user_hw_breakpoint(struct perf_event *bp, - struct perf_event_attr *attr) { return -ENOSYS; } -static inline struct perf_event * -register_wide_hw_breakpoint_cpu(struct perf_event_attr *attr, - perf_overflow_handler_t triggered, - void *context, - int cpu) { return NULL; } -static inline struct perf_event * __percpu * -register_wide_hw_breakpoint(struct perf_event_attr *attr, - perf_overflow_handler_t triggered, - void *context) { return NULL; } -static inline int -register_perf_hw_breakpoint(struct perf_event *bp) { return -ENOSYS; } -static inline int -__register_perf_hw_breakpoint(struct perf_event *bp) { return -ENOSYS; } -static inline void unregister_hw_breakpoint(struct perf_event *bp) { } -static inline void -unregister_wide_hw_breakpoint(struct perf_event * __percpu *cpu_events) { } -static inline int -reserve_bp_slot(struct perf_event *bp) {return -ENOSYS; } -static inline void release_bp_slot(struct perf_event *bp) { } - -static inline void flush_ptrace_hw_breakpoint(struct task_struct *tsk) { } - -static inline struct arch_hw_breakpoint *counter_arch_bp(struct perf_event *bp) -{ - return NULL; -} - -#endif /* CONFIG_HAVE_HW_BREAKPOINT */ -#endif /* _LINUX_HW_BREAKPOINT_H */ diff --git a/src/linux/include/linux/hw_random.h b/src/linux/include/linux/hw_random.h deleted file mode 100644 index 34a0dc1..0000000 --- a/src/linux/include/linux/hw_random.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - Hardware Random Number Generator - - Please read Documentation/hw_random.txt for details on use. - - ---------------------------------------------------------- - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - - */ - -#ifndef LINUX_HWRANDOM_H_ -#define LINUX_HWRANDOM_H_ - -#include -#include -#include -#include - -/** - * struct hwrng - Hardware Random Number Generator driver - * @name: Unique RNG name. - * @init: Initialization callback (can be NULL). - * @cleanup: Cleanup callback (can be NULL). - * @data_present: Callback to determine if data is available - * on the RNG. If NULL, it is assumed that - * there is always data available. *OBSOLETE* - * @data_read: Read data from the RNG device. - * Returns the number of lower random bytes in "data". - * Must not be NULL. *OBSOLETE* - * @read: New API. drivers can fill up to max bytes of data - * into the buffer. The buffer is aligned for any type - * and max is guaranteed to be >= to that alignment - * (either 4 or 8 depending on architecture). - * @priv: Private data, for use by the RNG driver. - * @quality: Estimation of true entropy in RNG's bitstream - * (per mill). - */ -struct hwrng { - const char *name; - int (*init)(struct hwrng *rng); - void (*cleanup)(struct hwrng *rng); - int (*data_present)(struct hwrng *rng, int wait); - int (*data_read)(struct hwrng *rng, u32 *data); - int (*read)(struct hwrng *rng, void *data, size_t max, bool wait); - unsigned long priv; - unsigned short quality; - - /* internal. */ - struct list_head list; - struct kref ref; - struct completion cleanup_done; -}; - -struct device; - -/** Register a new Hardware Random Number Generator driver. */ -extern int hwrng_register(struct hwrng *rng); -extern int devm_hwrng_register(struct device *dev, struct hwrng *rng); -/** Unregister a Hardware Random Number Generator driver. */ -extern void hwrng_unregister(struct hwrng *rng); -extern void devm_hwrng_unregister(struct device *dve, struct hwrng *rng); -/** Feed random bits into the pool. */ -extern void add_hwgenerator_randomness(const char *buffer, size_t count, size_t entropy); - -#endif /* LINUX_HWRANDOM_H_ */ diff --git a/src/linux/include/linux/hwmon.h b/src/linux/include/linux/hwmon.h deleted file mode 100644 index 9d2f8bd..0000000 --- a/src/linux/include/linux/hwmon.h +++ /dev/null @@ -1,375 +0,0 @@ -/* - hwmon.h - part of lm_sensors, Linux kernel modules for hardware monitoring - - This file declares helper functions for the sysfs class "hwmon", - for use by sensors drivers. - - Copyright (C) 2005 Mark M. Hoffman - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; version 2 of the License. -*/ - -#ifndef _HWMON_H_ -#define _HWMON_H_ - -#include - -struct device; -struct attribute_group; - -enum hwmon_sensor_types { - hwmon_chip, - hwmon_temp, - hwmon_in, - hwmon_curr, - hwmon_power, - hwmon_energy, - hwmon_humidity, - hwmon_fan, - hwmon_pwm, -}; - -enum hwmon_chip_attributes { - hwmon_chip_temp_reset_history, - hwmon_chip_in_reset_history, - hwmon_chip_curr_reset_history, - hwmon_chip_power_reset_history, - hwmon_chip_register_tz, - hwmon_chip_update_interval, - hwmon_chip_alarms, -}; - -#define HWMON_C_TEMP_RESET_HISTORY BIT(hwmon_chip_temp_reset_history) -#define HWMON_C_IN_RESET_HISTORY BIT(hwmon_chip_in_reset_history) -#define HWMON_C_CURR_RESET_HISTORY BIT(hwmon_chip_curr_reset_history) -#define HWMON_C_POWER_RESET_HISTORY BIT(hwmon_chip_power_reset_history) -#define HWMON_C_REGISTER_TZ BIT(hwmon_chip_register_tz) -#define HWMON_C_UPDATE_INTERVAL BIT(hwmon_chip_update_interval) -#define HWMON_C_ALARMS BIT(hwmon_chip_alarms) - -enum hwmon_temp_attributes { - hwmon_temp_input = 0, - hwmon_temp_type, - hwmon_temp_lcrit, - hwmon_temp_lcrit_hyst, - hwmon_temp_min, - hwmon_temp_min_hyst, - hwmon_temp_max, - hwmon_temp_max_hyst, - hwmon_temp_crit, - hwmon_temp_crit_hyst, - hwmon_temp_emergency, - hwmon_temp_emergency_hyst, - hwmon_temp_alarm, - hwmon_temp_lcrit_alarm, - hwmon_temp_min_alarm, - hwmon_temp_max_alarm, - hwmon_temp_crit_alarm, - hwmon_temp_emergency_alarm, - hwmon_temp_fault, - hwmon_temp_offset, - hwmon_temp_label, - hwmon_temp_lowest, - hwmon_temp_highest, - hwmon_temp_reset_history, -}; - -#define HWMON_T_INPUT BIT(hwmon_temp_input) -#define HWMON_T_TYPE BIT(hwmon_temp_type) -#define HWMON_T_LCRIT BIT(hwmon_temp_lcrit) -#define HWMON_T_LCRIT_HYST BIT(hwmon_temp_lcrit_hyst) -#define HWMON_T_MIN BIT(hwmon_temp_min) -#define HWMON_T_MIN_HYST BIT(hwmon_temp_min_hyst) -#define HWMON_T_MAX BIT(hwmon_temp_max) -#define HWMON_T_MAX_HYST BIT(hwmon_temp_max_hyst) -#define HWMON_T_CRIT BIT(hwmon_temp_crit) -#define HWMON_T_CRIT_HYST BIT(hwmon_temp_crit_hyst) -#define HWMON_T_EMERGENCY BIT(hwmon_temp_emergency) -#define HWMON_T_EMERGENCY_HYST BIT(hwmon_temp_emergency_hyst) -#define HWMON_T_MIN_ALARM BIT(hwmon_temp_min_alarm) -#define HWMON_T_MAX_ALARM BIT(hwmon_temp_max_alarm) -#define HWMON_T_CRIT_ALARM BIT(hwmon_temp_crit_alarm) -#define HWMON_T_EMERGENCY_ALARM BIT(hwmon_temp_emergency_alarm) -#define HWMON_T_FAULT BIT(hwmon_temp_fault) -#define HWMON_T_OFFSET BIT(hwmon_temp_offset) -#define HWMON_T_LABEL BIT(hwmon_temp_label) -#define HWMON_T_LOWEST BIT(hwmon_temp_lowest) -#define HWMON_T_HIGHEST BIT(hwmon_temp_highest) -#define HWMON_T_RESET_HISTORY BIT(hwmon_temp_reset_history) - -enum hwmon_in_attributes { - hwmon_in_input, - hwmon_in_min, - hwmon_in_max, - hwmon_in_lcrit, - hwmon_in_crit, - hwmon_in_average, - hwmon_in_lowest, - hwmon_in_highest, - hwmon_in_reset_history, - hwmon_in_label, - hwmon_in_alarm, - hwmon_in_min_alarm, - hwmon_in_max_alarm, - hwmon_in_lcrit_alarm, - hwmon_in_crit_alarm, -}; - -#define HWMON_I_INPUT BIT(hwmon_in_input) -#define HWMON_I_MIN BIT(hwmon_in_min) -#define HWMON_I_MAX BIT(hwmon_in_max) -#define HWMON_I_LCRIT BIT(hwmon_in_lcrit) -#define HWMON_I_CRIT BIT(hwmon_in_crit) -#define HWMON_I_AVERAGE BIT(hwmon_in_average) -#define HWMON_I_LOWEST BIT(hwmon_in_lowest) -#define HWMON_I_HIGHEST BIT(hwmon_in_highest) -#define HWMON_I_RESET_HISTORY BIT(hwmon_in_reset_history) -#define HWMON_I_LABEL BIT(hwmon_in_label) -#define HWMON_I_ALARM BIT(hwmon_in_alarm) -#define HWMON_I_MIN_ALARM BIT(hwmon_in_min_alarm) -#define HWMON_I_MAX_ALARM BIT(hwmon_in_max_alarm) -#define HWMON_I_LCRIT_ALARM BIT(hwmon_in_lcrit_alarm) -#define HWMON_I_CRIT_ALARM BIT(hwmon_in_crit_alarm) - -enum hwmon_curr_attributes { - hwmon_curr_input, - hwmon_curr_min, - hwmon_curr_max, - hwmon_curr_lcrit, - hwmon_curr_crit, - hwmon_curr_average, - hwmon_curr_lowest, - hwmon_curr_highest, - hwmon_curr_reset_history, - hwmon_curr_label, - hwmon_curr_alarm, - hwmon_curr_min_alarm, - hwmon_curr_max_alarm, - hwmon_curr_lcrit_alarm, - hwmon_curr_crit_alarm, -}; - -#define HWMON_C_INPUT BIT(hwmon_curr_input) -#define HWMON_C_MIN BIT(hwmon_curr_min) -#define HWMON_C_MAX BIT(hwmon_curr_max) -#define HWMON_C_LCRIT BIT(hwmon_curr_lcrit) -#define HWMON_C_CRIT BIT(hwmon_curr_crit) -#define HWMON_C_AVERAGE BIT(hwmon_curr_average) -#define HWMON_C_LOWEST BIT(hwmon_curr_lowest) -#define HWMON_C_HIGHEST BIT(hwmon_curr_highest) -#define HWMON_C_RESET_HISTORY BIT(hwmon_curr_reset_history) -#define HWMON_C_LABEL BIT(hwmon_curr_label) -#define HWMON_C_ALARM BIT(hwmon_curr_alarm) -#define HWMON_C_MIN_ALARM BIT(hwmon_curr_min_alarm) -#define HWMON_C_MAX_ALARM BIT(hwmon_curr_max_alarm) -#define HWMON_C_LCRIT_ALARM BIT(hwmon_curr_lcrit_alarm) -#define HWMON_C_CRIT_ALARM BIT(hwmon_curr_crit_alarm) - -enum hwmon_power_attributes { - hwmon_power_average, - hwmon_power_average_interval, - hwmon_power_average_interval_max, - hwmon_power_average_interval_min, - hwmon_power_average_highest, - hwmon_power_average_lowest, - hwmon_power_average_max, - hwmon_power_average_min, - hwmon_power_input, - hwmon_power_input_highest, - hwmon_power_input_lowest, - hwmon_power_reset_history, - hwmon_power_accuracy, - hwmon_power_cap, - hwmon_power_cap_hyst, - hwmon_power_cap_max, - hwmon_power_cap_min, - hwmon_power_max, - hwmon_power_crit, - hwmon_power_label, - hwmon_power_alarm, - hwmon_power_cap_alarm, - hwmon_power_max_alarm, - hwmon_power_crit_alarm, -}; - -#define HWMON_P_AVERAGE BIT(hwmon_power_average) -#define HWMON_P_AVERAGE_INTERVAL BIT(hwmon_power_average_interval) -#define HWMON_P_AVERAGE_INTERVAL_MAX BIT(hwmon_power_average_interval_max) -#define HWMON_P_AVERAGE_INTERVAL_MIN BIT(hwmon_power_average_interval_min) -#define HWMON_P_AVERAGE_HIGHEST BIT(hwmon_power_average_highest) -#define HWMON_P_AVERAGE_LOWEST BIT(hwmon_power_average_lowest) -#define HWMON_P_AVERAGE_MAX BIT(hwmon_power_average_max) -#define HWMON_P_AVERAGE_MIN BIT(hwmon_power_average_min) -#define HWMON_P_INPUT BIT(hwmon_power_input) -#define HWMON_P_INPUT_HIGHEST BIT(hwmon_power_input_highest) -#define HWMON_P_INPUT_LOWEST BIT(hwmon_power_input_lowest) -#define HWMON_P_RESET_HISTORY BIT(hwmon_power_reset_history) -#define HWMON_P_ACCURACY BIT(hwmon_power_accuracy) -#define HWMON_P_CAP BIT(hwmon_power_cap) -#define HWMON_P_CAP_HYST BIT(hwmon_power_cap_hyst) -#define HWMON_P_CAP_MAX BIT(hwmon_power_cap_max) -#define HWMON_P_CAP_MIN BIT(hwmon_power_cap_min) -#define HWMON_P_MAX BIT(hwmon_power_max) -#define HWMON_P_CRIT BIT(hwmon_power_crit) -#define HWMON_P_LABEL BIT(hwmon_power_label) -#define HWMON_P_ALARM BIT(hwmon_power_alarm) -#define HWMON_P_CAP_ALARM BIT(hwmon_power_cap_alarm) -#define HWMON_P_MAX_ALARM BIT(hwmon_power_max_alarm) -#define HWMON_P_CRIT_ALARM BIT(hwmon_power_crit_alarm) - -enum hwmon_energy_attributes { - hwmon_energy_input, - hwmon_energy_label, -}; - -#define HWMON_E_INPUT BIT(hwmon_energy_input) -#define HWMON_E_LABEL BIT(hwmon_energy_label) - -enum hwmon_humidity_attributes { - hwmon_humidity_input, - hwmon_humidity_label, - hwmon_humidity_min, - hwmon_humidity_min_hyst, - hwmon_humidity_max, - hwmon_humidity_max_hyst, - hwmon_humidity_alarm, - hwmon_humidity_fault, -}; - -#define HWMON_H_INPUT BIT(hwmon_humidity_input) -#define HWMON_H_LABEL BIT(hwmon_humidity_label) -#define HWMON_H_MIN BIT(hwmon_humidity_min) -#define HWMON_H_MIN_HYST BIT(hwmon_humidity_min_hyst) -#define HWMON_H_MAX BIT(hwmon_humidity_max) -#define HWMON_H_MAX_HYST BIT(hwmon_humidity_max_hyst) -#define HWMON_H_ALARM BIT(hwmon_humidity_alarm) -#define HWMON_H_FAULT BIT(hwmon_humidity_fault) - -enum hwmon_fan_attributes { - hwmon_fan_input, - hwmon_fan_label, - hwmon_fan_min, - hwmon_fan_max, - hwmon_fan_div, - hwmon_fan_pulses, - hwmon_fan_target, - hwmon_fan_alarm, - hwmon_fan_min_alarm, - hwmon_fan_max_alarm, - hwmon_fan_fault, -}; - -#define HWMON_F_INPUT BIT(hwmon_fan_input) -#define HWMON_F_LABEL BIT(hwmon_fan_label) -#define HWMON_F_MIN BIT(hwmon_fan_min) -#define HWMON_F_MAX BIT(hwmon_fan_max) -#define HWMON_F_DIV BIT(hwmon_fan_div) -#define HWMON_F_PULSES BIT(hwmon_fan_pulses) -#define HWMON_F_TARGET BIT(hwmon_fan_target) -#define HWMON_F_ALARM BIT(hwmon_fan_alarm) -#define HWMON_F_MIN_ALARM BIT(hwmon_fan_min_alarm) -#define HWMON_F_MAX_ALARM BIT(hwmon_fan_max_alarm) -#define HWMON_F_FAULT BIT(hwmon_fan_fault) - -enum hwmon_pwm_attributes { - hwmon_pwm_input, - hwmon_pwm_enable, - hwmon_pwm_mode, - hwmon_pwm_freq, -}; - -#define HWMON_PWM_INPUT BIT(hwmon_pwm_input) -#define HWMON_PWM_ENABLE BIT(hwmon_pwm_enable) -#define HWMON_PWM_MODE BIT(hwmon_pwm_mode) -#define HWMON_PWM_FREQ BIT(hwmon_pwm_freq) - -/** - * struct hwmon_ops - hwmon device operations - * @is_visible: Callback to return attribute visibility. Mandatory. - * Parameters are: - * @const void *drvdata: - * Pointer to driver-private data structure passed - * as argument to hwmon_device_register_with_info(). - * @type: Sensor type - * @attr: Sensor attribute - * @channel: - * Channel number - * The function returns the file permissions. - * If the return value is 0, no attribute will be created. - * @read: Read callback. Optional. If not provided, attributes - * will not be readable. - * Parameters are: - * @dev: Pointer to hardware monitoring device - * @type: Sensor type - * @attr: Sensor attribute - * @channel: - * Channel number - * @val: Pointer to returned value - * The function returns 0 on success or a negative error number. - * @write: Write callback. Optional. If not provided, attributes - * will not be writable. - * Parameters are: - * @dev: Pointer to hardware monitoring device - * @type: Sensor type - * @attr: Sensor attribute - * @channel: - * Channel number - * @val: Value to write - * The function returns 0 on success or a negative error number. - */ -struct hwmon_ops { - umode_t (*is_visible)(const void *drvdata, enum hwmon_sensor_types type, - u32 attr, int channel); - int (*read)(struct device *dev, enum hwmon_sensor_types type, - u32 attr, int channel, long *val); - int (*write)(struct device *dev, enum hwmon_sensor_types type, - u32 attr, int channel, long val); -}; - -/** - * Channel information - * @type: Channel type. - * @config: Pointer to NULL-terminated list of channel parameters. - * Use for per-channel attributes. - */ -struct hwmon_channel_info { - enum hwmon_sensor_types type; - const u32 *config; -}; - -/** - * Chip configuration - * @ops: Pointer to hwmon operations. - * @info: Null-terminated list of channel information. - */ -struct hwmon_chip_info { - const struct hwmon_ops *ops; - const struct hwmon_channel_info **info; -}; - -struct device *hwmon_device_register(struct device *dev); -struct device * -hwmon_device_register_with_groups(struct device *dev, const char *name, - void *drvdata, - const struct attribute_group **groups); -struct device * -devm_hwmon_device_register_with_groups(struct device *dev, const char *name, - void *drvdata, - const struct attribute_group **groups); -struct device * -hwmon_device_register_with_info(struct device *dev, - const char *name, void *drvdata, - const struct hwmon_chip_info *info, - const struct attribute_group **groups); -struct device * -devm_hwmon_device_register_with_info(struct device *dev, - const char *name, void *drvdata, - const struct hwmon_chip_info *info, - const struct attribute_group **groups); - -void hwmon_device_unregister(struct device *dev); -void devm_hwmon_device_unregister(struct device *dev); - -#endif diff --git a/src/linux/include/linux/hypervisor.h b/src/linux/include/linux/hypervisor.h deleted file mode 100644 index 3fa5ef2..0000000 --- a/src/linux/include/linux/hypervisor.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef __LINUX_HYPEVISOR_H -#define __LINUX_HYPEVISOR_H - -/* - * Generic Hypervisor support - * Juergen Gross - */ - -#ifdef CONFIG_HYPERVISOR_GUEST -#include -#else -static inline void hypervisor_pin_vcpu(int cpu) -{ -} -#endif - -#endif /* __LINUX_HYPEVISOR_H */ diff --git a/src/linux/include/linux/i8042.h b/src/linux/include/linux/i8042.h deleted file mode 100644 index d98780c..0000000 --- a/src/linux/include/linux/i8042.h +++ /dev/null @@ -1,99 +0,0 @@ -#ifndef _LINUX_I8042_H -#define _LINUX_I8042_H - -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#include - -/* - * Standard commands. - */ - -#define I8042_CMD_CTL_RCTR 0x0120 -#define I8042_CMD_CTL_WCTR 0x1060 -#define I8042_CMD_CTL_TEST 0x01aa - -#define I8042_CMD_KBD_DISABLE 0x00ad -#define I8042_CMD_KBD_ENABLE 0x00ae -#define I8042_CMD_KBD_TEST 0x01ab -#define I8042_CMD_KBD_LOOP 0x11d2 - -#define I8042_CMD_AUX_DISABLE 0x00a7 -#define I8042_CMD_AUX_ENABLE 0x00a8 -#define I8042_CMD_AUX_TEST 0x01a9 -#define I8042_CMD_AUX_SEND 0x10d4 -#define I8042_CMD_AUX_LOOP 0x11d3 - -#define I8042_CMD_MUX_PFX 0x0090 -#define I8042_CMD_MUX_SEND 0x1090 - -/* - * Status register bits. - */ - -#define I8042_STR_PARITY 0x80 -#define I8042_STR_TIMEOUT 0x40 -#define I8042_STR_AUXDATA 0x20 -#define I8042_STR_KEYLOCK 0x10 -#define I8042_STR_CMDDAT 0x08 -#define I8042_STR_MUXERR 0x04 -#define I8042_STR_IBF 0x02 -#define I8042_STR_OBF 0x01 - -/* - * Control register bits. - */ - -#define I8042_CTR_KBDINT 0x01 -#define I8042_CTR_AUXINT 0x02 -#define I8042_CTR_IGNKEYLOCK 0x08 -#define I8042_CTR_KBDDIS 0x10 -#define I8042_CTR_AUXDIS 0x20 -#define I8042_CTR_XLATE 0x40 - -struct serio; - -#if defined(CONFIG_SERIO_I8042) || defined(CONFIG_SERIO_I8042_MODULE) - -void i8042_lock_chip(void); -void i8042_unlock_chip(void); -int i8042_command(unsigned char *param, int command); -int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, - struct serio *serio)); -int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str, - struct serio *serio)); - -#else - -static inline void i8042_lock_chip(void) -{ -} - -static inline void i8042_unlock_chip(void) -{ -} - -static inline int i8042_command(unsigned char *param, int command) -{ - return -ENODEV; -} - -static inline int i8042_install_filter(bool (*filter)(unsigned char data, unsigned char str, - struct serio *serio)) -{ - return -ENODEV; -} - -static inline int i8042_remove_filter(bool (*filter)(unsigned char data, unsigned char str, - struct serio *serio)) -{ - return -ENODEV; -} - -#endif - -#endif diff --git a/src/linux/include/linux/icmp.h b/src/linux/include/linux/icmp.h deleted file mode 100644 index efc1849..0000000 --- a/src/linux/include/linux/icmp.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the ICMP protocol. - * - * Version: @(#)icmp.h 1.0.3 04/28/93 - * - * Author: Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_ICMP_H -#define _LINUX_ICMP_H - -#include -#include - -static inline struct icmphdr *icmp_hdr(const struct sk_buff *skb) -{ - return (struct icmphdr *)skb_transport_header(skb); -} -#endif /* _LINUX_ICMP_H */ diff --git a/src/linux/include/linux/icmpv6.h b/src/linux/include/linux/icmpv6.h deleted file mode 100644 index 57086e9..0000000 --- a/src/linux/include/linux/icmpv6.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef _LINUX_ICMPV6_H -#define _LINUX_ICMPV6_H - -#include -#include - -static inline struct icmp6hdr *icmp6_hdr(const struct sk_buff *skb) -{ - return (struct icmp6hdr *)skb_transport_header(skb); -} - -#include - -#if IS_ENABLED(CONFIG_IPV6) -extern void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info); - -typedef void ip6_icmp_send_t(struct sk_buff *skb, u8 type, u8 code, __u32 info, - const struct in6_addr *force_saddr); -extern int inet6_register_icmp_sender(ip6_icmp_send_t *fn); -extern int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn); -int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type, - unsigned int data_len); - -#else - -static inline void icmpv6_send(struct sk_buff *skb, - u8 type, u8 code, __u32 info) -{ - -} -#endif - -extern int icmpv6_init(void); -extern int icmpv6_err_convert(u8 type, u8 code, - int *err); -extern void icmpv6_cleanup(void); -extern void icmpv6_param_prob(struct sk_buff *skb, - u8 code, int pos); - -struct flowi6; -struct in6_addr; -extern void icmpv6_flow_init(struct sock *sk, - struct flowi6 *fl6, - u8 type, - const struct in6_addr *saddr, - const struct in6_addr *daddr, - int oif); -#endif diff --git a/src/linux/include/linux/idr.h b/src/linux/include/linux/idr.h deleted file mode 100644 index 083d61e..0000000 --- a/src/linux/include/linux/idr.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * include/linux/idr.h - * - * 2002-10-18 written by Jim Houston jim.houston@ccur.com - * Copyright (C) 2002 by Concurrent Computer Corporation - * Distributed under the GNU GPL license version 2. - * - * Small id to pointer translation service avoiding fixed sized - * tables. - */ - -#ifndef __IDR_H__ -#define __IDR_H__ - -#include -#include -#include -#include - -/* - * We want shallower trees and thus more bits covered at each layer. 8 - * bits gives us large enough first layer for most use cases and maximum - * tree depth of 4. Each idr_layer is slightly larger than 2k on 64bit and - * 1k on 32bit. - */ -#define IDR_BITS 8 -#define IDR_SIZE (1 << IDR_BITS) -#define IDR_MASK ((1 << IDR_BITS)-1) - -struct idr_layer { - int prefix; /* the ID prefix of this idr_layer */ - int layer; /* distance from leaf */ - struct idr_layer __rcu *ary[1<hint); - - if (hint && (id & ~IDR_MASK) == hint->prefix) - return rcu_dereference_raw(hint->ary[id & IDR_MASK]); - - return idr_find_slowpath(idr, id); -} - -/** - * idr_for_each_entry - iterate over an idr's elements of a given type - * @idp: idr handle - * @entry: the type * to use as cursor - * @id: id entry's key - * - * @entry and @id do not need to be initialized before the loop, and - * after normal terminatinon @entry is left with the value NULL. This - * is convenient for a "not found" value. - */ -#define idr_for_each_entry(idp, entry, id) \ - for (id = 0; ((entry) = idr_get_next(idp, &(id))) != NULL; ++id) - -/** - * idr_for_each_entry - continue iteration over an idr's elements of a given type - * @idp: idr handle - * @entry: the type * to use as cursor - * @id: id entry's key - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define idr_for_each_entry_continue(idp, entry, id) \ - for ((entry) = idr_get_next((idp), &(id)); \ - entry; \ - ++id, (entry) = idr_get_next((idp), &(id))) - -/* - * IDA - IDR based id allocator, use when translation from id to - * pointer isn't necessary. - * - * IDA_BITMAP_LONGS is calculated to be one less to accommodate - * ida_bitmap->nr_busy so that the whole struct fits in 128 bytes. - */ -#define IDA_CHUNK_SIZE 128 /* 128 bytes per chunk */ -#define IDA_BITMAP_LONGS (IDA_CHUNK_SIZE / sizeof(long) - 1) -#define IDA_BITMAP_BITS (IDA_BITMAP_LONGS * sizeof(long) * 8) - -struct ida_bitmap { - long nr_busy; - unsigned long bitmap[IDA_BITMAP_LONGS]; -}; - -struct ida { - struct idr idr; - struct ida_bitmap *free_bitmap; -}; - -#define IDA_INIT(name) { .idr = IDR_INIT((name).idr), .free_bitmap = NULL, } -#define DEFINE_IDA(name) struct ida name = IDA_INIT(name) - -int ida_pre_get(struct ida *ida, gfp_t gfp_mask); -int ida_get_new_above(struct ida *ida, int starting_id, int *p_id); -void ida_remove(struct ida *ida, int id); -void ida_destroy(struct ida *ida); -void ida_init(struct ida *ida); - -int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end, - gfp_t gfp_mask); -void ida_simple_remove(struct ida *ida, unsigned int id); - -/** - * ida_get_new - allocate new ID - * @ida: idr handle - * @p_id: pointer to the allocated handle - * - * Simple wrapper around ida_get_new_above() w/ @starting_id of zero. - */ -static inline int ida_get_new(struct ida *ida, int *p_id) -{ - return ida_get_new_above(ida, 0, p_id); -} - -void __init idr_init_cache(void); - -#endif /* __IDR_H__ */ diff --git a/src/linux/include/linux/ieee802154.h b/src/linux/include/linux/ieee802154.h deleted file mode 100644 index ddb8901..0000000 --- a/src/linux/include/linux/ieee802154.h +++ /dev/null @@ -1,363 +0,0 @@ -/* - * IEEE802.15.4-2003 specification - * - * Copyright (C) 2007, 2008 Siemens AG - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Written by: - * Pavel Smolenskiy - * Maxim Gorbachyov - * Maxim Osipov - * Dmitry Eremin-Solenikov - * Alexander Smirnov - */ - -#ifndef LINUX_IEEE802154_H -#define LINUX_IEEE802154_H - -#include -#include - -#define IEEE802154_MTU 127 -#define IEEE802154_ACK_PSDU_LEN 5 -#define IEEE802154_MIN_PSDU_LEN 9 -#define IEEE802154_FCS_LEN 2 -#define IEEE802154_MAX_AUTH_TAG_LEN 16 -#define IEEE802154_FC_LEN 2 -#define IEEE802154_SEQ_LEN 1 - -/* General MAC frame format: - * 2 bytes: Frame Control - * 1 byte: Sequence Number - * 20 bytes: Addressing fields - * 14 bytes: Auxiliary Security Header - */ -#define IEEE802154_MAX_HEADER_LEN (2 + 1 + 20 + 14) -#define IEEE802154_MIN_HEADER_LEN (IEEE802154_ACK_PSDU_LEN - \ - IEEE802154_FCS_LEN) - -#define IEEE802154_PAN_ID_BROADCAST 0xffff -#define IEEE802154_ADDR_SHORT_BROADCAST 0xffff -#define IEEE802154_ADDR_SHORT_UNSPEC 0xfffe - -#define IEEE802154_EXTENDED_ADDR_LEN 8 -#define IEEE802154_SHORT_ADDR_LEN 2 -#define IEEE802154_PAN_ID_LEN 2 - -#define IEEE802154_LIFS_PERIOD 40 -#define IEEE802154_SIFS_PERIOD 12 -#define IEEE802154_MAX_SIFS_FRAME_SIZE 18 - -#define IEEE802154_MAX_CHANNEL 26 -#define IEEE802154_MAX_PAGE 31 - -#define IEEE802154_FC_TYPE_BEACON 0x0 /* Frame is beacon */ -#define IEEE802154_FC_TYPE_DATA 0x1 /* Frame is data */ -#define IEEE802154_FC_TYPE_ACK 0x2 /* Frame is acknowledgment */ -#define IEEE802154_FC_TYPE_MAC_CMD 0x3 /* Frame is MAC command */ - -#define IEEE802154_FC_TYPE_SHIFT 0 -#define IEEE802154_FC_TYPE_MASK ((1 << 3) - 1) -#define IEEE802154_FC_TYPE(x) ((x & IEEE802154_FC_TYPE_MASK) >> IEEE802154_FC_TYPE_SHIFT) -#define IEEE802154_FC_SET_TYPE(v, x) do { \ - v = (((v) & ~IEEE802154_FC_TYPE_MASK) | \ - (((x) << IEEE802154_FC_TYPE_SHIFT) & IEEE802154_FC_TYPE_MASK)); \ - } while (0) - -#define IEEE802154_FC_SECEN_SHIFT 3 -#define IEEE802154_FC_SECEN (1 << IEEE802154_FC_SECEN_SHIFT) -#define IEEE802154_FC_FRPEND_SHIFT 4 -#define IEEE802154_FC_FRPEND (1 << IEEE802154_FC_FRPEND_SHIFT) -#define IEEE802154_FC_ACK_REQ_SHIFT 5 -#define IEEE802154_FC_ACK_REQ (1 << IEEE802154_FC_ACK_REQ_SHIFT) -#define IEEE802154_FC_INTRA_PAN_SHIFT 6 -#define IEEE802154_FC_INTRA_PAN (1 << IEEE802154_FC_INTRA_PAN_SHIFT) - -#define IEEE802154_FC_SAMODE_SHIFT 14 -#define IEEE802154_FC_SAMODE_MASK (3 << IEEE802154_FC_SAMODE_SHIFT) -#define IEEE802154_FC_DAMODE_SHIFT 10 -#define IEEE802154_FC_DAMODE_MASK (3 << IEEE802154_FC_DAMODE_SHIFT) - -#define IEEE802154_FC_VERSION_SHIFT 12 -#define IEEE802154_FC_VERSION_MASK (3 << IEEE802154_FC_VERSION_SHIFT) -#define IEEE802154_FC_VERSION(x) ((x & IEEE802154_FC_VERSION_MASK) >> IEEE802154_FC_VERSION_SHIFT) - -#define IEEE802154_FC_SAMODE(x) \ - (((x) & IEEE802154_FC_SAMODE_MASK) >> IEEE802154_FC_SAMODE_SHIFT) - -#define IEEE802154_FC_DAMODE(x) \ - (((x) & IEEE802154_FC_DAMODE_MASK) >> IEEE802154_FC_DAMODE_SHIFT) - -#define IEEE802154_SCF_SECLEVEL_MASK 7 -#define IEEE802154_SCF_SECLEVEL_SHIFT 0 -#define IEEE802154_SCF_SECLEVEL(x) (x & IEEE802154_SCF_SECLEVEL_MASK) -#define IEEE802154_SCF_KEY_ID_MODE_SHIFT 3 -#define IEEE802154_SCF_KEY_ID_MODE_MASK (3 << IEEE802154_SCF_KEY_ID_MODE_SHIFT) -#define IEEE802154_SCF_KEY_ID_MODE(x) \ - ((x & IEEE802154_SCF_KEY_ID_MODE_MASK) >> IEEE802154_SCF_KEY_ID_MODE_SHIFT) - -#define IEEE802154_SCF_KEY_IMPLICIT 0 -#define IEEE802154_SCF_KEY_INDEX 1 -#define IEEE802154_SCF_KEY_SHORT_INDEX 2 -#define IEEE802154_SCF_KEY_HW_INDEX 3 - -#define IEEE802154_SCF_SECLEVEL_NONE 0 -#define IEEE802154_SCF_SECLEVEL_MIC32 1 -#define IEEE802154_SCF_SECLEVEL_MIC64 2 -#define IEEE802154_SCF_SECLEVEL_MIC128 3 -#define IEEE802154_SCF_SECLEVEL_ENC 4 -#define IEEE802154_SCF_SECLEVEL_ENC_MIC32 5 -#define IEEE802154_SCF_SECLEVEL_ENC_MIC64 6 -#define IEEE802154_SCF_SECLEVEL_ENC_MIC128 7 - -/* MAC footer size */ -#define IEEE802154_MFR_SIZE 2 /* 2 octets */ - -/* MAC's Command Frames Identifiers */ -#define IEEE802154_CMD_ASSOCIATION_REQ 0x01 -#define IEEE802154_CMD_ASSOCIATION_RESP 0x02 -#define IEEE802154_CMD_DISASSOCIATION_NOTIFY 0x03 -#define IEEE802154_CMD_DATA_REQ 0x04 -#define IEEE802154_CMD_PANID_CONFLICT_NOTIFY 0x05 -#define IEEE802154_CMD_ORPHAN_NOTIFY 0x06 -#define IEEE802154_CMD_BEACON_REQ 0x07 -#define IEEE802154_CMD_COORD_REALIGN_NOTIFY 0x08 -#define IEEE802154_CMD_GTS_REQ 0x09 - -/* - * The return values of MAC operations - */ -enum { - /* - * The requested operation was completed successfully. - * For a transmission request, this value indicates - * a successful transmission. - */ - IEEE802154_SUCCESS = 0x0, - - /* The beacon was lost following a synchronization request. */ - IEEE802154_BEACON_LOSS = 0xe0, - /* - * A transmission could not take place due to activity on the - * channel, i.e., the CSMA-CA mechanism has failed. - */ - IEEE802154_CHNL_ACCESS_FAIL = 0xe1, - /* The GTS request has been denied by the PAN coordinator. */ - IEEE802154_DENINED = 0xe2, - /* The attempt to disable the transceiver has failed. */ - IEEE802154_DISABLE_TRX_FAIL = 0xe3, - /* - * The received frame induces a failed security check according to - * the security suite. - */ - IEEE802154_FAILED_SECURITY_CHECK = 0xe4, - /* - * The frame resulting from secure processing has a length that is - * greater than aMACMaxFrameSize. - */ - IEEE802154_FRAME_TOO_LONG = 0xe5, - /* - * The requested GTS transmission failed because the specified GTS - * either did not have a transmit GTS direction or was not defined. - */ - IEEE802154_INVALID_GTS = 0xe6, - /* - * A request to purge an MSDU from the transaction queue was made using - * an MSDU handle that was not found in the transaction table. - */ - IEEE802154_INVALID_HANDLE = 0xe7, - /* A parameter in the primitive is out of the valid range.*/ - IEEE802154_INVALID_PARAMETER = 0xe8, - /* No acknowledgment was received after aMaxFrameRetries. */ - IEEE802154_NO_ACK = 0xe9, - /* A scan operation failed to find any network beacons.*/ - IEEE802154_NO_BEACON = 0xea, - /* No response data were available following a request. */ - IEEE802154_NO_DATA = 0xeb, - /* The operation failed because a short address was not allocated. */ - IEEE802154_NO_SHORT_ADDRESS = 0xec, - /* - * A receiver enable request was unsuccessful because it could not be - * completed within the CAP. - */ - IEEE802154_OUT_OF_CAP = 0xed, - /* - * A PAN identifier conflict has been detected and communicated to the - * PAN coordinator. - */ - IEEE802154_PANID_CONFLICT = 0xee, - /* A coordinator realignment command has been received. */ - IEEE802154_REALIGMENT = 0xef, - /* The transaction has expired and its information discarded. */ - IEEE802154_TRANSACTION_EXPIRED = 0xf0, - /* There is no capacity to store the transaction. */ - IEEE802154_TRANSACTION_OVERFLOW = 0xf1, - /* - * The transceiver was in the transmitter enabled state when the - * receiver was requested to be enabled. - */ - IEEE802154_TX_ACTIVE = 0xf2, - /* The appropriate key is not available in the ACL. */ - IEEE802154_UNAVAILABLE_KEY = 0xf3, - /* - * A SET/GET request was issued with the identifier of a PIB attribute - * that is not supported. - */ - IEEE802154_UNSUPPORTED_ATTR = 0xf4, - /* - * A request to perform a scan operation failed because the MLME was - * in the process of performing a previously initiated scan operation. - */ - IEEE802154_SCAN_IN_PROGRESS = 0xfc, -}; - -/* frame control handling */ -#define IEEE802154_FCTL_FTYPE 0x0003 -#define IEEE802154_FCTL_ACKREQ 0x0020 -#define IEEE802154_FCTL_SECEN 0x0004 -#define IEEE802154_FCTL_INTRA_PAN 0x0040 -#define IEEE802154_FCTL_DADDR 0x0c00 -#define IEEE802154_FCTL_SADDR 0xc000 - -#define IEEE802154_FTYPE_DATA 0x0001 - -#define IEEE802154_FCTL_ADDR_NONE 0x0000 -#define IEEE802154_FCTL_DADDR_SHORT 0x0800 -#define IEEE802154_FCTL_DADDR_EXTENDED 0x0c00 -#define IEEE802154_FCTL_SADDR_SHORT 0x8000 -#define IEEE802154_FCTL_SADDR_EXTENDED 0xc000 - -/* - * ieee802154_is_data - check if type is IEEE802154_FTYPE_DATA - * @fc: frame control bytes in little-endian byteorder - */ -static inline int ieee802154_is_data(__le16 fc) -{ - return (fc & cpu_to_le16(IEEE802154_FCTL_FTYPE)) == - cpu_to_le16(IEEE802154_FTYPE_DATA); -} - -/** - * ieee802154_is_secen - check if Security bit is set - * @fc: frame control bytes in little-endian byteorder - */ -static inline bool ieee802154_is_secen(__le16 fc) -{ - return fc & cpu_to_le16(IEEE802154_FCTL_SECEN); -} - -/** - * ieee802154_is_ackreq - check if acknowledgment request bit is set - * @fc: frame control bytes in little-endian byteorder - */ -static inline bool ieee802154_is_ackreq(__le16 fc) -{ - return fc & cpu_to_le16(IEEE802154_FCTL_ACKREQ); -} - -/** - * ieee802154_is_intra_pan - check if intra pan id communication - * @fc: frame control bytes in little-endian byteorder - */ -static inline bool ieee802154_is_intra_pan(__le16 fc) -{ - return fc & cpu_to_le16(IEEE802154_FCTL_INTRA_PAN); -} - -/* - * ieee802154_daddr_mode - get daddr mode from fc - * @fc: frame control bytes in little-endian byteorder - */ -static inline __le16 ieee802154_daddr_mode(__le16 fc) -{ - return fc & cpu_to_le16(IEEE802154_FCTL_DADDR); -} - -/* - * ieee802154_saddr_mode - get saddr mode from fc - * @fc: frame control bytes in little-endian byteorder - */ -static inline __le16 ieee802154_saddr_mode(__le16 fc) -{ - return fc & cpu_to_le16(IEEE802154_FCTL_SADDR); -} - -/** - * ieee802154_is_valid_psdu_len - check if psdu len is valid - * available lengths: - * 0-4 Reserved - * 5 MPDU (Acknowledgment) - * 6-8 Reserved - * 9-127 MPDU - * - * @len: psdu len with (MHR + payload + MFR) - */ -static inline bool ieee802154_is_valid_psdu_len(u8 len) -{ - return (len == IEEE802154_ACK_PSDU_LEN || - (len >= IEEE802154_MIN_PSDU_LEN && len <= IEEE802154_MTU)); -} - -/** - * ieee802154_is_valid_extended_unicast_addr - check if extended addr is valid - * @addr: extended addr to check - */ -static inline bool ieee802154_is_valid_extended_unicast_addr(__le64 addr) -{ - /* Bail out if the address is all zero, or if the group - * address bit is set. - */ - return ((addr != cpu_to_le64(0x0000000000000000ULL)) && - !(addr & cpu_to_le64(0x0100000000000000ULL))); -} - -/** - * ieee802154_is_broadcast_short_addr - check if short addr is broadcast - * @addr: short addr to check - */ -static inline bool ieee802154_is_broadcast_short_addr(__le16 addr) -{ - return (addr == cpu_to_le16(IEEE802154_ADDR_SHORT_BROADCAST)); -} - -/** - * ieee802154_is_unspec_short_addr - check if short addr is unspecified - * @addr: short addr to check - */ -static inline bool ieee802154_is_unspec_short_addr(__le16 addr) -{ - return (addr == cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC)); -} - -/** - * ieee802154_is_valid_src_short_addr - check if source short address is valid - * @addr: short addr to check - */ -static inline bool ieee802154_is_valid_src_short_addr(__le16 addr) -{ - return !(ieee802154_is_broadcast_short_addr(addr) || - ieee802154_is_unspec_short_addr(addr)); -} - -/** - * ieee802154_random_extended_addr - generates a random extended address - * @addr: extended addr pointer to place the random address - */ -static inline void ieee802154_random_extended_addr(__le64 *addr) -{ - get_random_bytes(addr, IEEE802154_EXTENDED_ADDR_LEN); - - /* clear the group bit, and set the locally administered bit */ - ((u8 *)addr)[IEEE802154_EXTENDED_ADDR_LEN - 1] &= ~0x01; - ((u8 *)addr)[IEEE802154_EXTENDED_ADDR_LEN - 1] |= 0x02; -} - -#endif /* LINUX_IEEE802154_H */ diff --git a/src/linux/include/linux/if_arp.h b/src/linux/include/linux/if_arp.h deleted file mode 100644 index f563907..0000000 --- a/src/linux/include/linux/if_arp.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Global definitions for the ARP (RFC 826) protocol. - * - * Version: @(#)if_arp.h 1.0.1 04/16/93 - * - * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988 - * Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source. - * Ross Biro - * Fred N. van Kempen, - * Florian La Roche, - * Jonathan Layes - * Arnaldo Carvalho de Melo ARPHRD_HWX25 - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_IF_ARP_H -#define _LINUX_IF_ARP_H - -#include -#include - -static inline struct arphdr *arp_hdr(const struct sk_buff *skb) -{ - return (struct arphdr *)skb_network_header(skb); -} - -static inline int arp_hdr_len(struct net_device *dev) -{ - switch (dev->type) { -#if IS_ENABLED(CONFIG_FIREWIRE_NET) - case ARPHRD_IEEE1394: - /* ARP header, device address and 2 IP addresses */ - return sizeof(struct arphdr) + dev->addr_len + sizeof(u32) * 2; -#endif - default: - /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ - return sizeof(struct arphdr) + (dev->addr_len + sizeof(u32)) * 2; - } -} -#endif /* _LINUX_IF_ARP_H */ diff --git a/src/linux/include/linux/if_bridge.h b/src/linux/include/linux/if_bridge.h deleted file mode 100644 index c6587c0..0000000 --- a/src/linux/include/linux/if_bridge.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Linux ethernet bridge - * - * Authors: - * Lennert Buytenhek - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_IF_BRIDGE_H -#define _LINUX_IF_BRIDGE_H - - -#include -#include -#include - -struct br_ip { - union { - __be32 ip4; -#if IS_ENABLED(CONFIG_IPV6) - struct in6_addr ip6; -#endif - } u; - __be16 proto; - __u16 vid; -}; - -struct br_ip_list { - struct list_head list; - struct br_ip addr; -}; - -#define BR_HAIRPIN_MODE BIT(0) -#define BR_BPDU_GUARD BIT(1) -#define BR_ROOT_BLOCK BIT(2) -#define BR_MULTICAST_FAST_LEAVE BIT(3) -#define BR_ADMIN_COST BIT(4) -#define BR_LEARNING BIT(5) -#define BR_FLOOD BIT(6) -#define BR_AUTO_MASK (BR_FLOOD | BR_LEARNING) -#define BR_PROMISC BIT(7) -#define BR_PROXYARP BIT(8) -#define BR_LEARNING_SYNC BIT(9) -#define BR_PROXYARP_WIFI BIT(10) -#define BR_MCAST_FLOOD BIT(11) - -#define BR_DEFAULT_AGEING_TIME (300 * HZ) - -extern void brioctl_set(int (*ioctl_hook)(struct net *, unsigned int, void __user *)); - -typedef int br_should_route_hook_t(struct sk_buff *skb); -extern br_should_route_hook_t __rcu *br_should_route_hook; - -#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_BRIDGE_IGMP_SNOOPING) -int br_multicast_list_adjacent(struct net_device *dev, - struct list_head *br_ip_list); -bool br_multicast_has_querier_anywhere(struct net_device *dev, int proto); -bool br_multicast_has_querier_adjacent(struct net_device *dev, int proto); -#else -static inline int br_multicast_list_adjacent(struct net_device *dev, - struct list_head *br_ip_list) -{ - return 0; -} -static inline bool br_multicast_has_querier_anywhere(struct net_device *dev, - int proto) -{ - return false; -} -static inline bool br_multicast_has_querier_adjacent(struct net_device *dev, - int proto) -{ - return false; -} -#endif - -#endif diff --git a/src/linux/include/linux/if_ether.h b/src/linux/include/linux/if_ether.h deleted file mode 100644 index 548fd53..0000000 --- a/src/linux/include/linux/if_ether.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Global definitions for the Ethernet IEEE 802.3 interface. - * - * Version: @(#)if_ether.h 1.0.1a 02/08/94 - * - * Author: Fred N. van Kempen, - * Donald Becker, - * Alan Cox, - * Steve Whitehouse, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_IF_ETHER_H -#define _LINUX_IF_ETHER_H - -#include -#include - -static inline struct ethhdr *eth_hdr(const struct sk_buff *skb) -{ - return (struct ethhdr *)skb_mac_header(skb); -} - -static inline struct ethhdr *inner_eth_hdr(const struct sk_buff *skb) -{ - return (struct ethhdr *)skb_inner_mac_header(skb); -} - -int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr); - -extern ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len); - -#endif /* _LINUX_IF_ETHER_H */ diff --git a/src/linux/include/linux/if_fddi.h b/src/linux/include/linux/if_fddi.h deleted file mode 100644 index f5550b3..0000000 --- a/src/linux/include/linux/if_fddi.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Global definitions for the ANSI FDDI interface. - * - * Version: @(#)if_fddi.h 1.0.2 Sep 29 2004 - * - * Author: Lawrence V. Stefani, - * - * if_fddi.h is based on previous if_ether.h and if_tr.h work by - * Fred N. van Kempen, - * Donald Becker, - * Alan Cox, - * Steve Whitehouse, - * Peter De Schrijver, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_IF_FDDI_H -#define _LINUX_IF_FDDI_H - -#include -#include - -/* Define FDDI statistics structure */ -struct fddi_statistics { - - /* Generic statistics. */ - - struct net_device_stats gen; - - /* Detailed FDDI statistics. Adopted from RFC 1512 */ - - __u8 smt_station_id[8]; - __u32 smt_op_version_id; - __u32 smt_hi_version_id; - __u32 smt_lo_version_id; - __u8 smt_user_data[32]; - __u32 smt_mib_version_id; - __u32 smt_mac_cts; - __u32 smt_non_master_cts; - __u32 smt_master_cts; - __u32 smt_available_paths; - __u32 smt_config_capabilities; - __u32 smt_config_policy; - __u32 smt_connection_policy; - __u32 smt_t_notify; - __u32 smt_stat_rpt_policy; - __u32 smt_trace_max_expiration; - __u32 smt_bypass_present; - __u32 smt_ecm_state; - __u32 smt_cf_state; - __u32 smt_remote_disconnect_flag; - __u32 smt_station_status; - __u32 smt_peer_wrap_flag; - __u32 smt_time_stamp; - __u32 smt_transition_time_stamp; - __u32 mac_frame_status_functions; - __u32 mac_t_max_capability; - __u32 mac_tvx_capability; - __u32 mac_available_paths; - __u32 mac_current_path; - __u8 mac_upstream_nbr[FDDI_K_ALEN]; - __u8 mac_downstream_nbr[FDDI_K_ALEN]; - __u8 mac_old_upstream_nbr[FDDI_K_ALEN]; - __u8 mac_old_downstream_nbr[FDDI_K_ALEN]; - __u32 mac_dup_address_test; - __u32 mac_requested_paths; - __u32 mac_downstream_port_type; - __u8 mac_smt_address[FDDI_K_ALEN]; - __u32 mac_t_req; - __u32 mac_t_neg; - __u32 mac_t_max; - __u32 mac_tvx_value; - __u32 mac_frame_cts; - __u32 mac_copied_cts; - __u32 mac_transmit_cts; - __u32 mac_error_cts; - __u32 mac_lost_cts; - __u32 mac_frame_error_threshold; - __u32 mac_frame_error_ratio; - __u32 mac_rmt_state; - __u32 mac_da_flag; - __u32 mac_una_da_flag; - __u32 mac_frame_error_flag; - __u32 mac_ma_unitdata_available; - __u32 mac_hardware_present; - __u32 mac_ma_unitdata_enable; - __u32 path_tvx_lower_bound; - __u32 path_t_max_lower_bound; - __u32 path_max_t_req; - __u32 path_configuration[8]; - __u32 port_my_type[2]; - __u32 port_neighbor_type[2]; - __u32 port_connection_policies[2]; - __u32 port_mac_indicated[2]; - __u32 port_current_path[2]; - __u8 port_requested_paths[3*2]; - __u32 port_mac_placement[2]; - __u32 port_available_paths[2]; - __u32 port_pmd_class[2]; - __u32 port_connection_capabilities[2]; - __u32 port_bs_flag[2]; - __u32 port_lct_fail_cts[2]; - __u32 port_ler_estimate[2]; - __u32 port_lem_reject_cts[2]; - __u32 port_lem_cts[2]; - __u32 port_ler_cutoff[2]; - __u32 port_ler_alarm[2]; - __u32 port_connect_state[2]; - __u32 port_pcm_state[2]; - __u32 port_pc_withhold[2]; - __u32 port_ler_flag[2]; - __u32 port_hardware_present[2]; -}; -#endif /* _LINUX_IF_FDDI_H */ diff --git a/src/linux/include/linux/if_frad.h b/src/linux/include/linux/if_frad.h deleted file mode 100644 index 4316aa1..0000000 --- a/src/linux/include/linux/if_frad.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * DLCI/FRAD Definitions for Frame Relay Access Devices. DLCI devices are - * created for each DLCI associated with a FRAD. The FRAD driver - * is not truly a network device, but the lower level device - * handler. This allows other FRAD manufacturers to use the DLCI - * code, including its RFC1490 encapsulation alongside the current - * implementation for the Sangoma cards. - * - * Version: @(#)if_ifrad.h 0.15 31 Mar 96 - * - * Author: Mike McLagan - * - * Changes: - * 0.15 Mike McLagan changed structure defs (packed) - * re-arranged flags - * added DLCI_RET vars - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _FRAD_H_ -#define _FRAD_H_ - -#include - - -#if defined(CONFIG_DLCI) || defined(CONFIG_DLCI_MODULE) - -/* these are the fields of an RFC 1490 header */ -struct frhdr -{ - unsigned char control; - - /* for IP packets, this can be the NLPID */ - unsigned char pad; - - unsigned char NLPID; - unsigned char OUI[3]; - __be16 PID; - -#define IP_NLPID pad -} __packed; - -/* see RFC 1490 for the definition of the following */ -#define FRAD_I_UI 0x03 - -#define FRAD_P_PADDING 0x00 -#define FRAD_P_Q933 0x08 -#define FRAD_P_SNAP 0x80 -#define FRAD_P_CLNP 0x81 -#define FRAD_P_IP 0xCC - -struct dlci_local -{ - struct net_device *master; - struct net_device *slave; - struct dlci_conf config; - int configured; - struct list_head list; - - /* callback function */ - void (*receive)(struct sk_buff *skb, struct net_device *); -}; - -struct frad_local -{ - struct net_device_stats stats; - - /* devices which this FRAD is slaved to */ - struct net_device *master[CONFIG_DLCI_MAX]; - short dlci[CONFIG_DLCI_MAX]; - - struct frad_conf config; - int configured; /* has this device been configured */ - int initialized; /* mem_start, port, irq set ? */ - - /* callback functions */ - int (*activate)(struct net_device *, struct net_device *); - int (*deactivate)(struct net_device *, struct net_device *); - int (*assoc)(struct net_device *, struct net_device *); - int (*deassoc)(struct net_device *, struct net_device *); - int (*dlci_conf)(struct net_device *, struct net_device *, int get); - - /* fields that are used by the Sangoma SDLA cards */ - struct timer_list timer; - int type; /* adapter type */ - int state; /* state of the S502/8 control latch */ - int buffer; /* current buffer for S508 firmware */ -}; - -#endif /* CONFIG_DLCI || CONFIG_DLCI_MODULE */ - -extern void dlci_ioctl_set(int (*hook)(unsigned int, void __user *)); - -#endif diff --git a/src/linux/include/linux/if_link.h b/src/linux/include/linux/if_link.h deleted file mode 100644 index 0b17c58..0000000 --- a/src/linux/include/linux/if_link.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _LINUX_IF_LINK_H -#define _LINUX_IF_LINK_H - -#include - - -/* We don't want this structure exposed to user space */ -struct ifla_vf_stats { - __u64 rx_packets; - __u64 tx_packets; - __u64 rx_bytes; - __u64 tx_bytes; - __u64 broadcast; - __u64 multicast; -}; - -struct ifla_vf_info { - __u32 vf; - __u8 mac[32]; - __u32 vlan; - __u32 qos; - __u32 spoofchk; - __u32 linkstate; - __u32 min_tx_rate; - __u32 max_tx_rate; - __u32 rss_query_en; - __u32 trusted; - __be16 vlan_proto; -}; -#endif /* _LINUX_IF_LINK_H */ diff --git a/src/linux/include/linux/if_macvlan.h b/src/linux/include/linux/if_macvlan.h deleted file mode 100644 index a4ccc31..0000000 --- a/src/linux/include/linux/if_macvlan.h +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef _LINUX_IF_MACVLAN_H -#define _LINUX_IF_MACVLAN_H - -#include -#include -#include -#include -#include -#include -#include - -#if IS_ENABLED(CONFIG_MACVTAP) -struct socket *macvtap_get_socket(struct file *); -#else -#include -#include -struct file; -struct socket; -static inline struct socket *macvtap_get_socket(struct file *f) -{ - return ERR_PTR(-EINVAL); -} -#endif /* CONFIG_MACVTAP */ - -struct macvlan_port; -struct macvtap_queue; - -/* - * Maximum times a macvtap device can be opened. This can be used to - * configure the number of receive queue, e.g. for multiqueue virtio. - */ -#define MAX_MACVTAP_QUEUES 256 - -#define MACVLAN_MC_FILTER_BITS 8 -#define MACVLAN_MC_FILTER_SZ (1 << MACVLAN_MC_FILTER_BITS) - -struct macvlan_dev { - struct net_device *dev; - struct list_head list; - struct hlist_node hlist; - struct macvlan_port *port; - struct net_device *lowerdev; - void *fwd_priv; - struct vlan_pcpu_stats __percpu *pcpu_stats; - - DECLARE_BITMAP(mc_filter, MACVLAN_MC_FILTER_SZ); - - netdev_features_t set_features; - enum macvlan_mode mode; - u16 flags; - /* This array tracks active taps. */ - struct macvtap_queue __rcu *taps[MAX_MACVTAP_QUEUES]; - /* This list tracks all taps (both enabled and disabled) */ - struct list_head queue_list; - int numvtaps; - int numqueues; - netdev_features_t tap_features; - int minor; - int nest_level; -#ifdef CONFIG_NET_POLL_CONTROLLER - struct netpoll *netpoll; -#endif - unsigned int macaddr_count; -}; - -static inline void macvlan_count_rx(const struct macvlan_dev *vlan, - unsigned int len, bool success, - bool multicast) -{ - if (likely(success)) { - struct vlan_pcpu_stats *pcpu_stats; - - pcpu_stats = this_cpu_ptr(vlan->pcpu_stats); - u64_stats_update_begin(&pcpu_stats->syncp); - pcpu_stats->rx_packets++; - pcpu_stats->rx_bytes += len; - if (multicast) - pcpu_stats->rx_multicast++; - u64_stats_update_end(&pcpu_stats->syncp); - } else { - this_cpu_inc(vlan->pcpu_stats->rx_errors); - } -} - -extern void macvlan_common_setup(struct net_device *dev); - -extern int macvlan_common_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]); - -extern void macvlan_count_rx(const struct macvlan_dev *vlan, - unsigned int len, bool success, - bool multicast); - -extern void macvlan_dellink(struct net_device *dev, struct list_head *head); - -extern int macvlan_link_register(struct rtnl_link_ops *ops); - -#if IS_ENABLED(CONFIG_MACVLAN) -static inline struct net_device * -macvlan_dev_real_dev(const struct net_device *dev) -{ - struct macvlan_dev *macvlan = netdev_priv(dev); - - return macvlan->lowerdev; -} -#else -static inline struct net_device * -macvlan_dev_real_dev(const struct net_device *dev) -{ - BUG(); - return NULL; -} -#endif - -#endif /* _LINUX_IF_MACVLAN_H */ diff --git a/src/linux/include/linux/if_pppol2tp.h b/src/linux/include/linux/if_pppol2tp.h deleted file mode 100644 index 0fb71e5..0000000 --- a/src/linux/include/linux/if_pppol2tp.h +++ /dev/null @@ -1,21 +0,0 @@ -/*************************************************************************** - * Linux PPP over L2TP (PPPoL2TP) Socket Implementation (RFC 2661) - * - * This file supplies definitions required by the PPP over L2TP driver - * (l2tp_ppp.c). All version information wrt this file is located in l2tp_ppp.c - * - * License: - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ -#ifndef __LINUX_IF_PPPOL2TP_H -#define __LINUX_IF_PPPOL2TP_H - -#include -#include -#include - -#endif diff --git a/src/linux/include/linux/if_pppox.h b/src/linux/include/linux/if_pppox.h deleted file mode 100644 index ba7a9b0..0000000 --- a/src/linux/include/linux/if_pppox.h +++ /dev/null @@ -1,97 +0,0 @@ -/*************************************************************************** - * Linux PPP over X - Generic PPP transport layer sockets - * Linux PPP over Ethernet (PPPoE) Socket Implementation (RFC 2516) - * - * This file supplies definitions required by the PPP over Ethernet driver - * (pppox.c). All version information wrt this file is located in pppox.c - * - * License: - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ -#ifndef __LINUX_IF_PPPOX_H -#define __LINUX_IF_PPPOX_H - -#include -#include -#include -#include -#include -#include - -static inline struct pppoe_hdr *pppoe_hdr(const struct sk_buff *skb) -{ - return (struct pppoe_hdr *)skb_network_header(skb); -} - -struct pppoe_opt { - struct net_device *dev; /* device associated with socket*/ - int ifindex; /* ifindex of device associated with socket */ - struct pppoe_addr pa; /* what this socket is bound to*/ - struct sockaddr_pppox relay; /* what socket data will be - relayed to (PPPoE relaying) */ - struct work_struct padt_work;/* Work item for handling PADT */ -}; - -struct pptp_opt { - struct pptp_addr src_addr; - struct pptp_addr dst_addr; - u32 ack_sent, ack_recv; - u32 seq_sent, seq_recv; - int ppp_flags; -}; -#include - -struct pppox_sock { - /* struct sock must be the first member of pppox_sock */ - struct sock sk; - struct ppp_channel chan; - struct pppox_sock *next; /* for hash table */ - union { - struct pppoe_opt pppoe; - struct pptp_opt pptp; - } proto; - __be16 num; -}; -#define pppoe_dev proto.pppoe.dev -#define pppoe_ifindex proto.pppoe.ifindex -#define pppoe_pa proto.pppoe.pa -#define pppoe_relay proto.pppoe.relay - -static inline struct pppox_sock *pppox_sk(struct sock *sk) -{ - return (struct pppox_sock *)sk; -} - -static inline struct sock *sk_pppox(struct pppox_sock *po) -{ - return (struct sock *)po; -} - -struct module; - -struct pppox_proto { - int (*create)(struct net *net, struct socket *sock, int kern); - int (*ioctl)(struct socket *sock, unsigned int cmd, - unsigned long arg); - struct module *owner; -}; - -extern int register_pppox_proto(int proto_num, const struct pppox_proto *pp); -extern void unregister_pppox_proto(int proto_num); -extern void pppox_unbind_sock(struct sock *sk);/* delete ppp-channel binding */ -extern int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); - -/* PPPoX socket states */ -enum { - PPPOX_NONE = 0, /* initial state */ - PPPOX_CONNECTED = 1, /* connection established ==TCP_ESTABLISHED */ - PPPOX_BOUND = 2, /* bound to ppp device */ - PPPOX_RELAY = 4, /* forwarding is enabled */ - PPPOX_DEAD = 16 /* dead, useless, please clean me up!*/ -}; - -#endif /* !(__LINUX_IF_PPPOX_H) */ diff --git a/src/linux/include/linux/if_tun.h b/src/linux/include/linux/if_tun.h deleted file mode 100644 index ed6da2e..0000000 --- a/src/linux/include/linux/if_tun.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Universal TUN/TAP device driver. - * Copyright (C) 1999-2000 Maxim Krasnyansky - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef __IF_TUN_H -#define __IF_TUN_H - -#include - -#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE) -struct socket *tun_get_socket(struct file *); -#else -#include -#include -struct file; -struct socket; -static inline struct socket *tun_get_socket(struct file *f) -{ - return ERR_PTR(-EINVAL); -} -#endif /* CONFIG_TUN */ -#endif /* __IF_TUN_H */ diff --git a/src/linux/include/linux/if_tunnel.h b/src/linux/include/linux/if_tunnel.h deleted file mode 100644 index 712710b..0000000 --- a/src/linux/include/linux/if_tunnel.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _IF_TUNNEL_H_ -#define _IF_TUNNEL_H_ - -#include -#include -#include -#include - -/* - * Locking : hash tables are protected by RCU and RTNL - */ - -#define for_each_ip_tunnel_rcu(pos, start) \ - for (pos = rcu_dereference(start); pos; pos = rcu_dereference(pos->next)) - -#endif /* _IF_TUNNEL_H_ */ diff --git a/src/linux/include/linux/if_vlan.h b/src/linux/include/linux/if_vlan.h deleted file mode 100644 index 3319d97..0000000 --- a/src/linux/include/linux/if_vlan.h +++ /dev/null @@ -1,665 +0,0 @@ -/* - * VLAN An implementation of 802.1Q VLAN tagging. - * - * Authors: Ben Greear - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ -#ifndef _LINUX_IF_VLAN_H_ -#define _LINUX_IF_VLAN_H_ - -#include -#include -#include -#include -#include - -#define VLAN_HLEN 4 /* The additional bytes required by VLAN - * (in addition to the Ethernet header) - */ -#define VLAN_ETH_HLEN 18 /* Total octets in header. */ -#define VLAN_ETH_ZLEN 64 /* Min. octets in frame sans FCS */ - -/* - * According to 802.3ac, the packet can be 4 bytes longer. --Klika Jan - */ -#define VLAN_ETH_DATA_LEN 1500 /* Max. octets in payload */ -#define VLAN_ETH_FRAME_LEN 1518 /* Max. octets in frame sans FCS */ - -/* - * struct vlan_hdr - vlan header - * @h_vlan_TCI: priority and VLAN ID - * @h_vlan_encapsulated_proto: packet type ID or len - */ -struct vlan_hdr { - __be16 h_vlan_TCI; - __be16 h_vlan_encapsulated_proto; -}; - -/** - * struct vlan_ethhdr - vlan ethernet header (ethhdr + vlan_hdr) - * @h_dest: destination ethernet address - * @h_source: source ethernet address - * @h_vlan_proto: ethernet protocol - * @h_vlan_TCI: priority and VLAN ID - * @h_vlan_encapsulated_proto: packet type ID or len - */ -struct vlan_ethhdr { - unsigned char h_dest[ETH_ALEN]; - unsigned char h_source[ETH_ALEN]; - __be16 h_vlan_proto; - __be16 h_vlan_TCI; - __be16 h_vlan_encapsulated_proto; -}; - -#include - -static inline struct vlan_ethhdr *vlan_eth_hdr(const struct sk_buff *skb) -{ - return (struct vlan_ethhdr *)skb_mac_header(skb); -} - -#define VLAN_PRIO_MASK 0xe000 /* Priority Code Point */ -#define VLAN_PRIO_SHIFT 13 -#define VLAN_CFI_MASK 0x1000 /* Canonical Format Indicator */ -#define VLAN_TAG_PRESENT VLAN_CFI_MASK -#define VLAN_VID_MASK 0x0fff /* VLAN Identifier */ -#define VLAN_N_VID 4096 - -/* found in socket.c */ -extern void vlan_ioctl_set(int (*hook)(struct net *, void __user *)); - -static inline bool is_vlan_dev(const struct net_device *dev) -{ - return dev->priv_flags & IFF_802_1Q_VLAN; -} - -#define skb_vlan_tag_present(__skb) ((__skb)->vlan_tci & VLAN_TAG_PRESENT) -#define skb_vlan_tag_get(__skb) ((__skb)->vlan_tci & ~VLAN_TAG_PRESENT) -#define skb_vlan_tag_get_id(__skb) ((__skb)->vlan_tci & VLAN_VID_MASK) -#define skb_vlan_tag_get_prio(__skb) ((__skb)->vlan_tci & VLAN_PRIO_MASK) - -/** - * struct vlan_pcpu_stats - VLAN percpu rx/tx stats - * @rx_packets: number of received packets - * @rx_bytes: number of received bytes - * @rx_multicast: number of received multicast packets - * @tx_packets: number of transmitted packets - * @tx_bytes: number of transmitted bytes - * @syncp: synchronization point for 64bit counters - * @rx_errors: number of rx errors - * @tx_dropped: number of tx drops - */ -struct vlan_pcpu_stats { - u64 rx_packets; - u64 rx_bytes; - u64 rx_multicast; - u64 tx_packets; - u64 tx_bytes; - struct u64_stats_sync syncp; - u32 rx_errors; - u32 tx_dropped; -}; - -#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) - -extern struct net_device *__vlan_find_dev_deep_rcu(struct net_device *real_dev, - __be16 vlan_proto, u16 vlan_id); -extern struct net_device *vlan_dev_real_dev(const struct net_device *dev); -extern u16 vlan_dev_vlan_id(const struct net_device *dev); -extern __be16 vlan_dev_vlan_proto(const struct net_device *dev); - -/** - * struct vlan_priority_tci_mapping - vlan egress priority mappings - * @priority: skb priority - * @vlan_qos: vlan priority: (skb->priority << 13) & 0xE000 - * @next: pointer to next struct - */ -struct vlan_priority_tci_mapping { - u32 priority; - u16 vlan_qos; - struct vlan_priority_tci_mapping *next; -}; - -struct proc_dir_entry; -struct netpoll; - -/** - * struct vlan_dev_priv - VLAN private device data - * @nr_ingress_mappings: number of ingress priority mappings - * @ingress_priority_map: ingress priority mappings - * @nr_egress_mappings: number of egress priority mappings - * @egress_priority_map: hash of egress priority mappings - * @vlan_proto: VLAN encapsulation protocol - * @vlan_id: VLAN identifier - * @flags: device flags - * @real_dev: underlying netdevice - * @real_dev_addr: address of underlying netdevice - * @dent: proc dir entry - * @vlan_pcpu_stats: ptr to percpu rx stats - */ -struct vlan_dev_priv { - unsigned int nr_ingress_mappings; - u32 ingress_priority_map[8]; - unsigned int nr_egress_mappings; - struct vlan_priority_tci_mapping *egress_priority_map[16]; - - __be16 vlan_proto; - u16 vlan_id; - u16 flags; - - struct net_device *real_dev; - unsigned char real_dev_addr[ETH_ALEN]; - - struct proc_dir_entry *dent; - struct vlan_pcpu_stats __percpu *vlan_pcpu_stats; -#ifdef CONFIG_NET_POLL_CONTROLLER - struct netpoll *netpoll; -#endif - unsigned int nest_level; -}; - -static inline struct vlan_dev_priv *vlan_dev_priv(const struct net_device *dev) -{ - return netdev_priv(dev); -} - -static inline u16 -vlan_dev_get_egress_qos_mask(struct net_device *dev, u32 skprio) -{ - struct vlan_priority_tci_mapping *mp; - - smp_rmb(); /* coupled with smp_wmb() in vlan_dev_set_egress_priority() */ - - mp = vlan_dev_priv(dev)->egress_priority_map[(skprio & 0xF)]; - while (mp) { - if (mp->priority == skprio) { - return mp->vlan_qos; /* This should already be shifted - * to mask correctly with the - * VLAN's TCI */ - } - mp = mp->next; - } - return 0; -} - -extern bool vlan_do_receive(struct sk_buff **skb); - -extern int vlan_vid_add(struct net_device *dev, __be16 proto, u16 vid); -extern void vlan_vid_del(struct net_device *dev, __be16 proto, u16 vid); - -extern int vlan_vids_add_by_dev(struct net_device *dev, - const struct net_device *by_dev); -extern void vlan_vids_del_by_dev(struct net_device *dev, - const struct net_device *by_dev); - -extern bool vlan_uses_dev(const struct net_device *dev); - -static inline int vlan_get_encap_level(struct net_device *dev) -{ - BUG_ON(!is_vlan_dev(dev)); - return vlan_dev_priv(dev)->nest_level; -} -#else -static inline struct net_device * -__vlan_find_dev_deep_rcu(struct net_device *real_dev, - __be16 vlan_proto, u16 vlan_id) -{ - return NULL; -} - -static inline struct net_device *vlan_dev_real_dev(const struct net_device *dev) -{ - BUG(); - return NULL; -} - -static inline u16 vlan_dev_vlan_id(const struct net_device *dev) -{ - BUG(); - return 0; -} - -static inline __be16 vlan_dev_vlan_proto(const struct net_device *dev) -{ - BUG(); - return 0; -} - -static inline u16 vlan_dev_get_egress_qos_mask(struct net_device *dev, - u32 skprio) -{ - return 0; -} - -static inline bool vlan_do_receive(struct sk_buff **skb) -{ - return false; -} - -static inline int vlan_vid_add(struct net_device *dev, __be16 proto, u16 vid) -{ - return 0; -} - -static inline void vlan_vid_del(struct net_device *dev, __be16 proto, u16 vid) -{ -} - -static inline int vlan_vids_add_by_dev(struct net_device *dev, - const struct net_device *by_dev) -{ - return 0; -} - -static inline void vlan_vids_del_by_dev(struct net_device *dev, - const struct net_device *by_dev) -{ -} - -static inline bool vlan_uses_dev(const struct net_device *dev) -{ - return false; -} -static inline int vlan_get_encap_level(struct net_device *dev) -{ - BUG(); - return 0; -} -#endif - -/** - * eth_type_vlan - check for valid vlan ether type. - * @ethertype: ether type to check - * - * Returns true if the ether type is a vlan ether type. - */ -static inline bool eth_type_vlan(__be16 ethertype) -{ - switch (ethertype) { - case htons(ETH_P_8021Q): - case htons(ETH_P_8021AD): - return true; - default: - return false; - } -} - -static inline bool vlan_hw_offload_capable(netdev_features_t features, - __be16 proto) -{ - if (proto == htons(ETH_P_8021Q) && features & NETIF_F_HW_VLAN_CTAG_TX) - return true; - if (proto == htons(ETH_P_8021AD) && features & NETIF_F_HW_VLAN_STAG_TX) - return true; - return false; -} - -/** - * __vlan_insert_tag - regular VLAN tag inserting - * @skb: skbuff to tag - * @vlan_proto: VLAN encapsulation protocol - * @vlan_tci: VLAN TCI to insert - * - * Inserts the VLAN tag into @skb as part of the payload - * Returns error if skb_cow_head failes. - * - * Does not change skb->protocol so this function can be used during receive. - */ -static inline int __vlan_insert_tag(struct sk_buff *skb, - __be16 vlan_proto, u16 vlan_tci) -{ - struct vlan_ethhdr *veth; - - if (skb_cow_head(skb, VLAN_HLEN) < 0) - return -ENOMEM; - - veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN); - - /* Move the mac addresses to the beginning of the new header. */ - memmove(skb->data, skb->data + VLAN_HLEN, 2 * ETH_ALEN); - skb->mac_header -= VLAN_HLEN; - - /* first, the ethernet type */ - veth->h_vlan_proto = vlan_proto; - - /* now, the TCI */ - veth->h_vlan_TCI = htons(vlan_tci); - - return 0; -} - -/** - * vlan_insert_tag - regular VLAN tag inserting - * @skb: skbuff to tag - * @vlan_proto: VLAN encapsulation protocol - * @vlan_tci: VLAN TCI to insert - * - * Inserts the VLAN tag into @skb as part of the payload - * Returns a VLAN tagged skb. If a new skb is created, @skb is freed. - * - * Following the skb_unshare() example, in case of error, the calling function - * doesn't have to worry about freeing the original skb. - * - * Does not change skb->protocol so this function can be used during receive. - */ -static inline struct sk_buff *vlan_insert_tag(struct sk_buff *skb, - __be16 vlan_proto, u16 vlan_tci) -{ - int err; - - err = __vlan_insert_tag(skb, vlan_proto, vlan_tci); - if (err) { - dev_kfree_skb_any(skb); - return NULL; - } - return skb; -} - -/** - * vlan_insert_tag_set_proto - regular VLAN tag inserting - * @skb: skbuff to tag - * @vlan_proto: VLAN encapsulation protocol - * @vlan_tci: VLAN TCI to insert - * - * Inserts the VLAN tag into @skb as part of the payload - * Returns a VLAN tagged skb. If a new skb is created, @skb is freed. - * - * Following the skb_unshare() example, in case of error, the calling function - * doesn't have to worry about freeing the original skb. - */ -static inline struct sk_buff *vlan_insert_tag_set_proto(struct sk_buff *skb, - __be16 vlan_proto, - u16 vlan_tci) -{ - skb = vlan_insert_tag(skb, vlan_proto, vlan_tci); - if (skb) - skb->protocol = vlan_proto; - return skb; -} - -/* - * __vlan_hwaccel_push_inside - pushes vlan tag to the payload - * @skb: skbuff to tag - * - * Pushes the VLAN tag from @skb->vlan_tci inside to the payload. - * - * Following the skb_unshare() example, in case of error, the calling function - * doesn't have to worry about freeing the original skb. - */ -static inline struct sk_buff *__vlan_hwaccel_push_inside(struct sk_buff *skb) -{ - skb = vlan_insert_tag_set_proto(skb, skb->vlan_proto, - skb_vlan_tag_get(skb)); - if (likely(skb)) - skb->vlan_tci = 0; - return skb; -} -/* - * vlan_hwaccel_push_inside - pushes vlan tag to the payload - * @skb: skbuff to tag - * - * Checks is tag is present in @skb->vlan_tci and if it is, it pushes the - * VLAN tag from @skb->vlan_tci inside to the payload. - * - * Following the skb_unshare() example, in case of error, the calling function - * doesn't have to worry about freeing the original skb. - */ -static inline struct sk_buff *vlan_hwaccel_push_inside(struct sk_buff *skb) -{ - if (skb_vlan_tag_present(skb)) - skb = __vlan_hwaccel_push_inside(skb); - return skb; -} - -/** - * __vlan_hwaccel_put_tag - hardware accelerated VLAN inserting - * @skb: skbuff to tag - * @vlan_proto: VLAN encapsulation protocol - * @vlan_tci: VLAN TCI to insert - * - * Puts the VLAN TCI in @skb->vlan_tci and lets the device do the rest - */ -static inline void __vlan_hwaccel_put_tag(struct sk_buff *skb, - __be16 vlan_proto, u16 vlan_tci) -{ - skb->vlan_proto = vlan_proto; - skb->vlan_tci = VLAN_TAG_PRESENT | vlan_tci; -} - -/** - * __vlan_get_tag - get the VLAN ID that is part of the payload - * @skb: skbuff to query - * @vlan_tci: buffer to store value - * - * Returns error if the skb is not of VLAN type - */ -static inline int __vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci) -{ - struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb->data; - - if (!eth_type_vlan(veth->h_vlan_proto)) - return -EINVAL; - - *vlan_tci = ntohs(veth->h_vlan_TCI); - return 0; -} - -/** - * __vlan_hwaccel_get_tag - get the VLAN ID that is in @skb->cb[] - * @skb: skbuff to query - * @vlan_tci: buffer to store value - * - * Returns error if @skb->vlan_tci is not set correctly - */ -static inline int __vlan_hwaccel_get_tag(const struct sk_buff *skb, - u16 *vlan_tci) -{ - if (skb_vlan_tag_present(skb)) { - *vlan_tci = skb_vlan_tag_get(skb); - return 0; - } else { - *vlan_tci = 0; - return -EINVAL; - } -} - -#define HAVE_VLAN_GET_TAG - -/** - * vlan_get_tag - get the VLAN ID from the skb - * @skb: skbuff to query - * @vlan_tci: buffer to store value - * - * Returns error if the skb is not VLAN tagged - */ -static inline int vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci) -{ - if (skb->dev->features & NETIF_F_HW_VLAN_CTAG_TX) { - return __vlan_hwaccel_get_tag(skb, vlan_tci); - } else { - return __vlan_get_tag(skb, vlan_tci); - } -} - -/** - * vlan_get_protocol - get protocol EtherType. - * @skb: skbuff to query - * @type: first vlan protocol - * @depth: buffer to store length of eth and vlan tags in bytes - * - * Returns the EtherType of the packet, regardless of whether it is - * vlan encapsulated (normal or hardware accelerated) or not. - */ -static inline __be16 __vlan_get_protocol(struct sk_buff *skb, __be16 type, - int *depth) -{ - unsigned int vlan_depth = skb->mac_len; - - /* if type is 802.1Q/AD then the header should already be - * present at mac_len - VLAN_HLEN (if mac_len > 0), or at - * ETH_HLEN otherwise - */ - if (eth_type_vlan(type)) { - if (vlan_depth) { - if (WARN_ON(vlan_depth < VLAN_HLEN)) - return 0; - vlan_depth -= VLAN_HLEN; - } else { - vlan_depth = ETH_HLEN; - } - do { - struct vlan_hdr *vh; - - if (unlikely(!pskb_may_pull(skb, - vlan_depth + VLAN_HLEN))) - return 0; - - vh = (struct vlan_hdr *)(skb->data + vlan_depth); - type = vh->h_vlan_encapsulated_proto; - vlan_depth += VLAN_HLEN; - } while (eth_type_vlan(type)); - } - - if (depth) - *depth = vlan_depth; - - return type; -} - -/** - * vlan_get_protocol - get protocol EtherType. - * @skb: skbuff to query - * - * Returns the EtherType of the packet, regardless of whether it is - * vlan encapsulated (normal or hardware accelerated) or not. - */ -static inline __be16 vlan_get_protocol(struct sk_buff *skb) -{ - return __vlan_get_protocol(skb, skb->protocol, NULL); -} - -static inline void vlan_set_encap_proto(struct sk_buff *skb, - struct vlan_hdr *vhdr) -{ - __be16 proto; - unsigned short *rawp; - - /* - * Was a VLAN packet, grab the encapsulated protocol, which the layer - * three protocols care about. - */ - - proto = vhdr->h_vlan_encapsulated_proto; - if (eth_proto_is_802_3(proto)) { - skb->protocol = proto; - return; - } - - rawp = (unsigned short *)(vhdr + 1); - if (*rawp == 0xFFFF) - /* - * This is a magic hack to spot IPX packets. Older Novell - * breaks the protocol design and runs IPX over 802.3 without - * an 802.2 LLC layer. We look for FFFF which isn't a used - * 802.2 SSAP/DSAP. This won't work for fault tolerant netware - * but does for the rest. - */ - skb->protocol = htons(ETH_P_802_3); - else - /* - * Real 802.2 LLC - */ - skb->protocol = htons(ETH_P_802_2); -} - -/** - * skb_vlan_tagged - check if skb is vlan tagged. - * @skb: skbuff to query - * - * Returns true if the skb is tagged, regardless of whether it is hardware - * accelerated or not. - */ -static inline bool skb_vlan_tagged(const struct sk_buff *skb) -{ - if (!skb_vlan_tag_present(skb) && - likely(!eth_type_vlan(skb->protocol))) - return false; - - return true; -} - -/** - * skb_vlan_tagged_multi - check if skb is vlan tagged with multiple headers. - * @skb: skbuff to query - * - * Returns true if the skb is tagged with multiple vlan headers, regardless - * of whether it is hardware accelerated or not. - */ -static inline bool skb_vlan_tagged_multi(const struct sk_buff *skb) -{ - __be16 protocol = skb->protocol; - - if (!skb_vlan_tag_present(skb)) { - struct vlan_ethhdr *veh; - - if (likely(!eth_type_vlan(protocol))) - return false; - - veh = (struct vlan_ethhdr *)skb->data; - protocol = veh->h_vlan_encapsulated_proto; - } - - if (!eth_type_vlan(protocol)) - return false; - - return true; -} - -/** - * vlan_features_check - drop unsafe features for skb with multiple tags. - * @skb: skbuff to query - * @features: features to be checked - * - * Returns features without unsafe ones if the skb has multiple tags. - */ -static inline netdev_features_t vlan_features_check(const struct sk_buff *skb, - netdev_features_t features) -{ - if (skb_vlan_tagged_multi(skb)) - features = netdev_intersect_features(features, - NETIF_F_SG | - NETIF_F_HIGHDMA | - NETIF_F_FRAGLIST | - NETIF_F_HW_CSUM | - NETIF_F_HW_VLAN_CTAG_TX | - NETIF_F_HW_VLAN_STAG_TX); - - return features; -} - -/** - * compare_vlan_header - Compare two vlan headers - * @h1: Pointer to vlan header - * @h2: Pointer to vlan header - * - * Compare two vlan headers, returns 0 if equal. - * - * Please note that alignment of h1 & h2 are only guaranteed to be 16 bits. - */ -static inline unsigned long compare_vlan_header(const struct vlan_hdr *h1, - const struct vlan_hdr *h2) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) - return *(u32 *)h1 ^ *(u32 *)h2; -#else - return ((__force u32)h1->h_vlan_TCI ^ (__force u32)h2->h_vlan_TCI) | - ((__force u32)h1->h_vlan_encapsulated_proto ^ - (__force u32)h2->h_vlan_encapsulated_proto); -#endif -} -#endif /* !(_LINUX_IF_VLAN_H_) */ diff --git a/src/linux/include/linux/igmp.h b/src/linux/include/linux/igmp.h deleted file mode 100644 index 12f6fba..0000000 --- a/src/linux/include/linux/igmp.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * Linux NET3: Internet Group Management Protocol [IGMP] - * - * Authors: - * Alan Cox - * - * Extended to talk the BSD extended IGMP protocol of mrouted 3.6 - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_IGMP_H -#define _LINUX_IGMP_H - -#include -#include -#include -#include - -static inline struct igmphdr *igmp_hdr(const struct sk_buff *skb) -{ - return (struct igmphdr *)skb_transport_header(skb); -} - -static inline struct igmpv3_report * - igmpv3_report_hdr(const struct sk_buff *skb) -{ - return (struct igmpv3_report *)skb_transport_header(skb); -} - -static inline struct igmpv3_query * - igmpv3_query_hdr(const struct sk_buff *skb) -{ - return (struct igmpv3_query *)skb_transport_header(skb); -} - -struct ip_sf_socklist { - unsigned int sl_max; - unsigned int sl_count; - struct rcu_head rcu; - __be32 sl_addr[0]; -}; - -#define IP_SFLSIZE(count) (sizeof(struct ip_sf_socklist) + \ - (count) * sizeof(__be32)) - -#define IP_SFBLOCK 10 /* allocate this many at once */ - -/* ip_mc_socklist is real list now. Speed is not argument; - this list never used in fast path code - */ - -struct ip_mc_socklist { - struct ip_mc_socklist __rcu *next_rcu; - struct ip_mreqn multi; - unsigned int sfmode; /* MCAST_{INCLUDE,EXCLUDE} */ - struct ip_sf_socklist __rcu *sflist; - struct rcu_head rcu; -}; - -struct ip_sf_list { - struct ip_sf_list *sf_next; - __be32 sf_inaddr; - unsigned long sf_count[2]; /* include/exclude counts */ - unsigned char sf_gsresp; /* include in g & s response? */ - unsigned char sf_oldin; /* change state */ - unsigned char sf_crcount; /* retrans. left to send */ -}; - -struct ip_mc_list { - struct in_device *interface; - __be32 multiaddr; - unsigned int sfmode; - struct ip_sf_list *sources; - struct ip_sf_list *tomb; - unsigned long sfcount[2]; - union { - struct ip_mc_list *next; - struct ip_mc_list __rcu *next_rcu; - }; - struct ip_mc_list __rcu *next_hash; - struct timer_list timer; - int users; - atomic_t refcnt; - spinlock_t lock; - char tm_running; - char reporter; - char unsolicit_count; - char loaded; - unsigned char gsquery; /* check source marks? */ - unsigned char crcount; - struct rcu_head rcu; -}; - -/* V3 exponential field decoding */ -#define IGMPV3_MASK(value, nb) ((nb)>=32 ? (value) : ((1<<(nb))-1) & (value)) -#define IGMPV3_EXP(thresh, nbmant, nbexp, value) \ - ((value) < (thresh) ? (value) : \ - ((IGMPV3_MASK(value, nbmant) | (1<<(nbmant))) << \ - (IGMPV3_MASK((value) >> (nbmant), nbexp) + (nbexp)))) - -#define IGMPV3_QQIC(value) IGMPV3_EXP(0x80, 4, 3, value) -#define IGMPV3_MRC(value) IGMPV3_EXP(0x80, 4, 3, value) - -extern int ip_check_mc_rcu(struct in_device *dev, __be32 mc_addr, __be32 src_addr, u8 proto); -extern int igmp_rcv(struct sk_buff *); -extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr); -extern int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr); -extern void ip_mc_drop_socket(struct sock *sk); -extern int ip_mc_source(int add, int omode, struct sock *sk, - struct ip_mreq_source *mreqs, int ifindex); -extern int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf,int ifindex); -extern int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, - struct ip_msfilter __user *optval, int __user *optlen); -extern int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, - struct group_filter __user *optval, int __user *optlen); -extern int ip_mc_sf_allow(struct sock *sk, __be32 local, __be32 rmt, int dif); -extern void ip_mc_init_dev(struct in_device *); -extern void ip_mc_destroy_dev(struct in_device *); -extern void ip_mc_up(struct in_device *); -extern void ip_mc_down(struct in_device *); -extern void ip_mc_unmap(struct in_device *); -extern void ip_mc_remap(struct in_device *); -extern void ip_mc_dec_group(struct in_device *in_dev, __be32 addr); -extern void ip_mc_inc_group(struct in_device *in_dev, __be32 addr); -int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed); - -#endif diff --git a/src/linux/include/linux/ima.h b/src/linux/include/linux/ima.h deleted file mode 100644 index 0eb7c2e..0000000 --- a/src/linux/include/linux/ima.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2008 IBM Corporation - * Author: Mimi Zohar - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - */ - -#ifndef _LINUX_IMA_H -#define _LINUX_IMA_H - -#include -struct linux_binprm; - -#ifdef CONFIG_IMA -extern int ima_bprm_check(struct linux_binprm *bprm); -extern int ima_file_check(struct file *file, int mask, int opened); -extern void ima_file_free(struct file *file); -extern int ima_file_mmap(struct file *file, unsigned long prot); -extern int ima_read_file(struct file *file, enum kernel_read_file_id id); -extern int ima_post_read_file(struct file *file, void *buf, loff_t size, - enum kernel_read_file_id id); -extern void ima_post_path_mknod(struct dentry *dentry); - -#else -static inline int ima_bprm_check(struct linux_binprm *bprm) -{ - return 0; -} - -static inline int ima_file_check(struct file *file, int mask, int opened) -{ - return 0; -} - -static inline void ima_file_free(struct file *file) -{ - return; -} - -static inline int ima_file_mmap(struct file *file, unsigned long prot) -{ - return 0; -} - -static inline int ima_read_file(struct file *file, enum kernel_read_file_id id) -{ - return 0; -} - -static inline int ima_post_read_file(struct file *file, void *buf, loff_t size, - enum kernel_read_file_id id) -{ - return 0; -} - -static inline void ima_post_path_mknod(struct dentry *dentry) -{ - return; -} - -#endif /* CONFIG_IMA */ - -#ifdef CONFIG_IMA_APPRAISE -extern void ima_inode_post_setattr(struct dentry *dentry); -extern int ima_inode_setxattr(struct dentry *dentry, const char *xattr_name, - const void *xattr_value, size_t xattr_value_len); -extern int ima_inode_removexattr(struct dentry *dentry, const char *xattr_name); -#else -static inline void ima_inode_post_setattr(struct dentry *dentry) -{ - return; -} - -static inline int ima_inode_setxattr(struct dentry *dentry, - const char *xattr_name, - const void *xattr_value, - size_t xattr_value_len) -{ - return 0; -} - -static inline int ima_inode_removexattr(struct dentry *dentry, - const char *xattr_name) -{ - return 0; -} -#endif /* CONFIG_IMA_APPRAISE */ -#endif /* _LINUX_IMA_H */ diff --git a/src/linux/include/linux/in.h b/src/linux/include/linux/in.h deleted file mode 100644 index 31b4937..0000000 --- a/src/linux/include/linux/in.h +++ /dev/null @@ -1,104 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions of the Internet Protocol. - * - * Version: @(#)in.h 1.0.1 04/21/93 - * - * Authors: Original taken from the GNU Project file. - * Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_IN_H -#define _LINUX_IN_H - - -#include -#include - -static inline int proto_ports_offset(int proto) -{ - switch (proto) { - case IPPROTO_TCP: - case IPPROTO_UDP: - case IPPROTO_DCCP: - case IPPROTO_ESP: /* SPI */ - case IPPROTO_SCTP: - case IPPROTO_UDPLITE: - return 0; - case IPPROTO_AH: /* SPI */ - return 4; - default: - return -EINVAL; - } -} - -static inline bool ipv4_is_loopback(__be32 addr) -{ - return (addr & htonl(0xff000000)) == htonl(0x7f000000); -} - -static inline bool ipv4_is_multicast(__be32 addr) -{ - return (addr & htonl(0xf0000000)) == htonl(0xe0000000); -} - -static inline bool ipv4_is_local_multicast(__be32 addr) -{ - return (addr & htonl(0xffffff00)) == htonl(0xe0000000); -} - -static inline bool ipv4_is_lbcast(__be32 addr) -{ - /* limited broadcast */ - return addr == htonl(INADDR_BROADCAST); -} - -static inline bool ipv4_is_zeronet(__be32 addr) -{ - return (addr & htonl(0xff000000)) == htonl(0x00000000); -} - -/* Special-Use IPv4 Addresses (RFC3330) */ - -static inline bool ipv4_is_private_10(__be32 addr) -{ - return (addr & htonl(0xff000000)) == htonl(0x0a000000); -} - -static inline bool ipv4_is_private_172(__be32 addr) -{ - return (addr & htonl(0xfff00000)) == htonl(0xac100000); -} - -static inline bool ipv4_is_private_192(__be32 addr) -{ - return (addr & htonl(0xffff0000)) == htonl(0xc0a80000); -} - -static inline bool ipv4_is_linklocal_169(__be32 addr) -{ - return (addr & htonl(0xffff0000)) == htonl(0xa9fe0000); -} - -static inline bool ipv4_is_anycast_6to4(__be32 addr) -{ - return (addr & htonl(0xffffff00)) == htonl(0xc0586300); -} - -static inline bool ipv4_is_test_192(__be32 addr) -{ - return (addr & htonl(0xffffff00)) == htonl(0xc0000200); -} - -static inline bool ipv4_is_test_198(__be32 addr) -{ - return (addr & htonl(0xfffe0000)) == htonl(0xc6120000); -} -#endif /* _LINUX_IN_H */ diff --git a/src/linux/include/linux/in6.h b/src/linux/include/linux/in6.h deleted file mode 100644 index 34edf1f..0000000 --- a/src/linux/include/linux/in6.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Types and definitions for AF_INET6 - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * Sources: - * IPv6 Program Interfaces for BSD Systems - * - * - * Advanced Sockets API for IPv6 - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_IN6_H -#define _LINUX_IN6_H - -#include - -/* IPv6 Wildcard Address (::) and Loopback Address (::1) defined in RFC2553 - * NOTE: Be aware the IN6ADDR_* constants and in6addr_* externals are defined - * in network byte order, not in host byte order as are the IPv4 equivalents - */ -extern const struct in6_addr in6addr_any; -#define IN6ADDR_ANY_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } } -extern const struct in6_addr in6addr_loopback; -#define IN6ADDR_LOOPBACK_INIT { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } -extern const struct in6_addr in6addr_linklocal_allnodes; -#define IN6ADDR_LINKLOCAL_ALLNODES_INIT \ - { { { 0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } -extern const struct in6_addr in6addr_linklocal_allrouters; -#define IN6ADDR_LINKLOCAL_ALLROUTERS_INIT \ - { { { 0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2 } } } -extern const struct in6_addr in6addr_interfacelocal_allnodes; -#define IN6ADDR_INTERFACELOCAL_ALLNODES_INIT \ - { { { 0xff,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } -extern const struct in6_addr in6addr_interfacelocal_allrouters; -#define IN6ADDR_INTERFACELOCAL_ALLROUTERS_INIT \ - { { { 0xff,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2 } } } -extern const struct in6_addr in6addr_sitelocal_allrouters; -#define IN6ADDR_SITELOCAL_ALLROUTERS_INIT \ - { { { 0xff,5,0,0,0,0,0,0,0,0,0,0,0,0,0,2 } } } -#endif diff --git a/src/linux/include/linux/inet.h b/src/linux/include/linux/inet.h deleted file mode 100644 index 4cca05c..0000000 --- a/src/linux/include/linux/inet.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Swansea University Computer Society NET3 - * - * This work is derived from NET2Debugged, which is in turn derived - * from NET2D which was written by: - * Fred N. van Kempen, - * - * This work was derived from Ross Biro's inspirational work - * for the LINUX operating system. His version numbers were: - * - * $Id: Space.c,v 0.8.4.5 1992/12/12 19:25:04 bir7 Exp $ - * $Id: arp.c,v 0.8.4.6 1993/01/28 22:30:00 bir7 Exp $ - * $Id: arp.h,v 0.8.4.6 1993/01/28 22:30:00 bir7 Exp $ - * $Id: dev.c,v 0.8.4.13 1993/01/23 18:00:11 bir7 Exp $ - * $Id: dev.h,v 0.8.4.7 1993/01/23 18:00:11 bir7 Exp $ - * $Id: eth.c,v 0.8.4.4 1993/01/22 23:21:38 bir7 Exp $ - * $Id: eth.h,v 0.8.4.1 1992/11/10 00:17:18 bir7 Exp $ - * $Id: icmp.c,v 0.8.4.9 1993/01/23 18:00:11 bir7 Exp $ - * $Id: icmp.h,v 0.8.4.2 1992/11/15 14:55:30 bir7 Exp $ - * $Id: ip.c,v 0.8.4.8 1992/12/12 19:25:04 bir7 Exp $ - * $Id: ip.h,v 0.8.4.2 1993/01/23 18:00:11 bir7 Exp $ - * $Id: loopback.c,v 0.8.4.8 1993/01/23 18:00:11 bir7 Exp $ - * $Id: packet.c,v 0.8.4.7 1993/01/26 22:04:00 bir7 Exp $ - * $Id: protocols.c,v 0.8.4.3 1992/11/15 14:55:30 bir7 Exp $ - * $Id: raw.c,v 0.8.4.12 1993/01/26 22:04:00 bir7 Exp $ - * $Id: sock.c,v 0.8.4.6 1993/01/28 22:30:00 bir7 Exp $ - * $Id: sock.h,v 0.8.4.7 1993/01/26 22:04:00 bir7 Exp $ - * $Id: tcp.c,v 0.8.4.16 1993/01/26 22:04:00 bir7 Exp $ - * $Id: tcp.h,v 0.8.4.7 1993/01/22 22:58:08 bir7 Exp $ - * $Id: timer.c,v 0.8.4.8 1993/01/23 18:00:11 bir7 Exp $ - * $Id: timer.h,v 0.8.4.2 1993/01/23 18:00:11 bir7 Exp $ - * $Id: udp.c,v 0.8.4.12 1993/01/26 22:04:00 bir7 Exp $ - * $Id: udp.h,v 0.8.4.1 1992/11/10 00:17:18 bir7 Exp $ - * $Id: we.c,v 0.8.4.10 1993/01/23 18:00:11 bir7 Exp $ - * $Id: wereg.h,v 0.8.4.1 1992/11/10 00:17:18 bir7 Exp $ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_INET_H -#define _LINUX_INET_H - -#include - -/* - * These mimic similar macros defined in user-space for inet_ntop(3). - * See /usr/include/netinet/in.h . - */ -#define INET_ADDRSTRLEN (16) -#define INET6_ADDRSTRLEN (48) - -extern __be32 in_aton(const char *str); -extern int in4_pton(const char *src, int srclen, u8 *dst, int delim, const char **end); -extern int in6_pton(const char *src, int srclen, u8 *dst, int delim, const char **end); -#endif /* _LINUX_INET_H */ diff --git a/src/linux/include/linux/inet_diag.h b/src/linux/include/linux/inet_diag.h deleted file mode 100644 index 65da430..0000000 --- a/src/linux/include/linux/inet_diag.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef _INET_DIAG_H_ -#define _INET_DIAG_H_ 1 - -#include - -struct net; -struct sock; -struct inet_hashinfo; -struct nlattr; -struct nlmsghdr; -struct sk_buff; -struct netlink_callback; - -struct inet_diag_handler { - void (*dump)(struct sk_buff *skb, - struct netlink_callback *cb, - const struct inet_diag_req_v2 *r, - struct nlattr *bc); - - int (*dump_one)(struct sk_buff *in_skb, - const struct nlmsghdr *nlh, - const struct inet_diag_req_v2 *req); - - void (*idiag_get_info)(struct sock *sk, - struct inet_diag_msg *r, - void *info); - - int (*destroy)(struct sk_buff *in_skb, - const struct inet_diag_req_v2 *req); - - __u16 idiag_type; - __u16 idiag_info_size; -}; - -struct inet_connection_sock; -int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, - struct sk_buff *skb, const struct inet_diag_req_v2 *req, - struct user_namespace *user_ns, - u32 pid, u32 seq, u16 nlmsg_flags, - const struct nlmsghdr *unlh, bool net_admin); -void inet_diag_dump_icsk(struct inet_hashinfo *h, struct sk_buff *skb, - struct netlink_callback *cb, - const struct inet_diag_req_v2 *r, - struct nlattr *bc); -int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, - struct sk_buff *in_skb, const struct nlmsghdr *nlh, - const struct inet_diag_req_v2 *req); - -struct sock *inet_diag_find_one_icsk(struct net *net, - struct inet_hashinfo *hashinfo, - const struct inet_diag_req_v2 *req); - -int inet_diag_bc_sk(const struct nlattr *_bc, struct sock *sk); - -void inet_diag_msg_common_fill(struct inet_diag_msg *r, struct sock *sk); - -int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb, - struct inet_diag_msg *r, int ext, - struct user_namespace *user_ns, bool net_admin); - -extern int inet_diag_register(const struct inet_diag_handler *handler); -extern void inet_diag_unregister(const struct inet_diag_handler *handler); -#endif /* _INET_DIAG_H_ */ diff --git a/src/linux/include/linux/inetdevice.h b/src/linux/include/linux/inetdevice.h deleted file mode 100644 index ee971f3..0000000 --- a/src/linux/include/linux/inetdevice.h +++ /dev/null @@ -1,261 +0,0 @@ -#ifndef _LINUX_INETDEVICE_H -#define _LINUX_INETDEVICE_H - -#ifdef __KERNEL__ - -#include -#include -#include -#include -#include -#include -#include -#include - -struct ipv4_devconf { - void *sysctl; - int data[IPV4_DEVCONF_MAX]; - DECLARE_BITMAP(state, IPV4_DEVCONF_MAX); -}; - -#define MC_HASH_SZ_LOG 9 - -struct in_device { - struct net_device *dev; - atomic_t refcnt; - int dead; - struct in_ifaddr *ifa_list; /* IP ifaddr chain */ - - struct ip_mc_list __rcu *mc_list; /* IP multicast filter chain */ - struct ip_mc_list __rcu * __rcu *mc_hash; - - int mc_count; /* Number of installed mcasts */ - spinlock_t mc_tomb_lock; - struct ip_mc_list *mc_tomb; - unsigned long mr_v1_seen; - unsigned long mr_v2_seen; - unsigned long mr_maxdelay; - unsigned char mr_qrv; - unsigned char mr_gq_running; - unsigned char mr_ifc_count; - struct timer_list mr_gq_timer; /* general query timer */ - struct timer_list mr_ifc_timer; /* interface change timer */ - - struct neigh_parms *arp_parms; - struct ipv4_devconf cnf; - struct rcu_head rcu_head; -}; - -#define IPV4_DEVCONF(cnf, attr) ((cnf).data[IPV4_DEVCONF_ ## attr - 1]) -#define IPV4_DEVCONF_ALL(net, attr) \ - IPV4_DEVCONF((*(net)->ipv4.devconf_all), attr) - -static inline int ipv4_devconf_get(struct in_device *in_dev, int index) -{ - index--; - return in_dev->cnf.data[index]; -} - -static inline void ipv4_devconf_set(struct in_device *in_dev, int index, - int val) -{ - index--; - set_bit(index, in_dev->cnf.state); - in_dev->cnf.data[index] = val; -} - -static inline void ipv4_devconf_setall(struct in_device *in_dev) -{ - bitmap_fill(in_dev->cnf.state, IPV4_DEVCONF_MAX); -} - -#define IN_DEV_CONF_GET(in_dev, attr) \ - ipv4_devconf_get((in_dev), IPV4_DEVCONF_ ## attr) -#define IN_DEV_CONF_SET(in_dev, attr, val) \ - ipv4_devconf_set((in_dev), IPV4_DEVCONF_ ## attr, (val)) - -#define IN_DEV_ANDCONF(in_dev, attr) \ - (IPV4_DEVCONF_ALL(dev_net(in_dev->dev), attr) && \ - IN_DEV_CONF_GET((in_dev), attr)) - -#define IN_DEV_NET_ORCONF(in_dev, net, attr) \ - (IPV4_DEVCONF_ALL(net, attr) || \ - IN_DEV_CONF_GET((in_dev), attr)) - -#define IN_DEV_ORCONF(in_dev, attr) \ - IN_DEV_NET_ORCONF(in_dev, dev_net(in_dev->dev), attr) - -#define IN_DEV_MAXCONF(in_dev, attr) \ - (max(IPV4_DEVCONF_ALL(dev_net(in_dev->dev), attr), \ - IN_DEV_CONF_GET((in_dev), attr))) - -#define IN_DEV_FORWARD(in_dev) IN_DEV_CONF_GET((in_dev), FORWARDING) -#define IN_DEV_MFORWARD(in_dev) IN_DEV_ANDCONF((in_dev), MC_FORWARDING) -#define IN_DEV_RPFILTER(in_dev) IN_DEV_MAXCONF((in_dev), RP_FILTER) -#define IN_DEV_SRC_VMARK(in_dev) IN_DEV_ORCONF((in_dev), SRC_VMARK) -#define IN_DEV_SOURCE_ROUTE(in_dev) IN_DEV_ANDCONF((in_dev), \ - ACCEPT_SOURCE_ROUTE) -#define IN_DEV_ACCEPT_LOCAL(in_dev) IN_DEV_ORCONF((in_dev), ACCEPT_LOCAL) -#define IN_DEV_BOOTP_RELAY(in_dev) IN_DEV_ANDCONF((in_dev), BOOTP_RELAY) - -#define IN_DEV_LOG_MARTIANS(in_dev) IN_DEV_ORCONF((in_dev), LOG_MARTIANS) -#define IN_DEV_PROXY_ARP(in_dev) IN_DEV_ORCONF((in_dev), PROXY_ARP) -#define IN_DEV_PROXY_ARP_PVLAN(in_dev) IN_DEV_CONF_GET(in_dev, PROXY_ARP_PVLAN) -#define IN_DEV_SHARED_MEDIA(in_dev) IN_DEV_ORCONF((in_dev), SHARED_MEDIA) -#define IN_DEV_TX_REDIRECTS(in_dev) IN_DEV_ORCONF((in_dev), SEND_REDIRECTS) -#define IN_DEV_SEC_REDIRECTS(in_dev) IN_DEV_ORCONF((in_dev), \ - SECURE_REDIRECTS) -#define IN_DEV_IDTAG(in_dev) IN_DEV_CONF_GET(in_dev, TAG) -#define IN_DEV_MEDIUM_ID(in_dev) IN_DEV_CONF_GET(in_dev, MEDIUM_ID) -#define IN_DEV_PROMOTE_SECONDARIES(in_dev) \ - IN_DEV_ORCONF((in_dev), \ - PROMOTE_SECONDARIES) -#define IN_DEV_ROUTE_LOCALNET(in_dev) IN_DEV_ORCONF(in_dev, ROUTE_LOCALNET) -#define IN_DEV_NET_ROUTE_LOCALNET(in_dev, net) \ - IN_DEV_NET_ORCONF(in_dev, net, ROUTE_LOCALNET) - -#define IN_DEV_RX_REDIRECTS(in_dev) \ - ((IN_DEV_FORWARD(in_dev) && \ - IN_DEV_ANDCONF((in_dev), ACCEPT_REDIRECTS)) \ - || (!IN_DEV_FORWARD(in_dev) && \ - IN_DEV_ORCONF((in_dev), ACCEPT_REDIRECTS))) - -#define IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) \ - IN_DEV_CONF_GET((in_dev), IGNORE_ROUTES_WITH_LINKDOWN) - -#define IN_DEV_ARPFILTER(in_dev) IN_DEV_ORCONF((in_dev), ARPFILTER) -#define IN_DEV_ARP_ACCEPT(in_dev) IN_DEV_ORCONF((in_dev), ARP_ACCEPT) -#define IN_DEV_ARP_ANNOUNCE(in_dev) IN_DEV_MAXCONF((in_dev), ARP_ANNOUNCE) -#define IN_DEV_ARP_IGNORE(in_dev) IN_DEV_MAXCONF((in_dev), ARP_IGNORE) -#define IN_DEV_ARP_NOTIFY(in_dev) IN_DEV_MAXCONF((in_dev), ARP_NOTIFY) - -struct in_ifaddr { - struct hlist_node hash; - struct in_ifaddr *ifa_next; - struct in_device *ifa_dev; - struct rcu_head rcu_head; - __be32 ifa_local; - __be32 ifa_address; - __be32 ifa_mask; - __be32 ifa_broadcast; - unsigned char ifa_scope; - unsigned char ifa_prefixlen; - __u32 ifa_flags; - char ifa_label[IFNAMSIZ]; - - /* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */ - __u32 ifa_valid_lft; - __u32 ifa_preferred_lft; - unsigned long ifa_cstamp; /* created timestamp */ - unsigned long ifa_tstamp; /* updated timestamp */ -}; - -int register_inetaddr_notifier(struct notifier_block *nb); -int unregister_inetaddr_notifier(struct notifier_block *nb); - -void inet_netconf_notify_devconf(struct net *net, int type, int ifindex, - struct ipv4_devconf *devconf); - -struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref); -static inline struct net_device *ip_dev_find(struct net *net, __be32 addr) -{ - return __ip_dev_find(net, addr, true); -} - -int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b); -int devinet_ioctl(struct net *net, unsigned int cmd, void __user *); -void devinet_init(void); -struct in_device *inetdev_by_index(struct net *, int); -__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope); -__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev, __be32 dst, - __be32 local, int scope); -struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, - __be32 mask); -static __inline__ bool inet_ifa_match(__be32 addr, struct in_ifaddr *ifa) -{ - return !((addr^ifa->ifa_address)&ifa->ifa_mask); -} - -/* - * Check if a mask is acceptable. - */ - -static __inline__ bool bad_mask(__be32 mask, __be32 addr) -{ - __u32 hmask; - if (addr & (mask = ~mask)) - return true; - hmask = ntohl(mask); - if (hmask & (hmask+1)) - return true; - return false; -} - -#define for_primary_ifa(in_dev) { struct in_ifaddr *ifa; \ - for (ifa = (in_dev)->ifa_list; ifa && !(ifa->ifa_flags&IFA_F_SECONDARY); ifa = ifa->ifa_next) - -#define for_ifa(in_dev) { struct in_ifaddr *ifa; \ - for (ifa = (in_dev)->ifa_list; ifa; ifa = ifa->ifa_next) - - -#define endfor_ifa(in_dev) } - -static inline struct in_device *__in_dev_get_rcu(const struct net_device *dev) -{ - return rcu_dereference(dev->ip_ptr); -} - -static inline struct in_device *in_dev_get(const struct net_device *dev) -{ - struct in_device *in_dev; - - rcu_read_lock(); - in_dev = __in_dev_get_rcu(dev); - if (in_dev) - atomic_inc(&in_dev->refcnt); - rcu_read_unlock(); - return in_dev; -} - -static inline struct in_device *__in_dev_get_rtnl(const struct net_device *dev) -{ - return rtnl_dereference(dev->ip_ptr); -} - -static inline struct neigh_parms *__in_dev_arp_parms_get_rcu(const struct net_device *dev) -{ - struct in_device *in_dev = __in_dev_get_rcu(dev); - - return in_dev ? in_dev->arp_parms : NULL; -} - -void in_dev_finish_destroy(struct in_device *idev); - -static inline void in_dev_put(struct in_device *idev) -{ - if (atomic_dec_and_test(&idev->refcnt)) - in_dev_finish_destroy(idev); -} - -#define __in_dev_put(idev) atomic_dec(&(idev)->refcnt) -#define in_dev_hold(idev) atomic_inc(&(idev)->refcnt) - -#endif /* __KERNEL__ */ - -static __inline__ __be32 inet_make_mask(int logmask) -{ - if (logmask) - return htonl(~((1U<<(32-logmask))-1)); - return 0; -} - -static __inline__ int inet_mask_len(__be32 mask) -{ - __u32 hmask = ntohl(mask); - if (!hmask) - return 0; - return 32 - ffz(~hmask); -} - - -#endif /* _LINUX_INETDEVICE_H */ diff --git a/src/linux/include/linux/init.h b/src/linux/include/linux/init.h deleted file mode 100644 index e30104c..0000000 --- a/src/linux/include/linux/init.h +++ /dev/null @@ -1,276 +0,0 @@ -#ifndef _LINUX_INIT_H -#define _LINUX_INIT_H - -#include -#include - -/* These macros are used to mark some functions or - * initialized data (doesn't apply to uninitialized data) - * as `initialization' functions. The kernel can take this - * as hint that the function is used only during the initialization - * phase and free up used memory resources after - * - * Usage: - * For functions: - * - * You should add __init immediately before the function name, like: - * - * static void __init initme(int x, int y) - * { - * extern int z; z = x * y; - * } - * - * If the function has a prototype somewhere, you can also add - * __init between closing brace of the prototype and semicolon: - * - * extern int initialize_foobar_device(int, int, int) __init; - * - * For initialized data: - * You should insert __initdata or __initconst between the variable name - * and equal sign followed by value, e.g.: - * - * static int init_variable __initdata = 0; - * static const char linux_logo[] __initconst = { 0x32, 0x36, ... }; - * - * Don't forget to initialize data not at file scope, i.e. within a function, - * as gcc otherwise puts the data into the bss section and not into the init - * section. - */ - -/* These are for everybody (although not all archs will actually - discard it in modules) */ -#define __init __section(.init.text) __cold notrace __latent_entropy -#define __initdata __section(.init.data) -#define __initconst __section(.init.rodata) -#define __exitdata __section(.exit.data) -#define __exit_call __used __section(.exitcall.exit) - -/* - * modpost check for section mismatches during the kernel build. - * A section mismatch happens when there are references from a - * code or data section to an init section (both code or data). - * The init sections are (for most archs) discarded by the kernel - * when early init has completed so all such references are potential bugs. - * For exit sections the same issue exists. - * - * The following markers are used for the cases where the reference to - * the *init / *exit section (code or data) is valid and will teach - * modpost not to issue a warning. Intended semantics is that a code or - * data tagged __ref* can reference code or data from init section without - * producing a warning (of course, no warning does not mean code is - * correct, so optimally document why the __ref is needed and why it's OK). - * - * The markers follow same syntax rules as __init / __initdata. - */ -#define __ref __section(.ref.text) noinline -#define __refdata __section(.ref.data) -#define __refconst __section(.ref.rodata) - -#ifdef MODULE -#define __exitused -#else -#define __exitused __used -#endif - -#define __exit __section(.exit.text) __exitused __cold notrace - -/* Used for MEMORY_HOTPLUG */ -#define __meminit __section(.meminit.text) __cold notrace \ - __latent_entropy -#define __meminitdata __section(.meminit.data) -#define __meminitconst __section(.meminit.rodata) -#define __memexit __section(.memexit.text) __exitused __cold notrace -#define __memexitdata __section(.memexit.data) -#define __memexitconst __section(.memexit.rodata) - -/* For assembly routines */ -#define __HEAD .section ".head.text","ax" -#define __INIT .section ".init.text","ax" -#define __FINIT .previous - -#define __INITDATA .section ".init.data","aw",%progbits -#define __INITRODATA .section ".init.rodata","a",%progbits -#define __FINITDATA .previous - -#define __MEMINIT .section ".meminit.text", "ax" -#define __MEMINITDATA .section ".meminit.data", "aw" -#define __MEMINITRODATA .section ".meminit.rodata", "a" - -/* silence warnings when references are OK */ -#define __REF .section ".ref.text", "ax" -#define __REFDATA .section ".ref.data", "aw" -#define __REFCONST .section ".ref.rodata", "a" - -#ifndef __ASSEMBLY__ -/* - * Used for initialization calls.. - */ -typedef int (*initcall_t)(void); -typedef void (*exitcall_t)(void); - -extern initcall_t __con_initcall_start[], __con_initcall_end[]; -extern initcall_t __security_initcall_start[], __security_initcall_end[]; - -/* Used for contructor calls. */ -typedef void (*ctor_fn_t)(void); - -/* Defined in init/main.c */ -extern int do_one_initcall(initcall_t fn); -extern char __initdata boot_command_line[]; -extern char *saved_command_line; -extern unsigned int reset_devices; - -/* used by init/main.c */ -void setup_arch(char **); -void prepare_namespace(void); -void __init load_default_modules(void); -int __init init_rootfs(void); - -#ifdef CONFIG_DEBUG_RODATA -void mark_rodata_ro(void); -#endif - -extern void (*late_time_init)(void); - -extern bool initcall_debug; - -#endif - -#ifndef MODULE - -#ifndef __ASSEMBLY__ - -/* - * initcalls are now grouped by functionality into separate - * subsections. Ordering inside the subsections is determined - * by link order. - * For backwards compatibility, initcall() puts the call in - * the device init subsection. - * - * The `id' arg to __define_initcall() is needed so that multiple initcalls - * can point at the same handler without causing duplicate-symbol build errors. - * - * Initcalls are run by placing pointers in initcall sections that the - * kernel iterates at runtime. The linker can do dead code / data elimination - * and remove that completely, so the initcall sections have to be marked - * as KEEP() in the linker script. - */ - -#define __define_initcall(fn, id) \ - static initcall_t __initcall_##fn##id __used \ - __attribute__((__section__(".initcall" #id ".init"))) = fn; - -/* - * Early initcalls run before initializing SMP. - * - * Only for built-in code, not modules. - */ -#define early_initcall(fn) __define_initcall(fn, early) - -/* - * A "pure" initcall has no dependencies on anything else, and purely - * initializes variables that couldn't be statically initialized. - * - * This only exists for built-in code, not for modules. - * Keep main.c:initcall_level_names[] in sync. - */ -#define pure_initcall(fn) __define_initcall(fn, 0) - -#define core_initcall(fn) __define_initcall(fn, 1) -#define core_initcall_sync(fn) __define_initcall(fn, 1s) -#define postcore_initcall(fn) __define_initcall(fn, 2) -#define postcore_initcall_sync(fn) __define_initcall(fn, 2s) -#define arch_initcall(fn) __define_initcall(fn, 3) -#define arch_initcall_sync(fn) __define_initcall(fn, 3s) -#define subsys_initcall(fn) __define_initcall(fn, 4) -#define subsys_initcall_sync(fn) __define_initcall(fn, 4s) -#define fs_initcall(fn) __define_initcall(fn, 5) -#define fs_initcall_sync(fn) __define_initcall(fn, 5s) -#define rootfs_initcall(fn) __define_initcall(fn, rootfs) -#define device_initcall(fn) __define_initcall(fn, 6) -#define device_initcall_sync(fn) __define_initcall(fn, 6s) -#define late_initcall(fn) __define_initcall(fn, 7) -#define late_initcall_sync(fn) __define_initcall(fn, 7s) - -#define __initcall(fn) device_initcall(fn) - -#define __exitcall(fn) \ - static exitcall_t __exitcall_##fn __exit_call = fn - -#define console_initcall(fn) \ - static initcall_t __initcall_##fn \ - __used __section(.con_initcall.init) = fn - -#define security_initcall(fn) \ - static initcall_t __initcall_##fn \ - __used __section(.security_initcall.init) = fn - -struct obs_kernel_param { - const char *str; - int (*setup_func)(char *); - int early; -}; - -/* - * Only for really core code. See moduleparam.h for the normal way. - * - * Force the alignment so the compiler doesn't space elements of the - * obs_kernel_param "array" too far apart in .init.setup. - */ -#define __setup_param(str, unique_id, fn, early) \ - static const char __setup_str_##unique_id[] __initconst \ - __aligned(1) = str; \ - static struct obs_kernel_param __setup_##unique_id \ - __used __section(.init.setup) \ - __attribute__((aligned((sizeof(long))))) \ - = { __setup_str_##unique_id, fn, early } - -#define __setup(str, fn) \ - __setup_param(str, fn, fn, 0) - -/* - * NOTE: fn is as per module_param, not __setup! - * Emits warning if fn returns non-zero. - */ -#define early_param(str, fn) \ - __setup_param(str, fn, fn, 1) - -#define early_param_on_off(str_on, str_off, var, config) \ - \ - int var = IS_ENABLED(config); \ - \ - static int __init parse_##var##_on(char *arg) \ - { \ - var = 1; \ - return 0; \ - } \ - __setup_param(str_on, parse_##var##_on, parse_##var##_on, 1); \ - \ - static int __init parse_##var##_off(char *arg) \ - { \ - var = 0; \ - return 0; \ - } \ - __setup_param(str_off, parse_##var##_off, parse_##var##_off, 1) - -/* Relies on boot_command_line being set */ -void __init parse_early_param(void); -void __init parse_early_options(char *cmdline); -#endif /* __ASSEMBLY__ */ - -#else /* MODULE */ - -#define __setup_param(str, unique_id, fn) /* nothing */ -#define __setup(str, func) /* nothing */ -#endif - -/* Data marked not to be saved by software suspend */ -#define __nosavedata __section(.data..nosave) - -#ifdef MODULE -#define __exit_p(x) x -#else -#define __exit_p(x) NULL -#endif - -#endif /* _LINUX_INIT_H */ diff --git a/src/linux/include/linux/init_task.h b/src/linux/include/linux/init_task.h deleted file mode 100644 index 325f649..0000000 --- a/src/linux/include/linux/init_task.h +++ /dev/null @@ -1,288 +0,0 @@ -#ifndef _LINUX__INIT_TASK_H -#define _LINUX__INIT_TASK_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef CONFIG_SMP -# define INIT_PUSHABLE_TASKS(tsk) \ - .pushable_tasks = PLIST_NODE_INIT(tsk.pushable_tasks, MAX_PRIO), -#else -# define INIT_PUSHABLE_TASKS(tsk) -#endif - -extern struct files_struct init_files; -extern struct fs_struct init_fs; - -#ifdef CONFIG_CPUSETS -#define INIT_CPUSET_SEQ(tsk) \ - .mems_allowed_seq = SEQCNT_ZERO(tsk.mems_allowed_seq), -#else -#define INIT_CPUSET_SEQ(tsk) -#endif - -#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE -#define INIT_PREV_CPUTIME(x) .prev_cputime = { \ - .lock = __RAW_SPIN_LOCK_UNLOCKED(x.prev_cputime.lock), \ -}, -#else -#define INIT_PREV_CPUTIME(x) -#endif - -#define INIT_SIGNALS(sig) { \ - .nr_threads = 1, \ - .thread_head = LIST_HEAD_INIT(init_task.thread_node), \ - .wait_chldexit = __WAIT_QUEUE_HEAD_INITIALIZER(sig.wait_chldexit),\ - .shared_pending = { \ - .list = LIST_HEAD_INIT(sig.shared_pending.list), \ - .signal = {{0}}}, \ - .posix_timers = LIST_HEAD_INIT(sig.posix_timers), \ - .cpu_timers = INIT_CPU_TIMERS(sig.cpu_timers), \ - .rlim = INIT_RLIMITS, \ - .cputimer = { \ - .cputime_atomic = INIT_CPUTIME_ATOMIC, \ - .running = false, \ - .checking_timer = false, \ - }, \ - INIT_PREV_CPUTIME(sig) \ - .cred_guard_mutex = \ - __MUTEX_INITIALIZER(sig.cred_guard_mutex), \ -} - -extern struct nsproxy init_nsproxy; - -#define INIT_SIGHAND(sighand) { \ - .count = ATOMIC_INIT(1), \ - .action = { { { .sa_handler = SIG_DFL, } }, }, \ - .siglock = __SPIN_LOCK_UNLOCKED(sighand.siglock), \ - .signalfd_wqh = __WAIT_QUEUE_HEAD_INITIALIZER(sighand.signalfd_wqh), \ -} - -extern struct group_info init_groups; - -#define INIT_STRUCT_PID { \ - .count = ATOMIC_INIT(1), \ - .tasks = { \ - { .first = NULL }, \ - { .first = NULL }, \ - { .first = NULL }, \ - }, \ - .level = 0, \ - .numbers = { { \ - .nr = 0, \ - .ns = &init_pid_ns, \ - .pid_chain = { .next = NULL, .pprev = NULL }, \ - }, } \ -} - -#define INIT_PID_LINK(type) \ -{ \ - .node = { \ - .next = NULL, \ - .pprev = NULL, \ - }, \ - .pid = &init_struct_pid, \ -} - -#ifdef CONFIG_AUDITSYSCALL -#define INIT_IDS \ - .loginuid = INVALID_UID, \ - .sessionid = (unsigned int)-1, -#else -#define INIT_IDS -#endif - -#ifdef CONFIG_PREEMPT_RCU -#define INIT_TASK_RCU_TREE_PREEMPT() \ - .rcu_blocked_node = NULL, -#else -#define INIT_TASK_RCU_TREE_PREEMPT(tsk) -#endif -#ifdef CONFIG_PREEMPT_RCU -#define INIT_TASK_RCU_PREEMPT(tsk) \ - .rcu_read_lock_nesting = 0, \ - .rcu_read_unlock_special.s = 0, \ - .rcu_node_entry = LIST_HEAD_INIT(tsk.rcu_node_entry), \ - INIT_TASK_RCU_TREE_PREEMPT() -#else -#define INIT_TASK_RCU_PREEMPT(tsk) -#endif -#ifdef CONFIG_TASKS_RCU -#define INIT_TASK_RCU_TASKS(tsk) \ - .rcu_tasks_holdout = false, \ - .rcu_tasks_holdout_list = \ - LIST_HEAD_INIT(tsk.rcu_tasks_holdout_list), \ - .rcu_tasks_idle_cpu = -1, -#else -#define INIT_TASK_RCU_TASKS(tsk) -#endif - -extern struct cred init_cred; - -extern struct task_group root_task_group; - -#ifdef CONFIG_CGROUP_SCHED -# define INIT_CGROUP_SCHED(tsk) \ - .sched_task_group = &root_task_group, -#else -# define INIT_CGROUP_SCHED(tsk) -#endif - -#ifdef CONFIG_PERF_EVENTS -# define INIT_PERF_EVENTS(tsk) \ - .perf_event_mutex = \ - __MUTEX_INITIALIZER(tsk.perf_event_mutex), \ - .perf_event_list = LIST_HEAD_INIT(tsk.perf_event_list), -#else -# define INIT_PERF_EVENTS(tsk) -#endif - -#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN -# define INIT_VTIME(tsk) \ - .vtime_seqcount = SEQCNT_ZERO(tsk.vtime_seqcount), \ - .vtime_snap = 0, \ - .vtime_snap_whence = VTIME_SYS, -#else -# define INIT_VTIME(tsk) -#endif - -#define INIT_TASK_COMM "swapper" - -#ifdef CONFIG_RT_MUTEXES -# define INIT_RT_MUTEXES(tsk) \ - .pi_waiters = RB_ROOT, \ - .pi_waiters_leftmost = NULL, -#else -# define INIT_RT_MUTEXES(tsk) -#endif - -#ifdef CONFIG_NUMA_BALANCING -# define INIT_NUMA_BALANCING(tsk) \ - .numa_preferred_nid = -1, \ - .numa_group = NULL, \ - .numa_faults = NULL, -#else -# define INIT_NUMA_BALANCING(tsk) -#endif - -#ifdef CONFIG_KASAN -# define INIT_KASAN(tsk) \ - .kasan_depth = 1, -#else -# define INIT_KASAN(tsk) -#endif - -#ifdef CONFIG_THREAD_INFO_IN_TASK -# define INIT_TASK_TI(tsk) \ - .thread_info = INIT_THREAD_INFO(tsk), \ - .stack_refcount = ATOMIC_INIT(1), -#else -# define INIT_TASK_TI(tsk) -#endif - -/* - * INIT_TASK is used to set up the first task table, touch at - * your own risk!. Base=0, limit=0x1fffff (=2MB) - */ -#define INIT_TASK(tsk) \ -{ \ - INIT_TASK_TI(tsk) \ - .state = 0, \ - .stack = init_stack, \ - .usage = ATOMIC_INIT(2), \ - .flags = PF_KTHREAD, \ - .prio = MAX_PRIO-20, \ - .static_prio = MAX_PRIO-20, \ - .normal_prio = MAX_PRIO-20, \ - .policy = SCHED_NORMAL, \ - .cpus_allowed = CPU_MASK_ALL, \ - .nr_cpus_allowed= NR_CPUS, \ - .mm = NULL, \ - .active_mm = &init_mm, \ - .restart_block = { \ - .fn = do_no_restart_syscall, \ - }, \ - .se = { \ - .group_node = LIST_HEAD_INIT(tsk.se.group_node), \ - }, \ - .rt = { \ - .run_list = LIST_HEAD_INIT(tsk.rt.run_list), \ - .time_slice = RR_TIMESLICE, \ - }, \ - .tasks = LIST_HEAD_INIT(tsk.tasks), \ - INIT_PUSHABLE_TASKS(tsk) \ - INIT_CGROUP_SCHED(tsk) \ - .ptraced = LIST_HEAD_INIT(tsk.ptraced), \ - .ptrace_entry = LIST_HEAD_INIT(tsk.ptrace_entry), \ - .real_parent = &tsk, \ - .parent = &tsk, \ - .children = LIST_HEAD_INIT(tsk.children), \ - .sibling = LIST_HEAD_INIT(tsk.sibling), \ - .group_leader = &tsk, \ - RCU_POINTER_INITIALIZER(real_cred, &init_cred), \ - RCU_POINTER_INITIALIZER(cred, &init_cred), \ - .comm = INIT_TASK_COMM, \ - .thread = INIT_THREAD, \ - .fs = &init_fs, \ - .files = &init_files, \ - .signal = &init_signals, \ - .sighand = &init_sighand, \ - .nsproxy = &init_nsproxy, \ - .pending = { \ - .list = LIST_HEAD_INIT(tsk.pending.list), \ - .signal = {{0}}}, \ - .blocked = {{0}}, \ - .alloc_lock = __SPIN_LOCK_UNLOCKED(tsk.alloc_lock), \ - .journal_info = NULL, \ - .cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \ - .pi_lock = __RAW_SPIN_LOCK_UNLOCKED(tsk.pi_lock), \ - .timer_slack_ns = 50000, /* 50 usec default slack */ \ - .pids = { \ - [PIDTYPE_PID] = INIT_PID_LINK(PIDTYPE_PID), \ - [PIDTYPE_PGID] = INIT_PID_LINK(PIDTYPE_PGID), \ - [PIDTYPE_SID] = INIT_PID_LINK(PIDTYPE_SID), \ - }, \ - .thread_group = LIST_HEAD_INIT(tsk.thread_group), \ - .thread_node = LIST_HEAD_INIT(init_signals.thread_head), \ - INIT_IDS \ - INIT_PERF_EVENTS(tsk) \ - INIT_TRACE_IRQFLAGS \ - INIT_LOCKDEP \ - INIT_FTRACE_GRAPH \ - INIT_TRACE_RECURSION \ - INIT_TASK_RCU_PREEMPT(tsk) \ - INIT_TASK_RCU_TASKS(tsk) \ - INIT_CPUSET_SEQ(tsk) \ - INIT_RT_MUTEXES(tsk) \ - INIT_PREV_CPUTIME(tsk) \ - INIT_VTIME(tsk) \ - INIT_NUMA_BALANCING(tsk) \ - INIT_KASAN(tsk) \ -} - - -#define INIT_CPU_TIMERS(cpu_timers) \ -{ \ - LIST_HEAD_INIT(cpu_timers[0]), \ - LIST_HEAD_INIT(cpu_timers[1]), \ - LIST_HEAD_INIT(cpu_timers[2]), \ -} - -/* Attach to the init_task data structure for proper alignment */ -#define __init_task_data __attribute__((__section__(".data..init_task"))) - - -#endif diff --git a/src/linux/include/linux/initrd.h b/src/linux/include/linux/initrd.h deleted file mode 100644 index 55289d2..0000000 --- a/src/linux/include/linux/initrd.h +++ /dev/null @@ -1,20 +0,0 @@ - -#define INITRD_MINOR 250 /* shouldn't collide with /dev/ram* too soon ... */ - -/* 1 = load ramdisk, 0 = don't load */ -extern int rd_doload; - -/* 1 = prompt for ramdisk, 0 = don't prompt */ -extern int rd_prompt; - -/* starting block # of image */ -extern int rd_image_start; - -/* 1 if it is not an error if initrd_start < memory_start */ -extern int initrd_below_start_ok; - -/* free_initrd_mem always gets called with the next two as arguments.. */ -extern unsigned long initrd_start, initrd_end; -extern void free_initrd_mem(unsigned long, unsigned long); - -extern unsigned int real_root_dev; diff --git a/src/linux/include/linux/input.h b/src/linux/include/linux/input.h deleted file mode 100644 index a65e3b2..0000000 --- a/src/linux/include/linux/input.h +++ /dev/null @@ -1,536 +0,0 @@ -/* - * Copyright (c) 1999-2002 Vojtech Pavlik - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ -#ifndef _INPUT_H -#define _INPUT_H - -#include -#include -#include -/* Implementation details, userspace should not care about these */ -#define ABS_MT_FIRST ABS_MT_TOUCH_MAJOR -#define ABS_MT_LAST ABS_MT_TOOL_Y - -/* - * In-kernel definitions. - */ - -#include -#include -#include -#include - -/** - * struct input_value - input value representation - * @type: type of value (EV_KEY, EV_ABS, etc) - * @code: the value code - * @value: the value - */ -struct input_value { - __u16 type; - __u16 code; - __s32 value; -}; - -/** - * struct input_dev - represents an input device - * @name: name of the device - * @phys: physical path to the device in the system hierarchy - * @uniq: unique identification code for the device (if device has it) - * @id: id of the device (struct input_id) - * @propbit: bitmap of device properties and quirks - * @evbit: bitmap of types of events supported by the device (EV_KEY, - * EV_REL, etc.) - * @keybit: bitmap of keys/buttons this device has - * @relbit: bitmap of relative axes for the device - * @absbit: bitmap of absolute axes for the device - * @mscbit: bitmap of miscellaneous events supported by the device - * @ledbit: bitmap of leds present on the device - * @sndbit: bitmap of sound effects supported by the device - * @ffbit: bitmap of force feedback effects supported by the device - * @swbit: bitmap of switches present on the device - * @hint_events_per_packet: average number of events generated by the - * device in a packet (between EV_SYN/SYN_REPORT events). Used by - * event handlers to estimate size of the buffer needed to hold - * events. - * @keycodemax: size of keycode table - * @keycodesize: size of elements in keycode table - * @keycode: map of scancodes to keycodes for this device - * @getkeycode: optional legacy method to retrieve current keymap. - * @setkeycode: optional method to alter current keymap, used to implement - * sparse keymaps. If not supplied default mechanism will be used. - * The method is being called while holding event_lock and thus must - * not sleep - * @ff: force feedback structure associated with the device if device - * supports force feedback effects - * @repeat_key: stores key code of the last key pressed; used to implement - * software autorepeat - * @timer: timer for software autorepeat - * @rep: current values for autorepeat parameters (delay, rate) - * @mt: pointer to multitouch state - * @absinfo: array of &struct input_absinfo elements holding information - * about absolute axes (current value, min, max, flat, fuzz, - * resolution) - * @key: reflects current state of device's keys/buttons - * @led: reflects current state of device's LEDs - * @snd: reflects current state of sound effects - * @sw: reflects current state of device's switches - * @open: this method is called when the very first user calls - * input_open_device(). The driver must prepare the device - * to start generating events (start polling thread, - * request an IRQ, submit URB, etc.) - * @close: this method is called when the very last user calls - * input_close_device(). - * @flush: purges the device. Most commonly used to get rid of force - * feedback effects loaded into the device when disconnecting - * from it - * @event: event handler for events sent _to_ the device, like EV_LED - * or EV_SND. The device is expected to carry out the requested - * action (turn on a LED, play sound, etc.) The call is protected - * by @event_lock and must not sleep - * @grab: input handle that currently has the device grabbed (via - * EVIOCGRAB ioctl). When a handle grabs a device it becomes sole - * recipient for all input events coming from the device - * @event_lock: this spinlock is taken when input core receives - * and processes a new event for the device (in input_event()). - * Code that accesses and/or modifies parameters of a device - * (such as keymap or absmin, absmax, absfuzz, etc.) after device - * has been registered with input core must take this lock. - * @mutex: serializes calls to open(), close() and flush() methods - * @users: stores number of users (input handlers) that opened this - * device. It is used by input_open_device() and input_close_device() - * to make sure that dev->open() is only called when the first - * user opens device and dev->close() is called when the very - * last user closes the device - * @going_away: marks devices that are in a middle of unregistering and - * causes input_open_device*() fail with -ENODEV. - * @dev: driver model's view of this device - * @h_list: list of input handles associated with the device. When - * accessing the list dev->mutex must be held - * @node: used to place the device onto input_dev_list - * @num_vals: number of values queued in the current frame - * @max_vals: maximum number of values queued in a frame - * @vals: array of values queued in the current frame - * @devres_managed: indicates that devices is managed with devres framework - * and needs not be explicitly unregistered or freed. - */ -struct input_dev { - const char *name; - const char *phys; - const char *uniq; - struct input_id id; - - unsigned long propbit[BITS_TO_LONGS(INPUT_PROP_CNT)]; - - unsigned long evbit[BITS_TO_LONGS(EV_CNT)]; - unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; - unsigned long relbit[BITS_TO_LONGS(REL_CNT)]; - unsigned long absbit[BITS_TO_LONGS(ABS_CNT)]; - unsigned long mscbit[BITS_TO_LONGS(MSC_CNT)]; - unsigned long ledbit[BITS_TO_LONGS(LED_CNT)]; - unsigned long sndbit[BITS_TO_LONGS(SND_CNT)]; - unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; - unsigned long swbit[BITS_TO_LONGS(SW_CNT)]; - - unsigned int hint_events_per_packet; - - unsigned int keycodemax; - unsigned int keycodesize; - void *keycode; - - int (*setkeycode)(struct input_dev *dev, - const struct input_keymap_entry *ke, - unsigned int *old_keycode); - int (*getkeycode)(struct input_dev *dev, - struct input_keymap_entry *ke); - - struct ff_device *ff; - - unsigned int repeat_key; - struct timer_list timer; - - int rep[REP_CNT]; - - struct input_mt *mt; - - struct input_absinfo *absinfo; - - unsigned long key[BITS_TO_LONGS(KEY_CNT)]; - unsigned long led[BITS_TO_LONGS(LED_CNT)]; - unsigned long snd[BITS_TO_LONGS(SND_CNT)]; - unsigned long sw[BITS_TO_LONGS(SW_CNT)]; - - int (*open)(struct input_dev *dev); - void (*close)(struct input_dev *dev); - int (*flush)(struct input_dev *dev, struct file *file); - int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); - - struct input_handle __rcu *grab; - - spinlock_t event_lock; - struct mutex mutex; - - unsigned int users; - bool going_away; - - struct device dev; - - struct list_head h_list; - struct list_head node; - - unsigned int num_vals; - unsigned int max_vals; - struct input_value *vals; - - bool devres_managed; -}; -#define to_input_dev(d) container_of(d, struct input_dev, dev) - -/* - * Verify that we are in sync with input_device_id mod_devicetable.h #defines - */ - -#if EV_MAX != INPUT_DEVICE_ID_EV_MAX -#error "EV_MAX and INPUT_DEVICE_ID_EV_MAX do not match" -#endif - -#if KEY_MIN_INTERESTING != INPUT_DEVICE_ID_KEY_MIN_INTERESTING -#error "KEY_MIN_INTERESTING and INPUT_DEVICE_ID_KEY_MIN_INTERESTING do not match" -#endif - -#if KEY_MAX != INPUT_DEVICE_ID_KEY_MAX -#error "KEY_MAX and INPUT_DEVICE_ID_KEY_MAX do not match" -#endif - -#if REL_MAX != INPUT_DEVICE_ID_REL_MAX -#error "REL_MAX and INPUT_DEVICE_ID_REL_MAX do not match" -#endif - -#if ABS_MAX != INPUT_DEVICE_ID_ABS_MAX -#error "ABS_MAX and INPUT_DEVICE_ID_ABS_MAX do not match" -#endif - -#if MSC_MAX != INPUT_DEVICE_ID_MSC_MAX -#error "MSC_MAX and INPUT_DEVICE_ID_MSC_MAX do not match" -#endif - -#if LED_MAX != INPUT_DEVICE_ID_LED_MAX -#error "LED_MAX and INPUT_DEVICE_ID_LED_MAX do not match" -#endif - -#if SND_MAX != INPUT_DEVICE_ID_SND_MAX -#error "SND_MAX and INPUT_DEVICE_ID_SND_MAX do not match" -#endif - -#if FF_MAX != INPUT_DEVICE_ID_FF_MAX -#error "FF_MAX and INPUT_DEVICE_ID_FF_MAX do not match" -#endif - -#if SW_MAX != INPUT_DEVICE_ID_SW_MAX -#error "SW_MAX and INPUT_DEVICE_ID_SW_MAX do not match" -#endif - -#define INPUT_DEVICE_ID_MATCH_DEVICE \ - (INPUT_DEVICE_ID_MATCH_BUS | INPUT_DEVICE_ID_MATCH_VENDOR | INPUT_DEVICE_ID_MATCH_PRODUCT) -#define INPUT_DEVICE_ID_MATCH_DEVICE_AND_VERSION \ - (INPUT_DEVICE_ID_MATCH_DEVICE | INPUT_DEVICE_ID_MATCH_VERSION) - -struct input_handle; - -/** - * struct input_handler - implements one of interfaces for input devices - * @private: driver-specific data - * @event: event handler. This method is being called by input core with - * interrupts disabled and dev->event_lock spinlock held and so - * it may not sleep - * @events: event sequence handler. This method is being called by - * input core with interrupts disabled and dev->event_lock - * spinlock held and so it may not sleep - * @filter: similar to @event; separates normal event handlers from - * "filters". - * @match: called after comparing device's id with handler's id_table - * to perform fine-grained matching between device and handler - * @connect: called when attaching a handler to an input device - * @disconnect: disconnects a handler from input device - * @start: starts handler for given handle. This function is called by - * input core right after connect() method and also when a process - * that "grabbed" a device releases it - * @legacy_minors: set to %true by drivers using legacy minor ranges - * @minor: beginning of range of 32 legacy minors for devices this driver - * can provide - * @name: name of the handler, to be shown in /proc/bus/input/handlers - * @id_table: pointer to a table of input_device_ids this driver can - * handle - * @h_list: list of input handles associated with the handler - * @node: for placing the driver onto input_handler_list - * - * Input handlers attach to input devices and create input handles. There - * are likely several handlers attached to any given input device at the - * same time. All of them will get their copy of input event generated by - * the device. - * - * The very same structure is used to implement input filters. Input core - * allows filters to run first and will not pass event to regular handlers - * if any of the filters indicate that the event should be filtered (by - * returning %true from their filter() method). - * - * Note that input core serializes calls to connect() and disconnect() - * methods. - */ -struct input_handler { - - void *private; - - void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); - void (*events)(struct input_handle *handle, - const struct input_value *vals, unsigned int count); - bool (*filter)(struct input_handle *handle, unsigned int type, unsigned int code, int value); - bool (*match)(struct input_handler *handler, struct input_dev *dev); - int (*connect)(struct input_handler *handler, struct input_dev *dev, const struct input_device_id *id); - void (*disconnect)(struct input_handle *handle); - void (*start)(struct input_handle *handle); - - bool legacy_minors; - int minor; - const char *name; - - const struct input_device_id *id_table; - - struct list_head h_list; - struct list_head node; -}; - -/** - * struct input_handle - links input device with an input handler - * @private: handler-specific data - * @open: counter showing whether the handle is 'open', i.e. should deliver - * events from its device - * @name: name given to the handle by handler that created it - * @dev: input device the handle is attached to - * @handler: handler that works with the device through this handle - * @d_node: used to put the handle on device's list of attached handles - * @h_node: used to put the handle on handler's list of handles from which - * it gets events - */ -struct input_handle { - - void *private; - - int open; - const char *name; - - struct input_dev *dev; - struct input_handler *handler; - - struct list_head d_node; - struct list_head h_node; -}; - -struct input_dev __must_check *input_allocate_device(void); -struct input_dev __must_check *devm_input_allocate_device(struct device *); -void input_free_device(struct input_dev *dev); - -static inline struct input_dev *input_get_device(struct input_dev *dev) -{ - return dev ? to_input_dev(get_device(&dev->dev)) : NULL; -} - -static inline void input_put_device(struct input_dev *dev) -{ - if (dev) - put_device(&dev->dev); -} - -static inline void *input_get_drvdata(struct input_dev *dev) -{ - return dev_get_drvdata(&dev->dev); -} - -static inline void input_set_drvdata(struct input_dev *dev, void *data) -{ - dev_set_drvdata(&dev->dev, data); -} - -int __must_check input_register_device(struct input_dev *); -void input_unregister_device(struct input_dev *); - -void input_reset_device(struct input_dev *); - -int __must_check input_register_handler(struct input_handler *); -void input_unregister_handler(struct input_handler *); - -int __must_check input_get_new_minor(int legacy_base, unsigned int legacy_num, - bool allow_dynamic); -void input_free_minor(unsigned int minor); - -int input_handler_for_each_handle(struct input_handler *, void *data, - int (*fn)(struct input_handle *, void *)); - -int input_register_handle(struct input_handle *); -void input_unregister_handle(struct input_handle *); - -int input_grab_device(struct input_handle *); -void input_release_device(struct input_handle *); - -int input_open_device(struct input_handle *); -void input_close_device(struct input_handle *); - -int input_flush_device(struct input_handle *handle, struct file *file); - -void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); -void input_inject_event(struct input_handle *handle, unsigned int type, unsigned int code, int value); - -static inline void input_report_key(struct input_dev *dev, unsigned int code, int value) -{ - input_event(dev, EV_KEY, code, !!value); -} - -static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value) -{ - input_event(dev, EV_REL, code, value); -} - -static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value) -{ - input_event(dev, EV_ABS, code, value); -} - -static inline void input_report_ff_status(struct input_dev *dev, unsigned int code, int value) -{ - input_event(dev, EV_FF_STATUS, code, value); -} - -static inline void input_report_switch(struct input_dev *dev, unsigned int code, int value) -{ - input_event(dev, EV_SW, code, !!value); -} - -static inline void input_sync(struct input_dev *dev) -{ - input_event(dev, EV_SYN, SYN_REPORT, 0); -} - -static inline void input_mt_sync(struct input_dev *dev) -{ - input_event(dev, EV_SYN, SYN_MT_REPORT, 0); -} - -void input_set_capability(struct input_dev *dev, unsigned int type, unsigned int code); - -/** - * input_set_events_per_packet - tell handlers about the driver event rate - * @dev: the input device used by the driver - * @n_events: the average number of events between calls to input_sync() - * - * If the event rate sent from a device is unusually large, use this - * function to set the expected event rate. This will allow handlers - * to set up an appropriate buffer size for the event stream, in order - * to minimize information loss. - */ -static inline void input_set_events_per_packet(struct input_dev *dev, int n_events) -{ - dev->hint_events_per_packet = n_events; -} - -void input_alloc_absinfo(struct input_dev *dev); -void input_set_abs_params(struct input_dev *dev, unsigned int axis, - int min, int max, int fuzz, int flat); - -#define INPUT_GENERATE_ABS_ACCESSORS(_suffix, _item) \ -static inline int input_abs_get_##_suffix(struct input_dev *dev, \ - unsigned int axis) \ -{ \ - return dev->absinfo ? dev->absinfo[axis]._item : 0; \ -} \ - \ -static inline void input_abs_set_##_suffix(struct input_dev *dev, \ - unsigned int axis, int val) \ -{ \ - input_alloc_absinfo(dev); \ - if (dev->absinfo) \ - dev->absinfo[axis]._item = val; \ -} - -INPUT_GENERATE_ABS_ACCESSORS(val, value) -INPUT_GENERATE_ABS_ACCESSORS(min, minimum) -INPUT_GENERATE_ABS_ACCESSORS(max, maximum) -INPUT_GENERATE_ABS_ACCESSORS(fuzz, fuzz) -INPUT_GENERATE_ABS_ACCESSORS(flat, flat) -INPUT_GENERATE_ABS_ACCESSORS(res, resolution) - -int input_scancode_to_scalar(const struct input_keymap_entry *ke, - unsigned int *scancode); - -int input_get_keycode(struct input_dev *dev, struct input_keymap_entry *ke); -int input_set_keycode(struct input_dev *dev, - const struct input_keymap_entry *ke); - -void input_enable_softrepeat(struct input_dev *dev, int delay, int period); - -extern struct class input_class; - -/** - * struct ff_device - force-feedback part of an input device - * @upload: Called to upload an new effect into device - * @erase: Called to erase an effect from device - * @playback: Called to request device to start playing specified effect - * @set_gain: Called to set specified gain - * @set_autocenter: Called to auto-center device - * @destroy: called by input core when parent input device is being - * destroyed - * @private: driver-specific data, will be freed automatically - * @ffbit: bitmap of force feedback capabilities truly supported by - * device (not emulated like ones in input_dev->ffbit) - * @mutex: mutex for serializing access to the device - * @max_effects: maximum number of effects supported by device - * @effects: pointer to an array of effects currently loaded into device - * @effect_owners: array of effect owners; when file handle owning - * an effect gets closed the effect is automatically erased - * - * Every force-feedback device must implement upload() and playback() - * methods; erase() is optional. set_gain() and set_autocenter() need - * only be implemented if driver sets up FF_GAIN and FF_AUTOCENTER - * bits. - * - * Note that playback(), set_gain() and set_autocenter() are called with - * dev->event_lock spinlock held and interrupts off and thus may not - * sleep. - */ -struct ff_device { - int (*upload)(struct input_dev *dev, struct ff_effect *effect, - struct ff_effect *old); - int (*erase)(struct input_dev *dev, int effect_id); - - int (*playback)(struct input_dev *dev, int effect_id, int value); - void (*set_gain)(struct input_dev *dev, u16 gain); - void (*set_autocenter)(struct input_dev *dev, u16 magnitude); - - void (*destroy)(struct ff_device *); - - void *private; - - unsigned long ffbit[BITS_TO_LONGS(FF_CNT)]; - - struct mutex mutex; - - int max_effects; - struct ff_effect *effects; - struct file *effect_owners[]; -}; - -int input_ff_create(struct input_dev *dev, unsigned int max_effects); -void input_ff_destroy(struct input_dev *dev); - -int input_ff_event(struct input_dev *dev, unsigned int type, unsigned int code, int value); - -int input_ff_upload(struct input_dev *dev, struct ff_effect *effect, struct file *file); -int input_ff_erase(struct input_dev *dev, int effect_id, struct file *file); - -int input_ff_create_memless(struct input_dev *dev, void *data, - int (*play_effect)(struct input_dev *, void *, struct ff_effect *)); - -#endif diff --git a/src/linux/include/linux/input/mt.h b/src/linux/include/linux/input/mt.h deleted file mode 100644 index d7188de..0000000 --- a/src/linux/include/linux/input/mt.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef _INPUT_MT_H -#define _INPUT_MT_H - -/* - * Input Multitouch Library - * - * Copyright (c) 2010 Henrik Rydberg - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - -#include - -#define TRKID_MAX 0xffff - -#define INPUT_MT_POINTER 0x0001 /* pointer device, e.g. trackpad */ -#define INPUT_MT_DIRECT 0x0002 /* direct device, e.g. touchscreen */ -#define INPUT_MT_DROP_UNUSED 0x0004 /* drop contacts not seen in frame */ -#define INPUT_MT_TRACK 0x0008 /* use in-kernel tracking */ -#define INPUT_MT_SEMI_MT 0x0010 /* semi-mt device, finger count handled manually */ - -/** - * struct input_mt_slot - represents the state of an input MT slot - * @abs: holds current values of ABS_MT axes for this slot - * @frame: last frame at which input_mt_report_slot_state() was called - * @key: optional driver designation of this slot - */ -struct input_mt_slot { - int abs[ABS_MT_LAST - ABS_MT_FIRST + 1]; - unsigned int frame; - unsigned int key; -}; - -/** - * struct input_mt - state of tracked contacts - * @trkid: stores MT tracking ID for the next contact - * @num_slots: number of MT slots the device uses - * @slot: MT slot currently being transmitted - * @flags: input_mt operation flags - * @frame: increases every time input_mt_sync_frame() is called - * @red: reduced cost matrix for in-kernel tracking - * @slots: array of slots holding current values of tracked contacts - */ -struct input_mt { - int trkid; - int num_slots; - int slot; - unsigned int flags; - unsigned int frame; - int *red; - struct input_mt_slot slots[]; -}; - -static inline void input_mt_set_value(struct input_mt_slot *slot, - unsigned code, int value) -{ - slot->abs[code - ABS_MT_FIRST] = value; -} - -static inline int input_mt_get_value(const struct input_mt_slot *slot, - unsigned code) -{ - return slot->abs[code - ABS_MT_FIRST]; -} - -static inline bool input_mt_is_active(const struct input_mt_slot *slot) -{ - return input_mt_get_value(slot, ABS_MT_TRACKING_ID) >= 0; -} - -static inline bool input_mt_is_used(const struct input_mt *mt, - const struct input_mt_slot *slot) -{ - return slot->frame == mt->frame; -} - -int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots, - unsigned int flags); -void input_mt_destroy_slots(struct input_dev *dev); - -static inline int input_mt_new_trkid(struct input_mt *mt) -{ - return mt->trkid++ & TRKID_MAX; -} - -static inline void input_mt_slot(struct input_dev *dev, int slot) -{ - input_event(dev, EV_ABS, ABS_MT_SLOT, slot); -} - -static inline bool input_is_mt_value(int axis) -{ - return axis >= ABS_MT_FIRST && axis <= ABS_MT_LAST; -} - -static inline bool input_is_mt_axis(int axis) -{ - return axis == ABS_MT_SLOT || input_is_mt_value(axis); -} - -void input_mt_report_slot_state(struct input_dev *dev, - unsigned int tool_type, bool active); - -void input_mt_report_finger_count(struct input_dev *dev, int count); -void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count); -void input_mt_drop_unused(struct input_dev *dev); - -void input_mt_sync_frame(struct input_dev *dev); - -/** - * struct input_mt_pos - contact position - * @x: horizontal coordinate - * @y: vertical coordinate - */ -struct input_mt_pos { - s16 x, y; -}; - -int input_mt_assign_slots(struct input_dev *dev, int *slots, - const struct input_mt_pos *pos, int num_pos, - int dmax); - -int input_mt_get_slot_by_key(struct input_dev *dev, int key); - -#endif diff --git a/src/linux/include/linux/integrity.h b/src/linux/include/linux/integrity.h deleted file mode 100644 index c2d6082..0000000 --- a/src/linux/include/linux/integrity.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2009 IBM Corporation - * Author: Mimi Zohar - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 2 of the License. - */ - -#ifndef _LINUX_INTEGRITY_H -#define _LINUX_INTEGRITY_H - -#include - -enum integrity_status { - INTEGRITY_PASS = 0, - INTEGRITY_FAIL, - INTEGRITY_NOLABEL, - INTEGRITY_NOXATTRS, - INTEGRITY_UNKNOWN, -}; - -/* List of EVM protected security xattrs */ -#ifdef CONFIG_INTEGRITY -extern struct integrity_iint_cache *integrity_inode_get(struct inode *inode); -extern void integrity_inode_free(struct inode *inode); -extern void __init integrity_load_keys(void); - -#else -static inline struct integrity_iint_cache * - integrity_inode_get(struct inode *inode) -{ - return NULL; -} - -static inline void integrity_inode_free(struct inode *inode) -{ - return; -} - -static inline void integrity_load_keys(void) -{ -} -#endif /* CONFIG_INTEGRITY */ - -#endif /* _LINUX_INTEGRITY_H */ diff --git a/src/linux/include/linux/interrupt.h b/src/linux/include/linux/interrupt.h deleted file mode 100644 index 72f0721..0000000 --- a/src/linux/include/linux/interrupt.h +++ /dev/null @@ -1,722 +0,0 @@ -/* interrupt.h */ -#ifndef _LINUX_INTERRUPT_H -#define _LINUX_INTERRUPT_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* - * These correspond to the IORESOURCE_IRQ_* defines in - * linux/ioport.h to select the interrupt line behaviour. When - * requesting an interrupt without specifying a IRQF_TRIGGER, the - * setting should be assumed to be "as already configured", which - * may be as per machine or firmware initialisation. - */ -#define IRQF_TRIGGER_NONE 0x00000000 -#define IRQF_TRIGGER_RISING 0x00000001 -#define IRQF_TRIGGER_FALLING 0x00000002 -#define IRQF_TRIGGER_HIGH 0x00000004 -#define IRQF_TRIGGER_LOW 0x00000008 -#define IRQF_TRIGGER_MASK (IRQF_TRIGGER_HIGH | IRQF_TRIGGER_LOW | \ - IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING) -#define IRQF_TRIGGER_PROBE 0x00000010 - -/* - * These flags used only by the kernel as part of the - * irq handling routines. - * - * IRQF_SHARED - allow sharing the irq among several devices - * IRQF_PROBE_SHARED - set by callers when they expect sharing mismatches to occur - * IRQF_TIMER - Flag to mark this interrupt as timer interrupt - * IRQF_PERCPU - Interrupt is per cpu - * IRQF_NOBALANCING - Flag to exclude this interrupt from irq balancing - * IRQF_IRQPOLL - Interrupt is used for polling (only the interrupt that is - * registered first in an shared interrupt is considered for - * performance reasons) - * IRQF_ONESHOT - Interrupt is not reenabled after the hardirq handler finished. - * Used by threaded interrupts which need to keep the - * irq line disabled until the threaded handler has been run. - * IRQF_NO_SUSPEND - Do not disable this IRQ during suspend. Does not guarantee - * that this interrupt will wake the system from a suspended - * state. See Documentation/power/suspend-and-interrupts.txt - * IRQF_FORCE_RESUME - Force enable it on resume even if IRQF_NO_SUSPEND is set - * IRQF_NO_THREAD - Interrupt cannot be threaded - * IRQF_EARLY_RESUME - Resume IRQ early during syscore instead of at device - * resume time. - * IRQF_COND_SUSPEND - If the IRQ is shared with a NO_SUSPEND user, execute this - * interrupt handler after suspending interrupts. For system - * wakeup devices users need to implement wakeup detection in - * their interrupt handlers. - */ -#define IRQF_SHARED 0x00000080 -#define IRQF_PROBE_SHARED 0x00000100 -#define __IRQF_TIMER 0x00000200 -#define IRQF_PERCPU 0x00000400 -#define IRQF_NOBALANCING 0x00000800 -#define IRQF_IRQPOLL 0x00001000 -#define IRQF_ONESHOT 0x00002000 -#define IRQF_NO_SUSPEND 0x00004000 -#define IRQF_FORCE_RESUME 0x00008000 -#define IRQF_NO_THREAD 0x00010000 -#define IRQF_EARLY_RESUME 0x00020000 -#define IRQF_COND_SUSPEND 0x00040000 - -#define IRQF_TIMER (__IRQF_TIMER | IRQF_NO_SUSPEND | IRQF_NO_THREAD) - -/* - * These values can be returned by request_any_context_irq() and - * describe the context the interrupt will be run in. - * - * IRQC_IS_HARDIRQ - interrupt runs in hardirq context - * IRQC_IS_NESTED - interrupt runs in a nested threaded context - */ -enum { - IRQC_IS_HARDIRQ = 0, - IRQC_IS_NESTED, -}; - -typedef irqreturn_t (*irq_handler_t)(int, void *); - -/** - * struct irqaction - per interrupt action descriptor - * @handler: interrupt handler function - * @name: name of the device - * @dev_id: cookie to identify the device - * @percpu_dev_id: cookie to identify the device - * @next: pointer to the next irqaction for shared interrupts - * @irq: interrupt number - * @flags: flags (see IRQF_* above) - * @thread_fn: interrupt handler function for threaded interrupts - * @thread: thread pointer for threaded interrupts - * @secondary: pointer to secondary irqaction (force threading) - * @thread_flags: flags related to @thread - * @thread_mask: bitmask for keeping track of @thread activity - * @dir: pointer to the proc/irq/NN/name entry - */ -struct irqaction { - irq_handler_t handler; - void *dev_id; - void __percpu *percpu_dev_id; - struct irqaction *next; - irq_handler_t thread_fn; - struct task_struct *thread; - struct irqaction *secondary; - unsigned int irq; - unsigned int flags; - unsigned long thread_flags; - unsigned long thread_mask; - const char *name; - struct proc_dir_entry *dir; -} ____cacheline_internodealigned_in_smp; - -extern irqreturn_t no_action(int cpl, void *dev_id); - -/* - * If a (PCI) device interrupt is not connected we set dev->irq to - * IRQ_NOTCONNECTED. This causes request_irq() to fail with -ENOTCONN, so we - * can distingiush that case from other error returns. - * - * 0x80000000 is guaranteed to be outside the available range of interrupts - * and easy to distinguish from other possible incorrect values. - */ -#define IRQ_NOTCONNECTED (1U << 31) - -extern int __must_check -request_threaded_irq(unsigned int irq, irq_handler_t handler, - irq_handler_t thread_fn, - unsigned long flags, const char *name, void *dev); - -static inline int __must_check -request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, - const char *name, void *dev) -{ - return request_threaded_irq(irq, handler, NULL, flags, name, dev); -} - -extern int __must_check -request_any_context_irq(unsigned int irq, irq_handler_t handler, - unsigned long flags, const char *name, void *dev_id); - -extern int __must_check -request_percpu_irq(unsigned int irq, irq_handler_t handler, - const char *devname, void __percpu *percpu_dev_id); - -extern void free_irq(unsigned int, void *); -extern void free_percpu_irq(unsigned int, void __percpu *); - -struct device; - -extern int __must_check -devm_request_threaded_irq(struct device *dev, unsigned int irq, - irq_handler_t handler, irq_handler_t thread_fn, - unsigned long irqflags, const char *devname, - void *dev_id); - -static inline int __must_check -devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler, - unsigned long irqflags, const char *devname, void *dev_id) -{ - return devm_request_threaded_irq(dev, irq, handler, NULL, irqflags, - devname, dev_id); -} - -extern int __must_check -devm_request_any_context_irq(struct device *dev, unsigned int irq, - irq_handler_t handler, unsigned long irqflags, - const char *devname, void *dev_id); - -extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id); - -/* - * On lockdep we dont want to enable hardirqs in hardirq - * context. Use local_irq_enable_in_hardirq() to annotate - * kernel code that has to do this nevertheless (pretty much - * the only valid case is for old/broken hardware that is - * insanely slow). - * - * NOTE: in theory this might break fragile code that relies - * on hardirq delivery - in practice we dont seem to have such - * places left. So the only effect should be slightly increased - * irqs-off latencies. - */ -#ifdef CONFIG_LOCKDEP -# define local_irq_enable_in_hardirq() do { } while (0) -#else -# define local_irq_enable_in_hardirq() local_irq_enable() -#endif - -extern void disable_irq_nosync(unsigned int irq); -extern bool disable_hardirq(unsigned int irq); -extern void disable_irq(unsigned int irq); -extern void disable_percpu_irq(unsigned int irq); -extern void enable_irq(unsigned int irq); -extern void enable_percpu_irq(unsigned int irq, unsigned int type); -extern bool irq_percpu_is_enabled(unsigned int irq); -extern void irq_wake_thread(unsigned int irq, void *dev_id); - -/* The following three functions are for the core kernel use only. */ -extern void suspend_device_irqs(void); -extern void resume_device_irqs(void); - -/** - * struct irq_affinity_notify - context for notification of IRQ affinity changes - * @irq: Interrupt to which notification applies - * @kref: Reference count, for internal use - * @work: Work item, for internal use - * @notify: Function to be called on change. This will be - * called in process context. - * @release: Function to be called on release. This will be - * called in process context. Once registered, the - * structure must only be freed when this function is - * called or later. - */ -struct irq_affinity_notify { - unsigned int irq; - struct kref kref; - struct work_struct work; - void (*notify)(struct irq_affinity_notify *, const cpumask_t *mask); - void (*release)(struct kref *ref); -}; - -#if defined(CONFIG_SMP) - -extern cpumask_var_t irq_default_affinity; - -/* Internal implementation. Use the helpers below */ -extern int __irq_set_affinity(unsigned int irq, const struct cpumask *cpumask, - bool force); - -/** - * irq_set_affinity - Set the irq affinity of a given irq - * @irq: Interrupt to set affinity - * @cpumask: cpumask - * - * Fails if cpumask does not contain an online CPU - */ -static inline int -irq_set_affinity(unsigned int irq, const struct cpumask *cpumask) -{ - return __irq_set_affinity(irq, cpumask, false); -} - -/** - * irq_force_affinity - Force the irq affinity of a given irq - * @irq: Interrupt to set affinity - * @cpumask: cpumask - * - * Same as irq_set_affinity, but without checking the mask against - * online cpus. - * - * Solely for low level cpu hotplug code, where we need to make per - * cpu interrupts affine before the cpu becomes online. - */ -static inline int -irq_force_affinity(unsigned int irq, const struct cpumask *cpumask) -{ - return __irq_set_affinity(irq, cpumask, true); -} - -extern int irq_can_set_affinity(unsigned int irq); -extern int irq_select_affinity(unsigned int irq); - -extern int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m); - -extern int -irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify); - -struct cpumask *irq_create_affinity_masks(const struct cpumask *affinity, int nvec); -int irq_calc_affinity_vectors(const struct cpumask *affinity, int maxvec); - -#else /* CONFIG_SMP */ - -static inline int irq_set_affinity(unsigned int irq, const struct cpumask *m) -{ - return -EINVAL; -} - -static inline int irq_force_affinity(unsigned int irq, const struct cpumask *cpumask) -{ - return 0; -} - -static inline int irq_can_set_affinity(unsigned int irq) -{ - return 0; -} - -static inline int irq_select_affinity(unsigned int irq) { return 0; } - -static inline int irq_set_affinity_hint(unsigned int irq, - const struct cpumask *m) -{ - return -EINVAL; -} - -static inline int -irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify) -{ - return 0; -} - -static inline struct cpumask * -irq_create_affinity_masks(const struct cpumask *affinity, int nvec) -{ - return NULL; -} - -static inline int -irq_calc_affinity_vectors(const struct cpumask *affinity, int maxvec) -{ - return maxvec; -} - -#endif /* CONFIG_SMP */ - -/* - * Special lockdep variants of irq disabling/enabling. - * These should be used for locking constructs that - * know that a particular irq context which is disabled, - * and which is the only irq-context user of a lock, - * that it's safe to take the lock in the irq-disabled - * section without disabling hardirqs. - * - * On !CONFIG_LOCKDEP they are equivalent to the normal - * irq disable/enable methods. - */ -static inline void disable_irq_nosync_lockdep(unsigned int irq) -{ - disable_irq_nosync(irq); -#ifdef CONFIG_LOCKDEP - local_irq_disable(); -#endif -} - -static inline void disable_irq_nosync_lockdep_irqsave(unsigned int irq, unsigned long *flags) -{ - disable_irq_nosync(irq); -#ifdef CONFIG_LOCKDEP - local_irq_save(*flags); -#endif -} - -static inline void disable_irq_lockdep(unsigned int irq) -{ - disable_irq(irq); -#ifdef CONFIG_LOCKDEP - local_irq_disable(); -#endif -} - -static inline void enable_irq_lockdep(unsigned int irq) -{ -#ifdef CONFIG_LOCKDEP - local_irq_enable(); -#endif - enable_irq(irq); -} - -static inline void enable_irq_lockdep_irqrestore(unsigned int irq, unsigned long *flags) -{ -#ifdef CONFIG_LOCKDEP - local_irq_restore(*flags); -#endif - enable_irq(irq); -} - -/* IRQ wakeup (PM) control: */ -extern int irq_set_irq_wake(unsigned int irq, unsigned int on); - -static inline int enable_irq_wake(unsigned int irq) -{ - return irq_set_irq_wake(irq, 1); -} - -static inline int disable_irq_wake(unsigned int irq) -{ - return irq_set_irq_wake(irq, 0); -} - -/* - * irq_get_irqchip_state/irq_set_irqchip_state specific flags - */ -enum irqchip_irq_state { - IRQCHIP_STATE_PENDING, /* Is interrupt pending? */ - IRQCHIP_STATE_ACTIVE, /* Is interrupt in progress? */ - IRQCHIP_STATE_MASKED, /* Is interrupt masked? */ - IRQCHIP_STATE_LINE_LEVEL, /* Is IRQ line high? */ -}; - -extern int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which, - bool *state); -extern int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which, - bool state); - -#ifdef CONFIG_IRQ_FORCED_THREADING -extern bool force_irqthreads; -#else -#define force_irqthreads (0) -#endif - -#ifndef __ARCH_SET_SOFTIRQ_PENDING -#define set_softirq_pending(x) (local_softirq_pending() = (x)) -#define or_softirq_pending(x) (local_softirq_pending() |= (x)) -#endif - -/* Some architectures might implement lazy enabling/disabling of - * interrupts. In some cases, such as stop_machine, we might want - * to ensure that after a local_irq_disable(), interrupts have - * really been disabled in hardware. Such architectures need to - * implement the following hook. - */ -#ifndef hard_irq_disable -#define hard_irq_disable() do { } while(0) -#endif - -/* PLEASE, avoid to allocate new softirqs, if you need not _really_ high - frequency threaded job scheduling. For almost all the purposes - tasklets are more than enough. F.e. all serial device BHs et - al. should be converted to tasklets, not to softirqs. - */ - -enum -{ - HI_SOFTIRQ=0, - TIMER_SOFTIRQ, - NET_TX_SOFTIRQ, - NET_RX_SOFTIRQ, - BLOCK_SOFTIRQ, - IRQ_POLL_SOFTIRQ, - TASKLET_SOFTIRQ, - SCHED_SOFTIRQ, - HRTIMER_SOFTIRQ, /* Unused, but kept as tools rely on the - numbering. Sigh! */ - RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */ - - NR_SOFTIRQS -}; - -#define SOFTIRQ_STOP_IDLE_MASK (~(1 << RCU_SOFTIRQ)) - -/* map softirq index to softirq name. update 'softirq_to_name' in - * kernel/softirq.c when adding a new softirq. - */ -extern const char * const softirq_to_name[NR_SOFTIRQS]; - -/* softirq mask and active fields moved to irq_cpustat_t in - * asm/hardirq.h to get better cache usage. KAO - */ - -struct softirq_action -{ - void (*action)(struct softirq_action *); -}; - -asmlinkage void do_softirq(void); -asmlinkage void __do_softirq(void); - -#ifdef __ARCH_HAS_DO_SOFTIRQ -void do_softirq_own_stack(void); -#else -static inline void do_softirq_own_stack(void) -{ - __do_softirq(); -} -#endif - -extern void open_softirq(int nr, void (*action)(struct softirq_action *)); -extern void softirq_init(void); -extern void __raise_softirq_irqoff(unsigned int nr); - -extern void raise_softirq_irqoff(unsigned int nr); -extern void raise_softirq(unsigned int nr); - -DECLARE_PER_CPU(struct task_struct *, ksoftirqd); - -static inline struct task_struct *this_cpu_ksoftirqd(void) -{ - return this_cpu_read(ksoftirqd); -} - -/* Tasklets --- multithreaded analogue of BHs. - - Main feature differing them of generic softirqs: tasklet - is running only on one CPU simultaneously. - - Main feature differing them of BHs: different tasklets - may be run simultaneously on different CPUs. - - Properties: - * If tasklet_schedule() is called, then tasklet is guaranteed - to be executed on some cpu at least once after this. - * If the tasklet is already scheduled, but its execution is still not - started, it will be executed only once. - * If this tasklet is already running on another CPU (or schedule is called - from tasklet itself), it is rescheduled for later. - * Tasklet is strictly serialized wrt itself, but not - wrt another tasklets. If client needs some intertask synchronization, - he makes it with spinlocks. - */ - -struct tasklet_struct -{ - struct tasklet_struct *next; - unsigned long state; - atomic_t count; - void (*func)(unsigned long); - unsigned long data; -}; - -#define DECLARE_TASKLET(name, func, data) \ -struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data } - -#define DECLARE_TASKLET_DISABLED(name, func, data) \ -struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(1), func, data } - - -enum -{ - TASKLET_STATE_SCHED, /* Tasklet is scheduled for execution */ - TASKLET_STATE_RUN /* Tasklet is running (SMP only) */ -}; - -#ifdef CONFIG_SMP -static inline int tasklet_trylock(struct tasklet_struct *t) -{ - return !test_and_set_bit(TASKLET_STATE_RUN, &(t)->state); -} - -static inline void tasklet_unlock(struct tasklet_struct *t) -{ - smp_mb__before_atomic(); - clear_bit(TASKLET_STATE_RUN, &(t)->state); -} - -static inline void tasklet_unlock_wait(struct tasklet_struct *t) -{ - while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barrier(); } -} -#else -#define tasklet_trylock(t) 1 -#define tasklet_unlock_wait(t) do { } while (0) -#define tasklet_unlock(t) do { } while (0) -#endif - -extern void __tasklet_schedule(struct tasklet_struct *t); - -static inline void tasklet_schedule(struct tasklet_struct *t) -{ - if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) - __tasklet_schedule(t); -} - -extern void __tasklet_hi_schedule(struct tasklet_struct *t); - -static inline void tasklet_hi_schedule(struct tasklet_struct *t) -{ - if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) - __tasklet_hi_schedule(t); -} - -extern void __tasklet_hi_schedule_first(struct tasklet_struct *t); - -/* - * This version avoids touching any other tasklets. Needed for kmemcheck - * in order not to take any page faults while enqueueing this tasklet; - * consider VERY carefully whether you really need this or - * tasklet_hi_schedule()... - */ -static inline void tasklet_hi_schedule_first(struct tasklet_struct *t) -{ - if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) - __tasklet_hi_schedule_first(t); -} - - -static inline void tasklet_disable_nosync(struct tasklet_struct *t) -{ - atomic_inc(&t->count); - smp_mb__after_atomic(); -} - -static inline void tasklet_disable(struct tasklet_struct *t) -{ - tasklet_disable_nosync(t); - tasklet_unlock_wait(t); - smp_mb(); -} - -static inline void tasklet_enable(struct tasklet_struct *t) -{ - smp_mb__before_atomic(); - atomic_dec(&t->count); -} - -extern void tasklet_kill(struct tasklet_struct *t); -extern void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu); -extern void tasklet_init(struct tasklet_struct *t, - void (*func)(unsigned long), unsigned long data); - -struct tasklet_hrtimer { - struct hrtimer timer; - struct tasklet_struct tasklet; - enum hrtimer_restart (*function)(struct hrtimer *); -}; - -extern void -tasklet_hrtimer_init(struct tasklet_hrtimer *ttimer, - enum hrtimer_restart (*function)(struct hrtimer *), - clockid_t which_clock, enum hrtimer_mode mode); - -static inline -void tasklet_hrtimer_start(struct tasklet_hrtimer *ttimer, ktime_t time, - const enum hrtimer_mode mode) -{ - hrtimer_start(&ttimer->timer, time, mode); -} - -static inline -void tasklet_hrtimer_cancel(struct tasklet_hrtimer *ttimer) -{ - hrtimer_cancel(&ttimer->timer); - tasklet_kill(&ttimer->tasklet); -} - -/* - * Autoprobing for irqs: - * - * probe_irq_on() and probe_irq_off() provide robust primitives - * for accurate IRQ probing during kernel initialization. They are - * reasonably simple to use, are not "fooled" by spurious interrupts, - * and, unlike other attempts at IRQ probing, they do not get hung on - * stuck interrupts (such as unused PS2 mouse interfaces on ASUS boards). - * - * For reasonably foolproof probing, use them as follows: - * - * 1. clear and/or mask the device's internal interrupt. - * 2. sti(); - * 3. irqs = probe_irq_on(); // "take over" all unassigned idle IRQs - * 4. enable the device and cause it to trigger an interrupt. - * 5. wait for the device to interrupt, using non-intrusive polling or a delay. - * 6. irq = probe_irq_off(irqs); // get IRQ number, 0=none, negative=multiple - * 7. service the device to clear its pending interrupt. - * 8. loop again if paranoia is required. - * - * probe_irq_on() returns a mask of allocated irq's. - * - * probe_irq_off() takes the mask as a parameter, - * and returns the irq number which occurred, - * or zero if none occurred, or a negative irq number - * if more than one irq occurred. - */ - -#if !defined(CONFIG_GENERIC_IRQ_PROBE) -static inline unsigned long probe_irq_on(void) -{ - return 0; -} -static inline int probe_irq_off(unsigned long val) -{ - return 0; -} -static inline unsigned int probe_irq_mask(unsigned long val) -{ - return 0; -} -#else -extern unsigned long probe_irq_on(void); /* returns 0 on failure */ -extern int probe_irq_off(unsigned long); /* returns 0 or negative on failure */ -extern unsigned int probe_irq_mask(unsigned long); /* returns mask of ISA interrupts */ -#endif - -#ifdef CONFIG_PROC_FS -/* Initialize /proc/irq/ */ -extern void init_irq_proc(void); -#else -static inline void init_irq_proc(void) -{ -} -#endif - -struct seq_file; -int show_interrupts(struct seq_file *p, void *v); -int arch_show_interrupts(struct seq_file *p, int prec); - -extern int early_irq_init(void); -extern int arch_probe_nr_irqs(void); -extern int arch_early_irq_init(void); - -#if defined(CONFIG_FUNCTION_GRAPH_TRACER) || defined(CONFIG_KASAN) -/* - * We want to know which function is an entrypoint of a hardirq or a softirq. - */ -#define __irq_entry __attribute__((__section__(".irqentry.text"))) -#define __softirq_entry \ - __attribute__((__section__(".softirqentry.text"))) - -/* Limits of hardirq entrypoints */ -extern char __irqentry_text_start[]; -extern char __irqentry_text_end[]; -/* Limits of softirq entrypoints */ -extern char __softirqentry_text_start[]; -extern char __softirqentry_text_end[]; - -#else -#define __irq_entry -#define __softirq_entry -#endif - -#endif diff --git a/src/linux/include/linux/interval_tree_generic.h b/src/linux/include/linux/interval_tree_generic.h deleted file mode 100644 index 58370e1..0000000 --- a/src/linux/include/linux/interval_tree_generic.h +++ /dev/null @@ -1,191 +0,0 @@ -/* - Interval Trees - (C) 2012 Michel Lespinasse - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - include/linux/interval_tree_generic.h -*/ - -#include - -/* - * Template for implementing interval trees - * - * ITSTRUCT: struct type of the interval tree nodes - * ITRB: name of struct rb_node field within ITSTRUCT - * ITTYPE: type of the interval endpoints - * ITSUBTREE: name of ITTYPE field within ITSTRUCT holding last-in-subtree - * ITSTART(n): start endpoint of ITSTRUCT node n - * ITLAST(n): last endpoint of ITSTRUCT node n - * ITSTATIC: 'static' or empty - * ITPREFIX: prefix to use for the inline tree definitions - * - * Note - before using this, please consider if non-generic version - * (interval_tree.h) would work for you... - */ - -#define INTERVAL_TREE_DEFINE(ITSTRUCT, ITRB, ITTYPE, ITSUBTREE, \ - ITSTART, ITLAST, ITSTATIC, ITPREFIX) \ - \ -/* Callbacks for augmented rbtree insert and remove */ \ - \ -static inline ITTYPE ITPREFIX ## _compute_subtree_last(ITSTRUCT *node) \ -{ \ - ITTYPE max = ITLAST(node), subtree_last; \ - if (node->ITRB.rb_left) { \ - subtree_last = rb_entry(node->ITRB.rb_left, \ - ITSTRUCT, ITRB)->ITSUBTREE; \ - if (max < subtree_last) \ - max = subtree_last; \ - } \ - if (node->ITRB.rb_right) { \ - subtree_last = rb_entry(node->ITRB.rb_right, \ - ITSTRUCT, ITRB)->ITSUBTREE; \ - if (max < subtree_last) \ - max = subtree_last; \ - } \ - return max; \ -} \ - \ -RB_DECLARE_CALLBACKS(static, ITPREFIX ## _augment, ITSTRUCT, ITRB, \ - ITTYPE, ITSUBTREE, ITPREFIX ## _compute_subtree_last) \ - \ -/* Insert / remove interval nodes from the tree */ \ - \ -ITSTATIC void ITPREFIX ## _insert(ITSTRUCT *node, struct rb_root *root) \ -{ \ - struct rb_node **link = &root->rb_node, *rb_parent = NULL; \ - ITTYPE start = ITSTART(node), last = ITLAST(node); \ - ITSTRUCT *parent; \ - \ - while (*link) { \ - rb_parent = *link; \ - parent = rb_entry(rb_parent, ITSTRUCT, ITRB); \ - if (parent->ITSUBTREE < last) \ - parent->ITSUBTREE = last; \ - if (start < ITSTART(parent)) \ - link = &parent->ITRB.rb_left; \ - else \ - link = &parent->ITRB.rb_right; \ - } \ - \ - node->ITSUBTREE = last; \ - rb_link_node(&node->ITRB, rb_parent, link); \ - rb_insert_augmented(&node->ITRB, root, &ITPREFIX ## _augment); \ -} \ - \ -ITSTATIC void ITPREFIX ## _remove(ITSTRUCT *node, struct rb_root *root) \ -{ \ - rb_erase_augmented(&node->ITRB, root, &ITPREFIX ## _augment); \ -} \ - \ -/* \ - * Iterate over intervals intersecting [start;last] \ - * \ - * Note that a node's interval intersects [start;last] iff: \ - * Cond1: ITSTART(node) <= last \ - * and \ - * Cond2: start <= ITLAST(node) \ - */ \ - \ -static ITSTRUCT * \ -ITPREFIX ## _subtree_search(ITSTRUCT *node, ITTYPE start, ITTYPE last) \ -{ \ - while (true) { \ - /* \ - * Loop invariant: start <= node->ITSUBTREE \ - * (Cond2 is satisfied by one of the subtree nodes) \ - */ \ - if (node->ITRB.rb_left) { \ - ITSTRUCT *left = rb_entry(node->ITRB.rb_left, \ - ITSTRUCT, ITRB); \ - if (start <= left->ITSUBTREE) { \ - /* \ - * Some nodes in left subtree satisfy Cond2. \ - * Iterate to find the leftmost such node N. \ - * If it also satisfies Cond1, that's the \ - * match we are looking for. Otherwise, there \ - * is no matching interval as nodes to the \ - * right of N can't satisfy Cond1 either. \ - */ \ - node = left; \ - continue; \ - } \ - } \ - if (ITSTART(node) <= last) { /* Cond1 */ \ - if (start <= ITLAST(node)) /* Cond2 */ \ - return node; /* node is leftmost match */ \ - if (node->ITRB.rb_right) { \ - node = rb_entry(node->ITRB.rb_right, \ - ITSTRUCT, ITRB); \ - if (start <= node->ITSUBTREE) \ - continue; \ - } \ - } \ - return NULL; /* No match */ \ - } \ -} \ - \ -ITSTATIC ITSTRUCT * \ -ITPREFIX ## _iter_first(struct rb_root *root, ITTYPE start, ITTYPE last) \ -{ \ - ITSTRUCT *node; \ - \ - if (!root->rb_node) \ - return NULL; \ - node = rb_entry(root->rb_node, ITSTRUCT, ITRB); \ - if (node->ITSUBTREE < start) \ - return NULL; \ - return ITPREFIX ## _subtree_search(node, start, last); \ -} \ - \ -ITSTATIC ITSTRUCT * \ -ITPREFIX ## _iter_next(ITSTRUCT *node, ITTYPE start, ITTYPE last) \ -{ \ - struct rb_node *rb = node->ITRB.rb_right, *prev; \ - \ - while (true) { \ - /* \ - * Loop invariants: \ - * Cond1: ITSTART(node) <= last \ - * rb == node->ITRB.rb_right \ - * \ - * First, search right subtree if suitable \ - */ \ - if (rb) { \ - ITSTRUCT *right = rb_entry(rb, ITSTRUCT, ITRB); \ - if (start <= right->ITSUBTREE) \ - return ITPREFIX ## _subtree_search(right, \ - start, last); \ - } \ - \ - /* Move up the tree until we come from a node's left child */ \ - do { \ - rb = rb_parent(&node->ITRB); \ - if (!rb) \ - return NULL; \ - prev = &node->ITRB; \ - node = rb_entry(rb, ITSTRUCT, ITRB); \ - rb = node->ITRB.rb_right; \ - } while (prev == rb); \ - \ - /* Check if the node intersects [start;last] */ \ - if (last < ITSTART(node)) /* !Cond1 */ \ - return NULL; \ - else if (start <= ITLAST(node)) /* Cond2 */ \ - return node; \ - } \ -} diff --git a/src/linux/include/linux/io.h b/src/linux/include/linux/io.h deleted file mode 100644 index 82ef36e..0000000 --- a/src/linux/include/linux/io.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright 2006 PathScale, Inc. All Rights Reserved. - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef _LINUX_IO_H -#define _LINUX_IO_H - -#include -#include -#include -#include -#include -#include - -struct device; -struct resource; - -__visible void __iowrite32_copy(void __iomem *to, const void *from, size_t count); -void __ioread32_copy(void *to, const void __iomem *from, size_t count); -void __iowrite64_copy(void __iomem *to, const void *from, size_t count); - -#ifdef CONFIG_MMU -int ioremap_page_range(unsigned long addr, unsigned long end, - phys_addr_t phys_addr, pgprot_t prot); -#else -static inline int ioremap_page_range(unsigned long addr, unsigned long end, - phys_addr_t phys_addr, pgprot_t prot) -{ - return 0; -} -#endif - -#ifdef CONFIG_HAVE_ARCH_HUGE_VMAP -void __init ioremap_huge_init(void); -int arch_ioremap_pud_supported(void); -int arch_ioremap_pmd_supported(void); -#else -static inline void ioremap_huge_init(void) { } -#endif - -/* - * Managed iomap interface - */ -#ifdef CONFIG_HAS_IOPORT_MAP -void __iomem * devm_ioport_map(struct device *dev, unsigned long port, - unsigned int nr); -void devm_ioport_unmap(struct device *dev, void __iomem *addr); -#else -static inline void __iomem *devm_ioport_map(struct device *dev, - unsigned long port, - unsigned int nr) -{ - return NULL; -} - -static inline void devm_ioport_unmap(struct device *dev, void __iomem *addr) -{ -} -#endif - -#define IOMEM_ERR_PTR(err) (__force void __iomem *)ERR_PTR(err) - -void __iomem *devm_ioremap(struct device *dev, resource_size_t offset, - resource_size_t size); -void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset, - resource_size_t size); -void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset, - resource_size_t size); -void devm_iounmap(struct device *dev, void __iomem *addr); -int check_signature(const volatile void __iomem *io_addr, - const unsigned char *signature, int length); -void devm_ioremap_release(struct device *dev, void *res); - -void *devm_memremap(struct device *dev, resource_size_t offset, - size_t size, unsigned long flags); -void devm_memunmap(struct device *dev, void *addr); - -void *__devm_memremap_pages(struct device *dev, struct resource *res); - -/* - * Some systems do not have legacy ISA devices. - * /dev/port is not a valid interface on these systems. - * So for those archs, should define the following symbol. - */ -#ifndef arch_has_dev_port -#define arch_has_dev_port() (1) -#endif - -/* - * Some systems (x86 without PAT) have a somewhat reliable way to mark a - * physical address range such that uncached mappings will actually - * end up write-combining. This facility should be used in conjunction - * with pgprot_writecombine, ioremap-wc, or set_memory_wc, since it has - * no effect if the per-page mechanisms are functional. - * (On x86 without PAT, these functions manipulate MTRRs.) - * - * arch_phys_del_wc(0) or arch_phys_del_wc(any error code) is guaranteed - * to have no effect. - */ -#ifndef arch_phys_wc_add -static inline int __must_check arch_phys_wc_add(unsigned long base, - unsigned long size) -{ - return 0; /* It worked (i.e. did nothing). */ -} - -static inline void arch_phys_wc_del(int handle) -{ -} - -#define arch_phys_wc_add arch_phys_wc_add -#ifndef arch_phys_wc_index -static inline int arch_phys_wc_index(int handle) -{ - return -1; -} -#define arch_phys_wc_index arch_phys_wc_index -#endif -#endif - -enum { - /* See memremap() kernel-doc for usage description... */ - MEMREMAP_WB = 1 << 0, - MEMREMAP_WT = 1 << 1, - MEMREMAP_WC = 1 << 2, -}; - -void *memremap(resource_size_t offset, size_t size, unsigned long flags); -void memunmap(void *addr); - -/* - * On x86 PAT systems we have memory tracking that keeps track of - * the allowed mappings on memory ranges. This tracking works for - * all the in-kernel mapping APIs (ioremap*), but where the user - * wishes to map a range from a physical device into user memory - * the tracking won't be updated. This API is to be used by - * drivers which remap physical device pages into userspace, - * and wants to make sure they are mapped WC and not UC. - */ -#ifndef arch_io_reserve_memtype_wc -static inline int arch_io_reserve_memtype_wc(resource_size_t base, - resource_size_t size) -{ - return 0; -} - -static inline void arch_io_free_memtype_wc(resource_size_t base, - resource_size_t size) -{ -} -#endif - -#endif /* _LINUX_IO_H */ diff --git a/src/linux/include/linux/iocontext.h b/src/linux/include/linux/iocontext.h deleted file mode 100644 index df38db2..0000000 --- a/src/linux/include/linux/iocontext.h +++ /dev/null @@ -1,157 +0,0 @@ -#ifndef IOCONTEXT_H -#define IOCONTEXT_H - -#include -#include -#include - -enum { - ICQ_EXITED = 1 << 2, -}; - -/* - * An io_cq (icq) is association between an io_context (ioc) and a - * request_queue (q). This is used by elevators which need to track - * information per ioc - q pair. - * - * Elevator can request use of icq by setting elevator_type->icq_size and - * ->icq_align. Both size and align must be larger than that of struct - * io_cq and elevator can use the tail area for private information. The - * recommended way to do this is defining a struct which contains io_cq as - * the first member followed by private members and using its size and - * align. For example, - * - * struct snail_io_cq { - * struct io_cq icq; - * int poke_snail; - * int feed_snail; - * }; - * - * struct elevator_type snail_elv_type { - * .ops = { ... }, - * .icq_size = sizeof(struct snail_io_cq), - * .icq_align = __alignof__(struct snail_io_cq), - * ... - * }; - * - * If icq_size is set, block core will manage icq's. All requests will - * have its ->elv.icq field set before elevator_ops->elevator_set_req_fn() - * is called and be holding a reference to the associated io_context. - * - * Whenever a new icq is created, elevator_ops->elevator_init_icq_fn() is - * called and, on destruction, ->elevator_exit_icq_fn(). Both functions - * are called with both the associated io_context and queue locks held. - * - * Elevator is allowed to lookup icq using ioc_lookup_icq() while holding - * queue lock but the returned icq is valid only until the queue lock is - * released. Elevators can not and should not try to create or destroy - * icq's. - * - * As icq's are linked from both ioc and q, the locking rules are a bit - * complex. - * - * - ioc lock nests inside q lock. - * - * - ioc->icq_list and icq->ioc_node are protected by ioc lock. - * q->icq_list and icq->q_node by q lock. - * - * - ioc->icq_tree and ioc->icq_hint are protected by ioc lock, while icq - * itself is protected by q lock. However, both the indexes and icq - * itself are also RCU managed and lookup can be performed holding only - * the q lock. - * - * - icq's are not reference counted. They are destroyed when either the - * ioc or q goes away. Each request with icq set holds an extra - * reference to ioc to ensure it stays until the request is completed. - * - * - Linking and unlinking icq's are performed while holding both ioc and q - * locks. Due to the lock ordering, q exit is simple but ioc exit - * requires reverse-order double lock dance. - */ -struct io_cq { - struct request_queue *q; - struct io_context *ioc; - - /* - * q_node and ioc_node link io_cq through icq_list of q and ioc - * respectively. Both fields are unused once ioc_exit_icq() is - * called and shared with __rcu_icq_cache and __rcu_head which are - * used for RCU free of io_cq. - */ - union { - struct list_head q_node; - struct kmem_cache *__rcu_icq_cache; - }; - union { - struct hlist_node ioc_node; - struct rcu_head __rcu_head; - }; - - unsigned int flags; -}; - -/* - * I/O subsystem state of the associated processes. It is refcounted - * and kmalloc'ed. These could be shared between processes. - */ -struct io_context { - atomic_long_t refcount; - atomic_t active_ref; - atomic_t nr_tasks; - - /* all the fields below are protected by this lock */ - spinlock_t lock; - - unsigned short ioprio; - - /* - * For request batching - */ - int nr_batch_requests; /* Number of requests left in the batch */ - unsigned long last_waited; /* Time last woken after wait for request */ - - struct radix_tree_root icq_tree; - struct io_cq __rcu *icq_hint; - struct hlist_head icq_list; - - struct work_struct release_work; -}; - -/** - * get_io_context_active - get active reference on ioc - * @ioc: ioc of interest - * - * Only iocs with active reference can issue new IOs. This function - * acquires an active reference on @ioc. The caller must already have an - * active reference on @ioc. - */ -static inline void get_io_context_active(struct io_context *ioc) -{ - WARN_ON_ONCE(atomic_long_read(&ioc->refcount) <= 0); - WARN_ON_ONCE(atomic_read(&ioc->active_ref) <= 0); - atomic_long_inc(&ioc->refcount); - atomic_inc(&ioc->active_ref); -} - -static inline void ioc_task_link(struct io_context *ioc) -{ - get_io_context_active(ioc); - - WARN_ON_ONCE(atomic_read(&ioc->nr_tasks) <= 0); - atomic_inc(&ioc->nr_tasks); -} - -struct task_struct; -#ifdef CONFIG_BLOCK -void put_io_context(struct io_context *ioc); -void put_io_context_active(struct io_context *ioc); -void exit_io_context(struct task_struct *task); -struct io_context *get_task_io_context(struct task_struct *task, - gfp_t gfp_flags, int node); -#else -struct io_context; -static inline void put_io_context(struct io_context *ioc) { } -static inline void exit_io_context(struct task_struct *task) { } -#endif - -#endif diff --git a/src/linux/include/linux/iomap.h b/src/linux/include/linux/iomap.h deleted file mode 100644 index 7892f55..0000000 --- a/src/linux/include/linux/iomap.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef LINUX_IOMAP_H -#define LINUX_IOMAP_H 1 - -#include - -struct fiemap_extent_info; -struct inode; -struct iov_iter; -struct kiocb; -struct vm_area_struct; -struct vm_fault; - -/* - * Types of block ranges for iomap mappings: - */ -#define IOMAP_HOLE 0x01 /* no blocks allocated, need allocation */ -#define IOMAP_DELALLOC 0x02 /* delayed allocation blocks */ -#define IOMAP_MAPPED 0x03 /* blocks allocated @blkno */ -#define IOMAP_UNWRITTEN 0x04 /* blocks allocated @blkno in unwritten state */ - -/* - * Flags for all iomap mappings: - */ -#define IOMAP_F_NEW 0x01 /* blocks have been newly allocated */ - -/* - * Flags that only need to be reported for IOMAP_REPORT requests: - */ -#define IOMAP_F_MERGED 0x10 /* contains multiple blocks/extents */ -#define IOMAP_F_SHARED 0x20 /* block shared with another file */ - -/* - * Magic value for blkno: - */ -#define IOMAP_NULL_BLOCK -1LL /* blkno is not valid */ - -struct iomap { - sector_t blkno; /* 1st sector of mapping, 512b units */ - loff_t offset; /* file offset of mapping, bytes */ - u64 length; /* length of mapping, bytes */ - u16 type; /* type of mapping */ - u16 flags; /* flags for mapping */ - struct block_device *bdev; /* block device for I/O */ -}; - -/* - * Flags for iomap_begin / iomap_end. No flag implies a read. - */ -#define IOMAP_WRITE (1 << 0) /* writing, must allocate blocks */ -#define IOMAP_ZERO (1 << 1) /* zeroing operation, may skip holes */ -#define IOMAP_REPORT (1 << 2) /* report extent status, e.g. FIEMAP */ - -struct iomap_ops { - /* - * Return the existing mapping at pos, or reserve space starting at - * pos for up to length, as long as we can do it as a single mapping. - * The actual length is returned in iomap->length. - */ - int (*iomap_begin)(struct inode *inode, loff_t pos, loff_t length, - unsigned flags, struct iomap *iomap); - - /* - * Commit and/or unreserve space previous allocated using iomap_begin. - * Written indicates the length of the successful write operation which - * needs to be commited, while the rest needs to be unreserved. - * Written might be zero if no data was written. - */ - int (*iomap_end)(struct inode *inode, loff_t pos, loff_t length, - ssize_t written, unsigned flags, struct iomap *iomap); -}; - -ssize_t iomap_file_buffered_write(struct kiocb *iocb, struct iov_iter *from, - struct iomap_ops *ops); -int iomap_file_dirty(struct inode *inode, loff_t pos, loff_t len, - struct iomap_ops *ops); -int iomap_zero_range(struct inode *inode, loff_t pos, loff_t len, - bool *did_zero, struct iomap_ops *ops); -int iomap_truncate_page(struct inode *inode, loff_t pos, bool *did_zero, - struct iomap_ops *ops); -int iomap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf, - struct iomap_ops *ops); -int iomap_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, - loff_t start, loff_t len, struct iomap_ops *ops); - -#endif /* LINUX_IOMAP_H */ diff --git a/src/linux/include/linux/ioport.h b/src/linux/include/linux/ioport.h deleted file mode 100644 index 6230064..0000000 --- a/src/linux/include/linux/ioport.h +++ /dev/null @@ -1,285 +0,0 @@ -/* - * ioport.h Definitions of routines for detecting, reserving and - * allocating system resources. - * - * Authors: Linus Torvalds - */ - -#ifndef _LINUX_IOPORT_H -#define _LINUX_IOPORT_H - -#ifndef __ASSEMBLY__ -#include -#include -/* - * Resources are tree-like, allowing - * nesting etc.. - */ -struct resource { - resource_size_t start; - resource_size_t end; - const char *name; - unsigned long flags; - unsigned long desc; - struct resource *parent, *sibling, *child; -}; - -/* - * IO resources have these defined flags. - * - * PCI devices expose these flags to userspace in the "resource" sysfs file, - * so don't move them. - */ -#define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */ - -#define IORESOURCE_TYPE_BITS 0x00001f00 /* Resource type */ -#define IORESOURCE_IO 0x00000100 /* PCI/ISA I/O ports */ -#define IORESOURCE_MEM 0x00000200 -#define IORESOURCE_REG 0x00000300 /* Register offsets */ -#define IORESOURCE_IRQ 0x00000400 -#define IORESOURCE_DMA 0x00000800 -#define IORESOURCE_BUS 0x00001000 - -#define IORESOURCE_PREFETCH 0x00002000 /* No side effects */ -#define IORESOURCE_READONLY 0x00004000 -#define IORESOURCE_CACHEABLE 0x00008000 -#define IORESOURCE_RANGELENGTH 0x00010000 -#define IORESOURCE_SHADOWABLE 0x00020000 - -#define IORESOURCE_SIZEALIGN 0x00040000 /* size indicates alignment */ -#define IORESOURCE_STARTALIGN 0x00080000 /* start field is alignment */ - -#define IORESOURCE_MEM_64 0x00100000 -#define IORESOURCE_WINDOW 0x00200000 /* forwarded by bridge */ -#define IORESOURCE_MUXED 0x00400000 /* Resource is software muxed */ - -#define IORESOURCE_EXT_TYPE_BITS 0x01000000 /* Resource extended types */ -#define IORESOURCE_SYSRAM 0x01000000 /* System RAM (modifier) */ - -#define IORESOURCE_EXCLUSIVE 0x08000000 /* Userland may not map this resource */ - -#define IORESOURCE_DISABLED 0x10000000 -#define IORESOURCE_UNSET 0x20000000 /* No address assigned yet */ -#define IORESOURCE_AUTO 0x40000000 -#define IORESOURCE_BUSY 0x80000000 /* Driver has marked this resource busy */ - -/* I/O resource extended types */ -#define IORESOURCE_SYSTEM_RAM (IORESOURCE_MEM|IORESOURCE_SYSRAM) - -/* PnP IRQ specific bits (IORESOURCE_BITS) */ -#define IORESOURCE_IRQ_HIGHEDGE (1<<0) -#define IORESOURCE_IRQ_LOWEDGE (1<<1) -#define IORESOURCE_IRQ_HIGHLEVEL (1<<2) -#define IORESOURCE_IRQ_LOWLEVEL (1<<3) -#define IORESOURCE_IRQ_SHAREABLE (1<<4) -#define IORESOURCE_IRQ_OPTIONAL (1<<5) - -/* PnP DMA specific bits (IORESOURCE_BITS) */ -#define IORESOURCE_DMA_TYPE_MASK (3<<0) -#define IORESOURCE_DMA_8BIT (0<<0) -#define IORESOURCE_DMA_8AND16BIT (1<<0) -#define IORESOURCE_DMA_16BIT (2<<0) - -#define IORESOURCE_DMA_MASTER (1<<2) -#define IORESOURCE_DMA_BYTE (1<<3) -#define IORESOURCE_DMA_WORD (1<<4) - -#define IORESOURCE_DMA_SPEED_MASK (3<<6) -#define IORESOURCE_DMA_COMPATIBLE (0<<6) -#define IORESOURCE_DMA_TYPEA (1<<6) -#define IORESOURCE_DMA_TYPEB (2<<6) -#define IORESOURCE_DMA_TYPEF (3<<6) - -/* PnP memory I/O specific bits (IORESOURCE_BITS) */ -#define IORESOURCE_MEM_WRITEABLE (1<<0) /* dup: IORESOURCE_READONLY */ -#define IORESOURCE_MEM_CACHEABLE (1<<1) /* dup: IORESOURCE_CACHEABLE */ -#define IORESOURCE_MEM_RANGELENGTH (1<<2) /* dup: IORESOURCE_RANGELENGTH */ -#define IORESOURCE_MEM_TYPE_MASK (3<<3) -#define IORESOURCE_MEM_8BIT (0<<3) -#define IORESOURCE_MEM_16BIT (1<<3) -#define IORESOURCE_MEM_8AND16BIT (2<<3) -#define IORESOURCE_MEM_32BIT (3<<3) -#define IORESOURCE_MEM_SHADOWABLE (1<<5) /* dup: IORESOURCE_SHADOWABLE */ -#define IORESOURCE_MEM_EXPANSIONROM (1<<6) - -/* PnP I/O specific bits (IORESOURCE_BITS) */ -#define IORESOURCE_IO_16BIT_ADDR (1<<0) -#define IORESOURCE_IO_FIXED (1<<1) -#define IORESOURCE_IO_SPARSE (1<<2) - -/* PCI ROM control bits (IORESOURCE_BITS) */ -#define IORESOURCE_ROM_ENABLE (1<<0) /* ROM is enabled, same as PCI_ROM_ADDRESS_ENABLE */ -#define IORESOURCE_ROM_SHADOW (1<<1) /* Use RAM image, not ROM BAR */ - -/* PCI control bits. Shares IORESOURCE_BITS with above PCI ROM. */ -#define IORESOURCE_PCI_FIXED (1<<4) /* Do not move resource */ -#define IORESOURCE_PCI_EA_BEI (1<<5) /* BAR Equivalent Indicator */ - -/* - * I/O Resource Descriptors - * - * Descriptors are used by walk_iomem_res_desc() and region_intersects() - * for searching a specific resource range in the iomem table. Assign - * a new descriptor when a resource range supports the search interfaces. - * Otherwise, resource.desc must be set to IORES_DESC_NONE (0). - */ -enum { - IORES_DESC_NONE = 0, - IORES_DESC_CRASH_KERNEL = 1, - IORES_DESC_ACPI_TABLES = 2, - IORES_DESC_ACPI_NV_STORAGE = 3, - IORES_DESC_PERSISTENT_MEMORY = 4, - IORES_DESC_PERSISTENT_MEMORY_LEGACY = 5, -}; - -/* helpers to define resources */ -#define DEFINE_RES_NAMED(_start, _size, _name, _flags) \ - { \ - .start = (_start), \ - .end = (_start) + (_size) - 1, \ - .name = (_name), \ - .flags = (_flags), \ - .desc = IORES_DESC_NONE, \ - } - -#define DEFINE_RES_IO_NAMED(_start, _size, _name) \ - DEFINE_RES_NAMED((_start), (_size), (_name), IORESOURCE_IO) -#define DEFINE_RES_IO(_start, _size) \ - DEFINE_RES_IO_NAMED((_start), (_size), NULL) - -#define DEFINE_RES_MEM_NAMED(_start, _size, _name) \ - DEFINE_RES_NAMED((_start), (_size), (_name), IORESOURCE_MEM) -#define DEFINE_RES_MEM(_start, _size) \ - DEFINE_RES_MEM_NAMED((_start), (_size), NULL) - -#define DEFINE_RES_IRQ_NAMED(_irq, _name) \ - DEFINE_RES_NAMED((_irq), 1, (_name), IORESOURCE_IRQ) -#define DEFINE_RES_IRQ(_irq) \ - DEFINE_RES_IRQ_NAMED((_irq), NULL) - -#define DEFINE_RES_DMA_NAMED(_dma, _name) \ - DEFINE_RES_NAMED((_dma), 1, (_name), IORESOURCE_DMA) -#define DEFINE_RES_DMA(_dma) \ - DEFINE_RES_DMA_NAMED((_dma), NULL) - -/* PC/ISA/whatever - the normal PC address spaces: IO and memory */ -extern struct resource ioport_resource; -extern struct resource iomem_resource; - -extern struct resource *request_resource_conflict(struct resource *root, struct resource *new); -extern int request_resource(struct resource *root, struct resource *new); -extern int release_resource(struct resource *new); -void release_child_resources(struct resource *new); -extern void reserve_region_with_split(struct resource *root, - resource_size_t start, resource_size_t end, - const char *name); -extern struct resource *insert_resource_conflict(struct resource *parent, struct resource *new); -extern int insert_resource(struct resource *parent, struct resource *new); -extern void insert_resource_expand_to_fit(struct resource *root, struct resource *new); -extern int remove_resource(struct resource *old); -extern void arch_remove_reservations(struct resource *avail); -extern int allocate_resource(struct resource *root, struct resource *new, - resource_size_t size, resource_size_t min, - resource_size_t max, resource_size_t align, - resource_size_t (*alignf)(void *, - const struct resource *, - resource_size_t, - resource_size_t), - void *alignf_data); -struct resource *lookup_resource(struct resource *root, resource_size_t start); -int adjust_resource(struct resource *res, resource_size_t start, - resource_size_t size); -resource_size_t resource_alignment(struct resource *res); -static inline resource_size_t resource_size(const struct resource *res) -{ - return res->end - res->start + 1; -} -static inline unsigned long resource_type(const struct resource *res) -{ - return res->flags & IORESOURCE_TYPE_BITS; -} -static inline unsigned long resource_ext_type(const struct resource *res) -{ - return res->flags & IORESOURCE_EXT_TYPE_BITS; -} -/* True iff r1 completely contains r2 */ -static inline bool resource_contains(struct resource *r1, struct resource *r2) -{ - if (resource_type(r1) != resource_type(r2)) - return false; - if (r1->flags & IORESOURCE_UNSET || r2->flags & IORESOURCE_UNSET) - return false; - return r1->start <= r2->start && r1->end >= r2->end; -} - - -/* Convenience shorthand with allocation */ -#define request_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), 0) -#define request_muxed_region(start,n,name) __request_region(&ioport_resource, (start), (n), (name), IORESOURCE_MUXED) -#define __request_mem_region(start,n,name, excl) __request_region(&iomem_resource, (start), (n), (name), excl) -#define request_mem_region(start,n,name) __request_region(&iomem_resource, (start), (n), (name), 0) -#define request_mem_region_exclusive(start,n,name) \ - __request_region(&iomem_resource, (start), (n), (name), IORESOURCE_EXCLUSIVE) -#define rename_region(region, newname) do { (region)->name = (newname); } while (0) - -extern struct resource * __request_region(struct resource *, - resource_size_t start, - resource_size_t n, - const char *name, int flags); - -/* Compatibility cruft */ -#define release_region(start,n) __release_region(&ioport_resource, (start), (n)) -#define release_mem_region(start,n) __release_region(&iomem_resource, (start), (n)) - -extern void __release_region(struct resource *, resource_size_t, - resource_size_t); -#ifdef CONFIG_MEMORY_HOTREMOVE -extern int release_mem_region_adjustable(struct resource *, resource_size_t, - resource_size_t); -#endif - -/* Wrappers for managed devices */ -struct device; - -extern int devm_request_resource(struct device *dev, struct resource *root, - struct resource *new); -extern void devm_release_resource(struct device *dev, struct resource *new); - -#define devm_request_region(dev,start,n,name) \ - __devm_request_region(dev, &ioport_resource, (start), (n), (name)) -#define devm_request_mem_region(dev,start,n,name) \ - __devm_request_region(dev, &iomem_resource, (start), (n), (name)) - -extern struct resource * __devm_request_region(struct device *dev, - struct resource *parent, resource_size_t start, - resource_size_t n, const char *name); - -#define devm_release_region(dev, start, n) \ - __devm_release_region(dev, &ioport_resource, (start), (n)) -#define devm_release_mem_region(dev, start, n) \ - __devm_release_region(dev, &iomem_resource, (start), (n)) - -extern void __devm_release_region(struct device *dev, struct resource *parent, - resource_size_t start, resource_size_t n); -extern int iomem_map_sanity_check(resource_size_t addr, unsigned long size); -extern int iomem_is_exclusive(u64 addr); - -extern int -walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages, - void *arg, int (*func)(unsigned long, unsigned long, void *)); -extern int -walk_system_ram_res(u64 start, u64 end, void *arg, - int (*func)(u64, u64, void *)); -extern int -walk_iomem_res_desc(unsigned long desc, unsigned long flags, u64 start, u64 end, - void *arg, int (*func)(u64, u64, void *)); - -/* True if any part of r1 overlaps r2 */ -static inline bool resource_overlaps(struct resource *r1, struct resource *r2) -{ - return (r1->start <= r2->end && r1->end >= r2->start); -} - - -#endif /* __ASSEMBLY__ */ -#endif /* _LINUX_IOPORT_H */ diff --git a/src/linux/include/linux/ioprio.h b/src/linux/include/linux/ioprio.h deleted file mode 100644 index 8c12390..0000000 --- a/src/linux/include/linux/ioprio.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef IOPRIO_H -#define IOPRIO_H - -#include -#include - -/* - * Gives us 8 prio classes with 13-bits of data for each class - */ -#define IOPRIO_CLASS_SHIFT (13) -#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1) - -#define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT) -#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK) -#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data) - -#define ioprio_valid(mask) (IOPRIO_PRIO_CLASS((mask)) != IOPRIO_CLASS_NONE) - -/* - * These are the io priority groups as implemented by CFQ. RT is the realtime - * class, it always gets premium service. BE is the best-effort scheduling - * class, the default for any process. IDLE is the idle scheduling class, it - * is only served when no one else is using the disk. - */ -enum { - IOPRIO_CLASS_NONE, - IOPRIO_CLASS_RT, - IOPRIO_CLASS_BE, - IOPRIO_CLASS_IDLE, -}; - -/* - * 8 best effort priority levels are supported - */ -#define IOPRIO_BE_NR (8) - -enum { - IOPRIO_WHO_PROCESS = 1, - IOPRIO_WHO_PGRP, - IOPRIO_WHO_USER, -}; - -/* - * Fallback BE priority - */ -#define IOPRIO_NORM (4) - -/* - * if process has set io priority explicitly, use that. if not, convert - * the cpu scheduler nice value to an io priority - */ -static inline int task_nice_ioprio(struct task_struct *task) -{ - return (task_nice(task) + 20) / 5; -} - -/* - * This is for the case where the task hasn't asked for a specific IO class. - * Check for idle and rt task process, and return appropriate IO class. - */ -static inline int task_nice_ioclass(struct task_struct *task) -{ - if (task->policy == SCHED_IDLE) - return IOPRIO_CLASS_IDLE; - else if (task->policy == SCHED_FIFO || task->policy == SCHED_RR) - return IOPRIO_CLASS_RT; - else - return IOPRIO_CLASS_BE; -} - -/* - * For inheritance, return the highest of the two given priorities - */ -extern int ioprio_best(unsigned short aprio, unsigned short bprio); - -extern int set_task_ioprio(struct task_struct *task, int ioprio); - -#endif diff --git a/src/linux/include/linux/ip.h b/src/linux/include/linux/ip.h deleted file mode 100644 index 492bc65..0000000 --- a/src/linux/include/linux/ip.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the IP protocol. - * - * Version: @(#)ip.h 1.0.2 04/28/93 - * - * Authors: Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_IP_H -#define _LINUX_IP_H - -#include -#include - -static inline struct iphdr *ip_hdr(const struct sk_buff *skb) -{ - return (struct iphdr *)skb_network_header(skb); -} - -static inline struct iphdr *inner_ip_hdr(const struct sk_buff *skb) -{ - return (struct iphdr *)skb_inner_network_header(skb); -} - -static inline struct iphdr *ipip_hdr(const struct sk_buff *skb) -{ - return (struct iphdr *)skb_transport_header(skb); -} -#endif /* _LINUX_IP_H */ diff --git a/src/linux/include/linux/ipc.h b/src/linux/include/linux/ipc.h deleted file mode 100644 index 9d84942..0000000 --- a/src/linux/include/linux/ipc.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef _LINUX_IPC_H -#define _LINUX_IPC_H - -#include -#include -#include - -#define IPCMNI 32768 /* <= MAX_INT limit for ipc arrays (including sysctl changes) */ - -/* used by in-kernel data structures */ -struct kern_ipc_perm -{ - spinlock_t lock; - bool deleted; - int id; - key_t key; - kuid_t uid; - kgid_t gid; - kuid_t cuid; - kgid_t cgid; - umode_t mode; - unsigned long seq; - void *security; -}; - -#endif /* _LINUX_IPC_H */ diff --git a/src/linux/include/linux/ipc_namespace.h b/src/linux/include/linux/ipc_namespace.h deleted file mode 100644 index 848e579..0000000 --- a/src/linux/include/linux/ipc_namespace.h +++ /dev/null @@ -1,159 +0,0 @@ -#ifndef __IPC_NAMESPACE_H__ -#define __IPC_NAMESPACE_H__ - -#include -#include -#include -#include -#include -#include - -struct user_namespace; - -struct ipc_ids { - int in_use; - unsigned short seq; - struct rw_semaphore rwsem; - struct idr ipcs_idr; - int next_id; -}; - -struct ipc_namespace { - atomic_t count; - struct ipc_ids ids[3]; - - int sem_ctls[4]; - int used_sems; - - unsigned int msg_ctlmax; - unsigned int msg_ctlmnb; - unsigned int msg_ctlmni; - atomic_t msg_bytes; - atomic_t msg_hdrs; - - size_t shm_ctlmax; - size_t shm_ctlall; - unsigned long shm_tot; - int shm_ctlmni; - /* - * Defines whether IPC_RMID is forced for _all_ shm segments regardless - * of shmctl() - */ - int shm_rmid_forced; - - struct notifier_block ipcns_nb; - - /* The kern_mount of the mqueuefs sb. We take a ref on it */ - struct vfsmount *mq_mnt; - - /* # queues in this ns, protected by mq_lock */ - unsigned int mq_queues_count; - - /* next fields are set through sysctl */ - unsigned int mq_queues_max; /* initialized to DFLT_QUEUESMAX */ - unsigned int mq_msg_max; /* initialized to DFLT_MSGMAX */ - unsigned int mq_msgsize_max; /* initialized to DFLT_MSGSIZEMAX */ - unsigned int mq_msg_default; - unsigned int mq_msgsize_default; - - /* user_ns which owns the ipc ns */ - struct user_namespace *user_ns; - struct ucounts *ucounts; - - struct ns_common ns; -}; - -extern struct ipc_namespace init_ipc_ns; -extern spinlock_t mq_lock; - -#ifdef CONFIG_SYSVIPC -extern void shm_destroy_orphaned(struct ipc_namespace *ns); -#else /* CONFIG_SYSVIPC */ -static inline void shm_destroy_orphaned(struct ipc_namespace *ns) {} -#endif /* CONFIG_SYSVIPC */ - -#ifdef CONFIG_POSIX_MQUEUE -extern int mq_init_ns(struct ipc_namespace *ns); -/* - * POSIX Message Queue default values: - * - * MIN_*: Lowest value an admin can set the maximum unprivileged limit to - * DFLT_*MAX: Default values for the maximum unprivileged limits - * DFLT_{MSG,MSGSIZE}: Default values used when the user doesn't supply - * an attribute to the open call and the queue must be created - * HARD_*: Highest value the maximums can be set to. These are enforced - * on CAP_SYS_RESOURCE apps as well making them inviolate (so make them - * suitably high) - * - * POSIX Requirements: - * Per app minimum openable message queues - 8. This does not map well - * to the fact that we limit the number of queues on a per namespace - * basis instead of a per app basis. So, make the default high enough - * that no given app should have a hard time opening 8 queues. - * Minimum maximum for HARD_MSGMAX - 32767. I bumped this to 65536. - * Minimum maximum for HARD_MSGSIZEMAX - POSIX is silent on this. However, - * we have run into a situation where running applications in the wild - * require this to be at least 5MB, and preferably 10MB, so I set the - * value to 16MB in hopes that this user is the worst of the bunch and - * the new maximum will handle anyone else. I may have to revisit this - * in the future. - */ -#define DFLT_QUEUESMAX 256 -#define MIN_MSGMAX 1 -#define DFLT_MSG 10U -#define DFLT_MSGMAX 10 -#define HARD_MSGMAX 65536 -#define MIN_MSGSIZEMAX 128 -#define DFLT_MSGSIZE 8192U -#define DFLT_MSGSIZEMAX 8192 -#define HARD_MSGSIZEMAX (16*1024*1024) -#else -static inline int mq_init_ns(struct ipc_namespace *ns) { return 0; } -#endif - -#if defined(CONFIG_IPC_NS) -extern struct ipc_namespace *copy_ipcs(unsigned long flags, - struct user_namespace *user_ns, struct ipc_namespace *ns); - -static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns) -{ - if (ns) - atomic_inc(&ns->count); - return ns; -} - -extern void put_ipc_ns(struct ipc_namespace *ns); -#else -static inline struct ipc_namespace *copy_ipcs(unsigned long flags, - struct user_namespace *user_ns, struct ipc_namespace *ns) -{ - if (flags & CLONE_NEWIPC) - return ERR_PTR(-EINVAL); - - return ns; -} - -static inline struct ipc_namespace *get_ipc_ns(struct ipc_namespace *ns) -{ - return ns; -} - -static inline void put_ipc_ns(struct ipc_namespace *ns) -{ -} -#endif - -#ifdef CONFIG_POSIX_MQUEUE_SYSCTL - -struct ctl_table_header; -extern struct ctl_table_header *mq_register_sysctl_table(void); - -#else /* CONFIG_POSIX_MQUEUE_SYSCTL */ - -static inline struct ctl_table_header *mq_register_sysctl_table(void) -{ - return NULL; -} - -#endif /* CONFIG_POSIX_MQUEUE_SYSCTL */ -#endif diff --git a/src/linux/include/linux/ipv6.h b/src/linux/include/linux/ipv6.h deleted file mode 100644 index a064997..0000000 --- a/src/linux/include/linux/ipv6.h +++ /dev/null @@ -1,368 +0,0 @@ -#ifndef _IPV6_H -#define _IPV6_H - -#include - -#define ipv6_optlen(p) (((p)->hdrlen+1) << 3) -#define ipv6_authlen(p) (((p)->hdrlen+2) << 2) -/* - * This structure contains configuration options per IPv6 link. - */ -struct ipv6_devconf { - __s32 forwarding; - __s32 hop_limit; - __s32 mtu6; - __s32 accept_ra; - __s32 accept_redirects; - __s32 autoconf; - __s32 dad_transmits; - __s32 rtr_solicits; - __s32 rtr_solicit_interval; - __s32 rtr_solicit_max_interval; - __s32 rtr_solicit_delay; - __s32 force_mld_version; - __s32 mldv1_unsolicited_report_interval; - __s32 mldv2_unsolicited_report_interval; - __s32 use_tempaddr; - __s32 temp_valid_lft; - __s32 temp_prefered_lft; - __s32 regen_max_retry; - __s32 max_desync_factor; - __s32 max_addresses; - __s32 accept_ra_defrtr; - __s32 accept_ra_min_hop_limit; - __s32 accept_ra_pinfo; - __s32 ignore_routes_with_linkdown; -#ifdef CONFIG_IPV6_ROUTER_PREF - __s32 accept_ra_rtr_pref; - __s32 rtr_probe_interval; -#ifdef CONFIG_IPV6_ROUTE_INFO - __s32 accept_ra_rt_info_max_plen; -#endif -#endif - __s32 proxy_ndp; - __s32 accept_source_route; - __s32 accept_ra_from_local; -#ifdef CONFIG_IPV6_OPTIMISTIC_DAD - __s32 optimistic_dad; - __s32 use_optimistic; -#endif -#ifdef CONFIG_IPV6_MROUTE - __s32 mc_forwarding; -#endif - __s32 disable_ipv6; - __s32 drop_unicast_in_l2_multicast; - __s32 accept_dad; - __s32 force_tllao; - __s32 ndisc_notify; - __s32 suppress_frag_ndisc; - __s32 accept_ra_mtu; - __s32 drop_unsolicited_na; - struct ipv6_stable_secret { - bool initialized; - struct in6_addr secret; - } stable_secret; - __s32 use_oif_addrs_only; - __s32 keep_addr_on_down; - - struct ctl_table_header *sysctl_header; -}; - -struct ipv6_params { - __s32 disable_ipv6; - __s32 autoconf; -}; -extern struct ipv6_params ipv6_defaults; -#include -#include -#include - -#include - -static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb) -{ - return (struct ipv6hdr *)skb_network_header(skb); -} - -static inline struct ipv6hdr *inner_ipv6_hdr(const struct sk_buff *skb) -{ - return (struct ipv6hdr *)skb_inner_network_header(skb); -} - -static inline struct ipv6hdr *ipipv6_hdr(const struct sk_buff *skb) -{ - return (struct ipv6hdr *)skb_transport_header(skb); -} - -/* - This structure contains results of exthdrs parsing - as offsets from skb->nh. - */ - -struct inet6_skb_parm { - int iif; - __be16 ra; - __u16 dst0; - __u16 srcrt; - __u16 dst1; - __u16 lastopt; - __u16 nhoff; - __u16 flags; -#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) - __u16 dsthao; -#endif - __u16 frag_max_size; - -#define IP6SKB_XFRM_TRANSFORMED 1 -#define IP6SKB_FORWARDED 2 -#define IP6SKB_REROUTED 4 -#define IP6SKB_ROUTERALERT 8 -#define IP6SKB_FRAGMENTED 16 -#define IP6SKB_HOPBYHOP 32 -#define IP6SKB_L3SLAVE 64 -}; - -#if defined(CONFIG_NET_L3_MASTER_DEV) -static inline bool ipv6_l3mdev_skb(__u16 flags) -{ - return flags & IP6SKB_L3SLAVE; -} -#else -static inline bool ipv6_l3mdev_skb(__u16 flags) -{ - return false; -} -#endif - -#define IP6CB(skb) ((struct inet6_skb_parm*)((skb)->cb)) -#define IP6CBMTU(skb) ((struct ip6_mtuinfo *)((skb)->cb)) - -static inline int inet6_iif(const struct sk_buff *skb) -{ - bool l3_slave = ipv6_l3mdev_skb(IP6CB(skb)->flags); - - return l3_slave ? skb->skb_iif : IP6CB(skb)->iif; -} - -/* can not be used in TCP layer after tcp_v6_fill_cb */ -static inline bool inet6_exact_dif_match(struct net *net, struct sk_buff *skb) -{ -#if defined(CONFIG_NET_L3_MASTER_DEV) - if (!net->ipv4.sysctl_tcp_l3mdev_accept && - skb && ipv6_l3mdev_skb(IP6CB(skb)->flags)) - return true; -#endif - return false; -} - -struct tcp6_request_sock { - struct tcp_request_sock tcp6rsk_tcp; -}; - -struct ipv6_mc_socklist; -struct ipv6_ac_socklist; -struct ipv6_fl_socklist; - -struct inet6_cork { - struct ipv6_txoptions *opt; - u8 hop_limit; - u8 tclass; -}; - -/** - * struct ipv6_pinfo - ipv6 private area - * - * In the struct sock hierarchy (tcp6_sock, upd6_sock, etc) - * this _must_ be the last member, so that inet6_sk_generic - * is able to calculate its offset from the base struct sock - * by using the struct proto->slab_obj_size member. -acme - */ -struct ipv6_pinfo { - struct in6_addr saddr; - struct in6_pktinfo sticky_pktinfo; - const struct in6_addr *daddr_cache; -#ifdef CONFIG_IPV6_SUBTREES - const struct in6_addr *saddr_cache; -#endif - - __be32 flow_label; - __u32 frag_size; - - /* - * Packed in 16bits. - * Omit one shift by by putting the signed field at MSB. - */ -#if defined(__BIG_ENDIAN_BITFIELD) - __s16 hop_limit:9; - __u16 __unused_1:7; -#else - __u16 __unused_1:7; - __s16 hop_limit:9; -#endif - -#if defined(__BIG_ENDIAN_BITFIELD) - /* Packed in 16bits. */ - __s16 mcast_hops:9; - __u16 __unused_2:6, - mc_loop:1; -#else - __u16 mc_loop:1, - __unused_2:6; - __s16 mcast_hops:9; -#endif - int ucast_oif; - int mcast_oif; - - /* pktoption flags */ - union { - struct { - __u16 srcrt:1, - osrcrt:1, - rxinfo:1, - rxoinfo:1, - rxhlim:1, - rxohlim:1, - hopopts:1, - ohopopts:1, - dstopts:1, - odstopts:1, - rxflow:1, - rxtclass:1, - rxpmtu:1, - rxorigdstaddr:1; - /* 2 bits hole */ - } bits; - __u16 all; - } rxopt; - - /* sockopt flags */ - __u16 recverr:1, - sndflow:1, - repflow:1, - pmtudisc:3, - padding:1, /* 1 bit hole */ - srcprefs:3, /* 001: prefer temporary address - * 010: prefer public address - * 100: prefer care-of address - */ - dontfrag:1, - autoflowlabel:1; - __u8 min_hopcount; - __u8 tclass; - __be32 rcv_flowinfo; - - __u32 dst_cookie; - __u32 rx_dst_cookie; - - struct ipv6_mc_socklist __rcu *ipv6_mc_list; - struct ipv6_ac_socklist *ipv6_ac_list; - struct ipv6_fl_socklist __rcu *ipv6_fl_list; - - struct ipv6_txoptions __rcu *opt; - struct sk_buff *pktoptions; - struct sk_buff *rxpmtu; - struct inet6_cork cork; -}; - -/* WARNING: don't change the layout of the members in {raw,udp,tcp}6_sock! */ -struct raw6_sock { - /* inet_sock has to be the first member of raw6_sock */ - struct inet_sock inet; - __u32 checksum; /* perform checksum */ - __u32 offset; /* checksum offset */ - struct icmp6_filter filter; - __u32 ip6mr_table; - /* ipv6_pinfo has to be the last member of raw6_sock, see inet6_sk_generic */ - struct ipv6_pinfo inet6; -}; - -struct udp6_sock { - struct udp_sock udp; - /* ipv6_pinfo has to be the last member of udp6_sock, see inet6_sk_generic */ - struct ipv6_pinfo inet6; -}; - -struct tcp6_sock { - struct tcp_sock tcp; - /* ipv6_pinfo has to be the last member of tcp6_sock, see inet6_sk_generic */ - struct ipv6_pinfo inet6; -}; - -extern int inet6_sk_rebuild_header(struct sock *sk); - -struct tcp6_timewait_sock { - struct tcp_timewait_sock tcp6tw_tcp; -}; - -#if IS_ENABLED(CONFIG_IPV6) -bool ipv6_mod_enabled(void); - -static inline struct ipv6_pinfo *inet6_sk(const struct sock *__sk) -{ - return sk_fullsock(__sk) ? inet_sk(__sk)->pinet6 : NULL; -} - -static inline struct raw6_sock *raw6_sk(const struct sock *sk) -{ - return (struct raw6_sock *)sk; -} - -static inline void inet_sk_copy_descendant(struct sock *sk_to, - const struct sock *sk_from) -{ - int ancestor_size = sizeof(struct inet_sock); - - if (sk_from->sk_family == PF_INET6) - ancestor_size += sizeof(struct ipv6_pinfo); - - __inet_sk_copy_descendant(sk_to, sk_from, ancestor_size); -} - -#define __ipv6_only_sock(sk) (sk->sk_ipv6only) -#define ipv6_only_sock(sk) (__ipv6_only_sock(sk)) -#define ipv6_sk_rxinfo(sk) ((sk)->sk_family == PF_INET6 && \ - inet6_sk(sk)->rxopt.bits.rxinfo) - -static inline const struct in6_addr *inet6_rcv_saddr(const struct sock *sk) -{ - if (sk->sk_family == AF_INET6) - return &sk->sk_v6_rcv_saddr; - return NULL; -} - -static inline int inet_v6_ipv6only(const struct sock *sk) -{ - /* ipv6only field is at same position for timewait and other sockets */ - return ipv6_only_sock(sk); -} -#else -#define __ipv6_only_sock(sk) 0 -#define ipv6_only_sock(sk) 0 -#define ipv6_sk_rxinfo(sk) 0 - -static inline bool ipv6_mod_enabled(void) -{ - return false; -} - -static inline struct ipv6_pinfo * inet6_sk(const struct sock *__sk) -{ - return NULL; -} - -static inline struct inet6_request_sock * - inet6_rsk(const struct request_sock *rsk) -{ - return NULL; -} - -static inline struct raw6_sock *raw6_sk(const struct sock *sk) -{ - return NULL; -} - -#define inet6_rcv_saddr(__sk) NULL -#define tcp_twsk_ipv6only(__sk) 0 -#define inet_v6_ipv6only(__sk) 0 -#endif /* IS_ENABLED(CONFIG_IPV6) */ -#endif /* _IPV6_H */ diff --git a/src/linux/include/linux/ipv6_route.h b/src/linux/include/linux/ipv6_route.h deleted file mode 100644 index 25b5f1f..0000000 --- a/src/linux/include/linux/ipv6_route.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_IPV6_ROUTE_H -#define _LINUX_IPV6_ROUTE_H - -#include - -#define IPV6_EXTRACT_PREF(flag) (((flag) & RTF_PREF_MASK) >> 27) -#define IPV6_DECODE_PREF(pref) ((pref) ^ 2) /* 1:low,2:med,3:high */ -#endif diff --git a/src/linux/include/linux/irq.h b/src/linux/include/linux/irq.h deleted file mode 100644 index e798755..0000000 --- a/src/linux/include/linux/irq.h +++ /dev/null @@ -1,992 +0,0 @@ -#ifndef _LINUX_IRQ_H -#define _LINUX_IRQ_H - -/* - * Please do not include this file in generic code. There is currently - * no requirement for any architecture to implement anything held - * within this file. - * - * Thanks. --rmk - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -struct seq_file; -struct module; -struct msi_msg; -enum irqchip_irq_state; - -/* - * IRQ line status. - * - * Bits 0-7 are the same as the IRQF_* bits in linux/interrupt.h - * - * IRQ_TYPE_NONE - default, unspecified type - * IRQ_TYPE_EDGE_RISING - rising edge triggered - * IRQ_TYPE_EDGE_FALLING - falling edge triggered - * IRQ_TYPE_EDGE_BOTH - rising and falling edge triggered - * IRQ_TYPE_LEVEL_HIGH - high level triggered - * IRQ_TYPE_LEVEL_LOW - low level triggered - * IRQ_TYPE_LEVEL_MASK - Mask to filter out the level bits - * IRQ_TYPE_SENSE_MASK - Mask for all the above bits - * IRQ_TYPE_DEFAULT - For use by some PICs to ask irq_set_type - * to setup the HW to a sane default (used - * by irqdomain map() callbacks to synchronize - * the HW state and SW flags for a newly - * allocated descriptor). - * - * IRQ_TYPE_PROBE - Special flag for probing in progress - * - * Bits which can be modified via irq_set/clear/modify_status_flags() - * IRQ_LEVEL - Interrupt is level type. Will be also - * updated in the code when the above trigger - * bits are modified via irq_set_irq_type() - * IRQ_PER_CPU - Mark an interrupt PER_CPU. Will protect - * it from affinity setting - * IRQ_NOPROBE - Interrupt cannot be probed by autoprobing - * IRQ_NOREQUEST - Interrupt cannot be requested via - * request_irq() - * IRQ_NOTHREAD - Interrupt cannot be threaded - * IRQ_NOAUTOEN - Interrupt is not automatically enabled in - * request/setup_irq() - * IRQ_NO_BALANCING - Interrupt cannot be balanced (affinity set) - * IRQ_MOVE_PCNTXT - Interrupt can be migrated from process context - * IRQ_NESTED_THREAD - Interrupt nests into another thread - * IRQ_PER_CPU_DEVID - Dev_id is a per-cpu variable - * IRQ_IS_POLLED - Always polled by another interrupt. Exclude - * it from the spurious interrupt detection - * mechanism and from core side polling. - * IRQ_DISABLE_UNLAZY - Disable lazy irq disable - */ -enum { - IRQ_TYPE_NONE = 0x00000000, - IRQ_TYPE_EDGE_RISING = 0x00000001, - IRQ_TYPE_EDGE_FALLING = 0x00000002, - IRQ_TYPE_EDGE_BOTH = (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING), - IRQ_TYPE_LEVEL_HIGH = 0x00000004, - IRQ_TYPE_LEVEL_LOW = 0x00000008, - IRQ_TYPE_LEVEL_MASK = (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH), - IRQ_TYPE_SENSE_MASK = 0x0000000f, - IRQ_TYPE_DEFAULT = IRQ_TYPE_SENSE_MASK, - - IRQ_TYPE_PROBE = 0x00000010, - - IRQ_LEVEL = (1 << 8), - IRQ_PER_CPU = (1 << 9), - IRQ_NOPROBE = (1 << 10), - IRQ_NOREQUEST = (1 << 11), - IRQ_NOAUTOEN = (1 << 12), - IRQ_NO_BALANCING = (1 << 13), - IRQ_MOVE_PCNTXT = (1 << 14), - IRQ_NESTED_THREAD = (1 << 15), - IRQ_NOTHREAD = (1 << 16), - IRQ_PER_CPU_DEVID = (1 << 17), - IRQ_IS_POLLED = (1 << 18), - IRQ_DISABLE_UNLAZY = (1 << 19), -}; - -#define IRQF_MODIFY_MASK \ - (IRQ_TYPE_SENSE_MASK | IRQ_NOPROBE | IRQ_NOREQUEST | \ - IRQ_NOAUTOEN | IRQ_MOVE_PCNTXT | IRQ_LEVEL | IRQ_NO_BALANCING | \ - IRQ_PER_CPU | IRQ_NESTED_THREAD | IRQ_NOTHREAD | IRQ_PER_CPU_DEVID | \ - IRQ_IS_POLLED | IRQ_DISABLE_UNLAZY) - -#define IRQ_NO_BALANCING_MASK (IRQ_PER_CPU | IRQ_NO_BALANCING) - -/* - * Return value for chip->irq_set_affinity() - * - * IRQ_SET_MASK_OK - OK, core updates irq_common_data.affinity - * IRQ_SET_MASK_NOCPY - OK, chip did update irq_common_data.affinity - * IRQ_SET_MASK_OK_DONE - Same as IRQ_SET_MASK_OK for core. Special code to - * support stacked irqchips, which indicates skipping - * all descendent irqchips. - */ -enum { - IRQ_SET_MASK_OK = 0, - IRQ_SET_MASK_OK_NOCOPY, - IRQ_SET_MASK_OK_DONE, -}; - -struct msi_desc; -struct irq_domain; - -/** - * struct irq_common_data - per irq data shared by all irqchips - * @state_use_accessors: status information for irq chip functions. - * Use accessor functions to deal with it - * @node: node index useful for balancing - * @handler_data: per-IRQ data for the irq_chip methods - * @affinity: IRQ affinity on SMP. If this is an IPI - * related irq, then this is the mask of the - * CPUs to which an IPI can be sent. - * @msi_desc: MSI descriptor - * @ipi_offset: Offset of first IPI target cpu in @affinity. Optional. - */ -struct irq_common_data { - unsigned int __private state_use_accessors; -#ifdef CONFIG_NUMA - unsigned int node; -#endif - void *handler_data; - struct msi_desc *msi_desc; - cpumask_var_t affinity; -#ifdef CONFIG_GENERIC_IRQ_IPI - unsigned int ipi_offset; -#endif -}; - -/** - * struct irq_data - per irq chip data passed down to chip functions - * @mask: precomputed bitmask for accessing the chip registers - * @irq: interrupt number - * @hwirq: hardware interrupt number, local to the interrupt domain - * @common: point to data shared by all irqchips - * @chip: low level interrupt hardware access - * @domain: Interrupt translation domain; responsible for mapping - * between hwirq number and linux irq number. - * @parent_data: pointer to parent struct irq_data to support hierarchy - * irq_domain - * @chip_data: platform-specific per-chip private data for the chip - * methods, to allow shared chip implementations - */ -struct irq_data { - u32 mask; - unsigned int irq; - unsigned long hwirq; - struct irq_common_data *common; - struct irq_chip *chip; - struct irq_domain *domain; -#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY - struct irq_data *parent_data; -#endif - void *chip_data; -}; - -/* - * Bit masks for irq_common_data.state_use_accessors - * - * IRQD_TRIGGER_MASK - Mask for the trigger type bits - * IRQD_SETAFFINITY_PENDING - Affinity setting is pending - * IRQD_NO_BALANCING - Balancing disabled for this IRQ - * IRQD_PER_CPU - Interrupt is per cpu - * IRQD_AFFINITY_SET - Interrupt affinity was set - * IRQD_LEVEL - Interrupt is level triggered - * IRQD_WAKEUP_STATE - Interrupt is configured for wakeup - * from suspend - * IRDQ_MOVE_PCNTXT - Interrupt can be moved in process - * context - * IRQD_IRQ_DISABLED - Disabled state of the interrupt - * IRQD_IRQ_MASKED - Masked state of the interrupt - * IRQD_IRQ_INPROGRESS - In progress state of the interrupt - * IRQD_WAKEUP_ARMED - Wakeup mode armed - * IRQD_FORWARDED_TO_VCPU - The interrupt is forwarded to a VCPU - * IRQD_AFFINITY_MANAGED - Affinity is auto-managed by the kernel - */ -enum { - IRQD_TRIGGER_MASK = 0xf, - IRQD_SETAFFINITY_PENDING = (1 << 8), - IRQD_NO_BALANCING = (1 << 10), - IRQD_PER_CPU = (1 << 11), - IRQD_AFFINITY_SET = (1 << 12), - IRQD_LEVEL = (1 << 13), - IRQD_WAKEUP_STATE = (1 << 14), - IRQD_MOVE_PCNTXT = (1 << 15), - IRQD_IRQ_DISABLED = (1 << 16), - IRQD_IRQ_MASKED = (1 << 17), - IRQD_IRQ_INPROGRESS = (1 << 18), - IRQD_WAKEUP_ARMED = (1 << 19), - IRQD_FORWARDED_TO_VCPU = (1 << 20), - IRQD_AFFINITY_MANAGED = (1 << 21), -}; - -#define __irqd_to_state(d) ACCESS_PRIVATE((d)->common, state_use_accessors) - -static inline bool irqd_is_setaffinity_pending(struct irq_data *d) -{ - return __irqd_to_state(d) & IRQD_SETAFFINITY_PENDING; -} - -static inline bool irqd_is_per_cpu(struct irq_data *d) -{ - return __irqd_to_state(d) & IRQD_PER_CPU; -} - -static inline bool irqd_can_balance(struct irq_data *d) -{ - return !(__irqd_to_state(d) & (IRQD_PER_CPU | IRQD_NO_BALANCING)); -} - -static inline bool irqd_affinity_was_set(struct irq_data *d) -{ - return __irqd_to_state(d) & IRQD_AFFINITY_SET; -} - -static inline void irqd_mark_affinity_was_set(struct irq_data *d) -{ - __irqd_to_state(d) |= IRQD_AFFINITY_SET; -} - -static inline u32 irqd_get_trigger_type(struct irq_data *d) -{ - return __irqd_to_state(d) & IRQD_TRIGGER_MASK; -} - -/* - * Must only be called inside irq_chip.irq_set_type() functions. - */ -static inline void irqd_set_trigger_type(struct irq_data *d, u32 type) -{ - __irqd_to_state(d) &= ~IRQD_TRIGGER_MASK; - __irqd_to_state(d) |= type & IRQD_TRIGGER_MASK; -} - -static inline bool irqd_is_level_type(struct irq_data *d) -{ - return __irqd_to_state(d) & IRQD_LEVEL; -} - -static inline bool irqd_is_wakeup_set(struct irq_data *d) -{ - return __irqd_to_state(d) & IRQD_WAKEUP_STATE; -} - -static inline bool irqd_can_move_in_process_context(struct irq_data *d) -{ - return __irqd_to_state(d) & IRQD_MOVE_PCNTXT; -} - -static inline bool irqd_irq_disabled(struct irq_data *d) -{ - return __irqd_to_state(d) & IRQD_IRQ_DISABLED; -} - -static inline bool irqd_irq_masked(struct irq_data *d) -{ - return __irqd_to_state(d) & IRQD_IRQ_MASKED; -} - -static inline bool irqd_irq_inprogress(struct irq_data *d) -{ - return __irqd_to_state(d) & IRQD_IRQ_INPROGRESS; -} - -static inline bool irqd_is_wakeup_armed(struct irq_data *d) -{ - return __irqd_to_state(d) & IRQD_WAKEUP_ARMED; -} - -static inline bool irqd_is_forwarded_to_vcpu(struct irq_data *d) -{ - return __irqd_to_state(d) & IRQD_FORWARDED_TO_VCPU; -} - -static inline void irqd_set_forwarded_to_vcpu(struct irq_data *d) -{ - __irqd_to_state(d) |= IRQD_FORWARDED_TO_VCPU; -} - -static inline void irqd_clr_forwarded_to_vcpu(struct irq_data *d) -{ - __irqd_to_state(d) &= ~IRQD_FORWARDED_TO_VCPU; -} - -static inline bool irqd_affinity_is_managed(struct irq_data *d) -{ - return __irqd_to_state(d) & IRQD_AFFINITY_MANAGED; -} - -#undef __irqd_to_state - -static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d) -{ - return d->hwirq; -} - -/** - * struct irq_chip - hardware interrupt chip descriptor - * - * @parent_device: pointer to parent device for irqchip - * @name: name for /proc/interrupts - * @irq_startup: start up the interrupt (defaults to ->enable if NULL) - * @irq_shutdown: shut down the interrupt (defaults to ->disable if NULL) - * @irq_enable: enable the interrupt (defaults to chip->unmask if NULL) - * @irq_disable: disable the interrupt - * @irq_ack: start of a new interrupt - * @irq_mask: mask an interrupt source - * @irq_mask_ack: ack and mask an interrupt source - * @irq_unmask: unmask an interrupt source - * @irq_eoi: end of interrupt - * @irq_set_affinity: set the CPU affinity on SMP machines - * @irq_retrigger: resend an IRQ to the CPU - * @irq_set_type: set the flow type (IRQ_TYPE_LEVEL/etc.) of an IRQ - * @irq_set_wake: enable/disable power-management wake-on of an IRQ - * @irq_bus_lock: function to lock access to slow bus (i2c) chips - * @irq_bus_sync_unlock:function to sync and unlock slow bus (i2c) chips - * @irq_cpu_online: configure an interrupt source for a secondary CPU - * @irq_cpu_offline: un-configure an interrupt source for a secondary CPU - * @irq_suspend: function called from core code on suspend once per - * chip, when one or more interrupts are installed - * @irq_resume: function called from core code on resume once per chip, - * when one ore more interrupts are installed - * @irq_pm_shutdown: function called from core code on shutdown once per chip - * @irq_calc_mask: Optional function to set irq_data.mask for special cases - * @irq_print_chip: optional to print special chip info in show_interrupts - * @irq_request_resources: optional to request resources before calling - * any other callback related to this irq - * @irq_release_resources: optional to release resources acquired with - * irq_request_resources - * @irq_compose_msi_msg: optional to compose message content for MSI - * @irq_write_msi_msg: optional to write message content for MSI - * @irq_get_irqchip_state: return the internal state of an interrupt - * @irq_set_irqchip_state: set the internal state of a interrupt - * @irq_set_vcpu_affinity: optional to target a vCPU in a virtual machine - * @ipi_send_single: send a single IPI to destination cpus - * @ipi_send_mask: send an IPI to destination cpus in cpumask - * @flags: chip specific flags - */ -struct irq_chip { - struct device *parent_device; - const char *name; - unsigned int (*irq_startup)(struct irq_data *data); - void (*irq_shutdown)(struct irq_data *data); - void (*irq_enable)(struct irq_data *data); - void (*irq_disable)(struct irq_data *data); - - void (*irq_ack)(struct irq_data *data); - void (*irq_mask)(struct irq_data *data); - void (*irq_mask_ack)(struct irq_data *data); - void (*irq_unmask)(struct irq_data *data); - void (*irq_eoi)(struct irq_data *data); - - int (*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force); - int (*irq_retrigger)(struct irq_data *data); - int (*irq_set_type)(struct irq_data *data, unsigned int flow_type); - int (*irq_set_wake)(struct irq_data *data, unsigned int on); - - void (*irq_bus_lock)(struct irq_data *data); - void (*irq_bus_sync_unlock)(struct irq_data *data); - - void (*irq_cpu_online)(struct irq_data *data); - void (*irq_cpu_offline)(struct irq_data *data); - - void (*irq_suspend)(struct irq_data *data); - void (*irq_resume)(struct irq_data *data); - void (*irq_pm_shutdown)(struct irq_data *data); - - void (*irq_calc_mask)(struct irq_data *data); - - void (*irq_print_chip)(struct irq_data *data, struct seq_file *p); - int (*irq_request_resources)(struct irq_data *data); - void (*irq_release_resources)(struct irq_data *data); - - void (*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg); - void (*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg); - - int (*irq_get_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool *state); - int (*irq_set_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool state); - - int (*irq_set_vcpu_affinity)(struct irq_data *data, void *vcpu_info); - - void (*ipi_send_single)(struct irq_data *data, unsigned int cpu); - void (*ipi_send_mask)(struct irq_data *data, const struct cpumask *dest); - - unsigned long flags; -}; - -/* - * irq_chip specific flags - * - * IRQCHIP_SET_TYPE_MASKED: Mask before calling chip.irq_set_type() - * IRQCHIP_EOI_IF_HANDLED: Only issue irq_eoi() when irq was handled - * IRQCHIP_MASK_ON_SUSPEND: Mask non wake irqs in the suspend path - * IRQCHIP_ONOFFLINE_ENABLED: Only call irq_on/off_line callbacks - * when irq enabled - * IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip - * IRQCHIP_ONESHOT_SAFE: One shot does not require mask/unmask - * IRQCHIP_EOI_THREADED: Chip requires eoi() on unmask in threaded mode - */ -enum { - IRQCHIP_SET_TYPE_MASKED = (1 << 0), - IRQCHIP_EOI_IF_HANDLED = (1 << 1), - IRQCHIP_MASK_ON_SUSPEND = (1 << 2), - IRQCHIP_ONOFFLINE_ENABLED = (1 << 3), - IRQCHIP_SKIP_SET_WAKE = (1 << 4), - IRQCHIP_ONESHOT_SAFE = (1 << 5), - IRQCHIP_EOI_THREADED = (1 << 6), -}; - -#include - -/* - * Pick up the arch-dependent methods: - */ -#include - -#ifndef NR_IRQS_LEGACY -# define NR_IRQS_LEGACY 0 -#endif - -#ifndef ARCH_IRQ_INIT_FLAGS -# define ARCH_IRQ_INIT_FLAGS 0 -#endif - -#define IRQ_DEFAULT_INIT_FLAGS ARCH_IRQ_INIT_FLAGS - -struct irqaction; -extern int setup_irq(unsigned int irq, struct irqaction *new); -extern void remove_irq(unsigned int irq, struct irqaction *act); -extern int setup_percpu_irq(unsigned int irq, struct irqaction *new); -extern void remove_percpu_irq(unsigned int irq, struct irqaction *act); - -extern void irq_cpu_online(void); -extern void irq_cpu_offline(void); -extern int irq_set_affinity_locked(struct irq_data *data, - const struct cpumask *cpumask, bool force); -extern int irq_set_vcpu_affinity(unsigned int irq, void *vcpu_info); - -extern void irq_migrate_all_off_this_cpu(void); - -#if defined(CONFIG_SMP) && defined(CONFIG_GENERIC_PENDING_IRQ) -void irq_move_irq(struct irq_data *data); -void irq_move_masked_irq(struct irq_data *data); -#else -static inline void irq_move_irq(struct irq_data *data) { } -static inline void irq_move_masked_irq(struct irq_data *data) { } -#endif - -extern int no_irq_affinity; - -#ifdef CONFIG_HARDIRQS_SW_RESEND -int irq_set_parent(int irq, int parent_irq); -#else -static inline int irq_set_parent(int irq, int parent_irq) -{ - return 0; -} -#endif - -/* - * Built-in IRQ handlers for various IRQ types, - * callable via desc->handle_irq() - */ -extern void handle_level_irq(struct irq_desc *desc); -extern void handle_fasteoi_irq(struct irq_desc *desc); -extern void handle_edge_irq(struct irq_desc *desc); -extern void handle_edge_eoi_irq(struct irq_desc *desc); -extern void handle_simple_irq(struct irq_desc *desc); -extern void handle_untracked_irq(struct irq_desc *desc); -extern void handle_percpu_irq(struct irq_desc *desc); -extern void handle_percpu_devid_irq(struct irq_desc *desc); -extern void handle_bad_irq(struct irq_desc *desc); -extern void handle_nested_irq(unsigned int irq); - -extern int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg); -extern int irq_chip_pm_get(struct irq_data *data); -extern int irq_chip_pm_put(struct irq_data *data); -#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY -extern void irq_chip_enable_parent(struct irq_data *data); -extern void irq_chip_disable_parent(struct irq_data *data); -extern void irq_chip_ack_parent(struct irq_data *data); -extern int irq_chip_retrigger_hierarchy(struct irq_data *data); -extern void irq_chip_mask_parent(struct irq_data *data); -extern void irq_chip_unmask_parent(struct irq_data *data); -extern void irq_chip_eoi_parent(struct irq_data *data); -extern int irq_chip_set_affinity_parent(struct irq_data *data, - const struct cpumask *dest, - bool force); -extern int irq_chip_set_wake_parent(struct irq_data *data, unsigned int on); -extern int irq_chip_set_vcpu_affinity_parent(struct irq_data *data, - void *vcpu_info); -extern int irq_chip_set_type_parent(struct irq_data *data, unsigned int type); -#endif - -/* Handling of unhandled and spurious interrupts: */ -extern void note_interrupt(struct irq_desc *desc, irqreturn_t action_ret); - - -/* Enable/disable irq debugging output: */ -extern int noirqdebug_setup(char *str); - -/* Checks whether the interrupt can be requested by request_irq(): */ -extern int can_request_irq(unsigned int irq, unsigned long irqflags); - -/* Dummy irq-chip implementations: */ -extern struct irq_chip no_irq_chip; -extern struct irq_chip dummy_irq_chip; - -extern void -irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, - irq_flow_handler_t handle, const char *name); - -static inline void irq_set_chip_and_handler(unsigned int irq, struct irq_chip *chip, - irq_flow_handler_t handle) -{ - irq_set_chip_and_handler_name(irq, chip, handle, NULL); -} - -extern int irq_set_percpu_devid(unsigned int irq); -extern int irq_set_percpu_devid_partition(unsigned int irq, - const struct cpumask *affinity); -extern int irq_get_percpu_devid_partition(unsigned int irq, - struct cpumask *affinity); - -extern void -__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, - const char *name); - -static inline void -irq_set_handler(unsigned int irq, irq_flow_handler_t handle) -{ - __irq_set_handler(irq, handle, 0, NULL); -} - -/* - * Set a highlevel chained flow handler for a given IRQ. - * (a chained handler is automatically enabled and set to - * IRQ_NOREQUEST, IRQ_NOPROBE, and IRQ_NOTHREAD) - */ -static inline void -irq_set_chained_handler(unsigned int irq, irq_flow_handler_t handle) -{ - __irq_set_handler(irq, handle, 1, NULL); -} - -/* - * Set a highlevel chained flow handler and its data for a given IRQ. - * (a chained handler is automatically enabled and set to - * IRQ_NOREQUEST, IRQ_NOPROBE, and IRQ_NOTHREAD) - */ -void -irq_set_chained_handler_and_data(unsigned int irq, irq_flow_handler_t handle, - void *data); - -void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set); - -static inline void irq_set_status_flags(unsigned int irq, unsigned long set) -{ - irq_modify_status(irq, 0, set); -} - -static inline void irq_clear_status_flags(unsigned int irq, unsigned long clr) -{ - irq_modify_status(irq, clr, 0); -} - -static inline void irq_set_noprobe(unsigned int irq) -{ - irq_modify_status(irq, 0, IRQ_NOPROBE); -} - -static inline void irq_set_probe(unsigned int irq) -{ - irq_modify_status(irq, IRQ_NOPROBE, 0); -} - -static inline void irq_set_nothread(unsigned int irq) -{ - irq_modify_status(irq, 0, IRQ_NOTHREAD); -} - -static inline void irq_set_thread(unsigned int irq) -{ - irq_modify_status(irq, IRQ_NOTHREAD, 0); -} - -static inline void irq_set_nested_thread(unsigned int irq, bool nest) -{ - if (nest) - irq_set_status_flags(irq, IRQ_NESTED_THREAD); - else - irq_clear_status_flags(irq, IRQ_NESTED_THREAD); -} - -static inline void irq_set_percpu_devid_flags(unsigned int irq) -{ - irq_set_status_flags(irq, - IRQ_NOAUTOEN | IRQ_PER_CPU | IRQ_NOTHREAD | - IRQ_NOPROBE | IRQ_PER_CPU_DEVID); -} - -/* Set/get chip/data for an IRQ: */ -extern int irq_set_chip(unsigned int irq, struct irq_chip *chip); -extern int irq_set_handler_data(unsigned int irq, void *data); -extern int irq_set_chip_data(unsigned int irq, void *data); -extern int irq_set_irq_type(unsigned int irq, unsigned int type); -extern int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry); -extern int irq_set_msi_desc_off(unsigned int irq_base, unsigned int irq_offset, - struct msi_desc *entry); -extern struct irq_data *irq_get_irq_data(unsigned int irq); - -static inline struct irq_chip *irq_get_chip(unsigned int irq) -{ - struct irq_data *d = irq_get_irq_data(irq); - return d ? d->chip : NULL; -} - -static inline struct irq_chip *irq_data_get_irq_chip(struct irq_data *d) -{ - return d->chip; -} - -static inline void *irq_get_chip_data(unsigned int irq) -{ - struct irq_data *d = irq_get_irq_data(irq); - return d ? d->chip_data : NULL; -} - -static inline void *irq_data_get_irq_chip_data(struct irq_data *d) -{ - return d->chip_data; -} - -static inline void *irq_get_handler_data(unsigned int irq) -{ - struct irq_data *d = irq_get_irq_data(irq); - return d ? d->common->handler_data : NULL; -} - -static inline void *irq_data_get_irq_handler_data(struct irq_data *d) -{ - return d->common->handler_data; -} - -static inline struct msi_desc *irq_get_msi_desc(unsigned int irq) -{ - struct irq_data *d = irq_get_irq_data(irq); - return d ? d->common->msi_desc : NULL; -} - -static inline struct msi_desc *irq_data_get_msi_desc(struct irq_data *d) -{ - return d->common->msi_desc; -} - -static inline u32 irq_get_trigger_type(unsigned int irq) -{ - struct irq_data *d = irq_get_irq_data(irq); - return d ? irqd_get_trigger_type(d) : 0; -} - -static inline int irq_common_data_get_node(struct irq_common_data *d) -{ -#ifdef CONFIG_NUMA - return d->node; -#else - return 0; -#endif -} - -static inline int irq_data_get_node(struct irq_data *d) -{ - return irq_common_data_get_node(d->common); -} - -static inline struct cpumask *irq_get_affinity_mask(int irq) -{ - struct irq_data *d = irq_get_irq_data(irq); - - return d ? d->common->affinity : NULL; -} - -static inline struct cpumask *irq_data_get_affinity_mask(struct irq_data *d) -{ - return d->common->affinity; -} - -unsigned int arch_dynirq_lower_bound(unsigned int from); - -int __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, - struct module *owner, const struct cpumask *affinity); - -/* use macros to avoid needing export.h for THIS_MODULE */ -#define irq_alloc_descs(irq, from, cnt, node) \ - __irq_alloc_descs(irq, from, cnt, node, THIS_MODULE, NULL) - -#define irq_alloc_desc(node) \ - irq_alloc_descs(-1, 0, 1, node) - -#define irq_alloc_desc_at(at, node) \ - irq_alloc_descs(at, at, 1, node) - -#define irq_alloc_desc_from(from, node) \ - irq_alloc_descs(-1, from, 1, node) - -#define irq_alloc_descs_from(from, cnt, node) \ - irq_alloc_descs(-1, from, cnt, node) - -void irq_free_descs(unsigned int irq, unsigned int cnt); -static inline void irq_free_desc(unsigned int irq) -{ - irq_free_descs(irq, 1); -} - -#ifdef CONFIG_GENERIC_IRQ_LEGACY_ALLOC_HWIRQ -unsigned int irq_alloc_hwirqs(int cnt, int node); -static inline unsigned int irq_alloc_hwirq(int node) -{ - return irq_alloc_hwirqs(1, node); -} -void irq_free_hwirqs(unsigned int from, int cnt); -static inline void irq_free_hwirq(unsigned int irq) -{ - return irq_free_hwirqs(irq, 1); -} -int arch_setup_hwirq(unsigned int irq, int node); -void arch_teardown_hwirq(unsigned int irq); -#endif - -#ifdef CONFIG_GENERIC_IRQ_LEGACY -void irq_init_desc(unsigned int irq); -#endif - -/** - * struct irq_chip_regs - register offsets for struct irq_gci - * @enable: Enable register offset to reg_base - * @disable: Disable register offset to reg_base - * @mask: Mask register offset to reg_base - * @ack: Ack register offset to reg_base - * @eoi: Eoi register offset to reg_base - * @type: Type configuration register offset to reg_base - * @polarity: Polarity configuration register offset to reg_base - */ -struct irq_chip_regs { - unsigned long enable; - unsigned long disable; - unsigned long mask; - unsigned long ack; - unsigned long eoi; - unsigned long type; - unsigned long polarity; -}; - -/** - * struct irq_chip_type - Generic interrupt chip instance for a flow type - * @chip: The real interrupt chip which provides the callbacks - * @regs: Register offsets for this chip - * @handler: Flow handler associated with this chip - * @type: Chip can handle these flow types - * @mask_cache_priv: Cached mask register private to the chip type - * @mask_cache: Pointer to cached mask register - * - * A irq_generic_chip can have several instances of irq_chip_type when - * it requires different functions and register offsets for different - * flow types. - */ -struct irq_chip_type { - struct irq_chip chip; - struct irq_chip_regs regs; - irq_flow_handler_t handler; - u32 type; - u32 mask_cache_priv; - u32 *mask_cache; -}; - -/** - * struct irq_chip_generic - Generic irq chip data structure - * @lock: Lock to protect register and cache data access - * @reg_base: Register base address (virtual) - * @reg_readl: Alternate I/O accessor (defaults to readl if NULL) - * @reg_writel: Alternate I/O accessor (defaults to writel if NULL) - * @suspend: Function called from core code on suspend once per - * chip; can be useful instead of irq_chip::suspend to - * handle chip details even when no interrupts are in use - * @resume: Function called from core code on resume once per chip; - * can be useful instead of irq_chip::suspend to handle - * chip details even when no interrupts are in use - * @irq_base: Interrupt base nr for this chip - * @irq_cnt: Number of interrupts handled by this chip - * @mask_cache: Cached mask register shared between all chip types - * @type_cache: Cached type register - * @polarity_cache: Cached polarity register - * @wake_enabled: Interrupt can wakeup from suspend - * @wake_active: Interrupt is marked as an wakeup from suspend source - * @num_ct: Number of available irq_chip_type instances (usually 1) - * @private: Private data for non generic chip callbacks - * @installed: bitfield to denote installed interrupts - * @unused: bitfield to denote unused interrupts - * @domain: irq domain pointer - * @list: List head for keeping track of instances - * @chip_types: Array of interrupt irq_chip_types - * - * Note, that irq_chip_generic can have multiple irq_chip_type - * implementations which can be associated to a particular irq line of - * an irq_chip_generic instance. That allows to share and protect - * state in an irq_chip_generic instance when we need to implement - * different flow mechanisms (level/edge) for it. - */ -struct irq_chip_generic { - raw_spinlock_t lock; - void __iomem *reg_base; - u32 (*reg_readl)(void __iomem *addr); - void (*reg_writel)(u32 val, void __iomem *addr); - void (*suspend)(struct irq_chip_generic *gc); - void (*resume)(struct irq_chip_generic *gc); - unsigned int irq_base; - unsigned int irq_cnt; - u32 mask_cache; - u32 type_cache; - u32 polarity_cache; - u32 wake_enabled; - u32 wake_active; - unsigned int num_ct; - void *private; - unsigned long installed; - unsigned long unused; - struct irq_domain *domain; - struct list_head list; - struct irq_chip_type chip_types[0]; -}; - -/** - * enum irq_gc_flags - Initialization flags for generic irq chips - * @IRQ_GC_INIT_MASK_CACHE: Initialize the mask_cache by reading mask reg - * @IRQ_GC_INIT_NESTED_LOCK: Set the lock class of the irqs to nested for - * irq chips which need to call irq_set_wake() on - * the parent irq. Usually GPIO implementations - * @IRQ_GC_MASK_CACHE_PER_TYPE: Mask cache is chip type private - * @IRQ_GC_NO_MASK: Do not calculate irq_data->mask - * @IRQ_GC_BE_IO: Use big-endian register accesses (default: LE) - */ -enum irq_gc_flags { - IRQ_GC_INIT_MASK_CACHE = 1 << 0, - IRQ_GC_INIT_NESTED_LOCK = 1 << 1, - IRQ_GC_MASK_CACHE_PER_TYPE = 1 << 2, - IRQ_GC_NO_MASK = 1 << 3, - IRQ_GC_BE_IO = 1 << 4, -}; - -/* - * struct irq_domain_chip_generic - Generic irq chip data structure for irq domains - * @irqs_per_chip: Number of interrupts per chip - * @num_chips: Number of chips - * @irq_flags_to_set: IRQ* flags to set on irq setup - * @irq_flags_to_clear: IRQ* flags to clear on irq setup - * @gc_flags: Generic chip specific setup flags - * @gc: Array of pointers to generic interrupt chips - */ -struct irq_domain_chip_generic { - unsigned int irqs_per_chip; - unsigned int num_chips; - unsigned int irq_flags_to_clear; - unsigned int irq_flags_to_set; - enum irq_gc_flags gc_flags; - struct irq_chip_generic *gc[0]; -}; - -/* Generic chip callback functions */ -void irq_gc_noop(struct irq_data *d); -void irq_gc_mask_disable_reg(struct irq_data *d); -void irq_gc_mask_set_bit(struct irq_data *d); -void irq_gc_mask_clr_bit(struct irq_data *d); -void irq_gc_unmask_enable_reg(struct irq_data *d); -void irq_gc_ack_set_bit(struct irq_data *d); -void irq_gc_ack_clr_bit(struct irq_data *d); -void irq_gc_mask_disable_reg_and_ack(struct irq_data *d); -void irq_gc_eoi(struct irq_data *d); -int irq_gc_set_wake(struct irq_data *d, unsigned int on); - -/* Setup functions for irq_chip_generic */ -int irq_map_generic_chip(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hw_irq); -struct irq_chip_generic * -irq_alloc_generic_chip(const char *name, int nr_ct, unsigned int irq_base, - void __iomem *reg_base, irq_flow_handler_t handler); -void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, - enum irq_gc_flags flags, unsigned int clr, - unsigned int set); -int irq_setup_alt_chip(struct irq_data *d, unsigned int type); -void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk, - unsigned int clr, unsigned int set); - -struct irq_chip_generic *irq_get_domain_generic_chip(struct irq_domain *d, unsigned int hw_irq); - -int __irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip, - int num_ct, const char *name, - irq_flow_handler_t handler, - unsigned int clr, unsigned int set, - enum irq_gc_flags flags); - -#define irq_alloc_domain_generic_chips(d, irqs_per_chip, num_ct, name, \ - handler, clr, set, flags) \ -({ \ - MAYBE_BUILD_BUG_ON(irqs_per_chip > 32); \ - __irq_alloc_domain_generic_chips(d, irqs_per_chip, num_ct, name,\ - handler, clr, set, flags); \ -}) - -static inline struct irq_chip_type *irq_data_get_chip_type(struct irq_data *d) -{ - return container_of(d->chip, struct irq_chip_type, chip); -} - -#define IRQ_MSK(n) (u32)((n) < 32 ? ((1 << (n)) - 1) : UINT_MAX) - -#ifdef CONFIG_SMP -static inline void irq_gc_lock(struct irq_chip_generic *gc) -{ - raw_spin_lock(&gc->lock); -} - -static inline void irq_gc_unlock(struct irq_chip_generic *gc) -{ - raw_spin_unlock(&gc->lock); -} -#else -static inline void irq_gc_lock(struct irq_chip_generic *gc) { } -static inline void irq_gc_unlock(struct irq_chip_generic *gc) { } -#endif - -/* - * The irqsave variants are for usage in non interrupt code. Do not use - * them in irq_chip callbacks. Use irq_gc_lock() instead. - */ -#define irq_gc_lock_irqsave(gc, flags) \ - raw_spin_lock_irqsave(&(gc)->lock, flags) - -#define irq_gc_unlock_irqrestore(gc, flags) \ - raw_spin_unlock_irqrestore(&(gc)->lock, flags) - -static inline void irq_reg_writel(struct irq_chip_generic *gc, - u32 val, int reg_offset) -{ - if (gc->reg_writel) - gc->reg_writel(val, gc->reg_base + reg_offset); - else - writel(val, gc->reg_base + reg_offset); -} - -static inline u32 irq_reg_readl(struct irq_chip_generic *gc, - int reg_offset) -{ - if (gc->reg_readl) - return gc->reg_readl(gc->reg_base + reg_offset); - else - return readl(gc->reg_base + reg_offset); -} - -/* Contrary to Linux irqs, for hardware irqs the irq number 0 is valid */ -#define INVALID_HWIRQ (~0UL) -irq_hw_number_t ipi_get_hwirq(unsigned int irq, unsigned int cpu); -int __ipi_send_single(struct irq_desc *desc, unsigned int cpu); -int __ipi_send_mask(struct irq_desc *desc, const struct cpumask *dest); -int ipi_send_single(unsigned int virq, unsigned int cpu); -int ipi_send_mask(unsigned int virq, const struct cpumask *dest); - -#endif /* _LINUX_IRQ_H */ diff --git a/src/linux/include/linux/irq_cpustat.h b/src/linux/include/linux/irq_cpustat.h deleted file mode 100644 index 77e4bac..0000000 --- a/src/linux/include/linux/irq_cpustat.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef __irq_cpustat_h -#define __irq_cpustat_h - -/* - * Contains default mappings for irq_cpustat_t, used by almost every - * architecture. Some arch (like s390) have per cpu hardware pages and - * they define their own mappings for irq_stat. - * - * Keith Owens July 2000. - */ - - -/* - * Simple wrappers reducing source bloat. Define all irq_stat fields - * here, even ones that are arch dependent. That way we get common - * definitions instead of differing sets for each arch. - */ - -#ifndef __ARCH_IRQ_STAT -extern irq_cpustat_t irq_stat[]; /* defined in asm/hardirq.h */ -#define __IRQ_STAT(cpu, member) (irq_stat[cpu].member) -#endif - - /* arch independent irq_stat fields */ -#define local_softirq_pending() \ - __IRQ_STAT(smp_processor_id(), __softirq_pending) - - /* arch dependent irq_stat fields */ -#define nmi_count(cpu) __IRQ_STAT((cpu), __nmi_count) /* i386 */ - -#endif /* __irq_cpustat_h */ diff --git a/src/linux/include/linux/irq_work.h b/src/linux/include/linux/irq_work.h deleted file mode 100644 index 47b9ebd..0000000 --- a/src/linux/include/linux/irq_work.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef _LINUX_IRQ_WORK_H -#define _LINUX_IRQ_WORK_H - -#include - -/* - * An entry can be in one of four states: - * - * free NULL, 0 -> {claimed} : free to be used - * claimed NULL, 3 -> {pending} : claimed to be enqueued - * pending next, 3 -> {busy} : queued, pending callback - * busy NULL, 2 -> {free, claimed} : callback in progress, can be claimed - */ - -#define IRQ_WORK_PENDING 1UL -#define IRQ_WORK_BUSY 2UL -#define IRQ_WORK_FLAGS 3UL -#define IRQ_WORK_LAZY 4UL /* Doesn't want IPI, wait for tick */ - -struct irq_work { - unsigned long flags; - struct llist_node llnode; - void (*func)(struct irq_work *); -}; - -static inline -void init_irq_work(struct irq_work *work, void (*func)(struct irq_work *)) -{ - work->flags = 0; - work->func = func; -} - -#define DEFINE_IRQ_WORK(name, _f) struct irq_work name = { .func = (_f), } - -bool irq_work_queue(struct irq_work *work); - -#ifdef CONFIG_SMP -bool irq_work_queue_on(struct irq_work *work, int cpu); -#endif - -void irq_work_tick(void); -void irq_work_sync(struct irq_work *work); - -#ifdef CONFIG_IRQ_WORK -#include - -void irq_work_run(void); -bool irq_work_needs_cpu(void); -#else -static inline bool irq_work_needs_cpu(void) { return false; } -static inline void irq_work_run(void) { } -#endif - -#endif /* _LINUX_IRQ_WORK_H */ diff --git a/src/linux/include/linux/irqdesc.h b/src/linux/include/linux/irqdesc.h deleted file mode 100644 index c9be579..0000000 --- a/src/linux/include/linux/irqdesc.h +++ /dev/null @@ -1,260 +0,0 @@ -#ifndef _LINUX_IRQDESC_H -#define _LINUX_IRQDESC_H - -#include -#include - -/* - * Core internal functions to deal with irq descriptors - */ - -struct irq_affinity_notify; -struct proc_dir_entry; -struct module; -struct irq_desc; -struct irq_domain; -struct pt_regs; - -/** - * struct irq_desc - interrupt descriptor - * @irq_common_data: per irq and chip data passed down to chip functions - * @kstat_irqs: irq stats per cpu - * @handle_irq: highlevel irq-events handler - * @preflow_handler: handler called before the flow handler (currently used by sparc) - * @action: the irq action chain - * @status: status information - * @core_internal_state__do_not_mess_with_it: core internal status information - * @depth: disable-depth, for nested irq_disable() calls - * @wake_depth: enable depth, for multiple irq_set_irq_wake() callers - * @irq_count: stats field to detect stalled irqs - * @last_unhandled: aging timer for unhandled count - * @irqs_unhandled: stats field for spurious unhandled interrupts - * @threads_handled: stats field for deferred spurious detection of threaded handlers - * @threads_handled_last: comparator field for deferred spurious detection of theraded handlers - * @lock: locking for SMP - * @affinity_hint: hint to user space for preferred irq affinity - * @affinity_notify: context for notification of affinity changes - * @pending_mask: pending rebalanced interrupts - * @threads_oneshot: bitfield to handle shared oneshot threads - * @threads_active: number of irqaction threads currently running - * @wait_for_threads: wait queue for sync_irq to wait for threaded handlers - * @nr_actions: number of installed actions on this descriptor - * @no_suspend_depth: number of irqactions on a irq descriptor with - * IRQF_NO_SUSPEND set - * @force_resume_depth: number of irqactions on a irq descriptor with - * IRQF_FORCE_RESUME set - * @rcu: rcu head for delayed free - * @kobj: kobject used to represent this struct in sysfs - * @dir: /proc/irq/ procfs entry - * @name: flow handler name for /proc/interrupts output - */ -struct irq_desc { - struct irq_common_data irq_common_data; - struct irq_data irq_data; - unsigned int __percpu *kstat_irqs; - irq_flow_handler_t handle_irq; -#ifdef CONFIG_IRQ_PREFLOW_FASTEOI - irq_preflow_handler_t preflow_handler; -#endif - struct irqaction *action; /* IRQ action list */ - unsigned int status_use_accessors; - unsigned int core_internal_state__do_not_mess_with_it; - unsigned int depth; /* nested irq disables */ - unsigned int wake_depth; /* nested wake enables */ - unsigned int irq_count; /* For detecting broken IRQs */ - unsigned long last_unhandled; /* Aging timer for unhandled count */ - unsigned int irqs_unhandled; - atomic_t threads_handled; - int threads_handled_last; - raw_spinlock_t lock; - struct cpumask *percpu_enabled; - const struct cpumask *percpu_affinity; -#ifdef CONFIG_SMP - const struct cpumask *affinity_hint; - struct irq_affinity_notify *affinity_notify; -#ifdef CONFIG_GENERIC_PENDING_IRQ - cpumask_var_t pending_mask; -#endif -#endif - unsigned long threads_oneshot; - atomic_t threads_active; - wait_queue_head_t wait_for_threads; -#ifdef CONFIG_PM_SLEEP - unsigned int nr_actions; - unsigned int no_suspend_depth; - unsigned int cond_suspend_depth; - unsigned int force_resume_depth; -#endif -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *dir; -#endif -#ifdef CONFIG_SPARSE_IRQ - struct rcu_head rcu; - struct kobject kobj; -#endif - int parent_irq; - struct module *owner; - const char *name; -} ____cacheline_internodealigned_in_smp; - -#ifdef CONFIG_SPARSE_IRQ -extern void irq_lock_sparse(void); -extern void irq_unlock_sparse(void); -#else -static inline void irq_lock_sparse(void) { } -static inline void irq_unlock_sparse(void) { } -extern struct irq_desc irq_desc[NR_IRQS]; -#endif - -static inline struct irq_desc *irq_data_to_desc(struct irq_data *data) -{ - return container_of(data->common, struct irq_desc, irq_common_data); -} - -static inline unsigned int irq_desc_get_irq(struct irq_desc *desc) -{ - return desc->irq_data.irq; -} - -static inline struct irq_data *irq_desc_get_irq_data(struct irq_desc *desc) -{ - return &desc->irq_data; -} - -static inline struct irq_chip *irq_desc_get_chip(struct irq_desc *desc) -{ - return desc->irq_data.chip; -} - -static inline void *irq_desc_get_chip_data(struct irq_desc *desc) -{ - return desc->irq_data.chip_data; -} - -static inline void *irq_desc_get_handler_data(struct irq_desc *desc) -{ - return desc->irq_common_data.handler_data; -} - -static inline struct msi_desc *irq_desc_get_msi_desc(struct irq_desc *desc) -{ - return desc->irq_common_data.msi_desc; -} - -/* - * Architectures call this to let the generic IRQ layer - * handle an interrupt. - */ -static inline void generic_handle_irq_desc(struct irq_desc *desc) -{ - desc->handle_irq(desc); -} - -int generic_handle_irq(unsigned int irq); - -#ifdef CONFIG_HANDLE_DOMAIN_IRQ -/* - * Convert a HW interrupt number to a logical one using a IRQ domain, - * and handle the result interrupt number. Return -EINVAL if - * conversion failed. Providing a NULL domain indicates that the - * conversion has already been done. - */ -int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq, - bool lookup, struct pt_regs *regs); - -static inline int handle_domain_irq(struct irq_domain *domain, - unsigned int hwirq, struct pt_regs *regs) -{ - return __handle_domain_irq(domain, hwirq, true, regs); -} -#endif - -/* Test to see if a driver has successfully requested an irq */ -static inline int irq_desc_has_action(struct irq_desc *desc) -{ - return desc->action != NULL; -} - -static inline int irq_has_action(unsigned int irq) -{ - return irq_desc_has_action(irq_to_desc(irq)); -} - -/** - * irq_set_handler_locked - Set irq handler from a locked region - * @data: Pointer to the irq_data structure which identifies the irq - * @handler: Flow control handler function for this interrupt - * - * Sets the handler in the irq descriptor associated to @data. - * - * Must be called with irq_desc locked and valid parameters. Typical - * call site is the irq_set_type() callback. - */ -static inline void irq_set_handler_locked(struct irq_data *data, - irq_flow_handler_t handler) -{ - struct irq_desc *desc = irq_data_to_desc(data); - - desc->handle_irq = handler; -} - -/** - * irq_set_chip_handler_name_locked - Set chip, handler and name from a locked region - * @data: Pointer to the irq_data structure for which the chip is set - * @chip: Pointer to the new irq chip - * @handler: Flow control handler function for this interrupt - * @name: Name of the interrupt - * - * Replace the irq chip at the proper hierarchy level in @data and - * sets the handler and name in the associated irq descriptor. - * - * Must be called with irq_desc locked and valid parameters. - */ -static inline void -irq_set_chip_handler_name_locked(struct irq_data *data, struct irq_chip *chip, - irq_flow_handler_t handler, const char *name) -{ - struct irq_desc *desc = irq_data_to_desc(data); - - desc->handle_irq = handler; - desc->name = name; - data->chip = chip; -} - -static inline int irq_balancing_disabled(unsigned int irq) -{ - struct irq_desc *desc; - - desc = irq_to_desc(irq); - return desc->status_use_accessors & IRQ_NO_BALANCING_MASK; -} - -static inline int irq_is_percpu(unsigned int irq) -{ - struct irq_desc *desc; - - desc = irq_to_desc(irq); - return desc->status_use_accessors & IRQ_PER_CPU; -} - -static inline void -irq_set_lockdep_class(unsigned int irq, struct lock_class_key *class) -{ - struct irq_desc *desc = irq_to_desc(irq); - - if (desc) - lockdep_set_class(&desc->lock, class); -} - -#ifdef CONFIG_IRQ_PREFLOW_FASTEOI -static inline void -__irq_set_preflow_handler(unsigned int irq, irq_preflow_handler_t handler) -{ - struct irq_desc *desc; - - desc = irq_to_desc(irq); - desc->preflow_handler = handler; -} -#endif - -#endif diff --git a/src/linux/include/linux/irqdomain.h b/src/linux/include/linux/irqdomain.h deleted file mode 100644 index ffb8460..0000000 --- a/src/linux/include/linux/irqdomain.h +++ /dev/null @@ -1,493 +0,0 @@ -/* - * irq_domain - IRQ translation domains - * - * Translation infrastructure between hw and linux irq numbers. This is - * helpful for interrupt controllers to implement mapping between hardware - * irq numbers and the Linux irq number space. - * - * irq_domains also have hooks for translating device tree or other - * firmware interrupt representations into a hardware irq number that - * can be mapped back to a Linux irq number without any extra platform - * support code. - * - * Interrupt controller "domain" data structure. This could be defined as a - * irq domain controller. That is, it handles the mapping between hardware - * and virtual interrupt numbers for a given interrupt domain. The domain - * structure is generally created by the PIC code for a given PIC instance - * (though a domain can cover more than one PIC if they have a flat number - * model). It's the domain callbacks that are responsible for setting the - * irq_chip on a given irq_desc after it's been mapped. - * - * The host code and data structures use a fwnode_handle pointer to - * identify the domain. In some cases, and in order to preserve source - * code compatibility, this fwnode pointer is "upgraded" to a DT - * device_node. For those firmware infrastructures that do not provide - * a unique identifier for an interrupt controller, the irq_domain - * code offers a fwnode allocator. - */ - -#ifndef _LINUX_IRQDOMAIN_H -#define _LINUX_IRQDOMAIN_H - -#include -#include -#include -#include - -struct device_node; -struct irq_domain; -struct of_device_id; -struct irq_chip; -struct irq_data; -struct cpumask; - -/* Number of irqs reserved for a legacy isa controller */ -#define NUM_ISA_INTERRUPTS 16 - -#define IRQ_DOMAIN_IRQ_SPEC_PARAMS 16 - -/** - * struct irq_fwspec - generic IRQ specifier structure - * - * @fwnode: Pointer to a firmware-specific descriptor - * @param_count: Number of device-specific parameters - * @param: Device-specific parameters - * - * This structure, directly modeled after of_phandle_args, is used to - * pass a device-specific description of an interrupt. - */ -struct irq_fwspec { - struct fwnode_handle *fwnode; - int param_count; - u32 param[IRQ_DOMAIN_IRQ_SPEC_PARAMS]; -}; - -/* - * Should several domains have the same device node, but serve - * different purposes (for example one domain is for PCI/MSI, and the - * other for wired IRQs), they can be distinguished using a - * bus-specific token. Most domains are expected to only carry - * DOMAIN_BUS_ANY. - */ -enum irq_domain_bus_token { - DOMAIN_BUS_ANY = 0, - DOMAIN_BUS_WIRED, - DOMAIN_BUS_PCI_MSI, - DOMAIN_BUS_PLATFORM_MSI, - DOMAIN_BUS_NEXUS, - DOMAIN_BUS_IPI, - DOMAIN_BUS_FSL_MC_MSI, -}; - -/** - * struct irq_domain_ops - Methods for irq_domain objects - * @match: Match an interrupt controller device node to a host, returns - * 1 on a match - * @map: Create or update a mapping between a virtual irq number and a hw - * irq number. This is called only once for a given mapping. - * @unmap: Dispose of such a mapping - * @xlate: Given a device tree node and interrupt specifier, decode - * the hardware irq number and linux irq type value. - * - * Functions below are provided by the driver and called whenever a new mapping - * is created or an old mapping is disposed. The driver can then proceed to - * whatever internal data structures management is required. It also needs - * to setup the irq_desc when returning from map(). - */ -struct irq_domain_ops { - int (*match)(struct irq_domain *d, struct device_node *node, - enum irq_domain_bus_token bus_token); - int (*select)(struct irq_domain *d, struct irq_fwspec *fwspec, - enum irq_domain_bus_token bus_token); - int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw); - void (*unmap)(struct irq_domain *d, unsigned int virq); - int (*xlate)(struct irq_domain *d, struct device_node *node, - const u32 *intspec, unsigned int intsize, - unsigned long *out_hwirq, unsigned int *out_type); - -#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY - /* extended V2 interfaces to support hierarchy irq_domains */ - int (*alloc)(struct irq_domain *d, unsigned int virq, - unsigned int nr_irqs, void *arg); - void (*free)(struct irq_domain *d, unsigned int virq, - unsigned int nr_irqs); - void (*activate)(struct irq_domain *d, struct irq_data *irq_data); - void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data); - int (*translate)(struct irq_domain *d, struct irq_fwspec *fwspec, - unsigned long *out_hwirq, unsigned int *out_type); -#endif -}; - -extern struct irq_domain_ops irq_generic_chip_ops; - -struct irq_domain_chip_generic; - -/** - * struct irq_domain - Hardware interrupt number translation object - * @link: Element in global irq_domain list. - * @name: Name of interrupt domain - * @ops: pointer to irq_domain methods - * @host_data: private data pointer for use by owner. Not touched by irq_domain - * core code. - * @flags: host per irq_domain flags - * - * Optional elements - * @of_node: Pointer to device tree nodes associated with the irq_domain. Used - * when decoding device tree interrupt specifiers. - * @gc: Pointer to a list of generic chips. There is a helper function for - * setting up one or more generic chips for interrupt controllers - * drivers using the generic chip library which uses this pointer. - * @parent: Pointer to parent irq_domain to support hierarchy irq_domains - * - * Revmap data, used internally by irq_domain - * @revmap_direct_max_irq: The largest hwirq that can be set for controllers that - * support direct mapping - * @revmap_size: Size of the linear map table @linear_revmap[] - * @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map - * @linear_revmap: Linear table of hwirq->virq reverse mappings - */ -struct irq_domain { - struct list_head link; - const char *name; - const struct irq_domain_ops *ops; - void *host_data; - unsigned int flags; - - /* Optional data */ - struct fwnode_handle *fwnode; - enum irq_domain_bus_token bus_token; - struct irq_domain_chip_generic *gc; -#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY - struct irq_domain *parent; -#endif - - /* reverse map data. The linear map gets appended to the irq_domain */ - irq_hw_number_t hwirq_max; - unsigned int revmap_direct_max_irq; - unsigned int revmap_size; - struct radix_tree_root revmap_tree; - unsigned int linear_revmap[]; -}; - -/* Irq domain flags */ -enum { - /* Irq domain is hierarchical */ - IRQ_DOMAIN_FLAG_HIERARCHY = (1 << 0), - - /* Core calls alloc/free recursive through the domain hierarchy. */ - IRQ_DOMAIN_FLAG_AUTO_RECURSIVE = (1 << 1), - - /* Irq domain is an IPI domain with virq per cpu */ - IRQ_DOMAIN_FLAG_IPI_PER_CPU = (1 << 2), - - /* Irq domain is an IPI domain with single virq */ - IRQ_DOMAIN_FLAG_IPI_SINGLE = (1 << 3), - - /* - * Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved - * for implementation specific purposes and ignored by the - * core code. - */ - IRQ_DOMAIN_FLAG_NONCORE = (1 << 16), -}; - -static inline struct device_node *irq_domain_get_of_node(struct irq_domain *d) -{ - return to_of_node(d->fwnode); -} - -#ifdef CONFIG_IRQ_DOMAIN -struct fwnode_handle *irq_domain_alloc_fwnode(void *data); -void irq_domain_free_fwnode(struct fwnode_handle *fwnode); -struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size, - irq_hw_number_t hwirq_max, int direct_max, - const struct irq_domain_ops *ops, - void *host_data); -struct irq_domain *irq_domain_add_simple(struct device_node *of_node, - unsigned int size, - unsigned int first_irq, - const struct irq_domain_ops *ops, - void *host_data); -struct irq_domain *irq_domain_add_legacy(struct device_node *of_node, - unsigned int size, - unsigned int first_irq, - irq_hw_number_t first_hwirq, - const struct irq_domain_ops *ops, - void *host_data); -extern struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec, - enum irq_domain_bus_token bus_token); -extern void irq_set_default_host(struct irq_domain *host); -extern int irq_domain_alloc_descs(int virq, unsigned int nr_irqs, - irq_hw_number_t hwirq, int node, - const struct cpumask *affinity); - -static inline struct fwnode_handle *of_node_to_fwnode(struct device_node *node) -{ - return node ? &node->fwnode : NULL; -} - -static inline bool is_fwnode_irqchip(struct fwnode_handle *fwnode) -{ - return fwnode && fwnode->type == FWNODE_IRQCHIP; -} - -static inline -struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode, - enum irq_domain_bus_token bus_token) -{ - struct irq_fwspec fwspec = { - .fwnode = fwnode, - }; - - return irq_find_matching_fwspec(&fwspec, bus_token); -} - -static inline struct irq_domain *irq_find_matching_host(struct device_node *node, - enum irq_domain_bus_token bus_token) -{ - return irq_find_matching_fwnode(of_node_to_fwnode(node), bus_token); -} - -static inline struct irq_domain *irq_find_host(struct device_node *node) -{ - return irq_find_matching_host(node, DOMAIN_BUS_ANY); -} - -/** - * irq_domain_add_linear() - Allocate and register a linear revmap irq_domain. - * @of_node: pointer to interrupt controller's device tree node. - * @size: Number of interrupts in the domain. - * @ops: map/unmap domain callbacks - * @host_data: Controller private data pointer - */ -static inline struct irq_domain *irq_domain_add_linear(struct device_node *of_node, - unsigned int size, - const struct irq_domain_ops *ops, - void *host_data) -{ - return __irq_domain_add(of_node_to_fwnode(of_node), size, size, 0, ops, host_data); -} -static inline struct irq_domain *irq_domain_add_nomap(struct device_node *of_node, - unsigned int max_irq, - const struct irq_domain_ops *ops, - void *host_data) -{ - return __irq_domain_add(of_node_to_fwnode(of_node), 0, max_irq, max_irq, ops, host_data); -} -static inline struct irq_domain *irq_domain_add_legacy_isa( - struct device_node *of_node, - const struct irq_domain_ops *ops, - void *host_data) -{ - return irq_domain_add_legacy(of_node, NUM_ISA_INTERRUPTS, 0, 0, ops, - host_data); -} -static inline struct irq_domain *irq_domain_add_tree(struct device_node *of_node, - const struct irq_domain_ops *ops, - void *host_data) -{ - return __irq_domain_add(of_node_to_fwnode(of_node), 0, ~0, 0, ops, host_data); -} - -static inline struct irq_domain *irq_domain_create_linear(struct fwnode_handle *fwnode, - unsigned int size, - const struct irq_domain_ops *ops, - void *host_data) -{ - return __irq_domain_add(fwnode, size, size, 0, ops, host_data); -} - -static inline struct irq_domain *irq_domain_create_tree(struct fwnode_handle *fwnode, - const struct irq_domain_ops *ops, - void *host_data) -{ - return __irq_domain_add(fwnode, 0, ~0, 0, ops, host_data); -} - -extern void irq_domain_remove(struct irq_domain *host); - -extern int irq_domain_associate(struct irq_domain *domain, unsigned int irq, - irq_hw_number_t hwirq); -extern void irq_domain_associate_many(struct irq_domain *domain, - unsigned int irq_base, - irq_hw_number_t hwirq_base, int count); -extern void irq_domain_disassociate(struct irq_domain *domain, - unsigned int irq); - -extern unsigned int irq_create_mapping(struct irq_domain *host, - irq_hw_number_t hwirq); -extern unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec); -extern void irq_dispose_mapping(unsigned int virq); - -/** - * irq_linear_revmap() - Find a linux irq from a hw irq number. - * @domain: domain owning this hardware interrupt - * @hwirq: hardware irq number in that domain space - * - * This is a fast path alternative to irq_find_mapping() that can be - * called directly by irq controller code to save a handful of - * instructions. It is always safe to call, but won't find irqs mapped - * using the radix tree. - */ -static inline unsigned int irq_linear_revmap(struct irq_domain *domain, - irq_hw_number_t hwirq) -{ - return hwirq < domain->revmap_size ? domain->linear_revmap[hwirq] : 0; -} -extern unsigned int irq_find_mapping(struct irq_domain *host, - irq_hw_number_t hwirq); -extern unsigned int irq_create_direct_mapping(struct irq_domain *host); -extern int irq_create_strict_mappings(struct irq_domain *domain, - unsigned int irq_base, - irq_hw_number_t hwirq_base, int count); - -static inline int irq_create_identity_mapping(struct irq_domain *host, - irq_hw_number_t hwirq) -{ - return irq_create_strict_mappings(host, hwirq, hwirq, 1); -} - -extern const struct irq_domain_ops irq_domain_simple_ops; - -/* stock xlate functions */ -int irq_domain_xlate_onecell(struct irq_domain *d, struct device_node *ctrlr, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_type); -int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_type); -int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr, - const u32 *intspec, unsigned int intsize, - irq_hw_number_t *out_hwirq, unsigned int *out_type); - -/* IPI functions */ -int irq_reserve_ipi(struct irq_domain *domain, const struct cpumask *dest); -int irq_destroy_ipi(unsigned int irq, const struct cpumask *dest); - -/* V2 interfaces to support hierarchy IRQ domains. */ -extern struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain, - unsigned int virq); -extern void irq_domain_set_info(struct irq_domain *domain, unsigned int virq, - irq_hw_number_t hwirq, struct irq_chip *chip, - void *chip_data, irq_flow_handler_t handler, - void *handler_data, const char *handler_name); -#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY -extern struct irq_domain *irq_domain_create_hierarchy(struct irq_domain *parent, - unsigned int flags, unsigned int size, - struct fwnode_handle *fwnode, - const struct irq_domain_ops *ops, void *host_data); - -static inline struct irq_domain *irq_domain_add_hierarchy(struct irq_domain *parent, - unsigned int flags, - unsigned int size, - struct device_node *node, - const struct irq_domain_ops *ops, - void *host_data) -{ - return irq_domain_create_hierarchy(parent, flags, size, - of_node_to_fwnode(node), - ops, host_data); -} - -extern int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base, - unsigned int nr_irqs, int node, void *arg, - bool realloc, const struct cpumask *affinity); -extern void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs); -extern void irq_domain_activate_irq(struct irq_data *irq_data); -extern void irq_domain_deactivate_irq(struct irq_data *irq_data); - -static inline int irq_domain_alloc_irqs(struct irq_domain *domain, - unsigned int nr_irqs, int node, void *arg) -{ - return __irq_domain_alloc_irqs(domain, -1, nr_irqs, node, arg, false, - NULL); -} - -extern int irq_domain_alloc_irqs_recursive(struct irq_domain *domain, - unsigned int irq_base, - unsigned int nr_irqs, void *arg); -extern int irq_domain_set_hwirq_and_chip(struct irq_domain *domain, - unsigned int virq, - irq_hw_number_t hwirq, - struct irq_chip *chip, - void *chip_data); -extern void irq_domain_reset_irq_data(struct irq_data *irq_data); -extern void irq_domain_free_irqs_common(struct irq_domain *domain, - unsigned int virq, - unsigned int nr_irqs); -extern void irq_domain_free_irqs_top(struct irq_domain *domain, - unsigned int virq, unsigned int nr_irqs); - -extern int irq_domain_alloc_irqs_parent(struct irq_domain *domain, - unsigned int irq_base, - unsigned int nr_irqs, void *arg); - -extern void irq_domain_free_irqs_parent(struct irq_domain *domain, - unsigned int irq_base, - unsigned int nr_irqs); - -static inline bool irq_domain_is_hierarchy(struct irq_domain *domain) -{ - return domain->flags & IRQ_DOMAIN_FLAG_HIERARCHY; -} - -static inline bool irq_domain_is_ipi(struct irq_domain *domain) -{ - return domain->flags & - (IRQ_DOMAIN_FLAG_IPI_PER_CPU | IRQ_DOMAIN_FLAG_IPI_SINGLE); -} - -static inline bool irq_domain_is_ipi_per_cpu(struct irq_domain *domain) -{ - return domain->flags & IRQ_DOMAIN_FLAG_IPI_PER_CPU; -} - -static inline bool irq_domain_is_ipi_single(struct irq_domain *domain) -{ - return domain->flags & IRQ_DOMAIN_FLAG_IPI_SINGLE; -} -#else /* CONFIG_IRQ_DOMAIN_HIERARCHY */ -static inline void irq_domain_activate_irq(struct irq_data *data) { } -static inline void irq_domain_deactivate_irq(struct irq_data *data) { } -static inline int irq_domain_alloc_irqs(struct irq_domain *domain, - unsigned int nr_irqs, int node, void *arg) -{ - return -1; -} - -static inline void irq_domain_free_irqs(unsigned int virq, - unsigned int nr_irqs) { } - -static inline bool irq_domain_is_hierarchy(struct irq_domain *domain) -{ - return false; -} - -static inline bool irq_domain_is_ipi(struct irq_domain *domain) -{ - return false; -} - -static inline bool irq_domain_is_ipi_per_cpu(struct irq_domain *domain) -{ - return false; -} - -static inline bool irq_domain_is_ipi_single(struct irq_domain *domain) -{ - return false; -} -#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */ - -#else /* CONFIG_IRQ_DOMAIN */ -static inline void irq_dispose_mapping(unsigned int virq) { } -static inline void irq_domain_activate_irq(struct irq_data *data) { } -static inline void irq_domain_deactivate_irq(struct irq_data *data) { } -static inline struct irq_domain *irq_find_matching_fwnode( - struct fwnode_handle *fwnode, enum irq_domain_bus_token bus_token) -{ - return NULL; -} -#endif /* !CONFIG_IRQ_DOMAIN */ - -#endif /* _LINUX_IRQDOMAIN_H */ diff --git a/src/linux/include/linux/irqflags.h b/src/linux/include/linux/irqflags.h deleted file mode 100644 index 5dd1272..0000000 --- a/src/linux/include/linux/irqflags.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * include/linux/irqflags.h - * - * IRQ flags tracing: follow the state of the hardirq and softirq flags and - * provide callbacks for transitions between ON and OFF states. - * - * This file gets included from lowlevel asm headers too, to provide - * wrapped versions of the local_irq_*() APIs, based on the - * raw_local_irq_*() macros from the lowlevel headers. - */ -#ifndef _LINUX_TRACE_IRQFLAGS_H -#define _LINUX_TRACE_IRQFLAGS_H - -#include -#include - -#ifdef CONFIG_TRACE_IRQFLAGS - extern void trace_softirqs_on(unsigned long ip); - extern void trace_softirqs_off(unsigned long ip); - extern void trace_hardirqs_on(void); - extern void trace_hardirqs_off(void); -# define trace_hardirq_context(p) ((p)->hardirq_context) -# define trace_softirq_context(p) ((p)->softirq_context) -# define trace_hardirqs_enabled(p) ((p)->hardirqs_enabled) -# define trace_softirqs_enabled(p) ((p)->softirqs_enabled) -# define trace_hardirq_enter() do { current->hardirq_context++; } while (0) -# define trace_hardirq_exit() do { current->hardirq_context--; } while (0) -# define lockdep_softirq_enter() do { current->softirq_context++; } while (0) -# define lockdep_softirq_exit() do { current->softirq_context--; } while (0) -# define INIT_TRACE_IRQFLAGS .softirqs_enabled = 1, -#else -# define trace_hardirqs_on() do { } while (0) -# define trace_hardirqs_off() do { } while (0) -# define trace_softirqs_on(ip) do { } while (0) -# define trace_softirqs_off(ip) do { } while (0) -# define trace_hardirq_context(p) 0 -# define trace_softirq_context(p) 0 -# define trace_hardirqs_enabled(p) 0 -# define trace_softirqs_enabled(p) 0 -# define trace_hardirq_enter() do { } while (0) -# define trace_hardirq_exit() do { } while (0) -# define lockdep_softirq_enter() do { } while (0) -# define lockdep_softirq_exit() do { } while (0) -# define INIT_TRACE_IRQFLAGS -#endif - -#if defined(CONFIG_IRQSOFF_TRACER) || \ - defined(CONFIG_PREEMPT_TRACER) - extern void stop_critical_timings(void); - extern void start_critical_timings(void); -#else -# define stop_critical_timings() do { } while (0) -# define start_critical_timings() do { } while (0) -#endif - -/* - * Wrap the arch provided IRQ routines to provide appropriate checks. - */ -#define raw_local_irq_disable() arch_local_irq_disable() -#define raw_local_irq_enable() arch_local_irq_enable() -#define raw_local_irq_save(flags) \ - do { \ - typecheck(unsigned long, flags); \ - flags = arch_local_irq_save(); \ - } while (0) -#define raw_local_irq_restore(flags) \ - do { \ - typecheck(unsigned long, flags); \ - arch_local_irq_restore(flags); \ - } while (0) -#define raw_local_save_flags(flags) \ - do { \ - typecheck(unsigned long, flags); \ - flags = arch_local_save_flags(); \ - } while (0) -#define raw_irqs_disabled_flags(flags) \ - ({ \ - typecheck(unsigned long, flags); \ - arch_irqs_disabled_flags(flags); \ - }) -#define raw_irqs_disabled() (arch_irqs_disabled()) -#define raw_safe_halt() arch_safe_halt() - -/* - * The local_irq_*() APIs are equal to the raw_local_irq*() - * if !TRACE_IRQFLAGS. - */ -#ifdef CONFIG_TRACE_IRQFLAGS -#define local_irq_enable() \ - do { trace_hardirqs_on(); raw_local_irq_enable(); } while (0) -#define local_irq_disable() \ - do { raw_local_irq_disable(); trace_hardirqs_off(); } while (0) -#define local_irq_save(flags) \ - do { \ - raw_local_irq_save(flags); \ - trace_hardirqs_off(); \ - } while (0) - - -#define local_irq_restore(flags) \ - do { \ - if (raw_irqs_disabled_flags(flags)) { \ - raw_local_irq_restore(flags); \ - trace_hardirqs_off(); \ - } else { \ - trace_hardirqs_on(); \ - raw_local_irq_restore(flags); \ - } \ - } while (0) - -#define safe_halt() \ - do { \ - trace_hardirqs_on(); \ - raw_safe_halt(); \ - } while (0) - - -#else /* !CONFIG_TRACE_IRQFLAGS */ - -#define local_irq_enable() do { raw_local_irq_enable(); } while (0) -#define local_irq_disable() do { raw_local_irq_disable(); } while (0) -#define local_irq_save(flags) \ - do { \ - raw_local_irq_save(flags); \ - } while (0) -#define local_irq_restore(flags) do { raw_local_irq_restore(flags); } while (0) -#define safe_halt() do { raw_safe_halt(); } while (0) - -#endif /* CONFIG_TRACE_IRQFLAGS */ - -#define local_save_flags(flags) raw_local_save_flags(flags) - -/* - * Some architectures don't define arch_irqs_disabled(), so even if either - * definition would be fine we need to use different ones for the time being - * to avoid build issues. - */ -#ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT -#define irqs_disabled() \ - ({ \ - unsigned long _flags; \ - raw_local_save_flags(_flags); \ - raw_irqs_disabled_flags(_flags); \ - }) -#else /* !CONFIG_TRACE_IRQFLAGS_SUPPORT */ -#define irqs_disabled() raw_irqs_disabled() -#endif /* CONFIG_TRACE_IRQFLAGS_SUPPORT */ - -#define irqs_disabled_flags(flags) raw_irqs_disabled_flags(flags) - -#endif diff --git a/src/linux/include/linux/irqhandler.h b/src/linux/include/linux/irqhandler.h deleted file mode 100644 index 661bed0..0000000 --- a/src/linux/include/linux/irqhandler.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _LINUX_IRQHANDLER_H -#define _LINUX_IRQHANDLER_H - -/* - * Interrupt flow handler typedefs are defined here to avoid circular - * include dependencies. - */ - -struct irq_desc; -struct irq_data; -typedef void (*irq_flow_handler_t)(struct irq_desc *desc); -typedef void (*irq_preflow_handler_t)(struct irq_data *data); - -#endif diff --git a/src/linux/include/linux/irqnr.h b/src/linux/include/linux/irqnr.h deleted file mode 100644 index 9669bf9..0000000 --- a/src/linux/include/linux/irqnr.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef _LINUX_IRQNR_H -#define _LINUX_IRQNR_H - -#include - - -extern int nr_irqs; -extern struct irq_desc *irq_to_desc(unsigned int irq); -unsigned int irq_get_next_irq(unsigned int offset); - -# define for_each_irq_desc(irq, desc) \ - for (irq = 0, desc = irq_to_desc(irq); irq < nr_irqs; \ - irq++, desc = irq_to_desc(irq)) \ - if (!desc) \ - ; \ - else - - -# define for_each_irq_desc_reverse(irq, desc) \ - for (irq = nr_irqs - 1, desc = irq_to_desc(irq); irq >= 0; \ - irq--, desc = irq_to_desc(irq)) \ - if (!desc) \ - ; \ - else - -# define for_each_active_irq(irq) \ - for (irq = irq_get_next_irq(0); irq < nr_irqs; \ - irq = irq_get_next_irq(irq + 1)) - -#define for_each_irq_nr(irq) \ - for (irq = 0; irq < nr_irqs; irq++) - -#endif diff --git a/src/linux/include/linux/irqreturn.h b/src/linux/include/linux/irqreturn.h deleted file mode 100644 index eb1bdcf..0000000 --- a/src/linux/include/linux/irqreturn.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _LINUX_IRQRETURN_H -#define _LINUX_IRQRETURN_H - -/** - * enum irqreturn - * @IRQ_NONE interrupt was not from this device or was not handled - * @IRQ_HANDLED interrupt was handled by this device - * @IRQ_WAKE_THREAD handler requests to wake the handler thread - */ -enum irqreturn { - IRQ_NONE = (0 << 0), - IRQ_HANDLED = (1 << 0), - IRQ_WAKE_THREAD = (1 << 1), -}; - -typedef enum irqreturn irqreturn_t; -#define IRQ_RETVAL(x) ((x) ? IRQ_HANDLED : IRQ_NONE) - -#endif diff --git a/src/linux/include/linux/jbd2.h b/src/linux/include/linux/jbd2.h deleted file mode 100644 index dfaa1f4..0000000 --- a/src/linux/include/linux/jbd2.h +++ /dev/null @@ -1,1536 +0,0 @@ -/* - * linux/include/linux/jbd2.h - * - * Written by Stephen C. Tweedie - * - * Copyright 1998-2000 Red Hat, Inc --- All Rights Reserved - * - * This file is part of the Linux kernel and is made available under - * the terms of the GNU General Public License, version 2, or at your - * option, any later version, incorporated herein by reference. - * - * Definitions for transaction data structures for the buffer cache - * filesystem journaling support. - */ - -#ifndef _LINUX_JBD2_H -#define _LINUX_JBD2_H - -/* Allow this file to be included directly into e2fsprogs */ -#ifndef __KERNEL__ -#include "jfs_compat.h" -#define JBD2_DEBUG -#else - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#define journal_oom_retry 1 - -/* - * Define JBD2_PARANIOD_IOFAIL to cause a kernel BUG() if ext4 finds - * certain classes of error which can occur due to failed IOs. Under - * normal use we want ext4 to continue after such errors, because - * hardware _can_ fail, but for debugging purposes when running tests on - * known-good hardware we may want to trap these errors. - */ -#undef JBD2_PARANOID_IOFAIL - -/* - * The default maximum commit age, in seconds. - */ -#define JBD2_DEFAULT_MAX_COMMIT_AGE 5 - -#ifdef CONFIG_JBD2_DEBUG -/* - * Define JBD2_EXPENSIVE_CHECKING to enable more expensive internal - * consistency checks. By default we don't do this unless - * CONFIG_JBD2_DEBUG is on. - */ -#define JBD2_EXPENSIVE_CHECKING -extern ushort jbd2_journal_enable_debug; -void __jbd2_debug(int level, const char *file, const char *func, - unsigned int line, const char *fmt, ...); - -#define jbd_debug(n, fmt, a...) \ - __jbd2_debug((n), __FILE__, __func__, __LINE__, (fmt), ##a) -#else -#define jbd_debug(n, fmt, a...) /**/ -#endif - -extern void *jbd2_alloc(size_t size, gfp_t flags); -extern void jbd2_free(void *ptr, size_t size); - -#define JBD2_MIN_JOURNAL_BLOCKS 1024 - -#ifdef __KERNEL__ - -/** - * typedef handle_t - The handle_t type represents a single atomic update being performed by some process. - * - * All filesystem modifications made by the process go - * through this handle. Recursive operations (such as quota operations) - * are gathered into a single update. - * - * The buffer credits field is used to account for journaled buffers - * being modified by the running process. To ensure that there is - * enough log space for all outstanding operations, we need to limit the - * number of outstanding buffers possible at any time. When the - * operation completes, any buffer credits not used are credited back to - * the transaction, so that at all times we know how many buffers the - * outstanding updates on a transaction might possibly touch. - * - * This is an opaque datatype. - **/ -typedef struct jbd2_journal_handle handle_t; /* Atomic operation type */ - - -/** - * typedef journal_t - The journal_t maintains all of the journaling state information for a single filesystem. - * - * journal_t is linked to from the fs superblock structure. - * - * We use the journal_t to keep track of all outstanding transaction - * activity on the filesystem, and to manage the state of the log - * writing process. - * - * This is an opaque datatype. - **/ -typedef struct journal_s journal_t; /* Journal control structure */ -#endif - -/* - * Internal structures used by the logging mechanism: - */ - -#define JBD2_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */ - -/* - * On-disk structures - */ - -/* - * Descriptor block types: - */ - -#define JBD2_DESCRIPTOR_BLOCK 1 -#define JBD2_COMMIT_BLOCK 2 -#define JBD2_SUPERBLOCK_V1 3 -#define JBD2_SUPERBLOCK_V2 4 -#define JBD2_REVOKE_BLOCK 5 - -/* - * Standard header for all descriptor blocks: - */ -typedef struct journal_header_s -{ - __be32 h_magic; - __be32 h_blocktype; - __be32 h_sequence; -} journal_header_t; - -/* - * Checksum types. - */ -#define JBD2_CRC32_CHKSUM 1 -#define JBD2_MD5_CHKSUM 2 -#define JBD2_SHA1_CHKSUM 3 -#define JBD2_CRC32C_CHKSUM 4 - -#define JBD2_CRC32_CHKSUM_SIZE 4 - -#define JBD2_CHECKSUM_BYTES (32 / sizeof(u32)) -/* - * Commit block header for storing transactional checksums: - * - * NOTE: If FEATURE_COMPAT_CHECKSUM (checksum v1) is set, the h_chksum* - * fields are used to store a checksum of the descriptor and data blocks. - * - * If FEATURE_INCOMPAT_CSUM_V2 (checksum v2) is set, then the h_chksum - * field is used to store crc32c(uuid+commit_block). Each journal metadata - * block gets its own checksum, and data block checksums are stored in - * journal_block_tag (in the descriptor). The other h_chksum* fields are - * not used. - * - * If FEATURE_INCOMPAT_CSUM_V3 is set, the descriptor block uses - * journal_block_tag3_t to store a full 32-bit checksum. Everything else - * is the same as v2. - * - * Checksum v1, v2, and v3 are mutually exclusive features. - */ -struct commit_header { - __be32 h_magic; - __be32 h_blocktype; - __be32 h_sequence; - unsigned char h_chksum_type; - unsigned char h_chksum_size; - unsigned char h_padding[2]; - __be32 h_chksum[JBD2_CHECKSUM_BYTES]; - __be64 h_commit_sec; - __be32 h_commit_nsec; -}; - -/* - * The block tag: used to describe a single buffer in the journal. - * t_blocknr_high is only used if INCOMPAT_64BIT is set, so this - * raw struct shouldn't be used for pointer math or sizeof() - use - * journal_tag_bytes(journal) instead to compute this. - */ -typedef struct journal_block_tag3_s -{ - __be32 t_blocknr; /* The on-disk block number */ - __be32 t_flags; /* See below */ - __be32 t_blocknr_high; /* most-significant high 32bits. */ - __be32 t_checksum; /* crc32c(uuid+seq+block) */ -} journal_block_tag3_t; - -typedef struct journal_block_tag_s -{ - __be32 t_blocknr; /* The on-disk block number */ - __be16 t_checksum; /* truncated crc32c(uuid+seq+block) */ - __be16 t_flags; /* See below */ - __be32 t_blocknr_high; /* most-significant high 32bits. */ -} journal_block_tag_t; - -/* Tail of descriptor or revoke block, for checksumming */ -struct jbd2_journal_block_tail { - __be32 t_checksum; /* crc32c(uuid+descr_block) */ -}; - -/* - * The revoke descriptor: used on disk to describe a series of blocks to - * be revoked from the log - */ -typedef struct jbd2_journal_revoke_header_s -{ - journal_header_t r_header; - __be32 r_count; /* Count of bytes used in the block */ -} jbd2_journal_revoke_header_t; - -/* Definitions for the journal tag flags word: */ -#define JBD2_FLAG_ESCAPE 1 /* on-disk block is escaped */ -#define JBD2_FLAG_SAME_UUID 2 /* block has same uuid as previous */ -#define JBD2_FLAG_DELETED 4 /* block deleted by this transaction */ -#define JBD2_FLAG_LAST_TAG 8 /* last tag in this descriptor block */ - - -/* - * The journal superblock. All fields are in big-endian byte order. - */ -typedef struct journal_superblock_s -{ -/* 0x0000 */ - journal_header_t s_header; - -/* 0x000C */ - /* Static information describing the journal */ - __be32 s_blocksize; /* journal device blocksize */ - __be32 s_maxlen; /* total blocks in journal file */ - __be32 s_first; /* first block of log information */ - -/* 0x0018 */ - /* Dynamic information describing the current state of the log */ - __be32 s_sequence; /* first commit ID expected in log */ - __be32 s_start; /* blocknr of start of log */ - -/* 0x0020 */ - /* Error value, as set by jbd2_journal_abort(). */ - __be32 s_errno; - -/* 0x0024 */ - /* Remaining fields are only valid in a version-2 superblock */ - __be32 s_feature_compat; /* compatible feature set */ - __be32 s_feature_incompat; /* incompatible feature set */ - __be32 s_feature_ro_compat; /* readonly-compatible feature set */ -/* 0x0030 */ - __u8 s_uuid[16]; /* 128-bit uuid for journal */ - -/* 0x0040 */ - __be32 s_nr_users; /* Nr of filesystems sharing log */ - - __be32 s_dynsuper; /* Blocknr of dynamic superblock copy*/ - -/* 0x0048 */ - __be32 s_max_transaction; /* Limit of journal blocks per trans.*/ - __be32 s_max_trans_data; /* Limit of data blocks per trans. */ - -/* 0x0050 */ - __u8 s_checksum_type; /* checksum type */ - __u8 s_padding2[3]; - __u32 s_padding[42]; - __be32 s_checksum; /* crc32c(superblock) */ - -/* 0x0100 */ - __u8 s_users[16*48]; /* ids of all fs'es sharing the log */ -/* 0x0400 */ -} journal_superblock_t; - -/* Use the jbd2_{has,set,clear}_feature_* helpers; these will be removed */ -#define JBD2_HAS_COMPAT_FEATURE(j,mask) \ - ((j)->j_format_version >= 2 && \ - ((j)->j_superblock->s_feature_compat & cpu_to_be32((mask)))) -#define JBD2_HAS_RO_COMPAT_FEATURE(j,mask) \ - ((j)->j_format_version >= 2 && \ - ((j)->j_superblock->s_feature_ro_compat & cpu_to_be32((mask)))) -#define JBD2_HAS_INCOMPAT_FEATURE(j,mask) \ - ((j)->j_format_version >= 2 && \ - ((j)->j_superblock->s_feature_incompat & cpu_to_be32((mask)))) - -#define JBD2_FEATURE_COMPAT_CHECKSUM 0x00000001 - -#define JBD2_FEATURE_INCOMPAT_REVOKE 0x00000001 -#define JBD2_FEATURE_INCOMPAT_64BIT 0x00000002 -#define JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT 0x00000004 -#define JBD2_FEATURE_INCOMPAT_CSUM_V2 0x00000008 -#define JBD2_FEATURE_INCOMPAT_CSUM_V3 0x00000010 - -/* See "journal feature predicate functions" below */ - -/* Features known to this kernel version: */ -#define JBD2_KNOWN_COMPAT_FEATURES JBD2_FEATURE_COMPAT_CHECKSUM -#define JBD2_KNOWN_ROCOMPAT_FEATURES 0 -#define JBD2_KNOWN_INCOMPAT_FEATURES (JBD2_FEATURE_INCOMPAT_REVOKE | \ - JBD2_FEATURE_INCOMPAT_64BIT | \ - JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT | \ - JBD2_FEATURE_INCOMPAT_CSUM_V2 | \ - JBD2_FEATURE_INCOMPAT_CSUM_V3) - -#ifdef __KERNEL__ - -#include -#include - -enum jbd_state_bits { - BH_JBD /* Has an attached ext3 journal_head */ - = BH_PrivateStart, - BH_JWrite, /* Being written to log (@@@ DEBUGGING) */ - BH_Freed, /* Has been freed (truncated) */ - BH_Revoked, /* Has been revoked from the log */ - BH_RevokeValid, /* Revoked flag is valid */ - BH_JBDDirty, /* Is dirty but journaled */ - BH_State, /* Pins most journal_head state */ - BH_JournalHead, /* Pins bh->b_private and jh->b_bh */ - BH_Shadow, /* IO on shadow buffer is running */ - BH_Verified, /* Metadata block has been verified ok */ - BH_JBDPrivateStart, /* First bit available for private use by FS */ -}; - -BUFFER_FNS(JBD, jbd) -BUFFER_FNS(JWrite, jwrite) -BUFFER_FNS(JBDDirty, jbddirty) -TAS_BUFFER_FNS(JBDDirty, jbddirty) -BUFFER_FNS(Revoked, revoked) -TAS_BUFFER_FNS(Revoked, revoked) -BUFFER_FNS(RevokeValid, revokevalid) -TAS_BUFFER_FNS(RevokeValid, revokevalid) -BUFFER_FNS(Freed, freed) -BUFFER_FNS(Shadow, shadow) -BUFFER_FNS(Verified, verified) - -static inline struct buffer_head *jh2bh(struct journal_head *jh) -{ - return jh->b_bh; -} - -static inline struct journal_head *bh2jh(struct buffer_head *bh) -{ - return bh->b_private; -} - -static inline void jbd_lock_bh_state(struct buffer_head *bh) -{ - bit_spin_lock(BH_State, &bh->b_state); -} - -static inline int jbd_trylock_bh_state(struct buffer_head *bh) -{ - return bit_spin_trylock(BH_State, &bh->b_state); -} - -static inline int jbd_is_locked_bh_state(struct buffer_head *bh) -{ - return bit_spin_is_locked(BH_State, &bh->b_state); -} - -static inline void jbd_unlock_bh_state(struct buffer_head *bh) -{ - bit_spin_unlock(BH_State, &bh->b_state); -} - -static inline void jbd_lock_bh_journal_head(struct buffer_head *bh) -{ - bit_spin_lock(BH_JournalHead, &bh->b_state); -} - -static inline void jbd_unlock_bh_journal_head(struct buffer_head *bh) -{ - bit_spin_unlock(BH_JournalHead, &bh->b_state); -} - -#define J_ASSERT(assert) BUG_ON(!(assert)) - -#define J_ASSERT_BH(bh, expr) J_ASSERT(expr) -#define J_ASSERT_JH(jh, expr) J_ASSERT(expr) - -#if defined(JBD2_PARANOID_IOFAIL) -#define J_EXPECT(expr, why...) J_ASSERT(expr) -#define J_EXPECT_BH(bh, expr, why...) J_ASSERT_BH(bh, expr) -#define J_EXPECT_JH(jh, expr, why...) J_ASSERT_JH(jh, expr) -#else -#define __journal_expect(expr, why...) \ - ({ \ - int val = (expr); \ - if (!val) { \ - printk(KERN_ERR \ - "JBD2 unexpected failure: %s: %s;\n", \ - __func__, #expr); \ - printk(KERN_ERR why "\n"); \ - } \ - val; \ - }) -#define J_EXPECT(expr, why...) __journal_expect(expr, ## why) -#define J_EXPECT_BH(bh, expr, why...) __journal_expect(expr, ## why) -#define J_EXPECT_JH(jh, expr, why...) __journal_expect(expr, ## why) -#endif - -/* Flags in jbd_inode->i_flags */ -#define __JI_COMMIT_RUNNING 0 -#define __JI_WRITE_DATA 1 -#define __JI_WAIT_DATA 2 - -/* - * Commit of the inode data in progress. We use this flag to protect us from - * concurrent deletion of inode. We cannot use reference to inode for this - * since we cannot afford doing last iput() on behalf of kjournald - */ -#define JI_COMMIT_RUNNING (1 << __JI_COMMIT_RUNNING) -/* Write allocated dirty buffers in this inode before commit */ -#define JI_WRITE_DATA (1 << __JI_WRITE_DATA) -/* Wait for outstanding data writes for this inode before commit */ -#define JI_WAIT_DATA (1 << __JI_WAIT_DATA) - -/** - * struct jbd_inode is the structure linking inodes in ordered mode - * present in a transaction so that we can sync them during commit. - */ -struct jbd2_inode { - /* Which transaction does this inode belong to? Either the running - * transaction or the committing one. [j_list_lock] */ - transaction_t *i_transaction; - - /* Pointer to the running transaction modifying inode's data in case - * there is already a committing transaction touching it. [j_list_lock] */ - transaction_t *i_next_transaction; - - /* List of inodes in the i_transaction [j_list_lock] */ - struct list_head i_list; - - /* VFS inode this inode belongs to [constant during the lifetime - * of the structure] */ - struct inode *i_vfs_inode; - - /* Flags of inode [j_list_lock] */ - unsigned long i_flags; -}; - -struct jbd2_revoke_table_s; - -/** - * struct handle_s - The handle_s type is the concrete type associated with - * handle_t. - * @h_transaction: Which compound transaction is this update a part of? - * @h_buffer_credits: Number of remaining buffers we are allowed to dirty. - * @h_ref: Reference count on this handle - * @h_err: Field for caller's use to track errors through large fs operations - * @h_sync: flag for sync-on-close - * @h_jdata: flag to force data journaling - * @h_aborted: flag indicating fatal error on handle - **/ - -/* Docbook can't yet cope with the bit fields, but will leave the documentation - * in so it can be fixed later. - */ - -struct jbd2_journal_handle -{ - union { - /* Which compound transaction is this update a part of? */ - transaction_t *h_transaction; - /* Which journal handle belongs to - used iff h_reserved set */ - journal_t *h_journal; - }; - - /* Handle reserved for finishing the logical operation */ - handle_t *h_rsv_handle; - - /* Number of remaining buffers we are allowed to dirty: */ - int h_buffer_credits; - - /* Reference count on this handle */ - int h_ref; - - /* Field for caller's use to track errors through large fs */ - /* operations */ - int h_err; - - /* Flags [no locking] */ - unsigned int h_sync: 1; /* sync-on-close */ - unsigned int h_jdata: 1; /* force data journaling */ - unsigned int h_reserved: 1; /* handle with reserved credits */ - unsigned int h_aborted: 1; /* fatal error on handle */ - unsigned int h_type: 8; /* for handle statistics */ - unsigned int h_line_no: 16; /* for handle statistics */ - - unsigned long h_start_jiffies; - unsigned int h_requested_credits; -}; - - -/* - * Some stats for checkpoint phase - */ -struct transaction_chp_stats_s { - unsigned long cs_chp_time; - __u32 cs_forced_to_close; - __u32 cs_written; - __u32 cs_dropped; -}; - -/* The transaction_t type is the guts of the journaling mechanism. It - * tracks a compound transaction through its various states: - * - * RUNNING: accepting new updates - * LOCKED: Updates still running but we don't accept new ones - * RUNDOWN: Updates are tidying up but have finished requesting - * new buffers to modify (state not used for now) - * FLUSH: All updates complete, but we are still writing to disk - * COMMIT: All data on disk, writing commit record - * FINISHED: We still have to keep the transaction for checkpointing. - * - * The transaction keeps track of all of the buffers modified by a - * running transaction, and all of the buffers committed but not yet - * flushed to home for finished transactions. - */ - -/* - * Lock ranking: - * - * j_list_lock - * ->jbd_lock_bh_journal_head() (This is "innermost") - * - * j_state_lock - * ->jbd_lock_bh_state() - * - * jbd_lock_bh_state() - * ->j_list_lock - * - * j_state_lock - * ->t_handle_lock - * - * j_state_lock - * ->j_list_lock (journal_unmap_buffer) - * - */ - -struct transaction_s -{ - /* Pointer to the journal for this transaction. [no locking] */ - journal_t *t_journal; - - /* Sequence number for this transaction [no locking] */ - tid_t t_tid; - - /* - * Transaction's current state - * [no locking - only kjournald2 alters this] - * [j_list_lock] guards transition of a transaction into T_FINISHED - * state and subsequent call of __jbd2_journal_drop_transaction() - * FIXME: needs barriers - * KLUDGE: [use j_state_lock] - */ - enum { - T_RUNNING, - T_LOCKED, - T_FLUSH, - T_COMMIT, - T_COMMIT_DFLUSH, - T_COMMIT_JFLUSH, - T_COMMIT_CALLBACK, - T_FINISHED - } t_state; - - /* - * Where in the log does this transaction's commit start? [no locking] - */ - unsigned long t_log_start; - - /* Number of buffers on the t_buffers list [j_list_lock] */ - int t_nr_buffers; - - /* - * Doubly-linked circular list of all buffers reserved but not yet - * modified by this transaction [j_list_lock] - */ - struct journal_head *t_reserved_list; - - /* - * Doubly-linked circular list of all metadata buffers owned by this - * transaction [j_list_lock] - */ - struct journal_head *t_buffers; - - /* - * Doubly-linked circular list of all forget buffers (superseded - * buffers which we can un-checkpoint once this transaction commits) - * [j_list_lock] - */ - struct journal_head *t_forget; - - /* - * Doubly-linked circular list of all buffers still to be flushed before - * this transaction can be checkpointed. [j_list_lock] - */ - struct journal_head *t_checkpoint_list; - - /* - * Doubly-linked circular list of all buffers submitted for IO while - * checkpointing. [j_list_lock] - */ - struct journal_head *t_checkpoint_io_list; - - /* - * Doubly-linked circular list of metadata buffers being shadowed by log - * IO. The IO buffers on the iobuf list and the shadow buffers on this - * list match each other one for one at all times. [j_list_lock] - */ - struct journal_head *t_shadow_list; - - /* - * List of inodes whose data we've modified in data=ordered mode. - * [j_list_lock] - */ - struct list_head t_inode_list; - - /* - * Protects info related to handles - */ - spinlock_t t_handle_lock; - - /* - * Longest time some handle had to wait for running transaction - */ - unsigned long t_max_wait; - - /* - * When transaction started - */ - unsigned long t_start; - - /* - * When commit was requested - */ - unsigned long t_requested; - - /* - * Checkpointing stats [j_checkpoint_sem] - */ - struct transaction_chp_stats_s t_chp_stats; - - /* - * Number of outstanding updates running on this transaction - * [t_handle_lock] - */ - atomic_t t_updates; - - /* - * Number of buffers reserved for use by all handles in this transaction - * handle but not yet modified. [t_handle_lock] - */ - atomic_t t_outstanding_credits; - - /* - * Forward and backward links for the circular list of all transactions - * awaiting checkpoint. [j_list_lock] - */ - transaction_t *t_cpnext, *t_cpprev; - - /* - * When will the transaction expire (become due for commit), in jiffies? - * [no locking] - */ - unsigned long t_expires; - - /* - * When this transaction started, in nanoseconds [no locking] - */ - ktime_t t_start_time; - - /* - * How many handles used this transaction? [t_handle_lock] - */ - atomic_t t_handle_count; - - /* - * This transaction is being forced and some process is - * waiting for it to finish. - */ - unsigned int t_synchronous_commit:1; - - /* Disk flush needs to be sent to fs partition [no locking] */ - int t_need_data_flush; - - /* - * For use by the filesystem to store fs-specific data - * structures associated with the transaction - */ - struct list_head t_private_list; -}; - -struct transaction_run_stats_s { - unsigned long rs_wait; - unsigned long rs_request_delay; - unsigned long rs_running; - unsigned long rs_locked; - unsigned long rs_flushing; - unsigned long rs_logging; - - __u32 rs_handle_count; - __u32 rs_blocks; - __u32 rs_blocks_logged; -}; - -struct transaction_stats_s { - unsigned long ts_tid; - unsigned long ts_requested; - struct transaction_run_stats_s run; -}; - -static inline unsigned long -jbd2_time_diff(unsigned long start, unsigned long end) -{ - if (end >= start) - return end - start; - - return end + (MAX_JIFFY_OFFSET - start); -} - -#define JBD2_NR_BATCH 64 - -/** - * struct journal_s - The journal_s type is the concrete type associated with - * journal_t. - * @j_flags: General journaling state flags - * @j_errno: Is there an outstanding uncleared error on the journal (from a - * prior abort)? - * @j_sb_buffer: First part of superblock buffer - * @j_superblock: Second part of superblock buffer - * @j_format_version: Version of the superblock format - * @j_state_lock: Protect the various scalars in the journal - * @j_barrier_count: Number of processes waiting to create a barrier lock - * @j_barrier: The barrier lock itself - * @j_running_transaction: The current running transaction.. - * @j_committing_transaction: the transaction we are pushing to disk - * @j_checkpoint_transactions: a linked circular list of all transactions - * waiting for checkpointing - * @j_wait_transaction_locked: Wait queue for waiting for a locked transaction - * to start committing, or for a barrier lock to be released - * @j_wait_done_commit: Wait queue for waiting for commit to complete - * @j_wait_commit: Wait queue to trigger commit - * @j_wait_updates: Wait queue to wait for updates to complete - * @j_wait_reserved: Wait queue to wait for reserved buffer credits to drop - * @j_checkpoint_mutex: Mutex for locking against concurrent checkpoints - * @j_head: Journal head - identifies the first unused block in the journal - * @j_tail: Journal tail - identifies the oldest still-used block in the - * journal. - * @j_free: Journal free - how many free blocks are there in the journal? - * @j_first: The block number of the first usable block - * @j_last: The block number one beyond the last usable block - * @j_dev: Device where we store the journal - * @j_blocksize: blocksize for the location where we store the journal. - * @j_blk_offset: starting block offset for into the device where we store the - * journal - * @j_fs_dev: Device which holds the client fs. For internal journal this will - * be equal to j_dev - * @j_reserved_credits: Number of buffers reserved from the running transaction - * @j_maxlen: Total maximum capacity of the journal region on disk. - * @j_list_lock: Protects the buffer lists and internal buffer state. - * @j_inode: Optional inode where we store the journal. If present, all journal - * block numbers are mapped into this inode via bmap(). - * @j_tail_sequence: Sequence number of the oldest transaction in the log - * @j_transaction_sequence: Sequence number of the next transaction to grant - * @j_commit_sequence: Sequence number of the most recently committed - * transaction - * @j_commit_request: Sequence number of the most recent transaction wanting - * commit - * @j_uuid: Uuid of client object. - * @j_task: Pointer to the current commit thread for this journal - * @j_max_transaction_buffers: Maximum number of metadata buffers to allow in a - * single compound commit transaction - * @j_commit_interval: What is the maximum transaction lifetime before we begin - * a commit? - * @j_commit_timer: The timer used to wakeup the commit thread - * @j_revoke_lock: Protect the revoke table - * @j_revoke: The revoke table - maintains the list of revoked blocks in the - * current transaction. - * @j_revoke_table: alternate revoke tables for j_revoke - * @j_wbuf: array of buffer_heads for jbd2_journal_commit_transaction - * @j_wbufsize: maximum number of buffer_heads allowed in j_wbuf, the - * number that will fit in j_blocksize - * @j_last_sync_writer: most recent pid which did a synchronous write - * @j_history_lock: Protect the transactions statistics history - * @j_proc_entry: procfs entry for the jbd statistics directory - * @j_stats: Overall statistics - * @j_private: An opaque pointer to fs-private information. - * @j_trans_commit_map: Lockdep entity to track transaction commit dependencies - */ - -struct journal_s -{ - /* General journaling state flags [j_state_lock] */ - unsigned long j_flags; - - /* - * Is there an outstanding uncleared error on the journal (from a prior - * abort)? [j_state_lock] - */ - int j_errno; - - /* The superblock buffer */ - struct buffer_head *j_sb_buffer; - journal_superblock_t *j_superblock; - - /* Version of the superblock format */ - int j_format_version; - - /* - * Protect the various scalars in the journal - */ - rwlock_t j_state_lock; - - /* - * Number of processes waiting to create a barrier lock [j_state_lock] - */ - int j_barrier_count; - - /* The barrier lock itself */ - struct mutex j_barrier; - - /* - * Transactions: The current running transaction... - * [j_state_lock] [caller holding open handle] - */ - transaction_t *j_running_transaction; - - /* - * the transaction we are pushing to disk - * [j_state_lock] [caller holding open handle] - */ - transaction_t *j_committing_transaction; - - /* - * ... and a linked circular list of all transactions waiting for - * checkpointing. [j_list_lock] - */ - transaction_t *j_checkpoint_transactions; - - /* - * Wait queue for waiting for a locked transaction to start committing, - * or for a barrier lock to be released - */ - wait_queue_head_t j_wait_transaction_locked; - - /* Wait queue for waiting for commit to complete */ - wait_queue_head_t j_wait_done_commit; - - /* Wait queue to trigger commit */ - wait_queue_head_t j_wait_commit; - - /* Wait queue to wait for updates to complete */ - wait_queue_head_t j_wait_updates; - - /* Wait queue to wait for reserved buffer credits to drop */ - wait_queue_head_t j_wait_reserved; - - /* Semaphore for locking against concurrent checkpoints */ - struct mutex j_checkpoint_mutex; - - /* - * List of buffer heads used by the checkpoint routine. This - * was moved from jbd2_log_do_checkpoint() to reduce stack - * usage. Access to this array is controlled by the - * j_checkpoint_mutex. [j_checkpoint_mutex] - */ - struct buffer_head *j_chkpt_bhs[JBD2_NR_BATCH]; - - /* - * Journal head: identifies the first unused block in the journal. - * [j_state_lock] - */ - unsigned long j_head; - - /* - * Journal tail: identifies the oldest still-used block in the journal. - * [j_state_lock] - */ - unsigned long j_tail; - - /* - * Journal free: how many free blocks are there in the journal? - * [j_state_lock] - */ - unsigned long j_free; - - /* - * Journal start and end: the block numbers of the first usable block - * and one beyond the last usable block in the journal. [j_state_lock] - */ - unsigned long j_first; - unsigned long j_last; - - /* - * Device, blocksize and starting block offset for the location where we - * store the journal. - */ - struct block_device *j_dev; - int j_blocksize; - unsigned long long j_blk_offset; - char j_devname[BDEVNAME_SIZE+24]; - - /* - * Device which holds the client fs. For internal journal this will be - * equal to j_dev. - */ - struct block_device *j_fs_dev; - - /* Total maximum capacity of the journal region on disk. */ - unsigned int j_maxlen; - - /* Number of buffers reserved from the running transaction */ - atomic_t j_reserved_credits; - - /* - * Protects the buffer lists and internal buffer state. - */ - spinlock_t j_list_lock; - - /* Optional inode where we store the journal. If present, all */ - /* journal block numbers are mapped into this inode via */ - /* bmap(). */ - struct inode *j_inode; - - /* - * Sequence number of the oldest transaction in the log [j_state_lock] - */ - tid_t j_tail_sequence; - - /* - * Sequence number of the next transaction to grant [j_state_lock] - */ - tid_t j_transaction_sequence; - - /* - * Sequence number of the most recently committed transaction - * [j_state_lock]. - */ - tid_t j_commit_sequence; - - /* - * Sequence number of the most recent transaction wanting commit - * [j_state_lock] - */ - tid_t j_commit_request; - - /* - * Journal uuid: identifies the object (filesystem, LVM volume etc) - * backed by this journal. This will eventually be replaced by an array - * of uuids, allowing us to index multiple devices within a single - * journal and to perform atomic updates across them. - */ - __u8 j_uuid[16]; - - /* Pointer to the current commit thread for this journal */ - struct task_struct *j_task; - - /* - * Maximum number of metadata buffers to allow in a single compound - * commit transaction - */ - int j_max_transaction_buffers; - - /* - * What is the maximum transaction lifetime before we begin a commit? - */ - unsigned long j_commit_interval; - - /* The timer used to wakeup the commit thread: */ - struct timer_list j_commit_timer; - - /* - * The revoke table: maintains the list of revoked blocks in the - * current transaction. [j_revoke_lock] - */ - spinlock_t j_revoke_lock; - struct jbd2_revoke_table_s *j_revoke; - struct jbd2_revoke_table_s *j_revoke_table[2]; - - /* - * array of bhs for jbd2_journal_commit_transaction - */ - struct buffer_head **j_wbuf; - int j_wbufsize; - - /* - * this is the pid of hte last person to run a synchronous operation - * through the journal - */ - pid_t j_last_sync_writer; - - /* - * the average amount of time in nanoseconds it takes to commit a - * transaction to disk. [j_state_lock] - */ - u64 j_average_commit_time; - - /* - * minimum and maximum times that we should wait for - * additional filesystem operations to get batched into a - * synchronous handle in microseconds - */ - u32 j_min_batch_time; - u32 j_max_batch_time; - - /* This function is called when a transaction is closed */ - void (*j_commit_callback)(journal_t *, - transaction_t *); - - /* - * Journal statistics - */ - spinlock_t j_history_lock; - struct proc_dir_entry *j_proc_entry; - struct transaction_stats_s j_stats; - - /* Failed journal commit ID */ - unsigned int j_failed_commit; - - /* - * An opaque pointer to fs-private information. ext3 puts its - * superblock pointer here - */ - void *j_private; - - /* Reference to checksum algorithm driver via cryptoapi */ - struct crypto_shash *j_chksum_driver; - - /* Precomputed journal UUID checksum for seeding other checksums */ - __u32 j_csum_seed; - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - /* - * Lockdep entity to track transaction commit dependencies. Handles - * hold this "lock" for read, when we wait for commit, we acquire the - * "lock" for writing. This matches the properties of jbd2 journalling - * where the running transaction has to wait for all handles to be - * dropped to commit that transaction and also acquiring a handle may - * require transaction commit to finish. - */ - struct lockdep_map j_trans_commit_map; -#endif -}; - -#define jbd2_might_wait_for_commit(j) \ - do { \ - rwsem_acquire(&j->j_trans_commit_map, 0, 0, _THIS_IP_); \ - rwsem_release(&j->j_trans_commit_map, 1, _THIS_IP_); \ - } while (0) - -/* journal feature predicate functions */ -#define JBD2_FEATURE_COMPAT_FUNCS(name, flagname) \ -static inline bool jbd2_has_feature_##name(journal_t *j) \ -{ \ - return ((j)->j_format_version >= 2 && \ - ((j)->j_superblock->s_feature_compat & \ - cpu_to_be32(JBD2_FEATURE_COMPAT_##flagname)) != 0); \ -} \ -static inline void jbd2_set_feature_##name(journal_t *j) \ -{ \ - (j)->j_superblock->s_feature_compat |= \ - cpu_to_be32(JBD2_FEATURE_COMPAT_##flagname); \ -} \ -static inline void jbd2_clear_feature_##name(journal_t *j) \ -{ \ - (j)->j_superblock->s_feature_compat &= \ - ~cpu_to_be32(JBD2_FEATURE_COMPAT_##flagname); \ -} - -#define JBD2_FEATURE_RO_COMPAT_FUNCS(name, flagname) \ -static inline bool jbd2_has_feature_##name(journal_t *j) \ -{ \ - return ((j)->j_format_version >= 2 && \ - ((j)->j_superblock->s_feature_ro_compat & \ - cpu_to_be32(JBD2_FEATURE_RO_COMPAT_##flagname)) != 0); \ -} \ -static inline void jbd2_set_feature_##name(journal_t *j) \ -{ \ - (j)->j_superblock->s_feature_ro_compat |= \ - cpu_to_be32(JBD2_FEATURE_RO_COMPAT_##flagname); \ -} \ -static inline void jbd2_clear_feature_##name(journal_t *j) \ -{ \ - (j)->j_superblock->s_feature_ro_compat &= \ - ~cpu_to_be32(JBD2_FEATURE_RO_COMPAT_##flagname); \ -} - -#define JBD2_FEATURE_INCOMPAT_FUNCS(name, flagname) \ -static inline bool jbd2_has_feature_##name(journal_t *j) \ -{ \ - return ((j)->j_format_version >= 2 && \ - ((j)->j_superblock->s_feature_incompat & \ - cpu_to_be32(JBD2_FEATURE_INCOMPAT_##flagname)) != 0); \ -} \ -static inline void jbd2_set_feature_##name(journal_t *j) \ -{ \ - (j)->j_superblock->s_feature_incompat |= \ - cpu_to_be32(JBD2_FEATURE_INCOMPAT_##flagname); \ -} \ -static inline void jbd2_clear_feature_##name(journal_t *j) \ -{ \ - (j)->j_superblock->s_feature_incompat &= \ - ~cpu_to_be32(JBD2_FEATURE_INCOMPAT_##flagname); \ -} - -JBD2_FEATURE_COMPAT_FUNCS(checksum, CHECKSUM) - -JBD2_FEATURE_INCOMPAT_FUNCS(revoke, REVOKE) -JBD2_FEATURE_INCOMPAT_FUNCS(64bit, 64BIT) -JBD2_FEATURE_INCOMPAT_FUNCS(async_commit, ASYNC_COMMIT) -JBD2_FEATURE_INCOMPAT_FUNCS(csum2, CSUM_V2) -JBD2_FEATURE_INCOMPAT_FUNCS(csum3, CSUM_V3) - -/* - * Journal flag definitions - */ -#define JBD2_UNMOUNT 0x001 /* Journal thread is being destroyed */ -#define JBD2_ABORT 0x002 /* Journaling has been aborted for errors. */ -#define JBD2_ACK_ERR 0x004 /* The errno in the sb has been acked */ -#define JBD2_FLUSHED 0x008 /* The journal superblock has been flushed */ -#define JBD2_LOADED 0x010 /* The journal superblock has been loaded */ -#define JBD2_BARRIER 0x020 /* Use IDE barriers */ -#define JBD2_ABORT_ON_SYNCDATA_ERR 0x040 /* Abort the journal on file - * data write error in ordered - * mode */ -#define JBD2_REC_ERR 0x080 /* The errno in the sb has been recorded */ - -/* - * Function declarations for the journaling transaction and buffer - * management - */ - -/* Filing buffers */ -extern void jbd2_journal_unfile_buffer(journal_t *, struct journal_head *); -extern void __jbd2_journal_refile_buffer(struct journal_head *); -extern void jbd2_journal_refile_buffer(journal_t *, struct journal_head *); -extern void __jbd2_journal_file_buffer(struct journal_head *, transaction_t *, int); -extern void __journal_free_buffer(struct journal_head *bh); -extern void jbd2_journal_file_buffer(struct journal_head *, transaction_t *, int); -extern void __journal_clean_data_list(transaction_t *transaction); -static inline void jbd2_file_log_bh(struct list_head *head, struct buffer_head *bh) -{ - list_add_tail(&bh->b_assoc_buffers, head); -} -static inline void jbd2_unfile_log_bh(struct buffer_head *bh) -{ - list_del_init(&bh->b_assoc_buffers); -} - -/* Log buffer allocation */ -struct buffer_head *jbd2_journal_get_descriptor_buffer(transaction_t *, int); -void jbd2_descriptor_block_csum_set(journal_t *, struct buffer_head *); -int jbd2_journal_next_log_block(journal_t *, unsigned long long *); -int jbd2_journal_get_log_tail(journal_t *journal, tid_t *tid, - unsigned long *block); -int __jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block); -void jbd2_update_log_tail(journal_t *journal, tid_t tid, unsigned long block); - -/* Commit management */ -extern void jbd2_journal_commit_transaction(journal_t *); - -/* Checkpoint list management */ -void __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy); -int __jbd2_journal_remove_checkpoint(struct journal_head *); -void jbd2_journal_destroy_checkpoint(journal_t *journal); -void __jbd2_journal_insert_checkpoint(struct journal_head *, transaction_t *); - - -/* - * Triggers - */ - -struct jbd2_buffer_trigger_type { - /* - * Fired a the moment data to write to the journal are known to be - * stable - so either at the moment b_frozen_data is created or just - * before a buffer is written to the journal. mapped_data is a mapped - * buffer that is the frozen data for commit. - */ - void (*t_frozen)(struct jbd2_buffer_trigger_type *type, - struct buffer_head *bh, void *mapped_data, - size_t size); - - /* - * Fired during journal abort for dirty buffers that will not be - * committed. - */ - void (*t_abort)(struct jbd2_buffer_trigger_type *type, - struct buffer_head *bh); -}; - -extern void jbd2_buffer_frozen_trigger(struct journal_head *jh, - void *mapped_data, - struct jbd2_buffer_trigger_type *triggers); -extern void jbd2_buffer_abort_trigger(struct journal_head *jh, - struct jbd2_buffer_trigger_type *triggers); - -/* Buffer IO */ -extern int jbd2_journal_write_metadata_buffer(transaction_t *transaction, - struct journal_head *jh_in, - struct buffer_head **bh_out, - sector_t blocknr); - -/* Transaction locking */ -extern void __wait_on_journal (journal_t *); - -/* Transaction cache support */ -extern void jbd2_journal_destroy_transaction_cache(void); -extern int jbd2_journal_init_transaction_cache(void); -extern void jbd2_journal_free_transaction(transaction_t *); - -/* - * Journal locking. - * - * We need to lock the journal during transaction state changes so that nobody - * ever tries to take a handle on the running transaction while we are in the - * middle of moving it to the commit phase. j_state_lock does this. - * - * Note that the locking is completely interrupt unsafe. We never touch - * journal structures from interrupts. - */ - -static inline handle_t *journal_current_handle(void) -{ - return current->journal_info; -} - -/* The journaling code user interface: - * - * Create and destroy handles - * Register buffer modifications against the current transaction. - */ - -extern handle_t *jbd2_journal_start(journal_t *, int nblocks); -extern handle_t *jbd2__journal_start(journal_t *, int blocks, int rsv_blocks, - gfp_t gfp_mask, unsigned int type, - unsigned int line_no); -extern int jbd2_journal_restart(handle_t *, int nblocks); -extern int jbd2__journal_restart(handle_t *, int nblocks, gfp_t gfp_mask); -extern int jbd2_journal_start_reserved(handle_t *handle, - unsigned int type, unsigned int line_no); -extern void jbd2_journal_free_reserved(handle_t *handle); -extern int jbd2_journal_extend (handle_t *, int nblocks); -extern int jbd2_journal_get_write_access(handle_t *, struct buffer_head *); -extern int jbd2_journal_get_create_access (handle_t *, struct buffer_head *); -extern int jbd2_journal_get_undo_access(handle_t *, struct buffer_head *); -void jbd2_journal_set_triggers(struct buffer_head *, - struct jbd2_buffer_trigger_type *type); -extern int jbd2_journal_dirty_metadata (handle_t *, struct buffer_head *); -extern int jbd2_journal_forget (handle_t *, struct buffer_head *); -extern void journal_sync_buffer (struct buffer_head *); -extern int jbd2_journal_invalidatepage(journal_t *, - struct page *, unsigned int, unsigned int); -extern int jbd2_journal_try_to_free_buffers(journal_t *, struct page *, gfp_t); -extern int jbd2_journal_stop(handle_t *); -extern int jbd2_journal_flush (journal_t *); -extern void jbd2_journal_lock_updates (journal_t *); -extern void jbd2_journal_unlock_updates (journal_t *); - -extern journal_t * jbd2_journal_init_dev(struct block_device *bdev, - struct block_device *fs_dev, - unsigned long long start, int len, int bsize); -extern journal_t * jbd2_journal_init_inode (struct inode *); -extern int jbd2_journal_update_format (journal_t *); -extern int jbd2_journal_check_used_features - (journal_t *, unsigned long, unsigned long, unsigned long); -extern int jbd2_journal_check_available_features - (journal_t *, unsigned long, unsigned long, unsigned long); -extern int jbd2_journal_set_features - (journal_t *, unsigned long, unsigned long, unsigned long); -extern void jbd2_journal_clear_features - (journal_t *, unsigned long, unsigned long, unsigned long); -extern int jbd2_journal_load (journal_t *journal); -extern int jbd2_journal_destroy (journal_t *); -extern int jbd2_journal_recover (journal_t *journal); -extern int jbd2_journal_wipe (journal_t *, int); -extern int jbd2_journal_skip_recovery (journal_t *); -extern void jbd2_journal_update_sb_errno(journal_t *); -extern int jbd2_journal_update_sb_log_tail (journal_t *, tid_t, - unsigned long, int); -extern void __jbd2_journal_abort_hard (journal_t *); -extern void jbd2_journal_abort (journal_t *, int); -extern int jbd2_journal_errno (journal_t *); -extern void jbd2_journal_ack_err (journal_t *); -extern int jbd2_journal_clear_err (journal_t *); -extern int jbd2_journal_bmap(journal_t *, unsigned long, unsigned long long *); -extern int jbd2_journal_force_commit(journal_t *); -extern int jbd2_journal_force_commit_nested(journal_t *); -extern int jbd2_journal_inode_add_write(handle_t *handle, struct jbd2_inode *inode); -extern int jbd2_journal_inode_add_wait(handle_t *handle, struct jbd2_inode *inode); -extern int jbd2_journal_begin_ordered_truncate(journal_t *journal, - struct jbd2_inode *inode, loff_t new_size); -extern void jbd2_journal_init_jbd_inode(struct jbd2_inode *jinode, struct inode *inode); -extern void jbd2_journal_release_jbd_inode(journal_t *journal, struct jbd2_inode *jinode); - -/* - * journal_head management - */ -struct journal_head *jbd2_journal_add_journal_head(struct buffer_head *bh); -struct journal_head *jbd2_journal_grab_journal_head(struct buffer_head *bh); -void jbd2_journal_put_journal_head(struct journal_head *jh); - -/* - * handle management - */ -extern struct kmem_cache *jbd2_handle_cache; - -static inline handle_t *jbd2_alloc_handle(gfp_t gfp_flags) -{ - return kmem_cache_zalloc(jbd2_handle_cache, gfp_flags); -} - -static inline void jbd2_free_handle(handle_t *handle) -{ - kmem_cache_free(jbd2_handle_cache, handle); -} - -/* - * jbd2_inode management (optional, for those file systems that want to use - * dynamically allocated jbd2_inode structures) - */ -extern struct kmem_cache *jbd2_inode_cache; - -static inline struct jbd2_inode *jbd2_alloc_inode(gfp_t gfp_flags) -{ - return kmem_cache_alloc(jbd2_inode_cache, gfp_flags); -} - -static inline void jbd2_free_inode(struct jbd2_inode *jinode) -{ - kmem_cache_free(jbd2_inode_cache, jinode); -} - -/* Primary revoke support */ -#define JOURNAL_REVOKE_DEFAULT_HASH 256 -extern int jbd2_journal_init_revoke(journal_t *, int); -extern void jbd2_journal_destroy_revoke_caches(void); -extern int jbd2_journal_init_revoke_caches(void); - -extern void jbd2_journal_destroy_revoke(journal_t *); -extern int jbd2_journal_revoke (handle_t *, unsigned long long, struct buffer_head *); -extern int jbd2_journal_cancel_revoke(handle_t *, struct journal_head *); -extern void jbd2_journal_write_revoke_records(transaction_t *transaction, - struct list_head *log_bufs); - -/* Recovery revoke support */ -extern int jbd2_journal_set_revoke(journal_t *, unsigned long long, tid_t); -extern int jbd2_journal_test_revoke(journal_t *, unsigned long long, tid_t); -extern void jbd2_journal_clear_revoke(journal_t *); -extern void jbd2_journal_switch_revoke_table(journal_t *journal); -extern void jbd2_clear_buffer_revoked_flags(journal_t *journal); - -/* - * The log thread user interface: - * - * Request space in the current transaction, and force transaction commit - * transitions on demand. - */ - -int jbd2_log_start_commit(journal_t *journal, tid_t tid); -int __jbd2_log_start_commit(journal_t *journal, tid_t tid); -int jbd2_journal_start_commit(journal_t *journal, tid_t *tid); -int jbd2_log_wait_commit(journal_t *journal, tid_t tid); -int jbd2_complete_transaction(journal_t *journal, tid_t tid); -int jbd2_log_do_checkpoint(journal_t *journal); -int jbd2_trans_will_send_data_barrier(journal_t *journal, tid_t tid); - -void __jbd2_log_wait_for_space(journal_t *journal); -extern void __jbd2_journal_drop_transaction(journal_t *, transaction_t *); -extern int jbd2_cleanup_journal_tail(journal_t *); - -/* - * is_journal_abort - * - * Simple test wrapper function to test the JBD2_ABORT state flag. This - * bit, when set, indicates that we have had a fatal error somewhere, - * either inside the journaling layer or indicated to us by the client - * (eg. ext3), and that we and should not commit any further - * transactions. - */ - -static inline int is_journal_aborted(journal_t *journal) -{ - return journal->j_flags & JBD2_ABORT; -} - -static inline int is_handle_aborted(handle_t *handle) -{ - if (handle->h_aborted || !handle->h_transaction) - return 1; - return is_journal_aborted(handle->h_transaction->t_journal); -} - -static inline void jbd2_journal_abort_handle(handle_t *handle) -{ - handle->h_aborted = 1; -} - -#endif /* __KERNEL__ */ - -/* Comparison functions for transaction IDs: perform comparisons using - * modulo arithmetic so that they work over sequence number wraps. */ - -static inline int tid_gt(tid_t x, tid_t y) -{ - int difference = (x - y); - return (difference > 0); -} - -static inline int tid_geq(tid_t x, tid_t y) -{ - int difference = (x - y); - return (difference >= 0); -} - -extern int jbd2_journal_blocks_per_page(struct inode *inode); -extern size_t journal_tag_bytes(journal_t *journal); - -static inline bool jbd2_journal_has_csum_v2or3_feature(journal_t *j) -{ - return jbd2_has_feature_csum2(j) || jbd2_has_feature_csum3(j); -} - -static inline int jbd2_journal_has_csum_v2or3(journal_t *journal) -{ - WARN_ON_ONCE(jbd2_journal_has_csum_v2or3_feature(journal) && - journal->j_chksum_driver == NULL); - - return journal->j_chksum_driver != NULL; -} - -/* - * We reserve t_outstanding_credits >> JBD2_CONTROL_BLOCKS_SHIFT for - * transaction control blocks. - */ -#define JBD2_CONTROL_BLOCKS_SHIFT 5 - -/* - * Return the minimum number of blocks which must be free in the journal - * before a new transaction may be started. Must be called under j_state_lock. - */ -static inline int jbd2_space_needed(journal_t *journal) -{ - int nblocks = journal->j_max_transaction_buffers; - return nblocks + (nblocks >> JBD2_CONTROL_BLOCKS_SHIFT); -} - -/* - * Return number of free blocks in the log. Must be called under j_state_lock. - */ -static inline unsigned long jbd2_log_space_left(journal_t *journal) -{ - /* Allow for rounding errors */ - unsigned long free = journal->j_free - 32; - - if (journal->j_committing_transaction) { - unsigned long committing = atomic_read(&journal-> - j_committing_transaction->t_outstanding_credits); - - /* Transaction + control blocks */ - free -= committing + (committing >> JBD2_CONTROL_BLOCKS_SHIFT); - } - return free; -} - -/* - * Definitions which augment the buffer_head layer - */ - -/* journaling buffer types */ -#define BJ_None 0 /* Not journaled */ -#define BJ_Metadata 1 /* Normal journaled metadata */ -#define BJ_Forget 2 /* Buffer superseded by this transaction */ -#define BJ_Shadow 3 /* Buffer contents being shadowed to the log */ -#define BJ_Reserved 4 /* Buffer is reserved for access by journal */ -#define BJ_Types 5 - -extern int jbd_blocks_per_page(struct inode *inode); - -/* JBD uses a CRC32 checksum */ -#define JBD_MAX_CHECKSUM_SIZE 4 - -static inline u32 jbd2_chksum(journal_t *journal, u32 crc, - const void *address, unsigned int length) -{ - struct { - struct shash_desc shash; - char ctx[JBD_MAX_CHECKSUM_SIZE]; - } desc; - int err; - - BUG_ON(crypto_shash_descsize(journal->j_chksum_driver) > - JBD_MAX_CHECKSUM_SIZE); - - desc.shash.tfm = journal->j_chksum_driver; - desc.shash.flags = 0; - *(u32 *)desc.ctx = crc; - - err = crypto_shash_update(&desc.shash, address, length); - BUG_ON(err); - - return *(u32 *)desc.ctx; -} - -/* Return most recent uncommitted transaction */ -static inline tid_t jbd2_get_latest_transaction(journal_t *journal) -{ - tid_t tid; - - read_lock(&journal->j_state_lock); - tid = journal->j_commit_request; - if (journal->j_running_transaction) - tid = journal->j_running_transaction->t_tid; - read_unlock(&journal->j_state_lock); - return tid; -} - -#ifdef __KERNEL__ - -#define buffer_trace_init(bh) do {} while (0) -#define print_buffer_fields(bh) do {} while (0) -#define print_buffer_trace(bh) do {} while (0) -#define BUFFER_TRACE(bh, info) do {} while (0) -#define BUFFER_TRACE2(bh, bh2, info) do {} while (0) -#define JBUFFER_TRACE(jh, info) do {} while (0) - -#endif /* __KERNEL__ */ - -#define EFSBADCRC EBADMSG /* Bad CRC detected */ -#define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */ - -#endif /* _LINUX_JBD2_H */ diff --git a/src/linux/include/linux/jhash.h b/src/linux/include/linux/jhash.h deleted file mode 100644 index 348c6f4..0000000 --- a/src/linux/include/linux/jhash.h +++ /dev/null @@ -1,175 +0,0 @@ -#ifndef _LINUX_JHASH_H -#define _LINUX_JHASH_H - -/* jhash.h: Jenkins hash support. - * - * Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net) - * - * http://burtleburtle.net/bob/hash/ - * - * These are the credits from Bob's sources: - * - * lookup3.c, by Bob Jenkins, May 2006, Public Domain. - * - * These are functions for producing 32-bit hashes for hash table lookup. - * hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() - * are externally useful functions. Routines to test the hash are included - * if SELF_TEST is defined. You can use this free for any purpose. It's in - * the public domain. It has no warranty. - * - * Copyright (C) 2009-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu) - * - * I've modified Bob's hash to be useful in the Linux kernel, and - * any bugs present are my fault. - * Jozsef - */ -#include -#include - -/* Best hash sizes are of power of two */ -#define jhash_size(n) ((u32)1<<(n)) -/* Mask the hash value, i.e (value & jhash_mask(n)) instead of (value % n) */ -#define jhash_mask(n) (jhash_size(n)-1) - -/* __jhash_mix -- mix 3 32-bit values reversibly. */ -#define __jhash_mix(a, b, c) \ -{ \ - a -= c; a ^= rol32(c, 4); c += b; \ - b -= a; b ^= rol32(a, 6); a += c; \ - c -= b; c ^= rol32(b, 8); b += a; \ - a -= c; a ^= rol32(c, 16); c += b; \ - b -= a; b ^= rol32(a, 19); a += c; \ - c -= b; c ^= rol32(b, 4); b += a; \ -} - -/* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */ -#define __jhash_final(a, b, c) \ -{ \ - c ^= b; c -= rol32(b, 14); \ - a ^= c; a -= rol32(c, 11); \ - b ^= a; b -= rol32(a, 25); \ - c ^= b; c -= rol32(b, 16); \ - a ^= c; a -= rol32(c, 4); \ - b ^= a; b -= rol32(a, 14); \ - c ^= b; c -= rol32(b, 24); \ -} - -/* An arbitrary initial parameter */ -#define JHASH_INITVAL 0xdeadbeef - -/* jhash - hash an arbitrary key - * @k: sequence of bytes as key - * @length: the length of the key - * @initval: the previous hash, or an arbitray value - * - * The generic version, hashes an arbitrary sequence of bytes. - * No alignment or length assumptions are made about the input key. - * - * Returns the hash value of the key. The result depends on endianness. - */ -static inline u32 jhash(const void *key, u32 length, u32 initval) -{ - u32 a, b, c; - const u8 *k = key; - - /* Set up the internal state */ - a = b = c = JHASH_INITVAL + length + initval; - - /* All but the last block: affect some 32 bits of (a,b,c) */ - while (length > 12) { - a += __get_unaligned_cpu32(k); - b += __get_unaligned_cpu32(k + 4); - c += __get_unaligned_cpu32(k + 8); - __jhash_mix(a, b, c); - length -= 12; - k += 12; - } - /* Last block: affect all 32 bits of (c) */ - /* All the case statements fall through */ - switch (length) { - case 12: c += (u32)k[11]<<24; - case 11: c += (u32)k[10]<<16; - case 10: c += (u32)k[9]<<8; - case 9: c += k[8]; - case 8: b += (u32)k[7]<<24; - case 7: b += (u32)k[6]<<16; - case 6: b += (u32)k[5]<<8; - case 5: b += k[4]; - case 4: a += (u32)k[3]<<24; - case 3: a += (u32)k[2]<<16; - case 2: a += (u32)k[1]<<8; - case 1: a += k[0]; - __jhash_final(a, b, c); - case 0: /* Nothing left to add */ - break; - } - - return c; -} - -/* jhash2 - hash an array of u32's - * @k: the key which must be an array of u32's - * @length: the number of u32's in the key - * @initval: the previous hash, or an arbitray value - * - * Returns the hash value of the key. - */ -static inline u32 jhash2(const u32 *k, u32 length, u32 initval) -{ - u32 a, b, c; - - /* Set up the internal state */ - a = b = c = JHASH_INITVAL + (length<<2) + initval; - - /* Handle most of the key */ - while (length > 3) { - a += k[0]; - b += k[1]; - c += k[2]; - __jhash_mix(a, b, c); - length -= 3; - k += 3; - } - - /* Handle the last 3 u32's: all the case statements fall through */ - switch (length) { - case 3: c += k[2]; - case 2: b += k[1]; - case 1: a += k[0]; - __jhash_final(a, b, c); - case 0: /* Nothing left to add */ - break; - } - - return c; -} - - -/* __jhash_nwords - hash exactly 3, 2 or 1 word(s) */ -static inline u32 __jhash_nwords(u32 a, u32 b, u32 c, u32 initval) -{ - a += initval; - b += initval; - c += initval; - - __jhash_final(a, b, c); - - return c; -} - -static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval) -{ - return __jhash_nwords(a, b, c, initval + JHASH_INITVAL + (3 << 2)); -} - -static inline u32 jhash_2words(u32 a, u32 b, u32 initval) -{ - return __jhash_nwords(a, b, 0, initval + JHASH_INITVAL + (2 << 2)); -} - -static inline u32 jhash_1word(u32 a, u32 initval) -{ - return __jhash_nwords(a, 0, 0, initval + JHASH_INITVAL + (1 << 2)); -} - -#endif /* _LINUX_JHASH_H */ diff --git a/src/linux/include/linux/jiffies.h b/src/linux/include/linux/jiffies.h deleted file mode 100644 index 589d14e..0000000 --- a/src/linux/include/linux/jiffies.h +++ /dev/null @@ -1,453 +0,0 @@ -#ifndef _LINUX_JIFFIES_H -#define _LINUX_JIFFIES_H - -#include -#include -#include -#include -#include -#include /* for HZ */ -#include - -/* - * The following defines establish the engineering parameters of the PLL - * model. The HZ variable establishes the timer interrupt frequency, 100 Hz - * for the SunOS kernel, 256 Hz for the Ultrix kernel and 1024 Hz for the - * OSF/1 kernel. The SHIFT_HZ define expresses the same value as the - * nearest power of two in order to avoid hardware multiply operations. - */ -#if HZ >= 12 && HZ < 24 -# define SHIFT_HZ 4 -#elif HZ >= 24 && HZ < 48 -# define SHIFT_HZ 5 -#elif HZ >= 48 && HZ < 96 -# define SHIFT_HZ 6 -#elif HZ >= 96 && HZ < 192 -# define SHIFT_HZ 7 -#elif HZ >= 192 && HZ < 384 -# define SHIFT_HZ 8 -#elif HZ >= 384 && HZ < 768 -# define SHIFT_HZ 9 -#elif HZ >= 768 && HZ < 1536 -# define SHIFT_HZ 10 -#elif HZ >= 1536 && HZ < 3072 -# define SHIFT_HZ 11 -#elif HZ >= 3072 && HZ < 6144 -# define SHIFT_HZ 12 -#elif HZ >= 6144 && HZ < 12288 -# define SHIFT_HZ 13 -#else -# error Invalid value of HZ. -#endif - -/* Suppose we want to divide two numbers NOM and DEN: NOM/DEN, then we can - * improve accuracy by shifting LSH bits, hence calculating: - * (NOM << LSH) / DEN - * This however means trouble for large NOM, because (NOM << LSH) may no - * longer fit in 32 bits. The following way of calculating this gives us - * some slack, under the following conditions: - * - (NOM / DEN) fits in (32 - LSH) bits. - * - (NOM % DEN) fits in (32 - LSH) bits. - */ -#define SH_DIV(NOM,DEN,LSH) ( (((NOM) / (DEN)) << (LSH)) \ - + ((((NOM) % (DEN)) << (LSH)) + (DEN) / 2) / (DEN)) - -/* LATCH is used in the interval timer and ftape setup. */ -#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */ - -extern int register_refined_jiffies(long clock_tick_rate); - -/* TICK_NSEC is the time between ticks in nsec assuming SHIFTED_HZ */ -#define TICK_NSEC ((NSEC_PER_SEC+HZ/2)/HZ) - -/* TICK_USEC is the time between ticks in usec assuming fake USER_HZ */ -#define TICK_USEC ((1000000UL + USER_HZ/2) / USER_HZ) - -/* some arch's have a small-data section that can be accessed register-relative - * but that can only take up to, say, 4-byte variables. jiffies being part of - * an 8-byte variable may not be correctly accessed unless we force the issue - */ -#define __jiffy_data __attribute__((section(".data"))) - -/* - * The 64-bit value is not atomic - you MUST NOT read it - * without sampling the sequence number in jiffies_lock. - * get_jiffies_64() will do this for you as appropriate. - */ -extern u64 __jiffy_data jiffies_64; -extern unsigned long volatile __jiffy_data jiffies; - -#if (BITS_PER_LONG < 64) -u64 get_jiffies_64(void); -#else -static inline u64 get_jiffies_64(void) -{ - return (u64)jiffies; -} -#endif - -/* - * These inlines deal with timer wrapping correctly. You are - * strongly encouraged to use them - * 1. Because people otherwise forget - * 2. Because if the timer wrap changes in future you won't have to - * alter your driver code. - * - * time_after(a,b) returns true if the time a is after time b. - * - * Do this with "<0" and ">=0" to only test the sign of the result. A - * good compiler would generate better code (and a really good compiler - * wouldn't care). Gcc is currently neither. - */ -#define time_after(a,b) \ - (typecheck(unsigned long, a) && \ - typecheck(unsigned long, b) && \ - ((long)((b) - (a)) < 0)) -#define time_before(a,b) time_after(b,a) - -#define time_after_eq(a,b) \ - (typecheck(unsigned long, a) && \ - typecheck(unsigned long, b) && \ - ((long)((a) - (b)) >= 0)) -#define time_before_eq(a,b) time_after_eq(b,a) - -/* - * Calculate whether a is in the range of [b, c]. - */ -#define time_in_range(a,b,c) \ - (time_after_eq(a,b) && \ - time_before_eq(a,c)) - -/* - * Calculate whether a is in the range of [b, c). - */ -#define time_in_range_open(a,b,c) \ - (time_after_eq(a,b) && \ - time_before(a,c)) - -/* Same as above, but does so with platform independent 64bit types. - * These must be used when utilizing jiffies_64 (i.e. return value of - * get_jiffies_64() */ -#define time_after64(a,b) \ - (typecheck(__u64, a) && \ - typecheck(__u64, b) && \ - ((__s64)((b) - (a)) < 0)) -#define time_before64(a,b) time_after64(b,a) - -#define time_after_eq64(a,b) \ - (typecheck(__u64, a) && \ - typecheck(__u64, b) && \ - ((__s64)((a) - (b)) >= 0)) -#define time_before_eq64(a,b) time_after_eq64(b,a) - -#define time_in_range64(a, b, c) \ - (time_after_eq64(a, b) && \ - time_before_eq64(a, c)) - -/* - * These four macros compare jiffies and 'a' for convenience. - */ - -/* time_is_before_jiffies(a) return true if a is before jiffies */ -#define time_is_before_jiffies(a) time_after(jiffies, a) -#define time_is_before_jiffies64(a) time_after64(get_jiffies_64(), a) - -/* time_is_after_jiffies(a) return true if a is after jiffies */ -#define time_is_after_jiffies(a) time_before(jiffies, a) -#define time_is_after_jiffies64(a) time_before64(get_jiffies_64(), a) - -/* time_is_before_eq_jiffies(a) return true if a is before or equal to jiffies*/ -#define time_is_before_eq_jiffies(a) time_after_eq(jiffies, a) -#define time_is_before_eq_jiffies64(a) time_after_eq64(get_jiffies_64(), a) - -/* time_is_after_eq_jiffies(a) return true if a is after or equal to jiffies*/ -#define time_is_after_eq_jiffies(a) time_before_eq(jiffies, a) -#define time_is_after_eq_jiffies64(a) time_before_eq64(get_jiffies_64(), a) - -/* - * Have the 32 bit jiffies value wrap 5 minutes after boot - * so jiffies wrap bugs show up earlier. - */ -#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) - -/* - * Change timeval to jiffies, trying to avoid the - * most obvious overflows.. - * - * And some not so obvious. - * - * Note that we don't want to return LONG_MAX, because - * for various timeout reasons we often end up having - * to wait "jiffies+1" in order to guarantee that we wait - * at _least_ "jiffies" - so "jiffies+1" had better still - * be positive. - */ -#define MAX_JIFFY_OFFSET ((LONG_MAX >> 1)-1) - -extern unsigned long preset_lpj; - -/* - * We want to do realistic conversions of time so we need to use the same - * values the update wall clock code uses as the jiffies size. This value - * is: TICK_NSEC (which is defined in timex.h). This - * is a constant and is in nanoseconds. We will use scaled math - * with a set of scales defined here as SEC_JIFFIE_SC, USEC_JIFFIE_SC and - * NSEC_JIFFIE_SC. Note that these defines contain nothing but - * constants and so are computed at compile time. SHIFT_HZ (computed in - * timex.h) adjusts the scaling for different HZ values. - - * Scaled math??? What is that? - * - * Scaled math is a way to do integer math on values that would, - * otherwise, either overflow, underflow, or cause undesired div - * instructions to appear in the execution path. In short, we "scale" - * up the operands so they take more bits (more precision, less - * underflow), do the desired operation and then "scale" the result back - * by the same amount. If we do the scaling by shifting we avoid the - * costly mpy and the dastardly div instructions. - - * Suppose, for example, we want to convert from seconds to jiffies - * where jiffies is defined in nanoseconds as NSEC_PER_JIFFIE. The - * simple math is: jiff = (sec * NSEC_PER_SEC) / NSEC_PER_JIFFIE; We - * observe that (NSEC_PER_SEC / NSEC_PER_JIFFIE) is a constant which we - * might calculate at compile time, however, the result will only have - * about 3-4 bits of precision (less for smaller values of HZ). - * - * So, we scale as follows: - * jiff = (sec) * (NSEC_PER_SEC / NSEC_PER_JIFFIE); - * jiff = ((sec) * ((NSEC_PER_SEC * SCALE)/ NSEC_PER_JIFFIE)) / SCALE; - * Then we make SCALE a power of two so: - * jiff = ((sec) * ((NSEC_PER_SEC << SCALE)/ NSEC_PER_JIFFIE)) >> SCALE; - * Now we define: - * #define SEC_CONV = ((NSEC_PER_SEC << SCALE)/ NSEC_PER_JIFFIE)) - * jiff = (sec * SEC_CONV) >> SCALE; - * - * Often the math we use will expand beyond 32-bits so we tell C how to - * do this and pass the 64-bit result of the mpy through the ">> SCALE" - * which should take the result back to 32-bits. We want this expansion - * to capture as much precision as possible. At the same time we don't - * want to overflow so we pick the SCALE to avoid this. In this file, - * that means using a different scale for each range of HZ values (as - * defined in timex.h). - * - * For those who want to know, gcc will give a 64-bit result from a "*" - * operator if the result is a long long AND at least one of the - * operands is cast to long long (usually just prior to the "*" so as - * not to confuse it into thinking it really has a 64-bit operand, - * which, buy the way, it can do, but it takes more code and at least 2 - * mpys). - - * We also need to be aware that one second in nanoseconds is only a - * couple of bits away from overflowing a 32-bit word, so we MUST use - * 64-bits to get the full range time in nanoseconds. - - */ - -/* - * Here are the scales we will use. One for seconds, nanoseconds and - * microseconds. - * - * Within the limits of cpp we do a rough cut at the SEC_JIFFIE_SC and - * check if the sign bit is set. If not, we bump the shift count by 1. - * (Gets an extra bit of precision where we can use it.) - * We know it is set for HZ = 1024 and HZ = 100 not for 1000. - * Haven't tested others. - - * Limits of cpp (for #if expressions) only long (no long long), but - * then we only need the most signicant bit. - */ - -#define SEC_JIFFIE_SC (31 - SHIFT_HZ) -#if !((((NSEC_PER_SEC << 2) / TICK_NSEC) << (SEC_JIFFIE_SC - 2)) & 0x80000000) -#undef SEC_JIFFIE_SC -#define SEC_JIFFIE_SC (32 - SHIFT_HZ) -#endif -#define NSEC_JIFFIE_SC (SEC_JIFFIE_SC + 29) -#define SEC_CONVERSION ((unsigned long)((((u64)NSEC_PER_SEC << SEC_JIFFIE_SC) +\ - TICK_NSEC -1) / (u64)TICK_NSEC)) - -#define NSEC_CONVERSION ((unsigned long)((((u64)1 << NSEC_JIFFIE_SC) +\ - TICK_NSEC -1) / (u64)TICK_NSEC)) -/* - * The maximum jiffie value is (MAX_INT >> 1). Here we translate that - * into seconds. The 64-bit case will overflow if we are not careful, - * so use the messy SH_DIV macro to do it. Still all constants. - */ -#if BITS_PER_LONG < 64 -# define MAX_SEC_IN_JIFFIES \ - (long)((u64)((u64)MAX_JIFFY_OFFSET * TICK_NSEC) / NSEC_PER_SEC) -#else /* take care of overflow on 64 bits machines */ -# define MAX_SEC_IN_JIFFIES \ - (SH_DIV((MAX_JIFFY_OFFSET >> SEC_JIFFIE_SC) * TICK_NSEC, NSEC_PER_SEC, 1) - 1) - -#endif - -/* - * Convert various time units to each other: - */ -extern unsigned int jiffies_to_msecs(const unsigned long j); -extern unsigned int jiffies_to_usecs(const unsigned long j); - -static inline u64 jiffies_to_nsecs(const unsigned long j) -{ - return (u64)jiffies_to_usecs(j) * NSEC_PER_USEC; -} - -extern unsigned long __msecs_to_jiffies(const unsigned int m); -#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ) -/* - * HZ is equal to or smaller than 1000, and 1000 is a nice round - * multiple of HZ, divide with the factor between them, but round - * upwards: - */ -static inline unsigned long _msecs_to_jiffies(const unsigned int m) -{ - return (m + (MSEC_PER_SEC / HZ) - 1) / (MSEC_PER_SEC / HZ); -} -#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC) -/* - * HZ is larger than 1000, and HZ is a nice round multiple of 1000 - - * simply multiply with the factor between them. - * - * But first make sure the multiplication result cannot overflow: - */ -static inline unsigned long _msecs_to_jiffies(const unsigned int m) -{ - if (m > jiffies_to_msecs(MAX_JIFFY_OFFSET)) - return MAX_JIFFY_OFFSET; - return m * (HZ / MSEC_PER_SEC); -} -#else -/* - * Generic case - multiply, round and divide. But first check that if - * we are doing a net multiplication, that we wouldn't overflow: - */ -static inline unsigned long _msecs_to_jiffies(const unsigned int m) -{ - if (HZ > MSEC_PER_SEC && m > jiffies_to_msecs(MAX_JIFFY_OFFSET)) - return MAX_JIFFY_OFFSET; - - return (MSEC_TO_HZ_MUL32 * m + MSEC_TO_HZ_ADJ32) >> MSEC_TO_HZ_SHR32; -} -#endif -/** - * msecs_to_jiffies: - convert milliseconds to jiffies - * @m: time in milliseconds - * - * conversion is done as follows: - * - * - negative values mean 'infinite timeout' (MAX_JIFFY_OFFSET) - * - * - 'too large' values [that would result in larger than - * MAX_JIFFY_OFFSET values] mean 'infinite timeout' too. - * - * - all other values are converted to jiffies by either multiplying - * the input value by a factor or dividing it with a factor and - * handling any 32-bit overflows. - * for the details see __msecs_to_jiffies() - * - * msecs_to_jiffies() checks for the passed in value being a constant - * via __builtin_constant_p() allowing gcc to eliminate most of the - * code, __msecs_to_jiffies() is called if the value passed does not - * allow constant folding and the actual conversion must be done at - * runtime. - * the HZ range specific helpers _msecs_to_jiffies() are called both - * directly here and from __msecs_to_jiffies() in the case where - * constant folding is not possible. - */ -static __always_inline unsigned long msecs_to_jiffies(const unsigned int m) -{ - if (__builtin_constant_p(m)) { - if ((int)m < 0) - return MAX_JIFFY_OFFSET; - return _msecs_to_jiffies(m); - } else { - return __msecs_to_jiffies(m); - } -} - -extern unsigned long __usecs_to_jiffies(const unsigned int u); -#if !(USEC_PER_SEC % HZ) -static inline unsigned long _usecs_to_jiffies(const unsigned int u) -{ - return (u + (USEC_PER_SEC / HZ) - 1) / (USEC_PER_SEC / HZ); -} -#else -static inline unsigned long _usecs_to_jiffies(const unsigned int u) -{ - return (USEC_TO_HZ_MUL32 * u + USEC_TO_HZ_ADJ32) - >> USEC_TO_HZ_SHR32; -} -#endif - -/** - * usecs_to_jiffies: - convert microseconds to jiffies - * @u: time in microseconds - * - * conversion is done as follows: - * - * - 'too large' values [that would result in larger than - * MAX_JIFFY_OFFSET values] mean 'infinite timeout' too. - * - * - all other values are converted to jiffies by either multiplying - * the input value by a factor or dividing it with a factor and - * handling any 32-bit overflows as for msecs_to_jiffies. - * - * usecs_to_jiffies() checks for the passed in value being a constant - * via __builtin_constant_p() allowing gcc to eliminate most of the - * code, __usecs_to_jiffies() is called if the value passed does not - * allow constant folding and the actual conversion must be done at - * runtime. - * the HZ range specific helpers _usecs_to_jiffies() are called both - * directly here and from __msecs_to_jiffies() in the case where - * constant folding is not possible. - */ -static __always_inline unsigned long usecs_to_jiffies(const unsigned int u) -{ - if (__builtin_constant_p(u)) { - if (u > jiffies_to_usecs(MAX_JIFFY_OFFSET)) - return MAX_JIFFY_OFFSET; - return _usecs_to_jiffies(u); - } else { - return __usecs_to_jiffies(u); - } -} - -extern unsigned long timespec64_to_jiffies(const struct timespec64 *value); -extern void jiffies_to_timespec64(const unsigned long jiffies, - struct timespec64 *value); -static inline unsigned long timespec_to_jiffies(const struct timespec *value) -{ - struct timespec64 ts = timespec_to_timespec64(*value); - - return timespec64_to_jiffies(&ts); -} - -static inline void jiffies_to_timespec(const unsigned long jiffies, - struct timespec *value) -{ - struct timespec64 ts; - - jiffies_to_timespec64(jiffies, &ts); - *value = timespec64_to_timespec(ts); -} - -extern unsigned long timeval_to_jiffies(const struct timeval *value); -extern void jiffies_to_timeval(const unsigned long jiffies, - struct timeval *value); - -extern clock_t jiffies_to_clock_t(unsigned long x); -static inline clock_t jiffies_delta_to_clock_t(long delta) -{ - return jiffies_to_clock_t(max(0L, delta)); -} - -extern unsigned long clock_t_to_jiffies(unsigned long x); -extern u64 jiffies_64_to_clock_t(u64 x); -extern u64 nsec_to_clock_t(u64 x); -extern u64 nsecs_to_jiffies64(u64 n); -extern unsigned long nsecs_to_jiffies(u64 n); - -#define TIMESTAMP_SIZE 30 - -#endif diff --git a/src/linux/include/linux/journal-head.h b/src/linux/include/linux/journal-head.h deleted file mode 100644 index 98cd41b..0000000 --- a/src/linux/include/linux/journal-head.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * include/linux/journal-head.h - * - * buffer_head fields for JBD - * - * 27 May 2001 Andrew Morton - * Created - pulled out of fs.h - */ - -#ifndef JOURNAL_HEAD_H_INCLUDED -#define JOURNAL_HEAD_H_INCLUDED - -typedef unsigned int tid_t; /* Unique transaction ID */ -typedef struct transaction_s transaction_t; /* Compound transaction type */ - - -struct buffer_head; - -struct journal_head { - /* - * Points back to our buffer_head. [jbd_lock_bh_journal_head()] - */ - struct buffer_head *b_bh; - - /* - * Reference count - see description in journal.c - * [jbd_lock_bh_journal_head()] - */ - int b_jcount; - - /* - * Journalling list for this buffer [jbd_lock_bh_state()] - * NOTE: We *cannot* combine this with b_modified into a bitfield - * as gcc would then (which the C standard allows but which is - * very unuseful) make 64-bit accesses to the bitfield and clobber - * b_jcount if its update races with bitfield modification. - */ - unsigned b_jlist; - - /* - * This flag signals the buffer has been modified by - * the currently running transaction - * [jbd_lock_bh_state()] - */ - unsigned b_modified; - - /* - * Copy of the buffer data frozen for writing to the log. - * [jbd_lock_bh_state()] - */ - char *b_frozen_data; - - /* - * Pointer to a saved copy of the buffer containing no uncommitted - * deallocation references, so that allocations can avoid overwriting - * uncommitted deletes. [jbd_lock_bh_state()] - */ - char *b_committed_data; - - /* - * Pointer to the compound transaction which owns this buffer's - * metadata: either the running transaction or the committing - * transaction (if there is one). Only applies to buffers on a - * transaction's data or metadata journaling list. - * [j_list_lock] [jbd_lock_bh_state()] - * Either of these locks is enough for reading, both are needed for - * changes. - */ - transaction_t *b_transaction; - - /* - * Pointer to the running compound transaction which is currently - * modifying the buffer's metadata, if there was already a transaction - * committing it when the new transaction touched it. - * [t_list_lock] [jbd_lock_bh_state()] - */ - transaction_t *b_next_transaction; - - /* - * Doubly-linked list of buffers on a transaction's data, metadata or - * forget queue. [t_list_lock] [jbd_lock_bh_state()] - */ - struct journal_head *b_tnext, *b_tprev; - - /* - * Pointer to the compound transaction against which this buffer - * is checkpointed. Only dirty buffers can be checkpointed. - * [j_list_lock] - */ - transaction_t *b_cp_transaction; - - /* - * Doubly-linked list of buffers still remaining to be flushed - * before an old transaction can be checkpointed. - * [j_list_lock] - */ - struct journal_head *b_cpnext, *b_cpprev; - - /* Trigger type */ - struct jbd2_buffer_trigger_type *b_triggers; - - /* Trigger type for the committing transaction's frozen data */ - struct jbd2_buffer_trigger_type *b_frozen_triggers; -}; - -#endif /* JOURNAL_HEAD_H_INCLUDED */ diff --git a/src/linux/include/linux/jump_label.h b/src/linux/include/linux/jump_label.h deleted file mode 100644 index a0547c5..0000000 --- a/src/linux/include/linux/jump_label.h +++ /dev/null @@ -1,407 +0,0 @@ -#ifndef _LINUX_JUMP_LABEL_H -#define _LINUX_JUMP_LABEL_H - -/* - * Jump label support - * - * Copyright (C) 2009-2012 Jason Baron - * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra - * - * DEPRECATED API: - * - * The use of 'struct static_key' directly, is now DEPRECATED. In addition - * static_key_{true,false}() is also DEPRECATED. IE DO NOT use the following: - * - * struct static_key false = STATIC_KEY_INIT_FALSE; - * struct static_key true = STATIC_KEY_INIT_TRUE; - * static_key_true() - * static_key_false() - * - * The updated API replacements are: - * - * DEFINE_STATIC_KEY_TRUE(key); - * DEFINE_STATIC_KEY_FALSE(key); - * DEFINE_STATIC_KEY_ARRAY_TRUE(keys, count); - * DEFINE_STATIC_KEY_ARRAY_FALSE(keys, count); - * static_branch_likely() - * static_branch_unlikely() - * - * Jump labels provide an interface to generate dynamic branches using - * self-modifying code. Assuming toolchain and architecture support, if we - * define a "key" that is initially false via "DEFINE_STATIC_KEY_FALSE(key)", - * an "if (static_branch_unlikely(&key))" statement is an unconditional branch - * (which defaults to false - and the true block is placed out of line). - * Similarly, we can define an initially true key via - * "DEFINE_STATIC_KEY_TRUE(key)", and use it in the same - * "if (static_branch_unlikely(&key))", in which case we will generate an - * unconditional branch to the out-of-line true branch. Keys that are - * initially true or false can be using in both static_branch_unlikely() - * and static_branch_likely() statements. - * - * At runtime we can change the branch target by setting the key - * to true via a call to static_branch_enable(), or false using - * static_branch_disable(). If the direction of the branch is switched by - * these calls then we run-time modify the branch target via a - * no-op -> jump or jump -> no-op conversion. For example, for an - * initially false key that is used in an "if (static_branch_unlikely(&key))" - * statement, setting the key to true requires us to patch in a jump - * to the out-of-line of true branch. - * - * In addition to static_branch_{enable,disable}, we can also reference count - * the key or branch direction via static_branch_{inc,dec}. Thus, - * static_branch_inc() can be thought of as a 'make more true' and - * static_branch_dec() as a 'make more false'. - * - * Since this relies on modifying code, the branch modifying functions - * must be considered absolute slow paths (machine wide synchronization etc.). - * OTOH, since the affected branches are unconditional, their runtime overhead - * will be absolutely minimal, esp. in the default (off) case where the total - * effect is a single NOP of appropriate size. The on case will patch in a jump - * to the out-of-line block. - * - * When the control is directly exposed to userspace, it is prudent to delay the - * decrement to avoid high frequency code modifications which can (and do) - * cause significant performance degradation. Struct static_key_deferred and - * static_key_slow_dec_deferred() provide for this. - * - * Lacking toolchain and or architecture support, static keys fall back to a - * simple conditional branch. - * - * Additional babbling in: Documentation/static-keys.txt - */ - -#if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_JUMP_LABEL) -# define HAVE_JUMP_LABEL -#endif - -#ifndef __ASSEMBLY__ - -#include -#include - -extern bool static_key_initialized; - -#define STATIC_KEY_CHECK_USE() WARN(!static_key_initialized, \ - "%s used before call to jump_label_init", \ - __func__) - -#ifdef HAVE_JUMP_LABEL - -struct static_key { - atomic_t enabled; -/* Set lsb bit to 1 if branch is default true, 0 ot */ - struct jump_entry *entries; -#ifdef CONFIG_MODULES - struct static_key_mod *next; -#endif -}; - -#else -struct static_key { - atomic_t enabled; -}; -#endif /* HAVE_JUMP_LABEL */ -#endif /* __ASSEMBLY__ */ - -#ifdef HAVE_JUMP_LABEL -#include -#endif - -#ifndef __ASSEMBLY__ - -enum jump_label_type { - JUMP_LABEL_NOP = 0, - JUMP_LABEL_JMP, -}; - -struct module; - -#ifdef HAVE_JUMP_LABEL - -#define JUMP_TYPE_FALSE 0UL -#define JUMP_TYPE_TRUE 1UL -#define JUMP_TYPE_MASK 1UL - -static __always_inline bool static_key_false(struct static_key *key) -{ - return arch_static_branch(key, false); -} - -static __always_inline bool static_key_true(struct static_key *key) -{ - return !arch_static_branch(key, true); -} - -extern struct jump_entry __start___jump_table[]; -extern struct jump_entry __stop___jump_table[]; - -extern void jump_label_init(void); -extern void jump_label_lock(void); -extern void jump_label_unlock(void); -extern void arch_jump_label_transform(struct jump_entry *entry, - enum jump_label_type type); -extern void arch_jump_label_transform_static(struct jump_entry *entry, - enum jump_label_type type); -extern int jump_label_text_reserved(void *start, void *end); -extern void static_key_slow_inc(struct static_key *key); -extern void static_key_slow_dec(struct static_key *key); -extern void jump_label_apply_nops(struct module *mod); -extern int static_key_count(struct static_key *key); -extern void static_key_enable(struct static_key *key); -extern void static_key_disable(struct static_key *key); - -/* - * We should be using ATOMIC_INIT() for initializing .enabled, but - * the inclusion of atomic.h is problematic for inclusion of jump_label.h - * in 'low-level' headers. Thus, we are initializing .enabled with a - * raw value, but have added a BUILD_BUG_ON() to catch any issues in - * jump_label_init() see: kernel/jump_label.c. - */ -#define STATIC_KEY_INIT_TRUE \ - { .enabled = { 1 }, \ - .entries = (void *)JUMP_TYPE_TRUE } -#define STATIC_KEY_INIT_FALSE \ - { .enabled = { 0 }, \ - .entries = (void *)JUMP_TYPE_FALSE } - -#else /* !HAVE_JUMP_LABEL */ - -#include -#include - -static inline int static_key_count(struct static_key *key) -{ - return atomic_read(&key->enabled); -} - -static __always_inline void jump_label_init(void) -{ - static_key_initialized = true; -} - -static __always_inline bool static_key_false(struct static_key *key) -{ - if (unlikely(static_key_count(key) > 0)) - return true; - return false; -} - -static __always_inline bool static_key_true(struct static_key *key) -{ - if (likely(static_key_count(key) > 0)) - return true; - return false; -} - -static inline void static_key_slow_inc(struct static_key *key) -{ - STATIC_KEY_CHECK_USE(); - atomic_inc(&key->enabled); -} - -static inline void static_key_slow_dec(struct static_key *key) -{ - STATIC_KEY_CHECK_USE(); - atomic_dec(&key->enabled); -} - -static inline int jump_label_text_reserved(void *start, void *end) -{ - return 0; -} - -static inline void jump_label_lock(void) {} -static inline void jump_label_unlock(void) {} - -static inline int jump_label_apply_nops(struct module *mod) -{ - return 0; -} - -static inline void static_key_enable(struct static_key *key) -{ - int count = static_key_count(key); - - WARN_ON_ONCE(count < 0 || count > 1); - - if (!count) - static_key_slow_inc(key); -} - -static inline void static_key_disable(struct static_key *key) -{ - int count = static_key_count(key); - - WARN_ON_ONCE(count < 0 || count > 1); - - if (count) - static_key_slow_dec(key); -} - -#define STATIC_KEY_INIT_TRUE { .enabled = ATOMIC_INIT(1) } -#define STATIC_KEY_INIT_FALSE { .enabled = ATOMIC_INIT(0) } - -#endif /* HAVE_JUMP_LABEL */ - -#define STATIC_KEY_INIT STATIC_KEY_INIT_FALSE -#define jump_label_enabled static_key_enabled - -/* -------------------------------------------------------------------------- */ - -/* - * Two type wrappers around static_key, such that we can use compile time - * type differentiation to emit the right code. - * - * All the below code is macros in order to play type games. - */ - -struct static_key_true { - struct static_key key; -}; - -struct static_key_false { - struct static_key key; -}; - -#define STATIC_KEY_TRUE_INIT (struct static_key_true) { .key = STATIC_KEY_INIT_TRUE, } -#define STATIC_KEY_FALSE_INIT (struct static_key_false){ .key = STATIC_KEY_INIT_FALSE, } - -#define DEFINE_STATIC_KEY_TRUE(name) \ - struct static_key_true name = STATIC_KEY_TRUE_INIT - -#define DECLARE_STATIC_KEY_TRUE(name) \ - extern struct static_key_true name - -#define DEFINE_STATIC_KEY_FALSE(name) \ - struct static_key_false name = STATIC_KEY_FALSE_INIT - -#define DECLARE_STATIC_KEY_FALSE(name) \ - extern struct static_key_false name - -#define DEFINE_STATIC_KEY_ARRAY_TRUE(name, count) \ - struct static_key_true name[count] = { \ - [0 ... (count) - 1] = STATIC_KEY_TRUE_INIT, \ - } - -#define DEFINE_STATIC_KEY_ARRAY_FALSE(name, count) \ - struct static_key_false name[count] = { \ - [0 ... (count) - 1] = STATIC_KEY_FALSE_INIT, \ - } - -extern bool ____wrong_branch_error(void); - -#define static_key_enabled(x) \ -({ \ - if (!__builtin_types_compatible_p(typeof(*x), struct static_key) && \ - !__builtin_types_compatible_p(typeof(*x), struct static_key_true) &&\ - !__builtin_types_compatible_p(typeof(*x), struct static_key_false)) \ - ____wrong_branch_error(); \ - static_key_count((struct static_key *)x) > 0; \ -}) - -#ifdef HAVE_JUMP_LABEL - -/* - * Combine the right initial value (type) with the right branch order - * to generate the desired result. - * - * - * type\branch| likely (1) | unlikely (0) - * -----------+-----------------------+------------------ - * | | - * true (1) | ... | ... - * | NOP | JMP L - * | | 1: ... - * | L: ... | - * | | - * | | L: - * | | jmp 1b - * | | - * -----------+-----------------------+------------------ - * | | - * false (0) | ... | ... - * | JMP L | NOP - * | | 1: ... - * | L: ... | - * | | - * | | L: - * | | jmp 1b - * | | - * -----------+-----------------------+------------------ - * - * The initial value is encoded in the LSB of static_key::entries, - * type: 0 = false, 1 = true. - * - * The branch type is encoded in the LSB of jump_entry::key, - * branch: 0 = unlikely, 1 = likely. - * - * This gives the following logic table: - * - * enabled type branch instuction - * -----------------------------+----------- - * 0 0 0 | NOP - * 0 0 1 | JMP - * 0 1 0 | NOP - * 0 1 1 | JMP - * - * 1 0 0 | JMP - * 1 0 1 | NOP - * 1 1 0 | JMP - * 1 1 1 | NOP - * - * Which gives the following functions: - * - * dynamic: instruction = enabled ^ branch - * static: instruction = type ^ branch - * - * See jump_label_type() / jump_label_init_type(). - */ - -#define static_branch_likely(x) \ -({ \ - bool branch; \ - if (__builtin_types_compatible_p(typeof(*x), struct static_key_true)) \ - branch = !arch_static_branch(&(x)->key, true); \ - else if (__builtin_types_compatible_p(typeof(*x), struct static_key_false)) \ - branch = !arch_static_branch_jump(&(x)->key, true); \ - else \ - branch = ____wrong_branch_error(); \ - branch; \ -}) - -#define static_branch_unlikely(x) \ -({ \ - bool branch; \ - if (__builtin_types_compatible_p(typeof(*x), struct static_key_true)) \ - branch = arch_static_branch_jump(&(x)->key, false); \ - else if (__builtin_types_compatible_p(typeof(*x), struct static_key_false)) \ - branch = arch_static_branch(&(x)->key, false); \ - else \ - branch = ____wrong_branch_error(); \ - branch; \ -}) - -#else /* !HAVE_JUMP_LABEL */ - -#define static_branch_likely(x) likely(static_key_enabled(&(x)->key)) -#define static_branch_unlikely(x) unlikely(static_key_enabled(&(x)->key)) - -#endif /* HAVE_JUMP_LABEL */ - -/* - * Advanced usage; refcount, branch is enabled when: count != 0 - */ - -#define static_branch_inc(x) static_key_slow_inc(&(x)->key) -#define static_branch_dec(x) static_key_slow_dec(&(x)->key) - -/* - * Normal usage; boolean enable/disable. - */ - -#define static_branch_enable(x) static_key_enable(&(x)->key) -#define static_branch_disable(x) static_key_disable(&(x)->key) - -#endif /* _LINUX_JUMP_LABEL_H */ - -#endif /* __ASSEMBLY__ */ diff --git a/src/linux/include/linux/jump_label_ratelimit.h b/src/linux/include/linux/jump_label_ratelimit.h deleted file mode 100644 index 089f70f..0000000 --- a/src/linux/include/linux/jump_label_ratelimit.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef _LINUX_JUMP_LABEL_RATELIMIT_H -#define _LINUX_JUMP_LABEL_RATELIMIT_H - -#include -#include - -#if defined(CC_HAVE_ASM_GOTO) && defined(CONFIG_JUMP_LABEL) -struct static_key_deferred { - struct static_key key; - unsigned long timeout; - struct delayed_work work; -}; -#endif - -#ifdef HAVE_JUMP_LABEL -extern void static_key_slow_dec_deferred(struct static_key_deferred *key); -extern void -jump_label_rate_limit(struct static_key_deferred *key, unsigned long rl); - -#else /* !HAVE_JUMP_LABEL */ -struct static_key_deferred { - struct static_key key; -}; -static inline void static_key_slow_dec_deferred(struct static_key_deferred *key) -{ - STATIC_KEY_CHECK_USE(); - static_key_slow_dec(&key->key); -} -static inline void -jump_label_rate_limit(struct static_key_deferred *key, - unsigned long rl) -{ - STATIC_KEY_CHECK_USE(); -} -#endif /* HAVE_JUMP_LABEL */ -#endif /* _LINUX_JUMP_LABEL_RATELIMIT_H */ diff --git a/src/linux/include/linux/kallsyms.h b/src/linux/include/linux/kallsyms.h deleted file mode 100644 index 6883e19..0000000 --- a/src/linux/include/linux/kallsyms.h +++ /dev/null @@ -1,128 +0,0 @@ -/* Rewritten and vastly simplified by Rusty Russell for in-kernel - * module loader: - * Copyright 2002 Rusty Russell IBM Corporation - */ -#ifndef _LINUX_KALLSYMS_H -#define _LINUX_KALLSYMS_H - -#include -#include -#include - -#define KSYM_NAME_LEN 128 -#define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + (KSYM_NAME_LEN - 1) + \ - 2*(BITS_PER_LONG*3/10) + (MODULE_NAME_LEN - 1) + 1) - -struct module; - -#ifdef CONFIG_KALLSYMS -/* Lookup the address for a symbol. Returns 0 if not found. */ -unsigned long kallsyms_lookup_name(const char *name); - -/* Call a function on each kallsyms symbol in the core kernel */ -int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, - unsigned long), - void *data); - -extern int kallsyms_lookup_size_offset(unsigned long addr, - unsigned long *symbolsize, - unsigned long *offset); - -/* Lookup an address. modname is set to NULL if it's in the kernel. */ -const char *kallsyms_lookup(unsigned long addr, - unsigned long *symbolsize, - unsigned long *offset, - char **modname, char *namebuf); - -/* Look up a kernel symbol and return it in a text buffer. */ -extern int sprint_symbol(char *buffer, unsigned long address); -extern int sprint_symbol_no_offset(char *buffer, unsigned long address); -extern int sprint_backtrace(char *buffer, unsigned long address); - -/* Look up a kernel symbol and print it to the kernel messages. */ -extern void __print_symbol(const char *fmt, unsigned long address); - -int lookup_symbol_name(unsigned long addr, char *symname); -int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name); - -#else /* !CONFIG_KALLSYMS */ - -static inline unsigned long kallsyms_lookup_name(const char *name) -{ - return 0; -} - -static inline int kallsyms_on_each_symbol(int (*fn)(void *, const char *, - struct module *, - unsigned long), - void *data) -{ - return 0; -} - -static inline int kallsyms_lookup_size_offset(unsigned long addr, - unsigned long *symbolsize, - unsigned long *offset) -{ - return 0; -} - -static inline const char *kallsyms_lookup(unsigned long addr, - unsigned long *symbolsize, - unsigned long *offset, - char **modname, char *namebuf) -{ - return NULL; -} - -static inline int sprint_symbol(char *buffer, unsigned long addr) -{ - *buffer = '\0'; - return 0; -} - -static inline int sprint_symbol_no_offset(char *buffer, unsigned long addr) -{ - *buffer = '\0'; - return 0; -} - -static inline int sprint_backtrace(char *buffer, unsigned long addr) -{ - *buffer = '\0'; - return 0; -} - -static inline int lookup_symbol_name(unsigned long addr, char *symname) -{ - return -ERANGE; -} - -static inline int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name) -{ - return -ERANGE; -} - -/* Stupid that this does nothing, but I didn't create this mess. */ -#define __print_symbol(fmt, addr) -#endif /*CONFIG_KALLSYMS*/ - -/* This macro allows us to keep printk typechecking */ -static __printf(1, 2) -void __check_printsym_format(const char *fmt, ...) -{ -} - -static inline void print_symbol(const char *fmt, unsigned long addr) -{ - __check_printsym_format(fmt, ""); - __print_symbol(fmt, (unsigned long) - __builtin_extract_return_addr((void *)addr)); -} - -static inline void print_ip_sym(unsigned long ip) -{ - printk("[<%p>] %pS\n", (void *) ip, (void *) ip); -} - -#endif /*_LINUX_KALLSYMS_H*/ diff --git a/src/linux/include/linux/kasan.h b/src/linux/include/linux/kasan.h deleted file mode 100644 index 820c0ad..0000000 --- a/src/linux/include/linux/kasan.h +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef _LINUX_KASAN_H -#define _LINUX_KASAN_H - -#include -#include - -struct kmem_cache; -struct page; -struct vm_struct; - -#ifdef CONFIG_KASAN - -#define KASAN_SHADOW_SCALE_SHIFT 3 - -#include -#include - -extern unsigned char kasan_zero_page[PAGE_SIZE]; -extern pte_t kasan_zero_pte[PTRS_PER_PTE]; -extern pmd_t kasan_zero_pmd[PTRS_PER_PMD]; -extern pud_t kasan_zero_pud[PTRS_PER_PUD]; - -void kasan_populate_zero_shadow(const void *shadow_start, - const void *shadow_end); - -static inline void *kasan_mem_to_shadow(const void *addr) -{ - return (void *)((unsigned long)addr >> KASAN_SHADOW_SCALE_SHIFT) - + KASAN_SHADOW_OFFSET; -} - -/* Enable reporting bugs after kasan_disable_current() */ -static inline void kasan_enable_current(void) -{ - current->kasan_depth++; -} - -/* Disable reporting bugs for current task */ -static inline void kasan_disable_current(void) -{ - current->kasan_depth--; -} - -void kasan_unpoison_shadow(const void *address, size_t size); - -void kasan_unpoison_task_stack(struct task_struct *task); -void kasan_unpoison_stack_above_sp_to(const void *watermark); - -void kasan_alloc_pages(struct page *page, unsigned int order); -void kasan_free_pages(struct page *page, unsigned int order); - -void kasan_cache_create(struct kmem_cache *cache, size_t *size, - unsigned long *flags); -void kasan_cache_shrink(struct kmem_cache *cache); -void kasan_cache_destroy(struct kmem_cache *cache); - -void kasan_poison_slab(struct page *page); -void kasan_unpoison_object_data(struct kmem_cache *cache, void *object); -void kasan_poison_object_data(struct kmem_cache *cache, void *object); -void kasan_init_slab_obj(struct kmem_cache *cache, const void *object); - -void kasan_kmalloc_large(const void *ptr, size_t size, gfp_t flags); -void kasan_kfree_large(const void *ptr); -void kasan_poison_kfree(void *ptr); -void kasan_kmalloc(struct kmem_cache *s, const void *object, size_t size, - gfp_t flags); -void kasan_krealloc(const void *object, size_t new_size, gfp_t flags); - -void kasan_slab_alloc(struct kmem_cache *s, void *object, gfp_t flags); -bool kasan_slab_free(struct kmem_cache *s, void *object); - -struct kasan_cache { - int alloc_meta_offset; - int free_meta_offset; -}; - -int kasan_module_alloc(void *addr, size_t size); -void kasan_free_shadow(const struct vm_struct *vm); - -size_t ksize(const void *); -static inline void kasan_unpoison_slab(const void *ptr) { ksize(ptr); } -size_t kasan_metadata_size(struct kmem_cache *cache); - -#else /* CONFIG_KASAN */ - -static inline void kasan_unpoison_shadow(const void *address, size_t size) {} - -static inline void kasan_unpoison_task_stack(struct task_struct *task) {} -static inline void kasan_unpoison_stack_above_sp_to(const void *watermark) {} - -static inline void kasan_enable_current(void) {} -static inline void kasan_disable_current(void) {} - -static inline void kasan_alloc_pages(struct page *page, unsigned int order) {} -static inline void kasan_free_pages(struct page *page, unsigned int order) {} - -static inline void kasan_cache_create(struct kmem_cache *cache, - size_t *size, - unsigned long *flags) {} -static inline void kasan_cache_shrink(struct kmem_cache *cache) {} -static inline void kasan_cache_destroy(struct kmem_cache *cache) {} - -static inline void kasan_poison_slab(struct page *page) {} -static inline void kasan_unpoison_object_data(struct kmem_cache *cache, - void *object) {} -static inline void kasan_poison_object_data(struct kmem_cache *cache, - void *object) {} -static inline void kasan_init_slab_obj(struct kmem_cache *cache, - const void *object) {} - -static inline void kasan_kmalloc_large(void *ptr, size_t size, gfp_t flags) {} -static inline void kasan_kfree_large(const void *ptr) {} -static inline void kasan_poison_kfree(void *ptr) {} -static inline void kasan_kmalloc(struct kmem_cache *s, const void *object, - size_t size, gfp_t flags) {} -static inline void kasan_krealloc(const void *object, size_t new_size, - gfp_t flags) {} - -static inline void kasan_slab_alloc(struct kmem_cache *s, void *object, - gfp_t flags) {} -static inline bool kasan_slab_free(struct kmem_cache *s, void *object) -{ - return false; -} - -static inline int kasan_module_alloc(void *addr, size_t size) { return 0; } -static inline void kasan_free_shadow(const struct vm_struct *vm) {} - -static inline void kasan_unpoison_slab(const void *ptr) { } -static inline size_t kasan_metadata_size(struct kmem_cache *cache) { return 0; } - -#endif /* CONFIG_KASAN */ - -#endif /* LINUX_KASAN_H */ diff --git a/src/linux/include/linux/kbd_kern.h b/src/linux/include/linux/kbd_kern.h deleted file mode 100644 index cbfb171..0000000 --- a/src/linux/include/linux/kbd_kern.h +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef _KBD_KERN_H -#define _KBD_KERN_H - -#include -#include -#include - -extern struct tasklet_struct keyboard_tasklet; - -extern char *func_table[MAX_NR_FUNC]; -extern char func_buf[]; -extern char *funcbufptr; -extern int funcbufsize, funcbufleft; - -/* - * kbd->xxx contains the VC-local things (flag settings etc..) - * - * Note: externally visible are LED_SCR, LED_NUM, LED_CAP defined in kd.h - * The code in KDGETLED / KDSETLED depends on the internal and - * external order being the same. - * - * Note: lockstate is used as index in the array key_map. - */ -struct kbd_struct { - - unsigned char lockstate; -/* 8 modifiers - the names do not have any meaning at all; - they can be associated to arbitrarily chosen keys */ -#define VC_SHIFTLOCK KG_SHIFT /* shift lock mode */ -#define VC_ALTGRLOCK KG_ALTGR /* altgr lock mode */ -#define VC_CTRLLOCK KG_CTRL /* control lock mode */ -#define VC_ALTLOCK KG_ALT /* alt lock mode */ -#define VC_SHIFTLLOCK KG_SHIFTL /* shiftl lock mode */ -#define VC_SHIFTRLOCK KG_SHIFTR /* shiftr lock mode */ -#define VC_CTRLLLOCK KG_CTRLL /* ctrll lock mode */ -#define VC_CTRLRLOCK KG_CTRLR /* ctrlr lock mode */ - unsigned char slockstate; /* for `sticky' Shift, Ctrl, etc. */ - - unsigned char ledmode:1; -#define LED_SHOW_FLAGS 0 /* traditional state */ -#define LED_SHOW_IOCTL 1 /* only change leds upon ioctl */ - - unsigned char ledflagstate:4; /* flags, not lights */ - unsigned char default_ledflagstate:4; -#define VC_SCROLLOCK 0 /* scroll-lock mode */ -#define VC_NUMLOCK 1 /* numeric lock mode */ -#define VC_CAPSLOCK 2 /* capslock mode */ -#define VC_KANALOCK 3 /* kanalock mode */ - - unsigned char kbdmode:3; /* one 3-bit value */ -#define VC_XLATE 0 /* translate keycodes using keymap */ -#define VC_MEDIUMRAW 1 /* medium raw (keycode) mode */ -#define VC_RAW 2 /* raw (scancode) mode */ -#define VC_UNICODE 3 /* Unicode mode */ -#define VC_OFF 4 /* disabled mode */ - - unsigned char modeflags:5; -#define VC_APPLIC 0 /* application key mode */ -#define VC_CKMODE 1 /* cursor key mode */ -#define VC_REPEAT 2 /* keyboard repeat */ -#define VC_CRLF 3 /* 0 - enter sends CR, 1 - enter sends CRLF */ -#define VC_META 4 /* 0 - meta, 1 - meta=prefix with ESC */ -}; - -extern int kbd_init(void); - -extern void setledstate(struct kbd_struct *kbd, unsigned int led); - -extern int do_poke_blanked_console; - -extern void (*kbd_ledfunc)(unsigned int led); - -extern int set_console(int nr); -extern void schedule_console_callback(void); - -/* FIXME: review locking for vt.c callers */ -static inline void set_leds(void) -{ - tasklet_schedule(&keyboard_tasklet); -} - -static inline int vc_kbd_mode(struct kbd_struct * kbd, int flag) -{ - return ((kbd->modeflags >> flag) & 1); -} - -static inline int vc_kbd_led(struct kbd_struct * kbd, int flag) -{ - return ((kbd->ledflagstate >> flag) & 1); -} - -static inline void set_vc_kbd_mode(struct kbd_struct * kbd, int flag) -{ - kbd->modeflags |= 1 << flag; -} - -static inline void set_vc_kbd_led(struct kbd_struct * kbd, int flag) -{ - kbd->ledflagstate |= 1 << flag; -} - -static inline void clr_vc_kbd_mode(struct kbd_struct * kbd, int flag) -{ - kbd->modeflags &= ~(1 << flag); -} - -static inline void clr_vc_kbd_led(struct kbd_struct * kbd, int flag) -{ - kbd->ledflagstate &= ~(1 << flag); -} - -static inline void chg_vc_kbd_lock(struct kbd_struct * kbd, int flag) -{ - kbd->lockstate ^= 1 << flag; -} - -static inline void chg_vc_kbd_slock(struct kbd_struct * kbd, int flag) -{ - kbd->slockstate ^= 1 << flag; -} - -static inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag) -{ - kbd->modeflags ^= 1 << flag; -} - -static inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag) -{ - kbd->ledflagstate ^= 1 << flag; -} - -#define U(x) ((x) ^ 0xf000) - -#define BRL_UC_ROW 0x2800 - -/* keyboard.c */ - -struct console; - -void compute_shiftstate(void); - -/* defkeymap.c */ - -extern unsigned int keymap_count; - -#endif diff --git a/src/linux/include/linux/kbuild.h b/src/linux/include/linux/kbuild.h deleted file mode 100644 index 22a7219..0000000 --- a/src/linux/include/linux/kbuild.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __LINUX_KBUILD_H -#define __LINUX_KBUILD_H - -#define DEFINE(sym, val) \ - asm volatile("\n->" #sym " %0 " #val : : "i" (val)) - -#define BLANK() asm volatile("\n->" : : ) - -#define OFFSET(sym, str, mem) \ - DEFINE(sym, offsetof(struct str, mem)) - -#define COMMENT(x) \ - asm volatile("\n->#" x) - -#endif diff --git a/src/linux/include/linux/kconfig.h b/src/linux/include/linux/kconfig.h deleted file mode 100644 index 8f2e059..0000000 --- a/src/linux/include/linux/kconfig.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef __LINUX_KCONFIG_H -#define __LINUX_KCONFIG_H - -#include - -#define __ARG_PLACEHOLDER_1 0, -#define __take_second_arg(__ignored, val, ...) val - -/* - * The use of "&&" / "||" is limited in certain expressions. - * The followings enable to calculate "and" / "or" with macro expansion only. - */ -#define __and(x, y) ___and(x, y) -#define ___and(x, y) ____and(__ARG_PLACEHOLDER_##x, y) -#define ____and(arg1_or_junk, y) __take_second_arg(arg1_or_junk y, 0) - -#define __or(x, y) ___or(x, y) -#define ___or(x, y) ____or(__ARG_PLACEHOLDER_##x, y) -#define ____or(arg1_or_junk, y) __take_second_arg(arg1_or_junk 1, y) - -/* - * Helper macros to use CONFIG_ options in C/CPP expressions. Note that - * these only work with boolean and tristate options. - */ - -/* - * Getting something that works in C and CPP for an arg that may or may - * not be defined is tricky. Here, if we have "#define CONFIG_BOOGER 1" - * we match on the placeholder define, insert the "0," for arg1 and generate - * the triplet (0, 1, 0). Then the last step cherry picks the 2nd arg (a one). - * When CONFIG_BOOGER is not defined, we generate a (... 1, 0) pair, and when - * the last step cherry picks the 2nd arg, we get a zero. - */ -#define __is_defined(x) ___is_defined(x) -#define ___is_defined(val) ____is_defined(__ARG_PLACEHOLDER_##val) -#define ____is_defined(arg1_or_junk) __take_second_arg(arg1_or_junk 1, 0) - -/* - * IS_BUILTIN(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y', 0 - * otherwise. For boolean options, this is equivalent to - * IS_ENABLED(CONFIG_FOO). - */ -#define IS_BUILTIN(option) __is_defined(option) - -/* - * IS_MODULE(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'm', 0 - * otherwise. - */ -#define IS_MODULE(option) __is_defined(option##_MODULE) - -/* - * IS_REACHABLE(CONFIG_FOO) evaluates to 1 if the currently compiled - * code can call a function defined in code compiled based on CONFIG_FOO. - * This is similar to IS_ENABLED(), but returns false when invoked from - * built-in code when CONFIG_FOO is set to 'm'. - */ -#define IS_REACHABLE(option) __or(IS_BUILTIN(option), \ - __and(IS_MODULE(option), __is_defined(MODULE))) - -/* - * IS_ENABLED(CONFIG_FOO) evaluates to 1 if CONFIG_FOO is set to 'y' or 'm', - * 0 otherwise. - */ -#define IS_ENABLED(option) __or(IS_BUILTIN(option), IS_MODULE(option)) - -#endif /* __LINUX_KCONFIG_H */ diff --git a/src/linux/include/linux/kcov.h b/src/linux/include/linux/kcov.h deleted file mode 100644 index 2883ac9..0000000 --- a/src/linux/include/linux/kcov.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _LINUX_KCOV_H -#define _LINUX_KCOV_H - -#include - -struct task_struct; - -#ifdef CONFIG_KCOV - -void kcov_task_init(struct task_struct *t); -void kcov_task_exit(struct task_struct *t); - -enum kcov_mode { - /* Coverage collection is not enabled yet. */ - KCOV_MODE_DISABLED = 0, - /* - * Tracing coverage collection mode. - * Covered PCs are collected in a per-task buffer. - */ - KCOV_MODE_TRACE = 1, -}; - -#else - -static inline void kcov_task_init(struct task_struct *t) {} -static inline void kcov_task_exit(struct task_struct *t) {} - -#endif /* CONFIG_KCOV */ -#endif /* _LINUX_KCOV_H */ diff --git a/src/linux/include/linux/kd.h b/src/linux/include/linux/kd.h deleted file mode 100644 index 25bd17f..0000000 --- a/src/linux/include/linux/kd.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _LINUX_KD_H -#define _LINUX_KD_H - -#include - -#define KD_FONT_FLAG_OLD 0x80000000 /* Invoked via old interface [compat] */ -#endif /* _LINUX_KD_H */ diff --git a/src/linux/include/linux/kdb.h b/src/linux/include/linux/kdb.h deleted file mode 100644 index 410deca..0000000 --- a/src/linux/include/linux/kdb.h +++ /dev/null @@ -1,221 +0,0 @@ -#ifndef _KDB_H -#define _KDB_H - -/* - * Kernel Debugger Architecture Independent Global Headers - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. - * - * Copyright (c) 2000-2007 Silicon Graphics, Inc. All Rights Reserved. - * Copyright (C) 2000 Stephane Eranian - * Copyright (C) 2009 Jason Wessel - */ - -/* Shifted versions of the command enable bits are be used if the command - * has no arguments (see kdb_check_flags). This allows commands, such as - * go, to have different permissions depending upon whether it is called - * with an argument. - */ -#define KDB_ENABLE_NO_ARGS_SHIFT 10 - -typedef enum { - KDB_ENABLE_ALL = (1 << 0), /* Enable everything */ - KDB_ENABLE_MEM_READ = (1 << 1), - KDB_ENABLE_MEM_WRITE = (1 << 2), - KDB_ENABLE_REG_READ = (1 << 3), - KDB_ENABLE_REG_WRITE = (1 << 4), - KDB_ENABLE_INSPECT = (1 << 5), - KDB_ENABLE_FLOW_CTRL = (1 << 6), - KDB_ENABLE_SIGNAL = (1 << 7), - KDB_ENABLE_REBOOT = (1 << 8), - /* User exposed values stop here, all remaining flags are - * exclusively used to describe a commands behaviour. - */ - - KDB_ENABLE_ALWAYS_SAFE = (1 << 9), - KDB_ENABLE_MASK = (1 << KDB_ENABLE_NO_ARGS_SHIFT) - 1, - - KDB_ENABLE_ALL_NO_ARGS = KDB_ENABLE_ALL << KDB_ENABLE_NO_ARGS_SHIFT, - KDB_ENABLE_MEM_READ_NO_ARGS = KDB_ENABLE_MEM_READ - << KDB_ENABLE_NO_ARGS_SHIFT, - KDB_ENABLE_MEM_WRITE_NO_ARGS = KDB_ENABLE_MEM_WRITE - << KDB_ENABLE_NO_ARGS_SHIFT, - KDB_ENABLE_REG_READ_NO_ARGS = KDB_ENABLE_REG_READ - << KDB_ENABLE_NO_ARGS_SHIFT, - KDB_ENABLE_REG_WRITE_NO_ARGS = KDB_ENABLE_REG_WRITE - << KDB_ENABLE_NO_ARGS_SHIFT, - KDB_ENABLE_INSPECT_NO_ARGS = KDB_ENABLE_INSPECT - << KDB_ENABLE_NO_ARGS_SHIFT, - KDB_ENABLE_FLOW_CTRL_NO_ARGS = KDB_ENABLE_FLOW_CTRL - << KDB_ENABLE_NO_ARGS_SHIFT, - KDB_ENABLE_SIGNAL_NO_ARGS = KDB_ENABLE_SIGNAL - << KDB_ENABLE_NO_ARGS_SHIFT, - KDB_ENABLE_REBOOT_NO_ARGS = KDB_ENABLE_REBOOT - << KDB_ENABLE_NO_ARGS_SHIFT, - KDB_ENABLE_ALWAYS_SAFE_NO_ARGS = KDB_ENABLE_ALWAYS_SAFE - << KDB_ENABLE_NO_ARGS_SHIFT, - KDB_ENABLE_MASK_NO_ARGS = KDB_ENABLE_MASK << KDB_ENABLE_NO_ARGS_SHIFT, - - KDB_REPEAT_NO_ARGS = 0x40000000, /* Repeat the command w/o arguments */ - KDB_REPEAT_WITH_ARGS = 0x80000000, /* Repeat the command with args */ -} kdb_cmdflags_t; - -typedef int (*kdb_func_t)(int, const char **); - -#ifdef CONFIG_KGDB_KDB -#include -#include -#include - -#define KDB_POLL_FUNC_MAX 5 -extern int kdb_poll_idx; - -/* - * kdb_initial_cpu is initialized to -1, and is set to the cpu - * number whenever the kernel debugger is entered. - */ -extern int kdb_initial_cpu; -extern atomic_t kdb_event; - -/* Types and messages used for dynamically added kdb shell commands */ - -#define KDB_MAXARGS 16 /* Maximum number of arguments to a function */ - -/* KDB return codes from a command or internal kdb function */ -#define KDB_NOTFOUND (-1) -#define KDB_ARGCOUNT (-2) -#define KDB_BADWIDTH (-3) -#define KDB_BADRADIX (-4) -#define KDB_NOTENV (-5) -#define KDB_NOENVVALUE (-6) -#define KDB_NOTIMP (-7) -#define KDB_ENVFULL (-8) -#define KDB_ENVBUFFULL (-9) -#define KDB_TOOMANYBPT (-10) -#define KDB_TOOMANYDBREGS (-11) -#define KDB_DUPBPT (-12) -#define KDB_BPTNOTFOUND (-13) -#define KDB_BADMODE (-14) -#define KDB_BADINT (-15) -#define KDB_INVADDRFMT (-16) -#define KDB_BADREG (-17) -#define KDB_BADCPUNUM (-18) -#define KDB_BADLENGTH (-19) -#define KDB_NOBP (-20) -#define KDB_BADADDR (-21) -#define KDB_NOPERM (-22) - -/* - * kdb_diemsg - * - * Contains a pointer to the last string supplied to the - * kernel 'die' panic function. - */ -extern const char *kdb_diemsg; - -#define KDB_FLAG_EARLYKDB (1 << 0) /* set from boot parameter kdb=early */ -#define KDB_FLAG_CATASTROPHIC (1 << 1) /* A catastrophic event has occurred */ -#define KDB_FLAG_CMD_INTERRUPT (1 << 2) /* Previous command was interrupted */ -#define KDB_FLAG_NOIPI (1 << 3) /* Do not send IPIs */ -#define KDB_FLAG_NO_CONSOLE (1 << 5) /* No console is available, - * kdb is disabled */ -#define KDB_FLAG_NO_VT_CONSOLE (1 << 6) /* No VT console is available, do - * not use keyboard */ -#define KDB_FLAG_NO_I8042 (1 << 7) /* No i8042 chip is available, do - * not use keyboard */ - -extern int kdb_flags; /* Global flags, see kdb_state for per cpu state */ - -extern void kdb_save_flags(void); -extern void kdb_restore_flags(void); - -#define KDB_FLAG(flag) (kdb_flags & KDB_FLAG_##flag) -#define KDB_FLAG_SET(flag) ((void)(kdb_flags |= KDB_FLAG_##flag)) -#define KDB_FLAG_CLEAR(flag) ((void)(kdb_flags &= ~KDB_FLAG_##flag)) - -/* - * External entry point for the kernel debugger. The pt_regs - * at the time of entry are supplied along with the reason for - * entry to the kernel debugger. - */ - -typedef enum { - KDB_REASON_ENTER = 1, /* KDB_ENTER() trap/fault - regs valid */ - KDB_REASON_ENTER_SLAVE, /* KDB_ENTER_SLAVE() trap/fault - regs valid */ - KDB_REASON_BREAK, /* Breakpoint inst. - regs valid */ - KDB_REASON_DEBUG, /* Debug Fault - regs valid */ - KDB_REASON_OOPS, /* Kernel Oops - regs valid */ - KDB_REASON_SWITCH, /* CPU switch - regs valid*/ - KDB_REASON_KEYBOARD, /* Keyboard entry - regs valid */ - KDB_REASON_NMI, /* Non-maskable interrupt; regs valid */ - KDB_REASON_RECURSE, /* Recursive entry to kdb; - * regs probably valid */ - KDB_REASON_SSTEP, /* Single Step trap. - regs valid */ - KDB_REASON_SYSTEM_NMI, /* In NMI due to SYSTEM cmd; regs valid */ -} kdb_reason_t; - -enum kdb_msgsrc { - KDB_MSGSRC_INTERNAL, /* direct call to kdb_printf() */ - KDB_MSGSRC_PRINTK, /* trapped from printk() */ -}; - -extern int kdb_trap_printk; -extern __printf(2, 0) int vkdb_printf(enum kdb_msgsrc src, const char *fmt, - va_list args); -extern __printf(1, 2) int kdb_printf(const char *, ...); -typedef __printf(1, 2) int (*kdb_printf_t)(const char *, ...); - -extern void kdb_init(int level); - -/* Access to kdb specific polling devices */ -typedef int (*get_char_func)(void); -extern get_char_func kdb_poll_funcs[]; -extern int kdb_get_kbd_char(void); - -static inline -int kdb_process_cpu(const struct task_struct *p) -{ - unsigned int cpu = task_cpu(p); - if (cpu > num_possible_cpus()) - cpu = 0; - return cpu; -} - -/* kdb access to register set for stack dumping */ -extern struct pt_regs *kdb_current_regs; -#ifdef CONFIG_KALLSYMS -extern const char *kdb_walk_kallsyms(loff_t *pos); -#else /* ! CONFIG_KALLSYMS */ -static inline const char *kdb_walk_kallsyms(loff_t *pos) -{ - return NULL; -} -#endif /* ! CONFIG_KALLSYMS */ - -/* Dynamic kdb shell command registration */ -extern int kdb_register(char *, kdb_func_t, char *, char *, short); -extern int kdb_register_flags(char *, kdb_func_t, char *, char *, - short, kdb_cmdflags_t); -extern int kdb_unregister(char *); -#else /* ! CONFIG_KGDB_KDB */ -static inline __printf(1, 2) int kdb_printf(const char *fmt, ...) { return 0; } -static inline void kdb_init(int level) {} -static inline int kdb_register(char *cmd, kdb_func_t func, char *usage, - char *help, short minlen) { return 0; } -static inline int kdb_register_flags(char *cmd, kdb_func_t func, char *usage, - char *help, short minlen, - kdb_cmdflags_t flags) { return 0; } -static inline int kdb_unregister(char *cmd) { return 0; } -#endif /* CONFIG_KGDB_KDB */ -enum { - KDB_NOT_INITIALIZED, - KDB_INIT_EARLY, - KDB_INIT_FULL, -}; - -extern int kdbgetintenv(const char *, int *); -extern int kdb_set(int, const char **); - -#endif /* !_KDB_H */ diff --git a/src/linux/include/linux/kdebug.h b/src/linux/include/linux/kdebug.h deleted file mode 100644 index ed81509..0000000 --- a/src/linux/include/linux/kdebug.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _LINUX_KDEBUG_H -#define _LINUX_KDEBUG_H - -#include - -struct notifier_block; - -struct die_args { - struct pt_regs *regs; - const char *str; - long err; - int trapnr; - int signr; -}; - -int register_die_notifier(struct notifier_block *nb); -int unregister_die_notifier(struct notifier_block *nb); - -int notify_die(enum die_val val, const char *str, - struct pt_regs *regs, long err, int trap, int sig); - -#endif /* _LINUX_KDEBUG_H */ diff --git a/src/linux/include/linux/kdev_t.h b/src/linux/include/linux/kdev_t.h deleted file mode 100644 index 8e9e288..0000000 --- a/src/linux/include/linux/kdev_t.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef _LINUX_KDEV_T_H -#define _LINUX_KDEV_T_H - -#include - -#define MINORBITS 20 -#define MINORMASK ((1U << MINORBITS) - 1) - -#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) -#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) -#define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) - -#define print_dev_t(buffer, dev) \ - sprintf((buffer), "%u:%u\n", MAJOR(dev), MINOR(dev)) - -#define format_dev_t(buffer, dev) \ - ({ \ - sprintf(buffer, "%u:%u", MAJOR(dev), MINOR(dev)); \ - buffer; \ - }) - -/* acceptable for old filesystems */ -static inline bool old_valid_dev(dev_t dev) -{ - return MAJOR(dev) < 256 && MINOR(dev) < 256; -} - -static inline u16 old_encode_dev(dev_t dev) -{ - return (MAJOR(dev) << 8) | MINOR(dev); -} - -static inline dev_t old_decode_dev(u16 val) -{ - return MKDEV((val >> 8) & 255, val & 255); -} - -static inline u32 new_encode_dev(dev_t dev) -{ - unsigned major = MAJOR(dev); - unsigned minor = MINOR(dev); - return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12); -} - -static inline dev_t new_decode_dev(u32 dev) -{ - unsigned major = (dev & 0xfff00) >> 8; - unsigned minor = (dev & 0xff) | ((dev >> 12) & 0xfff00); - return MKDEV(major, minor); -} - -static inline u64 huge_encode_dev(dev_t dev) -{ - return new_encode_dev(dev); -} - -static inline dev_t huge_decode_dev(u64 dev) -{ - return new_decode_dev(dev); -} - -static inline int sysv_valid_dev(dev_t dev) -{ - return MAJOR(dev) < (1<<14) && MINOR(dev) < (1<<18); -} - -static inline u32 sysv_encode_dev(dev_t dev) -{ - return MINOR(dev) | (MAJOR(dev) << 18); -} - -static inline unsigned sysv_major(u32 dev) -{ - return (dev >> 18) & 0x3fff; -} - -static inline unsigned sysv_minor(u32 dev) -{ - return dev & 0x3ffff; -} - -#endif diff --git a/src/linux/include/linux/kern_levels.h b/src/linux/include/linux/kern_levels.h deleted file mode 100644 index f282d4e..0000000 --- a/src/linux/include/linux/kern_levels.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef __KERN_LEVELS_H__ -#define __KERN_LEVELS_H__ - -#define KERN_SOH "\001" /* ASCII Start Of Header */ -#define KERN_SOH_ASCII '\001' - -#define KERN_EMERG KERN_SOH "0" /* system is unusable */ -#define KERN_ALERT KERN_SOH "1" /* action must be taken immediately */ -#define KERN_CRIT KERN_SOH "2" /* critical conditions */ -#define KERN_ERR KERN_SOH "3" /* error conditions */ -#define KERN_WARNING KERN_SOH "4" /* warning conditions */ -#define KERN_NOTICE KERN_SOH "5" /* normal but significant condition */ -#define KERN_INFO KERN_SOH "6" /* informational */ -#define KERN_DEBUG KERN_SOH "7" /* debug-level messages */ - -#define KERN_DEFAULT KERN_SOH "d" /* the default kernel loglevel */ - -/* - * Annotation for a "continued" line of log printout (only done after a - * line that had no enclosing \n). Only to be used by core/arch code - * during early bootup (a continued line is not SMP-safe otherwise). - */ -#define KERN_CONT KERN_SOH "c" - -/* integer equivalents of KERN_ */ -#define LOGLEVEL_SCHED -2 /* Deferred messages from sched code - * are set to this special level */ -#define LOGLEVEL_DEFAULT -1 /* default (or last) loglevel */ -#define LOGLEVEL_EMERG 0 /* system is unusable */ -#define LOGLEVEL_ALERT 1 /* action must be taken immediately */ -#define LOGLEVEL_CRIT 2 /* critical conditions */ -#define LOGLEVEL_ERR 3 /* error conditions */ -#define LOGLEVEL_WARNING 4 /* warning conditions */ -#define LOGLEVEL_NOTICE 5 /* normal but significant condition */ -#define LOGLEVEL_INFO 6 /* informational */ -#define LOGLEVEL_DEBUG 7 /* debug-level messages */ - -#endif diff --git a/src/linux/include/linux/kernel.h b/src/linux/include/linux/kernel.h deleted file mode 100644 index bc6ed52..0000000 --- a/src/linux/include/linux/kernel.h +++ /dev/null @@ -1,856 +0,0 @@ -#ifndef _LINUX_KERNEL_H -#define _LINUX_KERNEL_H - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define USHRT_MAX ((u16)(~0U)) -#define SHRT_MAX ((s16)(USHRT_MAX>>1)) -#define SHRT_MIN ((s16)(-SHRT_MAX - 1)) -#define INT_MAX ((int)(~0U>>1)) -#define INT_MIN (-INT_MAX - 1) -#define UINT_MAX (~0U) -#define LONG_MAX ((long)(~0UL>>1)) -#define LONG_MIN (-LONG_MAX - 1) -#define ULONG_MAX (~0UL) -#define LLONG_MAX ((long long)(~0ULL>>1)) -#define LLONG_MIN (-LLONG_MAX - 1) -#define ULLONG_MAX (~0ULL) -#define SIZE_MAX (~(size_t)0) - -#define U8_MAX ((u8)~0U) -#define S8_MAX ((s8)(U8_MAX>>1)) -#define S8_MIN ((s8)(-S8_MAX - 1)) -#define U16_MAX ((u16)~0U) -#define S16_MAX ((s16)(U16_MAX>>1)) -#define S16_MIN ((s16)(-S16_MAX - 1)) -#define U32_MAX ((u32)~0U) -#define S32_MAX ((s32)(U32_MAX>>1)) -#define S32_MIN ((s32)(-S32_MAX - 1)) -#define U64_MAX ((u64)~0ULL) -#define S64_MAX ((s64)(U64_MAX>>1)) -#define S64_MIN ((s64)(-S64_MAX - 1)) - -#define STACK_MAGIC 0xdeadbeef - -#define REPEAT_BYTE(x) ((~0ul / 0xff) * (x)) - -#define ALIGN(x, a) __ALIGN_KERNEL((x), (a)) -#define __ALIGN_MASK(x, mask) __ALIGN_KERNEL_MASK((x), (mask)) -#define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a))) -#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) - -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) - -#define u64_to_user_ptr(x) ( \ -{ \ - typecheck(u64, x); \ - (void __user *)(uintptr_t)x; \ -} \ -) - -/* - * This looks more complex than it should be. But we need to - * get the type for the ~ right in round_down (it needs to be - * as wide as the result!), and we want to evaluate the macro - * arguments just once each. - */ -#define __round_mask(x, y) ((__typeof__(x))((y)-1)) -#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1) -#define round_down(x, y) ((x) & ~__round_mask(x, y)) - -#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) -#define DIV_ROUND_UP __KERNEL_DIV_ROUND_UP -#define DIV_ROUND_UP_ULL(ll,d) \ - ({ unsigned long long _tmp = (ll)+(d)-1; do_div(_tmp, d); _tmp; }) - -#if BITS_PER_LONG == 32 -# define DIV_ROUND_UP_SECTOR_T(ll,d) DIV_ROUND_UP_ULL(ll, d) -#else -# define DIV_ROUND_UP_SECTOR_T(ll,d) DIV_ROUND_UP(ll,d) -#endif - -/* The `const' in roundup() prevents gcc-3.3 from calling __divdi3 */ -#define roundup(x, y) ( \ -{ \ - const typeof(y) __y = y; \ - (((x) + (__y - 1)) / __y) * __y; \ -} \ -) -#define rounddown(x, y) ( \ -{ \ - typeof(x) __x = (x); \ - __x - (__x % (y)); \ -} \ -) - -/* - * Divide positive or negative dividend by positive divisor and round - * to closest integer. Result is undefined for negative divisors and - * for negative dividends if the divisor variable type is unsigned. - */ -#define DIV_ROUND_CLOSEST(x, divisor)( \ -{ \ - typeof(x) __x = x; \ - typeof(divisor) __d = divisor; \ - (((typeof(x))-1) > 0 || \ - ((typeof(divisor))-1) > 0 || (__x) > 0) ? \ - (((__x) + ((__d) / 2)) / (__d)) : \ - (((__x) - ((__d) / 2)) / (__d)); \ -} \ -) -/* - * Same as above but for u64 dividends. divisor must be a 32-bit - * number. - */ -#define DIV_ROUND_CLOSEST_ULL(x, divisor)( \ -{ \ - typeof(divisor) __d = divisor; \ - unsigned long long _tmp = (x) + (__d) / 2; \ - do_div(_tmp, __d); \ - _tmp; \ -} \ -) - -/* - * Multiplies an integer by a fraction, while avoiding unnecessary - * overflow or loss of precision. - */ -#define mult_frac(x, numer, denom)( \ -{ \ - typeof(x) quot = (x) / (denom); \ - typeof(x) rem = (x) % (denom); \ - (quot * (numer)) + ((rem * (numer)) / (denom)); \ -} \ -) - - -#define _RET_IP_ (unsigned long)__builtin_return_address(0) -#define _THIS_IP_ ({ __label__ __here; __here: (unsigned long)&&__here; }) - -#ifdef CONFIG_LBDAF -# include -# define sector_div(a, b) do_div(a, b) -#else -# define sector_div(n, b)( \ -{ \ - int _res; \ - _res = (n) % (b); \ - (n) /= (b); \ - _res; \ -} \ -) -#endif - -/** - * upper_32_bits - return bits 32-63 of a number - * @n: the number we're accessing - * - * A basic shift-right of a 64- or 32-bit quantity. Use this to suppress - * the "right shift count >= width of type" warning when that quantity is - * 32-bits. - */ -#define upper_32_bits(n) ((u32)(((n) >> 16) >> 16)) - -/** - * lower_32_bits - return bits 0-31 of a number - * @n: the number we're accessing - */ -#define lower_32_bits(n) ((u32)(n)) - -struct completion; -struct pt_regs; -struct user; - -#ifdef CONFIG_PREEMPT_VOLUNTARY -extern int _cond_resched(void); -# define might_resched() _cond_resched() -#else -# define might_resched() do { } while (0) -#endif - -#ifdef CONFIG_DEBUG_ATOMIC_SLEEP - void ___might_sleep(const char *file, int line, int preempt_offset); - void __might_sleep(const char *file, int line, int preempt_offset); -/** - * might_sleep - annotation for functions that can sleep - * - * this macro will print a stack trace if it is executed in an atomic - * context (spinlock, irq-handler, ...). - * - * This is a useful debugging help to be able to catch problems early and not - * be bitten later when the calling function happens to sleep when it is not - * supposed to. - */ -# define might_sleep() \ - do { __might_sleep(__FILE__, __LINE__, 0); might_resched(); } while (0) -# define sched_annotate_sleep() (current->task_state_change = 0) -#else - static inline void ___might_sleep(const char *file, int line, - int preempt_offset) { } - static inline void __might_sleep(const char *file, int line, - int preempt_offset) { } -# define might_sleep() do { might_resched(); } while (0) -# define sched_annotate_sleep() do { } while (0) -#endif - -#define might_sleep_if(cond) do { if (cond) might_sleep(); } while (0) - -/** - * abs - return absolute value of an argument - * @x: the value. If it is unsigned type, it is converted to signed type first. - * char is treated as if it was signed (regardless of whether it really is) - * but the macro's return type is preserved as char. - * - * Return: an absolute value of x. - */ -#define abs(x) __abs_choose_expr(x, long long, \ - __abs_choose_expr(x, long, \ - __abs_choose_expr(x, int, \ - __abs_choose_expr(x, short, \ - __abs_choose_expr(x, char, \ - __builtin_choose_expr( \ - __builtin_types_compatible_p(typeof(x), char), \ - (char)({ signed char __x = (x); __x<0?-__x:__x; }), \ - ((void)0))))))) - -#define __abs_choose_expr(x, type, other) __builtin_choose_expr( \ - __builtin_types_compatible_p(typeof(x), signed type) || \ - __builtin_types_compatible_p(typeof(x), unsigned type), \ - ({ signed type __x = (x); __x < 0 ? -__x : __x; }), other) - -/** - * reciprocal_scale - "scale" a value into range [0, ep_ro) - * @val: value - * @ep_ro: right open interval endpoint - * - * Perform a "reciprocal multiplication" in order to "scale" a value into - * range [0, ep_ro), where the upper interval endpoint is right-open. - * This is useful, e.g. for accessing a index of an array containing - * ep_ro elements, for example. Think of it as sort of modulus, only that - * the result isn't that of modulo. ;) Note that if initial input is a - * small value, then result will return 0. - * - * Return: a result based on val in interval [0, ep_ro). - */ -static inline u32 reciprocal_scale(u32 val, u32 ep_ro) -{ - return (u32)(((u64) val * ep_ro) >> 32); -} - -#if defined(CONFIG_MMU) && \ - (defined(CONFIG_PROVE_LOCKING) || defined(CONFIG_DEBUG_ATOMIC_SLEEP)) -#define might_fault() __might_fault(__FILE__, __LINE__) -void __might_fault(const char *file, int line); -#else -static inline void might_fault(void) { } -#endif - -extern struct atomic_notifier_head panic_notifier_list; -extern long (*panic_blink)(int state); -__printf(1, 2) -void panic(const char *fmt, ...) __noreturn __cold; -void nmi_panic(struct pt_regs *regs, const char *msg); -extern void oops_enter(void); -extern void oops_exit(void); -void print_oops_end_marker(void); -extern int oops_may_print(void); -void do_exit(long error_code) __noreturn; -void complete_and_exit(struct completion *, long) __noreturn; - -/* Internal, do not use. */ -int __must_check _kstrtoul(const char *s, unsigned int base, unsigned long *res); -int __must_check _kstrtol(const char *s, unsigned int base, long *res); - -int __must_check kstrtoull(const char *s, unsigned int base, unsigned long long *res); -int __must_check kstrtoll(const char *s, unsigned int base, long long *res); - -/** - * kstrtoul - convert a string to an unsigned long - * @s: The start of the string. The string must be null-terminated, and may also - * include a single newline before its terminating null. The first character - * may also be a plus sign, but not a minus sign. - * @base: The number base to use. The maximum supported base is 16. If base is - * given as 0, then the base of the string is automatically detected with the - * conventional semantics - If it begins with 0x the number will be parsed as a - * hexadecimal (case insensitive), if it otherwise begins with 0, it will be - * parsed as an octal number. Otherwise it will be parsed as a decimal. - * @res: Where to write the result of the conversion on success. - * - * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. - * Used as a replacement for the obsolete simple_strtoull. Return code must - * be checked. -*/ -static inline int __must_check kstrtoul(const char *s, unsigned int base, unsigned long *res) -{ - /* - * We want to shortcut function call, but - * __builtin_types_compatible_p(unsigned long, unsigned long long) = 0. - */ - if (sizeof(unsigned long) == sizeof(unsigned long long) && - __alignof__(unsigned long) == __alignof__(unsigned long long)) - return kstrtoull(s, base, (unsigned long long *)res); - else - return _kstrtoul(s, base, res); -} - -/** - * kstrtol - convert a string to a long - * @s: The start of the string. The string must be null-terminated, and may also - * include a single newline before its terminating null. The first character - * may also be a plus sign or a minus sign. - * @base: The number base to use. The maximum supported base is 16. If base is - * given as 0, then the base of the string is automatically detected with the - * conventional semantics - If it begins with 0x the number will be parsed as a - * hexadecimal (case insensitive), if it otherwise begins with 0, it will be - * parsed as an octal number. Otherwise it will be parsed as a decimal. - * @res: Where to write the result of the conversion on success. - * - * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. - * Used as a replacement for the obsolete simple_strtoull. Return code must - * be checked. - */ -static inline int __must_check kstrtol(const char *s, unsigned int base, long *res) -{ - /* - * We want to shortcut function call, but - * __builtin_types_compatible_p(long, long long) = 0. - */ - if (sizeof(long) == sizeof(long long) && - __alignof__(long) == __alignof__(long long)) - return kstrtoll(s, base, (long long *)res); - else - return _kstrtol(s, base, res); -} - -int __must_check kstrtouint(const char *s, unsigned int base, unsigned int *res); -int __must_check kstrtoint(const char *s, unsigned int base, int *res); - -static inline int __must_check kstrtou64(const char *s, unsigned int base, u64 *res) -{ - return kstrtoull(s, base, res); -} - -static inline int __must_check kstrtos64(const char *s, unsigned int base, s64 *res) -{ - return kstrtoll(s, base, res); -} - -static inline int __must_check kstrtou32(const char *s, unsigned int base, u32 *res) -{ - return kstrtouint(s, base, res); -} - -static inline int __must_check kstrtos32(const char *s, unsigned int base, s32 *res) -{ - return kstrtoint(s, base, res); -} - -int __must_check kstrtou16(const char *s, unsigned int base, u16 *res); -int __must_check kstrtos16(const char *s, unsigned int base, s16 *res); -int __must_check kstrtou8(const char *s, unsigned int base, u8 *res); -int __must_check kstrtos8(const char *s, unsigned int base, s8 *res); -int __must_check kstrtobool(const char *s, bool *res); - -int __must_check kstrtoull_from_user(const char __user *s, size_t count, unsigned int base, unsigned long long *res); -int __must_check kstrtoll_from_user(const char __user *s, size_t count, unsigned int base, long long *res); -int __must_check kstrtoul_from_user(const char __user *s, size_t count, unsigned int base, unsigned long *res); -int __must_check kstrtol_from_user(const char __user *s, size_t count, unsigned int base, long *res); -int __must_check kstrtouint_from_user(const char __user *s, size_t count, unsigned int base, unsigned int *res); -int __must_check kstrtoint_from_user(const char __user *s, size_t count, unsigned int base, int *res); -int __must_check kstrtou16_from_user(const char __user *s, size_t count, unsigned int base, u16 *res); -int __must_check kstrtos16_from_user(const char __user *s, size_t count, unsigned int base, s16 *res); -int __must_check kstrtou8_from_user(const char __user *s, size_t count, unsigned int base, u8 *res); -int __must_check kstrtos8_from_user(const char __user *s, size_t count, unsigned int base, s8 *res); -int __must_check kstrtobool_from_user(const char __user *s, size_t count, bool *res); - -static inline int __must_check kstrtou64_from_user(const char __user *s, size_t count, unsigned int base, u64 *res) -{ - return kstrtoull_from_user(s, count, base, res); -} - -static inline int __must_check kstrtos64_from_user(const char __user *s, size_t count, unsigned int base, s64 *res) -{ - return kstrtoll_from_user(s, count, base, res); -} - -static inline int __must_check kstrtou32_from_user(const char __user *s, size_t count, unsigned int base, u32 *res) -{ - return kstrtouint_from_user(s, count, base, res); -} - -static inline int __must_check kstrtos32_from_user(const char __user *s, size_t count, unsigned int base, s32 *res) -{ - return kstrtoint_from_user(s, count, base, res); -} - -/* Obsolete, do not use. Use kstrto instead */ - -extern unsigned long simple_strtoul(const char *,char **,unsigned int); -extern long simple_strtol(const char *,char **,unsigned int); -extern unsigned long long simple_strtoull(const char *,char **,unsigned int); -extern long long simple_strtoll(const char *,char **,unsigned int); - -extern int num_to_str(char *buf, int size, unsigned long long num); - -/* lib/printf utilities */ - -extern __printf(2, 3) int sprintf(char *buf, const char * fmt, ...); -extern __printf(2, 0) int vsprintf(char *buf, const char *, va_list); -extern __printf(3, 4) -int snprintf(char *buf, size_t size, const char *fmt, ...); -extern __printf(3, 0) -int vsnprintf(char *buf, size_t size, const char *fmt, va_list args); -extern __printf(3, 4) -int scnprintf(char *buf, size_t size, const char *fmt, ...); -extern __printf(3, 0) -int vscnprintf(char *buf, size_t size, const char *fmt, va_list args); -extern __printf(2, 3) __malloc -char *kasprintf(gfp_t gfp, const char *fmt, ...); -extern __printf(2, 0) __malloc -char *kvasprintf(gfp_t gfp, const char *fmt, va_list args); -extern __printf(2, 0) -const char *kvasprintf_const(gfp_t gfp, const char *fmt, va_list args); - -extern __scanf(2, 3) -int sscanf(const char *, const char *, ...); -extern __scanf(2, 0) -int vsscanf(const char *, const char *, va_list); - -extern int get_option(char **str, int *pint); -extern char *get_options(const char *str, int nints, int *ints); -extern unsigned long long memparse(const char *ptr, char **retptr); -extern bool parse_option_str(const char *str, const char *option); - -extern int core_kernel_text(unsigned long addr); -extern int core_kernel_data(unsigned long addr); -extern int __kernel_text_address(unsigned long addr); -extern int kernel_text_address(unsigned long addr); -extern int func_ptr_is_kernel_text(void *ptr); - -unsigned long int_sqrt(unsigned long); - -extern void bust_spinlocks(int yes); -extern int oops_in_progress; /* If set, an oops, panic(), BUG() or die() is in progress */ -extern int panic_timeout; -extern int panic_on_oops; -extern int panic_on_unrecovered_nmi; -extern int panic_on_io_nmi; -extern int panic_on_warn; -extern int sysctl_panic_on_rcu_stall; -extern int sysctl_panic_on_stackoverflow; - -extern bool crash_kexec_post_notifiers; - -/* - * panic_cpu is used for synchronizing panic() and crash_kexec() execution. It - * holds a CPU number which is executing panic() currently. A value of - * PANIC_CPU_INVALID means no CPU has entered panic() or crash_kexec(). - */ -extern atomic_t panic_cpu; -#define PANIC_CPU_INVALID -1 - -/* - * Only to be used by arch init code. If the user over-wrote the default - * CONFIG_PANIC_TIMEOUT, honor it. - */ -static inline void set_arch_panic_timeout(int timeout, int arch_default_timeout) -{ - if (panic_timeout == arch_default_timeout) - panic_timeout = timeout; -} -extern const char *print_tainted(void); -enum lockdep_ok { - LOCKDEP_STILL_OK, - LOCKDEP_NOW_UNRELIABLE -}; -extern void add_taint(unsigned flag, enum lockdep_ok); -extern int test_taint(unsigned flag); -extern unsigned long get_taint(void); -extern int root_mountflags; - -extern bool early_boot_irqs_disabled; - -/* Values used for system_state */ -extern enum system_states { - SYSTEM_BOOTING, - SYSTEM_RUNNING, - SYSTEM_HALT, - SYSTEM_POWER_OFF, - SYSTEM_RESTART, -} system_state; - -#define TAINT_PROPRIETARY_MODULE 0 -#define TAINT_FORCED_MODULE 1 -#define TAINT_CPU_OUT_OF_SPEC 2 -#define TAINT_FORCED_RMMOD 3 -#define TAINT_MACHINE_CHECK 4 -#define TAINT_BAD_PAGE 5 -#define TAINT_USER 6 -#define TAINT_DIE 7 -#define TAINT_OVERRIDDEN_ACPI_TABLE 8 -#define TAINT_WARN 9 -#define TAINT_CRAP 10 -#define TAINT_FIRMWARE_WORKAROUND 11 -#define TAINT_OOT_MODULE 12 -#define TAINT_UNSIGNED_MODULE 13 -#define TAINT_SOFTLOCKUP 14 -#define TAINT_LIVEPATCH 15 - -extern const char hex_asc[]; -#define hex_asc_lo(x) hex_asc[((x) & 0x0f)] -#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4] - -static inline char *hex_byte_pack(char *buf, u8 byte) -{ - *buf++ = hex_asc_hi(byte); - *buf++ = hex_asc_lo(byte); - return buf; -} - -extern const char hex_asc_upper[]; -#define hex_asc_upper_lo(x) hex_asc_upper[((x) & 0x0f)] -#define hex_asc_upper_hi(x) hex_asc_upper[((x) & 0xf0) >> 4] - -static inline char *hex_byte_pack_upper(char *buf, u8 byte) -{ - *buf++ = hex_asc_upper_hi(byte); - *buf++ = hex_asc_upper_lo(byte); - return buf; -} - -extern int hex_to_bin(char ch); -extern int __must_check hex2bin(u8 *dst, const char *src, size_t count); -extern char *bin2hex(char *dst, const void *src, size_t count); - -bool mac_pton(const char *s, u8 *mac); - -/* - * General tracing related utility functions - trace_printk(), - * tracing_on/tracing_off and tracing_start()/tracing_stop - * - * Use tracing_on/tracing_off when you want to quickly turn on or off - * tracing. It simply enables or disables the recording of the trace events. - * This also corresponds to the user space /sys/kernel/debug/tracing/tracing_on - * file, which gives a means for the kernel and userspace to interact. - * Place a tracing_off() in the kernel where you want tracing to end. - * From user space, examine the trace, and then echo 1 > tracing_on - * to continue tracing. - * - * tracing_stop/tracing_start has slightly more overhead. It is used - * by things like suspend to ram where disabling the recording of the - * trace is not enough, but tracing must actually stop because things - * like calling smp_processor_id() may crash the system. - * - * Most likely, you want to use tracing_on/tracing_off. - */ - -enum ftrace_dump_mode { - DUMP_NONE, - DUMP_ALL, - DUMP_ORIG, -}; - -#ifdef CONFIG_TRACING -void tracing_on(void); -void tracing_off(void); -int tracing_is_on(void); -void tracing_snapshot(void); -void tracing_snapshot_alloc(void); - -extern void tracing_start(void); -extern void tracing_stop(void); - -static inline __printf(1, 2) -void ____trace_printk_check_format(const char *fmt, ...) -{ -} -#define __trace_printk_check_format(fmt, args...) \ -do { \ - if (0) \ - ____trace_printk_check_format(fmt, ##args); \ -} while (0) - -/** - * trace_printk - printf formatting in the ftrace buffer - * @fmt: the printf format for printing - * - * Note: __trace_printk is an internal function for trace_printk and - * the @ip is passed in via the trace_printk macro. - * - * This function allows a kernel developer to debug fast path sections - * that printk is not appropriate for. By scattering in various - * printk like tracing in the code, a developer can quickly see - * where problems are occurring. - * - * This is intended as a debugging tool for the developer only. - * Please refrain from leaving trace_printks scattered around in - * your code. (Extra memory is used for special buffers that are - * allocated when trace_printk() is used) - * - * A little optization trick is done here. If there's only one - * argument, there's no need to scan the string for printf formats. - * The trace_puts() will suffice. But how can we take advantage of - * using trace_puts() when trace_printk() has only one argument? - * By stringifying the args and checking the size we can tell - * whether or not there are args. __stringify((__VA_ARGS__)) will - * turn into "()\0" with a size of 3 when there are no args, anything - * else will be bigger. All we need to do is define a string to this, - * and then take its size and compare to 3. If it's bigger, use - * do_trace_printk() otherwise, optimize it to trace_puts(). Then just - * let gcc optimize the rest. - */ - -#define trace_printk(fmt, ...) \ -do { \ - char _______STR[] = __stringify((__VA_ARGS__)); \ - if (sizeof(_______STR) > 3) \ - do_trace_printk(fmt, ##__VA_ARGS__); \ - else \ - trace_puts(fmt); \ -} while (0) - -#define do_trace_printk(fmt, args...) \ -do { \ - static const char *trace_printk_fmt __used \ - __attribute__((section("__trace_printk_fmt"))) = \ - __builtin_constant_p(fmt) ? fmt : NULL; \ - \ - __trace_printk_check_format(fmt, ##args); \ - \ - if (__builtin_constant_p(fmt)) \ - __trace_bprintk(_THIS_IP_, trace_printk_fmt, ##args); \ - else \ - __trace_printk(_THIS_IP_, fmt, ##args); \ -} while (0) - -extern __printf(2, 3) -int __trace_bprintk(unsigned long ip, const char *fmt, ...); - -extern __printf(2, 3) -int __trace_printk(unsigned long ip, const char *fmt, ...); - -/** - * trace_puts - write a string into the ftrace buffer - * @str: the string to record - * - * Note: __trace_bputs is an internal function for trace_puts and - * the @ip is passed in via the trace_puts macro. - * - * This is similar to trace_printk() but is made for those really fast - * paths that a developer wants the least amount of "Heisenbug" affects, - * where the processing of the print format is still too much. - * - * This function allows a kernel developer to debug fast path sections - * that printk is not appropriate for. By scattering in various - * printk like tracing in the code, a developer can quickly see - * where problems are occurring. - * - * This is intended as a debugging tool for the developer only. - * Please refrain from leaving trace_puts scattered around in - * your code. (Extra memory is used for special buffers that are - * allocated when trace_puts() is used) - * - * Returns: 0 if nothing was written, positive # if string was. - * (1 when __trace_bputs is used, strlen(str) when __trace_puts is used) - */ - -#define trace_puts(str) ({ \ - static const char *trace_printk_fmt __used \ - __attribute__((section("__trace_printk_fmt"))) = \ - __builtin_constant_p(str) ? str : NULL; \ - \ - if (__builtin_constant_p(str)) \ - __trace_bputs(_THIS_IP_, trace_printk_fmt); \ - else \ - __trace_puts(_THIS_IP_, str, strlen(str)); \ -}) -extern int __trace_bputs(unsigned long ip, const char *str); -extern int __trace_puts(unsigned long ip, const char *str, int size); - -extern void trace_dump_stack(int skip); - -/* - * The double __builtin_constant_p is because gcc will give us an error - * if we try to allocate the static variable to fmt if it is not a - * constant. Even with the outer if statement. - */ -#define ftrace_vprintk(fmt, vargs) \ -do { \ - if (__builtin_constant_p(fmt)) { \ - static const char *trace_printk_fmt __used \ - __attribute__((section("__trace_printk_fmt"))) = \ - __builtin_constant_p(fmt) ? fmt : NULL; \ - \ - __ftrace_vbprintk(_THIS_IP_, trace_printk_fmt, vargs); \ - } else \ - __ftrace_vprintk(_THIS_IP_, fmt, vargs); \ -} while (0) - -extern __printf(2, 0) int -__ftrace_vbprintk(unsigned long ip, const char *fmt, va_list ap); - -extern __printf(2, 0) int -__ftrace_vprintk(unsigned long ip, const char *fmt, va_list ap); - -extern void ftrace_dump(enum ftrace_dump_mode oops_dump_mode); -#else -static inline void tracing_start(void) { } -static inline void tracing_stop(void) { } -static inline void trace_dump_stack(int skip) { } - -static inline void tracing_on(void) { } -static inline void tracing_off(void) { } -static inline int tracing_is_on(void) { return 0; } -static inline void tracing_snapshot(void) { } -static inline void tracing_snapshot_alloc(void) { } - -static inline __printf(1, 2) -int trace_printk(const char *fmt, ...) -{ - return 0; -} -static __printf(1, 0) inline int -ftrace_vprintk(const char *fmt, va_list ap) -{ - return 0; -} -static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { } -#endif /* CONFIG_TRACING */ - -/* - * min()/max()/clamp() macros that also do - * strict type-checking.. See the - * "unnecessary" pointer comparison. - */ -#define __min(t1, t2, min1, min2, x, y) ({ \ - t1 min1 = (x); \ - t2 min2 = (y); \ - (void) (&min1 == &min2); \ - min1 < min2 ? min1 : min2; }) -#define min(x, y) \ - __min(typeof(x), typeof(y), \ - __UNIQUE_ID(min1_), __UNIQUE_ID(min2_), \ - x, y) - -#define __max(t1, t2, max1, max2, x, y) ({ \ - t1 max1 = (x); \ - t2 max2 = (y); \ - (void) (&max1 == &max2); \ - max1 > max2 ? max1 : max2; }) -#define max(x, y) \ - __max(typeof(x), typeof(y), \ - __UNIQUE_ID(max1_), __UNIQUE_ID(max2_), \ - x, y) - -#define min3(x, y, z) min((typeof(x))min(x, y), z) -#define max3(x, y, z) max((typeof(x))max(x, y), z) - -/** - * min_not_zero - return the minimum that is _not_ zero, unless both are zero - * @x: value1 - * @y: value2 - */ -#define min_not_zero(x, y) ({ \ - typeof(x) __x = (x); \ - typeof(y) __y = (y); \ - __x == 0 ? __y : ((__y == 0) ? __x : min(__x, __y)); }) - -/** - * clamp - return a value clamped to a given range with strict typechecking - * @val: current value - * @lo: lowest allowable value - * @hi: highest allowable value - * - * This macro does strict typechecking of lo/hi to make sure they are of the - * same type as val. See the unnecessary pointer comparisons. - */ -#define clamp(val, lo, hi) min((typeof(val))max(val, lo), hi) - -/* - * ..and if you can't take the strict - * types, you can specify one yourself. - * - * Or not use min/max/clamp at all, of course. - */ -#define min_t(type, x, y) \ - __min(type, type, \ - __UNIQUE_ID(min1_), __UNIQUE_ID(min2_), \ - x, y) - -#define max_t(type, x, y) \ - __max(type, type, \ - __UNIQUE_ID(min1_), __UNIQUE_ID(min2_), \ - x, y) - -/** - * clamp_t - return a value clamped to a given range using a given type - * @type: the type of variable to use - * @val: current value - * @lo: minimum allowable value - * @hi: maximum allowable value - * - * This macro does no typechecking and uses temporary variables of type - * 'type' to make all the comparisons. - */ -#define clamp_t(type, val, lo, hi) min_t(type, max_t(type, val, lo), hi) - -/** - * clamp_val - return a value clamped to a given range using val's type - * @val: current value - * @lo: minimum allowable value - * @hi: maximum allowable value - * - * This macro does no typechecking and uses temporary variables of whatever - * type the input argument 'val' is. This is useful when val is an unsigned - * type and min and max are literals that will otherwise be assigned a signed - * integer type. - */ -#define clamp_val(val, lo, hi) clamp_t(typeof(val), val, lo, hi) - - -/* - * swap - swap value of @a and @b - */ -#define swap(a, b) \ - do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) - -/** - * container_of - cast a member of a structure out to the containing structure - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - * - */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -/* Rebuild everything on CONFIG_FTRACE_MCOUNT_RECORD */ -#ifdef CONFIG_FTRACE_MCOUNT_RECORD -# define REBUILD_DUE_TO_FTRACE_MCOUNT_RECORD -#endif - -/* Permissions on a sysfs file: you didn't miss the 0 prefix did you? */ -#define VERIFY_OCTAL_PERMISSIONS(perms) \ - (BUILD_BUG_ON_ZERO((perms) < 0) + \ - BUILD_BUG_ON_ZERO((perms) > 0777) + \ - /* USER_READABLE >= GROUP_READABLE >= OTHER_READABLE */ \ - BUILD_BUG_ON_ZERO((((perms) >> 6) & 4) < (((perms) >> 3) & 4)) + \ - BUILD_BUG_ON_ZERO((((perms) >> 3) & 4) < ((perms) & 4)) + \ - /* USER_WRITABLE >= GROUP_WRITABLE */ \ - BUILD_BUG_ON_ZERO((((perms) >> 6) & 2) < (((perms) >> 3) & 2)) + \ - /* OTHER_WRITABLE? Generally considered a bad idea. */ \ - BUILD_BUG_ON_ZERO((perms) & 2) + \ - (perms)) -#endif diff --git a/src/linux/include/linux/kernel_stat.h b/src/linux/include/linux/kernel_stat.h deleted file mode 100644 index 44fda64..0000000 --- a/src/linux/include/linux/kernel_stat.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef _LINUX_KERNEL_STAT_H -#define _LINUX_KERNEL_STAT_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * 'kernel_stat.h' contains the definitions needed for doing - * some kernel statistics (CPU usage, context switches ...), - * used by rstatd/perfmeter - */ - -enum cpu_usage_stat { - CPUTIME_USER, - CPUTIME_NICE, - CPUTIME_SYSTEM, - CPUTIME_SOFTIRQ, - CPUTIME_IRQ, - CPUTIME_IDLE, - CPUTIME_IOWAIT, - CPUTIME_STEAL, - CPUTIME_GUEST, - CPUTIME_GUEST_NICE, - NR_STATS, -}; - -struct kernel_cpustat { - u64 cpustat[NR_STATS]; -}; - -struct kernel_stat { - unsigned long irqs_sum; - unsigned int softirqs[NR_SOFTIRQS]; -}; - -DECLARE_PER_CPU(struct kernel_stat, kstat); -DECLARE_PER_CPU(struct kernel_cpustat, kernel_cpustat); - -/* Must have preemption disabled for this to be meaningful. */ -#define kstat_this_cpu this_cpu_ptr(&kstat) -#define kcpustat_this_cpu this_cpu_ptr(&kernel_cpustat) -#define kstat_cpu(cpu) per_cpu(kstat, cpu) -#define kcpustat_cpu(cpu) per_cpu(kernel_cpustat, cpu) - -extern unsigned long long nr_context_switches(void); - -extern unsigned int kstat_irqs_cpu(unsigned int irq, int cpu); -extern void kstat_incr_irq_this_cpu(unsigned int irq); - -static inline void kstat_incr_softirqs_this_cpu(unsigned int irq) -{ - __this_cpu_inc(kstat.softirqs[irq]); -} - -static inline unsigned int kstat_softirqs_cpu(unsigned int irq, int cpu) -{ - return kstat_cpu(cpu).softirqs[irq]; -} - -/* - * Number of interrupts per specific IRQ source, since bootup - */ -extern unsigned int kstat_irqs(unsigned int irq); -extern unsigned int kstat_irqs_usr(unsigned int irq); - -/* - * Number of interrupts per cpu, since bootup - */ -static inline unsigned int kstat_cpu_irqs_sum(unsigned int cpu) -{ - return kstat_cpu(cpu).irqs_sum; -} - -extern void account_user_time(struct task_struct *, cputime_t, cputime_t); -extern void account_system_time(struct task_struct *, int, cputime_t, cputime_t); -extern void account_steal_time(cputime_t); -extern void account_idle_time(cputime_t); - -#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE -static inline void account_process_tick(struct task_struct *tsk, int user) -{ - vtime_account_user(tsk); -} -#else -extern void account_process_tick(struct task_struct *, int user); -#endif - -extern void account_idle_ticks(unsigned long ticks); - -#endif /* _LINUX_KERNEL_STAT_H */ diff --git a/src/linux/include/linux/kernfs.h b/src/linux/include/linux/kernfs.h deleted file mode 100644 index 7056238..0000000 --- a/src/linux/include/linux/kernfs.h +++ /dev/null @@ -1,513 +0,0 @@ -/* - * kernfs.h - pseudo filesystem decoupled from vfs locking - * - * This file is released under the GPLv2. - */ - -#ifndef __LINUX_KERNFS_H -#define __LINUX_KERNFS_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct file; -struct dentry; -struct iattr; -struct seq_file; -struct vm_area_struct; -struct super_block; -struct file_system_type; - -struct kernfs_open_node; -struct kernfs_iattrs; - -enum kernfs_node_type { - KERNFS_DIR = 0x0001, - KERNFS_FILE = 0x0002, - KERNFS_LINK = 0x0004, -}; - -#define KERNFS_TYPE_MASK 0x000f -#define KERNFS_FLAG_MASK ~KERNFS_TYPE_MASK - -enum kernfs_node_flag { - KERNFS_ACTIVATED = 0x0010, - KERNFS_NS = 0x0020, - KERNFS_HAS_SEQ_SHOW = 0x0040, - KERNFS_HAS_MMAP = 0x0080, - KERNFS_LOCKDEP = 0x0100, - KERNFS_SUICIDAL = 0x0400, - KERNFS_SUICIDED = 0x0800, - KERNFS_EMPTY_DIR = 0x1000, -}; - -/* @flags for kernfs_create_root() */ -enum kernfs_root_flag { - /* - * kernfs_nodes are created in the deactivated state and invisible. - * They require explicit kernfs_activate() to become visible. This - * can be used to make related nodes become visible atomically - * after all nodes are created successfully. - */ - KERNFS_ROOT_CREATE_DEACTIVATED = 0x0001, - - /* - * For regular flies, if the opener has CAP_DAC_OVERRIDE, open(2) - * succeeds regardless of the RW permissions. sysfs had an extra - * layer of enforcement where open(2) fails with -EACCES regardless - * of CAP_DAC_OVERRIDE if the permission doesn't have the - * respective read or write access at all (none of S_IRUGO or - * S_IWUGO) or the respective operation isn't implemented. The - * following flag enables that behavior. - */ - KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK = 0x0002, -}; - -/* type-specific structures for kernfs_node union members */ -struct kernfs_elem_dir { - unsigned long subdirs; - /* children rbtree starts here and goes through kn->rb */ - struct rb_root children; - - /* - * The kernfs hierarchy this directory belongs to. This fits - * better directly in kernfs_node but is here to save space. - */ - struct kernfs_root *root; -}; - -struct kernfs_elem_symlink { - struct kernfs_node *target_kn; -}; - -struct kernfs_elem_attr { - const struct kernfs_ops *ops; - struct kernfs_open_node *open; - loff_t size; - struct kernfs_node *notify_next; /* for kernfs_notify() */ -}; - -/* - * kernfs_node - the building block of kernfs hierarchy. Each and every - * kernfs node is represented by single kernfs_node. Most fields are - * private to kernfs and shouldn't be accessed directly by kernfs users. - * - * As long as s_count reference is held, the kernfs_node itself is - * accessible. Dereferencing elem or any other outer entity requires - * active reference. - */ -struct kernfs_node { - atomic_t count; - atomic_t active; -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map dep_map; -#endif - /* - * Use kernfs_get_parent() and kernfs_name/path() instead of - * accessing the following two fields directly. If the node is - * never moved to a different parent, it is safe to access the - * parent directly. - */ - struct kernfs_node *parent; - const char *name; - - struct rb_node rb; - - const void *ns; /* namespace tag */ - unsigned int hash; /* ns + name hash */ - union { - struct kernfs_elem_dir dir; - struct kernfs_elem_symlink symlink; - struct kernfs_elem_attr attr; - }; - - void *priv; - - unsigned short flags; - umode_t mode; - unsigned int ino; - struct kernfs_iattrs *iattr; -}; - -/* - * kernfs_syscall_ops may be specified on kernfs_create_root() to support - * syscalls. These optional callbacks are invoked on the matching syscalls - * and can perform any kernfs operations which don't necessarily have to be - * the exact operation requested. An active reference is held for each - * kernfs_node parameter. - */ -struct kernfs_syscall_ops { - int (*remount_fs)(struct kernfs_root *root, int *flags, char *data); - int (*show_options)(struct seq_file *sf, struct kernfs_root *root); - - int (*mkdir)(struct kernfs_node *parent, const char *name, - umode_t mode); - int (*rmdir)(struct kernfs_node *kn); - int (*rename)(struct kernfs_node *kn, struct kernfs_node *new_parent, - const char *new_name); - int (*show_path)(struct seq_file *sf, struct kernfs_node *kn, - struct kernfs_root *root); -}; - -struct kernfs_root { - /* published fields */ - struct kernfs_node *kn; - unsigned int flags; /* KERNFS_ROOT_* flags */ - - /* private fields, do not use outside kernfs proper */ - struct ida ino_ida; - struct kernfs_syscall_ops *syscall_ops; - - /* list of kernfs_super_info of this root, protected by kernfs_mutex */ - struct list_head supers; - - wait_queue_head_t deactivate_waitq; -}; - -struct kernfs_open_file { - /* published fields */ - struct kernfs_node *kn; - struct file *file; - void *priv; - - /* private fields, do not use outside kernfs proper */ - struct mutex mutex; - struct mutex prealloc_mutex; - int event; - struct list_head list; - char *prealloc_buf; - - size_t atomic_write_len; - bool mmapped; - const struct vm_operations_struct *vm_ops; -}; - -struct kernfs_ops { - /* - * Read is handled by either seq_file or raw_read(). - * - * If seq_show() is present, seq_file path is active. Other seq - * operations are optional and if not implemented, the behavior is - * equivalent to single_open(). @sf->private points to the - * associated kernfs_open_file. - * - * read() is bounced through kernel buffer and a read larger than - * PAGE_SIZE results in partial operation of PAGE_SIZE. - */ - int (*seq_show)(struct seq_file *sf, void *v); - - void *(*seq_start)(struct seq_file *sf, loff_t *ppos); - void *(*seq_next)(struct seq_file *sf, void *v, loff_t *ppos); - void (*seq_stop)(struct seq_file *sf, void *v); - - ssize_t (*read)(struct kernfs_open_file *of, char *buf, size_t bytes, - loff_t off); - - /* - * write() is bounced through kernel buffer. If atomic_write_len - * is not set, a write larger than PAGE_SIZE results in partial - * operations of PAGE_SIZE chunks. If atomic_write_len is set, - * writes upto the specified size are executed atomically but - * larger ones are rejected with -E2BIG. - */ - size_t atomic_write_len; - /* - * "prealloc" causes a buffer to be allocated at open for - * all read/write requests. As ->seq_show uses seq_read() - * which does its own allocation, it is incompatible with - * ->prealloc. Provide ->read and ->write with ->prealloc. - */ - bool prealloc; - ssize_t (*write)(struct kernfs_open_file *of, char *buf, size_t bytes, - loff_t off); - - int (*mmap)(struct kernfs_open_file *of, struct vm_area_struct *vma); - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lock_class_key lockdep_key; -#endif -}; - -#ifdef CONFIG_KERNFS - -static inline enum kernfs_node_type kernfs_type(struct kernfs_node *kn) -{ - return kn->flags & KERNFS_TYPE_MASK; -} - -/** - * kernfs_enable_ns - enable namespace under a directory - * @kn: directory of interest, should be empty - * - * This is to be called right after @kn is created to enable namespace - * under it. All children of @kn must have non-NULL namespace tags and - * only the ones which match the super_block's tag will be visible. - */ -static inline void kernfs_enable_ns(struct kernfs_node *kn) -{ - WARN_ON_ONCE(kernfs_type(kn) != KERNFS_DIR); - WARN_ON_ONCE(!RB_EMPTY_ROOT(&kn->dir.children)); - kn->flags |= KERNFS_NS; -} - -/** - * kernfs_ns_enabled - test whether namespace is enabled - * @kn: the node to test - * - * Test whether namespace filtering is enabled for the children of @ns. - */ -static inline bool kernfs_ns_enabled(struct kernfs_node *kn) -{ - return kn->flags & KERNFS_NS; -} - -int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen); -int kernfs_path_from_node(struct kernfs_node *root_kn, struct kernfs_node *kn, - char *buf, size_t buflen); -void pr_cont_kernfs_name(struct kernfs_node *kn); -void pr_cont_kernfs_path(struct kernfs_node *kn); -struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn); -struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent, - const char *name, const void *ns); -struct kernfs_node *kernfs_walk_and_get_ns(struct kernfs_node *parent, - const char *path, const void *ns); -void kernfs_get(struct kernfs_node *kn); -void kernfs_put(struct kernfs_node *kn); - -struct kernfs_node *kernfs_node_from_dentry(struct dentry *dentry); -struct kernfs_root *kernfs_root_from_sb(struct super_block *sb); -struct inode *kernfs_get_inode(struct super_block *sb, struct kernfs_node *kn); - -struct dentry *kernfs_node_dentry(struct kernfs_node *kn, - struct super_block *sb); -struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops, - unsigned int flags, void *priv); -void kernfs_destroy_root(struct kernfs_root *root); - -struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent, - const char *name, umode_t mode, - void *priv, const void *ns); -struct kernfs_node *kernfs_create_empty_dir(struct kernfs_node *parent, - const char *name); -struct kernfs_node *__kernfs_create_file(struct kernfs_node *parent, - const char *name, - umode_t mode, loff_t size, - const struct kernfs_ops *ops, - void *priv, const void *ns, - struct lock_class_key *key); -struct kernfs_node *kernfs_create_link(struct kernfs_node *parent, - const char *name, - struct kernfs_node *target); -void kernfs_activate(struct kernfs_node *kn); -void kernfs_remove(struct kernfs_node *kn); -void kernfs_break_active_protection(struct kernfs_node *kn); -void kernfs_unbreak_active_protection(struct kernfs_node *kn); -bool kernfs_remove_self(struct kernfs_node *kn); -int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, - const void *ns); -int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent, - const char *new_name, const void *new_ns); -int kernfs_setattr(struct kernfs_node *kn, const struct iattr *iattr); -void kernfs_notify(struct kernfs_node *kn); - -const void *kernfs_super_ns(struct super_block *sb); -struct dentry *kernfs_mount_ns(struct file_system_type *fs_type, int flags, - struct kernfs_root *root, unsigned long magic, - bool *new_sb_created, const void *ns); -void kernfs_kill_sb(struct super_block *sb); -struct super_block *kernfs_pin_sb(struct kernfs_root *root, const void *ns); - -void kernfs_init(void); - -#else /* CONFIG_KERNFS */ - -static inline enum kernfs_node_type kernfs_type(struct kernfs_node *kn) -{ return 0; } /* whatever */ - -static inline void kernfs_enable_ns(struct kernfs_node *kn) { } - -static inline bool kernfs_ns_enabled(struct kernfs_node *kn) -{ return false; } - -static inline int kernfs_name(struct kernfs_node *kn, char *buf, size_t buflen) -{ return -ENOSYS; } - -static inline int kernfs_path_from_node(struct kernfs_node *root_kn, - struct kernfs_node *kn, - char *buf, size_t buflen) -{ return -ENOSYS; } - -static inline void pr_cont_kernfs_name(struct kernfs_node *kn) { } -static inline void pr_cont_kernfs_path(struct kernfs_node *kn) { } - -static inline struct kernfs_node *kernfs_get_parent(struct kernfs_node *kn) -{ return NULL; } - -static inline struct kernfs_node * -kernfs_find_and_get_ns(struct kernfs_node *parent, const char *name, - const void *ns) -{ return NULL; } -static inline struct kernfs_node * -kernfs_walk_and_get_ns(struct kernfs_node *parent, const char *path, - const void *ns) -{ return NULL; } - -static inline void kernfs_get(struct kernfs_node *kn) { } -static inline void kernfs_put(struct kernfs_node *kn) { } - -static inline struct kernfs_node *kernfs_node_from_dentry(struct dentry *dentry) -{ return NULL; } - -static inline struct kernfs_root *kernfs_root_from_sb(struct super_block *sb) -{ return NULL; } - -static inline struct inode * -kernfs_get_inode(struct super_block *sb, struct kernfs_node *kn) -{ return NULL; } - -static inline struct kernfs_root * -kernfs_create_root(struct kernfs_syscall_ops *scops, unsigned int flags, - void *priv) -{ return ERR_PTR(-ENOSYS); } - -static inline void kernfs_destroy_root(struct kernfs_root *root) { } - -static inline struct kernfs_node * -kernfs_create_dir_ns(struct kernfs_node *parent, const char *name, - umode_t mode, void *priv, const void *ns) -{ return ERR_PTR(-ENOSYS); } - -static inline struct kernfs_node * -__kernfs_create_file(struct kernfs_node *parent, const char *name, - umode_t mode, loff_t size, const struct kernfs_ops *ops, - void *priv, const void *ns, struct lock_class_key *key) -{ return ERR_PTR(-ENOSYS); } - -static inline struct kernfs_node * -kernfs_create_link(struct kernfs_node *parent, const char *name, - struct kernfs_node *target) -{ return ERR_PTR(-ENOSYS); } - -static inline void kernfs_activate(struct kernfs_node *kn) { } - -static inline void kernfs_remove(struct kernfs_node *kn) { } - -static inline bool kernfs_remove_self(struct kernfs_node *kn) -{ return false; } - -static inline int kernfs_remove_by_name_ns(struct kernfs_node *kn, - const char *name, const void *ns) -{ return -ENOSYS; } - -static inline int kernfs_rename_ns(struct kernfs_node *kn, - struct kernfs_node *new_parent, - const char *new_name, const void *new_ns) -{ return -ENOSYS; } - -static inline int kernfs_setattr(struct kernfs_node *kn, - const struct iattr *iattr) -{ return -ENOSYS; } - -static inline void kernfs_notify(struct kernfs_node *kn) { } - -static inline const void *kernfs_super_ns(struct super_block *sb) -{ return NULL; } - -static inline struct dentry * -kernfs_mount_ns(struct file_system_type *fs_type, int flags, - struct kernfs_root *root, unsigned long magic, - bool *new_sb_created, const void *ns) -{ return ERR_PTR(-ENOSYS); } - -static inline void kernfs_kill_sb(struct super_block *sb) { } - -static inline void kernfs_init(void) { } - -#endif /* CONFIG_KERNFS */ - -/** - * kernfs_path - build full path of a given node - * @kn: kernfs_node of interest - * @buf: buffer to copy @kn's name into - * @buflen: size of @buf - * - * Builds and returns the full path of @kn in @buf of @buflen bytes. The - * path is built from the end of @buf so the returned pointer usually - * doesn't match @buf. If @buf isn't long enough, @buf is nul terminated - * and %NULL is returned. - */ -static inline int kernfs_path(struct kernfs_node *kn, char *buf, size_t buflen) -{ - return kernfs_path_from_node(kn, NULL, buf, buflen); -} - -static inline struct kernfs_node * -kernfs_find_and_get(struct kernfs_node *kn, const char *name) -{ - return kernfs_find_and_get_ns(kn, name, NULL); -} - -static inline struct kernfs_node * -kernfs_walk_and_get(struct kernfs_node *kn, const char *path) -{ - return kernfs_walk_and_get_ns(kn, path, NULL); -} - -static inline struct kernfs_node * -kernfs_create_dir(struct kernfs_node *parent, const char *name, umode_t mode, - void *priv) -{ - return kernfs_create_dir_ns(parent, name, mode, priv, NULL); -} - -static inline struct kernfs_node * -kernfs_create_file_ns(struct kernfs_node *parent, const char *name, - umode_t mode, loff_t size, const struct kernfs_ops *ops, - void *priv, const void *ns) -{ - struct lock_class_key *key = NULL; - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - key = (struct lock_class_key *)&ops->lockdep_key; -#endif - return __kernfs_create_file(parent, name, mode, size, ops, priv, ns, - key); -} - -static inline struct kernfs_node * -kernfs_create_file(struct kernfs_node *parent, const char *name, umode_t mode, - loff_t size, const struct kernfs_ops *ops, void *priv) -{ - return kernfs_create_file_ns(parent, name, mode, size, ops, priv, NULL); -} - -static inline int kernfs_remove_by_name(struct kernfs_node *parent, - const char *name) -{ - return kernfs_remove_by_name_ns(parent, name, NULL); -} - -static inline int kernfs_rename(struct kernfs_node *kn, - struct kernfs_node *new_parent, - const char *new_name) -{ - return kernfs_rename_ns(kn, new_parent, new_name, NULL); -} - -static inline struct dentry * -kernfs_mount(struct file_system_type *fs_type, int flags, - struct kernfs_root *root, unsigned long magic, - bool *new_sb_created) -{ - return kernfs_mount_ns(fs_type, flags, root, - magic, new_sb_created, NULL); -} - -#endif /* __LINUX_KERNFS_H */ diff --git a/src/linux/include/linux/kexec.h b/src/linux/include/linux/kexec.h deleted file mode 100644 index 406c33d..0000000 --- a/src/linux/include/linux/kexec.h +++ /dev/null @@ -1,380 +0,0 @@ -#ifndef LINUX_KEXEC_H -#define LINUX_KEXEC_H - -#define IND_DESTINATION_BIT 0 -#define IND_INDIRECTION_BIT 1 -#define IND_DONE_BIT 2 -#define IND_SOURCE_BIT 3 - -#define IND_DESTINATION (1 << IND_DESTINATION_BIT) -#define IND_INDIRECTION (1 << IND_INDIRECTION_BIT) -#define IND_DONE (1 << IND_DONE_BIT) -#define IND_SOURCE (1 << IND_SOURCE_BIT) -#define IND_FLAGS (IND_DESTINATION | IND_INDIRECTION | IND_DONE | IND_SOURCE) - -#if !defined(__ASSEMBLY__) - -#include - -#include - -#ifdef CONFIG_KEXEC_CORE -#include -#include -#include -#include -#include -#include -#include -#include - -/* Verify architecture specific macros are defined */ - -#ifndef KEXEC_SOURCE_MEMORY_LIMIT -#error KEXEC_SOURCE_MEMORY_LIMIT not defined -#endif - -#ifndef KEXEC_DESTINATION_MEMORY_LIMIT -#error KEXEC_DESTINATION_MEMORY_LIMIT not defined -#endif - -#ifndef KEXEC_CONTROL_MEMORY_LIMIT -#error KEXEC_CONTROL_MEMORY_LIMIT not defined -#endif - -#ifndef KEXEC_CONTROL_MEMORY_GFP -#define KEXEC_CONTROL_MEMORY_GFP (GFP_KERNEL | __GFP_NORETRY) -#endif - -#ifndef KEXEC_CONTROL_PAGE_SIZE -#error KEXEC_CONTROL_PAGE_SIZE not defined -#endif - -#ifndef KEXEC_ARCH -#error KEXEC_ARCH not defined -#endif - -#ifndef KEXEC_CRASH_CONTROL_MEMORY_LIMIT -#define KEXEC_CRASH_CONTROL_MEMORY_LIMIT KEXEC_CONTROL_MEMORY_LIMIT -#endif - -#ifndef KEXEC_CRASH_MEM_ALIGN -#define KEXEC_CRASH_MEM_ALIGN PAGE_SIZE -#endif - -#define KEXEC_NOTE_HEAD_BYTES ALIGN(sizeof(struct elf_note), 4) -#define KEXEC_CORE_NOTE_NAME "CORE" -#define KEXEC_CORE_NOTE_NAME_BYTES ALIGN(sizeof(KEXEC_CORE_NOTE_NAME), 4) -#define KEXEC_CORE_NOTE_DESC_BYTES ALIGN(sizeof(struct elf_prstatus), 4) -/* - * The per-cpu notes area is a list of notes terminated by a "NULL" - * note header. For kdump, the code in vmcore.c runs in the context - * of the second kernel to combine them into one note. - */ -#ifndef KEXEC_NOTE_BYTES -#define KEXEC_NOTE_BYTES ( (KEXEC_NOTE_HEAD_BYTES * 2) + \ - KEXEC_CORE_NOTE_NAME_BYTES + \ - KEXEC_CORE_NOTE_DESC_BYTES ) -#endif - -/* - * This structure is used to hold the arguments that are used when loading - * kernel binaries. - */ - -typedef unsigned long kimage_entry_t; - -struct kexec_segment { - /* - * This pointer can point to user memory if kexec_load() system - * call is used or will point to kernel memory if - * kexec_file_load() system call is used. - * - * Use ->buf when expecting to deal with user memory and use ->kbuf - * when expecting to deal with kernel memory. - */ - union { - void __user *buf; - void *kbuf; - }; - size_t bufsz; - unsigned long mem; - size_t memsz; -}; - -#ifdef CONFIG_COMPAT -struct compat_kexec_segment { - compat_uptr_t buf; - compat_size_t bufsz; - compat_ulong_t mem; /* User space sees this as a (void *) ... */ - compat_size_t memsz; -}; -#endif - -#ifdef CONFIG_KEXEC_FILE -struct purgatory_info { - /* Pointer to elf header of read only purgatory */ - Elf_Ehdr *ehdr; - - /* Pointer to purgatory sechdrs which are modifiable */ - Elf_Shdr *sechdrs; - /* - * Temporary buffer location where purgatory is loaded and relocated - * This memory can be freed post image load - */ - void *purgatory_buf; - - /* Address where purgatory is finally loaded and is executed from */ - unsigned long purgatory_load_addr; -}; - -typedef int (kexec_probe_t)(const char *kernel_buf, unsigned long kernel_size); -typedef void *(kexec_load_t)(struct kimage *image, char *kernel_buf, - unsigned long kernel_len, char *initrd, - unsigned long initrd_len, char *cmdline, - unsigned long cmdline_len); -typedef int (kexec_cleanup_t)(void *loader_data); - -#ifdef CONFIG_KEXEC_VERIFY_SIG -typedef int (kexec_verify_sig_t)(const char *kernel_buf, - unsigned long kernel_len); -#endif - -struct kexec_file_ops { - kexec_probe_t *probe; - kexec_load_t *load; - kexec_cleanup_t *cleanup; -#ifdef CONFIG_KEXEC_VERIFY_SIG - kexec_verify_sig_t *verify_sig; -#endif -}; -#endif - -struct kimage { - kimage_entry_t head; - kimage_entry_t *entry; - kimage_entry_t *last_entry; - - unsigned long start; - struct page *control_code_page; - struct page *swap_page; - - unsigned long nr_segments; - struct kexec_segment segment[KEXEC_SEGMENT_MAX]; - - struct list_head control_pages; - struct list_head dest_pages; - struct list_head unusable_pages; - - /* Address of next control page to allocate for crash kernels. */ - unsigned long control_page; - - /* Flags to indicate special processing */ - unsigned int type : 1; -#define KEXEC_TYPE_DEFAULT 0 -#define KEXEC_TYPE_CRASH 1 - unsigned int preserve_context : 1; - /* If set, we are using file mode kexec syscall */ - unsigned int file_mode:1; - -#ifdef ARCH_HAS_KIMAGE_ARCH - struct kimage_arch arch; -#endif - -#ifdef CONFIG_KEXEC_FILE - /* Additional fields for file based kexec syscall */ - void *kernel_buf; - unsigned long kernel_buf_len; - - void *initrd_buf; - unsigned long initrd_buf_len; - - char *cmdline_buf; - unsigned long cmdline_buf_len; - - /* File operations provided by image loader */ - struct kexec_file_ops *fops; - - /* Image loader handling the kernel can store a pointer here */ - void *image_loader_data; - - /* Information for loading purgatory */ - struct purgatory_info purgatory_info; -#endif -}; - -/* kexec interface functions */ -extern void machine_kexec(struct kimage *image); -extern int machine_kexec_prepare(struct kimage *image); -extern void machine_kexec_cleanup(struct kimage *image); -extern asmlinkage long sys_kexec_load(unsigned long entry, - unsigned long nr_segments, - struct kexec_segment __user *segments, - unsigned long flags); -extern int kernel_kexec(void); -extern int kexec_add_buffer(struct kimage *image, char *buffer, - unsigned long bufsz, unsigned long memsz, - unsigned long buf_align, unsigned long buf_min, - unsigned long buf_max, bool top_down, - unsigned long *load_addr); -extern struct page *kimage_alloc_control_pages(struct kimage *image, - unsigned int order); -extern int kexec_load_purgatory(struct kimage *image, unsigned long min, - unsigned long max, int top_down, - unsigned long *load_addr); -extern int kexec_purgatory_get_set_symbol(struct kimage *image, - const char *name, void *buf, - unsigned int size, bool get_value); -extern void *kexec_purgatory_get_symbol_addr(struct kimage *image, - const char *name); -extern void __crash_kexec(struct pt_regs *); -extern void crash_kexec(struct pt_regs *); -int kexec_should_crash(struct task_struct *); -int kexec_crash_loaded(void); -void crash_save_cpu(struct pt_regs *regs, int cpu); -void crash_save_vmcoreinfo(void); -void arch_crash_save_vmcoreinfo(void); -__printf(1, 2) -void vmcoreinfo_append_str(const char *fmt, ...); -phys_addr_t paddr_vmcoreinfo_note(void); - -#define VMCOREINFO_OSRELEASE(value) \ - vmcoreinfo_append_str("OSRELEASE=%s\n", value) -#define VMCOREINFO_PAGESIZE(value) \ - vmcoreinfo_append_str("PAGESIZE=%ld\n", value) -#define VMCOREINFO_SYMBOL(name) \ - vmcoreinfo_append_str("SYMBOL(%s)=%lx\n", #name, (unsigned long)&name) -#define VMCOREINFO_SIZE(name) \ - vmcoreinfo_append_str("SIZE(%s)=%lu\n", #name, \ - (unsigned long)sizeof(name)) -#define VMCOREINFO_STRUCT_SIZE(name) \ - vmcoreinfo_append_str("SIZE(%s)=%lu\n", #name, \ - (unsigned long)sizeof(struct name)) -#define VMCOREINFO_OFFSET(name, field) \ - vmcoreinfo_append_str("OFFSET(%s.%s)=%lu\n", #name, #field, \ - (unsigned long)offsetof(struct name, field)) -#define VMCOREINFO_LENGTH(name, value) \ - vmcoreinfo_append_str("LENGTH(%s)=%lu\n", #name, (unsigned long)value) -#define VMCOREINFO_NUMBER(name) \ - vmcoreinfo_append_str("NUMBER(%s)=%ld\n", #name, (long)name) -#define VMCOREINFO_CONFIG(name) \ - vmcoreinfo_append_str("CONFIG_%s=y\n", #name) -#define VMCOREINFO_PAGE_OFFSET(value) \ - vmcoreinfo_append_str("PAGE_OFFSET=%lx\n", (unsigned long)value) -#define VMCOREINFO_VMALLOC_START(value) \ - vmcoreinfo_append_str("VMALLOC_START=%lx\n", (unsigned long)value) -#define VMCOREINFO_VMEMMAP_START(value) \ - vmcoreinfo_append_str("VMEMMAP_START=%lx\n", (unsigned long)value) - -extern struct kimage *kexec_image; -extern struct kimage *kexec_crash_image; -extern int kexec_load_disabled; - -#ifndef kexec_flush_icache_page -#define kexec_flush_icache_page(page) -#endif - -/* List of defined/legal kexec flags */ -#ifndef CONFIG_KEXEC_JUMP -#define KEXEC_FLAGS KEXEC_ON_CRASH -#else -#define KEXEC_FLAGS (KEXEC_ON_CRASH | KEXEC_PRESERVE_CONTEXT) -#endif - -/* List of defined/legal kexec file flags */ -#define KEXEC_FILE_FLAGS (KEXEC_FILE_UNLOAD | KEXEC_FILE_ON_CRASH | \ - KEXEC_FILE_NO_INITRAMFS) - -#define VMCOREINFO_BYTES (4096) -#define VMCOREINFO_NOTE_NAME "VMCOREINFO" -#define VMCOREINFO_NOTE_NAME_BYTES ALIGN(sizeof(VMCOREINFO_NOTE_NAME), 4) -#define VMCOREINFO_NOTE_SIZE (KEXEC_NOTE_HEAD_BYTES*2 + VMCOREINFO_BYTES \ - + VMCOREINFO_NOTE_NAME_BYTES) - -/* Location of a reserved region to hold the crash kernel. - */ -extern struct resource crashk_res; -extern struct resource crashk_low_res; -typedef u32 note_buf_t[KEXEC_NOTE_BYTES/4]; -extern note_buf_t __percpu *crash_notes; -extern u32 vmcoreinfo_note[VMCOREINFO_NOTE_SIZE/4]; -extern size_t vmcoreinfo_size; -extern size_t vmcoreinfo_max_size; - -/* flag to track if kexec reboot is in progress */ -extern bool kexec_in_progress; - -int __init parse_crashkernel(char *cmdline, unsigned long long system_ram, - unsigned long long *crash_size, unsigned long long *crash_base); -int parse_crashkernel_high(char *cmdline, unsigned long long system_ram, - unsigned long long *crash_size, unsigned long long *crash_base); -int parse_crashkernel_low(char *cmdline, unsigned long long system_ram, - unsigned long long *crash_size, unsigned long long *crash_base); -int crash_shrink_memory(unsigned long new_size); -size_t crash_get_memory_size(void); -void crash_free_reserved_phys_range(unsigned long begin, unsigned long end); - -int __weak arch_kexec_kernel_image_probe(struct kimage *image, void *buf, - unsigned long buf_len); -void * __weak arch_kexec_kernel_image_load(struct kimage *image); -int __weak arch_kimage_file_post_load_cleanup(struct kimage *image); -int __weak arch_kexec_kernel_verify_sig(struct kimage *image, void *buf, - unsigned long buf_len); -int __weak arch_kexec_apply_relocations_add(const Elf_Ehdr *ehdr, - Elf_Shdr *sechdrs, unsigned int relsec); -int __weak arch_kexec_apply_relocations(const Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, - unsigned int relsec); -void arch_kexec_protect_crashkres(void); -void arch_kexec_unprotect_crashkres(void); - -#ifndef page_to_boot_pfn -static inline unsigned long page_to_boot_pfn(struct page *page) -{ - return page_to_pfn(page); -} -#endif - -#ifndef boot_pfn_to_page -static inline struct page *boot_pfn_to_page(unsigned long boot_pfn) -{ - return pfn_to_page(boot_pfn); -} -#endif - -#ifndef phys_to_boot_phys -static inline unsigned long phys_to_boot_phys(phys_addr_t phys) -{ - return phys; -} -#endif - -#ifndef boot_phys_to_phys -static inline phys_addr_t boot_phys_to_phys(unsigned long boot_phys) -{ - return boot_phys; -} -#endif - -static inline unsigned long virt_to_boot_phys(void *addr) -{ - return phys_to_boot_phys(__pa((unsigned long)addr)); -} - -static inline void *boot_phys_to_virt(unsigned long entry) -{ - return phys_to_virt(boot_phys_to_phys(entry)); -} - -#else /* !CONFIG_KEXEC_CORE */ -struct pt_regs; -struct task_struct; -static inline void __crash_kexec(struct pt_regs *regs) { } -static inline void crash_kexec(struct pt_regs *regs) { } -static inline int kexec_should_crash(struct task_struct *p) { return 0; } -static inline int kexec_crash_loaded(void) { return 0; } -#define kexec_in_progress false -#endif /* CONFIG_KEXEC_CORE */ - -#endif /* !defined(__ASSEBMLY__) */ - -#endif /* LINUX_KEXEC_H */ diff --git a/src/linux/include/linux/key.h b/src/linux/include/linux/key.h deleted file mode 100644 index 7229147..0000000 --- a/src/linux/include/linux/key.h +++ /dev/null @@ -1,395 +0,0 @@ -/* Authentication token and access key management - * - * Copyright (C) 2004, 2007 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * - * See Documentation/security/keys.txt for information on keys/keyrings. - */ - -#ifndef _LINUX_KEY_H -#define _LINUX_KEY_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __KERNEL__ -#include - -/* key handle serial number */ -typedef int32_t key_serial_t; - -/* key handle permissions mask */ -typedef uint32_t key_perm_t; - -struct key; - -#ifdef CONFIG_KEYS - -#undef KEY_DEBUGGING - -#define KEY_POS_VIEW 0x01000000 /* possessor can view a key's attributes */ -#define KEY_POS_READ 0x02000000 /* possessor can read key payload / view keyring */ -#define KEY_POS_WRITE 0x04000000 /* possessor can update key payload / add link to keyring */ -#define KEY_POS_SEARCH 0x08000000 /* possessor can find a key in search / search a keyring */ -#define KEY_POS_LINK 0x10000000 /* possessor can create a link to a key/keyring */ -#define KEY_POS_SETATTR 0x20000000 /* possessor can set key attributes */ -#define KEY_POS_ALL 0x3f000000 - -#define KEY_USR_VIEW 0x00010000 /* user permissions... */ -#define KEY_USR_READ 0x00020000 -#define KEY_USR_WRITE 0x00040000 -#define KEY_USR_SEARCH 0x00080000 -#define KEY_USR_LINK 0x00100000 -#define KEY_USR_SETATTR 0x00200000 -#define KEY_USR_ALL 0x003f0000 - -#define KEY_GRP_VIEW 0x00000100 /* group permissions... */ -#define KEY_GRP_READ 0x00000200 -#define KEY_GRP_WRITE 0x00000400 -#define KEY_GRP_SEARCH 0x00000800 -#define KEY_GRP_LINK 0x00001000 -#define KEY_GRP_SETATTR 0x00002000 -#define KEY_GRP_ALL 0x00003f00 - -#define KEY_OTH_VIEW 0x00000001 /* third party permissions... */ -#define KEY_OTH_READ 0x00000002 -#define KEY_OTH_WRITE 0x00000004 -#define KEY_OTH_SEARCH 0x00000008 -#define KEY_OTH_LINK 0x00000010 -#define KEY_OTH_SETATTR 0x00000020 -#define KEY_OTH_ALL 0x0000003f - -#define KEY_PERM_UNDEF 0xffffffff - -struct seq_file; -struct user_struct; -struct signal_struct; -struct cred; - -struct key_type; -struct key_owner; -struct keyring_list; -struct keyring_name; - -struct keyring_index_key { - struct key_type *type; - const char *description; - size_t desc_len; -}; - -union key_payload { - void __rcu *rcu_data0; - void *data[4]; -}; - -/*****************************************************************************/ -/* - * key reference with possession attribute handling - * - * NOTE! key_ref_t is a typedef'd pointer to a type that is not actually - * defined. This is because we abuse the bottom bit of the reference to carry a - * flag to indicate whether the calling process possesses that key in one of - * its keyrings. - * - * the key_ref_t has been made a separate type so that the compiler can reject - * attempts to dereference it without proper conversion. - * - * the three functions are used to assemble and disassemble references - */ -typedef struct __key_reference_with_attributes *key_ref_t; - -static inline key_ref_t make_key_ref(const struct key *key, - bool possession) -{ - return (key_ref_t) ((unsigned long) key | possession); -} - -static inline struct key *key_ref_to_ptr(const key_ref_t key_ref) -{ - return (struct key *) ((unsigned long) key_ref & ~1UL); -} - -static inline bool is_key_possessed(const key_ref_t key_ref) -{ - return (unsigned long) key_ref & 1UL; -} - -/*****************************************************************************/ -/* - * authentication token / access credential / keyring - * - types of key include: - * - keyrings - * - disk encryption IDs - * - Kerberos TGTs and tickets - */ -struct key { - atomic_t usage; /* number of references */ - key_serial_t serial; /* key serial number */ - union { - struct list_head graveyard_link; - struct rb_node serial_node; - }; - struct rw_semaphore sem; /* change vs change sem */ - struct key_user *user; /* owner of this key */ - void *security; /* security data for this key */ - union { - time_t expiry; /* time at which key expires (or 0) */ - time_t revoked_at; /* time at which key was revoked */ - }; - time_t last_used_at; /* last time used for LRU keyring discard */ - kuid_t uid; - kgid_t gid; - key_perm_t perm; /* access permissions */ - unsigned short quotalen; /* length added to quota */ - unsigned short datalen; /* payload data length - * - may not match RCU dereferenced payload - * - payload should contain own length - */ - -#ifdef KEY_DEBUGGING - unsigned magic; -#define KEY_DEBUG_MAGIC 0x18273645u -#define KEY_DEBUG_MAGIC_X 0xf8e9dacbu -#endif - - unsigned long flags; /* status flags (change with bitops) */ -#define KEY_FLAG_INSTANTIATED 0 /* set if key has been instantiated */ -#define KEY_FLAG_DEAD 1 /* set if key type has been deleted */ -#define KEY_FLAG_REVOKED 2 /* set if key had been revoked */ -#define KEY_FLAG_IN_QUOTA 3 /* set if key consumes quota */ -#define KEY_FLAG_USER_CONSTRUCT 4 /* set if key is being constructed in userspace */ -#define KEY_FLAG_NEGATIVE 5 /* set if key is negative */ -#define KEY_FLAG_ROOT_CAN_CLEAR 6 /* set if key can be cleared by root without permission */ -#define KEY_FLAG_INVALIDATED 7 /* set if key has been invalidated */ -#define KEY_FLAG_BUILTIN 8 /* set if key is built in to the kernel */ -#define KEY_FLAG_ROOT_CAN_INVAL 9 /* set if key can be invalidated by root without permission */ -#define KEY_FLAG_KEEP 10 /* set if key should not be removed */ - - /* the key type and key description string - * - the desc is used to match a key against search criteria - * - it should be a printable string - * - eg: for krb5 AFS, this might be "afs@REDHAT.COM" - */ - union { - struct keyring_index_key index_key; - struct { - struct key_type *type; /* type of key */ - char *description; - }; - }; - - /* key data - * - this is used to hold the data actually used in cryptography or - * whatever - */ - union { - union key_payload payload; - struct { - /* Keyring bits */ - struct list_head name_link; - struct assoc_array keys; - }; - int reject_error; - }; - - /* This is set on a keyring to restrict the addition of a link to a key - * to it. If this method isn't provided then it is assumed that the - * keyring is open to any addition. It is ignored for non-keyring - * keys. - * - * This is intended for use with rings of trusted keys whereby addition - * to the keyring needs to be controlled. KEY_ALLOC_BYPASS_RESTRICTION - * overrides this, allowing the kernel to add extra keys without - * restriction. - */ - int (*restrict_link)(struct key *keyring, - const struct key_type *type, - const union key_payload *payload); -}; - -extern struct key *key_alloc(struct key_type *type, - const char *desc, - kuid_t uid, kgid_t gid, - const struct cred *cred, - key_perm_t perm, - unsigned long flags, - int (*restrict_link)(struct key *, - const struct key_type *, - const union key_payload *)); - - -#define KEY_ALLOC_IN_QUOTA 0x0000 /* add to quota, reject if would overrun */ -#define KEY_ALLOC_QUOTA_OVERRUN 0x0001 /* add to quota, permit even if overrun */ -#define KEY_ALLOC_NOT_IN_QUOTA 0x0002 /* not in quota */ -#define KEY_ALLOC_BUILT_IN 0x0004 /* Key is built into kernel */ -#define KEY_ALLOC_BYPASS_RESTRICTION 0x0008 /* Override the check on restricted keyrings */ - -extern void key_revoke(struct key *key); -extern void key_invalidate(struct key *key); -extern void key_put(struct key *key); - -static inline struct key *__key_get(struct key *key) -{ - atomic_inc(&key->usage); - return key; -} - -static inline struct key *key_get(struct key *key) -{ - return key ? __key_get(key) : key; -} - -static inline void key_ref_put(key_ref_t key_ref) -{ - key_put(key_ref_to_ptr(key_ref)); -} - -extern struct key *request_key(struct key_type *type, - const char *description, - const char *callout_info); - -extern struct key *request_key_with_auxdata(struct key_type *type, - const char *description, - const void *callout_info, - size_t callout_len, - void *aux); - -extern struct key *request_key_async(struct key_type *type, - const char *description, - const void *callout_info, - size_t callout_len); - -extern struct key *request_key_async_with_auxdata(struct key_type *type, - const char *description, - const void *callout_info, - size_t callout_len, - void *aux); - -extern int wait_for_key_construction(struct key *key, bool intr); - -extern int key_validate(const struct key *key); - -extern key_ref_t key_create_or_update(key_ref_t keyring, - const char *type, - const char *description, - const void *payload, - size_t plen, - key_perm_t perm, - unsigned long flags); - -extern int key_update(key_ref_t key, - const void *payload, - size_t plen); - -extern int key_link(struct key *keyring, - struct key *key); - -extern int key_unlink(struct key *keyring, - struct key *key); - -extern struct key *keyring_alloc(const char *description, kuid_t uid, kgid_t gid, - const struct cred *cred, - key_perm_t perm, - unsigned long flags, - int (*restrict_link)(struct key *, - const struct key_type *, - const union key_payload *), - struct key *dest); - -extern int restrict_link_reject(struct key *keyring, - const struct key_type *type, - const union key_payload *payload); - -extern int keyring_clear(struct key *keyring); - -extern key_ref_t keyring_search(key_ref_t keyring, - struct key_type *type, - const char *description); - -extern int keyring_add_key(struct key *keyring, - struct key *key); - -extern struct key *key_lookup(key_serial_t id); - -static inline key_serial_t key_serial(const struct key *key) -{ - return key ? key->serial : 0; -} - -extern void key_set_timeout(struct key *, unsigned); - -/* - * The permissions required on a key that we're looking up. - */ -#define KEY_NEED_VIEW 0x01 /* Require permission to view attributes */ -#define KEY_NEED_READ 0x02 /* Require permission to read content */ -#define KEY_NEED_WRITE 0x04 /* Require permission to update / modify */ -#define KEY_NEED_SEARCH 0x08 /* Require permission to search (keyring) or find (key) */ -#define KEY_NEED_LINK 0x10 /* Require permission to link */ -#define KEY_NEED_SETATTR 0x20 /* Require permission to change attributes */ -#define KEY_NEED_ALL 0x3f /* All the above permissions */ - -/** - * key_is_instantiated - Determine if a key has been positively instantiated - * @key: The key to check. - * - * Return true if the specified key has been positively instantiated, false - * otherwise. - */ -static inline bool key_is_instantiated(const struct key *key) -{ - return test_bit(KEY_FLAG_INSTANTIATED, &key->flags) && - !test_bit(KEY_FLAG_NEGATIVE, &key->flags); -} - -#define rcu_dereference_key(KEY) \ - (rcu_dereference_protected((KEY)->payload.rcu_data0, \ - rwsem_is_locked(&((struct key *)(KEY))->sem))) - -#define rcu_assign_keypointer(KEY, PAYLOAD) \ -do { \ - rcu_assign_pointer((KEY)->payload.rcu_data0, (PAYLOAD)); \ -} while (0) - -#ifdef CONFIG_SYSCTL -extern struct ctl_table key_sysctls[]; -#endif -/* - * the userspace interface - */ -extern int install_thread_keyring_to_cred(struct cred *cred); -extern void key_fsuid_changed(struct task_struct *tsk); -extern void key_fsgid_changed(struct task_struct *tsk); -extern void key_init(void); - -#else /* CONFIG_KEYS */ - -#define key_validate(k) 0 -#define key_serial(k) 0 -#define key_get(k) ({ NULL; }) -#define key_revoke(k) do { } while(0) -#define key_invalidate(k) do { } while(0) -#define key_put(k) do { } while(0) -#define key_ref_put(k) do { } while(0) -#define make_key_ref(k, p) NULL -#define key_ref_to_ptr(k) NULL -#define is_key_possessed(k) 0 -#define key_fsuid_changed(t) do { } while(0) -#define key_fsgid_changed(t) do { } while(0) -#define key_init() do { } while(0) - -#endif /* CONFIG_KEYS */ -#endif /* __KERNEL__ */ -#endif /* _LINUX_KEY_H */ diff --git a/src/linux/include/linux/keyboard.h b/src/linux/include/linux/keyboard.h deleted file mode 100644 index 131ed51..0000000 --- a/src/linux/include/linux/keyboard.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __LINUX_KEYBOARD_H -#define __LINUX_KEYBOARD_H - -#include - -struct notifier_block; -extern unsigned short *key_maps[MAX_NR_KEYMAPS]; -extern unsigned short plain_map[NR_KEYS]; - -struct keyboard_notifier_param { - struct vc_data *vc; /* VC on which the keyboard press was done */ - int down; /* Pressure of the key? */ - int shift; /* Current shift mask */ - int ledstate; /* Current led state */ - unsigned int value; /* keycode, unicode value or keysym */ -}; - -extern int register_keyboard_notifier(struct notifier_block *nb); -extern int unregister_keyboard_notifier(struct notifier_block *nb); -#endif diff --git a/src/linux/include/linux/kfifo.h b/src/linux/include/linux/kfifo.h deleted file mode 100644 index 41eb6fd..0000000 --- a/src/linux/include/linux/kfifo.h +++ /dev/null @@ -1,833 +0,0 @@ -/* - * A generic kernel FIFO implementation - * - * Copyright (C) 2013 Stefani Seibold - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#ifndef _LINUX_KFIFO_H -#define _LINUX_KFIFO_H - -/* - * How to porting drivers to the new generic FIFO API: - * - * - Modify the declaration of the "struct kfifo *" object into a - * in-place "struct kfifo" object - * - Init the in-place object with kfifo_alloc() or kfifo_init() - * Note: The address of the in-place "struct kfifo" object must be - * passed as the first argument to this functions - * - Replace the use of __kfifo_put into kfifo_in and __kfifo_get - * into kfifo_out - * - Replace the use of kfifo_put into kfifo_in_spinlocked and kfifo_get - * into kfifo_out_spinlocked - * Note: the spinlock pointer formerly passed to kfifo_init/kfifo_alloc - * must be passed now to the kfifo_in_spinlocked and kfifo_out_spinlocked - * as the last parameter - * - The formerly __kfifo_* functions are renamed into kfifo_* - */ - -/* - * Note about locking : There is no locking required until only * one reader - * and one writer is using the fifo and no kfifo_reset() will be * called - * kfifo_reset_out() can be safely used, until it will be only called - * in the reader thread. - * For multiple writer and one reader there is only a need to lock the writer. - * And vice versa for only one writer and multiple reader there is only a need - * to lock the reader. - */ - -#include -#include -#include -#include - -struct __kfifo { - unsigned int in; - unsigned int out; - unsigned int mask; - unsigned int esize; - void *data; -}; - -#define __STRUCT_KFIFO_COMMON(datatype, recsize, ptrtype) \ - union { \ - struct __kfifo kfifo; \ - datatype *type; \ - const datatype *const_type; \ - char (*rectype)[recsize]; \ - ptrtype *ptr; \ - ptrtype const *ptr_const; \ - } - -#define __STRUCT_KFIFO(type, size, recsize, ptrtype) \ -{ \ - __STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \ - type buf[((size < 2) || (size & (size - 1))) ? -1 : size]; \ -} - -#define STRUCT_KFIFO(type, size) \ - struct __STRUCT_KFIFO(type, size, 0, type) - -#define __STRUCT_KFIFO_PTR(type, recsize, ptrtype) \ -{ \ - __STRUCT_KFIFO_COMMON(type, recsize, ptrtype); \ - type buf[0]; \ -} - -#define STRUCT_KFIFO_PTR(type) \ - struct __STRUCT_KFIFO_PTR(type, 0, type) - -/* - * define compatibility "struct kfifo" for dynamic allocated fifos - */ -struct kfifo __STRUCT_KFIFO_PTR(unsigned char, 0, void); - -#define STRUCT_KFIFO_REC_1(size) \ - struct __STRUCT_KFIFO(unsigned char, size, 1, void) - -#define STRUCT_KFIFO_REC_2(size) \ - struct __STRUCT_KFIFO(unsigned char, size, 2, void) - -/* - * define kfifo_rec types - */ -struct kfifo_rec_ptr_1 __STRUCT_KFIFO_PTR(unsigned char, 1, void); -struct kfifo_rec_ptr_2 __STRUCT_KFIFO_PTR(unsigned char, 2, void); - -/* - * helper macro to distinguish between real in place fifo where the fifo - * array is a part of the structure and the fifo type where the array is - * outside of the fifo structure. - */ -#define __is_kfifo_ptr(fifo) (sizeof(*fifo) == sizeof(struct __kfifo)) - -/** - * DECLARE_KFIFO_PTR - macro to declare a fifo pointer object - * @fifo: name of the declared fifo - * @type: type of the fifo elements - */ -#define DECLARE_KFIFO_PTR(fifo, type) STRUCT_KFIFO_PTR(type) fifo - -/** - * DECLARE_KFIFO - macro to declare a fifo object - * @fifo: name of the declared fifo - * @type: type of the fifo elements - * @size: the number of elements in the fifo, this must be a power of 2 - */ -#define DECLARE_KFIFO(fifo, type, size) STRUCT_KFIFO(type, size) fifo - -/** - * INIT_KFIFO - Initialize a fifo declared by DECLARE_KFIFO - * @fifo: name of the declared fifo datatype - */ -#define INIT_KFIFO(fifo) \ -(void)({ \ - typeof(&(fifo)) __tmp = &(fifo); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - __kfifo->in = 0; \ - __kfifo->out = 0; \ - __kfifo->mask = __is_kfifo_ptr(__tmp) ? 0 : ARRAY_SIZE(__tmp->buf) - 1;\ - __kfifo->esize = sizeof(*__tmp->buf); \ - __kfifo->data = __is_kfifo_ptr(__tmp) ? NULL : __tmp->buf; \ -}) - -/** - * DEFINE_KFIFO - macro to define and initialize a fifo - * @fifo: name of the declared fifo datatype - * @type: type of the fifo elements - * @size: the number of elements in the fifo, this must be a power of 2 - * - * Note: the macro can be used for global and local fifo data type variables. - */ -#define DEFINE_KFIFO(fifo, type, size) \ - DECLARE_KFIFO(fifo, type, size) = \ - (typeof(fifo)) { \ - { \ - { \ - .in = 0, \ - .out = 0, \ - .mask = __is_kfifo_ptr(&(fifo)) ? \ - 0 : \ - ARRAY_SIZE((fifo).buf) - 1, \ - .esize = sizeof(*(fifo).buf), \ - .data = __is_kfifo_ptr(&(fifo)) ? \ - NULL : \ - (fifo).buf, \ - } \ - } \ - } - - -static inline unsigned int __must_check -__kfifo_uint_must_check_helper(unsigned int val) -{ - return val; -} - -static inline int __must_check -__kfifo_int_must_check_helper(int val) -{ - return val; -} - -/** - * kfifo_initialized - Check if the fifo is initialized - * @fifo: address of the fifo to check - * - * Return %true if fifo is initialized, otherwise %false. - * Assumes the fifo was 0 before. - */ -#define kfifo_initialized(fifo) ((fifo)->kfifo.mask) - -/** - * kfifo_esize - returns the size of the element managed by the fifo - * @fifo: address of the fifo to be used - */ -#define kfifo_esize(fifo) ((fifo)->kfifo.esize) - -/** - * kfifo_recsize - returns the size of the record length field - * @fifo: address of the fifo to be used - */ -#define kfifo_recsize(fifo) (sizeof(*(fifo)->rectype)) - -/** - * kfifo_size - returns the size of the fifo in elements - * @fifo: address of the fifo to be used - */ -#define kfifo_size(fifo) ((fifo)->kfifo.mask + 1) - -/** - * kfifo_reset - removes the entire fifo content - * @fifo: address of the fifo to be used - * - * Note: usage of kfifo_reset() is dangerous. It should be only called when the - * fifo is exclusived locked or when it is secured that no other thread is - * accessing the fifo. - */ -#define kfifo_reset(fifo) \ -(void)({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - __tmp->kfifo.in = __tmp->kfifo.out = 0; \ -}) - -/** - * kfifo_reset_out - skip fifo content - * @fifo: address of the fifo to be used - * - * Note: The usage of kfifo_reset_out() is safe until it will be only called - * from the reader thread and there is only one concurrent reader. Otherwise - * it is dangerous and must be handled in the same way as kfifo_reset(). - */ -#define kfifo_reset_out(fifo) \ -(void)({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - __tmp->kfifo.out = __tmp->kfifo.in; \ -}) - -/** - * kfifo_len - returns the number of used elements in the fifo - * @fifo: address of the fifo to be used - */ -#define kfifo_len(fifo) \ -({ \ - typeof((fifo) + 1) __tmpl = (fifo); \ - __tmpl->kfifo.in - __tmpl->kfifo.out; \ -}) - -/** - * kfifo_is_empty - returns true if the fifo is empty - * @fifo: address of the fifo to be used - */ -#define kfifo_is_empty(fifo) \ -({ \ - typeof((fifo) + 1) __tmpq = (fifo); \ - __tmpq->kfifo.in == __tmpq->kfifo.out; \ -}) - -/** - * kfifo_is_full - returns true if the fifo is full - * @fifo: address of the fifo to be used - */ -#define kfifo_is_full(fifo) \ -({ \ - typeof((fifo) + 1) __tmpq = (fifo); \ - kfifo_len(__tmpq) > __tmpq->kfifo.mask; \ -}) - -/** - * kfifo_avail - returns the number of unused elements in the fifo - * @fifo: address of the fifo to be used - */ -#define kfifo_avail(fifo) \ -__kfifo_uint_must_check_helper( \ -({ \ - typeof((fifo) + 1) __tmpq = (fifo); \ - const size_t __recsize = sizeof(*__tmpq->rectype); \ - unsigned int __avail = kfifo_size(__tmpq) - kfifo_len(__tmpq); \ - (__recsize) ? ((__avail <= __recsize) ? 0 : \ - __kfifo_max_r(__avail - __recsize, __recsize)) : \ - __avail; \ -}) \ -) - -/** - * kfifo_skip - skip output data - * @fifo: address of the fifo to be used - */ -#define kfifo_skip(fifo) \ -(void)({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - const size_t __recsize = sizeof(*__tmp->rectype); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - if (__recsize) \ - __kfifo_skip_r(__kfifo, __recsize); \ - else \ - __kfifo->out++; \ -}) - -/** - * kfifo_peek_len - gets the size of the next fifo record - * @fifo: address of the fifo to be used - * - * This function returns the size of the next fifo record in number of bytes. - */ -#define kfifo_peek_len(fifo) \ -__kfifo_uint_must_check_helper( \ -({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - const size_t __recsize = sizeof(*__tmp->rectype); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - (!__recsize) ? kfifo_len(__tmp) * sizeof(*__tmp->type) : \ - __kfifo_len_r(__kfifo, __recsize); \ -}) \ -) - -/** - * kfifo_alloc - dynamically allocates a new fifo buffer - * @fifo: pointer to the fifo - * @size: the number of elements in the fifo, this must be a power of 2 - * @gfp_mask: get_free_pages mask, passed to kmalloc() - * - * This macro dynamically allocates a new fifo buffer. - * - * The numer of elements will be rounded-up to a power of 2. - * The fifo will be release with kfifo_free(). - * Return 0 if no error, otherwise an error code. - */ -#define kfifo_alloc(fifo, size, gfp_mask) \ -__kfifo_int_must_check_helper( \ -({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - __is_kfifo_ptr(__tmp) ? \ - __kfifo_alloc(__kfifo, size, sizeof(*__tmp->type), gfp_mask) : \ - -EINVAL; \ -}) \ -) - -/** - * kfifo_free - frees the fifo - * @fifo: the fifo to be freed - */ -#define kfifo_free(fifo) \ -({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - if (__is_kfifo_ptr(__tmp)) \ - __kfifo_free(__kfifo); \ -}) - -/** - * kfifo_init - initialize a fifo using a preallocated buffer - * @fifo: the fifo to assign the buffer - * @buffer: the preallocated buffer to be used - * @size: the size of the internal buffer, this have to be a power of 2 - * - * This macro initialize a fifo using a preallocated buffer. - * - * The numer of elements will be rounded-up to a power of 2. - * Return 0 if no error, otherwise an error code. - */ -#define kfifo_init(fifo, buffer, size) \ -({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - __is_kfifo_ptr(__tmp) ? \ - __kfifo_init(__kfifo, buffer, size, sizeof(*__tmp->type)) : \ - -EINVAL; \ -}) - -/** - * kfifo_put - put data into the fifo - * @fifo: address of the fifo to be used - * @val: the data to be added - * - * This macro copies the given value into the fifo. - * It returns 0 if the fifo was full. Otherwise it returns the number - * processed elements. - * - * Note that with only one concurrent reader and one concurrent - * writer, you don't need extra locking to use these macro. - */ -#define kfifo_put(fifo, val) \ -({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - typeof(*__tmp->const_type) __val = (val); \ - unsigned int __ret; \ - size_t __recsize = sizeof(*__tmp->rectype); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - if (__recsize) \ - __ret = __kfifo_in_r(__kfifo, &__val, sizeof(__val), \ - __recsize); \ - else { \ - __ret = !kfifo_is_full(__tmp); \ - if (__ret) { \ - (__is_kfifo_ptr(__tmp) ? \ - ((typeof(__tmp->type))__kfifo->data) : \ - (__tmp->buf) \ - )[__kfifo->in & __tmp->kfifo.mask] = \ - *(typeof(__tmp->type))&__val; \ - smp_wmb(); \ - __kfifo->in++; \ - } \ - } \ - __ret; \ -}) - -/** - * kfifo_get - get data from the fifo - * @fifo: address of the fifo to be used - * @val: address where to store the data - * - * This macro reads the data from the fifo. - * It returns 0 if the fifo was empty. Otherwise it returns the number - * processed elements. - * - * Note that with only one concurrent reader and one concurrent - * writer, you don't need extra locking to use these macro. - */ -#define kfifo_get(fifo, val) \ -__kfifo_uint_must_check_helper( \ -({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - typeof(__tmp->ptr) __val = (val); \ - unsigned int __ret; \ - const size_t __recsize = sizeof(*__tmp->rectype); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - if (__recsize) \ - __ret = __kfifo_out_r(__kfifo, __val, sizeof(*__val), \ - __recsize); \ - else { \ - __ret = !kfifo_is_empty(__tmp); \ - if (__ret) { \ - *(typeof(__tmp->type))__val = \ - (__is_kfifo_ptr(__tmp) ? \ - ((typeof(__tmp->type))__kfifo->data) : \ - (__tmp->buf) \ - )[__kfifo->out & __tmp->kfifo.mask]; \ - smp_wmb(); \ - __kfifo->out++; \ - } \ - } \ - __ret; \ -}) \ -) - -/** - * kfifo_peek - get data from the fifo without removing - * @fifo: address of the fifo to be used - * @val: address where to store the data - * - * This reads the data from the fifo without removing it from the fifo. - * It returns 0 if the fifo was empty. Otherwise it returns the number - * processed elements. - * - * Note that with only one concurrent reader and one concurrent - * writer, you don't need extra locking to use these macro. - */ -#define kfifo_peek(fifo, val) \ -__kfifo_uint_must_check_helper( \ -({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - typeof(__tmp->ptr) __val = (val); \ - unsigned int __ret; \ - const size_t __recsize = sizeof(*__tmp->rectype); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - if (__recsize) \ - __ret = __kfifo_out_peek_r(__kfifo, __val, sizeof(*__val), \ - __recsize); \ - else { \ - __ret = !kfifo_is_empty(__tmp); \ - if (__ret) { \ - *(typeof(__tmp->type))__val = \ - (__is_kfifo_ptr(__tmp) ? \ - ((typeof(__tmp->type))__kfifo->data) : \ - (__tmp->buf) \ - )[__kfifo->out & __tmp->kfifo.mask]; \ - smp_wmb(); \ - } \ - } \ - __ret; \ -}) \ -) - -/** - * kfifo_in - put data into the fifo - * @fifo: address of the fifo to be used - * @buf: the data to be added - * @n: number of elements to be added - * - * This macro copies the given buffer into the fifo and returns the - * number of copied elements. - * - * Note that with only one concurrent reader and one concurrent - * writer, you don't need extra locking to use these macro. - */ -#define kfifo_in(fifo, buf, n) \ -({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - typeof(__tmp->ptr_const) __buf = (buf); \ - unsigned long __n = (n); \ - const size_t __recsize = sizeof(*__tmp->rectype); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - (__recsize) ?\ - __kfifo_in_r(__kfifo, __buf, __n, __recsize) : \ - __kfifo_in(__kfifo, __buf, __n); \ -}) - -/** - * kfifo_in_spinlocked - put data into the fifo using a spinlock for locking - * @fifo: address of the fifo to be used - * @buf: the data to be added - * @n: number of elements to be added - * @lock: pointer to the spinlock to use for locking - * - * This macro copies the given values buffer into the fifo and returns the - * number of copied elements. - */ -#define kfifo_in_spinlocked(fifo, buf, n, lock) \ -({ \ - unsigned long __flags; \ - unsigned int __ret; \ - spin_lock_irqsave(lock, __flags); \ - __ret = kfifo_in(fifo, buf, n); \ - spin_unlock_irqrestore(lock, __flags); \ - __ret; \ -}) - -/* alias for kfifo_in_spinlocked, will be removed in a future release */ -#define kfifo_in_locked(fifo, buf, n, lock) \ - kfifo_in_spinlocked(fifo, buf, n, lock) - -/** - * kfifo_out - get data from the fifo - * @fifo: address of the fifo to be used - * @buf: pointer to the storage buffer - * @n: max. number of elements to get - * - * This macro get some data from the fifo and return the numbers of elements - * copied. - * - * Note that with only one concurrent reader and one concurrent - * writer, you don't need extra locking to use these macro. - */ -#define kfifo_out(fifo, buf, n) \ -__kfifo_uint_must_check_helper( \ -({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - typeof(__tmp->ptr) __buf = (buf); \ - unsigned long __n = (n); \ - const size_t __recsize = sizeof(*__tmp->rectype); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - (__recsize) ?\ - __kfifo_out_r(__kfifo, __buf, __n, __recsize) : \ - __kfifo_out(__kfifo, __buf, __n); \ -}) \ -) - -/** - * kfifo_out_spinlocked - get data from the fifo using a spinlock for locking - * @fifo: address of the fifo to be used - * @buf: pointer to the storage buffer - * @n: max. number of elements to get - * @lock: pointer to the spinlock to use for locking - * - * This macro get the data from the fifo and return the numbers of elements - * copied. - */ -#define kfifo_out_spinlocked(fifo, buf, n, lock) \ -__kfifo_uint_must_check_helper( \ -({ \ - unsigned long __flags; \ - unsigned int __ret; \ - spin_lock_irqsave(lock, __flags); \ - __ret = kfifo_out(fifo, buf, n); \ - spin_unlock_irqrestore(lock, __flags); \ - __ret; \ -}) \ -) - -/* alias for kfifo_out_spinlocked, will be removed in a future release */ -#define kfifo_out_locked(fifo, buf, n, lock) \ - kfifo_out_spinlocked(fifo, buf, n, lock) - -/** - * kfifo_from_user - puts some data from user space into the fifo - * @fifo: address of the fifo to be used - * @from: pointer to the data to be added - * @len: the length of the data to be added - * @copied: pointer to output variable to store the number of copied bytes - * - * This macro copies at most @len bytes from the @from into the - * fifo, depending of the available space and returns -EFAULT/0. - * - * Note that with only one concurrent reader and one concurrent - * writer, you don't need extra locking to use these macro. - */ -#define kfifo_from_user(fifo, from, len, copied) \ -__kfifo_uint_must_check_helper( \ -({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - const void __user *__from = (from); \ - unsigned int __len = (len); \ - unsigned int *__copied = (copied); \ - const size_t __recsize = sizeof(*__tmp->rectype); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - (__recsize) ? \ - __kfifo_from_user_r(__kfifo, __from, __len, __copied, __recsize) : \ - __kfifo_from_user(__kfifo, __from, __len, __copied); \ -}) \ -) - -/** - * kfifo_to_user - copies data from the fifo into user space - * @fifo: address of the fifo to be used - * @to: where the data must be copied - * @len: the size of the destination buffer - * @copied: pointer to output variable to store the number of copied bytes - * - * This macro copies at most @len bytes from the fifo into the - * @to buffer and returns -EFAULT/0. - * - * Note that with only one concurrent reader and one concurrent - * writer, you don't need extra locking to use these macro. - */ -#define kfifo_to_user(fifo, to, len, copied) \ -__kfifo_uint_must_check_helper( \ -({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - void __user *__to = (to); \ - unsigned int __len = (len); \ - unsigned int *__copied = (copied); \ - const size_t __recsize = sizeof(*__tmp->rectype); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - (__recsize) ? \ - __kfifo_to_user_r(__kfifo, __to, __len, __copied, __recsize) : \ - __kfifo_to_user(__kfifo, __to, __len, __copied); \ -}) \ -) - -/** - * kfifo_dma_in_prepare - setup a scatterlist for DMA input - * @fifo: address of the fifo to be used - * @sgl: pointer to the scatterlist array - * @nents: number of entries in the scatterlist array - * @len: number of elements to transfer - * - * This macro fills a scatterlist for DMA input. - * It returns the number entries in the scatterlist array. - * - * Note that with only one concurrent reader and one concurrent - * writer, you don't need extra locking to use these macros. - */ -#define kfifo_dma_in_prepare(fifo, sgl, nents, len) \ -({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - struct scatterlist *__sgl = (sgl); \ - int __nents = (nents); \ - unsigned int __len = (len); \ - const size_t __recsize = sizeof(*__tmp->rectype); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - (__recsize) ? \ - __kfifo_dma_in_prepare_r(__kfifo, __sgl, __nents, __len, __recsize) : \ - __kfifo_dma_in_prepare(__kfifo, __sgl, __nents, __len); \ -}) - -/** - * kfifo_dma_in_finish - finish a DMA IN operation - * @fifo: address of the fifo to be used - * @len: number of bytes to received - * - * This macro finish a DMA IN operation. The in counter will be updated by - * the len parameter. No error checking will be done. - * - * Note that with only one concurrent reader and one concurrent - * writer, you don't need extra locking to use these macros. - */ -#define kfifo_dma_in_finish(fifo, len) \ -(void)({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - unsigned int __len = (len); \ - const size_t __recsize = sizeof(*__tmp->rectype); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - if (__recsize) \ - __kfifo_dma_in_finish_r(__kfifo, __len, __recsize); \ - else \ - __kfifo->in += __len / sizeof(*__tmp->type); \ -}) - -/** - * kfifo_dma_out_prepare - setup a scatterlist for DMA output - * @fifo: address of the fifo to be used - * @sgl: pointer to the scatterlist array - * @nents: number of entries in the scatterlist array - * @len: number of elements to transfer - * - * This macro fills a scatterlist for DMA output which at most @len bytes - * to transfer. - * It returns the number entries in the scatterlist array. - * A zero means there is no space available and the scatterlist is not filled. - * - * Note that with only one concurrent reader and one concurrent - * writer, you don't need extra locking to use these macros. - */ -#define kfifo_dma_out_prepare(fifo, sgl, nents, len) \ -({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - struct scatterlist *__sgl = (sgl); \ - int __nents = (nents); \ - unsigned int __len = (len); \ - const size_t __recsize = sizeof(*__tmp->rectype); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - (__recsize) ? \ - __kfifo_dma_out_prepare_r(__kfifo, __sgl, __nents, __len, __recsize) : \ - __kfifo_dma_out_prepare(__kfifo, __sgl, __nents, __len); \ -}) - -/** - * kfifo_dma_out_finish - finish a DMA OUT operation - * @fifo: address of the fifo to be used - * @len: number of bytes transferred - * - * This macro finish a DMA OUT operation. The out counter will be updated by - * the len parameter. No error checking will be done. - * - * Note that with only one concurrent reader and one concurrent - * writer, you don't need extra locking to use these macros. - */ -#define kfifo_dma_out_finish(fifo, len) \ -(void)({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - unsigned int __len = (len); \ - const size_t __recsize = sizeof(*__tmp->rectype); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - if (__recsize) \ - __kfifo_dma_out_finish_r(__kfifo, __recsize); \ - else \ - __kfifo->out += __len / sizeof(*__tmp->type); \ -}) - -/** - * kfifo_out_peek - gets some data from the fifo - * @fifo: address of the fifo to be used - * @buf: pointer to the storage buffer - * @n: max. number of elements to get - * - * This macro get the data from the fifo and return the numbers of elements - * copied. The data is not removed from the fifo. - * - * Note that with only one concurrent reader and one concurrent - * writer, you don't need extra locking to use these macro. - */ -#define kfifo_out_peek(fifo, buf, n) \ -__kfifo_uint_must_check_helper( \ -({ \ - typeof((fifo) + 1) __tmp = (fifo); \ - typeof(__tmp->ptr) __buf = (buf); \ - unsigned long __n = (n); \ - const size_t __recsize = sizeof(*__tmp->rectype); \ - struct __kfifo *__kfifo = &__tmp->kfifo; \ - (__recsize) ? \ - __kfifo_out_peek_r(__kfifo, __buf, __n, __recsize) : \ - __kfifo_out_peek(__kfifo, __buf, __n); \ -}) \ -) - -extern int __kfifo_alloc(struct __kfifo *fifo, unsigned int size, - size_t esize, gfp_t gfp_mask); - -extern void __kfifo_free(struct __kfifo *fifo); - -extern int __kfifo_init(struct __kfifo *fifo, void *buffer, - unsigned int size, size_t esize); - -extern unsigned int __kfifo_in(struct __kfifo *fifo, - const void *buf, unsigned int len); - -extern unsigned int __kfifo_out(struct __kfifo *fifo, - void *buf, unsigned int len); - -extern int __kfifo_from_user(struct __kfifo *fifo, - const void __user *from, unsigned long len, unsigned int *copied); - -extern int __kfifo_to_user(struct __kfifo *fifo, - void __user *to, unsigned long len, unsigned int *copied); - -extern unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo, - struct scatterlist *sgl, int nents, unsigned int len); - -extern unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo, - struct scatterlist *sgl, int nents, unsigned int len); - -extern unsigned int __kfifo_out_peek(struct __kfifo *fifo, - void *buf, unsigned int len); - -extern unsigned int __kfifo_in_r(struct __kfifo *fifo, - const void *buf, unsigned int len, size_t recsize); - -extern unsigned int __kfifo_out_r(struct __kfifo *fifo, - void *buf, unsigned int len, size_t recsize); - -extern int __kfifo_from_user_r(struct __kfifo *fifo, - const void __user *from, unsigned long len, unsigned int *copied, - size_t recsize); - -extern int __kfifo_to_user_r(struct __kfifo *fifo, void __user *to, - unsigned long len, unsigned int *copied, size_t recsize); - -extern unsigned int __kfifo_dma_in_prepare_r(struct __kfifo *fifo, - struct scatterlist *sgl, int nents, unsigned int len, size_t recsize); - -extern void __kfifo_dma_in_finish_r(struct __kfifo *fifo, - unsigned int len, size_t recsize); - -extern unsigned int __kfifo_dma_out_prepare_r(struct __kfifo *fifo, - struct scatterlist *sgl, int nents, unsigned int len, size_t recsize); - -extern void __kfifo_dma_out_finish_r(struct __kfifo *fifo, size_t recsize); - -extern unsigned int __kfifo_len_r(struct __kfifo *fifo, size_t recsize); - -extern void __kfifo_skip_r(struct __kfifo *fifo, size_t recsize); - -extern unsigned int __kfifo_out_peek_r(struct __kfifo *fifo, - void *buf, unsigned int len, size_t recsize); - -extern unsigned int __kfifo_max_r(unsigned int len, size_t recsize); - -#endif diff --git a/src/linux/include/linux/kgdb.h b/src/linux/include/linux/kgdb.h deleted file mode 100644 index e465bb1..0000000 --- a/src/linux/include/linux/kgdb.h +++ /dev/null @@ -1,327 +0,0 @@ -/* - * This provides the callbacks and functions that KGDB needs to share between - * the core, I/O and arch-specific portions. - * - * Author: Amit Kale and - * Tom Rini - * - * 2001-2004 (c) Amit S. Kale and 2003-2005 (c) MontaVista Software, Inc. - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ -#ifndef _KGDB_H_ -#define _KGDB_H_ - -#include -#include -#include -#ifdef CONFIG_HAVE_ARCH_KGDB -#include -#endif - -#ifdef CONFIG_KGDB -struct pt_regs; - -/** - * kgdb_skipexception - (optional) exit kgdb_handle_exception early - * @exception: Exception vector number - * @regs: Current &struct pt_regs. - * - * On some architectures it is required to skip a breakpoint - * exception when it occurs after a breakpoint has been removed. - * This can be implemented in the architecture specific portion of kgdb. - */ -extern int kgdb_skipexception(int exception, struct pt_regs *regs); - -struct tasklet_struct; -struct task_struct; -struct uart_port; - -/** - * kgdb_breakpoint - compiled in breakpoint - * - * This will be implemented as a static inline per architecture. This - * function is called by the kgdb core to execute an architecture - * specific trap to cause kgdb to enter the exception processing. - * - */ -void kgdb_breakpoint(void); - -extern int kgdb_connected; -extern int kgdb_io_module_registered; - -extern atomic_t kgdb_setting_breakpoint; -extern atomic_t kgdb_cpu_doing_single_step; - -extern struct task_struct *kgdb_usethread; -extern struct task_struct *kgdb_contthread; - -enum kgdb_bptype { - BP_BREAKPOINT = 0, - BP_HARDWARE_BREAKPOINT, - BP_WRITE_WATCHPOINT, - BP_READ_WATCHPOINT, - BP_ACCESS_WATCHPOINT, - BP_POKE_BREAKPOINT, -}; - -enum kgdb_bpstate { - BP_UNDEFINED = 0, - BP_REMOVED, - BP_SET, - BP_ACTIVE -}; - -struct kgdb_bkpt { - unsigned long bpt_addr; - unsigned char saved_instr[BREAK_INSTR_SIZE]; - enum kgdb_bptype type; - enum kgdb_bpstate state; -}; - -struct dbg_reg_def_t { - char *name; - int size; - int offset; -}; - -#ifndef DBG_MAX_REG_NUM -#define DBG_MAX_REG_NUM 0 -#else -extern struct dbg_reg_def_t dbg_reg_def[]; -extern char *dbg_get_reg(int regno, void *mem, struct pt_regs *regs); -extern int dbg_set_reg(int regno, void *mem, struct pt_regs *regs); -#endif -#ifndef KGDB_MAX_BREAKPOINTS -# define KGDB_MAX_BREAKPOINTS 1000 -#endif - -#define KGDB_HW_BREAKPOINT 1 - -/* - * Functions each KGDB-supporting architecture must provide: - */ - -/** - * kgdb_arch_init - Perform any architecture specific initalization. - * - * This function will handle the initalization of any architecture - * specific callbacks. - */ -extern int kgdb_arch_init(void); - -/** - * kgdb_arch_exit - Perform any architecture specific uninitalization. - * - * This function will handle the uninitalization of any architecture - * specific callbacks, for dynamic registration and unregistration. - */ -extern void kgdb_arch_exit(void); - -/** - * pt_regs_to_gdb_regs - Convert ptrace regs to GDB regs - * @gdb_regs: A pointer to hold the registers in the order GDB wants. - * @regs: The &struct pt_regs of the current process. - * - * Convert the pt_regs in @regs into the format for registers that - * GDB expects, stored in @gdb_regs. - */ -extern void pt_regs_to_gdb_regs(unsigned long *gdb_regs, struct pt_regs *regs); - -/** - * sleeping_thread_to_gdb_regs - Convert ptrace regs to GDB regs - * @gdb_regs: A pointer to hold the registers in the order GDB wants. - * @p: The &struct task_struct of the desired process. - * - * Convert the register values of the sleeping process in @p to - * the format that GDB expects. - * This function is called when kgdb does not have access to the - * &struct pt_regs and therefore it should fill the gdb registers - * @gdb_regs with what has been saved in &struct thread_struct - * thread field during switch_to. - */ -extern void -sleeping_thread_to_gdb_regs(unsigned long *gdb_regs, struct task_struct *p); - -/** - * gdb_regs_to_pt_regs - Convert GDB regs to ptrace regs. - * @gdb_regs: A pointer to hold the registers we've received from GDB. - * @regs: A pointer to a &struct pt_regs to hold these values in. - * - * Convert the GDB regs in @gdb_regs into the pt_regs, and store them - * in @regs. - */ -extern void gdb_regs_to_pt_regs(unsigned long *gdb_regs, struct pt_regs *regs); - -/** - * kgdb_arch_handle_exception - Handle architecture specific GDB packets. - * @vector: The error vector of the exception that happened. - * @signo: The signal number of the exception that happened. - * @err_code: The error code of the exception that happened. - * @remcom_in_buffer: The buffer of the packet we have read. - * @remcom_out_buffer: The buffer of %BUFMAX bytes to write a packet into. - * @regs: The &struct pt_regs of the current process. - * - * This function MUST handle the 'c' and 's' command packets, - * as well packets to set / remove a hardware breakpoint, if used. - * If there are additional packets which the hardware needs to handle, - * they are handled here. The code should return -1 if it wants to - * process more packets, and a %0 or %1 if it wants to exit from the - * kgdb callback. - */ -extern int -kgdb_arch_handle_exception(int vector, int signo, int err_code, - char *remcom_in_buffer, - char *remcom_out_buffer, - struct pt_regs *regs); - -/** - * kgdb_roundup_cpus - Get other CPUs into a holding pattern - * @flags: Current IRQ state - * - * On SMP systems, we need to get the attention of the other CPUs - * and get them into a known state. This should do what is needed - * to get the other CPUs to call kgdb_wait(). Note that on some arches, - * the NMI approach is not used for rounding up all the CPUs. For example, - * in case of MIPS, smp_call_function() is used to roundup CPUs. In - * this case, we have to make sure that interrupts are enabled before - * calling smp_call_function(). The argument to this function is - * the flags that will be used when restoring the interrupts. There is - * local_irq_save() call before kgdb_roundup_cpus(). - * - * On non-SMP systems, this is not called. - */ -extern void kgdb_roundup_cpus(unsigned long flags); - -/** - * kgdb_arch_set_pc - Generic call back to the program counter - * @regs: Current &struct pt_regs. - * @pc: The new value for the program counter - * - * This function handles updating the program counter and requires an - * architecture specific implementation. - */ -extern void kgdb_arch_set_pc(struct pt_regs *regs, unsigned long pc); - - -/* Optional functions. */ -extern int kgdb_validate_break_address(unsigned long addr); -extern int kgdb_arch_set_breakpoint(struct kgdb_bkpt *bpt); -extern int kgdb_arch_remove_breakpoint(struct kgdb_bkpt *bpt); - -/** - * kgdb_arch_late - Perform any architecture specific initalization. - * - * This function will handle the late initalization of any - * architecture specific callbacks. This is an optional function for - * handling things like late initialization of hw breakpoints. The - * default implementation does nothing. - */ -extern void kgdb_arch_late(void); - - -/** - * struct kgdb_arch - Describe architecture specific values. - * @gdb_bpt_instr: The instruction to trigger a breakpoint. - * @flags: Flags for the breakpoint, currently just %KGDB_HW_BREAKPOINT. - * @set_breakpoint: Allow an architecture to specify how to set a software - * breakpoint. - * @remove_breakpoint: Allow an architecture to specify how to remove a - * software breakpoint. - * @set_hw_breakpoint: Allow an architecture to specify how to set a hardware - * breakpoint. - * @remove_hw_breakpoint: Allow an architecture to specify how to remove a - * hardware breakpoint. - * @disable_hw_break: Allow an architecture to specify how to disable - * hardware breakpoints for a single cpu. - * @remove_all_hw_break: Allow an architecture to specify how to remove all - * hardware breakpoints. - * @correct_hw_break: Allow an architecture to specify how to correct the - * hardware debug registers. - * @enable_nmi: Manage NMI-triggered entry to KGDB - */ -struct kgdb_arch { - unsigned char gdb_bpt_instr[BREAK_INSTR_SIZE]; - unsigned long flags; - - int (*set_breakpoint)(unsigned long, char *); - int (*remove_breakpoint)(unsigned long, char *); - int (*set_hw_breakpoint)(unsigned long, int, enum kgdb_bptype); - int (*remove_hw_breakpoint)(unsigned long, int, enum kgdb_bptype); - void (*disable_hw_break)(struct pt_regs *regs); - void (*remove_all_hw_break)(void); - void (*correct_hw_break)(void); - - void (*enable_nmi)(bool on); -}; - -/** - * struct kgdb_io - Describe the interface for an I/O driver to talk with KGDB. - * @name: Name of the I/O driver. - * @read_char: Pointer to a function that will return one char. - * @write_char: Pointer to a function that will write one char. - * @flush: Pointer to a function that will flush any pending writes. - * @init: Pointer to a function that will initialize the device. - * @pre_exception: Pointer to a function that will do any prep work for - * the I/O driver. - * @post_exception: Pointer to a function that will do any cleanup work - * for the I/O driver. - * @is_console: 1 if the end device is a console 0 if the I/O device is - * not a console - */ -struct kgdb_io { - const char *name; - int (*read_char) (void); - void (*write_char) (u8); - void (*flush) (void); - int (*init) (void); - void (*pre_exception) (void); - void (*post_exception) (void); - int is_console; -}; - -extern struct kgdb_arch arch_kgdb_ops; - -extern unsigned long kgdb_arch_pc(int exception, struct pt_regs *regs); - -#ifdef CONFIG_SERIAL_KGDB_NMI -extern int kgdb_register_nmi_console(void); -extern int kgdb_unregister_nmi_console(void); -extern bool kgdb_nmi_poll_knock(void); -#else -static inline int kgdb_register_nmi_console(void) { return 0; } -static inline int kgdb_unregister_nmi_console(void) { return 0; } -static inline bool kgdb_nmi_poll_knock(void) { return 1; } -#endif - -extern int kgdb_register_io_module(struct kgdb_io *local_kgdb_io_ops); -extern void kgdb_unregister_io_module(struct kgdb_io *local_kgdb_io_ops); -extern struct kgdb_io *dbg_io_ops; - -extern int kgdb_hex2long(char **ptr, unsigned long *long_val); -extern char *kgdb_mem2hex(char *mem, char *buf, int count); -extern int kgdb_hex2mem(char *buf, char *mem, int count); - -extern int kgdb_isremovedbreak(unsigned long addr); -extern void kgdb_schedule_breakpoint(void); - -extern int -kgdb_handle_exception(int ex_vector, int signo, int err_code, - struct pt_regs *regs); -extern int kgdb_nmicallback(int cpu, void *regs); -extern int kgdb_nmicallin(int cpu, int trapnr, void *regs, int err_code, - atomic_t *snd_rdy); -extern void gdbstub_exit(int status); - -extern int kgdb_single_step; -extern atomic_t kgdb_active; -#define in_dbg_master() \ - (raw_smp_processor_id() == atomic_read(&kgdb_active)) -extern bool dbg_is_early; -extern void __init dbg_late_init(void); -#else /* ! CONFIG_KGDB */ -#define in_dbg_master() (0) -#define dbg_late_init() -#endif /* ! CONFIG_KGDB */ -#endif /* _KGDB_H_ */ diff --git a/src/linux/include/linux/khugepaged.h b/src/linux/include/linux/khugepaged.h deleted file mode 100644 index 1e032a1..0000000 --- a/src/linux/include/linux/khugepaged.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef _LINUX_KHUGEPAGED_H -#define _LINUX_KHUGEPAGED_H - -#include /* MMF_VM_HUGEPAGE */ - -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -extern struct attribute_group khugepaged_attr_group; - -extern int khugepaged_init(void); -extern void khugepaged_destroy(void); -extern int start_stop_khugepaged(void); -extern int __khugepaged_enter(struct mm_struct *mm); -extern void __khugepaged_exit(struct mm_struct *mm); -extern int khugepaged_enter_vma_merge(struct vm_area_struct *vma, - unsigned long vm_flags); - -#define khugepaged_enabled() \ - (transparent_hugepage_flags & \ - ((1<flags)) - return __khugepaged_enter(mm); - return 0; -} - -static inline void khugepaged_exit(struct mm_struct *mm) -{ - if (test_bit(MMF_VM_HUGEPAGE, &mm->flags)) - __khugepaged_exit(mm); -} - -static inline int khugepaged_enter(struct vm_area_struct *vma, - unsigned long vm_flags) -{ - if (!test_bit(MMF_VM_HUGEPAGE, &vma->vm_mm->flags)) - if ((khugepaged_always() || - (khugepaged_req_madv() && (vm_flags & VM_HUGEPAGE))) && - !(vm_flags & VM_NOHUGEPAGE)) - if (__khugepaged_enter(vma->vm_mm)) - return -ENOMEM; - return 0; -} -#else /* CONFIG_TRANSPARENT_HUGEPAGE */ -static inline int khugepaged_fork(struct mm_struct *mm, struct mm_struct *oldmm) -{ - return 0; -} -static inline void khugepaged_exit(struct mm_struct *mm) -{ -} -static inline int khugepaged_enter(struct vm_area_struct *vma, - unsigned long vm_flags) -{ - return 0; -} -static inline int khugepaged_enter_vma_merge(struct vm_area_struct *vma, - unsigned long vm_flags) -{ - return 0; -} -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ - -#endif /* _LINUX_KHUGEPAGED_H */ diff --git a/src/linux/include/linux/klist.h b/src/linux/include/linux/klist.h deleted file mode 100644 index 953f283..0000000 --- a/src/linux/include/linux/klist.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * klist.h - Some generic list helpers, extending struct list_head a bit. - * - * Implementations are found in lib/klist.c - * - * - * Copyright (C) 2005 Patrick Mochel - * - * This file is rleased under the GPL v2. - */ - -#ifndef _LINUX_KLIST_H -#define _LINUX_KLIST_H - -#include -#include -#include - -struct klist_node; -struct klist { - spinlock_t k_lock; - struct list_head k_list; - void (*get)(struct klist_node *); - void (*put)(struct klist_node *); -} __attribute__ ((aligned (sizeof(void *)))); - -#define KLIST_INIT(_name, _get, _put) \ - { .k_lock = __SPIN_LOCK_UNLOCKED(_name.k_lock), \ - .k_list = LIST_HEAD_INIT(_name.k_list), \ - .get = _get, \ - .put = _put, } - -#define DEFINE_KLIST(_name, _get, _put) \ - struct klist _name = KLIST_INIT(_name, _get, _put) - -extern void klist_init(struct klist *k, void (*get)(struct klist_node *), - void (*put)(struct klist_node *)); - -struct klist_node { - void *n_klist; /* never access directly */ - struct list_head n_node; - struct kref n_ref; -}; - -extern void klist_add_tail(struct klist_node *n, struct klist *k); -extern void klist_add_head(struct klist_node *n, struct klist *k); -extern void klist_add_behind(struct klist_node *n, struct klist_node *pos); -extern void klist_add_before(struct klist_node *n, struct klist_node *pos); - -extern void klist_del(struct klist_node *n); -extern void klist_remove(struct klist_node *n); - -extern int klist_node_attached(struct klist_node *n); - - -struct klist_iter { - struct klist *i_klist; - struct klist_node *i_cur; -}; - - -extern void klist_iter_init(struct klist *k, struct klist_iter *i); -extern void klist_iter_init_node(struct klist *k, struct klist_iter *i, - struct klist_node *n); -extern void klist_iter_exit(struct klist_iter *i); -extern struct klist_node *klist_prev(struct klist_iter *i); -extern struct klist_node *klist_next(struct klist_iter *i); - -#endif diff --git a/src/linux/include/linux/kmemcheck.h b/src/linux/include/linux/kmemcheck.h deleted file mode 100644 index 39f8453..0000000 --- a/src/linux/include/linux/kmemcheck.h +++ /dev/null @@ -1,171 +0,0 @@ -#ifndef LINUX_KMEMCHECK_H -#define LINUX_KMEMCHECK_H - -#include -#include - -#ifdef CONFIG_KMEMCHECK -extern int kmemcheck_enabled; - -/* The slab-related functions. */ -void kmemcheck_alloc_shadow(struct page *page, int order, gfp_t flags, int node); -void kmemcheck_free_shadow(struct page *page, int order); -void kmemcheck_slab_alloc(struct kmem_cache *s, gfp_t gfpflags, void *object, - size_t size); -void kmemcheck_slab_free(struct kmem_cache *s, void *object, size_t size); - -void kmemcheck_pagealloc_alloc(struct page *p, unsigned int order, - gfp_t gfpflags); - -void kmemcheck_show_pages(struct page *p, unsigned int n); -void kmemcheck_hide_pages(struct page *p, unsigned int n); - -bool kmemcheck_page_is_tracked(struct page *p); - -void kmemcheck_mark_unallocated(void *address, unsigned int n); -void kmemcheck_mark_uninitialized(void *address, unsigned int n); -void kmemcheck_mark_initialized(void *address, unsigned int n); -void kmemcheck_mark_freed(void *address, unsigned int n); - -void kmemcheck_mark_unallocated_pages(struct page *p, unsigned int n); -void kmemcheck_mark_uninitialized_pages(struct page *p, unsigned int n); -void kmemcheck_mark_initialized_pages(struct page *p, unsigned int n); - -int kmemcheck_show_addr(unsigned long address); -int kmemcheck_hide_addr(unsigned long address); - -bool kmemcheck_is_obj_initialized(unsigned long addr, size_t size); - -/* - * Bitfield annotations - * - * How to use: If you have a struct using bitfields, for example - * - * struct a { - * int x:8, y:8; - * }; - * - * then this should be rewritten as - * - * struct a { - * kmemcheck_bitfield_begin(flags); - * int x:8, y:8; - * kmemcheck_bitfield_end(flags); - * }; - * - * Now the "flags_begin" and "flags_end" members may be used to refer to the - * beginning and end, respectively, of the bitfield (and things like - * &x.flags_begin is allowed). As soon as the struct is allocated, the bit- - * fields should be annotated: - * - * struct a *a = kmalloc(sizeof(struct a), GFP_KERNEL); - * kmemcheck_annotate_bitfield(a, flags); - */ -#define kmemcheck_bitfield_begin(name) \ - int name##_begin[0]; - -#define kmemcheck_bitfield_end(name) \ - int name##_end[0]; - -#define kmemcheck_annotate_bitfield(ptr, name) \ - do { \ - int _n; \ - \ - if (!ptr) \ - break; \ - \ - _n = (long) &((ptr)->name##_end) \ - - (long) &((ptr)->name##_begin); \ - BUILD_BUG_ON(_n < 0); \ - \ - kmemcheck_mark_initialized(&((ptr)->name##_begin), _n); \ - } while (0) - -#define kmemcheck_annotate_variable(var) \ - do { \ - kmemcheck_mark_initialized(&(var), sizeof(var)); \ - } while (0) \ - -#else -#define kmemcheck_enabled 0 - -static inline void -kmemcheck_alloc_shadow(struct page *page, int order, gfp_t flags, int node) -{ -} - -static inline void -kmemcheck_free_shadow(struct page *page, int order) -{ -} - -static inline void -kmemcheck_slab_alloc(struct kmem_cache *s, gfp_t gfpflags, void *object, - size_t size) -{ -} - -static inline void kmemcheck_slab_free(struct kmem_cache *s, void *object, - size_t size) -{ -} - -static inline void kmemcheck_pagealloc_alloc(struct page *p, - unsigned int order, gfp_t gfpflags) -{ -} - -static inline bool kmemcheck_page_is_tracked(struct page *p) -{ - return false; -} - -static inline void kmemcheck_mark_unallocated(void *address, unsigned int n) -{ -} - -static inline void kmemcheck_mark_uninitialized(void *address, unsigned int n) -{ -} - -static inline void kmemcheck_mark_initialized(void *address, unsigned int n) -{ -} - -static inline void kmemcheck_mark_freed(void *address, unsigned int n) -{ -} - -static inline void kmemcheck_mark_unallocated_pages(struct page *p, - unsigned int n) -{ -} - -static inline void kmemcheck_mark_uninitialized_pages(struct page *p, - unsigned int n) -{ -} - -static inline void kmemcheck_mark_initialized_pages(struct page *p, - unsigned int n) -{ -} - -static inline bool kmemcheck_is_obj_initialized(unsigned long addr, size_t size) -{ - return true; -} - -#define kmemcheck_bitfield_begin(name) -#define kmemcheck_bitfield_end(name) -#define kmemcheck_annotate_bitfield(ptr, name) \ - do { \ - } while (0) - -#define kmemcheck_annotate_variable(var) \ - do { \ - } while (0) - -#endif /* CONFIG_KMEMCHECK */ - -#endif /* LINUX_KMEMCHECK_H */ diff --git a/src/linux/include/linux/kmemleak.h b/src/linux/include/linux/kmemleak.h deleted file mode 100644 index 1c2a328..0000000 --- a/src/linux/include/linux/kmemleak.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * include/linux/kmemleak.h - * - * Copyright (C) 2008 ARM Limited - * Written by Catalin Marinas - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef __KMEMLEAK_H -#define __KMEMLEAK_H - -#include - -#ifdef CONFIG_DEBUG_KMEMLEAK - -extern void kmemleak_init(void) __init; -extern void kmemleak_alloc(const void *ptr, size_t size, int min_count, - gfp_t gfp) __ref; -extern void kmemleak_alloc_percpu(const void __percpu *ptr, size_t size, - gfp_t gfp) __ref; -extern void kmemleak_free(const void *ptr) __ref; -extern void kmemleak_free_part(const void *ptr, size_t size) __ref; -extern void kmemleak_free_percpu(const void __percpu *ptr) __ref; -extern void kmemleak_update_trace(const void *ptr) __ref; -extern void kmemleak_not_leak(const void *ptr) __ref; -extern void kmemleak_ignore(const void *ptr) __ref; -extern void kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp) __ref; -extern void kmemleak_no_scan(const void *ptr) __ref; -extern void kmemleak_alloc_phys(phys_addr_t phys, size_t size, int min_count, - gfp_t gfp) __ref; -extern void kmemleak_free_part_phys(phys_addr_t phys, size_t size) __ref; -extern void kmemleak_not_leak_phys(phys_addr_t phys) __ref; -extern void kmemleak_ignore_phys(phys_addr_t phys) __ref; - -static inline void kmemleak_alloc_recursive(const void *ptr, size_t size, - int min_count, unsigned long flags, - gfp_t gfp) -{ - if (!(flags & SLAB_NOLEAKTRACE)) - kmemleak_alloc(ptr, size, min_count, gfp); -} - -static inline void kmemleak_free_recursive(const void *ptr, unsigned long flags) -{ - if (!(flags & SLAB_NOLEAKTRACE)) - kmemleak_free(ptr); -} - -static inline void kmemleak_erase(void **ptr) -{ - *ptr = NULL; -} - -#else - -static inline void kmemleak_init(void) -{ -} -static inline void kmemleak_alloc(const void *ptr, size_t size, int min_count, - gfp_t gfp) -{ -} -static inline void kmemleak_alloc_recursive(const void *ptr, size_t size, - int min_count, unsigned long flags, - gfp_t gfp) -{ -} -static inline void kmemleak_alloc_percpu(const void __percpu *ptr, size_t size, - gfp_t gfp) -{ -} -static inline void kmemleak_free(const void *ptr) -{ -} -static inline void kmemleak_free_part(const void *ptr, size_t size) -{ -} -static inline void kmemleak_free_recursive(const void *ptr, unsigned long flags) -{ -} -static inline void kmemleak_free_percpu(const void __percpu *ptr) -{ -} -static inline void kmemleak_update_trace(const void *ptr) -{ -} -static inline void kmemleak_not_leak(const void *ptr) -{ -} -static inline void kmemleak_ignore(const void *ptr) -{ -} -static inline void kmemleak_scan_area(const void *ptr, size_t size, gfp_t gfp) -{ -} -static inline void kmemleak_erase(void **ptr) -{ -} -static inline void kmemleak_no_scan(const void *ptr) -{ -} -static inline void kmemleak_alloc_phys(phys_addr_t phys, size_t size, - int min_count, gfp_t gfp) -{ -} -static inline void kmemleak_free_part_phys(phys_addr_t phys, size_t size) -{ -} -static inline void kmemleak_not_leak_phys(phys_addr_t phys) -{ -} -static inline void kmemleak_ignore_phys(phys_addr_t phys) -{ -} - -#endif /* CONFIG_DEBUG_KMEMLEAK */ - -#endif /* __KMEMLEAK_H */ diff --git a/src/linux/include/linux/kmod.h b/src/linux/include/linux/kmod.h deleted file mode 100644 index fcfd2bf..0000000 --- a/src/linux/include/linux/kmod.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef __LINUX_KMOD_H__ -#define __LINUX_KMOD_H__ - -/* - * include/linux/kmod.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include - -#define KMOD_PATH_LEN 256 - -#ifdef CONFIG_MODULES -extern char modprobe_path[]; /* for sysctl */ -/* modprobe exit status on success, -ve on error. Return value - * usually useless though. */ -extern __printf(2, 3) -int __request_module(bool wait, const char *name, ...); -#define request_module(mod...) __request_module(true, mod) -#define request_module_nowait(mod...) __request_module(false, mod) -#define try_then_request_module(x, mod...) \ - ((x) ?: (__request_module(true, mod), (x))) -#else -static inline int request_module(const char *name, ...) { return -ENOSYS; } -static inline int request_module_nowait(const char *name, ...) { return -ENOSYS; } -#define try_then_request_module(x, mod...) (x) -#endif - - -struct cred; -struct file; - -#define UMH_NO_WAIT 0 /* don't wait at all */ -#define UMH_WAIT_EXEC 1 /* wait for the exec, but not the process */ -#define UMH_WAIT_PROC 2 /* wait for the process to complete */ -#define UMH_KILLABLE 4 /* wait for EXEC/PROC killable */ - -struct subprocess_info { - struct work_struct work; - struct completion *complete; - char *path; - char **argv; - char **envp; - int wait; - int retval; - int (*init)(struct subprocess_info *info, struct cred *new); - void (*cleanup)(struct subprocess_info *info); - void *data; -}; - -extern int -call_usermodehelper(char *path, char **argv, char **envp, int wait); - -extern struct subprocess_info * -call_usermodehelper_setup(char *path, char **argv, char **envp, gfp_t gfp_mask, - int (*init)(struct subprocess_info *info, struct cred *new), - void (*cleanup)(struct subprocess_info *), void *data); - -extern int -call_usermodehelper_exec(struct subprocess_info *info, int wait); - -extern struct ctl_table usermodehelper_table[]; - -enum umh_disable_depth { - UMH_ENABLED = 0, - UMH_FREEZING, - UMH_DISABLED, -}; - -extern int __usermodehelper_disable(enum umh_disable_depth depth); -extern void __usermodehelper_set_disable_depth(enum umh_disable_depth depth); - -static inline int usermodehelper_disable(void) -{ - return __usermodehelper_disable(UMH_DISABLED); -} - -static inline void usermodehelper_enable(void) -{ - __usermodehelper_set_disable_depth(UMH_ENABLED); -} - -extern int usermodehelper_read_trylock(void); -extern long usermodehelper_read_lock_wait(long timeout); -extern void usermodehelper_read_unlock(void); - -#endif /* __LINUX_KMOD_H__ */ diff --git a/src/linux/include/linux/kmsg_dump.h b/src/linux/include/linux/kmsg_dump.h deleted file mode 100644 index 2e7a1e0..0000000 --- a/src/linux/include/linux/kmsg_dump.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * linux/include/kmsg_dump.h - * - * Copyright (C) 2009 Net Insight AB - * - * Author: Simon Kagstrom - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive - * for more details. - */ -#ifndef _LINUX_KMSG_DUMP_H -#define _LINUX_KMSG_DUMP_H - -#include -#include - -/* - * Keep this list arranged in rough order of priority. Anything listed after - * KMSG_DUMP_OOPS will not be logged by default unless printk.always_kmsg_dump - * is passed to the kernel. - */ -enum kmsg_dump_reason { - KMSG_DUMP_UNDEF, - KMSG_DUMP_PANIC, - KMSG_DUMP_OOPS, - KMSG_DUMP_EMERG, - KMSG_DUMP_RESTART, - KMSG_DUMP_HALT, - KMSG_DUMP_POWEROFF, -}; - -/** - * struct kmsg_dumper - kernel crash message dumper structure - * @list: Entry in the dumper list (private) - * @dump: Call into dumping code which will retrieve the data with - * through the record iterator - * @max_reason: filter for highest reason number that should be dumped - * @registered: Flag that specifies if this is already registered - */ -struct kmsg_dumper { - struct list_head list; - void (*dump)(struct kmsg_dumper *dumper, enum kmsg_dump_reason reason); - enum kmsg_dump_reason max_reason; - bool active; - bool registered; - - /* private state of the kmsg iterator */ - u32 cur_idx; - u32 next_idx; - u64 cur_seq; - u64 next_seq; -}; - -#ifdef CONFIG_PRINTK -void kmsg_dump(enum kmsg_dump_reason reason); - -bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog, - char *line, size_t size, size_t *len); - -bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, - char *line, size_t size, size_t *len); - -bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, - char *buf, size_t size, size_t *len); - -void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper); - -void kmsg_dump_rewind(struct kmsg_dumper *dumper); - -int kmsg_dump_register(struct kmsg_dumper *dumper); - -int kmsg_dump_unregister(struct kmsg_dumper *dumper); -#else -static inline void kmsg_dump(enum kmsg_dump_reason reason) -{ -} - -static inline bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, - bool syslog, const char *line, - size_t size, size_t *len) -{ - return false; -} - -static inline bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, - const char *line, size_t size, size_t *len) -{ - return false; -} - -static inline bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, - char *buf, size_t size, size_t *len) -{ - return false; -} - -static inline void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper) -{ -} - -static inline void kmsg_dump_rewind(struct kmsg_dumper *dumper) -{ -} - -static inline int kmsg_dump_register(struct kmsg_dumper *dumper) -{ - return -EINVAL; -} - -static inline int kmsg_dump_unregister(struct kmsg_dumper *dumper) -{ - return -EINVAL; -} -#endif - -#endif /* _LINUX_KMSG_DUMP_H */ diff --git a/src/linux/include/linux/kobj_map.h b/src/linux/include/linux/kobj_map.h deleted file mode 100644 index 18ca75f..0000000 --- a/src/linux/include/linux/kobj_map.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * kobj_map.h - */ - -#ifndef _KOBJ_MAP_H_ -#define _KOBJ_MAP_H_ - -#include - -typedef struct kobject *kobj_probe_t(dev_t, int *, void *); -struct kobj_map; - -int kobj_map(struct kobj_map *, dev_t, unsigned long, struct module *, - kobj_probe_t *, int (*)(dev_t, void *), void *); -void kobj_unmap(struct kobj_map *, dev_t, unsigned long); -struct kobject *kobj_lookup(struct kobj_map *, dev_t, int *); -struct kobj_map *kobj_map_init(kobj_probe_t *, struct mutex *); - -#endif /* _KOBJ_MAP_H_ */ diff --git a/src/linux/include/linux/kobject.h b/src/linux/include/linux/kobject.h deleted file mode 100644 index e628459..0000000 --- a/src/linux/include/linux/kobject.h +++ /dev/null @@ -1,225 +0,0 @@ -/* - * kobject.h - generic kernel object infrastructure. - * - * Copyright (c) 2002-2003 Patrick Mochel - * Copyright (c) 2002-2003 Open Source Development Labs - * Copyright (c) 2006-2008 Greg Kroah-Hartman - * Copyright (c) 2006-2008 Novell Inc. - * - * This file is released under the GPLv2. - * - * Please read Documentation/kobject.txt before using the kobject - * interface, ESPECIALLY the parts about reference counts and object - * destructors. - */ - -#ifndef _KOBJECT_H_ -#define _KOBJECT_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define UEVENT_HELPER_PATH_LEN 256 -#define UEVENT_NUM_ENVP 32 /* number of env pointers */ -#define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */ - -#ifdef CONFIG_UEVENT_HELPER -/* path to the userspace helper executed on an event */ -extern char uevent_helper[]; -#endif - -/* counter to tag the uevent, read only except for the kobject core */ -extern u64 uevent_seqnum; - -/* - * The actions here must match the index to the string array - * in lib/kobject_uevent.c - * - * Do not add new actions here without checking with the driver-core - * maintainers. Action strings are not meant to express subsystem - * or device specific properties. In most cases you want to send a - * kobject_uevent_env(kobj, KOBJ_CHANGE, env) with additional event - * specific variables added to the event environment. - */ -enum kobject_action { - KOBJ_ADD, - KOBJ_REMOVE, - KOBJ_CHANGE, - KOBJ_MOVE, - KOBJ_ONLINE, - KOBJ_OFFLINE, - KOBJ_MAX -}; - -struct kobject { - const char *name; - struct list_head entry; - struct kobject *parent; - struct kset *kset; - struct kobj_type *ktype; - struct kernfs_node *sd; /* sysfs directory entry */ - struct kref kref; -#ifdef CONFIG_DEBUG_KOBJECT_RELEASE - struct delayed_work release; -#endif - unsigned int state_initialized:1; - unsigned int state_in_sysfs:1; - unsigned int state_add_uevent_sent:1; - unsigned int state_remove_uevent_sent:1; - unsigned int uevent_suppress:1; -}; - -extern __printf(2, 3) -int kobject_set_name(struct kobject *kobj, const char *name, ...); -extern __printf(2, 0) -int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, - va_list vargs); - -static inline const char *kobject_name(const struct kobject *kobj) -{ - return kobj->name; -} - -extern void kobject_init(struct kobject *kobj, struct kobj_type *ktype); -extern __printf(3, 4) __must_check -int kobject_add(struct kobject *kobj, struct kobject *parent, - const char *fmt, ...); -extern __printf(4, 5) __must_check -int kobject_init_and_add(struct kobject *kobj, - struct kobj_type *ktype, struct kobject *parent, - const char *fmt, ...); - -extern void kobject_del(struct kobject *kobj); - -extern struct kobject * __must_check kobject_create(void); -extern struct kobject * __must_check kobject_create_and_add(const char *name, - struct kobject *parent); - -extern int __must_check kobject_rename(struct kobject *, const char *new_name); -extern int __must_check kobject_move(struct kobject *, struct kobject *); - -extern struct kobject *kobject_get(struct kobject *kobj); -extern void kobject_put(struct kobject *kobj); - -extern const void *kobject_namespace(struct kobject *kobj); -extern char *kobject_get_path(struct kobject *kobj, gfp_t flag); - -struct kobj_type { - void (*release)(struct kobject *kobj); - const struct sysfs_ops *sysfs_ops; - struct attribute **default_attrs; - const struct kobj_ns_type_operations *(*child_ns_type)(struct kobject *kobj); - const void *(*namespace)(struct kobject *kobj); -}; - -struct kobj_uevent_env { - char *argv[3]; - char *envp[UEVENT_NUM_ENVP]; - int envp_idx; - char buf[UEVENT_BUFFER_SIZE]; - int buflen; -}; - -struct kset_uevent_ops { - int (* const filter)(struct kset *kset, struct kobject *kobj); - const char *(* const name)(struct kset *kset, struct kobject *kobj); - int (* const uevent)(struct kset *kset, struct kobject *kobj, - struct kobj_uevent_env *env); -}; - -struct kobj_attribute { - struct attribute attr; - ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr, - char *buf); - ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr, - const char *buf, size_t count); -}; - -extern const struct sysfs_ops kobj_sysfs_ops; - -struct sock; - -/** - * struct kset - a set of kobjects of a specific type, belonging to a specific subsystem. - * - * A kset defines a group of kobjects. They can be individually - * different "types" but overall these kobjects all want to be grouped - * together and operated on in the same manner. ksets are used to - * define the attribute callbacks and other common events that happen to - * a kobject. - * - * @list: the list of all kobjects for this kset - * @list_lock: a lock for iterating over the kobjects - * @kobj: the embedded kobject for this kset (recursion, isn't it fun...) - * @uevent_ops: the set of uevent operations for this kset. These are - * called whenever a kobject has something happen to it so that the kset - * can add new environment variables, or filter out the uevents if so - * desired. - */ -struct kset { - struct list_head list; - spinlock_t list_lock; - struct kobject kobj; - const struct kset_uevent_ops *uevent_ops; -}; - -extern void kset_init(struct kset *kset); -extern int __must_check kset_register(struct kset *kset); -extern void kset_unregister(struct kset *kset); -extern struct kset * __must_check kset_create_and_add(const char *name, - const struct kset_uevent_ops *u, - struct kobject *parent_kobj); - -static inline struct kset *to_kset(struct kobject *kobj) -{ - return kobj ? container_of(kobj, struct kset, kobj) : NULL; -} - -static inline struct kset *kset_get(struct kset *k) -{ - return k ? to_kset(kobject_get(&k->kobj)) : NULL; -} - -static inline void kset_put(struct kset *k) -{ - kobject_put(&k->kobj); -} - -static inline struct kobj_type *get_ktype(struct kobject *kobj) -{ - return kobj->ktype; -} - -extern struct kobject *kset_find_obj(struct kset *, const char *); - -/* The global /sys/kernel/ kobject for people to chain off of */ -extern struct kobject *kernel_kobj; -/* The global /sys/kernel/mm/ kobject for people to chain off of */ -extern struct kobject *mm_kobj; -/* The global /sys/hypervisor/ kobject for people to chain off of */ -extern struct kobject *hypervisor_kobj; -/* The global /sys/power/ kobject for people to chain off of */ -extern struct kobject *power_kobj; -/* The global /sys/firmware/ kobject for people to chain off of */ -extern struct kobject *firmware_kobj; - -int kobject_uevent(struct kobject *kobj, enum kobject_action action); -int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, - char *envp[]); - -__printf(2, 3) -int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...); - -int kobject_action_type(const char *buf, size_t count, - enum kobject_action *type); - -#endif /* _KOBJECT_H_ */ diff --git a/src/linux/include/linux/kobject_ns.h b/src/linux/include/linux/kobject_ns.h deleted file mode 100644 index df32d25..0000000 --- a/src/linux/include/linux/kobject_ns.h +++ /dev/null @@ -1,60 +0,0 @@ -/* Kernel object name space definitions - * - * Copyright (c) 2002-2003 Patrick Mochel - * Copyright (c) 2002-2003 Open Source Development Labs - * Copyright (c) 2006-2008 Greg Kroah-Hartman - * Copyright (c) 2006-2008 Novell Inc. - * - * Split from kobject.h by David Howells (dhowells@redhat.com) - * - * This file is released under the GPLv2. - * - * Please read Documentation/kobject.txt before using the kobject - * interface, ESPECIALLY the parts about reference counts and object - * destructors. - */ - -#ifndef _LINUX_KOBJECT_NS_H -#define _LINUX_KOBJECT_NS_H - -struct sock; -struct kobject; - -/* - * Namespace types which are used to tag kobjects and sysfs entries. - * Network namespace will likely be the first. - */ -enum kobj_ns_type { - KOBJ_NS_TYPE_NONE = 0, - KOBJ_NS_TYPE_NET, - KOBJ_NS_TYPES -}; - -/* - * Callbacks so sysfs can determine namespaces - * @grab_current_ns: return a new reference to calling task's namespace - * @netlink_ns: return namespace to which a sock belongs (right?) - * @initial_ns: return the initial namespace (i.e. init_net_ns) - * @drop_ns: drops a reference to namespace - */ -struct kobj_ns_type_operations { - enum kobj_ns_type type; - bool (*current_may_mount)(void); - void *(*grab_current_ns)(void); - const void *(*netlink_ns)(struct sock *sk); - const void *(*initial_ns)(void); - void (*drop_ns)(void *); -}; - -int kobj_ns_type_register(const struct kobj_ns_type_operations *ops); -int kobj_ns_type_registered(enum kobj_ns_type type); -const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent); -const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj); - -bool kobj_ns_current_may_mount(enum kobj_ns_type type); -void *kobj_ns_grab_current(enum kobj_ns_type type); -const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk); -const void *kobj_ns_initial(enum kobj_ns_type type); -void kobj_ns_drop(enum kobj_ns_type type, void *ns); - -#endif /* _LINUX_KOBJECT_NS_H */ diff --git a/src/linux/include/linux/kprobes.h b/src/linux/include/linux/kprobes.h deleted file mode 100644 index 8f68490..0000000 --- a/src/linux/include/linux/kprobes.h +++ /dev/null @@ -1,498 +0,0 @@ -#ifndef _LINUX_KPROBES_H -#define _LINUX_KPROBES_H -/* - * Kernel Probes (KProbes) - * include/linux/kprobes.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) IBM Corporation, 2002, 2004 - * - * 2002-Oct Created by Vamsi Krishna S Kernel - * Probes initial implementation ( includes suggestions from - * Rusty Russell). - * 2004-July Suparna Bhattacharya added jumper probes - * interface to access function arguments. - * 2005-May Hien Nguyen and Jim Keniston - * and Prasanna S Panchamukhi - * added function-return probes. - */ -#include /* for __kprobes */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_KPROBES -#include - -/* kprobe_status settings */ -#define KPROBE_HIT_ACTIVE 0x00000001 -#define KPROBE_HIT_SS 0x00000002 -#define KPROBE_REENTER 0x00000004 -#define KPROBE_HIT_SSDONE 0x00000008 - -#else /* CONFIG_KPROBES */ -typedef int kprobe_opcode_t; -struct arch_specific_insn { - int dummy; -}; -#endif /* CONFIG_KPROBES */ - -struct kprobe; -struct pt_regs; -struct kretprobe; -struct kretprobe_instance; -typedef int (*kprobe_pre_handler_t) (struct kprobe *, struct pt_regs *); -typedef int (*kprobe_break_handler_t) (struct kprobe *, struct pt_regs *); -typedef void (*kprobe_post_handler_t) (struct kprobe *, struct pt_regs *, - unsigned long flags); -typedef int (*kprobe_fault_handler_t) (struct kprobe *, struct pt_regs *, - int trapnr); -typedef int (*kretprobe_handler_t) (struct kretprobe_instance *, - struct pt_regs *); - -struct kprobe { - struct hlist_node hlist; - - /* list of kprobes for multi-handler support */ - struct list_head list; - - /*count the number of times this probe was temporarily disarmed */ - unsigned long nmissed; - - /* location of the probe point */ - kprobe_opcode_t *addr; - - /* Allow user to indicate symbol name of the probe point */ - const char *symbol_name; - - /* Offset into the symbol */ - unsigned int offset; - - /* Called before addr is executed. */ - kprobe_pre_handler_t pre_handler; - - /* Called after addr is executed, unless... */ - kprobe_post_handler_t post_handler; - - /* - * ... called if executing addr causes a fault (eg. page fault). - * Return 1 if it handled fault, otherwise kernel will see it. - */ - kprobe_fault_handler_t fault_handler; - - /* - * ... called if breakpoint trap occurs in probe handler. - * Return 1 if it handled break, otherwise kernel will see it. - */ - kprobe_break_handler_t break_handler; - - /* Saved opcode (which has been replaced with breakpoint) */ - kprobe_opcode_t opcode; - - /* copy of the original instruction */ - struct arch_specific_insn ainsn; - - /* - * Indicates various status flags. - * Protected by kprobe_mutex after this kprobe is registered. - */ - u32 flags; -}; - -/* Kprobe status flags */ -#define KPROBE_FLAG_GONE 1 /* breakpoint has already gone */ -#define KPROBE_FLAG_DISABLED 2 /* probe is temporarily disabled */ -#define KPROBE_FLAG_OPTIMIZED 4 /* - * probe is really optimized. - * NOTE: - * this flag is only for optimized_kprobe. - */ -#define KPROBE_FLAG_FTRACE 8 /* probe is using ftrace */ - -/* Has this kprobe gone ? */ -static inline int kprobe_gone(struct kprobe *p) -{ - return p->flags & KPROBE_FLAG_GONE; -} - -/* Is this kprobe disabled ? */ -static inline int kprobe_disabled(struct kprobe *p) -{ - return p->flags & (KPROBE_FLAG_DISABLED | KPROBE_FLAG_GONE); -} - -/* Is this kprobe really running optimized path ? */ -static inline int kprobe_optimized(struct kprobe *p) -{ - return p->flags & KPROBE_FLAG_OPTIMIZED; -} - -/* Is this kprobe uses ftrace ? */ -static inline int kprobe_ftrace(struct kprobe *p) -{ - return p->flags & KPROBE_FLAG_FTRACE; -} - -/* - * Special probe type that uses setjmp-longjmp type tricks to resume - * execution at a specified entry with a matching prototype corresponding - * to the probed function - a trick to enable arguments to become - * accessible seamlessly by probe handling logic. - * Note: - * Because of the way compilers allocate stack space for local variables - * etc upfront, regardless of sub-scopes within a function, this mirroring - * principle currently works only for probes placed on function entry points. - */ -struct jprobe { - struct kprobe kp; - void *entry; /* probe handling code to jump to */ -}; - -/* For backward compatibility with old code using JPROBE_ENTRY() */ -#define JPROBE_ENTRY(handler) (handler) - -/* - * Function-return probe - - * Note: - * User needs to provide a handler function, and initialize maxactive. - * maxactive - The maximum number of instances of the probed function that - * can be active concurrently. - * nmissed - tracks the number of times the probed function's return was - * ignored, due to maxactive being too low. - * - */ -struct kretprobe { - struct kprobe kp; - kretprobe_handler_t handler; - kretprobe_handler_t entry_handler; - int maxactive; - int nmissed; - size_t data_size; - struct hlist_head free_instances; - raw_spinlock_t lock; -}; - -struct kretprobe_instance { - struct hlist_node hlist; - struct kretprobe *rp; - kprobe_opcode_t *ret_addr; - struct task_struct *task; - char data[0]; -}; - -struct kretprobe_blackpoint { - const char *name; - void *addr; -}; - -struct kprobe_blacklist_entry { - struct list_head list; - unsigned long start_addr; - unsigned long end_addr; -}; - -#ifdef CONFIG_KPROBES -DECLARE_PER_CPU(struct kprobe *, current_kprobe); -DECLARE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); - -/* - * For #ifdef avoidance: - */ -static inline int kprobes_built_in(void) -{ - return 1; -} - -#ifdef CONFIG_KRETPROBES -extern void arch_prepare_kretprobe(struct kretprobe_instance *ri, - struct pt_regs *regs); -extern int arch_trampoline_kprobe(struct kprobe *p); -#else /* CONFIG_KRETPROBES */ -static inline void arch_prepare_kretprobe(struct kretprobe *rp, - struct pt_regs *regs) -{ -} -static inline int arch_trampoline_kprobe(struct kprobe *p) -{ - return 0; -} -#endif /* CONFIG_KRETPROBES */ - -extern struct kretprobe_blackpoint kretprobe_blacklist[]; - -static inline void kretprobe_assert(struct kretprobe_instance *ri, - unsigned long orig_ret_address, unsigned long trampoline_address) -{ - if (!orig_ret_address || (orig_ret_address == trampoline_address)) { - printk("kretprobe BUG!: Processing kretprobe %p @ %p\n", - ri->rp, ri->rp->kp.addr); - BUG(); - } -} - -#ifdef CONFIG_KPROBES_SANITY_TEST -extern int init_test_probes(void); -#else -static inline int init_test_probes(void) -{ - return 0; -} -#endif /* CONFIG_KPROBES_SANITY_TEST */ - -extern int arch_prepare_kprobe(struct kprobe *p); -extern void arch_arm_kprobe(struct kprobe *p); -extern void arch_disarm_kprobe(struct kprobe *p); -extern int arch_init_kprobes(void); -extern void show_registers(struct pt_regs *regs); -extern void kprobes_inc_nmissed_count(struct kprobe *p); -extern bool arch_within_kprobe_blacklist(unsigned long addr); - -extern bool within_kprobe_blacklist(unsigned long addr); - -struct kprobe_insn_cache { - struct mutex mutex; - void *(*alloc)(void); /* allocate insn page */ - void (*free)(void *); /* free insn page */ - struct list_head pages; /* list of kprobe_insn_page */ - size_t insn_size; /* size of instruction slot */ - int nr_garbage; -}; - -extern kprobe_opcode_t *__get_insn_slot(struct kprobe_insn_cache *c); -extern void __free_insn_slot(struct kprobe_insn_cache *c, - kprobe_opcode_t *slot, int dirty); - -#define DEFINE_INSN_CACHE_OPS(__name) \ -extern struct kprobe_insn_cache kprobe_##__name##_slots; \ - \ -static inline kprobe_opcode_t *get_##__name##_slot(void) \ -{ \ - return __get_insn_slot(&kprobe_##__name##_slots); \ -} \ - \ -static inline void free_##__name##_slot(kprobe_opcode_t *slot, int dirty)\ -{ \ - __free_insn_slot(&kprobe_##__name##_slots, slot, dirty); \ -} \ - -DEFINE_INSN_CACHE_OPS(insn); - -#ifdef CONFIG_OPTPROBES -/* - * Internal structure for direct jump optimized probe - */ -struct optimized_kprobe { - struct kprobe kp; - struct list_head list; /* list for optimizing queue */ - struct arch_optimized_insn optinsn; -}; - -/* Architecture dependent functions for direct jump optimization */ -extern int arch_prepared_optinsn(struct arch_optimized_insn *optinsn); -extern int arch_check_optimized_kprobe(struct optimized_kprobe *op); -extern int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, - struct kprobe *orig); -extern void arch_remove_optimized_kprobe(struct optimized_kprobe *op); -extern void arch_optimize_kprobes(struct list_head *oplist); -extern void arch_unoptimize_kprobes(struct list_head *oplist, - struct list_head *done_list); -extern void arch_unoptimize_kprobe(struct optimized_kprobe *op); -extern int arch_within_optimized_kprobe(struct optimized_kprobe *op, - unsigned long addr); - -extern void opt_pre_handler(struct kprobe *p, struct pt_regs *regs); - -DEFINE_INSN_CACHE_OPS(optinsn); - -#ifdef CONFIG_SYSCTL -extern int sysctl_kprobes_optimization; -extern int proc_kprobes_optimization_handler(struct ctl_table *table, - int write, void __user *buffer, - size_t *length, loff_t *ppos); -#endif - -#endif /* CONFIG_OPTPROBES */ -#ifdef CONFIG_KPROBES_ON_FTRACE -extern void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip, - struct ftrace_ops *ops, struct pt_regs *regs); -extern int arch_prepare_kprobe_ftrace(struct kprobe *p); -#endif - -int arch_check_ftrace_location(struct kprobe *p); - -/* Get the kprobe at this addr (if any) - called with preemption disabled */ -struct kprobe *get_kprobe(void *addr); -void kretprobe_hash_lock(struct task_struct *tsk, - struct hlist_head **head, unsigned long *flags); -void kretprobe_hash_unlock(struct task_struct *tsk, unsigned long *flags); -struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk); - -/* kprobe_running() will just return the current_kprobe on this CPU */ -static inline struct kprobe *kprobe_running(void) -{ - return (__this_cpu_read(current_kprobe)); -} - -static inline void reset_current_kprobe(void) -{ - __this_cpu_write(current_kprobe, NULL); -} - -static inline struct kprobe_ctlblk *get_kprobe_ctlblk(void) -{ - return this_cpu_ptr(&kprobe_ctlblk); -} - -int register_kprobe(struct kprobe *p); -void unregister_kprobe(struct kprobe *p); -int register_kprobes(struct kprobe **kps, int num); -void unregister_kprobes(struct kprobe **kps, int num); -int setjmp_pre_handler(struct kprobe *, struct pt_regs *); -int longjmp_break_handler(struct kprobe *, struct pt_regs *); -int register_jprobe(struct jprobe *p); -void unregister_jprobe(struct jprobe *p); -int register_jprobes(struct jprobe **jps, int num); -void unregister_jprobes(struct jprobe **jps, int num); -void jprobe_return(void); -unsigned long arch_deref_entry_point(void *); - -int register_kretprobe(struct kretprobe *rp); -void unregister_kretprobe(struct kretprobe *rp); -int register_kretprobes(struct kretprobe **rps, int num); -void unregister_kretprobes(struct kretprobe **rps, int num); - -void kprobe_flush_task(struct task_struct *tk); -void recycle_rp_inst(struct kretprobe_instance *ri, struct hlist_head *head); - -int disable_kprobe(struct kprobe *kp); -int enable_kprobe(struct kprobe *kp); - -void dump_kprobe(struct kprobe *kp); - -#else /* !CONFIG_KPROBES: */ - -static inline int kprobes_built_in(void) -{ - return 0; -} -static inline int kprobe_fault_handler(struct pt_regs *regs, int trapnr) -{ - return 0; -} -static inline struct kprobe *get_kprobe(void *addr) -{ - return NULL; -} -static inline struct kprobe *kprobe_running(void) -{ - return NULL; -} -static inline int register_kprobe(struct kprobe *p) -{ - return -ENOSYS; -} -static inline int register_kprobes(struct kprobe **kps, int num) -{ - return -ENOSYS; -} -static inline void unregister_kprobe(struct kprobe *p) -{ -} -static inline void unregister_kprobes(struct kprobe **kps, int num) -{ -} -static inline int register_jprobe(struct jprobe *p) -{ - return -ENOSYS; -} -static inline int register_jprobes(struct jprobe **jps, int num) -{ - return -ENOSYS; -} -static inline void unregister_jprobe(struct jprobe *p) -{ -} -static inline void unregister_jprobes(struct jprobe **jps, int num) -{ -} -static inline void jprobe_return(void) -{ -} -static inline int register_kretprobe(struct kretprobe *rp) -{ - return -ENOSYS; -} -static inline int register_kretprobes(struct kretprobe **rps, int num) -{ - return -ENOSYS; -} -static inline void unregister_kretprobe(struct kretprobe *rp) -{ -} -static inline void unregister_kretprobes(struct kretprobe **rps, int num) -{ -} -static inline void kprobe_flush_task(struct task_struct *tk) -{ -} -static inline int disable_kprobe(struct kprobe *kp) -{ - return -ENOSYS; -} -static inline int enable_kprobe(struct kprobe *kp) -{ - return -ENOSYS; -} -#endif /* CONFIG_KPROBES */ -static inline int disable_kretprobe(struct kretprobe *rp) -{ - return disable_kprobe(&rp->kp); -} -static inline int enable_kretprobe(struct kretprobe *rp) -{ - return enable_kprobe(&rp->kp); -} -static inline int disable_jprobe(struct jprobe *jp) -{ - return disable_kprobe(&jp->kp); -} -static inline int enable_jprobe(struct jprobe *jp) -{ - return enable_kprobe(&jp->kp); -} - -#ifdef CONFIG_KPROBES -/* - * Blacklist ganerating macro. Specify functions which is not probed - * by using this macro. - */ -#define __NOKPROBE_SYMBOL(fname) \ -static unsigned long __used \ - __attribute__((section("_kprobe_blacklist"))) \ - _kbl_addr_##fname = (unsigned long)fname; -#define NOKPROBE_SYMBOL(fname) __NOKPROBE_SYMBOL(fname) -#else -#define NOKPROBE_SYMBOL(fname) -#endif - -#endif /* _LINUX_KPROBES_H */ diff --git a/src/linux/include/linux/kref.h b/src/linux/include/linux/kref.h deleted file mode 100644 index e15828f..0000000 --- a/src/linux/include/linux/kref.h +++ /dev/null @@ -1,138 +0,0 @@ -/* - * kref.h - library routines for handling generic reference counted objects - * - * Copyright (C) 2004 Greg Kroah-Hartman - * Copyright (C) 2004 IBM Corp. - * - * based on kobject.h which was: - * Copyright (C) 2002-2003 Patrick Mochel - * Copyright (C) 2002-2003 Open Source Development Labs - * - * This file is released under the GPLv2. - * - */ - -#ifndef _KREF_H_ -#define _KREF_H_ - -#include -#include -#include -#include - -struct kref { - atomic_t refcount; -}; - -/** - * kref_init - initialize object. - * @kref: object in question. - */ -static inline void kref_init(struct kref *kref) -{ - atomic_set(&kref->refcount, 1); -} - -/** - * kref_get - increment refcount for object. - * @kref: object. - */ -static inline void kref_get(struct kref *kref) -{ - /* If refcount was 0 before incrementing then we have a race - * condition when this kref is freeing by some other thread right now. - * In this case one should use kref_get_unless_zero() - */ - WARN_ON_ONCE(atomic_inc_return(&kref->refcount) < 2); -} - -/** - * kref_sub - subtract a number of refcounts for object. - * @kref: object. - * @count: Number of recounts to subtract. - * @release: pointer to the function that will clean up the object when the - * last reference to the object is released. - * This pointer is required, and it is not acceptable to pass kfree - * in as this function. If the caller does pass kfree to this - * function, you will be publicly mocked mercilessly by the kref - * maintainer, and anyone else who happens to notice it. You have - * been warned. - * - * Subtract @count from the refcount, and if 0, call release(). - * Return 1 if the object was removed, otherwise return 0. Beware, if this - * function returns 0, you still can not count on the kref from remaining in - * memory. Only use the return value if you want to see if the kref is now - * gone, not present. - */ -static inline int kref_sub(struct kref *kref, unsigned int count, - void (*release)(struct kref *kref)) -{ - WARN_ON(release == NULL); - - if (atomic_sub_and_test((int) count, &kref->refcount)) { - release(kref); - return 1; - } - return 0; -} - -/** - * kref_put - decrement refcount for object. - * @kref: object. - * @release: pointer to the function that will clean up the object when the - * last reference to the object is released. - * This pointer is required, and it is not acceptable to pass kfree - * in as this function. If the caller does pass kfree to this - * function, you will be publicly mocked mercilessly by the kref - * maintainer, and anyone else who happens to notice it. You have - * been warned. - * - * Decrement the refcount, and if 0, call release(). - * Return 1 if the object was removed, otherwise return 0. Beware, if this - * function returns 0, you still can not count on the kref from remaining in - * memory. Only use the return value if you want to see if the kref is now - * gone, not present. - */ -static inline int kref_put(struct kref *kref, void (*release)(struct kref *kref)) -{ - return kref_sub(kref, 1, release); -} - -static inline int kref_put_mutex(struct kref *kref, - void (*release)(struct kref *kref), - struct mutex *lock) -{ - WARN_ON(release == NULL); - if (unlikely(!atomic_add_unless(&kref->refcount, -1, 1))) { - mutex_lock(lock); - if (unlikely(!atomic_dec_and_test(&kref->refcount))) { - mutex_unlock(lock); - return 0; - } - release(kref); - return 1; - } - return 0; -} - -/** - * kref_get_unless_zero - Increment refcount for object unless it is zero. - * @kref: object. - * - * Return non-zero if the increment succeeded. Otherwise return 0. - * - * This function is intended to simplify locking around refcounting for - * objects that can be looked up from a lookup structure, and which are - * removed from that lookup structure in the object destructor. - * Operations on such objects require at least a read lock around - * lookup + kref_get, and a write lock around kref_put + remove from lookup - * structure. Furthermore, RCU implementations become extremely tricky. - * With a lookup followed by a kref_get_unless_zero *with return value check* - * locking in the kref_put path can be deferred to the actual removal from - * the lookup structure and RCU lookups become trivial. - */ -static inline int __must_check kref_get_unless_zero(struct kref *kref) -{ - return atomic_add_unless(&kref->refcount, 1, 0); -} -#endif /* _KREF_H_ */ diff --git a/src/linux/include/linux/ksm.h b/src/linux/include/linux/ksm.h deleted file mode 100644 index 481c8c4..0000000 --- a/src/linux/include/linux/ksm.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef __LINUX_KSM_H -#define __LINUX_KSM_H -/* - * Memory merging support. - * - * This code enables dynamic sharing of identical pages found in different - * memory areas, even if they are not shared by fork(). - */ - -#include -#include -#include -#include -#include - -struct stable_node; -struct mem_cgroup; - -#ifdef CONFIG_KSM -int ksm_madvise(struct vm_area_struct *vma, unsigned long start, - unsigned long end, int advice, unsigned long *vm_flags); -int __ksm_enter(struct mm_struct *mm); -void __ksm_exit(struct mm_struct *mm); - -static inline int ksm_fork(struct mm_struct *mm, struct mm_struct *oldmm) -{ - if (test_bit(MMF_VM_MERGEABLE, &oldmm->flags)) - return __ksm_enter(mm); - return 0; -} - -static inline void ksm_exit(struct mm_struct *mm) -{ - if (test_bit(MMF_VM_MERGEABLE, &mm->flags)) - __ksm_exit(mm); -} - -static inline struct stable_node *page_stable_node(struct page *page) -{ - return PageKsm(page) ? page_rmapping(page) : NULL; -} - -static inline void set_page_stable_node(struct page *page, - struct stable_node *stable_node) -{ - page->mapping = (void *)((unsigned long)stable_node | PAGE_MAPPING_KSM); -} - -/* - * When do_swap_page() first faults in from swap what used to be a KSM page, - * no problem, it will be assigned to this vma's anon_vma; but thereafter, - * it might be faulted into a different anon_vma (or perhaps to a different - * offset in the same anon_vma). do_swap_page() cannot do all the locking - * needed to reconstitute a cross-anon_vma KSM page: for now it has to make - * a copy, and leave remerging the pages to a later pass of ksmd. - * - * We'd like to make this conditional on vma->vm_flags & VM_MERGEABLE, - * but what if the vma was unmerged while the page was swapped out? - */ -struct page *ksm_might_need_to_copy(struct page *page, - struct vm_area_struct *vma, unsigned long address); - -int rmap_walk_ksm(struct page *page, struct rmap_walk_control *rwc); -void ksm_migrate_page(struct page *newpage, struct page *oldpage); - -#else /* !CONFIG_KSM */ - -static inline int ksm_fork(struct mm_struct *mm, struct mm_struct *oldmm) -{ - return 0; -} - -static inline void ksm_exit(struct mm_struct *mm) -{ -} - -#ifdef CONFIG_MMU -static inline int ksm_madvise(struct vm_area_struct *vma, unsigned long start, - unsigned long end, int advice, unsigned long *vm_flags) -{ - return 0; -} - -static inline struct page *ksm_might_need_to_copy(struct page *page, - struct vm_area_struct *vma, unsigned long address) -{ - return page; -} - -static inline int page_referenced_ksm(struct page *page, - struct mem_cgroup *memcg, unsigned long *vm_flags) -{ - return 0; -} - -static inline int rmap_walk_ksm(struct page *page, - struct rmap_walk_control *rwc) -{ - return 0; -} - -static inline void ksm_migrate_page(struct page *newpage, struct page *oldpage) -{ -} -#endif /* CONFIG_MMU */ -#endif /* !CONFIG_KSM */ - -#endif /* __LINUX_KSM_H */ diff --git a/src/linux/include/linux/kthread.h b/src/linux/include/linux/kthread.h deleted file mode 100644 index a6e82a6..0000000 --- a/src/linux/include/linux/kthread.h +++ /dev/null @@ -1,200 +0,0 @@ -#ifndef _LINUX_KTHREAD_H -#define _LINUX_KTHREAD_H -/* Simple interface for creating and stopping kernel threads without mess. */ -#include -#include - -__printf(4, 5) -struct task_struct *kthread_create_on_node(int (*threadfn)(void *data), - void *data, - int node, - const char namefmt[], ...); - -/** - * kthread_create - create a kthread on the current node - * @threadfn: the function to run in the thread - * @data: data pointer for @threadfn() - * @namefmt: printf-style format string for the thread name - * @...: arguments for @namefmt. - * - * This macro will create a kthread on the current node, leaving it in - * the stopped state. This is just a helper for kthread_create_on_node(); - * see the documentation there for more details. - */ -#define kthread_create(threadfn, data, namefmt, arg...) \ - kthread_create_on_node(threadfn, data, NUMA_NO_NODE, namefmt, ##arg) - - -struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data), - void *data, - unsigned int cpu, - const char *namefmt); - -/** - * kthread_run - create and wake a thread. - * @threadfn: the function to run until signal_pending(current). - * @data: data ptr for @threadfn. - * @namefmt: printf-style name for the thread. - * - * Description: Convenient wrapper for kthread_create() followed by - * wake_up_process(). Returns the kthread or ERR_PTR(-ENOMEM). - */ -#define kthread_run(threadfn, data, namefmt, ...) \ -({ \ - struct task_struct *__k \ - = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \ - if (!IS_ERR(__k)) \ - wake_up_process(__k); \ - __k; \ -}) - -void kthread_bind(struct task_struct *k, unsigned int cpu); -void kthread_bind_mask(struct task_struct *k, const struct cpumask *mask); -int kthread_stop(struct task_struct *k); -bool kthread_should_stop(void); -bool kthread_should_park(void); -bool kthread_freezable_should_stop(bool *was_frozen); -void *kthread_data(struct task_struct *k); -void *kthread_probe_data(struct task_struct *k); -int kthread_park(struct task_struct *k); -void kthread_unpark(struct task_struct *k); -void kthread_parkme(void); - -int kthreadd(void *unused); -extern struct task_struct *kthreadd_task; -extern int tsk_fork_get_node(struct task_struct *tsk); - -/* - * Simple work processor based on kthread. - * - * This provides easier way to make use of kthreads. A kthread_work - * can be queued and flushed using queue/kthread_flush_work() - * respectively. Queued kthread_works are processed by a kthread - * running kthread_worker_fn(). - */ -struct kthread_work; -typedef void (*kthread_work_func_t)(struct kthread_work *work); -void kthread_delayed_work_timer_fn(unsigned long __data); - -enum { - KTW_FREEZABLE = 1 << 0, /* freeze during suspend */ -}; - -struct kthread_worker { - unsigned int flags; - spinlock_t lock; - struct list_head work_list; - struct list_head delayed_work_list; - struct task_struct *task; - struct kthread_work *current_work; -}; - -struct kthread_work { - struct list_head node; - kthread_work_func_t func; - struct kthread_worker *worker; - /* Number of canceling calls that are running at the moment. */ - int canceling; -}; - -struct kthread_delayed_work { - struct kthread_work work; - struct timer_list timer; -}; - -#define KTHREAD_WORKER_INIT(worker) { \ - .lock = __SPIN_LOCK_UNLOCKED((worker).lock), \ - .work_list = LIST_HEAD_INIT((worker).work_list), \ - .delayed_work_list = LIST_HEAD_INIT((worker).delayed_work_list),\ - } - -#define KTHREAD_WORK_INIT(work, fn) { \ - .node = LIST_HEAD_INIT((work).node), \ - .func = (fn), \ - } - -#define KTHREAD_DELAYED_WORK_INIT(dwork, fn) { \ - .work = KTHREAD_WORK_INIT((dwork).work, (fn)), \ - .timer = __TIMER_INITIALIZER(kthread_delayed_work_timer_fn, \ - 0, (unsigned long)&(dwork), \ - TIMER_IRQSAFE), \ - } - -#define DEFINE_KTHREAD_WORKER(worker) \ - struct kthread_worker worker = KTHREAD_WORKER_INIT(worker) - -#define DEFINE_KTHREAD_WORK(work, fn) \ - struct kthread_work work = KTHREAD_WORK_INIT(work, fn) - -#define DEFINE_KTHREAD_DELAYED_WORK(dwork, fn) \ - struct kthread_delayed_work dwork = \ - KTHREAD_DELAYED_WORK_INIT(dwork, fn) - -/* - * kthread_worker.lock needs its own lockdep class key when defined on - * stack with lockdep enabled. Use the following macros in such cases. - */ -#ifdef CONFIG_LOCKDEP -# define KTHREAD_WORKER_INIT_ONSTACK(worker) \ - ({ kthread_init_worker(&worker); worker; }) -# define DEFINE_KTHREAD_WORKER_ONSTACK(worker) \ - struct kthread_worker worker = KTHREAD_WORKER_INIT_ONSTACK(worker) -#else -# define DEFINE_KTHREAD_WORKER_ONSTACK(worker) DEFINE_KTHREAD_WORKER(worker) -#endif - -extern void __kthread_init_worker(struct kthread_worker *worker, - const char *name, struct lock_class_key *key); - -#define kthread_init_worker(worker) \ - do { \ - static struct lock_class_key __key; \ - __kthread_init_worker((worker), "("#worker")->lock", &__key); \ - } while (0) - -#define kthread_init_work(work, fn) \ - do { \ - memset((work), 0, sizeof(struct kthread_work)); \ - INIT_LIST_HEAD(&(work)->node); \ - (work)->func = (fn); \ - } while (0) - -#define kthread_init_delayed_work(dwork, fn) \ - do { \ - kthread_init_work(&(dwork)->work, (fn)); \ - __setup_timer(&(dwork)->timer, \ - kthread_delayed_work_timer_fn, \ - (unsigned long)(dwork), \ - TIMER_IRQSAFE); \ - } while (0) - -int kthread_worker_fn(void *worker_ptr); - -__printf(2, 3) -struct kthread_worker * -kthread_create_worker(unsigned int flags, const char namefmt[], ...); - -struct kthread_worker * -kthread_create_worker_on_cpu(int cpu, unsigned int flags, - const char namefmt[], ...); - -bool kthread_queue_work(struct kthread_worker *worker, - struct kthread_work *work); - -bool kthread_queue_delayed_work(struct kthread_worker *worker, - struct kthread_delayed_work *dwork, - unsigned long delay); - -bool kthread_mod_delayed_work(struct kthread_worker *worker, - struct kthread_delayed_work *dwork, - unsigned long delay); - -void kthread_flush_work(struct kthread_work *work); -void kthread_flush_worker(struct kthread_worker *worker); - -bool kthread_cancel_work_sync(struct kthread_work *work); -bool kthread_cancel_delayed_work_sync(struct kthread_delayed_work *work); - -void kthread_destroy_worker(struct kthread_worker *worker); - -#endif /* _LINUX_KTHREAD_H */ diff --git a/src/linux/include/linux/ktime.h b/src/linux/include/linux/ktime.h deleted file mode 100644 index 0fb7ffb..0000000 --- a/src/linux/include/linux/ktime.h +++ /dev/null @@ -1,311 +0,0 @@ -/* - * include/linux/ktime.h - * - * ktime_t - nanosecond-resolution time format. - * - * Copyright(C) 2005, Thomas Gleixner - * Copyright(C) 2005, Red Hat, Inc., Ingo Molnar - * - * data type definitions, declarations, prototypes and macros. - * - * Started by: Thomas Gleixner and Ingo Molnar - * - * Credits: - * - * Roman Zippel provided the ideas and primary code snippets of - * the ktime_t union and further simplifications of the original - * code. - * - * For licencing details see kernel-base/COPYING - */ -#ifndef _LINUX_KTIME_H -#define _LINUX_KTIME_H - -#include -#include - -/* - * ktime_t: - * - * A single 64-bit variable is used to store the hrtimers - * internal representation of time values in scalar nanoseconds. The - * design plays out best on 64-bit CPUs, where most conversions are - * NOPs and most arithmetic ktime_t operations are plain arithmetic - * operations. - * - */ -union ktime { - s64 tv64; -}; - -typedef union ktime ktime_t; /* Kill this */ - -/** - * ktime_set - Set a ktime_t variable from a seconds/nanoseconds value - * @secs: seconds to set - * @nsecs: nanoseconds to set - * - * Return: The ktime_t representation of the value. - */ -static inline ktime_t ktime_set(const s64 secs, const unsigned long nsecs) -{ - if (unlikely(secs >= KTIME_SEC_MAX)) - return (ktime_t){ .tv64 = KTIME_MAX }; - - return (ktime_t) { .tv64 = secs * NSEC_PER_SEC + (s64)nsecs }; -} - -/* Subtract two ktime_t variables. rem = lhs -rhs: */ -#define ktime_sub(lhs, rhs) \ - ({ (ktime_t){ .tv64 = (lhs).tv64 - (rhs).tv64 }; }) - -/* Add two ktime_t variables. res = lhs + rhs: */ -#define ktime_add(lhs, rhs) \ - ({ (ktime_t){ .tv64 = (lhs).tv64 + (rhs).tv64 }; }) - -/* - * Same as ktime_add(), but avoids undefined behaviour on overflow; however, - * this means that you must check the result for overflow yourself. - */ -#define ktime_add_unsafe(lhs, rhs) \ - ({ (ktime_t){ .tv64 = (u64) (lhs).tv64 + (rhs).tv64 }; }) - -/* - * Add a ktime_t variable and a scalar nanosecond value. - * res = kt + nsval: - */ -#define ktime_add_ns(kt, nsval) \ - ({ (ktime_t){ .tv64 = (kt).tv64 + (nsval) }; }) - -/* - * Subtract a scalar nanosecod from a ktime_t variable - * res = kt - nsval: - */ -#define ktime_sub_ns(kt, nsval) \ - ({ (ktime_t){ .tv64 = (kt).tv64 - (nsval) }; }) - -/* convert a timespec to ktime_t format: */ -static inline ktime_t timespec_to_ktime(struct timespec ts) -{ - return ktime_set(ts.tv_sec, ts.tv_nsec); -} - -/* convert a timespec64 to ktime_t format: */ -static inline ktime_t timespec64_to_ktime(struct timespec64 ts) -{ - return ktime_set(ts.tv_sec, ts.tv_nsec); -} - -/* convert a timeval to ktime_t format: */ -static inline ktime_t timeval_to_ktime(struct timeval tv) -{ - return ktime_set(tv.tv_sec, tv.tv_usec * NSEC_PER_USEC); -} - -/* Map the ktime_t to timespec conversion to ns_to_timespec function */ -#define ktime_to_timespec(kt) ns_to_timespec((kt).tv64) - -/* Map the ktime_t to timespec conversion to ns_to_timespec function */ -#define ktime_to_timespec64(kt) ns_to_timespec64((kt).tv64) - -/* Map the ktime_t to timeval conversion to ns_to_timeval function */ -#define ktime_to_timeval(kt) ns_to_timeval((kt).tv64) - -/* Convert ktime_t to nanoseconds - NOP in the scalar storage format: */ -#define ktime_to_ns(kt) ((kt).tv64) - - -/** - * ktime_equal - Compares two ktime_t variables to see if they are equal - * @cmp1: comparable1 - * @cmp2: comparable2 - * - * Compare two ktime_t variables. - * - * Return: 1 if equal. - */ -static inline int ktime_equal(const ktime_t cmp1, const ktime_t cmp2) -{ - return cmp1.tv64 == cmp2.tv64; -} - -/** - * ktime_compare - Compares two ktime_t variables for less, greater or equal - * @cmp1: comparable1 - * @cmp2: comparable2 - * - * Return: ... - * cmp1 < cmp2: return <0 - * cmp1 == cmp2: return 0 - * cmp1 > cmp2: return >0 - */ -static inline int ktime_compare(const ktime_t cmp1, const ktime_t cmp2) -{ - if (cmp1.tv64 < cmp2.tv64) - return -1; - if (cmp1.tv64 > cmp2.tv64) - return 1; - return 0; -} - -/** - * ktime_after - Compare if a ktime_t value is bigger than another one. - * @cmp1: comparable1 - * @cmp2: comparable2 - * - * Return: true if cmp1 happened after cmp2. - */ -static inline bool ktime_after(const ktime_t cmp1, const ktime_t cmp2) -{ - return ktime_compare(cmp1, cmp2) > 0; -} - -/** - * ktime_before - Compare if a ktime_t value is smaller than another one. - * @cmp1: comparable1 - * @cmp2: comparable2 - * - * Return: true if cmp1 happened before cmp2. - */ -static inline bool ktime_before(const ktime_t cmp1, const ktime_t cmp2) -{ - return ktime_compare(cmp1, cmp2) < 0; -} - -#if BITS_PER_LONG < 64 -extern s64 __ktime_divns(const ktime_t kt, s64 div); -static inline s64 ktime_divns(const ktime_t kt, s64 div) -{ - /* - * Negative divisors could cause an inf loop, - * so bug out here. - */ - BUG_ON(div < 0); - if (__builtin_constant_p(div) && !(div >> 32)) { - s64 ns = kt.tv64; - u64 tmp = ns < 0 ? -ns : ns; - - do_div(tmp, div); - return ns < 0 ? -tmp : tmp; - } else { - return __ktime_divns(kt, div); - } -} -#else /* BITS_PER_LONG < 64 */ -static inline s64 ktime_divns(const ktime_t kt, s64 div) -{ - /* - * 32-bit implementation cannot handle negative divisors, - * so catch them on 64bit as well. - */ - WARN_ON(div < 0); - return kt.tv64 / div; -} -#endif - -static inline s64 ktime_to_us(const ktime_t kt) -{ - return ktime_divns(kt, NSEC_PER_USEC); -} - -static inline s64 ktime_to_ms(const ktime_t kt) -{ - return ktime_divns(kt, NSEC_PER_MSEC); -} - -static inline s64 ktime_us_delta(const ktime_t later, const ktime_t earlier) -{ - return ktime_to_us(ktime_sub(later, earlier)); -} - -static inline s64 ktime_ms_delta(const ktime_t later, const ktime_t earlier) -{ - return ktime_to_ms(ktime_sub(later, earlier)); -} - -static inline ktime_t ktime_add_us(const ktime_t kt, const u64 usec) -{ - return ktime_add_ns(kt, usec * NSEC_PER_USEC); -} - -static inline ktime_t ktime_add_ms(const ktime_t kt, const u64 msec) -{ - return ktime_add_ns(kt, msec * NSEC_PER_MSEC); -} - -static inline ktime_t ktime_sub_us(const ktime_t kt, const u64 usec) -{ - return ktime_sub_ns(kt, usec * NSEC_PER_USEC); -} - -static inline ktime_t ktime_sub_ms(const ktime_t kt, const u64 msec) -{ - return ktime_sub_ns(kt, msec * NSEC_PER_MSEC); -} - -extern ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs); - -/** - * ktime_to_timespec_cond - convert a ktime_t variable to timespec - * format only if the variable contains data - * @kt: the ktime_t variable to convert - * @ts: the timespec variable to store the result in - * - * Return: %true if there was a successful conversion, %false if kt was 0. - */ -static inline __must_check bool ktime_to_timespec_cond(const ktime_t kt, - struct timespec *ts) -{ - if (kt.tv64) { - *ts = ktime_to_timespec(kt); - return true; - } else { - return false; - } -} - -/** - * ktime_to_timespec64_cond - convert a ktime_t variable to timespec64 - * format only if the variable contains data - * @kt: the ktime_t variable to convert - * @ts: the timespec variable to store the result in - * - * Return: %true if there was a successful conversion, %false if kt was 0. - */ -static inline __must_check bool ktime_to_timespec64_cond(const ktime_t kt, - struct timespec64 *ts) -{ - if (kt.tv64) { - *ts = ktime_to_timespec64(kt); - return true; - } else { - return false; - } -} - -/* - * The resolution of the clocks. The resolution value is returned in - * the clock_getres() system call to give application programmers an - * idea of the (in)accuracy of timers. Timer values are rounded up to - * this resolution values. - */ -#define LOW_RES_NSEC TICK_NSEC -#define KTIME_LOW_RES (ktime_t){ .tv64 = LOW_RES_NSEC } - -static inline ktime_t ns_to_ktime(u64 ns) -{ - static const ktime_t ktime_zero = { .tv64 = 0 }; - - return ktime_add_ns(ktime_zero, ns); -} - -static inline ktime_t ms_to_ktime(u64 ms) -{ - static const ktime_t ktime_zero = { .tv64 = 0 }; - - return ktime_add_ms(ktime_zero, ms); -} - -# include - -#endif diff --git a/src/linux/include/linux/latencytop.h b/src/linux/include/linux/latencytop.h deleted file mode 100644 index 59ccab2..0000000 --- a/src/linux/include/linux/latencytop.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * latencytop.h: Infrastructure for displaying latency - * - * (C) Copyright 2008 Intel Corporation - * Author: Arjan van de Ven - * - */ - -#ifndef _INCLUDE_GUARD_LATENCYTOP_H_ -#define _INCLUDE_GUARD_LATENCYTOP_H_ - -#include -struct task_struct; - -#ifdef CONFIG_LATENCYTOP - -#define LT_SAVECOUNT 32 -#define LT_BACKTRACEDEPTH 12 - -struct latency_record { - unsigned long backtrace[LT_BACKTRACEDEPTH]; - unsigned int count; - unsigned long time; - unsigned long max; -}; - - - -extern int latencytop_enabled; -void __account_scheduler_latency(struct task_struct *task, int usecs, int inter); -static inline void -account_scheduler_latency(struct task_struct *task, int usecs, int inter) -{ - if (unlikely(latencytop_enabled)) - __account_scheduler_latency(task, usecs, inter); -} - -void clear_all_latency_tracing(struct task_struct *p); - -extern int sysctl_latencytop(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); - -#else - -static inline void -account_scheduler_latency(struct task_struct *task, int usecs, int inter) -{ -} - -static inline void clear_all_latency_tracing(struct task_struct *p) -{ -} - -#endif - -#endif diff --git a/src/linux/include/linux/lcm.h b/src/linux/include/linux/lcm.h deleted file mode 100644 index 1ce79a7..0000000 --- a/src/linux/include/linux/lcm.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _LCM_H -#define _LCM_H - -#include - -unsigned long lcm(unsigned long a, unsigned long b) __attribute_const__; -unsigned long lcm_not_zero(unsigned long a, unsigned long b) __attribute_const__; - -#endif /* _LCM_H */ diff --git a/src/linux/include/linux/leds.h b/src/linux/include/linux/leds.h deleted file mode 100644 index ddfcb2d..0000000 --- a/src/linux/include/linux/leds.h +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Driver model for leds and led triggers - * - * Copyright (C) 2005 John Lenz - * Copyright (C) 2005 Richard Purdie - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - */ -#ifndef __LINUX_LEDS_H_INCLUDED -#define __LINUX_LEDS_H_INCLUDED - -#include -#include -#include -#include -#include -#include -#include - -struct device; -/* - * LED Core - */ - -enum led_brightness { - LED_OFF = 0, - LED_HALF = 127, - LED_FULL = 255, -}; - -struct led_classdev { - const char *name; - enum led_brightness brightness; - enum led_brightness max_brightness; - int flags; - - /* Lower 16 bits reflect status */ -#define LED_SUSPENDED (1 << 0) -#define LED_UNREGISTERING (1 << 1) - /* Upper 16 bits reflect control information */ -#define LED_CORE_SUSPENDRESUME (1 << 16) -#define LED_BLINK_SW (1 << 17) -#define LED_BLINK_ONESHOT (1 << 18) -#define LED_BLINK_ONESHOT_STOP (1 << 19) -#define LED_BLINK_INVERT (1 << 20) -#define LED_BLINK_BRIGHTNESS_CHANGE (1 << 21) -#define LED_BLINK_DISABLE (1 << 22) -#define LED_SYSFS_DISABLE (1 << 23) -#define LED_DEV_CAP_FLASH (1 << 24) -#define LED_HW_PLUGGABLE (1 << 25) -#define LED_PANIC_INDICATOR (1 << 26) - - /* Set LED brightness level - * Must not sleep. Use brightness_set_blocking for drivers - * that can sleep while setting brightness. - */ - void (*brightness_set)(struct led_classdev *led_cdev, - enum led_brightness brightness); - /* - * Set LED brightness level immediately - it can block the caller for - * the time required for accessing a LED device register. - */ - int (*brightness_set_blocking)(struct led_classdev *led_cdev, - enum led_brightness brightness); - /* Get LED brightness level */ - enum led_brightness (*brightness_get)(struct led_classdev *led_cdev); - - /* - * Activate hardware accelerated blink, delays are in milliseconds - * and if both are zero then a sensible default should be chosen. - * The call should adjust the timings in that case and if it can't - * match the values specified exactly. - * Deactivate blinking again when the brightness is set to LED_OFF - * via the brightness_set() callback. - */ - int (*blink_set)(struct led_classdev *led_cdev, - unsigned long *delay_on, - unsigned long *delay_off); - - struct device *dev; - const struct attribute_group **groups; - - struct list_head node; /* LED Device list */ - const char *default_trigger; /* Trigger to use */ - - unsigned long blink_delay_on, blink_delay_off; - struct timer_list blink_timer; - int blink_brightness; - void (*flash_resume)(struct led_classdev *led_cdev); - - struct work_struct set_brightness_work; - int delayed_set_value; - -#ifdef CONFIG_LEDS_TRIGGERS - /* Protects the trigger data below */ - struct rw_semaphore trigger_lock; - - struct led_trigger *trigger; - struct list_head trig_list; - void *trigger_data; - /* true if activated - deactivate routine uses it to do cleanup */ - bool activated; -#endif - - /* Ensures consistent access to the LED Flash Class device */ - struct mutex led_access; -}; - -extern int led_classdev_register(struct device *parent, - struct led_classdev *led_cdev); -extern int devm_led_classdev_register(struct device *parent, - struct led_classdev *led_cdev); -extern void led_classdev_unregister(struct led_classdev *led_cdev); -extern void devm_led_classdev_unregister(struct device *parent, - struct led_classdev *led_cdev); -extern void led_classdev_suspend(struct led_classdev *led_cdev); -extern void led_classdev_resume(struct led_classdev *led_cdev); - -/** - * led_blink_set - set blinking with software fallback - * @led_cdev: the LED to start blinking - * @delay_on: the time it should be on (in ms) - * @delay_off: the time it should ble off (in ms) - * - * This function makes the LED blink, attempting to use the - * hardware acceleration if possible, but falling back to - * software blinking if there is no hardware blinking or if - * the LED refuses the passed values. - * - * Note that if software blinking is active, simply calling - * led_cdev->brightness_set() will not stop the blinking, - * use led_classdev_brightness_set() instead. - */ -extern void led_blink_set(struct led_classdev *led_cdev, - unsigned long *delay_on, - unsigned long *delay_off); -/** - * led_blink_set_oneshot - do a oneshot software blink - * @led_cdev: the LED to start blinking - * @delay_on: the time it should be on (in ms) - * @delay_off: the time it should ble off (in ms) - * @invert: blink off, then on, leaving the led on - * - * This function makes the LED blink one time for delay_on + - * delay_off time, ignoring the request if another one-shot - * blink is already in progress. - * - * If invert is set, led blinks for delay_off first, then for - * delay_on and leave the led on after the on-off cycle. - */ -extern void led_blink_set_oneshot(struct led_classdev *led_cdev, - unsigned long *delay_on, - unsigned long *delay_off, - int invert); -/** - * led_set_brightness - set LED brightness - * @led_cdev: the LED to set - * @brightness: the brightness to set it to - * - * Set an LED's brightness, and, if necessary, cancel the - * software blink timer that implements blinking when the - * hardware doesn't. This function is guaranteed not to sleep. - */ -extern void led_set_brightness(struct led_classdev *led_cdev, - enum led_brightness brightness); - -/** - * led_set_brightness_sync - set LED brightness synchronously - * @led_cdev: the LED to set - * @brightness: the brightness to set it to - * - * Set an LED's brightness immediately. This function will block - * the caller for the time required for accessing device registers, - * and it can sleep. - * - * Returns: 0 on success or negative error value on failure - */ -extern int led_set_brightness_sync(struct led_classdev *led_cdev, - enum led_brightness value); - -/** - * led_update_brightness - update LED brightness - * @led_cdev: the LED to query - * - * Get an LED's current brightness and update led_cdev->brightness - * member with the obtained value. - * - * Returns: 0 on success or negative error value on failure - */ -extern int led_update_brightness(struct led_classdev *led_cdev); - -/** - * led_sysfs_disable - disable LED sysfs interface - * @led_cdev: the LED to set - * - * Disable the led_cdev's sysfs interface. - */ -extern void led_sysfs_disable(struct led_classdev *led_cdev); - -/** - * led_sysfs_enable - enable LED sysfs interface - * @led_cdev: the LED to set - * - * Enable the led_cdev's sysfs interface. - */ -extern void led_sysfs_enable(struct led_classdev *led_cdev); - -/** - * led_sysfs_is_disabled - check if LED sysfs interface is disabled - * @led_cdev: the LED to query - * - * Returns: true if the led_cdev's sysfs interface is disabled. - */ -static inline bool led_sysfs_is_disabled(struct led_classdev *led_cdev) -{ - return led_cdev->flags & LED_SYSFS_DISABLE; -} - -/* - * LED Triggers - */ -/* Registration functions for simple triggers */ -#define DEFINE_LED_TRIGGER(x) static struct led_trigger *x; -#define DEFINE_LED_TRIGGER_GLOBAL(x) struct led_trigger *x; - -#ifdef CONFIG_LEDS_TRIGGERS - -#define TRIG_NAME_MAX 50 - -struct led_trigger { - /* Trigger Properties */ - const char *name; - void (*activate)(struct led_classdev *led_cdev); - void (*deactivate)(struct led_classdev *led_cdev); - - /* LEDs under control by this trigger (for simple triggers) */ - rwlock_t leddev_list_lock; - struct list_head led_cdevs; - - /* Link to next registered trigger */ - struct list_head next_trig; -}; - -ssize_t led_trigger_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count); -ssize_t led_trigger_show(struct device *dev, struct device_attribute *attr, - char *buf); - -/* Registration functions for complex triggers */ -extern int led_trigger_register(struct led_trigger *trigger); -extern void led_trigger_unregister(struct led_trigger *trigger); -extern int devm_led_trigger_register(struct device *dev, - struct led_trigger *trigger); - -extern void led_trigger_register_simple(const char *name, - struct led_trigger **trigger); -extern void led_trigger_unregister_simple(struct led_trigger *trigger); -extern void led_trigger_event(struct led_trigger *trigger, - enum led_brightness event); -extern void led_trigger_blink(struct led_trigger *trigger, - unsigned long *delay_on, - unsigned long *delay_off); -extern void led_trigger_blink_oneshot(struct led_trigger *trigger, - unsigned long *delay_on, - unsigned long *delay_off, - int invert); -extern void led_trigger_set_default(struct led_classdev *led_cdev); -extern void led_trigger_set(struct led_classdev *led_cdev, - struct led_trigger *trigger); -extern void led_trigger_remove(struct led_classdev *led_cdev); - -static inline void *led_get_trigger_data(struct led_classdev *led_cdev) -{ - return led_cdev->trigger_data; -} - -/** - * led_trigger_rename_static - rename a trigger - * @name: the new trigger name - * @trig: the LED trigger to rename - * - * Change a LED trigger name by copying the string passed in - * name into current trigger name, which MUST be large - * enough for the new string. - * - * Note that name must NOT point to the same string used - * during LED registration, as that could lead to races. - * - * This is meant to be used on triggers with statically - * allocated name. - */ -extern void led_trigger_rename_static(const char *name, - struct led_trigger *trig); - -#else - -/* Trigger has no members */ -struct led_trigger {}; - -/* Trigger inline empty functions */ -static inline void led_trigger_register_simple(const char *name, - struct led_trigger **trigger) {} -static inline void led_trigger_unregister_simple(struct led_trigger *trigger) {} -static inline void led_trigger_event(struct led_trigger *trigger, - enum led_brightness event) {} -static inline void led_trigger_blink(struct led_trigger *trigger, - unsigned long *delay_on, - unsigned long *delay_off) {} -static inline void led_trigger_blink_oneshot(struct led_trigger *trigger, - unsigned long *delay_on, - unsigned long *delay_off, - int invert) {} -static inline void led_trigger_set_default(struct led_classdev *led_cdev) {} -static inline void led_trigger_set(struct led_classdev *led_cdev, - struct led_trigger *trigger) {} -static inline void led_trigger_remove(struct led_classdev *led_cdev) {} -static inline void *led_get_trigger_data(struct led_classdev *led_cdev) -{ - return NULL; -} - -#endif /* CONFIG_LEDS_TRIGGERS */ - -/* Trigger specific functions */ -#ifdef CONFIG_LEDS_TRIGGER_DISK -extern void ledtrig_disk_activity(void); -#else -static inline void ledtrig_disk_activity(void) {} -#endif - -#ifdef CONFIG_LEDS_TRIGGER_MTD -extern void ledtrig_mtd_activity(void); -#else -static inline void ledtrig_mtd_activity(void) {} -#endif - -#if defined(CONFIG_LEDS_TRIGGER_CAMERA) || defined(CONFIG_LEDS_TRIGGER_CAMERA_MODULE) -extern void ledtrig_flash_ctrl(bool on); -extern void ledtrig_torch_ctrl(bool on); -#else -static inline void ledtrig_flash_ctrl(bool on) {} -static inline void ledtrig_torch_ctrl(bool on) {} -#endif - -/* - * Generic LED platform data for describing LED names and default triggers. - */ -struct led_info { - const char *name; - const char *default_trigger; - int flags; -}; - -struct led_platform_data { - int num_leds; - struct led_info *leds; -}; - -struct gpio_desc; -typedef int (*gpio_blink_set_t)(struct gpio_desc *desc, int state, - unsigned long *delay_on, - unsigned long *delay_off); - -/* For the leds-gpio driver */ -struct gpio_led { - const char *name; - const char *default_trigger; - unsigned gpio; - unsigned active_low : 1; - unsigned retain_state_suspended : 1; - unsigned panic_indicator : 1; - unsigned default_state : 2; - /* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */ - struct gpio_desc *gpiod; -}; -#define LEDS_GPIO_DEFSTATE_OFF 0 -#define LEDS_GPIO_DEFSTATE_ON 1 -#define LEDS_GPIO_DEFSTATE_KEEP 2 - -struct gpio_led_platform_data { - int num_leds; - const struct gpio_led *leds; - -#define GPIO_LED_NO_BLINK_LOW 0 /* No blink GPIO state low */ -#define GPIO_LED_NO_BLINK_HIGH 1 /* No blink GPIO state high */ -#define GPIO_LED_BLINK 2 /* Please, blink */ - gpio_blink_set_t gpio_blink_set; -}; - -#ifdef CONFIG_NEW_LEDS -struct platform_device *gpio_led_register_device( - int id, const struct gpio_led_platform_data *pdata); -#else -static inline struct platform_device *gpio_led_register_device( - int id, const struct gpio_led_platform_data *pdata) -{ - return 0; -} -#endif - -enum cpu_led_event { - CPU_LED_IDLE_START, /* CPU enters idle */ - CPU_LED_IDLE_END, /* CPU idle ends */ - CPU_LED_START, /* Machine starts, especially resume */ - CPU_LED_STOP, /* Machine stops, especially suspend */ - CPU_LED_HALTED, /* Machine shutdown */ -}; -#ifdef CONFIG_LEDS_TRIGGER_CPU -extern void ledtrig_cpu(enum cpu_led_event evt); -#else -static inline void ledtrig_cpu(enum cpu_led_event evt) -{ - return; -} -#endif - -#endif /* __LINUX_LEDS_H_INCLUDED */ diff --git a/src/linux/include/linux/libps2.h b/src/linux/include/linux/libps2.h deleted file mode 100644 index 4ad06e8..0000000 --- a/src/linux/include/linux/libps2.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef _LIBPS2_H -#define _LIBPS2_H - -/* - * Copyright (C) 1999-2002 Vojtech Pavlik - * Copyright (C) 2004 Dmitry Torokhov - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ - - -#define PS2_CMD_GETID 0x02f2 -#define PS2_CMD_RESET_BAT 0x02ff - -#define PS2_RET_BAT 0xaa -#define PS2_RET_ID 0x00 -#define PS2_RET_ACK 0xfa -#define PS2_RET_NAK 0xfe -#define PS2_RET_ERR 0xfc - -#define PS2_FLAG_ACK 1 /* Waiting for ACK/NAK */ -#define PS2_FLAG_CMD 2 /* Waiting for command to finish */ -#define PS2_FLAG_CMD1 4 /* Waiting for the first byte of command response */ -#define PS2_FLAG_WAITID 8 /* Command execiting is GET ID */ -#define PS2_FLAG_NAK 16 /* Last transmission was NAKed */ - -struct ps2dev { - struct serio *serio; - - /* Ensures that only one command is executing at a time */ - struct mutex cmd_mutex; - - /* Used to signal completion from interrupt handler */ - wait_queue_head_t wait; - - unsigned long flags; - unsigned char cmdbuf[8]; - unsigned char cmdcnt; - unsigned char nak; -}; - -void ps2_init(struct ps2dev *ps2dev, struct serio *serio); -int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout); -void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout); -void ps2_begin_command(struct ps2dev *ps2dev); -void ps2_end_command(struct ps2dev *ps2dev); -int __ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command); -int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command); -int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data); -int ps2_handle_response(struct ps2dev *ps2dev, unsigned char data); -void ps2_cmd_aborted(struct ps2dev *ps2dev); -int ps2_is_keyboard_id(char id); - -#endif /* _LIBPS2_H */ diff --git a/src/linux/include/linux/license.h b/src/linux/include/linux/license.h deleted file mode 100644 index decdbf4..0000000 --- a/src/linux/include/linux/license.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef __LICENSE_H -#define __LICENSE_H - -static inline int license_is_gpl_compatible(const char *license) -{ - return (strcmp(license, "GPL") == 0 - || strcmp(license, "GPL v2") == 0 - || strcmp(license, "GPL and additional rights") == 0 - || strcmp(license, "Dual BSD/GPL") == 0 - || strcmp(license, "Dual MIT/GPL") == 0 - || strcmp(license, "Dual MPL/GPL") == 0); -} - -#endif diff --git a/src/linux/include/linux/linkage.h b/src/linux/include/linux/linkage.h deleted file mode 100644 index a6a42dd..0000000 --- a/src/linux/include/linux/linkage.h +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef _LINUX_LINKAGE_H -#define _LINUX_LINKAGE_H - -#include -#include -#include -#include - -/* Some toolchains use other characters (e.g. '`') to mark new line in macro */ -#ifndef ASM_NL -#define ASM_NL ; -#endif - -#ifdef __cplusplus -#define CPP_ASMLINKAGE extern "C" -#else -#define CPP_ASMLINKAGE -#endif - -#ifndef asmlinkage -#define asmlinkage CPP_ASMLINKAGE -#endif - -#ifndef cond_syscall -#define cond_syscall(x) asm( \ - ".weak " VMLINUX_SYMBOL_STR(x) "\n\t" \ - ".set " VMLINUX_SYMBOL_STR(x) "," \ - VMLINUX_SYMBOL_STR(sys_ni_syscall)) -#endif - -#ifndef SYSCALL_ALIAS -#define SYSCALL_ALIAS(alias, name) asm( \ - ".globl " VMLINUX_SYMBOL_STR(alias) "\n\t" \ - ".set " VMLINUX_SYMBOL_STR(alias) "," \ - VMLINUX_SYMBOL_STR(name)) -#endif - -#define __page_aligned_data __section(.data..page_aligned) __aligned(PAGE_SIZE) -#define __page_aligned_bss __section(.bss..page_aligned) __aligned(PAGE_SIZE) - -/* - * For assembly routines. - * - * Note when using these that you must specify the appropriate - * alignment directives yourself - */ -#define __PAGE_ALIGNED_DATA .section ".data..page_aligned", "aw" -#define __PAGE_ALIGNED_BSS .section ".bss..page_aligned", "aw" - -/* - * This is used by architectures to keep arguments on the stack - * untouched by the compiler by keeping them live until the end. - * The argument stack may be owned by the assembly-language - * caller, not the callee, and gcc doesn't always understand - * that. - * - * We have the return value, and a maximum of six arguments. - * - * This should always be followed by a "return ret" for the - * protection to work (ie no more work that the compiler might - * end up needing stack temporaries for). - */ -/* Assembly files may be compiled with -traditional .. */ -#ifndef __ASSEMBLY__ -#ifndef asmlinkage_protect -# define asmlinkage_protect(n, ret, args...) do { } while (0) -#endif -#endif - -#ifndef __ALIGN -#define __ALIGN .align 4,0x90 -#define __ALIGN_STR ".align 4,0x90" -#endif - -#ifdef __ASSEMBLY__ - -#ifndef LINKER_SCRIPT -#define ALIGN __ALIGN -#define ALIGN_STR __ALIGN_STR - -#ifndef ENTRY -#define ENTRY(name) \ - .globl name ASM_NL \ - ALIGN ASM_NL \ - name: -#endif -#endif /* LINKER_SCRIPT */ - -#ifndef WEAK -#define WEAK(name) \ - .weak name ASM_NL \ - name: -#endif - -#ifndef END -#define END(name) \ - .size name, .-name -#endif - -/* If symbol 'name' is treated as a subroutine (gets called, and returns) - * then please use ENDPROC to mark 'name' as STT_FUNC for the benefit of - * static analysis tools such as stack depth analyzer. - */ -#ifndef ENDPROC -#define ENDPROC(name) \ - .type name, @function ASM_NL \ - END(name) -#endif - -#endif - -#endif diff --git a/src/linux/include/linux/list.h b/src/linux/include/linux/list.h deleted file mode 100644 index 5809e9a..0000000 --- a/src/linux/include/linux/list.h +++ /dev/null @@ -1,763 +0,0 @@ -#ifndef _LINUX_LIST_H -#define _LINUX_LIST_H - -#include -#include -#include -#include -#include - -/* - * Simple doubly linked list implementation. - * - * Some of the internal functions ("__xxx") are useful when - * manipulating whole lists rather than single entries, as - * sometimes we already know the next/prev entries and we can - * generate better code by using them directly rather than - * using the generic single-entry routines. - */ - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -static inline void INIT_LIST_HEAD(struct list_head *list) -{ - WRITE_ONCE(list->next, list); - list->prev = list; -} - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -#ifndef CONFIG_DEBUG_LIST -static inline void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - WRITE_ONCE(prev->next, new); -} -#else -extern void __list_add(struct list_head *new, - struct list_head *prev, - struct list_head *next); -#endif - -/** - * list_add - add a new entry - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - */ -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head * prev, struct list_head * next) -{ - next->prev = prev; - WRITE_ONCE(prev->next, next); -} - -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty() on entry does not return true after this, the entry is - * in an undefined state. - */ -#ifndef CONFIG_DEBUG_LIST -static inline void __list_del_entry(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); -} - -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = LIST_POISON1; - entry->prev = LIST_POISON2; -} -#else -extern void __list_del_entry(struct list_head *entry); -extern void list_del(struct list_head *entry); -#endif - -/** - * list_replace - replace old entry by new one - * @old : the element to be replaced - * @new : the new element to insert - * - * If @old was empty, it will be overwritten. - */ -static inline void list_replace(struct list_head *old, - struct list_head *new) -{ - new->next = old->next; - new->next->prev = new; - new->prev = old->prev; - new->prev->next = new; -} - -static inline void list_replace_init(struct list_head *old, - struct list_head *new) -{ - list_replace(old, new); - INIT_LIST_HEAD(old); -} - -/** - * list_del_init - deletes entry from list and reinitialize it. - * @entry: the element to delete from the list. - */ -static inline void list_del_init(struct list_head *entry) -{ - __list_del_entry(entry); - INIT_LIST_HEAD(entry); -} - -/** - * list_move - delete from one list and add as another's head - * @list: the entry to move - * @head: the head that will precede our entry - */ -static inline void list_move(struct list_head *list, struct list_head *head) -{ - __list_del_entry(list); - list_add(list, head); -} - -/** - * list_move_tail - delete from one list and add as another's tail - * @list: the entry to move - * @head: the head that will follow our entry - */ -static inline void list_move_tail(struct list_head *list, - struct list_head *head) -{ - __list_del_entry(list); - list_add_tail(list, head); -} - -/** - * list_is_last - tests whether @list is the last entry in list @head - * @list: the entry to test - * @head: the head of the list - */ -static inline int list_is_last(const struct list_head *list, - const struct list_head *head) -{ - return list->next == head; -} - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) -{ - return READ_ONCE(head->next) == head; -} - -/** - * list_empty_careful - tests whether a list is empty and not being modified - * @head: the list to test - * - * Description: - * tests whether a list is empty _and_ checks that no other CPU might be - * in the process of modifying either member (next or prev) - * - * NOTE: using list_empty_careful() without synchronization - * can only be safe if the only activity that can happen - * to the list entry is list_del_init(). Eg. it cannot be used - * if another CPU could re-list_add() it. - */ -static inline int list_empty_careful(const struct list_head *head) -{ - struct list_head *next = head->next; - return (next == head) && (next == head->prev); -} - -/** - * list_rotate_left - rotate the list to the left - * @head: the head of the list - */ -static inline void list_rotate_left(struct list_head *head) -{ - struct list_head *first; - - if (!list_empty(head)) { - first = head->next; - list_move_tail(first, head); - } -} - -/** - * list_is_singular - tests whether a list has just one entry. - * @head: the list to test. - */ -static inline int list_is_singular(const struct list_head *head) -{ - return !list_empty(head) && (head->next == head->prev); -} - -static inline void __list_cut_position(struct list_head *list, - struct list_head *head, struct list_head *entry) -{ - struct list_head *new_first = entry->next; - list->next = head->next; - list->next->prev = list; - list->prev = entry; - entry->next = list; - head->next = new_first; - new_first->prev = head; -} - -/** - * list_cut_position - cut a list into two - * @list: a new list to add all removed entries - * @head: a list with entries - * @entry: an entry within head, could be the head itself - * and if so we won't cut the list - * - * This helper moves the initial part of @head, up to and - * including @entry, from @head to @list. You should - * pass on @entry an element you know is on @head. @list - * should be an empty list or a list you do not care about - * losing its data. - * - */ -static inline void list_cut_position(struct list_head *list, - struct list_head *head, struct list_head *entry) -{ - if (list_empty(head)) - return; - if (list_is_singular(head) && - (head->next != entry && head != entry)) - return; - if (entry == head) - INIT_LIST_HEAD(list); - else - __list_cut_position(list, head, entry); -} - -static inline void __list_splice(const struct list_head *list, - struct list_head *prev, - struct list_head *next) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - - first->prev = prev; - prev->next = first; - - last->next = next; - next->prev = last; -} - -/** - * list_splice - join two lists, this is designed for stacks - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice(const struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head, head->next); -} - -/** - * list_splice_tail - join two lists, each list being a queue - * @list: the new list to add. - * @head: the place to add it in the first list. - */ -static inline void list_splice_tail(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) - __list_splice(list, head->prev, head); -} - -/** - * list_splice_init - join two lists and reinitialise the emptied list. - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * The list at @list is reinitialised - */ -static inline void list_splice_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head, head->next); - INIT_LIST_HEAD(list); - } -} - -/** - * list_splice_tail_init - join two lists and reinitialise the emptied list - * @list: the new list to add. - * @head: the place to add it in the first list. - * - * Each of the lists is a queue. - * The list at @list is reinitialised - */ -static inline void list_splice_tail_init(struct list_head *list, - struct list_head *head) -{ - if (!list_empty(list)) { - __list_splice(list, head->prev, head); - INIT_LIST_HEAD(list); - } -} - -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_head within the struct. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_first_entry - get the first element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_head within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -/** - * list_last_entry - get the last element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_head within the struct. - * - * Note, that list is expected to be not empty. - */ -#define list_last_entry(ptr, type, member) \ - list_entry((ptr)->prev, type, member) - -/** - * list_first_entry_or_null - get the first element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_head within the struct. - * - * Note that if the list is empty, it returns NULL. - */ -#define list_first_entry_or_null(ptr, type, member) ({ \ - struct list_head *head__ = (ptr); \ - struct list_head *pos__ = READ_ONCE(head__->next); \ - pos__ != head__ ? list_entry(pos__, type, member) : NULL; \ -}) - -/** - * list_next_entry - get the next element in list - * @pos: the type * to cursor - * @member: the name of the list_head within the struct. - */ -#define list_next_entry(pos, member) \ - list_entry((pos)->member.next, typeof(*(pos)), member) - -/** - * list_prev_entry - get the prev element in list - * @pos: the type * to cursor - * @member: the name of the list_head within the struct. - */ -#define list_prev_entry(pos, member) \ - list_entry((pos)->member.prev, typeof(*(pos)), member) - -/** - * list_for_each - iterate over a list - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -/** - * list_for_each_prev - iterate over a list backwards - * @pos: the &struct list_head to use as a loop cursor. - * @head: the head for your list. - */ -#define list_for_each_prev(pos, head) \ - for (pos = (head)->prev; pos != (head); pos = pos->prev) - -/** - * list_for_each_safe - iterate over a list safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -/** - * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry - * @pos: the &struct list_head to use as a loop cursor. - * @n: another &struct list_head to use as temporary storage - * @head: the head for your list. - */ -#define list_for_each_prev_safe(pos, n, head) \ - for (pos = (head)->prev, n = pos->prev; \ - pos != (head); \ - pos = n, n = pos->prev) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_head within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_first_entry(head, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_next_entry(pos, member)) - -/** - * list_for_each_entry_reverse - iterate backwards over list of given type. - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_head within the struct. - */ -#define list_for_each_entry_reverse(pos, head, member) \ - for (pos = list_last_entry(head, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_prev_entry(pos, member)) - -/** - * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue() - * @pos: the type * to use as a start point - * @head: the head of the list - * @member: the name of the list_head within the struct. - * - * Prepares a pos entry for use as a start point in list_for_each_entry_continue(). - */ -#define list_prepare_entry(pos, head, member) \ - ((pos) ? : list_entry(head, typeof(*pos), member)) - -/** - * list_for_each_entry_continue - continue iteration over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_head within the struct. - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define list_for_each_entry_continue(pos, head, member) \ - for (pos = list_next_entry(pos, member); \ - &pos->member != (head); \ - pos = list_next_entry(pos, member)) - -/** - * list_for_each_entry_continue_reverse - iterate backwards from the given point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_head within the struct. - * - * Start to iterate over list of given type backwards, continuing after - * the current position. - */ -#define list_for_each_entry_continue_reverse(pos, head, member) \ - for (pos = list_prev_entry(pos, member); \ - &pos->member != (head); \ - pos = list_prev_entry(pos, member)) - -/** - * list_for_each_entry_from - iterate over list of given type from the current point - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_head within the struct. - * - * Iterate over list of given type, continuing from current position. - */ -#define list_for_each_entry_from(pos, head, member) \ - for (; &pos->member != (head); \ - pos = list_next_entry(pos, member)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_head within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_first_entry(head, typeof(*pos), member), \ - n = list_next_entry(pos, member); \ - &pos->member != (head); \ - pos = n, n = list_next_entry(n, member)) - -/** - * list_for_each_entry_safe_continue - continue list iteration safe against removal - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_head within the struct. - * - * Iterate over list of given type, continuing after current point, - * safe against removal of list entry. - */ -#define list_for_each_entry_safe_continue(pos, n, head, member) \ - for (pos = list_next_entry(pos, member), \ - n = list_next_entry(pos, member); \ - &pos->member != (head); \ - pos = n, n = list_next_entry(n, member)) - -/** - * list_for_each_entry_safe_from - iterate over list from current point safe against removal - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_head within the struct. - * - * Iterate over list of given type from current point, safe against - * removal of list entry. - */ -#define list_for_each_entry_safe_from(pos, n, head, member) \ - for (n = list_next_entry(pos, member); \ - &pos->member != (head); \ - pos = n, n = list_next_entry(n, member)) - -/** - * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_head within the struct. - * - * Iterate backwards over list of given type, safe against removal - * of list entry. - */ -#define list_for_each_entry_safe_reverse(pos, n, head, member) \ - for (pos = list_last_entry(head, typeof(*pos), member), \ - n = list_prev_entry(pos, member); \ - &pos->member != (head); \ - pos = n, n = list_prev_entry(n, member)) - -/** - * list_safe_reset_next - reset a stale list_for_each_entry_safe loop - * @pos: the loop cursor used in the list_for_each_entry_safe loop - * @n: temporary storage used in list_for_each_entry_safe - * @member: the name of the list_head within the struct. - * - * list_safe_reset_next is not safe to use in general if the list may be - * modified concurrently (eg. the lock is dropped in the loop body). An - * exception to this is if the cursor element (pos) is pinned in the list, - * and list_safe_reset_next is called after re-taking the lock and before - * completing the current iteration of the loop body. - */ -#define list_safe_reset_next(pos, n, member) \ - n = list_next_entry(pos, member) - -/* - * Double linked lists with a single pointer list head. - * Mostly useful for hash tables where the two pointer list head is - * too wasteful. - * You lose the ability to access the tail in O(1). - */ - -#define HLIST_HEAD_INIT { .first = NULL } -#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL } -#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL) -static inline void INIT_HLIST_NODE(struct hlist_node *h) -{ - h->next = NULL; - h->pprev = NULL; -} - -static inline int hlist_unhashed(const struct hlist_node *h) -{ - return !h->pprev; -} - -static inline int hlist_empty(const struct hlist_head *h) -{ - return !READ_ONCE(h->first); -} - -static inline void __hlist_del(struct hlist_node *n) -{ - struct hlist_node *next = n->next; - struct hlist_node **pprev = n->pprev; - - WRITE_ONCE(*pprev, next); - if (next) - next->pprev = pprev; -} - -static inline void hlist_del(struct hlist_node *n) -{ - __hlist_del(n); - n->next = LIST_POISON1; - n->pprev = LIST_POISON2; -} - -static inline void hlist_del_init(struct hlist_node *n) -{ - if (!hlist_unhashed(n)) { - __hlist_del(n); - INIT_HLIST_NODE(n); - } -} - -static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) -{ - struct hlist_node *first = h->first; - n->next = first; - if (first) - first->pprev = &n->next; - WRITE_ONCE(h->first, n); - n->pprev = &h->first; -} - -/* next must be != NULL */ -static inline void hlist_add_before(struct hlist_node *n, - struct hlist_node *next) -{ - n->pprev = next->pprev; - n->next = next; - next->pprev = &n->next; - WRITE_ONCE(*(n->pprev), n); -} - -static inline void hlist_add_behind(struct hlist_node *n, - struct hlist_node *prev) -{ - n->next = prev->next; - WRITE_ONCE(prev->next, n); - n->pprev = &prev->next; - - if (n->next) - n->next->pprev = &n->next; -} - -/* after that we'll appear to be on some hlist and hlist_del will work */ -static inline void hlist_add_fake(struct hlist_node *n) -{ - n->pprev = &n->next; -} - -static inline bool hlist_fake(struct hlist_node *h) -{ - return h->pprev == &h->next; -} - -/* - * Check whether the node is the only node of the head without - * accessing head: - */ -static inline bool -hlist_is_singular_node(struct hlist_node *n, struct hlist_head *h) -{ - return !n->next && n->pprev == &h->first; -} - -/* - * Move a list from one list head to another. Fixup the pprev - * reference of the first entry if it exists. - */ -static inline void hlist_move_list(struct hlist_head *old, - struct hlist_head *new) -{ - new->first = old->first; - if (new->first) - new->first->pprev = &new->first; - old->first = NULL; -} - -#define hlist_entry(ptr, type, member) container_of(ptr,type,member) - -#define hlist_for_each(pos, head) \ - for (pos = (head)->first; pos ; pos = pos->next) - -#define hlist_for_each_safe(pos, n, head) \ - for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \ - pos = n) - -#define hlist_entry_safe(ptr, type, member) \ - ({ typeof(ptr) ____ptr = (ptr); \ - ____ptr ? hlist_entry(____ptr, type, member) : NULL; \ - }) - -/** - * hlist_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry(pos, head, member) \ - for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\ - pos; \ - pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) - -/** - * hlist_for_each_entry_continue - iterate over a hlist continuing after current point - * @pos: the type * to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_continue(pos, member) \ - for (pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member);\ - pos; \ - pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) - -/** - * hlist_for_each_entry_from - iterate over a hlist continuing from current point - * @pos: the type * to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_from(pos, member) \ - for (; pos; \ - pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member)) - -/** - * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another &struct hlist_node to use as temporary storage - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_safe(pos, n, head, member) \ - for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\ - pos && ({ n = pos->member.next; 1; }); \ - pos = hlist_entry_safe(n, typeof(*pos), member)) - -#endif diff --git a/src/linux/include/linux/list_bl.h b/src/linux/include/linux/list_bl.h deleted file mode 100644 index cb48330..0000000 --- a/src/linux/include/linux/list_bl.h +++ /dev/null @@ -1,162 +0,0 @@ -#ifndef _LINUX_LIST_BL_H -#define _LINUX_LIST_BL_H - -#include -#include - -/* - * Special version of lists, where head of the list has a lock in the lowest - * bit. This is useful for scalable hash tables without increasing memory - * footprint overhead. - * - * For modification operations, the 0 bit of hlist_bl_head->first - * pointer must be set. - * - * With some small modifications, this can easily be adapted to store several - * arbitrary bits (not just a single lock bit), if the need arises to store - * some fast and compact auxiliary data. - */ - -#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) -#define LIST_BL_LOCKMASK 1UL -#else -#define LIST_BL_LOCKMASK 0UL -#endif - -#ifdef CONFIG_DEBUG_LIST -#define LIST_BL_BUG_ON(x) BUG_ON(x) -#else -#define LIST_BL_BUG_ON(x) -#endif - - -struct hlist_bl_head { - struct hlist_bl_node *first; -}; - -struct hlist_bl_node { - struct hlist_bl_node *next, **pprev; -}; -#define INIT_HLIST_BL_HEAD(ptr) \ - ((ptr)->first = NULL) - -static inline void INIT_HLIST_BL_NODE(struct hlist_bl_node *h) -{ - h->next = NULL; - h->pprev = NULL; -} - -#define hlist_bl_entry(ptr, type, member) container_of(ptr,type,member) - -static inline bool hlist_bl_unhashed(const struct hlist_bl_node *h) -{ - return !h->pprev; -} - -static inline struct hlist_bl_node *hlist_bl_first(struct hlist_bl_head *h) -{ - return (struct hlist_bl_node *) - ((unsigned long)h->first & ~LIST_BL_LOCKMASK); -} - -static inline void hlist_bl_set_first(struct hlist_bl_head *h, - struct hlist_bl_node *n) -{ - LIST_BL_BUG_ON((unsigned long)n & LIST_BL_LOCKMASK); - LIST_BL_BUG_ON(((unsigned long)h->first & LIST_BL_LOCKMASK) != - LIST_BL_LOCKMASK); - h->first = (struct hlist_bl_node *)((unsigned long)n | LIST_BL_LOCKMASK); -} - -static inline bool hlist_bl_empty(const struct hlist_bl_head *h) -{ - return !((unsigned long)READ_ONCE(h->first) & ~LIST_BL_LOCKMASK); -} - -static inline void hlist_bl_add_head(struct hlist_bl_node *n, - struct hlist_bl_head *h) -{ - struct hlist_bl_node *first = hlist_bl_first(h); - - n->next = first; - if (first) - first->pprev = &n->next; - n->pprev = &h->first; - hlist_bl_set_first(h, n); -} - -static inline void __hlist_bl_del(struct hlist_bl_node *n) -{ - struct hlist_bl_node *next = n->next; - struct hlist_bl_node **pprev = n->pprev; - - LIST_BL_BUG_ON((unsigned long)n & LIST_BL_LOCKMASK); - - /* pprev may be `first`, so be careful not to lose the lock bit */ - WRITE_ONCE(*pprev, - (struct hlist_bl_node *) - ((unsigned long)next | - ((unsigned long)*pprev & LIST_BL_LOCKMASK))); - if (next) - next->pprev = pprev; -} - -static inline void hlist_bl_del(struct hlist_bl_node *n) -{ - __hlist_bl_del(n); - n->next = LIST_POISON1; - n->pprev = LIST_POISON2; -} - -static inline void hlist_bl_del_init(struct hlist_bl_node *n) -{ - if (!hlist_bl_unhashed(n)) { - __hlist_bl_del(n); - INIT_HLIST_BL_NODE(n); - } -} - -static inline void hlist_bl_lock(struct hlist_bl_head *b) -{ - bit_spin_lock(0, (unsigned long *)b); -} - -static inline void hlist_bl_unlock(struct hlist_bl_head *b) -{ - __bit_spin_unlock(0, (unsigned long *)b); -} - -static inline bool hlist_bl_is_locked(struct hlist_bl_head *b) -{ - return bit_spin_is_locked(0, (unsigned long *)b); -} - -/** - * hlist_bl_for_each_entry - iterate over list of given type - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - * - */ -#define hlist_bl_for_each_entry(tpos, pos, head, member) \ - for (pos = hlist_bl_first(head); \ - pos && \ - ({ tpos = hlist_bl_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_bl_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @n: another &struct hlist_node to use as temporary storage - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_bl_for_each_entry_safe(tpos, pos, n, head, member) \ - for (pos = hlist_bl_first(head); \ - pos && ({ n = pos->next; 1; }) && \ - ({ tpos = hlist_bl_entry(pos, typeof(*tpos), member); 1;}); \ - pos = n) - -#endif diff --git a/src/linux/include/linux/list_lru.h b/src/linux/include/linux/list_lru.h deleted file mode 100644 index cb0ba9f..0000000 --- a/src/linux/include/linux/list_lru.h +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2013 Red Hat, Inc. and Parallels Inc. All rights reserved. - * Authors: David Chinner and Glauber Costa - * - * Generic LRU infrastructure - */ -#ifndef _LRU_LIST_H -#define _LRU_LIST_H - -#include -#include -#include - -struct mem_cgroup; - -/* list_lru_walk_cb has to always return one of those */ -enum lru_status { - LRU_REMOVED, /* item removed from list */ - LRU_REMOVED_RETRY, /* item removed, but lock has been - dropped and reacquired */ - LRU_ROTATE, /* item referenced, give another pass */ - LRU_SKIP, /* item cannot be locked, skip */ - LRU_RETRY, /* item not freeable. May drop the lock - internally, but has to return locked. */ -}; - -struct list_lru_one { - struct list_head list; - /* may become negative during memcg reparenting */ - long nr_items; -}; - -struct list_lru_memcg { - /* array of per cgroup lists, indexed by memcg_cache_id */ - struct list_lru_one *lru[0]; -}; - -struct list_lru_node { - /* protects all lists on the node, including per cgroup */ - spinlock_t lock; - /* global list, used for the root cgroup in cgroup aware lrus */ - struct list_lru_one lru; -#if defined(CONFIG_MEMCG) && !defined(CONFIG_SLOB) - /* for cgroup aware lrus points to per cgroup lists, otherwise NULL */ - struct list_lru_memcg *memcg_lrus; -#endif -} ____cacheline_aligned_in_smp; - -struct list_lru { - struct list_lru_node *node; -#if defined(CONFIG_MEMCG) && !defined(CONFIG_SLOB) - struct list_head list; -#endif -}; - -void list_lru_destroy(struct list_lru *lru); -int __list_lru_init(struct list_lru *lru, bool memcg_aware, - struct lock_class_key *key); - -#define list_lru_init(lru) __list_lru_init((lru), false, NULL) -#define list_lru_init_key(lru, key) __list_lru_init((lru), false, (key)) -#define list_lru_init_memcg(lru) __list_lru_init((lru), true, NULL) - -int memcg_update_all_list_lrus(int num_memcgs); -void memcg_drain_all_list_lrus(int src_idx, int dst_idx); - -/** - * list_lru_add: add an element to the lru list's tail - * @list_lru: the lru pointer - * @item: the item to be added. - * - * If the element is already part of a list, this function returns doing - * nothing. Therefore the caller does not need to keep state about whether or - * not the element already belongs in the list and is allowed to lazy update - * it. Note however that this is valid for *a* list, not *this* list. If - * the caller organize itself in a way that elements can be in more than - * one type of list, it is up to the caller to fully remove the item from - * the previous list (with list_lru_del() for instance) before moving it - * to @list_lru - * - * Return value: true if the list was updated, false otherwise - */ -bool list_lru_add(struct list_lru *lru, struct list_head *item); - -/** - * list_lru_del: delete an element to the lru list - * @list_lru: the lru pointer - * @item: the item to be deleted. - * - * This function works analogously as list_lru_add in terms of list - * manipulation. The comments about an element already pertaining to - * a list are also valid for list_lru_del. - * - * Return value: true if the list was updated, false otherwise - */ -bool list_lru_del(struct list_lru *lru, struct list_head *item); - -/** - * list_lru_count_one: return the number of objects currently held by @lru - * @lru: the lru pointer. - * @nid: the node id to count from. - * @memcg: the cgroup to count from. - * - * Always return a non-negative number, 0 for empty lists. There is no - * guarantee that the list is not updated while the count is being computed. - * Callers that want such a guarantee need to provide an outer lock. - */ -unsigned long list_lru_count_one(struct list_lru *lru, - int nid, struct mem_cgroup *memcg); -unsigned long list_lru_count_node(struct list_lru *lru, int nid); - -static inline unsigned long list_lru_shrink_count(struct list_lru *lru, - struct shrink_control *sc) -{ - return list_lru_count_one(lru, sc->nid, sc->memcg); -} - -static inline unsigned long list_lru_count(struct list_lru *lru) -{ - long count = 0; - int nid; - - for_each_node_state(nid, N_NORMAL_MEMORY) - count += list_lru_count_node(lru, nid); - - return count; -} - -void list_lru_isolate(struct list_lru_one *list, struct list_head *item); -void list_lru_isolate_move(struct list_lru_one *list, struct list_head *item, - struct list_head *head); - -typedef enum lru_status (*list_lru_walk_cb)(struct list_head *item, - struct list_lru_one *list, spinlock_t *lock, void *cb_arg); - -/** - * list_lru_walk_one: walk a list_lru, isolating and disposing freeable items. - * @lru: the lru pointer. - * @nid: the node id to scan from. - * @memcg: the cgroup to scan from. - * @isolate: callback function that is resposible for deciding what to do with - * the item currently being scanned - * @cb_arg: opaque type that will be passed to @isolate - * @nr_to_walk: how many items to scan. - * - * This function will scan all elements in a particular list_lru, calling the - * @isolate callback for each of those items, along with the current list - * spinlock and a caller-provided opaque. The @isolate callback can choose to - * drop the lock internally, but *must* return with the lock held. The callback - * will return an enum lru_status telling the list_lru infrastructure what to - * do with the object being scanned. - * - * Please note that nr_to_walk does not mean how many objects will be freed, - * just how many objects will be scanned. - * - * Return value: the number of objects effectively removed from the LRU. - */ -unsigned long list_lru_walk_one(struct list_lru *lru, - int nid, struct mem_cgroup *memcg, - list_lru_walk_cb isolate, void *cb_arg, - unsigned long *nr_to_walk); -unsigned long list_lru_walk_node(struct list_lru *lru, int nid, - list_lru_walk_cb isolate, void *cb_arg, - unsigned long *nr_to_walk); - -static inline unsigned long -list_lru_shrink_walk(struct list_lru *lru, struct shrink_control *sc, - list_lru_walk_cb isolate, void *cb_arg) -{ - return list_lru_walk_one(lru, sc->nid, sc->memcg, isolate, cb_arg, - &sc->nr_to_scan); -} - -static inline unsigned long -list_lru_walk(struct list_lru *lru, list_lru_walk_cb isolate, - void *cb_arg, unsigned long nr_to_walk) -{ - long isolated = 0; - int nid; - - for_each_node_state(nid, N_NORMAL_MEMORY) { - isolated += list_lru_walk_node(lru, nid, isolate, - cb_arg, &nr_to_walk); - if (nr_to_walk <= 0) - break; - } - return isolated; -} -#endif /* _LRU_LIST_H */ diff --git a/src/linux/include/linux/list_nulls.h b/src/linux/include/linux/list_nulls.h deleted file mode 100644 index b01fe10..0000000 --- a/src/linux/include/linux/list_nulls.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef _LINUX_LIST_NULLS_H -#define _LINUX_LIST_NULLS_H - -#include -#include - -/* - * Special version of lists, where end of list is not a NULL pointer, - * but a 'nulls' marker, which can have many different values. - * (up to 2^31 different values guaranteed on all platforms) - * - * In the standard hlist, termination of a list is the NULL pointer. - * In this special 'nulls' variant, we use the fact that objects stored in - * a list are aligned on a word (4 or 8 bytes alignment). - * We therefore use the last significant bit of 'ptr' : - * Set to 1 : This is a 'nulls' end-of-list marker (ptr >> 1) - * Set to 0 : This is a pointer to some object (ptr) - */ - -struct hlist_nulls_head { - struct hlist_nulls_node *first; -}; - -struct hlist_nulls_node { - struct hlist_nulls_node *next, **pprev; -}; -#define NULLS_MARKER(value) (1UL | (((long)value) << 1)) -#define INIT_HLIST_NULLS_HEAD(ptr, nulls) \ - ((ptr)->first = (struct hlist_nulls_node *) NULLS_MARKER(nulls)) - -#define hlist_nulls_entry(ptr, type, member) container_of(ptr,type,member) -/** - * ptr_is_a_nulls - Test if a ptr is a nulls - * @ptr: ptr to be tested - * - */ -static inline int is_a_nulls(const struct hlist_nulls_node *ptr) -{ - return ((unsigned long)ptr & 1); -} - -/** - * get_nulls_value - Get the 'nulls' value of the end of chain - * @ptr: end of chain - * - * Should be called only if is_a_nulls(ptr); - */ -static inline unsigned long get_nulls_value(const struct hlist_nulls_node *ptr) -{ - return ((unsigned long)ptr) >> 1; -} - -static inline int hlist_nulls_unhashed(const struct hlist_nulls_node *h) -{ - return !h->pprev; -} - -static inline int hlist_nulls_empty(const struct hlist_nulls_head *h) -{ - return is_a_nulls(READ_ONCE(h->first)); -} - -static inline void hlist_nulls_add_head(struct hlist_nulls_node *n, - struct hlist_nulls_head *h) -{ - struct hlist_nulls_node *first = h->first; - - n->next = first; - n->pprev = &h->first; - h->first = n; - if (!is_a_nulls(first)) - first->pprev = &n->next; -} - -static inline void __hlist_nulls_del(struct hlist_nulls_node *n) -{ - struct hlist_nulls_node *next = n->next; - struct hlist_nulls_node **pprev = n->pprev; - - WRITE_ONCE(*pprev, next); - if (!is_a_nulls(next)) - next->pprev = pprev; -} - -static inline void hlist_nulls_del(struct hlist_nulls_node *n) -{ - __hlist_nulls_del(n); - n->pprev = LIST_POISON2; -} - -/** - * hlist_nulls_for_each_entry - iterate over list of given type - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - * - */ -#define hlist_nulls_for_each_entry(tpos, pos, head, member) \ - for (pos = (head)->first; \ - (!is_a_nulls(pos)) && \ - ({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -/** - * hlist_nulls_for_each_entry_from - iterate over a hlist continuing from current point - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - * - */ -#define hlist_nulls_for_each_entry_from(tpos, pos, member) \ - for (; (!is_a_nulls(pos)) && \ - ({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1;}); \ - pos = pos->next) - -#endif diff --git a/src/linux/include/linux/list_sort.h b/src/linux/include/linux/list_sort.h deleted file mode 100644 index 1a2df2e..0000000 --- a/src/linux/include/linux/list_sort.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _LINUX_LIST_SORT_H -#define _LINUX_LIST_SORT_H - -#include - -struct list_head; - -void list_sort(void *priv, struct list_head *head, - int (*cmp)(void *priv, struct list_head *a, - struct list_head *b)); -#endif diff --git a/src/linux/include/linux/llist.h b/src/linux/include/linux/llist.h deleted file mode 100644 index fd4ca0b..0000000 --- a/src/linux/include/linux/llist.h +++ /dev/null @@ -1,200 +0,0 @@ -#ifndef LLIST_H -#define LLIST_H -/* - * Lock-less NULL terminated single linked list - * - * If there are multiple producers and multiple consumers, llist_add - * can be used in producers and llist_del_all can be used in - * consumers. They can work simultaneously without lock. But - * llist_del_first can not be used here. Because llist_del_first - * depends on list->first->next does not changed if list->first is not - * changed during its operation, but llist_del_first, llist_add, - * llist_add (or llist_del_all, llist_add, llist_add) sequence in - * another consumer may violate that. - * - * If there are multiple producers and one consumer, llist_add can be - * used in producers and llist_del_all or llist_del_first can be used - * in the consumer. - * - * This can be summarized as follow: - * - * | add | del_first | del_all - * add | - | - | - - * del_first | | L | L - * del_all | | | - - * - * Where "-" stands for no lock is needed, while "L" stands for lock - * is needed. - * - * The list entries deleted via llist_del_all can be traversed with - * traversing function such as llist_for_each etc. But the list - * entries can not be traversed safely before deleted from the list. - * The order of deleted entries is from the newest to the oldest added - * one. If you want to traverse from the oldest to the newest, you - * must reverse the order by yourself before traversing. - * - * The basic atomic operation of this list is cmpxchg on long. On - * architectures that don't have NMI-safe cmpxchg implementation, the - * list can NOT be used in NMI handlers. So code that uses the list in - * an NMI handler should depend on CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG. - * - * Copyright 2010,2011 Intel Corp. - * Author: Huang Ying - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include - -struct llist_head { - struct llist_node *first; -}; - -struct llist_node { - struct llist_node *next; -}; - -#define LLIST_HEAD_INIT(name) { NULL } -#define LLIST_HEAD(name) struct llist_head name = LLIST_HEAD_INIT(name) - -/** - * init_llist_head - initialize lock-less list head - * @head: the head for your lock-less list - */ -static inline void init_llist_head(struct llist_head *list) -{ - list->first = NULL; -} - -/** - * llist_entry - get the struct of this entry - * @ptr: the &struct llist_node pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the llist_node within the struct. - */ -#define llist_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * llist_for_each - iterate over some deleted entries of a lock-less list - * @pos: the &struct llist_node to use as a loop cursor - * @node: the first entry of deleted list entries - * - * In general, some entries of the lock-less list can be traversed - * safely only after being deleted from list, so start with an entry - * instead of list head. - * - * If being used on entries deleted from lock-less list directly, the - * traverse order is from the newest to the oldest added entry. If - * you want to traverse from the oldest to the newest, you must - * reverse the order by yourself before traversing. - */ -#define llist_for_each(pos, node) \ - for ((pos) = (node); pos; (pos) = (pos)->next) - -/** - * llist_for_each_entry - iterate over some deleted entries of lock-less list of given type - * @pos: the type * to use as a loop cursor. - * @node: the fist entry of deleted list entries. - * @member: the name of the llist_node with the struct. - * - * In general, some entries of the lock-less list can be traversed - * safely only after being removed from list, so start with an entry - * instead of list head. - * - * If being used on entries deleted from lock-less list directly, the - * traverse order is from the newest to the oldest added entry. If - * you want to traverse from the oldest to the newest, you must - * reverse the order by yourself before traversing. - */ -#define llist_for_each_entry(pos, node, member) \ - for ((pos) = llist_entry((node), typeof(*(pos)), member); \ - &(pos)->member != NULL; \ - (pos) = llist_entry((pos)->member.next, typeof(*(pos)), member)) - -/** - * llist_for_each_entry_safe - iterate over some deleted entries of lock-less list of given type - * safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @node: the first entry of deleted list entries. - * @member: the name of the llist_node with the struct. - * - * In general, some entries of the lock-less list can be traversed - * safely only after being removed from list, so start with an entry - * instead of list head. - * - * If being used on entries deleted from lock-less list directly, the - * traverse order is from the newest to the oldest added entry. If - * you want to traverse from the oldest to the newest, you must - * reverse the order by yourself before traversing. - */ -#define llist_for_each_entry_safe(pos, n, node, member) \ - for (pos = llist_entry((node), typeof(*pos), member); \ - &pos->member != NULL && \ - (n = llist_entry(pos->member.next, typeof(*n), member), true); \ - pos = n) - -/** - * llist_empty - tests whether a lock-less list is empty - * @head: the list to test - * - * Not guaranteed to be accurate or up to date. Just a quick way to - * test whether the list is empty without deleting something from the - * list. - */ -static inline bool llist_empty(const struct llist_head *head) -{ - return ACCESS_ONCE(head->first) == NULL; -} - -static inline struct llist_node *llist_next(struct llist_node *node) -{ - return node->next; -} - -extern bool llist_add_batch(struct llist_node *new_first, - struct llist_node *new_last, - struct llist_head *head); -/** - * llist_add - add a new entry - * @new: new entry to be added - * @head: the head for your lock-less list - * - * Returns true if the list was empty prior to adding this entry. - */ -static inline bool llist_add(struct llist_node *new, struct llist_head *head) -{ - return llist_add_batch(new, new, head); -} - -/** - * llist_del_all - delete all entries from lock-less list - * @head: the head of lock-less list to delete all entries - * - * If list is empty, return NULL, otherwise, delete all entries and - * return the pointer to the first entry. The order of entries - * deleted is from the newest to the oldest added one. - */ -static inline struct llist_node *llist_del_all(struct llist_head *head) -{ - return xchg(&head->first, NULL); -} - -extern struct llist_node *llist_del_first(struct llist_head *head); - -struct llist_node *llist_reverse_order(struct llist_node *head); - -#endif /* LLIST_H */ diff --git a/src/linux/include/linux/lockdep.h b/src/linux/include/linux/lockdep.h deleted file mode 100644 index c1458fe..0000000 --- a/src/linux/include/linux/lockdep.h +++ /dev/null @@ -1,579 +0,0 @@ -/* - * Runtime locking correctness validator - * - * Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar - * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra - * - * see Documentation/locking/lockdep-design.txt for more details. - */ -#ifndef __LINUX_LOCKDEP_H -#define __LINUX_LOCKDEP_H - -struct task_struct; -struct lockdep_map; - -/* for sysctl */ -extern int prove_locking; -extern int lock_stat; - -#define MAX_LOCKDEP_SUBCLASSES 8UL - -#ifdef CONFIG_LOCKDEP - -#include -#include -#include -#include - -/* - * We'd rather not expose kernel/lockdep_states.h this wide, but we do need - * the total number of states... :-( - */ -#define XXX_LOCK_USAGE_STATES (1+3*4) - -/* - * NR_LOCKDEP_CACHING_CLASSES ... Number of classes - * cached in the instance of lockdep_map - * - * Currently main class (subclass == 0) and signle depth subclass - * are cached in lockdep_map. This optimization is mainly targeting - * on rq->lock. double_rq_lock() acquires this highly competitive with - * single depth. - */ -#define NR_LOCKDEP_CACHING_CLASSES 2 - -/* - * Lock-classes are keyed via unique addresses, by embedding the - * lockclass-key into the kernel (or module) .data section. (For - * static locks we use the lock address itself as the key.) - */ -struct lockdep_subclass_key { - char __one_byte; -} __attribute__ ((__packed__)); - -struct lock_class_key { - struct lockdep_subclass_key subkeys[MAX_LOCKDEP_SUBCLASSES]; -}; - -extern struct lock_class_key __lockdep_no_validate__; - -#define LOCKSTAT_POINTS 4 - -/* - * The lock-class itself: - */ -struct lock_class { - /* - * class-hash: - */ - struct hlist_node hash_entry; - - /* - * global list of all lock-classes: - */ - struct list_head lock_entry; - - struct lockdep_subclass_key *key; - unsigned int subclass; - unsigned int dep_gen_id; - - /* - * IRQ/softirq usage tracking bits: - */ - unsigned long usage_mask; - struct stack_trace usage_traces[XXX_LOCK_USAGE_STATES]; - - /* - * These fields represent a directed graph of lock dependencies, - * to every node we attach a list of "forward" and a list of - * "backward" graph nodes. - */ - struct list_head locks_after, locks_before; - - /* - * Generation counter, when doing certain classes of graph walking, - * to ensure that we check one node only once: - */ - unsigned int version; - - /* - * Statistics counter: - */ - unsigned long ops; - - const char *name; - int name_version; - -#ifdef CONFIG_LOCK_STAT - unsigned long contention_point[LOCKSTAT_POINTS]; - unsigned long contending_point[LOCKSTAT_POINTS]; -#endif -}; - -#ifdef CONFIG_LOCK_STAT -struct lock_time { - s64 min; - s64 max; - s64 total; - unsigned long nr; -}; - -enum bounce_type { - bounce_acquired_write, - bounce_acquired_read, - bounce_contended_write, - bounce_contended_read, - nr_bounce_types, - - bounce_acquired = bounce_acquired_write, - bounce_contended = bounce_contended_write, -}; - -struct lock_class_stats { - unsigned long contention_point[LOCKSTAT_POINTS]; - unsigned long contending_point[LOCKSTAT_POINTS]; - struct lock_time read_waittime; - struct lock_time write_waittime; - struct lock_time read_holdtime; - struct lock_time write_holdtime; - unsigned long bounces[nr_bounce_types]; -}; - -struct lock_class_stats lock_stats(struct lock_class *class); -void clear_lock_stats(struct lock_class *class); -#endif - -/* - * Map the lock object (the lock instance) to the lock-class object. - * This is embedded into specific lock instances: - */ -struct lockdep_map { - struct lock_class_key *key; - struct lock_class *class_cache[NR_LOCKDEP_CACHING_CLASSES]; - const char *name; -#ifdef CONFIG_LOCK_STAT - int cpu; - unsigned long ip; -#endif -}; - -static inline void lockdep_copy_map(struct lockdep_map *to, - struct lockdep_map *from) -{ - int i; - - *to = *from; - /* - * Since the class cache can be modified concurrently we could observe - * half pointers (64bit arch using 32bit copy insns). Therefore clear - * the caches and take the performance hit. - * - * XXX it doesn't work well with lockdep_set_class_and_subclass(), since - * that relies on cache abuse. - */ - for (i = 0; i < NR_LOCKDEP_CACHING_CLASSES; i++) - to->class_cache[i] = NULL; -} - -/* - * Every lock has a list of other locks that were taken after it. - * We only grow the list, never remove from it: - */ -struct lock_list { - struct list_head entry; - struct lock_class *class; - struct stack_trace trace; - int distance; - - /* - * The parent field is used to implement breadth-first search, and the - * bit 0 is reused to indicate if the lock has been accessed in BFS. - */ - struct lock_list *parent; -}; - -/* - * We record lock dependency chains, so that we can cache them: - */ -struct lock_chain { - /* see BUILD_BUG_ON()s in lookup_chain_cache() */ - unsigned int irq_context : 2, - depth : 6, - base : 24; - /* 4 byte hole */ - struct hlist_node entry; - u64 chain_key; -}; - -#define MAX_LOCKDEP_KEYS_BITS 13 -/* - * Subtract one because we offset hlock->class_idx by 1 in order - * to make 0 mean no class. This avoids overflowing the class_idx - * bitfield and hitting the BUG in hlock_class(). - */ -#define MAX_LOCKDEP_KEYS ((1UL << MAX_LOCKDEP_KEYS_BITS) - 1) - -struct held_lock { - /* - * One-way hash of the dependency chain up to this point. We - * hash the hashes step by step as the dependency chain grows. - * - * We use it for dependency-caching and we skip detection - * passes and dependency-updates if there is a cache-hit, so - * it is absolutely critical for 100% coverage of the validator - * to have a unique key value for every unique dependency path - * that can occur in the system, to make a unique hash value - * as likely as possible - hence the 64-bit width. - * - * The task struct holds the current hash value (initialized - * with zero), here we store the previous hash value: - */ - u64 prev_chain_key; - unsigned long acquire_ip; - struct lockdep_map *instance; - struct lockdep_map *nest_lock; -#ifdef CONFIG_LOCK_STAT - u64 waittime_stamp; - u64 holdtime_stamp; -#endif - unsigned int class_idx:MAX_LOCKDEP_KEYS_BITS; - /* - * The lock-stack is unified in that the lock chains of interrupt - * contexts nest ontop of process context chains, but we 'separate' - * the hashes by starting with 0 if we cross into an interrupt - * context, and we also keep do not add cross-context lock - * dependencies - the lock usage graph walking covers that area - * anyway, and we'd just unnecessarily increase the number of - * dependencies otherwise. [Note: hardirq and softirq contexts - * are separated from each other too.] - * - * The following field is used to detect when we cross into an - * interrupt context: - */ - unsigned int irq_context:2; /* bit 0 - soft, bit 1 - hard */ - unsigned int trylock:1; /* 16 bits */ - - unsigned int read:2; /* see lock_acquire() comment */ - unsigned int check:1; /* see lock_acquire() comment */ - unsigned int hardirqs_off:1; - unsigned int references:12; /* 32 bits */ - unsigned int pin_count; -}; - -/* - * Initialization, self-test and debugging-output methods: - */ -extern void lockdep_info(void); -extern void lockdep_reset(void); -extern void lockdep_reset_lock(struct lockdep_map *lock); -extern void lockdep_free_key_range(void *start, unsigned long size); -extern asmlinkage void lockdep_sys_exit(void); - -extern void lockdep_off(void); -extern void lockdep_on(void); - -/* - * These methods are used by specific locking variants (spinlocks, - * rwlocks, mutexes and rwsems) to pass init/acquire/release events - * to lockdep: - */ - -extern void lockdep_init_map(struct lockdep_map *lock, const char *name, - struct lock_class_key *key, int subclass); - -/* - * To initialize a lockdep_map statically use this macro. - * Note that _name must not be NULL. - */ -#define STATIC_LOCKDEP_MAP_INIT(_name, _key) \ - { .name = (_name), .key = (void *)(_key), } - -/* - * Reinitialize a lock key - for cases where there is special locking or - * special initialization of locks so that the validator gets the scope - * of dependencies wrong: they are either too broad (they need a class-split) - * or they are too narrow (they suffer from a false class-split): - */ -#define lockdep_set_class(lock, key) \ - lockdep_init_map(&(lock)->dep_map, #key, key, 0) -#define lockdep_set_class_and_name(lock, key, name) \ - lockdep_init_map(&(lock)->dep_map, name, key, 0) -#define lockdep_set_class_and_subclass(lock, key, sub) \ - lockdep_init_map(&(lock)->dep_map, #key, key, sub) -#define lockdep_set_subclass(lock, sub) \ - lockdep_init_map(&(lock)->dep_map, #lock, \ - (lock)->dep_map.key, sub) - -#define lockdep_set_novalidate_class(lock) \ - lockdep_set_class_and_name(lock, &__lockdep_no_validate__, #lock) -/* - * Compare locking classes - */ -#define lockdep_match_class(lock, key) lockdep_match_key(&(lock)->dep_map, key) - -static inline int lockdep_match_key(struct lockdep_map *lock, - struct lock_class_key *key) -{ - return lock->key == key; -} - -/* - * Acquire a lock. - * - * Values for "read": - * - * 0: exclusive (write) acquire - * 1: read-acquire (no recursion allowed) - * 2: read-acquire with same-instance recursion allowed - * - * Values for check: - * - * 0: simple checks (freeing, held-at-exit-time, etc.) - * 1: full validation - */ -extern void lock_acquire(struct lockdep_map *lock, unsigned int subclass, - int trylock, int read, int check, - struct lockdep_map *nest_lock, unsigned long ip); - -extern void lock_release(struct lockdep_map *lock, int nested, - unsigned long ip); - -#define lockdep_is_held(lock) lock_is_held(&(lock)->dep_map) - -extern int lock_is_held(struct lockdep_map *lock); - -extern void lock_set_class(struct lockdep_map *lock, const char *name, - struct lock_class_key *key, unsigned int subclass, - unsigned long ip); - -static inline void lock_set_subclass(struct lockdep_map *lock, - unsigned int subclass, unsigned long ip) -{ - lock_set_class(lock, lock->name, lock->key, subclass, ip); -} - -extern void lockdep_set_current_reclaim_state(gfp_t gfp_mask); -extern void lockdep_clear_current_reclaim_state(void); -extern void lockdep_trace_alloc(gfp_t mask); - -struct pin_cookie { unsigned int val; }; - -#define NIL_COOKIE (struct pin_cookie){ .val = 0U, } - -extern struct pin_cookie lock_pin_lock(struct lockdep_map *lock); -extern void lock_repin_lock(struct lockdep_map *lock, struct pin_cookie); -extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie); - -# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, - -#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0) - -#define lockdep_assert_held(l) do { \ - WARN_ON(debug_locks && !lockdep_is_held(l)); \ - } while (0) - -#define lockdep_assert_held_once(l) do { \ - WARN_ON_ONCE(debug_locks && !lockdep_is_held(l)); \ - } while (0) - -#define lockdep_recursing(tsk) ((tsk)->lockdep_recursion) - -#define lockdep_pin_lock(l) lock_pin_lock(&(l)->dep_map) -#define lockdep_repin_lock(l,c) lock_repin_lock(&(l)->dep_map, (c)) -#define lockdep_unpin_lock(l,c) lock_unpin_lock(&(l)->dep_map, (c)) - -#else /* !CONFIG_LOCKDEP */ - -static inline void lockdep_off(void) -{ -} - -static inline void lockdep_on(void) -{ -} - -# define lock_acquire(l, s, t, r, c, n, i) do { } while (0) -# define lock_release(l, n, i) do { } while (0) -# define lock_set_class(l, n, k, s, i) do { } while (0) -# define lock_set_subclass(l, s, i) do { } while (0) -# define lockdep_set_current_reclaim_state(g) do { } while (0) -# define lockdep_clear_current_reclaim_state() do { } while (0) -# define lockdep_trace_alloc(g) do { } while (0) -# define lockdep_info() do { } while (0) -# define lockdep_init_map(lock, name, key, sub) \ - do { (void)(name); (void)(key); } while (0) -# define lockdep_set_class(lock, key) do { (void)(key); } while (0) -# define lockdep_set_class_and_name(lock, key, name) \ - do { (void)(key); (void)(name); } while (0) -#define lockdep_set_class_and_subclass(lock, key, sub) \ - do { (void)(key); } while (0) -#define lockdep_set_subclass(lock, sub) do { } while (0) - -#define lockdep_set_novalidate_class(lock) do { } while (0) - -/* - * We don't define lockdep_match_class() and lockdep_match_key() for !LOCKDEP - * case since the result is not well defined and the caller should rather - * #ifdef the call himself. - */ - -# define INIT_LOCKDEP -# define lockdep_reset() do { debug_locks = 1; } while (0) -# define lockdep_free_key_range(start, size) do { } while (0) -# define lockdep_sys_exit() do { } while (0) -/* - * The class key takes no space if lockdep is disabled: - */ -struct lock_class_key { }; - -#define lockdep_depth(tsk) (0) - -#define lockdep_assert_held(l) do { (void)(l); } while (0) -#define lockdep_assert_held_once(l) do { (void)(l); } while (0) - -#define lockdep_recursing(tsk) (0) - -struct pin_cookie { }; - -#define NIL_COOKIE (struct pin_cookie){ } - -#define lockdep_pin_lock(l) ({ struct pin_cookie cookie; cookie; }) -#define lockdep_repin_lock(l, c) do { (void)(l); (void)(c); } while (0) -#define lockdep_unpin_lock(l, c) do { (void)(l); (void)(c); } while (0) - -#endif /* !LOCKDEP */ - -#ifdef CONFIG_LOCK_STAT - -extern void lock_contended(struct lockdep_map *lock, unsigned long ip); -extern void lock_acquired(struct lockdep_map *lock, unsigned long ip); - -#define LOCK_CONTENDED(_lock, try, lock) \ -do { \ - if (!try(_lock)) { \ - lock_contended(&(_lock)->dep_map, _RET_IP_); \ - lock(_lock); \ - } \ - lock_acquired(&(_lock)->dep_map, _RET_IP_); \ -} while (0) - -#define LOCK_CONTENDED_RETURN(_lock, try, lock) \ -({ \ - int ____err = 0; \ - if (!try(_lock)) { \ - lock_contended(&(_lock)->dep_map, _RET_IP_); \ - ____err = lock(_lock); \ - } \ - if (!____err) \ - lock_acquired(&(_lock)->dep_map, _RET_IP_); \ - ____err; \ -}) - -#else /* CONFIG_LOCK_STAT */ - -#define lock_contended(lockdep_map, ip) do {} while (0) -#define lock_acquired(lockdep_map, ip) do {} while (0) - -#define LOCK_CONTENDED(_lock, try, lock) \ - lock(_lock) - -#define LOCK_CONTENDED_RETURN(_lock, try, lock) \ - lock(_lock) - -#endif /* CONFIG_LOCK_STAT */ - -#ifdef CONFIG_LOCKDEP - -/* - * On lockdep we dont want the hand-coded irq-enable of - * _raw_*_lock_flags() code, because lockdep assumes - * that interrupts are not re-enabled during lock-acquire: - */ -#define LOCK_CONTENDED_FLAGS(_lock, try, lock, lockfl, flags) \ - LOCK_CONTENDED((_lock), (try), (lock)) - -#else /* CONFIG_LOCKDEP */ - -#define LOCK_CONTENDED_FLAGS(_lock, try, lock, lockfl, flags) \ - lockfl((_lock), (flags)) - -#endif /* CONFIG_LOCKDEP */ - -#ifdef CONFIG_TRACE_IRQFLAGS -extern void print_irqtrace_events(struct task_struct *curr); -#else -static inline void print_irqtrace_events(struct task_struct *curr) -{ -} -#endif - -/* - * For trivial one-depth nesting of a lock-class, the following - * global define can be used. (Subsystems with multiple levels - * of nesting should define their own lock-nesting subclasses.) - */ -#define SINGLE_DEPTH_NESTING 1 - -/* - * Map the dependency ops to NOP or to real lockdep ops, depending - * on the per lock-class debug mode: - */ - -#define lock_acquire_exclusive(l, s, t, n, i) lock_acquire(l, s, t, 0, 1, n, i) -#define lock_acquire_shared(l, s, t, n, i) lock_acquire(l, s, t, 1, 1, n, i) -#define lock_acquire_shared_recursive(l, s, t, n, i) lock_acquire(l, s, t, 2, 1, n, i) - -#define spin_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i) -#define spin_acquire_nest(l, s, t, n, i) lock_acquire_exclusive(l, s, t, n, i) -#define spin_release(l, n, i) lock_release(l, n, i) - -#define rwlock_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i) -#define rwlock_acquire_read(l, s, t, i) lock_acquire_shared_recursive(l, s, t, NULL, i) -#define rwlock_release(l, n, i) lock_release(l, n, i) - -#define seqcount_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i) -#define seqcount_acquire_read(l, s, t, i) lock_acquire_shared_recursive(l, s, t, NULL, i) -#define seqcount_release(l, n, i) lock_release(l, n, i) - -#define mutex_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i) -#define mutex_acquire_nest(l, s, t, n, i) lock_acquire_exclusive(l, s, t, n, i) -#define mutex_release(l, n, i) lock_release(l, n, i) - -#define rwsem_acquire(l, s, t, i) lock_acquire_exclusive(l, s, t, NULL, i) -#define rwsem_acquire_nest(l, s, t, n, i) lock_acquire_exclusive(l, s, t, n, i) -#define rwsem_acquire_read(l, s, t, i) lock_acquire_shared(l, s, t, NULL, i) -#define rwsem_release(l, n, i) lock_release(l, n, i) - -#define lock_map_acquire(l) lock_acquire_exclusive(l, 0, 0, NULL, _THIS_IP_) -#define lock_map_acquire_read(l) lock_acquire_shared_recursive(l, 0, 0, NULL, _THIS_IP_) -#define lock_map_acquire_tryread(l) lock_acquire_shared_recursive(l, 0, 1, NULL, _THIS_IP_) -#define lock_map_release(l) lock_release(l, 1, _THIS_IP_) - -#ifdef CONFIG_PROVE_LOCKING -# define might_lock(lock) \ -do { \ - typecheck(struct lockdep_map *, &(lock)->dep_map); \ - lock_acquire(&(lock)->dep_map, 0, 0, 0, 1, NULL, _THIS_IP_); \ - lock_release(&(lock)->dep_map, 0, _THIS_IP_); \ -} while (0) -# define might_lock_read(lock) \ -do { \ - typecheck(struct lockdep_map *, &(lock)->dep_map); \ - lock_acquire(&(lock)->dep_map, 0, 0, 1, 1, NULL, _THIS_IP_); \ - lock_release(&(lock)->dep_map, 0, _THIS_IP_); \ -} while (0) -#else -# define might_lock(lock) do { } while (0) -# define might_lock_read(lock) do { } while (0) -#endif - -#ifdef CONFIG_LOCKDEP -void lockdep_rcu_suspicious(const char *file, const int line, const char *s); -#else -static inline void -lockdep_rcu_suspicious(const char *file, const int line, const char *s) -{ -} -#endif - -#endif /* __LINUX_LOCKDEP_H */ diff --git a/src/linux/include/linux/lockref.h b/src/linux/include/linux/lockref.h deleted file mode 100644 index b10b122..0000000 --- a/src/linux/include/linux/lockref.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef __LINUX_LOCKREF_H -#define __LINUX_LOCKREF_H - -/* - * Locked reference counts. - * - * These are different from just plain atomic refcounts in that they - * are atomic with respect to the spinlock that goes with them. In - * particular, there can be implementations that don't actually get - * the spinlock for the common decrement/increment operations, but they - * still have to check that the operation is done semantically as if - * the spinlock had been taken (using a cmpxchg operation that covers - * both the lock and the count word, or using memory transactions, for - * example). - */ - -#include -#include - -#define USE_CMPXCHG_LOCKREF \ - (IS_ENABLED(CONFIG_ARCH_USE_CMPXCHG_LOCKREF) && \ - IS_ENABLED(CONFIG_SMP) && SPINLOCK_SIZE <= 4) - -struct lockref { - union { -#if USE_CMPXCHG_LOCKREF - aligned_u64 lock_count; -#endif - struct { - spinlock_t lock; - int count; - }; - }; -}; - -extern void lockref_get(struct lockref *); -extern int lockref_put_return(struct lockref *); -extern int lockref_get_not_zero(struct lockref *); -extern int lockref_get_or_lock(struct lockref *); -extern int lockref_put_or_lock(struct lockref *); - -extern void lockref_mark_dead(struct lockref *); -extern int lockref_get_not_dead(struct lockref *); - -/* Must be called under spinlock for reliable results */ -static inline int __lockref_is_dead(const struct lockref *l) -{ - return ((int)l->count < 0); -} - -#endif /* __LINUX_LOCKREF_H */ diff --git a/src/linux/include/linux/log2.h b/src/linux/include/linux/log2.h deleted file mode 100644 index fd7ff3d..0000000 --- a/src/linux/include/linux/log2.h +++ /dev/null @@ -1,208 +0,0 @@ -/* Integer base 2 logarithm calculation - * - * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _LINUX_LOG2_H -#define _LINUX_LOG2_H - -#include -#include - -/* - * deal with unrepresentable constant logarithms - */ -extern __attribute__((const, noreturn)) -int ____ilog2_NaN(void); - -/* - * non-constant log of base 2 calculators - * - the arch may override these in asm/bitops.h if they can be implemented - * more efficiently than using fls() and fls64() - * - the arch is not required to handle n==0 if implementing the fallback - */ -#ifndef CONFIG_ARCH_HAS_ILOG2_U32 -static inline __attribute__((const)) -int __ilog2_u32(u32 n) -{ - return fls(n) - 1; -} -#endif - -#ifndef CONFIG_ARCH_HAS_ILOG2_U64 -static inline __attribute__((const)) -int __ilog2_u64(u64 n) -{ - return fls64(n) - 1; -} -#endif - -/* - * Determine whether some value is a power of two, where zero is - * *not* considered a power of two. - */ - -static inline __attribute__((const)) -bool is_power_of_2(unsigned long n) -{ - return (n != 0 && ((n & (n - 1)) == 0)); -} - -/* - * round up to nearest power of two - */ -static inline __attribute__((const)) -unsigned long __roundup_pow_of_two(unsigned long n) -{ - return 1UL << fls_long(n - 1); -} - -/* - * round down to nearest power of two - */ -static inline __attribute__((const)) -unsigned long __rounddown_pow_of_two(unsigned long n) -{ - return 1UL << (fls_long(n) - 1); -} - -/** - * ilog2 - log of base 2 of 32-bit or a 64-bit unsigned value - * @n - parameter - * - * constant-capable log of base 2 calculation - * - this can be used to initialise global variables from constant data, hence - * the massive ternary operator construction - * - * selects the appropriately-sized optimised version depending on sizeof(n) - */ -#define ilog2(n) \ -( \ - __builtin_constant_p(n) ? ( \ - (n) < 1 ? ____ilog2_NaN() : \ - (n) & (1ULL << 63) ? 63 : \ - (n) & (1ULL << 62) ? 62 : \ - (n) & (1ULL << 61) ? 61 : \ - (n) & (1ULL << 60) ? 60 : \ - (n) & (1ULL << 59) ? 59 : \ - (n) & (1ULL << 58) ? 58 : \ - (n) & (1ULL << 57) ? 57 : \ - (n) & (1ULL << 56) ? 56 : \ - (n) & (1ULL << 55) ? 55 : \ - (n) & (1ULL << 54) ? 54 : \ - (n) & (1ULL << 53) ? 53 : \ - (n) & (1ULL << 52) ? 52 : \ - (n) & (1ULL << 51) ? 51 : \ - (n) & (1ULL << 50) ? 50 : \ - (n) & (1ULL << 49) ? 49 : \ - (n) & (1ULL << 48) ? 48 : \ - (n) & (1ULL << 47) ? 47 : \ - (n) & (1ULL << 46) ? 46 : \ - (n) & (1ULL << 45) ? 45 : \ - (n) & (1ULL << 44) ? 44 : \ - (n) & (1ULL << 43) ? 43 : \ - (n) & (1ULL << 42) ? 42 : \ - (n) & (1ULL << 41) ? 41 : \ - (n) & (1ULL << 40) ? 40 : \ - (n) & (1ULL << 39) ? 39 : \ - (n) & (1ULL << 38) ? 38 : \ - (n) & (1ULL << 37) ? 37 : \ - (n) & (1ULL << 36) ? 36 : \ - (n) & (1ULL << 35) ? 35 : \ - (n) & (1ULL << 34) ? 34 : \ - (n) & (1ULL << 33) ? 33 : \ - (n) & (1ULL << 32) ? 32 : \ - (n) & (1ULL << 31) ? 31 : \ - (n) & (1ULL << 30) ? 30 : \ - (n) & (1ULL << 29) ? 29 : \ - (n) & (1ULL << 28) ? 28 : \ - (n) & (1ULL << 27) ? 27 : \ - (n) & (1ULL << 26) ? 26 : \ - (n) & (1ULL << 25) ? 25 : \ - (n) & (1ULL << 24) ? 24 : \ - (n) & (1ULL << 23) ? 23 : \ - (n) & (1ULL << 22) ? 22 : \ - (n) & (1ULL << 21) ? 21 : \ - (n) & (1ULL << 20) ? 20 : \ - (n) & (1ULL << 19) ? 19 : \ - (n) & (1ULL << 18) ? 18 : \ - (n) & (1ULL << 17) ? 17 : \ - (n) & (1ULL << 16) ? 16 : \ - (n) & (1ULL << 15) ? 15 : \ - (n) & (1ULL << 14) ? 14 : \ - (n) & (1ULL << 13) ? 13 : \ - (n) & (1ULL << 12) ? 12 : \ - (n) & (1ULL << 11) ? 11 : \ - (n) & (1ULL << 10) ? 10 : \ - (n) & (1ULL << 9) ? 9 : \ - (n) & (1ULL << 8) ? 8 : \ - (n) & (1ULL << 7) ? 7 : \ - (n) & (1ULL << 6) ? 6 : \ - (n) & (1ULL << 5) ? 5 : \ - (n) & (1ULL << 4) ? 4 : \ - (n) & (1ULL << 3) ? 3 : \ - (n) & (1ULL << 2) ? 2 : \ - (n) & (1ULL << 1) ? 1 : \ - (n) & (1ULL << 0) ? 0 : \ - ____ilog2_NaN() \ - ) : \ - (sizeof(n) <= 4) ? \ - __ilog2_u32(n) : \ - __ilog2_u64(n) \ - ) - -/** - * roundup_pow_of_two - round the given value up to nearest power of two - * @n - parameter - * - * round the given value up to the nearest power of two - * - the result is undefined when n == 0 - * - this can be used to initialise global variables from constant data - */ -#define roundup_pow_of_two(n) \ -( \ - __builtin_constant_p(n) ? ( \ - (n == 1) ? 1 : \ - (1UL << (ilog2((n) - 1) + 1)) \ - ) : \ - __roundup_pow_of_two(n) \ - ) - -/** - * rounddown_pow_of_two - round the given value down to nearest power of two - * @n - parameter - * - * round the given value down to the nearest power of two - * - the result is undefined when n == 0 - * - this can be used to initialise global variables from constant data - */ -#define rounddown_pow_of_two(n) \ -( \ - __builtin_constant_p(n) ? ( \ - (1UL << ilog2(n))) : \ - __rounddown_pow_of_two(n) \ - ) - -/** - * order_base_2 - calculate the (rounded up) base 2 order of the argument - * @n: parameter - * - * The first few values calculated by this routine: - * ob2(0) = 0 - * ob2(1) = 0 - * ob2(2) = 1 - * ob2(3) = 2 - * ob2(4) = 2 - * ob2(5) = 3 - * ... and so on. - */ - -#define order_base_2(n) ilog2(roundup_pow_of_two(n)) - -#endif /* _LINUX_LOG2_H */ diff --git a/src/linux/include/linux/lsm_hooks.h b/src/linux/include/linux/lsm_hooks.h deleted file mode 100644 index 558adfa..0000000 --- a/src/linux/include/linux/lsm_hooks.h +++ /dev/null @@ -1,1937 +0,0 @@ -/* - * Linux Security Module interfaces - * - * Copyright (C) 2001 WireX Communications, Inc - * Copyright (C) 2001 Greg Kroah-Hartman - * Copyright (C) 2001 Networks Associates Technology, Inc - * Copyright (C) 2001 James Morris - * Copyright (C) 2001 Silicon Graphics, Inc. (Trust Technology Group) - * Copyright (C) 2015 Intel Corporation. - * Copyright (C) 2015 Casey Schaufler - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Due to this file being licensed under the GPL there is controversy over - * whether this permits you to write a module that #includes this file - * without placing your module under the GPL. Please consult a lawyer for - * advice before doing this. - * - */ - -#ifndef __LINUX_LSM_HOOKS_H -#define __LINUX_LSM_HOOKS_H - -#include -#include -#include - -/** - * Security hooks for program execution operations. - * - * @bprm_set_creds: - * Save security information in the bprm->security field, typically based - * on information about the bprm->file, for later use by the apply_creds - * hook. This hook may also optionally check permissions (e.g. for - * transitions between security domains). - * This hook may be called multiple times during a single execve, e.g. for - * interpreters. The hook can tell whether it has already been called by - * checking to see if @bprm->security is non-NULL. If so, then the hook - * may decide either to retain the security information saved earlier or - * to replace it. - * @bprm contains the linux_binprm structure. - * Return 0 if the hook is successful and permission is granted. - * @bprm_check_security: - * This hook mediates the point when a search for a binary handler will - * begin. It allows a check the @bprm->security value which is set in the - * preceding set_creds call. The primary difference from set_creds is - * that the argv list and envp list are reliably available in @bprm. This - * hook may be called multiple times during a single execve; and in each - * pass set_creds is called first. - * @bprm contains the linux_binprm structure. - * Return 0 if the hook is successful and permission is granted. - * @bprm_committing_creds: - * Prepare to install the new security attributes of a process being - * transformed by an execve operation, based on the old credentials - * pointed to by @current->cred and the information set in @bprm->cred by - * the bprm_set_creds hook. @bprm points to the linux_binprm structure. - * This hook is a good place to perform state changes on the process such - * as closing open file descriptors to which access will no longer be - * granted when the attributes are changed. This is called immediately - * before commit_creds(). - * @bprm_committed_creds: - * Tidy up after the installation of the new security attributes of a - * process being transformed by an execve operation. The new credentials - * have, by this point, been set to @current->cred. @bprm points to the - * linux_binprm structure. This hook is a good place to perform state - * changes on the process such as clearing out non-inheritable signal - * state. This is called immediately after commit_creds(). - * @bprm_secureexec: - * Return a boolean value (0 or 1) indicating whether a "secure exec" - * is required. The flag is passed in the auxiliary table - * on the initial stack to the ELF interpreter to indicate whether libc - * should enable secure mode. - * @bprm contains the linux_binprm structure. - * - * Security hooks for filesystem operations. - * - * @sb_alloc_security: - * Allocate and attach a security structure to the sb->s_security field. - * The s_security field is initialized to NULL when the structure is - * allocated. - * @sb contains the super_block structure to be modified. - * Return 0 if operation was successful. - * @sb_free_security: - * Deallocate and clear the sb->s_security field. - * @sb contains the super_block structure to be modified. - * @sb_statfs: - * Check permission before obtaining filesystem statistics for the @mnt - * mountpoint. - * @dentry is a handle on the superblock for the filesystem. - * Return 0 if permission is granted. - * @sb_mount: - * Check permission before an object specified by @dev_name is mounted on - * the mount point named by @nd. For an ordinary mount, @dev_name - * identifies a device if the file system type requires a device. For a - * remount (@flags & MS_REMOUNT), @dev_name is irrelevant. For a - * loopback/bind mount (@flags & MS_BIND), @dev_name identifies the - * pathname of the object being mounted. - * @dev_name contains the name for object being mounted. - * @path contains the path for mount point object. - * @type contains the filesystem type. - * @flags contains the mount flags. - * @data contains the filesystem-specific data. - * Return 0 if permission is granted. - * @sb_copy_data: - * Allow mount option data to be copied prior to parsing by the filesystem, - * so that the security module can extract security-specific mount - * options cleanly (a filesystem may modify the data e.g. with strsep()). - * This also allows the original mount data to be stripped of security- - * specific options to avoid having to make filesystems aware of them. - * @type the type of filesystem being mounted. - * @orig the original mount data copied from userspace. - * @copy copied data which will be passed to the security module. - * Returns 0 if the copy was successful. - * @sb_remount: - * Extracts security system specific mount options and verifies no changes - * are being made to those options. - * @sb superblock being remounted - * @data contains the filesystem-specific data. - * Return 0 if permission is granted. - * @sb_umount: - * Check permission before the @mnt file system is unmounted. - * @mnt contains the mounted file system. - * @flags contains the unmount flags, e.g. MNT_FORCE. - * Return 0 if permission is granted. - * @sb_pivotroot: - * Check permission before pivoting the root filesystem. - * @old_path contains the path for the new location of the - * current root (put_old). - * @new_path contains the path for the new root (new_root). - * Return 0 if permission is granted. - * @sb_set_mnt_opts: - * Set the security relevant mount options used for a superblock - * @sb the superblock to set security mount options for - * @opts binary data structure containing all lsm mount data - * @sb_clone_mnt_opts: - * Copy all security options from a given superblock to another - * @oldsb old superblock which contain information to clone - * @newsb new superblock which needs filled in - * @sb_parse_opts_str: - * Parse a string of security data filling in the opts structure - * @options string containing all mount options known by the LSM - * @opts binary data structure usable by the LSM - * @dentry_init_security: - * Compute a context for a dentry as the inode is not yet available - * since NFSv4 has no label backed by an EA anyway. - * @dentry dentry to use in calculating the context. - * @mode mode used to determine resource type. - * @name name of the last path component used to create file - * @ctx pointer to place the pointer to the resulting context in. - * @ctxlen point to place the length of the resulting context. - * @dentry_create_files_as: - * Compute a context for a dentry as the inode is not yet available - * and set that context in passed in creds so that new files are - * created using that context. Context is calculated using the - * passed in creds and not the creds of the caller. - * @dentry dentry to use in calculating the context. - * @mode mode used to determine resource type. - * @name name of the last path component used to create file - * @old creds which should be used for context calculation - * @new creds to modify - * - * - * Security hooks for inode operations. - * - * @inode_alloc_security: - * Allocate and attach a security structure to @inode->i_security. The - * i_security field is initialized to NULL when the inode structure is - * allocated. - * @inode contains the inode structure. - * Return 0 if operation was successful. - * @inode_free_security: - * @inode contains the inode structure. - * Deallocate the inode security structure and set @inode->i_security to - * NULL. - * @inode_init_security: - * Obtain the security attribute name suffix and value to set on a newly - * created inode and set up the incore security field for the new inode. - * This hook is called by the fs code as part of the inode creation - * transaction and provides for atomic labeling of the inode, unlike - * the post_create/mkdir/... hooks called by the VFS. The hook function - * is expected to allocate the name and value via kmalloc, with the caller - * being responsible for calling kfree after using them. - * If the security module does not use security attributes or does - * not wish to put a security attribute on this particular inode, - * then it should return -EOPNOTSUPP to skip this processing. - * @inode contains the inode structure of the newly created inode. - * @dir contains the inode structure of the parent directory. - * @qstr contains the last path component of the new object - * @name will be set to the allocated name suffix (e.g. selinux). - * @value will be set to the allocated attribute value. - * @len will be set to the length of the value. - * Returns 0 if @name and @value have been successfully set, - * -EOPNOTSUPP if no security attribute is needed, or - * -ENOMEM on memory allocation failure. - * @inode_create: - * Check permission to create a regular file. - * @dir contains inode structure of the parent of the new file. - * @dentry contains the dentry structure for the file to be created. - * @mode contains the file mode of the file to be created. - * Return 0 if permission is granted. - * @inode_link: - * Check permission before creating a new hard link to a file. - * @old_dentry contains the dentry structure for an existing - * link to the file. - * @dir contains the inode structure of the parent directory - * of the new link. - * @new_dentry contains the dentry structure for the new link. - * Return 0 if permission is granted. - * @path_link: - * Check permission before creating a new hard link to a file. - * @old_dentry contains the dentry structure for an existing link - * to the file. - * @new_dir contains the path structure of the parent directory of - * the new link. - * @new_dentry contains the dentry structure for the new link. - * Return 0 if permission is granted. - * @inode_unlink: - * Check the permission to remove a hard link to a file. - * @dir contains the inode structure of parent directory of the file. - * @dentry contains the dentry structure for file to be unlinked. - * Return 0 if permission is granted. - * @path_unlink: - * Check the permission to remove a hard link to a file. - * @dir contains the path structure of parent directory of the file. - * @dentry contains the dentry structure for file to be unlinked. - * Return 0 if permission is granted. - * @inode_symlink: - * Check the permission to create a symbolic link to a file. - * @dir contains the inode structure of parent directory of - * the symbolic link. - * @dentry contains the dentry structure of the symbolic link. - * @old_name contains the pathname of file. - * Return 0 if permission is granted. - * @path_symlink: - * Check the permission to create a symbolic link to a file. - * @dir contains the path structure of parent directory of - * the symbolic link. - * @dentry contains the dentry structure of the symbolic link. - * @old_name contains the pathname of file. - * Return 0 if permission is granted. - * @inode_mkdir: - * Check permissions to create a new directory in the existing directory - * associated with inode structure @dir. - * @dir contains the inode structure of parent of the directory - * to be created. - * @dentry contains the dentry structure of new directory. - * @mode contains the mode of new directory. - * Return 0 if permission is granted. - * @path_mkdir: - * Check permissions to create a new directory in the existing directory - * associated with path structure @path. - * @dir contains the path structure of parent of the directory - * to be created. - * @dentry contains the dentry structure of new directory. - * @mode contains the mode of new directory. - * Return 0 if permission is granted. - * @inode_rmdir: - * Check the permission to remove a directory. - * @dir contains the inode structure of parent of the directory - * to be removed. - * @dentry contains the dentry structure of directory to be removed. - * Return 0 if permission is granted. - * @path_rmdir: - * Check the permission to remove a directory. - * @dir contains the path structure of parent of the directory to be - * removed. - * @dentry contains the dentry structure of directory to be removed. - * Return 0 if permission is granted. - * @inode_mknod: - * Check permissions when creating a special file (or a socket or a fifo - * file created via the mknod system call). Note that if mknod operation - * is being done for a regular file, then the create hook will be called - * and not this hook. - * @dir contains the inode structure of parent of the new file. - * @dentry contains the dentry structure of the new file. - * @mode contains the mode of the new file. - * @dev contains the device number. - * Return 0 if permission is granted. - * @path_mknod: - * Check permissions when creating a file. Note that this hook is called - * even if mknod operation is being done for a regular file. - * @dir contains the path structure of parent of the new file. - * @dentry contains the dentry structure of the new file. - * @mode contains the mode of the new file. - * @dev contains the undecoded device number. Use new_decode_dev() to get - * the decoded device number. - * Return 0 if permission is granted. - * @inode_rename: - * Check for permission to rename a file or directory. - * @old_dir contains the inode structure for parent of the old link. - * @old_dentry contains the dentry structure of the old link. - * @new_dir contains the inode structure for parent of the new link. - * @new_dentry contains the dentry structure of the new link. - * Return 0 if permission is granted. - * @path_rename: - * Check for permission to rename a file or directory. - * @old_dir contains the path structure for parent of the old link. - * @old_dentry contains the dentry structure of the old link. - * @new_dir contains the path structure for parent of the new link. - * @new_dentry contains the dentry structure of the new link. - * Return 0 if permission is granted. - * @path_chmod: - * Check for permission to change DAC's permission of a file or directory. - * @dentry contains the dentry structure. - * @mnt contains the vfsmnt structure. - * @mode contains DAC's mode. - * Return 0 if permission is granted. - * @path_chown: - * Check for permission to change owner/group of a file or directory. - * @path contains the path structure. - * @uid contains new owner's ID. - * @gid contains new group's ID. - * Return 0 if permission is granted. - * @path_chroot: - * Check for permission to change root directory. - * @path contains the path structure. - * Return 0 if permission is granted. - * @inode_readlink: - * Check the permission to read the symbolic link. - * @dentry contains the dentry structure for the file link. - * Return 0 if permission is granted. - * @inode_follow_link: - * Check permission to follow a symbolic link when looking up a pathname. - * @dentry contains the dentry structure for the link. - * @inode contains the inode, which itself is not stable in RCU-walk - * @rcu indicates whether we are in RCU-walk mode. - * Return 0 if permission is granted. - * @inode_permission: - * Check permission before accessing an inode. This hook is called by the - * existing Linux permission function, so a security module can use it to - * provide additional checking for existing Linux permission checks. - * Notice that this hook is called when a file is opened (as well as many - * other operations), whereas the file_security_ops permission hook is - * called when the actual read/write operations are performed. - * @inode contains the inode structure to check. - * @mask contains the permission mask. - * Return 0 if permission is granted. - * @inode_setattr: - * Check permission before setting file attributes. Note that the kernel - * call to notify_change is performed from several locations, whenever - * file attributes change (such as when a file is truncated, chown/chmod - * operations, transferring disk quotas, etc). - * @dentry contains the dentry structure for the file. - * @attr is the iattr structure containing the new file attributes. - * Return 0 if permission is granted. - * @path_truncate: - * Check permission before truncating a file. - * @path contains the path structure for the file. - * Return 0 if permission is granted. - * @inode_getattr: - * Check permission before obtaining file attributes. - * @mnt is the vfsmount where the dentry was looked up - * @dentry contains the dentry structure for the file. - * Return 0 if permission is granted. - * @inode_setxattr: - * Check permission before setting the extended attributes - * @value identified by @name for @dentry. - * Return 0 if permission is granted. - * @inode_post_setxattr: - * Update inode security field after successful setxattr operation. - * @value identified by @name for @dentry. - * @inode_getxattr: - * Check permission before obtaining the extended attributes - * identified by @name for @dentry. - * Return 0 if permission is granted. - * @inode_listxattr: - * Check permission before obtaining the list of extended attribute - * names for @dentry. - * Return 0 if permission is granted. - * @inode_removexattr: - * Check permission before removing the extended attribute - * identified by @name for @dentry. - * Return 0 if permission is granted. - * @inode_getsecurity: - * Retrieve a copy of the extended attribute representation of the - * security label associated with @name for @inode via @buffer. Note that - * @name is the remainder of the attribute name after the security prefix - * has been removed. @alloc is used to specify of the call should return a - * value via the buffer or just the value length Return size of buffer on - * success. - * @inode_setsecurity: - * Set the security label associated with @name for @inode from the - * extended attribute value @value. @size indicates the size of the - * @value in bytes. @flags may be XATTR_CREATE, XATTR_REPLACE, or 0. - * Note that @name is the remainder of the attribute name after the - * security. prefix has been removed. - * Return 0 on success. - * @inode_listsecurity: - * Copy the extended attribute names for the security labels - * associated with @inode into @buffer. The maximum size of @buffer - * is specified by @buffer_size. @buffer may be NULL to request - * the size of the buffer required. - * Returns number of bytes used/required on success. - * @inode_need_killpriv: - * Called when an inode has been changed. - * @dentry is the dentry being changed. - * Return <0 on error to abort the inode change operation. - * Return 0 if inode_killpriv does not need to be called. - * Return >0 if inode_killpriv does need to be called. - * @inode_killpriv: - * The setuid bit is being removed. Remove similar security labels. - * Called with the dentry->d_inode->i_mutex held. - * @dentry is the dentry being changed. - * Return 0 on success. If error is returned, then the operation - * causing setuid bit removal is failed. - * @inode_getsecid: - * Get the secid associated with the node. - * @inode contains a pointer to the inode. - * @secid contains a pointer to the location where result will be saved. - * In case of failure, @secid will be set to zero. - * @inode_copy_up: - * A file is about to be copied up from lower layer to upper layer of - * overlay filesystem. Security module can prepare a set of new creds - * and modify as need be and return new creds. Caller will switch to - * new creds temporarily to create new file and release newly allocated - * creds. - * @src indicates the union dentry of file that is being copied up. - * @new pointer to pointer to return newly allocated creds. - * Returns 0 on success or a negative error code on error. - * @inode_copy_up_xattr: - * Filter the xattrs being copied up when a unioned file is copied - * up from a lower layer to the union/overlay layer. - * @name indicates the name of the xattr. - * Returns 0 to accept the xattr, 1 to discard the xattr, -EOPNOTSUPP if - * security module does not know about attribute or a negative error code - * to abort the copy up. Note that the caller is responsible for reading - * and writing the xattrs as this hook is merely a filter. - * - * Security hooks for file operations - * - * @file_permission: - * Check file permissions before accessing an open file. This hook is - * called by various operations that read or write files. A security - * module can use this hook to perform additional checking on these - * operations, e.g. to revalidate permissions on use to support privilege - * bracketing or policy changes. Notice that this hook is used when the - * actual read/write operations are performed, whereas the - * inode_security_ops hook is called when a file is opened (as well as - * many other operations). - * Caveat: Although this hook can be used to revalidate permissions for - * various system call operations that read or write files, it does not - * address the revalidation of permissions for memory-mapped files. - * Security modules must handle this separately if they need such - * revalidation. - * @file contains the file structure being accessed. - * @mask contains the requested permissions. - * Return 0 if permission is granted. - * @file_alloc_security: - * Allocate and attach a security structure to the file->f_security field. - * The security field is initialized to NULL when the structure is first - * created. - * @file contains the file structure to secure. - * Return 0 if the hook is successful and permission is granted. - * @file_free_security: - * Deallocate and free any security structures stored in file->f_security. - * @file contains the file structure being modified. - * @file_ioctl: - * @file contains the file structure. - * @cmd contains the operation to perform. - * @arg contains the operational arguments. - * Check permission for an ioctl operation on @file. Note that @arg - * sometimes represents a user space pointer; in other cases, it may be a - * simple integer value. When @arg represents a user space pointer, it - * should never be used by the security module. - * Return 0 if permission is granted. - * @mmap_addr : - * Check permissions for a mmap operation at @addr. - * @addr contains virtual address that will be used for the operation. - * Return 0 if permission is granted. - * @mmap_file : - * Check permissions for a mmap operation. The @file may be NULL, e.g. - * if mapping anonymous memory. - * @file contains the file structure for file to map (may be NULL). - * @reqprot contains the protection requested by the application. - * @prot contains the protection that will be applied by the kernel. - * @flags contains the operational flags. - * Return 0 if permission is granted. - * @file_mprotect: - * Check permissions before changing memory access permissions. - * @vma contains the memory region to modify. - * @reqprot contains the protection requested by the application. - * @prot contains the protection that will be applied by the kernel. - * Return 0 if permission is granted. - * @file_lock: - * Check permission before performing file locking operations. - * Note: this hook mediates both flock and fcntl style locks. - * @file contains the file structure. - * @cmd contains the posix-translated lock operation to perform - * (e.g. F_RDLCK, F_WRLCK). - * Return 0 if permission is granted. - * @file_fcntl: - * Check permission before allowing the file operation specified by @cmd - * from being performed on the file @file. Note that @arg sometimes - * represents a user space pointer; in other cases, it may be a simple - * integer value. When @arg represents a user space pointer, it should - * never be used by the security module. - * @file contains the file structure. - * @cmd contains the operation to be performed. - * @arg contains the operational arguments. - * Return 0 if permission is granted. - * @file_set_fowner: - * Save owner security information (typically from current->security) in - * file->f_security for later use by the send_sigiotask hook. - * @file contains the file structure to update. - * Return 0 on success. - * @file_send_sigiotask: - * Check permission for the file owner @fown to send SIGIO or SIGURG to the - * process @tsk. Note that this hook is sometimes called from interrupt. - * Note that the fown_struct, @fown, is never outside the context of a - * struct file, so the file structure (and associated security information) - * can always be obtained: - * container_of(fown, struct file, f_owner) - * @tsk contains the structure of task receiving signal. - * @fown contains the file owner information. - * @sig is the signal that will be sent. When 0, kernel sends SIGIO. - * Return 0 if permission is granted. - * @file_receive: - * This hook allows security modules to control the ability of a process - * to receive an open file descriptor via socket IPC. - * @file contains the file structure being received. - * Return 0 if permission is granted. - * @file_open - * Save open-time permission checking state for later use upon - * file_permission, and recheck access if anything has changed - * since inode_permission. - * - * Security hooks for task operations. - * - * @task_create: - * Check permission before creating a child process. See the clone(2) - * manual page for definitions of the @clone_flags. - * @clone_flags contains the flags indicating what should be shared. - * Return 0 if permission is granted. - * @task_free: - * @task task being freed - * Handle release of task-related resources. (Note that this can be called - * from interrupt context.) - * @cred_alloc_blank: - * @cred points to the credentials. - * @gfp indicates the atomicity of any memory allocations. - * Only allocate sufficient memory and attach to @cred such that - * cred_transfer() will not get ENOMEM. - * @cred_free: - * @cred points to the credentials. - * Deallocate and clear the cred->security field in a set of credentials. - * @cred_prepare: - * @new points to the new credentials. - * @old points to the original credentials. - * @gfp indicates the atomicity of any memory allocations. - * Prepare a new set of credentials by copying the data from the old set. - * @cred_transfer: - * @new points to the new credentials. - * @old points to the original credentials. - * Transfer data from original creds to new creds - * @kernel_act_as: - * Set the credentials for a kernel service to act as (subjective context). - * @new points to the credentials to be modified. - * @secid specifies the security ID to be set - * The current task must be the one that nominated @secid. - * Return 0 if successful. - * @kernel_create_files_as: - * Set the file creation context in a set of credentials to be the same as - * the objective context of the specified inode. - * @new points to the credentials to be modified. - * @inode points to the inode to use as a reference. - * The current task must be the one that nominated @inode. - * Return 0 if successful. - * @kernel_module_request: - * Ability to trigger the kernel to automatically upcall to userspace for - * userspace to load a kernel module with the given name. - * @kmod_name name of the module requested by the kernel - * Return 0 if successful. - * @kernel_read_file: - * Read a file specified by userspace. - * @file contains the file structure pointing to the file being read - * by the kernel. - * @id kernel read file identifier - * Return 0 if permission is granted. - * @kernel_post_read_file: - * Read a file specified by userspace. - * @file contains the file structure pointing to the file being read - * by the kernel. - * @buf pointer to buffer containing the file contents. - * @size length of the file contents. - * @id kernel read file identifier - * Return 0 if permission is granted. - * @task_fix_setuid: - * Update the module's state after setting one or more of the user - * identity attributes of the current process. The @flags parameter - * indicates which of the set*uid system calls invoked this hook. If - * @new is the set of credentials that will be installed. Modifications - * should be made to this rather than to @current->cred. - * @old is the set of credentials that are being replaces - * @flags contains one of the LSM_SETID_* values. - * Return 0 on success. - * @task_setpgid: - * Check permission before setting the process group identifier of the - * process @p to @pgid. - * @p contains the task_struct for process being modified. - * @pgid contains the new pgid. - * Return 0 if permission is granted. - * @task_getpgid: - * Check permission before getting the process group identifier of the - * process @p. - * @p contains the task_struct for the process. - * Return 0 if permission is granted. - * @task_getsid: - * Check permission before getting the session identifier of the process - * @p. - * @p contains the task_struct for the process. - * Return 0 if permission is granted. - * @task_getsecid: - * Retrieve the security identifier of the process @p. - * @p contains the task_struct for the process and place is into @secid. - * In case of failure, @secid will be set to zero. - * - * @task_setnice: - * Check permission before setting the nice value of @p to @nice. - * @p contains the task_struct of process. - * @nice contains the new nice value. - * Return 0 if permission is granted. - * @task_setioprio - * Check permission before setting the ioprio value of @p to @ioprio. - * @p contains the task_struct of process. - * @ioprio contains the new ioprio value - * Return 0 if permission is granted. - * @task_getioprio - * Check permission before getting the ioprio value of @p. - * @p contains the task_struct of process. - * Return 0 if permission is granted. - * @task_setrlimit: - * Check permission before setting the resource limits of the current - * process for @resource to @new_rlim. The old resource limit values can - * be examined by dereferencing (current->signal->rlim + resource). - * @resource contains the resource whose limit is being set. - * @new_rlim contains the new limits for @resource. - * Return 0 if permission is granted. - * @task_setscheduler: - * Check permission before setting scheduling policy and/or parameters of - * process @p based on @policy and @lp. - * @p contains the task_struct for process. - * @policy contains the scheduling policy. - * @lp contains the scheduling parameters. - * Return 0 if permission is granted. - * @task_getscheduler: - * Check permission before obtaining scheduling information for process - * @p. - * @p contains the task_struct for process. - * Return 0 if permission is granted. - * @task_movememory - * Check permission before moving memory owned by process @p. - * @p contains the task_struct for process. - * Return 0 if permission is granted. - * @task_kill: - * Check permission before sending signal @sig to @p. @info can be NULL, - * the constant 1, or a pointer to a siginfo structure. If @info is 1 or - * SI_FROMKERNEL(info) is true, then the signal should be viewed as coming - * from the kernel and should typically be permitted. - * SIGIO signals are handled separately by the send_sigiotask hook in - * file_security_ops. - * @p contains the task_struct for process. - * @info contains the signal information. - * @sig contains the signal value. - * @secid contains the sid of the process where the signal originated - * Return 0 if permission is granted. - * @task_wait: - * Check permission before allowing a process to reap a child process @p - * and collect its status information. - * @p contains the task_struct for process. - * Return 0 if permission is granted. - * @task_prctl: - * Check permission before performing a process control operation on the - * current process. - * @option contains the operation. - * @arg2 contains a argument. - * @arg3 contains a argument. - * @arg4 contains a argument. - * @arg5 contains a argument. - * Return -ENOSYS if no-one wanted to handle this op, any other value to - * cause prctl() to return immediately with that value. - * @task_to_inode: - * Set the security attributes for an inode based on an associated task's - * security attributes, e.g. for /proc/pid inodes. - * @p contains the task_struct for the task. - * @inode contains the inode structure for the inode. - * - * Security hooks for Netlink messaging. - * - * @netlink_send: - * Save security information for a netlink message so that permission - * checking can be performed when the message is processed. The security - * information can be saved using the eff_cap field of the - * netlink_skb_parms structure. Also may be used to provide fine - * grained control over message transmission. - * @sk associated sock of task sending the message. - * @skb contains the sk_buff structure for the netlink message. - * Return 0 if the information was successfully saved and message - * is allowed to be transmitted. - * - * Security hooks for Unix domain networking. - * - * @unix_stream_connect: - * Check permissions before establishing a Unix domain stream connection - * between @sock and @other. - * @sock contains the sock structure. - * @other contains the peer sock structure. - * @newsk contains the new sock structure. - * Return 0 if permission is granted. - * @unix_may_send: - * Check permissions before connecting or sending datagrams from @sock to - * @other. - * @sock contains the socket structure. - * @other contains the peer socket structure. - * Return 0 if permission is granted. - * - * The @unix_stream_connect and @unix_may_send hooks were necessary because - * Linux provides an alternative to the conventional file name space for Unix - * domain sockets. Whereas binding and connecting to sockets in the file name - * space is mediated by the typical file permissions (and caught by the mknod - * and permission hooks in inode_security_ops), binding and connecting to - * sockets in the abstract name space is completely unmediated. Sufficient - * control of Unix domain sockets in the abstract name space isn't possible - * using only the socket layer hooks, since we need to know the actual target - * socket, which is not looked up until we are inside the af_unix code. - * - * Security hooks for socket operations. - * - * @socket_create: - * Check permissions prior to creating a new socket. - * @family contains the requested protocol family. - * @type contains the requested communications type. - * @protocol contains the requested protocol. - * @kern set to 1 if a kernel socket. - * Return 0 if permission is granted. - * @socket_post_create: - * This hook allows a module to update or allocate a per-socket security - * structure. Note that the security field was not added directly to the - * socket structure, but rather, the socket security information is stored - * in the associated inode. Typically, the inode alloc_security hook will - * allocate and and attach security information to - * sock->inode->i_security. This hook may be used to update the - * sock->inode->i_security field with additional information that wasn't - * available when the inode was allocated. - * @sock contains the newly created socket structure. - * @family contains the requested protocol family. - * @type contains the requested communications type. - * @protocol contains the requested protocol. - * @kern set to 1 if a kernel socket. - * @socket_bind: - * Check permission before socket protocol layer bind operation is - * performed and the socket @sock is bound to the address specified in the - * @address parameter. - * @sock contains the socket structure. - * @address contains the address to bind to. - * @addrlen contains the length of address. - * Return 0 if permission is granted. - * @socket_connect: - * Check permission before socket protocol layer connect operation - * attempts to connect socket @sock to a remote address, @address. - * @sock contains the socket structure. - * @address contains the address of remote endpoint. - * @addrlen contains the length of address. - * Return 0 if permission is granted. - * @socket_listen: - * Check permission before socket protocol layer listen operation. - * @sock contains the socket structure. - * @backlog contains the maximum length for the pending connection queue. - * Return 0 if permission is granted. - * @socket_accept: - * Check permission before accepting a new connection. Note that the new - * socket, @newsock, has been created and some information copied to it, - * but the accept operation has not actually been performed. - * @sock contains the listening socket structure. - * @newsock contains the newly created server socket for connection. - * Return 0 if permission is granted. - * @socket_sendmsg: - * Check permission before transmitting a message to another socket. - * @sock contains the socket structure. - * @msg contains the message to be transmitted. - * @size contains the size of message. - * Return 0 if permission is granted. - * @socket_recvmsg: - * Check permission before receiving a message from a socket. - * @sock contains the socket structure. - * @msg contains the message structure. - * @size contains the size of message structure. - * @flags contains the operational flags. - * Return 0 if permission is granted. - * @socket_getsockname: - * Check permission before the local address (name) of the socket object - * @sock is retrieved. - * @sock contains the socket structure. - * Return 0 if permission is granted. - * @socket_getpeername: - * Check permission before the remote address (name) of a socket object - * @sock is retrieved. - * @sock contains the socket structure. - * Return 0 if permission is granted. - * @socket_getsockopt: - * Check permissions before retrieving the options associated with socket - * @sock. - * @sock contains the socket structure. - * @level contains the protocol level to retrieve option from. - * @optname contains the name of option to retrieve. - * Return 0 if permission is granted. - * @socket_setsockopt: - * Check permissions before setting the options associated with socket - * @sock. - * @sock contains the socket structure. - * @level contains the protocol level to set options for. - * @optname contains the name of the option to set. - * Return 0 if permission is granted. - * @socket_shutdown: - * Checks permission before all or part of a connection on the socket - * @sock is shut down. - * @sock contains the socket structure. - * @how contains the flag indicating how future sends and receives - * are handled. - * Return 0 if permission is granted. - * @socket_sock_rcv_skb: - * Check permissions on incoming network packets. This hook is distinct - * from Netfilter's IP input hooks since it is the first time that the - * incoming sk_buff @skb has been associated with a particular socket, @sk. - * Must not sleep inside this hook because some callers hold spinlocks. - * @sk contains the sock (not socket) associated with the incoming sk_buff. - * @skb contains the incoming network data. - * @socket_getpeersec_stream: - * This hook allows the security module to provide peer socket security - * state for unix or connected tcp sockets to userspace via getsockopt - * SO_GETPEERSEC. For tcp sockets this can be meaningful if the - * socket is associated with an ipsec SA. - * @sock is the local socket. - * @optval userspace memory where the security state is to be copied. - * @optlen userspace int where the module should copy the actual length - * of the security state. - * @len as input is the maximum length to copy to userspace provided - * by the caller. - * Return 0 if all is well, otherwise, typical getsockopt return - * values. - * @socket_getpeersec_dgram: - * This hook allows the security module to provide peer socket security - * state for udp sockets on a per-packet basis to userspace via - * getsockopt SO_GETPEERSEC. The application must first have indicated - * the IP_PASSSEC option via getsockopt. It can then retrieve the - * security state returned by this hook for a packet via the SCM_SECURITY - * ancillary message type. - * @skb is the skbuff for the packet being queried - * @secdata is a pointer to a buffer in which to copy the security data - * @seclen is the maximum length for @secdata - * Return 0 on success, error on failure. - * @sk_alloc_security: - * Allocate and attach a security structure to the sk->sk_security field, - * which is used to copy security attributes between local stream sockets. - * @sk_free_security: - * Deallocate security structure. - * @sk_clone_security: - * Clone/copy security structure. - * @sk_getsecid: - * Retrieve the LSM-specific secid for the sock to enable caching - * of network authorizations. - * @sock_graft: - * Sets the socket's isec sid to the sock's sid. - * @inet_conn_request: - * Sets the openreq's sid to socket's sid with MLS portion taken - * from peer sid. - * @inet_csk_clone: - * Sets the new child socket's sid to the openreq sid. - * @inet_conn_established: - * Sets the connection's peersid to the secmark on skb. - * @secmark_relabel_packet: - * check if the process should be allowed to relabel packets to - * the given secid - * @security_secmark_refcount_inc - * tells the LSM to increment the number of secmark labeling rules loaded - * @security_secmark_refcount_dec - * tells the LSM to decrement the number of secmark labeling rules loaded - * @req_classify_flow: - * Sets the flow's sid to the openreq sid. - * @tun_dev_alloc_security: - * This hook allows a module to allocate a security structure for a TUN - * device. - * @security pointer to a security structure pointer. - * Returns a zero on success, negative values on failure. - * @tun_dev_free_security: - * This hook allows a module to free the security structure for a TUN - * device. - * @security pointer to the TUN device's security structure - * @tun_dev_create: - * Check permissions prior to creating a new TUN device. - * @tun_dev_attach_queue: - * Check permissions prior to attaching to a TUN device queue. - * @security pointer to the TUN device's security structure. - * @tun_dev_attach: - * This hook can be used by the module to update any security state - * associated with the TUN device's sock structure. - * @sk contains the existing sock structure. - * @security pointer to the TUN device's security structure. - * @tun_dev_open: - * This hook can be used by the module to update any security state - * associated with the TUN device's security structure. - * @security pointer to the TUN devices's security structure. - * - * Security hooks for XFRM operations. - * - * @xfrm_policy_alloc_security: - * @ctxp is a pointer to the xfrm_sec_ctx being added to Security Policy - * Database used by the XFRM system. - * @sec_ctx contains the security context information being provided by - * the user-level policy update program (e.g., setkey). - * Allocate a security structure to the xp->security field; the security - * field is initialized to NULL when the xfrm_policy is allocated. - * Return 0 if operation was successful (memory to allocate, legal context) - * @gfp is to specify the context for the allocation - * @xfrm_policy_clone_security: - * @old_ctx contains an existing xfrm_sec_ctx. - * @new_ctxp contains a new xfrm_sec_ctx being cloned from old. - * Allocate a security structure in new_ctxp that contains the - * information from the old_ctx structure. - * Return 0 if operation was successful (memory to allocate). - * @xfrm_policy_free_security: - * @ctx contains the xfrm_sec_ctx - * Deallocate xp->security. - * @xfrm_policy_delete_security: - * @ctx contains the xfrm_sec_ctx. - * Authorize deletion of xp->security. - * @xfrm_state_alloc: - * @x contains the xfrm_state being added to the Security Association - * Database by the XFRM system. - * @sec_ctx contains the security context information being provided by - * the user-level SA generation program (e.g., setkey or racoon). - * Allocate a security structure to the x->security field; the security - * field is initialized to NULL when the xfrm_state is allocated. Set the - * context to correspond to sec_ctx. Return 0 if operation was successful - * (memory to allocate, legal context). - * @xfrm_state_alloc_acquire: - * @x contains the xfrm_state being added to the Security Association - * Database by the XFRM system. - * @polsec contains the policy's security context. - * @secid contains the secid from which to take the mls portion of the - * context. - * Allocate a security structure to the x->security field; the security - * field is initialized to NULL when the xfrm_state is allocated. Set the - * context to correspond to secid. Return 0 if operation was successful - * (memory to allocate, legal context). - * @xfrm_state_free_security: - * @x contains the xfrm_state. - * Deallocate x->security. - * @xfrm_state_delete_security: - * @x contains the xfrm_state. - * Authorize deletion of x->security. - * @xfrm_policy_lookup: - * @ctx contains the xfrm_sec_ctx for which the access control is being - * checked. - * @fl_secid contains the flow security label that is used to authorize - * access to the policy xp. - * @dir contains the direction of the flow (input or output). - * Check permission when a flow selects a xfrm_policy for processing - * XFRMs on a packet. The hook is called when selecting either a - * per-socket policy or a generic xfrm policy. - * Return 0 if permission is granted, -ESRCH otherwise, or -errno - * on other errors. - * @xfrm_state_pol_flow_match: - * @x contains the state to match. - * @xp contains the policy to check for a match. - * @fl contains the flow to check for a match. - * Return 1 if there is a match. - * @xfrm_decode_session: - * @skb points to skb to decode. - * @secid points to the flow key secid to set. - * @ckall says if all xfrms used should be checked for same secid. - * Return 0 if ckall is zero or all xfrms used have the same secid. - * - * Security hooks affecting all Key Management operations - * - * @key_alloc: - * Permit allocation of a key and assign security data. Note that key does - * not have a serial number assigned at this point. - * @key points to the key. - * @flags is the allocation flags - * Return 0 if permission is granted, -ve error otherwise. - * @key_free: - * Notification of destruction; free security data. - * @key points to the key. - * No return value. - * @key_permission: - * See whether a specific operational right is granted to a process on a - * key. - * @key_ref refers to the key (key pointer + possession attribute bit). - * @cred points to the credentials to provide the context against which to - * evaluate the security data on the key. - * @perm describes the combination of permissions required of this key. - * Return 0 if permission is granted, -ve error otherwise. - * @key_getsecurity: - * Get a textual representation of the security context attached to a key - * for the purposes of honouring KEYCTL_GETSECURITY. This function - * allocates the storage for the NUL-terminated string and the caller - * should free it. - * @key points to the key to be queried. - * @_buffer points to a pointer that should be set to point to the - * resulting string (if no label or an error occurs). - * Return the length of the string (including terminating NUL) or -ve if - * an error. - * May also return 0 (and a NULL buffer pointer) if there is no label. - * - * Security hooks affecting all System V IPC operations. - * - * @ipc_permission: - * Check permissions for access to IPC - * @ipcp contains the kernel IPC permission structure - * @flag contains the desired (requested) permission set - * Return 0 if permission is granted. - * @ipc_getsecid: - * Get the secid associated with the ipc object. - * @ipcp contains the kernel IPC permission structure. - * @secid contains a pointer to the location where result will be saved. - * In case of failure, @secid will be set to zero. - * - * Security hooks for individual messages held in System V IPC message queues - * @msg_msg_alloc_security: - * Allocate and attach a security structure to the msg->security field. - * The security field is initialized to NULL when the structure is first - * created. - * @msg contains the message structure to be modified. - * Return 0 if operation was successful and permission is granted. - * @msg_msg_free_security: - * Deallocate the security structure for this message. - * @msg contains the message structure to be modified. - * - * Security hooks for System V IPC Message Queues - * - * @msg_queue_alloc_security: - * Allocate and attach a security structure to the - * msq->q_perm.security field. The security field is initialized to - * NULL when the structure is first created. - * @msq contains the message queue structure to be modified. - * Return 0 if operation was successful and permission is granted. - * @msg_queue_free_security: - * Deallocate security structure for this message queue. - * @msq contains the message queue structure to be modified. - * @msg_queue_associate: - * Check permission when a message queue is requested through the - * msgget system call. This hook is only called when returning the - * message queue identifier for an existing message queue, not when a - * new message queue is created. - * @msq contains the message queue to act upon. - * @msqflg contains the operation control flags. - * Return 0 if permission is granted. - * @msg_queue_msgctl: - * Check permission when a message control operation specified by @cmd - * is to be performed on the message queue @msq. - * The @msq may be NULL, e.g. for IPC_INFO or MSG_INFO. - * @msq contains the message queue to act upon. May be NULL. - * @cmd contains the operation to be performed. - * Return 0 if permission is granted. - * @msg_queue_msgsnd: - * Check permission before a message, @msg, is enqueued on the message - * queue, @msq. - * @msq contains the message queue to send message to. - * @msg contains the message to be enqueued. - * @msqflg contains operational flags. - * Return 0 if permission is granted. - * @msg_queue_msgrcv: - * Check permission before a message, @msg, is removed from the message - * queue, @msq. The @target task structure contains a pointer to the - * process that will be receiving the message (not equal to the current - * process when inline receives are being performed). - * @msq contains the message queue to retrieve message from. - * @msg contains the message destination. - * @target contains the task structure for recipient process. - * @type contains the type of message requested. - * @mode contains the operational flags. - * Return 0 if permission is granted. - * - * Security hooks for System V Shared Memory Segments - * - * @shm_alloc_security: - * Allocate and attach a security structure to the shp->shm_perm.security - * field. The security field is initialized to NULL when the structure is - * first created. - * @shp contains the shared memory structure to be modified. - * Return 0 if operation was successful and permission is granted. - * @shm_free_security: - * Deallocate the security struct for this memory segment. - * @shp contains the shared memory structure to be modified. - * @shm_associate: - * Check permission when a shared memory region is requested through the - * shmget system call. This hook is only called when returning the shared - * memory region identifier for an existing region, not when a new shared - * memory region is created. - * @shp contains the shared memory structure to be modified. - * @shmflg contains the operation control flags. - * Return 0 if permission is granted. - * @shm_shmctl: - * Check permission when a shared memory control operation specified by - * @cmd is to be performed on the shared memory region @shp. - * The @shp may be NULL, e.g. for IPC_INFO or SHM_INFO. - * @shp contains shared memory structure to be modified. - * @cmd contains the operation to be performed. - * Return 0 if permission is granted. - * @shm_shmat: - * Check permissions prior to allowing the shmat system call to attach the - * shared memory segment @shp to the data segment of the calling process. - * The attaching address is specified by @shmaddr. - * @shp contains the shared memory structure to be modified. - * @shmaddr contains the address to attach memory region to. - * @shmflg contains the operational flags. - * Return 0 if permission is granted. - * - * Security hooks for System V Semaphores - * - * @sem_alloc_security: - * Allocate and attach a security structure to the sma->sem_perm.security - * field. The security field is initialized to NULL when the structure is - * first created. - * @sma contains the semaphore structure - * Return 0 if operation was successful and permission is granted. - * @sem_free_security: - * deallocate security struct for this semaphore - * @sma contains the semaphore structure. - * @sem_associate: - * Check permission when a semaphore is requested through the semget - * system call. This hook is only called when returning the semaphore - * identifier for an existing semaphore, not when a new one must be - * created. - * @sma contains the semaphore structure. - * @semflg contains the operation control flags. - * Return 0 if permission is granted. - * @sem_semctl: - * Check permission when a semaphore operation specified by @cmd is to be - * performed on the semaphore @sma. The @sma may be NULL, e.g. for - * IPC_INFO or SEM_INFO. - * @sma contains the semaphore structure. May be NULL. - * @cmd contains the operation to be performed. - * Return 0 if permission is granted. - * @sem_semop - * Check permissions before performing operations on members of the - * semaphore set @sma. If the @alter flag is nonzero, the semaphore set - * may be modified. - * @sma contains the semaphore structure. - * @sops contains the operations to perform. - * @nsops contains the number of operations to perform. - * @alter contains the flag indicating whether changes are to be made. - * Return 0 if permission is granted. - * - * @binder_set_context_mgr - * Check whether @mgr is allowed to be the binder context manager. - * @mgr contains the task_struct for the task being registered. - * Return 0 if permission is granted. - * @binder_transaction - * Check whether @from is allowed to invoke a binder transaction call - * to @to. - * @from contains the task_struct for the sending task. - * @to contains the task_struct for the receiving task. - * @binder_transfer_binder - * Check whether @from is allowed to transfer a binder reference to @to. - * @from contains the task_struct for the sending task. - * @to contains the task_struct for the receiving task. - * @binder_transfer_file - * Check whether @from is allowed to transfer @file to @to. - * @from contains the task_struct for the sending task. - * @file contains the struct file being transferred. - * @to contains the task_struct for the receiving task. - * - * @ptrace_access_check: - * Check permission before allowing the current process to trace the - * @child process. - * Security modules may also want to perform a process tracing check - * during an execve in the set_security or apply_creds hooks of - * tracing check during an execve in the bprm_set_creds hook of - * binprm_security_ops if the process is being traced and its security - * attributes would be changed by the execve. - * @child contains the task_struct structure for the target process. - * @mode contains the PTRACE_MODE flags indicating the form of access. - * Return 0 if permission is granted. - * @ptrace_traceme: - * Check that the @parent process has sufficient permission to trace the - * current process before allowing the current process to present itself - * to the @parent process for tracing. - * @parent contains the task_struct structure for debugger process. - * Return 0 if permission is granted. - * @capget: - * Get the @effective, @inheritable, and @permitted capability sets for - * the @target process. The hook may also perform permission checking to - * determine if the current process is allowed to see the capability sets - * of the @target process. - * @target contains the task_struct structure for target process. - * @effective contains the effective capability set. - * @inheritable contains the inheritable capability set. - * @permitted contains the permitted capability set. - * Return 0 if the capability sets were successfully obtained. - * @capset: - * Set the @effective, @inheritable, and @permitted capability sets for - * the current process. - * @new contains the new credentials structure for target process. - * @old contains the current credentials structure for target process. - * @effective contains the effective capability set. - * @inheritable contains the inheritable capability set. - * @permitted contains the permitted capability set. - * Return 0 and update @new if permission is granted. - * @capable: - * Check whether the @tsk process has the @cap capability in the indicated - * credentials. - * @cred contains the credentials to use. - * @ns contains the user namespace we want the capability in - * @cap contains the capability . - * @audit: Whether to write an audit message or not - * Return 0 if the capability is granted for @tsk. - * @syslog: - * Check permission before accessing the kernel message ring or changing - * logging to the console. - * See the syslog(2) manual page for an explanation of the @type values. - * @type contains the type of action. - * @from_file indicates the context of action (if it came from /proc). - * Return 0 if permission is granted. - * @settime: - * Check permission to change the system time. - * struct timespec64 is defined in include/linux/time64.h and timezone - * is defined in include/linux/time.h - * @ts contains new time - * @tz contains new timezone - * Return 0 if permission is granted. - * @vm_enough_memory: - * Check permissions for allocating a new virtual mapping. - * @mm contains the mm struct it is being added to. - * @pages contains the number of pages. - * Return 0 if permission is granted. - * - * @ismaclabel: - * Check if the extended attribute specified by @name - * represents a MAC label. Returns 1 if name is a MAC - * attribute otherwise returns 0. - * @name full extended attribute name to check against - * LSM as a MAC label. - * - * @secid_to_secctx: - * Convert secid to security context. If secdata is NULL the length of - * the result will be returned in seclen, but no secdata will be returned. - * This does mean that the length could change between calls to check the - * length and the next call which actually allocates and returns the - * secdata. - * @secid contains the security ID. - * @secdata contains the pointer that stores the converted security - * context. - * @seclen pointer which contains the length of the data - * @secctx_to_secid: - * Convert security context to secid. - * @secid contains the pointer to the generated security ID. - * @secdata contains the security context. - * - * @release_secctx: - * Release the security context. - * @secdata contains the security context. - * @seclen contains the length of the security context. - * - * Security hooks for Audit - * - * @audit_rule_init: - * Allocate and initialize an LSM audit rule structure. - * @field contains the required Audit action. - * Fields flags are defined in include/linux/audit.h - * @op contains the operator the rule uses. - * @rulestr contains the context where the rule will be applied to. - * @lsmrule contains a pointer to receive the result. - * Return 0 if @lsmrule has been successfully set, - * -EINVAL in case of an invalid rule. - * - * @audit_rule_known: - * Specifies whether given @rule contains any fields related to - * current LSM. - * @rule contains the audit rule of interest. - * Return 1 in case of relation found, 0 otherwise. - * - * @audit_rule_match: - * Determine if given @secid matches a rule previously approved - * by @audit_rule_known. - * @secid contains the security id in question. - * @field contains the field which relates to current LSM. - * @op contains the operator that will be used for matching. - * @rule points to the audit rule that will be checked against. - * @actx points to the audit context associated with the check. - * Return 1 if secid matches the rule, 0 if it does not, -ERRNO on failure. - * - * @audit_rule_free: - * Deallocate the LSM audit rule structure previously allocated by - * audit_rule_init. - * @rule contains the allocated rule - * - * @inode_invalidate_secctx: - * Notify the security module that it must revalidate the security context - * of an inode. - * - * @inode_notifysecctx: - * Notify the security module of what the security context of an inode - * should be. Initializes the incore security context managed by the - * security module for this inode. Example usage: NFS client invokes - * this hook to initialize the security context in its incore inode to the - * value provided by the server for the file when the server returned the - * file's attributes to the client. - * - * Must be called with inode->i_mutex locked. - * - * @inode we wish to set the security context of. - * @ctx contains the string which we wish to set in the inode. - * @ctxlen contains the length of @ctx. - * - * @inode_setsecctx: - * Change the security context of an inode. Updates the - * incore security context managed by the security module and invokes the - * fs code as needed (via __vfs_setxattr_noperm) to update any backing - * xattrs that represent the context. Example usage: NFS server invokes - * this hook to change the security context in its incore inode and on the - * backing filesystem to a value provided by the client on a SETATTR - * operation. - * - * Must be called with inode->i_mutex locked. - * - * @dentry contains the inode we wish to set the security context of. - * @ctx contains the string which we wish to set in the inode. - * @ctxlen contains the length of @ctx. - * - * @inode_getsecctx: - * On success, returns 0 and fills out @ctx and @ctxlen with the security - * context for the given @inode. - * - * @inode we wish to get the security context of. - * @ctx is a pointer in which to place the allocated security context. - * @ctxlen points to the place to put the length of @ctx. - * This is the main security structure. - */ - -union security_list_options { - int (*binder_set_context_mgr)(struct task_struct *mgr); - int (*binder_transaction)(struct task_struct *from, - struct task_struct *to); - int (*binder_transfer_binder)(struct task_struct *from, - struct task_struct *to); - int (*binder_transfer_file)(struct task_struct *from, - struct task_struct *to, - struct file *file); - - int (*ptrace_access_check)(struct task_struct *child, - unsigned int mode); - int (*ptrace_traceme)(struct task_struct *parent); - int (*capget)(struct task_struct *target, kernel_cap_t *effective, - kernel_cap_t *inheritable, kernel_cap_t *permitted); - int (*capset)(struct cred *new, const struct cred *old, - const kernel_cap_t *effective, - const kernel_cap_t *inheritable, - const kernel_cap_t *permitted); - int (*capable)(const struct cred *cred, struct user_namespace *ns, - int cap, int audit); - int (*quotactl)(int cmds, int type, int id, struct super_block *sb); - int (*quota_on)(struct dentry *dentry); - int (*syslog)(int type); - int (*settime)(const struct timespec64 *ts, const struct timezone *tz); - int (*vm_enough_memory)(struct mm_struct *mm, long pages); - - int (*bprm_set_creds)(struct linux_binprm *bprm); - int (*bprm_check_security)(struct linux_binprm *bprm); - int (*bprm_secureexec)(struct linux_binprm *bprm); - void (*bprm_committing_creds)(struct linux_binprm *bprm); - void (*bprm_committed_creds)(struct linux_binprm *bprm); - - int (*sb_alloc_security)(struct super_block *sb); - void (*sb_free_security)(struct super_block *sb); - int (*sb_copy_data)(char *orig, char *copy); - int (*sb_remount)(struct super_block *sb, void *data); - int (*sb_kern_mount)(struct super_block *sb, int flags, void *data); - int (*sb_show_options)(struct seq_file *m, struct super_block *sb); - int (*sb_statfs)(struct dentry *dentry); - int (*sb_mount)(const char *dev_name, const struct path *path, - const char *type, unsigned long flags, void *data); - int (*sb_umount)(struct vfsmount *mnt, int flags); - int (*sb_pivotroot)(const struct path *old_path, const struct path *new_path); - int (*sb_set_mnt_opts)(struct super_block *sb, - struct security_mnt_opts *opts, - unsigned long kern_flags, - unsigned long *set_kern_flags); - int (*sb_clone_mnt_opts)(const struct super_block *oldsb, - struct super_block *newsb); - int (*sb_parse_opts_str)(char *options, struct security_mnt_opts *opts); - int (*dentry_init_security)(struct dentry *dentry, int mode, - const struct qstr *name, void **ctx, - u32 *ctxlen); - int (*dentry_create_files_as)(struct dentry *dentry, int mode, - struct qstr *name, - const struct cred *old, - struct cred *new); - - -#ifdef CONFIG_SECURITY_PATH - int (*path_unlink)(const struct path *dir, struct dentry *dentry); - int (*path_mkdir)(const struct path *dir, struct dentry *dentry, - umode_t mode); - int (*path_rmdir)(const struct path *dir, struct dentry *dentry); - int (*path_mknod)(const struct path *dir, struct dentry *dentry, - umode_t mode, unsigned int dev); - int (*path_truncate)(const struct path *path); - int (*path_symlink)(const struct path *dir, struct dentry *dentry, - const char *old_name); - int (*path_link)(struct dentry *old_dentry, const struct path *new_dir, - struct dentry *new_dentry); - int (*path_rename)(const struct path *old_dir, struct dentry *old_dentry, - const struct path *new_dir, - struct dentry *new_dentry); - int (*path_chmod)(const struct path *path, umode_t mode); - int (*path_chown)(const struct path *path, kuid_t uid, kgid_t gid); - int (*path_chroot)(const struct path *path); -#endif - - int (*inode_alloc_security)(struct inode *inode); - void (*inode_free_security)(struct inode *inode); - int (*inode_init_security)(struct inode *inode, struct inode *dir, - const struct qstr *qstr, - const char **name, void **value, - size_t *len); - int (*inode_create)(struct inode *dir, struct dentry *dentry, - umode_t mode); - int (*inode_link)(struct dentry *old_dentry, struct inode *dir, - struct dentry *new_dentry); - int (*inode_unlink)(struct inode *dir, struct dentry *dentry); - int (*inode_symlink)(struct inode *dir, struct dentry *dentry, - const char *old_name); - int (*inode_mkdir)(struct inode *dir, struct dentry *dentry, - umode_t mode); - int (*inode_rmdir)(struct inode *dir, struct dentry *dentry); - int (*inode_mknod)(struct inode *dir, struct dentry *dentry, - umode_t mode, dev_t dev); - int (*inode_rename)(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, - struct dentry *new_dentry); - int (*inode_readlink)(struct dentry *dentry); - int (*inode_follow_link)(struct dentry *dentry, struct inode *inode, - bool rcu); - int (*inode_permission)(struct inode *inode, int mask); - int (*inode_setattr)(struct dentry *dentry, struct iattr *attr); - int (*inode_getattr)(const struct path *path); - int (*inode_setxattr)(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags); - void (*inode_post_setxattr)(struct dentry *dentry, const char *name, - const void *value, size_t size, - int flags); - int (*inode_getxattr)(struct dentry *dentry, const char *name); - int (*inode_listxattr)(struct dentry *dentry); - int (*inode_removexattr)(struct dentry *dentry, const char *name); - int (*inode_need_killpriv)(struct dentry *dentry); - int (*inode_killpriv)(struct dentry *dentry); - int (*inode_getsecurity)(struct inode *inode, const char *name, - void **buffer, bool alloc); - int (*inode_setsecurity)(struct inode *inode, const char *name, - const void *value, size_t size, - int flags); - int (*inode_listsecurity)(struct inode *inode, char *buffer, - size_t buffer_size); - void (*inode_getsecid)(struct inode *inode, u32 *secid); - int (*inode_copy_up)(struct dentry *src, struct cred **new); - int (*inode_copy_up_xattr)(const char *name); - - int (*file_permission)(struct file *file, int mask); - int (*file_alloc_security)(struct file *file); - void (*file_free_security)(struct file *file); - int (*file_ioctl)(struct file *file, unsigned int cmd, - unsigned long arg); - int (*mmap_addr)(unsigned long addr); - int (*mmap_file)(struct file *file, unsigned long reqprot, - unsigned long prot, unsigned long flags); - int (*file_mprotect)(struct vm_area_struct *vma, unsigned long reqprot, - unsigned long prot); - int (*file_lock)(struct file *file, unsigned int cmd); - int (*file_fcntl)(struct file *file, unsigned int cmd, - unsigned long arg); - void (*file_set_fowner)(struct file *file); - int (*file_send_sigiotask)(struct task_struct *tsk, - struct fown_struct *fown, int sig); - int (*file_receive)(struct file *file); - int (*file_open)(struct file *file, const struct cred *cred); - - int (*task_create)(unsigned long clone_flags); - void (*task_free)(struct task_struct *task); - int (*cred_alloc_blank)(struct cred *cred, gfp_t gfp); - void (*cred_free)(struct cred *cred); - int (*cred_prepare)(struct cred *new, const struct cred *old, - gfp_t gfp); - void (*cred_transfer)(struct cred *new, const struct cred *old); - int (*kernel_act_as)(struct cred *new, u32 secid); - int (*kernel_create_files_as)(struct cred *new, struct inode *inode); - int (*kernel_module_request)(char *kmod_name); - int (*kernel_read_file)(struct file *file, enum kernel_read_file_id id); - int (*kernel_post_read_file)(struct file *file, char *buf, loff_t size, - enum kernel_read_file_id id); - int (*task_fix_setuid)(struct cred *new, const struct cred *old, - int flags); - int (*task_setpgid)(struct task_struct *p, pid_t pgid); - int (*task_getpgid)(struct task_struct *p); - int (*task_getsid)(struct task_struct *p); - void (*task_getsecid)(struct task_struct *p, u32 *secid); - int (*task_setnice)(struct task_struct *p, int nice); - int (*task_setioprio)(struct task_struct *p, int ioprio); - int (*task_getioprio)(struct task_struct *p); - int (*task_setrlimit)(struct task_struct *p, unsigned int resource, - struct rlimit *new_rlim); - int (*task_setscheduler)(struct task_struct *p); - int (*task_getscheduler)(struct task_struct *p); - int (*task_movememory)(struct task_struct *p); - int (*task_kill)(struct task_struct *p, struct siginfo *info, - int sig, u32 secid); - int (*task_wait)(struct task_struct *p); - int (*task_prctl)(int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5); - void (*task_to_inode)(struct task_struct *p, struct inode *inode); - - int (*ipc_permission)(struct kern_ipc_perm *ipcp, short flag); - void (*ipc_getsecid)(struct kern_ipc_perm *ipcp, u32 *secid); - - int (*msg_msg_alloc_security)(struct msg_msg *msg); - void (*msg_msg_free_security)(struct msg_msg *msg); - - int (*msg_queue_alloc_security)(struct msg_queue *msq); - void (*msg_queue_free_security)(struct msg_queue *msq); - int (*msg_queue_associate)(struct msg_queue *msq, int msqflg); - int (*msg_queue_msgctl)(struct msg_queue *msq, int cmd); - int (*msg_queue_msgsnd)(struct msg_queue *msq, struct msg_msg *msg, - int msqflg); - int (*msg_queue_msgrcv)(struct msg_queue *msq, struct msg_msg *msg, - struct task_struct *target, long type, - int mode); - - int (*shm_alloc_security)(struct shmid_kernel *shp); - void (*shm_free_security)(struct shmid_kernel *shp); - int (*shm_associate)(struct shmid_kernel *shp, int shmflg); - int (*shm_shmctl)(struct shmid_kernel *shp, int cmd); - int (*shm_shmat)(struct shmid_kernel *shp, char __user *shmaddr, - int shmflg); - - int (*sem_alloc_security)(struct sem_array *sma); - void (*sem_free_security)(struct sem_array *sma); - int (*sem_associate)(struct sem_array *sma, int semflg); - int (*sem_semctl)(struct sem_array *sma, int cmd); - int (*sem_semop)(struct sem_array *sma, struct sembuf *sops, - unsigned nsops, int alter); - - int (*netlink_send)(struct sock *sk, struct sk_buff *skb); - - void (*d_instantiate)(struct dentry *dentry, struct inode *inode); - - int (*getprocattr)(struct task_struct *p, char *name, char **value); - int (*setprocattr)(struct task_struct *p, char *name, void *value, - size_t size); - int (*ismaclabel)(const char *name); - int (*secid_to_secctx)(u32 secid, char **secdata, u32 *seclen); - int (*secctx_to_secid)(const char *secdata, u32 seclen, u32 *secid); - void (*release_secctx)(char *secdata, u32 seclen); - - void (*inode_invalidate_secctx)(struct inode *inode); - int (*inode_notifysecctx)(struct inode *inode, void *ctx, u32 ctxlen); - int (*inode_setsecctx)(struct dentry *dentry, void *ctx, u32 ctxlen); - int (*inode_getsecctx)(struct inode *inode, void **ctx, u32 *ctxlen); - -#ifdef CONFIG_SECURITY_NETWORK - int (*unix_stream_connect)(struct sock *sock, struct sock *other, - struct sock *newsk); - int (*unix_may_send)(struct socket *sock, struct socket *other); - - int (*socket_create)(int family, int type, int protocol, int kern); - int (*socket_post_create)(struct socket *sock, int family, int type, - int protocol, int kern); - int (*socket_bind)(struct socket *sock, struct sockaddr *address, - int addrlen); - int (*socket_connect)(struct socket *sock, struct sockaddr *address, - int addrlen); - int (*socket_listen)(struct socket *sock, int backlog); - int (*socket_accept)(struct socket *sock, struct socket *newsock); - int (*socket_sendmsg)(struct socket *sock, struct msghdr *msg, - int size); - int (*socket_recvmsg)(struct socket *sock, struct msghdr *msg, - int size, int flags); - int (*socket_getsockname)(struct socket *sock); - int (*socket_getpeername)(struct socket *sock); - int (*socket_getsockopt)(struct socket *sock, int level, int optname); - int (*socket_setsockopt)(struct socket *sock, int level, int optname); - int (*socket_shutdown)(struct socket *sock, int how); - int (*socket_sock_rcv_skb)(struct sock *sk, struct sk_buff *skb); - int (*socket_getpeersec_stream)(struct socket *sock, - char __user *optval, - int __user *optlen, unsigned len); - int (*socket_getpeersec_dgram)(struct socket *sock, - struct sk_buff *skb, u32 *secid); - int (*sk_alloc_security)(struct sock *sk, int family, gfp_t priority); - void (*sk_free_security)(struct sock *sk); - void (*sk_clone_security)(const struct sock *sk, struct sock *newsk); - void (*sk_getsecid)(struct sock *sk, u32 *secid); - void (*sock_graft)(struct sock *sk, struct socket *parent); - int (*inet_conn_request)(struct sock *sk, struct sk_buff *skb, - struct request_sock *req); - void (*inet_csk_clone)(struct sock *newsk, - const struct request_sock *req); - void (*inet_conn_established)(struct sock *sk, struct sk_buff *skb); - int (*secmark_relabel_packet)(u32 secid); - void (*secmark_refcount_inc)(void); - void (*secmark_refcount_dec)(void); - void (*req_classify_flow)(const struct request_sock *req, - struct flowi *fl); - int (*tun_dev_alloc_security)(void **security); - void (*tun_dev_free_security)(void *security); - int (*tun_dev_create)(void); - int (*tun_dev_attach_queue)(void *security); - int (*tun_dev_attach)(struct sock *sk, void *security); - int (*tun_dev_open)(void *security); -#endif /* CONFIG_SECURITY_NETWORK */ - -#ifdef CONFIG_SECURITY_NETWORK_XFRM - int (*xfrm_policy_alloc_security)(struct xfrm_sec_ctx **ctxp, - struct xfrm_user_sec_ctx *sec_ctx, - gfp_t gfp); - int (*xfrm_policy_clone_security)(struct xfrm_sec_ctx *old_ctx, - struct xfrm_sec_ctx **new_ctx); - void (*xfrm_policy_free_security)(struct xfrm_sec_ctx *ctx); - int (*xfrm_policy_delete_security)(struct xfrm_sec_ctx *ctx); - int (*xfrm_state_alloc)(struct xfrm_state *x, - struct xfrm_user_sec_ctx *sec_ctx); - int (*xfrm_state_alloc_acquire)(struct xfrm_state *x, - struct xfrm_sec_ctx *polsec, - u32 secid); - void (*xfrm_state_free_security)(struct xfrm_state *x); - int (*xfrm_state_delete_security)(struct xfrm_state *x); - int (*xfrm_policy_lookup)(struct xfrm_sec_ctx *ctx, u32 fl_secid, - u8 dir); - int (*xfrm_state_pol_flow_match)(struct xfrm_state *x, - struct xfrm_policy *xp, - const struct flowi *fl); - int (*xfrm_decode_session)(struct sk_buff *skb, u32 *secid, int ckall); -#endif /* CONFIG_SECURITY_NETWORK_XFRM */ - - /* key management security hooks */ -#ifdef CONFIG_KEYS - int (*key_alloc)(struct key *key, const struct cred *cred, - unsigned long flags); - void (*key_free)(struct key *key); - int (*key_permission)(key_ref_t key_ref, const struct cred *cred, - unsigned perm); - int (*key_getsecurity)(struct key *key, char **_buffer); -#endif /* CONFIG_KEYS */ - -#ifdef CONFIG_AUDIT - int (*audit_rule_init)(u32 field, u32 op, char *rulestr, - void **lsmrule); - int (*audit_rule_known)(struct audit_krule *krule); - int (*audit_rule_match)(u32 secid, u32 field, u32 op, void *lsmrule, - struct audit_context *actx); - void (*audit_rule_free)(void *lsmrule); -#endif /* CONFIG_AUDIT */ -}; - -struct security_hook_heads { - struct list_head binder_set_context_mgr; - struct list_head binder_transaction; - struct list_head binder_transfer_binder; - struct list_head binder_transfer_file; - struct list_head ptrace_access_check; - struct list_head ptrace_traceme; - struct list_head capget; - struct list_head capset; - struct list_head capable; - struct list_head quotactl; - struct list_head quota_on; - struct list_head syslog; - struct list_head settime; - struct list_head vm_enough_memory; - struct list_head bprm_set_creds; - struct list_head bprm_check_security; - struct list_head bprm_secureexec; - struct list_head bprm_committing_creds; - struct list_head bprm_committed_creds; - struct list_head sb_alloc_security; - struct list_head sb_free_security; - struct list_head sb_copy_data; - struct list_head sb_remount; - struct list_head sb_kern_mount; - struct list_head sb_show_options; - struct list_head sb_statfs; - struct list_head sb_mount; - struct list_head sb_umount; - struct list_head sb_pivotroot; - struct list_head sb_set_mnt_opts; - struct list_head sb_clone_mnt_opts; - struct list_head sb_parse_opts_str; - struct list_head dentry_init_security; - struct list_head dentry_create_files_as; -#ifdef CONFIG_SECURITY_PATH - struct list_head path_unlink; - struct list_head path_mkdir; - struct list_head path_rmdir; - struct list_head path_mknod; - struct list_head path_truncate; - struct list_head path_symlink; - struct list_head path_link; - struct list_head path_rename; - struct list_head path_chmod; - struct list_head path_chown; - struct list_head path_chroot; -#endif - struct list_head inode_alloc_security; - struct list_head inode_free_security; - struct list_head inode_init_security; - struct list_head inode_create; - struct list_head inode_link; - struct list_head inode_unlink; - struct list_head inode_symlink; - struct list_head inode_mkdir; - struct list_head inode_rmdir; - struct list_head inode_mknod; - struct list_head inode_rename; - struct list_head inode_readlink; - struct list_head inode_follow_link; - struct list_head inode_permission; - struct list_head inode_setattr; - struct list_head inode_getattr; - struct list_head inode_setxattr; - struct list_head inode_post_setxattr; - struct list_head inode_getxattr; - struct list_head inode_listxattr; - struct list_head inode_removexattr; - struct list_head inode_need_killpriv; - struct list_head inode_killpriv; - struct list_head inode_getsecurity; - struct list_head inode_setsecurity; - struct list_head inode_listsecurity; - struct list_head inode_getsecid; - struct list_head inode_copy_up; - struct list_head inode_copy_up_xattr; - struct list_head file_permission; - struct list_head file_alloc_security; - struct list_head file_free_security; - struct list_head file_ioctl; - struct list_head mmap_addr; - struct list_head mmap_file; - struct list_head file_mprotect; - struct list_head file_lock; - struct list_head file_fcntl; - struct list_head file_set_fowner; - struct list_head file_send_sigiotask; - struct list_head file_receive; - struct list_head file_open; - struct list_head task_create; - struct list_head task_free; - struct list_head cred_alloc_blank; - struct list_head cred_free; - struct list_head cred_prepare; - struct list_head cred_transfer; - struct list_head kernel_act_as; - struct list_head kernel_create_files_as; - struct list_head kernel_read_file; - struct list_head kernel_post_read_file; - struct list_head kernel_module_request; - struct list_head task_fix_setuid; - struct list_head task_setpgid; - struct list_head task_getpgid; - struct list_head task_getsid; - struct list_head task_getsecid; - struct list_head task_setnice; - struct list_head task_setioprio; - struct list_head task_getioprio; - struct list_head task_setrlimit; - struct list_head task_setscheduler; - struct list_head task_getscheduler; - struct list_head task_movememory; - struct list_head task_kill; - struct list_head task_wait; - struct list_head task_prctl; - struct list_head task_to_inode; - struct list_head ipc_permission; - struct list_head ipc_getsecid; - struct list_head msg_msg_alloc_security; - struct list_head msg_msg_free_security; - struct list_head msg_queue_alloc_security; - struct list_head msg_queue_free_security; - struct list_head msg_queue_associate; - struct list_head msg_queue_msgctl; - struct list_head msg_queue_msgsnd; - struct list_head msg_queue_msgrcv; - struct list_head shm_alloc_security; - struct list_head shm_free_security; - struct list_head shm_associate; - struct list_head shm_shmctl; - struct list_head shm_shmat; - struct list_head sem_alloc_security; - struct list_head sem_free_security; - struct list_head sem_associate; - struct list_head sem_semctl; - struct list_head sem_semop; - struct list_head netlink_send; - struct list_head d_instantiate; - struct list_head getprocattr; - struct list_head setprocattr; - struct list_head ismaclabel; - struct list_head secid_to_secctx; - struct list_head secctx_to_secid; - struct list_head release_secctx; - struct list_head inode_invalidate_secctx; - struct list_head inode_notifysecctx; - struct list_head inode_setsecctx; - struct list_head inode_getsecctx; -#ifdef CONFIG_SECURITY_NETWORK - struct list_head unix_stream_connect; - struct list_head unix_may_send; - struct list_head socket_create; - struct list_head socket_post_create; - struct list_head socket_bind; - struct list_head socket_connect; - struct list_head socket_listen; - struct list_head socket_accept; - struct list_head socket_sendmsg; - struct list_head socket_recvmsg; - struct list_head socket_getsockname; - struct list_head socket_getpeername; - struct list_head socket_getsockopt; - struct list_head socket_setsockopt; - struct list_head socket_shutdown; - struct list_head socket_sock_rcv_skb; - struct list_head socket_getpeersec_stream; - struct list_head socket_getpeersec_dgram; - struct list_head sk_alloc_security; - struct list_head sk_free_security; - struct list_head sk_clone_security; - struct list_head sk_getsecid; - struct list_head sock_graft; - struct list_head inet_conn_request; - struct list_head inet_csk_clone; - struct list_head inet_conn_established; - struct list_head secmark_relabel_packet; - struct list_head secmark_refcount_inc; - struct list_head secmark_refcount_dec; - struct list_head req_classify_flow; - struct list_head tun_dev_alloc_security; - struct list_head tun_dev_free_security; - struct list_head tun_dev_create; - struct list_head tun_dev_attach_queue; - struct list_head tun_dev_attach; - struct list_head tun_dev_open; -#endif /* CONFIG_SECURITY_NETWORK */ -#ifdef CONFIG_SECURITY_NETWORK_XFRM - struct list_head xfrm_policy_alloc_security; - struct list_head xfrm_policy_clone_security; - struct list_head xfrm_policy_free_security; - struct list_head xfrm_policy_delete_security; - struct list_head xfrm_state_alloc; - struct list_head xfrm_state_alloc_acquire; - struct list_head xfrm_state_free_security; - struct list_head xfrm_state_delete_security; - struct list_head xfrm_policy_lookup; - struct list_head xfrm_state_pol_flow_match; - struct list_head xfrm_decode_session; -#endif /* CONFIG_SECURITY_NETWORK_XFRM */ -#ifdef CONFIG_KEYS - struct list_head key_alloc; - struct list_head key_free; - struct list_head key_permission; - struct list_head key_getsecurity; -#endif /* CONFIG_KEYS */ -#ifdef CONFIG_AUDIT - struct list_head audit_rule_init; - struct list_head audit_rule_known; - struct list_head audit_rule_match; - struct list_head audit_rule_free; -#endif /* CONFIG_AUDIT */ -}; - -/* - * Security module hook list structure. - * For use with generic list macros for common operations. - */ -struct security_hook_list { - struct list_head list; - struct list_head *head; - union security_list_options hook; -}; - -/* - * Initializing a security_hook_list structure takes - * up a lot of space in a source file. This macro takes - * care of the common case and reduces the amount of - * text involved. - */ -#define LSM_HOOK_INIT(HEAD, HOOK) \ - { .head = &security_hook_heads.HEAD, .hook = { .HEAD = HOOK } } - -extern struct security_hook_heads security_hook_heads; - -static inline void security_add_hooks(struct security_hook_list *hooks, - int count) -{ - int i; - - for (i = 0; i < count; i++) - list_add_tail_rcu(&hooks[i].list, hooks[i].head); -} - -#ifdef CONFIG_SECURITY_SELINUX_DISABLE -/* - * Assuring the safety of deleting a security module is up to - * the security module involved. This may entail ordering the - * module's hook list in a particular way, refusing to disable - * the module once a policy is loaded or any number of other - * actions better imagined than described. - * - * The name of the configuration option reflects the only module - * that currently uses the mechanism. Any developer who thinks - * disabling their module is a good idea needs to be at least as - * careful as the SELinux team. - */ -static inline void security_delete_hooks(struct security_hook_list *hooks, - int count) -{ - int i; - - for (i = 0; i < count; i++) - list_del_rcu(&hooks[i].list); -} -#endif /* CONFIG_SECURITY_SELINUX_DISABLE */ - -extern int __init security_module_enable(const char *module); -extern void __init capability_add_hooks(void); -#ifdef CONFIG_SECURITY_YAMA -extern void __init yama_add_hooks(void); -#else -static inline void __init yama_add_hooks(void) { } -#endif -#ifdef CONFIG_SECURITY_LOADPIN -void __init loadpin_add_hooks(void); -#else -static inline void loadpin_add_hooks(void) { }; -#endif - -#endif /* ! __LINUX_LSM_HOOKS_H */ diff --git a/src/linux/include/linux/lzo.h b/src/linux/include/linux/lzo.h deleted file mode 100644 index a0848d9..0000000 --- a/src/linux/include/linux/lzo.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef __LZO_H__ -#define __LZO_H__ -/* - * LZO Public Kernel Interface - * A mini subset of the LZO real-time data compression library - * - * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer - * - * The full LZO package can be found at: - * http://www.oberhumer.com/opensource/lzo/ - * - * Changed for Linux kernel use by: - * Nitin Gupta - * Richard Purdie - */ - -#define LZO1X_1_MEM_COMPRESS (8192 * sizeof(unsigned short)) -#define LZO1X_MEM_COMPRESS LZO1X_1_MEM_COMPRESS - -#define lzo1x_worst_compress(x) ((x) + ((x) / 16) + 64 + 3) - -/* This requires 'wrkmem' of size LZO1X_1_MEM_COMPRESS */ -int lzo1x_1_compress(const unsigned char *src, size_t src_len, - unsigned char *dst, size_t *dst_len, void *wrkmem); - -/* safe decompression with overrun testing */ -int lzo1x_decompress_safe(const unsigned char *src, size_t src_len, - unsigned char *dst, size_t *dst_len); - -/* - * Return values (< 0 = Error) - */ -#define LZO_E_OK 0 -#define LZO_E_ERROR (-1) -#define LZO_E_OUT_OF_MEMORY (-2) -#define LZO_E_NOT_COMPRESSIBLE (-3) -#define LZO_E_INPUT_OVERRUN (-4) -#define LZO_E_OUTPUT_OVERRUN (-5) -#define LZO_E_LOOKBEHIND_OVERRUN (-6) -#define LZO_E_EOF_NOT_FOUND (-7) -#define LZO_E_INPUT_NOT_CONSUMED (-8) -#define LZO_E_NOT_YET_IMPLEMENTED (-9) -#define LZO_E_INVALID_ARGUMENT (-10) - -#endif diff --git a/src/linux/include/linux/math64.h b/src/linux/include/linux/math64.h deleted file mode 100644 index 6e8b5b2..0000000 --- a/src/linux/include/linux/math64.h +++ /dev/null @@ -1,246 +0,0 @@ -#ifndef _LINUX_MATH64_H -#define _LINUX_MATH64_H - -#include -#include - -#if BITS_PER_LONG == 64 - -#define div64_long(x, y) div64_s64((x), (y)) -#define div64_ul(x, y) div64_u64((x), (y)) - -/** - * div_u64_rem - unsigned 64bit divide with 32bit divisor with remainder - * - * This is commonly provided by 32bit archs to provide an optimized 64bit - * divide. - */ -static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder) -{ - *remainder = dividend % divisor; - return dividend / divisor; -} - -/** - * div_s64_rem - signed 64bit divide with 32bit divisor with remainder - */ -static inline s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder) -{ - *remainder = dividend % divisor; - return dividend / divisor; -} - -/** - * div64_u64_rem - unsigned 64bit divide with 64bit divisor and remainder - */ -static inline u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder) -{ - *remainder = dividend % divisor; - return dividend / divisor; -} - -/** - * div64_u64 - unsigned 64bit divide with 64bit divisor - */ -static inline u64 div64_u64(u64 dividend, u64 divisor) -{ - return dividend / divisor; -} - -/** - * div64_s64 - signed 64bit divide with 64bit divisor - */ -static inline s64 div64_s64(s64 dividend, s64 divisor) -{ - return dividend / divisor; -} - -#elif BITS_PER_LONG == 32 - -#define div64_long(x, y) div_s64((x), (y)) -#define div64_ul(x, y) div_u64((x), (y)) - -#ifndef div_u64_rem -static inline u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder) -{ - *remainder = do_div(dividend, divisor); - return dividend; -} -#endif - -#ifndef div_s64_rem -extern s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder); -#endif - -#ifndef div64_u64_rem -extern u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder); -#endif - -#ifndef div64_u64 -extern u64 div64_u64(u64 dividend, u64 divisor); -#endif - -#ifndef div64_s64 -extern s64 div64_s64(s64 dividend, s64 divisor); -#endif - -#endif /* BITS_PER_LONG */ - -/** - * div_u64 - unsigned 64bit divide with 32bit divisor - * - * This is the most common 64bit divide and should be used if possible, - * as many 32bit archs can optimize this variant better than a full 64bit - * divide. - */ -#ifndef div_u64 -static inline u64 div_u64(u64 dividend, u32 divisor) -{ - u32 remainder; - return div_u64_rem(dividend, divisor, &remainder); -} -#endif - -/** - * div_s64 - signed 64bit divide with 32bit divisor - */ -#ifndef div_s64 -static inline s64 div_s64(s64 dividend, s32 divisor) -{ - s32 remainder; - return div_s64_rem(dividend, divisor, &remainder); -} -#endif - -u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder); - -static __always_inline u32 -__iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder) -{ - u32 ret = 0; - - while (dividend >= divisor) { - /* The following asm() prevents the compiler from - optimising this loop into a modulo operation. */ - asm("" : "+rm"(dividend)); - - dividend -= divisor; - ret++; - } - - *remainder = dividend; - - return ret; -} - -#if defined(CONFIG_ARCH_SUPPORTS_INT128) && defined(__SIZEOF_INT128__) - -#ifndef mul_u64_u32_shr -static inline u64 mul_u64_u32_shr(u64 a, u32 mul, unsigned int shift) -{ - return (u64)(((unsigned __int128)a * mul) >> shift); -} -#endif /* mul_u64_u32_shr */ - -#ifndef mul_u64_u64_shr -static inline u64 mul_u64_u64_shr(u64 a, u64 mul, unsigned int shift) -{ - return (u64)(((unsigned __int128)a * mul) >> shift); -} -#endif /* mul_u64_u64_shr */ - -#else - -#ifndef mul_u64_u32_shr -static inline u64 mul_u64_u32_shr(u64 a, u32 mul, unsigned int shift) -{ - u32 ah, al; - u64 ret; - - al = a; - ah = a >> 32; - - ret = ((u64)al * mul) >> shift; - if (ah) - ret += ((u64)ah * mul) << (32 - shift); - - return ret; -} -#endif /* mul_u64_u32_shr */ - -#ifndef mul_u64_u64_shr -static inline u64 mul_u64_u64_shr(u64 a, u64 b, unsigned int shift) -{ - union { - u64 ll; - struct { -#ifdef __BIG_ENDIAN - u32 high, low; -#else - u32 low, high; -#endif - } l; - } rl, rm, rn, rh, a0, b0; - u64 c; - - a0.ll = a; - b0.ll = b; - - rl.ll = (u64)a0.l.low * b0.l.low; - rm.ll = (u64)a0.l.low * b0.l.high; - rn.ll = (u64)a0.l.high * b0.l.low; - rh.ll = (u64)a0.l.high * b0.l.high; - - /* - * Each of these lines computes a 64-bit intermediate result into "c", - * starting at bits 32-95. The low 32-bits go into the result of the - * multiplication, the high 32-bits are carried into the next step. - */ - rl.l.high = c = (u64)rl.l.high + rm.l.low + rn.l.low; - rh.l.low = c = (c >> 32) + rm.l.high + rn.l.high + rh.l.low; - rh.l.high = (c >> 32) + rh.l.high; - - /* - * The 128-bit result of the multiplication is in rl.ll and rh.ll, - * shift it right and throw away the high part of the result. - */ - if (shift == 0) - return rl.ll; - if (shift < 64) - return (rl.ll >> shift) | (rh.ll << (64 - shift)); - return rh.ll >> (shift & 63); -} -#endif /* mul_u64_u64_shr */ - -#endif - -#ifndef mul_u64_u32_div -static inline u64 mul_u64_u32_div(u64 a, u32 mul, u32 divisor) -{ - union { - u64 ll; - struct { -#ifdef __BIG_ENDIAN - u32 high, low; -#else - u32 low, high; -#endif - } l; - } u, rl, rh; - - u.ll = a; - rl.ll = (u64)u.l.low * mul; - rh.ll = (u64)u.l.high * mul + rl.l.high; - - /* Bits 32-63 of the result will be in rh.l.low. */ - rl.l.high = do_div(rh.ll, divisor); - - /* Bits 0-31 of the result will be in rl.l.low. */ - do_div(rl.ll, divisor); - - rl.l.high = rh.l.low; - return rl.ll; -} -#endif /* mul_u64_u32_div */ - -#endif /* _LINUX_MATH64_H */ diff --git a/src/linux/include/linux/mbcache.h b/src/linux/include/linux/mbcache.h deleted file mode 100644 index 86c9a8b..0000000 --- a/src/linux/include/linux/mbcache.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef _LINUX_MBCACHE_H -#define _LINUX_MBCACHE_H - -#include -#include -#include -#include -#include - -struct mb_cache; - -struct mb_cache_entry { - /* List of entries in cache - protected by cache->c_list_lock */ - struct list_head e_list; - /* Hash table list - protected by hash chain bitlock */ - struct hlist_bl_node e_hash_list; - atomic_t e_refcnt; - /* Key in hash - stable during lifetime of the entry */ - u32 e_key; - u32 e_referenced:1; - u32 e_reusable:1; - /* Block number of hashed block - stable during lifetime of the entry */ - sector_t e_block; -}; - -struct mb_cache *mb_cache_create(int bucket_bits); -void mb_cache_destroy(struct mb_cache *cache); - -int mb_cache_entry_create(struct mb_cache *cache, gfp_t mask, u32 key, - sector_t block, bool reusable); -void __mb_cache_entry_free(struct mb_cache_entry *entry); -static inline int mb_cache_entry_put(struct mb_cache *cache, - struct mb_cache_entry *entry) -{ - if (!atomic_dec_and_test(&entry->e_refcnt)) - return 0; - __mb_cache_entry_free(entry); - return 1; -} - -void mb_cache_entry_delete_block(struct mb_cache *cache, u32 key, - sector_t block); -struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *cache, u32 key, - sector_t block); -struct mb_cache_entry *mb_cache_entry_find_first(struct mb_cache *cache, - u32 key); -struct mb_cache_entry *mb_cache_entry_find_next(struct mb_cache *cache, - struct mb_cache_entry *entry); -void mb_cache_entry_touch(struct mb_cache *cache, - struct mb_cache_entry *entry); - -#endif /* _LINUX_MBCACHE_H */ diff --git a/src/linux/include/linux/mdio.h b/src/linux/include/linux/mdio.h deleted file mode 100644 index bf9d1d7..0000000 --- a/src/linux/include/linux/mdio.h +++ /dev/null @@ -1,265 +0,0 @@ -/* - * linux/mdio.h: definitions for MDIO (clause 45) transceivers - * Copyright 2006-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. - */ -#ifndef __LINUX_MDIO_H__ -#define __LINUX_MDIO_H__ - -#include - -struct mii_bus; - -/* Multiple levels of nesting are possible. However typically this is - * limited to nested DSA like layer, a MUX layer, and the normal - * user. Instead of trying to handle the general case, just define - * these cases. - */ -enum mdio_mutex_lock_class { - MDIO_MUTEX_NORMAL, - MDIO_MUTEX_MUX, - MDIO_MUTEX_NESTED, -}; - -struct mdio_device { - struct device dev; - - const struct dev_pm_ops *pm_ops; - struct mii_bus *bus; - - int (*bus_match)(struct device *dev, struct device_driver *drv); - void (*device_free)(struct mdio_device *mdiodev); - void (*device_remove)(struct mdio_device *mdiodev); - - /* Bus address of the MDIO device (0-31) */ - int addr; - int flags; -}; -#define to_mdio_device(d) container_of(d, struct mdio_device, dev) - -/* struct mdio_driver_common: Common to all MDIO drivers */ -struct mdio_driver_common { - struct device_driver driver; - int flags; -}; -#define MDIO_DEVICE_FLAG_PHY 1 -#define to_mdio_common_driver(d) \ - container_of(d, struct mdio_driver_common, driver) - -/* struct mdio_driver: Generic MDIO driver */ -struct mdio_driver { - struct mdio_driver_common mdiodrv; - - /* - * Called during discovery. Used to set - * up device-specific structures, if any - */ - int (*probe)(struct mdio_device *mdiodev); - - /* Clears up any memory if needed */ - void (*remove)(struct mdio_device *mdiodev); -}; -#define to_mdio_driver(d) \ - container_of(to_mdio_common_driver(d), struct mdio_driver, mdiodrv) - -void mdio_device_free(struct mdio_device *mdiodev); -struct mdio_device *mdio_device_create(struct mii_bus *bus, int addr); -int mdio_device_register(struct mdio_device *mdiodev); -void mdio_device_remove(struct mdio_device *mdiodev); -int mdio_driver_register(struct mdio_driver *drv); -void mdio_driver_unregister(struct mdio_driver *drv); - -static inline bool mdio_phy_id_is_c45(int phy_id) -{ - return (phy_id & MDIO_PHY_ID_C45) && !(phy_id & ~MDIO_PHY_ID_C45_MASK); -} - -static inline __u16 mdio_phy_id_prtad(int phy_id) -{ - return (phy_id & MDIO_PHY_ID_PRTAD) >> 5; -} - -static inline __u16 mdio_phy_id_devad(int phy_id) -{ - return phy_id & MDIO_PHY_ID_DEVAD; -} - -/** - * struct mdio_if_info - Ethernet controller MDIO interface - * @prtad: PRTAD of the PHY (%MDIO_PRTAD_NONE if not present/unknown) - * @mmds: Mask of MMDs expected to be present in the PHY. This must be - * non-zero unless @prtad = %MDIO_PRTAD_NONE. - * @mode_support: MDIO modes supported. If %MDIO_SUPPORTS_C22 is set then - * MII register access will be passed through with @devad = - * %MDIO_DEVAD_NONE. If %MDIO_EMULATE_C22 is set then access to - * commonly used clause 22 registers will be translated into - * clause 45 registers. - * @dev: Net device structure - * @mdio_read: Register read function; returns value or negative error code - * @mdio_write: Register write function; returns 0 or negative error code - */ -struct mdio_if_info { - int prtad; - u32 mmds; - unsigned mode_support; - - struct net_device *dev; - int (*mdio_read)(struct net_device *dev, int prtad, int devad, - u16 addr); - int (*mdio_write)(struct net_device *dev, int prtad, int devad, - u16 addr, u16 val); -}; - -#define MDIO_PRTAD_NONE (-1) -#define MDIO_DEVAD_NONE (-1) -#define MDIO_SUPPORTS_C22 1 -#define MDIO_SUPPORTS_C45 2 -#define MDIO_EMULATE_C22 4 - -struct ethtool_cmd; -struct ethtool_pauseparam; -extern int mdio45_probe(struct mdio_if_info *mdio, int prtad); -extern int mdio_set_flag(const struct mdio_if_info *mdio, - int prtad, int devad, u16 addr, int mask, - bool sense); -extern int mdio45_links_ok(const struct mdio_if_info *mdio, u32 mmds); -extern int mdio45_nway_restart(const struct mdio_if_info *mdio); -extern void mdio45_ethtool_gset_npage(const struct mdio_if_info *mdio, - struct ethtool_cmd *ecmd, - u32 npage_adv, u32 npage_lpa); - -/** - * mdio45_ethtool_gset - get settings for ETHTOOL_GSET - * @mdio: MDIO interface - * @ecmd: Ethtool request structure - * - * Since the CSRs for auto-negotiation using next pages are not fully - * standardised, this function does not attempt to decode them. Use - * mdio45_ethtool_gset_npage() to specify advertisement bits from next - * pages. - */ -static inline void mdio45_ethtool_gset(const struct mdio_if_info *mdio, - struct ethtool_cmd *ecmd) -{ - mdio45_ethtool_gset_npage(mdio, ecmd, 0, 0); -} - -extern int mdio_mii_ioctl(const struct mdio_if_info *mdio, - struct mii_ioctl_data *mii_data, int cmd); - -/** - * mmd_eee_cap_to_ethtool_sup_t - * @eee_cap: value of the MMD EEE Capability register - * - * A small helper function that translates MMD EEE Capability (3.20) bits - * to ethtool supported settings. - */ -static inline u32 mmd_eee_cap_to_ethtool_sup_t(u16 eee_cap) -{ - u32 supported = 0; - - if (eee_cap & MDIO_EEE_100TX) - supported |= SUPPORTED_100baseT_Full; - if (eee_cap & MDIO_EEE_1000T) - supported |= SUPPORTED_1000baseT_Full; - if (eee_cap & MDIO_EEE_10GT) - supported |= SUPPORTED_10000baseT_Full; - if (eee_cap & MDIO_EEE_1000KX) - supported |= SUPPORTED_1000baseKX_Full; - if (eee_cap & MDIO_EEE_10GKX4) - supported |= SUPPORTED_10000baseKX4_Full; - if (eee_cap & MDIO_EEE_10GKR) - supported |= SUPPORTED_10000baseKR_Full; - - return supported; -} - -/** - * mmd_eee_adv_to_ethtool_adv_t - * @eee_adv: value of the MMD EEE Advertisement/Link Partner Ability registers - * - * A small helper function that translates the MMD EEE Advertisment (7.60) - * and MMD EEE Link Partner Ability (7.61) bits to ethtool advertisement - * settings. - */ -static inline u32 mmd_eee_adv_to_ethtool_adv_t(u16 eee_adv) -{ - u32 adv = 0; - - if (eee_adv & MDIO_EEE_100TX) - adv |= ADVERTISED_100baseT_Full; - if (eee_adv & MDIO_EEE_1000T) - adv |= ADVERTISED_1000baseT_Full; - if (eee_adv & MDIO_EEE_10GT) - adv |= ADVERTISED_10000baseT_Full; - if (eee_adv & MDIO_EEE_1000KX) - adv |= ADVERTISED_1000baseKX_Full; - if (eee_adv & MDIO_EEE_10GKX4) - adv |= ADVERTISED_10000baseKX4_Full; - if (eee_adv & MDIO_EEE_10GKR) - adv |= ADVERTISED_10000baseKR_Full; - - return adv; -} - -/** - * ethtool_adv_to_mmd_eee_adv_t - * @adv: the ethtool advertisement settings - * - * A small helper function that translates ethtool advertisement settings - * to EEE advertisements for the MMD EEE Advertisement (7.60) and - * MMD EEE Link Partner Ability (7.61) registers. - */ -static inline u16 ethtool_adv_to_mmd_eee_adv_t(u32 adv) -{ - u16 reg = 0; - - if (adv & ADVERTISED_100baseT_Full) - reg |= MDIO_EEE_100TX; - if (adv & ADVERTISED_1000baseT_Full) - reg |= MDIO_EEE_1000T; - if (adv & ADVERTISED_10000baseT_Full) - reg |= MDIO_EEE_10GT; - if (adv & ADVERTISED_1000baseKX_Full) - reg |= MDIO_EEE_1000KX; - if (adv & ADVERTISED_10000baseKX4_Full) - reg |= MDIO_EEE_10GKX4; - if (adv & ADVERTISED_10000baseKR_Full) - reg |= MDIO_EEE_10GKR; - - return reg; -} - -int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum); -int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum); -int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val); -int mdiobus_write_nested(struct mii_bus *bus, int addr, u32 regnum, u16 val); - -int mdiobus_register_device(struct mdio_device *mdiodev); -int mdiobus_unregister_device(struct mdio_device *mdiodev); -bool mdiobus_is_registered_device(struct mii_bus *bus, int addr); -struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr); - -/** - * module_mdio_driver() - Helper macro for registering mdio drivers - * - * Helper macro for MDIO drivers which do not do anything special in module - * init/exit. Each module may only use this macro once, and calling it - * replaces module_init() and module_exit(). - */ -#define mdio_module_driver(_mdio_driver) \ -static int __init mdio_module_init(void) \ -{ \ - return mdio_driver_register(&_mdio_driver); \ -} \ -module_init(mdio_module_init); \ -static void __exit mdio_module_exit(void) \ -{ \ - mdio_driver_unregister(&_mdio_driver); \ -} \ -module_exit(mdio_module_exit) - -#endif /* __LINUX_MDIO_H__ */ diff --git a/src/linux/include/linux/memblock.h b/src/linux/include/linux/memblock.h deleted file mode 100644 index 5b759c9..0000000 --- a/src/linux/include/linux/memblock.h +++ /dev/null @@ -1,434 +0,0 @@ -#ifndef _LINUX_MEMBLOCK_H -#define _LINUX_MEMBLOCK_H -#ifdef __KERNEL__ - -#ifdef CONFIG_HAVE_MEMBLOCK -/* - * Logical memory blocks. - * - * Copyright (C) 2001 Peter Bergner, IBM Corp. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include - -#define INIT_MEMBLOCK_REGIONS 128 -#define INIT_PHYSMEM_REGIONS 4 - -/* Definition of memblock flags. */ -enum { - MEMBLOCK_NONE = 0x0, /* No special request */ - MEMBLOCK_HOTPLUG = 0x1, /* hotpluggable region */ - MEMBLOCK_MIRROR = 0x2, /* mirrored region */ - MEMBLOCK_NOMAP = 0x4, /* don't add to kernel direct mapping */ -}; - -struct memblock_region { - phys_addr_t base; - phys_addr_t size; - unsigned long flags; -#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP - int nid; -#endif -}; - -struct memblock_type { - unsigned long cnt; /* number of regions */ - unsigned long max; /* size of the allocated array */ - phys_addr_t total_size; /* size of all regions */ - struct memblock_region *regions; -}; - -struct memblock { - bool bottom_up; /* is bottom up direction? */ - phys_addr_t current_limit; - struct memblock_type memory; - struct memblock_type reserved; -#ifdef CONFIG_HAVE_MEMBLOCK_PHYS_MAP - struct memblock_type physmem; -#endif -}; - -extern struct memblock memblock; -extern int memblock_debug; -#ifdef CONFIG_MOVABLE_NODE -/* If movable_node boot option specified */ -extern bool movable_node_enabled; -#endif /* CONFIG_MOVABLE_NODE */ - -#ifdef CONFIG_ARCH_DISCARD_MEMBLOCK -#define __init_memblock __meminit -#define __initdata_memblock __meminitdata -#else -#define __init_memblock -#define __initdata_memblock -#endif - -#define memblock_dbg(fmt, ...) \ - if (memblock_debug) printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__) - -phys_addr_t memblock_find_in_range_node(phys_addr_t size, phys_addr_t align, - phys_addr_t start, phys_addr_t end, - int nid, ulong flags); -phys_addr_t memblock_find_in_range(phys_addr_t start, phys_addr_t end, - phys_addr_t size, phys_addr_t align); -phys_addr_t get_allocated_memblock_reserved_regions_info(phys_addr_t *addr); -phys_addr_t get_allocated_memblock_memory_regions_info(phys_addr_t *addr); -void memblock_allow_resize(void); -int memblock_add_node(phys_addr_t base, phys_addr_t size, int nid); -int memblock_add(phys_addr_t base, phys_addr_t size); -int memblock_remove(phys_addr_t base, phys_addr_t size); -int memblock_free(phys_addr_t base, phys_addr_t size); -int memblock_reserve(phys_addr_t base, phys_addr_t size); -void memblock_trim_memory(phys_addr_t align); -bool memblock_overlaps_region(struct memblock_type *type, - phys_addr_t base, phys_addr_t size); -int memblock_mark_hotplug(phys_addr_t base, phys_addr_t size); -int memblock_clear_hotplug(phys_addr_t base, phys_addr_t size); -int memblock_mark_mirror(phys_addr_t base, phys_addr_t size); -int memblock_mark_nomap(phys_addr_t base, phys_addr_t size); -ulong choose_memblock_flags(void); - -/* Low level functions */ -int memblock_add_range(struct memblock_type *type, - phys_addr_t base, phys_addr_t size, - int nid, unsigned long flags); - -void __next_mem_range(u64 *idx, int nid, ulong flags, - struct memblock_type *type_a, - struct memblock_type *type_b, phys_addr_t *out_start, - phys_addr_t *out_end, int *out_nid); - -void __next_mem_range_rev(u64 *idx, int nid, ulong flags, - struct memblock_type *type_a, - struct memblock_type *type_b, phys_addr_t *out_start, - phys_addr_t *out_end, int *out_nid); - -void __next_reserved_mem_region(u64 *idx, phys_addr_t *out_start, - phys_addr_t *out_end); - -/** - * for_each_mem_range - iterate through memblock areas from type_a and not - * included in type_b. Or just type_a if type_b is NULL. - * @i: u64 used as loop variable - * @type_a: ptr to memblock_type to iterate - * @type_b: ptr to memblock_type which excludes from the iteration - * @nid: node selector, %NUMA_NO_NODE for all nodes - * @flags: pick from blocks based on memory attributes - * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL - * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL - * @p_nid: ptr to int for nid of the range, can be %NULL - */ -#define for_each_mem_range(i, type_a, type_b, nid, flags, \ - p_start, p_end, p_nid) \ - for (i = 0, __next_mem_range(&i, nid, flags, type_a, type_b, \ - p_start, p_end, p_nid); \ - i != (u64)ULLONG_MAX; \ - __next_mem_range(&i, nid, flags, type_a, type_b, \ - p_start, p_end, p_nid)) - -/** - * for_each_mem_range_rev - reverse iterate through memblock areas from - * type_a and not included in type_b. Or just type_a if type_b is NULL. - * @i: u64 used as loop variable - * @type_a: ptr to memblock_type to iterate - * @type_b: ptr to memblock_type which excludes from the iteration - * @nid: node selector, %NUMA_NO_NODE for all nodes - * @flags: pick from blocks based on memory attributes - * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL - * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL - * @p_nid: ptr to int for nid of the range, can be %NULL - */ -#define for_each_mem_range_rev(i, type_a, type_b, nid, flags, \ - p_start, p_end, p_nid) \ - for (i = (u64)ULLONG_MAX, \ - __next_mem_range_rev(&i, nid, flags, type_a, type_b,\ - p_start, p_end, p_nid); \ - i != (u64)ULLONG_MAX; \ - __next_mem_range_rev(&i, nid, flags, type_a, type_b, \ - p_start, p_end, p_nid)) - -/** - * for_each_reserved_mem_region - iterate over all reserved memblock areas - * @i: u64 used as loop variable - * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL - * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL - * - * Walks over reserved areas of memblock. Available as soon as memblock - * is initialized. - */ -#define for_each_reserved_mem_region(i, p_start, p_end) \ - for (i = 0UL, __next_reserved_mem_region(&i, p_start, p_end); \ - i != (u64)ULLONG_MAX; \ - __next_reserved_mem_region(&i, p_start, p_end)) - -#ifdef CONFIG_MOVABLE_NODE -static inline bool memblock_is_hotpluggable(struct memblock_region *m) -{ - return m->flags & MEMBLOCK_HOTPLUG; -} - -static inline bool __init_memblock movable_node_is_enabled(void) -{ - return movable_node_enabled; -} -#else -static inline bool memblock_is_hotpluggable(struct memblock_region *m) -{ - return false; -} -static inline bool movable_node_is_enabled(void) -{ - return false; -} -#endif - -static inline bool memblock_is_mirror(struct memblock_region *m) -{ - return m->flags & MEMBLOCK_MIRROR; -} - -static inline bool memblock_is_nomap(struct memblock_region *m) -{ - return m->flags & MEMBLOCK_NOMAP; -} - -#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP -int memblock_search_pfn_nid(unsigned long pfn, unsigned long *start_pfn, - unsigned long *end_pfn); -void __next_mem_pfn_range(int *idx, int nid, unsigned long *out_start_pfn, - unsigned long *out_end_pfn, int *out_nid); - -/** - * for_each_mem_pfn_range - early memory pfn range iterator - * @i: an integer used as loop variable - * @nid: node selector, %MAX_NUMNODES for all nodes - * @p_start: ptr to ulong for start pfn of the range, can be %NULL - * @p_end: ptr to ulong for end pfn of the range, can be %NULL - * @p_nid: ptr to int for nid of the range, can be %NULL - * - * Walks over configured memory ranges. - */ -#define for_each_mem_pfn_range(i, nid, p_start, p_end, p_nid) \ - for (i = -1, __next_mem_pfn_range(&i, nid, p_start, p_end, p_nid); \ - i >= 0; __next_mem_pfn_range(&i, nid, p_start, p_end, p_nid)) -#endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */ - -/** - * for_each_free_mem_range - iterate through free memblock areas - * @i: u64 used as loop variable - * @nid: node selector, %NUMA_NO_NODE for all nodes - * @flags: pick from blocks based on memory attributes - * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL - * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL - * @p_nid: ptr to int for nid of the range, can be %NULL - * - * Walks over free (memory && !reserved) areas of memblock. Available as - * soon as memblock is initialized. - */ -#define for_each_free_mem_range(i, nid, flags, p_start, p_end, p_nid) \ - for_each_mem_range(i, &memblock.memory, &memblock.reserved, \ - nid, flags, p_start, p_end, p_nid) - -/** - * for_each_free_mem_range_reverse - rev-iterate through free memblock areas - * @i: u64 used as loop variable - * @nid: node selector, %NUMA_NO_NODE for all nodes - * @flags: pick from blocks based on memory attributes - * @p_start: ptr to phys_addr_t for start address of the range, can be %NULL - * @p_end: ptr to phys_addr_t for end address of the range, can be %NULL - * @p_nid: ptr to int for nid of the range, can be %NULL - * - * Walks over free (memory && !reserved) areas of memblock in reverse - * order. Available as soon as memblock is initialized. - */ -#define for_each_free_mem_range_reverse(i, nid, flags, p_start, p_end, \ - p_nid) \ - for_each_mem_range_rev(i, &memblock.memory, &memblock.reserved, \ - nid, flags, p_start, p_end, p_nid) - -static inline void memblock_set_region_flags(struct memblock_region *r, - unsigned long flags) -{ - r->flags |= flags; -} - -static inline void memblock_clear_region_flags(struct memblock_region *r, - unsigned long flags) -{ - r->flags &= ~flags; -} - -#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP -int memblock_set_node(phys_addr_t base, phys_addr_t size, - struct memblock_type *type, int nid); - -static inline void memblock_set_region_node(struct memblock_region *r, int nid) -{ - r->nid = nid; -} - -static inline int memblock_get_region_node(const struct memblock_region *r) -{ - return r->nid; -} -#else -static inline void memblock_set_region_node(struct memblock_region *r, int nid) -{ -} - -static inline int memblock_get_region_node(const struct memblock_region *r) -{ - return 0; -} -#endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */ - -phys_addr_t memblock_alloc_nid(phys_addr_t size, phys_addr_t align, int nid); -phys_addr_t memblock_alloc_try_nid(phys_addr_t size, phys_addr_t align, int nid); - -phys_addr_t memblock_alloc(phys_addr_t size, phys_addr_t align); - -#ifdef CONFIG_MOVABLE_NODE -/* - * Set the allocation direction to bottom-up or top-down. - */ -static inline void __init memblock_set_bottom_up(bool enable) -{ - memblock.bottom_up = enable; -} - -/* - * Check if the allocation direction is bottom-up or not. - * if this is true, that said, memblock will allocate memory - * in bottom-up direction. - */ -static inline bool memblock_bottom_up(void) -{ - return memblock.bottom_up; -} -#else -static inline void __init memblock_set_bottom_up(bool enable) {} -static inline bool memblock_bottom_up(void) { return false; } -#endif - -/* Flags for memblock_alloc_base() amd __memblock_alloc_base() */ -#define MEMBLOCK_ALLOC_ANYWHERE (~(phys_addr_t)0) -#define MEMBLOCK_ALLOC_ACCESSIBLE 0 - -phys_addr_t __init memblock_alloc_range(phys_addr_t size, phys_addr_t align, - phys_addr_t start, phys_addr_t end, - ulong flags); -phys_addr_t memblock_alloc_base(phys_addr_t size, phys_addr_t align, - phys_addr_t max_addr); -phys_addr_t __memblock_alloc_base(phys_addr_t size, phys_addr_t align, - phys_addr_t max_addr); -phys_addr_t memblock_phys_mem_size(void); -phys_addr_t memblock_reserved_size(void); -phys_addr_t memblock_mem_size(unsigned long limit_pfn); -phys_addr_t memblock_start_of_DRAM(void); -phys_addr_t memblock_end_of_DRAM(void); -void memblock_enforce_memory_limit(phys_addr_t memory_limit); -void memblock_mem_limit_remove_map(phys_addr_t limit); -bool memblock_is_memory(phys_addr_t addr); -int memblock_is_map_memory(phys_addr_t addr); -int memblock_is_region_memory(phys_addr_t base, phys_addr_t size); -bool memblock_is_reserved(phys_addr_t addr); -bool memblock_is_region_reserved(phys_addr_t base, phys_addr_t size); - -extern void __memblock_dump_all(void); - -static inline void memblock_dump_all(void) -{ - if (memblock_debug) - __memblock_dump_all(); -} - -/** - * memblock_set_current_limit - Set the current allocation limit to allow - * limiting allocations to what is currently - * accessible during boot - * @limit: New limit value (physical address) - */ -void memblock_set_current_limit(phys_addr_t limit); - - -phys_addr_t memblock_get_current_limit(void); - -/* - * pfn conversion functions - * - * While the memory MEMBLOCKs should always be page aligned, the reserved - * MEMBLOCKs may not be. This accessor attempt to provide a very clear - * idea of what they return for such non aligned MEMBLOCKs. - */ - -/** - * memblock_region_memory_base_pfn - Return the lowest pfn intersecting with the memory region - * @reg: memblock_region structure - */ -static inline unsigned long memblock_region_memory_base_pfn(const struct memblock_region *reg) -{ - return PFN_UP(reg->base); -} - -/** - * memblock_region_memory_end_pfn - Return the end_pfn this region - * @reg: memblock_region structure - */ -static inline unsigned long memblock_region_memory_end_pfn(const struct memblock_region *reg) -{ - return PFN_DOWN(reg->base + reg->size); -} - -/** - * memblock_region_reserved_base_pfn - Return the lowest pfn intersecting with the reserved region - * @reg: memblock_region structure - */ -static inline unsigned long memblock_region_reserved_base_pfn(const struct memblock_region *reg) -{ - return PFN_DOWN(reg->base); -} - -/** - * memblock_region_reserved_end_pfn - Return the end_pfn this region - * @reg: memblock_region structure - */ -static inline unsigned long memblock_region_reserved_end_pfn(const struct memblock_region *reg) -{ - return PFN_UP(reg->base + reg->size); -} - -#define for_each_memblock(memblock_type, region) \ - for (region = memblock.memblock_type.regions; \ - region < (memblock.memblock_type.regions + memblock.memblock_type.cnt); \ - region++) - -#define for_each_memblock_type(memblock_type, rgn) \ - for (idx = 0, rgn = &memblock_type->regions[0]; \ - idx < memblock_type->cnt; \ - idx++, rgn = &memblock_type->regions[idx]) - -#ifdef CONFIG_MEMTEST -extern void early_memtest(phys_addr_t start, phys_addr_t end); -#else -static inline void early_memtest(phys_addr_t start, phys_addr_t end) -{ -} -#endif - -#else -static inline phys_addr_t memblock_alloc(phys_addr_t size, phys_addr_t align) -{ - return 0; -} - -#endif /* CONFIG_HAVE_MEMBLOCK */ - -#endif /* __KERNEL__ */ - -#endif /* _LINUX_MEMBLOCK_H */ diff --git a/src/linux/include/linux/memcontrol.h b/src/linux/include/linux/memcontrol.h deleted file mode 100644 index 61d20c1..0000000 --- a/src/linux/include/linux/memcontrol.h +++ /dev/null @@ -1,881 +0,0 @@ -/* memcontrol.h - Memory Controller - * - * Copyright IBM Corporation, 2007 - * Author Balbir Singh - * - * Copyright 2007 OpenVZ SWsoft Inc - * Author: Pavel Emelianov - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _LINUX_MEMCONTROL_H -#define _LINUX_MEMCONTROL_H -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct mem_cgroup; -struct page; -struct mm_struct; -struct kmem_cache; - -/* - * The corresponding mem_cgroup_stat_names is defined in mm/memcontrol.c, - * These two lists should keep in accord with each other. - */ -enum mem_cgroup_stat_index { - /* - * For MEM_CONTAINER_TYPE_ALL, usage = pagecache + rss. - */ - MEM_CGROUP_STAT_CACHE, /* # of pages charged as cache */ - MEM_CGROUP_STAT_RSS, /* # of pages charged as anon rss */ - MEM_CGROUP_STAT_RSS_HUGE, /* # of pages charged as anon huge */ - MEM_CGROUP_STAT_FILE_MAPPED, /* # of pages charged as file rss */ - MEM_CGROUP_STAT_DIRTY, /* # of dirty pages in page cache */ - MEM_CGROUP_STAT_WRITEBACK, /* # of pages under writeback */ - MEM_CGROUP_STAT_SWAP, /* # of pages, swapped out */ - MEM_CGROUP_STAT_NSTATS, - /* default hierarchy stats */ - MEMCG_KERNEL_STACK_KB = MEM_CGROUP_STAT_NSTATS, - MEMCG_SLAB_RECLAIMABLE, - MEMCG_SLAB_UNRECLAIMABLE, - MEMCG_SOCK, - MEMCG_NR_STAT, -}; - -struct mem_cgroup_reclaim_cookie { - pg_data_t *pgdat; - int priority; - unsigned int generation; -}; - -enum mem_cgroup_events_index { - MEM_CGROUP_EVENTS_PGPGIN, /* # of pages paged in */ - MEM_CGROUP_EVENTS_PGPGOUT, /* # of pages paged out */ - MEM_CGROUP_EVENTS_PGFAULT, /* # of page-faults */ - MEM_CGROUP_EVENTS_PGMAJFAULT, /* # of major page-faults */ - MEM_CGROUP_EVENTS_NSTATS, - /* default hierarchy events */ - MEMCG_LOW = MEM_CGROUP_EVENTS_NSTATS, - MEMCG_HIGH, - MEMCG_MAX, - MEMCG_OOM, - MEMCG_NR_EVENTS, -}; - -/* - * Per memcg event counter is incremented at every pagein/pageout. With THP, - * it will be incremated by the number of pages. This counter is used for - * for trigger some periodic events. This is straightforward and better - * than using jiffies etc. to handle periodic memcg event. - */ -enum mem_cgroup_events_target { - MEM_CGROUP_TARGET_THRESH, - MEM_CGROUP_TARGET_SOFTLIMIT, - MEM_CGROUP_TARGET_NUMAINFO, - MEM_CGROUP_NTARGETS, -}; - -#ifdef CONFIG_MEMCG - -#define MEM_CGROUP_ID_SHIFT 16 -#define MEM_CGROUP_ID_MAX USHRT_MAX - -struct mem_cgroup_id { - int id; - atomic_t ref; -}; - -struct mem_cgroup_stat_cpu { - long count[MEMCG_NR_STAT]; - unsigned long events[MEMCG_NR_EVENTS]; - unsigned long nr_page_events; - unsigned long targets[MEM_CGROUP_NTARGETS]; -}; - -struct mem_cgroup_reclaim_iter { - struct mem_cgroup *position; - /* scan generation, increased every round-trip */ - unsigned int generation; -}; - -/* - * per-zone information in memory controller. - */ -struct mem_cgroup_per_node { - struct lruvec lruvec; - unsigned long lru_size[NR_LRU_LISTS]; - - struct mem_cgroup_reclaim_iter iter[DEF_PRIORITY + 1]; - - struct rb_node tree_node; /* RB tree node */ - unsigned long usage_in_excess;/* Set to the value by which */ - /* the soft limit is exceeded*/ - bool on_tree; - struct mem_cgroup *memcg; /* Back pointer, we cannot */ - /* use container_of */ -}; - -struct mem_cgroup_threshold { - struct eventfd_ctx *eventfd; - unsigned long threshold; -}; - -/* For threshold */ -struct mem_cgroup_threshold_ary { - /* An array index points to threshold just below or equal to usage. */ - int current_threshold; - /* Size of entries[] */ - unsigned int size; - /* Array of thresholds */ - struct mem_cgroup_threshold entries[0]; -}; - -struct mem_cgroup_thresholds { - /* Primary thresholds array */ - struct mem_cgroup_threshold_ary *primary; - /* - * Spare threshold array. - * This is needed to make mem_cgroup_unregister_event() "never fail". - * It must be able to store at least primary->size - 1 entries. - */ - struct mem_cgroup_threshold_ary *spare; -}; - -enum memcg_kmem_state { - KMEM_NONE, - KMEM_ALLOCATED, - KMEM_ONLINE, -}; - -/* - * The memory controller data structure. The memory controller controls both - * page cache and RSS per cgroup. We would eventually like to provide - * statistics based on the statistics developed by Rik Van Riel for clock-pro, - * to help the administrator determine what knobs to tune. - */ -struct mem_cgroup { - struct cgroup_subsys_state css; - - /* Private memcg ID. Used to ID objects that outlive the cgroup */ - struct mem_cgroup_id id; - - /* Accounted resources */ - struct page_counter memory; - struct page_counter swap; - - /* Legacy consumer-oriented counters */ - struct page_counter memsw; - struct page_counter kmem; - struct page_counter tcpmem; - - /* Normal memory consumption range */ - unsigned long low; - unsigned long high; - - /* Range enforcement for interrupt charges */ - struct work_struct high_work; - - unsigned long soft_limit; - - /* vmpressure notifications */ - struct vmpressure vmpressure; - - /* - * Should the accounting and control be hierarchical, per subtree? - */ - bool use_hierarchy; - - /* protected by memcg_oom_lock */ - bool oom_lock; - int under_oom; - - int swappiness; - /* OOM-Killer disable */ - int oom_kill_disable; - - /* handle for "memory.events" */ - struct cgroup_file events_file; - - /* protect arrays of thresholds */ - struct mutex thresholds_lock; - - /* thresholds for memory usage. RCU-protected */ - struct mem_cgroup_thresholds thresholds; - - /* thresholds for mem+swap usage. RCU-protected */ - struct mem_cgroup_thresholds memsw_thresholds; - - /* For oom notifier event fd */ - struct list_head oom_notify; - - /* - * Should we move charges of a task when a task is moved into this - * mem_cgroup ? And what type of charges should we move ? - */ - unsigned long move_charge_at_immigrate; - /* - * set > 0 if pages under this cgroup are moving to other cgroup. - */ - atomic_t moving_account; - /* taken only while moving_account > 0 */ - spinlock_t move_lock; - struct task_struct *move_lock_task; - unsigned long move_lock_flags; - /* - * percpu counter. - */ - struct mem_cgroup_stat_cpu __percpu *stat; - - unsigned long socket_pressure; - - /* Legacy tcp memory accounting */ - bool tcpmem_active; - int tcpmem_pressure; - -#ifndef CONFIG_SLOB - /* Index in the kmem_cache->memcg_params.memcg_caches array */ - int kmemcg_id; - enum memcg_kmem_state kmem_state; -#endif - - int last_scanned_node; -#if MAX_NUMNODES > 1 - nodemask_t scan_nodes; - atomic_t numainfo_events; - atomic_t numainfo_updating; -#endif - -#ifdef CONFIG_CGROUP_WRITEBACK - struct list_head cgwb_list; - struct wb_domain cgwb_domain; -#endif - - /* List of events which userspace want to receive */ - struct list_head event_list; - spinlock_t event_list_lock; - - struct mem_cgroup_per_node *nodeinfo[0]; - /* WARNING: nodeinfo must be the last member here */ -}; - -extern struct mem_cgroup *root_mem_cgroup; - -static inline bool mem_cgroup_disabled(void) -{ - return !cgroup_subsys_enabled(memory_cgrp_subsys); -} - -/** - * mem_cgroup_events - count memory events against a cgroup - * @memcg: the memory cgroup - * @idx: the event index - * @nr: the number of events to account for - */ -static inline void mem_cgroup_events(struct mem_cgroup *memcg, - enum mem_cgroup_events_index idx, - unsigned int nr) -{ - this_cpu_add(memcg->stat->events[idx], nr); - cgroup_file_notify(&memcg->events_file); -} - -bool mem_cgroup_low(struct mem_cgroup *root, struct mem_cgroup *memcg); - -int mem_cgroup_try_charge(struct page *page, struct mm_struct *mm, - gfp_t gfp_mask, struct mem_cgroup **memcgp, - bool compound); -void mem_cgroup_commit_charge(struct page *page, struct mem_cgroup *memcg, - bool lrucare, bool compound); -void mem_cgroup_cancel_charge(struct page *page, struct mem_cgroup *memcg, - bool compound); -void mem_cgroup_uncharge(struct page *page); -void mem_cgroup_uncharge_list(struct list_head *page_list); - -void mem_cgroup_migrate(struct page *oldpage, struct page *newpage); - -static struct mem_cgroup_per_node * -mem_cgroup_nodeinfo(struct mem_cgroup *memcg, int nid) -{ - return memcg->nodeinfo[nid]; -} - -/** - * mem_cgroup_lruvec - get the lru list vector for a node or a memcg zone - * @node: node of the wanted lruvec - * @memcg: memcg of the wanted lruvec - * - * Returns the lru list vector holding pages for a given @node or a given - * @memcg and @zone. This can be the node lruvec, if the memory controller - * is disabled. - */ -static inline struct lruvec *mem_cgroup_lruvec(struct pglist_data *pgdat, - struct mem_cgroup *memcg) -{ - struct mem_cgroup_per_node *mz; - struct lruvec *lruvec; - - if (mem_cgroup_disabled()) { - lruvec = node_lruvec(pgdat); - goto out; - } - - mz = mem_cgroup_nodeinfo(memcg, pgdat->node_id); - lruvec = &mz->lruvec; -out: - /* - * Since a node can be onlined after the mem_cgroup was created, - * we have to be prepared to initialize lruvec->pgdat here; - * and if offlined then reonlined, we need to reinitialize it. - */ - if (unlikely(lruvec->pgdat != pgdat)) - lruvec->pgdat = pgdat; - return lruvec; -} - -struct lruvec *mem_cgroup_page_lruvec(struct page *, struct pglist_data *); - -bool task_in_mem_cgroup(struct task_struct *task, struct mem_cgroup *memcg); -struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p); - -static inline -struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css){ - return css ? container_of(css, struct mem_cgroup, css) : NULL; -} - -#define mem_cgroup_from_counter(counter, member) \ - container_of(counter, struct mem_cgroup, member) - -struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *, - struct mem_cgroup *, - struct mem_cgroup_reclaim_cookie *); -void mem_cgroup_iter_break(struct mem_cgroup *, struct mem_cgroup *); -int mem_cgroup_scan_tasks(struct mem_cgroup *, - int (*)(struct task_struct *, void *), void *); - -static inline unsigned short mem_cgroup_id(struct mem_cgroup *memcg) -{ - if (mem_cgroup_disabled()) - return 0; - - return memcg->id.id; -} -struct mem_cgroup *mem_cgroup_from_id(unsigned short id); - -/** - * parent_mem_cgroup - find the accounting parent of a memcg - * @memcg: memcg whose parent to find - * - * Returns the parent memcg, or NULL if this is the root or the memory - * controller is in legacy no-hierarchy mode. - */ -static inline struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg) -{ - if (!memcg->memory.parent) - return NULL; - return mem_cgroup_from_counter(memcg->memory.parent, memory); -} - -static inline bool mem_cgroup_is_descendant(struct mem_cgroup *memcg, - struct mem_cgroup *root) -{ - if (root == memcg) - return true; - if (!root->use_hierarchy) - return false; - return cgroup_is_descendant(memcg->css.cgroup, root->css.cgroup); -} - -static inline bool mm_match_cgroup(struct mm_struct *mm, - struct mem_cgroup *memcg) -{ - struct mem_cgroup *task_memcg; - bool match = false; - - rcu_read_lock(); - task_memcg = mem_cgroup_from_task(rcu_dereference(mm->owner)); - if (task_memcg) - match = mem_cgroup_is_descendant(task_memcg, memcg); - rcu_read_unlock(); - return match; -} - -struct cgroup_subsys_state *mem_cgroup_css_from_page(struct page *page); -ino_t page_cgroup_ino(struct page *page); - -static inline bool mem_cgroup_online(struct mem_cgroup *memcg) -{ - if (mem_cgroup_disabled()) - return true; - return !!(memcg->css.flags & CSS_ONLINE); -} - -/* - * For memory reclaim. - */ -int mem_cgroup_select_victim_node(struct mem_cgroup *memcg); - -void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru, - int nr_pages); - -unsigned long mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg, - int nid, unsigned int lru_mask); - -static inline -unsigned long mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list lru) -{ - struct mem_cgroup_per_node *mz; - - mz = container_of(lruvec, struct mem_cgroup_per_node, lruvec); - return mz->lru_size[lru]; -} - -void mem_cgroup_handle_over_high(void); - -unsigned long mem_cgroup_get_limit(struct mem_cgroup *memcg); - -void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, - struct task_struct *p); - -static inline void mem_cgroup_oom_enable(void) -{ - WARN_ON(current->memcg_may_oom); - current->memcg_may_oom = 1; -} - -static inline void mem_cgroup_oom_disable(void) -{ - WARN_ON(!current->memcg_may_oom); - current->memcg_may_oom = 0; -} - -static inline bool task_in_memcg_oom(struct task_struct *p) -{ - return p->memcg_in_oom; -} - -bool mem_cgroup_oom_synchronize(bool wait); - -#ifdef CONFIG_MEMCG_SWAP -extern int do_swap_account; -#endif - -void lock_page_memcg(struct page *page); -void unlock_page_memcg(struct page *page); - -/** - * mem_cgroup_update_page_stat - update page state statistics - * @page: the page - * @idx: page state item to account - * @val: number of pages (positive or negative) - * - * The @page must be locked or the caller must use lock_page_memcg() - * to prevent double accounting when the page is concurrently being - * moved to another memcg: - * - * lock_page(page) or lock_page_memcg(page) - * if (TestClearPageState(page)) - * mem_cgroup_update_page_stat(page, state, -1); - * unlock_page(page) or unlock_page_memcg(page) - */ -static inline void mem_cgroup_update_page_stat(struct page *page, - enum mem_cgroup_stat_index idx, int val) -{ - VM_BUG_ON(!(rcu_read_lock_held() || PageLocked(page))); - - if (page->mem_cgroup) - this_cpu_add(page->mem_cgroup->stat->count[idx], val); -} - -static inline void mem_cgroup_inc_page_stat(struct page *page, - enum mem_cgroup_stat_index idx) -{ - mem_cgroup_update_page_stat(page, idx, 1); -} - -static inline void mem_cgroup_dec_page_stat(struct page *page, - enum mem_cgroup_stat_index idx) -{ - mem_cgroup_update_page_stat(page, idx, -1); -} - -unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order, - gfp_t gfp_mask, - unsigned long *total_scanned); - -static inline void mem_cgroup_count_vm_event(struct mm_struct *mm, - enum vm_event_item idx) -{ - struct mem_cgroup *memcg; - - if (mem_cgroup_disabled()) - return; - - rcu_read_lock(); - memcg = mem_cgroup_from_task(rcu_dereference(mm->owner)); - if (unlikely(!memcg)) - goto out; - - switch (idx) { - case PGFAULT: - this_cpu_inc(memcg->stat->events[MEM_CGROUP_EVENTS_PGFAULT]); - break; - case PGMAJFAULT: - this_cpu_inc(memcg->stat->events[MEM_CGROUP_EVENTS_PGMAJFAULT]); - break; - default: - BUG(); - } -out: - rcu_read_unlock(); -} -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -void mem_cgroup_split_huge_fixup(struct page *head); -#endif - -#else /* CONFIG_MEMCG */ - -#define MEM_CGROUP_ID_SHIFT 0 -#define MEM_CGROUP_ID_MAX 0 - -struct mem_cgroup; - -static inline bool mem_cgroup_disabled(void) -{ - return true; -} - -static inline void mem_cgroup_events(struct mem_cgroup *memcg, - enum mem_cgroup_events_index idx, - unsigned int nr) -{ -} - -static inline bool mem_cgroup_low(struct mem_cgroup *root, - struct mem_cgroup *memcg) -{ - return false; -} - -static inline int mem_cgroup_try_charge(struct page *page, struct mm_struct *mm, - gfp_t gfp_mask, - struct mem_cgroup **memcgp, - bool compound) -{ - *memcgp = NULL; - return 0; -} - -static inline void mem_cgroup_commit_charge(struct page *page, - struct mem_cgroup *memcg, - bool lrucare, bool compound) -{ -} - -static inline void mem_cgroup_cancel_charge(struct page *page, - struct mem_cgroup *memcg, - bool compound) -{ -} - -static inline void mem_cgroup_uncharge(struct page *page) -{ -} - -static inline void mem_cgroup_uncharge_list(struct list_head *page_list) -{ -} - -static inline void mem_cgroup_migrate(struct page *old, struct page *new) -{ -} - -static inline struct lruvec *mem_cgroup_lruvec(struct pglist_data *pgdat, - struct mem_cgroup *memcg) -{ - return node_lruvec(pgdat); -} - -static inline struct lruvec *mem_cgroup_page_lruvec(struct page *page, - struct pglist_data *pgdat) -{ - return &pgdat->lruvec; -} - -static inline bool mm_match_cgroup(struct mm_struct *mm, - struct mem_cgroup *memcg) -{ - return true; -} - -static inline bool task_in_mem_cgroup(struct task_struct *task, - const struct mem_cgroup *memcg) -{ - return true; -} - -static inline struct mem_cgroup * -mem_cgroup_iter(struct mem_cgroup *root, - struct mem_cgroup *prev, - struct mem_cgroup_reclaim_cookie *reclaim) -{ - return NULL; -} - -static inline void mem_cgroup_iter_break(struct mem_cgroup *root, - struct mem_cgroup *prev) -{ -} - -static inline int mem_cgroup_scan_tasks(struct mem_cgroup *memcg, - int (*fn)(struct task_struct *, void *), void *arg) -{ - return 0; -} - -static inline unsigned short mem_cgroup_id(struct mem_cgroup *memcg) -{ - return 0; -} - -static inline struct mem_cgroup *mem_cgroup_from_id(unsigned short id) -{ - WARN_ON_ONCE(id); - /* XXX: This should always return root_mem_cgroup */ - return NULL; -} - -static inline bool mem_cgroup_online(struct mem_cgroup *memcg) -{ - return true; -} - -static inline unsigned long -mem_cgroup_get_lru_size(struct lruvec *lruvec, enum lru_list lru) -{ - return 0; -} - -static inline unsigned long -mem_cgroup_node_nr_lru_pages(struct mem_cgroup *memcg, - int nid, unsigned int lru_mask) -{ - return 0; -} - -static inline unsigned long mem_cgroup_get_limit(struct mem_cgroup *memcg) -{ - return 0; -} - -static inline void -mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p) -{ -} - -static inline void lock_page_memcg(struct page *page) -{ -} - -static inline void unlock_page_memcg(struct page *page) -{ -} - -static inline void mem_cgroup_handle_over_high(void) -{ -} - -static inline void mem_cgroup_oom_enable(void) -{ -} - -static inline void mem_cgroup_oom_disable(void) -{ -} - -static inline bool task_in_memcg_oom(struct task_struct *p) -{ - return false; -} - -static inline bool mem_cgroup_oom_synchronize(bool wait) -{ - return false; -} - -static inline void mem_cgroup_inc_page_stat(struct page *page, - enum mem_cgroup_stat_index idx) -{ -} - -static inline void mem_cgroup_dec_page_stat(struct page *page, - enum mem_cgroup_stat_index idx) -{ -} - -static inline -unsigned long mem_cgroup_soft_limit_reclaim(pg_data_t *pgdat, int order, - gfp_t gfp_mask, - unsigned long *total_scanned) -{ - return 0; -} - -static inline void mem_cgroup_split_huge_fixup(struct page *head) -{ -} - -static inline -void mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx) -{ -} -#endif /* CONFIG_MEMCG */ - -#ifdef CONFIG_CGROUP_WRITEBACK - -struct list_head *mem_cgroup_cgwb_list(struct mem_cgroup *memcg); -struct wb_domain *mem_cgroup_wb_domain(struct bdi_writeback *wb); -void mem_cgroup_wb_stats(struct bdi_writeback *wb, unsigned long *pfilepages, - unsigned long *pheadroom, unsigned long *pdirty, - unsigned long *pwriteback); - -#else /* CONFIG_CGROUP_WRITEBACK */ - -static inline struct wb_domain *mem_cgroup_wb_domain(struct bdi_writeback *wb) -{ - return NULL; -} - -static inline void mem_cgroup_wb_stats(struct bdi_writeback *wb, - unsigned long *pfilepages, - unsigned long *pheadroom, - unsigned long *pdirty, - unsigned long *pwriteback) -{ -} - -#endif /* CONFIG_CGROUP_WRITEBACK */ - -struct sock; -bool mem_cgroup_charge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages); -void mem_cgroup_uncharge_skmem(struct mem_cgroup *memcg, unsigned int nr_pages); -#ifdef CONFIG_MEMCG -extern struct static_key_false memcg_sockets_enabled_key; -#define mem_cgroup_sockets_enabled static_branch_unlikely(&memcg_sockets_enabled_key) -void mem_cgroup_sk_alloc(struct sock *sk); -void mem_cgroup_sk_free(struct sock *sk); -static inline bool mem_cgroup_under_socket_pressure(struct mem_cgroup *memcg) -{ - if (!cgroup_subsys_on_dfl(memory_cgrp_subsys) && memcg->tcpmem_pressure) - return true; - do { - if (time_before(jiffies, memcg->socket_pressure)) - return true; - } while ((memcg = parent_mem_cgroup(memcg))); - return false; -} -#else -#define mem_cgroup_sockets_enabled 0 -static inline void mem_cgroup_sk_alloc(struct sock *sk) { }; -static inline void mem_cgroup_sk_free(struct sock *sk) { }; -static inline bool mem_cgroup_under_socket_pressure(struct mem_cgroup *memcg) -{ - return false; -} -#endif - -struct kmem_cache *memcg_kmem_get_cache(struct kmem_cache *cachep); -void memcg_kmem_put_cache(struct kmem_cache *cachep); -int memcg_kmem_charge_memcg(struct page *page, gfp_t gfp, int order, - struct mem_cgroup *memcg); -int memcg_kmem_charge(struct page *page, gfp_t gfp, int order); -void memcg_kmem_uncharge(struct page *page, int order); - -#if defined(CONFIG_MEMCG) && !defined(CONFIG_SLOB) -extern struct static_key_false memcg_kmem_enabled_key; - -extern int memcg_nr_cache_ids; -void memcg_get_cache_ids(void); -void memcg_put_cache_ids(void); - -/* - * Helper macro to loop through all memcg-specific caches. Callers must still - * check if the cache is valid (it is either valid or NULL). - * the slab_mutex must be held when looping through those caches - */ -#define for_each_memcg_cache_index(_idx) \ - for ((_idx) = 0; (_idx) < memcg_nr_cache_ids; (_idx)++) - -static inline bool memcg_kmem_enabled(void) -{ - return static_branch_unlikely(&memcg_kmem_enabled_key); -} - -/* - * helper for accessing a memcg's index. It will be used as an index in the - * child cache array in kmem_cache, and also to derive its name. This function - * will return -1 when this is not a kmem-limited memcg. - */ -static inline int memcg_cache_id(struct mem_cgroup *memcg) -{ - return memcg ? memcg->kmemcg_id : -1; -} - -/** - * memcg_kmem_update_page_stat - update kmem page state statistics - * @page: the page - * @idx: page state item to account - * @val: number of pages (positive or negative) - */ -static inline void memcg_kmem_update_page_stat(struct page *page, - enum mem_cgroup_stat_index idx, int val) -{ - if (memcg_kmem_enabled() && page->mem_cgroup) - this_cpu_add(page->mem_cgroup->stat->count[idx], val); -} - -#else -#define for_each_memcg_cache_index(_idx) \ - for (; NULL; ) - -static inline bool memcg_kmem_enabled(void) -{ - return false; -} - -static inline int memcg_cache_id(struct mem_cgroup *memcg) -{ - return -1; -} - -static inline void memcg_get_cache_ids(void) -{ -} - -static inline void memcg_put_cache_ids(void) -{ -} - -static inline void memcg_kmem_update_page_stat(struct page *page, - enum mem_cgroup_stat_index idx, int val) -{ -} -#endif /* CONFIG_MEMCG && !CONFIG_SLOB */ - -#endif /* _LINUX_MEMCONTROL_H */ diff --git a/src/linux/include/linux/memory.h b/src/linux/include/linux/memory.h deleted file mode 100644 index 093607f..0000000 --- a/src/linux/include/linux/memory.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * include/linux/memory.h - generic memory definition - * - * This is mainly for topological representation. We define the - * basic "struct memory_block" here, which can be embedded in per-arch - * definitions or NUMA information. - * - * Basic handling of the devices is done in drivers/base/memory.c - * and system devices are handled in drivers/base/sys.c. - * - * Memory block are exported via sysfs in the class/memory/devices/ - * directory. - * - */ -#ifndef _LINUX_MEMORY_H_ -#define _LINUX_MEMORY_H_ - -#include -#include -#include -#include - -#define MIN_MEMORY_BLOCK_SIZE (1UL << SECTION_SIZE_BITS) - -struct memory_block { - unsigned long start_section_nr; - unsigned long end_section_nr; - unsigned long state; /* serialized by the dev->lock */ - int section_count; /* serialized by mem_sysfs_mutex */ - int online_type; /* for passing data to online routine */ - int phys_device; /* to which fru does this belong? */ - void *hw; /* optional pointer to fw/hw data */ - int (*phys_callback)(struct memory_block *); - struct device dev; -}; - -int arch_get_memory_phys_device(unsigned long start_pfn); -unsigned long memory_block_size_bytes(void); - -/* These states are exposed to userspace as text strings in sysfs */ -#define MEM_ONLINE (1<<0) /* exposed to userspace */ -#define MEM_GOING_OFFLINE (1<<1) /* exposed to userspace */ -#define MEM_OFFLINE (1<<2) /* exposed to userspace */ -#define MEM_GOING_ONLINE (1<<3) -#define MEM_CANCEL_ONLINE (1<<4) -#define MEM_CANCEL_OFFLINE (1<<5) - -struct memory_notify { - unsigned long start_pfn; - unsigned long nr_pages; - int status_change_nid_normal; - int status_change_nid_high; - int status_change_nid; -}; - -/* - * During pageblock isolation, count the number of pages within the - * range [start_pfn, start_pfn + nr_pages) which are owned by code - * in the notifier chain. - */ -#define MEM_ISOLATE_COUNT (1<<0) - -struct memory_isolate_notify { - unsigned long start_pfn; /* Start of range to check */ - unsigned int nr_pages; /* # pages in range to check */ - unsigned int pages_found; /* # pages owned found by callbacks */ -}; - -struct notifier_block; -struct mem_section; - -/* - * Priorities for the hotplug memory callback routines (stored in decreasing - * order in the callback chain) - */ -#define SLAB_CALLBACK_PRI 1 -#define IPC_CALLBACK_PRI 10 - -#ifndef CONFIG_MEMORY_HOTPLUG_SPARSE -static inline int memory_dev_init(void) -{ - return 0; -} -static inline int register_memory_notifier(struct notifier_block *nb) -{ - return 0; -} -static inline void unregister_memory_notifier(struct notifier_block *nb) -{ -} -static inline int memory_notify(unsigned long val, void *v) -{ - return 0; -} -static inline int register_memory_isolate_notifier(struct notifier_block *nb) -{ - return 0; -} -static inline void unregister_memory_isolate_notifier(struct notifier_block *nb) -{ -} -static inline int memory_isolate_notify(unsigned long val, void *v) -{ - return 0; -} -#else -extern int register_memory_notifier(struct notifier_block *nb); -extern void unregister_memory_notifier(struct notifier_block *nb); -extern int register_memory_isolate_notifier(struct notifier_block *nb); -extern void unregister_memory_isolate_notifier(struct notifier_block *nb); -extern int register_new_memory(int, struct mem_section *); -extern int memory_block_change_state(struct memory_block *mem, - unsigned long to_state, - unsigned long from_state_req); -#ifdef CONFIG_MEMORY_HOTREMOVE -extern int unregister_memory_section(struct mem_section *); -#endif -extern int memory_dev_init(void); -extern int memory_notify(unsigned long val, void *v); -extern int memory_isolate_notify(unsigned long val, void *v); -extern struct memory_block *find_memory_block_hinted(struct mem_section *, - struct memory_block *); -extern struct memory_block *find_memory_block(struct mem_section *); -#define CONFIG_MEM_BLOCK_SIZE (PAGES_PER_SECTION< -#include -#include -#include - -struct page; -struct zone; -struct pglist_data; -struct mem_section; -struct memory_block; -struct resource; - -#ifdef CONFIG_MEMORY_HOTPLUG - -/* - * Types for free bootmem stored in page->lru.next. These have to be in - * some random range in unsigned long space for debugging purposes. - */ -enum { - MEMORY_HOTPLUG_MIN_BOOTMEM_TYPE = 12, - SECTION_INFO = MEMORY_HOTPLUG_MIN_BOOTMEM_TYPE, - MIX_SECTION_INFO, - NODE_INFO, - MEMORY_HOTPLUG_MAX_BOOTMEM_TYPE = NODE_INFO, -}; - -/* Types for control the zone type of onlined and offlined memory */ -enum { - MMOP_OFFLINE = -1, - MMOP_ONLINE_KEEP, - MMOP_ONLINE_KERNEL, - MMOP_ONLINE_MOVABLE, -}; - -/* - * pgdat resizing functions - */ -static inline -void pgdat_resize_lock(struct pglist_data *pgdat, unsigned long *flags) -{ - spin_lock_irqsave(&pgdat->node_size_lock, *flags); -} -static inline -void pgdat_resize_unlock(struct pglist_data *pgdat, unsigned long *flags) -{ - spin_unlock_irqrestore(&pgdat->node_size_lock, *flags); -} -static inline -void pgdat_resize_init(struct pglist_data *pgdat) -{ - spin_lock_init(&pgdat->node_size_lock); -} -/* - * Zone resizing functions - * - * Note: any attempt to resize a zone should has pgdat_resize_lock() - * zone_span_writelock() both held. This ensure the size of a zone - * can't be changed while pgdat_resize_lock() held. - */ -static inline unsigned zone_span_seqbegin(struct zone *zone) -{ - return read_seqbegin(&zone->span_seqlock); -} -static inline int zone_span_seqretry(struct zone *zone, unsigned iv) -{ - return read_seqretry(&zone->span_seqlock, iv); -} -static inline void zone_span_writelock(struct zone *zone) -{ - write_seqlock(&zone->span_seqlock); -} -static inline void zone_span_writeunlock(struct zone *zone) -{ - write_sequnlock(&zone->span_seqlock); -} -static inline void zone_seqlock_init(struct zone *zone) -{ - seqlock_init(&zone->span_seqlock); -} -extern int zone_grow_free_lists(struct zone *zone, unsigned long new_nr_pages); -extern int zone_grow_waitqueues(struct zone *zone, unsigned long nr_pages); -extern int add_one_highpage(struct page *page, int pfn, int bad_ppro); -/* VM interface that may be used by firmware interface */ -extern int online_pages(unsigned long, unsigned long, int); -extern int test_pages_in_a_zone(unsigned long, unsigned long); -extern void __offline_isolated_pages(unsigned long, unsigned long); - -typedef void (*online_page_callback_t)(struct page *page); - -extern int set_online_page_callback(online_page_callback_t callback); -extern int restore_online_page_callback(online_page_callback_t callback); - -extern void __online_page_set_limits(struct page *page); -extern void __online_page_increment_counters(struct page *page); -extern void __online_page_free(struct page *page); - -extern int try_online_node(int nid); - -extern bool memhp_auto_online; - -#ifdef CONFIG_MEMORY_HOTREMOVE -extern bool is_pageblock_removable_nolock(struct page *page); -extern int arch_remove_memory(u64 start, u64 size); -extern int __remove_pages(struct zone *zone, unsigned long start_pfn, - unsigned long nr_pages); -#endif /* CONFIG_MEMORY_HOTREMOVE */ - -/* reasonably generic interface to expand the physical pages in a zone */ -extern int __add_pages(int nid, struct zone *zone, unsigned long start_pfn, - unsigned long nr_pages); - -#ifdef CONFIG_NUMA -extern int memory_add_physaddr_to_nid(u64 start); -#else -static inline int memory_add_physaddr_to_nid(u64 start) -{ - return 0; -} -#endif - -#ifdef CONFIG_HAVE_ARCH_NODEDATA_EXTENSION -/* - * For supporting node-hotadd, we have to allocate a new pgdat. - * - * If an arch has generic style NODE_DATA(), - * node_data[nid] = kzalloc() works well. But it depends on the architecture. - * - * In general, generic_alloc_nodedata() is used. - * Now, arch_free_nodedata() is just defined for error path of node_hot_add. - * - */ -extern pg_data_t *arch_alloc_nodedata(int nid); -extern void arch_free_nodedata(pg_data_t *pgdat); -extern void arch_refresh_nodedata(int nid, pg_data_t *pgdat); - -#else /* CONFIG_HAVE_ARCH_NODEDATA_EXTENSION */ - -#define arch_alloc_nodedata(nid) generic_alloc_nodedata(nid) -#define arch_free_nodedata(pgdat) generic_free_nodedata(pgdat) - -#ifdef CONFIG_NUMA -/* - * If ARCH_HAS_NODEDATA_EXTENSION=n, this func is used to allocate pgdat. - * XXX: kmalloc_node() can't work well to get new node's memory at this time. - * Because, pgdat for the new node is not allocated/initialized yet itself. - * To use new node's memory, more consideration will be necessary. - */ -#define generic_alloc_nodedata(nid) \ -({ \ - kzalloc(sizeof(pg_data_t), GFP_KERNEL); \ -}) -/* - * This definition is just for error path in node hotadd. - * For node hotremove, we have to replace this. - */ -#define generic_free_nodedata(pgdat) kfree(pgdat) - -extern pg_data_t *node_data[]; -static inline void arch_refresh_nodedata(int nid, pg_data_t *pgdat) -{ - node_data[nid] = pgdat; -} - -#else /* !CONFIG_NUMA */ - -/* never called */ -static inline pg_data_t *generic_alloc_nodedata(int nid) -{ - BUG(); - return NULL; -} -static inline void generic_free_nodedata(pg_data_t *pgdat) -{ -} -static inline void arch_refresh_nodedata(int nid, pg_data_t *pgdat) -{ -} -#endif /* CONFIG_NUMA */ -#endif /* CONFIG_HAVE_ARCH_NODEDATA_EXTENSION */ - -#ifdef CONFIG_HAVE_BOOTMEM_INFO_NODE -extern void __init register_page_bootmem_info_node(struct pglist_data *pgdat); -#else -static inline void register_page_bootmem_info_node(struct pglist_data *pgdat) -{ -} -#endif -extern void put_page_bootmem(struct page *page); -extern void get_page_bootmem(unsigned long ingo, struct page *page, - unsigned long type); - -void get_online_mems(void); -void put_online_mems(void); - -void mem_hotplug_begin(void); -void mem_hotplug_done(void); - -extern void set_zone_contiguous(struct zone *zone); -extern void clear_zone_contiguous(struct zone *zone); - -#else /* ! CONFIG_MEMORY_HOTPLUG */ -/* - * Stub functions for when hotplug is off - */ -static inline void pgdat_resize_lock(struct pglist_data *p, unsigned long *f) {} -static inline void pgdat_resize_unlock(struct pglist_data *p, unsigned long *f) {} -static inline void pgdat_resize_init(struct pglist_data *pgdat) {} - -static inline unsigned zone_span_seqbegin(struct zone *zone) -{ - return 0; -} -static inline int zone_span_seqretry(struct zone *zone, unsigned iv) -{ - return 0; -} -static inline void zone_span_writelock(struct zone *zone) {} -static inline void zone_span_writeunlock(struct zone *zone) {} -static inline void zone_seqlock_init(struct zone *zone) {} - -static inline int mhp_notimplemented(const char *func) -{ - printk(KERN_WARNING "%s() called, with CONFIG_MEMORY_HOTPLUG disabled\n", func); - dump_stack(); - return -ENOSYS; -} - -static inline void register_page_bootmem_info_node(struct pglist_data *pgdat) -{ -} - -static inline int try_online_node(int nid) -{ - return 0; -} - -static inline void get_online_mems(void) {} -static inline void put_online_mems(void) {} - -static inline void mem_hotplug_begin(void) {} -static inline void mem_hotplug_done(void) {} - -#endif /* ! CONFIG_MEMORY_HOTPLUG */ - -#ifdef CONFIG_MEMORY_HOTREMOVE - -extern bool is_mem_section_removable(unsigned long pfn, unsigned long nr_pages); -extern void try_offline_node(int nid); -extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages); -extern void remove_memory(int nid, u64 start, u64 size); - -#else -static inline bool is_mem_section_removable(unsigned long pfn, - unsigned long nr_pages) -{ - return false; -} - -static inline void try_offline_node(int nid) {} - -static inline int offline_pages(unsigned long start_pfn, unsigned long nr_pages) -{ - return -EINVAL; -} - -static inline void remove_memory(int nid, u64 start, u64 size) {} -#endif /* CONFIG_MEMORY_HOTREMOVE */ - -extern int walk_memory_range(unsigned long start_pfn, unsigned long end_pfn, - void *arg, int (*func)(struct memory_block *, void *)); -extern int add_memory(int nid, u64 start, u64 size); -extern int add_memory_resource(int nid, struct resource *resource, bool online); -extern int zone_for_memory(int nid, u64 start, u64 size, int zone_default, - bool for_device); -extern int arch_add_memory(int nid, u64 start, u64 size, bool for_device); -extern int offline_pages(unsigned long start_pfn, unsigned long nr_pages); -extern bool is_memblock_offlined(struct memory_block *mem); -extern void remove_memory(int nid, u64 start, u64 size); -extern int sparse_add_one_section(struct zone *zone, unsigned long start_pfn); -extern void sparse_remove_one_section(struct zone *zone, struct mem_section *ms, - unsigned long map_offset); -extern struct page *sparse_decode_mem_map(unsigned long coded_mem_map, - unsigned long pnum); -extern int zone_can_shift(unsigned long pfn, unsigned long nr_pages, - enum zone_type target); - -#endif /* __LINUX_MEMORY_HOTPLUG_H */ diff --git a/src/linux/include/linux/mempolicy.h b/src/linux/include/linux/mempolicy.h deleted file mode 100644 index 5e5b296..0000000 --- a/src/linux/include/linux/mempolicy.h +++ /dev/null @@ -1,305 +0,0 @@ -/* - * NUMA memory policies for Linux. - * Copyright 2003,2004 Andi Kleen SuSE Labs - */ -#ifndef _LINUX_MEMPOLICY_H -#define _LINUX_MEMPOLICY_H 1 - - -#include -#include -#include -#include -#include -#include -#include - -struct mm_struct; - -#ifdef CONFIG_NUMA - -/* - * Describe a memory policy. - * - * A mempolicy can be either associated with a process or with a VMA. - * For VMA related allocations the VMA policy is preferred, otherwise - * the process policy is used. Interrupts ignore the memory policy - * of the current process. - * - * Locking policy for interlave: - * In process context there is no locking because only the process accesses - * its own state. All vma manipulation is somewhat protected by a down_read on - * mmap_sem. - * - * Freeing policy: - * Mempolicy objects are reference counted. A mempolicy will be freed when - * mpol_put() decrements the reference count to zero. - * - * Duplicating policy objects: - * mpol_dup() allocates a new mempolicy and copies the specified mempolicy - * to the new storage. The reference count of the new object is initialized - * to 1, representing the caller of mpol_dup(). - */ -struct mempolicy { - atomic_t refcnt; - unsigned short mode; /* See MPOL_* above */ - unsigned short flags; /* See set_mempolicy() MPOL_F_* above */ - union { - short preferred_node; /* preferred */ - nodemask_t nodes; /* interleave/bind */ - /* undefined for default */ - } v; - union { - nodemask_t cpuset_mems_allowed; /* relative to these nodes */ - nodemask_t user_nodemask; /* nodemask passed by user */ - } w; -}; - -/* - * Support for managing mempolicy data objects (clone, copy, destroy) - * The default fast path of a NULL MPOL_DEFAULT policy is always inlined. - */ - -extern void __mpol_put(struct mempolicy *pol); -static inline void mpol_put(struct mempolicy *pol) -{ - if (pol) - __mpol_put(pol); -} - -/* - * Does mempolicy pol need explicit unref after use? - * Currently only needed for shared policies. - */ -static inline int mpol_needs_cond_ref(struct mempolicy *pol) -{ - return (pol && (pol->flags & MPOL_F_SHARED)); -} - -static inline void mpol_cond_put(struct mempolicy *pol) -{ - if (mpol_needs_cond_ref(pol)) - __mpol_put(pol); -} - -extern struct mempolicy *__mpol_dup(struct mempolicy *pol); -static inline struct mempolicy *mpol_dup(struct mempolicy *pol) -{ - if (pol) - pol = __mpol_dup(pol); - return pol; -} - -#define vma_policy(vma) ((vma)->vm_policy) - -static inline void mpol_get(struct mempolicy *pol) -{ - if (pol) - atomic_inc(&pol->refcnt); -} - -extern bool __mpol_equal(struct mempolicy *a, struct mempolicy *b); -static inline bool mpol_equal(struct mempolicy *a, struct mempolicy *b) -{ - if (a == b) - return true; - return __mpol_equal(a, b); -} - -/* - * Tree of shared policies for a shared memory region. - * Maintain the policies in a pseudo mm that contains vmas. The vmas - * carry the policy. As a special twist the pseudo mm is indexed in pages, not - * bytes, so that we can work with shared memory segments bigger than - * unsigned long. - */ - -struct sp_node { - struct rb_node nd; - unsigned long start, end; - struct mempolicy *policy; -}; - -struct shared_policy { - struct rb_root root; - rwlock_t lock; -}; - -int vma_dup_policy(struct vm_area_struct *src, struct vm_area_struct *dst); -void mpol_shared_policy_init(struct shared_policy *sp, struct mempolicy *mpol); -int mpol_set_shared_policy(struct shared_policy *info, - struct vm_area_struct *vma, - struct mempolicy *new); -void mpol_free_shared_policy(struct shared_policy *p); -struct mempolicy *mpol_shared_policy_lookup(struct shared_policy *sp, - unsigned long idx); - -struct mempolicy *get_task_policy(struct task_struct *p); -struct mempolicy *__get_vma_policy(struct vm_area_struct *vma, - unsigned long addr); -bool vma_policy_mof(struct vm_area_struct *vma); - -extern void numa_default_policy(void); -extern void numa_policy_init(void); -extern void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new, - enum mpol_rebind_step step); -extern void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new); - -extern struct zonelist *huge_zonelist(struct vm_area_struct *vma, - unsigned long addr, gfp_t gfp_flags, - struct mempolicy **mpol, nodemask_t **nodemask); -extern bool init_nodemask_of_mempolicy(nodemask_t *mask); -extern bool mempolicy_nodemask_intersects(struct task_struct *tsk, - const nodemask_t *mask); -extern unsigned int mempolicy_slab_node(void); - -extern enum zone_type policy_zone; - -static inline void check_highest_zone(enum zone_type k) -{ - if (k > policy_zone && k != ZONE_MOVABLE) - policy_zone = k; -} - -int do_migrate_pages(struct mm_struct *mm, const nodemask_t *from, - const nodemask_t *to, int flags); - - -#ifdef CONFIG_TMPFS -extern int mpol_parse_str(char *str, struct mempolicy **mpol); -#endif - -extern void mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol); - -/* Check if a vma is migratable */ -static inline bool vma_migratable(struct vm_area_struct *vma) -{ - if (vma->vm_flags & (VM_IO | VM_PFNMAP)) - return false; - -#ifndef CONFIG_ARCH_ENABLE_HUGEPAGE_MIGRATION - if (vma->vm_flags & VM_HUGETLB) - return false; -#endif - - /* - * Migration allocates pages in the highest zone. If we cannot - * do so then migration (at least from node to node) is not - * possible. - */ - if (vma->vm_file && - gfp_zone(mapping_gfp_mask(vma->vm_file->f_mapping)) - < policy_zone) - return false; - return true; -} - -extern int mpol_misplaced(struct page *, struct vm_area_struct *, unsigned long); -extern void mpol_put_task_policy(struct task_struct *); - -#else - -struct mempolicy {}; - -static inline bool mpol_equal(struct mempolicy *a, struct mempolicy *b) -{ - return true; -} - -static inline void mpol_put(struct mempolicy *p) -{ -} - -static inline void mpol_cond_put(struct mempolicy *pol) -{ -} - -static inline void mpol_get(struct mempolicy *pol) -{ -} - -struct shared_policy {}; - -static inline void mpol_shared_policy_init(struct shared_policy *sp, - struct mempolicy *mpol) -{ -} - -static inline void mpol_free_shared_policy(struct shared_policy *p) -{ -} - -static inline struct mempolicy * -mpol_shared_policy_lookup(struct shared_policy *sp, unsigned long idx) -{ - return NULL; -} - -#define vma_policy(vma) NULL - -static inline int -vma_dup_policy(struct vm_area_struct *src, struct vm_area_struct *dst) -{ - return 0; -} - -static inline void numa_policy_init(void) -{ -} - -static inline void numa_default_policy(void) -{ -} - -static inline void mpol_rebind_task(struct task_struct *tsk, - const nodemask_t *new, - enum mpol_rebind_step step) -{ -} - -static inline void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new) -{ -} - -static inline struct zonelist *huge_zonelist(struct vm_area_struct *vma, - unsigned long addr, gfp_t gfp_flags, - struct mempolicy **mpol, nodemask_t **nodemask) -{ - *mpol = NULL; - *nodemask = NULL; - return node_zonelist(0, gfp_flags); -} - -static inline bool init_nodemask_of_mempolicy(nodemask_t *m) -{ - return false; -} - -static inline int do_migrate_pages(struct mm_struct *mm, const nodemask_t *from, - const nodemask_t *to, int flags) -{ - return 0; -} - -static inline void check_highest_zone(int k) -{ -} - -#ifdef CONFIG_TMPFS -static inline int mpol_parse_str(char *str, struct mempolicy **mpol) -{ - return 1; /* error */ -} -#endif - -static inline int mpol_misplaced(struct page *page, struct vm_area_struct *vma, - unsigned long address) -{ - return -1; /* no node preference */ -} - -static inline void mpol_put_task_policy(struct task_struct *task) -{ -} -#endif /* CONFIG_NUMA */ -#endif diff --git a/src/linux/include/linux/mempool.h b/src/linux/include/linux/mempool.h deleted file mode 100644 index b1086c9..0000000 --- a/src/linux/include/linux/mempool.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * memory buffer pool support - */ -#ifndef _LINUX_MEMPOOL_H -#define _LINUX_MEMPOOL_H - -#include -#include - -struct kmem_cache; - -typedef void * (mempool_alloc_t)(gfp_t gfp_mask, void *pool_data); -typedef void (mempool_free_t)(void *element, void *pool_data); - -typedef struct mempool_s { - spinlock_t lock; - int min_nr; /* nr of elements at *elements */ - int curr_nr; /* Current nr of elements at *elements */ - void **elements; - - void *pool_data; - mempool_alloc_t *alloc; - mempool_free_t *free; - wait_queue_head_t wait; -} mempool_t; - -extern mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn, - mempool_free_t *free_fn, void *pool_data); -extern mempool_t *mempool_create_node(int min_nr, mempool_alloc_t *alloc_fn, - mempool_free_t *free_fn, void *pool_data, - gfp_t gfp_mask, int nid); - -extern int mempool_resize(mempool_t *pool, int new_min_nr); -extern void mempool_destroy(mempool_t *pool); -extern void *mempool_alloc(mempool_t *pool, gfp_t gfp_mask) __malloc; -extern void mempool_free(void *element, mempool_t *pool); - -/* - * A mempool_alloc_t and mempool_free_t that get the memory from - * a slab cache that is passed in through pool_data. - * Note: the slab cache may not have a ctor function. - */ -void *mempool_alloc_slab(gfp_t gfp_mask, void *pool_data); -void mempool_free_slab(void *element, void *pool_data); -static inline mempool_t * -mempool_create_slab_pool(int min_nr, struct kmem_cache *kc) -{ - return mempool_create(min_nr, mempool_alloc_slab, mempool_free_slab, - (void *) kc); -} - -/* - * a mempool_alloc_t and a mempool_free_t to kmalloc and kfree the - * amount of memory specified by pool_data - */ -void *mempool_kmalloc(gfp_t gfp_mask, void *pool_data); -void mempool_kfree(void *element, void *pool_data); -static inline mempool_t *mempool_create_kmalloc_pool(int min_nr, size_t size) -{ - return mempool_create(min_nr, mempool_kmalloc, mempool_kfree, - (void *) size); -} - -/* - * A mempool_alloc_t and mempool_free_t for a simple page allocator that - * allocates pages of the order specified by pool_data - */ -void *mempool_alloc_pages(gfp_t gfp_mask, void *pool_data); -void mempool_free_pages(void *element, void *pool_data); -static inline mempool_t *mempool_create_page_pool(int min_nr, int order) -{ - return mempool_create(min_nr, mempool_alloc_pages, mempool_free_pages, - (void *)(long)order); -} - -#endif /* _LINUX_MEMPOOL_H */ diff --git a/src/linux/include/linux/memremap.h b/src/linux/include/linux/memremap.h deleted file mode 100644 index 9341619..0000000 --- a/src/linux/include/linux/memremap.h +++ /dev/null @@ -1,114 +0,0 @@ -#ifndef _LINUX_MEMREMAP_H_ -#define _LINUX_MEMREMAP_H_ -#include -#include -#include - -struct resource; -struct device; - -/** - * struct vmem_altmap - pre-allocated storage for vmemmap_populate - * @base_pfn: base of the entire dev_pagemap mapping - * @reserve: pages mapped, but reserved for driver use (relative to @base) - * @free: free pages set aside in the mapping for memmap storage - * @align: pages reserved to meet allocation alignments - * @alloc: track pages consumed, private to vmemmap_populate() - */ -struct vmem_altmap { - const unsigned long base_pfn; - const unsigned long reserve; - unsigned long free; - unsigned long align; - unsigned long alloc; -}; - -unsigned long vmem_altmap_offset(struct vmem_altmap *altmap); -void vmem_altmap_free(struct vmem_altmap *altmap, unsigned long nr_pfns); - -#ifdef CONFIG_ZONE_DEVICE -struct vmem_altmap *to_vmem_altmap(unsigned long memmap_start); -#else -static inline struct vmem_altmap *to_vmem_altmap(unsigned long memmap_start) -{ - return NULL; -} -#endif - -/** - * struct dev_pagemap - metadata for ZONE_DEVICE mappings - * @altmap: pre-allocated/reserved memory for vmemmap allocations - * @res: physical address range covered by @ref - * @ref: reference count that pins the devm_memremap_pages() mapping - * @dev: host device of the mapping for debug - */ -struct dev_pagemap { - struct vmem_altmap *altmap; - const struct resource *res; - struct percpu_ref *ref; - struct device *dev; -}; - -#ifdef CONFIG_ZONE_DEVICE -void *devm_memremap_pages(struct device *dev, struct resource *res, - struct percpu_ref *ref, struct vmem_altmap *altmap); -struct dev_pagemap *find_dev_pagemap(resource_size_t phys); -#else -static inline void *devm_memremap_pages(struct device *dev, - struct resource *res, struct percpu_ref *ref, - struct vmem_altmap *altmap) -{ - /* - * Fail attempts to call devm_memremap_pages() without - * ZONE_DEVICE support enabled, this requires callers to fall - * back to plain devm_memremap() based on config - */ - WARN_ON_ONCE(1); - return ERR_PTR(-ENXIO); -} - -static inline struct dev_pagemap *find_dev_pagemap(resource_size_t phys) -{ - return NULL; -} -#endif - -/** - * get_dev_pagemap() - take a new live reference on the dev_pagemap for @pfn - * @pfn: page frame number to lookup page_map - * @pgmap: optional known pgmap that already has a reference - * - * @pgmap allows the overhead of a lookup to be bypassed when @pfn lands in the - * same mapping. - */ -static inline struct dev_pagemap *get_dev_pagemap(unsigned long pfn, - struct dev_pagemap *pgmap) -{ - const struct resource *res = pgmap ? pgmap->res : NULL; - resource_size_t phys = PFN_PHYS(pfn); - - /* - * In the cached case we're already holding a live reference so - * we can simply do a blind increment - */ - if (res && phys >= res->start && phys <= res->end) { - percpu_ref_get(pgmap->ref); - return pgmap; - } - - /* fall back to slow path lookup */ - rcu_read_lock(); - pgmap = find_dev_pagemap(phys); - if (pgmap && !percpu_ref_tryget_live(pgmap->ref)) - pgmap = NULL; - rcu_read_unlock(); - - return pgmap; -} - -static inline void put_dev_pagemap(struct dev_pagemap *pgmap) -{ - if (pgmap) - percpu_ref_put(pgmap->ref); -} -#endif /* _LINUX_MEMREMAP_H_ */ diff --git a/src/linux/include/linux/migrate.h b/src/linux/include/linux/migrate.h deleted file mode 100644 index ae8d475..0000000 --- a/src/linux/include/linux/migrate.h +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef _LINUX_MIGRATE_H -#define _LINUX_MIGRATE_H - -#include -#include -#include - -typedef struct page *new_page_t(struct page *page, unsigned long private, - int **reason); -typedef void free_page_t(struct page *page, unsigned long private); - -/* - * Return values from addresss_space_operations.migratepage(): - * - negative errno on page migration failure; - * - zero on page migration success; - */ -#define MIGRATEPAGE_SUCCESS 0 - -enum migrate_reason { - MR_COMPACTION, - MR_MEMORY_FAILURE, - MR_MEMORY_HOTPLUG, - MR_SYSCALL, /* also applies to cpusets */ - MR_MEMPOLICY_MBIND, - MR_NUMA_MISPLACED, - MR_CMA, - MR_TYPES -}; - -/* In mm/debug.c; also keep sync with include/trace/events/migrate.h */ -extern char *migrate_reason_names[MR_TYPES]; - -#ifdef CONFIG_MIGRATION - -extern void putback_movable_pages(struct list_head *l); -extern int migrate_page(struct address_space *, - struct page *, struct page *, enum migrate_mode); -extern int migrate_pages(struct list_head *l, new_page_t new, free_page_t free, - unsigned long private, enum migrate_mode mode, int reason); -extern bool isolate_movable_page(struct page *page, isolate_mode_t mode); -extern void putback_movable_page(struct page *page); - -extern int migrate_prep(void); -extern int migrate_prep_local(void); -extern void migrate_page_copy(struct page *newpage, struct page *page); -extern int migrate_huge_page_move_mapping(struct address_space *mapping, - struct page *newpage, struct page *page); -extern int migrate_page_move_mapping(struct address_space *mapping, - struct page *newpage, struct page *page, - struct buffer_head *head, enum migrate_mode mode, - int extra_count); -#else - -static inline void putback_movable_pages(struct list_head *l) {} -static inline int migrate_pages(struct list_head *l, new_page_t new, - free_page_t free, unsigned long private, enum migrate_mode mode, - int reason) - { return -ENOSYS; } - -static inline int migrate_prep(void) { return -ENOSYS; } -static inline int migrate_prep_local(void) { return -ENOSYS; } - -static inline void migrate_page_copy(struct page *newpage, - struct page *page) {} - -static inline int migrate_huge_page_move_mapping(struct address_space *mapping, - struct page *newpage, struct page *page) -{ - return -ENOSYS; -} - -#endif /* CONFIG_MIGRATION */ - -#ifdef CONFIG_COMPACTION -extern int PageMovable(struct page *page); -extern void __SetPageMovable(struct page *page, struct address_space *mapping); -extern void __ClearPageMovable(struct page *page); -#else -static inline int PageMovable(struct page *page) { return 0; }; -static inline void __SetPageMovable(struct page *page, - struct address_space *mapping) -{ -} -static inline void __ClearPageMovable(struct page *page) -{ -} -#endif - -#ifdef CONFIG_NUMA_BALANCING -extern bool pmd_trans_migrating(pmd_t pmd); -extern int migrate_misplaced_page(struct page *page, - struct vm_area_struct *vma, int node); -#else -static inline bool pmd_trans_migrating(pmd_t pmd) -{ - return false; -} -static inline int migrate_misplaced_page(struct page *page, - struct vm_area_struct *vma, int node) -{ - return -EAGAIN; /* can't migrate now */ -} -#endif /* CONFIG_NUMA_BALANCING */ - -#if defined(CONFIG_NUMA_BALANCING) && defined(CONFIG_TRANSPARENT_HUGEPAGE) -extern int migrate_misplaced_transhuge_page(struct mm_struct *mm, - struct vm_area_struct *vma, - pmd_t *pmd, pmd_t entry, - unsigned long address, - struct page *page, int node); -#else -static inline int migrate_misplaced_transhuge_page(struct mm_struct *mm, - struct vm_area_struct *vma, - pmd_t *pmd, pmd_t entry, - unsigned long address, - struct page *page, int node) -{ - return -EAGAIN; -} -#endif /* CONFIG_NUMA_BALANCING && CONFIG_TRANSPARENT_HUGEPAGE*/ - -#endif /* _LINUX_MIGRATE_H */ diff --git a/src/linux/include/linux/migrate_mode.h b/src/linux/include/linux/migrate_mode.h deleted file mode 100644 index ebf3d89..0000000 --- a/src/linux/include/linux/migrate_mode.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef MIGRATE_MODE_H_INCLUDED -#define MIGRATE_MODE_H_INCLUDED -/* - * MIGRATE_ASYNC means never block - * MIGRATE_SYNC_LIGHT in the current implementation means to allow blocking - * on most operations but not ->writepage as the potential stall time - * is too significant - * MIGRATE_SYNC will block when migrating pages - */ -enum migrate_mode { - MIGRATE_ASYNC, - MIGRATE_SYNC_LIGHT, - MIGRATE_SYNC, -}; - -#endif /* MIGRATE_MODE_H_INCLUDED */ diff --git a/src/linux/include/linux/mii.h b/src/linux/include/linux/mii.h deleted file mode 100644 index 47492c9..0000000 --- a/src/linux/include/linux/mii.h +++ /dev/null @@ -1,339 +0,0 @@ -/* - * linux/mii.h: definitions for MII-compatible transceivers - * Originally drivers/net/sunhme.h. - * - * Copyright (C) 1996, 1999, 2001 David S. Miller (davem@redhat.com) - */ -#ifndef __LINUX_MII_H__ -#define __LINUX_MII_H__ - - -#include -#include - -struct ethtool_cmd; - -struct mii_if_info { - int phy_id; - int advertising; - int phy_id_mask; - int reg_num_mask; - - unsigned int full_duplex : 1; /* is full duplex? */ - unsigned int force_media : 1; /* is autoneg. disabled? */ - unsigned int supports_gmii : 1; /* are GMII registers supported? */ - - struct net_device *dev; - int (*mdio_read) (struct net_device *dev, int phy_id, int location); - void (*mdio_write) (struct net_device *dev, int phy_id, int location, int val); -}; - -extern int mii_link_ok (struct mii_if_info *mii); -extern int mii_nway_restart (struct mii_if_info *mii); -extern int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd); -extern int mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd); -extern int mii_check_gmii_support(struct mii_if_info *mii); -extern void mii_check_link (struct mii_if_info *mii); -extern unsigned int mii_check_media (struct mii_if_info *mii, - unsigned int ok_to_print, - unsigned int init_media); -extern int generic_mii_ioctl(struct mii_if_info *mii_if, - struct mii_ioctl_data *mii_data, int cmd, - unsigned int *duplex_changed); - - -static inline struct mii_ioctl_data *if_mii(struct ifreq *rq) -{ - return (struct mii_ioctl_data *) &rq->ifr_ifru; -} - -/** - * mii_nway_result - * @negotiated: value of MII ANAR and'd with ANLPAR - * - * Given a set of MII abilities, check each bit and returns the - * currently supported media, in the priority order defined by - * IEEE 802.3u. We use LPA_xxx constants but note this is not the - * value of LPA solely, as described above. - * - * The one exception to IEEE 802.3u is that 100baseT4 is placed - * between 100T-full and 100T-half. If your phy does not support - * 100T4 this is fine. If your phy places 100T4 elsewhere in the - * priority order, you will need to roll your own function. - */ -static inline unsigned int mii_nway_result (unsigned int negotiated) -{ - unsigned int ret; - - if (negotiated & LPA_100FULL) - ret = LPA_100FULL; - else if (negotiated & LPA_100BASE4) - ret = LPA_100BASE4; - else if (negotiated & LPA_100HALF) - ret = LPA_100HALF; - else if (negotiated & LPA_10FULL) - ret = LPA_10FULL; - else - ret = LPA_10HALF; - - return ret; -} - -/** - * mii_duplex - * @duplex_lock: Non-zero if duplex is locked at full - * @negotiated: value of MII ANAR and'd with ANLPAR - * - * A small helper function for a common case. Returns one - * if the media is operating or locked at full duplex, and - * returns zero otherwise. - */ -static inline unsigned int mii_duplex (unsigned int duplex_lock, - unsigned int negotiated) -{ - if (duplex_lock) - return 1; - if (mii_nway_result(negotiated) & LPA_DUPLEX) - return 1; - return 0; -} - -/** - * ethtool_adv_to_mii_adv_t - * @ethadv: the ethtool advertisement settings - * - * A small helper function that translates ethtool advertisement - * settings to phy autonegotiation advertisements for the - * MII_ADVERTISE register. - */ -static inline u32 ethtool_adv_to_mii_adv_t(u32 ethadv) -{ - u32 result = 0; - - if (ethadv & ADVERTISED_10baseT_Half) - result |= ADVERTISE_10HALF; - if (ethadv & ADVERTISED_10baseT_Full) - result |= ADVERTISE_10FULL; - if (ethadv & ADVERTISED_100baseT_Half) - result |= ADVERTISE_100HALF; - if (ethadv & ADVERTISED_100baseT_Full) - result |= ADVERTISE_100FULL; - if (ethadv & ADVERTISED_Pause) - result |= ADVERTISE_PAUSE_CAP; - if (ethadv & ADVERTISED_Asym_Pause) - result |= ADVERTISE_PAUSE_ASYM; - - return result; -} - -/** - * mii_adv_to_ethtool_adv_t - * @adv: value of the MII_ADVERTISE register - * - * A small helper function that translates MII_ADVERTISE bits - * to ethtool advertisement settings. - */ -static inline u32 mii_adv_to_ethtool_adv_t(u32 adv) -{ - u32 result = 0; - - if (adv & ADVERTISE_10HALF) - result |= ADVERTISED_10baseT_Half; - if (adv & ADVERTISE_10FULL) - result |= ADVERTISED_10baseT_Full; - if (adv & ADVERTISE_100HALF) - result |= ADVERTISED_100baseT_Half; - if (adv & ADVERTISE_100FULL) - result |= ADVERTISED_100baseT_Full; - if (adv & ADVERTISE_PAUSE_CAP) - result |= ADVERTISED_Pause; - if (adv & ADVERTISE_PAUSE_ASYM) - result |= ADVERTISED_Asym_Pause; - - return result; -} - -/** - * ethtool_adv_to_mii_ctrl1000_t - * @ethadv: the ethtool advertisement settings - * - * A small helper function that translates ethtool advertisement - * settings to phy autonegotiation advertisements for the - * MII_CTRL1000 register when in 1000T mode. - */ -static inline u32 ethtool_adv_to_mii_ctrl1000_t(u32 ethadv) -{ - u32 result = 0; - - if (ethadv & ADVERTISED_1000baseT_Half) - result |= ADVERTISE_1000HALF; - if (ethadv & ADVERTISED_1000baseT_Full) - result |= ADVERTISE_1000FULL; - - return result; -} - -/** - * mii_ctrl1000_to_ethtool_adv_t - * @adv: value of the MII_CTRL1000 register - * - * A small helper function that translates MII_CTRL1000 - * bits, when in 1000Base-T mode, to ethtool - * advertisement settings. - */ -static inline u32 mii_ctrl1000_to_ethtool_adv_t(u32 adv) -{ - u32 result = 0; - - if (adv & ADVERTISE_1000HALF) - result |= ADVERTISED_1000baseT_Half; - if (adv & ADVERTISE_1000FULL) - result |= ADVERTISED_1000baseT_Full; - - return result; -} - -/** - * mii_lpa_to_ethtool_lpa_t - * @adv: value of the MII_LPA register - * - * A small helper function that translates MII_LPA - * bits, when in 1000Base-T mode, to ethtool - * LP advertisement settings. - */ -static inline u32 mii_lpa_to_ethtool_lpa_t(u32 lpa) -{ - u32 result = 0; - - if (lpa & LPA_LPACK) - result |= ADVERTISED_Autoneg; - - return result | mii_adv_to_ethtool_adv_t(lpa); -} - -/** - * mii_stat1000_to_ethtool_lpa_t - * @adv: value of the MII_STAT1000 register - * - * A small helper function that translates MII_STAT1000 - * bits, when in 1000Base-T mode, to ethtool - * advertisement settings. - */ -static inline u32 mii_stat1000_to_ethtool_lpa_t(u32 lpa) -{ - u32 result = 0; - - if (lpa & LPA_1000HALF) - result |= ADVERTISED_1000baseT_Half; - if (lpa & LPA_1000FULL) - result |= ADVERTISED_1000baseT_Full; - - return result; -} - -/** - * ethtool_adv_to_mii_adv_x - * @ethadv: the ethtool advertisement settings - * - * A small helper function that translates ethtool advertisement - * settings to phy autonegotiation advertisements for the - * MII_CTRL1000 register when in 1000Base-X mode. - */ -static inline u32 ethtool_adv_to_mii_adv_x(u32 ethadv) -{ - u32 result = 0; - - if (ethadv & ADVERTISED_1000baseT_Half) - result |= ADVERTISE_1000XHALF; - if (ethadv & ADVERTISED_1000baseT_Full) - result |= ADVERTISE_1000XFULL; - if (ethadv & ADVERTISED_Pause) - result |= ADVERTISE_1000XPAUSE; - if (ethadv & ADVERTISED_Asym_Pause) - result |= ADVERTISE_1000XPSE_ASYM; - - return result; -} - -/** - * mii_adv_to_ethtool_adv_x - * @adv: value of the MII_CTRL1000 register - * - * A small helper function that translates MII_CTRL1000 - * bits, when in 1000Base-X mode, to ethtool - * advertisement settings. - */ -static inline u32 mii_adv_to_ethtool_adv_x(u32 adv) -{ - u32 result = 0; - - if (adv & ADVERTISE_1000XHALF) - result |= ADVERTISED_1000baseT_Half; - if (adv & ADVERTISE_1000XFULL) - result |= ADVERTISED_1000baseT_Full; - if (adv & ADVERTISE_1000XPAUSE) - result |= ADVERTISED_Pause; - if (adv & ADVERTISE_1000XPSE_ASYM) - result |= ADVERTISED_Asym_Pause; - - return result; -} - -/** - * mii_lpa_to_ethtool_lpa_x - * @adv: value of the MII_LPA register - * - * A small helper function that translates MII_LPA - * bits, when in 1000Base-X mode, to ethtool - * LP advertisement settings. - */ -static inline u32 mii_lpa_to_ethtool_lpa_x(u32 lpa) -{ - u32 result = 0; - - if (lpa & LPA_LPACK) - result |= ADVERTISED_Autoneg; - - return result | mii_adv_to_ethtool_adv_x(lpa); -} - -/** - * mii_advertise_flowctrl - get flow control advertisement flags - * @cap: Flow control capabilities (FLOW_CTRL_RX, FLOW_CTRL_TX or both) - */ -static inline u16 mii_advertise_flowctrl(int cap) -{ - u16 adv = 0; - - if (cap & FLOW_CTRL_RX) - adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; - if (cap & FLOW_CTRL_TX) - adv ^= ADVERTISE_PAUSE_ASYM; - - return adv; -} - -/** - * mii_resolve_flowctrl_fdx - * @lcladv: value of MII ADVERTISE register - * @rmtadv: value of MII LPA register - * - * Resolve full duplex flow control as per IEEE 802.3-2005 table 28B-3 - */ -static inline u8 mii_resolve_flowctrl_fdx(u16 lcladv, u16 rmtadv) -{ - u8 cap = 0; - - if (lcladv & rmtadv & ADVERTISE_PAUSE_CAP) { - cap = FLOW_CTRL_TX | FLOW_CTRL_RX; - } else if (lcladv & rmtadv & ADVERTISE_PAUSE_ASYM) { - if (lcladv & ADVERTISE_PAUSE_CAP) - cap = FLOW_CTRL_RX; - else if (rmtadv & ADVERTISE_PAUSE_CAP) - cap = FLOW_CTRL_TX; - } - - return cap; -} - -#endif /* __LINUX_MII_H__ */ diff --git a/src/linux/include/linux/miscdevice.h b/src/linux/include/linux/miscdevice.h deleted file mode 100644 index 722698a..0000000 --- a/src/linux/include/linux/miscdevice.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef _LINUX_MISCDEVICE_H -#define _LINUX_MISCDEVICE_H -#include -#include -#include -#include - -/* - * These allocations are managed by device@lanana.org. If you use an - * entry that is not in assigned your entry may well be moved and - * reassigned, or set dynamic if a fixed value is not justified. - */ - -#define PSMOUSE_MINOR 1 -#define MS_BUSMOUSE_MINOR 2 /* unused */ -#define ATIXL_BUSMOUSE_MINOR 3 /* unused */ -/*#define AMIGAMOUSE_MINOR 4 FIXME OBSOLETE */ -#define ATARIMOUSE_MINOR 5 /* unused */ -#define SUN_MOUSE_MINOR 6 /* unused */ -#define APOLLO_MOUSE_MINOR 7 /* unused */ -#define PC110PAD_MINOR 9 /* unused */ -/*#define ADB_MOUSE_MINOR 10 FIXME OBSOLETE */ -#define WATCHDOG_MINOR 130 /* Watchdog timer */ -#define TEMP_MINOR 131 /* Temperature Sensor */ -#define RTC_MINOR 135 -#define EFI_RTC_MINOR 136 /* EFI Time services */ -#define VHCI_MINOR 137 -#define SUN_OPENPROM_MINOR 139 -#define DMAPI_MINOR 140 /* unused */ -#define NVRAM_MINOR 144 -#define SGI_MMTIMER 153 -#define STORE_QUEUE_MINOR 155 /* unused */ -#define I2O_MINOR 166 -#define MICROCODE_MINOR 184 -#define VFIO_MINOR 196 -#define TUN_MINOR 200 -#define CUSE_MINOR 203 -#define MWAVE_MINOR 219 /* ACP/Mwave Modem */ -#define MPT_MINOR 220 -#define MPT2SAS_MINOR 221 -#define MPT3SAS_MINOR 222 -#define UINPUT_MINOR 223 -#define MISC_MCELOG_MINOR 227 -#define HPET_MINOR 228 -#define FUSE_MINOR 229 -#define KVM_MINOR 232 -#define BTRFS_MINOR 234 -#define AUTOFS_MINOR 235 -#define MAPPER_CTRL_MINOR 236 -#define LOOP_CTRL_MINOR 237 -#define VHOST_NET_MINOR 238 -#define UHID_MINOR 239 -#define USERIO_MINOR 240 -#define MISC_DYNAMIC_MINOR 255 - -struct device; -struct attribute_group; - -struct miscdevice { - int minor; - const char *name; - const struct file_operations *fops; - struct list_head list; - struct device *parent; - struct device *this_device; - const struct attribute_group **groups; - const char *nodename; - umode_t mode; -}; - -extern int misc_register(struct miscdevice *misc); -extern void misc_deregister(struct miscdevice *misc); - -/* - * Helper macro for drivers that don't do anything special in module init / exit - * call. This helps in eleminating of boilerplate code. - */ -#define module_misc_device(__misc_device) \ - module_driver(__misc_device, misc_register, misc_deregister) - -#define MODULE_ALIAS_MISCDEV(minor) \ - MODULE_ALIAS("char-major-" __stringify(MISC_MAJOR) \ - "-" __stringify(minor)) -#endif diff --git a/src/linux/include/linux/mm.h b/src/linux/include/linux/mm.h deleted file mode 100644 index a92c8d7..0000000 --- a/src/linux/include/linux/mm.h +++ /dev/null @@ -1,2452 +0,0 @@ -#ifndef _LINUX_MM_H -#define _LINUX_MM_H - -#include - -#ifdef __KERNEL__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct mempolicy; -struct anon_vma; -struct anon_vma_chain; -struct file_ra_state; -struct user_struct; -struct writeback_control; -struct bdi_writeback; - -#ifndef CONFIG_NEED_MULTIPLE_NODES /* Don't use mapnrs, do it properly */ -extern unsigned long max_mapnr; - -static inline void set_max_mapnr(unsigned long limit) -{ - max_mapnr = limit; -} -#else -static inline void set_max_mapnr(unsigned long limit) { } -#endif - -extern unsigned long totalram_pages; -extern void * high_memory; -extern int page_cluster; - -#ifdef CONFIG_SYSCTL -extern int sysctl_legacy_va_layout; -#else -#define sysctl_legacy_va_layout 0 -#endif - -#ifdef CONFIG_HAVE_ARCH_MMAP_RND_BITS -extern const int mmap_rnd_bits_min; -extern const int mmap_rnd_bits_max; -extern int mmap_rnd_bits __read_mostly; -#endif -#ifdef CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS -extern const int mmap_rnd_compat_bits_min; -extern const int mmap_rnd_compat_bits_max; -extern int mmap_rnd_compat_bits __read_mostly; -#endif - -#include -#include -#include - -#ifndef __pa_symbol -#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x), 0)) -#endif - -#ifndef page_to_virt -#define page_to_virt(x) __va(PFN_PHYS(page_to_pfn(x))) -#endif - -/* - * To prevent common memory management code establishing - * a zero page mapping on a read fault. - * This macro should be defined within . - * s390 does this to prevent multiplexing of hardware bits - * related to the physical page in case of virtualization. - */ -#ifndef mm_forbids_zeropage -#define mm_forbids_zeropage(X) (0) -#endif - -/* - * Default maximum number of active map areas, this limits the number of vmas - * per mm struct. Users can overwrite this number by sysctl but there is a - * problem. - * - * When a program's coredump is generated as ELF format, a section is created - * per a vma. In ELF, the number of sections is represented in unsigned short. - * This means the number of sections should be smaller than 65535 at coredump. - * Because the kernel adds some informative sections to a image of program at - * generating coredump, we need some margin. The number of extra sections is - * 1-3 now and depends on arch. We use "5" as safe margin, here. - * - * ELF extended numbering allows more than 65535 sections, so 16-bit bound is - * not a hard limit any more. Although some userspace tools can be surprised by - * that. - */ -#define MAPCOUNT_ELF_CORE_MARGIN (5) -#define DEFAULT_MAX_MAP_COUNT (USHRT_MAX - MAPCOUNT_ELF_CORE_MARGIN) - -extern int sysctl_max_map_count; - -extern unsigned long sysctl_user_reserve_kbytes; -extern unsigned long sysctl_admin_reserve_kbytes; - -extern int sysctl_overcommit_memory; -extern int sysctl_overcommit_ratio; -extern unsigned long sysctl_overcommit_kbytes; - -extern int overcommit_ratio_handler(struct ctl_table *, int, void __user *, - size_t *, loff_t *); -extern int overcommit_kbytes_handler(struct ctl_table *, int, void __user *, - size_t *, loff_t *); - -#define nth_page(page,n) pfn_to_page(page_to_pfn((page)) + (n)) - -/* to align the pointer to the (next) page boundary */ -#define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE) - -/* test whether an address (unsigned long or pointer) is aligned to PAGE_SIZE */ -#define PAGE_ALIGNED(addr) IS_ALIGNED((unsigned long)(addr), PAGE_SIZE) - -/* - * Linux kernel virtual memory manager primitives. - * The idea being to have a "virtual" mm in the same way - * we have a virtual fs - giving a cleaner interface to the - * mm details, and allowing different kinds of memory mappings - * (from shared memory to executable loading to arbitrary - * mmap() functions). - */ - -extern struct kmem_cache *vm_area_cachep; - -#ifndef CONFIG_MMU -extern struct rb_root nommu_region_tree; -extern struct rw_semaphore nommu_region_sem; - -extern unsigned int kobjsize(const void *objp); -#endif - -/* - * vm_flags in vm_area_struct, see mm_types.h. - * When changing, update also include/trace/events/mmflags.h - */ -#define VM_NONE 0x00000000 - -#define VM_READ 0x00000001 /* currently active flags */ -#define VM_WRITE 0x00000002 -#define VM_EXEC 0x00000004 -#define VM_SHARED 0x00000008 - -/* mprotect() hardcodes VM_MAYREAD >> 4 == VM_READ, and so for r/w/x bits. */ -#define VM_MAYREAD 0x00000010 /* limits for mprotect() etc */ -#define VM_MAYWRITE 0x00000020 -#define VM_MAYEXEC 0x00000040 -#define VM_MAYSHARE 0x00000080 - -#define VM_GROWSDOWN 0x00000100 /* general info on the segment */ -#define VM_UFFD_MISSING 0x00000200 /* missing pages tracking */ -#define VM_PFNMAP 0x00000400 /* Page-ranges managed without "struct page", just pure PFN */ -#define VM_DENYWRITE 0x00000800 /* ETXTBSY on write attempts.. */ -#define VM_UFFD_WP 0x00001000 /* wrprotect pages tracking */ - -#define VM_LOCKED 0x00002000 -#define VM_IO 0x00004000 /* Memory mapped I/O or similar */ - - /* Used by sys_madvise() */ -#define VM_SEQ_READ 0x00008000 /* App will access data sequentially */ -#define VM_RAND_READ 0x00010000 /* App will not benefit from clustered reads */ - -#define VM_DONTCOPY 0x00020000 /* Do not copy this vma on fork */ -#define VM_DONTEXPAND 0x00040000 /* Cannot expand with mremap() */ -#define VM_LOCKONFAULT 0x00080000 /* Lock the pages covered when they are faulted in */ -#define VM_ACCOUNT 0x00100000 /* Is a VM accounted object */ -#define VM_NORESERVE 0x00200000 /* should the VM suppress accounting */ -#define VM_HUGETLB 0x00400000 /* Huge TLB Page VM */ -#define VM_ARCH_1 0x01000000 /* Architecture-specific flag */ -#define VM_ARCH_2 0x02000000 -#define VM_DONTDUMP 0x04000000 /* Do not include in the core dump */ - -#ifdef CONFIG_MEM_SOFT_DIRTY -# define VM_SOFTDIRTY 0x08000000 /* Not soft dirty clean area */ -#else -# define VM_SOFTDIRTY 0 -#endif - -#define VM_MIXEDMAP 0x10000000 /* Can contain "struct page" and pure PFN pages */ -#define VM_HUGEPAGE 0x20000000 /* MADV_HUGEPAGE marked this vma */ -#define VM_NOHUGEPAGE 0x40000000 /* MADV_NOHUGEPAGE marked this vma */ -#define VM_MERGEABLE 0x80000000 /* KSM may merge identical pages */ - -#ifdef CONFIG_ARCH_USES_HIGH_VMA_FLAGS -#define VM_HIGH_ARCH_BIT_0 32 /* bit only usable on 64-bit architectures */ -#define VM_HIGH_ARCH_BIT_1 33 /* bit only usable on 64-bit architectures */ -#define VM_HIGH_ARCH_BIT_2 34 /* bit only usable on 64-bit architectures */ -#define VM_HIGH_ARCH_BIT_3 35 /* bit only usable on 64-bit architectures */ -#define VM_HIGH_ARCH_0 BIT(VM_HIGH_ARCH_BIT_0) -#define VM_HIGH_ARCH_1 BIT(VM_HIGH_ARCH_BIT_1) -#define VM_HIGH_ARCH_2 BIT(VM_HIGH_ARCH_BIT_2) -#define VM_HIGH_ARCH_3 BIT(VM_HIGH_ARCH_BIT_3) -#endif /* CONFIG_ARCH_USES_HIGH_VMA_FLAGS */ - -#if defined(CONFIG_X86) -# define VM_PAT VM_ARCH_1 /* PAT reserves whole VMA at once (x86) */ -#if defined (CONFIG_X86_INTEL_MEMORY_PROTECTION_KEYS) -# define VM_PKEY_SHIFT VM_HIGH_ARCH_BIT_0 -# define VM_PKEY_BIT0 VM_HIGH_ARCH_0 /* A protection key is a 4-bit value */ -# define VM_PKEY_BIT1 VM_HIGH_ARCH_1 -# define VM_PKEY_BIT2 VM_HIGH_ARCH_2 -# define VM_PKEY_BIT3 VM_HIGH_ARCH_3 -#endif -#elif defined(CONFIG_PPC) -# define VM_SAO VM_ARCH_1 /* Strong Access Ordering (powerpc) */ -#elif defined(CONFIG_PARISC) -# define VM_GROWSUP VM_ARCH_1 -#elif defined(CONFIG_METAG) -# define VM_GROWSUP VM_ARCH_1 -#elif defined(CONFIG_IA64) -# define VM_GROWSUP VM_ARCH_1 -#elif !defined(CONFIG_MMU) -# define VM_MAPPED_COPY VM_ARCH_1 /* T if mapped copy of data (nommu mmap) */ -#endif - -#if defined(CONFIG_X86) -/* MPX specific bounds table or bounds directory */ -# define VM_MPX VM_ARCH_2 -#endif - -#ifndef VM_GROWSUP -# define VM_GROWSUP VM_NONE -#endif - -/* Bits set in the VMA until the stack is in its final location */ -#define VM_STACK_INCOMPLETE_SETUP (VM_RAND_READ | VM_SEQ_READ) - -#ifndef VM_STACK_DEFAULT_FLAGS /* arch can override this */ -#define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS -#endif - -#ifdef CONFIG_STACK_GROWSUP -#define VM_STACK VM_GROWSUP -#else -#define VM_STACK VM_GROWSDOWN -#endif - -#define VM_STACK_FLAGS (VM_STACK | VM_STACK_DEFAULT_FLAGS | VM_ACCOUNT) - -/* - * Special vmas that are non-mergable, non-mlock()able. - * Note: mm/huge_memory.c VM_NO_THP depends on this definition. - */ -#define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_PFNMAP | VM_MIXEDMAP) - -/* This mask defines which mm->def_flags a process can inherit its parent */ -#define VM_INIT_DEF_MASK VM_NOHUGEPAGE - -/* This mask is used to clear all the VMA flags used by mlock */ -#define VM_LOCKED_CLEAR_MASK (~(VM_LOCKED | VM_LOCKONFAULT)) - -/* - * mapping from the currently active vm_flags protection bits (the - * low four bits) to a page protection mask.. - */ -extern pgprot_t protection_map[16]; - -#define FAULT_FLAG_WRITE 0x01 /* Fault was a write access */ -#define FAULT_FLAG_MKWRITE 0x02 /* Fault was mkwrite of existing pte */ -#define FAULT_FLAG_ALLOW_RETRY 0x04 /* Retry fault if blocking */ -#define FAULT_FLAG_RETRY_NOWAIT 0x08 /* Don't drop mmap_sem and wait when retrying */ -#define FAULT_FLAG_KILLABLE 0x10 /* The fault task is in SIGKILL killable region */ -#define FAULT_FLAG_TRIED 0x20 /* Second try */ -#define FAULT_FLAG_USER 0x40 /* The fault originated in userspace */ -#define FAULT_FLAG_REMOTE 0x80 /* faulting for non current tsk/mm */ -#define FAULT_FLAG_INSTRUCTION 0x100 /* The fault was during an instruction fetch */ - -/* - * vm_fault is filled by the the pagefault handler and passed to the vma's - * ->fault function. The vma's ->fault is responsible for returning a bitmask - * of VM_FAULT_xxx flags that give details about how the fault was handled. - * - * MM layer fills up gfp_mask for page allocations but fault handler might - * alter it if its implementation requires a different allocation context. - * - * pgoff should be used in favour of virtual_address, if possible. - */ -struct vm_fault { - unsigned int flags; /* FAULT_FLAG_xxx flags */ - gfp_t gfp_mask; /* gfp mask to be used for allocations */ - pgoff_t pgoff; /* Logical page offset based on vma */ - void __user *virtual_address; /* Faulting virtual address */ - - struct page *cow_page; /* Handler may choose to COW */ - struct page *page; /* ->fault handlers should return a - * page here, unless VM_FAULT_NOPAGE - * is set (which is also implied by - * VM_FAULT_ERROR). - */ - void *entry; /* ->fault handler can alternatively - * return locked DAX entry. In that - * case handler should return - * VM_FAULT_DAX_LOCKED and fill in - * entry here. - */ -}; - -/* - * Page fault context: passes though page fault handler instead of endless list - * of function arguments. - */ -struct fault_env { - struct vm_area_struct *vma; /* Target VMA */ - unsigned long address; /* Faulting virtual address */ - unsigned int flags; /* FAULT_FLAG_xxx flags */ - pmd_t *pmd; /* Pointer to pmd entry matching - * the 'address' - */ - pte_t *pte; /* Pointer to pte entry matching - * the 'address'. NULL if the page - * table hasn't been allocated. - */ - spinlock_t *ptl; /* Page table lock. - * Protects pte page table if 'pte' - * is not NULL, otherwise pmd. - */ - pgtable_t prealloc_pte; /* Pre-allocated pte page table. - * vm_ops->map_pages() calls - * alloc_set_pte() from atomic context. - * do_fault_around() pre-allocates - * page table to avoid allocation from - * atomic context. - */ -}; - -/* - * These are the virtual MM functions - opening of an area, closing and - * unmapping it (needed to keep files on disk up-to-date etc), pointer - * to the functions called when a no-page or a wp-page exception occurs. - */ -struct vm_operations_struct { - void (*open)(struct vm_area_struct * area); - void (*close)(struct vm_area_struct * area); - int (*mremap)(struct vm_area_struct * area); - int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf); - int (*pmd_fault)(struct vm_area_struct *, unsigned long address, - pmd_t *, unsigned int flags); - void (*map_pages)(struct fault_env *fe, - pgoff_t start_pgoff, pgoff_t end_pgoff); - - /* notification that a previously read-only page is about to become - * writable, if an error is returned it will cause a SIGBUS */ - int (*page_mkwrite)(struct vm_area_struct *vma, struct vm_fault *vmf); - - /* same as page_mkwrite when using VM_PFNMAP|VM_MIXEDMAP */ - int (*pfn_mkwrite)(struct vm_area_struct *vma, struct vm_fault *vmf); - - /* called by access_process_vm when get_user_pages() fails, typically - * for use by special VMAs that can switch between memory and hardware - */ - int (*access)(struct vm_area_struct *vma, unsigned long addr, - void *buf, int len, int write); - - /* Called by the /proc/PID/maps code to ask the vma whether it - * has a special name. Returning non-NULL will also cause this - * vma to be dumped unconditionally. */ - const char *(*name)(struct vm_area_struct *vma); - -#ifdef CONFIG_NUMA - /* - * set_policy() op must add a reference to any non-NULL @new mempolicy - * to hold the policy upon return. Caller should pass NULL @new to - * remove a policy and fall back to surrounding context--i.e. do not - * install a MPOL_DEFAULT policy, nor the task or system default - * mempolicy. - */ - int (*set_policy)(struct vm_area_struct *vma, struct mempolicy *new); - - /* - * get_policy() op must add reference [mpol_get()] to any policy at - * (vma,addr) marked as MPOL_SHARED. The shared policy infrastructure - * in mm/mempolicy.c will do this automatically. - * get_policy() must NOT add a ref if the policy at (vma,addr) is not - * marked as MPOL_SHARED. vma policies are protected by the mmap_sem. - * If no [shared/vma] mempolicy exists at the addr, get_policy() op - * must return NULL--i.e., do not "fallback" to task or system default - * policy. - */ - struct mempolicy *(*get_policy)(struct vm_area_struct *vma, - unsigned long addr); -#endif - /* - * Called by vm_normal_page() for special PTEs to find the - * page for @addr. This is useful if the default behavior - * (using pte_page()) would not find the correct page. - */ - struct page *(*find_special_page)(struct vm_area_struct *vma, - unsigned long addr); -}; - -struct mmu_gather; -struct inode; - -#define page_private(page) ((page)->private) -#define set_page_private(page, v) ((page)->private = (v)) - -#if !defined(__HAVE_ARCH_PTE_DEVMAP) || !defined(CONFIG_TRANSPARENT_HUGEPAGE) -static inline int pmd_devmap(pmd_t pmd) -{ - return 0; -} -#endif - -/* - * FIXME: take this include out, include page-flags.h in - * files which need it (119 of them) - */ -#include -#include - -/* - * Methods to modify the page usage count. - * - * What counts for a page usage: - * - cache mapping (page->mapping) - * - private data (page->private) - * - page mapped in a task's page tables, each mapping - * is counted separately - * - * Also, many kernel routines increase the page count before a critical - * routine so they can be sure the page doesn't go away from under them. - */ - -/* - * Drop a ref, return true if the refcount fell to zero (the page has no users) - */ -static inline int put_page_testzero(struct page *page) -{ - VM_BUG_ON_PAGE(page_ref_count(page) == 0, page); - return page_ref_dec_and_test(page); -} - -/* - * Try to grab a ref unless the page has a refcount of zero, return false if - * that is the case. - * This can be called when MMU is off so it must not access - * any of the virtual mappings. - */ -static inline int get_page_unless_zero(struct page *page) -{ - return page_ref_add_unless(page, 1, 0); -} - -extern int page_is_ram(unsigned long pfn); - -enum { - REGION_INTERSECTS, - REGION_DISJOINT, - REGION_MIXED, -}; - -int region_intersects(resource_size_t offset, size_t size, unsigned long flags, - unsigned long desc); - -/* Support for virtually mapped pages */ -struct page *vmalloc_to_page(const void *addr); -unsigned long vmalloc_to_pfn(const void *addr); - -/* - * Determine if an address is within the vmalloc range - * - * On nommu, vmalloc/vfree wrap through kmalloc/kfree directly, so there - * is no special casing required. - */ -static inline bool is_vmalloc_addr(const void *x) -{ -#ifdef CONFIG_MMU - unsigned long addr = (unsigned long)x; - - return addr >= VMALLOC_START && addr < VMALLOC_END; -#else - return false; -#endif -} -#ifdef CONFIG_MMU -extern int is_vmalloc_or_module_addr(const void *x); -#else -static inline int is_vmalloc_or_module_addr(const void *x) -{ - return 0; -} -#endif - -extern void kvfree(const void *addr); - -static inline atomic_t *compound_mapcount_ptr(struct page *page) -{ - return &page[1].compound_mapcount; -} - -static inline int compound_mapcount(struct page *page) -{ - VM_BUG_ON_PAGE(!PageCompound(page), page); - page = compound_head(page); - return atomic_read(compound_mapcount_ptr(page)) + 1; -} - -/* - * The atomic page->_mapcount, starts from -1: so that transitions - * both from it and to it can be tracked, using atomic_inc_and_test - * and atomic_add_negative(-1). - */ -static inline void page_mapcount_reset(struct page *page) -{ - atomic_set(&(page)->_mapcount, -1); -} - -int __page_mapcount(struct page *page); - -static inline int page_mapcount(struct page *page) -{ - VM_BUG_ON_PAGE(PageSlab(page), page); - - if (unlikely(PageCompound(page))) - return __page_mapcount(page); - return atomic_read(&page->_mapcount) + 1; -} - -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -int total_mapcount(struct page *page); -int page_trans_huge_mapcount(struct page *page, int *total_mapcount); -#else -static inline int total_mapcount(struct page *page) -{ - return page_mapcount(page); -} -static inline int page_trans_huge_mapcount(struct page *page, - int *total_mapcount) -{ - int mapcount = page_mapcount(page); - if (total_mapcount) - *total_mapcount = mapcount; - return mapcount; -} -#endif - -static inline struct page *virt_to_head_page(const void *x) -{ - struct page *page = virt_to_page(x); - - return compound_head(page); -} - -void __put_page(struct page *page); - -void put_pages_list(struct list_head *pages); - -void split_page(struct page *page, unsigned int order); - -/* - * Compound pages have a destructor function. Provide a - * prototype for that function and accessor functions. - * These are _only_ valid on the head of a compound page. - */ -typedef void compound_page_dtor(struct page *); - -/* Keep the enum in sync with compound_page_dtors array in mm/page_alloc.c */ -enum compound_dtor_id { - NULL_COMPOUND_DTOR, - COMPOUND_PAGE_DTOR, -#ifdef CONFIG_HUGETLB_PAGE - HUGETLB_PAGE_DTOR, -#endif -#ifdef CONFIG_TRANSPARENT_HUGEPAGE - TRANSHUGE_PAGE_DTOR, -#endif - NR_COMPOUND_DTORS, -}; -extern compound_page_dtor * const compound_page_dtors[]; - -static inline void set_compound_page_dtor(struct page *page, - enum compound_dtor_id compound_dtor) -{ - VM_BUG_ON_PAGE(compound_dtor >= NR_COMPOUND_DTORS, page); - page[1].compound_dtor = compound_dtor; -} - -static inline compound_page_dtor *get_compound_page_dtor(struct page *page) -{ - VM_BUG_ON_PAGE(page[1].compound_dtor >= NR_COMPOUND_DTORS, page); - return compound_page_dtors[page[1].compound_dtor]; -} - -static inline unsigned int compound_order(struct page *page) -{ - if (!PageHead(page)) - return 0; - return page[1].compound_order; -} - -static inline void set_compound_order(struct page *page, unsigned int order) -{ - page[1].compound_order = order; -} - -void free_compound_page(struct page *page); - -#ifdef CONFIG_MMU -/* - * Do pte_mkwrite, but only if the vma says VM_WRITE. We do this when - * servicing faults for write access. In the normal case, do always want - * pte_mkwrite. But get_user_pages can cause write faults for mappings - * that do not have writing enabled, when used by access_process_vm. - */ -static inline pte_t maybe_mkwrite(pte_t pte, struct vm_area_struct *vma) -{ - if (likely(vma->vm_flags & VM_WRITE)) - pte = pte_mkwrite(pte); - return pte; -} - -int alloc_set_pte(struct fault_env *fe, struct mem_cgroup *memcg, - struct page *page); -#endif - -/* - * Multiple processes may "see" the same page. E.g. for untouched - * mappings of /dev/null, all processes see the same page full of - * zeroes, and text pages of executables and shared libraries have - * only one copy in memory, at most, normally. - * - * For the non-reserved pages, page_count(page) denotes a reference count. - * page_count() == 0 means the page is free. page->lru is then used for - * freelist management in the buddy allocator. - * page_count() > 0 means the page has been allocated. - * - * Pages are allocated by the slab allocator in order to provide memory - * to kmalloc and kmem_cache_alloc. In this case, the management of the - * page, and the fields in 'struct page' are the responsibility of mm/slab.c - * unless a particular usage is carefully commented. (the responsibility of - * freeing the kmalloc memory is the caller's, of course). - * - * A page may be used by anyone else who does a __get_free_page(). - * In this case, page_count still tracks the references, and should only - * be used through the normal accessor functions. The top bits of page->flags - * and page->virtual store page management information, but all other fields - * are unused and could be used privately, carefully. The management of this - * page is the responsibility of the one who allocated it, and those who have - * subsequently been given references to it. - * - * The other pages (we may call them "pagecache pages") are completely - * managed by the Linux memory manager: I/O, buffers, swapping etc. - * The following discussion applies only to them. - * - * A pagecache page contains an opaque `private' member, which belongs to the - * page's address_space. Usually, this is the address of a circular list of - * the page's disk buffers. PG_private must be set to tell the VM to call - * into the filesystem to release these pages. - * - * A page may belong to an inode's memory mapping. In this case, page->mapping - * is the pointer to the inode, and page->index is the file offset of the page, - * in units of PAGE_SIZE. - * - * If pagecache pages are not associated with an inode, they are said to be - * anonymous pages. These may become associated with the swapcache, and in that - * case PG_swapcache is set, and page->private is an offset into the swapcache. - * - * In either case (swapcache or inode backed), the pagecache itself holds one - * reference to the page. Setting PG_private should also increment the - * refcount. The each user mapping also has a reference to the page. - * - * The pagecache pages are stored in a per-mapping radix tree, which is - * rooted at mapping->page_tree, and indexed by offset. - * Where 2.4 and early 2.6 kernels kept dirty/clean pages in per-address_space - * lists, we instead now tag pages as dirty/writeback in the radix tree. - * - * All pagecache pages may be subject to I/O: - * - inode pages may need to be read from disk, - * - inode pages which have been modified and are MAP_SHARED may need - * to be written back to the inode on disk, - * - anonymous pages (including MAP_PRIVATE file mappings) which have been - * modified may need to be swapped out to swap space and (later) to be read - * back into memory. - */ - -/* - * The zone field is never updated after free_area_init_core() - * sets it, so none of the operations on it need to be atomic. - */ - -/* Page flags: | [SECTION] | [NODE] | ZONE | [LAST_CPUPID] | ... | FLAGS | */ -#define SECTIONS_PGOFF ((sizeof(unsigned long)*8) - SECTIONS_WIDTH) -#define NODES_PGOFF (SECTIONS_PGOFF - NODES_WIDTH) -#define ZONES_PGOFF (NODES_PGOFF - ZONES_WIDTH) -#define LAST_CPUPID_PGOFF (ZONES_PGOFF - LAST_CPUPID_WIDTH) - -/* - * Define the bit shifts to access each section. For non-existent - * sections we define the shift as 0; that plus a 0 mask ensures - * the compiler will optimise away reference to them. - */ -#define SECTIONS_PGSHIFT (SECTIONS_PGOFF * (SECTIONS_WIDTH != 0)) -#define NODES_PGSHIFT (NODES_PGOFF * (NODES_WIDTH != 0)) -#define ZONES_PGSHIFT (ZONES_PGOFF * (ZONES_WIDTH != 0)) -#define LAST_CPUPID_PGSHIFT (LAST_CPUPID_PGOFF * (LAST_CPUPID_WIDTH != 0)) - -/* NODE:ZONE or SECTION:ZONE is used to ID a zone for the buddy allocator */ -#ifdef NODE_NOT_IN_PAGE_FLAGS -#define ZONEID_SHIFT (SECTIONS_SHIFT + ZONES_SHIFT) -#define ZONEID_PGOFF ((SECTIONS_PGOFF < ZONES_PGOFF)? \ - SECTIONS_PGOFF : ZONES_PGOFF) -#else -#define ZONEID_SHIFT (NODES_SHIFT + ZONES_SHIFT) -#define ZONEID_PGOFF ((NODES_PGOFF < ZONES_PGOFF)? \ - NODES_PGOFF : ZONES_PGOFF) -#endif - -#define ZONEID_PGSHIFT (ZONEID_PGOFF * (ZONEID_SHIFT != 0)) - -#if SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > BITS_PER_LONG - NR_PAGEFLAGS -#error SECTIONS_WIDTH+NODES_WIDTH+ZONES_WIDTH > BITS_PER_LONG - NR_PAGEFLAGS -#endif - -#define ZONES_MASK ((1UL << ZONES_WIDTH) - 1) -#define NODES_MASK ((1UL << NODES_WIDTH) - 1) -#define SECTIONS_MASK ((1UL << SECTIONS_WIDTH) - 1) -#define LAST_CPUPID_MASK ((1UL << LAST_CPUPID_SHIFT) - 1) -#define ZONEID_MASK ((1UL << ZONEID_SHIFT) - 1) - -static inline enum zone_type page_zonenum(const struct page *page) -{ - return (page->flags >> ZONES_PGSHIFT) & ZONES_MASK; -} - -#ifdef CONFIG_ZONE_DEVICE -void get_zone_device_page(struct page *page); -void put_zone_device_page(struct page *page); -static inline bool is_zone_device_page(const struct page *page) -{ - return page_zonenum(page) == ZONE_DEVICE; -} -#else -static inline void get_zone_device_page(struct page *page) -{ -} -static inline void put_zone_device_page(struct page *page) -{ -} -static inline bool is_zone_device_page(const struct page *page) -{ - return false; -} -#endif - -static inline void get_page(struct page *page) -{ - page = compound_head(page); - /* - * Getting a normal page or the head of a compound page - * requires to already have an elevated page->_refcount. - */ - VM_BUG_ON_PAGE(page_ref_count(page) <= 0, page); - page_ref_inc(page); - - if (unlikely(is_zone_device_page(page))) - get_zone_device_page(page); -} - -static inline void put_page(struct page *page) -{ - page = compound_head(page); - - if (put_page_testzero(page)) - __put_page(page); - - if (unlikely(is_zone_device_page(page))) - put_zone_device_page(page); -} - -#if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP) -#define SECTION_IN_PAGE_FLAGS -#endif - -/* - * The identification function is mainly used by the buddy allocator for - * determining if two pages could be buddies. We are not really identifying - * the zone since we could be using the section number id if we do not have - * node id available in page flags. - * We only guarantee that it will return the same value for two combinable - * pages in a zone. - */ -static inline int page_zone_id(struct page *page) -{ - return (page->flags >> ZONEID_PGSHIFT) & ZONEID_MASK; -} - -static inline int zone_to_nid(struct zone *zone) -{ -#ifdef CONFIG_NUMA - return zone->node; -#else - return 0; -#endif -} - -#ifdef NODE_NOT_IN_PAGE_FLAGS -extern int page_to_nid(const struct page *page); -#else -static inline int page_to_nid(const struct page *page) -{ - return (page->flags >> NODES_PGSHIFT) & NODES_MASK; -} -#endif - -#ifdef CONFIG_NUMA_BALANCING -static inline int cpu_pid_to_cpupid(int cpu, int pid) -{ - return ((cpu & LAST__CPU_MASK) << LAST__PID_SHIFT) | (pid & LAST__PID_MASK); -} - -static inline int cpupid_to_pid(int cpupid) -{ - return cpupid & LAST__PID_MASK; -} - -static inline int cpupid_to_cpu(int cpupid) -{ - return (cpupid >> LAST__PID_SHIFT) & LAST__CPU_MASK; -} - -static inline int cpupid_to_nid(int cpupid) -{ - return cpu_to_node(cpupid_to_cpu(cpupid)); -} - -static inline bool cpupid_pid_unset(int cpupid) -{ - return cpupid_to_pid(cpupid) == (-1 & LAST__PID_MASK); -} - -static inline bool cpupid_cpu_unset(int cpupid) -{ - return cpupid_to_cpu(cpupid) == (-1 & LAST__CPU_MASK); -} - -static inline bool __cpupid_match_pid(pid_t task_pid, int cpupid) -{ - return (task_pid & LAST__PID_MASK) == cpupid_to_pid(cpupid); -} - -#define cpupid_match_pid(task, cpupid) __cpupid_match_pid(task->pid, cpupid) -#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS -static inline int page_cpupid_xchg_last(struct page *page, int cpupid) -{ - return xchg(&page->_last_cpupid, cpupid & LAST_CPUPID_MASK); -} - -static inline int page_cpupid_last(struct page *page) -{ - return page->_last_cpupid; -} -static inline void page_cpupid_reset_last(struct page *page) -{ - page->_last_cpupid = -1 & LAST_CPUPID_MASK; -} -#else -static inline int page_cpupid_last(struct page *page) -{ - return (page->flags >> LAST_CPUPID_PGSHIFT) & LAST_CPUPID_MASK; -} - -extern int page_cpupid_xchg_last(struct page *page, int cpupid); - -static inline void page_cpupid_reset_last(struct page *page) -{ - page->flags |= LAST_CPUPID_MASK << LAST_CPUPID_PGSHIFT; -} -#endif /* LAST_CPUPID_NOT_IN_PAGE_FLAGS */ -#else /* !CONFIG_NUMA_BALANCING */ -static inline int page_cpupid_xchg_last(struct page *page, int cpupid) -{ - return page_to_nid(page); /* XXX */ -} - -static inline int page_cpupid_last(struct page *page) -{ - return page_to_nid(page); /* XXX */ -} - -static inline int cpupid_to_nid(int cpupid) -{ - return -1; -} - -static inline int cpupid_to_pid(int cpupid) -{ - return -1; -} - -static inline int cpupid_to_cpu(int cpupid) -{ - return -1; -} - -static inline int cpu_pid_to_cpupid(int nid, int pid) -{ - return -1; -} - -static inline bool cpupid_pid_unset(int cpupid) -{ - return 1; -} - -static inline void page_cpupid_reset_last(struct page *page) -{ -} - -static inline bool cpupid_match_pid(struct task_struct *task, int cpupid) -{ - return false; -} -#endif /* CONFIG_NUMA_BALANCING */ - -static inline struct zone *page_zone(const struct page *page) -{ - return &NODE_DATA(page_to_nid(page))->node_zones[page_zonenum(page)]; -} - -static inline pg_data_t *page_pgdat(const struct page *page) -{ - return NODE_DATA(page_to_nid(page)); -} - -#ifdef SECTION_IN_PAGE_FLAGS -static inline void set_page_section(struct page *page, unsigned long section) -{ - page->flags &= ~(SECTIONS_MASK << SECTIONS_PGSHIFT); - page->flags |= (section & SECTIONS_MASK) << SECTIONS_PGSHIFT; -} - -static inline unsigned long page_to_section(const struct page *page) -{ - return (page->flags >> SECTIONS_PGSHIFT) & SECTIONS_MASK; -} -#endif - -static inline void set_page_zone(struct page *page, enum zone_type zone) -{ - page->flags &= ~(ZONES_MASK << ZONES_PGSHIFT); - page->flags |= (zone & ZONES_MASK) << ZONES_PGSHIFT; -} - -static inline void set_page_node(struct page *page, unsigned long node) -{ - page->flags &= ~(NODES_MASK << NODES_PGSHIFT); - page->flags |= (node & NODES_MASK) << NODES_PGSHIFT; -} - -static inline void set_page_links(struct page *page, enum zone_type zone, - unsigned long node, unsigned long pfn) -{ - set_page_zone(page, zone); - set_page_node(page, node); -#ifdef SECTION_IN_PAGE_FLAGS - set_page_section(page, pfn_to_section_nr(pfn)); -#endif -} - -#ifdef CONFIG_MEMCG -static inline struct mem_cgroup *page_memcg(struct page *page) -{ - return page->mem_cgroup; -} -static inline struct mem_cgroup *page_memcg_rcu(struct page *page) -{ - WARN_ON_ONCE(!rcu_read_lock_held()); - return READ_ONCE(page->mem_cgroup); -} -#else -static inline struct mem_cgroup *page_memcg(struct page *page) -{ - return NULL; -} -static inline struct mem_cgroup *page_memcg_rcu(struct page *page) -{ - WARN_ON_ONCE(!rcu_read_lock_held()); - return NULL; -} -#endif - -/* - * Some inline functions in vmstat.h depend on page_zone() - */ -#include - -static __always_inline void *lowmem_page_address(const struct page *page) -{ - return page_to_virt(page); -} - -#if defined(CONFIG_HIGHMEM) && !defined(WANT_PAGE_VIRTUAL) -#define HASHED_PAGE_VIRTUAL -#endif - -#if defined(WANT_PAGE_VIRTUAL) -static inline void *page_address(const struct page *page) -{ - return page->virtual; -} -static inline void set_page_address(struct page *page, void *address) -{ - page->virtual = address; -} -#define page_address_init() do { } while(0) -#endif - -#if defined(HASHED_PAGE_VIRTUAL) -void *page_address(const struct page *page); -void set_page_address(struct page *page, void *virtual); -void page_address_init(void); -#endif - -#if !defined(HASHED_PAGE_VIRTUAL) && !defined(WANT_PAGE_VIRTUAL) -#define page_address(page) lowmem_page_address(page) -#define set_page_address(page, address) do { } while(0) -#define page_address_init() do { } while(0) -#endif - -extern void *page_rmapping(struct page *page); -extern struct anon_vma *page_anon_vma(struct page *page); -extern struct address_space *page_mapping(struct page *page); - -extern struct address_space *__page_file_mapping(struct page *); - -static inline -struct address_space *page_file_mapping(struct page *page) -{ - if (unlikely(PageSwapCache(page))) - return __page_file_mapping(page); - - return page->mapping; -} - -extern pgoff_t __page_file_index(struct page *page); - -/* - * Return the pagecache index of the passed page. Regular pagecache pages - * use ->index whereas swapcache pages use swp_offset(->private) - */ -static inline pgoff_t page_index(struct page *page) -{ - if (unlikely(PageSwapCache(page))) - return __page_file_index(page); - return page->index; -} - -bool page_mapped(struct page *page); -struct address_space *page_mapping(struct page *page); - -/* - * Return true only if the page has been allocated with - * ALLOC_NO_WATERMARKS and the low watermark was not - * met implying that the system is under some pressure. - */ -static inline bool page_is_pfmemalloc(struct page *page) -{ - /* - * Page index cannot be this large so this must be - * a pfmemalloc page. - */ - return page->index == -1UL; -} - -/* - * Only to be called by the page allocator on a freshly allocated - * page. - */ -static inline void set_page_pfmemalloc(struct page *page) -{ - page->index = -1UL; -} - -static inline void clear_page_pfmemalloc(struct page *page) -{ - page->index = 0; -} - -/* - * Different kinds of faults, as returned by handle_mm_fault(). - * Used to decide whether a process gets delivered SIGBUS or - * just gets major/minor fault counters bumped up. - */ - -#define VM_FAULT_OOM 0x0001 -#define VM_FAULT_SIGBUS 0x0002 -#define VM_FAULT_MAJOR 0x0004 -#define VM_FAULT_WRITE 0x0008 /* Special case for get_user_pages */ -#define VM_FAULT_HWPOISON 0x0010 /* Hit poisoned small page */ -#define VM_FAULT_HWPOISON_LARGE 0x0020 /* Hit poisoned large page. Index encoded in upper bits */ -#define VM_FAULT_SIGSEGV 0x0040 - -#define VM_FAULT_NOPAGE 0x0100 /* ->fault installed the pte, not return page */ -#define VM_FAULT_LOCKED 0x0200 /* ->fault locked the returned page */ -#define VM_FAULT_RETRY 0x0400 /* ->fault blocked, must retry */ -#define VM_FAULT_FALLBACK 0x0800 /* huge page fault failed, fall back to small */ -#define VM_FAULT_DAX_LOCKED 0x1000 /* ->fault has locked DAX entry */ - -#define VM_FAULT_HWPOISON_LARGE_MASK 0xf000 /* encodes hpage index for large hwpoison */ - -#define VM_FAULT_ERROR (VM_FAULT_OOM | VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV | \ - VM_FAULT_HWPOISON | VM_FAULT_HWPOISON_LARGE | \ - VM_FAULT_FALLBACK) - -/* Encode hstate index for a hwpoisoned large page */ -#define VM_FAULT_SET_HINDEX(x) ((x) << 12) -#define VM_FAULT_GET_HINDEX(x) (((x) >> 12) & 0xf) - -/* - * Can be called by the pagefault handler when it gets a VM_FAULT_OOM. - */ -extern void pagefault_out_of_memory(void); - -#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK) - -/* - * Flags passed to show_mem() and show_free_areas() to suppress output in - * various contexts. - */ -#define SHOW_MEM_FILTER_NODES (0x0001u) /* disallowed nodes */ - -extern void show_free_areas(unsigned int flags); -extern bool skip_free_areas_node(unsigned int flags, int nid); - -int shmem_zero_setup(struct vm_area_struct *); -#ifdef CONFIG_SHMEM -bool shmem_mapping(struct address_space *mapping); -#else -static inline bool shmem_mapping(struct address_space *mapping) -{ - return false; -} -#endif - -extern bool can_do_mlock(void); -extern int user_shm_lock(size_t, struct user_struct *); -extern void user_shm_unlock(size_t, struct user_struct *); - -/* - * Parameter block passed down to zap_pte_range in exceptional cases. - */ -struct zap_details { - struct address_space *check_mapping; /* Check page->mapping if set */ - pgoff_t first_index; /* Lowest page->index to unmap */ - pgoff_t last_index; /* Highest page->index to unmap */ - bool ignore_dirty; /* Ignore dirty pages */ - bool check_swap_entries; /* Check also swap entries */ -}; - -struct page *vm_normal_page(struct vm_area_struct *vma, unsigned long addr, - pte_t pte); -struct page *vm_normal_page_pmd(struct vm_area_struct *vma, unsigned long addr, - pmd_t pmd); - -int zap_vma_ptes(struct vm_area_struct *vma, unsigned long address, - unsigned long size); -void zap_page_range(struct vm_area_struct *vma, unsigned long address, - unsigned long size, struct zap_details *); -void unmap_vmas(struct mmu_gather *tlb, struct vm_area_struct *start_vma, - unsigned long start, unsigned long end); - -/** - * mm_walk - callbacks for walk_page_range - * @pmd_entry: if set, called for each non-empty PMD (3rd-level) entry - * this handler is required to be able to handle - * pmd_trans_huge() pmds. They may simply choose to - * split_huge_page() instead of handling it explicitly. - * @pte_entry: if set, called for each non-empty PTE (4th-level) entry - * @pte_hole: if set, called for each hole at all levels - * @hugetlb_entry: if set, called for each hugetlb entry - * @test_walk: caller specific callback function to determine whether - * we walk over the current vma or not. Returning 0 - * value means "do page table walk over the current vma," - * and a negative one means "abort current page table walk - * right now." 1 means "skip the current vma." - * @mm: mm_struct representing the target process of page table walk - * @vma: vma currently walked (NULL if walking outside vmas) - * @private: private data for callbacks' usage - * - * (see the comment on walk_page_range() for more details) - */ -struct mm_walk { - int (*pmd_entry)(pmd_t *pmd, unsigned long addr, - unsigned long next, struct mm_walk *walk); - int (*pte_entry)(pte_t *pte, unsigned long addr, - unsigned long next, struct mm_walk *walk); - int (*pte_hole)(unsigned long addr, unsigned long next, - struct mm_walk *walk); - int (*hugetlb_entry)(pte_t *pte, unsigned long hmask, - unsigned long addr, unsigned long next, - struct mm_walk *walk); - int (*test_walk)(unsigned long addr, unsigned long next, - struct mm_walk *walk); - struct mm_struct *mm; - struct vm_area_struct *vma; - void *private; -}; - -int walk_page_range(unsigned long addr, unsigned long end, - struct mm_walk *walk); -int walk_page_vma(struct vm_area_struct *vma, struct mm_walk *walk); -void free_pgd_range(struct mmu_gather *tlb, unsigned long addr, - unsigned long end, unsigned long floor, unsigned long ceiling); -int copy_page_range(struct mm_struct *dst, struct mm_struct *src, - struct vm_area_struct *vma); -void unmap_mapping_range(struct address_space *mapping, - loff_t const holebegin, loff_t const holelen, int even_cows); -int follow_pfn(struct vm_area_struct *vma, unsigned long address, - unsigned long *pfn); -int follow_phys(struct vm_area_struct *vma, unsigned long address, - unsigned int flags, unsigned long *prot, resource_size_t *phys); -int generic_access_phys(struct vm_area_struct *vma, unsigned long addr, - void *buf, int len, int write); - -static inline void unmap_shared_mapping_range(struct address_space *mapping, - loff_t const holebegin, loff_t const holelen) -{ - unmap_mapping_range(mapping, holebegin, holelen, 0); -} - -extern void truncate_pagecache(struct inode *inode, loff_t new); -extern void truncate_setsize(struct inode *inode, loff_t newsize); -void pagecache_isize_extended(struct inode *inode, loff_t from, loff_t to); -void truncate_pagecache_range(struct inode *inode, loff_t offset, loff_t end); -int truncate_inode_page(struct address_space *mapping, struct page *page); -int generic_error_remove_page(struct address_space *mapping, struct page *page); -int invalidate_inode_page(struct page *page); - -#ifdef CONFIG_MMU -extern int handle_mm_fault(struct vm_area_struct *vma, unsigned long address, - unsigned int flags); -extern int fixup_user_fault(struct task_struct *tsk, struct mm_struct *mm, - unsigned long address, unsigned int fault_flags, - bool *unlocked); -#else -static inline int handle_mm_fault(struct vm_area_struct *vma, - unsigned long address, unsigned int flags) -{ - /* should never happen if there's no MMU */ - BUG(); - return VM_FAULT_SIGBUS; -} -static inline int fixup_user_fault(struct task_struct *tsk, - struct mm_struct *mm, unsigned long address, - unsigned int fault_flags, bool *unlocked) -{ - /* should never happen if there's no MMU */ - BUG(); - return -EFAULT; -} -#endif - -extern int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, - unsigned int gup_flags); -extern int access_remote_vm(struct mm_struct *mm, unsigned long addr, - void *buf, int len, unsigned int gup_flags); - -long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm, - unsigned long start, unsigned long nr_pages, - unsigned int gup_flags, struct page **pages, - struct vm_area_struct **vmas); -long get_user_pages(unsigned long start, unsigned long nr_pages, - unsigned int gup_flags, struct page **pages, - struct vm_area_struct **vmas); -long get_user_pages_locked(unsigned long start, unsigned long nr_pages, - unsigned int gup_flags, struct page **pages, int *locked); -long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm, - unsigned long start, unsigned long nr_pages, - struct page **pages, unsigned int gup_flags); -long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages, - struct page **pages, unsigned int gup_flags); -int get_user_pages_fast(unsigned long start, int nr_pages, int write, - struct page **pages); - -/* Container for pinned pfns / pages */ -struct frame_vector { - unsigned int nr_allocated; /* Number of frames we have space for */ - unsigned int nr_frames; /* Number of frames stored in ptrs array */ - bool got_ref; /* Did we pin pages by getting page ref? */ - bool is_pfns; /* Does array contain pages or pfns? */ - void *ptrs[0]; /* Array of pinned pfns / pages. Use - * pfns_vector_pages() or pfns_vector_pfns() - * for access */ -}; - -struct frame_vector *frame_vector_create(unsigned int nr_frames); -void frame_vector_destroy(struct frame_vector *vec); -int get_vaddr_frames(unsigned long start, unsigned int nr_pfns, - unsigned int gup_flags, struct frame_vector *vec); -void put_vaddr_frames(struct frame_vector *vec); -int frame_vector_to_pages(struct frame_vector *vec); -void frame_vector_to_pfns(struct frame_vector *vec); - -static inline unsigned int frame_vector_count(struct frame_vector *vec) -{ - return vec->nr_frames; -} - -static inline struct page **frame_vector_pages(struct frame_vector *vec) -{ - if (vec->is_pfns) { - int err = frame_vector_to_pages(vec); - - if (err) - return ERR_PTR(err); - } - return (struct page **)(vec->ptrs); -} - -static inline unsigned long *frame_vector_pfns(struct frame_vector *vec) -{ - if (!vec->is_pfns) - frame_vector_to_pfns(vec); - return (unsigned long *)(vec->ptrs); -} - -struct kvec; -int get_kernel_pages(const struct kvec *iov, int nr_pages, int write, - struct page **pages); -int get_kernel_page(unsigned long start, int write, struct page **pages); -struct page *get_dump_page(unsigned long addr); - -extern int try_to_release_page(struct page * page, gfp_t gfp_mask); -extern void do_invalidatepage(struct page *page, unsigned int offset, - unsigned int length); - -int __set_page_dirty_nobuffers(struct page *page); -int __set_page_dirty_no_writeback(struct page *page); -int redirty_page_for_writepage(struct writeback_control *wbc, - struct page *page); -void account_page_dirtied(struct page *page, struct address_space *mapping); -void account_page_cleaned(struct page *page, struct address_space *mapping, - struct bdi_writeback *wb); -int set_page_dirty(struct page *page); -int set_page_dirty_lock(struct page *page); -void cancel_dirty_page(struct page *page); -int clear_page_dirty_for_io(struct page *page); - -int get_cmdline(struct task_struct *task, char *buffer, int buflen); - -/* Is the vma a continuation of the stack vma above it? */ -static inline int vma_growsdown(struct vm_area_struct *vma, unsigned long addr) -{ - return vma && (vma->vm_end == addr) && (vma->vm_flags & VM_GROWSDOWN); -} - -static inline bool vma_is_anonymous(struct vm_area_struct *vma) -{ - return !vma->vm_ops; -} - -static inline int stack_guard_page_start(struct vm_area_struct *vma, - unsigned long addr) -{ - return (vma->vm_flags & VM_GROWSDOWN) && - (vma->vm_start == addr) && - !vma_growsdown(vma->vm_prev, addr); -} - -/* Is the vma a continuation of the stack vma below it? */ -static inline int vma_growsup(struct vm_area_struct *vma, unsigned long addr) -{ - return vma && (vma->vm_start == addr) && (vma->vm_flags & VM_GROWSUP); -} - -static inline int stack_guard_page_end(struct vm_area_struct *vma, - unsigned long addr) -{ - return (vma->vm_flags & VM_GROWSUP) && - (vma->vm_end == addr) && - !vma_growsup(vma->vm_next, addr); -} - -int vma_is_stack_for_current(struct vm_area_struct *vma); - -extern unsigned long move_page_tables(struct vm_area_struct *vma, - unsigned long old_addr, struct vm_area_struct *new_vma, - unsigned long new_addr, unsigned long len, - bool need_rmap_locks); -extern unsigned long change_protection(struct vm_area_struct *vma, unsigned long start, - unsigned long end, pgprot_t newprot, - int dirty_accountable, int prot_numa); -extern int mprotect_fixup(struct vm_area_struct *vma, - struct vm_area_struct **pprev, unsigned long start, - unsigned long end, unsigned long newflags); - -/* - * doesn't attempt to fault and will return short. - */ -int __get_user_pages_fast(unsigned long start, int nr_pages, int write, - struct page **pages); -/* - * per-process(per-mm_struct) statistics. - */ -static inline unsigned long get_mm_counter(struct mm_struct *mm, int member) -{ - long val = atomic_long_read(&mm->rss_stat.count[member]); - -#ifdef SPLIT_RSS_COUNTING - /* - * counter is updated in asynchronous manner and may go to minus. - * But it's never be expected number for users. - */ - if (val < 0) - val = 0; -#endif - return (unsigned long)val; -} - -static inline void add_mm_counter(struct mm_struct *mm, int member, long value) -{ - atomic_long_add(value, &mm->rss_stat.count[member]); -} - -static inline void inc_mm_counter(struct mm_struct *mm, int member) -{ - atomic_long_inc(&mm->rss_stat.count[member]); -} - -static inline void dec_mm_counter(struct mm_struct *mm, int member) -{ - atomic_long_dec(&mm->rss_stat.count[member]); -} - -/* Optimized variant when page is already known not to be PageAnon */ -static inline int mm_counter_file(struct page *page) -{ - if (PageSwapBacked(page)) - return MM_SHMEMPAGES; - return MM_FILEPAGES; -} - -static inline int mm_counter(struct page *page) -{ - if (PageAnon(page)) - return MM_ANONPAGES; - return mm_counter_file(page); -} - -static inline unsigned long get_mm_rss(struct mm_struct *mm) -{ - return get_mm_counter(mm, MM_FILEPAGES) + - get_mm_counter(mm, MM_ANONPAGES) + - get_mm_counter(mm, MM_SHMEMPAGES); -} - -static inline unsigned long get_mm_hiwater_rss(struct mm_struct *mm) -{ - return max(mm->hiwater_rss, get_mm_rss(mm)); -} - -static inline unsigned long get_mm_hiwater_vm(struct mm_struct *mm) -{ - return max(mm->hiwater_vm, mm->total_vm); -} - -static inline void update_hiwater_rss(struct mm_struct *mm) -{ - unsigned long _rss = get_mm_rss(mm); - - if ((mm)->hiwater_rss < _rss) - (mm)->hiwater_rss = _rss; -} - -static inline void update_hiwater_vm(struct mm_struct *mm) -{ - if (mm->hiwater_vm < mm->total_vm) - mm->hiwater_vm = mm->total_vm; -} - -static inline void reset_mm_hiwater_rss(struct mm_struct *mm) -{ - mm->hiwater_rss = get_mm_rss(mm); -} - -static inline void setmax_mm_hiwater_rss(unsigned long *maxrss, - struct mm_struct *mm) -{ - unsigned long hiwater_rss = get_mm_hiwater_rss(mm); - - if (*maxrss < hiwater_rss) - *maxrss = hiwater_rss; -} - -#if defined(SPLIT_RSS_COUNTING) -void sync_mm_rss(struct mm_struct *mm); -#else -static inline void sync_mm_rss(struct mm_struct *mm) -{ -} -#endif - -#ifndef __HAVE_ARCH_PTE_DEVMAP -static inline int pte_devmap(pte_t pte) -{ - return 0; -} -#endif - -int vma_wants_writenotify(struct vm_area_struct *vma, pgprot_t vm_page_prot); - -extern pte_t *__get_locked_pte(struct mm_struct *mm, unsigned long addr, - spinlock_t **ptl); -static inline pte_t *get_locked_pte(struct mm_struct *mm, unsigned long addr, - spinlock_t **ptl) -{ - pte_t *ptep; - __cond_lock(*ptl, ptep = __get_locked_pte(mm, addr, ptl)); - return ptep; -} - -#ifdef __PAGETABLE_PUD_FOLDED -static inline int __pud_alloc(struct mm_struct *mm, pgd_t *pgd, - unsigned long address) -{ - return 0; -} -#else -int __pud_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address); -#endif - -#if defined(__PAGETABLE_PMD_FOLDED) || !defined(CONFIG_MMU) -static inline int __pmd_alloc(struct mm_struct *mm, pud_t *pud, - unsigned long address) -{ - return 0; -} - -static inline void mm_nr_pmds_init(struct mm_struct *mm) {} - -static inline unsigned long mm_nr_pmds(struct mm_struct *mm) -{ - return 0; -} - -static inline void mm_inc_nr_pmds(struct mm_struct *mm) {} -static inline void mm_dec_nr_pmds(struct mm_struct *mm) {} - -#else -int __pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address); - -static inline void mm_nr_pmds_init(struct mm_struct *mm) -{ - atomic_long_set(&mm->nr_pmds, 0); -} - -static inline unsigned long mm_nr_pmds(struct mm_struct *mm) -{ - return atomic_long_read(&mm->nr_pmds); -} - -static inline void mm_inc_nr_pmds(struct mm_struct *mm) -{ - atomic_long_inc(&mm->nr_pmds); -} - -static inline void mm_dec_nr_pmds(struct mm_struct *mm) -{ - atomic_long_dec(&mm->nr_pmds); -} -#endif - -int __pte_alloc(struct mm_struct *mm, pmd_t *pmd, unsigned long address); -int __pte_alloc_kernel(pmd_t *pmd, unsigned long address); - -/* - * The following ifdef needed to get the 4level-fixup.h header to work. - * Remove it when 4level-fixup.h has been removed. - */ -#if defined(CONFIG_MMU) && !defined(__ARCH_HAS_4LEVEL_HACK) -static inline pud_t *pud_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address) -{ - return (unlikely(pgd_none(*pgd)) && __pud_alloc(mm, pgd, address))? - NULL: pud_offset(pgd, address); -} - -static inline pmd_t *pmd_alloc(struct mm_struct *mm, pud_t *pud, unsigned long address) -{ - return (unlikely(pud_none(*pud)) && __pmd_alloc(mm, pud, address))? - NULL: pmd_offset(pud, address); -} -#endif /* CONFIG_MMU && !__ARCH_HAS_4LEVEL_HACK */ - -#if USE_SPLIT_PTE_PTLOCKS -#if ALLOC_SPLIT_PTLOCKS -void __init ptlock_cache_init(void); -extern bool ptlock_alloc(struct page *page); -extern void ptlock_free(struct page *page); - -static inline spinlock_t *ptlock_ptr(struct page *page) -{ - return page->ptl; -} -#else /* ALLOC_SPLIT_PTLOCKS */ -static inline void ptlock_cache_init(void) -{ -} - -static inline bool ptlock_alloc(struct page *page) -{ - return true; -} - -static inline void ptlock_free(struct page *page) -{ -} - -static inline spinlock_t *ptlock_ptr(struct page *page) -{ - return &page->ptl; -} -#endif /* ALLOC_SPLIT_PTLOCKS */ - -static inline spinlock_t *pte_lockptr(struct mm_struct *mm, pmd_t *pmd) -{ - return ptlock_ptr(pmd_page(*pmd)); -} - -static inline bool ptlock_init(struct page *page) -{ - /* - * prep_new_page() initialize page->private (and therefore page->ptl) - * with 0. Make sure nobody took it in use in between. - * - * It can happen if arch try to use slab for page table allocation: - * slab code uses page->slab_cache, which share storage with page->ptl. - */ - VM_BUG_ON_PAGE(*(unsigned long *)&page->ptl, page); - if (!ptlock_alloc(page)) - return false; - spin_lock_init(ptlock_ptr(page)); - return true; -} - -/* Reset page->mapping so free_pages_check won't complain. */ -static inline void pte_lock_deinit(struct page *page) -{ - page->mapping = NULL; - ptlock_free(page); -} - -#else /* !USE_SPLIT_PTE_PTLOCKS */ -/* - * We use mm->page_table_lock to guard all pagetable pages of the mm. - */ -static inline spinlock_t *pte_lockptr(struct mm_struct *mm, pmd_t *pmd) -{ - return &mm->page_table_lock; -} -static inline void ptlock_cache_init(void) {} -static inline bool ptlock_init(struct page *page) { return true; } -static inline void pte_lock_deinit(struct page *page) {} -#endif /* USE_SPLIT_PTE_PTLOCKS */ - -static inline void pgtable_init(void) -{ - ptlock_cache_init(); - pgtable_cache_init(); -} - -static inline bool pgtable_page_ctor(struct page *page) -{ - if (!ptlock_init(page)) - return false; - inc_zone_page_state(page, NR_PAGETABLE); - return true; -} - -static inline void pgtable_page_dtor(struct page *page) -{ - pte_lock_deinit(page); - dec_zone_page_state(page, NR_PAGETABLE); -} - -#define pte_offset_map_lock(mm, pmd, address, ptlp) \ -({ \ - spinlock_t *__ptl = pte_lockptr(mm, pmd); \ - pte_t *__pte = pte_offset_map(pmd, address); \ - *(ptlp) = __ptl; \ - spin_lock(__ptl); \ - __pte; \ -}) - -#define pte_unmap_unlock(pte, ptl) do { \ - spin_unlock(ptl); \ - pte_unmap(pte); \ -} while (0) - -#define pte_alloc(mm, pmd, address) \ - (unlikely(pmd_none(*(pmd))) && __pte_alloc(mm, pmd, address)) - -#define pte_alloc_map(mm, pmd, address) \ - (pte_alloc(mm, pmd, address) ? NULL : pte_offset_map(pmd, address)) - -#define pte_alloc_map_lock(mm, pmd, address, ptlp) \ - (pte_alloc(mm, pmd, address) ? \ - NULL : pte_offset_map_lock(mm, pmd, address, ptlp)) - -#define pte_alloc_kernel(pmd, address) \ - ((unlikely(pmd_none(*(pmd))) && __pte_alloc_kernel(pmd, address))? \ - NULL: pte_offset_kernel(pmd, address)) - -#if USE_SPLIT_PMD_PTLOCKS - -static struct page *pmd_to_page(pmd_t *pmd) -{ - unsigned long mask = ~(PTRS_PER_PMD * sizeof(pmd_t) - 1); - return virt_to_page((void *)((unsigned long) pmd & mask)); -} - -static inline spinlock_t *pmd_lockptr(struct mm_struct *mm, pmd_t *pmd) -{ - return ptlock_ptr(pmd_to_page(pmd)); -} - -static inline bool pgtable_pmd_page_ctor(struct page *page) -{ -#ifdef CONFIG_TRANSPARENT_HUGEPAGE - page->pmd_huge_pte = NULL; -#endif - return ptlock_init(page); -} - -static inline void pgtable_pmd_page_dtor(struct page *page) -{ -#ifdef CONFIG_TRANSPARENT_HUGEPAGE - VM_BUG_ON_PAGE(page->pmd_huge_pte, page); -#endif - ptlock_free(page); -} - -#define pmd_huge_pte(mm, pmd) (pmd_to_page(pmd)->pmd_huge_pte) - -#else - -static inline spinlock_t *pmd_lockptr(struct mm_struct *mm, pmd_t *pmd) -{ - return &mm->page_table_lock; -} - -static inline bool pgtable_pmd_page_ctor(struct page *page) { return true; } -static inline void pgtable_pmd_page_dtor(struct page *page) {} - -#define pmd_huge_pte(mm, pmd) ((mm)->pmd_huge_pte) - -#endif - -static inline spinlock_t *pmd_lock(struct mm_struct *mm, pmd_t *pmd) -{ - spinlock_t *ptl = pmd_lockptr(mm, pmd); - spin_lock(ptl); - return ptl; -} - -extern void free_area_init(unsigned long * zones_size); -extern void free_area_init_node(int nid, unsigned long * zones_size, - unsigned long zone_start_pfn, unsigned long *zholes_size); -extern void free_initmem(void); - -/* - * Free reserved pages within range [PAGE_ALIGN(start), end & PAGE_MASK) - * into the buddy system. The freed pages will be poisoned with pattern - * "poison" if it's within range [0, UCHAR_MAX]. - * Return pages freed into the buddy system. - */ -extern unsigned long free_reserved_area(void *start, void *end, - int poison, char *s); - -#ifdef CONFIG_HIGHMEM -/* - * Free a highmem page into the buddy system, adjusting totalhigh_pages - * and totalram_pages. - */ -extern void free_highmem_page(struct page *page); -#endif - -extern void adjust_managed_page_count(struct page *page, long count); -extern void mem_init_print_info(const char *str); - -extern void reserve_bootmem_region(phys_addr_t start, phys_addr_t end); - -/* Free the reserved page into the buddy system, so it gets managed. */ -static inline void __free_reserved_page(struct page *page) -{ - ClearPageReserved(page); - init_page_count(page); - __free_page(page); -} - -static inline void free_reserved_page(struct page *page) -{ - __free_reserved_page(page); - adjust_managed_page_count(page, 1); -} - -static inline void mark_page_reserved(struct page *page) -{ - SetPageReserved(page); - adjust_managed_page_count(page, -1); -} - -/* - * Default method to free all the __init memory into the buddy system. - * The freed pages will be poisoned with pattern "poison" if it's within - * range [0, UCHAR_MAX]. - * Return pages freed into the buddy system. - */ -static inline unsigned long free_initmem_default(int poison) -{ - extern char __init_begin[], __init_end[]; - - return free_reserved_area(&__init_begin, &__init_end, - poison, "unused kernel"); -} - -static inline unsigned long get_num_physpages(void) -{ - int nid; - unsigned long phys_pages = 0; - - for_each_online_node(nid) - phys_pages += node_present_pages(nid); - - return phys_pages; -} - -#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP -/* - * With CONFIG_HAVE_MEMBLOCK_NODE_MAP set, an architecture may initialise its - * zones, allocate the backing mem_map and account for memory holes in a more - * architecture independent manner. This is a substitute for creating the - * zone_sizes[] and zholes_size[] arrays and passing them to - * free_area_init_node() - * - * An architecture is expected to register range of page frames backed by - * physical memory with memblock_add[_node]() before calling - * free_area_init_nodes() passing in the PFN each zone ends at. At a basic - * usage, an architecture is expected to do something like - * - * unsigned long max_zone_pfns[MAX_NR_ZONES] = {max_dma, max_normal_pfn, - * max_highmem_pfn}; - * for_each_valid_physical_page_range() - * memblock_add_node(base, size, nid) - * free_area_init_nodes(max_zone_pfns); - * - * free_bootmem_with_active_regions() calls free_bootmem_node() for each - * registered physical page range. Similarly - * sparse_memory_present_with_active_regions() calls memory_present() for - * each range when SPARSEMEM is enabled. - * - * See mm/page_alloc.c for more information on each function exposed by - * CONFIG_HAVE_MEMBLOCK_NODE_MAP. - */ -extern void free_area_init_nodes(unsigned long *max_zone_pfn); -unsigned long node_map_pfn_alignment(void); -unsigned long __absent_pages_in_range(int nid, unsigned long start_pfn, - unsigned long end_pfn); -extern unsigned long absent_pages_in_range(unsigned long start_pfn, - unsigned long end_pfn); -extern void get_pfn_range_for_nid(unsigned int nid, - unsigned long *start_pfn, unsigned long *end_pfn); -extern unsigned long find_min_pfn_with_active_regions(void); -extern void free_bootmem_with_active_regions(int nid, - unsigned long max_low_pfn); -extern void sparse_memory_present_with_active_regions(int nid); - -#endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */ - -#if !defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP) && \ - !defined(CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID) -static inline int __early_pfn_to_nid(unsigned long pfn, - struct mminit_pfnnid_cache *state) -{ - return 0; -} -#else -/* please see mm/page_alloc.c */ -extern int __meminit early_pfn_to_nid(unsigned long pfn); -/* there is a per-arch backend function. */ -extern int __meminit __early_pfn_to_nid(unsigned long pfn, - struct mminit_pfnnid_cache *state); -#endif - -extern void set_dma_reserve(unsigned long new_dma_reserve); -extern void memmap_init_zone(unsigned long, int, unsigned long, - unsigned long, enum memmap_context); -extern void setup_per_zone_wmarks(void); -extern int __meminit init_per_zone_wmark_min(void); -extern void mem_init(void); -extern void __init mmap_init(void); -extern void show_mem(unsigned int flags); -extern long si_mem_available(void); -extern void si_meminfo(struct sysinfo * val); -extern void si_meminfo_node(struct sysinfo *val, int nid); -#ifdef __HAVE_ARCH_RESERVED_KERNEL_PAGES -extern unsigned long arch_reserved_kernel_pages(void); -#endif - -extern __printf(2, 3) -void warn_alloc(gfp_t gfp_mask, const char *fmt, ...); - -extern void setup_per_cpu_pageset(void); - -extern void zone_pcp_update(struct zone *zone); -extern void zone_pcp_reset(struct zone *zone); - -/* page_alloc.c */ -extern int min_free_kbytes; -extern int watermark_scale_factor; - -/* nommu.c */ -extern atomic_long_t mmap_pages_allocated; -extern int nommu_shrink_inode_mappings(struct inode *, size_t, size_t); - -/* interval_tree.c */ -void vma_interval_tree_insert(struct vm_area_struct *node, - struct rb_root *root); -void vma_interval_tree_insert_after(struct vm_area_struct *node, - struct vm_area_struct *prev, - struct rb_root *root); -void vma_interval_tree_remove(struct vm_area_struct *node, - struct rb_root *root); -struct vm_area_struct *vma_interval_tree_iter_first(struct rb_root *root, - unsigned long start, unsigned long last); -struct vm_area_struct *vma_interval_tree_iter_next(struct vm_area_struct *node, - unsigned long start, unsigned long last); - -#define vma_interval_tree_foreach(vma, root, start, last) \ - for (vma = vma_interval_tree_iter_first(root, start, last); \ - vma; vma = vma_interval_tree_iter_next(vma, start, last)) - -void anon_vma_interval_tree_insert(struct anon_vma_chain *node, - struct rb_root *root); -void anon_vma_interval_tree_remove(struct anon_vma_chain *node, - struct rb_root *root); -struct anon_vma_chain *anon_vma_interval_tree_iter_first( - struct rb_root *root, unsigned long start, unsigned long last); -struct anon_vma_chain *anon_vma_interval_tree_iter_next( - struct anon_vma_chain *node, unsigned long start, unsigned long last); -#ifdef CONFIG_DEBUG_VM_RB -void anon_vma_interval_tree_verify(struct anon_vma_chain *node); -#endif - -#define anon_vma_interval_tree_foreach(avc, root, start, last) \ - for (avc = anon_vma_interval_tree_iter_first(root, start, last); \ - avc; avc = anon_vma_interval_tree_iter_next(avc, start, last)) - -/* mmap.c */ -extern int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin); -extern int __vma_adjust(struct vm_area_struct *vma, unsigned long start, - unsigned long end, pgoff_t pgoff, struct vm_area_struct *insert, - struct vm_area_struct *expand); -static inline int vma_adjust(struct vm_area_struct *vma, unsigned long start, - unsigned long end, pgoff_t pgoff, struct vm_area_struct *insert) -{ - return __vma_adjust(vma, start, end, pgoff, insert, NULL); -} -extern struct vm_area_struct *vma_merge(struct mm_struct *, - struct vm_area_struct *prev, unsigned long addr, unsigned long end, - unsigned long vm_flags, struct anon_vma *, struct file *, pgoff_t, - struct mempolicy *, struct vm_userfaultfd_ctx); -extern struct anon_vma *find_mergeable_anon_vma(struct vm_area_struct *); -extern int split_vma(struct mm_struct *, - struct vm_area_struct *, unsigned long addr, int new_below); -extern int insert_vm_struct(struct mm_struct *, struct vm_area_struct *); -extern void __vma_link_rb(struct mm_struct *, struct vm_area_struct *, - struct rb_node **, struct rb_node *); -extern void unlink_file_vma(struct vm_area_struct *); -extern struct vm_area_struct *copy_vma(struct vm_area_struct **, - unsigned long addr, unsigned long len, pgoff_t pgoff, - bool *need_rmap_locks); -extern void exit_mmap(struct mm_struct *); - -static inline int check_data_rlimit(unsigned long rlim, - unsigned long new, - unsigned long start, - unsigned long end_data, - unsigned long start_data) -{ - if (rlim < RLIM_INFINITY) { - if (((new - start) + (end_data - start_data)) > rlim) - return -ENOSPC; - } - - return 0; -} - -extern int mm_take_all_locks(struct mm_struct *mm); -extern void mm_drop_all_locks(struct mm_struct *mm); - -extern void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file); -extern struct file *get_mm_exe_file(struct mm_struct *mm); -extern struct file *get_task_exe_file(struct task_struct *task); - -extern bool may_expand_vm(struct mm_struct *, vm_flags_t, unsigned long npages); -extern void vm_stat_account(struct mm_struct *, vm_flags_t, long npages); - -extern bool vma_is_special_mapping(const struct vm_area_struct *vma, - const struct vm_special_mapping *sm); -extern struct vm_area_struct *_install_special_mapping(struct mm_struct *mm, - unsigned long addr, unsigned long len, - unsigned long flags, - const struct vm_special_mapping *spec); -/* This is an obsolete alternative to _install_special_mapping. */ -extern int install_special_mapping(struct mm_struct *mm, - unsigned long addr, unsigned long len, - unsigned long flags, struct page **pages); - -extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); - -extern unsigned long mmap_region(struct file *file, unsigned long addr, - unsigned long len, vm_flags_t vm_flags, unsigned long pgoff); -extern unsigned long do_mmap(struct file *file, unsigned long addr, - unsigned long len, unsigned long prot, unsigned long flags, - vm_flags_t vm_flags, unsigned long pgoff, unsigned long *populate); -extern int do_munmap(struct mm_struct *, unsigned long, size_t); - -static inline unsigned long -do_mmap_pgoff(struct file *file, unsigned long addr, - unsigned long len, unsigned long prot, unsigned long flags, - unsigned long pgoff, unsigned long *populate) -{ - return do_mmap(file, addr, len, prot, flags, 0, pgoff, populate); -} - -#ifdef CONFIG_MMU -extern int __mm_populate(unsigned long addr, unsigned long len, - int ignore_errors); -static inline void mm_populate(unsigned long addr, unsigned long len) -{ - /* Ignore errors */ - (void) __mm_populate(addr, len, 1); -} -#else -static inline void mm_populate(unsigned long addr, unsigned long len) {} -#endif - -/* These take the mm semaphore themselves */ -extern int __must_check vm_brk(unsigned long, unsigned long); -extern int vm_munmap(unsigned long, size_t); -extern unsigned long __must_check vm_mmap(struct file *, unsigned long, - unsigned long, unsigned long, - unsigned long, unsigned long); - -struct vm_unmapped_area_info { -#define VM_UNMAPPED_AREA_TOPDOWN 1 - unsigned long flags; - unsigned long length; - unsigned long low_limit; - unsigned long high_limit; - unsigned long align_mask; - unsigned long align_offset; -}; - -extern unsigned long unmapped_area(struct vm_unmapped_area_info *info); -extern unsigned long unmapped_area_topdown(struct vm_unmapped_area_info *info); - -/* - * Search for an unmapped address range. - * - * We are looking for a range that: - * - does not intersect with any VMA; - * - is contained within the [low_limit, high_limit) interval; - * - is at least the desired size. - * - satisfies (begin_addr & align_mask) == (align_offset & align_mask) - */ -static inline unsigned long -vm_unmapped_area(struct vm_unmapped_area_info *info) -{ - if (info->flags & VM_UNMAPPED_AREA_TOPDOWN) - return unmapped_area_topdown(info); - else - return unmapped_area(info); -} - -/* truncate.c */ -extern void truncate_inode_pages(struct address_space *, loff_t); -extern void truncate_inode_pages_range(struct address_space *, - loff_t lstart, loff_t lend); -extern void truncate_inode_pages_final(struct address_space *); - -/* generic vm_area_ops exported for stackable file systems */ -extern int filemap_fault(struct vm_area_struct *, struct vm_fault *); -extern void filemap_map_pages(struct fault_env *fe, - pgoff_t start_pgoff, pgoff_t end_pgoff); -extern int filemap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); - -/* mm/page-writeback.c */ -int write_one_page(struct page *page, int wait); -void task_dirty_inc(struct task_struct *tsk); - -/* readahead.c */ -#define VM_MAX_READAHEAD 128 /* kbytes */ -#define VM_MIN_READAHEAD 16 /* kbytes (includes current page) */ - -int force_page_cache_readahead(struct address_space *mapping, struct file *filp, - pgoff_t offset, unsigned long nr_to_read); - -void page_cache_sync_readahead(struct address_space *mapping, - struct file_ra_state *ra, - struct file *filp, - pgoff_t offset, - unsigned long size); - -void page_cache_async_readahead(struct address_space *mapping, - struct file_ra_state *ra, - struct file *filp, - struct page *pg, - pgoff_t offset, - unsigned long size); - -/* Generic expand stack which grows the stack according to GROWS{UP,DOWN} */ -extern int expand_stack(struct vm_area_struct *vma, unsigned long address); - -/* CONFIG_STACK_GROWSUP still needs to to grow downwards at some places */ -extern int expand_downwards(struct vm_area_struct *vma, - unsigned long address); -#if VM_GROWSUP -extern int expand_upwards(struct vm_area_struct *vma, unsigned long address); -#else - #define expand_upwards(vma, address) (0) -#endif - -/* Look up the first VMA which satisfies addr < vm_end, NULL if none. */ -extern struct vm_area_struct * find_vma(struct mm_struct * mm, unsigned long addr); -extern struct vm_area_struct * find_vma_prev(struct mm_struct * mm, unsigned long addr, - struct vm_area_struct **pprev); - -/* Look up the first VMA which intersects the interval start_addr..end_addr-1, - NULL if none. Assume start_addr < end_addr. */ -static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr) -{ - struct vm_area_struct * vma = find_vma(mm,start_addr); - - if (vma && end_addr <= vma->vm_start) - vma = NULL; - return vma; -} - -static inline unsigned long vma_pages(struct vm_area_struct *vma) -{ - return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; -} - -/* Look up the first VMA which exactly match the interval vm_start ... vm_end */ -static inline struct vm_area_struct *find_exact_vma(struct mm_struct *mm, - unsigned long vm_start, unsigned long vm_end) -{ - struct vm_area_struct *vma = find_vma(mm, vm_start); - - if (vma && (vma->vm_start != vm_start || vma->vm_end != vm_end)) - vma = NULL; - - return vma; -} - -#ifdef CONFIG_MMU -pgprot_t vm_get_page_prot(unsigned long vm_flags); -void vma_set_page_prot(struct vm_area_struct *vma); -#else -static inline pgprot_t vm_get_page_prot(unsigned long vm_flags) -{ - return __pgprot(0); -} -static inline void vma_set_page_prot(struct vm_area_struct *vma) -{ - vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); -} -#endif - -#ifdef CONFIG_NUMA_BALANCING -unsigned long change_prot_numa(struct vm_area_struct *vma, - unsigned long start, unsigned long end); -#endif - -struct vm_area_struct *find_extend_vma(struct mm_struct *, unsigned long addr); -int remap_pfn_range(struct vm_area_struct *, unsigned long addr, - unsigned long pfn, unsigned long size, pgprot_t); -int vm_insert_page(struct vm_area_struct *, unsigned long addr, struct page *); -int vm_insert_pfn(struct vm_area_struct *vma, unsigned long addr, - unsigned long pfn); -int vm_insert_pfn_prot(struct vm_area_struct *vma, unsigned long addr, - unsigned long pfn, pgprot_t pgprot); -int vm_insert_mixed(struct vm_area_struct *vma, unsigned long addr, - pfn_t pfn); -int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long len); - - -struct page *follow_page_mask(struct vm_area_struct *vma, - unsigned long address, unsigned int foll_flags, - unsigned int *page_mask); - -static inline struct page *follow_page(struct vm_area_struct *vma, - unsigned long address, unsigned int foll_flags) -{ - unsigned int unused_page_mask; - return follow_page_mask(vma, address, foll_flags, &unused_page_mask); -} - -#define FOLL_WRITE 0x01 /* check pte is writable */ -#define FOLL_TOUCH 0x02 /* mark page accessed */ -#define FOLL_GET 0x04 /* do get_page on page */ -#define FOLL_DUMP 0x08 /* give error on hole if it would be zero */ -#define FOLL_FORCE 0x10 /* get_user_pages read/write w/o permission */ -#define FOLL_NOWAIT 0x20 /* if a disk transfer is needed, start the IO - * and return without waiting upon it */ -#define FOLL_POPULATE 0x40 /* fault in page */ -#define FOLL_SPLIT 0x80 /* don't return transhuge pages, split them */ -#define FOLL_HWPOISON 0x100 /* check page is hwpoisoned */ -#define FOLL_NUMA 0x200 /* force NUMA hinting page fault */ -#define FOLL_MIGRATION 0x400 /* wait for page to replace migration entry */ -#define FOLL_TRIED 0x800 /* a retry, previous pass started an IO */ -#define FOLL_MLOCK 0x1000 /* lock present pages */ -#define FOLL_REMOTE 0x2000 /* we are working on non-current tsk/mm */ -#define FOLL_COW 0x4000 /* internal GUP flag */ - -typedef int (*pte_fn_t)(pte_t *pte, pgtable_t token, unsigned long addr, - void *data); -extern int apply_to_page_range(struct mm_struct *mm, unsigned long address, - unsigned long size, pte_fn_t fn, void *data); - - -#ifdef CONFIG_PAGE_POISONING -extern bool page_poisoning_enabled(void); -extern void kernel_poison_pages(struct page *page, int numpages, int enable); -extern bool page_is_poisoned(struct page *page); -#else -static inline bool page_poisoning_enabled(void) { return false; } -static inline void kernel_poison_pages(struct page *page, int numpages, - int enable) { } -static inline bool page_is_poisoned(struct page *page) { return false; } -#endif - -#ifdef CONFIG_DEBUG_PAGEALLOC -extern bool _debug_pagealloc_enabled; -extern void __kernel_map_pages(struct page *page, int numpages, int enable); - -static inline bool debug_pagealloc_enabled(void) -{ - return _debug_pagealloc_enabled; -} - -static inline void -kernel_map_pages(struct page *page, int numpages, int enable) -{ - if (!debug_pagealloc_enabled()) - return; - - __kernel_map_pages(page, numpages, enable); -} -#ifdef CONFIG_HIBERNATION -extern bool kernel_page_present(struct page *page); -#endif /* CONFIG_HIBERNATION */ -#else /* CONFIG_DEBUG_PAGEALLOC */ -static inline void -kernel_map_pages(struct page *page, int numpages, int enable) {} -#ifdef CONFIG_HIBERNATION -static inline bool kernel_page_present(struct page *page) { return true; } -#endif /* CONFIG_HIBERNATION */ -static inline bool debug_pagealloc_enabled(void) -{ - return false; -} -#endif /* CONFIG_DEBUG_PAGEALLOC */ - -#ifdef __HAVE_ARCH_GATE_AREA -extern struct vm_area_struct *get_gate_vma(struct mm_struct *mm); -extern int in_gate_area_no_mm(unsigned long addr); -extern int in_gate_area(struct mm_struct *mm, unsigned long addr); -#else -static inline struct vm_area_struct *get_gate_vma(struct mm_struct *mm) -{ - return NULL; -} -static inline int in_gate_area_no_mm(unsigned long addr) { return 0; } -static inline int in_gate_area(struct mm_struct *mm, unsigned long addr) -{ - return 0; -} -#endif /* __HAVE_ARCH_GATE_AREA */ - -extern bool process_shares_mm(struct task_struct *p, struct mm_struct *mm); - -#ifdef CONFIG_SYSCTL -extern int sysctl_drop_caches; -int drop_caches_sysctl_handler(struct ctl_table *, int, - void __user *, size_t *, loff_t *); -#endif - -void drop_slab(void); -void drop_slab_node(int nid); - -#ifndef CONFIG_MMU -#define randomize_va_space 0 -#else -extern int randomize_va_space; -#endif - -const char * arch_vma_name(struct vm_area_struct *vma); -void print_vma_addr(char *prefix, unsigned long rip); - -void sparse_mem_maps_populate_node(struct page **map_map, - unsigned long pnum_begin, - unsigned long pnum_end, - unsigned long map_count, - int nodeid); - -struct page *sparse_mem_map_populate(unsigned long pnum, int nid); -pgd_t *vmemmap_pgd_populate(unsigned long addr, int node); -pud_t *vmemmap_pud_populate(pgd_t *pgd, unsigned long addr, int node); -pmd_t *vmemmap_pmd_populate(pud_t *pud, unsigned long addr, int node); -pte_t *vmemmap_pte_populate(pmd_t *pmd, unsigned long addr, int node); -void *vmemmap_alloc_block(unsigned long size, int node); -struct vmem_altmap; -void *__vmemmap_alloc_block_buf(unsigned long size, int node, - struct vmem_altmap *altmap); -static inline void *vmemmap_alloc_block_buf(unsigned long size, int node) -{ - return __vmemmap_alloc_block_buf(size, node, NULL); -} - -void vmemmap_verify(pte_t *, int, unsigned long, unsigned long); -int vmemmap_populate_basepages(unsigned long start, unsigned long end, - int node); -int vmemmap_populate(unsigned long start, unsigned long end, int node); -void vmemmap_populate_print_last(void); -#ifdef CONFIG_MEMORY_HOTPLUG -void vmemmap_free(unsigned long start, unsigned long end); -#endif -void register_page_bootmem_memmap(unsigned long section_nr, struct page *map, - unsigned long size); - -enum mf_flags { - MF_COUNT_INCREASED = 1 << 0, - MF_ACTION_REQUIRED = 1 << 1, - MF_MUST_KILL = 1 << 2, - MF_SOFT_OFFLINE = 1 << 3, -}; -extern int memory_failure(unsigned long pfn, int trapno, int flags); -extern void memory_failure_queue(unsigned long pfn, int trapno, int flags); -extern int unpoison_memory(unsigned long pfn); -extern int get_hwpoison_page(struct page *page); -#define put_hwpoison_page(page) put_page(page) -extern int sysctl_memory_failure_early_kill; -extern int sysctl_memory_failure_recovery; -extern void shake_page(struct page *p, int access); -extern atomic_long_t num_poisoned_pages; -extern int soft_offline_page(struct page *page, int flags); - - -/* - * Error handlers for various types of pages. - */ -enum mf_result { - MF_IGNORED, /* Error: cannot be handled */ - MF_FAILED, /* Error: handling failed */ - MF_DELAYED, /* Will be handled later */ - MF_RECOVERED, /* Successfully recovered */ -}; - -enum mf_action_page_type { - MF_MSG_KERNEL, - MF_MSG_KERNEL_HIGH_ORDER, - MF_MSG_SLAB, - MF_MSG_DIFFERENT_COMPOUND, - MF_MSG_POISONED_HUGE, - MF_MSG_HUGE, - MF_MSG_FREE_HUGE, - MF_MSG_UNMAP_FAILED, - MF_MSG_DIRTY_SWAPCACHE, - MF_MSG_CLEAN_SWAPCACHE, - MF_MSG_DIRTY_MLOCKED_LRU, - MF_MSG_CLEAN_MLOCKED_LRU, - MF_MSG_DIRTY_UNEVICTABLE_LRU, - MF_MSG_CLEAN_UNEVICTABLE_LRU, - MF_MSG_DIRTY_LRU, - MF_MSG_CLEAN_LRU, - MF_MSG_TRUNCATED_LRU, - MF_MSG_BUDDY, - MF_MSG_BUDDY_2ND, - MF_MSG_UNKNOWN, -}; - -#if defined(CONFIG_TRANSPARENT_HUGEPAGE) || defined(CONFIG_HUGETLBFS) -extern void clear_huge_page(struct page *page, - unsigned long addr, - unsigned int pages_per_huge_page); -extern void copy_user_huge_page(struct page *dst, struct page *src, - unsigned long addr, struct vm_area_struct *vma, - unsigned int pages_per_huge_page); -#endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_HUGETLBFS */ - -extern struct page_ext_operations debug_guardpage_ops; -extern struct page_ext_operations page_poisoning_ops; - -#ifdef CONFIG_DEBUG_PAGEALLOC -extern unsigned int _debug_guardpage_minorder; -extern bool _debug_guardpage_enabled; - -static inline unsigned int debug_guardpage_minorder(void) -{ - return _debug_guardpage_minorder; -} - -static inline bool debug_guardpage_enabled(void) -{ - return _debug_guardpage_enabled; -} - -static inline bool page_is_guard(struct page *page) -{ - struct page_ext *page_ext; - - if (!debug_guardpage_enabled()) - return false; - - page_ext = lookup_page_ext(page); - if (unlikely(!page_ext)) - return false; - - return test_bit(PAGE_EXT_DEBUG_GUARD, &page_ext->flags); -} -#else -static inline unsigned int debug_guardpage_minorder(void) { return 0; } -static inline bool debug_guardpage_enabled(void) { return false; } -static inline bool page_is_guard(struct page *page) { return false; } -#endif /* CONFIG_DEBUG_PAGEALLOC */ - -#if MAX_NUMNODES > 1 -void __init setup_nr_node_ids(void); -#else -static inline void setup_nr_node_ids(void) {} -#endif - -#endif /* __KERNEL__ */ -#endif /* _LINUX_MM_H */ diff --git a/src/linux/include/linux/mm_inline.h b/src/linux/include/linux/mm_inline.h deleted file mode 100644 index 71613e8..0000000 --- a/src/linux/include/linux/mm_inline.h +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef LINUX_MM_INLINE_H -#define LINUX_MM_INLINE_H - -#include -#include - -/** - * page_is_file_cache - should the page be on a file LRU or anon LRU? - * @page: the page to test - * - * Returns 1 if @page is page cache page backed by a regular filesystem, - * or 0 if @page is anonymous, tmpfs or otherwise ram or swap backed. - * Used by functions that manipulate the LRU lists, to sort a page - * onto the right LRU list. - * - * We would like to get this info without a page flag, but the state - * needs to survive until the page is last deleted from the LRU, which - * could be as far down as __page_cache_release. - */ -static inline int page_is_file_cache(struct page *page) -{ - return !PageSwapBacked(page); -} - -static __always_inline void __update_lru_size(struct lruvec *lruvec, - enum lru_list lru, enum zone_type zid, - int nr_pages) -{ - struct pglist_data *pgdat = lruvec_pgdat(lruvec); - - __mod_node_page_state(pgdat, NR_LRU_BASE + lru, nr_pages); - __mod_zone_page_state(&pgdat->node_zones[zid], - NR_ZONE_LRU_BASE + lru, nr_pages); -} - -static __always_inline void update_lru_size(struct lruvec *lruvec, - enum lru_list lru, enum zone_type zid, - int nr_pages) -{ - __update_lru_size(lruvec, lru, zid, nr_pages); -#ifdef CONFIG_MEMCG - mem_cgroup_update_lru_size(lruvec, lru, nr_pages); -#endif -} - -static __always_inline void add_page_to_lru_list(struct page *page, - struct lruvec *lruvec, enum lru_list lru) -{ - update_lru_size(lruvec, lru, page_zonenum(page), hpage_nr_pages(page)); - list_add(&page->lru, &lruvec->lists[lru]); -} - -static __always_inline void del_page_from_lru_list(struct page *page, - struct lruvec *lruvec, enum lru_list lru) -{ - list_del(&page->lru); - update_lru_size(lruvec, lru, page_zonenum(page), -hpage_nr_pages(page)); -} - -/** - * page_lru_base_type - which LRU list type should a page be on? - * @page: the page to test - * - * Used for LRU list index arithmetic. - * - * Returns the base LRU type - file or anon - @page should be on. - */ -static inline enum lru_list page_lru_base_type(struct page *page) -{ - if (page_is_file_cache(page)) - return LRU_INACTIVE_FILE; - return LRU_INACTIVE_ANON; -} - -/** - * page_off_lru - which LRU list was page on? clearing its lru flags. - * @page: the page to test - * - * Returns the LRU list a page was on, as an index into the array of LRU - * lists; and clears its Unevictable or Active flags, ready for freeing. - */ -static __always_inline enum lru_list page_off_lru(struct page *page) -{ - enum lru_list lru; - - if (PageUnevictable(page)) { - __ClearPageUnevictable(page); - lru = LRU_UNEVICTABLE; - } else { - lru = page_lru_base_type(page); - if (PageActive(page)) { - __ClearPageActive(page); - lru += LRU_ACTIVE; - } - } - return lru; -} - -/** - * page_lru - which LRU list should a page be on? - * @page: the page to test - * - * Returns the LRU list a page should be on, as an index - * into the array of LRU lists. - */ -static __always_inline enum lru_list page_lru(struct page *page) -{ - enum lru_list lru; - - if (PageUnevictable(page)) - lru = LRU_UNEVICTABLE; - else { - lru = page_lru_base_type(page); - if (PageActive(page)) - lru += LRU_ACTIVE; - } - return lru; -} - -#define lru_to_page(head) (list_entry((head)->prev, struct page, lru)) - -#endif diff --git a/src/linux/include/linux/mm_types.h b/src/linux/include/linux/mm_types.h deleted file mode 100644 index 4a8aced..0000000 --- a/src/linux/include/linux/mm_types.h +++ /dev/null @@ -1,618 +0,0 @@ -#ifndef _LINUX_MM_TYPES_H -#define _LINUX_MM_TYPES_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef AT_VECTOR_SIZE_ARCH -#define AT_VECTOR_SIZE_ARCH 0 -#endif -#define AT_VECTOR_SIZE (2*(AT_VECTOR_SIZE_ARCH + AT_VECTOR_SIZE_BASE + 1)) - -struct address_space; -struct mem_cgroup; - -#define USE_SPLIT_PTE_PTLOCKS (NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS) -#define USE_SPLIT_PMD_PTLOCKS (USE_SPLIT_PTE_PTLOCKS && \ - IS_ENABLED(CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK)) -#define ALLOC_SPLIT_PTLOCKS (SPINLOCK_SIZE > BITS_PER_LONG/8) - -/* - * Each physical page in the system has a struct page associated with - * it to keep track of whatever it is we are using the page for at the - * moment. Note that we have no way to track which tasks are using - * a page, though if it is a pagecache page, rmap structures can tell us - * who is mapping it. - * - * The objects in struct page are organized in double word blocks in - * order to allows us to use atomic double word operations on portions - * of struct page. That is currently only used by slub but the arrangement - * allows the use of atomic double word operations on the flags/mapping - * and lru list pointers also. - */ -struct page { - /* First double word block */ - unsigned long flags; /* Atomic flags, some possibly - * updated asynchronously */ - union { - struct address_space *mapping; /* If low bit clear, points to - * inode address_space, or NULL. - * If page mapped as anonymous - * memory, low bit is set, and - * it points to anon_vma object: - * see PAGE_MAPPING_ANON below. - */ - void *s_mem; /* slab first object */ - atomic_t compound_mapcount; /* first tail page */ - /* page_deferred_list().next -- second tail page */ - }; - - /* Second double word */ - union { - pgoff_t index; /* Our offset within mapping. */ - void *freelist; /* sl[aou]b first free object */ - /* page_deferred_list().prev -- second tail page */ - }; - - union { -#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \ - defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE) - /* Used for cmpxchg_double in slub */ - unsigned long counters; -#else - /* - * Keep _refcount separate from slub cmpxchg_double data. - * As the rest of the double word is protected by slab_lock - * but _refcount is not. - */ - unsigned counters; -#endif - struct { - - union { - /* - * Count of ptes mapped in mms, to show when - * page is mapped & limit reverse map searches. - * - * Extra information about page type may be - * stored here for pages that are never mapped, - * in which case the value MUST BE <= -2. - * See page-flags.h for more details. - */ - atomic_t _mapcount; - - unsigned int active; /* SLAB */ - struct { /* SLUB */ - unsigned inuse:16; - unsigned objects:15; - unsigned frozen:1; - }; - int units; /* SLOB */ - }; - /* - * Usage count, *USE WRAPPER FUNCTION* when manual - * accounting. See page_ref.h - */ - atomic_t _refcount; - }; - }; - - /* - * Third double word block - * - * WARNING: bit 0 of the first word encode PageTail(). That means - * the rest users of the storage space MUST NOT use the bit to - * avoid collision and false-positive PageTail(). - */ - union { - struct list_head lru; /* Pageout list, eg. active_list - * protected by zone_lru_lock ! - * Can be used as a generic list - * by the page owner. - */ - struct dev_pagemap *pgmap; /* ZONE_DEVICE pages are never on an - * lru or handled by a slab - * allocator, this points to the - * hosting device page map. - */ - struct { /* slub per cpu partial pages */ - struct page *next; /* Next partial slab */ -#ifdef CONFIG_64BIT - int pages; /* Nr of partial slabs left */ - int pobjects; /* Approximate # of objects */ -#else - short int pages; - short int pobjects; -#endif - }; - - struct rcu_head rcu_head; /* Used by SLAB - * when destroying via RCU - */ - /* Tail pages of compound page */ - struct { - unsigned long compound_head; /* If bit zero is set */ - - /* First tail page only */ -#ifdef CONFIG_64BIT - /* - * On 64 bit system we have enough space in struct page - * to encode compound_dtor and compound_order with - * unsigned int. It can help compiler generate better or - * smaller code on some archtectures. - */ - unsigned int compound_dtor; - unsigned int compound_order; -#else - unsigned short int compound_dtor; - unsigned short int compound_order; -#endif - }; - -#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && USE_SPLIT_PMD_PTLOCKS - struct { - unsigned long __pad; /* do not overlay pmd_huge_pte - * with compound_head to avoid - * possible bit 0 collision. - */ - pgtable_t pmd_huge_pte; /* protected by page->ptl */ - }; -#endif - }; - - /* Remainder is not double word aligned */ - union { - unsigned long private; /* Mapping-private opaque data: - * usually used for buffer_heads - * if PagePrivate set; used for - * swp_entry_t if PageSwapCache; - * indicates order in the buddy - * system if PG_buddy is set. - */ -#if USE_SPLIT_PTE_PTLOCKS -#if ALLOC_SPLIT_PTLOCKS - spinlock_t *ptl; -#else - spinlock_t ptl; -#endif -#endif - struct kmem_cache *slab_cache; /* SL[AU]B: Pointer to slab */ - }; - -#ifdef CONFIG_MEMCG - struct mem_cgroup *mem_cgroup; -#endif - - /* - * On machines where all RAM is mapped into kernel address space, - * we can simply calculate the virtual address. On machines with - * highmem some memory is mapped into kernel virtual memory - * dynamically, so we need a place to store that address. - * Note that this field could be 16 bits on x86 ... ;) - * - * Architectures with slow multiplication can define - * WANT_PAGE_VIRTUAL in asm/page.h - */ -#if defined(WANT_PAGE_VIRTUAL) - void *virtual; /* Kernel virtual address (NULL if - not kmapped, ie. highmem) */ -#endif /* WANT_PAGE_VIRTUAL */ - -#ifdef CONFIG_KMEMCHECK - /* - * kmemcheck wants to track the status of each byte in a page; this - * is a pointer to such a status block. NULL if not tracked. - */ - void *shadow; -#endif - -#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS - int _last_cpupid; -#endif -} -/* - * The struct page can be forced to be double word aligned so that atomic ops - * on double words work. The SLUB allocator can make use of such a feature. - */ -#ifdef CONFIG_HAVE_ALIGNED_STRUCT_PAGE - __aligned(2 * sizeof(unsigned long)) -#endif -; - -struct page_frag { - struct page *page; -#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536) - __u32 offset; - __u32 size; -#else - __u16 offset; - __u16 size; -#endif -}; - -#define PAGE_FRAG_CACHE_MAX_SIZE __ALIGN_MASK(32768, ~PAGE_MASK) -#define PAGE_FRAG_CACHE_MAX_ORDER get_order(PAGE_FRAG_CACHE_MAX_SIZE) - -struct page_frag_cache { - void * va; -#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) - __u16 offset; - __u16 size; -#else - __u32 offset; -#endif - /* we maintain a pagecount bias, so that we dont dirty cache line - * containing page->_refcount every time we allocate a fragment. - */ - unsigned int pagecnt_bias; - bool pfmemalloc; -}; - -typedef unsigned long vm_flags_t; - -/* - * A region containing a mapping of a non-memory backed file under NOMMU - * conditions. These are held in a global tree and are pinned by the VMAs that - * map parts of them. - */ -struct vm_region { - struct rb_node vm_rb; /* link in global region tree */ - vm_flags_t vm_flags; /* VMA vm_flags */ - unsigned long vm_start; /* start address of region */ - unsigned long vm_end; /* region initialised to here */ - unsigned long vm_top; /* region allocated to here */ - unsigned long vm_pgoff; /* the offset in vm_file corresponding to vm_start */ - struct file *vm_file; /* the backing file or NULL */ - - int vm_usage; /* region usage count (access under nommu_region_sem) */ - bool vm_icache_flushed : 1; /* true if the icache has been flushed for - * this region */ -}; - -#ifdef CONFIG_USERFAULTFD -#define NULL_VM_UFFD_CTX ((struct vm_userfaultfd_ctx) { NULL, }) -struct vm_userfaultfd_ctx { - struct userfaultfd_ctx *ctx; -}; -#else /* CONFIG_USERFAULTFD */ -#define NULL_VM_UFFD_CTX ((struct vm_userfaultfd_ctx) {}) -struct vm_userfaultfd_ctx {}; -#endif /* CONFIG_USERFAULTFD */ - -/* - * This struct defines a memory VMM memory area. There is one of these - * per VM-area/task. A VM area is any part of the process virtual memory - * space that has a special rule for the page-fault handlers (ie a shared - * library, the executable area etc). - */ -struct vm_area_struct { - /* The first cache line has the info for VMA tree walking. */ - - unsigned long vm_start; /* Our start address within vm_mm. */ - unsigned long vm_end; /* The first byte after our end address - within vm_mm. */ - - /* linked list of VM areas per task, sorted by address */ - struct vm_area_struct *vm_next, *vm_prev; - - struct rb_node vm_rb; - - /* - * Largest free memory gap in bytes to the left of this VMA. - * Either between this VMA and vma->vm_prev, or between one of the - * VMAs below us in the VMA rbtree and its ->vm_prev. This helps - * get_unmapped_area find a free area of the right size. - */ - unsigned long rb_subtree_gap; - - /* Second cache line starts here. */ - - struct mm_struct *vm_mm; /* The address space we belong to. */ - pgprot_t vm_page_prot; /* Access permissions of this VMA. */ - unsigned long vm_flags; /* Flags, see mm.h. */ - - /* - * For areas with an address space and backing store, - * linkage into the address_space->i_mmap interval tree. - */ - struct { - struct rb_node rb; - unsigned long rb_subtree_last; - } shared; - - /* - * A file's MAP_PRIVATE vma can be in both i_mmap tree and anon_vma - * list, after a COW of one of the file pages. A MAP_SHARED vma - * can only be in the i_mmap tree. An anonymous MAP_PRIVATE, stack - * or brk vma (with NULL file) can only be in an anon_vma list. - */ - struct list_head anon_vma_chain; /* Serialized by mmap_sem & - * page_table_lock */ - struct anon_vma *anon_vma; /* Serialized by page_table_lock */ - - /* Function pointers to deal with this struct. */ - const struct vm_operations_struct *vm_ops; - - /* Information about our backing store: */ - unsigned long vm_pgoff; /* Offset (within vm_file) in PAGE_SIZE - units */ - struct file * vm_file; /* File we map to (can be NULL). */ - void * vm_private_data; /* was vm_pte (shared mem) */ - -#ifndef CONFIG_MMU - struct vm_region *vm_region; /* NOMMU mapping region */ -#endif -#ifdef CONFIG_NUMA - struct mempolicy *vm_policy; /* NUMA policy for the VMA */ -#endif - struct vm_userfaultfd_ctx vm_userfaultfd_ctx; -}; - -struct core_thread { - struct task_struct *task; - struct core_thread *next; -}; - -struct core_state { - atomic_t nr_threads; - struct core_thread dumper; - struct completion startup; -}; - -enum { - MM_FILEPAGES, /* Resident file mapping pages */ - MM_ANONPAGES, /* Resident anonymous pages */ - MM_SWAPENTS, /* Anonymous swap entries */ - MM_SHMEMPAGES, /* Resident shared memory pages */ - NR_MM_COUNTERS -}; - -#if USE_SPLIT_PTE_PTLOCKS && defined(CONFIG_MMU) -#define SPLIT_RSS_COUNTING -/* per-thread cached information, */ -struct task_rss_stat { - int events; /* for synchronization threshold */ - int count[NR_MM_COUNTERS]; -}; -#endif /* USE_SPLIT_PTE_PTLOCKS */ - -struct mm_rss_stat { - atomic_long_t count[NR_MM_COUNTERS]; -}; - -struct kioctx_table; -struct mm_struct { - struct vm_area_struct *mmap; /* list of VMAs */ - struct rb_root mm_rb; - u32 vmacache_seqnum; /* per-thread vmacache */ -#ifdef CONFIG_MMU - unsigned long (*get_unmapped_area) (struct file *filp, - unsigned long addr, unsigned long len, - unsigned long pgoff, unsigned long flags); -#endif - unsigned long mmap_base; /* base of mmap area */ - unsigned long mmap_legacy_base; /* base of mmap area in bottom-up allocations */ - unsigned long task_size; /* size of task vm space */ - unsigned long highest_vm_end; /* highest vma end address */ - pgd_t * pgd; - atomic_t mm_users; /* How many users with user space? */ - atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */ - atomic_long_t nr_ptes; /* PTE page table pages */ -#if CONFIG_PGTABLE_LEVELS > 2 - atomic_long_t nr_pmds; /* PMD page table pages */ -#endif - int map_count; /* number of VMAs */ - - spinlock_t page_table_lock; /* Protects page tables and some counters */ - struct rw_semaphore mmap_sem; - - struct list_head mmlist; /* List of maybe swapped mm's. These are globally strung - * together off init_mm.mmlist, and are protected - * by mmlist_lock - */ - - - unsigned long hiwater_rss; /* High-watermark of RSS usage */ - unsigned long hiwater_vm; /* High-water virtual memory usage */ - - unsigned long total_vm; /* Total pages mapped */ - unsigned long locked_vm; /* Pages that have PG_mlocked set */ - unsigned long pinned_vm; /* Refcount permanently increased */ - unsigned long data_vm; /* VM_WRITE & ~VM_SHARED & ~VM_STACK */ - unsigned long exec_vm; /* VM_EXEC & ~VM_WRITE & ~VM_STACK */ - unsigned long stack_vm; /* VM_STACK */ - unsigned long def_flags; - unsigned long start_code, end_code, start_data, end_data; - unsigned long start_brk, brk, start_stack; - unsigned long arg_start, arg_end, env_start, env_end; - - unsigned long saved_auxv[AT_VECTOR_SIZE]; /* for /proc/PID/auxv */ - - /* - * Special counters, in some configurations protected by the - * page_table_lock, in other configurations by being atomic. - */ - struct mm_rss_stat rss_stat; - - struct linux_binfmt *binfmt; - - cpumask_var_t cpu_vm_mask_var; - - /* Architecture-specific MM context */ - mm_context_t context; - - unsigned long flags; /* Must use atomic bitops to access the bits */ - - struct core_state *core_state; /* coredumping support */ -#ifdef CONFIG_AIO - spinlock_t ioctx_lock; - struct kioctx_table __rcu *ioctx_table; -#endif -#ifdef CONFIG_MEMCG - /* - * "owner" points to a task that is regarded as the canonical - * user/owner of this mm. All of the following must be true in - * order for it to be changed: - * - * current == mm->owner - * current->mm != mm - * new_owner->mm == mm - * new_owner->alloc_lock is held - */ - struct task_struct __rcu *owner; -#endif - - /* store ref to file /proc//exe symlink points to */ - struct file __rcu *exe_file; -#ifdef CONFIG_MMU_NOTIFIER - struct mmu_notifier_mm *mmu_notifier_mm; -#endif -#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && !USE_SPLIT_PMD_PTLOCKS - pgtable_t pmd_huge_pte; /* protected by page_table_lock */ -#endif -#ifdef CONFIG_CPUMASK_OFFSTACK - struct cpumask cpumask_allocation; -#endif -#ifdef CONFIG_NUMA_BALANCING - /* - * numa_next_scan is the next time that the PTEs will be marked - * pte_numa. NUMA hinting faults will gather statistics and migrate - * pages to new nodes if necessary. - */ - unsigned long numa_next_scan; - - /* Restart point for scanning and setting pte_numa */ - unsigned long numa_scan_offset; - - /* numa_scan_seq prevents two threads setting pte_numa */ - int numa_scan_seq; -#endif -#if defined(CONFIG_NUMA_BALANCING) || defined(CONFIG_COMPACTION) - /* - * An operation with batched TLB flushing is going on. Anything that - * can move process memory needs to flush the TLB when moving a - * PROT_NONE or PROT_NUMA mapped page. - */ - bool tlb_flush_pending; -#endif - struct uprobes_state uprobes_state; -#ifdef CONFIG_X86_INTEL_MPX - /* address of the bounds directory */ - void __user *bd_addr; -#endif -#ifdef CONFIG_HUGETLB_PAGE - atomic_long_t hugetlb_usage; -#endif - struct work_struct async_put_work; -}; - -static inline void mm_init_cpumask(struct mm_struct *mm) -{ -#ifdef CONFIG_CPUMASK_OFFSTACK - mm->cpu_vm_mask_var = &mm->cpumask_allocation; -#endif - cpumask_clear(mm->cpu_vm_mask_var); -} - -/* Future-safe accessor for struct mm_struct's cpu_vm_mask. */ -static inline cpumask_t *mm_cpumask(struct mm_struct *mm) -{ - return mm->cpu_vm_mask_var; -} - -#if defined(CONFIG_NUMA_BALANCING) || defined(CONFIG_COMPACTION) -/* - * Memory barriers to keep this state in sync are graciously provided by - * the page table locks, outside of which no page table modifications happen. - * The barriers below prevent the compiler from re-ordering the instructions - * around the memory barriers that are already present in the code. - */ -static inline bool mm_tlb_flush_pending(struct mm_struct *mm) -{ - barrier(); - return mm->tlb_flush_pending; -} -static inline void set_tlb_flush_pending(struct mm_struct *mm) -{ - mm->tlb_flush_pending = true; - - /* - * Guarantee that the tlb_flush_pending store does not leak into the - * critical section updating the page tables - */ - smp_mb__before_spinlock(); -} -/* Clearing is done after a TLB flush, which also provides a barrier. */ -static inline void clear_tlb_flush_pending(struct mm_struct *mm) -{ - barrier(); - mm->tlb_flush_pending = false; -} -#else -static inline bool mm_tlb_flush_pending(struct mm_struct *mm) -{ - return false; -} -static inline void set_tlb_flush_pending(struct mm_struct *mm) -{ -} -static inline void clear_tlb_flush_pending(struct mm_struct *mm) -{ -} -#endif - -struct vm_fault; - -struct vm_special_mapping { - const char *name; /* The name, e.g. "[vdso]". */ - - /* - * If .fault is not provided, this points to a - * NULL-terminated array of pages that back the special mapping. - * - * This must not be NULL unless .fault is provided. - */ - struct page **pages; - - /* - * If non-NULL, then this is called to resolve page faults - * on the special mapping. If used, .pages is not checked. - */ - int (*fault)(const struct vm_special_mapping *sm, - struct vm_area_struct *vma, - struct vm_fault *vmf); - - int (*mremap)(const struct vm_special_mapping *sm, - struct vm_area_struct *new_vma); -}; - -enum tlb_flush_reason { - TLB_FLUSH_ON_TASK_SWITCH, - TLB_REMOTE_SHOOTDOWN, - TLB_LOCAL_SHOOTDOWN, - TLB_LOCAL_MM_SHOOTDOWN, - TLB_REMOTE_SEND_IPI, - NR_TLB_FLUSH_REASONS, -}; - - /* - * A swap entry has to fit into a "unsigned long", as the entry is hidden - * in the "index" field of the swapper address space. - */ -typedef struct { - unsigned long val; -} swp_entry_t; - -#endif /* _LINUX_MM_TYPES_H */ diff --git a/src/linux/include/linux/mman.h b/src/linux/include/linux/mman.h deleted file mode 100644 index 634c4c5..0000000 --- a/src/linux/include/linux/mman.h +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef _LINUX_MMAN_H -#define _LINUX_MMAN_H - -#include -#include - -#include -#include - -extern int sysctl_overcommit_memory; -extern int sysctl_overcommit_ratio; -extern unsigned long sysctl_overcommit_kbytes; -extern struct percpu_counter vm_committed_as; - -#ifdef CONFIG_SMP -extern s32 vm_committed_as_batch; -#else -#define vm_committed_as_batch 0 -#endif - -unsigned long vm_memory_committed(void); - -static inline void vm_acct_memory(long pages) -{ - __percpu_counter_add(&vm_committed_as, pages, vm_committed_as_batch); -} - -static inline void vm_unacct_memory(long pages) -{ - vm_acct_memory(-pages); -} - -/* - * Allow architectures to handle additional protection bits - */ - -#ifndef arch_calc_vm_prot_bits -#define arch_calc_vm_prot_bits(prot, pkey) 0 -#endif - -#ifndef arch_vm_get_page_prot -#define arch_vm_get_page_prot(vm_flags) __pgprot(0) -#endif - -#ifndef arch_validate_prot -/* - * This is called from mprotect(). PROT_GROWSDOWN and PROT_GROWSUP have - * already been masked out. - * - * Returns true if the prot flags are valid - */ -static inline bool arch_validate_prot(unsigned long prot) -{ - return (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC | PROT_SEM)) == 0; -} -#define arch_validate_prot arch_validate_prot -#endif - -/* - * Optimisation macro. It is equivalent to: - * (x & bit1) ? bit2 : 0 - * but this version is faster. - * ("bit1" and "bit2" must be single bits) - */ -#define _calc_vm_trans(x, bit1, bit2) \ - ((bit1) <= (bit2) ? ((x) & (bit1)) * ((bit2) / (bit1)) \ - : ((x) & (bit1)) / ((bit1) / (bit2))) - -/* - * Combine the mmap "prot" argument into "vm_flags" used internally. - */ -static inline unsigned long -calc_vm_prot_bits(unsigned long prot, unsigned long pkey) -{ - return _calc_vm_trans(prot, PROT_READ, VM_READ ) | - _calc_vm_trans(prot, PROT_WRITE, VM_WRITE) | - _calc_vm_trans(prot, PROT_EXEC, VM_EXEC) | - arch_calc_vm_prot_bits(prot, pkey); -} - -/* - * Combine the mmap "flags" argument into "vm_flags" used internally. - */ -static inline unsigned long -calc_vm_flag_bits(unsigned long flags) -{ - return _calc_vm_trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN ) | - _calc_vm_trans(flags, MAP_DENYWRITE, VM_DENYWRITE ) | - _calc_vm_trans(flags, MAP_LOCKED, VM_LOCKED ); -} - -unsigned long vm_commit_limit(void); -#endif /* _LINUX_MMAN_H */ diff --git a/src/linux/include/linux/mmdebug.h b/src/linux/include/linux/mmdebug.h deleted file mode 100644 index 451a811..0000000 --- a/src/linux/include/linux/mmdebug.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef LINUX_MM_DEBUG_H -#define LINUX_MM_DEBUG_H 1 - -#include -#include - -struct page; -struct vm_area_struct; -struct mm_struct; - -extern void dump_page(struct page *page, const char *reason); -extern void __dump_page(struct page *page, const char *reason); -void dump_vma(const struct vm_area_struct *vma); -void dump_mm(const struct mm_struct *mm); - -#ifdef CONFIG_DEBUG_VM -#define VM_BUG_ON(cond) BUG_ON(cond) -#define VM_BUG_ON_PAGE(cond, page) \ - do { \ - if (unlikely(cond)) { \ - dump_page(page, "VM_BUG_ON_PAGE(" __stringify(cond)")");\ - BUG(); \ - } \ - } while (0) -#define VM_BUG_ON_VMA(cond, vma) \ - do { \ - if (unlikely(cond)) { \ - dump_vma(vma); \ - BUG(); \ - } \ - } while (0) -#define VM_BUG_ON_MM(cond, mm) \ - do { \ - if (unlikely(cond)) { \ - dump_mm(mm); \ - BUG(); \ - } \ - } while (0) -#define VM_WARN_ON(cond) WARN_ON(cond) -#define VM_WARN_ON_ONCE(cond) WARN_ON_ONCE(cond) -#define VM_WARN_ONCE(cond, format...) WARN_ONCE(cond, format) -#define VM_WARN(cond, format...) WARN(cond, format) -#else -#define VM_BUG_ON(cond) BUILD_BUG_ON_INVALID(cond) -#define VM_BUG_ON_PAGE(cond, page) VM_BUG_ON(cond) -#define VM_BUG_ON_VMA(cond, vma) VM_BUG_ON(cond) -#define VM_BUG_ON_MM(cond, mm) VM_BUG_ON(cond) -#define VM_WARN_ON(cond) BUILD_BUG_ON_INVALID(cond) -#define VM_WARN_ON_ONCE(cond) BUILD_BUG_ON_INVALID(cond) -#define VM_WARN_ONCE(cond, format...) BUILD_BUG_ON_INVALID(cond) -#define VM_WARN(cond, format...) BUILD_BUG_ON_INVALID(cond) -#endif - -#ifdef CONFIG_DEBUG_VIRTUAL -#define VIRTUAL_BUG_ON(cond) BUG_ON(cond) -#else -#define VIRTUAL_BUG_ON(cond) do { } while (0) -#endif - -#ifdef CONFIG_DEBUG_VM_PGFLAGS -#define VM_BUG_ON_PGFLAGS(cond, page) VM_BUG_ON_PAGE(cond, page) -#else -#define VM_BUG_ON_PGFLAGS(cond, page) BUILD_BUG_ON_INVALID(cond) -#endif - -#endif diff --git a/src/linux/include/linux/mmu_context.h b/src/linux/include/linux/mmu_context.h deleted file mode 100644 index a444178..0000000 --- a/src/linux/include/linux/mmu_context.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _LINUX_MMU_CONTEXT_H -#define _LINUX_MMU_CONTEXT_H - -#include - -struct mm_struct; - -void use_mm(struct mm_struct *mm); -void unuse_mm(struct mm_struct *mm); - -/* Architectures that care about IRQ state in switch_mm can override this. */ -#ifndef switch_mm_irqs_off -# define switch_mm_irqs_off switch_mm -#endif - -#endif diff --git a/src/linux/include/linux/mmu_notifier.h b/src/linux/include/linux/mmu_notifier.h deleted file mode 100644 index a1a210d..0000000 --- a/src/linux/include/linux/mmu_notifier.h +++ /dev/null @@ -1,483 +0,0 @@ -#ifndef _LINUX_MMU_NOTIFIER_H -#define _LINUX_MMU_NOTIFIER_H - -#include -#include -#include -#include - -struct mmu_notifier; -struct mmu_notifier_ops; - -#ifdef CONFIG_MMU_NOTIFIER - -/* - * The mmu notifier_mm structure is allocated and installed in - * mm->mmu_notifier_mm inside the mm_take_all_locks() protected - * critical section and it's released only when mm_count reaches zero - * in mmdrop(). - */ -struct mmu_notifier_mm { - /* all mmu notifiers registerd in this mm are queued in this list */ - struct hlist_head list; - /* to serialize the list modifications and hlist_unhashed */ - spinlock_t lock; -}; - -struct mmu_notifier_ops { - /* - * Called either by mmu_notifier_unregister or when the mm is - * being destroyed by exit_mmap, always before all pages are - * freed. This can run concurrently with other mmu notifier - * methods (the ones invoked outside the mm context) and it - * should tear down all secondary mmu mappings and freeze the - * secondary mmu. If this method isn't implemented you've to - * be sure that nothing could possibly write to the pages - * through the secondary mmu by the time the last thread with - * tsk->mm == mm exits. - * - * As side note: the pages freed after ->release returns could - * be immediately reallocated by the gart at an alias physical - * address with a different cache model, so if ->release isn't - * implemented because all _software_ driven memory accesses - * through the secondary mmu are terminated by the time the - * last thread of this mm quits, you've also to be sure that - * speculative _hardware_ operations can't allocate dirty - * cachelines in the cpu that could not be snooped and made - * coherent with the other read and write operations happening - * through the gart alias address, so leading to memory - * corruption. - */ - void (*release)(struct mmu_notifier *mn, - struct mm_struct *mm); - - /* - * clear_flush_young is called after the VM is - * test-and-clearing the young/accessed bitflag in the - * pte. This way the VM will provide proper aging to the - * accesses to the page through the secondary MMUs and not - * only to the ones through the Linux pte. - * Start-end is necessary in case the secondary MMU is mapping the page - * at a smaller granularity than the primary MMU. - */ - int (*clear_flush_young)(struct mmu_notifier *mn, - struct mm_struct *mm, - unsigned long start, - unsigned long end); - - /* - * clear_young is a lightweight version of clear_flush_young. Like the - * latter, it is supposed to test-and-clear the young/accessed bitflag - * in the secondary pte, but it may omit flushing the secondary tlb. - */ - int (*clear_young)(struct mmu_notifier *mn, - struct mm_struct *mm, - unsigned long start, - unsigned long end); - - /* - * test_young is called to check the young/accessed bitflag in - * the secondary pte. This is used to know if the page is - * frequently used without actually clearing the flag or tearing - * down the secondary mapping on the page. - */ - int (*test_young)(struct mmu_notifier *mn, - struct mm_struct *mm, - unsigned long address); - - /* - * change_pte is called in cases that pte mapping to page is changed: - * for example, when ksm remaps pte to point to a new shared page. - */ - void (*change_pte)(struct mmu_notifier *mn, - struct mm_struct *mm, - unsigned long address, - pte_t pte); - - /* - * Before this is invoked any secondary MMU is still ok to - * read/write to the page previously pointed to by the Linux - * pte because the page hasn't been freed yet and it won't be - * freed until this returns. If required set_page_dirty has to - * be called internally to this method. - */ - void (*invalidate_page)(struct mmu_notifier *mn, - struct mm_struct *mm, - unsigned long address); - - /* - * invalidate_range_start() and invalidate_range_end() must be - * paired and are called only when the mmap_sem and/or the - * locks protecting the reverse maps are held. If the subsystem - * can't guarantee that no additional references are taken to - * the pages in the range, it has to implement the - * invalidate_range() notifier to remove any references taken - * after invalidate_range_start(). - * - * Invalidation of multiple concurrent ranges may be - * optionally permitted by the driver. Either way the - * establishment of sptes is forbidden in the range passed to - * invalidate_range_begin/end for the whole duration of the - * invalidate_range_begin/end critical section. - * - * invalidate_range_start() is called when all pages in the - * range are still mapped and have at least a refcount of one. - * - * invalidate_range_end() is called when all pages in the - * range have been unmapped and the pages have been freed by - * the VM. - * - * The VM will remove the page table entries and potentially - * the page between invalidate_range_start() and - * invalidate_range_end(). If the page must not be freed - * because of pending I/O or other circumstances then the - * invalidate_range_start() callback (or the initial mapping - * by the driver) must make sure that the refcount is kept - * elevated. - * - * If the driver increases the refcount when the pages are - * initially mapped into an address space then either - * invalidate_range_start() or invalidate_range_end() may - * decrease the refcount. If the refcount is decreased on - * invalidate_range_start() then the VM can free pages as page - * table entries are removed. If the refcount is only - * droppped on invalidate_range_end() then the driver itself - * will drop the last refcount but it must take care to flush - * any secondary tlb before doing the final free on the - * page. Pages will no longer be referenced by the linux - * address space but may still be referenced by sptes until - * the last refcount is dropped. - */ - void (*invalidate_range_start)(struct mmu_notifier *mn, - struct mm_struct *mm, - unsigned long start, unsigned long end); - void (*invalidate_range_end)(struct mmu_notifier *mn, - struct mm_struct *mm, - unsigned long start, unsigned long end); - - /* - * invalidate_range() is either called between - * invalidate_range_start() and invalidate_range_end() when the - * VM has to free pages that where unmapped, but before the - * pages are actually freed, or outside of _start()/_end() when - * a (remote) TLB is necessary. - * - * If invalidate_range() is used to manage a non-CPU TLB with - * shared page-tables, it not necessary to implement the - * invalidate_range_start()/end() notifiers, as - * invalidate_range() alread catches the points in time when an - * external TLB range needs to be flushed. - * - * The invalidate_range() function is called under the ptl - * spin-lock and not allowed to sleep. - * - * Note that this function might be called with just a sub-range - * of what was passed to invalidate_range_start()/end(), if - * called between those functions. - */ - void (*invalidate_range)(struct mmu_notifier *mn, struct mm_struct *mm, - unsigned long start, unsigned long end); -}; - -/* - * The notifier chains are protected by mmap_sem and/or the reverse map - * semaphores. Notifier chains are only changed when all reverse maps and - * the mmap_sem locks are taken. - * - * Therefore notifier chains can only be traversed when either - * - * 1. mmap_sem is held. - * 2. One of the reverse map locks is held (i_mmap_rwsem or anon_vma->rwsem). - * 3. No other concurrent thread can access the list (release) - */ -struct mmu_notifier { - struct hlist_node hlist; - const struct mmu_notifier_ops *ops; -}; - -static inline int mm_has_notifiers(struct mm_struct *mm) -{ - return unlikely(mm->mmu_notifier_mm); -} - -extern int mmu_notifier_register(struct mmu_notifier *mn, - struct mm_struct *mm); -extern int __mmu_notifier_register(struct mmu_notifier *mn, - struct mm_struct *mm); -extern void mmu_notifier_unregister(struct mmu_notifier *mn, - struct mm_struct *mm); -extern void mmu_notifier_unregister_no_release(struct mmu_notifier *mn, - struct mm_struct *mm); -extern void __mmu_notifier_mm_destroy(struct mm_struct *mm); -extern void __mmu_notifier_release(struct mm_struct *mm); -extern int __mmu_notifier_clear_flush_young(struct mm_struct *mm, - unsigned long start, - unsigned long end); -extern int __mmu_notifier_clear_young(struct mm_struct *mm, - unsigned long start, - unsigned long end); -extern int __mmu_notifier_test_young(struct mm_struct *mm, - unsigned long address); -extern void __mmu_notifier_change_pte(struct mm_struct *mm, - unsigned long address, pte_t pte); -extern void __mmu_notifier_invalidate_page(struct mm_struct *mm, - unsigned long address); -extern void __mmu_notifier_invalidate_range_start(struct mm_struct *mm, - unsigned long start, unsigned long end); -extern void __mmu_notifier_invalidate_range_end(struct mm_struct *mm, - unsigned long start, unsigned long end); -extern void __mmu_notifier_invalidate_range(struct mm_struct *mm, - unsigned long start, unsigned long end); - -static inline void mmu_notifier_release(struct mm_struct *mm) -{ - if (mm_has_notifiers(mm)) - __mmu_notifier_release(mm); -} - -static inline int mmu_notifier_clear_flush_young(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - if (mm_has_notifiers(mm)) - return __mmu_notifier_clear_flush_young(mm, start, end); - return 0; -} - -static inline int mmu_notifier_clear_young(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - if (mm_has_notifiers(mm)) - return __mmu_notifier_clear_young(mm, start, end); - return 0; -} - -static inline int mmu_notifier_test_young(struct mm_struct *mm, - unsigned long address) -{ - if (mm_has_notifiers(mm)) - return __mmu_notifier_test_young(mm, address); - return 0; -} - -static inline void mmu_notifier_change_pte(struct mm_struct *mm, - unsigned long address, pte_t pte) -{ - if (mm_has_notifiers(mm)) - __mmu_notifier_change_pte(mm, address, pte); -} - -static inline void mmu_notifier_invalidate_page(struct mm_struct *mm, - unsigned long address) -{ - if (mm_has_notifiers(mm)) - __mmu_notifier_invalidate_page(mm, address); -} - -static inline void mmu_notifier_invalidate_range_start(struct mm_struct *mm, - unsigned long start, unsigned long end) -{ - if (mm_has_notifiers(mm)) - __mmu_notifier_invalidate_range_start(mm, start, end); -} - -static inline void mmu_notifier_invalidate_range_end(struct mm_struct *mm, - unsigned long start, unsigned long end) -{ - if (mm_has_notifiers(mm)) - __mmu_notifier_invalidate_range_end(mm, start, end); -} - -static inline void mmu_notifier_invalidate_range(struct mm_struct *mm, - unsigned long start, unsigned long end) -{ - if (mm_has_notifiers(mm)) - __mmu_notifier_invalidate_range(mm, start, end); -} - -static inline void mmu_notifier_mm_init(struct mm_struct *mm) -{ - mm->mmu_notifier_mm = NULL; -} - -static inline void mmu_notifier_mm_destroy(struct mm_struct *mm) -{ - if (mm_has_notifiers(mm)) - __mmu_notifier_mm_destroy(mm); -} - -#define ptep_clear_flush_young_notify(__vma, __address, __ptep) \ -({ \ - int __young; \ - struct vm_area_struct *___vma = __vma; \ - unsigned long ___address = __address; \ - __young = ptep_clear_flush_young(___vma, ___address, __ptep); \ - __young |= mmu_notifier_clear_flush_young(___vma->vm_mm, \ - ___address, \ - ___address + \ - PAGE_SIZE); \ - __young; \ -}) - -#define pmdp_clear_flush_young_notify(__vma, __address, __pmdp) \ -({ \ - int __young; \ - struct vm_area_struct *___vma = __vma; \ - unsigned long ___address = __address; \ - __young = pmdp_clear_flush_young(___vma, ___address, __pmdp); \ - __young |= mmu_notifier_clear_flush_young(___vma->vm_mm, \ - ___address, \ - ___address + \ - PMD_SIZE); \ - __young; \ -}) - -#define ptep_clear_young_notify(__vma, __address, __ptep) \ -({ \ - int __young; \ - struct vm_area_struct *___vma = __vma; \ - unsigned long ___address = __address; \ - __young = ptep_test_and_clear_young(___vma, ___address, __ptep);\ - __young |= mmu_notifier_clear_young(___vma->vm_mm, ___address, \ - ___address + PAGE_SIZE); \ - __young; \ -}) - -#define pmdp_clear_young_notify(__vma, __address, __pmdp) \ -({ \ - int __young; \ - struct vm_area_struct *___vma = __vma; \ - unsigned long ___address = __address; \ - __young = pmdp_test_and_clear_young(___vma, ___address, __pmdp);\ - __young |= mmu_notifier_clear_young(___vma->vm_mm, ___address, \ - ___address + PMD_SIZE); \ - __young; \ -}) - -#define ptep_clear_flush_notify(__vma, __address, __ptep) \ -({ \ - unsigned long ___addr = __address & PAGE_MASK; \ - struct mm_struct *___mm = (__vma)->vm_mm; \ - pte_t ___pte; \ - \ - ___pte = ptep_clear_flush(__vma, __address, __ptep); \ - mmu_notifier_invalidate_range(___mm, ___addr, \ - ___addr + PAGE_SIZE); \ - \ - ___pte; \ -}) - -#define pmdp_huge_clear_flush_notify(__vma, __haddr, __pmd) \ -({ \ - unsigned long ___haddr = __haddr & HPAGE_PMD_MASK; \ - struct mm_struct *___mm = (__vma)->vm_mm; \ - pmd_t ___pmd; \ - \ - ___pmd = pmdp_huge_clear_flush(__vma, __haddr, __pmd); \ - mmu_notifier_invalidate_range(___mm, ___haddr, \ - ___haddr + HPAGE_PMD_SIZE); \ - \ - ___pmd; \ -}) - -#define pmdp_huge_get_and_clear_notify(__mm, __haddr, __pmd) \ -({ \ - unsigned long ___haddr = __haddr & HPAGE_PMD_MASK; \ - pmd_t ___pmd; \ - \ - ___pmd = pmdp_huge_get_and_clear(__mm, __haddr, __pmd); \ - mmu_notifier_invalidate_range(__mm, ___haddr, \ - ___haddr + HPAGE_PMD_SIZE); \ - \ - ___pmd; \ -}) - -/* - * set_pte_at_notify() sets the pte _after_ running the notifier. - * This is safe to start by updating the secondary MMUs, because the primary MMU - * pte invalidate must have already happened with a ptep_clear_flush() before - * set_pte_at_notify() has been invoked. Updating the secondary MMUs first is - * required when we change both the protection of the mapping from read-only to - * read-write and the pfn (like during copy on write page faults). Otherwise the - * old page would remain mapped readonly in the secondary MMUs after the new - * page is already writable by some CPU through the primary MMU. - */ -#define set_pte_at_notify(__mm, __address, __ptep, __pte) \ -({ \ - struct mm_struct *___mm = __mm; \ - unsigned long ___address = __address; \ - pte_t ___pte = __pte; \ - \ - mmu_notifier_change_pte(___mm, ___address, ___pte); \ - set_pte_at(___mm, ___address, __ptep, ___pte); \ -}) - -extern void mmu_notifier_call_srcu(struct rcu_head *rcu, - void (*func)(struct rcu_head *rcu)); -extern void mmu_notifier_synchronize(void); - -#else /* CONFIG_MMU_NOTIFIER */ - -static inline void mmu_notifier_release(struct mm_struct *mm) -{ -} - -static inline int mmu_notifier_clear_flush_young(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - return 0; -} - -static inline int mmu_notifier_test_young(struct mm_struct *mm, - unsigned long address) -{ - return 0; -} - -static inline void mmu_notifier_change_pte(struct mm_struct *mm, - unsigned long address, pte_t pte) -{ -} - -static inline void mmu_notifier_invalidate_page(struct mm_struct *mm, - unsigned long address) -{ -} - -static inline void mmu_notifier_invalidate_range_start(struct mm_struct *mm, - unsigned long start, unsigned long end) -{ -} - -static inline void mmu_notifier_invalidate_range_end(struct mm_struct *mm, - unsigned long start, unsigned long end) -{ -} - -static inline void mmu_notifier_invalidate_range(struct mm_struct *mm, - unsigned long start, unsigned long end) -{ -} - -static inline void mmu_notifier_mm_init(struct mm_struct *mm) -{ -} - -static inline void mmu_notifier_mm_destroy(struct mm_struct *mm) -{ -} - -#define ptep_clear_flush_young_notify ptep_clear_flush_young -#define pmdp_clear_flush_young_notify pmdp_clear_flush_young -#define ptep_clear_young_notify ptep_test_and_clear_young -#define pmdp_clear_young_notify pmdp_test_and_clear_young -#define ptep_clear_flush_notify ptep_clear_flush -#define pmdp_huge_clear_flush_notify pmdp_huge_clear_flush -#define pmdp_huge_get_and_clear_notify pmdp_huge_get_and_clear -#define set_pte_at_notify set_pte_at - -#endif /* CONFIG_MMU_NOTIFIER */ - -#endif /* _LINUX_MMU_NOTIFIER_H */ diff --git a/src/linux/include/linux/mmzone.h b/src/linux/include/linux/mmzone.h deleted file mode 100644 index 0f088f3..0000000 --- a/src/linux/include/linux/mmzone.h +++ /dev/null @@ -1,1268 +0,0 @@ -#ifndef _LINUX_MMZONE_H -#define _LINUX_MMZONE_H - -#ifndef __ASSEMBLY__ -#ifndef __GENERATING_BOUNDS_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Free memory management - zoned buddy allocator. */ -#ifndef CONFIG_FORCE_MAX_ZONEORDER -#define MAX_ORDER 11 -#else -#define MAX_ORDER CONFIG_FORCE_MAX_ZONEORDER -#endif -#define MAX_ORDER_NR_PAGES (1 << (MAX_ORDER - 1)) - -/* - * PAGE_ALLOC_COSTLY_ORDER is the order at which allocations are deemed - * costly to service. That is between allocation orders which should - * coalesce naturally under reasonable reclaim pressure and those which - * will not. - */ -#define PAGE_ALLOC_COSTLY_ORDER 3 - -enum { - MIGRATE_UNMOVABLE, - MIGRATE_MOVABLE, - MIGRATE_RECLAIMABLE, - MIGRATE_PCPTYPES, /* the number of types on the pcp lists */ - MIGRATE_HIGHATOMIC = MIGRATE_PCPTYPES, -#ifdef CONFIG_CMA - /* - * MIGRATE_CMA migration type is designed to mimic the way - * ZONE_MOVABLE works. Only movable pages can be allocated - * from MIGRATE_CMA pageblocks and page allocator never - * implicitly change migration type of MIGRATE_CMA pageblock. - * - * The way to use it is to change migratetype of a range of - * pageblocks to MIGRATE_CMA which can be done by - * __free_pageblock_cma() function. What is important though - * is that a range of pageblocks must be aligned to - * MAX_ORDER_NR_PAGES should biggest page be bigger then - * a single pageblock. - */ - MIGRATE_CMA, -#endif -#ifdef CONFIG_MEMORY_ISOLATION - MIGRATE_ISOLATE, /* can't allocate from here */ -#endif - MIGRATE_TYPES -}; - -/* In mm/page_alloc.c; keep in sync also with show_migration_types() there */ -extern char * const migratetype_names[MIGRATE_TYPES]; - -#ifdef CONFIG_CMA -# define is_migrate_cma(migratetype) unlikely((migratetype) == MIGRATE_CMA) -# define is_migrate_cma_page(_page) (get_pageblock_migratetype(_page) == MIGRATE_CMA) -#else -# define is_migrate_cma(migratetype) false -# define is_migrate_cma_page(_page) false -#endif - -#define for_each_migratetype_order(order, type) \ - for (order = 0; order < MAX_ORDER; order++) \ - for (type = 0; type < MIGRATE_TYPES; type++) - -extern int page_group_by_mobility_disabled; - -#define NR_MIGRATETYPE_BITS (PB_migrate_end - PB_migrate + 1) -#define MIGRATETYPE_MASK ((1UL << NR_MIGRATETYPE_BITS) - 1) - -#define get_pageblock_migratetype(page) \ - get_pfnblock_flags_mask(page, page_to_pfn(page), \ - PB_migrate_end, MIGRATETYPE_MASK) - -struct free_area { - struct list_head free_list[MIGRATE_TYPES]; - unsigned long nr_free; -}; - -struct pglist_data; - -/* - * zone->lock and the zone lru_lock are two of the hottest locks in the kernel. - * So add a wild amount of padding here to ensure that they fall into separate - * cachelines. There are very few zone structures in the machine, so space - * consumption is not a concern here. - */ -#if defined(CONFIG_SMP) -struct zone_padding { - char x[0]; -} ____cacheline_internodealigned_in_smp; -#define ZONE_PADDING(name) struct zone_padding name; -#else -#define ZONE_PADDING(name) -#endif - -enum zone_stat_item { - /* First 128 byte cacheline (assuming 64 bit words) */ - NR_FREE_PAGES, - NR_ZONE_LRU_BASE, /* Used only for compaction and reclaim retry */ - NR_ZONE_INACTIVE_ANON = NR_ZONE_LRU_BASE, - NR_ZONE_ACTIVE_ANON, - NR_ZONE_INACTIVE_FILE, - NR_ZONE_ACTIVE_FILE, - NR_ZONE_UNEVICTABLE, - NR_ZONE_WRITE_PENDING, /* Count of dirty, writeback and unstable pages */ - NR_MLOCK, /* mlock()ed pages found and moved off LRU */ - NR_SLAB_RECLAIMABLE, - NR_SLAB_UNRECLAIMABLE, - NR_PAGETABLE, /* used for pagetables */ - NR_KERNEL_STACK_KB, /* measured in KiB */ - /* Second 128 byte cacheline */ - NR_BOUNCE, -#if IS_ENABLED(CONFIG_ZSMALLOC) - NR_ZSPAGES, /* allocated in zsmalloc */ -#endif -#ifdef CONFIG_NUMA - NUMA_HIT, /* allocated in intended node */ - NUMA_MISS, /* allocated in non intended node */ - NUMA_FOREIGN, /* was intended here, hit elsewhere */ - NUMA_INTERLEAVE_HIT, /* interleaver preferred this zone */ - NUMA_LOCAL, /* allocation from local node */ - NUMA_OTHER, /* allocation from other node */ -#endif - NR_FREE_CMA_PAGES, - NR_VM_ZONE_STAT_ITEMS }; - -enum node_stat_item { - NR_LRU_BASE, - NR_INACTIVE_ANON = NR_LRU_BASE, /* must match order of LRU_[IN]ACTIVE */ - NR_ACTIVE_ANON, /* " " " " " */ - NR_INACTIVE_FILE, /* " " " " " */ - NR_ACTIVE_FILE, /* " " " " " */ - NR_UNEVICTABLE, /* " " " " " */ - NR_ISOLATED_ANON, /* Temporary isolated pages from anon lru */ - NR_ISOLATED_FILE, /* Temporary isolated pages from file lru */ - NR_PAGES_SCANNED, /* pages scanned since last reclaim */ - WORKINGSET_REFAULT, - WORKINGSET_ACTIVATE, - WORKINGSET_NODERECLAIM, - NR_ANON_MAPPED, /* Mapped anonymous pages */ - NR_FILE_MAPPED, /* pagecache pages mapped into pagetables. - only modified from process context */ - NR_FILE_PAGES, - NR_FILE_DIRTY, - NR_WRITEBACK, - NR_WRITEBACK_TEMP, /* Writeback using temporary buffers */ - NR_SHMEM, /* shmem pages (included tmpfs/GEM pages) */ - NR_SHMEM_THPS, - NR_SHMEM_PMDMAPPED, - NR_ANON_THPS, - NR_UNSTABLE_NFS, /* NFS unstable pages */ - NR_VMSCAN_WRITE, - NR_VMSCAN_IMMEDIATE, /* Prioritise for reclaim when writeback ends */ - NR_DIRTIED, /* page dirtyings since bootup */ - NR_WRITTEN, /* page writings since bootup */ - NR_VM_NODE_STAT_ITEMS -}; - -/* - * We do arithmetic on the LRU lists in various places in the code, - * so it is important to keep the active lists LRU_ACTIVE higher in - * the array than the corresponding inactive lists, and to keep - * the *_FILE lists LRU_FILE higher than the corresponding _ANON lists. - * - * This has to be kept in sync with the statistics in zone_stat_item - * above and the descriptions in vmstat_text in mm/vmstat.c - */ -#define LRU_BASE 0 -#define LRU_ACTIVE 1 -#define LRU_FILE 2 - -enum lru_list { - LRU_INACTIVE_ANON = LRU_BASE, - LRU_ACTIVE_ANON = LRU_BASE + LRU_ACTIVE, - LRU_INACTIVE_FILE = LRU_BASE + LRU_FILE, - LRU_ACTIVE_FILE = LRU_BASE + LRU_FILE + LRU_ACTIVE, - LRU_UNEVICTABLE, - NR_LRU_LISTS -}; - -#define for_each_lru(lru) for (lru = 0; lru < NR_LRU_LISTS; lru++) - -#define for_each_evictable_lru(lru) for (lru = 0; lru <= LRU_ACTIVE_FILE; lru++) - -static inline int is_file_lru(enum lru_list lru) -{ - return (lru == LRU_INACTIVE_FILE || lru == LRU_ACTIVE_FILE); -} - -static inline int is_active_lru(enum lru_list lru) -{ - return (lru == LRU_ACTIVE_ANON || lru == LRU_ACTIVE_FILE); -} - -struct zone_reclaim_stat { - /* - * The pageout code in vmscan.c keeps track of how many of the - * mem/swap backed and file backed pages are referenced. - * The higher the rotated/scanned ratio, the more valuable - * that cache is. - * - * The anon LRU stats live in [0], file LRU stats in [1] - */ - unsigned long recent_rotated[2]; - unsigned long recent_scanned[2]; -}; - -struct lruvec { - struct list_head lists[NR_LRU_LISTS]; - struct zone_reclaim_stat reclaim_stat; - /* Evictions & activations on the inactive file list */ - atomic_long_t inactive_age; -#ifdef CONFIG_MEMCG - struct pglist_data *pgdat; -#endif -}; - -/* Mask used at gathering information at once (see memcontrol.c) */ -#define LRU_ALL_FILE (BIT(LRU_INACTIVE_FILE) | BIT(LRU_ACTIVE_FILE)) -#define LRU_ALL_ANON (BIT(LRU_INACTIVE_ANON) | BIT(LRU_ACTIVE_ANON)) -#define LRU_ALL ((1 << NR_LRU_LISTS) - 1) - -/* Isolate clean file */ -#define ISOLATE_CLEAN ((__force isolate_mode_t)0x1) -/* Isolate unmapped file */ -#define ISOLATE_UNMAPPED ((__force isolate_mode_t)0x2) -/* Isolate for asynchronous migration */ -#define ISOLATE_ASYNC_MIGRATE ((__force isolate_mode_t)0x4) -/* Isolate unevictable pages */ -#define ISOLATE_UNEVICTABLE ((__force isolate_mode_t)0x8) - -/* LRU Isolation modes. */ -typedef unsigned __bitwise__ isolate_mode_t; - -enum zone_watermarks { - WMARK_MIN, - WMARK_LOW, - WMARK_HIGH, - NR_WMARK -}; - -#define min_wmark_pages(z) (z->watermark[WMARK_MIN]) -#define low_wmark_pages(z) (z->watermark[WMARK_LOW]) -#define high_wmark_pages(z) (z->watermark[WMARK_HIGH]) - -struct per_cpu_pages { - int count; /* number of pages in the list */ - int high; /* high watermark, emptying needed */ - int batch; /* chunk size for buddy add/remove */ - - /* Lists of pages, one per migrate type stored on the pcp-lists */ - struct list_head lists[MIGRATE_PCPTYPES]; -}; - -struct per_cpu_pageset { - struct per_cpu_pages pcp; -#ifdef CONFIG_NUMA - s8 expire; -#endif -#ifdef CONFIG_SMP - s8 stat_threshold; - s8 vm_stat_diff[NR_VM_ZONE_STAT_ITEMS]; -#endif -}; - -struct per_cpu_nodestat { - s8 stat_threshold; - s8 vm_node_stat_diff[NR_VM_NODE_STAT_ITEMS]; -}; - -#endif /* !__GENERATING_BOUNDS.H */ - -enum zone_type { -#ifdef CONFIG_ZONE_DMA - /* - * ZONE_DMA is used when there are devices that are not able - * to do DMA to all of addressable memory (ZONE_NORMAL). Then we - * carve out the portion of memory that is needed for these devices. - * The range is arch specific. - * - * Some examples - * - * Architecture Limit - * --------------------------- - * parisc, ia64, sparc <4G - * s390 <2G - * arm Various - * alpha Unlimited or 0-16MB. - * - * i386, x86_64 and multiple other arches - * <16M. - */ - ZONE_DMA, -#endif -#ifdef CONFIG_ZONE_DMA32 - /* - * x86_64 needs two ZONE_DMAs because it supports devices that are - * only able to do DMA to the lower 16M but also 32 bit devices that - * can only do DMA areas below 4G. - */ - ZONE_DMA32, -#endif - /* - * Normal addressable memory is in ZONE_NORMAL. DMA operations can be - * performed on pages in ZONE_NORMAL if the DMA devices support - * transfers to all addressable memory. - */ - ZONE_NORMAL, -#ifdef CONFIG_HIGHMEM - /* - * A memory area that is only addressable by the kernel through - * mapping portions into its own address space. This is for example - * used by i386 to allow the kernel to address the memory beyond - * 900MB. The kernel will set up special mappings (page - * table entries on i386) for each page that the kernel needs to - * access. - */ - ZONE_HIGHMEM, -#endif - ZONE_MOVABLE, -#ifdef CONFIG_ZONE_DEVICE - ZONE_DEVICE, -#endif - __MAX_NR_ZONES - -}; - -#ifndef __GENERATING_BOUNDS_H - -struct zone { - /* Read-mostly fields */ - - /* zone watermarks, access with *_wmark_pages(zone) macros */ - unsigned long watermark[NR_WMARK]; - - unsigned long nr_reserved_highatomic; - - /* - * We don't know if the memory that we're going to allocate will be - * freeable or/and it will be released eventually, so to avoid totally - * wasting several GB of ram we must reserve some of the lower zone - * memory (otherwise we risk to run OOM on the lower zones despite - * there being tons of freeable ram on the higher zones). This array is - * recalculated at runtime if the sysctl_lowmem_reserve_ratio sysctl - * changes. - */ - long lowmem_reserve[MAX_NR_ZONES]; - -#ifdef CONFIG_NUMA - int node; -#endif - struct pglist_data *zone_pgdat; - struct per_cpu_pageset __percpu *pageset; - -#ifndef CONFIG_SPARSEMEM - /* - * Flags for a pageblock_nr_pages block. See pageblock-flags.h. - * In SPARSEMEM, this map is stored in struct mem_section - */ - unsigned long *pageblock_flags; -#endif /* CONFIG_SPARSEMEM */ - - /* zone_start_pfn == zone_start_paddr >> PAGE_SHIFT */ - unsigned long zone_start_pfn; - - /* - * spanned_pages is the total pages spanned by the zone, including - * holes, which is calculated as: - * spanned_pages = zone_end_pfn - zone_start_pfn; - * - * present_pages is physical pages existing within the zone, which - * is calculated as: - * present_pages = spanned_pages - absent_pages(pages in holes); - * - * managed_pages is present pages managed by the buddy system, which - * is calculated as (reserved_pages includes pages allocated by the - * bootmem allocator): - * managed_pages = present_pages - reserved_pages; - * - * So present_pages may be used by memory hotplug or memory power - * management logic to figure out unmanaged pages by checking - * (present_pages - managed_pages). And managed_pages should be used - * by page allocator and vm scanner to calculate all kinds of watermarks - * and thresholds. - * - * Locking rules: - * - * zone_start_pfn and spanned_pages are protected by span_seqlock. - * It is a seqlock because it has to be read outside of zone->lock, - * and it is done in the main allocator path. But, it is written - * quite infrequently. - * - * The span_seq lock is declared along with zone->lock because it is - * frequently read in proximity to zone->lock. It's good to - * give them a chance of being in the same cacheline. - * - * Write access to present_pages at runtime should be protected by - * mem_hotplug_begin/end(). Any reader who can't tolerant drift of - * present_pages should get_online_mems() to get a stable value. - * - * Read access to managed_pages should be safe because it's unsigned - * long. Write access to zone->managed_pages and totalram_pages are - * protected by managed_page_count_lock at runtime. Idealy only - * adjust_managed_page_count() should be used instead of directly - * touching zone->managed_pages and totalram_pages. - */ - unsigned long managed_pages; - unsigned long spanned_pages; - unsigned long present_pages; - - const char *name; - -#ifdef CONFIG_MEMORY_ISOLATION - /* - * Number of isolated pageblock. It is used to solve incorrect - * freepage counting problem due to racy retrieving migratetype - * of pageblock. Protected by zone->lock. - */ - unsigned long nr_isolate_pageblock; -#endif - -#ifdef CONFIG_MEMORY_HOTPLUG - /* see spanned/present_pages for more description */ - seqlock_t span_seqlock; -#endif - - int initialized; - - /* Write-intensive fields used from the page allocator */ - ZONE_PADDING(_pad1_) - - /* free areas of different sizes */ - struct free_area free_area[MAX_ORDER]; - - /* zone flags, see below */ - unsigned long flags; - - /* Primarily protects free_area */ - spinlock_t lock; - - /* Write-intensive fields used by compaction and vmstats. */ - ZONE_PADDING(_pad2_) - - /* - * When free pages are below this point, additional steps are taken - * when reading the number of free pages to avoid per-cpu counter - * drift allowing watermarks to be breached - */ - unsigned long percpu_drift_mark; - -#if defined CONFIG_COMPACTION || defined CONFIG_CMA - /* pfn where compaction free scanner should start */ - unsigned long compact_cached_free_pfn; - /* pfn where async and sync compaction migration scanner should start */ - unsigned long compact_cached_migrate_pfn[2]; -#endif - -#ifdef CONFIG_COMPACTION - /* - * On compaction failure, 1<zone_start_pfn + zone->spanned_pages; -} - -static inline bool zone_spans_pfn(const struct zone *zone, unsigned long pfn) -{ - return zone->zone_start_pfn <= pfn && pfn < zone_end_pfn(zone); -} - -static inline bool zone_is_initialized(struct zone *zone) -{ - return zone->initialized; -} - -static inline bool zone_is_empty(struct zone *zone) -{ - return zone->spanned_pages == 0; -} - -/* - * The "priority" of VM scanning is how much of the queues we will scan in one - * go. A value of 12 for DEF_PRIORITY implies that we will scan 1/4096th of the - * queues ("queue_length >> 12") during an aging round. - */ -#define DEF_PRIORITY 12 - -/* Maximum number of zones on a zonelist */ -#define MAX_ZONES_PER_ZONELIST (MAX_NUMNODES * MAX_NR_ZONES) - -enum { - ZONELIST_FALLBACK, /* zonelist with fallback */ -#ifdef CONFIG_NUMA - /* - * The NUMA zonelists are doubled because we need zonelists that - * restrict the allocations to a single node for __GFP_THISNODE. - */ - ZONELIST_NOFALLBACK, /* zonelist without fallback (__GFP_THISNODE) */ -#endif - MAX_ZONELISTS -}; - -/* - * This struct contains information about a zone in a zonelist. It is stored - * here to avoid dereferences into large structures and lookups of tables - */ -struct zoneref { - struct zone *zone; /* Pointer to actual zone */ - int zone_idx; /* zone_idx(zoneref->zone) */ -}; - -/* - * One allocation request operates on a zonelist. A zonelist - * is a list of zones, the first one is the 'goal' of the - * allocation, the other zones are fallback zones, in decreasing - * priority. - * - * To speed the reading of the zonelist, the zonerefs contain the zone index - * of the entry being read. Helper functions to access information given - * a struct zoneref are - * - * zonelist_zone() - Return the struct zone * for an entry in _zonerefs - * zonelist_zone_idx() - Return the index of the zone for an entry - * zonelist_node_idx() - Return the index of the node for an entry - */ -struct zonelist { - struct zoneref _zonerefs[MAX_ZONES_PER_ZONELIST + 1]; -}; - -#ifndef CONFIG_DISCONTIGMEM -/* The array of struct pages - for discontigmem use pgdat->lmem_map */ -extern struct page *mem_map; -#endif - -/* - * The pg_data_t structure is used in machines with CONFIG_DISCONTIGMEM - * (mostly NUMA machines?) to denote a higher-level memory zone than the - * zone denotes. - * - * On NUMA machines, each NUMA node would have a pg_data_t to describe - * it's memory layout. - * - * Memory statistics and page replacement data structures are maintained on a - * per-zone basis. - */ -struct bootmem_data; -typedef struct pglist_data { - struct zone node_zones[MAX_NR_ZONES]; - struct zonelist node_zonelists[MAX_ZONELISTS]; - int nr_zones; -#ifdef CONFIG_FLAT_NODE_MEM_MAP /* means !SPARSEMEM */ - struct page *node_mem_map; -#ifdef CONFIG_PAGE_EXTENSION - struct page_ext *node_page_ext; -#endif -#endif -#ifndef CONFIG_NO_BOOTMEM - struct bootmem_data *bdata; -#endif -#ifdef CONFIG_MEMORY_HOTPLUG - /* - * Must be held any time you expect node_start_pfn, node_present_pages - * or node_spanned_pages stay constant. Holding this will also - * guarantee that any pfn_valid() stays that way. - * - * pgdat_resize_lock() and pgdat_resize_unlock() are provided to - * manipulate node_size_lock without checking for CONFIG_MEMORY_HOTPLUG. - * - * Nests above zone->lock and zone->span_seqlock - */ - spinlock_t node_size_lock; -#endif - unsigned long node_start_pfn; - unsigned long node_present_pages; /* total number of physical pages */ - unsigned long node_spanned_pages; /* total size of physical page - range, including holes */ - int node_id; - wait_queue_head_t kswapd_wait; - wait_queue_head_t pfmemalloc_wait; - struct task_struct *kswapd; /* Protected by - mem_hotplug_begin/end() */ - int kswapd_order; - enum zone_type kswapd_classzone_idx; - -#ifdef CONFIG_COMPACTION - int kcompactd_max_order; - enum zone_type kcompactd_classzone_idx; - wait_queue_head_t kcompactd_wait; - struct task_struct *kcompactd; -#endif -#ifdef CONFIG_NUMA_BALANCING - /* Lock serializing the migrate rate limiting window */ - spinlock_t numabalancing_migrate_lock; - - /* Rate limiting time interval */ - unsigned long numabalancing_migrate_next_window; - - /* Number of pages migrated during the rate limiting time interval */ - unsigned long numabalancing_migrate_nr_pages; -#endif - /* - * This is a per-node reserve of pages that are not available - * to userspace allocations. - */ - unsigned long totalreserve_pages; - -#ifdef CONFIG_NUMA - /* - * zone reclaim becomes active if more unmapped pages exist. - */ - unsigned long min_unmapped_pages; - unsigned long min_slab_pages; -#endif /* CONFIG_NUMA */ - - /* Write-intensive fields used by page reclaim */ - ZONE_PADDING(_pad1_) - spinlock_t lru_lock; - -#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT - /* - * If memory initialisation on large machines is deferred then this - * is the first PFN that needs to be initialised. - */ - unsigned long first_deferred_pfn; -#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */ - -#ifdef CONFIG_TRANSPARENT_HUGEPAGE - spinlock_t split_queue_lock; - struct list_head split_queue; - unsigned long split_queue_len; -#endif - - /* Fields commonly accessed by the page reclaim scanner */ - struct lruvec lruvec; - - /* - * The target ratio of ACTIVE_ANON to INACTIVE_ANON pages on - * this node's LRU. Maintained by the pageout code. - */ - unsigned int inactive_ratio; - - unsigned long flags; - - ZONE_PADDING(_pad2_) - - /* Per-node vmstats */ - struct per_cpu_nodestat __percpu *per_cpu_nodestats; - atomic_long_t vm_stat[NR_VM_NODE_STAT_ITEMS]; -} pg_data_t; - -#define node_present_pages(nid) (NODE_DATA(nid)->node_present_pages) -#define node_spanned_pages(nid) (NODE_DATA(nid)->node_spanned_pages) -#ifdef CONFIG_FLAT_NODE_MEM_MAP -#define pgdat_page_nr(pgdat, pagenr) ((pgdat)->node_mem_map + (pagenr)) -#else -#define pgdat_page_nr(pgdat, pagenr) pfn_to_page((pgdat)->node_start_pfn + (pagenr)) -#endif -#define nid_page_nr(nid, pagenr) pgdat_page_nr(NODE_DATA(nid),(pagenr)) - -#define node_start_pfn(nid) (NODE_DATA(nid)->node_start_pfn) -#define node_end_pfn(nid) pgdat_end_pfn(NODE_DATA(nid)) -static inline spinlock_t *zone_lru_lock(struct zone *zone) -{ - return &zone->zone_pgdat->lru_lock; -} - -static inline struct lruvec *node_lruvec(struct pglist_data *pgdat) -{ - return &pgdat->lruvec; -} - -static inline unsigned long pgdat_end_pfn(pg_data_t *pgdat) -{ - return pgdat->node_start_pfn + pgdat->node_spanned_pages; -} - -static inline bool pgdat_is_empty(pg_data_t *pgdat) -{ - return !pgdat->node_start_pfn && !pgdat->node_spanned_pages; -} - -static inline int zone_id(const struct zone *zone) -{ - struct pglist_data *pgdat = zone->zone_pgdat; - - return zone - pgdat->node_zones; -} - -#ifdef CONFIG_ZONE_DEVICE -static inline bool is_dev_zone(const struct zone *zone) -{ - return zone_id(zone) == ZONE_DEVICE; -} -#else -static inline bool is_dev_zone(const struct zone *zone) -{ - return false; -} -#endif - -#include - -extern struct mutex zonelists_mutex; -void build_all_zonelists(pg_data_t *pgdat, struct zone *zone); -void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx); -bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, - int classzone_idx, unsigned int alloc_flags, - long free_pages); -bool zone_watermark_ok(struct zone *z, unsigned int order, - unsigned long mark, int classzone_idx, - unsigned int alloc_flags); -bool zone_watermark_ok_safe(struct zone *z, unsigned int order, - unsigned long mark, int classzone_idx); -enum memmap_context { - MEMMAP_EARLY, - MEMMAP_HOTPLUG, -}; -extern int init_currently_empty_zone(struct zone *zone, unsigned long start_pfn, - unsigned long size); - -extern void lruvec_init(struct lruvec *lruvec); - -static inline struct pglist_data *lruvec_pgdat(struct lruvec *lruvec) -{ -#ifdef CONFIG_MEMCG - return lruvec->pgdat; -#else - return container_of(lruvec, struct pglist_data, lruvec); -#endif -} - -extern unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru); - -#ifdef CONFIG_HAVE_MEMORY_PRESENT -void memory_present(int nid, unsigned long start, unsigned long end); -#else -static inline void memory_present(int nid, unsigned long start, unsigned long end) {} -#endif - -#ifdef CONFIG_HAVE_MEMORYLESS_NODES -int local_memory_node(int node_id); -#else -static inline int local_memory_node(int node_id) { return node_id; }; -#endif - -#ifdef CONFIG_NEED_NODE_MEMMAP_SIZE -unsigned long __init node_memmap_size_bytes(int, unsigned long, unsigned long); -#endif - -/* - * zone_idx() returns 0 for the ZONE_DMA zone, 1 for the ZONE_NORMAL zone, etc. - */ -#define zone_idx(zone) ((zone) - (zone)->zone_pgdat->node_zones) - -/* - * Returns true if a zone has pages managed by the buddy allocator. - * All the reclaim decisions have to use this function rather than - * populated_zone(). If the whole zone is reserved then we can easily - * end up with populated_zone() && !managed_zone(). - */ -static inline bool managed_zone(struct zone *zone) -{ - return zone->managed_pages; -} - -/* Returns true if a zone has memory */ -static inline bool populated_zone(struct zone *zone) -{ - return zone->present_pages; -} - -extern int movable_zone; - -#ifdef CONFIG_HIGHMEM -static inline int zone_movable_is_highmem(void) -{ -#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP - return movable_zone == ZONE_HIGHMEM; -#else - return (ZONE_MOVABLE - 1) == ZONE_HIGHMEM; -#endif -} -#endif - -static inline int is_highmem_idx(enum zone_type idx) -{ -#ifdef CONFIG_HIGHMEM - return (idx == ZONE_HIGHMEM || - (idx == ZONE_MOVABLE && zone_movable_is_highmem())); -#else - return 0; -#endif -} - -/** - * is_highmem - helper function to quickly check if a struct zone is a - * highmem zone or not. This is an attempt to keep references - * to ZONE_{DMA/NORMAL/HIGHMEM/etc} in general code to a minimum. - * @zone - pointer to struct zone variable - */ -static inline int is_highmem(struct zone *zone) -{ -#ifdef CONFIG_HIGHMEM - return is_highmem_idx(zone_idx(zone)); -#else - return 0; -#endif -} - -/* These two functions are used to setup the per zone pages min values */ -struct ctl_table; -int min_free_kbytes_sysctl_handler(struct ctl_table *, int, - void __user *, size_t *, loff_t *); -int watermark_scale_factor_sysctl_handler(struct ctl_table *, int, - void __user *, size_t *, loff_t *); -extern int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES-1]; -int lowmem_reserve_ratio_sysctl_handler(struct ctl_table *, int, - void __user *, size_t *, loff_t *); -int percpu_pagelist_fraction_sysctl_handler(struct ctl_table *, int, - void __user *, size_t *, loff_t *); -int sysctl_min_unmapped_ratio_sysctl_handler(struct ctl_table *, int, - void __user *, size_t *, loff_t *); -int sysctl_min_slab_ratio_sysctl_handler(struct ctl_table *, int, - void __user *, size_t *, loff_t *); - -extern int numa_zonelist_order_handler(struct ctl_table *, int, - void __user *, size_t *, loff_t *); -extern char numa_zonelist_order[]; -#define NUMA_ZONELIST_ORDER_LEN 16 /* string buffer size */ - -#ifndef CONFIG_NEED_MULTIPLE_NODES - -extern struct pglist_data contig_page_data; -#define NODE_DATA(nid) (&contig_page_data) -#define NODE_MEM_MAP(nid) mem_map - -#else /* CONFIG_NEED_MULTIPLE_NODES */ - -#include - -#endif /* !CONFIG_NEED_MULTIPLE_NODES */ - -extern struct pglist_data *first_online_pgdat(void); -extern struct pglist_data *next_online_pgdat(struct pglist_data *pgdat); -extern struct zone *next_zone(struct zone *zone); - -/** - * for_each_online_pgdat - helper macro to iterate over all online nodes - * @pgdat - pointer to a pg_data_t variable - */ -#define for_each_online_pgdat(pgdat) \ - for (pgdat = first_online_pgdat(); \ - pgdat; \ - pgdat = next_online_pgdat(pgdat)) -/** - * for_each_zone - helper macro to iterate over all memory zones - * @zone - pointer to struct zone variable - * - * The user only needs to declare the zone variable, for_each_zone - * fills it in. - */ -#define for_each_zone(zone) \ - for (zone = (first_online_pgdat())->node_zones; \ - zone; \ - zone = next_zone(zone)) - -#define for_each_populated_zone(zone) \ - for (zone = (first_online_pgdat())->node_zones; \ - zone; \ - zone = next_zone(zone)) \ - if (!populated_zone(zone)) \ - ; /* do nothing */ \ - else - -static inline struct zone *zonelist_zone(struct zoneref *zoneref) -{ - return zoneref->zone; -} - -static inline int zonelist_zone_idx(struct zoneref *zoneref) -{ - return zoneref->zone_idx; -} - -static inline int zonelist_node_idx(struct zoneref *zoneref) -{ -#ifdef CONFIG_NUMA - /* zone_to_nid not available in this context */ - return zoneref->zone->node; -#else - return 0; -#endif /* CONFIG_NUMA */ -} - -struct zoneref *__next_zones_zonelist(struct zoneref *z, - enum zone_type highest_zoneidx, - nodemask_t *nodes); - -/** - * next_zones_zonelist - Returns the next zone at or below highest_zoneidx within the allowed nodemask using a cursor within a zonelist as a starting point - * @z - The cursor used as a starting point for the search - * @highest_zoneidx - The zone index of the highest zone to return - * @nodes - An optional nodemask to filter the zonelist with - * - * This function returns the next zone at or below a given zone index that is - * within the allowed nodemask using a cursor as the starting point for the - * search. The zoneref returned is a cursor that represents the current zone - * being examined. It should be advanced by one before calling - * next_zones_zonelist again. - */ -static __always_inline struct zoneref *next_zones_zonelist(struct zoneref *z, - enum zone_type highest_zoneidx, - nodemask_t *nodes) -{ - if (likely(!nodes && zonelist_zone_idx(z) <= highest_zoneidx)) - return z; - return __next_zones_zonelist(z, highest_zoneidx, nodes); -} - -/** - * first_zones_zonelist - Returns the first zone at or below highest_zoneidx within the allowed nodemask in a zonelist - * @zonelist - The zonelist to search for a suitable zone - * @highest_zoneidx - The zone index of the highest zone to return - * @nodes - An optional nodemask to filter the zonelist with - * @zone - The first suitable zone found is returned via this parameter - * - * This function returns the first zone at or below a given zone index that is - * within the allowed nodemask. The zoneref returned is a cursor that can be - * used to iterate the zonelist with next_zones_zonelist by advancing it by - * one before calling. - */ -static inline struct zoneref *first_zones_zonelist(struct zonelist *zonelist, - enum zone_type highest_zoneidx, - nodemask_t *nodes) -{ - return next_zones_zonelist(zonelist->_zonerefs, - highest_zoneidx, nodes); -} - -/** - * for_each_zone_zonelist_nodemask - helper macro to iterate over valid zones in a zonelist at or below a given zone index and within a nodemask - * @zone - The current zone in the iterator - * @z - The current pointer within zonelist->zones being iterated - * @zlist - The zonelist being iterated - * @highidx - The zone index of the highest zone to return - * @nodemask - Nodemask allowed by the allocator - * - * This iterator iterates though all zones at or below a given zone index and - * within a given nodemask - */ -#define for_each_zone_zonelist_nodemask(zone, z, zlist, highidx, nodemask) \ - for (z = first_zones_zonelist(zlist, highidx, nodemask), zone = zonelist_zone(z); \ - zone; \ - z = next_zones_zonelist(++z, highidx, nodemask), \ - zone = zonelist_zone(z)) - -#define for_next_zone_zonelist_nodemask(zone, z, zlist, highidx, nodemask) \ - for (zone = z->zone; \ - zone; \ - z = next_zones_zonelist(++z, highidx, nodemask), \ - zone = zonelist_zone(z)) - - -/** - * for_each_zone_zonelist - helper macro to iterate over valid zones in a zonelist at or below a given zone index - * @zone - The current zone in the iterator - * @z - The current pointer within zonelist->zones being iterated - * @zlist - The zonelist being iterated - * @highidx - The zone index of the highest zone to return - * - * This iterator iterates though all zones at or below a given zone index. - */ -#define for_each_zone_zonelist(zone, z, zlist, highidx) \ - for_each_zone_zonelist_nodemask(zone, z, zlist, highidx, NULL) - -#ifdef CONFIG_SPARSEMEM -#include -#endif - -#if !defined(CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID) && \ - !defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP) -static inline unsigned long early_pfn_to_nid(unsigned long pfn) -{ - return 0; -} -#endif - -#ifdef CONFIG_FLATMEM -#define pfn_to_nid(pfn) (0) -#endif - -#ifdef CONFIG_SPARSEMEM - -/* - * SECTION_SHIFT #bits space required to store a section # - * - * PA_SECTION_SHIFT physical address to/from section number - * PFN_SECTION_SHIFT pfn to/from section number - */ -#define PA_SECTION_SHIFT (SECTION_SIZE_BITS) -#define PFN_SECTION_SHIFT (SECTION_SIZE_BITS - PAGE_SHIFT) - -#define NR_MEM_SECTIONS (1UL << SECTIONS_SHIFT) - -#define PAGES_PER_SECTION (1UL << PFN_SECTION_SHIFT) -#define PAGE_SECTION_MASK (~(PAGES_PER_SECTION-1)) - -#define SECTION_BLOCKFLAGS_BITS \ - ((1UL << (PFN_SECTION_SHIFT - pageblock_order)) * NR_PAGEBLOCK_BITS) - -#if (MAX_ORDER - 1 + PAGE_SHIFT) > SECTION_SIZE_BITS -#error Allocator MAX_ORDER exceeds SECTION_SIZE -#endif - -#define pfn_to_section_nr(pfn) ((pfn) >> PFN_SECTION_SHIFT) -#define section_nr_to_pfn(sec) ((sec) << PFN_SECTION_SHIFT) - -#define SECTION_ALIGN_UP(pfn) (((pfn) + PAGES_PER_SECTION - 1) & PAGE_SECTION_MASK) -#define SECTION_ALIGN_DOWN(pfn) ((pfn) & PAGE_SECTION_MASK) - -struct page; -struct page_ext; -struct mem_section { - /* - * This is, logically, a pointer to an array of struct - * pages. However, it is stored with some other magic. - * (see sparse.c::sparse_init_one_section()) - * - * Additionally during early boot we encode node id of - * the location of the section here to guide allocation. - * (see sparse.c::memory_present()) - * - * Making it a UL at least makes someone do a cast - * before using it wrong. - */ - unsigned long section_mem_map; - - /* See declaration of similar field in struct zone */ - unsigned long *pageblock_flags; -#ifdef CONFIG_PAGE_EXTENSION - /* - * If SPARSEMEM, pgdat doesn't have page_ext pointer. We use - * section. (see page_ext.h about this.) - */ - struct page_ext *page_ext; - unsigned long pad; -#endif - /* - * WARNING: mem_section must be a power-of-2 in size for the - * calculation and use of SECTION_ROOT_MASK to make sense. - */ -}; - -#ifdef CONFIG_SPARSEMEM_EXTREME -#define SECTIONS_PER_ROOT (PAGE_SIZE / sizeof (struct mem_section)) -#else -#define SECTIONS_PER_ROOT 1 -#endif - -#define SECTION_NR_TO_ROOT(sec) ((sec) / SECTIONS_PER_ROOT) -#define NR_SECTION_ROOTS DIV_ROUND_UP(NR_MEM_SECTIONS, SECTIONS_PER_ROOT) -#define SECTION_ROOT_MASK (SECTIONS_PER_ROOT - 1) - -#ifdef CONFIG_SPARSEMEM_EXTREME -extern struct mem_section *mem_section[NR_SECTION_ROOTS]; -#else -extern struct mem_section mem_section[NR_SECTION_ROOTS][SECTIONS_PER_ROOT]; -#endif - -static inline struct mem_section *__nr_to_section(unsigned long nr) -{ - if (!mem_section[SECTION_NR_TO_ROOT(nr)]) - return NULL; - return &mem_section[SECTION_NR_TO_ROOT(nr)][nr & SECTION_ROOT_MASK]; -} -extern int __section_nr(struct mem_section* ms); -extern unsigned long usemap_size(void); - -/* - * We use the lower bits of the mem_map pointer to store - * a little bit of information. There should be at least - * 3 bits here due to 32-bit alignment. - */ -#define SECTION_MARKED_PRESENT (1UL<<0) -#define SECTION_HAS_MEM_MAP (1UL<<1) -#define SECTION_MAP_LAST_BIT (1UL<<2) -#define SECTION_MAP_MASK (~(SECTION_MAP_LAST_BIT-1)) -#define SECTION_NID_SHIFT 2 - -static inline struct page *__section_mem_map_addr(struct mem_section *section) -{ - unsigned long map = section->section_mem_map; - map &= SECTION_MAP_MASK; - return (struct page *)map; -} - -static inline int present_section(struct mem_section *section) -{ - return (section && (section->section_mem_map & SECTION_MARKED_PRESENT)); -} - -static inline int present_section_nr(unsigned long nr) -{ - return present_section(__nr_to_section(nr)); -} - -static inline int valid_section(struct mem_section *section) -{ - return (section && (section->section_mem_map & SECTION_HAS_MEM_MAP)); -} - -static inline int valid_section_nr(unsigned long nr) -{ - return valid_section(__nr_to_section(nr)); -} - -static inline struct mem_section *__pfn_to_section(unsigned long pfn) -{ - return __nr_to_section(pfn_to_section_nr(pfn)); -} - -#ifndef CONFIG_HAVE_ARCH_PFN_VALID -static inline int pfn_valid(unsigned long pfn) -{ - if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS) - return 0; - return valid_section(__nr_to_section(pfn_to_section_nr(pfn))); -} -#endif - -static inline int pfn_present(unsigned long pfn) -{ - if (pfn_to_section_nr(pfn) >= NR_MEM_SECTIONS) - return 0; - return present_section(__nr_to_section(pfn_to_section_nr(pfn))); -} - -/* - * These are _only_ used during initialisation, therefore they - * can use __initdata ... They could have names to indicate - * this restriction. - */ -#ifdef CONFIG_NUMA -#define pfn_to_nid(pfn) \ -({ \ - unsigned long __pfn_to_nid_pfn = (pfn); \ - page_to_nid(pfn_to_page(__pfn_to_nid_pfn)); \ -}) -#else -#define pfn_to_nid(pfn) (0) -#endif - -#define early_pfn_valid(pfn) pfn_valid(pfn) -void sparse_init(void); -#else -#define sparse_init() do {} while (0) -#define sparse_index_init(_sec, _nid) do {} while (0) -#endif /* CONFIG_SPARSEMEM */ - -/* - * During memory init memblocks map pfns to nids. The search is expensive and - * this caches recent lookups. The implementation of __early_pfn_to_nid - * may treat start/end as pfns or sections. - */ -struct mminit_pfnnid_cache { - unsigned long last_start; - unsigned long last_end; - int last_nid; -}; - -#ifndef early_pfn_valid -#define early_pfn_valid(pfn) (1) -#endif - -void memory_present(int nid, unsigned long start, unsigned long end); -unsigned long __init node_memmap_size_bytes(int, unsigned long, unsigned long); - -/* - * If it is possible to have holes within a MAX_ORDER_NR_PAGES, then we - * need to check pfn validility within that MAX_ORDER_NR_PAGES block. - * pfn_valid_within() should be used in this case; we optimise this away - * when we have no holes within a MAX_ORDER_NR_PAGES block. - */ -#ifdef CONFIG_HOLES_IN_ZONE -#define pfn_valid_within(pfn) pfn_valid(pfn) -#else -#define pfn_valid_within(pfn) (1) -#endif - -#ifdef CONFIG_ARCH_HAS_HOLES_MEMORYMODEL -/* - * pfn_valid() is meant to be able to tell if a given PFN has valid memmap - * associated with it or not. In FLATMEM, it is expected that holes always - * have valid memmap as long as there is valid PFNs either side of the hole. - * In SPARSEMEM, it is assumed that a valid section has a memmap for the - * entire section. - * - * However, an ARM, and maybe other embedded architectures in the future - * free memmap backing holes to save memory on the assumption the memmap is - * never used. The page_zone linkages are then broken even though pfn_valid() - * returns true. A walker of the full memmap must then do this additional - * check to ensure the memmap they are looking at is sane by making sure - * the zone and PFN linkages are still valid. This is expensive, but walkers - * of the full memmap are extremely rare. - */ -bool memmap_valid_within(unsigned long pfn, - struct page *page, struct zone *zone); -#else -static inline bool memmap_valid_within(unsigned long pfn, - struct page *page, struct zone *zone) -{ - return true; -} -#endif /* CONFIG_ARCH_HAS_HOLES_MEMORYMODEL */ - -#endif /* !__GENERATING_BOUNDS.H */ -#endif /* !__ASSEMBLY__ */ -#endif /* _LINUX_MMZONE_H */ diff --git a/src/linux/include/linux/mnt_namespace.h b/src/linux/include/linux/mnt_namespace.h deleted file mode 100644 index 12b2ab5..0000000 --- a/src/linux/include/linux/mnt_namespace.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _NAMESPACE_H_ -#define _NAMESPACE_H_ -#ifdef __KERNEL__ - -struct mnt_namespace; -struct fs_struct; -struct user_namespace; - -extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *, - struct user_namespace *, struct fs_struct *); -extern void put_mnt_ns(struct mnt_namespace *ns); - -extern const struct file_operations proc_mounts_operations; -extern const struct file_operations proc_mountinfo_operations; -extern const struct file_operations proc_mountstats_operations; - -#endif -#endif diff --git a/src/linux/include/linux/mod_devicetable.h b/src/linux/include/linux/mod_devicetable.h deleted file mode 100644 index ed84c07..0000000 --- a/src/linux/include/linux/mod_devicetable.h +++ /dev/null @@ -1,676 +0,0 @@ -/* - * Device tables which are exported to userspace via - * scripts/mod/file2alias.c. You must keep that file in sync with this - * header. - */ - -#ifndef LINUX_MOD_DEVICETABLE_H -#define LINUX_MOD_DEVICETABLE_H - -#ifdef __KERNEL__ -#include -#include -typedef unsigned long kernel_ulong_t; -#endif - -#define PCI_ANY_ID (~0) - -struct pci_device_id { - __u32 vendor, device; /* Vendor and device ID or PCI_ANY_ID*/ - __u32 subvendor, subdevice; /* Subsystem ID's or PCI_ANY_ID */ - __u32 class, class_mask; /* (class,subclass,prog-if) triplet */ - kernel_ulong_t driver_data; /* Data private to the driver */ -}; - - -#define IEEE1394_MATCH_VENDOR_ID 0x0001 -#define IEEE1394_MATCH_MODEL_ID 0x0002 -#define IEEE1394_MATCH_SPECIFIER_ID 0x0004 -#define IEEE1394_MATCH_VERSION 0x0008 - -struct ieee1394_device_id { - __u32 match_flags; - __u32 vendor_id; - __u32 model_id; - __u32 specifier_id; - __u32 version; - kernel_ulong_t driver_data; -}; - - -/* - * Device table entry for "new style" table-driven USB drivers. - * User mode code can read these tables to choose which modules to load. - * Declare the table as a MODULE_DEVICE_TABLE. - * - * A probe() parameter will point to a matching entry from this table. - * Use the driver_info field for each match to hold information tied - * to that match: device quirks, etc. - * - * Terminate the driver's table with an all-zeroes entry. - * Use the flag values to control which fields are compared. - */ - -/** - * struct usb_device_id - identifies USB devices for probing and hotplugging - * @match_flags: Bit mask controlling which of the other fields are used to - * match against new devices. Any field except for driver_info may be - * used, although some only make sense in conjunction with other fields. - * This is usually set by a USB_DEVICE_*() macro, which sets all - * other fields in this structure except for driver_info. - * @idVendor: USB vendor ID for a device; numbers are assigned - * by the USB forum to its members. - * @idProduct: Vendor-assigned product ID. - * @bcdDevice_lo: Low end of range of vendor-assigned product version numbers. - * This is also used to identify individual product versions, for - * a range consisting of a single device. - * @bcdDevice_hi: High end of version number range. The range of product - * versions is inclusive. - * @bDeviceClass: Class of device; numbers are assigned - * by the USB forum. Products may choose to implement classes, - * or be vendor-specific. Device classes specify behavior of all - * the interfaces on a device. - * @bDeviceSubClass: Subclass of device; associated with bDeviceClass. - * @bDeviceProtocol: Protocol of device; associated with bDeviceClass. - * @bInterfaceClass: Class of interface; numbers are assigned - * by the USB forum. Products may choose to implement classes, - * or be vendor-specific. Interface classes specify behavior only - * of a given interface; other interfaces may support other classes. - * @bInterfaceSubClass: Subclass of interface; associated with bInterfaceClass. - * @bInterfaceProtocol: Protocol of interface; associated with bInterfaceClass. - * @bInterfaceNumber: Number of interface; composite devices may use - * fixed interface numbers to differentiate between vendor-specific - * interfaces. - * @driver_info: Holds information used by the driver. Usually it holds - * a pointer to a descriptor understood by the driver, or perhaps - * device flags. - * - * In most cases, drivers will create a table of device IDs by using - * USB_DEVICE(), or similar macros designed for that purpose. - * They will then export it to userspace using MODULE_DEVICE_TABLE(), - * and provide it to the USB core through their usb_driver structure. - * - * See the usb_match_id() function for information about how matches are - * performed. Briefly, you will normally use one of several macros to help - * construct these entries. Each entry you provide will either identify - * one or more specific products, or will identify a class of products - * which have agreed to behave the same. You should put the more specific - * matches towards the beginning of your table, so that driver_info can - * record quirks of specific products. - */ -struct usb_device_id { - /* which fields to match against? */ - __u16 match_flags; - - /* Used for product specific matches; range is inclusive */ - __u16 idVendor; - __u16 idProduct; - __u16 bcdDevice_lo; - __u16 bcdDevice_hi; - - /* Used for device class matches */ - __u8 bDeviceClass; - __u8 bDeviceSubClass; - __u8 bDeviceProtocol; - - /* Used for interface class matches */ - __u8 bInterfaceClass; - __u8 bInterfaceSubClass; - __u8 bInterfaceProtocol; - - /* Used for vendor-specific interface matches */ - __u8 bInterfaceNumber; - - /* not matched against */ - kernel_ulong_t driver_info - __attribute__((aligned(sizeof(kernel_ulong_t)))); -}; - -/* Some useful macros to use to create struct usb_device_id */ -#define USB_DEVICE_ID_MATCH_VENDOR 0x0001 -#define USB_DEVICE_ID_MATCH_PRODUCT 0x0002 -#define USB_DEVICE_ID_MATCH_DEV_LO 0x0004 -#define USB_DEVICE_ID_MATCH_DEV_HI 0x0008 -#define USB_DEVICE_ID_MATCH_DEV_CLASS 0x0010 -#define USB_DEVICE_ID_MATCH_DEV_SUBCLASS 0x0020 -#define USB_DEVICE_ID_MATCH_DEV_PROTOCOL 0x0040 -#define USB_DEVICE_ID_MATCH_INT_CLASS 0x0080 -#define USB_DEVICE_ID_MATCH_INT_SUBCLASS 0x0100 -#define USB_DEVICE_ID_MATCH_INT_PROTOCOL 0x0200 -#define USB_DEVICE_ID_MATCH_INT_NUMBER 0x0400 - -#define HID_ANY_ID (~0) -#define HID_BUS_ANY 0xffff -#define HID_GROUP_ANY 0x0000 - -struct hid_device_id { - __u16 bus; - __u16 group; - __u32 vendor; - __u32 product; - kernel_ulong_t driver_data; -}; - -/* s390 CCW devices */ -struct ccw_device_id { - __u16 match_flags; /* which fields to match against */ - - __u16 cu_type; /* control unit type */ - __u16 dev_type; /* device type */ - __u8 cu_model; /* control unit model */ - __u8 dev_model; /* device model */ - - kernel_ulong_t driver_info; -}; - -#define CCW_DEVICE_ID_MATCH_CU_TYPE 0x01 -#define CCW_DEVICE_ID_MATCH_CU_MODEL 0x02 -#define CCW_DEVICE_ID_MATCH_DEVICE_TYPE 0x04 -#define CCW_DEVICE_ID_MATCH_DEVICE_MODEL 0x08 - -/* s390 AP bus devices */ -struct ap_device_id { - __u16 match_flags; /* which fields to match against */ - __u8 dev_type; /* device type */ - kernel_ulong_t driver_info; -}; - -#define AP_DEVICE_ID_MATCH_DEVICE_TYPE 0x01 - -/* s390 css bus devices (subchannels) */ -struct css_device_id { - __u8 match_flags; - __u8 type; /* subchannel type */ - kernel_ulong_t driver_data; -}; - -#define ACPI_ID_LEN 9 - -struct acpi_device_id { - __u8 id[ACPI_ID_LEN]; - kernel_ulong_t driver_data; - __u32 cls; - __u32 cls_msk; -}; - -#define PNP_ID_LEN 8 -#define PNP_MAX_DEVICES 8 - -struct pnp_device_id { - __u8 id[PNP_ID_LEN]; - kernel_ulong_t driver_data; -}; - -struct pnp_card_device_id { - __u8 id[PNP_ID_LEN]; - kernel_ulong_t driver_data; - struct { - __u8 id[PNP_ID_LEN]; - } devs[PNP_MAX_DEVICES]; -}; - - -#define SERIO_ANY 0xff - -struct serio_device_id { - __u8 type; - __u8 extra; - __u8 id; - __u8 proto; -}; - -struct hda_device_id { - __u32 vendor_id; - __u32 rev_id; - __u8 api_version; - const char *name; - unsigned long driver_data; -}; - -/* - * Struct used for matching a device - */ -struct of_device_id { - char name[32]; - char type[32]; - char compatible[128]; - const void *data; -}; - -/* VIO */ -struct vio_device_id { - char type[32]; - char compat[32]; -}; - -/* PCMCIA */ - -struct pcmcia_device_id { - __u16 match_flags; - - __u16 manf_id; - __u16 card_id; - - __u8 func_id; - - /* for real multi-function devices */ - __u8 function; - - /* for pseudo multi-function devices */ - __u8 device_no; - - __u32 prod_id_hash[4]; - - /* not matched against in kernelspace */ - const char * prod_id[4]; - - /* not matched against */ - kernel_ulong_t driver_info; - char * cisfile; -}; - -#define PCMCIA_DEV_ID_MATCH_MANF_ID 0x0001 -#define PCMCIA_DEV_ID_MATCH_CARD_ID 0x0002 -#define PCMCIA_DEV_ID_MATCH_FUNC_ID 0x0004 -#define PCMCIA_DEV_ID_MATCH_FUNCTION 0x0008 -#define PCMCIA_DEV_ID_MATCH_PROD_ID1 0x0010 -#define PCMCIA_DEV_ID_MATCH_PROD_ID2 0x0020 -#define PCMCIA_DEV_ID_MATCH_PROD_ID3 0x0040 -#define PCMCIA_DEV_ID_MATCH_PROD_ID4 0x0080 -#define PCMCIA_DEV_ID_MATCH_DEVICE_NO 0x0100 -#define PCMCIA_DEV_ID_MATCH_FAKE_CIS 0x0200 -#define PCMCIA_DEV_ID_MATCH_ANONYMOUS 0x0400 - -/* Input */ -#define INPUT_DEVICE_ID_EV_MAX 0x1f -#define INPUT_DEVICE_ID_KEY_MIN_INTERESTING 0x71 -#define INPUT_DEVICE_ID_KEY_MAX 0x2ff -#define INPUT_DEVICE_ID_REL_MAX 0x0f -#define INPUT_DEVICE_ID_ABS_MAX 0x3f -#define INPUT_DEVICE_ID_MSC_MAX 0x07 -#define INPUT_DEVICE_ID_LED_MAX 0x0f -#define INPUT_DEVICE_ID_SND_MAX 0x07 -#define INPUT_DEVICE_ID_FF_MAX 0x7f -#define INPUT_DEVICE_ID_SW_MAX 0x0f - -#define INPUT_DEVICE_ID_MATCH_BUS 1 -#define INPUT_DEVICE_ID_MATCH_VENDOR 2 -#define INPUT_DEVICE_ID_MATCH_PRODUCT 4 -#define INPUT_DEVICE_ID_MATCH_VERSION 8 - -#define INPUT_DEVICE_ID_MATCH_EVBIT 0x0010 -#define INPUT_DEVICE_ID_MATCH_KEYBIT 0x0020 -#define INPUT_DEVICE_ID_MATCH_RELBIT 0x0040 -#define INPUT_DEVICE_ID_MATCH_ABSBIT 0x0080 -#define INPUT_DEVICE_ID_MATCH_MSCIT 0x0100 -#define INPUT_DEVICE_ID_MATCH_LEDBIT 0x0200 -#define INPUT_DEVICE_ID_MATCH_SNDBIT 0x0400 -#define INPUT_DEVICE_ID_MATCH_FFBIT 0x0800 -#define INPUT_DEVICE_ID_MATCH_SWBIT 0x1000 - -struct input_device_id { - - kernel_ulong_t flags; - - __u16 bustype; - __u16 vendor; - __u16 product; - __u16 version; - - kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1]; - kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1]; - kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1]; - kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1]; - kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1]; - kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1]; - kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1]; - kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1]; - kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1]; - - kernel_ulong_t driver_info; -}; - -/* EISA */ - -#define EISA_SIG_LEN 8 - -/* The EISA signature, in ASCII form, null terminated */ -struct eisa_device_id { - char sig[EISA_SIG_LEN]; - kernel_ulong_t driver_data; -}; - -#define EISA_DEVICE_MODALIAS_FMT "eisa:s%s" - -struct parisc_device_id { - __u8 hw_type; /* 5 bits used */ - __u8 hversion_rev; /* 4 bits */ - __u16 hversion; /* 12 bits */ - __u32 sversion; /* 20 bits */ -}; - -#define PA_HWTYPE_ANY_ID 0xff -#define PA_HVERSION_REV_ANY_ID 0xff -#define PA_HVERSION_ANY_ID 0xffff -#define PA_SVERSION_ANY_ID 0xffffffff - -/* SDIO */ - -#define SDIO_ANY_ID (~0) - -struct sdio_device_id { - __u8 class; /* Standard interface or SDIO_ANY_ID */ - __u16 vendor; /* Vendor or SDIO_ANY_ID */ - __u16 device; /* Device ID or SDIO_ANY_ID */ - kernel_ulong_t driver_data; /* Data private to the driver */ -}; - -/* SSB core, see drivers/ssb/ */ -struct ssb_device_id { - __u16 vendor; - __u16 coreid; - __u8 revision; - __u8 __pad; -} __attribute__((packed, aligned(2))); -#define SSB_DEVICE(_vendor, _coreid, _revision) \ - { .vendor = _vendor, .coreid = _coreid, .revision = _revision, } - -#define SSB_ANY_VENDOR 0xFFFF -#define SSB_ANY_ID 0xFFFF -#define SSB_ANY_REV 0xFF - -/* Broadcom's specific AMBA core, see drivers/bcma/ */ -struct bcma_device_id { - __u16 manuf; - __u16 id; - __u8 rev; - __u8 class; -} __attribute__((packed,aligned(2))); -#define BCMA_CORE(_manuf, _id, _rev, _class) \ - { .manuf = _manuf, .id = _id, .rev = _rev, .class = _class, } - -#define BCMA_ANY_MANUF 0xFFFF -#define BCMA_ANY_ID 0xFFFF -#define BCMA_ANY_REV 0xFF -#define BCMA_ANY_CLASS 0xFF - -struct virtio_device_id { - __u32 device; - __u32 vendor; -}; -#define VIRTIO_DEV_ANY_ID 0xffffffff - -/* - * For Hyper-V devices we use the device guid as the id. - */ -struct hv_vmbus_device_id { - uuid_le guid; - kernel_ulong_t driver_data; /* Data private to the driver */ -}; - -/* rpmsg */ - -#define RPMSG_NAME_SIZE 32 -#define RPMSG_DEVICE_MODALIAS_FMT "rpmsg:%s" - -struct rpmsg_device_id { - char name[RPMSG_NAME_SIZE]; -}; - -/* i2c */ - -#define I2C_NAME_SIZE 20 -#define I2C_MODULE_PREFIX "i2c:" - -struct i2c_device_id { - char name[I2C_NAME_SIZE]; - kernel_ulong_t driver_data; /* Data private to the driver */ -}; - -/* spi */ - -#define SPI_NAME_SIZE 32 -#define SPI_MODULE_PREFIX "spi:" - -struct spi_device_id { - char name[SPI_NAME_SIZE]; - kernel_ulong_t driver_data; /* Data private to the driver */ -}; - -#define SPMI_NAME_SIZE 32 -#define SPMI_MODULE_PREFIX "spmi:" - -struct spmi_device_id { - char name[SPMI_NAME_SIZE]; - kernel_ulong_t driver_data; /* Data private to the driver */ -}; - -/* dmi */ -enum dmi_field { - DMI_NONE, - DMI_BIOS_VENDOR, - DMI_BIOS_VERSION, - DMI_BIOS_DATE, - DMI_SYS_VENDOR, - DMI_PRODUCT_NAME, - DMI_PRODUCT_VERSION, - DMI_PRODUCT_SERIAL, - DMI_PRODUCT_UUID, - DMI_BOARD_VENDOR, - DMI_BOARD_NAME, - DMI_BOARD_VERSION, - DMI_BOARD_SERIAL, - DMI_BOARD_ASSET_TAG, - DMI_CHASSIS_VENDOR, - DMI_CHASSIS_TYPE, - DMI_CHASSIS_VERSION, - DMI_CHASSIS_SERIAL, - DMI_CHASSIS_ASSET_TAG, - DMI_STRING_MAX, -}; - -struct dmi_strmatch { - unsigned char slot:7; - unsigned char exact_match:1; - char substr[79]; -}; - -struct dmi_system_id { - int (*callback)(const struct dmi_system_id *); - const char *ident; - struct dmi_strmatch matches[4]; - void *driver_data; -}; -/* - * struct dmi_device_id appears during expansion of - * "MODULE_DEVICE_TABLE(dmi, x)". Compiler doesn't look inside it - * but this is enough for gcc 3.4.6 to error out: - * error: storage size of '__mod_dmi_device_table' isn't known - */ -#define dmi_device_id dmi_system_id - -#define DMI_MATCH(a, b) { .slot = a, .substr = b } -#define DMI_EXACT_MATCH(a, b) { .slot = a, .substr = b, .exact_match = 1 } - -#define PLATFORM_NAME_SIZE 20 -#define PLATFORM_MODULE_PREFIX "platform:" - -struct platform_device_id { - char name[PLATFORM_NAME_SIZE]; - kernel_ulong_t driver_data; -}; - -#define MDIO_MODULE_PREFIX "mdio:" - -#define MDIO_ID_FMT "%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d" -#define MDIO_ID_ARGS(_id) \ - (_id)>>31, ((_id)>>30) & 1, ((_id)>>29) & 1, ((_id)>>28) & 1, \ - ((_id)>>27) & 1, ((_id)>>26) & 1, ((_id)>>25) & 1, ((_id)>>24) & 1, \ - ((_id)>>23) & 1, ((_id)>>22) & 1, ((_id)>>21) & 1, ((_id)>>20) & 1, \ - ((_id)>>19) & 1, ((_id)>>18) & 1, ((_id)>>17) & 1, ((_id)>>16) & 1, \ - ((_id)>>15) & 1, ((_id)>>14) & 1, ((_id)>>13) & 1, ((_id)>>12) & 1, \ - ((_id)>>11) & 1, ((_id)>>10) & 1, ((_id)>>9) & 1, ((_id)>>8) & 1, \ - ((_id)>>7) & 1, ((_id)>>6) & 1, ((_id)>>5) & 1, ((_id)>>4) & 1, \ - ((_id)>>3) & 1, ((_id)>>2) & 1, ((_id)>>1) & 1, (_id) & 1 - -/** - * struct mdio_device_id - identifies PHY devices on an MDIO/MII bus - * @phy_id: The result of - * (mdio_read(&MII_PHYSID1) << 16 | mdio_read(&PHYSID2)) & @phy_id_mask - * for this PHY type - * @phy_id_mask: Defines the significant bits of @phy_id. A value of 0 - * is used to terminate an array of struct mdio_device_id. - */ -struct mdio_device_id { - __u32 phy_id; - __u32 phy_id_mask; -}; - -struct zorro_device_id { - __u32 id; /* Device ID or ZORRO_WILDCARD */ - kernel_ulong_t driver_data; /* Data private to the driver */ -}; - -#define ZORRO_WILDCARD (0xffffffff) /* not official */ - -#define ZORRO_DEVICE_MODALIAS_FMT "zorro:i%08X" - -#define ISAPNP_ANY_ID 0xffff -struct isapnp_device_id { - unsigned short card_vendor, card_device; - unsigned short vendor, function; - kernel_ulong_t driver_data; /* data private to the driver */ -}; - -/** - * struct amba_id - identifies a device on an AMBA bus - * @id: The significant bits if the hardware device ID - * @mask: Bitmask specifying which bits of the id field are significant when - * matching. A driver binds to a device when ((hardware device ID) & mask) - * == id. - * @data: Private data used by the driver. - */ -struct amba_id { - unsigned int id; - unsigned int mask; - void *data; -}; - -/** - * struct mips_cdmm_device_id - identifies devices in MIPS CDMM bus - * @type: Device type identifier. - */ -struct mips_cdmm_device_id { - __u8 type; -}; - -/* - * Match x86 CPUs for CPU specific drivers. - * See documentation of "x86_match_cpu" for details. - */ - -/* - * MODULE_DEVICE_TABLE expects this struct to be called x86cpu_device_id. - * Although gcc seems to ignore this error, clang fails without this define. - */ -#define x86cpu_device_id x86_cpu_id -struct x86_cpu_id { - __u16 vendor; - __u16 family; - __u16 model; - __u16 feature; /* bit index */ - kernel_ulong_t driver_data; -}; - -#define X86_FEATURE_MATCH(x) \ - { X86_VENDOR_ANY, X86_FAMILY_ANY, X86_MODEL_ANY, x } - -#define X86_VENDOR_ANY 0xffff -#define X86_FAMILY_ANY 0 -#define X86_MODEL_ANY 0 -#define X86_FEATURE_ANY 0 /* Same as FPU, you can't test for that */ - -/* - * Generic table type for matching CPU features. - * @feature: the bit number of the feature (0 - 65535) - */ - -struct cpu_feature { - __u16 feature; -}; - -#define IPACK_ANY_FORMAT 0xff -#define IPACK_ANY_ID (~0) -struct ipack_device_id { - __u8 format; /* Format version or IPACK_ANY_ID */ - __u32 vendor; /* Vendor ID or IPACK_ANY_ID */ - __u32 device; /* Device ID or IPACK_ANY_ID */ -}; - -#define MEI_CL_MODULE_PREFIX "mei:" -#define MEI_CL_NAME_SIZE 32 -#define MEI_CL_VERSION_ANY 0xff - -/** - * struct mei_cl_device_id - MEI client device identifier - * @name: helper name - * @uuid: client uuid - * @version: client protocol version - * @driver_info: information used by the driver. - * - * identifies mei client device by uuid and name - */ -struct mei_cl_device_id { - char name[MEI_CL_NAME_SIZE]; - uuid_le uuid; - __u8 version; - kernel_ulong_t driver_info; -}; - -/* RapidIO */ - -#define RIO_ANY_ID 0xffff - -/** - * struct rio_device_id - RIO device identifier - * @did: RapidIO device ID - * @vid: RapidIO vendor ID - * @asm_did: RapidIO assembly device ID - * @asm_vid: RapidIO assembly vendor ID - * - * Identifies a RapidIO device based on both the device/vendor IDs and - * the assembly device/vendor IDs. - */ -struct rio_device_id { - __u16 did, vid; - __u16 asm_did, asm_vid; -}; - -struct mcb_device_id { - __u16 device; - kernel_ulong_t driver_data; -}; - -struct ulpi_device_id { - __u16 vendor; - __u16 product; - kernel_ulong_t driver_data; -}; - -/** - * struct fsl_mc_device_id - MC object device identifier - * @vendor: vendor ID - * @obj_type: MC object type - * @ver_major: MC object version major number - * @ver_minor: MC object version minor number - * - * Type of entries in the "device Id" table for MC object devices supported by - * a MC object device driver. The last entry of the table has vendor set to 0x0 - */ -struct fsl_mc_device_id { - __u16 vendor; - const char obj_type[16]; -}; - - -#endif /* LINUX_MOD_DEVICETABLE_H */ diff --git a/src/linux/include/linux/module.h b/src/linux/include/linux/module.h deleted file mode 100644 index 0c3207d..0000000 --- a/src/linux/include/linux/module.h +++ /dev/null @@ -1,806 +0,0 @@ -#ifndef _LINUX_MODULE_H -#define _LINUX_MODULE_H -/* - * Dynamic loading of modules into the kernel. - * - * Rewritten by Richard Henderson Dec 1996 - * Rewritten again by Rusty Russell, 2002 - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* only as arch move module.h -> extable.h */ -#include - -#include -#include - -/* In stripped ARM and x86-64 modules, ~ is surprisingly rare. */ -#define MODULE_SIG_STRING "~Module signature appended~\n" - -/* Not Yet Implemented */ -#define MODULE_SUPPORTED_DEVICE(name) - -#define MODULE_NAME_LEN MAX_PARAM_PREFIX_LEN - -struct modversion_info { - unsigned long crc; - char name[MODULE_NAME_LEN]; -}; - -struct module; -struct exception_table_entry; - -struct module_kobject { - struct kobject kobj; - struct module *mod; - struct kobject *drivers_dir; - struct module_param_attrs *mp; - struct completion *kobj_completion; -}; - -struct module_attribute { - struct attribute attr; - ssize_t (*show)(struct module_attribute *, struct module_kobject *, - char *); - ssize_t (*store)(struct module_attribute *, struct module_kobject *, - const char *, size_t count); - void (*setup)(struct module *, const char *); - int (*test)(struct module *); - void (*free)(struct module *); -}; - -struct module_version_attribute { - struct module_attribute mattr; - const char *module_name; - const char *version; -} __attribute__ ((__aligned__(sizeof(void *)))); - -extern ssize_t __modver_version_show(struct module_attribute *, - struct module_kobject *, char *); - -extern struct module_attribute module_uevent; - -/* These are either module local, or the kernel's dummy ones. */ -extern int init_module(void); -extern void cleanup_module(void); - -#ifndef MODULE -/** - * module_init() - driver initialization entry point - * @x: function to be run at kernel boot time or module insertion - * - * module_init() will either be called during do_initcalls() (if - * builtin) or at module insertion time (if a module). There can only - * be one per module. - */ -#define module_init(x) __initcall(x); - -/** - * module_exit() - driver exit entry point - * @x: function to be run when driver is removed - * - * module_exit() will wrap the driver clean-up code - * with cleanup_module() when used with rmmod when - * the driver is a module. If the driver is statically - * compiled into the kernel, module_exit() has no effect. - * There can only be one per module. - */ -#define module_exit(x) __exitcall(x); - -#else /* MODULE */ - -/* - * In most cases loadable modules do not need custom - * initcall levels. There are still some valid cases where - * a driver may be needed early if built in, and does not - * matter when built as a loadable module. Like bus - * snooping debug drivers. - */ -#define early_initcall(fn) module_init(fn) -#define core_initcall(fn) module_init(fn) -#define core_initcall_sync(fn) module_init(fn) -#define postcore_initcall(fn) module_init(fn) -#define postcore_initcall_sync(fn) module_init(fn) -#define arch_initcall(fn) module_init(fn) -#define subsys_initcall(fn) module_init(fn) -#define subsys_initcall_sync(fn) module_init(fn) -#define fs_initcall(fn) module_init(fn) -#define fs_initcall_sync(fn) module_init(fn) -#define rootfs_initcall(fn) module_init(fn) -#define device_initcall(fn) module_init(fn) -#define device_initcall_sync(fn) module_init(fn) -#define late_initcall(fn) module_init(fn) -#define late_initcall_sync(fn) module_init(fn) - -#define console_initcall(fn) module_init(fn) -#define security_initcall(fn) module_init(fn) - -/* Each module must use one module_init(). */ -#define module_init(initfn) \ - static inline initcall_t __inittest(void) \ - { return initfn; } \ - int init_module(void) __attribute__((alias(#initfn))); - -/* This is only required if you want to be unloadable. */ -#define module_exit(exitfn) \ - static inline exitcall_t __exittest(void) \ - { return exitfn; } \ - void cleanup_module(void) __attribute__((alias(#exitfn))); - -#endif - -/* This means "can be init if no module support, otherwise module load - may call it." */ -#ifdef CONFIG_MODULES -#define __init_or_module -#define __initdata_or_module -#define __initconst_or_module -#define __INIT_OR_MODULE .text -#define __INITDATA_OR_MODULE .data -#define __INITRODATA_OR_MODULE .section ".rodata","a",%progbits -#else -#define __init_or_module __init -#define __initdata_or_module __initdata -#define __initconst_or_module __initconst -#define __INIT_OR_MODULE __INIT -#define __INITDATA_OR_MODULE __INITDATA -#define __INITRODATA_OR_MODULE __INITRODATA -#endif /*CONFIG_MODULES*/ - -/* Generic info of form tag = "info" */ -#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info) - -/* For userspace: you can also call me... */ -#define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias) - -/* Soft module dependencies. See man modprobe.d for details. - * Example: MODULE_SOFTDEP("pre: module-foo module-bar post: module-baz") - */ -#define MODULE_SOFTDEP(_softdep) MODULE_INFO(softdep, _softdep) - -/* - * The following license idents are currently accepted as indicating free - * software modules - * - * "GPL" [GNU Public License v2 or later] - * "GPL v2" [GNU Public License v2] - * "GPL and additional rights" [GNU Public License v2 rights and more] - * "Dual BSD/GPL" [GNU Public License v2 - * or BSD license choice] - * "Dual MIT/GPL" [GNU Public License v2 - * or MIT license choice] - * "Dual MPL/GPL" [GNU Public License v2 - * or Mozilla license choice] - * - * The following other idents are available - * - * "Proprietary" [Non free products] - * - * There are dual licensed components, but when running with Linux it is the - * GPL that is relevant so this is a non issue. Similarly LGPL linked with GPL - * is a GPL combined work. - * - * This exists for several reasons - * 1. So modinfo can show license info for users wanting to vet their setup - * is free - * 2. So the community can ignore bug reports including proprietary modules - * 3. So vendors can do likewise based on their own policies - */ -#define MODULE_LICENSE(_license) MODULE_INFO(license, _license) - -/* - * Author(s), use "Name " or just "Name", for multiple - * authors use multiple MODULE_AUTHOR() statements/lines. - */ -#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author) - -/* What your module does. */ -#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description) - -#ifdef MODULE -/* Creates an alias so file2alias.c can find device table. */ -#define MODULE_DEVICE_TABLE(type, name) \ -extern const typeof(name) __mod_##type##__##name##_device_table \ - __attribute__ ((unused, alias(__stringify(name)))) -#else /* !MODULE */ -#define MODULE_DEVICE_TABLE(type, name) -#endif - -/* Version of form [:][-]. - * Or for CVS/RCS ID version, everything but the number is stripped. - * : A (small) unsigned integer which allows you to start versions - * anew. If not mentioned, it's zero. eg. "2:1.0" is after - * "1:2.0". - - * : The may contain only alphanumerics and the - * character `.'. Ordered by numeric sort for numeric parts, - * ascii sort for ascii parts (as per RPM or DEB algorithm). - - * : Like , but inserted for local - * customizations, eg "rh3" or "rusty1". - - * Using this automatically adds a checksum of the .c files and the - * local headers in "srcversion". - */ - -#if defined(MODULE) || !defined(CONFIG_SYSFS) -#define MODULE_VERSION(_version) MODULE_INFO(version, _version) -#else -#define MODULE_VERSION(_version) \ - static struct module_version_attribute ___modver_attr = { \ - .mattr = { \ - .attr = { \ - .name = "version", \ - .mode = S_IRUGO, \ - }, \ - .show = __modver_version_show, \ - }, \ - .module_name = KBUILD_MODNAME, \ - .version = _version, \ - }; \ - static const struct module_version_attribute \ - __used __attribute__ ((__section__ ("__modver"))) \ - * __moduleparam_const __modver_attr = &___modver_attr -#endif - -/* Optional firmware file (or files) needed by the module - * format is simply firmware file name. Multiple firmware - * files require multiple MODULE_FIRMWARE() specifiers */ -#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware) - -struct notifier_block; - -#ifdef CONFIG_MODULES - -extern int modules_disabled; /* for sysctl */ -/* Get/put a kernel symbol (calls must be symmetric) */ -void *__symbol_get(const char *symbol); -void *__symbol_get_gpl(const char *symbol); -#define symbol_get(x) ((typeof(&x))(__symbol_get(VMLINUX_SYMBOL_STR(x)))) - -/* modules using other modules: kdb wants to see this. */ -struct module_use { - struct list_head source_list; - struct list_head target_list; - struct module *source, *target; -}; - -enum module_state { - MODULE_STATE_LIVE, /* Normal state. */ - MODULE_STATE_COMING, /* Full formed, running module_init. */ - MODULE_STATE_GOING, /* Going away. */ - MODULE_STATE_UNFORMED, /* Still setting it up. */ -}; - -struct module; - -struct mod_tree_node { - struct module *mod; - struct latch_tree_node node; -}; - -struct module_layout { - /* The actual code + data. */ - void *base; - /* Total size. */ - unsigned int size; - /* The size of the executable code. */ - unsigned int text_size; - /* Size of RO section of the module (text+rodata) */ - unsigned int ro_size; - /* Size of RO after init section */ - unsigned int ro_after_init_size; - -#ifdef CONFIG_MODULES_TREE_LOOKUP - struct mod_tree_node mtn; -#endif -}; - -#ifdef CONFIG_MODULES_TREE_LOOKUP -/* Only touch one cacheline for common rbtree-for-core-layout case. */ -#define __module_layout_align ____cacheline_aligned -#else -#define __module_layout_align -#endif - -struct mod_kallsyms { - Elf_Sym *symtab; - unsigned int num_symtab; - char *strtab; -}; - -#ifdef CONFIG_LIVEPATCH -struct klp_modinfo { - Elf_Ehdr hdr; - Elf_Shdr *sechdrs; - char *secstrings; - unsigned int symndx; -}; -#endif - -struct module { - enum module_state state; - - /* Member of list of modules */ - struct list_head list; - - /* Unique handle for this module */ - char name[MODULE_NAME_LEN]; - - /* Sysfs stuff. */ - struct module_kobject mkobj; - struct module_attribute *modinfo_attrs; - const char *version; - const char *srcversion; - struct kobject *holders_dir; - - /* Exported symbols */ - const struct kernel_symbol *syms; - const unsigned long *crcs; - unsigned int num_syms; - - /* Kernel parameters. */ -#ifdef CONFIG_SYSFS - struct mutex param_lock; -#endif - struct kernel_param *kp; - unsigned int num_kp; - - /* GPL-only exported symbols. */ - unsigned int num_gpl_syms; - const struct kernel_symbol *gpl_syms; - const unsigned long *gpl_crcs; - -#ifdef CONFIG_UNUSED_SYMBOLS - /* unused exported symbols. */ - const struct kernel_symbol *unused_syms; - const unsigned long *unused_crcs; - unsigned int num_unused_syms; - - /* GPL-only, unused exported symbols. */ - unsigned int num_unused_gpl_syms; - const struct kernel_symbol *unused_gpl_syms; - const unsigned long *unused_gpl_crcs; -#endif - -#ifdef CONFIG_MODULE_SIG - /* Signature was verified. */ - bool sig_ok; -#endif - - bool async_probe_requested; - - /* symbols that will be GPL-only in the near future. */ - const struct kernel_symbol *gpl_future_syms; - const unsigned long *gpl_future_crcs; - unsigned int num_gpl_future_syms; - - /* Exception table */ - unsigned int num_exentries; - struct exception_table_entry *extable; - - /* Startup function. */ - int (*init)(void); - - /* Core layout: rbtree is accessed frequently, so keep together. */ - struct module_layout core_layout __module_layout_align; - struct module_layout init_layout; - - /* Arch-specific module values */ - struct mod_arch_specific arch; - - unsigned int taints; /* same bits as kernel:tainted */ - -#ifdef CONFIG_GENERIC_BUG - /* Support for BUG */ - unsigned num_bugs; - struct list_head bug_list; - struct bug_entry *bug_table; -#endif - -#ifdef CONFIG_KALLSYMS - /* Protected by RCU and/or module_mutex: use rcu_dereference() */ - struct mod_kallsyms *kallsyms; - struct mod_kallsyms core_kallsyms; - - /* Section attributes */ - struct module_sect_attrs *sect_attrs; - - /* Notes attributes */ - struct module_notes_attrs *notes_attrs; -#endif - - /* The command line arguments (may be mangled). People like - keeping pointers to this stuff */ - char *args; - -#ifdef CONFIG_SMP - /* Per-cpu data. */ - void __percpu *percpu; - unsigned int percpu_size; -#endif - -#ifdef CONFIG_TRACEPOINTS - unsigned int num_tracepoints; - struct tracepoint * const *tracepoints_ptrs; -#endif -#ifdef HAVE_JUMP_LABEL - struct jump_entry *jump_entries; - unsigned int num_jump_entries; -#endif -#ifdef CONFIG_TRACING - unsigned int num_trace_bprintk_fmt; - const char **trace_bprintk_fmt_start; -#endif -#ifdef CONFIG_EVENT_TRACING - struct trace_event_call **trace_events; - unsigned int num_trace_events; - struct trace_enum_map **trace_enums; - unsigned int num_trace_enums; -#endif -#ifdef CONFIG_FTRACE_MCOUNT_RECORD - unsigned int num_ftrace_callsites; - unsigned long *ftrace_callsites; -#endif - -#ifdef CONFIG_LIVEPATCH - bool klp; /* Is this a livepatch module? */ - bool klp_alive; - - /* Elf information */ - struct klp_modinfo *klp_info; -#endif - -#ifdef CONFIG_MODULE_UNLOAD - /* What modules depend on me? */ - struct list_head source_list; - /* What modules do I depend on? */ - struct list_head target_list; - - /* Destruction function. */ - void (*exit)(void); - - atomic_t refcnt; -#endif - -#ifdef CONFIG_CONSTRUCTORS - /* Constructor functions. */ - ctor_fn_t *ctors; - unsigned int num_ctors; -#endif -} ____cacheline_aligned; -#ifndef MODULE_ARCH_INIT -#define MODULE_ARCH_INIT {} -#endif - -extern struct mutex module_mutex; - -/* FIXME: It'd be nice to isolate modules during init, too, so they - aren't used before they (may) fail. But presently too much code - (IDE & SCSI) require entry into the module during init.*/ -static inline int module_is_live(struct module *mod) -{ - return mod->state != MODULE_STATE_GOING; -} - -struct module *__module_text_address(unsigned long addr); -struct module *__module_address(unsigned long addr); -bool is_module_address(unsigned long addr); -bool is_module_percpu_address(unsigned long addr); -bool is_module_text_address(unsigned long addr); - -static inline bool within_module_core(unsigned long addr, - const struct module *mod) -{ - return (unsigned long)mod->core_layout.base <= addr && - addr < (unsigned long)mod->core_layout.base + mod->core_layout.size; -} - -static inline bool within_module_init(unsigned long addr, - const struct module *mod) -{ - return (unsigned long)mod->init_layout.base <= addr && - addr < (unsigned long)mod->init_layout.base + mod->init_layout.size; -} - -static inline bool within_module(unsigned long addr, const struct module *mod) -{ - return within_module_init(addr, mod) || within_module_core(addr, mod); -} - -/* Search for module by name: must hold module_mutex. */ -struct module *find_module(const char *name); - -struct symsearch { - const struct kernel_symbol *start, *stop; - const unsigned long *crcs; - enum { - NOT_GPL_ONLY, - GPL_ONLY, - WILL_BE_GPL_ONLY, - } licence; - bool unused; -}; - -/* - * Search for an exported symbol by name. - * - * Must be called with module_mutex held or preemption disabled. - */ -const struct kernel_symbol *find_symbol(const char *name, - struct module **owner, - const unsigned long **crc, - bool gplok, - bool warn); - -/* - * Walk the exported symbol table - * - * Must be called with module_mutex held or preemption disabled. - */ -bool each_symbol_section(bool (*fn)(const struct symsearch *arr, - struct module *owner, - void *data), void *data); - -/* Returns 0 and fills in value, defined and namebuf, or -ERANGE if - symnum out of range. */ -int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type, - char *name, char *module_name, int *exported); - -/* Look for this name: can be of form module:name. */ -unsigned long module_kallsyms_lookup_name(const char *name); - -int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, - struct module *, unsigned long), - void *data); - -extern void __noreturn __module_put_and_exit(struct module *mod, - long code); -#define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code) - -#ifdef CONFIG_MODULE_UNLOAD -int module_refcount(struct module *mod); -void __symbol_put(const char *symbol); -#define symbol_put(x) __symbol_put(VMLINUX_SYMBOL_STR(x)) -void symbol_put_addr(void *addr); - -/* Sometimes we know we already have a refcount, and it's easier not - to handle the error case (which only happens with rmmod --wait). */ -extern void __module_get(struct module *module); - -/* This is the Right Way to get a module: if it fails, it's being removed, - * so pretend it's not there. */ -extern bool try_module_get(struct module *module); - -extern void module_put(struct module *module); - -#else /*!CONFIG_MODULE_UNLOAD*/ -static inline int try_module_get(struct module *module) -{ - return !module || module_is_live(module); -} -static inline void module_put(struct module *module) -{ -} -static inline void __module_get(struct module *module) -{ -} -#define symbol_put(x) do { } while (0) -#define symbol_put_addr(p) do { } while (0) - -#endif /* CONFIG_MODULE_UNLOAD */ -int ref_module(struct module *a, struct module *b); - -/* This is a #define so the string doesn't get put in every .o file */ -#define module_name(mod) \ -({ \ - struct module *__mod = (mod); \ - __mod ? __mod->name : "kernel"; \ -}) - -/* For kallsyms to ask for address resolution. namebuf should be at - * least KSYM_NAME_LEN long: a pointer to namebuf is returned if - * found, otherwise NULL. */ -const char *module_address_lookup(unsigned long addr, - unsigned long *symbolsize, - unsigned long *offset, - char **modname, - char *namebuf); -int lookup_module_symbol_name(unsigned long addr, char *symname); -int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name); - -int register_module_notifier(struct notifier_block *nb); -int unregister_module_notifier(struct notifier_block *nb); - -extern void print_modules(void); - -static inline bool module_requested_async_probing(struct module *module) -{ - return module && module->async_probe_requested; -} - -#ifdef CONFIG_LIVEPATCH -static inline bool is_livepatch_module(struct module *mod) -{ - return mod->klp; -} -#else /* !CONFIG_LIVEPATCH */ -static inline bool is_livepatch_module(struct module *mod) -{ - return false; -} -#endif /* CONFIG_LIVEPATCH */ - -#else /* !CONFIG_MODULES... */ - -static inline struct module *__module_address(unsigned long addr) -{ - return NULL; -} - -static inline struct module *__module_text_address(unsigned long addr) -{ - return NULL; -} - -static inline bool is_module_address(unsigned long addr) -{ - return false; -} - -static inline bool is_module_percpu_address(unsigned long addr) -{ - return false; -} - -static inline bool is_module_text_address(unsigned long addr) -{ - return false; -} - -/* Get/put a kernel symbol (calls should be symmetric) */ -#define symbol_get(x) ({ extern typeof(x) x __attribute__((weak)); &(x); }) -#define symbol_put(x) do { } while (0) -#define symbol_put_addr(x) do { } while (0) - -static inline void __module_get(struct module *module) -{ -} - -static inline int try_module_get(struct module *module) -{ - return 1; -} - -static inline void module_put(struct module *module) -{ -} - -#define module_name(mod) "kernel" - -/* For kallsyms to ask for address resolution. NULL means not found. */ -static inline const char *module_address_lookup(unsigned long addr, - unsigned long *symbolsize, - unsigned long *offset, - char **modname, - char *namebuf) -{ - return NULL; -} - -static inline int lookup_module_symbol_name(unsigned long addr, char *symname) -{ - return -ERANGE; -} - -static inline int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name) -{ - return -ERANGE; -} - -static inline int module_get_kallsym(unsigned int symnum, unsigned long *value, - char *type, char *name, - char *module_name, int *exported) -{ - return -ERANGE; -} - -static inline unsigned long module_kallsyms_lookup_name(const char *name) -{ - return 0; -} - -static inline int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, - struct module *, - unsigned long), - void *data) -{ - return 0; -} - -static inline int register_module_notifier(struct notifier_block *nb) -{ - /* no events will happen anyway, so this can always succeed */ - return 0; -} - -static inline int unregister_module_notifier(struct notifier_block *nb) -{ - return 0; -} - -#define module_put_and_exit(code) do_exit(code) - -static inline void print_modules(void) -{ -} - -static inline bool module_requested_async_probing(struct module *module) -{ - return false; -} - -#endif /* CONFIG_MODULES */ - -#ifdef CONFIG_SYSFS -extern struct kset *module_kset; -extern struct kobj_type module_ktype; -extern int module_sysfs_initialized; -#endif /* CONFIG_SYSFS */ - -#define symbol_request(x) try_then_request_module(symbol_get(x), "symbol:" #x) - -/* BELOW HERE ALL THESE ARE OBSOLETE AND WILL VANISH */ - -#define __MODULE_STRING(x) __stringify(x) - -#ifdef CONFIG_DEBUG_SET_MODULE_RONX -extern void set_all_modules_text_rw(void); -extern void set_all_modules_text_ro(void); -extern void module_enable_ro(const struct module *mod, bool after_init); -extern void module_disable_ro(const struct module *mod); -#else -static inline void set_all_modules_text_rw(void) { } -static inline void set_all_modules_text_ro(void) { } -static inline void module_enable_ro(const struct module *mod, bool after_init) { } -static inline void module_disable_ro(const struct module *mod) { } -#endif - -#ifdef CONFIG_GENERIC_BUG -void module_bug_finalize(const Elf_Ehdr *, const Elf_Shdr *, - struct module *); -void module_bug_cleanup(struct module *); - -#else /* !CONFIG_GENERIC_BUG */ - -static inline void module_bug_finalize(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - struct module *mod) -{ -} -static inline void module_bug_cleanup(struct module *mod) {} -#endif /* CONFIG_GENERIC_BUG */ - -#ifdef CONFIG_MODULE_SIG -static inline bool module_sig_ok(struct module *module) -{ - return module->sig_ok; -} -#else /* !CONFIG_MODULE_SIG */ -static inline bool module_sig_ok(struct module *module) -{ - return true; -} -#endif /* CONFIG_MODULE_SIG */ - -#endif /* _LINUX_MODULE_H */ diff --git a/src/linux/include/linux/moduleloader.h b/src/linux/include/linux/moduleloader.h deleted file mode 100644 index 4d0cb9b..0000000 --- a/src/linux/include/linux/moduleloader.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef _LINUX_MODULELOADER_H -#define _LINUX_MODULELOADER_H -/* The stuff needed for archs to support modules. */ - -#include -#include - -/* These may be implemented by architectures that need to hook into the - * module loader code. Architectures that don't need to do anything special - * can just rely on the 'weak' default hooks defined in kernel/module.c. - * Note, however, that at least one of apply_relocate or apply_relocate_add - * must be implemented by each architecture. - */ - -/* Adjust arch-specific sections. Return 0 on success. */ -int module_frob_arch_sections(Elf_Ehdr *hdr, - Elf_Shdr *sechdrs, - char *secstrings, - struct module *mod); - -/* Additional bytes needed by arch in front of individual sections */ -unsigned int arch_mod_section_prepend(struct module *mod, unsigned int section); - -/* Allocator used for allocating struct module, core sections and init - sections. Returns NULL on failure. */ -void *module_alloc(unsigned long size); - -/* Free memory returned from module_alloc. */ -void module_memfree(void *module_region); - -/* - * Apply the given relocation to the (simplified) ELF. Return -error - * or 0. - */ -#ifdef CONFIG_MODULES_USE_ELF_REL -int apply_relocate(Elf_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *mod); -#else -static inline int apply_relocate(Elf_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - printk(KERN_ERR "module %s: REL relocation unsupported\n", - module_name(me)); - return -ENOEXEC; -} -#endif - -/* - * Apply the given add relocation to the (simplified) ELF. Return - * -error or 0 - */ -#ifdef CONFIG_MODULES_USE_ELF_RELA -int apply_relocate_add(Elf_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *mod); -#else -static inline int apply_relocate_add(Elf_Shdr *sechdrs, - const char *strtab, - unsigned int symindex, - unsigned int relsec, - struct module *me) -{ - printk(KERN_ERR "module %s: REL relocation unsupported\n", - module_name(me)); - return -ENOEXEC; -} -#endif - -/* Any final processing of module before access. Return -error or 0. */ -int module_finalize(const Elf_Ehdr *hdr, - const Elf_Shdr *sechdrs, - struct module *mod); - -/* Any cleanup needed when module leaves. */ -void module_arch_cleanup(struct module *mod); - -/* Any cleanup before freeing mod->module_init */ -void module_arch_freeing_init(struct module *mod); - -#ifdef CONFIG_KASAN -#include -#define MODULE_ALIGN (PAGE_SIZE << KASAN_SHADOW_SCALE_SHIFT) -#else -#define MODULE_ALIGN PAGE_SIZE -#endif - -#endif diff --git a/src/linux/include/linux/moduleparam.h b/src/linux/include/linux/moduleparam.h deleted file mode 100644 index 52666d9..0000000 --- a/src/linux/include/linux/moduleparam.h +++ /dev/null @@ -1,482 +0,0 @@ -#ifndef _LINUX_MODULE_PARAMS_H -#define _LINUX_MODULE_PARAMS_H -/* (C) Copyright 2001, 2002 Rusty Russell IBM Corporation */ -#include -#include -#include - -/* You can override this manually, but generally this should match the - module name. */ -#ifdef MODULE -#define MODULE_PARAM_PREFIX /* empty */ -#else -#define MODULE_PARAM_PREFIX KBUILD_MODNAME "." -#endif - -/* Chosen so that structs with an unsigned long line up. */ -#define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long)) - -#ifdef MODULE -#define __MODULE_INFO(tag, name, info) \ -static const char __UNIQUE_ID(name)[] \ - __used __attribute__((section(".modinfo"), unused, aligned(1))) \ - = __stringify(tag) "=" info -#else /* !MODULE */ -/* This struct is here for syntactic coherency, it is not used */ -#define __MODULE_INFO(tag, name, info) \ - struct __UNIQUE_ID(name) {} -#endif -#define __MODULE_PARM_TYPE(name, _type) \ - __MODULE_INFO(parmtype, name##type, #name ":" _type) - -/* One for each parameter, describing how to use it. Some files do - multiple of these per line, so can't just use MODULE_INFO. */ -#define MODULE_PARM_DESC(_parm, desc) \ - __MODULE_INFO(parm, _parm, #_parm ":" desc) - -struct kernel_param; - -/* - * Flags available for kernel_param_ops - * - * NOARG - the parameter allows for no argument (foo instead of foo=1) - */ -enum { - KERNEL_PARAM_OPS_FL_NOARG = (1 << 0) -}; - -struct kernel_param_ops { - /* How the ops should behave */ - unsigned int flags; - /* Returns 0, or -errno. arg is in kp->arg. */ - int (*set)(const char *val, const struct kernel_param *kp); - /* Returns length written or -errno. Buffer is 4k (ie. be short!) */ - int (*get)(char *buffer, const struct kernel_param *kp); - /* Optional function to free kp->arg when module unloaded. */ - void (*free)(void *arg); -}; - -/* - * Flags available for kernel_param - * - * UNSAFE - the parameter is dangerous and setting it will taint the kernel - */ -enum { - KERNEL_PARAM_FL_UNSAFE = (1 << 0) -}; - -struct kernel_param { - const char *name; - struct module *mod; - const struct kernel_param_ops *ops; - const u16 perm; - s8 level; - u8 flags; - union { - void *arg; - const struct kparam_string *str; - const struct kparam_array *arr; - }; -}; - -extern const struct kernel_param __start___param[], __stop___param[]; - -/* Special one for strings we want to copy into */ -struct kparam_string { - unsigned int maxlen; - char *string; -}; - -/* Special one for arrays */ -struct kparam_array -{ - unsigned int max; - unsigned int elemsize; - unsigned int *num; - const struct kernel_param_ops *ops; - void *elem; -}; - -/** - * module_param - typesafe helper for a module/cmdline parameter - * @value: the variable to alter, and exposed parameter name. - * @type: the type of the parameter - * @perm: visibility in sysfs. - * - * @value becomes the module parameter, or (prefixed by KBUILD_MODNAME and a - * ".") the kernel commandline parameter. Note that - is changed to _, so - * the user can use "foo-bar=1" even for variable "foo_bar". - * - * @perm is 0 if the the variable is not to appear in sysfs, or 0444 - * for world-readable, 0644 for root-writable, etc. Note that if it - * is writable, you may need to use kernel_param_lock() around - * accesses (esp. charp, which can be kfreed when it changes). - * - * The @type is simply pasted to refer to a param_ops_##type and a - * param_check_##type: for convenience many standard types are provided but - * you can create your own by defining those variables. - * - * Standard types are: - * byte, short, ushort, int, uint, long, ulong - * charp: a character pointer - * bool: a bool, values 0/1, y/n, Y/N. - * invbool: the above, only sense-reversed (N = true). - */ -#define module_param(name, type, perm) \ - module_param_named(name, name, type, perm) - -/** - * module_param_unsafe - same as module_param but taints kernel - */ -#define module_param_unsafe(name, type, perm) \ - module_param_named_unsafe(name, name, type, perm) - -/** - * module_param_named - typesafe helper for a renamed module/cmdline parameter - * @name: a valid C identifier which is the parameter name. - * @value: the actual lvalue to alter. - * @type: the type of the parameter - * @perm: visibility in sysfs. - * - * Usually it's a good idea to have variable names and user-exposed names the - * same, but that's harder if the variable must be non-static or is inside a - * structure. This allows exposure under a different name. - */ -#define module_param_named(name, value, type, perm) \ - param_check_##type(name, &(value)); \ - module_param_cb(name, ¶m_ops_##type, &value, perm); \ - __MODULE_PARM_TYPE(name, #type) - -/** - * module_param_named_unsafe - same as module_param_named but taints kernel - */ -#define module_param_named_unsafe(name, value, type, perm) \ - param_check_##type(name, &(value)); \ - module_param_cb_unsafe(name, ¶m_ops_##type, &value, perm); \ - __MODULE_PARM_TYPE(name, #type) - -/** - * module_param_cb - general callback for a module/cmdline parameter - * @name: a valid C identifier which is the parameter name. - * @ops: the set & get operations for this parameter. - * @perm: visibility in sysfs. - * - * The ops can have NULL set or get functions. - */ -#define module_param_cb(name, ops, arg, perm) \ - __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, -1, 0) - -#define module_param_cb_unsafe(name, ops, arg, perm) \ - __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, -1, \ - KERNEL_PARAM_FL_UNSAFE) - -/** - * _param_cb - general callback for a module/cmdline parameter - * to be evaluated before certain initcall level - * @name: a valid C identifier which is the parameter name. - * @ops: the set & get operations for this parameter. - * @perm: visibility in sysfs. - * - * The ops can have NULL set or get functions. - */ -#define __level_param_cb(name, ops, arg, perm, level) \ - __module_param_call(MODULE_PARAM_PREFIX, name, ops, arg, perm, level, 0) - -#define core_param_cb(name, ops, arg, perm) \ - __level_param_cb(name, ops, arg, perm, 1) - -#define postcore_param_cb(name, ops, arg, perm) \ - __level_param_cb(name, ops, arg, perm, 2) - -#define arch_param_cb(name, ops, arg, perm) \ - __level_param_cb(name, ops, arg, perm, 3) - -#define subsys_param_cb(name, ops, arg, perm) \ - __level_param_cb(name, ops, arg, perm, 4) - -#define fs_param_cb(name, ops, arg, perm) \ - __level_param_cb(name, ops, arg, perm, 5) - -#define device_param_cb(name, ops, arg, perm) \ - __level_param_cb(name, ops, arg, perm, 6) - -#define late_param_cb(name, ops, arg, perm) \ - __level_param_cb(name, ops, arg, perm, 7) - -/* On alpha, ia64 and ppc64 relocations to global data cannot go into - read-only sections (which is part of respective UNIX ABI on these - platforms). So 'const' makes no sense and even causes compile failures - with some compilers. */ -#if defined(CONFIG_ALPHA) || defined(CONFIG_IA64) || defined(CONFIG_PPC64) -#define __moduleparam_const -#else -#define __moduleparam_const const -#endif - -/* This is the fundamental function for registering boot/module - parameters. */ -#define __module_param_call(prefix, name, ops, arg, perm, level, flags) \ - /* Default value instead of permissions? */ \ - static const char __param_str_##name[] = prefix #name; \ - static struct kernel_param __moduleparam_const __param_##name \ - __used \ - __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \ - = { __param_str_##name, THIS_MODULE, ops, \ - VERIFY_OCTAL_PERMISSIONS(perm), level, flags, { arg } } - -/* Obsolete - use module_param_cb() */ -#define module_param_call(name, set, get, arg, perm) \ - static const struct kernel_param_ops __param_ops_##name = \ - { .flags = 0, (void *)set, (void *)get }; \ - __module_param_call(MODULE_PARAM_PREFIX, \ - name, &__param_ops_##name, arg, \ - (perm) + sizeof(__check_old_set_param(set))*0, -1, 0) - -/* We don't get oldget: it's often a new-style param_get_uint, etc. */ -static inline int -__check_old_set_param(int (*oldset)(const char *, struct kernel_param *)) -{ - return 0; -} - -#ifdef CONFIG_SYSFS -extern void kernel_param_lock(struct module *mod); -extern void kernel_param_unlock(struct module *mod); -#else -static inline void kernel_param_lock(struct module *mod) -{ -} -static inline void kernel_param_unlock(struct module *mod) -{ -} -#endif - -#ifndef MODULE -/** - * core_param - define a historical core kernel parameter. - * @name: the name of the cmdline and sysfs parameter (often the same as var) - * @var: the variable - * @type: the type of the parameter - * @perm: visibility in sysfs - * - * core_param is just like module_param(), but cannot be modular and - * doesn't add a prefix (such as "printk."). This is for compatibility - * with __setup(), and it makes sense as truly core parameters aren't - * tied to the particular file they're in. - */ -#define core_param(name, var, type, perm) \ - param_check_##type(name, &(var)); \ - __module_param_call("", name, ¶m_ops_##type, &var, perm, -1, 0) - -/** - * core_param_unsafe - same as core_param but taints kernel - */ -#define core_param_unsafe(name, var, type, perm) \ - param_check_##type(name, &(var)); \ - __module_param_call("", name, ¶m_ops_##type, &var, perm, \ - -1, KERNEL_PARAM_FL_UNSAFE) - -#endif /* !MODULE */ - -/** - * module_param_string - a char array parameter - * @name: the name of the parameter - * @string: the string variable - * @len: the maximum length of the string, incl. terminator - * @perm: visibility in sysfs. - * - * This actually copies the string when it's set (unlike type charp). - * @len is usually just sizeof(string). - */ -#define module_param_string(name, string, len, perm) \ - static const struct kparam_string __param_string_##name \ - = { len, string }; \ - __module_param_call(MODULE_PARAM_PREFIX, name, \ - ¶m_ops_string, \ - .str = &__param_string_##name, perm, -1, 0);\ - __MODULE_PARM_TYPE(name, "string") - -/** - * parameq - checks if two parameter names match - * @name1: parameter name 1 - * @name2: parameter name 2 - * - * Returns true if the two parameter names are equal. - * Dashes (-) are considered equal to underscores (_). - */ -extern bool parameq(const char *name1, const char *name2); - -/** - * parameqn - checks if two parameter names match - * @name1: parameter name 1 - * @name2: parameter name 2 - * @n: the length to compare - * - * Similar to parameq(), except it compares @n characters. - */ -extern bool parameqn(const char *name1, const char *name2, size_t n); - -/* Called on module insert or kernel boot */ -extern char *parse_args(const char *name, - char *args, - const struct kernel_param *params, - unsigned num, - s16 level_min, - s16 level_max, - void *arg, - int (*unknown)(char *param, char *val, - const char *doing, void *arg)); - -/* Called by module remove. */ -#ifdef CONFIG_SYSFS -extern void destroy_params(const struct kernel_param *params, unsigned num); -#else -static inline void destroy_params(const struct kernel_param *params, - unsigned num) -{ -} -#endif /* !CONFIG_SYSFS */ - -/* All the helper functions */ -/* The macros to do compile-time type checking stolen from Jakub - Jelinek, who IIRC came up with this idea for the 2.4 module init code. */ -#define __param_check(name, p, type) \ - static inline type __always_unused *__check_##name(void) { return(p); } - -extern const struct kernel_param_ops param_ops_byte; -extern int param_set_byte(const char *val, const struct kernel_param *kp); -extern int param_get_byte(char *buffer, const struct kernel_param *kp); -#define param_check_byte(name, p) __param_check(name, p, unsigned char) - -extern const struct kernel_param_ops param_ops_short; -extern int param_set_short(const char *val, const struct kernel_param *kp); -extern int param_get_short(char *buffer, const struct kernel_param *kp); -#define param_check_short(name, p) __param_check(name, p, short) - -extern const struct kernel_param_ops param_ops_ushort; -extern int param_set_ushort(const char *val, const struct kernel_param *kp); -extern int param_get_ushort(char *buffer, const struct kernel_param *kp); -#define param_check_ushort(name, p) __param_check(name, p, unsigned short) - -extern const struct kernel_param_ops param_ops_int; -extern int param_set_int(const char *val, const struct kernel_param *kp); -extern int param_get_int(char *buffer, const struct kernel_param *kp); -#define param_check_int(name, p) __param_check(name, p, int) - -extern const struct kernel_param_ops param_ops_uint; -extern int param_set_uint(const char *val, const struct kernel_param *kp); -extern int param_get_uint(char *buffer, const struct kernel_param *kp); -#define param_check_uint(name, p) __param_check(name, p, unsigned int) - -extern const struct kernel_param_ops param_ops_long; -extern int param_set_long(const char *val, const struct kernel_param *kp); -extern int param_get_long(char *buffer, const struct kernel_param *kp); -#define param_check_long(name, p) __param_check(name, p, long) - -extern const struct kernel_param_ops param_ops_ulong; -extern int param_set_ulong(const char *val, const struct kernel_param *kp); -extern int param_get_ulong(char *buffer, const struct kernel_param *kp); -#define param_check_ulong(name, p) __param_check(name, p, unsigned long) - -extern const struct kernel_param_ops param_ops_ullong; -extern int param_set_ullong(const char *val, const struct kernel_param *kp); -extern int param_get_ullong(char *buffer, const struct kernel_param *kp); -#define param_check_ullong(name, p) __param_check(name, p, unsigned long long) - -extern const struct kernel_param_ops param_ops_charp; -extern int param_set_charp(const char *val, const struct kernel_param *kp); -extern int param_get_charp(char *buffer, const struct kernel_param *kp); -extern void param_free_charp(void *arg); -#define param_check_charp(name, p) __param_check(name, p, char *) - -/* We used to allow int as well as bool. We're taking that away! */ -extern const struct kernel_param_ops param_ops_bool; -extern int param_set_bool(const char *val, const struct kernel_param *kp); -extern int param_get_bool(char *buffer, const struct kernel_param *kp); -#define param_check_bool(name, p) __param_check(name, p, bool) - -extern const struct kernel_param_ops param_ops_bool_enable_only; -extern int param_set_bool_enable_only(const char *val, - const struct kernel_param *kp); -/* getter is the same as for the regular bool */ -#define param_check_bool_enable_only param_check_bool - -extern const struct kernel_param_ops param_ops_invbool; -extern int param_set_invbool(const char *val, const struct kernel_param *kp); -extern int param_get_invbool(char *buffer, const struct kernel_param *kp); -#define param_check_invbool(name, p) __param_check(name, p, bool) - -/* An int, which can only be set like a bool (though it shows as an int). */ -extern const struct kernel_param_ops param_ops_bint; -extern int param_set_bint(const char *val, const struct kernel_param *kp); -#define param_get_bint param_get_int -#define param_check_bint param_check_int - -/** - * module_param_array - a parameter which is an array of some type - * @name: the name of the array variable - * @type: the type, as per module_param() - * @nump: optional pointer filled in with the number written - * @perm: visibility in sysfs - * - * Input and output are as comma-separated values. Commas inside values - * don't work properly (eg. an array of charp). - * - * ARRAY_SIZE(@name) is used to determine the number of elements in the - * array, so the definition must be visible. - */ -#define module_param_array(name, type, nump, perm) \ - module_param_array_named(name, name, type, nump, perm) - -/** - * module_param_array_named - renamed parameter which is an array of some type - * @name: a valid C identifier which is the parameter name - * @array: the name of the array variable - * @type: the type, as per module_param() - * @nump: optional pointer filled in with the number written - * @perm: visibility in sysfs - * - * This exposes a different name than the actual variable name. See - * module_param_named() for why this might be necessary. - */ -#define module_param_array_named(name, array, type, nump, perm) \ - param_check_##type(name, &(array)[0]); \ - static const struct kparam_array __param_arr_##name \ - = { .max = ARRAY_SIZE(array), .num = nump, \ - .ops = ¶m_ops_##type, \ - .elemsize = sizeof(array[0]), .elem = array }; \ - __module_param_call(MODULE_PARAM_PREFIX, name, \ - ¶m_array_ops, \ - .arr = &__param_arr_##name, \ - perm, -1, 0); \ - __MODULE_PARM_TYPE(name, "array of " #type) - -extern const struct kernel_param_ops param_array_ops; - -extern const struct kernel_param_ops param_ops_string; -extern int param_set_copystring(const char *val, const struct kernel_param *); -extern int param_get_string(char *buffer, const struct kernel_param *kp); - -/* for exporting parameters in /sys/module/.../parameters */ - -struct module; - -#if defined(CONFIG_SYSFS) && defined(CONFIG_MODULES) -extern int module_param_sysfs_setup(struct module *mod, - const struct kernel_param *kparam, - unsigned int num_params); - -extern void module_param_sysfs_remove(struct module *mod); -#else -static inline int module_param_sysfs_setup(struct module *mod, - const struct kernel_param *kparam, - unsigned int num_params) -{ - return 0; -} - -static inline void module_param_sysfs_remove(struct module *mod) -{ } -#endif - -#endif /* _LINUX_MODULE_PARAMS_H */ diff --git a/src/linux/include/linux/mount.h b/src/linux/include/linux/mount.h deleted file mode 100644 index 1172cce..0000000 --- a/src/linux/include/linux/mount.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * - * Definitions for mount interface. This describes the in the kernel build - * linkedlist with mounted filesystems. - * - * Author: Marco van Wieringen - * - */ -#ifndef _LINUX_MOUNT_H -#define _LINUX_MOUNT_H - -#include -#include -#include -#include -#include -#include - -struct super_block; -struct vfsmount; -struct dentry; -struct mnt_namespace; - -#define MNT_NOSUID 0x01 -#define MNT_NODEV 0x02 -#define MNT_NOEXEC 0x04 -#define MNT_NOATIME 0x08 -#define MNT_NODIRATIME 0x10 -#define MNT_RELATIME 0x20 -#define MNT_READONLY 0x40 /* does the user want this to be r/o? */ - -#define MNT_SHRINKABLE 0x100 -#define MNT_WRITE_HOLD 0x200 - -#define MNT_SHARED 0x1000 /* if the vfsmount is a shared mount */ -#define MNT_UNBINDABLE 0x2000 /* if the vfsmount is a unbindable mount */ -/* - * MNT_SHARED_MASK is the set of flags that should be cleared when a - * mount becomes shared. Currently, this is only the flag that says a - * mount cannot be bind mounted, since this is how we create a mount - * that shares events with another mount. If you add a new MNT_* - * flag, consider how it interacts with shared mounts. - */ -#define MNT_SHARED_MASK (MNT_UNBINDABLE) -#define MNT_USER_SETTABLE_MASK (MNT_NOSUID | MNT_NODEV | MNT_NOEXEC \ - | MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME \ - | MNT_READONLY) -#define MNT_ATIME_MASK (MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME ) - -#define MNT_INTERNAL_FLAGS (MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL | \ - MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED) - -#define MNT_INTERNAL 0x4000 - -#define MNT_LOCK_ATIME 0x040000 -#define MNT_LOCK_NOEXEC 0x080000 -#define MNT_LOCK_NOSUID 0x100000 -#define MNT_LOCK_NODEV 0x200000 -#define MNT_LOCK_READONLY 0x400000 -#define MNT_LOCKED 0x800000 -#define MNT_DOOMED 0x1000000 -#define MNT_SYNC_UMOUNT 0x2000000 -#define MNT_MARKED 0x4000000 -#define MNT_UMOUNT 0x8000000 - -struct vfsmount { - struct dentry *mnt_root; /* root of the mounted tree */ - struct super_block *mnt_sb; /* pointer to superblock */ - int mnt_flags; -}; - -struct file; /* forward dec */ -struct path; - -extern int mnt_want_write(struct vfsmount *mnt); -extern int mnt_want_write_file(struct file *file); -extern int mnt_clone_write(struct vfsmount *mnt); -extern void mnt_drop_write(struct vfsmount *mnt); -extern void mnt_drop_write_file(struct file *file); -extern void mntput(struct vfsmount *mnt); -extern struct vfsmount *mntget(struct vfsmount *mnt); -extern struct vfsmount *mnt_clone_internal(struct path *path); -extern int __mnt_is_readonly(struct vfsmount *mnt); -extern bool mnt_may_suid(struct vfsmount *mnt); - -struct path; -extern struct vfsmount *clone_private_mount(struct path *path); - -struct file_system_type; -extern struct vfsmount *vfs_kern_mount(struct file_system_type *type, - int flags, const char *name, - void *data); - -extern void mnt_set_expiry(struct vfsmount *mnt, struct list_head *expiry_list); -extern void mark_mounts_for_expiry(struct list_head *mounts); - -extern dev_t name_to_dev_t(const char *name); - -extern unsigned int sysctl_mount_max; - -#endif /* _LINUX_MOUNT_H */ diff --git a/src/linux/include/linux/mpage.h b/src/linux/include/linux/mpage.h deleted file mode 100644 index 068a0c9..0000000 --- a/src/linux/include/linux/mpage.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - * include/linux/mpage.h - * - * Contains declarations related to preparing and submitting BIOS which contain - * multiple pagecache pages. - */ - -/* - * (And no, it doesn't do the #ifdef __MPAGE_H thing, and it doesn't do - * nested includes. Get it right in the .c file). - */ -#ifdef CONFIG_BLOCK - -struct writeback_control; - -int mpage_readpages(struct address_space *mapping, struct list_head *pages, - unsigned nr_pages, get_block_t get_block); -int mpage_readpage(struct page *page, get_block_t get_block); -int mpage_writepages(struct address_space *mapping, - struct writeback_control *wbc, get_block_t get_block); -int mpage_writepage(struct page *page, get_block_t *get_block, - struct writeback_control *wbc); - -#endif diff --git a/src/linux/include/linux/mpls.h b/src/linux/include/linux/mpls.h deleted file mode 100644 index 9999145..0000000 --- a/src/linux/include/linux/mpls.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _LINUX_MPLS_H -#define _LINUX_MPLS_H - -#include - -#endif /* _LINUX_MPLS_H */ diff --git a/src/linux/include/linux/mroute.h b/src/linux/include/linux/mroute.h deleted file mode 100644 index e5fb813..0000000 --- a/src/linux/include/linux/mroute.h +++ /dev/null @@ -1,124 +0,0 @@ -#ifndef __LINUX_MROUTE_H -#define __LINUX_MROUTE_H - -#include -#include -#include -#include - -#ifdef CONFIG_IP_MROUTE -static inline int ip_mroute_opt(int opt) -{ - return opt >= MRT_BASE && opt <= MRT_MAX; -} - -int ip_mroute_setsockopt(struct sock *, int, char __user *, unsigned int); -int ip_mroute_getsockopt(struct sock *, int, char __user *, int __user *); -int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg); -int ipmr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg); -int ip_mr_init(void); -#else -static inline int ip_mroute_setsockopt(struct sock *sock, int optname, - char __user *optval, unsigned int optlen) -{ - return -ENOPROTOOPT; -} - -static inline int ip_mroute_getsockopt(struct sock *sock, int optname, - char __user *optval, int __user *optlen) -{ - return -ENOPROTOOPT; -} - -static inline int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) -{ - return -ENOIOCTLCMD; -} - -static inline int ip_mr_init(void) -{ - return 0; -} - -static inline int ip_mroute_opt(int opt) -{ - return 0; -} -#endif - -struct vif_device { - struct net_device *dev; /* Device we are using */ - unsigned long bytes_in,bytes_out; - unsigned long pkt_in,pkt_out; /* Statistics */ - unsigned long rate_limit; /* Traffic shaping (NI) */ - unsigned char threshold; /* TTL threshold */ - unsigned short flags; /* Control flags */ - __be32 local,remote; /* Addresses(remote for tunnels)*/ - int link; /* Physical interface index */ -}; - -#define VIFF_STATIC 0x8000 - -#define VIF_EXISTS(_mrt, _idx) ((_mrt)->vif_table[_idx].dev != NULL) -#define MFC_LINES 64 - -struct mr_table { - struct list_head list; - possible_net_t net; - u32 id; - struct sock __rcu *mroute_sk; - struct timer_list ipmr_expire_timer; - struct list_head mfc_unres_queue; - struct list_head mfc_cache_array[MFC_LINES]; - struct vif_device vif_table[MAXVIFS]; - int maxvif; - atomic_t cache_resolve_queue_len; - bool mroute_do_assert; - bool mroute_do_pim; - int mroute_reg_vif_num; -}; - -/* mfc_flags: - * MFC_STATIC - the entry was added statically (not by a routing daemon) - */ -enum { - MFC_STATIC = BIT(0), -}; - -struct mfc_cache { - struct list_head list; - __be32 mfc_mcastgrp; /* Group the entry belongs to */ - __be32 mfc_origin; /* Source of packet */ - vifi_t mfc_parent; /* Source interface */ - int mfc_flags; /* Flags on line */ - - union { - struct { - unsigned long expires; - struct sk_buff_head unresolved; /* Unresolved buffers */ - } unres; - struct { - unsigned long last_assert; - int minvif; - int maxvif; - unsigned long bytes; - unsigned long pkt; - unsigned long wrong_if; - unsigned long lastuse; - unsigned char ttls[MAXVIFS]; /* TTL thresholds */ - } res; - } mfc_un; - struct rcu_head rcu; -}; - -#ifdef __BIG_ENDIAN -#define MFC_HASH(a,b) (((((__force u32)(__be32)a)>>24)^(((__force u32)(__be32)b)>>26))&(MFC_LINES-1)) -#else -#define MFC_HASH(a,b) ((((__force u32)(__be32)a)^(((__force u32)(__be32)b)>>2))&(MFC_LINES-1)) -#endif - -struct rtmsg; -int ipmr_get_route(struct net *net, struct sk_buff *skb, - __be32 saddr, __be32 daddr, - struct rtmsg *rtm, int nowait, u32 portid); -#endif diff --git a/src/linux/include/linux/mroute6.h b/src/linux/include/linux/mroute6.h deleted file mode 100644 index 19a1c0c..0000000 --- a/src/linux/include/linux/mroute6.h +++ /dev/null @@ -1,134 +0,0 @@ -#ifndef __LINUX_MROUTE6_H -#define __LINUX_MROUTE6_H - - -#include -#include /* for struct sk_buff_head */ -#include -#include - -#ifdef CONFIG_IPV6_MROUTE -static inline int ip6_mroute_opt(int opt) -{ - return (opt >= MRT6_BASE) && (opt <= MRT6_MAX); -} -#else -static inline int ip6_mroute_opt(int opt) -{ - return 0; -} -#endif - -struct sock; - -#ifdef CONFIG_IPV6_MROUTE -extern int ip6_mroute_setsockopt(struct sock *, int, char __user *, unsigned int); -extern int ip6_mroute_getsockopt(struct sock *, int, char __user *, int __user *); -extern int ip6_mr_input(struct sk_buff *skb); -extern int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg); -extern int ip6mr_compat_ioctl(struct sock *sk, unsigned int cmd, void __user *arg); -extern int ip6_mr_init(void); -extern void ip6_mr_cleanup(void); -#else -static inline -int ip6_mroute_setsockopt(struct sock *sock, - int optname, char __user *optval, unsigned int optlen) -{ - return -ENOPROTOOPT; -} - -static inline -int ip6_mroute_getsockopt(struct sock *sock, - int optname, char __user *optval, int __user *optlen) -{ - return -ENOPROTOOPT; -} - -static inline -int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) -{ - return -ENOIOCTLCMD; -} - -static inline int ip6_mr_init(void) -{ - return 0; -} - -static inline void ip6_mr_cleanup(void) -{ - return; -} -#endif - -struct mif_device { - struct net_device *dev; /* Device we are using */ - unsigned long bytes_in,bytes_out; - unsigned long pkt_in,pkt_out; /* Statistics */ - unsigned long rate_limit; /* Traffic shaping (NI) */ - unsigned char threshold; /* TTL threshold */ - unsigned short flags; /* Control flags */ - int link; /* Physical interface index */ -}; - -#define VIFF_STATIC 0x8000 - -struct mfc6_cache { - struct list_head list; - struct in6_addr mf6c_mcastgrp; /* Group the entry belongs to */ - struct in6_addr mf6c_origin; /* Source of packet */ - mifi_t mf6c_parent; /* Source interface */ - int mfc_flags; /* Flags on line */ - - union { - struct { - unsigned long expires; - struct sk_buff_head unresolved; /* Unresolved buffers */ - } unres; - struct { - unsigned long last_assert; - int minvif; - int maxvif; - unsigned long bytes; - unsigned long pkt; - unsigned long wrong_if; - unsigned long lastuse; - unsigned char ttls[MAXMIFS]; /* TTL thresholds */ - } res; - } mfc_un; -}; - -#define MFC_STATIC 1 -#define MFC_NOTIFY 2 - -#define MFC6_LINES 64 - -#define MFC6_HASH(a, g) (((__force u32)(a)->s6_addr32[0] ^ \ - (__force u32)(a)->s6_addr32[1] ^ \ - (__force u32)(a)->s6_addr32[2] ^ \ - (__force u32)(a)->s6_addr32[3] ^ \ - (__force u32)(g)->s6_addr32[0] ^ \ - (__force u32)(g)->s6_addr32[1] ^ \ - (__force u32)(g)->s6_addr32[2] ^ \ - (__force u32)(g)->s6_addr32[3]) % MFC6_LINES) - -#define MFC_ASSERT_THRESH (3*HZ) /* Maximal freq. of asserts */ - -struct rtmsg; -extern int ip6mr_get_route(struct net *net, struct sk_buff *skb, - struct rtmsg *rtm, int nowait, u32 portid); - -#ifdef CONFIG_IPV6_MROUTE -extern struct sock *mroute6_socket(struct net *net, struct sk_buff *skb); -extern int ip6mr_sk_done(struct sock *sk); -#else -static inline struct sock *mroute6_socket(struct net *net, struct sk_buff *skb) -{ - return NULL; -} -static inline int ip6mr_sk_done(struct sock *sk) -{ - return 0; -} -#endif -#endif diff --git a/src/linux/include/linux/msdos_fs.h b/src/linux/include/linux/msdos_fs.h deleted file mode 100644 index e1b163f..0000000 --- a/src/linux/include/linux/msdos_fs.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _LINUX_MSDOS_FS_H -#define _LINUX_MSDOS_FS_H - -#include - -/* media of boot sector */ -static inline int fat_valid_media(u8 media) -{ - return 0xf8 <= media || media == 0xf0; -} -#endif /* !_LINUX_MSDOS_FS_H */ diff --git a/src/linux/include/linux/msi.h b/src/linux/include/linux/msi.h deleted file mode 100644 index 0db320b..0000000 --- a/src/linux/include/linux/msi.h +++ /dev/null @@ -1,338 +0,0 @@ -#ifndef LINUX_MSI_H -#define LINUX_MSI_H - -#include -#include - -struct msi_msg { - u32 address_lo; /* low 32 bits of msi message address */ - u32 address_hi; /* high 32 bits of msi message address */ - u32 data; /* 16 bits of msi message data */ -}; - -extern int pci_msi_ignore_mask; -/* Helper functions */ -struct irq_data; -struct msi_desc; -struct pci_dev; -struct platform_msi_priv_data; -void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg); -void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg); - -typedef void (*irq_write_msi_msg_t)(struct msi_desc *desc, - struct msi_msg *msg); - -/** - * platform_msi_desc - Platform device specific msi descriptor data - * @msi_priv_data: Pointer to platform private data - * @msi_index: The index of the MSI descriptor for multi MSI - */ -struct platform_msi_desc { - struct platform_msi_priv_data *msi_priv_data; - u16 msi_index; -}; - -/** - * fsl_mc_msi_desc - FSL-MC device specific msi descriptor data - * @msi_index: The index of the MSI descriptor - */ -struct fsl_mc_msi_desc { - u16 msi_index; -}; - -/** - * struct msi_desc - Descriptor structure for MSI based interrupts - * @list: List head for management - * @irq: The base interrupt number - * @nvec_used: The number of vectors used - * @dev: Pointer to the device which uses this descriptor - * @msg: The last set MSI message cached for reuse - * @affinity: Optional pointer to a cpu affinity mask for this descriptor - * - * @masked: [PCI MSI/X] Mask bits - * @is_msix: [PCI MSI/X] True if MSI-X - * @multiple: [PCI MSI/X] log2 num of messages allocated - * @multi_cap: [PCI MSI/X] log2 num of messages supported - * @maskbit: [PCI MSI/X] Mask-Pending bit supported? - * @is_64: [PCI MSI/X] Address size: 0=32bit 1=64bit - * @entry_nr: [PCI MSI/X] Entry which is described by this descriptor - * @default_irq:[PCI MSI/X] The default pre-assigned non-MSI irq - * @mask_pos: [PCI MSI] Mask register position - * @mask_base: [PCI MSI-X] Mask register base address - * @platform: [platform] Platform device specific msi descriptor data - */ -struct msi_desc { - /* Shared device/bus type independent data */ - struct list_head list; - unsigned int irq; - unsigned int nvec_used; - struct device *dev; - struct msi_msg msg; - struct cpumask *affinity; - - union { - /* PCI MSI/X specific data */ - struct { - u32 masked; - struct { - __u8 is_msix : 1; - __u8 multiple : 3; - __u8 multi_cap : 3; - __u8 maskbit : 1; - __u8 is_64 : 1; - __u16 entry_nr; - unsigned default_irq; - } msi_attrib; - union { - u8 mask_pos; - void __iomem *mask_base; - }; - }; - - /* - * Non PCI variants add their data structure here. New - * entries need to use a named structure. We want - * proper name spaces for this. The PCI part is - * anonymous for now as it would require an immediate - * tree wide cleanup. - */ - struct platform_msi_desc platform; - struct fsl_mc_msi_desc fsl_mc; - }; -}; - -/* Helpers to hide struct msi_desc implementation details */ -#define msi_desc_to_dev(desc) ((desc)->dev) -#define dev_to_msi_list(dev) (&(dev)->msi_list) -#define first_msi_entry(dev) \ - list_first_entry(dev_to_msi_list((dev)), struct msi_desc, list) -#define for_each_msi_entry(desc, dev) \ - list_for_each_entry((desc), dev_to_msi_list((dev)), list) - -#ifdef CONFIG_PCI_MSI -#define first_pci_msi_entry(pdev) first_msi_entry(&(pdev)->dev) -#define for_each_pci_msi_entry(desc, pdev) \ - for_each_msi_entry((desc), &(pdev)->dev) - -struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc); -void *msi_desc_to_pci_sysdata(struct msi_desc *desc); -#else /* CONFIG_PCI_MSI */ -static inline void *msi_desc_to_pci_sysdata(struct msi_desc *desc) -{ - return NULL; -} -#endif /* CONFIG_PCI_MSI */ - -struct msi_desc *alloc_msi_entry(struct device *dev, int nvec, - const struct cpumask *affinity); -void free_msi_entry(struct msi_desc *entry); -void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg); -void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg); -void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg); - -u32 __pci_msix_desc_mask_irq(struct msi_desc *desc, u32 flag); -u32 __pci_msi_desc_mask_irq(struct msi_desc *desc, u32 mask, u32 flag); -void pci_msi_mask_irq(struct irq_data *data); -void pci_msi_unmask_irq(struct irq_data *data); - -/* Conversion helpers. Should be removed after merging */ -static inline void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg) -{ - __pci_write_msi_msg(entry, msg); -} -static inline void write_msi_msg(int irq, struct msi_msg *msg) -{ - pci_write_msi_msg(irq, msg); -} -static inline void mask_msi_irq(struct irq_data *data) -{ - pci_msi_mask_irq(data); -} -static inline void unmask_msi_irq(struct irq_data *data) -{ - pci_msi_unmask_irq(data); -} - -/* - * The arch hooks to setup up msi irqs. Those functions are - * implemented as weak symbols so that they /can/ be overriden by - * architecture specific code if needed. - */ -int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc); -void arch_teardown_msi_irq(unsigned int irq); -int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type); -void arch_teardown_msi_irqs(struct pci_dev *dev); -void arch_restore_msi_irqs(struct pci_dev *dev); - -void default_teardown_msi_irqs(struct pci_dev *dev); -void default_restore_msi_irqs(struct pci_dev *dev); - -struct msi_controller { - struct module *owner; - struct device *dev; - struct device_node *of_node; - struct list_head list; - - int (*setup_irq)(struct msi_controller *chip, struct pci_dev *dev, - struct msi_desc *desc); - int (*setup_irqs)(struct msi_controller *chip, struct pci_dev *dev, - int nvec, int type); - void (*teardown_irq)(struct msi_controller *chip, unsigned int irq); -}; - -#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN - -#include -#include - -struct irq_domain; -struct irq_domain_ops; -struct irq_chip; -struct device_node; -struct fwnode_handle; -struct msi_domain_info; - -/** - * struct msi_domain_ops - MSI interrupt domain callbacks - * @get_hwirq: Retrieve the resulting hw irq number - * @msi_init: Domain specific init function for MSI interrupts - * @msi_free: Domain specific function to free a MSI interrupts - * @msi_check: Callback for verification of the domain/info/dev data - * @msi_prepare: Prepare the allocation of the interrupts in the domain - * @msi_finish: Optional callback to finalize the allocation - * @set_desc: Set the msi descriptor for an interrupt - * @handle_error: Optional error handler if the allocation fails - * - * @get_hwirq, @msi_init and @msi_free are callbacks used by - * msi_create_irq_domain() and related interfaces - * - * @msi_check, @msi_prepare, @msi_finish, @set_desc and @handle_error - * are callbacks used by msi_domain_alloc_irqs() and related - * interfaces which are based on msi_desc. - */ -struct msi_domain_ops { - irq_hw_number_t (*get_hwirq)(struct msi_domain_info *info, - msi_alloc_info_t *arg); - int (*msi_init)(struct irq_domain *domain, - struct msi_domain_info *info, - unsigned int virq, irq_hw_number_t hwirq, - msi_alloc_info_t *arg); - void (*msi_free)(struct irq_domain *domain, - struct msi_domain_info *info, - unsigned int virq); - int (*msi_check)(struct irq_domain *domain, - struct msi_domain_info *info, - struct device *dev); - int (*msi_prepare)(struct irq_domain *domain, - struct device *dev, int nvec, - msi_alloc_info_t *arg); - void (*msi_finish)(msi_alloc_info_t *arg, int retval); - void (*set_desc)(msi_alloc_info_t *arg, - struct msi_desc *desc); - int (*handle_error)(struct irq_domain *domain, - struct msi_desc *desc, int error); -}; - -/** - * struct msi_domain_info - MSI interrupt domain data - * @flags: Flags to decribe features and capabilities - * @ops: The callback data structure - * @chip: Optional: associated interrupt chip - * @chip_data: Optional: associated interrupt chip data - * @handler: Optional: associated interrupt flow handler - * @handler_data: Optional: associated interrupt flow handler data - * @handler_name: Optional: associated interrupt flow handler name - * @data: Optional: domain specific data - */ -struct msi_domain_info { - u32 flags; - struct msi_domain_ops *ops; - struct irq_chip *chip; - void *chip_data; - irq_flow_handler_t handler; - void *handler_data; - const char *handler_name; - void *data; -}; - -/* Flags for msi_domain_info */ -enum { - /* - * Init non implemented ops callbacks with default MSI domain - * callbacks. - */ - MSI_FLAG_USE_DEF_DOM_OPS = (1 << 0), - /* - * Init non implemented chip callbacks with default MSI chip - * callbacks. - */ - MSI_FLAG_USE_DEF_CHIP_OPS = (1 << 1), - /* Support multiple PCI MSI interrupts */ - MSI_FLAG_MULTI_PCI_MSI = (1 << 2), - /* Support PCI MSIX interrupts */ - MSI_FLAG_PCI_MSIX = (1 << 3), - /* Needs early activate, required for PCI */ - MSI_FLAG_ACTIVATE_EARLY = (1 << 4), -}; - -int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask, - bool force); - -struct irq_domain *msi_create_irq_domain(struct fwnode_handle *fwnode, - struct msi_domain_info *info, - struct irq_domain *parent); -int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev, - int nvec); -void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev); -struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain); - -struct irq_domain *platform_msi_create_irq_domain(struct fwnode_handle *fwnode, - struct msi_domain_info *info, - struct irq_domain *parent); -int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec, - irq_write_msi_msg_t write_msi_msg); -void platform_msi_domain_free_irqs(struct device *dev); - -/* When an MSI domain is used as an intermediate domain */ -int msi_domain_prepare_irqs(struct irq_domain *domain, struct device *dev, - int nvec, msi_alloc_info_t *args); -int msi_domain_populate_irqs(struct irq_domain *domain, struct device *dev, - int virq, int nvec, msi_alloc_info_t *args); -struct irq_domain * -platform_msi_create_device_domain(struct device *dev, - unsigned int nvec, - irq_write_msi_msg_t write_msi_msg, - const struct irq_domain_ops *ops, - void *host_data); -int platform_msi_domain_alloc(struct irq_domain *domain, unsigned int virq, - unsigned int nr_irqs); -void platform_msi_domain_free(struct irq_domain *domain, unsigned int virq, - unsigned int nvec); -void *platform_msi_get_host_data(struct irq_domain *domain); -#endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */ - -#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN -void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg); -struct irq_domain *pci_msi_create_irq_domain(struct fwnode_handle *fwnode, - struct msi_domain_info *info, - struct irq_domain *parent); -int pci_msi_domain_alloc_irqs(struct irq_domain *domain, struct pci_dev *dev, - int nvec, int type); -void pci_msi_domain_free_irqs(struct irq_domain *domain, struct pci_dev *dev); -struct irq_domain *pci_msi_create_default_irq_domain(struct fwnode_handle *fwnode, - struct msi_domain_info *info, struct irq_domain *parent); - -irq_hw_number_t pci_msi_domain_calc_hwirq(struct pci_dev *dev, - struct msi_desc *desc); -int pci_msi_domain_check_cap(struct irq_domain *domain, - struct msi_domain_info *info, struct device *dev); -u32 pci_msi_domain_get_msi_rid(struct irq_domain *domain, struct pci_dev *pdev); -struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev); -#else -static inline struct irq_domain *pci_msi_get_device_domain(struct pci_dev *pdev) -{ - return NULL; -} -#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */ - -#endif /* LINUX_MSI_H */ diff --git a/src/linux/include/linux/mutex.h b/src/linux/include/linux/mutex.h deleted file mode 100644 index 2cb7531..0000000 --- a/src/linux/include/linux/mutex.h +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Mutexes: blocking mutual exclusion locks - * - * started by Ingo Molnar: - * - * Copyright (C) 2004, 2005, 2006 Red Hat, Inc., Ingo Molnar - * - * This file contains the main data structure and API definitions. - */ -#ifndef __LINUX_MUTEX_H -#define __LINUX_MUTEX_H - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Simple, straightforward mutexes with strict semantics: - * - * - only one task can hold the mutex at a time - * - only the owner can unlock the mutex - * - multiple unlocks are not permitted - * - recursive locking is not permitted - * - a mutex object must be initialized via the API - * - a mutex object must not be initialized via memset or copying - * - task may not exit with mutex held - * - memory areas where held locks reside must not be freed - * - held mutexes must not be reinitialized - * - mutexes may not be used in hardware or software interrupt - * contexts such as tasklets and timers - * - * These semantics are fully enforced when DEBUG_MUTEXES is - * enabled. Furthermore, besides enforcing the above rules, the mutex - * debugging code also implements a number of additional features - * that make lock debugging easier and faster: - * - * - uses symbolic names of mutexes, whenever they are printed in debug output - * - point-of-acquire tracking, symbolic lookup of function names - * - list of all locks held in the system, printout of them - * - owner tracking - * - detects self-recursing locks and prints out all relevant info - * - detects multi-task circular deadlocks and prints out all affected - * locks and tasks (and only those tasks) - */ -struct mutex { - /* 1: unlocked, 0: locked, negative: locked, possible waiters */ - atomic_t count; - spinlock_t wait_lock; - struct list_head wait_list; -#if defined(CONFIG_DEBUG_MUTEXES) || defined(CONFIG_MUTEX_SPIN_ON_OWNER) - struct task_struct *owner; -#endif -#ifdef CONFIG_MUTEX_SPIN_ON_OWNER - struct optimistic_spin_queue osq; /* Spinner MCS lock */ -#endif -#ifdef CONFIG_DEBUG_MUTEXES - void *magic; -#endif -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map dep_map; -#endif -}; - -/* - * This is the control structure for tasks blocked on mutex, - * which resides on the blocked task's kernel stack: - */ -struct mutex_waiter { - struct list_head list; - struct task_struct *task; -#ifdef CONFIG_DEBUG_MUTEXES - void *magic; -#endif -}; - -#ifdef CONFIG_DEBUG_MUTEXES -# include -#else -# define __DEBUG_MUTEX_INITIALIZER(lockname) -/** - * mutex_init - initialize the mutex - * @mutex: the mutex to be initialized - * - * Initialize the mutex to unlocked state. - * - * It is not allowed to initialize an already locked mutex. - */ -# define mutex_init(mutex) \ -do { \ - static struct lock_class_key __key; \ - \ - __mutex_init((mutex), #mutex, &__key); \ -} while (0) -static inline void mutex_destroy(struct mutex *lock) {} -#endif - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# define __DEP_MAP_MUTEX_INITIALIZER(lockname) \ - , .dep_map = { .name = #lockname } -#else -# define __DEP_MAP_MUTEX_INITIALIZER(lockname) -#endif - -#define __MUTEX_INITIALIZER(lockname) \ - { .count = ATOMIC_INIT(1) \ - , .wait_lock = __SPIN_LOCK_UNLOCKED(lockname.wait_lock) \ - , .wait_list = LIST_HEAD_INIT(lockname.wait_list) \ - __DEBUG_MUTEX_INITIALIZER(lockname) \ - __DEP_MAP_MUTEX_INITIALIZER(lockname) } - -#define DEFINE_MUTEX(mutexname) \ - struct mutex mutexname = __MUTEX_INITIALIZER(mutexname) - -extern void __mutex_init(struct mutex *lock, const char *name, - struct lock_class_key *key); - -/** - * mutex_is_locked - is the mutex locked - * @lock: the mutex to be queried - * - * Returns 1 if the mutex is locked, 0 if unlocked. - */ -static inline int mutex_is_locked(struct mutex *lock) -{ - return atomic_read(&lock->count) != 1; -} - -/* - * See kernel/locking/mutex.c for detailed documentation of these APIs. - * Also see Documentation/locking/mutex-design.txt. - */ -#ifdef CONFIG_DEBUG_LOCK_ALLOC -extern void mutex_lock_nested(struct mutex *lock, unsigned int subclass); -extern void _mutex_lock_nest_lock(struct mutex *lock, struct lockdep_map *nest_lock); - -extern int __must_check mutex_lock_interruptible_nested(struct mutex *lock, - unsigned int subclass); -extern int __must_check mutex_lock_killable_nested(struct mutex *lock, - unsigned int subclass); - -#define mutex_lock(lock) mutex_lock_nested(lock, 0) -#define mutex_lock_interruptible(lock) mutex_lock_interruptible_nested(lock, 0) -#define mutex_lock_killable(lock) mutex_lock_killable_nested(lock, 0) - -#define mutex_lock_nest_lock(lock, nest_lock) \ -do { \ - typecheck(struct lockdep_map *, &(nest_lock)->dep_map); \ - _mutex_lock_nest_lock(lock, &(nest_lock)->dep_map); \ -} while (0) - -#else -extern void mutex_lock(struct mutex *lock); -extern int __must_check mutex_lock_interruptible(struct mutex *lock); -extern int __must_check mutex_lock_killable(struct mutex *lock); - -# define mutex_lock_nested(lock, subclass) mutex_lock(lock) -# define mutex_lock_interruptible_nested(lock, subclass) mutex_lock_interruptible(lock) -# define mutex_lock_killable_nested(lock, subclass) mutex_lock_killable(lock) -# define mutex_lock_nest_lock(lock, nest_lock) mutex_lock(lock) -#endif - -/* - * NOTE: mutex_trylock() follows the spin_trylock() convention, - * not the down_trylock() convention! - * - * Returns 1 if the mutex has been acquired successfully, and 0 on contention. - */ -extern int mutex_trylock(struct mutex *lock); -extern void mutex_unlock(struct mutex *lock); - -extern int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock); - -#endif /* __LINUX_MUTEX_H */ diff --git a/src/linux/include/linux/namei.h b/src/linux/include/linux/namei.h deleted file mode 100644 index f29abda..0000000 --- a/src/linux/include/linux/namei.h +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef _LINUX_NAMEI_H -#define _LINUX_NAMEI_H - -#include -#include -#include -#include - -enum { MAX_NESTED_LINKS = 8 }; - -#define MAXSYMLINKS 40 - -/* - * Type of the last component on LOOKUP_PARENT - */ -enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND}; - -/* - * The bitmask for a lookup event: - * - follow links at the end - * - require a directory - * - ending slashes ok even for nonexistent files - * - internal "there are more path components" flag - * - dentry cache is untrusted; force a real lookup - * - suppress terminal automount - */ -#define LOOKUP_FOLLOW 0x0001 -#define LOOKUP_DIRECTORY 0x0002 -#define LOOKUP_AUTOMOUNT 0x0004 - -#define LOOKUP_PARENT 0x0010 -#define LOOKUP_REVAL 0x0020 -#define LOOKUP_RCU 0x0040 -#define LOOKUP_NO_REVAL 0x0080 - -/* - * Intent data - */ -#define LOOKUP_OPEN 0x0100 -#define LOOKUP_CREATE 0x0200 -#define LOOKUP_EXCL 0x0400 -#define LOOKUP_RENAME_TARGET 0x0800 - -#define LOOKUP_JUMPED 0x1000 -#define LOOKUP_ROOT 0x2000 -#define LOOKUP_EMPTY 0x4000 - -extern int path_pts(struct path *path); - -extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty); - -static inline int user_path_at(int dfd, const char __user *name, unsigned flags, - struct path *path) -{ - return user_path_at_empty(dfd, name, flags, path, NULL); -} - -static inline int user_path(const char __user *name, struct path *path) -{ - return user_path_at_empty(AT_FDCWD, name, LOOKUP_FOLLOW, path, NULL); -} - -static inline int user_lpath(const char __user *name, struct path *path) -{ - return user_path_at_empty(AT_FDCWD, name, 0, path, NULL); -} - -static inline int user_path_dir(const char __user *name, struct path *path) -{ - return user_path_at_empty(AT_FDCWD, name, - LOOKUP_FOLLOW | LOOKUP_DIRECTORY, path, NULL); -} - -extern int kern_path(const char *, unsigned, struct path *); - -extern struct dentry *kern_path_create(int, const char *, struct path *, unsigned int); -extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int); -extern void done_path_create(struct path *, struct dentry *); -extern struct dentry *kern_path_locked(const char *, struct path *); -extern int kern_path_mountpoint(int, const char *, struct path *, unsigned int); - -extern struct dentry *lookup_one_len(const char *, struct dentry *, int); -extern struct dentry *lookup_one_len_unlocked(const char *, struct dentry *, int); - -extern int follow_down_one(struct path *); -extern int follow_down(struct path *); -extern int follow_up(struct path *); - -extern struct dentry *lock_rename(struct dentry *, struct dentry *); -extern void unlock_rename(struct dentry *, struct dentry *); - -extern void nd_jump_link(struct path *path); - -static inline void nd_terminate_link(void *name, size_t len, size_t maxlen) -{ - ((char *) name)[min(len, maxlen)] = '\0'; -} - -/** - * retry_estale - determine whether the caller should retry an operation - * @error: the error that would currently be returned - * @flags: flags being used for next lookup attempt - * - * Check to see if the error code was -ESTALE, and then determine whether - * to retry the call based on whether "flags" already has LOOKUP_REVAL set. - * - * Returns true if the caller should try the operation again. - */ -static inline bool -retry_estale(const long error, const unsigned int flags) -{ - return error == -ESTALE && !(flags & LOOKUP_REVAL); -} - -#endif /* _LINUX_NAMEI_H */ diff --git a/src/linux/include/linux/net.h b/src/linux/include/linux/net.h deleted file mode 100644 index cd0c8bd..0000000 --- a/src/linux/include/linux/net.h +++ /dev/null @@ -1,314 +0,0 @@ -/* - * NET An implementation of the SOCKET network access protocol. - * This is the master header file for the Linux NET layer, - * or, in plain English: the networking handling part of the - * kernel. - * - * Version: @(#)net.h 1.0.3 05/25/93 - * - * Authors: Orest Zborowski, - * Ross Biro - * Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_NET_H -#define _LINUX_NET_H - -#include -#include -#include -#include /* For O_CLOEXEC and O_NONBLOCK */ -#include -#include -#include -#include - -#include - -struct poll_table_struct; -struct pipe_inode_info; -struct inode; -struct file; -struct net; - -/* Historically, SOCKWQ_ASYNC_NOSPACE & SOCKWQ_ASYNC_WAITDATA were located - * in sock->flags, but moved into sk->sk_wq->flags to be RCU protected. - * Eventually all flags will be in sk->sk_wq_flags. - */ -#define SOCKWQ_ASYNC_NOSPACE 0 -#define SOCKWQ_ASYNC_WAITDATA 1 -#define SOCK_NOSPACE 2 -#define SOCK_PASSCRED 3 -#define SOCK_PASSSEC 4 - -#ifndef ARCH_HAS_SOCKET_TYPES -/** - * enum sock_type - Socket types - * @SOCK_STREAM: stream (connection) socket - * @SOCK_DGRAM: datagram (conn.less) socket - * @SOCK_RAW: raw socket - * @SOCK_RDM: reliably-delivered message - * @SOCK_SEQPACKET: sequential packet socket - * @SOCK_DCCP: Datagram Congestion Control Protocol socket - * @SOCK_PACKET: linux specific way of getting packets at the dev level. - * For writing rarp and other similar things on the user level. - * - * When adding some new socket type please - * grep ARCH_HAS_SOCKET_TYPE include/asm-* /socket.h, at least MIPS - * overrides this enum for binary compat reasons. - */ -enum sock_type { - SOCK_STREAM = 1, - SOCK_DGRAM = 2, - SOCK_RAW = 3, - SOCK_RDM = 4, - SOCK_SEQPACKET = 5, - SOCK_DCCP = 6, - SOCK_PACKET = 10, -}; - -#define SOCK_MAX (SOCK_PACKET + 1) -/* Mask which covers at least up to SOCK_MASK-1. The - * remaining bits are used as flags. */ -#define SOCK_TYPE_MASK 0xf - -/* Flags for socket, socketpair, accept4 */ -#define SOCK_CLOEXEC O_CLOEXEC -#ifndef SOCK_NONBLOCK -#define SOCK_NONBLOCK O_NONBLOCK -#endif - -#endif /* ARCH_HAS_SOCKET_TYPES */ - -enum sock_shutdown_cmd { - SHUT_RD, - SHUT_WR, - SHUT_RDWR, -}; - -struct socket_wq { - /* Note: wait MUST be first field of socket_wq */ - wait_queue_head_t wait; - struct fasync_struct *fasync_list; - unsigned long flags; /* %SOCKWQ_ASYNC_NOSPACE, etc */ - struct rcu_head rcu; -} ____cacheline_aligned_in_smp; - -/** - * struct socket - general BSD socket - * @state: socket state (%SS_CONNECTED, etc) - * @type: socket type (%SOCK_STREAM, etc) - * @flags: socket flags (%SOCK_NOSPACE, etc) - * @ops: protocol specific socket operations - * @file: File back pointer for gc - * @sk: internal networking protocol agnostic socket representation - * @wq: wait queue for several uses - */ -struct socket { - socket_state state; - - kmemcheck_bitfield_begin(type); - short type; - kmemcheck_bitfield_end(type); - - unsigned long flags; - - struct socket_wq __rcu *wq; - - struct file *file; - struct sock *sk; - const struct proto_ops *ops; -}; - -struct vm_area_struct; -struct page; -struct sockaddr; -struct msghdr; -struct module; -struct sk_buff; -typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *, - unsigned int, size_t); - -struct proto_ops { - int family; - struct module *owner; - int (*release) (struct socket *sock); - int (*bind) (struct socket *sock, - struct sockaddr *myaddr, - int sockaddr_len); - int (*connect) (struct socket *sock, - struct sockaddr *vaddr, - int sockaddr_len, int flags); - int (*socketpair)(struct socket *sock1, - struct socket *sock2); - int (*accept) (struct socket *sock, - struct socket *newsock, int flags); - int (*getname) (struct socket *sock, - struct sockaddr *addr, - int *sockaddr_len, int peer); - unsigned int (*poll) (struct file *file, struct socket *sock, - struct poll_table_struct *wait); - int (*ioctl) (struct socket *sock, unsigned int cmd, - unsigned long arg); -#ifdef CONFIG_COMPAT - int (*compat_ioctl) (struct socket *sock, unsigned int cmd, - unsigned long arg); -#endif - int (*listen) (struct socket *sock, int len); - int (*shutdown) (struct socket *sock, int flags); - int (*setsockopt)(struct socket *sock, int level, - int optname, char __user *optval, unsigned int optlen); - int (*getsockopt)(struct socket *sock, int level, - int optname, char __user *optval, int __user *optlen); -#ifdef CONFIG_COMPAT - int (*compat_setsockopt)(struct socket *sock, int level, - int optname, char __user *optval, unsigned int optlen); - int (*compat_getsockopt)(struct socket *sock, int level, - int optname, char __user *optval, int __user *optlen); -#endif - int (*sendmsg) (struct socket *sock, struct msghdr *m, - size_t total_len); - /* Notes for implementing recvmsg: - * =============================== - * msg->msg_namelen should get updated by the recvmsg handlers - * iff msg_name != NULL. It is by default 0 to prevent - * returning uninitialized memory to user space. The recvfrom - * handlers can assume that msg.msg_name is either NULL or has - * a minimum size of sizeof(struct sockaddr_storage). - */ - int (*recvmsg) (struct socket *sock, struct msghdr *m, - size_t total_len, int flags); - int (*mmap) (struct file *file, struct socket *sock, - struct vm_area_struct * vma); - ssize_t (*sendpage) (struct socket *sock, struct page *page, - int offset, size_t size, int flags); - ssize_t (*splice_read)(struct socket *sock, loff_t *ppos, - struct pipe_inode_info *pipe, size_t len, unsigned int flags); - int (*set_peek_off)(struct sock *sk, int val); - int (*peek_len)(struct socket *sock); - int (*read_sock)(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor); -}; - -#define DECLARE_SOCKADDR(type, dst, src) \ - type dst = ({ __sockaddr_check_size(sizeof(*dst)); (type) src; }) - -struct net_proto_family { - int family; - int (*create)(struct net *net, struct socket *sock, - int protocol, int kern); - struct module *owner; -}; - -struct iovec; -struct kvec; - -enum { - SOCK_WAKE_IO, - SOCK_WAKE_WAITD, - SOCK_WAKE_SPACE, - SOCK_WAKE_URG, -}; - -int sock_wake_async(struct socket_wq *sk_wq, int how, int band); -int sock_register(const struct net_proto_family *fam); -void sock_unregister(int family); -int __sock_create(struct net *net, int family, int type, int proto, - struct socket **res, int kern); -int sock_create(int family, int type, int proto, struct socket **res); -int sock_create_kern(struct net *net, int family, int type, int proto, struct socket **res); -int sock_create_lite(int family, int type, int proto, struct socket **res); -struct socket *sock_alloc(void); -void sock_release(struct socket *sock); -int sock_sendmsg(struct socket *sock, struct msghdr *msg); -int sock_recvmsg(struct socket *sock, struct msghdr *msg, int flags); -struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname); -struct socket *sockfd_lookup(int fd, int *err); -struct socket *sock_from_file(struct file *file, int *err); -#define sockfd_put(sock) fput(sock->file) -int net_ratelimit(void); - -#define net_ratelimited_function(function, ...) \ -do { \ - if (net_ratelimit()) \ - function(__VA_ARGS__); \ -} while (0) - -#define net_emerg_ratelimited(fmt, ...) \ - net_ratelimited_function(pr_emerg, fmt, ##__VA_ARGS__) -#define net_alert_ratelimited(fmt, ...) \ - net_ratelimited_function(pr_alert, fmt, ##__VA_ARGS__) -#define net_crit_ratelimited(fmt, ...) \ - net_ratelimited_function(pr_crit, fmt, ##__VA_ARGS__) -#define net_err_ratelimited(fmt, ...) \ - net_ratelimited_function(pr_err, fmt, ##__VA_ARGS__) -#define net_notice_ratelimited(fmt, ...) \ - net_ratelimited_function(pr_notice, fmt, ##__VA_ARGS__) -#define net_warn_ratelimited(fmt, ...) \ - net_ratelimited_function(pr_warn, fmt, ##__VA_ARGS__) -#define net_info_ratelimited(fmt, ...) \ - net_ratelimited_function(pr_info, fmt, ##__VA_ARGS__) -#if defined(CONFIG_DYNAMIC_DEBUG) -#define net_dbg_ratelimited(fmt, ...) \ -do { \ - DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \ - if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT) && \ - net_ratelimit()) \ - __dynamic_pr_debug(&descriptor, pr_fmt(fmt), \ - ##__VA_ARGS__); \ -} while (0) -#elif defined(DEBUG) -#define net_dbg_ratelimited(fmt, ...) \ - net_ratelimited_function(pr_debug, fmt, ##__VA_ARGS__) -#else -#define net_dbg_ratelimited(fmt, ...) \ - do { \ - if (0) \ - no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \ - } while (0) -#endif - -#define net_get_random_once(buf, nbytes) \ - get_random_once((buf), (nbytes)) - -int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, - size_t num, size_t len); -int kernel_recvmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, - size_t num, size_t len, int flags); - -int kernel_bind(struct socket *sock, struct sockaddr *addr, int addrlen); -int kernel_listen(struct socket *sock, int backlog); -int kernel_accept(struct socket *sock, struct socket **newsock, int flags); -int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen, - int flags); -int kernel_getsockname(struct socket *sock, struct sockaddr *addr, - int *addrlen); -int kernel_getpeername(struct socket *sock, struct sockaddr *addr, - int *addrlen); -int kernel_getsockopt(struct socket *sock, int level, int optname, char *optval, - int *optlen); -int kernel_setsockopt(struct socket *sock, int level, int optname, char *optval, - unsigned int optlen); -int kernel_sendpage(struct socket *sock, struct page *page, int offset, - size_t size, int flags); -int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg); -int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how); - -#define MODULE_ALIAS_NETPROTO(proto) \ - MODULE_ALIAS("net-pf-" __stringify(proto)) - -#define MODULE_ALIAS_NET_PF_PROTO(pf, proto) \ - MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto)) - -#define MODULE_ALIAS_NET_PF_PROTO_TYPE(pf, proto, type) \ - MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto) \ - "-type-" __stringify(type)) - -#define MODULE_ALIAS_NET_PF_PROTO_NAME(pf, proto, name) \ - MODULE_ALIAS("net-pf-" __stringify(pf) "-proto-" __stringify(proto) \ - name) -#endif /* _LINUX_NET_H */ diff --git a/src/linux/include/linux/netdev_features.h b/src/linux/include/linux/netdev_features.h deleted file mode 100644 index 9c6c8ef..0000000 --- a/src/linux/include/linux/netdev_features.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Network device features. - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_NETDEV_FEATURES_H -#define _LINUX_NETDEV_FEATURES_H - -#include - -typedef u64 netdev_features_t; - -enum { - NETIF_F_SG_BIT, /* Scatter/gather IO. */ - NETIF_F_IP_CSUM_BIT, /* Can checksum TCP/UDP over IPv4. */ - __UNUSED_NETIF_F_1, - NETIF_F_HW_CSUM_BIT, /* Can checksum all the packets. */ - NETIF_F_IPV6_CSUM_BIT, /* Can checksum TCP/UDP over IPV6 */ - NETIF_F_HIGHDMA_BIT, /* Can DMA to high memory. */ - NETIF_F_FRAGLIST_BIT, /* Scatter/gather IO. */ - NETIF_F_HW_VLAN_CTAG_TX_BIT, /* Transmit VLAN CTAG HW acceleration */ - NETIF_F_HW_VLAN_CTAG_RX_BIT, /* Receive VLAN CTAG HW acceleration */ - NETIF_F_HW_VLAN_CTAG_FILTER_BIT,/* Receive filtering on VLAN CTAGs */ - NETIF_F_VLAN_CHALLENGED_BIT, /* Device cannot handle VLAN packets */ - NETIF_F_GSO_BIT, /* Enable software GSO. */ - NETIF_F_LLTX_BIT, /* LockLess TX - deprecated. Please */ - /* do not use LLTX in new drivers */ - NETIF_F_NETNS_LOCAL_BIT, /* Does not change network namespaces */ - NETIF_F_GRO_BIT, /* Generic receive offload */ - NETIF_F_LRO_BIT, /* large receive offload */ - - /**/NETIF_F_GSO_SHIFT, /* keep the order of SKB_GSO_* bits */ - NETIF_F_TSO_BIT /* ... TCPv4 segmentation */ - = NETIF_F_GSO_SHIFT, - NETIF_F_UFO_BIT, /* ... UDPv4 fragmentation */ - NETIF_F_GSO_ROBUST_BIT, /* ... ->SKB_GSO_DODGY */ - NETIF_F_TSO_ECN_BIT, /* ... TCP ECN support */ - NETIF_F_TSO_MANGLEID_BIT, /* ... IPV4 ID mangling allowed */ - NETIF_F_TSO6_BIT, /* ... TCPv6 segmentation */ - NETIF_F_FSO_BIT, /* ... FCoE segmentation */ - NETIF_F_GSO_GRE_BIT, /* ... GRE with TSO */ - NETIF_F_GSO_GRE_CSUM_BIT, /* ... GRE with csum with TSO */ - NETIF_F_GSO_IPXIP4_BIT, /* ... IP4 or IP6 over IP4 with TSO */ - NETIF_F_GSO_IPXIP6_BIT, /* ... IP4 or IP6 over IP6 with TSO */ - NETIF_F_GSO_UDP_TUNNEL_BIT, /* ... UDP TUNNEL with TSO */ - NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT,/* ... UDP TUNNEL with TSO & CSUM */ - NETIF_F_GSO_PARTIAL_BIT, /* ... Only segment inner-most L4 - * in hardware and all other - * headers in software. - */ - NETIF_F_GSO_TUNNEL_REMCSUM_BIT, /* ... TUNNEL with TSO & REMCSUM */ - NETIF_F_GSO_SCTP_BIT, /* ... SCTP fragmentation */ - /**/NETIF_F_GSO_LAST = /* last bit, see GSO_MASK */ - NETIF_F_GSO_SCTP_BIT, - - NETIF_F_FCOE_CRC_BIT, /* FCoE CRC32 */ - NETIF_F_SCTP_CRC_BIT, /* SCTP checksum offload */ - NETIF_F_FCOE_MTU_BIT, /* Supports max FCoE MTU, 2158 bytes*/ - NETIF_F_NTUPLE_BIT, /* N-tuple filters supported */ - NETIF_F_RXHASH_BIT, /* Receive hashing offload */ - NETIF_F_RXCSUM_BIT, /* Receive checksumming offload */ - NETIF_F_NOCACHE_COPY_BIT, /* Use no-cache copyfromuser */ - NETIF_F_LOOPBACK_BIT, /* Enable loopback */ - NETIF_F_RXFCS_BIT, /* Append FCS to skb pkt data */ - NETIF_F_RXALL_BIT, /* Receive errored frames too */ - NETIF_F_HW_VLAN_STAG_TX_BIT, /* Transmit VLAN STAG HW acceleration */ - NETIF_F_HW_VLAN_STAG_RX_BIT, /* Receive VLAN STAG HW acceleration */ - NETIF_F_HW_VLAN_STAG_FILTER_BIT,/* Receive filtering on VLAN STAGs */ - NETIF_F_HW_L2FW_DOFFLOAD_BIT, /* Allow L2 Forwarding in Hardware */ - NETIF_F_BUSY_POLL_BIT, /* Busy poll */ - - NETIF_F_HW_TC_BIT, /* Offload TC infrastructure */ - - /* - * Add your fresh new feature above and remember to update - * netdev_features_strings[] in net/core/ethtool.c and maybe - * some feature mask #defines below. Please also describe it - * in Documentation/networking/netdev-features.txt. - */ - - /**/NETDEV_FEATURE_COUNT -}; - -/* copy'n'paste compression ;) */ -#define __NETIF_F_BIT(bit) ((netdev_features_t)1 << (bit)) -#define __NETIF_F(name) __NETIF_F_BIT(NETIF_F_##name##_BIT) - -#define NETIF_F_FCOE_CRC __NETIF_F(FCOE_CRC) -#define NETIF_F_FCOE_MTU __NETIF_F(FCOE_MTU) -#define NETIF_F_FRAGLIST __NETIF_F(FRAGLIST) -#define NETIF_F_FSO __NETIF_F(FSO) -#define NETIF_F_GRO __NETIF_F(GRO) -#define NETIF_F_GSO __NETIF_F(GSO) -#define NETIF_F_GSO_ROBUST __NETIF_F(GSO_ROBUST) -#define NETIF_F_HIGHDMA __NETIF_F(HIGHDMA) -#define NETIF_F_HW_CSUM __NETIF_F(HW_CSUM) -#define NETIF_F_HW_VLAN_CTAG_FILTER __NETIF_F(HW_VLAN_CTAG_FILTER) -#define NETIF_F_HW_VLAN_CTAG_RX __NETIF_F(HW_VLAN_CTAG_RX) -#define NETIF_F_HW_VLAN_CTAG_TX __NETIF_F(HW_VLAN_CTAG_TX) -#define NETIF_F_IP_CSUM __NETIF_F(IP_CSUM) -#define NETIF_F_IPV6_CSUM __NETIF_F(IPV6_CSUM) -#define NETIF_F_LLTX __NETIF_F(LLTX) -#define NETIF_F_LOOPBACK __NETIF_F(LOOPBACK) -#define NETIF_F_LRO __NETIF_F(LRO) -#define NETIF_F_NETNS_LOCAL __NETIF_F(NETNS_LOCAL) -#define NETIF_F_NOCACHE_COPY __NETIF_F(NOCACHE_COPY) -#define NETIF_F_NTUPLE __NETIF_F(NTUPLE) -#define NETIF_F_RXCSUM __NETIF_F(RXCSUM) -#define NETIF_F_RXHASH __NETIF_F(RXHASH) -#define NETIF_F_SCTP_CRC __NETIF_F(SCTP_CRC) -#define NETIF_F_SG __NETIF_F(SG) -#define NETIF_F_TSO6 __NETIF_F(TSO6) -#define NETIF_F_TSO_ECN __NETIF_F(TSO_ECN) -#define NETIF_F_TSO __NETIF_F(TSO) -#define NETIF_F_UFO __NETIF_F(UFO) -#define NETIF_F_VLAN_CHALLENGED __NETIF_F(VLAN_CHALLENGED) -#define NETIF_F_RXFCS __NETIF_F(RXFCS) -#define NETIF_F_RXALL __NETIF_F(RXALL) -#define NETIF_F_GSO_GRE __NETIF_F(GSO_GRE) -#define NETIF_F_GSO_GRE_CSUM __NETIF_F(GSO_GRE_CSUM) -#define NETIF_F_GSO_IPXIP4 __NETIF_F(GSO_IPXIP4) -#define NETIF_F_GSO_IPXIP6 __NETIF_F(GSO_IPXIP6) -#define NETIF_F_GSO_UDP_TUNNEL __NETIF_F(GSO_UDP_TUNNEL) -#define NETIF_F_GSO_UDP_TUNNEL_CSUM __NETIF_F(GSO_UDP_TUNNEL_CSUM) -#define NETIF_F_TSO_MANGLEID __NETIF_F(TSO_MANGLEID) -#define NETIF_F_GSO_PARTIAL __NETIF_F(GSO_PARTIAL) -#define NETIF_F_GSO_TUNNEL_REMCSUM __NETIF_F(GSO_TUNNEL_REMCSUM) -#define NETIF_F_GSO_SCTP __NETIF_F(GSO_SCTP) -#define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER) -#define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX) -#define NETIF_F_HW_VLAN_STAG_TX __NETIF_F(HW_VLAN_STAG_TX) -#define NETIF_F_HW_L2FW_DOFFLOAD __NETIF_F(HW_L2FW_DOFFLOAD) -#define NETIF_F_BUSY_POLL __NETIF_F(BUSY_POLL) -#define NETIF_F_HW_TC __NETIF_F(HW_TC) - -#define for_each_netdev_feature(mask_addr, bit) \ - for_each_set_bit(bit, (unsigned long *)mask_addr, NETDEV_FEATURE_COUNT) - -/* Features valid for ethtool to change */ -/* = all defined minus driver/device-class-related */ -#define NETIF_F_NEVER_CHANGE (NETIF_F_VLAN_CHALLENGED | \ - NETIF_F_LLTX | NETIF_F_NETNS_LOCAL) - -/* remember that ((t)1 << t_BITS) is undefined in C99 */ -#define NETIF_F_ETHTOOL_BITS ((__NETIF_F_BIT(NETDEV_FEATURE_COUNT - 1) | \ - (__NETIF_F_BIT(NETDEV_FEATURE_COUNT - 1) - 1)) & \ - ~NETIF_F_NEVER_CHANGE) - -/* Segmentation offload feature mask */ -#define NETIF_F_GSO_MASK (__NETIF_F_BIT(NETIF_F_GSO_LAST + 1) - \ - __NETIF_F_BIT(NETIF_F_GSO_SHIFT)) - -/* List of IP checksum features. Note that NETIF_F_ HW_CSUM should not be - * set in features when NETIF_F_IP_CSUM or NETIF_F_IPV6_CSUM are set-- - * this would be contradictory - */ -#define NETIF_F_CSUM_MASK (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | \ - NETIF_F_HW_CSUM) - -#define NETIF_F_ALL_TSO (NETIF_F_TSO | NETIF_F_TSO6 | \ - NETIF_F_TSO_ECN | NETIF_F_TSO_MANGLEID) - -#define NETIF_F_ALL_FCOE (NETIF_F_FCOE_CRC | NETIF_F_FCOE_MTU | \ - NETIF_F_FSO) - -/* List of features with software fallbacks. */ -#define NETIF_F_GSO_SOFTWARE (NETIF_F_ALL_TSO | NETIF_F_UFO | \ - NETIF_F_GSO_SCTP) - -/* - * If one device supports one of these features, then enable them - * for all in netdev_increment_features. - */ -#define NETIF_F_ONE_FOR_ALL (NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ROBUST | \ - NETIF_F_SG | NETIF_F_HIGHDMA | \ - NETIF_F_FRAGLIST | NETIF_F_VLAN_CHALLENGED) - -/* - * If one device doesn't support one of these features, then disable it - * for all in netdev_increment_features. - */ -#define NETIF_F_ALL_FOR_ALL (NETIF_F_NOCACHE_COPY | NETIF_F_FSO) - -/* - * If upper/master device has these features disabled, they must be disabled - * on all lower/slave devices as well. - */ -#define NETIF_F_UPPER_DISABLES NETIF_F_LRO - -/* changeable features with no special hardware requirements */ -#define NETIF_F_SOFT_FEATURES (NETIF_F_GSO | NETIF_F_GRO) - -#define NETIF_F_VLAN_FEATURES (NETIF_F_HW_VLAN_CTAG_FILTER | \ - NETIF_F_HW_VLAN_CTAG_RX | \ - NETIF_F_HW_VLAN_CTAG_TX | \ - NETIF_F_HW_VLAN_STAG_FILTER | \ - NETIF_F_HW_VLAN_STAG_RX | \ - NETIF_F_HW_VLAN_STAG_TX) - -#define NETIF_F_GSO_ENCAP_ALL (NETIF_F_GSO_GRE | \ - NETIF_F_GSO_GRE_CSUM | \ - NETIF_F_GSO_IPXIP4 | \ - NETIF_F_GSO_IPXIP6 | \ - NETIF_F_GSO_UDP_TUNNEL | \ - NETIF_F_GSO_UDP_TUNNEL_CSUM) - -#endif /* _LINUX_NETDEV_FEATURES_H */ diff --git a/src/linux/include/linux/netdevice.h b/src/linux/include/linux/netdevice.h deleted file mode 100644 index e16a2a9..0000000 --- a/src/linux/include/linux/netdevice.h +++ /dev/null @@ -1,4462 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the Interfaces handler. - * - * Version: @(#)dev.h 1.0.10 08/12/93 - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Corey Minyard - * Donald J. Becker, - * Alan Cox, - * Bjorn Ekwall. - * Pekka Riikonen - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Moved to /usr/include/linux for NET3 - */ -#ifndef _LINUX_NETDEVICE_H -#define _LINUX_NETDEVICE_H - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#ifdef CONFIG_DCB -#include -#endif -#include - -#include -#include -#include -#include -#include -#include - -struct netpoll_info; -struct device; -struct phy_device; -/* 802.11 specific */ -struct wireless_dev; -/* 802.15.4 specific */ -struct wpan_dev; -struct mpls_dev; -/* UDP Tunnel offloads */ -struct udp_tunnel_info; -struct bpf_prog; - -void netdev_set_default_ethtool_ops(struct net_device *dev, - const struct ethtool_ops *ops); - -/* Backlog congestion levels */ -#define NET_RX_SUCCESS 0 /* keep 'em coming, baby */ -#define NET_RX_DROP 1 /* packet dropped */ - -/* - * Transmit return codes: transmit return codes originate from three different - * namespaces: - * - * - qdisc return codes - * - driver transmit return codes - * - errno values - * - * Drivers are allowed to return any one of those in their hard_start_xmit() - * function. Real network devices commonly used with qdiscs should only return - * the driver transmit return codes though - when qdiscs are used, the actual - * transmission happens asynchronously, so the value is not propagated to - * higher layers. Virtual network devices transmit synchronously; in this case - * the driver transmit return codes are consumed by dev_queue_xmit(), and all - * others are propagated to higher layers. - */ - -/* qdisc ->enqueue() return codes. */ -#define NET_XMIT_SUCCESS 0x00 -#define NET_XMIT_DROP 0x01 /* skb dropped */ -#define NET_XMIT_CN 0x02 /* congestion notification */ -#define NET_XMIT_MASK 0x0f /* qdisc flags in net/sch_generic.h */ - -/* NET_XMIT_CN is special. It does not guarantee that this packet is lost. It - * indicates that the device will soon be dropping packets, or already drops - * some packets of the same priority; prompting us to send less aggressively. */ -#define net_xmit_eval(e) ((e) == NET_XMIT_CN ? 0 : (e)) -#define net_xmit_errno(e) ((e) != NET_XMIT_CN ? -ENOBUFS : 0) - -/* Driver transmit return codes */ -#define NETDEV_TX_MASK 0xf0 - -enum netdev_tx { - __NETDEV_TX_MIN = INT_MIN, /* make sure enum is signed */ - NETDEV_TX_OK = 0x00, /* driver took care of packet */ - NETDEV_TX_BUSY = 0x10, /* driver tx path was busy*/ -}; -typedef enum netdev_tx netdev_tx_t; - -/* - * Current order: NETDEV_TX_MASK > NET_XMIT_MASK >= 0 is significant; - * hard_start_xmit() return < NET_XMIT_MASK means skb was consumed. - */ -static inline bool dev_xmit_complete(int rc) -{ - /* - * Positive cases with an skb consumed by a driver: - * - successful transmission (rc == NETDEV_TX_OK) - * - error while transmitting (rc < 0) - * - error while queueing to a different device (rc & NET_XMIT_MASK) - */ - if (likely(rc < NET_XMIT_MASK)) - return true; - - return false; -} - -/* - * Compute the worst-case header length according to the protocols - * used. - */ - -#if defined(CONFIG_HYPERV_NET) -# define LL_MAX_HEADER 128 -#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25) -# if defined(CONFIG_MAC80211_MESH) -# define LL_MAX_HEADER 128 -# else -# define LL_MAX_HEADER 96 -# endif -#else -# define LL_MAX_HEADER 32 -#endif - -#if !IS_ENABLED(CONFIG_NET_IPIP) && !IS_ENABLED(CONFIG_NET_IPGRE) && \ - !IS_ENABLED(CONFIG_IPV6_SIT) && !IS_ENABLED(CONFIG_IPV6_TUNNEL) -#define MAX_HEADER LL_MAX_HEADER -#else -#define MAX_HEADER (LL_MAX_HEADER + 48) -#endif - -/* - * Old network device statistics. Fields are native words - * (unsigned long) so they can be read and written atomically. - */ - -struct net_device_stats { - unsigned long rx_packets; - unsigned long tx_packets; - unsigned long rx_bytes; - unsigned long tx_bytes; - unsigned long rx_errors; - unsigned long tx_errors; - unsigned long rx_dropped; - unsigned long tx_dropped; - unsigned long multicast; - unsigned long collisions; - unsigned long rx_length_errors; - unsigned long rx_over_errors; - unsigned long rx_crc_errors; - unsigned long rx_frame_errors; - unsigned long rx_fifo_errors; - unsigned long rx_missed_errors; - unsigned long tx_aborted_errors; - unsigned long tx_carrier_errors; - unsigned long tx_fifo_errors; - unsigned long tx_heartbeat_errors; - unsigned long tx_window_errors; - unsigned long rx_compressed; - unsigned long tx_compressed; -}; - - -#include -#include - -#ifdef CONFIG_RPS -#include -extern struct static_key rps_needed; -#endif - -struct neighbour; -struct neigh_parms; -struct sk_buff; - -struct netdev_hw_addr { - struct list_head list; - unsigned char addr[MAX_ADDR_LEN]; - unsigned char type; -#define NETDEV_HW_ADDR_T_LAN 1 -#define NETDEV_HW_ADDR_T_SAN 2 -#define NETDEV_HW_ADDR_T_SLAVE 3 -#define NETDEV_HW_ADDR_T_UNICAST 4 -#define NETDEV_HW_ADDR_T_MULTICAST 5 - bool global_use; - int sync_cnt; - int refcount; - int synced; - struct rcu_head rcu_head; -}; - -struct netdev_hw_addr_list { - struct list_head list; - int count; -}; - -#define netdev_hw_addr_list_count(l) ((l)->count) -#define netdev_hw_addr_list_empty(l) (netdev_hw_addr_list_count(l) == 0) -#define netdev_hw_addr_list_for_each(ha, l) \ - list_for_each_entry(ha, &(l)->list, list) - -#define netdev_uc_count(dev) netdev_hw_addr_list_count(&(dev)->uc) -#define netdev_uc_empty(dev) netdev_hw_addr_list_empty(&(dev)->uc) -#define netdev_for_each_uc_addr(ha, dev) \ - netdev_hw_addr_list_for_each(ha, &(dev)->uc) - -#define netdev_mc_count(dev) netdev_hw_addr_list_count(&(dev)->mc) -#define netdev_mc_empty(dev) netdev_hw_addr_list_empty(&(dev)->mc) -#define netdev_for_each_mc_addr(ha, dev) \ - netdev_hw_addr_list_for_each(ha, &(dev)->mc) - -struct hh_cache { - u16 hh_len; - u16 __pad; - seqlock_t hh_lock; - - /* cached hardware header; allow for machine alignment needs. */ -#define HH_DATA_MOD 16 -#define HH_DATA_OFF(__len) \ - (HH_DATA_MOD - (((__len - 1) & (HH_DATA_MOD - 1)) + 1)) -#define HH_DATA_ALIGN(__len) \ - (((__len)+(HH_DATA_MOD-1))&~(HH_DATA_MOD - 1)) - unsigned long hh_data[HH_DATA_ALIGN(LL_MAX_HEADER) / sizeof(long)]; -}; - -/* Reserve HH_DATA_MOD byte-aligned hard_header_len, but at least that much. - * Alternative is: - * dev->hard_header_len ? (dev->hard_header_len + - * (HH_DATA_MOD - 1)) & ~(HH_DATA_MOD - 1) : 0 - * - * We could use other alignment values, but we must maintain the - * relationship HH alignment <= LL alignment. - */ -#define LL_RESERVED_SPACE(dev) \ - ((((dev)->hard_header_len+(dev)->needed_headroom)&~(HH_DATA_MOD - 1)) + HH_DATA_MOD) -#define LL_RESERVED_SPACE_EXTRA(dev,extra) \ - ((((dev)->hard_header_len+(dev)->needed_headroom+(extra))&~(HH_DATA_MOD - 1)) + HH_DATA_MOD) - -struct header_ops { - int (*create) (struct sk_buff *skb, struct net_device *dev, - unsigned short type, const void *daddr, - const void *saddr, unsigned int len); - int (*parse)(const struct sk_buff *skb, unsigned char *haddr); - int (*cache)(const struct neighbour *neigh, struct hh_cache *hh, __be16 type); - void (*cache_update)(struct hh_cache *hh, - const struct net_device *dev, - const unsigned char *haddr); - bool (*validate)(const char *ll_header, unsigned int len); -}; - -/* These flag bits are private to the generic network queueing - * layer; they may not be explicitly referenced by any other - * code. - */ - -enum netdev_state_t { - __LINK_STATE_START, - __LINK_STATE_PRESENT, - __LINK_STATE_NOCARRIER, - __LINK_STATE_LINKWATCH_PENDING, - __LINK_STATE_DORMANT, -}; - - -/* - * This structure holds boot-time configured netdevice settings. They - * are then used in the device probing. - */ -struct netdev_boot_setup { - char name[IFNAMSIZ]; - struct ifmap map; -}; -#define NETDEV_BOOT_SETUP_MAX 8 - -int __init netdev_boot_setup(char *str); - -/* - * Structure for NAPI scheduling similar to tasklet but with weighting - */ -struct napi_struct { - /* The poll_list must only be managed by the entity which - * changes the state of the NAPI_STATE_SCHED bit. This means - * whoever atomically sets that bit can add this napi_struct - * to the per-CPU poll_list, and whoever clears that bit - * can remove from the list right before clearing the bit. - */ - struct list_head poll_list; - - unsigned long state; - int weight; - unsigned int gro_count; - int (*poll)(struct napi_struct *, int); -#ifdef CONFIG_NETPOLL - spinlock_t poll_lock; - int poll_owner; -#endif - struct net_device *dev; - struct sk_buff *gro_list; - struct sk_buff *skb; - struct hrtimer timer; - struct list_head dev_list; - struct hlist_node napi_hash_node; - unsigned int napi_id; -}; - -enum { - NAPI_STATE_SCHED, /* Poll is scheduled */ - NAPI_STATE_DISABLE, /* Disable pending */ - NAPI_STATE_NPSVC, /* Netpoll - don't dequeue from poll_list */ - NAPI_STATE_HASHED, /* In NAPI hash (busy polling possible) */ - NAPI_STATE_NO_BUSY_POLL,/* Do not add in napi_hash, no busy polling */ -}; - -enum gro_result { - GRO_MERGED, - GRO_MERGED_FREE, - GRO_HELD, - GRO_NORMAL, - GRO_DROP, -}; -typedef enum gro_result gro_result_t; - -/* - * enum rx_handler_result - Possible return values for rx_handlers. - * @RX_HANDLER_CONSUMED: skb was consumed by rx_handler, do not process it - * further. - * @RX_HANDLER_ANOTHER: Do another round in receive path. This is indicated in - * case skb->dev was changed by rx_handler. - * @RX_HANDLER_EXACT: Force exact delivery, no wildcard. - * @RX_HANDLER_PASS: Do nothing, pass the skb as if no rx_handler was called. - * - * rx_handlers are functions called from inside __netif_receive_skb(), to do - * special processing of the skb, prior to delivery to protocol handlers. - * - * Currently, a net_device can only have a single rx_handler registered. Trying - * to register a second rx_handler will return -EBUSY. - * - * To register a rx_handler on a net_device, use netdev_rx_handler_register(). - * To unregister a rx_handler on a net_device, use - * netdev_rx_handler_unregister(). - * - * Upon return, rx_handler is expected to tell __netif_receive_skb() what to - * do with the skb. - * - * If the rx_handler consumed the skb in some way, it should return - * RX_HANDLER_CONSUMED. This is appropriate when the rx_handler arranged for - * the skb to be delivered in some other way. - * - * If the rx_handler changed skb->dev, to divert the skb to another - * net_device, it should return RX_HANDLER_ANOTHER. The rx_handler for the - * new device will be called if it exists. - * - * If the rx_handler decides the skb should be ignored, it should return - * RX_HANDLER_EXACT. The skb will only be delivered to protocol handlers that - * are registered on exact device (ptype->dev == skb->dev). - * - * If the rx_handler didn't change skb->dev, but wants the skb to be normally - * delivered, it should return RX_HANDLER_PASS. - * - * A device without a registered rx_handler will behave as if rx_handler - * returned RX_HANDLER_PASS. - */ - -enum rx_handler_result { - RX_HANDLER_CONSUMED, - RX_HANDLER_ANOTHER, - RX_HANDLER_EXACT, - RX_HANDLER_PASS, -}; -typedef enum rx_handler_result rx_handler_result_t; -typedef rx_handler_result_t rx_handler_func_t(struct sk_buff **pskb); - -void __napi_schedule(struct napi_struct *n); -void __napi_schedule_irqoff(struct napi_struct *n); - -static inline bool napi_disable_pending(struct napi_struct *n) -{ - return test_bit(NAPI_STATE_DISABLE, &n->state); -} - -/** - * napi_schedule_prep - check if NAPI can be scheduled - * @n: NAPI context - * - * Test if NAPI routine is already running, and if not mark - * it as running. This is used as a condition variable to - * insure only one NAPI poll instance runs. We also make - * sure there is no pending NAPI disable. - */ -static inline bool napi_schedule_prep(struct napi_struct *n) -{ - return !napi_disable_pending(n) && - !test_and_set_bit(NAPI_STATE_SCHED, &n->state); -} - -/** - * napi_schedule - schedule NAPI poll - * @n: NAPI context - * - * Schedule NAPI poll routine to be called if it is not already - * running. - */ -static inline void napi_schedule(struct napi_struct *n) -{ - if (napi_schedule_prep(n)) - __napi_schedule(n); -} - -/** - * napi_schedule_irqoff - schedule NAPI poll - * @n: NAPI context - * - * Variant of napi_schedule(), assuming hard irqs are masked. - */ -static inline void napi_schedule_irqoff(struct napi_struct *n) -{ - if (napi_schedule_prep(n)) - __napi_schedule_irqoff(n); -} - -/* Try to reschedule poll. Called by dev->poll() after napi_complete(). */ -static inline bool napi_reschedule(struct napi_struct *napi) -{ - if (napi_schedule_prep(napi)) { - __napi_schedule(napi); - return true; - } - return false; -} - -void __napi_complete(struct napi_struct *n); -void napi_complete_done(struct napi_struct *n, int work_done); -/** - * napi_complete - NAPI processing complete - * @n: NAPI context - * - * Mark NAPI processing as complete. - * Consider using napi_complete_done() instead. - */ -static inline void napi_complete(struct napi_struct *n) -{ - return napi_complete_done(n, 0); -} - -/** - * napi_hash_add - add a NAPI to global hashtable - * @napi: NAPI context - * - * Generate a new napi_id and store a @napi under it in napi_hash. - * Used for busy polling (CONFIG_NET_RX_BUSY_POLL). - * Note: This is normally automatically done from netif_napi_add(), - * so might disappear in a future Linux version. - */ -void napi_hash_add(struct napi_struct *napi); - -/** - * napi_hash_del - remove a NAPI from global table - * @napi: NAPI context - * - * Warning: caller must observe RCU grace period - * before freeing memory containing @napi, if - * this function returns true. - * Note: core networking stack automatically calls it - * from netif_napi_del(). - * Drivers might want to call this helper to combine all - * the needed RCU grace periods into a single one. - */ -bool napi_hash_del(struct napi_struct *napi); - -/** - * napi_disable - prevent NAPI from scheduling - * @n: NAPI context - * - * Stop NAPI from being scheduled on this context. - * Waits till any outstanding processing completes. - */ -void napi_disable(struct napi_struct *n); - -/** - * napi_enable - enable NAPI scheduling - * @n: NAPI context - * - * Resume NAPI from being scheduled on this context. - * Must be paired with napi_disable. - */ -static inline void napi_enable(struct napi_struct *n) -{ - BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); - smp_mb__before_atomic(); - clear_bit(NAPI_STATE_SCHED, &n->state); - clear_bit(NAPI_STATE_NPSVC, &n->state); -} - -/** - * napi_synchronize - wait until NAPI is not running - * @n: NAPI context - * - * Wait until NAPI is done being scheduled on this context. - * Waits till any outstanding processing completes but - * does not disable future activations. - */ -static inline void napi_synchronize(const struct napi_struct *n) -{ - if (IS_ENABLED(CONFIG_SMP)) - while (test_bit(NAPI_STATE_SCHED, &n->state)) - msleep(1); - else - barrier(); -} - -enum netdev_queue_state_t { - __QUEUE_STATE_DRV_XOFF, - __QUEUE_STATE_STACK_XOFF, - __QUEUE_STATE_FROZEN, -}; - -#define QUEUE_STATE_DRV_XOFF (1 << __QUEUE_STATE_DRV_XOFF) -#define QUEUE_STATE_STACK_XOFF (1 << __QUEUE_STATE_STACK_XOFF) -#define QUEUE_STATE_FROZEN (1 << __QUEUE_STATE_FROZEN) - -#define QUEUE_STATE_ANY_XOFF (QUEUE_STATE_DRV_XOFF | QUEUE_STATE_STACK_XOFF) -#define QUEUE_STATE_ANY_XOFF_OR_FROZEN (QUEUE_STATE_ANY_XOFF | \ - QUEUE_STATE_FROZEN) -#define QUEUE_STATE_DRV_XOFF_OR_FROZEN (QUEUE_STATE_DRV_XOFF | \ - QUEUE_STATE_FROZEN) - -/* - * __QUEUE_STATE_DRV_XOFF is used by drivers to stop the transmit queue. The - * netif_tx_* functions below are used to manipulate this flag. The - * __QUEUE_STATE_STACK_XOFF flag is used by the stack to stop the transmit - * queue independently. The netif_xmit_*stopped functions below are called - * to check if the queue has been stopped by the driver or stack (either - * of the XOFF bits are set in the state). Drivers should not need to call - * netif_xmit*stopped functions, they should only be using netif_tx_*. - */ - -struct netdev_queue { -/* - * read-mostly part - */ - struct net_device *dev; - struct Qdisc __rcu *qdisc; - struct Qdisc *qdisc_sleeping; -#ifdef CONFIG_SYSFS - struct kobject kobj; -#endif -#if defined(CONFIG_XPS) && defined(CONFIG_NUMA) - int numa_node; -#endif - unsigned long tx_maxrate; - /* - * Number of TX timeouts for this queue - * (/sys/class/net/DEV/Q/trans_timeout) - */ - unsigned long trans_timeout; -/* - * write-mostly part - */ - spinlock_t _xmit_lock ____cacheline_aligned_in_smp; - int xmit_lock_owner; - /* - * Time (in jiffies) of last Tx - */ - unsigned long trans_start; - - unsigned long state; - -#ifdef CONFIG_BQL - struct dql dql; -#endif -} ____cacheline_aligned_in_smp; - -static inline int netdev_queue_numa_node_read(const struct netdev_queue *q) -{ -#if defined(CONFIG_XPS) && defined(CONFIG_NUMA) - return q->numa_node; -#else - return NUMA_NO_NODE; -#endif -} - -static inline void netdev_queue_numa_node_write(struct netdev_queue *q, int node) -{ -#if defined(CONFIG_XPS) && defined(CONFIG_NUMA) - q->numa_node = node; -#endif -} - -#ifdef CONFIG_RPS -/* - * This structure holds an RPS map which can be of variable length. The - * map is an array of CPUs. - */ -struct rps_map { - unsigned int len; - struct rcu_head rcu; - u16 cpus[0]; -}; -#define RPS_MAP_SIZE(_num) (sizeof(struct rps_map) + ((_num) * sizeof(u16))) - -/* - * The rps_dev_flow structure contains the mapping of a flow to a CPU, the - * tail pointer for that CPU's input queue at the time of last enqueue, and - * a hardware filter index. - */ -struct rps_dev_flow { - u16 cpu; - u16 filter; - unsigned int last_qtail; -}; -#define RPS_NO_FILTER 0xffff - -/* - * The rps_dev_flow_table structure contains a table of flow mappings. - */ -struct rps_dev_flow_table { - unsigned int mask; - struct rcu_head rcu; - struct rps_dev_flow flows[0]; -}; -#define RPS_DEV_FLOW_TABLE_SIZE(_num) (sizeof(struct rps_dev_flow_table) + \ - ((_num) * sizeof(struct rps_dev_flow))) - -/* - * The rps_sock_flow_table contains mappings of flows to the last CPU - * on which they were processed by the application (set in recvmsg). - * Each entry is a 32bit value. Upper part is the high-order bits - * of flow hash, lower part is CPU number. - * rps_cpu_mask is used to partition the space, depending on number of - * possible CPUs : rps_cpu_mask = roundup_pow_of_two(nr_cpu_ids) - 1 - * For example, if 64 CPUs are possible, rps_cpu_mask = 0x3f, - * meaning we use 32-6=26 bits for the hash. - */ -struct rps_sock_flow_table { - u32 mask; - - u32 ents[0] ____cacheline_aligned_in_smp; -}; -#define RPS_SOCK_FLOW_TABLE_SIZE(_num) (offsetof(struct rps_sock_flow_table, ents[_num])) - -#define RPS_NO_CPU 0xffff - -extern u32 rps_cpu_mask; -extern struct rps_sock_flow_table __rcu *rps_sock_flow_table; - -static inline void rps_record_sock_flow(struct rps_sock_flow_table *table, - u32 hash) -{ - if (table && hash) { - unsigned int index = hash & table->mask; - u32 val = hash & ~rps_cpu_mask; - - /* We only give a hint, preemption can change CPU under us */ - val |= raw_smp_processor_id(); - - if (table->ents[index] != val) - table->ents[index] = val; - } -} - -#ifdef CONFIG_RFS_ACCEL -bool rps_may_expire_flow(struct net_device *dev, u16 rxq_index, u32 flow_id, - u16 filter_id); -#endif -#endif /* CONFIG_RPS */ - -/* This structure contains an instance of an RX queue. */ -struct netdev_rx_queue { -#ifdef CONFIG_RPS - struct rps_map __rcu *rps_map; - struct rps_dev_flow_table __rcu *rps_flow_table; -#endif - struct kobject kobj; - struct net_device *dev; -} ____cacheline_aligned_in_smp; - -/* - * RX queue sysfs structures and functions. - */ -struct rx_queue_attribute { - struct attribute attr; - ssize_t (*show)(struct netdev_rx_queue *queue, - struct rx_queue_attribute *attr, char *buf); - ssize_t (*store)(struct netdev_rx_queue *queue, - struct rx_queue_attribute *attr, const char *buf, size_t len); -}; - -#ifdef CONFIG_XPS -/* - * This structure holds an XPS map which can be of variable length. The - * map is an array of queues. - */ -struct xps_map { - unsigned int len; - unsigned int alloc_len; - struct rcu_head rcu; - u16 queues[0]; -}; -#define XPS_MAP_SIZE(_num) (sizeof(struct xps_map) + ((_num) * sizeof(u16))) -#define XPS_MIN_MAP_ALLOC ((L1_CACHE_ALIGN(offsetof(struct xps_map, queues[1])) \ - - sizeof(struct xps_map)) / sizeof(u16)) - -/* - * This structure holds all XPS maps for device. Maps are indexed by CPU. - */ -struct xps_dev_maps { - struct rcu_head rcu; - struct xps_map __rcu *cpu_map[0]; -}; -#define XPS_DEV_MAPS_SIZE (sizeof(struct xps_dev_maps) + \ - (nr_cpu_ids * sizeof(struct xps_map *))) -#endif /* CONFIG_XPS */ - -#define TC_MAX_QUEUE 16 -#define TC_BITMASK 15 -/* HW offloaded queuing disciplines txq count and offset maps */ -struct netdev_tc_txq { - u16 count; - u16 offset; -}; - -#if defined(CONFIG_FCOE) || defined(CONFIG_FCOE_MODULE) -/* - * This structure is to hold information about the device - * configured to run FCoE protocol stack. - */ -struct netdev_fcoe_hbainfo { - char manufacturer[64]; - char serial_number[64]; - char hardware_version[64]; - char driver_version[64]; - char optionrom_version[64]; - char firmware_version[64]; - char model[256]; - char model_description[256]; -}; -#endif - -#define MAX_PHYS_ITEM_ID_LEN 32 - -/* This structure holds a unique identifier to identify some - * physical item (port for example) used by a netdevice. - */ -struct netdev_phys_item_id { - unsigned char id[MAX_PHYS_ITEM_ID_LEN]; - unsigned char id_len; -}; - -static inline bool netdev_phys_item_id_same(struct netdev_phys_item_id *a, - struct netdev_phys_item_id *b) -{ - return a->id_len == b->id_len && - memcmp(a->id, b->id, a->id_len) == 0; -} - -typedef u16 (*select_queue_fallback_t)(struct net_device *dev, - struct sk_buff *skb); - -/* These structures hold the attributes of qdisc and classifiers - * that are being passed to the netdevice through the setup_tc op. - */ -enum { - TC_SETUP_MQPRIO, - TC_SETUP_CLSU32, - TC_SETUP_CLSFLOWER, - TC_SETUP_MATCHALL, - TC_SETUP_CLSBPF, -}; - -struct tc_cls_u32_offload; - -struct tc_to_netdev { - unsigned int type; - union { - u8 tc; - struct tc_cls_u32_offload *cls_u32; - struct tc_cls_flower_offload *cls_flower; - struct tc_cls_matchall_offload *cls_mall; - struct tc_cls_bpf_offload *cls_bpf; - }; -}; - -/* These structures hold the attributes of xdp state that are being passed - * to the netdevice through the xdp op. - */ -enum xdp_netdev_command { - /* Set or clear a bpf program used in the earliest stages of packet - * rx. The prog will have been loaded as BPF_PROG_TYPE_XDP. The callee - * is responsible for calling bpf_prog_put on any old progs that are - * stored. In case of error, the callee need not release the new prog - * reference, but on success it takes ownership and must bpf_prog_put - * when it is no longer used. - */ - XDP_SETUP_PROG, - /* Check if a bpf program is set on the device. The callee should - * return true if a program is currently attached and running. - */ - XDP_QUERY_PROG, -}; - -struct netdev_xdp { - enum xdp_netdev_command command; - union { - /* XDP_SETUP_PROG */ - struct bpf_prog *prog; - /* XDP_QUERY_PROG */ - bool prog_attached; - }; -}; - -/* - * This structure defines the management hooks for network devices. - * The following hooks can be defined; unless noted otherwise, they are - * optional and can be filled with a null pointer. - * - * int (*ndo_init)(struct net_device *dev); - * This function is called once when a network device is registered. - * The network device can use this for any late stage initialization - * or semantic validation. It can fail with an error code which will - * be propagated back to register_netdev. - * - * void (*ndo_uninit)(struct net_device *dev); - * This function is called when device is unregistered or when registration - * fails. It is not called if init fails. - * - * int (*ndo_open)(struct net_device *dev); - * This function is called when a network device transitions to the up - * state. - * - * int (*ndo_stop)(struct net_device *dev); - * This function is called when a network device transitions to the down - * state. - * - * netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb, - * struct net_device *dev); - * Called when a packet needs to be transmitted. - * Returns NETDEV_TX_OK. Can return NETDEV_TX_BUSY, but you should stop - * the queue before that can happen; it's for obsolete devices and weird - * corner cases, but the stack really does a non-trivial amount - * of useless work if you return NETDEV_TX_BUSY. - * Required; cannot be NULL. - * - * netdev_features_t (*ndo_fix_features)(struct net_device *dev, - * netdev_features_t features); - * Adjusts the requested feature flags according to device-specific - * constraints, and returns the resulting flags. Must not modify - * the device state. - * - * u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb, - * void *accel_priv, select_queue_fallback_t fallback); - * Called to decide which queue to use when device supports multiple - * transmit queues. - * - * void (*ndo_change_rx_flags)(struct net_device *dev, int flags); - * This function is called to allow device receiver to make - * changes to configuration when multicast or promiscuous is enabled. - * - * void (*ndo_set_rx_mode)(struct net_device *dev); - * This function is called device changes address list filtering. - * If driver handles unicast address filtering, it should set - * IFF_UNICAST_FLT in its priv_flags. - * - * int (*ndo_set_mac_address)(struct net_device *dev, void *addr); - * This function is called when the Media Access Control address - * needs to be changed. If this interface is not defined, the - * MAC address can not be changed. - * - * int (*ndo_validate_addr)(struct net_device *dev); - * Test if Media Access Control address is valid for the device. - * - * int (*ndo_do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd); - * Called when a user requests an ioctl which can't be handled by - * the generic interface code. If not defined ioctls return - * not supported error code. - * - * int (*ndo_set_config)(struct net_device *dev, struct ifmap *map); - * Used to set network devices bus interface parameters. This interface - * is retained for legacy reasons; new devices should use the bus - * interface (PCI) for low level management. - * - * int (*ndo_change_mtu)(struct net_device *dev, int new_mtu); - * Called when a user wants to change the Maximum Transfer Unit - * of a device. If not defined, any request to change MTU will - * will return an error. - * - * void (*ndo_tx_timeout)(struct net_device *dev); - * Callback used when the transmitter has not made any progress - * for dev->watchdog ticks. - * - * struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev, - * struct rtnl_link_stats64 *storage); - * struct net_device_stats* (*ndo_get_stats)(struct net_device *dev); - * Called when a user wants to get the network device usage - * statistics. Drivers must do one of the following: - * 1. Define @ndo_get_stats64 to fill in a zero-initialised - * rtnl_link_stats64 structure passed by the caller. - * 2. Define @ndo_get_stats to update a net_device_stats structure - * (which should normally be dev->stats) and return a pointer to - * it. The structure may be changed asynchronously only if each - * field is written atomically. - * 3. Update dev->stats asynchronously and atomically, and define - * neither operation. - * - * bool (*ndo_has_offload_stats)(int attr_id) - * Return true if this device supports offload stats of this attr_id. - * - * int (*ndo_get_offload_stats)(int attr_id, const struct net_device *dev, - * void *attr_data) - * Get statistics for offload operations by attr_id. Write it into the - * attr_data pointer. - * - * int (*ndo_vlan_rx_add_vid)(struct net_device *dev, __be16 proto, u16 vid); - * If device supports VLAN filtering this function is called when a - * VLAN id is registered. - * - * int (*ndo_vlan_rx_kill_vid)(struct net_device *dev, __be16 proto, u16 vid); - * If device supports VLAN filtering this function is called when a - * VLAN id is unregistered. - * - * void (*ndo_poll_controller)(struct net_device *dev); - * - * SR-IOV management functions. - * int (*ndo_set_vf_mac)(struct net_device *dev, int vf, u8* mac); - * int (*ndo_set_vf_vlan)(struct net_device *dev, int vf, u16 vlan, - * u8 qos, __be16 proto); - * int (*ndo_set_vf_rate)(struct net_device *dev, int vf, int min_tx_rate, - * int max_tx_rate); - * int (*ndo_set_vf_spoofchk)(struct net_device *dev, int vf, bool setting); - * int (*ndo_set_vf_trust)(struct net_device *dev, int vf, bool setting); - * int (*ndo_get_vf_config)(struct net_device *dev, - * int vf, struct ifla_vf_info *ivf); - * int (*ndo_set_vf_link_state)(struct net_device *dev, int vf, int link_state); - * int (*ndo_set_vf_port)(struct net_device *dev, int vf, - * struct nlattr *port[]); - * - * Enable or disable the VF ability to query its RSS Redirection Table and - * Hash Key. This is needed since on some devices VF share this information - * with PF and querying it may introduce a theoretical security risk. - * int (*ndo_set_vf_rss_query_en)(struct net_device *dev, int vf, bool setting); - * int (*ndo_get_vf_port)(struct net_device *dev, int vf, struct sk_buff *skb); - * int (*ndo_setup_tc)(struct net_device *dev, u8 tc) - * Called to setup 'tc' number of traffic classes in the net device. This - * is always called from the stack with the rtnl lock held and netif tx - * queues stopped. This allows the netdevice to perform queue management - * safely. - * - * Fiber Channel over Ethernet (FCoE) offload functions. - * int (*ndo_fcoe_enable)(struct net_device *dev); - * Called when the FCoE protocol stack wants to start using LLD for FCoE - * so the underlying device can perform whatever needed configuration or - * initialization to support acceleration of FCoE traffic. - * - * int (*ndo_fcoe_disable)(struct net_device *dev); - * Called when the FCoE protocol stack wants to stop using LLD for FCoE - * so the underlying device can perform whatever needed clean-ups to - * stop supporting acceleration of FCoE traffic. - * - * int (*ndo_fcoe_ddp_setup)(struct net_device *dev, u16 xid, - * struct scatterlist *sgl, unsigned int sgc); - * Called when the FCoE Initiator wants to initialize an I/O that - * is a possible candidate for Direct Data Placement (DDP). The LLD can - * perform necessary setup and returns 1 to indicate the device is set up - * successfully to perform DDP on this I/O, otherwise this returns 0. - * - * int (*ndo_fcoe_ddp_done)(struct net_device *dev, u16 xid); - * Called when the FCoE Initiator/Target is done with the DDPed I/O as - * indicated by the FC exchange id 'xid', so the underlying device can - * clean up and reuse resources for later DDP requests. - * - * int (*ndo_fcoe_ddp_target)(struct net_device *dev, u16 xid, - * struct scatterlist *sgl, unsigned int sgc); - * Called when the FCoE Target wants to initialize an I/O that - * is a possible candidate for Direct Data Placement (DDP). The LLD can - * perform necessary setup and returns 1 to indicate the device is set up - * successfully to perform DDP on this I/O, otherwise this returns 0. - * - * int (*ndo_fcoe_get_hbainfo)(struct net_device *dev, - * struct netdev_fcoe_hbainfo *hbainfo); - * Called when the FCoE Protocol stack wants information on the underlying - * device. This information is utilized by the FCoE protocol stack to - * register attributes with Fiber Channel management service as per the - * FC-GS Fabric Device Management Information(FDMI) specification. - * - * int (*ndo_fcoe_get_wwn)(struct net_device *dev, u64 *wwn, int type); - * Called when the underlying device wants to override default World Wide - * Name (WWN) generation mechanism in FCoE protocol stack to pass its own - * World Wide Port Name (WWPN) or World Wide Node Name (WWNN) to the FCoE - * protocol stack to use. - * - * RFS acceleration. - * int (*ndo_rx_flow_steer)(struct net_device *dev, const struct sk_buff *skb, - * u16 rxq_index, u32 flow_id); - * Set hardware filter for RFS. rxq_index is the target queue index; - * flow_id is a flow ID to be passed to rps_may_expire_flow() later. - * Return the filter ID on success, or a negative error code. - * - * Slave management functions (for bridge, bonding, etc). - * int (*ndo_add_slave)(struct net_device *dev, struct net_device *slave_dev); - * Called to make another netdev an underling. - * - * int (*ndo_del_slave)(struct net_device *dev, struct net_device *slave_dev); - * Called to release previously enslaved netdev. - * - * Feature/offload setting functions. - * int (*ndo_set_features)(struct net_device *dev, netdev_features_t features); - * Called to update device configuration to new features. Passed - * feature set might be less than what was returned by ndo_fix_features()). - * Must return >0 or -errno if it changed dev->features itself. - * - * int (*ndo_fdb_add)(struct ndmsg *ndm, struct nlattr *tb[], - * struct net_device *dev, - * const unsigned char *addr, u16 vid, u16 flags) - * Adds an FDB entry to dev for addr. - * int (*ndo_fdb_del)(struct ndmsg *ndm, struct nlattr *tb[], - * struct net_device *dev, - * const unsigned char *addr, u16 vid) - * Deletes the FDB entry from dev coresponding to addr. - * int (*ndo_fdb_dump)(struct sk_buff *skb, struct netlink_callback *cb, - * struct net_device *dev, struct net_device *filter_dev, - * int *idx) - * Used to add FDB entries to dump requests. Implementers should add - * entries to skb and update idx with the number of entries. - * - * int (*ndo_bridge_setlink)(struct net_device *dev, struct nlmsghdr *nlh, - * u16 flags) - * int (*ndo_bridge_getlink)(struct sk_buff *skb, u32 pid, u32 seq, - * struct net_device *dev, u32 filter_mask, - * int nlflags) - * int (*ndo_bridge_dellink)(struct net_device *dev, struct nlmsghdr *nlh, - * u16 flags); - * - * int (*ndo_change_carrier)(struct net_device *dev, bool new_carrier); - * Called to change device carrier. Soft-devices (like dummy, team, etc) - * which do not represent real hardware may define this to allow their - * userspace components to manage their virtual carrier state. Devices - * that determine carrier state from physical hardware properties (eg - * network cables) or protocol-dependent mechanisms (eg - * USB_CDC_NOTIFY_NETWORK_CONNECTION) should NOT implement this function. - * - * int (*ndo_get_phys_port_id)(struct net_device *dev, - * struct netdev_phys_item_id *ppid); - * Called to get ID of physical port of this device. If driver does - * not implement this, it is assumed that the hw is not able to have - * multiple net devices on single physical port. - * - * void (*ndo_udp_tunnel_add)(struct net_device *dev, - * struct udp_tunnel_info *ti); - * Called by UDP tunnel to notify a driver about the UDP port and socket - * address family that a UDP tunnel is listnening to. It is called only - * when a new port starts listening. The operation is protected by the - * RTNL. - * - * void (*ndo_udp_tunnel_del)(struct net_device *dev, - * struct udp_tunnel_info *ti); - * Called by UDP tunnel to notify the driver about a UDP port and socket - * address family that the UDP tunnel is not listening to anymore. The - * operation is protected by the RTNL. - * - * void* (*ndo_dfwd_add_station)(struct net_device *pdev, - * struct net_device *dev) - * Called by upper layer devices to accelerate switching or other - * station functionality into hardware. 'pdev is the lowerdev - * to use for the offload and 'dev' is the net device that will - * back the offload. Returns a pointer to the private structure - * the upper layer will maintain. - * void (*ndo_dfwd_del_station)(struct net_device *pdev, void *priv) - * Called by upper layer device to delete the station created - * by 'ndo_dfwd_add_station'. 'pdev' is the net device backing - * the station and priv is the structure returned by the add - * operation. - * netdev_tx_t (*ndo_dfwd_start_xmit)(struct sk_buff *skb, - * struct net_device *dev, - * void *priv); - * Callback to use for xmit over the accelerated station. This - * is used in place of ndo_start_xmit on accelerated net - * devices. - * netdev_features_t (*ndo_features_check)(struct sk_buff *skb, - * struct net_device *dev - * netdev_features_t features); - * Called by core transmit path to determine if device is capable of - * performing offload operations on a given packet. This is to give - * the device an opportunity to implement any restrictions that cannot - * be otherwise expressed by feature flags. The check is called with - * the set of features that the stack has calculated and it returns - * those the driver believes to be appropriate. - * int (*ndo_set_tx_maxrate)(struct net_device *dev, - * int queue_index, u32 maxrate); - * Called when a user wants to set a max-rate limitation of specific - * TX queue. - * int (*ndo_get_iflink)(const struct net_device *dev); - * Called to get the iflink value of this device. - * void (*ndo_change_proto_down)(struct net_device *dev, - * bool proto_down); - * This function is used to pass protocol port error state information - * to the switch driver. The switch driver can react to the proto_down - * by doing a phys down on the associated switch port. - * int (*ndo_fill_metadata_dst)(struct net_device *dev, struct sk_buff *skb); - * This function is used to get egress tunnel information for given skb. - * This is useful for retrieving outer tunnel header parameters while - * sampling packet. - * void (*ndo_set_rx_headroom)(struct net_device *dev, int needed_headroom); - * This function is used to specify the headroom that the skb must - * consider when allocation skb during packet reception. Setting - * appropriate rx headroom value allows avoiding skb head copy on - * forward. Setting a negative value resets the rx headroom to the - * default value. - * int (*ndo_xdp)(struct net_device *dev, struct netdev_xdp *xdp); - * This function is used to set or query state related to XDP on the - * netdevice. See definition of enum xdp_netdev_command for details. - * - */ -struct net_device_ops { - int (*ndo_init)(struct net_device *dev); - void (*ndo_uninit)(struct net_device *dev); - int (*ndo_open)(struct net_device *dev); - int (*ndo_stop)(struct net_device *dev); - netdev_tx_t (*ndo_start_xmit)(struct sk_buff *skb, - struct net_device *dev); - netdev_features_t (*ndo_features_check)(struct sk_buff *skb, - struct net_device *dev, - netdev_features_t features); - u16 (*ndo_select_queue)(struct net_device *dev, - struct sk_buff *skb, - void *accel_priv, - select_queue_fallback_t fallback); - void (*ndo_change_rx_flags)(struct net_device *dev, - int flags); - void (*ndo_set_rx_mode)(struct net_device *dev); - int (*ndo_set_mac_address)(struct net_device *dev, - void *addr); - int (*ndo_validate_addr)(struct net_device *dev); - int (*ndo_do_ioctl)(struct net_device *dev, - struct ifreq *ifr, int cmd); - int (*ndo_set_config)(struct net_device *dev, - struct ifmap *map); - int (*ndo_change_mtu)(struct net_device *dev, - int new_mtu); - int (*ndo_neigh_setup)(struct net_device *dev, - struct neigh_parms *); - void (*ndo_tx_timeout) (struct net_device *dev); - - struct rtnl_link_stats64* (*ndo_get_stats64)(struct net_device *dev, - struct rtnl_link_stats64 *storage); - bool (*ndo_has_offload_stats)(int attr_id); - int (*ndo_get_offload_stats)(int attr_id, - const struct net_device *dev, - void *attr_data); - struct net_device_stats* (*ndo_get_stats)(struct net_device *dev); - - int (*ndo_vlan_rx_add_vid)(struct net_device *dev, - __be16 proto, u16 vid); - int (*ndo_vlan_rx_kill_vid)(struct net_device *dev, - __be16 proto, u16 vid); -#ifdef CONFIG_NET_POLL_CONTROLLER - void (*ndo_poll_controller)(struct net_device *dev); - int (*ndo_netpoll_setup)(struct net_device *dev, - struct netpoll_info *info); - void (*ndo_netpoll_cleanup)(struct net_device *dev); -#endif -#ifdef CONFIG_NET_RX_BUSY_POLL - int (*ndo_busy_poll)(struct napi_struct *dev); -#endif - int (*ndo_set_vf_mac)(struct net_device *dev, - int queue, u8 *mac); - int (*ndo_set_vf_vlan)(struct net_device *dev, - int queue, u16 vlan, - u8 qos, __be16 proto); - int (*ndo_set_vf_rate)(struct net_device *dev, - int vf, int min_tx_rate, - int max_tx_rate); - int (*ndo_set_vf_spoofchk)(struct net_device *dev, - int vf, bool setting); - int (*ndo_set_vf_trust)(struct net_device *dev, - int vf, bool setting); - int (*ndo_get_vf_config)(struct net_device *dev, - int vf, - struct ifla_vf_info *ivf); - int (*ndo_set_vf_link_state)(struct net_device *dev, - int vf, int link_state); - int (*ndo_get_vf_stats)(struct net_device *dev, - int vf, - struct ifla_vf_stats - *vf_stats); - int (*ndo_set_vf_port)(struct net_device *dev, - int vf, - struct nlattr *port[]); - int (*ndo_get_vf_port)(struct net_device *dev, - int vf, struct sk_buff *skb); - int (*ndo_set_vf_guid)(struct net_device *dev, - int vf, u64 guid, - int guid_type); - int (*ndo_set_vf_rss_query_en)( - struct net_device *dev, - int vf, bool setting); - int (*ndo_setup_tc)(struct net_device *dev, - u32 handle, - __be16 protocol, - struct tc_to_netdev *tc); -#if IS_ENABLED(CONFIG_FCOE) - int (*ndo_fcoe_enable)(struct net_device *dev); - int (*ndo_fcoe_disable)(struct net_device *dev); - int (*ndo_fcoe_ddp_setup)(struct net_device *dev, - u16 xid, - struct scatterlist *sgl, - unsigned int sgc); - int (*ndo_fcoe_ddp_done)(struct net_device *dev, - u16 xid); - int (*ndo_fcoe_ddp_target)(struct net_device *dev, - u16 xid, - struct scatterlist *sgl, - unsigned int sgc); - int (*ndo_fcoe_get_hbainfo)(struct net_device *dev, - struct netdev_fcoe_hbainfo *hbainfo); -#endif - -#if IS_ENABLED(CONFIG_LIBFCOE) -#define NETDEV_FCOE_WWNN 0 -#define NETDEV_FCOE_WWPN 1 - int (*ndo_fcoe_get_wwn)(struct net_device *dev, - u64 *wwn, int type); -#endif - -#ifdef CONFIG_RFS_ACCEL - int (*ndo_rx_flow_steer)(struct net_device *dev, - const struct sk_buff *skb, - u16 rxq_index, - u32 flow_id); -#endif - int (*ndo_add_slave)(struct net_device *dev, - struct net_device *slave_dev); - int (*ndo_del_slave)(struct net_device *dev, - struct net_device *slave_dev); - netdev_features_t (*ndo_fix_features)(struct net_device *dev, - netdev_features_t features); - int (*ndo_set_features)(struct net_device *dev, - netdev_features_t features); - int (*ndo_neigh_construct)(struct net_device *dev, - struct neighbour *n); - void (*ndo_neigh_destroy)(struct net_device *dev, - struct neighbour *n); - - int (*ndo_fdb_add)(struct ndmsg *ndm, - struct nlattr *tb[], - struct net_device *dev, - const unsigned char *addr, - u16 vid, - u16 flags); - int (*ndo_fdb_del)(struct ndmsg *ndm, - struct nlattr *tb[], - struct net_device *dev, - const unsigned char *addr, - u16 vid); - int (*ndo_fdb_dump)(struct sk_buff *skb, - struct netlink_callback *cb, - struct net_device *dev, - struct net_device *filter_dev, - int *idx); - - int (*ndo_bridge_setlink)(struct net_device *dev, - struct nlmsghdr *nlh, - u16 flags); - int (*ndo_bridge_getlink)(struct sk_buff *skb, - u32 pid, u32 seq, - struct net_device *dev, - u32 filter_mask, - int nlflags); - int (*ndo_bridge_dellink)(struct net_device *dev, - struct nlmsghdr *nlh, - u16 flags); - int (*ndo_change_carrier)(struct net_device *dev, - bool new_carrier); - int (*ndo_get_phys_port_id)(struct net_device *dev, - struct netdev_phys_item_id *ppid); - int (*ndo_get_phys_port_name)(struct net_device *dev, - char *name, size_t len); - void (*ndo_udp_tunnel_add)(struct net_device *dev, - struct udp_tunnel_info *ti); - void (*ndo_udp_tunnel_del)(struct net_device *dev, - struct udp_tunnel_info *ti); - void* (*ndo_dfwd_add_station)(struct net_device *pdev, - struct net_device *dev); - void (*ndo_dfwd_del_station)(struct net_device *pdev, - void *priv); - - netdev_tx_t (*ndo_dfwd_start_xmit) (struct sk_buff *skb, - struct net_device *dev, - void *priv); - int (*ndo_get_lock_subclass)(struct net_device *dev); - int (*ndo_set_tx_maxrate)(struct net_device *dev, - int queue_index, - u32 maxrate); - int (*ndo_get_iflink)(const struct net_device *dev); - int (*ndo_change_proto_down)(struct net_device *dev, - bool proto_down); - int (*ndo_fill_metadata_dst)(struct net_device *dev, - struct sk_buff *skb); - void (*ndo_set_rx_headroom)(struct net_device *dev, - int needed_headroom); - int (*ndo_xdp)(struct net_device *dev, - struct netdev_xdp *xdp); -}; - -/** - * enum net_device_priv_flags - &struct net_device priv_flags - * - * These are the &struct net_device, they are only set internally - * by drivers and used in the kernel. These flags are invisible to - * userspace; this means that the order of these flags can change - * during any kernel release. - * - * You should have a pretty good reason to be extending these flags. - * - * @IFF_802_1Q_VLAN: 802.1Q VLAN device - * @IFF_EBRIDGE: Ethernet bridging device - * @IFF_BONDING: bonding master or slave - * @IFF_ISATAP: ISATAP interface (RFC4214) - * @IFF_WAN_HDLC: WAN HDLC device - * @IFF_XMIT_DST_RELEASE: dev_hard_start_xmit() is allowed to - * release skb->dst - * @IFF_DONT_BRIDGE: disallow bridging this ether dev - * @IFF_DISABLE_NETPOLL: disable netpoll at run-time - * @IFF_MACVLAN_PORT: device used as macvlan port - * @IFF_BRIDGE_PORT: device used as bridge port - * @IFF_OVS_DATAPATH: device used as Open vSwitch datapath port - * @IFF_TX_SKB_SHARING: The interface supports sharing skbs on transmit - * @IFF_UNICAST_FLT: Supports unicast filtering - * @IFF_TEAM_PORT: device used as team port - * @IFF_SUPP_NOFCS: device supports sending custom FCS - * @IFF_LIVE_ADDR_CHANGE: device supports hardware address - * change when it's running - * @IFF_MACVLAN: Macvlan device - * @IFF_XMIT_DST_RELEASE_PERM: IFF_XMIT_DST_RELEASE not taking into account - * underlying stacked devices - * @IFF_IPVLAN_MASTER: IPvlan master device - * @IFF_IPVLAN_SLAVE: IPvlan slave device - * @IFF_L3MDEV_MASTER: device is an L3 master device - * @IFF_NO_QUEUE: device can run without qdisc attached - * @IFF_OPENVSWITCH: device is a Open vSwitch master - * @IFF_L3MDEV_SLAVE: device is enslaved to an L3 master device - * @IFF_TEAM: device is a team device - * @IFF_RXFH_CONFIGURED: device has had Rx Flow indirection table configured - * @IFF_PHONY_HEADROOM: the headroom value is controlled by an external - * entity (i.e. the master device for bridged veth) - * @IFF_MACSEC: device is a MACsec device - */ -enum netdev_priv_flags { - IFF_802_1Q_VLAN = 1<<0, - IFF_EBRIDGE = 1<<1, - IFF_BONDING = 1<<2, - IFF_ISATAP = 1<<3, - IFF_WAN_HDLC = 1<<4, - IFF_XMIT_DST_RELEASE = 1<<5, - IFF_DONT_BRIDGE = 1<<6, - IFF_DISABLE_NETPOLL = 1<<7, - IFF_MACVLAN_PORT = 1<<8, - IFF_BRIDGE_PORT = 1<<9, - IFF_OVS_DATAPATH = 1<<10, - IFF_TX_SKB_SHARING = 1<<11, - IFF_UNICAST_FLT = 1<<12, - IFF_TEAM_PORT = 1<<13, - IFF_SUPP_NOFCS = 1<<14, - IFF_LIVE_ADDR_CHANGE = 1<<15, - IFF_MACVLAN = 1<<16, - IFF_XMIT_DST_RELEASE_PERM = 1<<17, - IFF_IPVLAN_MASTER = 1<<18, - IFF_IPVLAN_SLAVE = 1<<19, - IFF_L3MDEV_MASTER = 1<<20, - IFF_NO_QUEUE = 1<<21, - IFF_OPENVSWITCH = 1<<22, - IFF_L3MDEV_SLAVE = 1<<23, - IFF_TEAM = 1<<24, - IFF_RXFH_CONFIGURED = 1<<25, - IFF_PHONY_HEADROOM = 1<<26, - IFF_MACSEC = 1<<27, -}; - -#define IFF_802_1Q_VLAN IFF_802_1Q_VLAN -#define IFF_EBRIDGE IFF_EBRIDGE -#define IFF_BONDING IFF_BONDING -#define IFF_ISATAP IFF_ISATAP -#define IFF_WAN_HDLC IFF_WAN_HDLC -#define IFF_XMIT_DST_RELEASE IFF_XMIT_DST_RELEASE -#define IFF_DONT_BRIDGE IFF_DONT_BRIDGE -#define IFF_DISABLE_NETPOLL IFF_DISABLE_NETPOLL -#define IFF_MACVLAN_PORT IFF_MACVLAN_PORT -#define IFF_BRIDGE_PORT IFF_BRIDGE_PORT -#define IFF_OVS_DATAPATH IFF_OVS_DATAPATH -#define IFF_TX_SKB_SHARING IFF_TX_SKB_SHARING -#define IFF_UNICAST_FLT IFF_UNICAST_FLT -#define IFF_TEAM_PORT IFF_TEAM_PORT -#define IFF_SUPP_NOFCS IFF_SUPP_NOFCS -#define IFF_LIVE_ADDR_CHANGE IFF_LIVE_ADDR_CHANGE -#define IFF_MACVLAN IFF_MACVLAN -#define IFF_XMIT_DST_RELEASE_PERM IFF_XMIT_DST_RELEASE_PERM -#define IFF_IPVLAN_MASTER IFF_IPVLAN_MASTER -#define IFF_IPVLAN_SLAVE IFF_IPVLAN_SLAVE -#define IFF_L3MDEV_MASTER IFF_L3MDEV_MASTER -#define IFF_NO_QUEUE IFF_NO_QUEUE -#define IFF_OPENVSWITCH IFF_OPENVSWITCH -#define IFF_L3MDEV_SLAVE IFF_L3MDEV_SLAVE -#define IFF_TEAM IFF_TEAM -#define IFF_RXFH_CONFIGURED IFF_RXFH_CONFIGURED -#define IFF_MACSEC IFF_MACSEC - -/** - * struct net_device - The DEVICE structure. - * Actually, this whole structure is a big mistake. It mixes I/O - * data with strictly "high-level" data, and it has to know about - * almost every data structure used in the INET module. - * - * @name: This is the first field of the "visible" part of this structure - * (i.e. as seen by users in the "Space.c" file). It is the name - * of the interface. - * - * @name_hlist: Device name hash chain, please keep it close to name[] - * @ifalias: SNMP alias - * @mem_end: Shared memory end - * @mem_start: Shared memory start - * @base_addr: Device I/O address - * @irq: Device IRQ number - * - * @carrier_changes: Stats to monitor carrier on<->off transitions - * - * @state: Generic network queuing layer state, see netdev_state_t - * @dev_list: The global list of network devices - * @napi_list: List entry used for polling NAPI devices - * @unreg_list: List entry when we are unregistering the - * device; see the function unregister_netdev - * @close_list: List entry used when we are closing the device - * @ptype_all: Device-specific packet handlers for all protocols - * @ptype_specific: Device-specific, protocol-specific packet handlers - * - * @adj_list: Directly linked devices, like slaves for bonding - * @all_adj_list: All linked devices, *including* neighbours - * @features: Currently active device features - * @hw_features: User-changeable features - * - * @wanted_features: User-requested features - * @vlan_features: Mask of features inheritable by VLAN devices - * - * @hw_enc_features: Mask of features inherited by encapsulating devices - * This field indicates what encapsulation - * offloads the hardware is capable of doing, - * and drivers will need to set them appropriately. - * - * @mpls_features: Mask of features inheritable by MPLS - * - * @ifindex: interface index - * @group: The group the device belongs to - * - * @stats: Statistics struct, which was left as a legacy, use - * rtnl_link_stats64 instead - * - * @rx_dropped: Dropped packets by core network, - * do not use this in drivers - * @tx_dropped: Dropped packets by core network, - * do not use this in drivers - * @rx_nohandler: nohandler dropped packets by core network on - * inactive devices, do not use this in drivers - * - * @wireless_handlers: List of functions to handle Wireless Extensions, - * instead of ioctl, - * see for details. - * @wireless_data: Instance data managed by the core of wireless extensions - * - * @netdev_ops: Includes several pointers to callbacks, - * if one wants to override the ndo_*() functions - * @ethtool_ops: Management operations - * @ndisc_ops: Includes callbacks for different IPv6 neighbour - * discovery handling. Necessary for e.g. 6LoWPAN. - * @header_ops: Includes callbacks for creating,parsing,caching,etc - * of Layer 2 headers. - * - * @flags: Interface flags (a la BSD) - * @priv_flags: Like 'flags' but invisible to userspace, - * see if.h for the definitions - * @gflags: Global flags ( kept as legacy ) - * @padded: How much padding added by alloc_netdev() - * @operstate: RFC2863 operstate - * @link_mode: Mapping policy to operstate - * @if_port: Selectable AUI, TP, ... - * @dma: DMA channel - * @mtu: Interface MTU value - * @type: Interface hardware type - * @hard_header_len: Maximum hardware header length. - * - * @needed_headroom: Extra headroom the hardware may need, but not in all - * cases can this be guaranteed - * @needed_tailroom: Extra tailroom the hardware may need, but not in all - * cases can this be guaranteed. Some cases also use - * LL_MAX_HEADER instead to allocate the skb - * - * interface address info: - * - * @perm_addr: Permanent hw address - * @addr_assign_type: Hw address assignment type - * @addr_len: Hardware address length - * @neigh_priv_len: Used in neigh_alloc() - * @dev_id: Used to differentiate devices that share - * the same link layer address - * @dev_port: Used to differentiate devices that share - * the same function - * @addr_list_lock: XXX: need comments on this one - * @uc_promisc: Counter that indicates promiscuous mode - * has been enabled due to the need to listen to - * additional unicast addresses in a device that - * does not implement ndo_set_rx_mode() - * @uc: unicast mac addresses - * @mc: multicast mac addresses - * @dev_addrs: list of device hw addresses - * @queues_kset: Group of all Kobjects in the Tx and RX queues - * @promiscuity: Number of times the NIC is told to work in - * promiscuous mode; if it becomes 0 the NIC will - * exit promiscuous mode - * @allmulti: Counter, enables or disables allmulticast mode - * - * @vlan_info: VLAN info - * @dsa_ptr: dsa specific data - * @tipc_ptr: TIPC specific data - * @atalk_ptr: AppleTalk link - * @ip_ptr: IPv4 specific data - * @dn_ptr: DECnet specific data - * @ip6_ptr: IPv6 specific data - * @ax25_ptr: AX.25 specific data - * @ieee80211_ptr: IEEE 802.11 specific data, assign before registering - * - * @last_rx: Time of last Rx - * @dev_addr: Hw address (before bcast, - * because most packets are unicast) - * - * @_rx: Array of RX queues - * @num_rx_queues: Number of RX queues - * allocated at register_netdev() time - * @real_num_rx_queues: Number of RX queues currently active in device - * - * @rx_handler: handler for received packets - * @rx_handler_data: XXX: need comments on this one - * @ingress_queue: XXX: need comments on this one - * @broadcast: hw bcast address - * - * @rx_cpu_rmap: CPU reverse-mapping for RX completion interrupts, - * indexed by RX queue number. Assigned by driver. - * This must only be set if the ndo_rx_flow_steer - * operation is defined - * @index_hlist: Device index hash chain - * - * @_tx: Array of TX queues - * @num_tx_queues: Number of TX queues allocated at alloc_netdev_mq() time - * @real_num_tx_queues: Number of TX queues currently active in device - * @qdisc: Root qdisc from userspace point of view - * @tx_queue_len: Max frames per queue allowed - * @tx_global_lock: XXX: need comments on this one - * - * @xps_maps: XXX: need comments on this one - * - * @watchdog_timeo: Represents the timeout that is used by - * the watchdog (see dev_watchdog()) - * @watchdog_timer: List of timers - * - * @pcpu_refcnt: Number of references to this device - * @todo_list: Delayed register/unregister - * @link_watch_list: XXX: need comments on this one - * - * @reg_state: Register/unregister state machine - * @dismantle: Device is going to be freed - * @rtnl_link_state: This enum represents the phases of creating - * a new link - * - * @destructor: Called from unregister, - * can be used to call free_netdev - * @npinfo: XXX: need comments on this one - * @nd_net: Network namespace this network device is inside - * - * @ml_priv: Mid-layer private - * @lstats: Loopback statistics - * @tstats: Tunnel statistics - * @dstats: Dummy statistics - * @vstats: Virtual ethernet statistics - * - * @garp_port: GARP - * @mrp_port: MRP - * - * @dev: Class/net/name entry - * @sysfs_groups: Space for optional device, statistics and wireless - * sysfs groups - * - * @sysfs_rx_queue_group: Space for optional per-rx queue attributes - * @rtnl_link_ops: Rtnl_link_ops - * - * @gso_max_size: Maximum size of generic segmentation offload - * @gso_max_segs: Maximum number of segments that can be passed to the - * NIC for GSO - * - * @dcbnl_ops: Data Center Bridging netlink ops - * @num_tc: Number of traffic classes in the net device - * @tc_to_txq: XXX: need comments on this one - * @prio_tc_map: XXX: need comments on this one - * - * @fcoe_ddp_xid: Max exchange id for FCoE LRO by ddp - * - * @priomap: XXX: need comments on this one - * @phydev: Physical device may attach itself - * for hardware timestamping - * - * @qdisc_tx_busylock: lockdep class annotating Qdisc->busylock spinlock - * @qdisc_running_key: lockdep class annotating Qdisc->running seqcount - * - * @proto_down: protocol port state information can be sent to the - * switch driver and used to set the phys state of the - * switch port. - * - * FIXME: cleanup struct net_device such that network protocol info - * moves out. - */ - -struct net_device { - char name[IFNAMSIZ]; - struct hlist_node name_hlist; - char *ifalias; - /* - * I/O specific fields - * FIXME: Merge these and struct ifmap into one - */ - unsigned long mem_end; - unsigned long mem_start; - unsigned long base_addr; - int irq; - - atomic_t carrier_changes; - - /* - * Some hardware also needs these fields (state,dev_list, - * napi_list,unreg_list,close_list) but they are not - * part of the usual set specified in Space.c. - */ - - unsigned long state; - - struct list_head dev_list; - struct list_head napi_list; - struct list_head unreg_list; - struct list_head close_list; - struct list_head ptype_all; - struct list_head ptype_specific; - - struct { - struct list_head upper; - struct list_head lower; - } adj_list; - - struct { - struct list_head upper; - struct list_head lower; - } all_adj_list; - - netdev_features_t features; - netdev_features_t hw_features; - netdev_features_t wanted_features; - netdev_features_t vlan_features; - netdev_features_t hw_enc_features; - netdev_features_t mpls_features; - netdev_features_t gso_partial_features; - - int ifindex; - int group; - - struct net_device_stats stats; - - atomic_long_t rx_dropped; - atomic_long_t tx_dropped; - atomic_long_t rx_nohandler; - -#ifdef CONFIG_WIRELESS_EXT - const struct iw_handler_def *wireless_handlers; - struct iw_public_data *wireless_data; -#endif - const struct net_device_ops *netdev_ops; - const struct ethtool_ops *ethtool_ops; -#ifdef CONFIG_NET_SWITCHDEV - const struct switchdev_ops *switchdev_ops; -#endif -#ifdef CONFIG_NET_L3_MASTER_DEV - const struct l3mdev_ops *l3mdev_ops; -#endif -#if IS_ENABLED(CONFIG_IPV6) - const struct ndisc_ops *ndisc_ops; -#endif - - const struct header_ops *header_ops; - - unsigned int flags; - unsigned int priv_flags; - - unsigned short gflags; - unsigned short padded; - - unsigned char operstate; - unsigned char link_mode; - - unsigned char if_port; - unsigned char dma; - - unsigned int mtu; - unsigned short type; - unsigned short hard_header_len; - - unsigned short needed_headroom; - unsigned short needed_tailroom; - - /* Interface address info. */ - unsigned char perm_addr[MAX_ADDR_LEN]; - unsigned char addr_assign_type; - unsigned char addr_len; - unsigned short neigh_priv_len; - unsigned short dev_id; - unsigned short dev_port; - spinlock_t addr_list_lock; - unsigned char name_assign_type; - bool uc_promisc; - struct netdev_hw_addr_list uc; - struct netdev_hw_addr_list mc; - struct netdev_hw_addr_list dev_addrs; - -#ifdef CONFIG_SYSFS - struct kset *queues_kset; -#endif - unsigned int promiscuity; - unsigned int allmulti; - - - /* Protocol-specific pointers */ - -#if IS_ENABLED(CONFIG_VLAN_8021Q) - struct vlan_info __rcu *vlan_info; -#endif -#if IS_ENABLED(CONFIG_NET_DSA) - struct dsa_switch_tree *dsa_ptr; -#endif -#if IS_ENABLED(CONFIG_TIPC) - struct tipc_bearer __rcu *tipc_ptr; -#endif - void *atalk_ptr; - struct in_device __rcu *ip_ptr; - struct dn_dev __rcu *dn_ptr; - struct inet6_dev __rcu *ip6_ptr; - void *ax25_ptr; - struct wireless_dev *ieee80211_ptr; - struct wpan_dev *ieee802154_ptr; -#if IS_ENABLED(CONFIG_MPLS_ROUTING) - struct mpls_dev __rcu *mpls_ptr; -#endif - -/* - * Cache lines mostly used on receive path (including eth_type_trans()) - */ - unsigned long last_rx; - - /* Interface address info used in eth_type_trans() */ - unsigned char *dev_addr; - -#ifdef CONFIG_SYSFS - struct netdev_rx_queue *_rx; - - unsigned int num_rx_queues; - unsigned int real_num_rx_queues; -#endif - - unsigned long gro_flush_timeout; - rx_handler_func_t __rcu *rx_handler; - void __rcu *rx_handler_data; - -#ifdef CONFIG_NET_CLS_ACT - struct tcf_proto __rcu *ingress_cl_list; -#endif - struct netdev_queue __rcu *ingress_queue; -#ifdef CONFIG_NETFILTER_INGRESS - struct nf_hook_entry __rcu *nf_hooks_ingress; -#endif - - unsigned char broadcast[MAX_ADDR_LEN]; -#ifdef CONFIG_RFS_ACCEL - struct cpu_rmap *rx_cpu_rmap; -#endif - struct hlist_node index_hlist; - -/* - * Cache lines mostly used on transmit path - */ - struct netdev_queue *_tx ____cacheline_aligned_in_smp; - unsigned int num_tx_queues; - unsigned int real_num_tx_queues; - struct Qdisc *qdisc; -#ifdef CONFIG_NET_SCHED - DECLARE_HASHTABLE (qdisc_hash, 4); -#endif - unsigned long tx_queue_len; - spinlock_t tx_global_lock; - int watchdog_timeo; - -#ifdef CONFIG_XPS - struct xps_dev_maps __rcu *xps_maps; -#endif -#ifdef CONFIG_NET_CLS_ACT - struct tcf_proto __rcu *egress_cl_list; -#endif - - /* These may be needed for future network-power-down code. */ - struct timer_list watchdog_timer; - - int __percpu *pcpu_refcnt; - struct list_head todo_list; - - struct list_head link_watch_list; - - enum { NETREG_UNINITIALIZED=0, - NETREG_REGISTERED, /* completed register_netdevice */ - NETREG_UNREGISTERING, /* called unregister_netdevice */ - NETREG_UNREGISTERED, /* completed unregister todo */ - NETREG_RELEASED, /* called free_netdev */ - NETREG_DUMMY, /* dummy device for NAPI poll */ - } reg_state:8; - - bool dismantle; - - enum { - RTNL_LINK_INITIALIZED, - RTNL_LINK_INITIALIZING, - } rtnl_link_state:16; - - void (*destructor)(struct net_device *dev); - -#ifdef CONFIG_NETPOLL - struct netpoll_info __rcu *npinfo; -#endif - - possible_net_t nd_net; - - /* mid-layer private */ - union { - void *ml_priv; - struct pcpu_lstats __percpu *lstats; - struct pcpu_sw_netstats __percpu *tstats; - struct pcpu_dstats __percpu *dstats; - struct pcpu_vstats __percpu *vstats; - }; - - struct garp_port __rcu *garp_port; - struct mrp_port __rcu *mrp_port; - - struct device dev; - const struct attribute_group *sysfs_groups[4]; - const struct attribute_group *sysfs_rx_queue_group; - - const struct rtnl_link_ops *rtnl_link_ops; - - /* for setting kernel sock attribute on TCP connection setup */ -#define GSO_MAX_SIZE 65536 - unsigned int gso_max_size; -#define GSO_MAX_SEGS 65535 - u16 gso_max_segs; - -#ifdef CONFIG_DCB - const struct dcbnl_rtnl_ops *dcbnl_ops; -#endif - u8 num_tc; - struct netdev_tc_txq tc_to_txq[TC_MAX_QUEUE]; - u8 prio_tc_map[TC_BITMASK + 1]; - -#if IS_ENABLED(CONFIG_FCOE) - unsigned int fcoe_ddp_xid; -#endif -#if IS_ENABLED(CONFIG_CGROUP_NET_PRIO) - struct netprio_map __rcu *priomap; -#endif - struct phy_device *phydev; - struct lock_class_key *qdisc_tx_busylock; - struct lock_class_key *qdisc_running_key; - bool proto_down; -}; -#define to_net_dev(d) container_of(d, struct net_device, dev) - -#define NETDEV_ALIGN 32 - -static inline -int netdev_get_prio_tc_map(const struct net_device *dev, u32 prio) -{ - return dev->prio_tc_map[prio & TC_BITMASK]; -} - -static inline -int netdev_set_prio_tc_map(struct net_device *dev, u8 prio, u8 tc) -{ - if (tc >= dev->num_tc) - return -EINVAL; - - dev->prio_tc_map[prio & TC_BITMASK] = tc & TC_BITMASK; - return 0; -} - -static inline -void netdev_reset_tc(struct net_device *dev) -{ - dev->num_tc = 0; - memset(dev->tc_to_txq, 0, sizeof(dev->tc_to_txq)); - memset(dev->prio_tc_map, 0, sizeof(dev->prio_tc_map)); -} - -static inline -int netdev_set_tc_queue(struct net_device *dev, u8 tc, u16 count, u16 offset) -{ - if (tc >= dev->num_tc) - return -EINVAL; - - dev->tc_to_txq[tc].count = count; - dev->tc_to_txq[tc].offset = offset; - return 0; -} - -static inline -int netdev_set_num_tc(struct net_device *dev, u8 num_tc) -{ - if (num_tc > TC_MAX_QUEUE) - return -EINVAL; - - dev->num_tc = num_tc; - return 0; -} - -static inline -int netdev_get_num_tc(struct net_device *dev) -{ - return dev->num_tc; -} - -static inline -struct netdev_queue *netdev_get_tx_queue(const struct net_device *dev, - unsigned int index) -{ - return &dev->_tx[index]; -} - -static inline struct netdev_queue *skb_get_tx_queue(const struct net_device *dev, - const struct sk_buff *skb) -{ - return netdev_get_tx_queue(dev, skb_get_queue_mapping(skb)); -} - -static inline void netdev_for_each_tx_queue(struct net_device *dev, - void (*f)(struct net_device *, - struct netdev_queue *, - void *), - void *arg) -{ - unsigned int i; - - for (i = 0; i < dev->num_tx_queues; i++) - f(dev, &dev->_tx[i], arg); -} - -#define netdev_lockdep_set_classes(dev) \ -{ \ - static struct lock_class_key qdisc_tx_busylock_key; \ - static struct lock_class_key qdisc_running_key; \ - static struct lock_class_key qdisc_xmit_lock_key; \ - static struct lock_class_key dev_addr_list_lock_key; \ - unsigned int i; \ - \ - (dev)->qdisc_tx_busylock = &qdisc_tx_busylock_key; \ - (dev)->qdisc_running_key = &qdisc_running_key; \ - lockdep_set_class(&(dev)->addr_list_lock, \ - &dev_addr_list_lock_key); \ - for (i = 0; i < (dev)->num_tx_queues; i++) \ - lockdep_set_class(&(dev)->_tx[i]._xmit_lock, \ - &qdisc_xmit_lock_key); \ -} - -struct netdev_queue *netdev_pick_tx(struct net_device *dev, - struct sk_buff *skb, - void *accel_priv); - -/* returns the headroom that the master device needs to take in account - * when forwarding to this dev - */ -static inline unsigned netdev_get_fwd_headroom(struct net_device *dev) -{ - return dev->priv_flags & IFF_PHONY_HEADROOM ? 0 : dev->needed_headroom; -} - -static inline void netdev_set_rx_headroom(struct net_device *dev, int new_hr) -{ - if (dev->netdev_ops->ndo_set_rx_headroom) - dev->netdev_ops->ndo_set_rx_headroom(dev, new_hr); -} - -/* set the device rx headroom to the dev's default */ -static inline void netdev_reset_rx_headroom(struct net_device *dev) -{ - netdev_set_rx_headroom(dev, -1); -} - -/* - * Net namespace inlines - */ -static inline -struct net *dev_net(const struct net_device *dev) -{ - return read_pnet(&dev->nd_net); -} - -static inline -void dev_net_set(struct net_device *dev, struct net *net) -{ - write_pnet(&dev->nd_net, net); -} - -static inline bool netdev_uses_dsa(struct net_device *dev) -{ -#if IS_ENABLED(CONFIG_NET_DSA) - if (dev->dsa_ptr != NULL) - return dsa_uses_tagged_protocol(dev->dsa_ptr); -#endif - return false; -} - -/** - * netdev_priv - access network device private data - * @dev: network device - * - * Get network device private data - */ -static inline void *netdev_priv(const struct net_device *dev) -{ - return (char *)dev + ALIGN(sizeof(struct net_device), NETDEV_ALIGN); -} - -/* Set the sysfs physical device reference for the network logical device - * if set prior to registration will cause a symlink during initialization. - */ -#define SET_NETDEV_DEV(net, pdev) ((net)->dev.parent = (pdev)) - -/* Set the sysfs device type for the network logical device to allow - * fine-grained identification of different network device types. For - * example Ethernet, Wireless LAN, Bluetooth, WiMAX etc. - */ -#define SET_NETDEV_DEVTYPE(net, devtype) ((net)->dev.type = (devtype)) - -/* Default NAPI poll() weight - * Device drivers are strongly advised to not use bigger value - */ -#define NAPI_POLL_WEIGHT 64 - -/** - * netif_napi_add - initialize a NAPI context - * @dev: network device - * @napi: NAPI context - * @poll: polling function - * @weight: default weight - * - * netif_napi_add() must be used to initialize a NAPI context prior to calling - * *any* of the other NAPI-related functions. - */ -void netif_napi_add(struct net_device *dev, struct napi_struct *napi, - int (*poll)(struct napi_struct *, int), int weight); - -/** - * netif_tx_napi_add - initialize a NAPI context - * @dev: network device - * @napi: NAPI context - * @poll: polling function - * @weight: default weight - * - * This variant of netif_napi_add() should be used from drivers using NAPI - * to exclusively poll a TX queue. - * This will avoid we add it into napi_hash[], thus polluting this hash table. - */ -static inline void netif_tx_napi_add(struct net_device *dev, - struct napi_struct *napi, - int (*poll)(struct napi_struct *, int), - int weight) -{ - set_bit(NAPI_STATE_NO_BUSY_POLL, &napi->state); - netif_napi_add(dev, napi, poll, weight); -} - -/** - * netif_napi_del - remove a NAPI context - * @napi: NAPI context - * - * netif_napi_del() removes a NAPI context from the network device NAPI list - */ -void netif_napi_del(struct napi_struct *napi); - -struct napi_gro_cb { - /* Virtual address of skb_shinfo(skb)->frags[0].page + offset. */ - void *frag0; - - /* Length of frag0. */ - unsigned int frag0_len; - - /* This indicates where we are processing relative to skb->data. */ - int data_offset; - - /* This is non-zero if the packet cannot be merged with the new skb. */ - u16 flush; - - /* Save the IP ID here and check when we get to the transport layer */ - u16 flush_id; - - /* Number of segments aggregated. */ - u16 count; - - /* Start offset for remote checksum offload */ - u16 gro_remcsum_start; - - /* jiffies when first packet was created/queued */ - unsigned long age; - - /* Used in ipv6_gro_receive() and foo-over-udp */ - u16 proto; - - /* This is non-zero if the packet may be of the same flow. */ - u8 same_flow:1; - - /* Used in tunnel GRO receive */ - u8 encap_mark:1; - - /* GRO checksum is valid */ - u8 csum_valid:1; - - /* Number of checksums via CHECKSUM_UNNECESSARY */ - u8 csum_cnt:3; - - /* Free the skb? */ - u8 free:2; -#define NAPI_GRO_FREE 1 -#define NAPI_GRO_FREE_STOLEN_HEAD 2 - - /* Used in foo-over-udp, set in udp[46]_gro_receive */ - u8 is_ipv6:1; - - /* Used in GRE, set in fou/gue_gro_receive */ - u8 is_fou:1; - - /* Used to determine if flush_id can be ignored */ - u8 is_atomic:1; - - /* Number of gro_receive callbacks this packet already went through */ - u8 recursion_counter:4; - - /* 1 bit hole */ - - /* used to support CHECKSUM_COMPLETE for tunneling protocols */ - __wsum csum; - - /* used in skb_gro_receive() slow path */ - struct sk_buff *last; -}; - -#define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb) - -#define GRO_RECURSION_LIMIT 15 -static inline int gro_recursion_inc_test(struct sk_buff *skb) -{ - return ++NAPI_GRO_CB(skb)->recursion_counter == GRO_RECURSION_LIMIT; -} - -typedef struct sk_buff **(*gro_receive_t)(struct sk_buff **, struct sk_buff *); -static inline struct sk_buff **call_gro_receive(gro_receive_t cb, - struct sk_buff **head, - struct sk_buff *skb) -{ - if (unlikely(gro_recursion_inc_test(skb))) { - NAPI_GRO_CB(skb)->flush |= 1; - return NULL; - } - - return cb(head, skb); -} - -typedef struct sk_buff **(*gro_receive_sk_t)(struct sock *, struct sk_buff **, - struct sk_buff *); -static inline struct sk_buff **call_gro_receive_sk(gro_receive_sk_t cb, - struct sock *sk, - struct sk_buff **head, - struct sk_buff *skb) -{ - if (unlikely(gro_recursion_inc_test(skb))) { - NAPI_GRO_CB(skb)->flush |= 1; - return NULL; - } - - return cb(sk, head, skb); -} - -struct packet_type { - __be16 type; /* This is really htons(ether_type). */ - struct net_device *dev; /* NULL is wildcarded here */ - int (*func) (struct sk_buff *, - struct net_device *, - struct packet_type *, - struct net_device *); - bool (*id_match)(struct packet_type *ptype, - struct sock *sk); - void *af_packet_priv; - struct list_head list; -}; - -struct offload_callbacks { - struct sk_buff *(*gso_segment)(struct sk_buff *skb, - netdev_features_t features); - struct sk_buff **(*gro_receive)(struct sk_buff **head, - struct sk_buff *skb); - int (*gro_complete)(struct sk_buff *skb, int nhoff); -}; - -struct packet_offload { - __be16 type; /* This is really htons(ether_type). */ - u16 priority; - struct offload_callbacks callbacks; - struct list_head list; -}; - -/* often modified stats are per-CPU, other are shared (netdev->stats) */ -struct pcpu_sw_netstats { - u64 rx_packets; - u64 rx_bytes; - u64 tx_packets; - u64 tx_bytes; - struct u64_stats_sync syncp; -}; - -#define __netdev_alloc_pcpu_stats(type, gfp) \ -({ \ - typeof(type) __percpu *pcpu_stats = alloc_percpu_gfp(type, gfp);\ - if (pcpu_stats) { \ - int __cpu; \ - for_each_possible_cpu(__cpu) { \ - typeof(type) *stat; \ - stat = per_cpu_ptr(pcpu_stats, __cpu); \ - u64_stats_init(&stat->syncp); \ - } \ - } \ - pcpu_stats; \ -}) - -#define netdev_alloc_pcpu_stats(type) \ - __netdev_alloc_pcpu_stats(type, GFP_KERNEL) - -enum netdev_lag_tx_type { - NETDEV_LAG_TX_TYPE_UNKNOWN, - NETDEV_LAG_TX_TYPE_RANDOM, - NETDEV_LAG_TX_TYPE_BROADCAST, - NETDEV_LAG_TX_TYPE_ROUNDROBIN, - NETDEV_LAG_TX_TYPE_ACTIVEBACKUP, - NETDEV_LAG_TX_TYPE_HASH, -}; - -struct netdev_lag_upper_info { - enum netdev_lag_tx_type tx_type; -}; - -struct netdev_lag_lower_state_info { - u8 link_up : 1, - tx_enabled : 1; -}; - -#include - -/* netdevice notifier chain. Please remember to update the rtnetlink - * notification exclusion list in rtnetlink_event() when adding new - * types. - */ -#define NETDEV_UP 0x0001 /* For now you can't veto a device up/down */ -#define NETDEV_DOWN 0x0002 -#define NETDEV_REBOOT 0x0003 /* Tell a protocol stack a network interface - detected a hardware crash and restarted - - we can use this eg to kick tcp sessions - once done */ -#define NETDEV_CHANGE 0x0004 /* Notify device state change */ -#define NETDEV_REGISTER 0x0005 -#define NETDEV_UNREGISTER 0x0006 -#define NETDEV_CHANGEMTU 0x0007 /* notify after mtu change happened */ -#define NETDEV_CHANGEADDR 0x0008 -#define NETDEV_GOING_DOWN 0x0009 -#define NETDEV_CHANGENAME 0x000A -#define NETDEV_FEAT_CHANGE 0x000B -#define NETDEV_BONDING_FAILOVER 0x000C -#define NETDEV_PRE_UP 0x000D -#define NETDEV_PRE_TYPE_CHANGE 0x000E -#define NETDEV_POST_TYPE_CHANGE 0x000F -#define NETDEV_POST_INIT 0x0010 -#define NETDEV_UNREGISTER_FINAL 0x0011 -#define NETDEV_RELEASE 0x0012 -#define NETDEV_NOTIFY_PEERS 0x0013 -#define NETDEV_JOIN 0x0014 -#define NETDEV_CHANGEUPPER 0x0015 -#define NETDEV_RESEND_IGMP 0x0016 -#define NETDEV_PRECHANGEMTU 0x0017 /* notify before mtu change happened */ -#define NETDEV_CHANGEINFODATA 0x0018 -#define NETDEV_BONDING_INFO 0x0019 -#define NETDEV_PRECHANGEUPPER 0x001A -#define NETDEV_CHANGELOWERSTATE 0x001B -#define NETDEV_UDP_TUNNEL_PUSH_INFO 0x001C -#define NETDEV_CHANGE_TX_QUEUE_LEN 0x001E - -int register_netdevice_notifier(struct notifier_block *nb); -int unregister_netdevice_notifier(struct notifier_block *nb); - -struct netdev_notifier_info { - struct net_device *dev; -}; - -struct netdev_notifier_change_info { - struct netdev_notifier_info info; /* must be first */ - unsigned int flags_changed; -}; - -struct netdev_notifier_changeupper_info { - struct netdev_notifier_info info; /* must be first */ - struct net_device *upper_dev; /* new upper dev */ - bool master; /* is upper dev master */ - bool linking; /* is the notification for link or unlink */ - void *upper_info; /* upper dev info */ -}; - -struct netdev_notifier_changelowerstate_info { - struct netdev_notifier_info info; /* must be first */ - void *lower_state_info; /* is lower dev state */ -}; - -static inline void netdev_notifier_info_init(struct netdev_notifier_info *info, - struct net_device *dev) -{ - info->dev = dev; -} - -static inline struct net_device * -netdev_notifier_info_to_dev(const struct netdev_notifier_info *info) -{ - return info->dev; -} - -int call_netdevice_notifiers(unsigned long val, struct net_device *dev); - - -extern rwlock_t dev_base_lock; /* Device list lock */ - -#define for_each_netdev(net, d) \ - list_for_each_entry(d, &(net)->dev_base_head, dev_list) -#define for_each_netdev_reverse(net, d) \ - list_for_each_entry_reverse(d, &(net)->dev_base_head, dev_list) -#define for_each_netdev_rcu(net, d) \ - list_for_each_entry_rcu(d, &(net)->dev_base_head, dev_list) -#define for_each_netdev_safe(net, d, n) \ - list_for_each_entry_safe(d, n, &(net)->dev_base_head, dev_list) -#define for_each_netdev_continue(net, d) \ - list_for_each_entry_continue(d, &(net)->dev_base_head, dev_list) -#define for_each_netdev_continue_rcu(net, d) \ - list_for_each_entry_continue_rcu(d, &(net)->dev_base_head, dev_list) -#define for_each_netdev_in_bond_rcu(bond, slave) \ - for_each_netdev_rcu(&init_net, slave) \ - if (netdev_master_upper_dev_get_rcu(slave) == (bond)) -#define net_device_entry(lh) list_entry(lh, struct net_device, dev_list) - -static inline struct net_device *next_net_device(struct net_device *dev) -{ - struct list_head *lh; - struct net *net; - - net = dev_net(dev); - lh = dev->dev_list.next; - return lh == &net->dev_base_head ? NULL : net_device_entry(lh); -} - -static inline struct net_device *next_net_device_rcu(struct net_device *dev) -{ - struct list_head *lh; - struct net *net; - - net = dev_net(dev); - lh = rcu_dereference(list_next_rcu(&dev->dev_list)); - return lh == &net->dev_base_head ? NULL : net_device_entry(lh); -} - -static inline struct net_device *first_net_device(struct net *net) -{ - return list_empty(&net->dev_base_head) ? NULL : - net_device_entry(net->dev_base_head.next); -} - -static inline struct net_device *first_net_device_rcu(struct net *net) -{ - struct list_head *lh = rcu_dereference(list_next_rcu(&net->dev_base_head)); - - return lh == &net->dev_base_head ? NULL : net_device_entry(lh); -} - -int netdev_boot_setup_check(struct net_device *dev); -unsigned long netdev_boot_base(const char *prefix, int unit); -struct net_device *dev_getbyhwaddr_rcu(struct net *net, unsigned short type, - const char *hwaddr); -struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type); -struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type); -void dev_add_pack(struct packet_type *pt); -void dev_remove_pack(struct packet_type *pt); -void __dev_remove_pack(struct packet_type *pt); -void dev_add_offload(struct packet_offload *po); -void dev_remove_offload(struct packet_offload *po); - -int dev_get_iflink(const struct net_device *dev); -int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb); -struct net_device *__dev_get_by_flags(struct net *net, unsigned short flags, - unsigned short mask); -struct net_device *dev_get_by_name(struct net *net, const char *name); -struct net_device *dev_get_by_name_rcu(struct net *net, const char *name); -struct net_device *__dev_get_by_name(struct net *net, const char *name); -int dev_alloc_name(struct net_device *dev, const char *name); -int dev_open(struct net_device *dev); -int dev_close(struct net_device *dev); -int dev_close_many(struct list_head *head, bool unlink); -void dev_disable_lro(struct net_device *dev); -int dev_loopback_xmit(struct net *net, struct sock *sk, struct sk_buff *newskb); -int dev_queue_xmit(struct sk_buff *skb); -int dev_queue_xmit_accel(struct sk_buff *skb, void *accel_priv); -int register_netdevice(struct net_device *dev); -void unregister_netdevice_queue(struct net_device *dev, struct list_head *head); -void unregister_netdevice_many(struct list_head *head); -static inline void unregister_netdevice(struct net_device *dev) -{ - unregister_netdevice_queue(dev, NULL); -} - -int netdev_refcnt_read(const struct net_device *dev); -void free_netdev(struct net_device *dev); -void netdev_freemem(struct net_device *dev); -void synchronize_net(void); -int init_dummy_netdev(struct net_device *dev); - -DECLARE_PER_CPU(int, xmit_recursion); -#define XMIT_RECURSION_LIMIT 10 - -static inline int dev_recursion_level(void) -{ - return this_cpu_read(xmit_recursion); -} - -struct net_device *dev_get_by_index(struct net *net, int ifindex); -struct net_device *__dev_get_by_index(struct net *net, int ifindex); -struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex); -int netdev_get_name(struct net *net, char *name, int ifindex); -int dev_restart(struct net_device *dev); -int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb); - -static inline unsigned int skb_gro_offset(const struct sk_buff *skb) -{ - return NAPI_GRO_CB(skb)->data_offset; -} - -static inline unsigned int skb_gro_len(const struct sk_buff *skb) -{ - return skb->len - NAPI_GRO_CB(skb)->data_offset; -} - -static inline void skb_gro_pull(struct sk_buff *skb, unsigned int len) -{ - NAPI_GRO_CB(skb)->data_offset += len; -} - -static inline void *skb_gro_header_fast(struct sk_buff *skb, - unsigned int offset) -{ - return NAPI_GRO_CB(skb)->frag0 + offset; -} - -static inline int skb_gro_header_hard(struct sk_buff *skb, unsigned int hlen) -{ - return NAPI_GRO_CB(skb)->frag0_len < hlen; -} - -static inline void *skb_gro_header_slow(struct sk_buff *skb, unsigned int hlen, - unsigned int offset) -{ - if (!pskb_may_pull(skb, hlen)) - return NULL; - - NAPI_GRO_CB(skb)->frag0 = NULL; - NAPI_GRO_CB(skb)->frag0_len = 0; - return skb->data + offset; -} - -static inline void *skb_gro_network_header(struct sk_buff *skb) -{ - return (NAPI_GRO_CB(skb)->frag0 ?: skb->data) + - skb_network_offset(skb); -} - -static inline void skb_gro_postpull_rcsum(struct sk_buff *skb, - const void *start, unsigned int len) -{ - if (NAPI_GRO_CB(skb)->csum_valid) - NAPI_GRO_CB(skb)->csum = csum_sub(NAPI_GRO_CB(skb)->csum, - csum_partial(start, len, 0)); -} - -/* GRO checksum functions. These are logical equivalents of the normal - * checksum functions (in skbuff.h) except that they operate on the GRO - * offsets and fields in sk_buff. - */ - -__sum16 __skb_gro_checksum_complete(struct sk_buff *skb); - -static inline bool skb_at_gro_remcsum_start(struct sk_buff *skb) -{ - return (NAPI_GRO_CB(skb)->gro_remcsum_start == skb_gro_offset(skb)); -} - -static inline bool __skb_gro_checksum_validate_needed(struct sk_buff *skb, - bool zero_okay, - __sum16 check) -{ - return ((skb->ip_summed != CHECKSUM_PARTIAL || - skb_checksum_start_offset(skb) < - skb_gro_offset(skb)) && - !skb_at_gro_remcsum_start(skb) && - NAPI_GRO_CB(skb)->csum_cnt == 0 && - (!zero_okay || check)); -} - -static inline __sum16 __skb_gro_checksum_validate_complete(struct sk_buff *skb, - __wsum psum) -{ - if (NAPI_GRO_CB(skb)->csum_valid && - !csum_fold(csum_add(psum, NAPI_GRO_CB(skb)->csum))) - return 0; - - NAPI_GRO_CB(skb)->csum = psum; - - return __skb_gro_checksum_complete(skb); -} - -static inline void skb_gro_incr_csum_unnecessary(struct sk_buff *skb) -{ - if (NAPI_GRO_CB(skb)->csum_cnt > 0) { - /* Consume a checksum from CHECKSUM_UNNECESSARY */ - NAPI_GRO_CB(skb)->csum_cnt--; - } else { - /* Update skb for CHECKSUM_UNNECESSARY and csum_level when we - * verified a new top level checksum or an encapsulated one - * during GRO. This saves work if we fallback to normal path. - */ - __skb_incr_checksum_unnecessary(skb); - } -} - -#define __skb_gro_checksum_validate(skb, proto, zero_okay, check, \ - compute_pseudo) \ -({ \ - __sum16 __ret = 0; \ - if (__skb_gro_checksum_validate_needed(skb, zero_okay, check)) \ - __ret = __skb_gro_checksum_validate_complete(skb, \ - compute_pseudo(skb, proto)); \ - if (__ret) \ - __skb_mark_checksum_bad(skb); \ - else \ - skb_gro_incr_csum_unnecessary(skb); \ - __ret; \ -}) - -#define skb_gro_checksum_validate(skb, proto, compute_pseudo) \ - __skb_gro_checksum_validate(skb, proto, false, 0, compute_pseudo) - -#define skb_gro_checksum_validate_zero_check(skb, proto, check, \ - compute_pseudo) \ - __skb_gro_checksum_validate(skb, proto, true, check, compute_pseudo) - -#define skb_gro_checksum_simple_validate(skb) \ - __skb_gro_checksum_validate(skb, 0, false, 0, null_compute_pseudo) - -static inline bool __skb_gro_checksum_convert_check(struct sk_buff *skb) -{ - return (NAPI_GRO_CB(skb)->csum_cnt == 0 && - !NAPI_GRO_CB(skb)->csum_valid); -} - -static inline void __skb_gro_checksum_convert(struct sk_buff *skb, - __sum16 check, __wsum pseudo) -{ - NAPI_GRO_CB(skb)->csum = ~pseudo; - NAPI_GRO_CB(skb)->csum_valid = 1; -} - -#define skb_gro_checksum_try_convert(skb, proto, check, compute_pseudo) \ -do { \ - if (__skb_gro_checksum_convert_check(skb)) \ - __skb_gro_checksum_convert(skb, check, \ - compute_pseudo(skb, proto)); \ -} while (0) - -struct gro_remcsum { - int offset; - __wsum delta; -}; - -static inline void skb_gro_remcsum_init(struct gro_remcsum *grc) -{ - grc->offset = 0; - grc->delta = 0; -} - -static inline void *skb_gro_remcsum_process(struct sk_buff *skb, void *ptr, - unsigned int off, size_t hdrlen, - int start, int offset, - struct gro_remcsum *grc, - bool nopartial) -{ - __wsum delta; - size_t plen = hdrlen + max_t(size_t, offset + sizeof(u16), start); - - BUG_ON(!NAPI_GRO_CB(skb)->csum_valid); - - if (!nopartial) { - NAPI_GRO_CB(skb)->gro_remcsum_start = off + hdrlen + start; - return ptr; - } - - ptr = skb_gro_header_fast(skb, off); - if (skb_gro_header_hard(skb, off + plen)) { - ptr = skb_gro_header_slow(skb, off + plen, off); - if (!ptr) - return NULL; - } - - delta = remcsum_adjust(ptr + hdrlen, NAPI_GRO_CB(skb)->csum, - start, offset); - - /* Adjust skb->csum since we changed the packet */ - NAPI_GRO_CB(skb)->csum = csum_add(NAPI_GRO_CB(skb)->csum, delta); - - grc->offset = off + hdrlen + offset; - grc->delta = delta; - - return ptr; -} - -static inline void skb_gro_remcsum_cleanup(struct sk_buff *skb, - struct gro_remcsum *grc) -{ - void *ptr; - size_t plen = grc->offset + sizeof(u16); - - if (!grc->delta) - return; - - ptr = skb_gro_header_fast(skb, grc->offset); - if (skb_gro_header_hard(skb, grc->offset + sizeof(u16))) { - ptr = skb_gro_header_slow(skb, plen, grc->offset); - if (!ptr) - return; - } - - remcsum_unadjust((__sum16 *)ptr, grc->delta); -} - -struct skb_csum_offl_spec { - __u16 ipv4_okay:1, - ipv6_okay:1, - encap_okay:1, - ip_options_okay:1, - ext_hdrs_okay:1, - tcp_okay:1, - udp_okay:1, - sctp_okay:1, - vlan_okay:1, - no_encapped_ipv6:1, - no_not_encapped:1; -}; - -bool __skb_csum_offload_chk(struct sk_buff *skb, - const struct skb_csum_offl_spec *spec, - bool *csum_encapped, - bool csum_help); - -static inline bool skb_csum_offload_chk(struct sk_buff *skb, - const struct skb_csum_offl_spec *spec, - bool *csum_encapped, - bool csum_help) -{ - if (skb->ip_summed != CHECKSUM_PARTIAL) - return false; - - return __skb_csum_offload_chk(skb, spec, csum_encapped, csum_help); -} - -static inline bool skb_csum_offload_chk_help(struct sk_buff *skb, - const struct skb_csum_offl_spec *spec) -{ - bool csum_encapped; - - return skb_csum_offload_chk(skb, spec, &csum_encapped, true); -} - -static inline bool skb_csum_off_chk_help_cmn(struct sk_buff *skb) -{ - static const struct skb_csum_offl_spec csum_offl_spec = { - .ipv4_okay = 1, - .ip_options_okay = 1, - .ipv6_okay = 1, - .vlan_okay = 1, - .tcp_okay = 1, - .udp_okay = 1, - }; - - return skb_csum_offload_chk_help(skb, &csum_offl_spec); -} - -static inline bool skb_csum_off_chk_help_cmn_v4_only(struct sk_buff *skb) -{ - static const struct skb_csum_offl_spec csum_offl_spec = { - .ipv4_okay = 1, - .ip_options_okay = 1, - .tcp_okay = 1, - .udp_okay = 1, - .vlan_okay = 1, - }; - - return skb_csum_offload_chk_help(skb, &csum_offl_spec); -} - -static inline int dev_hard_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, - const void *daddr, const void *saddr, - unsigned int len) -{ - if (!dev->header_ops || !dev->header_ops->create) - return 0; - - return dev->header_ops->create(skb, dev, type, daddr, saddr, len); -} - -static inline int dev_parse_header(const struct sk_buff *skb, - unsigned char *haddr) -{ - const struct net_device *dev = skb->dev; - - if (!dev->header_ops || !dev->header_ops->parse) - return 0; - return dev->header_ops->parse(skb, haddr); -} - -/* ll_header must have at least hard_header_len allocated */ -static inline bool dev_validate_header(const struct net_device *dev, - char *ll_header, int len) -{ - if (likely(len >= dev->hard_header_len)) - return true; - - if (capable(CAP_SYS_RAWIO)) { - memset(ll_header + len, 0, dev->hard_header_len - len); - return true; - } - - if (dev->header_ops && dev->header_ops->validate) - return dev->header_ops->validate(ll_header, len); - - return false; -} - -typedef int gifconf_func_t(struct net_device * dev, char __user * bufptr, int len); -int register_gifconf(unsigned int family, gifconf_func_t *gifconf); -static inline int unregister_gifconf(unsigned int family) -{ - return register_gifconf(family, NULL); -} - -#ifdef CONFIG_NET_FLOW_LIMIT -#define FLOW_LIMIT_HISTORY (1 << 7) /* must be ^2 and !overflow buckets */ -struct sd_flow_limit { - u64 count; - unsigned int num_buckets; - unsigned int history_head; - u16 history[FLOW_LIMIT_HISTORY]; - u8 buckets[]; -}; - -extern int netdev_flow_limit_table_len; -#endif /* CONFIG_NET_FLOW_LIMIT */ - -/* - * Incoming packets are placed on per-CPU queues - */ -struct softnet_data { - struct list_head poll_list; - struct sk_buff_head process_queue; - - /* stats */ - unsigned int processed; - unsigned int time_squeeze; - unsigned int received_rps; -#ifdef CONFIG_RPS - struct softnet_data *rps_ipi_list; -#endif -#ifdef CONFIG_NET_FLOW_LIMIT - struct sd_flow_limit __rcu *flow_limit; -#endif - struct Qdisc *output_queue; - struct Qdisc **output_queue_tailp; - struct sk_buff *completion_queue; - -#ifdef CONFIG_RPS - /* input_queue_head should be written by cpu owning this struct, - * and only read by other cpus. Worth using a cache line. - */ - unsigned int input_queue_head ____cacheline_aligned_in_smp; - - /* Elements below can be accessed between CPUs for RPS/RFS */ - struct call_single_data csd ____cacheline_aligned_in_smp; - struct softnet_data *rps_ipi_next; - unsigned int cpu; - unsigned int input_queue_tail; -#endif - unsigned int dropped; - struct sk_buff_head input_pkt_queue; - struct napi_struct backlog; - -}; - -static inline void input_queue_head_incr(struct softnet_data *sd) -{ -#ifdef CONFIG_RPS - sd->input_queue_head++; -#endif -} - -static inline void input_queue_tail_incr_save(struct softnet_data *sd, - unsigned int *qtail) -{ -#ifdef CONFIG_RPS - *qtail = ++sd->input_queue_tail; -#endif -} - -DECLARE_PER_CPU_ALIGNED(struct softnet_data, softnet_data); - -void __netif_schedule(struct Qdisc *q); -void netif_schedule_queue(struct netdev_queue *txq); - -static inline void netif_tx_schedule_all(struct net_device *dev) -{ - unsigned int i; - - for (i = 0; i < dev->num_tx_queues; i++) - netif_schedule_queue(netdev_get_tx_queue(dev, i)); -} - -static __always_inline void netif_tx_start_queue(struct netdev_queue *dev_queue) -{ - clear_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state); -} - -/** - * netif_start_queue - allow transmit - * @dev: network device - * - * Allow upper layers to call the device hard_start_xmit routine. - */ -static inline void netif_start_queue(struct net_device *dev) -{ - netif_tx_start_queue(netdev_get_tx_queue(dev, 0)); -} - -static inline void netif_tx_start_all_queues(struct net_device *dev) -{ - unsigned int i; - - for (i = 0; i < dev->num_tx_queues; i++) { - struct netdev_queue *txq = netdev_get_tx_queue(dev, i); - netif_tx_start_queue(txq); - } -} - -void netif_tx_wake_queue(struct netdev_queue *dev_queue); - -/** - * netif_wake_queue - restart transmit - * @dev: network device - * - * Allow upper layers to call the device hard_start_xmit routine. - * Used for flow control when transmit resources are available. - */ -static inline void netif_wake_queue(struct net_device *dev) -{ - netif_tx_wake_queue(netdev_get_tx_queue(dev, 0)); -} - -static inline void netif_tx_wake_all_queues(struct net_device *dev) -{ - unsigned int i; - - for (i = 0; i < dev->num_tx_queues; i++) { - struct netdev_queue *txq = netdev_get_tx_queue(dev, i); - netif_tx_wake_queue(txq); - } -} - -static __always_inline void netif_tx_stop_queue(struct netdev_queue *dev_queue) -{ - set_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state); -} - -/** - * netif_stop_queue - stop transmitted packets - * @dev: network device - * - * Stop upper layers calling the device hard_start_xmit routine. - * Used for flow control when transmit resources are unavailable. - */ -static inline void netif_stop_queue(struct net_device *dev) -{ - netif_tx_stop_queue(netdev_get_tx_queue(dev, 0)); -} - -void netif_tx_stop_all_queues(struct net_device *dev); - -static inline bool netif_tx_queue_stopped(const struct netdev_queue *dev_queue) -{ - return test_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state); -} - -/** - * netif_queue_stopped - test if transmit queue is flowblocked - * @dev: network device - * - * Test if transmit queue on device is currently unable to send. - */ -static inline bool netif_queue_stopped(const struct net_device *dev) -{ - return netif_tx_queue_stopped(netdev_get_tx_queue(dev, 0)); -} - -static inline bool netif_xmit_stopped(const struct netdev_queue *dev_queue) -{ - return dev_queue->state & QUEUE_STATE_ANY_XOFF; -} - -static inline bool -netif_xmit_frozen_or_stopped(const struct netdev_queue *dev_queue) -{ - return dev_queue->state & QUEUE_STATE_ANY_XOFF_OR_FROZEN; -} - -static inline bool -netif_xmit_frozen_or_drv_stopped(const struct netdev_queue *dev_queue) -{ - return dev_queue->state & QUEUE_STATE_DRV_XOFF_OR_FROZEN; -} - -/** - * netdev_txq_bql_enqueue_prefetchw - prefetch bql data for write - * @dev_queue: pointer to transmit queue - * - * BQL enabled drivers might use this helper in their ndo_start_xmit(), - * to give appropriate hint to the CPU. - */ -static inline void netdev_txq_bql_enqueue_prefetchw(struct netdev_queue *dev_queue) -{ -#ifdef CONFIG_BQL - prefetchw(&dev_queue->dql.num_queued); -#endif -} - -/** - * netdev_txq_bql_complete_prefetchw - prefetch bql data for write - * @dev_queue: pointer to transmit queue - * - * BQL enabled drivers might use this helper in their TX completion path, - * to give appropriate hint to the CPU. - */ -static inline void netdev_txq_bql_complete_prefetchw(struct netdev_queue *dev_queue) -{ -#ifdef CONFIG_BQL - prefetchw(&dev_queue->dql.limit); -#endif -} - -static inline void netdev_tx_sent_queue(struct netdev_queue *dev_queue, - unsigned int bytes) -{ -#ifdef CONFIG_BQL - dql_queued(&dev_queue->dql, bytes); - - if (likely(dql_avail(&dev_queue->dql) >= 0)) - return; - - set_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state); - - /* - * The XOFF flag must be set before checking the dql_avail below, - * because in netdev_tx_completed_queue we update the dql_completed - * before checking the XOFF flag. - */ - smp_mb(); - - /* check again in case another CPU has just made room avail */ - if (unlikely(dql_avail(&dev_queue->dql) >= 0)) - clear_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state); -#endif -} - -/** - * netdev_sent_queue - report the number of bytes queued to hardware - * @dev: network device - * @bytes: number of bytes queued to the hardware device queue - * - * Report the number of bytes queued for sending/completion to the network - * device hardware queue. @bytes should be a good approximation and should - * exactly match netdev_completed_queue() @bytes - */ -static inline void netdev_sent_queue(struct net_device *dev, unsigned int bytes) -{ - netdev_tx_sent_queue(netdev_get_tx_queue(dev, 0), bytes); -} - -static inline void netdev_tx_completed_queue(struct netdev_queue *dev_queue, - unsigned int pkts, unsigned int bytes) -{ -#ifdef CONFIG_BQL - if (unlikely(!bytes)) - return; - - dql_completed(&dev_queue->dql, bytes); - - /* - * Without the memory barrier there is a small possiblity that - * netdev_tx_sent_queue will miss the update and cause the queue to - * be stopped forever - */ - smp_mb(); - - if (dql_avail(&dev_queue->dql) < 0) - return; - - if (test_and_clear_bit(__QUEUE_STATE_STACK_XOFF, &dev_queue->state)) - netif_schedule_queue(dev_queue); -#endif -} - -/** - * netdev_completed_queue - report bytes and packets completed by device - * @dev: network device - * @pkts: actual number of packets sent over the medium - * @bytes: actual number of bytes sent over the medium - * - * Report the number of bytes and packets transmitted by the network device - * hardware queue over the physical medium, @bytes must exactly match the - * @bytes amount passed to netdev_sent_queue() - */ -static inline void netdev_completed_queue(struct net_device *dev, - unsigned int pkts, unsigned int bytes) -{ - netdev_tx_completed_queue(netdev_get_tx_queue(dev, 0), pkts, bytes); -} - -static inline void netdev_tx_reset_queue(struct netdev_queue *q) -{ -#ifdef CONFIG_BQL - clear_bit(__QUEUE_STATE_STACK_XOFF, &q->state); - dql_reset(&q->dql); -#endif -} - -/** - * netdev_reset_queue - reset the packets and bytes count of a network device - * @dev_queue: network device - * - * Reset the bytes and packet count of a network device and clear the - * software flow control OFF bit for this network device - */ -static inline void netdev_reset_queue(struct net_device *dev_queue) -{ - netdev_tx_reset_queue(netdev_get_tx_queue(dev_queue, 0)); -} - -/** - * netdev_cap_txqueue - check if selected tx queue exceeds device queues - * @dev: network device - * @queue_index: given tx queue index - * - * Returns 0 if given tx queue index >= number of device tx queues, - * otherwise returns the originally passed tx queue index. - */ -static inline u16 netdev_cap_txqueue(struct net_device *dev, u16 queue_index) -{ - if (unlikely(queue_index >= dev->real_num_tx_queues)) { - net_warn_ratelimited("%s selects TX queue %d, but real number of TX queues is %d\n", - dev->name, queue_index, - dev->real_num_tx_queues); - return 0; - } - - return queue_index; -} - -/** - * netif_running - test if up - * @dev: network device - * - * Test if the device has been brought up. - */ -static inline bool netif_running(const struct net_device *dev) -{ - return test_bit(__LINK_STATE_START, &dev->state); -} - -/* - * Routines to manage the subqueues on a device. We only need start, - * stop, and a check if it's stopped. All other device management is - * done at the overall netdevice level. - * Also test the device if we're multiqueue. - */ - -/** - * netif_start_subqueue - allow sending packets on subqueue - * @dev: network device - * @queue_index: sub queue index - * - * Start individual transmit queue of a device with multiple transmit queues. - */ -static inline void netif_start_subqueue(struct net_device *dev, u16 queue_index) -{ - struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index); - - netif_tx_start_queue(txq); -} - -/** - * netif_stop_subqueue - stop sending packets on subqueue - * @dev: network device - * @queue_index: sub queue index - * - * Stop individual transmit queue of a device with multiple transmit queues. - */ -static inline void netif_stop_subqueue(struct net_device *dev, u16 queue_index) -{ - struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index); - netif_tx_stop_queue(txq); -} - -/** - * netif_subqueue_stopped - test status of subqueue - * @dev: network device - * @queue_index: sub queue index - * - * Check individual transmit queue of a device with multiple transmit queues. - */ -static inline bool __netif_subqueue_stopped(const struct net_device *dev, - u16 queue_index) -{ - struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index); - - return netif_tx_queue_stopped(txq); -} - -static inline bool netif_subqueue_stopped(const struct net_device *dev, - struct sk_buff *skb) -{ - return __netif_subqueue_stopped(dev, skb_get_queue_mapping(skb)); -} - -void netif_wake_subqueue(struct net_device *dev, u16 queue_index); - -#ifdef CONFIG_XPS -int netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask, - u16 index); -#else -static inline int netif_set_xps_queue(struct net_device *dev, - const struct cpumask *mask, - u16 index) -{ - return 0; -} -#endif - -u16 __skb_tx_hash(const struct net_device *dev, struct sk_buff *skb, - unsigned int num_tx_queues); - -/* - * Returns a Tx hash for the given packet when dev->real_num_tx_queues is used - * as a distribution range limit for the returned value. - */ -static inline u16 skb_tx_hash(const struct net_device *dev, - struct sk_buff *skb) -{ - return __skb_tx_hash(dev, skb, dev->real_num_tx_queues); -} - -/** - * netif_is_multiqueue - test if device has multiple transmit queues - * @dev: network device - * - * Check if device has multiple transmit queues - */ -static inline bool netif_is_multiqueue(const struct net_device *dev) -{ - return dev->num_tx_queues > 1; -} - -int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq); - -#ifdef CONFIG_SYSFS -int netif_set_real_num_rx_queues(struct net_device *dev, unsigned int rxq); -#else -static inline int netif_set_real_num_rx_queues(struct net_device *dev, - unsigned int rxq) -{ - return 0; -} -#endif - -#ifdef CONFIG_SYSFS -static inline unsigned int get_netdev_rx_queue_index( - struct netdev_rx_queue *queue) -{ - struct net_device *dev = queue->dev; - int index = queue - dev->_rx; - - BUG_ON(index >= dev->num_rx_queues); - return index; -} -#endif - -#define DEFAULT_MAX_NUM_RSS_QUEUES (8) -int netif_get_num_default_rss_queues(void); - -enum skb_free_reason { - SKB_REASON_CONSUMED, - SKB_REASON_DROPPED, -}; - -void __dev_kfree_skb_irq(struct sk_buff *skb, enum skb_free_reason reason); -void __dev_kfree_skb_any(struct sk_buff *skb, enum skb_free_reason reason); - -/* - * It is not allowed to call kfree_skb() or consume_skb() from hardware - * interrupt context or with hardware interrupts being disabled. - * (in_irq() || irqs_disabled()) - * - * We provide four helpers that can be used in following contexts : - * - * dev_kfree_skb_irq(skb) when caller drops a packet from irq context, - * replacing kfree_skb(skb) - * - * dev_consume_skb_irq(skb) when caller consumes a packet from irq context. - * Typically used in place of consume_skb(skb) in TX completion path - * - * dev_kfree_skb_any(skb) when caller doesn't know its current irq context, - * replacing kfree_skb(skb) - * - * dev_consume_skb_any(skb) when caller doesn't know its current irq context, - * and consumed a packet. Used in place of consume_skb(skb) - */ -static inline void dev_kfree_skb_irq(struct sk_buff *skb) -{ - __dev_kfree_skb_irq(skb, SKB_REASON_DROPPED); -} - -static inline void dev_consume_skb_irq(struct sk_buff *skb) -{ - __dev_kfree_skb_irq(skb, SKB_REASON_CONSUMED); -} - -static inline void dev_kfree_skb_any(struct sk_buff *skb) -{ - __dev_kfree_skb_any(skb, SKB_REASON_DROPPED); -} - -static inline void dev_consume_skb_any(struct sk_buff *skb) -{ - __dev_kfree_skb_any(skb, SKB_REASON_CONSUMED); -} - -int netif_rx(struct sk_buff *skb); -int netif_rx_ni(struct sk_buff *skb); -int netif_receive_skb(struct sk_buff *skb); -gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb); -void napi_gro_flush(struct napi_struct *napi, bool flush_old); -struct sk_buff *napi_get_frags(struct napi_struct *napi); -gro_result_t napi_gro_frags(struct napi_struct *napi); -struct packet_offload *gro_find_receive_by_type(__be16 type); -struct packet_offload *gro_find_complete_by_type(__be16 type); - -static inline void napi_free_frags(struct napi_struct *napi) -{ - kfree_skb(napi->skb); - napi->skb = NULL; -} - -bool netdev_is_rx_handler_busy(struct net_device *dev); -int netdev_rx_handler_register(struct net_device *dev, - rx_handler_func_t *rx_handler, - void *rx_handler_data); -void netdev_rx_handler_unregister(struct net_device *dev); - -bool dev_valid_name(const char *name); -int dev_ioctl(struct net *net, unsigned int cmd, void __user *); -int dev_ethtool(struct net *net, struct ifreq *); -unsigned int dev_get_flags(const struct net_device *); -int __dev_change_flags(struct net_device *, unsigned int flags); -int dev_change_flags(struct net_device *, unsigned int); -void __dev_notify_flags(struct net_device *, unsigned int old_flags, - unsigned int gchanges); -int dev_change_name(struct net_device *, const char *); -int dev_set_alias(struct net_device *, const char *, size_t); -int dev_change_net_namespace(struct net_device *, struct net *, const char *); -int dev_set_mtu(struct net_device *, int); -void dev_set_group(struct net_device *, int); -int dev_set_mac_address(struct net_device *, struct sockaddr *); -int dev_change_carrier(struct net_device *, bool new_carrier); -int dev_get_phys_port_id(struct net_device *dev, - struct netdev_phys_item_id *ppid); -int dev_get_phys_port_name(struct net_device *dev, - char *name, size_t len); -int dev_change_proto_down(struct net_device *dev, bool proto_down); -int dev_change_xdp_fd(struct net_device *dev, int fd); -struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *dev); -struct sk_buff *dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, - struct netdev_queue *txq, int *ret); -int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb); -int dev_forward_skb(struct net_device *dev, struct sk_buff *skb); -bool is_skb_forwardable(const struct net_device *dev, - const struct sk_buff *skb); - -static __always_inline int ____dev_forward_skb(struct net_device *dev, - struct sk_buff *skb) -{ - if (skb_orphan_frags(skb, GFP_ATOMIC) || - unlikely(!is_skb_forwardable(dev, skb))) { - atomic_long_inc(&dev->rx_dropped); - kfree_skb(skb); - return NET_RX_DROP; - } - - skb_scrub_packet(skb, true); - skb->priority = 0; - return 0; -} - -void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev); - -extern int netdev_budget; - -/* Called by rtnetlink.c:rtnl_unlock() */ -void netdev_run_todo(void); - -/** - * dev_put - release reference to device - * @dev: network device - * - * Release reference to device to allow it to be freed. - */ -static inline void dev_put(struct net_device *dev) -{ - this_cpu_dec(*dev->pcpu_refcnt); -} - -/** - * dev_hold - get reference to device - * @dev: network device - * - * Hold reference to device to keep it from being freed. - */ -static inline void dev_hold(struct net_device *dev) -{ - this_cpu_inc(*dev->pcpu_refcnt); -} - -/* Carrier loss detection, dial on demand. The functions netif_carrier_on - * and _off may be called from IRQ context, but it is caller - * who is responsible for serialization of these calls. - * - * The name carrier is inappropriate, these functions should really be - * called netif_lowerlayer_*() because they represent the state of any - * kind of lower layer not just hardware media. - */ - -void linkwatch_init_dev(struct net_device *dev); -void linkwatch_fire_event(struct net_device *dev); -void linkwatch_forget_dev(struct net_device *dev); - -/** - * netif_carrier_ok - test if carrier present - * @dev: network device - * - * Check if carrier is present on device - */ -static inline bool netif_carrier_ok(const struct net_device *dev) -{ - return !test_bit(__LINK_STATE_NOCARRIER, &dev->state); -} - -unsigned long dev_trans_start(struct net_device *dev); - -void __netdev_watchdog_up(struct net_device *dev); - -void netif_carrier_on(struct net_device *dev); - -void netif_carrier_off(struct net_device *dev); - -/** - * netif_dormant_on - mark device as dormant. - * @dev: network device - * - * Mark device as dormant (as per RFC2863). - * - * The dormant state indicates that the relevant interface is not - * actually in a condition to pass packets (i.e., it is not 'up') but is - * in a "pending" state, waiting for some external event. For "on- - * demand" interfaces, this new state identifies the situation where the - * interface is waiting for events to place it in the up state. - */ -static inline void netif_dormant_on(struct net_device *dev) -{ - if (!test_and_set_bit(__LINK_STATE_DORMANT, &dev->state)) - linkwatch_fire_event(dev); -} - -/** - * netif_dormant_off - set device as not dormant. - * @dev: network device - * - * Device is not in dormant state. - */ -static inline void netif_dormant_off(struct net_device *dev) -{ - if (test_and_clear_bit(__LINK_STATE_DORMANT, &dev->state)) - linkwatch_fire_event(dev); -} - -/** - * netif_dormant - test if carrier present - * @dev: network device - * - * Check if carrier is present on device - */ -static inline bool netif_dormant(const struct net_device *dev) -{ - return test_bit(__LINK_STATE_DORMANT, &dev->state); -} - - -/** - * netif_oper_up - test if device is operational - * @dev: network device - * - * Check if carrier is operational - */ -static inline bool netif_oper_up(const struct net_device *dev) -{ - return (dev->operstate == IF_OPER_UP || - dev->operstate == IF_OPER_UNKNOWN /* backward compat */); -} - -/** - * netif_device_present - is device available or removed - * @dev: network device - * - * Check if device has not been removed from system. - */ -static inline bool netif_device_present(struct net_device *dev) -{ - return test_bit(__LINK_STATE_PRESENT, &dev->state); -} - -void netif_device_detach(struct net_device *dev); - -void netif_device_attach(struct net_device *dev); - -/* - * Network interface message level settings - */ - -enum { - NETIF_MSG_DRV = 0x0001, - NETIF_MSG_PROBE = 0x0002, - NETIF_MSG_LINK = 0x0004, - NETIF_MSG_TIMER = 0x0008, - NETIF_MSG_IFDOWN = 0x0010, - NETIF_MSG_IFUP = 0x0020, - NETIF_MSG_RX_ERR = 0x0040, - NETIF_MSG_TX_ERR = 0x0080, - NETIF_MSG_TX_QUEUED = 0x0100, - NETIF_MSG_INTR = 0x0200, - NETIF_MSG_TX_DONE = 0x0400, - NETIF_MSG_RX_STATUS = 0x0800, - NETIF_MSG_PKTDATA = 0x1000, - NETIF_MSG_HW = 0x2000, - NETIF_MSG_WOL = 0x4000, -}; - -#define netif_msg_drv(p) ((p)->msg_enable & NETIF_MSG_DRV) -#define netif_msg_probe(p) ((p)->msg_enable & NETIF_MSG_PROBE) -#define netif_msg_link(p) ((p)->msg_enable & NETIF_MSG_LINK) -#define netif_msg_timer(p) ((p)->msg_enable & NETIF_MSG_TIMER) -#define netif_msg_ifdown(p) ((p)->msg_enable & NETIF_MSG_IFDOWN) -#define netif_msg_ifup(p) ((p)->msg_enable & NETIF_MSG_IFUP) -#define netif_msg_rx_err(p) ((p)->msg_enable & NETIF_MSG_RX_ERR) -#define netif_msg_tx_err(p) ((p)->msg_enable & NETIF_MSG_TX_ERR) -#define netif_msg_tx_queued(p) ((p)->msg_enable & NETIF_MSG_TX_QUEUED) -#define netif_msg_intr(p) ((p)->msg_enable & NETIF_MSG_INTR) -#define netif_msg_tx_done(p) ((p)->msg_enable & NETIF_MSG_TX_DONE) -#define netif_msg_rx_status(p) ((p)->msg_enable & NETIF_MSG_RX_STATUS) -#define netif_msg_pktdata(p) ((p)->msg_enable & NETIF_MSG_PKTDATA) -#define netif_msg_hw(p) ((p)->msg_enable & NETIF_MSG_HW) -#define netif_msg_wol(p) ((p)->msg_enable & NETIF_MSG_WOL) - -static inline u32 netif_msg_init(int debug_value, int default_msg_enable_bits) -{ - /* use default */ - if (debug_value < 0 || debug_value >= (sizeof(u32) * 8)) - return default_msg_enable_bits; - if (debug_value == 0) /* no output */ - return 0; - /* set low N bits */ - return (1 << debug_value) - 1; -} - -static inline void __netif_tx_lock(struct netdev_queue *txq, int cpu) -{ - spin_lock(&txq->_xmit_lock); - txq->xmit_lock_owner = cpu; -} - -static inline void __netif_tx_lock_bh(struct netdev_queue *txq) -{ - spin_lock_bh(&txq->_xmit_lock); - txq->xmit_lock_owner = smp_processor_id(); -} - -static inline bool __netif_tx_trylock(struct netdev_queue *txq) -{ - bool ok = spin_trylock(&txq->_xmit_lock); - if (likely(ok)) - txq->xmit_lock_owner = smp_processor_id(); - return ok; -} - -static inline void __netif_tx_unlock(struct netdev_queue *txq) -{ - txq->xmit_lock_owner = -1; - spin_unlock(&txq->_xmit_lock); -} - -static inline void __netif_tx_unlock_bh(struct netdev_queue *txq) -{ - txq->xmit_lock_owner = -1; - spin_unlock_bh(&txq->_xmit_lock); -} - -static inline void txq_trans_update(struct netdev_queue *txq) -{ - if (txq->xmit_lock_owner != -1) - txq->trans_start = jiffies; -} - -/* legacy drivers only, netdev_start_xmit() sets txq->trans_start */ -static inline void netif_trans_update(struct net_device *dev) -{ - struct netdev_queue *txq = netdev_get_tx_queue(dev, 0); - - if (txq->trans_start != jiffies) - txq->trans_start = jiffies; -} - -/** - * netif_tx_lock - grab network device transmit lock - * @dev: network device - * - * Get network device transmit lock - */ -static inline void netif_tx_lock(struct net_device *dev) -{ - unsigned int i; - int cpu; - - spin_lock(&dev->tx_global_lock); - cpu = smp_processor_id(); - for (i = 0; i < dev->num_tx_queues; i++) { - struct netdev_queue *txq = netdev_get_tx_queue(dev, i); - - /* We are the only thread of execution doing a - * freeze, but we have to grab the _xmit_lock in - * order to synchronize with threads which are in - * the ->hard_start_xmit() handler and already - * checked the frozen bit. - */ - __netif_tx_lock(txq, cpu); - set_bit(__QUEUE_STATE_FROZEN, &txq->state); - __netif_tx_unlock(txq); - } -} - -static inline void netif_tx_lock_bh(struct net_device *dev) -{ - local_bh_disable(); - netif_tx_lock(dev); -} - -static inline void netif_tx_unlock(struct net_device *dev) -{ - unsigned int i; - - for (i = 0; i < dev->num_tx_queues; i++) { - struct netdev_queue *txq = netdev_get_tx_queue(dev, i); - - /* No need to grab the _xmit_lock here. If the - * queue is not stopped for another reason, we - * force a schedule. - */ - clear_bit(__QUEUE_STATE_FROZEN, &txq->state); - netif_schedule_queue(txq); - } - spin_unlock(&dev->tx_global_lock); -} - -static inline void netif_tx_unlock_bh(struct net_device *dev) -{ - netif_tx_unlock(dev); - local_bh_enable(); -} - -#define HARD_TX_LOCK(dev, txq, cpu) { \ - if ((dev->features & NETIF_F_LLTX) == 0) { \ - __netif_tx_lock(txq, cpu); \ - } \ -} - -#define HARD_TX_TRYLOCK(dev, txq) \ - (((dev->features & NETIF_F_LLTX) == 0) ? \ - __netif_tx_trylock(txq) : \ - true ) - -#define HARD_TX_UNLOCK(dev, txq) { \ - if ((dev->features & NETIF_F_LLTX) == 0) { \ - __netif_tx_unlock(txq); \ - } \ -} - -static inline void netif_tx_disable(struct net_device *dev) -{ - unsigned int i; - int cpu; - - local_bh_disable(); - cpu = smp_processor_id(); - for (i = 0; i < dev->num_tx_queues; i++) { - struct netdev_queue *txq = netdev_get_tx_queue(dev, i); - - __netif_tx_lock(txq, cpu); - netif_tx_stop_queue(txq); - __netif_tx_unlock(txq); - } - local_bh_enable(); -} - -static inline void netif_addr_lock(struct net_device *dev) -{ - spin_lock(&dev->addr_list_lock); -} - -static inline void netif_addr_lock_nested(struct net_device *dev) -{ - int subclass = SINGLE_DEPTH_NESTING; - - if (dev->netdev_ops->ndo_get_lock_subclass) - subclass = dev->netdev_ops->ndo_get_lock_subclass(dev); - - spin_lock_nested(&dev->addr_list_lock, subclass); -} - -static inline void netif_addr_lock_bh(struct net_device *dev) -{ - spin_lock_bh(&dev->addr_list_lock); -} - -static inline void netif_addr_unlock(struct net_device *dev) -{ - spin_unlock(&dev->addr_list_lock); -} - -static inline void netif_addr_unlock_bh(struct net_device *dev) -{ - spin_unlock_bh(&dev->addr_list_lock); -} - -/* - * dev_addrs walker. Should be used only for read access. Call with - * rcu_read_lock held. - */ -#define for_each_dev_addr(dev, ha) \ - list_for_each_entry_rcu(ha, &dev->dev_addrs.list, list) - -/* These functions live elsewhere (drivers/net/net_init.c, but related) */ - -void ether_setup(struct net_device *dev); - -/* Support for loadable net-drivers */ -struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, - unsigned char name_assign_type, - void (*setup)(struct net_device *), - unsigned int txqs, unsigned int rxqs); -#define alloc_netdev(sizeof_priv, name, name_assign_type, setup) \ - alloc_netdev_mqs(sizeof_priv, name, name_assign_type, setup, 1, 1) - -#define alloc_netdev_mq(sizeof_priv, name, name_assign_type, setup, count) \ - alloc_netdev_mqs(sizeof_priv, name, name_assign_type, setup, count, \ - count) - -int register_netdev(struct net_device *dev); -void unregister_netdev(struct net_device *dev); - -/* General hardware address lists handling functions */ -int __hw_addr_sync(struct netdev_hw_addr_list *to_list, - struct netdev_hw_addr_list *from_list, int addr_len); -void __hw_addr_unsync(struct netdev_hw_addr_list *to_list, - struct netdev_hw_addr_list *from_list, int addr_len); -int __hw_addr_sync_dev(struct netdev_hw_addr_list *list, - struct net_device *dev, - int (*sync)(struct net_device *, const unsigned char *), - int (*unsync)(struct net_device *, - const unsigned char *)); -void __hw_addr_unsync_dev(struct netdev_hw_addr_list *list, - struct net_device *dev, - int (*unsync)(struct net_device *, - const unsigned char *)); -void __hw_addr_init(struct netdev_hw_addr_list *list); - -/* Functions used for device addresses handling */ -int dev_addr_add(struct net_device *dev, const unsigned char *addr, - unsigned char addr_type); -int dev_addr_del(struct net_device *dev, const unsigned char *addr, - unsigned char addr_type); -void dev_addr_flush(struct net_device *dev); -int dev_addr_init(struct net_device *dev); - -/* Functions used for unicast addresses handling */ -int dev_uc_add(struct net_device *dev, const unsigned char *addr); -int dev_uc_add_excl(struct net_device *dev, const unsigned char *addr); -int dev_uc_del(struct net_device *dev, const unsigned char *addr); -int dev_uc_sync(struct net_device *to, struct net_device *from); -int dev_uc_sync_multiple(struct net_device *to, struct net_device *from); -void dev_uc_unsync(struct net_device *to, struct net_device *from); -void dev_uc_flush(struct net_device *dev); -void dev_uc_init(struct net_device *dev); - -/** - * __dev_uc_sync - Synchonize device's unicast list - * @dev: device to sync - * @sync: function to call if address should be added - * @unsync: function to call if address should be removed - * - * Add newly added addresses to the interface, and release - * addresses that have been deleted. - */ -static inline int __dev_uc_sync(struct net_device *dev, - int (*sync)(struct net_device *, - const unsigned char *), - int (*unsync)(struct net_device *, - const unsigned char *)) -{ - return __hw_addr_sync_dev(&dev->uc, dev, sync, unsync); -} - -/** - * __dev_uc_unsync - Remove synchronized addresses from device - * @dev: device to sync - * @unsync: function to call if address should be removed - * - * Remove all addresses that were added to the device by dev_uc_sync(). - */ -static inline void __dev_uc_unsync(struct net_device *dev, - int (*unsync)(struct net_device *, - const unsigned char *)) -{ - __hw_addr_unsync_dev(&dev->uc, dev, unsync); -} - -/* Functions used for multicast addresses handling */ -int dev_mc_add(struct net_device *dev, const unsigned char *addr); -int dev_mc_add_global(struct net_device *dev, const unsigned char *addr); -int dev_mc_add_excl(struct net_device *dev, const unsigned char *addr); -int dev_mc_del(struct net_device *dev, const unsigned char *addr); -int dev_mc_del_global(struct net_device *dev, const unsigned char *addr); -int dev_mc_sync(struct net_device *to, struct net_device *from); -int dev_mc_sync_multiple(struct net_device *to, struct net_device *from); -void dev_mc_unsync(struct net_device *to, struct net_device *from); -void dev_mc_flush(struct net_device *dev); -void dev_mc_init(struct net_device *dev); - -/** - * __dev_mc_sync - Synchonize device's multicast list - * @dev: device to sync - * @sync: function to call if address should be added - * @unsync: function to call if address should be removed - * - * Add newly added addresses to the interface, and release - * addresses that have been deleted. - */ -static inline int __dev_mc_sync(struct net_device *dev, - int (*sync)(struct net_device *, - const unsigned char *), - int (*unsync)(struct net_device *, - const unsigned char *)) -{ - return __hw_addr_sync_dev(&dev->mc, dev, sync, unsync); -} - -/** - * __dev_mc_unsync - Remove synchronized addresses from device - * @dev: device to sync - * @unsync: function to call if address should be removed - * - * Remove all addresses that were added to the device by dev_mc_sync(). - */ -static inline void __dev_mc_unsync(struct net_device *dev, - int (*unsync)(struct net_device *, - const unsigned char *)) -{ - __hw_addr_unsync_dev(&dev->mc, dev, unsync); -} - -/* Functions used for secondary unicast and multicast support */ -void dev_set_rx_mode(struct net_device *dev); -void __dev_set_rx_mode(struct net_device *dev); -int dev_set_promiscuity(struct net_device *dev, int inc); -int dev_set_allmulti(struct net_device *dev, int inc); -void netdev_state_change(struct net_device *dev); -void netdev_notify_peers(struct net_device *dev); -void netdev_features_change(struct net_device *dev); -/* Load a device via the kmod */ -void dev_load(struct net *net, const char *name); -struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev, - struct rtnl_link_stats64 *storage); -void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64, - const struct net_device_stats *netdev_stats); - -extern int netdev_max_backlog; -extern int netdev_tstamp_prequeue; -extern int weight_p; - -bool netdev_has_upper_dev(struct net_device *dev, struct net_device *upper_dev); -struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev, - struct list_head **iter); -struct net_device *netdev_all_upper_get_next_dev_rcu(struct net_device *dev, - struct list_head **iter); - -/* iterate through upper list, must be called under RCU read lock */ -#define netdev_for_each_upper_dev_rcu(dev, updev, iter) \ - for (iter = &(dev)->adj_list.upper, \ - updev = netdev_upper_get_next_dev_rcu(dev, &(iter)); \ - updev; \ - updev = netdev_upper_get_next_dev_rcu(dev, &(iter))) - -/* iterate through upper list, must be called under RCU read lock */ -#define netdev_for_each_all_upper_dev_rcu(dev, updev, iter) \ - for (iter = &(dev)->all_adj_list.upper, \ - updev = netdev_all_upper_get_next_dev_rcu(dev, &(iter)); \ - updev; \ - updev = netdev_all_upper_get_next_dev_rcu(dev, &(iter))) - -void *netdev_lower_get_next_private(struct net_device *dev, - struct list_head **iter); -void *netdev_lower_get_next_private_rcu(struct net_device *dev, - struct list_head **iter); - -#define netdev_for_each_lower_private(dev, priv, iter) \ - for (iter = (dev)->adj_list.lower.next, \ - priv = netdev_lower_get_next_private(dev, &(iter)); \ - priv; \ - priv = netdev_lower_get_next_private(dev, &(iter))) - -#define netdev_for_each_lower_private_rcu(dev, priv, iter) \ - for (iter = &(dev)->adj_list.lower, \ - priv = netdev_lower_get_next_private_rcu(dev, &(iter)); \ - priv; \ - priv = netdev_lower_get_next_private_rcu(dev, &(iter))) - -void *netdev_lower_get_next(struct net_device *dev, - struct list_head **iter); - -#define netdev_for_each_lower_dev(dev, ldev, iter) \ - for (iter = (dev)->adj_list.lower.next, \ - ldev = netdev_lower_get_next(dev, &(iter)); \ - ldev; \ - ldev = netdev_lower_get_next(dev, &(iter))) - -struct net_device *netdev_all_lower_get_next(struct net_device *dev, - struct list_head **iter); -struct net_device *netdev_all_lower_get_next_rcu(struct net_device *dev, - struct list_head **iter); - -#define netdev_for_each_all_lower_dev(dev, ldev, iter) \ - for (iter = (dev)->all_adj_list.lower.next, \ - ldev = netdev_all_lower_get_next(dev, &(iter)); \ - ldev; \ - ldev = netdev_all_lower_get_next(dev, &(iter))) - -#define netdev_for_each_all_lower_dev_rcu(dev, ldev, iter) \ - for (iter = &(dev)->all_adj_list.lower, \ - ldev = netdev_all_lower_get_next_rcu(dev, &(iter)); \ - ldev; \ - ldev = netdev_all_lower_get_next_rcu(dev, &(iter))) - -void *netdev_adjacent_get_private(struct list_head *adj_list); -void *netdev_lower_get_first_private_rcu(struct net_device *dev); -struct net_device *netdev_master_upper_dev_get(struct net_device *dev); -struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev); -int netdev_upper_dev_link(struct net_device *dev, struct net_device *upper_dev); -int netdev_master_upper_dev_link(struct net_device *dev, - struct net_device *upper_dev, - void *upper_priv, void *upper_info); -void netdev_upper_dev_unlink(struct net_device *dev, - struct net_device *upper_dev); -void netdev_adjacent_rename_links(struct net_device *dev, char *oldname); -void *netdev_lower_dev_get_private(struct net_device *dev, - struct net_device *lower_dev); -void netdev_lower_state_changed(struct net_device *lower_dev, - void *lower_state_info); -int netdev_default_l2upper_neigh_construct(struct net_device *dev, - struct neighbour *n); -void netdev_default_l2upper_neigh_destroy(struct net_device *dev, - struct neighbour *n); - -/* RSS keys are 40 or 52 bytes long */ -#define NETDEV_RSS_KEY_LEN 52 -extern u8 netdev_rss_key[NETDEV_RSS_KEY_LEN] __read_mostly; -void netdev_rss_key_fill(void *buffer, size_t len); - -int dev_get_nest_level(struct net_device *dev); -int skb_checksum_help(struct sk_buff *skb); -struct sk_buff *__skb_gso_segment(struct sk_buff *skb, - netdev_features_t features, bool tx_path); -struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb, - netdev_features_t features); - -struct netdev_bonding_info { - ifslave slave; - ifbond master; -}; - -struct netdev_notifier_bonding_info { - struct netdev_notifier_info info; /* must be first */ - struct netdev_bonding_info bonding_info; -}; - -void netdev_bonding_info_change(struct net_device *dev, - struct netdev_bonding_info *bonding_info); - -static inline -struct sk_buff *skb_gso_segment(struct sk_buff *skb, netdev_features_t features) -{ - return __skb_gso_segment(skb, features, true); -} -__be16 skb_network_protocol(struct sk_buff *skb, int *depth); - -static inline bool can_checksum_protocol(netdev_features_t features, - __be16 protocol) -{ - if (protocol == htons(ETH_P_FCOE)) - return !!(features & NETIF_F_FCOE_CRC); - - /* Assume this is an IP checksum (not SCTP CRC) */ - - if (features & NETIF_F_HW_CSUM) { - /* Can checksum everything */ - return true; - } - - switch (protocol) { - case htons(ETH_P_IP): - return !!(features & NETIF_F_IP_CSUM); - case htons(ETH_P_IPV6): - return !!(features & NETIF_F_IPV6_CSUM); - default: - return false; - } -} - -/* Map an ethertype into IP protocol if possible */ -static inline int eproto_to_ipproto(int eproto) -{ - switch (eproto) { - case htons(ETH_P_IP): - return IPPROTO_IP; - case htons(ETH_P_IPV6): - return IPPROTO_IPV6; - default: - return -1; - } -} - -#ifdef CONFIG_BUG -void netdev_rx_csum_fault(struct net_device *dev); -#else -static inline void netdev_rx_csum_fault(struct net_device *dev) -{ -} -#endif -/* rx skb timestamps */ -void net_enable_timestamp(void); -void net_disable_timestamp(void); - -#ifdef CONFIG_PROC_FS -int __init dev_proc_init(void); -#else -#define dev_proc_init() 0 -#endif - -static inline netdev_tx_t __netdev_start_xmit(const struct net_device_ops *ops, - struct sk_buff *skb, struct net_device *dev, - bool more) -{ - skb->xmit_more = more ? 1 : 0; - return ops->ndo_start_xmit(skb, dev); -} - -static inline netdev_tx_t netdev_start_xmit(struct sk_buff *skb, struct net_device *dev, - struct netdev_queue *txq, bool more) -{ - const struct net_device_ops *ops = dev->netdev_ops; - int rc; - - rc = __netdev_start_xmit(ops, skb, dev, more); - if (rc == NETDEV_TX_OK) - txq_trans_update(txq); - - return rc; -} - -int netdev_class_create_file_ns(struct class_attribute *class_attr, - const void *ns); -void netdev_class_remove_file_ns(struct class_attribute *class_attr, - const void *ns); - -static inline int netdev_class_create_file(struct class_attribute *class_attr) -{ - return netdev_class_create_file_ns(class_attr, NULL); -} - -static inline void netdev_class_remove_file(struct class_attribute *class_attr) -{ - netdev_class_remove_file_ns(class_attr, NULL); -} - -extern struct kobj_ns_type_operations net_ns_type_operations; - -const char *netdev_drivername(const struct net_device *dev); - -void linkwatch_run_queue(void); - -static inline netdev_features_t netdev_intersect_features(netdev_features_t f1, - netdev_features_t f2) -{ - if ((f1 ^ f2) & NETIF_F_HW_CSUM) { - if (f1 & NETIF_F_HW_CSUM) - f1 |= (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM); - else - f2 |= (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM); - } - - return f1 & f2; -} - -static inline netdev_features_t netdev_get_wanted_features( - struct net_device *dev) -{ - return (dev->features & ~dev->hw_features) | dev->wanted_features; -} -netdev_features_t netdev_increment_features(netdev_features_t all, - netdev_features_t one, netdev_features_t mask); - -/* Allow TSO being used on stacked device : - * Performing the GSO segmentation before last device - * is a performance improvement. - */ -static inline netdev_features_t netdev_add_tso_features(netdev_features_t features, - netdev_features_t mask) -{ - return netdev_increment_features(features, NETIF_F_ALL_TSO, mask); -} - -int __netdev_update_features(struct net_device *dev); -void netdev_update_features(struct net_device *dev); -void netdev_change_features(struct net_device *dev); - -void netif_stacked_transfer_operstate(const struct net_device *rootdev, - struct net_device *dev); - -netdev_features_t passthru_features_check(struct sk_buff *skb, - struct net_device *dev, - netdev_features_t features); -netdev_features_t netif_skb_features(struct sk_buff *skb); - -static inline bool net_gso_ok(netdev_features_t features, int gso_type) -{ - netdev_features_t feature = (netdev_features_t)gso_type << NETIF_F_GSO_SHIFT; - - /* check flags correspondence */ - BUILD_BUG_ON(SKB_GSO_TCPV4 != (NETIF_F_TSO >> NETIF_F_GSO_SHIFT)); - BUILD_BUG_ON(SKB_GSO_UDP != (NETIF_F_UFO >> NETIF_F_GSO_SHIFT)); - BUILD_BUG_ON(SKB_GSO_DODGY != (NETIF_F_GSO_ROBUST >> NETIF_F_GSO_SHIFT)); - BUILD_BUG_ON(SKB_GSO_TCP_ECN != (NETIF_F_TSO_ECN >> NETIF_F_GSO_SHIFT)); - BUILD_BUG_ON(SKB_GSO_TCP_FIXEDID != (NETIF_F_TSO_MANGLEID >> NETIF_F_GSO_SHIFT)); - BUILD_BUG_ON(SKB_GSO_TCPV6 != (NETIF_F_TSO6 >> NETIF_F_GSO_SHIFT)); - BUILD_BUG_ON(SKB_GSO_FCOE != (NETIF_F_FSO >> NETIF_F_GSO_SHIFT)); - BUILD_BUG_ON(SKB_GSO_GRE != (NETIF_F_GSO_GRE >> NETIF_F_GSO_SHIFT)); - BUILD_BUG_ON(SKB_GSO_GRE_CSUM != (NETIF_F_GSO_GRE_CSUM >> NETIF_F_GSO_SHIFT)); - BUILD_BUG_ON(SKB_GSO_IPXIP4 != (NETIF_F_GSO_IPXIP4 >> NETIF_F_GSO_SHIFT)); - BUILD_BUG_ON(SKB_GSO_IPXIP6 != (NETIF_F_GSO_IPXIP6 >> NETIF_F_GSO_SHIFT)); - BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL != (NETIF_F_GSO_UDP_TUNNEL >> NETIF_F_GSO_SHIFT)); - BUILD_BUG_ON(SKB_GSO_UDP_TUNNEL_CSUM != (NETIF_F_GSO_UDP_TUNNEL_CSUM >> NETIF_F_GSO_SHIFT)); - BUILD_BUG_ON(SKB_GSO_PARTIAL != (NETIF_F_GSO_PARTIAL >> NETIF_F_GSO_SHIFT)); - BUILD_BUG_ON(SKB_GSO_TUNNEL_REMCSUM != (NETIF_F_GSO_TUNNEL_REMCSUM >> NETIF_F_GSO_SHIFT)); - BUILD_BUG_ON(SKB_GSO_SCTP != (NETIF_F_GSO_SCTP >> NETIF_F_GSO_SHIFT)); - - return (features & feature) == feature; -} - -static inline bool skb_gso_ok(struct sk_buff *skb, netdev_features_t features) -{ - return net_gso_ok(features, skb_shinfo(skb)->gso_type) && - (!skb_has_frag_list(skb) || (features & NETIF_F_FRAGLIST)); -} - -static inline bool netif_needs_gso(struct sk_buff *skb, - netdev_features_t features) -{ - return skb_is_gso(skb) && (!skb_gso_ok(skb, features) || - unlikely((skb->ip_summed != CHECKSUM_PARTIAL) && - (skb->ip_summed != CHECKSUM_UNNECESSARY))); -} - -static inline void netif_set_gso_max_size(struct net_device *dev, - unsigned int size) -{ - dev->gso_max_size = size; -} - -static inline void skb_gso_error_unwind(struct sk_buff *skb, __be16 protocol, - int pulled_hlen, u16 mac_offset, - int mac_len) -{ - skb->protocol = protocol; - skb->encapsulation = 1; - skb_push(skb, pulled_hlen); - skb_reset_transport_header(skb); - skb->mac_header = mac_offset; - skb->network_header = skb->mac_header + mac_len; - skb->mac_len = mac_len; -} - -static inline bool netif_is_macsec(const struct net_device *dev) -{ - return dev->priv_flags & IFF_MACSEC; -} - -static inline bool netif_is_macvlan(const struct net_device *dev) -{ - return dev->priv_flags & IFF_MACVLAN; -} - -static inline bool netif_is_macvlan_port(const struct net_device *dev) -{ - return dev->priv_flags & IFF_MACVLAN_PORT; -} - -static inline bool netif_is_ipvlan(const struct net_device *dev) -{ - return dev->priv_flags & IFF_IPVLAN_SLAVE; -} - -static inline bool netif_is_ipvlan_port(const struct net_device *dev) -{ - return dev->priv_flags & IFF_IPVLAN_MASTER; -} - -static inline bool netif_is_bond_master(const struct net_device *dev) -{ - return dev->flags & IFF_MASTER && dev->priv_flags & IFF_BONDING; -} - -static inline bool netif_is_bond_slave(const struct net_device *dev) -{ - return dev->flags & IFF_SLAVE && dev->priv_flags & IFF_BONDING; -} - -static inline bool netif_supports_nofcs(struct net_device *dev) -{ - return dev->priv_flags & IFF_SUPP_NOFCS; -} - -static inline bool netif_is_l3_master(const struct net_device *dev) -{ - return dev->priv_flags & IFF_L3MDEV_MASTER; -} - -static inline bool netif_is_l3_slave(const struct net_device *dev) -{ - return dev->priv_flags & IFF_L3MDEV_SLAVE; -} - -static inline bool netif_is_bridge_master(const struct net_device *dev) -{ - return dev->priv_flags & IFF_EBRIDGE; -} - -static inline bool netif_is_bridge_port(const struct net_device *dev) -{ - return dev->priv_flags & IFF_BRIDGE_PORT; -} - -static inline bool netif_is_ovs_master(const struct net_device *dev) -{ - return dev->priv_flags & IFF_OPENVSWITCH; -} - -static inline bool netif_is_team_master(const struct net_device *dev) -{ - return dev->priv_flags & IFF_TEAM; -} - -static inline bool netif_is_team_port(const struct net_device *dev) -{ - return dev->priv_flags & IFF_TEAM_PORT; -} - -static inline bool netif_is_lag_master(const struct net_device *dev) -{ - return netif_is_bond_master(dev) || netif_is_team_master(dev); -} - -static inline bool netif_is_lag_port(const struct net_device *dev) -{ - return netif_is_bond_slave(dev) || netif_is_team_port(dev); -} - -static inline bool netif_is_rxfh_configured(const struct net_device *dev) -{ - return dev->priv_flags & IFF_RXFH_CONFIGURED; -} - -/* This device needs to keep skb dst for qdisc enqueue or ndo_start_xmit() */ -static inline void netif_keep_dst(struct net_device *dev) -{ - dev->priv_flags &= ~(IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM); -} - -/* return true if dev can't cope with mtu frames that need vlan tag insertion */ -static inline bool netif_reduces_vlan_mtu(struct net_device *dev) -{ - /* TODO: reserve and use an additional IFF bit, if we get more users */ - return dev->priv_flags & IFF_MACSEC; -} - -extern struct pernet_operations __net_initdata loopback_net_ops; - -/* Logging, debugging and troubleshooting/diagnostic helpers. */ - -/* netdev_printk helpers, similar to dev_printk */ - -static inline const char *netdev_name(const struct net_device *dev) -{ - if (!dev->name[0] || strchr(dev->name, '%')) - return "(unnamed net_device)"; - return dev->name; -} - -static inline const char *netdev_reg_state(const struct net_device *dev) -{ - switch (dev->reg_state) { - case NETREG_UNINITIALIZED: return " (uninitialized)"; - case NETREG_REGISTERED: return ""; - case NETREG_UNREGISTERING: return " (unregistering)"; - case NETREG_UNREGISTERED: return " (unregistered)"; - case NETREG_RELEASED: return " (released)"; - case NETREG_DUMMY: return " (dummy)"; - } - - WARN_ONCE(1, "%s: unknown reg_state %d\n", dev->name, dev->reg_state); - return " (unknown)"; -} - -__printf(3, 4) -void netdev_printk(const char *level, const struct net_device *dev, - const char *format, ...); -__printf(2, 3) -void netdev_emerg(const struct net_device *dev, const char *format, ...); -__printf(2, 3) -void netdev_alert(const struct net_device *dev, const char *format, ...); -__printf(2, 3) -void netdev_crit(const struct net_device *dev, const char *format, ...); -__printf(2, 3) -void netdev_err(const struct net_device *dev, const char *format, ...); -__printf(2, 3) -void netdev_warn(const struct net_device *dev, const char *format, ...); -__printf(2, 3) -void netdev_notice(const struct net_device *dev, const char *format, ...); -__printf(2, 3) -void netdev_info(const struct net_device *dev, const char *format, ...); - -#define MODULE_ALIAS_NETDEV(device) \ - MODULE_ALIAS("netdev-" device) - -#if defined(CONFIG_DYNAMIC_DEBUG) -#define netdev_dbg(__dev, format, args...) \ -do { \ - dynamic_netdev_dbg(__dev, format, ##args); \ -} while (0) -#elif defined(DEBUG) -#define netdev_dbg(__dev, format, args...) \ - netdev_printk(KERN_DEBUG, __dev, format, ##args) -#else -#define netdev_dbg(__dev, format, args...) \ -({ \ - if (0) \ - netdev_printk(KERN_DEBUG, __dev, format, ##args); \ -}) -#endif - -#if defined(VERBOSE_DEBUG) -#define netdev_vdbg netdev_dbg -#else - -#define netdev_vdbg(dev, format, args...) \ -({ \ - if (0) \ - netdev_printk(KERN_DEBUG, dev, format, ##args); \ - 0; \ -}) -#endif - -/* - * netdev_WARN() acts like dev_printk(), but with the key difference - * of using a WARN/WARN_ON to get the message out, including the - * file/line information and a backtrace. - */ -#define netdev_WARN(dev, format, args...) \ - WARN(1, "netdevice: %s%s\n" format, netdev_name(dev), \ - netdev_reg_state(dev), ##args) - -/* netif printk helpers, similar to netdev_printk */ - -#define netif_printk(priv, type, level, dev, fmt, args...) \ -do { \ - if (netif_msg_##type(priv)) \ - netdev_printk(level, (dev), fmt, ##args); \ -} while (0) - -#define netif_level(level, priv, type, dev, fmt, args...) \ -do { \ - if (netif_msg_##type(priv)) \ - netdev_##level(dev, fmt, ##args); \ -} while (0) - -#define netif_emerg(priv, type, dev, fmt, args...) \ - netif_level(emerg, priv, type, dev, fmt, ##args) -#define netif_alert(priv, type, dev, fmt, args...) \ - netif_level(alert, priv, type, dev, fmt, ##args) -#define netif_crit(priv, type, dev, fmt, args...) \ - netif_level(crit, priv, type, dev, fmt, ##args) -#define netif_err(priv, type, dev, fmt, args...) \ - netif_level(err, priv, type, dev, fmt, ##args) -#define netif_warn(priv, type, dev, fmt, args...) \ - netif_level(warn, priv, type, dev, fmt, ##args) -#define netif_notice(priv, type, dev, fmt, args...) \ - netif_level(notice, priv, type, dev, fmt, ##args) -#define netif_info(priv, type, dev, fmt, args...) \ - netif_level(info, priv, type, dev, fmt, ##args) - -#if defined(CONFIG_DYNAMIC_DEBUG) -#define netif_dbg(priv, type, netdev, format, args...) \ -do { \ - if (netif_msg_##type(priv)) \ - dynamic_netdev_dbg(netdev, format, ##args); \ -} while (0) -#elif defined(DEBUG) -#define netif_dbg(priv, type, dev, format, args...) \ - netif_printk(priv, type, KERN_DEBUG, dev, format, ##args) -#else -#define netif_dbg(priv, type, dev, format, args...) \ -({ \ - if (0) \ - netif_printk(priv, type, KERN_DEBUG, dev, format, ##args); \ - 0; \ -}) -#endif - -#if defined(VERBOSE_DEBUG) -#define netif_vdbg netif_dbg -#else -#define netif_vdbg(priv, type, dev, format, args...) \ -({ \ - if (0) \ - netif_printk(priv, type, KERN_DEBUG, dev, format, ##args); \ - 0; \ -}) -#endif - -/* - * The list of packet types we will receive (as opposed to discard) - * and the routines to invoke. - * - * Why 16. Because with 16 the only overlap we get on a hash of the - * low nibble of the protocol value is RARP/SNAP/X.25. - * - * NOTE: That is no longer true with the addition of VLAN tags. Not - * sure which should go first, but I bet it won't make much - * difference if we are running VLANs. The good news is that - * this protocol won't be in the list unless compiled in, so - * the average user (w/out VLANs) will not be adversely affected. - * --BLG - * - * 0800 IP - * 8100 802.1Q VLAN - * 0001 802.3 - * 0002 AX.25 - * 0004 802.2 - * 8035 RARP - * 0005 SNAP - * 0805 X.25 - * 0806 ARP - * 8137 IPX - * 0009 Localtalk - * 86DD IPv6 - */ -#define PTYPE_HASH_SIZE (16) -#define PTYPE_HASH_MASK (PTYPE_HASH_SIZE - 1) - -#endif /* _LINUX_NETDEVICE_H */ diff --git a/src/linux/include/linux/netfilter.h b/src/linux/include/linux/netfilter.h deleted file mode 100644 index abc7fdc..0000000 --- a/src/linux/include/linux/netfilter.h +++ /dev/null @@ -1,426 +0,0 @@ -#ifndef __LINUX_NETFILTER_H -#define __LINUX_NETFILTER_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_NETFILTER -static inline int NF_DROP_GETERR(int verdict) -{ - return -(verdict >> NF_VERDICT_QBITS); -} - -static inline int nf_inet_addr_cmp(const union nf_inet_addr *a1, - const union nf_inet_addr *a2) -{ - return a1->all[0] == a2->all[0] && - a1->all[1] == a2->all[1] && - a1->all[2] == a2->all[2] && - a1->all[3] == a2->all[3]; -} - -static inline void nf_inet_addr_mask(const union nf_inet_addr *a1, - union nf_inet_addr *result, - const union nf_inet_addr *mask) -{ - result->all[0] = a1->all[0] & mask->all[0]; - result->all[1] = a1->all[1] & mask->all[1]; - result->all[2] = a1->all[2] & mask->all[2]; - result->all[3] = a1->all[3] & mask->all[3]; -} - -int netfilter_init(void); - -struct sk_buff; - -struct nf_hook_ops; - -struct sock; - -struct nf_hook_state { - unsigned int hook; - int thresh; - u_int8_t pf; - struct net_device *in; - struct net_device *out; - struct sock *sk; - struct net *net; - struct nf_hook_entry __rcu *hook_entries; - int (*okfn)(struct net *, struct sock *, struct sk_buff *); -}; - -typedef unsigned int nf_hookfn(void *priv, - struct sk_buff *skb, - const struct nf_hook_state *state); -struct nf_hook_ops { - struct list_head list; - - /* User fills in from here down. */ - nf_hookfn *hook; - struct net_device *dev; - void *priv; - u_int8_t pf; - unsigned int hooknum; - /* Hooks are ordered in ascending priority. */ - int priority; -}; - -struct nf_hook_entry { - struct nf_hook_entry __rcu *next; - struct nf_hook_ops ops; - const struct nf_hook_ops *orig_ops; -}; - -static inline void nf_hook_state_init(struct nf_hook_state *p, - struct nf_hook_entry *hook_entry, - unsigned int hook, - int thresh, u_int8_t pf, - struct net_device *indev, - struct net_device *outdev, - struct sock *sk, - struct net *net, - int (*okfn)(struct net *, struct sock *, struct sk_buff *)) -{ - p->hook = hook; - p->thresh = thresh; - p->pf = pf; - p->in = indev; - p->out = outdev; - p->sk = sk; - p->net = net; - RCU_INIT_POINTER(p->hook_entries, hook_entry); - p->okfn = okfn; -} - - - -struct nf_sockopt_ops { - struct list_head list; - - u_int8_t pf; - - /* Non-inclusive ranges: use 0/0/NULL to never get called. */ - int set_optmin; - int set_optmax; - int (*set)(struct sock *sk, int optval, void __user *user, unsigned int len); -#ifdef CONFIG_COMPAT - int (*compat_set)(struct sock *sk, int optval, - void __user *user, unsigned int len); -#endif - int get_optmin; - int get_optmax; - int (*get)(struct sock *sk, int optval, void __user *user, int *len); -#ifdef CONFIG_COMPAT - int (*compat_get)(struct sock *sk, int optval, - void __user *user, int *len); -#endif - /* Use the module struct to lock set/get code in place */ - struct module *owner; -}; - -/* Function to register/unregister hook points. */ -int nf_register_net_hook(struct net *net, const struct nf_hook_ops *ops); -void nf_unregister_net_hook(struct net *net, const struct nf_hook_ops *ops); -int nf_register_net_hooks(struct net *net, const struct nf_hook_ops *reg, - unsigned int n); -void nf_unregister_net_hooks(struct net *net, const struct nf_hook_ops *reg, - unsigned int n); - -int nf_register_hook(struct nf_hook_ops *reg); -void nf_unregister_hook(struct nf_hook_ops *reg); -int nf_register_hooks(struct nf_hook_ops *reg, unsigned int n); -void nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n); -int _nf_register_hooks(struct nf_hook_ops *reg, unsigned int n); -void _nf_unregister_hooks(struct nf_hook_ops *reg, unsigned int n); - -/* Functions to register get/setsockopt ranges (non-inclusive). You - need to check permissions yourself! */ -int nf_register_sockopt(struct nf_sockopt_ops *reg); -void nf_unregister_sockopt(struct nf_sockopt_ops *reg); - -#ifdef HAVE_JUMP_LABEL -extern struct static_key nf_hooks_needed[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; -#endif - -int nf_hook_slow(struct sk_buff *skb, struct nf_hook_state *state); - -/** - * nf_hook_thresh - call a netfilter hook - * - * Returns 1 if the hook has allowed the packet to pass. The function - * okfn must be invoked by the caller in this case. Any other return - * value indicates the packet has been consumed by the hook. - */ -static inline int nf_hook_thresh(u_int8_t pf, unsigned int hook, - struct net *net, - struct sock *sk, - struct sk_buff *skb, - struct net_device *indev, - struct net_device *outdev, - int (*okfn)(struct net *, struct sock *, struct sk_buff *), - int thresh) -{ - struct nf_hook_entry *hook_head; - int ret = 1; - -#ifdef HAVE_JUMP_LABEL - if (__builtin_constant_p(pf) && - __builtin_constant_p(hook) && - !static_key_false(&nf_hooks_needed[pf][hook])) - return 1; -#endif - - rcu_read_lock(); - hook_head = rcu_dereference(net->nf.hooks[pf][hook]); - if (hook_head) { - struct nf_hook_state state; - - nf_hook_state_init(&state, hook_head, hook, thresh, - pf, indev, outdev, sk, net, okfn); - - ret = nf_hook_slow(skb, &state); - } - rcu_read_unlock(); - - return ret; -} - -static inline int nf_hook(u_int8_t pf, unsigned int hook, struct net *net, - struct sock *sk, struct sk_buff *skb, - struct net_device *indev, struct net_device *outdev, - int (*okfn)(struct net *, struct sock *, struct sk_buff *)) -{ - return nf_hook_thresh(pf, hook, net, sk, skb, indev, outdev, okfn, INT_MIN); -} - -/* Activate hook; either okfn or kfree_skb called, unless a hook - returns NF_STOLEN (in which case, it's up to the hook to deal with - the consequences). - - Returns -ERRNO if packet dropped. Zero means queued, stolen or - accepted. -*/ - -/* RR: - > I don't want nf_hook to return anything because people might forget - > about async and trust the return value to mean "packet was ok". - - AK: - Just document it clearly, then you can expect some sense from kernel - coders :) -*/ - -static inline int -NF_HOOK_THRESH(uint8_t pf, unsigned int hook, struct net *net, struct sock *sk, - struct sk_buff *skb, struct net_device *in, - struct net_device *out, - int (*okfn)(struct net *, struct sock *, struct sk_buff *), - int thresh) -{ - int ret = nf_hook_thresh(pf, hook, net, sk, skb, in, out, okfn, thresh); - if (ret == 1) - ret = okfn(net, sk, skb); - return ret; -} - -static inline int -NF_HOOK_COND(uint8_t pf, unsigned int hook, struct net *net, struct sock *sk, - struct sk_buff *skb, struct net_device *in, struct net_device *out, - int (*okfn)(struct net *, struct sock *, struct sk_buff *), - bool cond) -{ - int ret; - - if (!cond || - ((ret = nf_hook_thresh(pf, hook, net, sk, skb, in, out, okfn, INT_MIN)) == 1)) - ret = okfn(net, sk, skb); - return ret; -} - -static inline int -NF_HOOK(uint8_t pf, unsigned int hook, struct net *net, struct sock *sk, struct sk_buff *skb, - struct net_device *in, struct net_device *out, - int (*okfn)(struct net *, struct sock *, struct sk_buff *)) -{ - return NF_HOOK_THRESH(pf, hook, net, sk, skb, in, out, okfn, INT_MIN); -} - -/* Call setsockopt() */ -int nf_setsockopt(struct sock *sk, u_int8_t pf, int optval, char __user *opt, - unsigned int len); -int nf_getsockopt(struct sock *sk, u_int8_t pf, int optval, char __user *opt, - int *len); -#ifdef CONFIG_COMPAT -int compat_nf_setsockopt(struct sock *sk, u_int8_t pf, int optval, - char __user *opt, unsigned int len); -int compat_nf_getsockopt(struct sock *sk, u_int8_t pf, int optval, - char __user *opt, int *len); -#endif - -/* Call this before modifying an existing packet: ensures it is - modifiable and linear to the point you care about (writable_len). - Returns true or false. */ -int skb_make_writable(struct sk_buff *skb, unsigned int writable_len); - -struct flowi; -struct nf_queue_entry; - -struct nf_afinfo { - unsigned short family; - __sum16 (*checksum)(struct sk_buff *skb, unsigned int hook, - unsigned int dataoff, u_int8_t protocol); - __sum16 (*checksum_partial)(struct sk_buff *skb, - unsigned int hook, - unsigned int dataoff, - unsigned int len, - u_int8_t protocol); - int (*route)(struct net *net, struct dst_entry **dst, - struct flowi *fl, bool strict); - void (*saveroute)(const struct sk_buff *skb, - struct nf_queue_entry *entry); - int (*reroute)(struct net *net, struct sk_buff *skb, - const struct nf_queue_entry *entry); - int route_key_size; -}; - -extern const struct nf_afinfo __rcu *nf_afinfo[NFPROTO_NUMPROTO]; -static inline const struct nf_afinfo *nf_get_afinfo(unsigned short family) -{ - return rcu_dereference(nf_afinfo[family]); -} - -static inline __sum16 -nf_checksum(struct sk_buff *skb, unsigned int hook, unsigned int dataoff, - u_int8_t protocol, unsigned short family) -{ - const struct nf_afinfo *afinfo; - __sum16 csum = 0; - - rcu_read_lock(); - afinfo = nf_get_afinfo(family); - if (afinfo) - csum = afinfo->checksum(skb, hook, dataoff, protocol); - rcu_read_unlock(); - return csum; -} - -static inline __sum16 -nf_checksum_partial(struct sk_buff *skb, unsigned int hook, - unsigned int dataoff, unsigned int len, - u_int8_t protocol, unsigned short family) -{ - const struct nf_afinfo *afinfo; - __sum16 csum = 0; - - rcu_read_lock(); - afinfo = nf_get_afinfo(family); - if (afinfo) - csum = afinfo->checksum_partial(skb, hook, dataoff, len, - protocol); - rcu_read_unlock(); - return csum; -} - -int nf_register_afinfo(const struct nf_afinfo *afinfo); -void nf_unregister_afinfo(const struct nf_afinfo *afinfo); - -#include -extern void (*nf_nat_decode_session_hook)(struct sk_buff *, struct flowi *); - -static inline void -nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family) -{ -#ifdef CONFIG_NF_NAT_NEEDED - void (*decodefn)(struct sk_buff *, struct flowi *); - - rcu_read_lock(); - decodefn = rcu_dereference(nf_nat_decode_session_hook); - if (decodefn) - decodefn(skb, fl); - rcu_read_unlock(); -#endif -} - -#else /* !CONFIG_NETFILTER */ -static inline int -NF_HOOK_COND(uint8_t pf, unsigned int hook, struct net *net, struct sock *sk, - struct sk_buff *skb, struct net_device *in, struct net_device *out, - int (*okfn)(struct net *, struct sock *, struct sk_buff *), - bool cond) -{ - return okfn(net, sk, skb); -} - -static inline int -NF_HOOK(uint8_t pf, unsigned int hook, struct net *net, struct sock *sk, - struct sk_buff *skb, struct net_device *in, struct net_device *out, - int (*okfn)(struct net *, struct sock *, struct sk_buff *)) -{ - return okfn(net, sk, skb); -} - -static inline int nf_hook(u_int8_t pf, unsigned int hook, struct net *net, - struct sock *sk, struct sk_buff *skb, - struct net_device *indev, struct net_device *outdev, - int (*okfn)(struct net *, struct sock *, struct sk_buff *)) -{ - return 1; -} -struct flowi; -static inline void -nf_nat_decode_session(struct sk_buff *skb, struct flowi *fl, u_int8_t family) -{ -} -#endif /*CONFIG_NETFILTER*/ - -#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) -#include - -extern void (*ip_ct_attach)(struct sk_buff *, const struct sk_buff *) __rcu; -void nf_ct_attach(struct sk_buff *, const struct sk_buff *); -extern void (*nf_ct_destroy)(struct nf_conntrack *) __rcu; -#else -static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {} -#endif - -struct nf_conn; -enum ip_conntrack_info; -struct nlattr; - -struct nfnl_ct_hook { - struct nf_conn *(*get_ct)(const struct sk_buff *skb, - enum ip_conntrack_info *ctinfo); - size_t (*build_size)(const struct nf_conn *ct); - int (*build)(struct sk_buff *skb, struct nf_conn *ct, - enum ip_conntrack_info ctinfo, - u_int16_t ct_attr, u_int16_t ct_info_attr); - int (*parse)(const struct nlattr *attr, struct nf_conn *ct); - int (*attach_expect)(const struct nlattr *attr, struct nf_conn *ct, - u32 portid, u32 report); - void (*seq_adjust)(struct sk_buff *skb, struct nf_conn *ct, - enum ip_conntrack_info ctinfo, s32 off); -}; -extern struct nfnl_ct_hook __rcu *nfnl_ct_hook; - -/** - * nf_skb_duplicated - TEE target has sent a packet - * - * When a xtables target sends a packet, the OUTPUT and POSTROUTING - * hooks are traversed again, i.e. nft and xtables are invoked recursively. - * - * This is used by xtables TEE target to prevent the duplicated skb from - * being duplicated again. - */ -DECLARE_PER_CPU(bool, nf_skb_duplicated); - -#endif /*__LINUX_NETFILTER_H*/ diff --git a/src/linux/include/linux/netfilter_bridge.h b/src/linux/include/linux/netfilter_bridge.h deleted file mode 100644 index 2ed40c4..0000000 --- a/src/linux/include/linux/netfilter_bridge.h +++ /dev/null @@ -1,76 +0,0 @@ -#ifndef __LINUX_BRIDGE_NETFILTER_H -#define __LINUX_BRIDGE_NETFILTER_H - -#include -#include - -enum nf_br_hook_priorities { - NF_BR_PRI_FIRST = INT_MIN, - NF_BR_PRI_NAT_DST_BRIDGED = -300, - NF_BR_PRI_FILTER_BRIDGED = -200, - NF_BR_PRI_BRNF = 0, - NF_BR_PRI_NAT_DST_OTHER = 100, - NF_BR_PRI_FILTER_OTHER = 200, - NF_BR_PRI_NAT_SRC = 300, - NF_BR_PRI_LAST = INT_MAX, -}; - -#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) - -int br_handle_frame_finish(struct net *net, struct sock *sk, struct sk_buff *skb); - -static inline void br_drop_fake_rtable(struct sk_buff *skb) -{ - struct dst_entry *dst = skb_dst(skb); - - if (dst && (dst->flags & DST_FAKE_RTABLE)) - skb_dst_drop(skb); -} - -static inline int nf_bridge_get_physinif(const struct sk_buff *skb) -{ - struct nf_bridge_info *nf_bridge; - - if (skb->nf_bridge == NULL) - return 0; - - nf_bridge = skb->nf_bridge; - return nf_bridge->physindev ? nf_bridge->physindev->ifindex : 0; -} - -static inline int nf_bridge_get_physoutif(const struct sk_buff *skb) -{ - struct nf_bridge_info *nf_bridge; - - if (skb->nf_bridge == NULL) - return 0; - - nf_bridge = skb->nf_bridge; - return nf_bridge->physoutdev ? nf_bridge->physoutdev->ifindex : 0; -} - -static inline struct net_device * -nf_bridge_get_physindev(const struct sk_buff *skb) -{ - return skb->nf_bridge ? skb->nf_bridge->physindev : NULL; -} - -static inline struct net_device * -nf_bridge_get_physoutdev(const struct sk_buff *skb) -{ - return skb->nf_bridge ? skb->nf_bridge->physoutdev : NULL; -} - -static inline bool nf_bridge_in_prerouting(const struct sk_buff *skb) -{ - return skb->nf_bridge && skb->nf_bridge->in_prerouting; -} -#else -#define br_drop_fake_rtable(skb) do { } while (0) -static inline bool nf_bridge_in_prerouting(const struct sk_buff *skb) -{ - return false; -} -#endif /* CONFIG_BRIDGE_NETFILTER */ - -#endif diff --git a/src/linux/include/linux/netfilter_defs.h b/src/linux/include/linux/netfilter_defs.h deleted file mode 100644 index d3a7f85..0000000 --- a/src/linux/include/linux/netfilter_defs.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef __LINUX_NETFILTER_CORE_H_ -#define __LINUX_NETFILTER_CORE_H_ - -#include - -/* Largest hook number + 1, see uapi/linux/netfilter_decnet.h */ -#define NF_MAX_HOOKS 8 - -#endif diff --git a/src/linux/include/linux/netfilter_ingress.h b/src/linux/include/linux/netfilter_ingress.h deleted file mode 100644 index 33e37fb..0000000 --- a/src/linux/include/linux/netfilter_ingress.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef _NETFILTER_INGRESS_H_ -#define _NETFILTER_INGRESS_H_ - -#include -#include - -#ifdef CONFIG_NETFILTER_INGRESS -static inline bool nf_hook_ingress_active(const struct sk_buff *skb) -{ -#ifdef HAVE_JUMP_LABEL - if (!static_key_false(&nf_hooks_needed[NFPROTO_NETDEV][NF_NETDEV_INGRESS])) - return false; -#endif - return rcu_access_pointer(skb->dev->nf_hooks_ingress); -} - -/* caller must hold rcu_read_lock */ -static inline int nf_hook_ingress(struct sk_buff *skb) -{ - struct nf_hook_entry *e = rcu_dereference(skb->dev->nf_hooks_ingress); - struct nf_hook_state state; - - /* Must recheck the ingress hook head, in the event it became NULL - * after the check in nf_hook_ingress_active evaluated to true. - */ - if (unlikely(!e)) - return 0; - - nf_hook_state_init(&state, e, NF_NETDEV_INGRESS, INT_MIN, - NFPROTO_NETDEV, skb->dev, NULL, NULL, - dev_net(skb->dev), NULL); - return nf_hook_slow(skb, &state); -} - -static inline void nf_hook_ingress_init(struct net_device *dev) -{ - RCU_INIT_POINTER(dev->nf_hooks_ingress, NULL); -} -#else /* CONFIG_NETFILTER_INGRESS */ -static inline int nf_hook_ingress_active(struct sk_buff *skb) -{ - return 0; -} - -static inline int nf_hook_ingress(struct sk_buff *skb) -{ - return 0; -} - -static inline void nf_hook_ingress_init(struct net_device *dev) {} -#endif /* CONFIG_NETFILTER_INGRESS */ -#endif /* _NETFILTER_INGRESS_H_ */ diff --git a/src/linux/include/linux/netfilter_ipv4.h b/src/linux/include/linux/netfilter_ipv4.h deleted file mode 100644 index 98c03b2..0000000 --- a/src/linux/include/linux/netfilter_ipv4.h +++ /dev/null @@ -1,12 +0,0 @@ -/* IPv4-specific defines for netfilter. - * (C)1998 Rusty Russell -- This code is GPL. - */ -#ifndef __LINUX_IP_NETFILTER_H -#define __LINUX_IP_NETFILTER_H - -#include - -int ip_route_me_harder(struct net *net, struct sk_buff *skb, unsigned addr_type); -__sum16 nf_ip_checksum(struct sk_buff *skb, unsigned int hook, - unsigned int dataoff, u_int8_t protocol); -#endif /*__LINUX_IP_NETFILTER_H*/ diff --git a/src/linux/include/linux/netfilter_ipv6.h b/src/linux/include/linux/netfilter_ipv6.h deleted file mode 100644 index 47c6b04..0000000 --- a/src/linux/include/linux/netfilter_ipv6.h +++ /dev/null @@ -1,44 +0,0 @@ -/* IPv6-specific defines for netfilter. - * (C)1998 Rusty Russell -- This code is GPL. - * (C)1999 David Jeffery - * this header was blatantly ripped from netfilter_ipv4.h - * it's amazing what adding a bunch of 6s can do =8^) - */ -#ifndef __LINUX_IP6_NETFILTER_H -#define __LINUX_IP6_NETFILTER_H - -#include - -/* - * Hook functions for ipv6 to allow xt_* modules to be built-in even - * if IPv6 is a module. - */ -struct nf_ipv6_ops { - int (*chk_addr)(struct net *net, const struct in6_addr *addr, - const struct net_device *dev, int strict); - void (*route_input)(struct sk_buff *skb); - int (*fragment)(struct net *net, struct sock *sk, struct sk_buff *skb, - int (*output)(struct net *, struct sock *, struct sk_buff *)); -}; - -#ifdef CONFIG_NETFILTER -int ip6_route_me_harder(struct net *net, struct sk_buff *skb); -__sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, - unsigned int dataoff, u_int8_t protocol); - -int ipv6_netfilter_init(void); -void ipv6_netfilter_fini(void); - -extern const struct nf_ipv6_ops __rcu *nf_ipv6_ops; -static inline const struct nf_ipv6_ops *nf_get_ipv6_ops(void) -{ - return rcu_dereference(nf_ipv6_ops); -} - -#else /* CONFIG_NETFILTER */ -static inline int ipv6_netfilter_init(void) { return 0; } -static inline void ipv6_netfilter_fini(void) { return; } -static inline const struct nf_ipv6_ops *nf_get_ipv6_ops(void) { return NULL; } -#endif /* CONFIG_NETFILTER */ - -#endif /*__LINUX_IP6_NETFILTER_H*/ diff --git a/src/linux/include/linux/netlink.h b/src/linux/include/linux/netlink.h deleted file mode 100644 index da14ab6..0000000 --- a/src/linux/include/linux/netlink.h +++ /dev/null @@ -1,184 +0,0 @@ -#ifndef __LINUX_NETLINK_H -#define __LINUX_NETLINK_H - - -#include -#include -#include -#include -#include - -struct net; - -static inline struct nlmsghdr *nlmsg_hdr(const struct sk_buff *skb) -{ - return (struct nlmsghdr *)skb->data; -} - -enum netlink_skb_flags { - NETLINK_SKB_MMAPED = 0x1, /* Packet data is mmaped */ - NETLINK_SKB_TX = 0x2, /* Packet was sent by userspace */ - NETLINK_SKB_DELIVERED = 0x4, /* Packet was delivered */ - NETLINK_SKB_DST = 0x8, /* Dst set in sendto or sendmsg */ -}; - -struct netlink_skb_parms { - struct scm_creds creds; /* Skb credentials */ - __u32 portid; - __u32 dst_group; - __u32 flags; - struct sock *sk; - bool nsid_is_set; - int nsid; -}; - -#define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb)) -#define NETLINK_CREDS(skb) (&NETLINK_CB((skb)).creds) - - -extern void netlink_table_grab(void); -extern void netlink_table_ungrab(void); - -#define NL_CFG_F_NONROOT_RECV (1 << 0) -#define NL_CFG_F_NONROOT_SEND (1 << 1) - -/* optional Netlink kernel configuration parameters */ -struct netlink_kernel_cfg { - unsigned int groups; - unsigned int flags; - void (*input)(struct sk_buff *skb); - struct mutex *cb_mutex; - int (*bind)(struct net *net, int group); - void (*unbind)(struct net *net, int group); - bool (*compare)(struct net *net, struct sock *sk); -}; - -extern struct sock *__netlink_kernel_create(struct net *net, int unit, - struct module *module, - struct netlink_kernel_cfg *cfg); -static inline struct sock * -netlink_kernel_create(struct net *net, int unit, struct netlink_kernel_cfg *cfg) -{ - return __netlink_kernel_create(net, unit, THIS_MODULE, cfg); -} - -extern void netlink_kernel_release(struct sock *sk); -extern int __netlink_change_ngroups(struct sock *sk, unsigned int groups); -extern int netlink_change_ngroups(struct sock *sk, unsigned int groups); -extern void __netlink_clear_multicast_users(struct sock *sk, unsigned int group); -extern void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err); -extern int netlink_has_listeners(struct sock *sk, unsigned int group); - -extern int netlink_unicast(struct sock *ssk, struct sk_buff *skb, __u32 portid, int nonblock); -extern int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, __u32 portid, - __u32 group, gfp_t allocation); -extern int netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb, - __u32 portid, __u32 group, gfp_t allocation, - int (*filter)(struct sock *dsk, struct sk_buff *skb, void *data), - void *filter_data); -extern int netlink_set_err(struct sock *ssk, __u32 portid, __u32 group, int code); -extern int netlink_register_notifier(struct notifier_block *nb); -extern int netlink_unregister_notifier(struct notifier_block *nb); - -/* finegrained unicast helpers: */ -struct sock *netlink_getsockbyfilp(struct file *filp); -int netlink_attachskb(struct sock *sk, struct sk_buff *skb, - long *timeo, struct sock *ssk); -void netlink_detachskb(struct sock *sk, struct sk_buff *skb); -int netlink_sendskb(struct sock *sk, struct sk_buff *skb); - -static inline struct sk_buff * -netlink_skb_clone(struct sk_buff *skb, gfp_t gfp_mask) -{ - struct sk_buff *nskb; - - nskb = skb_clone(skb, gfp_mask); - if (!nskb) - return NULL; - - /* This is a large skb, set destructor callback to release head */ - if (is_vmalloc_addr(skb->head)) - nskb->destructor = skb->destructor; - - return nskb; -} - -/* - * skb should fit one page. This choice is good for headerless malloc. - * But we should limit to 8K so that userspace does not have to - * use enormous buffer sizes on recvmsg() calls just to avoid - * MSG_TRUNC when PAGE_SIZE is very large. - */ -#if PAGE_SIZE < 8192UL -#define NLMSG_GOODSIZE SKB_WITH_OVERHEAD(PAGE_SIZE) -#else -#define NLMSG_GOODSIZE SKB_WITH_OVERHEAD(8192UL) -#endif - -#define NLMSG_DEFAULT_SIZE (NLMSG_GOODSIZE - NLMSG_HDRLEN) - - -struct netlink_callback { - struct sk_buff *skb; - const struct nlmsghdr *nlh; - int (*start)(struct netlink_callback *); - int (*dump)(struct sk_buff * skb, - struct netlink_callback *cb); - int (*done)(struct netlink_callback *cb); - void *data; - /* the module that dump function belong to */ - struct module *module; - u16 family; - u16 min_dump_alloc; - unsigned int prev_seq, seq; - long args[6]; -}; - -struct netlink_notify { - struct net *net; - u32 portid; - int protocol; -}; - -struct nlmsghdr * -__nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int len, int flags); - -struct netlink_dump_control { - int (*start)(struct netlink_callback *); - int (*dump)(struct sk_buff *skb, struct netlink_callback *); - int (*done)(struct netlink_callback *); - void *data; - struct module *module; - u16 min_dump_alloc; -}; - -extern int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, - const struct nlmsghdr *nlh, - struct netlink_dump_control *control); -static inline int netlink_dump_start(struct sock *ssk, struct sk_buff *skb, - const struct nlmsghdr *nlh, - struct netlink_dump_control *control) -{ - if (!control->module) - control->module = THIS_MODULE; - - return __netlink_dump_start(ssk, skb, nlh, control); -} - -struct netlink_tap { - struct net_device *dev; - struct module *module; - struct list_head list; -}; - -extern int netlink_add_tap(struct netlink_tap *nt); -extern int netlink_remove_tap(struct netlink_tap *nt); - -bool __netlink_ns_capable(const struct netlink_skb_parms *nsp, - struct user_namespace *ns, int cap); -bool netlink_ns_capable(const struct sk_buff *skb, - struct user_namespace *ns, int cap); -bool netlink_capable(const struct sk_buff *skb, int cap); -bool netlink_net_capable(const struct sk_buff *skb, int cap); - -#endif /* __LINUX_NETLINK_H */ diff --git a/src/linux/include/linux/netpoll.h b/src/linux/include/linux/netpoll.h deleted file mode 100644 index b25ee9f..0000000 --- a/src/linux/include/linux/netpoll.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Common code for low-level network console, dump, and debugger code - * - * Derived from netconsole, kgdb-over-ethernet, and netdump patches - */ - -#ifndef _LINUX_NETPOLL_H -#define _LINUX_NETPOLL_H - -#include -#include -#include -#include - -union inet_addr { - __u32 all[4]; - __be32 ip; - __be32 ip6[4]; - struct in_addr in; - struct in6_addr in6; -}; - -struct netpoll { - struct net_device *dev; - char dev_name[IFNAMSIZ]; - const char *name; - - union inet_addr local_ip, remote_ip; - bool ipv6; - u16 local_port, remote_port; - u8 remote_mac[ETH_ALEN]; - - struct work_struct cleanup_work; -}; - -struct netpoll_info { - atomic_t refcnt; - - struct semaphore dev_lock; - - struct sk_buff_head txq; - - struct delayed_work tx_work; - - struct netpoll *netpoll; - struct rcu_head rcu; -}; - -#ifdef CONFIG_NETPOLL -extern void netpoll_poll_disable(struct net_device *dev); -extern void netpoll_poll_enable(struct net_device *dev); -#else -static inline void netpoll_poll_disable(struct net_device *dev) { return; } -static inline void netpoll_poll_enable(struct net_device *dev) { return; } -#endif - -void netpoll_send_udp(struct netpoll *np, const char *msg, int len); -void netpoll_print_options(struct netpoll *np); -int netpoll_parse_options(struct netpoll *np, char *opt); -int __netpoll_setup(struct netpoll *np, struct net_device *ndev); -int netpoll_setup(struct netpoll *np); -void __netpoll_cleanup(struct netpoll *np); -void __netpoll_free_async(struct netpoll *np); -void netpoll_cleanup(struct netpoll *np); -void netpoll_send_skb_on_dev(struct netpoll *np, struct sk_buff *skb, - struct net_device *dev); -static inline void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) -{ - unsigned long flags; - local_irq_save(flags); - netpoll_send_skb_on_dev(np, skb, np->dev); - local_irq_restore(flags); -} - -#ifdef CONFIG_NETPOLL -static inline void *netpoll_poll_lock(struct napi_struct *napi) -{ - struct net_device *dev = napi->dev; - - if (dev && dev->npinfo) { - spin_lock(&napi->poll_lock); - napi->poll_owner = smp_processor_id(); - return napi; - } - return NULL; -} - -static inline void netpoll_poll_unlock(void *have) -{ - struct napi_struct *napi = have; - - if (napi) { - napi->poll_owner = -1; - spin_unlock(&napi->poll_lock); - } -} - -static inline bool netpoll_tx_running(struct net_device *dev) -{ - return irqs_disabled(); -} - -#else -static inline void *netpoll_poll_lock(struct napi_struct *napi) -{ - return NULL; -} -static inline void netpoll_poll_unlock(void *have) -{ -} -static inline void netpoll_netdev_init(struct net_device *dev) -{ -} -static inline bool netpoll_tx_running(struct net_device *dev) -{ - return false; -} -#endif - -#endif diff --git a/src/linux/include/linux/nfs.h b/src/linux/include/linux/nfs.h deleted file mode 100644 index 610af51..0000000 --- a/src/linux/include/linux/nfs.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * NFS protocol definitions - * - * This file contains constants mostly for Version 2 of the protocol, - * but also has a couple of NFSv3 bits in (notably the error codes). - */ -#ifndef _LINUX_NFS_H -#define _LINUX_NFS_H - -#include -#include -#include - -/* - * This is the kernel NFS client file handle representation - */ -#define NFS_MAXFHSIZE 128 -struct nfs_fh { - unsigned short size; - unsigned char data[NFS_MAXFHSIZE]; -}; - -/* - * Returns a zero iff the size and data fields match. - * Checks only "size" bytes in the data field. - */ -static inline int nfs_compare_fh(const struct nfs_fh *a, const struct nfs_fh *b) -{ - return a->size != b->size || memcmp(a->data, b->data, a->size) != 0; -} - -static inline void nfs_copy_fh(struct nfs_fh *target, const struct nfs_fh *source) -{ - target->size = source->size; - memcpy(target->data, source->data, source->size); -} - - -/* - * This is really a general kernel constant, but since nothing like - * this is defined in the kernel headers, I have to do it here. - */ -#define NFS_OFFSET_MAX ((__s64)((~(__u64)0) >> 1)) - - -enum nfs3_stable_how { - NFS_UNSTABLE = 0, - NFS_DATA_SYNC = 1, - NFS_FILE_SYNC = 2, - - /* used by direct.c to mark verf as invalid */ - NFS_INVALID_STABLE_HOW = -1 -}; -#endif /* _LINUX_NFS_H */ diff --git a/src/linux/include/linux/nfs3.h b/src/linux/include/linux/nfs3.h deleted file mode 100644 index a778ad8..0000000 --- a/src/linux/include/linux/nfs3.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * NFSv3 protocol definitions - */ -#ifndef _LINUX_NFS3_H -#define _LINUX_NFS3_H - -#include - - -/* Number of 32bit words in post_op_attr */ -#define NFS3_POST_OP_ATTR_WORDS 22 - -#endif /* _LINUX_NFS3_H */ diff --git a/src/linux/include/linux/nfs4.h b/src/linux/include/linux/nfs4.h deleted file mode 100644 index 9094faf..0000000 --- a/src/linux/include/linux/nfs4.h +++ /dev/null @@ -1,658 +0,0 @@ -/* - * include/linux/nfs4.h - * - * NFSv4 protocol definitions. - * - * Copyright (c) 2002 The Regents of the University of Michigan. - * All rights reserved. - * - * Kendrick Smith - * Andy Adamson - */ -#ifndef _LINUX_NFS4_H -#define _LINUX_NFS4_H - -#include -#include -#include - -enum nfs4_acl_whotype { - NFS4_ACL_WHO_NAMED = 0, - NFS4_ACL_WHO_OWNER, - NFS4_ACL_WHO_GROUP, - NFS4_ACL_WHO_EVERYONE, -}; - -struct nfs4_ace { - uint32_t type; - uint32_t flag; - uint32_t access_mask; - int whotype; - union { - kuid_t who_uid; - kgid_t who_gid; - }; -}; - -struct nfs4_acl { - uint32_t naces; - struct nfs4_ace aces[0]; -}; - -#define NFS4_MAXLABELLEN 2048 - -struct nfs4_label { - uint32_t lfs; - uint32_t pi; - u32 len; - char *label; -}; - -typedef struct { char data[NFS4_VERIFIER_SIZE]; } nfs4_verifier; - -struct nfs4_stateid_struct { - union { - char data[NFS4_STATEID_SIZE]; - struct { - __be32 seqid; - char other[NFS4_STATEID_OTHER_SIZE]; - } __attribute__ ((packed)); - }; - - enum { - NFS4_INVALID_STATEID_TYPE = 0, - NFS4_SPECIAL_STATEID_TYPE, - NFS4_OPEN_STATEID_TYPE, - NFS4_LOCK_STATEID_TYPE, - NFS4_DELEGATION_STATEID_TYPE, - NFS4_LAYOUT_STATEID_TYPE, - NFS4_PNFS_DS_STATEID_TYPE, - NFS4_REVOKED_STATEID_TYPE, - } type; -}; - -typedef struct nfs4_stateid_struct nfs4_stateid; - -enum nfs_opnum4 { - OP_ACCESS = 3, - OP_CLOSE = 4, - OP_COMMIT = 5, - OP_CREATE = 6, - OP_DELEGPURGE = 7, - OP_DELEGRETURN = 8, - OP_GETATTR = 9, - OP_GETFH = 10, - OP_LINK = 11, - OP_LOCK = 12, - OP_LOCKT = 13, - OP_LOCKU = 14, - OP_LOOKUP = 15, - OP_LOOKUPP = 16, - OP_NVERIFY = 17, - OP_OPEN = 18, - OP_OPENATTR = 19, - OP_OPEN_CONFIRM = 20, - OP_OPEN_DOWNGRADE = 21, - OP_PUTFH = 22, - OP_PUTPUBFH = 23, - OP_PUTROOTFH = 24, - OP_READ = 25, - OP_READDIR = 26, - OP_READLINK = 27, - OP_REMOVE = 28, - OP_RENAME = 29, - OP_RENEW = 30, - OP_RESTOREFH = 31, - OP_SAVEFH = 32, - OP_SECINFO = 33, - OP_SETATTR = 34, - OP_SETCLIENTID = 35, - OP_SETCLIENTID_CONFIRM = 36, - OP_VERIFY = 37, - OP_WRITE = 38, - OP_RELEASE_LOCKOWNER = 39, - - /* nfs41 */ - OP_BACKCHANNEL_CTL = 40, - OP_BIND_CONN_TO_SESSION = 41, - OP_EXCHANGE_ID = 42, - OP_CREATE_SESSION = 43, - OP_DESTROY_SESSION = 44, - OP_FREE_STATEID = 45, - OP_GET_DIR_DELEGATION = 46, - OP_GETDEVICEINFO = 47, - OP_GETDEVICELIST = 48, - OP_LAYOUTCOMMIT = 49, - OP_LAYOUTGET = 50, - OP_LAYOUTRETURN = 51, - OP_SECINFO_NO_NAME = 52, - OP_SEQUENCE = 53, - OP_SET_SSV = 54, - OP_TEST_STATEID = 55, - OP_WANT_DELEGATION = 56, - OP_DESTROY_CLIENTID = 57, - OP_RECLAIM_COMPLETE = 58, - - /* nfs42 */ - OP_ALLOCATE = 59, - OP_COPY = 60, - OP_COPY_NOTIFY = 61, - OP_DEALLOCATE = 62, - OP_IO_ADVISE = 63, - OP_LAYOUTERROR = 64, - OP_LAYOUTSTATS = 65, - OP_OFFLOAD_CANCEL = 66, - OP_OFFLOAD_STATUS = 67, - OP_READ_PLUS = 68, - OP_SEEK = 69, - OP_WRITE_SAME = 70, - OP_CLONE = 71, - - OP_ILLEGAL = 10044, -}; - -/*Defining first and last NFS4 operations implemented. -Needs to be updated if more operations are defined in future.*/ - -#define FIRST_NFS4_OP OP_ACCESS -#define LAST_NFS40_OP OP_RELEASE_LOCKOWNER -#define LAST_NFS41_OP OP_RECLAIM_COMPLETE -#define LAST_NFS42_OP OP_CLONE -#define LAST_NFS4_OP LAST_NFS42_OP - -enum nfsstat4 { - NFS4_OK = 0, - NFS4ERR_PERM = 1, - NFS4ERR_NOENT = 2, - NFS4ERR_IO = 5, - NFS4ERR_NXIO = 6, - NFS4ERR_ACCESS = 13, - NFS4ERR_EXIST = 17, - NFS4ERR_XDEV = 18, - /* Unused/reserved 19 */ - NFS4ERR_NOTDIR = 20, - NFS4ERR_ISDIR = 21, - NFS4ERR_INVAL = 22, - NFS4ERR_FBIG = 27, - NFS4ERR_NOSPC = 28, - NFS4ERR_ROFS = 30, - NFS4ERR_MLINK = 31, - NFS4ERR_NAMETOOLONG = 63, - NFS4ERR_NOTEMPTY = 66, - NFS4ERR_DQUOT = 69, - NFS4ERR_STALE = 70, - NFS4ERR_BADHANDLE = 10001, - NFS4ERR_BAD_COOKIE = 10003, - NFS4ERR_NOTSUPP = 10004, - NFS4ERR_TOOSMALL = 10005, - NFS4ERR_SERVERFAULT = 10006, - NFS4ERR_BADTYPE = 10007, - NFS4ERR_DELAY = 10008, - NFS4ERR_SAME = 10009, - NFS4ERR_DENIED = 10010, - NFS4ERR_EXPIRED = 10011, - NFS4ERR_LOCKED = 10012, - NFS4ERR_GRACE = 10013, - NFS4ERR_FHEXPIRED = 10014, - NFS4ERR_SHARE_DENIED = 10015, - NFS4ERR_WRONGSEC = 10016, - NFS4ERR_CLID_INUSE = 10017, - NFS4ERR_RESOURCE = 10018, - NFS4ERR_MOVED = 10019, - NFS4ERR_NOFILEHANDLE = 10020, - NFS4ERR_MINOR_VERS_MISMATCH = 10021, - NFS4ERR_STALE_CLIENTID = 10022, - NFS4ERR_STALE_STATEID = 10023, - NFS4ERR_OLD_STATEID = 10024, - NFS4ERR_BAD_STATEID = 10025, - NFS4ERR_BAD_SEQID = 10026, - NFS4ERR_NOT_SAME = 10027, - NFS4ERR_LOCK_RANGE = 10028, - NFS4ERR_SYMLINK = 10029, - NFS4ERR_RESTOREFH = 10030, - NFS4ERR_LEASE_MOVED = 10031, - NFS4ERR_ATTRNOTSUPP = 10032, - NFS4ERR_NO_GRACE = 10033, - NFS4ERR_RECLAIM_BAD = 10034, - NFS4ERR_RECLAIM_CONFLICT = 10035, - NFS4ERR_BADXDR = 10036, - NFS4ERR_LOCKS_HELD = 10037, - NFS4ERR_OPENMODE = 10038, - NFS4ERR_BADOWNER = 10039, - NFS4ERR_BADCHAR = 10040, - NFS4ERR_BADNAME = 10041, - NFS4ERR_BAD_RANGE = 10042, - NFS4ERR_LOCK_NOTSUPP = 10043, - NFS4ERR_OP_ILLEGAL = 10044, - NFS4ERR_DEADLOCK = 10045, - NFS4ERR_FILE_OPEN = 10046, - NFS4ERR_ADMIN_REVOKED = 10047, - NFS4ERR_CB_PATH_DOWN = 10048, - - /* nfs41 */ - NFS4ERR_BADIOMODE = 10049, - NFS4ERR_BADLAYOUT = 10050, - NFS4ERR_BAD_SESSION_DIGEST = 10051, - NFS4ERR_BADSESSION = 10052, - NFS4ERR_BADSLOT = 10053, - NFS4ERR_COMPLETE_ALREADY = 10054, - NFS4ERR_CONN_NOT_BOUND_TO_SESSION = 10055, - NFS4ERR_DELEG_ALREADY_WANTED = 10056, - NFS4ERR_BACK_CHAN_BUSY = 10057, /* backchan reqs outstanding */ - NFS4ERR_LAYOUTTRYLATER = 10058, - NFS4ERR_LAYOUTUNAVAILABLE = 10059, - NFS4ERR_NOMATCHING_LAYOUT = 10060, - NFS4ERR_RECALLCONFLICT = 10061, - NFS4ERR_UNKNOWN_LAYOUTTYPE = 10062, - NFS4ERR_SEQ_MISORDERED = 10063, /* unexpected seq.id in req */ - NFS4ERR_SEQUENCE_POS = 10064, /* [CB_]SEQ. op not 1st op */ - NFS4ERR_REQ_TOO_BIG = 10065, /* request too big */ - NFS4ERR_REP_TOO_BIG = 10066, /* reply too big */ - NFS4ERR_REP_TOO_BIG_TO_CACHE = 10067, /* rep. not all cached */ - NFS4ERR_RETRY_UNCACHED_REP = 10068, /* retry & rep. uncached */ - NFS4ERR_UNSAFE_COMPOUND = 10069, /* retry/recovery too hard */ - NFS4ERR_TOO_MANY_OPS = 10070, /* too many ops in [CB_]COMP */ - NFS4ERR_OP_NOT_IN_SESSION = 10071, /* op needs [CB_]SEQ. op */ - NFS4ERR_HASH_ALG_UNSUPP = 10072, /* hash alg. not supp. */ - /* Error 10073 is unused. */ - NFS4ERR_CLIENTID_BUSY = 10074, /* clientid has state */ - NFS4ERR_PNFS_IO_HOLE = 10075, /* IO to _SPARSE file hole */ - NFS4ERR_SEQ_FALSE_RETRY = 10076, /* retry not original */ - NFS4ERR_BAD_HIGH_SLOT = 10077, /* sequence arg bad */ - NFS4ERR_DEADSESSION = 10078, /* persistent session dead */ - NFS4ERR_ENCR_ALG_UNSUPP = 10079, /* SSV alg mismatch */ - NFS4ERR_PNFS_NO_LAYOUT = 10080, /* direct I/O with no layout */ - NFS4ERR_NOT_ONLY_OP = 10081, /* bad compound */ - NFS4ERR_WRONG_CRED = 10082, /* permissions:state change */ - NFS4ERR_WRONG_TYPE = 10083, /* current operation mismatch */ - NFS4ERR_DIRDELEG_UNAVAIL = 10084, /* no directory delegation */ - NFS4ERR_REJECT_DELEG = 10085, /* on callback */ - NFS4ERR_RETURNCONFLICT = 10086, /* outstanding layoutreturn */ - NFS4ERR_DELEG_REVOKED = 10087, /* deleg./layout revoked */ - - /* nfs42 */ - NFS4ERR_PARTNER_NOTSUPP = 10088, - NFS4ERR_PARTNER_NO_AUTH = 10089, - NFS4ERR_UNION_NOTSUPP = 10090, - NFS4ERR_OFFLOAD_DENIED = 10091, - NFS4ERR_WRONG_LFS = 10092, - NFS4ERR_BADLABEL = 10093, - NFS4ERR_OFFLOAD_NO_REQS = 10094, -}; - -static inline bool seqid_mutating_err(u32 err) -{ - /* rfc 3530 section 8.1.5: */ - switch (err) { - case NFS4ERR_STALE_CLIENTID: - case NFS4ERR_STALE_STATEID: - case NFS4ERR_BAD_STATEID: - case NFS4ERR_BAD_SEQID: - case NFS4ERR_BADXDR: - case NFS4ERR_RESOURCE: - case NFS4ERR_NOFILEHANDLE: - return false; - }; - return true; -} - -/* - * Note: NF4BAD is not actually part of the protocol; it is just used - * internally by nfsd. - */ -enum nfs_ftype4 { - NF4BAD = 0, - NF4REG = 1, /* Regular File */ - NF4DIR = 2, /* Directory */ - NF4BLK = 3, /* Special File - block device */ - NF4CHR = 4, /* Special File - character device */ - NF4LNK = 5, /* Symbolic Link */ - NF4SOCK = 6, /* Special File - socket */ - NF4FIFO = 7, /* Special File - fifo */ - NF4ATTRDIR = 8, /* Attribute Directory */ - NF4NAMEDATTR = 9 /* Named Attribute */ -}; - -enum open_claim_type4 { - NFS4_OPEN_CLAIM_NULL = 0, - NFS4_OPEN_CLAIM_PREVIOUS = 1, - NFS4_OPEN_CLAIM_DELEGATE_CUR = 2, - NFS4_OPEN_CLAIM_DELEGATE_PREV = 3, - NFS4_OPEN_CLAIM_FH = 4, /* 4.1 */ - NFS4_OPEN_CLAIM_DELEG_CUR_FH = 5, /* 4.1 */ - NFS4_OPEN_CLAIM_DELEG_PREV_FH = 6, /* 4.1 */ -}; - -enum opentype4 { - NFS4_OPEN_NOCREATE = 0, - NFS4_OPEN_CREATE = 1 -}; - -enum createmode4 { - NFS4_CREATE_UNCHECKED = 0, - NFS4_CREATE_GUARDED = 1, - NFS4_CREATE_EXCLUSIVE = 2, - /* - * New to NFSv4.1. If session is persistent, - * GUARDED4 MUST be used. Otherwise, use - * EXCLUSIVE4_1 instead of EXCLUSIVE4. - */ - NFS4_CREATE_EXCLUSIVE4_1 = 3 -}; - -enum limit_by4 { - NFS4_LIMIT_SIZE = 1, - NFS4_LIMIT_BLOCKS = 2 -}; - -enum open_delegation_type4 { - NFS4_OPEN_DELEGATE_NONE = 0, - NFS4_OPEN_DELEGATE_READ = 1, - NFS4_OPEN_DELEGATE_WRITE = 2, - NFS4_OPEN_DELEGATE_NONE_EXT = 3, /* 4.1 */ -}; - -enum why_no_delegation4 { /* new to v4.1 */ - WND4_NOT_WANTED = 0, - WND4_CONTENTION = 1, - WND4_RESOURCE = 2, - WND4_NOT_SUPP_FTYPE = 3, - WND4_WRITE_DELEG_NOT_SUPP_FTYPE = 4, - WND4_NOT_SUPP_UPGRADE = 5, - WND4_NOT_SUPP_DOWNGRADE = 6, - WND4_CANCELLED = 7, - WND4_IS_DIR = 8, -}; - -enum lock_type4 { - NFS4_UNLOCK_LT = 0, - NFS4_READ_LT = 1, - NFS4_WRITE_LT = 2, - NFS4_READW_LT = 3, - NFS4_WRITEW_LT = 4 -}; - - -/* Mandatory Attributes */ -#define FATTR4_WORD0_SUPPORTED_ATTRS (1UL << 0) -#define FATTR4_WORD0_TYPE (1UL << 1) -#define FATTR4_WORD0_FH_EXPIRE_TYPE (1UL << 2) -#define FATTR4_WORD0_CHANGE (1UL << 3) -#define FATTR4_WORD0_SIZE (1UL << 4) -#define FATTR4_WORD0_LINK_SUPPORT (1UL << 5) -#define FATTR4_WORD0_SYMLINK_SUPPORT (1UL << 6) -#define FATTR4_WORD0_NAMED_ATTR (1UL << 7) -#define FATTR4_WORD0_FSID (1UL << 8) -#define FATTR4_WORD0_UNIQUE_HANDLES (1UL << 9) -#define FATTR4_WORD0_LEASE_TIME (1UL << 10) -#define FATTR4_WORD0_RDATTR_ERROR (1UL << 11) -/* Mandatory in NFSv4.1 */ -#define FATTR4_WORD2_SUPPATTR_EXCLCREAT (1UL << 11) - -/* Recommended Attributes */ -#define FATTR4_WORD0_ACL (1UL << 12) -#define FATTR4_WORD0_ACLSUPPORT (1UL << 13) -#define FATTR4_WORD0_ARCHIVE (1UL << 14) -#define FATTR4_WORD0_CANSETTIME (1UL << 15) -#define FATTR4_WORD0_CASE_INSENSITIVE (1UL << 16) -#define FATTR4_WORD0_CASE_PRESERVING (1UL << 17) -#define FATTR4_WORD0_CHOWN_RESTRICTED (1UL << 18) -#define FATTR4_WORD0_FILEHANDLE (1UL << 19) -#define FATTR4_WORD0_FILEID (1UL << 20) -#define FATTR4_WORD0_FILES_AVAIL (1UL << 21) -#define FATTR4_WORD0_FILES_FREE (1UL << 22) -#define FATTR4_WORD0_FILES_TOTAL (1UL << 23) -#define FATTR4_WORD0_FS_LOCATIONS (1UL << 24) -#define FATTR4_WORD0_HIDDEN (1UL << 25) -#define FATTR4_WORD0_HOMOGENEOUS (1UL << 26) -#define FATTR4_WORD0_MAXFILESIZE (1UL << 27) -#define FATTR4_WORD0_MAXLINK (1UL << 28) -#define FATTR4_WORD0_MAXNAME (1UL << 29) -#define FATTR4_WORD0_MAXREAD (1UL << 30) -#define FATTR4_WORD0_MAXWRITE (1UL << 31) -#define FATTR4_WORD1_MIMETYPE (1UL << 0) -#define FATTR4_WORD1_MODE (1UL << 1) -#define FATTR4_WORD1_NO_TRUNC (1UL << 2) -#define FATTR4_WORD1_NUMLINKS (1UL << 3) -#define FATTR4_WORD1_OWNER (1UL << 4) -#define FATTR4_WORD1_OWNER_GROUP (1UL << 5) -#define FATTR4_WORD1_QUOTA_HARD (1UL << 6) -#define FATTR4_WORD1_QUOTA_SOFT (1UL << 7) -#define FATTR4_WORD1_QUOTA_USED (1UL << 8) -#define FATTR4_WORD1_RAWDEV (1UL << 9) -#define FATTR4_WORD1_SPACE_AVAIL (1UL << 10) -#define FATTR4_WORD1_SPACE_FREE (1UL << 11) -#define FATTR4_WORD1_SPACE_TOTAL (1UL << 12) -#define FATTR4_WORD1_SPACE_USED (1UL << 13) -#define FATTR4_WORD1_SYSTEM (1UL << 14) -#define FATTR4_WORD1_TIME_ACCESS (1UL << 15) -#define FATTR4_WORD1_TIME_ACCESS_SET (1UL << 16) -#define FATTR4_WORD1_TIME_BACKUP (1UL << 17) -#define FATTR4_WORD1_TIME_CREATE (1UL << 18) -#define FATTR4_WORD1_TIME_DELTA (1UL << 19) -#define FATTR4_WORD1_TIME_METADATA (1UL << 20) -#define FATTR4_WORD1_TIME_MODIFY (1UL << 21) -#define FATTR4_WORD1_TIME_MODIFY_SET (1UL << 22) -#define FATTR4_WORD1_MOUNTED_ON_FILEID (1UL << 23) -#define FATTR4_WORD1_FS_LAYOUT_TYPES (1UL << 30) -#define FATTR4_WORD2_LAYOUT_TYPES (1UL << 0) -#define FATTR4_WORD2_LAYOUT_BLKSIZE (1UL << 1) -#define FATTR4_WORD2_MDSTHRESHOLD (1UL << 4) -#define FATTR4_WORD2_CLONE_BLKSIZE (1UL << 13) -#define FATTR4_WORD2_SECURITY_LABEL (1UL << 16) - -/* MDS threshold bitmap bits */ -#define THRESHOLD_RD (1UL << 0) -#define THRESHOLD_WR (1UL << 1) -#define THRESHOLD_RD_IO (1UL << 2) -#define THRESHOLD_WR_IO (1UL << 3) - -#define NFSPROC4_NULL 0 -#define NFSPROC4_COMPOUND 1 -#define NFS4_VERSION 4 -#define NFS4_MINOR_VERSION 0 - -#define NFS4_DEBUG 1 - -/* Index of predefined Linux client operations */ - -enum { - NFSPROC4_CLNT_NULL = 0, /* Unused */ - NFSPROC4_CLNT_READ, - NFSPROC4_CLNT_WRITE, - NFSPROC4_CLNT_COMMIT, - NFSPROC4_CLNT_OPEN, - NFSPROC4_CLNT_OPEN_CONFIRM, - NFSPROC4_CLNT_OPEN_NOATTR, - NFSPROC4_CLNT_OPEN_DOWNGRADE, - NFSPROC4_CLNT_CLOSE, - NFSPROC4_CLNT_SETATTR, - NFSPROC4_CLNT_FSINFO, - NFSPROC4_CLNT_RENEW, - NFSPROC4_CLNT_SETCLIENTID, - NFSPROC4_CLNT_SETCLIENTID_CONFIRM, - NFSPROC4_CLNT_LOCK, - NFSPROC4_CLNT_LOCKT, - NFSPROC4_CLNT_LOCKU, - NFSPROC4_CLNT_ACCESS, - NFSPROC4_CLNT_GETATTR, - NFSPROC4_CLNT_LOOKUP, - NFSPROC4_CLNT_LOOKUP_ROOT, - NFSPROC4_CLNT_REMOVE, - NFSPROC4_CLNT_RENAME, - NFSPROC4_CLNT_LINK, - NFSPROC4_CLNT_SYMLINK, - NFSPROC4_CLNT_CREATE, - NFSPROC4_CLNT_PATHCONF, - NFSPROC4_CLNT_STATFS, - NFSPROC4_CLNT_READLINK, - NFSPROC4_CLNT_READDIR, - NFSPROC4_CLNT_SERVER_CAPS, - NFSPROC4_CLNT_DELEGRETURN, - NFSPROC4_CLNT_GETACL, - NFSPROC4_CLNT_SETACL, - NFSPROC4_CLNT_FS_LOCATIONS, - NFSPROC4_CLNT_RELEASE_LOCKOWNER, - NFSPROC4_CLNT_SECINFO, - NFSPROC4_CLNT_FSID_PRESENT, - - /* nfs41 */ - NFSPROC4_CLNT_EXCHANGE_ID, - NFSPROC4_CLNT_CREATE_SESSION, - NFSPROC4_CLNT_DESTROY_SESSION, - NFSPROC4_CLNT_SEQUENCE, - NFSPROC4_CLNT_GET_LEASE_TIME, - NFSPROC4_CLNT_RECLAIM_COMPLETE, - NFSPROC4_CLNT_LAYOUTGET, - NFSPROC4_CLNT_GETDEVICEINFO, - NFSPROC4_CLNT_LAYOUTCOMMIT, - NFSPROC4_CLNT_LAYOUTRETURN, - NFSPROC4_CLNT_SECINFO_NO_NAME, - NFSPROC4_CLNT_TEST_STATEID, - NFSPROC4_CLNT_FREE_STATEID, - NFSPROC4_CLNT_GETDEVICELIST, - NFSPROC4_CLNT_BIND_CONN_TO_SESSION, - NFSPROC4_CLNT_DESTROY_CLIENTID, - - /* nfs42 */ - NFSPROC4_CLNT_SEEK, - NFSPROC4_CLNT_ALLOCATE, - NFSPROC4_CLNT_DEALLOCATE, - NFSPROC4_CLNT_LAYOUTSTATS, - NFSPROC4_CLNT_CLONE, - NFSPROC4_CLNT_COPY, -}; - -/* nfs41 types */ -struct nfs4_sessionid { - unsigned char data[NFS4_MAX_SESSIONID_LEN]; -}; - -/* Create Session Flags */ -#define SESSION4_PERSIST 0x001 -#define SESSION4_BACK_CHAN 0x002 -#define SESSION4_RDMA 0x004 - -#define SESSION4_FLAG_MASK_A 0x007 - -enum state_protect_how4 { - SP4_NONE = 0, - SP4_MACH_CRED = 1, - SP4_SSV = 2 -}; - -enum pnfs_layouttype { - LAYOUT_NFSV4_1_FILES = 1, - LAYOUT_OSD2_OBJECTS = 2, - LAYOUT_BLOCK_VOLUME = 3, - LAYOUT_FLEX_FILES = 4, - LAYOUT_SCSI = 5, - LAYOUT_TYPE_MAX -}; - -/* used for both layout return and recall */ -enum pnfs_layoutreturn_type { - RETURN_FILE = 1, - RETURN_FSID = 2, - RETURN_ALL = 3 -}; - -enum pnfs_iomode { - IOMODE_READ = 1, - IOMODE_RW = 2, - IOMODE_ANY = 3, -}; - -enum pnfs_notify_deviceid_type4 { - NOTIFY_DEVICEID4_CHANGE = 1 << 1, - NOTIFY_DEVICEID4_DELETE = 1 << 2, -}; - -enum pnfs_block_volume_type { - PNFS_BLOCK_VOLUME_SIMPLE = 0, - PNFS_BLOCK_VOLUME_SLICE = 1, - PNFS_BLOCK_VOLUME_CONCAT = 2, - PNFS_BLOCK_VOLUME_STRIPE = 3, - PNFS_BLOCK_VOLUME_SCSI = 4, -}; - -enum pnfs_block_extent_state { - PNFS_BLOCK_READWRITE_DATA = 0, - PNFS_BLOCK_READ_DATA = 1, - PNFS_BLOCK_INVALID_DATA = 2, - PNFS_BLOCK_NONE_DATA = 3, -}; - -/* on the wire size of a block layout extent */ -#define PNFS_BLOCK_EXTENT_SIZE \ - (7 * sizeof(__be32) + NFS4_DEVICEID4_SIZE) - -/* on the wire size of a scsi commit range */ -#define PNFS_SCSI_RANGE_SIZE \ - (4 * sizeof(__be32)) - -enum scsi_code_set { - PS_CODE_SET_BINARY = 1, - PS_CODE_SET_ASCII = 2, - PS_CODE_SET_UTF8 = 3 -}; - -enum scsi_designator_type { - PS_DESIGNATOR_T10 = 1, - PS_DESIGNATOR_EUI64 = 2, - PS_DESIGNATOR_NAA = 3, - PS_DESIGNATOR_NAME = 8 -}; - -#define NFL4_UFLG_MASK 0x0000003F -#define NFL4_UFLG_DENSE 0x00000001 -#define NFL4_UFLG_COMMIT_THRU_MDS 0x00000002 -#define NFL4_UFLG_STRIPE_UNIT_SIZE_MASK 0xFFFFFFC0 - -/* Encoded in the loh_body field of type layouthint4 */ -enum filelayout_hint_care4 { - NFLH4_CARE_DENSE = NFL4_UFLG_DENSE, - NFLH4_CARE_COMMIT_THRU_MDS = NFL4_UFLG_COMMIT_THRU_MDS, - NFLH4_CARE_STRIPE_UNIT_SIZE = 0x00000040, - NFLH4_CARE_STRIPE_COUNT = 0x00000080 -}; - -#define NFS4_DEVICEID4_SIZE 16 - -struct nfs4_deviceid { - char data[NFS4_DEVICEID4_SIZE]; -}; - -enum data_content4 { - NFS4_CONTENT_DATA = 0, - NFS4_CONTENT_HOLE = 1, -}; - -enum pnfs_update_layout_reason { - PNFS_UPDATE_LAYOUT_UNKNOWN = 0, - PNFS_UPDATE_LAYOUT_NO_PNFS, - PNFS_UPDATE_LAYOUT_RD_ZEROLEN, - PNFS_UPDATE_LAYOUT_MDSTHRESH, - PNFS_UPDATE_LAYOUT_NOMEM, - PNFS_UPDATE_LAYOUT_BULK_RECALL, - PNFS_UPDATE_LAYOUT_IO_TEST_FAIL, - PNFS_UPDATE_LAYOUT_FOUND_CACHED, - PNFS_UPDATE_LAYOUT_RETURN, - PNFS_UPDATE_LAYOUT_RETRY, - PNFS_UPDATE_LAYOUT_BLOCKED, - PNFS_UPDATE_LAYOUT_INVALID_OPEN, - PNFS_UPDATE_LAYOUT_SEND_LAYOUTGET, -}; - -#define NFS4_OP_MAP_NUM_LONGS \ - DIV_ROUND_UP(LAST_NFS4_OP, 8 * sizeof(unsigned long)) -#define NFS4_OP_MAP_NUM_WORDS \ - (NFS4_OP_MAP_NUM_LONGS * sizeof(unsigned long) / sizeof(u32)) -struct nfs4_op_map { - union { - unsigned long longs[NFS4_OP_MAP_NUM_LONGS]; - u32 words[NFS4_OP_MAP_NUM_WORDS]; - } u; -}; - -#endif diff --git a/src/linux/include/linux/nfs_fs.h b/src/linux/include/linux/nfs_fs.h deleted file mode 100644 index 810124b..0000000 --- a/src/linux/include/linux/nfs_fs.h +++ /dev/null @@ -1,569 +0,0 @@ -/* - * linux/include/linux/nfs_fs.h - * - * Copyright (C) 1992 Rick Sladkey - * - * OS-specific nfs filesystem definitions and declarations - */ -#ifndef _LINUX_NFS_FS_H -#define _LINUX_NFS_FS_H - -#include - - -/* - * Enable dprintk() debugging support for nfs client. - */ -#ifdef CONFIG_NFS_DEBUG -# define NFS_DEBUG -#endif - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -/* - * These are the default flags for swap requests - */ -#define NFS_RPC_SWAPFLAGS (RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS) - -/* - * NFSv3/v4 Access mode cache entry - */ -struct nfs_access_entry { - struct rb_node rb_node; - struct list_head lru; - unsigned long jiffies; - struct rpc_cred * cred; - int mask; - struct rcu_head rcu_head; -}; - -struct nfs_lockowner { - fl_owner_t l_owner; - pid_t l_pid; -}; - -struct nfs_lock_context { - atomic_t count; - struct list_head list; - struct nfs_open_context *open_context; - struct nfs_lockowner lockowner; - atomic_t io_count; -}; - -struct nfs4_state; -struct nfs_open_context { - struct nfs_lock_context lock_context; - struct dentry *dentry; - struct rpc_cred *cred; - struct nfs4_state *state; - fmode_t mode; - - unsigned long flags; -#define NFS_CONTEXT_ERROR_WRITE (0) -#define NFS_CONTEXT_RESEND_WRITES (1) -#define NFS_CONTEXT_BAD (2) - int error; - - struct list_head list; - struct nfs4_threshold *mdsthreshold; -}; - -struct nfs_open_dir_context { - struct list_head list; - struct rpc_cred *cred; - unsigned long attr_gencount; - __u64 dir_cookie; - __u64 dup_cookie; - signed char duped; -}; - -/* - * NFSv4 delegation - */ -struct nfs_delegation; - -struct posix_acl; - -/* - * nfs fs inode data in memory - */ -struct nfs_inode { - /* - * The 64bit 'inode number' - */ - __u64 fileid; - - /* - * NFS file handle - */ - struct nfs_fh fh; - - /* - * Various flags - */ - unsigned long flags; /* atomic bit ops */ - unsigned long cache_validity; /* bit mask */ - - /* - * read_cache_jiffies is when we started read-caching this inode. - * attrtimeo is for how long the cached information is assumed - * to be valid. A successful attribute revalidation doubles - * attrtimeo (up to acregmax/acdirmax), a failure resets it to - * acregmin/acdirmin. - * - * We need to revalidate the cached attrs for this inode if - * - * jiffies - read_cache_jiffies >= attrtimeo - * - * Please note the comparison is greater than or equal - * so that zero timeout values can be specified. - */ - unsigned long read_cache_jiffies; - unsigned long attrtimeo; - unsigned long attrtimeo_timestamp; - - unsigned long attr_gencount; - /* "Generation counter" for the attribute cache. This is - * bumped whenever we update the metadata on the - * server. - */ - unsigned long cache_change_attribute; - - struct rb_root access_cache; - struct list_head access_cache_entry_lru; - struct list_head access_cache_inode_lru; - - /* - * This is the cookie verifier used for NFSv3 readdir - * operations - */ - __be32 cookieverf[2]; - - unsigned long nrequests; - struct nfs_mds_commit_info commit_info; - - /* Open contexts for shared mmap writes */ - struct list_head open_files; - - /* Readers: in-flight sillydelete RPC calls */ - /* Writers: rmdir */ - struct rw_semaphore rmdir_sem; - -#if IS_ENABLED(CONFIG_NFS_V4) - struct nfs4_cached_acl *nfs4_acl; - /* NFSv4 state */ - struct list_head open_states; - struct nfs_delegation __rcu *delegation; - struct rw_semaphore rwsem; - - /* pNFS layout information */ - struct pnfs_layout_hdr *layout; -#endif /* CONFIG_NFS_V4*/ - /* how many bytes have been written/read and how many bytes queued up */ - __u64 write_io; - __u64 read_io; -#ifdef CONFIG_NFS_FSCACHE - struct fscache_cookie *fscache; -#endif - struct inode vfs_inode; -}; - -/* - * Cache validity bit flags - */ -#define NFS_INO_INVALID_ATTR 0x0001 /* cached attrs are invalid */ -#define NFS_INO_INVALID_DATA 0x0002 /* cached data is invalid */ -#define NFS_INO_INVALID_ATIME 0x0004 /* cached atime is invalid */ -#define NFS_INO_INVALID_ACCESS 0x0008 /* cached access cred invalid */ -#define NFS_INO_INVALID_ACL 0x0010 /* cached acls are invalid */ -#define NFS_INO_REVAL_PAGECACHE 0x0020 /* must revalidate pagecache */ -#define NFS_INO_REVAL_FORCED 0x0040 /* force revalidation ignoring a delegation */ -#define NFS_INO_INVALID_LABEL 0x0080 /* cached label is invalid */ - -/* - * Bit offsets in flags field - */ -#define NFS_INO_ADVISE_RDPLUS (0) /* advise readdirplus */ -#define NFS_INO_STALE (1) /* possible stale inode */ -#define NFS_INO_ACL_LRU_SET (2) /* Inode is on the LRU list */ -#define NFS_INO_INVALIDATING (3) /* inode is being invalidated */ -#define NFS_INO_FSCACHE (5) /* inode can be cached by FS-Cache */ -#define NFS_INO_FSCACHE_LOCK (6) /* FS-Cache cookie management lock */ -#define NFS_INO_LAYOUTCOMMIT (9) /* layoutcommit required */ -#define NFS_INO_LAYOUTCOMMITTING (10) /* layoutcommit inflight */ -#define NFS_INO_LAYOUTSTATS (11) /* layoutstats inflight */ -#define NFS_INO_ODIRECT (12) /* I/O setting is O_DIRECT */ - -static inline struct nfs_inode *NFS_I(const struct inode *inode) -{ - return container_of(inode, struct nfs_inode, vfs_inode); -} - -static inline struct nfs_server *NFS_SB(const struct super_block *s) -{ - return (struct nfs_server *)(s->s_fs_info); -} - -static inline struct nfs_fh *NFS_FH(const struct inode *inode) -{ - return &NFS_I(inode)->fh; -} - -static inline struct nfs_server *NFS_SERVER(const struct inode *inode) -{ - return NFS_SB(inode->i_sb); -} - -static inline struct rpc_clnt *NFS_CLIENT(const struct inode *inode) -{ - return NFS_SERVER(inode)->client; -} - -static inline const struct nfs_rpc_ops *NFS_PROTO(const struct inode *inode) -{ - return NFS_SERVER(inode)->nfs_client->rpc_ops; -} - -static inline unsigned NFS_MINATTRTIMEO(const struct inode *inode) -{ - struct nfs_server *nfss = NFS_SERVER(inode); - return S_ISDIR(inode->i_mode) ? nfss->acdirmin : nfss->acregmin; -} - -static inline unsigned NFS_MAXATTRTIMEO(const struct inode *inode) -{ - struct nfs_server *nfss = NFS_SERVER(inode); - return S_ISDIR(inode->i_mode) ? nfss->acdirmax : nfss->acregmax; -} - -static inline int NFS_STALE(const struct inode *inode) -{ - return test_bit(NFS_INO_STALE, &NFS_I(inode)->flags); -} - -static inline struct fscache_cookie *nfs_i_fscache(struct inode *inode) -{ -#ifdef CONFIG_NFS_FSCACHE - return NFS_I(inode)->fscache; -#else - return NULL; -#endif -} - -static inline __u64 NFS_FILEID(const struct inode *inode) -{ - return NFS_I(inode)->fileid; -} - -static inline void set_nfs_fileid(struct inode *inode, __u64 fileid) -{ - NFS_I(inode)->fileid = fileid; -} - -static inline void nfs_mark_for_revalidate(struct inode *inode) -{ - struct nfs_inode *nfsi = NFS_I(inode); - - spin_lock(&inode->i_lock); - nfsi->cache_validity |= NFS_INO_INVALID_ATTR | - NFS_INO_REVAL_PAGECACHE | - NFS_INO_INVALID_ACCESS | - NFS_INO_INVALID_ACL; - if (S_ISDIR(inode->i_mode)) - nfsi->cache_validity |= NFS_INO_INVALID_DATA; - spin_unlock(&inode->i_lock); -} - -static inline int nfs_server_capable(struct inode *inode, int cap) -{ - return NFS_SERVER(inode)->caps & cap; -} - -static inline void nfs_set_verifier(struct dentry * dentry, unsigned long verf) -{ - dentry->d_time = verf; -} - -/** - * nfs_save_change_attribute - Returns the inode attribute change cookie - * @dir - pointer to parent directory inode - * The "change attribute" is updated every time we finish an operation - * that will result in a metadata change on the server. - */ -static inline unsigned long nfs_save_change_attribute(struct inode *dir) -{ - return NFS_I(dir)->cache_change_attribute; -} - -/** - * nfs_verify_change_attribute - Detects NFS remote directory changes - * @dir - pointer to parent directory inode - * @chattr - previously saved change attribute - * Return "false" if the verifiers doesn't match the change attribute. - * This would usually indicate that the directory contents have changed on - * the server, and that any dentries need revalidating. - */ -static inline int nfs_verify_change_attribute(struct inode *dir, unsigned long chattr) -{ - return chattr == NFS_I(dir)->cache_change_attribute; -} - -/* - * linux/fs/nfs/inode.c - */ -extern int nfs_sync_mapping(struct address_space *mapping); -extern void nfs_zap_mapping(struct inode *inode, struct address_space *mapping); -extern void nfs_zap_caches(struct inode *); -extern void nfs_invalidate_atime(struct inode *); -extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *, - struct nfs_fattr *, struct nfs4_label *); -extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *); -extern int nfs_post_op_update_inode(struct inode *inode, struct nfs_fattr *fattr); -extern int nfs_post_op_update_inode_force_wcc(struct inode *inode, struct nfs_fattr *fattr); -extern int nfs_post_op_update_inode_force_wcc_locked(struct inode *inode, struct nfs_fattr *fattr); -extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *); -extern void nfs_access_add_cache(struct inode *, struct nfs_access_entry *); -extern void nfs_access_set_mask(struct nfs_access_entry *, u32); -extern int nfs_permission(struct inode *, int); -extern int nfs_open(struct inode *, struct file *); -extern int nfs_attribute_timeout(struct inode *inode); -extern int nfs_attribute_cache_expired(struct inode *inode); -extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode); -extern int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *inode); -extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); -extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping); -extern int nfs_revalidate_mapping_rcu(struct inode *inode); -extern int nfs_setattr(struct dentry *, struct iattr *); -extern void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr, struct nfs_fattr *); -extern void nfs_setsecurity(struct inode *inode, struct nfs_fattr *fattr, - struct nfs4_label *label); -extern struct nfs_open_context *get_nfs_open_context(struct nfs_open_context *ctx); -extern void put_nfs_open_context(struct nfs_open_context *ctx); -extern struct nfs_open_context *nfs_find_open_context(struct inode *inode, struct rpc_cred *cred, fmode_t mode); -extern struct nfs_open_context *alloc_nfs_open_context(struct dentry *dentry, fmode_t f_mode); -extern void nfs_inode_attach_open_context(struct nfs_open_context *ctx); -extern void nfs_file_set_open_context(struct file *filp, struct nfs_open_context *ctx); -extern void nfs_file_clear_open_context(struct file *flip); -extern struct nfs_lock_context *nfs_get_lock_context(struct nfs_open_context *ctx); -extern void nfs_put_lock_context(struct nfs_lock_context *l_ctx); -extern u64 nfs_compat_user_ino64(u64 fileid); -extern void nfs_fattr_init(struct nfs_fattr *fattr); -extern void nfs_fattr_set_barrier(struct nfs_fattr *fattr); -extern unsigned long nfs_inc_attr_generation_counter(void); - -extern struct nfs_fattr *nfs_alloc_fattr(void); - -static inline void nfs_free_fattr(const struct nfs_fattr *fattr) -{ - kfree(fattr); -} - -extern struct nfs_fh *nfs_alloc_fhandle(void); - -static inline void nfs_free_fhandle(const struct nfs_fh *fh) -{ - kfree(fh); -} - -#ifdef NFS_DEBUG -extern u32 _nfs_display_fhandle_hash(const struct nfs_fh *fh); -static inline u32 nfs_display_fhandle_hash(const struct nfs_fh *fh) -{ - return _nfs_display_fhandle_hash(fh); -} -extern void _nfs_display_fhandle(const struct nfs_fh *fh, const char *caption); -#define nfs_display_fhandle(fh, caption) \ - do { \ - if (unlikely(nfs_debug & NFSDBG_FACILITY)) \ - _nfs_display_fhandle(fh, caption); \ - } while (0) -#else -static inline u32 nfs_display_fhandle_hash(const struct nfs_fh *fh) -{ - return 0; -} -static inline void nfs_display_fhandle(const struct nfs_fh *fh, - const char *caption) -{ -} -#endif - -/* - * linux/fs/nfs/nfsroot.c - */ -extern int nfs_root_data(char **root_device, char **root_data); /*__init*/ -/* linux/net/ipv4/ipconfig.c: trims ip addr off front of name, too. */ -extern __be32 root_nfs_parse_addr(char *name); /*__init*/ - -/* - * linux/fs/nfs/file.c - */ -extern const struct file_operations nfs_file_operations; -#if IS_ENABLED(CONFIG_NFS_V4) -extern const struct file_operations nfs4_file_operations; -#endif /* CONFIG_NFS_V4 */ -extern const struct address_space_operations nfs_file_aops; -extern const struct address_space_operations nfs_dir_aops; - -static inline struct nfs_open_context *nfs_file_open_context(struct file *filp) -{ - return filp->private_data; -} - -static inline struct rpc_cred *nfs_file_cred(struct file *file) -{ - if (file != NULL) { - struct nfs_open_context *ctx = - nfs_file_open_context(file); - if (ctx) - return ctx->cred; - } - return NULL; -} - -/* - * linux/fs/nfs/direct.c - */ -extern ssize_t nfs_direct_IO(struct kiocb *, struct iov_iter *); -extern ssize_t nfs_file_direct_read(struct kiocb *iocb, - struct iov_iter *iter); -extern ssize_t nfs_file_direct_write(struct kiocb *iocb, - struct iov_iter *iter); - -/* - * linux/fs/nfs/dir.c - */ -extern const struct file_operations nfs_dir_operations; -extern const struct dentry_operations nfs_dentry_operations; - -extern void nfs_force_lookup_revalidate(struct inode *dir); -extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, - struct nfs_fattr *fattr, struct nfs4_label *label); -extern int nfs_may_open(struct inode *inode, struct rpc_cred *cred, int openflags); -extern void nfs_access_zap_cache(struct inode *inode); - -/* - * linux/fs/nfs/symlink.c - */ -extern const struct inode_operations nfs_symlink_inode_operations; - -/* - * linux/fs/nfs/sysctl.c - */ -#ifdef CONFIG_SYSCTL -extern int nfs_register_sysctl(void); -extern void nfs_unregister_sysctl(void); -#else -#define nfs_register_sysctl() 0 -#define nfs_unregister_sysctl() do { } while(0) -#endif - -/* - * linux/fs/nfs/namespace.c - */ -extern const struct inode_operations nfs_mountpoint_inode_operations; -extern const struct inode_operations nfs_referral_inode_operations; -extern int nfs_mountpoint_expiry_timeout; -extern void nfs_release_automount_timer(void); - -/* - * linux/fs/nfs/unlink.c - */ -extern void nfs_complete_unlink(struct dentry *dentry, struct inode *); - -/* - * linux/fs/nfs/write.c - */ -extern int nfs_congestion_kb; -extern int nfs_writepage(struct page *page, struct writeback_control *wbc); -extern int nfs_writepages(struct address_space *, struct writeback_control *); -extern int nfs_flush_incompatible(struct file *file, struct page *page); -extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int); - -/* - * Try to write back everything synchronously (but check the - * return value!) - */ -extern int nfs_sync_inode(struct inode *inode); -extern int nfs_wb_all(struct inode *inode); -extern int nfs_wb_single_page(struct inode *inode, struct page *page, bool launder); -extern int nfs_wb_page_cancel(struct inode *inode, struct page* page); -extern int nfs_commit_inode(struct inode *, int); -extern struct nfs_commit_data *nfs_commitdata_alloc(void); -extern void nfs_commit_free(struct nfs_commit_data *data); - -static inline int -nfs_wb_launder_page(struct inode *inode, struct page *page) -{ - return nfs_wb_single_page(inode, page, true); -} - -static inline int -nfs_wb_page(struct inode *inode, struct page *page) -{ - return nfs_wb_single_page(inode, page, false); -} - -static inline int -nfs_have_writebacks(struct inode *inode) -{ - return NFS_I(inode)->nrequests != 0; -} - -/* - * linux/fs/nfs/read.c - */ -extern int nfs_readpage(struct file *, struct page *); -extern int nfs_readpages(struct file *, struct address_space *, - struct list_head *, unsigned); -extern int nfs_readpage_async(struct nfs_open_context *, struct inode *, - struct page *); - -/* - * inline functions - */ - -static inline loff_t nfs_size_to_loff_t(__u64 size) -{ - return min_t(u64, size, OFFSET_MAX); -} - -static inline ino_t -nfs_fileid_to_ino_t(u64 fileid) -{ - ino_t ino = (ino_t) fileid; - if (sizeof(ino_t) < sizeof(u64)) - ino ^= fileid >> (sizeof(u64)-sizeof(ino_t)) * 8; - return ino; -} - -#define NFS_JUKEBOX_RETRY_TIME (5 * HZ) - - -# undef ifdebug -# ifdef NFS_DEBUG -# define ifdebug(fac) if (unlikely(nfs_debug & NFSDBG_##fac)) -# define NFS_IFDEBUG(x) x -# else -# define ifdebug(fac) if (0) -# define NFS_IFDEBUG(x) -# endif -#endif diff --git a/src/linux/include/linux/nfs_fs_i.h b/src/linux/include/linux/nfs_fs_i.h deleted file mode 100644 index a5c50d9..0000000 --- a/src/linux/include/linux/nfs_fs_i.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _NFS_FS_I -#define _NFS_FS_I - -struct nlm_lockowner; - -/* - * NFS lock info - */ -struct nfs_lock_info { - u32 state; - struct nlm_lockowner *owner; - struct list_head list; -}; - -struct nfs4_lock_state; -struct nfs4_lock_info { - struct nfs4_lock_state *owner; -}; - -#endif diff --git a/src/linux/include/linux/nfs_fs_sb.h b/src/linux/include/linux/nfs_fs_sb.h deleted file mode 100644 index b34097c..0000000 --- a/src/linux/include/linux/nfs_fs_sb.h +++ /dev/null @@ -1,254 +0,0 @@ -#ifndef _NFS_FS_SB -#define _NFS_FS_SB - -#include -#include -#include -#include -#include -#include - -#include - -struct nfs4_session; -struct nfs_iostats; -struct nlm_host; -struct nfs4_sequence_args; -struct nfs4_sequence_res; -struct nfs_server; -struct nfs4_minor_version_ops; -struct nfs41_server_scope; -struct nfs41_impl_id; - -/* - * The nfs_client identifies our client state to the server. - */ -struct nfs_client { - atomic_t cl_count; - atomic_t cl_mds_count; - int cl_cons_state; /* current construction state (-ve: init error) */ -#define NFS_CS_READY 0 /* ready to be used */ -#define NFS_CS_INITING 1 /* busy initialising */ -#define NFS_CS_SESSION_INITING 2 /* busy initialising session */ - unsigned long cl_res_state; /* NFS resources state */ -#define NFS_CS_CALLBACK 1 /* - callback started */ -#define NFS_CS_IDMAP 2 /* - idmap started */ -#define NFS_CS_RENEWD 3 /* - renewd started */ -#define NFS_CS_STOP_RENEW 4 /* no more state to renew */ -#define NFS_CS_CHECK_LEASE_TIME 5 /* need to check lease time */ - unsigned long cl_flags; /* behavior switches */ -#define NFS_CS_NORESVPORT 0 /* - use ephemeral src port */ -#define NFS_CS_DISCRTRY 1 /* - disconnect on RPC retry */ -#define NFS_CS_MIGRATION 2 /* - transparent state migr */ -#define NFS_CS_INFINITE_SLOTS 3 /* - don't limit TCP slots */ -#define NFS_CS_NO_RETRANS_TIMEOUT 4 /* - Disable retransmit timeouts */ - struct sockaddr_storage cl_addr; /* server identifier */ - size_t cl_addrlen; - char * cl_hostname; /* hostname of server */ - char * cl_acceptor; /* GSSAPI acceptor name */ - struct list_head cl_share_link; /* link in global client list */ - struct list_head cl_superblocks; /* List of nfs_server structs */ - - struct rpc_clnt * cl_rpcclient; - const struct nfs_rpc_ops *rpc_ops; /* NFS protocol vector */ - int cl_proto; /* Network transport protocol */ - struct nfs_subversion * cl_nfs_mod; /* pointer to nfs version module */ - - u32 cl_minorversion;/* NFSv4 minorversion */ - struct rpc_cred *cl_machine_cred; - -#if IS_ENABLED(CONFIG_NFS_V4) - struct list_head cl_ds_clients; /* auth flavor data servers */ - u64 cl_clientid; /* constant */ - nfs4_verifier cl_confirm; /* Clientid verifier */ - unsigned long cl_state; - - spinlock_t cl_lock; - - unsigned long cl_lease_time; - unsigned long cl_last_renewal; - struct delayed_work cl_renewd; - - struct rpc_wait_queue cl_rpcwaitq; - - /* idmapper */ - struct idmap * cl_idmap; - - /* Client owner identifier */ - const char * cl_owner_id; - - u32 cl_cb_ident; /* v4.0 callback identifier */ - const struct nfs4_minor_version_ops *cl_mvops; - unsigned long cl_mig_gen; - - /* NFSv4.0 transport blocking */ - struct nfs4_slot_table *cl_slot_tbl; - - /* The sequence id to use for the next CREATE_SESSION */ - u32 cl_seqid; - /* The flags used for obtaining the clientid during EXCHANGE_ID */ - u32 cl_exchange_flags; - struct nfs4_session *cl_session; /* shared session */ - bool cl_preserve_clid; - struct nfs41_server_owner *cl_serverowner; - struct nfs41_server_scope *cl_serverscope; - struct nfs41_impl_id *cl_implid; - /* nfs 4.1+ state protection modes: */ - unsigned long cl_sp4_flags; -#define NFS_SP4_MACH_CRED_MINIMAL 1 /* Minimal sp4_mach_cred - state ops - * must use machine cred */ -#define NFS_SP4_MACH_CRED_CLEANUP 2 /* CLOSE and LOCKU */ -#define NFS_SP4_MACH_CRED_SECINFO 3 /* SECINFO and SECINFO_NO_NAME */ -#define NFS_SP4_MACH_CRED_STATEID 4 /* TEST_STATEID and FREE_STATEID */ -#define NFS_SP4_MACH_CRED_WRITE 5 /* WRITE */ -#define NFS_SP4_MACH_CRED_COMMIT 6 /* COMMIT */ -#define NFS_SP4_MACH_CRED_PNFS_CLEANUP 7 /* LAYOUTRETURN */ -#if IS_ENABLED(CONFIG_NFS_V4_1) - wait_queue_head_t cl_lock_waitq; -#endif /* CONFIG_NFS_V4_1 */ -#endif /* CONFIG_NFS_V4 */ - - /* Our own IP address, as a null-terminated string. - * This is used to generate the mv0 callback address. - */ - char cl_ipaddr[48]; - -#ifdef CONFIG_NFS_FSCACHE - struct fscache_cookie *fscache; /* client index cache cookie */ -#endif - - struct net *cl_net; -}; - -/* - * NFS client parameters stored in the superblock. - */ -struct nfs_server { - struct nfs_client * nfs_client; /* shared client and NFS4 state */ - struct list_head client_link; /* List of other nfs_server structs - * that share the same client - */ - struct list_head master_link; /* link in master servers list */ - struct rpc_clnt * client; /* RPC client handle */ - struct rpc_clnt * client_acl; /* ACL RPC client handle */ - struct nlm_host *nlm_host; /* NLM client handle */ - struct nfs_iostats __percpu *io_stats; /* I/O statistics */ - struct backing_dev_info backing_dev_info; - atomic_long_t writeback; /* number of writeback pages */ - int flags; /* various flags */ - unsigned int caps; /* server capabilities */ - unsigned int rsize; /* read size */ - unsigned int rpages; /* read size (in pages) */ - unsigned int wsize; /* write size */ - unsigned int wpages; /* write size (in pages) */ - unsigned int wtmult; /* server disk block size */ - unsigned int dtsize; /* readdir size */ - unsigned short port; /* "port=" setting */ - unsigned int bsize; /* server block size */ - unsigned int acregmin; /* attr cache timeouts */ - unsigned int acregmax; - unsigned int acdirmin; - unsigned int acdirmax; - unsigned int namelen; - unsigned int options; /* extra options enabled by mount */ - unsigned int clone_blksize; /* granularity of a CLONE operation */ -#define NFS_OPTION_FSCACHE 0x00000001 /* - local caching enabled */ -#define NFS_OPTION_MIGRATION 0x00000002 /* - NFSv4 migration enabled */ - - struct nfs_fsid fsid; - __u64 maxfilesize; /* maximum file size */ - struct timespec time_delta; /* smallest time granularity */ - unsigned long mount_time; /* when this fs was mounted */ - struct super_block *super; /* VFS super block */ - dev_t s_dev; /* superblock dev numbers */ - struct nfs_auth_info auth_info; /* parsed auth flavors */ - -#ifdef CONFIG_NFS_FSCACHE - struct nfs_fscache_key *fscache_key; /* unique key for superblock */ - struct fscache_cookie *fscache; /* superblock cookie */ -#endif - - u32 pnfs_blksize; /* layout_blksize attr */ -#if IS_ENABLED(CONFIG_NFS_V4) - u32 attr_bitmask[3];/* V4 bitmask representing the set - of attributes supported on this - filesystem */ - u32 attr_bitmask_nl[3]; - /* V4 bitmask representing the - set of attributes supported - on this filesystem excluding - the label support bit. */ - u32 exclcreat_bitmask[3]; - /* V4 bitmask representing the - set of attributes supported - on this filesystem for the - exclusive create. */ - u32 cache_consistency_bitmask[3]; - /* V4 bitmask representing the subset - of change attribute, size, ctime - and mtime attributes supported by - the server */ - u32 acl_bitmask; /* V4 bitmask representing the ACEs - that are supported on this - filesystem */ - u32 fh_expire_type; /* V4 bitmask representing file - handle volatility type for - this filesystem */ - struct pnfs_layoutdriver_type *pnfs_curr_ld; /* Active layout driver */ - struct rpc_wait_queue roc_rpcwaitq; - void *pnfs_ld_data; /* per mount point data */ - - /* the following fields are protected by nfs_client->cl_lock */ - struct rb_root state_owners; -#endif - struct ida openowner_id; - struct ida lockowner_id; - struct list_head state_owners_lru; - struct list_head layouts; - struct list_head delegations; - - unsigned long mig_gen; - unsigned long mig_status; -#define NFS_MIG_IN_TRANSITION (1) -#define NFS_MIG_FAILED (2) - - void (*destroy)(struct nfs_server *); - - atomic_t active; /* Keep trace of any activity to this server */ - - /* mountd-related mount options */ - struct sockaddr_storage mountd_address; - size_t mountd_addrlen; - u32 mountd_version; - unsigned short mountd_port; - unsigned short mountd_protocol; -}; - -/* Server capabilities */ -#define NFS_CAP_READDIRPLUS (1U << 0) -#define NFS_CAP_HARDLINKS (1U << 1) -#define NFS_CAP_SYMLINKS (1U << 2) -#define NFS_CAP_ACLS (1U << 3) -#define NFS_CAP_ATOMIC_OPEN (1U << 4) -/* #define NFS_CAP_CHANGE_ATTR (1U << 5) */ -#define NFS_CAP_FILEID (1U << 6) -#define NFS_CAP_MODE (1U << 7) -#define NFS_CAP_NLINK (1U << 8) -#define NFS_CAP_OWNER (1U << 9) -#define NFS_CAP_OWNER_GROUP (1U << 10) -#define NFS_CAP_ATIME (1U << 11) -#define NFS_CAP_CTIME (1U << 12) -#define NFS_CAP_MTIME (1U << 13) -#define NFS_CAP_POSIX_LOCK (1U << 14) -#define NFS_CAP_UIDGID_NOMAP (1U << 15) -#define NFS_CAP_STATEID_NFSV41 (1U << 16) -#define NFS_CAP_ATOMIC_OPEN_V1 (1U << 17) -#define NFS_CAP_SECURITY_LABEL (1U << 18) -#define NFS_CAP_SEEK (1U << 19) -#define NFS_CAP_ALLOCATE (1U << 20) -#define NFS_CAP_DEALLOCATE (1U << 21) -#define NFS_CAP_LAYOUTSTATS (1U << 22) -#define NFS_CAP_CLONE (1U << 23) -#define NFS_CAP_COPY (1U << 24) - -#endif diff --git a/src/linux/include/linux/nfs_xdr.h b/src/linux/include/linux/nfs_xdr.h deleted file mode 100644 index beb1e10..0000000 --- a/src/linux/include/linux/nfs_xdr.h +++ /dev/null @@ -1,1622 +0,0 @@ -#ifndef _LINUX_NFS_XDR_H -#define _LINUX_NFS_XDR_H - -#include -#include - -/* - * To change the maximum rsize and wsize supported by the NFS client, adjust - * NFS_MAX_FILE_IO_SIZE. 64KB is a typical maximum, but some servers can - * support a megabyte or more. The default is left at 4096 bytes, which is - * reasonable for NFS over UDP. - */ -#define NFS_MAX_FILE_IO_SIZE (1048576U) -#define NFS_DEF_FILE_IO_SIZE (4096U) -#define NFS_MIN_FILE_IO_SIZE (1024U) - -struct nfs4_string { - unsigned int len; - char *data; -}; - -struct nfs_fsid { - uint64_t major; - uint64_t minor; -}; - -/* - * Helper for checking equality between 2 fsids. - */ -static inline int nfs_fsid_equal(const struct nfs_fsid *a, const struct nfs_fsid *b) -{ - return a->major == b->major && a->minor == b->minor; -} - -struct nfs4_threshold { - __u32 bm; - __u32 l_type; - __u64 rd_sz; - __u64 wr_sz; - __u64 rd_io_sz; - __u64 wr_io_sz; -}; - -struct nfs_fattr { - unsigned int valid; /* which fields are valid */ - umode_t mode; - __u32 nlink; - kuid_t uid; - kgid_t gid; - dev_t rdev; - __u64 size; - union { - struct { - __u32 blocksize; - __u32 blocks; - } nfs2; - struct { - __u64 used; - } nfs3; - } du; - struct nfs_fsid fsid; - __u64 fileid; - __u64 mounted_on_fileid; - struct timespec atime; - struct timespec mtime; - struct timespec ctime; - __u64 change_attr; /* NFSv4 change attribute */ - __u64 pre_change_attr;/* pre-op NFSv4 change attribute */ - __u64 pre_size; /* pre_op_attr.size */ - struct timespec pre_mtime; /* pre_op_attr.mtime */ - struct timespec pre_ctime; /* pre_op_attr.ctime */ - unsigned long time_start; - unsigned long gencount; - struct nfs4_string *owner_name; - struct nfs4_string *group_name; - struct nfs4_threshold *mdsthreshold; /* pNFS threshold hints */ -}; - -#define NFS_ATTR_FATTR_TYPE (1U << 0) -#define NFS_ATTR_FATTR_MODE (1U << 1) -#define NFS_ATTR_FATTR_NLINK (1U << 2) -#define NFS_ATTR_FATTR_OWNER (1U << 3) -#define NFS_ATTR_FATTR_GROUP (1U << 4) -#define NFS_ATTR_FATTR_RDEV (1U << 5) -#define NFS_ATTR_FATTR_SIZE (1U << 6) -#define NFS_ATTR_FATTR_PRESIZE (1U << 7) -#define NFS_ATTR_FATTR_BLOCKS_USED (1U << 8) -#define NFS_ATTR_FATTR_SPACE_USED (1U << 9) -#define NFS_ATTR_FATTR_FSID (1U << 10) -#define NFS_ATTR_FATTR_FILEID (1U << 11) -#define NFS_ATTR_FATTR_ATIME (1U << 12) -#define NFS_ATTR_FATTR_MTIME (1U << 13) -#define NFS_ATTR_FATTR_CTIME (1U << 14) -#define NFS_ATTR_FATTR_PREMTIME (1U << 15) -#define NFS_ATTR_FATTR_PRECTIME (1U << 16) -#define NFS_ATTR_FATTR_CHANGE (1U << 17) -#define NFS_ATTR_FATTR_PRECHANGE (1U << 18) -#define NFS_ATTR_FATTR_V4_LOCATIONS (1U << 19) -#define NFS_ATTR_FATTR_V4_REFERRAL (1U << 20) -#define NFS_ATTR_FATTR_MOUNTPOINT (1U << 21) -#define NFS_ATTR_FATTR_MOUNTED_ON_FILEID (1U << 22) -#define NFS_ATTR_FATTR_OWNER_NAME (1U << 23) -#define NFS_ATTR_FATTR_GROUP_NAME (1U << 24) -#define NFS_ATTR_FATTR_V4_SECURITY_LABEL (1U << 25) - -#define NFS_ATTR_FATTR (NFS_ATTR_FATTR_TYPE \ - | NFS_ATTR_FATTR_MODE \ - | NFS_ATTR_FATTR_NLINK \ - | NFS_ATTR_FATTR_OWNER \ - | NFS_ATTR_FATTR_GROUP \ - | NFS_ATTR_FATTR_RDEV \ - | NFS_ATTR_FATTR_SIZE \ - | NFS_ATTR_FATTR_FSID \ - | NFS_ATTR_FATTR_FILEID \ - | NFS_ATTR_FATTR_ATIME \ - | NFS_ATTR_FATTR_MTIME \ - | NFS_ATTR_FATTR_CTIME \ - | NFS_ATTR_FATTR_CHANGE) -#define NFS_ATTR_FATTR_V2 (NFS_ATTR_FATTR \ - | NFS_ATTR_FATTR_BLOCKS_USED) -#define NFS_ATTR_FATTR_V3 (NFS_ATTR_FATTR \ - | NFS_ATTR_FATTR_SPACE_USED) -#define NFS_ATTR_FATTR_V4 (NFS_ATTR_FATTR \ - | NFS_ATTR_FATTR_SPACE_USED \ - | NFS_ATTR_FATTR_V4_SECURITY_LABEL) - -/* - * Maximal number of supported layout drivers. - */ -#define NFS_MAX_LAYOUT_TYPES 8 - -/* - * Info on the file system - */ -struct nfs_fsinfo { - struct nfs_fattr *fattr; /* Post-op attributes */ - __u32 rtmax; /* max. read transfer size */ - __u32 rtpref; /* pref. read transfer size */ - __u32 rtmult; /* reads should be multiple of this */ - __u32 wtmax; /* max. write transfer size */ - __u32 wtpref; /* pref. write transfer size */ - __u32 wtmult; /* writes should be multiple of this */ - __u32 dtpref; /* pref. readdir transfer size */ - __u64 maxfilesize; - struct timespec time_delta; /* server time granularity */ - __u32 lease_time; /* in seconds */ - __u32 nlayouttypes; /* number of layouttypes */ - __u32 layouttype[NFS_MAX_LAYOUT_TYPES]; /* supported pnfs layout driver */ - __u32 blksize; /* preferred pnfs io block size */ - __u32 clone_blksize; /* granularity of a CLONE operation */ -}; - -struct nfs_fsstat { - struct nfs_fattr *fattr; /* Post-op attributes */ - __u64 tbytes; /* total size in bytes */ - __u64 fbytes; /* # of free bytes */ - __u64 abytes; /* # of bytes available to user */ - __u64 tfiles; /* # of files */ - __u64 ffiles; /* # of free files */ - __u64 afiles; /* # of files available to user */ -}; - -struct nfs2_fsstat { - __u32 tsize; /* Server transfer size */ - __u32 bsize; /* Filesystem block size */ - __u32 blocks; /* No. of "bsize" blocks on filesystem */ - __u32 bfree; /* No. of free "bsize" blocks */ - __u32 bavail; /* No. of available "bsize" blocks */ -}; - -struct nfs_pathconf { - struct nfs_fattr *fattr; /* Post-op attributes */ - __u32 max_link; /* max # of hard links */ - __u32 max_namelen; /* max name length */ -}; - -struct nfs4_change_info { - u32 atomic; - u64 before; - u64 after; -}; - -struct nfs_seqid; - -/* nfs41 sessions channel attributes */ -struct nfs4_channel_attrs { - u32 max_rqst_sz; - u32 max_resp_sz; - u32 max_resp_sz_cached; - u32 max_ops; - u32 max_reqs; -}; - -struct nfs4_slot; -struct nfs4_sequence_args { - struct nfs4_slot *sa_slot; - u8 sa_cache_this : 1, - sa_privileged : 1; -}; - -struct nfs4_sequence_res { - struct nfs4_slot *sr_slot; /* slot used to send request */ - unsigned long sr_timestamp; - int sr_status; /* sequence operation status */ - u32 sr_status_flags; - u32 sr_highest_slotid; - u32 sr_target_highest_slotid; -}; - -struct nfs4_get_lease_time_args { - struct nfs4_sequence_args la_seq_args; -}; - -struct nfs4_get_lease_time_res { - struct nfs4_sequence_res lr_seq_res; - struct nfs_fsinfo *lr_fsinfo; -}; - -#define PNFS_LAYOUT_MAXSIZE 4096 - -struct nfs4_layoutdriver_data { - struct page **pages; - __u32 pglen; - __u32 len; -}; - -struct pnfs_layout_range { - u32 iomode; - u64 offset; - u64 length; -}; - -struct nfs4_layoutget_args { - struct nfs4_sequence_args seq_args; - __u32 type; - struct pnfs_layout_range range; - __u64 minlength; - __u32 maxcount; - struct inode *inode; - struct nfs_open_context *ctx; - nfs4_stateid stateid; - struct nfs4_layoutdriver_data layout; -}; - -struct nfs4_layoutget_res { - struct nfs4_sequence_res seq_res; - __u32 return_on_close; - struct pnfs_layout_range range; - __u32 type; - nfs4_stateid stateid; - struct nfs4_layoutdriver_data *layoutp; -}; - -struct nfs4_layoutget { - struct nfs4_layoutget_args args; - struct nfs4_layoutget_res res; - struct rpc_cred *cred; - gfp_t gfp_flags; -}; - -struct nfs4_getdeviceinfo_args { - struct nfs4_sequence_args seq_args; - struct pnfs_device *pdev; - __u32 notify_types; -}; - -struct nfs4_getdeviceinfo_res { - struct nfs4_sequence_res seq_res; - struct pnfs_device *pdev; - __u32 notification; -}; - -struct nfs4_layoutcommit_args { - struct nfs4_sequence_args seq_args; - nfs4_stateid stateid; - __u64 lastbytewritten; - struct inode *inode; - const u32 *bitmask; - size_t layoutupdate_len; - struct page *layoutupdate_page; - struct page **layoutupdate_pages; - __be32 *start_p; -}; - -struct nfs4_layoutcommit_res { - struct nfs4_sequence_res seq_res; - struct nfs_fattr *fattr; - const struct nfs_server *server; - int status; -}; - -struct nfs4_layoutcommit_data { - struct rpc_task task; - struct nfs_fattr fattr; - struct list_head lseg_list; - struct rpc_cred *cred; - struct inode *inode; - struct nfs4_layoutcommit_args args; - struct nfs4_layoutcommit_res res; -}; - -struct nfs4_layoutreturn_args { - struct nfs4_sequence_args seq_args; - struct pnfs_layout_hdr *layout; - struct inode *inode; - struct pnfs_layout_range range; - nfs4_stateid stateid; - __u32 layout_type; -}; - -struct nfs4_layoutreturn_res { - struct nfs4_sequence_res seq_res; - u32 lrs_present; - nfs4_stateid stateid; -}; - -struct nfs4_layoutreturn { - struct nfs4_layoutreturn_args args; - struct nfs4_layoutreturn_res res; - struct rpc_cred *cred; - struct nfs_client *clp; - struct inode *inode; - int rpc_status; -}; - -#define PNFS_LAYOUTSTATS_MAXSIZE 256 - -struct nfs42_layoutstat_args; -struct nfs42_layoutstat_devinfo; -typedef void (*layoutstats_encode_t)(struct xdr_stream *, - struct nfs42_layoutstat_args *, - struct nfs42_layoutstat_devinfo *); - -/* Per file per deviceid layoutstats */ -struct nfs42_layoutstat_devinfo { - struct nfs4_deviceid dev_id; - __u64 offset; - __u64 length; - __u64 read_count; - __u64 read_bytes; - __u64 write_count; - __u64 write_bytes; - __u32 layout_type; - layoutstats_encode_t layoutstats_encode; - void *layout_private; -}; - -struct nfs42_layoutstat_args { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fh; - struct inode *inode; - nfs4_stateid stateid; - int num_dev; - struct nfs42_layoutstat_devinfo *devinfo; -}; - -struct nfs42_layoutstat_res { - struct nfs4_sequence_res seq_res; - int num_dev; - int rpc_status; -}; - -struct nfs42_layoutstat_data { - struct inode *inode; - struct nfs42_layoutstat_args args; - struct nfs42_layoutstat_res res; -}; - -struct nfs42_clone_args { - struct nfs4_sequence_args seq_args; - struct nfs_fh *src_fh; - struct nfs_fh *dst_fh; - nfs4_stateid src_stateid; - nfs4_stateid dst_stateid; - __u64 src_offset; - __u64 dst_offset; - __u64 count; - const u32 *dst_bitmask; -}; - -struct nfs42_clone_res { - struct nfs4_sequence_res seq_res; - unsigned int rpc_status; - struct nfs_fattr *dst_fattr; - const struct nfs_server *server; -}; - -struct stateowner_id { - __u64 create_time; - __u32 uniquifier; -}; - -/* - * Arguments to the open call. - */ -struct nfs_openargs { - struct nfs4_sequence_args seq_args; - const struct nfs_fh * fh; - struct nfs_seqid * seqid; - int open_flags; - fmode_t fmode; - u32 share_access; - u32 access; - __u64 clientid; - struct stateowner_id id; - union { - struct { - struct iattr * attrs; /* UNCHECKED, GUARDED, EXCLUSIVE4_1 */ - nfs4_verifier verifier; /* EXCLUSIVE */ - }; - nfs4_stateid delegation; /* CLAIM_DELEGATE_CUR */ - fmode_t delegation_type; /* CLAIM_PREVIOUS */ - } u; - const struct qstr * name; - const struct nfs_server *server; /* Needed for ID mapping */ - const u32 * bitmask; - const u32 * open_bitmap; - enum open_claim_type4 claim; - enum createmode4 createmode; - const struct nfs4_label *label; -}; - -struct nfs_openres { - struct nfs4_sequence_res seq_res; - nfs4_stateid stateid; - struct nfs_fh fh; - struct nfs4_change_info cinfo; - __u32 rflags; - struct nfs_fattr * f_attr; - struct nfs4_label *f_label; - struct nfs_seqid * seqid; - const struct nfs_server *server; - fmode_t delegation_type; - nfs4_stateid delegation; - unsigned long pagemod_limit; - __u32 do_recall; - __u32 attrset[NFS4_BITMAP_SIZE]; - struct nfs4_string *owner; - struct nfs4_string *group_owner; - __u32 access_request; - __u32 access_supported; - __u32 access_result; -}; - -/* - * Arguments to the open_confirm call. - */ -struct nfs_open_confirmargs { - struct nfs4_sequence_args seq_args; - const struct nfs_fh * fh; - nfs4_stateid * stateid; - struct nfs_seqid * seqid; -}; - -struct nfs_open_confirmres { - struct nfs4_sequence_res seq_res; - nfs4_stateid stateid; - struct nfs_seqid * seqid; -}; - -/* - * Arguments to the close call. - */ -struct nfs_closeargs { - struct nfs4_sequence_args seq_args; - struct nfs_fh * fh; - nfs4_stateid stateid; - struct nfs_seqid * seqid; - fmode_t fmode; - u32 share_access; - const u32 * bitmask; -}; - -struct nfs_closeres { - struct nfs4_sequence_res seq_res; - nfs4_stateid stateid; - struct nfs_fattr * fattr; - struct nfs_seqid * seqid; - const struct nfs_server *server; -}; -/* - * * Arguments to the lock,lockt, and locku call. - * */ -struct nfs_lowner { - __u64 clientid; - __u64 id; - dev_t s_dev; -}; - -struct nfs_lock_args { - struct nfs4_sequence_args seq_args; - struct nfs_fh * fh; - struct file_lock * fl; - struct nfs_seqid * lock_seqid; - nfs4_stateid lock_stateid; - struct nfs_seqid * open_seqid; - nfs4_stateid open_stateid; - struct nfs_lowner lock_owner; - unsigned char block : 1; - unsigned char reclaim : 1; - unsigned char new_lock : 1; - unsigned char new_lock_owner : 1; -}; - -struct nfs_lock_res { - struct nfs4_sequence_res seq_res; - nfs4_stateid stateid; - struct nfs_seqid * lock_seqid; - struct nfs_seqid * open_seqid; -}; - -struct nfs_locku_args { - struct nfs4_sequence_args seq_args; - struct nfs_fh * fh; - struct file_lock * fl; - struct nfs_seqid * seqid; - nfs4_stateid stateid; -}; - -struct nfs_locku_res { - struct nfs4_sequence_res seq_res; - nfs4_stateid stateid; - struct nfs_seqid * seqid; -}; - -struct nfs_lockt_args { - struct nfs4_sequence_args seq_args; - struct nfs_fh * fh; - struct file_lock * fl; - struct nfs_lowner lock_owner; -}; - -struct nfs_lockt_res { - struct nfs4_sequence_res seq_res; - struct file_lock * denied; /* LOCK, LOCKT failed */ -}; - -struct nfs_release_lockowner_args { - struct nfs4_sequence_args seq_args; - struct nfs_lowner lock_owner; -}; - -struct nfs_release_lockowner_res { - struct nfs4_sequence_res seq_res; -}; - -struct nfs4_delegreturnargs { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *fhandle; - const nfs4_stateid *stateid; - const u32 * bitmask; -}; - -struct nfs4_delegreturnres { - struct nfs4_sequence_res seq_res; - struct nfs_fattr * fattr; - struct nfs_server *server; -}; - -/* - * Arguments to the write call. - */ -struct nfs_write_verifier { - char data[8]; -}; - -struct nfs_writeverf { - struct nfs_write_verifier verifier; - enum nfs3_stable_how committed; -}; - -/* - * Arguments shared by the read and write call. - */ -struct nfs_pgio_args { - struct nfs4_sequence_args seq_args; - struct nfs_fh * fh; - struct nfs_open_context *context; - struct nfs_lock_context *lock_context; - nfs4_stateid stateid; - __u64 offset; - __u32 count; - unsigned int pgbase; - struct page ** pages; - const u32 * bitmask; /* used by write */ - enum nfs3_stable_how stable; /* used by write */ -}; - -struct nfs_pgio_res { - struct nfs4_sequence_res seq_res; - struct nfs_fattr * fattr; - __u32 count; - __u32 op_status; - int eof; /* used by read */ - struct nfs_writeverf * verf; /* used by write */ - const struct nfs_server *server; /* used by write */ - -}; - -/* - * Arguments to the commit call. - */ -struct nfs_commitargs { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fh; - __u64 offset; - __u32 count; - const u32 *bitmask; -}; - -struct nfs_commitres { - struct nfs4_sequence_res seq_res; - __u32 op_status; - struct nfs_fattr *fattr; - struct nfs_writeverf *verf; - const struct nfs_server *server; -}; - -/* - * Common arguments to the unlink call - */ -struct nfs_removeargs { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *fh; - struct qstr name; -}; - -struct nfs_removeres { - struct nfs4_sequence_res seq_res; - struct nfs_server *server; - struct nfs_fattr *dir_attr; - struct nfs4_change_info cinfo; -}; - -/* - * Common arguments to the rename call - */ -struct nfs_renameargs { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *old_dir; - const struct nfs_fh *new_dir; - const struct qstr *old_name; - const struct qstr *new_name; -}; - -struct nfs_renameres { - struct nfs4_sequence_res seq_res; - struct nfs_server *server; - struct nfs4_change_info old_cinfo; - struct nfs_fattr *old_fattr; - struct nfs4_change_info new_cinfo; - struct nfs_fattr *new_fattr; -}; - -/* parsed sec= options */ -#define NFS_AUTH_INFO_MAX_FLAVORS 12 /* see fs/nfs/super.c */ -struct nfs_auth_info { - unsigned int flavor_len; - rpc_authflavor_t flavors[NFS_AUTH_INFO_MAX_FLAVORS]; -}; - -/* - * Argument struct for decode_entry function - */ -struct nfs_entry { - __u64 ino; - __u64 cookie, - prev_cookie; - const char * name; - unsigned int len; - int eof; - struct nfs_fh * fh; - struct nfs_fattr * fattr; - struct nfs4_label *label; - unsigned char d_type; - struct nfs_server * server; -}; - -/* - * The following types are for NFSv2 only. - */ -struct nfs_sattrargs { - struct nfs_fh * fh; - struct iattr * sattr; -}; - -struct nfs_diropargs { - struct nfs_fh * fh; - const char * name; - unsigned int len; -}; - -struct nfs_createargs { - struct nfs_fh * fh; - const char * name; - unsigned int len; - struct iattr * sattr; -}; - -struct nfs_setattrargs { - struct nfs4_sequence_args seq_args; - struct nfs_fh * fh; - nfs4_stateid stateid; - struct iattr * iap; - const struct nfs_server * server; /* Needed for name mapping */ - const u32 * bitmask; - const struct nfs4_label *label; -}; - -struct nfs_setaclargs { - struct nfs4_sequence_args seq_args; - struct nfs_fh * fh; - size_t acl_len; - struct page ** acl_pages; -}; - -struct nfs_setaclres { - struct nfs4_sequence_res seq_res; -}; - -struct nfs_getaclargs { - struct nfs4_sequence_args seq_args; - struct nfs_fh * fh; - size_t acl_len; - struct page ** acl_pages; -}; - -/* getxattr ACL interface flags */ -#define NFS4_ACL_TRUNC 0x0001 /* ACL was truncated */ -struct nfs_getaclres { - struct nfs4_sequence_res seq_res; - size_t acl_len; - size_t acl_data_offset; - int acl_flags; - struct page * acl_scratch; -}; - -struct nfs_setattrres { - struct nfs4_sequence_res seq_res; - struct nfs_fattr * fattr; - struct nfs4_label *label; - const struct nfs_server * server; -}; - -struct nfs_linkargs { - struct nfs_fh * fromfh; - struct nfs_fh * tofh; - const char * toname; - unsigned int tolen; -}; - -struct nfs_symlinkargs { - struct nfs_fh * fromfh; - const char * fromname; - unsigned int fromlen; - struct page ** pages; - unsigned int pathlen; - struct iattr * sattr; -}; - -struct nfs_readdirargs { - struct nfs_fh * fh; - __u32 cookie; - unsigned int count; - struct page ** pages; -}; - -struct nfs3_getaclargs { - struct nfs_fh * fh; - int mask; - struct page ** pages; -}; - -struct nfs3_setaclargs { - struct inode * inode; - int mask; - struct posix_acl * acl_access; - struct posix_acl * acl_default; - size_t len; - unsigned int npages; - struct page ** pages; -}; - -struct nfs_diropok { - struct nfs_fh * fh; - struct nfs_fattr * fattr; -}; - -struct nfs_readlinkargs { - struct nfs_fh * fh; - unsigned int pgbase; - unsigned int pglen; - struct page ** pages; -}; - -struct nfs3_sattrargs { - struct nfs_fh * fh; - struct iattr * sattr; - unsigned int guard; - struct timespec guardtime; -}; - -struct nfs3_diropargs { - struct nfs_fh * fh; - const char * name; - unsigned int len; -}; - -struct nfs3_accessargs { - struct nfs_fh * fh; - __u32 access; -}; - -struct nfs3_createargs { - struct nfs_fh * fh; - const char * name; - unsigned int len; - struct iattr * sattr; - enum nfs3_createmode createmode; - __be32 verifier[2]; -}; - -struct nfs3_mkdirargs { - struct nfs_fh * fh; - const char * name; - unsigned int len; - struct iattr * sattr; -}; - -struct nfs3_symlinkargs { - struct nfs_fh * fromfh; - const char * fromname; - unsigned int fromlen; - struct page ** pages; - unsigned int pathlen; - struct iattr * sattr; -}; - -struct nfs3_mknodargs { - struct nfs_fh * fh; - const char * name; - unsigned int len; - enum nfs3_ftype type; - struct iattr * sattr; - dev_t rdev; -}; - -struct nfs3_linkargs { - struct nfs_fh * fromfh; - struct nfs_fh * tofh; - const char * toname; - unsigned int tolen; -}; - -struct nfs3_readdirargs { - struct nfs_fh * fh; - __u64 cookie; - __be32 verf[2]; - int plus; - unsigned int count; - struct page ** pages; -}; - -struct nfs3_diropres { - struct nfs_fattr * dir_attr; - struct nfs_fh * fh; - struct nfs_fattr * fattr; -}; - -struct nfs3_accessres { - struct nfs_fattr * fattr; - __u32 access; -}; - -struct nfs3_readlinkargs { - struct nfs_fh * fh; - unsigned int pgbase; - unsigned int pglen; - struct page ** pages; -}; - -struct nfs3_linkres { - struct nfs_fattr * dir_attr; - struct nfs_fattr * fattr; -}; - -struct nfs3_readdirres { - struct nfs_fattr * dir_attr; - __be32 * verf; - int plus; -}; - -struct nfs3_getaclres { - struct nfs_fattr * fattr; - int mask; - unsigned int acl_access_count; - unsigned int acl_default_count; - struct posix_acl * acl_access; - struct posix_acl * acl_default; -}; - -#if IS_ENABLED(CONFIG_NFS_V4) - -typedef u64 clientid4; - -struct nfs4_accessargs { - struct nfs4_sequence_args seq_args; - const struct nfs_fh * fh; - const u32 * bitmask; - u32 access; -}; - -struct nfs4_accessres { - struct nfs4_sequence_res seq_res; - const struct nfs_server * server; - struct nfs_fattr * fattr; - u32 supported; - u32 access; -}; - -struct nfs4_create_arg { - struct nfs4_sequence_args seq_args; - u32 ftype; - union { - struct { - struct page ** pages; - unsigned int len; - } symlink; /* NF4LNK */ - struct { - u32 specdata1; - u32 specdata2; - } device; /* NF4BLK, NF4CHR */ - } u; - const struct qstr * name; - const struct nfs_server * server; - const struct iattr * attrs; - const struct nfs_fh * dir_fh; - const u32 * bitmask; - const struct nfs4_label *label; -}; - -struct nfs4_create_res { - struct nfs4_sequence_res seq_res; - const struct nfs_server * server; - struct nfs_fh * fh; - struct nfs_fattr * fattr; - struct nfs4_label *label; - struct nfs4_change_info dir_cinfo; -}; - -struct nfs4_fsinfo_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh * fh; - const u32 * bitmask; -}; - -struct nfs4_fsinfo_res { - struct nfs4_sequence_res seq_res; - struct nfs_fsinfo *fsinfo; -}; - -struct nfs4_getattr_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh * fh; - const u32 * bitmask; -}; - -struct nfs4_getattr_res { - struct nfs4_sequence_res seq_res; - const struct nfs_server * server; - struct nfs_fattr * fattr; - struct nfs4_label *label; -}; - -struct nfs4_link_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh * fh; - const struct nfs_fh * dir_fh; - const struct qstr * name; - const u32 * bitmask; -}; - -struct nfs4_link_res { - struct nfs4_sequence_res seq_res; - const struct nfs_server * server; - struct nfs_fattr * fattr; - struct nfs4_label *label; - struct nfs4_change_info cinfo; - struct nfs_fattr * dir_attr; -}; - - -struct nfs4_lookup_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh * dir_fh; - const struct qstr * name; - const u32 * bitmask; -}; - -struct nfs4_lookup_res { - struct nfs4_sequence_res seq_res; - const struct nfs_server * server; - struct nfs_fattr * fattr; - struct nfs_fh * fh; - struct nfs4_label *label; -}; - -struct nfs4_lookup_root_arg { - struct nfs4_sequence_args seq_args; - const u32 * bitmask; -}; - -struct nfs4_pathconf_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh * fh; - const u32 * bitmask; -}; - -struct nfs4_pathconf_res { - struct nfs4_sequence_res seq_res; - struct nfs_pathconf *pathconf; -}; - -struct nfs4_readdir_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh * fh; - u64 cookie; - nfs4_verifier verifier; - u32 count; - struct page ** pages; /* zero-copy data */ - unsigned int pgbase; /* zero-copy data */ - const u32 * bitmask; - int plus; -}; - -struct nfs4_readdir_res { - struct nfs4_sequence_res seq_res; - nfs4_verifier verifier; - unsigned int pgbase; -}; - -struct nfs4_readlink { - struct nfs4_sequence_args seq_args; - const struct nfs_fh * fh; - unsigned int pgbase; - unsigned int pglen; /* zero-copy data */ - struct page ** pages; /* zero-copy data */ -}; - -struct nfs4_readlink_res { - struct nfs4_sequence_res seq_res; -}; - -struct nfs4_setclientid { - const nfs4_verifier * sc_verifier; - u32 sc_prog; - unsigned int sc_netid_len; - char sc_netid[RPCBIND_MAXNETIDLEN + 1]; - unsigned int sc_uaddr_len; - char sc_uaddr[RPCBIND_MAXUADDRLEN + 1]; - struct nfs_client *sc_clnt; - struct rpc_cred *sc_cred; -}; - -struct nfs4_setclientid_res { - u64 clientid; - nfs4_verifier confirm; -}; - -struct nfs4_statfs_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh * fh; - const u32 * bitmask; -}; - -struct nfs4_statfs_res { - struct nfs4_sequence_res seq_res; - struct nfs_fsstat *fsstat; -}; - -struct nfs4_server_caps_arg { - struct nfs4_sequence_args seq_args; - struct nfs_fh *fhandle; - const u32 * bitmask; -}; - -struct nfs4_server_caps_res { - struct nfs4_sequence_res seq_res; - u32 attr_bitmask[3]; - u32 exclcreat_bitmask[3]; - u32 acl_bitmask; - u32 has_links; - u32 has_symlinks; - u32 fh_expire_type; -}; - -#define NFS4_PATHNAME_MAXCOMPONENTS 512 -struct nfs4_pathname { - unsigned int ncomponents; - struct nfs4_string components[NFS4_PATHNAME_MAXCOMPONENTS]; -}; - -#define NFS4_FS_LOCATION_MAXSERVERS 10 -struct nfs4_fs_location { - unsigned int nservers; - struct nfs4_string servers[NFS4_FS_LOCATION_MAXSERVERS]; - struct nfs4_pathname rootpath; -}; - -#define NFS4_FS_LOCATIONS_MAXENTRIES 10 -struct nfs4_fs_locations { - struct nfs_fattr fattr; - const struct nfs_server *server; - struct nfs4_pathname fs_path; - int nlocations; - struct nfs4_fs_location locations[NFS4_FS_LOCATIONS_MAXENTRIES]; -}; - -struct nfs4_fs_locations_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *dir_fh; - const struct nfs_fh *fh; - const struct qstr *name; - struct page *page; - const u32 *bitmask; - clientid4 clientid; - unsigned char migration:1, renew:1; -}; - -struct nfs4_fs_locations_res { - struct nfs4_sequence_res seq_res; - struct nfs4_fs_locations *fs_locations; - unsigned char migration:1, renew:1; -}; - -struct nfs4_secinfo4 { - u32 flavor; - struct rpcsec_gss_info flavor_info; -}; - -struct nfs4_secinfo_flavors { - unsigned int num_flavors; - struct nfs4_secinfo4 flavors[0]; -}; - -struct nfs4_secinfo_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *dir_fh; - const struct qstr *name; -}; - -struct nfs4_secinfo_res { - struct nfs4_sequence_res seq_res; - struct nfs4_secinfo_flavors *flavors; -}; - -struct nfs4_fsid_present_arg { - struct nfs4_sequence_args seq_args; - const struct nfs_fh *fh; - clientid4 clientid; - unsigned char renew:1; -}; - -struct nfs4_fsid_present_res { - struct nfs4_sequence_res seq_res; - struct nfs_fh *fh; - unsigned char renew:1; -}; - -#endif /* CONFIG_NFS_V4 */ - -struct nfstime4 { - u64 seconds; - u32 nseconds; -}; - -#ifdef CONFIG_NFS_V4_1 - -struct pnfs_commit_bucket { - struct list_head written; - struct list_head committing; - struct pnfs_layout_segment *wlseg; - struct pnfs_layout_segment *clseg; - struct nfs_writeverf direct_verf; -}; - -struct pnfs_ds_commit_info { - int nwritten; - int ncommitting; - int nbuckets; - struct pnfs_commit_bucket *buckets; -}; - -struct nfs41_state_protection { - u32 how; - struct nfs4_op_map enforce; - struct nfs4_op_map allow; -}; - -struct nfs41_exchange_id_args { - struct nfs_client *client; - nfs4_verifier *verifier; - u32 flags; - struct nfs41_state_protection state_protect; -}; - -struct nfs41_server_owner { - uint64_t minor_id; - uint32_t major_id_sz; - char major_id[NFS4_OPAQUE_LIMIT]; -}; - -struct nfs41_server_scope { - uint32_t server_scope_sz; - char server_scope[NFS4_OPAQUE_LIMIT]; -}; - -struct nfs41_impl_id { - char domain[NFS4_OPAQUE_LIMIT + 1]; - char name[NFS4_OPAQUE_LIMIT + 1]; - struct nfstime4 date; -}; - -struct nfs41_bind_conn_to_session_args { - struct nfs_client *client; - struct nfs4_sessionid sessionid; - u32 dir; - bool use_conn_in_rdma_mode; -}; - -struct nfs41_bind_conn_to_session_res { - struct nfs4_sessionid sessionid; - u32 dir; - bool use_conn_in_rdma_mode; -}; - -struct nfs41_exchange_id_res { - u64 clientid; - u32 seqid; - u32 flags; - struct nfs41_server_owner *server_owner; - struct nfs41_server_scope *server_scope; - struct nfs41_impl_id *impl_id; - struct nfs41_state_protection state_protect; -}; - -struct nfs41_create_session_args { - struct nfs_client *client; - u64 clientid; - uint32_t seqid; - uint32_t flags; - uint32_t cb_program; - struct nfs4_channel_attrs fc_attrs; /* Fore Channel */ - struct nfs4_channel_attrs bc_attrs; /* Back Channel */ -}; - -struct nfs41_create_session_res { - struct nfs4_sessionid sessionid; - uint32_t seqid; - uint32_t flags; - struct nfs4_channel_attrs fc_attrs; /* Fore Channel */ - struct nfs4_channel_attrs bc_attrs; /* Back Channel */ -}; - -struct nfs41_reclaim_complete_args { - struct nfs4_sequence_args seq_args; - /* In the future extend to include curr_fh for use with migration */ - unsigned char one_fs:1; -}; - -struct nfs41_reclaim_complete_res { - struct nfs4_sequence_res seq_res; -}; - -#define SECINFO_STYLE_CURRENT_FH 0 -#define SECINFO_STYLE_PARENT 1 -struct nfs41_secinfo_no_name_args { - struct nfs4_sequence_args seq_args; - int style; -}; - -struct nfs41_test_stateid_args { - struct nfs4_sequence_args seq_args; - nfs4_stateid *stateid; -}; - -struct nfs41_test_stateid_res { - struct nfs4_sequence_res seq_res; - unsigned int status; -}; - -struct nfs41_free_stateid_args { - struct nfs4_sequence_args seq_args; - nfs4_stateid stateid; -}; - -struct nfs41_free_stateid_res { - struct nfs4_sequence_res seq_res; - unsigned int status; -}; - -static inline void -nfs_free_pnfs_ds_cinfo(struct pnfs_ds_commit_info *cinfo) -{ - kfree(cinfo->buckets); -} - -#else - -struct pnfs_ds_commit_info { -}; - -static inline void -nfs_free_pnfs_ds_cinfo(struct pnfs_ds_commit_info *cinfo) -{ -} - -#endif /* CONFIG_NFS_V4_1 */ - -#ifdef CONFIG_NFS_V4_2 -struct nfs42_falloc_args { - struct nfs4_sequence_args seq_args; - - struct nfs_fh *falloc_fh; - nfs4_stateid falloc_stateid; - u64 falloc_offset; - u64 falloc_length; - const u32 *falloc_bitmask; -}; - -struct nfs42_falloc_res { - struct nfs4_sequence_res seq_res; - unsigned int status; - - struct nfs_fattr *falloc_fattr; - const struct nfs_server *falloc_server; -}; - -struct nfs42_copy_args { - struct nfs4_sequence_args seq_args; - - struct nfs_fh *src_fh; - nfs4_stateid src_stateid; - u64 src_pos; - - struct nfs_fh *dst_fh; - nfs4_stateid dst_stateid; - u64 dst_pos; - - u64 count; -}; - -struct nfs42_write_res { - u64 count; - struct nfs_writeverf verifier; -}; - -struct nfs42_copy_res { - struct nfs4_sequence_res seq_res; - struct nfs42_write_res write_res; - bool consecutive; - bool synchronous; -}; - -struct nfs42_seek_args { - struct nfs4_sequence_args seq_args; - - struct nfs_fh *sa_fh; - nfs4_stateid sa_stateid; - u64 sa_offset; - u32 sa_what; -}; - -struct nfs42_seek_res { - struct nfs4_sequence_res seq_res; - unsigned int status; - - u32 sr_eof; - u64 sr_offset; -}; -#endif - -struct nfs_page; - -#define NFS_PAGEVEC_SIZE (8U) - -struct nfs_page_array { - struct page **pagevec; - unsigned int npages; /* Max length of pagevec */ - struct page *page_array[NFS_PAGEVEC_SIZE]; -}; - -/* used as flag bits in nfs_pgio_header */ -enum { - NFS_IOHDR_ERROR = 0, - NFS_IOHDR_EOF, - NFS_IOHDR_REDO, - NFS_IOHDR_STAT, -}; - -struct nfs_pgio_header { - struct inode *inode; - struct rpc_cred *cred; - struct list_head pages; - struct nfs_page *req; - struct nfs_writeverf verf; /* Used for writes */ - struct pnfs_layout_segment *lseg; - loff_t io_start; - const struct rpc_call_ops *mds_ops; - void (*release) (struct nfs_pgio_header *hdr); - const struct nfs_pgio_completion_ops *completion_ops; - const struct nfs_rw_ops *rw_ops; - struct nfs_direct_req *dreq; - void *layout_private; - spinlock_t lock; - /* fields protected by lock */ - int pnfs_error; - int error; /* merge with pnfs_error */ - unsigned long good_bytes; /* boundary of good data */ - unsigned long flags; - - /* - * rpc data - */ - struct rpc_task task; - struct nfs_fattr fattr; - struct nfs_pgio_args args; /* argument struct */ - struct nfs_pgio_res res; /* result struct */ - unsigned long timestamp; /* For lease renewal */ - int (*pgio_done_cb)(struct rpc_task *, struct nfs_pgio_header *); - __u64 mds_offset; /* Filelayout dense stripe */ - struct nfs_page_array page_array; - struct nfs_client *ds_clp; /* pNFS data server */ - int ds_commit_idx; /* ds index if ds_clp is set */ - int pgio_mirror_idx;/* mirror index in pgio layer */ -}; - -struct nfs_mds_commit_info { - atomic_t rpcs_out; - unsigned long ncommit; - struct list_head list; -}; - -struct nfs_commit_info; -struct nfs_commit_data; -struct nfs_inode; -struct nfs_commit_completion_ops { - void (*completion) (struct nfs_commit_data *data); - void (*resched_write) (struct nfs_commit_info *, struct nfs_page *); -}; - -struct nfs_commit_info { - struct inode *inode; /* Needed for inode->i_lock */ - struct nfs_mds_commit_info *mds; - struct pnfs_ds_commit_info *ds; - struct nfs_direct_req *dreq; /* O_DIRECT request */ - const struct nfs_commit_completion_ops *completion_ops; -}; - -struct nfs_commit_data { - struct rpc_task task; - struct inode *inode; - struct rpc_cred *cred; - struct nfs_fattr fattr; - struct nfs_writeverf verf; - struct list_head pages; /* Coalesced requests we wish to flush */ - struct list_head list; /* lists of struct nfs_write_data */ - struct nfs_direct_req *dreq; /* O_DIRECT request */ - struct nfs_commitargs args; /* argument struct */ - struct nfs_commitres res; /* result struct */ - struct nfs_open_context *context; - struct pnfs_layout_segment *lseg; - struct nfs_client *ds_clp; /* pNFS data server */ - int ds_commit_index; - loff_t lwb; - const struct rpc_call_ops *mds_ops; - const struct nfs_commit_completion_ops *completion_ops; - int (*commit_done_cb) (struct rpc_task *task, struct nfs_commit_data *data); - unsigned long flags; -}; - -struct nfs_pgio_completion_ops { - void (*error_cleanup)(struct list_head *head); - void (*init_hdr)(struct nfs_pgio_header *hdr); - void (*completion)(struct nfs_pgio_header *hdr); - void (*reschedule_io)(struct nfs_pgio_header *hdr); -}; - -struct nfs_unlinkdata { - struct nfs_removeargs args; - struct nfs_removeres res; - struct dentry *dentry; - wait_queue_head_t wq; - struct rpc_cred *cred; - struct nfs_fattr dir_attr; - long timeout; -}; - -struct nfs_renamedata { - struct nfs_renameargs args; - struct nfs_renameres res; - struct rpc_cred *cred; - struct inode *old_dir; - struct dentry *old_dentry; - struct nfs_fattr old_fattr; - struct inode *new_dir; - struct dentry *new_dentry; - struct nfs_fattr new_fattr; - void (*complete)(struct rpc_task *, struct nfs_renamedata *); - long timeout; -}; - -struct nfs_access_entry; -struct nfs_client; -struct rpc_timeout; -struct nfs_subversion; -struct nfs_mount_info; -struct nfs_client_initdata; -struct nfs_pageio_descriptor; - -/* - * RPC procedure vector for NFSv2/NFSv3 demuxing - */ -struct nfs_rpc_ops { - u32 version; /* Protocol version */ - const struct dentry_operations *dentry_ops; - const struct inode_operations *dir_inode_ops; - const struct inode_operations *file_inode_ops; - const struct file_operations *file_ops; - - int (*getroot) (struct nfs_server *, struct nfs_fh *, - struct nfs_fsinfo *); - struct vfsmount *(*submount) (struct nfs_server *, struct dentry *, - struct nfs_fh *, struct nfs_fattr *); - struct dentry *(*try_mount) (int, const char *, struct nfs_mount_info *, - struct nfs_subversion *); - int (*getattr) (struct nfs_server *, struct nfs_fh *, - struct nfs_fattr *, struct nfs4_label *); - int (*setattr) (struct dentry *, struct nfs_fattr *, - struct iattr *); - int (*lookup) (struct inode *, const struct qstr *, - struct nfs_fh *, struct nfs_fattr *, - struct nfs4_label *); - int (*access) (struct inode *, struct nfs_access_entry *); - int (*readlink)(struct inode *, struct page *, unsigned int, - unsigned int); - int (*create) (struct inode *, struct dentry *, - struct iattr *, int); - int (*remove) (struct inode *, const struct qstr *); - void (*unlink_setup) (struct rpc_message *, struct inode *dir); - void (*unlink_rpc_prepare) (struct rpc_task *, struct nfs_unlinkdata *); - int (*unlink_done) (struct rpc_task *, struct inode *); - void (*rename_setup) (struct rpc_message *msg, struct inode *dir); - void (*rename_rpc_prepare)(struct rpc_task *task, struct nfs_renamedata *); - int (*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir); - int (*link) (struct inode *, struct inode *, const struct qstr *); - int (*symlink) (struct inode *, struct dentry *, struct page *, - unsigned int, struct iattr *); - int (*mkdir) (struct inode *, struct dentry *, struct iattr *); - int (*rmdir) (struct inode *, const struct qstr *); - int (*readdir) (struct dentry *, struct rpc_cred *, - u64, struct page **, unsigned int, int); - int (*mknod) (struct inode *, struct dentry *, struct iattr *, - dev_t); - int (*statfs) (struct nfs_server *, struct nfs_fh *, - struct nfs_fsstat *); - int (*fsinfo) (struct nfs_server *, struct nfs_fh *, - struct nfs_fsinfo *); - int (*pathconf) (struct nfs_server *, struct nfs_fh *, - struct nfs_pathconf *); - int (*set_capabilities)(struct nfs_server *, struct nfs_fh *); - int (*decode_dirent)(struct xdr_stream *, struct nfs_entry *, int); - int (*pgio_rpc_prepare)(struct rpc_task *, - struct nfs_pgio_header *); - void (*read_setup)(struct nfs_pgio_header *, struct rpc_message *); - int (*read_done)(struct rpc_task *, struct nfs_pgio_header *); - void (*write_setup)(struct nfs_pgio_header *, struct rpc_message *); - int (*write_done)(struct rpc_task *, struct nfs_pgio_header *); - void (*commit_setup) (struct nfs_commit_data *, struct rpc_message *); - void (*commit_rpc_prepare)(struct rpc_task *, struct nfs_commit_data *); - int (*commit_done) (struct rpc_task *, struct nfs_commit_data *); - int (*lock)(struct file *, int, struct file_lock *); - int (*lock_check_bounds)(const struct file_lock *); - void (*clear_acl_cache)(struct inode *); - void (*close_context)(struct nfs_open_context *ctx, int); - struct inode * (*open_context) (struct inode *dir, - struct nfs_open_context *ctx, - int open_flags, - struct iattr *iattr, - int *); - int (*have_delegation)(struct inode *, fmode_t); - int (*return_delegation)(struct inode *); - struct nfs_client *(*alloc_client) (const struct nfs_client_initdata *); - struct nfs_client *(*init_client) (struct nfs_client *, - const struct nfs_client_initdata *); - void (*free_client) (struct nfs_client *); - struct nfs_server *(*create_server)(struct nfs_mount_info *, struct nfs_subversion *); - struct nfs_server *(*clone_server)(struct nfs_server *, struct nfs_fh *, - struct nfs_fattr *, rpc_authflavor_t); -}; - -/* - * NFS_CALL(getattr, inode, (fattr)); - * into - * NFS_PROTO(inode)->getattr(fattr); - */ -#define NFS_CALL(op, inode, args) NFS_PROTO(inode)->op args - -/* - * Function vectors etc. for the NFS client - */ -extern const struct nfs_rpc_ops nfs_v2_clientops; -extern const struct nfs_rpc_ops nfs_v3_clientops; -extern const struct nfs_rpc_ops nfs_v4_clientops; -extern const struct rpc_version nfs_version2; -extern const struct rpc_version nfs_version3; -extern const struct rpc_version nfs_version4; - -extern const struct rpc_version nfsacl_version3; -extern const struct rpc_program nfsacl_program; - -#endif diff --git a/src/linux/include/linux/nfsacl.h b/src/linux/include/linux/nfsacl.h deleted file mode 100644 index 5e69e67..0000000 --- a/src/linux/include/linux/nfsacl.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * File: linux/nfsacl.h - * - * (C) 2003 Andreas Gruenbacher - */ -#ifndef __LINUX_NFSACL_H -#define __LINUX_NFSACL_H - - -#include -#include -#include - -/* Maximum number of ACL entries over NFS */ -#define NFS_ACL_MAX_ENTRIES 1024 - -#define NFSACL_MAXWORDS (2*(2+3*NFS_ACL_MAX_ENTRIES)) -#define NFSACL_MAXPAGES ((2*(8+12*NFS_ACL_MAX_ENTRIES) + PAGE_SIZE-1) \ - >> PAGE_SHIFT) - -#define NFS_ACL_MAX_ENTRIES_INLINE (5) -#define NFS_ACL_INLINE_BUFSIZE ((2*(2+3*NFS_ACL_MAX_ENTRIES_INLINE)) << 2) - -static inline unsigned int -nfsacl_size(struct posix_acl *acl_access, struct posix_acl *acl_default) -{ - unsigned int w = 16; - w += max(acl_access ? (int)acl_access->a_count : 3, 4) * 12; - if (acl_default) - w += max((int)acl_default->a_count, 4) * 12; - return w; -} - -extern int -nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, - struct posix_acl *acl, int encode_entries, int typeflag); -extern int -nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt, - struct posix_acl **pacl); - -#endif /* __LINUX_NFSACL_H */ diff --git a/src/linux/include/linux/nls.h b/src/linux/include/linux/nls.h deleted file mode 100644 index 520681b..0000000 --- a/src/linux/include/linux/nls.h +++ /dev/null @@ -1,108 +0,0 @@ -#ifndef _LINUX_NLS_H -#define _LINUX_NLS_H - -#include - -/* Unicode has changed over the years. Unicode code points no longer - * fit into 16 bits; as of Unicode 5 valid code points range from 0 - * to 0x10ffff (17 planes, where each plane holds 65536 code points). - * - * The original decision to represent Unicode characters as 16-bit - * wchar_t values is now outdated. But plane 0 still includes the - * most commonly used characters, so we will retain it. The newer - * 32-bit unicode_t type can be used when it is necessary to - * represent the full Unicode character set. - */ - -/* Plane-0 Unicode character */ -typedef u16 wchar_t; -#define MAX_WCHAR_T 0xffff - -/* Arbitrary Unicode character */ -typedef u32 unicode_t; - -struct nls_table { - const char *charset; - const char *alias; - int (*uni2char) (wchar_t uni, unsigned char *out, int boundlen); - int (*char2uni) (const unsigned char *rawstring, int boundlen, - wchar_t *uni); - const unsigned char *charset2lower; - const unsigned char *charset2upper; - struct module *owner; - struct nls_table *next; -}; - -/* this value hold the maximum octet of charset */ -#define NLS_MAX_CHARSET_SIZE 6 /* for UTF-8 */ - -/* Byte order for UTF-16 strings */ -enum utf16_endian { - UTF16_HOST_ENDIAN, - UTF16_LITTLE_ENDIAN, - UTF16_BIG_ENDIAN -}; - -/* nls_base.c */ -extern int __register_nls(struct nls_table *, struct module *); -extern int unregister_nls(struct nls_table *); -extern struct nls_table *load_nls(char *); -extern void unload_nls(struct nls_table *); -extern struct nls_table *load_nls_default(void); -#define register_nls(nls) __register_nls((nls), THIS_MODULE) - -extern int utf8_to_utf32(const u8 *s, int len, unicode_t *pu); -extern int utf32_to_utf8(unicode_t u, u8 *s, int maxlen); -extern int utf8s_to_utf16s(const u8 *s, int len, - enum utf16_endian endian, wchar_t *pwcs, int maxlen); -extern int utf16s_to_utf8s(const wchar_t *pwcs, int len, - enum utf16_endian endian, u8 *s, int maxlen); - -static inline unsigned char nls_tolower(struct nls_table *t, unsigned char c) -{ - unsigned char nc = t->charset2lower[c]; - - return nc ? nc : c; -} - -static inline unsigned char nls_toupper(struct nls_table *t, unsigned char c) -{ - unsigned char nc = t->charset2upper[c]; - - return nc ? nc : c; -} - -static inline int nls_strnicmp(struct nls_table *t, const unsigned char *s1, - const unsigned char *s2, int len) -{ - while (len--) { - if (nls_tolower(t, *s1++) != nls_tolower(t, *s2++)) - return 1; - } - - return 0; -} - -/* - * nls_nullsize - return length of null character for codepage - * @codepage - codepage for which to return length of NULL terminator - * - * Since we can't guarantee that the null terminator will be a particular - * length, we have to check against the codepage. If there's a problem - * determining it, assume a single-byte NULL terminator. - */ -static inline int -nls_nullsize(const struct nls_table *codepage) -{ - int charlen; - char tmp[NLS_MAX_CHARSET_SIZE]; - - charlen = codepage->uni2char(0, tmp, NLS_MAX_CHARSET_SIZE); - - return charlen > 0 ? charlen : 1; -} - -#define MODULE_ALIAS_NLS(name) MODULE_ALIAS("nls_" __stringify(name)) - -#endif /* _LINUX_NLS_H */ - diff --git a/src/linux/include/linux/nmi.h b/src/linux/include/linux/nmi.h deleted file mode 100644 index a78c35c..0000000 --- a/src/linux/include/linux/nmi.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * linux/include/linux/nmi.h - */ -#ifndef LINUX_NMI_H -#define LINUX_NMI_H - -#include -#include - -/** - * touch_nmi_watchdog - restart NMI watchdog timeout. - * - * If the architecture supports the NMI watchdog, touch_nmi_watchdog() - * may be used to reset the timeout - for code which intentionally - * disables interrupts for a long time. This call is stateless. - */ -#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR) -#include -extern void touch_nmi_watchdog(void); -#else -static inline void touch_nmi_watchdog(void) -{ - touch_softlockup_watchdog(); -} -#endif - -#if defined(CONFIG_HARDLOCKUP_DETECTOR) -extern void hardlockup_detector_disable(void); -#else -static inline void hardlockup_detector_disable(void) {} -#endif - -/* - * Create trigger_all_cpu_backtrace() out of the arch-provided - * base function. Return whether such support was available, - * to allow calling code to fall back to some other mechanism: - */ -#ifdef arch_trigger_cpumask_backtrace -static inline bool trigger_all_cpu_backtrace(void) -{ - arch_trigger_cpumask_backtrace(cpu_online_mask, false); - return true; -} - -static inline bool trigger_allbutself_cpu_backtrace(void) -{ - arch_trigger_cpumask_backtrace(cpu_online_mask, true); - return true; -} - -static inline bool trigger_cpumask_backtrace(struct cpumask *mask) -{ - arch_trigger_cpumask_backtrace(mask, false); - return true; -} - -static inline bool trigger_single_cpu_backtrace(int cpu) -{ - arch_trigger_cpumask_backtrace(cpumask_of(cpu), false); - return true; -} - -/* generic implementation */ -void nmi_trigger_cpumask_backtrace(const cpumask_t *mask, - bool exclude_self, - void (*raise)(cpumask_t *mask)); -bool nmi_cpu_backtrace(struct pt_regs *regs); - -#else -static inline bool trigger_all_cpu_backtrace(void) -{ - return false; -} -static inline bool trigger_allbutself_cpu_backtrace(void) -{ - return false; -} -static inline bool trigger_cpumask_backtrace(struct cpumask *mask) -{ - return false; -} -static inline bool trigger_single_cpu_backtrace(int cpu) -{ - return false; -} -#endif - -#ifdef CONFIG_LOCKUP_DETECTOR -u64 hw_nmi_get_sample_period(int watchdog_thresh); -extern int nmi_watchdog_enabled; -extern int soft_watchdog_enabled; -extern int watchdog_user_enabled; -extern int watchdog_thresh; -extern unsigned long *watchdog_cpumask_bits; -extern int sysctl_softlockup_all_cpu_backtrace; -extern int sysctl_hardlockup_all_cpu_backtrace; -struct ctl_table; -extern int proc_watchdog(struct ctl_table *, int , - void __user *, size_t *, loff_t *); -extern int proc_nmi_watchdog(struct ctl_table *, int , - void __user *, size_t *, loff_t *); -extern int proc_soft_watchdog(struct ctl_table *, int , - void __user *, size_t *, loff_t *); -extern int proc_watchdog_thresh(struct ctl_table *, int , - void __user *, size_t *, loff_t *); -extern int proc_watchdog_cpumask(struct ctl_table *, int, - void __user *, size_t *, loff_t *); -extern int lockup_detector_suspend(void); -extern void lockup_detector_resume(void); -#else -static inline int lockup_detector_suspend(void) -{ - return 0; -} - -static inline void lockup_detector_resume(void) -{ -} -#endif - -#ifdef CONFIG_HAVE_ACPI_APEI_NMI -#include -#endif - -#endif diff --git a/src/linux/include/linux/node.h b/src/linux/include/linux/node.h deleted file mode 100644 index 2115ad5..0000000 --- a/src/linux/include/linux/node.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * include/linux/node.h - generic node definition - * - * This is mainly for topological representation. We define the - * basic 'struct node' here, which can be embedded in per-arch - * definitions of processors. - * - * Basic handling of the devices is done in drivers/base/node.c - * and system devices are handled in drivers/base/sys.c. - * - * Nodes are exported via driverfs in the class/node/devices/ - * directory. - */ -#ifndef _LINUX_NODE_H_ -#define _LINUX_NODE_H_ - -#include -#include -#include - -struct node { - struct device dev; - -#if defined(CONFIG_MEMORY_HOTPLUG_SPARSE) && defined(CONFIG_HUGETLBFS) - struct work_struct node_work; -#endif -}; - -struct memory_block; -extern struct node *node_devices[]; -typedef void (*node_registration_func_t)(struct node *); - -extern void unregister_node(struct node *node); -#ifdef CONFIG_NUMA -extern int register_one_node(int nid); -extern void unregister_one_node(int nid); -extern int register_cpu_under_node(unsigned int cpu, unsigned int nid); -extern int unregister_cpu_under_node(unsigned int cpu, unsigned int nid); -extern int register_mem_sect_under_node(struct memory_block *mem_blk, - int nid); -extern int unregister_mem_sect_under_nodes(struct memory_block *mem_blk, - unsigned long phys_index); - -#ifdef CONFIG_HUGETLBFS -extern void register_hugetlbfs_with_node(node_registration_func_t doregister, - node_registration_func_t unregister); -#endif -#else -static inline int register_one_node(int nid) -{ - return 0; -} -static inline int unregister_one_node(int nid) -{ - return 0; -} -static inline int register_cpu_under_node(unsigned int cpu, unsigned int nid) -{ - return 0; -} -static inline int unregister_cpu_under_node(unsigned int cpu, unsigned int nid) -{ - return 0; -} -static inline int register_mem_sect_under_node(struct memory_block *mem_blk, - int nid) -{ - return 0; -} -static inline int unregister_mem_sect_under_nodes(struct memory_block *mem_blk, - unsigned long phys_index) -{ - return 0; -} - -static inline void register_hugetlbfs_with_node(node_registration_func_t reg, - node_registration_func_t unreg) -{ -} -#endif - -#define to_node(device) container_of(device, struct node, dev) - -#endif /* _LINUX_NODE_H_ */ diff --git a/src/linux/include/linux/nodemask.h b/src/linux/include/linux/nodemask.h deleted file mode 100644 index f746e44..0000000 --- a/src/linux/include/linux/nodemask.h +++ /dev/null @@ -1,536 +0,0 @@ -#ifndef __LINUX_NODEMASK_H -#define __LINUX_NODEMASK_H - -/* - * Nodemasks provide a bitmap suitable for representing the - * set of Node's in a system, one bit position per Node number. - * - * See detailed comments in the file linux/bitmap.h describing the - * data type on which these nodemasks are based. - * - * For details of nodemask_parse_user(), see bitmap_parse_user() in - * lib/bitmap.c. For details of nodelist_parse(), see bitmap_parselist(), - * also in bitmap.c. For details of node_remap(), see bitmap_bitremap in - * lib/bitmap.c. For details of nodes_remap(), see bitmap_remap in - * lib/bitmap.c. For details of nodes_onto(), see bitmap_onto in - * lib/bitmap.c. For details of nodes_fold(), see bitmap_fold in - * lib/bitmap.c. - * - * The available nodemask operations are: - * - * void node_set(node, mask) turn on bit 'node' in mask - * void node_clear(node, mask) turn off bit 'node' in mask - * void nodes_setall(mask) set all bits - * void nodes_clear(mask) clear all bits - * int node_isset(node, mask) true iff bit 'node' set in mask - * int node_test_and_set(node, mask) test and set bit 'node' in mask - * - * void nodes_and(dst, src1, src2) dst = src1 & src2 [intersection] - * void nodes_or(dst, src1, src2) dst = src1 | src2 [union] - * void nodes_xor(dst, src1, src2) dst = src1 ^ src2 - * void nodes_andnot(dst, src1, src2) dst = src1 & ~src2 - * void nodes_complement(dst, src) dst = ~src - * - * int nodes_equal(mask1, mask2) Does mask1 == mask2? - * int nodes_intersects(mask1, mask2) Do mask1 and mask2 intersect? - * int nodes_subset(mask1, mask2) Is mask1 a subset of mask2? - * int nodes_empty(mask) Is mask empty (no bits sets)? - * int nodes_full(mask) Is mask full (all bits sets)? - * int nodes_weight(mask) Hamming weight - number of set bits - * - * void nodes_shift_right(dst, src, n) Shift right - * void nodes_shift_left(dst, src, n) Shift left - * - * int first_node(mask) Number lowest set bit, or MAX_NUMNODES - * int next_node(node, mask) Next node past 'node', or MAX_NUMNODES - * int next_node_in(node, mask) Next node past 'node', or wrap to first, - * or MAX_NUMNODES - * int first_unset_node(mask) First node not set in mask, or - * MAX_NUMNODES - * - * nodemask_t nodemask_of_node(node) Return nodemask with bit 'node' set - * NODE_MASK_ALL Initializer - all bits set - * NODE_MASK_NONE Initializer - no bits set - * unsigned long *nodes_addr(mask) Array of unsigned long's in mask - * - * int nodemask_parse_user(ubuf, ulen, mask) Parse ascii string as nodemask - * int nodelist_parse(buf, map) Parse ascii string as nodelist - * int node_remap(oldbit, old, new) newbit = map(old, new)(oldbit) - * void nodes_remap(dst, src, old, new) *dst = map(old, new)(src) - * void nodes_onto(dst, orig, relmap) *dst = orig relative to relmap - * void nodes_fold(dst, orig, sz) dst bits = orig bits mod sz - * - * for_each_node_mask(node, mask) for-loop node over mask - * - * int num_online_nodes() Number of online Nodes - * int num_possible_nodes() Number of all possible Nodes - * - * int node_random(mask) Random node with set bit in mask - * - * int node_online(node) Is some node online? - * int node_possible(node) Is some node possible? - * - * node_set_online(node) set bit 'node' in node_online_map - * node_set_offline(node) clear bit 'node' in node_online_map - * - * for_each_node(node) for-loop node over node_possible_map - * for_each_online_node(node) for-loop node over node_online_map - * - * Subtlety: - * 1) The 'type-checked' form of node_isset() causes gcc (3.3.2, anyway) - * to generate slightly worse code. So use a simple one-line #define - * for node_isset(), instead of wrapping an inline inside a macro, the - * way we do the other calls. - * - * NODEMASK_SCRATCH - * When doing above logical AND, OR, XOR, Remap operations the callers tend to - * need temporary nodemask_t's on the stack. But if NODES_SHIFT is large, - * nodemask_t's consume too much stack space. NODEMASK_SCRATCH is a helper - * for such situations. See below and CPUMASK_ALLOC also. - */ - -#include -#include -#include -#include - -typedef struct { DECLARE_BITMAP(bits, MAX_NUMNODES); } nodemask_t; -extern nodemask_t _unused_nodemask_arg_; - -/** - * nodemask_pr_args - printf args to output a nodemask - * @maskp: nodemask to be printed - * - * Can be used to provide arguments for '%*pb[l]' when printing a nodemask. - */ -#define nodemask_pr_args(maskp) MAX_NUMNODES, (maskp)->bits - -/* - * The inline keyword gives the compiler room to decide to inline, or - * not inline a function as it sees best. However, as these functions - * are called in both __init and non-__init functions, if they are not - * inlined we will end up with a section mis-match error (of the type of - * freeable items not being freed). So we must use __always_inline here - * to fix the problem. If other functions in the future also end up in - * this situation they will also need to be annotated as __always_inline - */ -#define node_set(node, dst) __node_set((node), &(dst)) -static __always_inline void __node_set(int node, volatile nodemask_t *dstp) -{ - set_bit(node, dstp->bits); -} - -#define node_clear(node, dst) __node_clear((node), &(dst)) -static inline void __node_clear(int node, volatile nodemask_t *dstp) -{ - clear_bit(node, dstp->bits); -} - -#define nodes_setall(dst) __nodes_setall(&(dst), MAX_NUMNODES) -static inline void __nodes_setall(nodemask_t *dstp, unsigned int nbits) -{ - bitmap_fill(dstp->bits, nbits); -} - -#define nodes_clear(dst) __nodes_clear(&(dst), MAX_NUMNODES) -static inline void __nodes_clear(nodemask_t *dstp, unsigned int nbits) -{ - bitmap_zero(dstp->bits, nbits); -} - -/* No static inline type checking - see Subtlety (1) above. */ -#define node_isset(node, nodemask) test_bit((node), (nodemask).bits) - -#define node_test_and_set(node, nodemask) \ - __node_test_and_set((node), &(nodemask)) -static inline int __node_test_and_set(int node, nodemask_t *addr) -{ - return test_and_set_bit(node, addr->bits); -} - -#define nodes_and(dst, src1, src2) \ - __nodes_and(&(dst), &(src1), &(src2), MAX_NUMNODES) -static inline void __nodes_and(nodemask_t *dstp, const nodemask_t *src1p, - const nodemask_t *src2p, unsigned int nbits) -{ - bitmap_and(dstp->bits, src1p->bits, src2p->bits, nbits); -} - -#define nodes_or(dst, src1, src2) \ - __nodes_or(&(dst), &(src1), &(src2), MAX_NUMNODES) -static inline void __nodes_or(nodemask_t *dstp, const nodemask_t *src1p, - const nodemask_t *src2p, unsigned int nbits) -{ - bitmap_or(dstp->bits, src1p->bits, src2p->bits, nbits); -} - -#define nodes_xor(dst, src1, src2) \ - __nodes_xor(&(dst), &(src1), &(src2), MAX_NUMNODES) -static inline void __nodes_xor(nodemask_t *dstp, const nodemask_t *src1p, - const nodemask_t *src2p, unsigned int nbits) -{ - bitmap_xor(dstp->bits, src1p->bits, src2p->bits, nbits); -} - -#define nodes_andnot(dst, src1, src2) \ - __nodes_andnot(&(dst), &(src1), &(src2), MAX_NUMNODES) -static inline void __nodes_andnot(nodemask_t *dstp, const nodemask_t *src1p, - const nodemask_t *src2p, unsigned int nbits) -{ - bitmap_andnot(dstp->bits, src1p->bits, src2p->bits, nbits); -} - -#define nodes_complement(dst, src) \ - __nodes_complement(&(dst), &(src), MAX_NUMNODES) -static inline void __nodes_complement(nodemask_t *dstp, - const nodemask_t *srcp, unsigned int nbits) -{ - bitmap_complement(dstp->bits, srcp->bits, nbits); -} - -#define nodes_equal(src1, src2) \ - __nodes_equal(&(src1), &(src2), MAX_NUMNODES) -static inline int __nodes_equal(const nodemask_t *src1p, - const nodemask_t *src2p, unsigned int nbits) -{ - return bitmap_equal(src1p->bits, src2p->bits, nbits); -} - -#define nodes_intersects(src1, src2) \ - __nodes_intersects(&(src1), &(src2), MAX_NUMNODES) -static inline int __nodes_intersects(const nodemask_t *src1p, - const nodemask_t *src2p, unsigned int nbits) -{ - return bitmap_intersects(src1p->bits, src2p->bits, nbits); -} - -#define nodes_subset(src1, src2) \ - __nodes_subset(&(src1), &(src2), MAX_NUMNODES) -static inline int __nodes_subset(const nodemask_t *src1p, - const nodemask_t *src2p, unsigned int nbits) -{ - return bitmap_subset(src1p->bits, src2p->bits, nbits); -} - -#define nodes_empty(src) __nodes_empty(&(src), MAX_NUMNODES) -static inline int __nodes_empty(const nodemask_t *srcp, unsigned int nbits) -{ - return bitmap_empty(srcp->bits, nbits); -} - -#define nodes_full(nodemask) __nodes_full(&(nodemask), MAX_NUMNODES) -static inline int __nodes_full(const nodemask_t *srcp, unsigned int nbits) -{ - return bitmap_full(srcp->bits, nbits); -} - -#define nodes_weight(nodemask) __nodes_weight(&(nodemask), MAX_NUMNODES) -static inline int __nodes_weight(const nodemask_t *srcp, unsigned int nbits) -{ - return bitmap_weight(srcp->bits, nbits); -} - -#define nodes_shift_right(dst, src, n) \ - __nodes_shift_right(&(dst), &(src), (n), MAX_NUMNODES) -static inline void __nodes_shift_right(nodemask_t *dstp, - const nodemask_t *srcp, int n, int nbits) -{ - bitmap_shift_right(dstp->bits, srcp->bits, n, nbits); -} - -#define nodes_shift_left(dst, src, n) \ - __nodes_shift_left(&(dst), &(src), (n), MAX_NUMNODES) -static inline void __nodes_shift_left(nodemask_t *dstp, - const nodemask_t *srcp, int n, int nbits) -{ - bitmap_shift_left(dstp->bits, srcp->bits, n, nbits); -} - -/* FIXME: better would be to fix all architectures to never return - > MAX_NUMNODES, then the silly min_ts could be dropped. */ - -#define first_node(src) __first_node(&(src)) -static inline int __first_node(const nodemask_t *srcp) -{ - return min_t(int, MAX_NUMNODES, find_first_bit(srcp->bits, MAX_NUMNODES)); -} - -#define next_node(n, src) __next_node((n), &(src)) -static inline int __next_node(int n, const nodemask_t *srcp) -{ - return min_t(int,MAX_NUMNODES,find_next_bit(srcp->bits, MAX_NUMNODES, n+1)); -} - -/* - * Find the next present node in src, starting after node n, wrapping around to - * the first node in src if needed. Returns MAX_NUMNODES if src is empty. - */ -#define next_node_in(n, src) __next_node_in((n), &(src)) -int __next_node_in(int node, const nodemask_t *srcp); - -static inline void init_nodemask_of_node(nodemask_t *mask, int node) -{ - nodes_clear(*mask); - node_set(node, *mask); -} - -#define nodemask_of_node(node) \ -({ \ - typeof(_unused_nodemask_arg_) m; \ - if (sizeof(m) == sizeof(unsigned long)) { \ - m.bits[0] = 1UL << (node); \ - } else { \ - init_nodemask_of_node(&m, (node)); \ - } \ - m; \ -}) - -#define first_unset_node(mask) __first_unset_node(&(mask)) -static inline int __first_unset_node(const nodemask_t *maskp) -{ - return min_t(int,MAX_NUMNODES, - find_first_zero_bit(maskp->bits, MAX_NUMNODES)); -} - -#define NODE_MASK_LAST_WORD BITMAP_LAST_WORD_MASK(MAX_NUMNODES) - -#if MAX_NUMNODES <= BITS_PER_LONG - -#define NODE_MASK_ALL \ -((nodemask_t) { { \ - [BITS_TO_LONGS(MAX_NUMNODES)-1] = NODE_MASK_LAST_WORD \ -} }) - -#else - -#define NODE_MASK_ALL \ -((nodemask_t) { { \ - [0 ... BITS_TO_LONGS(MAX_NUMNODES)-2] = ~0UL, \ - [BITS_TO_LONGS(MAX_NUMNODES)-1] = NODE_MASK_LAST_WORD \ -} }) - -#endif - -#define NODE_MASK_NONE \ -((nodemask_t) { { \ - [0 ... BITS_TO_LONGS(MAX_NUMNODES)-1] = 0UL \ -} }) - -#define nodes_addr(src) ((src).bits) - -#define nodemask_parse_user(ubuf, ulen, dst) \ - __nodemask_parse_user((ubuf), (ulen), &(dst), MAX_NUMNODES) -static inline int __nodemask_parse_user(const char __user *buf, int len, - nodemask_t *dstp, int nbits) -{ - return bitmap_parse_user(buf, len, dstp->bits, nbits); -} - -#define nodelist_parse(buf, dst) __nodelist_parse((buf), &(dst), MAX_NUMNODES) -static inline int __nodelist_parse(const char *buf, nodemask_t *dstp, int nbits) -{ - return bitmap_parselist(buf, dstp->bits, nbits); -} - -#define node_remap(oldbit, old, new) \ - __node_remap((oldbit), &(old), &(new), MAX_NUMNODES) -static inline int __node_remap(int oldbit, - const nodemask_t *oldp, const nodemask_t *newp, int nbits) -{ - return bitmap_bitremap(oldbit, oldp->bits, newp->bits, nbits); -} - -#define nodes_remap(dst, src, old, new) \ - __nodes_remap(&(dst), &(src), &(old), &(new), MAX_NUMNODES) -static inline void __nodes_remap(nodemask_t *dstp, const nodemask_t *srcp, - const nodemask_t *oldp, const nodemask_t *newp, int nbits) -{ - bitmap_remap(dstp->bits, srcp->bits, oldp->bits, newp->bits, nbits); -} - -#define nodes_onto(dst, orig, relmap) \ - __nodes_onto(&(dst), &(orig), &(relmap), MAX_NUMNODES) -static inline void __nodes_onto(nodemask_t *dstp, const nodemask_t *origp, - const nodemask_t *relmapp, int nbits) -{ - bitmap_onto(dstp->bits, origp->bits, relmapp->bits, nbits); -} - -#define nodes_fold(dst, orig, sz) \ - __nodes_fold(&(dst), &(orig), sz, MAX_NUMNODES) -static inline void __nodes_fold(nodemask_t *dstp, const nodemask_t *origp, - int sz, int nbits) -{ - bitmap_fold(dstp->bits, origp->bits, sz, nbits); -} - -#if MAX_NUMNODES > 1 -#define for_each_node_mask(node, mask) \ - for ((node) = first_node(mask); \ - (node) < MAX_NUMNODES; \ - (node) = next_node((node), (mask))) -#else /* MAX_NUMNODES == 1 */ -#define for_each_node_mask(node, mask) \ - if (!nodes_empty(mask)) \ - for ((node) = 0; (node) < 1; (node)++) -#endif /* MAX_NUMNODES */ - -/* - * Bitmasks that are kept for all the nodes. - */ -enum node_states { - N_POSSIBLE, /* The node could become online at some point */ - N_ONLINE, /* The node is online */ - N_NORMAL_MEMORY, /* The node has regular memory */ -#ifdef CONFIG_HIGHMEM - N_HIGH_MEMORY, /* The node has regular or high memory */ -#else - N_HIGH_MEMORY = N_NORMAL_MEMORY, -#endif -#ifdef CONFIG_MOVABLE_NODE - N_MEMORY, /* The node has memory(regular, high, movable) */ -#else - N_MEMORY = N_HIGH_MEMORY, -#endif - N_CPU, /* The node has one or more cpus */ - NR_NODE_STATES -}; - -/* - * The following particular system nodemasks and operations - * on them manage all possible and online nodes. - */ - -extern nodemask_t node_states[NR_NODE_STATES]; - -#if MAX_NUMNODES > 1 -static inline int node_state(int node, enum node_states state) -{ - return node_isset(node, node_states[state]); -} - -static inline void node_set_state(int node, enum node_states state) -{ - __node_set(node, &node_states[state]); -} - -static inline void node_clear_state(int node, enum node_states state) -{ - __node_clear(node, &node_states[state]); -} - -static inline int num_node_state(enum node_states state) -{ - return nodes_weight(node_states[state]); -} - -#define for_each_node_state(__node, __state) \ - for_each_node_mask((__node), node_states[__state]) - -#define first_online_node first_node(node_states[N_ONLINE]) -#define first_memory_node first_node(node_states[N_MEMORY]) -static inline int next_online_node(int nid) -{ - return next_node(nid, node_states[N_ONLINE]); -} -static inline int next_memory_node(int nid) -{ - return next_node(nid, node_states[N_MEMORY]); -} - -extern int nr_node_ids; -extern int nr_online_nodes; - -static inline void node_set_online(int nid) -{ - node_set_state(nid, N_ONLINE); - nr_online_nodes = num_node_state(N_ONLINE); -} - -static inline void node_set_offline(int nid) -{ - node_clear_state(nid, N_ONLINE); - nr_online_nodes = num_node_state(N_ONLINE); -} - -#else - -static inline int node_state(int node, enum node_states state) -{ - return node == 0; -} - -static inline void node_set_state(int node, enum node_states state) -{ -} - -static inline void node_clear_state(int node, enum node_states state) -{ -} - -static inline int num_node_state(enum node_states state) -{ - return 1; -} - -#define for_each_node_state(node, __state) \ - for ( (node) = 0; (node) == 0; (node) = 1) - -#define first_online_node 0 -#define first_memory_node 0 -#define next_online_node(nid) (MAX_NUMNODES) -#define nr_node_ids 1 -#define nr_online_nodes 1 - -#define node_set_online(node) node_set_state((node), N_ONLINE) -#define node_set_offline(node) node_clear_state((node), N_ONLINE) - -#endif - -#if defined(CONFIG_NUMA) && (MAX_NUMNODES > 1) -extern int node_random(const nodemask_t *maskp); -#else -static inline int node_random(const nodemask_t *mask) -{ - return 0; -} -#endif - -#define node_online_map node_states[N_ONLINE] -#define node_possible_map node_states[N_POSSIBLE] - -#define num_online_nodes() num_node_state(N_ONLINE) -#define num_possible_nodes() num_node_state(N_POSSIBLE) -#define node_online(node) node_state((node), N_ONLINE) -#define node_possible(node) node_state((node), N_POSSIBLE) - -#define for_each_node(node) for_each_node_state(node, N_POSSIBLE) -#define for_each_online_node(node) for_each_node_state(node, N_ONLINE) - -/* - * For nodemask scrach area. - * NODEMASK_ALLOC(type, name) allocates an object with a specified type and - * name. - */ -#if NODES_SHIFT > 8 /* nodemask_t > 256 bytes */ -#define NODEMASK_ALLOC(type, name, gfp_flags) \ - type *name = kmalloc(sizeof(*name), gfp_flags) -#define NODEMASK_FREE(m) kfree(m) -#else -#define NODEMASK_ALLOC(type, name, gfp_flags) type _##name, *name = &_##name -#define NODEMASK_FREE(m) do {} while (0) -#endif - -/* A example struture for using NODEMASK_ALLOC, used in mempolicy. */ -struct nodemask_scratch { - nodemask_t mask1; - nodemask_t mask2; -}; - -#define NODEMASK_SCRATCH(x) \ - NODEMASK_ALLOC(struct nodemask_scratch, x, \ - GFP_KERNEL | __GFP_NORETRY) -#define NODEMASK_SCRATCH_FREE(x) NODEMASK_FREE(x) - - -#endif /* __LINUX_NODEMASK_H */ diff --git a/src/linux/include/linux/notifier.h b/src/linux/include/linux/notifier.h deleted file mode 100644 index 4149868..0000000 --- a/src/linux/include/linux/notifier.h +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Routines to manage notifier chains for passing status changes to any - * interested routines. We need this instead of hard coded call lists so - * that modules can poke their nose into the innards. The network devices - * needed them so here they are for the rest of you. - * - * Alan Cox - */ - -#ifndef _LINUX_NOTIFIER_H -#define _LINUX_NOTIFIER_H -#include -#include -#include -#include - -/* - * Notifier chains are of four types: - * - * Atomic notifier chains: Chain callbacks run in interrupt/atomic - * context. Callouts are not allowed to block. - * Blocking notifier chains: Chain callbacks run in process context. - * Callouts are allowed to block. - * Raw notifier chains: There are no restrictions on callbacks, - * registration, or unregistration. All locking and protection - * must be provided by the caller. - * SRCU notifier chains: A variant of blocking notifier chains, with - * the same restrictions. - * - * atomic_notifier_chain_register() may be called from an atomic context, - * but blocking_notifier_chain_register() and srcu_notifier_chain_register() - * must be called from a process context. Ditto for the corresponding - * _unregister() routines. - * - * atomic_notifier_chain_unregister(), blocking_notifier_chain_unregister(), - * and srcu_notifier_chain_unregister() _must not_ be called from within - * the call chain. - * - * SRCU notifier chains are an alternative form of blocking notifier chains. - * They use SRCU (Sleepable Read-Copy Update) instead of rw-semaphores for - * protection of the chain links. This means there is _very_ low overhead - * in srcu_notifier_call_chain(): no cache bounces and no memory barriers. - * As compensation, srcu_notifier_chain_unregister() is rather expensive. - * SRCU notifier chains should be used when the chain will be called very - * often but notifier_blocks will seldom be removed. Also, SRCU notifier - * chains are slightly more difficult to use because they require special - * runtime initialization. - */ - -struct notifier_block; - -typedef int (*notifier_fn_t)(struct notifier_block *nb, - unsigned long action, void *data); - -struct notifier_block { - notifier_fn_t notifier_call; - struct notifier_block __rcu *next; - int priority; -}; - -struct atomic_notifier_head { - spinlock_t lock; - struct notifier_block __rcu *head; -}; - -struct blocking_notifier_head { - struct rw_semaphore rwsem; - struct notifier_block __rcu *head; -}; - -struct raw_notifier_head { - struct notifier_block __rcu *head; -}; - -struct srcu_notifier_head { - struct mutex mutex; - struct srcu_struct srcu; - struct notifier_block __rcu *head; -}; - -#define ATOMIC_INIT_NOTIFIER_HEAD(name) do { \ - spin_lock_init(&(name)->lock); \ - (name)->head = NULL; \ - } while (0) -#define BLOCKING_INIT_NOTIFIER_HEAD(name) do { \ - init_rwsem(&(name)->rwsem); \ - (name)->head = NULL; \ - } while (0) -#define RAW_INIT_NOTIFIER_HEAD(name) do { \ - (name)->head = NULL; \ - } while (0) - -/* srcu_notifier_heads must be initialized and cleaned up dynamically */ -extern void srcu_init_notifier_head(struct srcu_notifier_head *nh); -#define srcu_cleanup_notifier_head(name) \ - cleanup_srcu_struct(&(name)->srcu); - -#define ATOMIC_NOTIFIER_INIT(name) { \ - .lock = __SPIN_LOCK_UNLOCKED(name.lock), \ - .head = NULL } -#define BLOCKING_NOTIFIER_INIT(name) { \ - .rwsem = __RWSEM_INITIALIZER((name).rwsem), \ - .head = NULL } -#define RAW_NOTIFIER_INIT(name) { \ - .head = NULL } -/* srcu_notifier_heads cannot be initialized statically */ - -#define ATOMIC_NOTIFIER_HEAD(name) \ - struct atomic_notifier_head name = \ - ATOMIC_NOTIFIER_INIT(name) -#define BLOCKING_NOTIFIER_HEAD(name) \ - struct blocking_notifier_head name = \ - BLOCKING_NOTIFIER_INIT(name) -#define RAW_NOTIFIER_HEAD(name) \ - struct raw_notifier_head name = \ - RAW_NOTIFIER_INIT(name) - -#ifdef __KERNEL__ - -extern int atomic_notifier_chain_register(struct atomic_notifier_head *nh, - struct notifier_block *nb); -extern int blocking_notifier_chain_register(struct blocking_notifier_head *nh, - struct notifier_block *nb); -extern int raw_notifier_chain_register(struct raw_notifier_head *nh, - struct notifier_block *nb); -extern int srcu_notifier_chain_register(struct srcu_notifier_head *nh, - struct notifier_block *nb); - -extern int blocking_notifier_chain_cond_register( - struct blocking_notifier_head *nh, - struct notifier_block *nb); - -extern int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, - struct notifier_block *nb); -extern int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh, - struct notifier_block *nb); -extern int raw_notifier_chain_unregister(struct raw_notifier_head *nh, - struct notifier_block *nb); -extern int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh, - struct notifier_block *nb); - -extern int atomic_notifier_call_chain(struct atomic_notifier_head *nh, - unsigned long val, void *v); -extern int __atomic_notifier_call_chain(struct atomic_notifier_head *nh, - unsigned long val, void *v, int nr_to_call, int *nr_calls); -extern int blocking_notifier_call_chain(struct blocking_notifier_head *nh, - unsigned long val, void *v); -extern int __blocking_notifier_call_chain(struct blocking_notifier_head *nh, - unsigned long val, void *v, int nr_to_call, int *nr_calls); -extern int raw_notifier_call_chain(struct raw_notifier_head *nh, - unsigned long val, void *v); -extern int __raw_notifier_call_chain(struct raw_notifier_head *nh, - unsigned long val, void *v, int nr_to_call, int *nr_calls); -extern int srcu_notifier_call_chain(struct srcu_notifier_head *nh, - unsigned long val, void *v); -extern int __srcu_notifier_call_chain(struct srcu_notifier_head *nh, - unsigned long val, void *v, int nr_to_call, int *nr_calls); - -#define NOTIFY_DONE 0x0000 /* Don't care */ -#define NOTIFY_OK 0x0001 /* Suits me */ -#define NOTIFY_STOP_MASK 0x8000 /* Don't call further */ -#define NOTIFY_BAD (NOTIFY_STOP_MASK|0x0002) - /* Bad/Veto action */ -/* - * Clean way to return from the notifier and stop further calls. - */ -#define NOTIFY_STOP (NOTIFY_OK|NOTIFY_STOP_MASK) - -/* Encapsulate (negative) errno value (in particular, NOTIFY_BAD <=> EPERM). */ -static inline int notifier_from_errno(int err) -{ - if (err) - return NOTIFY_STOP_MASK | (NOTIFY_OK - err); - - return NOTIFY_OK; -} - -/* Restore (negative) errno value from notify return value. */ -static inline int notifier_to_errno(int ret) -{ - ret &= ~NOTIFY_STOP_MASK; - return ret > NOTIFY_OK ? NOTIFY_OK - ret : 0; -} - -/* - * Declared notifiers so far. I can imagine quite a few more chains - * over time (eg laptop power reset chains, reboot chain (to clean - * device units up), device [un]mount chain, module load/unload chain, - * low memory chain, screenblank chain (for plug in modular screenblankers) - * VC switch chains (for loadable kernel svgalib VC switch helpers) etc... - */ - -/* CPU notfiers are defined in include/linux/cpu.h. */ - -/* netdevice notifiers are defined in include/linux/netdevice.h */ - -/* reboot notifiers are defined in include/linux/reboot.h. */ - -/* Hibernation and suspend events are defined in include/linux/suspend.h. */ - -/* Virtual Terminal events are defined in include/linux/vt.h. */ - -#define NETLINK_URELEASE 0x0001 /* Unicast netlink socket released */ - -/* Console keyboard events. - * Note: KBD_KEYCODE is always sent before KBD_UNBOUND_KEYCODE, KBD_UNICODE and - * KBD_KEYSYM. */ -#define KBD_KEYCODE 0x0001 /* Keyboard keycode, called before any other */ -#define KBD_UNBOUND_KEYCODE 0x0002 /* Keyboard keycode which is not bound to any other */ -#define KBD_UNICODE 0x0003 /* Keyboard unicode */ -#define KBD_KEYSYM 0x0004 /* Keyboard keysym */ -#define KBD_POST_KEYSYM 0x0005 /* Called after keyboard keysym interpretation */ - -extern struct blocking_notifier_head reboot_notifier_list; - -#endif /* __KERNEL__ */ -#endif /* _LINUX_NOTIFIER_H */ diff --git a/src/linux/include/linux/ns_common.h b/src/linux/include/linux/ns_common.h deleted file mode 100644 index 85a5c8c..0000000 --- a/src/linux/include/linux/ns_common.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _LINUX_NS_COMMON_H -#define _LINUX_NS_COMMON_H - -struct proc_ns_operations; - -struct ns_common { - atomic_long_t stashed; - const struct proc_ns_operations *ops; - unsigned int inum; -}; - -#endif diff --git a/src/linux/include/linux/nsproxy.h b/src/linux/include/linux/nsproxy.h deleted file mode 100644 index ac0d65b..0000000 --- a/src/linux/include/linux/nsproxy.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef _LINUX_NSPROXY_H -#define _LINUX_NSPROXY_H - -#include -#include - -struct mnt_namespace; -struct uts_namespace; -struct ipc_namespace; -struct pid_namespace; -struct cgroup_namespace; -struct fs_struct; - -/* - * A structure to contain pointers to all per-process - * namespaces - fs (mount), uts, network, sysvipc, etc. - * - * The pid namespace is an exception -- it's accessed using - * task_active_pid_ns. The pid namespace here is the - * namespace that children will use. - * - * 'count' is the number of tasks holding a reference. - * The count for each namespace, then, will be the number - * of nsproxies pointing to it, not the number of tasks. - * - * The nsproxy is shared by tasks which share all namespaces. - * As soon as a single namespace is cloned or unshared, the - * nsproxy is copied. - */ -struct nsproxy { - atomic_t count; - struct uts_namespace *uts_ns; - struct ipc_namespace *ipc_ns; - struct mnt_namespace *mnt_ns; - struct pid_namespace *pid_ns_for_children; - struct net *net_ns; - struct cgroup_namespace *cgroup_ns; -}; -extern struct nsproxy init_nsproxy; - -/* - * the namespaces access rules are: - * - * 1. only current task is allowed to change tsk->nsproxy pointer or - * any pointer on the nsproxy itself. Current must hold the task_lock - * when changing tsk->nsproxy. - * - * 2. when accessing (i.e. reading) current task's namespaces - no - * precautions should be taken - just dereference the pointers - * - * 3. the access to other task namespaces is performed like this - * task_lock(task); - * nsproxy = task->nsproxy; - * if (nsproxy != NULL) { - * / * - * * work with the namespaces here - * * e.g. get the reference on one of them - * * / - * } / * - * * NULL task->nsproxy means that this task is - * * almost dead (zombie) - * * / - * task_unlock(task); - * - */ - -int copy_namespaces(unsigned long flags, struct task_struct *tsk); -void exit_task_namespaces(struct task_struct *tsk); -void switch_task_namespaces(struct task_struct *tsk, struct nsproxy *new); -void free_nsproxy(struct nsproxy *ns); -int unshare_nsproxy_namespaces(unsigned long, struct nsproxy **, - struct cred *, struct fs_struct *); -int __init nsproxy_cache_init(void); - -static inline void put_nsproxy(struct nsproxy *ns) -{ - if (atomic_dec_and_test(&ns->count)) { - free_nsproxy(ns); - } -} - -static inline void get_nsproxy(struct nsproxy *ns) -{ - atomic_inc(&ns->count); -} - -#endif diff --git a/src/linux/include/linux/numa.h b/src/linux/include/linux/numa.h deleted file mode 100644 index 3aaa316..0000000 --- a/src/linux/include/linux/numa.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _LINUX_NUMA_H -#define _LINUX_NUMA_H - - -#ifdef CONFIG_NODES_SHIFT -#define NODES_SHIFT CONFIG_NODES_SHIFT -#else -#define NODES_SHIFT 0 -#endif - -#define MAX_NUMNODES (1 << NODES_SHIFT) - -#define NUMA_NO_NODE (-1) - -#endif /* _LINUX_NUMA_H */ diff --git a/src/linux/include/linux/of.h b/src/linux/include/linux/of.h deleted file mode 100644 index 299aeb1..0000000 --- a/src/linux/include/linux/of.h +++ /dev/null @@ -1,1295 +0,0 @@ -#ifndef _LINUX_OF_H -#define _LINUX_OF_H -/* - * Definitions for talking to the Open Firmware PROM on - * Power Macintosh and other computers. - * - * Copyright (C) 1996-2005 Paul Mackerras. - * - * Updates for PPC64 by Peter Bergner & David Engebretsen, IBM Corp. - * Updates for SPARC64 by David S. Miller - * Derived from PowerPC and Sparc prom.h files by Stephen Rothwell, IBM Corp. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -typedef u32 phandle; -typedef u32 ihandle; - -struct property { - char *name; - int length; - void *value; - struct property *next; - unsigned long _flags; - unsigned int unique_id; - struct bin_attribute attr; -}; - -#if defined(CONFIG_SPARC) -struct of_irq_controller; -#endif - -struct device_node { - const char *name; - const char *type; - phandle phandle; - const char *full_name; - struct fwnode_handle fwnode; - - struct property *properties; - struct property *deadprops; /* removed properties */ - struct device_node *parent; - struct device_node *child; - struct device_node *sibling; - struct kobject kobj; - unsigned long _flags; - void *data; -#if defined(CONFIG_SPARC) - const char *path_component_name; - unsigned int unique_id; - struct of_irq_controller *irq_trans; -#endif -}; - -#define MAX_PHANDLE_ARGS 16 -struct of_phandle_args { - struct device_node *np; - int args_count; - uint32_t args[MAX_PHANDLE_ARGS]; -}; - -struct of_phandle_iterator { - /* Common iterator information */ - const char *cells_name; - int cell_count; - const struct device_node *parent; - - /* List size information */ - const __be32 *list_end; - const __be32 *phandle_end; - - /* Current position state */ - const __be32 *cur; - uint32_t cur_count; - phandle phandle; - struct device_node *node; -}; - -struct of_reconfig_data { - struct device_node *dn; - struct property *prop; - struct property *old_prop; -}; - -/* initialize a node */ -extern struct kobj_type of_node_ktype; -static inline void of_node_init(struct device_node *node) -{ - kobject_init(&node->kobj, &of_node_ktype); - node->fwnode.type = FWNODE_OF; -} - -/* true when node is initialized */ -static inline int of_node_is_initialized(struct device_node *node) -{ - return node && node->kobj.state_initialized; -} - -/* true when node is attached (i.e. present on sysfs) */ -static inline int of_node_is_attached(struct device_node *node) -{ - return node && node->kobj.state_in_sysfs; -} - -#ifdef CONFIG_OF_DYNAMIC -extern struct device_node *of_node_get(struct device_node *node); -extern void of_node_put(struct device_node *node); -#else /* CONFIG_OF_DYNAMIC */ -/* Dummy ref counting routines - to be implemented later */ -static inline struct device_node *of_node_get(struct device_node *node) -{ - return node; -} -static inline void of_node_put(struct device_node *node) { } -#endif /* !CONFIG_OF_DYNAMIC */ - -/* Pointer for first entry in chain of all nodes. */ -extern struct device_node *of_root; -extern struct device_node *of_chosen; -extern struct device_node *of_aliases; -extern struct device_node *of_stdout; -extern raw_spinlock_t devtree_lock; - -/* flag descriptions (need to be visible even when !CONFIG_OF) */ -#define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */ -#define OF_DETACHED 2 /* node has been detached from the device tree */ -#define OF_POPULATED 3 /* device already created for the node */ -#define OF_POPULATED_BUS 4 /* of_platform_populate recursed to children of this node */ - -#define OF_BAD_ADDR ((u64)-1) - -#ifdef CONFIG_OF -void of_core_init(void); - -static inline bool is_of_node(struct fwnode_handle *fwnode) -{ - return !IS_ERR_OR_NULL(fwnode) && fwnode->type == FWNODE_OF; -} - -static inline struct device_node *to_of_node(struct fwnode_handle *fwnode) -{ - return is_of_node(fwnode) ? - container_of(fwnode, struct device_node, fwnode) : NULL; -} - -static inline bool of_have_populated_dt(void) -{ - return of_root != NULL; -} - -static inline bool of_node_is_root(const struct device_node *node) -{ - return node && (node->parent == NULL); -} - -static inline int of_node_check_flag(struct device_node *n, unsigned long flag) -{ - return test_bit(flag, &n->_flags); -} - -static inline int of_node_test_and_set_flag(struct device_node *n, - unsigned long flag) -{ - return test_and_set_bit(flag, &n->_flags); -} - -static inline void of_node_set_flag(struct device_node *n, unsigned long flag) -{ - set_bit(flag, &n->_flags); -} - -static inline void of_node_clear_flag(struct device_node *n, unsigned long flag) -{ - clear_bit(flag, &n->_flags); -} - -static inline int of_property_check_flag(struct property *p, unsigned long flag) -{ - return test_bit(flag, &p->_flags); -} - -static inline void of_property_set_flag(struct property *p, unsigned long flag) -{ - set_bit(flag, &p->_flags); -} - -static inline void of_property_clear_flag(struct property *p, unsigned long flag) -{ - clear_bit(flag, &p->_flags); -} - -extern struct device_node *__of_find_all_nodes(struct device_node *prev); -extern struct device_node *of_find_all_nodes(struct device_node *prev); - -/* - * OF address retrieval & translation - */ - -/* Helper to read a big number; size is in cells (not bytes) */ -static inline u64 of_read_number(const __be32 *cell, int size) -{ - u64 r = 0; - while (size--) - r = (r << 32) | be32_to_cpu(*(cell++)); - return r; -} - -/* Like of_read_number, but we want an unsigned long result */ -static inline unsigned long of_read_ulong(const __be32 *cell, int size) -{ - /* toss away upper bits if unsigned long is smaller than u64 */ - return of_read_number(cell, size); -} - -#if defined(CONFIG_SPARC) -#include -#endif - -/* Default #address and #size cells. Allow arch asm/prom.h to override */ -#if !defined(OF_ROOT_NODE_ADDR_CELLS_DEFAULT) -#define OF_ROOT_NODE_ADDR_CELLS_DEFAULT 1 -#define OF_ROOT_NODE_SIZE_CELLS_DEFAULT 1 -#endif - -#define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) -#define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) - -static inline const char *of_node_full_name(const struct device_node *np) -{ - return np ? np->full_name : ""; -} - -#define for_each_of_allnodes_from(from, dn) \ - for (dn = __of_find_all_nodes(from); dn; dn = __of_find_all_nodes(dn)) -#define for_each_of_allnodes(dn) for_each_of_allnodes_from(NULL, dn) -extern struct device_node *of_find_node_by_name(struct device_node *from, - const char *name); -extern struct device_node *of_find_node_by_type(struct device_node *from, - const char *type); -extern struct device_node *of_find_compatible_node(struct device_node *from, - const char *type, const char *compat); -extern struct device_node *of_find_matching_node_and_match( - struct device_node *from, - const struct of_device_id *matches, - const struct of_device_id **match); - -extern struct device_node *of_find_node_opts_by_path(const char *path, - const char **opts); -static inline struct device_node *of_find_node_by_path(const char *path) -{ - return of_find_node_opts_by_path(path, NULL); -} - -extern struct device_node *of_find_node_by_phandle(phandle handle); -extern struct device_node *of_get_parent(const struct device_node *node); -extern struct device_node *of_get_next_parent(struct device_node *node); -extern struct device_node *of_get_next_child(const struct device_node *node, - struct device_node *prev); -extern struct device_node *of_get_next_available_child( - const struct device_node *node, struct device_node *prev); - -extern struct device_node *of_get_child_by_name(const struct device_node *node, - const char *name); - -/* cache lookup */ -extern struct device_node *of_find_next_cache_node(const struct device_node *); -extern struct device_node *of_find_node_with_property( - struct device_node *from, const char *prop_name); - -extern struct property *of_find_property(const struct device_node *np, - const char *name, - int *lenp); -extern int of_property_count_elems_of_size(const struct device_node *np, - const char *propname, int elem_size); -extern int of_property_read_u32_index(const struct device_node *np, - const char *propname, - u32 index, u32 *out_value); -extern int of_property_read_variable_u8_array(const struct device_node *np, - const char *propname, u8 *out_values, - size_t sz_min, size_t sz_max); -extern int of_property_read_variable_u16_array(const struct device_node *np, - const char *propname, u16 *out_values, - size_t sz_min, size_t sz_max); -extern int of_property_read_variable_u32_array(const struct device_node *np, - const char *propname, - u32 *out_values, - size_t sz_min, - size_t sz_max); -extern int of_property_read_u64(const struct device_node *np, - const char *propname, u64 *out_value); -extern int of_property_read_variable_u64_array(const struct device_node *np, - const char *propname, - u64 *out_values, - size_t sz_min, - size_t sz_max); - -extern int of_property_read_string(const struct device_node *np, - const char *propname, - const char **out_string); -extern int of_property_match_string(const struct device_node *np, - const char *propname, - const char *string); -extern int of_property_read_string_helper(const struct device_node *np, - const char *propname, - const char **out_strs, size_t sz, int index); -extern int of_device_is_compatible(const struct device_node *device, - const char *); -extern int of_device_compatible_match(struct device_node *device, - const char *const *compat); -extern bool of_device_is_available(const struct device_node *device); -extern bool of_device_is_big_endian(const struct device_node *device); -extern const void *of_get_property(const struct device_node *node, - const char *name, - int *lenp); -extern struct device_node *of_get_cpu_node(int cpu, unsigned int *thread); -#define for_each_property_of_node(dn, pp) \ - for (pp = dn->properties; pp != NULL; pp = pp->next) - -extern int of_n_addr_cells(struct device_node *np); -extern int of_n_size_cells(struct device_node *np); -extern const struct of_device_id *of_match_node( - const struct of_device_id *matches, const struct device_node *node); -extern int of_modalias_node(struct device_node *node, char *modalias, int len); -extern void of_print_phandle_args(const char *msg, const struct of_phandle_args *args); -extern struct device_node *of_parse_phandle(const struct device_node *np, - const char *phandle_name, - int index); -extern int of_parse_phandle_with_args(const struct device_node *np, - const char *list_name, const char *cells_name, int index, - struct of_phandle_args *out_args); -extern int of_parse_phandle_with_fixed_args(const struct device_node *np, - const char *list_name, int cells_count, int index, - struct of_phandle_args *out_args); -extern int of_count_phandle_with_args(const struct device_node *np, - const char *list_name, const char *cells_name); - -/* phandle iterator functions */ -extern int of_phandle_iterator_init(struct of_phandle_iterator *it, - const struct device_node *np, - const char *list_name, - const char *cells_name, - int cell_count); - -extern int of_phandle_iterator_next(struct of_phandle_iterator *it); -extern int of_phandle_iterator_args(struct of_phandle_iterator *it, - uint32_t *args, - int size); - -extern void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)); -extern int of_alias_get_id(struct device_node *np, const char *stem); -extern int of_alias_get_highest_id(const char *stem); - -extern int of_machine_is_compatible(const char *compat); - -extern int of_add_property(struct device_node *np, struct property *prop); -extern int of_remove_property(struct device_node *np, struct property *prop); -extern int of_update_property(struct device_node *np, struct property *newprop); - -/* For updating the device tree at runtime */ -#define OF_RECONFIG_ATTACH_NODE 0x0001 -#define OF_RECONFIG_DETACH_NODE 0x0002 -#define OF_RECONFIG_ADD_PROPERTY 0x0003 -#define OF_RECONFIG_REMOVE_PROPERTY 0x0004 -#define OF_RECONFIG_UPDATE_PROPERTY 0x0005 - -extern int of_attach_node(struct device_node *); -extern int of_detach_node(struct device_node *); - -#define of_match_ptr(_ptr) (_ptr) - -/** - * of_property_read_u8_array - Find and read an array of u8 from a property. - * - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * @out_values: pointer to return value, modified only if return value is 0. - * @sz: number of array elements to read - * - * Search for a property in a device node and read 8-bit value(s) from - * it. Returns 0 on success, -EINVAL if the property does not exist, - * -ENODATA if property does not have a value, and -EOVERFLOW if the - * property data isn't large enough. - * - * dts entry of array should be like: - * property = /bits/ 8 <0x50 0x60 0x70>; - * - * The out_values is modified only if a valid u8 value can be decoded. - */ -static inline int of_property_read_u8_array(const struct device_node *np, - const char *propname, - u8 *out_values, size_t sz) -{ - int ret = of_property_read_variable_u8_array(np, propname, out_values, - sz, 0); - if (ret >= 0) - return 0; - else - return ret; -} - -/** - * of_property_read_u16_array - Find and read an array of u16 from a property. - * - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * @out_values: pointer to return value, modified only if return value is 0. - * @sz: number of array elements to read - * - * Search for a property in a device node and read 16-bit value(s) from - * it. Returns 0 on success, -EINVAL if the property does not exist, - * -ENODATA if property does not have a value, and -EOVERFLOW if the - * property data isn't large enough. - * - * dts entry of array should be like: - * property = /bits/ 16 <0x5000 0x6000 0x7000>; - * - * The out_values is modified only if a valid u16 value can be decoded. - */ -static inline int of_property_read_u16_array(const struct device_node *np, - const char *propname, - u16 *out_values, size_t sz) -{ - int ret = of_property_read_variable_u16_array(np, propname, out_values, - sz, 0); - if (ret >= 0) - return 0; - else - return ret; -} - -/** - * of_property_read_u32_array - Find and read an array of 32 bit integers - * from a property. - * - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * @out_values: pointer to return value, modified only if return value is 0. - * @sz: number of array elements to read - * - * Search for a property in a device node and read 32-bit value(s) from - * it. Returns 0 on success, -EINVAL if the property does not exist, - * -ENODATA if property does not have a value, and -EOVERFLOW if the - * property data isn't large enough. - * - * The out_values is modified only if a valid u32 value can be decoded. - */ -static inline int of_property_read_u32_array(const struct device_node *np, - const char *propname, - u32 *out_values, size_t sz) -{ - int ret = of_property_read_variable_u32_array(np, propname, out_values, - sz, 0); - if (ret >= 0) - return 0; - else - return ret; -} - -/** - * of_property_read_u64_array - Find and read an array of 64 bit integers - * from a property. - * - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * @out_values: pointer to return value, modified only if return value is 0. - * @sz: number of array elements to read - * - * Search for a property in a device node and read 64-bit value(s) from - * it. Returns 0 on success, -EINVAL if the property does not exist, - * -ENODATA if property does not have a value, and -EOVERFLOW if the - * property data isn't large enough. - * - * The out_values is modified only if a valid u64 value can be decoded. - */ -static inline int of_property_read_u64_array(const struct device_node *np, - const char *propname, - u64 *out_values, size_t sz) -{ - int ret = of_property_read_variable_u64_array(np, propname, out_values, - sz, 0); - if (ret >= 0) - return 0; - else - return ret; -} - -/* - * struct property *prop; - * const __be32 *p; - * u32 u; - * - * of_property_for_each_u32(np, "propname", prop, p, u) - * printk("U32 value: %x\n", u); - */ -const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur, - u32 *pu); -/* - * struct property *prop; - * const char *s; - * - * of_property_for_each_string(np, "propname", prop, s) - * printk("String value: %s\n", s); - */ -const char *of_prop_next_string(struct property *prop, const char *cur); - -bool of_console_check(struct device_node *dn, char *name, int index); - -#else /* CONFIG_OF */ - -static inline void of_core_init(void) -{ -} - -static inline bool is_of_node(struct fwnode_handle *fwnode) -{ - return false; -} - -static inline struct device_node *to_of_node(struct fwnode_handle *fwnode) -{ - return NULL; -} - -static inline const char* of_node_full_name(const struct device_node *np) -{ - return ""; -} - -static inline struct device_node *of_find_node_by_name(struct device_node *from, - const char *name) -{ - return NULL; -} - -static inline struct device_node *of_find_node_by_type(struct device_node *from, - const char *type) -{ - return NULL; -} - -static inline struct device_node *of_find_matching_node_and_match( - struct device_node *from, - const struct of_device_id *matches, - const struct of_device_id **match) -{ - return NULL; -} - -static inline struct device_node *of_find_node_by_path(const char *path) -{ - return NULL; -} - -static inline struct device_node *of_find_node_opts_by_path(const char *path, - const char **opts) -{ - return NULL; -} - -static inline struct device_node *of_find_node_by_phandle(phandle handle) -{ - return NULL; -} - -static inline struct device_node *of_get_parent(const struct device_node *node) -{ - return NULL; -} - -static inline struct device_node *of_get_next_child( - const struct device_node *node, struct device_node *prev) -{ - return NULL; -} - -static inline struct device_node *of_get_next_available_child( - const struct device_node *node, struct device_node *prev) -{ - return NULL; -} - -static inline struct device_node *of_find_node_with_property( - struct device_node *from, const char *prop_name) -{ - return NULL; -} - -static inline bool of_have_populated_dt(void) -{ - return false; -} - -static inline struct device_node *of_get_child_by_name( - const struct device_node *node, - const char *name) -{ - return NULL; -} - -static inline int of_device_is_compatible(const struct device_node *device, - const char *name) -{ - return 0; -} - -static inline bool of_device_is_available(const struct device_node *device) -{ - return false; -} - -static inline bool of_device_is_big_endian(const struct device_node *device) -{ - return false; -} - -static inline struct property *of_find_property(const struct device_node *np, - const char *name, - int *lenp) -{ - return NULL; -} - -static inline struct device_node *of_find_compatible_node( - struct device_node *from, - const char *type, - const char *compat) -{ - return NULL; -} - -static inline int of_property_count_elems_of_size(const struct device_node *np, - const char *propname, int elem_size) -{ - return -ENOSYS; -} - -static inline int of_property_read_u32_index(const struct device_node *np, - const char *propname, u32 index, u32 *out_value) -{ - return -ENOSYS; -} - -static inline int of_property_read_u8_array(const struct device_node *np, - const char *propname, u8 *out_values, size_t sz) -{ - return -ENOSYS; -} - -static inline int of_property_read_u16_array(const struct device_node *np, - const char *propname, u16 *out_values, size_t sz) -{ - return -ENOSYS; -} - -static inline int of_property_read_u32_array(const struct device_node *np, - const char *propname, - u32 *out_values, size_t sz) -{ - return -ENOSYS; -} - -static inline int of_property_read_u64_array(const struct device_node *np, - const char *propname, - u64 *out_values, size_t sz) -{ - return -ENOSYS; -} - -static inline int of_property_read_string(const struct device_node *np, - const char *propname, - const char **out_string) -{ - return -ENOSYS; -} - -static inline int of_property_read_string_helper(const struct device_node *np, - const char *propname, - const char **out_strs, size_t sz, int index) -{ - return -ENOSYS; -} - -static inline const void *of_get_property(const struct device_node *node, - const char *name, - int *lenp) -{ - return NULL; -} - -static inline struct device_node *of_get_cpu_node(int cpu, - unsigned int *thread) -{ - return NULL; -} - -static inline int of_property_read_u64(const struct device_node *np, - const char *propname, u64 *out_value) -{ - return -ENOSYS; -} - -static inline int of_property_match_string(const struct device_node *np, - const char *propname, - const char *string) -{ - return -ENOSYS; -} - -static inline struct device_node *of_parse_phandle(const struct device_node *np, - const char *phandle_name, - int index) -{ - return NULL; -} - -static inline int of_parse_phandle_with_args(const struct device_node *np, - const char *list_name, - const char *cells_name, - int index, - struct of_phandle_args *out_args) -{ - return -ENOSYS; -} - -static inline int of_parse_phandle_with_fixed_args(const struct device_node *np, - const char *list_name, int cells_count, int index, - struct of_phandle_args *out_args) -{ - return -ENOSYS; -} - -static inline int of_count_phandle_with_args(struct device_node *np, - const char *list_name, - const char *cells_name) -{ - return -ENOSYS; -} - -static inline int of_phandle_iterator_init(struct of_phandle_iterator *it, - const struct device_node *np, - const char *list_name, - const char *cells_name, - int cell_count) -{ - return -ENOSYS; -} - -static inline int of_phandle_iterator_next(struct of_phandle_iterator *it) -{ - return -ENOSYS; -} - -static inline int of_phandle_iterator_args(struct of_phandle_iterator *it, - uint32_t *args, - int size) -{ - return 0; -} - -static inline int of_alias_get_id(struct device_node *np, const char *stem) -{ - return -ENOSYS; -} - -static inline int of_alias_get_highest_id(const char *stem) -{ - return -ENOSYS; -} - -static inline int of_machine_is_compatible(const char *compat) -{ - return 0; -} - -static inline bool of_console_check(const struct device_node *dn, const char *name, int index) -{ - return false; -} - -static inline const __be32 *of_prop_next_u32(struct property *prop, - const __be32 *cur, u32 *pu) -{ - return NULL; -} - -static inline const char *of_prop_next_string(struct property *prop, - const char *cur) -{ - return NULL; -} - -static inline int of_node_check_flag(struct device_node *n, unsigned long flag) -{ - return 0; -} - -static inline int of_node_test_and_set_flag(struct device_node *n, - unsigned long flag) -{ - return 0; -} - -static inline void of_node_set_flag(struct device_node *n, unsigned long flag) -{ -} - -static inline void of_node_clear_flag(struct device_node *n, unsigned long flag) -{ -} - -static inline int of_property_check_flag(struct property *p, unsigned long flag) -{ - return 0; -} - -static inline void of_property_set_flag(struct property *p, unsigned long flag) -{ -} - -static inline void of_property_clear_flag(struct property *p, unsigned long flag) -{ -} - -#define of_match_ptr(_ptr) NULL -#define of_match_node(_matches, _node) NULL -#endif /* CONFIG_OF */ - -/* Default string compare functions, Allow arch asm/prom.h to override */ -#if !defined(of_compat_cmp) -#define of_compat_cmp(s1, s2, l) strcasecmp((s1), (s2)) -#define of_prop_cmp(s1, s2) strcmp((s1), (s2)) -#define of_node_cmp(s1, s2) strcasecmp((s1), (s2)) -#endif - -#if defined(CONFIG_OF) && defined(CONFIG_NUMA) -extern int of_node_to_nid(struct device_node *np); -#else -static inline int of_node_to_nid(struct device_node *device) -{ - return NUMA_NO_NODE; -} -#endif - -#ifdef CONFIG_OF_NUMA -extern int of_numa_init(void); -#else -static inline int of_numa_init(void) -{ - return -ENOSYS; -} -#endif - -static inline struct device_node *of_find_matching_node( - struct device_node *from, - const struct of_device_id *matches) -{ - return of_find_matching_node_and_match(from, matches, NULL); -} - -/** - * of_property_count_u8_elems - Count the number of u8 elements in a property - * - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * - * Search for a property in a device node and count the number of u8 elements - * in it. Returns number of elements on sucess, -EINVAL if the property does - * not exist or its length does not match a multiple of u8 and -ENODATA if the - * property does not have a value. - */ -static inline int of_property_count_u8_elems(const struct device_node *np, - const char *propname) -{ - return of_property_count_elems_of_size(np, propname, sizeof(u8)); -} - -/** - * of_property_count_u16_elems - Count the number of u16 elements in a property - * - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * - * Search for a property in a device node and count the number of u16 elements - * in it. Returns number of elements on sucess, -EINVAL if the property does - * not exist or its length does not match a multiple of u16 and -ENODATA if the - * property does not have a value. - */ -static inline int of_property_count_u16_elems(const struct device_node *np, - const char *propname) -{ - return of_property_count_elems_of_size(np, propname, sizeof(u16)); -} - -/** - * of_property_count_u32_elems - Count the number of u32 elements in a property - * - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * - * Search for a property in a device node and count the number of u32 elements - * in it. Returns number of elements on sucess, -EINVAL if the property does - * not exist or its length does not match a multiple of u32 and -ENODATA if the - * property does not have a value. - */ -static inline int of_property_count_u32_elems(const struct device_node *np, - const char *propname) -{ - return of_property_count_elems_of_size(np, propname, sizeof(u32)); -} - -/** - * of_property_count_u64_elems - Count the number of u64 elements in a property - * - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * - * Search for a property in a device node and count the number of u64 elements - * in it. Returns number of elements on sucess, -EINVAL if the property does - * not exist or its length does not match a multiple of u64 and -ENODATA if the - * property does not have a value. - */ -static inline int of_property_count_u64_elems(const struct device_node *np, - const char *propname) -{ - return of_property_count_elems_of_size(np, propname, sizeof(u64)); -} - -/** - * of_property_read_string_array() - Read an array of strings from a multiple - * strings property. - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * @out_strs: output array of string pointers. - * @sz: number of array elements to read. - * - * Search for a property in a device tree node and retrieve a list of - * terminated string values (pointer to data, not a copy) in that property. - * - * If @out_strs is NULL, the number of strings in the property is returned. - */ -static inline int of_property_read_string_array(const struct device_node *np, - const char *propname, const char **out_strs, - size_t sz) -{ - return of_property_read_string_helper(np, propname, out_strs, sz, 0); -} - -/** - * of_property_count_strings() - Find and return the number of strings from a - * multiple strings property. - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * - * Search for a property in a device tree node and retrieve the number of null - * terminated string contain in it. Returns the number of strings on - * success, -EINVAL if the property does not exist, -ENODATA if property - * does not have a value, and -EILSEQ if the string is not null-terminated - * within the length of the property data. - */ -static inline int of_property_count_strings(const struct device_node *np, - const char *propname) -{ - return of_property_read_string_helper(np, propname, NULL, 0, 0); -} - -/** - * of_property_read_string_index() - Find and read a string from a multiple - * strings property. - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * @index: index of the string in the list of strings - * @out_string: pointer to null terminated return string, modified only if - * return value is 0. - * - * Search for a property in a device tree node and retrieve a null - * terminated string value (pointer to data, not a copy) in the list of strings - * contained in that property. - * Returns 0 on success, -EINVAL if the property does not exist, -ENODATA if - * property does not have a value, and -EILSEQ if the string is not - * null-terminated within the length of the property data. - * - * The out_string pointer is modified only if a valid string can be decoded. - */ -static inline int of_property_read_string_index(const struct device_node *np, - const char *propname, - int index, const char **output) -{ - int rc = of_property_read_string_helper(np, propname, output, 1, index); - return rc < 0 ? rc : 0; -} - -/** - * of_property_read_bool - Findfrom a property - * @np: device node from which the property value is to be read. - * @propname: name of the property to be searched. - * - * Search for a property in a device node. - * Returns true if the property exists false otherwise. - */ -static inline bool of_property_read_bool(const struct device_node *np, - const char *propname) -{ - struct property *prop = of_find_property(np, propname, NULL); - - return prop ? true : false; -} - -static inline int of_property_read_u8(const struct device_node *np, - const char *propname, - u8 *out_value) -{ - return of_property_read_u8_array(np, propname, out_value, 1); -} - -static inline int of_property_read_u16(const struct device_node *np, - const char *propname, - u16 *out_value) -{ - return of_property_read_u16_array(np, propname, out_value, 1); -} - -static inline int of_property_read_u32(const struct device_node *np, - const char *propname, - u32 *out_value) -{ - return of_property_read_u32_array(np, propname, out_value, 1); -} - -static inline int of_property_read_s32(const struct device_node *np, - const char *propname, - s32 *out_value) -{ - return of_property_read_u32(np, propname, (u32*) out_value); -} - -#define of_for_each_phandle(it, err, np, ln, cn, cc) \ - for (of_phandle_iterator_init((it), (np), (ln), (cn), (cc)), \ - err = of_phandle_iterator_next(it); \ - err == 0; \ - err = of_phandle_iterator_next(it)) - -#define of_property_for_each_u32(np, propname, prop, p, u) \ - for (prop = of_find_property(np, propname, NULL), \ - p = of_prop_next_u32(prop, NULL, &u); \ - p; \ - p = of_prop_next_u32(prop, p, &u)) - -#define of_property_for_each_string(np, propname, prop, s) \ - for (prop = of_find_property(np, propname, NULL), \ - s = of_prop_next_string(prop, NULL); \ - s; \ - s = of_prop_next_string(prop, s)) - -#define for_each_node_by_name(dn, name) \ - for (dn = of_find_node_by_name(NULL, name); dn; \ - dn = of_find_node_by_name(dn, name)) -#define for_each_node_by_type(dn, type) \ - for (dn = of_find_node_by_type(NULL, type); dn; \ - dn = of_find_node_by_type(dn, type)) -#define for_each_compatible_node(dn, type, compatible) \ - for (dn = of_find_compatible_node(NULL, type, compatible); dn; \ - dn = of_find_compatible_node(dn, type, compatible)) -#define for_each_matching_node(dn, matches) \ - for (dn = of_find_matching_node(NULL, matches); dn; \ - dn = of_find_matching_node(dn, matches)) -#define for_each_matching_node_and_match(dn, matches, match) \ - for (dn = of_find_matching_node_and_match(NULL, matches, match); \ - dn; dn = of_find_matching_node_and_match(dn, matches, match)) - -#define for_each_child_of_node(parent, child) \ - for (child = of_get_next_child(parent, NULL); child != NULL; \ - child = of_get_next_child(parent, child)) -#define for_each_available_child_of_node(parent, child) \ - for (child = of_get_next_available_child(parent, NULL); child != NULL; \ - child = of_get_next_available_child(parent, child)) - -#define for_each_node_with_property(dn, prop_name) \ - for (dn = of_find_node_with_property(NULL, prop_name); dn; \ - dn = of_find_node_with_property(dn, prop_name)) - -static inline int of_get_child_count(const struct device_node *np) -{ - struct device_node *child; - int num = 0; - - for_each_child_of_node(np, child) - num++; - - return num; -} - -static inline int of_get_available_child_count(const struct device_node *np) -{ - struct device_node *child; - int num = 0; - - for_each_available_child_of_node(np, child) - num++; - - return num; -} - -#if defined(CONFIG_OF) && !defined(MODULE) -#define _OF_DECLARE(table, name, compat, fn, fn_type) \ - static const struct of_device_id __of_table_##name \ - __used __section(__##table##_of_table) \ - = { .compatible = compat, \ - .data = (fn == (fn_type)NULL) ? fn : fn } -#else -#define _OF_DECLARE(table, name, compat, fn, fn_type) \ - static const struct of_device_id __of_table_##name \ - __attribute__((unused)) \ - = { .compatible = compat, \ - .data = (fn == (fn_type)NULL) ? fn : fn } -#endif - -typedef int (*of_init_fn_2)(struct device_node *, struct device_node *); -typedef int (*of_init_fn_1_ret)(struct device_node *); -typedef void (*of_init_fn_1)(struct device_node *); - -#define OF_DECLARE_1(table, name, compat, fn) \ - _OF_DECLARE(table, name, compat, fn, of_init_fn_1) -#define OF_DECLARE_1_RET(table, name, compat, fn) \ - _OF_DECLARE(table, name, compat, fn, of_init_fn_1_ret) -#define OF_DECLARE_2(table, name, compat, fn) \ - _OF_DECLARE(table, name, compat, fn, of_init_fn_2) - -/** - * struct of_changeset_entry - Holds a changeset entry - * - * @node: list_head for the log list - * @action: notifier action - * @np: pointer to the device node affected - * @prop: pointer to the property affected - * @old_prop: hold a pointer to the original property - * - * Every modification of the device tree during a changeset - * is held in a list of of_changeset_entry structures. - * That way we can recover from a partial application, or we can - * revert the changeset - */ -struct of_changeset_entry { - struct list_head node; - unsigned long action; - struct device_node *np; - struct property *prop; - struct property *old_prop; -}; - -/** - * struct of_changeset - changeset tracker structure - * - * @entries: list_head for the changeset entries - * - * changesets are a convenient way to apply bulk changes to the - * live tree. In case of an error, changes are rolled-back. - * changesets live on after initial application, and if not - * destroyed after use, they can be reverted in one single call. - */ -struct of_changeset { - struct list_head entries; -}; - -enum of_reconfig_change { - OF_RECONFIG_NO_CHANGE = 0, - OF_RECONFIG_CHANGE_ADD, - OF_RECONFIG_CHANGE_REMOVE, -}; - -#ifdef CONFIG_OF_DYNAMIC -extern int of_reconfig_notifier_register(struct notifier_block *); -extern int of_reconfig_notifier_unregister(struct notifier_block *); -extern int of_reconfig_notify(unsigned long, struct of_reconfig_data *rd); -extern int of_reconfig_get_state_change(unsigned long action, - struct of_reconfig_data *arg); - -extern void of_changeset_init(struct of_changeset *ocs); -extern void of_changeset_destroy(struct of_changeset *ocs); -extern int of_changeset_apply(struct of_changeset *ocs); -extern int of_changeset_revert(struct of_changeset *ocs); -extern int of_changeset_action(struct of_changeset *ocs, - unsigned long action, struct device_node *np, - struct property *prop); - -static inline int of_changeset_attach_node(struct of_changeset *ocs, - struct device_node *np) -{ - return of_changeset_action(ocs, OF_RECONFIG_ATTACH_NODE, np, NULL); -} - -static inline int of_changeset_detach_node(struct of_changeset *ocs, - struct device_node *np) -{ - return of_changeset_action(ocs, OF_RECONFIG_DETACH_NODE, np, NULL); -} - -static inline int of_changeset_add_property(struct of_changeset *ocs, - struct device_node *np, struct property *prop) -{ - return of_changeset_action(ocs, OF_RECONFIG_ADD_PROPERTY, np, prop); -} - -static inline int of_changeset_remove_property(struct of_changeset *ocs, - struct device_node *np, struct property *prop) -{ - return of_changeset_action(ocs, OF_RECONFIG_REMOVE_PROPERTY, np, prop); -} - -static inline int of_changeset_update_property(struct of_changeset *ocs, - struct device_node *np, struct property *prop) -{ - return of_changeset_action(ocs, OF_RECONFIG_UPDATE_PROPERTY, np, prop); -} -#else /* CONFIG_OF_DYNAMIC */ -static inline int of_reconfig_notifier_register(struct notifier_block *nb) -{ - return -EINVAL; -} -static inline int of_reconfig_notifier_unregister(struct notifier_block *nb) -{ - return -EINVAL; -} -static inline int of_reconfig_notify(unsigned long action, - struct of_reconfig_data *arg) -{ - return -EINVAL; -} -static inline int of_reconfig_get_state_change(unsigned long action, - struct of_reconfig_data *arg) -{ - return -EINVAL; -} -#endif /* CONFIG_OF_DYNAMIC */ - -/* CONFIG_OF_RESOLVE api */ -extern int of_resolve_phandles(struct device_node *tree); - -/** - * of_device_is_system_power_controller - Tells if system-power-controller is found for device_node - * @np: Pointer to the given device_node - * - * return true if present false otherwise - */ -static inline bool of_device_is_system_power_controller(const struct device_node *np) -{ - return of_property_read_bool(np, "system-power-controller"); -} - -/** - * Overlay support - */ - -#ifdef CONFIG_OF_OVERLAY - -/* ID based overlays; the API for external users */ -int of_overlay_create(struct device_node *tree); -int of_overlay_destroy(int id); -int of_overlay_destroy_all(void); - -#else - -static inline int of_overlay_create(struct device_node *tree) -{ - return -ENOTSUPP; -} - -static inline int of_overlay_destroy(int id) -{ - return -ENOTSUPP; -} - -static inline int of_overlay_destroy_all(void) -{ - return -ENOTSUPP; -} - -#endif - -#endif /* _LINUX_OF_H */ diff --git a/src/linux/include/linux/of_address.h b/src/linux/include/linux/of_address.h deleted file mode 100644 index 3786473..0000000 --- a/src/linux/include/linux/of_address.h +++ /dev/null @@ -1,156 +0,0 @@ -#ifndef __OF_ADDRESS_H -#define __OF_ADDRESS_H -#include -#include -#include -#include - -struct of_pci_range_parser { - struct device_node *node; - const __be32 *range; - const __be32 *end; - int np; - int pna; -}; - -struct of_pci_range { - u32 pci_space; - u64 pci_addr; - u64 cpu_addr; - u64 size; - u32 flags; -}; - -#define for_each_of_pci_range(parser, range) \ - for (; of_pci_range_parser_one(parser, range);) - -/* Translate a DMA address from device space to CPU space */ -extern u64 of_translate_dma_address(struct device_node *dev, - const __be32 *in_addr); - -#ifdef CONFIG_OF_ADDRESS -extern u64 of_translate_address(struct device_node *np, const __be32 *addr); -extern int of_address_to_resource(struct device_node *dev, int index, - struct resource *r); -extern struct device_node *of_find_matching_node_by_address( - struct device_node *from, - const struct of_device_id *matches, - u64 base_address); -extern void __iomem *of_iomap(struct device_node *device, int index); -void __iomem *of_io_request_and_map(struct device_node *device, - int index, const char *name); - -/* Extract an address from a device, returns the region size and - * the address space flags too. The PCI version uses a BAR number - * instead of an absolute index - */ -extern const __be32 *of_get_address(struct device_node *dev, int index, - u64 *size, unsigned int *flags); - -extern int of_pci_range_parser_init(struct of_pci_range_parser *parser, - struct device_node *node); -extern struct of_pci_range *of_pci_range_parser_one( - struct of_pci_range_parser *parser, - struct of_pci_range *range); -extern int of_dma_get_range(struct device_node *np, u64 *dma_addr, - u64 *paddr, u64 *size); -extern bool of_dma_is_coherent(struct device_node *np); -#else /* CONFIG_OF_ADDRESS */ -static inline void __iomem *of_io_request_and_map(struct device_node *device, - int index, const char *name) -{ - return IOMEM_ERR_PTR(-EINVAL); -} - -static inline u64 of_translate_address(struct device_node *np, - const __be32 *addr) -{ - return OF_BAD_ADDR; -} - -static inline struct device_node *of_find_matching_node_by_address( - struct device_node *from, - const struct of_device_id *matches, - u64 base_address) -{ - return NULL; -} - -static inline const __be32 *of_get_address(struct device_node *dev, int index, - u64 *size, unsigned int *flags) -{ - return NULL; -} - -static inline int of_pci_range_parser_init(struct of_pci_range_parser *parser, - struct device_node *node) -{ - return -1; -} - -static inline struct of_pci_range *of_pci_range_parser_one( - struct of_pci_range_parser *parser, - struct of_pci_range *range) -{ - return NULL; -} - -static inline int of_dma_get_range(struct device_node *np, u64 *dma_addr, - u64 *paddr, u64 *size) -{ - return -ENODEV; -} - -static inline bool of_dma_is_coherent(struct device_node *np) -{ - return false; -} -#endif /* CONFIG_OF_ADDRESS */ - -#ifdef CONFIG_OF -extern int of_address_to_resource(struct device_node *dev, int index, - struct resource *r); -void __iomem *of_iomap(struct device_node *node, int index); -#else -static inline int of_address_to_resource(struct device_node *dev, int index, - struct resource *r) -{ - return -EINVAL; -} - -static inline void __iomem *of_iomap(struct device_node *device, int index) -{ - return NULL; -} -#endif - -#if defined(CONFIG_OF_ADDRESS) && defined(CONFIG_PCI) -extern const __be32 *of_get_pci_address(struct device_node *dev, int bar_no, - u64 *size, unsigned int *flags); -extern int of_pci_address_to_resource(struct device_node *dev, int bar, - struct resource *r); -extern int of_pci_range_to_resource(struct of_pci_range *range, - struct device_node *np, - struct resource *res); -#else /* CONFIG_OF_ADDRESS && CONFIG_PCI */ -static inline int of_pci_address_to_resource(struct device_node *dev, int bar, - struct resource *r) -{ - return -ENOSYS; -} - -static inline const __be32 *of_get_pci_address(struct device_node *dev, - int bar_no, u64 *size, unsigned int *flags) -{ - return NULL; -} -static inline int of_pci_range_to_resource(struct of_pci_range *range, - struct device_node *np, - struct resource *res) -{ - return -ENOSYS; -} -#endif /* CONFIG_OF_ADDRESS && CONFIG_PCI */ - -#endif /* __OF_ADDRESS_H */ - diff --git a/src/linux/include/linux/of_device.h b/src/linux/include/linux/of_device.h deleted file mode 100644 index cc7dd68..0000000 --- a/src/linux/include/linux/of_device.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef _LINUX_OF_DEVICE_H -#define _LINUX_OF_DEVICE_H - -#include -#include -#include /* temporary until merge */ - -#include -#include - -struct device; - -#ifdef CONFIG_OF -extern const struct of_device_id *of_match_device( - const struct of_device_id *matches, const struct device *dev); -extern void of_device_make_bus_id(struct device *dev); - -/** - * of_driver_match_device - Tell if a driver's of_match_table matches a device. - * @drv: the device_driver structure to test - * @dev: the device structure to match against - */ -static inline int of_driver_match_device(struct device *dev, - const struct device_driver *drv) -{ - return of_match_device(drv->of_match_table, dev) != NULL; -} - -extern struct platform_device *of_dev_get(struct platform_device *dev); -extern void of_dev_put(struct platform_device *dev); - -extern int of_device_add(struct platform_device *pdev); -extern int of_device_register(struct platform_device *ofdev); -extern void of_device_unregister(struct platform_device *ofdev); - -extern const void *of_device_get_match_data(const struct device *dev); - -extern ssize_t of_device_get_modalias(struct device *dev, - char *str, ssize_t len); - -extern void of_device_uevent(struct device *dev, struct kobj_uevent_env *env); -extern int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env); - -static inline void of_device_node_put(struct device *dev) -{ - of_node_put(dev->of_node); -} - -static inline struct device_node *of_cpu_device_node_get(int cpu) -{ - struct device *cpu_dev; - cpu_dev = get_cpu_device(cpu); - if (!cpu_dev) - return NULL; - return of_node_get(cpu_dev->of_node); -} - -void of_dma_configure(struct device *dev, struct device_node *np); -#else /* CONFIG_OF */ - -static inline int of_driver_match_device(struct device *dev, - const struct device_driver *drv) -{ - return 0; -} - -static inline void of_device_uevent(struct device *dev, - struct kobj_uevent_env *env) { } - -static inline const void *of_device_get_match_data(const struct device *dev) -{ - return NULL; -} - -static inline int of_device_get_modalias(struct device *dev, - char *str, ssize_t len) -{ - return -ENODEV; -} - -static inline int of_device_uevent_modalias(struct device *dev, - struct kobj_uevent_env *env) -{ - return -ENODEV; -} - -static inline void of_device_node_put(struct device *dev) { } - -static inline const struct of_device_id *__of_match_device( - const struct of_device_id *matches, const struct device *dev) -{ - return NULL; -} -#define of_match_device(matches, dev) \ - __of_match_device(of_match_ptr(matches), (dev)) - -static inline struct device_node *of_cpu_device_node_get(int cpu) -{ - return NULL; -} -static inline void of_dma_configure(struct device *dev, struct device_node *np) -{} -#endif /* CONFIG_OF */ - -#endif /* _LINUX_OF_DEVICE_H */ diff --git a/src/linux/include/linux/of_irq.h b/src/linux/include/linux/of_irq.h deleted file mode 100644 index 1e0deb8..0000000 --- a/src/linux/include/linux/of_irq.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef __OF_IRQ_H -#define __OF_IRQ_H - -#include -#include -#include -#include -#include -#include - -typedef int (*of_irq_init_cb_t)(struct device_node *, struct device_node *); - -/* - * Workarounds only applied to 32bit powermac machines - */ -#define OF_IMAP_OLDWORLD_MAC 0x00000001 -#define OF_IMAP_NO_PHANDLE 0x00000002 - -#if defined(CONFIG_PPC32) && defined(CONFIG_PPC_PMAC) -extern unsigned int of_irq_workarounds; -extern struct device_node *of_irq_dflt_pic; -extern int of_irq_parse_oldworld(struct device_node *device, int index, - struct of_phandle_args *out_irq); -#else /* CONFIG_PPC32 && CONFIG_PPC_PMAC */ -#define of_irq_workarounds (0) -#define of_irq_dflt_pic (NULL) -static inline int of_irq_parse_oldworld(struct device_node *device, int index, - struct of_phandle_args *out_irq) -{ - return -EINVAL; -} -#endif /* CONFIG_PPC32 && CONFIG_PPC_PMAC */ - -extern int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq); -extern int of_irq_parse_one(struct device_node *device, int index, - struct of_phandle_args *out_irq); -extern unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data); -extern int of_irq_to_resource(struct device_node *dev, int index, - struct resource *r); - -extern void of_irq_init(const struct of_device_id *matches); - -#ifdef CONFIG_OF_IRQ -extern int of_irq_count(struct device_node *dev); -extern int of_irq_get(struct device_node *dev, int index); -extern int of_irq_get_byname(struct device_node *dev, const char *name); -extern int of_irq_to_resource_table(struct device_node *dev, - struct resource *res, int nr_irqs); -extern struct device_node *of_irq_find_parent(struct device_node *child); -extern struct irq_domain *of_msi_get_domain(struct device *dev, - struct device_node *np, - enum irq_domain_bus_token token); -extern struct irq_domain *of_msi_map_get_device_domain(struct device *dev, - u32 rid); -extern void of_msi_configure(struct device *dev, struct device_node *np); -u32 of_msi_map_rid(struct device *dev, struct device_node *msi_np, u32 rid_in); -#else -static inline int of_irq_count(struct device_node *dev) -{ - return 0; -} -static inline int of_irq_get(struct device_node *dev, int index) -{ - return 0; -} -static inline int of_irq_get_byname(struct device_node *dev, const char *name) -{ - return 0; -} -static inline int of_irq_to_resource_table(struct device_node *dev, - struct resource *res, int nr_irqs) -{ - return 0; -} -static inline void *of_irq_find_parent(struct device_node *child) -{ - return NULL; -} - -static inline struct irq_domain *of_msi_get_domain(struct device *dev, - struct device_node *np, - enum irq_domain_bus_token token) -{ - return NULL; -} -static inline struct irq_domain *of_msi_map_get_device_domain(struct device *dev, - u32 rid) -{ - return NULL; -} -static inline void of_msi_configure(struct device *dev, struct device_node *np) -{ -} -static inline u32 of_msi_map_rid(struct device *dev, - struct device_node *msi_np, u32 rid_in) -{ - return rid_in; -} -#endif - -#if defined(CONFIG_OF_IRQ) || defined(CONFIG_SPARC) -/* - * irq_of_parse_and_map() is used by all OF enabled platforms; but SPARC - * implements it differently. However, the prototype is the same for all, - * so declare it here regardless of the CONFIG_OF_IRQ setting. - */ -extern unsigned int irq_of_parse_and_map(struct device_node *node, int index); - -#else /* !CONFIG_OF && !CONFIG_SPARC */ -static inline unsigned int irq_of_parse_and_map(struct device_node *dev, - int index) -{ - return 0; -} -#endif /* !CONFIG_OF */ - -#endif /* __OF_IRQ_H */ diff --git a/src/linux/include/linux/of_net.h b/src/linux/include/linux/of_net.h deleted file mode 100644 index 9cd72aa..0000000 --- a/src/linux/include/linux/of_net.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * OF helpers for network devices. - * - * This file is released under the GPLv2 - */ - -#ifndef __LINUX_OF_NET_H -#define __LINUX_OF_NET_H - -#ifdef CONFIG_OF_NET -#include - -struct net_device; -extern int of_get_phy_mode(struct device_node *np); -extern const void *of_get_mac_address(struct device_node *np); -extern struct net_device *of_find_net_device_by_node(struct device_node *np); -#else -static inline int of_get_phy_mode(struct device_node *np) -{ - return -ENODEV; -} - -static inline const void *of_get_mac_address(struct device_node *np) -{ - return NULL; -} - -static inline struct net_device *of_find_net_device_by_node(struct device_node *np) -{ - return NULL; -} -#endif - -#endif /* __LINUX_OF_NET_H */ diff --git a/src/linux/include/linux/of_platform.h b/src/linux/include/linux/of_platform.h deleted file mode 100644 index 956a100..0000000 --- a/src/linux/include/linux/of_platform.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef _LINUX_OF_PLATFORM_H -#define _LINUX_OF_PLATFORM_H -/* - * Copyright (C) 2006 Benjamin Herrenschmidt, IBM Corp. - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include - -/** - * struct of_dev_auxdata - lookup table entry for device names & platform_data - * @compatible: compatible value of node to match against node - * @phys_addr: Start address of registers to match against node - * @name: Name to assign for matching nodes - * @platform_data: platform_data to assign for matching nodes - * - * This lookup table allows the caller of of_platform_populate() to override - * the names of devices when creating devices from the device tree. The table - * should be terminated with an empty entry. It also allows the platform_data - * pointer to be set. - * - * The reason for this functionality is that some Linux infrastructure uses - * the device name to look up a specific device, but the Linux-specific names - * are not encoded into the device tree, so the kernel needs to provide specific - * values. - * - * Note: Using an auxdata lookup table should be considered a last resort when - * converting a platform to use the DT. Normally the automatically generated - * device name will not matter, and drivers should obtain data from the device - * node instead of from an anonymous platform_data pointer. - */ -struct of_dev_auxdata { - char *compatible; - resource_size_t phys_addr; - char *name; - void *platform_data; -}; - -/* Macro to simplify populating a lookup table */ -#define OF_DEV_AUXDATA(_compat,_phys,_name,_pdata) \ - { .compatible = _compat, .phys_addr = _phys, .name = _name, \ - .platform_data = _pdata } - -extern const struct of_device_id of_default_bus_match_table[]; - -/* Platform drivers register/unregister */ -extern struct platform_device *of_device_alloc(struct device_node *np, - const char *bus_id, - struct device *parent); -extern struct platform_device *of_find_device_by_node(struct device_node *np); - -/* Platform devices and busses creation */ -extern struct platform_device *of_platform_device_create(struct device_node *np, - const char *bus_id, - struct device *parent); - -extern int of_platform_bus_probe(struct device_node *root, - const struct of_device_id *matches, - struct device *parent); -#ifdef CONFIG_OF_ADDRESS -extern int of_platform_populate(struct device_node *root, - const struct of_device_id *matches, - const struct of_dev_auxdata *lookup, - struct device *parent); -extern int of_platform_default_populate(struct device_node *root, - const struct of_dev_auxdata *lookup, - struct device *parent); -extern void of_platform_depopulate(struct device *parent); -#else -static inline int of_platform_populate(struct device_node *root, - const struct of_device_id *matches, - const struct of_dev_auxdata *lookup, - struct device *parent) -{ - return -ENODEV; -} -static inline int of_platform_default_populate(struct device_node *root, - const struct of_dev_auxdata *lookup, - struct device *parent) -{ - return -ENODEV; -} -static inline void of_platform_depopulate(struct device *parent) { } -#endif - -#if defined(CONFIG_OF_DYNAMIC) && defined(CONFIG_OF_ADDRESS) -extern void of_platform_register_reconfig_notifier(void); -#else -static inline void of_platform_register_reconfig_notifier(void) { } -#endif - -#endif /* _LINUX_OF_PLATFORM_H */ diff --git a/src/linux/include/linux/once.h b/src/linux/include/linux/once.h deleted file mode 100644 index 285f12c..0000000 --- a/src/linux/include/linux/once.h +++ /dev/null @@ -1,57 +0,0 @@ -#ifndef _LINUX_ONCE_H -#define _LINUX_ONCE_H - -#include -#include - -bool __do_once_start(bool *done, unsigned long *flags); -void __do_once_done(bool *done, struct static_key *once_key, - unsigned long *flags); - -/* Call a function exactly once. The idea of DO_ONCE() is to perform - * a function call such as initialization of random seeds, etc, only - * once, where DO_ONCE() can live in the fast-path. After @func has - * been called with the passed arguments, the static key will patch - * out the condition into a nop. DO_ONCE() guarantees type safety of - * arguments! - * - * Not that the following is not equivalent ... - * - * DO_ONCE(func, arg); - * DO_ONCE(func, arg); - * - * ... to this version: - * - * void foo(void) - * { - * DO_ONCE(func, arg); - * } - * - * foo(); - * foo(); - * - * In case the one-time invocation could be triggered from multiple - * places, then a common helper function must be defined, so that only - * a single static key will be placed there! - */ -#define DO_ONCE(func, ...) \ - ({ \ - bool ___ret = false; \ - static bool ___done = false; \ - static struct static_key ___once_key = STATIC_KEY_INIT_TRUE; \ - if (static_key_true(&___once_key)) { \ - unsigned long ___flags; \ - ___ret = __do_once_start(&___done, &___flags); \ - if (unlikely(___ret)) { \ - func(__VA_ARGS__); \ - __do_once_done(&___done, &___once_key, \ - &___flags); \ - } \ - } \ - ___ret; \ - }) - -#define get_random_once(buf, nbytes) \ - DO_ONCE(get_random_bytes, (buf), (nbytes)) - -#endif /* _LINUX_ONCE_H */ diff --git a/src/linux/include/linux/oom.h b/src/linux/include/linux/oom.h deleted file mode 100644 index b4e36e9..0000000 --- a/src/linux/include/linux/oom.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef __INCLUDE_LINUX_OOM_H -#define __INCLUDE_LINUX_OOM_H - - -#include -#include -#include -#include - -struct zonelist; -struct notifier_block; -struct mem_cgroup; -struct task_struct; - -/* - * Details of the page allocation that triggered the oom killer that are used to - * determine what should be killed. - */ -struct oom_control { - /* Used to determine cpuset */ - struct zonelist *zonelist; - - /* Used to determine mempolicy */ - nodemask_t *nodemask; - - /* Memory cgroup in which oom is invoked, or NULL for global oom */ - struct mem_cgroup *memcg; - - /* Used to determine cpuset and node locality requirement */ - const gfp_t gfp_mask; - - /* - * order == -1 means the oom kill is required by sysrq, otherwise only - * for display purposes. - */ - const int order; - - /* Used by oom implementation, do not set */ - unsigned long totalpages; - struct task_struct *chosen; - unsigned long chosen_points; -}; - -extern struct mutex oom_lock; - -static inline void set_current_oom_origin(void) -{ - current->signal->oom_flag_origin = true; -} - -static inline void clear_current_oom_origin(void) -{ - current->signal->oom_flag_origin = false; -} - -static inline bool oom_task_origin(const struct task_struct *p) -{ - return p->signal->oom_flag_origin; -} - -static inline bool tsk_is_oom_victim(struct task_struct * tsk) -{ - return tsk->signal->oom_mm; -} - -extern unsigned long oom_badness(struct task_struct *p, - struct mem_cgroup *memcg, const nodemask_t *nodemask, - unsigned long totalpages); - -extern bool out_of_memory(struct oom_control *oc); - -extern void exit_oom_victim(void); - -extern int register_oom_notifier(struct notifier_block *nb); -extern int unregister_oom_notifier(struct notifier_block *nb); - -extern bool oom_killer_disable(signed long timeout); -extern void oom_killer_enable(void); - -extern struct task_struct *find_lock_task_mm(struct task_struct *p); - -/* sysctls */ -extern int sysctl_oom_dump_tasks; -extern int sysctl_oom_kill_allocating_task; -extern int sysctl_panic_on_oom; -#endif /* _INCLUDE_LINUX_OOM_H */ diff --git a/src/linux/include/linux/osq_lock.h b/src/linux/include/linux/osq_lock.h deleted file mode 100644 index 703ea5c..0000000 --- a/src/linux/include/linux/osq_lock.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef __LINUX_OSQ_LOCK_H -#define __LINUX_OSQ_LOCK_H - -/* - * An MCS like lock especially tailored for optimistic spinning for sleeping - * lock implementations (mutex, rwsem, etc). - */ -struct optimistic_spin_node { - struct optimistic_spin_node *next, *prev; - int locked; /* 1 if lock acquired */ - int cpu; /* encoded CPU # + 1 value */ -}; - -struct optimistic_spin_queue { - /* - * Stores an encoded value of the CPU # of the tail node in the queue. - * If the queue is empty, then it's set to OSQ_UNLOCKED_VAL. - */ - atomic_t tail; -}; - -#define OSQ_UNLOCKED_VAL (0) - -/* Init macro and function. */ -#define OSQ_LOCK_UNLOCKED { ATOMIC_INIT(OSQ_UNLOCKED_VAL) } - -static inline void osq_lock_init(struct optimistic_spin_queue *lock) -{ - atomic_set(&lock->tail, OSQ_UNLOCKED_VAL); -} - -extern bool osq_lock(struct optimistic_spin_queue *lock); -extern void osq_unlock(struct optimistic_spin_queue *lock); - -static inline bool osq_is_locked(struct optimistic_spin_queue *lock) -{ - return atomic_read(&lock->tail) != OSQ_UNLOCKED_VAL; -} - -#endif diff --git a/src/linux/include/linux/page-flags-layout.h b/src/linux/include/linux/page-flags-layout.h deleted file mode 100644 index 77b078c..0000000 --- a/src/linux/include/linux/page-flags-layout.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef PAGE_FLAGS_LAYOUT_H -#define PAGE_FLAGS_LAYOUT_H - -#include -#include - -/* - * When a memory allocation must conform to specific limitations (such - * as being suitable for DMA) the caller will pass in hints to the - * allocator in the gfp_mask, in the zone modifier bits. These bits - * are used to select a priority ordered list of memory zones which - * match the requested limits. See gfp_zone() in include/linux/gfp.h - */ -#if MAX_NR_ZONES < 2 -#define ZONES_SHIFT 0 -#elif MAX_NR_ZONES <= 2 -#define ZONES_SHIFT 1 -#elif MAX_NR_ZONES <= 4 -#define ZONES_SHIFT 2 -#elif MAX_NR_ZONES <= 8 -#define ZONES_SHIFT 3 -#else -#error ZONES_SHIFT -- too many zones configured adjust calculation -#endif - -#ifdef CONFIG_SPARSEMEM -#include - -/* SECTION_SHIFT #bits space required to store a section # */ -#define SECTIONS_SHIFT (MAX_PHYSMEM_BITS - SECTION_SIZE_BITS) - -#endif /* CONFIG_SPARSEMEM */ - -/* - * page->flags layout: - * - * There are five possibilities for how page->flags get laid out. The first - * pair is for the normal case without sparsemem. The second pair is for - * sparsemem when there is plenty of space for node and section information. - * The last is when there is insufficient space in page->flags and a separate - * lookup is necessary. - * - * No sparsemem or sparsemem vmemmap: | NODE | ZONE | ... | FLAGS | - * " plus space for last_cpupid: | NODE | ZONE | LAST_CPUPID ... | FLAGS | - * classic sparse with space for node:| SECTION | NODE | ZONE | ... | FLAGS | - * " plus space for last_cpupid: | SECTION | NODE | ZONE | LAST_CPUPID ... | FLAGS | - * classic sparse no space for node: | SECTION | ZONE | ... | FLAGS | - */ -#if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP) -#define SECTIONS_WIDTH SECTIONS_SHIFT -#else -#define SECTIONS_WIDTH 0 -#endif - -#define ZONES_WIDTH ZONES_SHIFT - -#if SECTIONS_WIDTH+ZONES_WIDTH+NODES_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS -#define NODES_WIDTH NODES_SHIFT -#else -#ifdef CONFIG_SPARSEMEM_VMEMMAP -#error "Vmemmap: No space for nodes field in page flags" -#endif -#define NODES_WIDTH 0 -#endif - -#ifdef CONFIG_NUMA_BALANCING -#define LAST__PID_SHIFT 8 -#define LAST__PID_MASK ((1 << LAST__PID_SHIFT)-1) - -#define LAST__CPU_SHIFT NR_CPUS_BITS -#define LAST__CPU_MASK ((1 << LAST__CPU_SHIFT)-1) - -#define LAST_CPUPID_SHIFT (LAST__PID_SHIFT+LAST__CPU_SHIFT) -#else -#define LAST_CPUPID_SHIFT 0 -#endif - -#if SECTIONS_WIDTH+ZONES_WIDTH+NODES_SHIFT+LAST_CPUPID_SHIFT <= BITS_PER_LONG - NR_PAGEFLAGS -#define LAST_CPUPID_WIDTH LAST_CPUPID_SHIFT -#else -#define LAST_CPUPID_WIDTH 0 -#endif - -/* - * We are going to use the flags for the page to node mapping if its in - * there. This includes the case where there is no node, so it is implicit. - */ -#if !(NODES_WIDTH > 0 || NODES_SHIFT == 0) -#define NODE_NOT_IN_PAGE_FLAGS -#endif - -#if defined(CONFIG_NUMA_BALANCING) && LAST_CPUPID_WIDTH == 0 -#define LAST_CPUPID_NOT_IN_PAGE_FLAGS -#endif - -#endif /* _LINUX_PAGE_FLAGS_LAYOUT */ diff --git a/src/linux/include/linux/page-flags.h b/src/linux/include/linux/page-flags.h deleted file mode 100644 index 74e4dda..0000000 --- a/src/linux/include/linux/page-flags.h +++ /dev/null @@ -1,742 +0,0 @@ -/* - * Macros for manipulating and testing page->flags - */ - -#ifndef PAGE_FLAGS_H -#define PAGE_FLAGS_H - -#include -#include -#include -#ifndef __GENERATING_BOUNDS_H -#include -#include -#endif /* !__GENERATING_BOUNDS_H */ - -/* - * Various page->flags bits: - * - * PG_reserved is set for special pages, which can never be swapped out. Some - * of them might not even exist (eg empty_bad_page)... - * - * The PG_private bitflag is set on pagecache pages if they contain filesystem - * specific data (which is normally at page->private). It can be used by - * private allocations for its own usage. - * - * During initiation of disk I/O, PG_locked is set. This bit is set before I/O - * and cleared when writeback _starts_ or when read _completes_. PG_writeback - * is set before writeback starts and cleared when it finishes. - * - * PG_locked also pins a page in pagecache, and blocks truncation of the file - * while it is held. - * - * page_waitqueue(page) is a wait queue of all tasks waiting for the page - * to become unlocked. - * - * PG_uptodate tells whether the page's contents is valid. When a read - * completes, the page becomes uptodate, unless a disk I/O error happened. - * - * PG_referenced, PG_reclaim are used for page reclaim for anonymous and - * file-backed pagecache (see mm/vmscan.c). - * - * PG_error is set to indicate that an I/O error occurred on this page. - * - * PG_arch_1 is an architecture specific page state bit. The generic code - * guarantees that this bit is cleared for a page when it first is entered into - * the page cache. - * - * PG_highmem pages are not permanently mapped into the kernel virtual address - * space, they need to be kmapped separately for doing IO on the pages. The - * struct page (these bits with information) are always mapped into kernel - * address space... - * - * PG_hwpoison indicates that a page got corrupted in hardware and contains - * data with incorrect ECC bits that triggered a machine check. Accessing is - * not safe since it may cause another machine check. Don't touch! - */ - -/* - * Don't use the *_dontuse flags. Use the macros. Otherwise you'll break - * locked- and dirty-page accounting. - * - * The page flags field is split into two parts, the main flags area - * which extends from the low bits upwards, and the fields area which - * extends from the high bits downwards. - * - * | FIELD | ... | FLAGS | - * N-1 ^ 0 - * (NR_PAGEFLAGS) - * - * The fields area is reserved for fields mapping zone, node (for NUMA) and - * SPARSEMEM section (for variants of SPARSEMEM that require section ids like - * SPARSEMEM_EXTREME with !SPARSEMEM_VMEMMAP). - */ -enum pageflags { - PG_locked, /* Page is locked. Don't touch. */ - PG_error, - PG_referenced, - PG_uptodate, - PG_dirty, - PG_lru, - PG_active, - PG_slab, - PG_owner_priv_1, /* Owner use. If pagecache, fs may use*/ - PG_arch_1, - PG_reserved, - PG_private, /* If pagecache, has fs-private data */ - PG_private_2, /* If pagecache, has fs aux data */ - PG_writeback, /* Page is under writeback */ - PG_head, /* A head page */ - PG_swapcache, /* Swap page: swp_entry_t in private */ - PG_mappedtodisk, /* Has blocks allocated on-disk */ - PG_reclaim, /* To be reclaimed asap */ - PG_swapbacked, /* Page is backed by RAM/swap */ - PG_unevictable, /* Page is "unevictable" */ -#ifdef CONFIG_MMU - PG_mlocked, /* Page is vma mlocked */ -#endif -#ifdef CONFIG_ARCH_USES_PG_UNCACHED - PG_uncached, /* Page has been mapped as uncached */ -#endif -#ifdef CONFIG_MEMORY_FAILURE - PG_hwpoison, /* hardware poisoned page. Don't touch */ -#endif -#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) - PG_young, - PG_idle, -#endif - __NR_PAGEFLAGS, - - /* Filesystems */ - PG_checked = PG_owner_priv_1, - - /* Two page bits are conscripted by FS-Cache to maintain local caching - * state. These bits are set on pages belonging to the netfs's inodes - * when those inodes are being locally cached. - */ - PG_fscache = PG_private_2, /* page backed by cache */ - - /* XEN */ - /* Pinned in Xen as a read-only pagetable page. */ - PG_pinned = PG_owner_priv_1, - /* Pinned as part of domain save (see xen_mm_pin_all()). */ - PG_savepinned = PG_dirty, - /* Has a grant mapping of another (foreign) domain's page. */ - PG_foreign = PG_owner_priv_1, - - /* SLOB */ - PG_slob_free = PG_private, - - /* Compound pages. Stored in first tail page's flags */ - PG_double_map = PG_private_2, - - /* non-lru isolated movable page */ - PG_isolated = PG_reclaim, -}; - -#ifndef __GENERATING_BOUNDS_H - -struct page; /* forward declaration */ - -static inline struct page *compound_head(struct page *page) -{ - unsigned long head = READ_ONCE(page->compound_head); - - if (unlikely(head & 1)) - return (struct page *) (head - 1); - return page; -} - -static __always_inline int PageTail(struct page *page) -{ - return READ_ONCE(page->compound_head) & 1; -} - -static __always_inline int PageCompound(struct page *page) -{ - return test_bit(PG_head, &page->flags) || PageTail(page); -} - -/* - * Page flags policies wrt compound pages - * - * PF_ANY: - * the page flag is relevant for small, head and tail pages. - * - * PF_HEAD: - * for compound page all operations related to the page flag applied to - * head page. - * - * PF_NO_TAIL: - * modifications of the page flag must be done on small or head pages, - * checks can be done on tail pages too. - * - * PF_NO_COMPOUND: - * the page flag is not relevant for compound pages. - */ -#define PF_ANY(page, enforce) page -#define PF_HEAD(page, enforce) compound_head(page) -#define PF_NO_TAIL(page, enforce) ({ \ - VM_BUG_ON_PGFLAGS(enforce && PageTail(page), page); \ - compound_head(page);}) -#define PF_NO_COMPOUND(page, enforce) ({ \ - VM_BUG_ON_PGFLAGS(enforce && PageCompound(page), page); \ - page;}) - -/* - * Macros to create function definitions for page flags - */ -#define TESTPAGEFLAG(uname, lname, policy) \ -static __always_inline int Page##uname(struct page *page) \ - { return test_bit(PG_##lname, &policy(page, 0)->flags); } - -#define SETPAGEFLAG(uname, lname, policy) \ -static __always_inline void SetPage##uname(struct page *page) \ - { set_bit(PG_##lname, &policy(page, 1)->flags); } - -#define CLEARPAGEFLAG(uname, lname, policy) \ -static __always_inline void ClearPage##uname(struct page *page) \ - { clear_bit(PG_##lname, &policy(page, 1)->flags); } - -#define __SETPAGEFLAG(uname, lname, policy) \ -static __always_inline void __SetPage##uname(struct page *page) \ - { __set_bit(PG_##lname, &policy(page, 1)->flags); } - -#define __CLEARPAGEFLAG(uname, lname, policy) \ -static __always_inline void __ClearPage##uname(struct page *page) \ - { __clear_bit(PG_##lname, &policy(page, 1)->flags); } - -#define TESTSETFLAG(uname, lname, policy) \ -static __always_inline int TestSetPage##uname(struct page *page) \ - { return test_and_set_bit(PG_##lname, &policy(page, 1)->flags); } - -#define TESTCLEARFLAG(uname, lname, policy) \ -static __always_inline int TestClearPage##uname(struct page *page) \ - { return test_and_clear_bit(PG_##lname, &policy(page, 1)->flags); } - -#define PAGEFLAG(uname, lname, policy) \ - TESTPAGEFLAG(uname, lname, policy) \ - SETPAGEFLAG(uname, lname, policy) \ - CLEARPAGEFLAG(uname, lname, policy) - -#define __PAGEFLAG(uname, lname, policy) \ - TESTPAGEFLAG(uname, lname, policy) \ - __SETPAGEFLAG(uname, lname, policy) \ - __CLEARPAGEFLAG(uname, lname, policy) - -#define TESTSCFLAG(uname, lname, policy) \ - TESTSETFLAG(uname, lname, policy) \ - TESTCLEARFLAG(uname, lname, policy) - -#define TESTPAGEFLAG_FALSE(uname) \ -static inline int Page##uname(const struct page *page) { return 0; } - -#define SETPAGEFLAG_NOOP(uname) \ -static inline void SetPage##uname(struct page *page) { } - -#define CLEARPAGEFLAG_NOOP(uname) \ -static inline void ClearPage##uname(struct page *page) { } - -#define __CLEARPAGEFLAG_NOOP(uname) \ -static inline void __ClearPage##uname(struct page *page) { } - -#define TESTSETFLAG_FALSE(uname) \ -static inline int TestSetPage##uname(struct page *page) { return 0; } - -#define TESTCLEARFLAG_FALSE(uname) \ -static inline int TestClearPage##uname(struct page *page) { return 0; } - -#define PAGEFLAG_FALSE(uname) TESTPAGEFLAG_FALSE(uname) \ - SETPAGEFLAG_NOOP(uname) CLEARPAGEFLAG_NOOP(uname) - -#define TESTSCFLAG_FALSE(uname) \ - TESTSETFLAG_FALSE(uname) TESTCLEARFLAG_FALSE(uname) - -__PAGEFLAG(Locked, locked, PF_NO_TAIL) -PAGEFLAG(Error, error, PF_NO_COMPOUND) TESTCLEARFLAG(Error, error, PF_NO_COMPOUND) -PAGEFLAG(Referenced, referenced, PF_HEAD) - TESTCLEARFLAG(Referenced, referenced, PF_HEAD) - __SETPAGEFLAG(Referenced, referenced, PF_HEAD) -PAGEFLAG(Dirty, dirty, PF_HEAD) TESTSCFLAG(Dirty, dirty, PF_HEAD) - __CLEARPAGEFLAG(Dirty, dirty, PF_HEAD) -PAGEFLAG(LRU, lru, PF_HEAD) __CLEARPAGEFLAG(LRU, lru, PF_HEAD) -PAGEFLAG(Active, active, PF_HEAD) __CLEARPAGEFLAG(Active, active, PF_HEAD) - TESTCLEARFLAG(Active, active, PF_HEAD) -__PAGEFLAG(Slab, slab, PF_NO_TAIL) -__PAGEFLAG(SlobFree, slob_free, PF_NO_TAIL) -PAGEFLAG(Checked, checked, PF_NO_COMPOUND) /* Used by some filesystems */ - -/* Xen */ -PAGEFLAG(Pinned, pinned, PF_NO_COMPOUND) - TESTSCFLAG(Pinned, pinned, PF_NO_COMPOUND) -PAGEFLAG(SavePinned, savepinned, PF_NO_COMPOUND); -PAGEFLAG(Foreign, foreign, PF_NO_COMPOUND); - -PAGEFLAG(Reserved, reserved, PF_NO_COMPOUND) - __CLEARPAGEFLAG(Reserved, reserved, PF_NO_COMPOUND) -PAGEFLAG(SwapBacked, swapbacked, PF_NO_TAIL) - __CLEARPAGEFLAG(SwapBacked, swapbacked, PF_NO_TAIL) - __SETPAGEFLAG(SwapBacked, swapbacked, PF_NO_TAIL) - -/* - * Private page markings that may be used by the filesystem that owns the page - * for its own purposes. - * - PG_private and PG_private_2 cause releasepage() and co to be invoked - */ -PAGEFLAG(Private, private, PF_ANY) __SETPAGEFLAG(Private, private, PF_ANY) - __CLEARPAGEFLAG(Private, private, PF_ANY) -PAGEFLAG(Private2, private_2, PF_ANY) TESTSCFLAG(Private2, private_2, PF_ANY) -PAGEFLAG(OwnerPriv1, owner_priv_1, PF_ANY) - TESTCLEARFLAG(OwnerPriv1, owner_priv_1, PF_ANY) - -/* - * Only test-and-set exist for PG_writeback. The unconditional operators are - * risky: they bypass page accounting. - */ -TESTPAGEFLAG(Writeback, writeback, PF_NO_COMPOUND) - TESTSCFLAG(Writeback, writeback, PF_NO_COMPOUND) -PAGEFLAG(MappedToDisk, mappedtodisk, PF_NO_TAIL) - -/* PG_readahead is only used for reads; PG_reclaim is only for writes */ -PAGEFLAG(Reclaim, reclaim, PF_NO_TAIL) - TESTCLEARFLAG(Reclaim, reclaim, PF_NO_TAIL) -PAGEFLAG(Readahead, reclaim, PF_NO_COMPOUND) - TESTCLEARFLAG(Readahead, reclaim, PF_NO_COMPOUND) - -#ifdef CONFIG_HIGHMEM -/* - * Must use a macro here due to header dependency issues. page_zone() is not - * available at this point. - */ -#define PageHighMem(__p) is_highmem_idx(page_zonenum(__p)) -#else -PAGEFLAG_FALSE(HighMem) -#endif - -#ifdef CONFIG_SWAP -PAGEFLAG(SwapCache, swapcache, PF_NO_COMPOUND) -#else -PAGEFLAG_FALSE(SwapCache) -#endif - -PAGEFLAG(Unevictable, unevictable, PF_HEAD) - __CLEARPAGEFLAG(Unevictable, unevictable, PF_HEAD) - TESTCLEARFLAG(Unevictable, unevictable, PF_HEAD) - -#ifdef CONFIG_MMU -PAGEFLAG(Mlocked, mlocked, PF_NO_TAIL) - __CLEARPAGEFLAG(Mlocked, mlocked, PF_NO_TAIL) - TESTSCFLAG(Mlocked, mlocked, PF_NO_TAIL) -#else -PAGEFLAG_FALSE(Mlocked) __CLEARPAGEFLAG_NOOP(Mlocked) - TESTSCFLAG_FALSE(Mlocked) -#endif - -#ifdef CONFIG_ARCH_USES_PG_UNCACHED -PAGEFLAG(Uncached, uncached, PF_NO_COMPOUND) -#else -PAGEFLAG_FALSE(Uncached) -#endif - -#ifdef CONFIG_MEMORY_FAILURE -PAGEFLAG(HWPoison, hwpoison, PF_ANY) -TESTSCFLAG(HWPoison, hwpoison, PF_ANY) -#define __PG_HWPOISON (1UL << PG_hwpoison) -#else -PAGEFLAG_FALSE(HWPoison) -#define __PG_HWPOISON 0 -#endif - -#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) -TESTPAGEFLAG(Young, young, PF_ANY) -SETPAGEFLAG(Young, young, PF_ANY) -TESTCLEARFLAG(Young, young, PF_ANY) -PAGEFLAG(Idle, idle, PF_ANY) -#endif - -/* - * On an anonymous page mapped into a user virtual memory area, - * page->mapping points to its anon_vma, not to a struct address_space; - * with the PAGE_MAPPING_ANON bit set to distinguish it. See rmap.h. - * - * On an anonymous page in a VM_MERGEABLE area, if CONFIG_KSM is enabled, - * the PAGE_MAPPING_MOVABLE bit may be set along with the PAGE_MAPPING_ANON - * bit; and then page->mapping points, not to an anon_vma, but to a private - * structure which KSM associates with that merged page. See ksm.h. - * - * PAGE_MAPPING_KSM without PAGE_MAPPING_ANON is used for non-lru movable - * page and then page->mapping points a struct address_space. - * - * Please note that, confusingly, "page_mapping" refers to the inode - * address_space which maps the page from disk; whereas "page_mapped" - * refers to user virtual address space into which the page is mapped. - */ -#define PAGE_MAPPING_ANON 0x1 -#define PAGE_MAPPING_MOVABLE 0x2 -#define PAGE_MAPPING_KSM (PAGE_MAPPING_ANON | PAGE_MAPPING_MOVABLE) -#define PAGE_MAPPING_FLAGS (PAGE_MAPPING_ANON | PAGE_MAPPING_MOVABLE) - -static __always_inline int PageMappingFlags(struct page *page) -{ - return ((unsigned long)page->mapping & PAGE_MAPPING_FLAGS) != 0; -} - -static __always_inline int PageAnon(struct page *page) -{ - page = compound_head(page); - return ((unsigned long)page->mapping & PAGE_MAPPING_ANON) != 0; -} - -static __always_inline int __PageMovable(struct page *page) -{ - return ((unsigned long)page->mapping & PAGE_MAPPING_FLAGS) == - PAGE_MAPPING_MOVABLE; -} - -#ifdef CONFIG_KSM -/* - * A KSM page is one of those write-protected "shared pages" or "merged pages" - * which KSM maps into multiple mms, wherever identical anonymous page content - * is found in VM_MERGEABLE vmas. It's a PageAnon page, pointing not to any - * anon_vma, but to that page's node of the stable tree. - */ -static __always_inline int PageKsm(struct page *page) -{ - page = compound_head(page); - return ((unsigned long)page->mapping & PAGE_MAPPING_FLAGS) == - PAGE_MAPPING_KSM; -} -#else -TESTPAGEFLAG_FALSE(Ksm) -#endif - -u64 stable_page_flags(struct page *page); - -static inline int PageUptodate(struct page *page) -{ - int ret; - page = compound_head(page); - ret = test_bit(PG_uptodate, &(page)->flags); - /* - * Must ensure that the data we read out of the page is loaded - * _after_ we've loaded page->flags to check for PageUptodate. - * We can skip the barrier if the page is not uptodate, because - * we wouldn't be reading anything from it. - * - * See SetPageUptodate() for the other side of the story. - */ - if (ret) - smp_rmb(); - - return ret; -} - -static __always_inline void __SetPageUptodate(struct page *page) -{ - VM_BUG_ON_PAGE(PageTail(page), page); - smp_wmb(); - __set_bit(PG_uptodate, &page->flags); -} - -static __always_inline void SetPageUptodate(struct page *page) -{ - VM_BUG_ON_PAGE(PageTail(page), page); - /* - * Memory barrier must be issued before setting the PG_uptodate bit, - * so that all previous stores issued in order to bring the page - * uptodate are actually visible before PageUptodate becomes true. - */ - smp_wmb(); - set_bit(PG_uptodate, &page->flags); -} - -CLEARPAGEFLAG(Uptodate, uptodate, PF_NO_TAIL) - -int test_clear_page_writeback(struct page *page); -int __test_set_page_writeback(struct page *page, bool keep_write); - -#define test_set_page_writeback(page) \ - __test_set_page_writeback(page, false) -#define test_set_page_writeback_keepwrite(page) \ - __test_set_page_writeback(page, true) - -static inline void set_page_writeback(struct page *page) -{ - test_set_page_writeback(page); -} - -static inline void set_page_writeback_keepwrite(struct page *page) -{ - test_set_page_writeback_keepwrite(page); -} - -__PAGEFLAG(Head, head, PF_ANY) CLEARPAGEFLAG(Head, head, PF_ANY) - -static __always_inline void set_compound_head(struct page *page, struct page *head) -{ - WRITE_ONCE(page->compound_head, (unsigned long)head + 1); -} - -static __always_inline void clear_compound_head(struct page *page) -{ - WRITE_ONCE(page->compound_head, 0); -} - -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -static inline void ClearPageCompound(struct page *page) -{ - BUG_ON(!PageHead(page)); - ClearPageHead(page); -} -#endif - -#define PG_head_mask ((1UL << PG_head)) - -#ifdef CONFIG_HUGETLB_PAGE -int PageHuge(struct page *page); -int PageHeadHuge(struct page *page); -bool page_huge_active(struct page *page); -#else -TESTPAGEFLAG_FALSE(Huge) -TESTPAGEFLAG_FALSE(HeadHuge) - -static inline bool page_huge_active(struct page *page) -{ - return 0; -} -#endif - - -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -/* - * PageHuge() only returns true for hugetlbfs pages, but not for - * normal or transparent huge pages. - * - * PageTransHuge() returns true for both transparent huge and - * hugetlbfs pages, but not normal pages. PageTransHuge() can only be - * called only in the core VM paths where hugetlbfs pages can't exist. - */ -static inline int PageTransHuge(struct page *page) -{ - VM_BUG_ON_PAGE(PageTail(page), page); - return PageHead(page); -} - -/* - * PageTransCompound returns true for both transparent huge pages - * and hugetlbfs pages, so it should only be called when it's known - * that hugetlbfs pages aren't involved. - */ -static inline int PageTransCompound(struct page *page) -{ - return PageCompound(page); -} - -/* - * PageTransCompoundMap is the same as PageTransCompound, but it also - * guarantees the primary MMU has the entire compound page mapped - * through pmd_trans_huge, which in turn guarantees the secondary MMUs - * can also map the entire compound page. This allows the secondary - * MMUs to call get_user_pages() only once for each compound page and - * to immediately map the entire compound page with a single secondary - * MMU fault. If there will be a pmd split later, the secondary MMUs - * will get an update through the MMU notifier invalidation through - * split_huge_pmd(). - * - * Unlike PageTransCompound, this is safe to be called only while - * split_huge_pmd() cannot run from under us, like if protected by the - * MMU notifier, otherwise it may result in page->_mapcount < 0 false - * positives. - */ -static inline int PageTransCompoundMap(struct page *page) -{ - return PageTransCompound(page) && atomic_read(&page->_mapcount) < 0; -} - -/* - * PageTransTail returns true for both transparent huge pages - * and hugetlbfs pages, so it should only be called when it's known - * that hugetlbfs pages aren't involved. - */ -static inline int PageTransTail(struct page *page) -{ - return PageTail(page); -} - -/* - * PageDoubleMap indicates that the compound page is mapped with PTEs as well - * as PMDs. - * - * This is required for optimization of rmap operations for THP: we can postpone - * per small page mapcount accounting (and its overhead from atomic operations) - * until the first PMD split. - * - * For the page PageDoubleMap means ->_mapcount in all sub-pages is offset up - * by one. This reference will go away with last compound_mapcount. - * - * See also __split_huge_pmd_locked() and page_remove_anon_compound_rmap(). - */ -static inline int PageDoubleMap(struct page *page) -{ - return PageHead(page) && test_bit(PG_double_map, &page[1].flags); -} - -static inline void SetPageDoubleMap(struct page *page) -{ - VM_BUG_ON_PAGE(!PageHead(page), page); - set_bit(PG_double_map, &page[1].flags); -} - -static inline void ClearPageDoubleMap(struct page *page) -{ - VM_BUG_ON_PAGE(!PageHead(page), page); - clear_bit(PG_double_map, &page[1].flags); -} -static inline int TestSetPageDoubleMap(struct page *page) -{ - VM_BUG_ON_PAGE(!PageHead(page), page); - return test_and_set_bit(PG_double_map, &page[1].flags); -} - -static inline int TestClearPageDoubleMap(struct page *page) -{ - VM_BUG_ON_PAGE(!PageHead(page), page); - return test_and_clear_bit(PG_double_map, &page[1].flags); -} - -#else -TESTPAGEFLAG_FALSE(TransHuge) -TESTPAGEFLAG_FALSE(TransCompound) -TESTPAGEFLAG_FALSE(TransCompoundMap) -TESTPAGEFLAG_FALSE(TransTail) -PAGEFLAG_FALSE(DoubleMap) - TESTSETFLAG_FALSE(DoubleMap) - TESTCLEARFLAG_FALSE(DoubleMap) -#endif - -/* - * For pages that are never mapped to userspace, page->mapcount may be - * used for storing extra information about page type. Any value used - * for this purpose must be <= -2, but it's better start not too close - * to -2 so that an underflow of the page_mapcount() won't be mistaken - * for a special page. - */ -#define PAGE_MAPCOUNT_OPS(uname, lname) \ -static __always_inline int Page##uname(struct page *page) \ -{ \ - return atomic_read(&page->_mapcount) == \ - PAGE_##lname##_MAPCOUNT_VALUE; \ -} \ -static __always_inline void __SetPage##uname(struct page *page) \ -{ \ - VM_BUG_ON_PAGE(atomic_read(&page->_mapcount) != -1, page); \ - atomic_set(&page->_mapcount, PAGE_##lname##_MAPCOUNT_VALUE); \ -} \ -static __always_inline void __ClearPage##uname(struct page *page) \ -{ \ - VM_BUG_ON_PAGE(!Page##uname(page), page); \ - atomic_set(&page->_mapcount, -1); \ -} - -/* - * PageBuddy() indicate that the page is free and in the buddy system - * (see mm/page_alloc.c). - */ -#define PAGE_BUDDY_MAPCOUNT_VALUE (-128) -PAGE_MAPCOUNT_OPS(Buddy, BUDDY) - -/* - * PageBalloon() is set on pages that are on the balloon page list - * (see mm/balloon_compaction.c). - */ -#define PAGE_BALLOON_MAPCOUNT_VALUE (-256) -PAGE_MAPCOUNT_OPS(Balloon, BALLOON) - -/* - * If kmemcg is enabled, the buddy allocator will set PageKmemcg() on - * pages allocated with __GFP_ACCOUNT. It gets cleared on page free. - */ -#define PAGE_KMEMCG_MAPCOUNT_VALUE (-512) -PAGE_MAPCOUNT_OPS(Kmemcg, KMEMCG) - -extern bool is_free_buddy_page(struct page *page); - -__PAGEFLAG(Isolated, isolated, PF_ANY); - -/* - * If network-based swap is enabled, sl*b must keep track of whether pages - * were allocated from pfmemalloc reserves. - */ -static inline int PageSlabPfmemalloc(struct page *page) -{ - VM_BUG_ON_PAGE(!PageSlab(page), page); - return PageActive(page); -} - -static inline void SetPageSlabPfmemalloc(struct page *page) -{ - VM_BUG_ON_PAGE(!PageSlab(page), page); - SetPageActive(page); -} - -static inline void __ClearPageSlabPfmemalloc(struct page *page) -{ - VM_BUG_ON_PAGE(!PageSlab(page), page); - __ClearPageActive(page); -} - -static inline void ClearPageSlabPfmemalloc(struct page *page) -{ - VM_BUG_ON_PAGE(!PageSlab(page), page); - ClearPageActive(page); -} - -#ifdef CONFIG_MMU -#define __PG_MLOCKED (1UL << PG_mlocked) -#else -#define __PG_MLOCKED 0 -#endif - -/* - * Flags checked when a page is freed. Pages being freed should not have - * these flags set. It they are, there is a problem. - */ -#define PAGE_FLAGS_CHECK_AT_FREE \ - (1UL << PG_lru | 1UL << PG_locked | \ - 1UL << PG_private | 1UL << PG_private_2 | \ - 1UL << PG_writeback | 1UL << PG_reserved | \ - 1UL << PG_slab | 1UL << PG_swapcache | 1UL << PG_active | \ - 1UL << PG_unevictable | __PG_MLOCKED) - -/* - * Flags checked when a page is prepped for return by the page allocator. - * Pages being prepped should not have these flags set. It they are set, - * there has been a kernel bug or struct page corruption. - * - * __PG_HWPOISON is exceptional because it needs to be kept beyond page's - * alloc-free cycle to prevent from reusing the page. - */ -#define PAGE_FLAGS_CHECK_AT_PREP \ - (((1UL << NR_PAGEFLAGS) - 1) & ~__PG_HWPOISON) - -#define PAGE_FLAGS_PRIVATE \ - (1UL << PG_private | 1UL << PG_private_2) -/** - * page_has_private - Determine if page has private stuff - * @page: The page to be checked - * - * Determine if a page has private stuff, indicating that release routines - * should be invoked upon it. - */ -static inline int page_has_private(struct page *page) -{ - return !!(page->flags & PAGE_FLAGS_PRIVATE); -} - -#undef PF_ANY -#undef PF_HEAD -#undef PF_NO_TAIL -#undef PF_NO_COMPOUND -#endif /* !__GENERATING_BOUNDS_H */ - -#endif /* PAGE_FLAGS_H */ diff --git a/src/linux/include/linux/page-isolation.h b/src/linux/include/linux/page-isolation.h deleted file mode 100644 index 047d647..0000000 --- a/src/linux/include/linux/page-isolation.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef __LINUX_PAGEISOLATION_H -#define __LINUX_PAGEISOLATION_H - -#ifdef CONFIG_MEMORY_ISOLATION -static inline bool has_isolate_pageblock(struct zone *zone) -{ - return zone->nr_isolate_pageblock; -} -static inline bool is_migrate_isolate_page(struct page *page) -{ - return get_pageblock_migratetype(page) == MIGRATE_ISOLATE; -} -static inline bool is_migrate_isolate(int migratetype) -{ - return migratetype == MIGRATE_ISOLATE; -} -#else -static inline bool has_isolate_pageblock(struct zone *zone) -{ - return false; -} -static inline bool is_migrate_isolate_page(struct page *page) -{ - return false; -} -static inline bool is_migrate_isolate(int migratetype) -{ - return false; -} -#endif - -bool has_unmovable_pages(struct zone *zone, struct page *page, int count, - bool skip_hwpoisoned_pages); -void set_pageblock_migratetype(struct page *page, int migratetype); -int move_freepages_block(struct zone *zone, struct page *page, - int migratetype); -int move_freepages(struct zone *zone, - struct page *start_page, struct page *end_page, - int migratetype); - -/* - * Changes migrate type in [start_pfn, end_pfn) to be MIGRATE_ISOLATE. - * If specified range includes migrate types other than MOVABLE or CMA, - * this will fail with -EBUSY. - * - * For isolating all pages in the range finally, the caller have to - * free all pages in the range. test_page_isolated() can be used for - * test it. - */ -int -start_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn, - unsigned migratetype, bool skip_hwpoisoned_pages); - -/* - * Changes MIGRATE_ISOLATE to MIGRATE_MOVABLE. - * target range is [start_pfn, end_pfn) - */ -int -undo_isolate_page_range(unsigned long start_pfn, unsigned long end_pfn, - unsigned migratetype); - -/* - * Test all pages in [start_pfn, end_pfn) are isolated or not. - */ -int test_pages_isolated(unsigned long start_pfn, unsigned long end_pfn, - bool skip_hwpoisoned_pages); - -struct page *alloc_migrate_target(struct page *page, unsigned long private, - int **resultp); - -#endif diff --git a/src/linux/include/linux/page_counter.h b/src/linux/include/linux/page_counter.h deleted file mode 100644 index 7e62920..0000000 --- a/src/linux/include/linux/page_counter.h +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef _LINUX_PAGE_COUNTER_H -#define _LINUX_PAGE_COUNTER_H - -#include -#include -#include - -struct page_counter { - atomic_long_t count; - unsigned long limit; - struct page_counter *parent; - - /* legacy */ - unsigned long watermark; - unsigned long failcnt; -}; - -#if BITS_PER_LONG == 32 -#define PAGE_COUNTER_MAX LONG_MAX -#else -#define PAGE_COUNTER_MAX (LONG_MAX / PAGE_SIZE) -#endif - -static inline void page_counter_init(struct page_counter *counter, - struct page_counter *parent) -{ - atomic_long_set(&counter->count, 0); - counter->limit = PAGE_COUNTER_MAX; - counter->parent = parent; -} - -static inline unsigned long page_counter_read(struct page_counter *counter) -{ - return atomic_long_read(&counter->count); -} - -void page_counter_cancel(struct page_counter *counter, unsigned long nr_pages); -void page_counter_charge(struct page_counter *counter, unsigned long nr_pages); -bool page_counter_try_charge(struct page_counter *counter, - unsigned long nr_pages, - struct page_counter **fail); -void page_counter_uncharge(struct page_counter *counter, unsigned long nr_pages); -int page_counter_limit(struct page_counter *counter, unsigned long limit); -int page_counter_memparse(const char *buf, const char *max, - unsigned long *nr_pages); - -static inline void page_counter_reset_watermark(struct page_counter *counter) -{ - counter->watermark = page_counter_read(counter); -} - -#endif /* _LINUX_PAGE_COUNTER_H */ diff --git a/src/linux/include/linux/page_ext.h b/src/linux/include/linux/page_ext.h deleted file mode 100644 index 9298c39..0000000 --- a/src/linux/include/linux/page_ext.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef __LINUX_PAGE_EXT_H -#define __LINUX_PAGE_EXT_H - -#include -#include -#include - -struct pglist_data; -struct page_ext_operations { - size_t offset; - size_t size; - bool (*need)(void); - void (*init)(void); -}; - -#ifdef CONFIG_PAGE_EXTENSION - -/* - * page_ext->flags bits: - * - * PAGE_EXT_DEBUG_POISON is set for poisoned pages. This is used to - * implement generic debug pagealloc feature. The pages are filled with - * poison patterns and set this flag after free_pages(). The poisoned - * pages are verified whether the patterns are not corrupted and clear - * the flag before alloc_pages(). - */ - -enum page_ext_flags { - PAGE_EXT_DEBUG_POISON, /* Page is poisoned */ - PAGE_EXT_DEBUG_GUARD, - PAGE_EXT_OWNER, -#if defined(CONFIG_IDLE_PAGE_TRACKING) && !defined(CONFIG_64BIT) - PAGE_EXT_YOUNG, - PAGE_EXT_IDLE, -#endif -}; - -/* - * Page Extension can be considered as an extended mem_map. - * A page_ext page is associated with every page descriptor. The - * page_ext helps us add more information about the page. - * All page_ext are allocated at boot or memory hotplug event, - * then the page_ext for pfn always exists. - */ -struct page_ext { - unsigned long flags; -}; - -extern void pgdat_page_ext_init(struct pglist_data *pgdat); - -#ifdef CONFIG_SPARSEMEM -static inline void page_ext_init_flatmem(void) -{ -} -extern void page_ext_init(void); -#else -extern void page_ext_init_flatmem(void); -static inline void page_ext_init(void) -{ -} -#endif - -struct page_ext *lookup_page_ext(struct page *page); - -#else /* !CONFIG_PAGE_EXTENSION */ -struct page_ext; - -static inline void pgdat_page_ext_init(struct pglist_data *pgdat) -{ -} - -static inline struct page_ext *lookup_page_ext(struct page *page) -{ - return NULL; -} - -static inline void page_ext_init(void) -{ -} - -static inline void page_ext_init_flatmem(void) -{ -} -#endif /* CONFIG_PAGE_EXTENSION */ -#endif /* __LINUX_PAGE_EXT_H */ diff --git a/src/linux/include/linux/page_idle.h b/src/linux/include/linux/page_idle.h deleted file mode 100644 index fec4027..0000000 --- a/src/linux/include/linux/page_idle.h +++ /dev/null @@ -1,139 +0,0 @@ -#ifndef _LINUX_MM_PAGE_IDLE_H -#define _LINUX_MM_PAGE_IDLE_H - -#include -#include -#include - -#ifdef CONFIG_IDLE_PAGE_TRACKING - -#ifdef CONFIG_64BIT -static inline bool page_is_young(struct page *page) -{ - return PageYoung(page); -} - -static inline void set_page_young(struct page *page) -{ - SetPageYoung(page); -} - -static inline bool test_and_clear_page_young(struct page *page) -{ - return TestClearPageYoung(page); -} - -static inline bool page_is_idle(struct page *page) -{ - return PageIdle(page); -} - -static inline void set_page_idle(struct page *page) -{ - SetPageIdle(page); -} - -static inline void clear_page_idle(struct page *page) -{ - ClearPageIdle(page); -} -#else /* !CONFIG_64BIT */ -/* - * If there is not enough space to store Idle and Young bits in page flags, use - * page ext flags instead. - */ -extern struct page_ext_operations page_idle_ops; - -static inline bool page_is_young(struct page *page) -{ - struct page_ext *page_ext = lookup_page_ext(page); - - if (unlikely(!page_ext)) - return false; - - return test_bit(PAGE_EXT_YOUNG, &page_ext->flags); -} - -static inline void set_page_young(struct page *page) -{ - struct page_ext *page_ext = lookup_page_ext(page); - - if (unlikely(!page_ext)) - return; - - set_bit(PAGE_EXT_YOUNG, &page_ext->flags); -} - -static inline bool test_and_clear_page_young(struct page *page) -{ - struct page_ext *page_ext = lookup_page_ext(page); - - if (unlikely(!page_ext)) - return false; - - return test_and_clear_bit(PAGE_EXT_YOUNG, &page_ext->flags); -} - -static inline bool page_is_idle(struct page *page) -{ - struct page_ext *page_ext = lookup_page_ext(page); - - if (unlikely(!page_ext)) - return false; - - return test_bit(PAGE_EXT_IDLE, &page_ext->flags); -} - -static inline void set_page_idle(struct page *page) -{ - struct page_ext *page_ext = lookup_page_ext(page); - - if (unlikely(!page_ext)) - return; - - set_bit(PAGE_EXT_IDLE, &page_ext->flags); -} - -static inline void clear_page_idle(struct page *page) -{ - struct page_ext *page_ext = lookup_page_ext(page); - - if (unlikely(!page_ext)) - return; - - clear_bit(PAGE_EXT_IDLE, &page_ext->flags); -} -#endif /* CONFIG_64BIT */ - -#else /* !CONFIG_IDLE_PAGE_TRACKING */ - -static inline bool page_is_young(struct page *page) -{ - return false; -} - -static inline void set_page_young(struct page *page) -{ -} - -static inline bool test_and_clear_page_young(struct page *page) -{ - return false; -} - -static inline bool page_is_idle(struct page *page) -{ - return false; -} - -static inline void set_page_idle(struct page *page) -{ -} - -static inline void clear_page_idle(struct page *page) -{ -} - -#endif /* CONFIG_IDLE_PAGE_TRACKING */ - -#endif /* _LINUX_MM_PAGE_IDLE_H */ diff --git a/src/linux/include/linux/page_owner.h b/src/linux/include/linux/page_owner.h deleted file mode 100644 index 2be728d..0000000 --- a/src/linux/include/linux/page_owner.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef __LINUX_PAGE_OWNER_H -#define __LINUX_PAGE_OWNER_H - -#include - -#ifdef CONFIG_PAGE_OWNER -extern struct static_key_false page_owner_inited; -extern struct page_ext_operations page_owner_ops; - -extern void __reset_page_owner(struct page *page, unsigned int order); -extern void __set_page_owner(struct page *page, - unsigned int order, gfp_t gfp_mask); -extern void __split_page_owner(struct page *page, unsigned int order); -extern void __copy_page_owner(struct page *oldpage, struct page *newpage); -extern void __set_page_owner_migrate_reason(struct page *page, int reason); -extern void __dump_page_owner(struct page *page); -extern void pagetypeinfo_showmixedcount_print(struct seq_file *m, - pg_data_t *pgdat, struct zone *zone); - -static inline void reset_page_owner(struct page *page, unsigned int order) -{ - if (static_branch_unlikely(&page_owner_inited)) - __reset_page_owner(page, order); -} - -static inline void set_page_owner(struct page *page, - unsigned int order, gfp_t gfp_mask) -{ - if (static_branch_unlikely(&page_owner_inited)) - __set_page_owner(page, order, gfp_mask); -} - -static inline void split_page_owner(struct page *page, unsigned int order) -{ - if (static_branch_unlikely(&page_owner_inited)) - __split_page_owner(page, order); -} -static inline void copy_page_owner(struct page *oldpage, struct page *newpage) -{ - if (static_branch_unlikely(&page_owner_inited)) - __copy_page_owner(oldpage, newpage); -} -static inline void set_page_owner_migrate_reason(struct page *page, int reason) -{ - if (static_branch_unlikely(&page_owner_inited)) - __set_page_owner_migrate_reason(page, reason); -} -static inline void dump_page_owner(struct page *page) -{ - if (static_branch_unlikely(&page_owner_inited)) - __dump_page_owner(page); -} -#else -static inline void reset_page_owner(struct page *page, unsigned int order) -{ -} -static inline void set_page_owner(struct page *page, - unsigned int order, gfp_t gfp_mask) -{ -} -static inline void split_page_owner(struct page *page, - unsigned int order) -{ -} -static inline void copy_page_owner(struct page *oldpage, struct page *newpage) -{ -} -static inline void set_page_owner_migrate_reason(struct page *page, int reason) -{ -} -static inline void dump_page_owner(struct page *page) -{ -} -#endif /* CONFIG_PAGE_OWNER */ -#endif /* __LINUX_PAGE_OWNER_H */ diff --git a/src/linux/include/linux/page_ref.h b/src/linux/include/linux/page_ref.h deleted file mode 100644 index 610e132..0000000 --- a/src/linux/include/linux/page_ref.h +++ /dev/null @@ -1,182 +0,0 @@ -#ifndef _LINUX_PAGE_REF_H -#define _LINUX_PAGE_REF_H - -#include -#include -#include -#include - -extern struct tracepoint __tracepoint_page_ref_set; -extern struct tracepoint __tracepoint_page_ref_mod; -extern struct tracepoint __tracepoint_page_ref_mod_and_test; -extern struct tracepoint __tracepoint_page_ref_mod_and_return; -extern struct tracepoint __tracepoint_page_ref_mod_unless; -extern struct tracepoint __tracepoint_page_ref_freeze; -extern struct tracepoint __tracepoint_page_ref_unfreeze; - -#ifdef CONFIG_DEBUG_PAGE_REF - -/* - * Ideally we would want to use the trace__enabled() helper - * functions. But due to include header file issues, that is not - * feasible. Instead we have to open code the static key functions. - * - * See trace_##name##_enabled(void) in include/linux/tracepoint.h - */ -#define page_ref_tracepoint_active(t) static_key_false(&(t).key) - -extern void __page_ref_set(struct page *page, int v); -extern void __page_ref_mod(struct page *page, int v); -extern void __page_ref_mod_and_test(struct page *page, int v, int ret); -extern void __page_ref_mod_and_return(struct page *page, int v, int ret); -extern void __page_ref_mod_unless(struct page *page, int v, int u); -extern void __page_ref_freeze(struct page *page, int v, int ret); -extern void __page_ref_unfreeze(struct page *page, int v); - -#else - -#define page_ref_tracepoint_active(t) false - -static inline void __page_ref_set(struct page *page, int v) -{ -} -static inline void __page_ref_mod(struct page *page, int v) -{ -} -static inline void __page_ref_mod_and_test(struct page *page, int v, int ret) -{ -} -static inline void __page_ref_mod_and_return(struct page *page, int v, int ret) -{ -} -static inline void __page_ref_mod_unless(struct page *page, int v, int u) -{ -} -static inline void __page_ref_freeze(struct page *page, int v, int ret) -{ -} -static inline void __page_ref_unfreeze(struct page *page, int v) -{ -} - -#endif - -static inline int page_ref_count(struct page *page) -{ - return atomic_read(&page->_refcount); -} - -static inline int page_count(struct page *page) -{ - return atomic_read(&compound_head(page)->_refcount); -} - -static inline void set_page_count(struct page *page, int v) -{ - atomic_set(&page->_refcount, v); - if (page_ref_tracepoint_active(__tracepoint_page_ref_set)) - __page_ref_set(page, v); -} - -/* - * Setup the page count before being freed into the page allocator for - * the first time (boot or memory hotplug) - */ -static inline void init_page_count(struct page *page) -{ - set_page_count(page, 1); -} - -static inline void page_ref_add(struct page *page, int nr) -{ - atomic_add(nr, &page->_refcount); - if (page_ref_tracepoint_active(__tracepoint_page_ref_mod)) - __page_ref_mod(page, nr); -} - -static inline void page_ref_sub(struct page *page, int nr) -{ - atomic_sub(nr, &page->_refcount); - if (page_ref_tracepoint_active(__tracepoint_page_ref_mod)) - __page_ref_mod(page, -nr); -} - -static inline void page_ref_inc(struct page *page) -{ - atomic_inc(&page->_refcount); - if (page_ref_tracepoint_active(__tracepoint_page_ref_mod)) - __page_ref_mod(page, 1); -} - -static inline void page_ref_dec(struct page *page) -{ - atomic_dec(&page->_refcount); - if (page_ref_tracepoint_active(__tracepoint_page_ref_mod)) - __page_ref_mod(page, -1); -} - -static inline int page_ref_sub_and_test(struct page *page, int nr) -{ - int ret = atomic_sub_and_test(nr, &page->_refcount); - - if (page_ref_tracepoint_active(__tracepoint_page_ref_mod_and_test)) - __page_ref_mod_and_test(page, -nr, ret); - return ret; -} - -static inline int page_ref_inc_return(struct page *page) -{ - int ret = atomic_inc_return(&page->_refcount); - - if (page_ref_tracepoint_active(__tracepoint_page_ref_mod_and_return)) - __page_ref_mod_and_return(page, 1, ret); - return ret; -} - -static inline int page_ref_dec_and_test(struct page *page) -{ - int ret = atomic_dec_and_test(&page->_refcount); - - if (page_ref_tracepoint_active(__tracepoint_page_ref_mod_and_test)) - __page_ref_mod_and_test(page, -1, ret); - return ret; -} - -static inline int page_ref_dec_return(struct page *page) -{ - int ret = atomic_dec_return(&page->_refcount); - - if (page_ref_tracepoint_active(__tracepoint_page_ref_mod_and_return)) - __page_ref_mod_and_return(page, -1, ret); - return ret; -} - -static inline int page_ref_add_unless(struct page *page, int nr, int u) -{ - int ret = atomic_add_unless(&page->_refcount, nr, u); - - if (page_ref_tracepoint_active(__tracepoint_page_ref_mod_unless)) - __page_ref_mod_unless(page, nr, ret); - return ret; -} - -static inline int page_ref_freeze(struct page *page, int count) -{ - int ret = likely(atomic_cmpxchg(&page->_refcount, count, 0) == count); - - if (page_ref_tracepoint_active(__tracepoint_page_ref_freeze)) - __page_ref_freeze(page, count, ret); - return ret; -} - -static inline void page_ref_unfreeze(struct page *page, int count) -{ - VM_BUG_ON_PAGE(page_count(page) != 0, page); - VM_BUG_ON(count == 0); - - atomic_set(&page->_refcount, count); - if (page_ref_tracepoint_active(__tracepoint_page_ref_unfreeze)) - __page_ref_unfreeze(page, count); -} - -#endif diff --git a/src/linux/include/linux/pageblock-flags.h b/src/linux/include/linux/pageblock-flags.h deleted file mode 100644 index e942558..0000000 --- a/src/linux/include/linux/pageblock-flags.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Macros for manipulating and testing flags related to a - * pageblock_nr_pages number of pages. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation version 2 of the License - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) IBM Corporation, 2006 - * - * Original author, Mel Gorman - * Major cleanups and reduction of bit operations, Andy Whitcroft - */ -#ifndef PAGEBLOCK_FLAGS_H -#define PAGEBLOCK_FLAGS_H - -#include - -/* Bit indices that affect a whole block of pages */ -enum pageblock_bits { - PB_migrate, - PB_migrate_end = PB_migrate + 3 - 1, - /* 3 bits required for migrate types */ - PB_migrate_skip,/* If set the block is skipped by compaction */ - - /* - * Assume the bits will always align on a word. If this assumption - * changes then get/set pageblock needs updating. - */ - NR_PAGEBLOCK_BITS -}; - -#ifdef CONFIG_HUGETLB_PAGE - -#ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE - -/* Huge page sizes are variable */ -extern unsigned int pageblock_order; - -#else /* CONFIG_HUGETLB_PAGE_SIZE_VARIABLE */ - -/* Huge pages are a constant size */ -#define pageblock_order HUGETLB_PAGE_ORDER - -#endif /* CONFIG_HUGETLB_PAGE_SIZE_VARIABLE */ - -#else /* CONFIG_HUGETLB_PAGE */ - -/* If huge pages are not used, group by MAX_ORDER_NR_PAGES */ -#define pageblock_order (MAX_ORDER-1) - -#endif /* CONFIG_HUGETLB_PAGE */ - -#define pageblock_nr_pages (1UL << pageblock_order) - -/* Forward declaration */ -struct page; - -unsigned long get_pfnblock_flags_mask(struct page *page, - unsigned long pfn, - unsigned long end_bitidx, - unsigned long mask); - -void set_pfnblock_flags_mask(struct page *page, - unsigned long flags, - unsigned long pfn, - unsigned long end_bitidx, - unsigned long mask); - -/* Declarations for getting and setting flags. See mm/page_alloc.c */ -#define get_pageblock_flags_group(page, start_bitidx, end_bitidx) \ - get_pfnblock_flags_mask(page, page_to_pfn(page), \ - end_bitidx, \ - (1 << (end_bitidx - start_bitidx + 1)) - 1) -#define set_pageblock_flags_group(page, flags, start_bitidx, end_bitidx) \ - set_pfnblock_flags_mask(page, flags, page_to_pfn(page), \ - end_bitidx, \ - (1 << (end_bitidx - start_bitidx + 1)) - 1) - -#ifdef CONFIG_COMPACTION -#define get_pageblock_skip(page) \ - get_pageblock_flags_group(page, PB_migrate_skip, \ - PB_migrate_skip) -#define clear_pageblock_skip(page) \ - set_pageblock_flags_group(page, 0, PB_migrate_skip, \ - PB_migrate_skip) -#define set_pageblock_skip(page) \ - set_pageblock_flags_group(page, 1, PB_migrate_skip, \ - PB_migrate_skip) -#endif /* CONFIG_COMPACTION */ - -#endif /* PAGEBLOCK_FLAGS_H */ diff --git a/src/linux/include/linux/pagemap.h b/src/linux/include/linux/pagemap.h deleted file mode 100644 index 7dbe914..0000000 --- a/src/linux/include/linux/pagemap.h +++ /dev/null @@ -1,626 +0,0 @@ -#ifndef _LINUX_PAGEMAP_H -#define _LINUX_PAGEMAP_H - -/* - * Copyright 1995 Linus Torvalds - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for in_interrupt() */ -#include - -/* - * Bits in mapping->flags. - */ -enum mapping_flags { - AS_EIO = 0, /* IO error on async write */ - AS_ENOSPC = 1, /* ENOSPC on async write */ - AS_MM_ALL_LOCKS = 2, /* under mm_take_all_locks() */ - AS_UNEVICTABLE = 3, /* e.g., ramdisk, SHM_LOCK */ - AS_EXITING = 4, /* final truncate in progress */ - /* writeback related tags are not used */ - AS_NO_WRITEBACK_TAGS = 5, -}; - -static inline void mapping_set_error(struct address_space *mapping, int error) -{ - if (unlikely(error)) { - if (error == -ENOSPC) - set_bit(AS_ENOSPC, &mapping->flags); - else - set_bit(AS_EIO, &mapping->flags); - } -} - -static inline void mapping_set_unevictable(struct address_space *mapping) -{ - set_bit(AS_UNEVICTABLE, &mapping->flags); -} - -static inline void mapping_clear_unevictable(struct address_space *mapping) -{ - clear_bit(AS_UNEVICTABLE, &mapping->flags); -} - -static inline int mapping_unevictable(struct address_space *mapping) -{ - if (mapping) - return test_bit(AS_UNEVICTABLE, &mapping->flags); - return !!mapping; -} - -static inline void mapping_set_exiting(struct address_space *mapping) -{ - set_bit(AS_EXITING, &mapping->flags); -} - -static inline int mapping_exiting(struct address_space *mapping) -{ - return test_bit(AS_EXITING, &mapping->flags); -} - -static inline void mapping_set_no_writeback_tags(struct address_space *mapping) -{ - set_bit(AS_NO_WRITEBACK_TAGS, &mapping->flags); -} - -static inline int mapping_use_writeback_tags(struct address_space *mapping) -{ - return !test_bit(AS_NO_WRITEBACK_TAGS, &mapping->flags); -} - -static inline gfp_t mapping_gfp_mask(struct address_space * mapping) -{ - return mapping->gfp_mask; -} - -/* Restricts the given gfp_mask to what the mapping allows. */ -static inline gfp_t mapping_gfp_constraint(struct address_space *mapping, - gfp_t gfp_mask) -{ - return mapping_gfp_mask(mapping) & gfp_mask; -} - -/* - * This is non-atomic. Only to be used before the mapping is activated. - * Probably needs a barrier... - */ -static inline void mapping_set_gfp_mask(struct address_space *m, gfp_t mask) -{ - m->gfp_mask = mask; -} - -void release_pages(struct page **pages, int nr, bool cold); - -/* - * speculatively take a reference to a page. - * If the page is free (_refcount == 0), then _refcount is untouched, and 0 - * is returned. Otherwise, _refcount is incremented by 1 and 1 is returned. - * - * This function must be called inside the same rcu_read_lock() section as has - * been used to lookup the page in the pagecache radix-tree (or page table): - * this allows allocators to use a synchronize_rcu() to stabilize _refcount. - * - * Unless an RCU grace period has passed, the count of all pages coming out - * of the allocator must be considered unstable. page_count may return higher - * than expected, and put_page must be able to do the right thing when the - * page has been finished with, no matter what it is subsequently allocated - * for (because put_page is what is used here to drop an invalid speculative - * reference). - * - * This is the interesting part of the lockless pagecache (and lockless - * get_user_pages) locking protocol, where the lookup-side (eg. find_get_page) - * has the following pattern: - * 1. find page in radix tree - * 2. conditionally increment refcount - * 3. check the page is still in pagecache (if no, goto 1) - * - * Remove-side that cares about stability of _refcount (eg. reclaim) has the - * following (with tree_lock held for write): - * A. atomically check refcount is correct and set it to 0 (atomic_cmpxchg) - * B. remove page from pagecache - * C. free the page - * - * There are 2 critical interleavings that matter: - * - 2 runs before A: in this case, A sees elevated refcount and bails out - * - A runs before 2: in this case, 2 sees zero refcount and retries; - * subsequently, B will complete and 1 will find no page, causing the - * lookup to return NULL. - * - * It is possible that between 1 and 2, the page is removed then the exact same - * page is inserted into the same position in pagecache. That's OK: the - * old find_get_page using tree_lock could equally have run before or after - * such a re-insertion, depending on order that locks are granted. - * - * Lookups racing against pagecache insertion isn't a big problem: either 1 - * will find the page or it will not. Likewise, the old find_get_page could run - * either before the insertion or afterwards, depending on timing. - */ -static inline int page_cache_get_speculative(struct page *page) -{ - VM_BUG_ON(in_interrupt()); - -#ifdef CONFIG_TINY_RCU -# ifdef CONFIG_PREEMPT_COUNT - VM_BUG_ON(!in_atomic()); -# endif - /* - * Preempt must be disabled here - we rely on rcu_read_lock doing - * this for us. - * - * Pagecache won't be truncated from interrupt context, so if we have - * found a page in the radix tree here, we have pinned its refcount by - * disabling preempt, and hence no need for the "speculative get" that - * SMP requires. - */ - VM_BUG_ON_PAGE(page_count(page) == 0, page); - page_ref_inc(page); - -#else - if (unlikely(!get_page_unless_zero(page))) { - /* - * Either the page has been freed, or will be freed. - * In either case, retry here and the caller should - * do the right thing (see comments above). - */ - return 0; - } -#endif - VM_BUG_ON_PAGE(PageTail(page), page); - - return 1; -} - -/* - * Same as above, but add instead of inc (could just be merged) - */ -static inline int page_cache_add_speculative(struct page *page, int count) -{ - VM_BUG_ON(in_interrupt()); - -#if !defined(CONFIG_SMP) && defined(CONFIG_TREE_RCU) -# ifdef CONFIG_PREEMPT_COUNT - VM_BUG_ON(!in_atomic()); -# endif - VM_BUG_ON_PAGE(page_count(page) == 0, page); - page_ref_add(page, count); - -#else - if (unlikely(!page_ref_add_unless(page, count, 0))) - return 0; -#endif - VM_BUG_ON_PAGE(PageCompound(page) && page != compound_head(page), page); - - return 1; -} - -#ifdef CONFIG_NUMA -extern struct page *__page_cache_alloc(gfp_t gfp); -#else -static inline struct page *__page_cache_alloc(gfp_t gfp) -{ - return alloc_pages(gfp, 0); -} -#endif - -static inline struct page *page_cache_alloc(struct address_space *x) -{ - return __page_cache_alloc(mapping_gfp_mask(x)); -} - -static inline struct page *page_cache_alloc_cold(struct address_space *x) -{ - return __page_cache_alloc(mapping_gfp_mask(x)|__GFP_COLD); -} - -static inline gfp_t readahead_gfp_mask(struct address_space *x) -{ - return mapping_gfp_mask(x) | - __GFP_COLD | __GFP_NORETRY | __GFP_NOWARN; -} - -typedef int filler_t(void *, struct page *); - -pgoff_t page_cache_next_hole(struct address_space *mapping, - pgoff_t index, unsigned long max_scan); -pgoff_t page_cache_prev_hole(struct address_space *mapping, - pgoff_t index, unsigned long max_scan); - -#define FGP_ACCESSED 0x00000001 -#define FGP_LOCK 0x00000002 -#define FGP_CREAT 0x00000004 -#define FGP_WRITE 0x00000008 -#define FGP_NOFS 0x00000010 -#define FGP_NOWAIT 0x00000020 - -struct page *pagecache_get_page(struct address_space *mapping, pgoff_t offset, - int fgp_flags, gfp_t cache_gfp_mask); - -/** - * find_get_page - find and get a page reference - * @mapping: the address_space to search - * @offset: the page index - * - * Looks up the page cache slot at @mapping & @offset. If there is a - * page cache page, it is returned with an increased refcount. - * - * Otherwise, %NULL is returned. - */ -static inline struct page *find_get_page(struct address_space *mapping, - pgoff_t offset) -{ - return pagecache_get_page(mapping, offset, 0, 0); -} - -static inline struct page *find_get_page_flags(struct address_space *mapping, - pgoff_t offset, int fgp_flags) -{ - return pagecache_get_page(mapping, offset, fgp_flags, 0); -} - -/** - * find_lock_page - locate, pin and lock a pagecache page - * pagecache_get_page - find and get a page reference - * @mapping: the address_space to search - * @offset: the page index - * - * Looks up the page cache slot at @mapping & @offset. If there is a - * page cache page, it is returned locked and with an increased - * refcount. - * - * Otherwise, %NULL is returned. - * - * find_lock_page() may sleep. - */ -static inline struct page *find_lock_page(struct address_space *mapping, - pgoff_t offset) -{ - return pagecache_get_page(mapping, offset, FGP_LOCK, 0); -} - -/** - * find_or_create_page - locate or add a pagecache page - * @mapping: the page's address_space - * @index: the page's index into the mapping - * @gfp_mask: page allocation mode - * - * Looks up the page cache slot at @mapping & @offset. If there is a - * page cache page, it is returned locked and with an increased - * refcount. - * - * If the page is not present, a new page is allocated using @gfp_mask - * and added to the page cache and the VM's LRU list. The page is - * returned locked and with an increased refcount. - * - * On memory exhaustion, %NULL is returned. - * - * find_or_create_page() may sleep, even if @gfp_flags specifies an - * atomic allocation! - */ -static inline struct page *find_or_create_page(struct address_space *mapping, - pgoff_t offset, gfp_t gfp_mask) -{ - return pagecache_get_page(mapping, offset, - FGP_LOCK|FGP_ACCESSED|FGP_CREAT, - gfp_mask); -} - -/** - * grab_cache_page_nowait - returns locked page at given index in given cache - * @mapping: target address_space - * @index: the page index - * - * Same as grab_cache_page(), but do not wait if the page is unavailable. - * This is intended for speculative data generators, where the data can - * be regenerated if the page couldn't be grabbed. This routine should - * be safe to call while holding the lock for another page. - * - * Clear __GFP_FS when allocating the page to avoid recursion into the fs - * and deadlock against the caller's locked page. - */ -static inline struct page *grab_cache_page_nowait(struct address_space *mapping, - pgoff_t index) -{ - return pagecache_get_page(mapping, index, - FGP_LOCK|FGP_CREAT|FGP_NOFS|FGP_NOWAIT, - mapping_gfp_mask(mapping)); -} - -struct page *find_get_entry(struct address_space *mapping, pgoff_t offset); -struct page *find_lock_entry(struct address_space *mapping, pgoff_t offset); -unsigned find_get_entries(struct address_space *mapping, pgoff_t start, - unsigned int nr_entries, struct page **entries, - pgoff_t *indices); -unsigned find_get_pages(struct address_space *mapping, pgoff_t start, - unsigned int nr_pages, struct page **pages); -unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t start, - unsigned int nr_pages, struct page **pages); -unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index, - int tag, unsigned int nr_pages, struct page **pages); -unsigned find_get_entries_tag(struct address_space *mapping, pgoff_t start, - int tag, unsigned int nr_entries, - struct page **entries, pgoff_t *indices); - -struct page *grab_cache_page_write_begin(struct address_space *mapping, - pgoff_t index, unsigned flags); - -/* - * Returns locked page at given index in given cache, creating it if needed. - */ -static inline struct page *grab_cache_page(struct address_space *mapping, - pgoff_t index) -{ - return find_or_create_page(mapping, index, mapping_gfp_mask(mapping)); -} - -extern struct page * read_cache_page(struct address_space *mapping, - pgoff_t index, filler_t *filler, void *data); -extern struct page * read_cache_page_gfp(struct address_space *mapping, - pgoff_t index, gfp_t gfp_mask); -extern int read_cache_pages(struct address_space *mapping, - struct list_head *pages, filler_t *filler, void *data); - -static inline struct page *read_mapping_page(struct address_space *mapping, - pgoff_t index, void *data) -{ - filler_t *filler = (filler_t *)mapping->a_ops->readpage; - return read_cache_page(mapping, index, filler, data); -} - -/* - * Get index of the page with in radix-tree - * (TODO: remove once hugetlb pages will have ->index in PAGE_SIZE) - */ -static inline pgoff_t page_to_index(struct page *page) -{ - pgoff_t pgoff; - - if (likely(!PageTransTail(page))) - return page->index; - - /* - * We don't initialize ->index for tail pages: calculate based on - * head page - */ - pgoff = compound_head(page)->index; - pgoff += page - compound_head(page); - return pgoff; -} - -/* - * Get the offset in PAGE_SIZE. - * (TODO: hugepage should have ->index in PAGE_SIZE) - */ -static inline pgoff_t page_to_pgoff(struct page *page) -{ - if (unlikely(PageHeadHuge(page))) - return page->index << compound_order(page); - - return page_to_index(page); -} - -/* - * Return byte-offset into filesystem object for page. - */ -static inline loff_t page_offset(struct page *page) -{ - return ((loff_t)page->index) << PAGE_SHIFT; -} - -static inline loff_t page_file_offset(struct page *page) -{ - return ((loff_t)page_index(page)) << PAGE_SHIFT; -} - -extern pgoff_t linear_hugepage_index(struct vm_area_struct *vma, - unsigned long address); - -static inline pgoff_t linear_page_index(struct vm_area_struct *vma, - unsigned long address) -{ - pgoff_t pgoff; - if (unlikely(is_vm_hugetlb_page(vma))) - return linear_hugepage_index(vma, address); - pgoff = (address - vma->vm_start) >> PAGE_SHIFT; - pgoff += vma->vm_pgoff; - return pgoff; -} - -extern void __lock_page(struct page *page); -extern int __lock_page_killable(struct page *page); -extern int __lock_page_or_retry(struct page *page, struct mm_struct *mm, - unsigned int flags); -extern void unlock_page(struct page *page); - -static inline int trylock_page(struct page *page) -{ - page = compound_head(page); - return (likely(!test_and_set_bit_lock(PG_locked, &page->flags))); -} - -/* - * lock_page may only be called if we have the page's inode pinned. - */ -static inline void lock_page(struct page *page) -{ - might_sleep(); - if (!trylock_page(page)) - __lock_page(page); -} - -/* - * lock_page_killable is like lock_page but can be interrupted by fatal - * signals. It returns 0 if it locked the page and -EINTR if it was - * killed while waiting. - */ -static inline int lock_page_killable(struct page *page) -{ - might_sleep(); - if (!trylock_page(page)) - return __lock_page_killable(page); - return 0; -} - -/* - * lock_page_or_retry - Lock the page, unless this would block and the - * caller indicated that it can handle a retry. - * - * Return value and mmap_sem implications depend on flags; see - * __lock_page_or_retry(). - */ -static inline int lock_page_or_retry(struct page *page, struct mm_struct *mm, - unsigned int flags) -{ - might_sleep(); - return trylock_page(page) || __lock_page_or_retry(page, mm, flags); -} - -/* - * This is exported only for wait_on_page_locked/wait_on_page_writeback, - * and for filesystems which need to wait on PG_private. - */ -extern void wait_on_page_bit(struct page *page, int bit_nr); - -extern int wait_on_page_bit_killable(struct page *page, int bit_nr); -extern int wait_on_page_bit_killable_timeout(struct page *page, - int bit_nr, unsigned long timeout); - -static inline int wait_on_page_locked_killable(struct page *page) -{ - if (!PageLocked(page)) - return 0; - return wait_on_page_bit_killable(compound_head(page), PG_locked); -} - -extern wait_queue_head_t *page_waitqueue(struct page *page); -static inline void wake_up_page(struct page *page, int bit) -{ - __wake_up_bit(page_waitqueue(page), &page->flags, bit); -} - -/* - * Wait for a page to be unlocked. - * - * This must be called with the caller "holding" the page, - * ie with increased "page->count" so that the page won't - * go away during the wait.. - */ -static inline void wait_on_page_locked(struct page *page) -{ - if (PageLocked(page)) - wait_on_page_bit(compound_head(page), PG_locked); -} - -/* - * Wait for a page to complete writeback - */ -static inline void wait_on_page_writeback(struct page *page) -{ - if (PageWriteback(page)) - wait_on_page_bit(page, PG_writeback); -} - -extern void end_page_writeback(struct page *page); -void wait_for_stable_page(struct page *page); - -void page_endio(struct page *page, bool is_write, int err); - -/* - * Add an arbitrary waiter to a page's wait queue - */ -extern void add_page_wait_queue(struct page *page, wait_queue_t *waiter); - -/* - * Fault everything in given userspace address range in. - */ -static inline int fault_in_pages_writeable(char __user *uaddr, int size) -{ - char __user *end = uaddr + size - 1; - - if (unlikely(size == 0)) - return 0; - - if (unlikely(uaddr > end)) - return -EFAULT; - /* - * Writing zeroes into userspace here is OK, because we know that if - * the zero gets there, we'll be overwriting it. - */ - do { - if (unlikely(__put_user(0, uaddr) != 0)) - return -EFAULT; - uaddr += PAGE_SIZE; - } while (uaddr <= end); - - /* Check whether the range spilled into the next page. */ - if (((unsigned long)uaddr & PAGE_MASK) == - ((unsigned long)end & PAGE_MASK)) - return __put_user(0, end); - - return 0; -} - -static inline int fault_in_pages_readable(const char __user *uaddr, int size) -{ - volatile char c; - const char __user *end = uaddr + size - 1; - - if (unlikely(size == 0)) - return 0; - - if (unlikely(uaddr > end)) - return -EFAULT; - - do { - if (unlikely(__get_user(c, uaddr) != 0)) - return -EFAULT; - uaddr += PAGE_SIZE; - } while (uaddr <= end); - - /* Check whether the range spilled into the next page. */ - if (((unsigned long)uaddr & PAGE_MASK) == - ((unsigned long)end & PAGE_MASK)) { - return __get_user(c, end); - } - - (void)c; - return 0; -} - -int add_to_page_cache_locked(struct page *page, struct address_space *mapping, - pgoff_t index, gfp_t gfp_mask); -int add_to_page_cache_lru(struct page *page, struct address_space *mapping, - pgoff_t index, gfp_t gfp_mask); -extern void delete_from_page_cache(struct page *page); -extern void __delete_from_page_cache(struct page *page, void *shadow); -int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask); - -/* - * Like add_to_page_cache_locked, but used to add newly allocated pages: - * the page is new, so we can just run __SetPageLocked() against it. - */ -static inline int add_to_page_cache(struct page *page, - struct address_space *mapping, pgoff_t offset, gfp_t gfp_mask) -{ - int error; - - __SetPageLocked(page); - error = add_to_page_cache_locked(page, mapping, offset, gfp_mask); - if (unlikely(error)) - __ClearPageLocked(page); - return error; -} - -static inline unsigned long dir_pages(struct inode *inode) -{ - return (unsigned long)(inode->i_size + PAGE_SIZE - 1) >> - PAGE_SHIFT; -} - -#endif /* _LINUX_PAGEMAP_H */ diff --git a/src/linux/include/linux/pagevec.h b/src/linux/include/linux/pagevec.h deleted file mode 100644 index b45d391..0000000 --- a/src/linux/include/linux/pagevec.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * include/linux/pagevec.h - * - * In many places it is efficient to batch an operation up against multiple - * pages. A pagevec is a multipage container which is used for that. - */ - -#ifndef _LINUX_PAGEVEC_H -#define _LINUX_PAGEVEC_H - -/* 14 pointers + two long's align the pagevec structure to a power of two */ -#define PAGEVEC_SIZE 14 - -struct page; -struct address_space; - -struct pagevec { - unsigned long nr; - unsigned long cold; - struct page *pages[PAGEVEC_SIZE]; -}; - -void __pagevec_release(struct pagevec *pvec); -void __pagevec_lru_add(struct pagevec *pvec); -unsigned pagevec_lookup_entries(struct pagevec *pvec, - struct address_space *mapping, - pgoff_t start, unsigned nr_entries, - pgoff_t *indices); -void pagevec_remove_exceptionals(struct pagevec *pvec); -unsigned pagevec_lookup(struct pagevec *pvec, struct address_space *mapping, - pgoff_t start, unsigned nr_pages); -unsigned pagevec_lookup_tag(struct pagevec *pvec, - struct address_space *mapping, pgoff_t *index, int tag, - unsigned nr_pages); - -static inline void pagevec_init(struct pagevec *pvec, int cold) -{ - pvec->nr = 0; - pvec->cold = cold; -} - -static inline void pagevec_reinit(struct pagevec *pvec) -{ - pvec->nr = 0; -} - -static inline unsigned pagevec_count(struct pagevec *pvec) -{ - return pvec->nr; -} - -static inline unsigned pagevec_space(struct pagevec *pvec) -{ - return PAGEVEC_SIZE - pvec->nr; -} - -/* - * Add a page to a pagevec. Returns the number of slots still available. - */ -static inline unsigned pagevec_add(struct pagevec *pvec, struct page *page) -{ - pvec->pages[pvec->nr++] = page; - return pagevec_space(pvec); -} - -static inline void pagevec_release(struct pagevec *pvec) -{ - if (pagevec_count(pvec)) - __pagevec_release(pvec); -} - -#endif /* _LINUX_PAGEVEC_H */ diff --git a/src/linux/include/linux/parser.h b/src/linux/include/linux/parser.h deleted file mode 100644 index 39d5b79..0000000 --- a/src/linux/include/linux/parser.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * linux/include/linux/parser.h - * - * Header for lib/parser.c - * Intended use of these functions is parsing filesystem argument lists, - * but could potentially be used anywhere else that simple option=arg - * parsing is required. - */ - - -/* associates an integer enumerator with a pattern string. */ -struct match_token { - int token; - const char *pattern; -}; - -typedef struct match_token match_table_t[]; - -/* Maximum number of arguments that match_token will find in a pattern */ -enum {MAX_OPT_ARGS = 3}; - -/* Describe the location within a string of a substring */ -typedef struct { - char *from; - char *to; -} substring_t; - -int match_token(char *, const match_table_t table, substring_t args[]); -int match_int(substring_t *, int *result); -int match_octal(substring_t *, int *result); -int match_hex(substring_t *, int *result); -bool match_wildcard(const char *pattern, const char *str); -size_t match_strlcpy(char *, const substring_t *, size_t); -char *match_strdup(const substring_t *); diff --git a/src/linux/include/linux/path.h b/src/linux/include/linux/path.h deleted file mode 100644 index d137218..0000000 --- a/src/linux/include/linux/path.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _LINUX_PATH_H -#define _LINUX_PATH_H - -struct dentry; -struct vfsmount; - -struct path { - struct vfsmount *mnt; - struct dentry *dentry; -}; - -extern void path_get(const struct path *); -extern void path_put(const struct path *); - -static inline int path_equal(const struct path *path1, const struct path *path2) -{ - return path1->mnt == path2->mnt && path1->dentry == path2->dentry; -} - -#endif /* _LINUX_PATH_H */ diff --git a/src/linux/include/linux/pci-dma-compat.h b/src/linux/include/linux/pci-dma-compat.h deleted file mode 100644 index 39726ca..0000000 --- a/src/linux/include/linux/pci-dma-compat.h +++ /dev/null @@ -1,147 +0,0 @@ -/* include this file if the platform implements the dma_ DMA Mapping API - * and wants to provide the pci_ DMA Mapping API in terms of it */ - -#ifndef _ASM_GENERIC_PCI_DMA_COMPAT_H -#define _ASM_GENERIC_PCI_DMA_COMPAT_H - -#include - -/* This defines the direction arg to the DMA mapping routines. */ -#define PCI_DMA_BIDIRECTIONAL 0 -#define PCI_DMA_TODEVICE 1 -#define PCI_DMA_FROMDEVICE 2 -#define PCI_DMA_NONE 3 - -static inline void * -pci_alloc_consistent(struct pci_dev *hwdev, size_t size, - dma_addr_t *dma_handle) -{ - return dma_alloc_coherent(hwdev == NULL ? NULL : &hwdev->dev, size, dma_handle, GFP_ATOMIC); -} - -static inline void * -pci_zalloc_consistent(struct pci_dev *hwdev, size_t size, - dma_addr_t *dma_handle) -{ - return dma_zalloc_coherent(hwdev == NULL ? NULL : &hwdev->dev, - size, dma_handle, GFP_ATOMIC); -} - -static inline void -pci_free_consistent(struct pci_dev *hwdev, size_t size, - void *vaddr, dma_addr_t dma_handle) -{ - dma_free_coherent(hwdev == NULL ? NULL : &hwdev->dev, size, vaddr, dma_handle); -} - -static inline dma_addr_t -pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction) -{ - return dma_map_single(hwdev == NULL ? NULL : &hwdev->dev, ptr, size, (enum dma_data_direction)direction); -} - -static inline void -pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr, - size_t size, int direction) -{ - dma_unmap_single(hwdev == NULL ? NULL : &hwdev->dev, dma_addr, size, (enum dma_data_direction)direction); -} - -static inline dma_addr_t -pci_map_page(struct pci_dev *hwdev, struct page *page, - unsigned long offset, size_t size, int direction) -{ - return dma_map_page(hwdev == NULL ? NULL : &hwdev->dev, page, offset, size, (enum dma_data_direction)direction); -} - -static inline void -pci_unmap_page(struct pci_dev *hwdev, dma_addr_t dma_address, - size_t size, int direction) -{ - dma_unmap_page(hwdev == NULL ? NULL : &hwdev->dev, dma_address, size, (enum dma_data_direction)direction); -} - -static inline int -pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nents, int direction) -{ - return dma_map_sg(hwdev == NULL ? NULL : &hwdev->dev, sg, nents, (enum dma_data_direction)direction); -} - -static inline void -pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg, - int nents, int direction) -{ - dma_unmap_sg(hwdev == NULL ? NULL : &hwdev->dev, sg, nents, (enum dma_data_direction)direction); -} - -static inline void -pci_dma_sync_single_for_cpu(struct pci_dev *hwdev, dma_addr_t dma_handle, - size_t size, int direction) -{ - dma_sync_single_for_cpu(hwdev == NULL ? NULL : &hwdev->dev, dma_handle, size, (enum dma_data_direction)direction); -} - -static inline void -pci_dma_sync_single_for_device(struct pci_dev *hwdev, dma_addr_t dma_handle, - size_t size, int direction) -{ - dma_sync_single_for_device(hwdev == NULL ? NULL : &hwdev->dev, dma_handle, size, (enum dma_data_direction)direction); -} - -static inline void -pci_dma_sync_sg_for_cpu(struct pci_dev *hwdev, struct scatterlist *sg, - int nelems, int direction) -{ - dma_sync_sg_for_cpu(hwdev == NULL ? NULL : &hwdev->dev, sg, nelems, (enum dma_data_direction)direction); -} - -static inline void -pci_dma_sync_sg_for_device(struct pci_dev *hwdev, struct scatterlist *sg, - int nelems, int direction) -{ - dma_sync_sg_for_device(hwdev == NULL ? NULL : &hwdev->dev, sg, nelems, (enum dma_data_direction)direction); -} - -static inline int -pci_dma_mapping_error(struct pci_dev *pdev, dma_addr_t dma_addr) -{ - return dma_mapping_error(&pdev->dev, dma_addr); -} - -#ifdef CONFIG_PCI -static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask) -{ - return dma_set_mask(&dev->dev, mask); -} - -static inline int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) -{ - return dma_set_coherent_mask(&dev->dev, mask); -} - -static inline int pci_set_dma_max_seg_size(struct pci_dev *dev, - unsigned int size) -{ - return dma_set_max_seg_size(&dev->dev, size); -} - -static inline int pci_set_dma_seg_boundary(struct pci_dev *dev, - unsigned long mask) -{ - return dma_set_seg_boundary(&dev->dev, mask); -} -#else -static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask) -{ return -EIO; } -static inline int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) -{ return -EIO; } -static inline int pci_set_dma_max_seg_size(struct pci_dev *dev, - unsigned int size) -{ return -EIO; } -static inline int pci_set_dma_seg_boundary(struct pci_dev *dev, - unsigned long mask) -{ return -EIO; } -#endif - -#endif diff --git a/src/linux/include/linux/pci.h b/src/linux/include/linux/pci.h deleted file mode 100644 index a38772a..0000000 --- a/src/linux/include/linux/pci.h +++ /dev/null @@ -1,2147 +0,0 @@ -/* - * pci.h - * - * PCI defines and function prototypes - * Copyright 1994, Drew Eckhardt - * Copyright 1997--1999 Martin Mares - * - * For more information, please consult the following manuals (look at - * http://www.pcisig.com/ for how to get them): - * - * PCI BIOS Specification - * PCI Local Bus Specification - * PCI to PCI Bridge Specification - * PCI System Design Guide - */ -#ifndef LINUX_PCI_H -#define LINUX_PCI_H - - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * The PCI interface treats multi-function devices as independent - * devices. The slot/function address of each device is encoded - * in a single byte as follows: - * - * 7:3 = slot - * 2:0 = function - * - * PCI_DEVFN(), PCI_SLOT(), and PCI_FUNC() are defined in uapi/linux/pci.h. - * In the interest of not exposing interfaces to user-space unnecessarily, - * the following kernel-only defines are being added here. - */ -#define PCI_DEVID(bus, devfn) ((((u16)(bus)) << 8) | (devfn)) -/* return bus from PCI devid = ((u16)bus_number) << 8) | devfn */ -#define PCI_BUS_NUM(x) (((x) >> 8) & 0xff) - -/* pci_slot represents a physical slot */ -struct pci_slot { - struct pci_bus *bus; /* The bus this slot is on */ - struct list_head list; /* node in list of slots on this bus */ - struct hotplug_slot *hotplug; /* Hotplug info (migrate over time) */ - unsigned char number; /* PCI_SLOT(pci_dev->devfn) */ - struct kobject kobj; -}; - -static inline const char *pci_slot_name(const struct pci_slot *slot) -{ - return kobject_name(&slot->kobj); -} - -/* File state for mmap()s on /proc/bus/pci/X/Y */ -enum pci_mmap_state { - pci_mmap_io, - pci_mmap_mem -}; - -/* - * For PCI devices, the region numbers are assigned this way: - */ -enum { - /* #0-5: standard PCI resources */ - PCI_STD_RESOURCES, - PCI_STD_RESOURCE_END = 5, - - /* #6: expansion ROM resource */ - PCI_ROM_RESOURCE, - - /* device specific resources */ -#ifdef CONFIG_PCI_IOV - PCI_IOV_RESOURCES, - PCI_IOV_RESOURCE_END = PCI_IOV_RESOURCES + PCI_SRIOV_NUM_BARS - 1, -#endif - - /* resources assigned to buses behind the bridge */ -#define PCI_BRIDGE_RESOURCE_NUM 4 - - PCI_BRIDGE_RESOURCES, - PCI_BRIDGE_RESOURCE_END = PCI_BRIDGE_RESOURCES + - PCI_BRIDGE_RESOURCE_NUM - 1, - - /* total resources associated with a PCI device */ - PCI_NUM_RESOURCES, - - /* preserve this for compatibility */ - DEVICE_COUNT_RESOURCE = PCI_NUM_RESOURCES, -}; - -/* - * pci_power_t values must match the bits in the Capabilities PME_Support - * and Control/Status PowerState fields in the Power Management capability. - */ -typedef int __bitwise pci_power_t; - -#define PCI_D0 ((pci_power_t __force) 0) -#define PCI_D1 ((pci_power_t __force) 1) -#define PCI_D2 ((pci_power_t __force) 2) -#define PCI_D3hot ((pci_power_t __force) 3) -#define PCI_D3cold ((pci_power_t __force) 4) -#define PCI_UNKNOWN ((pci_power_t __force) 5) -#define PCI_POWER_ERROR ((pci_power_t __force) -1) - -/* Remember to update this when the list above changes! */ -extern const char *pci_power_names[]; - -static inline const char *pci_power_name(pci_power_t state) -{ - return pci_power_names[1 + (__force int) state]; -} - -#define PCI_PM_D2_DELAY 200 -#define PCI_PM_D3_WAIT 10 -#define PCI_PM_D3COLD_WAIT 100 -#define PCI_PM_BUS_WAIT 50 - -/** The pci_channel state describes connectivity between the CPU and - * the pci device. If some PCI bus between here and the pci device - * has crashed or locked up, this info is reflected here. - */ -typedef unsigned int __bitwise pci_channel_state_t; - -enum pci_channel_state { - /* I/O channel is in normal state */ - pci_channel_io_normal = (__force pci_channel_state_t) 1, - - /* I/O to channel is blocked */ - pci_channel_io_frozen = (__force pci_channel_state_t) 2, - - /* PCI card is dead */ - pci_channel_io_perm_failure = (__force pci_channel_state_t) 3, -}; - -typedef unsigned int __bitwise pcie_reset_state_t; - -enum pcie_reset_state { - /* Reset is NOT asserted (Use to deassert reset) */ - pcie_deassert_reset = (__force pcie_reset_state_t) 1, - - /* Use #PERST to reset PCIe device */ - pcie_warm_reset = (__force pcie_reset_state_t) 2, - - /* Use PCIe Hot Reset to reset device */ - pcie_hot_reset = (__force pcie_reset_state_t) 3 -}; - -typedef unsigned short __bitwise pci_dev_flags_t; -enum pci_dev_flags { - /* INTX_DISABLE in PCI_COMMAND register disables MSI - * generation too. - */ - PCI_DEV_FLAGS_MSI_INTX_DISABLE_BUG = (__force pci_dev_flags_t) (1 << 0), - /* Device configuration is irrevocably lost if disabled into D3 */ - PCI_DEV_FLAGS_NO_D3 = (__force pci_dev_flags_t) (1 << 1), - /* Provide indication device is assigned by a Virtual Machine Manager */ - PCI_DEV_FLAGS_ASSIGNED = (__force pci_dev_flags_t) (1 << 2), - /* Flag for quirk use to store if quirk-specific ACS is enabled */ - PCI_DEV_FLAGS_ACS_ENABLED_QUIRK = (__force pci_dev_flags_t) (1 << 3), - /* Use a PCIe-to-PCI bridge alias even if !pci_is_pcie */ - PCI_DEV_FLAG_PCIE_BRIDGE_ALIAS = (__force pci_dev_flags_t) (1 << 5), - /* Do not use bus resets for device */ - PCI_DEV_FLAGS_NO_BUS_RESET = (__force pci_dev_flags_t) (1 << 6), - /* Do not use PM reset even if device advertises NoSoftRst- */ - PCI_DEV_FLAGS_NO_PM_RESET = (__force pci_dev_flags_t) (1 << 7), - /* Get VPD from function 0 VPD */ - PCI_DEV_FLAGS_VPD_REF_F0 = (__force pci_dev_flags_t) (1 << 8), -}; - -enum pci_irq_reroute_variant { - INTEL_IRQ_REROUTE_VARIANT = 1, - MAX_IRQ_REROUTE_VARIANTS = 3 -}; - -typedef unsigned short __bitwise pci_bus_flags_t; -enum pci_bus_flags { - PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1, - PCI_BUS_FLAGS_NO_MMRBC = (__force pci_bus_flags_t) 2, - PCI_BUS_FLAGS_NO_AERSID = (__force pci_bus_flags_t) 4, -}; - -/* These values come from the PCI Express Spec */ -enum pcie_link_width { - PCIE_LNK_WIDTH_RESRV = 0x00, - PCIE_LNK_X1 = 0x01, - PCIE_LNK_X2 = 0x02, - PCIE_LNK_X4 = 0x04, - PCIE_LNK_X8 = 0x08, - PCIE_LNK_X12 = 0x0C, - PCIE_LNK_X16 = 0x10, - PCIE_LNK_X32 = 0x20, - PCIE_LNK_WIDTH_UNKNOWN = 0xFF, -}; - -/* Based on the PCI Hotplug Spec, but some values are made up by us */ -enum pci_bus_speed { - PCI_SPEED_33MHz = 0x00, - PCI_SPEED_66MHz = 0x01, - PCI_SPEED_66MHz_PCIX = 0x02, - PCI_SPEED_100MHz_PCIX = 0x03, - PCI_SPEED_133MHz_PCIX = 0x04, - PCI_SPEED_66MHz_PCIX_ECC = 0x05, - PCI_SPEED_100MHz_PCIX_ECC = 0x06, - PCI_SPEED_133MHz_PCIX_ECC = 0x07, - PCI_SPEED_66MHz_PCIX_266 = 0x09, - PCI_SPEED_100MHz_PCIX_266 = 0x0a, - PCI_SPEED_133MHz_PCIX_266 = 0x0b, - AGP_UNKNOWN = 0x0c, - AGP_1X = 0x0d, - AGP_2X = 0x0e, - AGP_4X = 0x0f, - AGP_8X = 0x10, - PCI_SPEED_66MHz_PCIX_533 = 0x11, - PCI_SPEED_100MHz_PCIX_533 = 0x12, - PCI_SPEED_133MHz_PCIX_533 = 0x13, - PCIE_SPEED_2_5GT = 0x14, - PCIE_SPEED_5_0GT = 0x15, - PCIE_SPEED_8_0GT = 0x16, - PCI_SPEED_UNKNOWN = 0xff, -}; - -struct pci_cap_saved_data { - u16 cap_nr; - bool cap_extended; - unsigned int size; - u32 data[0]; -}; - -struct pci_cap_saved_state { - struct hlist_node next; - struct pci_cap_saved_data cap; -}; - -struct pcie_link_state; -struct pci_vpd; -struct pci_sriov; -struct pci_ats; - -/* - * The pci_dev structure is used to describe PCI devices. - */ -struct pci_dev { - struct list_head bus_list; /* node in per-bus list */ - struct pci_bus *bus; /* bus this device is on */ - struct pci_bus *subordinate; /* bus this device bridges to */ - - void *sysdata; /* hook for sys-specific extension */ - struct proc_dir_entry *procent; /* device entry in /proc/bus/pci */ - struct pci_slot *slot; /* Physical slot this device is in */ - - unsigned int devfn; /* encoded device & function index */ - unsigned short vendor; - unsigned short device; - unsigned short subsystem_vendor; - unsigned short subsystem_device; - unsigned int class; /* 3 bytes: (base,sub,prog-if) */ - u8 revision; /* PCI revision, low byte of class word */ - u8 hdr_type; /* PCI header type (`multi' flag masked out) */ -#ifdef CONFIG_PCIEAER - u16 aer_cap; /* AER capability offset */ -#endif - u8 pcie_cap; /* PCIe capability offset */ - u8 msi_cap; /* MSI capability offset */ - u8 msix_cap; /* MSI-X capability offset */ - u8 pcie_mpss:3; /* PCIe Max Payload Size Supported */ - u8 rom_base_reg; /* which config register controls the ROM */ - u8 pin; /* which interrupt pin this device uses */ - u16 pcie_flags_reg; /* cached PCIe Capabilities Register */ - unsigned long *dma_alias_mask;/* mask of enabled devfn aliases */ - - struct pci_driver *driver; /* which driver has allocated this device */ - u64 dma_mask; /* Mask of the bits of bus address this - device implements. Normally this is - 0xffffffff. You only need to change - this if your device has broken DMA - or supports 64-bit transfers. */ - - struct device_dma_parameters dma_parms; - - pci_power_t current_state; /* Current operating state. In ACPI-speak, - this is D0-D3, D0 being fully functional, - and D3 being off. */ - u8 pm_cap; /* PM capability offset */ - unsigned int pme_support:5; /* Bitmask of states from which PME# - can be generated */ - unsigned int pme_interrupt:1; - unsigned int pme_poll:1; /* Poll device's PME status bit */ - unsigned int d1_support:1; /* Low power state D1 is supported */ - unsigned int d2_support:1; /* Low power state D2 is supported */ - unsigned int no_d1d2:1; /* D1 and D2 are forbidden */ - unsigned int no_d3cold:1; /* D3cold is forbidden */ - unsigned int bridge_d3:1; /* Allow D3 for bridge */ - unsigned int d3cold_allowed:1; /* D3cold is allowed by user */ - unsigned int mmio_always_on:1; /* disallow turning off io/mem - decoding during bar sizing */ - unsigned int wakeup_prepared:1; - unsigned int runtime_d3cold:1; /* whether go through runtime - D3cold, not set for devices - powered on/off by the - corresponding bridge */ - unsigned int ignore_hotplug:1; /* Ignore hotplug events */ - unsigned int hotplug_user_indicators:1; /* SlotCtl indicators - controlled exclusively by - user sysfs */ - unsigned int d3_delay; /* D3->D0 transition time in ms */ - unsigned int d3cold_delay; /* D3cold->D0 transition time in ms */ - -#ifdef CONFIG_PCIEASPM - struct pcie_link_state *link_state; /* ASPM link state */ -#endif - - pci_channel_state_t error_state; /* current connectivity state */ - struct device dev; /* Generic device interface */ - - int cfg_size; /* Size of configuration space */ - - /* - * Instead of touching interrupt line and base address registers - * directly, use the values stored here. They might be different! - */ - unsigned int irq; - struct cpumask *irq_affinity; - struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */ - - bool match_driver; /* Skip attaching driver */ - /* These fields are used by common fixups */ - unsigned int transparent:1; /* Subtractive decode PCI bridge */ - unsigned int multifunction:1;/* Part of multi-function device */ - /* keep track of device state */ - unsigned int is_added:1; - unsigned int is_busmaster:1; /* device is busmaster */ - unsigned int no_msi:1; /* device may not use msi */ - unsigned int no_64bit_msi:1; /* device may only use 32-bit MSIs */ - unsigned int block_cfg_access:1; /* config space access is blocked */ - unsigned int broken_parity_status:1; /* Device generates false positive parity */ - unsigned int irq_reroute_variant:2; /* device needs IRQ rerouting variant */ - unsigned int msi_enabled:1; - unsigned int msix_enabled:1; - unsigned int ari_enabled:1; /* ARI forwarding */ - unsigned int ats_enabled:1; /* Address Translation Service */ - unsigned int is_managed:1; - unsigned int needs_freset:1; /* Dev requires fundamental reset */ - unsigned int state_saved:1; - unsigned int is_physfn:1; - unsigned int is_virtfn:1; - unsigned int reset_fn:1; - unsigned int is_hotplug_bridge:1; - unsigned int __aer_firmware_first_valid:1; - unsigned int __aer_firmware_first:1; - unsigned int broken_intx_masking:1; - unsigned int io_window_1k:1; /* Intel P2P bridge 1K I/O windows */ - unsigned int irq_managed:1; - unsigned int has_secondary_link:1; - unsigned int non_compliant_bars:1; /* broken BARs; ignore them */ - pci_dev_flags_t dev_flags; - atomic_t enable_cnt; /* pci_enable_device has been called */ - - u32 saved_config_space[16]; /* config space saved at suspend time */ - struct hlist_head saved_cap_space; - struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */ - int rom_attr_enabled; /* has display of the rom attribute been enabled? */ - struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */ - struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */ - -#ifdef CONFIG_PCIE_PTM - unsigned int ptm_root:1; - unsigned int ptm_enabled:1; - u8 ptm_granularity; -#endif -#ifdef CONFIG_PCI_MSI - const struct attribute_group **msi_irq_groups; -#endif - struct pci_vpd *vpd; -#ifdef CONFIG_PCI_ATS - union { - struct pci_sriov *sriov; /* SR-IOV capability related */ - struct pci_dev *physfn; /* the PF this VF is associated with */ - }; - u16 ats_cap; /* ATS Capability offset */ - u8 ats_stu; /* ATS Smallest Translation Unit */ - atomic_t ats_ref_cnt; /* number of VFs with ATS enabled */ -#endif - phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */ - size_t romlen; /* Length of ROM if it's not from the BAR */ - char *driver_override; /* Driver name to force a match */ -}; - -static inline struct pci_dev *pci_physfn(struct pci_dev *dev) -{ -#ifdef CONFIG_PCI_IOV - if (dev->is_virtfn) - dev = dev->physfn; -#endif - return dev; -} - -struct pci_dev *pci_alloc_dev(struct pci_bus *bus); - -#define to_pci_dev(n) container_of(n, struct pci_dev, dev) -#define for_each_pci_dev(d) while ((d = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, d)) != NULL) - -static inline int pci_channel_offline(struct pci_dev *pdev) -{ - return (pdev->error_state != pci_channel_io_normal); -} - -struct pci_host_bridge { - struct device dev; - struct pci_bus *bus; /* root bus */ - struct list_head windows; /* resource_entry */ - void (*release_fn)(struct pci_host_bridge *); - void *release_data; - unsigned int ignore_reset_delay:1; /* for entire hierarchy */ - /* Resource alignment requirements */ - resource_size_t (*align_resource)(struct pci_dev *dev, - const struct resource *res, - resource_size_t start, - resource_size_t size, - resource_size_t align); -}; - -#define to_pci_host_bridge(n) container_of(n, struct pci_host_bridge, dev) - -struct pci_host_bridge *pci_find_host_bridge(struct pci_bus *bus); - -void pci_set_host_bridge_release(struct pci_host_bridge *bridge, - void (*release_fn)(struct pci_host_bridge *), - void *release_data); - -int pcibios_root_bridge_prepare(struct pci_host_bridge *bridge); - -/* - * The first PCI_BRIDGE_RESOURCE_NUM PCI bus resources (those that correspond - * to P2P or CardBus bridge windows) go in a table. Additional ones (for - * buses below host bridges or subtractive decode bridges) go in the list. - * Use pci_bus_for_each_resource() to iterate through all the resources. - */ - -/* - * PCI_SUBTRACTIVE_DECODE means the bridge forwards the window implicitly - * and there's no way to program the bridge with the details of the window. - * This does not apply to ACPI _CRS windows, even with the _DEC subtractive- - * decode bit set, because they are explicit and can be programmed with _SRS. - */ -#define PCI_SUBTRACTIVE_DECODE 0x1 - -struct pci_bus_resource { - struct list_head list; - struct resource *res; - unsigned int flags; -}; - -#define PCI_REGION_FLAG_MASK 0x0fU /* These bits of resource flags tell us the PCI region flags */ - -struct pci_bus { - struct list_head node; /* node in list of buses */ - struct pci_bus *parent; /* parent bus this bridge is on */ - struct list_head children; /* list of child buses */ - struct list_head devices; /* list of devices on this bus */ - struct pci_dev *self; /* bridge device as seen by parent */ - struct list_head slots; /* list of slots on this bus; - protected by pci_slot_mutex */ - struct resource *resource[PCI_BRIDGE_RESOURCE_NUM]; - struct list_head resources; /* address space routed to this bus */ - struct resource busn_res; /* bus numbers routed to this bus */ - - struct pci_ops *ops; /* configuration access functions */ - struct msi_controller *msi; /* MSI controller */ - void *sysdata; /* hook for sys-specific extension */ - struct proc_dir_entry *procdir; /* directory entry in /proc/bus/pci */ - - unsigned char number; /* bus number */ - unsigned char primary; /* number of primary bridge */ - unsigned char max_bus_speed; /* enum pci_bus_speed */ - unsigned char cur_bus_speed; /* enum pci_bus_speed */ -#ifdef CONFIG_PCI_DOMAINS_GENERIC - int domain_nr; -#endif - - char name[48]; - - unsigned short bridge_ctl; /* manage NO_ISA/FBB/et al behaviors */ - pci_bus_flags_t bus_flags; /* inherited by child buses */ - struct device *bridge; - struct device dev; - struct bin_attribute *legacy_io; /* legacy I/O for this bus */ - struct bin_attribute *legacy_mem; /* legacy mem */ - unsigned int is_added:1; -}; - -#define to_pci_bus(n) container_of(n, struct pci_bus, dev) - -/* - * Returns true if the PCI bus is root (behind host-PCI bridge), - * false otherwise - * - * Some code assumes that "bus->self == NULL" means that bus is a root bus. - * This is incorrect because "virtual" buses added for SR-IOV (via - * virtfn_add_bus()) have "bus->self == NULL" but are not root buses. - */ -static inline bool pci_is_root_bus(struct pci_bus *pbus) -{ - return !(pbus->parent); -} - -/** - * pci_is_bridge - check if the PCI device is a bridge - * @dev: PCI device - * - * Return true if the PCI device is bridge whether it has subordinate - * or not. - */ -static inline bool pci_is_bridge(struct pci_dev *dev) -{ - return dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS; -} - -static inline struct pci_dev *pci_upstream_bridge(struct pci_dev *dev) -{ - dev = pci_physfn(dev); - if (pci_is_root_bus(dev->bus)) - return NULL; - - return dev->bus->self; -} - -struct device *pci_get_host_bridge_device(struct pci_dev *dev); -void pci_put_host_bridge_device(struct device *dev); - -#ifdef CONFIG_PCI_MSI -static inline bool pci_dev_msi_enabled(struct pci_dev *pci_dev) -{ - return pci_dev->msi_enabled || pci_dev->msix_enabled; -} -#else -static inline bool pci_dev_msi_enabled(struct pci_dev *pci_dev) { return false; } -#endif - -/* - * Error values that may be returned by PCI functions. - */ -#define PCIBIOS_SUCCESSFUL 0x00 -#define PCIBIOS_FUNC_NOT_SUPPORTED 0x81 -#define PCIBIOS_BAD_VENDOR_ID 0x83 -#define PCIBIOS_DEVICE_NOT_FOUND 0x86 -#define PCIBIOS_BAD_REGISTER_NUMBER 0x87 -#define PCIBIOS_SET_FAILED 0x88 -#define PCIBIOS_BUFFER_TOO_SMALL 0x89 - -/* - * Translate above to generic errno for passing back through non-PCI code. - */ -static inline int pcibios_err_to_errno(int err) -{ - if (err <= PCIBIOS_SUCCESSFUL) - return err; /* Assume already errno */ - - switch (err) { - case PCIBIOS_FUNC_NOT_SUPPORTED: - return -ENOENT; - case PCIBIOS_BAD_VENDOR_ID: - return -ENOTTY; - case PCIBIOS_DEVICE_NOT_FOUND: - return -ENODEV; - case PCIBIOS_BAD_REGISTER_NUMBER: - return -EFAULT; - case PCIBIOS_SET_FAILED: - return -EIO; - case PCIBIOS_BUFFER_TOO_SMALL: - return -ENOSPC; - } - - return -ERANGE; -} - -/* Low-level architecture-dependent routines */ - -struct pci_ops { - int (*add_bus)(struct pci_bus *bus); - void (*remove_bus)(struct pci_bus *bus); - void __iomem *(*map_bus)(struct pci_bus *bus, unsigned int devfn, int where); - int (*read)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *val); - int (*write)(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 val); -}; - -/* - * ACPI needs to be able to access PCI config space before we've done a - * PCI bus scan and created pci_bus structures. - */ -int raw_pci_read(unsigned int domain, unsigned int bus, unsigned int devfn, - int reg, int len, u32 *val); -int raw_pci_write(unsigned int domain, unsigned int bus, unsigned int devfn, - int reg, int len, u32 val); - -#ifdef CONFIG_PCI_BUS_ADDR_T_64BIT -typedef u64 pci_bus_addr_t; -#else -typedef u32 pci_bus_addr_t; -#endif - -struct pci_bus_region { - pci_bus_addr_t start; - pci_bus_addr_t end; -}; - -struct pci_dynids { - spinlock_t lock; /* protects list, index */ - struct list_head list; /* for IDs added at runtime */ -}; - - -/* - * PCI Error Recovery System (PCI-ERS). If a PCI device driver provides - * a set of callbacks in struct pci_error_handlers, that device driver - * will be notified of PCI bus errors, and will be driven to recovery - * when an error occurs. - */ - -typedef unsigned int __bitwise pci_ers_result_t; - -enum pci_ers_result { - /* no result/none/not supported in device driver */ - PCI_ERS_RESULT_NONE = (__force pci_ers_result_t) 1, - - /* Device driver can recover without slot reset */ - PCI_ERS_RESULT_CAN_RECOVER = (__force pci_ers_result_t) 2, - - /* Device driver wants slot to be reset. */ - PCI_ERS_RESULT_NEED_RESET = (__force pci_ers_result_t) 3, - - /* Device has completely failed, is unrecoverable */ - PCI_ERS_RESULT_DISCONNECT = (__force pci_ers_result_t) 4, - - /* Device driver is fully recovered and operational */ - PCI_ERS_RESULT_RECOVERED = (__force pci_ers_result_t) 5, - - /* No AER capabilities registered for the driver */ - PCI_ERS_RESULT_NO_AER_DRIVER = (__force pci_ers_result_t) 6, -}; - -/* PCI bus error event callbacks */ -struct pci_error_handlers { - /* PCI bus error detected on this device */ - pci_ers_result_t (*error_detected)(struct pci_dev *dev, - enum pci_channel_state error); - - /* MMIO has been re-enabled, but not DMA */ - pci_ers_result_t (*mmio_enabled)(struct pci_dev *dev); - - /* PCI Express link has been reset */ - pci_ers_result_t (*link_reset)(struct pci_dev *dev); - - /* PCI slot has been reset */ - pci_ers_result_t (*slot_reset)(struct pci_dev *dev); - - /* PCI function reset prepare or completed */ - void (*reset_notify)(struct pci_dev *dev, bool prepare); - - /* Device driver may resume normal operations */ - void (*resume)(struct pci_dev *dev); -}; - - -struct module; -struct pci_driver { - struct list_head node; - const char *name; - const struct pci_device_id *id_table; /* must be non-NULL for probe to be called */ - int (*probe) (struct pci_dev *dev, const struct pci_device_id *id); /* New device inserted */ - void (*remove) (struct pci_dev *dev); /* Device removed (NULL if not a hot-plug capable driver) */ - int (*suspend) (struct pci_dev *dev, pm_message_t state); /* Device suspended */ - int (*suspend_late) (struct pci_dev *dev, pm_message_t state); - int (*resume_early) (struct pci_dev *dev); - int (*resume) (struct pci_dev *dev); /* Device woken up */ - void (*shutdown) (struct pci_dev *dev); - int (*sriov_configure) (struct pci_dev *dev, int num_vfs); /* PF pdev */ - const struct pci_error_handlers *err_handler; - struct device_driver driver; - struct pci_dynids dynids; -}; - -#define to_pci_driver(drv) container_of(drv, struct pci_driver, driver) - -/** - * PCI_DEVICE - macro used to describe a specific pci device - * @vend: the 16 bit PCI Vendor ID - * @dev: the 16 bit PCI Device ID - * - * This macro is used to create a struct pci_device_id that matches a - * specific device. The subvendor and subdevice fields will be set to - * PCI_ANY_ID. - */ -#define PCI_DEVICE(vend,dev) \ - .vendor = (vend), .device = (dev), \ - .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID - -/** - * PCI_DEVICE_SUB - macro used to describe a specific pci device with subsystem - * @vend: the 16 bit PCI Vendor ID - * @dev: the 16 bit PCI Device ID - * @subvend: the 16 bit PCI Subvendor ID - * @subdev: the 16 bit PCI Subdevice ID - * - * This macro is used to create a struct pci_device_id that matches a - * specific device with subsystem information. - */ -#define PCI_DEVICE_SUB(vend, dev, subvend, subdev) \ - .vendor = (vend), .device = (dev), \ - .subvendor = (subvend), .subdevice = (subdev) - -/** - * PCI_DEVICE_CLASS - macro used to describe a specific pci device class - * @dev_class: the class, subclass, prog-if triple for this device - * @dev_class_mask: the class mask for this device - * - * This macro is used to create a struct pci_device_id that matches a - * specific PCI class. The vendor, device, subvendor, and subdevice - * fields will be set to PCI_ANY_ID. - */ -#define PCI_DEVICE_CLASS(dev_class,dev_class_mask) \ - .class = (dev_class), .class_mask = (dev_class_mask), \ - .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \ - .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID - -/** - * PCI_VDEVICE - macro used to describe a specific pci device in short form - * @vend: the vendor name - * @dev: the 16 bit PCI Device ID - * - * This macro is used to create a struct pci_device_id that matches a - * specific PCI device. The subvendor, and subdevice fields will be set - * to PCI_ANY_ID. The macro allows the next field to follow as the device - * private data. - */ - -#define PCI_VDEVICE(vend, dev) \ - .vendor = PCI_VENDOR_ID_##vend, .device = (dev), \ - .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, 0, 0 - -enum { - PCI_REASSIGN_ALL_RSRC = 0x00000001, /* ignore firmware setup */ - PCI_REASSIGN_ALL_BUS = 0x00000002, /* reassign all bus numbers */ - PCI_PROBE_ONLY = 0x00000004, /* use existing setup */ - PCI_CAN_SKIP_ISA_ALIGN = 0x00000008, /* don't do ISA alignment */ - PCI_ENABLE_PROC_DOMAINS = 0x00000010, /* enable domains in /proc */ - PCI_COMPAT_DOMAIN_0 = 0x00000020, /* ... except domain 0 */ - PCI_SCAN_ALL_PCIE_DEVS = 0x00000040, /* scan all, not just dev 0 */ -}; - -/* these external functions are only available when PCI support is enabled */ -#ifdef CONFIG_PCI - -extern unsigned int pci_flags; - -static inline void pci_set_flags(int flags) { pci_flags = flags; } -static inline void pci_add_flags(int flags) { pci_flags |= flags; } -static inline void pci_clear_flags(int flags) { pci_flags &= ~flags; } -static inline int pci_has_flag(int flag) { return pci_flags & flag; } - -void pcie_bus_configure_settings(struct pci_bus *bus); - -enum pcie_bus_config_types { - PCIE_BUS_TUNE_OFF, /* don't touch MPS at all */ - PCIE_BUS_DEFAULT, /* ensure MPS matches upstream bridge */ - PCIE_BUS_SAFE, /* use largest MPS boot-time devices support */ - PCIE_BUS_PERFORMANCE, /* use MPS and MRRS for best performance */ - PCIE_BUS_PEER2PEER, /* set MPS = 128 for all devices */ -}; - -extern enum pcie_bus_config_types pcie_bus_config; - -extern struct bus_type pci_bus_type; - -/* Do NOT directly access these two variables, unless you are arch-specific PCI - * code, or PCI core code. */ -extern struct list_head pci_root_buses; /* list of all known PCI buses */ -/* Some device drivers need know if PCI is initiated */ -int no_pci_devices(void); - -void pcibios_resource_survey_bus(struct pci_bus *bus); -void pcibios_bus_add_device(struct pci_dev *pdev); -void pcibios_add_bus(struct pci_bus *bus); -void pcibios_remove_bus(struct pci_bus *bus); -void pcibios_fixup_bus(struct pci_bus *); -int __must_check pcibios_enable_device(struct pci_dev *, int mask); -/* Architecture-specific versions may override this (weak) */ -char *pcibios_setup(char *str); - -/* Used only when drivers/pci/setup.c is used */ -resource_size_t pcibios_align_resource(void *, const struct resource *, - resource_size_t, - resource_size_t); -void pcibios_update_irq(struct pci_dev *, int irq); - -/* Weak but can be overriden by arch */ -void pci_fixup_cardbus(struct pci_bus *); - -/* Generic PCI functions used internally */ - -void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region, - struct resource *res); -void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res, - struct pci_bus_region *region); -void pcibios_scan_specific_bus(int busn); -struct pci_bus *pci_find_bus(int domain, int busnr); -void pci_bus_add_devices(const struct pci_bus *bus); -struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata); -struct pci_bus *pci_create_root_bus(struct device *parent, int bus, - struct pci_ops *ops, void *sysdata, - struct list_head *resources); -int pci_bus_insert_busn_res(struct pci_bus *b, int bus, int busmax); -int pci_bus_update_busn_res_end(struct pci_bus *b, int busmax); -void pci_bus_release_busn_res(struct pci_bus *b); -struct pci_bus *pci_scan_root_bus_msi(struct device *parent, int bus, - struct pci_ops *ops, void *sysdata, - struct list_head *resources, - struct msi_controller *msi); -struct pci_bus *pci_scan_root_bus(struct device *parent, int bus, - struct pci_ops *ops, void *sysdata, - struct list_head *resources); -struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, - int busnr); -void pcie_update_link_speed(struct pci_bus *bus, u16 link_status); -struct pci_slot *pci_create_slot(struct pci_bus *parent, int slot_nr, - const char *name, - struct hotplug_slot *hotplug); -void pci_destroy_slot(struct pci_slot *slot); -#ifdef CONFIG_SYSFS -void pci_dev_assign_slot(struct pci_dev *dev); -#else -static inline void pci_dev_assign_slot(struct pci_dev *dev) { } -#endif -int pci_scan_slot(struct pci_bus *bus, int devfn); -struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn); -void pci_device_add(struct pci_dev *dev, struct pci_bus *bus); -unsigned int pci_scan_child_bus(struct pci_bus *bus); -void pci_bus_add_device(struct pci_dev *dev); -void pci_read_bridge_bases(struct pci_bus *child); -struct resource *pci_find_parent_resource(const struct pci_dev *dev, - struct resource *res); -struct pci_dev *pci_find_pcie_root_port(struct pci_dev *dev); -u8 pci_swizzle_interrupt_pin(const struct pci_dev *dev, u8 pin); -int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge); -u8 pci_common_swizzle(struct pci_dev *dev, u8 *pinp); -struct pci_dev *pci_dev_get(struct pci_dev *dev); -void pci_dev_put(struct pci_dev *dev); -void pci_remove_bus(struct pci_bus *b); -void pci_stop_and_remove_bus_device(struct pci_dev *dev); -void pci_stop_and_remove_bus_device_locked(struct pci_dev *dev); -void pci_stop_root_bus(struct pci_bus *bus); -void pci_remove_root_bus(struct pci_bus *bus); -void pci_setup_cardbus(struct pci_bus *bus); -void pcibios_setup_bridge(struct pci_bus *bus, unsigned long type); -void pci_sort_breadthfirst(void); -#define dev_is_pci(d) ((d)->bus == &pci_bus_type) -#define dev_is_pf(d) ((dev_is_pci(d) ? to_pci_dev(d)->is_physfn : false)) -#define dev_num_vf(d) ((dev_is_pci(d) ? pci_num_vf(to_pci_dev(d)) : 0)) - -/* Generic PCI functions exported to card drivers */ - -enum pci_lost_interrupt_reason { - PCI_LOST_IRQ_NO_INFORMATION = 0, - PCI_LOST_IRQ_DISABLE_MSI, - PCI_LOST_IRQ_DISABLE_MSIX, - PCI_LOST_IRQ_DISABLE_ACPI, -}; -enum pci_lost_interrupt_reason pci_lost_interrupt(struct pci_dev *dev); -int pci_find_capability(struct pci_dev *dev, int cap); -int pci_find_next_capability(struct pci_dev *dev, u8 pos, int cap); -int pci_find_ext_capability(struct pci_dev *dev, int cap); -int pci_find_next_ext_capability(struct pci_dev *dev, int pos, int cap); -int pci_find_ht_capability(struct pci_dev *dev, int ht_cap); -int pci_find_next_ht_capability(struct pci_dev *dev, int pos, int ht_cap); -struct pci_bus *pci_find_next_bus(const struct pci_bus *from); - -struct pci_dev *pci_get_device(unsigned int vendor, unsigned int device, - struct pci_dev *from); -struct pci_dev *pci_get_subsys(unsigned int vendor, unsigned int device, - unsigned int ss_vendor, unsigned int ss_device, - struct pci_dev *from); -struct pci_dev *pci_get_slot(struct pci_bus *bus, unsigned int devfn); -struct pci_dev *pci_get_domain_bus_and_slot(int domain, unsigned int bus, - unsigned int devfn); -static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus, - unsigned int devfn) -{ - return pci_get_domain_bus_and_slot(0, bus, devfn); -} -struct pci_dev *pci_get_class(unsigned int class, struct pci_dev *from); -int pci_dev_present(const struct pci_device_id *ids); - -int pci_bus_read_config_byte(struct pci_bus *bus, unsigned int devfn, - int where, u8 *val); -int pci_bus_read_config_word(struct pci_bus *bus, unsigned int devfn, - int where, u16 *val); -int pci_bus_read_config_dword(struct pci_bus *bus, unsigned int devfn, - int where, u32 *val); -int pci_bus_write_config_byte(struct pci_bus *bus, unsigned int devfn, - int where, u8 val); -int pci_bus_write_config_word(struct pci_bus *bus, unsigned int devfn, - int where, u16 val); -int pci_bus_write_config_dword(struct pci_bus *bus, unsigned int devfn, - int where, u32 val); - -int pci_generic_config_read(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 *val); -int pci_generic_config_write(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 val); -int pci_generic_config_read32(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 *val); -int pci_generic_config_write32(struct pci_bus *bus, unsigned int devfn, - int where, int size, u32 val); - -struct pci_ops *pci_bus_set_ops(struct pci_bus *bus, struct pci_ops *ops); - -static inline int pci_read_config_byte(const struct pci_dev *dev, int where, u8 *val) -{ - return pci_bus_read_config_byte(dev->bus, dev->devfn, where, val); -} -static inline int pci_read_config_word(const struct pci_dev *dev, int where, u16 *val) -{ - return pci_bus_read_config_word(dev->bus, dev->devfn, where, val); -} -static inline int pci_read_config_dword(const struct pci_dev *dev, int where, - u32 *val) -{ - return pci_bus_read_config_dword(dev->bus, dev->devfn, where, val); -} -static inline int pci_write_config_byte(const struct pci_dev *dev, int where, u8 val) -{ - return pci_bus_write_config_byte(dev->bus, dev->devfn, where, val); -} -static inline int pci_write_config_word(const struct pci_dev *dev, int where, u16 val) -{ - return pci_bus_write_config_word(dev->bus, dev->devfn, where, val); -} -static inline int pci_write_config_dword(const struct pci_dev *dev, int where, - u32 val) -{ - return pci_bus_write_config_dword(dev->bus, dev->devfn, where, val); -} - -int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val); -int pcie_capability_read_dword(struct pci_dev *dev, int pos, u32 *val); -int pcie_capability_write_word(struct pci_dev *dev, int pos, u16 val); -int pcie_capability_write_dword(struct pci_dev *dev, int pos, u32 val); -int pcie_capability_clear_and_set_word(struct pci_dev *dev, int pos, - u16 clear, u16 set); -int pcie_capability_clear_and_set_dword(struct pci_dev *dev, int pos, - u32 clear, u32 set); - -static inline int pcie_capability_set_word(struct pci_dev *dev, int pos, - u16 set) -{ - return pcie_capability_clear_and_set_word(dev, pos, 0, set); -} - -static inline int pcie_capability_set_dword(struct pci_dev *dev, int pos, - u32 set) -{ - return pcie_capability_clear_and_set_dword(dev, pos, 0, set); -} - -static inline int pcie_capability_clear_word(struct pci_dev *dev, int pos, - u16 clear) -{ - return pcie_capability_clear_and_set_word(dev, pos, clear, 0); -} - -static inline int pcie_capability_clear_dword(struct pci_dev *dev, int pos, - u32 clear) -{ - return pcie_capability_clear_and_set_dword(dev, pos, clear, 0); -} - -/* user-space driven config access */ -int pci_user_read_config_byte(struct pci_dev *dev, int where, u8 *val); -int pci_user_read_config_word(struct pci_dev *dev, int where, u16 *val); -int pci_user_read_config_dword(struct pci_dev *dev, int where, u32 *val); -int pci_user_write_config_byte(struct pci_dev *dev, int where, u8 val); -int pci_user_write_config_word(struct pci_dev *dev, int where, u16 val); -int pci_user_write_config_dword(struct pci_dev *dev, int where, u32 val); - -int __must_check pci_enable_device(struct pci_dev *dev); -int __must_check pci_enable_device_io(struct pci_dev *dev); -int __must_check pci_enable_device_mem(struct pci_dev *dev); -int __must_check pci_reenable_device(struct pci_dev *); -int __must_check pcim_enable_device(struct pci_dev *pdev); -void pcim_pin_device(struct pci_dev *pdev); - -static inline int pci_is_enabled(struct pci_dev *pdev) -{ - return (atomic_read(&pdev->enable_cnt) > 0); -} - -static inline int pci_is_managed(struct pci_dev *pdev) -{ - return pdev->is_managed; -} - -void pci_disable_device(struct pci_dev *dev); - -extern unsigned int pcibios_max_latency; -void pci_set_master(struct pci_dev *dev); -void pci_clear_master(struct pci_dev *dev); - -int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state); -int pci_set_cacheline_size(struct pci_dev *dev); -#define HAVE_PCI_SET_MWI -int __must_check pci_set_mwi(struct pci_dev *dev); -int pci_try_set_mwi(struct pci_dev *dev); -void pci_clear_mwi(struct pci_dev *dev); -void pci_intx(struct pci_dev *dev, int enable); -bool pci_intx_mask_supported(struct pci_dev *dev); -bool pci_check_and_mask_intx(struct pci_dev *dev); -bool pci_check_and_unmask_intx(struct pci_dev *dev); -int pci_wait_for_pending(struct pci_dev *dev, int pos, u16 mask); -int pci_wait_for_pending_transaction(struct pci_dev *dev); -int pcix_get_max_mmrbc(struct pci_dev *dev); -int pcix_get_mmrbc(struct pci_dev *dev); -int pcix_set_mmrbc(struct pci_dev *dev, int mmrbc); -int pcie_get_readrq(struct pci_dev *dev); -int pcie_set_readrq(struct pci_dev *dev, int rq); -int pcie_get_mps(struct pci_dev *dev); -int pcie_set_mps(struct pci_dev *dev, int mps); -int pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed, - enum pcie_link_width *width); -int __pci_reset_function(struct pci_dev *dev); -int __pci_reset_function_locked(struct pci_dev *dev); -int pci_reset_function(struct pci_dev *dev); -int pci_try_reset_function(struct pci_dev *dev); -int pci_probe_reset_slot(struct pci_slot *slot); -int pci_reset_slot(struct pci_slot *slot); -int pci_try_reset_slot(struct pci_slot *slot); -int pci_probe_reset_bus(struct pci_bus *bus); -int pci_reset_bus(struct pci_bus *bus); -int pci_try_reset_bus(struct pci_bus *bus); -void pci_reset_secondary_bus(struct pci_dev *dev); -void pcibios_reset_secondary_bus(struct pci_dev *dev); -void pci_reset_bridge_secondary_bus(struct pci_dev *dev); -void pci_update_resource(struct pci_dev *dev, int resno); -int __must_check pci_assign_resource(struct pci_dev *dev, int i); -int __must_check pci_reassign_resource(struct pci_dev *dev, int i, resource_size_t add_size, resource_size_t align); -int pci_select_bars(struct pci_dev *dev, unsigned long flags); -bool pci_device_is_present(struct pci_dev *pdev); -void pci_ignore_hotplug(struct pci_dev *dev); - -/* ROM control related routines */ -int pci_enable_rom(struct pci_dev *pdev); -void pci_disable_rom(struct pci_dev *pdev); -void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size); -void pci_unmap_rom(struct pci_dev *pdev, void __iomem *rom); -size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size); -void __iomem __must_check *pci_platform_rom(struct pci_dev *pdev, size_t *size); - -/* Power management related routines */ -int pci_save_state(struct pci_dev *dev); -void pci_restore_state(struct pci_dev *dev); -struct pci_saved_state *pci_store_saved_state(struct pci_dev *dev); -int pci_load_saved_state(struct pci_dev *dev, - struct pci_saved_state *state); -int pci_load_and_free_saved_state(struct pci_dev *dev, - struct pci_saved_state **state); -struct pci_cap_saved_state *pci_find_saved_cap(struct pci_dev *dev, char cap); -struct pci_cap_saved_state *pci_find_saved_ext_cap(struct pci_dev *dev, - u16 cap); -int pci_add_cap_save_buffer(struct pci_dev *dev, char cap, unsigned int size); -int pci_add_ext_cap_save_buffer(struct pci_dev *dev, - u16 cap, unsigned int size); -int __pci_complete_power_transition(struct pci_dev *dev, pci_power_t state); -int pci_set_power_state(struct pci_dev *dev, pci_power_t state); -pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state); -bool pci_pme_capable(struct pci_dev *dev, pci_power_t state); -void pci_pme_active(struct pci_dev *dev, bool enable); -int __pci_enable_wake(struct pci_dev *dev, pci_power_t state, - bool runtime, bool enable); -int pci_wake_from_d3(struct pci_dev *dev, bool enable); -int pci_prepare_to_sleep(struct pci_dev *dev); -int pci_back_from_sleep(struct pci_dev *dev); -bool pci_dev_run_wake(struct pci_dev *dev); -bool pci_check_pme_status(struct pci_dev *dev); -void pci_pme_wakeup_bus(struct pci_bus *bus); -void pci_d3cold_enable(struct pci_dev *dev); -void pci_d3cold_disable(struct pci_dev *dev); - -static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, - bool enable) -{ - return __pci_enable_wake(dev, state, false, enable); -} - -/* PCI Virtual Channel */ -int pci_save_vc_state(struct pci_dev *dev); -void pci_restore_vc_state(struct pci_dev *dev); -void pci_allocate_vc_save_buffers(struct pci_dev *dev); - -/* For use by arch with custom probe code */ -void set_pcie_port_type(struct pci_dev *pdev); -void set_pcie_hotplug_bridge(struct pci_dev *pdev); - -/* Functions for PCI Hotplug drivers to use */ -int pci_bus_find_capability(struct pci_bus *bus, unsigned int devfn, int cap); -unsigned int pci_rescan_bus_bridge_resize(struct pci_dev *bridge); -unsigned int pci_rescan_bus(struct pci_bus *bus); -void pci_lock_rescan_remove(void); -void pci_unlock_rescan_remove(void); - -/* Vital product data routines */ -ssize_t pci_read_vpd(struct pci_dev *dev, loff_t pos, size_t count, void *buf); -ssize_t pci_write_vpd(struct pci_dev *dev, loff_t pos, size_t count, const void *buf); -int pci_set_vpd_size(struct pci_dev *dev, size_t len); - -/* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */ -resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx); -void pci_bus_assign_resources(const struct pci_bus *bus); -void pci_bus_claim_resources(struct pci_bus *bus); -void pci_bus_size_bridges(struct pci_bus *bus); -int pci_claim_resource(struct pci_dev *, int); -int pci_claim_bridge_resource(struct pci_dev *bridge, int i); -void pci_assign_unassigned_resources(void); -void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge); -void pci_assign_unassigned_bus_resources(struct pci_bus *bus); -void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus); -void pdev_enable_device(struct pci_dev *); -int pci_enable_resources(struct pci_dev *, int mask); -void pci_fixup_irqs(u8 (*)(struct pci_dev *, u8 *), - int (*)(const struct pci_dev *, u8, u8)); -struct resource *pci_find_resource(struct pci_dev *dev, struct resource *res); -#define HAVE_PCI_REQ_REGIONS 2 -int __must_check pci_request_regions(struct pci_dev *, const char *); -int __must_check pci_request_regions_exclusive(struct pci_dev *, const char *); -void pci_release_regions(struct pci_dev *); -int __must_check pci_request_region(struct pci_dev *, int, const char *); -int __must_check pci_request_region_exclusive(struct pci_dev *, int, const char *); -void pci_release_region(struct pci_dev *, int); -int pci_request_selected_regions(struct pci_dev *, int, const char *); -int pci_request_selected_regions_exclusive(struct pci_dev *, int, const char *); -void pci_release_selected_regions(struct pci_dev *, int); - -/* drivers/pci/bus.c */ -struct pci_bus *pci_bus_get(struct pci_bus *bus); -void pci_bus_put(struct pci_bus *bus); -void pci_add_resource(struct list_head *resources, struct resource *res); -void pci_add_resource_offset(struct list_head *resources, struct resource *res, - resource_size_t offset); -void pci_free_resource_list(struct list_head *resources); -void pci_bus_add_resource(struct pci_bus *bus, struct resource *res, - unsigned int flags); -struct resource *pci_bus_resource_n(const struct pci_bus *bus, int n); -void pci_bus_remove_resources(struct pci_bus *bus); -int devm_request_pci_bus_resources(struct device *dev, - struct list_head *resources); - -#define pci_bus_for_each_resource(bus, res, i) \ - for (i = 0; \ - (res = pci_bus_resource_n(bus, i)) || i < PCI_BRIDGE_RESOURCE_NUM; \ - i++) - -int __must_check pci_bus_alloc_resource(struct pci_bus *bus, - struct resource *res, resource_size_t size, - resource_size_t align, resource_size_t min, - unsigned long type_mask, - resource_size_t (*alignf)(void *, - const struct resource *, - resource_size_t, - resource_size_t), - void *alignf_data); - - -int pci_register_io_range(phys_addr_t addr, resource_size_t size); -unsigned long pci_address_to_pio(phys_addr_t addr); -phys_addr_t pci_pio_to_address(unsigned long pio); -int pci_remap_iospace(const struct resource *res, phys_addr_t phys_addr); -void pci_unmap_iospace(struct resource *res); - -static inline pci_bus_addr_t pci_bus_address(struct pci_dev *pdev, int bar) -{ - struct pci_bus_region region; - - pcibios_resource_to_bus(pdev->bus, ®ion, &pdev->resource[bar]); - return region.start; -} - -/* Proper probing supporting hot-pluggable devices */ -int __must_check __pci_register_driver(struct pci_driver *, struct module *, - const char *mod_name); - -/* - * pci_register_driver must be a macro so that KBUILD_MODNAME can be expanded - */ -#define pci_register_driver(driver) \ - __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME) - -void pci_unregister_driver(struct pci_driver *dev); - -/** - * module_pci_driver() - Helper macro for registering a PCI driver - * @__pci_driver: pci_driver struct - * - * Helper macro for PCI drivers which do not do anything special in module - * init/exit. This eliminates a lot of boilerplate. Each module may only - * use this macro once, and calling it replaces module_init() and module_exit() - */ -#define module_pci_driver(__pci_driver) \ - module_driver(__pci_driver, pci_register_driver, \ - pci_unregister_driver) - -/** - * builtin_pci_driver() - Helper macro for registering a PCI driver - * @__pci_driver: pci_driver struct - * - * Helper macro for PCI drivers which do not do anything special in their - * init code. This eliminates a lot of boilerplate. Each driver may only - * use this macro once, and calling it replaces device_initcall(...) - */ -#define builtin_pci_driver(__pci_driver) \ - builtin_driver(__pci_driver, pci_register_driver) - -struct pci_driver *pci_dev_driver(const struct pci_dev *dev); -int pci_add_dynid(struct pci_driver *drv, - unsigned int vendor, unsigned int device, - unsigned int subvendor, unsigned int subdevice, - unsigned int class, unsigned int class_mask, - unsigned long driver_data); -const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, - struct pci_dev *dev); -int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, - int pass); - -void pci_walk_bus(struct pci_bus *top, int (*cb)(struct pci_dev *, void *), - void *userdata); -int pci_cfg_space_size(struct pci_dev *dev); -unsigned char pci_bus_max_busnr(struct pci_bus *bus); -void pci_setup_bridge(struct pci_bus *bus); -resource_size_t pcibios_window_alignment(struct pci_bus *bus, - unsigned long type); -resource_size_t pcibios_iov_resource_alignment(struct pci_dev *dev, int resno); - -#define PCI_VGA_STATE_CHANGE_BRIDGE (1 << 0) -#define PCI_VGA_STATE_CHANGE_DECODES (1 << 1) - -int pci_set_vga_state(struct pci_dev *pdev, bool decode, - unsigned int command_bits, u32 flags); - -#define PCI_IRQ_LEGACY (1 << 0) /* allow legacy interrupts */ -#define PCI_IRQ_MSI (1 << 1) /* allow MSI interrupts */ -#define PCI_IRQ_MSIX (1 << 2) /* allow MSI-X interrupts */ -#define PCI_IRQ_AFFINITY (1 << 3) /* auto-assign affinity */ -#define PCI_IRQ_ALL_TYPES \ - (PCI_IRQ_LEGACY | PCI_IRQ_MSI | PCI_IRQ_MSIX) - -/* kmem_cache style wrapper around pci_alloc_consistent() */ - -#include -#include - -#define pci_pool dma_pool -#define pci_pool_create(name, pdev, size, align, allocation) \ - dma_pool_create(name, &pdev->dev, size, align, allocation) -#define pci_pool_destroy(pool) dma_pool_destroy(pool) -#define pci_pool_alloc(pool, flags, handle) dma_pool_alloc(pool, flags, handle) -#define pci_pool_zalloc(pool, flags, handle) \ - dma_pool_zalloc(pool, flags, handle) -#define pci_pool_free(pool, vaddr, addr) dma_pool_free(pool, vaddr, addr) - -struct msix_entry { - u32 vector; /* kernel uses to write allocated vector */ - u16 entry; /* driver uses to specify entry, OS writes */ -}; - -#ifdef CONFIG_PCI_MSI -int pci_msi_vec_count(struct pci_dev *dev); -void pci_msi_shutdown(struct pci_dev *dev); -void pci_disable_msi(struct pci_dev *dev); -int pci_msix_vec_count(struct pci_dev *dev); -int pci_enable_msix(struct pci_dev *dev, struct msix_entry *entries, int nvec); -void pci_msix_shutdown(struct pci_dev *dev); -void pci_disable_msix(struct pci_dev *dev); -void pci_restore_msi_state(struct pci_dev *dev); -int pci_msi_enabled(void); -int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec); -static inline int pci_enable_msi_exact(struct pci_dev *dev, int nvec) -{ - int rc = pci_enable_msi_range(dev, nvec, nvec); - if (rc < 0) - return rc; - return 0; -} -int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, - int minvec, int maxvec); -static inline int pci_enable_msix_exact(struct pci_dev *dev, - struct msix_entry *entries, int nvec) -{ - int rc = pci_enable_msix_range(dev, entries, nvec, nvec); - if (rc < 0) - return rc; - return 0; -} -int pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs, - unsigned int max_vecs, unsigned int flags); -void pci_free_irq_vectors(struct pci_dev *dev); -int pci_irq_vector(struct pci_dev *dev, unsigned int nr); -const struct cpumask *pci_irq_get_affinity(struct pci_dev *pdev, int vec); - -#else -static inline int pci_msi_vec_count(struct pci_dev *dev) { return -ENOSYS; } -static inline void pci_msi_shutdown(struct pci_dev *dev) { } -static inline void pci_disable_msi(struct pci_dev *dev) { } -static inline int pci_msix_vec_count(struct pci_dev *dev) { return -ENOSYS; } -static inline int pci_enable_msix(struct pci_dev *dev, - struct msix_entry *entries, int nvec) -{ return -ENOSYS; } -static inline void pci_msix_shutdown(struct pci_dev *dev) { } -static inline void pci_disable_msix(struct pci_dev *dev) { } -static inline void pci_restore_msi_state(struct pci_dev *dev) { } -static inline int pci_msi_enabled(void) { return 0; } -static inline int pci_enable_msi_range(struct pci_dev *dev, int minvec, - int maxvec) -{ return -ENOSYS; } -static inline int pci_enable_msi_exact(struct pci_dev *dev, int nvec) -{ return -ENOSYS; } -static inline int pci_enable_msix_range(struct pci_dev *dev, - struct msix_entry *entries, int minvec, int maxvec) -{ return -ENOSYS; } -static inline int pci_enable_msix_exact(struct pci_dev *dev, - struct msix_entry *entries, int nvec) -{ return -ENOSYS; } -static inline int pci_alloc_irq_vectors(struct pci_dev *dev, - unsigned int min_vecs, unsigned int max_vecs, - unsigned int flags) -{ - if (min_vecs > 1) - return -EINVAL; - return 1; -} -static inline void pci_free_irq_vectors(struct pci_dev *dev) -{ -} - -static inline int pci_irq_vector(struct pci_dev *dev, unsigned int nr) -{ - if (WARN_ON_ONCE(nr > 0)) - return -EINVAL; - return dev->irq; -} -static inline const struct cpumask *pci_irq_get_affinity(struct pci_dev *pdev, - int vec) -{ - return cpu_possible_mask; -} -#endif - -#ifdef CONFIG_PCIEPORTBUS -extern bool pcie_ports_disabled; -extern bool pcie_ports_auto; -#else -#define pcie_ports_disabled true -#define pcie_ports_auto false -#endif - -#ifdef CONFIG_PCIEASPM -bool pcie_aspm_support_enabled(void); -#else -static inline bool pcie_aspm_support_enabled(void) { return false; } -#endif - -#ifdef CONFIG_PCIEAER -void pci_no_aer(void); -bool pci_aer_available(void); -int pci_aer_init(struct pci_dev *dev); -#else -static inline void pci_no_aer(void) { } -static inline bool pci_aer_available(void) { return false; } -static inline int pci_aer_init(struct pci_dev *d) { return -ENODEV; } -#endif - -#ifdef CONFIG_PCIE_ECRC -void pcie_set_ecrc_checking(struct pci_dev *dev); -void pcie_ecrc_get_policy(char *str); -#else -static inline void pcie_set_ecrc_checking(struct pci_dev *dev) { } -static inline void pcie_ecrc_get_policy(char *str) { } -#endif - -#define pci_enable_msi(pdev) pci_enable_msi_exact(pdev, 1) - -#ifdef CONFIG_HT_IRQ -/* The functions a driver should call */ -int ht_create_irq(struct pci_dev *dev, int idx); -void ht_destroy_irq(unsigned int irq); -#endif /* CONFIG_HT_IRQ */ - -#ifdef CONFIG_PCI_ATS -/* Address Translation Service */ -void pci_ats_init(struct pci_dev *dev); -int pci_enable_ats(struct pci_dev *dev, int ps); -void pci_disable_ats(struct pci_dev *dev); -int pci_ats_queue_depth(struct pci_dev *dev); -#else -static inline void pci_ats_init(struct pci_dev *d) { } -static inline int pci_enable_ats(struct pci_dev *d, int ps) { return -ENODEV; } -static inline void pci_disable_ats(struct pci_dev *d) { } -static inline int pci_ats_queue_depth(struct pci_dev *d) { return -ENODEV; } -#endif - -#ifdef CONFIG_PCIE_PTM -int pci_enable_ptm(struct pci_dev *dev, u8 *granularity); -#else -static inline int pci_enable_ptm(struct pci_dev *dev, u8 *granularity) -{ return -EINVAL; } -#endif - -void pci_cfg_access_lock(struct pci_dev *dev); -bool pci_cfg_access_trylock(struct pci_dev *dev); -void pci_cfg_access_unlock(struct pci_dev *dev); - -/* - * PCI domain support. Sometimes called PCI segment (eg by ACPI), - * a PCI domain is defined to be a set of PCI buses which share - * configuration space. - */ -#ifdef CONFIG_PCI_DOMAINS -extern int pci_domains_supported; -int pci_get_new_domain_nr(void); -#else -enum { pci_domains_supported = 0 }; -static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } -static inline int pci_proc_domain(struct pci_bus *bus) { return 0; } -static inline int pci_get_new_domain_nr(void) { return -ENOSYS; } -#endif /* CONFIG_PCI_DOMAINS */ - -/* - * Generic implementation for PCI domain support. If your - * architecture does not need custom management of PCI - * domains then this implementation will be used - */ -#ifdef CONFIG_PCI_DOMAINS_GENERIC -static inline int pci_domain_nr(struct pci_bus *bus) -{ - return bus->domain_nr; -} -#ifdef CONFIG_ACPI -int acpi_pci_bus_find_domain_nr(struct pci_bus *bus); -#else -static inline int acpi_pci_bus_find_domain_nr(struct pci_bus *bus) -{ return 0; } -#endif -int pci_bus_find_domain_nr(struct pci_bus *bus, struct device *parent); -#endif - -/* some architectures require additional setup to direct VGA traffic */ -typedef int (*arch_set_vga_state_t)(struct pci_dev *pdev, bool decode, - unsigned int command_bits, u32 flags); -void pci_register_set_vga_state(arch_set_vga_state_t func); - -static inline int -pci_request_io_regions(struct pci_dev *pdev, const char *name) -{ - return pci_request_selected_regions(pdev, - pci_select_bars(pdev, IORESOURCE_IO), name); -} - -static inline void -pci_release_io_regions(struct pci_dev *pdev) -{ - return pci_release_selected_regions(pdev, - pci_select_bars(pdev, IORESOURCE_IO)); -} - -static inline int -pci_request_mem_regions(struct pci_dev *pdev, const char *name) -{ - return pci_request_selected_regions(pdev, - pci_select_bars(pdev, IORESOURCE_MEM), name); -} - -static inline void -pci_release_mem_regions(struct pci_dev *pdev) -{ - return pci_release_selected_regions(pdev, - pci_select_bars(pdev, IORESOURCE_MEM)); -} - -#else /* CONFIG_PCI is not enabled */ - -static inline void pci_set_flags(int flags) { } -static inline void pci_add_flags(int flags) { } -static inline void pci_clear_flags(int flags) { } -static inline int pci_has_flag(int flag) { return 0; } - -/* - * If the system does not have PCI, clearly these return errors. Define - * these as simple inline functions to avoid hair in drivers. - */ - -#define _PCI_NOP(o, s, t) \ - static inline int pci_##o##_config_##s(struct pci_dev *dev, \ - int where, t val) \ - { return PCIBIOS_FUNC_NOT_SUPPORTED; } - -#define _PCI_NOP_ALL(o, x) _PCI_NOP(o, byte, u8 x) \ - _PCI_NOP(o, word, u16 x) \ - _PCI_NOP(o, dword, u32 x) -_PCI_NOP_ALL(read, *) -_PCI_NOP_ALL(write,) - -static inline struct pci_dev *pci_get_device(unsigned int vendor, - unsigned int device, - struct pci_dev *from) -{ return NULL; } - -static inline struct pci_dev *pci_get_subsys(unsigned int vendor, - unsigned int device, - unsigned int ss_vendor, - unsigned int ss_device, - struct pci_dev *from) -{ return NULL; } - -static inline struct pci_dev *pci_get_class(unsigned int class, - struct pci_dev *from) -{ return NULL; } - -#define pci_dev_present(ids) (0) -#define no_pci_devices() (1) -#define pci_dev_put(dev) do { } while (0) - -static inline void pci_set_master(struct pci_dev *dev) { } -static inline int pci_enable_device(struct pci_dev *dev) { return -EIO; } -static inline void pci_disable_device(struct pci_dev *dev) { } -static inline int pci_assign_resource(struct pci_dev *dev, int i) -{ return -EBUSY; } -static inline int __pci_register_driver(struct pci_driver *drv, - struct module *owner) -{ return 0; } -static inline int pci_register_driver(struct pci_driver *drv) -{ return 0; } -static inline void pci_unregister_driver(struct pci_driver *drv) { } -static inline int pci_find_capability(struct pci_dev *dev, int cap) -{ return 0; } -static inline int pci_find_next_capability(struct pci_dev *dev, u8 post, - int cap) -{ return 0; } -static inline int pci_find_ext_capability(struct pci_dev *dev, int cap) -{ return 0; } - -/* Power management related routines */ -static inline int pci_save_state(struct pci_dev *dev) { return 0; } -static inline void pci_restore_state(struct pci_dev *dev) { } -static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state) -{ return 0; } -static inline int pci_wake_from_d3(struct pci_dev *dev, bool enable) -{ return 0; } -static inline pci_power_t pci_choose_state(struct pci_dev *dev, - pm_message_t state) -{ return PCI_D0; } -static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, - int enable) -{ return 0; } - -static inline struct resource *pci_find_resource(struct pci_dev *dev, - struct resource *res) -{ return NULL; } -static inline int pci_request_regions(struct pci_dev *dev, const char *res_name) -{ return -EIO; } -static inline void pci_release_regions(struct pci_dev *dev) { } - -static inline unsigned long pci_address_to_pio(phys_addr_t addr) { return -1; } - -static inline void pci_block_cfg_access(struct pci_dev *dev) { } -static inline int pci_block_cfg_access_in_atomic(struct pci_dev *dev) -{ return 0; } -static inline void pci_unblock_cfg_access(struct pci_dev *dev) { } - -static inline struct pci_bus *pci_find_next_bus(const struct pci_bus *from) -{ return NULL; } -static inline struct pci_dev *pci_get_slot(struct pci_bus *bus, - unsigned int devfn) -{ return NULL; } -static inline struct pci_dev *pci_get_bus_and_slot(unsigned int bus, - unsigned int devfn) -{ return NULL; } - -static inline int pci_domain_nr(struct pci_bus *bus) { return 0; } -static inline struct pci_dev *pci_dev_get(struct pci_dev *dev) { return NULL; } -static inline int pci_get_new_domain_nr(void) { return -ENOSYS; } - -#define dev_is_pci(d) (false) -#define dev_is_pf(d) (false) -#define dev_num_vf(d) (0) -#endif /* CONFIG_PCI */ - -/* Include architecture-dependent settings and functions */ - -#include - -#ifndef pci_root_bus_fwnode -#define pci_root_bus_fwnode(bus) NULL -#endif - -/* these helpers provide future and backwards compatibility - * for accessing popular PCI BAR info */ -#define pci_resource_start(dev, bar) ((dev)->resource[(bar)].start) -#define pci_resource_end(dev, bar) ((dev)->resource[(bar)].end) -#define pci_resource_flags(dev, bar) ((dev)->resource[(bar)].flags) -#define pci_resource_len(dev,bar) \ - ((pci_resource_start((dev), (bar)) == 0 && \ - pci_resource_end((dev), (bar)) == \ - pci_resource_start((dev), (bar))) ? 0 : \ - \ - (pci_resource_end((dev), (bar)) - \ - pci_resource_start((dev), (bar)) + 1)) - -/* Similar to the helpers above, these manipulate per-pci_dev - * driver-specific data. They are really just a wrapper around - * the generic device structure functions of these calls. - */ -static inline void *pci_get_drvdata(struct pci_dev *pdev) -{ - return dev_get_drvdata(&pdev->dev); -} - -static inline void pci_set_drvdata(struct pci_dev *pdev, void *data) -{ - dev_set_drvdata(&pdev->dev, data); -} - -/* If you want to know what to call your pci_dev, ask this function. - * Again, it's a wrapper around the generic device. - */ -static inline const char *pci_name(const struct pci_dev *pdev) -{ - return dev_name(&pdev->dev); -} - - -/* Some archs don't want to expose struct resource to userland as-is - * in sysfs and /proc - */ -#ifdef HAVE_ARCH_PCI_RESOURCE_TO_USER -void pci_resource_to_user(const struct pci_dev *dev, int bar, - const struct resource *rsrc, - resource_size_t *start, resource_size_t *end); -#else -static inline void pci_resource_to_user(const struct pci_dev *dev, int bar, - const struct resource *rsrc, resource_size_t *start, - resource_size_t *end) -{ - *start = rsrc->start; - *end = rsrc->end; -} -#endif /* HAVE_ARCH_PCI_RESOURCE_TO_USER */ - - -/* - * The world is not perfect and supplies us with broken PCI devices. - * For at least a part of these bugs we need a work-around, so both - * generic (drivers/pci/quirks.c) and per-architecture code can define - * fixup hooks to be called for particular buggy devices. - */ - -struct pci_fixup { - u16 vendor; /* You can use PCI_ANY_ID here of course */ - u16 device; /* You can use PCI_ANY_ID here of course */ - u32 class; /* You can use PCI_ANY_ID here too */ - unsigned int class_shift; /* should be 0, 8, 16 */ - void (*hook)(struct pci_dev *dev); -}; - -enum pci_fixup_pass { - pci_fixup_early, /* Before probing BARs */ - pci_fixup_header, /* After reading configuration header */ - pci_fixup_final, /* Final phase of device fixups */ - pci_fixup_enable, /* pci_enable_device() time */ - pci_fixup_resume, /* pci_device_resume() */ - pci_fixup_suspend, /* pci_device_suspend() */ - pci_fixup_resume_early, /* pci_device_resume_early() */ - pci_fixup_suspend_late, /* pci_device_suspend_late() */ -}; - -/* Anonymous variables would be nice... */ -#define DECLARE_PCI_FIXUP_SECTION(section, name, vendor, device, class, \ - class_shift, hook) \ - static const struct pci_fixup __PASTE(__pci_fixup_##name,__LINE__) __used \ - __attribute__((__section__(#section), aligned((sizeof(void *))))) \ - = { vendor, device, class, class_shift, hook }; - -#define DECLARE_PCI_FIXUP_CLASS_EARLY(vendor, device, class, \ - class_shift, hook) \ - DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early, \ - hook, vendor, device, class, class_shift, hook) -#define DECLARE_PCI_FIXUP_CLASS_HEADER(vendor, device, class, \ - class_shift, hook) \ - DECLARE_PCI_FIXUP_SECTION(.pci_fixup_header, \ - hook, vendor, device, class, class_shift, hook) -#define DECLARE_PCI_FIXUP_CLASS_FINAL(vendor, device, class, \ - class_shift, hook) \ - DECLARE_PCI_FIXUP_SECTION(.pci_fixup_final, \ - hook, vendor, device, class, class_shift, hook) -#define DECLARE_PCI_FIXUP_CLASS_ENABLE(vendor, device, class, \ - class_shift, hook) \ - DECLARE_PCI_FIXUP_SECTION(.pci_fixup_enable, \ - hook, vendor, device, class, class_shift, hook) -#define DECLARE_PCI_FIXUP_CLASS_RESUME(vendor, device, class, \ - class_shift, hook) \ - DECLARE_PCI_FIXUP_SECTION(.pci_fixup_resume, \ - resume##hook, vendor, device, class, \ - class_shift, hook) -#define DECLARE_PCI_FIXUP_CLASS_RESUME_EARLY(vendor, device, class, \ - class_shift, hook) \ - DECLARE_PCI_FIXUP_SECTION(.pci_fixup_resume_early, \ - resume_early##hook, vendor, device, \ - class, class_shift, hook) -#define DECLARE_PCI_FIXUP_CLASS_SUSPEND(vendor, device, class, \ - class_shift, hook) \ - DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend, \ - suspend##hook, vendor, device, class, \ - class_shift, hook) -#define DECLARE_PCI_FIXUP_CLASS_SUSPEND_LATE(vendor, device, class, \ - class_shift, hook) \ - DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend_late, \ - suspend_late##hook, vendor, device, \ - class, class_shift, hook) - -#define DECLARE_PCI_FIXUP_EARLY(vendor, device, hook) \ - DECLARE_PCI_FIXUP_SECTION(.pci_fixup_early, \ - hook, vendor, device, PCI_ANY_ID, 0, hook) -#define DECLARE_PCI_FIXUP_HEADER(vendor, device, hook) \ - DECLARE_PCI_FIXUP_SECTION(.pci_fixup_header, \ - hook, vendor, device, PCI_ANY_ID, 0, hook) -#define DECLARE_PCI_FIXUP_FINAL(vendor, device, hook) \ - DECLARE_PCI_FIXUP_SECTION(.pci_fixup_final, \ - hook, vendor, device, PCI_ANY_ID, 0, hook) -#define DECLARE_PCI_FIXUP_ENABLE(vendor, device, hook) \ - DECLARE_PCI_FIXUP_SECTION(.pci_fixup_enable, \ - hook, vendor, device, PCI_ANY_ID, 0, hook) -#define DECLARE_PCI_FIXUP_RESUME(vendor, device, hook) \ - DECLARE_PCI_FIXUP_SECTION(.pci_fixup_resume, \ - resume##hook, vendor, device, \ - PCI_ANY_ID, 0, hook) -#define DECLARE_PCI_FIXUP_RESUME_EARLY(vendor, device, hook) \ - DECLARE_PCI_FIXUP_SECTION(.pci_fixup_resume_early, \ - resume_early##hook, vendor, device, \ - PCI_ANY_ID, 0, hook) -#define DECLARE_PCI_FIXUP_SUSPEND(vendor, device, hook) \ - DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend, \ - suspend##hook, vendor, device, \ - PCI_ANY_ID, 0, hook) -#define DECLARE_PCI_FIXUP_SUSPEND_LATE(vendor, device, hook) \ - DECLARE_PCI_FIXUP_SECTION(.pci_fixup_suspend_late, \ - suspend_late##hook, vendor, device, \ - PCI_ANY_ID, 0, hook) - -#ifdef CONFIG_PCI_QUIRKS -void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev); -int pci_dev_specific_acs_enabled(struct pci_dev *dev, u16 acs_flags); -int pci_dev_specific_enable_acs(struct pci_dev *dev); -#else -static inline void pci_fixup_device(enum pci_fixup_pass pass, - struct pci_dev *dev) { } -static inline int pci_dev_specific_acs_enabled(struct pci_dev *dev, - u16 acs_flags) -{ - return -ENOTTY; -} -static inline int pci_dev_specific_enable_acs(struct pci_dev *dev) -{ - return -ENOTTY; -} -#endif - -void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen); -void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr); -void __iomem * const *pcim_iomap_table(struct pci_dev *pdev); -int pcim_iomap_regions(struct pci_dev *pdev, int mask, const char *name); -int pcim_iomap_regions_request_all(struct pci_dev *pdev, int mask, - const char *name); -void pcim_iounmap_regions(struct pci_dev *pdev, int mask); - -extern int pci_pci_problems; -#define PCIPCI_FAIL 1 /* No PCI PCI DMA */ -#define PCIPCI_TRITON 2 -#define PCIPCI_NATOMA 4 -#define PCIPCI_VIAETBF 8 -#define PCIPCI_VSFX 16 -#define PCIPCI_ALIMAGIK 32 /* Need low latency setting */ -#define PCIAGP_FAIL 64 /* No PCI to AGP DMA */ - -extern unsigned long pci_cardbus_io_size; -extern unsigned long pci_cardbus_mem_size; -extern u8 pci_dfl_cache_line_size; -extern u8 pci_cache_line_size; - -extern unsigned long pci_hotplug_io_size; -extern unsigned long pci_hotplug_mem_size; -extern unsigned long pci_hotplug_bus_size; - -/* Architecture-specific versions may override these (weak) */ -void pcibios_disable_device(struct pci_dev *dev); -void pcibios_set_master(struct pci_dev *dev); -int pcibios_set_pcie_reset_state(struct pci_dev *dev, - enum pcie_reset_state state); -int pcibios_add_device(struct pci_dev *dev); -void pcibios_release_device(struct pci_dev *dev); -void pcibios_penalize_isa_irq(int irq, int active); -int pcibios_alloc_irq(struct pci_dev *dev); -void pcibios_free_irq(struct pci_dev *dev); - -#ifdef CONFIG_HIBERNATE_CALLBACKS -extern struct dev_pm_ops pcibios_pm_ops; -#endif - -#if defined(CONFIG_PCI_MMCONFIG) || defined(CONFIG_ACPI_MCFG) -void __init pci_mmcfg_early_init(void); -void __init pci_mmcfg_late_init(void); -#else -static inline void pci_mmcfg_early_init(void) { } -static inline void pci_mmcfg_late_init(void) { } -#endif - -int pci_ext_cfg_avail(void); - -void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar); -void __iomem *pci_ioremap_wc_bar(struct pci_dev *pdev, int bar); - -#ifdef CONFIG_PCI_IOV -int pci_iov_virtfn_bus(struct pci_dev *dev, int id); -int pci_iov_virtfn_devfn(struct pci_dev *dev, int id); - -int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn); -void pci_disable_sriov(struct pci_dev *dev); -int pci_iov_add_virtfn(struct pci_dev *dev, int id, int reset); -void pci_iov_remove_virtfn(struct pci_dev *dev, int id, int reset); -int pci_num_vf(struct pci_dev *dev); -int pci_vfs_assigned(struct pci_dev *dev); -int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs); -int pci_sriov_get_totalvfs(struct pci_dev *dev); -resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno); -#else -static inline int pci_iov_virtfn_bus(struct pci_dev *dev, int id) -{ - return -ENOSYS; -} -static inline int pci_iov_virtfn_devfn(struct pci_dev *dev, int id) -{ - return -ENOSYS; -} -static inline int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn) -{ return -ENODEV; } -static inline int pci_iov_add_virtfn(struct pci_dev *dev, int id, int reset) -{ - return -ENOSYS; -} -static inline void pci_iov_remove_virtfn(struct pci_dev *dev, - int id, int reset) { } -static inline void pci_disable_sriov(struct pci_dev *dev) { } -static inline int pci_num_vf(struct pci_dev *dev) { return 0; } -static inline int pci_vfs_assigned(struct pci_dev *dev) -{ return 0; } -static inline int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs) -{ return 0; } -static inline int pci_sriov_get_totalvfs(struct pci_dev *dev) -{ return 0; } -static inline resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno) -{ return 0; } -#endif - -#if defined(CONFIG_HOTPLUG_PCI) || defined(CONFIG_HOTPLUG_PCI_MODULE) -void pci_hp_create_module_link(struct pci_slot *pci_slot); -void pci_hp_remove_module_link(struct pci_slot *pci_slot); -#endif - -/** - * pci_pcie_cap - get the saved PCIe capability offset - * @dev: PCI device - * - * PCIe capability offset is calculated at PCI device initialization - * time and saved in the data structure. This function returns saved - * PCIe capability offset. Using this instead of pci_find_capability() - * reduces unnecessary search in the PCI configuration space. If you - * need to calculate PCIe capability offset from raw device for some - * reasons, please use pci_find_capability() instead. - */ -static inline int pci_pcie_cap(struct pci_dev *dev) -{ - return dev->pcie_cap; -} - -/** - * pci_is_pcie - check if the PCI device is PCI Express capable - * @dev: PCI device - * - * Returns: true if the PCI device is PCI Express capable, false otherwise. - */ -static inline bool pci_is_pcie(struct pci_dev *dev) -{ - return pci_pcie_cap(dev); -} - -/** - * pcie_caps_reg - get the PCIe Capabilities Register - * @dev: PCI device - */ -static inline u16 pcie_caps_reg(const struct pci_dev *dev) -{ - return dev->pcie_flags_reg; -} - -/** - * pci_pcie_type - get the PCIe device/port type - * @dev: PCI device - */ -static inline int pci_pcie_type(const struct pci_dev *dev) -{ - return (pcie_caps_reg(dev) & PCI_EXP_FLAGS_TYPE) >> 4; -} - -static inline struct pci_dev *pcie_find_root_port(struct pci_dev *dev) -{ - while (1) { - if (!pci_is_pcie(dev)) - break; - if (pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT) - return dev; - if (!dev->bus->self) - break; - dev = dev->bus->self; - } - return NULL; -} - -void pci_request_acs(void); -bool pci_acs_enabled(struct pci_dev *pdev, u16 acs_flags); -bool pci_acs_path_enabled(struct pci_dev *start, - struct pci_dev *end, u16 acs_flags); - -#define PCI_VPD_LRDT 0x80 /* Large Resource Data Type */ -#define PCI_VPD_LRDT_ID(x) ((x) | PCI_VPD_LRDT) - -/* Large Resource Data Type Tag Item Names */ -#define PCI_VPD_LTIN_ID_STRING 0x02 /* Identifier String */ -#define PCI_VPD_LTIN_RO_DATA 0x10 /* Read-Only Data */ -#define PCI_VPD_LTIN_RW_DATA 0x11 /* Read-Write Data */ - -#define PCI_VPD_LRDT_ID_STRING PCI_VPD_LRDT_ID(PCI_VPD_LTIN_ID_STRING) -#define PCI_VPD_LRDT_RO_DATA PCI_VPD_LRDT_ID(PCI_VPD_LTIN_RO_DATA) -#define PCI_VPD_LRDT_RW_DATA PCI_VPD_LRDT_ID(PCI_VPD_LTIN_RW_DATA) - -/* Small Resource Data Type Tag Item Names */ -#define PCI_VPD_STIN_END 0x0f /* End */ - -#define PCI_VPD_SRDT_END (PCI_VPD_STIN_END << 3) - -#define PCI_VPD_SRDT_TIN_MASK 0x78 -#define PCI_VPD_SRDT_LEN_MASK 0x07 -#define PCI_VPD_LRDT_TIN_MASK 0x7f - -#define PCI_VPD_LRDT_TAG_SIZE 3 -#define PCI_VPD_SRDT_TAG_SIZE 1 - -#define PCI_VPD_INFO_FLD_HDR_SIZE 3 - -#define PCI_VPD_RO_KEYWORD_PARTNO "PN" -#define PCI_VPD_RO_KEYWORD_MFR_ID "MN" -#define PCI_VPD_RO_KEYWORD_VENDOR0 "V0" -#define PCI_VPD_RO_KEYWORD_CHKSUM "RV" - -/** - * pci_vpd_lrdt_size - Extracts the Large Resource Data Type length - * @lrdt: Pointer to the beginning of the Large Resource Data Type tag - * - * Returns the extracted Large Resource Data Type length. - */ -static inline u16 pci_vpd_lrdt_size(const u8 *lrdt) -{ - return (u16)lrdt[1] + ((u16)lrdt[2] << 8); -} - -/** - * pci_vpd_lrdt_tag - Extracts the Large Resource Data Type Tag Item - * @lrdt: Pointer to the beginning of the Large Resource Data Type tag - * - * Returns the extracted Large Resource Data Type Tag item. - */ -static inline u16 pci_vpd_lrdt_tag(const u8 *lrdt) -{ - return (u16)(lrdt[0] & PCI_VPD_LRDT_TIN_MASK); -} - -/** - * pci_vpd_srdt_size - Extracts the Small Resource Data Type length - * @lrdt: Pointer to the beginning of the Small Resource Data Type tag - * - * Returns the extracted Small Resource Data Type length. - */ -static inline u8 pci_vpd_srdt_size(const u8 *srdt) -{ - return (*srdt) & PCI_VPD_SRDT_LEN_MASK; -} - -/** - * pci_vpd_srdt_tag - Extracts the Small Resource Data Type Tag Item - * @lrdt: Pointer to the beginning of the Small Resource Data Type tag - * - * Returns the extracted Small Resource Data Type Tag Item. - */ -static inline u8 pci_vpd_srdt_tag(const u8 *srdt) -{ - return ((*srdt) & PCI_VPD_SRDT_TIN_MASK) >> 3; -} - -/** - * pci_vpd_info_field_size - Extracts the information field length - * @lrdt: Pointer to the beginning of an information field header - * - * Returns the extracted information field length. - */ -static inline u8 pci_vpd_info_field_size(const u8 *info_field) -{ - return info_field[2]; -} - -/** - * pci_vpd_find_tag - Locates the Resource Data Type tag provided - * @buf: Pointer to buffered vpd data - * @off: The offset into the buffer at which to begin the search - * @len: The length of the vpd buffer - * @rdt: The Resource Data Type to search for - * - * Returns the index where the Resource Data Type was found or - * -ENOENT otherwise. - */ -int pci_vpd_find_tag(const u8 *buf, unsigned int off, unsigned int len, u8 rdt); - -/** - * pci_vpd_find_info_keyword - Locates an information field keyword in the VPD - * @buf: Pointer to buffered vpd data - * @off: The offset into the buffer at which to begin the search - * @len: The length of the buffer area, relative to off, in which to search - * @kw: The keyword to search for - * - * Returns the index where the information field keyword was found or - * -ENOENT otherwise. - */ -int pci_vpd_find_info_keyword(const u8 *buf, unsigned int off, - unsigned int len, const char *kw); - -/* PCI <-> OF binding helpers */ -#ifdef CONFIG_OF -struct device_node; -struct irq_domain; -void pci_set_of_node(struct pci_dev *dev); -void pci_release_of_node(struct pci_dev *dev); -void pci_set_bus_of_node(struct pci_bus *bus); -void pci_release_bus_of_node(struct pci_bus *bus); -struct irq_domain *pci_host_bridge_of_msi_domain(struct pci_bus *bus); - -/* Arch may override this (weak) */ -struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus); - -static inline struct device_node * -pci_device_to_OF_node(const struct pci_dev *pdev) -{ - return pdev ? pdev->dev.of_node : NULL; -} - -static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus) -{ - return bus ? bus->dev.of_node : NULL; -} - -#else /* CONFIG_OF */ -static inline void pci_set_of_node(struct pci_dev *dev) { } -static inline void pci_release_of_node(struct pci_dev *dev) { } -static inline void pci_set_bus_of_node(struct pci_bus *bus) { } -static inline void pci_release_bus_of_node(struct pci_bus *bus) { } -static inline struct device_node * -pci_device_to_OF_node(const struct pci_dev *pdev) { return NULL; } -static inline struct irq_domain * -pci_host_bridge_of_msi_domain(struct pci_bus *bus) { return NULL; } -#endif /* CONFIG_OF */ - -#ifdef CONFIG_ACPI -struct irq_domain *pci_host_bridge_acpi_msi_domain(struct pci_bus *bus); - -void -pci_msi_register_fwnode_provider(struct fwnode_handle *(*fn)(struct device *)); -#else -static inline struct irq_domain * -pci_host_bridge_acpi_msi_domain(struct pci_bus *bus) { return NULL; } -#endif - -#ifdef CONFIG_EEH -static inline struct eeh_dev *pci_dev_to_eeh_dev(struct pci_dev *pdev) -{ - return pdev->dev.archdata.edev; -} -#endif - -void pci_add_dma_alias(struct pci_dev *dev, u8 devfn); -bool pci_devs_are_dma_aliases(struct pci_dev *dev1, struct pci_dev *dev2); -int pci_for_each_dma_alias(struct pci_dev *pdev, - int (*fn)(struct pci_dev *pdev, - u16 alias, void *data), void *data); - -/* helper functions for operation of device flag */ -static inline void pci_set_dev_assigned(struct pci_dev *pdev) -{ - pdev->dev_flags |= PCI_DEV_FLAGS_ASSIGNED; -} -static inline void pci_clear_dev_assigned(struct pci_dev *pdev) -{ - pdev->dev_flags &= ~PCI_DEV_FLAGS_ASSIGNED; -} -static inline bool pci_is_dev_assigned(struct pci_dev *pdev) -{ - return (pdev->dev_flags & PCI_DEV_FLAGS_ASSIGNED) == PCI_DEV_FLAGS_ASSIGNED; -} - -/** - * pci_ari_enabled - query ARI forwarding status - * @bus: the PCI bus - * - * Returns true if ARI forwarding is enabled. - */ -static inline bool pci_ari_enabled(struct pci_bus *bus) -{ - return bus->self && bus->self->ari_enabled; -} - -/* provide the legacy pci_dma_* API */ -#include - -#endif /* LINUX_PCI_H */ diff --git a/src/linux/include/linux/pci_ids.h b/src/linux/include/linux/pci_ids.h deleted file mode 100644 index c58752f..0000000 --- a/src/linux/include/linux/pci_ids.h +++ /dev/null @@ -1,3037 +0,0 @@ -/* - * PCI Class, Vendor and Device IDs - * - * Please keep sorted. - * - * Do not add new entries to this file unless the definitions - * are shared between multiple drivers. - */ -#ifndef _LINUX_PCI_IDS_H -#define _LINUX_PCI_IDS_H - -/* Device classes and subclasses */ - -#define PCI_CLASS_NOT_DEFINED 0x0000 -#define PCI_CLASS_NOT_DEFINED_VGA 0x0001 - -#define PCI_BASE_CLASS_STORAGE 0x01 -#define PCI_CLASS_STORAGE_SCSI 0x0100 -#define PCI_CLASS_STORAGE_IDE 0x0101 -#define PCI_CLASS_STORAGE_FLOPPY 0x0102 -#define PCI_CLASS_STORAGE_IPI 0x0103 -#define PCI_CLASS_STORAGE_RAID 0x0104 -#define PCI_CLASS_STORAGE_SATA 0x0106 -#define PCI_CLASS_STORAGE_SATA_AHCI 0x010601 -#define PCI_CLASS_STORAGE_SAS 0x0107 -#define PCI_CLASS_STORAGE_OTHER 0x0180 - -#define PCI_BASE_CLASS_NETWORK 0x02 -#define PCI_CLASS_NETWORK_ETHERNET 0x0200 -#define PCI_CLASS_NETWORK_TOKEN_RING 0x0201 -#define PCI_CLASS_NETWORK_FDDI 0x0202 -#define PCI_CLASS_NETWORK_ATM 0x0203 -#define PCI_CLASS_NETWORK_OTHER 0x0280 - -#define PCI_BASE_CLASS_DISPLAY 0x03 -#define PCI_CLASS_DISPLAY_VGA 0x0300 -#define PCI_CLASS_DISPLAY_XGA 0x0301 -#define PCI_CLASS_DISPLAY_3D 0x0302 -#define PCI_CLASS_DISPLAY_OTHER 0x0380 - -#define PCI_BASE_CLASS_MULTIMEDIA 0x04 -#define PCI_CLASS_MULTIMEDIA_VIDEO 0x0400 -#define PCI_CLASS_MULTIMEDIA_AUDIO 0x0401 -#define PCI_CLASS_MULTIMEDIA_PHONE 0x0402 -#define PCI_CLASS_MULTIMEDIA_OTHER 0x0480 - -#define PCI_BASE_CLASS_MEMORY 0x05 -#define PCI_CLASS_MEMORY_RAM 0x0500 -#define PCI_CLASS_MEMORY_FLASH 0x0501 -#define PCI_CLASS_MEMORY_OTHER 0x0580 - -#define PCI_BASE_CLASS_BRIDGE 0x06 -#define PCI_CLASS_BRIDGE_HOST 0x0600 -#define PCI_CLASS_BRIDGE_ISA 0x0601 -#define PCI_CLASS_BRIDGE_EISA 0x0602 -#define PCI_CLASS_BRIDGE_MC 0x0603 -#define PCI_CLASS_BRIDGE_PCI 0x0604 -#define PCI_CLASS_BRIDGE_PCMCIA 0x0605 -#define PCI_CLASS_BRIDGE_NUBUS 0x0606 -#define PCI_CLASS_BRIDGE_CARDBUS 0x0607 -#define PCI_CLASS_BRIDGE_RACEWAY 0x0608 -#define PCI_CLASS_BRIDGE_OTHER 0x0680 - -#define PCI_BASE_CLASS_COMMUNICATION 0x07 -#define PCI_CLASS_COMMUNICATION_SERIAL 0x0700 -#define PCI_CLASS_COMMUNICATION_PARALLEL 0x0701 -#define PCI_CLASS_COMMUNICATION_MULTISERIAL 0x0702 -#define PCI_CLASS_COMMUNICATION_MODEM 0x0703 -#define PCI_CLASS_COMMUNICATION_OTHER 0x0780 - -#define PCI_BASE_CLASS_SYSTEM 0x08 -#define PCI_CLASS_SYSTEM_PIC 0x0800 -#define PCI_CLASS_SYSTEM_PIC_IOAPIC 0x080010 -#define PCI_CLASS_SYSTEM_PIC_IOXAPIC 0x080020 -#define PCI_CLASS_SYSTEM_DMA 0x0801 -#define PCI_CLASS_SYSTEM_TIMER 0x0802 -#define PCI_CLASS_SYSTEM_RTC 0x0803 -#define PCI_CLASS_SYSTEM_PCI_HOTPLUG 0x0804 -#define PCI_CLASS_SYSTEM_SDHCI 0x0805 -#define PCI_CLASS_SYSTEM_OTHER 0x0880 - -#define PCI_BASE_CLASS_INPUT 0x09 -#define PCI_CLASS_INPUT_KEYBOARD 0x0900 -#define PCI_CLASS_INPUT_PEN 0x0901 -#define PCI_CLASS_INPUT_MOUSE 0x0902 -#define PCI_CLASS_INPUT_SCANNER 0x0903 -#define PCI_CLASS_INPUT_GAMEPORT 0x0904 -#define PCI_CLASS_INPUT_OTHER 0x0980 - -#define PCI_BASE_CLASS_DOCKING 0x0a -#define PCI_CLASS_DOCKING_GENERIC 0x0a00 -#define PCI_CLASS_DOCKING_OTHER 0x0a80 - -#define PCI_BASE_CLASS_PROCESSOR 0x0b -#define PCI_CLASS_PROCESSOR_386 0x0b00 -#define PCI_CLASS_PROCESSOR_486 0x0b01 -#define PCI_CLASS_PROCESSOR_PENTIUM 0x0b02 -#define PCI_CLASS_PROCESSOR_ALPHA 0x0b10 -#define PCI_CLASS_PROCESSOR_POWERPC 0x0b20 -#define PCI_CLASS_PROCESSOR_MIPS 0x0b30 -#define PCI_CLASS_PROCESSOR_CO 0x0b40 - -#define PCI_BASE_CLASS_SERIAL 0x0c -#define PCI_CLASS_SERIAL_FIREWIRE 0x0c00 -#define PCI_CLASS_SERIAL_FIREWIRE_OHCI 0x0c0010 -#define PCI_CLASS_SERIAL_ACCESS 0x0c01 -#define PCI_CLASS_SERIAL_SSA 0x0c02 -#define PCI_CLASS_SERIAL_USB 0x0c03 -#define PCI_CLASS_SERIAL_USB_UHCI 0x0c0300 -#define PCI_CLASS_SERIAL_USB_OHCI 0x0c0310 -#define PCI_CLASS_SERIAL_USB_EHCI 0x0c0320 -#define PCI_CLASS_SERIAL_USB_XHCI 0x0c0330 -#define PCI_CLASS_SERIAL_USB_DEVICE 0x0c03fe -#define PCI_CLASS_SERIAL_FIBER 0x0c04 -#define PCI_CLASS_SERIAL_SMBUS 0x0c05 - -#define PCI_BASE_CLASS_WIRELESS 0x0d -#define PCI_CLASS_WIRELESS_RF_CONTROLLER 0x0d10 -#define PCI_CLASS_WIRELESS_WHCI 0x0d1010 - -#define PCI_BASE_CLASS_INTELLIGENT 0x0e -#define PCI_CLASS_INTELLIGENT_I2O 0x0e00 - -#define PCI_BASE_CLASS_SATELLITE 0x0f -#define PCI_CLASS_SATELLITE_TV 0x0f00 -#define PCI_CLASS_SATELLITE_AUDIO 0x0f01 -#define PCI_CLASS_SATELLITE_VOICE 0x0f03 -#define PCI_CLASS_SATELLITE_DATA 0x0f04 - -#define PCI_BASE_CLASS_CRYPT 0x10 -#define PCI_CLASS_CRYPT_NETWORK 0x1000 -#define PCI_CLASS_CRYPT_ENTERTAINMENT 0x1001 -#define PCI_CLASS_CRYPT_OTHER 0x1080 - -#define PCI_BASE_CLASS_SIGNAL_PROCESSING 0x11 -#define PCI_CLASS_SP_DPIO 0x1100 -#define PCI_CLASS_SP_OTHER 0x1180 - -#define PCI_CLASS_OTHERS 0xff - -/* Vendors and devices. Sort key: vendor first, device next. */ - -#define PCI_VENDOR_ID_TTTECH 0x0357 -#define PCI_DEVICE_ID_TTTECH_MC322 0x000a - -#define PCI_VENDOR_ID_DYNALINK 0x0675 -#define PCI_DEVICE_ID_DYNALINK_IS64PH 0x1702 - -#define PCI_VENDOR_ID_BERKOM 0x0871 -#define PCI_DEVICE_ID_BERKOM_A1T 0xffa1 -#define PCI_DEVICE_ID_BERKOM_T_CONCEPT 0xffa2 -#define PCI_DEVICE_ID_BERKOM_A4T 0xffa4 -#define PCI_DEVICE_ID_BERKOM_SCITEL_QUADRO 0xffa8 - -#define PCI_VENDOR_ID_COMPAQ 0x0e11 -#define PCI_DEVICE_ID_COMPAQ_TOKENRING 0x0508 -#define PCI_DEVICE_ID_COMPAQ_TACHYON 0xa0fc -#define PCI_DEVICE_ID_COMPAQ_SMART2P 0xae10 -#define PCI_DEVICE_ID_COMPAQ_NETEL100 0xae32 -#define PCI_DEVICE_ID_COMPAQ_NETEL10 0xae34 -#define PCI_DEVICE_ID_COMPAQ_TRIFLEX_IDE 0xae33 -#define PCI_DEVICE_ID_COMPAQ_NETFLEX3I 0xae35 -#define PCI_DEVICE_ID_COMPAQ_NETEL100D 0xae40 -#define PCI_DEVICE_ID_COMPAQ_NETEL100PI 0xae43 -#define PCI_DEVICE_ID_COMPAQ_NETEL100I 0xb011 -#define PCI_DEVICE_ID_COMPAQ_CISS 0xb060 -#define PCI_DEVICE_ID_COMPAQ_CISSB 0xb178 -#define PCI_DEVICE_ID_COMPAQ_CISSC 0x46 -#define PCI_DEVICE_ID_COMPAQ_THUNDER 0xf130 -#define PCI_DEVICE_ID_COMPAQ_NETFLEX3B 0xf150 - -#define PCI_VENDOR_ID_NCR 0x1000 -#define PCI_VENDOR_ID_LSI_LOGIC 0x1000 -#define PCI_DEVICE_ID_NCR_53C810 0x0001 -#define PCI_DEVICE_ID_NCR_53C820 0x0002 -#define PCI_DEVICE_ID_NCR_53C825 0x0003 -#define PCI_DEVICE_ID_NCR_53C815 0x0004 -#define PCI_DEVICE_ID_LSI_53C810AP 0x0005 -#define PCI_DEVICE_ID_NCR_53C860 0x0006 -#define PCI_DEVICE_ID_LSI_53C1510 0x000a -#define PCI_DEVICE_ID_NCR_53C896 0x000b -#define PCI_DEVICE_ID_NCR_53C895 0x000c -#define PCI_DEVICE_ID_NCR_53C885 0x000d -#define PCI_DEVICE_ID_NCR_53C875 0x000f -#define PCI_DEVICE_ID_NCR_53C1510 0x0010 -#define PCI_DEVICE_ID_LSI_53C895A 0x0012 -#define PCI_DEVICE_ID_LSI_53C875A 0x0013 -#define PCI_DEVICE_ID_LSI_53C1010_33 0x0020 -#define PCI_DEVICE_ID_LSI_53C1010_66 0x0021 -#define PCI_DEVICE_ID_LSI_53C1030 0x0030 -#define PCI_DEVICE_ID_LSI_1030_53C1035 0x0032 -#define PCI_DEVICE_ID_LSI_53C1035 0x0040 -#define PCI_DEVICE_ID_NCR_53C875J 0x008f -#define PCI_DEVICE_ID_LSI_FC909 0x0621 -#define PCI_DEVICE_ID_LSI_FC929 0x0622 -#define PCI_DEVICE_ID_LSI_FC929_LAN 0x0623 -#define PCI_DEVICE_ID_LSI_FC919 0x0624 -#define PCI_DEVICE_ID_LSI_FC919_LAN 0x0625 -#define PCI_DEVICE_ID_LSI_FC929X 0x0626 -#define PCI_DEVICE_ID_LSI_FC939X 0x0642 -#define PCI_DEVICE_ID_LSI_FC949X 0x0640 -#define PCI_DEVICE_ID_LSI_FC949ES 0x0646 -#define PCI_DEVICE_ID_LSI_FC919X 0x0628 -#define PCI_DEVICE_ID_NCR_YELLOWFIN 0x0701 -#define PCI_DEVICE_ID_LSI_61C102 0x0901 -#define PCI_DEVICE_ID_LSI_63C815 0x1000 -#define PCI_DEVICE_ID_LSI_SAS1064 0x0050 -#define PCI_DEVICE_ID_LSI_SAS1064R 0x0411 -#define PCI_DEVICE_ID_LSI_SAS1066 0x005E -#define PCI_DEVICE_ID_LSI_SAS1068 0x0054 -#define PCI_DEVICE_ID_LSI_SAS1064A 0x005C -#define PCI_DEVICE_ID_LSI_SAS1064E 0x0056 -#define PCI_DEVICE_ID_LSI_SAS1066E 0x005A -#define PCI_DEVICE_ID_LSI_SAS1068E 0x0058 -#define PCI_DEVICE_ID_LSI_SAS1078 0x0060 - -#define PCI_VENDOR_ID_ATI 0x1002 -/* Mach64 */ -#define PCI_DEVICE_ID_ATI_68800 0x4158 -#define PCI_DEVICE_ID_ATI_215CT222 0x4354 -#define PCI_DEVICE_ID_ATI_210888CX 0x4358 -#define PCI_DEVICE_ID_ATI_215ET222 0x4554 -/* Mach64 / Rage */ -#define PCI_DEVICE_ID_ATI_215GB 0x4742 -#define PCI_DEVICE_ID_ATI_215GD 0x4744 -#define PCI_DEVICE_ID_ATI_215GI 0x4749 -#define PCI_DEVICE_ID_ATI_215GP 0x4750 -#define PCI_DEVICE_ID_ATI_215GQ 0x4751 -#define PCI_DEVICE_ID_ATI_215XL 0x4752 -#define PCI_DEVICE_ID_ATI_215GT 0x4754 -#define PCI_DEVICE_ID_ATI_215GTB 0x4755 -#define PCI_DEVICE_ID_ATI_215_IV 0x4756 -#define PCI_DEVICE_ID_ATI_215_IW 0x4757 -#define PCI_DEVICE_ID_ATI_215_IZ 0x475A -#define PCI_DEVICE_ID_ATI_210888GX 0x4758 -#define PCI_DEVICE_ID_ATI_215_LB 0x4c42 -#define PCI_DEVICE_ID_ATI_215_LD 0x4c44 -#define PCI_DEVICE_ID_ATI_215_LG 0x4c47 -#define PCI_DEVICE_ID_ATI_215_LI 0x4c49 -#define PCI_DEVICE_ID_ATI_215_LM 0x4c4D -#define PCI_DEVICE_ID_ATI_215_LN 0x4c4E -#define PCI_DEVICE_ID_ATI_215_LR 0x4c52 -#define PCI_DEVICE_ID_ATI_215_LS 0x4c53 -#define PCI_DEVICE_ID_ATI_264_LT 0x4c54 -/* Mach64 VT */ -#define PCI_DEVICE_ID_ATI_264VT 0x5654 -#define PCI_DEVICE_ID_ATI_264VU 0x5655 -#define PCI_DEVICE_ID_ATI_264VV 0x5656 -/* Rage128 GL */ -#define PCI_DEVICE_ID_ATI_RAGE128_RE 0x5245 -#define PCI_DEVICE_ID_ATI_RAGE128_RF 0x5246 -#define PCI_DEVICE_ID_ATI_RAGE128_RG 0x5247 -/* Rage128 VR */ -#define PCI_DEVICE_ID_ATI_RAGE128_RK 0x524b -#define PCI_DEVICE_ID_ATI_RAGE128_RL 0x524c -#define PCI_DEVICE_ID_ATI_RAGE128_SE 0x5345 -#define PCI_DEVICE_ID_ATI_RAGE128_SF 0x5346 -#define PCI_DEVICE_ID_ATI_RAGE128_SG 0x5347 -#define PCI_DEVICE_ID_ATI_RAGE128_SH 0x5348 -#define PCI_DEVICE_ID_ATI_RAGE128_SK 0x534b -#define PCI_DEVICE_ID_ATI_RAGE128_SL 0x534c -#define PCI_DEVICE_ID_ATI_RAGE128_SM 0x534d -#define PCI_DEVICE_ID_ATI_RAGE128_SN 0x534e -/* Rage128 Ultra */ -#define PCI_DEVICE_ID_ATI_RAGE128_TF 0x5446 -#define PCI_DEVICE_ID_ATI_RAGE128_TL 0x544c -#define PCI_DEVICE_ID_ATI_RAGE128_TR 0x5452 -#define PCI_DEVICE_ID_ATI_RAGE128_TS 0x5453 -#define PCI_DEVICE_ID_ATI_RAGE128_TT 0x5454 -#define PCI_DEVICE_ID_ATI_RAGE128_TU 0x5455 -/* Rage128 M3 */ -#define PCI_DEVICE_ID_ATI_RAGE128_LE 0x4c45 -#define PCI_DEVICE_ID_ATI_RAGE128_LF 0x4c46 -/* Rage128 M4 */ -#define PCI_DEVICE_ID_ATI_RAGE128_MF 0x4d46 -#define PCI_DEVICE_ID_ATI_RAGE128_ML 0x4d4c -/* Rage128 Pro GL */ -#define PCI_DEVICE_ID_ATI_RAGE128_PA 0x5041 -#define PCI_DEVICE_ID_ATI_RAGE128_PB 0x5042 -#define PCI_DEVICE_ID_ATI_RAGE128_PC 0x5043 -#define PCI_DEVICE_ID_ATI_RAGE128_PD 0x5044 -#define PCI_DEVICE_ID_ATI_RAGE128_PE 0x5045 -#define PCI_DEVICE_ID_ATI_RAGE128_PF 0x5046 -/* Rage128 Pro VR */ -#define PCI_DEVICE_ID_ATI_RAGE128_PG 0x5047 -#define PCI_DEVICE_ID_ATI_RAGE128_PH 0x5048 -#define PCI_DEVICE_ID_ATI_RAGE128_PI 0x5049 -#define PCI_DEVICE_ID_ATI_RAGE128_PJ 0x504A -#define PCI_DEVICE_ID_ATI_RAGE128_PK 0x504B -#define PCI_DEVICE_ID_ATI_RAGE128_PL 0x504C -#define PCI_DEVICE_ID_ATI_RAGE128_PM 0x504D -#define PCI_DEVICE_ID_ATI_RAGE128_PN 0x504E -#define PCI_DEVICE_ID_ATI_RAGE128_PO 0x504F -#define PCI_DEVICE_ID_ATI_RAGE128_PP 0x5050 -#define PCI_DEVICE_ID_ATI_RAGE128_PQ 0x5051 -#define PCI_DEVICE_ID_ATI_RAGE128_PR 0x5052 -#define PCI_DEVICE_ID_ATI_RAGE128_PS 0x5053 -#define PCI_DEVICE_ID_ATI_RAGE128_PT 0x5054 -#define PCI_DEVICE_ID_ATI_RAGE128_PU 0x5055 -#define PCI_DEVICE_ID_ATI_RAGE128_PV 0x5056 -#define PCI_DEVICE_ID_ATI_RAGE128_PW 0x5057 -#define PCI_DEVICE_ID_ATI_RAGE128_PX 0x5058 -/* Rage128 M4 */ -/* Radeon R100 */ -#define PCI_DEVICE_ID_ATI_RADEON_QD 0x5144 -#define PCI_DEVICE_ID_ATI_RADEON_QE 0x5145 -#define PCI_DEVICE_ID_ATI_RADEON_QF 0x5146 -#define PCI_DEVICE_ID_ATI_RADEON_QG 0x5147 -/* Radeon RV100 (VE) */ -#define PCI_DEVICE_ID_ATI_RADEON_QY 0x5159 -#define PCI_DEVICE_ID_ATI_RADEON_QZ 0x515a -/* Radeon R200 (8500) */ -#define PCI_DEVICE_ID_ATI_RADEON_QL 0x514c -#define PCI_DEVICE_ID_ATI_RADEON_QN 0x514e -#define PCI_DEVICE_ID_ATI_RADEON_QO 0x514f -#define PCI_DEVICE_ID_ATI_RADEON_Ql 0x516c -#define PCI_DEVICE_ID_ATI_RADEON_BB 0x4242 -/* Radeon R200 (9100) */ -#define PCI_DEVICE_ID_ATI_RADEON_QM 0x514d -/* Radeon RV200 (7500) */ -#define PCI_DEVICE_ID_ATI_RADEON_QW 0x5157 -#define PCI_DEVICE_ID_ATI_RADEON_QX 0x5158 -/* Radeon NV-100 */ -/* Radeon RV250 (9000) */ -#define PCI_DEVICE_ID_ATI_RADEON_Id 0x4964 -#define PCI_DEVICE_ID_ATI_RADEON_Ie 0x4965 -#define PCI_DEVICE_ID_ATI_RADEON_If 0x4966 -#define PCI_DEVICE_ID_ATI_RADEON_Ig 0x4967 -/* Radeon RV280 (9200) */ -#define PCI_DEVICE_ID_ATI_RADEON_Ya 0x5961 -#define PCI_DEVICE_ID_ATI_RADEON_Yd 0x5964 -/* Radeon R300 (9500) */ -/* Radeon R300 (9700) */ -#define PCI_DEVICE_ID_ATI_RADEON_ND 0x4e44 -#define PCI_DEVICE_ID_ATI_RADEON_NE 0x4e45 -#define PCI_DEVICE_ID_ATI_RADEON_NF 0x4e46 -#define PCI_DEVICE_ID_ATI_RADEON_NG 0x4e47 -/* Radeon R350 (9800) */ -/* Radeon RV350 (9600) */ -/* Radeon M6 */ -#define PCI_DEVICE_ID_ATI_RADEON_LY 0x4c59 -#define PCI_DEVICE_ID_ATI_RADEON_LZ 0x4c5a -/* Radeon M7 */ -#define PCI_DEVICE_ID_ATI_RADEON_LW 0x4c57 -#define PCI_DEVICE_ID_ATI_RADEON_LX 0x4c58 -/* Radeon M9 */ -#define PCI_DEVICE_ID_ATI_RADEON_Ld 0x4c64 -#define PCI_DEVICE_ID_ATI_RADEON_Le 0x4c65 -#define PCI_DEVICE_ID_ATI_RADEON_Lf 0x4c66 -#define PCI_DEVICE_ID_ATI_RADEON_Lg 0x4c67 -/* Radeon */ -/* RadeonIGP */ -#define PCI_DEVICE_ID_ATI_RS100 0xcab0 -#define PCI_DEVICE_ID_ATI_RS200 0xcab2 -#define PCI_DEVICE_ID_ATI_RS200_B 0xcbb2 -#define PCI_DEVICE_ID_ATI_RS250 0xcab3 -#define PCI_DEVICE_ID_ATI_RS300_100 0x5830 -#define PCI_DEVICE_ID_ATI_RS300_133 0x5831 -#define PCI_DEVICE_ID_ATI_RS300_166 0x5832 -#define PCI_DEVICE_ID_ATI_RS300_200 0x5833 -#define PCI_DEVICE_ID_ATI_RS350_100 0x7830 -#define PCI_DEVICE_ID_ATI_RS350_133 0x7831 -#define PCI_DEVICE_ID_ATI_RS350_166 0x7832 -#define PCI_DEVICE_ID_ATI_RS350_200 0x7833 -#define PCI_DEVICE_ID_ATI_RS400_100 0x5a30 -#define PCI_DEVICE_ID_ATI_RS400_133 0x5a31 -#define PCI_DEVICE_ID_ATI_RS400_166 0x5a32 -#define PCI_DEVICE_ID_ATI_RS400_200 0x5a33 -#define PCI_DEVICE_ID_ATI_RS480 0x5950 -/* ATI IXP Chipset */ -#define PCI_DEVICE_ID_ATI_IXP200_IDE 0x4349 -#define PCI_DEVICE_ID_ATI_IXP200_SMBUS 0x4353 -#define PCI_DEVICE_ID_ATI_IXP300_SMBUS 0x4363 -#define PCI_DEVICE_ID_ATI_IXP300_IDE 0x4369 -#define PCI_DEVICE_ID_ATI_IXP300_SATA 0x436e -#define PCI_DEVICE_ID_ATI_IXP400_SMBUS 0x4372 -#define PCI_DEVICE_ID_ATI_IXP400_IDE 0x4376 -#define PCI_DEVICE_ID_ATI_IXP400_SATA 0x4379 -#define PCI_DEVICE_ID_ATI_IXP400_SATA2 0x437a -#define PCI_DEVICE_ID_ATI_IXP600_SATA 0x4380 -#define PCI_DEVICE_ID_ATI_SBX00_SMBUS 0x4385 -#define PCI_DEVICE_ID_ATI_IXP600_IDE 0x438c -#define PCI_DEVICE_ID_ATI_IXP700_SATA 0x4390 -#define PCI_DEVICE_ID_ATI_IXP700_IDE 0x439c - -#define PCI_VENDOR_ID_VLSI 0x1004 -#define PCI_DEVICE_ID_VLSI_82C592 0x0005 -#define PCI_DEVICE_ID_VLSI_82C593 0x0006 -#define PCI_DEVICE_ID_VLSI_82C594 0x0007 -#define PCI_DEVICE_ID_VLSI_82C597 0x0009 -#define PCI_DEVICE_ID_VLSI_82C541 0x000c -#define PCI_DEVICE_ID_VLSI_82C543 0x000d -#define PCI_DEVICE_ID_VLSI_82C532 0x0101 -#define PCI_DEVICE_ID_VLSI_82C534 0x0102 -#define PCI_DEVICE_ID_VLSI_82C535 0x0104 -#define PCI_DEVICE_ID_VLSI_82C147 0x0105 -#define PCI_DEVICE_ID_VLSI_VAS96011 0x0702 - -/* AMD RD890 Chipset */ -#define PCI_DEVICE_ID_RD890_IOMMU 0x5a23 - -#define PCI_VENDOR_ID_ADL 0x1005 -#define PCI_DEVICE_ID_ADL_2301 0x2301 - -#define PCI_VENDOR_ID_NS 0x100b -#define PCI_DEVICE_ID_NS_87415 0x0002 -#define PCI_DEVICE_ID_NS_87560_LIO 0x000e -#define PCI_DEVICE_ID_NS_87560_USB 0x0012 -#define PCI_DEVICE_ID_NS_83815 0x0020 -#define PCI_DEVICE_ID_NS_83820 0x0022 -#define PCI_DEVICE_ID_NS_CS5535_ISA 0x002b -#define PCI_DEVICE_ID_NS_CS5535_IDE 0x002d -#define PCI_DEVICE_ID_NS_CS5535_AUDIO 0x002e -#define PCI_DEVICE_ID_NS_CS5535_USB 0x002f -#define PCI_DEVICE_ID_NS_GX_VIDEO 0x0030 -#define PCI_DEVICE_ID_NS_SATURN 0x0035 -#define PCI_DEVICE_ID_NS_SCx200_BRIDGE 0x0500 -#define PCI_DEVICE_ID_NS_SCx200_SMI 0x0501 -#define PCI_DEVICE_ID_NS_SCx200_IDE 0x0502 -#define PCI_DEVICE_ID_NS_SCx200_AUDIO 0x0503 -#define PCI_DEVICE_ID_NS_SCx200_VIDEO 0x0504 -#define PCI_DEVICE_ID_NS_SCx200_XBUS 0x0505 -#define PCI_DEVICE_ID_NS_SC1100_BRIDGE 0x0510 -#define PCI_DEVICE_ID_NS_SC1100_SMI 0x0511 -#define PCI_DEVICE_ID_NS_SC1100_XBUS 0x0515 -#define PCI_DEVICE_ID_NS_87410 0xd001 - -#define PCI_DEVICE_ID_NS_GX_HOST_BRIDGE 0x0028 - -#define PCI_VENDOR_ID_TSENG 0x100c -#define PCI_DEVICE_ID_TSENG_W32P_2 0x3202 -#define PCI_DEVICE_ID_TSENG_W32P_b 0x3205 -#define PCI_DEVICE_ID_TSENG_W32P_c 0x3206 -#define PCI_DEVICE_ID_TSENG_W32P_d 0x3207 -#define PCI_DEVICE_ID_TSENG_ET6000 0x3208 - -#define PCI_VENDOR_ID_WEITEK 0x100e -#define PCI_DEVICE_ID_WEITEK_P9000 0x9001 -#define PCI_DEVICE_ID_WEITEK_P9100 0x9100 - -#define PCI_VENDOR_ID_DEC 0x1011 -#define PCI_DEVICE_ID_DEC_BRD 0x0001 -#define PCI_DEVICE_ID_DEC_TULIP 0x0002 -#define PCI_DEVICE_ID_DEC_TGA 0x0004 -#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009 -#define PCI_DEVICE_ID_DEC_TGA2 0x000D -#define PCI_DEVICE_ID_DEC_FDDI 0x000F -#define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014 -#define PCI_DEVICE_ID_DEC_21142 0x0019 -#define PCI_DEVICE_ID_DEC_21052 0x0021 -#define PCI_DEVICE_ID_DEC_21150 0x0022 -#define PCI_DEVICE_ID_DEC_21152 0x0024 -#define PCI_DEVICE_ID_DEC_21153 0x0025 -#define PCI_DEVICE_ID_DEC_21154 0x0026 -#define PCI_DEVICE_ID_DEC_21285 0x1065 -#define PCI_DEVICE_ID_COMPAQ_42XX 0x0046 - -#define PCI_VENDOR_ID_CIRRUS 0x1013 -#define PCI_DEVICE_ID_CIRRUS_7548 0x0038 -#define PCI_DEVICE_ID_CIRRUS_5430 0x00a0 -#define PCI_DEVICE_ID_CIRRUS_5434_4 0x00a4 -#define PCI_DEVICE_ID_CIRRUS_5434_8 0x00a8 -#define PCI_DEVICE_ID_CIRRUS_5436 0x00ac -#define PCI_DEVICE_ID_CIRRUS_5446 0x00b8 -#define PCI_DEVICE_ID_CIRRUS_5480 0x00bc -#define PCI_DEVICE_ID_CIRRUS_5462 0x00d0 -#define PCI_DEVICE_ID_CIRRUS_5464 0x00d4 -#define PCI_DEVICE_ID_CIRRUS_5465 0x00d6 -#define PCI_DEVICE_ID_CIRRUS_6729 0x1100 -#define PCI_DEVICE_ID_CIRRUS_6832 0x1110 -#define PCI_DEVICE_ID_CIRRUS_7543 0x1202 -#define PCI_DEVICE_ID_CIRRUS_4610 0x6001 -#define PCI_DEVICE_ID_CIRRUS_4612 0x6003 -#define PCI_DEVICE_ID_CIRRUS_4615 0x6004 - -#define PCI_VENDOR_ID_IBM 0x1014 -#define PCI_DEVICE_ID_IBM_TR 0x0018 -#define PCI_DEVICE_ID_IBM_TR_WAKE 0x003e -#define PCI_DEVICE_ID_IBM_CPC710_PCI64 0x00fc -#define PCI_DEVICE_ID_IBM_SNIPE 0x0180 -#define PCI_DEVICE_ID_IBM_CITRINE 0x028C -#define PCI_DEVICE_ID_IBM_GEMSTONE 0xB166 -#define PCI_DEVICE_ID_IBM_OBSIDIAN 0x02BD -#define PCI_DEVICE_ID_IBM_ICOM_DEV_ID_1 0x0031 -#define PCI_DEVICE_ID_IBM_ICOM_DEV_ID_2 0x0219 -#define PCI_DEVICE_ID_IBM_ICOM_V2_TWO_PORTS_RVX 0x021A -#define PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM 0x0251 -#define PCI_DEVICE_ID_IBM_ICOM_V2_ONE_PORT_RVX_ONE_PORT_MDM_PCIE 0x0361 -#define PCI_DEVICE_ID_IBM_ICOM_FOUR_PORT_MODEL 0x252 - -#define PCI_SUBVENDOR_ID_IBM 0x1014 -#define PCI_SUBDEVICE_ID_IBM_SATURN_SERIAL_ONE_PORT 0x03d4 - -#define PCI_VENDOR_ID_UNISYS 0x1018 -#define PCI_DEVICE_ID_UNISYS_DMA_DIRECTOR 0x001C - -#define PCI_VENDOR_ID_COMPEX2 0x101a /* pci.ids says "AT&T GIS (NCR)" */ -#define PCI_DEVICE_ID_COMPEX2_100VG 0x0005 - -#define PCI_VENDOR_ID_WD 0x101c -#define PCI_DEVICE_ID_WD_90C 0xc24a - -#define PCI_VENDOR_ID_AMI 0x101e -#define PCI_DEVICE_ID_AMI_MEGARAID3 0x1960 -#define PCI_DEVICE_ID_AMI_MEGARAID 0x9010 -#define PCI_DEVICE_ID_AMI_MEGARAID2 0x9060 - -#define PCI_VENDOR_ID_AMD 0x1022 -#define PCI_DEVICE_ID_AMD_K8_NB 0x1100 -#define PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP 0x1101 -#define PCI_DEVICE_ID_AMD_K8_NB_MEMCTL 0x1102 -#define PCI_DEVICE_ID_AMD_K8_NB_MISC 0x1103 -#define PCI_DEVICE_ID_AMD_10H_NB_HT 0x1200 -#define PCI_DEVICE_ID_AMD_10H_NB_MAP 0x1201 -#define PCI_DEVICE_ID_AMD_10H_NB_DRAM 0x1202 -#define PCI_DEVICE_ID_AMD_10H_NB_MISC 0x1203 -#define PCI_DEVICE_ID_AMD_10H_NB_LINK 0x1204 -#define PCI_DEVICE_ID_AMD_11H_NB_HT 0x1300 -#define PCI_DEVICE_ID_AMD_11H_NB_MAP 0x1301 -#define PCI_DEVICE_ID_AMD_11H_NB_DRAM 0x1302 -#define PCI_DEVICE_ID_AMD_11H_NB_MISC 0x1303 -#define PCI_DEVICE_ID_AMD_11H_NB_LINK 0x1304 -#define PCI_DEVICE_ID_AMD_15H_M10H_F3 0x1403 -#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F3 0x141d -#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F4 0x141e -#define PCI_DEVICE_ID_AMD_15H_M60H_NB_F3 0x1573 -#define PCI_DEVICE_ID_AMD_15H_M60H_NB_F4 0x1574 -#define PCI_DEVICE_ID_AMD_15H_NB_F0 0x1600 -#define PCI_DEVICE_ID_AMD_15H_NB_F1 0x1601 -#define PCI_DEVICE_ID_AMD_15H_NB_F2 0x1602 -#define PCI_DEVICE_ID_AMD_15H_NB_F3 0x1603 -#define PCI_DEVICE_ID_AMD_15H_NB_F4 0x1604 -#define PCI_DEVICE_ID_AMD_15H_NB_F5 0x1605 -#define PCI_DEVICE_ID_AMD_16H_NB_F3 0x1533 -#define PCI_DEVICE_ID_AMD_16H_NB_F4 0x1534 -#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F3 0x1583 -#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F4 0x1584 -#define PCI_DEVICE_ID_AMD_CNB17H_F3 0x1703 -#define PCI_DEVICE_ID_AMD_LANCE 0x2000 -#define PCI_DEVICE_ID_AMD_LANCE_HOME 0x2001 -#define PCI_DEVICE_ID_AMD_SCSI 0x2020 -#define PCI_DEVICE_ID_AMD_SERENADE 0x36c0 -#define PCI_DEVICE_ID_AMD_FE_GATE_7006 0x7006 -#define PCI_DEVICE_ID_AMD_FE_GATE_7007 0x7007 -#define PCI_DEVICE_ID_AMD_FE_GATE_700C 0x700C -#define PCI_DEVICE_ID_AMD_FE_GATE_700E 0x700E -#define PCI_DEVICE_ID_AMD_COBRA_7401 0x7401 -#define PCI_DEVICE_ID_AMD_VIPER_7409 0x7409 -#define PCI_DEVICE_ID_AMD_VIPER_740B 0x740B -#define PCI_DEVICE_ID_AMD_VIPER_7410 0x7410 -#define PCI_DEVICE_ID_AMD_VIPER_7411 0x7411 -#define PCI_DEVICE_ID_AMD_VIPER_7413 0x7413 -#define PCI_DEVICE_ID_AMD_VIPER_7440 0x7440 -#define PCI_DEVICE_ID_AMD_OPUS_7441 0x7441 -#define PCI_DEVICE_ID_AMD_OPUS_7443 0x7443 -#define PCI_DEVICE_ID_AMD_VIPER_7443 0x7443 -#define PCI_DEVICE_ID_AMD_OPUS_7445 0x7445 -#define PCI_DEVICE_ID_AMD_8111_PCI 0x7460 -#define PCI_DEVICE_ID_AMD_8111_LPC 0x7468 -#define PCI_DEVICE_ID_AMD_8111_IDE 0x7469 -#define PCI_DEVICE_ID_AMD_8111_SMBUS2 0x746a -#define PCI_DEVICE_ID_AMD_8111_SMBUS 0x746b -#define PCI_DEVICE_ID_AMD_8111_AUDIO 0x746d -#define PCI_DEVICE_ID_AMD_8151_0 0x7454 -#define PCI_DEVICE_ID_AMD_8131_BRIDGE 0x7450 -#define PCI_DEVICE_ID_AMD_8131_APIC 0x7451 -#define PCI_DEVICE_ID_AMD_8132_BRIDGE 0x7458 -#define PCI_DEVICE_ID_AMD_NL_USB 0x7912 -#define PCI_DEVICE_ID_AMD_CS5535_IDE 0x208F -#define PCI_DEVICE_ID_AMD_CS5536_ISA 0x2090 -#define PCI_DEVICE_ID_AMD_CS5536_FLASH 0x2091 -#define PCI_DEVICE_ID_AMD_CS5536_AUDIO 0x2093 -#define PCI_DEVICE_ID_AMD_CS5536_OHC 0x2094 -#define PCI_DEVICE_ID_AMD_CS5536_EHC 0x2095 -#define PCI_DEVICE_ID_AMD_CS5536_UDC 0x2096 -#define PCI_DEVICE_ID_AMD_CS5536_UOC 0x2097 -#define PCI_DEVICE_ID_AMD_CS5536_IDE 0x209A -#define PCI_DEVICE_ID_AMD_LX_VIDEO 0x2081 -#define PCI_DEVICE_ID_AMD_LX_AES 0x2082 -#define PCI_DEVICE_ID_AMD_HUDSON2_SATA_IDE 0x7800 -#define PCI_DEVICE_ID_AMD_HUDSON2_SMBUS 0x780b -#define PCI_DEVICE_ID_AMD_HUDSON2_IDE 0x780c -#define PCI_DEVICE_ID_AMD_KERNCZ_SMBUS 0x790b - -#define PCI_VENDOR_ID_TRIDENT 0x1023 -#define PCI_DEVICE_ID_TRIDENT_4DWAVE_DX 0x2000 -#define PCI_DEVICE_ID_TRIDENT_4DWAVE_NX 0x2001 -#define PCI_DEVICE_ID_TRIDENT_9320 0x9320 -#define PCI_DEVICE_ID_TRIDENT_9388 0x9388 -#define PCI_DEVICE_ID_TRIDENT_9397 0x9397 -#define PCI_DEVICE_ID_TRIDENT_939A 0x939A -#define PCI_DEVICE_ID_TRIDENT_9520 0x9520 -#define PCI_DEVICE_ID_TRIDENT_9525 0x9525 -#define PCI_DEVICE_ID_TRIDENT_9420 0x9420 -#define PCI_DEVICE_ID_TRIDENT_9440 0x9440 -#define PCI_DEVICE_ID_TRIDENT_9660 0x9660 -#define PCI_DEVICE_ID_TRIDENT_9750 0x9750 -#define PCI_DEVICE_ID_TRIDENT_9850 0x9850 -#define PCI_DEVICE_ID_TRIDENT_9880 0x9880 -#define PCI_DEVICE_ID_TRIDENT_8400 0x8400 -#define PCI_DEVICE_ID_TRIDENT_8420 0x8420 -#define PCI_DEVICE_ID_TRIDENT_8500 0x8500 - -#define PCI_VENDOR_ID_AI 0x1025 -#define PCI_DEVICE_ID_AI_M1435 0x1435 - -#define PCI_VENDOR_ID_DELL 0x1028 -#define PCI_DEVICE_ID_DELL_RACIII 0x0008 -#define PCI_DEVICE_ID_DELL_RAC4 0x0012 -#define PCI_DEVICE_ID_DELL_PERC5 0x0015 - -#define PCI_VENDOR_ID_MATROX 0x102B -#define PCI_DEVICE_ID_MATROX_MGA_2 0x0518 -#define PCI_DEVICE_ID_MATROX_MIL 0x0519 -#define PCI_DEVICE_ID_MATROX_MYS 0x051A -#define PCI_DEVICE_ID_MATROX_MIL_2 0x051b -#define PCI_DEVICE_ID_MATROX_MYS_AGP 0x051e -#define PCI_DEVICE_ID_MATROX_MIL_2_AGP 0x051f -#define PCI_DEVICE_ID_MATROX_MGA_IMP 0x0d10 -#define PCI_DEVICE_ID_MATROX_G100_MM 0x1000 -#define PCI_DEVICE_ID_MATROX_G100_AGP 0x1001 -#define PCI_DEVICE_ID_MATROX_G200_PCI 0x0520 -#define PCI_DEVICE_ID_MATROX_G200_AGP 0x0521 -#define PCI_DEVICE_ID_MATROX_G400 0x0525 -#define PCI_DEVICE_ID_MATROX_G200EV_PCI 0x0530 -#define PCI_DEVICE_ID_MATROX_G550 0x2527 -#define PCI_DEVICE_ID_MATROX_VIA 0x4536 - -#define PCI_VENDOR_ID_MOBILITY_ELECTRONICS 0x14f2 - -#define PCI_VENDOR_ID_CT 0x102c -#define PCI_DEVICE_ID_CT_69000 0x00c0 -#define PCI_DEVICE_ID_CT_65545 0x00d8 -#define PCI_DEVICE_ID_CT_65548 0x00dc -#define PCI_DEVICE_ID_CT_65550 0x00e0 -#define PCI_DEVICE_ID_CT_65554 0x00e4 -#define PCI_DEVICE_ID_CT_65555 0x00e5 - -#define PCI_VENDOR_ID_MIRO 0x1031 -#define PCI_DEVICE_ID_MIRO_36050 0x5601 -#define PCI_DEVICE_ID_MIRO_DC10PLUS 0x7efe -#define PCI_DEVICE_ID_MIRO_DC30PLUS 0xd801 - -#define PCI_VENDOR_ID_NEC 0x1033 -#define PCI_DEVICE_ID_NEC_CBUS_1 0x0001 /* PCI-Cbus Bridge */ -#define PCI_DEVICE_ID_NEC_LOCAL 0x0002 /* Local Bridge */ -#define PCI_DEVICE_ID_NEC_ATM 0x0003 /* ATM LAN Controller */ -#define PCI_DEVICE_ID_NEC_R4000 0x0004 /* R4000 Bridge */ -#define PCI_DEVICE_ID_NEC_486 0x0005 /* 486 Like Peripheral Bus Bridge */ -#define PCI_DEVICE_ID_NEC_ACCEL_1 0x0006 /* Graphic Accelerator */ -#define PCI_DEVICE_ID_NEC_UXBUS 0x0007 /* UX-Bus Bridge */ -#define PCI_DEVICE_ID_NEC_ACCEL_2 0x0008 /* Graphic Accelerator */ -#define PCI_DEVICE_ID_NEC_GRAPH 0x0009 /* PCI-CoreGraph Bridge */ -#define PCI_DEVICE_ID_NEC_VL 0x0016 /* PCI-VL Bridge */ -#define PCI_DEVICE_ID_NEC_STARALPHA2 0x002c /* STAR ALPHA2 */ -#define PCI_DEVICE_ID_NEC_CBUS_2 0x002d /* PCI-Cbus Bridge */ -#define PCI_DEVICE_ID_NEC_USB 0x0035 /* PCI-USB Host */ -#define PCI_DEVICE_ID_NEC_CBUS_3 0x003b -#define PCI_DEVICE_ID_NEC_NAPCCARD 0x003e -#define PCI_DEVICE_ID_NEC_PCX2 0x0046 /* PowerVR */ -#define PCI_DEVICE_ID_NEC_VRC5476 0x009b -#define PCI_DEVICE_ID_NEC_VRC4173 0x00a5 -#define PCI_DEVICE_ID_NEC_VRC5477_AC97 0x00a6 -#define PCI_DEVICE_ID_NEC_PC9821CS01 0x800c /* PC-9821-CS01 */ -#define PCI_DEVICE_ID_NEC_PC9821NRB06 0x800d /* PC-9821NR-B06 */ - -#define PCI_VENDOR_ID_FD 0x1036 -#define PCI_DEVICE_ID_FD_36C70 0x0000 - -#define PCI_VENDOR_ID_SI 0x1039 -#define PCI_DEVICE_ID_SI_5591_AGP 0x0001 -#define PCI_DEVICE_ID_SI_6202 0x0002 -#define PCI_DEVICE_ID_SI_503 0x0008 -#define PCI_DEVICE_ID_SI_ACPI 0x0009 -#define PCI_DEVICE_ID_SI_SMBUS 0x0016 -#define PCI_DEVICE_ID_SI_LPC 0x0018 -#define PCI_DEVICE_ID_SI_5597_VGA 0x0200 -#define PCI_DEVICE_ID_SI_6205 0x0205 -#define PCI_DEVICE_ID_SI_501 0x0406 -#define PCI_DEVICE_ID_SI_496 0x0496 -#define PCI_DEVICE_ID_SI_300 0x0300 -#define PCI_DEVICE_ID_SI_315H 0x0310 -#define PCI_DEVICE_ID_SI_315 0x0315 -#define PCI_DEVICE_ID_SI_315PRO 0x0325 -#define PCI_DEVICE_ID_SI_530 0x0530 -#define PCI_DEVICE_ID_SI_540 0x0540 -#define PCI_DEVICE_ID_SI_550 0x0550 -#define PCI_DEVICE_ID_SI_540_VGA 0x5300 -#define PCI_DEVICE_ID_SI_550_VGA 0x5315 -#define PCI_DEVICE_ID_SI_620 0x0620 -#define PCI_DEVICE_ID_SI_630 0x0630 -#define PCI_DEVICE_ID_SI_633 0x0633 -#define PCI_DEVICE_ID_SI_635 0x0635 -#define PCI_DEVICE_ID_SI_640 0x0640 -#define PCI_DEVICE_ID_SI_645 0x0645 -#define PCI_DEVICE_ID_SI_646 0x0646 -#define PCI_DEVICE_ID_SI_648 0x0648 -#define PCI_DEVICE_ID_SI_650 0x0650 -#define PCI_DEVICE_ID_SI_651 0x0651 -#define PCI_DEVICE_ID_SI_655 0x0655 -#define PCI_DEVICE_ID_SI_661 0x0661 -#define PCI_DEVICE_ID_SI_730 0x0730 -#define PCI_DEVICE_ID_SI_733 0x0733 -#define PCI_DEVICE_ID_SI_630_VGA 0x6300 -#define PCI_DEVICE_ID_SI_735 0x0735 -#define PCI_DEVICE_ID_SI_740 0x0740 -#define PCI_DEVICE_ID_SI_741 0x0741 -#define PCI_DEVICE_ID_SI_745 0x0745 -#define PCI_DEVICE_ID_SI_746 0x0746 -#define PCI_DEVICE_ID_SI_755 0x0755 -#define PCI_DEVICE_ID_SI_760 0x0760 -#define PCI_DEVICE_ID_SI_900 0x0900 -#define PCI_DEVICE_ID_SI_961 0x0961 -#define PCI_DEVICE_ID_SI_962 0x0962 -#define PCI_DEVICE_ID_SI_963 0x0963 -#define PCI_DEVICE_ID_SI_965 0x0965 -#define PCI_DEVICE_ID_SI_966 0x0966 -#define PCI_DEVICE_ID_SI_968 0x0968 -#define PCI_DEVICE_ID_SI_1180 0x1180 -#define PCI_DEVICE_ID_SI_5511 0x5511 -#define PCI_DEVICE_ID_SI_5513 0x5513 -#define PCI_DEVICE_ID_SI_5517 0x5517 -#define PCI_DEVICE_ID_SI_5518 0x5518 -#define PCI_DEVICE_ID_SI_5571 0x5571 -#define PCI_DEVICE_ID_SI_5581 0x5581 -#define PCI_DEVICE_ID_SI_5582 0x5582 -#define PCI_DEVICE_ID_SI_5591 0x5591 -#define PCI_DEVICE_ID_SI_5596 0x5596 -#define PCI_DEVICE_ID_SI_5597 0x5597 -#define PCI_DEVICE_ID_SI_5598 0x5598 -#define PCI_DEVICE_ID_SI_5600 0x5600 -#define PCI_DEVICE_ID_SI_7012 0x7012 -#define PCI_DEVICE_ID_SI_7013 0x7013 -#define PCI_DEVICE_ID_SI_7016 0x7016 -#define PCI_DEVICE_ID_SI_7018 0x7018 - -#define PCI_VENDOR_ID_HP 0x103c -#define PCI_VENDOR_ID_HP_3PAR 0x1590 -#define PCI_DEVICE_ID_HP_VISUALIZE_EG 0x1005 -#define PCI_DEVICE_ID_HP_VISUALIZE_FX6 0x1006 -#define PCI_DEVICE_ID_HP_VISUALIZE_FX4 0x1008 -#define PCI_DEVICE_ID_HP_VISUALIZE_FX2 0x100a -#define PCI_DEVICE_ID_HP_TACHYON 0x1028 -#define PCI_DEVICE_ID_HP_TACHLITE 0x1029 -#define PCI_DEVICE_ID_HP_J2585A 0x1030 -#define PCI_DEVICE_ID_HP_J2585B 0x1031 -#define PCI_DEVICE_ID_HP_J2973A 0x1040 -#define PCI_DEVICE_ID_HP_J2970A 0x1042 -#define PCI_DEVICE_ID_HP_DIVA 0x1048 -#define PCI_DEVICE_ID_HP_DIVA_TOSCA1 0x1049 -#define PCI_DEVICE_ID_HP_DIVA_TOSCA2 0x104A -#define PCI_DEVICE_ID_HP_DIVA_MAESTRO 0x104B -#define PCI_DEVICE_ID_HP_REO_IOC 0x10f1 -#define PCI_DEVICE_ID_HP_VISUALIZE_FXE 0x108b -#define PCI_DEVICE_ID_HP_DIVA_HALFDOME 0x1223 -#define PCI_DEVICE_ID_HP_DIVA_KEYSTONE 0x1226 -#define PCI_DEVICE_ID_HP_DIVA_POWERBAR 0x1227 -#define PCI_DEVICE_ID_HP_ZX1_IOC 0x122a -#define PCI_DEVICE_ID_HP_PCIX_LBA 0x122e -#define PCI_DEVICE_ID_HP_SX1000_IOC 0x127c -#define PCI_DEVICE_ID_HP_DIVA_EVEREST 0x1282 -#define PCI_DEVICE_ID_HP_DIVA_AUX 0x1290 -#define PCI_DEVICE_ID_HP_DIVA_RMP3 0x1301 -#define PCI_DEVICE_ID_HP_DIVA_HURRICANE 0x132a -#define PCI_DEVICE_ID_HP_CISSA 0x3220 -#define PCI_DEVICE_ID_HP_CISSC 0x3230 -#define PCI_DEVICE_ID_HP_CISSD 0x3238 -#define PCI_DEVICE_ID_HP_CISSE 0x323a -#define PCI_DEVICE_ID_HP_CISSF 0x323b -#define PCI_DEVICE_ID_HP_CISSH 0x323c -#define PCI_DEVICE_ID_HP_CISSI 0x3239 -#define PCI_DEVICE_ID_HP_ZX2_IOC 0x4031 - -#define PCI_VENDOR_ID_PCTECH 0x1042 -#define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000 -#define PCI_DEVICE_ID_PCTECH_RZ1001 0x1001 -#define PCI_DEVICE_ID_PCTECH_SAMURAI_IDE 0x3020 - -#define PCI_VENDOR_ID_ASUSTEK 0x1043 -#define PCI_DEVICE_ID_ASUSTEK_0675 0x0675 - -#define PCI_VENDOR_ID_DPT 0x1044 -#define PCI_DEVICE_ID_DPT 0xa400 - -#define PCI_VENDOR_ID_OPTI 0x1045 -#define PCI_DEVICE_ID_OPTI_82C558 0xc558 -#define PCI_DEVICE_ID_OPTI_82C621 0xc621 -#define PCI_DEVICE_ID_OPTI_82C700 0xc700 -#define PCI_DEVICE_ID_OPTI_82C825 0xd568 - -#define PCI_VENDOR_ID_ELSA 0x1048 -#define PCI_DEVICE_ID_ELSA_MICROLINK 0x1000 -#define PCI_DEVICE_ID_ELSA_QS3000 0x3000 - -#define PCI_VENDOR_ID_STMICRO 0x104A -#define PCI_DEVICE_ID_STMICRO_USB_HOST 0xCC00 -#define PCI_DEVICE_ID_STMICRO_USB_OHCI 0xCC01 -#define PCI_DEVICE_ID_STMICRO_USB_OTG 0xCC02 -#define PCI_DEVICE_ID_STMICRO_UART_HWFC 0xCC03 -#define PCI_DEVICE_ID_STMICRO_UART_NO_HWFC 0xCC04 -#define PCI_DEVICE_ID_STMICRO_SOC_DMA 0xCC05 -#define PCI_DEVICE_ID_STMICRO_SATA 0xCC06 -#define PCI_DEVICE_ID_STMICRO_I2C 0xCC07 -#define PCI_DEVICE_ID_STMICRO_SPI_HS 0xCC08 -#define PCI_DEVICE_ID_STMICRO_MAC 0xCC09 -#define PCI_DEVICE_ID_STMICRO_SDIO_EMMC 0xCC0A -#define PCI_DEVICE_ID_STMICRO_SDIO 0xCC0B -#define PCI_DEVICE_ID_STMICRO_GPIO 0xCC0C -#define PCI_DEVICE_ID_STMICRO_VIP 0xCC0D -#define PCI_DEVICE_ID_STMICRO_AUDIO_ROUTER_DMA 0xCC0E -#define PCI_DEVICE_ID_STMICRO_AUDIO_ROUTER_SRCS 0xCC0F -#define PCI_DEVICE_ID_STMICRO_AUDIO_ROUTER_MSPS 0xCC10 -#define PCI_DEVICE_ID_STMICRO_CAN 0xCC11 -#define PCI_DEVICE_ID_STMICRO_MLB 0xCC12 -#define PCI_DEVICE_ID_STMICRO_DBP 0xCC13 -#define PCI_DEVICE_ID_STMICRO_SATA_PHY 0xCC14 -#define PCI_DEVICE_ID_STMICRO_ESRAM 0xCC15 -#define PCI_DEVICE_ID_STMICRO_VIC 0xCC16 - -#define PCI_VENDOR_ID_BUSLOGIC 0x104B -#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC 0x0140 -#define PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER 0x1040 -#define PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT 0x8130 - -#define PCI_VENDOR_ID_TI 0x104c -#define PCI_DEVICE_ID_TI_TVP4020 0x3d07 -#define PCI_DEVICE_ID_TI_4450 0x8011 -#define PCI_DEVICE_ID_TI_XX21_XX11 0x8031 -#define PCI_DEVICE_ID_TI_XX21_XX11_FM 0x8033 -#define PCI_DEVICE_ID_TI_XX21_XX11_SD 0x8034 -#define PCI_DEVICE_ID_TI_X515 0x8036 -#define PCI_DEVICE_ID_TI_XX12 0x8039 -#define PCI_DEVICE_ID_TI_XX12_FM 0x803b -#define PCI_DEVICE_ID_TI_XIO2000A 0x8231 -#define PCI_DEVICE_ID_TI_1130 0xac12 -#define PCI_DEVICE_ID_TI_1031 0xac13 -#define PCI_DEVICE_ID_TI_1131 0xac15 -#define PCI_DEVICE_ID_TI_1250 0xac16 -#define PCI_DEVICE_ID_TI_1220 0xac17 -#define PCI_DEVICE_ID_TI_1221 0xac19 -#define PCI_DEVICE_ID_TI_1210 0xac1a -#define PCI_DEVICE_ID_TI_1450 0xac1b -#define PCI_DEVICE_ID_TI_1225 0xac1c -#define PCI_DEVICE_ID_TI_1251A 0xac1d -#define PCI_DEVICE_ID_TI_1211 0xac1e -#define PCI_DEVICE_ID_TI_1251B 0xac1f -#define PCI_DEVICE_ID_TI_4410 0xac41 -#define PCI_DEVICE_ID_TI_4451 0xac42 -#define PCI_DEVICE_ID_TI_4510 0xac44 -#define PCI_DEVICE_ID_TI_4520 0xac46 -#define PCI_DEVICE_ID_TI_7510 0xac47 -#define PCI_DEVICE_ID_TI_7610 0xac48 -#define PCI_DEVICE_ID_TI_7410 0xac49 -#define PCI_DEVICE_ID_TI_1410 0xac50 -#define PCI_DEVICE_ID_TI_1420 0xac51 -#define PCI_DEVICE_ID_TI_1451A 0xac52 -#define PCI_DEVICE_ID_TI_1620 0xac54 -#define PCI_DEVICE_ID_TI_1520 0xac55 -#define PCI_DEVICE_ID_TI_1510 0xac56 -#define PCI_DEVICE_ID_TI_X620 0xac8d -#define PCI_DEVICE_ID_TI_X420 0xac8e -#define PCI_DEVICE_ID_TI_XX20_FM 0xac8f - -#define PCI_VENDOR_ID_SONY 0x104d - -/* Winbond have two vendor IDs! See 0x10ad as well */ -#define PCI_VENDOR_ID_WINBOND2 0x1050 -#define PCI_DEVICE_ID_WINBOND2_89C940F 0x5a5a -#define PCI_DEVICE_ID_WINBOND2_6692 0x6692 - -#define PCI_VENDOR_ID_ANIGMA 0x1051 -#define PCI_DEVICE_ID_ANIGMA_MC145575 0x0100 - -#define PCI_VENDOR_ID_EFAR 0x1055 -#define PCI_DEVICE_ID_EFAR_SLC90E66_1 0x9130 -#define PCI_DEVICE_ID_EFAR_SLC90E66_3 0x9463 - -#define PCI_VENDOR_ID_MOTOROLA 0x1057 -#define PCI_DEVICE_ID_MOTOROLA_MPC105 0x0001 -#define PCI_DEVICE_ID_MOTOROLA_MPC106 0x0002 -#define PCI_DEVICE_ID_MOTOROLA_MPC107 0x0004 -#define PCI_DEVICE_ID_MOTOROLA_RAVEN 0x4801 -#define PCI_DEVICE_ID_MOTOROLA_FALCON 0x4802 -#define PCI_DEVICE_ID_MOTOROLA_HAWK 0x4803 -#define PCI_DEVICE_ID_MOTOROLA_HARRIER 0x480b -#define PCI_DEVICE_ID_MOTOROLA_MPC5200 0x5803 -#define PCI_DEVICE_ID_MOTOROLA_MPC5200B 0x5809 - -#define PCI_VENDOR_ID_PROMISE 0x105a -#define PCI_DEVICE_ID_PROMISE_20265 0x0d30 -#define PCI_DEVICE_ID_PROMISE_20267 0x4d30 -#define PCI_DEVICE_ID_PROMISE_20246 0x4d33 -#define PCI_DEVICE_ID_PROMISE_20262 0x4d38 -#define PCI_DEVICE_ID_PROMISE_20263 0x0D38 -#define PCI_DEVICE_ID_PROMISE_20268 0x4d68 -#define PCI_DEVICE_ID_PROMISE_20269 0x4d69 -#define PCI_DEVICE_ID_PROMISE_20270 0x6268 -#define PCI_DEVICE_ID_PROMISE_20271 0x6269 -#define PCI_DEVICE_ID_PROMISE_20275 0x1275 -#define PCI_DEVICE_ID_PROMISE_20276 0x5275 -#define PCI_DEVICE_ID_PROMISE_20277 0x7275 - -#define PCI_VENDOR_ID_FOXCONN 0x105b - -#define PCI_VENDOR_ID_UMC 0x1060 -#define PCI_DEVICE_ID_UMC_UM8673F 0x0101 -#define PCI_DEVICE_ID_UMC_UM8886BF 0x673a -#define PCI_DEVICE_ID_UMC_UM8886A 0x886a - -#define PCI_VENDOR_ID_PICOPOWER 0x1066 -#define PCI_DEVICE_ID_PICOPOWER_PT86C523 0x0002 -#define PCI_DEVICE_ID_PICOPOWER_PT86C523BBP 0x8002 - -#define PCI_VENDOR_ID_MYLEX 0x1069 -#define PCI_DEVICE_ID_MYLEX_DAC960_P 0x0001 -#define PCI_DEVICE_ID_MYLEX_DAC960_PD 0x0002 -#define PCI_DEVICE_ID_MYLEX_DAC960_PG 0x0010 -#define PCI_DEVICE_ID_MYLEX_DAC960_LA 0x0020 -#define PCI_DEVICE_ID_MYLEX_DAC960_LP 0x0050 -#define PCI_DEVICE_ID_MYLEX_DAC960_BA 0xBA56 -#define PCI_DEVICE_ID_MYLEX_DAC960_GEM 0xB166 - -#define PCI_VENDOR_ID_APPLE 0x106b -#define PCI_DEVICE_ID_APPLE_BANDIT 0x0001 -#define PCI_DEVICE_ID_APPLE_HYDRA 0x000e -#define PCI_DEVICE_ID_APPLE_UNI_N_FW 0x0018 -#define PCI_DEVICE_ID_APPLE_UNI_N_AGP 0x0020 -#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC 0x0021 -#define PCI_DEVICE_ID_APPLE_UNI_N_GMACP 0x0024 -#define PCI_DEVICE_ID_APPLE_UNI_N_AGP_P 0x0027 -#define PCI_DEVICE_ID_APPLE_UNI_N_AGP15 0x002d -#define PCI_DEVICE_ID_APPLE_UNI_N_PCI15 0x002e -#define PCI_DEVICE_ID_APPLE_UNI_N_GMAC2 0x0032 -#define PCI_DEVICE_ID_APPLE_UNI_N_ATA 0x0033 -#define PCI_DEVICE_ID_APPLE_UNI_N_AGP2 0x0034 -#define PCI_DEVICE_ID_APPLE_IPID_ATA100 0x003b -#define PCI_DEVICE_ID_APPLE_K2_ATA100 0x0043 -#define PCI_DEVICE_ID_APPLE_U3_AGP 0x004b -#define PCI_DEVICE_ID_APPLE_K2_GMAC 0x004c -#define PCI_DEVICE_ID_APPLE_SH_ATA 0x0050 -#define PCI_DEVICE_ID_APPLE_SH_SUNGEM 0x0051 -#define PCI_DEVICE_ID_APPLE_U3L_AGP 0x0058 -#define PCI_DEVICE_ID_APPLE_U3H_AGP 0x0059 -#define PCI_DEVICE_ID_APPLE_U4_PCIE 0x005b -#define PCI_DEVICE_ID_APPLE_IPID2_AGP 0x0066 -#define PCI_DEVICE_ID_APPLE_IPID2_ATA 0x0069 -#define PCI_DEVICE_ID_APPLE_IPID2_FW 0x006a -#define PCI_DEVICE_ID_APPLE_IPID2_GMAC 0x006b -#define PCI_DEVICE_ID_APPLE_TIGON3 0x1645 - -#define PCI_VENDOR_ID_YAMAHA 0x1073 -#define PCI_DEVICE_ID_YAMAHA_724 0x0004 -#define PCI_DEVICE_ID_YAMAHA_724F 0x000d -#define PCI_DEVICE_ID_YAMAHA_740 0x000a -#define PCI_DEVICE_ID_YAMAHA_740C 0x000c -#define PCI_DEVICE_ID_YAMAHA_744 0x0010 -#define PCI_DEVICE_ID_YAMAHA_754 0x0012 - -#define PCI_VENDOR_ID_QLOGIC 0x1077 -#define PCI_DEVICE_ID_QLOGIC_ISP10160 0x1016 -#define PCI_DEVICE_ID_QLOGIC_ISP1020 0x1020 -#define PCI_DEVICE_ID_QLOGIC_ISP1080 0x1080 -#define PCI_DEVICE_ID_QLOGIC_ISP12160 0x1216 -#define PCI_DEVICE_ID_QLOGIC_ISP1240 0x1240 -#define PCI_DEVICE_ID_QLOGIC_ISP1280 0x1280 -#define PCI_DEVICE_ID_QLOGIC_ISP2100 0x2100 -#define PCI_DEVICE_ID_QLOGIC_ISP2200 0x2200 -#define PCI_DEVICE_ID_QLOGIC_ISP2300 0x2300 -#define PCI_DEVICE_ID_QLOGIC_ISP2312 0x2312 -#define PCI_DEVICE_ID_QLOGIC_ISP2322 0x2322 -#define PCI_DEVICE_ID_QLOGIC_ISP6312 0x6312 -#define PCI_DEVICE_ID_QLOGIC_ISP6322 0x6322 -#define PCI_DEVICE_ID_QLOGIC_ISP2422 0x2422 -#define PCI_DEVICE_ID_QLOGIC_ISP2432 0x2432 -#define PCI_DEVICE_ID_QLOGIC_ISP2512 0x2512 -#define PCI_DEVICE_ID_QLOGIC_ISP2522 0x2522 -#define PCI_DEVICE_ID_QLOGIC_ISP5422 0x5422 -#define PCI_DEVICE_ID_QLOGIC_ISP5432 0x5432 - -#define PCI_VENDOR_ID_CYRIX 0x1078 -#define PCI_DEVICE_ID_CYRIX_5510 0x0000 -#define PCI_DEVICE_ID_CYRIX_PCI_MASTER 0x0001 -#define PCI_DEVICE_ID_CYRIX_5520 0x0002 -#define PCI_DEVICE_ID_CYRIX_5530_LEGACY 0x0100 -#define PCI_DEVICE_ID_CYRIX_5530_IDE 0x0102 -#define PCI_DEVICE_ID_CYRIX_5530_AUDIO 0x0103 -#define PCI_DEVICE_ID_CYRIX_5530_VIDEO 0x0104 - -#define PCI_VENDOR_ID_CONTAQ 0x1080 -#define PCI_DEVICE_ID_CONTAQ_82C693 0xc693 - -#define PCI_VENDOR_ID_OLICOM 0x108d -#define PCI_DEVICE_ID_OLICOM_OC2325 0x0012 -#define PCI_DEVICE_ID_OLICOM_OC2183 0x0013 -#define PCI_DEVICE_ID_OLICOM_OC2326 0x0014 - -#define PCI_VENDOR_ID_SUN 0x108e -#define PCI_DEVICE_ID_SUN_EBUS 0x1000 -#define PCI_DEVICE_ID_SUN_HAPPYMEAL 0x1001 -#define PCI_DEVICE_ID_SUN_RIO_EBUS 0x1100 -#define PCI_DEVICE_ID_SUN_RIO_GEM 0x1101 -#define PCI_DEVICE_ID_SUN_RIO_1394 0x1102 -#define PCI_DEVICE_ID_SUN_RIO_USB 0x1103 -#define PCI_DEVICE_ID_SUN_GEM 0x2bad -#define PCI_DEVICE_ID_SUN_SIMBA 0x5000 -#define PCI_DEVICE_ID_SUN_PBM 0x8000 -#define PCI_DEVICE_ID_SUN_SCHIZO 0x8001 -#define PCI_DEVICE_ID_SUN_SABRE 0xa000 -#define PCI_DEVICE_ID_SUN_HUMMINGBIRD 0xa001 -#define PCI_DEVICE_ID_SUN_TOMATILLO 0xa801 -#define PCI_DEVICE_ID_SUN_CASSINI 0xabba - -#define PCI_VENDOR_ID_NI 0x1093 -#define PCI_DEVICE_ID_NI_PCI2322 0xd130 -#define PCI_DEVICE_ID_NI_PCI2324 0xd140 -#define PCI_DEVICE_ID_NI_PCI2328 0xd150 -#define PCI_DEVICE_ID_NI_PXI8422_2322 0xd190 -#define PCI_DEVICE_ID_NI_PXI8422_2324 0xd1a0 -#define PCI_DEVICE_ID_NI_PXI8420_2322 0xd1d0 -#define PCI_DEVICE_ID_NI_PXI8420_2324 0xd1e0 -#define PCI_DEVICE_ID_NI_PXI8420_2328 0xd1f0 -#define PCI_DEVICE_ID_NI_PXI8420_23216 0xd1f1 -#define PCI_DEVICE_ID_NI_PCI2322I 0xd250 -#define PCI_DEVICE_ID_NI_PCI2324I 0xd270 -#define PCI_DEVICE_ID_NI_PCI23216 0xd2b0 -#define PCI_DEVICE_ID_NI_PXI8430_2322 0x7080 -#define PCI_DEVICE_ID_NI_PCI8430_2322 0x70db -#define PCI_DEVICE_ID_NI_PXI8430_2324 0x70dd -#define PCI_DEVICE_ID_NI_PCI8430_2324 0x70df -#define PCI_DEVICE_ID_NI_PXI8430_2328 0x70e2 -#define PCI_DEVICE_ID_NI_PCI8430_2328 0x70e4 -#define PCI_DEVICE_ID_NI_PXI8430_23216 0x70e6 -#define PCI_DEVICE_ID_NI_PCI8430_23216 0x70e7 -#define PCI_DEVICE_ID_NI_PXI8432_2322 0x70e8 -#define PCI_DEVICE_ID_NI_PCI8432_2322 0x70ea -#define PCI_DEVICE_ID_NI_PXI8432_2324 0x70ec -#define PCI_DEVICE_ID_NI_PCI8432_2324 0x70ee - -#define PCI_VENDOR_ID_CMD 0x1095 -#define PCI_DEVICE_ID_CMD_643 0x0643 -#define PCI_DEVICE_ID_CMD_646 0x0646 -#define PCI_DEVICE_ID_CMD_648 0x0648 -#define PCI_DEVICE_ID_CMD_649 0x0649 - -#define PCI_DEVICE_ID_SII_680 0x0680 -#define PCI_DEVICE_ID_SII_3112 0x3112 -#define PCI_DEVICE_ID_SII_1210SA 0x0240 - -#define PCI_VENDOR_ID_BROOKTREE 0x109e -#define PCI_DEVICE_ID_BROOKTREE_878 0x0878 -#define PCI_DEVICE_ID_BROOKTREE_879 0x0879 - -#define PCI_VENDOR_ID_SGI 0x10a9 -#define PCI_DEVICE_ID_SGI_IOC3 0x0003 -#define PCI_DEVICE_ID_SGI_LITHIUM 0x1002 -#define PCI_DEVICE_ID_SGI_IOC4 0x100a - -#define PCI_VENDOR_ID_WINBOND 0x10ad -#define PCI_DEVICE_ID_WINBOND_82C105 0x0105 -#define PCI_DEVICE_ID_WINBOND_83C553 0x0565 - -#define PCI_VENDOR_ID_PLX 0x10b5 -#define PCI_DEVICE_ID_PLX_R685 0x1030 -#define PCI_DEVICE_ID_PLX_ROMULUS 0x106a -#define PCI_DEVICE_ID_PLX_SPCOM800 0x1076 -#define PCI_DEVICE_ID_PLX_1077 0x1077 -#define PCI_DEVICE_ID_PLX_SPCOM200 0x1103 -#define PCI_DEVICE_ID_PLX_DJINN_ITOO 0x1151 -#define PCI_DEVICE_ID_PLX_R753 0x1152 -#define PCI_DEVICE_ID_PLX_OLITEC 0x1187 -#define PCI_DEVICE_ID_PLX_PCI200SYN 0x3196 -#define PCI_DEVICE_ID_PLX_9030 0x9030 -#define PCI_DEVICE_ID_PLX_9050 0x9050 -#define PCI_DEVICE_ID_PLX_9056 0x9056 -#define PCI_DEVICE_ID_PLX_9080 0x9080 -#define PCI_DEVICE_ID_PLX_GTEK_SERIAL2 0xa001 - -#define PCI_VENDOR_ID_MADGE 0x10b6 -#define PCI_DEVICE_ID_MADGE_MK2 0x0002 - -#define PCI_VENDOR_ID_3COM 0x10b7 -#define PCI_DEVICE_ID_3COM_3C985 0x0001 -#define PCI_DEVICE_ID_3COM_3C940 0x1700 -#define PCI_DEVICE_ID_3COM_3C339 0x3390 -#define PCI_DEVICE_ID_3COM_3C359 0x3590 -#define PCI_DEVICE_ID_3COM_3C940B 0x80eb -#define PCI_DEVICE_ID_3COM_3CR990 0x9900 -#define PCI_DEVICE_ID_3COM_3CR990_TX_95 0x9902 -#define PCI_DEVICE_ID_3COM_3CR990_TX_97 0x9903 -#define PCI_DEVICE_ID_3COM_3CR990B 0x9904 -#define PCI_DEVICE_ID_3COM_3CR990_FX 0x9905 -#define PCI_DEVICE_ID_3COM_3CR990SVR95 0x9908 -#define PCI_DEVICE_ID_3COM_3CR990SVR97 0x9909 -#define PCI_DEVICE_ID_3COM_3CR990SVR 0x990a - -#define PCI_VENDOR_ID_AL 0x10b9 -#define PCI_DEVICE_ID_AL_M1533 0x1533 -#define PCI_DEVICE_ID_AL_M1535 0x1535 -#define PCI_DEVICE_ID_AL_M1541 0x1541 -#define PCI_DEVICE_ID_AL_M1563 0x1563 -#define PCI_DEVICE_ID_AL_M1621 0x1621 -#define PCI_DEVICE_ID_AL_M1631 0x1631 -#define PCI_DEVICE_ID_AL_M1632 0x1632 -#define PCI_DEVICE_ID_AL_M1641 0x1641 -#define PCI_DEVICE_ID_AL_M1644 0x1644 -#define PCI_DEVICE_ID_AL_M1647 0x1647 -#define PCI_DEVICE_ID_AL_M1651 0x1651 -#define PCI_DEVICE_ID_AL_M1671 0x1671 -#define PCI_DEVICE_ID_AL_M1681 0x1681 -#define PCI_DEVICE_ID_AL_M1683 0x1683 -#define PCI_DEVICE_ID_AL_M1689 0x1689 -#define PCI_DEVICE_ID_AL_M5219 0x5219 -#define PCI_DEVICE_ID_AL_M5228 0x5228 -#define PCI_DEVICE_ID_AL_M5229 0x5229 -#define PCI_DEVICE_ID_AL_M5451 0x5451 -#define PCI_DEVICE_ID_AL_M7101 0x7101 - -#define PCI_VENDOR_ID_NEOMAGIC 0x10c8 -#define PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO 0x8005 -#define PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO 0x8006 -#define PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO 0x8016 - -#define PCI_VENDOR_ID_TCONRAD 0x10da -#define PCI_DEVICE_ID_TCONRAD_TOKENRING 0x0508 - -#define PCI_VENDOR_ID_NVIDIA 0x10de -#define PCI_DEVICE_ID_NVIDIA_TNT 0x0020 -#define PCI_DEVICE_ID_NVIDIA_TNT2 0x0028 -#define PCI_DEVICE_ID_NVIDIA_UTNT2 0x0029 -#define PCI_DEVICE_ID_NVIDIA_TNT_UNKNOWN 0x002a -#define PCI_DEVICE_ID_NVIDIA_VTNT2 0x002C -#define PCI_DEVICE_ID_NVIDIA_UVTNT2 0x002D -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SMBUS 0x0034 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE 0x0035 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA 0x0036 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2 0x003e -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_ULTRA 0x0040 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800 0x0041 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_LE 0x0042 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800_GT 0x0045 -#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_4000 0x004E -#define PCI_DEVICE_ID_NVIDIA_NFORCE4_SMBUS 0x0052 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE 0x0053 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA 0x0054 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2 0x0055 -#define PCI_DEVICE_ID_NVIDIA_CK804_AUDIO 0x0059 -#define PCI_DEVICE_ID_NVIDIA_CK804_PCIE 0x005d -#define PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS 0x0064 -#define PCI_DEVICE_ID_NVIDIA_NFORCE2_IDE 0x0065 -#define PCI_DEVICE_ID_NVIDIA_MCP2_MODEM 0x0069 -#define PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO 0x006a -#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS 0x0084 -#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_IDE 0x0085 -#define PCI_DEVICE_ID_NVIDIA_MCP2S_MODEM 0x0089 -#define PCI_DEVICE_ID_NVIDIA_CK8_AUDIO 0x008a -#define PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA 0x008e -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GT 0x0090 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_7800_GTX 0x0091 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800 0x0098 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_7800_GTX 0x0099 -#define PCI_DEVICE_ID_NVIDIA_ITNT2 0x00A0 -#define PCI_DEVICE_ID_GEFORCE_6800A 0x00c1 -#define PCI_DEVICE_ID_GEFORCE_6800A_LE 0x00c2 -#define PCI_DEVICE_ID_GEFORCE_GO_6800 0x00c8 -#define PCI_DEVICE_ID_GEFORCE_GO_6800_ULTRA 0x00c9 -#define PCI_DEVICE_ID_QUADRO_FX_GO1400 0x00cc -#define PCI_DEVICE_ID_QUADRO_FX_1400 0x00ce -#define PCI_DEVICE_ID_NVIDIA_NFORCE3 0x00d1 -#define PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS 0x00d4 -#define PCI_DEVICE_ID_NVIDIA_NFORCE3_IDE 0x00d5 -#define PCI_DEVICE_ID_NVIDIA_MCP3_MODEM 0x00d9 -#define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da -#define PCI_DEVICE_ID_NVIDIA_NFORCE3S 0x00e1 -#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA 0x00e3 -#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SMBUS 0x00e4 -#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_IDE 0x00e5 -#define PCI_DEVICE_ID_NVIDIA_CK8S_AUDIO 0x00ea -#define PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2 0x00ee -#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_ALT1 0x00f0 -#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT1 0x00f1 -#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6600_ALT2 0x00f2 -#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6200_ALT1 0x00f3 -#define PCIE_DEVICE_ID_NVIDIA_GEFORCE_6800_GT 0x00f9 -#define PCIE_DEVICE_ID_NVIDIA_QUADRO_NVS280 0x00fd -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_SDR 0x0100 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_DDR 0x0101 -#define PCI_DEVICE_ID_NVIDIA_QUADRO 0x0103 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX 0x0110 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_MX2 0x0111 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GO 0x0112 -#define PCI_DEVICE_ID_NVIDIA_QUADRO2_MXR 0x0113 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6600_GT 0x0140 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6600 0x0141 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6610_XL 0x0145 -#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_540 0x014E -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6200 0x014F -#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS 0x0150 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_GTS2 0x0151 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE2_ULTRA 0x0152 -#define PCI_DEVICE_ID_NVIDIA_QUADRO2_PRO 0x0153 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6200_TURBOCACHE 0x0161 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200 0x0164 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250 0x0166 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6200_1 0x0167 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_GO_6250_1 0x0168 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_460 0x0170 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440 0x0171 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420 0x0172 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_SE 0x0173 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO 0x0174 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO 0x0175 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_420_GO_M32 0x0176 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_460_GO 0x0177 -#define PCI_DEVICE_ID_NVIDIA_QUADRO4_500XGL 0x0178 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_440_GO_M64 0x0179 -#define PCI_DEVICE_ID_NVIDIA_QUADRO4_200 0x017A -#define PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL 0x017B -#define PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL 0x017C -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_410_GO_M16 0x017D -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440_8X 0x0181 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_440SE_8X 0x0182 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_420_8X 0x0183 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_4000 0x0185 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_448_GO 0x0186 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_488_GO 0x0187 -#define PCI_DEVICE_ID_NVIDIA_QUADRO4_580_XGL 0x0188 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_MX_MAC 0x0189 -#define PCI_DEVICE_ID_NVIDIA_QUADRO4_280_NVS 0x018A -#define PCI_DEVICE_ID_NVIDIA_QUADRO4_380_XGL 0x018B -#define PCI_DEVICE_ID_NVIDIA_IGEFORCE2 0x01a0 -#define PCI_DEVICE_ID_NVIDIA_NFORCE 0x01a4 -#define PCI_DEVICE_ID_NVIDIA_MCP1_AUDIO 0x01b1 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_SMBUS 0x01b4 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE 0x01bc -#define PCI_DEVICE_ID_NVIDIA_MCP1_MODEM 0x01c1 -#define PCI_DEVICE_ID_NVIDIA_NFORCE2 0x01e0 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE3 0x0200 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1 0x0201 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2 0x0202 -#define PCI_DEVICE_ID_NVIDIA_QUADRO_DDC 0x0203 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B 0x0211 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_LE 0x0212 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_6800B_GT 0x0215 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4600 0x0250 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4400 0x0251 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4200 0x0253 -#define PCI_DEVICE_ID_NVIDIA_QUADRO4_900XGL 0x0258 -#define PCI_DEVICE_ID_NVIDIA_QUADRO4_750XGL 0x0259 -#define PCI_DEVICE_ID_NVIDIA_QUADRO4_700XGL 0x025B -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS 0x0264 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE 0x0265 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA 0x0266 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2 0x0267 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS 0x0368 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE 0x036E -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA 0x037E -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2 0x037F -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800 0x0280 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800_8X 0x0281 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_TI_4800SE 0x0282 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE4_4200_GO 0x0286 -#define PCI_DEVICE_ID_NVIDIA_QUADRO4_980_XGL 0x0288 -#define PCI_DEVICE_ID_NVIDIA_QUADRO4_780_XGL 0x0289 -#define PCI_DEVICE_ID_NVIDIA_QUADRO4_700_GOGL 0x028C -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800_ULTRA 0x0301 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5800 0x0302 -#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_2000 0x0308 -#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1000 0x0309 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600_ULTRA 0x0311 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600 0x0312 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5600SE 0x0314 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5600 0x031A -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5650 0x031B -#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO700 0x031C -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200 0x0320 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_ULTRA 0x0321 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200_1 0x0322 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5200SE 0x0323 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5200 0x0324 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250 0x0325 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5500 0x0326 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5100 0x0327 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5250_32 0x0328 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO_5200 0x0329 -#define PCI_DEVICE_ID_NVIDIA_QUADRO_NVS_280_PCI 0x032A -#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_500 0x032B -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5300 0x032C -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5100 0x032D -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900_ULTRA 0x0330 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900 0x0331 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900XT 0x0332 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5950_ULTRA 0x0333 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5900ZT 0x0334 -#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_3000 0x0338 -#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_700 0x033F -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700_ULTRA 0x0341 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700 0x0342 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700LE 0x0343 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_5700VE 0x0344 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_1 0x0347 -#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2 0x0348 -#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000 0x034C -#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100 0x034E -#define PCI_DEVICE_ID_NVIDIA_MCP55_BRIDGE_V0 0x0360 -#define PCI_DEVICE_ID_NVIDIA_MCP55_BRIDGE_V4 0x0364 -#define PCI_DEVICE_ID_NVIDIA_NVENET_15 0x0373 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA 0x03E7 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SMBUS 0x03EB -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_IDE 0x03EC -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2 0x03F6 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3 0x03F7 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_SMBUS 0x0446 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP65_IDE 0x0448 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_SMBUS 0x0542 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP67_IDE 0x0560 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_IDE 0x056C -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP78S_SMBUS 0x0752 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP77_IDE 0x0759 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP73_SMBUS 0x07D8 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP79_SMBUS 0x0AA2 -#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP89_SATA 0x0D85 - -#define PCI_VENDOR_ID_IMS 0x10e0 -#define PCI_DEVICE_ID_IMS_TT128 0x9128 -#define PCI_DEVICE_ID_IMS_TT3D 0x9135 - -#define PCI_VENDOR_ID_AMCC 0x10e8 - -#define PCI_VENDOR_ID_INTERG 0x10ea -#define PCI_DEVICE_ID_INTERG_1682 0x1682 -#define PCI_DEVICE_ID_INTERG_2000 0x2000 -#define PCI_DEVICE_ID_INTERG_2010 0x2010 -#define PCI_DEVICE_ID_INTERG_5000 0x5000 -#define PCI_DEVICE_ID_INTERG_5050 0x5050 - -#define PCI_VENDOR_ID_REALTEK 0x10ec -#define PCI_DEVICE_ID_REALTEK_8139 0x8139 - -#define PCI_VENDOR_ID_XILINX 0x10ee -#define PCI_DEVICE_ID_RME_DIGI96 0x3fc0 -#define PCI_DEVICE_ID_RME_DIGI96_8 0x3fc1 -#define PCI_DEVICE_ID_RME_DIGI96_8_PRO 0x3fc2 -#define PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST 0x3fc3 -#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP 0x3fc5 -#define PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI 0x3fc6 - -#define PCI_VENDOR_ID_INIT 0x1101 - -#define PCI_VENDOR_ID_CREATIVE 0x1102 /* duplicate: ECTIVA */ -#define PCI_DEVICE_ID_CREATIVE_EMU10K1 0x0002 -#define PCI_DEVICE_ID_CREATIVE_20K1 0x0005 -#define PCI_DEVICE_ID_CREATIVE_20K2 0x000b -#define PCI_SUBDEVICE_ID_CREATIVE_SB0760 0x0024 -#define PCI_SUBDEVICE_ID_CREATIVE_SB08801 0x0041 -#define PCI_SUBDEVICE_ID_CREATIVE_SB08802 0x0042 -#define PCI_SUBDEVICE_ID_CREATIVE_SB08803 0x0043 -#define PCI_SUBDEVICE_ID_CREATIVE_SB1270 0x0062 -#define PCI_SUBDEVICE_ID_CREATIVE_HENDRIX 0x6000 - -#define PCI_VENDOR_ID_ECTIVA 0x1102 /* duplicate: CREATIVE */ -#define PCI_DEVICE_ID_ECTIVA_EV1938 0x8938 - -#define PCI_VENDOR_ID_TTI 0x1103 -#define PCI_DEVICE_ID_TTI_HPT343 0x0003 -#define PCI_DEVICE_ID_TTI_HPT366 0x0004 -#define PCI_DEVICE_ID_TTI_HPT372 0x0005 -#define PCI_DEVICE_ID_TTI_HPT302 0x0006 -#define PCI_DEVICE_ID_TTI_HPT371 0x0007 -#define PCI_DEVICE_ID_TTI_HPT374 0x0008 -#define PCI_DEVICE_ID_TTI_HPT372N 0x0009 /* apparently a 372N variant? */ - -#define PCI_VENDOR_ID_VIA 0x1106 -#define PCI_DEVICE_ID_VIA_8763_0 0x0198 -#define PCI_DEVICE_ID_VIA_8380_0 0x0204 -#define PCI_DEVICE_ID_VIA_3238_0 0x0238 -#define PCI_DEVICE_ID_VIA_PT880 0x0258 -#define PCI_DEVICE_ID_VIA_PT880ULTRA 0x0308 -#define PCI_DEVICE_ID_VIA_PX8X0_0 0x0259 -#define PCI_DEVICE_ID_VIA_3269_0 0x0269 -#define PCI_DEVICE_ID_VIA_K8T800PRO_0 0x0282 -#define PCI_DEVICE_ID_VIA_3296_0 0x0296 -#define PCI_DEVICE_ID_VIA_8363_0 0x0305 -#define PCI_DEVICE_ID_VIA_P4M800CE 0x0314 -#define PCI_DEVICE_ID_VIA_P4M890 0x0327 -#define PCI_DEVICE_ID_VIA_VT3324 0x0324 -#define PCI_DEVICE_ID_VIA_VT3336 0x0336 -#define PCI_DEVICE_ID_VIA_VT3351 0x0351 -#define PCI_DEVICE_ID_VIA_VT3364 0x0364 -#define PCI_DEVICE_ID_VIA_8371_0 0x0391 -#define PCI_DEVICE_ID_VIA_6415 0x0415 -#define PCI_DEVICE_ID_VIA_8501_0 0x0501 -#define PCI_DEVICE_ID_VIA_82C561 0x0561 -#define PCI_DEVICE_ID_VIA_82C586_1 0x0571 -#define PCI_DEVICE_ID_VIA_82C576 0x0576 -#define PCI_DEVICE_ID_VIA_82C586_0 0x0586 -#define PCI_DEVICE_ID_VIA_82C596 0x0596 -#define PCI_DEVICE_ID_VIA_82C597_0 0x0597 -#define PCI_DEVICE_ID_VIA_82C598_0 0x0598 -#define PCI_DEVICE_ID_VIA_8601_0 0x0601 -#define PCI_DEVICE_ID_VIA_8605_0 0x0605 -#define PCI_DEVICE_ID_VIA_82C686 0x0686 -#define PCI_DEVICE_ID_VIA_82C691_0 0x0691 -#define PCI_DEVICE_ID_VIA_82C576_1 0x1571 -#define PCI_DEVICE_ID_VIA_82C586_2 0x3038 -#define PCI_DEVICE_ID_VIA_82C586_3 0x3040 -#define PCI_DEVICE_ID_VIA_82C596_3 0x3050 -#define PCI_DEVICE_ID_VIA_82C596B_3 0x3051 -#define PCI_DEVICE_ID_VIA_82C686_4 0x3057 -#define PCI_DEVICE_ID_VIA_82C686_5 0x3058 -#define PCI_DEVICE_ID_VIA_8233_5 0x3059 -#define PCI_DEVICE_ID_VIA_8233_0 0x3074 -#define PCI_DEVICE_ID_VIA_8633_0 0x3091 -#define PCI_DEVICE_ID_VIA_8367_0 0x3099 -#define PCI_DEVICE_ID_VIA_8653_0 0x3101 -#define PCI_DEVICE_ID_VIA_8622 0x3102 -#define PCI_DEVICE_ID_VIA_8235_USB_2 0x3104 -#define PCI_DEVICE_ID_VIA_8233C_0 0x3109 -#define PCI_DEVICE_ID_VIA_8361 0x3112 -#define PCI_DEVICE_ID_VIA_XM266 0x3116 -#define PCI_DEVICE_ID_VIA_612X 0x3119 -#define PCI_DEVICE_ID_VIA_862X_0 0x3123 -#define PCI_DEVICE_ID_VIA_8753_0 0x3128 -#define PCI_DEVICE_ID_VIA_8233A 0x3147 -#define PCI_DEVICE_ID_VIA_8703_51_0 0x3148 -#define PCI_DEVICE_ID_VIA_8237_SATA 0x3149 -#define PCI_DEVICE_ID_VIA_XN266 0x3156 -#define PCI_DEVICE_ID_VIA_6410 0x3164 -#define PCI_DEVICE_ID_VIA_8754C_0 0x3168 -#define PCI_DEVICE_ID_VIA_8235 0x3177 -#define PCI_DEVICE_ID_VIA_8385_0 0x3188 -#define PCI_DEVICE_ID_VIA_8377_0 0x3189 -#define PCI_DEVICE_ID_VIA_8378_0 0x3205 -#define PCI_DEVICE_ID_VIA_8783_0 0x3208 -#define PCI_DEVICE_ID_VIA_8237 0x3227 -#define PCI_DEVICE_ID_VIA_8251 0x3287 -#define PCI_DEVICE_ID_VIA_8261 0x3402 -#define PCI_DEVICE_ID_VIA_8237A 0x3337 -#define PCI_DEVICE_ID_VIA_8237S 0x3372 -#define PCI_DEVICE_ID_VIA_SATA_EIDE 0x5324 -#define PCI_DEVICE_ID_VIA_8231 0x8231 -#define PCI_DEVICE_ID_VIA_8231_4 0x8235 -#define PCI_DEVICE_ID_VIA_8365_1 0x8305 -#define PCI_DEVICE_ID_VIA_CX700 0x8324 -#define PCI_DEVICE_ID_VIA_CX700_IDE 0x0581 -#define PCI_DEVICE_ID_VIA_VX800 0x8353 -#define PCI_DEVICE_ID_VIA_VX855 0x8409 -#define PCI_DEVICE_ID_VIA_VX900 0x8410 -#define PCI_DEVICE_ID_VIA_8371_1 0x8391 -#define PCI_DEVICE_ID_VIA_82C598_1 0x8598 -#define PCI_DEVICE_ID_VIA_838X_1 0xB188 -#define PCI_DEVICE_ID_VIA_83_87XX_1 0xB198 -#define PCI_DEVICE_ID_VIA_VX855_IDE 0xC409 -#define PCI_DEVICE_ID_VIA_ANON 0xFFFF - -#define PCI_VENDOR_ID_SIEMENS 0x110A -#define PCI_DEVICE_ID_SIEMENS_DSCC4 0x2102 - -#define PCI_VENDOR_ID_VORTEX 0x1119 -#define PCI_DEVICE_ID_VORTEX_GDT60x0 0x0000 -#define PCI_DEVICE_ID_VORTEX_GDT6000B 0x0001 -#define PCI_DEVICE_ID_VORTEX_GDT6x10 0x0002 -#define PCI_DEVICE_ID_VORTEX_GDT6x20 0x0003 -#define PCI_DEVICE_ID_VORTEX_GDT6530 0x0004 -#define PCI_DEVICE_ID_VORTEX_GDT6550 0x0005 -#define PCI_DEVICE_ID_VORTEX_GDT6x17 0x0006 -#define PCI_DEVICE_ID_VORTEX_GDT6x27 0x0007 -#define PCI_DEVICE_ID_VORTEX_GDT6537 0x0008 -#define PCI_DEVICE_ID_VORTEX_GDT6557 0x0009 -#define PCI_DEVICE_ID_VORTEX_GDT6x15 0x000a -#define PCI_DEVICE_ID_VORTEX_GDT6x25 0x000b -#define PCI_DEVICE_ID_VORTEX_GDT6535 0x000c -#define PCI_DEVICE_ID_VORTEX_GDT6555 0x000d -#define PCI_DEVICE_ID_VORTEX_GDT6x17RP 0x0100 -#define PCI_DEVICE_ID_VORTEX_GDT6x27RP 0x0101 -#define PCI_DEVICE_ID_VORTEX_GDT6537RP 0x0102 -#define PCI_DEVICE_ID_VORTEX_GDT6557RP 0x0103 -#define PCI_DEVICE_ID_VORTEX_GDT6x11RP 0x0104 -#define PCI_DEVICE_ID_VORTEX_GDT6x21RP 0x0105 - -#define PCI_VENDOR_ID_EF 0x111a -#define PCI_DEVICE_ID_EF_ATM_FPGA 0x0000 -#define PCI_DEVICE_ID_EF_ATM_ASIC 0x0002 -#define PCI_DEVICE_ID_EF_ATM_LANAI2 0x0003 -#define PCI_DEVICE_ID_EF_ATM_LANAIHB 0x0005 - -#define PCI_VENDOR_ID_IDT 0x111d -#define PCI_DEVICE_ID_IDT_IDT77201 0x0001 - -#define PCI_VENDOR_ID_FORE 0x1127 -#define PCI_DEVICE_ID_FORE_PCA200E 0x0300 - -#define PCI_VENDOR_ID_PHILIPS 0x1131 -#define PCI_DEVICE_ID_PHILIPS_SAA7146 0x7146 -#define PCI_DEVICE_ID_PHILIPS_SAA9730 0x9730 - -#define PCI_VENDOR_ID_EICON 0x1133 -#define PCI_DEVICE_ID_EICON_DIVA20 0xe002 -#define PCI_DEVICE_ID_EICON_DIVA20_U 0xe004 -#define PCI_DEVICE_ID_EICON_DIVA201 0xe005 -#define PCI_DEVICE_ID_EICON_DIVA202 0xe00b -#define PCI_DEVICE_ID_EICON_MAESTRA 0xe010 -#define PCI_DEVICE_ID_EICON_MAESTRAQ 0xe012 -#define PCI_DEVICE_ID_EICON_MAESTRAQ_U 0xe013 -#define PCI_DEVICE_ID_EICON_MAESTRAP 0xe014 - -#define PCI_VENDOR_ID_CISCO 0x1137 - -#define PCI_VENDOR_ID_ZIATECH 0x1138 -#define PCI_DEVICE_ID_ZIATECH_5550_HC 0x5550 - - -#define PCI_VENDOR_ID_SYSKONNECT 0x1148 -#define PCI_DEVICE_ID_SYSKONNECT_TR 0x4200 -#define PCI_DEVICE_ID_SYSKONNECT_GE 0x4300 -#define PCI_DEVICE_ID_SYSKONNECT_YU 0x4320 -#define PCI_DEVICE_ID_SYSKONNECT_9DXX 0x4400 -#define PCI_DEVICE_ID_SYSKONNECT_9MXX 0x4500 - -#define PCI_VENDOR_ID_DIGI 0x114f -#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_E 0x0070 -#define PCI_DEVICE_ID_DIGI_DF_M_E 0x0071 -#define PCI_DEVICE_ID_DIGI_DF_M_IOM2_A 0x0072 -#define PCI_DEVICE_ID_DIGI_DF_M_A 0x0073 -#define PCI_DEVICE_ID_DIGI_NEO_8 0x00B1 -#define PCI_DEVICE_ID_NEO_2DB9 0x00C8 -#define PCI_DEVICE_ID_NEO_2DB9PRI 0x00C9 -#define PCI_DEVICE_ID_NEO_2RJ45 0x00CA -#define PCI_DEVICE_ID_NEO_2RJ45PRI 0x00CB -#define PCIE_DEVICE_ID_NEO_4_IBM 0x00F4 - -#define PCI_VENDOR_ID_XIRCOM 0x115d -#define PCI_DEVICE_ID_XIRCOM_RBM56G 0x0101 -#define PCI_DEVICE_ID_XIRCOM_X3201_MDM 0x0103 - -#define PCI_VENDOR_ID_SERVERWORKS 0x1166 -#define PCI_DEVICE_ID_SERVERWORKS_HE 0x0008 -#define PCI_DEVICE_ID_SERVERWORKS_LE 0x0009 -#define PCI_DEVICE_ID_SERVERWORKS_GCNB_LE 0x0017 -#define PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB 0x0036 -#define PCI_DEVICE_ID_SERVERWORKS_EPB 0x0103 -#define PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE 0x0132 -#define PCI_DEVICE_ID_SERVERWORKS_OSB4 0x0200 -#define PCI_DEVICE_ID_SERVERWORKS_CSB5 0x0201 -#define PCI_DEVICE_ID_SERVERWORKS_CSB6 0x0203 -#define PCI_DEVICE_ID_SERVERWORKS_HT1000SB 0x0205 -#define PCI_DEVICE_ID_SERVERWORKS_OSB4IDE 0x0211 -#define PCI_DEVICE_ID_SERVERWORKS_CSB5IDE 0x0212 -#define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE 0x0213 -#define PCI_DEVICE_ID_SERVERWORKS_HT1000IDE 0x0214 -#define PCI_DEVICE_ID_SERVERWORKS_CSB6IDE2 0x0217 -#define PCI_DEVICE_ID_SERVERWORKS_CSB6LPC 0x0227 -#define PCI_DEVICE_ID_SERVERWORKS_HT1100LD 0x0408 - -#define PCI_VENDOR_ID_SBE 0x1176 -#define PCI_DEVICE_ID_SBE_WANXL100 0x0301 -#define PCI_DEVICE_ID_SBE_WANXL200 0x0302 -#define PCI_DEVICE_ID_SBE_WANXL400 0x0104 -#define PCI_SUBDEVICE_ID_SBE_T3E3 0x0009 -#define PCI_SUBDEVICE_ID_SBE_2T3E3_P0 0x0901 -#define PCI_SUBDEVICE_ID_SBE_2T3E3_P1 0x0902 - -#define PCI_VENDOR_ID_TOSHIBA 0x1179 -#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_1 0x0101 -#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_2 0x0102 -#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_3 0x0103 -#define PCI_DEVICE_ID_TOSHIBA_PICCOLO_5 0x0105 -#define PCI_DEVICE_ID_TOSHIBA_TOPIC95 0x060a -#define PCI_DEVICE_ID_TOSHIBA_TOPIC97 0x060f -#define PCI_DEVICE_ID_TOSHIBA_TOPIC100 0x0617 - -#define PCI_VENDOR_ID_TOSHIBA_2 0x102f -#define PCI_DEVICE_ID_TOSHIBA_TC35815CF 0x0030 -#define PCI_DEVICE_ID_TOSHIBA_TC35815_NWU 0x0031 -#define PCI_DEVICE_ID_TOSHIBA_TC35815_TX4939 0x0032 -#define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE 0x0105 -#define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC 0x0108 -#define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3 - -#define PCI_VENDOR_ID_ATTO 0x117c - -#define PCI_VENDOR_ID_RICOH 0x1180 -#define PCI_DEVICE_ID_RICOH_RL5C465 0x0465 -#define PCI_DEVICE_ID_RICOH_RL5C466 0x0466 -#define PCI_DEVICE_ID_RICOH_RL5C475 0x0475 -#define PCI_DEVICE_ID_RICOH_RL5C476 0x0476 -#define PCI_DEVICE_ID_RICOH_RL5C478 0x0478 -#define PCI_DEVICE_ID_RICOH_R5C822 0x0822 -#define PCI_DEVICE_ID_RICOH_R5CE822 0xe822 -#define PCI_DEVICE_ID_RICOH_R5CE823 0xe823 -#define PCI_DEVICE_ID_RICOH_R5C832 0x0832 -#define PCI_DEVICE_ID_RICOH_R5C843 0x0843 - -#define PCI_VENDOR_ID_DLINK 0x1186 -#define PCI_DEVICE_ID_DLINK_DGE510T 0x4c00 - -#define PCI_VENDOR_ID_ARTOP 0x1191 -#define PCI_DEVICE_ID_ARTOP_ATP850UF 0x0005 -#define PCI_DEVICE_ID_ARTOP_ATP860 0x0006 -#define PCI_DEVICE_ID_ARTOP_ATP860R 0x0007 -#define PCI_DEVICE_ID_ARTOP_ATP865 0x0008 -#define PCI_DEVICE_ID_ARTOP_ATP865R 0x0009 -#define PCI_DEVICE_ID_ARTOP_ATP867A 0x000A -#define PCI_DEVICE_ID_ARTOP_ATP867B 0x000B -#define PCI_DEVICE_ID_ARTOP_AEC7610 0x8002 -#define PCI_DEVICE_ID_ARTOP_AEC7612UW 0x8010 -#define PCI_DEVICE_ID_ARTOP_AEC7612U 0x8020 -#define PCI_DEVICE_ID_ARTOP_AEC7612S 0x8030 -#define PCI_DEVICE_ID_ARTOP_AEC7612D 0x8040 -#define PCI_DEVICE_ID_ARTOP_AEC7612SUW 0x8050 -#define PCI_DEVICE_ID_ARTOP_8060 0x8060 - -#define PCI_VENDOR_ID_ZEITNET 0x1193 -#define PCI_DEVICE_ID_ZEITNET_1221 0x0001 -#define PCI_DEVICE_ID_ZEITNET_1225 0x0002 - -#define PCI_VENDOR_ID_FUJITSU_ME 0x119e -#define PCI_DEVICE_ID_FUJITSU_FS155 0x0001 -#define PCI_DEVICE_ID_FUJITSU_FS50 0x0003 - -#define PCI_SUBVENDOR_ID_KEYSPAN 0x11a9 -#define PCI_SUBDEVICE_ID_KEYSPAN_SX2 0x5334 - -#define PCI_VENDOR_ID_MARVELL 0x11ab -#define PCI_VENDOR_ID_MARVELL_EXT 0x1b4b -#define PCI_DEVICE_ID_MARVELL_GT64111 0x4146 -#define PCI_DEVICE_ID_MARVELL_GT64260 0x6430 -#define PCI_DEVICE_ID_MARVELL_MV64360 0x6460 -#define PCI_DEVICE_ID_MARVELL_MV64460 0x6480 -#define PCI_DEVICE_ID_MARVELL_88ALP01_NAND 0x4100 -#define PCI_DEVICE_ID_MARVELL_88ALP01_SD 0x4101 -#define PCI_DEVICE_ID_MARVELL_88ALP01_CCIC 0x4102 - -#define PCI_VENDOR_ID_V3 0x11b0 -#define PCI_DEVICE_ID_V3_V960 0x0001 -#define PCI_DEVICE_ID_V3_V351 0x0002 - -#define PCI_VENDOR_ID_ATT 0x11c1 -#define PCI_DEVICE_ID_ATT_VENUS_MODEM 0x480 - -#define PCI_VENDOR_ID_SPECIALIX 0x11cb -#define PCI_SUBDEVICE_ID_SPECIALIX_SPEED4 0xa004 - -#define PCI_VENDOR_ID_ANALOG_DEVICES 0x11d4 -#define PCI_DEVICE_ID_AD1889JS 0x1889 - -#define PCI_DEVICE_ID_SEGA_BBA 0x1234 - -#define PCI_VENDOR_ID_ZORAN 0x11de -#define PCI_DEVICE_ID_ZORAN_36057 0x6057 -#define PCI_DEVICE_ID_ZORAN_36120 0x6120 - -#define PCI_VENDOR_ID_COMPEX 0x11f6 -#define PCI_DEVICE_ID_COMPEX_ENET100VG4 0x0112 - -#define PCI_VENDOR_ID_PMC_Sierra 0x11f8 - -#define PCI_VENDOR_ID_RP 0x11fe -#define PCI_DEVICE_ID_RP32INTF 0x0001 -#define PCI_DEVICE_ID_RP8INTF 0x0002 -#define PCI_DEVICE_ID_RP16INTF 0x0003 -#define PCI_DEVICE_ID_RP4QUAD 0x0004 -#define PCI_DEVICE_ID_RP8OCTA 0x0005 -#define PCI_DEVICE_ID_RP8J 0x0006 -#define PCI_DEVICE_ID_RP4J 0x0007 -#define PCI_DEVICE_ID_RP8SNI 0x0008 -#define PCI_DEVICE_ID_RP16SNI 0x0009 -#define PCI_DEVICE_ID_RPP4 0x000A -#define PCI_DEVICE_ID_RPP8 0x000B -#define PCI_DEVICE_ID_RP4M 0x000D -#define PCI_DEVICE_ID_RP2_232 0x000E -#define PCI_DEVICE_ID_RP2_422 0x000F -#define PCI_DEVICE_ID_URP32INTF 0x0801 -#define PCI_DEVICE_ID_URP8INTF 0x0802 -#define PCI_DEVICE_ID_URP16INTF 0x0803 -#define PCI_DEVICE_ID_URP8OCTA 0x0805 -#define PCI_DEVICE_ID_UPCI_RM3_8PORT 0x080C -#define PCI_DEVICE_ID_UPCI_RM3_4PORT 0x080D -#define PCI_DEVICE_ID_CRP16INTF 0x0903 - -#define PCI_VENDOR_ID_CYCLADES 0x120e -#define PCI_DEVICE_ID_CYCLOM_Y_Lo 0x0100 -#define PCI_DEVICE_ID_CYCLOM_Y_Hi 0x0101 -#define PCI_DEVICE_ID_CYCLOM_4Y_Lo 0x0102 -#define PCI_DEVICE_ID_CYCLOM_4Y_Hi 0x0103 -#define PCI_DEVICE_ID_CYCLOM_8Y_Lo 0x0104 -#define PCI_DEVICE_ID_CYCLOM_8Y_Hi 0x0105 -#define PCI_DEVICE_ID_CYCLOM_Z_Lo 0x0200 -#define PCI_DEVICE_ID_CYCLOM_Z_Hi 0x0201 -#define PCI_DEVICE_ID_PC300_RX_2 0x0300 -#define PCI_DEVICE_ID_PC300_RX_1 0x0301 -#define PCI_DEVICE_ID_PC300_TE_2 0x0310 -#define PCI_DEVICE_ID_PC300_TE_1 0x0311 -#define PCI_DEVICE_ID_PC300_TE_M_2 0x0320 -#define PCI_DEVICE_ID_PC300_TE_M_1 0x0321 - -#define PCI_VENDOR_ID_ESSENTIAL 0x120f -#define PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER 0x0001 - -#define PCI_VENDOR_ID_O2 0x1217 -#define PCI_DEVICE_ID_O2_6729 0x6729 -#define PCI_DEVICE_ID_O2_6730 0x673a -#define PCI_DEVICE_ID_O2_6832 0x6832 -#define PCI_DEVICE_ID_O2_6836 0x6836 -#define PCI_DEVICE_ID_O2_6812 0x6872 -#define PCI_DEVICE_ID_O2_6933 0x6933 -#define PCI_DEVICE_ID_O2_8120 0x8120 -#define PCI_DEVICE_ID_O2_8220 0x8220 -#define PCI_DEVICE_ID_O2_8221 0x8221 -#define PCI_DEVICE_ID_O2_8320 0x8320 -#define PCI_DEVICE_ID_O2_8321 0x8321 - -#define PCI_VENDOR_ID_3DFX 0x121a -#define PCI_DEVICE_ID_3DFX_VOODOO 0x0001 -#define PCI_DEVICE_ID_3DFX_VOODOO2 0x0002 -#define PCI_DEVICE_ID_3DFX_BANSHEE 0x0003 -#define PCI_DEVICE_ID_3DFX_VOODOO3 0x0005 -#define PCI_DEVICE_ID_3DFX_VOODOO5 0x0009 - -#define PCI_VENDOR_ID_AVM 0x1244 -#define PCI_DEVICE_ID_AVM_B1 0x0700 -#define PCI_DEVICE_ID_AVM_C4 0x0800 -#define PCI_DEVICE_ID_AVM_A1 0x0a00 -#define PCI_DEVICE_ID_AVM_A1_V2 0x0e00 -#define PCI_DEVICE_ID_AVM_C2 0x1100 -#define PCI_DEVICE_ID_AVM_T1 0x1200 - -#define PCI_VENDOR_ID_STALLION 0x124d - -/* Allied Telesyn */ -#define PCI_VENDOR_ID_AT 0x1259 -#define PCI_SUBDEVICE_ID_AT_2700FX 0x2701 -#define PCI_SUBDEVICE_ID_AT_2701FX 0x2703 - -#define PCI_VENDOR_ID_ESS 0x125d -#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 -#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 -#define PCI_DEVICE_ID_ESS_ALLEGRO_1 0x1988 -#define PCI_DEVICE_ID_ESS_ALLEGRO 0x1989 -#define PCI_DEVICE_ID_ESS_CANYON3D_2LE 0x1990 -#define PCI_DEVICE_ID_ESS_CANYON3D_2 0x1992 -#define PCI_DEVICE_ID_ESS_MAESTRO3 0x1998 -#define PCI_DEVICE_ID_ESS_MAESTRO3_1 0x1999 -#define PCI_DEVICE_ID_ESS_MAESTRO3_HW 0x199a -#define PCI_DEVICE_ID_ESS_MAESTRO3_2 0x199b - -#define PCI_VENDOR_ID_SATSAGEM 0x1267 -#define PCI_DEVICE_ID_SATSAGEM_NICCY 0x1016 - -#define PCI_VENDOR_ID_ENSONIQ 0x1274 -#define PCI_DEVICE_ID_ENSONIQ_CT5880 0x5880 -#define PCI_DEVICE_ID_ENSONIQ_ES1370 0x5000 -#define PCI_DEVICE_ID_ENSONIQ_ES1371 0x1371 - -#define PCI_VENDOR_ID_TRANSMETA 0x1279 -#define PCI_DEVICE_ID_EFFICEON 0x0060 - -#define PCI_VENDOR_ID_ROCKWELL 0x127A - -#define PCI_VENDOR_ID_ITE 0x1283 -#define PCI_DEVICE_ID_ITE_8172 0x8172 -#define PCI_DEVICE_ID_ITE_8211 0x8211 -#define PCI_DEVICE_ID_ITE_8212 0x8212 -#define PCI_DEVICE_ID_ITE_8213 0x8213 -#define PCI_DEVICE_ID_ITE_8152 0x8152 -#define PCI_DEVICE_ID_ITE_8872 0x8872 -#define PCI_DEVICE_ID_ITE_IT8330G_0 0xe886 - -/* formerly Platform Tech */ -#define PCI_DEVICE_ID_ESS_ESS0100 0x0100 - -#define PCI_VENDOR_ID_ALTEON 0x12ae - -#define PCI_SUBVENDOR_ID_CONNECT_TECH 0x12c4 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232 0x0001 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232 0x0002 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232 0x0003 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485 0x0004 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4 0x0005 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485 0x0006 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2 0x0007 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485 0x0008 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_2_6 0x0009 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH081101V1 0x000A -#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH041101V1 0x000B -#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_20MHZ 0x000C -#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_PTM 0x000D -#define PCI_SUBDEVICE_ID_CONNECT_TECH_NT960PCI 0x0100 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_2 0x0201 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_TITAN_4 0x0202 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_232 0x0300 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_232 0x0301 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_232 0x0302 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_1_1 0x0310 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_2 0x0311 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_4 0x0312 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2 0x0320 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4 0x0321 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8 0x0322 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_2_485 0x0330 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_4_485 0x0331 -#define PCI_SUBDEVICE_ID_CONNECT_TECH_PCI_UART_8_485 0x0332 - -#define PCI_VENDOR_ID_NVIDIA_SGS 0x12d2 -#define PCI_DEVICE_ID_NVIDIA_SGS_RIVA128 0x0018 - -#define PCI_SUBVENDOR_ID_CHASE_PCIFAST 0x12E0 -#define PCI_SUBDEVICE_ID_CHASE_PCIFAST4 0x0031 -#define PCI_SUBDEVICE_ID_CHASE_PCIFAST8 0x0021 -#define PCI_SUBDEVICE_ID_CHASE_PCIFAST16 0x0011 -#define PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC 0x0041 -#define PCI_SUBVENDOR_ID_CHASE_PCIRAS 0x124D -#define PCI_SUBDEVICE_ID_CHASE_PCIRAS4 0xF001 -#define PCI_SUBDEVICE_ID_CHASE_PCIRAS8 0xF010 - -#define PCI_VENDOR_ID_AUREAL 0x12eb -#define PCI_DEVICE_ID_AUREAL_VORTEX_1 0x0001 -#define PCI_DEVICE_ID_AUREAL_VORTEX_2 0x0002 -#define PCI_DEVICE_ID_AUREAL_ADVANTAGE 0x0003 - -#define PCI_VENDOR_ID_ELECTRONICDESIGNGMBH 0x12f8 -#define PCI_DEVICE_ID_LML_33R10 0x8a02 - -#define PCI_VENDOR_ID_ESDGMBH 0x12fe -#define PCI_DEVICE_ID_ESDGMBH_CPCIASIO4 0x0111 - -#define PCI_VENDOR_ID_CB 0x1307 /* Measurement Computing */ - -#define PCI_VENDOR_ID_SIIG 0x131f -#define PCI_SUBVENDOR_ID_SIIG 0x131f -#define PCI_DEVICE_ID_SIIG_1S_10x_550 0x1000 -#define PCI_DEVICE_ID_SIIG_1S_10x_650 0x1001 -#define PCI_DEVICE_ID_SIIG_1S_10x_850 0x1002 -#define PCI_DEVICE_ID_SIIG_1S1P_10x_550 0x1010 -#define PCI_DEVICE_ID_SIIG_1S1P_10x_650 0x1011 -#define PCI_DEVICE_ID_SIIG_1S1P_10x_850 0x1012 -#define PCI_DEVICE_ID_SIIG_1P_10x 0x1020 -#define PCI_DEVICE_ID_SIIG_2P_10x 0x1021 -#define PCI_DEVICE_ID_SIIG_2S_10x_550 0x1030 -#define PCI_DEVICE_ID_SIIG_2S_10x_650 0x1031 -#define PCI_DEVICE_ID_SIIG_2S_10x_850 0x1032 -#define PCI_DEVICE_ID_SIIG_2S1P_10x_550 0x1034 -#define PCI_DEVICE_ID_SIIG_2S1P_10x_650 0x1035 -#define PCI_DEVICE_ID_SIIG_2S1P_10x_850 0x1036 -#define PCI_DEVICE_ID_SIIG_4S_10x_550 0x1050 -#define PCI_DEVICE_ID_SIIG_4S_10x_650 0x1051 -#define PCI_DEVICE_ID_SIIG_4S_10x_850 0x1052 -#define PCI_DEVICE_ID_SIIG_1S_20x_550 0x2000 -#define PCI_DEVICE_ID_SIIG_1S_20x_650 0x2001 -#define PCI_DEVICE_ID_SIIG_1S_20x_850 0x2002 -#define PCI_DEVICE_ID_SIIG_1P_20x 0x2020 -#define PCI_DEVICE_ID_SIIG_2P_20x 0x2021 -#define PCI_DEVICE_ID_SIIG_2S_20x_550 0x2030 -#define PCI_DEVICE_ID_SIIG_2S_20x_650 0x2031 -#define PCI_DEVICE_ID_SIIG_2S_20x_850 0x2032 -#define PCI_DEVICE_ID_SIIG_2P1S_20x_550 0x2040 -#define PCI_DEVICE_ID_SIIG_2P1S_20x_650 0x2041 -#define PCI_DEVICE_ID_SIIG_2P1S_20x_850 0x2042 -#define PCI_DEVICE_ID_SIIG_1S1P_20x_550 0x2010 -#define PCI_DEVICE_ID_SIIG_1S1P_20x_650 0x2011 -#define PCI_DEVICE_ID_SIIG_1S1P_20x_850 0x2012 -#define PCI_DEVICE_ID_SIIG_4S_20x_550 0x2050 -#define PCI_DEVICE_ID_SIIG_4S_20x_650 0x2051 -#define PCI_DEVICE_ID_SIIG_4S_20x_850 0x2052 -#define PCI_DEVICE_ID_SIIG_2S1P_20x_550 0x2060 -#define PCI_DEVICE_ID_SIIG_2S1P_20x_650 0x2061 -#define PCI_DEVICE_ID_SIIG_2S1P_20x_850 0x2062 -#define PCI_DEVICE_ID_SIIG_8S_20x_550 0x2080 -#define PCI_DEVICE_ID_SIIG_8S_20x_650 0x2081 -#define PCI_DEVICE_ID_SIIG_8S_20x_850 0x2082 -#define PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL 0x2050 - -#define PCI_VENDOR_ID_RADISYS 0x1331 - -#define PCI_VENDOR_ID_MICRO_MEMORY 0x1332 -#define PCI_DEVICE_ID_MICRO_MEMORY_5415CN 0x5415 -#define PCI_DEVICE_ID_MICRO_MEMORY_5425CN 0x5425 -#define PCI_DEVICE_ID_MICRO_MEMORY_6155 0x6155 - -#define PCI_VENDOR_ID_DOMEX 0x134a -#define PCI_DEVICE_ID_DOMEX_DMX3191D 0x0001 - -#define PCI_VENDOR_ID_INTASHIELD 0x135a -#define PCI_DEVICE_ID_INTASHIELD_IS200 0x0d80 -#define PCI_DEVICE_ID_INTASHIELD_IS400 0x0dc0 - -#define PCI_VENDOR_ID_QUATECH 0x135C -#define PCI_DEVICE_ID_QUATECH_QSC100 0x0010 -#define PCI_DEVICE_ID_QUATECH_DSC100 0x0020 -#define PCI_DEVICE_ID_QUATECH_DSC200 0x0030 -#define PCI_DEVICE_ID_QUATECH_QSC200 0x0040 -#define PCI_DEVICE_ID_QUATECH_ESC100D 0x0050 -#define PCI_DEVICE_ID_QUATECH_ESC100M 0x0060 -#define PCI_DEVICE_ID_QUATECH_QSCP100 0x0120 -#define PCI_DEVICE_ID_QUATECH_DSCP100 0x0130 -#define PCI_DEVICE_ID_QUATECH_QSCP200 0x0140 -#define PCI_DEVICE_ID_QUATECH_DSCP200 0x0150 -#define PCI_DEVICE_ID_QUATECH_QSCLP100 0x0170 -#define PCI_DEVICE_ID_QUATECH_DSCLP100 0x0180 -#define PCI_DEVICE_ID_QUATECH_DSC100E 0x0181 -#define PCI_DEVICE_ID_QUATECH_SSCLP100 0x0190 -#define PCI_DEVICE_ID_QUATECH_QSCLP200 0x01A0 -#define PCI_DEVICE_ID_QUATECH_DSCLP200 0x01B0 -#define PCI_DEVICE_ID_QUATECH_DSC200E 0x01B1 -#define PCI_DEVICE_ID_QUATECH_SSCLP200 0x01C0 -#define PCI_DEVICE_ID_QUATECH_ESCLP100 0x01E0 -#define PCI_DEVICE_ID_QUATECH_SPPXP_100 0x0278 - -#define PCI_VENDOR_ID_SEALEVEL 0x135e -#define PCI_DEVICE_ID_SEALEVEL_U530 0x7101 -#define PCI_DEVICE_ID_SEALEVEL_UCOMM2 0x7201 -#define PCI_DEVICE_ID_SEALEVEL_UCOMM422 0x7402 -#define PCI_DEVICE_ID_SEALEVEL_UCOMM232 0x7202 -#define PCI_DEVICE_ID_SEALEVEL_COMM4 0x7401 -#define PCI_DEVICE_ID_SEALEVEL_COMM8 0x7801 -#define PCI_DEVICE_ID_SEALEVEL_7803 0x7803 -#define PCI_DEVICE_ID_SEALEVEL_UCOMM8 0x7804 - -#define PCI_VENDOR_ID_HYPERCOPE 0x1365 -#define PCI_DEVICE_ID_HYPERCOPE_PLX 0x9050 -#define PCI_SUBDEVICE_ID_HYPERCOPE_OLD_ERGO 0x0104 -#define PCI_SUBDEVICE_ID_HYPERCOPE_ERGO 0x0106 -#define PCI_SUBDEVICE_ID_HYPERCOPE_METRO 0x0107 -#define PCI_SUBDEVICE_ID_HYPERCOPE_CHAMP2 0x0108 - -#define PCI_VENDOR_ID_DIGIGRAM 0x1369 -#define PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM 0xc001 -#define PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_CAE_SERIAL_SUBSYSTEM 0xc002 - -#define PCI_VENDOR_ID_KAWASAKI 0x136b -#define PCI_DEVICE_ID_MCHIP_KL5A72002 0xff01 - -#define PCI_VENDOR_ID_CNET 0x1371 -#define PCI_DEVICE_ID_CNET_GIGACARD 0x434e - -#define PCI_VENDOR_ID_LMC 0x1376 -#define PCI_DEVICE_ID_LMC_HSSI 0x0003 -#define PCI_DEVICE_ID_LMC_DS3 0x0004 -#define PCI_DEVICE_ID_LMC_SSI 0x0005 -#define PCI_DEVICE_ID_LMC_T1 0x0006 - -#define PCI_VENDOR_ID_NETGEAR 0x1385 -#define PCI_DEVICE_ID_NETGEAR_GA620 0x620a - -#define PCI_VENDOR_ID_APPLICOM 0x1389 -#define PCI_DEVICE_ID_APPLICOM_PCIGENERIC 0x0001 -#define PCI_DEVICE_ID_APPLICOM_PCI2000IBS_CAN 0x0002 -#define PCI_DEVICE_ID_APPLICOM_PCI2000PFB 0x0003 - -#define PCI_VENDOR_ID_MOXA 0x1393 -#define PCI_DEVICE_ID_MOXA_RC7000 0x0001 -#define PCI_DEVICE_ID_MOXA_CP102 0x1020 -#define PCI_DEVICE_ID_MOXA_CP102UL 0x1021 -#define PCI_DEVICE_ID_MOXA_CP102U 0x1022 -#define PCI_DEVICE_ID_MOXA_C104 0x1040 -#define PCI_DEVICE_ID_MOXA_CP104U 0x1041 -#define PCI_DEVICE_ID_MOXA_CP104JU 0x1042 -#define PCI_DEVICE_ID_MOXA_CP104EL 0x1043 -#define PCI_DEVICE_ID_MOXA_CT114 0x1140 -#define PCI_DEVICE_ID_MOXA_CP114 0x1141 -#define PCI_DEVICE_ID_MOXA_CP118U 0x1180 -#define PCI_DEVICE_ID_MOXA_CP118EL 0x1181 -#define PCI_DEVICE_ID_MOXA_CP132 0x1320 -#define PCI_DEVICE_ID_MOXA_CP132U 0x1321 -#define PCI_DEVICE_ID_MOXA_CP134U 0x1340 -#define PCI_DEVICE_ID_MOXA_C168 0x1680 -#define PCI_DEVICE_ID_MOXA_CP168U 0x1681 -#define PCI_DEVICE_ID_MOXA_CP168EL 0x1682 -#define PCI_DEVICE_ID_MOXA_CP204J 0x2040 -#define PCI_DEVICE_ID_MOXA_C218 0x2180 -#define PCI_DEVICE_ID_MOXA_C320 0x3200 - -#define PCI_VENDOR_ID_CCD 0x1397 -#define PCI_DEVICE_ID_CCD_HFC4S 0x08B4 -#define PCI_SUBDEVICE_ID_CCD_PMX2S 0x1234 -#define PCI_DEVICE_ID_CCD_HFC8S 0x16B8 -#define PCI_DEVICE_ID_CCD_2BD0 0x2bd0 -#define PCI_DEVICE_ID_CCD_HFCE1 0x30B1 -#define PCI_SUBDEVICE_ID_CCD_SPD4S 0x3136 -#define PCI_SUBDEVICE_ID_CCD_SPDE1 0x3137 -#define PCI_DEVICE_ID_CCD_B000 0xb000 -#define PCI_DEVICE_ID_CCD_B006 0xb006 -#define PCI_DEVICE_ID_CCD_B007 0xb007 -#define PCI_DEVICE_ID_CCD_B008 0xb008 -#define PCI_DEVICE_ID_CCD_B009 0xb009 -#define PCI_DEVICE_ID_CCD_B00A 0xb00a -#define PCI_DEVICE_ID_CCD_B00B 0xb00b -#define PCI_DEVICE_ID_CCD_B00C 0xb00c -#define PCI_DEVICE_ID_CCD_B100 0xb100 -#define PCI_SUBDEVICE_ID_CCD_IOB4ST 0xB520 -#define PCI_SUBDEVICE_ID_CCD_IOB8STR 0xB521 -#define PCI_SUBDEVICE_ID_CCD_IOB8ST 0xB522 -#define PCI_SUBDEVICE_ID_CCD_IOB1E1 0xB523 -#define PCI_SUBDEVICE_ID_CCD_SWYX4S 0xB540 -#define PCI_SUBDEVICE_ID_CCD_JH4S20 0xB550 -#define PCI_SUBDEVICE_ID_CCD_IOB8ST_1 0xB552 -#define PCI_SUBDEVICE_ID_CCD_JHSE1 0xB553 -#define PCI_SUBDEVICE_ID_CCD_JH8S 0xB55B -#define PCI_SUBDEVICE_ID_CCD_BN4S 0xB560 -#define PCI_SUBDEVICE_ID_CCD_BN8S 0xB562 -#define PCI_SUBDEVICE_ID_CCD_BNE1 0xB563 -#define PCI_SUBDEVICE_ID_CCD_BNE1D 0xB564 -#define PCI_SUBDEVICE_ID_CCD_BNE1DP 0xB565 -#define PCI_SUBDEVICE_ID_CCD_BN2S 0xB566 -#define PCI_SUBDEVICE_ID_CCD_BN1SM 0xB567 -#define PCI_SUBDEVICE_ID_CCD_BN4SM 0xB568 -#define PCI_SUBDEVICE_ID_CCD_BN2SM 0xB569 -#define PCI_SUBDEVICE_ID_CCD_BNE1M 0xB56A -#define PCI_SUBDEVICE_ID_CCD_BN8SP 0xB56B -#define PCI_SUBDEVICE_ID_CCD_HFC4S 0xB620 -#define PCI_SUBDEVICE_ID_CCD_HFC8S 0xB622 -#define PCI_DEVICE_ID_CCD_B700 0xb700 -#define PCI_DEVICE_ID_CCD_B701 0xb701 -#define PCI_SUBDEVICE_ID_CCD_HFCE1 0xC523 -#define PCI_SUBDEVICE_ID_CCD_OV2S 0xE884 -#define PCI_SUBDEVICE_ID_CCD_OV4S 0xE888 -#define PCI_SUBDEVICE_ID_CCD_OV8S 0xE998 - -#define PCI_VENDOR_ID_EXAR 0x13a8 -#define PCI_DEVICE_ID_EXAR_XR17C152 0x0152 -#define PCI_DEVICE_ID_EXAR_XR17C154 0x0154 -#define PCI_DEVICE_ID_EXAR_XR17C158 0x0158 -#define PCI_DEVICE_ID_EXAR_XR17V352 0x0352 -#define PCI_DEVICE_ID_EXAR_XR17V354 0x0354 -#define PCI_DEVICE_ID_EXAR_XR17V358 0x0358 - -#define PCI_VENDOR_ID_MICROGATE 0x13c0 -#define PCI_DEVICE_ID_MICROGATE_USC 0x0010 -#define PCI_DEVICE_ID_MICROGATE_SCA 0x0030 - -#define PCI_VENDOR_ID_3WARE 0x13C1 -#define PCI_DEVICE_ID_3WARE_1000 0x1000 -#define PCI_DEVICE_ID_3WARE_7000 0x1001 -#define PCI_DEVICE_ID_3WARE_9000 0x1002 - -#define PCI_VENDOR_ID_IOMEGA 0x13ca -#define PCI_DEVICE_ID_IOMEGA_BUZ 0x4231 - -#define PCI_VENDOR_ID_ABOCOM 0x13D1 -#define PCI_DEVICE_ID_ABOCOM_2BD1 0x2BD1 - -#define PCI_VENDOR_ID_SUNDANCE 0x13f0 - -#define PCI_VENDOR_ID_CMEDIA 0x13f6 -#define PCI_DEVICE_ID_CMEDIA_CM8338A 0x0100 -#define PCI_DEVICE_ID_CMEDIA_CM8338B 0x0101 -#define PCI_DEVICE_ID_CMEDIA_CM8738 0x0111 -#define PCI_DEVICE_ID_CMEDIA_CM8738B 0x0112 - -#define PCI_VENDOR_ID_ADVANTECH 0x13fe - -#define PCI_VENDOR_ID_MEILHAUS 0x1402 - -#define PCI_VENDOR_ID_LAVA 0x1407 -#define PCI_DEVICE_ID_LAVA_DSERIAL 0x0100 /* 2x 16550 */ -#define PCI_DEVICE_ID_LAVA_QUATRO_A 0x0101 /* 2x 16550, half of 4 port */ -#define PCI_DEVICE_ID_LAVA_QUATRO_B 0x0102 /* 2x 16550, half of 4 port */ -#define PCI_DEVICE_ID_LAVA_QUATTRO_A 0x0120 /* 2x 16550A, half of 4 port */ -#define PCI_DEVICE_ID_LAVA_QUATTRO_B 0x0121 /* 2x 16550A, half of 4 port */ -#define PCI_DEVICE_ID_LAVA_OCTO_A 0x0180 /* 4x 16550A, half of 8 port */ -#define PCI_DEVICE_ID_LAVA_OCTO_B 0x0181 /* 4x 16550A, half of 8 port */ -#define PCI_DEVICE_ID_LAVA_PORT_PLUS 0x0200 /* 2x 16650 */ -#define PCI_DEVICE_ID_LAVA_QUAD_A 0x0201 /* 2x 16650, half of 4 port */ -#define PCI_DEVICE_ID_LAVA_QUAD_B 0x0202 /* 2x 16650, half of 4 port */ -#define PCI_DEVICE_ID_LAVA_SSERIAL 0x0500 /* 1x 16550 */ -#define PCI_DEVICE_ID_LAVA_PORT_650 0x0600 /* 1x 16650 */ -#define PCI_DEVICE_ID_LAVA_PARALLEL 0x8000 -#define PCI_DEVICE_ID_LAVA_DUAL_PAR_A 0x8002 /* The Lava Dual Parallel is */ -#define PCI_DEVICE_ID_LAVA_DUAL_PAR_B 0x8003 /* two PCI devices on a card */ -#define PCI_DEVICE_ID_LAVA_BOCA_IOPPAR 0x8800 - -#define PCI_VENDOR_ID_TIMEDIA 0x1409 -#define PCI_DEVICE_ID_TIMEDIA_1889 0x7168 - -#define PCI_VENDOR_ID_ICE 0x1412 -#define PCI_DEVICE_ID_ICE_1712 0x1712 -#define PCI_DEVICE_ID_VT1724 0x1724 - -#define PCI_VENDOR_ID_OXSEMI 0x1415 -#define PCI_DEVICE_ID_OXSEMI_12PCI840 0x8403 -#define PCI_DEVICE_ID_OXSEMI_PCIe840 0xC000 -#define PCI_DEVICE_ID_OXSEMI_PCIe840_G 0xC004 -#define PCI_DEVICE_ID_OXSEMI_PCIe952_0 0xC100 -#define PCI_DEVICE_ID_OXSEMI_PCIe952_0_G 0xC104 -#define PCI_DEVICE_ID_OXSEMI_PCIe952_1 0xC110 -#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_G 0xC114 -#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_U 0xC118 -#define PCI_DEVICE_ID_OXSEMI_PCIe952_1_GU 0xC11C -#define PCI_DEVICE_ID_OXSEMI_16PCI954 0x9501 -#define PCI_DEVICE_ID_OXSEMI_C950 0x950B -#define PCI_DEVICE_ID_OXSEMI_16PCI95N 0x9511 -#define PCI_DEVICE_ID_OXSEMI_16PCI954PP 0x9513 -#define PCI_DEVICE_ID_OXSEMI_16PCI952 0x9521 -#define PCI_DEVICE_ID_OXSEMI_16PCI952PP 0x9523 -#define PCI_SUBDEVICE_ID_OXSEMI_C950 0x0001 - -#define PCI_VENDOR_ID_CHELSIO 0x1425 - -#define PCI_VENDOR_ID_ADLINK 0x144a - -#define PCI_VENDOR_ID_SAMSUNG 0x144d - -#define PCI_VENDOR_ID_GIGABYTE 0x1458 - -#define PCI_VENDOR_ID_AMBIT 0x1468 - -#define PCI_VENDOR_ID_MYRICOM 0x14c1 - -#define PCI_VENDOR_ID_TITAN 0x14D2 -#define PCI_DEVICE_ID_TITAN_010L 0x8001 -#define PCI_DEVICE_ID_TITAN_100L 0x8010 -#define PCI_DEVICE_ID_TITAN_110L 0x8011 -#define PCI_DEVICE_ID_TITAN_200L 0x8020 -#define PCI_DEVICE_ID_TITAN_210L 0x8021 -#define PCI_DEVICE_ID_TITAN_400L 0x8040 -#define PCI_DEVICE_ID_TITAN_800L 0x8080 -#define PCI_DEVICE_ID_TITAN_100 0xA001 -#define PCI_DEVICE_ID_TITAN_200 0xA005 -#define PCI_DEVICE_ID_TITAN_400 0xA003 -#define PCI_DEVICE_ID_TITAN_800B 0xA004 - -#define PCI_VENDOR_ID_PANACOM 0x14d4 -#define PCI_DEVICE_ID_PANACOM_QUADMODEM 0x0400 -#define PCI_DEVICE_ID_PANACOM_DUALMODEM 0x0402 - -#define PCI_VENDOR_ID_SIPACKETS 0x14d9 -#define PCI_DEVICE_ID_SP1011 0x0010 - -#define PCI_VENDOR_ID_AFAVLAB 0x14db -#define PCI_DEVICE_ID_AFAVLAB_P028 0x2180 -#define PCI_DEVICE_ID_AFAVLAB_P030 0x2182 -#define PCI_SUBDEVICE_ID_AFAVLAB_P061 0x2150 - -#define PCI_VENDOR_ID_AMPLICON 0x14dc - -#define PCI_VENDOR_ID_BCM_GVC 0x14a4 -#define PCI_VENDOR_ID_BROADCOM 0x14e4 -#define PCI_DEVICE_ID_TIGON3_5752 0x1600 -#define PCI_DEVICE_ID_TIGON3_5752M 0x1601 -#define PCI_DEVICE_ID_NX2_5709 0x1639 -#define PCI_DEVICE_ID_NX2_5709S 0x163a -#define PCI_DEVICE_ID_TIGON3_5700 0x1644 -#define PCI_DEVICE_ID_TIGON3_5701 0x1645 -#define PCI_DEVICE_ID_TIGON3_5702 0x1646 -#define PCI_DEVICE_ID_TIGON3_5703 0x1647 -#define PCI_DEVICE_ID_TIGON3_5704 0x1648 -#define PCI_DEVICE_ID_TIGON3_5704S_2 0x1649 -#define PCI_DEVICE_ID_NX2_5706 0x164a -#define PCI_DEVICE_ID_NX2_5708 0x164c -#define PCI_DEVICE_ID_TIGON3_5702FE 0x164d -#define PCI_DEVICE_ID_NX2_57710 0x164e -#define PCI_DEVICE_ID_NX2_57711 0x164f -#define PCI_DEVICE_ID_NX2_57711E 0x1650 -#define PCI_DEVICE_ID_TIGON3_5705 0x1653 -#define PCI_DEVICE_ID_TIGON3_5705_2 0x1654 -#define PCI_DEVICE_ID_TIGON3_5719 0x1657 -#define PCI_DEVICE_ID_TIGON3_5721 0x1659 -#define PCI_DEVICE_ID_TIGON3_5722 0x165a -#define PCI_DEVICE_ID_TIGON3_5723 0x165b -#define PCI_DEVICE_ID_TIGON3_5705M 0x165d -#define PCI_DEVICE_ID_TIGON3_5705M_2 0x165e -#define PCI_DEVICE_ID_NX2_57712 0x1662 -#define PCI_DEVICE_ID_NX2_57712E 0x1663 -#define PCI_DEVICE_ID_NX2_57712_MF 0x1663 -#define PCI_DEVICE_ID_TIGON3_5714 0x1668 -#define PCI_DEVICE_ID_TIGON3_5714S 0x1669 -#define PCI_DEVICE_ID_TIGON3_5780 0x166a -#define PCI_DEVICE_ID_TIGON3_5780S 0x166b -#define PCI_DEVICE_ID_TIGON3_5705F 0x166e -#define PCI_DEVICE_ID_NX2_57712_VF 0x166f -#define PCI_DEVICE_ID_TIGON3_5754M 0x1672 -#define PCI_DEVICE_ID_TIGON3_5755M 0x1673 -#define PCI_DEVICE_ID_TIGON3_5756 0x1674 -#define PCI_DEVICE_ID_TIGON3_5750 0x1676 -#define PCI_DEVICE_ID_TIGON3_5751 0x1677 -#define PCI_DEVICE_ID_TIGON3_5715 0x1678 -#define PCI_DEVICE_ID_TIGON3_5715S 0x1679 -#define PCI_DEVICE_ID_TIGON3_5754 0x167a -#define PCI_DEVICE_ID_TIGON3_5755 0x167b -#define PCI_DEVICE_ID_TIGON3_5751M 0x167d -#define PCI_DEVICE_ID_TIGON3_5751F 0x167e -#define PCI_DEVICE_ID_TIGON3_5787F 0x167f -#define PCI_DEVICE_ID_TIGON3_5761E 0x1680 -#define PCI_DEVICE_ID_TIGON3_5761 0x1681 -#define PCI_DEVICE_ID_TIGON3_5764 0x1684 -#define PCI_DEVICE_ID_NX2_57800 0x168a -#define PCI_DEVICE_ID_NX2_57840 0x168d -#define PCI_DEVICE_ID_NX2_57810 0x168e -#define PCI_DEVICE_ID_TIGON3_5787M 0x1693 -#define PCI_DEVICE_ID_TIGON3_5782 0x1696 -#define PCI_DEVICE_ID_TIGON3_5784 0x1698 -#define PCI_DEVICE_ID_TIGON3_5786 0x169a -#define PCI_DEVICE_ID_TIGON3_5787 0x169b -#define PCI_DEVICE_ID_TIGON3_5788 0x169c -#define PCI_DEVICE_ID_TIGON3_5789 0x169d -#define PCI_DEVICE_ID_NX2_57840_4_10 0x16a1 -#define PCI_DEVICE_ID_NX2_57840_2_20 0x16a2 -#define PCI_DEVICE_ID_NX2_57840_MF 0x16a4 -#define PCI_DEVICE_ID_NX2_57800_MF 0x16a5 -#define PCI_DEVICE_ID_TIGON3_5702X 0x16a6 -#define PCI_DEVICE_ID_TIGON3_5703X 0x16a7 -#define PCI_DEVICE_ID_TIGON3_5704S 0x16a8 -#define PCI_DEVICE_ID_NX2_57800_VF 0x16a9 -#define PCI_DEVICE_ID_NX2_5706S 0x16aa -#define PCI_DEVICE_ID_NX2_5708S 0x16ac -#define PCI_DEVICE_ID_NX2_57840_VF 0x16ad -#define PCI_DEVICE_ID_NX2_57810_MF 0x16ae -#define PCI_DEVICE_ID_NX2_57810_VF 0x16af -#define PCI_DEVICE_ID_TIGON3_5702A3 0x16c6 -#define PCI_DEVICE_ID_TIGON3_5703A3 0x16c7 -#define PCI_DEVICE_ID_TIGON3_5781 0x16dd -#define PCI_DEVICE_ID_TIGON3_5753 0x16f7 -#define PCI_DEVICE_ID_TIGON3_5753M 0x16fd -#define PCI_DEVICE_ID_TIGON3_5753F 0x16fe -#define PCI_DEVICE_ID_TIGON3_5901 0x170d -#define PCI_DEVICE_ID_BCM4401B1 0x170c -#define PCI_DEVICE_ID_TIGON3_5901_2 0x170e -#define PCI_DEVICE_ID_TIGON3_5906 0x1712 -#define PCI_DEVICE_ID_TIGON3_5906M 0x1713 -#define PCI_DEVICE_ID_BCM4401 0x4401 -#define PCI_DEVICE_ID_BCM4401B0 0x4402 - -#define PCI_VENDOR_ID_TOPIC 0x151f -#define PCI_DEVICE_ID_TOPIC_TP560 0x0000 - -#define PCI_VENDOR_ID_MAINPINE 0x1522 -#define PCI_DEVICE_ID_MAINPINE_PBRIDGE 0x0100 -#define PCI_VENDOR_ID_ENE 0x1524 -#define PCI_DEVICE_ID_ENE_CB710_FLASH 0x0510 -#define PCI_DEVICE_ID_ENE_CB712_SD 0x0550 -#define PCI_DEVICE_ID_ENE_CB712_SD_2 0x0551 -#define PCI_DEVICE_ID_ENE_CB714_SD 0x0750 -#define PCI_DEVICE_ID_ENE_CB714_SD_2 0x0751 -#define PCI_DEVICE_ID_ENE_1211 0x1211 -#define PCI_DEVICE_ID_ENE_1225 0x1225 -#define PCI_DEVICE_ID_ENE_1410 0x1410 -#define PCI_DEVICE_ID_ENE_710 0x1411 -#define PCI_DEVICE_ID_ENE_712 0x1412 -#define PCI_DEVICE_ID_ENE_1420 0x1420 -#define PCI_DEVICE_ID_ENE_720 0x1421 -#define PCI_DEVICE_ID_ENE_722 0x1422 - -#define PCI_SUBVENDOR_ID_PERLE 0x155f -#define PCI_SUBDEVICE_ID_PCI_RAS4 0xf001 -#define PCI_SUBDEVICE_ID_PCI_RAS8 0xf010 - -#define PCI_VENDOR_ID_SYBA 0x1592 -#define PCI_DEVICE_ID_SYBA_2P_EPP 0x0782 -#define PCI_DEVICE_ID_SYBA_1P_ECP 0x0783 - -#define PCI_VENDOR_ID_MORETON 0x15aa -#define PCI_DEVICE_ID_RASTEL_2PORT 0x2000 - -#define PCI_VENDOR_ID_VMWARE 0x15ad - -#define PCI_VENDOR_ID_ZOLTRIX 0x15b0 -#define PCI_DEVICE_ID_ZOLTRIX_2BD0 0x2bd0 - -#define PCI_VENDOR_ID_MELLANOX 0x15b3 -#define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44 -#define PCI_DEVICE_ID_MELLANOX_TAVOR_BRIDGE 0x5a46 -#define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278 -#define PCI_DEVICE_ID_MELLANOX_ARBEL 0x6282 -#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c -#define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274 - -#define PCI_VENDOR_ID_DFI 0x15bd - -#define PCI_VENDOR_ID_QUICKNET 0x15e2 -#define PCI_DEVICE_ID_QUICKNET_XJ 0x0500 - -/* - * ADDI-DATA GmbH communication cards - */ -#define PCI_VENDOR_ID_ADDIDATA 0x15B8 -#define PCI_DEVICE_ID_ADDIDATA_APCI7500 0x7000 -#define PCI_DEVICE_ID_ADDIDATA_APCI7420 0x7001 -#define PCI_DEVICE_ID_ADDIDATA_APCI7300 0x7002 -#define PCI_DEVICE_ID_ADDIDATA_APCI7500_2 0x7009 -#define PCI_DEVICE_ID_ADDIDATA_APCI7420_2 0x700A -#define PCI_DEVICE_ID_ADDIDATA_APCI7300_2 0x700B -#define PCI_DEVICE_ID_ADDIDATA_APCI7500_3 0x700C -#define PCI_DEVICE_ID_ADDIDATA_APCI7420_3 0x700D -#define PCI_DEVICE_ID_ADDIDATA_APCI7300_3 0x700E -#define PCI_DEVICE_ID_ADDIDATA_APCI7800_3 0x700F -#define PCI_DEVICE_ID_ADDIDATA_APCIe7300 0x7010 -#define PCI_DEVICE_ID_ADDIDATA_APCIe7420 0x7011 -#define PCI_DEVICE_ID_ADDIDATA_APCIe7500 0x7012 -#define PCI_DEVICE_ID_ADDIDATA_APCIe7800 0x7013 - -#define PCI_VENDOR_ID_PDC 0x15e9 - -#define PCI_VENDOR_ID_FARSITE 0x1619 -#define PCI_DEVICE_ID_FARSITE_T2P 0x0400 -#define PCI_DEVICE_ID_FARSITE_T4P 0x0440 -#define PCI_DEVICE_ID_FARSITE_T1U 0x0610 -#define PCI_DEVICE_ID_FARSITE_T2U 0x0620 -#define PCI_DEVICE_ID_FARSITE_T4U 0x0640 -#define PCI_DEVICE_ID_FARSITE_TE1 0x1610 -#define PCI_DEVICE_ID_FARSITE_TE1C 0x1612 - -#define PCI_VENDOR_ID_ARIMA 0x161f - -#define PCI_VENDOR_ID_BROCADE 0x1657 -#define PCI_DEVICE_ID_BROCADE_CT 0x0014 -#define PCI_DEVICE_ID_BROCADE_FC_8G1P 0x0017 -#define PCI_DEVICE_ID_BROCADE_CT_FC 0x0021 - -#define PCI_VENDOR_ID_SIBYTE 0x166d -#define PCI_DEVICE_ID_BCM1250_PCI 0x0001 -#define PCI_DEVICE_ID_BCM1250_HT 0x0002 - -#define PCI_VENDOR_ID_ATHEROS 0x168c - -#define PCI_VENDOR_ID_NETCELL 0x169c -#define PCI_DEVICE_ID_REVOLUTION 0x0044 - -#define PCI_VENDOR_ID_CENATEK 0x16CA -#define PCI_DEVICE_ID_CENATEK_IDE 0x0001 - -#define PCI_VENDOR_ID_SYNOPSYS 0x16c3 - -#define PCI_VENDOR_ID_VITESSE 0x1725 -#define PCI_DEVICE_ID_VITESSE_VSC7174 0x7174 - -#define PCI_VENDOR_ID_LINKSYS 0x1737 -#define PCI_DEVICE_ID_LINKSYS_EG1064 0x1064 - -#define PCI_VENDOR_ID_ALTIMA 0x173b -#define PCI_DEVICE_ID_ALTIMA_AC1000 0x03e8 -#define PCI_DEVICE_ID_ALTIMA_AC1001 0x03e9 -#define PCI_DEVICE_ID_ALTIMA_AC9100 0x03ea -#define PCI_DEVICE_ID_ALTIMA_AC1003 0x03eb - -#define PCI_VENDOR_ID_CAVIUM 0x177d - -#define PCI_VENDOR_ID_TECHWELL 0x1797 -#define PCI_DEVICE_ID_TECHWELL_6800 0x6800 -#define PCI_DEVICE_ID_TECHWELL_6801 0x6801 -#define PCI_DEVICE_ID_TECHWELL_6804 0x6804 -#define PCI_DEVICE_ID_TECHWELL_6816_1 0x6810 -#define PCI_DEVICE_ID_TECHWELL_6816_2 0x6811 -#define PCI_DEVICE_ID_TECHWELL_6816_3 0x6812 -#define PCI_DEVICE_ID_TECHWELL_6816_4 0x6813 - -#define PCI_VENDOR_ID_BELKIN 0x1799 -#define PCI_DEVICE_ID_BELKIN_F5D7010V7 0x701f - -#define PCI_VENDOR_ID_RDC 0x17f3 -#define PCI_DEVICE_ID_RDC_R6020 0x6020 -#define PCI_DEVICE_ID_RDC_R6030 0x6030 -#define PCI_DEVICE_ID_RDC_R6040 0x6040 -#define PCI_DEVICE_ID_RDC_R6060 0x6060 -#define PCI_DEVICE_ID_RDC_R6061 0x6061 -#define PCI_DEVICE_ID_RDC_D1010 0x1010 - -#define PCI_VENDOR_ID_LENOVO 0x17aa - -#define PCI_VENDOR_ID_ARECA 0x17d3 -#define PCI_DEVICE_ID_ARECA_1110 0x1110 -#define PCI_DEVICE_ID_ARECA_1120 0x1120 -#define PCI_DEVICE_ID_ARECA_1130 0x1130 -#define PCI_DEVICE_ID_ARECA_1160 0x1160 -#define PCI_DEVICE_ID_ARECA_1170 0x1170 -#define PCI_DEVICE_ID_ARECA_1200 0x1200 -#define PCI_DEVICE_ID_ARECA_1201 0x1201 -#define PCI_DEVICE_ID_ARECA_1202 0x1202 -#define PCI_DEVICE_ID_ARECA_1210 0x1210 -#define PCI_DEVICE_ID_ARECA_1220 0x1220 -#define PCI_DEVICE_ID_ARECA_1230 0x1230 -#define PCI_DEVICE_ID_ARECA_1260 0x1260 -#define PCI_DEVICE_ID_ARECA_1270 0x1270 -#define PCI_DEVICE_ID_ARECA_1280 0x1280 -#define PCI_DEVICE_ID_ARECA_1380 0x1380 -#define PCI_DEVICE_ID_ARECA_1381 0x1381 -#define PCI_DEVICE_ID_ARECA_1680 0x1680 -#define PCI_DEVICE_ID_ARECA_1681 0x1681 - -#define PCI_VENDOR_ID_S2IO 0x17d5 -#define PCI_DEVICE_ID_S2IO_WIN 0x5731 -#define PCI_DEVICE_ID_S2IO_UNI 0x5831 -#define PCI_DEVICE_ID_HERC_WIN 0x5732 -#define PCI_DEVICE_ID_HERC_UNI 0x5832 - -#define PCI_VENDOR_ID_SITECOM 0x182d -#define PCI_DEVICE_ID_SITECOM_DC105V2 0x3069 - -#define PCI_VENDOR_ID_TOPSPIN 0x1867 - -#define PCI_VENDOR_ID_COMMTECH 0x18f7 - -#define PCI_VENDOR_ID_SILAN 0x1904 - -#define PCI_VENDOR_ID_RENESAS 0x1912 -#define PCI_DEVICE_ID_RENESAS_SH7781 0x0001 -#define PCI_DEVICE_ID_RENESAS_SH7780 0x0002 -#define PCI_DEVICE_ID_RENESAS_SH7763 0x0004 -#define PCI_DEVICE_ID_RENESAS_SH7785 0x0007 -#define PCI_DEVICE_ID_RENESAS_SH7786 0x0010 - -#define PCI_VENDOR_ID_SOLARFLARE 0x1924 -#define PCI_DEVICE_ID_SOLARFLARE_SFC4000A_0 0x0703 -#define PCI_DEVICE_ID_SOLARFLARE_SFC4000A_1 0x6703 -#define PCI_DEVICE_ID_SOLARFLARE_SFC4000B 0x0710 - -#define PCI_VENDOR_ID_TDI 0x192E -#define PCI_DEVICE_ID_TDI_EHCI 0x0101 - -#define PCI_VENDOR_ID_FREESCALE 0x1957 -#define PCI_DEVICE_ID_MPC8308 0xc006 -#define PCI_DEVICE_ID_MPC8315E 0x00b4 -#define PCI_DEVICE_ID_MPC8315 0x00b5 -#define PCI_DEVICE_ID_MPC8314E 0x00b6 -#define PCI_DEVICE_ID_MPC8314 0x00b7 -#define PCI_DEVICE_ID_MPC8378E 0x00c4 -#define PCI_DEVICE_ID_MPC8378 0x00c5 -#define PCI_DEVICE_ID_MPC8377E 0x00c6 -#define PCI_DEVICE_ID_MPC8377 0x00c7 -#define PCI_DEVICE_ID_MPC8548E 0x0012 -#define PCI_DEVICE_ID_MPC8548 0x0013 -#define PCI_DEVICE_ID_MPC8543E 0x0014 -#define PCI_DEVICE_ID_MPC8543 0x0015 -#define PCI_DEVICE_ID_MPC8547E 0x0018 -#define PCI_DEVICE_ID_MPC8545E 0x0019 -#define PCI_DEVICE_ID_MPC8545 0x001a -#define PCI_DEVICE_ID_MPC8569E 0x0061 -#define PCI_DEVICE_ID_MPC8569 0x0060 -#define PCI_DEVICE_ID_MPC8568E 0x0020 -#define PCI_DEVICE_ID_MPC8568 0x0021 -#define PCI_DEVICE_ID_MPC8567E 0x0022 -#define PCI_DEVICE_ID_MPC8567 0x0023 -#define PCI_DEVICE_ID_MPC8533E 0x0030 -#define PCI_DEVICE_ID_MPC8533 0x0031 -#define PCI_DEVICE_ID_MPC8544E 0x0032 -#define PCI_DEVICE_ID_MPC8544 0x0033 -#define PCI_DEVICE_ID_MPC8572E 0x0040 -#define PCI_DEVICE_ID_MPC8572 0x0041 -#define PCI_DEVICE_ID_MPC8536E 0x0050 -#define PCI_DEVICE_ID_MPC8536 0x0051 -#define PCI_DEVICE_ID_P2020E 0x0070 -#define PCI_DEVICE_ID_P2020 0x0071 -#define PCI_DEVICE_ID_P2010E 0x0078 -#define PCI_DEVICE_ID_P2010 0x0079 -#define PCI_DEVICE_ID_P1020E 0x0100 -#define PCI_DEVICE_ID_P1020 0x0101 -#define PCI_DEVICE_ID_P1021E 0x0102 -#define PCI_DEVICE_ID_P1021 0x0103 -#define PCI_DEVICE_ID_P1011E 0x0108 -#define PCI_DEVICE_ID_P1011 0x0109 -#define PCI_DEVICE_ID_P1022E 0x0110 -#define PCI_DEVICE_ID_P1022 0x0111 -#define PCI_DEVICE_ID_P1013E 0x0118 -#define PCI_DEVICE_ID_P1013 0x0119 -#define PCI_DEVICE_ID_P4080E 0x0400 -#define PCI_DEVICE_ID_P4080 0x0401 -#define PCI_DEVICE_ID_P4040E 0x0408 -#define PCI_DEVICE_ID_P4040 0x0409 -#define PCI_DEVICE_ID_P2040E 0x0410 -#define PCI_DEVICE_ID_P2040 0x0411 -#define PCI_DEVICE_ID_P3041E 0x041E -#define PCI_DEVICE_ID_P3041 0x041F -#define PCI_DEVICE_ID_P5020E 0x0420 -#define PCI_DEVICE_ID_P5020 0x0421 -#define PCI_DEVICE_ID_P5010E 0x0428 -#define PCI_DEVICE_ID_P5010 0x0429 -#define PCI_DEVICE_ID_MPC8641 0x7010 -#define PCI_DEVICE_ID_MPC8641D 0x7011 -#define PCI_DEVICE_ID_MPC8610 0x7018 - -#define PCI_VENDOR_ID_PASEMI 0x1959 - -#define PCI_VENDOR_ID_ATTANSIC 0x1969 -#define PCI_DEVICE_ID_ATTANSIC_L1 0x1048 -#define PCI_DEVICE_ID_ATTANSIC_L2 0x2048 - -#define PCI_VENDOR_ID_JMICRON 0x197B -#define PCI_DEVICE_ID_JMICRON_JMB360 0x2360 -#define PCI_DEVICE_ID_JMICRON_JMB361 0x2361 -#define PCI_DEVICE_ID_JMICRON_JMB362 0x2362 -#define PCI_DEVICE_ID_JMICRON_JMB363 0x2363 -#define PCI_DEVICE_ID_JMICRON_JMB364 0x2364 -#define PCI_DEVICE_ID_JMICRON_JMB365 0x2365 -#define PCI_DEVICE_ID_JMICRON_JMB366 0x2366 -#define PCI_DEVICE_ID_JMICRON_JMB368 0x2368 -#define PCI_DEVICE_ID_JMICRON_JMB369 0x2369 -#define PCI_DEVICE_ID_JMICRON_JMB38X_SD 0x2381 -#define PCI_DEVICE_ID_JMICRON_JMB38X_MMC 0x2382 -#define PCI_DEVICE_ID_JMICRON_JMB38X_MS 0x2383 -#define PCI_DEVICE_ID_JMICRON_JMB385_MS 0x2388 -#define PCI_DEVICE_ID_JMICRON_JMB388_SD 0x2391 -#define PCI_DEVICE_ID_JMICRON_JMB388_ESD 0x2392 -#define PCI_DEVICE_ID_JMICRON_JMB390_MS 0x2393 - -#define PCI_VENDOR_ID_KORENIX 0x1982 -#define PCI_DEVICE_ID_KORENIX_JETCARDF0 0x1600 -#define PCI_DEVICE_ID_KORENIX_JETCARDF1 0x16ff -#define PCI_DEVICE_ID_KORENIX_JETCARDF2 0x1700 -#define PCI_DEVICE_ID_KORENIX_JETCARDF3 0x17ff - -#define PCI_VENDOR_ID_NETRONOME 0x19ee -#define PCI_DEVICE_ID_NETRONOME_NFP3200 0x3200 -#define PCI_DEVICE_ID_NETRONOME_NFP3240 0x3240 -#define PCI_DEVICE_ID_NETRONOME_NFP4000 0x4000 -#define PCI_DEVICE_ID_NETRONOME_NFP6000 0x6000 -#define PCI_DEVICE_ID_NETRONOME_NFP6000_VF 0x6003 - -#define PCI_VENDOR_ID_QMI 0x1a32 - -#define PCI_VENDOR_ID_AZWAVE 0x1a3b - -#define PCI_VENDOR_ID_REDHAT_QUMRANET 0x1af4 -#define PCI_SUBVENDOR_ID_REDHAT_QUMRANET 0x1af4 -#define PCI_SUBDEVICE_ID_QEMU 0x1100 - -#define PCI_VENDOR_ID_ASMEDIA 0x1b21 - -#define PCI_VENDOR_ID_CIRCUITCO 0x1cc8 -#define PCI_SUBSYSTEM_ID_CIRCUITCO_MINNOWBOARD 0x0001 - -#define PCI_VENDOR_ID_TEKRAM 0x1de1 -#define PCI_DEVICE_ID_TEKRAM_DC290 0xdc29 - -#define PCI_VENDOR_ID_TEHUTI 0x1fc9 -#define PCI_DEVICE_ID_TEHUTI_3009 0x3009 -#define PCI_DEVICE_ID_TEHUTI_3010 0x3010 -#define PCI_DEVICE_ID_TEHUTI_3014 0x3014 - -#define PCI_VENDOR_ID_HINT 0x3388 -#define PCI_DEVICE_ID_HINT_VXPROII_IDE 0x8013 - -#define PCI_VENDOR_ID_3DLABS 0x3d3d -#define PCI_DEVICE_ID_3DLABS_PERMEDIA2 0x0007 -#define PCI_DEVICE_ID_3DLABS_PERMEDIA2V 0x0009 - -#define PCI_VENDOR_ID_NETXEN 0x4040 -#define PCI_DEVICE_ID_NX2031_10GXSR 0x0001 -#define PCI_DEVICE_ID_NX2031_10GCX4 0x0002 -#define PCI_DEVICE_ID_NX2031_4GCU 0x0003 -#define PCI_DEVICE_ID_NX2031_IMEZ 0x0004 -#define PCI_DEVICE_ID_NX2031_HMEZ 0x0005 -#define PCI_DEVICE_ID_NX2031_XG_MGMT 0x0024 -#define PCI_DEVICE_ID_NX2031_XG_MGMT2 0x0025 -#define PCI_DEVICE_ID_NX3031 0x0100 - -#define PCI_VENDOR_ID_AKS 0x416c -#define PCI_DEVICE_ID_AKS_ALADDINCARD 0x0100 - -#define PCI_VENDOR_ID_ACCESSIO 0x494f -#define PCI_DEVICE_ID_ACCESSIO_WDG_CSM 0x22c0 - -#define PCI_VENDOR_ID_S3 0x5333 -#define PCI_DEVICE_ID_S3_TRIO 0x8811 -#define PCI_DEVICE_ID_S3_868 0x8880 -#define PCI_DEVICE_ID_S3_968 0x88f0 -#define PCI_DEVICE_ID_S3_SAVAGE4 0x8a25 -#define PCI_DEVICE_ID_S3_PROSAVAGE8 0x8d04 -#define PCI_DEVICE_ID_S3_SONICVIBES 0xca00 - -#define PCI_VENDOR_ID_DUNORD 0x5544 -#define PCI_DEVICE_ID_DUNORD_I3000 0x0001 - -#define PCI_VENDOR_ID_DCI 0x6666 -#define PCI_DEVICE_ID_DCI_PCCOM4 0x0001 -#define PCI_DEVICE_ID_DCI_PCCOM8 0x0002 -#define PCI_DEVICE_ID_DCI_PCCOM2 0x0004 - -#define PCI_VENDOR_ID_INTEL 0x8086 -#define PCI_DEVICE_ID_INTEL_EESSC 0x0008 -#define PCI_DEVICE_ID_INTEL_PXHD_0 0x0320 -#define PCI_DEVICE_ID_INTEL_PXHD_1 0x0321 -#define PCI_DEVICE_ID_INTEL_PXH_0 0x0329 -#define PCI_DEVICE_ID_INTEL_PXH_1 0x032A -#define PCI_DEVICE_ID_INTEL_PXHV 0x032C -#define PCI_DEVICE_ID_INTEL_80332_0 0x0330 -#define PCI_DEVICE_ID_INTEL_80332_1 0x0332 -#define PCI_DEVICE_ID_INTEL_80333_0 0x0370 -#define PCI_DEVICE_ID_INTEL_80333_1 0x0372 -#define PCI_DEVICE_ID_INTEL_82375 0x0482 -#define PCI_DEVICE_ID_INTEL_82424 0x0483 -#define PCI_DEVICE_ID_INTEL_82378 0x0484 -#define PCI_DEVICE_ID_INTEL_MRST_SD0 0x0807 -#define PCI_DEVICE_ID_INTEL_MRST_SD1 0x0808 -#define PCI_DEVICE_ID_INTEL_MFD_SD 0x0820 -#define PCI_DEVICE_ID_INTEL_MFD_SDIO1 0x0821 -#define PCI_DEVICE_ID_INTEL_MFD_SDIO2 0x0822 -#define PCI_DEVICE_ID_INTEL_MFD_EMMC0 0x0823 -#define PCI_DEVICE_ID_INTEL_MFD_EMMC1 0x0824 -#define PCI_DEVICE_ID_INTEL_MRST_SD2 0x084F -#define PCI_DEVICE_ID_INTEL_QUARK_X1000_ILB 0x095E -#define PCI_DEVICE_ID_INTEL_I960 0x0960 -#define PCI_DEVICE_ID_INTEL_I960RM 0x0962 -#define PCI_DEVICE_ID_INTEL_CENTERTON_ILB 0x0c60 -#define PCI_DEVICE_ID_INTEL_8257X_SOL 0x1062 -#define PCI_DEVICE_ID_INTEL_82573E_SOL 0x1085 -#define PCI_DEVICE_ID_INTEL_82573L_SOL 0x108F -#define PCI_DEVICE_ID_INTEL_82815_MC 0x1130 -#define PCI_DEVICE_ID_INTEL_82815_CGC 0x1132 -#define PCI_DEVICE_ID_INTEL_82092AA_0 0x1221 -#define PCI_DEVICE_ID_INTEL_7505_0 0x2550 -#define PCI_DEVICE_ID_INTEL_7205_0 0x255d -#define PCI_DEVICE_ID_INTEL_82437 0x122d -#define PCI_DEVICE_ID_INTEL_82371FB_0 0x122e -#define PCI_DEVICE_ID_INTEL_82371FB_1 0x1230 -#define PCI_DEVICE_ID_INTEL_82371MX 0x1234 -#define PCI_DEVICE_ID_INTEL_82441 0x1237 -#define PCI_DEVICE_ID_INTEL_82380FB 0x124b -#define PCI_DEVICE_ID_INTEL_82439 0x1250 -#define PCI_DEVICE_ID_INTEL_LIGHT_RIDGE 0x1513 /* Tbt 1 Gen 1 */ -#define PCI_DEVICE_ID_INTEL_EAGLE_RIDGE 0x151a -#define PCI_DEVICE_ID_INTEL_LIGHT_PEAK 0x151b -#define PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C 0x1547 /* Tbt 1 Gen 2 */ -#define PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_2C 0x1548 -#define PCI_DEVICE_ID_INTEL_PORT_RIDGE 0x1549 -#define PCI_DEVICE_ID_INTEL_REDWOOD_RIDGE_2C_NHI 0x1566 /* Tbt 1 Gen 3 */ -#define PCI_DEVICE_ID_INTEL_REDWOOD_RIDGE_2C_BRIDGE 0x1567 -#define PCI_DEVICE_ID_INTEL_REDWOOD_RIDGE_4C_NHI 0x1568 -#define PCI_DEVICE_ID_INTEL_REDWOOD_RIDGE_4C_BRIDGE 0x1569 -#define PCI_DEVICE_ID_INTEL_FALCON_RIDGE_2C_NHI 0x156a /* Thunderbolt 2 */ -#define PCI_DEVICE_ID_INTEL_FALCON_RIDGE_2C_BRIDGE 0x156b -#define PCI_DEVICE_ID_INTEL_FALCON_RIDGE_4C_NHI 0x156c -#define PCI_DEVICE_ID_INTEL_FALCON_RIDGE_4C_BRIDGE 0x156d -#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_NHI 0x1575 /* Thunderbolt 3 */ -#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_2C_BRIDGE 0x1576 -#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_NHI 0x1577 -#define PCI_DEVICE_ID_INTEL_ALPINE_RIDGE_4C_BRIDGE 0x1578 -#define PCI_DEVICE_ID_INTEL_80960_RP 0x1960 -#define PCI_DEVICE_ID_INTEL_82840_HB 0x1a21 -#define PCI_DEVICE_ID_INTEL_82845_HB 0x1a30 -#define PCI_DEVICE_ID_INTEL_IOAT 0x1a38 -#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MIN 0x1c41 -#define PCI_DEVICE_ID_INTEL_COUGARPOINT_LPC_MAX 0x1c5f -#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_0 0x1d40 -#define PCI_DEVICE_ID_INTEL_PATSBURG_LPC_1 0x1d41 -#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_XHCI 0x1e31 -#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MIN 0x1e40 -#define PCI_DEVICE_ID_INTEL_PANTHERPOINT_LPC_MAX 0x1e5f -#define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MIN 0x2310 -#define PCI_DEVICE_ID_INTEL_DH89XXCC_LPC_MAX 0x231f -#define PCI_DEVICE_ID_INTEL_82801AA_0 0x2410 -#define PCI_DEVICE_ID_INTEL_82801AA_1 0x2411 -#define PCI_DEVICE_ID_INTEL_82801AA_3 0x2413 -#define PCI_DEVICE_ID_INTEL_82801AA_5 0x2415 -#define PCI_DEVICE_ID_INTEL_82801AA_6 0x2416 -#define PCI_DEVICE_ID_INTEL_82801AA_8 0x2418 -#define PCI_DEVICE_ID_INTEL_82801AB_0 0x2420 -#define PCI_DEVICE_ID_INTEL_82801AB_1 0x2421 -#define PCI_DEVICE_ID_INTEL_82801AB_3 0x2423 -#define PCI_DEVICE_ID_INTEL_82801AB_5 0x2425 -#define PCI_DEVICE_ID_INTEL_82801AB_6 0x2426 -#define PCI_DEVICE_ID_INTEL_82801AB_8 0x2428 -#define PCI_DEVICE_ID_INTEL_82801BA_0 0x2440 -#define PCI_DEVICE_ID_INTEL_82801BA_2 0x2443 -#define PCI_DEVICE_ID_INTEL_82801BA_4 0x2445 -#define PCI_DEVICE_ID_INTEL_82801BA_6 0x2448 -#define PCI_DEVICE_ID_INTEL_82801BA_8 0x244a -#define PCI_DEVICE_ID_INTEL_82801BA_9 0x244b -#define PCI_DEVICE_ID_INTEL_82801BA_10 0x244c -#define PCI_DEVICE_ID_INTEL_82801BA_11 0x244e -#define PCI_DEVICE_ID_INTEL_82801E_0 0x2450 -#define PCI_DEVICE_ID_INTEL_82801E_11 0x245b -#define PCI_DEVICE_ID_INTEL_82801CA_0 0x2480 -#define PCI_DEVICE_ID_INTEL_82801CA_3 0x2483 -#define PCI_DEVICE_ID_INTEL_82801CA_5 0x2485 -#define PCI_DEVICE_ID_INTEL_82801CA_6 0x2486 -#define PCI_DEVICE_ID_INTEL_82801CA_10 0x248a -#define PCI_DEVICE_ID_INTEL_82801CA_11 0x248b -#define PCI_DEVICE_ID_INTEL_82801CA_12 0x248c -#define PCI_DEVICE_ID_INTEL_82801DB_0 0x24c0 -#define PCI_DEVICE_ID_INTEL_82801DB_1 0x24c1 -#define PCI_DEVICE_ID_INTEL_82801DB_2 0x24c2 -#define PCI_DEVICE_ID_INTEL_82801DB_3 0x24c3 -#define PCI_DEVICE_ID_INTEL_82801DB_5 0x24c5 -#define PCI_DEVICE_ID_INTEL_82801DB_6 0x24c6 -#define PCI_DEVICE_ID_INTEL_82801DB_9 0x24c9 -#define PCI_DEVICE_ID_INTEL_82801DB_10 0x24ca -#define PCI_DEVICE_ID_INTEL_82801DB_11 0x24cb -#define PCI_DEVICE_ID_INTEL_82801DB_12 0x24cc -#define PCI_DEVICE_ID_INTEL_82801EB_0 0x24d0 -#define PCI_DEVICE_ID_INTEL_82801EB_1 0x24d1 -#define PCI_DEVICE_ID_INTEL_82801EB_3 0x24d3 -#define PCI_DEVICE_ID_INTEL_82801EB_5 0x24d5 -#define PCI_DEVICE_ID_INTEL_82801EB_6 0x24d6 -#define PCI_DEVICE_ID_INTEL_82801EB_11 0x24db -#define PCI_DEVICE_ID_INTEL_82801EB_12 0x24dc -#define PCI_DEVICE_ID_INTEL_82801EB_13 0x24dd -#define PCI_DEVICE_ID_INTEL_ESB_1 0x25a1 -#define PCI_DEVICE_ID_INTEL_ESB_2 0x25a2 -#define PCI_DEVICE_ID_INTEL_ESB_4 0x25a4 -#define PCI_DEVICE_ID_INTEL_ESB_5 0x25a6 -#define PCI_DEVICE_ID_INTEL_ESB_9 0x25ab -#define PCI_DEVICE_ID_INTEL_ESB_10 0x25ac -#define PCI_DEVICE_ID_INTEL_82820_HB 0x2500 -#define PCI_DEVICE_ID_INTEL_82820_UP_HB 0x2501 -#define PCI_DEVICE_ID_INTEL_82850_HB 0x2530 -#define PCI_DEVICE_ID_INTEL_82860_HB 0x2531 -#define PCI_DEVICE_ID_INTEL_E7501_MCH 0x254c -#define PCI_DEVICE_ID_INTEL_82845G_HB 0x2560 -#define PCI_DEVICE_ID_INTEL_82845G_IG 0x2562 -#define PCI_DEVICE_ID_INTEL_82865_HB 0x2570 -#define PCI_DEVICE_ID_INTEL_82865_IG 0x2572 -#define PCI_DEVICE_ID_INTEL_82875_HB 0x2578 -#define PCI_DEVICE_ID_INTEL_82915G_HB 0x2580 -#define PCI_DEVICE_ID_INTEL_82915G_IG 0x2582 -#define PCI_DEVICE_ID_INTEL_82915GM_HB 0x2590 -#define PCI_DEVICE_ID_INTEL_82915GM_IG 0x2592 -#define PCI_DEVICE_ID_INTEL_5000_ERR 0x25F0 -#define PCI_DEVICE_ID_INTEL_5000_FBD0 0x25F5 -#define PCI_DEVICE_ID_INTEL_5000_FBD1 0x25F6 -#define PCI_DEVICE_ID_INTEL_82945G_HB 0x2770 -#define PCI_DEVICE_ID_INTEL_82945G_IG 0x2772 -#define PCI_DEVICE_ID_INTEL_3000_HB 0x2778 -#define PCI_DEVICE_ID_INTEL_82945GM_HB 0x27A0 -#define PCI_DEVICE_ID_INTEL_82945GM_IG 0x27A2 -#define PCI_DEVICE_ID_INTEL_ICH6_0 0x2640 -#define PCI_DEVICE_ID_INTEL_ICH6_1 0x2641 -#define PCI_DEVICE_ID_INTEL_ICH6_2 0x2642 -#define PCI_DEVICE_ID_INTEL_ICH6_16 0x266a -#define PCI_DEVICE_ID_INTEL_ICH6_17 0x266d -#define PCI_DEVICE_ID_INTEL_ICH6_18 0x266e -#define PCI_DEVICE_ID_INTEL_ICH6_19 0x266f -#define PCI_DEVICE_ID_INTEL_ESB2_0 0x2670 -#define PCI_DEVICE_ID_INTEL_ESB2_14 0x2698 -#define PCI_DEVICE_ID_INTEL_ESB2_17 0x269b -#define PCI_DEVICE_ID_INTEL_ESB2_18 0x269e -#define PCI_DEVICE_ID_INTEL_ICH7_0 0x27b8 -#define PCI_DEVICE_ID_INTEL_ICH7_1 0x27b9 -#define PCI_DEVICE_ID_INTEL_ICH7_30 0x27b0 -#define PCI_DEVICE_ID_INTEL_TGP_LPC 0x27bc -#define PCI_DEVICE_ID_INTEL_ICH7_31 0x27bd -#define PCI_DEVICE_ID_INTEL_ICH7_17 0x27da -#define PCI_DEVICE_ID_INTEL_ICH7_19 0x27dd -#define PCI_DEVICE_ID_INTEL_ICH7_20 0x27de -#define PCI_DEVICE_ID_INTEL_ICH7_21 0x27df -#define PCI_DEVICE_ID_INTEL_ICH8_0 0x2810 -#define PCI_DEVICE_ID_INTEL_ICH8_1 0x2811 -#define PCI_DEVICE_ID_INTEL_ICH8_2 0x2812 -#define PCI_DEVICE_ID_INTEL_ICH8_3 0x2814 -#define PCI_DEVICE_ID_INTEL_ICH8_4 0x2815 -#define PCI_DEVICE_ID_INTEL_ICH8_5 0x283e -#define PCI_DEVICE_ID_INTEL_ICH8_6 0x2850 -#define PCI_DEVICE_ID_INTEL_ICH9_0 0x2910 -#define PCI_DEVICE_ID_INTEL_ICH9_1 0x2917 -#define PCI_DEVICE_ID_INTEL_ICH9_2 0x2912 -#define PCI_DEVICE_ID_INTEL_ICH9_3 0x2913 -#define PCI_DEVICE_ID_INTEL_ICH9_4 0x2914 -#define PCI_DEVICE_ID_INTEL_ICH9_5 0x2919 -#define PCI_DEVICE_ID_INTEL_ICH9_6 0x2930 -#define PCI_DEVICE_ID_INTEL_ICH9_7 0x2916 -#define PCI_DEVICE_ID_INTEL_ICH9_8 0x2918 -#define PCI_DEVICE_ID_INTEL_I7_MCR 0x2c18 -#define PCI_DEVICE_ID_INTEL_I7_MC_TAD 0x2c19 -#define PCI_DEVICE_ID_INTEL_I7_MC_RAS 0x2c1a -#define PCI_DEVICE_ID_INTEL_I7_MC_TEST 0x2c1c -#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL 0x2c20 -#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_ADDR 0x2c21 -#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_RANK 0x2c22 -#define PCI_DEVICE_ID_INTEL_I7_MC_CH0_TC 0x2c23 -#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL 0x2c28 -#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_ADDR 0x2c29 -#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_RANK 0x2c2a -#define PCI_DEVICE_ID_INTEL_I7_MC_CH1_TC 0x2c2b -#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL 0x2c30 -#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR 0x2c31 -#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK 0x2c32 -#define PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC 0x2c33 -#define PCI_DEVICE_ID_INTEL_I7_NONCORE 0x2c41 -#define PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT 0x2c40 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE 0x2c50 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT 0x2c51 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2 0x2c70 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_SAD 0x2c81 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_LINK0 0x2c90 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_QPI_PHY0 0x2c91 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR 0x2c98 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD 0x2c99 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST 0x2c9C -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_CTRL 0x2ca0 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_ADDR 0x2ca1 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK 0x2ca2 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC 0x2ca3 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL 0x2ca8 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR 0x2ca9 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK 0x2caa -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC 0x2cab -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR_REV2 0x2d98 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD_REV2 0x2d99 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_RAS_REV2 0x2d9a -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST_REV2 0x2d9c -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_CTRL_REV2 0x2da0 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_ADDR_REV2 0x2da1 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_RANK_REV2 0x2da2 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH0_TC_REV2 0x2da3 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_CTRL_REV2 0x2da8 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR_REV2 0x2da9 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK_REV2 0x2daa -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC_REV2 0x2dab -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_CTRL_REV2 0x2db0 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2 0x2db1 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2 0x2db2 -#define PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2 0x2db3 -#define PCI_DEVICE_ID_INTEL_82855PM_HB 0x3340 -#define PCI_DEVICE_ID_INTEL_IOAT_TBG4 0x3429 -#define PCI_DEVICE_ID_INTEL_IOAT_TBG5 0x342a -#define PCI_DEVICE_ID_INTEL_IOAT_TBG6 0x342b -#define PCI_DEVICE_ID_INTEL_IOAT_TBG7 0x342c -#define PCI_DEVICE_ID_INTEL_X58_HUB_MGMT 0x342e -#define PCI_DEVICE_ID_INTEL_IOAT_TBG0 0x3430 -#define PCI_DEVICE_ID_INTEL_IOAT_TBG1 0x3431 -#define PCI_DEVICE_ID_INTEL_IOAT_TBG2 0x3432 -#define PCI_DEVICE_ID_INTEL_IOAT_TBG3 0x3433 -#define PCI_DEVICE_ID_INTEL_82830_HB 0x3575 -#define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577 -#define PCI_DEVICE_ID_INTEL_82854_HB 0x358c -#define PCI_DEVICE_ID_INTEL_82854_IG 0x358e -#define PCI_DEVICE_ID_INTEL_82855GM_HB 0x3580 -#define PCI_DEVICE_ID_INTEL_82855GM_IG 0x3582 -#define PCI_DEVICE_ID_INTEL_E7520_MCH 0x3590 -#define PCI_DEVICE_ID_INTEL_E7320_MCH 0x3592 -#define PCI_DEVICE_ID_INTEL_MCH_PA 0x3595 -#define PCI_DEVICE_ID_INTEL_MCH_PA1 0x3596 -#define PCI_DEVICE_ID_INTEL_MCH_PB 0x3597 -#define PCI_DEVICE_ID_INTEL_MCH_PB1 0x3598 -#define PCI_DEVICE_ID_INTEL_MCH_PC 0x3599 -#define PCI_DEVICE_ID_INTEL_MCH_PC1 0x359a -#define PCI_DEVICE_ID_INTEL_E7525_MCH 0x359e -#define PCI_DEVICE_ID_INTEL_I7300_MCH_ERR 0x360c -#define PCI_DEVICE_ID_INTEL_I7300_MCH_FB0 0x360f -#define PCI_DEVICE_ID_INTEL_I7300_MCH_FB1 0x3610 -#define PCI_DEVICE_ID_INTEL_IOAT_CNB 0x360b -#define PCI_DEVICE_ID_INTEL_FBD_CNB 0x360c -#define PCI_DEVICE_ID_INTEL_IOAT_JSF0 0x3710 -#define PCI_DEVICE_ID_INTEL_IOAT_JSF1 0x3711 -#define PCI_DEVICE_ID_INTEL_IOAT_JSF2 0x3712 -#define PCI_DEVICE_ID_INTEL_IOAT_JSF3 0x3713 -#define PCI_DEVICE_ID_INTEL_IOAT_JSF4 0x3714 -#define PCI_DEVICE_ID_INTEL_IOAT_JSF5 0x3715 -#define PCI_DEVICE_ID_INTEL_IOAT_JSF6 0x3716 -#define PCI_DEVICE_ID_INTEL_IOAT_JSF7 0x3717 -#define PCI_DEVICE_ID_INTEL_IOAT_JSF8 0x3718 -#define PCI_DEVICE_ID_INTEL_IOAT_JSF9 0x3719 -#define PCI_DEVICE_ID_INTEL_ICH10_0 0x3a14 -#define PCI_DEVICE_ID_INTEL_ICH10_1 0x3a16 -#define PCI_DEVICE_ID_INTEL_ICH10_2 0x3a18 -#define PCI_DEVICE_ID_INTEL_ICH10_3 0x3a1a -#define PCI_DEVICE_ID_INTEL_ICH10_4 0x3a30 -#define PCI_DEVICE_ID_INTEL_ICH10_5 0x3a60 -#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MIN 0x3b00 -#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_LPC_MAX 0x3b1f -#define PCI_DEVICE_ID_INTEL_IOAT_SNB0 0x3c20 -#define PCI_DEVICE_ID_INTEL_IOAT_SNB1 0x3c21 -#define PCI_DEVICE_ID_INTEL_IOAT_SNB2 0x3c22 -#define PCI_DEVICE_ID_INTEL_IOAT_SNB3 0x3c23 -#define PCI_DEVICE_ID_INTEL_IOAT_SNB4 0x3c24 -#define PCI_DEVICE_ID_INTEL_IOAT_SNB5 0x3c25 -#define PCI_DEVICE_ID_INTEL_IOAT_SNB6 0x3c26 -#define PCI_DEVICE_ID_INTEL_IOAT_SNB7 0x3c27 -#define PCI_DEVICE_ID_INTEL_IOAT_SNB8 0x3c2e -#define PCI_DEVICE_ID_INTEL_IOAT_SNB9 0x3c2f -#define PCI_DEVICE_ID_INTEL_UNC_HA 0x3c46 -#define PCI_DEVICE_ID_INTEL_UNC_IMC0 0x3cb0 -#define PCI_DEVICE_ID_INTEL_UNC_IMC1 0x3cb1 -#define PCI_DEVICE_ID_INTEL_UNC_IMC2 0x3cb4 -#define PCI_DEVICE_ID_INTEL_UNC_IMC3 0x3cb5 -#define PCI_DEVICE_ID_INTEL_UNC_QPI0 0x3c41 -#define PCI_DEVICE_ID_INTEL_UNC_QPI1 0x3c42 -#define PCI_DEVICE_ID_INTEL_UNC_R2PCIE 0x3c43 -#define PCI_DEVICE_ID_INTEL_UNC_R3QPI0 0x3c44 -#define PCI_DEVICE_ID_INTEL_UNC_R3QPI1 0x3c45 -#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_RAS 0x3c71 /* 15.1 */ -#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR0 0x3c72 /* 16.2 */ -#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR1 0x3c73 /* 16.3 */ -#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR2 0x3c76 /* 16.6 */ -#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_ERR3 0x3c77 /* 16.7 */ -#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0 0x3ca0 /* 14.0 */ -#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA 0x3ca8 /* 15.0 */ -#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0 0x3caa /* 15.2 */ -#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD1 0x3cab /* 15.3 */ -#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD2 0x3cac /* 15.4 */ -#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD3 0x3cad /* 15.5 */ -#define PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO 0x3cb8 /* 17.0 */ -#define PCI_DEVICE_ID_INTEL_JAKETOWN_UBOX 0x3ce0 -#define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD0 0x3cf4 /* 12.6 */ -#define PCI_DEVICE_ID_INTEL_SBRIDGE_BR 0x3cf5 /* 13.6 */ -#define PCI_DEVICE_ID_INTEL_SBRIDGE_SAD1 0x3cf6 /* 12.7 */ -#define PCI_DEVICE_ID_INTEL_IOAT_SNB 0x402f -#define PCI_DEVICE_ID_INTEL_5100_16 0x65f0 -#define PCI_DEVICE_ID_INTEL_5100_19 0x65f3 -#define PCI_DEVICE_ID_INTEL_5100_21 0x65f5 -#define PCI_DEVICE_ID_INTEL_5100_22 0x65f6 -#define PCI_DEVICE_ID_INTEL_5400_ERR 0x4030 -#define PCI_DEVICE_ID_INTEL_5400_FBD0 0x4035 -#define PCI_DEVICE_ID_INTEL_5400_FBD1 0x4036 -#define PCI_DEVICE_ID_INTEL_IOAT_SCNB 0x65ff -#define PCI_DEVICE_ID_INTEL_EP80579_0 0x5031 -#define PCI_DEVICE_ID_INTEL_EP80579_1 0x5032 -#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000 -#define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010 -#define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020 -#define PCI_DEVICE_ID_INTEL_82437VX 0x7030 -#define PCI_DEVICE_ID_INTEL_82439TX 0x7100 -#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110 -#define PCI_DEVICE_ID_INTEL_82371AB 0x7111 -#define PCI_DEVICE_ID_INTEL_82371AB_2 0x7112 -#define PCI_DEVICE_ID_INTEL_82371AB_3 0x7113 -#define PCI_DEVICE_ID_INTEL_82810_MC1 0x7120 -#define PCI_DEVICE_ID_INTEL_82810_IG1 0x7121 -#define PCI_DEVICE_ID_INTEL_82810_MC3 0x7122 -#define PCI_DEVICE_ID_INTEL_82810_IG3 0x7123 -#define PCI_DEVICE_ID_INTEL_82810E_MC 0x7124 -#define PCI_DEVICE_ID_INTEL_82810E_IG 0x7125 -#define PCI_DEVICE_ID_INTEL_82443LX_0 0x7180 -#define PCI_DEVICE_ID_INTEL_82443LX_1 0x7181 -#define PCI_DEVICE_ID_INTEL_82443BX_0 0x7190 -#define PCI_DEVICE_ID_INTEL_82443BX_1 0x7191 -#define PCI_DEVICE_ID_INTEL_82443BX_2 0x7192 -#define PCI_DEVICE_ID_INTEL_440MX 0x7195 -#define PCI_DEVICE_ID_INTEL_440MX_6 0x7196 -#define PCI_DEVICE_ID_INTEL_82443MX_0 0x7198 -#define PCI_DEVICE_ID_INTEL_82443MX_1 0x7199 -#define PCI_DEVICE_ID_INTEL_82443MX_3 0x719b -#define PCI_DEVICE_ID_INTEL_82443GX_0 0x71a0 -#define PCI_DEVICE_ID_INTEL_82443GX_2 0x71a2 -#define PCI_DEVICE_ID_INTEL_82372FB_1 0x7601 -#define PCI_DEVICE_ID_INTEL_SCH_LPC 0x8119 -#define PCI_DEVICE_ID_INTEL_SCH_IDE 0x811a -#define PCI_DEVICE_ID_INTEL_E6XX_CU 0x8183 -#define PCI_DEVICE_ID_INTEL_ITC_LPC 0x8186 -#define PCI_DEVICE_ID_INTEL_82454GX 0x84c4 -#define PCI_DEVICE_ID_INTEL_82450GX 0x84c5 -#define PCI_DEVICE_ID_INTEL_82451NX 0x84ca -#define PCI_DEVICE_ID_INTEL_82454NX 0x84cb -#define PCI_DEVICE_ID_INTEL_84460GX 0x84ea -#define PCI_DEVICE_ID_INTEL_IXP4XX 0x8500 -#define PCI_DEVICE_ID_INTEL_IXP2800 0x9004 -#define PCI_DEVICE_ID_INTEL_S21152BB 0xb152 - -#define PCI_VENDOR_ID_SCALEMP 0x8686 -#define PCI_DEVICE_ID_SCALEMP_VSMP_CTL 0x1010 - -#define PCI_VENDOR_ID_COMPUTONE 0x8e0e -#define PCI_DEVICE_ID_COMPUTONE_PG 0x0302 -#define PCI_SUBVENDOR_ID_COMPUTONE 0x8e0e -#define PCI_SUBDEVICE_ID_COMPUTONE_PG4 0x0001 -#define PCI_SUBDEVICE_ID_COMPUTONE_PG8 0x0002 -#define PCI_SUBDEVICE_ID_COMPUTONE_PG6 0x0003 - -#define PCI_VENDOR_ID_KTI 0x8e2e - -#define PCI_VENDOR_ID_ADAPTEC 0x9004 -#define PCI_DEVICE_ID_ADAPTEC_7810 0x1078 -#define PCI_DEVICE_ID_ADAPTEC_7821 0x2178 -#define PCI_DEVICE_ID_ADAPTEC_38602 0x3860 -#define PCI_DEVICE_ID_ADAPTEC_7850 0x5078 -#define PCI_DEVICE_ID_ADAPTEC_7855 0x5578 -#define PCI_DEVICE_ID_ADAPTEC_3860 0x6038 -#define PCI_DEVICE_ID_ADAPTEC_1480A 0x6075 -#define PCI_DEVICE_ID_ADAPTEC_7860 0x6078 -#define PCI_DEVICE_ID_ADAPTEC_7861 0x6178 -#define PCI_DEVICE_ID_ADAPTEC_7870 0x7078 -#define PCI_DEVICE_ID_ADAPTEC_7871 0x7178 -#define PCI_DEVICE_ID_ADAPTEC_7872 0x7278 -#define PCI_DEVICE_ID_ADAPTEC_7873 0x7378 -#define PCI_DEVICE_ID_ADAPTEC_7874 0x7478 -#define PCI_DEVICE_ID_ADAPTEC_7895 0x7895 -#define PCI_DEVICE_ID_ADAPTEC_7880 0x8078 -#define PCI_DEVICE_ID_ADAPTEC_7881 0x8178 -#define PCI_DEVICE_ID_ADAPTEC_7882 0x8278 -#define PCI_DEVICE_ID_ADAPTEC_7883 0x8378 -#define PCI_DEVICE_ID_ADAPTEC_7884 0x8478 -#define PCI_DEVICE_ID_ADAPTEC_7885 0x8578 -#define PCI_DEVICE_ID_ADAPTEC_7886 0x8678 -#define PCI_DEVICE_ID_ADAPTEC_7887 0x8778 -#define PCI_DEVICE_ID_ADAPTEC_7888 0x8878 - -#define PCI_VENDOR_ID_ADAPTEC2 0x9005 -#define PCI_DEVICE_ID_ADAPTEC2_2940U2 0x0010 -#define PCI_DEVICE_ID_ADAPTEC2_2930U2 0x0011 -#define PCI_DEVICE_ID_ADAPTEC2_7890B 0x0013 -#define PCI_DEVICE_ID_ADAPTEC2_7890 0x001f -#define PCI_DEVICE_ID_ADAPTEC2_3940U2 0x0050 -#define PCI_DEVICE_ID_ADAPTEC2_3950U2D 0x0051 -#define PCI_DEVICE_ID_ADAPTEC2_7896 0x005f -#define PCI_DEVICE_ID_ADAPTEC2_7892A 0x0080 -#define PCI_DEVICE_ID_ADAPTEC2_7892B 0x0081 -#define PCI_DEVICE_ID_ADAPTEC2_7892D 0x0083 -#define PCI_DEVICE_ID_ADAPTEC2_7892P 0x008f -#define PCI_DEVICE_ID_ADAPTEC2_7899A 0x00c0 -#define PCI_DEVICE_ID_ADAPTEC2_7899B 0x00c1 -#define PCI_DEVICE_ID_ADAPTEC2_7899D 0x00c3 -#define PCI_DEVICE_ID_ADAPTEC2_7899P 0x00cf -#define PCI_DEVICE_ID_ADAPTEC2_OBSIDIAN 0x0500 -#define PCI_DEVICE_ID_ADAPTEC2_SCAMP 0x0503 - -#define PCI_VENDOR_ID_HOLTEK 0x9412 -#define PCI_DEVICE_ID_HOLTEK_6565 0x6565 - -#define PCI_VENDOR_ID_NETMOS 0x9710 -#define PCI_DEVICE_ID_NETMOS_9705 0x9705 -#define PCI_DEVICE_ID_NETMOS_9715 0x9715 -#define PCI_DEVICE_ID_NETMOS_9735 0x9735 -#define PCI_DEVICE_ID_NETMOS_9745 0x9745 -#define PCI_DEVICE_ID_NETMOS_9755 0x9755 -#define PCI_DEVICE_ID_NETMOS_9805 0x9805 -#define PCI_DEVICE_ID_NETMOS_9815 0x9815 -#define PCI_DEVICE_ID_NETMOS_9835 0x9835 -#define PCI_DEVICE_ID_NETMOS_9845 0x9845 -#define PCI_DEVICE_ID_NETMOS_9855 0x9855 -#define PCI_DEVICE_ID_NETMOS_9865 0x9865 -#define PCI_DEVICE_ID_NETMOS_9900 0x9900 -#define PCI_DEVICE_ID_NETMOS_9901 0x9901 -#define PCI_DEVICE_ID_NETMOS_9904 0x9904 -#define PCI_DEVICE_ID_NETMOS_9912 0x9912 -#define PCI_DEVICE_ID_NETMOS_9922 0x9922 - -#define PCI_VENDOR_ID_3COM_2 0xa727 - -#define PCI_VENDOR_ID_DIGIUM 0xd161 -#define PCI_DEVICE_ID_DIGIUM_HFC4S 0xb410 - -#define PCI_SUBVENDOR_ID_EXSYS 0xd84d -#define PCI_SUBDEVICE_ID_EXSYS_4014 0x4014 -#define PCI_SUBDEVICE_ID_EXSYS_4055 0x4055 - -#define PCI_VENDOR_ID_TIGERJET 0xe159 -#define PCI_DEVICE_ID_TIGERJET_300 0x0001 -#define PCI_DEVICE_ID_TIGERJET_100 0x0002 - -#define PCI_VENDOR_ID_XILINX_RME 0xea60 -#define PCI_DEVICE_ID_RME_DIGI32 0x9896 -#define PCI_DEVICE_ID_RME_DIGI32_PRO 0x9897 -#define PCI_DEVICE_ID_RME_DIGI32_8 0x9898 - -#define PCI_VENDOR_ID_XEN 0x5853 -#define PCI_DEVICE_ID_XEN_PLATFORM 0x0001 - -#define PCI_VENDOR_ID_OCZ 0x1b85 - -#endif /* _LINUX_PCI_IDS_H */ diff --git a/src/linux/include/linux/percpu-defs.h b/src/linux/include/linux/percpu-defs.h deleted file mode 100644 index 8f16299..0000000 --- a/src/linux/include/linux/percpu-defs.h +++ /dev/null @@ -1,514 +0,0 @@ -/* - * linux/percpu-defs.h - basic definitions for percpu areas - * - * DO NOT INCLUDE DIRECTLY OUTSIDE PERCPU IMPLEMENTATION PROPER. - * - * This file is separate from linux/percpu.h to avoid cyclic inclusion - * dependency from arch header files. Only to be included from - * asm/percpu.h. - * - * This file includes macros necessary to declare percpu sections and - * variables, and definitions of percpu accessors and operations. It - * should provide enough percpu features to arch header files even when - * they can only include asm/percpu.h to avoid cyclic inclusion dependency. - */ - -#ifndef _LINUX_PERCPU_DEFS_H -#define _LINUX_PERCPU_DEFS_H - -#ifdef CONFIG_SMP - -#ifdef MODULE -#define PER_CPU_SHARED_ALIGNED_SECTION "" -#define PER_CPU_ALIGNED_SECTION "" -#else -#define PER_CPU_SHARED_ALIGNED_SECTION "..shared_aligned" -#define PER_CPU_ALIGNED_SECTION "..shared_aligned" -#endif -#define PER_CPU_FIRST_SECTION "..first" - -#else - -#define PER_CPU_SHARED_ALIGNED_SECTION "" -#define PER_CPU_ALIGNED_SECTION "..shared_aligned" -#define PER_CPU_FIRST_SECTION "" - -#endif - -/* - * Base implementations of per-CPU variable declarations and definitions, where - * the section in which the variable is to be placed is provided by the - * 'sec' argument. This may be used to affect the parameters governing the - * variable's storage. - * - * NOTE! The sections for the DECLARE and for the DEFINE must match, lest - * linkage errors occur due the compiler generating the wrong code to access - * that section. - */ -#define __PCPU_ATTRS(sec) \ - __percpu __attribute__((section(PER_CPU_BASE_SECTION sec))) \ - PER_CPU_ATTRIBUTES - -#define __PCPU_DUMMY_ATTRS \ - __attribute__((section(".discard"), unused)) - -/* - * s390 and alpha modules require percpu variables to be defined as - * weak to force the compiler to generate GOT based external - * references for them. This is necessary because percpu sections - * will be located outside of the usually addressable area. - * - * This definition puts the following two extra restrictions when - * defining percpu variables. - * - * 1. The symbol must be globally unique, even the static ones. - * 2. Static percpu variables cannot be defined inside a function. - * - * Archs which need weak percpu definitions should define - * ARCH_NEEDS_WEAK_PER_CPU in asm/percpu.h when necessary. - * - * To ensure that the generic code observes the above two - * restrictions, if CONFIG_DEBUG_FORCE_WEAK_PER_CPU is set weak - * definition is used for all cases. - */ -#if defined(ARCH_NEEDS_WEAK_PER_CPU) || defined(CONFIG_DEBUG_FORCE_WEAK_PER_CPU) -/* - * __pcpu_scope_* dummy variable is used to enforce scope. It - * receives the static modifier when it's used in front of - * DEFINE_PER_CPU() and will trigger build failure if - * DECLARE_PER_CPU() is used for the same variable. - * - * __pcpu_unique_* dummy variable is used to enforce symbol uniqueness - * such that hidden weak symbol collision, which will cause unrelated - * variables to share the same address, can be detected during build. - */ -#define DECLARE_PER_CPU_SECTION(type, name, sec) \ - extern __PCPU_DUMMY_ATTRS char __pcpu_scope_##name; \ - extern __PCPU_ATTRS(sec) __typeof__(type) name - -#define DEFINE_PER_CPU_SECTION(type, name, sec) \ - __PCPU_DUMMY_ATTRS char __pcpu_scope_##name; \ - extern __PCPU_DUMMY_ATTRS char __pcpu_unique_##name; \ - __PCPU_DUMMY_ATTRS char __pcpu_unique_##name; \ - extern __PCPU_ATTRS(sec) __typeof__(type) name; \ - __PCPU_ATTRS(sec) PER_CPU_DEF_ATTRIBUTES __weak \ - __typeof__(type) name -#else -/* - * Normal declaration and definition macros. - */ -#define DECLARE_PER_CPU_SECTION(type, name, sec) \ - extern __PCPU_ATTRS(sec) __typeof__(type) name - -#define DEFINE_PER_CPU_SECTION(type, name, sec) \ - __PCPU_ATTRS(sec) PER_CPU_DEF_ATTRIBUTES \ - __typeof__(type) name -#endif - -/* - * Variant on the per-CPU variable declaration/definition theme used for - * ordinary per-CPU variables. - */ -#define DECLARE_PER_CPU(type, name) \ - DECLARE_PER_CPU_SECTION(type, name, "") - -#define DEFINE_PER_CPU(type, name) \ - DEFINE_PER_CPU_SECTION(type, name, "") - -/* - * Declaration/definition used for per-CPU variables that must come first in - * the set of variables. - */ -#define DECLARE_PER_CPU_FIRST(type, name) \ - DECLARE_PER_CPU_SECTION(type, name, PER_CPU_FIRST_SECTION) - -#define DEFINE_PER_CPU_FIRST(type, name) \ - DEFINE_PER_CPU_SECTION(type, name, PER_CPU_FIRST_SECTION) - -/* - * Declaration/definition used for per-CPU variables that must be cacheline - * aligned under SMP conditions so that, whilst a particular instance of the - * data corresponds to a particular CPU, inefficiencies due to direct access by - * other CPUs are reduced by preventing the data from unnecessarily spanning - * cachelines. - * - * An example of this would be statistical data, where each CPU's set of data - * is updated by that CPU alone, but the data from across all CPUs is collated - * by a CPU processing a read from a proc file. - */ -#define DECLARE_PER_CPU_SHARED_ALIGNED(type, name) \ - DECLARE_PER_CPU_SECTION(type, name, PER_CPU_SHARED_ALIGNED_SECTION) \ - ____cacheline_aligned_in_smp - -#define DEFINE_PER_CPU_SHARED_ALIGNED(type, name) \ - DEFINE_PER_CPU_SECTION(type, name, PER_CPU_SHARED_ALIGNED_SECTION) \ - ____cacheline_aligned_in_smp - -#define DECLARE_PER_CPU_ALIGNED(type, name) \ - DECLARE_PER_CPU_SECTION(type, name, PER_CPU_ALIGNED_SECTION) \ - ____cacheline_aligned - -#define DEFINE_PER_CPU_ALIGNED(type, name) \ - DEFINE_PER_CPU_SECTION(type, name, PER_CPU_ALIGNED_SECTION) \ - ____cacheline_aligned - -/* - * Declaration/definition used for per-CPU variables that must be page aligned. - */ -#define DECLARE_PER_CPU_PAGE_ALIGNED(type, name) \ - DECLARE_PER_CPU_SECTION(type, name, "..page_aligned") \ - __aligned(PAGE_SIZE) - -#define DEFINE_PER_CPU_PAGE_ALIGNED(type, name) \ - DEFINE_PER_CPU_SECTION(type, name, "..page_aligned") \ - __aligned(PAGE_SIZE) - -/* - * Declaration/definition used for per-CPU variables that must be read mostly. - */ -#define DECLARE_PER_CPU_READ_MOSTLY(type, name) \ - DECLARE_PER_CPU_SECTION(type, name, "..read_mostly") - -#define DEFINE_PER_CPU_READ_MOSTLY(type, name) \ - DEFINE_PER_CPU_SECTION(type, name, "..read_mostly") - -/* - * Intermodule exports for per-CPU variables. sparse forgets about - * address space across EXPORT_SYMBOL(), change EXPORT_SYMBOL() to - * noop if __CHECKER__. - */ -#ifndef __CHECKER__ -#define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(var) -#define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(var) -#else -#define EXPORT_PER_CPU_SYMBOL(var) -#define EXPORT_PER_CPU_SYMBOL_GPL(var) -#endif - -/* - * Accessors and operations. - */ -#ifndef __ASSEMBLY__ - -/* - * __verify_pcpu_ptr() verifies @ptr is a percpu pointer without evaluating - * @ptr and is invoked once before a percpu area is accessed by all - * accessors and operations. This is performed in the generic part of - * percpu and arch overrides don't need to worry about it; however, if an - * arch wants to implement an arch-specific percpu accessor or operation, - * it may use __verify_pcpu_ptr() to verify the parameters. - * - * + 0 is required in order to convert the pointer type from a - * potential array type to a pointer to a single item of the array. - */ -#define __verify_pcpu_ptr(ptr) \ -do { \ - const void __percpu *__vpp_verify = (typeof((ptr) + 0))NULL; \ - (void)__vpp_verify; \ -} while (0) - -#ifdef CONFIG_SMP - -/* - * Add an offset to a pointer but keep the pointer as-is. Use RELOC_HIDE() - * to prevent the compiler from making incorrect assumptions about the - * pointer value. The weird cast keeps both GCC and sparse happy. - */ -#define SHIFT_PERCPU_PTR(__p, __offset) \ - RELOC_HIDE((typeof(*(__p)) __kernel __force *)(__p), (__offset)) - -#define per_cpu_ptr(ptr, cpu) \ -({ \ - __verify_pcpu_ptr(ptr); \ - SHIFT_PERCPU_PTR((ptr), per_cpu_offset((cpu))); \ -}) - -#define raw_cpu_ptr(ptr) \ -({ \ - __verify_pcpu_ptr(ptr); \ - arch_raw_cpu_ptr(ptr); \ -}) - -#ifdef CONFIG_DEBUG_PREEMPT -#define this_cpu_ptr(ptr) \ -({ \ - __verify_pcpu_ptr(ptr); \ - SHIFT_PERCPU_PTR(ptr, my_cpu_offset); \ -}) -#else -#define this_cpu_ptr(ptr) raw_cpu_ptr(ptr) -#endif - -#else /* CONFIG_SMP */ - -#define VERIFY_PERCPU_PTR(__p) \ -({ \ - __verify_pcpu_ptr(__p); \ - (typeof(*(__p)) __kernel __force *)(__p); \ -}) - -#define per_cpu_ptr(ptr, cpu) ({ (void)(cpu); VERIFY_PERCPU_PTR(ptr); }) -#define raw_cpu_ptr(ptr) per_cpu_ptr(ptr, 0) -#define this_cpu_ptr(ptr) raw_cpu_ptr(ptr) - -#endif /* CONFIG_SMP */ - -#define per_cpu(var, cpu) (*per_cpu_ptr(&(var), cpu)) - -/* - * Must be an lvalue. Since @var must be a simple identifier, - * we force a syntax error here if it isn't. - */ -#define get_cpu_var(var) \ -(*({ \ - preempt_disable(); \ - this_cpu_ptr(&var); \ -})) - -/* - * The weird & is necessary because sparse considers (void)(var) to be - * a direct dereference of percpu variable (var). - */ -#define put_cpu_var(var) \ -do { \ - (void)&(var); \ - preempt_enable(); \ -} while (0) - -#define get_cpu_ptr(var) \ -({ \ - preempt_disable(); \ - this_cpu_ptr(var); \ -}) - -#define put_cpu_ptr(var) \ -do { \ - (void)(var); \ - preempt_enable(); \ -} while (0) - -/* - * Branching function to split up a function into a set of functions that - * are called for different scalar sizes of the objects handled. - */ - -extern void __bad_size_call_parameter(void); - -#ifdef CONFIG_DEBUG_PREEMPT -extern void __this_cpu_preempt_check(const char *op); -#else -static inline void __this_cpu_preempt_check(const char *op) { } -#endif - -#define __pcpu_size_call_return(stem, variable) \ -({ \ - typeof(variable) pscr_ret__; \ - __verify_pcpu_ptr(&(variable)); \ - switch(sizeof(variable)) { \ - case 1: pscr_ret__ = stem##1(variable); break; \ - case 2: pscr_ret__ = stem##2(variable); break; \ - case 4: pscr_ret__ = stem##4(variable); break; \ - case 8: pscr_ret__ = stem##8(variable); break; \ - default: \ - __bad_size_call_parameter(); break; \ - } \ - pscr_ret__; \ -}) - -#define __pcpu_size_call_return2(stem, variable, ...) \ -({ \ - typeof(variable) pscr2_ret__; \ - __verify_pcpu_ptr(&(variable)); \ - switch(sizeof(variable)) { \ - case 1: pscr2_ret__ = stem##1(variable, __VA_ARGS__); break; \ - case 2: pscr2_ret__ = stem##2(variable, __VA_ARGS__); break; \ - case 4: pscr2_ret__ = stem##4(variable, __VA_ARGS__); break; \ - case 8: pscr2_ret__ = stem##8(variable, __VA_ARGS__); break; \ - default: \ - __bad_size_call_parameter(); break; \ - } \ - pscr2_ret__; \ -}) - -/* - * Special handling for cmpxchg_double. cmpxchg_double is passed two - * percpu variables. The first has to be aligned to a double word - * boundary and the second has to follow directly thereafter. - * We enforce this on all architectures even if they don't support - * a double cmpxchg instruction, since it's a cheap requirement, and it - * avoids breaking the requirement for architectures with the instruction. - */ -#define __pcpu_double_call_return_bool(stem, pcp1, pcp2, ...) \ -({ \ - bool pdcrb_ret__; \ - __verify_pcpu_ptr(&(pcp1)); \ - BUILD_BUG_ON(sizeof(pcp1) != sizeof(pcp2)); \ - VM_BUG_ON((unsigned long)(&(pcp1)) % (2 * sizeof(pcp1))); \ - VM_BUG_ON((unsigned long)(&(pcp2)) != \ - (unsigned long)(&(pcp1)) + sizeof(pcp1)); \ - switch(sizeof(pcp1)) { \ - case 1: pdcrb_ret__ = stem##1(pcp1, pcp2, __VA_ARGS__); break; \ - case 2: pdcrb_ret__ = stem##2(pcp1, pcp2, __VA_ARGS__); break; \ - case 4: pdcrb_ret__ = stem##4(pcp1, pcp2, __VA_ARGS__); break; \ - case 8: pdcrb_ret__ = stem##8(pcp1, pcp2, __VA_ARGS__); break; \ - default: \ - __bad_size_call_parameter(); break; \ - } \ - pdcrb_ret__; \ -}) - -#define __pcpu_size_call(stem, variable, ...) \ -do { \ - __verify_pcpu_ptr(&(variable)); \ - switch(sizeof(variable)) { \ - case 1: stem##1(variable, __VA_ARGS__);break; \ - case 2: stem##2(variable, __VA_ARGS__);break; \ - case 4: stem##4(variable, __VA_ARGS__);break; \ - case 8: stem##8(variable, __VA_ARGS__);break; \ - default: \ - __bad_size_call_parameter();break; \ - } \ -} while (0) - -/* - * this_cpu operations (C) 2008-2013 Christoph Lameter - * - * Optimized manipulation for memory allocated through the per cpu - * allocator or for addresses of per cpu variables. - * - * These operation guarantee exclusivity of access for other operations - * on the *same* processor. The assumption is that per cpu data is only - * accessed by a single processor instance (the current one). - * - * The arch code can provide optimized implementation by defining macros - * for certain scalar sizes. F.e. provide this_cpu_add_2() to provide per - * cpu atomic operations for 2 byte sized RMW actions. If arch code does - * not provide operations for a scalar size then the fallback in the - * generic code will be used. - * - * cmpxchg_double replaces two adjacent scalars at once. The first two - * parameters are per cpu variables which have to be of the same size. A - * truth value is returned to indicate success or failure (since a double - * register result is difficult to handle). There is very limited hardware - * support for these operations, so only certain sizes may work. - */ - -/* - * Operations for contexts where we do not want to do any checks for - * preemptions. Unless strictly necessary, always use [__]this_cpu_*() - * instead. - * - * If there is no other protection through preempt disable and/or disabling - * interupts then one of these RMW operations can show unexpected behavior - * because the execution thread was rescheduled on another processor or an - * interrupt occurred and the same percpu variable was modified from the - * interrupt context. - */ -#define raw_cpu_read(pcp) __pcpu_size_call_return(raw_cpu_read_, pcp) -#define raw_cpu_write(pcp, val) __pcpu_size_call(raw_cpu_write_, pcp, val) -#define raw_cpu_add(pcp, val) __pcpu_size_call(raw_cpu_add_, pcp, val) -#define raw_cpu_and(pcp, val) __pcpu_size_call(raw_cpu_and_, pcp, val) -#define raw_cpu_or(pcp, val) __pcpu_size_call(raw_cpu_or_, pcp, val) -#define raw_cpu_add_return(pcp, val) __pcpu_size_call_return2(raw_cpu_add_return_, pcp, val) -#define raw_cpu_xchg(pcp, nval) __pcpu_size_call_return2(raw_cpu_xchg_, pcp, nval) -#define raw_cpu_cmpxchg(pcp, oval, nval) \ - __pcpu_size_call_return2(raw_cpu_cmpxchg_, pcp, oval, nval) -#define raw_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) \ - __pcpu_double_call_return_bool(raw_cpu_cmpxchg_double_, pcp1, pcp2, oval1, oval2, nval1, nval2) - -#define raw_cpu_sub(pcp, val) raw_cpu_add(pcp, -(val)) -#define raw_cpu_inc(pcp) raw_cpu_add(pcp, 1) -#define raw_cpu_dec(pcp) raw_cpu_sub(pcp, 1) -#define raw_cpu_sub_return(pcp, val) raw_cpu_add_return(pcp, -(typeof(pcp))(val)) -#define raw_cpu_inc_return(pcp) raw_cpu_add_return(pcp, 1) -#define raw_cpu_dec_return(pcp) raw_cpu_add_return(pcp, -1) - -/* - * Operations for contexts that are safe from preemption/interrupts. These - * operations verify that preemption is disabled. - */ -#define __this_cpu_read(pcp) \ -({ \ - __this_cpu_preempt_check("read"); \ - raw_cpu_read(pcp); \ -}) - -#define __this_cpu_write(pcp, val) \ -({ \ - __this_cpu_preempt_check("write"); \ - raw_cpu_write(pcp, val); \ -}) - -#define __this_cpu_add(pcp, val) \ -({ \ - __this_cpu_preempt_check("add"); \ - raw_cpu_add(pcp, val); \ -}) - -#define __this_cpu_and(pcp, val) \ -({ \ - __this_cpu_preempt_check("and"); \ - raw_cpu_and(pcp, val); \ -}) - -#define __this_cpu_or(pcp, val) \ -({ \ - __this_cpu_preempt_check("or"); \ - raw_cpu_or(pcp, val); \ -}) - -#define __this_cpu_add_return(pcp, val) \ -({ \ - __this_cpu_preempt_check("add_return"); \ - raw_cpu_add_return(pcp, val); \ -}) - -#define __this_cpu_xchg(pcp, nval) \ -({ \ - __this_cpu_preempt_check("xchg"); \ - raw_cpu_xchg(pcp, nval); \ -}) - -#define __this_cpu_cmpxchg(pcp, oval, nval) \ -({ \ - __this_cpu_preempt_check("cmpxchg"); \ - raw_cpu_cmpxchg(pcp, oval, nval); \ -}) - -#define __this_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) \ -({ __this_cpu_preempt_check("cmpxchg_double"); \ - raw_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2); \ -}) - -#define __this_cpu_sub(pcp, val) __this_cpu_add(pcp, -(typeof(pcp))(val)) -#define __this_cpu_inc(pcp) __this_cpu_add(pcp, 1) -#define __this_cpu_dec(pcp) __this_cpu_sub(pcp, 1) -#define __this_cpu_sub_return(pcp, val) __this_cpu_add_return(pcp, -(typeof(pcp))(val)) -#define __this_cpu_inc_return(pcp) __this_cpu_add_return(pcp, 1) -#define __this_cpu_dec_return(pcp) __this_cpu_add_return(pcp, -1) - -/* - * Operations with implied preemption/interrupt protection. These - * operations can be used without worrying about preemption or interrupt. - */ -#define this_cpu_read(pcp) __pcpu_size_call_return(this_cpu_read_, pcp) -#define this_cpu_write(pcp, val) __pcpu_size_call(this_cpu_write_, pcp, val) -#define this_cpu_add(pcp, val) __pcpu_size_call(this_cpu_add_, pcp, val) -#define this_cpu_and(pcp, val) __pcpu_size_call(this_cpu_and_, pcp, val) -#define this_cpu_or(pcp, val) __pcpu_size_call(this_cpu_or_, pcp, val) -#define this_cpu_add_return(pcp, val) __pcpu_size_call_return2(this_cpu_add_return_, pcp, val) -#define this_cpu_xchg(pcp, nval) __pcpu_size_call_return2(this_cpu_xchg_, pcp, nval) -#define this_cpu_cmpxchg(pcp, oval, nval) \ - __pcpu_size_call_return2(this_cpu_cmpxchg_, pcp, oval, nval) -#define this_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) \ - __pcpu_double_call_return_bool(this_cpu_cmpxchg_double_, pcp1, pcp2, oval1, oval2, nval1, nval2) - -#define this_cpu_sub(pcp, val) this_cpu_add(pcp, -(typeof(pcp))(val)) -#define this_cpu_inc(pcp) this_cpu_add(pcp, 1) -#define this_cpu_dec(pcp) this_cpu_sub(pcp, 1) -#define this_cpu_sub_return(pcp, val) this_cpu_add_return(pcp, -(typeof(pcp))(val)) -#define this_cpu_inc_return(pcp) this_cpu_add_return(pcp, 1) -#define this_cpu_dec_return(pcp) this_cpu_add_return(pcp, -1) - -#endif /* __ASSEMBLY__ */ -#endif /* _LINUX_PERCPU_DEFS_H */ diff --git a/src/linux/include/linux/percpu-refcount.h b/src/linux/include/linux/percpu-refcount.h deleted file mode 100644 index 1c7eec0..0000000 --- a/src/linux/include/linux/percpu-refcount.h +++ /dev/null @@ -1,326 +0,0 @@ -/* - * Percpu refcounts: - * (C) 2012 Google, Inc. - * Author: Kent Overstreet - * - * This implements a refcount with similar semantics to atomic_t - atomic_inc(), - * atomic_dec_and_test() - but percpu. - * - * There's one important difference between percpu refs and normal atomic_t - * refcounts; you have to keep track of your initial refcount, and then when you - * start shutting down you call percpu_ref_kill() _before_ dropping the initial - * refcount. - * - * The refcount will have a range of 0 to ((1U << 31) - 1), i.e. one bit less - * than an atomic_t - this is because of the way shutdown works, see - * percpu_ref_kill()/PERCPU_COUNT_BIAS. - * - * Before you call percpu_ref_kill(), percpu_ref_put() does not check for the - * refcount hitting 0 - it can't, if it was in percpu mode. percpu_ref_kill() - * puts the ref back in single atomic_t mode, collecting the per cpu refs and - * issuing the appropriate barriers, and then marks the ref as shutting down so - * that percpu_ref_put() will check for the ref hitting 0. After it returns, - * it's safe to drop the initial ref. - * - * USAGE: - * - * See fs/aio.c for some example usage; it's used there for struct kioctx, which - * is created when userspaces calls io_setup(), and destroyed when userspace - * calls io_destroy() or the process exits. - * - * In the aio code, kill_ioctx() is called when we wish to destroy a kioctx; it - * calls percpu_ref_kill(), then hlist_del_rcu() and synchronize_rcu() to remove - * the kioctx from the proccess's list of kioctxs - after that, there can't be - * any new users of the kioctx (from lookup_ioctx()) and it's then safe to drop - * the initial ref with percpu_ref_put(). - * - * Code that does a two stage shutdown like this often needs some kind of - * explicit synchronization to ensure the initial refcount can only be dropped - * once - percpu_ref_kill() does this for you, it returns true once and false if - * someone else already called it. The aio code uses it this way, but it's not - * necessary if the code has some other mechanism to synchronize teardown. - * around. - */ - -#ifndef _LINUX_PERCPU_REFCOUNT_H -#define _LINUX_PERCPU_REFCOUNT_H - -#include -#include -#include -#include -#include - -struct percpu_ref; -typedef void (percpu_ref_func_t)(struct percpu_ref *); - -/* flags set in the lower bits of percpu_ref->percpu_count_ptr */ -enum { - __PERCPU_REF_ATOMIC = 1LU << 0, /* operating in atomic mode */ - __PERCPU_REF_DEAD = 1LU << 1, /* (being) killed */ - __PERCPU_REF_ATOMIC_DEAD = __PERCPU_REF_ATOMIC | __PERCPU_REF_DEAD, - - __PERCPU_REF_FLAG_BITS = 2, -}; - -/* @flags for percpu_ref_init() */ -enum { - /* - * Start w/ ref == 1 in atomic mode. Can be switched to percpu - * operation using percpu_ref_switch_to_percpu(). If initialized - * with this flag, the ref will stay in atomic mode until - * percpu_ref_switch_to_percpu() is invoked on it. - */ - PERCPU_REF_INIT_ATOMIC = 1 << 0, - - /* - * Start dead w/ ref == 0 in atomic mode. Must be revived with - * percpu_ref_reinit() before used. Implies INIT_ATOMIC. - */ - PERCPU_REF_INIT_DEAD = 1 << 1, -}; - -struct percpu_ref { - atomic_long_t count; - /* - * The low bit of the pointer indicates whether the ref is in percpu - * mode; if set, then get/put will manipulate the atomic_t. - */ - unsigned long percpu_count_ptr; - percpu_ref_func_t *release; - percpu_ref_func_t *confirm_switch; - bool force_atomic:1; - struct rcu_head rcu; -}; - -int __must_check percpu_ref_init(struct percpu_ref *ref, - percpu_ref_func_t *release, unsigned int flags, - gfp_t gfp); -void percpu_ref_exit(struct percpu_ref *ref); -void percpu_ref_switch_to_atomic(struct percpu_ref *ref, - percpu_ref_func_t *confirm_switch); -void percpu_ref_switch_to_percpu(struct percpu_ref *ref); -void percpu_ref_kill_and_confirm(struct percpu_ref *ref, - percpu_ref_func_t *confirm_kill); -void percpu_ref_reinit(struct percpu_ref *ref); - -/** - * percpu_ref_kill - drop the initial ref - * @ref: percpu_ref to kill - * - * Must be used to drop the initial ref on a percpu refcount; must be called - * precisely once before shutdown. - * - * Puts @ref in non percpu mode, then does a call_rcu() before gathering up the - * percpu counters and dropping the initial ref. - */ -static inline void percpu_ref_kill(struct percpu_ref *ref) -{ - percpu_ref_kill_and_confirm(ref, NULL); -} - -/* - * Internal helper. Don't use outside percpu-refcount proper. The - * function doesn't return the pointer and let the caller test it for NULL - * because doing so forces the compiler to generate two conditional - * branches as it can't assume that @ref->percpu_count is not NULL. - */ -static inline bool __ref_is_percpu(struct percpu_ref *ref, - unsigned long __percpu **percpu_countp) -{ - unsigned long percpu_ptr; - - /* - * The value of @ref->percpu_count_ptr is tested for - * !__PERCPU_REF_ATOMIC, which may be set asynchronously, and then - * used as a pointer. If the compiler generates a separate fetch - * when using it as a pointer, __PERCPU_REF_ATOMIC may be set in - * between contaminating the pointer value, meaning that - * READ_ONCE() is required when fetching it. - */ - percpu_ptr = READ_ONCE(ref->percpu_count_ptr); - - /* paired with smp_store_release() in __percpu_ref_switch_to_percpu() */ - smp_read_barrier_depends(); - - /* - * Theoretically, the following could test just ATOMIC; however, - * then we'd have to mask off DEAD separately as DEAD may be - * visible without ATOMIC if we race with percpu_ref_kill(). DEAD - * implies ATOMIC anyway. Test them together. - */ - if (unlikely(percpu_ptr & __PERCPU_REF_ATOMIC_DEAD)) - return false; - - *percpu_countp = (unsigned long __percpu *)percpu_ptr; - return true; -} - -/** - * percpu_ref_get_many - increment a percpu refcount - * @ref: percpu_ref to get - * @nr: number of references to get - * - * Analogous to atomic_long_add(). - * - * This function is safe to call as long as @ref is between init and exit. - */ -static inline void percpu_ref_get_many(struct percpu_ref *ref, unsigned long nr) -{ - unsigned long __percpu *percpu_count; - - rcu_read_lock_sched(); - - if (__ref_is_percpu(ref, &percpu_count)) - this_cpu_add(*percpu_count, nr); - else - atomic_long_add(nr, &ref->count); - - rcu_read_unlock_sched(); -} - -/** - * percpu_ref_get - increment a percpu refcount - * @ref: percpu_ref to get - * - * Analagous to atomic_long_inc(). - * - * This function is safe to call as long as @ref is between init and exit. - */ -static inline void percpu_ref_get(struct percpu_ref *ref) -{ - percpu_ref_get_many(ref, 1); -} - -/** - * percpu_ref_tryget - try to increment a percpu refcount - * @ref: percpu_ref to try-get - * - * Increment a percpu refcount unless its count already reached zero. - * Returns %true on success; %false on failure. - * - * This function is safe to call as long as @ref is between init and exit. - */ -static inline bool percpu_ref_tryget(struct percpu_ref *ref) -{ - unsigned long __percpu *percpu_count; - int ret; - - rcu_read_lock_sched(); - - if (__ref_is_percpu(ref, &percpu_count)) { - this_cpu_inc(*percpu_count); - ret = true; - } else { - ret = atomic_long_inc_not_zero(&ref->count); - } - - rcu_read_unlock_sched(); - - return ret; -} - -/** - * percpu_ref_tryget_live - try to increment a live percpu refcount - * @ref: percpu_ref to try-get - * - * Increment a percpu refcount unless it has already been killed. Returns - * %true on success; %false on failure. - * - * Completion of percpu_ref_kill() in itself doesn't guarantee that this - * function will fail. For such guarantee, percpu_ref_kill_and_confirm() - * should be used. After the confirm_kill callback is invoked, it's - * guaranteed that no new reference will be given out by - * percpu_ref_tryget_live(). - * - * This function is safe to call as long as @ref is between init and exit. - */ -static inline bool percpu_ref_tryget_live(struct percpu_ref *ref) -{ - unsigned long __percpu *percpu_count; - int ret = false; - - rcu_read_lock_sched(); - - if (__ref_is_percpu(ref, &percpu_count)) { - this_cpu_inc(*percpu_count); - ret = true; - } else if (!(ref->percpu_count_ptr & __PERCPU_REF_DEAD)) { - ret = atomic_long_inc_not_zero(&ref->count); - } - - rcu_read_unlock_sched(); - - return ret; -} - -/** - * percpu_ref_put_many - decrement a percpu refcount - * @ref: percpu_ref to put - * @nr: number of references to put - * - * Decrement the refcount, and if 0, call the release function (which was passed - * to percpu_ref_init()) - * - * This function is safe to call as long as @ref is between init and exit. - */ -static inline void percpu_ref_put_many(struct percpu_ref *ref, unsigned long nr) -{ - unsigned long __percpu *percpu_count; - - rcu_read_lock_sched(); - - if (__ref_is_percpu(ref, &percpu_count)) - this_cpu_sub(*percpu_count, nr); - else if (unlikely(atomic_long_sub_and_test(nr, &ref->count))) - ref->release(ref); - - rcu_read_unlock_sched(); -} - -/** - * percpu_ref_put - decrement a percpu refcount - * @ref: percpu_ref to put - * - * Decrement the refcount, and if 0, call the release function (which was passed - * to percpu_ref_init()) - * - * This function is safe to call as long as @ref is between init and exit. - */ -static inline void percpu_ref_put(struct percpu_ref *ref) -{ - percpu_ref_put_many(ref, 1); -} - -/** - * percpu_ref_is_dying - test whether a percpu refcount is dying or dead - * @ref: percpu_ref to test - * - * Returns %true if @ref is dying or dead. - * - * This function is safe to call as long as @ref is between init and exit - * and the caller is responsible for synchronizing against state changes. - */ -static inline bool percpu_ref_is_dying(struct percpu_ref *ref) -{ - return ref->percpu_count_ptr & __PERCPU_REF_DEAD; -} - -/** - * percpu_ref_is_zero - test whether a percpu refcount reached zero - * @ref: percpu_ref to test - * - * Returns %true if @ref reached zero. - * - * This function is safe to call as long as @ref is between init and exit. - */ -static inline bool percpu_ref_is_zero(struct percpu_ref *ref) -{ - unsigned long __percpu *percpu_count; - - if (__ref_is_percpu(ref, &percpu_count)) - return false; - return !atomic_long_read(&ref->count); -} - -#endif diff --git a/src/linux/include/linux/percpu-rwsem.h b/src/linux/include/linux/percpu-rwsem.h deleted file mode 100644 index 5b2e615..0000000 --- a/src/linux/include/linux/percpu-rwsem.h +++ /dev/null @@ -1,145 +0,0 @@ -#ifndef _LINUX_PERCPU_RWSEM_H -#define _LINUX_PERCPU_RWSEM_H - -#include -#include -#include -#include -#include -#include - -struct percpu_rw_semaphore { - struct rcu_sync rss; - unsigned int __percpu *read_count; - struct rw_semaphore rw_sem; - wait_queue_head_t writer; - int readers_block; -}; - -#define DEFINE_STATIC_PERCPU_RWSEM(name) \ -static DEFINE_PER_CPU(unsigned int, __percpu_rwsem_rc_##name); \ -static struct percpu_rw_semaphore name = { \ - .rss = __RCU_SYNC_INITIALIZER(name.rss, RCU_SCHED_SYNC), \ - .read_count = &__percpu_rwsem_rc_##name, \ - .rw_sem = __RWSEM_INITIALIZER(name.rw_sem), \ - .writer = __WAIT_QUEUE_HEAD_INITIALIZER(name.writer), \ -} - -extern int __percpu_down_read(struct percpu_rw_semaphore *, int); -extern void __percpu_up_read(struct percpu_rw_semaphore *); - -static inline void percpu_down_read_preempt_disable(struct percpu_rw_semaphore *sem) -{ - might_sleep(); - - rwsem_acquire_read(&sem->rw_sem.dep_map, 0, 0, _RET_IP_); - - preempt_disable(); - /* - * We are in an RCU-sched read-side critical section, so the writer - * cannot both change sem->state from readers_fast and start checking - * counters while we are here. So if we see !sem->state, we know that - * the writer won't be checking until we're past the preempt_enable() - * and that one the synchronize_sched() is done, the writer will see - * anything we did within this RCU-sched read-size critical section. - */ - __this_cpu_inc(*sem->read_count); - if (unlikely(!rcu_sync_is_idle(&sem->rss))) - __percpu_down_read(sem, false); /* Unconditional memory barrier */ - barrier(); - /* - * The barrier() prevents the compiler from - * bleeding the critical section out. - */ -} - -static inline void percpu_down_read(struct percpu_rw_semaphore *sem) -{ - percpu_down_read_preempt_disable(sem); - preempt_enable(); -} - -static inline int percpu_down_read_trylock(struct percpu_rw_semaphore *sem) -{ - int ret = 1; - - preempt_disable(); - /* - * Same as in percpu_down_read(). - */ - __this_cpu_inc(*sem->read_count); - if (unlikely(!rcu_sync_is_idle(&sem->rss))) - ret = __percpu_down_read(sem, true); /* Unconditional memory barrier */ - preempt_enable(); - /* - * The barrier() from preempt_enable() prevents the compiler from - * bleeding the critical section out. - */ - - if (ret) - rwsem_acquire_read(&sem->rw_sem.dep_map, 0, 1, _RET_IP_); - - return ret; -} - -static inline void percpu_up_read_preempt_enable(struct percpu_rw_semaphore *sem) -{ - /* - * The barrier() prevents the compiler from - * bleeding the critical section out. - */ - barrier(); - /* - * Same as in percpu_down_read(). - */ - if (likely(rcu_sync_is_idle(&sem->rss))) - __this_cpu_dec(*sem->read_count); - else - __percpu_up_read(sem); /* Unconditional memory barrier */ - preempt_enable(); - - rwsem_release(&sem->rw_sem.dep_map, 1, _RET_IP_); -} - -static inline void percpu_up_read(struct percpu_rw_semaphore *sem) -{ - preempt_disable(); - percpu_up_read_preempt_enable(sem); -} - -extern void percpu_down_write(struct percpu_rw_semaphore *); -extern void percpu_up_write(struct percpu_rw_semaphore *); - -extern int __percpu_init_rwsem(struct percpu_rw_semaphore *, - const char *, struct lock_class_key *); - -extern void percpu_free_rwsem(struct percpu_rw_semaphore *); - -#define percpu_init_rwsem(sem) \ -({ \ - static struct lock_class_key rwsem_key; \ - __percpu_init_rwsem(sem, #sem, &rwsem_key); \ -}) - -#define percpu_rwsem_is_held(sem) lockdep_is_held(&(sem)->rw_sem) - -#define percpu_rwsem_assert_held(sem) \ - lockdep_assert_held(&(sem)->rw_sem) - -static inline void percpu_rwsem_release(struct percpu_rw_semaphore *sem, - bool read, unsigned long ip) -{ - lock_release(&sem->rw_sem.dep_map, 1, ip); -#ifdef CONFIG_RWSEM_SPIN_ON_OWNER - if (!read) - sem->rw_sem.owner = NULL; -#endif -} - -static inline void percpu_rwsem_acquire(struct percpu_rw_semaphore *sem, - bool read, unsigned long ip) -{ - lock_acquire(&sem->rw_sem.dep_map, 0, 1, read, 1, NULL, ip); -} - -#endif diff --git a/src/linux/include/linux/percpu.h b/src/linux/include/linux/percpu.h deleted file mode 100644 index 56939d3..0000000 --- a/src/linux/include/linux/percpu.h +++ /dev/null @@ -1,132 +0,0 @@ -#ifndef __LINUX_PERCPU_H -#define __LINUX_PERCPU_H - -#include -#include -#include -#include -#include -#include -#include - -#include - -/* enough to cover all DEFINE_PER_CPUs in modules */ -#ifdef CONFIG_MODULES -#define PERCPU_MODULE_RESERVE (8 << 10) -#else -#define PERCPU_MODULE_RESERVE 0 -#endif - -/* minimum unit size, also is the maximum supported allocation size */ -#define PCPU_MIN_UNIT_SIZE PFN_ALIGN(32 << 10) - -/* - * Percpu allocator can serve percpu allocations before slab is - * initialized which allows slab to depend on the percpu allocator. - * The following two parameters decide how much resource to - * preallocate for this. Keep PERCPU_DYNAMIC_RESERVE equal to or - * larger than PERCPU_DYNAMIC_EARLY_SIZE. - */ -#define PERCPU_DYNAMIC_EARLY_SLOTS 128 -#define PERCPU_DYNAMIC_EARLY_SIZE (12 << 10) - -/* - * PERCPU_DYNAMIC_RESERVE indicates the amount of free area to piggy - * back on the first chunk for dynamic percpu allocation if arch is - * manually allocating and mapping it for faster access (as a part of - * large page mapping for example). - * - * The following values give between one and two pages of free space - * after typical minimal boot (2-way SMP, single disk and NIC) with - * both defconfig and a distro config on x86_64 and 32. More - * intelligent way to determine this would be nice. - */ -#if BITS_PER_LONG > 32 -#define PERCPU_DYNAMIC_RESERVE (28 << 10) -#else -#define PERCPU_DYNAMIC_RESERVE (20 << 10) -#endif - -extern void *pcpu_base_addr; -extern const unsigned long *pcpu_unit_offsets; - -struct pcpu_group_info { - int nr_units; /* aligned # of units */ - unsigned long base_offset; /* base address offset */ - unsigned int *cpu_map; /* unit->cpu map, empty - * entries contain NR_CPUS */ -}; - -struct pcpu_alloc_info { - size_t static_size; - size_t reserved_size; - size_t dyn_size; - size_t unit_size; - size_t atom_size; - size_t alloc_size; - size_t __ai_size; /* internal, don't use */ - int nr_groups; /* 0 if grouping unnecessary */ - struct pcpu_group_info groups[]; -}; - -enum pcpu_fc { - PCPU_FC_AUTO, - PCPU_FC_EMBED, - PCPU_FC_PAGE, - - PCPU_FC_NR, -}; -extern const char * const pcpu_fc_names[PCPU_FC_NR]; - -extern enum pcpu_fc pcpu_chosen_fc; - -typedef void * (*pcpu_fc_alloc_fn_t)(unsigned int cpu, size_t size, - size_t align); -typedef void (*pcpu_fc_free_fn_t)(void *ptr, size_t size); -typedef void (*pcpu_fc_populate_pte_fn_t)(unsigned long addr); -typedef int (pcpu_fc_cpu_distance_fn_t)(unsigned int from, unsigned int to); - -extern struct pcpu_alloc_info * __init pcpu_alloc_alloc_info(int nr_groups, - int nr_units); -extern void __init pcpu_free_alloc_info(struct pcpu_alloc_info *ai); - -extern int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai, - void *base_addr); - -#ifdef CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK -extern int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size, - size_t atom_size, - pcpu_fc_cpu_distance_fn_t cpu_distance_fn, - pcpu_fc_alloc_fn_t alloc_fn, - pcpu_fc_free_fn_t free_fn); -#endif - -#ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK -extern int __init pcpu_page_first_chunk(size_t reserved_size, - pcpu_fc_alloc_fn_t alloc_fn, - pcpu_fc_free_fn_t free_fn, - pcpu_fc_populate_pte_fn_t populate_pte_fn); -#endif - -extern void __percpu *__alloc_reserved_percpu(size_t size, size_t align); -extern bool is_kernel_percpu_address(unsigned long addr); - -#if !defined(CONFIG_SMP) || !defined(CONFIG_HAVE_SETUP_PER_CPU_AREA) -extern void __init setup_per_cpu_areas(void); -#endif -extern void __init percpu_init_late(void); - -extern void __percpu *__alloc_percpu_gfp(size_t size, size_t align, gfp_t gfp); -extern void __percpu *__alloc_percpu(size_t size, size_t align); -extern void free_percpu(void __percpu *__pdata); -extern phys_addr_t per_cpu_ptr_to_phys(void *addr); - -#define alloc_percpu_gfp(type, gfp) \ - (typeof(type) __percpu *)__alloc_percpu_gfp(sizeof(type), \ - __alignof__(type), gfp) -#define alloc_percpu(type) \ - (typeof(type) __percpu *)__alloc_percpu(sizeof(type), \ - __alignof__(type)) - -#endif /* __LINUX_PERCPU_H */ diff --git a/src/linux/include/linux/percpu_counter.h b/src/linux/include/linux/percpu_counter.h deleted file mode 100644 index 84a1094..0000000 --- a/src/linux/include/linux/percpu_counter.h +++ /dev/null @@ -1,190 +0,0 @@ -#ifndef _LINUX_PERCPU_COUNTER_H -#define _LINUX_PERCPU_COUNTER_H -/* - * A simple "approximate counter" for use in ext2 and ext3 superblocks. - * - * WARNING: these things are HUGE. 4 kbytes per counter on 32-way P4. - */ - -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_SMP - -struct percpu_counter { - raw_spinlock_t lock; - s64 count; -#ifdef CONFIG_HOTPLUG_CPU - struct list_head list; /* All percpu_counters are on a list */ -#endif - s32 __percpu *counters; -}; - -extern int percpu_counter_batch; - -int __percpu_counter_init(struct percpu_counter *fbc, s64 amount, gfp_t gfp, - struct lock_class_key *key); - -#define percpu_counter_init(fbc, value, gfp) \ - ({ \ - static struct lock_class_key __key; \ - \ - __percpu_counter_init(fbc, value, gfp, &__key); \ - }) - -void percpu_counter_destroy(struct percpu_counter *fbc); -void percpu_counter_set(struct percpu_counter *fbc, s64 amount); -void __percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch); -s64 __percpu_counter_sum(struct percpu_counter *fbc); -int __percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch); - -static inline int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs) -{ - return __percpu_counter_compare(fbc, rhs, percpu_counter_batch); -} - -static inline void percpu_counter_add(struct percpu_counter *fbc, s64 amount) -{ - __percpu_counter_add(fbc, amount, percpu_counter_batch); -} - -static inline s64 percpu_counter_sum_positive(struct percpu_counter *fbc) -{ - s64 ret = __percpu_counter_sum(fbc); - return ret < 0 ? 0 : ret; -} - -static inline s64 percpu_counter_sum(struct percpu_counter *fbc) -{ - return __percpu_counter_sum(fbc); -} - -static inline s64 percpu_counter_read(struct percpu_counter *fbc) -{ - return fbc->count; -} - -/* - * It is possible for the percpu_counter_read() to return a small negative - * number for some counter which should never be negative. - * - */ -static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc) -{ - s64 ret = fbc->count; - - barrier(); /* Prevent reloads of fbc->count */ - if (ret >= 0) - return ret; - return 0; -} - -static inline int percpu_counter_initialized(struct percpu_counter *fbc) -{ - return (fbc->counters != NULL); -} - -#else /* !CONFIG_SMP */ - -struct percpu_counter { - s64 count; -}; - -static inline int percpu_counter_init(struct percpu_counter *fbc, s64 amount, - gfp_t gfp) -{ - fbc->count = amount; - return 0; -} - -static inline void percpu_counter_destroy(struct percpu_counter *fbc) -{ -} - -static inline void percpu_counter_set(struct percpu_counter *fbc, s64 amount) -{ - fbc->count = amount; -} - -static inline int percpu_counter_compare(struct percpu_counter *fbc, s64 rhs) -{ - if (fbc->count > rhs) - return 1; - else if (fbc->count < rhs) - return -1; - else - return 0; -} - -static inline int -__percpu_counter_compare(struct percpu_counter *fbc, s64 rhs, s32 batch) -{ - return percpu_counter_compare(fbc, rhs); -} - -static inline void -percpu_counter_add(struct percpu_counter *fbc, s64 amount) -{ - preempt_disable(); - fbc->count += amount; - preempt_enable(); -} - -static inline void -__percpu_counter_add(struct percpu_counter *fbc, s64 amount, s32 batch) -{ - percpu_counter_add(fbc, amount); -} - -static inline s64 percpu_counter_read(struct percpu_counter *fbc) -{ - return fbc->count; -} - -/* - * percpu_counter is intended to track positive numbers. In the UP case the - * number should never be negative. - */ -static inline s64 percpu_counter_read_positive(struct percpu_counter *fbc) -{ - return fbc->count; -} - -static inline s64 percpu_counter_sum_positive(struct percpu_counter *fbc) -{ - return percpu_counter_read_positive(fbc); -} - -static inline s64 percpu_counter_sum(struct percpu_counter *fbc) -{ - return percpu_counter_read(fbc); -} - -static inline int percpu_counter_initialized(struct percpu_counter *fbc) -{ - return 1; -} - -#endif /* CONFIG_SMP */ - -static inline void percpu_counter_inc(struct percpu_counter *fbc) -{ - percpu_counter_add(fbc, 1); -} - -static inline void percpu_counter_dec(struct percpu_counter *fbc) -{ - percpu_counter_add(fbc, -1); -} - -static inline void percpu_counter_sub(struct percpu_counter *fbc, s64 amount) -{ - percpu_counter_add(fbc, -amount); -} - -#endif /* _LINUX_PERCPU_COUNTER_H */ diff --git a/src/linux/include/linux/percpu_ida.h b/src/linux/include/linux/percpu_ida.h deleted file mode 100644 index f5cfdd6..0000000 --- a/src/linux/include/linux/percpu_ida.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef __PERCPU_IDA_H__ -#define __PERCPU_IDA_H__ - -#include -#include -#include -#include -#include -#include -#include - -struct percpu_ida_cpu; - -struct percpu_ida { - /* - * number of tags available to be allocated, as passed to - * percpu_ida_init() - */ - unsigned nr_tags; - unsigned percpu_max_size; - unsigned percpu_batch_size; - - struct percpu_ida_cpu __percpu *tag_cpu; - - /* - * Bitmap of cpus that (may) have tags on their percpu freelists: - * steal_tags() uses this to decide when to steal tags, and which cpus - * to try stealing from. - * - * It's ok for a freelist to be empty when its bit is set - steal_tags() - * will just keep looking - but the bitmap _must_ be set whenever a - * percpu freelist does have tags. - */ - cpumask_t cpus_have_tags; - - struct { - spinlock_t lock; - /* - * When we go to steal tags from another cpu (see steal_tags()), - * we want to pick a cpu at random. Cycling through them every - * time we steal is a bit easier and more or less equivalent: - */ - unsigned cpu_last_stolen; - - /* For sleeping on allocation failure */ - wait_queue_head_t wait; - - /* - * Global freelist - it's a stack where nr_free points to the - * top - */ - unsigned nr_free; - unsigned *freelist; - } ____cacheline_aligned_in_smp; -}; - -/* - * Number of tags we move between the percpu freelist and the global freelist at - * a time - */ -#define IDA_DEFAULT_PCPU_BATCH_MOVE 32U -/* Max size of percpu freelist, */ -#define IDA_DEFAULT_PCPU_SIZE ((IDA_DEFAULT_PCPU_BATCH_MOVE * 3) / 2) - -int percpu_ida_alloc(struct percpu_ida *pool, int state); -void percpu_ida_free(struct percpu_ida *pool, unsigned tag); - -void percpu_ida_destroy(struct percpu_ida *pool); -int __percpu_ida_init(struct percpu_ida *pool, unsigned long nr_tags, - unsigned long max_size, unsigned long batch_size); -static inline int percpu_ida_init(struct percpu_ida *pool, unsigned long nr_tags) -{ - return __percpu_ida_init(pool, nr_tags, IDA_DEFAULT_PCPU_SIZE, - IDA_DEFAULT_PCPU_BATCH_MOVE); -} - -typedef int (*percpu_ida_cb)(unsigned, void *); -int percpu_ida_for_each_free(struct percpu_ida *pool, percpu_ida_cb fn, - void *data); - -unsigned percpu_ida_free_tags(struct percpu_ida *pool, int cpu); -#endif /* __PERCPU_IDA_H__ */ diff --git a/src/linux/include/linux/perf_event.h b/src/linux/include/linux/perf_event.h deleted file mode 100644 index 4741ecd..0000000 --- a/src/linux/include/linux/perf_event.h +++ /dev/null @@ -1,1390 +0,0 @@ -/* - * Performance events: - * - * Copyright (C) 2008-2009, Thomas Gleixner - * Copyright (C) 2008-2011, Red Hat, Inc., Ingo Molnar - * Copyright (C) 2008-2011, Red Hat, Inc., Peter Zijlstra - * - * Data type definitions, declarations, prototypes. - * - * Started by: Thomas Gleixner and Ingo Molnar - * - * For licencing details see kernel-base/COPYING - */ -#ifndef _LINUX_PERF_EVENT_H -#define _LINUX_PERF_EVENT_H - -#include - -/* - * Kernel-internal data types and definitions: - */ - -#ifdef CONFIG_PERF_EVENTS -# include -# include -#endif - -struct perf_guest_info_callbacks { - int (*is_in_guest)(void); - int (*is_user_mode)(void); - unsigned long (*get_guest_ip)(void); -}; - -#ifdef CONFIG_HAVE_HW_BREAKPOINT -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct perf_callchain_entry { - __u64 nr; - __u64 ip[0]; /* /proc/sys/kernel/perf_event_max_stack */ -}; - -struct perf_callchain_entry_ctx { - struct perf_callchain_entry *entry; - u32 max_stack; - u32 nr; - short contexts; - bool contexts_maxed; -}; - -typedef unsigned long (*perf_copy_f)(void *dst, const void *src, - unsigned long off, unsigned long len); - -struct perf_raw_frag { - union { - struct perf_raw_frag *next; - unsigned long pad; - }; - perf_copy_f copy; - void *data; - u32 size; -} __packed; - -struct perf_raw_record { - struct perf_raw_frag frag; - u32 size; -}; - -/* - * branch stack layout: - * nr: number of taken branches stored in entries[] - * - * Note that nr can vary from sample to sample - * branches (to, from) are stored from most recent - * to least recent, i.e., entries[0] contains the most - * recent branch. - */ -struct perf_branch_stack { - __u64 nr; - struct perf_branch_entry entries[0]; -}; - -struct task_struct; - -/* - * extra PMU register associated with an event - */ -struct hw_perf_event_extra { - u64 config; /* register value */ - unsigned int reg; /* register address or index */ - int alloc; /* extra register already allocated */ - int idx; /* index in shared_regs->regs[] */ -}; - -/** - * struct hw_perf_event - performance event hardware details: - */ -struct hw_perf_event { -#ifdef CONFIG_PERF_EVENTS - union { - struct { /* hardware */ - u64 config; - u64 last_tag; - unsigned long config_base; - unsigned long event_base; - int event_base_rdpmc; - int idx; - int last_cpu; - int flags; - - struct hw_perf_event_extra extra_reg; - struct hw_perf_event_extra branch_reg; - }; - struct { /* software */ - struct hrtimer hrtimer; - }; - struct { /* tracepoint */ - /* for tp_event->class */ - struct list_head tp_list; - }; - struct { /* intel_cqm */ - int cqm_state; - u32 cqm_rmid; - int is_group_event; - struct list_head cqm_events_entry; - struct list_head cqm_groups_entry; - struct list_head cqm_group_entry; - }; - struct { /* itrace */ - int itrace_started; - }; - struct { /* amd_power */ - u64 pwr_acc; - u64 ptsc; - }; -#ifdef CONFIG_HAVE_HW_BREAKPOINT - struct { /* breakpoint */ - /* - * Crufty hack to avoid the chicken and egg - * problem hw_breakpoint has with context - * creation and event initalization. - */ - struct arch_hw_breakpoint info; - struct list_head bp_list; - }; -#endif - }; - /* - * If the event is a per task event, this will point to the task in - * question. See the comment in perf_event_alloc(). - */ - struct task_struct *target; - - /* - * PMU would store hardware filter configuration - * here. - */ - void *addr_filters; - - /* Last sync'ed generation of filters */ - unsigned long addr_filters_gen; - -/* - * hw_perf_event::state flags; used to track the PERF_EF_* state. - */ -#define PERF_HES_STOPPED 0x01 /* the counter is stopped */ -#define PERF_HES_UPTODATE 0x02 /* event->count up-to-date */ -#define PERF_HES_ARCH 0x04 - - int state; - - /* - * The last observed hardware counter value, updated with a - * local64_cmpxchg() such that pmu::read() can be called nested. - */ - local64_t prev_count; - - /* - * The period to start the next sample with. - */ - u64 sample_period; - - /* - * The period we started this sample with. - */ - u64 last_period; - - /* - * However much is left of the current period; note that this is - * a full 64bit value and allows for generation of periods longer - * than hardware might allow. - */ - local64_t period_left; - - /* - * State for throttling the event, see __perf_event_overflow() and - * perf_adjust_freq_unthr_context(). - */ - u64 interrupts_seq; - u64 interrupts; - - /* - * State for freq target events, see __perf_event_overflow() and - * perf_adjust_freq_unthr_context(). - */ - u64 freq_time_stamp; - u64 freq_count_stamp; -#endif -}; - -struct perf_event; - -/* - * Common implementation detail of pmu::{start,commit,cancel}_txn - */ -#define PERF_PMU_TXN_ADD 0x1 /* txn to add/schedule event on PMU */ -#define PERF_PMU_TXN_READ 0x2 /* txn to read event group from PMU */ - -/** - * pmu::capabilities flags - */ -#define PERF_PMU_CAP_NO_INTERRUPT 0x01 -#define PERF_PMU_CAP_NO_NMI 0x02 -#define PERF_PMU_CAP_AUX_NO_SG 0x04 -#define PERF_PMU_CAP_AUX_SW_DOUBLEBUF 0x08 -#define PERF_PMU_CAP_EXCLUSIVE 0x10 -#define PERF_PMU_CAP_ITRACE 0x20 -#define PERF_PMU_CAP_HETEROGENEOUS_CPUS 0x40 - -/** - * struct pmu - generic performance monitoring unit - */ -struct pmu { - struct list_head entry; - - struct module *module; - struct device *dev; - const struct attribute_group **attr_groups; - const char *name; - int type; - - /* - * various common per-pmu feature flags - */ - int capabilities; - - int * __percpu pmu_disable_count; - struct perf_cpu_context * __percpu pmu_cpu_context; - atomic_t exclusive_cnt; /* < 0: cpu; > 0: tsk */ - int task_ctx_nr; - int hrtimer_interval_ms; - - /* number of address filters this PMU can do */ - unsigned int nr_addr_filters; - - /* - * Fully disable/enable this PMU, can be used to protect from the PMI - * as well as for lazy/batch writing of the MSRs. - */ - void (*pmu_enable) (struct pmu *pmu); /* optional */ - void (*pmu_disable) (struct pmu *pmu); /* optional */ - - /* - * Try and initialize the event for this PMU. - * - * Returns: - * -ENOENT -- @event is not for this PMU - * - * -ENODEV -- @event is for this PMU but PMU not present - * -EBUSY -- @event is for this PMU but PMU temporarily unavailable - * -EINVAL -- @event is for this PMU but @event is not valid - * -EOPNOTSUPP -- @event is for this PMU, @event is valid, but not supported - * -EACCESS -- @event is for this PMU, @event is valid, but no privilidges - * - * 0 -- @event is for this PMU and valid - * - * Other error return values are allowed. - */ - int (*event_init) (struct perf_event *event); - - /* - * Notification that the event was mapped or unmapped. Called - * in the context of the mapping task. - */ - void (*event_mapped) (struct perf_event *event); /*optional*/ - void (*event_unmapped) (struct perf_event *event); /*optional*/ - - /* - * Flags for ->add()/->del()/ ->start()/->stop(). There are - * matching hw_perf_event::state flags. - */ -#define PERF_EF_START 0x01 /* start the counter when adding */ -#define PERF_EF_RELOAD 0x02 /* reload the counter when starting */ -#define PERF_EF_UPDATE 0x04 /* update the counter when stopping */ - - /* - * Adds/Removes a counter to/from the PMU, can be done inside a - * transaction, see the ->*_txn() methods. - * - * The add/del callbacks will reserve all hardware resources required - * to service the event, this includes any counter constraint - * scheduling etc. - * - * Called with IRQs disabled and the PMU disabled on the CPU the event - * is on. - * - * ->add() called without PERF_EF_START should result in the same state - * as ->add() followed by ->stop(). - * - * ->del() must always PERF_EF_UPDATE stop an event. If it calls - * ->stop() that must deal with already being stopped without - * PERF_EF_UPDATE. - */ - int (*add) (struct perf_event *event, int flags); - void (*del) (struct perf_event *event, int flags); - - /* - * Starts/Stops a counter present on the PMU. - * - * The PMI handler should stop the counter when perf_event_overflow() - * returns !0. ->start() will be used to continue. - * - * Also used to change the sample period. - * - * Called with IRQs disabled and the PMU disabled on the CPU the event - * is on -- will be called from NMI context with the PMU generates - * NMIs. - * - * ->stop() with PERF_EF_UPDATE will read the counter and update - * period/count values like ->read() would. - * - * ->start() with PERF_EF_RELOAD will reprogram the the counter - * value, must be preceded by a ->stop() with PERF_EF_UPDATE. - */ - void (*start) (struct perf_event *event, int flags); - void (*stop) (struct perf_event *event, int flags); - - /* - * Updates the counter value of the event. - * - * For sampling capable PMUs this will also update the software period - * hw_perf_event::period_left field. - */ - void (*read) (struct perf_event *event); - - /* - * Group events scheduling is treated as a transaction, add - * group events as a whole and perform one schedulability test. - * If the test fails, roll back the whole group - * - * Start the transaction, after this ->add() doesn't need to - * do schedulability tests. - * - * Optional. - */ - void (*start_txn) (struct pmu *pmu, unsigned int txn_flags); - /* - * If ->start_txn() disabled the ->add() schedulability test - * then ->commit_txn() is required to perform one. On success - * the transaction is closed. On error the transaction is kept - * open until ->cancel_txn() is called. - * - * Optional. - */ - int (*commit_txn) (struct pmu *pmu); - /* - * Will cancel the transaction, assumes ->del() is called - * for each successful ->add() during the transaction. - * - * Optional. - */ - void (*cancel_txn) (struct pmu *pmu); - - /* - * Will return the value for perf_event_mmap_page::index for this event, - * if no implementation is provided it will default to: event->hw.idx + 1. - */ - int (*event_idx) (struct perf_event *event); /*optional */ - - /* - * context-switches callback - */ - void (*sched_task) (struct perf_event_context *ctx, - bool sched_in); - /* - * PMU specific data size - */ - size_t task_ctx_size; - - - /* - * Return the count value for a counter. - */ - u64 (*count) (struct perf_event *event); /*optional*/ - - /* - * Set up pmu-private data structures for an AUX area - */ - void *(*setup_aux) (int cpu, void **pages, - int nr_pages, bool overwrite); - /* optional */ - - /* - * Free pmu-private AUX data structures - */ - void (*free_aux) (void *aux); /* optional */ - - /* - * Validate address range filters: make sure the HW supports the - * requested configuration and number of filters; return 0 if the - * supplied filters are valid, -errno otherwise. - * - * Runs in the context of the ioctl()ing process and is not serialized - * with the rest of the PMU callbacks. - */ - int (*addr_filters_validate) (struct list_head *filters); - /* optional */ - - /* - * Synchronize address range filter configuration: - * translate hw-agnostic filters into hardware configuration in - * event::hw::addr_filters. - * - * Runs as a part of filter sync sequence that is done in ->start() - * callback by calling perf_event_addr_filters_sync(). - * - * May (and should) traverse event::addr_filters::list, for which its - * caller provides necessary serialization. - */ - void (*addr_filters_sync) (struct perf_event *event); - /* optional */ - - /* - * Filter events for PMU-specific reasons. - */ - int (*filter_match) (struct perf_event *event); /* optional */ -}; - -/** - * struct perf_addr_filter - address range filter definition - * @entry: event's filter list linkage - * @inode: object file's inode for file-based filters - * @offset: filter range offset - * @size: filter range size - * @range: 1: range, 0: address - * @filter: 1: filter/start, 0: stop - * - * This is a hardware-agnostic filter configuration as specified by the user. - */ -struct perf_addr_filter { - struct list_head entry; - struct inode *inode; - unsigned long offset; - unsigned long size; - unsigned int range : 1, - filter : 1; -}; - -/** - * struct perf_addr_filters_head - container for address range filters - * @list: list of filters for this event - * @lock: spinlock that serializes accesses to the @list and event's - * (and its children's) filter generations. - * - * A child event will use parent's @list (and therefore @lock), so they are - * bundled together; see perf_event_addr_filters(). - */ -struct perf_addr_filters_head { - struct list_head list; - raw_spinlock_t lock; -}; - -/** - * enum perf_event_active_state - the states of a event - */ -enum perf_event_active_state { - PERF_EVENT_STATE_DEAD = -4, - PERF_EVENT_STATE_EXIT = -3, - PERF_EVENT_STATE_ERROR = -2, - PERF_EVENT_STATE_OFF = -1, - PERF_EVENT_STATE_INACTIVE = 0, - PERF_EVENT_STATE_ACTIVE = 1, -}; - -struct file; -struct perf_sample_data; - -typedef void (*perf_overflow_handler_t)(struct perf_event *, - struct perf_sample_data *, - struct pt_regs *regs); - -/* - * Event capabilities. For event_caps and groups caps. - * - * PERF_EV_CAP_SOFTWARE: Is a software event. - * PERF_EV_CAP_READ_ACTIVE_PKG: A CPU event (or cgroup event) that can be read - * from any CPU in the package where it is active. - */ -#define PERF_EV_CAP_SOFTWARE BIT(0) -#define PERF_EV_CAP_READ_ACTIVE_PKG BIT(1) - -#define SWEVENT_HLIST_BITS 8 -#define SWEVENT_HLIST_SIZE (1 << SWEVENT_HLIST_BITS) - -struct swevent_hlist { - struct hlist_head heads[SWEVENT_HLIST_SIZE]; - struct rcu_head rcu_head; -}; - -#define PERF_ATTACH_CONTEXT 0x01 -#define PERF_ATTACH_GROUP 0x02 -#define PERF_ATTACH_TASK 0x04 -#define PERF_ATTACH_TASK_DATA 0x08 - -struct perf_cgroup; -struct ring_buffer; - -struct pmu_event_list { - raw_spinlock_t lock; - struct list_head list; -}; - -/** - * struct perf_event - performance event kernel representation: - */ -struct perf_event { -#ifdef CONFIG_PERF_EVENTS - /* - * entry onto perf_event_context::event_list; - * modifications require ctx->lock - * RCU safe iterations. - */ - struct list_head event_entry; - - /* - * XXX: group_entry and sibling_list should be mutually exclusive; - * either you're a sibling on a group, or you're the group leader. - * Rework the code to always use the same list element. - * - * Locked for modification by both ctx->mutex and ctx->lock; holding - * either sufficies for read. - */ - struct list_head group_entry; - struct list_head sibling_list; - - /* - * We need storage to track the entries in perf_pmu_migrate_context; we - * cannot use the event_entry because of RCU and we want to keep the - * group in tact which avoids us using the other two entries. - */ - struct list_head migrate_entry; - - struct hlist_node hlist_entry; - struct list_head active_entry; - int nr_siblings; - - /* Not serialized. Only written during event initialization. */ - int event_caps; - /* The cumulative AND of all event_caps for events in this group. */ - int group_caps; - - struct perf_event *group_leader; - struct pmu *pmu; - void *pmu_private; - - enum perf_event_active_state state; - unsigned int attach_state; - local64_t count; - atomic64_t child_count; - - /* - * These are the total time in nanoseconds that the event - * has been enabled (i.e. eligible to run, and the task has - * been scheduled in, if this is a per-task event) - * and running (scheduled onto the CPU), respectively. - * - * They are computed from tstamp_enabled, tstamp_running and - * tstamp_stopped when the event is in INACTIVE or ACTIVE state. - */ - u64 total_time_enabled; - u64 total_time_running; - - /* - * These are timestamps used for computing total_time_enabled - * and total_time_running when the event is in INACTIVE or - * ACTIVE state, measured in nanoseconds from an arbitrary point - * in time. - * tstamp_enabled: the notional time when the event was enabled - * tstamp_running: the notional time when the event was scheduled on - * tstamp_stopped: in INACTIVE state, the notional time when the - * event was scheduled off. - */ - u64 tstamp_enabled; - u64 tstamp_running; - u64 tstamp_stopped; - - /* - * timestamp shadows the actual context timing but it can - * be safely used in NMI interrupt context. It reflects the - * context time as it was when the event was last scheduled in. - * - * ctx_time already accounts for ctx->timestamp. Therefore to - * compute ctx_time for a sample, simply add perf_clock(). - */ - u64 shadow_ctx_time; - - struct perf_event_attr attr; - u16 header_size; - u16 id_header_size; - u16 read_size; - struct hw_perf_event hw; - - struct perf_event_context *ctx; - atomic_long_t refcount; - - /* - * These accumulate total time (in nanoseconds) that children - * events have been enabled and running, respectively. - */ - atomic64_t child_total_time_enabled; - atomic64_t child_total_time_running; - - /* - * Protect attach/detach and child_list: - */ - struct mutex child_mutex; - struct list_head child_list; - struct perf_event *parent; - - int oncpu; - int cpu; - - struct list_head owner_entry; - struct task_struct *owner; - - /* mmap bits */ - struct mutex mmap_mutex; - atomic_t mmap_count; - - struct ring_buffer *rb; - struct list_head rb_entry; - unsigned long rcu_batches; - int rcu_pending; - - /* poll related */ - wait_queue_head_t waitq; - struct fasync_struct *fasync; - - /* delayed work for NMIs and such */ - int pending_wakeup; - int pending_kill; - int pending_disable; - struct irq_work pending; - - atomic_t event_limit; - - /* address range filters */ - struct perf_addr_filters_head addr_filters; - /* vma address array for file-based filders */ - unsigned long *addr_filters_offs; - unsigned long addr_filters_gen; - - void (*destroy)(struct perf_event *); - struct rcu_head rcu_head; - - struct pid_namespace *ns; - u64 id; - - u64 (*clock)(void); - perf_overflow_handler_t overflow_handler; - void *overflow_handler_context; -#ifdef CONFIG_BPF_SYSCALL - perf_overflow_handler_t orig_overflow_handler; - struct bpf_prog *prog; -#endif - -#ifdef CONFIG_EVENT_TRACING - struct trace_event_call *tp_event; - struct event_filter *filter; -#ifdef CONFIG_FUNCTION_TRACER - struct ftrace_ops ftrace_ops; -#endif -#endif - -#ifdef CONFIG_CGROUP_PERF - struct perf_cgroup *cgrp; /* cgroup event is attach to */ - int cgrp_defer_enabled; -#endif - - struct list_head sb_list; -#endif /* CONFIG_PERF_EVENTS */ -}; - -/** - * struct perf_event_context - event context structure - * - * Used as a container for task events and CPU events as well: - */ -struct perf_event_context { - struct pmu *pmu; - /* - * Protect the states of the events in the list, - * nr_active, and the list: - */ - raw_spinlock_t lock; - /* - * Protect the list of events. Locking either mutex or lock - * is sufficient to ensure the list doesn't change; to change - * the list you need to lock both the mutex and the spinlock. - */ - struct mutex mutex; - - struct list_head active_ctx_list; - struct list_head pinned_groups; - struct list_head flexible_groups; - struct list_head event_list; - int nr_events; - int nr_active; - int is_active; - int nr_stat; - int nr_freq; - int rotate_disable; - atomic_t refcount; - struct task_struct *task; - - /* - * Context clock, runs when context enabled. - */ - u64 time; - u64 timestamp; - - /* - * These fields let us detect when two contexts have both - * been cloned (inherited) from a common ancestor. - */ - struct perf_event_context *parent_ctx; - u64 parent_gen; - u64 generation; - int pin_count; -#ifdef CONFIG_CGROUP_PERF - int nr_cgroups; /* cgroup evts */ -#endif - void *task_ctx_data; /* pmu specific data */ - struct rcu_head rcu_head; -}; - -/* - * Number of contexts where an event can trigger: - * task, softirq, hardirq, nmi. - */ -#define PERF_NR_CONTEXTS 4 - -/** - * struct perf_event_cpu_context - per cpu event context structure - */ -struct perf_cpu_context { - struct perf_event_context ctx; - struct perf_event_context *task_ctx; - int active_oncpu; - int exclusive; - - raw_spinlock_t hrtimer_lock; - struct hrtimer hrtimer; - ktime_t hrtimer_interval; - unsigned int hrtimer_active; - - struct pmu *unique_pmu; -#ifdef CONFIG_CGROUP_PERF - struct perf_cgroup *cgrp; -#endif - - struct list_head sched_cb_entry; - int sched_cb_usage; -}; - -struct perf_output_handle { - struct perf_event *event; - struct ring_buffer *rb; - unsigned long wakeup; - unsigned long size; - union { - void *addr; - unsigned long head; - }; - int page; -}; - -struct bpf_perf_event_data_kern { - struct pt_regs *regs; - struct perf_sample_data *data; -}; - -#ifdef CONFIG_CGROUP_PERF - -/* - * perf_cgroup_info keeps track of time_enabled for a cgroup. - * This is a per-cpu dynamically allocated data structure. - */ -struct perf_cgroup_info { - u64 time; - u64 timestamp; -}; - -struct perf_cgroup { - struct cgroup_subsys_state css; - struct perf_cgroup_info __percpu *info; -}; - -/* - * Must ensure cgroup is pinned (css_get) before calling - * this function. In other words, we cannot call this function - * if there is no cgroup event for the current CPU context. - */ -static inline struct perf_cgroup * -perf_cgroup_from_task(struct task_struct *task, struct perf_event_context *ctx) -{ - return container_of(task_css_check(task, perf_event_cgrp_id, - ctx ? lockdep_is_held(&ctx->lock) - : true), - struct perf_cgroup, css); -} -#endif /* CONFIG_CGROUP_PERF */ - -#ifdef CONFIG_PERF_EVENTS - -extern void *perf_aux_output_begin(struct perf_output_handle *handle, - struct perf_event *event); -extern void perf_aux_output_end(struct perf_output_handle *handle, - unsigned long size, bool truncated); -extern int perf_aux_output_skip(struct perf_output_handle *handle, - unsigned long size); -extern void *perf_get_aux(struct perf_output_handle *handle); - -extern int perf_pmu_register(struct pmu *pmu, const char *name, int type); -extern void perf_pmu_unregister(struct pmu *pmu); - -extern int perf_num_counters(void); -extern const char *perf_pmu_name(void); -extern void __perf_event_task_sched_in(struct task_struct *prev, - struct task_struct *task); -extern void __perf_event_task_sched_out(struct task_struct *prev, - struct task_struct *next); -extern int perf_event_init_task(struct task_struct *child); -extern void perf_event_exit_task(struct task_struct *child); -extern void perf_event_free_task(struct task_struct *task); -extern void perf_event_delayed_put(struct task_struct *task); -extern struct file *perf_event_get(unsigned int fd); -extern const struct perf_event_attr *perf_event_attrs(struct perf_event *event); -extern void perf_event_print_debug(void); -extern void perf_pmu_disable(struct pmu *pmu); -extern void perf_pmu_enable(struct pmu *pmu); -extern void perf_sched_cb_dec(struct pmu *pmu); -extern void perf_sched_cb_inc(struct pmu *pmu); -extern int perf_event_task_disable(void); -extern int perf_event_task_enable(void); -extern int perf_event_refresh(struct perf_event *event, int refresh); -extern void perf_event_update_userpage(struct perf_event *event); -extern int perf_event_release_kernel(struct perf_event *event); -extern struct perf_event * -perf_event_create_kernel_counter(struct perf_event_attr *attr, - int cpu, - struct task_struct *task, - perf_overflow_handler_t callback, - void *context); -extern void perf_pmu_migrate_context(struct pmu *pmu, - int src_cpu, int dst_cpu); -extern u64 perf_event_read_local(struct perf_event *event); -extern u64 perf_event_read_value(struct perf_event *event, - u64 *enabled, u64 *running); - - -struct perf_sample_data { - /* - * Fields set by perf_sample_data_init(), group so as to - * minimize the cachelines touched. - */ - u64 addr; - struct perf_raw_record *raw; - struct perf_branch_stack *br_stack; - u64 period; - u64 weight; - u64 txn; - union perf_mem_data_src data_src; - - /* - * The other fields, optionally {set,used} by - * perf_{prepare,output}_sample(). - */ - u64 type; - u64 ip; - struct { - u32 pid; - u32 tid; - } tid_entry; - u64 time; - u64 id; - u64 stream_id; - struct { - u32 cpu; - u32 reserved; - } cpu_entry; - struct perf_callchain_entry *callchain; - - /* - * regs_user may point to task_pt_regs or to regs_user_copy, depending - * on arch details. - */ - struct perf_regs regs_user; - struct pt_regs regs_user_copy; - - struct perf_regs regs_intr; - u64 stack_user_size; -} ____cacheline_aligned; - -/* default value for data source */ -#define PERF_MEM_NA (PERF_MEM_S(OP, NA) |\ - PERF_MEM_S(LVL, NA) |\ - PERF_MEM_S(SNOOP, NA) |\ - PERF_MEM_S(LOCK, NA) |\ - PERF_MEM_S(TLB, NA)) - -static inline void perf_sample_data_init(struct perf_sample_data *data, - u64 addr, u64 period) -{ - /* remaining struct members initialized in perf_prepare_sample() */ - data->addr = addr; - data->raw = NULL; - data->br_stack = NULL; - data->period = period; - data->weight = 0; - data->data_src.val = PERF_MEM_NA; - data->txn = 0; -} - -extern void perf_output_sample(struct perf_output_handle *handle, - struct perf_event_header *header, - struct perf_sample_data *data, - struct perf_event *event); -extern void perf_prepare_sample(struct perf_event_header *header, - struct perf_sample_data *data, - struct perf_event *event, - struct pt_regs *regs); - -extern int perf_event_overflow(struct perf_event *event, - struct perf_sample_data *data, - struct pt_regs *regs); - -extern void perf_event_output_forward(struct perf_event *event, - struct perf_sample_data *data, - struct pt_regs *regs); -extern void perf_event_output_backward(struct perf_event *event, - struct perf_sample_data *data, - struct pt_regs *regs); -extern void perf_event_output(struct perf_event *event, - struct perf_sample_data *data, - struct pt_regs *regs); - -static inline bool -is_default_overflow_handler(struct perf_event *event) -{ - if (likely(event->overflow_handler == perf_event_output_forward)) - return true; - if (unlikely(event->overflow_handler == perf_event_output_backward)) - return true; - return false; -} - -extern void -perf_event_header__init_id(struct perf_event_header *header, - struct perf_sample_data *data, - struct perf_event *event); -extern void -perf_event__output_id_sample(struct perf_event *event, - struct perf_output_handle *handle, - struct perf_sample_data *sample); - -extern void -perf_log_lost_samples(struct perf_event *event, u64 lost); - -static inline bool is_sampling_event(struct perf_event *event) -{ - return event->attr.sample_period != 0; -} - -/* - * Return 1 for a software event, 0 for a hardware event - */ -static inline int is_software_event(struct perf_event *event) -{ - return event->event_caps & PERF_EV_CAP_SOFTWARE; -} - -extern struct static_key perf_swevent_enabled[PERF_COUNT_SW_MAX]; - -extern void ___perf_sw_event(u32, u64, struct pt_regs *, u64); -extern void __perf_sw_event(u32, u64, struct pt_regs *, u64); - -#ifndef perf_arch_fetch_caller_regs -static inline void perf_arch_fetch_caller_regs(struct pt_regs *regs, unsigned long ip) { } -#endif - -/* - * Take a snapshot of the regs. Skip ip and frame pointer to - * the nth caller. We only need a few of the regs: - * - ip for PERF_SAMPLE_IP - * - cs for user_mode() tests - * - bp for callchains - * - eflags, for future purposes, just in case - */ -static inline void perf_fetch_caller_regs(struct pt_regs *regs) -{ - perf_arch_fetch_caller_regs(regs, CALLER_ADDR0); -} - -static __always_inline void -perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr) -{ - if (static_key_false(&perf_swevent_enabled[event_id])) - __perf_sw_event(event_id, nr, regs, addr); -} - -DECLARE_PER_CPU(struct pt_regs, __perf_regs[4]); - -/* - * 'Special' version for the scheduler, it hard assumes no recursion, - * which is guaranteed by us not actually scheduling inside other swevents - * because those disable preemption. - */ -static __always_inline void -perf_sw_event_sched(u32 event_id, u64 nr, u64 addr) -{ - if (static_key_false(&perf_swevent_enabled[event_id])) { - struct pt_regs *regs = this_cpu_ptr(&__perf_regs[0]); - - perf_fetch_caller_regs(regs); - ___perf_sw_event(event_id, nr, regs, addr); - } -} - -extern struct static_key_false perf_sched_events; - -static __always_inline bool -perf_sw_migrate_enabled(void) -{ - if (static_key_false(&perf_swevent_enabled[PERF_COUNT_SW_CPU_MIGRATIONS])) - return true; - return false; -} - -static inline void perf_event_task_migrate(struct task_struct *task) -{ - if (perf_sw_migrate_enabled()) - task->sched_migrated = 1; -} - -static inline void perf_event_task_sched_in(struct task_struct *prev, - struct task_struct *task) -{ - if (static_branch_unlikely(&perf_sched_events)) - __perf_event_task_sched_in(prev, task); - - if (perf_sw_migrate_enabled() && task->sched_migrated) { - struct pt_regs *regs = this_cpu_ptr(&__perf_regs[0]); - - perf_fetch_caller_regs(regs); - ___perf_sw_event(PERF_COUNT_SW_CPU_MIGRATIONS, 1, regs, 0); - task->sched_migrated = 0; - } -} - -static inline void perf_event_task_sched_out(struct task_struct *prev, - struct task_struct *next) -{ - perf_sw_event_sched(PERF_COUNT_SW_CONTEXT_SWITCHES, 1, 0); - - if (static_branch_unlikely(&perf_sched_events)) - __perf_event_task_sched_out(prev, next); -} - -static inline u64 __perf_event_count(struct perf_event *event) -{ - return local64_read(&event->count) + atomic64_read(&event->child_count); -} - -extern void perf_event_mmap(struct vm_area_struct *vma); -extern struct perf_guest_info_callbacks *perf_guest_cbs; -extern int perf_register_guest_info_callbacks(struct perf_guest_info_callbacks *callbacks); -extern int perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *callbacks); - -extern void perf_event_exec(void); -extern void perf_event_comm(struct task_struct *tsk, bool exec); -extern void perf_event_fork(struct task_struct *tsk); - -/* Callchains */ -DECLARE_PER_CPU(struct perf_callchain_entry, perf_callchain_entry); - -extern void perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs); -extern void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs); -extern struct perf_callchain_entry * -get_perf_callchain(struct pt_regs *regs, u32 init_nr, bool kernel, bool user, - u32 max_stack, bool crosstask, bool add_mark); -extern int get_callchain_buffers(int max_stack); -extern void put_callchain_buffers(void); - -extern int sysctl_perf_event_max_stack; -extern int sysctl_perf_event_max_contexts_per_stack; - -static inline int perf_callchain_store_context(struct perf_callchain_entry_ctx *ctx, u64 ip) -{ - if (ctx->contexts < sysctl_perf_event_max_contexts_per_stack) { - struct perf_callchain_entry *entry = ctx->entry; - entry->ip[entry->nr++] = ip; - ++ctx->contexts; - return 0; - } else { - ctx->contexts_maxed = true; - return -1; /* no more room, stop walking the stack */ - } -} - -static inline int perf_callchain_store(struct perf_callchain_entry_ctx *ctx, u64 ip) -{ - if (ctx->nr < ctx->max_stack && !ctx->contexts_maxed) { - struct perf_callchain_entry *entry = ctx->entry; - entry->ip[entry->nr++] = ip; - ++ctx->nr; - return 0; - } else { - return -1; /* no more room, stop walking the stack */ - } -} - -extern int sysctl_perf_event_paranoid; -extern int sysctl_perf_event_mlock; -extern int sysctl_perf_event_sample_rate; -extern int sysctl_perf_cpu_time_max_percent; - -extern void perf_sample_event_took(u64 sample_len_ns); - -extern int perf_proc_update_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos); -extern int perf_cpu_time_max_percent_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos); - -int perf_event_max_stack_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); - -static inline bool perf_paranoid_tracepoint_raw(void) -{ - return sysctl_perf_event_paranoid > -1; -} - -static inline bool perf_paranoid_cpu(void) -{ - return sysctl_perf_event_paranoid > 0; -} - -static inline bool perf_paranoid_kernel(void) -{ - return sysctl_perf_event_paranoid > 1; -} - -extern void perf_event_init(void); -extern void perf_tp_event(u16 event_type, u64 count, void *record, - int entry_size, struct pt_regs *regs, - struct hlist_head *head, int rctx, - struct task_struct *task); -extern void perf_bp_event(struct perf_event *event, void *data); - -#ifndef perf_misc_flags -# define perf_misc_flags(regs) \ - (user_mode(regs) ? PERF_RECORD_MISC_USER : PERF_RECORD_MISC_KERNEL) -# define perf_instruction_pointer(regs) instruction_pointer(regs) -#endif - -static inline bool has_branch_stack(struct perf_event *event) -{ - return event->attr.sample_type & PERF_SAMPLE_BRANCH_STACK; -} - -static inline bool needs_branch_stack(struct perf_event *event) -{ - return event->attr.branch_sample_type != 0; -} - -static inline bool has_aux(struct perf_event *event) -{ - return event->pmu->setup_aux; -} - -static inline bool is_write_backward(struct perf_event *event) -{ - return !!event->attr.write_backward; -} - -static inline bool has_addr_filter(struct perf_event *event) -{ - return event->pmu->nr_addr_filters; -} - -/* - * An inherited event uses parent's filters - */ -static inline struct perf_addr_filters_head * -perf_event_addr_filters(struct perf_event *event) -{ - struct perf_addr_filters_head *ifh = &event->addr_filters; - - if (event->parent) - ifh = &event->parent->addr_filters; - - return ifh; -} - -extern void perf_event_addr_filters_sync(struct perf_event *event); - -extern int perf_output_begin(struct perf_output_handle *handle, - struct perf_event *event, unsigned int size); -extern int perf_output_begin_forward(struct perf_output_handle *handle, - struct perf_event *event, - unsigned int size); -extern int perf_output_begin_backward(struct perf_output_handle *handle, - struct perf_event *event, - unsigned int size); - -extern void perf_output_end(struct perf_output_handle *handle); -extern unsigned int perf_output_copy(struct perf_output_handle *handle, - const void *buf, unsigned int len); -extern unsigned int perf_output_skip(struct perf_output_handle *handle, - unsigned int len); -extern int perf_swevent_get_recursion_context(void); -extern void perf_swevent_put_recursion_context(int rctx); -extern u64 perf_swevent_set_period(struct perf_event *event); -extern void perf_event_enable(struct perf_event *event); -extern void perf_event_disable(struct perf_event *event); -extern void perf_event_disable_local(struct perf_event *event); -extern void perf_event_disable_inatomic(struct perf_event *event); -extern void perf_event_task_tick(void); -#else /* !CONFIG_PERF_EVENTS: */ -static inline void * -perf_aux_output_begin(struct perf_output_handle *handle, - struct perf_event *event) { return NULL; } -static inline void -perf_aux_output_end(struct perf_output_handle *handle, unsigned long size, - bool truncated) { } -static inline int -perf_aux_output_skip(struct perf_output_handle *handle, - unsigned long size) { return -EINVAL; } -static inline void * -perf_get_aux(struct perf_output_handle *handle) { return NULL; } -static inline void -perf_event_task_migrate(struct task_struct *task) { } -static inline void -perf_event_task_sched_in(struct task_struct *prev, - struct task_struct *task) { } -static inline void -perf_event_task_sched_out(struct task_struct *prev, - struct task_struct *next) { } -static inline int perf_event_init_task(struct task_struct *child) { return 0; } -static inline void perf_event_exit_task(struct task_struct *child) { } -static inline void perf_event_free_task(struct task_struct *task) { } -static inline void perf_event_delayed_put(struct task_struct *task) { } -static inline struct file *perf_event_get(unsigned int fd) { return ERR_PTR(-EINVAL); } -static inline const struct perf_event_attr *perf_event_attrs(struct perf_event *event) -{ - return ERR_PTR(-EINVAL); -} -static inline u64 perf_event_read_local(struct perf_event *event) { return -EINVAL; } -static inline void perf_event_print_debug(void) { } -static inline int perf_event_task_disable(void) { return -EINVAL; } -static inline int perf_event_task_enable(void) { return -EINVAL; } -static inline int perf_event_refresh(struct perf_event *event, int refresh) -{ - return -EINVAL; -} - -static inline void -perf_sw_event(u32 event_id, u64 nr, struct pt_regs *regs, u64 addr) { } -static inline void -perf_sw_event_sched(u32 event_id, u64 nr, u64 addr) { } -static inline void -perf_bp_event(struct perf_event *event, void *data) { } - -static inline int perf_register_guest_info_callbacks -(struct perf_guest_info_callbacks *callbacks) { return 0; } -static inline int perf_unregister_guest_info_callbacks -(struct perf_guest_info_callbacks *callbacks) { return 0; } - -static inline void perf_event_mmap(struct vm_area_struct *vma) { } -static inline void perf_event_exec(void) { } -static inline void perf_event_comm(struct task_struct *tsk, bool exec) { } -static inline void perf_event_fork(struct task_struct *tsk) { } -static inline void perf_event_init(void) { } -static inline int perf_swevent_get_recursion_context(void) { return -1; } -static inline void perf_swevent_put_recursion_context(int rctx) { } -static inline u64 perf_swevent_set_period(struct perf_event *event) { return 0; } -static inline void perf_event_enable(struct perf_event *event) { } -static inline void perf_event_disable(struct perf_event *event) { } -static inline int __perf_event_disable(void *info) { return -1; } -static inline void perf_event_task_tick(void) { } -static inline int perf_event_release_kernel(struct perf_event *event) { return 0; } -#endif - -#if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_INTEL) -extern void perf_restore_debug_store(void); -#else -static inline void perf_restore_debug_store(void) { } -#endif - -static __always_inline bool perf_raw_frag_last(const struct perf_raw_frag *frag) -{ - return frag->pad < sizeof(u64); -} - -#define perf_output_put(handle, x) perf_output_copy((handle), &(x), sizeof(x)) - -struct perf_pmu_events_attr { - struct device_attribute attr; - u64 id; - const char *event_str; -}; - -struct perf_pmu_events_ht_attr { - struct device_attribute attr; - u64 id; - const char *event_str_ht; - const char *event_str_noht; -}; - -ssize_t perf_event_sysfs_show(struct device *dev, struct device_attribute *attr, - char *page); - -#define PMU_EVENT_ATTR(_name, _var, _id, _show) \ -static struct perf_pmu_events_attr _var = { \ - .attr = __ATTR(_name, 0444, _show, NULL), \ - .id = _id, \ -}; - -#define PMU_EVENT_ATTR_STRING(_name, _var, _str) \ -static struct perf_pmu_events_attr _var = { \ - .attr = __ATTR(_name, 0444, perf_event_sysfs_show, NULL), \ - .id = 0, \ - .event_str = _str, \ -}; - -#define PMU_FORMAT_ATTR(_name, _format) \ -static ssize_t \ -_name##_show(struct device *dev, \ - struct device_attribute *attr, \ - char *page) \ -{ \ - BUILD_BUG_ON(sizeof(_format) >= PAGE_SIZE); \ - return sprintf(page, _format "\n"); \ -} \ - \ -static struct device_attribute format_attr_##_name = __ATTR_RO(_name) - -/* Performance counter hotplug functions */ -#ifdef CONFIG_PERF_EVENTS -int perf_event_init_cpu(unsigned int cpu); -int perf_event_exit_cpu(unsigned int cpu); -#else -#define perf_event_init_cpu NULL -#define perf_event_exit_cpu NULL -#endif - -#endif /* _LINUX_PERF_EVENT_H */ diff --git a/src/linux/include/linux/perf_regs.h b/src/linux/include/linux/perf_regs.h deleted file mode 100644 index a5f98d5..0000000 --- a/src/linux/include/linux/perf_regs.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _LINUX_PERF_REGS_H -#define _LINUX_PERF_REGS_H - -struct perf_regs { - __u64 abi; - struct pt_regs *regs; -}; - -#ifdef CONFIG_HAVE_PERF_REGS -#include -u64 perf_reg_value(struct pt_regs *regs, int idx); -int perf_reg_validate(u64 mask); -u64 perf_reg_abi(struct task_struct *task); -void perf_get_regs_user(struct perf_regs *regs_user, - struct pt_regs *regs, - struct pt_regs *regs_user_copy); -#else -static inline u64 perf_reg_value(struct pt_regs *regs, int idx) -{ - return 0; -} - -static inline int perf_reg_validate(u64 mask) -{ - return mask ? -ENOSYS : 0; -} - -static inline u64 perf_reg_abi(struct task_struct *task) -{ - return PERF_SAMPLE_REGS_ABI_NONE; -} - -static inline void perf_get_regs_user(struct perf_regs *regs_user, - struct pt_regs *regs, - struct pt_regs *regs_user_copy) -{ - regs_user->regs = task_pt_regs(current); - regs_user->abi = perf_reg_abi(current); -} -#endif /* CONFIG_HAVE_PERF_REGS */ -#endif /* _LINUX_PERF_REGS_H */ diff --git a/src/linux/include/linux/personality.h b/src/linux/include/linux/personality.h deleted file mode 100644 index aeb7892..0000000 --- a/src/linux/include/linux/personality.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _LINUX_PERSONALITY_H -#define _LINUX_PERSONALITY_H - -#include - -/* - * Return the base personality without flags. - */ -#define personality(pers) (pers & PER_MASK) - -/* - * Change personality of the currently running process. - */ -#define set_personality(pers) (current->personality = (pers)) - -#endif /* _LINUX_PERSONALITY_H */ diff --git a/src/linux/include/linux/pfn.h b/src/linux/include/linux/pfn.h deleted file mode 100644 index 1132953..0000000 --- a/src/linux/include/linux/pfn.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _LINUX_PFN_H_ -#define _LINUX_PFN_H_ - -#ifndef __ASSEMBLY__ -#include - -/* - * pfn_t: encapsulates a page-frame number that is optionally backed - * by memmap (struct page). Whether a pfn_t has a 'struct page' - * backing is indicated by flags in the high bits of the value. - */ -typedef struct { - u64 val; -} pfn_t; -#endif - -#define PFN_ALIGN(x) (((unsigned long)(x) + (PAGE_SIZE - 1)) & PAGE_MASK) -#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) -#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) -#define PFN_PHYS(x) ((phys_addr_t)(x) << PAGE_SHIFT) -#define PHYS_PFN(x) ((unsigned long)((x) >> PAGE_SHIFT)) - -#endif diff --git a/src/linux/include/linux/pfn_t.h b/src/linux/include/linux/pfn_t.h deleted file mode 100644 index a3d90b9..0000000 --- a/src/linux/include/linux/pfn_t.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef _LINUX_PFN_T_H_ -#define _LINUX_PFN_T_H_ -#include - -/* - * PFN_FLAGS_MASK - mask of all the possible valid pfn_t flags - * PFN_SG_CHAIN - pfn is a pointer to the next scatterlist entry - * PFN_SG_LAST - pfn references a page and is the last scatterlist entry - * PFN_DEV - pfn is not covered by system memmap by default - * PFN_MAP - pfn has a dynamic page mapping established by a device driver - */ -#define PFN_FLAGS_MASK (((u64) ~PAGE_MASK) << (BITS_PER_LONG_LONG - PAGE_SHIFT)) -#define PFN_SG_CHAIN (1ULL << (BITS_PER_LONG_LONG - 1)) -#define PFN_SG_LAST (1ULL << (BITS_PER_LONG_LONG - 2)) -#define PFN_DEV (1ULL << (BITS_PER_LONG_LONG - 3)) -#define PFN_MAP (1ULL << (BITS_PER_LONG_LONG - 4)) - -static inline pfn_t __pfn_to_pfn_t(unsigned long pfn, u64 flags) -{ - pfn_t pfn_t = { .val = pfn | (flags & PFN_FLAGS_MASK), }; - - return pfn_t; -} - -/* a default pfn to pfn_t conversion assumes that @pfn is pfn_valid() */ -static inline pfn_t pfn_to_pfn_t(unsigned long pfn) -{ - return __pfn_to_pfn_t(pfn, 0); -} - -static inline pfn_t phys_to_pfn_t(phys_addr_t addr, u64 flags) -{ - return __pfn_to_pfn_t(addr >> PAGE_SHIFT, flags); -} - -static inline bool pfn_t_has_page(pfn_t pfn) -{ - return (pfn.val & PFN_MAP) == PFN_MAP || (pfn.val & PFN_DEV) == 0; -} - -static inline unsigned long pfn_t_to_pfn(pfn_t pfn) -{ - return pfn.val & ~PFN_FLAGS_MASK; -} - -static inline struct page *pfn_t_to_page(pfn_t pfn) -{ - if (pfn_t_has_page(pfn)) - return pfn_to_page(pfn_t_to_pfn(pfn)); - return NULL; -} - -static inline phys_addr_t pfn_t_to_phys(pfn_t pfn) -{ - return PFN_PHYS(pfn_t_to_pfn(pfn)); -} - -static inline void *pfn_t_to_virt(pfn_t pfn) -{ - if (pfn_t_has_page(pfn)) - return __va(pfn_t_to_phys(pfn)); - return NULL; -} - -static inline pfn_t page_to_pfn_t(struct page *page) -{ - return pfn_to_pfn_t(page_to_pfn(page)); -} - -static inline int pfn_t_valid(pfn_t pfn) -{ - return pfn_valid(pfn_t_to_pfn(pfn)); -} - -#ifdef CONFIG_MMU -static inline pte_t pfn_t_pte(pfn_t pfn, pgprot_t pgprot) -{ - return pfn_pte(pfn_t_to_pfn(pfn), pgprot); -} -#endif - -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -static inline pmd_t pfn_t_pmd(pfn_t pfn, pgprot_t pgprot) -{ - return pfn_pmd(pfn_t_to_pfn(pfn), pgprot); -} -#endif - -#ifdef __HAVE_ARCH_PTE_DEVMAP -static inline bool pfn_t_devmap(pfn_t pfn) -{ - const u64 flags = PFN_DEV|PFN_MAP; - - return (pfn.val & flags) == flags; -} -#else -static inline bool pfn_t_devmap(pfn_t pfn) -{ - return false; -} -pte_t pte_mkdevmap(pte_t pte); -pmd_t pmd_mkdevmap(pmd_t pmd); -#endif -#endif /* _LINUX_PFN_T_H_ */ diff --git a/src/linux/include/linux/phy.h b/src/linux/include/linux/phy.h deleted file mode 100644 index e25f183..0000000 --- a/src/linux/include/linux/phy.h +++ /dev/null @@ -1,868 +0,0 @@ -/* - * Framework and drivers for configuring and reading different PHYs - * Based on code in sungem_phy.c and gianfar_phy.c - * - * Author: Andy Fleming - * - * Copyright (c) 2004 Freescale Semiconductor, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -#ifndef __PHY_H -#define __PHY_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define PHY_DEFAULT_FEATURES (SUPPORTED_Autoneg | \ - SUPPORTED_TP | \ - SUPPORTED_MII) - -#define PHY_10BT_FEATURES (SUPPORTED_10baseT_Half | \ - SUPPORTED_10baseT_Full) - -#define PHY_100BT_FEATURES (SUPPORTED_100baseT_Half | \ - SUPPORTED_100baseT_Full) - -#define PHY_1000BT_FEATURES (SUPPORTED_1000baseT_Half | \ - SUPPORTED_1000baseT_Full) - -#define PHY_BASIC_FEATURES (PHY_10BT_FEATURES | \ - PHY_100BT_FEATURES | \ - PHY_DEFAULT_FEATURES) - -#define PHY_GBIT_FEATURES (PHY_BASIC_FEATURES | \ - PHY_1000BT_FEATURES) - - -/* - * Set phydev->irq to PHY_POLL if interrupts are not supported, - * or not desired for this PHY. Set to PHY_IGNORE_INTERRUPT if - * the attached driver handles the interrupt - */ -#define PHY_POLL -1 -#define PHY_IGNORE_INTERRUPT -2 - -#define PHY_HAS_INTERRUPT 0x00000001 -#define PHY_HAS_MAGICANEG 0x00000002 -#define PHY_IS_INTERNAL 0x00000004 -#define MDIO_DEVICE_IS_PHY 0x80000000 - -/* Interface Mode definitions */ -typedef enum { - PHY_INTERFACE_MODE_NA, - PHY_INTERFACE_MODE_MII, - PHY_INTERFACE_MODE_GMII, - PHY_INTERFACE_MODE_SGMII, - PHY_INTERFACE_MODE_TBI, - PHY_INTERFACE_MODE_REVMII, - PHY_INTERFACE_MODE_RMII, - PHY_INTERFACE_MODE_RGMII, - PHY_INTERFACE_MODE_RGMII_ID, - PHY_INTERFACE_MODE_RGMII_RXID, - PHY_INTERFACE_MODE_RGMII_TXID, - PHY_INTERFACE_MODE_RTBI, - PHY_INTERFACE_MODE_SMII, - PHY_INTERFACE_MODE_XGMII, - PHY_INTERFACE_MODE_MOCA, - PHY_INTERFACE_MODE_QSGMII, - PHY_INTERFACE_MODE_TRGMII, - PHY_INTERFACE_MODE_MAX, -} phy_interface_t; - -/** - * It maps 'enum phy_interface_t' found in include/linux/phy.h - * into the device tree binding of 'phy-mode', so that Ethernet - * device driver can get phy interface from device tree. - */ -static inline const char *phy_modes(phy_interface_t interface) -{ - switch (interface) { - case PHY_INTERFACE_MODE_NA: - return ""; - case PHY_INTERFACE_MODE_MII: - return "mii"; - case PHY_INTERFACE_MODE_GMII: - return "gmii"; - case PHY_INTERFACE_MODE_SGMII: - return "sgmii"; - case PHY_INTERFACE_MODE_TBI: - return "tbi"; - case PHY_INTERFACE_MODE_REVMII: - return "rev-mii"; - case PHY_INTERFACE_MODE_RMII: - return "rmii"; - case PHY_INTERFACE_MODE_RGMII: - return "rgmii"; - case PHY_INTERFACE_MODE_RGMII_ID: - return "rgmii-id"; - case PHY_INTERFACE_MODE_RGMII_RXID: - return "rgmii-rxid"; - case PHY_INTERFACE_MODE_RGMII_TXID: - return "rgmii-txid"; - case PHY_INTERFACE_MODE_RTBI: - return "rtbi"; - case PHY_INTERFACE_MODE_SMII: - return "smii"; - case PHY_INTERFACE_MODE_XGMII: - return "xgmii"; - case PHY_INTERFACE_MODE_MOCA: - return "moca"; - case PHY_INTERFACE_MODE_QSGMII: - return "qsgmii"; - case PHY_INTERFACE_MODE_TRGMII: - return "trgmii"; - default: - return "unknown"; - } -} - - -#define PHY_INIT_TIMEOUT 100000 -#define PHY_STATE_TIME 1 -#define PHY_FORCE_TIMEOUT 10 -#define PHY_AN_TIMEOUT 10 - -#define PHY_MAX_ADDR 32 - -/* Used when trying to connect to a specific phy (mii bus id:phy device id) */ -#define PHY_ID_FMT "%s:%02x" - -/* - * Need to be a little smaller than phydev->dev.bus_id to leave room - * for the ":%02x" - */ -#define MII_BUS_ID_SIZE (20 - 3) - -/* Or MII_ADDR_C45 into regnum for read/write on mii_bus to enable the 21 bit - IEEE 802.3ae clause 45 addressing mode used by 10GIGE phy chips. */ -#define MII_ADDR_C45 (1<<30) - -struct device; -struct sk_buff; - -/* - * The Bus class for PHYs. Devices which provide access to - * PHYs should register using this structure - */ -struct mii_bus { - struct module *owner; - const char *name; - char id[MII_BUS_ID_SIZE]; - void *priv; - int (*read)(struct mii_bus *bus, int addr, int regnum); - int (*write)(struct mii_bus *bus, int addr, int regnum, u16 val); - int (*reset)(struct mii_bus *bus); - - /* - * A lock to ensure that only one thing can read/write - * the MDIO bus at a time - */ - struct mutex mdio_lock; - - struct device *parent; - enum { - MDIOBUS_ALLOCATED = 1, - MDIOBUS_REGISTERED, - MDIOBUS_UNREGISTERED, - MDIOBUS_RELEASED, - } state; - struct device dev; - - /* list of all PHYs on bus */ - struct mdio_device *mdio_map[PHY_MAX_ADDR]; - - /* PHY addresses to be ignored when probing */ - u32 phy_mask; - - /* PHY addresses to ignore the TA/read failure */ - u32 phy_ignore_ta_mask; - - /* - * An array of interrupts, each PHY's interrupt at the index - * matching its address - */ - int irq[PHY_MAX_ADDR]; -}; -#define to_mii_bus(d) container_of(d, struct mii_bus, dev) - -struct mii_bus *mdiobus_alloc_size(size_t); -static inline struct mii_bus *mdiobus_alloc(void) -{ - return mdiobus_alloc_size(0); -} - -int __mdiobus_register(struct mii_bus *bus, struct module *owner); -#define mdiobus_register(bus) __mdiobus_register(bus, THIS_MODULE) -void mdiobus_unregister(struct mii_bus *bus); -void mdiobus_free(struct mii_bus *bus); -struct mii_bus *devm_mdiobus_alloc_size(struct device *dev, int sizeof_priv); -static inline struct mii_bus *devm_mdiobus_alloc(struct device *dev) -{ - return devm_mdiobus_alloc_size(dev, 0); -} - -void devm_mdiobus_free(struct device *dev, struct mii_bus *bus); -struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr); - -#define PHY_INTERRUPT_DISABLED 0x0 -#define PHY_INTERRUPT_ENABLED 0x80000000 - -/* PHY state machine states: - * - * DOWN: PHY device and driver are not ready for anything. probe - * should be called if and only if the PHY is in this state, - * given that the PHY device exists. - * - PHY driver probe function will, depending on the PHY, set - * the state to STARTING or READY - * - * STARTING: PHY device is coming up, and the ethernet driver is - * not ready. PHY drivers may set this in the probe function. - * If they do, they are responsible for making sure the state is - * eventually set to indicate whether the PHY is UP or READY, - * depending on the state when the PHY is done starting up. - * - PHY driver will set the state to READY - * - start will set the state to PENDING - * - * READY: PHY is ready to send and receive packets, but the - * controller is not. By default, PHYs which do not implement - * probe will be set to this state by phy_probe(). If the PHY - * driver knows the PHY is ready, and the PHY state is STARTING, - * then it sets this STATE. - * - start will set the state to UP - * - * PENDING: PHY device is coming up, but the ethernet driver is - * ready. phy_start will set this state if the PHY state is - * STARTING. - * - PHY driver will set the state to UP when the PHY is ready - * - * UP: The PHY and attached device are ready to do work. - * Interrupts should be started here. - * - timer moves to AN - * - * AN: The PHY is currently negotiating the link state. Link is - * therefore down for now. phy_timer will set this state when it - * detects the state is UP. config_aneg will set this state - * whenever called with phydev->autoneg set to AUTONEG_ENABLE. - * - If autonegotiation finishes, but there's no link, it sets - * the state to NOLINK. - * - If aneg finishes with link, it sets the state to RUNNING, - * and calls adjust_link - * - If autonegotiation did not finish after an arbitrary amount - * of time, autonegotiation should be tried again if the PHY - * supports "magic" autonegotiation (back to AN) - * - If it didn't finish, and no magic_aneg, move to FORCING. - * - * NOLINK: PHY is up, but not currently plugged in. - * - If the timer notes that the link comes back, we move to RUNNING - * - config_aneg moves to AN - * - phy_stop moves to HALTED - * - * FORCING: PHY is being configured with forced settings - * - if link is up, move to RUNNING - * - If link is down, we drop to the next highest setting, and - * retry (FORCING) after a timeout - * - phy_stop moves to HALTED - * - * RUNNING: PHY is currently up, running, and possibly sending - * and/or receiving packets - * - timer will set CHANGELINK if we're polling (this ensures the - * link state is polled every other cycle of this state machine, - * which makes it every other second) - * - irq will set CHANGELINK - * - config_aneg will set AN - * - phy_stop moves to HALTED - * - * CHANGELINK: PHY experienced a change in link state - * - timer moves to RUNNING if link - * - timer moves to NOLINK if the link is down - * - phy_stop moves to HALTED - * - * HALTED: PHY is up, but no polling or interrupts are done. Or - * PHY is in an error state. - * - * - phy_start moves to RESUMING - * - * RESUMING: PHY was halted, but now wants to run again. - * - If we are forcing, or aneg is done, timer moves to RUNNING - * - If aneg is not done, timer moves to AN - * - phy_stop moves to HALTED - */ -enum phy_state { - PHY_DOWN = 0, - PHY_STARTING, - PHY_READY, - PHY_PENDING, - PHY_UP, - PHY_AN, - PHY_RUNNING, - PHY_NOLINK, - PHY_FORCING, - PHY_CHANGELINK, - PHY_HALTED, - PHY_RESUMING -}; - -/** - * struct phy_c45_device_ids - 802.3-c45 Device Identifiers - * @devices_in_package: Bit vector of devices present. - * @device_ids: The device identifer for each present device. - */ -struct phy_c45_device_ids { - u32 devices_in_package; - u32 device_ids[8]; -}; - -/* phy_device: An instance of a PHY - * - * drv: Pointer to the driver for this PHY instance - * phy_id: UID for this device found during discovery - * c45_ids: 802.3-c45 Device Identifers if is_c45. - * is_c45: Set to true if this phy uses clause 45 addressing. - * is_internal: Set to true if this phy is internal to a MAC. - * is_pseudo_fixed_link: Set to true if this phy is an Ethernet switch, etc. - * has_fixups: Set to true if this phy has fixups/quirks. - * suspended: Set to true if this phy has been suspended successfully. - * state: state of the PHY for management purposes - * dev_flags: Device-specific flags used by the PHY driver. - * link_timeout: The number of timer firings to wait before the - * giving up on the current attempt at acquiring a link - * irq: IRQ number of the PHY's interrupt (-1 if none) - * phy_timer: The timer for handling the state machine - * phy_queue: A work_queue for the interrupt - * attached_dev: The attached enet driver's device instance ptr - * adjust_link: Callback for the enet controller to respond to - * changes in the link state. - * - * speed, duplex, pause, supported, advertising, lp_advertising, - * and autoneg are used like in mii_if_info - * - * interrupts currently only supports enabled or disabled, - * but could be changed in the future to support enabling - * and disabling specific interrupts - * - * Contains some infrastructure for polling and interrupt - * handling, as well as handling shifts in PHY hardware state - */ -struct phy_device { - struct mdio_device mdio; - - /* Information about the PHY type */ - /* And management functions */ - struct phy_driver *drv; - - u32 phy_id; - - struct phy_c45_device_ids c45_ids; - bool is_c45; - bool is_internal; - bool is_pseudo_fixed_link; - bool has_fixups; - bool suspended; - - enum phy_state state; - - u32 dev_flags; - - phy_interface_t interface; - - /* - * forced speed & duplex (no autoneg) - * partner speed & duplex & pause (autoneg) - */ - int speed; - int duplex; - int pause; - int asym_pause; - - /* The most recently read link state */ - int link; - - /* Enabled Interrupts */ - u32 interrupts; - - /* Union of PHY and Attached devices' supported modes */ - /* See mii.h for more info */ - u32 supported; - u32 advertising; - u32 lp_advertising; - - int autoneg; - - int link_timeout; - - /* - * Interrupt number for this PHY - * -1 means no interrupt - */ - int irq; - - /* private data pointer */ - /* For use by PHYs to maintain extra state */ - void *priv; - - /* Interrupt and Polling infrastructure */ - struct work_struct phy_queue; - struct delayed_work state_queue; - atomic_t irq_disable; - - struct mutex lock; - - struct net_device *attached_dev; - - u8 mdix; - - void (*adjust_link)(struct net_device *dev); -}; -#define to_phy_device(d) container_of(to_mdio_device(d), \ - struct phy_device, mdio) - -/* struct phy_driver: Driver structure for a particular PHY type - * - * driver_data: static driver data - * phy_id: The result of reading the UID registers of this PHY - * type, and ANDing them with the phy_id_mask. This driver - * only works for PHYs with IDs which match this field - * name: The friendly name of this PHY type - * phy_id_mask: Defines the important bits of the phy_id - * features: A list of features (speed, duplex, etc) supported - * by this PHY - * flags: A bitfield defining certain other features this PHY - * supports (like interrupts) - * - * The drivers must implement config_aneg and read_status. All - * other functions are optional. Note that none of these - * functions should be called from interrupt time. The goal is - * for the bus read/write functions to be able to block when the - * bus transaction is happening, and be freed up by an interrupt - * (The MPC85xx has this ability, though it is not currently - * supported in the driver). - */ -struct phy_driver { - struct mdio_driver_common mdiodrv; - u32 phy_id; - char *name; - unsigned int phy_id_mask; - u32 features; - u32 flags; - const void *driver_data; - - /* - * Called to issue a PHY software reset - */ - int (*soft_reset)(struct phy_device *phydev); - - /* - * Called to initialize the PHY, - * including after a reset - */ - int (*config_init)(struct phy_device *phydev); - - /* - * Called during discovery. Used to set - * up device-specific structures, if any - */ - int (*probe)(struct phy_device *phydev); - - /* PHY Power Management */ - int (*suspend)(struct phy_device *phydev); - int (*resume)(struct phy_device *phydev); - - /* - * Configures the advertisement and resets - * autonegotiation if phydev->autoneg is on, - * forces the speed to the current settings in phydev - * if phydev->autoneg is off - */ - int (*config_aneg)(struct phy_device *phydev); - - /* Determines the auto negotiation result */ - int (*aneg_done)(struct phy_device *phydev); - - /* Determines the negotiated speed and duplex */ - int (*read_status)(struct phy_device *phydev); - - /* Clears any pending interrupts */ - int (*ack_interrupt)(struct phy_device *phydev); - - /* Enables or disables interrupts */ - int (*config_intr)(struct phy_device *phydev); - - /* - * Checks if the PHY generated an interrupt. - * For multi-PHY devices with shared PHY interrupt pin - */ - int (*did_interrupt)(struct phy_device *phydev); - - /* Clears up any memory if needed */ - void (*remove)(struct phy_device *phydev); - - /* Returns true if this is a suitable driver for the given - * phydev. If NULL, matching is based on phy_id and - * phy_id_mask. - */ - int (*match_phy_device)(struct phy_device *phydev); - - /* Handles ethtool queries for hardware time stamping. */ - int (*ts_info)(struct phy_device *phydev, struct ethtool_ts_info *ti); - - /* Handles SIOCSHWTSTAMP ioctl for hardware time stamping. */ - int (*hwtstamp)(struct phy_device *phydev, struct ifreq *ifr); - - /* - * Requests a Rx timestamp for 'skb'. If the skb is accepted, - * the phy driver promises to deliver it using netif_rx() as - * soon as a timestamp becomes available. One of the - * PTP_CLASS_ values is passed in 'type'. The function must - * return true if the skb is accepted for delivery. - */ - bool (*rxtstamp)(struct phy_device *dev, struct sk_buff *skb, int type); - - /* - * Requests a Tx timestamp for 'skb'. The phy driver promises - * to deliver it using skb_complete_tx_timestamp() as soon as a - * timestamp becomes available. One of the PTP_CLASS_ values - * is passed in 'type'. - */ - void (*txtstamp)(struct phy_device *dev, struct sk_buff *skb, int type); - - /* Some devices (e.g. qnap TS-119P II) require PHY register changes to - * enable Wake on LAN, so set_wol is provided to be called in the - * ethernet driver's set_wol function. */ - int (*set_wol)(struct phy_device *dev, struct ethtool_wolinfo *wol); - - /* See set_wol, but for checking whether Wake on LAN is enabled. */ - void (*get_wol)(struct phy_device *dev, struct ethtool_wolinfo *wol); - - /* - * Called to inform a PHY device driver when the core is about to - * change the link state. This callback is supposed to be used as - * fixup hook for drivers that need to take action when the link - * state changes. Drivers are by no means allowed to mess with the - * PHY device structure in their implementations. - */ - void (*link_change_notify)(struct phy_device *dev); - - /* A function provided by a phy specific driver to override the - * the PHY driver framework support for reading a MMD register - * from the PHY. If not supported, return -1. This function is - * optional for PHY specific drivers, if not provided then the - * default MMD read function is used by the PHY framework. - */ - int (*read_mmd_indirect)(struct phy_device *dev, int ptrad, - int devnum, int regnum); - - /* A function provided by a phy specific driver to override the - * the PHY driver framework support for writing a MMD register - * from the PHY. This function is optional for PHY specific drivers, - * if not provided then the default MMD read function is used by - * the PHY framework. - */ - void (*write_mmd_indirect)(struct phy_device *dev, int ptrad, - int devnum, int regnum, u32 val); - - /* Get the size and type of the eeprom contained within a plug-in - * module */ - int (*module_info)(struct phy_device *dev, - struct ethtool_modinfo *modinfo); - - /* Get the eeprom information from the plug-in module */ - int (*module_eeprom)(struct phy_device *dev, - struct ethtool_eeprom *ee, u8 *data); - - /* Get statistics from the phy using ethtool */ - int (*get_sset_count)(struct phy_device *dev); - void (*get_strings)(struct phy_device *dev, u8 *data); - void (*get_stats)(struct phy_device *dev, - struct ethtool_stats *stats, u64 *data); -}; -#define to_phy_driver(d) container_of(to_mdio_common_driver(d), \ - struct phy_driver, mdiodrv) - -#define PHY_ANY_ID "MATCH ANY PHY" -#define PHY_ANY_UID 0xffffffff - -/* A Structure for boards to register fixups with the PHY Lib */ -struct phy_fixup { - struct list_head list; - char bus_id[20]; - u32 phy_uid; - u32 phy_uid_mask; - int (*run)(struct phy_device *phydev); -}; - -/** - * phy_read_mmd - Convenience function for reading a register - * from an MMD on a given PHY. - * @phydev: The phy_device struct - * @devad: The MMD to read from - * @regnum: The register on the MMD to read - * - * Same rules as for phy_read(); - */ -static inline int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum) -{ - if (!phydev->is_c45) - return -EOPNOTSUPP; - - return mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, - MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff)); -} - -/** - * phy_read_mmd_indirect - reads data from the MMD registers - * @phydev: The PHY device bus - * @prtad: MMD Address - * @addr: PHY address on the MII bus - * - * Description: it reads data from the MMD registers (clause 22 to access to - * clause 45) of the specified phy address. - */ -int phy_read_mmd_indirect(struct phy_device *phydev, int prtad, int devad); - -/** - * phy_read - Convenience function for reading a given PHY register - * @phydev: the phy_device struct - * @regnum: register number to read - * - * NOTE: MUST NOT be called from interrupt context, - * because the bus read/write functions may wait for an interrupt - * to conclude the operation. - */ -static inline int phy_read(struct phy_device *phydev, u32 regnum) -{ - return mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, regnum); -} - -/** - * phy_write - Convenience function for writing a given PHY register - * @phydev: the phy_device struct - * @regnum: register number to write - * @val: value to write to @regnum - * - * NOTE: MUST NOT be called from interrupt context, - * because the bus read/write functions may wait for an interrupt - * to conclude the operation. - */ -static inline int phy_write(struct phy_device *phydev, u32 regnum, u16 val) -{ - return mdiobus_write(phydev->mdio.bus, phydev->mdio.addr, regnum, val); -} - -/** - * phy_interrupt_is_valid - Convenience function for testing a given PHY irq - * @phydev: the phy_device struct - * - * NOTE: must be kept in sync with addition/removal of PHY_POLL and - * PHY_IGNORE_INTERRUPT - */ -static inline bool phy_interrupt_is_valid(struct phy_device *phydev) -{ - return phydev->irq != PHY_POLL && phydev->irq != PHY_IGNORE_INTERRUPT; -} - -/** - * phy_is_internal - Convenience function for testing if a PHY is internal - * @phydev: the phy_device struct - */ -static inline bool phy_is_internal(struct phy_device *phydev) -{ - return phydev->is_internal; -} - -/** - * phy_interface_is_rgmii - Convenience function for testing if a PHY interface - * is RGMII (all variants) - * @phydev: the phy_device struct - */ -static inline bool phy_interface_is_rgmii(struct phy_device *phydev) -{ - return phydev->interface >= PHY_INTERFACE_MODE_RGMII && - phydev->interface <= PHY_INTERFACE_MODE_RGMII_TXID; -}; - -/* - * phy_is_pseudo_fixed_link - Convenience function for testing if this - * PHY is the CPU port facing side of an Ethernet switch, or similar. - * @phydev: the phy_device struct - */ -static inline bool phy_is_pseudo_fixed_link(struct phy_device *phydev) -{ - return phydev->is_pseudo_fixed_link; -} - -/** - * phy_write_mmd - Convenience function for writing a register - * on an MMD on a given PHY. - * @phydev: The phy_device struct - * @devad: The MMD to read from - * @regnum: The register on the MMD to read - * @val: value to write to @regnum - * - * Same rules as for phy_write(); - */ -static inline int phy_write_mmd(struct phy_device *phydev, int devad, - u32 regnum, u16 val) -{ - if (!phydev->is_c45) - return -EOPNOTSUPP; - - regnum = MII_ADDR_C45 | ((devad & 0x1f) << 16) | (regnum & 0xffff); - - return mdiobus_write(phydev->mdio.bus, phydev->mdio.addr, regnum, val); -} - -/** - * phy_write_mmd_indirect - writes data to the MMD registers - * @phydev: The PHY device - * @prtad: MMD Address - * @devad: MMD DEVAD - * @data: data to write in the MMD register - * - * Description: Write data from the MMD registers of the specified - * phy address. - */ -void phy_write_mmd_indirect(struct phy_device *phydev, int prtad, - int devad, u32 data); - -struct phy_device *phy_device_create(struct mii_bus *bus, int addr, int phy_id, - bool is_c45, - struct phy_c45_device_ids *c45_ids); -struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45); -int phy_device_register(struct phy_device *phy); -void phy_device_remove(struct phy_device *phydev); -int phy_init_hw(struct phy_device *phydev); -int phy_suspend(struct phy_device *phydev); -int phy_resume(struct phy_device *phydev); -struct phy_device *phy_attach(struct net_device *dev, const char *bus_id, - phy_interface_t interface); -struct phy_device *phy_find_first(struct mii_bus *bus); -int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, - u32 flags, phy_interface_t interface); -int phy_connect_direct(struct net_device *dev, struct phy_device *phydev, - void (*handler)(struct net_device *), - phy_interface_t interface); -struct phy_device *phy_connect(struct net_device *dev, const char *bus_id, - void (*handler)(struct net_device *), - phy_interface_t interface); -void phy_disconnect(struct phy_device *phydev); -void phy_detach(struct phy_device *phydev); -void phy_start(struct phy_device *phydev); -void phy_stop(struct phy_device *phydev); -int phy_start_aneg(struct phy_device *phydev); - -int phy_stop_interrupts(struct phy_device *phydev); - -static inline int phy_read_status(struct phy_device *phydev) -{ - return phydev->drv->read_status(phydev); -} - -#define phydev_err(_phydev, format, args...) \ - dev_err(&_phydev->mdio.dev, format, ##args) - -#define phydev_dbg(_phydev, format, args...) \ - dev_dbg(&_phydev->mdio.dev, format, ##args); - -static inline const char *phydev_name(const struct phy_device *phydev) -{ - return dev_name(&phydev->mdio.dev); -} - -void phy_attached_print(struct phy_device *phydev, const char *fmt, ...) - __printf(2, 3); -void phy_attached_info(struct phy_device *phydev); -int genphy_config_init(struct phy_device *phydev); -int genphy_setup_forced(struct phy_device *phydev); -int genphy_restart_aneg(struct phy_device *phydev); -int genphy_config_aneg(struct phy_device *phydev); -int genphy_aneg_done(struct phy_device *phydev); -int genphy_update_link(struct phy_device *phydev); -int genphy_read_status(struct phy_device *phydev); -int genphy_suspend(struct phy_device *phydev); -int genphy_resume(struct phy_device *phydev); -int genphy_soft_reset(struct phy_device *phydev); -void phy_driver_unregister(struct phy_driver *drv); -void phy_drivers_unregister(struct phy_driver *drv, int n); -int phy_driver_register(struct phy_driver *new_driver, struct module *owner); -int phy_drivers_register(struct phy_driver *new_driver, int n, - struct module *owner); -void phy_state_machine(struct work_struct *work); -void phy_change(struct work_struct *work); -void phy_mac_interrupt(struct phy_device *phydev, int new_link); -void phy_start_machine(struct phy_device *phydev); -void phy_stop_machine(struct phy_device *phydev); -int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd); -int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd); -int phy_ethtool_ksettings_get(struct phy_device *phydev, - struct ethtool_link_ksettings *cmd); -int phy_ethtool_ksettings_set(struct phy_device *phydev, - const struct ethtool_link_ksettings *cmd); -int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd); -int phy_start_interrupts(struct phy_device *phydev); -void phy_print_status(struct phy_device *phydev); -void phy_device_free(struct phy_device *phydev); -int phy_set_max_speed(struct phy_device *phydev, u32 max_speed); - -int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask, - int (*run)(struct phy_device *)); -int phy_register_fixup_for_id(const char *bus_id, - int (*run)(struct phy_device *)); -int phy_register_fixup_for_uid(u32 phy_uid, u32 phy_uid_mask, - int (*run)(struct phy_device *)); - -int phy_init_eee(struct phy_device *phydev, bool clk_stop_enable); -int phy_get_eee_err(struct phy_device *phydev); -int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_eee *data); -int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_eee *data); -int phy_ethtool_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol); -void phy_ethtool_get_wol(struct phy_device *phydev, - struct ethtool_wolinfo *wol); -int phy_ethtool_get_link_ksettings(struct net_device *ndev, - struct ethtool_link_ksettings *cmd); -int phy_ethtool_set_link_ksettings(struct net_device *ndev, - const struct ethtool_link_ksettings *cmd); - -int __init mdio_bus_init(void); -void mdio_bus_exit(void); - -extern struct bus_type mdio_bus_type; - -/** - * module_phy_driver() - Helper macro for registering PHY drivers - * @__phy_drivers: array of PHY drivers to register - * - * Helper macro for PHY drivers which do not do anything special in module - * init/exit. Each module may only use this macro once, and calling it - * replaces module_init() and module_exit(). - */ -#define phy_module_driver(__phy_drivers, __count) \ -static int __init phy_module_init(void) \ -{ \ - return phy_drivers_register(__phy_drivers, __count, THIS_MODULE); \ -} \ -module_init(phy_module_init); \ -static void __exit phy_module_exit(void) \ -{ \ - phy_drivers_unregister(__phy_drivers, __count); \ -} \ -module_exit(phy_module_exit) - -#define module_phy_driver(__phy_drivers) \ - phy_module_driver(__phy_drivers, ARRAY_SIZE(__phy_drivers)) - -#endif /* __PHY_H */ diff --git a/src/linux/include/linux/phy_fixed.h b/src/linux/include/linux/phy_fixed.h deleted file mode 100644 index 1d41ec4..0000000 --- a/src/linux/include/linux/phy_fixed.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef __PHY_FIXED_H -#define __PHY_FIXED_H - -struct fixed_phy_status { - int link; - int speed; - int duplex; - int pause; - int asym_pause; -}; - -struct device_node; - -#if IS_ENABLED(CONFIG_FIXED_PHY) -extern int fixed_phy_add(unsigned int irq, int phy_id, - struct fixed_phy_status *status, - int link_gpio); -extern struct phy_device *fixed_phy_register(unsigned int irq, - struct fixed_phy_status *status, - int link_gpio, - struct device_node *np); -extern void fixed_phy_unregister(struct phy_device *phydev); -extern int fixed_phy_set_link_update(struct phy_device *phydev, - int (*link_update)(struct net_device *, - struct fixed_phy_status *)); -extern int fixed_phy_update_state(struct phy_device *phydev, - const struct fixed_phy_status *status, - const struct fixed_phy_status *changed); -#else -static inline int fixed_phy_add(unsigned int irq, int phy_id, - struct fixed_phy_status *status, - int link_gpio) -{ - return -ENODEV; -} -static inline struct phy_device *fixed_phy_register(unsigned int irq, - struct fixed_phy_status *status, - int gpio_link, - struct device_node *np) -{ - return ERR_PTR(-ENODEV); -} -static inline void fixed_phy_unregister(struct phy_device *phydev) -{ -} -static inline int fixed_phy_set_link_update(struct phy_device *phydev, - int (*link_update)(struct net_device *, - struct fixed_phy_status *)) -{ - return -ENODEV; -} -static inline int fixed_phy_update_state(struct phy_device *phydev, - const struct fixed_phy_status *status, - const struct fixed_phy_status *changed) -{ - return -ENODEV; -} -#endif /* CONFIG_FIXED_PHY */ - -#endif /* __PHY_FIXED_H */ diff --git a/src/linux/include/linux/pid.h b/src/linux/include/linux/pid.h deleted file mode 100644 index 23705a5..0000000 --- a/src/linux/include/linux/pid.h +++ /dev/null @@ -1,200 +0,0 @@ -#ifndef _LINUX_PID_H -#define _LINUX_PID_H - -#include - -enum pid_type -{ - PIDTYPE_PID, - PIDTYPE_PGID, - PIDTYPE_SID, - PIDTYPE_MAX -}; - -/* - * What is struct pid? - * - * A struct pid is the kernel's internal notion of a process identifier. - * It refers to individual tasks, process groups, and sessions. While - * there are processes attached to it the struct pid lives in a hash - * table, so it and then the processes that it refers to can be found - * quickly from the numeric pid value. The attached processes may be - * quickly accessed by following pointers from struct pid. - * - * Storing pid_t values in the kernel and referring to them later has a - * problem. The process originally with that pid may have exited and the - * pid allocator wrapped, and another process could have come along - * and been assigned that pid. - * - * Referring to user space processes by holding a reference to struct - * task_struct has a problem. When the user space process exits - * the now useless task_struct is still kept. A task_struct plus a - * stack consumes around 10K of low kernel memory. More precisely - * this is THREAD_SIZE + sizeof(struct task_struct). By comparison - * a struct pid is about 64 bytes. - * - * Holding a reference to struct pid solves both of these problems. - * It is small so holding a reference does not consume a lot of - * resources, and since a new struct pid is allocated when the numeric pid - * value is reused (when pids wrap around) we don't mistakenly refer to new - * processes. - */ - - -/* - * struct upid is used to get the id of the struct pid, as it is - * seen in particular namespace. Later the struct pid is found with - * find_pid_ns() using the int nr and struct pid_namespace *ns. - */ - -struct upid { - /* Try to keep pid_chain in the same cacheline as nr for find_vpid */ - int nr; - struct pid_namespace *ns; - struct hlist_node pid_chain; -}; - -struct pid -{ - atomic_t count; - unsigned int level; - /* lists of tasks that use this pid */ - struct hlist_head tasks[PIDTYPE_MAX]; - struct rcu_head rcu; - struct upid numbers[1]; -}; - -extern struct pid init_struct_pid; - -struct pid_link -{ - struct hlist_node node; - struct pid *pid; -}; - -static inline struct pid *get_pid(struct pid *pid) -{ - if (pid) - atomic_inc(&pid->count); - return pid; -} - -extern void put_pid(struct pid *pid); -extern struct task_struct *pid_task(struct pid *pid, enum pid_type); -extern struct task_struct *get_pid_task(struct pid *pid, enum pid_type); - -extern struct pid *get_task_pid(struct task_struct *task, enum pid_type type); - -/* - * these helpers must be called with the tasklist_lock write-held. - */ -extern void attach_pid(struct task_struct *task, enum pid_type); -extern void detach_pid(struct task_struct *task, enum pid_type); -extern void change_pid(struct task_struct *task, enum pid_type, - struct pid *pid); -extern void transfer_pid(struct task_struct *old, struct task_struct *new, - enum pid_type); - -struct pid_namespace; -extern struct pid_namespace init_pid_ns; - -/* - * look up a PID in the hash table. Must be called with the tasklist_lock - * or rcu_read_lock() held. - * - * find_pid_ns() finds the pid in the namespace specified - * find_vpid() finds the pid by its virtual id, i.e. in the current namespace - * - * see also find_task_by_vpid() set in include/linux/sched.h - */ -extern struct pid *find_pid_ns(int nr, struct pid_namespace *ns); -extern struct pid *find_vpid(int nr); - -/* - * Lookup a PID in the hash table, and return with it's count elevated. - */ -extern struct pid *find_get_pid(int nr); -extern struct pid *find_ge_pid(int nr, struct pid_namespace *); -int next_pidmap(struct pid_namespace *pid_ns, unsigned int last); - -extern struct pid *alloc_pid(struct pid_namespace *ns); -extern void free_pid(struct pid *pid); -extern void disable_pid_allocation(struct pid_namespace *ns); - -/* - * ns_of_pid() returns the pid namespace in which the specified pid was - * allocated. - * - * NOTE: - * ns_of_pid() is expected to be called for a process (task) that has - * an attached 'struct pid' (see attach_pid(), detach_pid()) i.e @pid - * is expected to be non-NULL. If @pid is NULL, caller should handle - * the resulting NULL pid-ns. - */ -static inline struct pid_namespace *ns_of_pid(struct pid *pid) -{ - struct pid_namespace *ns = NULL; - if (pid) - ns = pid->numbers[pid->level].ns; - return ns; -} - -/* - * is_child_reaper returns true if the pid is the init process - * of the current namespace. As this one could be checked before - * pid_ns->child_reaper is assigned in copy_process, we check - * with the pid number. - */ -static inline bool is_child_reaper(struct pid *pid) -{ - return pid->numbers[pid->level].nr == 1; -} - -/* - * the helpers to get the pid's id seen from different namespaces - * - * pid_nr() : global id, i.e. the id seen from the init namespace; - * pid_vnr() : virtual id, i.e. the id seen from the pid namespace of - * current. - * pid_nr_ns() : id seen from the ns specified. - * - * see also task_xid_nr() etc in include/linux/sched.h - */ - -static inline pid_t pid_nr(struct pid *pid) -{ - pid_t nr = 0; - if (pid) - nr = pid->numbers[0].nr; - return nr; -} - -pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns); -pid_t pid_vnr(struct pid *pid); - -#define do_each_pid_task(pid, type, task) \ - do { \ - if ((pid) != NULL) \ - hlist_for_each_entry_rcu((task), \ - &(pid)->tasks[type], pids[type].node) { - - /* - * Both old and new leaders may be attached to - * the same pid in the middle of de_thread(). - */ -#define while_each_pid_task(pid, type, task) \ - if (type == PIDTYPE_PID) \ - break; \ - } \ - } while (0) - -#define do_each_pid_thread(pid, type, task) \ - do_each_pid_task(pid, type, task) { \ - struct task_struct *tg___ = task; \ - do { - -#define while_each_pid_thread(pid, type, task) \ - } while_each_thread(tg___, task); \ - task = tg___; \ - } while_each_pid_task(pid, type, task) -#endif /* _LINUX_PID_H */ diff --git a/src/linux/include/linux/pid_namespace.h b/src/linux/include/linux/pid_namespace.h deleted file mode 100644 index 34cce96..0000000 --- a/src/linux/include/linux/pid_namespace.h +++ /dev/null @@ -1,104 +0,0 @@ -#ifndef _LINUX_PID_NS_H -#define _LINUX_PID_NS_H - -#include -#include -#include -#include -#include -#include -#include -#include - -struct pidmap { - atomic_t nr_free; - void *page; -}; - -#define BITS_PER_PAGE (PAGE_SIZE * 8) -#define BITS_PER_PAGE_MASK (BITS_PER_PAGE-1) -#define PIDMAP_ENTRIES ((PID_MAX_LIMIT+BITS_PER_PAGE-1)/BITS_PER_PAGE) - -struct fs_pin; - -struct pid_namespace { - struct kref kref; - struct pidmap pidmap[PIDMAP_ENTRIES]; - struct rcu_head rcu; - int last_pid; - unsigned int nr_hashed; - struct task_struct *child_reaper; - struct kmem_cache *pid_cachep; - unsigned int level; - struct pid_namespace *parent; -#ifdef CONFIG_PROC_FS - struct vfsmount *proc_mnt; - struct dentry *proc_self; - struct dentry *proc_thread_self; -#endif -#ifdef CONFIG_BSD_PROCESS_ACCT - struct fs_pin *bacct; -#endif - struct user_namespace *user_ns; - struct ucounts *ucounts; - struct work_struct proc_work; - kgid_t pid_gid; - int hide_pid; - int reboot; /* group exit code if this pidns was rebooted */ - struct ns_common ns; -}; - -extern struct pid_namespace init_pid_ns; - -#define PIDNS_HASH_ADDING (1U << 31) - -#ifdef CONFIG_PID_NS -static inline struct pid_namespace *get_pid_ns(struct pid_namespace *ns) -{ - if (ns != &init_pid_ns) - kref_get(&ns->kref); - return ns; -} - -extern struct pid_namespace *copy_pid_ns(unsigned long flags, - struct user_namespace *user_ns, struct pid_namespace *ns); -extern void zap_pid_ns_processes(struct pid_namespace *pid_ns); -extern int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd); -extern void put_pid_ns(struct pid_namespace *ns); - -#else /* !CONFIG_PID_NS */ -#include - -static inline struct pid_namespace *get_pid_ns(struct pid_namespace *ns) -{ - return ns; -} - -static inline struct pid_namespace *copy_pid_ns(unsigned long flags, - struct user_namespace *user_ns, struct pid_namespace *ns) -{ - if (flags & CLONE_NEWPID) - ns = ERR_PTR(-EINVAL); - return ns; -} - -static inline void put_pid_ns(struct pid_namespace *ns) -{ -} - -static inline void zap_pid_ns_processes(struct pid_namespace *ns) -{ - BUG(); -} - -static inline int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd) -{ - return 0; -} -#endif /* CONFIG_PID_NS */ - -extern struct pid_namespace *task_active_pid_ns(struct task_struct *tsk); -void pidhash_init(void); -void pidmap_init(void); - -#endif /* _LINUX_PID_NS_H */ diff --git a/src/linux/include/linux/pim.h b/src/linux/include/linux/pim.h deleted file mode 100644 index e1d756f..0000000 --- a/src/linux/include/linux/pim.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef __LINUX_PIM_H -#define __LINUX_PIM_H - -#include - -/* Message types - V1 */ -#define PIM_V1_VERSION cpu_to_be32(0x10000000) -#define PIM_V1_REGISTER 1 - -/* Message types - V2 */ -#define PIM_VERSION 2 -#define PIM_REGISTER 1 - -#define PIM_NULL_REGISTER cpu_to_be32(0x40000000) - -static inline bool ipmr_pimsm_enabled(void) -{ - return IS_BUILTIN(CONFIG_IP_PIMSM_V1) || IS_BUILTIN(CONFIG_IP_PIMSM_V2); -} - -/* PIMv2 register message header layout (ietf-draft-idmr-pimvsm-v2-00.ps */ -struct pimreghdr -{ - __u8 type; - __u8 reserved; - __be16 csum; - __be32 flags; -}; - -struct sk_buff; -extern int pim_rcv_v1(struct sk_buff *); -#endif diff --git a/src/linux/include/linux/pinctrl/devinfo.h b/src/linux/include/linux/pinctrl/devinfo.h deleted file mode 100644 index 05082e4..0000000 --- a/src/linux/include/linux/pinctrl/devinfo.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Per-device information from the pin control system. - * This is the stuff that get included into the device - * core. - * - * Copyright (C) 2012 ST-Ericsson SA - * Written on behalf of Linaro for ST-Ericsson - * This interface is used in the core to keep track of pins. - * - * Author: Linus Walleij - * - * License terms: GNU General Public License (GPL) version 2 - */ - -#ifndef PINCTRL_DEVINFO_H -#define PINCTRL_DEVINFO_H - -#ifdef CONFIG_PINCTRL - -/* The device core acts as a consumer toward pinctrl */ -#include - -/** - * struct dev_pin_info - pin state container for devices - * @p: pinctrl handle for the containing device - * @default_state: the default state for the handle, if found - * @init_state: the state at probe time, if found - * @sleep_state: the state at suspend time, if found - * @idle_state: the state at idle (runtime suspend) time, if found - */ -struct dev_pin_info { - struct pinctrl *p; - struct pinctrl_state *default_state; - struct pinctrl_state *init_state; -#ifdef CONFIG_PM - struct pinctrl_state *sleep_state; - struct pinctrl_state *idle_state; -#endif -}; - -extern int pinctrl_bind_pins(struct device *dev); -extern int pinctrl_init_done(struct device *dev); - -#else - -/* Stubs if we're not using pinctrl */ - -static inline int pinctrl_bind_pins(struct device *dev) -{ - return 0; -} - -static inline int pinctrl_init_done(struct device *dev) -{ - return 0; -} - -#endif /* CONFIG_PINCTRL */ -#endif /* PINCTRL_DEVINFO_H */ diff --git a/src/linux/include/linux/pipe_fs_i.h b/src/linux/include/linux/pipe_fs_i.h deleted file mode 100644 index e7497c9..0000000 --- a/src/linux/include/linux/pipe_fs_i.h +++ /dev/null @@ -1,194 +0,0 @@ -#ifndef _LINUX_PIPE_FS_I_H -#define _LINUX_PIPE_FS_I_H - -#define PIPE_DEF_BUFFERS 16 - -#define PIPE_BUF_FLAG_LRU 0x01 /* page is on the LRU */ -#define PIPE_BUF_FLAG_ATOMIC 0x02 /* was atomically mapped */ -#define PIPE_BUF_FLAG_GIFT 0x04 /* page is a gift */ -#define PIPE_BUF_FLAG_PACKET 0x08 /* read() as a packet */ - -/** - * struct pipe_buffer - a linux kernel pipe buffer - * @page: the page containing the data for the pipe buffer - * @offset: offset of data inside the @page - * @len: length of data inside the @page - * @ops: operations associated with this buffer. See @pipe_buf_operations. - * @flags: pipe buffer flags. See above. - * @private: private data owned by the ops. - **/ -struct pipe_buffer { - struct page *page; - unsigned int offset, len; - const struct pipe_buf_operations *ops; - unsigned int flags; - unsigned long private; -}; - -/** - * struct pipe_inode_info - a linux kernel pipe - * @mutex: mutex protecting the whole thing - * @wait: reader/writer wait point in case of empty/full pipe - * @nrbufs: the number of non-empty pipe buffers in this pipe - * @buffers: total number of buffers (should be a power of 2) - * @curbuf: the current pipe buffer entry - * @tmp_page: cached released page - * @readers: number of current readers of this pipe - * @writers: number of current writers of this pipe - * @files: number of struct file referring this pipe (protected by ->i_lock) - * @waiting_writers: number of writers blocked waiting for room - * @r_counter: reader counter - * @w_counter: writer counter - * @fasync_readers: reader side fasync - * @fasync_writers: writer side fasync - * @bufs: the circular array of pipe buffers - * @user: the user who created this pipe - **/ -struct pipe_inode_info { - struct mutex mutex; - wait_queue_head_t wait; - unsigned int nrbufs, curbuf, buffers; - unsigned int readers; - unsigned int writers; - unsigned int files; - unsigned int waiting_writers; - unsigned int r_counter; - unsigned int w_counter; - struct page *tmp_page; - struct fasync_struct *fasync_readers; - struct fasync_struct *fasync_writers; - struct pipe_buffer *bufs; - struct user_struct *user; -}; - -/* - * Note on the nesting of these functions: - * - * ->confirm() - * ->steal() - * - * That is, ->steal() must be called on a confirmed buffer. - * See below for the meaning of each operation. Also see kerneldoc - * in fs/pipe.c for the pipe and generic variants of these hooks. - */ -struct pipe_buf_operations { - /* - * This is set to 1, if the generic pipe read/write may coalesce - * data into an existing buffer. If this is set to 0, a new pipe - * page segment is always used for new data. - */ - int can_merge; - - /* - * ->confirm() verifies that the data in the pipe buffer is there - * and that the contents are good. If the pages in the pipe belong - * to a file system, we may need to wait for IO completion in this - * hook. Returns 0 for good, or a negative error value in case of - * error. - */ - int (*confirm)(struct pipe_inode_info *, struct pipe_buffer *); - - /* - * When the contents of this pipe buffer has been completely - * consumed by a reader, ->release() is called. - */ - void (*release)(struct pipe_inode_info *, struct pipe_buffer *); - - /* - * Attempt to take ownership of the pipe buffer and its contents. - * ->steal() returns 0 for success, in which case the contents - * of the pipe (the buf->page) is locked and now completely owned - * by the caller. The page may then be transferred to a different - * mapping, the most often used case is insertion into different - * file address space cache. - */ - int (*steal)(struct pipe_inode_info *, struct pipe_buffer *); - - /* - * Get a reference to the pipe buffer. - */ - void (*get)(struct pipe_inode_info *, struct pipe_buffer *); -}; - -/** - * pipe_buf_get - get a reference to a pipe_buffer - * @pipe: the pipe that the buffer belongs to - * @buf: the buffer to get a reference to - */ -static inline void pipe_buf_get(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) -{ - buf->ops->get(pipe, buf); -} - -/** - * pipe_buf_release - put a reference to a pipe_buffer - * @pipe: the pipe that the buffer belongs to - * @buf: the buffer to put a reference to - */ -static inline void pipe_buf_release(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) -{ - const struct pipe_buf_operations *ops = buf->ops; - - buf->ops = NULL; - ops->release(pipe, buf); -} - -/** - * pipe_buf_confirm - verify contents of the pipe buffer - * @pipe: the pipe that the buffer belongs to - * @buf: the buffer to confirm - */ -static inline int pipe_buf_confirm(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) -{ - return buf->ops->confirm(pipe, buf); -} - -/** - * pipe_buf_steal - attempt to take ownership of a pipe_buffer - * @pipe: the pipe that the buffer belongs to - * @buf: the buffer to attempt to steal - */ -static inline int pipe_buf_steal(struct pipe_inode_info *pipe, - struct pipe_buffer *buf) -{ - return buf->ops->steal(pipe, buf); -} - -/* Differs from PIPE_BUF in that PIPE_SIZE is the length of the actual - memory allocation, whereas PIPE_BUF makes atomicity guarantees. */ -#define PIPE_SIZE PAGE_SIZE - -/* Pipe lock and unlock operations */ -void pipe_lock(struct pipe_inode_info *); -void pipe_unlock(struct pipe_inode_info *); -void pipe_double_lock(struct pipe_inode_info *, struct pipe_inode_info *); - -extern unsigned int pipe_max_size, pipe_min_size; -extern unsigned long pipe_user_pages_hard; -extern unsigned long pipe_user_pages_soft; -int pipe_proc_fn(struct ctl_table *, int, void __user *, size_t *, loff_t *); - -/* Drop the inode semaphore and wait for a pipe event, atomically */ -void pipe_wait(struct pipe_inode_info *pipe); - -struct pipe_inode_info *alloc_pipe_info(void); -void free_pipe_info(struct pipe_inode_info *); - -/* Generic pipe buffer ops functions */ -void generic_pipe_buf_get(struct pipe_inode_info *, struct pipe_buffer *); -int generic_pipe_buf_confirm(struct pipe_inode_info *, struct pipe_buffer *); -int generic_pipe_buf_steal(struct pipe_inode_info *, struct pipe_buffer *); -void generic_pipe_buf_release(struct pipe_inode_info *, struct pipe_buffer *); - -extern const struct pipe_buf_operations nosteal_pipe_buf_ops; - -/* for F_SETPIPE_SZ and F_GETPIPE_SZ */ -long pipe_fcntl(struct file *, unsigned int, unsigned long arg); -struct pipe_inode_info *get_pipe_info(struct file *file); - -int create_pipe_files(struct file **, int); - -#endif diff --git a/src/linux/include/linux/platform_device.h b/src/linux/include/linux/platform_device.h deleted file mode 100644 index 98c2a7c..0000000 --- a/src/linux/include/linux/platform_device.h +++ /dev/null @@ -1,371 +0,0 @@ -/* - * platform_device.h - generic, centralized driver model - * - * Copyright (c) 2001-2003 Patrick Mochel - * - * This file is released under the GPLv2 - * - * See Documentation/driver-model/ for more information. - */ - -#ifndef _PLATFORM_DEVICE_H_ -#define _PLATFORM_DEVICE_H_ - -#include -#include - -#define PLATFORM_DEVID_NONE (-1) -#define PLATFORM_DEVID_AUTO (-2) - -struct mfd_cell; -struct property_entry; - -struct platform_device { - const char *name; - int id; - bool id_auto; - struct device dev; - u32 num_resources; - struct resource *resource; - - const struct platform_device_id *id_entry; - char *driver_override; /* Driver name to force a match */ - - /* MFD cell pointer */ - struct mfd_cell *mfd_cell; - - /* arch specific additions */ - struct pdev_archdata archdata; -}; - -#define platform_get_device_id(pdev) ((pdev)->id_entry) - -#define to_platform_device(x) container_of((x), struct platform_device, dev) - -extern int platform_device_register(struct platform_device *); -extern void platform_device_unregister(struct platform_device *); - -extern struct bus_type platform_bus_type; -extern struct device platform_bus; - -extern void arch_setup_pdev_archdata(struct platform_device *); -extern struct resource *platform_get_resource(struct platform_device *, - unsigned int, unsigned int); -extern int platform_get_irq(struct platform_device *, unsigned int); -extern int platform_irq_count(struct platform_device *); -extern struct resource *platform_get_resource_byname(struct platform_device *, - unsigned int, - const char *); -extern int platform_get_irq_byname(struct platform_device *, const char *); -extern int platform_add_devices(struct platform_device **, int); - -struct platform_device_info { - struct device *parent; - struct fwnode_handle *fwnode; - - const char *name; - int id; - - const struct resource *res; - unsigned int num_res; - - const void *data; - size_t size_data; - u64 dma_mask; - - struct property_entry *properties; -}; -extern struct platform_device *platform_device_register_full( - const struct platform_device_info *pdevinfo); - -/** - * platform_device_register_resndata - add a platform-level device with - * resources and platform-specific data - * - * @parent: parent device for the device we're adding - * @name: base name of the device we're adding - * @id: instance id - * @res: set of resources that needs to be allocated for the device - * @num: number of resources - * @data: platform specific data for this platform device - * @size: size of platform specific data - * - * Returns &struct platform_device pointer on success, or ERR_PTR() on error. - */ -static inline struct platform_device *platform_device_register_resndata( - struct device *parent, const char *name, int id, - const struct resource *res, unsigned int num, - const void *data, size_t size) { - - struct platform_device_info pdevinfo = { - .parent = parent, - .name = name, - .id = id, - .res = res, - .num_res = num, - .data = data, - .size_data = size, - .dma_mask = 0, - }; - - return platform_device_register_full(&pdevinfo); -} - -/** - * platform_device_register_simple - add a platform-level device and its resources - * @name: base name of the device we're adding - * @id: instance id - * @res: set of resources that needs to be allocated for the device - * @num: number of resources - * - * This function creates a simple platform device that requires minimal - * resource and memory management. Canned release function freeing memory - * allocated for the device allows drivers using such devices to be - * unloaded without waiting for the last reference to the device to be - * dropped. - * - * This interface is primarily intended for use with legacy drivers which - * probe hardware directly. Because such drivers create sysfs device nodes - * themselves, rather than letting system infrastructure handle such device - * enumeration tasks, they don't fully conform to the Linux driver model. - * In particular, when such drivers are built as modules, they can't be - * "hotplugged". - * - * Returns &struct platform_device pointer on success, or ERR_PTR() on error. - */ -static inline struct platform_device *platform_device_register_simple( - const char *name, int id, - const struct resource *res, unsigned int num) -{ - return platform_device_register_resndata(NULL, name, id, - res, num, NULL, 0); -} - -/** - * platform_device_register_data - add a platform-level device with platform-specific data - * @parent: parent device for the device we're adding - * @name: base name of the device we're adding - * @id: instance id - * @data: platform specific data for this platform device - * @size: size of platform specific data - * - * This function creates a simple platform device that requires minimal - * resource and memory management. Canned release function freeing memory - * allocated for the device allows drivers using such devices to be - * unloaded without waiting for the last reference to the device to be - * dropped. - * - * Returns &struct platform_device pointer on success, or ERR_PTR() on error. - */ -static inline struct platform_device *platform_device_register_data( - struct device *parent, const char *name, int id, - const void *data, size_t size) -{ - return platform_device_register_resndata(parent, name, id, - NULL, 0, data, size); -} - -extern struct platform_device *platform_device_alloc(const char *name, int id); -extern int platform_device_add_resources(struct platform_device *pdev, - const struct resource *res, - unsigned int num); -extern int platform_device_add_data(struct platform_device *pdev, - const void *data, size_t size); -extern int platform_device_add_properties(struct platform_device *pdev, - struct property_entry *properties); -extern int platform_device_add(struct platform_device *pdev); -extern void platform_device_del(struct platform_device *pdev); -extern void platform_device_put(struct platform_device *pdev); - -struct platform_driver { - int (*probe)(struct platform_device *); - int (*remove)(struct platform_device *); - void (*shutdown)(struct platform_device *); - int (*suspend)(struct platform_device *, pm_message_t state); - int (*resume)(struct platform_device *); - struct device_driver driver; - const struct platform_device_id *id_table; - bool prevent_deferred_probe; -}; - -#define to_platform_driver(drv) (container_of((drv), struct platform_driver, \ - driver)) - -/* - * use a macro to avoid include chaining to get THIS_MODULE - */ -#define platform_driver_register(drv) \ - __platform_driver_register(drv, THIS_MODULE) -extern int __platform_driver_register(struct platform_driver *, - struct module *); -extern void platform_driver_unregister(struct platform_driver *); - -/* non-hotpluggable platform devices may use this so that probe() and - * its support may live in __init sections, conserving runtime memory. - */ -#define platform_driver_probe(drv, probe) \ - __platform_driver_probe(drv, probe, THIS_MODULE) -extern int __platform_driver_probe(struct platform_driver *driver, - int (*probe)(struct platform_device *), struct module *module); - -static inline void *platform_get_drvdata(const struct platform_device *pdev) -{ - return dev_get_drvdata(&pdev->dev); -} - -static inline void platform_set_drvdata(struct platform_device *pdev, - void *data) -{ - dev_set_drvdata(&pdev->dev, data); -} - -/* module_platform_driver() - Helper macro for drivers that don't do - * anything special in module init/exit. This eliminates a lot of - * boilerplate. Each module may only use this macro once, and - * calling it replaces module_init() and module_exit() - */ -#define module_platform_driver(__platform_driver) \ - module_driver(__platform_driver, platform_driver_register, \ - platform_driver_unregister) - -/* builtin_platform_driver() - Helper macro for builtin drivers that - * don't do anything special in driver init. This eliminates some - * boilerplate. Each driver may only use this macro once, and - * calling it replaces device_initcall(). Note this is meant to be - * a parallel of module_platform_driver() above, but w/o _exit stuff. - */ -#define builtin_platform_driver(__platform_driver) \ - builtin_driver(__platform_driver, platform_driver_register) - -/* module_platform_driver_probe() - Helper macro for drivers that don't do - * anything special in module init/exit. This eliminates a lot of - * boilerplate. Each module may only use this macro once, and - * calling it replaces module_init() and module_exit() - */ -#define module_platform_driver_probe(__platform_driver, __platform_probe) \ -static int __init __platform_driver##_init(void) \ -{ \ - return platform_driver_probe(&(__platform_driver), \ - __platform_probe); \ -} \ -module_init(__platform_driver##_init); \ -static void __exit __platform_driver##_exit(void) \ -{ \ - platform_driver_unregister(&(__platform_driver)); \ -} \ -module_exit(__platform_driver##_exit); - -/* builtin_platform_driver_probe() - Helper macro for drivers that don't do - * anything special in device init. This eliminates some boilerplate. Each - * driver may only use this macro once, and using it replaces device_initcall. - * This is meant to be a parallel of module_platform_driver_probe above, but - * without the __exit parts. - */ -#define builtin_platform_driver_probe(__platform_driver, __platform_probe) \ -static int __init __platform_driver##_init(void) \ -{ \ - return platform_driver_probe(&(__platform_driver), \ - __platform_probe); \ -} \ -device_initcall(__platform_driver##_init); \ - -#define platform_create_bundle(driver, probe, res, n_res, data, size) \ - __platform_create_bundle(driver, probe, res, n_res, data, size, THIS_MODULE) -extern struct platform_device *__platform_create_bundle( - struct platform_driver *driver, int (*probe)(struct platform_device *), - struct resource *res, unsigned int n_res, - const void *data, size_t size, struct module *module); - -int __platform_register_drivers(struct platform_driver * const *drivers, - unsigned int count, struct module *owner); -void platform_unregister_drivers(struct platform_driver * const *drivers, - unsigned int count); - -#define platform_register_drivers(drivers, count) \ - __platform_register_drivers(drivers, count, THIS_MODULE) - -/* early platform driver interface */ -struct early_platform_driver { - const char *class_str; - struct platform_driver *pdrv; - struct list_head list; - int requested_id; - char *buffer; - int bufsize; -}; - -#define EARLY_PLATFORM_ID_UNSET -2 -#define EARLY_PLATFORM_ID_ERROR -3 - -extern int early_platform_driver_register(struct early_platform_driver *epdrv, - char *buf); -extern void early_platform_add_devices(struct platform_device **devs, int num); - -static inline int is_early_platform_device(struct platform_device *pdev) -{ - return !pdev->dev.driver; -} - -extern void early_platform_driver_register_all(char *class_str); -extern int early_platform_driver_probe(char *class_str, - int nr_probe, int user_only); -extern void early_platform_cleanup(void); - -#define early_platform_init(class_string, platdrv) \ - early_platform_init_buffer(class_string, platdrv, NULL, 0) - -#ifndef MODULE -#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \ -static __initdata struct early_platform_driver early_driver = { \ - .class_str = class_string, \ - .buffer = buf, \ - .bufsize = bufsiz, \ - .pdrv = platdrv, \ - .requested_id = EARLY_PLATFORM_ID_UNSET, \ -}; \ -static int __init early_platform_driver_setup_func(char *buffer) \ -{ \ - return early_platform_driver_register(&early_driver, buffer); \ -} \ -early_param(class_string, early_platform_driver_setup_func) -#else /* MODULE */ -#define early_platform_init_buffer(class_string, platdrv, buf, bufsiz) \ -static inline char *early_platform_driver_setup_func(void) \ -{ \ - return bufsiz ? buf : NULL; \ -} -#endif /* MODULE */ - -#ifdef CONFIG_SUSPEND -extern int platform_pm_suspend(struct device *dev); -extern int platform_pm_resume(struct device *dev); -#else -#define platform_pm_suspend NULL -#define platform_pm_resume NULL -#endif - -#ifdef CONFIG_HIBERNATE_CALLBACKS -extern int platform_pm_freeze(struct device *dev); -extern int platform_pm_thaw(struct device *dev); -extern int platform_pm_poweroff(struct device *dev); -extern int platform_pm_restore(struct device *dev); -#else -#define platform_pm_freeze NULL -#define platform_pm_thaw NULL -#define platform_pm_poweroff NULL -#define platform_pm_restore NULL -#endif - -#ifdef CONFIG_PM_SLEEP -#define USE_PLATFORM_PM_SLEEP_OPS \ - .suspend = platform_pm_suspend, \ - .resume = platform_pm_resume, \ - .freeze = platform_pm_freeze, \ - .thaw = platform_pm_thaw, \ - .poweroff = platform_pm_poweroff, \ - .restore = platform_pm_restore, -#else -#define USE_PLATFORM_PM_SLEEP_OPS -#endif - -#endif /* _PLATFORM_DEVICE_H_ */ diff --git a/src/linux/include/linux/plist.h b/src/linux/include/linux/plist.h deleted file mode 100644 index 9788360..0000000 --- a/src/linux/include/linux/plist.h +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Descending-priority-sorted double-linked list - * - * (C) 2002-2003 Intel Corp - * Inaky Perez-Gonzalez . - * - * 2001-2005 (c) MontaVista Software, Inc. - * Daniel Walker - * - * (C) 2005 Thomas Gleixner - * - * Simplifications of the original code by - * Oleg Nesterov - * - * Licensed under the FSF's GNU Public License v2 or later. - * - * Based on simple lists (include/linux/list.h). - * - * This is a priority-sorted list of nodes; each node has a - * priority from INT_MIN (highest) to INT_MAX (lowest). - * - * Addition is O(K), removal is O(1), change of priority of a node is - * O(K) and K is the number of RT priority levels used in the system. - * (1 <= K <= 99) - * - * This list is really a list of lists: - * - * - The tier 1 list is the prio_list, different priority nodes. - * - * - The tier 2 list is the node_list, serialized nodes. - * - * Simple ASCII art explanation: - * - * pl:prio_list (only for plist_node) - * nl:node_list - * HEAD| NODE(S) - * | - * ||------------------------------------| - * ||->|pl|<->|pl|<--------------->|pl|<-| - * | |10| |21| |21| |21| |40| (prio) - * | | | | | | | | | | | - * | | | | | | | | | | | - * |->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<->|nl|<-| - * |-------------------------------------------| - * - * The nodes on the prio_list list are sorted by priority to simplify - * the insertion of new nodes. There are no nodes with duplicate - * priorites on the list. - * - * The nodes on the node_list are ordered by priority and can contain - * entries which have the same priority. Those entries are ordered - * FIFO - * - * Addition means: look for the prio_list node in the prio_list - * for the priority of the node and insert it before the node_list - * entry of the next prio_list node. If it is the first node of - * that priority, add it to the prio_list in the right position and - * insert it into the serialized node_list list - * - * Removal means remove it from the node_list and remove it from - * the prio_list if the node_list list_head is non empty. In case - * of removal from the prio_list it must be checked whether other - * entries of the same priority are on the list or not. If there - * is another entry of the same priority then this entry has to - * replace the removed entry on the prio_list. If the entry which - * is removed is the only entry of this priority then a simple - * remove from both list is sufficient. - * - * INT_MIN is the highest priority, 0 is the medium highest, INT_MAX - * is lowest priority. - * - * No locking is done, up to the caller. - * - */ -#ifndef _LINUX_PLIST_H_ -#define _LINUX_PLIST_H_ - -#include -#include - -struct plist_head { - struct list_head node_list; -}; - -struct plist_node { - int prio; - struct list_head prio_list; - struct list_head node_list; -}; - -/** - * PLIST_HEAD_INIT - static struct plist_head initializer - * @head: struct plist_head variable name - */ -#define PLIST_HEAD_INIT(head) \ -{ \ - .node_list = LIST_HEAD_INIT((head).node_list) \ -} - -/** - * PLIST_HEAD - declare and init plist_head - * @head: name for struct plist_head variable - */ -#define PLIST_HEAD(head) \ - struct plist_head head = PLIST_HEAD_INIT(head) - -/** - * PLIST_NODE_INIT - static struct plist_node initializer - * @node: struct plist_node variable name - * @__prio: initial node priority - */ -#define PLIST_NODE_INIT(node, __prio) \ -{ \ - .prio = (__prio), \ - .prio_list = LIST_HEAD_INIT((node).prio_list), \ - .node_list = LIST_HEAD_INIT((node).node_list), \ -} - -/** - * plist_head_init - dynamic struct plist_head initializer - * @head: &struct plist_head pointer - */ -static inline void -plist_head_init(struct plist_head *head) -{ - INIT_LIST_HEAD(&head->node_list); -} - -/** - * plist_node_init - Dynamic struct plist_node initializer - * @node: &struct plist_node pointer - * @prio: initial node priority - */ -static inline void plist_node_init(struct plist_node *node, int prio) -{ - node->prio = prio; - INIT_LIST_HEAD(&node->prio_list); - INIT_LIST_HEAD(&node->node_list); -} - -extern void plist_add(struct plist_node *node, struct plist_head *head); -extern void plist_del(struct plist_node *node, struct plist_head *head); - -extern void plist_requeue(struct plist_node *node, struct plist_head *head); - -/** - * plist_for_each - iterate over the plist - * @pos: the type * to use as a loop counter - * @head: the head for your list - */ -#define plist_for_each(pos, head) \ - list_for_each_entry(pos, &(head)->node_list, node_list) - -/** - * plist_for_each_continue - continue iteration over the plist - * @pos: the type * to use as a loop cursor - * @head: the head for your list - * - * Continue to iterate over plist, continuing after the current position. - */ -#define plist_for_each_continue(pos, head) \ - list_for_each_entry_continue(pos, &(head)->node_list, node_list) - -/** - * plist_for_each_safe - iterate safely over a plist of given type - * @pos: the type * to use as a loop counter - * @n: another type * to use as temporary storage - * @head: the head for your list - * - * Iterate over a plist of given type, safe against removal of list entry. - */ -#define plist_for_each_safe(pos, n, head) \ - list_for_each_entry_safe(pos, n, &(head)->node_list, node_list) - -/** - * plist_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop counter - * @head: the head for your list - * @mem: the name of the list_head within the struct - */ -#define plist_for_each_entry(pos, head, mem) \ - list_for_each_entry(pos, &(head)->node_list, mem.node_list) - -/** - * plist_for_each_entry_continue - continue iteration over list of given type - * @pos: the type * to use as a loop cursor - * @head: the head for your list - * @m: the name of the list_head within the struct - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define plist_for_each_entry_continue(pos, head, m) \ - list_for_each_entry_continue(pos, &(head)->node_list, m.node_list) - -/** - * plist_for_each_entry_safe - iterate safely over list of given type - * @pos: the type * to use as a loop counter - * @n: another type * to use as temporary storage - * @head: the head for your list - * @m: the name of the list_head within the struct - * - * Iterate over list of given type, safe against removal of list entry. - */ -#define plist_for_each_entry_safe(pos, n, head, m) \ - list_for_each_entry_safe(pos, n, &(head)->node_list, m.node_list) - -/** - * plist_head_empty - return !0 if a plist_head is empty - * @head: &struct plist_head pointer - */ -static inline int plist_head_empty(const struct plist_head *head) -{ - return list_empty(&head->node_list); -} - -/** - * plist_node_empty - return !0 if plist_node is not on a list - * @node: &struct plist_node pointer - */ -static inline int plist_node_empty(const struct plist_node *node) -{ - return list_empty(&node->node_list); -} - -/* All functions below assume the plist_head is not empty. */ - -/** - * plist_first_entry - get the struct for the first entry - * @head: the &struct plist_head pointer - * @type: the type of the struct this is embedded in - * @member: the name of the list_head within the struct - */ -#ifdef CONFIG_DEBUG_PI_LIST -# define plist_first_entry(head, type, member) \ -({ \ - WARN_ON(plist_head_empty(head)); \ - container_of(plist_first(head), type, member); \ -}) -#else -# define plist_first_entry(head, type, member) \ - container_of(plist_first(head), type, member) -#endif - -/** - * plist_last_entry - get the struct for the last entry - * @head: the &struct plist_head pointer - * @type: the type of the struct this is embedded in - * @member: the name of the list_head within the struct - */ -#ifdef CONFIG_DEBUG_PI_LIST -# define plist_last_entry(head, type, member) \ -({ \ - WARN_ON(plist_head_empty(head)); \ - container_of(plist_last(head), type, member); \ -}) -#else -# define plist_last_entry(head, type, member) \ - container_of(plist_last(head), type, member) -#endif - -/** - * plist_next - get the next entry in list - * @pos: the type * to cursor - */ -#define plist_next(pos) \ - list_next_entry(pos, node_list) - -/** - * plist_prev - get the prev entry in list - * @pos: the type * to cursor - */ -#define plist_prev(pos) \ - list_prev_entry(pos, node_list) - -/** - * plist_first - return the first node (and thus, highest priority) - * @head: the &struct plist_head pointer - * - * Assumes the plist is _not_ empty. - */ -static inline struct plist_node *plist_first(const struct plist_head *head) -{ - return list_entry(head->node_list.next, - struct plist_node, node_list); -} - -/** - * plist_last - return the last node (and thus, lowest priority) - * @head: the &struct plist_head pointer - * - * Assumes the plist is _not_ empty. - */ -static inline struct plist_node *plist_last(const struct plist_head *head) -{ - return list_entry(head->node_list.prev, - struct plist_node, node_list); -} - -#endif diff --git a/src/linux/include/linux/pm.h b/src/linux/include/linux/pm.h deleted file mode 100644 index 06eb353..0000000 --- a/src/linux/include/linux/pm.h +++ /dev/null @@ -1,789 +0,0 @@ -/* - * pm.h - Power management interface - * - * Copyright (C) 2000 Andrew Henroid - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _LINUX_PM_H -#define _LINUX_PM_H - -#include -#include -#include -#include -#include -#include - -/* - * Callbacks for platform drivers to implement. - */ -extern void (*pm_power_off)(void); -extern void (*pm_power_off_prepare)(void); - -struct device; /* we have a circular dep with device.h */ -#ifdef CONFIG_VT_CONSOLE_SLEEP -extern void pm_vt_switch_required(struct device *dev, bool required); -extern void pm_vt_switch_unregister(struct device *dev); -#else -static inline void pm_vt_switch_required(struct device *dev, bool required) -{ -} -static inline void pm_vt_switch_unregister(struct device *dev) -{ -} -#endif /* CONFIG_VT_CONSOLE_SLEEP */ - -/* - * Device power management - */ - -struct device; - -#ifdef CONFIG_PM -extern const char power_group_name[]; /* = "power" */ -#else -#define power_group_name NULL -#endif - -typedef struct pm_message { - int event; -} pm_message_t; - -/** - * struct dev_pm_ops - device PM callbacks - * - * Several device power state transitions are externally visible, affecting - * the state of pending I/O queues and (for drivers that touch hardware) - * interrupts, wakeups, DMA, and other hardware state. There may also be - * internal transitions to various low-power modes which are transparent - * to the rest of the driver stack (such as a driver that's ON gating off - * clocks which are not in active use). - * - * The externally visible transitions are handled with the help of callbacks - * included in this structure in such a way that two levels of callbacks are - * involved. First, the PM core executes callbacks provided by PM domains, - * device types, classes and bus types. They are the subsystem-level callbacks - * supposed to execute callbacks provided by device drivers, although they may - * choose not to do that. If the driver callbacks are executed, they have to - * collaborate with the subsystem-level callbacks to achieve the goals - * appropriate for the given system transition, given transition phase and the - * subsystem the device belongs to. - * - * @prepare: The principal role of this callback is to prevent new children of - * the device from being registered after it has returned (the driver's - * subsystem and generally the rest of the kernel is supposed to prevent - * new calls to the probe method from being made too once @prepare() has - * succeeded). If @prepare() detects a situation it cannot handle (e.g. - * registration of a child already in progress), it may return -EAGAIN, so - * that the PM core can execute it once again (e.g. after a new child has - * been registered) to recover from the race condition. - * This method is executed for all kinds of suspend transitions and is - * followed by one of the suspend callbacks: @suspend(), @freeze(), or - * @poweroff(). If the transition is a suspend to memory or standby (that - * is, not related to hibernation), the return value of @prepare() may be - * used to indicate to the PM core to leave the device in runtime suspend - * if applicable. Namely, if @prepare() returns a positive number, the PM - * core will understand that as a declaration that the device appears to be - * runtime-suspended and it may be left in that state during the entire - * transition and during the subsequent resume if all of its descendants - * are left in runtime suspend too. If that happens, @complete() will be - * executed directly after @prepare() and it must ensure the proper - * functioning of the device after the system resume. - * The PM core executes subsystem-level @prepare() for all devices before - * starting to invoke suspend callbacks for any of them, so generally - * devices may be assumed to be functional or to respond to runtime resume - * requests while @prepare() is being executed. However, device drivers - * may NOT assume anything about the availability of user space at that - * time and it is NOT valid to request firmware from within @prepare() - * (it's too late to do that). It also is NOT valid to allocate - * substantial amounts of memory from @prepare() in the GFP_KERNEL mode. - * [To work around these limitations, drivers may register suspend and - * hibernation notifiers to be executed before the freezing of tasks.] - * - * @complete: Undo the changes made by @prepare(). This method is executed for - * all kinds of resume transitions, following one of the resume callbacks: - * @resume(), @thaw(), @restore(). Also called if the state transition - * fails before the driver's suspend callback: @suspend(), @freeze() or - * @poweroff(), can be executed (e.g. if the suspend callback fails for one - * of the other devices that the PM core has unsuccessfully attempted to - * suspend earlier). - * The PM core executes subsystem-level @complete() after it has executed - * the appropriate resume callbacks for all devices. If the corresponding - * @prepare() at the beginning of the suspend transition returned a - * positive number and the device was left in runtime suspend (without - * executing any suspend and resume callbacks for it), @complete() will be - * the only callback executed for the device during resume. In that case, - * @complete() must be prepared to do whatever is necessary to ensure the - * proper functioning of the device after the system resume. To this end, - * @complete() can check the power.direct_complete flag of the device to - * learn whether (unset) or not (set) the previous suspend and resume - * callbacks have been executed for it. - * - * @suspend: Executed before putting the system into a sleep state in which the - * contents of main memory are preserved. The exact action to perform - * depends on the device's subsystem (PM domain, device type, class or bus - * type), but generally the device must be quiescent after subsystem-level - * @suspend() has returned, so that it doesn't do any I/O or DMA. - * Subsystem-level @suspend() is executed for all devices after invoking - * subsystem-level @prepare() for all of them. - * - * @suspend_late: Continue operations started by @suspend(). For a number of - * devices @suspend_late() may point to the same callback routine as the - * runtime suspend callback. - * - * @resume: Executed after waking the system up from a sleep state in which the - * contents of main memory were preserved. The exact action to perform - * depends on the device's subsystem, but generally the driver is expected - * to start working again, responding to hardware events and software - * requests (the device itself may be left in a low-power state, waiting - * for a runtime resume to occur). The state of the device at the time its - * driver's @resume() callback is run depends on the platform and subsystem - * the device belongs to. On most platforms, there are no restrictions on - * availability of resources like clocks during @resume(). - * Subsystem-level @resume() is executed for all devices after invoking - * subsystem-level @resume_noirq() for all of them. - * - * @resume_early: Prepare to execute @resume(). For a number of devices - * @resume_early() may point to the same callback routine as the runtime - * resume callback. - * - * @freeze: Hibernation-specific, executed before creating a hibernation image. - * Analogous to @suspend(), but it should not enable the device to signal - * wakeup events or change its power state. The majority of subsystems - * (with the notable exception of the PCI bus type) expect the driver-level - * @freeze() to save the device settings in memory to be used by @restore() - * during the subsequent resume from hibernation. - * Subsystem-level @freeze() is executed for all devices after invoking - * subsystem-level @prepare() for all of them. - * - * @freeze_late: Continue operations started by @freeze(). Analogous to - * @suspend_late(), but it should not enable the device to signal wakeup - * events or change its power state. - * - * @thaw: Hibernation-specific, executed after creating a hibernation image OR - * if the creation of an image has failed. Also executed after a failing - * attempt to restore the contents of main memory from such an image. - * Undo the changes made by the preceding @freeze(), so the device can be - * operated in the same way as immediately before the call to @freeze(). - * Subsystem-level @thaw() is executed for all devices after invoking - * subsystem-level @thaw_noirq() for all of them. It also may be executed - * directly after @freeze() in case of a transition error. - * - * @thaw_early: Prepare to execute @thaw(). Undo the changes made by the - * preceding @freeze_late(). - * - * @poweroff: Hibernation-specific, executed after saving a hibernation image. - * Analogous to @suspend(), but it need not save the device's settings in - * memory. - * Subsystem-level @poweroff() is executed for all devices after invoking - * subsystem-level @prepare() for all of them. - * - * @poweroff_late: Continue operations started by @poweroff(). Analogous to - * @suspend_late(), but it need not save the device's settings in memory. - * - * @restore: Hibernation-specific, executed after restoring the contents of main - * memory from a hibernation image, analogous to @resume(). - * - * @restore_early: Prepare to execute @restore(), analogous to @resume_early(). - * - * @suspend_noirq: Complete the actions started by @suspend(). Carry out any - * additional operations required for suspending the device that might be - * racing with its driver's interrupt handler, which is guaranteed not to - * run while @suspend_noirq() is being executed. - * It generally is expected that the device will be in a low-power state - * (appropriate for the target system sleep state) after subsystem-level - * @suspend_noirq() has returned successfully. If the device can generate - * system wakeup signals and is enabled to wake up the system, it should be - * configured to do so at that time. However, depending on the platform - * and device's subsystem, @suspend() or @suspend_late() may be allowed to - * put the device into the low-power state and configure it to generate - * wakeup signals, in which case it generally is not necessary to define - * @suspend_noirq(). - * - * @resume_noirq: Prepare for the execution of @resume() by carrying out any - * operations required for resuming the device that might be racing with - * its driver's interrupt handler, which is guaranteed not to run while - * @resume_noirq() is being executed. - * - * @freeze_noirq: Complete the actions started by @freeze(). Carry out any - * additional operations required for freezing the device that might be - * racing with its driver's interrupt handler, which is guaranteed not to - * run while @freeze_noirq() is being executed. - * The power state of the device should not be changed by either @freeze(), - * or @freeze_late(), or @freeze_noirq() and it should not be configured to - * signal system wakeup by any of these callbacks. - * - * @thaw_noirq: Prepare for the execution of @thaw() by carrying out any - * operations required for thawing the device that might be racing with its - * driver's interrupt handler, which is guaranteed not to run while - * @thaw_noirq() is being executed. - * - * @poweroff_noirq: Complete the actions started by @poweroff(). Analogous to - * @suspend_noirq(), but it need not save the device's settings in memory. - * - * @restore_noirq: Prepare for the execution of @restore() by carrying out any - * operations required for thawing the device that might be racing with its - * driver's interrupt handler, which is guaranteed not to run while - * @restore_noirq() is being executed. Analogous to @resume_noirq(). - * - * All of the above callbacks, except for @complete(), return error codes. - * However, the error codes returned by the resume operations, @resume(), - * @thaw(), @restore(), @resume_noirq(), @thaw_noirq(), and @restore_noirq(), do - * not cause the PM core to abort the resume transition during which they are - * returned. The error codes returned in those cases are only printed by the PM - * core to the system logs for debugging purposes. Still, it is recommended - * that drivers only return error codes from their resume methods in case of an - * unrecoverable failure (i.e. when the device being handled refuses to resume - * and becomes unusable) to allow us to modify the PM core in the future, so - * that it can avoid attempting to handle devices that failed to resume and - * their children. - * - * It is allowed to unregister devices while the above callbacks are being - * executed. However, a callback routine must NOT try to unregister the device - * it was called for, although it may unregister children of that device (for - * example, if it detects that a child was unplugged while the system was - * asleep). - * - * Refer to Documentation/power/devices.txt for more information about the role - * of the above callbacks in the system suspend process. - * - * There also are callbacks related to runtime power management of devices. - * Again, these callbacks are executed by the PM core only for subsystems - * (PM domains, device types, classes and bus types) and the subsystem-level - * callbacks are supposed to invoke the driver callbacks. Moreover, the exact - * actions to be performed by a device driver's callbacks generally depend on - * the platform and subsystem the device belongs to. - * - * @runtime_suspend: Prepare the device for a condition in which it won't be - * able to communicate with the CPU(s) and RAM due to power management. - * This need not mean that the device should be put into a low-power state. - * For example, if the device is behind a link which is about to be turned - * off, the device may remain at full power. If the device does go to low - * power and is capable of generating runtime wakeup events, remote wakeup - * (i.e., a hardware mechanism allowing the device to request a change of - * its power state via an interrupt) should be enabled for it. - * - * @runtime_resume: Put the device into the fully active state in response to a - * wakeup event generated by hardware or at the request of software. If - * necessary, put the device into the full-power state and restore its - * registers, so that it is fully operational. - * - * @runtime_idle: Device appears to be inactive and it might be put into a - * low-power state if all of the necessary conditions are satisfied. - * Check these conditions, and return 0 if it's appropriate to let the PM - * core queue a suspend request for the device. - * - * Refer to Documentation/power/runtime_pm.txt for more information about the - * role of the above callbacks in device runtime power management. - * - */ - -struct dev_pm_ops { - int (*prepare)(struct device *dev); - void (*complete)(struct device *dev); - int (*suspend)(struct device *dev); - int (*resume)(struct device *dev); - int (*freeze)(struct device *dev); - int (*thaw)(struct device *dev); - int (*poweroff)(struct device *dev); - int (*restore)(struct device *dev); - int (*suspend_late)(struct device *dev); - int (*resume_early)(struct device *dev); - int (*freeze_late)(struct device *dev); - int (*thaw_early)(struct device *dev); - int (*poweroff_late)(struct device *dev); - int (*restore_early)(struct device *dev); - int (*suspend_noirq)(struct device *dev); - int (*resume_noirq)(struct device *dev); - int (*freeze_noirq)(struct device *dev); - int (*thaw_noirq)(struct device *dev); - int (*poweroff_noirq)(struct device *dev); - int (*restore_noirq)(struct device *dev); - int (*runtime_suspend)(struct device *dev); - int (*runtime_resume)(struct device *dev); - int (*runtime_idle)(struct device *dev); -}; - -#ifdef CONFIG_PM_SLEEP -#define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ - .suspend = suspend_fn, \ - .resume = resume_fn, \ - .freeze = suspend_fn, \ - .thaw = resume_fn, \ - .poweroff = suspend_fn, \ - .restore = resume_fn, -#else -#define SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) -#endif - -#ifdef CONFIG_PM_SLEEP -#define SET_LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ - .suspend_late = suspend_fn, \ - .resume_early = resume_fn, \ - .freeze_late = suspend_fn, \ - .thaw_early = resume_fn, \ - .poweroff_late = suspend_fn, \ - .restore_early = resume_fn, -#else -#define SET_LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) -#endif - -#ifdef CONFIG_PM_SLEEP -#define SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ - .suspend_noirq = suspend_fn, \ - .resume_noirq = resume_fn, \ - .freeze_noirq = suspend_fn, \ - .thaw_noirq = resume_fn, \ - .poweroff_noirq = suspend_fn, \ - .restore_noirq = resume_fn, -#else -#define SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) -#endif - -#ifdef CONFIG_PM -#define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \ - .runtime_suspend = suspend_fn, \ - .runtime_resume = resume_fn, \ - .runtime_idle = idle_fn, -#else -#define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) -#endif - -/* - * Use this if you want to use the same suspend and resume callbacks for suspend - * to RAM and hibernation. - */ -#define SIMPLE_DEV_PM_OPS(name, suspend_fn, resume_fn) \ -const struct dev_pm_ops name = { \ - SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ -} - -/* - * Use this for defining a set of PM operations to be used in all situations - * (system suspend, hibernation or runtime PM). - * NOTE: In general, system suspend callbacks, .suspend() and .resume(), should - * be different from the corresponding runtime PM callbacks, .runtime_suspend(), - * and .runtime_resume(), because .runtime_suspend() always works on an already - * quiescent device, while .suspend() should assume that the device may be doing - * something when it is called (it should ensure that the device will be - * quiescent after it has returned). Therefore it's better to point the "late" - * suspend and "early" resume callback pointers, .suspend_late() and - * .resume_early(), to the same routines as .runtime_suspend() and - * .runtime_resume(), respectively (and analogously for hibernation). - */ -#define UNIVERSAL_DEV_PM_OPS(name, suspend_fn, resume_fn, idle_fn) \ -const struct dev_pm_ops name = { \ - SET_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn) \ - SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \ -} - -/** - * PM_EVENT_ messages - * - * The following PM_EVENT_ messages are defined for the internal use of the PM - * core, in order to provide a mechanism allowing the high level suspend and - * hibernation code to convey the necessary information to the device PM core - * code: - * - * ON No transition. - * - * FREEZE System is going to hibernate, call ->prepare() and ->freeze() - * for all devices. - * - * SUSPEND System is going to suspend, call ->prepare() and ->suspend() - * for all devices. - * - * HIBERNATE Hibernation image has been saved, call ->prepare() and - * ->poweroff() for all devices. - * - * QUIESCE Contents of main memory are going to be restored from a (loaded) - * hibernation image, call ->prepare() and ->freeze() for all - * devices. - * - * RESUME System is resuming, call ->resume() and ->complete() for all - * devices. - * - * THAW Hibernation image has been created, call ->thaw() and - * ->complete() for all devices. - * - * RESTORE Contents of main memory have been restored from a hibernation - * image, call ->restore() and ->complete() for all devices. - * - * RECOVER Creation of a hibernation image or restoration of the main - * memory contents from a hibernation image has failed, call - * ->thaw() and ->complete() for all devices. - * - * The following PM_EVENT_ messages are defined for internal use by - * kernel subsystems. They are never issued by the PM core. - * - * USER_SUSPEND Manual selective suspend was issued by userspace. - * - * USER_RESUME Manual selective resume was issued by userspace. - * - * REMOTE_WAKEUP Remote-wakeup request was received from the device. - * - * AUTO_SUSPEND Automatic (device idle) runtime suspend was - * initiated by the subsystem. - * - * AUTO_RESUME Automatic (device needed) runtime resume was - * requested by a driver. - */ - -#define PM_EVENT_INVALID (-1) -#define PM_EVENT_ON 0x0000 -#define PM_EVENT_FREEZE 0x0001 -#define PM_EVENT_SUSPEND 0x0002 -#define PM_EVENT_HIBERNATE 0x0004 -#define PM_EVENT_QUIESCE 0x0008 -#define PM_EVENT_RESUME 0x0010 -#define PM_EVENT_THAW 0x0020 -#define PM_EVENT_RESTORE 0x0040 -#define PM_EVENT_RECOVER 0x0080 -#define PM_EVENT_USER 0x0100 -#define PM_EVENT_REMOTE 0x0200 -#define PM_EVENT_AUTO 0x0400 - -#define PM_EVENT_SLEEP (PM_EVENT_SUSPEND | PM_EVENT_HIBERNATE) -#define PM_EVENT_USER_SUSPEND (PM_EVENT_USER | PM_EVENT_SUSPEND) -#define PM_EVENT_USER_RESUME (PM_EVENT_USER | PM_EVENT_RESUME) -#define PM_EVENT_REMOTE_RESUME (PM_EVENT_REMOTE | PM_EVENT_RESUME) -#define PM_EVENT_AUTO_SUSPEND (PM_EVENT_AUTO | PM_EVENT_SUSPEND) -#define PM_EVENT_AUTO_RESUME (PM_EVENT_AUTO | PM_EVENT_RESUME) - -#define PMSG_INVALID ((struct pm_message){ .event = PM_EVENT_INVALID, }) -#define PMSG_ON ((struct pm_message){ .event = PM_EVENT_ON, }) -#define PMSG_FREEZE ((struct pm_message){ .event = PM_EVENT_FREEZE, }) -#define PMSG_QUIESCE ((struct pm_message){ .event = PM_EVENT_QUIESCE, }) -#define PMSG_SUSPEND ((struct pm_message){ .event = PM_EVENT_SUSPEND, }) -#define PMSG_HIBERNATE ((struct pm_message){ .event = PM_EVENT_HIBERNATE, }) -#define PMSG_RESUME ((struct pm_message){ .event = PM_EVENT_RESUME, }) -#define PMSG_THAW ((struct pm_message){ .event = PM_EVENT_THAW, }) -#define PMSG_RESTORE ((struct pm_message){ .event = PM_EVENT_RESTORE, }) -#define PMSG_RECOVER ((struct pm_message){ .event = PM_EVENT_RECOVER, }) -#define PMSG_USER_SUSPEND ((struct pm_message) \ - { .event = PM_EVENT_USER_SUSPEND, }) -#define PMSG_USER_RESUME ((struct pm_message) \ - { .event = PM_EVENT_USER_RESUME, }) -#define PMSG_REMOTE_RESUME ((struct pm_message) \ - { .event = PM_EVENT_REMOTE_RESUME, }) -#define PMSG_AUTO_SUSPEND ((struct pm_message) \ - { .event = PM_EVENT_AUTO_SUSPEND, }) -#define PMSG_AUTO_RESUME ((struct pm_message) \ - { .event = PM_EVENT_AUTO_RESUME, }) - -#define PMSG_IS_AUTO(msg) (((msg).event & PM_EVENT_AUTO) != 0) - -/** - * Device run-time power management status. - * - * These status labels are used internally by the PM core to indicate the - * current status of a device with respect to the PM core operations. They do - * not reflect the actual power state of the device or its status as seen by the - * driver. - * - * RPM_ACTIVE Device is fully operational. Indicates that the device - * bus type's ->runtime_resume() callback has completed - * successfully. - * - * RPM_SUSPENDED Device bus type's ->runtime_suspend() callback has - * completed successfully. The device is regarded as - * suspended. - * - * RPM_RESUMING Device bus type's ->runtime_resume() callback is being - * executed. - * - * RPM_SUSPENDING Device bus type's ->runtime_suspend() callback is being - * executed. - */ - -enum rpm_status { - RPM_ACTIVE = 0, - RPM_RESUMING, - RPM_SUSPENDED, - RPM_SUSPENDING, -}; - -/** - * Device run-time power management request types. - * - * RPM_REQ_NONE Do nothing. - * - * RPM_REQ_IDLE Run the device bus type's ->runtime_idle() callback - * - * RPM_REQ_SUSPEND Run the device bus type's ->runtime_suspend() callback - * - * RPM_REQ_AUTOSUSPEND Same as RPM_REQ_SUSPEND, but not until the device has - * been inactive for as long as power.autosuspend_delay - * - * RPM_REQ_RESUME Run the device bus type's ->runtime_resume() callback - */ - -enum rpm_request { - RPM_REQ_NONE = 0, - RPM_REQ_IDLE, - RPM_REQ_SUSPEND, - RPM_REQ_AUTOSUSPEND, - RPM_REQ_RESUME, -}; - -struct wakeup_source; -struct wake_irq; -struct pm_domain_data; - -struct pm_subsys_data { - spinlock_t lock; - unsigned int refcount; -#ifdef CONFIG_PM_CLK - struct list_head clock_list; -#endif -#ifdef CONFIG_PM_GENERIC_DOMAINS - struct pm_domain_data *domain_data; -#endif -}; - -struct dev_pm_info { - pm_message_t power_state; - unsigned int can_wakeup:1; - unsigned int async_suspend:1; - bool is_prepared:1; /* Owned by the PM core */ - bool is_suspended:1; /* Ditto */ - bool is_noirq_suspended:1; - bool is_late_suspended:1; - bool early_init:1; /* Owned by the PM core */ - bool direct_complete:1; /* Owned by the PM core */ - spinlock_t lock; -#ifdef CONFIG_PM_SLEEP - struct list_head entry; - struct completion completion; - struct wakeup_source *wakeup; - bool wakeup_path:1; - bool syscore:1; - bool no_pm_callbacks:1; /* Owned by the PM core */ -#else - unsigned int should_wakeup:1; -#endif -#ifdef CONFIG_PM - struct timer_list suspend_timer; - unsigned long timer_expires; - struct work_struct work; - wait_queue_head_t wait_queue; - struct wake_irq *wakeirq; - atomic_t usage_count; - atomic_t child_count; - unsigned int disable_depth:3; - unsigned int idle_notification:1; - unsigned int request_pending:1; - unsigned int deferred_resume:1; - unsigned int run_wake:1; - unsigned int runtime_auto:1; - bool ignore_children:1; - unsigned int no_callbacks:1; - unsigned int irq_safe:1; - unsigned int use_autosuspend:1; - unsigned int timer_autosuspends:1; - unsigned int memalloc_noio:1; - enum rpm_request request; - enum rpm_status runtime_status; - int runtime_error; - int autosuspend_delay; - unsigned long last_busy; - unsigned long active_jiffies; - unsigned long suspended_jiffies; - unsigned long accounting_timestamp; -#endif - struct pm_subsys_data *subsys_data; /* Owned by the subsystem. */ - void (*set_latency_tolerance)(struct device *, s32); - struct dev_pm_qos *qos; -}; - -extern void update_pm_runtime_accounting(struct device *dev); -extern int dev_pm_get_subsys_data(struct device *dev); -extern void dev_pm_put_subsys_data(struct device *dev); - -/* - * Power domains provide callbacks that are executed during system suspend, - * hibernation, system resume and during runtime PM transitions along with - * subsystem-level and driver-level callbacks. - * - * @detach: Called when removing a device from the domain. - * @activate: Called before executing probe routines for bus types and drivers. - * @sync: Called after successful driver probe. - * @dismiss: Called after unsuccessful driver probe and after driver removal. - */ -struct dev_pm_domain { - struct dev_pm_ops ops; - void (*detach)(struct device *dev, bool power_off); - int (*activate)(struct device *dev); - void (*sync)(struct device *dev); - void (*dismiss)(struct device *dev); -}; - -/* - * The PM_EVENT_ messages are also used by drivers implementing the legacy - * suspend framework, based on the ->suspend() and ->resume() callbacks common - * for suspend and hibernation transitions, according to the rules below. - */ - -/* Necessary, because several drivers use PM_EVENT_PRETHAW */ -#define PM_EVENT_PRETHAW PM_EVENT_QUIESCE - -/* - * One transition is triggered by resume(), after a suspend() call; the - * message is implicit: - * - * ON Driver starts working again, responding to hardware events - * and software requests. The hardware may have gone through - * a power-off reset, or it may have maintained state from the - * previous suspend() which the driver will rely on while - * resuming. On most platforms, there are no restrictions on - * availability of resources like clocks during resume(). - * - * Other transitions are triggered by messages sent using suspend(). All - * these transitions quiesce the driver, so that I/O queues are inactive. - * That commonly entails turning off IRQs and DMA; there may be rules - * about how to quiesce that are specific to the bus or the device's type. - * (For example, network drivers mark the link state.) Other details may - * differ according to the message: - * - * SUSPEND Quiesce, enter a low power device state appropriate for - * the upcoming system state (such as PCI_D3hot), and enable - * wakeup events as appropriate. - * - * HIBERNATE Enter a low power device state appropriate for the hibernation - * state (eg. ACPI S4) and enable wakeup events as appropriate. - * - * FREEZE Quiesce operations so that a consistent image can be saved; - * but do NOT otherwise enter a low power device state, and do - * NOT emit system wakeup events. - * - * PRETHAW Quiesce as if for FREEZE; additionally, prepare for restoring - * the system from a snapshot taken after an earlier FREEZE. - * Some drivers will need to reset their hardware state instead - * of preserving it, to ensure that it's never mistaken for the - * state which that earlier snapshot had set up. - * - * A minimally power-aware driver treats all messages as SUSPEND, fully - * reinitializes its device during resume() -- whether or not it was reset - * during the suspend/resume cycle -- and can't issue wakeup events. - * - * More power-aware drivers may also use low power states at runtime as - * well as during system sleep states like PM_SUSPEND_STANDBY. They may - * be able to use wakeup events to exit from runtime low-power states, - * or from system low-power states such as standby or suspend-to-RAM. - */ - -#ifdef CONFIG_PM_SLEEP -extern void device_pm_lock(void); -extern void dpm_resume_start(pm_message_t state); -extern void dpm_resume_end(pm_message_t state); -extern void dpm_resume_noirq(pm_message_t state); -extern void dpm_resume_early(pm_message_t state); -extern void dpm_resume(pm_message_t state); -extern void dpm_complete(pm_message_t state); - -extern void device_pm_unlock(void); -extern int dpm_suspend_end(pm_message_t state); -extern int dpm_suspend_start(pm_message_t state); -extern int dpm_suspend_noirq(pm_message_t state); -extern int dpm_suspend_late(pm_message_t state); -extern int dpm_suspend(pm_message_t state); -extern int dpm_prepare(pm_message_t state); - -extern void __suspend_report_result(const char *function, void *fn, int ret); - -#define suspend_report_result(fn, ret) \ - do { \ - __suspend_report_result(__func__, fn, ret); \ - } while (0) - -extern int device_pm_wait_for_dev(struct device *sub, struct device *dev); -extern void dpm_for_each_dev(void *data, void (*fn)(struct device *, void *)); - -extern int pm_generic_prepare(struct device *dev); -extern int pm_generic_suspend_late(struct device *dev); -extern int pm_generic_suspend_noirq(struct device *dev); -extern int pm_generic_suspend(struct device *dev); -extern int pm_generic_resume_early(struct device *dev); -extern int pm_generic_resume_noirq(struct device *dev); -extern int pm_generic_resume(struct device *dev); -extern int pm_generic_freeze_noirq(struct device *dev); -extern int pm_generic_freeze_late(struct device *dev); -extern int pm_generic_freeze(struct device *dev); -extern int pm_generic_thaw_noirq(struct device *dev); -extern int pm_generic_thaw_early(struct device *dev); -extern int pm_generic_thaw(struct device *dev); -extern int pm_generic_restore_noirq(struct device *dev); -extern int pm_generic_restore_early(struct device *dev); -extern int pm_generic_restore(struct device *dev); -extern int pm_generic_poweroff_noirq(struct device *dev); -extern int pm_generic_poweroff_late(struct device *dev); -extern int pm_generic_poweroff(struct device *dev); -extern void pm_generic_complete(struct device *dev); -extern void pm_complete_with_resume_check(struct device *dev); - -#else /* !CONFIG_PM_SLEEP */ - -#define device_pm_lock() do {} while (0) -#define device_pm_unlock() do {} while (0) - -static inline int dpm_suspend_start(pm_message_t state) -{ - return 0; -} - -#define suspend_report_result(fn, ret) do {} while (0) - -static inline int device_pm_wait_for_dev(struct device *a, struct device *b) -{ - return 0; -} - -static inline void dpm_for_each_dev(void *data, void (*fn)(struct device *, void *)) -{ -} - -#define pm_generic_prepare NULL -#define pm_generic_suspend_late NULL -#define pm_generic_suspend_noirq NULL -#define pm_generic_suspend NULL -#define pm_generic_resume_early NULL -#define pm_generic_resume_noirq NULL -#define pm_generic_resume NULL -#define pm_generic_freeze_noirq NULL -#define pm_generic_freeze_late NULL -#define pm_generic_freeze NULL -#define pm_generic_thaw_noirq NULL -#define pm_generic_thaw_early NULL -#define pm_generic_thaw NULL -#define pm_generic_restore_noirq NULL -#define pm_generic_restore_early NULL -#define pm_generic_restore NULL -#define pm_generic_poweroff_noirq NULL -#define pm_generic_poweroff_late NULL -#define pm_generic_poweroff NULL -#define pm_generic_complete NULL -#endif /* !CONFIG_PM_SLEEP */ - -/* How to reorder dpm_list after device_move() */ -enum dpm_order { - DPM_ORDER_NONE, - DPM_ORDER_DEV_AFTER_PARENT, - DPM_ORDER_PARENT_BEFORE_DEV, - DPM_ORDER_DEV_LAST, -}; - -#endif /* _LINUX_PM_H */ diff --git a/src/linux/include/linux/pm_domain.h b/src/linux/include/linux/pm_domain.h deleted file mode 100644 index a09fe5c..0000000 --- a/src/linux/include/linux/pm_domain.h +++ /dev/null @@ -1,263 +0,0 @@ -/* - * pm_domain.h - Definitions and headers related to device power domains. - * - * Copyright (C) 2011 Rafael J. Wysocki , Renesas Electronics Corp. - * - * This file is released under the GPLv2. - */ - -#ifndef _LINUX_PM_DOMAIN_H -#define _LINUX_PM_DOMAIN_H - -#include -#include -#include -#include -#include -#include - -/* Defines used for the flags field in the struct generic_pm_domain */ -#define GENPD_FLAG_PM_CLK (1U << 0) /* PM domain uses PM clk */ - -#define GENPD_MAX_NUM_STATES 8 /* Number of possible low power states */ - -enum gpd_status { - GPD_STATE_ACTIVE = 0, /* PM domain is active */ - GPD_STATE_POWER_OFF, /* PM domain is off */ -}; - -struct dev_power_governor { - bool (*power_down_ok)(struct dev_pm_domain *domain); - bool (*suspend_ok)(struct device *dev); -}; - -struct gpd_dev_ops { - int (*start)(struct device *dev); - int (*stop)(struct device *dev); - bool (*active_wakeup)(struct device *dev); -}; - -struct genpd_power_state { - s64 power_off_latency_ns; - s64 power_on_latency_ns; -}; - -struct generic_pm_domain { - struct dev_pm_domain domain; /* PM domain operations */ - struct list_head gpd_list_node; /* Node in the global PM domains list */ - struct list_head master_links; /* Links with PM domain as a master */ - struct list_head slave_links; /* Links with PM domain as a slave */ - struct list_head dev_list; /* List of devices */ - struct mutex lock; - struct dev_power_governor *gov; - struct work_struct power_off_work; - struct fwnode_handle *provider; /* Identity of the domain provider */ - bool has_provider; - const char *name; - atomic_t sd_count; /* Number of subdomains with power "on" */ - enum gpd_status status; /* Current state of the domain */ - unsigned int device_count; /* Number of devices */ - unsigned int suspended_count; /* System suspend device counter */ - unsigned int prepared_count; /* Suspend counter of prepared devices */ - int (*power_off)(struct generic_pm_domain *domain); - int (*power_on)(struct generic_pm_domain *domain); - struct gpd_dev_ops dev_ops; - s64 max_off_time_ns; /* Maximum allowed "suspended" time. */ - bool max_off_time_changed; - bool cached_power_down_ok; - int (*attach_dev)(struct generic_pm_domain *domain, - struct device *dev); - void (*detach_dev)(struct generic_pm_domain *domain, - struct device *dev); - unsigned int flags; /* Bit field of configs for genpd */ - struct genpd_power_state states[GENPD_MAX_NUM_STATES]; - unsigned int state_count; /* number of states */ - unsigned int state_idx; /* state that genpd will go to when off */ - -}; - -static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd) -{ - return container_of(pd, struct generic_pm_domain, domain); -} - -struct gpd_link { - struct generic_pm_domain *master; - struct list_head master_node; - struct generic_pm_domain *slave; - struct list_head slave_node; -}; - -struct gpd_timing_data { - s64 suspend_latency_ns; - s64 resume_latency_ns; - s64 effective_constraint_ns; - bool constraint_changed; - bool cached_suspend_ok; -}; - -struct pm_domain_data { - struct list_head list_node; - struct device *dev; -}; - -struct generic_pm_domain_data { - struct pm_domain_data base; - struct gpd_timing_data td; - struct notifier_block nb; -}; - -#ifdef CONFIG_PM_GENERIC_DOMAINS -static inline struct generic_pm_domain_data *to_gpd_data(struct pm_domain_data *pdd) -{ - return container_of(pdd, struct generic_pm_domain_data, base); -} - -static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev) -{ - return to_gpd_data(dev->power.subsys_data->domain_data); -} - -extern int __pm_genpd_add_device(struct generic_pm_domain *genpd, - struct device *dev, - struct gpd_timing_data *td); - -extern int pm_genpd_remove_device(struct generic_pm_domain *genpd, - struct device *dev); -extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, - struct generic_pm_domain *new_subdomain); -extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, - struct generic_pm_domain *target); -extern int pm_genpd_init(struct generic_pm_domain *genpd, - struct dev_power_governor *gov, bool is_off); -extern int pm_genpd_remove(struct generic_pm_domain *genpd); - -extern struct dev_power_governor simple_qos_governor; -extern struct dev_power_governor pm_domain_always_on_gov; -#else - -static inline struct generic_pm_domain_data *dev_gpd_data(struct device *dev) -{ - return ERR_PTR(-ENOSYS); -} -static inline int __pm_genpd_add_device(struct generic_pm_domain *genpd, - struct device *dev, - struct gpd_timing_data *td) -{ - return -ENOSYS; -} -static inline int pm_genpd_remove_device(struct generic_pm_domain *genpd, - struct device *dev) -{ - return -ENOSYS; -} -static inline int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, - struct generic_pm_domain *new_sd) -{ - return -ENOSYS; -} -static inline int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, - struct generic_pm_domain *target) -{ - return -ENOSYS; -} -static inline int pm_genpd_init(struct generic_pm_domain *genpd, - struct dev_power_governor *gov, bool is_off) -{ - return -ENOSYS; -} -static inline int pm_genpd_remove(struct generic_pm_domain *genpd) -{ - return -ENOTSUPP; -} -#endif - -static inline int pm_genpd_add_device(struct generic_pm_domain *genpd, - struct device *dev) -{ - return __pm_genpd_add_device(genpd, dev, NULL); -} - -#ifdef CONFIG_PM_GENERIC_DOMAINS_SLEEP -extern void pm_genpd_syscore_poweroff(struct device *dev); -extern void pm_genpd_syscore_poweron(struct device *dev); -#else -static inline void pm_genpd_syscore_poweroff(struct device *dev) {} -static inline void pm_genpd_syscore_poweron(struct device *dev) {} -#endif - -/* OF PM domain providers */ -struct of_device_id; - -struct genpd_onecell_data { - struct generic_pm_domain **domains; - unsigned int num_domains; -}; - -#ifdef CONFIG_PM_GENERIC_DOMAINS_OF -int of_genpd_add_provider_simple(struct device_node *np, - struct generic_pm_domain *genpd); -int of_genpd_add_provider_onecell(struct device_node *np, - struct genpd_onecell_data *data); -void of_genpd_del_provider(struct device_node *np); -extern int of_genpd_add_device(struct of_phandle_args *args, - struct device *dev); -extern int of_genpd_add_subdomain(struct of_phandle_args *parent, - struct of_phandle_args *new_subdomain); -extern struct generic_pm_domain *of_genpd_remove_last(struct device_node *np); - -int genpd_dev_pm_attach(struct device *dev); -#else /* !CONFIG_PM_GENERIC_DOMAINS_OF */ -static inline int of_genpd_add_provider_simple(struct device_node *np, - struct generic_pm_domain *genpd) -{ - return -ENOTSUPP; -} - -static inline int of_genpd_add_provider_onecell(struct device_node *np, - struct genpd_onecell_data *data) -{ - return -ENOTSUPP; -} - -static inline void of_genpd_del_provider(struct device_node *np) {} - -static inline int of_genpd_add_device(struct of_phandle_args *args, - struct device *dev) -{ - return -ENODEV; -} - -static inline int of_genpd_add_subdomain(struct of_phandle_args *parent, - struct of_phandle_args *new_subdomain) -{ - return -ENODEV; -} - -static inline int genpd_dev_pm_attach(struct device *dev) -{ - return -ENODEV; -} - -static inline -struct generic_pm_domain *of_genpd_remove_last(struct device_node *np) -{ - return ERR_PTR(-ENOTSUPP); -} -#endif /* CONFIG_PM_GENERIC_DOMAINS_OF */ - -#ifdef CONFIG_PM -extern int dev_pm_domain_attach(struct device *dev, bool power_on); -extern void dev_pm_domain_detach(struct device *dev, bool power_off); -extern void dev_pm_domain_set(struct device *dev, struct dev_pm_domain *pd); -#else -static inline int dev_pm_domain_attach(struct device *dev, bool power_on) -{ - return -ENODEV; -} -static inline void dev_pm_domain_detach(struct device *dev, bool power_off) {} -static inline void dev_pm_domain_set(struct device *dev, - struct dev_pm_domain *pd) {} -#endif - -#endif /* _LINUX_PM_DOMAIN_H */ diff --git a/src/linux/include/linux/pm_qos.h b/src/linux/include/linux/pm_qos.h deleted file mode 100644 index 0f65d36..0000000 --- a/src/linux/include/linux/pm_qos.h +++ /dev/null @@ -1,242 +0,0 @@ -#ifndef _LINUX_PM_QOS_H -#define _LINUX_PM_QOS_H -/* interface for the pm_qos_power infrastructure of the linux kernel. - * - * Mark Gross - */ -#include -#include -#include -#include -#include - -enum { - PM_QOS_RESERVED = 0, - PM_QOS_CPU_DMA_LATENCY, - PM_QOS_NETWORK_LATENCY, - PM_QOS_NETWORK_THROUGHPUT, - PM_QOS_MEMORY_BANDWIDTH, - - /* insert new class ID */ - PM_QOS_NUM_CLASSES, -}; - -enum pm_qos_flags_status { - PM_QOS_FLAGS_UNDEFINED = -1, - PM_QOS_FLAGS_NONE, - PM_QOS_FLAGS_SOME, - PM_QOS_FLAGS_ALL, -}; - -#define PM_QOS_DEFAULT_VALUE -1 - -#define PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) -#define PM_QOS_NETWORK_LAT_DEFAULT_VALUE (2000 * USEC_PER_SEC) -#define PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE 0 -#define PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE 0 -#define PM_QOS_RESUME_LATENCY_DEFAULT_VALUE 0 -#define PM_QOS_LATENCY_TOLERANCE_DEFAULT_VALUE 0 -#define PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT (-1) -#define PM_QOS_LATENCY_ANY ((s32)(~(__u32)0 >> 1)) - -#define PM_QOS_FLAG_NO_POWER_OFF (1 << 0) -#define PM_QOS_FLAG_REMOTE_WAKEUP (1 << 1) - -struct pm_qos_request { - struct plist_node node; - int pm_qos_class; - struct delayed_work work; /* for pm_qos_update_request_timeout */ -}; - -struct pm_qos_flags_request { - struct list_head node; - s32 flags; /* Do not change to 64 bit */ -}; - -enum dev_pm_qos_req_type { - DEV_PM_QOS_RESUME_LATENCY = 1, - DEV_PM_QOS_LATENCY_TOLERANCE, - DEV_PM_QOS_FLAGS, -}; - -struct dev_pm_qos_request { - enum dev_pm_qos_req_type type; - union { - struct plist_node pnode; - struct pm_qos_flags_request flr; - } data; - struct device *dev; -}; - -enum pm_qos_type { - PM_QOS_UNITIALIZED, - PM_QOS_MAX, /* return the largest value */ - PM_QOS_MIN, /* return the smallest value */ - PM_QOS_SUM /* return the sum */ -}; - -/* - * Note: The lockless read path depends on the CPU accessing target_value - * or effective_flags atomically. Atomic access is only guaranteed on all CPU - * types linux supports for 32 bit quantites - */ -struct pm_qos_constraints { - struct plist_head list; - s32 target_value; /* Do not change to 64 bit */ - s32 default_value; - s32 no_constraint_value; - enum pm_qos_type type; - struct blocking_notifier_head *notifiers; -}; - -struct pm_qos_flags { - struct list_head list; - s32 effective_flags; /* Do not change to 64 bit */ -}; - -struct dev_pm_qos { - struct pm_qos_constraints resume_latency; - struct pm_qos_constraints latency_tolerance; - struct pm_qos_flags flags; - struct dev_pm_qos_request *resume_latency_req; - struct dev_pm_qos_request *latency_tolerance_req; - struct dev_pm_qos_request *flags_req; -}; - -/* Action requested to pm_qos_update_target */ -enum pm_qos_req_action { - PM_QOS_ADD_REQ, /* Add a new request */ - PM_QOS_UPDATE_REQ, /* Update an existing request */ - PM_QOS_REMOVE_REQ /* Remove an existing request */ -}; - -static inline int dev_pm_qos_request_active(struct dev_pm_qos_request *req) -{ - return req->dev != NULL; -} - -int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node, - enum pm_qos_req_action action, int value); -bool pm_qos_update_flags(struct pm_qos_flags *pqf, - struct pm_qos_flags_request *req, - enum pm_qos_req_action action, s32 val); -void pm_qos_add_request(struct pm_qos_request *req, int pm_qos_class, - s32 value); -void pm_qos_update_request(struct pm_qos_request *req, - s32 new_value); -void pm_qos_update_request_timeout(struct pm_qos_request *req, - s32 new_value, unsigned long timeout_us); -void pm_qos_remove_request(struct pm_qos_request *req); - -int pm_qos_request(int pm_qos_class); -int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier); -int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier); -int pm_qos_request_active(struct pm_qos_request *req); -s32 pm_qos_read_value(struct pm_qos_constraints *c); - -#ifdef CONFIG_PM -enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask); -enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, s32 mask); -s32 __dev_pm_qos_read_value(struct device *dev); -s32 dev_pm_qos_read_value(struct device *dev); -int dev_pm_qos_add_request(struct device *dev, struct dev_pm_qos_request *req, - enum dev_pm_qos_req_type type, s32 value); -int dev_pm_qos_update_request(struct dev_pm_qos_request *req, s32 new_value); -int dev_pm_qos_remove_request(struct dev_pm_qos_request *req); -int dev_pm_qos_add_notifier(struct device *dev, - struct notifier_block *notifier); -int dev_pm_qos_remove_notifier(struct device *dev, - struct notifier_block *notifier); -int dev_pm_qos_add_global_notifier(struct notifier_block *notifier); -int dev_pm_qos_remove_global_notifier(struct notifier_block *notifier); -void dev_pm_qos_constraints_init(struct device *dev); -void dev_pm_qos_constraints_destroy(struct device *dev); -int dev_pm_qos_add_ancestor_request(struct device *dev, - struct dev_pm_qos_request *req, - enum dev_pm_qos_req_type type, s32 value); -int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value); -void dev_pm_qos_hide_latency_limit(struct device *dev); -int dev_pm_qos_expose_flags(struct device *dev, s32 value); -void dev_pm_qos_hide_flags(struct device *dev); -int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set); -s32 dev_pm_qos_get_user_latency_tolerance(struct device *dev); -int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val); -int dev_pm_qos_expose_latency_tolerance(struct device *dev); -void dev_pm_qos_hide_latency_tolerance(struct device *dev); - -static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) -{ - return dev->power.qos->resume_latency_req->data.pnode.prio; -} - -static inline s32 dev_pm_qos_requested_flags(struct device *dev) -{ - return dev->power.qos->flags_req->data.flr.flags; -} -#else -static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, - s32 mask) - { return PM_QOS_FLAGS_UNDEFINED; } -static inline enum pm_qos_flags_status dev_pm_qos_flags(struct device *dev, - s32 mask) - { return PM_QOS_FLAGS_UNDEFINED; } -static inline s32 __dev_pm_qos_read_value(struct device *dev) - { return 0; } -static inline s32 dev_pm_qos_read_value(struct device *dev) - { return 0; } -static inline int dev_pm_qos_add_request(struct device *dev, - struct dev_pm_qos_request *req, - enum dev_pm_qos_req_type type, - s32 value) - { return 0; } -static inline int dev_pm_qos_update_request(struct dev_pm_qos_request *req, - s32 new_value) - { return 0; } -static inline int dev_pm_qos_remove_request(struct dev_pm_qos_request *req) - { return 0; } -static inline int dev_pm_qos_add_notifier(struct device *dev, - struct notifier_block *notifier) - { return 0; } -static inline int dev_pm_qos_remove_notifier(struct device *dev, - struct notifier_block *notifier) - { return 0; } -static inline int dev_pm_qos_add_global_notifier( - struct notifier_block *notifier) - { return 0; } -static inline int dev_pm_qos_remove_global_notifier( - struct notifier_block *notifier) - { return 0; } -static inline void dev_pm_qos_constraints_init(struct device *dev) -{ - dev->power.power_state = PMSG_ON; -} -static inline void dev_pm_qos_constraints_destroy(struct device *dev) -{ - dev->power.power_state = PMSG_INVALID; -} -static inline int dev_pm_qos_add_ancestor_request(struct device *dev, - struct dev_pm_qos_request *req, - enum dev_pm_qos_req_type type, - s32 value) - { return 0; } -static inline int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value) - { return 0; } -static inline void dev_pm_qos_hide_latency_limit(struct device *dev) {} -static inline int dev_pm_qos_expose_flags(struct device *dev, s32 value) - { return 0; } -static inline void dev_pm_qos_hide_flags(struct device *dev) {} -static inline int dev_pm_qos_update_flags(struct device *dev, s32 m, bool set) - { return 0; } -static inline s32 dev_pm_qos_get_user_latency_tolerance(struct device *dev) - { return PM_QOS_LATENCY_TOLERANCE_NO_CONSTRAINT; } -static inline int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val) - { return 0; } -static inline int dev_pm_qos_expose_latency_tolerance(struct device *dev) - { return 0; } -static inline void dev_pm_qos_hide_latency_tolerance(struct device *dev) {} - -static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev) { return 0; } -static inline s32 dev_pm_qos_requested_flags(struct device *dev) { return 0; } -#endif - -#endif diff --git a/src/linux/include/linux/pm_runtime.h b/src/linux/include/linux/pm_runtime.h deleted file mode 100644 index 2e14d26..0000000 --- a/src/linux/include/linux/pm_runtime.h +++ /dev/null @@ -1,288 +0,0 @@ -/* - * pm_runtime.h - Device run-time power management helper functions. - * - * Copyright (C) 2009 Rafael J. Wysocki - * - * This file is released under the GPLv2. - */ - -#ifndef _LINUX_PM_RUNTIME_H -#define _LINUX_PM_RUNTIME_H - -#include -#include -#include - -#include - -/* Runtime PM flag argument bits */ -#define RPM_ASYNC 0x01 /* Request is asynchronous */ -#define RPM_NOWAIT 0x02 /* Don't wait for concurrent - state change */ -#define RPM_GET_PUT 0x04 /* Increment/decrement the - usage_count */ -#define RPM_AUTO 0x08 /* Use autosuspend_delay */ - -#ifdef CONFIG_PM -extern struct workqueue_struct *pm_wq; - -static inline bool queue_pm_work(struct work_struct *work) -{ - return queue_work(pm_wq, work); -} - -extern int pm_generic_runtime_suspend(struct device *dev); -extern int pm_generic_runtime_resume(struct device *dev); -extern int pm_runtime_force_suspend(struct device *dev); -extern int pm_runtime_force_resume(struct device *dev); - -extern int __pm_runtime_idle(struct device *dev, int rpmflags); -extern int __pm_runtime_suspend(struct device *dev, int rpmflags); -extern int __pm_runtime_resume(struct device *dev, int rpmflags); -extern int pm_runtime_get_if_in_use(struct device *dev); -extern int pm_schedule_suspend(struct device *dev, unsigned int delay); -extern int __pm_runtime_set_status(struct device *dev, unsigned int status); -extern int pm_runtime_barrier(struct device *dev); -extern void pm_runtime_enable(struct device *dev); -extern void __pm_runtime_disable(struct device *dev, bool check_resume); -extern void pm_runtime_allow(struct device *dev); -extern void pm_runtime_forbid(struct device *dev); -extern void pm_runtime_no_callbacks(struct device *dev); -extern void pm_runtime_irq_safe(struct device *dev); -extern void __pm_runtime_use_autosuspend(struct device *dev, bool use); -extern void pm_runtime_set_autosuspend_delay(struct device *dev, int delay); -extern unsigned long pm_runtime_autosuspend_expiration(struct device *dev); -extern void pm_runtime_update_max_time_suspended(struct device *dev, - s64 delta_ns); -extern void pm_runtime_set_memalloc_noio(struct device *dev, bool enable); - -static inline void pm_suspend_ignore_children(struct device *dev, bool enable) -{ - dev->power.ignore_children = enable; -} - -static inline bool pm_children_suspended(struct device *dev) -{ - return dev->power.ignore_children - || !atomic_read(&dev->power.child_count); -} - -static inline void pm_runtime_get_noresume(struct device *dev) -{ - atomic_inc(&dev->power.usage_count); -} - -static inline void pm_runtime_put_noidle(struct device *dev) -{ - atomic_add_unless(&dev->power.usage_count, -1, 0); -} - -static inline bool device_run_wake(struct device *dev) -{ - return dev->power.run_wake; -} - -static inline void device_set_run_wake(struct device *dev, bool enable) -{ - dev->power.run_wake = enable; -} - -static inline bool pm_runtime_suspended(struct device *dev) -{ - return dev->power.runtime_status == RPM_SUSPENDED - && !dev->power.disable_depth; -} - -static inline bool pm_runtime_active(struct device *dev) -{ - return dev->power.runtime_status == RPM_ACTIVE - || dev->power.disable_depth; -} - -static inline bool pm_runtime_status_suspended(struct device *dev) -{ - return dev->power.runtime_status == RPM_SUSPENDED; -} - -static inline bool pm_runtime_enabled(struct device *dev) -{ - return !dev->power.disable_depth; -} - -static inline bool pm_runtime_callbacks_present(struct device *dev) -{ - return !dev->power.no_callbacks; -} - -static inline void pm_runtime_mark_last_busy(struct device *dev) -{ - ACCESS_ONCE(dev->power.last_busy) = jiffies; -} - -static inline bool pm_runtime_is_irq_safe(struct device *dev) -{ - return dev->power.irq_safe; -} - -#else /* !CONFIG_PM */ - -static inline bool queue_pm_work(struct work_struct *work) { return false; } - -static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; } -static inline int pm_generic_runtime_resume(struct device *dev) { return 0; } -static inline int pm_runtime_force_suspend(struct device *dev) { return 0; } -static inline int pm_runtime_force_resume(struct device *dev) { return 0; } - -static inline int __pm_runtime_idle(struct device *dev, int rpmflags) -{ - return -ENOSYS; -} -static inline int __pm_runtime_suspend(struct device *dev, int rpmflags) -{ - return -ENOSYS; -} -static inline int __pm_runtime_resume(struct device *dev, int rpmflags) -{ - return 1; -} -static inline int pm_schedule_suspend(struct device *dev, unsigned int delay) -{ - return -ENOSYS; -} -static inline int pm_runtime_get_if_in_use(struct device *dev) -{ - return -EINVAL; -} -static inline int __pm_runtime_set_status(struct device *dev, - unsigned int status) { return 0; } -static inline int pm_runtime_barrier(struct device *dev) { return 0; } -static inline void pm_runtime_enable(struct device *dev) {} -static inline void __pm_runtime_disable(struct device *dev, bool c) {} -static inline void pm_runtime_allow(struct device *dev) {} -static inline void pm_runtime_forbid(struct device *dev) {} - -static inline void pm_suspend_ignore_children(struct device *dev, bool enable) {} -static inline bool pm_children_suspended(struct device *dev) { return false; } -static inline void pm_runtime_get_noresume(struct device *dev) {} -static inline void pm_runtime_put_noidle(struct device *dev) {} -static inline bool device_run_wake(struct device *dev) { return false; } -static inline void device_set_run_wake(struct device *dev, bool enable) {} -static inline bool pm_runtime_suspended(struct device *dev) { return false; } -static inline bool pm_runtime_active(struct device *dev) { return true; } -static inline bool pm_runtime_status_suspended(struct device *dev) { return false; } -static inline bool pm_runtime_enabled(struct device *dev) { return false; } - -static inline void pm_runtime_no_callbacks(struct device *dev) {} -static inline void pm_runtime_irq_safe(struct device *dev) {} -static inline bool pm_runtime_is_irq_safe(struct device *dev) { return false; } - -static inline bool pm_runtime_callbacks_present(struct device *dev) { return false; } -static inline void pm_runtime_mark_last_busy(struct device *dev) {} -static inline void __pm_runtime_use_autosuspend(struct device *dev, - bool use) {} -static inline void pm_runtime_set_autosuspend_delay(struct device *dev, - int delay) {} -static inline unsigned long pm_runtime_autosuspend_expiration( - struct device *dev) { return 0; } -static inline void pm_runtime_set_memalloc_noio(struct device *dev, - bool enable){} - -#endif /* !CONFIG_PM */ - -static inline int pm_runtime_idle(struct device *dev) -{ - return __pm_runtime_idle(dev, 0); -} - -static inline int pm_runtime_suspend(struct device *dev) -{ - return __pm_runtime_suspend(dev, 0); -} - -static inline int pm_runtime_autosuspend(struct device *dev) -{ - return __pm_runtime_suspend(dev, RPM_AUTO); -} - -static inline int pm_runtime_resume(struct device *dev) -{ - return __pm_runtime_resume(dev, 0); -} - -static inline int pm_request_idle(struct device *dev) -{ - return __pm_runtime_idle(dev, RPM_ASYNC); -} - -static inline int pm_request_resume(struct device *dev) -{ - return __pm_runtime_resume(dev, RPM_ASYNC); -} - -static inline int pm_request_autosuspend(struct device *dev) -{ - return __pm_runtime_suspend(dev, RPM_ASYNC | RPM_AUTO); -} - -static inline int pm_runtime_get(struct device *dev) -{ - return __pm_runtime_resume(dev, RPM_GET_PUT | RPM_ASYNC); -} - -static inline int pm_runtime_get_sync(struct device *dev) -{ - return __pm_runtime_resume(dev, RPM_GET_PUT); -} - -static inline int pm_runtime_put(struct device *dev) -{ - return __pm_runtime_idle(dev, RPM_GET_PUT | RPM_ASYNC); -} - -static inline int pm_runtime_put_autosuspend(struct device *dev) -{ - return __pm_runtime_suspend(dev, - RPM_GET_PUT | RPM_ASYNC | RPM_AUTO); -} - -static inline int pm_runtime_put_sync(struct device *dev) -{ - return __pm_runtime_idle(dev, RPM_GET_PUT); -} - -static inline int pm_runtime_put_sync_suspend(struct device *dev) -{ - return __pm_runtime_suspend(dev, RPM_GET_PUT); -} - -static inline int pm_runtime_put_sync_autosuspend(struct device *dev) -{ - return __pm_runtime_suspend(dev, RPM_GET_PUT | RPM_AUTO); -} - -static inline int pm_runtime_set_active(struct device *dev) -{ - return __pm_runtime_set_status(dev, RPM_ACTIVE); -} - -static inline void pm_runtime_set_suspended(struct device *dev) -{ - __pm_runtime_set_status(dev, RPM_SUSPENDED); -} - -static inline void pm_runtime_disable(struct device *dev) -{ - __pm_runtime_disable(dev, true); -} - -static inline void pm_runtime_use_autosuspend(struct device *dev) -{ - __pm_runtime_use_autosuspend(dev, true); -} - -static inline void pm_runtime_dont_use_autosuspend(struct device *dev) -{ - __pm_runtime_use_autosuspend(dev, false); -} - -#endif diff --git a/src/linux/include/linux/pm_wakeup.h b/src/linux/include/linux/pm_wakeup.h deleted file mode 100644 index a344793..0000000 --- a/src/linux/include/linux/pm_wakeup.h +++ /dev/null @@ -1,204 +0,0 @@ -/* - * pm_wakeup.h - Power management wakeup interface - * - * Copyright (C) 2008 Alan Stern - * Copyright (C) 2010 Rafael J. Wysocki, Novell Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#ifndef _LINUX_PM_WAKEUP_H -#define _LINUX_PM_WAKEUP_H - -#ifndef _DEVICE_H_ -# error "please don't include this file directly" -#endif - -#include - -struct wake_irq; - -/** - * struct wakeup_source - Representation of wakeup sources - * - * @name: Name of the wakeup source - * @entry: Wakeup source list entry - * @lock: Wakeup source lock - * @wakeirq: Optional device specific wakeirq - * @timer: Wakeup timer list - * @timer_expires: Wakeup timer expiration - * @total_time: Total time this wakeup source has been active. - * @max_time: Maximum time this wakeup source has been continuously active. - * @last_time: Monotonic clock when the wakeup source's was touched last time. - * @prevent_sleep_time: Total time this source has been preventing autosleep. - * @event_count: Number of signaled wakeup events. - * @active_count: Number of times the wakeup source was activated. - * @relax_count: Number of times the wakeup source was deactivated. - * @expire_count: Number of times the wakeup source's timeout has expired. - * @wakeup_count: Number of times the wakeup source might abort suspend. - * @active: Status of the wakeup source. - * @has_timeout: The wakeup source has been activated with a timeout. - */ -struct wakeup_source { - const char *name; - struct list_head entry; - spinlock_t lock; - struct wake_irq *wakeirq; - struct timer_list timer; - unsigned long timer_expires; - ktime_t total_time; - ktime_t max_time; - ktime_t last_time; - ktime_t start_prevent_time; - ktime_t prevent_sleep_time; - unsigned long event_count; - unsigned long active_count; - unsigned long relax_count; - unsigned long expire_count; - unsigned long wakeup_count; - bool active:1; - bool autosleep_enabled:1; -}; - -#ifdef CONFIG_PM_SLEEP - -/* - * Changes to device_may_wakeup take effect on the next pm state change. - */ - -static inline bool device_can_wakeup(struct device *dev) -{ - return dev->power.can_wakeup; -} - -static inline bool device_may_wakeup(struct device *dev) -{ - return dev->power.can_wakeup && !!dev->power.wakeup; -} - -/* drivers/base/power/wakeup.c */ -extern void wakeup_source_prepare(struct wakeup_source *ws, const char *name); -extern struct wakeup_source *wakeup_source_create(const char *name); -extern void wakeup_source_drop(struct wakeup_source *ws); -extern void wakeup_source_destroy(struct wakeup_source *ws); -extern void wakeup_source_add(struct wakeup_source *ws); -extern void wakeup_source_remove(struct wakeup_source *ws); -extern struct wakeup_source *wakeup_source_register(const char *name); -extern void wakeup_source_unregister(struct wakeup_source *ws); -extern int device_wakeup_enable(struct device *dev); -extern int device_wakeup_disable(struct device *dev); -extern void device_set_wakeup_capable(struct device *dev, bool capable); -extern int device_init_wakeup(struct device *dev, bool val); -extern int device_set_wakeup_enable(struct device *dev, bool enable); -extern void __pm_stay_awake(struct wakeup_source *ws); -extern void pm_stay_awake(struct device *dev); -extern void __pm_relax(struct wakeup_source *ws); -extern void pm_relax(struct device *dev); -extern void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec); -extern void pm_wakeup_event(struct device *dev, unsigned int msec); - -#else /* !CONFIG_PM_SLEEP */ - -static inline void device_set_wakeup_capable(struct device *dev, bool capable) -{ - dev->power.can_wakeup = capable; -} - -static inline bool device_can_wakeup(struct device *dev) -{ - return dev->power.can_wakeup; -} - -static inline void wakeup_source_prepare(struct wakeup_source *ws, - const char *name) {} - -static inline struct wakeup_source *wakeup_source_create(const char *name) -{ - return NULL; -} - -static inline void wakeup_source_drop(struct wakeup_source *ws) {} - -static inline void wakeup_source_destroy(struct wakeup_source *ws) {} - -static inline void wakeup_source_add(struct wakeup_source *ws) {} - -static inline void wakeup_source_remove(struct wakeup_source *ws) {} - -static inline struct wakeup_source *wakeup_source_register(const char *name) -{ - return NULL; -} - -static inline void wakeup_source_unregister(struct wakeup_source *ws) {} - -static inline int device_wakeup_enable(struct device *dev) -{ - dev->power.should_wakeup = true; - return 0; -} - -static inline int device_wakeup_disable(struct device *dev) -{ - dev->power.should_wakeup = false; - return 0; -} - -static inline int device_set_wakeup_enable(struct device *dev, bool enable) -{ - dev->power.should_wakeup = enable; - return 0; -} - -static inline int device_init_wakeup(struct device *dev, bool val) -{ - device_set_wakeup_capable(dev, val); - device_set_wakeup_enable(dev, val); - return 0; -} - -static inline bool device_may_wakeup(struct device *dev) -{ - return dev->power.can_wakeup && dev->power.should_wakeup; -} - -static inline void __pm_stay_awake(struct wakeup_source *ws) {} - -static inline void pm_stay_awake(struct device *dev) {} - -static inline void __pm_relax(struct wakeup_source *ws) {} - -static inline void pm_relax(struct device *dev) {} - -static inline void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec) {} - -static inline void pm_wakeup_event(struct device *dev, unsigned int msec) {} - -#endif /* !CONFIG_PM_SLEEP */ - -static inline void wakeup_source_init(struct wakeup_source *ws, - const char *name) -{ - wakeup_source_prepare(ws, name); - wakeup_source_add(ws); -} - -static inline void wakeup_source_trash(struct wakeup_source *ws) -{ - wakeup_source_remove(ws); - wakeup_source_drop(ws); -} - -#endif /* _LINUX_PM_WAKEUP_H */ diff --git a/src/linux/include/linux/poison.h b/src/linux/include/linux/poison.h deleted file mode 100644 index 51334ed..0000000 --- a/src/linux/include/linux/poison.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef _LINUX_POISON_H -#define _LINUX_POISON_H - -/********** include/linux/list.h **********/ - -/* - * Architectures might want to move the poison pointer offset - * into some well-recognized area such as 0xdead000000000000, - * that is also not mappable by user-space exploits: - */ -#ifdef CONFIG_ILLEGAL_POINTER_VALUE -# define POISON_POINTER_DELTA _AC(CONFIG_ILLEGAL_POINTER_VALUE, UL) -#else -# define POISON_POINTER_DELTA 0 -#endif - -/* - * These are non-NULL pointers that will result in page faults - * under normal circumstances, used to verify that nobody uses - * non-initialized list entries. - */ -#define LIST_POISON1 ((void *) 0x100 + POISON_POINTER_DELTA) -#define LIST_POISON2 ((void *) 0x200 + POISON_POINTER_DELTA) - -/********** include/linux/timer.h **********/ -/* - * Magic number "tsta" to indicate a static timer initializer - * for the object debugging code. - */ -#define TIMER_ENTRY_STATIC ((void *) 0x300 + POISON_POINTER_DELTA) - -/********** mm/debug-pagealloc.c **********/ -#ifdef CONFIG_PAGE_POISONING_ZERO -#define PAGE_POISON 0x00 -#else -#define PAGE_POISON 0xaa -#endif - -/********** mm/page_alloc.c ************/ - -#define TAIL_MAPPING ((void *) 0x400 + POISON_POINTER_DELTA) - -/********** mm/slab.c **********/ -/* - * Magic nums for obj red zoning. - * Placed in the first word before and the first word after an obj. - */ -#define RED_INACTIVE 0x09F911029D74E35BULL /* when obj is inactive */ -#define RED_ACTIVE 0xD84156C5635688C0ULL /* when obj is active */ - -#define SLUB_RED_INACTIVE 0xbb -#define SLUB_RED_ACTIVE 0xcc - -/* ...and for poisoning */ -#define POISON_INUSE 0x5a /* for use-uninitialised poisoning */ -#define POISON_FREE 0x6b /* for use-after-free poisoning */ -#define POISON_END 0xa5 /* end-byte of poisoning */ - -/********** arch/$ARCH/mm/init.c **********/ -#define POISON_FREE_INITMEM 0xcc - -/********** arch/ia64/hp/common/sba_iommu.c **********/ -/* - * arch/ia64/hp/common/sba_iommu.c uses a 16-byte poison string with a - * value of "SBAIOMMU POISON\0" for spill-over poisoning. - */ - -/********** fs/jbd/journal.c **********/ -#define JBD_POISON_FREE 0x5b -#define JBD2_POISON_FREE 0x5c - -/********** drivers/base/dmapool.c **********/ -#define POOL_POISON_FREED 0xa7 /* !inuse */ -#define POOL_POISON_ALLOCATED 0xa9 /* !initted */ - -/********** drivers/atm/ **********/ -#define ATM_POISON_FREE 0x12 -#define ATM_POISON 0xdeadbeef - -/********** kernel/mutexes **********/ -#define MUTEX_DEBUG_INIT 0x11 -#define MUTEX_DEBUG_FREE 0x22 - -/********** lib/flex_array.c **********/ -#define FLEX_ARRAY_FREE 0x6c /* for use-after-free poisoning */ - -/********** security/ **********/ -#define KEY_DESTROY 0xbd - -#endif diff --git a/src/linux/include/linux/poll.h b/src/linux/include/linux/poll.h deleted file mode 100644 index 37b057b..0000000 --- a/src/linux/include/linux/poll.h +++ /dev/null @@ -1,165 +0,0 @@ -#ifndef _LINUX_POLL_H -#define _LINUX_POLL_H - - -#include -#include -#include -#include -#include -#include -#include -#include - -extern struct ctl_table epoll_table[]; /* for sysctl */ -/* ~832 bytes of stack space used max in sys_select/sys_poll before allocating - additional memory. */ -#define MAX_STACK_ALLOC 832 -#define FRONTEND_STACK_ALLOC 256 -#define SELECT_STACK_ALLOC FRONTEND_STACK_ALLOC -#define POLL_STACK_ALLOC FRONTEND_STACK_ALLOC -#define WQUEUES_STACK_ALLOC (MAX_STACK_ALLOC - FRONTEND_STACK_ALLOC) -#define N_INLINE_POLL_ENTRIES (WQUEUES_STACK_ALLOC / sizeof(struct poll_table_entry)) - -#define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM) - -struct poll_table_struct; - -/* - * structures and helpers for f_op->poll implementations - */ -typedef void (*poll_queue_proc)(struct file *, wait_queue_head_t *, struct poll_table_struct *); - -/* - * Do not touch the structure directly, use the access functions - * poll_does_not_wait() and poll_requested_events() instead. - */ -typedef struct poll_table_struct { - poll_queue_proc _qproc; - unsigned long _key; -} poll_table; - -static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p) -{ - if (p && p->_qproc && wait_address) - p->_qproc(filp, wait_address, p); -} - -/* - * Return true if it is guaranteed that poll will not wait. This is the case - * if the poll() of another file descriptor in the set got an event, so there - * is no need for waiting. - */ -static inline bool poll_does_not_wait(const poll_table *p) -{ - return p == NULL || p->_qproc == NULL; -} - -/* - * Return the set of events that the application wants to poll for. - * This is useful for drivers that need to know whether a DMA transfer has - * to be started implicitly on poll(). You typically only want to do that - * if the application is actually polling for POLLIN and/or POLLOUT. - */ -static inline unsigned long poll_requested_events(const poll_table *p) -{ - return p ? p->_key : ~0UL; -} - -static inline void init_poll_funcptr(poll_table *pt, poll_queue_proc qproc) -{ - pt->_qproc = qproc; - pt->_key = ~0UL; /* all events enabled */ -} - -struct poll_table_entry { - struct file *filp; - unsigned long key; - wait_queue_t wait; - wait_queue_head_t *wait_address; -}; - -/* - * Structures and helpers for select/poll syscall - */ -struct poll_wqueues { - poll_table pt; - struct poll_table_page *table; - struct task_struct *polling_task; - int triggered; - int error; - int inline_index; - struct poll_table_entry inline_entries[N_INLINE_POLL_ENTRIES]; -}; - -extern void poll_initwait(struct poll_wqueues *pwq); -extern void poll_freewait(struct poll_wqueues *pwq); -extern int poll_schedule_timeout(struct poll_wqueues *pwq, int state, - ktime_t *expires, unsigned long slack); -extern u64 select_estimate_accuracy(struct timespec64 *tv); - - -static inline int poll_schedule(struct poll_wqueues *pwq, int state) -{ - return poll_schedule_timeout(pwq, state, NULL, 0); -} - -/* - * Scalable version of the fd_set. - */ - -typedef struct { - unsigned long *in, *out, *ex; - unsigned long *res_in, *res_out, *res_ex; -} fd_set_bits; - -/* - * How many longwords for "nr" bits? - */ -#define FDS_BITPERLONG (8*sizeof(long)) -#define FDS_LONGS(nr) (((nr)+FDS_BITPERLONG-1)/FDS_BITPERLONG) -#define FDS_BYTES(nr) (FDS_LONGS(nr)*sizeof(long)) - -/* - * We do a VERIFY_WRITE here even though we are only reading this time: - * we'll write to it eventually.. - * - * Use "unsigned long" accesses to let user-mode fd_set's be long-aligned. - */ -static inline -int get_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset) -{ - nr = FDS_BYTES(nr); - if (ufdset) - return copy_from_user(fdset, ufdset, nr) ? -EFAULT : 0; - - memset(fdset, 0, nr); - return 0; -} - -static inline unsigned long __must_check -set_fd_set(unsigned long nr, void __user *ufdset, unsigned long *fdset) -{ - if (ufdset) - return __copy_to_user(ufdset, fdset, FDS_BYTES(nr)); - return 0; -} - -static inline -void zero_fd_set(unsigned long nr, unsigned long *fdset) -{ - memset(fdset, 0, FDS_BYTES(nr)); -} - -#define MAX_INT64_SECONDS (((s64)(~((u64)0)>>1)/HZ)-1) - -extern int do_select(int n, fd_set_bits *fds, struct timespec64 *end_time); -extern int do_sys_poll(struct pollfd __user * ufds, unsigned int nfds, - struct timespec64 *end_time); -extern int core_sys_select(int n, fd_set __user *inp, fd_set __user *outp, - fd_set __user *exp, struct timespec64 *end_time); - -extern int poll_select_set_timeout(struct timespec64 *to, time64_t sec, - long nsec); - -#endif /* _LINUX_POLL_H */ diff --git a/src/linux/include/linux/posix-clock.h b/src/linux/include/linux/posix-clock.h deleted file mode 100644 index 34c4498..0000000 --- a/src/linux/include/linux/posix-clock.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * posix-clock.h - support for dynamic clock devices - * - * Copyright (C) 2010 OMICRON electronics GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#ifndef _LINUX_POSIX_CLOCK_H_ -#define _LINUX_POSIX_CLOCK_H_ - -#include -#include -#include -#include -#include - -struct posix_clock; - -/** - * struct posix_clock_operations - functional interface to the clock - * - * Every posix clock is represented by a character device. Drivers may - * optionally offer extended capabilities by implementing the - * character device methods. The character device file operations are - * first handled by the clock device layer, then passed on to the - * driver by calling these functions. - * - * @owner: The clock driver should set to THIS_MODULE - * @clock_adjtime: Adjust the clock - * @clock_gettime: Read the current time - * @clock_getres: Get the clock resolution - * @clock_settime: Set the current time value - * @timer_create: Create a new timer - * @timer_delete: Remove a previously created timer - * @timer_gettime: Get remaining time and interval of a timer - * @timer_settime: Set a timer's initial expiration and interval - * @fasync: Optional character device fasync method - * @mmap: Optional character device mmap method - * @open: Optional character device open method - * @release: Optional character device release method - * @ioctl: Optional character device ioctl method - * @read: Optional character device read method - * @poll: Optional character device poll method - */ -struct posix_clock_operations { - struct module *owner; - - int (*clock_adjtime)(struct posix_clock *pc, struct timex *tx); - - int (*clock_gettime)(struct posix_clock *pc, struct timespec *ts); - - int (*clock_getres) (struct posix_clock *pc, struct timespec *ts); - - int (*clock_settime)(struct posix_clock *pc, - const struct timespec *ts); - - int (*timer_create) (struct posix_clock *pc, struct k_itimer *kit); - - int (*timer_delete) (struct posix_clock *pc, struct k_itimer *kit); - - void (*timer_gettime)(struct posix_clock *pc, - struct k_itimer *kit, struct itimerspec *tsp); - - int (*timer_settime)(struct posix_clock *pc, - struct k_itimer *kit, int flags, - struct itimerspec *tsp, struct itimerspec *old); - /* - * Optional character device methods: - */ - int (*fasync) (struct posix_clock *pc, - int fd, struct file *file, int on); - - long (*ioctl) (struct posix_clock *pc, - unsigned int cmd, unsigned long arg); - - int (*mmap) (struct posix_clock *pc, - struct vm_area_struct *vma); - - int (*open) (struct posix_clock *pc, fmode_t f_mode); - - uint (*poll) (struct posix_clock *pc, - struct file *file, poll_table *wait); - - int (*release) (struct posix_clock *pc); - - ssize_t (*read) (struct posix_clock *pc, - uint flags, char __user *buf, size_t cnt); -}; - -/** - * struct posix_clock - represents a dynamic posix clock - * - * @ops: Functional interface to the clock - * @cdev: Character device instance for this clock - * @kref: Reference count. - * @rwsem: Protects the 'zombie' field from concurrent access. - * @zombie: If 'zombie' is true, then the hardware has disappeared. - * @release: A function to free the structure when the reference count reaches - * zero. May be NULL if structure is statically allocated. - * - * Drivers should embed their struct posix_clock within a private - * structure, obtaining a reference to it during callbacks using - * container_of(). - */ -struct posix_clock { - struct posix_clock_operations ops; - struct cdev cdev; - struct kref kref; - struct rw_semaphore rwsem; - bool zombie; - void (*release)(struct posix_clock *clk); -}; - -/** - * posix_clock_register() - register a new clock - * @clk: Pointer to the clock. Caller must provide 'ops' and 'release' - * @devid: Allocated device id - * - * A clock driver calls this function to register itself with the - * clock device subsystem. If 'clk' points to dynamically allocated - * memory, then the caller must provide a 'release' function to free - * that memory. - * - * Returns zero on success, non-zero otherwise. - */ -int posix_clock_register(struct posix_clock *clk, dev_t devid); - -/** - * posix_clock_unregister() - unregister a clock - * @clk: Clock instance previously registered via posix_clock_register() - * - * A clock driver calls this function to remove itself from the clock - * device subsystem. The posix_clock itself will remain (in an - * inactive state) until its reference count drops to zero, at which - * point it will be deallocated with its 'release' method. - */ -void posix_clock_unregister(struct posix_clock *clk); - -#endif diff --git a/src/linux/include/linux/posix-timers.h b/src/linux/include/linux/posix-timers.h deleted file mode 100644 index 62d44c1..0000000 --- a/src/linux/include/linux/posix-timers.h +++ /dev/null @@ -1,138 +0,0 @@ -#ifndef _linux_POSIX_TIMERS_H -#define _linux_POSIX_TIMERS_H - -#include -#include -#include -#include -#include - - -static inline unsigned long long cputime_to_expires(cputime_t expires) -{ - return (__force unsigned long long)expires; -} - -static inline cputime_t expires_to_cputime(unsigned long long expires) -{ - return (__force cputime_t)expires; -} - -struct cpu_timer_list { - struct list_head entry; - unsigned long long expires, incr; - struct task_struct *task; - int firing; -}; - -/* - * Bit fields within a clockid: - * - * The most significant 29 bits hold either a pid or a file descriptor. - * - * Bit 2 indicates whether a cpu clock refers to a thread or a process. - * - * Bits 1 and 0 give the type: PROF=0, VIRT=1, SCHED=2, or FD=3. - * - * A clockid is invalid if bits 2, 1, and 0 are all set. - */ -#define CPUCLOCK_PID(clock) ((pid_t) ~((clock) >> 3)) -#define CPUCLOCK_PERTHREAD(clock) \ - (((clock) & (clockid_t) CPUCLOCK_PERTHREAD_MASK) != 0) - -#define CPUCLOCK_PERTHREAD_MASK 4 -#define CPUCLOCK_WHICH(clock) ((clock) & (clockid_t) CPUCLOCK_CLOCK_MASK) -#define CPUCLOCK_CLOCK_MASK 3 -#define CPUCLOCK_PROF 0 -#define CPUCLOCK_VIRT 1 -#define CPUCLOCK_SCHED 2 -#define CPUCLOCK_MAX 3 -#define CLOCKFD CPUCLOCK_MAX -#define CLOCKFD_MASK (CPUCLOCK_PERTHREAD_MASK|CPUCLOCK_CLOCK_MASK) - -#define MAKE_PROCESS_CPUCLOCK(pid, clock) \ - ((~(clockid_t) (pid) << 3) | (clockid_t) (clock)) -#define MAKE_THREAD_CPUCLOCK(tid, clock) \ - MAKE_PROCESS_CPUCLOCK((tid), (clock) | CPUCLOCK_PERTHREAD_MASK) - -#define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD) -#define CLOCKID_TO_FD(clk) ((unsigned int) ~((clk) >> 3)) - -/* POSIX.1b interval timer structure. */ -struct k_itimer { - struct list_head list; /* free/ allocate list */ - struct hlist_node t_hash; - spinlock_t it_lock; - clockid_t it_clock; /* which timer type */ - timer_t it_id; /* timer id */ - int it_overrun; /* overrun on pending signal */ - int it_overrun_last; /* overrun on last delivered signal */ - int it_requeue_pending; /* waiting to requeue this timer */ -#define REQUEUE_PENDING 1 - int it_sigev_notify; /* notify word of sigevent struct */ - struct signal_struct *it_signal; - union { - struct pid *it_pid; /* pid of process to send signal to */ - struct task_struct *it_process; /* for clock_nanosleep */ - }; - struct sigqueue *sigq; /* signal queue entry. */ - union { - struct { - struct hrtimer timer; - ktime_t interval; - } real; - struct cpu_timer_list cpu; - struct { - unsigned int clock; - unsigned int node; - unsigned long incr; - unsigned long expires; - } mmtimer; - struct { - struct alarm alarmtimer; - ktime_t interval; - } alarm; - struct rcu_head rcu; - } it; -}; - -struct k_clock { - int (*clock_getres) (const clockid_t which_clock, struct timespec *tp); - int (*clock_set) (const clockid_t which_clock, - const struct timespec *tp); - int (*clock_get) (const clockid_t which_clock, struct timespec * tp); - int (*clock_adj) (const clockid_t which_clock, struct timex *tx); - int (*timer_create) (struct k_itimer *timer); - int (*nsleep) (const clockid_t which_clock, int flags, - struct timespec *, struct timespec __user *); - long (*nsleep_restart) (struct restart_block *restart_block); - int (*timer_set) (struct k_itimer * timr, int flags, - struct itimerspec * new_setting, - struct itimerspec * old_setting); - int (*timer_del) (struct k_itimer * timr); -#define TIMER_RETRY 1 - void (*timer_get) (struct k_itimer * timr, - struct itimerspec * cur_setting); -}; - -extern struct k_clock clock_posix_cpu; -extern struct k_clock clock_posix_dynamic; - -void posix_timers_register_clock(const clockid_t clock_id, struct k_clock *new_clock); - -/* function to call to trigger timer event */ -int posix_timer_event(struct k_itimer *timr, int si_private); - -void posix_cpu_timer_schedule(struct k_itimer *timer); - -void run_posix_cpu_timers(struct task_struct *task); -void posix_cpu_timers_exit(struct task_struct *task); -void posix_cpu_timers_exit_group(struct task_struct *task); -void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx, - cputime_t *newval, cputime_t *oldval); - -long clock_nanosleep_restart(struct restart_block *restart_block); - -void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new); - -#endif diff --git a/src/linux/include/linux/posix_acl.h b/src/linux/include/linux/posix_acl.h deleted file mode 100644 index 5a9a739..0000000 --- a/src/linux/include/linux/posix_acl.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - File: linux/posix_acl.h - - (C) 2002 Andreas Gruenbacher, -*/ - - -#ifndef __LINUX_POSIX_ACL_H -#define __LINUX_POSIX_ACL_H - -#include -#include -#include -#include - -struct posix_acl_entry { - short e_tag; - unsigned short e_perm; - union { - kuid_t e_uid; - kgid_t e_gid; - }; -}; - -struct posix_acl { - atomic_t a_refcount; - struct rcu_head a_rcu; - unsigned int a_count; - struct posix_acl_entry a_entries[0]; -}; - -#define FOREACH_ACL_ENTRY(pa, acl, pe) \ - for(pa=(acl)->a_entries, pe=pa+(acl)->a_count; paa_refcount); - return acl; -} - -/* - * Free an ACL handle. - */ -static inline void -posix_acl_release(struct posix_acl *acl) -{ - if (acl && atomic_dec_and_test(&acl->a_refcount)) - kfree_rcu(acl, a_rcu); -} - - -/* posix_acl.c */ - -extern void posix_acl_init(struct posix_acl *, int); -extern struct posix_acl *posix_acl_alloc(int, gfp_t); -extern int posix_acl_valid(struct user_namespace *, const struct posix_acl *); -extern int posix_acl_permission(struct inode *, const struct posix_acl *, int); -extern struct posix_acl *posix_acl_from_mode(umode_t, gfp_t); -extern int posix_acl_equiv_mode(const struct posix_acl *, umode_t *); -extern int __posix_acl_create(struct posix_acl **, gfp_t, umode_t *); -extern int __posix_acl_chmod(struct posix_acl **, gfp_t, umode_t); - -extern struct posix_acl *get_posix_acl(struct inode *, int); -extern int set_posix_acl(struct inode *, int, struct posix_acl *); - -#ifdef CONFIG_FS_POSIX_ACL -extern int posix_acl_chmod(struct inode *, umode_t); -extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **, - struct posix_acl **); -extern int posix_acl_update_mode(struct inode *, umode_t *, struct posix_acl **); - -extern int simple_set_acl(struct inode *, struct posix_acl *, int); -extern int simple_acl_create(struct inode *, struct inode *); - -struct posix_acl *get_cached_acl(struct inode *inode, int type); -struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type); -void set_cached_acl(struct inode *inode, int type, struct posix_acl *acl); -void forget_cached_acl(struct inode *inode, int type); -void forget_all_cached_acls(struct inode *inode); - -static inline void cache_no_acl(struct inode *inode) -{ - inode->i_acl = NULL; - inode->i_default_acl = NULL; -} -#else -static inline int posix_acl_chmod(struct inode *inode, umode_t mode) -{ - return 0; -} - -#define simple_set_acl NULL - -static inline int simple_acl_create(struct inode *dir, struct inode *inode) -{ - return 0; -} -static inline void cache_no_acl(struct inode *inode) -{ -} - -static inline int posix_acl_create(struct inode *inode, umode_t *mode, - struct posix_acl **default_acl, struct posix_acl **acl) -{ - *default_acl = *acl = NULL; - return 0; -} - -static inline void forget_all_cached_acls(struct inode *inode) -{ -} -#endif /* CONFIG_FS_POSIX_ACL */ - -struct posix_acl *get_acl(struct inode *inode, int type); - -#endif /* __LINUX_POSIX_ACL_H */ diff --git a/src/linux/include/linux/posix_acl_xattr.h b/src/linux/include/linux/posix_acl_xattr.h deleted file mode 100644 index 8b867e3..0000000 --- a/src/linux/include/linux/posix_acl_xattr.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - File: linux/posix_acl_xattr.h - - Extended attribute system call representation of Access Control Lists. - - Copyright (C) 2000 by Andreas Gruenbacher - Copyright (C) 2002 SGI - Silicon Graphics, Inc - */ -#ifndef _POSIX_ACL_XATTR_H -#define _POSIX_ACL_XATTR_H - -#include -#include -#include - -static inline size_t -posix_acl_xattr_size(int count) -{ - return (sizeof(struct posix_acl_xattr_header) + - (count * sizeof(struct posix_acl_xattr_entry))); -} - -static inline int -posix_acl_xattr_count(size_t size) -{ - if (size < sizeof(struct posix_acl_xattr_header)) - return -1; - size -= sizeof(struct posix_acl_xattr_header); - if (size % sizeof(struct posix_acl_xattr_entry)) - return -1; - return size / sizeof(struct posix_acl_xattr_entry); -} - -#ifdef CONFIG_FS_POSIX_ACL -void posix_acl_fix_xattr_from_user(void *value, size_t size); -void posix_acl_fix_xattr_to_user(void *value, size_t size); -#else -static inline void posix_acl_fix_xattr_from_user(void *value, size_t size) -{ -} -static inline void posix_acl_fix_xattr_to_user(void *value, size_t size) -{ -} -#endif - -struct posix_acl *posix_acl_from_xattr(struct user_namespace *user_ns, - const void *value, size_t size); -int posix_acl_to_xattr(struct user_namespace *user_ns, - const struct posix_acl *acl, void *buffer, size_t size); - -extern const struct xattr_handler posix_acl_access_xattr_handler; -extern const struct xattr_handler posix_acl_default_xattr_handler; - -#endif /* _POSIX_ACL_XATTR_H */ diff --git a/src/linux/include/linux/power_supply.h b/src/linux/include/linux/power_supply.h deleted file mode 100644 index 3965503..0000000 --- a/src/linux/include/linux/power_supply.h +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Universal power supply monitor class - * - * Copyright © 2007 Anton Vorontsov - * Copyright © 2004 Szabolcs Gyurko - * Copyright © 2003 Ian Molton - * - * Modified: 2004, Oct Szabolcs Gyurko - * - * You may use this code as per GPL version 2 - */ - -#ifndef __LINUX_POWER_SUPPLY_H__ -#define __LINUX_POWER_SUPPLY_H__ - -#include -#include -#include -#include -#include - -/* - * All voltages, currents, charges, energies, time and temperatures in uV, - * µA, µAh, µWh, seconds and tenths of degree Celsius unless otherwise - * stated. It's driver's job to convert its raw values to units in which - * this class operates. - */ - -/* - * For systems where the charger determines the maximum battery capacity - * the min and max fields should be used to present these values to user - * space. Unused/unknown fields will not appear in sysfs. - */ - -enum { - POWER_SUPPLY_STATUS_UNKNOWN = 0, - POWER_SUPPLY_STATUS_CHARGING, - POWER_SUPPLY_STATUS_DISCHARGING, - POWER_SUPPLY_STATUS_NOT_CHARGING, - POWER_SUPPLY_STATUS_FULL, -}; - -enum { - POWER_SUPPLY_CHARGE_TYPE_UNKNOWN = 0, - POWER_SUPPLY_CHARGE_TYPE_NONE, - POWER_SUPPLY_CHARGE_TYPE_TRICKLE, - POWER_SUPPLY_CHARGE_TYPE_FAST, -}; - -enum { - POWER_SUPPLY_HEALTH_UNKNOWN = 0, - POWER_SUPPLY_HEALTH_GOOD, - POWER_SUPPLY_HEALTH_OVERHEAT, - POWER_SUPPLY_HEALTH_DEAD, - POWER_SUPPLY_HEALTH_OVERVOLTAGE, - POWER_SUPPLY_HEALTH_UNSPEC_FAILURE, - POWER_SUPPLY_HEALTH_COLD, - POWER_SUPPLY_HEALTH_WATCHDOG_TIMER_EXPIRE, - POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE, -}; - -enum { - POWER_SUPPLY_TECHNOLOGY_UNKNOWN = 0, - POWER_SUPPLY_TECHNOLOGY_NiMH, - POWER_SUPPLY_TECHNOLOGY_LION, - POWER_SUPPLY_TECHNOLOGY_LIPO, - POWER_SUPPLY_TECHNOLOGY_LiFe, - POWER_SUPPLY_TECHNOLOGY_NiCd, - POWER_SUPPLY_TECHNOLOGY_LiMn, -}; - -enum { - POWER_SUPPLY_CAPACITY_LEVEL_UNKNOWN = 0, - POWER_SUPPLY_CAPACITY_LEVEL_CRITICAL, - POWER_SUPPLY_CAPACITY_LEVEL_LOW, - POWER_SUPPLY_CAPACITY_LEVEL_NORMAL, - POWER_SUPPLY_CAPACITY_LEVEL_HIGH, - POWER_SUPPLY_CAPACITY_LEVEL_FULL, -}; - -enum { - POWER_SUPPLY_SCOPE_UNKNOWN = 0, - POWER_SUPPLY_SCOPE_SYSTEM, - POWER_SUPPLY_SCOPE_DEVICE, -}; - -enum power_supply_property { - /* Properties of type `int' */ - POWER_SUPPLY_PROP_STATUS = 0, - POWER_SUPPLY_PROP_CHARGE_TYPE, - POWER_SUPPLY_PROP_HEALTH, - POWER_SUPPLY_PROP_PRESENT, - POWER_SUPPLY_PROP_ONLINE, - POWER_SUPPLY_PROP_AUTHENTIC, - POWER_SUPPLY_PROP_TECHNOLOGY, - POWER_SUPPLY_PROP_CYCLE_COUNT, - POWER_SUPPLY_PROP_VOLTAGE_MAX, - POWER_SUPPLY_PROP_VOLTAGE_MIN, - POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, - POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, - POWER_SUPPLY_PROP_VOLTAGE_NOW, - POWER_SUPPLY_PROP_VOLTAGE_AVG, - POWER_SUPPLY_PROP_VOLTAGE_OCV, - POWER_SUPPLY_PROP_VOLTAGE_BOOT, - POWER_SUPPLY_PROP_CURRENT_MAX, - POWER_SUPPLY_PROP_CURRENT_NOW, - POWER_SUPPLY_PROP_CURRENT_AVG, - POWER_SUPPLY_PROP_CURRENT_BOOT, - POWER_SUPPLY_PROP_POWER_NOW, - POWER_SUPPLY_PROP_POWER_AVG, - POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, - POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN, - POWER_SUPPLY_PROP_CHARGE_FULL, - POWER_SUPPLY_PROP_CHARGE_EMPTY, - POWER_SUPPLY_PROP_CHARGE_NOW, - POWER_SUPPLY_PROP_CHARGE_AVG, - POWER_SUPPLY_PROP_CHARGE_COUNTER, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, - POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX, - POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT, - POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX, - POWER_SUPPLY_PROP_INPUT_CURRENT_LIMIT, - POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN, - POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN, - POWER_SUPPLY_PROP_ENERGY_FULL, - POWER_SUPPLY_PROP_ENERGY_EMPTY, - POWER_SUPPLY_PROP_ENERGY_NOW, - POWER_SUPPLY_PROP_ENERGY_AVG, - POWER_SUPPLY_PROP_CAPACITY, /* in percents! */ - POWER_SUPPLY_PROP_CAPACITY_ALERT_MIN, /* in percents! */ - POWER_SUPPLY_PROP_CAPACITY_ALERT_MAX, /* in percents! */ - POWER_SUPPLY_PROP_CAPACITY_LEVEL, - POWER_SUPPLY_PROP_TEMP, - POWER_SUPPLY_PROP_TEMP_MAX, - POWER_SUPPLY_PROP_TEMP_MIN, - POWER_SUPPLY_PROP_TEMP_ALERT_MIN, - POWER_SUPPLY_PROP_TEMP_ALERT_MAX, - POWER_SUPPLY_PROP_TEMP_AMBIENT, - POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MIN, - POWER_SUPPLY_PROP_TEMP_AMBIENT_ALERT_MAX, - POWER_SUPPLY_PROP_TIME_TO_EMPTY_NOW, - POWER_SUPPLY_PROP_TIME_TO_EMPTY_AVG, - POWER_SUPPLY_PROP_TIME_TO_FULL_NOW, - POWER_SUPPLY_PROP_TIME_TO_FULL_AVG, - POWER_SUPPLY_PROP_TYPE, /* use power_supply.type instead */ - POWER_SUPPLY_PROP_SCOPE, - POWER_SUPPLY_PROP_CHARGE_TERM_CURRENT, - POWER_SUPPLY_PROP_CALIBRATE, - /* Properties of type `const char *' */ - POWER_SUPPLY_PROP_MODEL_NAME, - POWER_SUPPLY_PROP_MANUFACTURER, - POWER_SUPPLY_PROP_SERIAL_NUMBER, -}; - -enum power_supply_type { - POWER_SUPPLY_TYPE_UNKNOWN = 0, - POWER_SUPPLY_TYPE_BATTERY, - POWER_SUPPLY_TYPE_UPS, - POWER_SUPPLY_TYPE_MAINS, - POWER_SUPPLY_TYPE_USB, /* Standard Downstream Port */ - POWER_SUPPLY_TYPE_USB_DCP, /* Dedicated Charging Port */ - POWER_SUPPLY_TYPE_USB_CDP, /* Charging Downstream Port */ - POWER_SUPPLY_TYPE_USB_ACA, /* Accessory Charger Adapters */ - POWER_SUPPLY_TYPE_USB_TYPE_C, /* Type C Port */ - POWER_SUPPLY_TYPE_USB_PD, /* Power Delivery Port */ - POWER_SUPPLY_TYPE_USB_PD_DRP, /* PD Dual Role Port */ -}; - -enum power_supply_notifier_events { - PSY_EVENT_PROP_CHANGED, -}; - -union power_supply_propval { - int intval; - const char *strval; -}; - -struct device_node; -struct power_supply; - -/* Run-time specific power supply configuration */ -struct power_supply_config { - struct device_node *of_node; - /* Driver private data */ - void *drv_data; - - char **supplied_to; - size_t num_supplicants; -}; - -/* Description of power supply */ -struct power_supply_desc { - const char *name; - enum power_supply_type type; - enum power_supply_property *properties; - size_t num_properties; - - /* - * Functions for drivers implementing power supply class. - * These shouldn't be called directly by other drivers for accessing - * this power supply. Instead use power_supply_*() functions (for - * example power_supply_get_property()). - */ - int (*get_property)(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val); - int (*set_property)(struct power_supply *psy, - enum power_supply_property psp, - const union power_supply_propval *val); - /* - * property_is_writeable() will be called during registration - * of power supply. If this happens during device probe then it must - * not access internal data of device (because probe did not end). - */ - int (*property_is_writeable)(struct power_supply *psy, - enum power_supply_property psp); - void (*external_power_changed)(struct power_supply *psy); - void (*set_charged)(struct power_supply *psy); - - /* - * Set if thermal zone should not be created for this power supply. - * For example for virtual supplies forwarding calls to actual - * sensors or other supplies. - */ - bool no_thermal; - /* For APM emulation, think legacy userspace. */ - int use_for_apm; -}; - -struct power_supply { - const struct power_supply_desc *desc; - - char **supplied_to; - size_t num_supplicants; - - char **supplied_from; - size_t num_supplies; - struct device_node *of_node; - - /* Driver private data */ - void *drv_data; - - /* private */ - struct device dev; - struct work_struct changed_work; - struct delayed_work deferred_register_work; - spinlock_t changed_lock; - bool changed; - bool initialized; - atomic_t use_cnt; -#ifdef CONFIG_THERMAL - struct thermal_zone_device *tzd; - struct thermal_cooling_device *tcd; -#endif - -#ifdef CONFIG_LEDS_TRIGGERS - struct led_trigger *charging_full_trig; - char *charging_full_trig_name; - struct led_trigger *charging_trig; - char *charging_trig_name; - struct led_trigger *full_trig; - char *full_trig_name; - struct led_trigger *online_trig; - char *online_trig_name; - struct led_trigger *charging_blink_full_solid_trig; - char *charging_blink_full_solid_trig_name; -#endif -}; - -/* - * This is recommended structure to specify static power supply parameters. - * Generic one, parametrizable for different power supplies. Power supply - * class itself does not use it, but that's what implementing most platform - * drivers, should try reuse for consistency. - */ - -struct power_supply_info { - const char *name; - int technology; - int voltage_max_design; - int voltage_min_design; - int charge_full_design; - int charge_empty_design; - int energy_full_design; - int energy_empty_design; - int use_for_apm; -}; - -extern struct atomic_notifier_head power_supply_notifier; -extern int power_supply_reg_notifier(struct notifier_block *nb); -extern void power_supply_unreg_notifier(struct notifier_block *nb); -extern struct power_supply *power_supply_get_by_name(const char *name); -extern void power_supply_put(struct power_supply *psy); -#ifdef CONFIG_OF -extern struct power_supply *power_supply_get_by_phandle(struct device_node *np, - const char *property); -extern struct power_supply *devm_power_supply_get_by_phandle( - struct device *dev, const char *property); -#else /* !CONFIG_OF */ -static inline struct power_supply * -power_supply_get_by_phandle(struct device_node *np, const char *property) -{ return NULL; } -static inline struct power_supply * -devm_power_supply_get_by_phandle(struct device *dev, const char *property) -{ return NULL; } -#endif /* CONFIG_OF */ -extern void power_supply_changed(struct power_supply *psy); -extern int power_supply_am_i_supplied(struct power_supply *psy); -extern int power_supply_set_battery_charged(struct power_supply *psy); - -#ifdef CONFIG_POWER_SUPPLY -extern int power_supply_is_system_supplied(void); -#else -static inline int power_supply_is_system_supplied(void) { return -ENOSYS; } -#endif - -extern int power_supply_get_property(struct power_supply *psy, - enum power_supply_property psp, - union power_supply_propval *val); -extern int power_supply_set_property(struct power_supply *psy, - enum power_supply_property psp, - const union power_supply_propval *val); -extern int power_supply_property_is_writeable(struct power_supply *psy, - enum power_supply_property psp); -extern void power_supply_external_power_changed(struct power_supply *psy); - -extern struct power_supply *__must_check -power_supply_register(struct device *parent, - const struct power_supply_desc *desc, - const struct power_supply_config *cfg); -extern struct power_supply *__must_check -power_supply_register_no_ws(struct device *parent, - const struct power_supply_desc *desc, - const struct power_supply_config *cfg); -extern struct power_supply *__must_check -devm_power_supply_register(struct device *parent, - const struct power_supply_desc *desc, - const struct power_supply_config *cfg); -extern struct power_supply *__must_check -devm_power_supply_register_no_ws(struct device *parent, - const struct power_supply_desc *desc, - const struct power_supply_config *cfg); -extern void power_supply_unregister(struct power_supply *psy); -extern int power_supply_powers(struct power_supply *psy, struct device *dev); - -extern void *power_supply_get_drvdata(struct power_supply *psy); -/* For APM emulation, think legacy userspace. */ -extern struct class *power_supply_class; - -static inline bool power_supply_is_amp_property(enum power_supply_property psp) -{ - switch (psp) { - case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: - case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN: - case POWER_SUPPLY_PROP_CHARGE_FULL: - case POWER_SUPPLY_PROP_CHARGE_EMPTY: - case POWER_SUPPLY_PROP_CHARGE_NOW: - case POWER_SUPPLY_PROP_CHARGE_AVG: - case POWER_SUPPLY_PROP_CHARGE_COUNTER: - case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT: - case POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX: - case POWER_SUPPLY_PROP_CURRENT_MAX: - case POWER_SUPPLY_PROP_CURRENT_NOW: - case POWER_SUPPLY_PROP_CURRENT_AVG: - case POWER_SUPPLY_PROP_CURRENT_BOOT: - return 1; - default: - break; - } - - return 0; -} - -static inline bool power_supply_is_watt_property(enum power_supply_property psp) -{ - switch (psp) { - case POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN: - case POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN: - case POWER_SUPPLY_PROP_ENERGY_FULL: - case POWER_SUPPLY_PROP_ENERGY_EMPTY: - case POWER_SUPPLY_PROP_ENERGY_NOW: - case POWER_SUPPLY_PROP_ENERGY_AVG: - case POWER_SUPPLY_PROP_VOLTAGE_MAX: - case POWER_SUPPLY_PROP_VOLTAGE_MIN: - case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: - case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: - case POWER_SUPPLY_PROP_VOLTAGE_NOW: - case POWER_SUPPLY_PROP_VOLTAGE_AVG: - case POWER_SUPPLY_PROP_VOLTAGE_OCV: - case POWER_SUPPLY_PROP_VOLTAGE_BOOT: - case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: - case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE_MAX: - case POWER_SUPPLY_PROP_POWER_NOW: - return 1; - default: - break; - } - - return 0; -} - -#endif /* __LINUX_POWER_SUPPLY_H__ */ diff --git a/src/linux/include/linux/ppp_channel.h b/src/linux/include/linux/ppp_channel.h deleted file mode 100644 index 5d87f81..0000000 --- a/src/linux/include/linux/ppp_channel.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef _PPP_CHANNEL_H_ -#define _PPP_CHANNEL_H_ -/* - * Definitions for the interface between the generic PPP code - * and a PPP channel. - * - * A PPP channel provides a way for the generic PPP code to send - * and receive packets over some sort of communications medium. - * Packets are stored in sk_buffs and have the 2-byte PPP protocol - * number at the start, but not the address and control bytes. - * - * Copyright 1999 Paul Mackerras. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * ==FILEVERSION 20000322== - */ - -#include -#include -#include -#include - -struct ppp_channel; - -struct ppp_channel_ops { - /* Send a packet (or multilink fragment) on this channel. - Returns 1 if it was accepted, 0 if not. */ - int (*start_xmit)(struct ppp_channel *, struct sk_buff *); - /* Handle an ioctl call that has come in via /dev/ppp. */ - int (*ioctl)(struct ppp_channel *, unsigned int, unsigned long); -}; - -struct ppp_channel { - void *private; /* channel private data */ - const struct ppp_channel_ops *ops; /* operations for this channel */ - int mtu; /* max transmit packet size */ - int hdrlen; /* amount of headroom channel needs */ - void *ppp; /* opaque to channel */ - int speed; /* transfer rate (bytes/second) */ - /* the following is not used at present */ - int latency; /* overhead time in milliseconds */ -}; - -#ifdef __KERNEL__ -/* Called by the channel when it can send some more data. */ -extern void ppp_output_wakeup(struct ppp_channel *); - -/* Called by the channel to process a received PPP packet. - The packet should have just the 2-byte PPP protocol header. */ -extern void ppp_input(struct ppp_channel *, struct sk_buff *); - -/* Called by the channel when an input error occurs, indicating - that we may have missed a packet. */ -extern void ppp_input_error(struct ppp_channel *, int code); - -/* Attach a channel to a given PPP unit in specified net. */ -extern int ppp_register_net_channel(struct net *, struct ppp_channel *); - -/* Attach a channel to a given PPP unit. */ -extern int ppp_register_channel(struct ppp_channel *); - -/* Detach a channel from its PPP unit (e.g. on hangup). */ -extern void ppp_unregister_channel(struct ppp_channel *); - -/* Get the channel number for a channel */ -extern int ppp_channel_index(struct ppp_channel *); - -/* Get the unit number associated with a channel, or -1 if none */ -extern int ppp_unit_number(struct ppp_channel *); - -/* Get the device name associated with a channel, or NULL if none */ -extern char *ppp_dev_name(struct ppp_channel *); - -/* - * SMP locking notes: - * The channel code must ensure that when it calls ppp_unregister_channel, - * nothing is executing in any of the procedures above, for that - * channel. The generic layer will ensure that nothing is executing - * in the start_xmit and ioctl routines for the channel by the time - * that ppp_unregister_channel returns. - */ - -#endif /* __KERNEL__ */ -#endif diff --git a/src/linux/include/linux/ppp_defs.h b/src/linux/include/linux/ppp_defs.h deleted file mode 100644 index 28aa023..0000000 --- a/src/linux/include/linux/ppp_defs.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * ppp_defs.h - PPP definitions. - * - * Copyright 1994-2000 Paul Mackerras. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - */ -#ifndef _PPP_DEFS_H_ -#define _PPP_DEFS_H_ - -#include -#include - -#define PPP_FCS(fcs, c) crc_ccitt_byte(fcs, c) -#endif /* _PPP_DEFS_H_ */ diff --git a/src/linux/include/linux/pr.h b/src/linux/include/linux/pr.h deleted file mode 100644 index 65c01c1..0000000 --- a/src/linux/include/linux/pr.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef LINUX_PR_H -#define LINUX_PR_H - -#include - -struct pr_ops { - int (*pr_register)(struct block_device *bdev, u64 old_key, u64 new_key, - u32 flags); - int (*pr_reserve)(struct block_device *bdev, u64 key, - enum pr_type type, u32 flags); - int (*pr_release)(struct block_device *bdev, u64 key, - enum pr_type type); - int (*pr_preempt)(struct block_device *bdev, u64 old_key, u64 new_key, - enum pr_type type, bool abort); - int (*pr_clear)(struct block_device *bdev, u64 key); -}; - -#endif /* LINUX_PR_H */ diff --git a/src/linux/include/linux/preempt.h b/src/linux/include/linux/preempt.h deleted file mode 100644 index 75e4e30..0000000 --- a/src/linux/include/linux/preempt.h +++ /dev/null @@ -1,301 +0,0 @@ -#ifndef __LINUX_PREEMPT_H -#define __LINUX_PREEMPT_H - -/* - * include/linux/preempt.h - macros for accessing and manipulating - * preempt_count (used for kernel preemption, interrupt count, etc.) - */ - -#include -#include - -/* - * We put the hardirq and softirq counter into the preemption - * counter. The bitmask has the following meaning: - * - * - bits 0-7 are the preemption count (max preemption depth: 256) - * - bits 8-15 are the softirq count (max # of softirqs: 256) - * - * The hardirq count could in theory be the same as the number of - * interrupts in the system, but we run all interrupt handlers with - * interrupts disabled, so we cannot have nesting interrupts. Though - * there are a few palaeontologic drivers which reenable interrupts in - * the handler, so we need more than one bit here. - * - * PREEMPT_MASK: 0x000000ff - * SOFTIRQ_MASK: 0x0000ff00 - * HARDIRQ_MASK: 0x000f0000 - * NMI_MASK: 0x00100000 - * PREEMPT_NEED_RESCHED: 0x80000000 - */ -#define PREEMPT_BITS 8 -#define SOFTIRQ_BITS 8 -#define HARDIRQ_BITS 4 -#define NMI_BITS 1 - -#define PREEMPT_SHIFT 0 -#define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS) -#define HARDIRQ_SHIFT (SOFTIRQ_SHIFT + SOFTIRQ_BITS) -#define NMI_SHIFT (HARDIRQ_SHIFT + HARDIRQ_BITS) - -#define __IRQ_MASK(x) ((1UL << (x))-1) - -#define PREEMPT_MASK (__IRQ_MASK(PREEMPT_BITS) << PREEMPT_SHIFT) -#define SOFTIRQ_MASK (__IRQ_MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT) -#define HARDIRQ_MASK (__IRQ_MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT) -#define NMI_MASK (__IRQ_MASK(NMI_BITS) << NMI_SHIFT) - -#define PREEMPT_OFFSET (1UL << PREEMPT_SHIFT) -#define SOFTIRQ_OFFSET (1UL << SOFTIRQ_SHIFT) -#define HARDIRQ_OFFSET (1UL << HARDIRQ_SHIFT) -#define NMI_OFFSET (1UL << NMI_SHIFT) - -#define SOFTIRQ_DISABLE_OFFSET (2 * SOFTIRQ_OFFSET) - -/* We use the MSB mostly because its available */ -#define PREEMPT_NEED_RESCHED 0x80000000 - -/* preempt_count() and related functions, depends on PREEMPT_NEED_RESCHED */ -#include - -#define hardirq_count() (preempt_count() & HARDIRQ_MASK) -#define softirq_count() (preempt_count() & SOFTIRQ_MASK) -#define irq_count() (preempt_count() & (HARDIRQ_MASK | SOFTIRQ_MASK \ - | NMI_MASK)) - -/* - * Are we doing bottom half or hardware interrupt processing? - * Are we in a softirq context? Interrupt context? - * in_softirq - Are we currently processing softirq or have bh disabled? - * in_serving_softirq - Are we currently processing softirq? - */ -#define in_irq() (hardirq_count()) -#define in_softirq() (softirq_count()) -#define in_interrupt() (irq_count()) -#define in_serving_softirq() (softirq_count() & SOFTIRQ_OFFSET) - -/* - * Are we in NMI context? - */ -#define in_nmi() (preempt_count() & NMI_MASK) - -/* - * The preempt_count offset after preempt_disable(); - */ -#if defined(CONFIG_PREEMPT_COUNT) -# define PREEMPT_DISABLE_OFFSET PREEMPT_OFFSET -#else -# define PREEMPT_DISABLE_OFFSET 0 -#endif - -/* - * The preempt_count offset after spin_lock() - */ -#define PREEMPT_LOCK_OFFSET PREEMPT_DISABLE_OFFSET - -/* - * The preempt_count offset needed for things like: - * - * spin_lock_bh() - * - * Which need to disable both preemption (CONFIG_PREEMPT_COUNT) and - * softirqs, such that unlock sequences of: - * - * spin_unlock(); - * local_bh_enable(); - * - * Work as expected. - */ -#define SOFTIRQ_LOCK_OFFSET (SOFTIRQ_DISABLE_OFFSET + PREEMPT_LOCK_OFFSET) - -/* - * Are we running in atomic context? WARNING: this macro cannot - * always detect atomic context; in particular, it cannot know about - * held spinlocks in non-preemptible kernels. Thus it should not be - * used in the general case to determine whether sleeping is possible. - * Do not use in_atomic() in driver code. - */ -#define in_atomic() (preempt_count() != 0) - -/* - * Check whether we were atomic before we did preempt_disable(): - * (used by the scheduler) - */ -#define in_atomic_preempt_off() (preempt_count() != PREEMPT_DISABLE_OFFSET) - -#if defined(CONFIG_DEBUG_PREEMPT) || defined(CONFIG_PREEMPT_TRACER) -extern void preempt_count_add(int val); -extern void preempt_count_sub(int val); -#define preempt_count_dec_and_test() \ - ({ preempt_count_sub(1); should_resched(0); }) -#else -#define preempt_count_add(val) __preempt_count_add(val) -#define preempt_count_sub(val) __preempt_count_sub(val) -#define preempt_count_dec_and_test() __preempt_count_dec_and_test() -#endif - -#define __preempt_count_inc() __preempt_count_add(1) -#define __preempt_count_dec() __preempt_count_sub(1) - -#define preempt_count_inc() preempt_count_add(1) -#define preempt_count_dec() preempt_count_sub(1) - -#ifdef CONFIG_PREEMPT_COUNT - -#define preempt_disable() \ -do { \ - preempt_count_inc(); \ - barrier(); \ -} while (0) - -#define sched_preempt_enable_no_resched() \ -do { \ - barrier(); \ - preempt_count_dec(); \ -} while (0) - -#define preempt_enable_no_resched() sched_preempt_enable_no_resched() - -#define preemptible() (preempt_count() == 0 && !irqs_disabled()) - -#ifdef CONFIG_PREEMPT -#define preempt_enable() \ -do { \ - barrier(); \ - if (unlikely(preempt_count_dec_and_test())) \ - __preempt_schedule(); \ -} while (0) - -#define preempt_enable_notrace() \ -do { \ - barrier(); \ - if (unlikely(__preempt_count_dec_and_test())) \ - __preempt_schedule_notrace(); \ -} while (0) - -#define preempt_check_resched() \ -do { \ - if (should_resched(0)) \ - __preempt_schedule(); \ -} while (0) - -#else /* !CONFIG_PREEMPT */ -#define preempt_enable() \ -do { \ - barrier(); \ - preempt_count_dec(); \ -} while (0) - -#define preempt_enable_notrace() \ -do { \ - barrier(); \ - __preempt_count_dec(); \ -} while (0) - -#define preempt_check_resched() do { } while (0) -#endif /* CONFIG_PREEMPT */ - -#define preempt_disable_notrace() \ -do { \ - __preempt_count_inc(); \ - barrier(); \ -} while (0) - -#define preempt_enable_no_resched_notrace() \ -do { \ - barrier(); \ - __preempt_count_dec(); \ -} while (0) - -#else /* !CONFIG_PREEMPT_COUNT */ - -/* - * Even if we don't have any preemption, we need preempt disable/enable - * to be barriers, so that we don't have things like get_user/put_user - * that can cause faults and scheduling migrate into our preempt-protected - * region. - */ -#define preempt_disable() barrier() -#define sched_preempt_enable_no_resched() barrier() -#define preempt_enable_no_resched() barrier() -#define preempt_enable() barrier() -#define preempt_check_resched() do { } while (0) - -#define preempt_disable_notrace() barrier() -#define preempt_enable_no_resched_notrace() barrier() -#define preempt_enable_notrace() barrier() -#define preemptible() 0 - -#endif /* CONFIG_PREEMPT_COUNT */ - -#ifdef MODULE -/* - * Modules have no business playing preemption tricks. - */ -#undef sched_preempt_enable_no_resched -#undef preempt_enable_no_resched -#undef preempt_enable_no_resched_notrace -#undef preempt_check_resched -#endif - -#define preempt_set_need_resched() \ -do { \ - set_preempt_need_resched(); \ -} while (0) -#define preempt_fold_need_resched() \ -do { \ - if (tif_need_resched()) \ - set_preempt_need_resched(); \ -} while (0) - -#ifdef CONFIG_PREEMPT_NOTIFIERS - -struct preempt_notifier; - -/** - * preempt_ops - notifiers called when a task is preempted and rescheduled - * @sched_in: we're about to be rescheduled: - * notifier: struct preempt_notifier for the task being scheduled - * cpu: cpu we're scheduled on - * @sched_out: we've just been preempted - * notifier: struct preempt_notifier for the task being preempted - * next: the task that's kicking us out - * - * Please note that sched_in and out are called under different - * contexts. sched_out is called with rq lock held and irq disabled - * while sched_in is called without rq lock and irq enabled. This - * difference is intentional and depended upon by its users. - */ -struct preempt_ops { - void (*sched_in)(struct preempt_notifier *notifier, int cpu); - void (*sched_out)(struct preempt_notifier *notifier, - struct task_struct *next); -}; - -/** - * preempt_notifier - key for installing preemption notifiers - * @link: internal use - * @ops: defines the notifier functions to be called - * - * Usually used in conjunction with container_of(). - */ -struct preempt_notifier { - struct hlist_node link; - struct preempt_ops *ops; -}; - -void preempt_notifier_inc(void); -void preempt_notifier_dec(void); -void preempt_notifier_register(struct preempt_notifier *notifier); -void preempt_notifier_unregister(struct preempt_notifier *notifier); - -static inline void preempt_notifier_init(struct preempt_notifier *notifier, - struct preempt_ops *ops) -{ - INIT_HLIST_NODE(¬ifier->link); - notifier->ops = ops; -} - -#endif - -#endif /* __LINUX_PREEMPT_H */ diff --git a/src/linux/include/linux/prefetch.h b/src/linux/include/linux/prefetch.h deleted file mode 100644 index a3bfbdf..0000000 --- a/src/linux/include/linux/prefetch.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Generic cache management functions. Everything is arch-specific, - * but this header exists to make sure the defines/functions can be - * used in a generic way. - * - * 2000-11-13 Arjan van de Ven - * - */ - -#ifndef _LINUX_PREFETCH_H -#define _LINUX_PREFETCH_H - -#include -#include -#include - -/* - prefetch(x) attempts to pre-emptively get the memory pointed to - by address "x" into the CPU L1 cache. - prefetch(x) should not cause any kind of exception, prefetch(0) is - specifically ok. - - prefetch() should be defined by the architecture, if not, the - #define below provides a no-op define. - - There are 3 prefetch() macros: - - prefetch(x) - prefetches the cacheline at "x" for read - prefetchw(x) - prefetches the cacheline at "x" for write - spin_lock_prefetch(x) - prefetches the spinlock *x for taking - - there is also PREFETCH_STRIDE which is the architecure-preferred - "lookahead" size for prefetching streamed operations. - -*/ - -#ifndef ARCH_HAS_PREFETCH -#define prefetch(x) __builtin_prefetch(x) -#endif - -#ifndef ARCH_HAS_PREFETCHW -#define prefetchw(x) __builtin_prefetch(x,1) -#endif - -#ifndef ARCH_HAS_SPINLOCK_PREFETCH -#define spin_lock_prefetch(x) prefetchw(x) -#endif - -#ifndef PREFETCH_STRIDE -#define PREFETCH_STRIDE (4*L1_CACHE_BYTES) -#endif - -static inline void prefetch_range(void *addr, size_t len) -{ -#ifdef ARCH_HAS_PREFETCH - char *cp; - char *end = addr + len; - - for (cp = addr; cp < end; cp += PREFETCH_STRIDE) - prefetch(cp); -#endif -} - -#endif diff --git a/src/linux/include/linux/printk.h b/src/linux/include/linux/printk.h deleted file mode 100644 index eac1af8..0000000 --- a/src/linux/include/linux/printk.h +++ /dev/null @@ -1,502 +0,0 @@ -#ifndef __KERNEL_PRINTK__ -#define __KERNEL_PRINTK__ - -#include -#include -#include -#include -#include - -extern const char linux_banner[]; -extern const char linux_proc_banner[]; - -static inline int printk_get_level(const char *buffer) -{ - if (buffer[0] == KERN_SOH_ASCII && buffer[1]) { - switch (buffer[1]) { - case '0' ... '7': - case 'd': /* KERN_DEFAULT */ - case 'c': /* KERN_CONT */ - return buffer[1]; - } - } - return 0; -} - -static inline const char *printk_skip_level(const char *buffer) -{ - if (printk_get_level(buffer)) - return buffer + 2; - - return buffer; -} - -#define CONSOLE_EXT_LOG_MAX 8192 - -/* printk's without a loglevel use this.. */ -#define MESSAGE_LOGLEVEL_DEFAULT CONFIG_MESSAGE_LOGLEVEL_DEFAULT - -/* We show everything that is MORE important than this.. */ -#define CONSOLE_LOGLEVEL_SILENT 0 /* Mum's the word */ -#define CONSOLE_LOGLEVEL_MIN 1 /* Minimum loglevel we let people use */ -#define CONSOLE_LOGLEVEL_QUIET 4 /* Shhh ..., when booted with "quiet" */ -#define CONSOLE_LOGLEVEL_DEFAULT 7 /* anything MORE serious than KERN_DEBUG */ -#define CONSOLE_LOGLEVEL_DEBUG 10 /* issue debug messages */ -#define CONSOLE_LOGLEVEL_MOTORMOUTH 15 /* You can't shut this one up */ - -extern int console_printk[]; - -#define console_loglevel (console_printk[0]) -#define default_message_loglevel (console_printk[1]) -#define minimum_console_loglevel (console_printk[2]) -#define default_console_loglevel (console_printk[3]) - -static inline void console_silent(void) -{ - console_loglevel = CONSOLE_LOGLEVEL_SILENT; -} - -static inline void console_verbose(void) -{ - if (console_loglevel) - console_loglevel = CONSOLE_LOGLEVEL_MOTORMOUTH; -} - -/* strlen("ratelimit") + 1 */ -#define DEVKMSG_STR_MAX_SIZE 10 -extern char devkmsg_log_str[]; -struct ctl_table; - -struct va_format { - const char *fmt; - va_list *va; -}; - -/* - * FW_BUG - * Add this to a message where you are sure the firmware is buggy or behaves - * really stupid or out of spec. Be aware that the responsible BIOS developer - * should be able to fix this issue or at least get a concrete idea of the - * problem by reading your message without the need of looking at the kernel - * code. - * - * Use it for definite and high priority BIOS bugs. - * - * FW_WARN - * Use it for not that clear (e.g. could the kernel messed up things already?) - * and medium priority BIOS bugs. - * - * FW_INFO - * Use this one if you want to tell the user or vendor about something - * suspicious, but generally harmless related to the firmware. - * - * Use it for information or very low priority BIOS bugs. - */ -#define FW_BUG "[Firmware Bug]: " -#define FW_WARN "[Firmware Warn]: " -#define FW_INFO "[Firmware Info]: " - -/* - * HW_ERR - * Add this to a message for hardware errors, so that user can report - * it to hardware vendor instead of LKML or software vendor. - */ -#define HW_ERR "[Hardware Error]: " - -/* - * DEPRECATED - * Add this to a message whenever you want to warn user space about the use - * of a deprecated aspect of an API so they can stop using it - */ -#define DEPRECATED "[Deprecated]: " - -/* - * Dummy printk for disabled debugging statements to use whilst maintaining - * gcc's format checking. - */ -#define no_printk(fmt, ...) \ -({ \ - do { \ - if (0) \ - printk(fmt, ##__VA_ARGS__); \ - } while (0); \ - 0; \ -}) - -#ifdef CONFIG_EARLY_PRINTK -extern asmlinkage __printf(1, 2) -void early_printk(const char *fmt, ...); -#else -static inline __printf(1, 2) __cold -void early_printk(const char *s, ...) { } -#endif - -#ifdef CONFIG_PRINTK_NMI -extern void printk_nmi_init(void); -extern void printk_nmi_enter(void); -extern void printk_nmi_exit(void); -extern void printk_nmi_flush(void); -extern void printk_nmi_flush_on_panic(void); -#else -static inline void printk_nmi_init(void) { } -static inline void printk_nmi_enter(void) { } -static inline void printk_nmi_exit(void) { } -static inline void printk_nmi_flush(void) { } -static inline void printk_nmi_flush_on_panic(void) { } -#endif /* PRINTK_NMI */ - -#ifdef CONFIG_PRINTK -asmlinkage __printf(5, 0) -int vprintk_emit(int facility, int level, - const char *dict, size_t dictlen, - const char *fmt, va_list args); - -asmlinkage __printf(1, 0) -int vprintk(const char *fmt, va_list args); - -asmlinkage __printf(5, 6) __cold -int printk_emit(int facility, int level, - const char *dict, size_t dictlen, - const char *fmt, ...); - -asmlinkage __printf(1, 2) __cold -int printk(const char *fmt, ...); - -/* - * Special printk facility for scheduler/timekeeping use only, _DO_NOT_USE_ ! - */ -__printf(1, 2) __cold int printk_deferred(const char *fmt, ...); - -/* - * Please don't use printk_ratelimit(), because it shares ratelimiting state - * with all other unrelated printk_ratelimit() callsites. Instead use - * printk_ratelimited() or plain old __ratelimit(). - */ -extern int __printk_ratelimit(const char *func); -#define printk_ratelimit() __printk_ratelimit(__func__) -extern bool printk_timed_ratelimit(unsigned long *caller_jiffies, - unsigned int interval_msec); - -extern int printk_delay_msec; -extern int dmesg_restrict; -extern int kptr_restrict; - -extern int -devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write, void __user *buf, - size_t *lenp, loff_t *ppos); - -extern void wake_up_klogd(void); - -char *log_buf_addr_get(void); -u32 log_buf_len_get(void); -void log_buf_kexec_setup(void); -void __init setup_log_buf(int early); -__printf(1, 2) void dump_stack_set_arch_desc(const char *fmt, ...); -void dump_stack_print_info(const char *log_lvl); -void show_regs_print_info(const char *log_lvl); -#else -static inline __printf(1, 0) -int vprintk(const char *s, va_list args) -{ - return 0; -} -static inline __printf(1, 2) __cold -int printk(const char *s, ...) -{ - return 0; -} -static inline __printf(1, 2) __cold -int printk_deferred(const char *s, ...) -{ - return 0; -} -static inline int printk_ratelimit(void) -{ - return 0; -} -static inline bool printk_timed_ratelimit(unsigned long *caller_jiffies, - unsigned int interval_msec) -{ - return false; -} - -static inline void wake_up_klogd(void) -{ -} - -static inline char *log_buf_addr_get(void) -{ - return NULL; -} - -static inline u32 log_buf_len_get(void) -{ - return 0; -} - -static inline void log_buf_kexec_setup(void) -{ -} - -static inline void setup_log_buf(int early) -{ -} - -static inline __printf(1, 2) void dump_stack_set_arch_desc(const char *fmt, ...) -{ -} - -static inline void dump_stack_print_info(const char *log_lvl) -{ -} - -static inline void show_regs_print_info(const char *log_lvl) -{ -} -#endif - -extern asmlinkage void dump_stack(void) __cold; - -#ifndef pr_fmt -#define pr_fmt(fmt) fmt -#endif - -/* - * These can be used to print at the various log levels. - * All of these will print unconditionally, although note that pr_debug() - * and other debug macros are compiled out unless either DEBUG is defined - * or CONFIG_DYNAMIC_DEBUG is set. - */ -#define pr_emerg(fmt, ...) \ - printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__) -#define pr_alert(fmt, ...) \ - printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__) -#define pr_crit(fmt, ...) \ - printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__) -#define pr_err(fmt, ...) \ - printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) -#define pr_warning(fmt, ...) \ - printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__) -#define pr_warn pr_warning -#define pr_notice(fmt, ...) \ - printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__) -#define pr_info(fmt, ...) \ - printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__) -/* - * Like KERN_CONT, pr_cont() should only be used when continuing - * a line with no newline ('\n') enclosed. Otherwise it defaults - * back to KERN_DEFAULT. - */ -#define pr_cont(fmt, ...) \ - printk(KERN_CONT fmt, ##__VA_ARGS__) - -/* pr_devel() should produce zero code unless DEBUG is defined */ -#ifdef DEBUG -#define pr_devel(fmt, ...) \ - printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) -#else -#define pr_devel(fmt, ...) \ - no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) -#endif - - -/* If you are writing a driver, please use dev_dbg instead */ -#if defined(CONFIG_DYNAMIC_DEBUG) -#include - -/* dynamic_pr_debug() uses pr_fmt() internally so we don't need it here */ -#define pr_debug(fmt, ...) \ - dynamic_pr_debug(fmt, ##__VA_ARGS__) -#elif defined(DEBUG) -#define pr_debug(fmt, ...) \ - printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) -#else -#define pr_debug(fmt, ...) \ - no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) -#endif - -/* - * Print a one-time message (analogous to WARN_ONCE() et al): - */ - -#ifdef CONFIG_PRINTK -#define printk_once(fmt, ...) \ -({ \ - static bool __print_once __read_mostly; \ - bool __ret_print_once = !__print_once; \ - \ - if (!__print_once) { \ - __print_once = true; \ - printk(fmt, ##__VA_ARGS__); \ - } \ - unlikely(__ret_print_once); \ -}) -#define printk_deferred_once(fmt, ...) \ -({ \ - static bool __print_once __read_mostly; \ - bool __ret_print_once = !__print_once; \ - \ - if (!__print_once) { \ - __print_once = true; \ - printk_deferred(fmt, ##__VA_ARGS__); \ - } \ - unlikely(__ret_print_once); \ -}) -#else -#define printk_once(fmt, ...) \ - no_printk(fmt, ##__VA_ARGS__) -#define printk_deferred_once(fmt, ...) \ - no_printk(fmt, ##__VA_ARGS__) -#endif - -#define pr_emerg_once(fmt, ...) \ - printk_once(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__) -#define pr_alert_once(fmt, ...) \ - printk_once(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__) -#define pr_crit_once(fmt, ...) \ - printk_once(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__) -#define pr_err_once(fmt, ...) \ - printk_once(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) -#define pr_warn_once(fmt, ...) \ - printk_once(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__) -#define pr_notice_once(fmt, ...) \ - printk_once(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__) -#define pr_info_once(fmt, ...) \ - printk_once(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__) -#define pr_cont_once(fmt, ...) \ - printk_once(KERN_CONT pr_fmt(fmt), ##__VA_ARGS__) - -#if defined(DEBUG) -#define pr_devel_once(fmt, ...) \ - printk_once(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) -#else -#define pr_devel_once(fmt, ...) \ - no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) -#endif - -/* If you are writing a driver, please use dev_dbg instead */ -#if defined(DEBUG) -#define pr_debug_once(fmt, ...) \ - printk_once(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) -#else -#define pr_debug_once(fmt, ...) \ - no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) -#endif - -/* - * ratelimited messages with local ratelimit_state, - * no local ratelimit_state used in the !PRINTK case - */ -#ifdef CONFIG_PRINTK -#define printk_ratelimited(fmt, ...) \ -({ \ - static DEFINE_RATELIMIT_STATE(_rs, \ - DEFAULT_RATELIMIT_INTERVAL, \ - DEFAULT_RATELIMIT_BURST); \ - \ - if (__ratelimit(&_rs)) \ - printk(fmt, ##__VA_ARGS__); \ -}) -#else -#define printk_ratelimited(fmt, ...) \ - no_printk(fmt, ##__VA_ARGS__) -#endif - -#define pr_emerg_ratelimited(fmt, ...) \ - printk_ratelimited(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__) -#define pr_alert_ratelimited(fmt, ...) \ - printk_ratelimited(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__) -#define pr_crit_ratelimited(fmt, ...) \ - printk_ratelimited(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__) -#define pr_err_ratelimited(fmt, ...) \ - printk_ratelimited(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) -#define pr_warn_ratelimited(fmt, ...) \ - printk_ratelimited(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__) -#define pr_notice_ratelimited(fmt, ...) \ - printk_ratelimited(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__) -#define pr_info_ratelimited(fmt, ...) \ - printk_ratelimited(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__) -/* no pr_cont_ratelimited, don't do that... */ - -#if defined(DEBUG) -#define pr_devel_ratelimited(fmt, ...) \ - printk_ratelimited(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) -#else -#define pr_devel_ratelimited(fmt, ...) \ - no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) -#endif - -/* If you are writing a driver, please use dev_dbg instead */ -#if defined(CONFIG_DYNAMIC_DEBUG) -/* descriptor check is first to prevent flooding with "callbacks suppressed" */ -#define pr_debug_ratelimited(fmt, ...) \ -do { \ - static DEFINE_RATELIMIT_STATE(_rs, \ - DEFAULT_RATELIMIT_INTERVAL, \ - DEFAULT_RATELIMIT_BURST); \ - DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, pr_fmt(fmt)); \ - if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT) && \ - __ratelimit(&_rs)) \ - __dynamic_pr_debug(&descriptor, pr_fmt(fmt), ##__VA_ARGS__); \ -} while (0) -#elif defined(DEBUG) -#define pr_debug_ratelimited(fmt, ...) \ - printk_ratelimited(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) -#else -#define pr_debug_ratelimited(fmt, ...) \ - no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) -#endif - -extern const struct file_operations kmsg_fops; - -enum { - DUMP_PREFIX_NONE, - DUMP_PREFIX_ADDRESS, - DUMP_PREFIX_OFFSET -}; -extern int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, - int groupsize, char *linebuf, size_t linebuflen, - bool ascii); -#ifdef CONFIG_PRINTK -extern void print_hex_dump(const char *level, const char *prefix_str, - int prefix_type, int rowsize, int groupsize, - const void *buf, size_t len, bool ascii); -#if defined(CONFIG_DYNAMIC_DEBUG) -#define print_hex_dump_bytes(prefix_str, prefix_type, buf, len) \ - dynamic_hex_dump(prefix_str, prefix_type, 16, 1, buf, len, true) -#else -extern void print_hex_dump_bytes(const char *prefix_str, int prefix_type, - const void *buf, size_t len); -#endif /* defined(CONFIG_DYNAMIC_DEBUG) */ -#else -static inline void print_hex_dump(const char *level, const char *prefix_str, - int prefix_type, int rowsize, int groupsize, - const void *buf, size_t len, bool ascii) -{ -} -static inline void print_hex_dump_bytes(const char *prefix_str, int prefix_type, - const void *buf, size_t len) -{ -} - -#endif - -#if defined(CONFIG_DYNAMIC_DEBUG) -#define print_hex_dump_debug(prefix_str, prefix_type, rowsize, \ - groupsize, buf, len, ascii) \ - dynamic_hex_dump(prefix_str, prefix_type, rowsize, \ - groupsize, buf, len, ascii) -#elif defined(DEBUG) -#define print_hex_dump_debug(prefix_str, prefix_type, rowsize, \ - groupsize, buf, len, ascii) \ - print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize, \ - groupsize, buf, len, ascii) -#else -static inline void print_hex_dump_debug(const char *prefix_str, int prefix_type, - int rowsize, int groupsize, - const void *buf, size_t len, bool ascii) -{ -} -#endif - -#endif diff --git a/src/linux/include/linux/proc_fs.h b/src/linux/include/linux/proc_fs.h deleted file mode 100644 index b97bf2e..0000000 --- a/src/linux/include/linux/proc_fs.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * The proc filesystem constants/structures - */ -#ifndef _LINUX_PROC_FS_H -#define _LINUX_PROC_FS_H - -#include -#include - -struct proc_dir_entry; - -#ifdef CONFIG_PROC_FS - -extern void proc_root_init(void); -extern void proc_flush_task(struct task_struct *); - -extern struct proc_dir_entry *proc_symlink(const char *, - struct proc_dir_entry *, const char *); -extern struct proc_dir_entry *proc_mkdir(const char *, struct proc_dir_entry *); -extern struct proc_dir_entry *proc_mkdir_data(const char *, umode_t, - struct proc_dir_entry *, void *); -extern struct proc_dir_entry *proc_mkdir_mode(const char *, umode_t, - struct proc_dir_entry *); - -extern struct proc_dir_entry *proc_create_data(const char *, umode_t, - struct proc_dir_entry *, - const struct file_operations *, - void *); - -static inline struct proc_dir_entry *proc_create( - const char *name, umode_t mode, struct proc_dir_entry *parent, - const struct file_operations *proc_fops) -{ - return proc_create_data(name, mode, parent, proc_fops, NULL); -} - -extern void proc_set_size(struct proc_dir_entry *, loff_t); -extern void proc_set_user(struct proc_dir_entry *, kuid_t, kgid_t); -extern void *PDE_DATA(const struct inode *); -extern void *proc_get_parent_data(const struct inode *); -extern void proc_remove(struct proc_dir_entry *); -extern void remove_proc_entry(const char *, struct proc_dir_entry *); -extern int remove_proc_subtree(const char *, struct proc_dir_entry *); - -#else /* CONFIG_PROC_FS */ - -static inline void proc_root_init(void) -{ -} - -static inline void proc_flush_task(struct task_struct *task) -{ -} - -static inline struct proc_dir_entry *proc_symlink(const char *name, - struct proc_dir_entry *parent,const char *dest) { return NULL;} -static inline struct proc_dir_entry *proc_mkdir(const char *name, - struct proc_dir_entry *parent) {return NULL;} -static inline struct proc_dir_entry *proc_mkdir_data(const char *name, - umode_t mode, struct proc_dir_entry *parent, void *data) { return NULL; } -static inline struct proc_dir_entry *proc_mkdir_mode(const char *name, - umode_t mode, struct proc_dir_entry *parent) { return NULL; } -#define proc_create(name, mode, parent, proc_fops) ({NULL;}) -#define proc_create_data(name, mode, parent, proc_fops, data) ({NULL;}) - -static inline void proc_set_size(struct proc_dir_entry *de, loff_t size) {} -static inline void proc_set_user(struct proc_dir_entry *de, kuid_t uid, kgid_t gid) {} -static inline void *PDE_DATA(const struct inode *inode) {BUG(); return NULL;} -static inline void *proc_get_parent_data(const struct inode *inode) { BUG(); return NULL; } - -static inline void proc_remove(struct proc_dir_entry *de) {} -#define remove_proc_entry(name, parent) do {} while (0) -static inline int remove_proc_subtree(const char *name, struct proc_dir_entry *parent) { return 0; } - -#endif /* CONFIG_PROC_FS */ - -struct net; - -static inline struct proc_dir_entry *proc_net_mkdir( - struct net *net, const char *name, struct proc_dir_entry *parent) -{ - return proc_mkdir_data(name, 0, parent, net); -} - -#endif /* _LINUX_PROC_FS_H */ diff --git a/src/linux/include/linux/proc_ns.h b/src/linux/include/linux/proc_ns.h deleted file mode 100644 index 12cb8bd..0000000 --- a/src/linux/include/linux/proc_ns.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * procfs namespace bits - */ -#ifndef _LINUX_PROC_NS_H -#define _LINUX_PROC_NS_H - -#include - -struct pid_namespace; -struct nsproxy; -struct path; -struct task_struct; -struct inode; - -struct proc_ns_operations { - const char *name; - int type; - struct ns_common *(*get)(struct task_struct *task); - void (*put)(struct ns_common *ns); - int (*install)(struct nsproxy *nsproxy, struct ns_common *ns); - struct user_namespace *(*owner)(struct ns_common *ns); - struct ns_common *(*get_parent)(struct ns_common *ns); -}; - -extern const struct proc_ns_operations netns_operations; -extern const struct proc_ns_operations utsns_operations; -extern const struct proc_ns_operations ipcns_operations; -extern const struct proc_ns_operations pidns_operations; -extern const struct proc_ns_operations userns_operations; -extern const struct proc_ns_operations mntns_operations; -extern const struct proc_ns_operations cgroupns_operations; - -/* - * We always define these enumerators - */ -enum { - PROC_ROOT_INO = 1, - PROC_IPC_INIT_INO = 0xEFFFFFFFU, - PROC_UTS_INIT_INO = 0xEFFFFFFEU, - PROC_USER_INIT_INO = 0xEFFFFFFDU, - PROC_PID_INIT_INO = 0xEFFFFFFCU, - PROC_CGROUP_INIT_INO = 0xEFFFFFFBU, -}; - -#ifdef CONFIG_PROC_FS - -extern int pid_ns_prepare_proc(struct pid_namespace *ns); -extern void pid_ns_release_proc(struct pid_namespace *ns); -extern int proc_alloc_inum(unsigned int *pino); -extern void proc_free_inum(unsigned int inum); - -#else /* CONFIG_PROC_FS */ - -static inline int pid_ns_prepare_proc(struct pid_namespace *ns) { return 0; } -static inline void pid_ns_release_proc(struct pid_namespace *ns) {} - -static inline int proc_alloc_inum(unsigned int *inum) -{ - *inum = 1; - return 0; -} -static inline void proc_free_inum(unsigned int inum) {} - -#endif /* CONFIG_PROC_FS */ - -static inline int ns_alloc_inum(struct ns_common *ns) -{ - atomic_long_set(&ns->stashed, 0); - return proc_alloc_inum(&ns->inum); -} - -#define ns_free_inum(ns) proc_free_inum((ns)->inum) - -extern struct file *proc_ns_fget(int fd); -#define get_proc_ns(inode) ((struct ns_common *)(inode)->i_private) -extern void *ns_get_path(struct path *path, struct task_struct *task, - const struct proc_ns_operations *ns_ops); - -extern int ns_get_name(char *buf, size_t size, struct task_struct *task, - const struct proc_ns_operations *ns_ops); -extern void nsfs_init(void); - -#endif /* _LINUX_PROC_NS_H */ diff --git a/src/linux/include/linux/profile.h b/src/linux/include/linux/profile.h deleted file mode 100644 index b537a25..0000000 --- a/src/linux/include/linux/profile.h +++ /dev/null @@ -1,138 +0,0 @@ -#ifndef _LINUX_PROFILE_H -#define _LINUX_PROFILE_H - -#include -#include -#include -#include - -#include - -#define CPU_PROFILING 1 -#define SCHED_PROFILING 2 -#define SLEEP_PROFILING 3 -#define KVM_PROFILING 4 - -struct proc_dir_entry; -struct pt_regs; -struct notifier_block; - -#if defined(CONFIG_PROFILING) && defined(CONFIG_PROC_FS) -void create_prof_cpu_mask(void); -int create_proc_profile(void); -#else -static inline void create_prof_cpu_mask(void) -{ -} - -static inline int create_proc_profile(void) -{ - return 0; -} -#endif - -enum profile_type { - PROFILE_TASK_EXIT, - PROFILE_MUNMAP -}; - -#ifdef CONFIG_PROFILING - -extern int prof_on __read_mostly; - -/* init basic kernel profiler */ -int profile_init(void); -int profile_setup(char *str); -void profile_tick(int type); -int setup_profiling_timer(unsigned int multiplier); - -/* - * Add multiple profiler hits to a given address: - */ -void profile_hits(int type, void *ip, unsigned int nr_hits); - -/* - * Single profiler hit: - */ -static inline void profile_hit(int type, void *ip) -{ - /* - * Speedup for the common (no profiling enabled) case: - */ - if (unlikely(prof_on == type)) - profile_hits(type, ip, 1); -} - -struct task_struct; -struct mm_struct; - -/* task is in do_exit() */ -void profile_task_exit(struct task_struct * task); - -/* task is dead, free task struct ? Returns 1 if - * the task was taken, 0 if the task should be freed. - */ -int profile_handoff_task(struct task_struct * task); - -/* sys_munmap */ -void profile_munmap(unsigned long addr); - -int task_handoff_register(struct notifier_block * n); -int task_handoff_unregister(struct notifier_block * n); - -int profile_event_register(enum profile_type, struct notifier_block * n); -int profile_event_unregister(enum profile_type, struct notifier_block * n); - -struct pt_regs; - -#else - -#define prof_on 0 - -static inline int profile_init(void) -{ - return 0; -} - -static inline void profile_tick(int type) -{ - return; -} - -static inline void profile_hits(int type, void *ip, unsigned int nr_hits) -{ - return; -} - -static inline void profile_hit(int type, void *ip) -{ - return; -} - -static inline int task_handoff_register(struct notifier_block * n) -{ - return -ENOSYS; -} - -static inline int task_handoff_unregister(struct notifier_block * n) -{ - return -ENOSYS; -} - -static inline int profile_event_register(enum profile_type t, struct notifier_block * n) -{ - return -ENOSYS; -} - -static inline int profile_event_unregister(enum profile_type t, struct notifier_block * n) -{ - return -ENOSYS; -} - -#define profile_task_exit(a) do { } while (0) -#define profile_handoff_task(a) (0) -#define profile_munmap(a) do { } while (0) - -#endif /* CONFIG_PROFILING */ - -#endif /* _LINUX_PROFILE_H */ diff --git a/src/linux/include/linux/projid.h b/src/linux/include/linux/projid.h deleted file mode 100644 index 8c1f2c5..0000000 --- a/src/linux/include/linux/projid.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef _LINUX_PROJID_H -#define _LINUX_PROJID_H - -/* - * A set of types for the internal kernel types representing project ids. - * - * The types defined in this header allow distinguishing which project ids in - * the kernel are values used by userspace and which project id values are - * the internal kernel values. With the addition of user namespaces the values - * can be different. Using the type system makes it possible for the compiler - * to detect when we overlook these differences. - * - */ -#include - -struct user_namespace; -extern struct user_namespace init_user_ns; - -typedef __kernel_uid32_t projid_t; - -typedef struct { - projid_t val; -} kprojid_t; - -static inline projid_t __kprojid_val(kprojid_t projid) -{ - return projid.val; -} - -#define KPROJIDT_INIT(value) (kprojid_t){ value } - -#define INVALID_PROJID KPROJIDT_INIT(-1) -#define OVERFLOW_PROJID 65534 - -static inline bool projid_eq(kprojid_t left, kprojid_t right) -{ - return __kprojid_val(left) == __kprojid_val(right); -} - -static inline bool projid_lt(kprojid_t left, kprojid_t right) -{ - return __kprojid_val(left) < __kprojid_val(right); -} - -static inline bool projid_valid(kprojid_t projid) -{ - return !projid_eq(projid, INVALID_PROJID); -} - -#ifdef CONFIG_USER_NS - -extern kprojid_t make_kprojid(struct user_namespace *from, projid_t projid); - -extern projid_t from_kprojid(struct user_namespace *to, kprojid_t projid); -extern projid_t from_kprojid_munged(struct user_namespace *to, kprojid_t projid); - -static inline bool kprojid_has_mapping(struct user_namespace *ns, kprojid_t projid) -{ - return from_kprojid(ns, projid) != (projid_t)-1; -} - -#else - -static inline kprojid_t make_kprojid(struct user_namespace *from, projid_t projid) -{ - return KPROJIDT_INIT(projid); -} - -static inline projid_t from_kprojid(struct user_namespace *to, kprojid_t kprojid) -{ - return __kprojid_val(kprojid); -} - -static inline projid_t from_kprojid_munged(struct user_namespace *to, kprojid_t kprojid) -{ - projid_t projid = from_kprojid(to, kprojid); - if (projid == (projid_t)-1) - projid = OVERFLOW_PROJID; - return projid; -} - -static inline bool kprojid_has_mapping(struct user_namespace *ns, kprojid_t projid) -{ - return true; -} - -#endif /* CONFIG_USER_NS */ - -#endif /* _LINUX_PROJID_H */ diff --git a/src/linux/include/linux/property.h b/src/linux/include/linux/property.h deleted file mode 100644 index 856e50b..0000000 --- a/src/linux/include/linux/property.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * property.h - Unified device property interface. - * - * Copyright (C) 2014, Intel Corporation - * Authors: Rafael J. Wysocki - * Mika Westerberg - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _LINUX_PROPERTY_H_ -#define _LINUX_PROPERTY_H_ - -#include -#include - -struct device; - -enum dev_prop_type { - DEV_PROP_U8, - DEV_PROP_U16, - DEV_PROP_U32, - DEV_PROP_U64, - DEV_PROP_STRING, - DEV_PROP_MAX, -}; - -enum dev_dma_attr { - DEV_DMA_NOT_SUPPORTED, - DEV_DMA_NON_COHERENT, - DEV_DMA_COHERENT, -}; - -bool device_property_present(struct device *dev, const char *propname); -int device_property_read_u8_array(struct device *dev, const char *propname, - u8 *val, size_t nval); -int device_property_read_u16_array(struct device *dev, const char *propname, - u16 *val, size_t nval); -int device_property_read_u32_array(struct device *dev, const char *propname, - u32 *val, size_t nval); -int device_property_read_u64_array(struct device *dev, const char *propname, - u64 *val, size_t nval); -int device_property_read_string_array(struct device *dev, const char *propname, - const char **val, size_t nval); -int device_property_read_string(struct device *dev, const char *propname, - const char **val); -int device_property_match_string(struct device *dev, - const char *propname, const char *string); - -bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname); -int fwnode_property_read_u8_array(struct fwnode_handle *fwnode, - const char *propname, u8 *val, - size_t nval); -int fwnode_property_read_u16_array(struct fwnode_handle *fwnode, - const char *propname, u16 *val, - size_t nval); -int fwnode_property_read_u32_array(struct fwnode_handle *fwnode, - const char *propname, u32 *val, - size_t nval); -int fwnode_property_read_u64_array(struct fwnode_handle *fwnode, - const char *propname, u64 *val, - size_t nval); -int fwnode_property_read_string_array(struct fwnode_handle *fwnode, - const char *propname, const char **val, - size_t nval); -int fwnode_property_read_string(struct fwnode_handle *fwnode, - const char *propname, const char **val); -int fwnode_property_match_string(struct fwnode_handle *fwnode, - const char *propname, const char *string); - -struct fwnode_handle *device_get_next_child_node(struct device *dev, - struct fwnode_handle *child); - -#define device_for_each_child_node(dev, child) \ - for (child = device_get_next_child_node(dev, NULL); child; \ - child = device_get_next_child_node(dev, child)) - -struct fwnode_handle *device_get_named_child_node(struct device *dev, - const char *childname); - -void fwnode_handle_put(struct fwnode_handle *fwnode); - -unsigned int device_get_child_node_count(struct device *dev); - -static inline bool device_property_read_bool(struct device *dev, - const char *propname) -{ - return device_property_present(dev, propname); -} - -static inline int device_property_read_u8(struct device *dev, - const char *propname, u8 *val) -{ - return device_property_read_u8_array(dev, propname, val, 1); -} - -static inline int device_property_read_u16(struct device *dev, - const char *propname, u16 *val) -{ - return device_property_read_u16_array(dev, propname, val, 1); -} - -static inline int device_property_read_u32(struct device *dev, - const char *propname, u32 *val) -{ - return device_property_read_u32_array(dev, propname, val, 1); -} - -static inline int device_property_read_u64(struct device *dev, - const char *propname, u64 *val) -{ - return device_property_read_u64_array(dev, propname, val, 1); -} - -static inline bool fwnode_property_read_bool(struct fwnode_handle *fwnode, - const char *propname) -{ - return fwnode_property_present(fwnode, propname); -} - -static inline int fwnode_property_read_u8(struct fwnode_handle *fwnode, - const char *propname, u8 *val) -{ - return fwnode_property_read_u8_array(fwnode, propname, val, 1); -} - -static inline int fwnode_property_read_u16(struct fwnode_handle *fwnode, - const char *propname, u16 *val) -{ - return fwnode_property_read_u16_array(fwnode, propname, val, 1); -} - -static inline int fwnode_property_read_u32(struct fwnode_handle *fwnode, - const char *propname, u32 *val) -{ - return fwnode_property_read_u32_array(fwnode, propname, val, 1); -} - -static inline int fwnode_property_read_u64(struct fwnode_handle *fwnode, - const char *propname, u64 *val) -{ - return fwnode_property_read_u64_array(fwnode, propname, val, 1); -} - -/** - * struct property_entry - "Built-in" device property representation. - * @name: Name of the property. - * @length: Length of data making up the value. - * @is_array: True when the property is an array. - * @is_string: True when property is a string. - * @pointer: Pointer to the property (an array of items of the given type). - * @value: Value of the property (when it is a single item of the given type). - */ -struct property_entry { - const char *name; - size_t length; - bool is_array; - bool is_string; - union { - union { - void *raw_data; - u8 *u8_data; - u16 *u16_data; - u32 *u32_data; - u64 *u64_data; - const char **str; - } pointer; - union { - unsigned long long raw_data; - u8 u8_data; - u16 u16_data; - u32 u32_data; - u64 u64_data; - const char *str; - } value; - }; -}; - -/* - * Note: the below four initializers for the anonymous union are carefully - * crafted to avoid gcc-4.4.4's problems with initialization of anon unions - * and structs. - */ - -#define PROPERTY_ENTRY_INTEGER_ARRAY(_name_, _type_, _val_) \ -{ \ - .name = _name_, \ - .length = ARRAY_SIZE(_val_) * sizeof(_type_), \ - .is_array = true, \ - .is_string = false, \ - { .pointer = { ._type_##_data = _val_ } }, \ -} - -#define PROPERTY_ENTRY_U8_ARRAY(_name_, _val_) \ - PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u8, _val_) -#define PROPERTY_ENTRY_U16_ARRAY(_name_, _val_) \ - PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u16, _val_) -#define PROPERTY_ENTRY_U32_ARRAY(_name_, _val_) \ - PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u32, _val_) -#define PROPERTY_ENTRY_U64_ARRAY(_name_, _val_) \ - PROPERTY_ENTRY_INTEGER_ARRAY(_name_, u64, _val_) - -#define PROPERTY_ENTRY_STRING_ARRAY(_name_, _val_) \ -{ \ - .name = _name_, \ - .length = ARRAY_SIZE(_val_) * sizeof(const char *), \ - .is_array = true, \ - .is_string = true, \ - { .pointer = { .str = _val_ } }, \ -} - -#define PROPERTY_ENTRY_INTEGER(_name_, _type_, _val_) \ -{ \ - .name = _name_, \ - .length = sizeof(_type_), \ - .is_string = false, \ - { .value = { ._type_##_data = _val_ } }, \ -} - -#define PROPERTY_ENTRY_U8(_name_, _val_) \ - PROPERTY_ENTRY_INTEGER(_name_, u8, _val_) -#define PROPERTY_ENTRY_U16(_name_, _val_) \ - PROPERTY_ENTRY_INTEGER(_name_, u16, _val_) -#define PROPERTY_ENTRY_U32(_name_, _val_) \ - PROPERTY_ENTRY_INTEGER(_name_, u32, _val_) -#define PROPERTY_ENTRY_U64(_name_, _val_) \ - PROPERTY_ENTRY_INTEGER(_name_, u64, _val_) - -#define PROPERTY_ENTRY_STRING(_name_, _val_) \ -{ \ - .name = _name_, \ - .length = sizeof(_val_), \ - .is_string = true, \ - { .value = { .str = _val_ } }, \ -} - -#define PROPERTY_ENTRY_BOOL(_name_) \ -{ \ - .name = _name_, \ -} - -int device_add_properties(struct device *dev, - struct property_entry *properties); -void device_remove_properties(struct device *dev); - -bool device_dma_supported(struct device *dev); - -enum dev_dma_attr device_get_dma_attr(struct device *dev); - -int device_get_phy_mode(struct device *dev); - -void *device_get_mac_address(struct device *dev, char *addr, int alen); - -#endif /* _LINUX_PROPERTY_H_ */ diff --git a/src/linux/include/linux/pstore.h b/src/linux/include/linux/pstore.h deleted file mode 100644 index 92013cc..0000000 --- a/src/linux/include/linux/pstore.h +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Persistent Storage - pstore.h - * - * Copyright (C) 2010 Intel Corporation - * - * This code is the generic layer to export data records from platform - * level persistent storage via a file system. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#ifndef _LINUX_PSTORE_H -#define _LINUX_PSTORE_H - -#include -#include -#include -#include -#include -#include -#include - -/* types */ -enum pstore_type_id { - PSTORE_TYPE_DMESG = 0, - PSTORE_TYPE_MCE = 1, - PSTORE_TYPE_CONSOLE = 2, - PSTORE_TYPE_FTRACE = 3, - /* PPC64 partition types */ - PSTORE_TYPE_PPC_RTAS = 4, - PSTORE_TYPE_PPC_OF = 5, - PSTORE_TYPE_PPC_COMMON = 6, - PSTORE_TYPE_PMSG = 7, - PSTORE_TYPE_PPC_OPAL = 8, - PSTORE_TYPE_UNKNOWN = 255 -}; - -struct module; - -struct pstore_info { - struct module *owner; - char *name; - spinlock_t buf_lock; /* serialize access to 'buf' */ - char *buf; - size_t bufsize; - struct mutex read_mutex; /* serialize open/read/close */ - int flags; - int (*open)(struct pstore_info *psi); - int (*close)(struct pstore_info *psi); - ssize_t (*read)(u64 *id, enum pstore_type_id *type, - int *count, struct timespec *time, char **buf, - bool *compressed, ssize_t *ecc_notice_size, - struct pstore_info *psi); - int (*write)(enum pstore_type_id type, - enum kmsg_dump_reason reason, u64 *id, - unsigned int part, int count, bool compressed, - size_t size, struct pstore_info *psi); - int (*write_buf)(enum pstore_type_id type, - enum kmsg_dump_reason reason, u64 *id, - unsigned int part, const char *buf, bool compressed, - size_t size, struct pstore_info *psi); - int (*write_buf_user)(enum pstore_type_id type, - enum kmsg_dump_reason reason, u64 *id, - unsigned int part, const char __user *buf, - bool compressed, size_t size, struct pstore_info *psi); - int (*erase)(enum pstore_type_id type, u64 id, - int count, struct timespec time, - struct pstore_info *psi); - void *data; -}; - -#define PSTORE_FLAGS_DMESG (1 << 0) -#define PSTORE_FLAGS_FRAGILE PSTORE_FLAGS_DMESG -#define PSTORE_FLAGS_CONSOLE (1 << 1) -#define PSTORE_FLAGS_FTRACE (1 << 2) -#define PSTORE_FLAGS_PMSG (1 << 3) - -extern int pstore_register(struct pstore_info *); -extern void pstore_unregister(struct pstore_info *); -extern bool pstore_cannot_block_path(enum kmsg_dump_reason reason); - -#endif /*_LINUX_PSTORE_H*/ diff --git a/src/linux/include/linux/ptp_classify.h b/src/linux/include/linux/ptp_classify.h deleted file mode 100644 index a079656..0000000 --- a/src/linux/include/linux/ptp_classify.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * PTP 1588 support - * - * This file implements a BPF that recognizes PTP event messages. - * - * Copyright (C) 2010 OMICRON electronics GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _PTP_CLASSIFY_H_ -#define _PTP_CLASSIFY_H_ - -#include -#include - -#define PTP_CLASS_NONE 0x00 /* not a PTP event message */ -#define PTP_CLASS_V1 0x01 /* protocol version 1 */ -#define PTP_CLASS_V2 0x02 /* protocol version 2 */ -#define PTP_CLASS_VMASK 0x0f /* max protocol version is 15 */ -#define PTP_CLASS_IPV4 0x10 /* event in an IPV4 UDP packet */ -#define PTP_CLASS_IPV6 0x20 /* event in an IPV6 UDP packet */ -#define PTP_CLASS_L2 0x40 /* event in a L2 packet */ -#define PTP_CLASS_PMASK 0x70 /* mask for the packet type field */ -#define PTP_CLASS_VLAN 0x80 /* event in a VLAN tagged packet */ - -#define PTP_CLASS_V1_IPV4 (PTP_CLASS_V1 | PTP_CLASS_IPV4) -#define PTP_CLASS_V1_IPV6 (PTP_CLASS_V1 | PTP_CLASS_IPV6) /* probably DNE */ -#define PTP_CLASS_V2_IPV4 (PTP_CLASS_V2 | PTP_CLASS_IPV4) -#define PTP_CLASS_V2_IPV6 (PTP_CLASS_V2 | PTP_CLASS_IPV6) -#define PTP_CLASS_V2_L2 (PTP_CLASS_V2 | PTP_CLASS_L2) -#define PTP_CLASS_V2_VLAN (PTP_CLASS_V2 | PTP_CLASS_VLAN) -#define PTP_CLASS_L4 (PTP_CLASS_IPV4 | PTP_CLASS_IPV6) - -#define PTP_EV_PORT 319 -#define PTP_GEN_BIT 0x08 /* indicates general message, if set in message type */ - -#define OFF_PTP_SOURCE_UUID 22 /* PTPv1 only */ -#define OFF_PTP_SEQUENCE_ID 30 -#define OFF_PTP_CONTROL 32 /* PTPv1 only */ - -/* Below defines should actually be removed at some point in time. */ -#define IP6_HLEN 40 -#define UDP_HLEN 8 -#define OFF_IHL 14 -#define IPV4_HLEN(data) (((struct iphdr *)(data + OFF_IHL))->ihl << 2) - -#if defined(CONFIG_NET_PTP_CLASSIFY) -/** - * ptp_classify_raw - classify a PTP packet - * @skb: buffer - * - * Runs a minimal BPF dissector to classify a network packet to - * determine the PTP class. In case the skb does not contain any - * PTP protocol data, PTP_CLASS_NONE will be returned, otherwise - * PTP_CLASS_V1_IPV{4,6}, PTP_CLASS_V2_IPV{4,6} or - * PTP_CLASS_V2_{L2,VLAN}, depending on the packet content. - */ -unsigned int ptp_classify_raw(const struct sk_buff *skb); - -void __init ptp_classifier_init(void); -#else -static inline void ptp_classifier_init(void) -{ -} -#endif -#endif /* _PTP_CLASSIFY_H_ */ diff --git a/src/linux/include/linux/ptrace.h b/src/linux/include/linux/ptrace.h deleted file mode 100644 index 504c98a..0000000 --- a/src/linux/include/linux/ptrace.h +++ /dev/null @@ -1,409 +0,0 @@ -#ifndef _LINUX_PTRACE_H -#define _LINUX_PTRACE_H - -#include /* For unlikely. */ -#include /* For struct task_struct. */ -#include /* for IS_ERR_VALUE */ -#include /* For BUG_ON. */ -#include /* For task_active_pid_ns. */ -#include - -/* - * Ptrace flags - * - * The owner ship rules for task->ptrace which holds the ptrace - * flags is simple. When a task is running it owns it's task->ptrace - * flags. When the a task is stopped the ptracer owns task->ptrace. - */ - -#define PT_SEIZED 0x00010000 /* SEIZE used, enable new behavior */ -#define PT_PTRACED 0x00000001 -#define PT_DTRACE 0x00000002 /* delayed trace (used on m68k, i386) */ -#define PT_PTRACE_CAP 0x00000004 /* ptracer can follow suid-exec */ - -#define PT_OPT_FLAG_SHIFT 3 -/* PT_TRACE_* event enable flags */ -#define PT_EVENT_FLAG(event) (1 << (PT_OPT_FLAG_SHIFT + (event))) -#define PT_TRACESYSGOOD PT_EVENT_FLAG(0) -#define PT_TRACE_FORK PT_EVENT_FLAG(PTRACE_EVENT_FORK) -#define PT_TRACE_VFORK PT_EVENT_FLAG(PTRACE_EVENT_VFORK) -#define PT_TRACE_CLONE PT_EVENT_FLAG(PTRACE_EVENT_CLONE) -#define PT_TRACE_EXEC PT_EVENT_FLAG(PTRACE_EVENT_EXEC) -#define PT_TRACE_VFORK_DONE PT_EVENT_FLAG(PTRACE_EVENT_VFORK_DONE) -#define PT_TRACE_EXIT PT_EVENT_FLAG(PTRACE_EVENT_EXIT) -#define PT_TRACE_SECCOMP PT_EVENT_FLAG(PTRACE_EVENT_SECCOMP) - -#define PT_EXITKILL (PTRACE_O_EXITKILL << PT_OPT_FLAG_SHIFT) -#define PT_SUSPEND_SECCOMP (PTRACE_O_SUSPEND_SECCOMP << PT_OPT_FLAG_SHIFT) - -/* single stepping state bits (used on ARM and PA-RISC) */ -#define PT_SINGLESTEP_BIT 31 -#define PT_SINGLESTEP (1<real_parent, child->parent); -} - -static inline void ptrace_unlink(struct task_struct *child) -{ - if (unlikely(child->ptrace)) - __ptrace_unlink(child); -} - -int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr, - unsigned long data); -int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr, - unsigned long data); - -/** - * ptrace_parent - return the task that is tracing the given task - * @task: task to consider - * - * Returns %NULL if no one is tracing @task, or the &struct task_struct - * pointer to its tracer. - * - * Must called under rcu_read_lock(). The pointer returned might be kept - * live only by RCU. During exec, this may be called with task_lock() held - * on @task, still held from when check_unsafe_exec() was called. - */ -static inline struct task_struct *ptrace_parent(struct task_struct *task) -{ - if (unlikely(task->ptrace)) - return rcu_dereference(task->parent); - return NULL; -} - -/** - * ptrace_event_enabled - test whether a ptrace event is enabled - * @task: ptracee of interest - * @event: %PTRACE_EVENT_* to test - * - * Test whether @event is enabled for ptracee @task. - * - * Returns %true if @event is enabled, %false otherwise. - */ -static inline bool ptrace_event_enabled(struct task_struct *task, int event) -{ - return task->ptrace & PT_EVENT_FLAG(event); -} - -/** - * ptrace_event - possibly stop for a ptrace event notification - * @event: %PTRACE_EVENT_* value to report - * @message: value for %PTRACE_GETEVENTMSG to return - * - * Check whether @event is enabled and, if so, report @event and @message - * to the ptrace parent. - * - * Called without locks. - */ -static inline void ptrace_event(int event, unsigned long message) -{ - if (unlikely(ptrace_event_enabled(current, event))) { - current->ptrace_message = message; - ptrace_notify((event << 8) | SIGTRAP); - } else if (event == PTRACE_EVENT_EXEC) { - /* legacy EXEC report via SIGTRAP */ - if ((current->ptrace & (PT_PTRACED|PT_SEIZED)) == PT_PTRACED) - send_sig(SIGTRAP, current, 0); - } -} - -/** - * ptrace_event_pid - possibly stop for a ptrace event notification - * @event: %PTRACE_EVENT_* value to report - * @pid: process identifier for %PTRACE_GETEVENTMSG to return - * - * Check whether @event is enabled and, if so, report @event and @pid - * to the ptrace parent. @pid is reported as the pid_t seen from the - * the ptrace parent's pid namespace. - * - * Called without locks. - */ -static inline void ptrace_event_pid(int event, struct pid *pid) -{ - /* - * FIXME: There's a potential race if a ptracer in a different pid - * namespace than parent attaches between computing message below and - * when we acquire tasklist_lock in ptrace_stop(). If this happens, - * the ptracer will get a bogus pid from PTRACE_GETEVENTMSG. - */ - unsigned long message = 0; - struct pid_namespace *ns; - - rcu_read_lock(); - ns = task_active_pid_ns(rcu_dereference(current->parent)); - if (ns) - message = pid_nr_ns(pid, ns); - rcu_read_unlock(); - - ptrace_event(event, message); -} - -/** - * ptrace_init_task - initialize ptrace state for a new child - * @child: new child task - * @ptrace: true if child should be ptrace'd by parent's tracer - * - * This is called immediately after adding @child to its parent's children - * list. @ptrace is false in the normal case, and true to ptrace @child. - * - * Called with current's siglock and write_lock_irq(&tasklist_lock) held. - */ -static inline void ptrace_init_task(struct task_struct *child, bool ptrace) -{ - INIT_LIST_HEAD(&child->ptrace_entry); - INIT_LIST_HEAD(&child->ptraced); - child->jobctl = 0; - child->ptrace = 0; - child->parent = child->real_parent; - - if (unlikely(ptrace) && current->ptrace) { - child->ptrace = current->ptrace; - __ptrace_link(child, current->parent); - - if (child->ptrace & PT_SEIZED) - task_set_jobctl_pending(child, JOBCTL_TRAP_STOP); - else - sigaddset(&child->pending.signal, SIGSTOP); - - set_tsk_thread_flag(child, TIF_SIGPENDING); - } -} - -/** - * ptrace_release_task - final ptrace-related cleanup of a zombie being reaped - * @task: task in %EXIT_DEAD state - * - * Called with write_lock(&tasklist_lock) held. - */ -static inline void ptrace_release_task(struct task_struct *task) -{ - BUG_ON(!list_empty(&task->ptraced)); - ptrace_unlink(task); - BUG_ON(!list_empty(&task->ptrace_entry)); -} - -#ifndef force_successful_syscall_return -/* - * System call handlers that, upon successful completion, need to return a - * negative value should call force_successful_syscall_return() right before - * returning. On architectures where the syscall convention provides for a - * separate error flag (e.g., alpha, ia64, ppc{,64}, sparc{,64}, possibly - * others), this macro can be used to ensure that the error flag will not get - * set. On architectures which do not support a separate error flag, the macro - * is a no-op and the spurious error condition needs to be filtered out by some - * other means (e.g., in user-level, by passing an extra argument to the - * syscall handler, or something along those lines). - */ -#define force_successful_syscall_return() do { } while (0) -#endif - -#ifndef is_syscall_success -/* - * On most systems we can tell if a syscall is a success based on if the retval - * is an error value. On some systems like ia64 and powerpc they have different - * indicators of success/failure and must define their own. - */ -#define is_syscall_success(regs) (!IS_ERR_VALUE((unsigned long)(regs_return_value(regs)))) -#endif - -/* - * should define the following things inside #ifdef __KERNEL__. - * - * These do-nothing inlines are used when the arch does not - * implement single-step. The kerneldoc comments are here - * to document the interface for all arch definitions. - */ - -#ifndef arch_has_single_step -/** - * arch_has_single_step - does this CPU support user-mode single-step? - * - * If this is defined, then there must be function declarations or - * inlines for user_enable_single_step() and user_disable_single_step(). - * arch_has_single_step() should evaluate to nonzero iff the machine - * supports instruction single-step for user mode. - * It can be a constant or it can test a CPU feature bit. - */ -#define arch_has_single_step() (0) - -/** - * user_enable_single_step - single-step in user-mode task - * @task: either current or a task stopped in %TASK_TRACED - * - * This can only be called when arch_has_single_step() has returned nonzero. - * Set @task so that when it returns to user mode, it will trap after the - * next single instruction executes. If arch_has_block_step() is defined, - * this must clear the effects of user_enable_block_step() too. - */ -static inline void user_enable_single_step(struct task_struct *task) -{ - BUG(); /* This can never be called. */ -} - -/** - * user_disable_single_step - cancel user-mode single-step - * @task: either current or a task stopped in %TASK_TRACED - * - * Clear @task of the effects of user_enable_single_step() and - * user_enable_block_step(). This can be called whether or not either - * of those was ever called on @task, and even if arch_has_single_step() - * returned zero. - */ -static inline void user_disable_single_step(struct task_struct *task) -{ -} -#else -extern void user_enable_single_step(struct task_struct *); -extern void user_disable_single_step(struct task_struct *); -#endif /* arch_has_single_step */ - -#ifndef arch_has_block_step -/** - * arch_has_block_step - does this CPU support user-mode block-step? - * - * If this is defined, then there must be a function declaration or inline - * for user_enable_block_step(), and arch_has_single_step() must be defined - * too. arch_has_block_step() should evaluate to nonzero iff the machine - * supports step-until-branch for user mode. It can be a constant or it - * can test a CPU feature bit. - */ -#define arch_has_block_step() (0) - -/** - * user_enable_block_step - step until branch in user-mode task - * @task: either current or a task stopped in %TASK_TRACED - * - * This can only be called when arch_has_block_step() has returned nonzero, - * and will never be called when single-instruction stepping is being used. - * Set @task so that when it returns to user mode, it will trap after the - * next branch or trap taken. - */ -static inline void user_enable_block_step(struct task_struct *task) -{ - BUG(); /* This can never be called. */ -} -#else -extern void user_enable_block_step(struct task_struct *); -#endif /* arch_has_block_step */ - -#ifdef ARCH_HAS_USER_SINGLE_STEP_INFO -extern void user_single_step_siginfo(struct task_struct *tsk, - struct pt_regs *regs, siginfo_t *info); -#else -static inline void user_single_step_siginfo(struct task_struct *tsk, - struct pt_regs *regs, siginfo_t *info) -{ - memset(info, 0, sizeof(*info)); - info->si_signo = SIGTRAP; -} -#endif - -#ifndef arch_ptrace_stop_needed -/** - * arch_ptrace_stop_needed - Decide whether arch_ptrace_stop() should be called - * @code: current->exit_code value ptrace will stop with - * @info: siginfo_t pointer (or %NULL) for signal ptrace will stop with - * - * This is called with the siglock held, to decide whether or not it's - * necessary to release the siglock and call arch_ptrace_stop() with the - * same @code and @info arguments. It can be defined to a constant if - * arch_ptrace_stop() is never required, or always is. On machines where - * this makes sense, it should be defined to a quick test to optimize out - * calling arch_ptrace_stop() when it would be superfluous. For example, - * if the thread has not been back to user mode since the last stop, the - * thread state might indicate that nothing needs to be done. - * - * This is guaranteed to be invoked once before a task stops for ptrace and - * may include arch-specific operations necessary prior to a ptrace stop. - */ -#define arch_ptrace_stop_needed(code, info) (0) -#endif - -#ifndef arch_ptrace_stop -/** - * arch_ptrace_stop - Do machine-specific work before stopping for ptrace - * @code: current->exit_code value ptrace will stop with - * @info: siginfo_t pointer (or %NULL) for signal ptrace will stop with - * - * This is called with no locks held when arch_ptrace_stop_needed() has - * just returned nonzero. It is allowed to block, e.g. for user memory - * access. The arch can have machine-specific work to be done before - * ptrace stops. On ia64, register backing store gets written back to user - * memory here. Since this can be costly (requires dropping the siglock), - * we only do it when the arch requires it for this particular stop, as - * indicated by arch_ptrace_stop_needed(). - */ -#define arch_ptrace_stop(code, info) do { } while (0) -#endif - -#ifndef current_pt_regs -#define current_pt_regs() task_pt_regs(current) -#endif - -#ifndef ptrace_signal_deliver -#define ptrace_signal_deliver() ((void)0) -#endif - -/* - * unlike current_pt_regs(), this one is equal to task_pt_regs(current) - * on *all* architectures; the only reason to have a per-arch definition - * is optimisation. - */ -#ifndef signal_pt_regs -#define signal_pt_regs() task_pt_regs(current) -#endif - -#ifndef current_user_stack_pointer -#define current_user_stack_pointer() user_stack_pointer(current_pt_regs()) -#endif - -extern int task_current_syscall(struct task_struct *target, long *callno, - unsigned long args[6], unsigned int maxargs, - unsigned long *sp, unsigned long *pc); - -#endif diff --git a/src/linux/include/linux/pvclock_gtod.h b/src/linux/include/linux/pvclock_gtod.h deleted file mode 100644 index a71d2db..0000000 --- a/src/linux/include/linux/pvclock_gtod.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _PVCLOCK_GTOD_H -#define _PVCLOCK_GTOD_H - -#include - -/* - * The pvclock gtod notifier is called when the system time is updated - * and is used to keep guest time synchronized with host time. - * - * The 'action' parameter in the notifier function is false (0), or - * true (non-zero) if system time was stepped. - */ -extern int pvclock_gtod_register_notifier(struct notifier_block *nb); -extern int pvclock_gtod_unregister_notifier(struct notifier_block *nb); - -#endif /* _PVCLOCK_GTOD_H */ diff --git a/src/linux/include/linux/quicklist.h b/src/linux/include/linux/quicklist.h deleted file mode 100644 index 3bdfa70..0000000 --- a/src/linux/include/linux/quicklist.h +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef LINUX_QUICKLIST_H -#define LINUX_QUICKLIST_H -/* - * Fast allocations and disposal of pages. Pages must be in the condition - * as needed after allocation when they are freed. Per cpu lists of pages - * are kept that only contain node local pages. - * - * (C) 2007, SGI. Christoph Lameter - */ -#include -#include -#include - -#ifdef CONFIG_QUICKLIST - -struct quicklist { - void *page; - int nr_pages; -}; - -DECLARE_PER_CPU(struct quicklist, quicklist)[CONFIG_NR_QUICK]; - -/* - * The two key functions quicklist_alloc and quicklist_free are inline so - * that they may be custom compiled for the platform. - * Specifying a NULL ctor can remove constructor support. Specifying - * a constant quicklist allows the determination of the exact address - * in the per cpu area. - * - * The fast patch in quicklist_alloc touched only a per cpu cacheline and - * the first cacheline of the page itself. There is minmal overhead involved. - */ -static inline void *quicklist_alloc(int nr, gfp_t flags, void (*ctor)(void *)) -{ - struct quicklist *q; - void **p = NULL; - - q =&get_cpu_var(quicklist)[nr]; - p = q->page; - if (likely(p)) { - q->page = p[0]; - p[0] = NULL; - q->nr_pages--; - } - put_cpu_var(quicklist); - if (likely(p)) - return p; - - p = (void *)__get_free_page(flags | __GFP_ZERO); - if (ctor && p) - ctor(p); - return p; -} - -static inline void __quicklist_free(int nr, void (*dtor)(void *), void *p, - struct page *page) -{ - struct quicklist *q; - - q = &get_cpu_var(quicklist)[nr]; - *(void **)p = q->page; - q->page = p; - q->nr_pages++; - put_cpu_var(quicklist); -} - -static inline void quicklist_free(int nr, void (*dtor)(void *), void *pp) -{ - __quicklist_free(nr, dtor, pp, virt_to_page(pp)); -} - -static inline void quicklist_free_page(int nr, void (*dtor)(void *), - struct page *page) -{ - __quicklist_free(nr, dtor, page_address(page), page); -} - -void quicklist_trim(int nr, void (*dtor)(void *), - unsigned long min_pages, unsigned long max_free); - -unsigned long quicklist_total_size(void); - -#else - -static inline unsigned long quicklist_total_size(void) -{ - return 0; -} - -#endif - -#endif /* LINUX_QUICKLIST_H */ - diff --git a/src/linux/include/linux/quota.h b/src/linux/include/linux/quota.h deleted file mode 100644 index 55107a8..0000000 --- a/src/linux/include/linux/quota.h +++ /dev/null @@ -1,543 +0,0 @@ -/* - * Copyright (c) 1982, 1986 Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Robert Elz at The University of Melbourne. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ -#ifndef _LINUX_QUOTA_ -#define _LINUX_QUOTA_ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#undef USRQUOTA -#undef GRPQUOTA -#undef PRJQUOTA -enum quota_type { - USRQUOTA = 0, /* element used for user quotas */ - GRPQUOTA = 1, /* element used for group quotas */ - PRJQUOTA = 2, /* element used for project quotas */ -}; - -/* Masks for quota types when used as a bitmask */ -#define QTYPE_MASK_USR (1 << USRQUOTA) -#define QTYPE_MASK_GRP (1 << GRPQUOTA) -#define QTYPE_MASK_PRJ (1 << PRJQUOTA) - -typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */ -typedef long long qsize_t; /* Type in which we store sizes */ - -struct kqid { /* Type in which we store the quota identifier */ - union { - kuid_t uid; - kgid_t gid; - kprojid_t projid; - }; - enum quota_type type; /* USRQUOTA (uid) or GRPQUOTA (gid) or PRJQUOTA (projid) */ -}; - -extern bool qid_eq(struct kqid left, struct kqid right); -extern bool qid_lt(struct kqid left, struct kqid right); -extern qid_t from_kqid(struct user_namespace *to, struct kqid qid); -extern qid_t from_kqid_munged(struct user_namespace *to, struct kqid qid); -extern bool qid_valid(struct kqid qid); - -/** - * make_kqid - Map a user-namespace, type, qid tuple into a kqid. - * @from: User namespace that the qid is in - * @type: The type of quota - * @qid: Quota identifier - * - * Maps a user-namespace, type qid tuple into a kernel internal - * kqid, and returns that kqid. - * - * When there is no mapping defined for the user-namespace, type, - * qid tuple an invalid kqid is returned. Callers are expected to - * test for and handle handle invalid kqids being returned. - * Invalid kqids may be tested for using qid_valid(). - */ -static inline struct kqid make_kqid(struct user_namespace *from, - enum quota_type type, qid_t qid) -{ - struct kqid kqid; - - kqid.type = type; - switch (type) { - case USRQUOTA: - kqid.uid = make_kuid(from, qid); - break; - case GRPQUOTA: - kqid.gid = make_kgid(from, qid); - break; - case PRJQUOTA: - kqid.projid = make_kprojid(from, qid); - break; - default: - BUG(); - } - return kqid; -} - -/** - * make_kqid_invalid - Explicitly make an invalid kqid - * @type: The type of quota identifier - * - * Returns an invalid kqid with the specified type. - */ -static inline struct kqid make_kqid_invalid(enum quota_type type) -{ - struct kqid kqid; - - kqid.type = type; - switch (type) { - case USRQUOTA: - kqid.uid = INVALID_UID; - break; - case GRPQUOTA: - kqid.gid = INVALID_GID; - break; - case PRJQUOTA: - kqid.projid = INVALID_PROJID; - break; - default: - BUG(); - } - return kqid; -} - -/** - * make_kqid_uid - Make a kqid from a kuid - * @uid: The kuid to make the quota identifier from - */ -static inline struct kqid make_kqid_uid(kuid_t uid) -{ - struct kqid kqid; - kqid.type = USRQUOTA; - kqid.uid = uid; - return kqid; -} - -/** - * make_kqid_gid - Make a kqid from a kgid - * @gid: The kgid to make the quota identifier from - */ -static inline struct kqid make_kqid_gid(kgid_t gid) -{ - struct kqid kqid; - kqid.type = GRPQUOTA; - kqid.gid = gid; - return kqid; -} - -/** - * make_kqid_projid - Make a kqid from a projid - * @projid: The kprojid to make the quota identifier from - */ -static inline struct kqid make_kqid_projid(kprojid_t projid) -{ - struct kqid kqid; - kqid.type = PRJQUOTA; - kqid.projid = projid; - return kqid; -} - -/** - * qid_has_mapping - Report if a qid maps into a user namespace. - * @ns: The user namespace to see if a value maps into. - * @qid: The kernel internal quota identifier to test. - */ -static inline bool qid_has_mapping(struct user_namespace *ns, struct kqid qid) -{ - return from_kqid(ns, qid) != (qid_t) -1; -} - - -extern spinlock_t dq_data_lock; - -/* Maximal numbers of writes for quota operation (insert/delete/update) - * (over VFS all formats) */ -#define DQUOT_INIT_ALLOC max(V1_INIT_ALLOC, V2_INIT_ALLOC) -#define DQUOT_INIT_REWRITE max(V1_INIT_REWRITE, V2_INIT_REWRITE) -#define DQUOT_DEL_ALLOC max(V1_DEL_ALLOC, V2_DEL_ALLOC) -#define DQUOT_DEL_REWRITE max(V1_DEL_REWRITE, V2_DEL_REWRITE) - -/* - * Data for one user/group kept in memory - */ -struct mem_dqblk { - qsize_t dqb_bhardlimit; /* absolute limit on disk blks alloc */ - qsize_t dqb_bsoftlimit; /* preferred limit on disk blks */ - qsize_t dqb_curspace; /* current used space */ - qsize_t dqb_rsvspace; /* current reserved space for delalloc*/ - qsize_t dqb_ihardlimit; /* absolute limit on allocated inodes */ - qsize_t dqb_isoftlimit; /* preferred inode limit */ - qsize_t dqb_curinodes; /* current # allocated inodes */ - time64_t dqb_btime; /* time limit for excessive disk use */ - time64_t dqb_itime; /* time limit for excessive inode use */ -}; - -/* - * Data for one quotafile kept in memory - */ -struct quota_format_type; - -struct mem_dqinfo { - struct quota_format_type *dqi_format; - int dqi_fmt_id; /* Id of the dqi_format - used when turning - * quotas on after remount RW */ - struct list_head dqi_dirty_list; /* List of dirty dquots */ - unsigned long dqi_flags; - unsigned int dqi_bgrace; - unsigned int dqi_igrace; - qsize_t dqi_max_spc_limit; - qsize_t dqi_max_ino_limit; - void *dqi_priv; -}; - -struct super_block; - -/* Mask for flags passed to userspace */ -#define DQF_GETINFO_MASK (DQF_ROOT_SQUASH | DQF_SYS_FILE) -/* Mask for flags modifiable from userspace */ -#define DQF_SETINFO_MASK DQF_ROOT_SQUASH - -enum { - DQF_INFO_DIRTY_B = DQF_PRIVATE, -}; -#define DQF_INFO_DIRTY (1 << DQF_INFO_DIRTY_B) /* Is info dirty? */ - -extern void mark_info_dirty(struct super_block *sb, int type); -static inline int info_dirty(struct mem_dqinfo *info) -{ - return test_bit(DQF_INFO_DIRTY_B, &info->dqi_flags); -} - -enum { - DQST_LOOKUPS, - DQST_DROPS, - DQST_READS, - DQST_WRITES, - DQST_CACHE_HITS, - DQST_ALLOC_DQUOTS, - DQST_FREE_DQUOTS, - DQST_SYNCS, - _DQST_DQSTAT_LAST -}; - -struct dqstats { - int stat[_DQST_DQSTAT_LAST]; - struct percpu_counter counter[_DQST_DQSTAT_LAST]; -}; - -extern struct dqstats *dqstats_pcpu; -extern struct dqstats dqstats; - -static inline void dqstats_inc(unsigned int type) -{ - percpu_counter_inc(&dqstats.counter[type]); -} - -static inline void dqstats_dec(unsigned int type) -{ - percpu_counter_dec(&dqstats.counter[type]); -} - -#define DQ_MOD_B 0 /* dquot modified since read */ -#define DQ_BLKS_B 1 /* uid/gid has been warned about blk limit */ -#define DQ_INODES_B 2 /* uid/gid has been warned about inode limit */ -#define DQ_FAKE_B 3 /* no limits only usage */ -#define DQ_READ_B 4 /* dquot was read into memory */ -#define DQ_ACTIVE_B 5 /* dquot is active (dquot_release not called) */ -#define DQ_LASTSET_B 6 /* Following 6 bits (see QIF_) are reserved\ - * for the mask of entries set via SETQUOTA\ - * quotactl. They are set under dq_data_lock\ - * and the quota format handling dquot can\ - * clear them when it sees fit. */ - -struct dquot { - struct hlist_node dq_hash; /* Hash list in memory */ - struct list_head dq_inuse; /* List of all quotas */ - struct list_head dq_free; /* Free list element */ - struct list_head dq_dirty; /* List of dirty dquots */ - struct mutex dq_lock; /* dquot IO lock */ - atomic_t dq_count; /* Use count */ - wait_queue_head_t dq_wait_unused; /* Wait queue for dquot to become unused */ - struct super_block *dq_sb; /* superblock this applies to */ - struct kqid dq_id; /* ID this applies to (uid, gid, projid) */ - loff_t dq_off; /* Offset of dquot on disk */ - unsigned long dq_flags; /* See DQ_* */ - struct mem_dqblk dq_dqb; /* Diskquota usage */ -}; - -/* Operations which must be implemented by each quota format */ -struct quota_format_ops { - int (*check_quota_file)(struct super_block *sb, int type); /* Detect whether file is in our format */ - int (*read_file_info)(struct super_block *sb, int type); /* Read main info about file - called on quotaon() */ - int (*write_file_info)(struct super_block *sb, int type); /* Write main info about file */ - int (*free_file_info)(struct super_block *sb, int type); /* Called on quotaoff() */ - int (*read_dqblk)(struct dquot *dquot); /* Read structure for one user */ - int (*commit_dqblk)(struct dquot *dquot); /* Write structure for one user */ - int (*release_dqblk)(struct dquot *dquot); /* Called when last reference to dquot is being dropped */ - int (*get_next_id)(struct super_block *sb, struct kqid *qid); /* Get next ID with existing structure in the quota file */ -}; - -/* Operations working with dquots */ -struct dquot_operations { - int (*write_dquot) (struct dquot *); /* Ordinary dquot write */ - struct dquot *(*alloc_dquot)(struct super_block *, int); /* Allocate memory for new dquot */ - void (*destroy_dquot)(struct dquot *); /* Free memory for dquot */ - int (*acquire_dquot) (struct dquot *); /* Quota is going to be created on disk */ - int (*release_dquot) (struct dquot *); /* Quota is going to be deleted from disk */ - int (*mark_dirty) (struct dquot *); /* Dquot is marked dirty */ - int (*write_info) (struct super_block *, int); /* Write of quota "superblock" */ - /* get reserved quota for delayed alloc, value returned is managed by - * quota code only */ - qsize_t *(*get_reserved_space) (struct inode *); - int (*get_projid) (struct inode *, kprojid_t *);/* Get project ID */ - /* Get next ID with active quota structure */ - int (*get_next_id) (struct super_block *sb, struct kqid *qid); -}; - -struct path; - -/* Structure for communicating via ->get_dqblk() & ->set_dqblk() */ -struct qc_dqblk { - int d_fieldmask; /* mask of fields to change in ->set_dqblk() */ - u64 d_spc_hardlimit; /* absolute limit on used space */ - u64 d_spc_softlimit; /* preferred limit on used space */ - u64 d_ino_hardlimit; /* maximum # allocated inodes */ - u64 d_ino_softlimit; /* preferred inode limit */ - u64 d_space; /* Space owned by the user */ - u64 d_ino_count; /* # inodes owned by the user */ - s64 d_ino_timer; /* zero if within inode limits */ - /* if not, we refuse service */ - s64 d_spc_timer; /* similar to above; for space */ - int d_ino_warns; /* # warnings issued wrt num inodes */ - int d_spc_warns; /* # warnings issued wrt used space */ - u64 d_rt_spc_hardlimit; /* absolute limit on realtime space */ - u64 d_rt_spc_softlimit; /* preferred limit on RT space */ - u64 d_rt_space; /* realtime space owned */ - s64 d_rt_spc_timer; /* similar to above; for RT space */ - int d_rt_spc_warns; /* # warnings issued wrt RT space */ -}; - -/* - * Field specifiers for ->set_dqblk() in struct qc_dqblk and also for - * ->set_info() in struct qc_info - */ -#define QC_INO_SOFT (1<<0) -#define QC_INO_HARD (1<<1) -#define QC_SPC_SOFT (1<<2) -#define QC_SPC_HARD (1<<3) -#define QC_RT_SPC_SOFT (1<<4) -#define QC_RT_SPC_HARD (1<<5) -#define QC_LIMIT_MASK (QC_INO_SOFT | QC_INO_HARD | QC_SPC_SOFT | QC_SPC_HARD | \ - QC_RT_SPC_SOFT | QC_RT_SPC_HARD) -#define QC_SPC_TIMER (1<<6) -#define QC_INO_TIMER (1<<7) -#define QC_RT_SPC_TIMER (1<<8) -#define QC_TIMER_MASK (QC_SPC_TIMER | QC_INO_TIMER | QC_RT_SPC_TIMER) -#define QC_SPC_WARNS (1<<9) -#define QC_INO_WARNS (1<<10) -#define QC_RT_SPC_WARNS (1<<11) -#define QC_WARNS_MASK (QC_SPC_WARNS | QC_INO_WARNS | QC_RT_SPC_WARNS) -#define QC_SPACE (1<<12) -#define QC_INO_COUNT (1<<13) -#define QC_RT_SPACE (1<<14) -#define QC_ACCT_MASK (QC_SPACE | QC_INO_COUNT | QC_RT_SPACE) -#define QC_FLAGS (1<<15) - -#define QCI_SYSFILE (1 << 0) /* Quota file is hidden from userspace */ -#define QCI_ROOT_SQUASH (1 << 1) /* Root squash turned on */ -#define QCI_ACCT_ENABLED (1 << 2) /* Quota accounting enabled */ -#define QCI_LIMITS_ENFORCED (1 << 3) /* Quota limits enforced */ - -/* Structures for communicating via ->get_state */ -struct qc_type_state { - unsigned int flags; /* Flags QCI_* */ - unsigned int spc_timelimit; /* Time after which space softlimit is - * enforced */ - unsigned int ino_timelimit; /* Ditto for inode softlimit */ - unsigned int rt_spc_timelimit; /* Ditto for real-time space */ - unsigned int spc_warnlimit; /* Limit for number of space warnings */ - unsigned int ino_warnlimit; /* Ditto for inodes */ - unsigned int rt_spc_warnlimit; /* Ditto for real-time space */ - unsigned long long ino; /* Inode number of quota file */ - blkcnt_t blocks; /* Number of 512-byte blocks in the file */ - blkcnt_t nextents; /* Number of extents in the file */ -}; - -struct qc_state { - unsigned int s_incoredqs; /* Number of dquots in core */ - /* - * Per quota type information. The array should really have - * max(MAXQUOTAS, XQM_MAXQUOTAS) entries. BUILD_BUG_ON in - * quota_getinfo() makes sure XQM_MAXQUOTAS is large enough. Once VFS - * supports project quotas, this can be changed to MAXQUOTAS - */ - struct qc_type_state s_state[XQM_MAXQUOTAS]; -}; - -/* Structure for communicating via ->set_info */ -struct qc_info { - int i_fieldmask; /* mask of fields to change in ->set_info() */ - unsigned int i_flags; /* Flags QCI_* */ - unsigned int i_spc_timelimit; /* Time after which space softlimit is - * enforced */ - unsigned int i_ino_timelimit; /* Ditto for inode softlimit */ - unsigned int i_rt_spc_timelimit;/* Ditto for real-time space */ - unsigned int i_spc_warnlimit; /* Limit for number of space warnings */ - unsigned int i_ino_warnlimit; /* Limit for number of inode warnings */ - unsigned int i_rt_spc_warnlimit; /* Ditto for real-time space */ -}; - -/* Operations handling requests from userspace */ -struct quotactl_ops { - int (*quota_on)(struct super_block *, int, int, struct path *); - int (*quota_off)(struct super_block *, int); - int (*quota_enable)(struct super_block *, unsigned int); - int (*quota_disable)(struct super_block *, unsigned int); - int (*quota_sync)(struct super_block *, int); - int (*set_info)(struct super_block *, int, struct qc_info *); - int (*get_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *); - int (*get_nextdqblk)(struct super_block *, struct kqid *, - struct qc_dqblk *); - int (*set_dqblk)(struct super_block *, struct kqid, struct qc_dqblk *); - int (*get_state)(struct super_block *, struct qc_state *); - int (*rm_xquota)(struct super_block *, unsigned int); -}; - -struct quota_format_type { - int qf_fmt_id; /* Quota format id */ - const struct quota_format_ops *qf_ops; /* Operations of format */ - struct module *qf_owner; /* Module implementing quota format */ - struct quota_format_type *qf_next; -}; - -/** - * Quota state flags - they actually come in two flavors - for users and groups. - * - * Actual typed flags layout: - * USRQUOTA GRPQUOTA - * DQUOT_USAGE_ENABLED 0x0001 0x0002 - * DQUOT_LIMITS_ENABLED 0x0004 0x0008 - * DQUOT_SUSPENDED 0x0010 0x0020 - * - * Following bits are used for non-typed flags: - * DQUOT_QUOTA_SYS_FILE 0x0040 - * DQUOT_NEGATIVE_USAGE 0x0080 - */ -enum { - _DQUOT_USAGE_ENABLED = 0, /* Track disk usage for users */ - _DQUOT_LIMITS_ENABLED, /* Enforce quota limits for users */ - _DQUOT_SUSPENDED, /* User diskquotas are off, but - * we have necessary info in - * memory to turn them on */ - _DQUOT_STATE_FLAGS -}; -#define DQUOT_USAGE_ENABLED (1 << _DQUOT_USAGE_ENABLED * MAXQUOTAS) -#define DQUOT_LIMITS_ENABLED (1 << _DQUOT_LIMITS_ENABLED * MAXQUOTAS) -#define DQUOT_SUSPENDED (1 << _DQUOT_SUSPENDED * MAXQUOTAS) -#define DQUOT_STATE_FLAGS (DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED | \ - DQUOT_SUSPENDED) -/* Other quota flags */ -#define DQUOT_STATE_LAST (_DQUOT_STATE_FLAGS * MAXQUOTAS) -#define DQUOT_QUOTA_SYS_FILE (1 << DQUOT_STATE_LAST) - /* Quota file is a special - * system file and user cannot - * touch it. Filesystem is - * responsible for setting - * S_NOQUOTA, S_NOATIME flags - */ -#define DQUOT_NEGATIVE_USAGE (1 << (DQUOT_STATE_LAST + 1)) - /* Allow negative quota usage */ -static inline unsigned int dquot_state_flag(unsigned int flags, int type) -{ - return flags << type; -} - -static inline unsigned int dquot_generic_flag(unsigned int flags, int type) -{ - return (flags >> type) & DQUOT_STATE_FLAGS; -} - -/* Bitmap of quota types where flag is set in flags */ -static __always_inline unsigned dquot_state_types(unsigned flags, unsigned flag) -{ - BUILD_BUG_ON_NOT_POWER_OF_2(flag); - return (flags / flag) & ((1 << MAXQUOTAS) - 1); -} - -#ifdef CONFIG_QUOTA_NETLINK_INTERFACE -extern void quota_send_warning(struct kqid qid, dev_t dev, - const char warntype); -#else -static inline void quota_send_warning(struct kqid qid, dev_t dev, - const char warntype) -{ - return; -} -#endif /* CONFIG_QUOTA_NETLINK_INTERFACE */ - -struct quota_info { - unsigned int flags; /* Flags for diskquotas on this device */ - struct mutex dqio_mutex; /* lock device while I/O in progress */ - struct mutex dqonoff_mutex; /* Serialize quotaon & quotaoff */ - struct inode *files[MAXQUOTAS]; /* inodes of quotafiles */ - struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */ - const struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */ -}; - -int register_quota_format(struct quota_format_type *fmt); -void unregister_quota_format(struct quota_format_type *fmt); - -struct quota_module_name { - int qm_fmt_id; - char *qm_mod_name; -}; - -#define INIT_QUOTA_MODULE_NAMES {\ - {QFMT_VFS_OLD, "quota_v1"},\ - {QFMT_VFS_V0, "quota_v2"},\ - {QFMT_VFS_V1, "quota_v2"},\ - {0, NULL}} - -#endif /* _QUOTA_ */ diff --git a/src/linux/include/linux/quotaops.h b/src/linux/include/linux/quotaops.h deleted file mode 100644 index f00fa86..0000000 --- a/src/linux/include/linux/quotaops.h +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Definitions for diskquota-operations. When diskquota is configured these - * macros expand to the right source-code. - * - * Author: Marco van Wieringen - */ -#ifndef _LINUX_QUOTAOPS_ -#define _LINUX_QUOTAOPS_ - -#include - -#define DQUOT_SPACE_WARN 0x1 -#define DQUOT_SPACE_RESERVE 0x2 -#define DQUOT_SPACE_NOFAIL 0x4 - -static inline struct quota_info *sb_dqopt(struct super_block *sb) -{ - return &sb->s_dquot; -} - -/* i_mutex must being held */ -static inline bool is_quota_modification(struct inode *inode, struct iattr *ia) -{ - return (ia->ia_valid & ATTR_SIZE && ia->ia_size != inode->i_size) || - (ia->ia_valid & ATTR_UID && !uid_eq(ia->ia_uid, inode->i_uid)) || - (ia->ia_valid & ATTR_GID && !gid_eq(ia->ia_gid, inode->i_gid)); -} - -#if defined(CONFIG_QUOTA) - -#define quota_error(sb, fmt, args...) \ - __quota_error((sb), __func__, fmt , ## args) - -extern __printf(3, 4) -void __quota_error(struct super_block *sb, const char *func, - const char *fmt, ...); - -/* - * declaration of quota_function calls in kernel. - */ -void inode_add_rsv_space(struct inode *inode, qsize_t number); -void inode_claim_rsv_space(struct inode *inode, qsize_t number); -void inode_sub_rsv_space(struct inode *inode, qsize_t number); -void inode_reclaim_rsv_space(struct inode *inode, qsize_t number); - -int dquot_initialize(struct inode *inode); -void dquot_drop(struct inode *inode); -struct dquot *dqget(struct super_block *sb, struct kqid qid); -static inline struct dquot *dqgrab(struct dquot *dquot) -{ - /* Make sure someone else has active reference to dquot */ - WARN_ON_ONCE(!atomic_read(&dquot->dq_count)); - WARN_ON_ONCE(!test_bit(DQ_ACTIVE_B, &dquot->dq_flags)); - atomic_inc(&dquot->dq_count); - return dquot; -} -void dqput(struct dquot *dquot); -int dquot_scan_active(struct super_block *sb, - int (*fn)(struct dquot *dquot, unsigned long priv), - unsigned long priv); -struct dquot *dquot_alloc(struct super_block *sb, int type); -void dquot_destroy(struct dquot *dquot); - -int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags); -void __dquot_free_space(struct inode *inode, qsize_t number, int flags); - -int dquot_alloc_inode(struct inode *inode); - -int dquot_claim_space_nodirty(struct inode *inode, qsize_t number); -void dquot_free_inode(struct inode *inode); -void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number); - -int dquot_disable(struct super_block *sb, int type, unsigned int flags); -/* Suspend quotas on remount RO */ -static inline int dquot_suspend(struct super_block *sb, int type) -{ - return dquot_disable(sb, type, DQUOT_SUSPENDED); -} -int dquot_resume(struct super_block *sb, int type); - -int dquot_commit(struct dquot *dquot); -int dquot_acquire(struct dquot *dquot); -int dquot_release(struct dquot *dquot); -int dquot_commit_info(struct super_block *sb, int type); -int dquot_get_next_id(struct super_block *sb, struct kqid *qid); -int dquot_mark_dquot_dirty(struct dquot *dquot); - -int dquot_file_open(struct inode *inode, struct file *file); - -int dquot_enable(struct inode *inode, int type, int format_id, - unsigned int flags); -int dquot_quota_on(struct super_block *sb, int type, int format_id, - struct path *path); -int dquot_quota_on_mount(struct super_block *sb, char *qf_name, - int format_id, int type); -int dquot_quota_off(struct super_block *sb, int type); -int dquot_writeback_dquots(struct super_block *sb, int type); -int dquot_quota_sync(struct super_block *sb, int type); -int dquot_get_state(struct super_block *sb, struct qc_state *state); -int dquot_set_dqinfo(struct super_block *sb, int type, struct qc_info *ii); -int dquot_get_dqblk(struct super_block *sb, struct kqid id, - struct qc_dqblk *di); -int dquot_get_next_dqblk(struct super_block *sb, struct kqid *id, - struct qc_dqblk *di); -int dquot_set_dqblk(struct super_block *sb, struct kqid id, - struct qc_dqblk *di); - -int __dquot_transfer(struct inode *inode, struct dquot **transfer_to); -int dquot_transfer(struct inode *inode, struct iattr *iattr); - -static inline struct mem_dqinfo *sb_dqinfo(struct super_block *sb, int type) -{ - return sb_dqopt(sb)->info + type; -} - -/* - * Functions for checking status of quota - */ - -static inline bool sb_has_quota_usage_enabled(struct super_block *sb, int type) -{ - return sb_dqopt(sb)->flags & - dquot_state_flag(DQUOT_USAGE_ENABLED, type); -} - -static inline bool sb_has_quota_limits_enabled(struct super_block *sb, int type) -{ - return sb_dqopt(sb)->flags & - dquot_state_flag(DQUOT_LIMITS_ENABLED, type); -} - -static inline bool sb_has_quota_suspended(struct super_block *sb, int type) -{ - return sb_dqopt(sb)->flags & - dquot_state_flag(DQUOT_SUSPENDED, type); -} - -static inline unsigned sb_any_quota_suspended(struct super_block *sb) -{ - return dquot_state_types(sb_dqopt(sb)->flags, DQUOT_SUSPENDED); -} - -/* Does kernel know about any quota information for given sb + type? */ -static inline bool sb_has_quota_loaded(struct super_block *sb, int type) -{ - /* Currently if anything is on, then quota usage is on as well */ - return sb_has_quota_usage_enabled(sb, type); -} - -static inline unsigned sb_any_quota_loaded(struct super_block *sb) -{ - return dquot_state_types(sb_dqopt(sb)->flags, DQUOT_USAGE_ENABLED); -} - -static inline bool sb_has_quota_active(struct super_block *sb, int type) -{ - return sb_has_quota_loaded(sb, type) && - !sb_has_quota_suspended(sb, type); -} - -/* - * Operations supported for diskquotas. - */ -extern const struct dquot_operations dquot_operations; -extern const struct quotactl_ops dquot_quotactl_ops; -extern const struct quotactl_ops dquot_quotactl_sysfile_ops; - -#else - -static inline int sb_has_quota_usage_enabled(struct super_block *sb, int type) -{ - return 0; -} - -static inline int sb_has_quota_limits_enabled(struct super_block *sb, int type) -{ - return 0; -} - -static inline int sb_has_quota_suspended(struct super_block *sb, int type) -{ - return 0; -} - -static inline int sb_any_quota_suspended(struct super_block *sb) -{ - return 0; -} - -/* Does kernel know about any quota information for given sb + type? */ -static inline int sb_has_quota_loaded(struct super_block *sb, int type) -{ - return 0; -} - -static inline int sb_any_quota_loaded(struct super_block *sb) -{ - return 0; -} - -static inline int sb_has_quota_active(struct super_block *sb, int type) -{ - return 0; -} - -static inline int dquot_initialize(struct inode *inode) -{ - return 0; -} - -static inline void dquot_drop(struct inode *inode) -{ -} - -static inline int dquot_alloc_inode(struct inode *inode) -{ - return 0; -} - -static inline void dquot_free_inode(struct inode *inode) -{ -} - -static inline int dquot_transfer(struct inode *inode, struct iattr *iattr) -{ - return 0; -} - -static inline int __dquot_alloc_space(struct inode *inode, qsize_t number, - int flags) -{ - if (!(flags & DQUOT_SPACE_RESERVE)) - inode_add_bytes(inode, number); - return 0; -} - -static inline void __dquot_free_space(struct inode *inode, qsize_t number, - int flags) -{ - if (!(flags & DQUOT_SPACE_RESERVE)) - inode_sub_bytes(inode, number); -} - -static inline int dquot_claim_space_nodirty(struct inode *inode, qsize_t number) -{ - inode_add_bytes(inode, number); - return 0; -} - -static inline int dquot_reclaim_space_nodirty(struct inode *inode, - qsize_t number) -{ - inode_sub_bytes(inode, number); - return 0; -} - -static inline int dquot_disable(struct super_block *sb, int type, - unsigned int flags) -{ - return 0; -} - -static inline int dquot_suspend(struct super_block *sb, int type) -{ - return 0; -} - -static inline int dquot_resume(struct super_block *sb, int type) -{ - return 0; -} - -#define dquot_file_open generic_file_open - -static inline int dquot_writeback_dquots(struct super_block *sb, int type) -{ - return 0; -} - -#endif /* CONFIG_QUOTA */ - -static inline int dquot_alloc_space_nodirty(struct inode *inode, qsize_t nr) -{ - return __dquot_alloc_space(inode, nr, DQUOT_SPACE_WARN); -} - -static inline void dquot_alloc_space_nofail(struct inode *inode, qsize_t nr) -{ - __dquot_alloc_space(inode, nr, DQUOT_SPACE_WARN|DQUOT_SPACE_NOFAIL); - mark_inode_dirty_sync(inode); -} - -static inline int dquot_alloc_space(struct inode *inode, qsize_t nr) -{ - int ret; - - ret = dquot_alloc_space_nodirty(inode, nr); - if (!ret) { - /* - * Mark inode fully dirty. Since we are allocating blocks, inode - * would become fully dirty soon anyway and it reportedly - * reduces lock contention. - */ - mark_inode_dirty(inode); - } - return ret; -} - -static inline int dquot_alloc_block_nodirty(struct inode *inode, qsize_t nr) -{ - return dquot_alloc_space_nodirty(inode, nr << inode->i_blkbits); -} - -static inline void dquot_alloc_block_nofail(struct inode *inode, qsize_t nr) -{ - dquot_alloc_space_nofail(inode, nr << inode->i_blkbits); -} - -static inline int dquot_alloc_block(struct inode *inode, qsize_t nr) -{ - return dquot_alloc_space(inode, nr << inode->i_blkbits); -} - -static inline int dquot_prealloc_block_nodirty(struct inode *inode, qsize_t nr) -{ - return __dquot_alloc_space(inode, nr << inode->i_blkbits, 0); -} - -static inline int dquot_prealloc_block(struct inode *inode, qsize_t nr) -{ - int ret; - - ret = dquot_prealloc_block_nodirty(inode, nr); - if (!ret) - mark_inode_dirty_sync(inode); - return ret; -} - -static inline int dquot_reserve_block(struct inode *inode, qsize_t nr) -{ - return __dquot_alloc_space(inode, nr << inode->i_blkbits, - DQUOT_SPACE_WARN|DQUOT_SPACE_RESERVE); -} - -static inline int dquot_claim_block(struct inode *inode, qsize_t nr) -{ - int ret; - - ret = dquot_claim_space_nodirty(inode, nr << inode->i_blkbits); - if (!ret) - mark_inode_dirty_sync(inode); - return ret; -} - -static inline void dquot_reclaim_block(struct inode *inode, qsize_t nr) -{ - dquot_reclaim_space_nodirty(inode, nr << inode->i_blkbits); - mark_inode_dirty_sync(inode); -} - -static inline void dquot_free_space_nodirty(struct inode *inode, qsize_t nr) -{ - __dquot_free_space(inode, nr, 0); -} - -static inline void dquot_free_space(struct inode *inode, qsize_t nr) -{ - dquot_free_space_nodirty(inode, nr); - mark_inode_dirty_sync(inode); -} - -static inline void dquot_free_block_nodirty(struct inode *inode, qsize_t nr) -{ - dquot_free_space_nodirty(inode, nr << inode->i_blkbits); -} - -static inline void dquot_free_block(struct inode *inode, qsize_t nr) -{ - dquot_free_space(inode, nr << inode->i_blkbits); -} - -static inline void dquot_release_reservation_block(struct inode *inode, - qsize_t nr) -{ - __dquot_free_space(inode, nr << inode->i_blkbits, DQUOT_SPACE_RESERVE); -} - -unsigned int qtype_enforce_flag(int type); - -#endif /* _LINUX_QUOTAOPS_ */ diff --git a/src/linux/include/linux/radix-tree.h b/src/linux/include/linux/radix-tree.h deleted file mode 100644 index af3581b..0000000 --- a/src/linux/include/linux/radix-tree.h +++ /dev/null @@ -1,582 +0,0 @@ -/* - * Copyright (C) 2001 Momchil Velikov - * Portions Copyright (C) 2001 Christoph Hellwig - * Copyright (C) 2006 Nick Piggin - * Copyright (C) 2012 Konstantin Khlebnikov - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#ifndef _LINUX_RADIX_TREE_H -#define _LINUX_RADIX_TREE_H - -#include -#include -#include -#include -#include -#include - -/* - * The bottom two bits of the slot determine how the remaining bits in the - * slot are interpreted: - * - * 00 - data pointer - * 01 - internal entry - * 10 - exceptional entry - * 11 - this bit combination is currently unused/reserved - * - * The internal entry may be a pointer to the next level in the tree, a - * sibling entry, or an indicator that the entry in this slot has been moved - * to another location in the tree and the lookup should be restarted. While - * NULL fits the 'data pointer' pattern, it means that there is no entry in - * the tree for this index (no matter what level of the tree it is found at). - * This means that you cannot store NULL in the tree as a value for the index. - */ -#define RADIX_TREE_ENTRY_MASK 3UL -#define RADIX_TREE_INTERNAL_NODE 1UL - -/* - * Most users of the radix tree store pointers but shmem/tmpfs stores swap - * entries in the same tree. They are marked as exceptional entries to - * distinguish them from pointers to struct page. - * EXCEPTIONAL_ENTRY tests the bit, EXCEPTIONAL_SHIFT shifts content past it. - */ -#define RADIX_TREE_EXCEPTIONAL_ENTRY 2 -#define RADIX_TREE_EXCEPTIONAL_SHIFT 2 - -static inline bool radix_tree_is_internal_node(void *ptr) -{ - return ((unsigned long)ptr & RADIX_TREE_ENTRY_MASK) == - RADIX_TREE_INTERNAL_NODE; -} - -/*** radix-tree API starts here ***/ - -#define RADIX_TREE_MAX_TAGS 3 - -#ifndef RADIX_TREE_MAP_SHIFT -#define RADIX_TREE_MAP_SHIFT (CONFIG_BASE_SMALL ? 4 : 6) -#endif - -#define RADIX_TREE_MAP_SIZE (1UL << RADIX_TREE_MAP_SHIFT) -#define RADIX_TREE_MAP_MASK (RADIX_TREE_MAP_SIZE-1) - -#define RADIX_TREE_TAG_LONGS \ - ((RADIX_TREE_MAP_SIZE + BITS_PER_LONG - 1) / BITS_PER_LONG) - -#define RADIX_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsigned long)) -#define RADIX_TREE_MAX_PATH (DIV_ROUND_UP(RADIX_TREE_INDEX_BITS, \ - RADIX_TREE_MAP_SHIFT)) - -/* Internally used bits of node->count */ -#define RADIX_TREE_COUNT_SHIFT (RADIX_TREE_MAP_SHIFT + 1) -#define RADIX_TREE_COUNT_MASK ((1UL << RADIX_TREE_COUNT_SHIFT) - 1) - -struct radix_tree_node { - unsigned char shift; /* Bits remaining in each slot */ - unsigned char offset; /* Slot offset in parent */ - unsigned int count; - union { - struct { - /* Used when ascending tree */ - struct radix_tree_node *parent; - /* For tree user */ - void *private_data; - }; - /* Used when freeing node */ - struct rcu_head rcu_head; - }; - /* For tree user */ - struct list_head private_list; - void __rcu *slots[RADIX_TREE_MAP_SIZE]; - unsigned long tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS]; -}; - -/* root tags are stored in gfp_mask, shifted by __GFP_BITS_SHIFT */ -struct radix_tree_root { - gfp_t gfp_mask; - struct radix_tree_node __rcu *rnode; -}; - -#define RADIX_TREE_INIT(mask) { \ - .gfp_mask = (mask), \ - .rnode = NULL, \ -} - -#define RADIX_TREE(name, mask) \ - struct radix_tree_root name = RADIX_TREE_INIT(mask) - -#define INIT_RADIX_TREE(root, mask) \ -do { \ - (root)->gfp_mask = (mask); \ - (root)->rnode = NULL; \ -} while (0) - -static inline bool radix_tree_empty(struct radix_tree_root *root) -{ - return root->rnode == NULL; -} - -/** - * Radix-tree synchronization - * - * The radix-tree API requires that users provide all synchronisation (with - * specific exceptions, noted below). - * - * Synchronization of access to the data items being stored in the tree, and - * management of their lifetimes must be completely managed by API users. - * - * For API usage, in general, - * - any function _modifying_ the tree or tags (inserting or deleting - * items, setting or clearing tags) must exclude other modifications, and - * exclude any functions reading the tree. - * - any function _reading_ the tree or tags (looking up items or tags, - * gang lookups) must exclude modifications to the tree, but may occur - * concurrently with other readers. - * - * The notable exceptions to this rule are the following functions: - * __radix_tree_lookup - * radix_tree_lookup - * radix_tree_lookup_slot - * radix_tree_tag_get - * radix_tree_gang_lookup - * radix_tree_gang_lookup_slot - * radix_tree_gang_lookup_tag - * radix_tree_gang_lookup_tag_slot - * radix_tree_tagged - * - * The first 8 functions are able to be called locklessly, using RCU. The - * caller must ensure calls to these functions are made within rcu_read_lock() - * regions. Other readers (lock-free or otherwise) and modifications may be - * running concurrently. - * - * It is still required that the caller manage the synchronization and lifetimes - * of the items. So if RCU lock-free lookups are used, typically this would mean - * that the items have their own locks, or are amenable to lock-free access; and - * that the items are freed by RCU (or only freed after having been deleted from - * the radix tree *and* a synchronize_rcu() grace period). - * - * (Note, rcu_assign_pointer and rcu_dereference are not needed to control - * access to data items when inserting into or looking up from the radix tree) - * - * Note that the value returned by radix_tree_tag_get() may not be relied upon - * if only the RCU read lock is held. Functions to set/clear tags and to - * delete nodes running concurrently with it may affect its result such that - * two consecutive reads in the same locked section may return different - * values. If reliability is required, modification functions must also be - * excluded from concurrency. - * - * radix_tree_tagged is able to be called without locking or RCU. - */ - -/** - * radix_tree_deref_slot - dereference a slot - * @pslot: pointer to slot, returned by radix_tree_lookup_slot - * Returns: item that was stored in that slot with any direct pointer flag - * removed. - * - * For use with radix_tree_lookup_slot(). Caller must hold tree at least read - * locked across slot lookup and dereference. Not required if write lock is - * held (ie. items cannot be concurrently inserted). - * - * radix_tree_deref_retry must be used to confirm validity of the pointer if - * only the read lock is held. - */ -static inline void *radix_tree_deref_slot(void **pslot) -{ - return rcu_dereference(*pslot); -} - -/** - * radix_tree_deref_slot_protected - dereference a slot without RCU lock but with tree lock held - * @pslot: pointer to slot, returned by radix_tree_lookup_slot - * Returns: item that was stored in that slot with any direct pointer flag - * removed. - * - * Similar to radix_tree_deref_slot but only used during migration when a pages - * mapping is being moved. The caller does not hold the RCU read lock but it - * must hold the tree lock to prevent parallel updates. - */ -static inline void *radix_tree_deref_slot_protected(void **pslot, - spinlock_t *treelock) -{ - return rcu_dereference_protected(*pslot, lockdep_is_held(treelock)); -} - -/** - * radix_tree_deref_retry - check radix_tree_deref_slot - * @arg: pointer returned by radix_tree_deref_slot - * Returns: 0 if retry is not required, otherwise retry is required - * - * radix_tree_deref_retry must be used with radix_tree_deref_slot. - */ -static inline int radix_tree_deref_retry(void *arg) -{ - return unlikely(radix_tree_is_internal_node(arg)); -} - -/** - * radix_tree_exceptional_entry - radix_tree_deref_slot gave exceptional entry? - * @arg: value returned by radix_tree_deref_slot - * Returns: 0 if well-aligned pointer, non-0 if exceptional entry. - */ -static inline int radix_tree_exceptional_entry(void *arg) -{ - /* Not unlikely because radix_tree_exception often tested first */ - return (unsigned long)arg & RADIX_TREE_EXCEPTIONAL_ENTRY; -} - -/** - * radix_tree_exception - radix_tree_deref_slot returned either exception? - * @arg: value returned by radix_tree_deref_slot - * Returns: 0 if well-aligned pointer, non-0 if either kind of exception. - */ -static inline int radix_tree_exception(void *arg) -{ - return unlikely((unsigned long)arg & RADIX_TREE_ENTRY_MASK); -} - -/** - * radix_tree_replace_slot - replace item in a slot - * @pslot: pointer to slot, returned by radix_tree_lookup_slot - * @item: new item to store in the slot. - * - * For use with radix_tree_lookup_slot(). Caller must hold tree write locked - * across slot lookup and replacement. - */ -static inline void radix_tree_replace_slot(void **pslot, void *item) -{ - BUG_ON(radix_tree_is_internal_node(item)); - rcu_assign_pointer(*pslot, item); -} - -int __radix_tree_create(struct radix_tree_root *root, unsigned long index, - unsigned order, struct radix_tree_node **nodep, - void ***slotp); -int __radix_tree_insert(struct radix_tree_root *, unsigned long index, - unsigned order, void *); -static inline int radix_tree_insert(struct radix_tree_root *root, - unsigned long index, void *entry) -{ - return __radix_tree_insert(root, index, 0, entry); -} -void *__radix_tree_lookup(struct radix_tree_root *root, unsigned long index, - struct radix_tree_node **nodep, void ***slotp); -void *radix_tree_lookup(struct radix_tree_root *, unsigned long); -void **radix_tree_lookup_slot(struct radix_tree_root *, unsigned long); -bool __radix_tree_delete_node(struct radix_tree_root *root, - struct radix_tree_node *node); -void *radix_tree_delete_item(struct radix_tree_root *, unsigned long, void *); -void *radix_tree_delete(struct radix_tree_root *, unsigned long); -void radix_tree_clear_tags(struct radix_tree_root *root, - struct radix_tree_node *node, - void **slot); -unsigned int radix_tree_gang_lookup(struct radix_tree_root *root, - void **results, unsigned long first_index, - unsigned int max_items); -unsigned int radix_tree_gang_lookup_slot(struct radix_tree_root *root, - void ***results, unsigned long *indices, - unsigned long first_index, unsigned int max_items); -int radix_tree_preload(gfp_t gfp_mask); -int radix_tree_maybe_preload(gfp_t gfp_mask); -int radix_tree_maybe_preload_order(gfp_t gfp_mask, int order); -void radix_tree_init(void); -void *radix_tree_tag_set(struct radix_tree_root *root, - unsigned long index, unsigned int tag); -void *radix_tree_tag_clear(struct radix_tree_root *root, - unsigned long index, unsigned int tag); -int radix_tree_tag_get(struct radix_tree_root *root, - unsigned long index, unsigned int tag); -unsigned int -radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, - unsigned long first_index, unsigned int max_items, - unsigned int tag); -unsigned int -radix_tree_gang_lookup_tag_slot(struct radix_tree_root *root, void ***results, - unsigned long first_index, unsigned int max_items, - unsigned int tag); -unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root, - unsigned long *first_indexp, unsigned long last_index, - unsigned long nr_to_tag, - unsigned int fromtag, unsigned int totag); -int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag); -unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item); - -static inline void radix_tree_preload_end(void) -{ - preempt_enable(); -} - -/** - * struct radix_tree_iter - radix tree iterator state - * - * @index: index of current slot - * @next_index: one beyond the last index for this chunk - * @tags: bit-mask for tag-iterating - * @shift: shift for the node that holds our slots - * - * This radix tree iterator works in terms of "chunks" of slots. A chunk is a - * subinterval of slots contained within one radix tree leaf node. It is - * described by a pointer to its first slot and a struct radix_tree_iter - * which holds the chunk's position in the tree and its size. For tagged - * iteration radix_tree_iter also holds the slots' bit-mask for one chosen - * radix tree tag. - */ -struct radix_tree_iter { - unsigned long index; - unsigned long next_index; - unsigned long tags; -#ifdef CONFIG_RADIX_TREE_MULTIORDER - unsigned int shift; -#endif -}; - -static inline unsigned int iter_shift(struct radix_tree_iter *iter) -{ -#ifdef CONFIG_RADIX_TREE_MULTIORDER - return iter->shift; -#else - return 0; -#endif -} - -#define RADIX_TREE_ITER_TAG_MASK 0x00FF /* tag index in lower byte */ -#define RADIX_TREE_ITER_TAGGED 0x0100 /* lookup tagged slots */ -#define RADIX_TREE_ITER_CONTIG 0x0200 /* stop at first hole */ - -/** - * radix_tree_iter_init - initialize radix tree iterator - * - * @iter: pointer to iterator state - * @start: iteration starting index - * Returns: NULL - */ -static __always_inline void ** -radix_tree_iter_init(struct radix_tree_iter *iter, unsigned long start) -{ - /* - * Leave iter->tags uninitialized. radix_tree_next_chunk() will fill it - * in the case of a successful tagged chunk lookup. If the lookup was - * unsuccessful or non-tagged then nobody cares about ->tags. - * - * Set index to zero to bypass next_index overflow protection. - * See the comment in radix_tree_next_chunk() for details. - */ - iter->index = 0; - iter->next_index = start; - return NULL; -} - -/** - * radix_tree_next_chunk - find next chunk of slots for iteration - * - * @root: radix tree root - * @iter: iterator state - * @flags: RADIX_TREE_ITER_* flags and tag index - * Returns: pointer to chunk first slot, or NULL if there no more left - * - * This function looks up the next chunk in the radix tree starting from - * @iter->next_index. It returns a pointer to the chunk's first slot. - * Also it fills @iter with data about chunk: position in the tree (index), - * its end (next_index), and constructs a bit mask for tagged iterating (tags). - */ -void **radix_tree_next_chunk(struct radix_tree_root *root, - struct radix_tree_iter *iter, unsigned flags); - -/** - * radix_tree_iter_retry - retry this chunk of the iteration - * @iter: iterator state - * - * If we iterate over a tree protected only by the RCU lock, a race - * against deletion or creation may result in seeing a slot for which - * radix_tree_deref_retry() returns true. If so, call this function - * and continue the iteration. - */ -static inline __must_check -void **radix_tree_iter_retry(struct radix_tree_iter *iter) -{ - iter->next_index = iter->index; - iter->tags = 0; - return NULL; -} - -static inline unsigned long -__radix_tree_iter_add(struct radix_tree_iter *iter, unsigned long slots) -{ - return iter->index + (slots << iter_shift(iter)); -} - -/** - * radix_tree_iter_next - resume iterating when the chunk may be invalid - * @iter: iterator state - * - * If the iterator needs to release then reacquire a lock, the chunk may - * have been invalidated by an insertion or deletion. Call this function - * to continue the iteration from the next index. - */ -static inline __must_check -void **radix_tree_iter_next(struct radix_tree_iter *iter) -{ - iter->next_index = __radix_tree_iter_add(iter, 1); - iter->tags = 0; - return NULL; -} - -/** - * radix_tree_chunk_size - get current chunk size - * - * @iter: pointer to radix tree iterator - * Returns: current chunk size - */ -static __always_inline long -radix_tree_chunk_size(struct radix_tree_iter *iter) -{ - return (iter->next_index - iter->index) >> iter_shift(iter); -} - -static inline struct radix_tree_node *entry_to_node(void *ptr) -{ - return (void *)((unsigned long)ptr & ~RADIX_TREE_INTERNAL_NODE); -} - -/** - * radix_tree_next_slot - find next slot in chunk - * - * @slot: pointer to current slot - * @iter: pointer to interator state - * @flags: RADIX_TREE_ITER_*, should be constant - * Returns: pointer to next slot, or NULL if there no more left - * - * This function updates @iter->index in the case of a successful lookup. - * For tagged lookup it also eats @iter->tags. - * - * There are several cases where 'slot' can be passed in as NULL to this - * function. These cases result from the use of radix_tree_iter_next() or - * radix_tree_iter_retry(). In these cases we don't end up dereferencing - * 'slot' because either: - * a) we are doing tagged iteration and iter->tags has been set to 0, or - * b) we are doing non-tagged iteration, and iter->index and iter->next_index - * have been set up so that radix_tree_chunk_size() returns 1 or 0. - */ -static __always_inline void ** -radix_tree_next_slot(void **slot, struct radix_tree_iter *iter, unsigned flags) -{ - if (flags & RADIX_TREE_ITER_TAGGED) { - void *canon = slot; - - iter->tags >>= 1; - if (unlikely(!iter->tags)) - return NULL; - while (IS_ENABLED(CONFIG_RADIX_TREE_MULTIORDER) && - radix_tree_is_internal_node(slot[1])) { - if (entry_to_node(slot[1]) == canon) { - iter->tags >>= 1; - iter->index = __radix_tree_iter_add(iter, 1); - slot++; - continue; - } - iter->next_index = __radix_tree_iter_add(iter, 1); - return NULL; - } - if (likely(iter->tags & 1ul)) { - iter->index = __radix_tree_iter_add(iter, 1); - return slot + 1; - } - if (!(flags & RADIX_TREE_ITER_CONTIG)) { - unsigned offset = __ffs(iter->tags); - - iter->tags >>= offset; - iter->index = __radix_tree_iter_add(iter, offset + 1); - return slot + offset + 1; - } - } else { - long count = radix_tree_chunk_size(iter); - void *canon = slot; - - while (--count > 0) { - slot++; - iter->index = __radix_tree_iter_add(iter, 1); - - if (IS_ENABLED(CONFIG_RADIX_TREE_MULTIORDER) && - radix_tree_is_internal_node(*slot)) { - if (entry_to_node(*slot) == canon) - continue; - iter->next_index = iter->index; - break; - } - - if (likely(*slot)) - return slot; - if (flags & RADIX_TREE_ITER_CONTIG) { - /* forbid switching to the next chunk */ - iter->next_index = 0; - break; - } - } - } - return NULL; -} - -/** - * radix_tree_for_each_slot - iterate over non-empty slots - * - * @slot: the void** variable for pointer to slot - * @root: the struct radix_tree_root pointer - * @iter: the struct radix_tree_iter pointer - * @start: iteration starting index - * - * @slot points to radix tree slot, @iter->index contains its index. - */ -#define radix_tree_for_each_slot(slot, root, iter, start) \ - for (slot = radix_tree_iter_init(iter, start) ; \ - slot || (slot = radix_tree_next_chunk(root, iter, 0)) ; \ - slot = radix_tree_next_slot(slot, iter, 0)) - -/** - * radix_tree_for_each_contig - iterate over contiguous slots - * - * @slot: the void** variable for pointer to slot - * @root: the struct radix_tree_root pointer - * @iter: the struct radix_tree_iter pointer - * @start: iteration starting index - * - * @slot points to radix tree slot, @iter->index contains its index. - */ -#define radix_tree_for_each_contig(slot, root, iter, start) \ - for (slot = radix_tree_iter_init(iter, start) ; \ - slot || (slot = radix_tree_next_chunk(root, iter, \ - RADIX_TREE_ITER_CONTIG)) ; \ - slot = radix_tree_next_slot(slot, iter, \ - RADIX_TREE_ITER_CONTIG)) - -/** - * radix_tree_for_each_tagged - iterate over tagged slots - * - * @slot: the void** variable for pointer to slot - * @root: the struct radix_tree_root pointer - * @iter: the struct radix_tree_iter pointer - * @start: iteration starting index - * @tag: tag index - * - * @slot points to radix tree slot, @iter->index contains its index. - */ -#define radix_tree_for_each_tagged(slot, root, iter, start, tag) \ - for (slot = radix_tree_iter_init(iter, start) ; \ - slot || (slot = radix_tree_next_chunk(root, iter, \ - RADIX_TREE_ITER_TAGGED | tag)) ; \ - slot = radix_tree_next_slot(slot, iter, \ - RADIX_TREE_ITER_TAGGED)) - -#endif /* _LINUX_RADIX_TREE_H */ diff --git a/src/linux/include/linux/raid/pq.h b/src/linux/include/linux/raid/pq.h deleted file mode 100644 index 4d57bba..0000000 --- a/src/linux/include/linux/raid/pq.h +++ /dev/null @@ -1,186 +0,0 @@ -/* -*- linux-c -*- ------------------------------------------------------- * - * - * Copyright 2003 H. Peter Anvin - All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, Inc., 53 Temple Place Ste 330, - * Boston MA 02111-1307, USA; either version 2 of the License, or - * (at your option) any later version; incorporated herein by reference. - * - * ----------------------------------------------------------------------- */ - -#ifndef LINUX_RAID_RAID6_H -#define LINUX_RAID_RAID6_H - -#ifdef __KERNEL__ - -/* Set to 1 to use kernel-wide empty_zero_page */ -#define RAID6_USE_EMPTY_ZERO_PAGE 0 -#include - -/* We need a pre-zeroed page... if we don't want to use the kernel-provided - one define it here */ -#if RAID6_USE_EMPTY_ZERO_PAGE -# define raid6_empty_zero_page empty_zero_page -#else -extern const char raid6_empty_zero_page[PAGE_SIZE]; -#endif - -#else /* ! __KERNEL__ */ -/* Used for testing in user space */ - -#include -#include -#include -#include -#include -#include - -/* Not standard, but glibc defines it */ -#define BITS_PER_LONG __WORDSIZE - -typedef uint8_t u8; -typedef uint16_t u16; -typedef uint32_t u32; -typedef uint64_t u64; - -#ifndef PAGE_SIZE -# define PAGE_SIZE 4096 -#endif -extern const char raid6_empty_zero_page[PAGE_SIZE]; - -#define __init -#define __exit -#define __attribute_const__ __attribute__((const)) -#define noinline __attribute__((noinline)) - -#define preempt_enable() -#define preempt_disable() -#define cpu_has_feature(x) 1 -#define enable_kernel_altivec() -#define disable_kernel_altivec() - -#define EXPORT_SYMBOL(sym) -#define EXPORT_SYMBOL_GPL(sym) -#define MODULE_LICENSE(licence) -#define MODULE_DESCRIPTION(desc) -#define subsys_initcall(x) -#define module_exit(x) -#endif /* __KERNEL__ */ - -/* Routine choices */ -struct raid6_calls { - void (*gen_syndrome)(int, size_t, void **); - void (*xor_syndrome)(int, int, int, size_t, void **); - int (*valid)(void); /* Returns 1 if this routine set is usable */ - const char *name; /* Name of this routine set */ - int prefer; /* Has special performance attribute */ -}; - -/* Selected algorithm */ -extern struct raid6_calls raid6_call; - -/* Various routine sets */ -extern const struct raid6_calls raid6_intx1; -extern const struct raid6_calls raid6_intx2; -extern const struct raid6_calls raid6_intx4; -extern const struct raid6_calls raid6_intx8; -extern const struct raid6_calls raid6_intx16; -extern const struct raid6_calls raid6_intx32; -extern const struct raid6_calls raid6_mmxx1; -extern const struct raid6_calls raid6_mmxx2; -extern const struct raid6_calls raid6_sse1x1; -extern const struct raid6_calls raid6_sse1x2; -extern const struct raid6_calls raid6_sse2x1; -extern const struct raid6_calls raid6_sse2x2; -extern const struct raid6_calls raid6_sse2x4; -extern const struct raid6_calls raid6_altivec1; -extern const struct raid6_calls raid6_altivec2; -extern const struct raid6_calls raid6_altivec4; -extern const struct raid6_calls raid6_altivec8; -extern const struct raid6_calls raid6_avx2x1; -extern const struct raid6_calls raid6_avx2x2; -extern const struct raid6_calls raid6_avx2x4; -extern const struct raid6_calls raid6_avx512x1; -extern const struct raid6_calls raid6_avx512x2; -extern const struct raid6_calls raid6_avx512x4; -extern const struct raid6_calls raid6_tilegx8; -extern const struct raid6_calls raid6_s390vx8; - -struct raid6_recov_calls { - void (*data2)(int, size_t, int, int, void **); - void (*datap)(int, size_t, int, void **); - int (*valid)(void); - const char *name; - int priority; -}; - -extern const struct raid6_recov_calls raid6_recov_intx1; -extern const struct raid6_recov_calls raid6_recov_ssse3; -extern const struct raid6_recov_calls raid6_recov_avx2; -extern const struct raid6_recov_calls raid6_recov_avx512; -extern const struct raid6_recov_calls raid6_recov_s390xc; - -extern const struct raid6_calls raid6_neonx1; -extern const struct raid6_calls raid6_neonx2; -extern const struct raid6_calls raid6_neonx4; -extern const struct raid6_calls raid6_neonx8; - -/* Algorithm list */ -extern const struct raid6_calls * const raid6_algos[]; -extern const struct raid6_recov_calls *const raid6_recov_algos[]; -int raid6_select_algo(void); - -/* Return values from chk_syndrome */ -#define RAID6_OK 0 -#define RAID6_P_BAD 1 -#define RAID6_Q_BAD 2 -#define RAID6_PQ_BAD 3 - -/* Galois field tables */ -extern const u8 raid6_gfmul[256][256] __attribute__((aligned(256))); -extern const u8 raid6_vgfmul[256][32] __attribute__((aligned(256))); -extern const u8 raid6_gfexp[256] __attribute__((aligned(256))); -extern const u8 raid6_gfinv[256] __attribute__((aligned(256))); -extern const u8 raid6_gfexi[256] __attribute__((aligned(256))); - -/* Recovery routines */ -extern void (*raid6_2data_recov)(int disks, size_t bytes, int faila, int failb, - void **ptrs); -extern void (*raid6_datap_recov)(int disks, size_t bytes, int faila, - void **ptrs); -void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, - void **ptrs); - -/* Some definitions to allow code to be compiled for testing in userspace */ -#ifndef __KERNEL__ - -# define jiffies raid6_jiffies() -# define printk printf -# define pr_err(format, ...) fprintf(stderr, format, ## __VA_ARGS__) -# define pr_info(format, ...) fprintf(stdout, format, ## __VA_ARGS__) -# define GFP_KERNEL 0 -# define __get_free_pages(x, y) ((unsigned long)mmap(NULL, PAGE_SIZE << (y), \ - PROT_READ|PROT_WRITE, \ - MAP_PRIVATE|MAP_ANONYMOUS,\ - 0, 0)) -# define free_pages(x, y) munmap((void *)(x), PAGE_SIZE << (y)) - -static inline void cpu_relax(void) -{ - /* Nothing */ -} - -#undef HZ -#define HZ 1000 -static inline uint32_t raid6_jiffies(void) -{ - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec*1000 + tv.tv_usec/1000; -} - -#endif /* ! __KERNEL__ */ - -#endif /* LINUX_RAID_RAID6_H */ diff --git a/src/linux/include/linux/raid/xor.h b/src/linux/include/linux/raid/xor.h deleted file mode 100644 index 5a21095..0000000 --- a/src/linux/include/linux/raid/xor.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _XOR_H -#define _XOR_H - -#define MAX_XOR_BLOCKS 4 - -extern void xor_blocks(unsigned int count, unsigned int bytes, - void *dest, void **srcs); - -struct xor_block_template { - struct xor_block_template *next; - const char *name; - int speed; - void (*do_2)(unsigned long, unsigned long *, unsigned long *); - void (*do_3)(unsigned long, unsigned long *, unsigned long *, - unsigned long *); - void (*do_4)(unsigned long, unsigned long *, unsigned long *, - unsigned long *, unsigned long *); - void (*do_5)(unsigned long, unsigned long *, unsigned long *, - unsigned long *, unsigned long *, unsigned long *); -}; - -#endif diff --git a/src/linux/include/linux/ramfs.h b/src/linux/include/linux/ramfs.h deleted file mode 100644 index ecc7309..0000000 --- a/src/linux/include/linux/ramfs.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _LINUX_RAMFS_H -#define _LINUX_RAMFS_H - -struct inode *ramfs_get_inode(struct super_block *sb, const struct inode *dir, - umode_t mode, dev_t dev); -extern struct dentry *ramfs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data); - -#ifdef CONFIG_MMU -static inline int -ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize) -{ - return 0; -} -#else -extern int ramfs_nommu_expand_for_mapping(struct inode *inode, size_t newsize); -#endif - -extern const struct file_operations ramfs_file_operations; -extern const struct vm_operations_struct generic_file_vm_ops; -extern int __init init_ramfs_fs(void); - -int ramfs_fill_super(struct super_block *sb, void *data, int silent); - -#endif diff --git a/src/linux/include/linux/random.h b/src/linux/include/linux/random.h deleted file mode 100644 index 7bd2403..0000000 --- a/src/linux/include/linux/random.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * include/linux/random.h - * - * Include file for the random number generator. - */ -#ifndef _LINUX_RANDOM_H -#define _LINUX_RANDOM_H - -#include -#include - -#include - -struct random_ready_callback { - struct list_head list; - void (*func)(struct random_ready_callback *rdy); - struct module *owner; -}; - -extern void add_device_randomness(const void *, unsigned int); - -#if defined(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) && !defined(__CHECKER__) -static inline void add_latent_entropy(void) -{ - add_device_randomness((const void *)&latent_entropy, - sizeof(latent_entropy)); -} -#else -static inline void add_latent_entropy(void) {} -#endif - -extern void add_input_randomness(unsigned int type, unsigned int code, - unsigned int value) __latent_entropy; -extern void add_interrupt_randomness(int irq, int irq_flags) __latent_entropy; - -extern void get_random_bytes(void *buf, int nbytes); -extern int add_random_ready_callback(struct random_ready_callback *rdy); -extern void del_random_ready_callback(struct random_ready_callback *rdy); -extern void get_random_bytes_arch(void *buf, int nbytes); -extern int random_int_secret_init(void); - -#ifndef MODULE -extern const struct file_operations random_fops, urandom_fops; -#endif - -unsigned int get_random_int(void); -unsigned long get_random_long(void); -unsigned long randomize_page(unsigned long start, unsigned long range); - -u32 prandom_u32(void); -void prandom_bytes(void *buf, size_t nbytes); -void prandom_seed(u32 seed); -void prandom_reseed_late(void); - -struct rnd_state { - __u32 s1, s2, s3, s4; -}; - -u32 prandom_u32_state(struct rnd_state *state); -void prandom_bytes_state(struct rnd_state *state, void *buf, size_t nbytes); -void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state); - -#define prandom_init_once(pcpu_state) \ - DO_ONCE(prandom_seed_full_state, (pcpu_state)) - -/** - * prandom_u32_max - returns a pseudo-random number in interval [0, ep_ro) - * @ep_ro: right open interval endpoint - * - * Returns a pseudo-random number that is in interval [0, ep_ro). Note - * that the result depends on PRNG being well distributed in [0, ~0U] - * u32 space. Here we use maximally equidistributed combined Tausworthe - * generator, that is, prandom_u32(). This is useful when requesting a - * random index of an array containing ep_ro elements, for example. - * - * Returns: pseudo-random number in interval [0, ep_ro) - */ -static inline u32 prandom_u32_max(u32 ep_ro) -{ - return (u32)(((u64) prandom_u32() * ep_ro) >> 32); -} - -/* - * Handle minimum values for seeds - */ -static inline u32 __seed(u32 x, u32 m) -{ - return (x < m) ? x + m : x; -} - -/** - * prandom_seed_state - set seed for prandom_u32_state(). - * @state: pointer to state structure to receive the seed. - * @seed: arbitrary 64-bit value to use as a seed. - */ -static inline void prandom_seed_state(struct rnd_state *state, u64 seed) -{ - u32 i = (seed >> 32) ^ (seed << 10) ^ seed; - - state->s1 = __seed(i, 2U); - state->s2 = __seed(i, 8U); - state->s3 = __seed(i, 16U); - state->s4 = __seed(i, 128U); -} - -#ifdef CONFIG_ARCH_RANDOM -# include -#else -static inline bool arch_get_random_long(unsigned long *v) -{ - return 0; -} -static inline bool arch_get_random_int(unsigned int *v) -{ - return 0; -} -static inline bool arch_has_random(void) -{ - return 0; -} -static inline bool arch_get_random_seed_long(unsigned long *v) -{ - return 0; -} -static inline bool arch_get_random_seed_int(unsigned int *v) -{ - return 0; -} -static inline bool arch_has_random_seed(void) -{ - return 0; -} -#endif - -/* Pseudo random number generator from numerical recipes. */ -static inline u32 next_pseudo_random32(u32 seed) -{ - return seed * 1664525 + 1013904223; -} - -#endif /* _LINUX_RANDOM_H */ diff --git a/src/linux/include/linux/range.h b/src/linux/include/linux/range.h deleted file mode 100644 index bd184a5..0000000 --- a/src/linux/include/linux/range.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _LINUX_RANGE_H -#define _LINUX_RANGE_H - -struct range { - u64 start; - u64 end; -}; - -int add_range(struct range *range, int az, int nr_range, - u64 start, u64 end); - - -int add_range_with_merge(struct range *range, int az, int nr_range, - u64 start, u64 end); - -void subtract_range(struct range *range, int az, u64 start, u64 end); - -int clean_sort_range(struct range *range, int az); - -void sort_range(struct range *range, int nr_range); - -#define MAX_RESOURCE ((resource_size_t)~0) -static inline resource_size_t cap_resource(u64 val) -{ - if (val > MAX_RESOURCE) - return MAX_RESOURCE; - - return val; -} -#endif diff --git a/src/linux/include/linux/ratelimit.h b/src/linux/include/linux/ratelimit.h deleted file mode 100644 index 57c9e06..0000000 --- a/src/linux/include/linux/ratelimit.h +++ /dev/null @@ -1,109 +0,0 @@ -#ifndef _LINUX_RATELIMIT_H -#define _LINUX_RATELIMIT_H - -#include -#include -#include - -#define DEFAULT_RATELIMIT_INTERVAL (5 * HZ) -#define DEFAULT_RATELIMIT_BURST 10 - -/* issue num suppressed message on exit */ -#define RATELIMIT_MSG_ON_RELEASE BIT(0) - -struct ratelimit_state { - raw_spinlock_t lock; /* protect the state */ - - int interval; - int burst; - int printed; - int missed; - unsigned long begin; - unsigned long flags; -}; - -#define RATELIMIT_STATE_INIT(name, interval_init, burst_init) { \ - .lock = __RAW_SPIN_LOCK_UNLOCKED(name.lock), \ - .interval = interval_init, \ - .burst = burst_init, \ - } - -#define RATELIMIT_STATE_INIT_DISABLED \ - RATELIMIT_STATE_INIT(ratelimit_state, 0, DEFAULT_RATELIMIT_BURST) - -#define DEFINE_RATELIMIT_STATE(name, interval_init, burst_init) \ - \ - struct ratelimit_state name = \ - RATELIMIT_STATE_INIT(name, interval_init, burst_init) \ - -static inline void ratelimit_state_init(struct ratelimit_state *rs, - int interval, int burst) -{ - memset(rs, 0, sizeof(*rs)); - - raw_spin_lock_init(&rs->lock); - rs->interval = interval; - rs->burst = burst; -} - -static inline void ratelimit_default_init(struct ratelimit_state *rs) -{ - return ratelimit_state_init(rs, DEFAULT_RATELIMIT_INTERVAL, - DEFAULT_RATELIMIT_BURST); -} - -static inline void ratelimit_state_exit(struct ratelimit_state *rs) -{ - if (!(rs->flags & RATELIMIT_MSG_ON_RELEASE)) - return; - - if (rs->missed) { - pr_warn("%s: %d output lines suppressed due to ratelimiting\n", - current->comm, rs->missed); - rs->missed = 0; - } -} - -static inline void -ratelimit_set_flags(struct ratelimit_state *rs, unsigned long flags) -{ - rs->flags = flags; -} - -extern struct ratelimit_state printk_ratelimit_state; - -extern int ___ratelimit(struct ratelimit_state *rs, const char *func); -#define __ratelimit(state) ___ratelimit(state, __func__) - -#ifdef CONFIG_PRINTK - -#define WARN_ON_RATELIMIT(condition, state) \ - WARN_ON((condition) && __ratelimit(state)) - -#define WARN_RATELIMIT(condition, format, ...) \ -({ \ - static DEFINE_RATELIMIT_STATE(_rs, \ - DEFAULT_RATELIMIT_INTERVAL, \ - DEFAULT_RATELIMIT_BURST); \ - int rtn = !!(condition); \ - \ - if (unlikely(rtn && __ratelimit(&_rs))) \ - WARN(rtn, format, ##__VA_ARGS__); \ - \ - rtn; \ -}) - -#else - -#define WARN_ON_RATELIMIT(condition, state) \ - WARN_ON(condition) - -#define WARN_RATELIMIT(condition, format, ...) \ -({ \ - int rtn = WARN(condition, format, ##__VA_ARGS__); \ - rtn; \ -}) - -#endif - -#endif /* _LINUX_RATELIMIT_H */ diff --git a/src/linux/include/linux/rbtree.h b/src/linux/include/linux/rbtree.h deleted file mode 100644 index e585018..0000000 --- a/src/linux/include/linux/rbtree.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - Red Black Trees - (C) 1999 Andrea Arcangeli - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - linux/include/linux/rbtree.h - - To use rbtrees you'll have to implement your own insert and search cores. - This will avoid us to use callbacks and to drop drammatically performances. - I know it's not the cleaner way, but in C (not in C++) to get - performances and genericity... - - See Documentation/rbtree.txt for documentation and samples. -*/ - -#ifndef _LINUX_RBTREE_H -#define _LINUX_RBTREE_H - -#include -#include -#include - -struct rb_node { - unsigned long __rb_parent_color; - struct rb_node *rb_right; - struct rb_node *rb_left; -} __attribute__((aligned(sizeof(long)))); - /* The alignment might seem pointless, but allegedly CRIS needs it */ - -struct rb_root { - struct rb_node *rb_node; -}; - - -#define rb_parent(r) ((struct rb_node *)((r)->__rb_parent_color & ~3)) - -#define RB_ROOT (struct rb_root) { NULL, } -#define rb_entry(ptr, type, member) container_of(ptr, type, member) - -#define RB_EMPTY_ROOT(root) (READ_ONCE((root)->rb_node) == NULL) - -/* 'empty' nodes are nodes that are known not to be inserted in an rbtree */ -#define RB_EMPTY_NODE(node) \ - ((node)->__rb_parent_color == (unsigned long)(node)) -#define RB_CLEAR_NODE(node) \ - ((node)->__rb_parent_color = (unsigned long)(node)) - - -extern void rb_insert_color(struct rb_node *, struct rb_root *); -extern void rb_erase(struct rb_node *, struct rb_root *); - - -/* Find logical next and previous nodes in a tree */ -extern struct rb_node *rb_next(const struct rb_node *); -extern struct rb_node *rb_prev(const struct rb_node *); -extern struct rb_node *rb_first(const struct rb_root *); -extern struct rb_node *rb_last(const struct rb_root *); - -/* Postorder iteration - always visit the parent after its children */ -extern struct rb_node *rb_first_postorder(const struct rb_root *); -extern struct rb_node *rb_next_postorder(const struct rb_node *); - -/* Fast replacement of a single node without remove/rebalance/add/rebalance */ -extern void rb_replace_node(struct rb_node *victim, struct rb_node *new, - struct rb_root *root); -extern void rb_replace_node_rcu(struct rb_node *victim, struct rb_node *new, - struct rb_root *root); - -static inline void rb_link_node(struct rb_node *node, struct rb_node *parent, - struct rb_node **rb_link) -{ - node->__rb_parent_color = (unsigned long)parent; - node->rb_left = node->rb_right = NULL; - - *rb_link = node; -} - -static inline void rb_link_node_rcu(struct rb_node *node, struct rb_node *parent, - struct rb_node **rb_link) -{ - node->__rb_parent_color = (unsigned long)parent; - node->rb_left = node->rb_right = NULL; - - rcu_assign_pointer(*rb_link, node); -} - -#define rb_entry_safe(ptr, type, member) \ - ({ typeof(ptr) ____ptr = (ptr); \ - ____ptr ? rb_entry(____ptr, type, member) : NULL; \ - }) - -/** - * rbtree_postorder_for_each_entry_safe - iterate in post-order over rb_root of - * given type allowing the backing memory of @pos to be invalidated - * - * @pos: the 'type *' to use as a loop cursor. - * @n: another 'type *' to use as temporary storage - * @root: 'rb_root *' of the rbtree. - * @field: the name of the rb_node field within 'type'. - * - * rbtree_postorder_for_each_entry_safe() provides a similar guarantee as - * list_for_each_entry_safe() and allows the iteration to continue independent - * of changes to @pos by the body of the loop. - * - * Note, however, that it cannot handle other modifications that re-order the - * rbtree it is iterating over. This includes calling rb_erase() on @pos, as - * rb_erase() may rebalance the tree, causing us to miss some nodes. - */ -#define rbtree_postorder_for_each_entry_safe(pos, n, root, field) \ - for (pos = rb_entry_safe(rb_first_postorder(root), typeof(*pos), field); \ - pos && ({ n = rb_entry_safe(rb_next_postorder(&pos->field), \ - typeof(*pos), field); 1; }); \ - pos = n) - -#endif /* _LINUX_RBTREE_H */ diff --git a/src/linux/include/linux/rbtree_augmented.h b/src/linux/include/linux/rbtree_augmented.h deleted file mode 100644 index d076183..0000000 --- a/src/linux/include/linux/rbtree_augmented.h +++ /dev/null @@ -1,262 +0,0 @@ -/* - Red Black Trees - (C) 1999 Andrea Arcangeli - (C) 2002 David Woodhouse - (C) 2012 Michel Lespinasse - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - linux/include/linux/rbtree_augmented.h -*/ - -#ifndef _LINUX_RBTREE_AUGMENTED_H -#define _LINUX_RBTREE_AUGMENTED_H - -#include -#include - -/* - * Please note - only struct rb_augment_callbacks and the prototypes for - * rb_insert_augmented() and rb_erase_augmented() are intended to be public. - * The rest are implementation details you are not expected to depend on. - * - * See Documentation/rbtree.txt for documentation and samples. - */ - -struct rb_augment_callbacks { - void (*propagate)(struct rb_node *node, struct rb_node *stop); - void (*copy)(struct rb_node *old, struct rb_node *new); - void (*rotate)(struct rb_node *old, struct rb_node *new); -}; - -extern void __rb_insert_augmented(struct rb_node *node, struct rb_root *root, - void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); -/* - * Fixup the rbtree and update the augmented information when rebalancing. - * - * On insertion, the user must update the augmented information on the path - * leading to the inserted node, then call rb_link_node() as usual and - * rb_augment_inserted() instead of the usual rb_insert_color() call. - * If rb_augment_inserted() rebalances the rbtree, it will callback into - * a user provided function to update the augmented information on the - * affected subtrees. - */ -static inline void -rb_insert_augmented(struct rb_node *node, struct rb_root *root, - const struct rb_augment_callbacks *augment) -{ - __rb_insert_augmented(node, root, augment->rotate); -} - -#define RB_DECLARE_CALLBACKS(rbstatic, rbname, rbstruct, rbfield, \ - rbtype, rbaugmented, rbcompute) \ -static inline void \ -rbname ## _propagate(struct rb_node *rb, struct rb_node *stop) \ -{ \ - while (rb != stop) { \ - rbstruct *node = rb_entry(rb, rbstruct, rbfield); \ - rbtype augmented = rbcompute(node); \ - if (node->rbaugmented == augmented) \ - break; \ - node->rbaugmented = augmented; \ - rb = rb_parent(&node->rbfield); \ - } \ -} \ -static inline void \ -rbname ## _copy(struct rb_node *rb_old, struct rb_node *rb_new) \ -{ \ - rbstruct *old = rb_entry(rb_old, rbstruct, rbfield); \ - rbstruct *new = rb_entry(rb_new, rbstruct, rbfield); \ - new->rbaugmented = old->rbaugmented; \ -} \ -static void \ -rbname ## _rotate(struct rb_node *rb_old, struct rb_node *rb_new) \ -{ \ - rbstruct *old = rb_entry(rb_old, rbstruct, rbfield); \ - rbstruct *new = rb_entry(rb_new, rbstruct, rbfield); \ - new->rbaugmented = old->rbaugmented; \ - old->rbaugmented = rbcompute(old); \ -} \ -rbstatic const struct rb_augment_callbacks rbname = { \ - rbname ## _propagate, rbname ## _copy, rbname ## _rotate \ -}; - - -#define RB_RED 0 -#define RB_BLACK 1 - -#define __rb_parent(pc) ((struct rb_node *)(pc & ~3)) - -#define __rb_color(pc) ((pc) & 1) -#define __rb_is_black(pc) __rb_color(pc) -#define __rb_is_red(pc) (!__rb_color(pc)) -#define rb_color(rb) __rb_color((rb)->__rb_parent_color) -#define rb_is_red(rb) __rb_is_red((rb)->__rb_parent_color) -#define rb_is_black(rb) __rb_is_black((rb)->__rb_parent_color) - -static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p) -{ - rb->__rb_parent_color = rb_color(rb) | (unsigned long)p; -} - -static inline void rb_set_parent_color(struct rb_node *rb, - struct rb_node *p, int color) -{ - rb->__rb_parent_color = (unsigned long)p | color; -} - -static inline void -__rb_change_child(struct rb_node *old, struct rb_node *new, - struct rb_node *parent, struct rb_root *root) -{ - if (parent) { - if (parent->rb_left == old) - WRITE_ONCE(parent->rb_left, new); - else - WRITE_ONCE(parent->rb_right, new); - } else - WRITE_ONCE(root->rb_node, new); -} - -static inline void -__rb_change_child_rcu(struct rb_node *old, struct rb_node *new, - struct rb_node *parent, struct rb_root *root) -{ - if (parent) { - if (parent->rb_left == old) - rcu_assign_pointer(parent->rb_left, new); - else - rcu_assign_pointer(parent->rb_right, new); - } else - rcu_assign_pointer(root->rb_node, new); -} - -extern void __rb_erase_color(struct rb_node *parent, struct rb_root *root, - void (*augment_rotate)(struct rb_node *old, struct rb_node *new)); - -static __always_inline struct rb_node * -__rb_erase_augmented(struct rb_node *node, struct rb_root *root, - const struct rb_augment_callbacks *augment) -{ - struct rb_node *child = node->rb_right; - struct rb_node *tmp = node->rb_left; - struct rb_node *parent, *rebalance; - unsigned long pc; - - if (!tmp) { - /* - * Case 1: node to erase has no more than 1 child (easy!) - * - * Note that if there is one child it must be red due to 5) - * and node must be black due to 4). We adjust colors locally - * so as to bypass __rb_erase_color() later on. - */ - pc = node->__rb_parent_color; - parent = __rb_parent(pc); - __rb_change_child(node, child, parent, root); - if (child) { - child->__rb_parent_color = pc; - rebalance = NULL; - } else - rebalance = __rb_is_black(pc) ? parent : NULL; - tmp = parent; - } else if (!child) { - /* Still case 1, but this time the child is node->rb_left */ - tmp->__rb_parent_color = pc = node->__rb_parent_color; - parent = __rb_parent(pc); - __rb_change_child(node, tmp, parent, root); - rebalance = NULL; - tmp = parent; - } else { - struct rb_node *successor = child, *child2; - - tmp = child->rb_left; - if (!tmp) { - /* - * Case 2: node's successor is its right child - * - * (n) (s) - * / \ / \ - * (x) (s) -> (x) (c) - * \ - * (c) - */ - parent = successor; - child2 = successor->rb_right; - - augment->copy(node, successor); - } else { - /* - * Case 3: node's successor is leftmost under - * node's right child subtree - * - * (n) (s) - * / \ / \ - * (x) (y) -> (x) (y) - * / / - * (p) (p) - * / / - * (s) (c) - * \ - * (c) - */ - do { - parent = successor; - successor = tmp; - tmp = tmp->rb_left; - } while (tmp); - child2 = successor->rb_right; - WRITE_ONCE(parent->rb_left, child2); - WRITE_ONCE(successor->rb_right, child); - rb_set_parent(child, successor); - - augment->copy(node, successor); - augment->propagate(parent, successor); - } - - tmp = node->rb_left; - WRITE_ONCE(successor->rb_left, tmp); - rb_set_parent(tmp, successor); - - pc = node->__rb_parent_color; - tmp = __rb_parent(pc); - __rb_change_child(node, successor, tmp, root); - - if (child2) { - successor->__rb_parent_color = pc; - rb_set_parent_color(child2, parent, RB_BLACK); - rebalance = NULL; - } else { - unsigned long pc2 = successor->__rb_parent_color; - successor->__rb_parent_color = pc; - rebalance = __rb_is_black(pc2) ? parent : NULL; - } - tmp = successor; - } - - augment->propagate(tmp, NULL); - return rebalance; -} - -static __always_inline void -rb_erase_augmented(struct rb_node *node, struct rb_root *root, - const struct rb_augment_callbacks *augment) -{ - struct rb_node *rebalance = __rb_erase_augmented(node, root, augment); - if (rebalance) - __rb_erase_color(rebalance, root, augment->rotate); -} - -#endif /* _LINUX_RBTREE_AUGMENTED_H */ diff --git a/src/linux/include/linux/rbtree_latch.h b/src/linux/include/linux/rbtree_latch.h deleted file mode 100644 index 4f3432c..0000000 --- a/src/linux/include/linux/rbtree_latch.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Latched RB-trees - * - * Copyright (C) 2015 Intel Corp., Peter Zijlstra - * - * Since RB-trees have non-atomic modifications they're not immediately suited - * for RCU/lockless queries. Even though we made RB-tree lookups non-fatal for - * lockless lookups; we cannot guarantee they return a correct result. - * - * The simplest solution is a seqlock + RB-tree, this will allow lockless - * lookups; but has the constraint (inherent to the seqlock) that read sides - * cannot nest in write sides. - * - * If we need to allow unconditional lookups (say as required for NMI context - * usage) we need a more complex setup; this data structure provides this by - * employing the latch technique -- see @raw_write_seqcount_latch -- to - * implement a latched RB-tree which does allow for unconditional lookups by - * virtue of always having (at least) one stable copy of the tree. - * - * However, while we have the guarantee that there is at all times one stable - * copy, this does not guarantee an iteration will not observe modifications. - * What might have been a stable copy at the start of the iteration, need not - * remain so for the duration of the iteration. - * - * Therefore, this does require a lockless RB-tree iteration to be non-fatal; - * see the comment in lib/rbtree.c. Note however that we only require the first - * condition -- not seeing partial stores -- because the latch thing isolates - * us from loops. If we were to interrupt a modification the lookup would be - * pointed at the stable tree and complete while the modification was halted. - */ - -#ifndef RB_TREE_LATCH_H -#define RB_TREE_LATCH_H - -#include -#include - -struct latch_tree_node { - struct rb_node node[2]; -}; - -struct latch_tree_root { - seqcount_t seq; - struct rb_root tree[2]; -}; - -/** - * latch_tree_ops - operators to define the tree order - * @less: used for insertion; provides the (partial) order between two elements. - * @comp: used for lookups; provides the order between the search key and an element. - * - * The operators are related like: - * - * comp(a->key,b) < 0 := less(a,b) - * comp(a->key,b) > 0 := less(b,a) - * comp(a->key,b) == 0 := !less(a,b) && !less(b,a) - * - * If these operators define a partial order on the elements we make no - * guarantee on which of the elements matching the key is found. See - * latch_tree_find(). - */ -struct latch_tree_ops { - bool (*less)(struct latch_tree_node *a, struct latch_tree_node *b); - int (*comp)(void *key, struct latch_tree_node *b); -}; - -static __always_inline struct latch_tree_node * -__lt_from_rb(struct rb_node *node, int idx) -{ - return container_of(node, struct latch_tree_node, node[idx]); -} - -static __always_inline void -__lt_insert(struct latch_tree_node *ltn, struct latch_tree_root *ltr, int idx, - bool (*less)(struct latch_tree_node *a, struct latch_tree_node *b)) -{ - struct rb_root *root = <r->tree[idx]; - struct rb_node **link = &root->rb_node; - struct rb_node *node = <n->node[idx]; - struct rb_node *parent = NULL; - struct latch_tree_node *ltp; - - while (*link) { - parent = *link; - ltp = __lt_from_rb(parent, idx); - - if (less(ltn, ltp)) - link = &parent->rb_left; - else - link = &parent->rb_right; - } - - rb_link_node_rcu(node, parent, link); - rb_insert_color(node, root); -} - -static __always_inline void -__lt_erase(struct latch_tree_node *ltn, struct latch_tree_root *ltr, int idx) -{ - rb_erase(<n->node[idx], <r->tree[idx]); -} - -static __always_inline struct latch_tree_node * -__lt_find(void *key, struct latch_tree_root *ltr, int idx, - int (*comp)(void *key, struct latch_tree_node *node)) -{ - struct rb_node *node = rcu_dereference_raw(ltr->tree[idx].rb_node); - struct latch_tree_node *ltn; - int c; - - while (node) { - ltn = __lt_from_rb(node, idx); - c = comp(key, ltn); - - if (c < 0) - node = rcu_dereference_raw(node->rb_left); - else if (c > 0) - node = rcu_dereference_raw(node->rb_right); - else - return ltn; - } - - return NULL; -} - -/** - * latch_tree_insert() - insert @node into the trees @root - * @node: nodes to insert - * @root: trees to insert @node into - * @ops: operators defining the node order - * - * It inserts @node into @root in an ordered fashion such that we can always - * observe one complete tree. See the comment for raw_write_seqcount_latch(). - * - * The inserts use rcu_assign_pointer() to publish the element such that the - * tree structure is stored before we can observe the new @node. - * - * All modifications (latch_tree_insert, latch_tree_remove) are assumed to be - * serialized. - */ -static __always_inline void -latch_tree_insert(struct latch_tree_node *node, - struct latch_tree_root *root, - const struct latch_tree_ops *ops) -{ - raw_write_seqcount_latch(&root->seq); - __lt_insert(node, root, 0, ops->less); - raw_write_seqcount_latch(&root->seq); - __lt_insert(node, root, 1, ops->less); -} - -/** - * latch_tree_erase() - removes @node from the trees @root - * @node: nodes to remote - * @root: trees to remove @node from - * @ops: operators defining the node order - * - * Removes @node from the trees @root in an ordered fashion such that we can - * always observe one complete tree. See the comment for - * raw_write_seqcount_latch(). - * - * It is assumed that @node will observe one RCU quiescent state before being - * reused of freed. - * - * All modifications (latch_tree_insert, latch_tree_remove) are assumed to be - * serialized. - */ -static __always_inline void -latch_tree_erase(struct latch_tree_node *node, - struct latch_tree_root *root, - const struct latch_tree_ops *ops) -{ - raw_write_seqcount_latch(&root->seq); - __lt_erase(node, root, 0); - raw_write_seqcount_latch(&root->seq); - __lt_erase(node, root, 1); -} - -/** - * latch_tree_find() - find the node matching @key in the trees @root - * @key: search key - * @root: trees to search for @key - * @ops: operators defining the node order - * - * Does a lockless lookup in the trees @root for the node matching @key. - * - * It is assumed that this is called while holding the appropriate RCU read - * side lock. - * - * If the operators define a partial order on the elements (there are multiple - * elements which have the same key value) it is undefined which of these - * elements will be found. Nor is it possible to iterate the tree to find - * further elements with the same key value. - * - * Returns: a pointer to the node matching @key or NULL. - */ -static __always_inline struct latch_tree_node * -latch_tree_find(void *key, struct latch_tree_root *root, - const struct latch_tree_ops *ops) -{ - struct latch_tree_node *node; - unsigned int seq; - - do { - seq = raw_read_seqcount_latch(&root->seq); - node = __lt_find(key, root, seq & 1, ops->comp); - } while (read_seqcount_retry(&root->seq, seq)); - - return node; -} - -#endif /* RB_TREE_LATCH_H */ diff --git a/src/linux/include/linux/rcu_sync.h b/src/linux/include/linux/rcu_sync.h deleted file mode 100644 index ece7ed9..0000000 --- a/src/linux/include/linux/rcu_sync.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * RCU-based infrastructure for lightweight reader-writer locking - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you can access it online at - * http://www.gnu.org/licenses/gpl-2.0.html. - * - * Copyright (c) 2015, Red Hat, Inc. - * - * Author: Oleg Nesterov - */ - -#ifndef _LINUX_RCU_SYNC_H_ -#define _LINUX_RCU_SYNC_H_ - -#include -#include - -enum rcu_sync_type { RCU_SYNC, RCU_SCHED_SYNC, RCU_BH_SYNC }; - -/* Structure to mediate between updaters and fastpath-using readers. */ -struct rcu_sync { - int gp_state; - int gp_count; - wait_queue_head_t gp_wait; - - int cb_state; - struct rcu_head cb_head; - - enum rcu_sync_type gp_type; -}; - -extern void rcu_sync_lockdep_assert(struct rcu_sync *); - -/** - * rcu_sync_is_idle() - Are readers permitted to use their fastpaths? - * @rsp: Pointer to rcu_sync structure to use for synchronization - * - * Returns true if readers are permitted to use their fastpaths. - * Must be invoked within an RCU read-side critical section whose - * flavor matches that of the rcu_sync struture. - */ -static inline bool rcu_sync_is_idle(struct rcu_sync *rsp) -{ -#ifdef CONFIG_PROVE_RCU - rcu_sync_lockdep_assert(rsp); -#endif - return !rsp->gp_state; /* GP_IDLE */ -} - -extern void rcu_sync_init(struct rcu_sync *, enum rcu_sync_type); -extern void rcu_sync_enter_start(struct rcu_sync *); -extern void rcu_sync_enter(struct rcu_sync *); -extern void rcu_sync_exit(struct rcu_sync *); -extern void rcu_sync_dtor(struct rcu_sync *); - -#define __RCU_SYNC_INITIALIZER(name, type) { \ - .gp_state = 0, \ - .gp_count = 0, \ - .gp_wait = __WAIT_QUEUE_HEAD_INITIALIZER(name.gp_wait), \ - .cb_state = 0, \ - .gp_type = type, \ - } - -#define __DEFINE_RCU_SYNC(name, type) \ - struct rcu_sync_struct name = __RCU_SYNC_INITIALIZER(name, type) - -#define DEFINE_RCU_SYNC(name) \ - __DEFINE_RCU_SYNC(name, RCU_SYNC) - -#define DEFINE_RCU_SCHED_SYNC(name) \ - __DEFINE_RCU_SYNC(name, RCU_SCHED_SYNC) - -#define DEFINE_RCU_BH_SYNC(name) \ - __DEFINE_RCU_SYNC(name, RCU_BH_SYNC) - -#endif /* _LINUX_RCU_SYNC_H_ */ diff --git a/src/linux/include/linux/rculist.h b/src/linux/include/linux/rculist.h deleted file mode 100644 index 8beb98d..0000000 --- a/src/linux/include/linux/rculist.h +++ /dev/null @@ -1,675 +0,0 @@ -#ifndef _LINUX_RCULIST_H -#define _LINUX_RCULIST_H - -#ifdef __KERNEL__ - -/* - * RCU-protected list version - */ -#include -#include - -/* - * Why is there no list_empty_rcu()? Because list_empty() serves this - * purpose. The list_empty() function fetches the RCU-protected pointer - * and compares it to the address of the list head, but neither dereferences - * this pointer itself nor provides this pointer to the caller. Therefore, - * it is not necessary to use rcu_dereference(), so that list_empty() can - * be used anywhere you would want to use a list_empty_rcu(). - */ - -/* - * INIT_LIST_HEAD_RCU - Initialize a list_head visible to RCU readers - * @list: list to be initialized - * - * You should instead use INIT_LIST_HEAD() for normal initialization and - * cleanup tasks, when readers have no access to the list being initialized. - * However, if the list being initialized is visible to readers, you - * need to keep the compiler from being too mischievous. - */ -static inline void INIT_LIST_HEAD_RCU(struct list_head *list) -{ - WRITE_ONCE(list->next, list); - WRITE_ONCE(list->prev, list); -} - -/* - * return the ->next pointer of a list_head in an rcu safe - * way, we must not access it directly - */ -#define list_next_rcu(list) (*((struct list_head __rcu **)(&(list)->next))) - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -#ifndef CONFIG_DEBUG_LIST -static inline void __list_add_rcu(struct list_head *new, - struct list_head *prev, struct list_head *next) -{ - new->next = next; - new->prev = prev; - rcu_assign_pointer(list_next_rcu(prev), new); - next->prev = new; -} -#else -void __list_add_rcu(struct list_head *new, - struct list_head *prev, struct list_head *next); -#endif - -/** - * list_add_rcu - add a new entry to rcu-protected list - * @new: new entry to be added - * @head: list head to add it after - * - * Insert a new entry after the specified head. - * This is good for implementing stacks. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as list_add_rcu() - * or list_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * list_for_each_entry_rcu(). - */ -static inline void list_add_rcu(struct list_head *new, struct list_head *head) -{ - __list_add_rcu(new, head, head->next); -} - -/** - * list_add_tail_rcu - add a new entry to rcu-protected list - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as list_add_tail_rcu() - * or list_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * list_for_each_entry_rcu(). - */ -static inline void list_add_tail_rcu(struct list_head *new, - struct list_head *head) -{ - __list_add_rcu(new, head->prev, head); -} - -/** - * list_del_rcu - deletes entry from list without re-initialization - * @entry: the element to delete from the list. - * - * Note: list_empty() on entry does not return true after this, - * the entry is in an undefined state. It is useful for RCU based - * lockfree traversal. - * - * In particular, it means that we can not poison the forward - * pointers that may still be used for walking the list. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as list_del_rcu() - * or list_add_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * list_for_each_entry_rcu(). - * - * Note that the caller is not permitted to immediately free - * the newly deleted entry. Instead, either synchronize_rcu() - * or call_rcu() must be used to defer freeing until an RCU - * grace period has elapsed. - */ -static inline void list_del_rcu(struct list_head *entry) -{ - __list_del_entry(entry); - entry->prev = LIST_POISON2; -} - -/** - * hlist_del_init_rcu - deletes entry from hash list with re-initialization - * @n: the element to delete from the hash list. - * - * Note: list_unhashed() on the node return true after this. It is - * useful for RCU based read lockfree traversal if the writer side - * must know if the list entry is still hashed or already unhashed. - * - * In particular, it means that we can not poison the forward pointers - * that may still be used for walking the hash list and we can only - * zero the pprev pointer so list_unhashed() will return true after - * this. - * - * The caller must take whatever precautions are necessary (such as - * holding appropriate locks) to avoid racing with another - * list-mutation primitive, such as hlist_add_head_rcu() or - * hlist_del_rcu(), running on this same list. However, it is - * perfectly legal to run concurrently with the _rcu list-traversal - * primitives, such as hlist_for_each_entry_rcu(). - */ -static inline void hlist_del_init_rcu(struct hlist_node *n) -{ - if (!hlist_unhashed(n)) { - __hlist_del(n); - n->pprev = NULL; - } -} - -/** - * list_replace_rcu - replace old entry by new one - * @old : the element to be replaced - * @new : the new element to insert - * - * The @old entry will be replaced with the @new entry atomically. - * Note: @old should not be empty. - */ -static inline void list_replace_rcu(struct list_head *old, - struct list_head *new) -{ - new->next = old->next; - new->prev = old->prev; - rcu_assign_pointer(list_next_rcu(new->prev), new); - new->next->prev = new; - old->prev = LIST_POISON2; -} - -/** - * __list_splice_init_rcu - join an RCU-protected list into an existing list. - * @list: the RCU-protected list to splice - * @prev: points to the last element of the existing list - * @next: points to the first element of the existing list - * @sync: function to sync: synchronize_rcu(), synchronize_sched(), ... - * - * The list pointed to by @prev and @next can be RCU-read traversed - * concurrently with this function. - * - * Note that this function blocks. - * - * Important note: the caller must take whatever action is necessary to prevent - * any other updates to the existing list. In principle, it is possible to - * modify the list as soon as sync() begins execution. If this sort of thing - * becomes necessary, an alternative version based on call_rcu() could be - * created. But only if -really- needed -- there is no shortage of RCU API - * members. - */ -static inline void __list_splice_init_rcu(struct list_head *list, - struct list_head *prev, - struct list_head *next, - void (*sync)(void)) -{ - struct list_head *first = list->next; - struct list_head *last = list->prev; - - /* - * "first" and "last" tracking list, so initialize it. RCU readers - * have access to this list, so we must use INIT_LIST_HEAD_RCU() - * instead of INIT_LIST_HEAD(). - */ - - INIT_LIST_HEAD_RCU(list); - - /* - * At this point, the list body still points to the source list. - * Wait for any readers to finish using the list before splicing - * the list body into the new list. Any new readers will see - * an empty list. - */ - - sync(); - - /* - * Readers are finished with the source list, so perform splice. - * The order is important if the new list is global and accessible - * to concurrent RCU readers. Note that RCU readers are not - * permitted to traverse the prev pointers without excluding - * this function. - */ - - last->next = next; - rcu_assign_pointer(list_next_rcu(prev), first); - first->prev = prev; - next->prev = last; -} - -/** - * list_splice_init_rcu - splice an RCU-protected list into an existing list, - * designed for stacks. - * @list: the RCU-protected list to splice - * @head: the place in the existing list to splice the first list into - * @sync: function to sync: synchronize_rcu(), synchronize_sched(), ... - */ -static inline void list_splice_init_rcu(struct list_head *list, - struct list_head *head, - void (*sync)(void)) -{ - if (!list_empty(list)) - __list_splice_init_rcu(list, head, head->next, sync); -} - -/** - * list_splice_tail_init_rcu - splice an RCU-protected list into an existing - * list, designed for queues. - * @list: the RCU-protected list to splice - * @head: the place in the existing list to splice the first list into - * @sync: function to sync: synchronize_rcu(), synchronize_sched(), ... - */ -static inline void list_splice_tail_init_rcu(struct list_head *list, - struct list_head *head, - void (*sync)(void)) -{ - if (!list_empty(list)) - __list_splice_init_rcu(list, head->prev, head, sync); -} - -/** - * list_entry_rcu - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_head within the struct. - * - * This primitive may safely run concurrently with the _rcu list-mutation - * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock(). - */ -#define list_entry_rcu(ptr, type, member) \ - container_of(lockless_dereference(ptr), type, member) - -/** - * Where are list_empty_rcu() and list_first_entry_rcu()? - * - * Implementing those functions following their counterparts list_empty() and - * list_first_entry() is not advisable because they lead to subtle race - * conditions as the following snippet shows: - * - * if (!list_empty_rcu(mylist)) { - * struct foo *bar = list_first_entry_rcu(mylist, struct foo, list_member); - * do_something(bar); - * } - * - * The list may not be empty when list_empty_rcu checks it, but it may be when - * list_first_entry_rcu rereads the ->next pointer. - * - * Rereading the ->next pointer is not a problem for list_empty() and - * list_first_entry() because they would be protected by a lock that blocks - * writers. - * - * See list_first_or_null_rcu for an alternative. - */ - -/** - * list_first_or_null_rcu - get the first element from a list - * @ptr: the list head to take the element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_head within the struct. - * - * Note that if the list is empty, it returns NULL. - * - * This primitive may safely run concurrently with the _rcu list-mutation - * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock(). - */ -#define list_first_or_null_rcu(ptr, type, member) \ -({ \ - struct list_head *__ptr = (ptr); \ - struct list_head *__next = READ_ONCE(__ptr->next); \ - likely(__ptr != __next) ? list_entry_rcu(__next, type, member) : NULL; \ -}) - -/** - * list_next_or_null_rcu - get the first element from a list - * @head: the head for the list. - * @ptr: the list head to take the next element from. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_head within the struct. - * - * Note that if the ptr is at the end of the list, NULL is returned. - * - * This primitive may safely run concurrently with the _rcu list-mutation - * primitives such as list_add_rcu() as long as it's guarded by rcu_read_lock(). - */ -#define list_next_or_null_rcu(head, ptr, type, member) \ -({ \ - struct list_head *__head = (head); \ - struct list_head *__ptr = (ptr); \ - struct list_head *__next = READ_ONCE(__ptr->next); \ - likely(__next != __head) ? list_entry_rcu(__next, type, \ - member) : NULL; \ -}) - -/** - * list_for_each_entry_rcu - iterate over rcu list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_head within the struct. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as list_add_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -#define list_for_each_entry_rcu(pos, head, member) \ - for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry_rcu(pos->member.next, typeof(*pos), member)) - -/** - * list_entry_lockless - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_head within the struct. - * - * This primitive may safely run concurrently with the _rcu list-mutation - * primitives such as list_add_rcu(), but requires some implicit RCU - * read-side guarding. One example is running within a special - * exception-time environment where preemption is disabled and where - * lockdep cannot be invoked (in which case updaters must use RCU-sched, - * as in synchronize_sched(), call_rcu_sched(), and friends). Another - * example is when items are added to the list, but never deleted. - */ -#define list_entry_lockless(ptr, type, member) \ - container_of((typeof(ptr))lockless_dereference(ptr), type, member) - -/** - * list_for_each_entry_lockless - iterate over rcu list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_struct within the struct. - * - * This primitive may safely run concurrently with the _rcu list-mutation - * primitives such as list_add_rcu(), but requires some implicit RCU - * read-side guarding. One example is running within a special - * exception-time environment where preemption is disabled and where - * lockdep cannot be invoked (in which case updaters must use RCU-sched, - * as in synchronize_sched(), call_rcu_sched(), and friends). Another - * example is when items are added to the list, but never deleted. - */ -#define list_for_each_entry_lockless(pos, head, member) \ - for (pos = list_entry_lockless((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry_lockless(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_continue_rcu - continue iteration over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_head within the struct. - * - * Continue to iterate over list of given type, continuing after - * the current position. - */ -#define list_for_each_entry_continue_rcu(pos, head, member) \ - for (pos = list_entry_rcu(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry_rcu(pos->member.next, typeof(*pos), member)) - -/** - * hlist_del_rcu - deletes entry from hash list without re-initialization - * @n: the element to delete from the hash list. - * - * Note: list_unhashed() on entry does not return true after this, - * the entry is in an undefined state. It is useful for RCU based - * lockfree traversal. - * - * In particular, it means that we can not poison the forward - * pointers that may still be used for walking the hash list. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_add_head_rcu() - * or hlist_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_for_each_entry(). - */ -static inline void hlist_del_rcu(struct hlist_node *n) -{ - __hlist_del(n); - n->pprev = LIST_POISON2; -} - -/** - * hlist_replace_rcu - replace old entry by new one - * @old : the element to be replaced - * @new : the new element to insert - * - * The @old entry will be replaced with the @new entry atomically. - */ -static inline void hlist_replace_rcu(struct hlist_node *old, - struct hlist_node *new) -{ - struct hlist_node *next = old->next; - - new->next = next; - new->pprev = old->pprev; - rcu_assign_pointer(*(struct hlist_node __rcu **)new->pprev, new); - if (next) - new->next->pprev = &new->next; - old->pprev = LIST_POISON2; -} - -/* - * return the first or the next element in an RCU protected hlist - */ -#define hlist_first_rcu(head) (*((struct hlist_node __rcu **)(&(head)->first))) -#define hlist_next_rcu(node) (*((struct hlist_node __rcu **)(&(node)->next))) -#define hlist_pprev_rcu(node) (*((struct hlist_node __rcu **)((node)->pprev))) - -/** - * hlist_add_head_rcu - * @n: the element to add to the hash list. - * @h: the list to add to. - * - * Description: - * Adds the specified element to the specified hlist, - * while permitting racing traversals. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_add_head_rcu() - * or hlist_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_for_each_entry_rcu(), used to prevent memory-consistency - * problems on Alpha CPUs. Regardless of the type of CPU, the - * list-traversal primitive must be guarded by rcu_read_lock(). - */ -static inline void hlist_add_head_rcu(struct hlist_node *n, - struct hlist_head *h) -{ - struct hlist_node *first = h->first; - - n->next = first; - n->pprev = &h->first; - rcu_assign_pointer(hlist_first_rcu(h), n); - if (first) - first->pprev = &n->next; -} - -/** - * hlist_add_tail_rcu - * @n: the element to add to the hash list. - * @h: the list to add to. - * - * Description: - * Adds the specified element to the specified hlist, - * while permitting racing traversals. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_add_head_rcu() - * or hlist_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_for_each_entry_rcu(), used to prevent memory-consistency - * problems on Alpha CPUs. Regardless of the type of CPU, the - * list-traversal primitive must be guarded by rcu_read_lock(). - */ -static inline void hlist_add_tail_rcu(struct hlist_node *n, - struct hlist_head *h) -{ - struct hlist_node *i, *last = NULL; - - for (i = hlist_first_rcu(h); i; i = hlist_next_rcu(i)) - last = i; - - if (last) { - n->next = last->next; - n->pprev = &last->next; - rcu_assign_pointer(hlist_next_rcu(last), n); - } else { - hlist_add_head_rcu(n, h); - } -} - -/** - * hlist_add_before_rcu - * @n: the new element to add to the hash list. - * @next: the existing element to add the new element before. - * - * Description: - * Adds the specified element to the specified hlist - * before the specified node while permitting racing traversals. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_add_head_rcu() - * or hlist_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_for_each_entry_rcu(), used to prevent memory-consistency - * problems on Alpha CPUs. - */ -static inline void hlist_add_before_rcu(struct hlist_node *n, - struct hlist_node *next) -{ - n->pprev = next->pprev; - n->next = next; - rcu_assign_pointer(hlist_pprev_rcu(n), n); - next->pprev = &n->next; -} - -/** - * hlist_add_behind_rcu - * @n: the new element to add to the hash list. - * @prev: the existing element to add the new element after. - * - * Description: - * Adds the specified element to the specified hlist - * after the specified node while permitting racing traversals. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_add_head_rcu() - * or hlist_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_for_each_entry_rcu(), used to prevent memory-consistency - * problems on Alpha CPUs. - */ -static inline void hlist_add_behind_rcu(struct hlist_node *n, - struct hlist_node *prev) -{ - n->next = prev->next; - n->pprev = &prev->next; - rcu_assign_pointer(hlist_next_rcu(prev), n); - if (n->next) - n->next->pprev = &n->next; -} - -#define __hlist_for_each_rcu(pos, head) \ - for (pos = rcu_dereference(hlist_first_rcu(head)); \ - pos; \ - pos = rcu_dereference(hlist_next_rcu(pos))) - -/** - * hlist_for_each_entry_rcu - iterate over rcu list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as hlist_add_head_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -#define hlist_for_each_entry_rcu(pos, head, member) \ - for (pos = hlist_entry_safe (rcu_dereference_raw(hlist_first_rcu(head)),\ - typeof(*(pos)), member); \ - pos; \ - pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu(\ - &(pos)->member)), typeof(*(pos)), member)) - -/** - * hlist_for_each_entry_rcu_notrace - iterate over rcu list of given type (for tracing) - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as hlist_add_head_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - * - * This is the same as hlist_for_each_entry_rcu() except that it does - * not do any RCU debugging or tracing. - */ -#define hlist_for_each_entry_rcu_notrace(pos, head, member) \ - for (pos = hlist_entry_safe (rcu_dereference_raw_notrace(hlist_first_rcu(head)),\ - typeof(*(pos)), member); \ - pos; \ - pos = hlist_entry_safe(rcu_dereference_raw_notrace(hlist_next_rcu(\ - &(pos)->member)), typeof(*(pos)), member)) - -/** - * hlist_for_each_entry_rcu_bh - iterate over rcu list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the hlist_node within the struct. - * - * This list-traversal primitive may safely run concurrently with - * the _rcu list-mutation primitives such as hlist_add_head_rcu() - * as long as the traversal is guarded by rcu_read_lock(). - */ -#define hlist_for_each_entry_rcu_bh(pos, head, member) \ - for (pos = hlist_entry_safe(rcu_dereference_bh(hlist_first_rcu(head)),\ - typeof(*(pos)), member); \ - pos; \ - pos = hlist_entry_safe(rcu_dereference_bh(hlist_next_rcu(\ - &(pos)->member)), typeof(*(pos)), member)) - -/** - * hlist_for_each_entry_continue_rcu - iterate over a hlist continuing after current point - * @pos: the type * to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_continue_rcu(pos, member) \ - for (pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu( \ - &(pos)->member)), typeof(*(pos)), member); \ - pos; \ - pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu( \ - &(pos)->member)), typeof(*(pos)), member)) - -/** - * hlist_for_each_entry_continue_rcu_bh - iterate over a hlist continuing after current point - * @pos: the type * to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_continue_rcu_bh(pos, member) \ - for (pos = hlist_entry_safe(rcu_dereference_bh(hlist_next_rcu( \ - &(pos)->member)), typeof(*(pos)), member); \ - pos; \ - pos = hlist_entry_safe(rcu_dereference_bh(hlist_next_rcu( \ - &(pos)->member)), typeof(*(pos)), member)) - -/** - * hlist_for_each_entry_from_rcu - iterate over a hlist continuing from current point - * @pos: the type * to use as a loop cursor. - * @member: the name of the hlist_node within the struct. - */ -#define hlist_for_each_entry_from_rcu(pos, member) \ - for (; pos; \ - pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu( \ - &(pos)->member)), typeof(*(pos)), member)) - -#endif /* __KERNEL__ */ -#endif diff --git a/src/linux/include/linux/rculist_bl.h b/src/linux/include/linux/rculist_bl.h deleted file mode 100644 index 4f216c5..0000000 --- a/src/linux/include/linux/rculist_bl.h +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef _LINUX_RCULIST_BL_H -#define _LINUX_RCULIST_BL_H - -/* - * RCU-protected bl list version. See include/linux/list_bl.h. - */ -#include -#include - -static inline void hlist_bl_set_first_rcu(struct hlist_bl_head *h, - struct hlist_bl_node *n) -{ - LIST_BL_BUG_ON((unsigned long)n & LIST_BL_LOCKMASK); - LIST_BL_BUG_ON(((unsigned long)h->first & LIST_BL_LOCKMASK) != - LIST_BL_LOCKMASK); - rcu_assign_pointer(h->first, - (struct hlist_bl_node *)((unsigned long)n | LIST_BL_LOCKMASK)); -} - -static inline struct hlist_bl_node *hlist_bl_first_rcu(struct hlist_bl_head *h) -{ - return (struct hlist_bl_node *) - ((unsigned long)rcu_dereference_check(h->first, hlist_bl_is_locked(h)) & ~LIST_BL_LOCKMASK); -} - -/** - * hlist_bl_del_init_rcu - deletes entry from hash list with re-initialization - * @n: the element to delete from the hash list. - * - * Note: hlist_bl_unhashed() on the node returns true after this. It is - * useful for RCU based read lockfree traversal if the writer side - * must know if the list entry is still hashed or already unhashed. - * - * In particular, it means that we can not poison the forward pointers - * that may still be used for walking the hash list and we can only - * zero the pprev pointer so list_unhashed() will return true after - * this. - * - * The caller must take whatever precautions are necessary (such as - * holding appropriate locks) to avoid racing with another - * list-mutation primitive, such as hlist_bl_add_head_rcu() or - * hlist_bl_del_rcu(), running on this same list. However, it is - * perfectly legal to run concurrently with the _rcu list-traversal - * primitives, such as hlist_bl_for_each_entry_rcu(). - */ -static inline void hlist_bl_del_init_rcu(struct hlist_bl_node *n) -{ - if (!hlist_bl_unhashed(n)) { - __hlist_bl_del(n); - n->pprev = NULL; - } -} - -/** - * hlist_bl_del_rcu - deletes entry from hash list without re-initialization - * @n: the element to delete from the hash list. - * - * Note: hlist_bl_unhashed() on entry does not return true after this, - * the entry is in an undefined state. It is useful for RCU based - * lockfree traversal. - * - * In particular, it means that we can not poison the forward - * pointers that may still be used for walking the hash list. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_bl_add_head_rcu() - * or hlist_bl_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_bl_for_each_entry(). - */ -static inline void hlist_bl_del_rcu(struct hlist_bl_node *n) -{ - __hlist_bl_del(n); - n->pprev = LIST_POISON2; -} - -/** - * hlist_bl_add_head_rcu - * @n: the element to add to the hash list. - * @h: the list to add to. - * - * Description: - * Adds the specified element to the specified hlist_bl, - * while permitting racing traversals. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_bl_add_head_rcu() - * or hlist_bl_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_bl_for_each_entry_rcu(), used to prevent memory-consistency - * problems on Alpha CPUs. Regardless of the type of CPU, the - * list-traversal primitive must be guarded by rcu_read_lock(). - */ -static inline void hlist_bl_add_head_rcu(struct hlist_bl_node *n, - struct hlist_bl_head *h) -{ - struct hlist_bl_node *first; - - /* don't need hlist_bl_first_rcu because we're under lock */ - first = hlist_bl_first(h); - - n->next = first; - if (first) - first->pprev = &n->next; - n->pprev = &h->first; - - /* need _rcu because we can have concurrent lock free readers */ - hlist_bl_set_first_rcu(h, n); -} -/** - * hlist_bl_for_each_entry_rcu - iterate over rcu list of given type - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_bl_node to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the hlist_bl_node within the struct. - * - */ -#define hlist_bl_for_each_entry_rcu(tpos, pos, head, member) \ - for (pos = hlist_bl_first_rcu(head); \ - pos && \ - ({ tpos = hlist_bl_entry(pos, typeof(*tpos), member); 1; }); \ - pos = rcu_dereference_raw(pos->next)) - -#endif diff --git a/src/linux/include/linux/rculist_nulls.h b/src/linux/include/linux/rculist_nulls.h deleted file mode 100644 index 4ae95f7..0000000 --- a/src/linux/include/linux/rculist_nulls.h +++ /dev/null @@ -1,160 +0,0 @@ -#ifndef _LINUX_RCULIST_NULLS_H -#define _LINUX_RCULIST_NULLS_H - -#ifdef __KERNEL__ - -/* - * RCU-protected list version - */ -#include -#include - -/** - * hlist_nulls_del_init_rcu - deletes entry from hash list with re-initialization - * @n: the element to delete from the hash list. - * - * Note: hlist_nulls_unhashed() on the node return true after this. It is - * useful for RCU based read lockfree traversal if the writer side - * must know if the list entry is still hashed or already unhashed. - * - * In particular, it means that we can not poison the forward pointers - * that may still be used for walking the hash list and we can only - * zero the pprev pointer so list_unhashed() will return true after - * this. - * - * The caller must take whatever precautions are necessary (such as - * holding appropriate locks) to avoid racing with another - * list-mutation primitive, such as hlist_nulls_add_head_rcu() or - * hlist_nulls_del_rcu(), running on this same list. However, it is - * perfectly legal to run concurrently with the _rcu list-traversal - * primitives, such as hlist_nulls_for_each_entry_rcu(). - */ -static inline void hlist_nulls_del_init_rcu(struct hlist_nulls_node *n) -{ - if (!hlist_nulls_unhashed(n)) { - __hlist_nulls_del(n); - n->pprev = NULL; - } -} - -#define hlist_nulls_first_rcu(head) \ - (*((struct hlist_nulls_node __rcu __force **)&(head)->first)) - -#define hlist_nulls_next_rcu(node) \ - (*((struct hlist_nulls_node __rcu __force **)&(node)->next)) - -/** - * hlist_nulls_del_rcu - deletes entry from hash list without re-initialization - * @n: the element to delete from the hash list. - * - * Note: hlist_nulls_unhashed() on entry does not return true after this, - * the entry is in an undefined state. It is useful for RCU based - * lockfree traversal. - * - * In particular, it means that we can not poison the forward - * pointers that may still be used for walking the hash list. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_nulls_add_head_rcu() - * or hlist_nulls_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_nulls_for_each_entry(). - */ -static inline void hlist_nulls_del_rcu(struct hlist_nulls_node *n) -{ - __hlist_nulls_del(n); - n->pprev = LIST_POISON2; -} - -/** - * hlist_nulls_add_head_rcu - * @n: the element to add to the hash list. - * @h: the list to add to. - * - * Description: - * Adds the specified element to the specified hlist_nulls, - * while permitting racing traversals. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_nulls_add_head_rcu() - * or hlist_nulls_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_nulls_for_each_entry_rcu(), used to prevent memory-consistency - * problems on Alpha CPUs. Regardless of the type of CPU, the - * list-traversal primitive must be guarded by rcu_read_lock(). - */ -static inline void hlist_nulls_add_head_rcu(struct hlist_nulls_node *n, - struct hlist_nulls_head *h) -{ - struct hlist_nulls_node *first = h->first; - - n->next = first; - n->pprev = &h->first; - rcu_assign_pointer(hlist_nulls_first_rcu(h), n); - if (!is_a_nulls(first)) - first->pprev = &n->next; -} - -/** - * hlist_nulls_add_tail_rcu - * @n: the element to add to the hash list. - * @h: the list to add to. - * - * Description: - * Adds the specified element to the end of the specified hlist_nulls, - * while permitting racing traversals. NOTE: tail insertion requires - * list traversal. - * - * The caller must take whatever precautions are necessary - * (such as holding appropriate locks) to avoid racing - * with another list-mutation primitive, such as hlist_nulls_add_head_rcu() - * or hlist_nulls_del_rcu(), running on this same list. - * However, it is perfectly legal to run concurrently with - * the _rcu list-traversal primitives, such as - * hlist_nulls_for_each_entry_rcu(), used to prevent memory-consistency - * problems on Alpha CPUs. Regardless of the type of CPU, the - * list-traversal primitive must be guarded by rcu_read_lock(). - */ -static inline void hlist_nulls_add_tail_rcu(struct hlist_nulls_node *n, - struct hlist_nulls_head *h) -{ - struct hlist_nulls_node *i, *last = NULL; - - for (i = hlist_nulls_first_rcu(h); !is_a_nulls(i); - i = hlist_nulls_next_rcu(i)) - last = i; - - if (last) { - n->next = last->next; - n->pprev = &last->next; - rcu_assign_pointer(hlist_nulls_next_rcu(last), n); - } else { - hlist_nulls_add_head_rcu(n, h); - } -} - -/** - * hlist_nulls_for_each_entry_rcu - iterate over rcu list of given type - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_nulls_node to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the hlist_nulls_node within the struct. - * - * The barrier() is needed to make sure compiler doesn't cache first element [1], - * as this loop can be restarted [2] - * [1] Documentation/atomic_ops.txt around line 114 - * [2] Documentation/RCU/rculist_nulls.txt around line 146 - */ -#define hlist_nulls_for_each_entry_rcu(tpos, pos, head, member) \ - for (({barrier();}), \ - pos = rcu_dereference_raw(hlist_nulls_first_rcu(head)); \ - (!is_a_nulls(pos)) && \ - ({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1; }); \ - pos = rcu_dereference_raw(hlist_nulls_next_rcu(pos))) - -#endif -#endif diff --git a/src/linux/include/linux/rcupdate.h b/src/linux/include/linux/rcupdate.h deleted file mode 100644 index 321f9ed..0000000 --- a/src/linux/include/linux/rcupdate.h +++ /dev/null @@ -1,1161 +0,0 @@ -/* - * Read-Copy Update mechanism for mutual exclusion - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you can access it online at - * http://www.gnu.org/licenses/gpl-2.0.html. - * - * Copyright IBM Corporation, 2001 - * - * Author: Dipankar Sarma - * - * Based on the original work by Paul McKenney - * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen. - * Papers: - * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf - * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001) - * - * For detailed explanation of Read-Copy Update mechanism see - - * http://lse.sourceforge.net/locking/rcupdate.html - * - */ - -#ifndef __LINUX_RCUPDATE_H -#define __LINUX_RCUPDATE_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifndef CONFIG_TINY_RCU -extern int rcu_expedited; /* for sysctl */ -extern int rcu_normal; /* also for sysctl */ -#endif /* #ifndef CONFIG_TINY_RCU */ - -#ifdef CONFIG_TINY_RCU -/* Tiny RCU doesn't expedite, as its purpose in life is instead to be tiny. */ -static inline bool rcu_gp_is_normal(void) /* Internal RCU use. */ -{ - return true; -} -static inline bool rcu_gp_is_expedited(void) /* Internal RCU use. */ -{ - return false; -} - -static inline void rcu_expedite_gp(void) -{ -} - -static inline void rcu_unexpedite_gp(void) -{ -} -#else /* #ifdef CONFIG_TINY_RCU */ -bool rcu_gp_is_normal(void); /* Internal RCU use. */ -bool rcu_gp_is_expedited(void); /* Internal RCU use. */ -void rcu_expedite_gp(void); -void rcu_unexpedite_gp(void); -#endif /* #else #ifdef CONFIG_TINY_RCU */ - -enum rcutorture_type { - RCU_FLAVOR, - RCU_BH_FLAVOR, - RCU_SCHED_FLAVOR, - RCU_TASKS_FLAVOR, - SRCU_FLAVOR, - INVALID_RCU_FLAVOR -}; - -#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU) -void rcutorture_get_gp_data(enum rcutorture_type test_type, int *flags, - unsigned long *gpnum, unsigned long *completed); -void rcutorture_record_test_transition(void); -void rcutorture_record_progress(unsigned long vernum); -void do_trace_rcu_torture_read(const char *rcutorturename, - struct rcu_head *rhp, - unsigned long secs, - unsigned long c_old, - unsigned long c); -#else -static inline void rcutorture_get_gp_data(enum rcutorture_type test_type, - int *flags, - unsigned long *gpnum, - unsigned long *completed) -{ - *flags = 0; - *gpnum = 0; - *completed = 0; -} -static inline void rcutorture_record_test_transition(void) -{ -} -static inline void rcutorture_record_progress(unsigned long vernum) -{ -} -#ifdef CONFIG_RCU_TRACE -void do_trace_rcu_torture_read(const char *rcutorturename, - struct rcu_head *rhp, - unsigned long secs, - unsigned long c_old, - unsigned long c); -#else -#define do_trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \ - do { } while (0) -#endif -#endif - -#define UINT_CMP_GE(a, b) (UINT_MAX / 2 >= (a) - (b)) -#define UINT_CMP_LT(a, b) (UINT_MAX / 2 < (a) - (b)) -#define ULONG_CMP_GE(a, b) (ULONG_MAX / 2 >= (a) - (b)) -#define ULONG_CMP_LT(a, b) (ULONG_MAX / 2 < (a) - (b)) -#define ulong2long(a) (*(long *)(&(a))) - -/* Exported common interfaces */ - -#ifdef CONFIG_PREEMPT_RCU - -/** - * call_rcu() - Queue an RCU callback for invocation after a grace period. - * @head: structure to be used for queueing the RCU updates. - * @func: actual callback function to be invoked after the grace period - * - * The callback function will be invoked some time after a full grace - * period elapses, in other words after all pre-existing RCU read-side - * critical sections have completed. However, the callback function - * might well execute concurrently with RCU read-side critical sections - * that started after call_rcu() was invoked. RCU read-side critical - * sections are delimited by rcu_read_lock() and rcu_read_unlock(), - * and may be nested. - * - * Note that all CPUs must agree that the grace period extended beyond - * all pre-existing RCU read-side critical section. On systems with more - * than one CPU, this means that when "func()" is invoked, each CPU is - * guaranteed to have executed a full memory barrier since the end of its - * last RCU read-side critical section whose beginning preceded the call - * to call_rcu(). It also means that each CPU executing an RCU read-side - * critical section that continues beyond the start of "func()" must have - * executed a memory barrier after the call_rcu() but before the beginning - * of that RCU read-side critical section. Note that these guarantees - * include CPUs that are offline, idle, or executing in user mode, as - * well as CPUs that are executing in the kernel. - * - * Furthermore, if CPU A invoked call_rcu() and CPU B invoked the - * resulting RCU callback function "func()", then both CPU A and CPU B are - * guaranteed to execute a full memory barrier during the time interval - * between the call to call_rcu() and the invocation of "func()" -- even - * if CPU A and CPU B are the same CPU (but again only if the system has - * more than one CPU). - */ -void call_rcu(struct rcu_head *head, - rcu_callback_t func); - -#else /* #ifdef CONFIG_PREEMPT_RCU */ - -/* In classic RCU, call_rcu() is just call_rcu_sched(). */ -#define call_rcu call_rcu_sched - -#endif /* #else #ifdef CONFIG_PREEMPT_RCU */ - -/** - * call_rcu_bh() - Queue an RCU for invocation after a quicker grace period. - * @head: structure to be used for queueing the RCU updates. - * @func: actual callback function to be invoked after the grace period - * - * The callback function will be invoked some time after a full grace - * period elapses, in other words after all currently executing RCU - * read-side critical sections have completed. call_rcu_bh() assumes - * that the read-side critical sections end on completion of a softirq - * handler. This means that read-side critical sections in process - * context must not be interrupted by softirqs. This interface is to be - * used when most of the read-side critical sections are in softirq context. - * RCU read-side critical sections are delimited by : - * - rcu_read_lock() and rcu_read_unlock(), if in interrupt context. - * OR - * - rcu_read_lock_bh() and rcu_read_unlock_bh(), if in process context. - * These may be nested. - * - * See the description of call_rcu() for more detailed information on - * memory ordering guarantees. - */ -void call_rcu_bh(struct rcu_head *head, - rcu_callback_t func); - -/** - * call_rcu_sched() - Queue an RCU for invocation after sched grace period. - * @head: structure to be used for queueing the RCU updates. - * @func: actual callback function to be invoked after the grace period - * - * The callback function will be invoked some time after a full grace - * period elapses, in other words after all currently executing RCU - * read-side critical sections have completed. call_rcu_sched() assumes - * that the read-side critical sections end on enabling of preemption - * or on voluntary preemption. - * RCU read-side critical sections are delimited by : - * - rcu_read_lock_sched() and rcu_read_unlock_sched(), - * OR - * anything that disables preemption. - * These may be nested. - * - * See the description of call_rcu() for more detailed information on - * memory ordering guarantees. - */ -void call_rcu_sched(struct rcu_head *head, - rcu_callback_t func); - -void synchronize_sched(void); - -/* - * Structure allowing asynchronous waiting on RCU. - */ -struct rcu_synchronize { - struct rcu_head head; - struct completion completion; -}; -void wakeme_after_rcu(struct rcu_head *head); - -void __wait_rcu_gp(bool checktiny, int n, call_rcu_func_t *crcu_array, - struct rcu_synchronize *rs_array); - -#define _wait_rcu_gp(checktiny, ...) \ -do { \ - call_rcu_func_t __crcu_array[] = { __VA_ARGS__ }; \ - struct rcu_synchronize __rs_array[ARRAY_SIZE(__crcu_array)]; \ - __wait_rcu_gp(checktiny, ARRAY_SIZE(__crcu_array), \ - __crcu_array, __rs_array); \ -} while (0) - -#define wait_rcu_gp(...) _wait_rcu_gp(false, __VA_ARGS__) - -/** - * synchronize_rcu_mult - Wait concurrently for multiple grace periods - * @...: List of call_rcu() functions for the flavors to wait on. - * - * This macro waits concurrently for multiple flavors of RCU grace periods. - * For example, synchronize_rcu_mult(call_rcu, call_rcu_bh) would wait - * on concurrent RCU and RCU-bh grace periods. Waiting on a give SRCU - * domain requires you to write a wrapper function for that SRCU domain's - * call_srcu() function, supplying the corresponding srcu_struct. - * - * If Tiny RCU, tell _wait_rcu_gp() not to bother waiting for RCU - * or RCU-bh, given that anywhere synchronize_rcu_mult() can be called - * is automatically a grace period. - */ -#define synchronize_rcu_mult(...) \ - _wait_rcu_gp(IS_ENABLED(CONFIG_TINY_RCU), __VA_ARGS__) - -/** - * call_rcu_tasks() - Queue an RCU for invocation task-based grace period - * @head: structure to be used for queueing the RCU updates. - * @func: actual callback function to be invoked after the grace period - * - * The callback function will be invoked some time after a full grace - * period elapses, in other words after all currently executing RCU - * read-side critical sections have completed. call_rcu_tasks() assumes - * that the read-side critical sections end at a voluntary context - * switch (not a preemption!), entry into idle, or transition to usermode - * execution. As such, there are no read-side primitives analogous to - * rcu_read_lock() and rcu_read_unlock() because this primitive is intended - * to determine that all tasks have passed through a safe state, not so - * much for data-strcuture synchronization. - * - * See the description of call_rcu() for more detailed information on - * memory ordering guarantees. - */ -void call_rcu_tasks(struct rcu_head *head, rcu_callback_t func); -void synchronize_rcu_tasks(void); -void rcu_barrier_tasks(void); - -#ifdef CONFIG_PREEMPT_RCU - -void __rcu_read_lock(void); -void __rcu_read_unlock(void); -void rcu_read_unlock_special(struct task_struct *t); -void synchronize_rcu(void); - -/* - * Defined as a macro as it is a very low level header included from - * areas that don't even know about current. This gives the rcu_read_lock() - * nesting depth, but makes sense only if CONFIG_PREEMPT_RCU -- in other - * types of kernel builds, the rcu_read_lock() nesting depth is unknowable. - */ -#define rcu_preempt_depth() (current->rcu_read_lock_nesting) - -#else /* #ifdef CONFIG_PREEMPT_RCU */ - -static inline void __rcu_read_lock(void) -{ - if (IS_ENABLED(CONFIG_PREEMPT_COUNT)) - preempt_disable(); -} - -static inline void __rcu_read_unlock(void) -{ - if (IS_ENABLED(CONFIG_PREEMPT_COUNT)) - preempt_enable(); -} - -static inline void synchronize_rcu(void) -{ - synchronize_sched(); -} - -static inline int rcu_preempt_depth(void) -{ - return 0; -} - -#endif /* #else #ifdef CONFIG_PREEMPT_RCU */ - -/* Internal to kernel */ -void rcu_init(void); -void rcu_sched_qs(void); -void rcu_bh_qs(void); -void rcu_check_callbacks(int user); -void rcu_report_dead(unsigned int cpu); -void rcu_cpu_starting(unsigned int cpu); - -#ifndef CONFIG_TINY_RCU -void rcu_end_inkernel_boot(void); -#else /* #ifndef CONFIG_TINY_RCU */ -static inline void rcu_end_inkernel_boot(void) { } -#endif /* #ifndef CONFIG_TINY_RCU */ - -#ifdef CONFIG_RCU_STALL_COMMON -void rcu_sysrq_start(void); -void rcu_sysrq_end(void); -#else /* #ifdef CONFIG_RCU_STALL_COMMON */ -static inline void rcu_sysrq_start(void) -{ -} -static inline void rcu_sysrq_end(void) -{ -} -#endif /* #else #ifdef CONFIG_RCU_STALL_COMMON */ - -#ifdef CONFIG_NO_HZ_FULL -void rcu_user_enter(void); -void rcu_user_exit(void); -#else -static inline void rcu_user_enter(void) { } -static inline void rcu_user_exit(void) { } -#endif /* CONFIG_NO_HZ_FULL */ - -#ifdef CONFIG_RCU_NOCB_CPU -void rcu_init_nohz(void); -#else /* #ifdef CONFIG_RCU_NOCB_CPU */ -static inline void rcu_init_nohz(void) -{ -} -#endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */ - -/** - * RCU_NONIDLE - Indicate idle-loop code that needs RCU readers - * @a: Code that RCU needs to pay attention to. - * - * RCU, RCU-bh, and RCU-sched read-side critical sections are forbidden - * in the inner idle loop, that is, between the rcu_idle_enter() and - * the rcu_idle_exit() -- RCU will happily ignore any such read-side - * critical sections. However, things like powertop need tracepoints - * in the inner idle loop. - * - * This macro provides the way out: RCU_NONIDLE(do_something_with_RCU()) - * will tell RCU that it needs to pay attention, invoke its argument - * (in this example, calling the do_something_with_RCU() function), - * and then tell RCU to go back to ignoring this CPU. It is permissible - * to nest RCU_NONIDLE() wrappers, but not indefinitely (but the limit is - * on the order of a million or so, even on 32-bit systems). It is - * not legal to block within RCU_NONIDLE(), nor is it permissible to - * transfer control either into or out of RCU_NONIDLE()'s statement. - */ -#define RCU_NONIDLE(a) \ - do { \ - rcu_irq_enter_irqson(); \ - do { a; } while (0); \ - rcu_irq_exit_irqson(); \ - } while (0) - -/* - * Note a voluntary context switch for RCU-tasks benefit. This is a - * macro rather than an inline function to avoid #include hell. - */ -#ifdef CONFIG_TASKS_RCU -#define TASKS_RCU(x) x -extern struct srcu_struct tasks_rcu_exit_srcu; -#define rcu_note_voluntary_context_switch(t) \ - do { \ - rcu_all_qs(); \ - if (READ_ONCE((t)->rcu_tasks_holdout)) \ - WRITE_ONCE((t)->rcu_tasks_holdout, false); \ - } while (0) -#else /* #ifdef CONFIG_TASKS_RCU */ -#define TASKS_RCU(x) do { } while (0) -#define rcu_note_voluntary_context_switch(t) rcu_all_qs() -#endif /* #else #ifdef CONFIG_TASKS_RCU */ - -/** - * cond_resched_rcu_qs - Report potential quiescent states to RCU - * - * This macro resembles cond_resched(), except that it is defined to - * report potential quiescent states to RCU-tasks even if the cond_resched() - * machinery were to be shut off, as some advocate for PREEMPT kernels. - */ -#define cond_resched_rcu_qs() \ -do { \ - if (!cond_resched()) \ - rcu_note_voluntary_context_switch(current); \ -} while (0) - -#if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) || defined(CONFIG_SMP) -bool __rcu_is_watching(void); -#endif /* #if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) || defined(CONFIG_SMP) */ - -/* - * Infrastructure to implement the synchronize_() primitives in - * TREE_RCU and rcu_barrier_() primitives in TINY_RCU. - */ - -#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU) -#include -#elif defined(CONFIG_TINY_RCU) -#include -#else -#error "Unknown RCU implementation specified to kernel configuration" -#endif - -/* - * init_rcu_head_on_stack()/destroy_rcu_head_on_stack() are needed for dynamic - * initialization and destruction of rcu_head on the stack. rcu_head structures - * allocated dynamically in the heap or defined statically don't need any - * initialization. - */ -#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD -void init_rcu_head(struct rcu_head *head); -void destroy_rcu_head(struct rcu_head *head); -void init_rcu_head_on_stack(struct rcu_head *head); -void destroy_rcu_head_on_stack(struct rcu_head *head); -#else /* !CONFIG_DEBUG_OBJECTS_RCU_HEAD */ -static inline void init_rcu_head(struct rcu_head *head) -{ -} - -static inline void destroy_rcu_head(struct rcu_head *head) -{ -} - -static inline void init_rcu_head_on_stack(struct rcu_head *head) -{ -} - -static inline void destroy_rcu_head_on_stack(struct rcu_head *head) -{ -} -#endif /* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */ - -#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) -bool rcu_lockdep_current_cpu_online(void); -#else /* #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */ -static inline bool rcu_lockdep_current_cpu_online(void) -{ - return true; -} -#endif /* #else #if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_PROVE_RCU) */ - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - -static inline void rcu_lock_acquire(struct lockdep_map *map) -{ - lock_acquire(map, 0, 0, 2, 0, NULL, _THIS_IP_); -} - -static inline void rcu_lock_release(struct lockdep_map *map) -{ - lock_release(map, 1, _THIS_IP_); -} - -extern struct lockdep_map rcu_lock_map; -extern struct lockdep_map rcu_bh_lock_map; -extern struct lockdep_map rcu_sched_lock_map; -extern struct lockdep_map rcu_callback_map; -int debug_lockdep_rcu_enabled(void); - -int rcu_read_lock_held(void); -int rcu_read_lock_bh_held(void); - -/** - * rcu_read_lock_sched_held() - might we be in RCU-sched read-side critical section? - * - * If CONFIG_DEBUG_LOCK_ALLOC is selected, returns nonzero iff in an - * RCU-sched read-side critical section. In absence of - * CONFIG_DEBUG_LOCK_ALLOC, this assumes we are in an RCU-sched read-side - * critical section unless it can prove otherwise. - */ -int rcu_read_lock_sched_held(void); - -#else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ - -# define rcu_lock_acquire(a) do { } while (0) -# define rcu_lock_release(a) do { } while (0) - -static inline int rcu_read_lock_held(void) -{ - return 1; -} - -static inline int rcu_read_lock_bh_held(void) -{ - return 1; -} - -static inline int rcu_read_lock_sched_held(void) -{ - return !preemptible(); -} -#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ - -#ifdef CONFIG_PROVE_RCU - -/** - * RCU_LOCKDEP_WARN - emit lockdep splat if specified condition is met - * @c: condition to check - * @s: informative message - */ -#define RCU_LOCKDEP_WARN(c, s) \ - do { \ - static bool __section(.data.unlikely) __warned; \ - if (debug_lockdep_rcu_enabled() && !__warned && (c)) { \ - __warned = true; \ - lockdep_rcu_suspicious(__FILE__, __LINE__, s); \ - } \ - } while (0) - -#if defined(CONFIG_PROVE_RCU) && !defined(CONFIG_PREEMPT_RCU) -static inline void rcu_preempt_sleep_check(void) -{ - RCU_LOCKDEP_WARN(lock_is_held(&rcu_lock_map), - "Illegal context switch in RCU read-side critical section"); -} -#else /* #ifdef CONFIG_PROVE_RCU */ -static inline void rcu_preempt_sleep_check(void) -{ -} -#endif /* #else #ifdef CONFIG_PROVE_RCU */ - -#define rcu_sleep_check() \ - do { \ - rcu_preempt_sleep_check(); \ - RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map), \ - "Illegal context switch in RCU-bh read-side critical section"); \ - RCU_LOCKDEP_WARN(lock_is_held(&rcu_sched_lock_map), \ - "Illegal context switch in RCU-sched read-side critical section"); \ - } while (0) - -#else /* #ifdef CONFIG_PROVE_RCU */ - -#define RCU_LOCKDEP_WARN(c, s) do { } while (0) -#define rcu_sleep_check() do { } while (0) - -#endif /* #else #ifdef CONFIG_PROVE_RCU */ - -/* - * Helper functions for rcu_dereference_check(), rcu_dereference_protected() - * and rcu_assign_pointer(). Some of these could be folded into their - * callers, but they are left separate in order to ease introduction of - * multiple flavors of pointers to match the multiple flavors of RCU - * (e.g., __rcu_bh, * __rcu_sched, and __srcu), should this make sense in - * the future. - */ - -#ifdef __CHECKER__ -#define rcu_dereference_sparse(p, space) \ - ((void)(((typeof(*p) space *)p) == p)) -#else /* #ifdef __CHECKER__ */ -#define rcu_dereference_sparse(p, space) -#endif /* #else #ifdef __CHECKER__ */ - -#define __rcu_access_pointer(p, space) \ -({ \ - typeof(*p) *_________p1 = (typeof(*p) *__force)READ_ONCE(p); \ - rcu_dereference_sparse(p, space); \ - ((typeof(*p) __force __kernel *)(_________p1)); \ -}) -#define __rcu_dereference_check(p, c, space) \ -({ \ - /* Dependency order vs. p above. */ \ - typeof(*p) *________p1 = (typeof(*p) *__force)lockless_dereference(p); \ - RCU_LOCKDEP_WARN(!(c), "suspicious rcu_dereference_check() usage"); \ - rcu_dereference_sparse(p, space); \ - ((typeof(*p) __force __kernel *)(________p1)); \ -}) -#define __rcu_dereference_protected(p, c, space) \ -({ \ - RCU_LOCKDEP_WARN(!(c), "suspicious rcu_dereference_protected() usage"); \ - rcu_dereference_sparse(p, space); \ - ((typeof(*p) __force __kernel *)(p)); \ -}) -#define rcu_dereference_raw(p) \ -({ \ - /* Dependency order vs. p above. */ \ - typeof(p) ________p1 = lockless_dereference(p); \ - ((typeof(*p) __force __kernel *)(________p1)); \ -}) - -/** - * RCU_INITIALIZER() - statically initialize an RCU-protected global variable - * @v: The value to statically initialize with. - */ -#define RCU_INITIALIZER(v) (typeof(*(v)) __force __rcu *)(v) - -/** - * rcu_assign_pointer() - assign to RCU-protected pointer - * @p: pointer to assign to - * @v: value to assign (publish) - * - * Assigns the specified value to the specified RCU-protected - * pointer, ensuring that any concurrent RCU readers will see - * any prior initialization. - * - * Inserts memory barriers on architectures that require them - * (which is most of them), and also prevents the compiler from - * reordering the code that initializes the structure after the pointer - * assignment. More importantly, this call documents which pointers - * will be dereferenced by RCU read-side code. - * - * In some special cases, you may use RCU_INIT_POINTER() instead - * of rcu_assign_pointer(). RCU_INIT_POINTER() is a bit faster due - * to the fact that it does not constrain either the CPU or the compiler. - * That said, using RCU_INIT_POINTER() when you should have used - * rcu_assign_pointer() is a very bad thing that results in - * impossible-to-diagnose memory corruption. So please be careful. - * See the RCU_INIT_POINTER() comment header for details. - * - * Note that rcu_assign_pointer() evaluates each of its arguments only - * once, appearances notwithstanding. One of the "extra" evaluations - * is in typeof() and the other visible only to sparse (__CHECKER__), - * neither of which actually execute the argument. As with most cpp - * macros, this execute-arguments-only-once property is important, so - * please be careful when making changes to rcu_assign_pointer() and the - * other macros that it invokes. - */ -#define rcu_assign_pointer(p, v) \ -({ \ - uintptr_t _r_a_p__v = (uintptr_t)(v); \ - \ - if (__builtin_constant_p(v) && (_r_a_p__v) == (uintptr_t)NULL) \ - WRITE_ONCE((p), (typeof(p))(_r_a_p__v)); \ - else \ - smp_store_release(&p, RCU_INITIALIZER((typeof(p))_r_a_p__v)); \ - _r_a_p__v; \ -}) - -/** - * rcu_access_pointer() - fetch RCU pointer with no dereferencing - * @p: The pointer to read - * - * Return the value of the specified RCU-protected pointer, but omit the - * smp_read_barrier_depends() and keep the READ_ONCE(). This is useful - * when the value of this pointer is accessed, but the pointer is not - * dereferenced, for example, when testing an RCU-protected pointer against - * NULL. Although rcu_access_pointer() may also be used in cases where - * update-side locks prevent the value of the pointer from changing, you - * should instead use rcu_dereference_protected() for this use case. - * - * It is also permissible to use rcu_access_pointer() when read-side - * access to the pointer was removed at least one grace period ago, as - * is the case in the context of the RCU callback that is freeing up - * the data, or after a synchronize_rcu() returns. This can be useful - * when tearing down multi-linked structures after a grace period - * has elapsed. - */ -#define rcu_access_pointer(p) __rcu_access_pointer((p), __rcu) - -/** - * rcu_dereference_check() - rcu_dereference with debug checking - * @p: The pointer to read, prior to dereferencing - * @c: The conditions under which the dereference will take place - * - * Do an rcu_dereference(), but check that the conditions under which the - * dereference will take place are correct. Typically the conditions - * indicate the various locking conditions that should be held at that - * point. The check should return true if the conditions are satisfied. - * An implicit check for being in an RCU read-side critical section - * (rcu_read_lock()) is included. - * - * For example: - * - * bar = rcu_dereference_check(foo->bar, lockdep_is_held(&foo->lock)); - * - * could be used to indicate to lockdep that foo->bar may only be dereferenced - * if either rcu_read_lock() is held, or that the lock required to replace - * the bar struct at foo->bar is held. - * - * Note that the list of conditions may also include indications of when a lock - * need not be held, for example during initialisation or destruction of the - * target struct: - * - * bar = rcu_dereference_check(foo->bar, lockdep_is_held(&foo->lock) || - * atomic_read(&foo->usage) == 0); - * - * Inserts memory barriers on architectures that require them - * (currently only the Alpha), prevents the compiler from refetching - * (and from merging fetches), and, more importantly, documents exactly - * which pointers are protected by RCU and checks that the pointer is - * annotated as __rcu. - */ -#define rcu_dereference_check(p, c) \ - __rcu_dereference_check((p), (c) || rcu_read_lock_held(), __rcu) - -/** - * rcu_dereference_bh_check() - rcu_dereference_bh with debug checking - * @p: The pointer to read, prior to dereferencing - * @c: The conditions under which the dereference will take place - * - * This is the RCU-bh counterpart to rcu_dereference_check(). - */ -#define rcu_dereference_bh_check(p, c) \ - __rcu_dereference_check((p), (c) || rcu_read_lock_bh_held(), __rcu) - -/** - * rcu_dereference_sched_check() - rcu_dereference_sched with debug checking - * @p: The pointer to read, prior to dereferencing - * @c: The conditions under which the dereference will take place - * - * This is the RCU-sched counterpart to rcu_dereference_check(). - */ -#define rcu_dereference_sched_check(p, c) \ - __rcu_dereference_check((p), (c) || rcu_read_lock_sched_held(), \ - __rcu) - -/* - * The tracing infrastructure traces RCU (we want that), but unfortunately - * some of the RCU checks causes tracing to lock up the system. - * - * The no-tracing version of rcu_dereference_raw() must not call - * rcu_read_lock_held(). - */ -#define rcu_dereference_raw_notrace(p) __rcu_dereference_check((p), 1, __rcu) - -/** - * rcu_dereference_protected() - fetch RCU pointer when updates prevented - * @p: The pointer to read, prior to dereferencing - * @c: The conditions under which the dereference will take place - * - * Return the value of the specified RCU-protected pointer, but omit - * both the smp_read_barrier_depends() and the READ_ONCE(). This - * is useful in cases where update-side locks prevent the value of the - * pointer from changing. Please note that this primitive does -not- - * prevent the compiler from repeating this reference or combining it - * with other references, so it should not be used without protection - * of appropriate locks. - * - * This function is only for update-side use. Using this function - * when protected only by rcu_read_lock() will result in infrequent - * but very ugly failures. - */ -#define rcu_dereference_protected(p, c) \ - __rcu_dereference_protected((p), (c), __rcu) - - -/** - * rcu_dereference() - fetch RCU-protected pointer for dereferencing - * @p: The pointer to read, prior to dereferencing - * - * This is a simple wrapper around rcu_dereference_check(). - */ -#define rcu_dereference(p) rcu_dereference_check(p, 0) - -/** - * rcu_dereference_bh() - fetch an RCU-bh-protected pointer for dereferencing - * @p: The pointer to read, prior to dereferencing - * - * Makes rcu_dereference_check() do the dirty work. - */ -#define rcu_dereference_bh(p) rcu_dereference_bh_check(p, 0) - -/** - * rcu_dereference_sched() - fetch RCU-sched-protected pointer for dereferencing - * @p: The pointer to read, prior to dereferencing - * - * Makes rcu_dereference_check() do the dirty work. - */ -#define rcu_dereference_sched(p) rcu_dereference_sched_check(p, 0) - -/** - * rcu_pointer_handoff() - Hand off a pointer from RCU to other mechanism - * @p: The pointer to hand off - * - * This is simply an identity function, but it documents where a pointer - * is handed off from RCU to some other synchronization mechanism, for - * example, reference counting or locking. In C11, it would map to - * kill_dependency(). It could be used as follows: - * - * rcu_read_lock(); - * p = rcu_dereference(gp); - * long_lived = is_long_lived(p); - * if (long_lived) { - * if (!atomic_inc_not_zero(p->refcnt)) - * long_lived = false; - * else - * p = rcu_pointer_handoff(p); - * } - * rcu_read_unlock(); - */ -#define rcu_pointer_handoff(p) (p) - -/** - * rcu_read_lock() - mark the beginning of an RCU read-side critical section - * - * When synchronize_rcu() is invoked on one CPU while other CPUs - * are within RCU read-side critical sections, then the - * synchronize_rcu() is guaranteed to block until after all the other - * CPUs exit their critical sections. Similarly, if call_rcu() is invoked - * on one CPU while other CPUs are within RCU read-side critical - * sections, invocation of the corresponding RCU callback is deferred - * until after the all the other CPUs exit their critical sections. - * - * Note, however, that RCU callbacks are permitted to run concurrently - * with new RCU read-side critical sections. One way that this can happen - * is via the following sequence of events: (1) CPU 0 enters an RCU - * read-side critical section, (2) CPU 1 invokes call_rcu() to register - * an RCU callback, (3) CPU 0 exits the RCU read-side critical section, - * (4) CPU 2 enters a RCU read-side critical section, (5) the RCU - * callback is invoked. This is legal, because the RCU read-side critical - * section that was running concurrently with the call_rcu() (and which - * therefore might be referencing something that the corresponding RCU - * callback would free up) has completed before the corresponding - * RCU callback is invoked. - * - * RCU read-side critical sections may be nested. Any deferred actions - * will be deferred until the outermost RCU read-side critical section - * completes. - * - * You can avoid reading and understanding the next paragraph by - * following this rule: don't put anything in an rcu_read_lock() RCU - * read-side critical section that would block in a !PREEMPT kernel. - * But if you want the full story, read on! - * - * In non-preemptible RCU implementations (TREE_RCU and TINY_RCU), - * it is illegal to block while in an RCU read-side critical section. - * In preemptible RCU implementations (PREEMPT_RCU) in CONFIG_PREEMPT - * kernel builds, RCU read-side critical sections may be preempted, - * but explicit blocking is illegal. Finally, in preemptible RCU - * implementations in real-time (with -rt patchset) kernel builds, RCU - * read-side critical sections may be preempted and they may also block, but - * only when acquiring spinlocks that are subject to priority inheritance. - */ -static inline void rcu_read_lock(void) -{ - __rcu_read_lock(); - __acquire(RCU); - rcu_lock_acquire(&rcu_lock_map); - RCU_LOCKDEP_WARN(!rcu_is_watching(), - "rcu_read_lock() used illegally while idle"); -} - -/* - * So where is rcu_write_lock()? It does not exist, as there is no - * way for writers to lock out RCU readers. This is a feature, not - * a bug -- this property is what provides RCU's performance benefits. - * Of course, writers must coordinate with each other. The normal - * spinlock primitives work well for this, but any other technique may be - * used as well. RCU does not care how the writers keep out of each - * others' way, as long as they do so. - */ - -/** - * rcu_read_unlock() - marks the end of an RCU read-side critical section. - * - * In most situations, rcu_read_unlock() is immune from deadlock. - * However, in kernels built with CONFIG_RCU_BOOST, rcu_read_unlock() - * is responsible for deboosting, which it does via rt_mutex_unlock(). - * Unfortunately, this function acquires the scheduler's runqueue and - * priority-inheritance spinlocks. This means that deadlock could result - * if the caller of rcu_read_unlock() already holds one of these locks or - * any lock that is ever acquired while holding them; or any lock which - * can be taken from interrupt context because rcu_boost()->rt_mutex_lock() - * does not disable irqs while taking ->wait_lock. - * - * That said, RCU readers are never priority boosted unless they were - * preempted. Therefore, one way to avoid deadlock is to make sure - * that preemption never happens within any RCU read-side critical - * section whose outermost rcu_read_unlock() is called with one of - * rt_mutex_unlock()'s locks held. Such preemption can be avoided in - * a number of ways, for example, by invoking preempt_disable() before - * critical section's outermost rcu_read_lock(). - * - * Given that the set of locks acquired by rt_mutex_unlock() might change - * at any time, a somewhat more future-proofed approach is to make sure - * that that preemption never happens within any RCU read-side critical - * section whose outermost rcu_read_unlock() is called with irqs disabled. - * This approach relies on the fact that rt_mutex_unlock() currently only - * acquires irq-disabled locks. - * - * The second of these two approaches is best in most situations, - * however, the first approach can also be useful, at least to those - * developers willing to keep abreast of the set of locks acquired by - * rt_mutex_unlock(). - * - * See rcu_read_lock() for more information. - */ -static inline void rcu_read_unlock(void) -{ - RCU_LOCKDEP_WARN(!rcu_is_watching(), - "rcu_read_unlock() used illegally while idle"); - __release(RCU); - __rcu_read_unlock(); - rcu_lock_release(&rcu_lock_map); /* Keep acq info for rls diags. */ -} - -/** - * rcu_read_lock_bh() - mark the beginning of an RCU-bh critical section - * - * This is equivalent of rcu_read_lock(), but to be used when updates - * are being done using call_rcu_bh() or synchronize_rcu_bh(). Since - * both call_rcu_bh() and synchronize_rcu_bh() consider completion of a - * softirq handler to be a quiescent state, a process in RCU read-side - * critical section must be protected by disabling softirqs. Read-side - * critical sections in interrupt context can use just rcu_read_lock(), - * though this should at least be commented to avoid confusing people - * reading the code. - * - * Note that rcu_read_lock_bh() and the matching rcu_read_unlock_bh() - * must occur in the same context, for example, it is illegal to invoke - * rcu_read_unlock_bh() from one task if the matching rcu_read_lock_bh() - * was invoked from some other task. - */ -static inline void rcu_read_lock_bh(void) -{ - local_bh_disable(); - __acquire(RCU_BH); - rcu_lock_acquire(&rcu_bh_lock_map); - RCU_LOCKDEP_WARN(!rcu_is_watching(), - "rcu_read_lock_bh() used illegally while idle"); -} - -/* - * rcu_read_unlock_bh - marks the end of a softirq-only RCU critical section - * - * See rcu_read_lock_bh() for more information. - */ -static inline void rcu_read_unlock_bh(void) -{ - RCU_LOCKDEP_WARN(!rcu_is_watching(), - "rcu_read_unlock_bh() used illegally while idle"); - rcu_lock_release(&rcu_bh_lock_map); - __release(RCU_BH); - local_bh_enable(); -} - -/** - * rcu_read_lock_sched() - mark the beginning of a RCU-sched critical section - * - * This is equivalent of rcu_read_lock(), but to be used when updates - * are being done using call_rcu_sched() or synchronize_rcu_sched(). - * Read-side critical sections can also be introduced by anything that - * disables preemption, including local_irq_disable() and friends. - * - * Note that rcu_read_lock_sched() and the matching rcu_read_unlock_sched() - * must occur in the same context, for example, it is illegal to invoke - * rcu_read_unlock_sched() from process context if the matching - * rcu_read_lock_sched() was invoked from an NMI handler. - */ -static inline void rcu_read_lock_sched(void) -{ - preempt_disable(); - __acquire(RCU_SCHED); - rcu_lock_acquire(&rcu_sched_lock_map); - RCU_LOCKDEP_WARN(!rcu_is_watching(), - "rcu_read_lock_sched() used illegally while idle"); -} - -/* Used by lockdep and tracing: cannot be traced, cannot call lockdep. */ -static inline notrace void rcu_read_lock_sched_notrace(void) -{ - preempt_disable_notrace(); - __acquire(RCU_SCHED); -} - -/* - * rcu_read_unlock_sched - marks the end of a RCU-classic critical section - * - * See rcu_read_lock_sched for more information. - */ -static inline void rcu_read_unlock_sched(void) -{ - RCU_LOCKDEP_WARN(!rcu_is_watching(), - "rcu_read_unlock_sched() used illegally while idle"); - rcu_lock_release(&rcu_sched_lock_map); - __release(RCU_SCHED); - preempt_enable(); -} - -/* Used by lockdep and tracing: cannot be traced, cannot call lockdep. */ -static inline notrace void rcu_read_unlock_sched_notrace(void) -{ - __release(RCU_SCHED); - preempt_enable_notrace(); -} - -/** - * RCU_INIT_POINTER() - initialize an RCU protected pointer - * - * Initialize an RCU-protected pointer in special cases where readers - * do not need ordering constraints on the CPU or the compiler. These - * special cases are: - * - * 1. This use of RCU_INIT_POINTER() is NULLing out the pointer -or- - * 2. The caller has taken whatever steps are required to prevent - * RCU readers from concurrently accessing this pointer -or- - * 3. The referenced data structure has already been exposed to - * readers either at compile time or via rcu_assign_pointer() -and- - * a. You have not made -any- reader-visible changes to - * this structure since then -or- - * b. It is OK for readers accessing this structure from its - * new location to see the old state of the structure. (For - * example, the changes were to statistical counters or to - * other state where exact synchronization is not required.) - * - * Failure to follow these rules governing use of RCU_INIT_POINTER() will - * result in impossible-to-diagnose memory corruption. As in the structures - * will look OK in crash dumps, but any concurrent RCU readers might - * see pre-initialized values of the referenced data structure. So - * please be very careful how you use RCU_INIT_POINTER()!!! - * - * If you are creating an RCU-protected linked structure that is accessed - * by a single external-to-structure RCU-protected pointer, then you may - * use RCU_INIT_POINTER() to initialize the internal RCU-protected - * pointers, but you must use rcu_assign_pointer() to initialize the - * external-to-structure pointer -after- you have completely initialized - * the reader-accessible portions of the linked structure. - * - * Note that unlike rcu_assign_pointer(), RCU_INIT_POINTER() provides no - * ordering guarantees for either the CPU or the compiler. - */ -#define RCU_INIT_POINTER(p, v) \ - do { \ - rcu_dereference_sparse(p, __rcu); \ - WRITE_ONCE(p, RCU_INITIALIZER(v)); \ - } while (0) - -/** - * RCU_POINTER_INITIALIZER() - statically initialize an RCU protected pointer - * - * GCC-style initialization for an RCU-protected pointer in a structure field. - */ -#define RCU_POINTER_INITIALIZER(p, v) \ - .p = RCU_INITIALIZER(v) - -/* - * Does the specified offset indicate that the corresponding rcu_head - * structure can be handled by kfree_rcu()? - */ -#define __is_kfree_rcu_offset(offset) ((offset) < 4096) - -/* - * Helper macro for kfree_rcu() to prevent argument-expansion eyestrain. - */ -#define __kfree_rcu(head, offset) \ - do { \ - BUILD_BUG_ON(!__is_kfree_rcu_offset(offset)); \ - kfree_call_rcu(head, (rcu_callback_t)(unsigned long)(offset)); \ - } while (0) - -/** - * kfree_rcu() - kfree an object after a grace period. - * @ptr: pointer to kfree - * @rcu_head: the name of the struct rcu_head within the type of @ptr. - * - * Many rcu callbacks functions just call kfree() on the base structure. - * These functions are trivial, but their size adds up, and furthermore - * when they are used in a kernel module, that module must invoke the - * high-latency rcu_barrier() function at module-unload time. - * - * The kfree_rcu() function handles this issue. Rather than encoding a - * function address in the embedded rcu_head structure, kfree_rcu() instead - * encodes the offset of the rcu_head structure within the base structure. - * Because the functions are not allowed in the low-order 4096 bytes of - * kernel virtual memory, offsets up to 4095 bytes can be accommodated. - * If the offset is larger than 4095 bytes, a compile-time error will - * be generated in __kfree_rcu(). If this error is triggered, you can - * either fall back to use of call_rcu() or rearrange the structure to - * position the rcu_head structure into the first 4096 bytes. - * - * Note that the allowable offset might decrease in the future, for example, - * to allow something like kmem_cache_free_rcu(). - * - * The BUILD_BUG_ON check must not involve any function calls, hence the - * checks are done in macros here. - */ -#define kfree_rcu(ptr, rcu_head) \ - __kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head)) - -#ifdef CONFIG_TINY_RCU -static inline int rcu_needs_cpu(u64 basemono, u64 *nextevt) -{ - *nextevt = KTIME_MAX; - return 0; -} -#endif /* #ifdef CONFIG_TINY_RCU */ - -#if defined(CONFIG_RCU_NOCB_CPU_ALL) -static inline bool rcu_is_nocb_cpu(int cpu) { return true; } -#elif defined(CONFIG_RCU_NOCB_CPU) -bool rcu_is_nocb_cpu(int cpu); -#else -static inline bool rcu_is_nocb_cpu(int cpu) { return false; } -#endif - - -/* Only for use by adaptive-ticks code. */ -#ifdef CONFIG_NO_HZ_FULL_SYSIDLE -bool rcu_sys_is_idle(void); -void rcu_sysidle_force_exit(void); -#else /* #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */ - -static inline bool rcu_sys_is_idle(void) -{ - return false; -} - -static inline void rcu_sysidle_force_exit(void) -{ -} - -#endif /* #else #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */ - - -/* - * Dump the ftrace buffer, but only one time per callsite per boot. - */ -#define rcu_ftrace_dump(oops_dump_mode) \ -do { \ - static atomic_t ___rfd_beenhere = ATOMIC_INIT(0); \ - \ - if (!atomic_read(&___rfd_beenhere) && \ - !atomic_xchg(&___rfd_beenhere, 1)) \ - ftrace_dump(oops_dump_mode); \ -} while (0) - - -#endif /* __LINUX_RCUPDATE_H */ diff --git a/src/linux/include/linux/rcutiny.h b/src/linux/include/linux/rcutiny.h deleted file mode 100644 index ac81e40..0000000 --- a/src/linux/include/linux/rcutiny.h +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Read-Copy Update mechanism for mutual exclusion, the Bloatwatch edition. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you can access it online at - * http://www.gnu.org/licenses/gpl-2.0.html. - * - * Copyright IBM Corporation, 2008 - * - * Author: Paul E. McKenney - * - * For detailed explanation of Read-Copy Update mechanism see - - * Documentation/RCU - */ -#ifndef __LINUX_TINY_H -#define __LINUX_TINY_H - -#include - -static inline unsigned long get_state_synchronize_rcu(void) -{ - return 0; -} - -static inline void cond_synchronize_rcu(unsigned long oldstate) -{ - might_sleep(); -} - -static inline unsigned long get_state_synchronize_sched(void) -{ - return 0; -} - -static inline void cond_synchronize_sched(unsigned long oldstate) -{ - might_sleep(); -} - -static inline void rcu_barrier_bh(void) -{ - wait_rcu_gp(call_rcu_bh); -} - -static inline void rcu_barrier_sched(void) -{ - wait_rcu_gp(call_rcu_sched); -} - -static inline void synchronize_rcu_expedited(void) -{ - synchronize_sched(); /* Only one CPU, so pretty fast anyway!!! */ -} - -static inline void rcu_barrier(void) -{ - rcu_barrier_sched(); /* Only one CPU, so only one list of callbacks! */ -} - -static inline void synchronize_rcu_bh(void) -{ - synchronize_sched(); -} - -static inline void synchronize_rcu_bh_expedited(void) -{ - synchronize_sched(); -} - -static inline void synchronize_sched_expedited(void) -{ - synchronize_sched(); -} - -static inline void kfree_call_rcu(struct rcu_head *head, - rcu_callback_t func) -{ - call_rcu(head, func); -} - -static inline void rcu_note_context_switch(void) -{ - rcu_sched_qs(); -} - -/* - * Take advantage of the fact that there is only one CPU, which - * allows us to ignore virtualization-based context switches. - */ -static inline void rcu_virt_note_context_switch(int cpu) -{ -} - -/* - * Return the number of grace periods started. - */ -static inline unsigned long rcu_batches_started(void) -{ - return 0; -} - -/* - * Return the number of bottom-half grace periods started. - */ -static inline unsigned long rcu_batches_started_bh(void) -{ - return 0; -} - -/* - * Return the number of sched grace periods started. - */ -static inline unsigned long rcu_batches_started_sched(void) -{ - return 0; -} - -/* - * Return the number of grace periods completed. - */ -static inline unsigned long rcu_batches_completed(void) -{ - return 0; -} - -/* - * Return the number of bottom-half grace periods completed. - */ -static inline unsigned long rcu_batches_completed_bh(void) -{ - return 0; -} - -/* - * Return the number of sched grace periods completed. - */ -static inline unsigned long rcu_batches_completed_sched(void) -{ - return 0; -} - -/* - * Return the number of expedited grace periods completed. - */ -static inline unsigned long rcu_exp_batches_completed(void) -{ - return 0; -} - -/* - * Return the number of expedited sched grace periods completed. - */ -static inline unsigned long rcu_exp_batches_completed_sched(void) -{ - return 0; -} - -static inline void rcu_force_quiescent_state(void) -{ -} - -static inline void rcu_bh_force_quiescent_state(void) -{ -} - -static inline void rcu_sched_force_quiescent_state(void) -{ -} - -static inline void show_rcu_gp_kthreads(void) -{ -} - -static inline void rcu_cpu_stall_reset(void) -{ -} - -static inline void rcu_idle_enter(void) -{ -} - -static inline void rcu_idle_exit(void) -{ -} - -static inline void rcu_irq_enter(void) -{ -} - -static inline void rcu_irq_exit_irqson(void) -{ -} - -static inline void rcu_irq_enter_irqson(void) -{ -} - -static inline void rcu_irq_exit(void) -{ -} - -static inline void exit_rcu(void) -{ -} - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -extern int rcu_scheduler_active __read_mostly; -void rcu_scheduler_starting(void); -#else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ -static inline void rcu_scheduler_starting(void) -{ -} -#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ - -#if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) - -static inline bool rcu_is_watching(void) -{ - return __rcu_is_watching(); -} - -#else /* defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) */ - -static inline bool rcu_is_watching(void) -{ - return true; -} - -#endif /* #else defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) */ - -static inline void rcu_all_qs(void) -{ - barrier(); /* Avoid RCU read-side critical sections leaking across. */ -} - -/* RCUtree hotplug events */ -#define rcutree_prepare_cpu NULL -#define rcutree_online_cpu NULL -#define rcutree_offline_cpu NULL -#define rcutree_dead_cpu NULL -#define rcutree_dying_cpu NULL - -#endif /* __LINUX_RCUTINY_H */ diff --git a/src/linux/include/linux/reboot.h b/src/linux/include/linux/reboot.h deleted file mode 100644 index a7ff409..0000000 --- a/src/linux/include/linux/reboot.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef _LINUX_REBOOT_H -#define _LINUX_REBOOT_H - - -#include -#include - -#define SYS_DOWN 0x0001 /* Notify of system down */ -#define SYS_RESTART SYS_DOWN -#define SYS_HALT 0x0002 /* Notify of system halt */ -#define SYS_POWER_OFF 0x0003 /* Notify of system power off */ - -enum reboot_mode { - REBOOT_COLD = 0, - REBOOT_WARM, - REBOOT_HARD, - REBOOT_SOFT, - REBOOT_GPIO, -}; -extern enum reboot_mode reboot_mode; - -enum reboot_type { - BOOT_TRIPLE = 't', - BOOT_KBD = 'k', - BOOT_BIOS = 'b', - BOOT_ACPI = 'a', - BOOT_EFI = 'e', - BOOT_CF9_FORCE = 'p', - BOOT_CF9_SAFE = 'q', -}; -extern enum reboot_type reboot_type; - -extern int reboot_default; -extern int reboot_cpu; -extern int reboot_force; - - -extern int register_reboot_notifier(struct notifier_block *); -extern int unregister_reboot_notifier(struct notifier_block *); - -extern int register_restart_handler(struct notifier_block *); -extern int unregister_restart_handler(struct notifier_block *); -extern void do_kernel_restart(char *cmd); - -/* - * Architecture-specific implementations of sys_reboot commands. - */ - -extern void migrate_to_reboot_cpu(void); -extern void machine_restart(char *cmd); -extern void machine_halt(void); -extern void machine_power_off(void); - -extern void machine_shutdown(void); -struct pt_regs; -extern void machine_crash_shutdown(struct pt_regs *); - -/* - * Architecture independent implemenations of sys_reboot commands. - */ - -extern void kernel_restart_prepare(char *cmd); -extern void kernel_restart(char *cmd); -extern void kernel_halt(void); -extern void kernel_power_off(void); - -extern int C_A_D; /* for sysctl */ -void ctrl_alt_del(void); - -#define POWEROFF_CMD_PATH_LEN 256 -extern char poweroff_cmd[POWEROFF_CMD_PATH_LEN]; - -extern void orderly_poweroff(bool force); -extern void orderly_reboot(void); - -/* - * Emergency restart, callable from an interrupt handler. - */ - -extern void emergency_restart(void); -#include - -#endif /* _LINUX_REBOOT_H */ diff --git a/src/linux/include/linux/reciprocal_div.h b/src/linux/include/linux/reciprocal_div.h deleted file mode 100644 index 8c5a3fb..0000000 --- a/src/linux/include/linux/reciprocal_div.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _LINUX_RECIPROCAL_DIV_H -#define _LINUX_RECIPROCAL_DIV_H - -#include - -/* - * This algorithm is based on the paper "Division by Invariant - * Integers Using Multiplication" by Torbjörn Granlund and Peter - * L. Montgomery. - * - * The assembler implementation from Agner Fog, which this code is - * based on, can be found here: - * http://www.agner.org/optimize/asmlib.zip - * - * This optimization for A/B is helpful if the divisor B is mostly - * runtime invariant. The reciprocal of B is calculated in the - * slow-path with reciprocal_value(). The fast-path can then just use - * a much faster multiplication operation with a variable dividend A - * to calculate the division A/B. - */ - -struct reciprocal_value { - u32 m; - u8 sh1, sh2; -}; - -struct reciprocal_value reciprocal_value(u32 d); - -static inline u32 reciprocal_divide(u32 a, struct reciprocal_value R) -{ - u32 t = (u32)(((u64)a * R.m) >> 32); - return (t + ((a - t) >> R.sh1)) >> R.sh2; -} - -#endif /* _LINUX_RECIPROCAL_DIV_H */ diff --git a/src/linux/include/linux/regset.h b/src/linux/include/linux/regset.h deleted file mode 100644 index 8e0c9fe..0000000 --- a/src/linux/include/linux/regset.h +++ /dev/null @@ -1,375 +0,0 @@ -/* - * User-mode machine state access - * - * Copyright (C) 2007 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License v.2. - * - * Red Hat Author: Roland McGrath. - */ - -#ifndef _LINUX_REGSET_H -#define _LINUX_REGSET_H 1 - -#include -#include -#include -#include -struct task_struct; -struct user_regset; - - -/** - * user_regset_active_fn - type of @active function in &struct user_regset - * @target: thread being examined - * @regset: regset being examined - * - * Return -%ENODEV if not available on the hardware found. - * Return %0 if no interesting state in this thread. - * Return >%0 number of @size units of interesting state. - * Any get call fetching state beyond that number will - * see the default initialization state for this data, - * so a caller that knows what the default state is need - * not copy it all out. - * This call is optional; the pointer is %NULL if there - * is no inexpensive check to yield a value < @n. - */ -typedef int user_regset_active_fn(struct task_struct *target, - const struct user_regset *regset); - -/** - * user_regset_get_fn - type of @get function in &struct user_regset - * @target: thread being examined - * @regset: regset being examined - * @pos: offset into the regset data to access, in bytes - * @count: amount of data to copy, in bytes - * @kbuf: if not %NULL, a kernel-space pointer to copy into - * @ubuf: if @kbuf is %NULL, a user-space pointer to copy into - * - * Fetch register values. Return %0 on success; -%EIO or -%ENODEV - * are usual failure returns. The @pos and @count values are in - * bytes, but must be properly aligned. If @kbuf is non-null, that - * buffer is used and @ubuf is ignored. If @kbuf is %NULL, then - * ubuf gives a userland pointer to access directly, and an -%EFAULT - * return value is possible. - */ -typedef int user_regset_get_fn(struct task_struct *target, - const struct user_regset *regset, - unsigned int pos, unsigned int count, - void *kbuf, void __user *ubuf); - -/** - * user_regset_set_fn - type of @set function in &struct user_regset - * @target: thread being examined - * @regset: regset being examined - * @pos: offset into the regset data to access, in bytes - * @count: amount of data to copy, in bytes - * @kbuf: if not %NULL, a kernel-space pointer to copy from - * @ubuf: if @kbuf is %NULL, a user-space pointer to copy from - * - * Store register values. Return %0 on success; -%EIO or -%ENODEV - * are usual failure returns. The @pos and @count values are in - * bytes, but must be properly aligned. If @kbuf is non-null, that - * buffer is used and @ubuf is ignored. If @kbuf is %NULL, then - * ubuf gives a userland pointer to access directly, and an -%EFAULT - * return value is possible. - */ -typedef int user_regset_set_fn(struct task_struct *target, - const struct user_regset *regset, - unsigned int pos, unsigned int count, - const void *kbuf, const void __user *ubuf); - -/** - * user_regset_writeback_fn - type of @writeback function in &struct user_regset - * @target: thread being examined - * @regset: regset being examined - * @immediate: zero if writeback at completion of next context switch is OK - * - * This call is optional; usually the pointer is %NULL. When - * provided, there is some user memory associated with this regset's - * hardware, such as memory backing cached register data on register - * window machines; the regset's data controls what user memory is - * used (e.g. via the stack pointer value). - * - * Write register data back to user memory. If the @immediate flag - * is nonzero, it must be written to the user memory so uaccess or - * access_process_vm() can see it when this call returns; if zero, - * then it must be written back by the time the task completes a - * context switch (as synchronized with wait_task_inactive()). - * Return %0 on success or if there was nothing to do, -%EFAULT for - * a memory problem (bad stack pointer or whatever), or -%EIO for a - * hardware problem. - */ -typedef int user_regset_writeback_fn(struct task_struct *target, - const struct user_regset *regset, - int immediate); - -/** - * struct user_regset - accessible thread CPU state - * @n: Number of slots (registers). - * @size: Size in bytes of a slot (register). - * @align: Required alignment, in bytes. - * @bias: Bias from natural indexing. - * @core_note_type: ELF note @n_type value used in core dumps. - * @get: Function to fetch values. - * @set: Function to store values. - * @active: Function to report if regset is active, or %NULL. - * @writeback: Function to write data back to user memory, or %NULL. - * - * This data structure describes a machine resource we call a register set. - * This is part of the state of an individual thread, not necessarily - * actual CPU registers per se. A register set consists of a number of - * similar slots, given by @n. Each slot is @size bytes, and aligned to - * @align bytes (which is at least @size). - * - * These functions must be called only on the current thread or on a - * thread that is in %TASK_STOPPED or %TASK_TRACED state, that we are - * guaranteed will not be woken up and return to user mode, and that we - * have called wait_task_inactive() on. (The target thread always might - * wake up for SIGKILL while these functions are working, in which case - * that thread's user_regset state might be scrambled.) - * - * The @pos argument must be aligned according to @align; the @count - * argument must be a multiple of @size. These functions are not - * responsible for checking for invalid arguments. - * - * When there is a natural value to use as an index, @bias gives the - * difference between the natural index and the slot index for the - * register set. For example, x86 GDT segment descriptors form a regset; - * the segment selector produces a natural index, but only a subset of - * that index space is available as a regset (the TLS slots); subtracting - * @bias from a segment selector index value computes the regset slot. - * - * If nonzero, @core_note_type gives the n_type field (NT_* value) - * of the core file note in which this regset's data appears. - * NT_PRSTATUS is a special case in that the regset data starts at - * offsetof(struct elf_prstatus, pr_reg) into the note data; that is - * part of the per-machine ELF formats userland knows about. In - * other cases, the core file note contains exactly the whole regset - * (@n * @size) and nothing else. The core file note is normally - * omitted when there is an @active function and it returns zero. - */ -struct user_regset { - user_regset_get_fn *get; - user_regset_set_fn *set; - user_regset_active_fn *active; - user_regset_writeback_fn *writeback; - unsigned int n; - unsigned int size; - unsigned int align; - unsigned int bias; - unsigned int core_note_type; -}; - -/** - * struct user_regset_view - available regsets - * @name: Identifier, e.g. UTS_MACHINE string. - * @regsets: Array of @n regsets available in this view. - * @n: Number of elements in @regsets. - * @e_machine: ELF header @e_machine %EM_* value written in core dumps. - * @e_flags: ELF header @e_flags value written in core dumps. - * @ei_osabi: ELF header @e_ident[%EI_OSABI] value written in core dumps. - * - * A regset view is a collection of regsets (&struct user_regset, - * above). This describes all the state of a thread that can be seen - * from a given architecture/ABI environment. More than one view might - * refer to the same &struct user_regset, or more than one regset - * might refer to the same machine-specific state in the thread. For - * example, a 32-bit thread's state could be examined from the 32-bit - * view or from the 64-bit view. Either method reaches the same thread - * register state, doing appropriate widening or truncation. - */ -struct user_regset_view { - const char *name; - const struct user_regset *regsets; - unsigned int n; - u32 e_flags; - u16 e_machine; - u8 ei_osabi; -}; - -/* - * This is documented here rather than at the definition sites because its - * implementation is machine-dependent but its interface is universal. - */ -/** - * task_user_regset_view - Return the process's native regset view. - * @tsk: a thread of the process in question - * - * Return the &struct user_regset_view that is native for the given process. - * For example, what it would access when it called ptrace(). - * Throughout the life of the process, this only changes at exec. - */ -const struct user_regset_view *task_user_regset_view(struct task_struct *tsk); - - -/* - * These are helpers for writing regset get/set functions in arch code. - * Because @start_pos and @end_pos are always compile-time constants, - * these are inlined into very little code though they look large. - * - * Use one or more calls sequentially for each chunk of regset data stored - * contiguously in memory. Call with constants for @start_pos and @end_pos, - * giving the range of byte positions in the regset that data corresponds - * to; @end_pos can be -1 if this chunk is at the end of the regset layout. - * Each call updates the arguments to point past its chunk. - */ - -static inline int user_regset_copyout(unsigned int *pos, unsigned int *count, - void **kbuf, - void __user **ubuf, const void *data, - const int start_pos, const int end_pos) -{ - if (*count == 0) - return 0; - BUG_ON(*pos < start_pos); - if (end_pos < 0 || *pos < end_pos) { - unsigned int copy = (end_pos < 0 ? *count - : min(*count, end_pos - *pos)); - data += *pos - start_pos; - if (*kbuf) { - memcpy(*kbuf, data, copy); - *kbuf += copy; - } else if (__copy_to_user(*ubuf, data, copy)) - return -EFAULT; - else - *ubuf += copy; - *pos += copy; - *count -= copy; - } - return 0; -} - -static inline int user_regset_copyin(unsigned int *pos, unsigned int *count, - const void **kbuf, - const void __user **ubuf, void *data, - const int start_pos, const int end_pos) -{ - if (*count == 0) - return 0; - BUG_ON(*pos < start_pos); - if (end_pos < 0 || *pos < end_pos) { - unsigned int copy = (end_pos < 0 ? *count - : min(*count, end_pos - *pos)); - data += *pos - start_pos; - if (*kbuf) { - memcpy(data, *kbuf, copy); - *kbuf += copy; - } else if (__copy_from_user(data, *ubuf, copy)) - return -EFAULT; - else - *ubuf += copy; - *pos += copy; - *count -= copy; - } - return 0; -} - -/* - * These two parallel the two above, but for portions of a regset layout - * that always read as all-zero or for which writes are ignored. - */ -static inline int user_regset_copyout_zero(unsigned int *pos, - unsigned int *count, - void **kbuf, void __user **ubuf, - const int start_pos, - const int end_pos) -{ - if (*count == 0) - return 0; - BUG_ON(*pos < start_pos); - if (end_pos < 0 || *pos < end_pos) { - unsigned int copy = (end_pos < 0 ? *count - : min(*count, end_pos - *pos)); - if (*kbuf) { - memset(*kbuf, 0, copy); - *kbuf += copy; - } else if (__clear_user(*ubuf, copy)) - return -EFAULT; - else - *ubuf += copy; - *pos += copy; - *count -= copy; - } - return 0; -} - -static inline int user_regset_copyin_ignore(unsigned int *pos, - unsigned int *count, - const void **kbuf, - const void __user **ubuf, - const int start_pos, - const int end_pos) -{ - if (*count == 0) - return 0; - BUG_ON(*pos < start_pos); - if (end_pos < 0 || *pos < end_pos) { - unsigned int copy = (end_pos < 0 ? *count - : min(*count, end_pos - *pos)); - if (*kbuf) - *kbuf += copy; - else - *ubuf += copy; - *pos += copy; - *count -= copy; - } - return 0; -} - -/** - * copy_regset_to_user - fetch a thread's user_regset data into user memory - * @target: thread to be examined - * @view: &struct user_regset_view describing user thread machine state - * @setno: index in @view->regsets - * @offset: offset into the regset data, in bytes - * @size: amount of data to copy, in bytes - * @data: user-mode pointer to copy into - */ -static inline int copy_regset_to_user(struct task_struct *target, - const struct user_regset_view *view, - unsigned int setno, - unsigned int offset, unsigned int size, - void __user *data) -{ - const struct user_regset *regset = &view->regsets[setno]; - - if (!regset->get) - return -EOPNOTSUPP; - - if (!access_ok(VERIFY_WRITE, data, size)) - return -EFAULT; - - return regset->get(target, regset, offset, size, NULL, data); -} - -/** - * copy_regset_from_user - store into thread's user_regset data from user memory - * @target: thread to be examined - * @view: &struct user_regset_view describing user thread machine state - * @setno: index in @view->regsets - * @offset: offset into the regset data, in bytes - * @size: amount of data to copy, in bytes - * @data: user-mode pointer to copy from - */ -static inline int copy_regset_from_user(struct task_struct *target, - const struct user_regset_view *view, - unsigned int setno, - unsigned int offset, unsigned int size, - const void __user *data) -{ - const struct user_regset *regset = &view->regsets[setno]; - - if (!regset->set) - return -EOPNOTSUPP; - - if (!access_ok(VERIFY_READ, data, size)) - return -EFAULT; - - return regset->set(target, regset, offset, size, NULL, data); -} - - -#endif /* */ diff --git a/src/linux/include/linux/relay.h b/src/linux/include/linux/relay.h deleted file mode 100644 index 68c1448..0000000 --- a/src/linux/include/linux/relay.h +++ /dev/null @@ -1,299 +0,0 @@ -/* - * linux/include/linux/relay.h - * - * Copyright (C) 2002, 2003 - Tom Zanussi (zanussi@us.ibm.com), IBM Corp - * Copyright (C) 1999, 2000, 2001, 2002 - Karim Yaghmour (karim@opersys.com) - * - * CONFIG_RELAY definitions and declarations - */ - -#ifndef _LINUX_RELAY_H -#define _LINUX_RELAY_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Tracks changes to rchan/rchan_buf structs - */ -#define RELAYFS_CHANNEL_VERSION 7 - -/* - * Per-cpu relay channel buffer - */ -struct rchan_buf -{ - void *start; /* start of channel buffer */ - void *data; /* start of current sub-buffer */ - size_t offset; /* current offset into sub-buffer */ - size_t subbufs_produced; /* count of sub-buffers produced */ - size_t subbufs_consumed; /* count of sub-buffers consumed */ - struct rchan *chan; /* associated channel */ - wait_queue_head_t read_wait; /* reader wait queue */ - struct irq_work wakeup_work; /* reader wakeup */ - struct dentry *dentry; /* channel file dentry */ - struct kref kref; /* channel buffer refcount */ - struct page **page_array; /* array of current buffer pages */ - unsigned int page_count; /* number of current buffer pages */ - unsigned int finalized; /* buffer has been finalized */ - size_t *padding; /* padding counts per sub-buffer */ - size_t prev_padding; /* temporary variable */ - size_t bytes_consumed; /* bytes consumed in cur read subbuf */ - size_t early_bytes; /* bytes consumed before VFS inited */ - unsigned int cpu; /* this buf's cpu */ -} ____cacheline_aligned; - -/* - * Relay channel data structure - */ -struct rchan -{ - u32 version; /* the version of this struct */ - size_t subbuf_size; /* sub-buffer size */ - size_t n_subbufs; /* number of sub-buffers per buffer */ - size_t alloc_size; /* total buffer size allocated */ - struct rchan_callbacks *cb; /* client callbacks */ - struct kref kref; /* channel refcount */ - void *private_data; /* for user-defined data */ - size_t last_toobig; /* tried to log event > subbuf size */ - struct rchan_buf ** __percpu buf; /* per-cpu channel buffers */ - int is_global; /* One global buffer ? */ - struct list_head list; /* for channel list */ - struct dentry *parent; /* parent dentry passed to open */ - int has_base_filename; /* has a filename associated? */ - char base_filename[NAME_MAX]; /* saved base filename */ -}; - -/* - * Relay channel client callbacks - */ -struct rchan_callbacks -{ - /* - * subbuf_start - called on buffer-switch to a new sub-buffer - * @buf: the channel buffer containing the new sub-buffer - * @subbuf: the start of the new sub-buffer - * @prev_subbuf: the start of the previous sub-buffer - * @prev_padding: unused space at the end of previous sub-buffer - * - * The client should return 1 to continue logging, 0 to stop - * logging. - * - * NOTE: subbuf_start will also be invoked when the buffer is - * created, so that the first sub-buffer can be initialized - * if necessary. In this case, prev_subbuf will be NULL. - * - * NOTE: the client can reserve bytes at the beginning of the new - * sub-buffer by calling subbuf_start_reserve() in this callback. - */ - int (*subbuf_start) (struct rchan_buf *buf, - void *subbuf, - void *prev_subbuf, - size_t prev_padding); - - /* - * buf_mapped - relay buffer mmap notification - * @buf: the channel buffer - * @filp: relay file pointer - * - * Called when a relay file is successfully mmapped - */ - void (*buf_mapped)(struct rchan_buf *buf, - struct file *filp); - - /* - * buf_unmapped - relay buffer unmap notification - * @buf: the channel buffer - * @filp: relay file pointer - * - * Called when a relay file is successfully unmapped - */ - void (*buf_unmapped)(struct rchan_buf *buf, - struct file *filp); - /* - * create_buf_file - create file to represent a relay channel buffer - * @filename: the name of the file to create - * @parent: the parent of the file to create - * @mode: the mode of the file to create - * @buf: the channel buffer - * @is_global: outparam - set non-zero if the buffer should be global - * - * Called during relay_open(), once for each per-cpu buffer, - * to allow the client to create a file to be used to - * represent the corresponding channel buffer. If the file is - * created outside of relay, the parent must also exist in - * that filesystem. - * - * The callback should return the dentry of the file created - * to represent the relay buffer. - * - * Setting the is_global outparam to a non-zero value will - * cause relay_open() to create a single global buffer rather - * than the default set of per-cpu buffers. - * - * See Documentation/filesystems/relay.txt for more info. - */ - struct dentry *(*create_buf_file)(const char *filename, - struct dentry *parent, - umode_t mode, - struct rchan_buf *buf, - int *is_global); - - /* - * remove_buf_file - remove file representing a relay channel buffer - * @dentry: the dentry of the file to remove - * - * Called during relay_close(), once for each per-cpu buffer, - * to allow the client to remove a file used to represent a - * channel buffer. - * - * The callback should return 0 if successful, negative if not. - */ - int (*remove_buf_file)(struct dentry *dentry); -}; - -/* - * CONFIG_RELAY kernel API, kernel/relay.c - */ - -struct rchan *relay_open(const char *base_filename, - struct dentry *parent, - size_t subbuf_size, - size_t n_subbufs, - struct rchan_callbacks *cb, - void *private_data); -extern int relay_late_setup_files(struct rchan *chan, - const char *base_filename, - struct dentry *parent); -extern void relay_close(struct rchan *chan); -extern void relay_flush(struct rchan *chan); -extern void relay_subbufs_consumed(struct rchan *chan, - unsigned int cpu, - size_t consumed); -extern void relay_reset(struct rchan *chan); -extern int relay_buf_full(struct rchan_buf *buf); - -extern size_t relay_switch_subbuf(struct rchan_buf *buf, - size_t length); - -/** - * relay_write - write data into the channel - * @chan: relay channel - * @data: data to be written - * @length: number of bytes to write - * - * Writes data into the current cpu's channel buffer. - * - * Protects the buffer by disabling interrupts. Use this - * if you might be logging from interrupt context. Try - * __relay_write() if you know you won't be logging from - * interrupt context. - */ -static inline void relay_write(struct rchan *chan, - const void *data, - size_t length) -{ - unsigned long flags; - struct rchan_buf *buf; - - local_irq_save(flags); - buf = *this_cpu_ptr(chan->buf); - if (unlikely(buf->offset + length > chan->subbuf_size)) - length = relay_switch_subbuf(buf, length); - memcpy(buf->data + buf->offset, data, length); - buf->offset += length; - local_irq_restore(flags); -} - -/** - * __relay_write - write data into the channel - * @chan: relay channel - * @data: data to be written - * @length: number of bytes to write - * - * Writes data into the current cpu's channel buffer. - * - * Protects the buffer by disabling preemption. Use - * relay_write() if you might be logging from interrupt - * context. - */ -static inline void __relay_write(struct rchan *chan, - const void *data, - size_t length) -{ - struct rchan_buf *buf; - - buf = *get_cpu_ptr(chan->buf); - if (unlikely(buf->offset + length > buf->chan->subbuf_size)) - length = relay_switch_subbuf(buf, length); - memcpy(buf->data + buf->offset, data, length); - buf->offset += length; - put_cpu_ptr(chan->buf); -} - -/** - * relay_reserve - reserve slot in channel buffer - * @chan: relay channel - * @length: number of bytes to reserve - * - * Returns pointer to reserved slot, NULL if full. - * - * Reserves a slot in the current cpu's channel buffer. - * Does not protect the buffer at all - caller must provide - * appropriate synchronization. - */ -static inline void *relay_reserve(struct rchan *chan, size_t length) -{ - void *reserved = NULL; - struct rchan_buf *buf = *get_cpu_ptr(chan->buf); - - if (unlikely(buf->offset + length > buf->chan->subbuf_size)) { - length = relay_switch_subbuf(buf, length); - if (!length) - goto end; - } - reserved = buf->data + buf->offset; - buf->offset += length; - -end: - put_cpu_ptr(chan->buf); - return reserved; -} - -/** - * subbuf_start_reserve - reserve bytes at the start of a sub-buffer - * @buf: relay channel buffer - * @length: number of bytes to reserve - * - * Helper function used to reserve bytes at the beginning of - * a sub-buffer in the subbuf_start() callback. - */ -static inline void subbuf_start_reserve(struct rchan_buf *buf, - size_t length) -{ - BUG_ON(length >= buf->chan->subbuf_size - 1); - buf->offset = length; -} - -/* - * exported relay file operations, kernel/relay.c - */ -extern const struct file_operations relay_file_operations; - -#ifdef CONFIG_RELAY -int relay_prepare_cpu(unsigned int cpu); -#else -#define relay_prepare_cpu NULL -#endif - -#endif /* _LINUX_RELAY_H */ - diff --git a/src/linux/include/linux/resource.h b/src/linux/include/linux/resource.h deleted file mode 100644 index 5bc3116..0000000 --- a/src/linux/include/linux/resource.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _LINUX_RESOURCE_H -#define _LINUX_RESOURCE_H - -#include - - -struct task_struct; - -int getrusage(struct task_struct *p, int who, struct rusage __user *ru); -int do_prlimit(struct task_struct *tsk, unsigned int resource, - struct rlimit *new_rlim, struct rlimit *old_rlim); - -#endif diff --git a/src/linux/include/linux/resource_ext.h b/src/linux/include/linux/resource_ext.h deleted file mode 100644 index e2bf63d..0000000 --- a/src/linux/include/linux/resource_ext.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2015, Intel Corporation - * Author: Jiang Liu - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ -#ifndef _LINUX_RESOURCE_EXT_H -#define _LINUX_RESOURCE_EXT_H -#include -#include -#include -#include - -/* Represent resource window for bridge devices */ -struct resource_win { - struct resource res; /* In master (CPU) address space */ - resource_size_t offset; /* Translation offset for bridge */ -}; - -/* - * Common resource list management data structure and interfaces to support - * ACPI, PNP and PCI host bridge etc. - */ -struct resource_entry { - struct list_head node; - struct resource *res; /* In master (CPU) address space */ - resource_size_t offset; /* Translation offset for bridge */ - struct resource __res; /* Default storage for res */ -}; - -extern struct resource_entry * -resource_list_create_entry(struct resource *res, size_t extra_size); -extern void resource_list_free(struct list_head *head); - -static inline void resource_list_add(struct resource_entry *entry, - struct list_head *head) -{ - list_add(&entry->node, head); -} - -static inline void resource_list_add_tail(struct resource_entry *entry, - struct list_head *head) -{ - list_add_tail(&entry->node, head); -} - -static inline void resource_list_del(struct resource_entry *entry) -{ - list_del(&entry->node); -} - -static inline void resource_list_free_entry(struct resource_entry *entry) -{ - kfree(entry); -} - -static inline void -resource_list_destroy_entry(struct resource_entry *entry) -{ - resource_list_del(entry); - resource_list_free_entry(entry); -} - -#define resource_list_for_each_entry(entry, list) \ - list_for_each_entry((entry), (list), node) - -#define resource_list_for_each_entry_safe(entry, tmp, list) \ - list_for_each_entry_safe((entry), (tmp), (list), node) - -#endif /* _LINUX_RESOURCE_EXT_H */ diff --git a/src/linux/include/linux/rhashtable.h b/src/linux/include/linux/rhashtable.h deleted file mode 100644 index 5c132d3..0000000 --- a/src/linux/include/linux/rhashtable.h +++ /dev/null @@ -1,1224 +0,0 @@ -/* - * Resizable, Scalable, Concurrent Hash Table - * - * Copyright (c) 2015-2016 Herbert Xu - * Copyright (c) 2014-2015 Thomas Graf - * Copyright (c) 2008-2014 Patrick McHardy - * - * Code partially derived from nft_hash - * Rewritten with rehash code from br_multicast plus single list - * pointer as suggested by Josh Triplett - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#ifndef _LINUX_RHASHTABLE_H -#define _LINUX_RHASHTABLE_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * The end of the chain is marked with a special nulls marks which has - * the following format: - * - * +-------+-----------------------------------------------------+-+ - * | Base | Hash |1| - * +-------+-----------------------------------------------------+-+ - * - * Base (4 bits) : Reserved to distinguish between multiple tables. - * Specified via &struct rhashtable_params.nulls_base. - * Hash (27 bits): Full hash (unmasked) of first element added to bucket - * 1 (1 bit) : Nulls marker (always set) - * - * The remaining bits of the next pointer remain unused for now. - */ -#define RHT_BASE_BITS 4 -#define RHT_HASH_BITS 27 -#define RHT_BASE_SHIFT RHT_HASH_BITS - -/* Base bits plus 1 bit for nulls marker */ -#define RHT_HASH_RESERVED_SPACE (RHT_BASE_BITS + 1) - -struct rhash_head { - struct rhash_head __rcu *next; -}; - -struct rhlist_head { - struct rhash_head rhead; - struct rhlist_head __rcu *next; -}; - -/** - * struct bucket_table - Table of hash buckets - * @size: Number of hash buckets - * @rehash: Current bucket being rehashed - * @hash_rnd: Random seed to fold into hash - * @locks_mask: Mask to apply before accessing locks[] - * @locks: Array of spinlocks protecting individual buckets - * @walkers: List of active walkers - * @rcu: RCU structure for freeing the table - * @future_tbl: Table under construction during rehashing - * @buckets: size * hash buckets - */ -struct bucket_table { - unsigned int size; - unsigned int rehash; - u32 hash_rnd; - unsigned int locks_mask; - spinlock_t *locks; - struct list_head walkers; - struct rcu_head rcu; - - struct bucket_table __rcu *future_tbl; - - struct rhash_head __rcu *buckets[] ____cacheline_aligned_in_smp; -}; - -/** - * struct rhashtable_compare_arg - Key for the function rhashtable_compare - * @ht: Hash table - * @key: Key to compare against - */ -struct rhashtable_compare_arg { - struct rhashtable *ht; - const void *key; -}; - -typedef u32 (*rht_hashfn_t)(const void *data, u32 len, u32 seed); -typedef u32 (*rht_obj_hashfn_t)(const void *data, u32 len, u32 seed); -typedef int (*rht_obj_cmpfn_t)(struct rhashtable_compare_arg *arg, - const void *obj); - -struct rhashtable; - -/** - * struct rhashtable_params - Hash table construction parameters - * @nelem_hint: Hint on number of elements, should be 75% of desired size - * @key_len: Length of key - * @key_offset: Offset of key in struct to be hashed - * @head_offset: Offset of rhash_head in struct to be hashed - * @insecure_max_entries: Maximum number of entries (may be exceeded) - * @max_size: Maximum size while expanding - * @min_size: Minimum size while shrinking - * @nulls_base: Base value to generate nulls marker - * @insecure_elasticity: Set to true to disable chain length checks - * @automatic_shrinking: Enable automatic shrinking of tables - * @locks_mul: Number of bucket locks to allocate per cpu (default: 128) - * @hashfn: Hash function (default: jhash2 if !(key_len % 4), or jhash) - * @obj_hashfn: Function to hash object - * @obj_cmpfn: Function to compare key with object - */ -struct rhashtable_params { - size_t nelem_hint; - size_t key_len; - size_t key_offset; - size_t head_offset; - unsigned int insecure_max_entries; - unsigned int max_size; - unsigned int min_size; - u32 nulls_base; - bool insecure_elasticity; - bool automatic_shrinking; - size_t locks_mul; - rht_hashfn_t hashfn; - rht_obj_hashfn_t obj_hashfn; - rht_obj_cmpfn_t obj_cmpfn; -}; - -/** - * struct rhashtable - Hash table handle - * @tbl: Bucket table - * @nelems: Number of elements in table - * @key_len: Key length for hashfn - * @elasticity: Maximum chain length before rehash - * @p: Configuration parameters - * @rhlist: True if this is an rhltable - * @run_work: Deferred worker to expand/shrink asynchronously - * @mutex: Mutex to protect current/future table swapping - * @lock: Spin lock to protect walker list - */ -struct rhashtable { - struct bucket_table __rcu *tbl; - atomic_t nelems; - unsigned int key_len; - unsigned int elasticity; - struct rhashtable_params p; - bool rhlist; - struct work_struct run_work; - struct mutex mutex; - spinlock_t lock; -}; - -/** - * struct rhltable - Hash table with duplicate objects in a list - * @ht: Underlying rhtable - */ -struct rhltable { - struct rhashtable ht; -}; - -/** - * struct rhashtable_walker - Hash table walker - * @list: List entry on list of walkers - * @tbl: The table that we were walking over - */ -struct rhashtable_walker { - struct list_head list; - struct bucket_table *tbl; -}; - -/** - * struct rhashtable_iter - Hash table iterator - * @ht: Table to iterate through - * @p: Current pointer - * @list: Current hash list pointer - * @walker: Associated rhashtable walker - * @slot: Current slot - * @skip: Number of entries to skip in slot - */ -struct rhashtable_iter { - struct rhashtable *ht; - struct rhash_head *p; - struct rhlist_head *list; - struct rhashtable_walker walker; - unsigned int slot; - unsigned int skip; -}; - -static inline unsigned long rht_marker(const struct rhashtable *ht, u32 hash) -{ - return NULLS_MARKER(ht->p.nulls_base + hash); -} - -#define INIT_RHT_NULLS_HEAD(ptr, ht, hash) \ - ((ptr) = (typeof(ptr)) rht_marker(ht, hash)) - -static inline bool rht_is_a_nulls(const struct rhash_head *ptr) -{ - return ((unsigned long) ptr & 1); -} - -static inline unsigned long rht_get_nulls_value(const struct rhash_head *ptr) -{ - return ((unsigned long) ptr) >> 1; -} - -static inline void *rht_obj(const struct rhashtable *ht, - const struct rhash_head *he) -{ - return (char *)he - ht->p.head_offset; -} - -static inline unsigned int rht_bucket_index(const struct bucket_table *tbl, - unsigned int hash) -{ - return (hash >> RHT_HASH_RESERVED_SPACE) & (tbl->size - 1); -} - -static inline unsigned int rht_key_hashfn( - struct rhashtable *ht, const struct bucket_table *tbl, - const void *key, const struct rhashtable_params params) -{ - unsigned int hash; - - /* params must be equal to ht->p if it isn't constant. */ - if (!__builtin_constant_p(params.key_len)) - hash = ht->p.hashfn(key, ht->key_len, tbl->hash_rnd); - else if (params.key_len) { - unsigned int key_len = params.key_len; - - if (params.hashfn) - hash = params.hashfn(key, key_len, tbl->hash_rnd); - else if (key_len & (sizeof(u32) - 1)) - hash = jhash(key, key_len, tbl->hash_rnd); - else - hash = jhash2(key, key_len / sizeof(u32), - tbl->hash_rnd); - } else { - unsigned int key_len = ht->p.key_len; - - if (params.hashfn) - hash = params.hashfn(key, key_len, tbl->hash_rnd); - else - hash = jhash(key, key_len, tbl->hash_rnd); - } - - return rht_bucket_index(tbl, hash); -} - -static inline unsigned int rht_head_hashfn( - struct rhashtable *ht, const struct bucket_table *tbl, - const struct rhash_head *he, const struct rhashtable_params params) -{ - const char *ptr = rht_obj(ht, he); - - return likely(params.obj_hashfn) ? - rht_bucket_index(tbl, params.obj_hashfn(ptr, params.key_len ?: - ht->p.key_len, - tbl->hash_rnd)) : - rht_key_hashfn(ht, tbl, ptr + params.key_offset, params); -} - -/** - * rht_grow_above_75 - returns true if nelems > 0.75 * table-size - * @ht: hash table - * @tbl: current table - */ -static inline bool rht_grow_above_75(const struct rhashtable *ht, - const struct bucket_table *tbl) -{ - /* Expand table when exceeding 75% load */ - return atomic_read(&ht->nelems) > (tbl->size / 4 * 3) && - (!ht->p.max_size || tbl->size < ht->p.max_size); -} - -/** - * rht_shrink_below_30 - returns true if nelems < 0.3 * table-size - * @ht: hash table - * @tbl: current table - */ -static inline bool rht_shrink_below_30(const struct rhashtable *ht, - const struct bucket_table *tbl) -{ - /* Shrink table beneath 30% load */ - return atomic_read(&ht->nelems) < (tbl->size * 3 / 10) && - tbl->size > ht->p.min_size; -} - -/** - * rht_grow_above_100 - returns true if nelems > table-size - * @ht: hash table - * @tbl: current table - */ -static inline bool rht_grow_above_100(const struct rhashtable *ht, - const struct bucket_table *tbl) -{ - return atomic_read(&ht->nelems) > tbl->size && - (!ht->p.max_size || tbl->size < ht->p.max_size); -} - -/** - * rht_grow_above_max - returns true if table is above maximum - * @ht: hash table - * @tbl: current table - */ -static inline bool rht_grow_above_max(const struct rhashtable *ht, - const struct bucket_table *tbl) -{ - return ht->p.insecure_max_entries && - atomic_read(&ht->nelems) >= ht->p.insecure_max_entries; -} - -/* The bucket lock is selected based on the hash and protects mutations - * on a group of hash buckets. - * - * A maximum of tbl->size/2 bucket locks is allocated. This ensures that - * a single lock always covers both buckets which may both contains - * entries which link to the same bucket of the old table during resizing. - * This allows to simplify the locking as locking the bucket in both - * tables during resize always guarantee protection. - * - * IMPORTANT: When holding the bucket lock of both the old and new table - * during expansions and shrinking, the old bucket lock must always be - * acquired first. - */ -static inline spinlock_t *rht_bucket_lock(const struct bucket_table *tbl, - unsigned int hash) -{ - return &tbl->locks[hash & tbl->locks_mask]; -} - -#ifdef CONFIG_PROVE_LOCKING -int lockdep_rht_mutex_is_held(struct rhashtable *ht); -int lockdep_rht_bucket_is_held(const struct bucket_table *tbl, u32 hash); -#else -static inline int lockdep_rht_mutex_is_held(struct rhashtable *ht) -{ - return 1; -} - -static inline int lockdep_rht_bucket_is_held(const struct bucket_table *tbl, - u32 hash) -{ - return 1; -} -#endif /* CONFIG_PROVE_LOCKING */ - -int rhashtable_init(struct rhashtable *ht, - const struct rhashtable_params *params); -int rhltable_init(struct rhltable *hlt, - const struct rhashtable_params *params); - -void *rhashtable_insert_slow(struct rhashtable *ht, const void *key, - struct rhash_head *obj); - -void rhashtable_walk_enter(struct rhashtable *ht, - struct rhashtable_iter *iter); -void rhashtable_walk_exit(struct rhashtable_iter *iter); -int rhashtable_walk_start(struct rhashtable_iter *iter) __acquires(RCU); -void *rhashtable_walk_next(struct rhashtable_iter *iter); -void rhashtable_walk_stop(struct rhashtable_iter *iter) __releases(RCU); - -void rhashtable_free_and_destroy(struct rhashtable *ht, - void (*free_fn)(void *ptr, void *arg), - void *arg); -void rhashtable_destroy(struct rhashtable *ht); - -#define rht_dereference(p, ht) \ - rcu_dereference_protected(p, lockdep_rht_mutex_is_held(ht)) - -#define rht_dereference_rcu(p, ht) \ - rcu_dereference_check(p, lockdep_rht_mutex_is_held(ht)) - -#define rht_dereference_bucket(p, tbl, hash) \ - rcu_dereference_protected(p, lockdep_rht_bucket_is_held(tbl, hash)) - -#define rht_dereference_bucket_rcu(p, tbl, hash) \ - rcu_dereference_check(p, lockdep_rht_bucket_is_held(tbl, hash)) - -#define rht_entry(tpos, pos, member) \ - ({ tpos = container_of(pos, typeof(*tpos), member); 1; }) - -/** - * rht_for_each_continue - continue iterating over hash chain - * @pos: the &struct rhash_head to use as a loop cursor. - * @head: the previous &struct rhash_head to continue from - * @tbl: the &struct bucket_table - * @hash: the hash value / bucket index - */ -#define rht_for_each_continue(pos, head, tbl, hash) \ - for (pos = rht_dereference_bucket(head, tbl, hash); \ - !rht_is_a_nulls(pos); \ - pos = rht_dereference_bucket((pos)->next, tbl, hash)) - -/** - * rht_for_each - iterate over hash chain - * @pos: the &struct rhash_head to use as a loop cursor. - * @tbl: the &struct bucket_table - * @hash: the hash value / bucket index - */ -#define rht_for_each(pos, tbl, hash) \ - rht_for_each_continue(pos, (tbl)->buckets[hash], tbl, hash) - -/** - * rht_for_each_entry_continue - continue iterating over hash chain - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct rhash_head to use as a loop cursor. - * @head: the previous &struct rhash_head to continue from - * @tbl: the &struct bucket_table - * @hash: the hash value / bucket index - * @member: name of the &struct rhash_head within the hashable struct. - */ -#define rht_for_each_entry_continue(tpos, pos, head, tbl, hash, member) \ - for (pos = rht_dereference_bucket(head, tbl, hash); \ - (!rht_is_a_nulls(pos)) && rht_entry(tpos, pos, member); \ - pos = rht_dereference_bucket((pos)->next, tbl, hash)) - -/** - * rht_for_each_entry - iterate over hash chain of given type - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct rhash_head to use as a loop cursor. - * @tbl: the &struct bucket_table - * @hash: the hash value / bucket index - * @member: name of the &struct rhash_head within the hashable struct. - */ -#define rht_for_each_entry(tpos, pos, tbl, hash, member) \ - rht_for_each_entry_continue(tpos, pos, (tbl)->buckets[hash], \ - tbl, hash, member) - -/** - * rht_for_each_entry_safe - safely iterate over hash chain of given type - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct rhash_head to use as a loop cursor. - * @next: the &struct rhash_head to use as next in loop cursor. - * @tbl: the &struct bucket_table - * @hash: the hash value / bucket index - * @member: name of the &struct rhash_head within the hashable struct. - * - * This hash chain list-traversal primitive allows for the looped code to - * remove the loop cursor from the list. - */ -#define rht_for_each_entry_safe(tpos, pos, next, tbl, hash, member) \ - for (pos = rht_dereference_bucket((tbl)->buckets[hash], tbl, hash), \ - next = !rht_is_a_nulls(pos) ? \ - rht_dereference_bucket(pos->next, tbl, hash) : NULL; \ - (!rht_is_a_nulls(pos)) && rht_entry(tpos, pos, member); \ - pos = next, \ - next = !rht_is_a_nulls(pos) ? \ - rht_dereference_bucket(pos->next, tbl, hash) : NULL) - -/** - * rht_for_each_rcu_continue - continue iterating over rcu hash chain - * @pos: the &struct rhash_head to use as a loop cursor. - * @head: the previous &struct rhash_head to continue from - * @tbl: the &struct bucket_table - * @hash: the hash value / bucket index - * - * This hash chain list-traversal primitive may safely run concurrently with - * the _rcu mutation primitives such as rhashtable_insert() as long as the - * traversal is guarded by rcu_read_lock(). - */ -#define rht_for_each_rcu_continue(pos, head, tbl, hash) \ - for (({barrier(); }), \ - pos = rht_dereference_bucket_rcu(head, tbl, hash); \ - !rht_is_a_nulls(pos); \ - pos = rcu_dereference_raw(pos->next)) - -/** - * rht_for_each_rcu - iterate over rcu hash chain - * @pos: the &struct rhash_head to use as a loop cursor. - * @tbl: the &struct bucket_table - * @hash: the hash value / bucket index - * - * This hash chain list-traversal primitive may safely run concurrently with - * the _rcu mutation primitives such as rhashtable_insert() as long as the - * traversal is guarded by rcu_read_lock(). - */ -#define rht_for_each_rcu(pos, tbl, hash) \ - rht_for_each_rcu_continue(pos, (tbl)->buckets[hash], tbl, hash) - -/** - * rht_for_each_entry_rcu_continue - continue iterating over rcu hash chain - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct rhash_head to use as a loop cursor. - * @head: the previous &struct rhash_head to continue from - * @tbl: the &struct bucket_table - * @hash: the hash value / bucket index - * @member: name of the &struct rhash_head within the hashable struct. - * - * This hash chain list-traversal primitive may safely run concurrently with - * the _rcu mutation primitives such as rhashtable_insert() as long as the - * traversal is guarded by rcu_read_lock(). - */ -#define rht_for_each_entry_rcu_continue(tpos, pos, head, tbl, hash, member) \ - for (({barrier(); }), \ - pos = rht_dereference_bucket_rcu(head, tbl, hash); \ - (!rht_is_a_nulls(pos)) && rht_entry(tpos, pos, member); \ - pos = rht_dereference_bucket_rcu(pos->next, tbl, hash)) - -/** - * rht_for_each_entry_rcu - iterate over rcu hash chain of given type - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct rhash_head to use as a loop cursor. - * @tbl: the &struct bucket_table - * @hash: the hash value / bucket index - * @member: name of the &struct rhash_head within the hashable struct. - * - * This hash chain list-traversal primitive may safely run concurrently with - * the _rcu mutation primitives such as rhashtable_insert() as long as the - * traversal is guarded by rcu_read_lock(). - */ -#define rht_for_each_entry_rcu(tpos, pos, tbl, hash, member) \ - rht_for_each_entry_rcu_continue(tpos, pos, (tbl)->buckets[hash],\ - tbl, hash, member) - -/** - * rhl_for_each_rcu - iterate over rcu hash table list - * @pos: the &struct rlist_head to use as a loop cursor. - * @list: the head of the list - * - * This hash chain list-traversal primitive should be used on the - * list returned by rhltable_lookup. - */ -#define rhl_for_each_rcu(pos, list) \ - for (pos = list; pos; pos = rcu_dereference_raw(pos->next)) - -/** - * rhl_for_each_entry_rcu - iterate over rcu hash table list of given type - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct rlist_head to use as a loop cursor. - * @list: the head of the list - * @member: name of the &struct rlist_head within the hashable struct. - * - * This hash chain list-traversal primitive should be used on the - * list returned by rhltable_lookup. - */ -#define rhl_for_each_entry_rcu(tpos, pos, list, member) \ - for (pos = list; pos && rht_entry(tpos, pos, member); \ - pos = rcu_dereference_raw(pos->next)) - -static inline int rhashtable_compare(struct rhashtable_compare_arg *arg, - const void *obj) -{ - struct rhashtable *ht = arg->ht; - const char *ptr = obj; - - return memcmp(ptr + ht->p.key_offset, arg->key, ht->p.key_len); -} - -/* Internal function, do not use. */ -static inline struct rhash_head *__rhashtable_lookup( - struct rhashtable *ht, const void *key, - const struct rhashtable_params params) -{ - struct rhashtable_compare_arg arg = { - .ht = ht, - .key = key, - }; - const struct bucket_table *tbl; - struct rhash_head *he; - unsigned int hash; - - tbl = rht_dereference_rcu(ht->tbl, ht); -restart: - hash = rht_key_hashfn(ht, tbl, key, params); - rht_for_each_rcu(he, tbl, hash) { - if (params.obj_cmpfn ? - params.obj_cmpfn(&arg, rht_obj(ht, he)) : - rhashtable_compare(&arg, rht_obj(ht, he))) - continue; - return he; - } - - /* Ensure we see any new tables. */ - smp_rmb(); - - tbl = rht_dereference_rcu(tbl->future_tbl, ht); - if (unlikely(tbl)) - goto restart; - - return NULL; -} - -/** - * rhashtable_lookup - search hash table - * @ht: hash table - * @key: the pointer to the key - * @params: hash table parameters - * - * Computes the hash value for the key and traverses the bucket chain looking - * for a entry with an identical key. The first matching entry is returned. - * - * This must only be called under the RCU read lock. - * - * Returns the first entry on which the compare function returned true. - */ -static inline void *rhashtable_lookup( - struct rhashtable *ht, const void *key, - const struct rhashtable_params params) -{ - struct rhash_head *he = __rhashtable_lookup(ht, key, params); - - return he ? rht_obj(ht, he) : NULL; -} - -/** - * rhashtable_lookup_fast - search hash table, without RCU read lock - * @ht: hash table - * @key: the pointer to the key - * @params: hash table parameters - * - * Computes the hash value for the key and traverses the bucket chain looking - * for a entry with an identical key. The first matching entry is returned. - * - * Only use this function when you have other mechanisms guaranteeing - * that the object won't go away after the RCU read lock is released. - * - * Returns the first entry on which the compare function returned true. - */ -static inline void *rhashtable_lookup_fast( - struct rhashtable *ht, const void *key, - const struct rhashtable_params params) -{ - void *obj; - - rcu_read_lock(); - obj = rhashtable_lookup(ht, key, params); - rcu_read_unlock(); - - return obj; -} - -/** - * rhltable_lookup - search hash list table - * @hlt: hash table - * @key: the pointer to the key - * @params: hash table parameters - * - * Computes the hash value for the key and traverses the bucket chain looking - * for a entry with an identical key. All matching entries are returned - * in a list. - * - * This must only be called under the RCU read lock. - * - * Returns the list of entries that match the given key. - */ -static inline struct rhlist_head *rhltable_lookup( - struct rhltable *hlt, const void *key, - const struct rhashtable_params params) -{ - struct rhash_head *he = __rhashtable_lookup(&hlt->ht, key, params); - - return he ? container_of(he, struct rhlist_head, rhead) : NULL; -} - -/* Internal function, please use rhashtable_insert_fast() instead. This - * function returns the existing element already in hashes in there is a clash, - * otherwise it returns an error via ERR_PTR(). - */ -static inline void *__rhashtable_insert_fast( - struct rhashtable *ht, const void *key, struct rhash_head *obj, - const struct rhashtable_params params, bool rhlist) -{ - struct rhashtable_compare_arg arg = { - .ht = ht, - .key = key, - }; - struct rhash_head __rcu **pprev; - struct bucket_table *tbl; - struct rhash_head *head; - spinlock_t *lock; - unsigned int hash; - int elasticity; - void *data; - - rcu_read_lock(); - - tbl = rht_dereference_rcu(ht->tbl, ht); - hash = rht_head_hashfn(ht, tbl, obj, params); - lock = rht_bucket_lock(tbl, hash); - spin_lock_bh(lock); - - if (unlikely(rht_dereference_bucket(tbl->future_tbl, tbl, hash))) { -slow_path: - spin_unlock_bh(lock); - rcu_read_unlock(); - return rhashtable_insert_slow(ht, key, obj); - } - - elasticity = ht->elasticity; - pprev = &tbl->buckets[hash]; - rht_for_each(head, tbl, hash) { - struct rhlist_head *plist; - struct rhlist_head *list; - - elasticity--; - if (!key || - (params.obj_cmpfn ? - params.obj_cmpfn(&arg, rht_obj(ht, head)) : - rhashtable_compare(&arg, rht_obj(ht, head)))) - continue; - - data = rht_obj(ht, head); - - if (!rhlist) - goto out; - - - list = container_of(obj, struct rhlist_head, rhead); - plist = container_of(head, struct rhlist_head, rhead); - - RCU_INIT_POINTER(list->next, plist); - head = rht_dereference_bucket(head->next, tbl, hash); - RCU_INIT_POINTER(list->rhead.next, head); - rcu_assign_pointer(*pprev, obj); - - goto good; - } - - if (elasticity <= 0) - goto slow_path; - - data = ERR_PTR(-E2BIG); - if (unlikely(rht_grow_above_max(ht, tbl))) - goto out; - - if (unlikely(rht_grow_above_100(ht, tbl))) - goto slow_path; - - head = rht_dereference_bucket(tbl->buckets[hash], tbl, hash); - - RCU_INIT_POINTER(obj->next, head); - if (rhlist) { - struct rhlist_head *list; - - list = container_of(obj, struct rhlist_head, rhead); - RCU_INIT_POINTER(list->next, NULL); - } - - rcu_assign_pointer(tbl->buckets[hash], obj); - - atomic_inc(&ht->nelems); - if (rht_grow_above_75(ht, tbl)) - schedule_work(&ht->run_work); - -good: - data = NULL; - -out: - spin_unlock_bh(lock); - rcu_read_unlock(); - - return data; -} - -/** - * rhashtable_insert_fast - insert object into hash table - * @ht: hash table - * @obj: pointer to hash head inside object - * @params: hash table parameters - * - * Will take a per bucket spinlock to protect against mutual mutations - * on the same bucket. Multiple insertions may occur in parallel unless - * they map to the same bucket lock. - * - * It is safe to call this function from atomic context. - * - * Will trigger an automatic deferred table resizing if the size grows - * beyond the watermark indicated by grow_decision() which can be passed - * to rhashtable_init(). - */ -static inline int rhashtable_insert_fast( - struct rhashtable *ht, struct rhash_head *obj, - const struct rhashtable_params params) -{ - void *ret; - - ret = __rhashtable_insert_fast(ht, NULL, obj, params, false); - if (IS_ERR(ret)) - return PTR_ERR(ret); - - return ret == NULL ? 0 : -EEXIST; -} - -/** - * rhltable_insert_key - insert object into hash list table - * @hlt: hash list table - * @key: the pointer to the key - * @list: pointer to hash list head inside object - * @params: hash table parameters - * - * Will take a per bucket spinlock to protect against mutual mutations - * on the same bucket. Multiple insertions may occur in parallel unless - * they map to the same bucket lock. - * - * It is safe to call this function from atomic context. - * - * Will trigger an automatic deferred table resizing if the size grows - * beyond the watermark indicated by grow_decision() which can be passed - * to rhashtable_init(). - */ -static inline int rhltable_insert_key( - struct rhltable *hlt, const void *key, struct rhlist_head *list, - const struct rhashtable_params params) -{ - return PTR_ERR(__rhashtable_insert_fast(&hlt->ht, key, &list->rhead, - params, true)); -} - -/** - * rhltable_insert - insert object into hash list table - * @hlt: hash list table - * @list: pointer to hash list head inside object - * @params: hash table parameters - * - * Will take a per bucket spinlock to protect against mutual mutations - * on the same bucket. Multiple insertions may occur in parallel unless - * they map to the same bucket lock. - * - * It is safe to call this function from atomic context. - * - * Will trigger an automatic deferred table resizing if the size grows - * beyond the watermark indicated by grow_decision() which can be passed - * to rhashtable_init(). - */ -static inline int rhltable_insert( - struct rhltable *hlt, struct rhlist_head *list, - const struct rhashtable_params params) -{ - const char *key = rht_obj(&hlt->ht, &list->rhead); - - key += params.key_offset; - - return rhltable_insert_key(hlt, key, list, params); -} - -/** - * rhashtable_lookup_insert_fast - lookup and insert object into hash table - * @ht: hash table - * @obj: pointer to hash head inside object - * @params: hash table parameters - * - * Locks down the bucket chain in both the old and new table if a resize - * is in progress to ensure that writers can't remove from the old table - * and can't insert to the new table during the atomic operation of search - * and insertion. Searches for duplicates in both the old and new table if - * a resize is in progress. - * - * This lookup function may only be used for fixed key hash table (key_len - * parameter set). It will BUG() if used inappropriately. - * - * It is safe to call this function from atomic context. - * - * Will trigger an automatic deferred table resizing if the size grows - * beyond the watermark indicated by grow_decision() which can be passed - * to rhashtable_init(). - */ -static inline int rhashtable_lookup_insert_fast( - struct rhashtable *ht, struct rhash_head *obj, - const struct rhashtable_params params) -{ - const char *key = rht_obj(ht, obj); - void *ret; - - BUG_ON(ht->p.obj_hashfn); - - ret = __rhashtable_insert_fast(ht, key + ht->p.key_offset, obj, params, - false); - if (IS_ERR(ret)) - return PTR_ERR(ret); - - return ret == NULL ? 0 : -EEXIST; -} - -/** - * rhashtable_lookup_insert_key - search and insert object to hash table - * with explicit key - * @ht: hash table - * @key: key - * @obj: pointer to hash head inside object - * @params: hash table parameters - * - * Locks down the bucket chain in both the old and new table if a resize - * is in progress to ensure that writers can't remove from the old table - * and can't insert to the new table during the atomic operation of search - * and insertion. Searches for duplicates in both the old and new table if - * a resize is in progress. - * - * Lookups may occur in parallel with hashtable mutations and resizing. - * - * Will trigger an automatic deferred table resizing if the size grows - * beyond the watermark indicated by grow_decision() which can be passed - * to rhashtable_init(). - * - * Returns zero on success. - */ -static inline int rhashtable_lookup_insert_key( - struct rhashtable *ht, const void *key, struct rhash_head *obj, - const struct rhashtable_params params) -{ - void *ret; - - BUG_ON(!ht->p.obj_hashfn || !key); - - ret = __rhashtable_insert_fast(ht, key, obj, params, false); - if (IS_ERR(ret)) - return PTR_ERR(ret); - - return ret == NULL ? 0 : -EEXIST; -} - -/** - * rhashtable_lookup_get_insert_key - lookup and insert object into hash table - * @ht: hash table - * @obj: pointer to hash head inside object - * @params: hash table parameters - * @data: pointer to element data already in hashes - * - * Just like rhashtable_lookup_insert_key(), but this function returns the - * object if it exists, NULL if it does not and the insertion was successful, - * and an ERR_PTR otherwise. - */ -static inline void *rhashtable_lookup_get_insert_key( - struct rhashtable *ht, const void *key, struct rhash_head *obj, - const struct rhashtable_params params) -{ - BUG_ON(!ht->p.obj_hashfn || !key); - - return __rhashtable_insert_fast(ht, key, obj, params, false); -} - -/* Internal function, please use rhashtable_remove_fast() instead */ -static inline int __rhashtable_remove_fast_one( - struct rhashtable *ht, struct bucket_table *tbl, - struct rhash_head *obj, const struct rhashtable_params params, - bool rhlist) -{ - struct rhash_head __rcu **pprev; - struct rhash_head *he; - spinlock_t * lock; - unsigned int hash; - int err = -ENOENT; - - hash = rht_head_hashfn(ht, tbl, obj, params); - lock = rht_bucket_lock(tbl, hash); - - spin_lock_bh(lock); - - pprev = &tbl->buckets[hash]; - rht_for_each(he, tbl, hash) { - struct rhlist_head *list; - - list = container_of(he, struct rhlist_head, rhead); - - if (he != obj) { - struct rhlist_head __rcu **lpprev; - - pprev = &he->next; - - if (!rhlist) - continue; - - do { - lpprev = &list->next; - list = rht_dereference_bucket(list->next, - tbl, hash); - } while (list && obj != &list->rhead); - - if (!list) - continue; - - list = rht_dereference_bucket(list->next, tbl, hash); - RCU_INIT_POINTER(*lpprev, list); - err = 0; - break; - } - - obj = rht_dereference_bucket(obj->next, tbl, hash); - err = 1; - - if (rhlist) { - list = rht_dereference_bucket(list->next, tbl, hash); - if (list) { - RCU_INIT_POINTER(list->rhead.next, obj); - obj = &list->rhead; - err = 0; - } - } - - rcu_assign_pointer(*pprev, obj); - break; - } - - spin_unlock_bh(lock); - - if (err > 0) { - atomic_dec(&ht->nelems); - if (unlikely(ht->p.automatic_shrinking && - rht_shrink_below_30(ht, tbl))) - schedule_work(&ht->run_work); - err = 0; - } - - return err; -} - -/* Internal function, please use rhashtable_remove_fast() instead */ -static inline int __rhashtable_remove_fast( - struct rhashtable *ht, struct rhash_head *obj, - const struct rhashtable_params params, bool rhlist) -{ - struct bucket_table *tbl; - int err; - - rcu_read_lock(); - - tbl = rht_dereference_rcu(ht->tbl, ht); - - /* Because we have already taken (and released) the bucket - * lock in old_tbl, if we find that future_tbl is not yet - * visible then that guarantees the entry to still be in - * the old tbl if it exists. - */ - while ((err = __rhashtable_remove_fast_one(ht, tbl, obj, params, - rhlist)) && - (tbl = rht_dereference_rcu(tbl->future_tbl, ht))) - ; - - rcu_read_unlock(); - - return err; -} - -/** - * rhashtable_remove_fast - remove object from hash table - * @ht: hash table - * @obj: pointer to hash head inside object - * @params: hash table parameters - * - * Since the hash chain is single linked, the removal operation needs to - * walk the bucket chain upon removal. The removal operation is thus - * considerable slow if the hash table is not correctly sized. - * - * Will automatically shrink the table via rhashtable_expand() if the - * shrink_decision function specified at rhashtable_init() returns true. - * - * Returns zero on success, -ENOENT if the entry could not be found. - */ -static inline int rhashtable_remove_fast( - struct rhashtable *ht, struct rhash_head *obj, - const struct rhashtable_params params) -{ - return __rhashtable_remove_fast(ht, obj, params, false); -} - -/** - * rhltable_remove - remove object from hash list table - * @hlt: hash list table - * @list: pointer to hash list head inside object - * @params: hash table parameters - * - * Since the hash chain is single linked, the removal operation needs to - * walk the bucket chain upon removal. The removal operation is thus - * considerable slow if the hash table is not correctly sized. - * - * Will automatically shrink the table via rhashtable_expand() if the - * shrink_decision function specified at rhashtable_init() returns true. - * - * Returns zero on success, -ENOENT if the entry could not be found. - */ -static inline int rhltable_remove( - struct rhltable *hlt, struct rhlist_head *list, - const struct rhashtable_params params) -{ - return __rhashtable_remove_fast(&hlt->ht, &list->rhead, params, true); -} - -/* Internal function, please use rhashtable_replace_fast() instead */ -static inline int __rhashtable_replace_fast( - struct rhashtable *ht, struct bucket_table *tbl, - struct rhash_head *obj_old, struct rhash_head *obj_new, - const struct rhashtable_params params) -{ - struct rhash_head __rcu **pprev; - struct rhash_head *he; - spinlock_t *lock; - unsigned int hash; - int err = -ENOENT; - - /* Minimally, the old and new objects must have same hash - * (which should mean identifiers are the same). - */ - hash = rht_head_hashfn(ht, tbl, obj_old, params); - if (hash != rht_head_hashfn(ht, tbl, obj_new, params)) - return -EINVAL; - - lock = rht_bucket_lock(tbl, hash); - - spin_lock_bh(lock); - - pprev = &tbl->buckets[hash]; - rht_for_each(he, tbl, hash) { - if (he != obj_old) { - pprev = &he->next; - continue; - } - - rcu_assign_pointer(obj_new->next, obj_old->next); - rcu_assign_pointer(*pprev, obj_new); - err = 0; - break; - } - - spin_unlock_bh(lock); - - return err; -} - -/** - * rhashtable_replace_fast - replace an object in hash table - * @ht: hash table - * @obj_old: pointer to hash head inside object being replaced - * @obj_new: pointer to hash head inside object which is new - * @params: hash table parameters - * - * Replacing an object doesn't affect the number of elements in the hash table - * or bucket, so we don't need to worry about shrinking or expanding the - * table here. - * - * Returns zero on success, -ENOENT if the entry could not be found, - * -EINVAL if hash is not the same for the old and new objects. - */ -static inline int rhashtable_replace_fast( - struct rhashtable *ht, struct rhash_head *obj_old, - struct rhash_head *obj_new, - const struct rhashtable_params params) -{ - struct bucket_table *tbl; - int err; - - rcu_read_lock(); - - tbl = rht_dereference_rcu(ht->tbl, ht); - - /* Because we have already taken (and released) the bucket - * lock in old_tbl, if we find that future_tbl is not yet - * visible then that guarantees the entry to still be in - * the old tbl if it exists. - */ - while ((err = __rhashtable_replace_fast(ht, tbl, obj_old, - obj_new, params)) && - (tbl = rht_dereference_rcu(tbl->future_tbl, ht))) - ; - - rcu_read_unlock(); - - return err; -} - -/* Obsolete function, do not use in new code. */ -static inline int rhashtable_walk_init(struct rhashtable *ht, - struct rhashtable_iter *iter, gfp_t gfp) -{ - rhashtable_walk_enter(ht, iter); - return 0; -} - -/** - * rhltable_walk_enter - Initialise an iterator - * @hlt: Table to walk over - * @iter: Hash table Iterator - * - * This function prepares a hash table walk. - * - * Note that if you restart a walk after rhashtable_walk_stop you - * may see the same object twice. Also, you may miss objects if - * there are removals in between rhashtable_walk_stop and the next - * call to rhashtable_walk_start. - * - * For a completely stable walk you should construct your own data - * structure outside the hash table. - * - * This function may sleep so you must not call it from interrupt - * context or with spin locks held. - * - * You must call rhashtable_walk_exit after this function returns. - */ -static inline void rhltable_walk_enter(struct rhltable *hlt, - struct rhashtable_iter *iter) -{ - return rhashtable_walk_enter(&hlt->ht, iter); -} - -/** - * rhltable_free_and_destroy - free elements and destroy hash list table - * @hlt: the hash list table to destroy - * @free_fn: callback to release resources of element - * @arg: pointer passed to free_fn - * - * See documentation for rhashtable_free_and_destroy. - */ -static inline void rhltable_free_and_destroy(struct rhltable *hlt, - void (*free_fn)(void *ptr, - void *arg), - void *arg) -{ - return rhashtable_free_and_destroy(&hlt->ht, free_fn, arg); -} - -static inline void rhltable_destroy(struct rhltable *hlt) -{ - return rhltable_free_and_destroy(hlt, NULL, NULL); -} - -#endif /* _LINUX_RHASHTABLE_H */ diff --git a/src/linux/include/linux/ring_buffer.h b/src/linux/include/linux/ring_buffer.h deleted file mode 100644 index 4acc552..0000000 --- a/src/linux/include/linux/ring_buffer.h +++ /dev/null @@ -1,201 +0,0 @@ -#ifndef _LINUX_RING_BUFFER_H -#define _LINUX_RING_BUFFER_H - -#include -#include -#include -#include - -struct ring_buffer; -struct ring_buffer_iter; - -/* - * Don't refer to this struct directly, use functions below. - */ -struct ring_buffer_event { - kmemcheck_bitfield_begin(bitfield); - u32 type_len:5, time_delta:27; - kmemcheck_bitfield_end(bitfield); - - u32 array[]; -}; - -/** - * enum ring_buffer_type - internal ring buffer types - * - * @RINGBUF_TYPE_PADDING: Left over page padding or discarded event - * If time_delta is 0: - * array is ignored - * size is variable depending on how much - * padding is needed - * If time_delta is non zero: - * array[0] holds the actual length - * size = 4 + length (bytes) - * - * @RINGBUF_TYPE_TIME_EXTEND: Extend the time delta - * array[0] = time delta (28 .. 59) - * size = 8 bytes - * - * @RINGBUF_TYPE_TIME_STAMP: Sync time stamp with external clock - * array[0] = tv_nsec - * array[1..2] = tv_sec - * size = 16 bytes - * - * <= @RINGBUF_TYPE_DATA_TYPE_LEN_MAX: - * Data record - * If type_len is zero: - * array[0] holds the actual length - * array[1..(length+3)/4] holds data - * size = 4 + length (bytes) - * else - * length = type_len << 2 - * array[0..(length+3)/4-1] holds data - * size = 4 + length (bytes) - */ -enum ring_buffer_type { - RINGBUF_TYPE_DATA_TYPE_LEN_MAX = 28, - RINGBUF_TYPE_PADDING, - RINGBUF_TYPE_TIME_EXTEND, - /* FIXME: RINGBUF_TYPE_TIME_STAMP not implemented */ - RINGBUF_TYPE_TIME_STAMP, -}; - -unsigned ring_buffer_event_length(struct ring_buffer_event *event); -void *ring_buffer_event_data(struct ring_buffer_event *event); - -/* - * ring_buffer_discard_commit will remove an event that has not - * ben committed yet. If this is used, then ring_buffer_unlock_commit - * must not be called on the discarded event. This function - * will try to remove the event from the ring buffer completely - * if another event has not been written after it. - * - * Example use: - * - * if (some_condition) - * ring_buffer_discard_commit(buffer, event); - * else - * ring_buffer_unlock_commit(buffer, event); - */ -void ring_buffer_discard_commit(struct ring_buffer *buffer, - struct ring_buffer_event *event); - -/* - * size is in bytes for each per CPU buffer. - */ -struct ring_buffer * -__ring_buffer_alloc(unsigned long size, unsigned flags, struct lock_class_key *key); - -/* - * Because the ring buffer is generic, if other users of the ring buffer get - * traced by ftrace, it can produce lockdep warnings. We need to keep each - * ring buffer's lock class separate. - */ -#define ring_buffer_alloc(size, flags) \ -({ \ - static struct lock_class_key __key; \ - __ring_buffer_alloc((size), (flags), &__key); \ -}) - -int ring_buffer_wait(struct ring_buffer *buffer, int cpu, bool full); -int ring_buffer_poll_wait(struct ring_buffer *buffer, int cpu, - struct file *filp, poll_table *poll_table); - - -#define RING_BUFFER_ALL_CPUS -1 - -void ring_buffer_free(struct ring_buffer *buffer); - -int ring_buffer_resize(struct ring_buffer *buffer, unsigned long size, int cpu); - -void ring_buffer_change_overwrite(struct ring_buffer *buffer, int val); - -struct ring_buffer_event *ring_buffer_lock_reserve(struct ring_buffer *buffer, - unsigned long length); -int ring_buffer_unlock_commit(struct ring_buffer *buffer, - struct ring_buffer_event *event); -int ring_buffer_write(struct ring_buffer *buffer, - unsigned long length, void *data); - -struct ring_buffer_event * -ring_buffer_peek(struct ring_buffer *buffer, int cpu, u64 *ts, - unsigned long *lost_events); -struct ring_buffer_event * -ring_buffer_consume(struct ring_buffer *buffer, int cpu, u64 *ts, - unsigned long *lost_events); - -struct ring_buffer_iter * -ring_buffer_read_prepare(struct ring_buffer *buffer, int cpu); -void ring_buffer_read_prepare_sync(void); -void ring_buffer_read_start(struct ring_buffer_iter *iter); -void ring_buffer_read_finish(struct ring_buffer_iter *iter); - -struct ring_buffer_event * -ring_buffer_iter_peek(struct ring_buffer_iter *iter, u64 *ts); -struct ring_buffer_event * -ring_buffer_read(struct ring_buffer_iter *iter, u64 *ts); -void ring_buffer_iter_reset(struct ring_buffer_iter *iter); -int ring_buffer_iter_empty(struct ring_buffer_iter *iter); - -unsigned long ring_buffer_size(struct ring_buffer *buffer, int cpu); - -void ring_buffer_reset_cpu(struct ring_buffer *buffer, int cpu); -void ring_buffer_reset(struct ring_buffer *buffer); - -#ifdef CONFIG_RING_BUFFER_ALLOW_SWAP -int ring_buffer_swap_cpu(struct ring_buffer *buffer_a, - struct ring_buffer *buffer_b, int cpu); -#else -static inline int -ring_buffer_swap_cpu(struct ring_buffer *buffer_a, - struct ring_buffer *buffer_b, int cpu) -{ - return -ENODEV; -} -#endif - -bool ring_buffer_empty(struct ring_buffer *buffer); -bool ring_buffer_empty_cpu(struct ring_buffer *buffer, int cpu); - -void ring_buffer_record_disable(struct ring_buffer *buffer); -void ring_buffer_record_enable(struct ring_buffer *buffer); -void ring_buffer_record_off(struct ring_buffer *buffer); -void ring_buffer_record_on(struct ring_buffer *buffer); -int ring_buffer_record_is_on(struct ring_buffer *buffer); -void ring_buffer_record_disable_cpu(struct ring_buffer *buffer, int cpu); -void ring_buffer_record_enable_cpu(struct ring_buffer *buffer, int cpu); - -u64 ring_buffer_oldest_event_ts(struct ring_buffer *buffer, int cpu); -unsigned long ring_buffer_bytes_cpu(struct ring_buffer *buffer, int cpu); -unsigned long ring_buffer_entries(struct ring_buffer *buffer); -unsigned long ring_buffer_overruns(struct ring_buffer *buffer); -unsigned long ring_buffer_entries_cpu(struct ring_buffer *buffer, int cpu); -unsigned long ring_buffer_overrun_cpu(struct ring_buffer *buffer, int cpu); -unsigned long ring_buffer_commit_overrun_cpu(struct ring_buffer *buffer, int cpu); -unsigned long ring_buffer_dropped_events_cpu(struct ring_buffer *buffer, int cpu); -unsigned long ring_buffer_read_events_cpu(struct ring_buffer *buffer, int cpu); - -u64 ring_buffer_time_stamp(struct ring_buffer *buffer, int cpu); -void ring_buffer_normalize_time_stamp(struct ring_buffer *buffer, - int cpu, u64 *ts); -void ring_buffer_set_clock(struct ring_buffer *buffer, - u64 (*clock)(void)); - -size_t ring_buffer_page_len(void *page); - - -void *ring_buffer_alloc_read_page(struct ring_buffer *buffer, int cpu); -void ring_buffer_free_read_page(struct ring_buffer *buffer, void *data); -int ring_buffer_read_page(struct ring_buffer *buffer, void **data_page, - size_t len, int cpu, int full); - -struct trace_seq; - -int ring_buffer_print_entry_header(struct trace_seq *s); -int ring_buffer_print_page_header(struct trace_seq *s); - -enum ring_buffer_flags { - RB_FL_OVERWRITE = 1 << 0, -}; - -#endif /* _LINUX_RING_BUFFER_H */ diff --git a/src/linux/include/linux/rmap.h b/src/linux/include/linux/rmap.h deleted file mode 100644 index b46bb56..0000000 --- a/src/linux/include/linux/rmap.h +++ /dev/null @@ -1,309 +0,0 @@ -#ifndef _LINUX_RMAP_H -#define _LINUX_RMAP_H -/* - * Declarations for Reverse Mapping functions in mm/rmap.c - */ - -#include -#include -#include -#include -#include - -/* - * The anon_vma heads a list of private "related" vmas, to scan if - * an anonymous page pointing to this anon_vma needs to be unmapped: - * the vmas on the list will be related by forking, or by splitting. - * - * Since vmas come and go as they are split and merged (particularly - * in mprotect), the mapping field of an anonymous page cannot point - * directly to a vma: instead it points to an anon_vma, on whose list - * the related vmas can be easily linked or unlinked. - * - * After unlinking the last vma on the list, we must garbage collect - * the anon_vma object itself: we're guaranteed no page can be - * pointing to this anon_vma once its vma list is empty. - */ -struct anon_vma { - struct anon_vma *root; /* Root of this anon_vma tree */ - struct rw_semaphore rwsem; /* W: modification, R: walking the list */ - /* - * The refcount is taken on an anon_vma when there is no - * guarantee that the vma of page tables will exist for - * the duration of the operation. A caller that takes - * the reference is responsible for clearing up the - * anon_vma if they are the last user on release - */ - atomic_t refcount; - - /* - * Count of child anon_vmas and VMAs which points to this anon_vma. - * - * This counter is used for making decision about reusing anon_vma - * instead of forking new one. See comments in function anon_vma_clone. - */ - unsigned degree; - - struct anon_vma *parent; /* Parent of this anon_vma */ - - /* - * NOTE: the LSB of the rb_root.rb_node is set by - * mm_take_all_locks() _after_ taking the above lock. So the - * rb_root must only be read/written after taking the above lock - * to be sure to see a valid next pointer. The LSB bit itself - * is serialized by a system wide lock only visible to - * mm_take_all_locks() (mm_all_locks_mutex). - */ - struct rb_root rb_root; /* Interval tree of private "related" vmas */ -}; - -/* - * The copy-on-write semantics of fork mean that an anon_vma - * can become associated with multiple processes. Furthermore, - * each child process will have its own anon_vma, where new - * pages for that process are instantiated. - * - * This structure allows us to find the anon_vmas associated - * with a VMA, or the VMAs associated with an anon_vma. - * The "same_vma" list contains the anon_vma_chains linking - * all the anon_vmas associated with this VMA. - * The "rb" field indexes on an interval tree the anon_vma_chains - * which link all the VMAs associated with this anon_vma. - */ -struct anon_vma_chain { - struct vm_area_struct *vma; - struct anon_vma *anon_vma; - struct list_head same_vma; /* locked by mmap_sem & page_table_lock */ - struct rb_node rb; /* locked by anon_vma->rwsem */ - unsigned long rb_subtree_last; -#ifdef CONFIG_DEBUG_VM_RB - unsigned long cached_vma_start, cached_vma_last; -#endif -}; - -enum ttu_flags { - TTU_UNMAP = 1, /* unmap mode */ - TTU_MIGRATION = 2, /* migration mode */ - TTU_MUNLOCK = 4, /* munlock mode */ - TTU_LZFREE = 8, /* lazy free mode */ - TTU_SPLIT_HUGE_PMD = 16, /* split huge PMD if any */ - - TTU_IGNORE_MLOCK = (1 << 8), /* ignore mlock */ - TTU_IGNORE_ACCESS = (1 << 9), /* don't age */ - TTU_IGNORE_HWPOISON = (1 << 10),/* corrupted page is recoverable */ - TTU_BATCH_FLUSH = (1 << 11), /* Batch TLB flushes where possible - * and caller guarantees they will - * do a final flush if necessary */ - TTU_RMAP_LOCKED = (1 << 12) /* do not grab rmap lock: - * caller holds it */ -}; - -#ifdef CONFIG_MMU -static inline void get_anon_vma(struct anon_vma *anon_vma) -{ - atomic_inc(&anon_vma->refcount); -} - -void __put_anon_vma(struct anon_vma *anon_vma); - -static inline void put_anon_vma(struct anon_vma *anon_vma) -{ - if (atomic_dec_and_test(&anon_vma->refcount)) - __put_anon_vma(anon_vma); -} - -static inline void anon_vma_lock_write(struct anon_vma *anon_vma) -{ - down_write(&anon_vma->root->rwsem); -} - -static inline void anon_vma_unlock_write(struct anon_vma *anon_vma) -{ - up_write(&anon_vma->root->rwsem); -} - -static inline void anon_vma_lock_read(struct anon_vma *anon_vma) -{ - down_read(&anon_vma->root->rwsem); -} - -static inline void anon_vma_unlock_read(struct anon_vma *anon_vma) -{ - up_read(&anon_vma->root->rwsem); -} - - -/* - * anon_vma helper functions. - */ -void anon_vma_init(void); /* create anon_vma_cachep */ -int anon_vma_prepare(struct vm_area_struct *); -void unlink_anon_vmas(struct vm_area_struct *); -int anon_vma_clone(struct vm_area_struct *, struct vm_area_struct *); -int anon_vma_fork(struct vm_area_struct *, struct vm_area_struct *); - -static inline void anon_vma_merge(struct vm_area_struct *vma, - struct vm_area_struct *next) -{ - VM_BUG_ON_VMA(vma->anon_vma != next->anon_vma, vma); - unlink_anon_vmas(next); -} - -struct anon_vma *page_get_anon_vma(struct page *page); - -/* bitflags for do_page_add_anon_rmap() */ -#define RMAP_EXCLUSIVE 0x01 -#define RMAP_COMPOUND 0x02 - -/* - * rmap interfaces called when adding or removing pte of page - */ -void page_move_anon_rmap(struct page *, struct vm_area_struct *); -void page_add_anon_rmap(struct page *, struct vm_area_struct *, - unsigned long, bool); -void do_page_add_anon_rmap(struct page *, struct vm_area_struct *, - unsigned long, int); -void page_add_new_anon_rmap(struct page *, struct vm_area_struct *, - unsigned long, bool); -void page_add_file_rmap(struct page *, bool); -void page_remove_rmap(struct page *, bool); - -void hugepage_add_anon_rmap(struct page *, struct vm_area_struct *, - unsigned long); -void hugepage_add_new_anon_rmap(struct page *, struct vm_area_struct *, - unsigned long); - -static inline void page_dup_rmap(struct page *page, bool compound) -{ - atomic_inc(compound ? compound_mapcount_ptr(page) : &page->_mapcount); -} - -/* - * Called from mm/vmscan.c to handle paging out - */ -int page_referenced(struct page *, int is_locked, - struct mem_cgroup *memcg, unsigned long *vm_flags); - -#define TTU_ACTION(x) ((x) & TTU_ACTION_MASK) - -int try_to_unmap(struct page *, enum ttu_flags flags); - -/* - * Used by uprobes to replace a userspace page safely - */ -pte_t *__page_check_address(struct page *, struct mm_struct *, - unsigned long, spinlock_t **, int); - -static inline pte_t *page_check_address(struct page *page, struct mm_struct *mm, - unsigned long address, - spinlock_t **ptlp, int sync) -{ - pte_t *ptep; - - __cond_lock(*ptlp, ptep = __page_check_address(page, mm, address, - ptlp, sync)); - return ptep; -} - -/* - * Used by idle page tracking to check if a page was referenced via page - * tables. - */ -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -bool page_check_address_transhuge(struct page *page, struct mm_struct *mm, - unsigned long address, pmd_t **pmdp, - pte_t **ptep, spinlock_t **ptlp); -#else -static inline bool page_check_address_transhuge(struct page *page, - struct mm_struct *mm, unsigned long address, - pmd_t **pmdp, pte_t **ptep, spinlock_t **ptlp) -{ - *ptep = page_check_address(page, mm, address, ptlp, 0); - *pmdp = NULL; - return !!*ptep; -} -#endif - -/* - * Used by swapoff to help locate where page is expected in vma. - */ -unsigned long page_address_in_vma(struct page *, struct vm_area_struct *); - -/* - * Cleans the PTEs of shared mappings. - * (and since clean PTEs should also be readonly, write protects them too) - * - * returns the number of cleaned PTEs. - */ -int page_mkclean(struct page *); - -/* - * called in munlock()/munmap() path to check for other vmas holding - * the page mlocked. - */ -int try_to_munlock(struct page *); - -void remove_migration_ptes(struct page *old, struct page *new, bool locked); - -/* - * Called by memory-failure.c to kill processes. - */ -struct anon_vma *page_lock_anon_vma_read(struct page *page); -void page_unlock_anon_vma_read(struct anon_vma *anon_vma); -int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma); - -/* - * rmap_walk_control: To control rmap traversing for specific needs - * - * arg: passed to rmap_one() and invalid_vma() - * rmap_one: executed on each vma where page is mapped - * done: for checking traversing termination condition - * anon_lock: for getting anon_lock by optimized way rather than default - * invalid_vma: for skipping uninterested vma - */ -struct rmap_walk_control { - void *arg; - int (*rmap_one)(struct page *page, struct vm_area_struct *vma, - unsigned long addr, void *arg); - int (*done)(struct page *page); - struct anon_vma *(*anon_lock)(struct page *page); - bool (*invalid_vma)(struct vm_area_struct *vma, void *arg); -}; - -int rmap_walk(struct page *page, struct rmap_walk_control *rwc); -int rmap_walk_locked(struct page *page, struct rmap_walk_control *rwc); - -#else /* !CONFIG_MMU */ - -#define anon_vma_init() do {} while (0) -#define anon_vma_prepare(vma) (0) -#define anon_vma_link(vma) do {} while (0) - -static inline int page_referenced(struct page *page, int is_locked, - struct mem_cgroup *memcg, - unsigned long *vm_flags) -{ - *vm_flags = 0; - return 0; -} - -#define try_to_unmap(page, refs) SWAP_FAIL - -static inline int page_mkclean(struct page *page) -{ - return 0; -} - - -#endif /* CONFIG_MMU */ - -/* - * Return values of try_to_unmap - */ -#define SWAP_SUCCESS 0 -#define SWAP_AGAIN 1 -#define SWAP_FAIL 2 -#define SWAP_MLOCK 3 -#define SWAP_LZFREE 4 - -#endif /* _LINUX_RMAP_H */ diff --git a/src/linux/include/linux/root_dev.h b/src/linux/include/linux/root_dev.h deleted file mode 100644 index ed241aa..0000000 --- a/src/linux/include/linux/root_dev.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _ROOT_DEV_H_ -#define _ROOT_DEV_H_ - -#include -#include -#include - -enum { - Root_NFS = MKDEV(UNNAMED_MAJOR, 255), - Root_RAM0 = MKDEV(RAMDISK_MAJOR, 0), - Root_RAM1 = MKDEV(RAMDISK_MAJOR, 1), - Root_FD0 = MKDEV(FLOPPY_MAJOR, 0), - Root_HDA1 = MKDEV(IDE0_MAJOR, 1), - Root_HDA2 = MKDEV(IDE0_MAJOR, 2), - Root_SDA1 = MKDEV(SCSI_DISK0_MAJOR, 1), - Root_SDA2 = MKDEV(SCSI_DISK0_MAJOR, 2), - Root_HDC1 = MKDEV(IDE1_MAJOR, 1), - Root_SR0 = MKDEV(SCSI_CDROM_MAJOR, 0), -}; - -extern dev_t ROOT_DEV; - -#endif diff --git a/src/linux/include/linux/rtc.h b/src/linux/include/linux/rtc.h deleted file mode 100644 index b693ada..0000000 --- a/src/linux/include/linux/rtc.h +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Generic RTC interface. - * This version contains the part of the user interface to the Real Time Clock - * service. It is used with both the legacy mc146818 and also EFI - * Struct rtc_time and first 12 ioctl by Paul Gortmaker, 1996 - separated out - * from to this file for 2.4 kernels. - * - * Copyright (C) 1999 Hewlett-Packard Co. - * Copyright (C) 1999 Stephane Eranian - */ -#ifndef _LINUX_RTC_H_ -#define _LINUX_RTC_H_ - - -#include -#include -#include - -extern int rtc_month_days(unsigned int month, unsigned int year); -extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year); -extern int rtc_valid_tm(struct rtc_time *tm); -extern time64_t rtc_tm_to_time64(struct rtc_time *tm); -extern void rtc_time64_to_tm(time64_t time, struct rtc_time *tm); -ktime_t rtc_tm_to_ktime(struct rtc_time tm); -struct rtc_time rtc_ktime_to_tm(ktime_t kt); - -/* - * rtc_tm_sub - Return the difference in seconds. - */ -static inline time64_t rtc_tm_sub(struct rtc_time *lhs, struct rtc_time *rhs) -{ - return rtc_tm_to_time64(lhs) - rtc_tm_to_time64(rhs); -} - -/** - * Deprecated. Use rtc_time64_to_tm(). - */ -static inline void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) -{ - rtc_time64_to_tm(time, tm); -} - -/** - * Deprecated. Use rtc_tm_to_time64(). - */ -static inline int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) -{ - *time = rtc_tm_to_time64(tm); - - return 0; -} - -#include -#include -#include -#include -#include -#include -#include - -extern struct class *rtc_class; - -/* - * For these RTC methods the device parameter is the physical device - * on whatever bus holds the hardware (I2C, Platform, SPI, etc), which - * was passed to rtc_device_register(). Its driver_data normally holds - * device state, including the rtc_device pointer for the RTC. - * - * Most of these methods are called with rtc_device.ops_lock held, - * through the rtc_*(struct rtc_device *, ...) calls. - * - * The (current) exceptions are mostly filesystem hooks: - * - the proc() hook for procfs - * - non-ioctl() chardev hooks: open(), release(), read_callback() - * - * REVISIT those periodic irq calls *do* have ops_lock when they're - * issued through ioctl() ... - */ -struct rtc_class_ops { - int (*open)(struct device *); - void (*release)(struct device *); - int (*ioctl)(struct device *, unsigned int, unsigned long); - int (*read_time)(struct device *, struct rtc_time *); - int (*set_time)(struct device *, struct rtc_time *); - int (*read_alarm)(struct device *, struct rtc_wkalrm *); - int (*set_alarm)(struct device *, struct rtc_wkalrm *); - int (*proc)(struct device *, struct seq_file *); - int (*set_mmss64)(struct device *, time64_t secs); - int (*set_mmss)(struct device *, unsigned long secs); - int (*read_callback)(struct device *, int data); - int (*alarm_irq_enable)(struct device *, unsigned int enabled); - int (*read_offset)(struct device *, long *offset); - int (*set_offset)(struct device *, long offset); -}; - -#define RTC_DEVICE_NAME_SIZE 20 -typedef struct rtc_task { - void (*func)(void *private_data); - void *private_data; -} rtc_task_t; - - -struct rtc_timer { - struct rtc_task task; - struct timerqueue_node node; - ktime_t period; - int enabled; -}; - - -/* flags */ -#define RTC_DEV_BUSY 0 - -struct rtc_device { - struct device dev; - struct module *owner; - - int id; - char name[RTC_DEVICE_NAME_SIZE]; - - const struct rtc_class_ops *ops; - struct mutex ops_lock; - - struct cdev char_dev; - unsigned long flags; - - unsigned long irq_data; - spinlock_t irq_lock; - wait_queue_head_t irq_queue; - struct fasync_struct *async_queue; - - struct rtc_task *irq_task; - spinlock_t irq_task_lock; - int irq_freq; - int max_user_freq; - - struct timerqueue_head timerqueue; - struct rtc_timer aie_timer; - struct rtc_timer uie_rtctimer; - struct hrtimer pie_timer; /* sub second exp, so needs hrtimer */ - int pie_enabled; - struct work_struct irqwork; - /* Some hardware can't support UIE mode */ - int uie_unsupported; - -#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL - struct work_struct uie_task; - struct timer_list uie_timer; - /* Those fields are protected by rtc->irq_lock */ - unsigned int oldsecs; - unsigned int uie_irq_active:1; - unsigned int stop_uie_polling:1; - unsigned int uie_task_active:1; - unsigned int uie_timer_active:1; -#endif -}; -#define to_rtc_device(d) container_of(d, struct rtc_device, dev) - -extern struct rtc_device *rtc_device_register(const char *name, - struct device *dev, - const struct rtc_class_ops *ops, - struct module *owner); -extern struct rtc_device *devm_rtc_device_register(struct device *dev, - const char *name, - const struct rtc_class_ops *ops, - struct module *owner); -extern void rtc_device_unregister(struct rtc_device *rtc); -extern void devm_rtc_device_unregister(struct device *dev, - struct rtc_device *rtc); - -extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm); -extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm); -extern int rtc_set_ntp_time(struct timespec64 now); -int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm); -extern int rtc_read_alarm(struct rtc_device *rtc, - struct rtc_wkalrm *alrm); -extern int rtc_set_alarm(struct rtc_device *rtc, - struct rtc_wkalrm *alrm); -extern int rtc_initialize_alarm(struct rtc_device *rtc, - struct rtc_wkalrm *alrm); -extern void rtc_update_irq(struct rtc_device *rtc, - unsigned long num, unsigned long events); - -extern struct rtc_device *rtc_class_open(const char *name); -extern void rtc_class_close(struct rtc_device *rtc); - -extern int rtc_irq_register(struct rtc_device *rtc, - struct rtc_task *task); -extern void rtc_irq_unregister(struct rtc_device *rtc, - struct rtc_task *task); -extern int rtc_irq_set_state(struct rtc_device *rtc, - struct rtc_task *task, int enabled); -extern int rtc_irq_set_freq(struct rtc_device *rtc, - struct rtc_task *task, int freq); -extern int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled); -extern int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled); -extern int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, - unsigned int enabled); - -void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode); -void rtc_aie_update_irq(void *private); -void rtc_uie_update_irq(void *private); -enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer); - -int rtc_register(rtc_task_t *task); -int rtc_unregister(rtc_task_t *task); -int rtc_control(rtc_task_t *t, unsigned int cmd, unsigned long arg); - -void rtc_timer_init(struct rtc_timer *timer, void (*f)(void *p), void *data); -int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer, - ktime_t expires, ktime_t period); -void rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer); -int rtc_read_offset(struct rtc_device *rtc, long *offset); -int rtc_set_offset(struct rtc_device *rtc, long offset); -void rtc_timer_do_work(struct work_struct *work); - -static inline bool is_leap_year(unsigned int year) -{ - return (!(year % 4) && (year % 100)) || !(year % 400); -} - -#ifdef CONFIG_RTC_HCTOSYS_DEVICE -extern int rtc_hctosys_ret; -#else -#define rtc_hctosys_ret -ENODEV -#endif - -#endif /* _LINUX_RTC_H_ */ diff --git a/src/linux/include/linux/rtmutex.h b/src/linux/include/linux/rtmutex.h deleted file mode 100644 index 1abba5c..0000000 --- a/src/linux/include/linux/rtmutex.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * RT Mutexes: blocking mutual exclusion locks with PI support - * - * started by Ingo Molnar and Thomas Gleixner: - * - * Copyright (C) 2004-2006 Red Hat, Inc., Ingo Molnar - * Copyright (C) 2006, Timesys Corp., Thomas Gleixner - * - * This file contains the public data structure and API definitions. - */ - -#ifndef __LINUX_RT_MUTEX_H -#define __LINUX_RT_MUTEX_H - -#include -#include -#include - -extern int max_lock_depth; /* for sysctl */ - -/** - * The rt_mutex structure - * - * @wait_lock: spinlock to protect the structure - * @waiters: rbtree root to enqueue waiters in priority order - * @waiters_leftmost: top waiter - * @owner: the mutex owner - */ -struct rt_mutex { - raw_spinlock_t wait_lock; - struct rb_root waiters; - struct rb_node *waiters_leftmost; - struct task_struct *owner; -#ifdef CONFIG_DEBUG_RT_MUTEXES - int save_state; - const char *name, *file; - int line; - void *magic; -#endif -}; - -struct rt_mutex_waiter; -struct hrtimer_sleeper; - -#ifdef CONFIG_DEBUG_RT_MUTEXES - extern int rt_mutex_debug_check_no_locks_freed(const void *from, - unsigned long len); - extern void rt_mutex_debug_check_no_locks_held(struct task_struct *task); -#else - static inline int rt_mutex_debug_check_no_locks_freed(const void *from, - unsigned long len) - { - return 0; - } -# define rt_mutex_debug_check_no_locks_held(task) do { } while (0) -#endif - -#ifdef CONFIG_DEBUG_RT_MUTEXES -# define __DEBUG_RT_MUTEX_INITIALIZER(mutexname) \ - , .name = #mutexname, .file = __FILE__, .line = __LINE__ -# define rt_mutex_init(mutex) __rt_mutex_init(mutex, __func__) - extern void rt_mutex_debug_task_free(struct task_struct *tsk); -#else -# define __DEBUG_RT_MUTEX_INITIALIZER(mutexname) -# define rt_mutex_init(mutex) __rt_mutex_init(mutex, NULL) -# define rt_mutex_debug_task_free(t) do { } while (0) -#endif - -#define __RT_MUTEX_INITIALIZER(mutexname) \ - { .wait_lock = __RAW_SPIN_LOCK_UNLOCKED(mutexname.wait_lock) \ - , .waiters = RB_ROOT \ - , .owner = NULL \ - __DEBUG_RT_MUTEX_INITIALIZER(mutexname)} - -#define DEFINE_RT_MUTEX(mutexname) \ - struct rt_mutex mutexname = __RT_MUTEX_INITIALIZER(mutexname) - -/** - * rt_mutex_is_locked - is the mutex locked - * @lock: the mutex to be queried - * - * Returns 1 if the mutex is locked, 0 if unlocked. - */ -static inline int rt_mutex_is_locked(struct rt_mutex *lock) -{ - return lock->owner != NULL; -} - -extern void __rt_mutex_init(struct rt_mutex *lock, const char *name); -extern void rt_mutex_destroy(struct rt_mutex *lock); - -extern void rt_mutex_lock(struct rt_mutex *lock); -extern int rt_mutex_lock_interruptible(struct rt_mutex *lock); -extern int rt_mutex_timed_lock(struct rt_mutex *lock, - struct hrtimer_sleeper *timeout); - -extern int rt_mutex_trylock(struct rt_mutex *lock); - -extern void rt_mutex_unlock(struct rt_mutex *lock); - -#endif diff --git a/src/linux/include/linux/rtnetlink.h b/src/linux/include/linux/rtnetlink.h deleted file mode 100644 index 57e5484..0000000 --- a/src/linux/include/linux/rtnetlink.h +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef __LINUX_RTNETLINK_H -#define __LINUX_RTNETLINK_H - - -#include -#include -#include -#include - -extern int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, u32 group, int echo); -extern int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid); -extern void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, - u32 group, struct nlmsghdr *nlh, gfp_t flags); -extern void rtnl_set_sk_err(struct net *net, u32 group, int error); -extern int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics); -extern int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, - u32 id, long expires, u32 error); - -void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change, gfp_t flags); -struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev, - unsigned change, gfp_t flags); -void rtmsg_ifinfo_send(struct sk_buff *skb, struct net_device *dev, - gfp_t flags); - - -/* RTNL is used as a global lock for all changes to network configuration */ -extern void rtnl_lock(void); -extern void rtnl_unlock(void); -extern int rtnl_trylock(void); -extern int rtnl_is_locked(void); - -extern wait_queue_head_t netdev_unregistering_wq; -extern struct mutex net_mutex; - -#ifdef CONFIG_PROVE_LOCKING -extern bool lockdep_rtnl_is_held(void); -#else -static inline bool lockdep_rtnl_is_held(void) -{ - return true; -} -#endif /* #ifdef CONFIG_PROVE_LOCKING */ - -/** - * rcu_dereference_rtnl - rcu_dereference with debug checking - * @p: The pointer to read, prior to dereferencing - * - * Do an rcu_dereference(p), but check caller either holds rcu_read_lock() - * or RTNL. Note : Please prefer rtnl_dereference() or rcu_dereference() - */ -#define rcu_dereference_rtnl(p) \ - rcu_dereference_check(p, lockdep_rtnl_is_held()) - -/** - * rcu_dereference_bh_rtnl - rcu_dereference_bh with debug checking - * @p: The pointer to read, prior to dereference - * - * Do an rcu_dereference_bh(p), but check caller either holds rcu_read_lock_bh() - * or RTNL. Note : Please prefer rtnl_dereference() or rcu_dereference_bh() - */ -#define rcu_dereference_bh_rtnl(p) \ - rcu_dereference_bh_check(p, lockdep_rtnl_is_held()) - -/** - * rtnl_dereference - fetch RCU pointer when updates are prevented by RTNL - * @p: The pointer to read, prior to dereferencing - * - * Return the value of the specified RCU-protected pointer, but omit - * both the smp_read_barrier_depends() and the ACCESS_ONCE(), because - * caller holds RTNL. - */ -#define rtnl_dereference(p) \ - rcu_dereference_protected(p, lockdep_rtnl_is_held()) - -static inline struct netdev_queue *dev_ingress_queue(struct net_device *dev) -{ - return rtnl_dereference(dev->ingress_queue); -} - -struct netdev_queue *dev_ingress_queue_create(struct net_device *dev); - -#ifdef CONFIG_NET_INGRESS -void net_inc_ingress_queue(void); -void net_dec_ingress_queue(void); -#endif - -#ifdef CONFIG_NET_EGRESS -void net_inc_egress_queue(void); -void net_dec_egress_queue(void); -#endif - -void rtnetlink_init(void); -void __rtnl_unlock(void); -void rtnl_kfree_skbs(struct sk_buff *head, struct sk_buff *tail); - -#define ASSERT_RTNL() do { \ - if (unlikely(!rtnl_is_locked())) { \ - printk(KERN_ERR "RTNL: assertion failed at %s (%d)\n", \ - __FILE__, __LINE__); \ - dump_stack(); \ - } \ -} while(0) - -extern int ndo_dflt_fdb_dump(struct sk_buff *skb, - struct netlink_callback *cb, - struct net_device *dev, - struct net_device *filter_dev, - int *idx); -extern int ndo_dflt_fdb_add(struct ndmsg *ndm, - struct nlattr *tb[], - struct net_device *dev, - const unsigned char *addr, - u16 vid, - u16 flags); -extern int ndo_dflt_fdb_del(struct ndmsg *ndm, - struct nlattr *tb[], - struct net_device *dev, - const unsigned char *addr, - u16 vid); - -extern int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, - struct net_device *dev, u16 mode, - u32 flags, u32 mask, int nlflags, - u32 filter_mask, - int (*vlan_fill)(struct sk_buff *skb, - struct net_device *dev, - u32 filter_mask)); -#endif /* __LINUX_RTNETLINK_H */ diff --git a/src/linux/include/linux/rwlock.h b/src/linux/include/linux/rwlock.h deleted file mode 100644 index bc2994e..0000000 --- a/src/linux/include/linux/rwlock.h +++ /dev/null @@ -1,125 +0,0 @@ -#ifndef __LINUX_RWLOCK_H -#define __LINUX_RWLOCK_H - -#ifndef __LINUX_SPINLOCK_H -# error "please don't include this file directly" -#endif - -/* - * rwlock related methods - * - * split out from spinlock.h - * - * portions Copyright 2005, Red Hat, Inc., Ingo Molnar - * Released under the General Public License (GPL). - */ - -#ifdef CONFIG_DEBUG_SPINLOCK - extern void __rwlock_init(rwlock_t *lock, const char *name, - struct lock_class_key *key); -# define rwlock_init(lock) \ -do { \ - static struct lock_class_key __key; \ - \ - __rwlock_init((lock), #lock, &__key); \ -} while (0) -#else -# define rwlock_init(lock) \ - do { *(lock) = __RW_LOCK_UNLOCKED(lock); } while (0) -#endif - -#ifdef CONFIG_DEBUG_SPINLOCK - extern void do_raw_read_lock(rwlock_t *lock) __acquires(lock); -#define do_raw_read_lock_flags(lock, flags) do_raw_read_lock(lock) - extern int do_raw_read_trylock(rwlock_t *lock); - extern void do_raw_read_unlock(rwlock_t *lock) __releases(lock); - extern void do_raw_write_lock(rwlock_t *lock) __acquires(lock); -#define do_raw_write_lock_flags(lock, flags) do_raw_write_lock(lock) - extern int do_raw_write_trylock(rwlock_t *lock); - extern void do_raw_write_unlock(rwlock_t *lock) __releases(lock); -#else -# define do_raw_read_lock(rwlock) do {__acquire(lock); arch_read_lock(&(rwlock)->raw_lock); } while (0) -# define do_raw_read_lock_flags(lock, flags) \ - do {__acquire(lock); arch_read_lock_flags(&(lock)->raw_lock, *(flags)); } while (0) -# define do_raw_read_trylock(rwlock) arch_read_trylock(&(rwlock)->raw_lock) -# define do_raw_read_unlock(rwlock) do {arch_read_unlock(&(rwlock)->raw_lock); __release(lock); } while (0) -# define do_raw_write_lock(rwlock) do {__acquire(lock); arch_write_lock(&(rwlock)->raw_lock); } while (0) -# define do_raw_write_lock_flags(lock, flags) \ - do {__acquire(lock); arch_write_lock_flags(&(lock)->raw_lock, *(flags)); } while (0) -# define do_raw_write_trylock(rwlock) arch_write_trylock(&(rwlock)->raw_lock) -# define do_raw_write_unlock(rwlock) do {arch_write_unlock(&(rwlock)->raw_lock); __release(lock); } while (0) -#endif - -#define read_can_lock(rwlock) arch_read_can_lock(&(rwlock)->raw_lock) -#define write_can_lock(rwlock) arch_write_can_lock(&(rwlock)->raw_lock) - -/* - * Define the various rw_lock methods. Note we define these - * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The various - * methods are defined as nops in the case they are not required. - */ -#define read_trylock(lock) __cond_lock(lock, _raw_read_trylock(lock)) -#define write_trylock(lock) __cond_lock(lock, _raw_write_trylock(lock)) - -#define write_lock(lock) _raw_write_lock(lock) -#define read_lock(lock) _raw_read_lock(lock) - -#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) - -#define read_lock_irqsave(lock, flags) \ - do { \ - typecheck(unsigned long, flags); \ - flags = _raw_read_lock_irqsave(lock); \ - } while (0) -#define write_lock_irqsave(lock, flags) \ - do { \ - typecheck(unsigned long, flags); \ - flags = _raw_write_lock_irqsave(lock); \ - } while (0) - -#else - -#define read_lock_irqsave(lock, flags) \ - do { \ - typecheck(unsigned long, flags); \ - _raw_read_lock_irqsave(lock, flags); \ - } while (0) -#define write_lock_irqsave(lock, flags) \ - do { \ - typecheck(unsigned long, flags); \ - _raw_write_lock_irqsave(lock, flags); \ - } while (0) - -#endif - -#define read_lock_irq(lock) _raw_read_lock_irq(lock) -#define read_lock_bh(lock) _raw_read_lock_bh(lock) -#define write_lock_irq(lock) _raw_write_lock_irq(lock) -#define write_lock_bh(lock) _raw_write_lock_bh(lock) -#define read_unlock(lock) _raw_read_unlock(lock) -#define write_unlock(lock) _raw_write_unlock(lock) -#define read_unlock_irq(lock) _raw_read_unlock_irq(lock) -#define write_unlock_irq(lock) _raw_write_unlock_irq(lock) - -#define read_unlock_irqrestore(lock, flags) \ - do { \ - typecheck(unsigned long, flags); \ - _raw_read_unlock_irqrestore(lock, flags); \ - } while (0) -#define read_unlock_bh(lock) _raw_read_unlock_bh(lock) - -#define write_unlock_irqrestore(lock, flags) \ - do { \ - typecheck(unsigned long, flags); \ - _raw_write_unlock_irqrestore(lock, flags); \ - } while (0) -#define write_unlock_bh(lock) _raw_write_unlock_bh(lock) - -#define write_trylock_irqsave(lock, flags) \ -({ \ - local_irq_save(flags); \ - write_trylock(lock) ? \ - 1 : ({ local_irq_restore(flags); 0; }); \ -}) - -#endif /* __LINUX_RWLOCK_H */ diff --git a/src/linux/include/linux/rwlock_types.h b/src/linux/include/linux/rwlock_types.h deleted file mode 100644 index cc0072e..0000000 --- a/src/linux/include/linux/rwlock_types.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef __LINUX_RWLOCK_TYPES_H -#define __LINUX_RWLOCK_TYPES_H - -/* - * include/linux/rwlock_types.h - generic rwlock type definitions - * and initializers - * - * portions Copyright 2005, Red Hat, Inc., Ingo Molnar - * Released under the General Public License (GPL). - */ -typedef struct { - arch_rwlock_t raw_lock; -#ifdef CONFIG_GENERIC_LOCKBREAK - unsigned int break_lock; -#endif -#ifdef CONFIG_DEBUG_SPINLOCK - unsigned int magic, owner_cpu; - void *owner; -#endif -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map dep_map; -#endif -} rwlock_t; - -#define RWLOCK_MAGIC 0xdeaf1eed - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# define RW_DEP_MAP_INIT(lockname) .dep_map = { .name = #lockname } -#else -# define RW_DEP_MAP_INIT(lockname) -#endif - -#ifdef CONFIG_DEBUG_SPINLOCK -#define __RW_LOCK_UNLOCKED(lockname) \ - (rwlock_t) { .raw_lock = __ARCH_RW_LOCK_UNLOCKED, \ - .magic = RWLOCK_MAGIC, \ - .owner = SPINLOCK_OWNER_INIT, \ - .owner_cpu = -1, \ - RW_DEP_MAP_INIT(lockname) } -#else -#define __RW_LOCK_UNLOCKED(lockname) \ - (rwlock_t) { .raw_lock = __ARCH_RW_LOCK_UNLOCKED, \ - RW_DEP_MAP_INIT(lockname) } -#endif - -#define DEFINE_RWLOCK(x) rwlock_t x = __RW_LOCK_UNLOCKED(x) - -#endif /* __LINUX_RWLOCK_TYPES_H */ diff --git a/src/linux/include/linux/rwsem-spinlock.h b/src/linux/include/linux/rwsem-spinlock.h deleted file mode 100644 index ae0528b..0000000 --- a/src/linux/include/linux/rwsem-spinlock.h +++ /dev/null @@ -1,45 +0,0 @@ -/* rwsem-spinlock.h: fallback C implementation - * - * Copyright (c) 2001 David Howells (dhowells@redhat.com). - * - Derived partially from ideas by Andrea Arcangeli - * - Derived also from comments by Linus - */ - -#ifndef _LINUX_RWSEM_SPINLOCK_H -#define _LINUX_RWSEM_SPINLOCK_H - -#ifndef _LINUX_RWSEM_H -#error "please don't include linux/rwsem-spinlock.h directly, use linux/rwsem.h instead" -#endif - -#ifdef __KERNEL__ -/* - * the rw-semaphore definition - * - if count is 0 then there are no active readers or writers - * - if count is +ve then that is the number of active readers - * - if count is -1 then there is one active writer - * - if wait_list is not empty, then there are processes waiting for the semaphore - */ -struct rw_semaphore { - __s32 count; - raw_spinlock_t wait_lock; - struct list_head wait_list; -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map dep_map; -#endif -}; - -#define RWSEM_UNLOCKED_VALUE 0x00000000 - -extern void __down_read(struct rw_semaphore *sem); -extern int __down_read_trylock(struct rw_semaphore *sem); -extern void __down_write(struct rw_semaphore *sem); -extern int __must_check __down_write_killable(struct rw_semaphore *sem); -extern int __down_write_trylock(struct rw_semaphore *sem); -extern void __up_read(struct rw_semaphore *sem); -extern void __up_write(struct rw_semaphore *sem); -extern void __downgrade_write(struct rw_semaphore *sem); -extern int rwsem_is_locked(struct rw_semaphore *sem); - -#endif /* __KERNEL__ */ -#endif /* _LINUX_RWSEM_SPINLOCK_H */ diff --git a/src/linux/include/linux/rwsem.h b/src/linux/include/linux/rwsem.h deleted file mode 100644 index dd1d142..0000000 --- a/src/linux/include/linux/rwsem.h +++ /dev/null @@ -1,187 +0,0 @@ -/* rwsem.h: R/W semaphores, public interface - * - * Written by David Howells (dhowells@redhat.com). - * Derived from asm-i386/semaphore.h - */ - -#ifndef _LINUX_RWSEM_H -#define _LINUX_RWSEM_H - -#include - -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_RWSEM_SPIN_ON_OWNER -#include -#endif - -struct rw_semaphore; - -#ifdef CONFIG_RWSEM_GENERIC_SPINLOCK -#include /* use a generic implementation */ -#define __RWSEM_INIT_COUNT(name) .count = RWSEM_UNLOCKED_VALUE -#else -/* All arch specific implementations share the same struct */ -struct rw_semaphore { - atomic_long_t count; - struct list_head wait_list; - raw_spinlock_t wait_lock; -#ifdef CONFIG_RWSEM_SPIN_ON_OWNER - struct optimistic_spin_queue osq; /* spinner MCS lock */ - /* - * Write owner. Used as a speculative check to see - * if the owner is running on the cpu. - */ - struct task_struct *owner; -#endif -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map dep_map; -#endif -}; - -extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem); -extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem); -extern struct rw_semaphore *rwsem_down_write_failed_killable(struct rw_semaphore *sem); -extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *); -extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem); - -/* Include the arch specific part */ -#include - -/* In all implementations count != 0 means locked */ -static inline int rwsem_is_locked(struct rw_semaphore *sem) -{ - return atomic_long_read(&sem->count) != 0; -} - -#define __RWSEM_INIT_COUNT(name) .count = ATOMIC_LONG_INIT(RWSEM_UNLOCKED_VALUE) -#endif - -/* Common initializer macros and functions */ - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# define __RWSEM_DEP_MAP_INIT(lockname) , .dep_map = { .name = #lockname } -#else -# define __RWSEM_DEP_MAP_INIT(lockname) -#endif - -#ifdef CONFIG_RWSEM_SPIN_ON_OWNER -#define __RWSEM_OPT_INIT(lockname) , .osq = OSQ_LOCK_UNLOCKED, .owner = NULL -#else -#define __RWSEM_OPT_INIT(lockname) -#endif - -#define __RWSEM_INITIALIZER(name) \ - { __RWSEM_INIT_COUNT(name), \ - .wait_list = LIST_HEAD_INIT((name).wait_list), \ - .wait_lock = __RAW_SPIN_LOCK_UNLOCKED(name.wait_lock) \ - __RWSEM_OPT_INIT(name) \ - __RWSEM_DEP_MAP_INIT(name) } - -#define DECLARE_RWSEM(name) \ - struct rw_semaphore name = __RWSEM_INITIALIZER(name) - -extern void __init_rwsem(struct rw_semaphore *sem, const char *name, - struct lock_class_key *key); - -#define init_rwsem(sem) \ -do { \ - static struct lock_class_key __key; \ - \ - __init_rwsem((sem), #sem, &__key); \ -} while (0) - -/* - * This is the same regardless of which rwsem implementation that is being used. - * It is just a heuristic meant to be called by somebody alreadying holding the - * rwsem to see if somebody from an incompatible type is wanting access to the - * lock. - */ -static inline int rwsem_is_contended(struct rw_semaphore *sem) -{ - return !list_empty(&sem->wait_list); -} - -/* - * lock for reading - */ -extern void down_read(struct rw_semaphore *sem); - -/* - * trylock for reading -- returns 1 if successful, 0 if contention - */ -extern int down_read_trylock(struct rw_semaphore *sem); - -/* - * lock for writing - */ -extern void down_write(struct rw_semaphore *sem); -extern int __must_check down_write_killable(struct rw_semaphore *sem); - -/* - * trylock for writing -- returns 1 if successful, 0 if contention - */ -extern int down_write_trylock(struct rw_semaphore *sem); - -/* - * release a read lock - */ -extern void up_read(struct rw_semaphore *sem); - -/* - * release a write lock - */ -extern void up_write(struct rw_semaphore *sem); - -/* - * downgrade write lock to read lock - */ -extern void downgrade_write(struct rw_semaphore *sem); - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -/* - * nested locking. NOTE: rwsems are not allowed to recurse - * (which occurs if the same task tries to acquire the same - * lock instance multiple times), but multiple locks of the - * same lock class might be taken, if the order of the locks - * is always the same. This ordering rule can be expressed - * to lockdep via the _nested() APIs, but enumerating the - * subclasses that are used. (If the nesting relationship is - * static then another method for expressing nested locking is - * the explicit definition of lock class keys and the use of - * lockdep_set_class() at lock initialization time. - * See Documentation/locking/lockdep-design.txt for more details.) - */ -extern void down_read_nested(struct rw_semaphore *sem, int subclass); -extern void down_write_nested(struct rw_semaphore *sem, int subclass); -extern int down_write_killable_nested(struct rw_semaphore *sem, int subclass); -extern void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep_map *nest_lock); - -# define down_write_nest_lock(sem, nest_lock) \ -do { \ - typecheck(struct lockdep_map *, &(nest_lock)->dep_map); \ - _down_write_nest_lock(sem, &(nest_lock)->dep_map); \ -} while (0); - -/* - * Take/release a lock when not the owner will release it. - * - * [ This API should be avoided as much as possible - the - * proper abstraction for this case is completions. ] - */ -extern void down_read_non_owner(struct rw_semaphore *sem); -extern void up_read_non_owner(struct rw_semaphore *sem); -#else -# define down_read_nested(sem, subclass) down_read(sem) -# define down_write_nest_lock(sem, nest_lock) down_write(sem) -# define down_write_nested(sem, subclass) down_write(sem) -# define down_write_killable_nested(sem, subclass) down_write_killable(sem) -# define down_read_non_owner(sem) down_read(sem) -# define up_read_non_owner(sem) up_read(sem) -#endif - -#endif /* _LINUX_RWSEM_H */ diff --git a/src/linux/include/linux/sbitmap.h b/src/linux/include/linux/sbitmap.h deleted file mode 100644 index f017fd6..0000000 --- a/src/linux/include/linux/sbitmap.h +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Fast and scalable bitmaps. - * - * Copyright (C) 2016 Facebook - * Copyright (C) 2013-2014 Jens Axboe - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __LINUX_SCALE_BITMAP_H -#define __LINUX_SCALE_BITMAP_H - -#include -#include - -/** - * struct sbitmap_word - Word in a &struct sbitmap. - */ -struct sbitmap_word { - /** - * @word: The bitmap word itself. - */ - unsigned long word; - - /** - * @depth: Number of bits being used in @word. - */ - unsigned long depth; -} ____cacheline_aligned_in_smp; - -/** - * struct sbitmap - Scalable bitmap. - * - * A &struct sbitmap is spread over multiple cachelines to avoid ping-pong. This - * trades off higher memory usage for better scalability. - */ -struct sbitmap { - /** - * @depth: Number of bits used in the whole bitmap. - */ - unsigned int depth; - - /** - * @shift: log2(number of bits used per word) - */ - unsigned int shift; - - /** - * @map_nr: Number of words (cachelines) being used for the bitmap. - */ - unsigned int map_nr; - - /** - * @map: Allocated bitmap. - */ - struct sbitmap_word *map; -}; - -#define SBQ_WAIT_QUEUES 8 -#define SBQ_WAKE_BATCH 8 - -/** - * struct sbq_wait_state - Wait queue in a &struct sbitmap_queue. - */ -struct sbq_wait_state { - /** - * @wait_cnt: Number of frees remaining before we wake up. - */ - atomic_t wait_cnt; - - /** - * @wait: Wait queue. - */ - wait_queue_head_t wait; -} ____cacheline_aligned_in_smp; - -/** - * struct sbitmap_queue - Scalable bitmap with the added ability to wait on free - * bits. - * - * A &struct sbitmap_queue uses multiple wait queues and rolling wakeups to - * avoid contention on the wait queue spinlock. This ensures that we don't hit a - * scalability wall when we run out of free bits and have to start putting tasks - * to sleep. - */ -struct sbitmap_queue { - /** - * @sb: Scalable bitmap. - */ - struct sbitmap sb; - - /* - * @alloc_hint: Cache of last successfully allocated or freed bit. - * - * This is per-cpu, which allows multiple users to stick to different - * cachelines until the map is exhausted. - */ - unsigned int __percpu *alloc_hint; - - /** - * @wake_batch: Number of bits which must be freed before we wake up any - * waiters. - */ - unsigned int wake_batch; - - /** - * @wake_index: Next wait queue in @ws to wake up. - */ - atomic_t wake_index; - - /** - * @ws: Wait queues. - */ - struct sbq_wait_state *ws; - - /** - * @round_robin: Allocate bits in strict round-robin order. - */ - bool round_robin; -}; - -/** - * sbitmap_init_node() - Initialize a &struct sbitmap on a specific memory node. - * @sb: Bitmap to initialize. - * @depth: Number of bits to allocate. - * @shift: Use 2^@shift bits per word in the bitmap; if a negative number if - * given, a good default is chosen. - * @flags: Allocation flags. - * @node: Memory node to allocate on. - * - * Return: Zero on success or negative errno on failure. - */ -int sbitmap_init_node(struct sbitmap *sb, unsigned int depth, int shift, - gfp_t flags, int node); - -/** - * sbitmap_free() - Free memory used by a &struct sbitmap. - * @sb: Bitmap to free. - */ -static inline void sbitmap_free(struct sbitmap *sb) -{ - kfree(sb->map); - sb->map = NULL; -} - -/** - * sbitmap_resize() - Resize a &struct sbitmap. - * @sb: Bitmap to resize. - * @depth: New number of bits to resize to. - * - * Doesn't reallocate anything. It's up to the caller to ensure that the new - * depth doesn't exceed the depth that the sb was initialized with. - */ -void sbitmap_resize(struct sbitmap *sb, unsigned int depth); - -/** - * sbitmap_get() - Try to allocate a free bit from a &struct sbitmap. - * @sb: Bitmap to allocate from. - * @alloc_hint: Hint for where to start searching for a free bit. - * @round_robin: If true, be stricter about allocation order; always allocate - * starting from the last allocated bit. This is less efficient - * than the default behavior (false). - * - * Return: Non-negative allocated bit number if successful, -1 otherwise. - */ -int sbitmap_get(struct sbitmap *sb, unsigned int alloc_hint, bool round_robin); - -/** - * sbitmap_any_bit_set() - Check for a set bit in a &struct sbitmap. - * @sb: Bitmap to check. - * - * Return: true if any bit in the bitmap is set, false otherwise. - */ -bool sbitmap_any_bit_set(const struct sbitmap *sb); - -/** - * sbitmap_any_bit_clear() - Check for an unset bit in a &struct - * sbitmap. - * @sb: Bitmap to check. - * - * Return: true if any bit in the bitmap is clear, false otherwise. - */ -bool sbitmap_any_bit_clear(const struct sbitmap *sb); - -typedef bool (*sb_for_each_fn)(struct sbitmap *, unsigned int, void *); - -/** - * sbitmap_for_each_set() - Iterate over each set bit in a &struct sbitmap. - * @sb: Bitmap to iterate over. - * @fn: Callback. Should return true to continue or false to break early. - * @data: Pointer to pass to callback. - * - * This is inline even though it's non-trivial so that the function calls to the - * callback will hopefully get optimized away. - */ -static inline void sbitmap_for_each_set(struct sbitmap *sb, sb_for_each_fn fn, - void *data) -{ - unsigned int i; - - for (i = 0; i < sb->map_nr; i++) { - struct sbitmap_word *word = &sb->map[i]; - unsigned int off, nr; - - if (!word->word) - continue; - - nr = 0; - off = i << sb->shift; - while (1) { - nr = find_next_bit(&word->word, word->depth, nr); - if (nr >= word->depth) - break; - - if (!fn(sb, off + nr, data)) - return; - - nr++; - } - } -} - -#define SB_NR_TO_INDEX(sb, bitnr) ((bitnr) >> (sb)->shift) -#define SB_NR_TO_BIT(sb, bitnr) ((bitnr) & ((1U << (sb)->shift) - 1U)) - -static inline unsigned long *__sbitmap_word(struct sbitmap *sb, - unsigned int bitnr) -{ - return &sb->map[SB_NR_TO_INDEX(sb, bitnr)].word; -} - -/* Helpers equivalent to the operations in asm/bitops.h and linux/bitmap.h */ - -static inline void sbitmap_set_bit(struct sbitmap *sb, unsigned int bitnr) -{ - set_bit(SB_NR_TO_BIT(sb, bitnr), __sbitmap_word(sb, bitnr)); -} - -static inline void sbitmap_clear_bit(struct sbitmap *sb, unsigned int bitnr) -{ - clear_bit(SB_NR_TO_BIT(sb, bitnr), __sbitmap_word(sb, bitnr)); -} - -static inline int sbitmap_test_bit(struct sbitmap *sb, unsigned int bitnr) -{ - return test_bit(SB_NR_TO_BIT(sb, bitnr), __sbitmap_word(sb, bitnr)); -} - -unsigned int sbitmap_weight(const struct sbitmap *sb); - -/** - * sbitmap_queue_init_node() - Initialize a &struct sbitmap_queue on a specific - * memory node. - * @sbq: Bitmap queue to initialize. - * @depth: See sbitmap_init_node(). - * @shift: See sbitmap_init_node(). - * @round_robin: See sbitmap_get(). - * @flags: Allocation flags. - * @node: Memory node to allocate on. - * - * Return: Zero on success or negative errno on failure. - */ -int sbitmap_queue_init_node(struct sbitmap_queue *sbq, unsigned int depth, - int shift, bool round_robin, gfp_t flags, int node); - -/** - * sbitmap_queue_free() - Free memory used by a &struct sbitmap_queue. - * - * @sbq: Bitmap queue to free. - */ -static inline void sbitmap_queue_free(struct sbitmap_queue *sbq) -{ - kfree(sbq->ws); - free_percpu(sbq->alloc_hint); - sbitmap_free(&sbq->sb); -} - -/** - * sbitmap_queue_resize() - Resize a &struct sbitmap_queue. - * @sbq: Bitmap queue to resize. - * @depth: New number of bits to resize to. - * - * Like sbitmap_resize(), this doesn't reallocate anything. It has to do - * some extra work on the &struct sbitmap_queue, so it's not safe to just - * resize the underlying &struct sbitmap. - */ -void sbitmap_queue_resize(struct sbitmap_queue *sbq, unsigned int depth); - -/** - * __sbitmap_queue_get() - Try to allocate a free bit from a &struct - * sbitmap_queue with preemption already disabled. - * @sbq: Bitmap queue to allocate from. - * - * Return: Non-negative allocated bit number if successful, -1 otherwise. - */ -int __sbitmap_queue_get(struct sbitmap_queue *sbq); - -/** - * sbitmap_queue_get() - Try to allocate a free bit from a &struct - * sbitmap_queue. - * @sbq: Bitmap queue to allocate from. - * @cpu: Output parameter; will contain the CPU we ran on (e.g., to be passed to - * sbitmap_queue_clear()). - * - * Return: Non-negative allocated bit number if successful, -1 otherwise. - */ -static inline int sbitmap_queue_get(struct sbitmap_queue *sbq, - unsigned int *cpu) -{ - int nr; - - *cpu = get_cpu(); - nr = __sbitmap_queue_get(sbq); - put_cpu(); - return nr; -} - -/** - * sbitmap_queue_clear() - Free an allocated bit and wake up waiters on a - * &struct sbitmap_queue. - * @sbq: Bitmap to free from. - * @nr: Bit number to free. - * @cpu: CPU the bit was allocated on. - */ -void sbitmap_queue_clear(struct sbitmap_queue *sbq, unsigned int nr, - unsigned int cpu); - -static inline int sbq_index_inc(int index) -{ - return (index + 1) & (SBQ_WAIT_QUEUES - 1); -} - -static inline void sbq_index_atomic_inc(atomic_t *index) -{ - int old = atomic_read(index); - int new = sbq_index_inc(old); - atomic_cmpxchg(index, old, new); -} - -/** - * sbq_wait_ptr() - Get the next wait queue to use for a &struct - * sbitmap_queue. - * @sbq: Bitmap queue to wait on. - * @wait_index: A counter per "user" of @sbq. - */ -static inline struct sbq_wait_state *sbq_wait_ptr(struct sbitmap_queue *sbq, - atomic_t *wait_index) -{ - struct sbq_wait_state *ws; - - ws = &sbq->ws[atomic_read(wait_index)]; - sbq_index_atomic_inc(wait_index); - return ws; -} - -/** - * sbitmap_queue_wake_all() - Wake up everything waiting on a &struct - * sbitmap_queue. - * @sbq: Bitmap queue to wake up. - */ -void sbitmap_queue_wake_all(struct sbitmap_queue *sbq); - -#endif /* __LINUX_SCALE_BITMAP_H */ diff --git a/src/linux/include/linux/scatterlist.h b/src/linux/include/linux/scatterlist.h deleted file mode 100644 index cb3c8fe..0000000 --- a/src/linux/include/linux/scatterlist.h +++ /dev/null @@ -1,407 +0,0 @@ -#ifndef _LINUX_SCATTERLIST_H -#define _LINUX_SCATTERLIST_H - -#include -#include -#include -#include -#include - -struct scatterlist { -#ifdef CONFIG_DEBUG_SG - unsigned long sg_magic; -#endif - unsigned long page_link; - unsigned int offset; - unsigned int length; - dma_addr_t dma_address; -#ifdef CONFIG_NEED_SG_DMA_LENGTH - unsigned int dma_length; -#endif -}; - -/* - * These macros should be used after a dma_map_sg call has been done - * to get bus addresses of each of the SG entries and their lengths. - * You should only work with the number of sg entries dma_map_sg - * returns, or alternatively stop on the first sg_dma_len(sg) which - * is 0. - */ -#define sg_dma_address(sg) ((sg)->dma_address) - -#ifdef CONFIG_NEED_SG_DMA_LENGTH -#define sg_dma_len(sg) ((sg)->dma_length) -#else -#define sg_dma_len(sg) ((sg)->length) -#endif - -struct sg_table { - struct scatterlist *sgl; /* the list */ - unsigned int nents; /* number of mapped entries */ - unsigned int orig_nents; /* original size of list */ -}; - -/* - * Notes on SG table design. - * - * We use the unsigned long page_link field in the scatterlist struct to place - * the page pointer AND encode information about the sg table as well. The two - * lower bits are reserved for this information. - * - * If bit 0 is set, then the page_link contains a pointer to the next sg - * table list. Otherwise the next entry is at sg + 1. - * - * If bit 1 is set, then this sg entry is the last element in a list. - * - * See sg_next(). - * - */ - -#define SG_MAGIC 0x87654321 - -/* - * We overload the LSB of the page pointer to indicate whether it's - * a valid sg entry, or whether it points to the start of a new scatterlist. - * Those low bits are there for everyone! (thanks mason :-) - */ -#define sg_is_chain(sg) ((sg)->page_link & 0x01) -#define sg_is_last(sg) ((sg)->page_link & 0x02) -#define sg_chain_ptr(sg) \ - ((struct scatterlist *) ((sg)->page_link & ~0x03)) - -/** - * sg_assign_page - Assign a given page to an SG entry - * @sg: SG entry - * @page: The page - * - * Description: - * Assign page to sg entry. Also see sg_set_page(), the most commonly used - * variant. - * - **/ -static inline void sg_assign_page(struct scatterlist *sg, struct page *page) -{ - unsigned long page_link = sg->page_link & 0x3; - - /* - * In order for the low bit stealing approach to work, pages - * must be aligned at a 32-bit boundary as a minimum. - */ - BUG_ON((unsigned long) page & 0x03); -#ifdef CONFIG_DEBUG_SG - BUG_ON(sg->sg_magic != SG_MAGIC); - BUG_ON(sg_is_chain(sg)); -#endif - sg->page_link = page_link | (unsigned long) page; -} - -/** - * sg_set_page - Set sg entry to point at given page - * @sg: SG entry - * @page: The page - * @len: Length of data - * @offset: Offset into page - * - * Description: - * Use this function to set an sg entry pointing at a page, never assign - * the page directly. We encode sg table information in the lower bits - * of the page pointer. See sg_page() for looking up the page belonging - * to an sg entry. - * - **/ -static inline void sg_set_page(struct scatterlist *sg, struct page *page, - unsigned int len, unsigned int offset) -{ - sg_assign_page(sg, page); - sg->offset = offset; - sg->length = len; -} - -static inline struct page *sg_page(struct scatterlist *sg) -{ -#ifdef CONFIG_DEBUG_SG - BUG_ON(sg->sg_magic != SG_MAGIC); - BUG_ON(sg_is_chain(sg)); -#endif - return (struct page *)((sg)->page_link & ~0x3); -} - -/** - * sg_set_buf - Set sg entry to point at given data - * @sg: SG entry - * @buf: Data - * @buflen: Data length - * - **/ -static inline void sg_set_buf(struct scatterlist *sg, const void *buf, - unsigned int buflen) -{ -#ifdef CONFIG_DEBUG_SG - BUG_ON(!virt_addr_valid(buf)); -#endif - sg_set_page(sg, virt_to_page(buf), buflen, offset_in_page(buf)); -} - -/* - * Loop over each sg element, following the pointer to a new list if necessary - */ -#define for_each_sg(sglist, sg, nr, __i) \ - for (__i = 0, sg = (sglist); __i < (nr); __i++, sg = sg_next(sg)) - -/** - * sg_chain - Chain two sglists together - * @prv: First scatterlist - * @prv_nents: Number of entries in prv - * @sgl: Second scatterlist - * - * Description: - * Links @prv@ and @sgl@ together, to form a longer scatterlist. - * - **/ -static inline void sg_chain(struct scatterlist *prv, unsigned int prv_nents, - struct scatterlist *sgl) -{ - /* - * offset and length are unused for chain entry. Clear them. - */ - prv[prv_nents - 1].offset = 0; - prv[prv_nents - 1].length = 0; - - /* - * Set lowest bit to indicate a link pointer, and make sure to clear - * the termination bit if it happens to be set. - */ - prv[prv_nents - 1].page_link = ((unsigned long) sgl | 0x01) & ~0x02; -} - -/** - * sg_mark_end - Mark the end of the scatterlist - * @sg: SG entryScatterlist - * - * Description: - * Marks the passed in sg entry as the termination point for the sg - * table. A call to sg_next() on this entry will return NULL. - * - **/ -static inline void sg_mark_end(struct scatterlist *sg) -{ -#ifdef CONFIG_DEBUG_SG - BUG_ON(sg->sg_magic != SG_MAGIC); -#endif - /* - * Set termination bit, clear potential chain bit - */ - sg->page_link |= 0x02; - sg->page_link &= ~0x01; -} - -/** - * sg_unmark_end - Undo setting the end of the scatterlist - * @sg: SG entryScatterlist - * - * Description: - * Removes the termination marker from the given entry of the scatterlist. - * - **/ -static inline void sg_unmark_end(struct scatterlist *sg) -{ -#ifdef CONFIG_DEBUG_SG - BUG_ON(sg->sg_magic != SG_MAGIC); -#endif - sg->page_link &= ~0x02; -} - -/** - * sg_phys - Return physical address of an sg entry - * @sg: SG entry - * - * Description: - * This calls page_to_phys() on the page in this sg entry, and adds the - * sg offset. The caller must know that it is legal to call page_to_phys() - * on the sg page. - * - **/ -static inline dma_addr_t sg_phys(struct scatterlist *sg) -{ - return page_to_phys(sg_page(sg)) + sg->offset; -} - -/** - * sg_virt - Return virtual address of an sg entry - * @sg: SG entry - * - * Description: - * This calls page_address() on the page in this sg entry, and adds the - * sg offset. The caller must know that the sg page has a valid virtual - * mapping. - * - **/ -static inline void *sg_virt(struct scatterlist *sg) -{ - return page_address(sg_page(sg)) + sg->offset; -} - -int sg_nents(struct scatterlist *sg); -int sg_nents_for_len(struct scatterlist *sg, u64 len); -struct scatterlist *sg_next(struct scatterlist *); -struct scatterlist *sg_last(struct scatterlist *s, unsigned int); -void sg_init_table(struct scatterlist *, unsigned int); -void sg_init_one(struct scatterlist *, const void *, unsigned int); -int sg_split(struct scatterlist *in, const int in_mapped_nents, - const off_t skip, const int nb_splits, - const size_t *split_sizes, - struct scatterlist **out, int *out_mapped_nents, - gfp_t gfp_mask); - -typedef struct scatterlist *(sg_alloc_fn)(unsigned int, gfp_t); -typedef void (sg_free_fn)(struct scatterlist *, unsigned int); - -void __sg_free_table(struct sg_table *, unsigned int, bool, sg_free_fn *); -void sg_free_table(struct sg_table *); -int __sg_alloc_table(struct sg_table *, unsigned int, unsigned int, - struct scatterlist *, gfp_t, sg_alloc_fn *); -int sg_alloc_table(struct sg_table *, unsigned int, gfp_t); -int sg_alloc_table_from_pages(struct sg_table *sgt, - struct page **pages, unsigned int n_pages, - unsigned long offset, unsigned long size, - gfp_t gfp_mask); - -size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, void *buf, - size_t buflen, off_t skip, bool to_buffer); - -size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents, - const void *buf, size_t buflen); -size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents, - void *buf, size_t buflen); - -size_t sg_pcopy_from_buffer(struct scatterlist *sgl, unsigned int nents, - const void *buf, size_t buflen, off_t skip); -size_t sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents, - void *buf, size_t buflen, off_t skip); - -/* - * Maximum number of entries that will be allocated in one piece, if - * a list larger than this is required then chaining will be utilized. - */ -#define SG_MAX_SINGLE_ALLOC (PAGE_SIZE / sizeof(struct scatterlist)) - -/* - * The maximum number of SG segments that we will put inside a - * scatterlist (unless chaining is used). Should ideally fit inside a - * single page, to avoid a higher order allocation. We could define this - * to SG_MAX_SINGLE_ALLOC to pack correctly at the highest order. The - * minimum value is 32 - */ -#define SG_CHUNK_SIZE 128 - -/* - * Like SG_CHUNK_SIZE, but for archs that have sg chaining. This limit - * is totally arbitrary, a setting of 2048 will get you at least 8mb ios. - */ -#ifdef CONFIG_ARCH_HAS_SG_CHAIN -#define SG_MAX_SEGMENTS 2048 -#else -#define SG_MAX_SEGMENTS SG_CHUNK_SIZE -#endif - -#ifdef CONFIG_SG_POOL -void sg_free_table_chained(struct sg_table *table, bool first_chunk); -int sg_alloc_table_chained(struct sg_table *table, int nents, - struct scatterlist *first_chunk); -#endif - -/* - * sg page iterator - * - * Iterates over sg entries page-by-page. On each successful iteration, - * you can call sg_page_iter_page(@piter) and sg_page_iter_dma_address(@piter) - * to get the current page and its dma address. @piter->sg will point to the - * sg holding this page and @piter->sg_pgoffset to the page's page offset - * within the sg. The iteration will stop either when a maximum number of sg - * entries was reached or a terminating sg (sg_last(sg) == true) was reached. - */ -struct sg_page_iter { - struct scatterlist *sg; /* sg holding the page */ - unsigned int sg_pgoffset; /* page offset within the sg */ - - /* these are internal states, keep away */ - unsigned int __nents; /* remaining sg entries */ - int __pg_advance; /* nr pages to advance at the - * next step */ -}; - -bool __sg_page_iter_next(struct sg_page_iter *piter); -void __sg_page_iter_start(struct sg_page_iter *piter, - struct scatterlist *sglist, unsigned int nents, - unsigned long pgoffset); -/** - * sg_page_iter_page - get the current page held by the page iterator - * @piter: page iterator holding the page - */ -static inline struct page *sg_page_iter_page(struct sg_page_iter *piter) -{ - return nth_page(sg_page(piter->sg), piter->sg_pgoffset); -} - -/** - * sg_page_iter_dma_address - get the dma address of the current page held by - * the page iterator. - * @piter: page iterator holding the page - */ -static inline dma_addr_t sg_page_iter_dma_address(struct sg_page_iter *piter) -{ - return sg_dma_address(piter->sg) + (piter->sg_pgoffset << PAGE_SHIFT); -} - -/** - * for_each_sg_page - iterate over the pages of the given sg list - * @sglist: sglist to iterate over - * @piter: page iterator to hold current page, sg, sg_pgoffset - * @nents: maximum number of sg entries to iterate over - * @pgoffset: starting page offset - */ -#define for_each_sg_page(sglist, piter, nents, pgoffset) \ - for (__sg_page_iter_start((piter), (sglist), (nents), (pgoffset)); \ - __sg_page_iter_next(piter);) - -/* - * Mapping sg iterator - * - * Iterates over sg entries mapping page-by-page. On each successful - * iteration, @miter->page points to the mapped page and - * @miter->length bytes of data can be accessed at @miter->addr. As - * long as an interation is enclosed between start and stop, the user - * is free to choose control structure and when to stop. - * - * @miter->consumed is set to @miter->length on each iteration. It - * can be adjusted if the user can't consume all the bytes in one go. - * Also, a stopped iteration can be resumed by calling next on it. - * This is useful when iteration needs to release all resources and - * continue later (e.g. at the next interrupt). - */ - -#define SG_MITER_ATOMIC (1 << 0) /* use kmap_atomic */ -#define SG_MITER_TO_SG (1 << 1) /* flush back to phys on unmap */ -#define SG_MITER_FROM_SG (1 << 2) /* nop */ - -struct sg_mapping_iter { - /* the following three fields can be accessed directly */ - struct page *page; /* currently mapped page */ - void *addr; /* pointer to the mapped area */ - size_t length; /* length of the mapped area */ - size_t consumed; /* number of consumed bytes */ - struct sg_page_iter piter; /* page iterator */ - - /* these are internal states, keep away */ - unsigned int __offset; /* offset within page */ - unsigned int __remaining; /* remaining bytes on page */ - unsigned int __flags; -}; - -void sg_miter_start(struct sg_mapping_iter *miter, struct scatterlist *sgl, - unsigned int nents, unsigned int flags); -bool sg_miter_skip(struct sg_mapping_iter *miter, off_t offset); -bool sg_miter_next(struct sg_mapping_iter *miter); -void sg_miter_stop(struct sg_mapping_iter *miter); - -#endif /* _LINUX_SCATTERLIST_H */ diff --git a/src/linux/include/linux/sched.h b/src/linux/include/linux/sched.h deleted file mode 100644 index e9c009d..0000000 --- a/src/linux/include/linux/sched.h +++ /dev/null @@ -1,3610 +0,0 @@ -#ifndef _LINUX_SCHED_H -#define _LINUX_SCHED_H - -#include - -#include - - -struct sched_param { - int sched_priority; -}; - -#include /* for HZ */ - -#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 -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define SCHED_ATTR_SIZE_VER0 48 /* sizeof first published struct */ - -/* - * Extended scheduling parameters data structure. - * - * This is needed because the original struct sched_param can not be - * altered without introducing ABI issues with legacy applications - * (e.g., in sched_getparam()). - * - * However, the possibility of specifying more than just a priority for - * the tasks may be useful for a wide variety of application fields, e.g., - * multimedia, streaming, automation and control, and many others. - * - * This variant (sched_attr) is meant at describing a so-called - * sporadic time-constrained task. In such model a task is specified by: - * - the activation period or minimum instance inter-arrival time; - * - the maximum (or average, depending on the actual scheduling - * discipline) computation time of all instances, a.k.a. runtime; - * - the deadline (relative to the actual activation time) of each - * instance. - * Very briefly, a periodic (sporadic) task asks for the execution of - * some specific computation --which is typically called an instance-- - * (at most) every period. Moreover, each instance typically lasts no more - * than the runtime and must be completed by time instant t equal to - * the instance activation time + the deadline. - * - * This is reflected by the actual fields of the sched_attr structure: - * - * @size size of the structure, for fwd/bwd compat. - * - * @sched_policy task's scheduling policy - * @sched_flags for customizing the scheduler behaviour - * @sched_nice task's nice value (SCHED_NORMAL/BATCH) - * @sched_priority task's static priority (SCHED_FIFO/RR) - * @sched_deadline representative of the task's deadline - * @sched_runtime representative of the task's runtime - * @sched_period representative of the task's period - * - * Given this task model, there are a multiplicity of scheduling algorithms - * and policies, that can be used to ensure all the tasks will make their - * timing constraints. - * - * As of now, the SCHED_DEADLINE policy (sched_dl scheduling class) is the - * only user of this new interface. More information about the algorithm - * available in the scheduling class file or in Documentation/. - */ -struct sched_attr { - u32 size; - - u32 sched_policy; - u64 sched_flags; - - /* SCHED_NORMAL, SCHED_BATCH */ - s32 sched_nice; - - /* SCHED_FIFO, SCHED_RR */ - u32 sched_priority; - - /* SCHED_DEADLINE */ - u64 sched_runtime; - u64 sched_deadline; - u64 sched_period; -}; - -struct futex_pi_state; -struct robust_list_head; -struct bio_list; -struct fs_struct; -struct perf_event_context; -struct blk_plug; -struct filename; -struct nameidata; - -#define VMACACHE_BITS 2 -#define VMACACHE_SIZE (1U << VMACACHE_BITS) -#define VMACACHE_MASK (VMACACHE_SIZE - 1) - -/* - * These are the constant used to fake the fixed-point load-average - * counting. Some notes: - * - 11 bit fractions expand to 22 bits by the multiplies: this gives - * a load-average precision of 10 bits integer + 11 bits fractional - * - if you want to count load-averages more often, you need more - * precision, or rounding will get you. With 2-second counting freq, - * the EXP_n values would be 1981, 2034 and 2043 if still using only - * 11 bit fractions. - */ -extern unsigned long avenrun[]; /* Load averages */ -extern void get_avenrun(unsigned long *loads, unsigned long offset, int shift); - -#define FSHIFT 11 /* nr of bits of precision */ -#define FIXED_1 (1<>= FSHIFT; - -extern unsigned long total_forks; -extern int nr_threads; -DECLARE_PER_CPU(unsigned long, process_counts); -extern int nr_processes(void); -extern unsigned long nr_running(void); -extern bool single_task_running(void); -extern unsigned long nr_iowait(void); -extern unsigned long nr_iowait_cpu(int cpu); -extern void get_iowait_load(unsigned long *nr_waiters, unsigned long *load); - -extern void calc_global_load(unsigned long ticks); - -#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON) -extern void cpu_load_update_nohz_start(void); -extern void cpu_load_update_nohz_stop(void); -#else -static inline void cpu_load_update_nohz_start(void) { } -static inline void cpu_load_update_nohz_stop(void) { } -#endif - -extern void dump_cpu_task(int cpu); - -struct seq_file; -struct cfs_rq; -struct task_group; -#ifdef CONFIG_SCHED_DEBUG -extern void proc_sched_show_task(struct task_struct *p, struct seq_file *m); -extern void proc_sched_set_task(struct task_struct *p); -#endif - -/* - * Task state bitmask. NOTE! These bits are also - * encoded in fs/proc/array.c: get_task_state(). - * - * We have two separate sets of flags: task->state - * is about runnability, while task->exit_state are - * about the task exiting. Confusing, but this way - * modifying one set can't modify the other one by - * mistake. - */ -#define TASK_RUNNING 0 -#define TASK_INTERRUPTIBLE 1 -#define TASK_UNINTERRUPTIBLE 2 -#define __TASK_STOPPED 4 -#define __TASK_TRACED 8 -/* in tsk->exit_state */ -#define EXIT_DEAD 16 -#define EXIT_ZOMBIE 32 -#define EXIT_TRACE (EXIT_ZOMBIE | EXIT_DEAD) -/* in tsk->state again */ -#define TASK_DEAD 64 -#define TASK_WAKEKILL 128 -#define TASK_WAKING 256 -#define TASK_PARKED 512 -#define TASK_NOLOAD 1024 -#define TASK_NEW 2048 -#define TASK_STATE_MAX 4096 - -#define TASK_STATE_TO_CHAR_STR "RSDTtXZxKWPNn" - -extern char ___assert_task_state[1 - 2*!!( - sizeof(TASK_STATE_TO_CHAR_STR)-1 != ilog2(TASK_STATE_MAX)+1)]; - -/* Convenience macros for the sake of set_task_state */ -#define TASK_KILLABLE (TASK_WAKEKILL | TASK_UNINTERRUPTIBLE) -#define TASK_STOPPED (TASK_WAKEKILL | __TASK_STOPPED) -#define TASK_TRACED (TASK_WAKEKILL | __TASK_TRACED) - -#define TASK_IDLE (TASK_UNINTERRUPTIBLE | TASK_NOLOAD) - -/* Convenience macros for the sake of wake_up */ -#define TASK_NORMAL (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE) -#define TASK_ALL (TASK_NORMAL | __TASK_STOPPED | __TASK_TRACED) - -/* get_task_state() */ -#define TASK_REPORT (TASK_RUNNING | TASK_INTERRUPTIBLE | \ - TASK_UNINTERRUPTIBLE | __TASK_STOPPED | \ - __TASK_TRACED | EXIT_ZOMBIE | EXIT_DEAD) - -#define task_is_traced(task) ((task->state & __TASK_TRACED) != 0) -#define task_is_stopped(task) ((task->state & __TASK_STOPPED) != 0) -#define task_is_stopped_or_traced(task) \ - ((task->state & (__TASK_STOPPED | __TASK_TRACED)) != 0) -#define task_contributes_to_load(task) \ - ((task->state & TASK_UNINTERRUPTIBLE) != 0 && \ - (task->flags & PF_FROZEN) == 0 && \ - (task->state & TASK_NOLOAD) == 0) - -#ifdef CONFIG_DEBUG_ATOMIC_SLEEP - -#define __set_task_state(tsk, state_value) \ - do { \ - (tsk)->task_state_change = _THIS_IP_; \ - (tsk)->state = (state_value); \ - } while (0) -#define set_task_state(tsk, state_value) \ - do { \ - (tsk)->task_state_change = _THIS_IP_; \ - smp_store_mb((tsk)->state, (state_value)); \ - } while (0) - -/* - * set_current_state() includes a barrier so that the write of current->state - * is correctly serialised wrt the caller's subsequent test of whether to - * actually sleep: - * - * set_current_state(TASK_UNINTERRUPTIBLE); - * if (do_i_need_to_sleep()) - * schedule(); - * - * If the caller does not need such serialisation then use __set_current_state() - */ -#define __set_current_state(state_value) \ - do { \ - current->task_state_change = _THIS_IP_; \ - current->state = (state_value); \ - } while (0) -#define set_current_state(state_value) \ - do { \ - current->task_state_change = _THIS_IP_; \ - smp_store_mb(current->state, (state_value)); \ - } while (0) - -#else - -#define __set_task_state(tsk, state_value) \ - do { (tsk)->state = (state_value); } while (0) -#define set_task_state(tsk, state_value) \ - smp_store_mb((tsk)->state, (state_value)) - -/* - * set_current_state() includes a barrier so that the write of current->state - * is correctly serialised wrt the caller's subsequent test of whether to - * actually sleep: - * - * set_current_state(TASK_UNINTERRUPTIBLE); - * if (do_i_need_to_sleep()) - * schedule(); - * - * If the caller does not need such serialisation then use __set_current_state() - */ -#define __set_current_state(state_value) \ - do { current->state = (state_value); } while (0) -#define set_current_state(state_value) \ - smp_store_mb(current->state, (state_value)) - -#endif - -/* Task command name length */ -#define TASK_COMM_LEN 16 - -#include - -/* - * This serializes "schedule()" and also protects - * the run-queue from deletions/modifications (but - * _adding_ to the beginning of the run-queue has - * a separate lock). - */ -extern rwlock_t tasklist_lock; -extern spinlock_t mmlist_lock; - -struct task_struct; - -#ifdef CONFIG_PROVE_RCU -extern int lockdep_tasklist_lock_is_held(void); -#endif /* #ifdef CONFIG_PROVE_RCU */ - -extern void sched_init(void); -extern void sched_init_smp(void); -extern asmlinkage void schedule_tail(struct task_struct *prev); -extern void init_idle(struct task_struct *idle, int cpu); -extern void init_idle_bootup_task(struct task_struct *idle); - -extern cpumask_var_t cpu_isolated_map; - -extern int runqueue_is_locked(int cpu); - -#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON) -extern void nohz_balance_enter_idle(int cpu); -extern void set_cpu_sd_state_idle(void); -extern int get_nohz_timer_target(void); -#else -static inline void nohz_balance_enter_idle(int cpu) { } -static inline void set_cpu_sd_state_idle(void) { } -#endif - -/* - * Only dump TASK_* tasks. (0 for all tasks) - */ -extern void show_state_filter(unsigned long state_filter); - -static inline void show_state(void) -{ - show_state_filter(0); -} - -extern void show_regs(struct pt_regs *); - -/* - * TASK is a pointer to the task whose backtrace we want to see (or NULL for current - * task), SP is the stack pointer of the first frame that should be shown in the back - * trace (or NULL if the entire call-chain of the task should be shown). - */ -extern void show_stack(struct task_struct *task, unsigned long *sp); - -extern void cpu_init (void); -extern void trap_init(void); -extern void update_process_times(int user); -extern void scheduler_tick(void); -extern int sched_cpu_starting(unsigned int cpu); -extern int sched_cpu_activate(unsigned int cpu); -extern int sched_cpu_deactivate(unsigned int cpu); - -#ifdef CONFIG_HOTPLUG_CPU -extern int sched_cpu_dying(unsigned int cpu); -#else -# define sched_cpu_dying NULL -#endif - -extern void sched_show_task(struct task_struct *p); - -#ifdef CONFIG_LOCKUP_DETECTOR -extern void touch_softlockup_watchdog_sched(void); -extern void touch_softlockup_watchdog(void); -extern void touch_softlockup_watchdog_sync(void); -extern void touch_all_softlockup_watchdogs(void); -extern int proc_dowatchdog_thresh(struct ctl_table *table, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos); -extern unsigned int softlockup_panic; -extern unsigned int hardlockup_panic; -void lockup_detector_init(void); -#else -static inline void touch_softlockup_watchdog_sched(void) -{ -} -static inline void touch_softlockup_watchdog(void) -{ -} -static inline void touch_softlockup_watchdog_sync(void) -{ -} -static inline void touch_all_softlockup_watchdogs(void) -{ -} -static inline void lockup_detector_init(void) -{ -} -#endif - -#ifdef CONFIG_DETECT_HUNG_TASK -void reset_hung_task_detector(void); -#else -static inline void reset_hung_task_detector(void) -{ -} -#endif - -/* Attach to any functions which should be ignored in wchan output. */ -#define __sched __attribute__((__section__(".sched.text"))) - -/* Linker adds these: start and end of __sched functions */ -extern char __sched_text_start[], __sched_text_end[]; - -/* Is this address in the __sched functions? */ -extern int in_sched_functions(unsigned long addr); - -#define MAX_SCHEDULE_TIMEOUT LONG_MAX -extern signed long schedule_timeout(signed long timeout); -extern signed long schedule_timeout_interruptible(signed long timeout); -extern signed long schedule_timeout_killable(signed long timeout); -extern signed long schedule_timeout_uninterruptible(signed long timeout); -extern signed long schedule_timeout_idle(signed long timeout); -asmlinkage void schedule(void); -extern void schedule_preempt_disabled(void); - -extern long io_schedule_timeout(long timeout); - -static inline void io_schedule(void) -{ - io_schedule_timeout(MAX_SCHEDULE_TIMEOUT); -} - -void __noreturn do_task_dead(void); - -struct nsproxy; -struct user_namespace; - -#ifdef CONFIG_MMU -extern void arch_pick_mmap_layout(struct mm_struct *mm); -extern unsigned long -arch_get_unmapped_area(struct file *, unsigned long, unsigned long, - unsigned long, unsigned long); -extern unsigned long -arch_get_unmapped_area_topdown(struct file *filp, unsigned long addr, - unsigned long len, unsigned long pgoff, - unsigned long flags); -#else -static inline void arch_pick_mmap_layout(struct mm_struct *mm) {} -#endif - -#define SUID_DUMP_DISABLE 0 /* No setuid dumping */ -#define SUID_DUMP_USER 1 /* Dump as user of process */ -#define SUID_DUMP_ROOT 2 /* Dump as root */ - -/* mm flags */ - -/* for SUID_DUMP_* above */ -#define MMF_DUMPABLE_BITS 2 -#define MMF_DUMPABLE_MASK ((1 << MMF_DUMPABLE_BITS) - 1) - -extern void set_dumpable(struct mm_struct *mm, int value); -/* - * This returns the actual value of the suid_dumpable flag. For things - * that are using this for checking for privilege transitions, it must - * test against SUID_DUMP_USER rather than treating it as a boolean - * value. - */ -static inline int __get_dumpable(unsigned long mm_flags) -{ - return mm_flags & MMF_DUMPABLE_MASK; -} - -static inline int get_dumpable(struct mm_struct *mm) -{ - return __get_dumpable(mm->flags); -} - -/* coredump filter bits */ -#define MMF_DUMP_ANON_PRIVATE 2 -#define MMF_DUMP_ANON_SHARED 3 -#define MMF_DUMP_MAPPED_PRIVATE 4 -#define MMF_DUMP_MAPPED_SHARED 5 -#define MMF_DUMP_ELF_HEADERS 6 -#define MMF_DUMP_HUGETLB_PRIVATE 7 -#define MMF_DUMP_HUGETLB_SHARED 8 -#define MMF_DUMP_DAX_PRIVATE 9 -#define MMF_DUMP_DAX_SHARED 10 - -#define MMF_DUMP_FILTER_SHIFT MMF_DUMPABLE_BITS -#define MMF_DUMP_FILTER_BITS 9 -#define MMF_DUMP_FILTER_MASK \ - (((1 << MMF_DUMP_FILTER_BITS) - 1) << MMF_DUMP_FILTER_SHIFT) -#define MMF_DUMP_FILTER_DEFAULT \ - ((1 << MMF_DUMP_ANON_PRIVATE) | (1 << MMF_DUMP_ANON_SHARED) |\ - (1 << MMF_DUMP_HUGETLB_PRIVATE) | MMF_DUMP_MASK_DEFAULT_ELF) - -#ifdef CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS -# define MMF_DUMP_MASK_DEFAULT_ELF (1 << MMF_DUMP_ELF_HEADERS) -#else -# define MMF_DUMP_MASK_DEFAULT_ELF 0 -#endif - /* leave room for more dump flags */ -#define MMF_VM_MERGEABLE 16 /* KSM may merge identical pages */ -#define MMF_VM_HUGEPAGE 17 /* set when VM_HUGEPAGE is set on vma */ -#define MMF_EXE_FILE_CHANGED 18 /* see prctl_set_mm_exe_file() */ - -#define MMF_HAS_UPROBES 19 /* has uprobes */ -#define MMF_RECALC_UPROBES 20 /* MMF_HAS_UPROBES can be wrong */ -#define MMF_OOM_SKIP 21 /* mm is of no interest for the OOM killer */ -#define MMF_UNSTABLE 22 /* mm is unstable for copy_from_user */ -#define MMF_HUGE_ZERO_PAGE 23 /* mm has ever used the global huge zero page */ - -#define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK) - -struct sighand_struct { - atomic_t count; - struct k_sigaction action[_NSIG]; - spinlock_t siglock; - wait_queue_head_t signalfd_wqh; -}; - -struct pacct_struct { - int ac_flag; - long ac_exitcode; - unsigned long ac_mem; - cputime_t ac_utime, ac_stime; - unsigned long ac_minflt, ac_majflt; -}; - -struct cpu_itimer { - cputime_t expires; - cputime_t incr; - u32 error; - u32 incr_error; -}; - -/** - * struct prev_cputime - snaphsot of system and user cputime - * @utime: time spent in user mode - * @stime: time spent in system mode - * @lock: protects the above two fields - * - * Stores previous user/system time values such that we can guarantee - * monotonicity. - */ -struct prev_cputime { -#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE - cputime_t utime; - cputime_t stime; - raw_spinlock_t lock; -#endif -}; - -static inline void prev_cputime_init(struct prev_cputime *prev) -{ -#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE - prev->utime = prev->stime = 0; - raw_spin_lock_init(&prev->lock); -#endif -} - -/** - * struct task_cputime - collected CPU time counts - * @utime: time spent in user mode, in &cputime_t units - * @stime: time spent in kernel mode, in &cputime_t units - * @sum_exec_runtime: total time spent on the CPU, in nanoseconds - * - * This structure groups together three kinds of CPU time that are tracked for - * threads and thread groups. Most things considering CPU time want to group - * these counts together and treat all three of them in parallel. - */ -struct task_cputime { - cputime_t utime; - cputime_t stime; - unsigned long long sum_exec_runtime; -}; - -/* Alternate field names when used to cache expirations. */ -#define virt_exp utime -#define prof_exp stime -#define sched_exp sum_exec_runtime - -#define INIT_CPUTIME \ - (struct task_cputime) { \ - .utime = 0, \ - .stime = 0, \ - .sum_exec_runtime = 0, \ - } - -/* - * This is the atomic variant of task_cputime, which can be used for - * storing and updating task_cputime statistics without locking. - */ -struct task_cputime_atomic { - atomic64_t utime; - atomic64_t stime; - atomic64_t sum_exec_runtime; -}; - -#define INIT_CPUTIME_ATOMIC \ - (struct task_cputime_atomic) { \ - .utime = ATOMIC64_INIT(0), \ - .stime = ATOMIC64_INIT(0), \ - .sum_exec_runtime = ATOMIC64_INIT(0), \ - } - -#define PREEMPT_DISABLED (PREEMPT_DISABLE_OFFSET + PREEMPT_ENABLED) - -/* - * Disable preemption until the scheduler is running -- use an unconditional - * value so that it also works on !PREEMPT_COUNT kernels. - * - * Reset by start_kernel()->sched_init()->init_idle()->init_idle_preempt_count(). - */ -#define INIT_PREEMPT_COUNT PREEMPT_OFFSET - -/* - * Initial preempt_count value; reflects the preempt_count schedule invariant - * which states that during context switches: - * - * preempt_count() == 2*PREEMPT_DISABLE_OFFSET - * - * Note: PREEMPT_DISABLE_OFFSET is 0 for !PREEMPT_COUNT kernels. - * Note: See finish_task_switch(). - */ -#define FORK_PREEMPT_COUNT (2*PREEMPT_DISABLE_OFFSET + PREEMPT_ENABLED) - -/** - * struct thread_group_cputimer - thread group interval timer counts - * @cputime_atomic: atomic thread group interval timers. - * @running: true when there are timers running and - * @cputime_atomic receives updates. - * @checking_timer: true when a thread in the group is in the - * process of checking for thread group timers. - * - * This structure contains the version of task_cputime, above, that is - * used for thread group CPU timer calculations. - */ -struct thread_group_cputimer { - struct task_cputime_atomic cputime_atomic; - bool running; - bool checking_timer; -}; - -#include -struct autogroup; - -/* - * NOTE! "signal_struct" does not have its own - * locking, because a shared signal_struct always - * implies a shared sighand_struct, so locking - * sighand_struct is always a proper superset of - * the locking of signal_struct. - */ -struct signal_struct { - atomic_t sigcnt; - atomic_t live; - int nr_threads; - struct list_head thread_head; - - wait_queue_head_t wait_chldexit; /* for wait4() */ - - /* current thread group signal load-balancing target: */ - struct task_struct *curr_target; - - /* shared signal handling: */ - struct sigpending shared_pending; - - /* thread group exit support */ - int group_exit_code; - /* overloaded: - * - notify group_exit_task when ->count is equal to notify_count - * - everyone except group_exit_task is stopped during signal delivery - * of fatal signals, group_exit_task processes the signal. - */ - int notify_count; - struct task_struct *group_exit_task; - - /* thread group stop support, overloads group_exit_code too */ - int group_stop_count; - unsigned int flags; /* see SIGNAL_* flags below */ - - /* - * PR_SET_CHILD_SUBREAPER marks a process, like a service - * manager, to re-parent orphan (double-forking) child processes - * to this process instead of 'init'. The service manager is - * able to receive SIGCHLD signals and is able to investigate - * the process until it calls wait(). All children of this - * process will inherit a flag if they should look for a - * child_subreaper process at exit. - */ - unsigned int is_child_subreaper:1; - unsigned int has_child_subreaper:1; - - /* POSIX.1b Interval Timers */ - int posix_timer_id; - struct list_head posix_timers; - - /* ITIMER_REAL timer for the process */ - struct hrtimer real_timer; - struct pid *leader_pid; - ktime_t it_real_incr; - - /* - * ITIMER_PROF and ITIMER_VIRTUAL timers for the process, we use - * CPUCLOCK_PROF and CPUCLOCK_VIRT for indexing array as these - * values are defined to 0 and 1 respectively - */ - struct cpu_itimer it[2]; - - /* - * Thread group totals for process CPU timers. - * See thread_group_cputimer(), et al, for details. - */ - struct thread_group_cputimer cputimer; - - /* Earliest-expiration cache. */ - struct task_cputime cputime_expires; - -#ifdef CONFIG_NO_HZ_FULL - atomic_t tick_dep_mask; -#endif - - struct list_head cpu_timers[3]; - - struct pid *tty_old_pgrp; - - /* boolean value for session group leader */ - int leader; - - struct tty_struct *tty; /* NULL if no tty */ - -#ifdef CONFIG_SCHED_AUTOGROUP - struct autogroup *autogroup; -#endif - /* - * Cumulative resource counters for dead threads in the group, - * and for reaped dead child processes forked by this group. - * Live threads maintain their own counters and add to these - * in __exit_signal, except for the group leader. - */ - seqlock_t stats_lock; - cputime_t utime, stime, cutime, cstime; - cputime_t gtime; - cputime_t cgtime; - struct prev_cputime prev_cputime; - unsigned long nvcsw, nivcsw, cnvcsw, cnivcsw; - unsigned long min_flt, maj_flt, cmin_flt, cmaj_flt; - unsigned long inblock, oublock, cinblock, coublock; - unsigned long maxrss, cmaxrss; - struct task_io_accounting ioac; - - /* - * Cumulative ns of schedule CPU time fo dead threads in the - * group, not including a zombie group leader, (This only differs - * from jiffies_to_ns(utime + stime) if sched_clock uses something - * other than jiffies.) - */ - unsigned long long sum_sched_runtime; - - /* - * We don't bother to synchronize most readers of this at all, - * because there is no reader checking a limit that actually needs - * to get both rlim_cur and rlim_max atomically, and either one - * alone is a single word that can safely be read normally. - * getrlimit/setrlimit use task_lock(current->group_leader) to - * protect this instead of the siglock, because they really - * have no need to disable irqs. - */ - struct rlimit rlim[RLIM_NLIMITS]; - -#ifdef CONFIG_BSD_PROCESS_ACCT - struct pacct_struct pacct; /* per-process accounting information */ -#endif -#ifdef CONFIG_TASKSTATS - struct taskstats *stats; -#endif -#ifdef CONFIG_AUDIT - unsigned audit_tty; - struct tty_audit_buf *tty_audit_buf; -#endif - - /* - * Thread is the potential origin of an oom condition; kill first on - * oom - */ - bool oom_flag_origin; - short oom_score_adj; /* OOM kill score adjustment */ - short oom_score_adj_min; /* OOM kill score adjustment min value. - * Only settable by CAP_SYS_RESOURCE. */ - struct mm_struct *oom_mm; /* recorded mm when the thread group got - * killed by the oom killer */ - - struct mutex cred_guard_mutex; /* guard against foreign influences on - * credential calculations - * (notably. ptrace) */ -}; - -/* - * Bits in flags field of signal_struct. - */ -#define SIGNAL_STOP_STOPPED 0x00000001 /* job control stop in effect */ -#define SIGNAL_STOP_CONTINUED 0x00000002 /* SIGCONT since WCONTINUED reap */ -#define SIGNAL_GROUP_EXIT 0x00000004 /* group exit in progress */ -#define SIGNAL_GROUP_COREDUMP 0x00000008 /* coredump in progress */ -/* - * Pending notifications to parent. - */ -#define SIGNAL_CLD_STOPPED 0x00000010 -#define SIGNAL_CLD_CONTINUED 0x00000020 -#define SIGNAL_CLD_MASK (SIGNAL_CLD_STOPPED|SIGNAL_CLD_CONTINUED) - -#define SIGNAL_UNKILLABLE 0x00000040 /* for init: ignore fatal signals */ - -/* If true, all threads except ->group_exit_task have pending SIGKILL */ -static inline int signal_group_exit(const struct signal_struct *sig) -{ - return (sig->flags & SIGNAL_GROUP_EXIT) || - (sig->group_exit_task != NULL); -} - -/* - * Some day this will be a full-fledged user tracking system.. - */ -struct user_struct { - atomic_t __count; /* reference count */ - atomic_t processes; /* How many processes does this user have? */ - atomic_t sigpending; /* How many pending signals does this user have? */ -#ifdef CONFIG_INOTIFY_USER - atomic_t inotify_watches; /* How many inotify watches does this user have? */ - atomic_t inotify_devs; /* How many inotify devs does this user have opened? */ -#endif -#ifdef CONFIG_FANOTIFY - atomic_t fanotify_listeners; -#endif -#ifdef CONFIG_EPOLL - atomic_long_t epoll_watches; /* The number of file descriptors currently watched */ -#endif -#ifdef CONFIG_POSIX_MQUEUE - /* protected by mq_lock */ - unsigned long mq_bytes; /* How many bytes can be allocated to mqueue? */ -#endif - unsigned long locked_shm; /* How many pages of mlocked shm ? */ - unsigned long unix_inflight; /* How many files in flight in unix sockets */ - atomic_long_t pipe_bufs; /* how many pages are allocated in pipe buffers */ - -#ifdef CONFIG_KEYS - struct key *uid_keyring; /* UID specific keyring */ - struct key *session_keyring; /* UID's default session keyring */ -#endif - - /* Hash table maintenance information */ - struct hlist_node uidhash_node; - kuid_t uid; - -#if defined(CONFIG_PERF_EVENTS) || defined(CONFIG_BPF_SYSCALL) - atomic_long_t locked_vm; -#endif -}; - -extern int uids_sysfs_init(void); - -extern struct user_struct *find_user(kuid_t); - -extern struct user_struct root_user; -#define INIT_USER (&root_user) - - -struct backing_dev_info; -struct reclaim_state; - -#ifdef CONFIG_SCHED_INFO -struct sched_info { - /* cumulative counters */ - unsigned long pcount; /* # of times run on this cpu */ - unsigned long long run_delay; /* time spent waiting on a runqueue */ - - /* timestamps */ - unsigned long long last_arrival,/* when we last ran on a cpu */ - last_queued; /* when we were last queued to run */ -}; -#endif /* CONFIG_SCHED_INFO */ - -#ifdef CONFIG_TASK_DELAY_ACCT -struct task_delay_info { - spinlock_t lock; - unsigned int flags; /* Private per-task flags */ - - /* For each stat XXX, add following, aligned appropriately - * - * struct timespec XXX_start, XXX_end; - * u64 XXX_delay; - * u32 XXX_count; - * - * Atomicity of updates to XXX_delay, XXX_count protected by - * single lock above (split into XXX_lock if contention is an issue). - */ - - /* - * XXX_count is incremented on every XXX operation, the delay - * associated with the operation is added to XXX_delay. - * XXX_delay contains the accumulated delay time in nanoseconds. - */ - u64 blkio_start; /* Shared by blkio, swapin */ - u64 blkio_delay; /* wait for sync block io completion */ - u64 swapin_delay; /* wait for swapin block io completion */ - u32 blkio_count; /* total count of the number of sync block */ - /* io operations performed */ - u32 swapin_count; /* total count of the number of swapin block */ - /* io operations performed */ - - u64 freepages_start; - u64 freepages_delay; /* wait for memory reclaim */ - u32 freepages_count; /* total count of memory reclaim */ -}; -#endif /* CONFIG_TASK_DELAY_ACCT */ - -static inline int sched_info_on(void) -{ -#ifdef CONFIG_SCHEDSTATS - return 1; -#elif defined(CONFIG_TASK_DELAY_ACCT) - extern int delayacct_on; - return delayacct_on; -#else - return 0; -#endif -} - -#ifdef CONFIG_SCHEDSTATS -void force_schedstat_enabled(void); -#endif - -enum cpu_idle_type { - CPU_IDLE, - CPU_NOT_IDLE, - CPU_NEWLY_IDLE, - CPU_MAX_IDLE_TYPES -}; - -/* - * Integer metrics need fixed point arithmetic, e.g., sched/fair - * has a few: load, load_avg, util_avg, freq, and capacity. - * - * We define a basic fixed point arithmetic range, and then formalize - * all these metrics based on that basic range. - */ -# define SCHED_FIXEDPOINT_SHIFT 10 -# define SCHED_FIXEDPOINT_SCALE (1L << SCHED_FIXEDPOINT_SHIFT) - -/* - * Increase resolution of cpu_capacity calculations - */ -#define SCHED_CAPACITY_SHIFT SCHED_FIXEDPOINT_SHIFT -#define SCHED_CAPACITY_SCALE (1L << SCHED_CAPACITY_SHIFT) - -/* - * Wake-queues are lists of tasks with a pending wakeup, whose - * callers have already marked the task as woken internally, - * and can thus carry on. A common use case is being able to - * do the wakeups once the corresponding user lock as been - * released. - * - * We hold reference to each task in the list across the wakeup, - * thus guaranteeing that the memory is still valid by the time - * the actual wakeups are performed in wake_up_q(). - * - * One per task suffices, because there's never a need for a task to be - * in two wake queues simultaneously; it is forbidden to abandon a task - * in a wake queue (a call to wake_up_q() _must_ follow), so if a task is - * already in a wake queue, the wakeup will happen soon and the second - * waker can just skip it. - * - * The WAKE_Q macro declares and initializes the list head. - * wake_up_q() does NOT reinitialize the list; it's expected to be - * called near the end of a function, where the fact that the queue is - * not used again will be easy to see by inspection. - * - * Note that this can cause spurious wakeups. schedule() callers - * must ensure the call is done inside a loop, confirming that the - * wakeup condition has in fact occurred. - */ -struct wake_q_node { - struct wake_q_node *next; -}; - -struct wake_q_head { - struct wake_q_node *first; - struct wake_q_node **lastp; -}; - -#define WAKE_Q_TAIL ((struct wake_q_node *) 0x01) - -#define WAKE_Q(name) \ - struct wake_q_head name = { WAKE_Q_TAIL, &name.first } - -extern void wake_q_add(struct wake_q_head *head, - struct task_struct *task); -extern void wake_up_q(struct wake_q_head *head); - -/* - * sched-domains (multiprocessor balancing) declarations: - */ -#ifdef CONFIG_SMP -#define SD_LOAD_BALANCE 0x0001 /* Do load balancing on this domain. */ -#define SD_BALANCE_NEWIDLE 0x0002 /* Balance when about to become idle */ -#define SD_BALANCE_EXEC 0x0004 /* Balance on exec */ -#define SD_BALANCE_FORK 0x0008 /* Balance on fork, clone */ -#define SD_BALANCE_WAKE 0x0010 /* Balance on wakeup */ -#define SD_WAKE_AFFINE 0x0020 /* Wake task to waking CPU */ -#define SD_ASYM_CPUCAPACITY 0x0040 /* Groups have different max cpu capacities */ -#define SD_SHARE_CPUCAPACITY 0x0080 /* Domain members share cpu capacity */ -#define SD_SHARE_POWERDOMAIN 0x0100 /* Domain members share power domain */ -#define SD_SHARE_PKG_RESOURCES 0x0200 /* Domain members share cpu pkg resources */ -#define SD_SERIALIZE 0x0400 /* Only a single load balancing instance */ -#define SD_ASYM_PACKING 0x0800 /* Place busy groups earlier in the domain */ -#define SD_PREFER_SIBLING 0x1000 /* Prefer to place tasks in a sibling domain */ -#define SD_OVERLAP 0x2000 /* sched_domains of this level overlap */ -#define SD_NUMA 0x4000 /* cross-node balancing */ - -#ifdef CONFIG_SCHED_SMT -static inline int cpu_smt_flags(void) -{ - return SD_SHARE_CPUCAPACITY | SD_SHARE_PKG_RESOURCES; -} -#endif - -#ifdef CONFIG_SCHED_MC -static inline int cpu_core_flags(void) -{ - return SD_SHARE_PKG_RESOURCES; -} -#endif - -#ifdef CONFIG_NUMA -static inline int cpu_numa_flags(void) -{ - return SD_NUMA; -} -#endif - -struct sched_domain_attr { - int relax_domain_level; -}; - -#define SD_ATTR_INIT (struct sched_domain_attr) { \ - .relax_domain_level = -1, \ -} - -extern int sched_domain_level_max; - -struct sched_group; - -struct sched_domain_shared { - atomic_t ref; - atomic_t nr_busy_cpus; - int has_idle_cores; -}; - -struct sched_domain { - /* These fields must be setup */ - struct sched_domain *parent; /* top domain must be null terminated */ - struct sched_domain *child; /* bottom domain must be null terminated */ - struct sched_group *groups; /* the balancing groups of the domain */ - unsigned long min_interval; /* Minimum balance interval ms */ - unsigned long max_interval; /* Maximum balance interval ms */ - unsigned int busy_factor; /* less balancing by factor if busy */ - unsigned int imbalance_pct; /* No balance until over watermark */ - unsigned int cache_nice_tries; /* Leave cache hot tasks for # tries */ - unsigned int busy_idx; - unsigned int idle_idx; - unsigned int newidle_idx; - unsigned int wake_idx; - unsigned int forkexec_idx; - unsigned int smt_gain; - - int nohz_idle; /* NOHZ IDLE status */ - int flags; /* See SD_* */ - int level; - - /* Runtime fields. */ - unsigned long last_balance; /* init to jiffies. units in jiffies */ - unsigned int balance_interval; /* initialise to 1. units in ms. */ - unsigned int nr_balance_failed; /* initialise to 0 */ - - /* idle_balance() stats */ - u64 max_newidle_lb_cost; - unsigned long next_decay_max_lb_cost; - - u64 avg_scan_cost; /* select_idle_sibling */ - -#ifdef CONFIG_SCHEDSTATS - /* load_balance() stats */ - unsigned int lb_count[CPU_MAX_IDLE_TYPES]; - unsigned int lb_failed[CPU_MAX_IDLE_TYPES]; - unsigned int lb_balanced[CPU_MAX_IDLE_TYPES]; - unsigned int lb_imbalance[CPU_MAX_IDLE_TYPES]; - unsigned int lb_gained[CPU_MAX_IDLE_TYPES]; - unsigned int lb_hot_gained[CPU_MAX_IDLE_TYPES]; - unsigned int lb_nobusyg[CPU_MAX_IDLE_TYPES]; - unsigned int lb_nobusyq[CPU_MAX_IDLE_TYPES]; - - /* Active load balancing */ - unsigned int alb_count; - unsigned int alb_failed; - unsigned int alb_pushed; - - /* SD_BALANCE_EXEC stats */ - unsigned int sbe_count; - unsigned int sbe_balanced; - unsigned int sbe_pushed; - - /* SD_BALANCE_FORK stats */ - unsigned int sbf_count; - unsigned int sbf_balanced; - unsigned int sbf_pushed; - - /* try_to_wake_up() stats */ - unsigned int ttwu_wake_remote; - unsigned int ttwu_move_affine; - unsigned int ttwu_move_balance; -#endif -#ifdef CONFIG_SCHED_DEBUG - char *name; -#endif - union { - void *private; /* used during construction */ - struct rcu_head rcu; /* used during destruction */ - }; - struct sched_domain_shared *shared; - - unsigned int span_weight; - /* - * Span of all CPUs in this domain. - * - * NOTE: this field is variable length. (Allocated dynamically - * by attaching extra space to the end of the structure, - * depending on how many CPUs the kernel has booted up with) - */ - unsigned long span[0]; -}; - -static inline struct cpumask *sched_domain_span(struct sched_domain *sd) -{ - return to_cpumask(sd->span); -} - -extern void partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[], - struct sched_domain_attr *dattr_new); - -/* Allocate an array of sched domains, for partition_sched_domains(). */ -cpumask_var_t *alloc_sched_domains(unsigned int ndoms); -void free_sched_domains(cpumask_var_t doms[], unsigned int ndoms); - -bool cpus_share_cache(int this_cpu, int that_cpu); - -typedef const struct cpumask *(*sched_domain_mask_f)(int cpu); -typedef int (*sched_domain_flags_f)(void); - -#define SDTL_OVERLAP 0x01 - -struct sd_data { - struct sched_domain **__percpu sd; - struct sched_domain_shared **__percpu sds; - struct sched_group **__percpu sg; - struct sched_group_capacity **__percpu sgc; -}; - -struct sched_domain_topology_level { - sched_domain_mask_f mask; - sched_domain_flags_f sd_flags; - int flags; - int numa_level; - struct sd_data data; -#ifdef CONFIG_SCHED_DEBUG - char *name; -#endif -}; - -extern void set_sched_topology(struct sched_domain_topology_level *tl); -extern void wake_up_if_idle(int cpu); - -#ifdef CONFIG_SCHED_DEBUG -# define SD_INIT_NAME(type) .name = #type -#else -# define SD_INIT_NAME(type) -#endif - -#else /* CONFIG_SMP */ - -struct sched_domain_attr; - -static inline void -partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[], - struct sched_domain_attr *dattr_new) -{ -} - -static inline bool cpus_share_cache(int this_cpu, int that_cpu) -{ - return true; -} - -#endif /* !CONFIG_SMP */ - - -struct io_context; /* See blkdev.h */ - - -#ifdef ARCH_HAS_PREFETCH_SWITCH_STACK -extern void prefetch_stack(struct task_struct *t); -#else -static inline void prefetch_stack(struct task_struct *t) { } -#endif - -struct audit_context; /* See audit.c */ -struct mempolicy; -struct pipe_inode_info; -struct uts_namespace; - -struct load_weight { - unsigned long weight; - u32 inv_weight; -}; - -/* - * The load_avg/util_avg accumulates an infinite geometric series - * (see __update_load_avg() in kernel/sched/fair.c). - * - * [load_avg definition] - * - * load_avg = runnable% * scale_load_down(load) - * - * where runnable% is the time ratio that a sched_entity is runnable. - * For cfs_rq, it is the aggregated load_avg of all runnable and - * blocked sched_entities. - * - * load_avg may also take frequency scaling into account: - * - * load_avg = runnable% * scale_load_down(load) * freq% - * - * where freq% is the CPU frequency normalized to the highest frequency. - * - * [util_avg definition] - * - * util_avg = running% * SCHED_CAPACITY_SCALE - * - * where running% is the time ratio that a sched_entity is running on - * a CPU. For cfs_rq, it is the aggregated util_avg of all runnable - * and blocked sched_entities. - * - * util_avg may also factor frequency scaling and CPU capacity scaling: - * - * util_avg = running% * SCHED_CAPACITY_SCALE * freq% * capacity% - * - * where freq% is the same as above, and capacity% is the CPU capacity - * normalized to the greatest capacity (due to uarch differences, etc). - * - * N.B., the above ratios (runnable%, running%, freq%, and capacity%) - * themselves are in the range of [0, 1]. To do fixed point arithmetics, - * we therefore scale them to as large a range as necessary. This is for - * example reflected by util_avg's SCHED_CAPACITY_SCALE. - * - * [Overflow issue] - * - * The 64-bit load_sum can have 4353082796 (=2^64/47742/88761) entities - * with the highest load (=88761), always runnable on a single cfs_rq, - * and should not overflow as the number already hits PID_MAX_LIMIT. - * - * For all other cases (including 32-bit kernels), struct load_weight's - * weight will overflow first before we do, because: - * - * Max(load_avg) <= Max(load.weight) - * - * Then it is the load_weight's responsibility to consider overflow - * issues. - */ -struct sched_avg { - u64 last_update_time, load_sum; - u32 util_sum, period_contrib; - unsigned long load_avg, util_avg; -}; - -#ifdef CONFIG_SCHEDSTATS -struct sched_statistics { - u64 wait_start; - u64 wait_max; - u64 wait_count; - u64 wait_sum; - u64 iowait_count; - u64 iowait_sum; - - u64 sleep_start; - u64 sleep_max; - s64 sum_sleep_runtime; - - u64 block_start; - u64 block_max; - u64 exec_max; - u64 slice_max; - - u64 nr_migrations_cold; - u64 nr_failed_migrations_affine; - u64 nr_failed_migrations_running; - u64 nr_failed_migrations_hot; - u64 nr_forced_migrations; - - u64 nr_wakeups; - u64 nr_wakeups_sync; - u64 nr_wakeups_migrate; - u64 nr_wakeups_local; - u64 nr_wakeups_remote; - u64 nr_wakeups_affine; - u64 nr_wakeups_affine_attempts; - u64 nr_wakeups_passive; - u64 nr_wakeups_idle; -}; -#endif - -struct sched_entity { - struct load_weight load; /* for load-balancing */ - struct rb_node run_node; - struct list_head group_node; - unsigned int on_rq; - - u64 exec_start; - u64 sum_exec_runtime; - u64 vruntime; - u64 prev_sum_exec_runtime; - - u64 nr_migrations; - -#ifdef CONFIG_SCHEDSTATS - struct sched_statistics statistics; -#endif - -#ifdef CONFIG_FAIR_GROUP_SCHED - int depth; - struct sched_entity *parent; - /* rq on which this entity is (to be) queued: */ - struct cfs_rq *cfs_rq; - /* rq "owned" by this entity/group: */ - struct cfs_rq *my_q; -#endif - -#ifdef CONFIG_SMP - /* - * Per entity load average tracking. - * - * Put into separate cache line so it does not - * collide with read-mostly values above. - */ - struct sched_avg avg ____cacheline_aligned_in_smp; -#endif -}; - -struct sched_rt_entity { - struct list_head run_list; - unsigned long timeout; - unsigned long watchdog_stamp; - unsigned int time_slice; - unsigned short on_rq; - unsigned short on_list; - - struct sched_rt_entity *back; -#ifdef CONFIG_RT_GROUP_SCHED - struct sched_rt_entity *parent; - /* rq on which this entity is (to be) queued: */ - struct rt_rq *rt_rq; - /* rq "owned" by this entity/group: */ - struct rt_rq *my_q; -#endif -}; - -struct sched_dl_entity { - struct rb_node rb_node; - - /* - * Original scheduling parameters. Copied here from sched_attr - * during sched_setattr(), they will remain the same until - * the next sched_setattr(). - */ - u64 dl_runtime; /* maximum runtime for each instance */ - u64 dl_deadline; /* relative deadline of each instance */ - u64 dl_period; /* separation of two instances (period) */ - u64 dl_bw; /* dl_runtime / dl_deadline */ - - /* - * Actual scheduling parameters. Initialized with the values above, - * they are continously updated during task execution. Note that - * the remaining runtime could be < 0 in case we are in overrun. - */ - s64 runtime; /* remaining runtime for this instance */ - u64 deadline; /* absolute deadline for this instance */ - unsigned int flags; /* specifying the scheduler behaviour */ - - /* - * Some bool flags: - * - * @dl_throttled tells if we exhausted the runtime. If so, the - * task has to wait for a replenishment to be performed at the - * next firing of dl_timer. - * - * @dl_boosted tells if we are boosted due to DI. If so we are - * outside bandwidth enforcement mechanism (but only until we - * exit the critical section); - * - * @dl_yielded tells if task gave up the cpu before consuming - * all its available runtime during the last job. - */ - int dl_throttled, dl_boosted, dl_yielded; - - /* - * Bandwidth enforcement timer. Each -deadline task has its - * own bandwidth to be enforced, thus we need one timer per task. - */ - struct hrtimer dl_timer; -}; - -union rcu_special { - struct { - u8 blocked; - u8 need_qs; - u8 exp_need_qs; - u8 pad; /* Otherwise the compiler can store garbage here. */ - } b; /* Bits. */ - u32 s; /* Set of bits. */ -}; -struct rcu_node; - -enum perf_event_task_context { - perf_invalid_context = -1, - perf_hw_context = 0, - perf_sw_context, - perf_nr_task_contexts, -}; - -/* Track pages that require TLB flushes */ -struct tlbflush_unmap_batch { - /* - * Each bit set is a CPU that potentially has a TLB entry for one of - * the PFNs being flushed. See set_tlb_ubc_flush_pending(). - */ - struct cpumask cpumask; - - /* True if any bit in cpumask is set */ - bool flush_required; - - /* - * If true then the PTE was dirty when unmapped. The entry must be - * flushed before IO is initiated or a stale TLB entry potentially - * allows an update without redirtying the page. - */ - bool writable; -}; - -struct task_struct { -#ifdef CONFIG_THREAD_INFO_IN_TASK - /* - * For reasons of header soup (see current_thread_info()), this - * must be the first element of task_struct. - */ - struct thread_info thread_info; -#endif - volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ - void *stack; - atomic_t usage; - unsigned int flags; /* per process flags, defined below */ - unsigned int ptrace; - -#ifdef CONFIG_SMP - struct llist_node wake_entry; - int on_cpu; -#ifdef CONFIG_THREAD_INFO_IN_TASK - unsigned int cpu; /* current CPU */ -#endif - unsigned int wakee_flips; - unsigned long wakee_flip_decay_ts; - struct task_struct *last_wakee; - - int wake_cpu; -#endif - int on_rq; - - int prio, static_prio, normal_prio; - unsigned int rt_priority; - const struct sched_class *sched_class; - struct sched_entity se; - struct sched_rt_entity rt; -#ifdef CONFIG_CGROUP_SCHED - struct task_group *sched_task_group; -#endif - struct sched_dl_entity dl; - -#ifdef CONFIG_PREEMPT_NOTIFIERS - /* list of struct preempt_notifier: */ - struct hlist_head preempt_notifiers; -#endif - -#ifdef CONFIG_BLK_DEV_IO_TRACE - unsigned int btrace_seq; -#endif - - unsigned int policy; - int nr_cpus_allowed; - cpumask_t cpus_allowed; - -#ifdef CONFIG_PREEMPT_RCU - int rcu_read_lock_nesting; - union rcu_special rcu_read_unlock_special; - struct list_head rcu_node_entry; - struct rcu_node *rcu_blocked_node; -#endif /* #ifdef CONFIG_PREEMPT_RCU */ -#ifdef CONFIG_TASKS_RCU - unsigned long rcu_tasks_nvcsw; - bool rcu_tasks_holdout; - struct list_head rcu_tasks_holdout_list; - int rcu_tasks_idle_cpu; -#endif /* #ifdef CONFIG_TASKS_RCU */ - -#ifdef CONFIG_SCHED_INFO - struct sched_info sched_info; -#endif - - struct list_head tasks; -#ifdef CONFIG_SMP - struct plist_node pushable_tasks; - struct rb_node pushable_dl_tasks; -#endif - - struct mm_struct *mm, *active_mm; - /* per-thread vma caching */ - u32 vmacache_seqnum; - struct vm_area_struct *vmacache[VMACACHE_SIZE]; -#if defined(SPLIT_RSS_COUNTING) - struct task_rss_stat rss_stat; -#endif -/* task state */ - int exit_state; - int exit_code, exit_signal; - int pdeath_signal; /* The signal sent when the parent dies */ - unsigned long jobctl; /* JOBCTL_*, siglock protected */ - - /* Used for emulating ABI behavior of previous Linux versions */ - unsigned int personality; - - /* scheduler bits, serialized by scheduler locks */ - unsigned sched_reset_on_fork:1; - unsigned sched_contributes_to_load:1; - unsigned sched_migrated:1; - unsigned sched_remote_wakeup:1; - unsigned :0; /* force alignment to the next boundary */ - - /* unserialized, strictly 'current' */ - unsigned in_execve:1; /* bit to tell LSMs we're in execve */ - unsigned in_iowait:1; -#if !defined(TIF_RESTORE_SIGMASK) - unsigned restore_sigmask:1; -#endif -#ifdef CONFIG_MEMCG - unsigned memcg_may_oom:1; -#ifndef CONFIG_SLOB - unsigned memcg_kmem_skip_account:1; -#endif -#endif -#ifdef CONFIG_COMPAT_BRK - unsigned brk_randomized:1; -#endif - - unsigned long atomic_flags; /* Flags needing atomic access. */ - - struct restart_block restart_block; - - pid_t pid; - pid_t tgid; - -#ifdef CONFIG_CC_STACKPROTECTOR - /* Canary value for the -fstack-protector gcc feature */ - unsigned long stack_canary; -#endif - /* - * pointers to (original) parent process, youngest child, younger sibling, - * older sibling, respectively. (p->father can be replaced with - * p->real_parent->pid) - */ - struct task_struct __rcu *real_parent; /* real parent process */ - struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */ - /* - * children/sibling forms the list of my natural children - */ - struct list_head children; /* list of my children */ - struct list_head sibling; /* linkage in my parent's children list */ - struct task_struct *group_leader; /* threadgroup leader */ - - /* - * ptraced is the list of tasks this task is using ptrace on. - * This includes both natural children and PTRACE_ATTACH targets. - * p->ptrace_entry is p's link on the p->parent->ptraced list. - */ - struct list_head ptraced; - struct list_head ptrace_entry; - - /* PID/PID hash table linkage. */ - struct pid_link pids[PIDTYPE_MAX]; - struct list_head thread_group; - struct list_head thread_node; - - struct completion *vfork_done; /* for vfork() */ - int __user *set_child_tid; /* CLONE_CHILD_SETTID */ - int __user *clear_child_tid; /* CLONE_CHILD_CLEARTID */ - - cputime_t utime, stime, utimescaled, stimescaled; - cputime_t gtime; - struct prev_cputime prev_cputime; -#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN - seqcount_t vtime_seqcount; - unsigned long long vtime_snap; - enum { - /* Task is sleeping or running in a CPU with VTIME inactive */ - VTIME_INACTIVE = 0, - /* Task runs in userspace in a CPU with VTIME active */ - VTIME_USER, - /* Task runs in kernelspace in a CPU with VTIME active */ - VTIME_SYS, - } vtime_snap_whence; -#endif - -#ifdef CONFIG_NO_HZ_FULL - atomic_t tick_dep_mask; -#endif - unsigned long nvcsw, nivcsw; /* context switch counts */ - u64 start_time; /* monotonic time in nsec */ - u64 real_start_time; /* boot based time in nsec */ -/* mm fault and swap info: this can arguably be seen as either mm-specific or thread-specific */ - unsigned long min_flt, maj_flt; - - struct task_cputime cputime_expires; - struct list_head cpu_timers[3]; - -/* process credentials */ - const struct cred __rcu *real_cred; /* objective and real subjective task - * credentials (COW) */ - const struct cred __rcu *cred; /* effective (overridable) subjective task - * credentials (COW) */ - char comm[TASK_COMM_LEN]; /* executable name excluding path - - access with [gs]et_task_comm (which lock - it with task_lock()) - - initialized normally by setup_new_exec */ -/* file system info */ - struct nameidata *nameidata; -#ifdef CONFIG_SYSVIPC -/* ipc stuff */ - struct sysv_sem sysvsem; - struct sysv_shm sysvshm; -#endif -#ifdef CONFIG_DETECT_HUNG_TASK -/* hung task detection */ - unsigned long last_switch_count; -#endif -/* filesystem information */ - struct fs_struct *fs; -/* open file information */ - struct files_struct *files; -/* namespaces */ - struct nsproxy *nsproxy; -/* signal handlers */ - struct signal_struct *signal; - struct sighand_struct *sighand; - - sigset_t blocked, real_blocked; - sigset_t saved_sigmask; /* restored if set_restore_sigmask() was used */ - struct sigpending pending; - - unsigned long sas_ss_sp; - size_t sas_ss_size; - unsigned sas_ss_flags; - - struct callback_head *task_works; - - struct audit_context *audit_context; -#ifdef CONFIG_AUDITSYSCALL - kuid_t loginuid; - unsigned int sessionid; -#endif - struct seccomp seccomp; - -/* Thread group tracking */ - u32 parent_exec_id; - u32 self_exec_id; -/* Protection of (de-)allocation: mm, files, fs, tty, keyrings, mems_allowed, - * mempolicy */ - spinlock_t alloc_lock; - - /* Protection of the PI data structures: */ - raw_spinlock_t pi_lock; - - struct wake_q_node wake_q; - -#ifdef CONFIG_RT_MUTEXES - /* PI waiters blocked on a rt_mutex held by this task */ - struct rb_root pi_waiters; - struct rb_node *pi_waiters_leftmost; - /* Deadlock detection and priority inheritance handling */ - struct rt_mutex_waiter *pi_blocked_on; -#endif - -#ifdef CONFIG_DEBUG_MUTEXES - /* mutex deadlock detection */ - struct mutex_waiter *blocked_on; -#endif -#ifdef CONFIG_TRACE_IRQFLAGS - unsigned int irq_events; - unsigned long hardirq_enable_ip; - unsigned long hardirq_disable_ip; - unsigned int hardirq_enable_event; - unsigned int hardirq_disable_event; - int hardirqs_enabled; - int hardirq_context; - unsigned long softirq_disable_ip; - unsigned long softirq_enable_ip; - unsigned int softirq_disable_event; - unsigned int softirq_enable_event; - int softirqs_enabled; - int softirq_context; -#endif -#ifdef CONFIG_LOCKDEP -# define MAX_LOCK_DEPTH 48UL - u64 curr_chain_key; - int lockdep_depth; - unsigned int lockdep_recursion; - struct held_lock held_locks[MAX_LOCK_DEPTH]; - gfp_t lockdep_reclaim_gfp; -#endif -#ifdef CONFIG_UBSAN - unsigned int in_ubsan; -#endif - -/* journalling filesystem info */ - void *journal_info; - -/* stacked block device info */ - struct bio_list *bio_list; - -#ifdef CONFIG_BLOCK -/* stack plugging */ - struct blk_plug *plug; -#endif - -/* VM state */ - struct reclaim_state *reclaim_state; - - struct backing_dev_info *backing_dev_info; - - struct io_context *io_context; - - unsigned long ptrace_message; - siginfo_t *last_siginfo; /* For ptrace use. */ - struct task_io_accounting ioac; -#if defined(CONFIG_TASK_XACCT) - u64 acct_rss_mem1; /* accumulated rss usage */ - u64 acct_vm_mem1; /* accumulated virtual memory usage */ - cputime_t acct_timexpd; /* stime + utime since last update */ -#endif -#ifdef CONFIG_CPUSETS - nodemask_t mems_allowed; /* Protected by alloc_lock */ - seqcount_t mems_allowed_seq; /* Seqence no to catch updates */ - int cpuset_mem_spread_rotor; - int cpuset_slab_spread_rotor; -#endif -#ifdef CONFIG_CGROUPS - /* Control Group info protected by css_set_lock */ - struct css_set __rcu *cgroups; - /* cg_list protected by css_set_lock and tsk->alloc_lock */ - struct list_head cg_list; -#endif -#ifdef CONFIG_FUTEX - struct robust_list_head __user *robust_list; -#ifdef CONFIG_COMPAT - struct compat_robust_list_head __user *compat_robust_list; -#endif - struct list_head pi_state_list; - struct futex_pi_state *pi_state_cache; -#endif -#ifdef CONFIG_PERF_EVENTS - struct perf_event_context *perf_event_ctxp[perf_nr_task_contexts]; - struct mutex perf_event_mutex; - struct list_head perf_event_list; -#endif -#ifdef CONFIG_DEBUG_PREEMPT - unsigned long preempt_disable_ip; -#endif -#ifdef CONFIG_NUMA - struct mempolicy *mempolicy; /* Protected by alloc_lock */ - short il_next; - short pref_node_fork; -#endif -#ifdef CONFIG_NUMA_BALANCING - int numa_scan_seq; - unsigned int numa_scan_period; - unsigned int numa_scan_period_max; - int numa_preferred_nid; - unsigned long numa_migrate_retry; - u64 node_stamp; /* migration stamp */ - u64 last_task_numa_placement; - u64 last_sum_exec_runtime; - struct callback_head numa_work; - - struct list_head numa_entry; - struct numa_group *numa_group; - - /* - * numa_faults is an array split into four regions: - * faults_memory, faults_cpu, faults_memory_buffer, faults_cpu_buffer - * in this precise order. - * - * faults_memory: Exponential decaying average of faults on a per-node - * basis. Scheduling placement decisions are made based on these - * counts. The values remain static for the duration of a PTE scan. - * faults_cpu: Track the nodes the process was running on when a NUMA - * hinting fault was incurred. - * faults_memory_buffer and faults_cpu_buffer: Record faults per node - * during the current scan window. When the scan completes, the counts - * in faults_memory and faults_cpu decay and these values are copied. - */ - unsigned long *numa_faults; - unsigned long total_numa_faults; - - /* - * numa_faults_locality tracks if faults recorded during the last - * scan window were remote/local or failed to migrate. The task scan - * period is adapted based on the locality of the faults with different - * weights depending on whether they were shared or private faults - */ - unsigned long numa_faults_locality[3]; - - unsigned long numa_pages_migrated; -#endif /* CONFIG_NUMA_BALANCING */ - -#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH - struct tlbflush_unmap_batch tlb_ubc; -#endif - - struct rcu_head rcu; - - /* - * cache last used pipe for splice - */ - struct pipe_inode_info *splice_pipe; - - struct page_frag task_frag; - -#ifdef CONFIG_TASK_DELAY_ACCT - struct task_delay_info *delays; -#endif -#ifdef CONFIG_FAULT_INJECTION - int make_it_fail; -#endif - /* - * when (nr_dirtied >= nr_dirtied_pause), it's time to call - * balance_dirty_pages() for some dirty throttling pause - */ - int nr_dirtied; - int nr_dirtied_pause; - unsigned long dirty_paused_when; /* start of a write-and-pause period */ - -#ifdef CONFIG_LATENCYTOP - int latency_record_count; - struct latency_record latency_record[LT_SAVECOUNT]; -#endif - /* - * time slack values; these are used to round up poll() and - * select() etc timeout values. These are in nanoseconds. - */ - u64 timer_slack_ns; - u64 default_timer_slack_ns; - -#ifdef CONFIG_KASAN - unsigned int kasan_depth; -#endif -#ifdef CONFIG_FUNCTION_GRAPH_TRACER - /* Index of current stored address in ret_stack */ - int curr_ret_stack; - /* Stack of return addresses for return function tracing */ - struct ftrace_ret_stack *ret_stack; - /* time stamp for last schedule */ - unsigned long long ftrace_timestamp; - /* - * Number of functions that haven't been traced - * because of depth overrun. - */ - atomic_t trace_overrun; - /* Pause for the tracing */ - atomic_t tracing_graph_pause; -#endif -#ifdef CONFIG_TRACING - /* state flags for use by tracers */ - unsigned long trace; - /* bitmask and counter of trace recursion */ - unsigned long trace_recursion; -#endif /* CONFIG_TRACING */ -#ifdef CONFIG_KCOV - /* Coverage collection mode enabled for this task (0 if disabled). */ - enum kcov_mode kcov_mode; - /* Size of the kcov_area. */ - unsigned kcov_size; - /* Buffer for coverage collection. */ - void *kcov_area; - /* kcov desciptor wired with this task or NULL. */ - struct kcov *kcov; -#endif -#ifdef CONFIG_MEMCG - struct mem_cgroup *memcg_in_oom; - gfp_t memcg_oom_gfp_mask; - int memcg_oom_order; - - /* number of pages to reclaim on returning to userland */ - unsigned int memcg_nr_pages_over_high; -#endif -#ifdef CONFIG_UPROBES - struct uprobe_task *utask; -#endif -#if defined(CONFIG_BCACHE) || defined(CONFIG_BCACHE_MODULE) - unsigned int sequential_io; - unsigned int sequential_io_avg; -#endif -#ifdef CONFIG_DEBUG_ATOMIC_SLEEP - unsigned long task_state_change; -#endif - int pagefault_disabled; -#ifdef CONFIG_MMU - struct task_struct *oom_reaper_list; -#endif -#ifdef CONFIG_VMAP_STACK - struct vm_struct *stack_vm_area; -#endif -#ifdef CONFIG_THREAD_INFO_IN_TASK - /* A live task holds one reference. */ - atomic_t stack_refcount; -#endif -/* CPU-specific state of this task */ - struct thread_struct thread; -/* - * WARNING: on x86, 'thread_struct' contains a variable-sized - * structure. It *MUST* be at the end of 'task_struct'. - * - * Do not put anything below here! - */ -}; - -#ifdef CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT -extern int arch_task_struct_size __read_mostly; -#else -# define arch_task_struct_size (sizeof(struct task_struct)) -#endif - -#ifdef CONFIG_VMAP_STACK -static inline struct vm_struct *task_stack_vm_area(const struct task_struct *t) -{ - return t->stack_vm_area; -} -#else -static inline struct vm_struct *task_stack_vm_area(const struct task_struct *t) -{ - return NULL; -} -#endif - -/* Future-safe accessor for struct task_struct's cpus_allowed. */ -#define tsk_cpus_allowed(tsk) (&(tsk)->cpus_allowed) - -static inline int tsk_nr_cpus_allowed(struct task_struct *p) -{ - return p->nr_cpus_allowed; -} - -#define TNF_MIGRATED 0x01 -#define TNF_NO_GROUP 0x02 -#define TNF_SHARED 0x04 -#define TNF_FAULT_LOCAL 0x08 -#define TNF_MIGRATE_FAIL 0x10 - -static inline bool in_vfork(struct task_struct *tsk) -{ - bool ret; - - /* - * need RCU to access ->real_parent if CLONE_VM was used along with - * CLONE_PARENT. - * - * We check real_parent->mm == tsk->mm because CLONE_VFORK does not - * imply CLONE_VM - * - * CLONE_VFORK can be used with CLONE_PARENT/CLONE_THREAD and thus - * ->real_parent is not necessarily the task doing vfork(), so in - * theory we can't rely on task_lock() if we want to dereference it. - * - * And in this case we can't trust the real_parent->mm == tsk->mm - * check, it can be false negative. But we do not care, if init or - * another oom-unkillable task does this it should blame itself. - */ - rcu_read_lock(); - ret = tsk->vfork_done && tsk->real_parent->mm == tsk->mm; - rcu_read_unlock(); - - return ret; -} - -#ifdef CONFIG_NUMA_BALANCING -extern void task_numa_fault(int last_node, int node, int pages, int flags); -extern pid_t task_numa_group_id(struct task_struct *p); -extern void set_numabalancing_state(bool enabled); -extern void task_numa_free(struct task_struct *p); -extern bool should_numa_migrate_memory(struct task_struct *p, struct page *page, - int src_nid, int dst_cpu); -#else -static inline void task_numa_fault(int last_node, int node, int pages, - int flags) -{ -} -static inline pid_t task_numa_group_id(struct task_struct *p) -{ - return 0; -} -static inline void set_numabalancing_state(bool enabled) -{ -} -static inline void task_numa_free(struct task_struct *p) -{ -} -static inline bool should_numa_migrate_memory(struct task_struct *p, - struct page *page, int src_nid, int dst_cpu) -{ - return true; -} -#endif - -static inline struct pid *task_pid(struct task_struct *task) -{ - return task->pids[PIDTYPE_PID].pid; -} - -static inline struct pid *task_tgid(struct task_struct *task) -{ - return task->group_leader->pids[PIDTYPE_PID].pid; -} - -/* - * Without tasklist or rcu lock it is not safe to dereference - * the result of task_pgrp/task_session even if task == current, - * we can race with another thread doing sys_setsid/sys_setpgid. - */ -static inline struct pid *task_pgrp(struct task_struct *task) -{ - return task->group_leader->pids[PIDTYPE_PGID].pid; -} - -static inline struct pid *task_session(struct task_struct *task) -{ - return task->group_leader->pids[PIDTYPE_SID].pid; -} - -struct pid_namespace; - -/* - * the helpers to get the task's different pids as they are seen - * from various namespaces - * - * task_xid_nr() : global id, i.e. the id seen from the init namespace; - * task_xid_vnr() : virtual id, i.e. the id seen from the pid namespace of - * current. - * task_xid_nr_ns() : id seen from the ns specified; - * - * set_task_vxid() : assigns a virtual id to a task; - * - * see also pid_nr() etc in include/linux/pid.h - */ -pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type, - struct pid_namespace *ns); - -static inline pid_t task_pid_nr(struct task_struct *tsk) -{ - return tsk->pid; -} - -static inline pid_t task_pid_nr_ns(struct task_struct *tsk, - struct pid_namespace *ns) -{ - return __task_pid_nr_ns(tsk, PIDTYPE_PID, ns); -} - -static inline pid_t task_pid_vnr(struct task_struct *tsk) -{ - return __task_pid_nr_ns(tsk, PIDTYPE_PID, NULL); -} - - -static inline pid_t task_tgid_nr(struct task_struct *tsk) -{ - return tsk->tgid; -} - -pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns); - -static inline pid_t task_tgid_vnr(struct task_struct *tsk) -{ - return pid_vnr(task_tgid(tsk)); -} - - -static inline int pid_alive(const struct task_struct *p); -static inline pid_t task_ppid_nr_ns(const struct task_struct *tsk, struct pid_namespace *ns) -{ - pid_t pid = 0; - - rcu_read_lock(); - if (pid_alive(tsk)) - pid = task_tgid_nr_ns(rcu_dereference(tsk->real_parent), ns); - rcu_read_unlock(); - - return pid; -} - -static inline pid_t task_ppid_nr(const struct task_struct *tsk) -{ - return task_ppid_nr_ns(tsk, &init_pid_ns); -} - -static inline pid_t task_pgrp_nr_ns(struct task_struct *tsk, - struct pid_namespace *ns) -{ - return __task_pid_nr_ns(tsk, PIDTYPE_PGID, ns); -} - -static inline pid_t task_pgrp_vnr(struct task_struct *tsk) -{ - return __task_pid_nr_ns(tsk, PIDTYPE_PGID, NULL); -} - - -static inline pid_t task_session_nr_ns(struct task_struct *tsk, - struct pid_namespace *ns) -{ - return __task_pid_nr_ns(tsk, PIDTYPE_SID, ns); -} - -static inline pid_t task_session_vnr(struct task_struct *tsk) -{ - return __task_pid_nr_ns(tsk, PIDTYPE_SID, NULL); -} - -/* obsolete, do not use */ -static inline pid_t task_pgrp_nr(struct task_struct *tsk) -{ - return task_pgrp_nr_ns(tsk, &init_pid_ns); -} - -/** - * pid_alive - check that a task structure is not stale - * @p: Task structure to be checked. - * - * Test if a process is not yet dead (at most zombie state) - * If pid_alive fails, then pointers within the task structure - * can be stale and must not be dereferenced. - * - * Return: 1 if the process is alive. 0 otherwise. - */ -static inline int pid_alive(const struct task_struct *p) -{ - return p->pids[PIDTYPE_PID].pid != NULL; -} - -/** - * is_global_init - check if a task structure is init. Since init - * is free to have sub-threads we need to check tgid. - * @tsk: Task structure to be checked. - * - * Check if a task structure is the first user space task the kernel created. - * - * Return: 1 if the task structure is init. 0 otherwise. - */ -static inline int is_global_init(struct task_struct *tsk) -{ - return task_tgid_nr(tsk) == 1; -} - -extern struct pid *cad_pid; - -extern void free_task(struct task_struct *tsk); -#define get_task_struct(tsk) do { atomic_inc(&(tsk)->usage); } while(0) - -extern void __put_task_struct(struct task_struct *t); - -static inline void put_task_struct(struct task_struct *t) -{ - if (atomic_dec_and_test(&t->usage)) - __put_task_struct(t); -} - -struct task_struct *task_rcu_dereference(struct task_struct **ptask); -struct task_struct *try_get_task_struct(struct task_struct **ptask); - -#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN -extern void task_cputime(struct task_struct *t, - cputime_t *utime, cputime_t *stime); -extern void task_cputime_scaled(struct task_struct *t, - cputime_t *utimescaled, cputime_t *stimescaled); -extern cputime_t task_gtime(struct task_struct *t); -#else -static inline void task_cputime(struct task_struct *t, - cputime_t *utime, cputime_t *stime) -{ - if (utime) - *utime = t->utime; - if (stime) - *stime = t->stime; -} - -static inline void task_cputime_scaled(struct task_struct *t, - cputime_t *utimescaled, - cputime_t *stimescaled) -{ - if (utimescaled) - *utimescaled = t->utimescaled; - if (stimescaled) - *stimescaled = t->stimescaled; -} - -static inline cputime_t task_gtime(struct task_struct *t) -{ - return t->gtime; -} -#endif -extern void task_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st); -extern void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st); - -/* - * Per process flags - */ -#define PF_EXITING 0x00000004 /* getting shut down */ -#define PF_EXITPIDONE 0x00000008 /* pi exit done on shut down */ -#define PF_VCPU 0x00000010 /* I'm a virtual CPU */ -#define PF_WQ_WORKER 0x00000020 /* I'm a workqueue worker */ -#define PF_FORKNOEXEC 0x00000040 /* forked but didn't exec */ -#define PF_MCE_PROCESS 0x00000080 /* process policy on mce errors */ -#define PF_SUPERPRIV 0x00000100 /* used super-user privileges */ -#define PF_DUMPCORE 0x00000200 /* dumped core */ -#define PF_SIGNALED 0x00000400 /* killed by a signal */ -#define PF_MEMALLOC 0x00000800 /* Allocating memory */ -#define PF_NPROC_EXCEEDED 0x00001000 /* set_user noticed that RLIMIT_NPROC was exceeded */ -#define PF_USED_MATH 0x00002000 /* if unset the fpu must be initialized before use */ -#define PF_USED_ASYNC 0x00004000 /* used async_schedule*(), used by module init */ -#define PF_NOFREEZE 0x00008000 /* this thread should not be frozen */ -#define PF_FROZEN 0x00010000 /* frozen for system suspend */ -#define PF_FSTRANS 0x00020000 /* inside a filesystem transaction */ -#define PF_KSWAPD 0x00040000 /* I am kswapd */ -#define PF_MEMALLOC_NOIO 0x00080000 /* Allocating memory without IO involved */ -#define PF_LESS_THROTTLE 0x00100000 /* Throttle me less: I clean memory */ -#define PF_KTHREAD 0x00200000 /* I am a kernel thread */ -#define PF_RANDOMIZE 0x00400000 /* randomize virtual address space */ -#define PF_SWAPWRITE 0x00800000 /* Allowed to write to swap */ -#define PF_NO_SETAFFINITY 0x04000000 /* Userland is not allowed to meddle with cpus_allowed */ -#define PF_MCE_EARLY 0x08000000 /* Early kill for mce process policy */ -#define PF_MUTEX_TESTER 0x20000000 /* Thread belongs to the rt mutex tester */ -#define PF_FREEZER_SKIP 0x40000000 /* Freezer should not count it as freezable */ -#define PF_SUSPEND_TASK 0x80000000 /* this thread called freeze_processes and should not be frozen */ - -/* - * Only the _current_ task can read/write to tsk->flags, but other - * tasks can access tsk->flags in readonly mode for example - * with tsk_used_math (like during threaded core dumping). - * There is however an exception to this rule during ptrace - * or during fork: the ptracer task is allowed to write to the - * child->flags of its traced child (same goes for fork, the parent - * can write to the child->flags), because we're guaranteed the - * child is not running and in turn not changing child->flags - * at the same time the parent does it. - */ -#define clear_stopped_child_used_math(child) do { (child)->flags &= ~PF_USED_MATH; } while (0) -#define set_stopped_child_used_math(child) do { (child)->flags |= PF_USED_MATH; } while (0) -#define clear_used_math() clear_stopped_child_used_math(current) -#define set_used_math() set_stopped_child_used_math(current) -#define conditional_stopped_child_used_math(condition, child) \ - do { (child)->flags &= ~PF_USED_MATH, (child)->flags |= (condition) ? PF_USED_MATH : 0; } while (0) -#define conditional_used_math(condition) \ - conditional_stopped_child_used_math(condition, current) -#define copy_to_stopped_child_used_math(child) \ - do { (child)->flags &= ~PF_USED_MATH, (child)->flags |= current->flags & PF_USED_MATH; } while (0) -/* NOTE: this will return 0 or PF_USED_MATH, it will never return 1 */ -#define tsk_used_math(p) ((p)->flags & PF_USED_MATH) -#define used_math() tsk_used_math(current) - -/* __GFP_IO isn't allowed if PF_MEMALLOC_NOIO is set in current->flags - * __GFP_FS is also cleared as it implies __GFP_IO. - */ -static inline gfp_t memalloc_noio_flags(gfp_t flags) -{ - if (unlikely(current->flags & PF_MEMALLOC_NOIO)) - flags &= ~(__GFP_IO | __GFP_FS); - return flags; -} - -static inline unsigned int memalloc_noio_save(void) -{ - unsigned int flags = current->flags & PF_MEMALLOC_NOIO; - current->flags |= PF_MEMALLOC_NOIO; - return flags; -} - -static inline void memalloc_noio_restore(unsigned int flags) -{ - current->flags = (current->flags & ~PF_MEMALLOC_NOIO) | flags; -} - -/* Per-process atomic flags. */ -#define PFA_NO_NEW_PRIVS 0 /* May not gain new privileges. */ -#define PFA_SPREAD_PAGE 1 /* Spread page cache over cpuset */ -#define PFA_SPREAD_SLAB 2 /* Spread some slab caches over cpuset */ -#define PFA_LMK_WAITING 3 /* Lowmemorykiller is waiting */ - - -#define TASK_PFA_TEST(name, func) \ - static inline bool task_##func(struct task_struct *p) \ - { return test_bit(PFA_##name, &p->atomic_flags); } -#define TASK_PFA_SET(name, func) \ - static inline void task_set_##func(struct task_struct *p) \ - { set_bit(PFA_##name, &p->atomic_flags); } -#define TASK_PFA_CLEAR(name, func) \ - static inline void task_clear_##func(struct task_struct *p) \ - { clear_bit(PFA_##name, &p->atomic_flags); } - -TASK_PFA_TEST(NO_NEW_PRIVS, no_new_privs) -TASK_PFA_SET(NO_NEW_PRIVS, no_new_privs) - -TASK_PFA_TEST(SPREAD_PAGE, spread_page) -TASK_PFA_SET(SPREAD_PAGE, spread_page) -TASK_PFA_CLEAR(SPREAD_PAGE, spread_page) - -TASK_PFA_TEST(SPREAD_SLAB, spread_slab) -TASK_PFA_SET(SPREAD_SLAB, spread_slab) -TASK_PFA_CLEAR(SPREAD_SLAB, spread_slab) - -TASK_PFA_TEST(LMK_WAITING, lmk_waiting) -TASK_PFA_SET(LMK_WAITING, lmk_waiting) - -/* - * task->jobctl flags - */ -#define JOBCTL_STOP_SIGMASK 0xffff /* signr of the last group stop */ - -#define JOBCTL_STOP_DEQUEUED_BIT 16 /* stop signal dequeued */ -#define JOBCTL_STOP_PENDING_BIT 17 /* task should stop for group stop */ -#define JOBCTL_STOP_CONSUME_BIT 18 /* consume group stop count */ -#define JOBCTL_TRAP_STOP_BIT 19 /* trap for STOP */ -#define JOBCTL_TRAP_NOTIFY_BIT 20 /* trap for NOTIFY */ -#define JOBCTL_TRAPPING_BIT 21 /* switching to TRACED */ -#define JOBCTL_LISTENING_BIT 22 /* ptracer is listening for events */ - -#define JOBCTL_STOP_DEQUEUED (1UL << JOBCTL_STOP_DEQUEUED_BIT) -#define JOBCTL_STOP_PENDING (1UL << JOBCTL_STOP_PENDING_BIT) -#define JOBCTL_STOP_CONSUME (1UL << JOBCTL_STOP_CONSUME_BIT) -#define JOBCTL_TRAP_STOP (1UL << JOBCTL_TRAP_STOP_BIT) -#define JOBCTL_TRAP_NOTIFY (1UL << JOBCTL_TRAP_NOTIFY_BIT) -#define JOBCTL_TRAPPING (1UL << JOBCTL_TRAPPING_BIT) -#define JOBCTL_LISTENING (1UL << JOBCTL_LISTENING_BIT) - -#define JOBCTL_TRAP_MASK (JOBCTL_TRAP_STOP | JOBCTL_TRAP_NOTIFY) -#define JOBCTL_PENDING_MASK (JOBCTL_STOP_PENDING | JOBCTL_TRAP_MASK) - -extern bool task_set_jobctl_pending(struct task_struct *task, - unsigned long mask); -extern void task_clear_jobctl_trapping(struct task_struct *task); -extern void task_clear_jobctl_pending(struct task_struct *task, - unsigned long mask); - -static inline void rcu_copy_process(struct task_struct *p) -{ -#ifdef CONFIG_PREEMPT_RCU - p->rcu_read_lock_nesting = 0; - p->rcu_read_unlock_special.s = 0; - p->rcu_blocked_node = NULL; - INIT_LIST_HEAD(&p->rcu_node_entry); -#endif /* #ifdef CONFIG_PREEMPT_RCU */ -#ifdef CONFIG_TASKS_RCU - p->rcu_tasks_holdout = false; - INIT_LIST_HEAD(&p->rcu_tasks_holdout_list); - p->rcu_tasks_idle_cpu = -1; -#endif /* #ifdef CONFIG_TASKS_RCU */ -} - -static inline void tsk_restore_flags(struct task_struct *task, - unsigned long orig_flags, unsigned long flags) -{ - task->flags &= ~flags; - task->flags |= orig_flags & flags; -} - -extern int cpuset_cpumask_can_shrink(const struct cpumask *cur, - const struct cpumask *trial); -extern int task_can_attach(struct task_struct *p, - const struct cpumask *cs_cpus_allowed); -#ifdef CONFIG_SMP -extern void do_set_cpus_allowed(struct task_struct *p, - const struct cpumask *new_mask); - -extern int set_cpus_allowed_ptr(struct task_struct *p, - const struct cpumask *new_mask); -#else -static inline void do_set_cpus_allowed(struct task_struct *p, - const struct cpumask *new_mask) -{ -} -static inline int set_cpus_allowed_ptr(struct task_struct *p, - const struct cpumask *new_mask) -{ - if (!cpumask_test_cpu(0, new_mask)) - return -EINVAL; - return 0; -} -#endif - -#ifdef CONFIG_NO_HZ_COMMON -void calc_load_enter_idle(void); -void calc_load_exit_idle(void); -#else -static inline void calc_load_enter_idle(void) { } -static inline void calc_load_exit_idle(void) { } -#endif /* CONFIG_NO_HZ_COMMON */ - -/* - * Do not use outside of architecture code which knows its limitations. - * - * sched_clock() has no promise of monotonicity or bounded drift between - * CPUs, use (which you should not) requires disabling IRQs. - * - * Please use one of the three interfaces below. - */ -extern unsigned long long notrace sched_clock(void); -/* - * See the comment in kernel/sched/clock.c - */ -extern u64 running_clock(void); -extern u64 sched_clock_cpu(int cpu); - - -extern void sched_clock_init(void); - -#ifndef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK -static inline void sched_clock_tick(void) -{ -} - -static inline void sched_clock_idle_sleep_event(void) -{ -} - -static inline void sched_clock_idle_wakeup_event(u64 delta_ns) -{ -} - -static inline u64 cpu_clock(int cpu) -{ - return sched_clock(); -} - -static inline u64 local_clock(void) -{ - return sched_clock(); -} -#else -/* - * Architectures can set this to 1 if they have specified - * CONFIG_HAVE_UNSTABLE_SCHED_CLOCK in their arch Kconfig, - * but then during bootup it turns out that sched_clock() - * is reliable after all: - */ -extern int sched_clock_stable(void); -extern void set_sched_clock_stable(void); -extern void clear_sched_clock_stable(void); - -extern void sched_clock_tick(void); -extern void sched_clock_idle_sleep_event(void); -extern void sched_clock_idle_wakeup_event(u64 delta_ns); - -/* - * As outlined in clock.c, provides a fast, high resolution, nanosecond - * time source that is monotonic per cpu argument and has bounded drift - * between cpus. - * - * ######################### BIG FAT WARNING ########################## - * # when comparing cpu_clock(i) to cpu_clock(j) for i != j, time can # - * # go backwards !! # - * #################################################################### - */ -static inline u64 cpu_clock(int cpu) -{ - return sched_clock_cpu(cpu); -} - -static inline u64 local_clock(void) -{ - return sched_clock_cpu(raw_smp_processor_id()); -} -#endif - -#ifdef CONFIG_IRQ_TIME_ACCOUNTING -/* - * An i/f to runtime opt-in for irq time accounting based off of sched_clock. - * The reason for this explicit opt-in is not to have perf penalty with - * slow sched_clocks. - */ -extern void enable_sched_clock_irqtime(void); -extern void disable_sched_clock_irqtime(void); -#else -static inline void enable_sched_clock_irqtime(void) {} -static inline void disable_sched_clock_irqtime(void) {} -#endif - -extern unsigned long long -task_sched_runtime(struct task_struct *task); - -/* sched_exec is called by processes performing an exec */ -#ifdef CONFIG_SMP -extern void sched_exec(void); -#else -#define sched_exec() {} -#endif - -extern void sched_clock_idle_sleep_event(void); -extern void sched_clock_idle_wakeup_event(u64 delta_ns); - -#ifdef CONFIG_HOTPLUG_CPU -extern void idle_task_exit(void); -#else -static inline void idle_task_exit(void) {} -#endif - -#if defined(CONFIG_NO_HZ_COMMON) && defined(CONFIG_SMP) -extern void wake_up_nohz_cpu(int cpu); -#else -static inline void wake_up_nohz_cpu(int cpu) { } -#endif - -#ifdef CONFIG_NO_HZ_FULL -extern u64 scheduler_tick_max_deferment(void); -#endif - -#ifdef CONFIG_SCHED_AUTOGROUP -extern void sched_autogroup_create_attach(struct task_struct *p); -extern void sched_autogroup_detach(struct task_struct *p); -extern void sched_autogroup_fork(struct signal_struct *sig); -extern void sched_autogroup_exit(struct signal_struct *sig); -extern void sched_autogroup_exit_task(struct task_struct *p); -#ifdef CONFIG_PROC_FS -extern void proc_sched_autogroup_show_task(struct task_struct *p, struct seq_file *m); -extern int proc_sched_autogroup_set_nice(struct task_struct *p, int nice); -#endif -#else -static inline void sched_autogroup_create_attach(struct task_struct *p) { } -static inline void sched_autogroup_detach(struct task_struct *p) { } -static inline void sched_autogroup_fork(struct signal_struct *sig) { } -static inline void sched_autogroup_exit(struct signal_struct *sig) { } -static inline void sched_autogroup_exit_task(struct task_struct *p) { } -#endif - -extern int yield_to(struct task_struct *p, bool preempt); -extern void set_user_nice(struct task_struct *p, long nice); -extern int task_prio(const struct task_struct *p); -/** - * task_nice - return the nice value of a given task. - * @p: the task in question. - * - * Return: The nice value [ -20 ... 0 ... 19 ]. - */ -static inline int task_nice(const struct task_struct *p) -{ - return PRIO_TO_NICE((p)->static_prio); -} -extern int can_nice(const struct task_struct *p, const int nice); -extern int task_curr(const struct task_struct *p); -extern int idle_cpu(int cpu); -extern int sched_setscheduler(struct task_struct *, int, - const struct sched_param *); -extern int sched_setscheduler_nocheck(struct task_struct *, int, - const struct sched_param *); -extern int sched_setattr(struct task_struct *, - const struct sched_attr *); -extern struct task_struct *idle_task(int cpu); -/** - * is_idle_task - is the specified task an idle task? - * @p: the task in question. - * - * Return: 1 if @p is an idle task. 0 otherwise. - */ -static inline bool is_idle_task(const struct task_struct *p) -{ - return p->pid == 0; -} -extern struct task_struct *curr_task(int cpu); -extern void ia64_set_curr_task(int cpu, struct task_struct *p); - -void yield(void); - -union thread_union { -#ifndef CONFIG_THREAD_INFO_IN_TASK - struct thread_info thread_info; -#endif - unsigned long stack[THREAD_SIZE/sizeof(long)]; -}; - -#ifndef __HAVE_ARCH_KSTACK_END -static inline int kstack_end(void *addr) -{ - /* Reliable end of stack detection: - * Some APM bios versions misalign the stack - */ - return !(((unsigned long)addr+sizeof(void*)-1) & (THREAD_SIZE-sizeof(void*))); -} -#endif - -extern union thread_union init_thread_union; -extern struct task_struct init_task; - -extern struct mm_struct init_mm; - -extern struct pid_namespace init_pid_ns; - -/* - * find a task by one of its numerical ids - * - * find_task_by_pid_ns(): - * finds a task by its pid in the specified namespace - * find_task_by_vpid(): - * finds a task by its virtual pid - * - * see also find_vpid() etc in include/linux/pid.h - */ - -extern struct task_struct *find_task_by_vpid(pid_t nr); -extern struct task_struct *find_task_by_pid_ns(pid_t nr, - struct pid_namespace *ns); - -/* per-UID process charging. */ -extern struct user_struct * alloc_uid(kuid_t); -static inline struct user_struct *get_uid(struct user_struct *u) -{ - atomic_inc(&u->__count); - return u; -} -extern void free_uid(struct user_struct *); - -#include - -extern void xtime_update(unsigned long ticks); - -extern int wake_up_state(struct task_struct *tsk, unsigned int state); -extern int wake_up_process(struct task_struct *tsk); -extern void wake_up_new_task(struct task_struct *tsk); -#ifdef CONFIG_SMP - extern void kick_process(struct task_struct *tsk); -#else - static inline void kick_process(struct task_struct *tsk) { } -#endif -extern int sched_fork(unsigned long clone_flags, struct task_struct *p); -extern void sched_dead(struct task_struct *p); - -extern void proc_caches_init(void); -extern void flush_signals(struct task_struct *); -extern void ignore_signals(struct task_struct *); -extern void flush_signal_handlers(struct task_struct *, int force_default); -extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info); - -static inline int kernel_dequeue_signal(siginfo_t *info) -{ - struct task_struct *tsk = current; - siginfo_t __info; - int ret; - - spin_lock_irq(&tsk->sighand->siglock); - ret = dequeue_signal(tsk, &tsk->blocked, info ?: &__info); - spin_unlock_irq(&tsk->sighand->siglock); - - return ret; -} - -static inline void kernel_signal_stop(void) -{ - spin_lock_irq(¤t->sighand->siglock); - if (current->jobctl & JOBCTL_STOP_DEQUEUED) - __set_current_state(TASK_STOPPED); - spin_unlock_irq(¤t->sighand->siglock); - - schedule(); -} - -extern void release_task(struct task_struct * p); -extern int send_sig_info(int, struct siginfo *, struct task_struct *); -extern int force_sigsegv(int, struct task_struct *); -extern int force_sig_info(int, struct siginfo *, struct task_struct *); -extern int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp); -extern int kill_pid_info(int sig, struct siginfo *info, struct pid *pid); -extern int kill_pid_info_as_cred(int, struct siginfo *, struct pid *, - const struct cred *, u32); -extern int kill_pgrp(struct pid *pid, int sig, int priv); -extern int kill_pid(struct pid *pid, int sig, int priv); -extern int kill_proc_info(int, struct siginfo *, pid_t); -extern __must_check bool do_notify_parent(struct task_struct *, int); -extern void __wake_up_parent(struct task_struct *p, struct task_struct *parent); -extern void force_sig(int, struct task_struct *); -extern int send_sig(int, struct task_struct *, int); -extern int zap_other_threads(struct task_struct *p); -extern struct sigqueue *sigqueue_alloc(void); -extern void sigqueue_free(struct sigqueue *); -extern int send_sigqueue(struct sigqueue *, struct task_struct *, int group); -extern int do_sigaction(int, struct k_sigaction *, struct k_sigaction *); - -#ifdef TIF_RESTORE_SIGMASK -/* - * Legacy restore_sigmask accessors. These are inefficient on - * SMP architectures because they require atomic operations. - */ - -/** - * set_restore_sigmask() - make sure saved_sigmask processing gets done - * - * This sets TIF_RESTORE_SIGMASK and ensures that the arch signal code - * will run before returning to user mode, to process the flag. For - * all callers, TIF_SIGPENDING is already set or it's no harm to set - * it. TIF_RESTORE_SIGMASK need not be in the set of bits that the - * arch code will notice on return to user mode, in case those bits - * are scarce. We set TIF_SIGPENDING here to ensure that the arch - * signal code always gets run when TIF_RESTORE_SIGMASK is set. - */ -static inline void set_restore_sigmask(void) -{ - set_thread_flag(TIF_RESTORE_SIGMASK); - WARN_ON(!test_thread_flag(TIF_SIGPENDING)); -} -static inline void clear_restore_sigmask(void) -{ - clear_thread_flag(TIF_RESTORE_SIGMASK); -} -static inline bool test_restore_sigmask(void) -{ - return test_thread_flag(TIF_RESTORE_SIGMASK); -} -static inline bool test_and_clear_restore_sigmask(void) -{ - return test_and_clear_thread_flag(TIF_RESTORE_SIGMASK); -} - -#else /* TIF_RESTORE_SIGMASK */ - -/* Higher-quality implementation, used if TIF_RESTORE_SIGMASK doesn't exist. */ -static inline void set_restore_sigmask(void) -{ - current->restore_sigmask = true; - WARN_ON(!test_thread_flag(TIF_SIGPENDING)); -} -static inline void clear_restore_sigmask(void) -{ - current->restore_sigmask = false; -} -static inline bool test_restore_sigmask(void) -{ - return current->restore_sigmask; -} -static inline bool test_and_clear_restore_sigmask(void) -{ - if (!current->restore_sigmask) - return false; - current->restore_sigmask = false; - return true; -} -#endif - -static inline void restore_saved_sigmask(void) -{ - if (test_and_clear_restore_sigmask()) - __set_current_blocked(¤t->saved_sigmask); -} - -static inline sigset_t *sigmask_to_save(void) -{ - sigset_t *res = ¤t->blocked; - if (unlikely(test_restore_sigmask())) - res = ¤t->saved_sigmask; - return res; -} - -static inline int kill_cad_pid(int sig, int priv) -{ - return kill_pid(cad_pid, sig, priv); -} - -/* These can be the second arg to send_sig_info/send_group_sig_info. */ -#define SEND_SIG_NOINFO ((struct siginfo *) 0) -#define SEND_SIG_PRIV ((struct siginfo *) 1) -#define SEND_SIG_FORCED ((struct siginfo *) 2) - -/* - * True if we are on the alternate signal stack. - */ -static inline int on_sig_stack(unsigned long sp) -{ - /* - * If the signal stack is SS_AUTODISARM then, by construction, we - * can't be on the signal stack unless user code deliberately set - * SS_AUTODISARM when we were already on it. - * - * This improves reliability: if user state gets corrupted such that - * the stack pointer points very close to the end of the signal stack, - * then this check will enable the signal to be handled anyway. - */ - if (current->sas_ss_flags & SS_AUTODISARM) - return 0; - -#ifdef CONFIG_STACK_GROWSUP - return sp >= current->sas_ss_sp && - sp - current->sas_ss_sp < current->sas_ss_size; -#else - return sp > current->sas_ss_sp && - sp - current->sas_ss_sp <= current->sas_ss_size; -#endif -} - -static inline int sas_ss_flags(unsigned long sp) -{ - if (!current->sas_ss_size) - return SS_DISABLE; - - return on_sig_stack(sp) ? SS_ONSTACK : 0; -} - -static inline void sas_ss_reset(struct task_struct *p) -{ - p->sas_ss_sp = 0; - p->sas_ss_size = 0; - p->sas_ss_flags = SS_DISABLE; -} - -static inline unsigned long sigsp(unsigned long sp, struct ksignal *ksig) -{ - if (unlikely((ksig->ka.sa.sa_flags & SA_ONSTACK)) && ! sas_ss_flags(sp)) -#ifdef CONFIG_STACK_GROWSUP - return current->sas_ss_sp; -#else - return current->sas_ss_sp + current->sas_ss_size; -#endif - return sp; -} - -/* - * Routines for handling mm_structs - */ -extern struct mm_struct * mm_alloc(void); - -/* mmdrop drops the mm and the page tables */ -extern void __mmdrop(struct mm_struct *); -static inline void mmdrop(struct mm_struct *mm) -{ - if (unlikely(atomic_dec_and_test(&mm->mm_count))) - __mmdrop(mm); -} - -static inline void mmdrop_async_fn(struct work_struct *work) -{ - struct mm_struct *mm = container_of(work, struct mm_struct, async_put_work); - __mmdrop(mm); -} - -static inline void mmdrop_async(struct mm_struct *mm) -{ - if (unlikely(atomic_dec_and_test(&mm->mm_count))) { - INIT_WORK(&mm->async_put_work, mmdrop_async_fn); - schedule_work(&mm->async_put_work); - } -} - -static inline bool mmget_not_zero(struct mm_struct *mm) -{ - return atomic_inc_not_zero(&mm->mm_users); -} - -/* mmput gets rid of the mappings and all user-space */ -extern void mmput(struct mm_struct *); -#ifdef CONFIG_MMU -/* same as above but performs the slow path from the async context. Can - * be called from the atomic context as well - */ -extern void mmput_async(struct mm_struct *); -#endif - -/* Grab a reference to a task's mm, if it is not already going away */ -extern struct mm_struct *get_task_mm(struct task_struct *task); -/* - * Grab a reference to a task's mm, if it is not already going away - * and ptrace_may_access with the mode parameter passed to it - * succeeds. - */ -extern struct mm_struct *mm_access(struct task_struct *task, unsigned int mode); -/* Remove the current tasks stale references to the old mm_struct */ -extern void mm_release(struct task_struct *, struct mm_struct *); - -#ifdef CONFIG_HAVE_COPY_THREAD_TLS -extern int copy_thread_tls(unsigned long, unsigned long, unsigned long, - struct task_struct *, unsigned long); -#else -extern int copy_thread(unsigned long, unsigned long, unsigned long, - struct task_struct *); - -/* Architectures that haven't opted into copy_thread_tls get the tls argument - * via pt_regs, so ignore the tls argument passed via C. */ -static inline int copy_thread_tls( - unsigned long clone_flags, unsigned long sp, unsigned long arg, - struct task_struct *p, unsigned long tls) -{ - return copy_thread(clone_flags, sp, arg, p); -} -#endif -extern void flush_thread(void); - -#ifdef CONFIG_HAVE_EXIT_THREAD -extern void exit_thread(struct task_struct *tsk); -#else -static inline void exit_thread(struct task_struct *tsk) -{ -} -#endif - -extern void exit_files(struct task_struct *); -extern void __cleanup_sighand(struct sighand_struct *); - -extern void exit_itimers(struct signal_struct *); -extern void flush_itimer_signals(void); - -extern void do_group_exit(int); - -extern int do_execve(struct filename *, - const char __user * const __user *, - const char __user * const __user *); -extern int do_execveat(int, struct filename *, - const char __user * const __user *, - const char __user * const __user *, - int); -extern long _do_fork(unsigned long, unsigned long, unsigned long, int __user *, int __user *, unsigned long); -extern long do_fork(unsigned long, unsigned long, unsigned long, int __user *, int __user *); -struct task_struct *fork_idle(int); -extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); - -extern void __set_task_comm(struct task_struct *tsk, const char *from, bool exec); -static inline void set_task_comm(struct task_struct *tsk, const char *from) -{ - __set_task_comm(tsk, from, false); -} -extern char *get_task_comm(char *to, struct task_struct *tsk); - -#ifdef CONFIG_SMP -void scheduler_ipi(void); -extern unsigned long wait_task_inactive(struct task_struct *, long match_state); -#else -static inline void scheduler_ipi(void) { } -static inline unsigned long wait_task_inactive(struct task_struct *p, - long match_state) -{ - return 1; -} -#endif - -#define tasklist_empty() \ - list_empty(&init_task.tasks) - -#define next_task(p) \ - list_entry_rcu((p)->tasks.next, struct task_struct, tasks) - -#define for_each_process(p) \ - for (p = &init_task ; (p = next_task(p)) != &init_task ; ) - -extern bool current_is_single_threaded(void); - -/* - * Careful: do_each_thread/while_each_thread is a double loop so - * 'break' will not work as expected - use goto instead. - */ -#define do_each_thread(g, t) \ - for (g = t = &init_task ; (g = t = next_task(g)) != &init_task ; ) do - -#define while_each_thread(g, t) \ - while ((t = next_thread(t)) != g) - -#define __for_each_thread(signal, t) \ - list_for_each_entry_rcu(t, &(signal)->thread_head, thread_node) - -#define for_each_thread(p, t) \ - __for_each_thread((p)->signal, t) - -/* Careful: this is a double loop, 'break' won't work as expected. */ -#define for_each_process_thread(p, t) \ - for_each_process(p) for_each_thread(p, t) - -static inline int get_nr_threads(struct task_struct *tsk) -{ - return tsk->signal->nr_threads; -} - -static inline bool thread_group_leader(struct task_struct *p) -{ - return p->exit_signal >= 0; -} - -/* Do to the insanities of de_thread it is possible for a process - * to have the pid of the thread group leader without actually being - * the thread group leader. For iteration through the pids in proc - * all we care about is that we have a task with the appropriate - * pid, we don't actually care if we have the right task. - */ -static inline bool has_group_leader_pid(struct task_struct *p) -{ - return task_pid(p) == p->signal->leader_pid; -} - -static inline -bool same_thread_group(struct task_struct *p1, struct task_struct *p2) -{ - return p1->signal == p2->signal; -} - -static inline struct task_struct *next_thread(const struct task_struct *p) -{ - return list_entry_rcu(p->thread_group.next, - struct task_struct, thread_group); -} - -static inline int thread_group_empty(struct task_struct *p) -{ - return list_empty(&p->thread_group); -} - -#define delay_group_leader(p) \ - (thread_group_leader(p) && !thread_group_empty(p)) - -/* - * Protects ->fs, ->files, ->mm, ->group_info, ->comm, keyring - * subscriptions and synchronises with wait4(). Also used in procfs. Also - * pins the final release of task.io_context. Also protects ->cpuset and - * ->cgroup.subsys[]. And ->vfork_done. - * - * Nests both inside and outside of read_lock(&tasklist_lock). - * It must not be nested with write_lock_irq(&tasklist_lock), - * neither inside nor outside. - */ -static inline void task_lock(struct task_struct *p) -{ - spin_lock(&p->alloc_lock); -} - -static inline void task_unlock(struct task_struct *p) -{ - spin_unlock(&p->alloc_lock); -} - -extern struct sighand_struct *__lock_task_sighand(struct task_struct *tsk, - unsigned long *flags); - -static inline struct sighand_struct *lock_task_sighand(struct task_struct *tsk, - unsigned long *flags) -{ - struct sighand_struct *ret; - - ret = __lock_task_sighand(tsk, flags); - (void)__cond_lock(&tsk->sighand->siglock, ret); - return ret; -} - -static inline void unlock_task_sighand(struct task_struct *tsk, - unsigned long *flags) -{ - spin_unlock_irqrestore(&tsk->sighand->siglock, *flags); -} - -/** - * threadgroup_change_begin - mark the beginning of changes to a threadgroup - * @tsk: task causing the changes - * - * All operations which modify a threadgroup - a new thread joining the - * group, death of a member thread (the assertion of PF_EXITING) and - * exec(2) dethreading the process and replacing the leader - are wrapped - * by threadgroup_change_{begin|end}(). This is to provide a place which - * subsystems needing threadgroup stability can hook into for - * synchronization. - */ -static inline void threadgroup_change_begin(struct task_struct *tsk) -{ - might_sleep(); - cgroup_threadgroup_change_begin(tsk); -} - -/** - * threadgroup_change_end - mark the end of changes to a threadgroup - * @tsk: task causing the changes - * - * See threadgroup_change_begin(). - */ -static inline void threadgroup_change_end(struct task_struct *tsk) -{ - cgroup_threadgroup_change_end(tsk); -} - -#ifdef CONFIG_THREAD_INFO_IN_TASK - -static inline struct thread_info *task_thread_info(struct task_struct *task) -{ - return &task->thread_info; -} - -/* - * When accessing the stack of a non-current task that might exit, use - * try_get_task_stack() instead. task_stack_page will return a pointer - * that could get freed out from under you. - */ -static inline void *task_stack_page(const struct task_struct *task) -{ - return task->stack; -} - -#define setup_thread_stack(new,old) do { } while(0) - -static inline unsigned long *end_of_stack(const struct task_struct *task) -{ - return task->stack; -} - -#elif !defined(__HAVE_THREAD_FUNCTIONS) - -#define task_thread_info(task) ((struct thread_info *)(task)->stack) -#define task_stack_page(task) ((void *)(task)->stack) - -static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org) -{ - *task_thread_info(p) = *task_thread_info(org); - task_thread_info(p)->task = p; -} - -/* - * Return the address of the last usable long on the stack. - * - * When the stack grows down, this is just above the thread - * info struct. Going any lower will corrupt the threadinfo. - * - * When the stack grows up, this is the highest address. - * Beyond that position, we corrupt data on the next page. - */ -static inline unsigned long *end_of_stack(struct task_struct *p) -{ -#ifdef CONFIG_STACK_GROWSUP - return (unsigned long *)((unsigned long)task_thread_info(p) + THREAD_SIZE) - 1; -#else - return (unsigned long *)(task_thread_info(p) + 1); -#endif -} - -#endif - -#ifdef CONFIG_THREAD_INFO_IN_TASK -static inline void *try_get_task_stack(struct task_struct *tsk) -{ - return atomic_inc_not_zero(&tsk->stack_refcount) ? - task_stack_page(tsk) : NULL; -} - -extern void put_task_stack(struct task_struct *tsk); -#else -static inline void *try_get_task_stack(struct task_struct *tsk) -{ - return task_stack_page(tsk); -} - -static inline void put_task_stack(struct task_struct *tsk) {} -#endif - -#define task_stack_end_corrupted(task) \ - (*(end_of_stack(task)) != STACK_END_MAGIC) - -static inline int object_is_on_stack(void *obj) -{ - void *stack = task_stack_page(current); - - return (obj >= stack) && (obj < (stack + THREAD_SIZE)); -} - -extern void thread_stack_cache_init(void); - -#ifdef CONFIG_DEBUG_STACK_USAGE -static inline unsigned long stack_not_used(struct task_struct *p) -{ - unsigned long *n = end_of_stack(p); - - do { /* Skip over canary */ -# ifdef CONFIG_STACK_GROWSUP - n--; -# else - n++; -# endif - } while (!*n); - -# ifdef CONFIG_STACK_GROWSUP - return (unsigned long)end_of_stack(p) - (unsigned long)n; -# else - return (unsigned long)n - (unsigned long)end_of_stack(p); -# endif -} -#endif -extern void set_task_stack_end_magic(struct task_struct *tsk); - -/* set thread flags in other task's structures - * - see asm/thread_info.h for TIF_xxxx flags available - */ -static inline void set_tsk_thread_flag(struct task_struct *tsk, int flag) -{ - set_ti_thread_flag(task_thread_info(tsk), flag); -} - -static inline void clear_tsk_thread_flag(struct task_struct *tsk, int flag) -{ - clear_ti_thread_flag(task_thread_info(tsk), flag); -} - -static inline int test_and_set_tsk_thread_flag(struct task_struct *tsk, int flag) -{ - return test_and_set_ti_thread_flag(task_thread_info(tsk), flag); -} - -static inline int test_and_clear_tsk_thread_flag(struct task_struct *tsk, int flag) -{ - return test_and_clear_ti_thread_flag(task_thread_info(tsk), flag); -} - -static inline int test_tsk_thread_flag(struct task_struct *tsk, int flag) -{ - return test_ti_thread_flag(task_thread_info(tsk), flag); -} - -static inline void set_tsk_need_resched(struct task_struct *tsk) -{ - set_tsk_thread_flag(tsk,TIF_NEED_RESCHED); -} - -static inline void clear_tsk_need_resched(struct task_struct *tsk) -{ - clear_tsk_thread_flag(tsk,TIF_NEED_RESCHED); -} - -static inline int test_tsk_need_resched(struct task_struct *tsk) -{ - return unlikely(test_tsk_thread_flag(tsk,TIF_NEED_RESCHED)); -} - -static inline int restart_syscall(void) -{ - set_tsk_thread_flag(current, TIF_SIGPENDING); - return -ERESTARTNOINTR; -} - -static inline int signal_pending(struct task_struct *p) -{ - return unlikely(test_tsk_thread_flag(p,TIF_SIGPENDING)); -} - -static inline int __fatal_signal_pending(struct task_struct *p) -{ - return unlikely(sigismember(&p->pending.signal, SIGKILL)); -} - -static inline int fatal_signal_pending(struct task_struct *p) -{ - return signal_pending(p) && __fatal_signal_pending(p); -} - -static inline int signal_pending_state(long state, struct task_struct *p) -{ - if (!(state & (TASK_INTERRUPTIBLE | TASK_WAKEKILL))) - return 0; - if (!signal_pending(p)) - return 0; - - return (state & TASK_INTERRUPTIBLE) || __fatal_signal_pending(p); -} - -/* - * cond_resched() and cond_resched_lock(): latency reduction via - * explicit rescheduling in places that are safe. The return - * value indicates whether a reschedule was done in fact. - * cond_resched_lock() will drop the spinlock before scheduling, - * cond_resched_softirq() will enable bhs before scheduling. - */ -#ifndef CONFIG_PREEMPT -extern int _cond_resched(void); -#else -static inline int _cond_resched(void) { return 0; } -#endif - -#define cond_resched() ({ \ - ___might_sleep(__FILE__, __LINE__, 0); \ - _cond_resched(); \ -}) - -extern int __cond_resched_lock(spinlock_t *lock); - -#define cond_resched_lock(lock) ({ \ - ___might_sleep(__FILE__, __LINE__, PREEMPT_LOCK_OFFSET);\ - __cond_resched_lock(lock); \ -}) - -extern int __cond_resched_softirq(void); - -#define cond_resched_softirq() ({ \ - ___might_sleep(__FILE__, __LINE__, SOFTIRQ_DISABLE_OFFSET); \ - __cond_resched_softirq(); \ -}) - -static inline void cond_resched_rcu(void) -{ -#if defined(CONFIG_DEBUG_ATOMIC_SLEEP) || !defined(CONFIG_PREEMPT_RCU) - rcu_read_unlock(); - cond_resched(); - rcu_read_lock(); -#endif -} - -static inline unsigned long get_preempt_disable_ip(struct task_struct *p) -{ -#ifdef CONFIG_DEBUG_PREEMPT - return p->preempt_disable_ip; -#else - return 0; -#endif -} - -/* - * Does a critical section need to be broken due to another - * task waiting?: (technically does not depend on CONFIG_PREEMPT, - * but a general need for low latency) - */ -static inline int spin_needbreak(spinlock_t *lock) -{ -#ifdef CONFIG_PREEMPT - return spin_is_contended(lock); -#else - return 0; -#endif -} - -/* - * Idle thread specific functions to determine the need_resched - * polling state. - */ -#ifdef TIF_POLLING_NRFLAG -static inline int tsk_is_polling(struct task_struct *p) -{ - return test_tsk_thread_flag(p, TIF_POLLING_NRFLAG); -} - -static inline void __current_set_polling(void) -{ - set_thread_flag(TIF_POLLING_NRFLAG); -} - -static inline bool __must_check current_set_polling_and_test(void) -{ - __current_set_polling(); - - /* - * Polling state must be visible before we test NEED_RESCHED, - * paired by resched_curr() - */ - smp_mb__after_atomic(); - - return unlikely(tif_need_resched()); -} - -static inline void __current_clr_polling(void) -{ - clear_thread_flag(TIF_POLLING_NRFLAG); -} - -static inline bool __must_check current_clr_polling_and_test(void) -{ - __current_clr_polling(); - - /* - * Polling state must be visible before we test NEED_RESCHED, - * paired by resched_curr() - */ - smp_mb__after_atomic(); - - return unlikely(tif_need_resched()); -} - -#else -static inline int tsk_is_polling(struct task_struct *p) { return 0; } -static inline void __current_set_polling(void) { } -static inline void __current_clr_polling(void) { } - -static inline bool __must_check current_set_polling_and_test(void) -{ - return unlikely(tif_need_resched()); -} -static inline bool __must_check current_clr_polling_and_test(void) -{ - return unlikely(tif_need_resched()); -} -#endif - -static inline void current_clr_polling(void) -{ - __current_clr_polling(); - - /* - * Ensure we check TIF_NEED_RESCHED after we clear the polling bit. - * Once the bit is cleared, we'll get IPIs with every new - * TIF_NEED_RESCHED and the IPI handler, scheduler_ipi(), will also - * fold. - */ - smp_mb(); /* paired with resched_curr() */ - - preempt_fold_need_resched(); -} - -static __always_inline bool need_resched(void) -{ - return unlikely(tif_need_resched()); -} - -/* - * Thread group CPU time accounting. - */ -void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times); -void thread_group_cputimer(struct task_struct *tsk, struct task_cputime *times); - -/* - * Reevaluate whether the task has signals pending delivery. - * Wake the task if so. - * This is required every time the blocked sigset_t changes. - * callers must hold sighand->siglock. - */ -extern void recalc_sigpending_and_wake(struct task_struct *t); -extern void recalc_sigpending(void); - -extern void signal_wake_up_state(struct task_struct *t, unsigned int state); - -static inline void signal_wake_up(struct task_struct *t, bool resume) -{ - signal_wake_up_state(t, resume ? TASK_WAKEKILL : 0); -} -static inline void ptrace_signal_wake_up(struct task_struct *t, bool resume) -{ - signal_wake_up_state(t, resume ? __TASK_TRACED : 0); -} - -/* - * Wrappers for p->thread_info->cpu access. No-op on UP. - */ -#ifdef CONFIG_SMP - -static inline unsigned int task_cpu(const struct task_struct *p) -{ -#ifdef CONFIG_THREAD_INFO_IN_TASK - return p->cpu; -#else - return task_thread_info(p)->cpu; -#endif -} - -static inline int task_node(const struct task_struct *p) -{ - return cpu_to_node(task_cpu(p)); -} - -extern void set_task_cpu(struct task_struct *p, unsigned int cpu); - -#else - -static inline unsigned int task_cpu(const struct task_struct *p) -{ - return 0; -} - -static inline void set_task_cpu(struct task_struct *p, unsigned int cpu) -{ -} - -#endif /* CONFIG_SMP */ - -extern long sched_setaffinity(pid_t pid, const struct cpumask *new_mask); -extern long sched_getaffinity(pid_t pid, struct cpumask *mask); - -#ifdef CONFIG_CGROUP_SCHED -extern struct task_group root_task_group; -#endif /* CONFIG_CGROUP_SCHED */ - -extern int task_can_switch_user(struct user_struct *up, - struct task_struct *tsk); - -#ifdef CONFIG_TASK_XACCT -static inline void add_rchar(struct task_struct *tsk, ssize_t amt) -{ - tsk->ioac.rchar += amt; -} - -static inline void add_wchar(struct task_struct *tsk, ssize_t amt) -{ - tsk->ioac.wchar += amt; -} - -static inline void inc_syscr(struct task_struct *tsk) -{ - tsk->ioac.syscr++; -} - -static inline void inc_syscw(struct task_struct *tsk) -{ - tsk->ioac.syscw++; -} -#else -static inline void add_rchar(struct task_struct *tsk, ssize_t amt) -{ -} - -static inline void add_wchar(struct task_struct *tsk, ssize_t amt) -{ -} - -static inline void inc_syscr(struct task_struct *tsk) -{ -} - -static inline void inc_syscw(struct task_struct *tsk) -{ -} -#endif - -#ifndef TASK_SIZE_OF -#define TASK_SIZE_OF(tsk) TASK_SIZE -#endif - -#ifdef CONFIG_MEMCG -extern void mm_update_next_owner(struct mm_struct *mm); -#else -static inline void mm_update_next_owner(struct mm_struct *mm) -{ -} -#endif /* CONFIG_MEMCG */ - -static inline unsigned long task_rlimit(const struct task_struct *tsk, - unsigned int limit) -{ - return READ_ONCE(tsk->signal->rlim[limit].rlim_cur); -} - -static inline unsigned long task_rlimit_max(const struct task_struct *tsk, - unsigned int limit) -{ - return READ_ONCE(tsk->signal->rlim[limit].rlim_max); -} - -static inline unsigned long rlimit(unsigned int limit) -{ - return task_rlimit(current, limit); -} - -static inline unsigned long rlimit_max(unsigned int limit) -{ - return task_rlimit_max(current, limit); -} - -#define SCHED_CPUFREQ_RT (1U << 0) -#define SCHED_CPUFREQ_DL (1U << 1) -#define SCHED_CPUFREQ_IOWAIT (1U << 2) - -#define SCHED_CPUFREQ_RT_DL (SCHED_CPUFREQ_RT | SCHED_CPUFREQ_DL) - -#ifdef CONFIG_CPU_FREQ -struct update_util_data { - void (*func)(struct update_util_data *data, u64 time, unsigned int flags); -}; - -void cpufreq_add_update_util_hook(int cpu, struct update_util_data *data, - void (*func)(struct update_util_data *data, u64 time, - unsigned int flags)); -void cpufreq_remove_update_util_hook(int cpu); -#endif /* CONFIG_CPU_FREQ */ - -#endif diff --git a/src/linux/include/linux/sched/deadline.h b/src/linux/include/linux/sched/deadline.h deleted file mode 100644 index 9089a2a..0000000 --- a/src/linux/include/linux/sched/deadline.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _SCHED_DEADLINE_H -#define _SCHED_DEADLINE_H - -/* - * SCHED_DEADLINE tasks has negative priorities, reflecting - * the fact that any of them has higher prio than RT and - * NORMAL/BATCH tasks. - */ - -#define MAX_DL_PRIO 0 - -static inline int dl_prio(int prio) -{ - if (unlikely(prio < MAX_DL_PRIO)) - return 1; - return 0; -} - -static inline int dl_task(struct task_struct *p) -{ - return dl_prio(p->prio); -} - -static inline bool dl_time_before(u64 a, u64 b) -{ - return (s64)(a - b) < 0; -} - -#endif /* _SCHED_DEADLINE_H */ diff --git a/src/linux/include/linux/sched/prio.h b/src/linux/include/linux/sched/prio.h deleted file mode 100644 index d9cf5a5..0000000 --- a/src/linux/include/linux/sched/prio.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef _SCHED_PRIO_H -#define _SCHED_PRIO_H - -#define MAX_NICE 19 -#define MIN_NICE -20 -#define NICE_WIDTH (MAX_NICE - MIN_NICE + 1) - -/* - * Priority of a process goes from 0..MAX_PRIO-1, valid RT - * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH - * tasks are in the range MAX_RT_PRIO..MAX_PRIO-1. Priority - * values are inverted: lower p->prio value means higher priority. - * - * The MAX_USER_RT_PRIO value allows the actual maximum - * RT priority to be separate from the value exported to - * user-space. This allows kernel threads to set their - * priority to a value higher than any user task. Note: - * MAX_RT_PRIO must not be smaller than MAX_USER_RT_PRIO. - */ - -#define MAX_USER_RT_PRIO 100 -#define MAX_RT_PRIO MAX_USER_RT_PRIO - -#define MAX_PRIO (MAX_RT_PRIO + NICE_WIDTH) -#define DEFAULT_PRIO (MAX_RT_PRIO + NICE_WIDTH / 2) - -/* - * Convert user-nice values [ -20 ... 0 ... 19 ] - * to static priority [ MAX_RT_PRIO..MAX_PRIO-1 ], - * and back. - */ -#define NICE_TO_PRIO(nice) ((nice) + DEFAULT_PRIO) -#define PRIO_TO_NICE(prio) ((prio) - DEFAULT_PRIO) - -/* - * 'User priority' is the nice value converted to something we - * can work with better when scaling various scheduler parameters, - * it's a [ 0 ... 39 ] range. - */ -#define USER_PRIO(p) ((p)-MAX_RT_PRIO) -#define TASK_USER_PRIO(p) USER_PRIO((p)->static_prio) -#define MAX_USER_PRIO (USER_PRIO(MAX_PRIO)) - -/* - * Convert nice value [19,-20] to rlimit style value [1,40]. - */ -static inline long nice_to_rlimit(long nice) -{ - return (MAX_NICE - nice + 1); -} - -/* - * Convert rlimit style value [1,40] to nice value [-20, 19]. - */ -static inline long rlimit_to_nice(long prio) -{ - return (MAX_NICE - prio + 1); -} - -#endif /* _SCHED_PRIO_H */ diff --git a/src/linux/include/linux/sched/rt.h b/src/linux/include/linux/sched/rt.h deleted file mode 100644 index a30b172..0000000 --- a/src/linux/include/linux/sched/rt.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef _SCHED_RT_H -#define _SCHED_RT_H - -#include - -static inline int rt_prio(int prio) -{ - if (unlikely(prio < MAX_RT_PRIO)) - return 1; - return 0; -} - -static inline int rt_task(struct task_struct *p) -{ - return rt_prio(p->prio); -} - -#ifdef CONFIG_RT_MUTEXES -extern int rt_mutex_getprio(struct task_struct *p); -extern void rt_mutex_setprio(struct task_struct *p, int prio); -extern int rt_mutex_get_effective_prio(struct task_struct *task, int newprio); -extern struct task_struct *rt_mutex_get_top_task(struct task_struct *task); -extern void rt_mutex_adjust_pi(struct task_struct *p); -static inline bool tsk_is_pi_blocked(struct task_struct *tsk) -{ - return tsk->pi_blocked_on != NULL; -} -#else -static inline int rt_mutex_getprio(struct task_struct *p) -{ - return p->normal_prio; -} - -static inline int rt_mutex_get_effective_prio(struct task_struct *task, - int newprio) -{ - return newprio; -} - -static inline struct task_struct *rt_mutex_get_top_task(struct task_struct *task) -{ - return NULL; -} -# define rt_mutex_adjust_pi(p) do { } while (0) -static inline bool tsk_is_pi_blocked(struct task_struct *tsk) -{ - return false; -} -#endif - -extern void normalize_rt_tasks(void); - - -/* - * default timeslice is 100 msecs (used only for SCHED_RR tasks). - * Timeslices get refilled after they expire. - */ -#define RR_TIMESLICE (100 * HZ / 1000) - -#endif /* _SCHED_RT_H */ diff --git a/src/linux/include/linux/sched/sysctl.h b/src/linux/include/linux/sched/sysctl.h deleted file mode 100644 index 22db1e6..0000000 --- a/src/linux/include/linux/sched/sysctl.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef _SCHED_SYSCTL_H -#define _SCHED_SYSCTL_H - -#ifdef CONFIG_DETECT_HUNG_TASK -extern int sysctl_hung_task_check_count; -extern unsigned int sysctl_hung_task_panic; -extern unsigned long sysctl_hung_task_timeout_secs; -extern int sysctl_hung_task_warnings; -extern int proc_dohung_task_timeout_secs(struct ctl_table *table, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos); -#else -/* Avoid need for ifdefs elsewhere in the code */ -enum { sysctl_hung_task_timeout_secs = 0 }; -#endif - -extern unsigned int sysctl_sched_latency; -extern unsigned int sysctl_sched_min_granularity; -extern unsigned int sysctl_sched_wakeup_granularity; -extern unsigned int sysctl_sched_child_runs_first; - -enum sched_tunable_scaling { - SCHED_TUNABLESCALING_NONE, - SCHED_TUNABLESCALING_LOG, - SCHED_TUNABLESCALING_LINEAR, - SCHED_TUNABLESCALING_END, -}; -extern enum sched_tunable_scaling sysctl_sched_tunable_scaling; - -extern unsigned int sysctl_numa_balancing_scan_delay; -extern unsigned int sysctl_numa_balancing_scan_period_min; -extern unsigned int sysctl_numa_balancing_scan_period_max; -extern unsigned int sysctl_numa_balancing_scan_size; - -#ifdef CONFIG_SCHED_DEBUG -extern unsigned int sysctl_sched_migration_cost; -extern unsigned int sysctl_sched_nr_migrate; -extern unsigned int sysctl_sched_time_avg; -extern unsigned int sysctl_sched_shares_window; - -int sched_proc_update_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *length, - loff_t *ppos); -#endif - -/* - * control realtime throttling: - * - * /proc/sys/kernel/sched_rt_period_us - * /proc/sys/kernel/sched_rt_runtime_us - */ -extern unsigned int sysctl_sched_rt_period; -extern int sysctl_sched_rt_runtime; - -#ifdef CONFIG_CFS_BANDWIDTH -extern unsigned int sysctl_sched_cfs_bandwidth_slice; -#endif - -#ifdef CONFIG_SCHED_AUTOGROUP -extern unsigned int sysctl_sched_autogroup_enabled; -#endif - -extern int sched_rr_timeslice; - -extern int sched_rr_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos); - -extern int sched_rt_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos); - -extern int sysctl_numa_balancing(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos); - -extern int sysctl_schedstats(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos); - -#endif /* _SCHED_SYSCTL_H */ diff --git a/src/linux/include/linux/sched_clock.h b/src/linux/include/linux/sched_clock.h deleted file mode 100644 index 411b52e..0000000 --- a/src/linux/include/linux/sched_clock.h +++ /dev/null @@ -1,26 +0,0 @@ -/* - * sched_clock.h: support for extending counters to full 64-bit ns counter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef LINUX_SCHED_CLOCK -#define LINUX_SCHED_CLOCK - -#ifdef CONFIG_GENERIC_SCHED_CLOCK -extern void sched_clock_postinit(void); - -extern void sched_clock_register(u64 (*read)(void), int bits, - unsigned long rate); -#else -static inline void sched_clock_postinit(void) { } - -static inline void sched_clock_register(u64 (*read)(void), int bits, - unsigned long rate) -{ - ; -} -#endif - -#endif diff --git a/src/linux/include/linux/screen_info.h b/src/linux/include/linux/screen_info.h deleted file mode 100644 index f0f8bad..0000000 --- a/src/linux/include/linux/screen_info.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _SCREEN_INFO_H -#define _SCREEN_INFO_H - -#include - -extern struct screen_info screen_info; - -#endif /* _SCREEN_INFO_H */ diff --git a/src/linux/include/linux/sctp.h b/src/linux/include/linux/sctp.h deleted file mode 100644 index fcb4c36..0000000 --- a/src/linux/include/linux/sctp.h +++ /dev/null @@ -1,713 +0,0 @@ -/* SCTP kernel reference Implementation - * (C) Copyright IBM Corp. 2001, 2004 - * Copyright (c) 1999-2000 Cisco, Inc. - * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001 Intel Corp. - * Copyright (c) 2001 Nokia, Inc. - * Copyright (c) 2001 La Monte H.P. Yarroll - * - * This file is part of the SCTP kernel reference Implementation - * - * Various protocol defined structures. - * - * This SCTP implementation is free software; - * you can redistribute it and/or modify it under the terms of - * the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This SCTP implementation is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * ************************ - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, see - * . - * - * Please send any bug reports or fixes you make to the - * email address(es): - * lksctp developers - * - * Or submit a bug report through the following website: - * http://www.sf.net/projects/lksctp - * - * Written or modified by: - * La Monte H.P. Yarroll - * Karl Knutson - * Jon Grimm - * Xingang Guo - * randall@sctp.chicago.il.us - * kmorneau@cisco.com - * qxie1@email.mot.com - * Sridhar Samudrala - * Kevin Gao - * - * Any bugs reported given to us we will try to fix... any fixes shared will - * be incorporated into the next SCTP release. - */ -#ifndef __LINUX_SCTP_H__ -#define __LINUX_SCTP_H__ - -#include /* We need in_addr. */ -#include /* We need in6_addr. */ -#include - -#include - -/* Section 3.1. SCTP Common Header Format */ -typedef struct sctphdr { - __be16 source; - __be16 dest; - __be32 vtag; - __le32 checksum; -} __packed sctp_sctphdr_t; - -static inline struct sctphdr *sctp_hdr(const struct sk_buff *skb) -{ - return (struct sctphdr *)skb_transport_header(skb); -} - -/* Section 3.2. Chunk Field Descriptions. */ -typedef struct sctp_chunkhdr { - __u8 type; - __u8 flags; - __be16 length; -} __packed sctp_chunkhdr_t; - - -/* Section 3.2. Chunk Type Values. - * [Chunk Type] identifies the type of information contained in the Chunk - * Value field. It takes a value from 0 to 254. The value of 255 is - * reserved for future use as an extension field. - */ -typedef enum { - SCTP_CID_DATA = 0, - SCTP_CID_INIT = 1, - SCTP_CID_INIT_ACK = 2, - SCTP_CID_SACK = 3, - SCTP_CID_HEARTBEAT = 4, - SCTP_CID_HEARTBEAT_ACK = 5, - SCTP_CID_ABORT = 6, - SCTP_CID_SHUTDOWN = 7, - SCTP_CID_SHUTDOWN_ACK = 8, - SCTP_CID_ERROR = 9, - SCTP_CID_COOKIE_ECHO = 10, - SCTP_CID_COOKIE_ACK = 11, - SCTP_CID_ECN_ECNE = 12, - SCTP_CID_ECN_CWR = 13, - SCTP_CID_SHUTDOWN_COMPLETE = 14, - - /* AUTH Extension Section 4.1 */ - SCTP_CID_AUTH = 0x0F, - - /* PR-SCTP Sec 3.2 */ - SCTP_CID_FWD_TSN = 0xC0, - - /* Use hex, as defined in ADDIP sec. 3.1 */ - SCTP_CID_ASCONF = 0xC1, - SCTP_CID_ASCONF_ACK = 0x80, -} sctp_cid_t; /* enum */ - - -/* Section 3.2 - * Chunk Types are encoded such that the highest-order two bits specify - * the action that must be taken if the processing endpoint does not - * recognize the Chunk Type. - */ -typedef enum { - SCTP_CID_ACTION_DISCARD = 0x00, - SCTP_CID_ACTION_DISCARD_ERR = 0x40, - SCTP_CID_ACTION_SKIP = 0x80, - SCTP_CID_ACTION_SKIP_ERR = 0xc0, -} sctp_cid_action_t; - -enum { SCTP_CID_ACTION_MASK = 0xc0, }; - -/* This flag is used in Chunk Flags for ABORT and SHUTDOWN COMPLETE. - * - * 3.3.7 Abort Association (ABORT) (6): - * The T bit is set to 0 if the sender had a TCB that it destroyed. - * If the sender did not have a TCB it should set this bit to 1. - */ -enum { SCTP_CHUNK_FLAG_T = 0x01 }; - -/* - * Set the T bit - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type = 14 |Reserved |T| Length = 4 | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * Chunk Flags: 8 bits - * - * Reserved: 7 bits - * Set to 0 on transmit and ignored on receipt. - * - * T bit: 1 bit - * The T bit is set to 0 if the sender had a TCB that it destroyed. If - * the sender did NOT have a TCB it should set this bit to 1. - * - * Note: Special rules apply to this chunk for verification, please - * see Section 8.5.1 for details. - */ - -#define sctp_test_T_bit(c) ((c)->chunk_hdr->flags & SCTP_CHUNK_FLAG_T) - -/* RFC 2960 - * Section 3.2.1 Optional/Variable-length Parmaeter Format. - */ - -typedef struct sctp_paramhdr { - __be16 type; - __be16 length; -} __packed sctp_paramhdr_t; - -typedef enum { - - /* RFC 2960 Section 3.3.5 */ - SCTP_PARAM_HEARTBEAT_INFO = cpu_to_be16(1), - /* RFC 2960 Section 3.3.2.1 */ - SCTP_PARAM_IPV4_ADDRESS = cpu_to_be16(5), - SCTP_PARAM_IPV6_ADDRESS = cpu_to_be16(6), - SCTP_PARAM_STATE_COOKIE = cpu_to_be16(7), - SCTP_PARAM_UNRECOGNIZED_PARAMETERS = cpu_to_be16(8), - SCTP_PARAM_COOKIE_PRESERVATIVE = cpu_to_be16(9), - SCTP_PARAM_HOST_NAME_ADDRESS = cpu_to_be16(11), - SCTP_PARAM_SUPPORTED_ADDRESS_TYPES = cpu_to_be16(12), - SCTP_PARAM_ECN_CAPABLE = cpu_to_be16(0x8000), - - /* AUTH Extension Section 3 */ - SCTP_PARAM_RANDOM = cpu_to_be16(0x8002), - SCTP_PARAM_CHUNKS = cpu_to_be16(0x8003), - SCTP_PARAM_HMAC_ALGO = cpu_to_be16(0x8004), - - /* Add-IP: Supported Extensions, Section 4.2 */ - SCTP_PARAM_SUPPORTED_EXT = cpu_to_be16(0x8008), - - /* PR-SCTP Sec 3.1 */ - SCTP_PARAM_FWD_TSN_SUPPORT = cpu_to_be16(0xc000), - - /* Add-IP Extension. Section 3.2 */ - SCTP_PARAM_ADD_IP = cpu_to_be16(0xc001), - SCTP_PARAM_DEL_IP = cpu_to_be16(0xc002), - SCTP_PARAM_ERR_CAUSE = cpu_to_be16(0xc003), - SCTP_PARAM_SET_PRIMARY = cpu_to_be16(0xc004), - SCTP_PARAM_SUCCESS_REPORT = cpu_to_be16(0xc005), - SCTP_PARAM_ADAPTATION_LAYER_IND = cpu_to_be16(0xc006), - -} sctp_param_t; /* enum */ - - -/* RFC 2960 Section 3.2.1 - * The Parameter Types are encoded such that the highest-order two bits - * specify the action that must be taken if the processing endpoint does - * not recognize the Parameter Type. - * - */ -typedef enum { - SCTP_PARAM_ACTION_DISCARD = cpu_to_be16(0x0000), - SCTP_PARAM_ACTION_DISCARD_ERR = cpu_to_be16(0x4000), - SCTP_PARAM_ACTION_SKIP = cpu_to_be16(0x8000), - SCTP_PARAM_ACTION_SKIP_ERR = cpu_to_be16(0xc000), -} sctp_param_action_t; - -enum { SCTP_PARAM_ACTION_MASK = cpu_to_be16(0xc000), }; - -/* RFC 2960 Section 3.3.1 Payload Data (DATA) (0) */ - -typedef struct sctp_datahdr { - __be32 tsn; - __be16 stream; - __be16 ssn; - __be32 ppid; - __u8 payload[0]; -} __packed sctp_datahdr_t; - -typedef struct sctp_data_chunk { - sctp_chunkhdr_t chunk_hdr; - sctp_datahdr_t data_hdr; -} __packed sctp_data_chunk_t; - -/* DATA Chuck Specific Flags */ -enum { - SCTP_DATA_MIDDLE_FRAG = 0x00, - SCTP_DATA_LAST_FRAG = 0x01, - SCTP_DATA_FIRST_FRAG = 0x02, - SCTP_DATA_NOT_FRAG = 0x03, - SCTP_DATA_UNORDERED = 0x04, - SCTP_DATA_SACK_IMM = 0x08, -}; -enum { SCTP_DATA_FRAG_MASK = 0x03, }; - - -/* RFC 2960 Section 3.3.2 Initiation (INIT) (1) - * - * This chunk is used to initiate a SCTP association between two - * endpoints. - */ -typedef struct sctp_inithdr { - __be32 init_tag; - __be32 a_rwnd; - __be16 num_outbound_streams; - __be16 num_inbound_streams; - __be32 initial_tsn; - __u8 params[0]; -} __packed sctp_inithdr_t; - -typedef struct sctp_init_chunk { - sctp_chunkhdr_t chunk_hdr; - sctp_inithdr_t init_hdr; -} __packed sctp_init_chunk_t; - - -/* Section 3.3.2.1. IPv4 Address Parameter (5) */ -typedef struct sctp_ipv4addr_param { - sctp_paramhdr_t param_hdr; - struct in_addr addr; -} __packed sctp_ipv4addr_param_t; - -/* Section 3.3.2.1. IPv6 Address Parameter (6) */ -typedef struct sctp_ipv6addr_param { - sctp_paramhdr_t param_hdr; - struct in6_addr addr; -} __packed sctp_ipv6addr_param_t; - -/* Section 3.3.2.1 Cookie Preservative (9) */ -typedef struct sctp_cookie_preserve_param { - sctp_paramhdr_t param_hdr; - __be32 lifespan_increment; -} __packed sctp_cookie_preserve_param_t; - -/* Section 3.3.2.1 Host Name Address (11) */ -typedef struct sctp_hostname_param { - sctp_paramhdr_t param_hdr; - uint8_t hostname[0]; -} __packed sctp_hostname_param_t; - -/* Section 3.3.2.1 Supported Address Types (12) */ -typedef struct sctp_supported_addrs_param { - sctp_paramhdr_t param_hdr; - __be16 types[0]; -} __packed sctp_supported_addrs_param_t; - -/* Appendix A. ECN Capable (32768) */ -typedef struct sctp_ecn_capable_param { - sctp_paramhdr_t param_hdr; -} __packed sctp_ecn_capable_param_t; - -/* ADDIP Section 3.2.6 Adaptation Layer Indication */ -typedef struct sctp_adaptation_ind_param { - struct sctp_paramhdr param_hdr; - __be32 adaptation_ind; -} __packed sctp_adaptation_ind_param_t; - -/* ADDIP Section 4.2.7 Supported Extensions Parameter */ -typedef struct sctp_supported_ext_param { - struct sctp_paramhdr param_hdr; - __u8 chunks[0]; -} __packed sctp_supported_ext_param_t; - -/* AUTH Section 3.1 Random */ -typedef struct sctp_random_param { - sctp_paramhdr_t param_hdr; - __u8 random_val[0]; -} __packed sctp_random_param_t; - -/* AUTH Section 3.2 Chunk List */ -typedef struct sctp_chunks_param { - sctp_paramhdr_t param_hdr; - __u8 chunks[0]; -} __packed sctp_chunks_param_t; - -/* AUTH Section 3.3 HMAC Algorithm */ -typedef struct sctp_hmac_algo_param { - sctp_paramhdr_t param_hdr; - __be16 hmac_ids[0]; -} __packed sctp_hmac_algo_param_t; - -/* RFC 2960. Section 3.3.3 Initiation Acknowledgement (INIT ACK) (2): - * The INIT ACK chunk is used to acknowledge the initiation of an SCTP - * association. - */ -typedef sctp_init_chunk_t sctp_initack_chunk_t; - -/* Section 3.3.3.1 State Cookie (7) */ -typedef struct sctp_cookie_param { - sctp_paramhdr_t p; - __u8 body[0]; -} __packed sctp_cookie_param_t; - -/* Section 3.3.3.1 Unrecognized Parameters (8) */ -typedef struct sctp_unrecognized_param { - sctp_paramhdr_t param_hdr; - sctp_paramhdr_t unrecognized; -} __packed sctp_unrecognized_param_t; - - - -/* - * 3.3.4 Selective Acknowledgement (SACK) (3): - * - * This chunk is sent to the peer endpoint to acknowledge received DATA - * chunks and to inform the peer endpoint of gaps in the received - * subsequences of DATA chunks as represented by their TSNs. - */ - -typedef struct sctp_gap_ack_block { - __be16 start; - __be16 end; -} __packed sctp_gap_ack_block_t; - -typedef __be32 sctp_dup_tsn_t; - -typedef union { - sctp_gap_ack_block_t gab; - sctp_dup_tsn_t dup; -} sctp_sack_variable_t; - -typedef struct sctp_sackhdr { - __be32 cum_tsn_ack; - __be32 a_rwnd; - __be16 num_gap_ack_blocks; - __be16 num_dup_tsns; - sctp_sack_variable_t variable[0]; -} __packed sctp_sackhdr_t; - -typedef struct sctp_sack_chunk { - sctp_chunkhdr_t chunk_hdr; - sctp_sackhdr_t sack_hdr; -} __packed sctp_sack_chunk_t; - - -/* RFC 2960. Section 3.3.5 Heartbeat Request (HEARTBEAT) (4): - * - * An endpoint should send this chunk to its peer endpoint to probe the - * reachability of a particular destination transport address defined in - * the present association. - */ - -typedef struct sctp_heartbeathdr { - sctp_paramhdr_t info; -} __packed sctp_heartbeathdr_t; - -typedef struct sctp_heartbeat_chunk { - sctp_chunkhdr_t chunk_hdr; - sctp_heartbeathdr_t hb_hdr; -} __packed sctp_heartbeat_chunk_t; - - -/* For the abort and shutdown ACK we must carry the init tag in the - * common header. Just the common header is all that is needed with a - * chunk descriptor. - */ -typedef struct sctp_abort_chunk { - sctp_chunkhdr_t uh; -} __packed sctp_abort_chunk_t; - - -/* For the graceful shutdown we must carry the tag (in common header) - * and the highest consecutive acking value. - */ -typedef struct sctp_shutdownhdr { - __be32 cum_tsn_ack; -} __packed sctp_shutdownhdr_t; - -struct sctp_shutdown_chunk_t { - sctp_chunkhdr_t chunk_hdr; - sctp_shutdownhdr_t shutdown_hdr; -} __packed; - -/* RFC 2960. Section 3.3.10 Operation Error (ERROR) (9) */ - -typedef struct sctp_errhdr { - __be16 cause; - __be16 length; - __u8 variable[0]; -} __packed sctp_errhdr_t; - -typedef struct sctp_operr_chunk { - sctp_chunkhdr_t chunk_hdr; - sctp_errhdr_t err_hdr; -} __packed sctp_operr_chunk_t; - -/* RFC 2960 3.3.10 - Operation Error - * - * Cause Code: 16 bits (unsigned integer) - * - * Defines the type of error conditions being reported. - * Cause Code - * Value Cause Code - * --------- ---------------- - * 1 Invalid Stream Identifier - * 2 Missing Mandatory Parameter - * 3 Stale Cookie Error - * 4 Out of Resource - * 5 Unresolvable Address - * 6 Unrecognized Chunk Type - * 7 Invalid Mandatory Parameter - * 8 Unrecognized Parameters - * 9 No User Data - * 10 Cookie Received While Shutting Down - */ -typedef enum { - - SCTP_ERROR_NO_ERROR = cpu_to_be16(0x00), - SCTP_ERROR_INV_STRM = cpu_to_be16(0x01), - SCTP_ERROR_MISS_PARAM = cpu_to_be16(0x02), - SCTP_ERROR_STALE_COOKIE = cpu_to_be16(0x03), - SCTP_ERROR_NO_RESOURCE = cpu_to_be16(0x04), - SCTP_ERROR_DNS_FAILED = cpu_to_be16(0x05), - SCTP_ERROR_UNKNOWN_CHUNK = cpu_to_be16(0x06), - SCTP_ERROR_INV_PARAM = cpu_to_be16(0x07), - SCTP_ERROR_UNKNOWN_PARAM = cpu_to_be16(0x08), - SCTP_ERROR_NO_DATA = cpu_to_be16(0x09), - SCTP_ERROR_COOKIE_IN_SHUTDOWN = cpu_to_be16(0x0a), - - - /* SCTP Implementation Guide: - * 11 Restart of an association with new addresses - * 12 User Initiated Abort - * 13 Protocol Violation - */ - - SCTP_ERROR_RESTART = cpu_to_be16(0x0b), - SCTP_ERROR_USER_ABORT = cpu_to_be16(0x0c), - SCTP_ERROR_PROTO_VIOLATION = cpu_to_be16(0x0d), - - /* ADDIP Section 3.3 New Error Causes - * - * Four new Error Causes are added to the SCTP Operational Errors, - * primarily for use in the ASCONF-ACK chunk. - * - * Value Cause Code - * --------- ---------------- - * 0x00A0 Request to Delete Last Remaining IP Address. - * 0x00A1 Operation Refused Due to Resource Shortage. - * 0x00A2 Request to Delete Source IP Address. - * 0x00A3 Association Aborted due to illegal ASCONF-ACK - * 0x00A4 Request refused - no authorization. - */ - SCTP_ERROR_DEL_LAST_IP = cpu_to_be16(0x00A0), - SCTP_ERROR_RSRC_LOW = cpu_to_be16(0x00A1), - SCTP_ERROR_DEL_SRC_IP = cpu_to_be16(0x00A2), - SCTP_ERROR_ASCONF_ACK = cpu_to_be16(0x00A3), - SCTP_ERROR_REQ_REFUSED = cpu_to_be16(0x00A4), - - /* AUTH Section 4. New Error Cause - * - * This section defines a new error cause that will be sent if an AUTH - * chunk is received with an unsupported HMAC identifier. - * illustrates the new error cause. - * - * Cause Code Error Cause Name - * -------------------------------------------------------------- - * 0x0105 Unsupported HMAC Identifier - */ - SCTP_ERROR_UNSUP_HMAC = cpu_to_be16(0x0105) -} sctp_error_t; - - - -/* RFC 2960. Appendix A. Explicit Congestion Notification. - * Explicit Congestion Notification Echo (ECNE) (12) - */ -typedef struct sctp_ecnehdr { - __be32 lowest_tsn; -} sctp_ecnehdr_t; - -typedef struct sctp_ecne_chunk { - sctp_chunkhdr_t chunk_hdr; - sctp_ecnehdr_t ence_hdr; -} __packed sctp_ecne_chunk_t; - -/* RFC 2960. Appendix A. Explicit Congestion Notification. - * Congestion Window Reduced (CWR) (13) - */ -typedef struct sctp_cwrhdr { - __be32 lowest_tsn; -} sctp_cwrhdr_t; - -typedef struct sctp_cwr_chunk { - sctp_chunkhdr_t chunk_hdr; - sctp_cwrhdr_t cwr_hdr; -} __packed sctp_cwr_chunk_t; - -/* PR-SCTP - * 3.2 Forward Cumulative TSN Chunk Definition (FORWARD TSN) - * - * Forward Cumulative TSN chunk has the following format: - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type = 192 | Flags = 0x00 | Length = Variable | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | New Cumulative TSN | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Stream-1 | Stream Sequence-1 | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * \ / - * / \ - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Stream-N | Stream Sequence-N | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * Chunk Flags: - * - * Set to all zeros on transmit and ignored on receipt. - * - * New Cumulative TSN: 32 bit u_int - * - * This indicates the new cumulative TSN to the data receiver. Upon - * the reception of this value, the data receiver MUST consider - * any missing TSNs earlier than or equal to this value as received - * and stop reporting them as gaps in any subsequent SACKs. - * - * Stream-N: 16 bit u_int - * - * This field holds a stream number that was skipped by this - * FWD-TSN. - * - * Stream Sequence-N: 16 bit u_int - * This field holds the sequence number associated with the stream - * that was skipped. The stream sequence field holds the largest stream - * sequence number in this stream being skipped. The receiver of - * the FWD-TSN's can use the Stream-N and Stream Sequence-N fields - * to enable delivery of any stranded TSN's that remain on the stream - * re-ordering queues. This field MUST NOT report TSN's corresponding - * to DATA chunk that are marked as unordered. For ordered DATA - * chunks this field MUST be filled in. - */ -struct sctp_fwdtsn_skip { - __be16 stream; - __be16 ssn; -} __packed; - -struct sctp_fwdtsn_hdr { - __be32 new_cum_tsn; - struct sctp_fwdtsn_skip skip[0]; -} __packed; - -struct sctp_fwdtsn_chunk { - struct sctp_chunkhdr chunk_hdr; - struct sctp_fwdtsn_hdr fwdtsn_hdr; -} __packed; - - -/* ADDIP - * Section 3.1.1 Address Configuration Change Chunk (ASCONF) - * - * Serial Number: 32 bits (unsigned integer) - * This value represents a Serial Number for the ASCONF Chunk. The - * valid range of Serial Number is from 0 to 2^32-1. - * Serial Numbers wrap back to 0 after reaching 2^32 -1. - * - * Address Parameter: 8 or 20 bytes (depending on type) - * The address is an address of the sender of the ASCONF chunk, - * the address MUST be considered part of the association by the - * peer endpoint. This field may be used by the receiver of the - * ASCONF to help in finding the association. This parameter MUST - * be present in every ASCONF message i.e. it is a mandatory TLV - * parameter. - * - * ASCONF Parameter: TLV format - * Each Address configuration change is represented by a TLV - * parameter as defined in Section 3.2. One or more requests may - * be present in an ASCONF Chunk. - * - * Section 3.1.2 Address Configuration Acknowledgement Chunk (ASCONF-ACK) - * - * Serial Number: 32 bits (unsigned integer) - * This value represents the Serial Number for the received ASCONF - * Chunk that is acknowledged by this chunk. This value is copied - * from the received ASCONF Chunk. - * - * ASCONF Parameter Response: TLV format - * The ASCONF Parameter Response is used in the ASCONF-ACK to - * report status of ASCONF processing. - */ -typedef struct sctp_addip_param { - sctp_paramhdr_t param_hdr; - __be32 crr_id; -} __packed sctp_addip_param_t; - -typedef struct sctp_addiphdr { - __be32 serial; - __u8 params[0]; -} __packed sctp_addiphdr_t; - -typedef struct sctp_addip_chunk { - sctp_chunkhdr_t chunk_hdr; - sctp_addiphdr_t addip_hdr; -} __packed sctp_addip_chunk_t; - -/* AUTH - * Section 4.1 Authentication Chunk (AUTH) - * - * This chunk is used to hold the result of the HMAC calculation. - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Type = 0x0F | Flags=0 | Length | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Shared Key Identifier | HMAC Identifier | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | | - * \ HMAC / - * / \ - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * Type: 1 byte (unsigned integer) - * This value MUST be set to 0x0F for all AUTH-chunks. - * - * Flags: 1 byte (unsigned integer) - * Set to zero on transmit and ignored on receipt. - * - * Length: 2 bytes (unsigned integer) - * This value holds the length of the HMAC in bytes plus 8. - * - * Shared Key Identifier: 2 bytes (unsigned integer) - * This value describes which endpoint pair shared key is used. - * - * HMAC Identifier: 2 bytes (unsigned integer) - * This value describes which message digest is being used. Table 2 - * shows the currently defined values. - * - * The following Table 2 shows the currently defined values for HMAC - * identifiers. - * - * +-----------------+--------------------------+ - * | HMAC Identifier | Message Digest Algorithm | - * +-----------------+--------------------------+ - * | 0 | Reserved | - * | 1 | SHA-1 defined in [8] | - * | 2 | Reserved | - * | 3 | SHA-256 defined in [8] | - * +-----------------+--------------------------+ - * - * - * HMAC: n bytes (unsigned integer) This hold the result of the HMAC - * calculation. - */ -typedef struct sctp_authhdr { - __be16 shkey_id; - __be16 hmac_id; - __u8 hmac[0]; -} __packed sctp_authhdr_t; - -typedef struct sctp_auth_chunk { - sctp_chunkhdr_t chunk_hdr; - sctp_authhdr_t auth_hdr; -} __packed sctp_auth_chunk_t; - -struct sctp_infox { - struct sctp_info *sctpinfo; - struct sctp_association *asoc; -}; - -#endif /* __LINUX_SCTP_H__ */ diff --git a/src/linux/include/linux/seccomp.h b/src/linux/include/linux/seccomp.h deleted file mode 100644 index ecc296c..0000000 --- a/src/linux/include/linux/seccomp.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef _LINUX_SECCOMP_H -#define _LINUX_SECCOMP_H - -#include - -#define SECCOMP_FILTER_FLAG_MASK (SECCOMP_FILTER_FLAG_TSYNC) - -#ifdef CONFIG_SECCOMP - -#include -#include - -struct seccomp_filter; -/** - * struct seccomp - the state of a seccomp'ed process - * - * @mode: indicates one of the valid values above for controlled - * system calls available to a process. - * @filter: must always point to a valid seccomp-filter or NULL as it is - * accessed without locking during system call entry. - * - * @filter must only be accessed from the context of current as there - * is no read locking. - */ -struct seccomp { - int mode; - struct seccomp_filter *filter; -}; - -#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER -extern int __secure_computing(const struct seccomp_data *sd); -static inline int secure_computing(const struct seccomp_data *sd) -{ - if (unlikely(test_thread_flag(TIF_SECCOMP))) - return __secure_computing(sd); - return 0; -} -#else -extern void secure_computing_strict(int this_syscall); -#endif - -extern long prctl_get_seccomp(void); -extern long prctl_set_seccomp(unsigned long, char __user *); - -static inline int seccomp_mode(struct seccomp *s) -{ - return s->mode; -} - -#else /* CONFIG_SECCOMP */ - -#include - -struct seccomp { }; -struct seccomp_filter { }; - -#ifdef CONFIG_HAVE_ARCH_SECCOMP_FILTER -static inline int secure_computing(struct seccomp_data *sd) { return 0; } -#else -static inline void secure_computing_strict(int this_syscall) { return; } -#endif - -static inline long prctl_get_seccomp(void) -{ - return -EINVAL; -} - -static inline long prctl_set_seccomp(unsigned long arg2, char __user *arg3) -{ - return -EINVAL; -} - -static inline int seccomp_mode(struct seccomp *s) -{ - return SECCOMP_MODE_DISABLED; -} -#endif /* CONFIG_SECCOMP */ - -#ifdef CONFIG_SECCOMP_FILTER -extern void put_seccomp_filter(struct task_struct *tsk); -extern void get_seccomp_filter(struct task_struct *tsk); -#else /* CONFIG_SECCOMP_FILTER */ -static inline void put_seccomp_filter(struct task_struct *tsk) -{ - return; -} -static inline void get_seccomp_filter(struct task_struct *tsk) -{ - return; -} -#endif /* CONFIG_SECCOMP_FILTER */ - -#if defined(CONFIG_SECCOMP_FILTER) && defined(CONFIG_CHECKPOINT_RESTORE) -extern long seccomp_get_filter(struct task_struct *task, - unsigned long filter_off, void __user *data); -#else -static inline long seccomp_get_filter(struct task_struct *task, - unsigned long n, void __user *data) -{ - return -EINVAL; -} -#endif /* CONFIG_SECCOMP_FILTER && CONFIG_CHECKPOINT_RESTORE */ -#endif /* _LINUX_SECCOMP_H */ diff --git a/src/linux/include/linux/securebits.h b/src/linux/include/linux/securebits.h deleted file mode 100644 index da1b33b..0000000 --- a/src/linux/include/linux/securebits.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _LINUX_SECUREBITS_H -#define _LINUX_SECUREBITS_H 1 - -#include - -#define issecure(X) (issecure_mask(X) & current_cred_xxx(securebits)) -#endif /* !_LINUX_SECUREBITS_H */ diff --git a/src/linux/include/linux/security.h b/src/linux/include/linux/security.h deleted file mode 100644 index c2125e9..0000000 --- a/src/linux/include/linux/security.h +++ /dev/null @@ -1,1689 +0,0 @@ -/* - * Linux Security plug - * - * Copyright (C) 2001 WireX Communications, Inc - * Copyright (C) 2001 Greg Kroah-Hartman - * Copyright (C) 2001 Networks Associates Technology, Inc - * Copyright (C) 2001 James Morris - * Copyright (C) 2001 Silicon Graphics, Inc. (Trust Technology Group) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Due to this file being licensed under the GPL there is controversy over - * whether this permits you to write a module that #includes this file - * without placing your module under the GPL. Please consult a lawyer for - * advice before doing this. - * - */ - -#ifndef __LINUX_SECURITY_H -#define __LINUX_SECURITY_H - -#include -#include -#include -#include -#include -#include -#include -#include - -struct linux_binprm; -struct cred; -struct rlimit; -struct siginfo; -struct sem_array; -struct sembuf; -struct kern_ipc_perm; -struct audit_context; -struct super_block; -struct inode; -struct dentry; -struct file; -struct vfsmount; -struct path; -struct qstr; -struct iattr; -struct fown_struct; -struct file_operations; -struct shmid_kernel; -struct msg_msg; -struct msg_queue; -struct xattr; -struct xfrm_sec_ctx; -struct mm_struct; - -/* If capable should audit the security request */ -#define SECURITY_CAP_NOAUDIT 0 -#define SECURITY_CAP_AUDIT 1 - -/* LSM Agnostic defines for sb_set_mnt_opts */ -#define SECURITY_LSM_NATIVE_LABELS 1 - -struct ctl_table; -struct audit_krule; -struct user_namespace; -struct timezone; - -/* These functions are in security/commoncap.c */ -extern int cap_capable(const struct cred *cred, struct user_namespace *ns, - int cap, int audit); -extern int cap_settime(const struct timespec64 *ts, const struct timezone *tz); -extern int cap_ptrace_access_check(struct task_struct *child, unsigned int mode); -extern int cap_ptrace_traceme(struct task_struct *parent); -extern int cap_capget(struct task_struct *target, kernel_cap_t *effective, kernel_cap_t *inheritable, kernel_cap_t *permitted); -extern int cap_capset(struct cred *new, const struct cred *old, - const kernel_cap_t *effective, - const kernel_cap_t *inheritable, - const kernel_cap_t *permitted); -extern int cap_bprm_set_creds(struct linux_binprm *bprm); -extern int cap_bprm_secureexec(struct linux_binprm *bprm); -extern int cap_inode_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags); -extern int cap_inode_removexattr(struct dentry *dentry, const char *name); -extern int cap_inode_need_killpriv(struct dentry *dentry); -extern int cap_inode_killpriv(struct dentry *dentry); -extern int cap_mmap_addr(unsigned long addr); -extern int cap_mmap_file(struct file *file, unsigned long reqprot, - unsigned long prot, unsigned long flags); -extern int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags); -extern int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5); -extern int cap_task_setscheduler(struct task_struct *p); -extern int cap_task_setioprio(struct task_struct *p, int ioprio); -extern int cap_task_setnice(struct task_struct *p, int nice); -extern int cap_vm_enough_memory(struct mm_struct *mm, long pages); - -struct msghdr; -struct sk_buff; -struct sock; -struct sockaddr; -struct socket; -struct flowi; -struct dst_entry; -struct xfrm_selector; -struct xfrm_policy; -struct xfrm_state; -struct xfrm_user_sec_ctx; -struct seq_file; - -#ifdef CONFIG_MMU -extern unsigned long mmap_min_addr; -extern unsigned long dac_mmap_min_addr; -#else -#define mmap_min_addr 0UL -#define dac_mmap_min_addr 0UL -#endif - -/* - * Values used in the task_security_ops calls - */ -/* setuid or setgid, id0 == uid or gid */ -#define LSM_SETID_ID 1 - -/* setreuid or setregid, id0 == real, id1 == eff */ -#define LSM_SETID_RE 2 - -/* setresuid or setresgid, id0 == real, id1 == eff, uid2 == saved */ -#define LSM_SETID_RES 4 - -/* setfsuid or setfsgid, id0 == fsuid or fsgid */ -#define LSM_SETID_FS 8 - -/* forward declares to avoid warnings */ -struct sched_param; -struct request_sock; - -/* bprm->unsafe reasons */ -#define LSM_UNSAFE_SHARE 1 -#define LSM_UNSAFE_PTRACE 2 -#define LSM_UNSAFE_PTRACE_CAP 4 -#define LSM_UNSAFE_NO_NEW_PRIVS 8 - -#ifdef CONFIG_MMU -extern int mmap_min_addr_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); -#endif - -/* security_inode_init_security callback function to write xattrs */ -typedef int (*initxattrs) (struct inode *inode, - const struct xattr *xattr_array, void *fs_data); - -#ifdef CONFIG_SECURITY - -struct security_mnt_opts { - char **mnt_opts; - int *mnt_opts_flags; - int num_mnt_opts; -}; - -static inline void security_init_mnt_opts(struct security_mnt_opts *opts) -{ - opts->mnt_opts = NULL; - opts->mnt_opts_flags = NULL; - opts->num_mnt_opts = 0; -} - -static inline void security_free_mnt_opts(struct security_mnt_opts *opts) -{ - int i; - if (opts->mnt_opts) - for (i = 0; i < opts->num_mnt_opts; i++) - kfree(opts->mnt_opts[i]); - kfree(opts->mnt_opts); - opts->mnt_opts = NULL; - kfree(opts->mnt_opts_flags); - opts->mnt_opts_flags = NULL; - opts->num_mnt_opts = 0; -} - -/* prototypes */ -extern int security_init(void); - -/* Security operations */ -int security_binder_set_context_mgr(struct task_struct *mgr); -int security_binder_transaction(struct task_struct *from, - struct task_struct *to); -int security_binder_transfer_binder(struct task_struct *from, - struct task_struct *to); -int security_binder_transfer_file(struct task_struct *from, - struct task_struct *to, struct file *file); -int security_ptrace_access_check(struct task_struct *child, unsigned int mode); -int security_ptrace_traceme(struct task_struct *parent); -int security_capget(struct task_struct *target, - kernel_cap_t *effective, - kernel_cap_t *inheritable, - kernel_cap_t *permitted); -int security_capset(struct cred *new, const struct cred *old, - const kernel_cap_t *effective, - const kernel_cap_t *inheritable, - const kernel_cap_t *permitted); -int security_capable(const struct cred *cred, struct user_namespace *ns, - int cap); -int security_capable_noaudit(const struct cred *cred, struct user_namespace *ns, - int cap); -int security_quotactl(int cmds, int type, int id, struct super_block *sb); -int security_quota_on(struct dentry *dentry); -int security_syslog(int type); -int security_settime64(const struct timespec64 *ts, const struct timezone *tz); -static inline int security_settime(const struct timespec *ts, const struct timezone *tz) -{ - struct timespec64 ts64 = timespec_to_timespec64(*ts); - - return security_settime64(&ts64, tz); -} -int security_vm_enough_memory_mm(struct mm_struct *mm, long pages); -int security_bprm_set_creds(struct linux_binprm *bprm); -int security_bprm_check(struct linux_binprm *bprm); -void security_bprm_committing_creds(struct linux_binprm *bprm); -void security_bprm_committed_creds(struct linux_binprm *bprm); -int security_bprm_secureexec(struct linux_binprm *bprm); -int security_sb_alloc(struct super_block *sb); -void security_sb_free(struct super_block *sb); -int security_sb_copy_data(char *orig, char *copy); -int security_sb_remount(struct super_block *sb, void *data); -int security_sb_kern_mount(struct super_block *sb, int flags, void *data); -int security_sb_show_options(struct seq_file *m, struct super_block *sb); -int security_sb_statfs(struct dentry *dentry); -int security_sb_mount(const char *dev_name, const struct path *path, - const char *type, unsigned long flags, void *data); -int security_sb_umount(struct vfsmount *mnt, int flags); -int security_sb_pivotroot(const struct path *old_path, const struct path *new_path); -int security_sb_set_mnt_opts(struct super_block *sb, - struct security_mnt_opts *opts, - unsigned long kern_flags, - unsigned long *set_kern_flags); -int security_sb_clone_mnt_opts(const struct super_block *oldsb, - struct super_block *newsb); -int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts); -int security_dentry_init_security(struct dentry *dentry, int mode, - const struct qstr *name, void **ctx, - u32 *ctxlen); -int security_dentry_create_files_as(struct dentry *dentry, int mode, - struct qstr *name, - const struct cred *old, - struct cred *new); - -int security_inode_alloc(struct inode *inode); -void security_inode_free(struct inode *inode); -int security_inode_init_security(struct inode *inode, struct inode *dir, - const struct qstr *qstr, - initxattrs initxattrs, void *fs_data); -int security_old_inode_init_security(struct inode *inode, struct inode *dir, - const struct qstr *qstr, const char **name, - void **value, size_t *len); -int security_inode_create(struct inode *dir, struct dentry *dentry, umode_t mode); -int security_inode_link(struct dentry *old_dentry, struct inode *dir, - struct dentry *new_dentry); -int security_inode_unlink(struct inode *dir, struct dentry *dentry); -int security_inode_symlink(struct inode *dir, struct dentry *dentry, - const char *old_name); -int security_inode_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode); -int security_inode_rmdir(struct inode *dir, struct dentry *dentry); -int security_inode_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev); -int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry, - struct inode *new_dir, struct dentry *new_dentry, - unsigned int flags); -int security_inode_readlink(struct dentry *dentry); -int security_inode_follow_link(struct dentry *dentry, struct inode *inode, - bool rcu); -int security_inode_permission(struct inode *inode, int mask); -int security_inode_setattr(struct dentry *dentry, struct iattr *attr); -int security_inode_getattr(const struct path *path); -int security_inode_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags); -void security_inode_post_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags); -int security_inode_getxattr(struct dentry *dentry, const char *name); -int security_inode_listxattr(struct dentry *dentry); -int security_inode_removexattr(struct dentry *dentry, const char *name); -int security_inode_need_killpriv(struct dentry *dentry); -int security_inode_killpriv(struct dentry *dentry); -int security_inode_getsecurity(struct inode *inode, const char *name, void **buffer, bool alloc); -int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags); -int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size); -void security_inode_getsecid(struct inode *inode, u32 *secid); -int security_inode_copy_up(struct dentry *src, struct cred **new); -int security_inode_copy_up_xattr(const char *name); -int security_file_permission(struct file *file, int mask); -int security_file_alloc(struct file *file); -void security_file_free(struct file *file); -int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -int security_mmap_file(struct file *file, unsigned long prot, - unsigned long flags); -int security_mmap_addr(unsigned long addr); -int security_file_mprotect(struct vm_area_struct *vma, unsigned long reqprot, - unsigned long prot); -int security_file_lock(struct file *file, unsigned int cmd); -int security_file_fcntl(struct file *file, unsigned int cmd, unsigned long arg); -void security_file_set_fowner(struct file *file); -int security_file_send_sigiotask(struct task_struct *tsk, - struct fown_struct *fown, int sig); -int security_file_receive(struct file *file); -int security_file_open(struct file *file, const struct cred *cred); -int security_task_create(unsigned long clone_flags); -void security_task_free(struct task_struct *task); -int security_cred_alloc_blank(struct cred *cred, gfp_t gfp); -void security_cred_free(struct cred *cred); -int security_prepare_creds(struct cred *new, const struct cred *old, gfp_t gfp); -void security_transfer_creds(struct cred *new, const struct cred *old); -int security_kernel_act_as(struct cred *new, u32 secid); -int security_kernel_create_files_as(struct cred *new, struct inode *inode); -int security_kernel_module_request(char *kmod_name); -int security_kernel_read_file(struct file *file, enum kernel_read_file_id id); -int security_kernel_post_read_file(struct file *file, char *buf, loff_t size, - enum kernel_read_file_id id); -int security_task_fix_setuid(struct cred *new, const struct cred *old, - int flags); -int security_task_setpgid(struct task_struct *p, pid_t pgid); -int security_task_getpgid(struct task_struct *p); -int security_task_getsid(struct task_struct *p); -void security_task_getsecid(struct task_struct *p, u32 *secid); -int security_task_setnice(struct task_struct *p, int nice); -int security_task_setioprio(struct task_struct *p, int ioprio); -int security_task_getioprio(struct task_struct *p); -int security_task_setrlimit(struct task_struct *p, unsigned int resource, - struct rlimit *new_rlim); -int security_task_setscheduler(struct task_struct *p); -int security_task_getscheduler(struct task_struct *p); -int security_task_movememory(struct task_struct *p); -int security_task_kill(struct task_struct *p, struct siginfo *info, - int sig, u32 secid); -int security_task_wait(struct task_struct *p); -int security_task_prctl(int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5); -void security_task_to_inode(struct task_struct *p, struct inode *inode); -int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag); -void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid); -int security_msg_msg_alloc(struct msg_msg *msg); -void security_msg_msg_free(struct msg_msg *msg); -int security_msg_queue_alloc(struct msg_queue *msq); -void security_msg_queue_free(struct msg_queue *msq); -int security_msg_queue_associate(struct msg_queue *msq, int msqflg); -int security_msg_queue_msgctl(struct msg_queue *msq, int cmd); -int security_msg_queue_msgsnd(struct msg_queue *msq, - struct msg_msg *msg, int msqflg); -int security_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg, - struct task_struct *target, long type, int mode); -int security_shm_alloc(struct shmid_kernel *shp); -void security_shm_free(struct shmid_kernel *shp); -int security_shm_associate(struct shmid_kernel *shp, int shmflg); -int security_shm_shmctl(struct shmid_kernel *shp, int cmd); -int security_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr, int shmflg); -int security_sem_alloc(struct sem_array *sma); -void security_sem_free(struct sem_array *sma); -int security_sem_associate(struct sem_array *sma, int semflg); -int security_sem_semctl(struct sem_array *sma, int cmd); -int security_sem_semop(struct sem_array *sma, struct sembuf *sops, - unsigned nsops, int alter); -void security_d_instantiate(struct dentry *dentry, struct inode *inode); -int security_getprocattr(struct task_struct *p, char *name, char **value); -int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size); -int security_netlink_send(struct sock *sk, struct sk_buff *skb); -int security_ismaclabel(const char *name); -int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen); -int security_secctx_to_secid(const char *secdata, u32 seclen, u32 *secid); -void security_release_secctx(char *secdata, u32 seclen); - -void security_inode_invalidate_secctx(struct inode *inode); -int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen); -int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen); -int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen); -#else /* CONFIG_SECURITY */ -struct security_mnt_opts { -}; - -static inline void security_init_mnt_opts(struct security_mnt_opts *opts) -{ -} - -static inline void security_free_mnt_opts(struct security_mnt_opts *opts) -{ -} - -/* - * This is the default capabilities functionality. Most of these functions - * are just stubbed out, but a few must call the proper capable code. - */ - -static inline int security_init(void) -{ - return 0; -} - -static inline int security_binder_set_context_mgr(struct task_struct *mgr) -{ - return 0; -} - -static inline int security_binder_transaction(struct task_struct *from, - struct task_struct *to) -{ - return 0; -} - -static inline int security_binder_transfer_binder(struct task_struct *from, - struct task_struct *to) -{ - return 0; -} - -static inline int security_binder_transfer_file(struct task_struct *from, - struct task_struct *to, - struct file *file) -{ - return 0; -} - -static inline int security_ptrace_access_check(struct task_struct *child, - unsigned int mode) -{ - return cap_ptrace_access_check(child, mode); -} - -static inline int security_ptrace_traceme(struct task_struct *parent) -{ - return cap_ptrace_traceme(parent); -} - -static inline int security_capget(struct task_struct *target, - kernel_cap_t *effective, - kernel_cap_t *inheritable, - kernel_cap_t *permitted) -{ - return cap_capget(target, effective, inheritable, permitted); -} - -static inline int security_capset(struct cred *new, - const struct cred *old, - const kernel_cap_t *effective, - const kernel_cap_t *inheritable, - const kernel_cap_t *permitted) -{ - return cap_capset(new, old, effective, inheritable, permitted); -} - -static inline int security_capable(const struct cred *cred, - struct user_namespace *ns, int cap) -{ - return cap_capable(cred, ns, cap, SECURITY_CAP_AUDIT); -} - -static inline int security_capable_noaudit(const struct cred *cred, - struct user_namespace *ns, int cap) { - return cap_capable(cred, ns, cap, SECURITY_CAP_NOAUDIT); -} - -static inline int security_quotactl(int cmds, int type, int id, - struct super_block *sb) -{ - return 0; -} - -static inline int security_quota_on(struct dentry *dentry) -{ - return 0; -} - -static inline int security_syslog(int type) -{ - return 0; -} - -static inline int security_settime64(const struct timespec64 *ts, - const struct timezone *tz) -{ - return cap_settime(ts, tz); -} - -static inline int security_settime(const struct timespec *ts, - const struct timezone *tz) -{ - struct timespec64 ts64 = timespec_to_timespec64(*ts); - - return cap_settime(&ts64, tz); -} - -static inline int security_vm_enough_memory_mm(struct mm_struct *mm, long pages) -{ - return __vm_enough_memory(mm, pages, cap_vm_enough_memory(mm, pages)); -} - -static inline int security_bprm_set_creds(struct linux_binprm *bprm) -{ - return cap_bprm_set_creds(bprm); -} - -static inline int security_bprm_check(struct linux_binprm *bprm) -{ - return 0; -} - -static inline void security_bprm_committing_creds(struct linux_binprm *bprm) -{ -} - -static inline void security_bprm_committed_creds(struct linux_binprm *bprm) -{ -} - -static inline int security_bprm_secureexec(struct linux_binprm *bprm) -{ - return cap_bprm_secureexec(bprm); -} - -static inline int security_sb_alloc(struct super_block *sb) -{ - return 0; -} - -static inline void security_sb_free(struct super_block *sb) -{ } - -static inline int security_sb_copy_data(char *orig, char *copy) -{ - return 0; -} - -static inline int security_sb_remount(struct super_block *sb, void *data) -{ - return 0; -} - -static inline int security_sb_kern_mount(struct super_block *sb, int flags, void *data) -{ - return 0; -} - -static inline int security_sb_show_options(struct seq_file *m, - struct super_block *sb) -{ - return 0; -} - -static inline int security_sb_statfs(struct dentry *dentry) -{ - return 0; -} - -static inline int security_sb_mount(const char *dev_name, const struct path *path, - const char *type, unsigned long flags, - void *data) -{ - return 0; -} - -static inline int security_sb_umount(struct vfsmount *mnt, int flags) -{ - return 0; -} - -static inline int security_sb_pivotroot(const struct path *old_path, - const struct path *new_path) -{ - return 0; -} - -static inline int security_sb_set_mnt_opts(struct super_block *sb, - struct security_mnt_opts *opts, - unsigned long kern_flags, - unsigned long *set_kern_flags) -{ - return 0; -} - -static inline int security_sb_clone_mnt_opts(const struct super_block *oldsb, - struct super_block *newsb) -{ - return 0; -} - -static inline int security_sb_parse_opts_str(char *options, struct security_mnt_opts *opts) -{ - return 0; -} - -static inline int security_inode_alloc(struct inode *inode) -{ - return 0; -} - -static inline void security_inode_free(struct inode *inode) -{ } - -static inline int security_dentry_init_security(struct dentry *dentry, - int mode, - const struct qstr *name, - void **ctx, - u32 *ctxlen) -{ - return -EOPNOTSUPP; -} - -static inline int security_dentry_create_files_as(struct dentry *dentry, - int mode, struct qstr *name, - const struct cred *old, - struct cred *new) -{ - return 0; -} - - -static inline int security_inode_init_security(struct inode *inode, - struct inode *dir, - const struct qstr *qstr, - const initxattrs xattrs, - void *fs_data) -{ - return 0; -} - -static inline int security_old_inode_init_security(struct inode *inode, - struct inode *dir, - const struct qstr *qstr, - const char **name, - void **value, size_t *len) -{ - return -EOPNOTSUPP; -} - -static inline int security_inode_create(struct inode *dir, - struct dentry *dentry, - umode_t mode) -{ - return 0; -} - -static inline int security_inode_link(struct dentry *old_dentry, - struct inode *dir, - struct dentry *new_dentry) -{ - return 0; -} - -static inline int security_inode_unlink(struct inode *dir, - struct dentry *dentry) -{ - return 0; -} - -static inline int security_inode_symlink(struct inode *dir, - struct dentry *dentry, - const char *old_name) -{ - return 0; -} - -static inline int security_inode_mkdir(struct inode *dir, - struct dentry *dentry, - int mode) -{ - return 0; -} - -static inline int security_inode_rmdir(struct inode *dir, - struct dentry *dentry) -{ - return 0; -} - -static inline int security_inode_mknod(struct inode *dir, - struct dentry *dentry, - int mode, dev_t dev) -{ - return 0; -} - -static inline int security_inode_rename(struct inode *old_dir, - struct dentry *old_dentry, - struct inode *new_dir, - struct dentry *new_dentry, - unsigned int flags) -{ - return 0; -} - -static inline int security_inode_readlink(struct dentry *dentry) -{ - return 0; -} - -static inline int security_inode_follow_link(struct dentry *dentry, - struct inode *inode, - bool rcu) -{ - return 0; -} - -static inline int security_inode_permission(struct inode *inode, int mask) -{ - return 0; -} - -static inline int security_inode_setattr(struct dentry *dentry, - struct iattr *attr) -{ - return 0; -} - -static inline int security_inode_getattr(const struct path *path) -{ - return 0; -} - -static inline int security_inode_setxattr(struct dentry *dentry, - const char *name, const void *value, size_t size, int flags) -{ - return cap_inode_setxattr(dentry, name, value, size, flags); -} - -static inline void security_inode_post_setxattr(struct dentry *dentry, - const char *name, const void *value, size_t size, int flags) -{ } - -static inline int security_inode_getxattr(struct dentry *dentry, - const char *name) -{ - return 0; -} - -static inline int security_inode_listxattr(struct dentry *dentry) -{ - return 0; -} - -static inline int security_inode_removexattr(struct dentry *dentry, - const char *name) -{ - return cap_inode_removexattr(dentry, name); -} - -static inline int security_inode_need_killpriv(struct dentry *dentry) -{ - return cap_inode_need_killpriv(dentry); -} - -static inline int security_inode_killpriv(struct dentry *dentry) -{ - return cap_inode_killpriv(dentry); -} - -static inline int security_inode_getsecurity(struct inode *inode, const char *name, void **buffer, bool alloc) -{ - return -EOPNOTSUPP; -} - -static inline int security_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags) -{ - return -EOPNOTSUPP; -} - -static inline int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size) -{ - return 0; -} - -static inline void security_inode_getsecid(struct inode *inode, u32 *secid) -{ - *secid = 0; -} - -static inline int security_inode_copy_up(struct dentry *src, struct cred **new) -{ - return 0; -} - -static inline int security_inode_copy_up_xattr(const char *name) -{ - return -EOPNOTSUPP; -} - -static inline int security_file_permission(struct file *file, int mask) -{ - return 0; -} - -static inline int security_file_alloc(struct file *file) -{ - return 0; -} - -static inline void security_file_free(struct file *file) -{ } - -static inline int security_file_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return 0; -} - -static inline int security_mmap_file(struct file *file, unsigned long prot, - unsigned long flags) -{ - return 0; -} - -static inline int security_mmap_addr(unsigned long addr) -{ - return cap_mmap_addr(addr); -} - -static inline int security_file_mprotect(struct vm_area_struct *vma, - unsigned long reqprot, - unsigned long prot) -{ - return 0; -} - -static inline int security_file_lock(struct file *file, unsigned int cmd) -{ - return 0; -} - -static inline int security_file_fcntl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - return 0; -} - -static inline void security_file_set_fowner(struct file *file) -{ - return; -} - -static inline int security_file_send_sigiotask(struct task_struct *tsk, - struct fown_struct *fown, - int sig) -{ - return 0; -} - -static inline int security_file_receive(struct file *file) -{ - return 0; -} - -static inline int security_file_open(struct file *file, - const struct cred *cred) -{ - return 0; -} - -static inline int security_task_create(unsigned long clone_flags) -{ - return 0; -} - -static inline void security_task_free(struct task_struct *task) -{ } - -static inline int security_cred_alloc_blank(struct cred *cred, gfp_t gfp) -{ - return 0; -} - -static inline void security_cred_free(struct cred *cred) -{ } - -static inline int security_prepare_creds(struct cred *new, - const struct cred *old, - gfp_t gfp) -{ - return 0; -} - -static inline void security_transfer_creds(struct cred *new, - const struct cred *old) -{ -} - -static inline int security_kernel_act_as(struct cred *cred, u32 secid) -{ - return 0; -} - -static inline int security_kernel_create_files_as(struct cred *cred, - struct inode *inode) -{ - return 0; -} - -static inline int security_kernel_module_request(char *kmod_name) -{ - return 0; -} - -static inline int security_kernel_read_file(struct file *file, - enum kernel_read_file_id id) -{ - return 0; -} - -static inline int security_kernel_post_read_file(struct file *file, - char *buf, loff_t size, - enum kernel_read_file_id id) -{ - return 0; -} - -static inline int security_task_fix_setuid(struct cred *new, - const struct cred *old, - int flags) -{ - return cap_task_fix_setuid(new, old, flags); -} - -static inline int security_task_setpgid(struct task_struct *p, pid_t pgid) -{ - return 0; -} - -static inline int security_task_getpgid(struct task_struct *p) -{ - return 0; -} - -static inline int security_task_getsid(struct task_struct *p) -{ - return 0; -} - -static inline void security_task_getsecid(struct task_struct *p, u32 *secid) -{ - *secid = 0; -} - -static inline int security_task_setnice(struct task_struct *p, int nice) -{ - return cap_task_setnice(p, nice); -} - -static inline int security_task_setioprio(struct task_struct *p, int ioprio) -{ - return cap_task_setioprio(p, ioprio); -} - -static inline int security_task_getioprio(struct task_struct *p) -{ - return 0; -} - -static inline int security_task_setrlimit(struct task_struct *p, - unsigned int resource, - struct rlimit *new_rlim) -{ - return 0; -} - -static inline int security_task_setscheduler(struct task_struct *p) -{ - return cap_task_setscheduler(p); -} - -static inline int security_task_getscheduler(struct task_struct *p) -{ - return 0; -} - -static inline int security_task_movememory(struct task_struct *p) -{ - return 0; -} - -static inline int security_task_kill(struct task_struct *p, - struct siginfo *info, int sig, - u32 secid) -{ - return 0; -} - -static inline int security_task_wait(struct task_struct *p) -{ - return 0; -} - -static inline int security_task_prctl(int option, unsigned long arg2, - unsigned long arg3, - unsigned long arg4, - unsigned long arg5) -{ - return cap_task_prctl(option, arg2, arg3, arg4, arg5); -} - -static inline void security_task_to_inode(struct task_struct *p, struct inode *inode) -{ } - -static inline int security_ipc_permission(struct kern_ipc_perm *ipcp, - short flag) -{ - return 0; -} - -static inline void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid) -{ - *secid = 0; -} - -static inline int security_msg_msg_alloc(struct msg_msg *msg) -{ - return 0; -} - -static inline void security_msg_msg_free(struct msg_msg *msg) -{ } - -static inline int security_msg_queue_alloc(struct msg_queue *msq) -{ - return 0; -} - -static inline void security_msg_queue_free(struct msg_queue *msq) -{ } - -static inline int security_msg_queue_associate(struct msg_queue *msq, - int msqflg) -{ - return 0; -} - -static inline int security_msg_queue_msgctl(struct msg_queue *msq, int cmd) -{ - return 0; -} - -static inline int security_msg_queue_msgsnd(struct msg_queue *msq, - struct msg_msg *msg, int msqflg) -{ - return 0; -} - -static inline int security_msg_queue_msgrcv(struct msg_queue *msq, - struct msg_msg *msg, - struct task_struct *target, - long type, int mode) -{ - return 0; -} - -static inline int security_shm_alloc(struct shmid_kernel *shp) -{ - return 0; -} - -static inline void security_shm_free(struct shmid_kernel *shp) -{ } - -static inline int security_shm_associate(struct shmid_kernel *shp, - int shmflg) -{ - return 0; -} - -static inline int security_shm_shmctl(struct shmid_kernel *shp, int cmd) -{ - return 0; -} - -static inline int security_shm_shmat(struct shmid_kernel *shp, - char __user *shmaddr, int shmflg) -{ - return 0; -} - -static inline int security_sem_alloc(struct sem_array *sma) -{ - return 0; -} - -static inline void security_sem_free(struct sem_array *sma) -{ } - -static inline int security_sem_associate(struct sem_array *sma, int semflg) -{ - return 0; -} - -static inline int security_sem_semctl(struct sem_array *sma, int cmd) -{ - return 0; -} - -static inline int security_sem_semop(struct sem_array *sma, - struct sembuf *sops, unsigned nsops, - int alter) -{ - return 0; -} - -static inline void security_d_instantiate(struct dentry *dentry, struct inode *inode) -{ } - -static inline int security_getprocattr(struct task_struct *p, char *name, char **value) -{ - return -EINVAL; -} - -static inline int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size) -{ - return -EINVAL; -} - -static inline int security_netlink_send(struct sock *sk, struct sk_buff *skb) -{ - return 0; -} - -static inline int security_ismaclabel(const char *name) -{ - return 0; -} - -static inline int security_secid_to_secctx(u32 secid, char **secdata, u32 *seclen) -{ - return -EOPNOTSUPP; -} - -static inline int security_secctx_to_secid(const char *secdata, - u32 seclen, - u32 *secid) -{ - return -EOPNOTSUPP; -} - -static inline void security_release_secctx(char *secdata, u32 seclen) -{ -} - -static inline void security_inode_invalidate_secctx(struct inode *inode) -{ -} - -static inline int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen) -{ - return -EOPNOTSUPP; -} -static inline int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen) -{ - return -EOPNOTSUPP; -} -static inline int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen) -{ - return -EOPNOTSUPP; -} -#endif /* CONFIG_SECURITY */ - -#ifdef CONFIG_SECURITY_NETWORK - -int security_unix_stream_connect(struct sock *sock, struct sock *other, struct sock *newsk); -int security_unix_may_send(struct socket *sock, struct socket *other); -int security_socket_create(int family, int type, int protocol, int kern); -int security_socket_post_create(struct socket *sock, int family, - int type, int protocol, int kern); -int security_socket_bind(struct socket *sock, struct sockaddr *address, int addrlen); -int security_socket_connect(struct socket *sock, struct sockaddr *address, int addrlen); -int security_socket_listen(struct socket *sock, int backlog); -int security_socket_accept(struct socket *sock, struct socket *newsock); -int security_socket_sendmsg(struct socket *sock, struct msghdr *msg, int size); -int security_socket_recvmsg(struct socket *sock, struct msghdr *msg, - int size, int flags); -int security_socket_getsockname(struct socket *sock); -int security_socket_getpeername(struct socket *sock); -int security_socket_getsockopt(struct socket *sock, int level, int optname); -int security_socket_setsockopt(struct socket *sock, int level, int optname); -int security_socket_shutdown(struct socket *sock, int how); -int security_sock_rcv_skb(struct sock *sk, struct sk_buff *skb); -int security_socket_getpeersec_stream(struct socket *sock, char __user *optval, - int __user *optlen, unsigned len); -int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid); -int security_sk_alloc(struct sock *sk, int family, gfp_t priority); -void security_sk_free(struct sock *sk); -void security_sk_clone(const struct sock *sk, struct sock *newsk); -void security_sk_classify_flow(struct sock *sk, struct flowi *fl); -void security_req_classify_flow(const struct request_sock *req, struct flowi *fl); -void security_sock_graft(struct sock*sk, struct socket *parent); -int security_inet_conn_request(struct sock *sk, - struct sk_buff *skb, struct request_sock *req); -void security_inet_csk_clone(struct sock *newsk, - const struct request_sock *req); -void security_inet_conn_established(struct sock *sk, - struct sk_buff *skb); -int security_secmark_relabel_packet(u32 secid); -void security_secmark_refcount_inc(void); -void security_secmark_refcount_dec(void); -int security_tun_dev_alloc_security(void **security); -void security_tun_dev_free_security(void *security); -int security_tun_dev_create(void); -int security_tun_dev_attach_queue(void *security); -int security_tun_dev_attach(struct sock *sk, void *security); -int security_tun_dev_open(void *security); - -#else /* CONFIG_SECURITY_NETWORK */ -static inline int security_unix_stream_connect(struct sock *sock, - struct sock *other, - struct sock *newsk) -{ - return 0; -} - -static inline int security_unix_may_send(struct socket *sock, - struct socket *other) -{ - return 0; -} - -static inline int security_socket_create(int family, int type, - int protocol, int kern) -{ - return 0; -} - -static inline int security_socket_post_create(struct socket *sock, - int family, - int type, - int protocol, int kern) -{ - return 0; -} - -static inline int security_socket_bind(struct socket *sock, - struct sockaddr *address, - int addrlen) -{ - return 0; -} - -static inline int security_socket_connect(struct socket *sock, - struct sockaddr *address, - int addrlen) -{ - return 0; -} - -static inline int security_socket_listen(struct socket *sock, int backlog) -{ - return 0; -} - -static inline int security_socket_accept(struct socket *sock, - struct socket *newsock) -{ - return 0; -} - -static inline int security_socket_sendmsg(struct socket *sock, - struct msghdr *msg, int size) -{ - return 0; -} - -static inline int security_socket_recvmsg(struct socket *sock, - struct msghdr *msg, int size, - int flags) -{ - return 0; -} - -static inline int security_socket_getsockname(struct socket *sock) -{ - return 0; -} - -static inline int security_socket_getpeername(struct socket *sock) -{ - return 0; -} - -static inline int security_socket_getsockopt(struct socket *sock, - int level, int optname) -{ - return 0; -} - -static inline int security_socket_setsockopt(struct socket *sock, - int level, int optname) -{ - return 0; -} - -static inline int security_socket_shutdown(struct socket *sock, int how) -{ - return 0; -} -static inline int security_sock_rcv_skb(struct sock *sk, - struct sk_buff *skb) -{ - return 0; -} - -static inline int security_socket_getpeersec_stream(struct socket *sock, char __user *optval, - int __user *optlen, unsigned len) -{ - return -ENOPROTOOPT; -} - -static inline int security_socket_getpeersec_dgram(struct socket *sock, struct sk_buff *skb, u32 *secid) -{ - return -ENOPROTOOPT; -} - -static inline int security_sk_alloc(struct sock *sk, int family, gfp_t priority) -{ - return 0; -} - -static inline void security_sk_free(struct sock *sk) -{ -} - -static inline void security_sk_clone(const struct sock *sk, struct sock *newsk) -{ -} - -static inline void security_sk_classify_flow(struct sock *sk, struct flowi *fl) -{ -} - -static inline void security_req_classify_flow(const struct request_sock *req, struct flowi *fl) -{ -} - -static inline void security_sock_graft(struct sock *sk, struct socket *parent) -{ -} - -static inline int security_inet_conn_request(struct sock *sk, - struct sk_buff *skb, struct request_sock *req) -{ - return 0; -} - -static inline void security_inet_csk_clone(struct sock *newsk, - const struct request_sock *req) -{ -} - -static inline void security_inet_conn_established(struct sock *sk, - struct sk_buff *skb) -{ -} - -static inline int security_secmark_relabel_packet(u32 secid) -{ - return 0; -} - -static inline void security_secmark_refcount_inc(void) -{ -} - -static inline void security_secmark_refcount_dec(void) -{ -} - -static inline int security_tun_dev_alloc_security(void **security) -{ - return 0; -} - -static inline void security_tun_dev_free_security(void *security) -{ -} - -static inline int security_tun_dev_create(void) -{ - return 0; -} - -static inline int security_tun_dev_attach_queue(void *security) -{ - return 0; -} - -static inline int security_tun_dev_attach(struct sock *sk, void *security) -{ - return 0; -} - -static inline int security_tun_dev_open(void *security) -{ - return 0; -} -#endif /* CONFIG_SECURITY_NETWORK */ - -#ifdef CONFIG_SECURITY_NETWORK_XFRM - -int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, - struct xfrm_user_sec_ctx *sec_ctx, gfp_t gfp); -int security_xfrm_policy_clone(struct xfrm_sec_ctx *old_ctx, struct xfrm_sec_ctx **new_ctxp); -void security_xfrm_policy_free(struct xfrm_sec_ctx *ctx); -int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx); -int security_xfrm_state_alloc(struct xfrm_state *x, struct xfrm_user_sec_ctx *sec_ctx); -int security_xfrm_state_alloc_acquire(struct xfrm_state *x, - struct xfrm_sec_ctx *polsec, u32 secid); -int security_xfrm_state_delete(struct xfrm_state *x); -void security_xfrm_state_free(struct xfrm_state *x); -int security_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir); -int security_xfrm_state_pol_flow_match(struct xfrm_state *x, - struct xfrm_policy *xp, - const struct flowi *fl); -int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid); -void security_skb_classify_flow(struct sk_buff *skb, struct flowi *fl); - -#else /* CONFIG_SECURITY_NETWORK_XFRM */ - -static inline int security_xfrm_policy_alloc(struct xfrm_sec_ctx **ctxp, - struct xfrm_user_sec_ctx *sec_ctx, - gfp_t gfp) -{ - return 0; -} - -static inline int security_xfrm_policy_clone(struct xfrm_sec_ctx *old, struct xfrm_sec_ctx **new_ctxp) -{ - return 0; -} - -static inline void security_xfrm_policy_free(struct xfrm_sec_ctx *ctx) -{ -} - -static inline int security_xfrm_policy_delete(struct xfrm_sec_ctx *ctx) -{ - return 0; -} - -static inline int security_xfrm_state_alloc(struct xfrm_state *x, - struct xfrm_user_sec_ctx *sec_ctx) -{ - return 0; -} - -static inline int security_xfrm_state_alloc_acquire(struct xfrm_state *x, - struct xfrm_sec_ctx *polsec, u32 secid) -{ - return 0; -} - -static inline void security_xfrm_state_free(struct xfrm_state *x) -{ -} - -static inline int security_xfrm_state_delete(struct xfrm_state *x) -{ - return 0; -} - -static inline int security_xfrm_policy_lookup(struct xfrm_sec_ctx *ctx, u32 fl_secid, u8 dir) -{ - return 0; -} - -static inline int security_xfrm_state_pol_flow_match(struct xfrm_state *x, - struct xfrm_policy *xp, const struct flowi *fl) -{ - return 1; -} - -static inline int security_xfrm_decode_session(struct sk_buff *skb, u32 *secid) -{ - return 0; -} - -static inline void security_skb_classify_flow(struct sk_buff *skb, struct flowi *fl) -{ -} - -#endif /* CONFIG_SECURITY_NETWORK_XFRM */ - -#ifdef CONFIG_SECURITY_PATH -int security_path_unlink(const struct path *dir, struct dentry *dentry); -int security_path_mkdir(const struct path *dir, struct dentry *dentry, umode_t mode); -int security_path_rmdir(const struct path *dir, struct dentry *dentry); -int security_path_mknod(const struct path *dir, struct dentry *dentry, umode_t mode, - unsigned int dev); -int security_path_truncate(const struct path *path); -int security_path_symlink(const struct path *dir, struct dentry *dentry, - const char *old_name); -int security_path_link(struct dentry *old_dentry, const struct path *new_dir, - struct dentry *new_dentry); -int security_path_rename(const struct path *old_dir, struct dentry *old_dentry, - const struct path *new_dir, struct dentry *new_dentry, - unsigned int flags); -int security_path_chmod(const struct path *path, umode_t mode); -int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid); -int security_path_chroot(const struct path *path); -#else /* CONFIG_SECURITY_PATH */ -static inline int security_path_unlink(const struct path *dir, struct dentry *dentry) -{ - return 0; -} - -static inline int security_path_mkdir(const struct path *dir, struct dentry *dentry, - umode_t mode) -{ - return 0; -} - -static inline int security_path_rmdir(const struct path *dir, struct dentry *dentry) -{ - return 0; -} - -static inline int security_path_mknod(const struct path *dir, struct dentry *dentry, - umode_t mode, unsigned int dev) -{ - return 0; -} - -static inline int security_path_truncate(const struct path *path) -{ - return 0; -} - -static inline int security_path_symlink(const struct path *dir, struct dentry *dentry, - const char *old_name) -{ - return 0; -} - -static inline int security_path_link(struct dentry *old_dentry, - const struct path *new_dir, - struct dentry *new_dentry) -{ - return 0; -} - -static inline int security_path_rename(const struct path *old_dir, - struct dentry *old_dentry, - const struct path *new_dir, - struct dentry *new_dentry, - unsigned int flags) -{ - return 0; -} - -static inline int security_path_chmod(const struct path *path, umode_t mode) -{ - return 0; -} - -static inline int security_path_chown(const struct path *path, kuid_t uid, kgid_t gid) -{ - return 0; -} - -static inline int security_path_chroot(const struct path *path) -{ - return 0; -} -#endif /* CONFIG_SECURITY_PATH */ - -#ifdef CONFIG_KEYS -#ifdef CONFIG_SECURITY - -int security_key_alloc(struct key *key, const struct cred *cred, unsigned long flags); -void security_key_free(struct key *key); -int security_key_permission(key_ref_t key_ref, - const struct cred *cred, unsigned perm); -int security_key_getsecurity(struct key *key, char **_buffer); - -#else - -static inline int security_key_alloc(struct key *key, - const struct cred *cred, - unsigned long flags) -{ - return 0; -} - -static inline void security_key_free(struct key *key) -{ -} - -static inline int security_key_permission(key_ref_t key_ref, - const struct cred *cred, - unsigned perm) -{ - return 0; -} - -static inline int security_key_getsecurity(struct key *key, char **_buffer) -{ - *_buffer = NULL; - return 0; -} - -#endif -#endif /* CONFIG_KEYS */ - -#ifdef CONFIG_AUDIT -#ifdef CONFIG_SECURITY -int security_audit_rule_init(u32 field, u32 op, char *rulestr, void **lsmrule); -int security_audit_rule_known(struct audit_krule *krule); -int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule, - struct audit_context *actx); -void security_audit_rule_free(void *lsmrule); - -#else - -static inline int security_audit_rule_init(u32 field, u32 op, char *rulestr, - void **lsmrule) -{ - return 0; -} - -static inline int security_audit_rule_known(struct audit_krule *krule) -{ - return 0; -} - -static inline int security_audit_rule_match(u32 secid, u32 field, u32 op, - void *lsmrule, struct audit_context *actx) -{ - return 0; -} - -static inline void security_audit_rule_free(void *lsmrule) -{ } - -#endif /* CONFIG_SECURITY */ -#endif /* CONFIG_AUDIT */ - -#ifdef CONFIG_SECURITYFS - -extern struct dentry *securityfs_create_file(const char *name, umode_t mode, - struct dentry *parent, void *data, - const struct file_operations *fops); -extern struct dentry *securityfs_create_dir(const char *name, struct dentry *parent); -extern void securityfs_remove(struct dentry *dentry); - -#else /* CONFIG_SECURITYFS */ - -static inline struct dentry *securityfs_create_dir(const char *name, - struct dentry *parent) -{ - return ERR_PTR(-ENODEV); -} - -static inline struct dentry *securityfs_create_file(const char *name, - umode_t mode, - struct dentry *parent, - void *data, - const struct file_operations *fops) -{ - return ERR_PTR(-ENODEV); -} - -static inline void securityfs_remove(struct dentry *dentry) -{} - -#endif - -#ifdef CONFIG_SECURITY - -static inline char *alloc_secdata(void) -{ - return (char *)get_zeroed_page(GFP_KERNEL); -} - -static inline void free_secdata(void *secdata) -{ - free_page((unsigned long)secdata); -} - -#else - -static inline char *alloc_secdata(void) -{ - return (char *)1; -} - -static inline void free_secdata(void *secdata) -{ } -#endif /* CONFIG_SECURITY */ - -#endif /* ! __LINUX_SECURITY_H */ - diff --git a/src/linux/include/linux/selection.h b/src/linux/include/linux/selection.h deleted file mode 100644 index 8e4624e..0000000 --- a/src/linux/include/linux/selection.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * selection.h - * - * Interface between console.c, tty_io.c, vt.c, vc_screen.c and selection.c - */ - -#ifndef _LINUX_SELECTION_H_ -#define _LINUX_SELECTION_H_ - -#include -#include - -struct tty_struct; - -extern struct vc_data *sel_cons; -struct tty_struct; - -extern void clear_selection(void); -extern int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty); -extern int paste_selection(struct tty_struct *tty); -extern int sel_loadlut(char __user *p); -extern int mouse_reporting(void); -extern void mouse_report(struct tty_struct * tty, int butt, int mrx, int mry); - -extern int console_blanked; - -extern const unsigned char color_table[]; -extern unsigned char default_red[]; -extern unsigned char default_grn[]; -extern unsigned char default_blu[]; - -extern unsigned short *screen_pos(struct vc_data *vc, int w_offset, int viewed); -extern u16 screen_glyph(struct vc_data *vc, int offset); -extern void complement_pos(struct vc_data *vc, int offset); -extern void invert_screen(struct vc_data *vc, int offset, int count, int shift); - -extern void getconsxy(struct vc_data *vc, unsigned char *p); -extern void putconsxy(struct vc_data *vc, unsigned char *p); - -extern u16 vcs_scr_readw(struct vc_data *vc, const u16 *org); -extern void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org); -extern void vcs_scr_updated(struct vc_data *vc); - -#endif diff --git a/src/linux/include/linux/selinux.h b/src/linux/include/linux/selinux.h deleted file mode 100644 index 44f4596..0000000 --- a/src/linux/include/linux/selinux.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SELinux services exported to the rest of the kernel. - * - * Author: James Morris - * - * Copyright (C) 2005 Red Hat, Inc., James Morris - * Copyright (C) 2006 Trusted Computer Solutions, Inc. - * Copyright (C) 2006 IBM Corporation, Timothy R. Chavez - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2, - * as published by the Free Software Foundation. - */ -#ifndef _LINUX_SELINUX_H -#define _LINUX_SELINUX_H - -struct selinux_audit_rule; -struct audit_context; -struct kern_ipc_perm; - -#ifdef CONFIG_SECURITY_SELINUX - -/** - * selinux_is_enabled - is SELinux enabled? - */ -bool selinux_is_enabled(void); -#else - -static inline bool selinux_is_enabled(void) -{ - return false; -} -#endif /* CONFIG_SECURITY_SELINUX */ - -#endif /* _LINUX_SELINUX_H */ diff --git a/src/linux/include/linux/sem.h b/src/linux/include/linux/sem.h deleted file mode 100644 index d0efd6e..0000000 --- a/src/linux/include/linux/sem.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _LINUX_SEM_H -#define _LINUX_SEM_H - -#include -#include -#include -#include - -struct task_struct; - -/* One sem_array data structure for each set of semaphores in the system. */ -struct sem_array { - struct kern_ipc_perm ____cacheline_aligned_in_smp - sem_perm; /* permissions .. see ipc.h */ - time_t sem_ctime; /* last change time */ - struct sem *sem_base; /* ptr to first semaphore in array */ - struct list_head pending_alter; /* pending operations */ - /* that alter the array */ - struct list_head pending_const; /* pending complex operations */ - /* that do not alter semvals */ - struct list_head list_id; /* undo requests on this array */ - int sem_nsems; /* no. of semaphores in array */ - int complex_count; /* pending complex operations */ - bool complex_mode; /* no parallel simple ops */ -}; - -#ifdef CONFIG_SYSVIPC - -struct sysv_sem { - struct sem_undo_list *undo_list; -}; - -extern int copy_semundo(unsigned long clone_flags, struct task_struct *tsk); -extern void exit_sem(struct task_struct *tsk); - -#else - -struct sysv_sem { - /* empty */ -}; - -static inline int copy_semundo(unsigned long clone_flags, struct task_struct *tsk) -{ - return 0; -} - -static inline void exit_sem(struct task_struct *tsk) -{ - return; -} -#endif - -#endif /* _LINUX_SEM_H */ diff --git a/src/linux/include/linux/semaphore.h b/src/linux/include/linux/semaphore.h deleted file mode 100644 index dc368b8..0000000 --- a/src/linux/include/linux/semaphore.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2008 Intel Corporation - * Author: Matthew Wilcox - * - * Distributed under the terms of the GNU GPL, version 2 - * - * Please see kernel/semaphore.c for documentation of these functions - */ -#ifndef __LINUX_SEMAPHORE_H -#define __LINUX_SEMAPHORE_H - -#include -#include - -/* Please don't access any members of this structure directly */ -struct semaphore { - raw_spinlock_t lock; - unsigned int count; - struct list_head wait_list; -}; - -#define __SEMAPHORE_INITIALIZER(name, n) \ -{ \ - .lock = __RAW_SPIN_LOCK_UNLOCKED((name).lock), \ - .count = n, \ - .wait_list = LIST_HEAD_INIT((name).wait_list), \ -} - -#define DEFINE_SEMAPHORE(name) \ - struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1) - -static inline void sema_init(struct semaphore *sem, int val) -{ - static struct lock_class_key __key; - *sem = (struct semaphore) __SEMAPHORE_INITIALIZER(*sem, val); - lockdep_init_map(&sem->lock.dep_map, "semaphore->lock", &__key, 0); -} - -extern void down(struct semaphore *sem); -extern int __must_check down_interruptible(struct semaphore *sem); -extern int __must_check down_killable(struct semaphore *sem); -extern int __must_check down_trylock(struct semaphore *sem); -extern int __must_check down_timeout(struct semaphore *sem, long jiffies); -extern void up(struct semaphore *sem); - -#endif /* __LINUX_SEMAPHORE_H */ diff --git a/src/linux/include/linux/seq_buf.h b/src/linux/include/linux/seq_buf.h deleted file mode 100644 index fb7eb9c..0000000 --- a/src/linux/include/linux/seq_buf.h +++ /dev/null @@ -1,133 +0,0 @@ -#ifndef _LINUX_SEQ_BUF_H -#define _LINUX_SEQ_BUF_H - -#include - -/* - * Trace sequences are used to allow a function to call several other functions - * to create a string of data to use. - */ - -/** - * seq_buf - seq buffer structure - * @buffer: pointer to the buffer - * @size: size of the buffer - * @len: the amount of data inside the buffer - * @readpos: The next position to read in the buffer. - */ -struct seq_buf { - char *buffer; - size_t size; - size_t len; - loff_t readpos; -}; - -static inline void seq_buf_clear(struct seq_buf *s) -{ - s->len = 0; - s->readpos = 0; -} - -static inline void -seq_buf_init(struct seq_buf *s, unsigned char *buf, unsigned int size) -{ - s->buffer = buf; - s->size = size; - seq_buf_clear(s); -} - -/* - * seq_buf have a buffer that might overflow. When this happens - * the len and size are set to be equal. - */ -static inline bool -seq_buf_has_overflowed(struct seq_buf *s) -{ - return s->len > s->size; -} - -static inline void -seq_buf_set_overflow(struct seq_buf *s) -{ - s->len = s->size + 1; -} - -/* - * How much buffer is left on the seq_buf? - */ -static inline unsigned int -seq_buf_buffer_left(struct seq_buf *s) -{ - if (seq_buf_has_overflowed(s)) - return 0; - - return s->size - s->len; -} - -/* How much buffer was written? */ -static inline unsigned int seq_buf_used(struct seq_buf *s) -{ - return min(s->len, s->size); -} - -/** - * seq_buf_get_buf - get buffer to write arbitrary data to - * @s: the seq_buf handle - * @bufp: the beginning of the buffer is stored here - * - * Return the number of bytes available in the buffer, or zero if - * there's no space. - */ -static inline size_t seq_buf_get_buf(struct seq_buf *s, char **bufp) -{ - WARN_ON(s->len > s->size + 1); - - if (s->len < s->size) { - *bufp = s->buffer + s->len; - return s->size - s->len; - } - - *bufp = NULL; - return 0; -} - -/** - * seq_buf_commit - commit data to the buffer - * @s: the seq_buf handle - * @num: the number of bytes to commit - * - * Commit @num bytes of data written to a buffer previously acquired - * by seq_buf_get. To signal an error condition, or that the data - * didn't fit in the available space, pass a negative @num value. - */ -static inline void seq_buf_commit(struct seq_buf *s, int num) -{ - if (num < 0) { - seq_buf_set_overflow(s); - } else { - /* num must be negative on overflow */ - BUG_ON(s->len + num > s->size); - s->len += num; - } -} - -extern __printf(2, 3) -int seq_buf_printf(struct seq_buf *s, const char *fmt, ...); -extern __printf(2, 0) -int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args); -extern int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s); -extern int seq_buf_to_user(struct seq_buf *s, char __user *ubuf, - int cnt); -extern int seq_buf_puts(struct seq_buf *s, const char *str); -extern int seq_buf_putc(struct seq_buf *s, unsigned char c); -extern int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len); -extern int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, - unsigned int len); -extern int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc); - -#ifdef CONFIG_BINARY_PRINTF -extern int -seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary); -#endif - -#endif /* _LINUX_SEQ_BUF_H */ diff --git a/src/linux/include/linux/seq_file.h b/src/linux/include/linux/seq_file.h deleted file mode 100644 index e305b66..0000000 --- a/src/linux/include/linux/seq_file.h +++ /dev/null @@ -1,223 +0,0 @@ -#ifndef _LINUX_SEQ_FILE_H -#define _LINUX_SEQ_FILE_H - -#include -#include -#include -#include -#include -#include -#include -#include - -struct seq_operations; - -struct seq_file { - char *buf; - size_t size; - size_t from; - size_t count; - size_t pad_until; - loff_t index; - loff_t read_pos; - u64 version; - struct mutex lock; - const struct seq_operations *op; - int poll_event; - const struct file *file; - void *private; -}; - -struct seq_operations { - void * (*start) (struct seq_file *m, loff_t *pos); - void (*stop) (struct seq_file *m, void *v); - void * (*next) (struct seq_file *m, void *v, loff_t *pos); - int (*show) (struct seq_file *m, void *v); -}; - -#define SEQ_SKIP 1 - -/** - * seq_has_overflowed - check if the buffer has overflowed - * @m: the seq_file handle - * - * seq_files have a buffer which may overflow. When this happens a larger - * buffer is reallocated and all the data will be printed again. - * The overflow state is true when m->count == m->size. - * - * Returns true if the buffer received more than it can hold. - */ -static inline bool seq_has_overflowed(struct seq_file *m) -{ - return m->count == m->size; -} - -/** - * seq_get_buf - get buffer to write arbitrary data to - * @m: the seq_file handle - * @bufp: the beginning of the buffer is stored here - * - * Return the number of bytes available in the buffer, or zero if - * there's no space. - */ -static inline size_t seq_get_buf(struct seq_file *m, char **bufp) -{ - BUG_ON(m->count > m->size); - if (m->count < m->size) - *bufp = m->buf + m->count; - else - *bufp = NULL; - - return m->size - m->count; -} - -/** - * seq_commit - commit data to the buffer - * @m: the seq_file handle - * @num: the number of bytes to commit - * - * Commit @num bytes of data written to a buffer previously acquired - * by seq_buf_get. To signal an error condition, or that the data - * didn't fit in the available space, pass a negative @num value. - */ -static inline void seq_commit(struct seq_file *m, int num) -{ - if (num < 0) { - m->count = m->size; - } else { - BUG_ON(m->count + num > m->size); - m->count += num; - } -} - -/** - * seq_setwidth - set padding width - * @m: the seq_file handle - * @size: the max number of bytes to pad. - * - * Call seq_setwidth() for setting max width, then call seq_printf() etc. and - * finally call seq_pad() to pad the remaining bytes. - */ -static inline void seq_setwidth(struct seq_file *m, size_t size) -{ - m->pad_until = m->count + size; -} -void seq_pad(struct seq_file *m, char c); - -char *mangle_path(char *s, const char *p, const char *esc); -int seq_open(struct file *, const struct seq_operations *); -ssize_t seq_read(struct file *, char __user *, size_t, loff_t *); -loff_t seq_lseek(struct file *, loff_t, int); -int seq_release(struct inode *, struct file *); -int seq_write(struct seq_file *seq, const void *data, size_t len); - -__printf(2, 0) -void seq_vprintf(struct seq_file *m, const char *fmt, va_list args); -__printf(2, 3) -void seq_printf(struct seq_file *m, const char *fmt, ...); -void seq_putc(struct seq_file *m, char c); -void seq_puts(struct seq_file *m, const char *s); -void seq_put_decimal_ull(struct seq_file *m, const char *delimiter, - unsigned long long num); -void seq_put_decimal_ll(struct seq_file *m, const char *delimiter, long long num); -void seq_escape(struct seq_file *m, const char *s, const char *esc); - -void seq_hex_dump(struct seq_file *m, const char *prefix_str, int prefix_type, - int rowsize, int groupsize, const void *buf, size_t len, - bool ascii); - -int seq_path(struct seq_file *, const struct path *, const char *); -int seq_file_path(struct seq_file *, struct file *, const char *); -int seq_dentry(struct seq_file *, struct dentry *, const char *); -int seq_path_root(struct seq_file *m, const struct path *path, - const struct path *root, const char *esc); - -int single_open(struct file *, int (*)(struct seq_file *, void *), void *); -int single_open_size(struct file *, int (*)(struct seq_file *, void *), void *, size_t); -int single_release(struct inode *, struct file *); -void *__seq_open_private(struct file *, const struct seq_operations *, int); -int seq_open_private(struct file *, const struct seq_operations *, int); -int seq_release_private(struct inode *, struct file *); - -static inline struct user_namespace *seq_user_ns(struct seq_file *seq) -{ -#ifdef CONFIG_USER_NS - return seq->file->f_cred->user_ns; -#else - extern struct user_namespace init_user_ns; - return &init_user_ns; -#endif -} - -/** - * seq_show_options - display mount options with appropriate escapes. - * @m: the seq_file handle - * @name: the mount option name - * @value: the mount option name's value, can be NULL - */ -static inline void seq_show_option(struct seq_file *m, const char *name, - const char *value) -{ - seq_putc(m, ','); - seq_escape(m, name, ",= \t\n\\"); - if (value) { - seq_putc(m, '='); - seq_escape(m, value, ", \t\n\\"); - } -} - -/** - * seq_show_option_n - display mount options with appropriate escapes - * where @value must be a specific length. - * @m: the seq_file handle - * @name: the mount option name - * @value: the mount option name's value, cannot be NULL - * @length: the length of @value to display - * - * This is a macro since this uses "length" to define the size of the - * stack buffer. - */ -#define seq_show_option_n(m, name, value, length) { \ - char val_buf[length + 1]; \ - strncpy(val_buf, value, length); \ - val_buf[length] = '\0'; \ - seq_show_option(m, name, val_buf); \ -} - -#define SEQ_START_TOKEN ((void *)1) -/* - * Helpers for iteration over list_head-s in seq_files - */ - -extern struct list_head *seq_list_start(struct list_head *head, - loff_t pos); -extern struct list_head *seq_list_start_head(struct list_head *head, - loff_t pos); -extern struct list_head *seq_list_next(void *v, struct list_head *head, - loff_t *ppos); - -/* - * Helpers for iteration over hlist_head-s in seq_files - */ - -extern struct hlist_node *seq_hlist_start(struct hlist_head *head, - loff_t pos); -extern struct hlist_node *seq_hlist_start_head(struct hlist_head *head, - loff_t pos); -extern struct hlist_node *seq_hlist_next(void *v, struct hlist_head *head, - loff_t *ppos); - -extern struct hlist_node *seq_hlist_start_rcu(struct hlist_head *head, - loff_t pos); -extern struct hlist_node *seq_hlist_start_head_rcu(struct hlist_head *head, - loff_t pos); -extern struct hlist_node *seq_hlist_next_rcu(void *v, - struct hlist_head *head, - loff_t *ppos); - -/* Helpers for iterating over per-cpu hlist_head-s in seq_files */ -extern struct hlist_node *seq_hlist_start_percpu(struct hlist_head __percpu *head, int *cpu, loff_t pos); - -extern struct hlist_node *seq_hlist_next_percpu(void *v, struct hlist_head __percpu *head, int *cpu, loff_t *pos); - -#endif diff --git a/src/linux/include/linux/seq_file_net.h b/src/linux/include/linux/seq_file_net.h deleted file mode 100644 index 32c89bb..0000000 --- a/src/linux/include/linux/seq_file_net.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef __SEQ_FILE_NET_H__ -#define __SEQ_FILE_NET_H__ - -#include - -struct net; -extern struct net init_net; - -struct seq_net_private { -#ifdef CONFIG_NET_NS - struct net *net; -#endif -}; - -int seq_open_net(struct inode *, struct file *, - const struct seq_operations *, int); -int single_open_net(struct inode *, struct file *file, - int (*show)(struct seq_file *, void *)); -int seq_release_net(struct inode *, struct file *); -int single_release_net(struct inode *, struct file *); -static inline struct net *seq_file_net(struct seq_file *seq) -{ -#ifdef CONFIG_NET_NS - return ((struct seq_net_private *)seq->private)->net; -#else - return &init_net; -#endif -} - -#endif diff --git a/src/linux/include/linux/seqlock.h b/src/linux/include/linux/seqlock.h deleted file mode 100644 index ead9765..0000000 --- a/src/linux/include/linux/seqlock.h +++ /dev/null @@ -1,601 +0,0 @@ -#ifndef __LINUX_SEQLOCK_H -#define __LINUX_SEQLOCK_H -/* - * Reader/writer consistent mechanism without starving writers. This type of - * lock for data where the reader wants a consistent set of information - * and is willing to retry if the information changes. There are two types - * of readers: - * 1. Sequence readers which never block a writer but they may have to retry - * if a writer is in progress by detecting change in sequence number. - * Writers do not wait for a sequence reader. - * 2. Locking readers which will wait if a writer or another locking reader - * is in progress. A locking reader in progress will also block a writer - * from going forward. Unlike the regular rwlock, the read lock here is - * exclusive so that only one locking reader can get it. - * - * This is not as cache friendly as brlock. Also, this may not work well - * for data that contains pointers, because any writer could - * invalidate a pointer that a reader was following. - * - * Expected non-blocking reader usage: - * do { - * seq = read_seqbegin(&foo); - * ... - * } while (read_seqretry(&foo, seq)); - * - * - * On non-SMP the spin locks disappear but the writer still needs - * to increment the sequence variables because an interrupt routine could - * change the state of the data. - * - * Based on x86_64 vsyscall gettimeofday - * by Keith Owens and Andrea Arcangeli - */ - -#include -#include -#include -#include -#include - -/* - * Version using sequence counter only. - * This can be used when code has its own mutex protecting the - * updating starting before the write_seqcountbeqin() and ending - * after the write_seqcount_end(). - */ -typedef struct seqcount { - unsigned sequence; -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map dep_map; -#endif -} seqcount_t; - -static inline void __seqcount_init(seqcount_t *s, const char *name, - struct lock_class_key *key) -{ - /* - * Make sure we are not reinitializing a held lock: - */ - lockdep_init_map(&s->dep_map, name, key, 0); - s->sequence = 0; -} - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# define SEQCOUNT_DEP_MAP_INIT(lockname) \ - .dep_map = { .name = #lockname } \ - -# define seqcount_init(s) \ - do { \ - static struct lock_class_key __key; \ - __seqcount_init((s), #s, &__key); \ - } while (0) - -static inline void seqcount_lockdep_reader_access(const seqcount_t *s) -{ - seqcount_t *l = (seqcount_t *)s; - unsigned long flags; - - local_irq_save(flags); - seqcount_acquire_read(&l->dep_map, 0, 0, _RET_IP_); - seqcount_release(&l->dep_map, 1, _RET_IP_); - local_irq_restore(flags); -} - -#else -# define SEQCOUNT_DEP_MAP_INIT(lockname) -# define seqcount_init(s) __seqcount_init(s, NULL, NULL) -# define seqcount_lockdep_reader_access(x) -#endif - -#define SEQCNT_ZERO(lockname) { .sequence = 0, SEQCOUNT_DEP_MAP_INIT(lockname)} - - -/** - * __read_seqcount_begin - begin a seq-read critical section (without barrier) - * @s: pointer to seqcount_t - * Returns: count to be passed to read_seqcount_retry - * - * __read_seqcount_begin is like read_seqcount_begin, but has no smp_rmb() - * barrier. Callers should ensure that smp_rmb() or equivalent ordering is - * provided before actually loading any of the variables that are to be - * protected in this critical section. - * - * Use carefully, only in critical code, and comment how the barrier is - * provided. - */ -static inline unsigned __read_seqcount_begin(const seqcount_t *s) -{ - unsigned ret; - -repeat: - ret = READ_ONCE(s->sequence); - if (unlikely(ret & 1)) { - cpu_relax(); - goto repeat; - } - return ret; -} - -/** - * raw_read_seqcount - Read the raw seqcount - * @s: pointer to seqcount_t - * Returns: count to be passed to read_seqcount_retry - * - * raw_read_seqcount opens a read critical section of the given - * seqcount without any lockdep checking and without checking or - * masking the LSB. Calling code is responsible for handling that. - */ -static inline unsigned raw_read_seqcount(const seqcount_t *s) -{ - unsigned ret = READ_ONCE(s->sequence); - smp_rmb(); - return ret; -} - -/** - * raw_read_seqcount_begin - start seq-read critical section w/o lockdep - * @s: pointer to seqcount_t - * Returns: count to be passed to read_seqcount_retry - * - * raw_read_seqcount_begin opens a read critical section of the given - * seqcount, but without any lockdep checking. Validity of the critical - * section is tested by checking read_seqcount_retry function. - */ -static inline unsigned raw_read_seqcount_begin(const seqcount_t *s) -{ - unsigned ret = __read_seqcount_begin(s); - smp_rmb(); - return ret; -} - -/** - * read_seqcount_begin - begin a seq-read critical section - * @s: pointer to seqcount_t - * Returns: count to be passed to read_seqcount_retry - * - * read_seqcount_begin opens a read critical section of the given seqcount. - * Validity of the critical section is tested by checking read_seqcount_retry - * function. - */ -static inline unsigned read_seqcount_begin(const seqcount_t *s) -{ - seqcount_lockdep_reader_access(s); - return raw_read_seqcount_begin(s); -} - -/** - * raw_seqcount_begin - begin a seq-read critical section - * @s: pointer to seqcount_t - * Returns: count to be passed to read_seqcount_retry - * - * raw_seqcount_begin opens a read critical section of the given seqcount. - * Validity of the critical section is tested by checking read_seqcount_retry - * function. - * - * Unlike read_seqcount_begin(), this function will not wait for the count - * to stabilize. If a writer is active when we begin, we will fail the - * read_seqcount_retry() instead of stabilizing at the beginning of the - * critical section. - */ -static inline unsigned raw_seqcount_begin(const seqcount_t *s) -{ - unsigned ret = READ_ONCE(s->sequence); - smp_rmb(); - return ret & ~1; -} - -/** - * __read_seqcount_retry - end a seq-read critical section (without barrier) - * @s: pointer to seqcount_t - * @start: count, from read_seqcount_begin - * Returns: 1 if retry is required, else 0 - * - * __read_seqcount_retry is like read_seqcount_retry, but has no smp_rmb() - * barrier. Callers should ensure that smp_rmb() or equivalent ordering is - * provided before actually loading any of the variables that are to be - * protected in this critical section. - * - * Use carefully, only in critical code, and comment how the barrier is - * provided. - */ -static inline int __read_seqcount_retry(const seqcount_t *s, unsigned start) -{ - return unlikely(s->sequence != start); -} - -/** - * read_seqcount_retry - end a seq-read critical section - * @s: pointer to seqcount_t - * @start: count, from read_seqcount_begin - * Returns: 1 if retry is required, else 0 - * - * read_seqcount_retry closes a read critical section of the given seqcount. - * If the critical section was invalid, it must be ignored (and typically - * retried). - */ -static inline int read_seqcount_retry(const seqcount_t *s, unsigned start) -{ - smp_rmb(); - return __read_seqcount_retry(s, start); -} - - - -static inline void raw_write_seqcount_begin(seqcount_t *s) -{ - s->sequence++; - smp_wmb(); -} - -static inline void raw_write_seqcount_end(seqcount_t *s) -{ - smp_wmb(); - s->sequence++; -} - -/** - * raw_write_seqcount_barrier - do a seq write barrier - * @s: pointer to seqcount_t - * - * This can be used to provide an ordering guarantee instead of the - * usual consistency guarantee. It is one wmb cheaper, because we can - * collapse the two back-to-back wmb()s. - * - * seqcount_t seq; - * bool X = true, Y = false; - * - * void read(void) - * { - * bool x, y; - * - * do { - * int s = read_seqcount_begin(&seq); - * - * x = X; y = Y; - * - * } while (read_seqcount_retry(&seq, s)); - * - * BUG_ON(!x && !y); - * } - * - * void write(void) - * { - * Y = true; - * - * raw_write_seqcount_barrier(seq); - * - * X = false; - * } - */ -static inline void raw_write_seqcount_barrier(seqcount_t *s) -{ - s->sequence++; - smp_wmb(); - s->sequence++; -} - -static inline int raw_read_seqcount_latch(seqcount_t *s) -{ - int seq = READ_ONCE(s->sequence); - /* Pairs with the first smp_wmb() in raw_write_seqcount_latch() */ - smp_read_barrier_depends(); - return seq; -} - -/** - * raw_write_seqcount_latch - redirect readers to even/odd copy - * @s: pointer to seqcount_t - * - * The latch technique is a multiversion concurrency control method that allows - * queries during non-atomic modifications. If you can guarantee queries never - * interrupt the modification -- e.g. the concurrency is strictly between CPUs - * -- you most likely do not need this. - * - * Where the traditional RCU/lockless data structures rely on atomic - * modifications to ensure queries observe either the old or the new state the - * latch allows the same for non-atomic updates. The trade-off is doubling the - * cost of storage; we have to maintain two copies of the entire data - * structure. - * - * Very simply put: we first modify one copy and then the other. This ensures - * there is always one copy in a stable state, ready to give us an answer. - * - * The basic form is a data structure like: - * - * struct latch_struct { - * seqcount_t seq; - * struct data_struct data[2]; - * }; - * - * Where a modification, which is assumed to be externally serialized, does the - * following: - * - * void latch_modify(struct latch_struct *latch, ...) - * { - * smp_wmb(); <- Ensure that the last data[1] update is visible - * latch->seq++; - * smp_wmb(); <- Ensure that the seqcount update is visible - * - * modify(latch->data[0], ...); - * - * smp_wmb(); <- Ensure that the data[0] update is visible - * latch->seq++; - * smp_wmb(); <- Ensure that the seqcount update is visible - * - * modify(latch->data[1], ...); - * } - * - * The query will have a form like: - * - * struct entry *latch_query(struct latch_struct *latch, ...) - * { - * struct entry *entry; - * unsigned seq, idx; - * - * do { - * seq = raw_read_seqcount_latch(&latch->seq); - * - * idx = seq & 0x01; - * entry = data_query(latch->data[idx], ...); - * - * smp_rmb(); - * } while (seq != latch->seq); - * - * return entry; - * } - * - * So during the modification, queries are first redirected to data[1]. Then we - * modify data[0]. When that is complete, we redirect queries back to data[0] - * and we can modify data[1]. - * - * NOTE: The non-requirement for atomic modifications does _NOT_ include - * the publishing of new entries in the case where data is a dynamic - * data structure. - * - * An iteration might start in data[0] and get suspended long enough - * to miss an entire modification sequence, once it resumes it might - * observe the new entry. - * - * NOTE: When data is a dynamic data structure; one should use regular RCU - * patterns to manage the lifetimes of the objects within. - */ -static inline void raw_write_seqcount_latch(seqcount_t *s) -{ - smp_wmb(); /* prior stores before incrementing "sequence" */ - s->sequence++; - smp_wmb(); /* increment "sequence" before following stores */ -} - -/* - * Sequence counter only version assumes that callers are using their - * own mutexing. - */ -static inline void write_seqcount_begin_nested(seqcount_t *s, int subclass) -{ - raw_write_seqcount_begin(s); - seqcount_acquire(&s->dep_map, subclass, 0, _RET_IP_); -} - -static inline void write_seqcount_begin(seqcount_t *s) -{ - write_seqcount_begin_nested(s, 0); -} - -static inline void write_seqcount_end(seqcount_t *s) -{ - seqcount_release(&s->dep_map, 1, _RET_IP_); - raw_write_seqcount_end(s); -} - -/** - * write_seqcount_invalidate - invalidate in-progress read-side seq operations - * @s: pointer to seqcount_t - * - * After write_seqcount_invalidate, no read-side seq operations will complete - * successfully and see data older than this. - */ -static inline void write_seqcount_invalidate(seqcount_t *s) -{ - smp_wmb(); - s->sequence+=2; -} - -typedef struct { - struct seqcount seqcount; - spinlock_t lock; -} seqlock_t; - -/* - * These macros triggered gcc-3.x compile-time problems. We think these are - * OK now. Be cautious. - */ -#define __SEQLOCK_UNLOCKED(lockname) \ - { \ - .seqcount = SEQCNT_ZERO(lockname), \ - .lock = __SPIN_LOCK_UNLOCKED(lockname) \ - } - -#define seqlock_init(x) \ - do { \ - seqcount_init(&(x)->seqcount); \ - spin_lock_init(&(x)->lock); \ - } while (0) - -#define DEFINE_SEQLOCK(x) \ - seqlock_t x = __SEQLOCK_UNLOCKED(x) - -/* - * Read side functions for starting and finalizing a read side section. - */ -static inline unsigned read_seqbegin(const seqlock_t *sl) -{ - return read_seqcount_begin(&sl->seqcount); -} - -static inline unsigned read_seqretry(const seqlock_t *sl, unsigned start) -{ - return read_seqcount_retry(&sl->seqcount, start); -} - -/* - * Lock out other writers and update the count. - * Acts like a normal spin_lock/unlock. - * Don't need preempt_disable() because that is in the spin_lock already. - */ -static inline void write_seqlock(seqlock_t *sl) -{ - spin_lock(&sl->lock); - write_seqcount_begin(&sl->seqcount); -} - -static inline void write_sequnlock(seqlock_t *sl) -{ - write_seqcount_end(&sl->seqcount); - spin_unlock(&sl->lock); -} - -static inline void write_seqlock_bh(seqlock_t *sl) -{ - spin_lock_bh(&sl->lock); - write_seqcount_begin(&sl->seqcount); -} - -static inline void write_sequnlock_bh(seqlock_t *sl) -{ - write_seqcount_end(&sl->seqcount); - spin_unlock_bh(&sl->lock); -} - -static inline void write_seqlock_irq(seqlock_t *sl) -{ - spin_lock_irq(&sl->lock); - write_seqcount_begin(&sl->seqcount); -} - -static inline void write_sequnlock_irq(seqlock_t *sl) -{ - write_seqcount_end(&sl->seqcount); - spin_unlock_irq(&sl->lock); -} - -static inline unsigned long __write_seqlock_irqsave(seqlock_t *sl) -{ - unsigned long flags; - - spin_lock_irqsave(&sl->lock, flags); - write_seqcount_begin(&sl->seqcount); - return flags; -} - -#define write_seqlock_irqsave(lock, flags) \ - do { flags = __write_seqlock_irqsave(lock); } while (0) - -static inline void -write_sequnlock_irqrestore(seqlock_t *sl, unsigned long flags) -{ - write_seqcount_end(&sl->seqcount); - spin_unlock_irqrestore(&sl->lock, flags); -} - -/* - * A locking reader exclusively locks out other writers and locking readers, - * but doesn't update the sequence number. Acts like a normal spin_lock/unlock. - * Don't need preempt_disable() because that is in the spin_lock already. - */ -static inline void read_seqlock_excl(seqlock_t *sl) -{ - spin_lock(&sl->lock); -} - -static inline void read_sequnlock_excl(seqlock_t *sl) -{ - spin_unlock(&sl->lock); -} - -/** - * read_seqbegin_or_lock - begin a sequence number check or locking block - * @lock: sequence lock - * @seq : sequence number to be checked - * - * First try it once optimistically without taking the lock. If that fails, - * take the lock. The sequence number is also used as a marker for deciding - * whether to be a reader (even) or writer (odd). - * N.B. seq must be initialized to an even number to begin with. - */ -static inline void read_seqbegin_or_lock(seqlock_t *lock, int *seq) -{ - if (!(*seq & 1)) /* Even */ - *seq = read_seqbegin(lock); - else /* Odd */ - read_seqlock_excl(lock); -} - -static inline int need_seqretry(seqlock_t *lock, int seq) -{ - return !(seq & 1) && read_seqretry(lock, seq); -} - -static inline void done_seqretry(seqlock_t *lock, int seq) -{ - if (seq & 1) - read_sequnlock_excl(lock); -} - -static inline void read_seqlock_excl_bh(seqlock_t *sl) -{ - spin_lock_bh(&sl->lock); -} - -static inline void read_sequnlock_excl_bh(seqlock_t *sl) -{ - spin_unlock_bh(&sl->lock); -} - -static inline void read_seqlock_excl_irq(seqlock_t *sl) -{ - spin_lock_irq(&sl->lock); -} - -static inline void read_sequnlock_excl_irq(seqlock_t *sl) -{ - spin_unlock_irq(&sl->lock); -} - -static inline unsigned long __read_seqlock_excl_irqsave(seqlock_t *sl) -{ - unsigned long flags; - - spin_lock_irqsave(&sl->lock, flags); - return flags; -} - -#define read_seqlock_excl_irqsave(lock, flags) \ - do { flags = __read_seqlock_excl_irqsave(lock); } while (0) - -static inline void -read_sequnlock_excl_irqrestore(seqlock_t *sl, unsigned long flags) -{ - spin_unlock_irqrestore(&sl->lock, flags); -} - -static inline unsigned long -read_seqbegin_or_lock_irqsave(seqlock_t *lock, int *seq) -{ - unsigned long flags = 0; - - if (!(*seq & 1)) /* Even */ - *seq = read_seqbegin(lock); - else /* Odd */ - read_seqlock_excl_irqsave(lock, flags); - - return flags; -} - -static inline void -done_seqretry_irqrestore(seqlock_t *lock, int seq, unsigned long flags) -{ - if (seq & 1) - read_sequnlock_excl_irqrestore(lock, flags); -} -#endif /* __LINUX_SEQLOCK_H */ diff --git a/src/linux/include/linux/serial.h b/src/linux/include/linux/serial.h deleted file mode 100644 index 0916107..0000000 --- a/src/linux/include/linux/serial.h +++ /dev/null @@ -1,33 +0,0 @@ -/* - * include/linux/serial.h - * - * Copyright (C) 1992 by Theodore Ts'o. - * - * Redistribution of this file is permitted under the terms of the GNU - * Public License (GPL) - */ -#ifndef _LINUX_SERIAL_H -#define _LINUX_SERIAL_H - -#include -#include - - -/* - * Counters of the input lines (CTS, DSR, RI, CD) interrupts - */ - -struct async_icount { - __u32 cts, dsr, rng, dcd, tx, rx; - __u32 frame, parity, overrun, brk; - __u32 buf_overrun; -}; - -/* - * The size of the serial xmit buffer is 1 page, or 4096 bytes - */ -#define SERIAL_XMIT_SIZE PAGE_SIZE - -#include - -#endif /* _LINUX_SERIAL_H */ diff --git a/src/linux/include/linux/serio.h b/src/linux/include/linux/serio.h deleted file mode 100644 index c733cff..0000000 --- a/src/linux/include/linux/serio.h +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright (C) 1999-2002 Vojtech Pavlik -* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ -#ifndef _SERIO_H -#define _SERIO_H - - -#include -#include -#include -#include -#include -#include -#include -#include - -extern struct bus_type serio_bus; - -struct serio { - void *port_data; - - char name[32]; - char phys[32]; - char firmware_id[128]; - - bool manual_bind; - - struct serio_device_id id; - - /* Protects critical sections from port's interrupt handler */ - spinlock_t lock; - - int (*write)(struct serio *, unsigned char); - int (*open)(struct serio *); - void (*close)(struct serio *); - int (*start)(struct serio *); - void (*stop)(struct serio *); - - struct serio *parent; - /* Entry in parent->children list */ - struct list_head child_node; - struct list_head children; - /* Level of nesting in serio hierarchy */ - unsigned int depth; - - /* - * serio->drv is accessed from interrupt handlers; when modifying - * caller should acquire serio->drv_mutex and serio->lock. - */ - struct serio_driver *drv; - /* Protects serio->drv so attributes can pin current driver */ - struct mutex drv_mutex; - - struct device dev; - - struct list_head node; - - /* - * For use by PS/2 layer when several ports share hardware and - * may get indigestion when exposed to concurrent access (i8042). - */ - struct mutex *ps2_cmd_mutex; -}; -#define to_serio_port(d) container_of(d, struct serio, dev) - -struct serio_driver { - const char *description; - - const struct serio_device_id *id_table; - bool manual_bind; - - void (*write_wakeup)(struct serio *); - irqreturn_t (*interrupt)(struct serio *, unsigned char, unsigned int); - int (*connect)(struct serio *, struct serio_driver *drv); - int (*reconnect)(struct serio *); - void (*disconnect)(struct serio *); - void (*cleanup)(struct serio *); - - struct device_driver driver; -}; -#define to_serio_driver(d) container_of(d, struct serio_driver, driver) - -int serio_open(struct serio *serio, struct serio_driver *drv); -void serio_close(struct serio *serio); -void serio_rescan(struct serio *serio); -void serio_reconnect(struct serio *serio); -irqreturn_t serio_interrupt(struct serio *serio, unsigned char data, unsigned int flags); - -void __serio_register_port(struct serio *serio, struct module *owner); - -/* use a define to avoid include chaining to get THIS_MODULE */ -#define serio_register_port(serio) \ - __serio_register_port(serio, THIS_MODULE) - -void serio_unregister_port(struct serio *serio); -void serio_unregister_child_port(struct serio *serio); - -int __must_check __serio_register_driver(struct serio_driver *drv, - struct module *owner, const char *mod_name); - -/* use a define to avoid include chaining to get THIS_MODULE & friends */ -#define serio_register_driver(drv) \ - __serio_register_driver(drv, THIS_MODULE, KBUILD_MODNAME) - -void serio_unregister_driver(struct serio_driver *drv); - -/** - * module_serio_driver() - Helper macro for registering a serio driver - * @__serio_driver: serio_driver struct - * - * Helper macro for serio drivers which do not do anything special in - * module init/exit. This eliminates a lot of boilerplate. Each module - * may only use this macro once, and calling it replaces module_init() - * and module_exit(). - */ -#define module_serio_driver(__serio_driver) \ - module_driver(__serio_driver, serio_register_driver, \ - serio_unregister_driver) - -static inline int serio_write(struct serio *serio, unsigned char data) -{ - if (serio->write) - return serio->write(serio, data); - else - return -1; -} - -static inline void serio_drv_write_wakeup(struct serio *serio) -{ - if (serio->drv && serio->drv->write_wakeup) - serio->drv->write_wakeup(serio); -} - -/* - * Use the following functions to manipulate serio's per-port - * driver-specific data. - */ -static inline void *serio_get_drvdata(struct serio *serio) -{ - return dev_get_drvdata(&serio->dev); -} - -static inline void serio_set_drvdata(struct serio *serio, void *data) -{ - dev_set_drvdata(&serio->dev, data); -} - -/* - * Use the following functions to protect critical sections in - * driver code from port's interrupt handler - */ -static inline void serio_pause_rx(struct serio *serio) -{ - spin_lock_irq(&serio->lock); -} - -static inline void serio_continue_rx(struct serio *serio) -{ - spin_unlock_irq(&serio->lock); -} - -#endif diff --git a/src/linux/include/linux/sfi.h b/src/linux/include/linux/sfi.h deleted file mode 100644 index e0e1597..0000000 --- a/src/linux/include/linux/sfi.h +++ /dev/null @@ -1,210 +0,0 @@ -/* sfi.h Simple Firmware Interface */ - -/* - - This file is provided under a dual BSD/GPLv2 license. When using or - redistributing this file, you may do so under either license. - - GPL LICENSE SUMMARY - - Copyright(c) 2009 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - The full GNU General Public License is included in this distribution - in the file called LICENSE.GPL. - - BSD LICENSE - - Copyright(c) 2009 Intel Corporation. All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - * Neither the name of Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -*/ - -#ifndef _LINUX_SFI_H -#define _LINUX_SFI_H - -#include -#include - -/* Table signatures reserved by the SFI specification */ -#define SFI_SIG_SYST "SYST" -#define SFI_SIG_FREQ "FREQ" -#define SFI_SIG_IDLE "IDLE" -#define SFI_SIG_CPUS "CPUS" -#define SFI_SIG_MTMR "MTMR" -#define SFI_SIG_MRTC "MRTC" -#define SFI_SIG_MMAP "MMAP" -#define SFI_SIG_APIC "APIC" -#define SFI_SIG_XSDT "XSDT" -#define SFI_SIG_WAKE "WAKE" -#define SFI_SIG_DEVS "DEVS" -#define SFI_SIG_GPIO "GPIO" - -#define SFI_SIGNATURE_SIZE 4 -#define SFI_OEM_ID_SIZE 6 -#define SFI_OEM_TABLE_ID_SIZE 8 - -#define SFI_NAME_LEN 16 - -#define SFI_SYST_SEARCH_BEGIN 0x000E0000 -#define SFI_SYST_SEARCH_END 0x000FFFFF - -#define SFI_GET_NUM_ENTRIES(ptable, entry_type) \ - ((ptable->header.len - sizeof(struct sfi_table_header)) / \ - (sizeof(entry_type))) -/* - * Table structures must be byte-packed to match the SFI specification, - * as they are provided by the BIOS. - */ -struct sfi_table_header { - char sig[SFI_SIGNATURE_SIZE]; - u32 len; - u8 rev; - u8 csum; - char oem_id[SFI_OEM_ID_SIZE]; - char oem_table_id[SFI_OEM_TABLE_ID_SIZE]; -} __packed; - -struct sfi_table_simple { - struct sfi_table_header header; - u64 pentry[1]; -} __packed; - -/* Comply with UEFI spec 2.1 */ -struct sfi_mem_entry { - u32 type; - u64 phys_start; - u64 virt_start; - u64 pages; - u64 attrib; -} __packed; - -struct sfi_cpu_table_entry { - u32 apic_id; -} __packed; - -struct sfi_cstate_table_entry { - u32 hint; /* MWAIT hint */ - u32 latency; /* latency in ms */ -} __packed; - -struct sfi_apic_table_entry { - u64 phys_addr; /* phy base addr for APIC reg */ -} __packed; - -struct sfi_freq_table_entry { - u32 freq_mhz; /* in MHZ */ - u32 latency; /* transition latency in ms */ - u32 ctrl_val; /* value to write to PERF_CTL */ -} __packed; - -struct sfi_wake_table_entry { - u64 phys_addr; /* pointer to where the wake vector locates */ -} __packed; - -struct sfi_timer_table_entry { - u64 phys_addr; /* phy base addr for the timer */ - u32 freq_hz; /* in HZ */ - u32 irq; -} __packed; - -struct sfi_rtc_table_entry { - u64 phys_addr; /* phy base addr for the RTC */ - u32 irq; -} __packed; - -struct sfi_device_table_entry { - u8 type; /* bus type, I2C, SPI or ...*/ -#define SFI_DEV_TYPE_SPI 0 -#define SFI_DEV_TYPE_I2C 1 -#define SFI_DEV_TYPE_UART 2 -#define SFI_DEV_TYPE_HSI 3 -#define SFI_DEV_TYPE_IPC 4 -#define SFI_DEV_TYPE_SD 5 - - u8 host_num; /* attached to host 0, 1...*/ - u16 addr; - u8 irq; - u32 max_freq; - char name[SFI_NAME_LEN]; -} __packed; - -struct sfi_gpio_table_entry { - char controller_name[SFI_NAME_LEN]; - u16 pin_no; - char pin_name[SFI_NAME_LEN]; -} __packed; - -typedef int (*sfi_table_handler) (struct sfi_table_header *table); - -#ifdef CONFIG_SFI -extern void __init sfi_init(void); -extern int __init sfi_platform_init(void); -extern void __init sfi_init_late(void); -extern int sfi_table_parse(char *signature, char *oem_id, char *oem_table_id, - sfi_table_handler handler); - -extern int sfi_disabled; -static inline void disable_sfi(void) -{ - sfi_disabled = 1; -} - -#else /* !CONFIG_SFI */ - -static inline void sfi_init(void) -{ -} - -static inline void sfi_init_late(void) -{ -} - -#define sfi_disabled 0 - -static inline int sfi_table_parse(char *signature, char *oem_id, - char *oem_table_id, - sfi_table_handler handler) -{ - return -1; -} - -#endif /* !CONFIG_SFI */ - -#endif /*_LINUX_SFI_H*/ diff --git a/src/linux/include/linux/shm.h b/src/linux/include/linux/shm.h deleted file mode 100644 index 04e8818..0000000 --- a/src/linux/include/linux/shm.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef _LINUX_SHM_H_ -#define _LINUX_SHM_H_ - -#include -#include -#include -#include - -struct shmid_kernel /* private to the kernel */ -{ - struct kern_ipc_perm shm_perm; - struct file *shm_file; - unsigned long shm_nattch; - unsigned long shm_segsz; - time_t shm_atim; - time_t shm_dtim; - time_t shm_ctim; - pid_t shm_cprid; - pid_t shm_lprid; - struct user_struct *mlock_user; - - /* The task created the shm object. NULL if the task is dead. */ - struct task_struct *shm_creator; - struct list_head shm_clist; /* list by creator */ -}; - -/* shm_mode upper byte flags */ -#define SHM_DEST 01000 /* segment will be destroyed on last detach */ -#define SHM_LOCKED 02000 /* segment will not be swapped */ -#define SHM_HUGETLB 04000 /* segment will use huge TLB pages */ -#define SHM_NORESERVE 010000 /* don't check for reservations */ - -/* Bits [26:31] are reserved */ - -/* - * When SHM_HUGETLB is set bits [26:31] encode the log2 of the huge page size. - * This gives us 6 bits, which is enough until someone invents 128 bit address - * spaces. - * - * Assume these are all power of twos. - * When 0 use the default page size. - */ -#define SHM_HUGE_SHIFT 26 -#define SHM_HUGE_MASK 0x3f -#define SHM_HUGE_2MB (21 << SHM_HUGE_SHIFT) -#define SHM_HUGE_1GB (30 << SHM_HUGE_SHIFT) - -#ifdef CONFIG_SYSVIPC -struct sysv_shm { - struct list_head shm_clist; -}; - -long do_shmat(int shmid, char __user *shmaddr, int shmflg, unsigned long *addr, - unsigned long shmlba); -bool is_file_shm_hugepages(struct file *file); -void exit_shm(struct task_struct *task); -#define shm_init_task(task) INIT_LIST_HEAD(&(task)->sysvshm.shm_clist) -#else -struct sysv_shm { - /* empty */ -}; - -static inline long do_shmat(int shmid, char __user *shmaddr, - int shmflg, unsigned long *addr, - unsigned long shmlba) -{ - return -ENOSYS; -} -static inline bool is_file_shm_hugepages(struct file *file) -{ - return false; -} -static inline void exit_shm(struct task_struct *task) -{ -} -static inline void shm_init_task(struct task_struct *task) -{ -} -#endif - -#endif /* _LINUX_SHM_H_ */ diff --git a/src/linux/include/linux/shmem_fs.h b/src/linux/include/linux/shmem_fs.h deleted file mode 100644 index ff078e7..0000000 --- a/src/linux/include/linux/shmem_fs.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef __SHMEM_FS_H -#define __SHMEM_FS_H - -#include -#include -#include -#include -#include -#include - -/* inode in-kernel data */ - -struct shmem_inode_info { - spinlock_t lock; - unsigned int seals; /* shmem seals */ - unsigned long flags; - unsigned long alloced; /* data pages alloced to file */ - unsigned long swapped; /* subtotal assigned to swap */ - struct list_head shrinklist; /* shrinkable hpage inodes */ - struct list_head swaplist; /* chain of maybes on swap */ - struct shared_policy policy; /* NUMA memory alloc policy */ - struct simple_xattrs xattrs; /* list of xattrs */ - struct inode vfs_inode; -}; - -struct shmem_sb_info { - unsigned long max_blocks; /* How many blocks are allowed */ - struct percpu_counter used_blocks; /* How many are allocated */ - unsigned long max_inodes; /* How many inodes are allowed */ - unsigned long free_inodes; /* How many are left for allocation */ - spinlock_t stat_lock; /* Serialize shmem_sb_info changes */ - umode_t mode; /* Mount mode for root directory */ - unsigned char huge; /* Whether to try for hugepages */ - kuid_t uid; /* Mount uid for root directory */ - kgid_t gid; /* Mount gid for root directory */ - struct mempolicy *mpol; /* default memory policy for mappings */ - spinlock_t shrinklist_lock; /* Protects shrinklist */ - struct list_head shrinklist; /* List of shinkable inodes */ - unsigned long shrinklist_len; /* Length of shrinklist */ -}; - -static inline struct shmem_inode_info *SHMEM_I(struct inode *inode) -{ - return container_of(inode, struct shmem_inode_info, vfs_inode); -} - -/* - * Functions in mm/shmem.c called directly from elsewhere: - */ -extern int shmem_init(void); -extern int shmem_fill_super(struct super_block *sb, void *data, int silent); -extern struct file *shmem_file_setup(const char *name, - loff_t size, unsigned long flags); -extern struct file *shmem_kernel_file_setup(const char *name, loff_t size, - unsigned long flags); -extern int shmem_zero_setup(struct vm_area_struct *); -extern unsigned long shmem_get_unmapped_area(struct file *, unsigned long addr, - unsigned long len, unsigned long pgoff, unsigned long flags); -extern int shmem_lock(struct file *file, int lock, struct user_struct *user); -extern bool shmem_mapping(struct address_space *mapping); -extern void shmem_unlock_mapping(struct address_space *mapping); -extern struct page *shmem_read_mapping_page_gfp(struct address_space *mapping, - pgoff_t index, gfp_t gfp_mask); -extern void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end); -extern int shmem_unuse(swp_entry_t entry, struct page *page); - -extern unsigned long shmem_swap_usage(struct vm_area_struct *vma); -extern unsigned long shmem_partial_swap_usage(struct address_space *mapping, - pgoff_t start, pgoff_t end); - -/* Flag allocation requirements to shmem_getpage */ -enum sgp_type { - SGP_READ, /* don't exceed i_size, don't allocate page */ - SGP_CACHE, /* don't exceed i_size, may allocate page */ - SGP_NOHUGE, /* like SGP_CACHE, but no huge pages */ - SGP_HUGE, /* like SGP_CACHE, huge pages preferred */ - SGP_WRITE, /* may exceed i_size, may allocate !Uptodate page */ - SGP_FALLOC, /* like SGP_WRITE, but make existing page Uptodate */ -}; - -extern int shmem_getpage(struct inode *inode, pgoff_t index, - struct page **pagep, enum sgp_type sgp); - -static inline struct page *shmem_read_mapping_page( - struct address_space *mapping, pgoff_t index) -{ - return shmem_read_mapping_page_gfp(mapping, index, - mapping_gfp_mask(mapping)); -} - -static inline bool shmem_file(struct file *file) -{ - if (!IS_ENABLED(CONFIG_SHMEM)) - return false; - if (!file || !file->f_mapping) - return false; - return shmem_mapping(file->f_mapping); -} - -extern bool shmem_charge(struct inode *inode, long pages); -extern void shmem_uncharge(struct inode *inode, long pages); - -#ifdef CONFIG_TMPFS - -extern int shmem_add_seals(struct file *file, unsigned int seals); -extern int shmem_get_seals(struct file *file); -extern long shmem_fcntl(struct file *file, unsigned int cmd, unsigned long arg); - -#else - -static inline long shmem_fcntl(struct file *f, unsigned int c, unsigned long a) -{ - return -EINVAL; -} - -#endif - -#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE -extern bool shmem_huge_enabled(struct vm_area_struct *vma); -#else -static inline bool shmem_huge_enabled(struct vm_area_struct *vma) -{ - return false; -} -#endif - -#endif diff --git a/src/linux/include/linux/shrinker.h b/src/linux/include/linux/shrinker.h deleted file mode 100644 index 4fcacd9..0000000 --- a/src/linux/include/linux/shrinker.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef _LINUX_SHRINKER_H -#define _LINUX_SHRINKER_H - -/* - * This struct is used to pass information from page reclaim to the shrinkers. - * We consolidate the values for easier extention later. - * - * The 'gfpmask' refers to the allocation we are currently trying to - * fulfil. - */ -struct shrink_control { - gfp_t gfp_mask; - - /* - * How many objects scan_objects should scan and try to reclaim. - * This is reset before every call, so it is safe for callees - * to modify. - */ - unsigned long nr_to_scan; - - /* current node being shrunk (for NUMA aware shrinkers) */ - int nid; - - /* current memcg being shrunk (for memcg aware shrinkers) */ - struct mem_cgroup *memcg; -}; - -#define SHRINK_STOP (~0UL) -/* - * A callback you can register to apply pressure to ageable caches. - * - * @count_objects should return the number of freeable items in the cache. If - * there are no objects to free or the number of freeable items cannot be - * determined, it should return 0. No deadlock checks should be done during the - * count callback - the shrinker relies on aggregating scan counts that couldn't - * be executed due to potential deadlocks to be run at a later call when the - * deadlock condition is no longer pending. - * - * @scan_objects will only be called if @count_objects returned a non-zero - * value for the number of freeable objects. The callout should scan the cache - * and attempt to free items from the cache. It should then return the number - * of objects freed during the scan, or SHRINK_STOP if progress cannot be made - * due to potential deadlocks. If SHRINK_STOP is returned, then no further - * attempts to call the @scan_objects will be made from the current reclaim - * context. - * - * @flags determine the shrinker abilities, like numa awareness - */ -struct shrinker { - unsigned long (*count_objects)(struct shrinker *, - struct shrink_control *sc); - unsigned long (*scan_objects)(struct shrinker *, - struct shrink_control *sc); - - int seeks; /* seeks to recreate an obj */ - long batch; /* reclaim batch size, 0 = default */ - unsigned long flags; - - /* These are for internal use */ - struct list_head list; - /* objs pending delete, per node */ - atomic_long_t *nr_deferred; -}; -#define DEFAULT_SEEKS 2 /* A good number if you don't know better. */ - -/* Flags */ -#define SHRINKER_NUMA_AWARE (1 << 0) -#define SHRINKER_MEMCG_AWARE (1 << 1) - -extern int register_shrinker(struct shrinker *); -extern void unregister_shrinker(struct shrinker *); -#endif diff --git a/src/linux/include/linux/signal.h b/src/linux/include/linux/signal.h deleted file mode 100644 index b63f63e..0000000 --- a/src/linux/include/linux/signal.h +++ /dev/null @@ -1,459 +0,0 @@ -#ifndef _LINUX_SIGNAL_H -#define _LINUX_SIGNAL_H - -#include -#include -#include - -struct task_struct; - -/* for sysctl */ -extern int print_fatal_signals; -/* - * Real Time signals may be queued. - */ - -struct sigqueue { - struct list_head list; - int flags; - siginfo_t info; - struct user_struct *user; -}; - -/* flags values. */ -#define SIGQUEUE_PREALLOC 1 - -struct sigpending { - struct list_head list; - sigset_t signal; -}; - -#ifndef HAVE_ARCH_COPY_SIGINFO - -#include - -static inline void copy_siginfo(struct siginfo *to, struct siginfo *from) -{ - if (from->si_code < 0) - memcpy(to, from, sizeof(*to)); - else - /* _sigchld is currently the largest know union member */ - memcpy(to, from, __ARCH_SI_PREAMBLE_SIZE + sizeof(from->_sifields._sigchld)); -} - -#endif - -/* - * Define some primitives to manipulate sigset_t. - */ - -#ifndef __HAVE_ARCH_SIG_BITOPS -#include - -/* We don't use for these because there is no need to - be atomic. */ -static inline void sigaddset(sigset_t *set, int _sig) -{ - unsigned long sig = _sig - 1; - if (_NSIG_WORDS == 1) - set->sig[0] |= 1UL << sig; - else - set->sig[sig / _NSIG_BPW] |= 1UL << (sig % _NSIG_BPW); -} - -static inline void sigdelset(sigset_t *set, int _sig) -{ - unsigned long sig = _sig - 1; - if (_NSIG_WORDS == 1) - set->sig[0] &= ~(1UL << sig); - else - set->sig[sig / _NSIG_BPW] &= ~(1UL << (sig % _NSIG_BPW)); -} - -static inline int sigismember(sigset_t *set, int _sig) -{ - unsigned long sig = _sig - 1; - if (_NSIG_WORDS == 1) - return 1 & (set->sig[0] >> sig); - else - return 1 & (set->sig[sig / _NSIG_BPW] >> (sig % _NSIG_BPW)); -} - -#endif /* __HAVE_ARCH_SIG_BITOPS */ - -static inline int sigisemptyset(sigset_t *set) -{ - switch (_NSIG_WORDS) { - case 4: - return (set->sig[3] | set->sig[2] | - set->sig[1] | set->sig[0]) == 0; - case 2: - return (set->sig[1] | set->sig[0]) == 0; - case 1: - return set->sig[0] == 0; - default: - BUILD_BUG(); - return 0; - } -} - -#define sigmask(sig) (1UL << ((sig) - 1)) - -#ifndef __HAVE_ARCH_SIG_SETOPS -#include - -#define _SIG_SET_BINOP(name, op) \ -static inline void name(sigset_t *r, const sigset_t *a, const sigset_t *b) \ -{ \ - unsigned long a0, a1, a2, a3, b0, b1, b2, b3; \ - \ - switch (_NSIG_WORDS) { \ - case 4: \ - a3 = a->sig[3]; a2 = a->sig[2]; \ - b3 = b->sig[3]; b2 = b->sig[2]; \ - r->sig[3] = op(a3, b3); \ - r->sig[2] = op(a2, b2); \ - case 2: \ - a1 = a->sig[1]; b1 = b->sig[1]; \ - r->sig[1] = op(a1, b1); \ - case 1: \ - a0 = a->sig[0]; b0 = b->sig[0]; \ - r->sig[0] = op(a0, b0); \ - break; \ - default: \ - BUILD_BUG(); \ - } \ -} - -#define _sig_or(x,y) ((x) | (y)) -_SIG_SET_BINOP(sigorsets, _sig_or) - -#define _sig_and(x,y) ((x) & (y)) -_SIG_SET_BINOP(sigandsets, _sig_and) - -#define _sig_andn(x,y) ((x) & ~(y)) -_SIG_SET_BINOP(sigandnsets, _sig_andn) - -#undef _SIG_SET_BINOP -#undef _sig_or -#undef _sig_and -#undef _sig_andn - -#define _SIG_SET_OP(name, op) \ -static inline void name(sigset_t *set) \ -{ \ - switch (_NSIG_WORDS) { \ - case 4: set->sig[3] = op(set->sig[3]); \ - set->sig[2] = op(set->sig[2]); \ - case 2: set->sig[1] = op(set->sig[1]); \ - case 1: set->sig[0] = op(set->sig[0]); \ - break; \ - default: \ - BUILD_BUG(); \ - } \ -} - -#define _sig_not(x) (~(x)) -_SIG_SET_OP(signotset, _sig_not) - -#undef _SIG_SET_OP -#undef _sig_not - -static inline void sigemptyset(sigset_t *set) -{ - switch (_NSIG_WORDS) { - default: - memset(set, 0, sizeof(sigset_t)); - break; - case 2: set->sig[1] = 0; - case 1: set->sig[0] = 0; - break; - } -} - -static inline void sigfillset(sigset_t *set) -{ - switch (_NSIG_WORDS) { - default: - memset(set, -1, sizeof(sigset_t)); - break; - case 2: set->sig[1] = -1; - case 1: set->sig[0] = -1; - break; - } -} - -/* Some extensions for manipulating the low 32 signals in particular. */ - -static inline void sigaddsetmask(sigset_t *set, unsigned long mask) -{ - set->sig[0] |= mask; -} - -static inline void sigdelsetmask(sigset_t *set, unsigned long mask) -{ - set->sig[0] &= ~mask; -} - -static inline int sigtestsetmask(sigset_t *set, unsigned long mask) -{ - return (set->sig[0] & mask) != 0; -} - -static inline void siginitset(sigset_t *set, unsigned long mask) -{ - set->sig[0] = mask; - switch (_NSIG_WORDS) { - default: - memset(&set->sig[1], 0, sizeof(long)*(_NSIG_WORDS-1)); - break; - case 2: set->sig[1] = 0; - case 1: ; - } -} - -static inline void siginitsetinv(sigset_t *set, unsigned long mask) -{ - set->sig[0] = ~mask; - switch (_NSIG_WORDS) { - default: - memset(&set->sig[1], -1, sizeof(long)*(_NSIG_WORDS-1)); - break; - case 2: set->sig[1] = -1; - case 1: ; - } -} - -#endif /* __HAVE_ARCH_SIG_SETOPS */ - -static inline void init_sigpending(struct sigpending *sig) -{ - sigemptyset(&sig->signal); - INIT_LIST_HEAD(&sig->list); -} - -extern void flush_sigqueue(struct sigpending *queue); - -/* Test if 'sig' is valid signal. Use this instead of testing _NSIG directly */ -static inline int valid_signal(unsigned long sig) -{ - return sig <= _NSIG ? 1 : 0; -} - -struct timespec; -struct pt_regs; - -extern int next_signal(struct sigpending *pending, sigset_t *mask); -extern int do_send_sig_info(int sig, struct siginfo *info, - struct task_struct *p, bool group); -extern int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p); -extern int __group_send_sig_info(int, struct siginfo *, struct task_struct *); -extern int do_sigtimedwait(const sigset_t *, siginfo_t *, - const struct timespec *); -extern int sigprocmask(int, sigset_t *, sigset_t *); -extern void set_current_blocked(sigset_t *); -extern void __set_current_blocked(const sigset_t *); -extern int show_unhandled_signals; - -struct sigaction { -#ifndef __ARCH_HAS_IRIX_SIGACTION - __sighandler_t sa_handler; - unsigned long sa_flags; -#else - unsigned int sa_flags; - __sighandler_t sa_handler; -#endif -#ifdef __ARCH_HAS_SA_RESTORER - __sigrestore_t sa_restorer; -#endif - sigset_t sa_mask; /* mask last for extensibility */ -}; - -struct k_sigaction { - struct sigaction sa; -#ifdef __ARCH_HAS_KA_RESTORER - __sigrestore_t ka_restorer; -#endif -}; - -#ifdef CONFIG_OLD_SIGACTION -struct old_sigaction { - __sighandler_t sa_handler; - old_sigset_t sa_mask; - unsigned long sa_flags; - __sigrestore_t sa_restorer; -}; -#endif - -struct ksignal { - struct k_sigaction ka; - siginfo_t info; - int sig; -}; - -extern int get_signal(struct ksignal *ksig); -extern void signal_setup_done(int failed, struct ksignal *ksig, int stepping); -extern void exit_signals(struct task_struct *tsk); -extern void kernel_sigaction(int, __sighandler_t); - -static inline void allow_signal(int sig) -{ - /* - * Kernel threads handle their own signals. Let the signal code - * know it'll be handled, so that they don't get converted to - * SIGKILL or just silently dropped. - */ - kernel_sigaction(sig, (__force __sighandler_t)2); -} - -static inline void disallow_signal(int sig) -{ - kernel_sigaction(sig, SIG_IGN); -} - -extern struct kmem_cache *sighand_cachep; - -int unhandled_signal(struct task_struct *tsk, int sig); - -/* - * In POSIX a signal is sent either to a specific thread (Linux task) - * or to the process as a whole (Linux thread group). How the signal - * is sent determines whether it's to one thread or the whole group, - * which determines which signal mask(s) are involved in blocking it - * from being delivered until later. When the signal is delivered, - * either it's caught or ignored by a user handler or it has a default - * effect that applies to the whole thread group (POSIX process). - * - * The possible effects an unblocked signal set to SIG_DFL can have are: - * ignore - Nothing Happens - * terminate - kill the process, i.e. all threads in the group, - * similar to exit_group. The group leader (only) reports - * WIFSIGNALED status to its parent. - * coredump - write a core dump file describing all threads using - * the same mm and then kill all those threads - * stop - stop all the threads in the group, i.e. TASK_STOPPED state - * - * SIGKILL and SIGSTOP cannot be caught, blocked, or ignored. - * Other signals when not blocked and set to SIG_DFL behaves as follows. - * The job control signals also have other special effects. - * - * +--------------------+------------------+ - * | POSIX signal | default action | - * +--------------------+------------------+ - * | SIGHUP | terminate | - * | SIGINT | terminate | - * | SIGQUIT | coredump | - * | SIGILL | coredump | - * | SIGTRAP | coredump | - * | SIGABRT/SIGIOT | coredump | - * | SIGBUS | coredump | - * | SIGFPE | coredump | - * | SIGKILL | terminate(+) | - * | SIGUSR1 | terminate | - * | SIGSEGV | coredump | - * | SIGUSR2 | terminate | - * | SIGPIPE | terminate | - * | SIGALRM | terminate | - * | SIGTERM | terminate | - * | SIGCHLD | ignore | - * | SIGCONT | ignore(*) | - * | SIGSTOP | stop(*)(+) | - * | SIGTSTP | stop(*) | - * | SIGTTIN | stop(*) | - * | SIGTTOU | stop(*) | - * | SIGURG | ignore | - * | SIGXCPU | coredump | - * | SIGXFSZ | coredump | - * | SIGVTALRM | terminate | - * | SIGPROF | terminate | - * | SIGPOLL/SIGIO | terminate | - * | SIGSYS/SIGUNUSED | coredump | - * | SIGSTKFLT | terminate | - * | SIGWINCH | ignore | - * | SIGPWR | terminate | - * | SIGRTMIN-SIGRTMAX | terminate | - * +--------------------+------------------+ - * | non-POSIX signal | default action | - * +--------------------+------------------+ - * | SIGEMT | coredump | - * +--------------------+------------------+ - * - * (+) For SIGKILL and SIGSTOP the action is "always", not just "default". - * (*) Special job control effects: - * When SIGCONT is sent, it resumes the process (all threads in the group) - * from TASK_STOPPED state and also clears any pending/queued stop signals - * (any of those marked with "stop(*)"). This happens regardless of blocking, - * catching, or ignoring SIGCONT. When any stop signal is sent, it clears - * any pending/queued SIGCONT signals; this happens regardless of blocking, - * catching, or ignored the stop signal, though (except for SIGSTOP) the - * default action of stopping the process may happen later or never. - */ - -#ifdef SIGEMT -#define SIGEMT_MASK rt_sigmask(SIGEMT) -#else -#define SIGEMT_MASK 0 -#endif - -#if SIGRTMIN > BITS_PER_LONG -#define rt_sigmask(sig) (1ULL << ((sig)-1)) -#else -#define rt_sigmask(sig) sigmask(sig) -#endif - -#define siginmask(sig, mask) \ - ((sig) < SIGRTMIN && (rt_sigmask(sig) & (mask))) - -#define SIG_KERNEL_ONLY_MASK (\ - rt_sigmask(SIGKILL) | rt_sigmask(SIGSTOP)) - -#define SIG_KERNEL_STOP_MASK (\ - rt_sigmask(SIGSTOP) | rt_sigmask(SIGTSTP) | \ - rt_sigmask(SIGTTIN) | rt_sigmask(SIGTTOU) ) - -#define SIG_KERNEL_COREDUMP_MASK (\ - rt_sigmask(SIGQUIT) | rt_sigmask(SIGILL) | \ - rt_sigmask(SIGTRAP) | rt_sigmask(SIGABRT) | \ - rt_sigmask(SIGFPE) | rt_sigmask(SIGSEGV) | \ - rt_sigmask(SIGBUS) | rt_sigmask(SIGSYS) | \ - rt_sigmask(SIGXCPU) | rt_sigmask(SIGXFSZ) | \ - SIGEMT_MASK ) - -#define SIG_KERNEL_IGNORE_MASK (\ - rt_sigmask(SIGCONT) | rt_sigmask(SIGCHLD) | \ - rt_sigmask(SIGWINCH) | rt_sigmask(SIGURG) ) - -#define sig_kernel_only(sig) siginmask(sig, SIG_KERNEL_ONLY_MASK) -#define sig_kernel_coredump(sig) siginmask(sig, SIG_KERNEL_COREDUMP_MASK) -#define sig_kernel_ignore(sig) siginmask(sig, SIG_KERNEL_IGNORE_MASK) -#define sig_kernel_stop(sig) siginmask(sig, SIG_KERNEL_STOP_MASK) - -#define sig_user_defined(t, signr) \ - (((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_DFL) && \ - ((t)->sighand->action[(signr)-1].sa.sa_handler != SIG_IGN)) - -#define sig_fatal(t, signr) \ - (!siginmask(signr, SIG_KERNEL_IGNORE_MASK|SIG_KERNEL_STOP_MASK) && \ - (t)->sighand->action[(signr)-1].sa.sa_handler == SIG_DFL) - -void signals_init(void); - -int restore_altstack(const stack_t __user *); -int __save_altstack(stack_t __user *, unsigned long); - -#define save_altstack_ex(uss, sp) do { \ - stack_t __user *__uss = uss; \ - struct task_struct *t = current; \ - put_user_ex((void __user *)t->sas_ss_sp, &__uss->ss_sp); \ - put_user_ex(t->sas_ss_flags, &__uss->ss_flags); \ - put_user_ex(t->sas_ss_size, &__uss->ss_size); \ - if (t->sas_ss_flags & SS_AUTODISARM) \ - sas_ss_reset(t); \ -} while (0); - -#ifdef CONFIG_PROC_FS -struct seq_file; -extern void render_sigset_t(struct seq_file *, const char *, sigset_t *); -#endif - -#endif /* _LINUX_SIGNAL_H */ diff --git a/src/linux/include/linux/signalfd.h b/src/linux/include/linux/signalfd.h deleted file mode 100644 index eadbe22..0000000 --- a/src/linux/include/linux/signalfd.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * include/linux/signalfd.h - * - * Copyright (C) 2007 Davide Libenzi - * - */ -#ifndef _LINUX_SIGNALFD_H -#define _LINUX_SIGNALFD_H - -#include - - -#ifdef CONFIG_SIGNALFD - -/* - * Deliver the signal to listening signalfd. - */ -static inline void signalfd_notify(struct task_struct *tsk, int sig) -{ - if (unlikely(waitqueue_active(&tsk->sighand->signalfd_wqh))) - wake_up(&tsk->sighand->signalfd_wqh); -} - -extern void signalfd_cleanup(struct sighand_struct *sighand); - -#else /* CONFIG_SIGNALFD */ - -static inline void signalfd_notify(struct task_struct *tsk, int sig) { } - -static inline void signalfd_cleanup(struct sighand_struct *sighand) { } - -#endif /* CONFIG_SIGNALFD */ - -#endif /* _LINUX_SIGNALFD_H */ diff --git a/src/linux/include/linux/sizes.h b/src/linux/include/linux/sizes.h deleted file mode 100644 index ce3e815..0000000 --- a/src/linux/include/linux/sizes.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * include/linux/sizes.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#ifndef __LINUX_SIZES_H__ -#define __LINUX_SIZES_H__ - -#define SZ_1 0x00000001 -#define SZ_2 0x00000002 -#define SZ_4 0x00000004 -#define SZ_8 0x00000008 -#define SZ_16 0x00000010 -#define SZ_32 0x00000020 -#define SZ_64 0x00000040 -#define SZ_128 0x00000080 -#define SZ_256 0x00000100 -#define SZ_512 0x00000200 - -#define SZ_1K 0x00000400 -#define SZ_2K 0x00000800 -#define SZ_4K 0x00001000 -#define SZ_8K 0x00002000 -#define SZ_16K 0x00004000 -#define SZ_32K 0x00008000 -#define SZ_64K 0x00010000 -#define SZ_128K 0x00020000 -#define SZ_256K 0x00040000 -#define SZ_512K 0x00080000 - -#define SZ_1M 0x00100000 -#define SZ_2M 0x00200000 -#define SZ_4M 0x00400000 -#define SZ_8M 0x00800000 -#define SZ_16M 0x01000000 -#define SZ_32M 0x02000000 -#define SZ_64M 0x04000000 -#define SZ_128M 0x08000000 -#define SZ_256M 0x10000000 -#define SZ_512M 0x20000000 - -#define SZ_1G 0x40000000 -#define SZ_2G 0x80000000 - -#endif /* __LINUX_SIZES_H__ */ diff --git a/src/linux/include/linux/skbuff.h b/src/linux/include/linux/skbuff.h deleted file mode 100644 index 32810f2..0000000 --- a/src/linux/include/linux/skbuff.h +++ /dev/null @@ -1,3877 +0,0 @@ -/* - * Definitions for the 'struct sk_buff' memory handlers. - * - * Authors: - * Alan Cox, - * Florian La Roche, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _LINUX_SKBUFF_H -#define _LINUX_SKBUFF_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* The interface for checksum offload between the stack and networking drivers - * is as follows... - * - * A. IP checksum related features - * - * Drivers advertise checksum offload capabilities in the features of a device. - * From the stack's point of view these are capabilities offered by the driver, - * a driver typically only advertises features that it is capable of offloading - * to its device. - * - * The checksum related features are: - * - * NETIF_F_HW_CSUM - The driver (or its device) is able to compute one - * IP (one's complement) checksum for any combination - * of protocols or protocol layering. The checksum is - * computed and set in a packet per the CHECKSUM_PARTIAL - * interface (see below). - * - * NETIF_F_IP_CSUM - Driver (device) is only able to checksum plain - * TCP or UDP packets over IPv4. These are specifically - * unencapsulated packets of the form IPv4|TCP or - * IPv4|UDP where the Protocol field in the IPv4 header - * is TCP or UDP. The IPv4 header may contain IP options - * This feature cannot be set in features for a device - * with NETIF_F_HW_CSUM also set. This feature is being - * DEPRECATED (see below). - * - * NETIF_F_IPV6_CSUM - Driver (device) is only able to checksum plain - * TCP or UDP packets over IPv6. These are specifically - * unencapsulated packets of the form IPv6|TCP or - * IPv4|UDP where the Next Header field in the IPv6 - * header is either TCP or UDP. IPv6 extension headers - * are not supported with this feature. This feature - * cannot be set in features for a device with - * NETIF_F_HW_CSUM also set. This feature is being - * DEPRECATED (see below). - * - * NETIF_F_RXCSUM - Driver (device) performs receive checksum offload. - * This flag is used only used to disable the RX checksum - * feature for a device. The stack will accept receive - * checksum indication in packets received on a device - * regardless of whether NETIF_F_RXCSUM is set. - * - * B. Checksumming of received packets by device. Indication of checksum - * verification is in set skb->ip_summed. Possible values are: - * - * CHECKSUM_NONE: - * - * Device did not checksum this packet e.g. due to lack of capabilities. - * The packet contains full (though not verified) checksum in packet but - * not in skb->csum. Thus, skb->csum is undefined in this case. - * - * CHECKSUM_UNNECESSARY: - * - * The hardware you're dealing with doesn't calculate the full checksum - * (as in CHECKSUM_COMPLETE), but it does parse headers and verify checksums - * for specific protocols. For such packets it will set CHECKSUM_UNNECESSARY - * if their checksums are okay. skb->csum is still undefined in this case - * though. A driver or device must never modify the checksum field in the - * packet even if checksum is verified. - * - * CHECKSUM_UNNECESSARY is applicable to following protocols: - * TCP: IPv6 and IPv4. - * UDP: IPv4 and IPv6. A device may apply CHECKSUM_UNNECESSARY to a - * zero UDP checksum for either IPv4 or IPv6, the networking stack - * may perform further validation in this case. - * GRE: only if the checksum is present in the header. - * SCTP: indicates the CRC in SCTP header has been validated. - * - * skb->csum_level indicates the number of consecutive checksums found in - * the packet minus one that have been verified as CHECKSUM_UNNECESSARY. - * For instance if a device receives an IPv6->UDP->GRE->IPv4->TCP packet - * and a device is able to verify the checksums for UDP (possibly zero), - * GRE (checksum flag is set), and TCP-- skb->csum_level would be set to - * two. If the device were only able to verify the UDP checksum and not - * GRE, either because it doesn't support GRE checksum of because GRE - * checksum is bad, skb->csum_level would be set to zero (TCP checksum is - * not considered in this case). - * - * CHECKSUM_COMPLETE: - * - * This is the most generic way. The device supplied checksum of the _whole_ - * packet as seen by netif_rx() and fills out in skb->csum. Meaning, the - * hardware doesn't need to parse L3/L4 headers to implement this. - * - * Note: Even if device supports only some protocols, but is able to produce - * skb->csum, it MUST use CHECKSUM_COMPLETE, not CHECKSUM_UNNECESSARY. - * - * CHECKSUM_PARTIAL: - * - * A checksum is set up to be offloaded to a device as described in the - * output description for CHECKSUM_PARTIAL. This may occur on a packet - * received directly from another Linux OS, e.g., a virtualized Linux kernel - * on the same host, or it may be set in the input path in GRO or remote - * checksum offload. For the purposes of checksum verification, the checksum - * referred to by skb->csum_start + skb->csum_offset and any preceding - * checksums in the packet are considered verified. Any checksums in the - * packet that are after the checksum being offloaded are not considered to - * be verified. - * - * C. Checksumming on transmit for non-GSO. The stack requests checksum offload - * in the skb->ip_summed for a packet. Values are: - * - * CHECKSUM_PARTIAL: - * - * The driver is required to checksum the packet as seen by hard_start_xmit() - * from skb->csum_start up to the end, and to record/write the checksum at - * offset skb->csum_start + skb->csum_offset. A driver may verify that the - * csum_start and csum_offset values are valid values given the length and - * offset of the packet, however they should not attempt to validate that the - * checksum refers to a legitimate transport layer checksum-- it is the - * purview of the stack to validate that csum_start and csum_offset are set - * correctly. - * - * When the stack requests checksum offload for a packet, the driver MUST - * ensure that the checksum is set correctly. A driver can either offload the - * checksum calculation to the device, or call skb_checksum_help (in the case - * that the device does not support offload for a particular checksum). - * - * NETIF_F_IP_CSUM and NETIF_F_IPV6_CSUM are being deprecated in favor of - * NETIF_F_HW_CSUM. New devices should use NETIF_F_HW_CSUM to indicate - * checksum offload capability. If a device has limited checksum capabilities - * (for instance can only perform NETIF_F_IP_CSUM or NETIF_F_IPV6_CSUM as - * described above) a helper function can be called to resolve - * CHECKSUM_PARTIAL. The helper functions are skb_csum_off_chk*. The helper - * function takes a spec argument that describes the protocol layer that is - * supported for checksum offload and can be called for each packet. If a - * packet does not match the specification for offload, skb_checksum_help - * is called to resolve the checksum. - * - * CHECKSUM_NONE: - * - * The skb was already checksummed by the protocol, or a checksum is not - * required. - * - * CHECKSUM_UNNECESSARY: - * - * This has the same meaning on as CHECKSUM_NONE for checksum offload on - * output. - * - * CHECKSUM_COMPLETE: - * Not used in checksum output. If a driver observes a packet with this value - * set in skbuff, if should treat as CHECKSUM_NONE being set. - * - * D. Non-IP checksum (CRC) offloads - * - * NETIF_F_SCTP_CRC - This feature indicates that a device is capable of - * offloading the SCTP CRC in a packet. To perform this offload the stack - * will set ip_summed to CHECKSUM_PARTIAL and set csum_start and csum_offset - * accordingly. Note the there is no indication in the skbuff that the - * CHECKSUM_PARTIAL refers to an SCTP checksum, a driver that supports - * both IP checksum offload and SCTP CRC offload must verify which offload - * is configured for a packet presumably by inspecting packet headers. - * - * NETIF_F_FCOE_CRC - This feature indicates that a device is capable of - * offloading the FCOE CRC in a packet. To perform this offload the stack - * will set ip_summed to CHECKSUM_PARTIAL and set csum_start and csum_offset - * accordingly. Note the there is no indication in the skbuff that the - * CHECKSUM_PARTIAL refers to an FCOE checksum, a driver that supports - * both IP checksum offload and FCOE CRC offload must verify which offload - * is configured for a packet presumably by inspecting packet headers. - * - * E. Checksumming on output with GSO. - * - * In the case of a GSO packet (skb_is_gso(skb) is true), checksum offload - * is implied by the SKB_GSO_* flags in gso_type. Most obviously, if the - * gso_type is SKB_GSO_TCPV4 or SKB_GSO_TCPV6, TCP checksum offload as - * part of the GSO operation is implied. If a checksum is being offloaded - * with GSO then ip_summed is CHECKSUM_PARTIAL, csum_start and csum_offset - * are set to refer to the outermost checksum being offload (two offloaded - * checksums are possible with UDP encapsulation). - */ - -/* Don't change this without changing skb_csum_unnecessary! */ -#define CHECKSUM_NONE 0 -#define CHECKSUM_UNNECESSARY 1 -#define CHECKSUM_COMPLETE 2 -#define CHECKSUM_PARTIAL 3 - -/* Maximum value in skb->csum_level */ -#define SKB_MAX_CSUM_LEVEL 3 - -#define SKB_DATA_ALIGN(X) ALIGN(X, SMP_CACHE_BYTES) -#define SKB_WITH_OVERHEAD(X) \ - ((X) - SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) -#define SKB_MAX_ORDER(X, ORDER) \ - SKB_WITH_OVERHEAD((PAGE_SIZE << (ORDER)) - (X)) -#define SKB_MAX_HEAD(X) (SKB_MAX_ORDER((X), 0)) -#define SKB_MAX_ALLOC (SKB_MAX_ORDER(0, 2)) - -/* return minimum truesize of one skb containing X bytes of data */ -#define SKB_TRUESIZE(X) ((X) + \ - SKB_DATA_ALIGN(sizeof(struct sk_buff)) + \ - SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) - -struct net_device; -struct scatterlist; -struct pipe_inode_info; -struct iov_iter; -struct napi_struct; - -#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) -struct nf_conntrack { - atomic_t use; -}; -#endif - -#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) -struct nf_bridge_info { - atomic_t use; - enum { - BRNF_PROTO_UNCHANGED, - BRNF_PROTO_8021Q, - BRNF_PROTO_PPPOE - } orig_proto:8; - u8 pkt_otherhost:1; - u8 in_prerouting:1; - u8 bridged_dnat:1; - __u16 frag_max_size; - struct net_device *physindev; - - /* always valid & non-NULL from FORWARD on, for physdev match */ - struct net_device *physoutdev; - union { - /* prerouting: detect dnat in orig/reply direction */ - __be32 ipv4_daddr; - struct in6_addr ipv6_daddr; - - /* after prerouting + nat detected: store original source - * mac since neigh resolution overwrites it, only used while - * skb is out in neigh layer. - */ - char neigh_header[8]; - }; -}; -#endif - -struct sk_buff_head { - /* These two members must be first. */ - struct sk_buff *next; - struct sk_buff *prev; - - __u32 qlen; - spinlock_t lock; -}; - -struct sk_buff; - -/* To allow 64K frame to be packed as single skb without frag_list we - * require 64K/PAGE_SIZE pages plus 1 additional page to allow for - * buffers which do not start on a page boundary. - * - * Since GRO uses frags we allocate at least 16 regardless of page - * size. - */ -#if (65536/PAGE_SIZE + 1) < 16 -#define MAX_SKB_FRAGS 16UL -#else -#define MAX_SKB_FRAGS (65536/PAGE_SIZE + 1) -#endif -extern int sysctl_max_skb_frags; - -/* Set skb_shinfo(skb)->gso_size to this in case you want skb_segment to - * segment using its current segmentation instead. - */ -#define GSO_BY_FRAGS 0xFFFF - -typedef struct skb_frag_struct skb_frag_t; - -struct skb_frag_struct { - struct { - struct page *p; - } page; -#if (BITS_PER_LONG > 32) || (PAGE_SIZE >= 65536) - __u32 page_offset; - __u32 size; -#else - __u16 page_offset; - __u16 size; -#endif -}; - -static inline unsigned int skb_frag_size(const skb_frag_t *frag) -{ - return frag->size; -} - -static inline void skb_frag_size_set(skb_frag_t *frag, unsigned int size) -{ - frag->size = size; -} - -static inline void skb_frag_size_add(skb_frag_t *frag, int delta) -{ - frag->size += delta; -} - -static inline void skb_frag_size_sub(skb_frag_t *frag, int delta) -{ - frag->size -= delta; -} - -#define HAVE_HW_TIME_STAMP - -/** - * struct skb_shared_hwtstamps - hardware time stamps - * @hwtstamp: hardware time stamp transformed into duration - * since arbitrary point in time - * - * Software time stamps generated by ktime_get_real() are stored in - * skb->tstamp. - * - * hwtstamps can only be compared against other hwtstamps from - * the same device. - * - * This structure is attached to packets as part of the - * &skb_shared_info. Use skb_hwtstamps() to get a pointer. - */ -struct skb_shared_hwtstamps { - ktime_t hwtstamp; -}; - -/* Definitions for tx_flags in struct skb_shared_info */ -enum { - /* generate hardware time stamp */ - SKBTX_HW_TSTAMP = 1 << 0, - - /* generate software time stamp when queueing packet to NIC */ - SKBTX_SW_TSTAMP = 1 << 1, - - /* device driver is going to provide hardware time stamp */ - SKBTX_IN_PROGRESS = 1 << 2, - - /* device driver supports TX zero-copy buffers */ - SKBTX_DEV_ZEROCOPY = 1 << 3, - - /* generate wifi status information (where possible) */ - SKBTX_WIFI_STATUS = 1 << 4, - - /* This indicates at least one fragment might be overwritten - * (as in vmsplice(), sendfile() ...) - * If we need to compute a TX checksum, we'll need to copy - * all frags to avoid possible bad checksum - */ - SKBTX_SHARED_FRAG = 1 << 5, - - /* generate software time stamp when entering packet scheduling */ - SKBTX_SCHED_TSTAMP = 1 << 6, -}; - -#define SKBTX_ANY_SW_TSTAMP (SKBTX_SW_TSTAMP | \ - SKBTX_SCHED_TSTAMP) -#define SKBTX_ANY_TSTAMP (SKBTX_HW_TSTAMP | SKBTX_ANY_SW_TSTAMP) - -/* - * The callback notifies userspace to release buffers when skb DMA is done in - * lower device, the skb last reference should be 0 when calling this. - * The zerocopy_success argument is true if zero copy transmit occurred, - * false on data copy or out of memory error caused by data copy attempt. - * The ctx field is used to track device context. - * The desc field is used to track userspace buffer index. - */ -struct ubuf_info { - void (*callback)(struct ubuf_info *, bool zerocopy_success); - void *ctx; - unsigned long desc; -}; - -/* This data is invariant across clones and lives at - * the end of the header data, ie. at skb->end. - */ -struct skb_shared_info { - unsigned char nr_frags; - __u8 tx_flags; - unsigned short gso_size; - /* Warning: this field is not always filled in (UFO)! */ - unsigned short gso_segs; - unsigned short gso_type; - struct sk_buff *frag_list; - struct skb_shared_hwtstamps hwtstamps; - u32 tskey; - __be32 ip6_frag_id; - - /* - * Warning : all fields before dataref are cleared in __alloc_skb() - */ - atomic_t dataref; - - /* Intermediate layers must ensure that destructor_arg - * remains valid until skb destructor */ - void * destructor_arg; - - /* must be last field, see pskb_expand_head() */ - skb_frag_t frags[MAX_SKB_FRAGS]; -}; - -/* We divide dataref into two halves. The higher 16 bits hold references - * to the payload part of skb->data. The lower 16 bits hold references to - * the entire skb->data. A clone of a headerless skb holds the length of - * the header in skb->hdr_len. - * - * All users must obey the rule that the skb->data reference count must be - * greater than or equal to the payload reference count. - * - * Holding a reference to the payload part means that the user does not - * care about modifications to the header part of skb->data. - */ -#define SKB_DATAREF_SHIFT 16 -#define SKB_DATAREF_MASK ((1 << SKB_DATAREF_SHIFT) - 1) - - -enum { - SKB_FCLONE_UNAVAILABLE, /* skb has no fclone (from head_cache) */ - SKB_FCLONE_ORIG, /* orig skb (from fclone_cache) */ - SKB_FCLONE_CLONE, /* companion fclone skb (from fclone_cache) */ -}; - -enum { - SKB_GSO_TCPV4 = 1 << 0, - SKB_GSO_UDP = 1 << 1, - - /* This indicates the skb is from an untrusted source. */ - SKB_GSO_DODGY = 1 << 2, - - /* This indicates the tcp segment has CWR set. */ - SKB_GSO_TCP_ECN = 1 << 3, - - SKB_GSO_TCP_FIXEDID = 1 << 4, - - SKB_GSO_TCPV6 = 1 << 5, - - SKB_GSO_FCOE = 1 << 6, - - SKB_GSO_GRE = 1 << 7, - - SKB_GSO_GRE_CSUM = 1 << 8, - - SKB_GSO_IPXIP4 = 1 << 9, - - SKB_GSO_IPXIP6 = 1 << 10, - - SKB_GSO_UDP_TUNNEL = 1 << 11, - - SKB_GSO_UDP_TUNNEL_CSUM = 1 << 12, - - SKB_GSO_PARTIAL = 1 << 13, - - SKB_GSO_TUNNEL_REMCSUM = 1 << 14, - - SKB_GSO_SCTP = 1 << 15, -}; - -#if BITS_PER_LONG > 32 -#define NET_SKBUFF_DATA_USES_OFFSET 1 -#endif - -#ifdef NET_SKBUFF_DATA_USES_OFFSET -typedef unsigned int sk_buff_data_t; -#else -typedef unsigned char *sk_buff_data_t; -#endif - -/** - * struct skb_mstamp - multi resolution time stamps - * @stamp_us: timestamp in us resolution - * @stamp_jiffies: timestamp in jiffies - */ -struct skb_mstamp { - union { - u64 v64; - struct { - u32 stamp_us; - u32 stamp_jiffies; - }; - }; -}; - -/** - * skb_mstamp_get - get current timestamp - * @cl: place to store timestamps - */ -static inline void skb_mstamp_get(struct skb_mstamp *cl) -{ - u64 val = local_clock(); - - do_div(val, NSEC_PER_USEC); - cl->stamp_us = (u32)val; - cl->stamp_jiffies = (u32)jiffies; -} - -/** - * skb_mstamp_delta - compute the difference in usec between two skb_mstamp - * @t1: pointer to newest sample - * @t0: pointer to oldest sample - */ -static inline u32 skb_mstamp_us_delta(const struct skb_mstamp *t1, - const struct skb_mstamp *t0) -{ - s32 delta_us = t1->stamp_us - t0->stamp_us; - u32 delta_jiffies = t1->stamp_jiffies - t0->stamp_jiffies; - - /* If delta_us is negative, this might be because interval is too big, - * or local_clock() drift is too big : fallback using jiffies. - */ - if (delta_us <= 0 || - delta_jiffies >= (INT_MAX / (USEC_PER_SEC / HZ))) - - delta_us = jiffies_to_usecs(delta_jiffies); - - return delta_us; -} - -static inline bool skb_mstamp_after(const struct skb_mstamp *t1, - const struct skb_mstamp *t0) -{ - s32 diff = t1->stamp_jiffies - t0->stamp_jiffies; - - if (!diff) - diff = t1->stamp_us - t0->stamp_us; - return diff > 0; -} - -/** - * struct sk_buff - socket buffer - * @next: Next buffer in list - * @prev: Previous buffer in list - * @tstamp: Time we arrived/left - * @rbnode: RB tree node, alternative to next/prev for netem/tcp - * @sk: Socket we are owned by - * @dev: Device we arrived on/are leaving by - * @cb: Control buffer. Free for use by every layer. Put private vars here - * @_skb_refdst: destination entry (with norefcount bit) - * @sp: the security path, used for xfrm - * @len: Length of actual data - * @data_len: Data length - * @mac_len: Length of link layer header - * @hdr_len: writable header length of cloned skb - * @csum: Checksum (must include start/offset pair) - * @csum_start: Offset from skb->head where checksumming should start - * @csum_offset: Offset from csum_start where checksum should be stored - * @priority: Packet queueing priority - * @ignore_df: allow local fragmentation - * @cloned: Head may be cloned (check refcnt to be sure) - * @ip_summed: Driver fed us an IP checksum - * @nohdr: Payload reference only, must not modify header - * @nfctinfo: Relationship of this skb to the connection - * @pkt_type: Packet class - * @fclone: skbuff clone status - * @ipvs_property: skbuff is owned by ipvs - * @peeked: this packet has been seen already, so stats have been - * done for it, don't do them again - * @nf_trace: netfilter packet trace flag - * @protocol: Packet protocol from driver - * @destructor: Destruct function - * @nfct: Associated connection, if any - * @nf_bridge: Saved data about a bridged frame - see br_netfilter.c - * @skb_iif: ifindex of device we arrived on - * @tc_index: Traffic control index - * @tc_verd: traffic control verdict - * @hash: the packet hash - * @queue_mapping: Queue mapping for multiqueue devices - * @xmit_more: More SKBs are pending for this queue - * @ndisc_nodetype: router type (from link layer) - * @ooo_okay: allow the mapping of a socket to a queue to be changed - * @l4_hash: indicate hash is a canonical 4-tuple hash over transport - * ports. - * @sw_hash: indicates hash was computed in software stack - * @wifi_acked_valid: wifi_acked was set - * @wifi_acked: whether frame was acked on wifi or not - * @no_fcs: Request NIC to treat last 4 bytes as Ethernet FCS - * @napi_id: id of the NAPI struct this skb came from - * @secmark: security marking - * @mark: Generic packet mark - * @vlan_proto: vlan encapsulation protocol - * @vlan_tci: vlan tag control information - * @inner_protocol: Protocol (encapsulation) - * @inner_transport_header: Inner transport layer header (encapsulation) - * @inner_network_header: Network layer header (encapsulation) - * @inner_mac_header: Link layer header (encapsulation) - * @transport_header: Transport layer header - * @network_header: Network layer header - * @mac_header: Link layer header - * @tail: Tail pointer - * @end: End pointer - * @head: Head of buffer - * @data: Data head pointer - * @truesize: Buffer size - * @users: User count - see {datagram,tcp}.c - */ - -struct sk_buff { - union { - struct { - /* These two members must be first. */ - struct sk_buff *next; - struct sk_buff *prev; - - union { - ktime_t tstamp; - struct skb_mstamp skb_mstamp; - }; - }; - struct rb_node rbnode; /* used in netem & tcp stack */ - }; - struct sock *sk; - struct net_device *dev; - - /* - * This is the control buffer. It is free to use for every - * layer. Please put your private variables there. If you - * want to keep them across layers you have to do a skb_clone() - * first. This is owned by whoever has the skb queued ATM. - */ - char cb[48] __aligned(8); - - unsigned long _skb_refdst; - void (*destructor)(struct sk_buff *skb); -#ifdef CONFIG_XFRM - struct sec_path *sp; -#endif -#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) - struct nf_conntrack *nfct; -#endif -#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) - struct nf_bridge_info *nf_bridge; -#endif - unsigned int len, - data_len; - __u16 mac_len, - hdr_len; - - /* Following fields are _not_ copied in __copy_skb_header() - * Note that queue_mapping is here mostly to fill a hole. - */ - kmemcheck_bitfield_begin(flags1); - __u16 queue_mapping; - -/* if you move cloned around you also must adapt those constants */ -#ifdef __BIG_ENDIAN_BITFIELD -#define CLONED_MASK (1 << 7) -#else -#define CLONED_MASK 1 -#endif -#define CLONED_OFFSET() offsetof(struct sk_buff, __cloned_offset) - - __u8 __cloned_offset[0]; - __u8 cloned:1, - nohdr:1, - fclone:2, - peeked:1, - head_frag:1, - xmit_more:1, - __unused:1; /* one bit hole */ - kmemcheck_bitfield_end(flags1); - - /* fields enclosed in headers_start/headers_end are copied - * using a single memcpy() in __copy_skb_header() - */ - /* private: */ - __u32 headers_start[0]; - /* public: */ - -/* if you move pkt_type around you also must adapt those constants */ -#ifdef __BIG_ENDIAN_BITFIELD -#define PKT_TYPE_MAX (7 << 5) -#else -#define PKT_TYPE_MAX 7 -#endif -#define PKT_TYPE_OFFSET() offsetof(struct sk_buff, __pkt_type_offset) - - __u8 __pkt_type_offset[0]; - __u8 pkt_type:3; - __u8 pfmemalloc:1; - __u8 ignore_df:1; - __u8 nfctinfo:3; - - __u8 nf_trace:1; - __u8 ip_summed:2; - __u8 ooo_okay:1; - __u8 l4_hash:1; - __u8 sw_hash:1; - __u8 wifi_acked_valid:1; - __u8 wifi_acked:1; - - __u8 no_fcs:1; - /* Indicates the inner headers are valid in the skbuff. */ - __u8 encapsulation:1; - __u8 encap_hdr_csum:1; - __u8 csum_valid:1; - __u8 csum_complete_sw:1; - __u8 csum_level:2; - __u8 csum_bad:1; - -#ifdef CONFIG_IPV6_NDISC_NODETYPE - __u8 ndisc_nodetype:2; -#endif - __u8 ipvs_property:1; - __u8 inner_protocol_type:1; - __u8 remcsum_offload:1; -#ifdef CONFIG_NET_SWITCHDEV - __u8 offload_fwd_mark:1; -#endif - /* 2, 4 or 5 bit hole */ - -#ifdef CONFIG_NET_SCHED - __u16 tc_index; /* traffic control index */ -#ifdef CONFIG_NET_CLS_ACT - __u16 tc_verd; /* traffic control verdict */ -#endif -#endif - - union { - __wsum csum; - struct { - __u16 csum_start; - __u16 csum_offset; - }; - }; - __u32 priority; - int skb_iif; - __u32 hash; - __be16 vlan_proto; - __u16 vlan_tci; -#if defined(CONFIG_NET_RX_BUSY_POLL) || defined(CONFIG_XPS) - union { - unsigned int napi_id; - unsigned int sender_cpu; - }; -#endif -#ifdef CONFIG_NETWORK_SECMARK - __u32 secmark; -#endif - - union { - __u32 mark; - __u32 reserved_tailroom; - }; - - union { - __be16 inner_protocol; - __u8 inner_ipproto; - }; - - __u16 inner_transport_header; - __u16 inner_network_header; - __u16 inner_mac_header; - - __be16 protocol; - __u16 transport_header; - __u16 network_header; - __u16 mac_header; - - /* private: */ - __u32 headers_end[0]; - /* public: */ - - /* These elements must be at the end, see alloc_skb() for details. */ - sk_buff_data_t tail; - sk_buff_data_t end; - unsigned char *head, - *data; - unsigned int truesize; - atomic_t users; -}; - -#ifdef __KERNEL__ -/* - * Handling routines are only of interest to the kernel - */ -#include - - -#define SKB_ALLOC_FCLONE 0x01 -#define SKB_ALLOC_RX 0x02 -#define SKB_ALLOC_NAPI 0x04 - -/* Returns true if the skb was allocated from PFMEMALLOC reserves */ -static inline bool skb_pfmemalloc(const struct sk_buff *skb) -{ - return unlikely(skb->pfmemalloc); -} - -/* - * skb might have a dst pointer attached, refcounted or not. - * _skb_refdst low order bit is set if refcount was _not_ taken - */ -#define SKB_DST_NOREF 1UL -#define SKB_DST_PTRMASK ~(SKB_DST_NOREF) - -/** - * skb_dst - returns skb dst_entry - * @skb: buffer - * - * Returns skb dst_entry, regardless of reference taken or not. - */ -static inline struct dst_entry *skb_dst(const struct sk_buff *skb) -{ - /* If refdst was not refcounted, check we still are in a - * rcu_read_lock section - */ - WARN_ON((skb->_skb_refdst & SKB_DST_NOREF) && - !rcu_read_lock_held() && - !rcu_read_lock_bh_held()); - return (struct dst_entry *)(skb->_skb_refdst & SKB_DST_PTRMASK); -} - -/** - * skb_dst_set - sets skb dst - * @skb: buffer - * @dst: dst entry - * - * Sets skb dst, assuming a reference was taken on dst and should - * be released by skb_dst_drop() - */ -static inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst) -{ - skb->_skb_refdst = (unsigned long)dst; -} - -/** - * skb_dst_set_noref - sets skb dst, hopefully, without taking reference - * @skb: buffer - * @dst: dst entry - * - * Sets skb dst, assuming a reference was not taken on dst. - * If dst entry is cached, we do not take reference and dst_release - * will be avoided by refdst_drop. If dst entry is not cached, we take - * reference, so that last dst_release can destroy the dst immediately. - */ -static inline void skb_dst_set_noref(struct sk_buff *skb, struct dst_entry *dst) -{ - WARN_ON(!rcu_read_lock_held() && !rcu_read_lock_bh_held()); - skb->_skb_refdst = (unsigned long)dst | SKB_DST_NOREF; -} - -/** - * skb_dst_is_noref - Test if skb dst isn't refcounted - * @skb: buffer - */ -static inline bool skb_dst_is_noref(const struct sk_buff *skb) -{ - return (skb->_skb_refdst & SKB_DST_NOREF) && skb_dst(skb); -} - -static inline struct rtable *skb_rtable(const struct sk_buff *skb) -{ - return (struct rtable *)skb_dst(skb); -} - -/* For mangling skb->pkt_type from user space side from applications - * such as nft, tc, etc, we only allow a conservative subset of - * possible pkt_types to be set. -*/ -static inline bool skb_pkt_type_ok(u32 ptype) -{ - return ptype <= PACKET_OTHERHOST; -} - -void kfree_skb(struct sk_buff *skb); -void kfree_skb_list(struct sk_buff *segs); -void skb_tx_error(struct sk_buff *skb); -void consume_skb(struct sk_buff *skb); -void __kfree_skb(struct sk_buff *skb); -extern struct kmem_cache *skbuff_head_cache; - -void kfree_skb_partial(struct sk_buff *skb, bool head_stolen); -bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from, - bool *fragstolen, int *delta_truesize); - -struct sk_buff *__alloc_skb(unsigned int size, gfp_t priority, int flags, - int node); -struct sk_buff *__build_skb(void *data, unsigned int frag_size); -struct sk_buff *build_skb(void *data, unsigned int frag_size); -static inline struct sk_buff *alloc_skb(unsigned int size, - gfp_t priority) -{ - return __alloc_skb(size, priority, 0, NUMA_NO_NODE); -} - -struct sk_buff *alloc_skb_with_frags(unsigned long header_len, - unsigned long data_len, - int max_page_order, - int *errcode, - gfp_t gfp_mask); - -/* Layout of fast clones : [skb1][skb2][fclone_ref] */ -struct sk_buff_fclones { - struct sk_buff skb1; - - struct sk_buff skb2; - - atomic_t fclone_ref; -}; - -/** - * skb_fclone_busy - check if fclone is busy - * @sk: socket - * @skb: buffer - * - * Returns true if skb is a fast clone, and its clone is not freed. - * Some drivers call skb_orphan() in their ndo_start_xmit(), - * so we also check that this didnt happen. - */ -static inline bool skb_fclone_busy(const struct sock *sk, - const struct sk_buff *skb) -{ - const struct sk_buff_fclones *fclones; - - fclones = container_of(skb, struct sk_buff_fclones, skb1); - - return skb->fclone == SKB_FCLONE_ORIG && - atomic_read(&fclones->fclone_ref) > 1 && - fclones->skb2.sk == sk; -} - -static inline struct sk_buff *alloc_skb_fclone(unsigned int size, - gfp_t priority) -{ - return __alloc_skb(size, priority, SKB_ALLOC_FCLONE, NUMA_NO_NODE); -} - -struct sk_buff *__alloc_skb_head(gfp_t priority, int node); -static inline struct sk_buff *alloc_skb_head(gfp_t priority) -{ - return __alloc_skb_head(priority, -1); -} - -struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src); -int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask); -struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t priority); -struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t priority); -struct sk_buff *__pskb_copy_fclone(struct sk_buff *skb, int headroom, - gfp_t gfp_mask, bool fclone); -static inline struct sk_buff *__pskb_copy(struct sk_buff *skb, int headroom, - gfp_t gfp_mask) -{ - return __pskb_copy_fclone(skb, headroom, gfp_mask, false); -} - -int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, gfp_t gfp_mask); -struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, - unsigned int headroom); -struct sk_buff *skb_copy_expand(const struct sk_buff *skb, int newheadroom, - int newtailroom, gfp_t priority); -int skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg, - int offset, int len); -int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, - int len); -int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer); -int skb_pad(struct sk_buff *skb, int pad); -#define dev_kfree_skb(a) consume_skb(a) - -int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, - int getfrag(void *from, char *to, int offset, - int len, int odd, struct sk_buff *skb), - void *from, int length); - -int skb_append_pagefrags(struct sk_buff *skb, struct page *page, - int offset, size_t size); - -struct skb_seq_state { - __u32 lower_offset; - __u32 upper_offset; - __u32 frag_idx; - __u32 stepped_offset; - struct sk_buff *root_skb; - struct sk_buff *cur_skb; - __u8 *frag_data; -}; - -void skb_prepare_seq_read(struct sk_buff *skb, unsigned int from, - unsigned int to, struct skb_seq_state *st); -unsigned int skb_seq_read(unsigned int consumed, const u8 **data, - struct skb_seq_state *st); -void skb_abort_seq_read(struct skb_seq_state *st); - -unsigned int skb_find_text(struct sk_buff *skb, unsigned int from, - unsigned int to, struct ts_config *config); - -/* - * Packet hash types specify the type of hash in skb_set_hash. - * - * Hash types refer to the protocol layer addresses which are used to - * construct a packet's hash. The hashes are used to differentiate or identify - * flows of the protocol layer for the hash type. Hash types are either - * layer-2 (L2), layer-3 (L3), or layer-4 (L4). - * - * Properties of hashes: - * - * 1) Two packets in different flows have different hash values - * 2) Two packets in the same flow should have the same hash value - * - * A hash at a higher layer is considered to be more specific. A driver should - * set the most specific hash possible. - * - * A driver cannot indicate a more specific hash than the layer at which a hash - * was computed. For instance an L3 hash cannot be set as an L4 hash. - * - * A driver may indicate a hash level which is less specific than the - * actual layer the hash was computed on. For instance, a hash computed - * at L4 may be considered an L3 hash. This should only be done if the - * driver can't unambiguously determine that the HW computed the hash at - * the higher layer. Note that the "should" in the second property above - * permits this. - */ -enum pkt_hash_types { - PKT_HASH_TYPE_NONE, /* Undefined type */ - PKT_HASH_TYPE_L2, /* Input: src_MAC, dest_MAC */ - PKT_HASH_TYPE_L3, /* Input: src_IP, dst_IP */ - PKT_HASH_TYPE_L4, /* Input: src_IP, dst_IP, src_port, dst_port */ -}; - -static inline void skb_clear_hash(struct sk_buff *skb) -{ - skb->hash = 0; - skb->sw_hash = 0; - skb->l4_hash = 0; -} - -static inline void skb_clear_hash_if_not_l4(struct sk_buff *skb) -{ - if (!skb->l4_hash) - skb_clear_hash(skb); -} - -static inline void -__skb_set_hash(struct sk_buff *skb, __u32 hash, bool is_sw, bool is_l4) -{ - skb->l4_hash = is_l4; - skb->sw_hash = is_sw; - skb->hash = hash; -} - -static inline void -skb_set_hash(struct sk_buff *skb, __u32 hash, enum pkt_hash_types type) -{ - /* Used by drivers to set hash from HW */ - __skb_set_hash(skb, hash, false, type == PKT_HASH_TYPE_L4); -} - -static inline void -__skb_set_sw_hash(struct sk_buff *skb, __u32 hash, bool is_l4) -{ - __skb_set_hash(skb, hash, true, is_l4); -} - -void __skb_get_hash(struct sk_buff *skb); -u32 __skb_get_hash_symmetric(struct sk_buff *skb); -u32 skb_get_poff(const struct sk_buff *skb); -u32 __skb_get_poff(const struct sk_buff *skb, void *data, - const struct flow_keys *keys, int hlen); -__be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto, - void *data, int hlen_proto); - -static inline __be32 skb_flow_get_ports(const struct sk_buff *skb, - int thoff, u8 ip_proto) -{ - return __skb_flow_get_ports(skb, thoff, ip_proto, NULL, 0); -} - -void skb_flow_dissector_init(struct flow_dissector *flow_dissector, - const struct flow_dissector_key *key, - unsigned int key_count); - -bool __skb_flow_dissect(const struct sk_buff *skb, - struct flow_dissector *flow_dissector, - void *target_container, - void *data, __be16 proto, int nhoff, int hlen, - unsigned int flags); - -static inline bool skb_flow_dissect(const struct sk_buff *skb, - struct flow_dissector *flow_dissector, - void *target_container, unsigned int flags) -{ - return __skb_flow_dissect(skb, flow_dissector, target_container, - NULL, 0, 0, 0, flags); -} - -static inline bool skb_flow_dissect_flow_keys(const struct sk_buff *skb, - struct flow_keys *flow, - unsigned int flags) -{ - memset(flow, 0, sizeof(*flow)); - return __skb_flow_dissect(skb, &flow_keys_dissector, flow, - NULL, 0, 0, 0, flags); -} - -static inline bool skb_flow_dissect_flow_keys_buf(struct flow_keys *flow, - void *data, __be16 proto, - int nhoff, int hlen, - unsigned int flags) -{ - memset(flow, 0, sizeof(*flow)); - return __skb_flow_dissect(NULL, &flow_keys_buf_dissector, flow, - data, proto, nhoff, hlen, flags); -} - -static inline __u32 skb_get_hash(struct sk_buff *skb) -{ - if (!skb->l4_hash && !skb->sw_hash) - __skb_get_hash(skb); - - return skb->hash; -} - -__u32 __skb_get_hash_flowi6(struct sk_buff *skb, const struct flowi6 *fl6); - -static inline __u32 skb_get_hash_flowi6(struct sk_buff *skb, const struct flowi6 *fl6) -{ - if (!skb->l4_hash && !skb->sw_hash) { - struct flow_keys keys; - __u32 hash = __get_hash_from_flowi6(fl6, &keys); - - __skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys)); - } - - return skb->hash; -} - -__u32 __skb_get_hash_flowi4(struct sk_buff *skb, const struct flowi4 *fl); - -static inline __u32 skb_get_hash_flowi4(struct sk_buff *skb, const struct flowi4 *fl4) -{ - if (!skb->l4_hash && !skb->sw_hash) { - struct flow_keys keys; - __u32 hash = __get_hash_from_flowi4(fl4, &keys); - - __skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys)); - } - - return skb->hash; -} - -__u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb); - -static inline __u32 skb_get_hash_raw(const struct sk_buff *skb) -{ - return skb->hash; -} - -static inline void skb_copy_hash(struct sk_buff *to, const struct sk_buff *from) -{ - to->hash = from->hash; - to->sw_hash = from->sw_hash; - to->l4_hash = from->l4_hash; -}; - -#ifdef NET_SKBUFF_DATA_USES_OFFSET -static inline unsigned char *skb_end_pointer(const struct sk_buff *skb) -{ - return skb->head + skb->end; -} - -static inline unsigned int skb_end_offset(const struct sk_buff *skb) -{ - return skb->end; -} -#else -static inline unsigned char *skb_end_pointer(const struct sk_buff *skb) -{ - return skb->end; -} - -static inline unsigned int skb_end_offset(const struct sk_buff *skb) -{ - return skb->end - skb->head; -} -#endif - -/* Internal */ -#define skb_shinfo(SKB) ((struct skb_shared_info *)(skb_end_pointer(SKB))) - -static inline struct skb_shared_hwtstamps *skb_hwtstamps(struct sk_buff *skb) -{ - return &skb_shinfo(skb)->hwtstamps; -} - -/** - * skb_queue_empty - check if a queue is empty - * @list: queue head - * - * Returns true if the queue is empty, false otherwise. - */ -static inline int skb_queue_empty(const struct sk_buff_head *list) -{ - return list->next == (const struct sk_buff *) list; -} - -/** - * skb_queue_is_last - check if skb is the last entry in the queue - * @list: queue head - * @skb: buffer - * - * Returns true if @skb is the last buffer on the list. - */ -static inline bool skb_queue_is_last(const struct sk_buff_head *list, - const struct sk_buff *skb) -{ - return skb->next == (const struct sk_buff *) list; -} - -/** - * skb_queue_is_first - check if skb is the first entry in the queue - * @list: queue head - * @skb: buffer - * - * Returns true if @skb is the first buffer on the list. - */ -static inline bool skb_queue_is_first(const struct sk_buff_head *list, - const struct sk_buff *skb) -{ - return skb->prev == (const struct sk_buff *) list; -} - -/** - * skb_queue_next - return the next packet in the queue - * @list: queue head - * @skb: current buffer - * - * Return the next packet in @list after @skb. It is only valid to - * call this if skb_queue_is_last() evaluates to false. - */ -static inline struct sk_buff *skb_queue_next(const struct sk_buff_head *list, - const struct sk_buff *skb) -{ - /* This BUG_ON may seem severe, but if we just return then we - * are going to dereference garbage. - */ - BUG_ON(skb_queue_is_last(list, skb)); - return skb->next; -} - -/** - * skb_queue_prev - return the prev packet in the queue - * @list: queue head - * @skb: current buffer - * - * Return the prev packet in @list before @skb. It is only valid to - * call this if skb_queue_is_first() evaluates to false. - */ -static inline struct sk_buff *skb_queue_prev(const struct sk_buff_head *list, - const struct sk_buff *skb) -{ - /* This BUG_ON may seem severe, but if we just return then we - * are going to dereference garbage. - */ - BUG_ON(skb_queue_is_first(list, skb)); - return skb->prev; -} - -/** - * skb_get - reference buffer - * @skb: buffer to reference - * - * Makes another reference to a socket buffer and returns a pointer - * to the buffer. - */ -static inline struct sk_buff *skb_get(struct sk_buff *skb) -{ - atomic_inc(&skb->users); - return skb; -} - -/* - * If users == 1, we are the only owner and are can avoid redundant - * atomic change. - */ - -/** - * skb_cloned - is the buffer a clone - * @skb: buffer to check - * - * Returns true if the buffer was generated with skb_clone() and is - * one of multiple shared copies of the buffer. Cloned buffers are - * shared data so must not be written to under normal circumstances. - */ -static inline int skb_cloned(const struct sk_buff *skb) -{ - return skb->cloned && - (atomic_read(&skb_shinfo(skb)->dataref) & SKB_DATAREF_MASK) != 1; -} - -static inline int skb_unclone(struct sk_buff *skb, gfp_t pri) -{ - might_sleep_if(gfpflags_allow_blocking(pri)); - - if (skb_cloned(skb)) - return pskb_expand_head(skb, 0, 0, pri); - - return 0; -} - -/** - * skb_header_cloned - is the header a clone - * @skb: buffer to check - * - * Returns true if modifying the header part of the buffer requires - * the data to be copied. - */ -static inline int skb_header_cloned(const struct sk_buff *skb) -{ - int dataref; - - if (!skb->cloned) - return 0; - - dataref = atomic_read(&skb_shinfo(skb)->dataref); - dataref = (dataref & SKB_DATAREF_MASK) - (dataref >> SKB_DATAREF_SHIFT); - return dataref != 1; -} - -static inline int skb_header_unclone(struct sk_buff *skb, gfp_t pri) -{ - might_sleep_if(gfpflags_allow_blocking(pri)); - - if (skb_header_cloned(skb)) - return pskb_expand_head(skb, 0, 0, pri); - - return 0; -} - -/** - * skb_header_release - release reference to header - * @skb: buffer to operate on - * - * Drop a reference to the header part of the buffer. This is done - * by acquiring a payload reference. You must not read from the header - * part of skb->data after this. - * Note : Check if you can use __skb_header_release() instead. - */ -static inline void skb_header_release(struct sk_buff *skb) -{ - BUG_ON(skb->nohdr); - skb->nohdr = 1; - atomic_add(1 << SKB_DATAREF_SHIFT, &skb_shinfo(skb)->dataref); -} - -/** - * __skb_header_release - release reference to header - * @skb: buffer to operate on - * - * Variant of skb_header_release() assuming skb is private to caller. - * We can avoid one atomic operation. - */ -static inline void __skb_header_release(struct sk_buff *skb) -{ - skb->nohdr = 1; - atomic_set(&skb_shinfo(skb)->dataref, 1 + (1 << SKB_DATAREF_SHIFT)); -} - - -/** - * skb_shared - is the buffer shared - * @skb: buffer to check - * - * Returns true if more than one person has a reference to this - * buffer. - */ -static inline int skb_shared(const struct sk_buff *skb) -{ - return atomic_read(&skb->users) != 1; -} - -/** - * skb_share_check - check if buffer is shared and if so clone it - * @skb: buffer to check - * @pri: priority for memory allocation - * - * If the buffer is shared the buffer is cloned and the old copy - * drops a reference. A new clone with a single reference is returned. - * If the buffer is not shared the original buffer is returned. When - * being called from interrupt status or with spinlocks held pri must - * be GFP_ATOMIC. - * - * NULL is returned on a memory allocation failure. - */ -static inline struct sk_buff *skb_share_check(struct sk_buff *skb, gfp_t pri) -{ - might_sleep_if(gfpflags_allow_blocking(pri)); - if (skb_shared(skb)) { - struct sk_buff *nskb = skb_clone(skb, pri); - - if (likely(nskb)) - consume_skb(skb); - else - kfree_skb(skb); - skb = nskb; - } - return skb; -} - -/* - * Copy shared buffers into a new sk_buff. We effectively do COW on - * packets to handle cases where we have a local reader and forward - * and a couple of other messy ones. The normal one is tcpdumping - * a packet thats being forwarded. - */ - -/** - * skb_unshare - make a copy of a shared buffer - * @skb: buffer to check - * @pri: priority for memory allocation - * - * If the socket buffer is a clone then this function creates a new - * copy of the data, drops a reference count on the old copy and returns - * the new copy with the reference count at 1. If the buffer is not a clone - * the original buffer is returned. When called with a spinlock held or - * from interrupt state @pri must be %GFP_ATOMIC - * - * %NULL is returned on a memory allocation failure. - */ -static inline struct sk_buff *skb_unshare(struct sk_buff *skb, - gfp_t pri) -{ - might_sleep_if(gfpflags_allow_blocking(pri)); - if (skb_cloned(skb)) { - struct sk_buff *nskb = skb_copy(skb, pri); - - /* Free our shared copy */ - if (likely(nskb)) - consume_skb(skb); - else - kfree_skb(skb); - skb = nskb; - } - return skb; -} - -/** - * skb_peek - peek at the head of an &sk_buff_head - * @list_: list to peek at - * - * Peek an &sk_buff. Unlike most other operations you _MUST_ - * be careful with this one. A peek leaves the buffer on the - * list and someone else may run off with it. You must hold - * the appropriate locks or have a private queue to do this. - * - * Returns %NULL for an empty list or a pointer to the head element. - * The reference count is not incremented and the reference is therefore - * volatile. Use with caution. - */ -static inline struct sk_buff *skb_peek(const struct sk_buff_head *list_) -{ - struct sk_buff *skb = list_->next; - - if (skb == (struct sk_buff *)list_) - skb = NULL; - return skb; -} - -/** - * skb_peek_next - peek skb following the given one from a queue - * @skb: skb to start from - * @list_: list to peek at - * - * Returns %NULL when the end of the list is met or a pointer to the - * next element. The reference count is not incremented and the - * reference is therefore volatile. Use with caution. - */ -static inline struct sk_buff *skb_peek_next(struct sk_buff *skb, - const struct sk_buff_head *list_) -{ - struct sk_buff *next = skb->next; - - if (next == (struct sk_buff *)list_) - next = NULL; - return next; -} - -/** - * skb_peek_tail - peek at the tail of an &sk_buff_head - * @list_: list to peek at - * - * Peek an &sk_buff. Unlike most other operations you _MUST_ - * be careful with this one. A peek leaves the buffer on the - * list and someone else may run off with it. You must hold - * the appropriate locks or have a private queue to do this. - * - * Returns %NULL for an empty list or a pointer to the tail element. - * The reference count is not incremented and the reference is therefore - * volatile. Use with caution. - */ -static inline struct sk_buff *skb_peek_tail(const struct sk_buff_head *list_) -{ - struct sk_buff *skb = list_->prev; - - if (skb == (struct sk_buff *)list_) - skb = NULL; - return skb; - -} - -/** - * skb_queue_len - get queue length - * @list_: list to measure - * - * Return the length of an &sk_buff queue. - */ -static inline __u32 skb_queue_len(const struct sk_buff_head *list_) -{ - return list_->qlen; -} - -/** - * __skb_queue_head_init - initialize non-spinlock portions of sk_buff_head - * @list: queue to initialize - * - * This initializes only the list and queue length aspects of - * an sk_buff_head object. This allows to initialize the list - * aspects of an sk_buff_head without reinitializing things like - * the spinlock. It can also be used for on-stack sk_buff_head - * objects where the spinlock is known to not be used. - */ -static inline void __skb_queue_head_init(struct sk_buff_head *list) -{ - list->prev = list->next = (struct sk_buff *)list; - list->qlen = 0; -} - -/* - * This function creates a split out lock class for each invocation; - * this is needed for now since a whole lot of users of the skb-queue - * infrastructure in drivers have different locking usage (in hardirq) - * than the networking core (in softirq only). In the long run either the - * network layer or drivers should need annotation to consolidate the - * main types of usage into 3 classes. - */ -static inline void skb_queue_head_init(struct sk_buff_head *list) -{ - spin_lock_init(&list->lock); - __skb_queue_head_init(list); -} - -static inline void skb_queue_head_init_class(struct sk_buff_head *list, - struct lock_class_key *class) -{ - skb_queue_head_init(list); - lockdep_set_class(&list->lock, class); -} - -/* - * Insert an sk_buff on a list. - * - * The "__skb_xxxx()" functions are the non-atomic ones that - * can only be called with interrupts disabled. - */ -void skb_insert(struct sk_buff *old, struct sk_buff *newsk, - struct sk_buff_head *list); -static inline void __skb_insert(struct sk_buff *newsk, - struct sk_buff *prev, struct sk_buff *next, - struct sk_buff_head *list) -{ - newsk->next = next; - newsk->prev = prev; - next->prev = prev->next = newsk; - list->qlen++; -} - -static inline void __skb_queue_splice(const struct sk_buff_head *list, - struct sk_buff *prev, - struct sk_buff *next) -{ - struct sk_buff *first = list->next; - struct sk_buff *last = list->prev; - - first->prev = prev; - prev->next = first; - - last->next = next; - next->prev = last; -} - -/** - * skb_queue_splice - join two skb lists, this is designed for stacks - * @list: the new list to add - * @head: the place to add it in the first list - */ -static inline void skb_queue_splice(const struct sk_buff_head *list, - struct sk_buff_head *head) -{ - if (!skb_queue_empty(list)) { - __skb_queue_splice(list, (struct sk_buff *) head, head->next); - head->qlen += list->qlen; - } -} - -/** - * skb_queue_splice_init - join two skb lists and reinitialise the emptied list - * @list: the new list to add - * @head: the place to add it in the first list - * - * The list at @list is reinitialised - */ -static inline void skb_queue_splice_init(struct sk_buff_head *list, - struct sk_buff_head *head) -{ - if (!skb_queue_empty(list)) { - __skb_queue_splice(list, (struct sk_buff *) head, head->next); - head->qlen += list->qlen; - __skb_queue_head_init(list); - } -} - -/** - * skb_queue_splice_tail - join two skb lists, each list being a queue - * @list: the new list to add - * @head: the place to add it in the first list - */ -static inline void skb_queue_splice_tail(const struct sk_buff_head *list, - struct sk_buff_head *head) -{ - if (!skb_queue_empty(list)) { - __skb_queue_splice(list, head->prev, (struct sk_buff *) head); - head->qlen += list->qlen; - } -} - -/** - * skb_queue_splice_tail_init - join two skb lists and reinitialise the emptied list - * @list: the new list to add - * @head: the place to add it in the first list - * - * Each of the lists is a queue. - * The list at @list is reinitialised - */ -static inline void skb_queue_splice_tail_init(struct sk_buff_head *list, - struct sk_buff_head *head) -{ - if (!skb_queue_empty(list)) { - __skb_queue_splice(list, head->prev, (struct sk_buff *) head); - head->qlen += list->qlen; - __skb_queue_head_init(list); - } -} - -/** - * __skb_queue_after - queue a buffer at the list head - * @list: list to use - * @prev: place after this buffer - * @newsk: buffer to queue - * - * Queue a buffer int the middle of a list. This function takes no locks - * and you must therefore hold required locks before calling it. - * - * A buffer cannot be placed on two lists at the same time. - */ -static inline void __skb_queue_after(struct sk_buff_head *list, - struct sk_buff *prev, - struct sk_buff *newsk) -{ - __skb_insert(newsk, prev, prev->next, list); -} - -void skb_append(struct sk_buff *old, struct sk_buff *newsk, - struct sk_buff_head *list); - -static inline void __skb_queue_before(struct sk_buff_head *list, - struct sk_buff *next, - struct sk_buff *newsk) -{ - __skb_insert(newsk, next->prev, next, list); -} - -/** - * __skb_queue_head - queue a buffer at the list head - * @list: list to use - * @newsk: buffer to queue - * - * Queue a buffer at the start of a list. This function takes no locks - * and you must therefore hold required locks before calling it. - * - * A buffer cannot be placed on two lists at the same time. - */ -void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk); -static inline void __skb_queue_head(struct sk_buff_head *list, - struct sk_buff *newsk) -{ - __skb_queue_after(list, (struct sk_buff *)list, newsk); -} - -/** - * __skb_queue_tail - queue a buffer at the list tail - * @list: list to use - * @newsk: buffer to queue - * - * Queue a buffer at the end of a list. This function takes no locks - * and you must therefore hold required locks before calling it. - * - * A buffer cannot be placed on two lists at the same time. - */ -void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk); -static inline void __skb_queue_tail(struct sk_buff_head *list, - struct sk_buff *newsk) -{ - __skb_queue_before(list, (struct sk_buff *)list, newsk); -} - -/* - * remove sk_buff from list. _Must_ be called atomically, and with - * the list known.. - */ -void skb_unlink(struct sk_buff *skb, struct sk_buff_head *list); -static inline void __skb_unlink(struct sk_buff *skb, struct sk_buff_head *list) -{ - struct sk_buff *next, *prev; - - list->qlen--; - next = skb->next; - prev = skb->prev; - skb->next = skb->prev = NULL; - next->prev = prev; - prev->next = next; -} - -/** - * __skb_dequeue - remove from the head of the queue - * @list: list to dequeue from - * - * Remove the head of the list. This function does not take any locks - * so must be used with appropriate locks held only. The head item is - * returned or %NULL if the list is empty. - */ -struct sk_buff *skb_dequeue(struct sk_buff_head *list); -static inline struct sk_buff *__skb_dequeue(struct sk_buff_head *list) -{ - struct sk_buff *skb = skb_peek(list); - if (skb) - __skb_unlink(skb, list); - return skb; -} - -/** - * __skb_dequeue_tail - remove from the tail of the queue - * @list: list to dequeue from - * - * Remove the tail of the list. This function does not take any locks - * so must be used with appropriate locks held only. The tail item is - * returned or %NULL if the list is empty. - */ -struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list); -static inline struct sk_buff *__skb_dequeue_tail(struct sk_buff_head *list) -{ - struct sk_buff *skb = skb_peek_tail(list); - if (skb) - __skb_unlink(skb, list); - return skb; -} - - -static inline bool skb_is_nonlinear(const struct sk_buff *skb) -{ - return skb->data_len; -} - -static inline unsigned int skb_headlen(const struct sk_buff *skb) -{ - return skb->len - skb->data_len; -} - -static inline int skb_pagelen(const struct sk_buff *skb) -{ - int i, len = 0; - - for (i = (int)skb_shinfo(skb)->nr_frags - 1; i >= 0; i--) - len += skb_frag_size(&skb_shinfo(skb)->frags[i]); - return len + skb_headlen(skb); -} - -/** - * __skb_fill_page_desc - initialise a paged fragment in an skb - * @skb: buffer containing fragment to be initialised - * @i: paged fragment index to initialise - * @page: the page to use for this fragment - * @off: the offset to the data with @page - * @size: the length of the data - * - * Initialises the @i'th fragment of @skb to point to &size bytes at - * offset @off within @page. - * - * Does not take any additional reference on the fragment. - */ -static inline void __skb_fill_page_desc(struct sk_buff *skb, int i, - struct page *page, int off, int size) -{ - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - /* - * Propagate page pfmemalloc to the skb if we can. The problem is - * that not all callers have unique ownership of the page but rely - * on page_is_pfmemalloc doing the right thing(tm). - */ - frag->page.p = page; - frag->page_offset = off; - skb_frag_size_set(frag, size); - - page = compound_head(page); - if (page_is_pfmemalloc(page)) - skb->pfmemalloc = true; -} - -/** - * skb_fill_page_desc - initialise a paged fragment in an skb - * @skb: buffer containing fragment to be initialised - * @i: paged fragment index to initialise - * @page: the page to use for this fragment - * @off: the offset to the data with @page - * @size: the length of the data - * - * As per __skb_fill_page_desc() -- initialises the @i'th fragment of - * @skb to point to @size bytes at offset @off within @page. In - * addition updates @skb such that @i is the last fragment. - * - * Does not take any additional reference on the fragment. - */ -static inline void skb_fill_page_desc(struct sk_buff *skb, int i, - struct page *page, int off, int size) -{ - __skb_fill_page_desc(skb, i, page, off, size); - skb_shinfo(skb)->nr_frags = i + 1; -} - -void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, - int size, unsigned int truesize); - -void skb_coalesce_rx_frag(struct sk_buff *skb, int i, int size, - unsigned int truesize); - -#define SKB_PAGE_ASSERT(skb) BUG_ON(skb_shinfo(skb)->nr_frags) -#define SKB_FRAG_ASSERT(skb) BUG_ON(skb_has_frag_list(skb)) -#define SKB_LINEAR_ASSERT(skb) BUG_ON(skb_is_nonlinear(skb)) - -#ifdef NET_SKBUFF_DATA_USES_OFFSET -static inline unsigned char *skb_tail_pointer(const struct sk_buff *skb) -{ - return skb->head + skb->tail; -} - -static inline void skb_reset_tail_pointer(struct sk_buff *skb) -{ - skb->tail = skb->data - skb->head; -} - -static inline void skb_set_tail_pointer(struct sk_buff *skb, const int offset) -{ - skb_reset_tail_pointer(skb); - skb->tail += offset; -} - -#else /* NET_SKBUFF_DATA_USES_OFFSET */ -static inline unsigned char *skb_tail_pointer(const struct sk_buff *skb) -{ - return skb->tail; -} - -static inline void skb_reset_tail_pointer(struct sk_buff *skb) -{ - skb->tail = skb->data; -} - -static inline void skb_set_tail_pointer(struct sk_buff *skb, const int offset) -{ - skb->tail = skb->data + offset; -} - -#endif /* NET_SKBUFF_DATA_USES_OFFSET */ - -/* - * Add data to an sk_buff - */ -unsigned char *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len); -unsigned char *skb_put(struct sk_buff *skb, unsigned int len); -static inline unsigned char *__skb_put(struct sk_buff *skb, unsigned int len) -{ - unsigned char *tmp = skb_tail_pointer(skb); - SKB_LINEAR_ASSERT(skb); - skb->tail += len; - skb->len += len; - return tmp; -} - -unsigned char *skb_push(struct sk_buff *skb, unsigned int len); -static inline unsigned char *__skb_push(struct sk_buff *skb, unsigned int len) -{ - skb->data -= len; - skb->len += len; - return skb->data; -} - -unsigned char *skb_pull(struct sk_buff *skb, unsigned int len); -static inline unsigned char *__skb_pull(struct sk_buff *skb, unsigned int len) -{ - skb->len -= len; - BUG_ON(skb->len < skb->data_len); - return skb->data += len; -} - -static inline unsigned char *skb_pull_inline(struct sk_buff *skb, unsigned int len) -{ - return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len); -} - -unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta); - -static inline unsigned char *__pskb_pull(struct sk_buff *skb, unsigned int len) -{ - if (len > skb_headlen(skb) && - !__pskb_pull_tail(skb, len - skb_headlen(skb))) - return NULL; - skb->len -= len; - return skb->data += len; -} - -static inline unsigned char *pskb_pull(struct sk_buff *skb, unsigned int len) -{ - return unlikely(len > skb->len) ? NULL : __pskb_pull(skb, len); -} - -static inline int pskb_may_pull(struct sk_buff *skb, unsigned int len) -{ - if (likely(len <= skb_headlen(skb))) - return 1; - if (unlikely(len > skb->len)) - return 0; - return __pskb_pull_tail(skb, len - skb_headlen(skb)) != NULL; -} - -/** - * skb_headroom - bytes at buffer head - * @skb: buffer to check - * - * Return the number of bytes of free space at the head of an &sk_buff. - */ -static inline unsigned int skb_headroom(const struct sk_buff *skb) -{ - return skb->data - skb->head; -} - -/** - * skb_tailroom - bytes at buffer end - * @skb: buffer to check - * - * Return the number of bytes of free space at the tail of an sk_buff - */ -static inline int skb_tailroom(const struct sk_buff *skb) -{ - return skb_is_nonlinear(skb) ? 0 : skb->end - skb->tail; -} - -/** - * skb_availroom - bytes at buffer end - * @skb: buffer to check - * - * Return the number of bytes of free space at the tail of an sk_buff - * allocated by sk_stream_alloc() - */ -static inline int skb_availroom(const struct sk_buff *skb) -{ - if (skb_is_nonlinear(skb)) - return 0; - - return skb->end - skb->tail - skb->reserved_tailroom; -} - -/** - * skb_reserve - adjust headroom - * @skb: buffer to alter - * @len: bytes to move - * - * Increase the headroom of an empty &sk_buff by reducing the tail - * room. This is only allowed for an empty buffer. - */ -static inline void skb_reserve(struct sk_buff *skb, int len) -{ - skb->data += len; - skb->tail += len; -} - -/** - * skb_tailroom_reserve - adjust reserved_tailroom - * @skb: buffer to alter - * @mtu: maximum amount of headlen permitted - * @needed_tailroom: minimum amount of reserved_tailroom - * - * Set reserved_tailroom so that headlen can be as large as possible but - * not larger than mtu and tailroom cannot be smaller than - * needed_tailroom. - * The required headroom should already have been reserved before using - * this function. - */ -static inline void skb_tailroom_reserve(struct sk_buff *skb, unsigned int mtu, - unsigned int needed_tailroom) -{ - SKB_LINEAR_ASSERT(skb); - if (mtu < skb_tailroom(skb) - needed_tailroom) - /* use at most mtu */ - skb->reserved_tailroom = skb_tailroom(skb) - mtu; - else - /* use up to all available space */ - skb->reserved_tailroom = needed_tailroom; -} - -#define ENCAP_TYPE_ETHER 0 -#define ENCAP_TYPE_IPPROTO 1 - -static inline void skb_set_inner_protocol(struct sk_buff *skb, - __be16 protocol) -{ - skb->inner_protocol = protocol; - skb->inner_protocol_type = ENCAP_TYPE_ETHER; -} - -static inline void skb_set_inner_ipproto(struct sk_buff *skb, - __u8 ipproto) -{ - skb->inner_ipproto = ipproto; - skb->inner_protocol_type = ENCAP_TYPE_IPPROTO; -} - -static inline void skb_reset_inner_headers(struct sk_buff *skb) -{ - skb->inner_mac_header = skb->mac_header; - skb->inner_network_header = skb->network_header; - skb->inner_transport_header = skb->transport_header; -} - -static inline void skb_reset_mac_len(struct sk_buff *skb) -{ - skb->mac_len = skb->network_header - skb->mac_header; -} - -static inline unsigned char *skb_inner_transport_header(const struct sk_buff - *skb) -{ - return skb->head + skb->inner_transport_header; -} - -static inline int skb_inner_transport_offset(const struct sk_buff *skb) -{ - return skb_inner_transport_header(skb) - skb->data; -} - -static inline void skb_reset_inner_transport_header(struct sk_buff *skb) -{ - skb->inner_transport_header = skb->data - skb->head; -} - -static inline void skb_set_inner_transport_header(struct sk_buff *skb, - const int offset) -{ - skb_reset_inner_transport_header(skb); - skb->inner_transport_header += offset; -} - -static inline unsigned char *skb_inner_network_header(const struct sk_buff *skb) -{ - return skb->head + skb->inner_network_header; -} - -static inline void skb_reset_inner_network_header(struct sk_buff *skb) -{ - skb->inner_network_header = skb->data - skb->head; -} - -static inline void skb_set_inner_network_header(struct sk_buff *skb, - const int offset) -{ - skb_reset_inner_network_header(skb); - skb->inner_network_header += offset; -} - -static inline unsigned char *skb_inner_mac_header(const struct sk_buff *skb) -{ - return skb->head + skb->inner_mac_header; -} - -static inline void skb_reset_inner_mac_header(struct sk_buff *skb) -{ - skb->inner_mac_header = skb->data - skb->head; -} - -static inline void skb_set_inner_mac_header(struct sk_buff *skb, - const int offset) -{ - skb_reset_inner_mac_header(skb); - skb->inner_mac_header += offset; -} -static inline bool skb_transport_header_was_set(const struct sk_buff *skb) -{ - return skb->transport_header != (typeof(skb->transport_header))~0U; -} - -static inline unsigned char *skb_transport_header(const struct sk_buff *skb) -{ - return skb->head + skb->transport_header; -} - -static inline void skb_reset_transport_header(struct sk_buff *skb) -{ - skb->transport_header = skb->data - skb->head; -} - -static inline void skb_set_transport_header(struct sk_buff *skb, - const int offset) -{ - skb_reset_transport_header(skb); - skb->transport_header += offset; -} - -static inline unsigned char *skb_network_header(const struct sk_buff *skb) -{ - return skb->head + skb->network_header; -} - -static inline void skb_reset_network_header(struct sk_buff *skb) -{ - skb->network_header = skb->data - skb->head; -} - -static inline void skb_set_network_header(struct sk_buff *skb, const int offset) -{ - skb_reset_network_header(skb); - skb->network_header += offset; -} - -static inline unsigned char *skb_mac_header(const struct sk_buff *skb) -{ - return skb->head + skb->mac_header; -} - -static inline int skb_mac_header_was_set(const struct sk_buff *skb) -{ - return skb->mac_header != (typeof(skb->mac_header))~0U; -} - -static inline void skb_reset_mac_header(struct sk_buff *skb) -{ - skb->mac_header = skb->data - skb->head; -} - -static inline void skb_set_mac_header(struct sk_buff *skb, const int offset) -{ - skb_reset_mac_header(skb); - skb->mac_header += offset; -} - -static inline void skb_pop_mac_header(struct sk_buff *skb) -{ - skb->mac_header = skb->network_header; -} - -static inline void skb_probe_transport_header(struct sk_buff *skb, - const int offset_hint) -{ - struct flow_keys keys; - - if (skb_transport_header_was_set(skb)) - return; - else if (skb_flow_dissect_flow_keys(skb, &keys, 0)) - skb_set_transport_header(skb, keys.control.thoff); - else - skb_set_transport_header(skb, offset_hint); -} - -static inline void skb_mac_header_rebuild(struct sk_buff *skb) -{ - if (skb_mac_header_was_set(skb)) { - const unsigned char *old_mac = skb_mac_header(skb); - - skb_set_mac_header(skb, -skb->mac_len); - memmove(skb_mac_header(skb), old_mac, skb->mac_len); - } -} - -static inline int skb_checksum_start_offset(const struct sk_buff *skb) -{ - return skb->csum_start - skb_headroom(skb); -} - -static inline unsigned char *skb_checksum_start(const struct sk_buff *skb) -{ - return skb->head + skb->csum_start; -} - -static inline int skb_transport_offset(const struct sk_buff *skb) -{ - return skb_transport_header(skb) - skb->data; -} - -static inline u32 skb_network_header_len(const struct sk_buff *skb) -{ - return skb->transport_header - skb->network_header; -} - -static inline u32 skb_inner_network_header_len(const struct sk_buff *skb) -{ - return skb->inner_transport_header - skb->inner_network_header; -} - -static inline int skb_network_offset(const struct sk_buff *skb) -{ - return skb_network_header(skb) - skb->data; -} - -static inline int skb_inner_network_offset(const struct sk_buff *skb) -{ - return skb_inner_network_header(skb) - skb->data; -} - -static inline int pskb_network_may_pull(struct sk_buff *skb, unsigned int len) -{ - return pskb_may_pull(skb, skb_network_offset(skb) + len); -} - -/* - * CPUs often take a performance hit when accessing unaligned memory - * locations. The actual performance hit varies, it can be small if the - * hardware handles it or large if we have to take an exception and fix it - * in software. - * - * Since an ethernet header is 14 bytes network drivers often end up with - * the IP header at an unaligned offset. The IP header can be aligned by - * shifting the start of the packet by 2 bytes. Drivers should do this - * with: - * - * skb_reserve(skb, NET_IP_ALIGN); - * - * The downside to this alignment of the IP header is that the DMA is now - * unaligned. On some architectures the cost of an unaligned DMA is high - * and this cost outweighs the gains made by aligning the IP header. - * - * Since this trade off varies between architectures, we allow NET_IP_ALIGN - * to be overridden. - */ -#ifndef NET_IP_ALIGN -#define NET_IP_ALIGN 2 -#endif - -/* - * The networking layer reserves some headroom in skb data (via - * dev_alloc_skb). This is used to avoid having to reallocate skb data when - * the header has to grow. In the default case, if the header has to grow - * 32 bytes or less we avoid the reallocation. - * - * Unfortunately this headroom changes the DMA alignment of the resulting - * network packet. As for NET_IP_ALIGN, this unaligned DMA is expensive - * on some architectures. An architecture can override this value, - * perhaps setting it to a cacheline in size (since that will maintain - * cacheline alignment of the DMA). It must be a power of 2. - * - * Various parts of the networking layer expect at least 32 bytes of - * headroom, you should not reduce this. - * - * Using max(32, L1_CACHE_BYTES) makes sense (especially with RPS) - * to reduce average number of cache lines per packet. - * get_rps_cpus() for example only access one 64 bytes aligned block : - * NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8) - */ -#ifndef NET_SKB_PAD -#define NET_SKB_PAD max(32, L1_CACHE_BYTES) -#endif - -int ___pskb_trim(struct sk_buff *skb, unsigned int len); - -static inline void __skb_set_length(struct sk_buff *skb, unsigned int len) -{ - if (unlikely(skb_is_nonlinear(skb))) { - WARN_ON(1); - return; - } - skb->len = len; - skb_set_tail_pointer(skb, len); -} - -static inline void __skb_trim(struct sk_buff *skb, unsigned int len) -{ - __skb_set_length(skb, len); -} - -void skb_trim(struct sk_buff *skb, unsigned int len); - -static inline int __pskb_trim(struct sk_buff *skb, unsigned int len) -{ - if (skb->data_len) - return ___pskb_trim(skb, len); - __skb_trim(skb, len); - return 0; -} - -static inline int pskb_trim(struct sk_buff *skb, unsigned int len) -{ - return (len < skb->len) ? __pskb_trim(skb, len) : 0; -} - -/** - * pskb_trim_unique - remove end from a paged unique (not cloned) buffer - * @skb: buffer to alter - * @len: new length - * - * This is identical to pskb_trim except that the caller knows that - * the skb is not cloned so we should never get an error due to out- - * of-memory. - */ -static inline void pskb_trim_unique(struct sk_buff *skb, unsigned int len) -{ - int err = pskb_trim(skb, len); - BUG_ON(err); -} - -static inline int __skb_grow(struct sk_buff *skb, unsigned int len) -{ - unsigned int diff = len - skb->len; - - if (skb_tailroom(skb) < diff) { - int ret = pskb_expand_head(skb, 0, diff - skb_tailroom(skb), - GFP_ATOMIC); - if (ret) - return ret; - } - __skb_set_length(skb, len); - return 0; -} - -/** - * skb_orphan - orphan a buffer - * @skb: buffer to orphan - * - * If a buffer currently has an owner then we call the owner's - * destructor function and make the @skb unowned. The buffer continues - * to exist but is no longer charged to its former owner. - */ -static inline void skb_orphan(struct sk_buff *skb) -{ - if (skb->destructor) { - skb->destructor(skb); - skb->destructor = NULL; - skb->sk = NULL; - } else { - BUG_ON(skb->sk); - } -} - -/** - * skb_orphan_frags - orphan the frags contained in a buffer - * @skb: buffer to orphan frags from - * @gfp_mask: allocation mask for replacement pages - * - * For each frag in the SKB which needs a destructor (i.e. has an - * owner) create a copy of that frag and release the original - * page by calling the destructor. - */ -static inline int skb_orphan_frags(struct sk_buff *skb, gfp_t gfp_mask) -{ - if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY))) - return 0; - return skb_copy_ubufs(skb, gfp_mask); -} - -/** - * __skb_queue_purge - empty a list - * @list: list to empty - * - * Delete all buffers on an &sk_buff list. Each buffer is removed from - * the list and one reference dropped. This function does not take the - * list lock and the caller must hold the relevant locks to use it. - */ -void skb_queue_purge(struct sk_buff_head *list); -static inline void __skb_queue_purge(struct sk_buff_head *list) -{ - struct sk_buff *skb; - while ((skb = __skb_dequeue(list)) != NULL) - kfree_skb(skb); -} - -void skb_rbtree_purge(struct rb_root *root); - -void *netdev_alloc_frag(unsigned int fragsz); - -struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int length, - gfp_t gfp_mask); - -/** - * netdev_alloc_skb - allocate an skbuff for rx on a specific device - * @dev: network device to receive on - * @length: length to allocate - * - * Allocate a new &sk_buff and assign it a usage count of one. The - * buffer has unspecified headroom built in. Users should allocate - * the headroom they think they need without accounting for the - * built in space. The built in space is used for optimisations. - * - * %NULL is returned if there is no free memory. Although this function - * allocates memory it can be called from an interrupt. - */ -static inline struct sk_buff *netdev_alloc_skb(struct net_device *dev, - unsigned int length) -{ - return __netdev_alloc_skb(dev, length, GFP_ATOMIC); -} - -/* legacy helper around __netdev_alloc_skb() */ -static inline struct sk_buff *__dev_alloc_skb(unsigned int length, - gfp_t gfp_mask) -{ - return __netdev_alloc_skb(NULL, length, gfp_mask); -} - -/* legacy helper around netdev_alloc_skb() */ -static inline struct sk_buff *dev_alloc_skb(unsigned int length) -{ - return netdev_alloc_skb(NULL, length); -} - - -static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev, - unsigned int length, gfp_t gfp) -{ - struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp); - - if (NET_IP_ALIGN && skb) - skb_reserve(skb, NET_IP_ALIGN); - return skb; -} - -static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev, - unsigned int length) -{ - return __netdev_alloc_skb_ip_align(dev, length, GFP_ATOMIC); -} - -static inline void skb_free_frag(void *addr) -{ - __free_page_frag(addr); -} - -void *napi_alloc_frag(unsigned int fragsz); -struct sk_buff *__napi_alloc_skb(struct napi_struct *napi, - unsigned int length, gfp_t gfp_mask); -static inline struct sk_buff *napi_alloc_skb(struct napi_struct *napi, - unsigned int length) -{ - return __napi_alloc_skb(napi, length, GFP_ATOMIC); -} -void napi_consume_skb(struct sk_buff *skb, int budget); - -void __kfree_skb_flush(void); -void __kfree_skb_defer(struct sk_buff *skb); - -/** - * __dev_alloc_pages - allocate page for network Rx - * @gfp_mask: allocation priority. Set __GFP_NOMEMALLOC if not for network Rx - * @order: size of the allocation - * - * Allocate a new page. - * - * %NULL is returned if there is no free memory. -*/ -static inline struct page *__dev_alloc_pages(gfp_t gfp_mask, - unsigned int order) -{ - /* This piece of code contains several assumptions. - * 1. This is for device Rx, therefor a cold page is preferred. - * 2. The expectation is the user wants a compound page. - * 3. If requesting a order 0 page it will not be compound - * due to the check to see if order has a value in prep_new_page - * 4. __GFP_MEMALLOC is ignored if __GFP_NOMEMALLOC is set due to - * code in gfp_to_alloc_flags that should be enforcing this. - */ - gfp_mask |= __GFP_COLD | __GFP_COMP | __GFP_MEMALLOC; - - return alloc_pages_node(NUMA_NO_NODE, gfp_mask, order); -} - -static inline struct page *dev_alloc_pages(unsigned int order) -{ - return __dev_alloc_pages(GFP_ATOMIC | __GFP_NOWARN, order); -} - -/** - * __dev_alloc_page - allocate a page for network Rx - * @gfp_mask: allocation priority. Set __GFP_NOMEMALLOC if not for network Rx - * - * Allocate a new page. - * - * %NULL is returned if there is no free memory. - */ -static inline struct page *__dev_alloc_page(gfp_t gfp_mask) -{ - return __dev_alloc_pages(gfp_mask, 0); -} - -static inline struct page *dev_alloc_page(void) -{ - return dev_alloc_pages(0); -} - -/** - * skb_propagate_pfmemalloc - Propagate pfmemalloc if skb is allocated after RX page - * @page: The page that was allocated from skb_alloc_page - * @skb: The skb that may need pfmemalloc set - */ -static inline void skb_propagate_pfmemalloc(struct page *page, - struct sk_buff *skb) -{ - if (page_is_pfmemalloc(page)) - skb->pfmemalloc = true; -} - -/** - * skb_frag_page - retrieve the page referred to by a paged fragment - * @frag: the paged fragment - * - * Returns the &struct page associated with @frag. - */ -static inline struct page *skb_frag_page(const skb_frag_t *frag) -{ - return frag->page.p; -} - -/** - * __skb_frag_ref - take an addition reference on a paged fragment. - * @frag: the paged fragment - * - * Takes an additional reference on the paged fragment @frag. - */ -static inline void __skb_frag_ref(skb_frag_t *frag) -{ - get_page(skb_frag_page(frag)); -} - -/** - * skb_frag_ref - take an addition reference on a paged fragment of an skb. - * @skb: the buffer - * @f: the fragment offset. - * - * Takes an additional reference on the @f'th paged fragment of @skb. - */ -static inline void skb_frag_ref(struct sk_buff *skb, int f) -{ - __skb_frag_ref(&skb_shinfo(skb)->frags[f]); -} - -/** - * __skb_frag_unref - release a reference on a paged fragment. - * @frag: the paged fragment - * - * Releases a reference on the paged fragment @frag. - */ -static inline void __skb_frag_unref(skb_frag_t *frag) -{ - put_page(skb_frag_page(frag)); -} - -/** - * skb_frag_unref - release a reference on a paged fragment of an skb. - * @skb: the buffer - * @f: the fragment offset - * - * Releases a reference on the @f'th paged fragment of @skb. - */ -static inline void skb_frag_unref(struct sk_buff *skb, int f) -{ - __skb_frag_unref(&skb_shinfo(skb)->frags[f]); -} - -/** - * skb_frag_address - gets the address of the data contained in a paged fragment - * @frag: the paged fragment buffer - * - * Returns the address of the data within @frag. The page must already - * be mapped. - */ -static inline void *skb_frag_address(const skb_frag_t *frag) -{ - return page_address(skb_frag_page(frag)) + frag->page_offset; -} - -/** - * skb_frag_address_safe - gets the address of the data contained in a paged fragment - * @frag: the paged fragment buffer - * - * Returns the address of the data within @frag. Checks that the page - * is mapped and returns %NULL otherwise. - */ -static inline void *skb_frag_address_safe(const skb_frag_t *frag) -{ - void *ptr = page_address(skb_frag_page(frag)); - if (unlikely(!ptr)) - return NULL; - - return ptr + frag->page_offset; -} - -/** - * __skb_frag_set_page - sets the page contained in a paged fragment - * @frag: the paged fragment - * @page: the page to set - * - * Sets the fragment @frag to contain @page. - */ -static inline void __skb_frag_set_page(skb_frag_t *frag, struct page *page) -{ - frag->page.p = page; -} - -/** - * skb_frag_set_page - sets the page contained in a paged fragment of an skb - * @skb: the buffer - * @f: the fragment offset - * @page: the page to set - * - * Sets the @f'th fragment of @skb to contain @page. - */ -static inline void skb_frag_set_page(struct sk_buff *skb, int f, - struct page *page) -{ - __skb_frag_set_page(&skb_shinfo(skb)->frags[f], page); -} - -bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t prio); - -/** - * skb_frag_dma_map - maps a paged fragment via the DMA API - * @dev: the device to map the fragment to - * @frag: the paged fragment to map - * @offset: the offset within the fragment (starting at the - * fragment's own offset) - * @size: the number of bytes to map - * @dir: the direction of the mapping (%PCI_DMA_*) - * - * Maps the page associated with @frag to @device. - */ -static inline dma_addr_t skb_frag_dma_map(struct device *dev, - const skb_frag_t *frag, - size_t offset, size_t size, - enum dma_data_direction dir) -{ - return dma_map_page(dev, skb_frag_page(frag), - frag->page_offset + offset, size, dir); -} - -static inline struct sk_buff *pskb_copy(struct sk_buff *skb, - gfp_t gfp_mask) -{ - return __pskb_copy(skb, skb_headroom(skb), gfp_mask); -} - - -static inline struct sk_buff *pskb_copy_for_clone(struct sk_buff *skb, - gfp_t gfp_mask) -{ - return __pskb_copy_fclone(skb, skb_headroom(skb), gfp_mask, true); -} - - -/** - * skb_clone_writable - is the header of a clone writable - * @skb: buffer to check - * @len: length up to which to write - * - * Returns true if modifying the header part of the cloned buffer - * does not requires the data to be copied. - */ -static inline int skb_clone_writable(const struct sk_buff *skb, unsigned int len) -{ - return !skb_header_cloned(skb) && - skb_headroom(skb) + len <= skb->hdr_len; -} - -static inline int skb_try_make_writable(struct sk_buff *skb, - unsigned int write_len) -{ - return skb_cloned(skb) && !skb_clone_writable(skb, write_len) && - pskb_expand_head(skb, 0, 0, GFP_ATOMIC); -} - -static inline int __skb_cow(struct sk_buff *skb, unsigned int headroom, - int cloned) -{ - int delta = 0; - - if (headroom > skb_headroom(skb)) - delta = headroom - skb_headroom(skb); - - if (delta || cloned) - return pskb_expand_head(skb, ALIGN(delta, NET_SKB_PAD), 0, - GFP_ATOMIC); - return 0; -} - -/** - * skb_cow - copy header of skb when it is required - * @skb: buffer to cow - * @headroom: needed headroom - * - * If the skb passed lacks sufficient headroom or its data part - * is shared, data is reallocated. If reallocation fails, an error - * is returned and original skb is not changed. - * - * The result is skb with writable area skb->head...skb->tail - * and at least @headroom of space at head. - */ -static inline int skb_cow(struct sk_buff *skb, unsigned int headroom) -{ - return __skb_cow(skb, headroom, skb_cloned(skb)); -} - -/** - * skb_cow_head - skb_cow but only making the head writable - * @skb: buffer to cow - * @headroom: needed headroom - * - * This function is identical to skb_cow except that we replace the - * skb_cloned check by skb_header_cloned. It should be used when - * you only need to push on some header and do not need to modify - * the data. - */ -static inline int skb_cow_head(struct sk_buff *skb, unsigned int headroom) -{ - return __skb_cow(skb, headroom, skb_header_cloned(skb)); -} - -/** - * skb_padto - pad an skbuff up to a minimal size - * @skb: buffer to pad - * @len: minimal length - * - * Pads up a buffer to ensure the trailing bytes exist and are - * blanked. If the buffer already contains sufficient data it - * is untouched. Otherwise it is extended. Returns zero on - * success. The skb is freed on error. - */ -static inline int skb_padto(struct sk_buff *skb, unsigned int len) -{ - unsigned int size = skb->len; - if (likely(size >= len)) - return 0; - return skb_pad(skb, len - size); -} - -/** - * skb_put_padto - increase size and pad an skbuff up to a minimal size - * @skb: buffer to pad - * @len: minimal length - * - * Pads up a buffer to ensure the trailing bytes exist and are - * blanked. If the buffer already contains sufficient data it - * is untouched. Otherwise it is extended. Returns zero on - * success. The skb is freed on error. - */ -static inline int skb_put_padto(struct sk_buff *skb, unsigned int len) -{ - unsigned int size = skb->len; - - if (unlikely(size < len)) { - len -= size; - if (skb_pad(skb, len)) - return -ENOMEM; - __skb_put(skb, len); - } - return 0; -} - -static inline int skb_add_data(struct sk_buff *skb, - struct iov_iter *from, int copy) -{ - const int off = skb->len; - - if (skb->ip_summed == CHECKSUM_NONE) { - __wsum csum = 0; - if (csum_and_copy_from_iter(skb_put(skb, copy), copy, - &csum, from) == copy) { - skb->csum = csum_block_add(skb->csum, csum, off); - return 0; - } - } else if (copy_from_iter(skb_put(skb, copy), copy, from) == copy) - return 0; - - __skb_trim(skb, off); - return -EFAULT; -} - -static inline bool skb_can_coalesce(struct sk_buff *skb, int i, - const struct page *page, int off) -{ - if (i) { - const struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i - 1]; - - return page == skb_frag_page(frag) && - off == frag->page_offset + skb_frag_size(frag); - } - return false; -} - -static inline int __skb_linearize(struct sk_buff *skb) -{ - return __pskb_pull_tail(skb, skb->data_len) ? 0 : -ENOMEM; -} - -/** - * skb_linearize - convert paged skb to linear one - * @skb: buffer to linarize - * - * If there is no free memory -ENOMEM is returned, otherwise zero - * is returned and the old skb data released. - */ -static inline int skb_linearize(struct sk_buff *skb) -{ - return skb_is_nonlinear(skb) ? __skb_linearize(skb) : 0; -} - -/** - * skb_has_shared_frag - can any frag be overwritten - * @skb: buffer to test - * - * Return true if the skb has at least one frag that might be modified - * by an external entity (as in vmsplice()/sendfile()) - */ -static inline bool skb_has_shared_frag(const struct sk_buff *skb) -{ - return skb_is_nonlinear(skb) && - skb_shinfo(skb)->tx_flags & SKBTX_SHARED_FRAG; -} - -/** - * skb_linearize_cow - make sure skb is linear and writable - * @skb: buffer to process - * - * If there is no free memory -ENOMEM is returned, otherwise zero - * is returned and the old skb data released. - */ -static inline int skb_linearize_cow(struct sk_buff *skb) -{ - return skb_is_nonlinear(skb) || skb_cloned(skb) ? - __skb_linearize(skb) : 0; -} - -static __always_inline void -__skb_postpull_rcsum(struct sk_buff *skb, const void *start, unsigned int len, - unsigned int off) -{ - if (skb->ip_summed == CHECKSUM_COMPLETE) - skb->csum = csum_block_sub(skb->csum, - csum_partial(start, len, 0), off); - else if (skb->ip_summed == CHECKSUM_PARTIAL && - skb_checksum_start_offset(skb) < 0) - skb->ip_summed = CHECKSUM_NONE; -} - -/** - * skb_postpull_rcsum - update checksum for received skb after pull - * @skb: buffer to update - * @start: start of data before pull - * @len: length of data pulled - * - * After doing a pull on a received packet, you need to call this to - * update the CHECKSUM_COMPLETE checksum, or set ip_summed to - * CHECKSUM_NONE so that it can be recomputed from scratch. - */ -static inline void skb_postpull_rcsum(struct sk_buff *skb, - const void *start, unsigned int len) -{ - __skb_postpull_rcsum(skb, start, len, 0); -} - -static __always_inline void -__skb_postpush_rcsum(struct sk_buff *skb, const void *start, unsigned int len, - unsigned int off) -{ - if (skb->ip_summed == CHECKSUM_COMPLETE) - skb->csum = csum_block_add(skb->csum, - csum_partial(start, len, 0), off); -} - -/** - * skb_postpush_rcsum - update checksum for received skb after push - * @skb: buffer to update - * @start: start of data after push - * @len: length of data pushed - * - * After doing a push on a received packet, you need to call this to - * update the CHECKSUM_COMPLETE checksum. - */ -static inline void skb_postpush_rcsum(struct sk_buff *skb, - const void *start, unsigned int len) -{ - __skb_postpush_rcsum(skb, start, len, 0); -} - -unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len); - -/** - * skb_push_rcsum - push skb and update receive checksum - * @skb: buffer to update - * @len: length of data pulled - * - * This function performs an skb_push on the packet and updates - * the CHECKSUM_COMPLETE checksum. It should be used on - * receive path processing instead of skb_push unless you know - * that the checksum difference is zero (e.g., a valid IP header) - * or you are setting ip_summed to CHECKSUM_NONE. - */ -static inline unsigned char *skb_push_rcsum(struct sk_buff *skb, - unsigned int len) -{ - skb_push(skb, len); - skb_postpush_rcsum(skb, skb->data, len); - return skb->data; -} - -/** - * pskb_trim_rcsum - trim received skb and update checksum - * @skb: buffer to trim - * @len: new length - * - * This is exactly the same as pskb_trim except that it ensures the - * checksum of received packets are still valid after the operation. - */ - -static inline int pskb_trim_rcsum(struct sk_buff *skb, unsigned int len) -{ - if (likely(len >= skb->len)) - return 0; - if (skb->ip_summed == CHECKSUM_COMPLETE) - skb->ip_summed = CHECKSUM_NONE; - return __pskb_trim(skb, len); -} - -static inline int __skb_trim_rcsum(struct sk_buff *skb, unsigned int len) -{ - if (skb->ip_summed == CHECKSUM_COMPLETE) - skb->ip_summed = CHECKSUM_NONE; - __skb_trim(skb, len); - return 0; -} - -static inline int __skb_grow_rcsum(struct sk_buff *skb, unsigned int len) -{ - if (skb->ip_summed == CHECKSUM_COMPLETE) - skb->ip_summed = CHECKSUM_NONE; - return __skb_grow(skb, len); -} - -#define skb_queue_walk(queue, skb) \ - for (skb = (queue)->next; \ - skb != (struct sk_buff *)(queue); \ - skb = skb->next) - -#define skb_queue_walk_safe(queue, skb, tmp) \ - for (skb = (queue)->next, tmp = skb->next; \ - skb != (struct sk_buff *)(queue); \ - skb = tmp, tmp = skb->next) - -#define skb_queue_walk_from(queue, skb) \ - for (; skb != (struct sk_buff *)(queue); \ - skb = skb->next) - -#define skb_queue_walk_from_safe(queue, skb, tmp) \ - for (tmp = skb->next; \ - skb != (struct sk_buff *)(queue); \ - skb = tmp, tmp = skb->next) - -#define skb_queue_reverse_walk(queue, skb) \ - for (skb = (queue)->prev; \ - skb != (struct sk_buff *)(queue); \ - skb = skb->prev) - -#define skb_queue_reverse_walk_safe(queue, skb, tmp) \ - for (skb = (queue)->prev, tmp = skb->prev; \ - skb != (struct sk_buff *)(queue); \ - skb = tmp, tmp = skb->prev) - -#define skb_queue_reverse_walk_from_safe(queue, skb, tmp) \ - for (tmp = skb->prev; \ - skb != (struct sk_buff *)(queue); \ - skb = tmp, tmp = skb->prev) - -static inline bool skb_has_frag_list(const struct sk_buff *skb) -{ - return skb_shinfo(skb)->frag_list != NULL; -} - -static inline void skb_frag_list_init(struct sk_buff *skb) -{ - skb_shinfo(skb)->frag_list = NULL; -} - -#define skb_walk_frags(skb, iter) \ - for (iter = skb_shinfo(skb)->frag_list; iter; iter = iter->next) - - -int __skb_wait_for_more_packets(struct sock *sk, int *err, long *timeo_p, - const struct sk_buff *skb); -struct sk_buff *__skb_try_recv_datagram(struct sock *sk, unsigned flags, - int *peeked, int *off, int *err, - struct sk_buff **last); -struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, - int *peeked, int *off, int *err); -struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, - int *err); -unsigned int datagram_poll(struct file *file, struct socket *sock, - struct poll_table_struct *wait); -int skb_copy_datagram_iter(const struct sk_buff *from, int offset, - struct iov_iter *to, int size); -static inline int skb_copy_datagram_msg(const struct sk_buff *from, int offset, - struct msghdr *msg, int size) -{ - return skb_copy_datagram_iter(from, offset, &msg->msg_iter, size); -} -int skb_copy_and_csum_datagram_msg(struct sk_buff *skb, int hlen, - struct msghdr *msg); -int skb_copy_datagram_from_iter(struct sk_buff *skb, int offset, - struct iov_iter *from, int len); -int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *frm); -void skb_free_datagram(struct sock *sk, struct sk_buff *skb); -void __skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb, int len); -static inline void skb_free_datagram_locked(struct sock *sk, - struct sk_buff *skb) -{ - __skb_free_datagram_locked(sk, skb, 0); -} -int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags); -int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len); -int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len); -__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, - int len, __wsum csum); -int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset, - struct pipe_inode_info *pipe, unsigned int len, - unsigned int flags); -void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to); -unsigned int skb_zerocopy_headlen(const struct sk_buff *from); -int skb_zerocopy(struct sk_buff *to, struct sk_buff *from, - int len, int hlen); -void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len); -int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen); -void skb_scrub_packet(struct sk_buff *skb, bool xnet); -unsigned int skb_gso_transport_seglen(const struct sk_buff *skb); -bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu); -struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features); -struct sk_buff *skb_vlan_untag(struct sk_buff *skb); -int skb_ensure_writable(struct sk_buff *skb, int write_len); -int __skb_vlan_pop(struct sk_buff *skb, u16 *vlan_tci); -int skb_vlan_pop(struct sk_buff *skb); -int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci); -struct sk_buff *pskb_extract(struct sk_buff *skb, int off, int to_copy, - gfp_t gfp); - -static inline int memcpy_from_msg(void *data, struct msghdr *msg, int len) -{ - return copy_from_iter(data, len, &msg->msg_iter) == len ? 0 : -EFAULT; -} - -static inline int memcpy_to_msg(struct msghdr *msg, void *data, int len) -{ - return copy_to_iter(data, len, &msg->msg_iter) == len ? 0 : -EFAULT; -} - -struct skb_checksum_ops { - __wsum (*update)(const void *mem, int len, __wsum wsum); - __wsum (*combine)(__wsum csum, __wsum csum2, int offset, int len); -}; - -__wsum __skb_checksum(const struct sk_buff *skb, int offset, int len, - __wsum csum, const struct skb_checksum_ops *ops); -__wsum skb_checksum(const struct sk_buff *skb, int offset, int len, - __wsum csum); - -static inline void * __must_check -__skb_header_pointer(const struct sk_buff *skb, int offset, - int len, void *data, int hlen, void *buffer) -{ - if (hlen - offset >= len) - return data + offset; - - if (!skb || - skb_copy_bits(skb, offset, buffer, len) < 0) - return NULL; - - return buffer; -} - -static inline void * __must_check -skb_header_pointer(const struct sk_buff *skb, int offset, int len, void *buffer) -{ - return __skb_header_pointer(skb, offset, len, skb->data, - skb_headlen(skb), buffer); -} - -/** - * skb_needs_linearize - check if we need to linearize a given skb - * depending on the given device features. - * @skb: socket buffer to check - * @features: net device features - * - * Returns true if either: - * 1. skb has frag_list and the device doesn't support FRAGLIST, or - * 2. skb is fragmented and the device does not support SG. - */ -static inline bool skb_needs_linearize(struct sk_buff *skb, - netdev_features_t features) -{ - return skb_is_nonlinear(skb) && - ((skb_has_frag_list(skb) && !(features & NETIF_F_FRAGLIST)) || - (skb_shinfo(skb)->nr_frags && !(features & NETIF_F_SG))); -} - -static inline void skb_copy_from_linear_data(const struct sk_buff *skb, - void *to, - const unsigned int len) -{ - memcpy(to, skb->data, len); -} - -static inline void skb_copy_from_linear_data_offset(const struct sk_buff *skb, - const int offset, void *to, - const unsigned int len) -{ - memcpy(to, skb->data + offset, len); -} - -static inline void skb_copy_to_linear_data(struct sk_buff *skb, - const void *from, - const unsigned int len) -{ - memcpy(skb->data, from, len); -} - -static inline void skb_copy_to_linear_data_offset(struct sk_buff *skb, - const int offset, - const void *from, - const unsigned int len) -{ - memcpy(skb->data + offset, from, len); -} - -void skb_init(void); - -static inline ktime_t skb_get_ktime(const struct sk_buff *skb) -{ - return skb->tstamp; -} - -/** - * skb_get_timestamp - get timestamp from a skb - * @skb: skb to get stamp from - * @stamp: pointer to struct timeval to store stamp in - * - * Timestamps are stored in the skb as offsets to a base timestamp. - * This function converts the offset back to a struct timeval and stores - * it in stamp. - */ -static inline void skb_get_timestamp(const struct sk_buff *skb, - struct timeval *stamp) -{ - *stamp = ktime_to_timeval(skb->tstamp); -} - -static inline void skb_get_timestampns(const struct sk_buff *skb, - struct timespec *stamp) -{ - *stamp = ktime_to_timespec(skb->tstamp); -} - -static inline void __net_timestamp(struct sk_buff *skb) -{ - skb->tstamp = ktime_get_real(); -} - -static inline ktime_t net_timedelta(ktime_t t) -{ - return ktime_sub(ktime_get_real(), t); -} - -static inline ktime_t net_invalid_timestamp(void) -{ - return ktime_set(0, 0); -} - -struct sk_buff *skb_clone_sk(struct sk_buff *skb); - -#ifdef CONFIG_NETWORK_PHY_TIMESTAMPING - -void skb_clone_tx_timestamp(struct sk_buff *skb); -bool skb_defer_rx_timestamp(struct sk_buff *skb); - -#else /* CONFIG_NETWORK_PHY_TIMESTAMPING */ - -static inline void skb_clone_tx_timestamp(struct sk_buff *skb) -{ -} - -static inline bool skb_defer_rx_timestamp(struct sk_buff *skb) -{ - return false; -} - -#endif /* !CONFIG_NETWORK_PHY_TIMESTAMPING */ - -/** - * skb_complete_tx_timestamp() - deliver cloned skb with tx timestamps - * - * PHY drivers may accept clones of transmitted packets for - * timestamping via their phy_driver.txtstamp method. These drivers - * must call this function to return the skb back to the stack with a - * timestamp. - * - * @skb: clone of the the original outgoing packet - * @hwtstamps: hardware time stamps - * - */ -void skb_complete_tx_timestamp(struct sk_buff *skb, - struct skb_shared_hwtstamps *hwtstamps); - -void __skb_tstamp_tx(struct sk_buff *orig_skb, - struct skb_shared_hwtstamps *hwtstamps, - struct sock *sk, int tstype); - -/** - * skb_tstamp_tx - queue clone of skb with send time stamps - * @orig_skb: the original outgoing packet - * @hwtstamps: hardware time stamps, may be NULL if not available - * - * If the skb has a socket associated, then this function clones the - * skb (thus sharing the actual data and optional structures), stores - * the optional hardware time stamping information (if non NULL) or - * generates a software time stamp (otherwise), then queues the clone - * to the error queue of the socket. Errors are silently ignored. - */ -void skb_tstamp_tx(struct sk_buff *orig_skb, - struct skb_shared_hwtstamps *hwtstamps); - -static inline void sw_tx_timestamp(struct sk_buff *skb) -{ - if (skb_shinfo(skb)->tx_flags & SKBTX_SW_TSTAMP && - !(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)) - skb_tstamp_tx(skb, NULL); -} - -/** - * skb_tx_timestamp() - Driver hook for transmit timestamping - * - * Ethernet MAC Drivers should call this function in their hard_xmit() - * function immediately before giving the sk_buff to the MAC hardware. - * - * Specifically, one should make absolutely sure that this function is - * called before TX completion of this packet can trigger. Otherwise - * the packet could potentially already be freed. - * - * @skb: A socket buffer. - */ -static inline void skb_tx_timestamp(struct sk_buff *skb) -{ - skb_clone_tx_timestamp(skb); - sw_tx_timestamp(skb); -} - -/** - * skb_complete_wifi_ack - deliver skb with wifi status - * - * @skb: the original outgoing packet - * @acked: ack status - * - */ -void skb_complete_wifi_ack(struct sk_buff *skb, bool acked); - -__sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len); -__sum16 __skb_checksum_complete(struct sk_buff *skb); - -static inline int skb_csum_unnecessary(const struct sk_buff *skb) -{ - return ((skb->ip_summed == CHECKSUM_UNNECESSARY) || - skb->csum_valid || - (skb->ip_summed == CHECKSUM_PARTIAL && - skb_checksum_start_offset(skb) >= 0)); -} - -/** - * skb_checksum_complete - Calculate checksum of an entire packet - * @skb: packet to process - * - * This function calculates the checksum over the entire packet plus - * the value of skb->csum. The latter can be used to supply the - * checksum of a pseudo header as used by TCP/UDP. It returns the - * checksum. - * - * For protocols that contain complete checksums such as ICMP/TCP/UDP, - * this function can be used to verify that checksum on received - * packets. In that case the function should return zero if the - * checksum is correct. In particular, this function will return zero - * if skb->ip_summed is CHECKSUM_UNNECESSARY which indicates that the - * hardware has already verified the correctness of the checksum. - */ -static inline __sum16 skb_checksum_complete(struct sk_buff *skb) -{ - return skb_csum_unnecessary(skb) ? - 0 : __skb_checksum_complete(skb); -} - -static inline void __skb_decr_checksum_unnecessary(struct sk_buff *skb) -{ - if (skb->ip_summed == CHECKSUM_UNNECESSARY) { - if (skb->csum_level == 0) - skb->ip_summed = CHECKSUM_NONE; - else - skb->csum_level--; - } -} - -static inline void __skb_incr_checksum_unnecessary(struct sk_buff *skb) -{ - if (skb->ip_summed == CHECKSUM_UNNECESSARY) { - if (skb->csum_level < SKB_MAX_CSUM_LEVEL) - skb->csum_level++; - } else if (skb->ip_summed == CHECKSUM_NONE) { - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->csum_level = 0; - } -} - -static inline void __skb_mark_checksum_bad(struct sk_buff *skb) -{ - /* Mark current checksum as bad (typically called from GRO - * path). In the case that ip_summed is CHECKSUM_NONE - * this must be the first checksum encountered in the packet. - * When ip_summed is CHECKSUM_UNNECESSARY, this is the first - * checksum after the last one validated. For UDP, a zero - * checksum can not be marked as bad. - */ - - if (skb->ip_summed == CHECKSUM_NONE || - skb->ip_summed == CHECKSUM_UNNECESSARY) - skb->csum_bad = 1; -} - -/* Check if we need to perform checksum complete validation. - * - * Returns true if checksum complete is needed, false otherwise - * (either checksum is unnecessary or zero checksum is allowed). - */ -static inline bool __skb_checksum_validate_needed(struct sk_buff *skb, - bool zero_okay, - __sum16 check) -{ - if (skb_csum_unnecessary(skb) || (zero_okay && !check)) { - skb->csum_valid = 1; - __skb_decr_checksum_unnecessary(skb); - return false; - } - - return true; -} - -/* For small packets <= CHECKSUM_BREAK peform checksum complete directly - * in checksum_init. - */ -#define CHECKSUM_BREAK 76 - -/* Unset checksum-complete - * - * Unset checksum complete can be done when packet is being modified - * (uncompressed for instance) and checksum-complete value is - * invalidated. - */ -static inline void skb_checksum_complete_unset(struct sk_buff *skb) -{ - if (skb->ip_summed == CHECKSUM_COMPLETE) - skb->ip_summed = CHECKSUM_NONE; -} - -/* Validate (init) checksum based on checksum complete. - * - * Return values: - * 0: checksum is validated or try to in skb_checksum_complete. In the latter - * case the ip_summed will not be CHECKSUM_UNNECESSARY and the pseudo - * checksum is stored in skb->csum for use in __skb_checksum_complete - * non-zero: value of invalid checksum - * - */ -static inline __sum16 __skb_checksum_validate_complete(struct sk_buff *skb, - bool complete, - __wsum psum) -{ - if (skb->ip_summed == CHECKSUM_COMPLETE) { - if (!csum_fold(csum_add(psum, skb->csum))) { - skb->csum_valid = 1; - return 0; - } - } else if (skb->csum_bad) { - /* ip_summed == CHECKSUM_NONE in this case */ - return (__force __sum16)1; - } - - skb->csum = psum; - - if (complete || skb->len <= CHECKSUM_BREAK) { - __sum16 csum; - - csum = __skb_checksum_complete(skb); - skb->csum_valid = !csum; - return csum; - } - - return 0; -} - -static inline __wsum null_compute_pseudo(struct sk_buff *skb, int proto) -{ - return 0; -} - -/* Perform checksum validate (init). Note that this is a macro since we only - * want to calculate the pseudo header which is an input function if necessary. - * First we try to validate without any computation (checksum unnecessary) and - * then calculate based on checksum complete calling the function to compute - * pseudo header. - * - * Return values: - * 0: checksum is validated or try to in skb_checksum_complete - * non-zero: value of invalid checksum - */ -#define __skb_checksum_validate(skb, proto, complete, \ - zero_okay, check, compute_pseudo) \ -({ \ - __sum16 __ret = 0; \ - skb->csum_valid = 0; \ - if (__skb_checksum_validate_needed(skb, zero_okay, check)) \ - __ret = __skb_checksum_validate_complete(skb, \ - complete, compute_pseudo(skb, proto)); \ - __ret; \ -}) - -#define skb_checksum_init(skb, proto, compute_pseudo) \ - __skb_checksum_validate(skb, proto, false, false, 0, compute_pseudo) - -#define skb_checksum_init_zero_check(skb, proto, check, compute_pseudo) \ - __skb_checksum_validate(skb, proto, false, true, check, compute_pseudo) - -#define skb_checksum_validate(skb, proto, compute_pseudo) \ - __skb_checksum_validate(skb, proto, true, false, 0, compute_pseudo) - -#define skb_checksum_validate_zero_check(skb, proto, check, \ - compute_pseudo) \ - __skb_checksum_validate(skb, proto, true, true, check, compute_pseudo) - -#define skb_checksum_simple_validate(skb) \ - __skb_checksum_validate(skb, 0, true, false, 0, null_compute_pseudo) - -static inline bool __skb_checksum_convert_check(struct sk_buff *skb) -{ - return (skb->ip_summed == CHECKSUM_NONE && - skb->csum_valid && !skb->csum_bad); -} - -static inline void __skb_checksum_convert(struct sk_buff *skb, - __sum16 check, __wsum pseudo) -{ - skb->csum = ~pseudo; - skb->ip_summed = CHECKSUM_COMPLETE; -} - -#define skb_checksum_try_convert(skb, proto, check, compute_pseudo) \ -do { \ - if (__skb_checksum_convert_check(skb)) \ - __skb_checksum_convert(skb, check, \ - compute_pseudo(skb, proto)); \ -} while (0) - -static inline void skb_remcsum_adjust_partial(struct sk_buff *skb, void *ptr, - u16 start, u16 offset) -{ - skb->ip_summed = CHECKSUM_PARTIAL; - skb->csum_start = ((unsigned char *)ptr + start) - skb->head; - skb->csum_offset = offset - start; -} - -/* Update skbuf and packet to reflect the remote checksum offload operation. - * When called, ptr indicates the starting point for skb->csum when - * ip_summed is CHECKSUM_COMPLETE. If we need create checksum complete - * here, skb_postpull_rcsum is done so skb->csum start is ptr. - */ -static inline void skb_remcsum_process(struct sk_buff *skb, void *ptr, - int start, int offset, bool nopartial) -{ - __wsum delta; - - if (!nopartial) { - skb_remcsum_adjust_partial(skb, ptr, start, offset); - return; - } - - if (unlikely(skb->ip_summed != CHECKSUM_COMPLETE)) { - __skb_checksum_complete(skb); - skb_postpull_rcsum(skb, skb->data, ptr - (void *)skb->data); - } - - delta = remcsum_adjust(ptr, skb->csum, start, offset); - - /* Adjust skb->csum since we changed the packet */ - skb->csum = csum_add(skb->csum, delta); -} - -#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) -void nf_conntrack_destroy(struct nf_conntrack *nfct); -static inline void nf_conntrack_put(struct nf_conntrack *nfct) -{ - if (nfct && atomic_dec_and_test(&nfct->use)) - nf_conntrack_destroy(nfct); -} -static inline void nf_conntrack_get(struct nf_conntrack *nfct) -{ - if (nfct) - atomic_inc(&nfct->use); -} -#endif -#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) -static inline void nf_bridge_put(struct nf_bridge_info *nf_bridge) -{ - if (nf_bridge && atomic_dec_and_test(&nf_bridge->use)) - kfree(nf_bridge); -} -static inline void nf_bridge_get(struct nf_bridge_info *nf_bridge) -{ - if (nf_bridge) - atomic_inc(&nf_bridge->use); -} -#endif /* CONFIG_BRIDGE_NETFILTER */ -static inline void nf_reset(struct sk_buff *skb) -{ -#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) - nf_conntrack_put(skb->nfct); - skb->nfct = NULL; -#endif -#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) - nf_bridge_put(skb->nf_bridge); - skb->nf_bridge = NULL; -#endif -} - -static inline void nf_reset_trace(struct sk_buff *skb) -{ -#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || defined(CONFIG_NF_TABLES) - skb->nf_trace = 0; -#endif -} - -/* Note: This doesn't put any conntrack and bridge info in dst. */ -static inline void __nf_copy(struct sk_buff *dst, const struct sk_buff *src, - bool copy) -{ -#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) - dst->nfct = src->nfct; - nf_conntrack_get(src->nfct); - if (copy) - dst->nfctinfo = src->nfctinfo; -#endif -#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) - dst->nf_bridge = src->nf_bridge; - nf_bridge_get(src->nf_bridge); -#endif -#if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || defined(CONFIG_NF_TABLES) - if (copy) - dst->nf_trace = src->nf_trace; -#endif -} - -static inline void nf_copy(struct sk_buff *dst, const struct sk_buff *src) -{ -#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) - nf_conntrack_put(dst->nfct); -#endif -#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) - nf_bridge_put(dst->nf_bridge); -#endif - __nf_copy(dst, src, true); -} - -#ifdef CONFIG_NETWORK_SECMARK -static inline void skb_copy_secmark(struct sk_buff *to, const struct sk_buff *from) -{ - to->secmark = from->secmark; -} - -static inline void skb_init_secmark(struct sk_buff *skb) -{ - skb->secmark = 0; -} -#else -static inline void skb_copy_secmark(struct sk_buff *to, const struct sk_buff *from) -{ } - -static inline void skb_init_secmark(struct sk_buff *skb) -{ } -#endif - -static inline bool skb_irq_freeable(const struct sk_buff *skb) -{ - return !skb->destructor && -#if IS_ENABLED(CONFIG_XFRM) - !skb->sp && -#endif -#if IS_ENABLED(CONFIG_NF_CONNTRACK) - !skb->nfct && -#endif - !skb->_skb_refdst && - !skb_has_frag_list(skb); -} - -static inline void skb_set_queue_mapping(struct sk_buff *skb, u16 queue_mapping) -{ - skb->queue_mapping = queue_mapping; -} - -static inline u16 skb_get_queue_mapping(const struct sk_buff *skb) -{ - return skb->queue_mapping; -} - -static inline void skb_copy_queue_mapping(struct sk_buff *to, const struct sk_buff *from) -{ - to->queue_mapping = from->queue_mapping; -} - -static inline void skb_record_rx_queue(struct sk_buff *skb, u16 rx_queue) -{ - skb->queue_mapping = rx_queue + 1; -} - -static inline u16 skb_get_rx_queue(const struct sk_buff *skb) -{ - return skb->queue_mapping - 1; -} - -static inline bool skb_rx_queue_recorded(const struct sk_buff *skb) -{ - return skb->queue_mapping != 0; -} - -static inline struct sec_path *skb_sec_path(struct sk_buff *skb) -{ -#ifdef CONFIG_XFRM - return skb->sp; -#else - return NULL; -#endif -} - -/* Keeps track of mac header offset relative to skb->head. - * It is useful for TSO of Tunneling protocol. e.g. GRE. - * For non-tunnel skb it points to skb_mac_header() and for - * tunnel skb it points to outer mac header. - * Keeps track of level of encapsulation of network headers. - */ -struct skb_gso_cb { - union { - int mac_offset; - int data_offset; - }; - int encap_level; - __wsum csum; - __u16 csum_start; -}; -#define SKB_SGO_CB_OFFSET 32 -#define SKB_GSO_CB(skb) ((struct skb_gso_cb *)((skb)->cb + SKB_SGO_CB_OFFSET)) - -static inline int skb_tnl_header_len(const struct sk_buff *inner_skb) -{ - return (skb_mac_header(inner_skb) - inner_skb->head) - - SKB_GSO_CB(inner_skb)->mac_offset; -} - -static inline int gso_pskb_expand_head(struct sk_buff *skb, int extra) -{ - int new_headroom, headroom; - int ret; - - headroom = skb_headroom(skb); - ret = pskb_expand_head(skb, extra, 0, GFP_ATOMIC); - if (ret) - return ret; - - new_headroom = skb_headroom(skb); - SKB_GSO_CB(skb)->mac_offset += (new_headroom - headroom); - return 0; -} - -static inline void gso_reset_checksum(struct sk_buff *skb, __wsum res) -{ - /* Do not update partial checksums if remote checksum is enabled. */ - if (skb->remcsum_offload) - return; - - SKB_GSO_CB(skb)->csum = res; - SKB_GSO_CB(skb)->csum_start = skb_checksum_start(skb) - skb->head; -} - -/* Compute the checksum for a gso segment. First compute the checksum value - * from the start of transport header to SKB_GSO_CB(skb)->csum_start, and - * then add in skb->csum (checksum from csum_start to end of packet). - * skb->csum and csum_start are then updated to reflect the checksum of the - * resultant packet starting from the transport header-- the resultant checksum - * is in the res argument (i.e. normally zero or ~ of checksum of a pseudo - * header. - */ -static inline __sum16 gso_make_checksum(struct sk_buff *skb, __wsum res) -{ - unsigned char *csum_start = skb_transport_header(skb); - int plen = (skb->head + SKB_GSO_CB(skb)->csum_start) - csum_start; - __wsum partial = SKB_GSO_CB(skb)->csum; - - SKB_GSO_CB(skb)->csum = res; - SKB_GSO_CB(skb)->csum_start = csum_start - skb->head; - - return csum_fold(csum_partial(csum_start, plen, partial)); -} - -static inline bool skb_is_gso(const struct sk_buff *skb) -{ - return skb_shinfo(skb)->gso_size; -} - -/* Note: Should be called only if skb_is_gso(skb) is true */ -static inline bool skb_is_gso_v6(const struct sk_buff *skb) -{ - return skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6; -} - -static inline void skb_gso_reset(struct sk_buff *skb) -{ - skb_shinfo(skb)->gso_size = 0; - skb_shinfo(skb)->gso_segs = 0; - skb_shinfo(skb)->gso_type = 0; -} - -void __skb_warn_lro_forwarding(const struct sk_buff *skb); - -static inline bool skb_warn_if_lro(const struct sk_buff *skb) -{ - /* LRO sets gso_size but not gso_type, whereas if GSO is really - * wanted then gso_type will be set. */ - const struct skb_shared_info *shinfo = skb_shinfo(skb); - - if (skb_is_nonlinear(skb) && shinfo->gso_size != 0 && - unlikely(shinfo->gso_type == 0)) { - __skb_warn_lro_forwarding(skb); - return true; - } - return false; -} - -static inline void skb_forward_csum(struct sk_buff *skb) -{ - /* Unfortunately we don't support this one. Any brave souls? */ - if (skb->ip_summed == CHECKSUM_COMPLETE) - skb->ip_summed = CHECKSUM_NONE; -} - -/** - * skb_checksum_none_assert - make sure skb ip_summed is CHECKSUM_NONE - * @skb: skb to check - * - * fresh skbs have their ip_summed set to CHECKSUM_NONE. - * Instead of forcing ip_summed to CHECKSUM_NONE, we can - * use this helper, to document places where we make this assertion. - */ -static inline void skb_checksum_none_assert(const struct sk_buff *skb) -{ -#ifdef DEBUG - BUG_ON(skb->ip_summed != CHECKSUM_NONE); -#endif -} - -bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off); - -int skb_checksum_setup(struct sk_buff *skb, bool recalculate); -struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb, - unsigned int transport_len, - __sum16(*skb_chkf)(struct sk_buff *skb)); - -/** - * skb_head_is_locked - Determine if the skb->head is locked down - * @skb: skb to check - * - * The head on skbs build around a head frag can be removed if they are - * not cloned. This function returns true if the skb head is locked down - * due to either being allocated via kmalloc, or by being a clone with - * multiple references to the head. - */ -static inline bool skb_head_is_locked(const struct sk_buff *skb) -{ - return !skb->head_frag || skb_cloned(skb); -} - -/** - * skb_gso_network_seglen - Return length of individual segments of a gso packet - * - * @skb: GSO skb - * - * skb_gso_network_seglen is used to determine the real size of the - * individual segments, including Layer3 (IP, IPv6) and L4 headers (TCP/UDP). - * - * The MAC/L2 header is not accounted for. - */ -static inline unsigned int skb_gso_network_seglen(const struct sk_buff *skb) -{ - unsigned int hdr_len = skb_transport_header(skb) - - skb_network_header(skb); - return hdr_len + skb_gso_transport_seglen(skb); -} - -/* Local Checksum Offload. - * Compute outer checksum based on the assumption that the - * inner checksum will be offloaded later. - * See Documentation/networking/checksum-offloads.txt for - * explanation of how this works. - * Fill in outer checksum adjustment (e.g. with sum of outer - * pseudo-header) before calling. - * Also ensure that inner checksum is in linear data area. - */ -static inline __wsum lco_csum(struct sk_buff *skb) -{ - unsigned char *csum_start = skb_checksum_start(skb); - unsigned char *l4_hdr = skb_transport_header(skb); - __wsum partial; - - /* Start with complement of inner checksum adjustment */ - partial = ~csum_unfold(*(__force __sum16 *)(csum_start + - skb->csum_offset)); - - /* Add in checksum of our headers (incl. outer checksum - * adjustment filled in by caller) and return result. - */ - return csum_partial(l4_hdr, csum_start - l4_hdr, partial); -} - -#endif /* __KERNEL__ */ -#endif /* _LINUX_SKBUFF_H */ diff --git a/src/linux/include/linux/slab.h b/src/linux/include/linux/slab.h deleted file mode 100644 index 084b12b..0000000 --- a/src/linux/include/linux/slab.h +++ /dev/null @@ -1,661 +0,0 @@ -/* - * Written by Mark Hemment, 1996 (markhe@nextd.demon.co.uk). - * - * (C) SGI 2006, Christoph Lameter - * Cleaned up and restructured to ease the addition of alternative - * implementations of SLAB allocators. - * (C) Linux Foundation 2008-2013 - * Unified interface for all slab allocators - */ - -#ifndef _LINUX_SLAB_H -#define _LINUX_SLAB_H - -#include -#include -#include - - -/* - * Flags to pass to kmem_cache_create(). - * The ones marked DEBUG are only valid if CONFIG_DEBUG_SLAB is set. - */ -#define SLAB_CONSISTENCY_CHECKS 0x00000100UL /* DEBUG: Perform (expensive) checks on alloc/free */ -#define SLAB_RED_ZONE 0x00000400UL /* DEBUG: Red zone objs in a cache */ -#define SLAB_POISON 0x00000800UL /* DEBUG: Poison objects */ -#define SLAB_HWCACHE_ALIGN 0x00002000UL /* Align objs on cache lines */ -#define SLAB_CACHE_DMA 0x00004000UL /* Use GFP_DMA memory */ -#define SLAB_STORE_USER 0x00010000UL /* DEBUG: Store the last owner for bug hunting */ -#define SLAB_PANIC 0x00040000UL /* Panic if kmem_cache_create() fails */ -/* - * SLAB_DESTROY_BY_RCU - **WARNING** READ THIS! - * - * This delays freeing the SLAB page by a grace period, it does _NOT_ - * delay object freeing. This means that if you do kmem_cache_free() - * that memory location is free to be reused at any time. Thus it may - * be possible to see another object there in the same RCU grace period. - * - * This feature only ensures the memory location backing the object - * stays valid, the trick to using this is relying on an independent - * object validation pass. Something like: - * - * rcu_read_lock() - * again: - * obj = lockless_lookup(key); - * if (obj) { - * if (!try_get_ref(obj)) // might fail for free objects - * goto again; - * - * if (obj->key != key) { // not the object we expected - * put_ref(obj); - * goto again; - * } - * } - * rcu_read_unlock(); - * - * This is useful if we need to approach a kernel structure obliquely, - * from its address obtained without the usual locking. We can lock - * the structure to stabilize it and check it's still at the given address, - * only if we can be sure that the memory has not been meanwhile reused - * for some other kind of object (which our subsystem's lock might corrupt). - * - * rcu_read_lock before reading the address, then rcu_read_unlock after - * taking the spinlock within the structure expected at that address. - */ -#define SLAB_DESTROY_BY_RCU 0x00080000UL /* Defer freeing slabs to RCU */ -#define SLAB_MEM_SPREAD 0x00100000UL /* Spread some memory over cpuset */ -#define SLAB_TRACE 0x00200000UL /* Trace allocations and frees */ - -/* Flag to prevent checks on free */ -#ifdef CONFIG_DEBUG_OBJECTS -# define SLAB_DEBUG_OBJECTS 0x00400000UL -#else -# define SLAB_DEBUG_OBJECTS 0x00000000UL -#endif - -#define SLAB_NOLEAKTRACE 0x00800000UL /* Avoid kmemleak tracing */ - -/* Don't track use of uninitialized memory */ -#ifdef CONFIG_KMEMCHECK -# define SLAB_NOTRACK 0x01000000UL -#else -# define SLAB_NOTRACK 0x00000000UL -#endif -#ifdef CONFIG_FAILSLAB -# define SLAB_FAILSLAB 0x02000000UL /* Fault injection mark */ -#else -# define SLAB_FAILSLAB 0x00000000UL -#endif -#if defined(CONFIG_MEMCG) && !defined(CONFIG_SLOB) -# define SLAB_ACCOUNT 0x04000000UL /* Account to memcg */ -#else -# define SLAB_ACCOUNT 0x00000000UL -#endif - -#ifdef CONFIG_KASAN -#define SLAB_KASAN 0x08000000UL -#else -#define SLAB_KASAN 0x00000000UL -#endif - -/* The following flags affect the page allocator grouping pages by mobility */ -#define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */ -#define SLAB_TEMPORARY SLAB_RECLAIM_ACCOUNT /* Objects are short-lived */ -/* - * ZERO_SIZE_PTR will be returned for zero sized kmalloc requests. - * - * Dereferencing ZERO_SIZE_PTR will lead to a distinct access fault. - * - * ZERO_SIZE_PTR can be passed to kfree though in the same way that NULL can. - * Both make kfree a no-op. - */ -#define ZERO_SIZE_PTR ((void *)16) - -#define ZERO_OR_NULL_PTR(x) ((unsigned long)(x) <= \ - (unsigned long)ZERO_SIZE_PTR) - -#include -#include - -struct mem_cgroup; -/* - * struct kmem_cache related prototypes - */ -void __init kmem_cache_init(void); -bool slab_is_available(void); - -struct kmem_cache *kmem_cache_create(const char *, size_t, size_t, - unsigned long, - void (*)(void *)); -void kmem_cache_destroy(struct kmem_cache *); -int kmem_cache_shrink(struct kmem_cache *); - -void memcg_create_kmem_cache(struct mem_cgroup *, struct kmem_cache *); -void memcg_deactivate_kmem_caches(struct mem_cgroup *); -void memcg_destroy_kmem_caches(struct mem_cgroup *); - -/* - * Please use this macro to create slab caches. Simply specify the - * name of the structure and maybe some flags that are listed above. - * - * The alignment of the struct determines object alignment. If you - * f.e. add ____cacheline_aligned_in_smp to the struct declaration - * then the objects will be properly aligned in SMP configurations. - */ -#define KMEM_CACHE(__struct, __flags) kmem_cache_create(#__struct,\ - sizeof(struct __struct), __alignof__(struct __struct),\ - (__flags), NULL) - -/* - * Common kmalloc functions provided by all allocators - */ -void * __must_check __krealloc(const void *, size_t, gfp_t); -void * __must_check krealloc(const void *, size_t, gfp_t); -void kfree(const void *); -void kzfree(const void *); -size_t ksize(const void *); - -#ifdef CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR -const char *__check_heap_object(const void *ptr, unsigned long n, - struct page *page); -#else -static inline const char *__check_heap_object(const void *ptr, - unsigned long n, - struct page *page) -{ - return NULL; -} -#endif - -/* - * Some archs want to perform DMA into kmalloc caches and need a guaranteed - * alignment larger than the alignment of a 64-bit integer. - * Setting ARCH_KMALLOC_MINALIGN in arch headers allows that. - */ -#if defined(ARCH_DMA_MINALIGN) && ARCH_DMA_MINALIGN > 8 -#define ARCH_KMALLOC_MINALIGN ARCH_DMA_MINALIGN -#define KMALLOC_MIN_SIZE ARCH_DMA_MINALIGN -#define KMALLOC_SHIFT_LOW ilog2(ARCH_DMA_MINALIGN) -#else -#define ARCH_KMALLOC_MINALIGN __alignof__(unsigned long long) -#endif - -/* - * Setting ARCH_SLAB_MINALIGN in arch headers allows a different alignment. - * Intended for arches that get misalignment faults even for 64 bit integer - * aligned buffers. - */ -#ifndef ARCH_SLAB_MINALIGN -#define ARCH_SLAB_MINALIGN __alignof__(unsigned long long) -#endif - -/* - * kmalloc and friends return ARCH_KMALLOC_MINALIGN aligned - * pointers. kmem_cache_alloc and friends return ARCH_SLAB_MINALIGN - * aligned pointers. - */ -#define __assume_kmalloc_alignment __assume_aligned(ARCH_KMALLOC_MINALIGN) -#define __assume_slab_alignment __assume_aligned(ARCH_SLAB_MINALIGN) -#define __assume_page_alignment __assume_aligned(PAGE_SIZE) - -/* - * Kmalloc array related definitions - */ - -#ifdef CONFIG_SLAB -/* - * The largest kmalloc size supported by the SLAB allocators is - * 32 megabyte (2^25) or the maximum allocatable page order if that is - * less than 32 MB. - * - * WARNING: Its not easy to increase this value since the allocators have - * to do various tricks to work around compiler limitations in order to - * ensure proper constant folding. - */ -#define KMALLOC_SHIFT_HIGH ((MAX_ORDER + PAGE_SHIFT - 1) <= 25 ? \ - (MAX_ORDER + PAGE_SHIFT - 1) : 25) -#define KMALLOC_SHIFT_MAX KMALLOC_SHIFT_HIGH -#ifndef KMALLOC_SHIFT_LOW -#define KMALLOC_SHIFT_LOW 5 -#endif -#endif - -#ifdef CONFIG_SLUB -/* - * SLUB directly allocates requests fitting in to an order-1 page - * (PAGE_SIZE*2). Larger requests are passed to the page allocator. - */ -#define KMALLOC_SHIFT_HIGH (PAGE_SHIFT + 1) -#define KMALLOC_SHIFT_MAX (MAX_ORDER + PAGE_SHIFT) -#ifndef KMALLOC_SHIFT_LOW -#define KMALLOC_SHIFT_LOW 3 -#endif -#endif - -#ifdef CONFIG_SLOB -/* - * SLOB passes all requests larger than one page to the page allocator. - * No kmalloc array is necessary since objects of different sizes can - * be allocated from the same page. - */ -#define KMALLOC_SHIFT_HIGH PAGE_SHIFT -#define KMALLOC_SHIFT_MAX 30 -#ifndef KMALLOC_SHIFT_LOW -#define KMALLOC_SHIFT_LOW 3 -#endif -#endif - -/* Maximum allocatable size */ -#define KMALLOC_MAX_SIZE (1UL << KMALLOC_SHIFT_MAX) -/* Maximum size for which we actually use a slab cache */ -#define KMALLOC_MAX_CACHE_SIZE (1UL << KMALLOC_SHIFT_HIGH) -/* Maximum order allocatable via the slab allocagtor */ -#define KMALLOC_MAX_ORDER (KMALLOC_SHIFT_MAX - PAGE_SHIFT) - -/* - * Kmalloc subsystem. - */ -#ifndef KMALLOC_MIN_SIZE -#define KMALLOC_MIN_SIZE (1 << KMALLOC_SHIFT_LOW) -#endif - -/* - * This restriction comes from byte sized index implementation. - * Page size is normally 2^12 bytes and, in this case, if we want to use - * byte sized index which can represent 2^8 entries, the size of the object - * should be equal or greater to 2^12 / 2^8 = 2^4 = 16. - * If minimum size of kmalloc is less than 16, we use it as minimum object - * size and give up to use byte sized index. - */ -#define SLAB_OBJ_MIN_SIZE (KMALLOC_MIN_SIZE < 16 ? \ - (KMALLOC_MIN_SIZE) : 16) - -#ifndef CONFIG_SLOB -extern struct kmem_cache *kmalloc_caches[KMALLOC_SHIFT_HIGH + 1]; -#ifdef CONFIG_ZONE_DMA -extern struct kmem_cache *kmalloc_dma_caches[KMALLOC_SHIFT_HIGH + 1]; -#endif - -/* - * Figure out which kmalloc slab an allocation of a certain size - * belongs to. - * 0 = zero alloc - * 1 = 65 .. 96 bytes - * 2 = 129 .. 192 bytes - * n = 2^(n-1)+1 .. 2^n - */ -static __always_inline int kmalloc_index(size_t size) -{ - if (!size) - return 0; - - if (size <= KMALLOC_MIN_SIZE) - return KMALLOC_SHIFT_LOW; - - if (KMALLOC_MIN_SIZE <= 32 && size > 64 && size <= 96) - return 1; - if (KMALLOC_MIN_SIZE <= 64 && size > 128 && size <= 192) - return 2; - if (size <= 8) return 3; - if (size <= 16) return 4; - if (size <= 32) return 5; - if (size <= 64) return 6; - if (size <= 128) return 7; - if (size <= 256) return 8; - if (size <= 512) return 9; - if (size <= 1024) return 10; - if (size <= 2 * 1024) return 11; - if (size <= 4 * 1024) return 12; - if (size <= 8 * 1024) return 13; - if (size <= 16 * 1024) return 14; - if (size <= 32 * 1024) return 15; - if (size <= 64 * 1024) return 16; - if (size <= 128 * 1024) return 17; - if (size <= 256 * 1024) return 18; - if (size <= 512 * 1024) return 19; - if (size <= 1024 * 1024) return 20; - if (size <= 2 * 1024 * 1024) return 21; - if (size <= 4 * 1024 * 1024) return 22; - if (size <= 8 * 1024 * 1024) return 23; - if (size <= 16 * 1024 * 1024) return 24; - if (size <= 32 * 1024 * 1024) return 25; - if (size <= 64 * 1024 * 1024) return 26; - BUG(); - - /* Will never be reached. Needed because the compiler may complain */ - return -1; -} -#endif /* !CONFIG_SLOB */ - -void *__kmalloc(size_t size, gfp_t flags) __assume_kmalloc_alignment __malloc; -void *kmem_cache_alloc(struct kmem_cache *, gfp_t flags) __assume_slab_alignment __malloc; -void kmem_cache_free(struct kmem_cache *, void *); - -/* - * Bulk allocation and freeing operations. These are accelerated in an - * allocator specific way to avoid taking locks repeatedly or building - * metadata structures unnecessarily. - * - * Note that interrupts must be enabled when calling these functions. - */ -void kmem_cache_free_bulk(struct kmem_cache *, size_t, void **); -int kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **); - -/* - * Caller must not use kfree_bulk() on memory not originally allocated - * by kmalloc(), because the SLOB allocator cannot handle this. - */ -static __always_inline void kfree_bulk(size_t size, void **p) -{ - kmem_cache_free_bulk(NULL, size, p); -} - -#ifdef CONFIG_NUMA -void *__kmalloc_node(size_t size, gfp_t flags, int node) __assume_kmalloc_alignment __malloc; -void *kmem_cache_alloc_node(struct kmem_cache *, gfp_t flags, int node) __assume_slab_alignment __malloc; -#else -static __always_inline void *__kmalloc_node(size_t size, gfp_t flags, int node) -{ - return __kmalloc(size, flags); -} - -static __always_inline void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t flags, int node) -{ - return kmem_cache_alloc(s, flags); -} -#endif - -#ifdef CONFIG_TRACING -extern void *kmem_cache_alloc_trace(struct kmem_cache *, gfp_t, size_t) __assume_slab_alignment __malloc; - -#ifdef CONFIG_NUMA -extern void *kmem_cache_alloc_node_trace(struct kmem_cache *s, - gfp_t gfpflags, - int node, size_t size) __assume_slab_alignment __malloc; -#else -static __always_inline void * -kmem_cache_alloc_node_trace(struct kmem_cache *s, - gfp_t gfpflags, - int node, size_t size) -{ - return kmem_cache_alloc_trace(s, gfpflags, size); -} -#endif /* CONFIG_NUMA */ - -#else /* CONFIG_TRACING */ -static __always_inline void *kmem_cache_alloc_trace(struct kmem_cache *s, - gfp_t flags, size_t size) -{ - void *ret = kmem_cache_alloc(s, flags); - - kasan_kmalloc(s, ret, size, flags); - return ret; -} - -static __always_inline void * -kmem_cache_alloc_node_trace(struct kmem_cache *s, - gfp_t gfpflags, - int node, size_t size) -{ - void *ret = kmem_cache_alloc_node(s, gfpflags, node); - - kasan_kmalloc(s, ret, size, gfpflags); - return ret; -} -#endif /* CONFIG_TRACING */ - -extern void *kmalloc_order(size_t size, gfp_t flags, unsigned int order) __assume_page_alignment __malloc; - -#ifdef CONFIG_TRACING -extern void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order) __assume_page_alignment __malloc; -#else -static __always_inline void * -kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order) -{ - return kmalloc_order(size, flags, order); -} -#endif - -static __always_inline void *kmalloc_large(size_t size, gfp_t flags) -{ - unsigned int order = get_order(size); - return kmalloc_order_trace(size, flags, order); -} - -/** - * kmalloc - allocate memory - * @size: how many bytes of memory are required. - * @flags: the type of memory to allocate. - * - * kmalloc is the normal method of allocating memory - * for objects smaller than page size in the kernel. - * - * The @flags argument may be one of: - * - * %GFP_USER - Allocate memory on behalf of user. May sleep. - * - * %GFP_KERNEL - Allocate normal kernel ram. May sleep. - * - * %GFP_ATOMIC - Allocation will not sleep. May use emergency pools. - * For example, use this inside interrupt handlers. - * - * %GFP_HIGHUSER - Allocate pages from high memory. - * - * %GFP_NOIO - Do not do any I/O at all while trying to get memory. - * - * %GFP_NOFS - Do not make any fs calls while trying to get memory. - * - * %GFP_NOWAIT - Allocation will not sleep. - * - * %__GFP_THISNODE - Allocate node-local memory only. - * - * %GFP_DMA - Allocation suitable for DMA. - * Should only be used for kmalloc() caches. Otherwise, use a - * slab created with SLAB_DMA. - * - * Also it is possible to set different flags by OR'ing - * in one or more of the following additional @flags: - * - * %__GFP_COLD - Request cache-cold pages instead of - * trying to return cache-warm pages. - * - * %__GFP_HIGH - This allocation has high priority and may use emergency pools. - * - * %__GFP_NOFAIL - Indicate that this allocation is in no way allowed to fail - * (think twice before using). - * - * %__GFP_NORETRY - If memory is not immediately available, - * then give up at once. - * - * %__GFP_NOWARN - If allocation fails, don't issue any warnings. - * - * %__GFP_REPEAT - If allocation fails initially, try once more before failing. - * - * There are other flags available as well, but these are not intended - * for general use, and so are not documented here. For a full list of - * potential flags, always refer to linux/gfp.h. - */ -static __always_inline void *kmalloc(size_t size, gfp_t flags) -{ - if (__builtin_constant_p(size)) { - if (size > KMALLOC_MAX_CACHE_SIZE) - return kmalloc_large(size, flags); -#ifndef CONFIG_SLOB - if (!(flags & GFP_DMA)) { - int index = kmalloc_index(size); - - if (!index) - return ZERO_SIZE_PTR; - - return kmem_cache_alloc_trace(kmalloc_caches[index], - flags, size); - } -#endif - } - return __kmalloc(size, flags); -} - -/* - * Determine size used for the nth kmalloc cache. - * return size or 0 if a kmalloc cache for that - * size does not exist - */ -static __always_inline int kmalloc_size(int n) -{ -#ifndef CONFIG_SLOB - if (n > 2) - return 1 << n; - - if (n == 1 && KMALLOC_MIN_SIZE <= 32) - return 96; - - if (n == 2 && KMALLOC_MIN_SIZE <= 64) - return 192; -#endif - return 0; -} - -static __always_inline void *kmalloc_node(size_t size, gfp_t flags, int node) -{ -#ifndef CONFIG_SLOB - if (__builtin_constant_p(size) && - size <= KMALLOC_MAX_CACHE_SIZE && !(flags & GFP_DMA)) { - int i = kmalloc_index(size); - - if (!i) - return ZERO_SIZE_PTR; - - return kmem_cache_alloc_node_trace(kmalloc_caches[i], - flags, node, size); - } -#endif - return __kmalloc_node(size, flags, node); -} - -struct memcg_cache_array { - struct rcu_head rcu; - struct kmem_cache *entries[0]; -}; - -/* - * This is the main placeholder for memcg-related information in kmem caches. - * Both the root cache and the child caches will have it. For the root cache, - * this will hold a dynamically allocated array large enough to hold - * information about the currently limited memcgs in the system. To allow the - * array to be accessed without taking any locks, on relocation we free the old - * version only after a grace period. - * - * Child caches will hold extra metadata needed for its operation. Fields are: - * - * @memcg: pointer to the memcg this cache belongs to - * @root_cache: pointer to the global, root cache, this cache was derived from - * - * Both root and child caches of the same kind are linked into a list chained - * through @list. - */ -struct memcg_cache_params { - bool is_root_cache; - struct list_head list; - union { - struct memcg_cache_array __rcu *memcg_caches; - struct { - struct mem_cgroup *memcg; - struct kmem_cache *root_cache; - }; - }; -}; - -int memcg_update_all_caches(int num_memcgs); - -/** - * kmalloc_array - allocate memory for an array. - * @n: number of elements. - * @size: element size. - * @flags: the type of memory to allocate (see kmalloc). - */ -static inline void *kmalloc_array(size_t n, size_t size, gfp_t flags) -{ - if (size != 0 && n > SIZE_MAX / size) - return NULL; - if (__builtin_constant_p(n) && __builtin_constant_p(size)) - return kmalloc(n * size, flags); - return __kmalloc(n * size, flags); -} - -/** - * kcalloc - allocate memory for an array. The memory is set to zero. - * @n: number of elements. - * @size: element size. - * @flags: the type of memory to allocate (see kmalloc). - */ -static inline void *kcalloc(size_t n, size_t size, gfp_t flags) -{ - return kmalloc_array(n, size, flags | __GFP_ZERO); -} - -/* - * kmalloc_track_caller is a special version of kmalloc that records the - * calling function of the routine calling it for slab leak tracking instead - * of just the calling function (confusing, eh?). - * It's useful when the call to kmalloc comes from a widely-used standard - * allocator where we care about the real place the memory allocation - * request comes from. - */ -extern void *__kmalloc_track_caller(size_t, gfp_t, unsigned long); -#define kmalloc_track_caller(size, flags) \ - __kmalloc_track_caller(size, flags, _RET_IP_) - -#ifdef CONFIG_NUMA -extern void *__kmalloc_node_track_caller(size_t, gfp_t, int, unsigned long); -#define kmalloc_node_track_caller(size, flags, node) \ - __kmalloc_node_track_caller(size, flags, node, \ - _RET_IP_) - -#else /* CONFIG_NUMA */ - -#define kmalloc_node_track_caller(size, flags, node) \ - kmalloc_track_caller(size, flags) - -#endif /* CONFIG_NUMA */ - -/* - * Shortcuts - */ -static inline void *kmem_cache_zalloc(struct kmem_cache *k, gfp_t flags) -{ - return kmem_cache_alloc(k, flags | __GFP_ZERO); -} - -/** - * kzalloc - allocate memory. The memory is set to zero. - * @size: how many bytes of memory are required. - * @flags: the type of memory to allocate (see kmalloc). - */ -static inline void *kzalloc(size_t size, gfp_t flags) -{ - return kmalloc(size, flags | __GFP_ZERO); -} - -/** - * kzalloc_node - allocate zeroed memory from a particular memory node. - * @size: how many bytes of memory are required. - * @flags: the type of memory to allocate (see kmalloc). - * @node: memory node from which to allocate - */ -static inline void *kzalloc_node(size_t size, gfp_t flags, int node) -{ - return kmalloc_node(size, flags | __GFP_ZERO, node); -} - -unsigned int kmem_cache_size(struct kmem_cache *s); -void __init kmem_cache_init_late(void); - -#if defined(CONFIG_SMP) && defined(CONFIG_SLAB) -int slab_prepare_cpu(unsigned int cpu); -int slab_dead_cpu(unsigned int cpu); -#else -#define slab_prepare_cpu NULL -#define slab_dead_cpu NULL -#endif - -#endif /* _LINUX_SLAB_H */ diff --git a/src/linux/include/linux/slub_def.h b/src/linux/include/linux/slub_def.h deleted file mode 100644 index 75f56c2..0000000 --- a/src/linux/include/linux/slub_def.h +++ /dev/null @@ -1,139 +0,0 @@ -#ifndef _LINUX_SLUB_DEF_H -#define _LINUX_SLUB_DEF_H - -/* - * SLUB : A Slab allocator without object queues. - * - * (C) 2007 SGI, Christoph Lameter - */ -#include - -enum stat_item { - ALLOC_FASTPATH, /* Allocation from cpu slab */ - ALLOC_SLOWPATH, /* Allocation by getting a new cpu slab */ - FREE_FASTPATH, /* Free to cpu slab */ - FREE_SLOWPATH, /* Freeing not to cpu slab */ - FREE_FROZEN, /* Freeing to frozen slab */ - FREE_ADD_PARTIAL, /* Freeing moves slab to partial list */ - FREE_REMOVE_PARTIAL, /* Freeing removes last object */ - ALLOC_FROM_PARTIAL, /* Cpu slab acquired from node partial list */ - ALLOC_SLAB, /* Cpu slab acquired from page allocator */ - ALLOC_REFILL, /* Refill cpu slab from slab freelist */ - ALLOC_NODE_MISMATCH, /* Switching cpu slab */ - FREE_SLAB, /* Slab freed to the page allocator */ - CPUSLAB_FLUSH, /* Abandoning of the cpu slab */ - DEACTIVATE_FULL, /* Cpu slab was full when deactivated */ - DEACTIVATE_EMPTY, /* Cpu slab was empty when deactivated */ - DEACTIVATE_TO_HEAD, /* Cpu slab was moved to the head of partials */ - DEACTIVATE_TO_TAIL, /* Cpu slab was moved to the tail of partials */ - DEACTIVATE_REMOTE_FREES,/* Slab contained remotely freed objects */ - DEACTIVATE_BYPASS, /* Implicit deactivation */ - ORDER_FALLBACK, /* Number of times fallback was necessary */ - CMPXCHG_DOUBLE_CPU_FAIL,/* Failure of this_cpu_cmpxchg_double */ - CMPXCHG_DOUBLE_FAIL, /* Number of times that cmpxchg double did not match */ - CPU_PARTIAL_ALLOC, /* Used cpu partial on alloc */ - CPU_PARTIAL_FREE, /* Refill cpu partial on free */ - CPU_PARTIAL_NODE, /* Refill cpu partial from node partial */ - CPU_PARTIAL_DRAIN, /* Drain cpu partial to node partial */ - NR_SLUB_STAT_ITEMS }; - -struct kmem_cache_cpu { - void **freelist; /* Pointer to next available object */ - unsigned long tid; /* Globally unique transaction id */ - struct page *page; /* The slab from which we are allocating */ - struct page *partial; /* Partially allocated frozen slabs */ -#ifdef CONFIG_SLUB_STATS - unsigned stat[NR_SLUB_STAT_ITEMS]; -#endif -}; - -/* - * Word size structure that can be atomically updated or read and that - * contains both the order and the number of objects that a slab of the - * given order would contain. - */ -struct kmem_cache_order_objects { - unsigned long x; -}; - -/* - * Slab cache management. - */ -struct kmem_cache { - struct kmem_cache_cpu __percpu *cpu_slab; - /* Used for retriving partial slabs etc */ - unsigned long flags; - unsigned long min_partial; - int size; /* The size of an object including meta data */ - int object_size; /* The size of an object without meta data */ - int offset; /* Free pointer offset. */ - int cpu_partial; /* Number of per cpu partial objects to keep around */ - struct kmem_cache_order_objects oo; - - /* Allocation and freeing of slabs */ - struct kmem_cache_order_objects max; - struct kmem_cache_order_objects min; - gfp_t allocflags; /* gfp flags to use on each alloc */ - int refcount; /* Refcount for slab cache destroy */ - void (*ctor)(void *); - int inuse; /* Offset to metadata */ - int align; /* Alignment */ - int reserved; /* Reserved bytes at the end of slabs */ - const char *name; /* Name (only for display!) */ - struct list_head list; /* List of slab caches */ - int red_left_pad; /* Left redzone padding size */ -#ifdef CONFIG_SYSFS - struct kobject kobj; /* For sysfs */ -#endif -#ifdef CONFIG_MEMCG - struct memcg_cache_params memcg_params; - int max_attr_size; /* for propagation, maximum size of a stored attr */ -#ifdef CONFIG_SYSFS - struct kset *memcg_kset; -#endif -#endif - -#ifdef CONFIG_NUMA - /* - * Defragmentation by allocating from a remote node. - */ - int remote_node_defrag_ratio; -#endif - -#ifdef CONFIG_SLAB_FREELIST_RANDOM - unsigned int *random_seq; -#endif - -#ifdef CONFIG_KASAN - struct kasan_cache kasan_info; -#endif - - struct kmem_cache_node *node[MAX_NUMNODES]; -}; - -#ifdef CONFIG_SYSFS -#define SLAB_SUPPORTS_SYSFS -void sysfs_slab_remove(struct kmem_cache *); -#else -static inline void sysfs_slab_remove(struct kmem_cache *s) -{ -} -#endif - -void object_err(struct kmem_cache *s, struct page *page, - u8 *object, char *reason); - -void *fixup_red_left(struct kmem_cache *s, void *p); - -static inline void *nearest_obj(struct kmem_cache *cache, struct page *page, - void *x) { - void *object = x - (x - page_address(page)) % cache->size; - void *last_object = page_address(page) + - (page->objects - 1) * cache->size; - void *result = (unlikely(object > last_object)) ? last_object : object; - - result = fixup_red_left(cache, result); - return result; -} - -#endif /* _LINUX_SLUB_DEF_H */ diff --git a/src/linux/include/linux/smp.h b/src/linux/include/linux/smp.h deleted file mode 100644 index 8e0cb7a..0000000 --- a/src/linux/include/linux/smp.h +++ /dev/null @@ -1,207 +0,0 @@ -#ifndef __LINUX_SMP_H -#define __LINUX_SMP_H - -/* - * Generic SMP support - * Alan Cox. - */ - -#include -#include -#include -#include -#include -#include - -typedef void (*smp_call_func_t)(void *info); -struct call_single_data { - struct llist_node llist; - smp_call_func_t func; - void *info; - unsigned int flags; -}; - -/* total number of cpus in this system (may exceed NR_CPUS) */ -extern unsigned int total_cpus; - -int smp_call_function_single(int cpuid, smp_call_func_t func, void *info, - int wait); - -/* - * Call a function on all processors - */ -int on_each_cpu(smp_call_func_t func, void *info, int wait); - -/* - * Call a function on processors specified by mask, which might include - * the local one. - */ -void on_each_cpu_mask(const struct cpumask *mask, smp_call_func_t func, - void *info, bool wait); - -/* - * Call a function on each processor for which the supplied function - * cond_func returns a positive value. This may include the local - * processor. - */ -void on_each_cpu_cond(bool (*cond_func)(int cpu, void *info), - smp_call_func_t func, void *info, bool wait, - gfp_t gfp_flags); - -int smp_call_function_single_async(int cpu, struct call_single_data *csd); - -#ifdef CONFIG_SMP - -#include -#include -#include -#include -#include - -/* - * main cross-CPU interfaces, handles INIT, TLB flush, STOP, etc. - * (defined in asm header): - */ - -/* - * stops all CPUs but the current one: - */ -extern void smp_send_stop(void); - -/* - * sends a 'reschedule' event to another CPU: - */ -extern void smp_send_reschedule(int cpu); - - -/* - * Prepare machine for booting other CPUs. - */ -extern void smp_prepare_cpus(unsigned int max_cpus); - -/* - * Bring a CPU up - */ -extern int __cpu_up(unsigned int cpunum, struct task_struct *tidle); - -/* - * Final polishing of CPUs - */ -extern void smp_cpus_done(unsigned int max_cpus); - -/* - * Call a function on all other processors - */ -int smp_call_function(smp_call_func_t func, void *info, int wait); -void smp_call_function_many(const struct cpumask *mask, - smp_call_func_t func, void *info, bool wait); - -int smp_call_function_any(const struct cpumask *mask, - smp_call_func_t func, void *info, int wait); - -void kick_all_cpus_sync(void); -void wake_up_all_idle_cpus(void); - -/* - * Generic and arch helpers - */ -void __init call_function_init(void); -void generic_smp_call_function_single_interrupt(void); -#define generic_smp_call_function_interrupt \ - generic_smp_call_function_single_interrupt - -/* - * Mark the boot cpu "online" so that it can call console drivers in - * printk() and can access its per-cpu storage. - */ -void smp_prepare_boot_cpu(void); - -extern unsigned int setup_max_cpus; -extern void __init setup_nr_cpu_ids(void); -extern void __init smp_init(void); - -#else /* !SMP */ - -static inline void smp_send_stop(void) { } - -/* - * These macros fold the SMP functionality into a single CPU system - */ -#define raw_smp_processor_id() 0 -static inline int up_smp_call_function(smp_call_func_t func, void *info) -{ - return 0; -} -#define smp_call_function(func, info, wait) \ - (up_smp_call_function(func, info)) - -static inline void smp_send_reschedule(int cpu) { } -#define smp_prepare_boot_cpu() do {} while (0) -#define smp_call_function_many(mask, func, info, wait) \ - (up_smp_call_function(func, info)) -static inline void call_function_init(void) { } - -static inline int -smp_call_function_any(const struct cpumask *mask, smp_call_func_t func, - void *info, int wait) -{ - return smp_call_function_single(0, func, info, wait); -} - -static inline void kick_all_cpus_sync(void) { } -static inline void wake_up_all_idle_cpus(void) { } - -#ifdef CONFIG_UP_LATE_INIT -extern void __init up_late_init(void); -static inline void smp_init(void) { up_late_init(); } -#else -static inline void smp_init(void) { } -#endif - -#endif /* !SMP */ - -/* - * smp_processor_id(): get the current CPU ID. - * - * if DEBUG_PREEMPT is enabled then we check whether it is - * used in a preemption-safe way. (smp_processor_id() is safe - * if it's used in a preemption-off critical section, or in - * a thread that is bound to the current CPU.) - * - * NOTE: raw_smp_processor_id() is for internal use only - * (smp_processor_id() is the preferred variant), but in rare - * instances it might also be used to turn off false positives - * (i.e. smp_processor_id() use that the debugging code reports but - * which use for some reason is legal). Don't use this to hack around - * the warning message, as your code might not work under PREEMPT. - */ -#ifdef CONFIG_DEBUG_PREEMPT - extern unsigned int debug_smp_processor_id(void); -# define smp_processor_id() debug_smp_processor_id() -#else -# define smp_processor_id() raw_smp_processor_id() -#endif - -#define get_cpu() ({ preempt_disable(); smp_processor_id(); }) -#define put_cpu() preempt_enable() - -/* - * Callback to arch code if there's nosmp or maxcpus=0 on the - * boot command line: - */ -extern void arch_disable_smp_support(void); - -extern void arch_enable_nonboot_cpus_begin(void); -extern void arch_enable_nonboot_cpus_end(void); - -void smp_setup_processor_id(void); - -int smp_call_on_cpu(unsigned int cpu, int (*func)(void *), void *par, - bool phys); - -/* SMP core functions */ -int smpcfd_prepare_cpu(unsigned int cpu); -int smpcfd_dead_cpu(unsigned int cpu); -int smpcfd_dying_cpu(unsigned int cpu); - -#endif /* __LINUX_SMP_H */ diff --git a/src/linux/include/linux/smpboot.h b/src/linux/include/linux/smpboot.h deleted file mode 100644 index 12910cf..0000000 --- a/src/linux/include/linux/smpboot.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef _LINUX_SMPBOOT_H -#define _LINUX_SMPBOOT_H - -#include - -struct task_struct; -/* Cookie handed to the thread_fn*/ -struct smpboot_thread_data; - -/** - * struct smp_hotplug_thread - CPU hotplug related thread descriptor - * @store: Pointer to per cpu storage for the task pointers - * @list: List head for core management - * @thread_should_run: Check whether the thread should run or not. Called with - * preemption disabled. - * @thread_fn: The associated thread function - * @create: Optional setup function, called when the thread gets - * created (Not called from the thread context) - * @setup: Optional setup function, called when the thread gets - * operational the first time - * @cleanup: Optional cleanup function, called when the thread - * should stop (module exit) - * @park: Optional park function, called when the thread is - * parked (cpu offline) - * @unpark: Optional unpark function, called when the thread is - * unparked (cpu online) - * @cpumask: Internal state. To update which threads are unparked, - * call smpboot_update_cpumask_percpu_thread(). - * @selfparking: Thread is not parked by the park function. - * @thread_comm: The base name of the thread - */ -struct smp_hotplug_thread { - struct task_struct __percpu **store; - struct list_head list; - int (*thread_should_run)(unsigned int cpu); - void (*thread_fn)(unsigned int cpu); - void (*create)(unsigned int cpu); - void (*setup)(unsigned int cpu); - void (*cleanup)(unsigned int cpu, bool online); - void (*park)(unsigned int cpu); - void (*unpark)(unsigned int cpu); - cpumask_var_t cpumask; - bool selfparking; - const char *thread_comm; -}; - -int smpboot_register_percpu_thread_cpumask(struct smp_hotplug_thread *plug_thread, - const struct cpumask *cpumask); - -static inline int -smpboot_register_percpu_thread(struct smp_hotplug_thread *plug_thread) -{ - return smpboot_register_percpu_thread_cpumask(plug_thread, - cpu_possible_mask); -} - -void smpboot_unregister_percpu_thread(struct smp_hotplug_thread *plug_thread); -int smpboot_update_cpumask_percpu_thread(struct smp_hotplug_thread *plug_thread, - const struct cpumask *); - -#endif diff --git a/src/linux/include/linux/sock_diag.h b/src/linux/include/linux/sock_diag.h deleted file mode 100644 index a0596ca..0000000 --- a/src/linux/include/linux/sock_diag.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef __SOCK_DIAG_H__ -#define __SOCK_DIAG_H__ - -#include -#include -#include -#include -#include - -struct sk_buff; -struct nlmsghdr; -struct sock; - -struct sock_diag_handler { - __u8 family; - int (*dump)(struct sk_buff *skb, struct nlmsghdr *nlh); - int (*get_info)(struct sk_buff *skb, struct sock *sk); - int (*destroy)(struct sk_buff *skb, struct nlmsghdr *nlh); -}; - -int sock_diag_register(const struct sock_diag_handler *h); -void sock_diag_unregister(const struct sock_diag_handler *h); - -void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh)); -void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh)); - -int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie); -void sock_diag_save_cookie(struct sock *sk, __u32 *cookie); - -int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attr); -int sock_diag_put_filterinfo(bool may_report_filterinfo, struct sock *sk, - struct sk_buff *skb, int attrtype); - -static inline -enum sknetlink_groups sock_diag_destroy_group(const struct sock *sk) -{ - switch (sk->sk_family) { - case AF_INET: - if (sk->sk_type == SOCK_RAW) - return SKNLGRP_NONE; - - switch (sk->sk_protocol) { - case IPPROTO_TCP: - return SKNLGRP_INET_TCP_DESTROY; - case IPPROTO_UDP: - return SKNLGRP_INET_UDP_DESTROY; - default: - return SKNLGRP_NONE; - } - case AF_INET6: - if (sk->sk_type == SOCK_RAW) - return SKNLGRP_NONE; - - switch (sk->sk_protocol) { - case IPPROTO_TCP: - return SKNLGRP_INET6_TCP_DESTROY; - case IPPROTO_UDP: - return SKNLGRP_INET6_UDP_DESTROY; - default: - return SKNLGRP_NONE; - } - default: - return SKNLGRP_NONE; - } -} - -static inline -bool sock_diag_has_destroy_listeners(const struct sock *sk) -{ - const struct net *n = sock_net(sk); - const enum sknetlink_groups group = sock_diag_destroy_group(sk); - - return group != SKNLGRP_NONE && n->diag_nlsk && - netlink_has_listeners(n->diag_nlsk, group); -} -void sock_diag_broadcast_destroy(struct sock *sk); - -int sock_diag_destroy(struct sock *sk, int err); -#endif diff --git a/src/linux/include/linux/socket.h b/src/linux/include/linux/socket.h deleted file mode 100644 index b5cc5a6..0000000 --- a/src/linux/include/linux/socket.h +++ /dev/null @@ -1,348 +0,0 @@ -#ifndef _LINUX_SOCKET_H -#define _LINUX_SOCKET_H - - -#include /* arch-dependent defines */ -#include /* the SIOCxxx I/O controls */ -#include /* iovec support */ -#include /* pid_t */ -#include /* __user */ -#include - -struct pid; -struct cred; - -#define __sockaddr_check_size(size) \ - BUILD_BUG_ON(((size) > sizeof(struct __kernel_sockaddr_storage))) - -#ifdef CONFIG_PROC_FS -struct seq_file; -extern void socket_seq_show(struct seq_file *seq); -#endif - -typedef __kernel_sa_family_t sa_family_t; - -/* - * 1003.1g requires sa_family_t and that sa_data is char. - */ - -struct sockaddr { - sa_family_t sa_family; /* address family, AF_xxx */ - char sa_data[14]; /* 14 bytes of protocol address */ -}; - -struct linger { - int l_onoff; /* Linger active */ - int l_linger; /* How long to linger for */ -}; - -#define sockaddr_storage __kernel_sockaddr_storage - -/* - * As we do 4.4BSD message passing we use a 4.4BSD message passing - * system, not 4.3. Thus msg_accrights(len) are now missing. They - * belong in an obscure libc emulation or the bin. - */ - -struct msghdr { - void *msg_name; /* ptr to socket address structure */ - int msg_namelen; /* size of socket address structure */ - struct iov_iter msg_iter; /* data */ - void *msg_control; /* ancillary data */ - __kernel_size_t msg_controllen; /* ancillary data buffer length */ - unsigned int msg_flags; /* flags on received message */ - struct kiocb *msg_iocb; /* ptr to iocb for async requests */ -}; - -struct user_msghdr { - void __user *msg_name; /* ptr to socket address structure */ - int msg_namelen; /* size of socket address structure */ - struct iovec __user *msg_iov; /* scatter/gather array */ - __kernel_size_t msg_iovlen; /* # elements in msg_iov */ - void __user *msg_control; /* ancillary data */ - __kernel_size_t msg_controllen; /* ancillary data buffer length */ - unsigned int msg_flags; /* flags on received message */ -}; - -/* For recvmmsg/sendmmsg */ -struct mmsghdr { - struct user_msghdr msg_hdr; - unsigned int msg_len; -}; - -/* - * POSIX 1003.1g - ancillary data object information - * Ancillary data consits of a sequence of pairs of - * (cmsghdr, cmsg_data[]) - */ - -struct cmsghdr { - __kernel_size_t cmsg_len; /* data byte count, including hdr */ - int cmsg_level; /* originating protocol */ - int cmsg_type; /* protocol-specific type */ -}; - -/* - * Ancillary data object information MACROS - * Table 5-14 of POSIX 1003.1g - */ - -#define __CMSG_NXTHDR(ctl, len, cmsg) __cmsg_nxthdr((ctl),(len),(cmsg)) -#define CMSG_NXTHDR(mhdr, cmsg) cmsg_nxthdr((mhdr), (cmsg)) - -#define CMSG_ALIGN(len) ( ((len)+sizeof(long)-1) & ~(sizeof(long)-1) ) - -#define CMSG_DATA(cmsg) ((void *)((char *)(cmsg) + CMSG_ALIGN(sizeof(struct cmsghdr)))) -#define CMSG_SPACE(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + CMSG_ALIGN(len)) -#define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr)) + (len)) - -#define __CMSG_FIRSTHDR(ctl,len) ((len) >= sizeof(struct cmsghdr) ? \ - (struct cmsghdr *)(ctl) : \ - (struct cmsghdr *)NULL) -#define CMSG_FIRSTHDR(msg) __CMSG_FIRSTHDR((msg)->msg_control, (msg)->msg_controllen) -#define CMSG_OK(mhdr, cmsg) ((cmsg)->cmsg_len >= sizeof(struct cmsghdr) && \ - (cmsg)->cmsg_len <= (unsigned long) \ - ((mhdr)->msg_controllen - \ - ((char *)(cmsg) - (char *)(mhdr)->msg_control))) -#define for_each_cmsghdr(cmsg, msg) \ - for (cmsg = CMSG_FIRSTHDR(msg); \ - cmsg; \ - cmsg = CMSG_NXTHDR(msg, cmsg)) - -/* - * Get the next cmsg header - * - * PLEASE, do not touch this function. If you think, that it is - * incorrect, grep kernel sources and think about consequences - * before trying to improve it. - * - * Now it always returns valid, not truncated ancillary object - * HEADER. But caller still MUST check, that cmsg->cmsg_len is - * inside range, given by msg->msg_controllen before using - * ancillary object DATA. --ANK (980731) - */ - -static inline struct cmsghdr * __cmsg_nxthdr(void *__ctl, __kernel_size_t __size, - struct cmsghdr *__cmsg) -{ - struct cmsghdr * __ptr; - - __ptr = (struct cmsghdr*)(((unsigned char *) __cmsg) + CMSG_ALIGN(__cmsg->cmsg_len)); - if ((unsigned long)((char*)(__ptr+1) - (char *) __ctl) > __size) - return (struct cmsghdr *)0; - - return __ptr; -} - -static inline struct cmsghdr * cmsg_nxthdr (struct msghdr *__msg, struct cmsghdr *__cmsg) -{ - return __cmsg_nxthdr(__msg->msg_control, __msg->msg_controllen, __cmsg); -} - -static inline size_t msg_data_left(struct msghdr *msg) -{ - return iov_iter_count(&msg->msg_iter); -} - -/* "Socket"-level control message types: */ - -#define SCM_RIGHTS 0x01 /* rw: access rights (array of int) */ -#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */ -#define SCM_SECURITY 0x03 /* rw: security label */ - -struct ucred { - __u32 pid; - __u32 uid; - __u32 gid; -}; - -/* Supported address families. */ -#define AF_UNSPEC 0 -#define AF_UNIX 1 /* Unix domain sockets */ -#define AF_LOCAL 1 /* POSIX name for AF_UNIX */ -#define AF_INET 2 /* Internet IP Protocol */ -#define AF_AX25 3 /* Amateur Radio AX.25 */ -#define AF_IPX 4 /* Novell IPX */ -#define AF_APPLETALK 5 /* AppleTalk DDP */ -#define AF_NETROM 6 /* Amateur Radio NET/ROM */ -#define AF_BRIDGE 7 /* Multiprotocol bridge */ -#define AF_ATMPVC 8 /* ATM PVCs */ -#define AF_X25 9 /* Reserved for X.25 project */ -#define AF_INET6 10 /* IP version 6 */ -#define AF_ROSE 11 /* Amateur Radio X.25 PLP */ -#define AF_DECnet 12 /* Reserved for DECnet project */ -#define AF_NETBEUI 13 /* Reserved for 802.2LLC project*/ -#define AF_SECURITY 14 /* Security callback pseudo AF */ -#define AF_KEY 15 /* PF_KEY key management API */ -#define AF_NETLINK 16 -#define AF_ROUTE AF_NETLINK /* Alias to emulate 4.4BSD */ -#define AF_PACKET 17 /* Packet family */ -#define AF_ASH 18 /* Ash */ -#define AF_ECONET 19 /* Acorn Econet */ -#define AF_ATMSVC 20 /* ATM SVCs */ -#define AF_RDS 21 /* RDS sockets */ -#define AF_SNA 22 /* Linux SNA Project (nutters!) */ -#define AF_IRDA 23 /* IRDA sockets */ -#define AF_PPPOX 24 /* PPPoX sockets */ -#define AF_WANPIPE 25 /* Wanpipe API Sockets */ -#define AF_LLC 26 /* Linux LLC */ -#define AF_IB 27 /* Native InfiniBand address */ -#define AF_MPLS 28 /* MPLS */ -#define AF_CAN 29 /* Controller Area Network */ -#define AF_TIPC 30 /* TIPC sockets */ -#define AF_BLUETOOTH 31 /* Bluetooth sockets */ -#define AF_IUCV 32 /* IUCV sockets */ -#define AF_RXRPC 33 /* RxRPC sockets */ -#define AF_ISDN 34 /* mISDN sockets */ -#define AF_PHONET 35 /* Phonet sockets */ -#define AF_IEEE802154 36 /* IEEE802154 sockets */ -#define AF_CAIF 37 /* CAIF sockets */ -#define AF_ALG 38 /* Algorithm sockets */ -#define AF_NFC 39 /* NFC sockets */ -#define AF_VSOCK 40 /* vSockets */ -#define AF_KCM 41 /* Kernel Connection Multiplexor*/ -#define AF_QIPCRTR 42 /* Qualcomm IPC Router */ - -#define AF_MAX 43 /* For now.. */ - -/* Protocol families, same as address families. */ -#define PF_UNSPEC AF_UNSPEC -#define PF_UNIX AF_UNIX -#define PF_LOCAL AF_LOCAL -#define PF_INET AF_INET -#define PF_AX25 AF_AX25 -#define PF_IPX AF_IPX -#define PF_APPLETALK AF_APPLETALK -#define PF_NETROM AF_NETROM -#define PF_BRIDGE AF_BRIDGE -#define PF_ATMPVC AF_ATMPVC -#define PF_X25 AF_X25 -#define PF_INET6 AF_INET6 -#define PF_ROSE AF_ROSE -#define PF_DECnet AF_DECnet -#define PF_NETBEUI AF_NETBEUI -#define PF_SECURITY AF_SECURITY -#define PF_KEY AF_KEY -#define PF_NETLINK AF_NETLINK -#define PF_ROUTE AF_ROUTE -#define PF_PACKET AF_PACKET -#define PF_ASH AF_ASH -#define PF_ECONET AF_ECONET -#define PF_ATMSVC AF_ATMSVC -#define PF_RDS AF_RDS -#define PF_SNA AF_SNA -#define PF_IRDA AF_IRDA -#define PF_PPPOX AF_PPPOX -#define PF_WANPIPE AF_WANPIPE -#define PF_LLC AF_LLC -#define PF_IB AF_IB -#define PF_MPLS AF_MPLS -#define PF_CAN AF_CAN -#define PF_TIPC AF_TIPC -#define PF_BLUETOOTH AF_BLUETOOTH -#define PF_IUCV AF_IUCV -#define PF_RXRPC AF_RXRPC -#define PF_ISDN AF_ISDN -#define PF_PHONET AF_PHONET -#define PF_IEEE802154 AF_IEEE802154 -#define PF_CAIF AF_CAIF -#define PF_ALG AF_ALG -#define PF_NFC AF_NFC -#define PF_VSOCK AF_VSOCK -#define PF_KCM AF_KCM -#define PF_QIPCRTR AF_QIPCRTR -#define PF_MAX AF_MAX - -/* Maximum queue length specifiable by listen. */ -#define SOMAXCONN 128 - -/* Flags we can use with send/ and recv. - Added those for 1003.1g not all are supported yet - */ - -#define MSG_OOB 1 -#define MSG_PEEK 2 -#define MSG_DONTROUTE 4 -#define MSG_TRYHARD 4 /* Synonym for MSG_DONTROUTE for DECnet */ -#define MSG_CTRUNC 8 -#define MSG_PROBE 0x10 /* Do not send. Only probe path f.e. for MTU */ -#define MSG_TRUNC 0x20 -#define MSG_DONTWAIT 0x40 /* Nonblocking io */ -#define MSG_EOR 0x80 /* End of record */ -#define MSG_WAITALL 0x100 /* Wait for a full request */ -#define MSG_FIN 0x200 -#define MSG_SYN 0x400 -#define MSG_CONFIRM 0x800 /* Confirm path validity */ -#define MSG_RST 0x1000 -#define MSG_ERRQUEUE 0x2000 /* Fetch message from error queue */ -#define MSG_NOSIGNAL 0x4000 /* Do not generate SIGPIPE */ -#define MSG_MORE 0x8000 /* Sender will send more */ -#define MSG_WAITFORONE 0x10000 /* recvmmsg(): block until 1+ packets avail */ -#define MSG_SENDPAGE_NOTLAST 0x20000 /* sendpage() internal : not the last page */ -#define MSG_BATCH 0x40000 /* sendmmsg(): more messages coming */ -#define MSG_EOF MSG_FIN - -#define MSG_FASTOPEN 0x20000000 /* Send data in TCP SYN */ -#define MSG_CMSG_CLOEXEC 0x40000000 /* Set close_on_exec for file - descriptor received through - SCM_RIGHTS */ -#if defined(CONFIG_COMPAT) -#define MSG_CMSG_COMPAT 0x80000000 /* This message needs 32 bit fixups */ -#else -#define MSG_CMSG_COMPAT 0 /* We never have 32 bit fixups */ -#endif - - -/* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */ -#define SOL_IP 0 -/* #define SOL_ICMP 1 No-no-no! Due to Linux :-) we cannot use SOL_ICMP=1 */ -#define SOL_TCP 6 -#define SOL_UDP 17 -#define SOL_IPV6 41 -#define SOL_ICMPV6 58 -#define SOL_SCTP 132 -#define SOL_UDPLITE 136 /* UDP-Lite (RFC 3828) */ -#define SOL_RAW 255 -#define SOL_IPX 256 -#define SOL_AX25 257 -#define SOL_ATALK 258 -#define SOL_NETROM 259 -#define SOL_ROSE 260 -#define SOL_DECNET 261 -#define SOL_X25 262 -#define SOL_PACKET 263 -#define SOL_ATM 264 /* ATM layer (cell level) */ -#define SOL_AAL 265 /* ATM Adaption Layer (packet level) */ -#define SOL_IRDA 266 -#define SOL_NETBEUI 267 -#define SOL_LLC 268 -#define SOL_DCCP 269 -#define SOL_NETLINK 270 -#define SOL_TIPC 271 -#define SOL_RXRPC 272 -#define SOL_PPPOL2TP 273 -#define SOL_BLUETOOTH 274 -#define SOL_PNPIPE 275 -#define SOL_RDS 276 -#define SOL_IUCV 277 -#define SOL_CAIF 278 -#define SOL_ALG 279 -#define SOL_NFC 280 -#define SOL_KCM 281 - -/* IPX options */ -#define IPX_TYPE 1 - -extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr); -extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data); - -struct timespec; - -/* The __sys_...msg variants allow MSG_CMSG_COMPAT */ -extern long __sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned flags); -extern long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags); -extern int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, - unsigned int flags, struct timespec *timeout); -extern int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, - unsigned int vlen, unsigned int flags); -#endif /* _LINUX_SOCKET_H */ diff --git a/src/linux/include/linux/sort.h b/src/linux/include/linux/sort.h deleted file mode 100644 index d534da2..0000000 --- a/src/linux/include/linux/sort.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _LINUX_SORT_H -#define _LINUX_SORT_H - -#include - -void sort(void *base, size_t num, size_t size, - int (*cmp)(const void *, const void *), - void (*swap)(void *, void *, int)); - -#endif diff --git a/src/linux/include/linux/spinlock.h b/src/linux/include/linux/spinlock.h deleted file mode 100644 index 47dd0ce..0000000 --- a/src/linux/include/linux/spinlock.h +++ /dev/null @@ -1,419 +0,0 @@ -#ifndef __LINUX_SPINLOCK_H -#define __LINUX_SPINLOCK_H - -/* - * include/linux/spinlock.h - generic spinlock/rwlock declarations - * - * here's the role of the various spinlock/rwlock related include files: - * - * on SMP builds: - * - * asm/spinlock_types.h: contains the arch_spinlock_t/arch_rwlock_t and the - * initializers - * - * linux/spinlock_types.h: - * defines the generic type and initializers - * - * asm/spinlock.h: contains the arch_spin_*()/etc. lowlevel - * implementations, mostly inline assembly code - * - * (also included on UP-debug builds:) - * - * linux/spinlock_api_smp.h: - * contains the prototypes for the _spin_*() APIs. - * - * linux/spinlock.h: builds the final spin_*() APIs. - * - * on UP builds: - * - * linux/spinlock_type_up.h: - * contains the generic, simplified UP spinlock type. - * (which is an empty structure on non-debug builds) - * - * linux/spinlock_types.h: - * defines the generic type and initializers - * - * linux/spinlock_up.h: - * contains the arch_spin_*()/etc. version of UP - * builds. (which are NOPs on non-debug, non-preempt - * builds) - * - * (included on UP-non-debug builds:) - * - * linux/spinlock_api_up.h: - * builds the _spin_*() APIs. - * - * linux/spinlock.h: builds the final spin_*() APIs. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * Must define these before including other files, inline functions need them - */ -#define LOCK_SECTION_NAME ".text..lock."KBUILD_BASENAME - -#define LOCK_SECTION_START(extra) \ - ".subsection 1\n\t" \ - extra \ - ".ifndef " LOCK_SECTION_NAME "\n\t" \ - LOCK_SECTION_NAME ":\n\t" \ - ".endif\n" - -#define LOCK_SECTION_END \ - ".previous\n\t" - -#define __lockfunc __attribute__((section(".spinlock.text"))) - -/* - * Pull the arch_spinlock_t and arch_rwlock_t definitions: - */ -#include - -/* - * Pull the arch_spin*() functions/declarations (UP-nondebug doesn't need them): - */ -#ifdef CONFIG_SMP -# include -#else -# include -#endif - -#ifdef CONFIG_DEBUG_SPINLOCK - extern void __raw_spin_lock_init(raw_spinlock_t *lock, const char *name, - struct lock_class_key *key); -# define raw_spin_lock_init(lock) \ -do { \ - static struct lock_class_key __key; \ - \ - __raw_spin_lock_init((lock), #lock, &__key); \ -} while (0) - -#else -# define raw_spin_lock_init(lock) \ - do { *(lock) = __RAW_SPIN_LOCK_UNLOCKED(lock); } while (0) -#endif - -#define raw_spin_is_locked(lock) arch_spin_is_locked(&(lock)->raw_lock) - -#ifdef CONFIG_GENERIC_LOCKBREAK -#define raw_spin_is_contended(lock) ((lock)->break_lock) -#else - -#ifdef arch_spin_is_contended -#define raw_spin_is_contended(lock) arch_spin_is_contended(&(lock)->raw_lock) -#else -#define raw_spin_is_contended(lock) (((void)(lock), 0)) -#endif /*arch_spin_is_contended*/ -#endif - -/* - * Despite its name it doesn't necessarily has to be a full barrier. - * It should only guarantee that a STORE before the critical section - * can not be reordered with LOADs and STOREs inside this section. - * spin_lock() is the one-way barrier, this LOAD can not escape out - * of the region. So the default implementation simply ensures that - * a STORE can not move into the critical section, smp_wmb() should - * serialize it with another STORE done by spin_lock(). - */ -#ifndef smp_mb__before_spinlock -#define smp_mb__before_spinlock() smp_wmb() -#endif - -/** - * raw_spin_unlock_wait - wait until the spinlock gets unlocked - * @lock: the spinlock in question. - */ -#define raw_spin_unlock_wait(lock) arch_spin_unlock_wait(&(lock)->raw_lock) - -#ifdef CONFIG_DEBUG_SPINLOCK - extern void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock); -#define do_raw_spin_lock_flags(lock, flags) do_raw_spin_lock(lock) - extern int do_raw_spin_trylock(raw_spinlock_t *lock); - extern void do_raw_spin_unlock(raw_spinlock_t *lock) __releases(lock); -#else -static inline void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock) -{ - __acquire(lock); - arch_spin_lock(&lock->raw_lock); -} - -static inline void -do_raw_spin_lock_flags(raw_spinlock_t *lock, unsigned long *flags) __acquires(lock) -{ - __acquire(lock); - arch_spin_lock_flags(&lock->raw_lock, *flags); -} - -static inline int do_raw_spin_trylock(raw_spinlock_t *lock) -{ - return arch_spin_trylock(&(lock)->raw_lock); -} - -static inline void do_raw_spin_unlock(raw_spinlock_t *lock) __releases(lock) -{ - arch_spin_unlock(&lock->raw_lock); - __release(lock); -} -#endif - -/* - * Define the various spin_lock methods. Note we define these - * regardless of whether CONFIG_SMP or CONFIG_PREEMPT are set. The - * various methods are defined as nops in the case they are not - * required. - */ -#define raw_spin_trylock(lock) __cond_lock(lock, _raw_spin_trylock(lock)) - -#define raw_spin_lock(lock) _raw_spin_lock(lock) - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# define raw_spin_lock_nested(lock, subclass) \ - _raw_spin_lock_nested(lock, subclass) -# define raw_spin_lock_bh_nested(lock, subclass) \ - _raw_spin_lock_bh_nested(lock, subclass) - -# define raw_spin_lock_nest_lock(lock, nest_lock) \ - do { \ - typecheck(struct lockdep_map *, &(nest_lock)->dep_map);\ - _raw_spin_lock_nest_lock(lock, &(nest_lock)->dep_map); \ - } while (0) -#else -/* - * Always evaluate the 'subclass' argument to avoid that the compiler - * warns about set-but-not-used variables when building with - * CONFIG_DEBUG_LOCK_ALLOC=n and with W=1. - */ -# define raw_spin_lock_nested(lock, subclass) \ - _raw_spin_lock(((void)(subclass), (lock))) -# define raw_spin_lock_nest_lock(lock, nest_lock) _raw_spin_lock(lock) -# define raw_spin_lock_bh_nested(lock, subclass) _raw_spin_lock_bh(lock) -#endif - -#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) - -#define raw_spin_lock_irqsave(lock, flags) \ - do { \ - typecheck(unsigned long, flags); \ - flags = _raw_spin_lock_irqsave(lock); \ - } while (0) - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -#define raw_spin_lock_irqsave_nested(lock, flags, subclass) \ - do { \ - typecheck(unsigned long, flags); \ - flags = _raw_spin_lock_irqsave_nested(lock, subclass); \ - } while (0) -#else -#define raw_spin_lock_irqsave_nested(lock, flags, subclass) \ - do { \ - typecheck(unsigned long, flags); \ - flags = _raw_spin_lock_irqsave(lock); \ - } while (0) -#endif - -#else - -#define raw_spin_lock_irqsave(lock, flags) \ - do { \ - typecheck(unsigned long, flags); \ - _raw_spin_lock_irqsave(lock, flags); \ - } while (0) - -#define raw_spin_lock_irqsave_nested(lock, flags, subclass) \ - raw_spin_lock_irqsave(lock, flags) - -#endif - -#define raw_spin_lock_irq(lock) _raw_spin_lock_irq(lock) -#define raw_spin_lock_bh(lock) _raw_spin_lock_bh(lock) -#define raw_spin_unlock(lock) _raw_spin_unlock(lock) -#define raw_spin_unlock_irq(lock) _raw_spin_unlock_irq(lock) - -#define raw_spin_unlock_irqrestore(lock, flags) \ - do { \ - typecheck(unsigned long, flags); \ - _raw_spin_unlock_irqrestore(lock, flags); \ - } while (0) -#define raw_spin_unlock_bh(lock) _raw_spin_unlock_bh(lock) - -#define raw_spin_trylock_bh(lock) \ - __cond_lock(lock, _raw_spin_trylock_bh(lock)) - -#define raw_spin_trylock_irq(lock) \ -({ \ - local_irq_disable(); \ - raw_spin_trylock(lock) ? \ - 1 : ({ local_irq_enable(); 0; }); \ -}) - -#define raw_spin_trylock_irqsave(lock, flags) \ -({ \ - local_irq_save(flags); \ - raw_spin_trylock(lock) ? \ - 1 : ({ local_irq_restore(flags); 0; }); \ -}) - -/** - * raw_spin_can_lock - would raw_spin_trylock() succeed? - * @lock: the spinlock in question. - */ -#define raw_spin_can_lock(lock) (!raw_spin_is_locked(lock)) - -/* Include rwlock functions */ -#include - -/* - * Pull the _spin_*()/_read_*()/_write_*() functions/declarations: - */ -#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) -# include -#else -# include -#endif - -/* - * Map the spin_lock functions to the raw variants for PREEMPT_RT=n - */ - -static __always_inline raw_spinlock_t *spinlock_check(spinlock_t *lock) -{ - return &lock->rlock; -} - -#define spin_lock_init(_lock) \ -do { \ - spinlock_check(_lock); \ - raw_spin_lock_init(&(_lock)->rlock); \ -} while (0) - -static __always_inline void spin_lock(spinlock_t *lock) -{ - raw_spin_lock(&lock->rlock); -} - -static __always_inline void spin_lock_bh(spinlock_t *lock) -{ - raw_spin_lock_bh(&lock->rlock); -} - -static __always_inline int spin_trylock(spinlock_t *lock) -{ - return raw_spin_trylock(&lock->rlock); -} - -#define spin_lock_nested(lock, subclass) \ -do { \ - raw_spin_lock_nested(spinlock_check(lock), subclass); \ -} while (0) - -#define spin_lock_bh_nested(lock, subclass) \ -do { \ - raw_spin_lock_bh_nested(spinlock_check(lock), subclass);\ -} while (0) - -#define spin_lock_nest_lock(lock, nest_lock) \ -do { \ - raw_spin_lock_nest_lock(spinlock_check(lock), nest_lock); \ -} while (0) - -static __always_inline void spin_lock_irq(spinlock_t *lock) -{ - raw_spin_lock_irq(&lock->rlock); -} - -#define spin_lock_irqsave(lock, flags) \ -do { \ - raw_spin_lock_irqsave(spinlock_check(lock), flags); \ -} while (0) - -#define spin_lock_irqsave_nested(lock, flags, subclass) \ -do { \ - raw_spin_lock_irqsave_nested(spinlock_check(lock), flags, subclass); \ -} while (0) - -static __always_inline void spin_unlock(spinlock_t *lock) -{ - raw_spin_unlock(&lock->rlock); -} - -static __always_inline void spin_unlock_bh(spinlock_t *lock) -{ - raw_spin_unlock_bh(&lock->rlock); -} - -static __always_inline void spin_unlock_irq(spinlock_t *lock) -{ - raw_spin_unlock_irq(&lock->rlock); -} - -static __always_inline void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags) -{ - raw_spin_unlock_irqrestore(&lock->rlock, flags); -} - -static __always_inline int spin_trylock_bh(spinlock_t *lock) -{ - return raw_spin_trylock_bh(&lock->rlock); -} - -static __always_inline int spin_trylock_irq(spinlock_t *lock) -{ - return raw_spin_trylock_irq(&lock->rlock); -} - -#define spin_trylock_irqsave(lock, flags) \ -({ \ - raw_spin_trylock_irqsave(spinlock_check(lock), flags); \ -}) - -static __always_inline void spin_unlock_wait(spinlock_t *lock) -{ - raw_spin_unlock_wait(&lock->rlock); -} - -static __always_inline int spin_is_locked(spinlock_t *lock) -{ - return raw_spin_is_locked(&lock->rlock); -} - -static __always_inline int spin_is_contended(spinlock_t *lock) -{ - return raw_spin_is_contended(&lock->rlock); -} - -static __always_inline int spin_can_lock(spinlock_t *lock) -{ - return raw_spin_can_lock(&lock->rlock); -} - -#define assert_spin_locked(lock) assert_raw_spin_locked(&(lock)->rlock) - -/* - * Pull the atomic_t declaration: - * (asm-mips/atomic.h needs above definitions) - */ -#include -/** - * atomic_dec_and_lock - lock on reaching reference count zero - * @atomic: the atomic counter - * @lock: the spinlock in question - * - * Decrements @atomic by 1. If the result is 0, returns true and locks - * @lock. Returns false for all other cases. - */ -extern int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock); -#define atomic_dec_and_lock(atomic, lock) \ - __cond_lock(lock, _atomic_dec_and_lock(atomic, lock)) - -#endif /* __LINUX_SPINLOCK_H */ diff --git a/src/linux/include/linux/spinlock_api_up.h b/src/linux/include/linux/spinlock_api_up.h deleted file mode 100644 index d3afef9..0000000 --- a/src/linux/include/linux/spinlock_api_up.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef __LINUX_SPINLOCK_API_UP_H -#define __LINUX_SPINLOCK_API_UP_H - -#ifndef __LINUX_SPINLOCK_H -# error "please don't include this file directly" -#endif - -/* - * include/linux/spinlock_api_up.h - * - * spinlock API implementation on UP-nondebug (inlined implementation) - * - * portions Copyright 2005, Red Hat, Inc., Ingo Molnar - * Released under the General Public License (GPL). - */ - -#define in_lock_functions(ADDR) 0 - -#define assert_raw_spin_locked(lock) do { (void)(lock); } while (0) - -/* - * In the UP-nondebug case there's no real locking going on, so the - * only thing we have to do is to keep the preempt counts and irq - * flags straight, to suppress compiler warnings of unused lock - * variables, and to add the proper checker annotations: - */ -#define ___LOCK(lock) \ - do { __acquire(lock); (void)(lock); } while (0) - -#define __LOCK(lock) \ - do { preempt_disable(); ___LOCK(lock); } while (0) - -#define __LOCK_BH(lock) \ - do { __local_bh_disable_ip(_THIS_IP_, SOFTIRQ_LOCK_OFFSET); ___LOCK(lock); } while (0) - -#define __LOCK_IRQ(lock) \ - do { local_irq_disable(); __LOCK(lock); } while (0) - -#define __LOCK_IRQSAVE(lock, flags) \ - do { local_irq_save(flags); __LOCK(lock); } while (0) - -#define ___UNLOCK(lock) \ - do { __release(lock); (void)(lock); } while (0) - -#define __UNLOCK(lock) \ - do { preempt_enable(); ___UNLOCK(lock); } while (0) - -#define __UNLOCK_BH(lock) \ - do { __local_bh_enable_ip(_THIS_IP_, SOFTIRQ_LOCK_OFFSET); \ - ___UNLOCK(lock); } while (0) - -#define __UNLOCK_IRQ(lock) \ - do { local_irq_enable(); __UNLOCK(lock); } while (0) - -#define __UNLOCK_IRQRESTORE(lock, flags) \ - do { local_irq_restore(flags); __UNLOCK(lock); } while (0) - -#define _raw_spin_lock(lock) __LOCK(lock) -#define _raw_spin_lock_nested(lock, subclass) __LOCK(lock) -#define _raw_spin_lock_bh_nested(lock, subclass) __LOCK(lock) -#define _raw_read_lock(lock) __LOCK(lock) -#define _raw_write_lock(lock) __LOCK(lock) -#define _raw_spin_lock_bh(lock) __LOCK_BH(lock) -#define _raw_read_lock_bh(lock) __LOCK_BH(lock) -#define _raw_write_lock_bh(lock) __LOCK_BH(lock) -#define _raw_spin_lock_irq(lock) __LOCK_IRQ(lock) -#define _raw_read_lock_irq(lock) __LOCK_IRQ(lock) -#define _raw_write_lock_irq(lock) __LOCK_IRQ(lock) -#define _raw_spin_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) -#define _raw_read_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) -#define _raw_write_lock_irqsave(lock, flags) __LOCK_IRQSAVE(lock, flags) -#define _raw_spin_trylock(lock) ({ __LOCK(lock); 1; }) -#define _raw_read_trylock(lock) ({ __LOCK(lock); 1; }) -#define _raw_write_trylock(lock) ({ __LOCK(lock); 1; }) -#define _raw_spin_trylock_bh(lock) ({ __LOCK_BH(lock); 1; }) -#define _raw_spin_unlock(lock) __UNLOCK(lock) -#define _raw_read_unlock(lock) __UNLOCK(lock) -#define _raw_write_unlock(lock) __UNLOCK(lock) -#define _raw_spin_unlock_bh(lock) __UNLOCK_BH(lock) -#define _raw_write_unlock_bh(lock) __UNLOCK_BH(lock) -#define _raw_read_unlock_bh(lock) __UNLOCK_BH(lock) -#define _raw_spin_unlock_irq(lock) __UNLOCK_IRQ(lock) -#define _raw_read_unlock_irq(lock) __UNLOCK_IRQ(lock) -#define _raw_write_unlock_irq(lock) __UNLOCK_IRQ(lock) -#define _raw_spin_unlock_irqrestore(lock, flags) \ - __UNLOCK_IRQRESTORE(lock, flags) -#define _raw_read_unlock_irqrestore(lock, flags) \ - __UNLOCK_IRQRESTORE(lock, flags) -#define _raw_write_unlock_irqrestore(lock, flags) \ - __UNLOCK_IRQRESTORE(lock, flags) - -#endif /* __LINUX_SPINLOCK_API_UP_H */ diff --git a/src/linux/include/linux/spinlock_types.h b/src/linux/include/linux/spinlock_types.h deleted file mode 100644 index 73548eb..0000000 --- a/src/linux/include/linux/spinlock_types.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef __LINUX_SPINLOCK_TYPES_H -#define __LINUX_SPINLOCK_TYPES_H - -/* - * include/linux/spinlock_types.h - generic spinlock type definitions - * and initializers - * - * portions Copyright 2005, Red Hat, Inc., Ingo Molnar - * Released under the General Public License (GPL). - */ - -#if defined(CONFIG_SMP) -# include -#else -# include -#endif - -#include - -typedef struct raw_spinlock { - arch_spinlock_t raw_lock; -#ifdef CONFIG_GENERIC_LOCKBREAK - unsigned int break_lock; -#endif -#ifdef CONFIG_DEBUG_SPINLOCK - unsigned int magic, owner_cpu; - void *owner; -#endif -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map dep_map; -#endif -} raw_spinlock_t; - -#define SPINLOCK_MAGIC 0xdead4ead - -#define SPINLOCK_OWNER_INIT ((void *)-1L) - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# define SPIN_DEP_MAP_INIT(lockname) .dep_map = { .name = #lockname } -#else -# define SPIN_DEP_MAP_INIT(lockname) -#endif - -#ifdef CONFIG_DEBUG_SPINLOCK -# define SPIN_DEBUG_INIT(lockname) \ - .magic = SPINLOCK_MAGIC, \ - .owner_cpu = -1, \ - .owner = SPINLOCK_OWNER_INIT, -#else -# define SPIN_DEBUG_INIT(lockname) -#endif - -#define __RAW_SPIN_LOCK_INITIALIZER(lockname) \ - { \ - .raw_lock = __ARCH_SPIN_LOCK_UNLOCKED, \ - SPIN_DEBUG_INIT(lockname) \ - SPIN_DEP_MAP_INIT(lockname) } - -#define __RAW_SPIN_LOCK_UNLOCKED(lockname) \ - (raw_spinlock_t) __RAW_SPIN_LOCK_INITIALIZER(lockname) - -#define DEFINE_RAW_SPINLOCK(x) raw_spinlock_t x = __RAW_SPIN_LOCK_UNLOCKED(x) - -typedef struct spinlock { - union { - struct raw_spinlock rlock; - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map)) - struct { - u8 __padding[LOCK_PADSIZE]; - struct lockdep_map dep_map; - }; -#endif - }; -} spinlock_t; - -#define __SPIN_LOCK_INITIALIZER(lockname) \ - { { .rlock = __RAW_SPIN_LOCK_INITIALIZER(lockname) } } - -#define __SPIN_LOCK_UNLOCKED(lockname) \ - (spinlock_t ) __SPIN_LOCK_INITIALIZER(lockname) - -#define DEFINE_SPINLOCK(x) spinlock_t x = __SPIN_LOCK_UNLOCKED(x) - -#include - -#endif /* __LINUX_SPINLOCK_TYPES_H */ diff --git a/src/linux/include/linux/spinlock_types_up.h b/src/linux/include/linux/spinlock_types_up.h deleted file mode 100644 index c09b640..0000000 --- a/src/linux/include/linux/spinlock_types_up.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef __LINUX_SPINLOCK_TYPES_UP_H -#define __LINUX_SPINLOCK_TYPES_UP_H - -#ifndef __LINUX_SPINLOCK_TYPES_H -# error "please don't include this file directly" -#endif - -/* - * include/linux/spinlock_types_up.h - spinlock type definitions for UP - * - * portions Copyright 2005, Red Hat, Inc., Ingo Molnar - * Released under the General Public License (GPL). - */ - -#ifdef CONFIG_DEBUG_SPINLOCK - -typedef struct { - volatile unsigned int slock; -} arch_spinlock_t; - -#define __ARCH_SPIN_LOCK_UNLOCKED { 1 } - -#else - -typedef struct { } arch_spinlock_t; - -#define __ARCH_SPIN_LOCK_UNLOCKED { } - -#endif - -typedef struct { - /* no debug version on UP */ -} arch_rwlock_t; - -#define __ARCH_RW_LOCK_UNLOCKED { } - -#endif /* __LINUX_SPINLOCK_TYPES_UP_H */ diff --git a/src/linux/include/linux/spinlock_up.h b/src/linux/include/linux/spinlock_up.h deleted file mode 100644 index 0d9848d..0000000 --- a/src/linux/include/linux/spinlock_up.h +++ /dev/null @@ -1,89 +0,0 @@ -#ifndef __LINUX_SPINLOCK_UP_H -#define __LINUX_SPINLOCK_UP_H - -#ifndef __LINUX_SPINLOCK_H -# error "please don't include this file directly" -#endif - -#include /* for cpu_relax() */ -#include - -/* - * include/linux/spinlock_up.h - UP-debug version of spinlocks. - * - * portions Copyright 2005, Red Hat, Inc., Ingo Molnar - * Released under the General Public License (GPL). - * - * In the debug case, 1 means unlocked, 0 means locked. (the values - * are inverted, to catch initialization bugs) - * - * No atomicity anywhere, we are on UP. However, we still need - * the compiler barriers, because we do not want the compiler to - * move potentially faulting instructions (notably user accesses) - * into the locked sequence, resulting in non-atomic execution. - */ - -#ifdef CONFIG_DEBUG_SPINLOCK -#define arch_spin_is_locked(x) ((x)->slock == 0) - -static inline void arch_spin_unlock_wait(arch_spinlock_t *lock) -{ - smp_cond_load_acquire(&lock->slock, VAL); -} - -static inline void arch_spin_lock(arch_spinlock_t *lock) -{ - lock->slock = 0; - barrier(); -} - -static inline void -arch_spin_lock_flags(arch_spinlock_t *lock, unsigned long flags) -{ - local_irq_save(flags); - lock->slock = 0; - barrier(); -} - -static inline int arch_spin_trylock(arch_spinlock_t *lock) -{ - char oldval = lock->slock; - - lock->slock = 0; - barrier(); - - return oldval > 0; -} - -static inline void arch_spin_unlock(arch_spinlock_t *lock) -{ - barrier(); - lock->slock = 1; -} - -/* - * Read-write spinlocks. No debug version. - */ -#define arch_read_lock(lock) do { barrier(); (void)(lock); } while (0) -#define arch_write_lock(lock) do { barrier(); (void)(lock); } while (0) -#define arch_read_trylock(lock) ({ barrier(); (void)(lock); 1; }) -#define arch_write_trylock(lock) ({ barrier(); (void)(lock); 1; }) -#define arch_read_unlock(lock) do { barrier(); (void)(lock); } while (0) -#define arch_write_unlock(lock) do { barrier(); (void)(lock); } while (0) - -#else /* DEBUG_SPINLOCK */ -#define arch_spin_is_locked(lock) ((void)(lock), 0) -#define arch_spin_unlock_wait(lock) do { barrier(); (void)(lock); } while (0) -/* for sched/core.c and kernel_lock.c: */ -# define arch_spin_lock(lock) do { barrier(); (void)(lock); } while (0) -# define arch_spin_lock_flags(lock, flags) do { barrier(); (void)(lock); } while (0) -# define arch_spin_unlock(lock) do { barrier(); (void)(lock); } while (0) -# define arch_spin_trylock(lock) ({ barrier(); (void)(lock); 1; }) -#endif /* DEBUG_SPINLOCK */ - -#define arch_spin_is_contended(lock) (((void)(lock), 0)) - -#define arch_read_can_lock(lock) (((void)(lock), 1)) -#define arch_write_can_lock(lock) (((void)(lock), 1)) - -#endif /* __LINUX_SPINLOCK_UP_H */ diff --git a/src/linux/include/linux/splice.h b/src/linux/include/linux/splice.h deleted file mode 100644 index 00a2116..0000000 --- a/src/linux/include/linux/splice.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Function declerations and data structures related to the splice - * implementation. - * - * Copyright (C) 2007 Jens Axboe - * - */ -#ifndef SPLICE_H -#define SPLICE_H - -#include - -/* - * Flags passed in from splice/tee/vmsplice - */ -#define SPLICE_F_MOVE (0x01) /* move pages instead of copying */ -#define SPLICE_F_NONBLOCK (0x02) /* don't block on the pipe splicing (but */ - /* we may still block on the fd we splice */ - /* from/to, of course */ -#define SPLICE_F_MORE (0x04) /* expect more data */ -#define SPLICE_F_GIFT (0x08) /* pages passed in are a gift */ - -/* - * Passed to the actors - */ -struct splice_desc { - size_t total_len; /* remaining length */ - unsigned int len; /* current length */ - unsigned int flags; /* splice flags */ - /* - * actor() private data - */ - union { - void __user *userptr; /* memory to write to */ - struct file *file; /* file to read/write */ - void *data; /* cookie */ - } u; - loff_t pos; /* file position */ - loff_t *opos; /* sendfile: output position */ - size_t num_spliced; /* number of bytes already spliced */ - bool need_wakeup; /* need to wake up writer */ -}; - -struct partial_page { - unsigned int offset; - unsigned int len; - unsigned long private; -}; - -/* - * Passed to splice_to_pipe - */ -struct splice_pipe_desc { - struct page **pages; /* page map */ - struct partial_page *partial; /* pages[] may not be contig */ - int nr_pages; /* number of populated pages in map */ - unsigned int nr_pages_max; /* pages[] & partial[] arrays size */ - unsigned int flags; /* splice flags */ - const struct pipe_buf_operations *ops;/* ops associated with output pipe */ - void (*spd_release)(struct splice_pipe_desc *, unsigned int); -}; - -typedef int (splice_actor)(struct pipe_inode_info *, struct pipe_buffer *, - struct splice_desc *); -typedef int (splice_direct_actor)(struct pipe_inode_info *, - struct splice_desc *); - -extern ssize_t splice_from_pipe(struct pipe_inode_info *, struct file *, - loff_t *, size_t, unsigned int, - splice_actor *); -extern ssize_t __splice_from_pipe(struct pipe_inode_info *, - struct splice_desc *, splice_actor *); -extern ssize_t splice_to_pipe(struct pipe_inode_info *, - struct splice_pipe_desc *); -extern ssize_t add_to_pipe(struct pipe_inode_info *, - struct pipe_buffer *); -extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *, - splice_direct_actor *); - -/* - * for dynamic pipe sizing - */ -extern int splice_grow_spd(const struct pipe_inode_info *, struct splice_pipe_desc *); -extern void splice_shrink_spd(struct splice_pipe_desc *); -extern void spd_release_page(struct splice_pipe_desc *, unsigned int); - -extern const struct pipe_buf_operations page_cache_pipe_buf_ops; -extern const struct pipe_buf_operations default_pipe_buf_ops; -#endif diff --git a/src/linux/include/linux/srcu.h b/src/linux/include/linux/srcu.h deleted file mode 100644 index dc8eb63..0000000 --- a/src/linux/include/linux/srcu.h +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Sleepable Read-Copy Update mechanism for mutual exclusion - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you can access it online at - * http://www.gnu.org/licenses/gpl-2.0.html. - * - * Copyright (C) IBM Corporation, 2006 - * Copyright (C) Fujitsu, 2012 - * - * Author: Paul McKenney - * Lai Jiangshan - * - * For detailed explanation of Read-Copy Update mechanism see - - * Documentation/RCU/ *.txt - * - */ - -#ifndef _LINUX_SRCU_H -#define _LINUX_SRCU_H - -#include -#include -#include - -struct srcu_struct_array { - unsigned long c[2]; - unsigned long seq[2]; -}; - -struct rcu_batch { - struct rcu_head *head, **tail; -}; - -#define RCU_BATCH_INIT(name) { NULL, &(name.head) } - -struct srcu_struct { - unsigned long completed; - struct srcu_struct_array __percpu *per_cpu_ref; - spinlock_t queue_lock; /* protect ->batch_queue, ->running */ - bool running; - /* callbacks just queued */ - struct rcu_batch batch_queue; - /* callbacks try to do the first check_zero */ - struct rcu_batch batch_check0; - /* callbacks done with the first check_zero and the flip */ - struct rcu_batch batch_check1; - struct rcu_batch batch_done; - struct delayed_work work; -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map dep_map; -#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ -}; - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - -int __init_srcu_struct(struct srcu_struct *sp, const char *name, - struct lock_class_key *key); - -#define init_srcu_struct(sp) \ -({ \ - static struct lock_class_key __srcu_key; \ - \ - __init_srcu_struct((sp), #sp, &__srcu_key); \ -}) - -#define __SRCU_DEP_MAP_INIT(srcu_name) .dep_map = { .name = #srcu_name }, -#else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ - -int init_srcu_struct(struct srcu_struct *sp); - -#define __SRCU_DEP_MAP_INIT(srcu_name) -#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ - -void process_srcu(struct work_struct *work); - -#define __SRCU_STRUCT_INIT(name) \ - { \ - .completed = -300, \ - .per_cpu_ref = &name##_srcu_array, \ - .queue_lock = __SPIN_LOCK_UNLOCKED(name.queue_lock), \ - .running = false, \ - .batch_queue = RCU_BATCH_INIT(name.batch_queue), \ - .batch_check0 = RCU_BATCH_INIT(name.batch_check0), \ - .batch_check1 = RCU_BATCH_INIT(name.batch_check1), \ - .batch_done = RCU_BATCH_INIT(name.batch_done), \ - .work = __DELAYED_WORK_INITIALIZER(name.work, process_srcu, 0),\ - __SRCU_DEP_MAP_INIT(name) \ - } - -/* - * Define and initialize a srcu struct at build time. - * Do -not- call init_srcu_struct() nor cleanup_srcu_struct() on it. - * - * Note that although DEFINE_STATIC_SRCU() hides the name from other - * files, the per-CPU variable rules nevertheless require that the - * chosen name be globally unique. These rules also prohibit use of - * DEFINE_STATIC_SRCU() within a function. If these rules are too - * restrictive, declare the srcu_struct manually. For example, in - * each file: - * - * static struct srcu_struct my_srcu; - * - * Then, before the first use of each my_srcu, manually initialize it: - * - * init_srcu_struct(&my_srcu); - * - * See include/linux/percpu-defs.h for the rules on per-CPU variables. - */ -#define __DEFINE_SRCU(name, is_static) \ - static DEFINE_PER_CPU(struct srcu_struct_array, name##_srcu_array);\ - is_static struct srcu_struct name = __SRCU_STRUCT_INIT(name) -#define DEFINE_SRCU(name) __DEFINE_SRCU(name, /* not static */) -#define DEFINE_STATIC_SRCU(name) __DEFINE_SRCU(name, static) - -/** - * call_srcu() - Queue a callback for invocation after an SRCU grace period - * @sp: srcu_struct in queue the callback - * @head: structure to be used for queueing the SRCU callback. - * @func: function to be invoked after the SRCU grace period - * - * The callback function will be invoked some time after a full SRCU - * grace period elapses, in other words after all pre-existing SRCU - * read-side critical sections have completed. However, the callback - * function might well execute concurrently with other SRCU read-side - * critical sections that started after call_srcu() was invoked. SRCU - * read-side critical sections are delimited by srcu_read_lock() and - * srcu_read_unlock(), and may be nested. - * - * The callback will be invoked from process context, but must nevertheless - * be fast and must not block. - */ -void call_srcu(struct srcu_struct *sp, struct rcu_head *head, - void (*func)(struct rcu_head *head)); - -void cleanup_srcu_struct(struct srcu_struct *sp); -int __srcu_read_lock(struct srcu_struct *sp) __acquires(sp); -void __srcu_read_unlock(struct srcu_struct *sp, int idx) __releases(sp); -void synchronize_srcu(struct srcu_struct *sp); -void synchronize_srcu_expedited(struct srcu_struct *sp); -unsigned long srcu_batches_completed(struct srcu_struct *sp); -void srcu_barrier(struct srcu_struct *sp); - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - -/** - * srcu_read_lock_held - might we be in SRCU read-side critical section? - * - * If CONFIG_DEBUG_LOCK_ALLOC is selected, returns nonzero iff in an SRCU - * read-side critical section. In absence of CONFIG_DEBUG_LOCK_ALLOC, - * this assumes we are in an SRCU read-side critical section unless it can - * prove otherwise. - * - * Checks debug_lockdep_rcu_enabled() to prevent false positives during boot - * and while lockdep is disabled. - * - * Note that SRCU is based on its own statemachine and it doesn't - * relies on normal RCU, it can be called from the CPU which - * is in the idle loop from an RCU point of view or offline. - */ -static inline int srcu_read_lock_held(struct srcu_struct *sp) -{ - if (!debug_lockdep_rcu_enabled()) - return 1; - return lock_is_held(&sp->dep_map); -} - -#else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ - -static inline int srcu_read_lock_held(struct srcu_struct *sp) -{ - return 1; -} - -#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ - -/** - * srcu_dereference_check - fetch SRCU-protected pointer for later dereferencing - * @p: the pointer to fetch and protect for later dereferencing - * @sp: pointer to the srcu_struct, which is used to check that we - * really are in an SRCU read-side critical section. - * @c: condition to check for update-side use - * - * If PROVE_RCU is enabled, invoking this outside of an RCU read-side - * critical section will result in an RCU-lockdep splat, unless @c evaluates - * to 1. The @c argument will normally be a logical expression containing - * lockdep_is_held() calls. - */ -#define srcu_dereference_check(p, sp, c) \ - __rcu_dereference_check((p), (c) || srcu_read_lock_held(sp), __rcu) - -/** - * srcu_dereference - fetch SRCU-protected pointer for later dereferencing - * @p: the pointer to fetch and protect for later dereferencing - * @sp: pointer to the srcu_struct, which is used to check that we - * really are in an SRCU read-side critical section. - * - * Makes rcu_dereference_check() do the dirty work. If PROVE_RCU - * is enabled, invoking this outside of an RCU read-side critical - * section will result in an RCU-lockdep splat. - */ -#define srcu_dereference(p, sp) srcu_dereference_check((p), (sp), 0) - -/** - * srcu_read_lock - register a new reader for an SRCU-protected structure. - * @sp: srcu_struct in which to register the new reader. - * - * Enter an SRCU read-side critical section. Note that SRCU read-side - * critical sections may be nested. However, it is illegal to - * call anything that waits on an SRCU grace period for the same - * srcu_struct, whether directly or indirectly. Please note that - * one way to indirectly wait on an SRCU grace period is to acquire - * a mutex that is held elsewhere while calling synchronize_srcu() or - * synchronize_srcu_expedited(). - * - * Note that srcu_read_lock() and the matching srcu_read_unlock() must - * occur in the same context, for example, it is illegal to invoke - * srcu_read_unlock() in an irq handler if the matching srcu_read_lock() - * was invoked in process context. - */ -static inline int srcu_read_lock(struct srcu_struct *sp) __acquires(sp) -{ - int retval; - - preempt_disable(); - retval = __srcu_read_lock(sp); - preempt_enable(); - rcu_lock_acquire(&(sp)->dep_map); - return retval; -} - -/** - * srcu_read_unlock - unregister a old reader from an SRCU-protected structure. - * @sp: srcu_struct in which to unregister the old reader. - * @idx: return value from corresponding srcu_read_lock(). - * - * Exit an SRCU read-side critical section. - */ -static inline void srcu_read_unlock(struct srcu_struct *sp, int idx) - __releases(sp) -{ - rcu_lock_release(&(sp)->dep_map); - __srcu_read_unlock(sp, idx); -} - -/** - * smp_mb__after_srcu_read_unlock - ensure full ordering after srcu_read_unlock - * - * Converts the preceding srcu_read_unlock into a two-way memory barrier. - * - * Call this after srcu_read_unlock, to guarantee that all memory operations - * that occur after smp_mb__after_srcu_read_unlock will appear to happen after - * the preceding srcu_read_unlock. - */ -static inline void smp_mb__after_srcu_read_unlock(void) -{ - /* __srcu_read_unlock has smp_mb() internally so nothing to do here. */ -} - -#endif diff --git a/src/linux/include/linux/stackdepot.h b/src/linux/include/linux/stackdepot.h deleted file mode 100644 index 7978b3e..0000000 --- a/src/linux/include/linux/stackdepot.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * A generic stack depot implementation - * - * Author: Alexander Potapenko - * Copyright (C) 2016 Google, Inc. - * - * Based on code by Dmitry Chernenkov. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _LINUX_STACKDEPOT_H -#define _LINUX_STACKDEPOT_H - -typedef u32 depot_stack_handle_t; - -struct stack_trace; - -depot_stack_handle_t depot_save_stack(struct stack_trace *trace, gfp_t flags); - -void depot_fetch_stack(depot_stack_handle_t handle, struct stack_trace *trace); - -#endif diff --git a/src/linux/include/linux/stackprotector.h b/src/linux/include/linux/stackprotector.h deleted file mode 100644 index 6f3e54c..0000000 --- a/src/linux/include/linux/stackprotector.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _LINUX_STACKPROTECTOR_H -#define _LINUX_STACKPROTECTOR_H 1 - -#include -#include -#include - -#ifdef CONFIG_CC_STACKPROTECTOR -# include -#else -static inline void boot_init_stack_canary(void) -{ -} -#endif - -#endif diff --git a/src/linux/include/linux/stacktrace.h b/src/linux/include/linux/stacktrace.h deleted file mode 100644 index 0a34489..0000000 --- a/src/linux/include/linux/stacktrace.h +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef __LINUX_STACKTRACE_H -#define __LINUX_STACKTRACE_H - -#include - -struct task_struct; -struct pt_regs; - -#ifdef CONFIG_STACKTRACE -struct stack_trace { - unsigned int nr_entries, max_entries; - unsigned long *entries; - int skip; /* input argument: How many entries to skip */ -}; - -extern void save_stack_trace(struct stack_trace *trace); -extern void save_stack_trace_regs(struct pt_regs *regs, - struct stack_trace *trace); -extern void save_stack_trace_tsk(struct task_struct *tsk, - struct stack_trace *trace); - -extern void print_stack_trace(struct stack_trace *trace, int spaces); -extern int snprint_stack_trace(char *buf, size_t size, - struct stack_trace *trace, int spaces); - -#ifdef CONFIG_USER_STACKTRACE_SUPPORT -extern void save_stack_trace_user(struct stack_trace *trace); -#else -# define save_stack_trace_user(trace) do { } while (0) -#endif - -#else -# define save_stack_trace(trace) do { } while (0) -# define save_stack_trace_tsk(tsk, trace) do { } while (0) -# define save_stack_trace_user(trace) do { } while (0) -# define print_stack_trace(trace, spaces) do { } while (0) -# define snprint_stack_trace(buf, size, trace, spaces) do { } while (0) -#endif - -#endif diff --git a/src/linux/include/linux/start_kernel.h b/src/linux/include/linux/start_kernel.h deleted file mode 100644 index d3e5f27..0000000 --- a/src/linux/include/linux/start_kernel.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _LINUX_START_KERNEL_H -#define _LINUX_START_KERNEL_H - -#include -#include - -/* Define the prototype for start_kernel here, rather than cluttering - up something else. */ - -extern asmlinkage void __init start_kernel(void); - -#endif /* _LINUX_START_KERNEL_H */ diff --git a/src/linux/include/linux/stat.h b/src/linux/include/linux/stat.h deleted file mode 100644 index 075cb0c..0000000 --- a/src/linux/include/linux/stat.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef _LINUX_STAT_H -#define _LINUX_STAT_H - - -#include -#include - -#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO) -#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO) -#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH) -#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH) -#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH) - -#define UTIME_NOW ((1l << 30) - 1l) -#define UTIME_OMIT ((1l << 30) - 2l) - -#include -#include -#include - -struct kstat { - u64 ino; - dev_t dev; - umode_t mode; - unsigned int nlink; - kuid_t uid; - kgid_t gid; - dev_t rdev; - loff_t size; - struct timespec atime; - struct timespec mtime; - struct timespec ctime; - unsigned long blksize; - unsigned long long blocks; -}; - -#endif diff --git a/src/linux/include/linux/statfs.h b/src/linux/include/linux/statfs.h deleted file mode 100644 index 0166d32..0000000 --- a/src/linux/include/linux/statfs.h +++ /dev/null @@ -1,43 +0,0 @@ -#ifndef _LINUX_STATFS_H -#define _LINUX_STATFS_H - -#include -#include - -struct kstatfs { - long f_type; - long f_bsize; - u64 f_blocks; - u64 f_bfree; - u64 f_bavail; - u64 f_files; - u64 f_ffree; - __kernel_fsid_t f_fsid; - long f_namelen; - long f_frsize; - long f_flags; - long f_spare[4]; -}; - -/* - * Definitions for the flag in f_flag. - * - * Generally these flags are equivalent to the MS_ flags used in the mount - * ABI. The exception is ST_VALID which has the same value as MS_REMOUNT - * which doesn't make any sense for statfs. - */ -#define ST_RDONLY 0x0001 /* mount read-only */ -#define ST_NOSUID 0x0002 /* ignore suid and sgid bits */ -#define ST_NODEV 0x0004 /* disallow access to device special files */ -#define ST_NOEXEC 0x0008 /* disallow program execution */ -#define ST_SYNCHRONOUS 0x0010 /* writes are synced at once */ -#define ST_VALID 0x0020 /* f_flags support is implemented */ -#define ST_MANDLOCK 0x0040 /* allow mandatory locks on an FS */ -/* 0x0080 used for ST_WRITE in glibc */ -/* 0x0100 used for ST_APPEND in glibc */ -/* 0x0200 used for ST_IMMUTABLE in glibc */ -#define ST_NOATIME 0x0400 /* do not update access times */ -#define ST_NODIRATIME 0x0800 /* do not update directory access times */ -#define ST_RELATIME 0x1000 /* update atime relative to mtime/ctime */ - -#endif diff --git a/src/linux/include/linux/static_key.h b/src/linux/include/linux/static_key.h deleted file mode 100644 index 27bd3f8..0000000 --- a/src/linux/include/linux/static_key.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/src/linux/include/linux/stddef.h b/src/linux/include/linux/stddef.h deleted file mode 100644 index 9c61c7c..0000000 --- a/src/linux/include/linux/stddef.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _LINUX_STDDEF_H -#define _LINUX_STDDEF_H - -#include - -#undef NULL -#define NULL ((void *)0) - -enum { - false = 0, - true = 1 -}; - -#undef offsetof -#ifdef __compiler_offsetof -#define offsetof(TYPE, MEMBER) __compiler_offsetof(TYPE, MEMBER) -#else -#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER) -#endif - -/** - * offsetofend(TYPE, MEMBER) - * - * @TYPE: The type of the structure - * @MEMBER: The member within the structure to get the end offset of - */ -#define offsetofend(TYPE, MEMBER) \ - (offsetof(TYPE, MEMBER) + sizeof(((TYPE *)0)->MEMBER)) - -#endif diff --git a/src/linux/include/linux/stop_machine.h b/src/linux/include/linux/stop_machine.h deleted file mode 100644 index 3cc9632..0000000 --- a/src/linux/include/linux/stop_machine.h +++ /dev/null @@ -1,144 +0,0 @@ -#ifndef _LINUX_STOP_MACHINE -#define _LINUX_STOP_MACHINE - -#include -#include -#include -#include - -/* - * stop_cpu[s]() is simplistic per-cpu maximum priority cpu - * monopolization mechanism. The caller can specify a non-sleeping - * function to be executed on a single or multiple cpus preempting all - * other processes and monopolizing those cpus until it finishes. - * - * Resources for this mechanism are preallocated when a cpu is brought - * up and requests are guaranteed to be served as long as the target - * cpus are online. - */ -typedef int (*cpu_stop_fn_t)(void *arg); - -#ifdef CONFIG_SMP - -struct cpu_stop_work { - struct list_head list; /* cpu_stopper->works */ - cpu_stop_fn_t fn; - void *arg; - struct cpu_stop_done *done; -}; - -int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg); -int stop_two_cpus(unsigned int cpu1, unsigned int cpu2, cpu_stop_fn_t fn, void *arg); -bool stop_one_cpu_nowait(unsigned int cpu, cpu_stop_fn_t fn, void *arg, - struct cpu_stop_work *work_buf); -int stop_cpus(const struct cpumask *cpumask, cpu_stop_fn_t fn, void *arg); -int try_stop_cpus(const struct cpumask *cpumask, cpu_stop_fn_t fn, void *arg); -void stop_machine_park(int cpu); -void stop_machine_unpark(int cpu); - -#else /* CONFIG_SMP */ - -#include - -struct cpu_stop_work { - struct work_struct work; - cpu_stop_fn_t fn; - void *arg; -}; - -static inline int stop_one_cpu(unsigned int cpu, cpu_stop_fn_t fn, void *arg) -{ - int ret = -ENOENT; - preempt_disable(); - if (cpu == smp_processor_id()) - ret = fn(arg); - preempt_enable(); - return ret; -} - -static void stop_one_cpu_nowait_workfn(struct work_struct *work) -{ - struct cpu_stop_work *stwork = - container_of(work, struct cpu_stop_work, work); - preempt_disable(); - stwork->fn(stwork->arg); - preempt_enable(); -} - -static inline bool stop_one_cpu_nowait(unsigned int cpu, - cpu_stop_fn_t fn, void *arg, - struct cpu_stop_work *work_buf) -{ - if (cpu == smp_processor_id()) { - INIT_WORK(&work_buf->work, stop_one_cpu_nowait_workfn); - work_buf->fn = fn; - work_buf->arg = arg; - schedule_work(&work_buf->work); - return true; - } - - return false; -} - -static inline int stop_cpus(const struct cpumask *cpumask, - cpu_stop_fn_t fn, void *arg) -{ - if (cpumask_test_cpu(raw_smp_processor_id(), cpumask)) - return stop_one_cpu(raw_smp_processor_id(), fn, arg); - return -ENOENT; -} - -static inline int try_stop_cpus(const struct cpumask *cpumask, - cpu_stop_fn_t fn, void *arg) -{ - return stop_cpus(cpumask, fn, arg); -} - -#endif /* CONFIG_SMP */ - -/* - * stop_machine "Bogolock": stop the entire machine, disable - * interrupts. This is a very heavy lock, which is equivalent to - * grabbing every spinlock (and more). So the "read" side to such a - * lock is anything which disables preemption. - */ -#if defined(CONFIG_SMP) || defined(CONFIG_HOTPLUG_CPU) - -/** - * stop_machine: freeze the machine on all CPUs and run this function - * @fn: the function to run - * @data: the data ptr for the @fn() - * @cpus: the cpus to run the @fn() on (NULL = any online cpu) - * - * Description: This causes a thread to be scheduled on every cpu, - * each of which disables interrupts. The result is that no one is - * holding a spinlock or inside any other preempt-disabled region when - * @fn() runs. - * - * This can be thought of as a very heavy write lock, equivalent to - * grabbing every spinlock in the kernel. */ -int stop_machine(cpu_stop_fn_t fn, void *data, const struct cpumask *cpus); - -int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data, - const struct cpumask *cpus); -#else /* CONFIG_SMP || CONFIG_HOTPLUG_CPU */ - -static inline int stop_machine(cpu_stop_fn_t fn, void *data, - const struct cpumask *cpus) -{ - unsigned long flags; - int ret; - local_irq_save(flags); - ret = fn(data); - local_irq_restore(flags); - return ret; -} - -static inline int stop_machine_from_inactive_cpu(cpu_stop_fn_t fn, void *data, - const struct cpumask *cpus) -{ - return stop_machine(fn, data, cpus); -} - -#endif /* CONFIG_SMP || CONFIG_HOTPLUG_CPU */ -#endif /* _LINUX_STOP_MACHINE */ diff --git a/src/linux/include/linux/string.h b/src/linux/include/linux/string.h deleted file mode 100644 index 26b6f6a..0000000 --- a/src/linux/include/linux/string.h +++ /dev/null @@ -1,172 +0,0 @@ -#ifndef _LINUX_STRING_H_ -#define _LINUX_STRING_H_ - - -#include /* for inline */ -#include /* for size_t */ -#include /* for NULL */ -#include -#include - -extern char *strndup_user(const char __user *, long); -extern void *memdup_user(const void __user *, size_t); -extern void *memdup_user_nul(const void __user *, size_t); - -/* - * Include machine specific inline routines - */ -#include - -#ifndef __HAVE_ARCH_STRCPY -extern char * strcpy(char *,const char *); -#endif -#ifndef __HAVE_ARCH_STRNCPY -extern char * strncpy(char *,const char *, __kernel_size_t); -#endif -#ifndef __HAVE_ARCH_STRLCPY -size_t strlcpy(char *, const char *, size_t); -#endif -#ifndef __HAVE_ARCH_STRSCPY -ssize_t __must_check strscpy(char *, const char *, size_t); -#endif -#ifndef __HAVE_ARCH_STRCAT -extern char * strcat(char *, const char *); -#endif -#ifndef __HAVE_ARCH_STRNCAT -extern char * strncat(char *, const char *, __kernel_size_t); -#endif -#ifndef __HAVE_ARCH_STRLCAT -extern size_t strlcat(char *, const char *, __kernel_size_t); -#endif -#ifndef __HAVE_ARCH_STRCMP -extern int strcmp(const char *,const char *); -#endif -#ifndef __HAVE_ARCH_STRNCMP -extern int strncmp(const char *,const char *,__kernel_size_t); -#endif -#ifndef __HAVE_ARCH_STRCASECMP -extern int strcasecmp(const char *s1, const char *s2); -#endif -#ifndef __HAVE_ARCH_STRNCASECMP -extern int strncasecmp(const char *s1, const char *s2, size_t n); -#endif -#ifndef __HAVE_ARCH_STRCHR -extern char * strchr(const char *,int); -#endif -#ifndef __HAVE_ARCH_STRCHRNUL -extern char * strchrnul(const char *,int); -#endif -#ifndef __HAVE_ARCH_STRNCHR -extern char * strnchr(const char *, size_t, int); -#endif -#ifndef __HAVE_ARCH_STRRCHR -extern char * strrchr(const char *,int); -#endif -extern char * __must_check skip_spaces(const char *); - -extern char *strim(char *); - -static inline __must_check char *strstrip(char *str) -{ - return strim(str); -} - -#ifndef __HAVE_ARCH_STRSTR -extern char * strstr(const char *, const char *); -#endif -#ifndef __HAVE_ARCH_STRNSTR -extern char * strnstr(const char *, const char *, size_t); -#endif -#ifndef __HAVE_ARCH_STRLEN -extern __kernel_size_t strlen(const char *); -#endif -#ifndef __HAVE_ARCH_STRNLEN -extern __kernel_size_t strnlen(const char *,__kernel_size_t); -#endif -#ifndef __HAVE_ARCH_STRPBRK -extern char * strpbrk(const char *,const char *); -#endif -#ifndef __HAVE_ARCH_STRSEP -extern char * strsep(char **,const char *); -#endif -#ifndef __HAVE_ARCH_STRSPN -extern __kernel_size_t strspn(const char *,const char *); -#endif -#ifndef __HAVE_ARCH_STRCSPN -extern __kernel_size_t strcspn(const char *,const char *); -#endif - -#ifndef __HAVE_ARCH_MEMSET -extern void * memset(void *,int,__kernel_size_t); -#endif -#ifndef __HAVE_ARCH_MEMCPY -extern void * memcpy(void *,const void *,__kernel_size_t); -#endif -#ifndef __HAVE_ARCH_MEMMOVE -extern void * memmove(void *,const void *,__kernel_size_t); -#endif -#ifndef __HAVE_ARCH_MEMSCAN -extern void * memscan(void *,int,__kernel_size_t); -#endif -#ifndef __HAVE_ARCH_MEMCMP -extern int memcmp(const void *,const void *,__kernel_size_t); -#endif -#ifndef __HAVE_ARCH_MEMCHR -extern void * memchr(const void *,int,__kernel_size_t); -#endif -void *memchr_inv(const void *s, int c, size_t n); -char *strreplace(char *s, char old, char new); - -extern void kfree_const(const void *x); - -extern char *kstrdup(const char *s, gfp_t gfp) __malloc; -extern const char *kstrdup_const(const char *s, gfp_t gfp); -extern char *kstrndup(const char *s, size_t len, gfp_t gfp); -extern void *kmemdup(const void *src, size_t len, gfp_t gfp); - -extern char **argv_split(gfp_t gfp, const char *str, int *argcp); -extern void argv_free(char **argv); - -extern bool sysfs_streq(const char *s1, const char *s2); -extern int kstrtobool(const char *s, bool *res); -static inline int strtobool(const char *s, bool *res) -{ - return kstrtobool(s, res); -} - -int match_string(const char * const *array, size_t n, const char *string); - -#ifdef CONFIG_BINARY_PRINTF -int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args); -int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf); -int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...) __printf(3, 4); -#endif - -extern ssize_t memory_read_from_buffer(void *to, size_t count, loff_t *ppos, - const void *from, size_t available); - -/** - * strstarts - does @str start with @prefix? - * @str: string to examine - * @prefix: prefix to look for. - */ -static inline bool strstarts(const char *str, const char *prefix) -{ - return strncmp(str, prefix, strlen(prefix)) == 0; -} - -size_t memweight(const void *ptr, size_t bytes); -void memzero_explicit(void *s, size_t count); - -/** - * kbasename - return the last part of a pathname. - * - * @path: path to extract the filename from. - */ -static inline const char *kbasename(const char *path) -{ - const char *tail = strrchr(path, '/'); - return tail ? tail + 1 : path; -} - -#endif /* _LINUX_STRING_H_ */ diff --git a/src/linux/include/linux/string_helpers.h b/src/linux/include/linux/string_helpers.h deleted file mode 100644 index 5ce9538..0000000 --- a/src/linux/include/linux/string_helpers.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef _LINUX_STRING_HELPERS_H_ -#define _LINUX_STRING_HELPERS_H_ - -#include - -struct file; - -/* Descriptions of the types of units to - * print in */ -enum string_size_units { - STRING_UNITS_10, /* use powers of 10^3 (standard SI) */ - STRING_UNITS_2, /* use binary powers of 2^10 */ -}; - -void string_get_size(u64 size, u64 blk_size, enum string_size_units units, - char *buf, int len); - -#define UNESCAPE_SPACE 0x01 -#define UNESCAPE_OCTAL 0x02 -#define UNESCAPE_HEX 0x04 -#define UNESCAPE_SPECIAL 0x08 -#define UNESCAPE_ANY \ - (UNESCAPE_SPACE | UNESCAPE_OCTAL | UNESCAPE_HEX | UNESCAPE_SPECIAL) - -int string_unescape(char *src, char *dst, size_t size, unsigned int flags); - -static inline int string_unescape_inplace(char *buf, unsigned int flags) -{ - return string_unescape(buf, buf, 0, flags); -} - -static inline int string_unescape_any(char *src, char *dst, size_t size) -{ - return string_unescape(src, dst, size, UNESCAPE_ANY); -} - -static inline int string_unescape_any_inplace(char *buf) -{ - return string_unescape_any(buf, buf, 0); -} - -#define ESCAPE_SPACE 0x01 -#define ESCAPE_SPECIAL 0x02 -#define ESCAPE_NULL 0x04 -#define ESCAPE_OCTAL 0x08 -#define ESCAPE_ANY \ - (ESCAPE_SPACE | ESCAPE_OCTAL | ESCAPE_SPECIAL | ESCAPE_NULL) -#define ESCAPE_NP 0x10 -#define ESCAPE_ANY_NP (ESCAPE_ANY | ESCAPE_NP) -#define ESCAPE_HEX 0x20 - -int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz, - unsigned int flags, const char *only); - -static inline int string_escape_mem_any_np(const char *src, size_t isz, - char *dst, size_t osz, const char *only) -{ - return string_escape_mem(src, isz, dst, osz, ESCAPE_ANY_NP, only); -} - -static inline int string_escape_str(const char *src, char *dst, size_t sz, - unsigned int flags, const char *only) -{ - return string_escape_mem(src, strlen(src), dst, sz, flags, only); -} - -static inline int string_escape_str_any_np(const char *src, char *dst, - size_t sz, const char *only) -{ - return string_escape_str(src, dst, sz, ESCAPE_ANY_NP, only); -} - -char *kstrdup_quotable(const char *src, gfp_t gfp); -char *kstrdup_quotable_cmdline(struct task_struct *task, gfp_t gfp); -char *kstrdup_quotable_file(struct file *file, gfp_t gfp); - -#endif diff --git a/src/linux/include/linux/stringhash.h b/src/linux/include/linux/stringhash.h deleted file mode 100644 index 7c2d951..0000000 --- a/src/linux/include/linux/stringhash.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef __LINUX_STRINGHASH_H -#define __LINUX_STRINGHASH_H - -#include /* For __pure */ -#include /* For u32, u64 */ -#include - -/* - * Routines for hashing strings of bytes to a 32-bit hash value. - * - * These hash functions are NOT GUARANTEED STABLE between kernel - * versions, architectures, or even repeated boots of the same kernel. - * (E.g. they may depend on boot-time hardware detection or be - * deliberately randomized.) - * - * They are also not intended to be secure against collisions caused by - * malicious inputs; much slower hash functions are required for that. - * - * They are optimized for pathname components, meaning short strings. - * Even if a majority of files have longer names, the dynamic profile of - * pathname components skews short due to short directory names. - * (E.g. /usr/lib/libsesquipedalianism.so.3.141.) - */ - -/* - * Version 1: one byte at a time. Example of use: - * - * unsigned long hash = init_name_hash; - * while (*p) - * hash = partial_name_hash(tolower(*p++), hash); - * hash = end_name_hash(hash); - * - * Although this is designed for bytes, fs/hfsplus/unicode.c - * abuses it to hash 16-bit values. - */ - -/* Hash courtesy of the R5 hash in reiserfs modulo sign bits */ -#define init_name_hash(salt) (unsigned long)(salt) - -/* partial hash update function. Assume roughly 4 bits per character */ -static inline unsigned long -partial_name_hash(unsigned long c, unsigned long prevhash) -{ - return (prevhash + (c << 4) + (c >> 4)) * 11; -} - -/* - * Finally: cut down the number of bits to a int value (and try to avoid - * losing bits). This also has the property (wanted by the dcache) - * that the msbits make a good hash table index. - */ -static inline unsigned long end_name_hash(unsigned long hash) -{ - return __hash_32((unsigned int)hash); -} - -/* - * Version 2: One word (32 or 64 bits) at a time. - * If CONFIG_DCACHE_WORD_ACCESS is defined (meaning - * exists, which describes major Linux platforms like x86 and ARM), then - * this computes a different hash function much faster. - * - * If not set, this falls back to a wrapper around the preceding. - */ -extern unsigned int __pure full_name_hash(const void *salt, const char *, unsigned int); - -/* - * A hash_len is a u64 with the hash of a string in the low - * half and the length in the high half. - */ -#define hashlen_hash(hashlen) ((u32)(hashlen)) -#define hashlen_len(hashlen) ((u32)((hashlen) >> 32)) -#define hashlen_create(hash, len) ((u64)(len)<<32 | (u32)(hash)) - -/* Return the "hash_len" (hash and length) of a null-terminated string */ -extern u64 __pure hashlen_string(const void *salt, const char *name); - -#endif /* __LINUX_STRINGHASH_H */ diff --git a/src/linux/include/linux/stringify.h b/src/linux/include/linux/stringify.h deleted file mode 100644 index 841cec8..0000000 --- a/src/linux/include/linux/stringify.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef __LINUX_STRINGIFY_H -#define __LINUX_STRINGIFY_H - -/* Indirect stringification. Doing two levels allows the parameter to be a - * macro itself. For example, compile with -DFOO=bar, __stringify(FOO) - * converts to "bar". - */ - -#define __stringify_1(x...) #x -#define __stringify(x...) __stringify_1(x) - -#endif /* !__LINUX_STRINGIFY_H */ diff --git a/src/linux/include/linux/sunrpc/auth.h b/src/linux/include/linux/sunrpc/auth.h deleted file mode 100644 index b1bc62b..0000000 --- a/src/linux/include/linux/sunrpc/auth.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - * linux/include/linux/sunrpc/auth.h - * - * Declarations for the RPC client authentication machinery. - * - * Copyright (C) 1996, Olaf Kirch - */ - -#ifndef _LINUX_SUNRPC_AUTH_H -#define _LINUX_SUNRPC_AUTH_H - -#ifdef __KERNEL__ - -#include -#include -#include - -#include -#include -#include -#include - -/* - * Maximum size of AUTH_NONE authentication information, in XDR words. - */ -#define NUL_CALLSLACK (4) -#define NUL_REPLYSLACK (2) - -/* - * Size of the nodename buffer. RFC1831 specifies a hard limit of 255 bytes, - * but Linux hostnames are actually limited to __NEW_UTS_LEN bytes. - */ -#define UNX_MAXNODENAME __NEW_UTS_LEN -#define UNX_CALLSLACK (21 + XDR_QUADLEN(UNX_MAXNODENAME)) - -struct rpcsec_gss_info; - -/* auth_cred ac_flags bits */ -enum { - RPC_CRED_KEY_EXPIRE_SOON = 1, /* underlying cred key will expire soon */ - RPC_CRED_NOTIFY_TIMEOUT = 2, /* nofity generic cred when underlying - key will expire soon */ -}; - -/* Work around the lack of a VFS credential */ -struct auth_cred { - kuid_t uid; - kgid_t gid; - struct group_info *group_info; - const char *principal; - unsigned long ac_flags; - unsigned char machine_cred : 1; -}; - -/* - * Client user credentials - */ -struct rpc_auth; -struct rpc_credops; -struct rpc_cred { - struct hlist_node cr_hash; /* hash chain */ - struct list_head cr_lru; /* lru garbage collection */ - struct rcu_head cr_rcu; - struct rpc_auth * cr_auth; - const struct rpc_credops *cr_ops; -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) - unsigned long cr_magic; /* 0x0f4aa4f0 */ -#endif - unsigned long cr_expire; /* when to gc */ - unsigned long cr_flags; /* various flags */ - atomic_t cr_count; /* ref count */ - - kuid_t cr_uid; - - /* per-flavor data */ -}; -#define RPCAUTH_CRED_NEW 0 -#define RPCAUTH_CRED_UPTODATE 1 -#define RPCAUTH_CRED_HASHED 2 -#define RPCAUTH_CRED_NEGATIVE 3 - -#define RPCAUTH_CRED_MAGIC 0x0f4aa4f0 - -/* rpc_auth au_flags */ -#define RPCAUTH_AUTH_NO_CRKEY_TIMEOUT 0x0001 /* underlying cred has no key timeout */ - -/* - * Client authentication handle - */ -struct rpc_cred_cache; -struct rpc_authops; -struct rpc_auth { - unsigned int au_cslack; /* call cred size estimate */ - /* guess at number of u32's auth adds before - * reply data; normally the verifier size: */ - unsigned int au_rslack; - /* for gss, used to calculate au_rslack: */ - unsigned int au_verfsize; - - unsigned int au_flags; /* various flags */ - const struct rpc_authops *au_ops; /* operations */ - rpc_authflavor_t au_flavor; /* pseudoflavor (note may - * differ from the flavor in - * au_ops->au_flavor in gss - * case) */ - atomic_t au_count; /* Reference counter */ - - struct rpc_cred_cache * au_credcache; - /* per-flavor data */ -}; - -/* rpc_auth au_flags */ -#define RPCAUTH_AUTH_DATATOUCH 0x00000002 - -struct rpc_auth_create_args { - rpc_authflavor_t pseudoflavor; - const char *target_name; -}; - -/* Flags for rpcauth_lookupcred() */ -#define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */ -#define RPCAUTH_LOOKUP_RCU 0x02 /* lock-less lookup */ - -/* - * Client authentication ops - */ -struct rpc_authops { - struct module *owner; - rpc_authflavor_t au_flavor; /* flavor (RPC_AUTH_*) */ - char * au_name; - struct rpc_auth * (*create)(struct rpc_auth_create_args *, struct rpc_clnt *); - void (*destroy)(struct rpc_auth *); - - int (*hash_cred)(struct auth_cred *, unsigned int); - struct rpc_cred * (*lookup_cred)(struct rpc_auth *, struct auth_cred *, int); - struct rpc_cred * (*crcreate)(struct rpc_auth*, struct auth_cred *, int, gfp_t); - int (*list_pseudoflavors)(rpc_authflavor_t *, int); - rpc_authflavor_t (*info2flavor)(struct rpcsec_gss_info *); - int (*flavor2info)(rpc_authflavor_t, - struct rpcsec_gss_info *); - int (*key_timeout)(struct rpc_auth *, - struct rpc_cred *); -}; - -struct rpc_credops { - const char * cr_name; /* Name of the auth flavour */ - int (*cr_init)(struct rpc_auth *, struct rpc_cred *); - void (*crdestroy)(struct rpc_cred *); - - int (*crmatch)(struct auth_cred *, struct rpc_cred *, int); - struct rpc_cred * (*crbind)(struct rpc_task *, struct rpc_cred *, int); - __be32 * (*crmarshal)(struct rpc_task *, __be32 *); - int (*crrefresh)(struct rpc_task *); - __be32 * (*crvalidate)(struct rpc_task *, __be32 *); - int (*crwrap_req)(struct rpc_task *, kxdreproc_t, - void *, __be32 *, void *); - int (*crunwrap_resp)(struct rpc_task *, kxdrdproc_t, - void *, __be32 *, void *); - int (*crkey_timeout)(struct rpc_cred *); - bool (*crkey_to_expire)(struct rpc_cred *); - char * (*crstringify_acceptor)(struct rpc_cred *); -}; - -extern const struct rpc_authops authunix_ops; -extern const struct rpc_authops authnull_ops; - -int __init rpc_init_authunix(void); -int __init rpc_init_generic_auth(void); -int __init rpcauth_init_module(void); -void rpcauth_remove_module(void); -void rpc_destroy_generic_auth(void); -void rpc_destroy_authunix(void); - -struct rpc_cred * rpc_lookup_cred(void); -struct rpc_cred * rpc_lookup_cred_nonblock(void); -struct rpc_cred * rpc_lookup_generic_cred(struct auth_cred *, int, gfp_t); -struct rpc_cred * rpc_lookup_machine_cred(const char *service_name); -int rpcauth_register(const struct rpc_authops *); -int rpcauth_unregister(const struct rpc_authops *); -struct rpc_auth * rpcauth_create(struct rpc_auth_create_args *, - struct rpc_clnt *); -void rpcauth_release(struct rpc_auth *); -rpc_authflavor_t rpcauth_get_pseudoflavor(rpc_authflavor_t, - struct rpcsec_gss_info *); -int rpcauth_get_gssinfo(rpc_authflavor_t, - struct rpcsec_gss_info *); -int rpcauth_list_flavors(rpc_authflavor_t *, int); -struct rpc_cred * rpcauth_lookup_credcache(struct rpc_auth *, struct auth_cred *, int, gfp_t); -void rpcauth_init_cred(struct rpc_cred *, const struct auth_cred *, struct rpc_auth *, const struct rpc_credops *); -struct rpc_cred * rpcauth_lookupcred(struct rpc_auth *, int); -struct rpc_cred * rpcauth_generic_bind_cred(struct rpc_task *, struct rpc_cred *, int); -void put_rpccred(struct rpc_cred *); -__be32 * rpcauth_marshcred(struct rpc_task *, __be32 *); -__be32 * rpcauth_checkverf(struct rpc_task *, __be32 *); -int rpcauth_wrap_req(struct rpc_task *task, kxdreproc_t encode, void *rqstp, __be32 *data, void *obj); -int rpcauth_unwrap_resp(struct rpc_task *task, kxdrdproc_t decode, void *rqstp, __be32 *data, void *obj); -int rpcauth_refreshcred(struct rpc_task *); -void rpcauth_invalcred(struct rpc_task *); -int rpcauth_uptodatecred(struct rpc_task *); -int rpcauth_init_credcache(struct rpc_auth *); -void rpcauth_destroy_credcache(struct rpc_auth *); -void rpcauth_clear_credcache(struct rpc_cred_cache *); -int rpcauth_key_timeout_notify(struct rpc_auth *, - struct rpc_cred *); -bool rpcauth_cred_key_to_expire(struct rpc_auth *, struct rpc_cred *); -char * rpcauth_stringify_acceptor(struct rpc_cred *); - -static inline -struct rpc_cred * get_rpccred(struct rpc_cred *cred) -{ - if (cred != NULL) - atomic_inc(&cred->cr_count); - return cred; -} - -/** - * get_rpccred_rcu - get a reference to a cred using rcu-protected pointer - * @cred: cred of which to take a reference - * - * In some cases, we may have a pointer to a credential to which we - * want to take a reference, but don't already have one. Because these - * objects are freed using RCU, we can access the cr_count while its - * on its way to destruction and only take a reference if it's not already - * zero. - */ -static inline struct rpc_cred * -get_rpccred_rcu(struct rpc_cred *cred) -{ - if (atomic_inc_not_zero(&cred->cr_count)) - return cred; - return NULL; -} - -#endif /* __KERNEL__ */ -#endif /* _LINUX_SUNRPC_AUTH_H */ diff --git a/src/linux/include/linux/sunrpc/clnt.h b/src/linux/include/linux/sunrpc/clnt.h deleted file mode 100644 index 85cc819..0000000 --- a/src/linux/include/linux/sunrpc/clnt.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - * linux/include/linux/sunrpc/clnt.h - * - * Declarations for the high-level RPC client interface - * - * Copyright (C) 1995, 1996, Olaf Kirch - */ - -#ifndef _LINUX_SUNRPC_CLNT_H -#define _LINUX_SUNRPC_CLNT_H - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct rpc_inode; - -/* - * The high-level client handle - */ -struct rpc_clnt { - atomic_t cl_count; /* Number of references */ - unsigned int cl_clid; /* client id */ - struct list_head cl_clients; /* Global list of clients */ - struct list_head cl_tasks; /* List of tasks */ - spinlock_t cl_lock; /* spinlock */ - struct rpc_xprt __rcu * cl_xprt; /* transport */ - struct rpc_procinfo * cl_procinfo; /* procedure info */ - u32 cl_prog, /* RPC program number */ - cl_vers, /* RPC version number */ - cl_maxproc; /* max procedure number */ - - struct rpc_auth * cl_auth; /* authenticator */ - struct rpc_stat * cl_stats; /* per-program statistics */ - struct rpc_iostats * cl_metrics; /* per-client statistics */ - - unsigned int cl_softrtry : 1,/* soft timeouts */ - cl_discrtry : 1,/* disconnect before retry */ - cl_noretranstimeo: 1,/* No retransmit timeouts */ - cl_autobind : 1,/* use getport() */ - cl_chatty : 1;/* be verbose */ - - struct rpc_rtt * cl_rtt; /* RTO estimator data */ - const struct rpc_timeout *cl_timeout; /* Timeout strategy */ - - atomic_t cl_swapper; /* swapfile count */ - int cl_nodelen; /* nodename length */ - char cl_nodename[UNX_MAXNODENAME+1]; - struct rpc_pipe_dir_head cl_pipedir_objects; - struct rpc_clnt * cl_parent; /* Points to parent of clones */ - struct rpc_rtt cl_rtt_default; - struct rpc_timeout cl_timeout_default; - const struct rpc_program *cl_program; -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) - struct dentry *cl_debugfs; /* debugfs directory */ -#endif - struct rpc_xprt_iter cl_xpi; -}; - -/* - * General RPC program info - */ -#define RPC_MAXVERSION 4 -struct rpc_program { - const char * name; /* protocol name */ - u32 number; /* program number */ - unsigned int nrvers; /* number of versions */ - const struct rpc_version ** version; /* version array */ - struct rpc_stat * stats; /* statistics */ - const char * pipe_dir_name; /* path to rpc_pipefs dir */ -}; - -struct rpc_version { - u32 number; /* version number */ - unsigned int nrprocs; /* number of procs */ - struct rpc_procinfo * procs; /* procedure array */ -}; - -/* - * Procedure information - */ -struct rpc_procinfo { - u32 p_proc; /* RPC procedure number */ - kxdreproc_t p_encode; /* XDR encode function */ - kxdrdproc_t p_decode; /* XDR decode function */ - unsigned int p_arglen; /* argument hdr length (u32) */ - unsigned int p_replen; /* reply hdr length (u32) */ - unsigned int p_count; /* call count */ - unsigned int p_timer; /* Which RTT timer to use */ - u32 p_statidx; /* Which procedure to account */ - const char * p_name; /* name of procedure */ -}; - -#ifdef __KERNEL__ - -struct rpc_create_args { - struct net *net; - int protocol; - struct sockaddr *address; - size_t addrsize; - struct sockaddr *saddress; - const struct rpc_timeout *timeout; - const char *servername; - const char *nodename; - const struct rpc_program *program; - u32 prognumber; /* overrides program->number */ - u32 version; - rpc_authflavor_t authflavor; - unsigned long flags; - char *client_name; - struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */ -}; - -struct rpc_add_xprt_test { - int (*add_xprt_test)(struct rpc_clnt *, - struct rpc_xprt *, - void *calldata); - void *data; -}; - -/* Values for "flags" field */ -#define RPC_CLNT_CREATE_HARDRTRY (1UL << 0) -#define RPC_CLNT_CREATE_AUTOBIND (1UL << 2) -#define RPC_CLNT_CREATE_NONPRIVPORT (1UL << 3) -#define RPC_CLNT_CREATE_NOPING (1UL << 4) -#define RPC_CLNT_CREATE_DISCRTRY (1UL << 5) -#define RPC_CLNT_CREATE_QUIET (1UL << 6) -#define RPC_CLNT_CREATE_INFINITE_SLOTS (1UL << 7) -#define RPC_CLNT_CREATE_NO_IDLE_TIMEOUT (1UL << 8) -#define RPC_CLNT_CREATE_NO_RETRANS_TIMEOUT (1UL << 9) - -struct rpc_clnt *rpc_create(struct rpc_create_args *args); -struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, - const struct rpc_program *, u32); -struct rpc_clnt *rpc_clone_client(struct rpc_clnt *); -struct rpc_clnt *rpc_clone_client_set_auth(struct rpc_clnt *, - rpc_authflavor_t); -int rpc_switch_client_transport(struct rpc_clnt *, - struct xprt_create *, - const struct rpc_timeout *); - -void rpc_shutdown_client(struct rpc_clnt *); -void rpc_release_client(struct rpc_clnt *); -void rpc_task_release_client(struct rpc_task *); - -int rpcb_create_local(struct net *); -void rpcb_put_local(struct net *); -int rpcb_register(struct net *, u32, u32, int, unsigned short); -int rpcb_v4_register(struct net *net, const u32 program, - const u32 version, - const struct sockaddr *address, - const char *netid); -void rpcb_getport_async(struct rpc_task *); - -void rpc_call_start(struct rpc_task *); -int rpc_call_async(struct rpc_clnt *clnt, - const struct rpc_message *msg, int flags, - const struct rpc_call_ops *tk_ops, - void *calldata); -int rpc_call_sync(struct rpc_clnt *clnt, - const struct rpc_message *msg, int flags); -struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, - int flags); -int rpc_restart_call_prepare(struct rpc_task *); -int rpc_restart_call(struct rpc_task *); -void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); -int rpc_protocol(struct rpc_clnt *); -struct net * rpc_net_ns(struct rpc_clnt *); -size_t rpc_max_payload(struct rpc_clnt *); -size_t rpc_max_bc_payload(struct rpc_clnt *); -unsigned long rpc_get_timeout(struct rpc_clnt *clnt); -void rpc_force_rebind(struct rpc_clnt *); -size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); -const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t); -int rpc_localaddr(struct rpc_clnt *, struct sockaddr *, size_t); - -int rpc_clnt_iterate_for_each_xprt(struct rpc_clnt *clnt, - int (*fn)(struct rpc_clnt *, struct rpc_xprt *, void *), - void *data); - -int rpc_clnt_test_and_add_xprt(struct rpc_clnt *clnt, - struct rpc_xprt_switch *xps, - struct rpc_xprt *xprt, - void *dummy); -int rpc_clnt_add_xprt(struct rpc_clnt *, struct xprt_create *, - int (*setup)(struct rpc_clnt *, - struct rpc_xprt_switch *, - struct rpc_xprt *, - void *), - void *data); -void rpc_cap_max_reconnect_timeout(struct rpc_clnt *clnt, - unsigned long timeo); - -int rpc_clnt_setup_test_and_add_xprt(struct rpc_clnt *, - struct rpc_xprt_switch *, - struct rpc_xprt *, - void *); - -const char *rpc_proc_name(const struct rpc_task *task); - -void rpc_clnt_xprt_switch_put(struct rpc_clnt *); -void rpc_clnt_xprt_switch_add_xprt(struct rpc_clnt *, struct rpc_xprt *); -bool rpc_clnt_xprt_switch_has_addr(struct rpc_clnt *clnt, - const struct sockaddr *sap); -#endif /* __KERNEL__ */ -#endif /* _LINUX_SUNRPC_CLNT_H */ diff --git a/src/linux/include/linux/sunrpc/debug.h b/src/linux/include/linux/sunrpc/debug.h deleted file mode 100644 index 59a7889..0000000 --- a/src/linux/include/linux/sunrpc/debug.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * linux/include/linux/sunrpc/debug.h - * - * Debugging support for sunrpc module - * - * Copyright (C) 1996, Olaf Kirch - */ -#ifndef _LINUX_SUNRPC_DEBUG_H_ -#define _LINUX_SUNRPC_DEBUG_H_ - -#include - -/* - * Debugging macros etc - */ -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) -extern unsigned int rpc_debug; -extern unsigned int nfs_debug; -extern unsigned int nfsd_debug; -extern unsigned int nlm_debug; -#endif - -#define dprintk(args...) dfprintk(FACILITY, ## args) -#define dprintk_rcu(args...) dfprintk_rcu(FACILITY, ## args) - -#undef ifdebug -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) -# define ifdebug(fac) if (unlikely(rpc_debug & RPCDBG_##fac)) - -# define dfprintk(fac, args...) \ - do { \ - ifdebug(fac) \ - printk(KERN_DEFAULT args); \ - } while (0) - -# define dfprintk_rcu(fac, args...) \ - do { \ - ifdebug(fac) { \ - rcu_read_lock(); \ - printk(KERN_DEFAULT args); \ - rcu_read_unlock(); \ - } \ - } while (0) - -# define RPC_IFDEBUG(x) x -#else -# define ifdebug(fac) if (0) -# define dfprintk(fac, args...) do {} while (0) -# define dfprintk_rcu(fac, args...) do {} while (0) -# define RPC_IFDEBUG(x) -#endif - -/* - * Sysctl interface for RPC debugging - */ - -struct rpc_clnt; -struct rpc_xprt; - -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) -void rpc_register_sysctl(void); -void rpc_unregister_sysctl(void); -void sunrpc_debugfs_init(void); -void sunrpc_debugfs_exit(void); -void rpc_clnt_debugfs_register(struct rpc_clnt *); -void rpc_clnt_debugfs_unregister(struct rpc_clnt *); -void rpc_xprt_debugfs_register(struct rpc_xprt *); -void rpc_xprt_debugfs_unregister(struct rpc_xprt *); -#else -static inline void -sunrpc_debugfs_init(void) -{ - return; -} - -static inline void -sunrpc_debugfs_exit(void) -{ - return; -} - -static inline void -rpc_clnt_debugfs_register(struct rpc_clnt *clnt) -{ - return; -} - -static inline void -rpc_clnt_debugfs_unregister(struct rpc_clnt *clnt) -{ - return; -} - -static inline void -rpc_xprt_debugfs_register(struct rpc_xprt *xprt) -{ - return; -} - -static inline void -rpc_xprt_debugfs_unregister(struct rpc_xprt *xprt) -{ - return; -} -#endif - -#endif /* _LINUX_SUNRPC_DEBUG_H_ */ diff --git a/src/linux/include/linux/sunrpc/gss_api.h b/src/linux/include/linux/sunrpc/gss_api.h deleted file mode 100644 index 68ec78c..0000000 --- a/src/linux/include/linux/sunrpc/gss_api.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * linux/include/linux/sunrpc/gss_api.h - * - * Somewhat simplified version of the gss api. - * - * Dug Song - * Andy Adamson - * Bruce Fields - * Copyright (c) 2000 The Regents of the University of Michigan - */ - -#ifndef _LINUX_SUNRPC_GSS_API_H -#define _LINUX_SUNRPC_GSS_API_H - -#ifdef __KERNEL__ -#include -#include -#include - -/* The mechanism-independent gss-api context: */ -struct gss_ctx { - struct gss_api_mech *mech_type; - void *internal_ctx_id; -}; - -#define GSS_C_NO_BUFFER ((struct xdr_netobj) 0) -#define GSS_C_NO_CONTEXT ((struct gss_ctx *) 0) -#define GSS_C_QOP_DEFAULT (0) - -/*XXX arbitrary length - is this set somewhere? */ -#define GSS_OID_MAX_LEN 32 -struct rpcsec_gss_oid { - unsigned int len; - u8 data[GSS_OID_MAX_LEN]; -}; - -/* From RFC 3530 */ -struct rpcsec_gss_info { - struct rpcsec_gss_oid oid; - u32 qop; - u32 service; -}; - -/* gss-api prototypes; note that these are somewhat simplified versions of - * the prototypes specified in RFC 2744. */ -int gss_import_sec_context( - const void* input_token, - size_t bufsize, - struct gss_api_mech *mech, - struct gss_ctx **ctx_id, - time_t *endtime, - gfp_t gfp_mask); -u32 gss_get_mic( - struct gss_ctx *ctx_id, - struct xdr_buf *message, - struct xdr_netobj *mic_token); -u32 gss_verify_mic( - struct gss_ctx *ctx_id, - struct xdr_buf *message, - struct xdr_netobj *mic_token); -u32 gss_wrap( - struct gss_ctx *ctx_id, - int offset, - struct xdr_buf *outbuf, - struct page **inpages); -u32 gss_unwrap( - struct gss_ctx *ctx_id, - int offset, - struct xdr_buf *inbuf); -u32 gss_delete_sec_context( - struct gss_ctx **ctx_id); - -rpc_authflavor_t gss_svc_to_pseudoflavor(struct gss_api_mech *, u32 qop, - u32 service); -u32 gss_pseudoflavor_to_service(struct gss_api_mech *, u32 pseudoflavor); -bool gss_pseudoflavor_to_datatouch(struct gss_api_mech *, u32 pseudoflavor); -char *gss_service_to_auth_domain_name(struct gss_api_mech *, u32 service); - -struct pf_desc { - u32 pseudoflavor; - u32 qop; - u32 service; - char *name; - char *auth_domain_name; - bool datatouch; -}; - -/* Different mechanisms (e.g., krb5 or spkm3) may implement gss-api, and - * mechanisms may be dynamically registered or unregistered by modules. */ - -/* Each mechanism is described by the following struct: */ -struct gss_api_mech { - struct list_head gm_list; - struct module *gm_owner; - struct rpcsec_gss_oid gm_oid; - char *gm_name; - const struct gss_api_ops *gm_ops; - /* pseudoflavors supported by this mechanism: */ - int gm_pf_num; - struct pf_desc * gm_pfs; - /* Should the following be a callback operation instead? */ - const char *gm_upcall_enctypes; -}; - -/* and must provide the following operations: */ -struct gss_api_ops { - int (*gss_import_sec_context)( - const void *input_token, - size_t bufsize, - struct gss_ctx *ctx_id, - time_t *endtime, - gfp_t gfp_mask); - u32 (*gss_get_mic)( - struct gss_ctx *ctx_id, - struct xdr_buf *message, - struct xdr_netobj *mic_token); - u32 (*gss_verify_mic)( - struct gss_ctx *ctx_id, - struct xdr_buf *message, - struct xdr_netobj *mic_token); - u32 (*gss_wrap)( - struct gss_ctx *ctx_id, - int offset, - struct xdr_buf *outbuf, - struct page **inpages); - u32 (*gss_unwrap)( - struct gss_ctx *ctx_id, - int offset, - struct xdr_buf *buf); - void (*gss_delete_sec_context)( - void *internal_ctx_id); -}; - -int gss_mech_register(struct gss_api_mech *); -void gss_mech_unregister(struct gss_api_mech *); - -/* returns a mechanism descriptor given an OID, and increments the mechanism's - * reference count. */ -struct gss_api_mech * gss_mech_get_by_OID(struct rpcsec_gss_oid *); - -/* Given a GSS security tuple, look up a pseudoflavor */ -rpc_authflavor_t gss_mech_info2flavor(struct rpcsec_gss_info *); - -/* Given a pseudoflavor, look up a GSS security tuple */ -int gss_mech_flavor2info(rpc_authflavor_t, struct rpcsec_gss_info *); - -/* Returns a reference to a mechanism, given a name like "krb5" etc. */ -struct gss_api_mech *gss_mech_get_by_name(const char *); - -/* Similar, but get by pseudoflavor. */ -struct gss_api_mech *gss_mech_get_by_pseudoflavor(u32); - -/* Fill in an array with a list of supported pseudoflavors */ -int gss_mech_list_pseudoflavors(rpc_authflavor_t *, int); - -struct gss_api_mech * gss_mech_get(struct gss_api_mech *); - -/* For every successful gss_mech_get or gss_mech_get_by_* call there must be a - * corresponding call to gss_mech_put. */ -void gss_mech_put(struct gss_api_mech *); - -#endif /* __KERNEL__ */ -#endif /* _LINUX_SUNRPC_GSS_API_H */ - diff --git a/src/linux/include/linux/sunrpc/msg_prot.h b/src/linux/include/linux/sunrpc/msg_prot.h deleted file mode 100644 index 59cbf16..0000000 --- a/src/linux/include/linux/sunrpc/msg_prot.h +++ /dev/null @@ -1,220 +0,0 @@ -/* - * linux/include/linux/sunrpc/msg_prot.h - * - * Copyright (C) 1996, Olaf Kirch - */ - -#ifndef _LINUX_SUNRPC_MSGPROT_H_ -#define _LINUX_SUNRPC_MSGPROT_H_ - -#ifdef __KERNEL__ /* user programs should get these from the rpc header files */ - -#define RPC_VERSION 2 - -/* size of an XDR encoding unit in bytes, i.e. 32bit */ -#define XDR_UNIT (4) - -/* spec defines authentication flavor as an unsigned 32 bit integer */ -typedef u32 rpc_authflavor_t; - -enum rpc_auth_flavors { - RPC_AUTH_NULL = 0, - RPC_AUTH_UNIX = 1, - RPC_AUTH_SHORT = 2, - RPC_AUTH_DES = 3, - RPC_AUTH_KRB = 4, - RPC_AUTH_GSS = 6, - RPC_AUTH_MAXFLAVOR = 8, - /* pseudoflavors: */ - RPC_AUTH_GSS_KRB5 = 390003, - RPC_AUTH_GSS_KRB5I = 390004, - RPC_AUTH_GSS_KRB5P = 390005, - RPC_AUTH_GSS_LKEY = 390006, - RPC_AUTH_GSS_LKEYI = 390007, - RPC_AUTH_GSS_LKEYP = 390008, - RPC_AUTH_GSS_SPKM = 390009, - RPC_AUTH_GSS_SPKMI = 390010, - RPC_AUTH_GSS_SPKMP = 390011, -}; - -/* Maximum size (in bytes) of an rpc credential or verifier */ -#define RPC_MAX_AUTH_SIZE (400) - -enum rpc_msg_type { - RPC_CALL = 0, - RPC_REPLY = 1 -}; - -enum rpc_reply_stat { - RPC_MSG_ACCEPTED = 0, - RPC_MSG_DENIED = 1 -}; - -enum rpc_accept_stat { - RPC_SUCCESS = 0, - RPC_PROG_UNAVAIL = 1, - RPC_PROG_MISMATCH = 2, - RPC_PROC_UNAVAIL = 3, - RPC_GARBAGE_ARGS = 4, - RPC_SYSTEM_ERR = 5, - /* internal use only */ - RPC_DROP_REPLY = 60000, -}; - -enum rpc_reject_stat { - RPC_MISMATCH = 0, - RPC_AUTH_ERROR = 1 -}; - -enum rpc_auth_stat { - RPC_AUTH_OK = 0, - RPC_AUTH_BADCRED = 1, - RPC_AUTH_REJECTEDCRED = 2, - RPC_AUTH_BADVERF = 3, - RPC_AUTH_REJECTEDVERF = 4, - RPC_AUTH_TOOWEAK = 5, - /* RPCSEC_GSS errors */ - RPCSEC_GSS_CREDPROBLEM = 13, - RPCSEC_GSS_CTXPROBLEM = 14 -}; - -#define RPC_MAXNETNAMELEN 256 - -/* - * From RFC 1831: - * - * "A record is composed of one or more record fragments. A record - * fragment is a four-byte header followed by 0 to (2**31) - 1 bytes of - * fragment data. The bytes encode an unsigned binary number; as with - * XDR integers, the byte order is from highest to lowest. The number - * encodes two values -- a boolean which indicates whether the fragment - * is the last fragment of the record (bit value 1 implies the fragment - * is the last fragment) and a 31-bit unsigned binary value which is the - * length in bytes of the fragment's data. The boolean value is the - * highest-order bit of the header; the length is the 31 low-order bits. - * (Note that this record specification is NOT in XDR standard form!)" - * - * The Linux RPC client always sends its requests in a single record - * fragment, limiting the maximum payload size for stream transports to - * 2GB. - */ - -typedef __be32 rpc_fraghdr; - -#define RPC_LAST_STREAM_FRAGMENT (1U << 31) -#define RPC_FRAGMENT_SIZE_MASK (~RPC_LAST_STREAM_FRAGMENT) -#define RPC_MAX_FRAGMENT_SIZE ((1U << 31) - 1) - -/* - * RPC call and reply header size as number of 32bit words (verifier - * size computed separately, see below) - */ -#define RPC_CALLHDRSIZE (6) -#define RPC_REPHDRSIZE (4) - - -/* - * Maximum RPC header size, including authentication, - * as number of 32bit words (see RFCs 1831, 1832). - * - * xid 1 xdr unit = 4 bytes - * mtype 1 - * rpc_version 1 - * program 1 - * prog_version 1 - * procedure 1 - * cred { - * flavor 1 - * length 1 - * body 100 xdr units = 400 bytes - * } - * verf { - * flavor 1 - * length 1 - * body 100 xdr units = 400 bytes - * } - * TOTAL 210 xdr units = 840 bytes - */ -#define RPC_MAX_HEADER_WITH_AUTH \ - (RPC_CALLHDRSIZE + 2*(2+RPC_MAX_AUTH_SIZE/4)) - -#define RPC_MAX_REPHEADER_WITH_AUTH \ - (RPC_REPHDRSIZE + (2 + RPC_MAX_AUTH_SIZE/4)) - -/* - * Well-known netids. See: - * - * http://www.iana.org/assignments/rpc-netids/rpc-netids.xhtml - */ -#define RPCBIND_NETID_UDP "udp" -#define RPCBIND_NETID_TCP "tcp" -#define RPCBIND_NETID_RDMA "rdma" -#define RPCBIND_NETID_SCTP "sctp" -#define RPCBIND_NETID_UDP6 "udp6" -#define RPCBIND_NETID_TCP6 "tcp6" -#define RPCBIND_NETID_RDMA6 "rdma6" -#define RPCBIND_NETID_SCTP6 "sctp6" -#define RPCBIND_NETID_LOCAL "local" - -/* - * Note that RFC 1833 does not put any size restrictions on the - * netid string, but all currently defined netid's fit in 5 bytes. - */ -#define RPCBIND_MAXNETIDLEN (5u) - -/* - * Universal addresses are introduced in RFC 1833 and further spelled - * out in RFC 3530. RPCBIND_MAXUADDRLEN defines a maximum byte length - * of a universal address for use in allocating buffers and character - * arrays. - * - * Quoting RFC 3530, section 2.2: - * - * For TCP over IPv4 and for UDP over IPv4, the format of r_addr is the - * US-ASCII string: - * - * h1.h2.h3.h4.p1.p2 - * - * The prefix, "h1.h2.h3.h4", is the standard textual form for - * representing an IPv4 address, which is always four octets long. - * Assuming big-endian ordering, h1, h2, h3, and h4, are respectively, - * the first through fourth octets each converted to ASCII-decimal. - * Assuming big-endian ordering, p1 and p2 are, respectively, the first - * and second octets each converted to ASCII-decimal. For example, if a - * host, in big-endian order, has an address of 0x0A010307 and there is - * a service listening on, in big endian order, port 0x020F (decimal - * 527), then the complete universal address is "10.1.3.7.2.15". - * - * ... - * - * For TCP over IPv6 and for UDP over IPv6, the format of r_addr is the - * US-ASCII string: - * - * x1:x2:x3:x4:x5:x6:x7:x8.p1.p2 - * - * The suffix "p1.p2" is the service port, and is computed the same way - * as with universal addresses for TCP and UDP over IPv4. The prefix, - * "x1:x2:x3:x4:x5:x6:x7:x8", is the standard textual form for - * representing an IPv6 address as defined in Section 2.2 of [RFC2373]. - * Additionally, the two alternative forms specified in Section 2.2 of - * [RFC2373] are also acceptable. - */ - -#include - -/* Maximum size of the port number part of a universal address */ -#define RPCBIND_MAXUADDRPLEN sizeof(".255.255") - -/* Maximum size of an IPv4 universal address */ -#define RPCBIND_MAXUADDR4LEN \ - (INET_ADDRSTRLEN + RPCBIND_MAXUADDRPLEN) - -/* Maximum size of an IPv6 universal address */ -#define RPCBIND_MAXUADDR6LEN \ - (INET6_ADDRSTRLEN + RPCBIND_MAXUADDRPLEN) - -/* Assume INET6_ADDRSTRLEN will always be larger than INET_ADDRSTRLEN... */ -#define RPCBIND_MAXUADDRLEN RPCBIND_MAXUADDR6LEN - -#endif /* __KERNEL__ */ -#endif /* _LINUX_SUNRPC_MSGPROT_H_ */ diff --git a/src/linux/include/linux/sunrpc/rpc_pipe_fs.h b/src/linux/include/linux/sunrpc/rpc_pipe_fs.h deleted file mode 100644 index 7f490be..0000000 --- a/src/linux/include/linux/sunrpc/rpc_pipe_fs.h +++ /dev/null @@ -1,137 +0,0 @@ -#ifndef _LINUX_SUNRPC_RPC_PIPE_FS_H -#define _LINUX_SUNRPC_RPC_PIPE_FS_H - -#ifdef __KERNEL__ - -#include - -struct rpc_pipe_dir_head { - struct list_head pdh_entries; - struct dentry *pdh_dentry; -}; - -struct rpc_pipe_dir_object_ops; -struct rpc_pipe_dir_object { - struct list_head pdo_head; - const struct rpc_pipe_dir_object_ops *pdo_ops; - - void *pdo_data; -}; - -struct rpc_pipe_dir_object_ops { - int (*create)(struct dentry *dir, - struct rpc_pipe_dir_object *pdo); - void (*destroy)(struct dentry *dir, - struct rpc_pipe_dir_object *pdo); -}; - -struct rpc_pipe_msg { - struct list_head list; - void *data; - size_t len; - size_t copied; - int errno; -}; - -struct rpc_pipe_ops { - ssize_t (*upcall)(struct file *, struct rpc_pipe_msg *, char __user *, size_t); - ssize_t (*downcall)(struct file *, const char __user *, size_t); - void (*release_pipe)(struct inode *); - int (*open_pipe)(struct inode *); - void (*destroy_msg)(struct rpc_pipe_msg *); -}; - -struct rpc_pipe { - struct list_head pipe; - struct list_head in_upcall; - struct list_head in_downcall; - int pipelen; - int nreaders; - int nwriters; -#define RPC_PIPE_WAIT_FOR_OPEN 1 - int flags; - struct delayed_work queue_timeout; - const struct rpc_pipe_ops *ops; - spinlock_t lock; - struct dentry *dentry; -}; - -struct rpc_inode { - struct inode vfs_inode; - void *private; - struct rpc_pipe *pipe; - wait_queue_head_t waitq; -}; - -static inline struct rpc_inode * -RPC_I(struct inode *inode) -{ - return container_of(inode, struct rpc_inode, vfs_inode); -} - -enum { - SUNRPC_PIPEFS_NFS_PRIO, - SUNRPC_PIPEFS_RPC_PRIO, -}; - -extern int rpc_pipefs_notifier_register(struct notifier_block *); -extern void rpc_pipefs_notifier_unregister(struct notifier_block *); - -enum { - RPC_PIPEFS_MOUNT, - RPC_PIPEFS_UMOUNT, -}; - -extern struct dentry *rpc_d_lookup_sb(const struct super_block *sb, - const unsigned char *dir_name); -extern int rpc_pipefs_init_net(struct net *net); -extern void rpc_pipefs_exit_net(struct net *net); -extern struct super_block *rpc_get_sb_net(const struct net *net); -extern void rpc_put_sb_net(const struct net *net); - -extern ssize_t rpc_pipe_generic_upcall(struct file *, struct rpc_pipe_msg *, - char __user *, size_t); -extern int rpc_queue_upcall(struct rpc_pipe *, struct rpc_pipe_msg *); - -struct rpc_clnt; -extern struct dentry *rpc_create_client_dir(struct dentry *, const char *, struct rpc_clnt *); -extern int rpc_remove_client_dir(struct rpc_clnt *); - -extern void rpc_init_pipe_dir_head(struct rpc_pipe_dir_head *pdh); -extern void rpc_init_pipe_dir_object(struct rpc_pipe_dir_object *pdo, - const struct rpc_pipe_dir_object_ops *pdo_ops, - void *pdo_data); -extern int rpc_add_pipe_dir_object(struct net *net, - struct rpc_pipe_dir_head *pdh, - struct rpc_pipe_dir_object *pdo); -extern void rpc_remove_pipe_dir_object(struct net *net, - struct rpc_pipe_dir_head *pdh, - struct rpc_pipe_dir_object *pdo); -extern struct rpc_pipe_dir_object *rpc_find_or_alloc_pipe_dir_object( - struct net *net, - struct rpc_pipe_dir_head *pdh, - int (*match)(struct rpc_pipe_dir_object *, void *), - struct rpc_pipe_dir_object *(*alloc)(void *), - void *data); - -struct cache_detail; -extern struct dentry *rpc_create_cache_dir(struct dentry *, - const char *, - umode_t umode, - struct cache_detail *); -extern void rpc_remove_cache_dir(struct dentry *); - -extern int rpc_rmdir(struct dentry *dentry); - -struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags); -void rpc_destroy_pipe_data(struct rpc_pipe *pipe); -extern struct dentry *rpc_mkpipe_dentry(struct dentry *, const char *, void *, - struct rpc_pipe *); -extern int rpc_unlink(struct dentry *); -extern int register_rpc_pipefs(void); -extern void unregister_rpc_pipefs(void); - -extern bool gssd_running(struct net *net); - -#endif -#endif diff --git a/src/linux/include/linux/sunrpc/sched.h b/src/linux/include/linux/sunrpc/sched.h deleted file mode 100644 index 7ba040c..0000000 --- a/src/linux/include/linux/sunrpc/sched.h +++ /dev/null @@ -1,296 +0,0 @@ -/* - * linux/include/linux/sunrpc/sched.h - * - * Scheduling primitives for kernel Sun RPC. - * - * Copyright (C) 1996, Olaf Kirch - */ - -#ifndef _LINUX_SUNRPC_SCHED_H_ -#define _LINUX_SUNRPC_SCHED_H_ - -#include -#include -#include -#include -#include -#include -#include - -/* - * This is the actual RPC procedure call info. - */ -struct rpc_procinfo; -struct rpc_message { - struct rpc_procinfo * rpc_proc; /* Procedure information */ - void * rpc_argp; /* Arguments */ - void * rpc_resp; /* Result */ - struct rpc_cred * rpc_cred; /* Credentials */ -}; - -struct rpc_call_ops; -struct rpc_wait_queue; -struct rpc_wait { - struct list_head list; /* wait queue links */ - struct list_head links; /* Links to related tasks */ - struct list_head timer_list; /* Timer list */ - unsigned long expires; -}; - -/* - * This is the RPC task struct - */ -struct rpc_task { - atomic_t tk_count; /* Reference count */ - int tk_status; /* result of last operation */ - struct list_head tk_task; /* global list of tasks */ - - /* - * callback to be executed after waking up - * action next procedure for async tasks - */ - void (*tk_callback)(struct rpc_task *); - void (*tk_action)(struct rpc_task *); - - unsigned long tk_timeout; /* timeout for rpc_sleep() */ - unsigned long tk_runstate; /* Task run status */ - - struct rpc_wait_queue *tk_waitqueue; /* RPC wait queue we're on */ - union { - struct work_struct tk_work; /* Async task work queue */ - struct rpc_wait tk_wait; /* RPC wait */ - } u; - - /* - * RPC call state - */ - struct rpc_message tk_msg; /* RPC call info */ - void * tk_calldata; /* Caller private data */ - const struct rpc_call_ops *tk_ops; /* Caller callbacks */ - - struct rpc_clnt * tk_client; /* RPC client */ - struct rpc_xprt * tk_xprt; /* Transport */ - - struct rpc_rqst * tk_rqstp; /* RPC request */ - - struct workqueue_struct *tk_workqueue; /* Normally rpciod, but could - * be any workqueue - */ - ktime_t tk_start; /* RPC task init timestamp */ - - pid_t tk_owner; /* Process id for batching tasks */ - unsigned short tk_flags; /* misc flags */ - unsigned short tk_timeouts; /* maj timeouts */ - -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS) - unsigned short tk_pid; /* debugging aid */ -#endif - unsigned char tk_priority : 2,/* Task priority */ - tk_garb_retry : 2, - tk_cred_retry : 2, - tk_rebind_retry : 2; -}; - -typedef void (*rpc_action)(struct rpc_task *); - -struct rpc_call_ops { - void (*rpc_call_prepare)(struct rpc_task *, void *); - void (*rpc_call_done)(struct rpc_task *, void *); - void (*rpc_count_stats)(struct rpc_task *, void *); - void (*rpc_release)(void *); -}; - -struct rpc_task_setup { - struct rpc_task *task; - struct rpc_clnt *rpc_client; - struct rpc_xprt *rpc_xprt; - const struct rpc_message *rpc_message; - const struct rpc_call_ops *callback_ops; - void *callback_data; - struct workqueue_struct *workqueue; - unsigned short flags; - signed char priority; -}; - -/* - * RPC task flags - */ -#define RPC_TASK_ASYNC 0x0001 /* is an async task */ -#define RPC_TASK_SWAPPER 0x0002 /* is swapping in/out */ -#define RPC_CALL_MAJORSEEN 0x0020 /* major timeout seen */ -#define RPC_TASK_ROOTCREDS 0x0040 /* force root creds */ -#define RPC_TASK_DYNAMIC 0x0080 /* task was kmalloc'ed */ -#define RPC_TASK_KILLED 0x0100 /* task was killed */ -#define RPC_TASK_SOFT 0x0200 /* Use soft timeouts */ -#define RPC_TASK_SOFTCONN 0x0400 /* Fail if can't connect */ -#define RPC_TASK_SENT 0x0800 /* message was sent */ -#define RPC_TASK_TIMEOUT 0x1000 /* fail with ETIMEDOUT on timeout */ -#define RPC_TASK_NOCONNECT 0x2000 /* return ENOTCONN if not connected */ -#define RPC_TASK_NO_RETRANS_TIMEOUT 0x4000 /* wait forever for a reply */ - -#define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC) -#define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) -#define RPC_DO_ROOTOVERRIDE(t) ((t)->tk_flags & RPC_TASK_ROOTCREDS) -#define RPC_ASSASSINATED(t) ((t)->tk_flags & RPC_TASK_KILLED) -#define RPC_IS_SOFT(t) ((t)->tk_flags & (RPC_TASK_SOFT|RPC_TASK_TIMEOUT)) -#define RPC_IS_SOFTCONN(t) ((t)->tk_flags & RPC_TASK_SOFTCONN) -#define RPC_WAS_SENT(t) ((t)->tk_flags & RPC_TASK_SENT) - -#define RPC_TASK_RUNNING 0 -#define RPC_TASK_QUEUED 1 -#define RPC_TASK_ACTIVE 2 - -#define RPC_IS_RUNNING(t) test_bit(RPC_TASK_RUNNING, &(t)->tk_runstate) -#define rpc_set_running(t) set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate) -#define rpc_test_and_set_running(t) \ - test_and_set_bit(RPC_TASK_RUNNING, &(t)->tk_runstate) -#define rpc_clear_running(t) \ - do { \ - smp_mb__before_atomic(); \ - clear_bit(RPC_TASK_RUNNING, &(t)->tk_runstate); \ - smp_mb__after_atomic(); \ - } while (0) - -#define RPC_IS_QUEUED(t) test_bit(RPC_TASK_QUEUED, &(t)->tk_runstate) -#define rpc_set_queued(t) set_bit(RPC_TASK_QUEUED, &(t)->tk_runstate) -#define rpc_clear_queued(t) \ - do { \ - smp_mb__before_atomic(); \ - clear_bit(RPC_TASK_QUEUED, &(t)->tk_runstate); \ - smp_mb__after_atomic(); \ - } while (0) - -#define RPC_IS_ACTIVATED(t) test_bit(RPC_TASK_ACTIVE, &(t)->tk_runstate) - -/* - * Task priorities. - * Note: if you change these, you must also change - * the task initialization definitions below. - */ -#define RPC_PRIORITY_LOW (-1) -#define RPC_PRIORITY_NORMAL (0) -#define RPC_PRIORITY_HIGH (1) -#define RPC_PRIORITY_PRIVILEGED (2) -#define RPC_NR_PRIORITY (1 + RPC_PRIORITY_PRIVILEGED - RPC_PRIORITY_LOW) - -struct rpc_timer { - struct timer_list timer; - struct list_head list; - unsigned long expires; -}; - -/* - * RPC synchronization objects - */ -struct rpc_wait_queue { - spinlock_t lock; - struct list_head tasks[RPC_NR_PRIORITY]; /* task queue for each priority level */ - pid_t owner; /* process id of last task serviced */ - unsigned char maxpriority; /* maximum priority (0 if queue is not a priority queue) */ - unsigned char priority; /* current priority */ - unsigned char nr; /* # tasks remaining for cookie */ - unsigned short qlen; /* total # tasks waiting in queue */ - struct rpc_timer timer_list; -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS) - const char * name; -#endif -}; - -/* - * This is the # requests to send consecutively - * from a single cookie. The aim is to improve - * performance of NFS operations such as read/write. - */ -#define RPC_BATCH_COUNT 16 -#define RPC_IS_PRIORITY(q) ((q)->maxpriority > 0) - -/* - * Function prototypes - */ -struct rpc_task *rpc_new_task(const struct rpc_task_setup *); -struct rpc_task *rpc_run_task(const struct rpc_task_setup *); -struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req); -void rpc_put_task(struct rpc_task *); -void rpc_put_task_async(struct rpc_task *); -void rpc_exit_task(struct rpc_task *); -void rpc_exit(struct rpc_task *, int); -void rpc_release_calldata(const struct rpc_call_ops *, void *); -void rpc_killall_tasks(struct rpc_clnt *); -void rpc_execute(struct rpc_task *); -void rpc_init_priority_wait_queue(struct rpc_wait_queue *, const char *); -void rpc_init_wait_queue(struct rpc_wait_queue *, const char *); -void rpc_destroy_wait_queue(struct rpc_wait_queue *); -void rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *, - rpc_action action); -void rpc_sleep_on_priority(struct rpc_wait_queue *, - struct rpc_task *, - rpc_action action, - int priority); -void rpc_wake_up_queued_task(struct rpc_wait_queue *, - struct rpc_task *); -void rpc_wake_up(struct rpc_wait_queue *); -struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *); -struct rpc_task *rpc_wake_up_first_on_wq(struct workqueue_struct *wq, - struct rpc_wait_queue *, - bool (*)(struct rpc_task *, void *), - void *); -struct rpc_task *rpc_wake_up_first(struct rpc_wait_queue *, - bool (*)(struct rpc_task *, void *), - void *); -void rpc_wake_up_status(struct rpc_wait_queue *, int); -void rpc_delay(struct rpc_task *, unsigned long); -int rpc_malloc(struct rpc_task *); -void rpc_free(struct rpc_task *); -int rpciod_up(void); -void rpciod_down(void); -int __rpc_wait_for_completion_task(struct rpc_task *task, wait_bit_action_f *); -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) -struct net; -void rpc_show_tasks(struct net *); -#endif -int rpc_init_mempool(void); -void rpc_destroy_mempool(void); -extern struct workqueue_struct *rpciod_workqueue; -extern struct workqueue_struct *xprtiod_workqueue; -void rpc_prepare_task(struct rpc_task *task); - -static inline int rpc_wait_for_completion_task(struct rpc_task *task) -{ - return __rpc_wait_for_completion_task(task, NULL); -} - -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS) -static inline const char * rpc_qname(const struct rpc_wait_queue *q) -{ - return ((q && q->name) ? q->name : "unknown"); -} - -static inline void rpc_assign_waitqueue_name(struct rpc_wait_queue *q, - const char *name) -{ - q->name = name; -} -#else -static inline void rpc_assign_waitqueue_name(struct rpc_wait_queue *q, - const char *name) -{ -} -#endif - -#if IS_ENABLED(CONFIG_SUNRPC_SWAP) -int rpc_clnt_swap_activate(struct rpc_clnt *clnt); -void rpc_clnt_swap_deactivate(struct rpc_clnt *clnt); -#else -static inline int -rpc_clnt_swap_activate(struct rpc_clnt *clnt) -{ - return -EINVAL; -} - -static inline void -rpc_clnt_swap_deactivate(struct rpc_clnt *clnt) -{ -} -#endif /* CONFIG_SUNRPC_SWAP */ - -#endif /* _LINUX_SUNRPC_SCHED_H_ */ diff --git a/src/linux/include/linux/sunrpc/stats.h b/src/linux/include/linux/sunrpc/stats.h deleted file mode 100644 index edc6421..0000000 --- a/src/linux/include/linux/sunrpc/stats.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * linux/include/linux/sunrpc/stats.h - * - * Client statistics collection for SUN RPC - * - * Copyright (C) 1996 Olaf Kirch - */ - -#ifndef _LINUX_SUNRPC_STATS_H -#define _LINUX_SUNRPC_STATS_H - -#include - -struct rpc_stat { - const struct rpc_program *program; - - unsigned int netcnt, - netudpcnt, - nettcpcnt, - nettcpconn, - netreconn; - unsigned int rpccnt, - rpcretrans, - rpcauthrefresh, - rpcgarbage; -}; - -struct svc_stat { - struct svc_program * program; - - unsigned int netcnt, - netudpcnt, - nettcpcnt, - nettcpconn; - unsigned int rpccnt, - rpcbadfmt, - rpcbadauth, - rpcbadclnt; -}; - -struct net; -#ifdef CONFIG_PROC_FS -int rpc_proc_init(struct net *); -void rpc_proc_exit(struct net *); -#else -static inline int rpc_proc_init(struct net *net) -{ - return 0; -} - -static inline void rpc_proc_exit(struct net *net) -{ -} -#endif - -#ifdef MODULE -void rpc_modcount(struct inode *, int); -#endif - -#ifdef CONFIG_PROC_FS -struct proc_dir_entry * rpc_proc_register(struct net *,struct rpc_stat *); -void rpc_proc_unregister(struct net *,const char *); -void rpc_proc_zero(const struct rpc_program *); -struct proc_dir_entry * svc_proc_register(struct net *, struct svc_stat *, - const struct file_operations *); -void svc_proc_unregister(struct net *, const char *); - -void svc_seq_show(struct seq_file *, - const struct svc_stat *); -#else - -static inline struct proc_dir_entry *rpc_proc_register(struct net *net, struct rpc_stat *s) { return NULL; } -static inline void rpc_proc_unregister(struct net *net, const char *p) {} -static inline void rpc_proc_zero(const struct rpc_program *p) {} - -static inline struct proc_dir_entry *svc_proc_register(struct net *net, struct svc_stat *s, - const struct file_operations *f) { return NULL; } -static inline void svc_proc_unregister(struct net *net, const char *p) {} - -static inline void svc_seq_show(struct seq_file *seq, - const struct svc_stat *st) {} -#endif - -#endif /* _LINUX_SUNRPC_STATS_H */ diff --git a/src/linux/include/linux/sunrpc/timer.h b/src/linux/include/linux/sunrpc/timer.h deleted file mode 100644 index 697d6e6..0000000 --- a/src/linux/include/linux/sunrpc/timer.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * linux/include/linux/sunrpc/timer.h - * - * Declarations for the RPC transport timer. - * - * Copyright (C) 2002 Trond Myklebust - */ - -#ifndef _LINUX_SUNRPC_TIMER_H -#define _LINUX_SUNRPC_TIMER_H - -#include - -struct rpc_rtt { - unsigned long timeo; /* default timeout value */ - unsigned long srtt[5]; /* smoothed round trip time << 3 */ - unsigned long sdrtt[5]; /* smoothed medium deviation of RTT */ - int ntimeouts[5]; /* Number of timeouts for the last request */ -}; - - -extern void rpc_init_rtt(struct rpc_rtt *rt, unsigned long timeo); -extern void rpc_update_rtt(struct rpc_rtt *rt, unsigned timer, long m); -extern unsigned long rpc_calc_rto(struct rpc_rtt *rt, unsigned timer); - -static inline void rpc_set_timeo(struct rpc_rtt *rt, int timer, int ntimeo) -{ - int *t; - if (!timer) - return; - t = &rt->ntimeouts[timer-1]; - if (ntimeo < *t) { - if (*t > 0) - (*t)--; - } else { - if (ntimeo > 8) - ntimeo = 8; - *t = ntimeo; - } -} - -static inline int rpc_ntimeo(struct rpc_rtt *rt, int timer) -{ - if (!timer) - return 0; - return rt->ntimeouts[timer-1]; -} - -#endif /* _LINUX_SUNRPC_TIMER_H */ diff --git a/src/linux/include/linux/sunrpc/types.h b/src/linux/include/linux/sunrpc/types.h deleted file mode 100644 index d222f47..0000000 --- a/src/linux/include/linux/sunrpc/types.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * linux/include/linux/sunrpc/types.h - * - * Generic types and misc stuff for RPC. - * - * Copyright (C) 1996, Olaf Kirch - */ - -#ifndef _LINUX_SUNRPC_TYPES_H_ -#define _LINUX_SUNRPC_TYPES_H_ - -#include -#include -#include -#include - -/* - * Shorthands - */ -#define signalled() (signal_pending(current)) - -#endif /* _LINUX_SUNRPC_TYPES_H_ */ diff --git a/src/linux/include/linux/sunrpc/xdr.h b/src/linux/include/linux/sunrpc/xdr.h deleted file mode 100644 index 56c48c8..0000000 --- a/src/linux/include/linux/sunrpc/xdr.h +++ /dev/null @@ -1,247 +0,0 @@ -/* - * XDR standard data types and function declarations - * - * Copyright (C) 1995-1997 Olaf Kirch - * - * Based on: - * RFC 4506 "XDR: External Data Representation Standard", May 2006 - */ - -#ifndef _SUNRPC_XDR_H_ -#define _SUNRPC_XDR_H_ - -#ifdef __KERNEL__ - -#include -#include -#include -#include - -/* - * Buffer adjustment - */ -#define XDR_QUADLEN(l) (((l) + 3) >> 2) - -/* - * Generic opaque `network object.' At the kernel level, this type - * is used only by lockd. - */ -#define XDR_MAX_NETOBJ 1024 -struct xdr_netobj { - unsigned int len; - u8 * data; -}; - -/* - * This is the legacy generic XDR function. rqstp is either a rpc_rqst - * (client side) or svc_rqst pointer (server side). - * Encode functions always assume there's enough room in the buffer. - */ -typedef int (*kxdrproc_t)(void *rqstp, __be32 *data, void *obj); - -/* - * Basic structure for transmission/reception of a client XDR message. - * Features a header (for a linear buffer containing RPC headers - * and the data payload for short messages), and then an array of - * pages. - * The tail iovec allows you to append data after the page array. Its - * main interest is for appending padding to the pages in order to - * satisfy the int_32-alignment requirements in RFC1832. - * - * For the future, we might want to string several of these together - * in a list if anybody wants to make use of NFSv4 COMPOUND - * operations and/or has a need for scatter/gather involving pages. - */ -struct xdr_buf { - struct kvec head[1], /* RPC header + non-page data */ - tail[1]; /* Appended after page data */ - - struct page ** pages; /* Array of pages */ - unsigned int page_base, /* Start of page data */ - page_len, /* Length of page data */ - flags; /* Flags for data disposition */ -#define XDRBUF_READ 0x01 /* target of file read */ -#define XDRBUF_WRITE 0x02 /* source of file write */ - - unsigned int buflen, /* Total length of storage buffer */ - len; /* Length of XDR encoded message */ -}; - -static inline void -xdr_buf_init(struct xdr_buf *buf, void *start, size_t len) -{ - buf->head[0].iov_base = start; - buf->head[0].iov_len = len; - buf->tail[0].iov_len = 0; - buf->page_len = 0; - buf->flags = 0; - buf->len = 0; - buf->buflen = len; -} - -/* - * pre-xdr'ed macros. - */ - -#define xdr_zero cpu_to_be32(0) -#define xdr_one cpu_to_be32(1) -#define xdr_two cpu_to_be32(2) - -#define rpc_success cpu_to_be32(RPC_SUCCESS) -#define rpc_prog_unavail cpu_to_be32(RPC_PROG_UNAVAIL) -#define rpc_prog_mismatch cpu_to_be32(RPC_PROG_MISMATCH) -#define rpc_proc_unavail cpu_to_be32(RPC_PROC_UNAVAIL) -#define rpc_garbage_args cpu_to_be32(RPC_GARBAGE_ARGS) -#define rpc_system_err cpu_to_be32(RPC_SYSTEM_ERR) -#define rpc_drop_reply cpu_to_be32(RPC_DROP_REPLY) - -#define rpc_auth_ok cpu_to_be32(RPC_AUTH_OK) -#define rpc_autherr_badcred cpu_to_be32(RPC_AUTH_BADCRED) -#define rpc_autherr_rejectedcred cpu_to_be32(RPC_AUTH_REJECTEDCRED) -#define rpc_autherr_badverf cpu_to_be32(RPC_AUTH_BADVERF) -#define rpc_autherr_rejectedverf cpu_to_be32(RPC_AUTH_REJECTEDVERF) -#define rpc_autherr_tooweak cpu_to_be32(RPC_AUTH_TOOWEAK) -#define rpcsec_gsserr_credproblem cpu_to_be32(RPCSEC_GSS_CREDPROBLEM) -#define rpcsec_gsserr_ctxproblem cpu_to_be32(RPCSEC_GSS_CTXPROBLEM) -#define rpc_autherr_oldseqnum cpu_to_be32(101) - -/* - * Miscellaneous XDR helper functions - */ -__be32 *xdr_encode_opaque_fixed(__be32 *p, const void *ptr, unsigned int len); -__be32 *xdr_encode_opaque(__be32 *p, const void *ptr, unsigned int len); -__be32 *xdr_encode_string(__be32 *p, const char *s); -__be32 *xdr_decode_string_inplace(__be32 *p, char **sp, unsigned int *lenp, - unsigned int maxlen); -__be32 *xdr_encode_netobj(__be32 *p, const struct xdr_netobj *); -__be32 *xdr_decode_netobj(__be32 *p, struct xdr_netobj *); - -void xdr_inline_pages(struct xdr_buf *, unsigned int, - struct page **, unsigned int, unsigned int); -void xdr_terminate_string(struct xdr_buf *, const u32); - -static inline __be32 *xdr_encode_array(__be32 *p, const void *s, unsigned int len) -{ - return xdr_encode_opaque(p, s, len); -} - -/* - * Decode 64bit quantities (NFSv3 support) - */ -static inline __be32 * -xdr_encode_hyper(__be32 *p, __u64 val) -{ - put_unaligned_be64(val, p); - return p + 2; -} - -static inline __be32 * -xdr_decode_hyper(__be32 *p, __u64 *valp) -{ - *valp = get_unaligned_be64(p); - return p + 2; -} - -static inline __be32 * -xdr_decode_opaque_fixed(__be32 *p, void *ptr, unsigned int len) -{ - memcpy(ptr, p, len); - return p + XDR_QUADLEN(len); -} - -/* - * Adjust kvec to reflect end of xdr'ed data (RPC client XDR) - */ -static inline int -xdr_adjust_iovec(struct kvec *iov, __be32 *p) -{ - return iov->iov_len = ((u8 *) p - (u8 *) iov->iov_base); -} - -/* - * XDR buffer helper functions - */ -extern void xdr_shift_buf(struct xdr_buf *, size_t); -extern void xdr_buf_from_iov(struct kvec *, struct xdr_buf *); -extern int xdr_buf_subsegment(struct xdr_buf *, struct xdr_buf *, unsigned int, unsigned int); -extern void xdr_buf_trim(struct xdr_buf *, unsigned int); -extern int xdr_buf_read_netobj(struct xdr_buf *, struct xdr_netobj *, unsigned int); -extern int read_bytes_from_xdr_buf(struct xdr_buf *, unsigned int, void *, unsigned int); -extern int write_bytes_to_xdr_buf(struct xdr_buf *, unsigned int, void *, unsigned int); - -/* - * Helper structure for copying from an sk_buff. - */ -struct xdr_skb_reader { - struct sk_buff *skb; - unsigned int offset; - size_t count; - __wsum csum; -}; - -typedef size_t (*xdr_skb_read_actor)(struct xdr_skb_reader *desc, void *to, size_t len); - -size_t xdr_skb_read_bits(struct xdr_skb_reader *desc, void *to, size_t len); -extern int csum_partial_copy_to_xdr(struct xdr_buf *, struct sk_buff *); -extern ssize_t xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int, - struct xdr_skb_reader *, xdr_skb_read_actor); - -extern int xdr_encode_word(struct xdr_buf *, unsigned int, u32); -extern int xdr_decode_word(struct xdr_buf *, unsigned int, u32 *); - -struct xdr_array2_desc; -typedef int (*xdr_xcode_elem_t)(struct xdr_array2_desc *desc, void *elem); -struct xdr_array2_desc { - unsigned int elem_size; - unsigned int array_len; - unsigned int array_maxlen; - xdr_xcode_elem_t xcode; -}; - -extern int xdr_decode_array2(struct xdr_buf *buf, unsigned int base, - struct xdr_array2_desc *desc); -extern int xdr_encode_array2(struct xdr_buf *buf, unsigned int base, - struct xdr_array2_desc *desc); -extern void _copy_from_pages(char *p, struct page **pages, size_t pgbase, - size_t len); - -/* - * Provide some simple tools for XDR buffer overflow-checking etc. - */ -struct xdr_stream { - __be32 *p; /* start of available buffer */ - struct xdr_buf *buf; /* XDR buffer to read/write */ - - __be32 *end; /* end of available buffer space */ - struct kvec *iov; /* pointer to the current kvec */ - struct kvec scratch; /* Scratch buffer */ - struct page **page_ptr; /* pointer to the current page */ - unsigned int nwords; /* Remaining decode buffer length */ -}; - -/* - * These are the xdr_stream style generic XDR encode and decode functions. - */ -typedef void (*kxdreproc_t)(void *rqstp, struct xdr_stream *xdr, void *obj); -typedef int (*kxdrdproc_t)(void *rqstp, struct xdr_stream *xdr, void *obj); - -extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p); -extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes); -extern void xdr_commit_encode(struct xdr_stream *xdr); -extern void xdr_truncate_encode(struct xdr_stream *xdr, size_t len); -extern int xdr_restrict_buflen(struct xdr_stream *xdr, int newbuflen); -extern void xdr_write_pages(struct xdr_stream *xdr, struct page **pages, - unsigned int base, unsigned int len); -extern unsigned int xdr_stream_pos(const struct xdr_stream *xdr); -extern void xdr_init_decode(struct xdr_stream *xdr, struct xdr_buf *buf, __be32 *p); -extern void xdr_init_decode_pages(struct xdr_stream *xdr, struct xdr_buf *buf, - struct page **pages, unsigned int len); -extern void xdr_set_scratch_buffer(struct xdr_stream *xdr, void *buf, size_t buflen); -extern __be32 *xdr_inline_decode(struct xdr_stream *xdr, size_t nbytes); -extern unsigned int xdr_read_pages(struct xdr_stream *xdr, unsigned int len); -extern void xdr_enter_page(struct xdr_stream *xdr, unsigned int len); -extern int xdr_process_buf(struct xdr_buf *buf, unsigned int offset, unsigned int len, int (*actor)(struct scatterlist *, void *), void *data); - -#endif /* __KERNEL__ */ - -#endif /* _SUNRPC_XDR_H_ */ diff --git a/src/linux/include/linux/sunrpc/xprt.h b/src/linux/include/linux/sunrpc/xprt.h deleted file mode 100644 index a5da60b..0000000 --- a/src/linux/include/linux/sunrpc/xprt.h +++ /dev/null @@ -1,479 +0,0 @@ -/* - * linux/include/linux/sunrpc/xprt.h - * - * Declarations for the RPC transport interface. - * - * Copyright (C) 1995, 1996 Olaf Kirch - */ - -#ifndef _LINUX_SUNRPC_XPRT_H -#define _LINUX_SUNRPC_XPRT_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __KERNEL__ - -#define RPC_MIN_SLOT_TABLE (2U) -#define RPC_DEF_SLOT_TABLE (16U) -#define RPC_MAX_SLOT_TABLE_LIMIT (65536U) -#define RPC_MAX_SLOT_TABLE RPC_MAX_SLOT_TABLE_LIMIT - -#define RPC_CWNDSHIFT (8U) -#define RPC_CWNDSCALE (1U << RPC_CWNDSHIFT) -#define RPC_INITCWND RPC_CWNDSCALE -#define RPC_MAXCWND(xprt) ((xprt)->max_reqs << RPC_CWNDSHIFT) -#define RPCXPRT_CONGESTED(xprt) ((xprt)->cong >= (xprt)->cwnd) - -/* - * This describes a timeout strategy - */ -struct rpc_timeout { - unsigned long to_initval, /* initial timeout */ - to_maxval, /* max timeout */ - to_increment; /* if !exponential */ - unsigned int to_retries; /* max # of retries */ - unsigned char to_exponential; -}; - -enum rpc_display_format_t { - RPC_DISPLAY_ADDR = 0, - RPC_DISPLAY_PORT, - RPC_DISPLAY_PROTO, - RPC_DISPLAY_HEX_ADDR, - RPC_DISPLAY_HEX_PORT, - RPC_DISPLAY_NETID, - RPC_DISPLAY_MAX, -}; - -struct rpc_task; -struct rpc_xprt; -struct seq_file; -struct svc_serv; -struct net; - -/* - * This describes a complete RPC request - */ -struct rpc_rqst { - /* - * This is the user-visible part - */ - struct rpc_xprt * rq_xprt; /* RPC client */ - struct xdr_buf rq_snd_buf; /* send buffer */ - struct xdr_buf rq_rcv_buf; /* recv buffer */ - - /* - * This is the private part - */ - struct rpc_task * rq_task; /* RPC task data */ - struct rpc_cred * rq_cred; /* Bound cred */ - __be32 rq_xid; /* request XID */ - int rq_cong; /* has incremented xprt->cong */ - u32 rq_seqno; /* gss seq no. used on req. */ - int rq_enc_pages_num; - struct page **rq_enc_pages; /* scratch pages for use by - gss privacy code */ - void (*rq_release_snd_buf)(struct rpc_rqst *); /* release rq_enc_pages */ - struct list_head rq_list; - - void *rq_xprtdata; /* Per-xprt private data */ - void *rq_buffer; /* Call XDR encode buffer */ - size_t rq_callsize; - void *rq_rbuffer; /* Reply XDR decode buffer */ - size_t rq_rcvsize; - size_t rq_xmit_bytes_sent; /* total bytes sent */ - size_t rq_reply_bytes_recvd; /* total reply bytes */ - /* received */ - - struct xdr_buf rq_private_buf; /* The receive buffer - * used in the softirq. - */ - unsigned long rq_majortimeo; /* major timeout alarm */ - unsigned long rq_timeout; /* Current timeout value */ - ktime_t rq_rtt; /* round-trip time */ - unsigned int rq_retries; /* # of retries */ - unsigned int rq_connect_cookie; - /* A cookie used to track the - state of the transport - connection */ - - /* - * Partial send handling - */ - u32 rq_bytes_sent; /* Bytes we have sent */ - - ktime_t rq_xtime; /* transmit time stamp */ - int rq_ntrans; - -#if defined(CONFIG_SUNRPC_BACKCHANNEL) - struct list_head rq_bc_list; /* Callback service list */ - unsigned long rq_bc_pa_state; /* Backchannel prealloc state */ - struct list_head rq_bc_pa_list; /* Backchannel prealloc list */ -#endif /* CONFIG_SUNRPC_BACKCHANEL */ -}; -#define rq_svec rq_snd_buf.head -#define rq_slen rq_snd_buf.len - -struct rpc_xprt_ops { - void (*set_buffer_size)(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize); - int (*reserve_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); - void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); - void (*alloc_slot)(struct rpc_xprt *xprt, struct rpc_task *task); - void (*rpcbind)(struct rpc_task *task); - void (*set_port)(struct rpc_xprt *xprt, unsigned short port); - void (*connect)(struct rpc_xprt *xprt, struct rpc_task *task); - int (*buf_alloc)(struct rpc_task *task); - void (*buf_free)(struct rpc_task *task); - int (*send_request)(struct rpc_task *task); - void (*set_retrans_timeout)(struct rpc_task *task); - void (*timer)(struct rpc_xprt *xprt, struct rpc_task *task); - void (*release_request)(struct rpc_task *task); - void (*close)(struct rpc_xprt *xprt); - void (*destroy)(struct rpc_xprt *xprt); - void (*print_stats)(struct rpc_xprt *xprt, struct seq_file *seq); - int (*enable_swap)(struct rpc_xprt *xprt); - void (*disable_swap)(struct rpc_xprt *xprt); - void (*inject_disconnect)(struct rpc_xprt *xprt); - int (*bc_setup)(struct rpc_xprt *xprt, - unsigned int min_reqs); - int (*bc_up)(struct svc_serv *serv, struct net *net); - size_t (*bc_maxpayload)(struct rpc_xprt *xprt); - void (*bc_free_rqst)(struct rpc_rqst *rqst); - void (*bc_destroy)(struct rpc_xprt *xprt, - unsigned int max_reqs); -}; - -/* - * RPC transport identifiers - * - * To preserve compatibility with the historical use of raw IP protocol - * id's for transport selection, UDP and TCP identifiers are specified - * with the previous values. No such restriction exists for new transports, - * except that they may not collide with these values (17 and 6, - * respectively). - */ -#define XPRT_TRANSPORT_BC (1 << 31) -enum xprt_transports { - XPRT_TRANSPORT_UDP = IPPROTO_UDP, - XPRT_TRANSPORT_TCP = IPPROTO_TCP, - XPRT_TRANSPORT_BC_TCP = IPPROTO_TCP | XPRT_TRANSPORT_BC, - XPRT_TRANSPORT_RDMA = 256, - XPRT_TRANSPORT_BC_RDMA = XPRT_TRANSPORT_RDMA | XPRT_TRANSPORT_BC, - XPRT_TRANSPORT_LOCAL = 257, -}; - -struct rpc_xprt { - struct kref kref; /* Reference count */ - struct rpc_xprt_ops * ops; /* transport methods */ - - const struct rpc_timeout *timeout; /* timeout parms */ - struct sockaddr_storage addr; /* server address */ - size_t addrlen; /* size of server address */ - int prot; /* IP protocol */ - - unsigned long cong; /* current congestion */ - unsigned long cwnd; /* congestion window */ - - size_t max_payload; /* largest RPC payload size, - in bytes */ - unsigned int tsh_size; /* size of transport specific - header */ - - struct rpc_wait_queue binding; /* requests waiting on rpcbind */ - struct rpc_wait_queue sending; /* requests waiting to send */ - struct rpc_wait_queue pending; /* requests in flight */ - struct rpc_wait_queue backlog; /* waiting for slot */ - struct list_head free; /* free slots */ - unsigned int max_reqs; /* max number of slots */ - unsigned int min_reqs; /* min number of slots */ - atomic_t num_reqs; /* total slots */ - unsigned long state; /* transport state */ - unsigned char resvport : 1; /* use a reserved port */ - atomic_t swapper; /* we're swapping over this - transport */ - unsigned int bind_index; /* bind function index */ - - /* - * Multipath - */ - struct list_head xprt_switch; - - /* - * Connection of transports - */ - unsigned long bind_timeout, - reestablish_timeout; - unsigned int connect_cookie; /* A cookie that gets bumped - every time the transport - is reconnected */ - - /* - * Disconnection of idle transports - */ - struct work_struct task_cleanup; - struct timer_list timer; - unsigned long last_used, - idle_timeout, - max_reconnect_timeout; - - /* - * Send stuff - */ - spinlock_t transport_lock; /* lock transport info */ - spinlock_t reserve_lock; /* lock slot table */ - u32 xid; /* Next XID value to use */ - struct rpc_task * snd_task; /* Task blocked in send */ - struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */ -#if defined(CONFIG_SUNRPC_BACKCHANNEL) - struct svc_serv *bc_serv; /* The RPC service which will */ - /* process the callback */ - int bc_alloc_count; /* Total number of preallocs */ - atomic_t bc_free_slots; - spinlock_t bc_pa_lock; /* Protects the preallocated - * items */ - struct list_head bc_pa_list; /* List of preallocated - * backchannel rpc_rqst's */ -#endif /* CONFIG_SUNRPC_BACKCHANNEL */ - struct list_head recv; - - struct { - unsigned long bind_count, /* total number of binds */ - connect_count, /* total number of connects */ - connect_start, /* connect start timestamp */ - connect_time, /* jiffies waiting for connect */ - sends, /* how many complete requests */ - recvs, /* how many complete requests */ - bad_xids, /* lookup_rqst didn't find XID */ - max_slots; /* max rpc_slots used */ - - unsigned long long req_u, /* average requests on the wire */ - bklog_u, /* backlog queue utilization */ - sending_u, /* send q utilization */ - pending_u; /* pend q utilization */ - } stat; - - struct net *xprt_net; - const char *servername; - const char *address_strings[RPC_DISPLAY_MAX]; -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) - struct dentry *debugfs; /* debugfs directory */ - atomic_t inject_disconnect; -#endif - struct rcu_head rcu; -}; - -#if defined(CONFIG_SUNRPC_BACKCHANNEL) -/* - * Backchannel flags - */ -#define RPC_BC_PA_IN_USE 0x0001 /* Preallocated backchannel */ - /* buffer in use */ -#endif /* CONFIG_SUNRPC_BACKCHANNEL */ - -#if defined(CONFIG_SUNRPC_BACKCHANNEL) -static inline int bc_prealloc(struct rpc_rqst *req) -{ - return test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state); -} -#else -static inline int bc_prealloc(struct rpc_rqst *req) -{ - return 0; -} -#endif /* CONFIG_SUNRPC_BACKCHANNEL */ - -#define XPRT_CREATE_INFINITE_SLOTS (1U) -#define XPRT_CREATE_NO_IDLE_TIMEOUT (1U << 1) - -struct xprt_create { - int ident; /* XPRT_TRANSPORT identifier */ - struct net * net; - struct sockaddr * srcaddr; /* optional local address */ - struct sockaddr * dstaddr; /* remote peer address */ - size_t addrlen; - const char *servername; - struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */ - struct rpc_xprt_switch *bc_xps; - unsigned int flags; -}; - -struct xprt_class { - struct list_head list; - int ident; /* XPRT_TRANSPORT identifier */ - struct rpc_xprt * (*setup)(struct xprt_create *); - struct module *owner; - char name[32]; -}; - -/* - * Generic internal transport functions - */ -struct rpc_xprt *xprt_create_transport(struct xprt_create *args); -void xprt_connect(struct rpc_task *task); -void xprt_reserve(struct rpc_task *task); -void xprt_retry_reserve(struct rpc_task *task); -int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task); -int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); -void xprt_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task); -void xprt_lock_and_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task); -bool xprt_prepare_transmit(struct rpc_task *task); -void xprt_transmit(struct rpc_task *task); -void xprt_end_transmit(struct rpc_task *task); -int xprt_adjust_timeout(struct rpc_rqst *req); -void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task); -void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); -void xprt_release(struct rpc_task *task); -struct rpc_xprt * xprt_get(struct rpc_xprt *xprt); -void xprt_put(struct rpc_xprt *xprt); -struct rpc_xprt * xprt_alloc(struct net *net, size_t size, - unsigned int num_prealloc, - unsigned int max_req); -void xprt_free(struct rpc_xprt *); - -static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *p) -{ - return p + xprt->tsh_size; -} - -static inline int -xprt_enable_swap(struct rpc_xprt *xprt) -{ - return xprt->ops->enable_swap(xprt); -} - -static inline void -xprt_disable_swap(struct rpc_xprt *xprt) -{ - xprt->ops->disable_swap(xprt); -} - -/* - * Transport switch helper functions - */ -int xprt_register_transport(struct xprt_class *type); -int xprt_unregister_transport(struct xprt_class *type); -int xprt_load_transport(const char *); -void xprt_set_retrans_timeout_def(struct rpc_task *task); -void xprt_set_retrans_timeout_rtt(struct rpc_task *task); -void xprt_wake_pending_tasks(struct rpc_xprt *xprt, int status); -void xprt_wait_for_buffer_space(struct rpc_task *task, rpc_action action); -void xprt_write_space(struct rpc_xprt *xprt); -void xprt_adjust_cwnd(struct rpc_xprt *xprt, struct rpc_task *task, int result); -struct rpc_rqst * xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid); -void xprt_complete_rqst(struct rpc_task *task, int copied); -void xprt_release_rqst_cong(struct rpc_task *task); -void xprt_disconnect_done(struct rpc_xprt *xprt); -void xprt_force_disconnect(struct rpc_xprt *xprt); -void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie); - -bool xprt_lock_connect(struct rpc_xprt *, struct rpc_task *, void *); -void xprt_unlock_connect(struct rpc_xprt *, void *); - -/* - * Reserved bit positions in xprt->state - */ -#define XPRT_LOCKED (0) -#define XPRT_CONNECTED (1) -#define XPRT_CONNECTING (2) -#define XPRT_CLOSE_WAIT (3) -#define XPRT_BOUND (4) -#define XPRT_BINDING (5) -#define XPRT_CLOSING (6) -#define XPRT_CONGESTED (9) - -static inline void xprt_set_connected(struct rpc_xprt *xprt) -{ - set_bit(XPRT_CONNECTED, &xprt->state); -} - -static inline void xprt_clear_connected(struct rpc_xprt *xprt) -{ - clear_bit(XPRT_CONNECTED, &xprt->state); -} - -static inline int xprt_connected(struct rpc_xprt *xprt) -{ - return test_bit(XPRT_CONNECTED, &xprt->state); -} - -static inline int xprt_test_and_set_connected(struct rpc_xprt *xprt) -{ - return test_and_set_bit(XPRT_CONNECTED, &xprt->state); -} - -static inline int xprt_test_and_clear_connected(struct rpc_xprt *xprt) -{ - return test_and_clear_bit(XPRT_CONNECTED, &xprt->state); -} - -static inline void xprt_clear_connecting(struct rpc_xprt *xprt) -{ - smp_mb__before_atomic(); - clear_bit(XPRT_CONNECTING, &xprt->state); - smp_mb__after_atomic(); -} - -static inline int xprt_connecting(struct rpc_xprt *xprt) -{ - return test_bit(XPRT_CONNECTING, &xprt->state); -} - -static inline int xprt_test_and_set_connecting(struct rpc_xprt *xprt) -{ - return test_and_set_bit(XPRT_CONNECTING, &xprt->state); -} - -static inline void xprt_set_bound(struct rpc_xprt *xprt) -{ - test_and_set_bit(XPRT_BOUND, &xprt->state); -} - -static inline int xprt_bound(struct rpc_xprt *xprt) -{ - return test_bit(XPRT_BOUND, &xprt->state); -} - -static inline void xprt_clear_bound(struct rpc_xprt *xprt) -{ - clear_bit(XPRT_BOUND, &xprt->state); -} - -static inline void xprt_clear_binding(struct rpc_xprt *xprt) -{ - smp_mb__before_atomic(); - clear_bit(XPRT_BINDING, &xprt->state); - smp_mb__after_atomic(); -} - -static inline int xprt_test_and_set_binding(struct rpc_xprt *xprt) -{ - return test_and_set_bit(XPRT_BINDING, &xprt->state); -} - -#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) -extern unsigned int rpc_inject_disconnect; -static inline void xprt_inject_disconnect(struct rpc_xprt *xprt) -{ - if (!rpc_inject_disconnect) - return; - if (atomic_dec_return(&xprt->inject_disconnect)) - return; - atomic_set(&xprt->inject_disconnect, rpc_inject_disconnect); - xprt->ops->inject_disconnect(xprt); -} -#else -static inline void xprt_inject_disconnect(struct rpc_xprt *xprt) -{ -} -#endif - -#endif /* __KERNEL__*/ - -#endif /* _LINUX_SUNRPC_XPRT_H */ diff --git a/src/linux/include/linux/sunrpc/xprtmultipath.h b/src/linux/include/linux/sunrpc/xprtmultipath.h deleted file mode 100644 index 507418c..0000000 --- a/src/linux/include/linux/sunrpc/xprtmultipath.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * RPC client multipathing definitions - * - * Copyright (c) 2015, 2016, Primary Data, Inc. All rights reserved. - * - * Trond Myklebust - */ -#ifndef _NET_SUNRPC_XPRTMULTIPATH_H -#define _NET_SUNRPC_XPRTMULTIPATH_H - -struct rpc_xprt_iter_ops; -struct rpc_xprt_switch { - spinlock_t xps_lock; - struct kref xps_kref; - - unsigned int xps_nxprts; - struct list_head xps_xprt_list; - - struct net * xps_net; - - const struct rpc_xprt_iter_ops *xps_iter_ops; - - struct rcu_head xps_rcu; -}; - -struct rpc_xprt_iter { - struct rpc_xprt_switch __rcu *xpi_xpswitch; - struct rpc_xprt * xpi_cursor; - - const struct rpc_xprt_iter_ops *xpi_ops; -}; - - -struct rpc_xprt_iter_ops { - void (*xpi_rewind)(struct rpc_xprt_iter *); - struct rpc_xprt *(*xpi_xprt)(struct rpc_xprt_iter *); - struct rpc_xprt *(*xpi_next)(struct rpc_xprt_iter *); -}; - -extern struct rpc_xprt_switch *xprt_switch_alloc(struct rpc_xprt *xprt, - gfp_t gfp_flags); - -extern struct rpc_xprt_switch *xprt_switch_get(struct rpc_xprt_switch *xps); -extern void xprt_switch_put(struct rpc_xprt_switch *xps); - -extern void rpc_xprt_switch_set_roundrobin(struct rpc_xprt_switch *xps); - -extern void rpc_xprt_switch_add_xprt(struct rpc_xprt_switch *xps, - struct rpc_xprt *xprt); -extern void rpc_xprt_switch_remove_xprt(struct rpc_xprt_switch *xps, - struct rpc_xprt *xprt); - -extern void xprt_iter_init(struct rpc_xprt_iter *xpi, - struct rpc_xprt_switch *xps); - -extern void xprt_iter_init_listall(struct rpc_xprt_iter *xpi, - struct rpc_xprt_switch *xps); - -extern void xprt_iter_destroy(struct rpc_xprt_iter *xpi); - -extern struct rpc_xprt_switch *xprt_iter_xchg_switch( - struct rpc_xprt_iter *xpi, - struct rpc_xprt_switch *newswitch); - -extern struct rpc_xprt *xprt_iter_xprt(struct rpc_xprt_iter *xpi); -extern struct rpc_xprt *xprt_iter_get_xprt(struct rpc_xprt_iter *xpi); -extern struct rpc_xprt *xprt_iter_get_next(struct rpc_xprt_iter *xpi); - -extern bool rpc_xprt_switch_has_addr(struct rpc_xprt_switch *xps, - const struct sockaddr *sap); -#endif diff --git a/src/linux/include/linux/suspend.h b/src/linux/include/linux/suspend.h deleted file mode 100644 index d971837..0000000 --- a/src/linux/include/linux/suspend.h +++ /dev/null @@ -1,540 +0,0 @@ -#ifndef _LINUX_SUSPEND_H -#define _LINUX_SUSPEND_H - -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_VT -extern void pm_set_vt_switch(int); -#else -static inline void pm_set_vt_switch(int do_switch) -{ -} -#endif - -#ifdef CONFIG_VT_CONSOLE_SLEEP -extern void pm_prepare_console(void); -extern void pm_restore_console(void); -#else -static inline void pm_prepare_console(void) -{ -} - -static inline void pm_restore_console(void) -{ -} -#endif - -typedef int __bitwise suspend_state_t; - -#define PM_SUSPEND_ON ((__force suspend_state_t) 0) -#define PM_SUSPEND_FREEZE ((__force suspend_state_t) 1) -#define PM_SUSPEND_STANDBY ((__force suspend_state_t) 2) -#define PM_SUSPEND_MEM ((__force suspend_state_t) 3) -#define PM_SUSPEND_MIN PM_SUSPEND_FREEZE -#define PM_SUSPEND_MAX ((__force suspend_state_t) 4) - -enum suspend_stat_step { - SUSPEND_FREEZE = 1, - SUSPEND_PREPARE, - SUSPEND_SUSPEND, - SUSPEND_SUSPEND_LATE, - SUSPEND_SUSPEND_NOIRQ, - SUSPEND_RESUME_NOIRQ, - SUSPEND_RESUME_EARLY, - SUSPEND_RESUME -}; - -struct suspend_stats { - int success; - int fail; - int failed_freeze; - int failed_prepare; - int failed_suspend; - int failed_suspend_late; - int failed_suspend_noirq; - int failed_resume; - int failed_resume_early; - int failed_resume_noirq; -#define REC_FAILED_NUM 2 - int last_failed_dev; - char failed_devs[REC_FAILED_NUM][40]; - int last_failed_errno; - int errno[REC_FAILED_NUM]; - int last_failed_step; - enum suspend_stat_step failed_steps[REC_FAILED_NUM]; -}; - -extern struct suspend_stats suspend_stats; - -static inline void dpm_save_failed_dev(const char *name) -{ - strlcpy(suspend_stats.failed_devs[suspend_stats.last_failed_dev], - name, - sizeof(suspend_stats.failed_devs[0])); - suspend_stats.last_failed_dev++; - suspend_stats.last_failed_dev %= REC_FAILED_NUM; -} - -static inline void dpm_save_failed_errno(int err) -{ - suspend_stats.errno[suspend_stats.last_failed_errno] = err; - suspend_stats.last_failed_errno++; - suspend_stats.last_failed_errno %= REC_FAILED_NUM; -} - -static inline void dpm_save_failed_step(enum suspend_stat_step step) -{ - suspend_stats.failed_steps[suspend_stats.last_failed_step] = step; - suspend_stats.last_failed_step++; - suspend_stats.last_failed_step %= REC_FAILED_NUM; -} - -/** - * struct platform_suspend_ops - Callbacks for managing platform dependent - * system sleep states. - * - * @valid: Callback to determine if given system sleep state is supported by - * the platform. - * Valid (ie. supported) states are advertised in /sys/power/state. Note - * that it still may be impossible to enter given system sleep state if the - * conditions aren't right. - * There is the %suspend_valid_only_mem function available that can be - * assigned to this if the platform only supports mem sleep. - * - * @begin: Initialise a transition to given system sleep state. - * @begin() is executed right prior to suspending devices. The information - * conveyed to the platform code by @begin() should be disregarded by it as - * soon as @end() is executed. If @begin() fails (ie. returns nonzero), - * @prepare(), @enter() and @finish() will not be called by the PM core. - * This callback is optional. However, if it is implemented, the argument - * passed to @enter() is redundant and should be ignored. - * - * @prepare: Prepare the platform for entering the system sleep state indicated - * by @begin(). - * @prepare() is called right after devices have been suspended (ie. the - * appropriate .suspend() method has been executed for each device) and - * before device drivers' late suspend callbacks are executed. It returns - * 0 on success or a negative error code otherwise, in which case the - * system cannot enter the desired sleep state (@prepare_late(), @enter(), - * and @wake() will not be called in that case). - * - * @prepare_late: Finish preparing the platform for entering the system sleep - * state indicated by @begin(). - * @prepare_late is called before disabling nonboot CPUs and after - * device drivers' late suspend callbacks have been executed. It returns - * 0 on success or a negative error code otherwise, in which case the - * system cannot enter the desired sleep state (@enter() will not be - * executed). - * - * @enter: Enter the system sleep state indicated by @begin() or represented by - * the argument if @begin() is not implemented. - * This callback is mandatory. It returns 0 on success or a negative - * error code otherwise, in which case the system cannot enter the desired - * sleep state. - * - * @wake: Called when the system has just left a sleep state, right after - * the nonboot CPUs have been enabled and before device drivers' early - * resume callbacks are executed. - * This callback is optional, but should be implemented by the platforms - * that implement @prepare_late(). If implemented, it is always called - * after @prepare_late and @enter(), even if one of them fails. - * - * @finish: Finish wake-up of the platform. - * @finish is called right prior to calling device drivers' regular suspend - * callbacks. - * This callback is optional, but should be implemented by the platforms - * that implement @prepare(). If implemented, it is always called after - * @enter() and @wake(), even if any of them fails. It is executed after - * a failing @prepare. - * - * @suspend_again: Returns whether the system should suspend again (true) or - * not (false). If the platform wants to poll sensors or execute some - * code during suspended without invoking userspace and most of devices, - * suspend_again callback is the place assuming that periodic-wakeup or - * alarm-wakeup is already setup. This allows to execute some codes while - * being kept suspended in the view of userland and devices. - * - * @end: Called by the PM core right after resuming devices, to indicate to - * the platform that the system has returned to the working state or - * the transition to the sleep state has been aborted. - * This callback is optional, but should be implemented by the platforms - * that implement @begin(). Accordingly, platforms implementing @begin() - * should also provide a @end() which cleans up transitions aborted before - * @enter(). - * - * @recover: Recover the platform from a suspend failure. - * Called by the PM core if the suspending of devices fails. - * This callback is optional and should only be implemented by platforms - * which require special recovery actions in that situation. - */ -struct platform_suspend_ops { - int (*valid)(suspend_state_t state); - int (*begin)(suspend_state_t state); - int (*prepare)(void); - int (*prepare_late)(void); - int (*enter)(suspend_state_t state); - void (*wake)(void); - void (*finish)(void); - bool (*suspend_again)(void); - void (*end)(void); - void (*recover)(void); -}; - -struct platform_freeze_ops { - int (*begin)(void); - int (*prepare)(void); - void (*restore)(void); - void (*end)(void); -}; - -#ifdef CONFIG_SUSPEND -/** - * suspend_set_ops - set platform dependent suspend operations - * @ops: The new suspend operations to set. - */ -extern void suspend_set_ops(const struct platform_suspend_ops *ops); -extern int suspend_valid_only_mem(suspend_state_t state); - -extern unsigned int pm_suspend_global_flags; - -#define PM_SUSPEND_FLAG_FW_SUSPEND (1 << 0) -#define PM_SUSPEND_FLAG_FW_RESUME (1 << 1) - -static inline void pm_suspend_clear_flags(void) -{ - pm_suspend_global_flags = 0; -} - -static inline void pm_set_suspend_via_firmware(void) -{ - pm_suspend_global_flags |= PM_SUSPEND_FLAG_FW_SUSPEND; -} - -static inline void pm_set_resume_via_firmware(void) -{ - pm_suspend_global_flags |= PM_SUSPEND_FLAG_FW_RESUME; -} - -static inline bool pm_suspend_via_firmware(void) -{ - return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_SUSPEND); -} - -static inline bool pm_resume_via_firmware(void) -{ - return !!(pm_suspend_global_flags & PM_SUSPEND_FLAG_FW_RESUME); -} - -/* Suspend-to-idle state machnine. */ -enum freeze_state { - FREEZE_STATE_NONE, /* Not suspended/suspending. */ - FREEZE_STATE_ENTER, /* Enter suspend-to-idle. */ - FREEZE_STATE_WAKE, /* Wake up from suspend-to-idle. */ -}; - -extern enum freeze_state __read_mostly suspend_freeze_state; - -static inline bool idle_should_freeze(void) -{ - return unlikely(suspend_freeze_state == FREEZE_STATE_ENTER); -} - -extern void __init pm_states_init(void); -extern void freeze_set_ops(const struct platform_freeze_ops *ops); -extern void freeze_wake(void); - -/** - * arch_suspend_disable_irqs - disable IRQs for suspend - * - * Disables IRQs (in the default case). This is a weak symbol in the common - * code and thus allows architectures to override it if more needs to be - * done. Not called for suspend to disk. - */ -extern void arch_suspend_disable_irqs(void); - -/** - * arch_suspend_enable_irqs - enable IRQs after suspend - * - * Enables IRQs (in the default case). This is a weak symbol in the common - * code and thus allows architectures to override it if more needs to be - * done. Not called for suspend to disk. - */ -extern void arch_suspend_enable_irqs(void); - -extern int pm_suspend(suspend_state_t state); -#else /* !CONFIG_SUSPEND */ -#define suspend_valid_only_mem NULL - -static inline void pm_suspend_clear_flags(void) {} -static inline void pm_set_suspend_via_firmware(void) {} -static inline void pm_set_resume_via_firmware(void) {} -static inline bool pm_suspend_via_firmware(void) { return false; } -static inline bool pm_resume_via_firmware(void) { return false; } - -static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {} -static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; } -static inline bool idle_should_freeze(void) { return false; } -static inline void __init pm_states_init(void) {} -static inline void freeze_set_ops(const struct platform_freeze_ops *ops) {} -static inline void freeze_wake(void) {} -#endif /* !CONFIG_SUSPEND */ - -/* struct pbe is used for creating lists of pages that should be restored - * atomically during the resume from disk, because the page frames they have - * occupied before the suspend are in use. - */ -struct pbe { - void *address; /* address of the copy */ - void *orig_address; /* original address of a page */ - struct pbe *next; -}; - -/* mm/page_alloc.c */ -extern void mark_free_pages(struct zone *zone); - -/** - * struct platform_hibernation_ops - hibernation platform support - * - * The methods in this structure allow a platform to carry out special - * operations required by it during a hibernation transition. - * - * All the methods below, except for @recover(), must be implemented. - * - * @begin: Tell the platform driver that we're starting hibernation. - * Called right after shrinking memory and before freezing devices. - * - * @end: Called by the PM core right after resuming devices, to indicate to - * the platform that the system has returned to the working state. - * - * @pre_snapshot: Prepare the platform for creating the hibernation image. - * Called right after devices have been frozen and before the nonboot - * CPUs are disabled (runs with IRQs on). - * - * @finish: Restore the previous state of the platform after the hibernation - * image has been created *or* put the platform into the normal operation - * mode after the hibernation (the same method is executed in both cases). - * Called right after the nonboot CPUs have been enabled and before - * thawing devices (runs with IRQs on). - * - * @prepare: Prepare the platform for entering the low power state. - * Called right after the hibernation image has been saved and before - * devices are prepared for entering the low power state. - * - * @enter: Put the system into the low power state after the hibernation image - * has been saved to disk. - * Called after the nonboot CPUs have been disabled and all of the low - * level devices have been shut down (runs with IRQs off). - * - * @leave: Perform the first stage of the cleanup after the system sleep state - * indicated by @set_target() has been left. - * Called right after the control has been passed from the boot kernel to - * the image kernel, before the nonboot CPUs are enabled and before devices - * are resumed. Executed with interrupts disabled. - * - * @pre_restore: Prepare system for the restoration from a hibernation image. - * Called right after devices have been frozen and before the nonboot - * CPUs are disabled (runs with IRQs on). - * - * @restore_cleanup: Clean up after a failing image restoration. - * Called right after the nonboot CPUs have been enabled and before - * thawing devices (runs with IRQs on). - * - * @recover: Recover the platform from a failure to suspend devices. - * Called by the PM core if the suspending of devices during hibernation - * fails. This callback is optional and should only be implemented by - * platforms which require special recovery actions in that situation. - */ -struct platform_hibernation_ops { - int (*begin)(void); - void (*end)(void); - int (*pre_snapshot)(void); - void (*finish)(void); - int (*prepare)(void); - int (*enter)(void); - void (*leave)(void); - int (*pre_restore)(void); - void (*restore_cleanup)(void); - void (*recover)(void); -}; - -#ifdef CONFIG_HIBERNATION -/* kernel/power/snapshot.c */ -extern void __register_nosave_region(unsigned long b, unsigned long e, int km); -static inline void __init register_nosave_region(unsigned long b, unsigned long e) -{ - __register_nosave_region(b, e, 0); -} -static inline void __init register_nosave_region_late(unsigned long b, unsigned long e) -{ - __register_nosave_region(b, e, 1); -} -extern int swsusp_page_is_forbidden(struct page *); -extern void swsusp_set_page_free(struct page *); -extern void swsusp_unset_page_free(struct page *); -extern unsigned long get_safe_page(gfp_t gfp_mask); - -extern void hibernation_set_ops(const struct platform_hibernation_ops *ops); -extern int hibernate(void); -extern bool system_entering_hibernation(void); -extern bool hibernation_available(void); -asmlinkage int swsusp_save(void); -extern struct pbe *restore_pblist; -#else /* CONFIG_HIBERNATION */ -static inline void register_nosave_region(unsigned long b, unsigned long e) {} -static inline void register_nosave_region_late(unsigned long b, unsigned long e) {} -static inline int swsusp_page_is_forbidden(struct page *p) { return 0; } -static inline void swsusp_set_page_free(struct page *p) {} -static inline void swsusp_unset_page_free(struct page *p) {} - -static inline void hibernation_set_ops(const struct platform_hibernation_ops *ops) {} -static inline int hibernate(void) { return -ENOSYS; } -static inline bool system_entering_hibernation(void) { return false; } -static inline bool hibernation_available(void) { return false; } -#endif /* CONFIG_HIBERNATION */ - -/* Hibernation and suspend events */ -#define PM_HIBERNATION_PREPARE 0x0001 /* Going to hibernate */ -#define PM_POST_HIBERNATION 0x0002 /* Hibernation finished */ -#define PM_SUSPEND_PREPARE 0x0003 /* Going to suspend the system */ -#define PM_POST_SUSPEND 0x0004 /* Suspend finished */ -#define PM_RESTORE_PREPARE 0x0005 /* Going to restore a saved image */ -#define PM_POST_RESTORE 0x0006 /* Restore failed */ - -extern struct mutex pm_mutex; - -#ifdef CONFIG_PM_SLEEP -void save_processor_state(void); -void restore_processor_state(void); - -/* kernel/power/main.c */ -extern int register_pm_notifier(struct notifier_block *nb); -extern int unregister_pm_notifier(struct notifier_block *nb); - -#define pm_notifier(fn, pri) { \ - static struct notifier_block fn##_nb = \ - { .notifier_call = fn, .priority = pri }; \ - register_pm_notifier(&fn##_nb); \ -} - -/* drivers/base/power/wakeup.c */ -extern bool events_check_enabled; -extern unsigned int pm_wakeup_irq; - -extern bool pm_wakeup_pending(void); -extern void pm_system_wakeup(void); -extern void pm_wakeup_clear(void); -extern void pm_system_irq_wakeup(unsigned int irq_number); -extern bool pm_get_wakeup_count(unsigned int *count, bool block); -extern bool pm_save_wakeup_count(unsigned int count); -extern void pm_wakep_autosleep_enabled(bool set); -extern void pm_print_active_wakeup_sources(void); - -static inline void lock_system_sleep(void) -{ - current->flags |= PF_FREEZER_SKIP; - mutex_lock(&pm_mutex); -} - -static inline void unlock_system_sleep(void) -{ - /* - * Don't use freezer_count() because we don't want the call to - * try_to_freeze() here. - * - * Reason: - * Fundamentally, we just don't need it, because freezing condition - * doesn't come into effect until we release the pm_mutex lock, - * since the freezer always works with pm_mutex held. - * - * More importantly, in the case of hibernation, - * unlock_system_sleep() gets called in snapshot_read() and - * snapshot_write() when the freezing condition is still in effect. - * Which means, if we use try_to_freeze() here, it would make them - * enter the refrigerator, thus causing hibernation to lockup. - */ - current->flags &= ~PF_FREEZER_SKIP; - mutex_unlock(&pm_mutex); -} - -#else /* !CONFIG_PM_SLEEP */ - -static inline int register_pm_notifier(struct notifier_block *nb) -{ - return 0; -} - -static inline int unregister_pm_notifier(struct notifier_block *nb) -{ - return 0; -} - -#define pm_notifier(fn, pri) do { (void)(fn); } while (0) - -static inline bool pm_wakeup_pending(void) { return false; } -static inline void pm_system_wakeup(void) {} -static inline void pm_wakeup_clear(void) {} -static inline void pm_system_irq_wakeup(unsigned int irq_number) {} - -static inline void lock_system_sleep(void) {} -static inline void unlock_system_sleep(void) {} - -#endif /* !CONFIG_PM_SLEEP */ - -#ifdef CONFIG_PM_SLEEP_DEBUG -extern bool pm_print_times_enabled; -#else -#define pm_print_times_enabled (false) -#endif - -#ifdef CONFIG_PM_AUTOSLEEP - -/* kernel/power/autosleep.c */ -void queue_up_suspend_work(void); - -#else /* !CONFIG_PM_AUTOSLEEP */ - -static inline void queue_up_suspend_work(void) {} - -#endif /* !CONFIG_PM_AUTOSLEEP */ - -#ifdef CONFIG_ARCH_SAVE_PAGE_KEYS -/* - * The ARCH_SAVE_PAGE_KEYS functions can be used by an architecture - * to save/restore additional information to/from the array of page - * frame numbers in the hibernation image. For s390 this is used to - * save and restore the storage key for each page that is included - * in the hibernation image. - */ -unsigned long page_key_additional_pages(unsigned long pages); -int page_key_alloc(unsigned long pages); -void page_key_free(void); -void page_key_read(unsigned long *pfn); -void page_key_memorize(unsigned long *pfn); -void page_key_write(void *address); - -#else /* !CONFIG_ARCH_SAVE_PAGE_KEYS */ - -static inline unsigned long page_key_additional_pages(unsigned long pages) -{ - return 0; -} - -static inline int page_key_alloc(unsigned long pages) -{ - return 0; -} - -static inline void page_key_free(void) {} -static inline void page_key_read(unsigned long *pfn) {} -static inline void page_key_memorize(unsigned long *pfn) {} -static inline void page_key_write(void *address) {} - -#endif /* !CONFIG_ARCH_SAVE_PAGE_KEYS */ - -#endif /* _LINUX_SUSPEND_H */ diff --git a/src/linux/include/linux/swab.h b/src/linux/include/linux/swab.h deleted file mode 100644 index 9ad3c60..0000000 --- a/src/linux/include/linux/swab.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _LINUX_SWAB_H -#define _LINUX_SWAB_H - -#include - -# define swab16 __swab16 -# define swab32 __swab32 -# define swab64 __swab64 -# define swahw32 __swahw32 -# define swahb32 __swahb32 -# define swab16p __swab16p -# define swab32p __swab32p -# define swab64p __swab64p -# define swahw32p __swahw32p -# define swahb32p __swahb32p -# define swab16s __swab16s -# define swab32s __swab32s -# define swab64s __swab64s -# define swahw32s __swahw32s -# define swahb32s __swahb32s -#endif /* _LINUX_SWAB_H */ diff --git a/src/linux/include/linux/swait.h b/src/linux/include/linux/swait.h deleted file mode 100644 index c1f9c62..0000000 --- a/src/linux/include/linux/swait.h +++ /dev/null @@ -1,172 +0,0 @@ -#ifndef _LINUX_SWAIT_H -#define _LINUX_SWAIT_H - -#include -#include -#include -#include - -/* - * Simple wait queues - * - * While these are very similar to the other/complex wait queues (wait.h) the - * most important difference is that the simple waitqueue allows for - * deterministic behaviour -- IOW it has strictly bounded IRQ and lock hold - * times. - * - * In order to make this so, we had to drop a fair number of features of the - * other waitqueue code; notably: - * - * - mixing INTERRUPTIBLE and UNINTERRUPTIBLE sleeps on the same waitqueue; - * all wakeups are TASK_NORMAL in order to avoid O(n) lookups for the right - * sleeper state. - * - * - the exclusive mode; because this requires preserving the list order - * and this is hard. - * - * - custom wake functions; because you cannot give any guarantees about - * random code. - * - * As a side effect of this; the data structures are slimmer. - * - * One would recommend using this wait queue where possible. - */ - -struct task_struct; - -struct swait_queue_head { - raw_spinlock_t lock; - struct list_head task_list; -}; - -struct swait_queue { - struct task_struct *task; - struct list_head task_list; -}; - -#define __SWAITQUEUE_INITIALIZER(name) { \ - .task = current, \ - .task_list = LIST_HEAD_INIT((name).task_list), \ -} - -#define DECLARE_SWAITQUEUE(name) \ - struct swait_queue name = __SWAITQUEUE_INITIALIZER(name) - -#define __SWAIT_QUEUE_HEAD_INITIALIZER(name) { \ - .lock = __RAW_SPIN_LOCK_UNLOCKED(name.lock), \ - .task_list = LIST_HEAD_INIT((name).task_list), \ -} - -#define DECLARE_SWAIT_QUEUE_HEAD(name) \ - struct swait_queue_head name = __SWAIT_QUEUE_HEAD_INITIALIZER(name) - -extern void __init_swait_queue_head(struct swait_queue_head *q, const char *name, - struct lock_class_key *key); - -#define init_swait_queue_head(q) \ - do { \ - static struct lock_class_key __key; \ - __init_swait_queue_head((q), #q, &__key); \ - } while (0) - -#ifdef CONFIG_LOCKDEP -# define __SWAIT_QUEUE_HEAD_INIT_ONSTACK(name) \ - ({ init_swait_queue_head(&name); name; }) -# define DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(name) \ - struct swait_queue_head name = __SWAIT_QUEUE_HEAD_INIT_ONSTACK(name) -#else -# define DECLARE_SWAIT_QUEUE_HEAD_ONSTACK(name) \ - DECLARE_SWAIT_QUEUE_HEAD(name) -#endif - -static inline int swait_active(struct swait_queue_head *q) -{ - return !list_empty(&q->task_list); -} - -extern void swake_up(struct swait_queue_head *q); -extern void swake_up_all(struct swait_queue_head *q); -extern void swake_up_locked(struct swait_queue_head *q); - -extern void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait); -extern void prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait, int state); -extern long prepare_to_swait_event(struct swait_queue_head *q, struct swait_queue *wait, int state); - -extern void __finish_swait(struct swait_queue_head *q, struct swait_queue *wait); -extern void finish_swait(struct swait_queue_head *q, struct swait_queue *wait); - -/* as per ___wait_event() but for swait, therefore "exclusive == 0" */ -#define ___swait_event(wq, condition, state, ret, cmd) \ -({ \ - struct swait_queue __wait; \ - long __ret = ret; \ - \ - INIT_LIST_HEAD(&__wait.task_list); \ - for (;;) { \ - long __int = prepare_to_swait_event(&wq, &__wait, state);\ - \ - if (condition) \ - break; \ - \ - if (___wait_is_interruptible(state) && __int) { \ - __ret = __int; \ - break; \ - } \ - \ - cmd; \ - } \ - finish_swait(&wq, &__wait); \ - __ret; \ -}) - -#define __swait_event(wq, condition) \ - (void)___swait_event(wq, condition, TASK_UNINTERRUPTIBLE, 0, \ - schedule()) - -#define swait_event(wq, condition) \ -do { \ - if (condition) \ - break; \ - __swait_event(wq, condition); \ -} while (0) - -#define __swait_event_timeout(wq, condition, timeout) \ - ___swait_event(wq, ___wait_cond_timeout(condition), \ - TASK_UNINTERRUPTIBLE, timeout, \ - __ret = schedule_timeout(__ret)) - -#define swait_event_timeout(wq, condition, timeout) \ -({ \ - long __ret = timeout; \ - if (!___wait_cond_timeout(condition)) \ - __ret = __swait_event_timeout(wq, condition, timeout); \ - __ret; \ -}) - -#define __swait_event_interruptible(wq, condition) \ - ___swait_event(wq, condition, TASK_INTERRUPTIBLE, 0, \ - schedule()) - -#define swait_event_interruptible(wq, condition) \ -({ \ - int __ret = 0; \ - if (!(condition)) \ - __ret = __swait_event_interruptible(wq, condition); \ - __ret; \ -}) - -#define __swait_event_interruptible_timeout(wq, condition, timeout) \ - ___swait_event(wq, ___wait_cond_timeout(condition), \ - TASK_INTERRUPTIBLE, timeout, \ - __ret = schedule_timeout(__ret)) - -#define swait_event_interruptible_timeout(wq, condition, timeout) \ -({ \ - long __ret = timeout; \ - if (!___wait_cond_timeout(condition)) \ - __ret = __swait_event_interruptible_timeout(wq, \ - condition, timeout); \ - __ret; \ -}) - -#endif /* _LINUX_SWAIT_H */ diff --git a/src/linux/include/linux/swap.h b/src/linux/include/linux/swap.h deleted file mode 100644 index a56523c..0000000 --- a/src/linux/include/linux/swap.h +++ /dev/null @@ -1,586 +0,0 @@ -#ifndef _LINUX_SWAP_H -#define _LINUX_SWAP_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct notifier_block; - -struct bio; - -#define SWAP_FLAG_PREFER 0x8000 /* set if swap priority specified */ -#define SWAP_FLAG_PRIO_MASK 0x7fff -#define SWAP_FLAG_PRIO_SHIFT 0 -#define SWAP_FLAG_DISCARD 0x10000 /* enable discard for swap */ -#define SWAP_FLAG_DISCARD_ONCE 0x20000 /* discard swap area at swapon-time */ -#define SWAP_FLAG_DISCARD_PAGES 0x40000 /* discard page-clusters after use */ - -#define SWAP_FLAGS_VALID (SWAP_FLAG_PRIO_MASK | SWAP_FLAG_PREFER | \ - SWAP_FLAG_DISCARD | SWAP_FLAG_DISCARD_ONCE | \ - SWAP_FLAG_DISCARD_PAGES) - -static inline int current_is_kswapd(void) -{ - return current->flags & PF_KSWAPD; -} - -/* - * MAX_SWAPFILES defines the maximum number of swaptypes: things which can - * be swapped to. The swap type and the offset into that swap type are - * encoded into pte's and into pgoff_t's in the swapcache. Using five bits - * for the type means that the maximum number of swapcache pages is 27 bits - * on 32-bit-pgoff_t architectures. And that assumes that the architecture packs - * the type/offset into the pte as 5/27 as well. - */ -#define MAX_SWAPFILES_SHIFT 5 - -/* - * Use some of the swap files numbers for other purposes. This - * is a convenient way to hook into the VM to trigger special - * actions on faults. - */ - -/* - * NUMA node memory migration support - */ -#ifdef CONFIG_MIGRATION -#define SWP_MIGRATION_NUM 2 -#define SWP_MIGRATION_READ (MAX_SWAPFILES + SWP_HWPOISON_NUM) -#define SWP_MIGRATION_WRITE (MAX_SWAPFILES + SWP_HWPOISON_NUM + 1) -#else -#define SWP_MIGRATION_NUM 0 -#endif - -/* - * Handling of hardware poisoned pages with memory corruption. - */ -#ifdef CONFIG_MEMORY_FAILURE -#define SWP_HWPOISON_NUM 1 -#define SWP_HWPOISON MAX_SWAPFILES -#else -#define SWP_HWPOISON_NUM 0 -#endif - -#define MAX_SWAPFILES \ - ((1 << MAX_SWAPFILES_SHIFT) - SWP_MIGRATION_NUM - SWP_HWPOISON_NUM) - -/* - * Magic header for a swap area. The first part of the union is - * what the swap magic looks like for the old (limited to 128MB) - * swap area format, the second part of the union adds - in the - * old reserved area - some extra information. Note that the first - * kilobyte is reserved for boot loader or disk label stuff... - * - * Having the magic at the end of the PAGE_SIZE makes detecting swap - * areas somewhat tricky on machines that support multiple page sizes. - * For 2.5 we'll probably want to move the magic to just beyond the - * bootbits... - */ -union swap_header { - struct { - char reserved[PAGE_SIZE - 10]; - char magic[10]; /* SWAP-SPACE or SWAPSPACE2 */ - } magic; - struct { - char bootbits[1024]; /* Space for disklabel etc. */ - __u32 version; - __u32 last_page; - __u32 nr_badpages; - unsigned char sws_uuid[16]; - unsigned char sws_volume[16]; - __u32 padding[117]; - __u32 badpages[1]; - } info; -}; - -/* - * current->reclaim_state points to one of these when a task is running - * memory reclaim - */ -struct reclaim_state { - unsigned long reclaimed_slab; -}; - -#ifdef __KERNEL__ - -struct address_space; -struct sysinfo; -struct writeback_control; -struct zone; - -/* - * A swap extent maps a range of a swapfile's PAGE_SIZE pages onto a range of - * disk blocks. A list of swap extents maps the entire swapfile. (Where the - * term `swapfile' refers to either a blockdevice or an IS_REG file. Apart - * from setup, they're handled identically. - * - * We always assume that blocks are of size PAGE_SIZE. - */ -struct swap_extent { - struct list_head list; - pgoff_t start_page; - pgoff_t nr_pages; - sector_t start_block; -}; - -/* - * Max bad pages in the new format.. - */ -#define __swapoffset(x) ((unsigned long)&((union swap_header *)0)->x) -#define MAX_SWAP_BADPAGES \ - ((__swapoffset(magic.magic) - __swapoffset(info.badpages)) / sizeof(int)) - -enum { - SWP_USED = (1 << 0), /* is slot in swap_info[] used? */ - SWP_WRITEOK = (1 << 1), /* ok to write to this swap? */ - SWP_DISCARDABLE = (1 << 2), /* blkdev support discard */ - SWP_DISCARDING = (1 << 3), /* now discarding a free cluster */ - SWP_SOLIDSTATE = (1 << 4), /* blkdev seeks are cheap */ - SWP_CONTINUED = (1 << 5), /* swap_map has count continuation */ - SWP_BLKDEV = (1 << 6), /* its a block device */ - SWP_FILE = (1 << 7), /* set after swap_activate success */ - SWP_AREA_DISCARD = (1 << 8), /* single-time swap area discards */ - SWP_PAGE_DISCARD = (1 << 9), /* freed swap page-cluster discards */ - /* add others here before... */ - SWP_SCANNING = (1 << 10), /* refcount in scan_swap_map */ -}; - -#define SWAP_CLUSTER_MAX 32UL -#define COMPACT_CLUSTER_MAX SWAP_CLUSTER_MAX - -#define SWAP_MAP_MAX 0x3e /* Max duplication count, in first swap_map */ -#define SWAP_MAP_BAD 0x3f /* Note pageblock is bad, in first swap_map */ -#define SWAP_HAS_CACHE 0x40 /* Flag page is cached, in first swap_map */ -#define SWAP_CONT_MAX 0x7f /* Max count, in each swap_map continuation */ -#define COUNT_CONTINUED 0x80 /* See swap_map continuation for full count */ -#define SWAP_MAP_SHMEM 0xbf /* Owned by shmem/tmpfs, in first swap_map */ - -/* - * We use this to track usage of a cluster. A cluster is a block of swap disk - * space with SWAPFILE_CLUSTER pages long and naturally aligns in disk. All - * free clusters are organized into a list. We fetch an entry from the list to - * get a free cluster. - * - * The data field stores next cluster if the cluster is free or cluster usage - * counter otherwise. The flags field determines if a cluster is free. This is - * protected by swap_info_struct.lock. - */ -struct swap_cluster_info { - unsigned int data:24; - unsigned int flags:8; -}; -#define CLUSTER_FLAG_FREE 1 /* This cluster is free */ -#define CLUSTER_FLAG_NEXT_NULL 2 /* This cluster has no next cluster */ - -/* - * We assign a cluster to each CPU, so each CPU can allocate swap entry from - * its own cluster and swapout sequentially. The purpose is to optimize swapout - * throughput. - */ -struct percpu_cluster { - struct swap_cluster_info index; /* Current cluster index */ - unsigned int next; /* Likely next allocation offset */ -}; - -struct swap_cluster_list { - struct swap_cluster_info head; - struct swap_cluster_info tail; -}; - -/* - * The in-memory structure used to track swap areas. - */ -struct swap_info_struct { - unsigned long flags; /* SWP_USED etc: see above */ - signed short prio; /* swap priority of this type */ - struct plist_node list; /* entry in swap_active_head */ - struct plist_node avail_list; /* entry in swap_avail_head */ - signed char type; /* strange name for an index */ - unsigned int max; /* extent of the swap_map */ - unsigned char *swap_map; /* vmalloc'ed array of usage counts */ - struct swap_cluster_info *cluster_info; /* cluster info. Only for SSD */ - struct swap_cluster_list free_clusters; /* free clusters list */ - unsigned int lowest_bit; /* index of first free in swap_map */ - unsigned int highest_bit; /* index of last free in swap_map */ - unsigned int pages; /* total of usable pages of swap */ - unsigned int inuse_pages; /* number of those currently in use */ - unsigned int cluster_next; /* likely index for next allocation */ - unsigned int cluster_nr; /* countdown to next cluster search */ - struct percpu_cluster __percpu *percpu_cluster; /* per cpu's swap location */ - struct swap_extent *curr_swap_extent; - struct swap_extent first_swap_extent; - struct block_device *bdev; /* swap device or bdev of swap file */ - struct file *swap_file; /* seldom referenced */ - unsigned int old_block_size; /* seldom referenced */ -#ifdef CONFIG_FRONTSWAP - unsigned long *frontswap_map; /* frontswap in-use, one bit per page */ - atomic_t frontswap_pages; /* frontswap pages in-use counter */ -#endif - spinlock_t lock; /* - * protect map scan related fields like - * swap_map, lowest_bit, highest_bit, - * inuse_pages, cluster_next, - * cluster_nr, lowest_alloc, - * highest_alloc, free/discard cluster - * list. other fields are only changed - * at swapon/swapoff, so are protected - * by swap_lock. changing flags need - * hold this lock and swap_lock. If - * both locks need hold, hold swap_lock - * first. - */ - struct work_struct discard_work; /* discard worker */ - struct swap_cluster_list discard_clusters; /* discard clusters list */ -}; - -/* linux/mm/workingset.c */ -void *workingset_eviction(struct address_space *mapping, struct page *page); -bool workingset_refault(void *shadow); -void workingset_activation(struct page *page); -extern struct list_lru workingset_shadow_nodes; - -static inline unsigned int workingset_node_pages(struct radix_tree_node *node) -{ - return node->count & RADIX_TREE_COUNT_MASK; -} - -static inline void workingset_node_pages_inc(struct radix_tree_node *node) -{ - node->count++; -} - -static inline void workingset_node_pages_dec(struct radix_tree_node *node) -{ - VM_WARN_ON_ONCE(!workingset_node_pages(node)); - node->count--; -} - -static inline unsigned int workingset_node_shadows(struct radix_tree_node *node) -{ - return node->count >> RADIX_TREE_COUNT_SHIFT; -} - -static inline void workingset_node_shadows_inc(struct radix_tree_node *node) -{ - node->count += 1U << RADIX_TREE_COUNT_SHIFT; -} - -static inline void workingset_node_shadows_dec(struct radix_tree_node *node) -{ - VM_WARN_ON_ONCE(!workingset_node_shadows(node)); - node->count -= 1U << RADIX_TREE_COUNT_SHIFT; -} - -/* linux/mm/page_alloc.c */ -extern unsigned long totalram_pages; -extern unsigned long totalreserve_pages; -extern unsigned long nr_free_buffer_pages(void); -extern unsigned long nr_free_pagecache_pages(void); - -/* Definition of global_page_state not available yet */ -#define nr_free_pages() global_page_state(NR_FREE_PAGES) - - -/* linux/mm/swap.c */ -extern void lru_cache_add(struct page *); -extern void lru_cache_add_anon(struct page *page); -extern void lru_cache_add_file(struct page *page); -extern void lru_add_page_tail(struct page *page, struct page *page_tail, - struct lruvec *lruvec, struct list_head *head); -extern void activate_page(struct page *); -extern void mark_page_accessed(struct page *); -extern void lru_add_drain(void); -extern void lru_add_drain_cpu(int cpu); -extern void lru_add_drain_all(void); -extern void rotate_reclaimable_page(struct page *page); -extern void deactivate_file_page(struct page *page); -extern void deactivate_page(struct page *page); -extern void swap_setup(void); - -extern void add_page_to_unevictable_list(struct page *page); - -extern void lru_cache_add_active_or_unevictable(struct page *page, - struct vm_area_struct *vma); - -/* linux/mm/vmscan.c */ -extern unsigned long zone_reclaimable_pages(struct zone *zone); -extern unsigned long pgdat_reclaimable_pages(struct pglist_data *pgdat); -extern unsigned long try_to_free_pages(struct zonelist *zonelist, int order, - gfp_t gfp_mask, nodemask_t *mask); -extern int __isolate_lru_page(struct page *page, isolate_mode_t mode); -extern unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg, - unsigned long nr_pages, - gfp_t gfp_mask, - bool may_swap); -extern unsigned long mem_cgroup_shrink_node(struct mem_cgroup *mem, - gfp_t gfp_mask, bool noswap, - pg_data_t *pgdat, - unsigned long *nr_scanned); -extern unsigned long shrink_all_memory(unsigned long nr_pages); -extern int vm_swappiness; -extern int remove_mapping(struct address_space *mapping, struct page *page); -extern unsigned long vm_total_pages; - -#ifdef CONFIG_NUMA -extern int node_reclaim_mode; -extern int sysctl_min_unmapped_ratio; -extern int sysctl_min_slab_ratio; -extern int node_reclaim(struct pglist_data *, gfp_t, unsigned int); -#else -#define node_reclaim_mode 0 -static inline int node_reclaim(struct pglist_data *pgdat, gfp_t mask, - unsigned int order) -{ - return 0; -} -#endif - -extern int page_evictable(struct page *page); -extern void check_move_unevictable_pages(struct page **, int nr_pages); - -extern int kswapd_run(int nid); -extern void kswapd_stop(int nid); - -#ifdef CONFIG_SWAP -/* linux/mm/page_io.c */ -extern int swap_readpage(struct page *); -extern int swap_writepage(struct page *page, struct writeback_control *wbc); -extern void end_swap_bio_write(struct bio *bio); -extern int __swap_writepage(struct page *page, struct writeback_control *wbc, - bio_end_io_t end_write_func); -extern int swap_set_page_dirty(struct page *page); - -int add_swap_extent(struct swap_info_struct *sis, unsigned long start_page, - unsigned long nr_pages, sector_t start_block); -int generic_swapfile_activate(struct swap_info_struct *, struct file *, - sector_t *); - -/* linux/mm/swap_state.c */ -extern struct address_space swapper_spaces[]; -#define swap_address_space(entry) (&swapper_spaces[swp_type(entry)]) -extern unsigned long total_swapcache_pages(void); -extern void show_swap_cache_info(void); -extern int add_to_swap(struct page *, struct list_head *list); -extern int add_to_swap_cache(struct page *, swp_entry_t, gfp_t); -extern int __add_to_swap_cache(struct page *page, swp_entry_t entry); -extern void __delete_from_swap_cache(struct page *); -extern void delete_from_swap_cache(struct page *); -extern void free_page_and_swap_cache(struct page *); -extern void free_pages_and_swap_cache(struct page **, int); -extern struct page *lookup_swap_cache(swp_entry_t); -extern struct page *read_swap_cache_async(swp_entry_t, gfp_t, - struct vm_area_struct *vma, unsigned long addr); -extern struct page *__read_swap_cache_async(swp_entry_t, gfp_t, - struct vm_area_struct *vma, unsigned long addr, - bool *new_page_allocated); -extern struct page *swapin_readahead(swp_entry_t, gfp_t, - struct vm_area_struct *vma, unsigned long addr); - -/* linux/mm/swapfile.c */ -extern atomic_long_t nr_swap_pages; -extern long total_swap_pages; - -/* Swap 50% full? Release swapcache more aggressively.. */ -static inline bool vm_swap_full(void) -{ - return atomic_long_read(&nr_swap_pages) * 2 < total_swap_pages; -} - -static inline long get_nr_swap_pages(void) -{ - return atomic_long_read(&nr_swap_pages); -} - -extern void si_swapinfo(struct sysinfo *); -extern swp_entry_t get_swap_page(void); -extern swp_entry_t get_swap_page_of_type(int); -extern int add_swap_count_continuation(swp_entry_t, gfp_t); -extern void swap_shmem_alloc(swp_entry_t); -extern int swap_duplicate(swp_entry_t); -extern int swapcache_prepare(swp_entry_t); -extern void swap_free(swp_entry_t); -extern void swapcache_free(swp_entry_t); -extern int free_swap_and_cache(swp_entry_t); -extern int swap_type_of(dev_t, sector_t, struct block_device **); -extern unsigned int count_swap_pages(int, int); -extern sector_t map_swap_page(struct page *, struct block_device **); -extern sector_t swapdev_block(int, pgoff_t); -extern int page_swapcount(struct page *); -extern int swp_swapcount(swp_entry_t entry); -extern struct swap_info_struct *page_swap_info(struct page *); -extern bool reuse_swap_page(struct page *, int *); -extern int try_to_free_swap(struct page *); -struct backing_dev_info; - -#else /* CONFIG_SWAP */ - -#define swap_address_space(entry) (NULL) -#define get_nr_swap_pages() 0L -#define total_swap_pages 0L -#define total_swapcache_pages() 0UL -#define vm_swap_full() 0 - -#define si_swapinfo(val) \ - do { (val)->freeswap = (val)->totalswap = 0; } while (0) -/* only sparc can not include linux/pagemap.h in this file - * so leave put_page and release_pages undeclared... */ -#define free_page_and_swap_cache(page) \ - put_page(page) -#define free_pages_and_swap_cache(pages, nr) \ - release_pages((pages), (nr), false); - -static inline void show_swap_cache_info(void) -{ -} - -#define free_swap_and_cache(swp) is_migration_entry(swp) -#define swapcache_prepare(swp) is_migration_entry(swp) - -static inline int add_swap_count_continuation(swp_entry_t swp, gfp_t gfp_mask) -{ - return 0; -} - -static inline void swap_shmem_alloc(swp_entry_t swp) -{ -} - -static inline int swap_duplicate(swp_entry_t swp) -{ - return 0; -} - -static inline void swap_free(swp_entry_t swp) -{ -} - -static inline void swapcache_free(swp_entry_t swp) -{ -} - -static inline struct page *swapin_readahead(swp_entry_t swp, gfp_t gfp_mask, - struct vm_area_struct *vma, unsigned long addr) -{ - return NULL; -} - -static inline int swap_writepage(struct page *p, struct writeback_control *wbc) -{ - return 0; -} - -static inline struct page *lookup_swap_cache(swp_entry_t swp) -{ - return NULL; -} - -static inline int add_to_swap(struct page *page, struct list_head *list) -{ - return 0; -} - -static inline int add_to_swap_cache(struct page *page, swp_entry_t entry, - gfp_t gfp_mask) -{ - return -1; -} - -static inline void __delete_from_swap_cache(struct page *page) -{ -} - -static inline void delete_from_swap_cache(struct page *page) -{ -} - -static inline int page_swapcount(struct page *page) -{ - return 0; -} - -static inline int swp_swapcount(swp_entry_t entry) -{ - return 0; -} - -#define reuse_swap_page(page, total_mapcount) \ - (page_trans_huge_mapcount(page, total_mapcount) == 1) - -static inline int try_to_free_swap(struct page *page) -{ - return 0; -} - -static inline swp_entry_t get_swap_page(void) -{ - swp_entry_t entry; - entry.val = 0; - return entry; -} - -#endif /* CONFIG_SWAP */ - -#ifdef CONFIG_MEMCG -static inline int mem_cgroup_swappiness(struct mem_cgroup *memcg) -{ - /* Cgroup2 doesn't have per-cgroup swappiness */ - if (cgroup_subsys_on_dfl(memory_cgrp_subsys)) - return vm_swappiness; - - /* root ? */ - if (mem_cgroup_disabled() || !memcg->css.parent) - return vm_swappiness; - - return memcg->swappiness; -} - -#else -static inline int mem_cgroup_swappiness(struct mem_cgroup *mem) -{ - return vm_swappiness; -} -#endif - -#ifdef CONFIG_MEMCG_SWAP -extern void mem_cgroup_swapout(struct page *page, swp_entry_t entry); -extern int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry); -extern void mem_cgroup_uncharge_swap(swp_entry_t entry); -extern long mem_cgroup_get_nr_swap_pages(struct mem_cgroup *memcg); -extern bool mem_cgroup_swap_full(struct page *page); -#else -static inline void mem_cgroup_swapout(struct page *page, swp_entry_t entry) -{ -} - -static inline int mem_cgroup_try_charge_swap(struct page *page, - swp_entry_t entry) -{ - return 0; -} - -static inline void mem_cgroup_uncharge_swap(swp_entry_t entry) -{ -} - -static inline long mem_cgroup_get_nr_swap_pages(struct mem_cgroup *memcg) -{ - return get_nr_swap_pages(); -} - -static inline bool mem_cgroup_swap_full(struct page *page) -{ - return vm_swap_full(); -} -#endif - -#endif /* __KERNEL__*/ -#endif /* _LINUX_SWAP_H */ diff --git a/src/linux/include/linux/swapops.h b/src/linux/include/linux/swapops.h deleted file mode 100644 index 5c3a5f3..0000000 --- a/src/linux/include/linux/swapops.h +++ /dev/null @@ -1,242 +0,0 @@ -#ifndef _LINUX_SWAPOPS_H -#define _LINUX_SWAPOPS_H - -#include -#include - -/* - * swapcache pages are stored in the swapper_space radix tree. We want to - * get good packing density in that tree, so the index should be dense in - * the low-order bits. - * - * We arrange the `type' and `offset' fields so that `type' is at the seven - * high-order bits of the swp_entry_t and `offset' is right-aligned in the - * remaining bits. Although `type' itself needs only five bits, we allow for - * shmem/tmpfs to shift it all up a further two bits: see swp_to_radix_entry(). - * - * swp_entry_t's are *never* stored anywhere in their arch-dependent format. - */ -#define SWP_TYPE_SHIFT(e) ((sizeof(e.val) * 8) - \ - (MAX_SWAPFILES_SHIFT + RADIX_TREE_EXCEPTIONAL_SHIFT)) -#define SWP_OFFSET_MASK(e) ((1UL << SWP_TYPE_SHIFT(e)) - 1) - -/* - * Store a type+offset into a swp_entry_t in an arch-independent format - */ -static inline swp_entry_t swp_entry(unsigned long type, pgoff_t offset) -{ - swp_entry_t ret; - - ret.val = (type << SWP_TYPE_SHIFT(ret)) | - (offset & SWP_OFFSET_MASK(ret)); - return ret; -} - -/* - * Extract the `type' field from a swp_entry_t. The swp_entry_t is in - * arch-independent format - */ -static inline unsigned swp_type(swp_entry_t entry) -{ - return (entry.val >> SWP_TYPE_SHIFT(entry)); -} - -/* - * Extract the `offset' field from a swp_entry_t. The swp_entry_t is in - * arch-independent format - */ -static inline pgoff_t swp_offset(swp_entry_t entry) -{ - return entry.val & SWP_OFFSET_MASK(entry); -} - -#ifdef CONFIG_MMU -/* check whether a pte points to a swap entry */ -static inline int is_swap_pte(pte_t pte) -{ - return !pte_none(pte) && !pte_present(pte); -} -#endif - -/* - * Convert the arch-dependent pte representation of a swp_entry_t into an - * arch-independent swp_entry_t. - */ -static inline swp_entry_t pte_to_swp_entry(pte_t pte) -{ - swp_entry_t arch_entry; - - if (pte_swp_soft_dirty(pte)) - pte = pte_swp_clear_soft_dirty(pte); - arch_entry = __pte_to_swp_entry(pte); - return swp_entry(__swp_type(arch_entry), __swp_offset(arch_entry)); -} - -/* - * Convert the arch-independent representation of a swp_entry_t into the - * arch-dependent pte representation. - */ -static inline pte_t swp_entry_to_pte(swp_entry_t entry) -{ - swp_entry_t arch_entry; - - arch_entry = __swp_entry(swp_type(entry), swp_offset(entry)); - return __swp_entry_to_pte(arch_entry); -} - -static inline swp_entry_t radix_to_swp_entry(void *arg) -{ - swp_entry_t entry; - - entry.val = (unsigned long)arg >> RADIX_TREE_EXCEPTIONAL_SHIFT; - return entry; -} - -static inline void *swp_to_radix_entry(swp_entry_t entry) -{ - unsigned long value; - - value = entry.val << RADIX_TREE_EXCEPTIONAL_SHIFT; - return (void *)(value | RADIX_TREE_EXCEPTIONAL_ENTRY); -} - -#ifdef CONFIG_MIGRATION -static inline swp_entry_t make_migration_entry(struct page *page, int write) -{ - BUG_ON(!PageLocked(page)); - return swp_entry(write ? SWP_MIGRATION_WRITE : SWP_MIGRATION_READ, - page_to_pfn(page)); -} - -static inline int is_migration_entry(swp_entry_t entry) -{ - return unlikely(swp_type(entry) == SWP_MIGRATION_READ || - swp_type(entry) == SWP_MIGRATION_WRITE); -} - -static inline int is_write_migration_entry(swp_entry_t entry) -{ - return unlikely(swp_type(entry) == SWP_MIGRATION_WRITE); -} - -static inline struct page *migration_entry_to_page(swp_entry_t entry) -{ - struct page *p = pfn_to_page(swp_offset(entry)); - /* - * Any use of migration entries may only occur while the - * corresponding page is locked - */ - BUG_ON(!PageLocked(p)); - return p; -} - -static inline void make_migration_entry_read(swp_entry_t *entry) -{ - *entry = swp_entry(SWP_MIGRATION_READ, swp_offset(*entry)); -} - -extern void __migration_entry_wait(struct mm_struct *mm, pte_t *ptep, - spinlock_t *ptl); -extern void migration_entry_wait(struct mm_struct *mm, pmd_t *pmd, - unsigned long address); -extern void migration_entry_wait_huge(struct vm_area_struct *vma, - struct mm_struct *mm, pte_t *pte); -#else - -#define make_migration_entry(page, write) swp_entry(0, 0) -static inline int is_migration_entry(swp_entry_t swp) -{ - return 0; -} -#define migration_entry_to_page(swp) NULL -static inline void make_migration_entry_read(swp_entry_t *entryp) { } -static inline void __migration_entry_wait(struct mm_struct *mm, pte_t *ptep, - spinlock_t *ptl) { } -static inline void migration_entry_wait(struct mm_struct *mm, pmd_t *pmd, - unsigned long address) { } -static inline void migration_entry_wait_huge(struct vm_area_struct *vma, - struct mm_struct *mm, pte_t *pte) { } -static inline int is_write_migration_entry(swp_entry_t entry) -{ - return 0; -} - -#endif - -#ifdef CONFIG_MEMORY_FAILURE - -extern atomic_long_t num_poisoned_pages __read_mostly; - -/* - * Support for hardware poisoned pages - */ -static inline swp_entry_t make_hwpoison_entry(struct page *page) -{ - BUG_ON(!PageLocked(page)); - return swp_entry(SWP_HWPOISON, page_to_pfn(page)); -} - -static inline int is_hwpoison_entry(swp_entry_t entry) -{ - return swp_type(entry) == SWP_HWPOISON; -} - -static inline bool test_set_page_hwpoison(struct page *page) -{ - return TestSetPageHWPoison(page); -} - -static inline void num_poisoned_pages_inc(void) -{ - atomic_long_inc(&num_poisoned_pages); -} - -static inline void num_poisoned_pages_dec(void) -{ - atomic_long_dec(&num_poisoned_pages); -} - -static inline void num_poisoned_pages_add(long num) -{ - atomic_long_add(num, &num_poisoned_pages); -} - -static inline void num_poisoned_pages_sub(long num) -{ - atomic_long_sub(num, &num_poisoned_pages); -} -#else - -static inline swp_entry_t make_hwpoison_entry(struct page *page) -{ - return swp_entry(0, 0); -} - -static inline int is_hwpoison_entry(swp_entry_t swp) -{ - return 0; -} - -static inline bool test_set_page_hwpoison(struct page *page) -{ - return false; -} - -static inline void num_poisoned_pages_inc(void) -{ -} -#endif - -#if defined(CONFIG_MEMORY_FAILURE) || defined(CONFIG_MIGRATION) -static inline int non_swap_entry(swp_entry_t entry) -{ - return swp_type(entry) >= MAX_SWAPFILES; -} -#else -static inline int non_swap_entry(swp_entry_t entry) -{ - return 0; -} -#endif - -#endif /* _LINUX_SWAPOPS_H */ diff --git a/src/linux/include/linux/syscalls.h b/src/linux/include/linux/syscalls.h deleted file mode 100644 index 39ebdfe..0000000 --- a/src/linux/include/linux/syscalls.h +++ /dev/null @@ -1,912 +0,0 @@ -/* - * syscalls.h - Linux syscall interfaces (non-arch-specific) - * - * Copyright (c) 2004 Randy Dunlap - * Copyright (c) 2004 Open Source Development Labs - * - * This file is released under the GPLv2. - * See the file COPYING for more details. - */ - -#ifndef _LINUX_SYSCALLS_H -#define _LINUX_SYSCALLS_H - -struct epoll_event; -struct iattr; -struct inode; -struct iocb; -struct io_event; -struct iovec; -struct itimerspec; -struct itimerval; -struct kexec_segment; -struct linux_dirent; -struct linux_dirent64; -struct list_head; -struct mmap_arg_struct; -struct msgbuf; -struct user_msghdr; -struct mmsghdr; -struct msqid_ds; -struct new_utsname; -struct nfsctl_arg; -struct __old_kernel_stat; -struct oldold_utsname; -struct old_utsname; -struct pollfd; -struct rlimit; -struct rlimit64; -struct rusage; -struct sched_param; -struct sched_attr; -struct sel_arg_struct; -struct semaphore; -struct sembuf; -struct shmid_ds; -struct sockaddr; -struct stat; -struct stat64; -struct statfs; -struct statfs64; -struct __sysctl_args; -struct sysinfo; -struct timespec; -struct timeval; -struct timex; -struct timezone; -struct tms; -struct utimbuf; -struct mq_attr; -struct compat_stat; -struct compat_timeval; -struct robust_list_head; -struct getcpu_cache; -struct old_linux_dirent; -struct perf_event_attr; -struct file_handle; -struct sigaltstack; -union bpf_attr; - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * __MAP - apply a macro to syscall arguments - * __MAP(n, m, t1, a1, t2, a2, ..., tn, an) will expand to - * m(t1, a1), m(t2, a2), ..., m(tn, an) - * The first argument must be equal to the amount of type/name - * pairs given. Note that this list of pairs (i.e. the arguments - * of __MAP starting at the third one) is in the same format as - * for SYSCALL_DEFINE/COMPAT_SYSCALL_DEFINE - */ -#define __MAP0(m,...) -#define __MAP1(m,t,a) m(t,a) -#define __MAP2(m,t,a,...) m(t,a), __MAP1(m,__VA_ARGS__) -#define __MAP3(m,t,a,...) m(t,a), __MAP2(m,__VA_ARGS__) -#define __MAP4(m,t,a,...) m(t,a), __MAP3(m,__VA_ARGS__) -#define __MAP5(m,t,a,...) m(t,a), __MAP4(m,__VA_ARGS__) -#define __MAP6(m,t,a,...) m(t,a), __MAP5(m,__VA_ARGS__) -#define __MAP(n,...) __MAP##n(__VA_ARGS__) - -#define __SC_DECL(t, a) t a -#define __TYPE_IS_L(t) (__same_type((t)0, 0L)) -#define __TYPE_IS_UL(t) (__same_type((t)0, 0UL)) -#define __TYPE_IS_LL(t) (__same_type((t)0, 0LL) || __same_type((t)0, 0ULL)) -#define __SC_LONG(t, a) __typeof(__builtin_choose_expr(__TYPE_IS_LL(t), 0LL, 0L)) a -#define __SC_CAST(t, a) (t) a -#define __SC_ARGS(t, a) a -#define __SC_TEST(t, a) (void)BUILD_BUG_ON_ZERO(!__TYPE_IS_LL(t) && sizeof(t) > sizeof(long)) - -#ifdef CONFIG_FTRACE_SYSCALLS -#define __SC_STR_ADECL(t, a) #a -#define __SC_STR_TDECL(t, a) #t - -extern struct trace_event_class event_class_syscall_enter; -extern struct trace_event_class event_class_syscall_exit; -extern struct trace_event_functions enter_syscall_print_funcs; -extern struct trace_event_functions exit_syscall_print_funcs; - -#define SYSCALL_TRACE_ENTER_EVENT(sname) \ - static struct syscall_metadata __syscall_meta_##sname; \ - static struct trace_event_call __used \ - event_enter_##sname = { \ - .class = &event_class_syscall_enter, \ - { \ - .name = "sys_enter"#sname, \ - }, \ - .event.funcs = &enter_syscall_print_funcs, \ - .data = (void *)&__syscall_meta_##sname,\ - .flags = TRACE_EVENT_FL_CAP_ANY, \ - }; \ - static struct trace_event_call __used \ - __attribute__((section("_ftrace_events"))) \ - *__event_enter_##sname = &event_enter_##sname; - -#define SYSCALL_TRACE_EXIT_EVENT(sname) \ - static struct syscall_metadata __syscall_meta_##sname; \ - static struct trace_event_call __used \ - event_exit_##sname = { \ - .class = &event_class_syscall_exit, \ - { \ - .name = "sys_exit"#sname, \ - }, \ - .event.funcs = &exit_syscall_print_funcs, \ - .data = (void *)&__syscall_meta_##sname,\ - .flags = TRACE_EVENT_FL_CAP_ANY, \ - }; \ - static struct trace_event_call __used \ - __attribute__((section("_ftrace_events"))) \ - *__event_exit_##sname = &event_exit_##sname; - -#define SYSCALL_METADATA(sname, nb, ...) \ - static const char *types_##sname[] = { \ - __MAP(nb,__SC_STR_TDECL,__VA_ARGS__) \ - }; \ - static const char *args_##sname[] = { \ - __MAP(nb,__SC_STR_ADECL,__VA_ARGS__) \ - }; \ - SYSCALL_TRACE_ENTER_EVENT(sname); \ - SYSCALL_TRACE_EXIT_EVENT(sname); \ - static struct syscall_metadata __used \ - __syscall_meta_##sname = { \ - .name = "sys"#sname, \ - .syscall_nr = -1, /* Filled in at boot */ \ - .nb_args = nb, \ - .types = nb ? types_##sname : NULL, \ - .args = nb ? args_##sname : NULL, \ - .enter_event = &event_enter_##sname, \ - .exit_event = &event_exit_##sname, \ - .enter_fields = LIST_HEAD_INIT(__syscall_meta_##sname.enter_fields), \ - }; \ - static struct syscall_metadata __used \ - __attribute__((section("__syscalls_metadata"))) \ - *__p_syscall_meta_##sname = &__syscall_meta_##sname; -#else -#define SYSCALL_METADATA(sname, nb, ...) -#endif - -#ifndef __SYSCALL_DEFINE_ARCH -#define __SYSCALL_DEFINE_ARCH(x, sname, ...) -#endif - -#define SYSCALL_DEFINE0(sname) \ - SYSCALL_METADATA(_##sname, 0); \ - __SYSCALL_DEFINE_ARCH(0, _##sname); \ - asmlinkage long sys_##sname(void) - -#define SYSCALL_DEFINE1(name, ...) SYSCALL_DEFINEx(1, _##name, __VA_ARGS__) -#define SYSCALL_DEFINE2(name, ...) SYSCALL_DEFINEx(2, _##name, __VA_ARGS__) -#define SYSCALL_DEFINE3(name, ...) SYSCALL_DEFINEx(3, _##name, __VA_ARGS__) -#define SYSCALL_DEFINE4(name, ...) SYSCALL_DEFINEx(4, _##name, __VA_ARGS__) -#define SYSCALL_DEFINE5(name, ...) SYSCALL_DEFINEx(5, _##name, __VA_ARGS__) -#define SYSCALL_DEFINE6(name, ...) SYSCALL_DEFINEx(6, _##name, __VA_ARGS__) - -#define SYSCALL_DEFINEx(x, sname, ...) \ - SYSCALL_METADATA(sname, x, __VA_ARGS__) \ - __SYSCALL_DEFINE_ARCH(x, sname, __VA_ARGS__) \ - __SYSCALL_DEFINEx(x, sname, __VA_ARGS__) - -#define __PROTECT(...) asmlinkage_protect(__VA_ARGS__) -#define __SYSCALL_DEFINEx(x, name, ...) \ - asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) \ - __attribute__((alias(__stringify(SyS##name)))); \ - static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \ - asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ - asmlinkage long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ - { \ - long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \ - __MAP(x,__SC_TEST,__VA_ARGS__); \ - __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ - return ret; \ - } \ - static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)) - -asmlinkage long sys32_quotactl(unsigned int cmd, const char __user *special, - qid_t id, void __user *addr); -asmlinkage long sys_time(time_t __user *tloc); -asmlinkage long sys_stime(time_t __user *tptr); -asmlinkage long sys_gettimeofday(struct timeval __user *tv, - struct timezone __user *tz); -asmlinkage long sys_settimeofday(struct timeval __user *tv, - struct timezone __user *tz); -asmlinkage long sys_adjtimex(struct timex __user *txc_p); - -asmlinkage long sys_times(struct tms __user *tbuf); - -asmlinkage long sys_gettid(void); -asmlinkage long sys_nanosleep(struct timespec __user *rqtp, struct timespec __user *rmtp); -asmlinkage long sys_alarm(unsigned int seconds); -asmlinkage long sys_getpid(void); -asmlinkage long sys_getppid(void); -asmlinkage long sys_getuid(void); -asmlinkage long sys_geteuid(void); -asmlinkage long sys_getgid(void); -asmlinkage long sys_getegid(void); -asmlinkage long sys_getresuid(uid_t __user *ruid, uid_t __user *euid, uid_t __user *suid); -asmlinkage long sys_getresgid(gid_t __user *rgid, gid_t __user *egid, gid_t __user *sgid); -asmlinkage long sys_getpgid(pid_t pid); -asmlinkage long sys_getpgrp(void); -asmlinkage long sys_getsid(pid_t pid); -asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist); - -asmlinkage long sys_setregid(gid_t rgid, gid_t egid); -asmlinkage long sys_setgid(gid_t gid); -asmlinkage long sys_setreuid(uid_t ruid, uid_t euid); -asmlinkage long sys_setuid(uid_t uid); -asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid); -asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid); -asmlinkage long sys_setfsuid(uid_t uid); -asmlinkage long sys_setfsgid(gid_t gid); -asmlinkage long sys_setpgid(pid_t pid, pid_t pgid); -asmlinkage long sys_setsid(void); -asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist); - -asmlinkage long sys_acct(const char __user *name); -asmlinkage long sys_capget(cap_user_header_t header, - cap_user_data_t dataptr); -asmlinkage long sys_capset(cap_user_header_t header, - const cap_user_data_t data); -asmlinkage long sys_personality(unsigned int personality); - -asmlinkage long sys_sigpending(old_sigset_t __user *set); -asmlinkage long sys_sigprocmask(int how, old_sigset_t __user *set, - old_sigset_t __user *oset); -asmlinkage long sys_sigaltstack(const struct sigaltstack __user *uss, - struct sigaltstack __user *uoss); - -asmlinkage long sys_getitimer(int which, struct itimerval __user *value); -asmlinkage long sys_setitimer(int which, - struct itimerval __user *value, - struct itimerval __user *ovalue); -asmlinkage long sys_timer_create(clockid_t which_clock, - struct sigevent __user *timer_event_spec, - timer_t __user * created_timer_id); -asmlinkage long sys_timer_gettime(timer_t timer_id, - struct itimerspec __user *setting); -asmlinkage long sys_timer_getoverrun(timer_t timer_id); -asmlinkage long sys_timer_settime(timer_t timer_id, int flags, - const struct itimerspec __user *new_setting, - struct itimerspec __user *old_setting); -asmlinkage long sys_timer_delete(timer_t timer_id); -asmlinkage long sys_clock_settime(clockid_t which_clock, - const struct timespec __user *tp); -asmlinkage long sys_clock_gettime(clockid_t which_clock, - struct timespec __user *tp); -asmlinkage long sys_clock_adjtime(clockid_t which_clock, - struct timex __user *tx); -asmlinkage long sys_clock_getres(clockid_t which_clock, - struct timespec __user *tp); -asmlinkage long sys_clock_nanosleep(clockid_t which_clock, int flags, - const struct timespec __user *rqtp, - struct timespec __user *rmtp); - -asmlinkage long sys_nice(int increment); -asmlinkage long sys_sched_setscheduler(pid_t pid, int policy, - struct sched_param __user *param); -asmlinkage long sys_sched_setparam(pid_t pid, - struct sched_param __user *param); -asmlinkage long sys_sched_setattr(pid_t pid, - struct sched_attr __user *attr, - unsigned int flags); -asmlinkage long sys_sched_getscheduler(pid_t pid); -asmlinkage long sys_sched_getparam(pid_t pid, - struct sched_param __user *param); -asmlinkage long sys_sched_getattr(pid_t pid, - struct sched_attr __user *attr, - unsigned int size, - unsigned int flags); -asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len, - unsigned long __user *user_mask_ptr); -asmlinkage long sys_sched_getaffinity(pid_t pid, unsigned int len, - unsigned long __user *user_mask_ptr); -asmlinkage long sys_sched_yield(void); -asmlinkage long sys_sched_get_priority_max(int policy); -asmlinkage long sys_sched_get_priority_min(int policy); -asmlinkage long sys_sched_rr_get_interval(pid_t pid, - struct timespec __user *interval); -asmlinkage long sys_setpriority(int which, int who, int niceval); -asmlinkage long sys_getpriority(int which, int who); - -asmlinkage long sys_shutdown(int, int); -asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, - void __user *arg); -asmlinkage long sys_restart_syscall(void); -asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, - struct kexec_segment __user *segments, - unsigned long flags); -asmlinkage long sys_kexec_file_load(int kernel_fd, int initrd_fd, - unsigned long cmdline_len, - const char __user *cmdline_ptr, - unsigned long flags); - -asmlinkage long sys_exit(int error_code); -asmlinkage long sys_exit_group(int error_code); -asmlinkage long sys_wait4(pid_t pid, int __user *stat_addr, - int options, struct rusage __user *ru); -asmlinkage long sys_waitid(int which, pid_t pid, - struct siginfo __user *infop, - int options, struct rusage __user *ru); -asmlinkage long sys_waitpid(pid_t pid, int __user *stat_addr, int options); -asmlinkage long sys_set_tid_address(int __user *tidptr); -asmlinkage long sys_futex(u32 __user *uaddr, int op, u32 val, - struct timespec __user *utime, u32 __user *uaddr2, - u32 val3); - -asmlinkage long sys_init_module(void __user *umod, unsigned long len, - const char __user *uargs); -asmlinkage long sys_delete_module(const char __user *name_user, - unsigned int flags); - -#ifdef CONFIG_OLD_SIGSUSPEND -asmlinkage long sys_sigsuspend(old_sigset_t mask); -#endif - -#ifdef CONFIG_OLD_SIGSUSPEND3 -asmlinkage long sys_sigsuspend(int unused1, int unused2, old_sigset_t mask); -#endif - -asmlinkage long sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize); - -#ifdef CONFIG_OLD_SIGACTION -asmlinkage long sys_sigaction(int, const struct old_sigaction __user *, - struct old_sigaction __user *); -#endif - -#ifndef CONFIG_ODD_RT_SIGACTION -asmlinkage long sys_rt_sigaction(int, - const struct sigaction __user *, - struct sigaction __user *, - size_t); -#endif -asmlinkage long sys_rt_sigprocmask(int how, sigset_t __user *set, - sigset_t __user *oset, size_t sigsetsize); -asmlinkage long sys_rt_sigpending(sigset_t __user *set, size_t sigsetsize); -asmlinkage long sys_rt_sigtimedwait(const sigset_t __user *uthese, - siginfo_t __user *uinfo, - const struct timespec __user *uts, - size_t sigsetsize); -asmlinkage long sys_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, - siginfo_t __user *uinfo); -asmlinkage long sys_kill(pid_t pid, int sig); -asmlinkage long sys_tgkill(pid_t tgid, pid_t pid, int sig); -asmlinkage long sys_tkill(pid_t pid, int sig); -asmlinkage long sys_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t __user *uinfo); -asmlinkage long sys_sgetmask(void); -asmlinkage long sys_ssetmask(int newmask); -asmlinkage long sys_signal(int sig, __sighandler_t handler); -asmlinkage long sys_pause(void); - -asmlinkage long sys_sync(void); -asmlinkage long sys_fsync(unsigned int fd); -asmlinkage long sys_fdatasync(unsigned int fd); -asmlinkage long sys_bdflush(int func, long data); -asmlinkage long sys_mount(char __user *dev_name, char __user *dir_name, - char __user *type, unsigned long flags, - void __user *data); -asmlinkage long sys_umount(char __user *name, int flags); -asmlinkage long sys_oldumount(char __user *name); -asmlinkage long sys_truncate(const char __user *path, long length); -asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length); -asmlinkage long sys_stat(const char __user *filename, - struct __old_kernel_stat __user *statbuf); -asmlinkage long sys_statfs(const char __user * path, - struct statfs __user *buf); -asmlinkage long sys_statfs64(const char __user *path, size_t sz, - struct statfs64 __user *buf); -asmlinkage long sys_fstatfs(unsigned int fd, struct statfs __user *buf); -asmlinkage long sys_fstatfs64(unsigned int fd, size_t sz, - struct statfs64 __user *buf); -asmlinkage long sys_lstat(const char __user *filename, - struct __old_kernel_stat __user *statbuf); -asmlinkage long sys_fstat(unsigned int fd, - struct __old_kernel_stat __user *statbuf); -asmlinkage long sys_newstat(const char __user *filename, - struct stat __user *statbuf); -asmlinkage long sys_newlstat(const char __user *filename, - struct stat __user *statbuf); -asmlinkage long sys_newfstat(unsigned int fd, struct stat __user *statbuf); -asmlinkage long sys_ustat(unsigned dev, struct ustat __user *ubuf); -#if defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_COMPAT_STAT64) -asmlinkage long sys_stat64(const char __user *filename, - struct stat64 __user *statbuf); -asmlinkage long sys_fstat64(unsigned long fd, struct stat64 __user *statbuf); -asmlinkage long sys_lstat64(const char __user *filename, - struct stat64 __user *statbuf); -asmlinkage long sys_fstatat64(int dfd, const char __user *filename, - struct stat64 __user *statbuf, int flag); -#endif -#if BITS_PER_LONG == 32 -asmlinkage long sys_truncate64(const char __user *path, loff_t length); -asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length); -#endif - -asmlinkage long sys_setxattr(const char __user *path, const char __user *name, - const void __user *value, size_t size, int flags); -asmlinkage long sys_lsetxattr(const char __user *path, const char __user *name, - const void __user *value, size_t size, int flags); -asmlinkage long sys_fsetxattr(int fd, const char __user *name, - const void __user *value, size_t size, int flags); -asmlinkage long sys_getxattr(const char __user *path, const char __user *name, - void __user *value, size_t size); -asmlinkage long sys_lgetxattr(const char __user *path, const char __user *name, - void __user *value, size_t size); -asmlinkage long sys_fgetxattr(int fd, const char __user *name, - void __user *value, size_t size); -asmlinkage long sys_listxattr(const char __user *path, char __user *list, - size_t size); -asmlinkage long sys_llistxattr(const char __user *path, char __user *list, - size_t size); -asmlinkage long sys_flistxattr(int fd, char __user *list, size_t size); -asmlinkage long sys_removexattr(const char __user *path, - const char __user *name); -asmlinkage long sys_lremovexattr(const char __user *path, - const char __user *name); -asmlinkage long sys_fremovexattr(int fd, const char __user *name); - -asmlinkage long sys_brk(unsigned long brk); -asmlinkage long sys_mprotect(unsigned long start, size_t len, - unsigned long prot); -asmlinkage long sys_mremap(unsigned long addr, - unsigned long old_len, unsigned long new_len, - unsigned long flags, unsigned long new_addr); -asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size, - unsigned long prot, unsigned long pgoff, - unsigned long flags); -asmlinkage long sys_msync(unsigned long start, size_t len, int flags); -asmlinkage long sys_fadvise64(int fd, loff_t offset, size_t len, int advice); -asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice); -asmlinkage long sys_munmap(unsigned long addr, size_t len); -asmlinkage long sys_mlock(unsigned long start, size_t len); -asmlinkage long sys_munlock(unsigned long start, size_t len); -asmlinkage long sys_mlockall(int flags); -asmlinkage long sys_munlockall(void); -asmlinkage long sys_madvise(unsigned long start, size_t len, int behavior); -asmlinkage long sys_mincore(unsigned long start, size_t len, - unsigned char __user * vec); - -asmlinkage long sys_pivot_root(const char __user *new_root, - const char __user *put_old); -asmlinkage long sys_chroot(const char __user *filename); -asmlinkage long sys_mknod(const char __user *filename, umode_t mode, - unsigned dev); -asmlinkage long sys_link(const char __user *oldname, - const char __user *newname); -asmlinkage long sys_symlink(const char __user *old, const char __user *new); -asmlinkage long sys_unlink(const char __user *pathname); -asmlinkage long sys_rename(const char __user *oldname, - const char __user *newname); -asmlinkage long sys_chmod(const char __user *filename, umode_t mode); -asmlinkage long sys_fchmod(unsigned int fd, umode_t mode); - -asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg); -#if BITS_PER_LONG == 32 -asmlinkage long sys_fcntl64(unsigned int fd, - unsigned int cmd, unsigned long arg); -#endif -asmlinkage long sys_pipe(int __user *fildes); -asmlinkage long sys_pipe2(int __user *fildes, int flags); -asmlinkage long sys_dup(unsigned int fildes); -asmlinkage long sys_dup2(unsigned int oldfd, unsigned int newfd); -asmlinkage long sys_dup3(unsigned int oldfd, unsigned int newfd, int flags); -asmlinkage long sys_ioperm(unsigned long from, unsigned long num, int on); -asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, - unsigned long arg); -asmlinkage long sys_flock(unsigned int fd, unsigned int cmd); -asmlinkage long sys_io_setup(unsigned nr_reqs, aio_context_t __user *ctx); -asmlinkage long sys_io_destroy(aio_context_t ctx); -asmlinkage long sys_io_getevents(aio_context_t ctx_id, - long min_nr, - long nr, - struct io_event __user *events, - struct timespec __user *timeout); -asmlinkage long sys_io_submit(aio_context_t, long, - struct iocb __user * __user *); -asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb __user *iocb, - struct io_event __user *result); -asmlinkage long sys_sendfile(int out_fd, int in_fd, - off_t __user *offset, size_t count); -asmlinkage long sys_sendfile64(int out_fd, int in_fd, - loff_t __user *offset, size_t count); -asmlinkage long sys_readlink(const char __user *path, - char __user *buf, int bufsiz); -asmlinkage long sys_creat(const char __user *pathname, umode_t mode); -asmlinkage long sys_open(const char __user *filename, - int flags, umode_t mode); -asmlinkage long sys_close(unsigned int fd); -asmlinkage long sys_access(const char __user *filename, int mode); -asmlinkage long sys_vhangup(void); -asmlinkage long sys_chown(const char __user *filename, - uid_t user, gid_t group); -asmlinkage long sys_lchown(const char __user *filename, - uid_t user, gid_t group); -asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group); -#ifdef CONFIG_HAVE_UID16 -asmlinkage long sys_chown16(const char __user *filename, - old_uid_t user, old_gid_t group); -asmlinkage long sys_lchown16(const char __user *filename, - old_uid_t user, old_gid_t group); -asmlinkage long sys_fchown16(unsigned int fd, old_uid_t user, old_gid_t group); -asmlinkage long sys_setregid16(old_gid_t rgid, old_gid_t egid); -asmlinkage long sys_setgid16(old_gid_t gid); -asmlinkage long sys_setreuid16(old_uid_t ruid, old_uid_t euid); -asmlinkage long sys_setuid16(old_uid_t uid); -asmlinkage long sys_setresuid16(old_uid_t ruid, old_uid_t euid, old_uid_t suid); -asmlinkage long sys_getresuid16(old_uid_t __user *ruid, - old_uid_t __user *euid, old_uid_t __user *suid); -asmlinkage long sys_setresgid16(old_gid_t rgid, old_gid_t egid, old_gid_t sgid); -asmlinkage long sys_getresgid16(old_gid_t __user *rgid, - old_gid_t __user *egid, old_gid_t __user *sgid); -asmlinkage long sys_setfsuid16(old_uid_t uid); -asmlinkage long sys_setfsgid16(old_gid_t gid); -asmlinkage long sys_getgroups16(int gidsetsize, old_gid_t __user *grouplist); -asmlinkage long sys_setgroups16(int gidsetsize, old_gid_t __user *grouplist); -asmlinkage long sys_getuid16(void); -asmlinkage long sys_geteuid16(void); -asmlinkage long sys_getgid16(void); -asmlinkage long sys_getegid16(void); -#endif - -asmlinkage long sys_utime(char __user *filename, - struct utimbuf __user *times); -asmlinkage long sys_utimes(char __user *filename, - struct timeval __user *utimes); -asmlinkage long sys_lseek(unsigned int fd, off_t offset, - unsigned int whence); -asmlinkage long sys_llseek(unsigned int fd, unsigned long offset_high, - unsigned long offset_low, loff_t __user *result, - unsigned int whence); -asmlinkage long sys_read(unsigned int fd, char __user *buf, size_t count); -asmlinkage long sys_readahead(int fd, loff_t offset, size_t count); -asmlinkage long sys_readv(unsigned long fd, - const struct iovec __user *vec, - unsigned long vlen); -asmlinkage long sys_write(unsigned int fd, const char __user *buf, - size_t count); -asmlinkage long sys_writev(unsigned long fd, - const struct iovec __user *vec, - unsigned long vlen); -asmlinkage long sys_pread64(unsigned int fd, char __user *buf, - size_t count, loff_t pos); -asmlinkage long sys_pwrite64(unsigned int fd, const char __user *buf, - size_t count, loff_t pos); -asmlinkage long sys_preadv(unsigned long fd, const struct iovec __user *vec, - unsigned long vlen, unsigned long pos_l, unsigned long pos_h); -asmlinkage long sys_preadv2(unsigned long fd, const struct iovec __user *vec, - unsigned long vlen, unsigned long pos_l, unsigned long pos_h, - int flags); -asmlinkage long sys_pwritev(unsigned long fd, const struct iovec __user *vec, - unsigned long vlen, unsigned long pos_l, unsigned long pos_h); -asmlinkage long sys_pwritev2(unsigned long fd, const struct iovec __user *vec, - unsigned long vlen, unsigned long pos_l, unsigned long pos_h, - int flags); -asmlinkage long sys_getcwd(char __user *buf, unsigned long size); -asmlinkage long sys_mkdir(const char __user *pathname, umode_t mode); -asmlinkage long sys_chdir(const char __user *filename); -asmlinkage long sys_fchdir(unsigned int fd); -asmlinkage long sys_rmdir(const char __user *pathname); -asmlinkage long sys_lookup_dcookie(u64 cookie64, char __user *buf, size_t len); -asmlinkage long sys_quotactl(unsigned int cmd, const char __user *special, - qid_t id, void __user *addr); -asmlinkage long sys_getdents(unsigned int fd, - struct linux_dirent __user *dirent, - unsigned int count); -asmlinkage long sys_getdents64(unsigned int fd, - struct linux_dirent64 __user *dirent, - unsigned int count); - -asmlinkage long sys_setsockopt(int fd, int level, int optname, - char __user *optval, int optlen); -asmlinkage long sys_getsockopt(int fd, int level, int optname, - char __user *optval, int __user *optlen); -asmlinkage long sys_bind(int, struct sockaddr __user *, int); -asmlinkage long sys_connect(int, struct sockaddr __user *, int); -asmlinkage long sys_accept(int, struct sockaddr __user *, int __user *); -asmlinkage long sys_accept4(int, struct sockaddr __user *, int __user *, int); -asmlinkage long sys_getsockname(int, struct sockaddr __user *, int __user *); -asmlinkage long sys_getpeername(int, struct sockaddr __user *, int __user *); -asmlinkage long sys_send(int, void __user *, size_t, unsigned); -asmlinkage long sys_sendto(int, void __user *, size_t, unsigned, - struct sockaddr __user *, int); -asmlinkage long sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags); -asmlinkage long sys_sendmmsg(int fd, struct mmsghdr __user *msg, - unsigned int vlen, unsigned flags); -asmlinkage long sys_recv(int, void __user *, size_t, unsigned); -asmlinkage long sys_recvfrom(int, void __user *, size_t, unsigned, - struct sockaddr __user *, int __user *); -asmlinkage long sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned flags); -asmlinkage long sys_recvmmsg(int fd, struct mmsghdr __user *msg, - unsigned int vlen, unsigned flags, - struct timespec __user *timeout); -asmlinkage long sys_socket(int, int, int); -asmlinkage long sys_socketpair(int, int, int, int __user *); -asmlinkage long sys_socketcall(int call, unsigned long __user *args); -asmlinkage long sys_listen(int, int); -asmlinkage long sys_poll(struct pollfd __user *ufds, unsigned int nfds, - int timeout); -asmlinkage long sys_select(int n, fd_set __user *inp, fd_set __user *outp, - fd_set __user *exp, struct timeval __user *tvp); -asmlinkage long sys_old_select(struct sel_arg_struct __user *arg); -asmlinkage long sys_epoll_create(int size); -asmlinkage long sys_epoll_create1(int flags); -asmlinkage long sys_epoll_ctl(int epfd, int op, int fd, - struct epoll_event __user *event); -asmlinkage long sys_epoll_wait(int epfd, struct epoll_event __user *events, - int maxevents, int timeout); -asmlinkage long sys_epoll_pwait(int epfd, struct epoll_event __user *events, - int maxevents, int timeout, - const sigset_t __user *sigmask, - size_t sigsetsize); -asmlinkage long sys_gethostname(char __user *name, int len); -asmlinkage long sys_sethostname(char __user *name, int len); -asmlinkage long sys_setdomainname(char __user *name, int len); -asmlinkage long sys_newuname(struct new_utsname __user *name); -asmlinkage long sys_uname(struct old_utsname __user *); -asmlinkage long sys_olduname(struct oldold_utsname __user *); - -asmlinkage long sys_getrlimit(unsigned int resource, - struct rlimit __user *rlim); -#if defined(COMPAT_RLIM_OLD_INFINITY) || !(defined(CONFIG_IA64)) -asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit __user *rlim); -#endif -asmlinkage long sys_setrlimit(unsigned int resource, - struct rlimit __user *rlim); -asmlinkage long sys_prlimit64(pid_t pid, unsigned int resource, - const struct rlimit64 __user *new_rlim, - struct rlimit64 __user *old_rlim); -asmlinkage long sys_getrusage(int who, struct rusage __user *ru); -asmlinkage long sys_umask(int mask); - -asmlinkage long sys_msgget(key_t key, int msgflg); -asmlinkage long sys_msgsnd(int msqid, struct msgbuf __user *msgp, - size_t msgsz, int msgflg); -asmlinkage long sys_msgrcv(int msqid, struct msgbuf __user *msgp, - size_t msgsz, long msgtyp, int msgflg); -asmlinkage long sys_msgctl(int msqid, int cmd, struct msqid_ds __user *buf); - -asmlinkage long sys_semget(key_t key, int nsems, int semflg); -asmlinkage long sys_semop(int semid, struct sembuf __user *sops, - unsigned nsops); -asmlinkage long sys_semctl(int semid, int semnum, int cmd, unsigned long arg); -asmlinkage long sys_semtimedop(int semid, struct sembuf __user *sops, - unsigned nsops, - const struct timespec __user *timeout); -asmlinkage long sys_shmat(int shmid, char __user *shmaddr, int shmflg); -asmlinkage long sys_shmget(key_t key, size_t size, int flag); -asmlinkage long sys_shmdt(char __user *shmaddr); -asmlinkage long sys_shmctl(int shmid, int cmd, struct shmid_ds __user *buf); -asmlinkage long sys_ipc(unsigned int call, int first, unsigned long second, - unsigned long third, void __user *ptr, long fifth); - -asmlinkage long sys_mq_open(const char __user *name, int oflag, umode_t mode, struct mq_attr __user *attr); -asmlinkage long sys_mq_unlink(const char __user *name); -asmlinkage long sys_mq_timedsend(mqd_t mqdes, const char __user *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec __user *abs_timeout); -asmlinkage long sys_mq_timedreceive(mqd_t mqdes, char __user *msg_ptr, size_t msg_len, unsigned int __user *msg_prio, const struct timespec __user *abs_timeout); -asmlinkage long sys_mq_notify(mqd_t mqdes, const struct sigevent __user *notification); -asmlinkage long sys_mq_getsetattr(mqd_t mqdes, const struct mq_attr __user *mqstat, struct mq_attr __user *omqstat); - -asmlinkage long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn); -asmlinkage long sys_pciconfig_read(unsigned long bus, unsigned long dfn, - unsigned long off, unsigned long len, - void __user *buf); -asmlinkage long sys_pciconfig_write(unsigned long bus, unsigned long dfn, - unsigned long off, unsigned long len, - void __user *buf); - -asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5); -asmlinkage long sys_swapon(const char __user *specialfile, int swap_flags); -asmlinkage long sys_swapoff(const char __user *specialfile); -asmlinkage long sys_sysctl(struct __sysctl_args __user *args); -asmlinkage long sys_sysinfo(struct sysinfo __user *info); -asmlinkage long sys_sysfs(int option, - unsigned long arg1, unsigned long arg2); -asmlinkage long sys_syslog(int type, char __user *buf, int len); -asmlinkage long sys_uselib(const char __user *library); -asmlinkage long sys_ni_syscall(void); -asmlinkage long sys_ptrace(long request, long pid, unsigned long addr, - unsigned long data); - -asmlinkage long sys_add_key(const char __user *_type, - const char __user *_description, - const void __user *_payload, - size_t plen, - key_serial_t destringid); - -asmlinkage long sys_request_key(const char __user *_type, - const char __user *_description, - const char __user *_callout_info, - key_serial_t destringid); - -asmlinkage long sys_keyctl(int cmd, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5); - -asmlinkage long sys_ioprio_set(int which, int who, int ioprio); -asmlinkage long sys_ioprio_get(int which, int who); -asmlinkage long sys_set_mempolicy(int mode, const unsigned long __user *nmask, - unsigned long maxnode); -asmlinkage long sys_migrate_pages(pid_t pid, unsigned long maxnode, - const unsigned long __user *from, - const unsigned long __user *to); -asmlinkage long sys_move_pages(pid_t pid, unsigned long nr_pages, - const void __user * __user *pages, - const int __user *nodes, - int __user *status, - int flags); -asmlinkage long sys_mbind(unsigned long start, unsigned long len, - unsigned long mode, - const unsigned long __user *nmask, - unsigned long maxnode, - unsigned flags); -asmlinkage long sys_get_mempolicy(int __user *policy, - unsigned long __user *nmask, - unsigned long maxnode, - unsigned long addr, unsigned long flags); - -asmlinkage long sys_inotify_init(void); -asmlinkage long sys_inotify_init1(int flags); -asmlinkage long sys_inotify_add_watch(int fd, const char __user *path, - u32 mask); -asmlinkage long sys_inotify_rm_watch(int fd, __s32 wd); - -asmlinkage long sys_spu_run(int fd, __u32 __user *unpc, - __u32 __user *ustatus); -asmlinkage long sys_spu_create(const char __user *name, - unsigned int flags, umode_t mode, int fd); - -asmlinkage long sys_mknodat(int dfd, const char __user * filename, umode_t mode, - unsigned dev); -asmlinkage long sys_mkdirat(int dfd, const char __user * pathname, umode_t mode); -asmlinkage long sys_unlinkat(int dfd, const char __user * pathname, int flag); -asmlinkage long sys_symlinkat(const char __user * oldname, - int newdfd, const char __user * newname); -asmlinkage long sys_linkat(int olddfd, const char __user *oldname, - int newdfd, const char __user *newname, int flags); -asmlinkage long sys_renameat(int olddfd, const char __user * oldname, - int newdfd, const char __user * newname); -asmlinkage long sys_renameat2(int olddfd, const char __user *oldname, - int newdfd, const char __user *newname, - unsigned int flags); -asmlinkage long sys_futimesat(int dfd, const char __user *filename, - struct timeval __user *utimes); -asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode); -asmlinkage long sys_fchmodat(int dfd, const char __user * filename, - umode_t mode); -asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user, - gid_t group, int flag); -asmlinkage long sys_openat(int dfd, const char __user *filename, int flags, - umode_t mode); -asmlinkage long sys_newfstatat(int dfd, const char __user *filename, - struct stat __user *statbuf, int flag); -asmlinkage long sys_readlinkat(int dfd, const char __user *path, char __user *buf, - int bufsiz); -asmlinkage long sys_utimensat(int dfd, const char __user *filename, - struct timespec __user *utimes, int flags); -asmlinkage long sys_unshare(unsigned long unshare_flags); - -asmlinkage long sys_splice(int fd_in, loff_t __user *off_in, - int fd_out, loff_t __user *off_out, - size_t len, unsigned int flags); - -asmlinkage long sys_vmsplice(int fd, const struct iovec __user *iov, - unsigned long nr_segs, unsigned int flags); - -asmlinkage long sys_tee(int fdin, int fdout, size_t len, unsigned int flags); - -asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes, - unsigned int flags); -asmlinkage long sys_sync_file_range2(int fd, unsigned int flags, - loff_t offset, loff_t nbytes); -asmlinkage long sys_get_robust_list(int pid, - struct robust_list_head __user * __user *head_ptr, - size_t __user *len_ptr); -asmlinkage long sys_set_robust_list(struct robust_list_head __user *head, - size_t len); -asmlinkage long sys_getcpu(unsigned __user *cpu, unsigned __user *node, struct getcpu_cache __user *cache); -asmlinkage long sys_signalfd(int ufd, sigset_t __user *user_mask, size_t sizemask); -asmlinkage long sys_signalfd4(int ufd, sigset_t __user *user_mask, size_t sizemask, int flags); -asmlinkage long sys_timerfd_create(int clockid, int flags); -asmlinkage long sys_timerfd_settime(int ufd, int flags, - const struct itimerspec __user *utmr, - struct itimerspec __user *otmr); -asmlinkage long sys_timerfd_gettime(int ufd, struct itimerspec __user *otmr); -asmlinkage long sys_eventfd(unsigned int count); -asmlinkage long sys_eventfd2(unsigned int count, int flags); -asmlinkage long sys_memfd_create(const char __user *uname_ptr, unsigned int flags); -asmlinkage long sys_userfaultfd(int flags); -asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len); -asmlinkage long sys_old_readdir(unsigned int, struct old_linux_dirent __user *, unsigned int); -asmlinkage long sys_pselect6(int, fd_set __user *, fd_set __user *, - fd_set __user *, struct timespec __user *, - void __user *); -asmlinkage long sys_ppoll(struct pollfd __user *, unsigned int, - struct timespec __user *, const sigset_t __user *, - size_t); -asmlinkage long sys_fanotify_init(unsigned int flags, unsigned int event_f_flags); -asmlinkage long sys_fanotify_mark(int fanotify_fd, unsigned int flags, - u64 mask, int fd, - const char __user *pathname); -asmlinkage long sys_syncfs(int fd); - -asmlinkage long sys_fork(void); -asmlinkage long sys_vfork(void); -#ifdef CONFIG_CLONE_BACKWARDS -asmlinkage long sys_clone(unsigned long, unsigned long, int __user *, unsigned long, - int __user *); -#else -#ifdef CONFIG_CLONE_BACKWARDS3 -asmlinkage long sys_clone(unsigned long, unsigned long, int, int __user *, - int __user *, unsigned long); -#else -asmlinkage long sys_clone(unsigned long, unsigned long, int __user *, - int __user *, unsigned long); -#endif -#endif - -asmlinkage long sys_execve(const char __user *filename, - const char __user *const __user *argv, - const char __user *const __user *envp); - -asmlinkage long sys_perf_event_open( - struct perf_event_attr __user *attr_uptr, - pid_t pid, int cpu, int group_fd, unsigned long flags); - -asmlinkage long sys_mmap_pgoff(unsigned long addr, unsigned long len, - unsigned long prot, unsigned long flags, - unsigned long fd, unsigned long pgoff); -asmlinkage long sys_old_mmap(struct mmap_arg_struct __user *arg); -asmlinkage long sys_name_to_handle_at(int dfd, const char __user *name, - struct file_handle __user *handle, - int __user *mnt_id, int flag); -asmlinkage long sys_open_by_handle_at(int mountdirfd, - struct file_handle __user *handle, - int flags); -asmlinkage long sys_setns(int fd, int nstype); -asmlinkage long sys_process_vm_readv(pid_t pid, - const struct iovec __user *lvec, - unsigned long liovcnt, - const struct iovec __user *rvec, - unsigned long riovcnt, - unsigned long flags); -asmlinkage long sys_process_vm_writev(pid_t pid, - const struct iovec __user *lvec, - unsigned long liovcnt, - const struct iovec __user *rvec, - unsigned long riovcnt, - unsigned long flags); - -asmlinkage long sys_kcmp(pid_t pid1, pid_t pid2, int type, - unsigned long idx1, unsigned long idx2); -asmlinkage long sys_finit_module(int fd, const char __user *uargs, int flags); -asmlinkage long sys_seccomp(unsigned int op, unsigned int flags, - const char __user *uargs); -asmlinkage long sys_getrandom(char __user *buf, size_t count, - unsigned int flags); -asmlinkage long sys_bpf(int cmd, union bpf_attr *attr, unsigned int size); - -asmlinkage long sys_execveat(int dfd, const char __user *filename, - const char __user *const __user *argv, - const char __user *const __user *envp, int flags); - -asmlinkage long sys_membarrier(int cmd, int flags); -asmlinkage long sys_copy_file_range(int fd_in, loff_t __user *off_in, - int fd_out, loff_t __user *off_out, - size_t len, unsigned int flags); - -asmlinkage long sys_mlock2(unsigned long start, size_t len, int flags); - -asmlinkage long sys_pkey_mprotect(unsigned long start, size_t len, - unsigned long prot, int pkey); -asmlinkage long sys_pkey_alloc(unsigned long flags, unsigned long init_val); -asmlinkage long sys_pkey_free(int pkey); - -#endif diff --git a/src/linux/include/linux/syscore_ops.h b/src/linux/include/linux/syscore_ops.h deleted file mode 100644 index 27b3b0b..0000000 --- a/src/linux/include/linux/syscore_ops.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * syscore_ops.h - System core operations. - * - * Copyright (C) 2011 Rafael J. Wysocki , Novell Inc. - * - * This file is released under the GPLv2. - */ - -#ifndef _LINUX_SYSCORE_OPS_H -#define _LINUX_SYSCORE_OPS_H - -#include - -struct syscore_ops { - struct list_head node; - int (*suspend)(void); - void (*resume)(void); - void (*shutdown)(void); -}; - -extern void register_syscore_ops(struct syscore_ops *ops); -extern void unregister_syscore_ops(struct syscore_ops *ops); -#ifdef CONFIG_PM_SLEEP -extern int syscore_suspend(void); -extern void syscore_resume(void); -#endif -extern void syscore_shutdown(void); - -#endif diff --git a/src/linux/include/linux/sysctl.h b/src/linux/include/linux/sysctl.h deleted file mode 100644 index adf4e51..0000000 --- a/src/linux/include/linux/sysctl.h +++ /dev/null @@ -1,227 +0,0 @@ -/* - * sysctl.h: General linux system control interface - * - * Begun 24 March 1995, Stephen Tweedie - * - **************************************************************** - **************************************************************** - ** - ** WARNING: - ** The values in this file are exported to user space via - ** the sysctl() binary interface. Do *NOT* change the - ** numbering of any existing values here, and do not change - ** any numbers within any one set of values. If you have to - ** redefine an existing interface, use a new number for it. - ** The kernel will then return -ENOTDIR to any application using - ** the old binary interface. - ** - **************************************************************** - **************************************************************** - */ -#ifndef _LINUX_SYSCTL_H -#define _LINUX_SYSCTL_H - -#include -#include -#include -#include -#include -#include - -/* For the /proc/sys support */ -struct completion; -struct ctl_table; -struct nsproxy; -struct ctl_table_root; -struct ctl_table_header; -struct ctl_dir; - -typedef int proc_handler (struct ctl_table *ctl, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); - -extern int proc_dostring(struct ctl_table *, int, - void __user *, size_t *, loff_t *); -extern int proc_dointvec(struct ctl_table *, int, - void __user *, size_t *, loff_t *); -extern int proc_douintvec(struct ctl_table *, int, - void __user *, size_t *, loff_t *); -extern int proc_dointvec_minmax(struct ctl_table *, int, - void __user *, size_t *, loff_t *); -extern int proc_dointvec_jiffies(struct ctl_table *, int, - void __user *, size_t *, loff_t *); -extern int proc_dointvec_userhz_jiffies(struct ctl_table *, int, - void __user *, size_t *, loff_t *); -extern int proc_dointvec_ms_jiffies(struct ctl_table *, int, - void __user *, size_t *, loff_t *); -extern int proc_doulongvec_minmax(struct ctl_table *, int, - void __user *, size_t *, loff_t *); -extern int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int, - void __user *, size_t *, loff_t *); -extern int proc_do_large_bitmap(struct ctl_table *, int, - void __user *, size_t *, loff_t *); - -/* - * Register a set of sysctl names by calling register_sysctl_table - * with an initialised array of struct ctl_table's. An entry with - * NULL procname terminates the table. table->de will be - * set up by the registration and need not be initialised in advance. - * - * sysctl names can be mirrored automatically under /proc/sys. The - * procname supplied controls /proc naming. - * - * The table's mode will be honoured both for sys_sysctl(2) and - * proc-fs access. - * - * Leaf nodes in the sysctl tree will be represented by a single file - * under /proc; non-leaf nodes will be represented by directories. A - * null procname disables /proc mirroring at this node. - * - * sysctl(2) can automatically manage read and write requests through - * the sysctl table. The data and maxlen fields of the ctl_table - * struct enable minimal validation of the values being written to be - * performed, and the mode field allows minimal authentication. - * - * There must be a proc_handler routine for any terminal nodes - * mirrored under /proc/sys (non-terminals are handled by a built-in - * directory handler). Several default handlers are available to - * cover common cases. - */ - -/* Support for userspace poll() to watch for changes */ -struct ctl_table_poll { - atomic_t event; - wait_queue_head_t wait; -}; - -static inline void *proc_sys_poll_event(struct ctl_table_poll *poll) -{ - return (void *)(unsigned long)atomic_read(&poll->event); -} - -#define __CTL_TABLE_POLL_INITIALIZER(name) { \ - .event = ATOMIC_INIT(0), \ - .wait = __WAIT_QUEUE_HEAD_INITIALIZER(name.wait) } - -#define DEFINE_CTL_TABLE_POLL(name) \ - struct ctl_table_poll name = __CTL_TABLE_POLL_INITIALIZER(name) - -/* A sysctl table is an array of struct ctl_table: */ -struct ctl_table -{ - const char *procname; /* Text ID for /proc/sys, or zero */ - void *data; - int maxlen; - umode_t mode; - struct ctl_table *child; /* Deprecated */ - proc_handler *proc_handler; /* Callback for text formatting */ - struct ctl_table_poll *poll; - void *extra1; - void *extra2; -}; - -struct ctl_node { - struct rb_node node; - struct ctl_table_header *header; -}; - -/* struct ctl_table_header is used to maintain dynamic lists of - struct ctl_table trees. */ -struct ctl_table_header -{ - union { - struct { - struct ctl_table *ctl_table; - int used; - int count; - int nreg; - }; - struct rcu_head rcu; - }; - struct completion *unregistering; - struct ctl_table *ctl_table_arg; - struct ctl_table_root *root; - struct ctl_table_set *set; - struct ctl_dir *parent; - struct ctl_node *node; -}; - -struct ctl_dir { - /* Header must be at the start of ctl_dir */ - struct ctl_table_header header; - struct rb_root root; -}; - -struct ctl_table_set { - int (*is_seen)(struct ctl_table_set *); - struct ctl_dir dir; -}; - -struct ctl_table_root { - struct ctl_table_set default_set; - struct ctl_table_set *(*lookup)(struct ctl_table_root *root); - void (*set_ownership)(struct ctl_table_header *head, - struct ctl_table *table, - kuid_t *uid, kgid_t *gid); - int (*permissions)(struct ctl_table_header *head, struct ctl_table *table); -}; - -/* struct ctl_path describes where in the hierarchy a table is added */ -struct ctl_path { - const char *procname; -}; - -#ifdef CONFIG_SYSCTL - -void proc_sys_poll_notify(struct ctl_table_poll *poll); - -extern void setup_sysctl_set(struct ctl_table_set *p, - struct ctl_table_root *root, - int (*is_seen)(struct ctl_table_set *)); -extern void retire_sysctl_set(struct ctl_table_set *set); - -void register_sysctl_root(struct ctl_table_root *root); -struct ctl_table_header *__register_sysctl_table( - struct ctl_table_set *set, - const char *path, struct ctl_table *table); -struct ctl_table_header *__register_sysctl_paths( - struct ctl_table_set *set, - const struct ctl_path *path, struct ctl_table *table); -struct ctl_table_header *register_sysctl(const char *path, struct ctl_table *table); -struct ctl_table_header *register_sysctl_table(struct ctl_table * table); -struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path, - struct ctl_table *table); - -void unregister_sysctl_table(struct ctl_table_header * table); - -extern int sysctl_init(void); - -extern struct ctl_table sysctl_mount_point[]; - -#else /* CONFIG_SYSCTL */ -static inline struct ctl_table_header *register_sysctl_table(struct ctl_table * table) -{ - return NULL; -} - -static inline struct ctl_table_header *register_sysctl_paths( - const struct ctl_path *path, struct ctl_table *table) -{ - return NULL; -} - -static inline void unregister_sysctl_table(struct ctl_table_header * table) -{ -} - -static inline void setup_sysctl_set(struct ctl_table_set *p, - struct ctl_table_root *root, - int (*is_seen)(struct ctl_table_set *)) -{ -} - -#endif /* CONFIG_SYSCTL */ - -int sysctl_max_threads(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); - -#endif /* _LINUX_SYSCTL_H */ diff --git a/src/linux/include/linux/sysfs.h b/src/linux/include/linux/sysfs.h deleted file mode 100644 index c6f0f0d..0000000 --- a/src/linux/include/linux/sysfs.h +++ /dev/null @@ -1,531 +0,0 @@ -/* - * sysfs.h - definitions for the device driver filesystem - * - * Copyright (c) 2001,2002 Patrick Mochel - * Copyright (c) 2004 Silicon Graphics, Inc. - * Copyright (c) 2007 SUSE Linux Products GmbH - * Copyright (c) 2007 Tejun Heo - * - * Please see Documentation/filesystems/sysfs.txt for more information. - */ - -#ifndef _SYSFS_H_ -#define _SYSFS_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -struct kobject; -struct module; -struct bin_attribute; -enum kobj_ns_type; - -struct attribute { - const char *name; - umode_t mode; -#ifdef CONFIG_DEBUG_LOCK_ALLOC - bool ignore_lockdep:1; - struct lock_class_key *key; - struct lock_class_key skey; -#endif -}; - -/** - * sysfs_attr_init - initialize a dynamically allocated sysfs attribute - * @attr: struct attribute to initialize - * - * Initialize a dynamically allocated struct attribute so we can - * make lockdep happy. This is a new requirement for attributes - * and initially this is only needed when lockdep is enabled. - * Lockdep gives a nice error when your attribute is added to - * sysfs if you don't have this. - */ -#ifdef CONFIG_DEBUG_LOCK_ALLOC -#define sysfs_attr_init(attr) \ -do { \ - static struct lock_class_key __key; \ - \ - (attr)->key = &__key; \ -} while (0) -#else -#define sysfs_attr_init(attr) do {} while (0) -#endif - -/** - * struct attribute_group - data structure used to declare an attribute group. - * @name: Optional: Attribute group name - * If specified, the attribute group will be created in - * a new subdirectory with this name. - * @is_visible: Optional: Function to return permissions associated with an - * attribute of the group. Will be called repeatedly for each - * non-binary attribute in the group. Only read/write - * permissions as well as SYSFS_PREALLOC are accepted. Must - * return 0 if an attribute is not visible. The returned value - * will replace static permissions defined in struct attribute. - * @is_bin_visible: - * Optional: Function to return permissions associated with a - * binary attribute of the group. Will be called repeatedly - * for each binary attribute in the group. Only read/write - * permissions as well as SYSFS_PREALLOC are accepted. Must - * return 0 if a binary attribute is not visible. The returned - * value will replace static permissions defined in - * struct bin_attribute. - * @attrs: Pointer to NULL terminated list of attributes. - * @bin_attrs: Pointer to NULL terminated list of binary attributes. - * Either attrs or bin_attrs or both must be provided. - */ -struct attribute_group { - const char *name; - umode_t (*is_visible)(struct kobject *, - struct attribute *, int); - umode_t (*is_bin_visible)(struct kobject *, - struct bin_attribute *, int); - struct attribute **attrs; - struct bin_attribute **bin_attrs; -}; - -/** - * Use these macros to make defining attributes easier. See include/linux/device.h - * for examples.. - */ - -#define SYSFS_PREALLOC 010000 - -#define __ATTR(_name, _mode, _show, _store) { \ - .attr = {.name = __stringify(_name), \ - .mode = VERIFY_OCTAL_PERMISSIONS(_mode) }, \ - .show = _show, \ - .store = _store, \ -} - -#define __ATTR_PREALLOC(_name, _mode, _show, _store) { \ - .attr = {.name = __stringify(_name), \ - .mode = SYSFS_PREALLOC | VERIFY_OCTAL_PERMISSIONS(_mode) },\ - .show = _show, \ - .store = _store, \ -} - -#define __ATTR_RO(_name) { \ - .attr = { .name = __stringify(_name), .mode = S_IRUGO }, \ - .show = _name##_show, \ -} - -#define __ATTR_WO(_name) { \ - .attr = { .name = __stringify(_name), .mode = S_IWUSR }, \ - .store = _name##_store, \ -} - -#define __ATTR_RW(_name) __ATTR(_name, (S_IWUSR | S_IRUGO), \ - _name##_show, _name##_store) - -#define __ATTR_NULL { .attr = { .name = NULL } } - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -#define __ATTR_IGNORE_LOCKDEP(_name, _mode, _show, _store) { \ - .attr = {.name = __stringify(_name), .mode = _mode, \ - .ignore_lockdep = true }, \ - .show = _show, \ - .store = _store, \ -} -#else -#define __ATTR_IGNORE_LOCKDEP __ATTR -#endif - -#define __ATTRIBUTE_GROUPS(_name) \ -static const struct attribute_group *_name##_groups[] = { \ - &_name##_group, \ - NULL, \ -} - -#define ATTRIBUTE_GROUPS(_name) \ -static const struct attribute_group _name##_group = { \ - .attrs = _name##_attrs, \ -}; \ -__ATTRIBUTE_GROUPS(_name) - -struct file; -struct vm_area_struct; - -struct bin_attribute { - struct attribute attr; - size_t size; - void *private; - ssize_t (*read)(struct file *, struct kobject *, struct bin_attribute *, - char *, loff_t, size_t); - ssize_t (*write)(struct file *, struct kobject *, struct bin_attribute *, - char *, loff_t, size_t); - int (*mmap)(struct file *, struct kobject *, struct bin_attribute *attr, - struct vm_area_struct *vma); -}; - -/** - * sysfs_bin_attr_init - initialize a dynamically allocated bin_attribute - * @attr: struct bin_attribute to initialize - * - * Initialize a dynamically allocated struct bin_attribute so we - * can make lockdep happy. This is a new requirement for - * attributes and initially this is only needed when lockdep is - * enabled. Lockdep gives a nice error when your attribute is - * added to sysfs if you don't have this. - */ -#define sysfs_bin_attr_init(bin_attr) sysfs_attr_init(&(bin_attr)->attr) - -/* macros to create static binary attributes easier */ -#define __BIN_ATTR(_name, _mode, _read, _write, _size) { \ - .attr = { .name = __stringify(_name), .mode = _mode }, \ - .read = _read, \ - .write = _write, \ - .size = _size, \ -} - -#define __BIN_ATTR_RO(_name, _size) { \ - .attr = { .name = __stringify(_name), .mode = S_IRUGO }, \ - .read = _name##_read, \ - .size = _size, \ -} - -#define __BIN_ATTR_RW(_name, _size) __BIN_ATTR(_name, \ - (S_IWUSR | S_IRUGO), _name##_read, \ - _name##_write, _size) - -#define __BIN_ATTR_NULL __ATTR_NULL - -#define BIN_ATTR(_name, _mode, _read, _write, _size) \ -struct bin_attribute bin_attr_##_name = __BIN_ATTR(_name, _mode, _read, \ - _write, _size) - -#define BIN_ATTR_RO(_name, _size) \ -struct bin_attribute bin_attr_##_name = __BIN_ATTR_RO(_name, _size) - -#define BIN_ATTR_RW(_name, _size) \ -struct bin_attribute bin_attr_##_name = __BIN_ATTR_RW(_name, _size) - -struct sysfs_ops { - ssize_t (*show)(struct kobject *, struct attribute *, char *); - ssize_t (*store)(struct kobject *, struct attribute *, const char *, size_t); -}; - -#ifdef CONFIG_SYSFS - -int __must_check sysfs_create_dir_ns(struct kobject *kobj, const void *ns); -void sysfs_remove_dir(struct kobject *kobj); -int __must_check sysfs_rename_dir_ns(struct kobject *kobj, const char *new_name, - const void *new_ns); -int __must_check sysfs_move_dir_ns(struct kobject *kobj, - struct kobject *new_parent_kobj, - const void *new_ns); -int __must_check sysfs_create_mount_point(struct kobject *parent_kobj, - const char *name); -void sysfs_remove_mount_point(struct kobject *parent_kobj, - const char *name); - -int __must_check sysfs_create_file_ns(struct kobject *kobj, - const struct attribute *attr, - const void *ns); -int __must_check sysfs_create_files(struct kobject *kobj, - const struct attribute **attr); -int __must_check sysfs_chmod_file(struct kobject *kobj, - const struct attribute *attr, umode_t mode); -void sysfs_remove_file_ns(struct kobject *kobj, const struct attribute *attr, - const void *ns); -bool sysfs_remove_file_self(struct kobject *kobj, const struct attribute *attr); -void sysfs_remove_files(struct kobject *kobj, const struct attribute **attr); - -int __must_check sysfs_create_bin_file(struct kobject *kobj, - const struct bin_attribute *attr); -void sysfs_remove_bin_file(struct kobject *kobj, - const struct bin_attribute *attr); - -int __must_check sysfs_create_link(struct kobject *kobj, struct kobject *target, - const char *name); -int __must_check sysfs_create_link_nowarn(struct kobject *kobj, - struct kobject *target, - const char *name); -void sysfs_remove_link(struct kobject *kobj, const char *name); - -int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *target, - const char *old_name, const char *new_name, - const void *new_ns); - -void sysfs_delete_link(struct kobject *dir, struct kobject *targ, - const char *name); - -int __must_check sysfs_create_group(struct kobject *kobj, - const struct attribute_group *grp); -int __must_check sysfs_create_groups(struct kobject *kobj, - const struct attribute_group **groups); -int sysfs_update_group(struct kobject *kobj, - const struct attribute_group *grp); -void sysfs_remove_group(struct kobject *kobj, - const struct attribute_group *grp); -void sysfs_remove_groups(struct kobject *kobj, - const struct attribute_group **groups); -int sysfs_add_file_to_group(struct kobject *kobj, - const struct attribute *attr, const char *group); -void sysfs_remove_file_from_group(struct kobject *kobj, - const struct attribute *attr, const char *group); -int sysfs_merge_group(struct kobject *kobj, - const struct attribute_group *grp); -void sysfs_unmerge_group(struct kobject *kobj, - const struct attribute_group *grp); -int sysfs_add_link_to_group(struct kobject *kobj, const char *group_name, - struct kobject *target, const char *link_name); -void sysfs_remove_link_from_group(struct kobject *kobj, const char *group_name, - const char *link_name); -int __compat_only_sysfs_link_entry_to_kobj(struct kobject *kobj, - struct kobject *target_kobj, - const char *target_name); - -void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr); - -int __must_check sysfs_init(void); - -static inline void sysfs_enable_ns(struct kernfs_node *kn) -{ - return kernfs_enable_ns(kn); -} - -#else /* CONFIG_SYSFS */ - -static inline int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) -{ - return 0; -} - -static inline void sysfs_remove_dir(struct kobject *kobj) -{ -} - -static inline int sysfs_rename_dir_ns(struct kobject *kobj, - const char *new_name, const void *new_ns) -{ - return 0; -} - -static inline int sysfs_move_dir_ns(struct kobject *kobj, - struct kobject *new_parent_kobj, - const void *new_ns) -{ - return 0; -} - -static inline int sysfs_create_mount_point(struct kobject *parent_kobj, - const char *name) -{ - return 0; -} - -static inline void sysfs_remove_mount_point(struct kobject *parent_kobj, - const char *name) -{ -} - -static inline int sysfs_create_file_ns(struct kobject *kobj, - const struct attribute *attr, - const void *ns) -{ - return 0; -} - -static inline int sysfs_create_files(struct kobject *kobj, - const struct attribute **attr) -{ - return 0; -} - -static inline int sysfs_chmod_file(struct kobject *kobj, - const struct attribute *attr, umode_t mode) -{ - return 0; -} - -static inline void sysfs_remove_file_ns(struct kobject *kobj, - const struct attribute *attr, - const void *ns) -{ -} - -static inline bool sysfs_remove_file_self(struct kobject *kobj, - const struct attribute *attr) -{ - return false; -} - -static inline void sysfs_remove_files(struct kobject *kobj, - const struct attribute **attr) -{ -} - -static inline int sysfs_create_bin_file(struct kobject *kobj, - const struct bin_attribute *attr) -{ - return 0; -} - -static inline void sysfs_remove_bin_file(struct kobject *kobj, - const struct bin_attribute *attr) -{ -} - -static inline int sysfs_create_link(struct kobject *kobj, - struct kobject *target, const char *name) -{ - return 0; -} - -static inline int sysfs_create_link_nowarn(struct kobject *kobj, - struct kobject *target, - const char *name) -{ - return 0; -} - -static inline void sysfs_remove_link(struct kobject *kobj, const char *name) -{ -} - -static inline int sysfs_rename_link_ns(struct kobject *k, struct kobject *t, - const char *old_name, - const char *new_name, const void *ns) -{ - return 0; -} - -static inline void sysfs_delete_link(struct kobject *k, struct kobject *t, - const char *name) -{ -} - -static inline int sysfs_create_group(struct kobject *kobj, - const struct attribute_group *grp) -{ - return 0; -} - -static inline int sysfs_create_groups(struct kobject *kobj, - const struct attribute_group **groups) -{ - return 0; -} - -static inline int sysfs_update_group(struct kobject *kobj, - const struct attribute_group *grp) -{ - return 0; -} - -static inline void sysfs_remove_group(struct kobject *kobj, - const struct attribute_group *grp) -{ -} - -static inline void sysfs_remove_groups(struct kobject *kobj, - const struct attribute_group **groups) -{ -} - -static inline int sysfs_add_file_to_group(struct kobject *kobj, - const struct attribute *attr, const char *group) -{ - return 0; -} - -static inline void sysfs_remove_file_from_group(struct kobject *kobj, - const struct attribute *attr, const char *group) -{ -} - -static inline int sysfs_merge_group(struct kobject *kobj, - const struct attribute_group *grp) -{ - return 0; -} - -static inline void sysfs_unmerge_group(struct kobject *kobj, - const struct attribute_group *grp) -{ -} - -static inline int sysfs_add_link_to_group(struct kobject *kobj, - const char *group_name, struct kobject *target, - const char *link_name) -{ - return 0; -} - -static inline void sysfs_remove_link_from_group(struct kobject *kobj, - const char *group_name, const char *link_name) -{ -} - -static inline int __compat_only_sysfs_link_entry_to_kobj( - struct kobject *kobj, - struct kobject *target_kobj, - const char *target_name) -{ - return 0; -} - -static inline void sysfs_notify(struct kobject *kobj, const char *dir, - const char *attr) -{ -} - -static inline int __must_check sysfs_init(void) -{ - return 0; -} - -static inline void sysfs_enable_ns(struct kernfs_node *kn) -{ -} - -#endif /* CONFIG_SYSFS */ - -static inline int __must_check sysfs_create_file(struct kobject *kobj, - const struct attribute *attr) -{ - return sysfs_create_file_ns(kobj, attr, NULL); -} - -static inline void sysfs_remove_file(struct kobject *kobj, - const struct attribute *attr) -{ - sysfs_remove_file_ns(kobj, attr, NULL); -} - -static inline int sysfs_rename_link(struct kobject *kobj, struct kobject *target, - const char *old_name, const char *new_name) -{ - return sysfs_rename_link_ns(kobj, target, old_name, new_name, NULL); -} - -static inline void sysfs_notify_dirent(struct kernfs_node *kn) -{ - kernfs_notify(kn); -} - -static inline struct kernfs_node *sysfs_get_dirent(struct kernfs_node *parent, - const unsigned char *name) -{ - return kernfs_find_and_get(parent, name); -} - -static inline struct kernfs_node *sysfs_get(struct kernfs_node *kn) -{ - kernfs_get(kn); - return kn; -} - -static inline void sysfs_put(struct kernfs_node *kn) -{ - kernfs_put(kn); -} - -#endif /* _SYSFS_H_ */ diff --git a/src/linux/include/linux/syslog.h b/src/linux/include/linux/syslog.h deleted file mode 100644 index c3a7f0c..0000000 --- a/src/linux/include/linux/syslog.h +++ /dev/null @@ -1,61 +0,0 @@ -/* Syslog internals - * - * Copyright 2010 Canonical, Ltd. - * Author: Kees Cook - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#ifndef _LINUX_SYSLOG_H -#define _LINUX_SYSLOG_H - -/* Close the log. Currently a NOP. */ -#define SYSLOG_ACTION_CLOSE 0 -/* Open the log. Currently a NOP. */ -#define SYSLOG_ACTION_OPEN 1 -/* Read from the log. */ -#define SYSLOG_ACTION_READ 2 -/* Read all messages remaining in the ring buffer. */ -#define SYSLOG_ACTION_READ_ALL 3 -/* Read and clear all messages remaining in the ring buffer */ -#define SYSLOG_ACTION_READ_CLEAR 4 -/* Clear ring buffer. */ -#define SYSLOG_ACTION_CLEAR 5 -/* Disable printk's to console */ -#define SYSLOG_ACTION_CONSOLE_OFF 6 -/* Enable printk's to console */ -#define SYSLOG_ACTION_CONSOLE_ON 7 -/* Set level of messages printed to console */ -#define SYSLOG_ACTION_CONSOLE_LEVEL 8 -/* Return number of unread characters in the log buffer */ -#define SYSLOG_ACTION_SIZE_UNREAD 9 -/* Return size of the log buffer */ -#define SYSLOG_ACTION_SIZE_BUFFER 10 - -#define SYSLOG_FROM_READER 0 -#define SYSLOG_FROM_PROC 1 - -int do_syslog(int type, char __user *buf, int count, int source); - -#ifdef CONFIG_PRINTK -int check_syslog_permissions(int type, int source); -#else -static inline int check_syslog_permissions(int type, int source) -{ - return 0; -} -#endif - -#endif /* _LINUX_SYSLOG_H */ diff --git a/src/linux/include/linux/sysrq.h b/src/linux/include/linux/sysrq.h deleted file mode 100644 index 387fa7d..0000000 --- a/src/linux/include/linux/sysrq.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -*- linux-c -*- - * - * $Id: sysrq.h,v 1.3 1997/07/17 11:54:33 mj Exp $ - * - * Linux Magic System Request Key Hacks - * - * (c) 1997 Martin Mares - * - * (c) 2000 Crutcher Dunnavant - * overhauled to use key registration - * based upon discusions in irc://irc.openprojects.net/#kernelnewbies - */ - -#ifndef _LINUX_SYSRQ_H -#define _LINUX_SYSRQ_H - -#include -#include - -/* Possible values of bitmask for enabling sysrq functions */ -/* 0x0001 is reserved for enable everything */ -#define SYSRQ_ENABLE_LOG 0x0002 -#define SYSRQ_ENABLE_KEYBOARD 0x0004 -#define SYSRQ_ENABLE_DUMP 0x0008 -#define SYSRQ_ENABLE_SYNC 0x0010 -#define SYSRQ_ENABLE_REMOUNT 0x0020 -#define SYSRQ_ENABLE_SIGNAL 0x0040 -#define SYSRQ_ENABLE_BOOT 0x0080 -#define SYSRQ_ENABLE_RTNICE 0x0100 - -struct sysrq_key_op { - void (*handler)(int); - char *help_msg; - char *action_msg; - int enable_mask; -}; - -#ifdef CONFIG_MAGIC_SYSRQ - -/* Generic SysRq interface -- you may call it from any device driver, supplying - * ASCII code of the key, pointer to registers and kbd/tty structs (if they - * are available -- else NULL's). - */ - -void handle_sysrq(int key); -void __handle_sysrq(int key, bool check_mask); -int register_sysrq_key(int key, struct sysrq_key_op *op); -int unregister_sysrq_key(int key, struct sysrq_key_op *op); -struct sysrq_key_op *__sysrq_get_key_op(int key); - -int sysrq_toggle_support(int enable_mask); - -#else - -static inline void handle_sysrq(int key) -{ -} - -static inline void __handle_sysrq(int key, bool check_mask) -{ -} - -static inline int register_sysrq_key(int key, struct sysrq_key_op *op) -{ - return -EINVAL; -} - -static inline int unregister_sysrq_key(int key, struct sysrq_key_op *op) -{ - return -EINVAL; -} - -#endif - -#endif /* _LINUX_SYSRQ_H */ diff --git a/src/linux/include/linux/task_io_accounting.h b/src/linux/include/linux/task_io_accounting.h deleted file mode 100644 index bdf855c..0000000 --- a/src/linux/include/linux/task_io_accounting.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * task_io_accounting: a structure which is used for recording a single task's - * IO statistics. - * - * Don't include this header file directly - it is designed to be dragged in via - * sched.h. - * - * Blame Andrew Morton for all this. - */ - -struct task_io_accounting { -#ifdef CONFIG_TASK_XACCT - /* bytes read */ - u64 rchar; - /* bytes written */ - u64 wchar; - /* # of read syscalls */ - u64 syscr; - /* # of write syscalls */ - u64 syscw; -#endif /* CONFIG_TASK_XACCT */ - -#ifdef CONFIG_TASK_IO_ACCOUNTING - /* - * The number of bytes which this task has caused to be read from - * storage. - */ - u64 read_bytes; - - /* - * The number of bytes which this task has caused, or shall cause to be - * written to disk. - */ - u64 write_bytes; - - /* - * A task can cause "negative" IO too. If this task truncates some - * dirty pagecache, some IO which another task has been accounted for - * (in its write_bytes) will not be happening. We _could_ just - * subtract that from the truncating task's write_bytes, but there is - * information loss in doing that. - */ - u64 cancelled_write_bytes; -#endif /* CONFIG_TASK_IO_ACCOUNTING */ -}; diff --git a/src/linux/include/linux/task_io_accounting_ops.h b/src/linux/include/linux/task_io_accounting_ops.h deleted file mode 100644 index 4d090f9..0000000 --- a/src/linux/include/linux/task_io_accounting_ops.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Task I/O accounting operations - */ -#ifndef __TASK_IO_ACCOUNTING_OPS_INCLUDED -#define __TASK_IO_ACCOUNTING_OPS_INCLUDED - -#include - -#ifdef CONFIG_TASK_IO_ACCOUNTING -static inline void task_io_account_read(size_t bytes) -{ - current->ioac.read_bytes += bytes; -} - -/* - * We approximate number of blocks, because we account bytes only. - * A 'block' is 512 bytes - */ -static inline unsigned long task_io_get_inblock(const struct task_struct *p) -{ - return p->ioac.read_bytes >> 9; -} - -static inline void task_io_account_write(size_t bytes) -{ - current->ioac.write_bytes += bytes; -} - -/* - * We approximate number of blocks, because we account bytes only. - * A 'block' is 512 bytes - */ -static inline unsigned long task_io_get_oublock(const struct task_struct *p) -{ - return p->ioac.write_bytes >> 9; -} - -static inline void task_io_account_cancelled_write(size_t bytes) -{ - current->ioac.cancelled_write_bytes += bytes; -} - -static inline void task_io_accounting_init(struct task_io_accounting *ioac) -{ - memset(ioac, 0, sizeof(*ioac)); -} - -static inline void task_blk_io_accounting_add(struct task_io_accounting *dst, - struct task_io_accounting *src) -{ - dst->read_bytes += src->read_bytes; - dst->write_bytes += src->write_bytes; - dst->cancelled_write_bytes += src->cancelled_write_bytes; -} - -#else - -static inline void task_io_account_read(size_t bytes) -{ -} - -static inline unsigned long task_io_get_inblock(const struct task_struct *p) -{ - return 0; -} - -static inline void task_io_account_write(size_t bytes) -{ -} - -static inline unsigned long task_io_get_oublock(const struct task_struct *p) -{ - return 0; -} - -static inline void task_io_account_cancelled_write(size_t bytes) -{ -} - -static inline void task_io_accounting_init(struct task_io_accounting *ioac) -{ -} - -static inline void task_blk_io_accounting_add(struct task_io_accounting *dst, - struct task_io_accounting *src) -{ -} - -#endif /* CONFIG_TASK_IO_ACCOUNTING */ - -#ifdef CONFIG_TASK_XACCT -static inline void task_chr_io_accounting_add(struct task_io_accounting *dst, - struct task_io_accounting *src) -{ - dst->rchar += src->rchar; - dst->wchar += src->wchar; - dst->syscr += src->syscr; - dst->syscw += src->syscw; -} -#else -static inline void task_chr_io_accounting_add(struct task_io_accounting *dst, - struct task_io_accounting *src) -{ -} -#endif /* CONFIG_TASK_XACCT */ - -static inline void task_io_accounting_add(struct task_io_accounting *dst, - struct task_io_accounting *src) -{ - task_chr_io_accounting_add(dst, src); - task_blk_io_accounting_add(dst, src); -} -#endif /* __TASK_IO_ACCOUNTING_OPS_INCLUDED */ diff --git a/src/linux/include/linux/task_work.h b/src/linux/include/linux/task_work.h deleted file mode 100644 index ca5a1cf..0000000 --- a/src/linux/include/linux/task_work.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _LINUX_TASK_WORK_H -#define _LINUX_TASK_WORK_H - -#include -#include - -typedef void (*task_work_func_t)(struct callback_head *); - -static inline void -init_task_work(struct callback_head *twork, task_work_func_t func) -{ - twork->func = func; -} - -int task_work_add(struct task_struct *task, struct callback_head *twork, bool); -struct callback_head *task_work_cancel(struct task_struct *, task_work_func_t); -void task_work_run(void); - -static inline void exit_task_work(struct task_struct *task) -{ - task_work_run(); -} - -#endif /* _LINUX_TASK_WORK_H */ diff --git a/src/linux/include/linux/taskstats_kern.h b/src/linux/include/linux/taskstats_kern.h deleted file mode 100644 index 58de6ed..0000000 --- a/src/linux/include/linux/taskstats_kern.h +++ /dev/null @@ -1,36 +0,0 @@ -/* taskstats_kern.h - kernel header for per-task statistics interface - * - * Copyright (C) Shailabh Nagar, IBM Corp. 2006 - * (C) Balbir Singh, IBM Corp. 2006 - */ - -#ifndef _LINUX_TASKSTATS_KERN_H -#define _LINUX_TASKSTATS_KERN_H - -#include -#include -#include - -#ifdef CONFIG_TASKSTATS -extern struct kmem_cache *taskstats_cache; -extern struct mutex taskstats_exit_mutex; - -static inline void taskstats_tgid_free(struct signal_struct *sig) -{ - if (sig->stats) - kmem_cache_free(taskstats_cache, sig->stats); -} - -extern void taskstats_exit(struct task_struct *, int group_dead); -extern void taskstats_init_early(void); -#else -static inline void taskstats_exit(struct task_struct *tsk, int group_dead) -{} -static inline void taskstats_tgid_free(struct signal_struct *sig) -{} -static inline void taskstats_init_early(void) -{} -#endif /* CONFIG_TASKSTATS */ - -#endif - diff --git a/src/linux/include/linux/tcp.h b/src/linux/include/linux/tcp.h deleted file mode 100644 index a17ae7b..0000000 --- a/src/linux/include/linux/tcp.h +++ /dev/null @@ -1,430 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the TCP protocol. - * - * Version: @(#)tcp.h 1.0.2 04/28/93 - * - * Author: Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_TCP_H -#define _LINUX_TCP_H - - -#include -#include -#include -#include -#include -#include - -static inline struct tcphdr *tcp_hdr(const struct sk_buff *skb) -{ - return (struct tcphdr *)skb_transport_header(skb); -} - -static inline unsigned int __tcp_hdrlen(const struct tcphdr *th) -{ - return th->doff * 4; -} - -static inline unsigned int tcp_hdrlen(const struct sk_buff *skb) -{ - return __tcp_hdrlen(tcp_hdr(skb)); -} - -static inline struct tcphdr *inner_tcp_hdr(const struct sk_buff *skb) -{ - return (struct tcphdr *)skb_inner_transport_header(skb); -} - -static inline unsigned int inner_tcp_hdrlen(const struct sk_buff *skb) -{ - return inner_tcp_hdr(skb)->doff * 4; -} - -static inline unsigned int tcp_optlen(const struct sk_buff *skb) -{ - return (tcp_hdr(skb)->doff - 5) * 4; -} - -/* TCP Fast Open */ -#define TCP_FASTOPEN_COOKIE_MIN 4 /* Min Fast Open Cookie size in bytes */ -#define TCP_FASTOPEN_COOKIE_MAX 16 /* Max Fast Open Cookie size in bytes */ -#define TCP_FASTOPEN_COOKIE_SIZE 8 /* the size employed by this impl. */ - -/* TCP Fast Open Cookie as stored in memory */ -struct tcp_fastopen_cookie { - s8 len; - u8 val[TCP_FASTOPEN_COOKIE_MAX]; - bool exp; /* In RFC6994 experimental option format */ -}; - -/* This defines a selective acknowledgement block. */ -struct tcp_sack_block_wire { - __be32 start_seq; - __be32 end_seq; -}; - -struct tcp_sack_block { - u32 start_seq; - u32 end_seq; -}; - -/*These are used to set the sack_ok field in struct tcp_options_received */ -#define TCP_SACK_SEEN (1 << 0) /*1 = peer is SACK capable, */ -#define TCP_FACK_ENABLED (1 << 1) /*1 = FACK is enabled locally*/ -#define TCP_DSACK_SEEN (1 << 2) /*1 = DSACK was received from peer*/ - -struct tcp_options_received { -/* PAWS/RTTM data */ - long ts_recent_stamp;/* Time we stored ts_recent (for aging) */ - u32 ts_recent; /* Time stamp to echo next */ - u32 rcv_tsval; /* Time stamp value */ - u32 rcv_tsecr; /* Time stamp echo reply */ - u16 saw_tstamp : 1, /* Saw TIMESTAMP on last packet */ - tstamp_ok : 1, /* TIMESTAMP seen on SYN packet */ - dsack : 1, /* D-SACK is scheduled */ - wscale_ok : 1, /* Wscale seen on SYN packet */ - sack_ok : 4, /* SACK seen on SYN packet */ - snd_wscale : 4, /* Window scaling received from sender */ - rcv_wscale : 4; /* Window scaling to send to receiver */ - u8 num_sacks; /* Number of SACK blocks */ - u16 user_mss; /* mss requested by user in ioctl */ - u16 mss_clamp; /* Maximal mss, negotiated at connection setup */ -}; - -static inline void tcp_clear_options(struct tcp_options_received *rx_opt) -{ - rx_opt->tstamp_ok = rx_opt->sack_ok = 0; - rx_opt->wscale_ok = rx_opt->snd_wscale = 0; -} - -/* This is the max number of SACKS that we'll generate and process. It's safe - * to increase this, although since: - * size = TCPOLEN_SACK_BASE_ALIGNED (4) + n * TCPOLEN_SACK_PERBLOCK (8) - * only four options will fit in a standard TCP header */ -#define TCP_NUM_SACKS 4 - -struct tcp_request_sock_ops; - -struct tcp_request_sock { - struct inet_request_sock req; - const struct tcp_request_sock_ops *af_specific; - struct skb_mstamp snt_synack; /* first SYNACK sent time */ - bool tfo_listener; - u32 txhash; - u32 rcv_isn; - u32 snt_isn; - u32 last_oow_ack_time; /* last SYNACK */ - u32 rcv_nxt; /* the ack # by SYNACK. For - * FastOpen it's the seq# - * after data-in-SYN. - */ -}; - -static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req) -{ - return (struct tcp_request_sock *)req; -} - -struct tcp_sock { - /* inet_connection_sock has to be the first member of tcp_sock */ - struct inet_connection_sock inet_conn; - u16 tcp_header_len; /* Bytes of tcp header to send */ - u16 gso_segs; /* Max number of segs per GSO packet */ - -/* - * Header prediction flags - * 0x5?10 << 16 + snd_wnd in net byte order - */ - __be32 pred_flags; - -/* - * RFC793 variables by their proper names. This means you can - * read the code and the spec side by side (and laugh ...) - * See RFC793 and RFC1122. The RFC writes these in capitals. - */ - u64 bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived - * sum(delta(rcv_nxt)), or how many bytes - * were acked. - */ - u32 segs_in; /* RFC4898 tcpEStatsPerfSegsIn - * total number of segments in. - */ - u32 data_segs_in; /* RFC4898 tcpEStatsPerfDataSegsIn - * total number of data segments in. - */ - u32 rcv_nxt; /* What we want to receive next */ - u32 copied_seq; /* Head of yet unread data */ - u32 rcv_wup; /* rcv_nxt on last window update sent */ - u32 snd_nxt; /* Next sequence we send */ - u32 segs_out; /* RFC4898 tcpEStatsPerfSegsOut - * The total number of segments sent. - */ - u32 data_segs_out; /* RFC4898 tcpEStatsPerfDataSegsOut - * total number of data segments sent. - */ - u64 bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked - * sum(delta(snd_una)), or how many bytes - * were acked. - */ - struct u64_stats_sync syncp; /* protects 64bit vars (cf tcp_get_info()) */ - - u32 snd_una; /* First byte we want an ack for */ - u32 snd_sml; /* Last byte of the most recently transmitted small packet */ - u32 rcv_tstamp; /* timestamp of last received ACK (for keepalives) */ - u32 lsndtime; /* timestamp of last sent data packet (for restart window) */ - u32 last_oow_ack_time; /* timestamp of last out-of-window ACK */ - - u32 tsoffset; /* timestamp offset */ - - struct list_head tsq_node; /* anchor in tsq_tasklet.head list */ - unsigned long tsq_flags; - - /* Data for direct copy to user */ - struct { - struct sk_buff_head prequeue; - struct task_struct *task; - struct msghdr *msg; - int memory; - int len; - } ucopy; - - u32 snd_wl1; /* Sequence for window update */ - u32 snd_wnd; /* The window we expect to receive */ - u32 max_window; /* Maximal window ever seen from peer */ - u32 mss_cache; /* Cached effective mss, not including SACKS */ - - u32 window_clamp; /* Maximal window to advertise */ - u32 rcv_ssthresh; /* Current window clamp */ - - /* Information of the most recently (s)acked skb */ - struct tcp_rack { - struct skb_mstamp mstamp; /* (Re)sent time of the skb */ - u8 advanced; /* mstamp advanced since last lost marking */ - u8 reord; /* reordering detected */ - } rack; - u16 advmss; /* Advertised MSS */ - u8 rate_app_limited:1, /* rate_{delivered,interval_us} limited? */ - unused:7; - u8 nonagle : 4,/* Disable Nagle algorithm? */ - thin_lto : 1,/* Use linear timeouts for thin streams */ - thin_dupack : 1,/* Fast retransmit on first dupack */ - repair : 1, - frto : 1;/* F-RTO (RFC5682) activated in CA_Loss */ - u8 repair_queue; - u8 do_early_retrans:1,/* Enable RFC5827 early-retransmit */ - syn_data:1, /* SYN includes data */ - syn_fastopen:1, /* SYN includes Fast Open option */ - syn_fastopen_exp:1,/* SYN includes Fast Open exp. option */ - syn_data_acked:1,/* data in SYN is acked by SYN-ACK */ - save_syn:1, /* Save headers of SYN packet */ - is_cwnd_limited:1;/* forward progress limited by snd_cwnd? */ - u32 tlp_high_seq; /* snd_nxt at the time of TLP retransmit. */ - -/* RTT measurement */ - u32 srtt_us; /* smoothed round trip time << 3 in usecs */ - u32 mdev_us; /* medium deviation */ - u32 mdev_max_us; /* maximal mdev for the last rtt period */ - u32 rttvar_us; /* smoothed mdev_max */ - u32 rtt_seq; /* sequence number to update rttvar */ - struct minmax rtt_min; - - u32 packets_out; /* Packets which are "in flight" */ - u32 retrans_out; /* Retransmitted packets out */ - u32 max_packets_out; /* max packets_out in last window */ - u32 max_packets_seq; /* right edge of max_packets_out flight */ - - u16 urg_data; /* Saved octet of OOB data and control flags */ - u8 ecn_flags; /* ECN status bits. */ - u8 keepalive_probes; /* num of allowed keep alive probes */ - u32 reordering; /* Packet reordering metric. */ - u32 snd_up; /* Urgent pointer */ - -/* - * Options received (usually on last packet, some only on SYN packets). - */ - struct tcp_options_received rx_opt; - -/* - * Slow start and congestion control (see also Nagle, and Karn & Partridge) - */ - u32 snd_ssthresh; /* Slow start size threshold */ - u32 snd_cwnd; /* Sending congestion window */ - u32 snd_cwnd_cnt; /* Linear increase counter */ - u32 snd_cwnd_clamp; /* Do not allow snd_cwnd to grow above this */ - u32 snd_cwnd_used; - u32 snd_cwnd_stamp; - u32 prior_cwnd; /* Congestion window at start of Recovery. */ - u32 prr_delivered; /* Number of newly delivered packets to - * receiver in Recovery. */ - u32 prr_out; /* Total number of pkts sent during Recovery. */ - u32 delivered; /* Total data packets delivered incl. rexmits */ - u32 lost; /* Total data packets lost incl. rexmits */ - u32 app_limited; /* limited until "delivered" reaches this val */ - struct skb_mstamp first_tx_mstamp; /* start of window send phase */ - struct skb_mstamp delivered_mstamp; /* time we reached "delivered" */ - u32 rate_delivered; /* saved rate sample: packets delivered */ - u32 rate_interval_us; /* saved rate sample: time elapsed */ - - u32 rcv_wnd; /* Current receiver window */ - u32 write_seq; /* Tail(+1) of data held in tcp send buffer */ - u32 notsent_lowat; /* TCP_NOTSENT_LOWAT */ - u32 pushed_seq; /* Last pushed seq, required to talk to windows */ - u32 lost_out; /* Lost packets */ - u32 sacked_out; /* SACK'd packets */ - u32 fackets_out; /* FACK'd packets */ - - /* from STCP, retrans queue hinting */ - struct sk_buff* lost_skb_hint; - struct sk_buff *retransmit_skb_hint; - - /* OOO segments go in this rbtree. Socket lock must be held. */ - struct rb_root out_of_order_queue; - struct sk_buff *ooo_last_skb; /* cache rb_last(out_of_order_queue) */ - - /* SACKs data, these 2 need to be together (see tcp_options_write) */ - struct tcp_sack_block duplicate_sack[1]; /* D-SACK block */ - struct tcp_sack_block selective_acks[4]; /* The SACKS themselves*/ - - struct tcp_sack_block recv_sack_cache[4]; - - struct sk_buff *highest_sack; /* skb just after the highest - * skb with SACKed bit set - * (validity guaranteed only if - * sacked_out > 0) - */ - - int lost_cnt_hint; - u32 retransmit_high; /* L-bits may be on up to this seqno */ - - u32 prior_ssthresh; /* ssthresh saved at recovery start */ - u32 high_seq; /* snd_nxt at onset of congestion */ - - u32 retrans_stamp; /* Timestamp of the last retransmit, - * also used in SYN-SENT to remember stamp of - * the first SYN. */ - u32 undo_marker; /* snd_una upon a new recovery episode. */ - int undo_retrans; /* number of undoable retransmissions. */ - u32 total_retrans; /* Total retransmits for entire connection */ - - u32 urg_seq; /* Seq of received urgent pointer */ - unsigned int keepalive_time; /* time before keep alive takes place */ - unsigned int keepalive_intvl; /* time interval between keep alive probes */ - - int linger2; - -/* Receiver side RTT estimation */ - struct { - u32 rtt; - u32 seq; - u32 time; - } rcv_rtt_est; - -/* Receiver queue space */ - struct { - int space; - u32 seq; - u32 time; - } rcvq_space; - -/* TCP-specific MTU probe information. */ - struct { - u32 probe_seq_start; - u32 probe_seq_end; - } mtu_probe; - u32 mtu_info; /* We received an ICMP_FRAG_NEEDED / ICMPV6_PKT_TOOBIG - * while socket was owned by user. - */ - -#ifdef CONFIG_TCP_MD5SIG -/* TCP AF-Specific parts; only used by MD5 Signature support so far */ - const struct tcp_sock_af_ops *af_specific; - -/* TCP MD5 Signature Option information */ - struct tcp_md5sig_info __rcu *md5sig_info; -#endif - -/* TCP fastopen related information */ - struct tcp_fastopen_request *fastopen_req; - /* fastopen_rsk points to request_sock that resulted in this big - * socket. Used to retransmit SYNACKs etc. - */ - struct request_sock *fastopen_rsk; - u32 *saved_syn; -}; - -enum tsq_flags { - TSQ_THROTTLED, - TSQ_QUEUED, - TCP_TSQ_DEFERRED, /* tcp_tasklet_func() found socket was owned */ - TCP_WRITE_TIMER_DEFERRED, /* tcp_write_timer() found socket was owned */ - TCP_DELACK_TIMER_DEFERRED, /* tcp_delack_timer() found socket was owned */ - TCP_MTU_REDUCED_DEFERRED, /* tcp_v{4|6}_err() could not call - * tcp_v{4|6}_mtu_reduced() - */ -}; - -static inline struct tcp_sock *tcp_sk(const struct sock *sk) -{ - return (struct tcp_sock *)sk; -} - -struct tcp_timewait_sock { - struct inet_timewait_sock tw_sk; -#define tw_rcv_nxt tw_sk.__tw_common.skc_tw_rcv_nxt -#define tw_snd_nxt tw_sk.__tw_common.skc_tw_snd_nxt - u32 tw_rcv_wnd; - u32 tw_ts_offset; - u32 tw_ts_recent; - - /* The time we sent the last out-of-window ACK: */ - u32 tw_last_oow_ack_time; - - long tw_ts_recent_stamp; -#ifdef CONFIG_TCP_MD5SIG - struct tcp_md5sig_key *tw_md5_key; -#endif -}; - -static inline struct tcp_timewait_sock *tcp_twsk(const struct sock *sk) -{ - return (struct tcp_timewait_sock *)sk; -} - -static inline bool tcp_passive_fastopen(const struct sock *sk) -{ - return (sk->sk_state == TCP_SYN_RECV && - tcp_sk(sk)->fastopen_rsk != NULL); -} - -static inline void fastopen_queue_tune(struct sock *sk, int backlog) -{ - struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue; - int somaxconn = READ_ONCE(sock_net(sk)->core.sysctl_somaxconn); - - queue->fastopenq.max_qlen = min_t(unsigned int, backlog, somaxconn); -} - -static inline void tcp_move_syn(struct tcp_sock *tp, - struct request_sock *req) -{ - tp->saved_syn = req->saved_syn; - req->saved_syn = NULL; -} - -static inline void tcp_saved_syn_free(struct tcp_sock *tp) -{ - kfree(tp->saved_syn); - tp->saved_syn = NULL; -} - -#endif /* _LINUX_TCP_H */ diff --git a/src/linux/include/linux/textsearch.h b/src/linux/include/linux/textsearch.h deleted file mode 100644 index cfaee86..0000000 --- a/src/linux/include/linux/textsearch.h +++ /dev/null @@ -1,178 +0,0 @@ -#ifndef __LINUX_TEXTSEARCH_H -#define __LINUX_TEXTSEARCH_H - -#include -#include -#include -#include -#include - -struct module; - -struct ts_config; - -#define TS_AUTOLOAD 1 /* Automatically load textsearch modules when needed */ -#define TS_IGNORECASE 2 /* Searches string case insensitively */ - -/** - * struct ts_state - search state - * @offset: offset for next match - * @cb: control buffer, for persistent variables of get_next_block() - */ -struct ts_state -{ - unsigned int offset; - char cb[40]; -}; - -/** - * struct ts_ops - search module operations - * @name: name of search algorithm - * @init: initialization function to prepare a search - * @find: find the next occurrence of the pattern - * @destroy: destroy algorithm specific parts of a search configuration - * @get_pattern: return head of pattern - * @get_pattern_len: return length of pattern - * @owner: module reference to algorithm - */ -struct ts_ops -{ - const char *name; - struct ts_config * (*init)(const void *, unsigned int, gfp_t, int); - unsigned int (*find)(struct ts_config *, - struct ts_state *); - void (*destroy)(struct ts_config *); - void * (*get_pattern)(struct ts_config *); - unsigned int (*get_pattern_len)(struct ts_config *); - struct module *owner; - struct list_head list; -}; - -/** - * struct ts_config - search configuration - * @ops: operations of chosen algorithm - * @flags: flags - * @get_next_block: callback to fetch the next block to search in - * @finish: callback to finalize a search - */ -struct ts_config -{ - struct ts_ops *ops; - int flags; - - /** - * get_next_block - fetch next block of data - * @consumed: number of bytes consumed by the caller - * @dst: destination buffer - * @conf: search configuration - * @state: search state - * - * Called repeatedly until 0 is returned. Must assign the - * head of the next block of data to &*dst and return the length - * of the block or 0 if at the end. consumed == 0 indicates - * a new search. May store/read persistent values in state->cb. - */ - unsigned int (*get_next_block)(unsigned int consumed, - const u8 **dst, - struct ts_config *conf, - struct ts_state *state); - - /** - * finish - finalize/clean a series of get_next_block() calls - * @conf: search configuration - * @state: search state - * - * Called after the last use of get_next_block(), may be used - * to cleanup any leftovers. - */ - void (*finish)(struct ts_config *conf, - struct ts_state *state); -}; - -/** - * textsearch_next - continue searching for a pattern - * @conf: search configuration - * @state: search state - * - * Continues a search looking for more occurrences of the pattern. - * textsearch_find() must be called to find the first occurrence - * in order to reset the state. - * - * Returns the position of the next occurrence of the pattern or - * UINT_MAX if not match was found. - */ -static inline unsigned int textsearch_next(struct ts_config *conf, - struct ts_state *state) -{ - unsigned int ret = conf->ops->find(conf, state); - - if (conf->finish) - conf->finish(conf, state); - - return ret; -} - -/** - * textsearch_find - start searching for a pattern - * @conf: search configuration - * @state: search state - * - * Returns the position of first occurrence of the pattern or - * UINT_MAX if no match was found. - */ -static inline unsigned int textsearch_find(struct ts_config *conf, - struct ts_state *state) -{ - state->offset = 0; - return textsearch_next(conf, state); -} - -/** - * textsearch_get_pattern - return head of the pattern - * @conf: search configuration - */ -static inline void *textsearch_get_pattern(struct ts_config *conf) -{ - return conf->ops->get_pattern(conf); -} - -/** - * textsearch_get_pattern_len - return length of the pattern - * @conf: search configuration - */ -static inline unsigned int textsearch_get_pattern_len(struct ts_config *conf) -{ - return conf->ops->get_pattern_len(conf); -} - -extern int textsearch_register(struct ts_ops *); -extern int textsearch_unregister(struct ts_ops *); -extern struct ts_config *textsearch_prepare(const char *, const void *, - unsigned int, gfp_t, int); -extern void textsearch_destroy(struct ts_config *conf); -extern unsigned int textsearch_find_continuous(struct ts_config *, - struct ts_state *, - const void *, unsigned int); - - -#define TS_PRIV_ALIGNTO 8 -#define TS_PRIV_ALIGN(len) (((len) + TS_PRIV_ALIGNTO-1) & ~(TS_PRIV_ALIGNTO-1)) - -static inline struct ts_config *alloc_ts_config(size_t payload, - gfp_t gfp_mask) -{ - struct ts_config *conf; - - conf = kzalloc(TS_PRIV_ALIGN(sizeof(*conf)) + payload, gfp_mask); - if (conf == NULL) - return ERR_PTR(-ENOMEM); - - return conf; -} - -static inline void *ts_config_priv(struct ts_config *conf) -{ - return ((u8 *) conf + TS_PRIV_ALIGN(sizeof(struct ts_config))); -} - -#endif diff --git a/src/linux/include/linux/thermal.h b/src/linux/include/linux/thermal.h deleted file mode 100644 index 511182a..0000000 --- a/src/linux/include/linux/thermal.h +++ /dev/null @@ -1,556 +0,0 @@ -/* - * thermal.h ($Revision: 0 $) - * - * Copyright (C) 2008 Intel Corp - * Copyright (C) 2008 Zhang Rui - * Copyright (C) 2008 Sujith Thomas - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - */ - -#ifndef __THERMAL_H__ -#define __THERMAL_H__ - -#include -#include -#include -#include -#include - -#define THERMAL_TRIPS_NONE -1 -#define THERMAL_MAX_TRIPS 12 - -/* invalid cooling state */ -#define THERMAL_CSTATE_INVALID -1UL - -/* No upper/lower limit requirement */ -#define THERMAL_NO_LIMIT ((u32)~0) - -/* Default weight of a bound cooling device */ -#define THERMAL_WEIGHT_DEFAULT 0 - -/* use value, which < 0K, to indicate an invalid/uninitialized temperature */ -#define THERMAL_TEMP_INVALID -274000 - -/* Unit conversion macros */ -#define DECI_KELVIN_TO_CELSIUS(t) ({ \ - long _t = (t); \ - ((_t-2732 >= 0) ? (_t-2732+5)/10 : (_t-2732-5)/10); \ -}) -#define CELSIUS_TO_DECI_KELVIN(t) ((t)*10+2732) -#define DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(t, off) (((t) - (off)) * 100) -#define DECI_KELVIN_TO_MILLICELSIUS(t) DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(t, 2732) -#define MILLICELSIUS_TO_DECI_KELVIN_WITH_OFFSET(t, off) (((t) / 100) + (off)) -#define MILLICELSIUS_TO_DECI_KELVIN(t) MILLICELSIUS_TO_DECI_KELVIN_WITH_OFFSET(t, 2732) - -/* Default Thermal Governor */ -#if defined(CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE) -#define DEFAULT_THERMAL_GOVERNOR "step_wise" -#elif defined(CONFIG_THERMAL_DEFAULT_GOV_FAIR_SHARE) -#define DEFAULT_THERMAL_GOVERNOR "fair_share" -#elif defined(CONFIG_THERMAL_DEFAULT_GOV_USER_SPACE) -#define DEFAULT_THERMAL_GOVERNOR "user_space" -#elif defined(CONFIG_THERMAL_DEFAULT_GOV_POWER_ALLOCATOR) -#define DEFAULT_THERMAL_GOVERNOR "power_allocator" -#endif - -struct thermal_zone_device; -struct thermal_cooling_device; -struct thermal_instance; - -enum thermal_device_mode { - THERMAL_DEVICE_DISABLED = 0, - THERMAL_DEVICE_ENABLED, -}; - -enum thermal_trip_type { - THERMAL_TRIP_ACTIVE = 0, - THERMAL_TRIP_PASSIVE, - THERMAL_TRIP_HOT, - THERMAL_TRIP_CRITICAL, -}; - -enum thermal_trend { - THERMAL_TREND_STABLE, /* temperature is stable */ - THERMAL_TREND_RAISING, /* temperature is raising */ - THERMAL_TREND_DROPPING, /* temperature is dropping */ - THERMAL_TREND_RAISE_FULL, /* apply highest cooling action */ - THERMAL_TREND_DROP_FULL, /* apply lowest cooling action */ -}; - -/* Thermal notification reason */ -enum thermal_notify_event { - THERMAL_EVENT_UNSPECIFIED, /* Unspecified event */ - THERMAL_EVENT_TEMP_SAMPLE, /* New Temperature sample */ - THERMAL_TRIP_VIOLATED, /* TRIP Point violation */ - THERMAL_TRIP_CHANGED, /* TRIP Point temperature changed */ - THERMAL_DEVICE_DOWN, /* Thermal device is down */ - THERMAL_DEVICE_UP, /* Thermal device is up after a down event */ - THERMAL_DEVICE_POWER_CAPABILITY_CHANGED, /* power capability changed */ -}; - -struct thermal_zone_device_ops { - int (*bind) (struct thermal_zone_device *, - struct thermal_cooling_device *); - int (*unbind) (struct thermal_zone_device *, - struct thermal_cooling_device *); - int (*get_temp) (struct thermal_zone_device *, int *); - int (*set_trips) (struct thermal_zone_device *, int, int); - int (*get_mode) (struct thermal_zone_device *, - enum thermal_device_mode *); - int (*set_mode) (struct thermal_zone_device *, - enum thermal_device_mode); - int (*get_trip_type) (struct thermal_zone_device *, int, - enum thermal_trip_type *); - int (*get_trip_temp) (struct thermal_zone_device *, int, int *); - int (*set_trip_temp) (struct thermal_zone_device *, int, int); - int (*get_trip_hyst) (struct thermal_zone_device *, int, int *); - int (*set_trip_hyst) (struct thermal_zone_device *, int, int); - int (*get_crit_temp) (struct thermal_zone_device *, int *); - int (*set_emul_temp) (struct thermal_zone_device *, int); - int (*get_trend) (struct thermal_zone_device *, int, - enum thermal_trend *); - int (*notify) (struct thermal_zone_device *, int, - enum thermal_trip_type); -}; - -struct thermal_cooling_device_ops { - int (*get_max_state) (struct thermal_cooling_device *, unsigned long *); - int (*get_cur_state) (struct thermal_cooling_device *, unsigned long *); - int (*set_cur_state) (struct thermal_cooling_device *, unsigned long); - int (*get_requested_power)(struct thermal_cooling_device *, - struct thermal_zone_device *, u32 *); - int (*state2power)(struct thermal_cooling_device *, - struct thermal_zone_device *, unsigned long, u32 *); - int (*power2state)(struct thermal_cooling_device *, - struct thermal_zone_device *, u32, unsigned long *); -}; - -struct thermal_cooling_device { - int id; - char type[THERMAL_NAME_LENGTH]; - struct device device; - struct device_node *np; - void *devdata; - const struct thermal_cooling_device_ops *ops; - bool updated; /* true if the cooling device does not need update */ - struct mutex lock; /* protect thermal_instances list */ - struct list_head thermal_instances; - struct list_head node; -}; - -struct thermal_attr { - struct device_attribute attr; - char name[THERMAL_NAME_LENGTH]; -}; - -/** - * struct thermal_zone_device - structure for a thermal zone - * @id: unique id number for each thermal zone - * @type: the thermal zone device type - * @device: &struct device for this thermal zone - * @trip_temp_attrs: attributes for trip points for sysfs: trip temperature - * @trip_type_attrs: attributes for trip points for sysfs: trip type - * @trip_hyst_attrs: attributes for trip points for sysfs: trip hysteresis - * @devdata: private pointer for device private data - * @trips: number of trip points the thermal zone supports - * @trips_disabled; bitmap for disabled trips - * @passive_delay: number of milliseconds to wait between polls when - * performing passive cooling. - * @polling_delay: number of milliseconds to wait between polls when - * checking whether trip points have been crossed (0 for - * interrupt driven systems) - * @temperature: current temperature. This is only for core code, - * drivers should use thermal_zone_get_temp() to get the - * current temperature - * @last_temperature: previous temperature read - * @emul_temperature: emulated temperature when using CONFIG_THERMAL_EMULATION - * @passive: 1 if you've crossed a passive trip point, 0 otherwise. - * @prev_low_trip: the low current temperature if you've crossed a passive - trip point. - * @prev_high_trip: the above current temperature if you've crossed a - passive trip point. - * @forced_passive: If > 0, temperature at which to switch on all ACPI - * processor cooling devices. Currently only used by the - * step-wise governor. - * @need_update: if equals 1, thermal_zone_device_update needs to be invoked. - * @ops: operations this &thermal_zone_device supports - * @tzp: thermal zone parameters - * @governor: pointer to the governor for this thermal zone - * @governor_data: private pointer for governor data - * @thermal_instances: list of &struct thermal_instance of this thermal zone - * @idr: &struct idr to generate unique id for this zone's cooling - * devices - * @lock: lock to protect thermal_instances list - * @node: node in thermal_tz_list (in thermal_core.c) - * @poll_queue: delayed work for polling - * @notify_event: Last notification event - */ -struct thermal_zone_device { - int id; - char type[THERMAL_NAME_LENGTH]; - struct device device; - struct thermal_attr *trip_temp_attrs; - struct thermal_attr *trip_type_attrs; - struct thermal_attr *trip_hyst_attrs; - void *devdata; - int trips; - unsigned long trips_disabled; /* bitmap for disabled trips */ - int passive_delay; - int polling_delay; - int temperature; - int last_temperature; - int emul_temperature; - int passive; - int prev_low_trip; - int prev_high_trip; - unsigned int forced_passive; - atomic_t need_update; - struct thermal_zone_device_ops *ops; - struct thermal_zone_params *tzp; - struct thermal_governor *governor; - void *governor_data; - struct list_head thermal_instances; - struct idr idr; - struct mutex lock; - struct list_head node; - struct delayed_work poll_queue; - enum thermal_notify_event notify_event; -}; - -/** - * struct thermal_governor - structure that holds thermal governor information - * @name: name of the governor - * @bind_to_tz: callback called when binding to a thermal zone. If it - * returns 0, the governor is bound to the thermal zone, - * otherwise it fails. - * @unbind_from_tz: callback called when a governor is unbound from a - * thermal zone. - * @throttle: callback called for every trip point even if temperature is - * below the trip point temperature - * @governor_list: node in thermal_governor_list (in thermal_core.c) - */ -struct thermal_governor { - char name[THERMAL_NAME_LENGTH]; - int (*bind_to_tz)(struct thermal_zone_device *tz); - void (*unbind_from_tz)(struct thermal_zone_device *tz); - int (*throttle)(struct thermal_zone_device *tz, int trip); - struct list_head governor_list; -}; - -/* Structure that holds binding parameters for a zone */ -struct thermal_bind_params { - struct thermal_cooling_device *cdev; - - /* - * This is a measure of 'how effectively these devices can - * cool 'this' thermal zone. It shall be determined by - * platform characterization. This value is relative to the - * rest of the weights so a cooling device whose weight is - * double that of another cooling device is twice as - * effective. See Documentation/thermal/sysfs-api.txt for more - * information. - */ - int weight; - - /* - * This is a bit mask that gives the binding relation between this - * thermal zone and cdev, for a particular trip point. - * See Documentation/thermal/sysfs-api.txt for more information. - */ - int trip_mask; - - /* - * This is an array of cooling state limits. Must have exactly - * 2 * thermal_zone.number_of_trip_points. It is an array consisting - * of tuples of state limits. Each trip - * will be associated with one state limit tuple when binding. - * A NULL pointer means - * on all trips. - */ - unsigned long *binding_limits; - int (*match) (struct thermal_zone_device *tz, - struct thermal_cooling_device *cdev); -}; - -/* Structure to define Thermal Zone parameters */ -struct thermal_zone_params { - char governor_name[THERMAL_NAME_LENGTH]; - - /* - * a boolean to indicate if the thermal to hwmon sysfs interface - * is required. when no_hwmon == false, a hwmon sysfs interface - * will be created. when no_hwmon == true, nothing will be done - */ - bool no_hwmon; - - int num_tbps; /* Number of tbp entries */ - struct thermal_bind_params *tbp; - - /* - * Sustainable power (heat) that this thermal zone can dissipate in - * mW - */ - u32 sustainable_power; - - /* - * Proportional parameter of the PID controller when - * overshooting (i.e., when temperature is below the target) - */ - s32 k_po; - - /* - * Proportional parameter of the PID controller when - * undershooting - */ - s32 k_pu; - - /* Integral parameter of the PID controller */ - s32 k_i; - - /* Derivative parameter of the PID controller */ - s32 k_d; - - /* threshold below which the error is no longer accumulated */ - s32 integral_cutoff; - - /* - * @slope: slope of a linear temperature adjustment curve. - * Used by thermal zone drivers. - */ - int slope; - /* - * @offset: offset of a linear temperature adjustment curve. - * Used by thermal zone drivers (default 0). - */ - int offset; -}; - -struct thermal_genl_event { - u32 orig; - enum events event; -}; - -/** - * struct thermal_zone_of_device_ops - scallbacks for handling DT based zones - * - * Mandatory: - * @get_temp: a pointer to a function that reads the sensor temperature. - * - * Optional: - * @get_trend: a pointer to a function that reads the sensor temperature trend. - * @set_trips: a pointer to a function that sets a temperature window. When - * this window is left the driver must inform the thermal core via - * thermal_zone_device_update. - * @set_emul_temp: a pointer to a function that sets sensor emulated - * temperature. - * @set_trip_temp: a pointer to a function that sets the trip temperature on - * hardware. - */ -struct thermal_zone_of_device_ops { - int (*get_temp)(void *, int *); - int (*get_trend)(void *, int, enum thermal_trend *); - int (*set_trips)(void *, int, int); - int (*set_emul_temp)(void *, int); - int (*set_trip_temp)(void *, int, int); -}; - -/** - * struct thermal_trip - representation of a point in temperature domain - * @np: pointer to struct device_node that this trip point was created from - * @temperature: temperature value in miliCelsius - * @hysteresis: relative hysteresis in miliCelsius - * @type: trip point type - */ - -struct thermal_trip { - struct device_node *np; - int temperature; - int hysteresis; - enum thermal_trip_type type; -}; - -/* Function declarations */ -#ifdef CONFIG_THERMAL_OF -struct thermal_zone_device * -thermal_zone_of_sensor_register(struct device *dev, int id, void *data, - const struct thermal_zone_of_device_ops *ops); -void thermal_zone_of_sensor_unregister(struct device *dev, - struct thermal_zone_device *tz); -struct thermal_zone_device *devm_thermal_zone_of_sensor_register( - struct device *dev, int id, void *data, - const struct thermal_zone_of_device_ops *ops); -void devm_thermal_zone_of_sensor_unregister(struct device *dev, - struct thermal_zone_device *tz); -#else -static inline struct thermal_zone_device * -thermal_zone_of_sensor_register(struct device *dev, int id, void *data, - const struct thermal_zone_of_device_ops *ops) -{ - return ERR_PTR(-ENODEV); -} - -static inline -void thermal_zone_of_sensor_unregister(struct device *dev, - struct thermal_zone_device *tz) -{ -} - -static inline struct thermal_zone_device *devm_thermal_zone_of_sensor_register( - struct device *dev, int id, void *data, - const struct thermal_zone_of_device_ops *ops) -{ - return ERR_PTR(-ENODEV); -} - -static inline -void devm_thermal_zone_of_sensor_unregister(struct device *dev, - struct thermal_zone_device *tz) -{ -} - -#endif - -#if IS_ENABLED(CONFIG_THERMAL) -static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev) -{ - return cdev->ops->get_requested_power && cdev->ops->state2power && - cdev->ops->power2state; -} - -int power_actor_get_max_power(struct thermal_cooling_device *, - struct thermal_zone_device *tz, u32 *max_power); -int power_actor_get_min_power(struct thermal_cooling_device *, - struct thermal_zone_device *tz, u32 *min_power); -int power_actor_set_power(struct thermal_cooling_device *, - struct thermal_instance *, u32); -struct thermal_zone_device *thermal_zone_device_register(const char *, int, int, - void *, struct thermal_zone_device_ops *, - struct thermal_zone_params *, int, int); -void thermal_zone_device_unregister(struct thermal_zone_device *); - -int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int, - struct thermal_cooling_device *, - unsigned long, unsigned long, - unsigned int); -int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int, - struct thermal_cooling_device *); -void thermal_zone_device_update(struct thermal_zone_device *, - enum thermal_notify_event); -void thermal_zone_set_trips(struct thermal_zone_device *); - -struct thermal_cooling_device *thermal_cooling_device_register(char *, void *, - const struct thermal_cooling_device_ops *); -struct thermal_cooling_device * -thermal_of_cooling_device_register(struct device_node *np, char *, void *, - const struct thermal_cooling_device_ops *); -void thermal_cooling_device_unregister(struct thermal_cooling_device *); -struct thermal_zone_device *thermal_zone_get_zone_by_name(const char *name); -int thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp); -int thermal_zone_get_slope(struct thermal_zone_device *tz); -int thermal_zone_get_offset(struct thermal_zone_device *tz); - -int get_tz_trend(struct thermal_zone_device *, int); -struct thermal_instance *get_thermal_instance(struct thermal_zone_device *, - struct thermal_cooling_device *, int); -void thermal_cdev_update(struct thermal_cooling_device *); -void thermal_notify_framework(struct thermal_zone_device *, int); -#else -static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev) -{ return false; } -static inline int power_actor_get_max_power(struct thermal_cooling_device *cdev, - struct thermal_zone_device *tz, u32 *max_power) -{ return 0; } -static inline int power_actor_get_min_power(struct thermal_cooling_device *cdev, - struct thermal_zone_device *tz, - u32 *min_power) -{ return -ENODEV; } -static inline int power_actor_set_power(struct thermal_cooling_device *cdev, - struct thermal_instance *tz, u32 power) -{ return 0; } -static inline struct thermal_zone_device *thermal_zone_device_register( - const char *type, int trips, int mask, void *devdata, - struct thermal_zone_device_ops *ops, - const struct thermal_zone_params *tzp, - int passive_delay, int polling_delay) -{ return ERR_PTR(-ENODEV); } -static inline void thermal_zone_device_unregister( - struct thermal_zone_device *tz) -{ } -static inline int thermal_zone_bind_cooling_device( - struct thermal_zone_device *tz, int trip, - struct thermal_cooling_device *cdev, - unsigned long upper, unsigned long lower, - unsigned int weight) -{ return -ENODEV; } -static inline int thermal_zone_unbind_cooling_device( - struct thermal_zone_device *tz, int trip, - struct thermal_cooling_device *cdev) -{ return -ENODEV; } -static inline void thermal_zone_device_update(struct thermal_zone_device *tz, - enum thermal_notify_event event) -{ } -static inline void thermal_zone_set_trips(struct thermal_zone_device *tz) -{ } -static inline struct thermal_cooling_device * -thermal_cooling_device_register(char *type, void *devdata, - const struct thermal_cooling_device_ops *ops) -{ return ERR_PTR(-ENODEV); } -static inline struct thermal_cooling_device * -thermal_of_cooling_device_register(struct device_node *np, - char *type, void *devdata, const struct thermal_cooling_device_ops *ops) -{ return ERR_PTR(-ENODEV); } -static inline void thermal_cooling_device_unregister( - struct thermal_cooling_device *cdev) -{ } -static inline struct thermal_zone_device *thermal_zone_get_zone_by_name( - const char *name) -{ return ERR_PTR(-ENODEV); } -static inline int thermal_zone_get_temp( - struct thermal_zone_device *tz, int *temp) -{ return -ENODEV; } -static inline int thermal_zone_get_slope( - struct thermal_zone_device *tz) -{ return -ENODEV; } -static inline int thermal_zone_get_offset( - struct thermal_zone_device *tz) -{ return -ENODEV; } -static inline int get_tz_trend(struct thermal_zone_device *tz, int trip) -{ return -ENODEV; } -static inline struct thermal_instance * -get_thermal_instance(struct thermal_zone_device *tz, - struct thermal_cooling_device *cdev, int trip) -{ return ERR_PTR(-ENODEV); } -static inline void thermal_cdev_update(struct thermal_cooling_device *cdev) -{ } -static inline void thermal_notify_framework(struct thermal_zone_device *tz, - int trip) -{ } -#endif /* CONFIG_THERMAL */ - -#if defined(CONFIG_NET) && IS_ENABLED(CONFIG_THERMAL) -extern int thermal_generate_netlink_event(struct thermal_zone_device *tz, - enum events event); -#else -static inline int thermal_generate_netlink_event(struct thermal_zone_device *tz, - enum events event) -{ - return 0; -} -#endif - -#endif /* __THERMAL_H__ */ diff --git a/src/linux/include/linux/thread_info.h b/src/linux/include/linux/thread_info.h deleted file mode 100644 index 2873baf..0000000 --- a/src/linux/include/linux/thread_info.h +++ /dev/null @@ -1,139 +0,0 @@ -/* thread_info.h: common low-level thread information accessors - * - * Copyright (C) 2002 David Howells (dhowells@redhat.com) - * - Incorporating suggestions made by Linus Torvalds - */ - -#ifndef _LINUX_THREAD_INFO_H -#define _LINUX_THREAD_INFO_H - -#include -#include - -struct timespec; -struct compat_timespec; - -#ifdef CONFIG_THREAD_INFO_IN_TASK -#define current_thread_info() ((struct thread_info *)current) -#endif - -/* - * System call restart block. - */ -struct restart_block { - long (*fn)(struct restart_block *); - union { - /* For futex_wait and futex_wait_requeue_pi */ - struct { - u32 __user *uaddr; - u32 val; - u32 flags; - u32 bitset; - u64 time; - u32 __user *uaddr2; - } futex; - /* For nanosleep */ - struct { - clockid_t clockid; - struct timespec __user *rmtp; -#ifdef CONFIG_COMPAT - struct compat_timespec __user *compat_rmtp; -#endif - u64 expires; - } nanosleep; - /* For poll */ - struct { - struct pollfd __user *ufds; - int nfds; - int has_timeout; - unsigned long tv_sec; - unsigned long tv_nsec; - } poll; - }; -}; - -extern long do_no_restart_syscall(struct restart_block *parm); - -#include -#include - -#ifdef __KERNEL__ - -#ifdef CONFIG_DEBUG_STACK_USAGE -# define THREADINFO_GFP (GFP_KERNEL_ACCOUNT | __GFP_NOTRACK | \ - __GFP_ZERO) -#else -# define THREADINFO_GFP (GFP_KERNEL_ACCOUNT | __GFP_NOTRACK) -#endif - -/* - * flag set/clear/test wrappers - * - pass TIF_xxxx constants to these functions - */ - -static inline void set_ti_thread_flag(struct thread_info *ti, int flag) -{ - set_bit(flag, (unsigned long *)&ti->flags); -} - -static inline void clear_ti_thread_flag(struct thread_info *ti, int flag) -{ - clear_bit(flag, (unsigned long *)&ti->flags); -} - -static inline int test_and_set_ti_thread_flag(struct thread_info *ti, int flag) -{ - return test_and_set_bit(flag, (unsigned long *)&ti->flags); -} - -static inline int test_and_clear_ti_thread_flag(struct thread_info *ti, int flag) -{ - return test_and_clear_bit(flag, (unsigned long *)&ti->flags); -} - -static inline int test_ti_thread_flag(struct thread_info *ti, int flag) -{ - return test_bit(flag, (unsigned long *)&ti->flags); -} - -#define set_thread_flag(flag) \ - set_ti_thread_flag(current_thread_info(), flag) -#define clear_thread_flag(flag) \ - clear_ti_thread_flag(current_thread_info(), flag) -#define test_and_set_thread_flag(flag) \ - test_and_set_ti_thread_flag(current_thread_info(), flag) -#define test_and_clear_thread_flag(flag) \ - test_and_clear_ti_thread_flag(current_thread_info(), flag) -#define test_thread_flag(flag) \ - test_ti_thread_flag(current_thread_info(), flag) - -#define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED) - -#ifndef CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES -static inline int arch_within_stack_frames(const void * const stack, - const void * const stackend, - const void *obj, unsigned long len) -{ - return 0; -} -#endif - -#ifdef CONFIG_HARDENED_USERCOPY -extern void __check_object_size(const void *ptr, unsigned long n, - bool to_user); - -static __always_inline void check_object_size(const void *ptr, unsigned long n, - bool to_user) -{ - if (!__builtin_constant_p(n)) - __check_object_size(ptr, n, to_user); -} -#else -static inline void check_object_size(const void *ptr, unsigned long n, - bool to_user) -{ } -#endif /* CONFIG_HARDENED_USERCOPY */ - -#endif /* __KERNEL__ */ - -#endif /* _LINUX_THREAD_INFO_H */ diff --git a/src/linux/include/linux/threads.h b/src/linux/include/linux/threads.h deleted file mode 100644 index 383ab95..0000000 --- a/src/linux/include/linux/threads.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _LINUX_THREADS_H -#define _LINUX_THREADS_H - - -/* - * The default limit for the nr of threads is now in - * /proc/sys/kernel/threads-max. - */ - -/* - * Maximum supported processors. Setting this smaller saves quite a - * bit of memory. Use nr_cpu_ids instead of this except for static bitmaps. - */ -#ifndef CONFIG_NR_CPUS -/* FIXME: This should be fixed in the arch's Kconfig */ -#define CONFIG_NR_CPUS 1 -#endif - -/* Places which use this should consider cpumask_var_t. */ -#define NR_CPUS CONFIG_NR_CPUS - -#define MIN_THREADS_LEFT_FOR_ROOT 4 - -/* - * This controls the default maximum pid allocated to a process - */ -#define PID_MAX_DEFAULT (CONFIG_BASE_SMALL ? 0x1000 : 0x8000) - -/* - * A maximum of 4 million PIDs should be enough for a while. - * [NOTE: PID/TIDs are limited to 2^29 ~= 500+ million, see futex.h.] - */ -#define PID_MAX_LIMIT (CONFIG_BASE_SMALL ? PAGE_SIZE * 8 : \ - (sizeof(long) > 4 ? 4 * 1024 * 1024 : PID_MAX_DEFAULT)) - -/* - * Define a minimum number of pids per cpu. Heuristically based - * on original pid max of 32k for 32 cpus. Also, increase the - * minimum settable value for pid_max on the running system based - * on similar defaults. See kernel/pid.c:pidmap_init() for details. - */ -#define PIDS_PER_CPU_DEFAULT 1024 -#define PIDS_PER_CPU_MIN 8 - -#endif diff --git a/src/linux/include/linux/tick.h b/src/linux/include/linux/tick.h deleted file mode 100644 index 62be078..0000000 --- a/src/linux/include/linux/tick.h +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Tick related global functions - */ -#ifndef _LINUX_TICK_H -#define _LINUX_TICK_H - -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_GENERIC_CLOCKEVENTS -extern void __init tick_init(void); -/* Should be core only, but ARM BL switcher requires it */ -extern void tick_suspend_local(void); -/* Should be core only, but XEN resume magic and ARM BL switcher require it */ -extern void tick_resume_local(void); -extern void tick_handover_do_timer(void); -extern void tick_cleanup_dead_cpu(int cpu); -#else /* CONFIG_GENERIC_CLOCKEVENTS */ -static inline void tick_init(void) { } -static inline void tick_suspend_local(void) { } -static inline void tick_resume_local(void) { } -static inline void tick_handover_do_timer(void) { } -static inline void tick_cleanup_dead_cpu(int cpu) { } -#endif /* !CONFIG_GENERIC_CLOCKEVENTS */ - -#if defined(CONFIG_GENERIC_CLOCKEVENTS) && defined(CONFIG_SUSPEND) -extern void tick_freeze(void); -extern void tick_unfreeze(void); -#else -static inline void tick_freeze(void) { } -static inline void tick_unfreeze(void) { } -#endif - -#ifdef CONFIG_TICK_ONESHOT -extern void tick_irq_enter(void); -# ifndef arch_needs_cpu -# define arch_needs_cpu() (0) -# endif -# else -static inline void tick_irq_enter(void) { } -#endif - -#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_TICK_ONESHOT) -extern void hotplug_cpu__broadcast_tick_pull(int dead_cpu); -#else -static inline void hotplug_cpu__broadcast_tick_pull(int dead_cpu) { } -#endif - -enum tick_broadcast_mode { - TICK_BROADCAST_OFF, - TICK_BROADCAST_ON, - TICK_BROADCAST_FORCE, -}; - -enum tick_broadcast_state { - TICK_BROADCAST_EXIT, - TICK_BROADCAST_ENTER, -}; - -#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST -extern void tick_broadcast_control(enum tick_broadcast_mode mode); -#else -static inline void tick_broadcast_control(enum tick_broadcast_mode mode) { } -#endif /* BROADCAST */ - -#ifdef CONFIG_GENERIC_CLOCKEVENTS -extern int tick_broadcast_oneshot_control(enum tick_broadcast_state state); -#else -static inline int tick_broadcast_oneshot_control(enum tick_broadcast_state state) -{ - return 0; -} -#endif - -static inline void tick_broadcast_enable(void) -{ - tick_broadcast_control(TICK_BROADCAST_ON); -} -static inline void tick_broadcast_disable(void) -{ - tick_broadcast_control(TICK_BROADCAST_OFF); -} -static inline void tick_broadcast_force(void) -{ - tick_broadcast_control(TICK_BROADCAST_FORCE); -} -static inline int tick_broadcast_enter(void) -{ - return tick_broadcast_oneshot_control(TICK_BROADCAST_ENTER); -} -static inline void tick_broadcast_exit(void) -{ - tick_broadcast_oneshot_control(TICK_BROADCAST_EXIT); -} - -enum tick_dep_bits { - TICK_DEP_BIT_POSIX_TIMER = 0, - TICK_DEP_BIT_PERF_EVENTS = 1, - TICK_DEP_BIT_SCHED = 2, - TICK_DEP_BIT_CLOCK_UNSTABLE = 3 -}; - -#define TICK_DEP_MASK_NONE 0 -#define TICK_DEP_MASK_POSIX_TIMER (1 << TICK_DEP_BIT_POSIX_TIMER) -#define TICK_DEP_MASK_PERF_EVENTS (1 << TICK_DEP_BIT_PERF_EVENTS) -#define TICK_DEP_MASK_SCHED (1 << TICK_DEP_BIT_SCHED) -#define TICK_DEP_MASK_CLOCK_UNSTABLE (1 << TICK_DEP_BIT_CLOCK_UNSTABLE) - -#ifdef CONFIG_NO_HZ_COMMON -extern bool tick_nohz_enabled; -extern int tick_nohz_tick_stopped(void); -extern void tick_nohz_idle_enter(void); -extern void tick_nohz_idle_exit(void); -extern void tick_nohz_irq_exit(void); -extern ktime_t tick_nohz_get_sleep_length(void); -extern u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time); -extern u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time); -#else /* !CONFIG_NO_HZ_COMMON */ -#define tick_nohz_enabled (0) -static inline int tick_nohz_tick_stopped(void) { return 0; } -static inline void tick_nohz_idle_enter(void) { } -static inline void tick_nohz_idle_exit(void) { } - -static inline ktime_t tick_nohz_get_sleep_length(void) -{ - ktime_t len = { .tv64 = NSEC_PER_SEC/HZ }; - - return len; -} -static inline u64 get_cpu_idle_time_us(int cpu, u64 *unused) { return -1; } -static inline u64 get_cpu_iowait_time_us(int cpu, u64 *unused) { return -1; } -#endif /* !CONFIG_NO_HZ_COMMON */ - -#ifdef CONFIG_NO_HZ_FULL -extern bool tick_nohz_full_running; -extern cpumask_var_t tick_nohz_full_mask; -extern cpumask_var_t housekeeping_mask; - -static inline bool tick_nohz_full_enabled(void) -{ - if (!context_tracking_is_enabled()) - return false; - - return tick_nohz_full_running; -} - -static inline bool tick_nohz_full_cpu(int cpu) -{ - if (!tick_nohz_full_enabled()) - return false; - - return cpumask_test_cpu(cpu, tick_nohz_full_mask); -} - -static inline void tick_nohz_full_add_cpus_to(struct cpumask *mask) -{ - if (tick_nohz_full_enabled()) - cpumask_or(mask, mask, tick_nohz_full_mask); -} - -static inline int housekeeping_any_cpu(void) -{ - return cpumask_any_and(housekeeping_mask, cpu_online_mask); -} - -extern void tick_nohz_dep_set(enum tick_dep_bits bit); -extern void tick_nohz_dep_clear(enum tick_dep_bits bit); -extern void tick_nohz_dep_set_cpu(int cpu, enum tick_dep_bits bit); -extern void tick_nohz_dep_clear_cpu(int cpu, enum tick_dep_bits bit); -extern void tick_nohz_dep_set_task(struct task_struct *tsk, - enum tick_dep_bits bit); -extern void tick_nohz_dep_clear_task(struct task_struct *tsk, - enum tick_dep_bits bit); -extern void tick_nohz_dep_set_signal(struct signal_struct *signal, - enum tick_dep_bits bit); -extern void tick_nohz_dep_clear_signal(struct signal_struct *signal, - enum tick_dep_bits bit); - -/* - * The below are tick_nohz_[set,clear]_dep() wrappers that optimize off-cases - * on top of static keys. - */ -static inline void tick_dep_set(enum tick_dep_bits bit) -{ - if (tick_nohz_full_enabled()) - tick_nohz_dep_set(bit); -} - -static inline void tick_dep_clear(enum tick_dep_bits bit) -{ - if (tick_nohz_full_enabled()) - tick_nohz_dep_clear(bit); -} - -static inline void tick_dep_set_cpu(int cpu, enum tick_dep_bits bit) -{ - if (tick_nohz_full_cpu(cpu)) - tick_nohz_dep_set_cpu(cpu, bit); -} - -static inline void tick_dep_clear_cpu(int cpu, enum tick_dep_bits bit) -{ - if (tick_nohz_full_cpu(cpu)) - tick_nohz_dep_clear_cpu(cpu, bit); -} - -static inline void tick_dep_set_task(struct task_struct *tsk, - enum tick_dep_bits bit) -{ - if (tick_nohz_full_enabled()) - tick_nohz_dep_set_task(tsk, bit); -} -static inline void tick_dep_clear_task(struct task_struct *tsk, - enum tick_dep_bits bit) -{ - if (tick_nohz_full_enabled()) - tick_nohz_dep_clear_task(tsk, bit); -} -static inline void tick_dep_set_signal(struct signal_struct *signal, - enum tick_dep_bits bit) -{ - if (tick_nohz_full_enabled()) - tick_nohz_dep_set_signal(signal, bit); -} -static inline void tick_dep_clear_signal(struct signal_struct *signal, - enum tick_dep_bits bit) -{ - if (tick_nohz_full_enabled()) - tick_nohz_dep_clear_signal(signal, bit); -} - -extern void tick_nohz_full_kick_cpu(int cpu); -extern void __tick_nohz_task_switch(void); -#else -static inline int housekeeping_any_cpu(void) -{ - return smp_processor_id(); -} -static inline bool tick_nohz_full_enabled(void) { return false; } -static inline bool tick_nohz_full_cpu(int cpu) { return false; } -static inline void tick_nohz_full_add_cpus_to(struct cpumask *mask) { } - -static inline void tick_dep_set(enum tick_dep_bits bit) { } -static inline void tick_dep_clear(enum tick_dep_bits bit) { } -static inline void tick_dep_set_cpu(int cpu, enum tick_dep_bits bit) { } -static inline void tick_dep_clear_cpu(int cpu, enum tick_dep_bits bit) { } -static inline void tick_dep_set_task(struct task_struct *tsk, - enum tick_dep_bits bit) { } -static inline void tick_dep_clear_task(struct task_struct *tsk, - enum tick_dep_bits bit) { } -static inline void tick_dep_set_signal(struct signal_struct *signal, - enum tick_dep_bits bit) { } -static inline void tick_dep_clear_signal(struct signal_struct *signal, - enum tick_dep_bits bit) { } - -static inline void tick_nohz_full_kick_cpu(int cpu) { } -static inline void __tick_nohz_task_switch(void) { } -#endif - -static inline const struct cpumask *housekeeping_cpumask(void) -{ -#ifdef CONFIG_NO_HZ_FULL - if (tick_nohz_full_enabled()) - return housekeeping_mask; -#endif - return cpu_possible_mask; -} - -static inline bool is_housekeeping_cpu(int cpu) -{ -#ifdef CONFIG_NO_HZ_FULL - if (tick_nohz_full_enabled()) - return cpumask_test_cpu(cpu, housekeeping_mask); -#endif - return true; -} - -static inline void housekeeping_affine(struct task_struct *t) -{ -#ifdef CONFIG_NO_HZ_FULL - if (tick_nohz_full_enabled()) - set_cpus_allowed_ptr(t, housekeeping_mask); - -#endif -} - -static inline void tick_nohz_task_switch(void) -{ - if (tick_nohz_full_enabled()) - __tick_nohz_task_switch(); -} - -#endif diff --git a/src/linux/include/linux/time.h b/src/linux/include/linux/time.h deleted file mode 100644 index 4cea09d..0000000 --- a/src/linux/include/linux/time.h +++ /dev/null @@ -1,278 +0,0 @@ -#ifndef _LINUX_TIME_H -#define _LINUX_TIME_H - -# include -# include -# include -# include - -extern struct timezone sys_tz; - -#define TIME_T_MAX (time_t)((1UL << ((sizeof(time_t) << 3) - 1)) - 1) - -static inline int timespec_equal(const struct timespec *a, - const struct timespec *b) -{ - return (a->tv_sec == b->tv_sec) && (a->tv_nsec == b->tv_nsec); -} - -/* - * lhs < rhs: return <0 - * lhs == rhs: return 0 - * lhs > rhs: return >0 - */ -static inline int timespec_compare(const struct timespec *lhs, const struct timespec *rhs) -{ - if (lhs->tv_sec < rhs->tv_sec) - return -1; - if (lhs->tv_sec > rhs->tv_sec) - return 1; - return lhs->tv_nsec - rhs->tv_nsec; -} - -static inline int timeval_compare(const struct timeval *lhs, const struct timeval *rhs) -{ - if (lhs->tv_sec < rhs->tv_sec) - return -1; - if (lhs->tv_sec > rhs->tv_sec) - return 1; - return lhs->tv_usec - rhs->tv_usec; -} - -extern time64_t mktime64(const unsigned int year, const unsigned int mon, - const unsigned int day, const unsigned int hour, - const unsigned int min, const unsigned int sec); - -/** - * Deprecated. Use mktime64(). - */ -static inline unsigned long mktime(const unsigned int year, - const unsigned int mon, const unsigned int day, - const unsigned int hour, const unsigned int min, - const unsigned int sec) -{ - return mktime64(year, mon, day, hour, min, sec); -} - -extern void set_normalized_timespec(struct timespec *ts, time_t sec, s64 nsec); - -/* - * timespec_add_safe assumes both values are positive and checks - * for overflow. It will return TIME_T_MAX if the reutrn would be - * smaller then either of the arguments. - */ -extern struct timespec timespec_add_safe(const struct timespec lhs, - const struct timespec rhs); - - -static inline struct timespec timespec_add(struct timespec lhs, - struct timespec rhs) -{ - struct timespec ts_delta; - set_normalized_timespec(&ts_delta, lhs.tv_sec + rhs.tv_sec, - lhs.tv_nsec + rhs.tv_nsec); - return ts_delta; -} - -/* - * sub = lhs - rhs, in normalized form - */ -static inline struct timespec timespec_sub(struct timespec lhs, - struct timespec rhs) -{ - struct timespec ts_delta; - set_normalized_timespec(&ts_delta, lhs.tv_sec - rhs.tv_sec, - lhs.tv_nsec - rhs.tv_nsec); - return ts_delta; -} - -/* - * Returns true if the timespec is norm, false if denorm: - */ -static inline bool timespec_valid(const struct timespec *ts) -{ - /* Dates before 1970 are bogus */ - if (ts->tv_sec < 0) - return false; - /* Can't have more nanoseconds then a second */ - if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) - return false; - return true; -} - -static inline bool timespec_valid_strict(const struct timespec *ts) -{ - if (!timespec_valid(ts)) - return false; - /* Disallow values that could overflow ktime_t */ - if ((unsigned long long)ts->tv_sec >= KTIME_SEC_MAX) - return false; - return true; -} - -static inline bool timeval_valid(const struct timeval *tv) -{ - /* Dates before 1970 are bogus */ - if (tv->tv_sec < 0) - return false; - - /* Can't have more microseconds then a second */ - if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC) - return false; - - return true; -} - -extern struct timespec timespec_trunc(struct timespec t, unsigned gran); - -/* - * Validates if a timespec/timeval used to inject a time offset is valid. - * Offsets can be postive or negative. The value of the timeval/timespec - * is the sum of its fields, but *NOTE*: the field tv_usec/tv_nsec must - * always be non-negative. - */ -static inline bool timeval_inject_offset_valid(const struct timeval *tv) -{ - /* We don't check the tv_sec as it can be positive or negative */ - - /* Can't have more microseconds then a second */ - if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC) - return false; - return true; -} - -static inline bool timespec_inject_offset_valid(const struct timespec *ts) -{ - /* We don't check the tv_sec as it can be positive or negative */ - - /* Can't have more nanoseconds then a second */ - if (ts->tv_nsec < 0 || ts->tv_nsec >= NSEC_PER_SEC) - return false; - return true; -} - -#define CURRENT_TIME (current_kernel_time()) -#define CURRENT_TIME_SEC ((struct timespec) { get_seconds(), 0 }) - -/* Some architectures do not supply their own clocksource. - * This is mainly the case in architectures that get their - * inter-tick times by reading the counter on their interval - * timer. Since these timers wrap every tick, they're not really - * useful as clocksources. Wrapping them to act like one is possible - * but not very efficient. So we provide a callout these arches - * can implement for use with the jiffies clocksource to provide - * finer then tick granular time. - */ -#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET -extern u32 (*arch_gettimeoffset)(void); -#endif - -struct itimerval; -extern int do_setitimer(int which, struct itimerval *value, - struct itimerval *ovalue); -extern int do_getitimer(int which, struct itimerval *value); - -extern unsigned int alarm_setitimer(unsigned int seconds); - -extern long do_utimes(int dfd, const char __user *filename, struct timespec *times, int flags); - -struct tms; -extern void do_sys_times(struct tms *); - -/* - * Similar to the struct tm in userspace , but it needs to be here so - * that the kernel source is self contained. - */ -struct tm { - /* - * the number of seconds after the minute, normally in the range - * 0 to 59, but can be up to 60 to allow for leap seconds - */ - int tm_sec; - /* the number of minutes after the hour, in the range 0 to 59*/ - int tm_min; - /* the number of hours past midnight, in the range 0 to 23 */ - int tm_hour; - /* the day of the month, in the range 1 to 31 */ - int tm_mday; - /* the number of months since January, in the range 0 to 11 */ - int tm_mon; - /* the number of years since 1900 */ - long tm_year; - /* the number of days since Sunday, in the range 0 to 6 */ - int tm_wday; - /* the number of days since January 1, in the range 0 to 365 */ - int tm_yday; -}; - -void time64_to_tm(time64_t totalsecs, int offset, struct tm *result); - -/** - * time_to_tm - converts the calendar time to local broken-down time - * - * @totalsecs the number of seconds elapsed since 00:00:00 on January 1, 1970, - * Coordinated Universal Time (UTC). - * @offset offset seconds adding to totalsecs. - * @result pointer to struct tm variable to receive broken-down time - */ -static inline void time_to_tm(time_t totalsecs, int offset, struct tm *result) -{ - time64_to_tm(totalsecs, offset, result); -} - -/** - * timespec_to_ns - Convert timespec to nanoseconds - * @ts: pointer to the timespec variable to be converted - * - * Returns the scalar nanosecond representation of the timespec - * parameter. - */ -static inline s64 timespec_to_ns(const struct timespec *ts) -{ - return ((s64) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec; -} - -/** - * timeval_to_ns - Convert timeval to nanoseconds - * @ts: pointer to the timeval variable to be converted - * - * Returns the scalar nanosecond representation of the timeval - * parameter. - */ -static inline s64 timeval_to_ns(const struct timeval *tv) -{ - return ((s64) tv->tv_sec * NSEC_PER_SEC) + - tv->tv_usec * NSEC_PER_USEC; -} - -/** - * ns_to_timespec - Convert nanoseconds to timespec - * @nsec: the nanoseconds value to be converted - * - * Returns the timespec representation of the nsec parameter. - */ -extern struct timespec ns_to_timespec(const s64 nsec); - -/** - * ns_to_timeval - Convert nanoseconds to timeval - * @nsec: the nanoseconds value to be converted - * - * Returns the timeval representation of the nsec parameter. - */ -extern struct timeval ns_to_timeval(const s64 nsec); - -/** - * timespec_add_ns - Adds nanoseconds to a timespec - * @a: pointer to timespec to be incremented - * @ns: unsigned nanoseconds value to be added - * - * This must always be inlined because its used from the x86-64 vdso, - * which cannot call other kernel functions. - */ -static __always_inline void timespec_add_ns(struct timespec *a, u64 ns) -{ - a->tv_sec += __iter_div_u64_rem(a->tv_nsec + ns, NSEC_PER_SEC, &ns); - a->tv_nsec = ns; -} - -#endif diff --git a/src/linux/include/linux/time64.h b/src/linux/include/linux/time64.h deleted file mode 100644 index 980c71b..0000000 --- a/src/linux/include/linux/time64.h +++ /dev/null @@ -1,225 +0,0 @@ -#ifndef _LINUX_TIME64_H -#define _LINUX_TIME64_H - -#include -#include - -typedef __s64 time64_t; -typedef __u64 timeu64_t; - -/* - * This wants to go into uapi/linux/time.h once we agreed about the - * userspace interfaces. - */ -#if __BITS_PER_LONG == 64 -# define timespec64 timespec -#define itimerspec64 itimerspec -#else -struct timespec64 { - time64_t tv_sec; /* seconds */ - long tv_nsec; /* nanoseconds */ -}; - -struct itimerspec64 { - struct timespec64 it_interval; - struct timespec64 it_value; -}; - -#endif - -/* Parameters used to convert the timespec values: */ -#define MSEC_PER_SEC 1000L -#define USEC_PER_MSEC 1000L -#define NSEC_PER_USEC 1000L -#define NSEC_PER_MSEC 1000000L -#define USEC_PER_SEC 1000000L -#define NSEC_PER_SEC 1000000000L -#define FSEC_PER_SEC 1000000000000000LL - -/* Located here for timespec[64]_valid_strict */ -#define TIME64_MAX ((s64)~((u64)1 << 63)) -#define KTIME_MAX ((s64)~((u64)1 << 63)) -#define KTIME_SEC_MAX (KTIME_MAX / NSEC_PER_SEC) - -#if __BITS_PER_LONG == 64 - -static inline struct timespec timespec64_to_timespec(const struct timespec64 ts64) -{ - return ts64; -} - -static inline struct timespec64 timespec_to_timespec64(const struct timespec ts) -{ - return ts; -} - -static inline struct itimerspec itimerspec64_to_itimerspec(struct itimerspec64 *its64) -{ - return *its64; -} - -static inline struct itimerspec64 itimerspec_to_itimerspec64(struct itimerspec *its) -{ - return *its; -} - -# define timespec64_equal timespec_equal -# define timespec64_compare timespec_compare -# define set_normalized_timespec64 set_normalized_timespec -# define timespec64_add timespec_add -# define timespec64_sub timespec_sub -# define timespec64_valid timespec_valid -# define timespec64_valid_strict timespec_valid_strict -# define timespec64_to_ns timespec_to_ns -# define ns_to_timespec64 ns_to_timespec -# define timespec64_add_ns timespec_add_ns - -#else - -static inline struct timespec timespec64_to_timespec(const struct timespec64 ts64) -{ - struct timespec ret; - - ret.tv_sec = (time_t)ts64.tv_sec; - ret.tv_nsec = ts64.tv_nsec; - return ret; -} - -static inline struct timespec64 timespec_to_timespec64(const struct timespec ts) -{ - struct timespec64 ret; - - ret.tv_sec = ts.tv_sec; - ret.tv_nsec = ts.tv_nsec; - return ret; -} - -static inline struct itimerspec itimerspec64_to_itimerspec(struct itimerspec64 *its64) -{ - struct itimerspec ret; - - ret.it_interval = timespec64_to_timespec(its64->it_interval); - ret.it_value = timespec64_to_timespec(its64->it_value); - return ret; -} - -static inline struct itimerspec64 itimerspec_to_itimerspec64(struct itimerspec *its) -{ - struct itimerspec64 ret; - - ret.it_interval = timespec_to_timespec64(its->it_interval); - ret.it_value = timespec_to_timespec64(its->it_value); - return ret; -} - -static inline int timespec64_equal(const struct timespec64 *a, - const struct timespec64 *b) -{ - return (a->tv_sec == b->tv_sec) && (a->tv_nsec == b->tv_nsec); -} - -/* - * lhs < rhs: return <0 - * lhs == rhs: return 0 - * lhs > rhs: return >0 - */ -static inline int timespec64_compare(const struct timespec64 *lhs, const struct timespec64 *rhs) -{ - if (lhs->tv_sec < rhs->tv_sec) - return -1; - if (lhs->tv_sec > rhs->tv_sec) - return 1; - return lhs->tv_nsec - rhs->tv_nsec; -} - -extern void set_normalized_timespec64(struct timespec64 *ts, time64_t sec, s64 nsec); - -static inline struct timespec64 timespec64_add(struct timespec64 lhs, - struct timespec64 rhs) -{ - struct timespec64 ts_delta; - set_normalized_timespec64(&ts_delta, lhs.tv_sec + rhs.tv_sec, - lhs.tv_nsec + rhs.tv_nsec); - return ts_delta; -} - -/* - * sub = lhs - rhs, in normalized form - */ -static inline struct timespec64 timespec64_sub(struct timespec64 lhs, - struct timespec64 rhs) -{ - struct timespec64 ts_delta; - set_normalized_timespec64(&ts_delta, lhs.tv_sec - rhs.tv_sec, - lhs.tv_nsec - rhs.tv_nsec); - return ts_delta; -} - -/* - * Returns true if the timespec64 is norm, false if denorm: - */ -static inline bool timespec64_valid(const struct timespec64 *ts) -{ - /* Dates before 1970 are bogus */ - if (ts->tv_sec < 0) - return false; - /* Can't have more nanoseconds then a second */ - if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC) - return false; - return true; -} - -static inline bool timespec64_valid_strict(const struct timespec64 *ts) -{ - if (!timespec64_valid(ts)) - return false; - /* Disallow values that could overflow ktime_t */ - if ((unsigned long long)ts->tv_sec >= KTIME_SEC_MAX) - return false; - return true; -} - -/** - * timespec64_to_ns - Convert timespec64 to nanoseconds - * @ts: pointer to the timespec64 variable to be converted - * - * Returns the scalar nanosecond representation of the timespec64 - * parameter. - */ -static inline s64 timespec64_to_ns(const struct timespec64 *ts) -{ - return ((s64) ts->tv_sec * NSEC_PER_SEC) + ts->tv_nsec; -} - -/** - * ns_to_timespec64 - Convert nanoseconds to timespec64 - * @nsec: the nanoseconds value to be converted - * - * Returns the timespec64 representation of the nsec parameter. - */ -extern struct timespec64 ns_to_timespec64(const s64 nsec); - -/** - * timespec64_add_ns - Adds nanoseconds to a timespec64 - * @a: pointer to timespec64 to be incremented - * @ns: unsigned nanoseconds value to be added - * - * This must always be inlined because its used from the x86-64 vdso, - * which cannot call other kernel functions. - */ -static __always_inline void timespec64_add_ns(struct timespec64 *a, u64 ns) -{ - a->tv_sec += __iter_div_u64_rem(a->tv_nsec + ns, NSEC_PER_SEC, &ns); - a->tv_nsec = ns; -} - -#endif - -/* - * timespec64_add_safe assumes both values are positive and checks for - * overflow. It will return TIME64_MAX in case of overflow. - */ -extern struct timespec64 timespec64_add_safe(const struct timespec64 lhs, - const struct timespec64 rhs); - -#endif /* _LINUX_TIME64_H */ diff --git a/src/linux/include/linux/timecounter.h b/src/linux/include/linux/timecounter.h deleted file mode 100644 index 4382035..0000000 --- a/src/linux/include/linux/timecounter.h +++ /dev/null @@ -1,139 +0,0 @@ -/* - * linux/include/linux/timecounter.h - * - * based on code that migrated away from - * linux/include/linux/clocksource.h - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef _LINUX_TIMECOUNTER_H -#define _LINUX_TIMECOUNTER_H - -#include - -/* simplify initialization of mask field */ -#define CYCLECOUNTER_MASK(bits) (cycle_t)((bits) < 64 ? ((1ULL<<(bits))-1) : -1) - -/** - * struct cyclecounter - hardware abstraction for a free running counter - * Provides completely state-free accessors to the underlying hardware. - * Depending on which hardware it reads, the cycle counter may wrap - * around quickly. Locking rules (if necessary) have to be defined - * by the implementor and user of specific instances of this API. - * - * @read: returns the current cycle value - * @mask: bitmask for two's complement - * subtraction of non 64 bit counters, - * see CYCLECOUNTER_MASK() helper macro - * @mult: cycle to nanosecond multiplier - * @shift: cycle to nanosecond divisor (power of two) - */ -struct cyclecounter { - cycle_t (*read)(const struct cyclecounter *cc); - cycle_t mask; - u32 mult; - u32 shift; -}; - -/** - * struct timecounter - layer above a %struct cyclecounter which counts nanoseconds - * Contains the state needed by timecounter_read() to detect - * cycle counter wrap around. Initialize with - * timecounter_init(). Also used to convert cycle counts into the - * corresponding nanosecond counts with timecounter_cyc2time(). Users - * of this code are responsible for initializing the underlying - * cycle counter hardware, locking issues and reading the time - * more often than the cycle counter wraps around. The nanosecond - * counter will only wrap around after ~585 years. - * - * @cc: the cycle counter used by this instance - * @cycle_last: most recent cycle counter value seen by - * timecounter_read() - * @nsec: continuously increasing count - * @mask: bit mask for maintaining the 'frac' field - * @frac: accumulated fractional nanoseconds - */ -struct timecounter { - const struct cyclecounter *cc; - cycle_t cycle_last; - u64 nsec; - u64 mask; - u64 frac; -}; - -/** - * cyclecounter_cyc2ns - converts cycle counter cycles to nanoseconds - * @cc: Pointer to cycle counter. - * @cycles: Cycles - * @mask: bit mask for maintaining the 'frac' field - * @frac: pointer to storage for the fractional nanoseconds. - */ -static inline u64 cyclecounter_cyc2ns(const struct cyclecounter *cc, - cycle_t cycles, u64 mask, u64 *frac) -{ - u64 ns = (u64) cycles; - - ns = (ns * cc->mult) + *frac; - *frac = ns & mask; - return ns >> cc->shift; -} - -/** - * timecounter_adjtime - Shifts the time of the clock. - * @delta: Desired change in nanoseconds. - */ -static inline void timecounter_adjtime(struct timecounter *tc, s64 delta) -{ - tc->nsec += delta; -} - -/** - * timecounter_init - initialize a time counter - * @tc: Pointer to time counter which is to be initialized/reset - * @cc: A cycle counter, ready to be used. - * @start_tstamp: Arbitrary initial time stamp. - * - * After this call the current cycle register (roughly) corresponds to - * the initial time stamp. Every call to timecounter_read() increments - * the time stamp counter by the number of elapsed nanoseconds. - */ -extern void timecounter_init(struct timecounter *tc, - const struct cyclecounter *cc, - u64 start_tstamp); - -/** - * timecounter_read - return nanoseconds elapsed since timecounter_init() - * plus the initial time stamp - * @tc: Pointer to time counter. - * - * In other words, keeps track of time since the same epoch as - * the function which generated the initial time stamp. - */ -extern u64 timecounter_read(struct timecounter *tc); - -/** - * timecounter_cyc2time - convert a cycle counter to same - * time base as values returned by - * timecounter_read() - * @tc: Pointer to time counter. - * @cycle_tstamp: a value returned by tc->cc->read() - * - * Cycle counts that are converted correctly as long as they - * fall into the interval [-1/2 max cycle count, +1/2 max cycle count], - * with "max cycle count" == cs->mask+1. - * - * This allows conversion of cycle counter values which were generated - * in the past. - */ -extern u64 timecounter_cyc2time(struct timecounter *tc, - cycle_t cycle_tstamp); - -#endif diff --git a/src/linux/include/linux/timekeeper_internal.h b/src/linux/include/linux/timekeeper_internal.h deleted file mode 100644 index e880054..0000000 --- a/src/linux/include/linux/timekeeper_internal.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * You SHOULD NOT be including this unless you're vsyscall - * handling code or timekeeping internal code! - */ - -#ifndef _LINUX_TIMEKEEPER_INTERNAL_H -#define _LINUX_TIMEKEEPER_INTERNAL_H - -#include -#include -#include - -/** - * struct tk_read_base - base structure for timekeeping readout - * @clock: Current clocksource used for timekeeping. - * @read: Read function of @clock - * @mask: Bitmask for two's complement subtraction of non 64bit clocks - * @cycle_last: @clock cycle value at last update - * @mult: (NTP adjusted) multiplier for scaled math conversion - * @shift: Shift value for scaled math conversion - * @xtime_nsec: Shifted (fractional) nano seconds offset for readout - * @base: ktime_t (nanoseconds) base time for readout - * - * This struct has size 56 byte on 64 bit. Together with a seqcount it - * occupies a single 64byte cache line. - * - * The struct is separate from struct timekeeper as it is also used - * for a fast NMI safe accessors. - */ -struct tk_read_base { - struct clocksource *clock; - cycle_t (*read)(struct clocksource *cs); - cycle_t mask; - cycle_t cycle_last; - u32 mult; - u32 shift; - u64 xtime_nsec; - ktime_t base; -}; - -/** - * struct timekeeper - Structure holding internal timekeeping values. - * @tkr_mono: The readout base structure for CLOCK_MONOTONIC - * @tkr_raw: The readout base structure for CLOCK_MONOTONIC_RAW - * @xtime_sec: Current CLOCK_REALTIME time in seconds - * @ktime_sec: Current CLOCK_MONOTONIC time in seconds - * @wall_to_monotonic: CLOCK_REALTIME to CLOCK_MONOTONIC offset - * @offs_real: Offset clock monotonic -> clock realtime - * @offs_boot: Offset clock monotonic -> clock boottime - * @offs_tai: Offset clock monotonic -> clock tai - * @tai_offset: The current UTC to TAI offset in seconds - * @clock_was_set_seq: The sequence number of clock was set events - * @cs_was_changed_seq: The sequence number of clocksource change events - * @next_leap_ktime: CLOCK_MONOTONIC time value of a pending leap-second - * @raw_time: Monotonic raw base time in timespec64 format - * @cycle_interval: Number of clock cycles in one NTP interval - * @xtime_interval: Number of clock shifted nano seconds in one NTP - * interval. - * @xtime_remainder: Shifted nano seconds left over when rounding - * @cycle_interval - * @raw_interval: Raw nano seconds accumulated per NTP interval. - * @ntp_error: Difference between accumulated time and NTP time in ntp - * shifted nano seconds. - * @ntp_error_shift: Shift conversion between clock shifted nano seconds and - * ntp shifted nano seconds. - * @last_warning: Warning ratelimiter (DEBUG_TIMEKEEPING) - * @underflow_seen: Underflow warning flag (DEBUG_TIMEKEEPING) - * @overflow_seen: Overflow warning flag (DEBUG_TIMEKEEPING) - * - * Note: For timespec(64) based interfaces wall_to_monotonic is what - * we need to add to xtime (or xtime corrected for sub jiffie times) - * to get to monotonic time. Monotonic is pegged at zero at system - * boot time, so wall_to_monotonic will be negative, however, we will - * ALWAYS keep the tv_nsec part positive so we can use the usual - * normalization. - * - * wall_to_monotonic is moved after resume from suspend for the - * monotonic time not to jump. We need to add total_sleep_time to - * wall_to_monotonic to get the real boot based time offset. - * - * wall_to_monotonic is no longer the boot time, getboottime must be - * used instead. - */ -struct timekeeper { - struct tk_read_base tkr_mono; - struct tk_read_base tkr_raw; - u64 xtime_sec; - unsigned long ktime_sec; - struct timespec64 wall_to_monotonic; - ktime_t offs_real; - ktime_t offs_boot; - ktime_t offs_tai; - s32 tai_offset; - unsigned int clock_was_set_seq; - u8 cs_was_changed_seq; - ktime_t next_leap_ktime; - struct timespec64 raw_time; - - /* The following members are for timekeeping internal use */ - cycle_t cycle_interval; - u64 xtime_interval; - s64 xtime_remainder; - u32 raw_interval; - /* The ntp_tick_length() value currently being used. - * This cached copy ensures we consistently apply the tick - * length for an entire tick, as ntp_tick_length may change - * mid-tick, and we don't want to apply that new value to - * the tick in progress. - */ - u64 ntp_tick; - /* Difference between accumulated time and NTP time in ntp - * shifted nano seconds. */ - s64 ntp_error; - u32 ntp_error_shift; - u32 ntp_err_mult; -#ifdef CONFIG_DEBUG_TIMEKEEPING - long last_warning; - /* - * These simple flag variables are managed - * without locks, which is racy, but they are - * ok since we don't really care about being - * super precise about how many events were - * seen, just that a problem was observed. - */ - int underflow_seen; - int overflow_seen; -#endif -}; - -#ifdef CONFIG_GENERIC_TIME_VSYSCALL - -extern void update_vsyscall(struct timekeeper *tk); -extern void update_vsyscall_tz(void); - -#elif defined(CONFIG_GENERIC_TIME_VSYSCALL_OLD) - -extern void update_vsyscall_old(struct timespec *ts, struct timespec *wtm, - struct clocksource *c, u32 mult, - cycle_t cycle_last); -extern void update_vsyscall_tz(void); - -#else - -static inline void update_vsyscall(struct timekeeper *tk) -{ -} -static inline void update_vsyscall_tz(void) -{ -} -#endif - -#endif /* _LINUX_TIMEKEEPER_INTERNAL_H */ diff --git a/src/linux/include/linux/timekeeping.h b/src/linux/include/linux/timekeeping.h deleted file mode 100644 index 09168c5..0000000 --- a/src/linux/include/linux/timekeeping.h +++ /dev/null @@ -1,355 +0,0 @@ -#ifndef _LINUX_TIMEKEEPING_H -#define _LINUX_TIMEKEEPING_H - -#include - -/* Included from linux/ktime.h */ - -void timekeeping_init(void); -extern int timekeeping_suspended; - -/* - * Get and set timeofday - */ -extern void do_gettimeofday(struct timeval *tv); -extern int do_settimeofday64(const struct timespec64 *ts); -extern int do_sys_settimeofday64(const struct timespec64 *tv, - const struct timezone *tz); -static inline int do_sys_settimeofday(const struct timespec *tv, - const struct timezone *tz) -{ - struct timespec64 ts64; - - if (!tv) - return do_sys_settimeofday64(NULL, tz); - - if (!timespec_valid(tv)) - return -EINVAL; - - ts64 = timespec_to_timespec64(*tv); - return do_sys_settimeofday64(&ts64, tz); -} - -/* - * Kernel time accessors - */ -unsigned long get_seconds(void); -struct timespec64 current_kernel_time64(void); -/* does not take xtime_lock */ -struct timespec __current_kernel_time(void); - -static inline struct timespec current_kernel_time(void) -{ - struct timespec64 now = current_kernel_time64(); - - return timespec64_to_timespec(now); -} - -/* - * timespec based interfaces - */ -struct timespec64 get_monotonic_coarse64(void); -extern void getrawmonotonic64(struct timespec64 *ts); -extern void ktime_get_ts64(struct timespec64 *ts); -extern time64_t ktime_get_seconds(void); -extern time64_t ktime_get_real_seconds(void); - -extern int __getnstimeofday64(struct timespec64 *tv); -extern void getnstimeofday64(struct timespec64 *tv); -extern void getboottime64(struct timespec64 *ts); - -#if BITS_PER_LONG == 64 -/** - * Deprecated. Use do_settimeofday64(). - */ -static inline int do_settimeofday(const struct timespec *ts) -{ - return do_settimeofday64(ts); -} - -static inline int __getnstimeofday(struct timespec *ts) -{ - return __getnstimeofday64(ts); -} - -static inline void getnstimeofday(struct timespec *ts) -{ - getnstimeofday64(ts); -} - -static inline void ktime_get_ts(struct timespec *ts) -{ - ktime_get_ts64(ts); -} - -static inline void ktime_get_real_ts(struct timespec *ts) -{ - getnstimeofday64(ts); -} - -static inline void getrawmonotonic(struct timespec *ts) -{ - getrawmonotonic64(ts); -} - -static inline struct timespec get_monotonic_coarse(void) -{ - return get_monotonic_coarse64(); -} - -static inline void getboottime(struct timespec *ts) -{ - return getboottime64(ts); -} -#else -/** - * Deprecated. Use do_settimeofday64(). - */ -static inline int do_settimeofday(const struct timespec *ts) -{ - struct timespec64 ts64; - - ts64 = timespec_to_timespec64(*ts); - return do_settimeofday64(&ts64); -} - -static inline int __getnstimeofday(struct timespec *ts) -{ - struct timespec64 ts64; - int ret = __getnstimeofday64(&ts64); - - *ts = timespec64_to_timespec(ts64); - return ret; -} - -static inline void getnstimeofday(struct timespec *ts) -{ - struct timespec64 ts64; - - getnstimeofday64(&ts64); - *ts = timespec64_to_timespec(ts64); -} - -static inline void ktime_get_ts(struct timespec *ts) -{ - struct timespec64 ts64; - - ktime_get_ts64(&ts64); - *ts = timespec64_to_timespec(ts64); -} - -static inline void ktime_get_real_ts(struct timespec *ts) -{ - struct timespec64 ts64; - - getnstimeofday64(&ts64); - *ts = timespec64_to_timespec(ts64); -} - -static inline void getrawmonotonic(struct timespec *ts) -{ - struct timespec64 ts64; - - getrawmonotonic64(&ts64); - *ts = timespec64_to_timespec(ts64); -} - -static inline struct timespec get_monotonic_coarse(void) -{ - return timespec64_to_timespec(get_monotonic_coarse64()); -} - -static inline void getboottime(struct timespec *ts) -{ - struct timespec64 ts64; - - getboottime64(&ts64); - *ts = timespec64_to_timespec(ts64); -} -#endif - -#define ktime_get_real_ts64(ts) getnstimeofday64(ts) - -/* - * ktime_t based interfaces - */ - -enum tk_offsets { - TK_OFFS_REAL, - TK_OFFS_BOOT, - TK_OFFS_TAI, - TK_OFFS_MAX, -}; - -extern ktime_t ktime_get(void); -extern ktime_t ktime_get_with_offset(enum tk_offsets offs); -extern ktime_t ktime_mono_to_any(ktime_t tmono, enum tk_offsets offs); -extern ktime_t ktime_get_raw(void); -extern u32 ktime_get_resolution_ns(void); - -/** - * ktime_get_real - get the real (wall-) time in ktime_t format - */ -static inline ktime_t ktime_get_real(void) -{ - return ktime_get_with_offset(TK_OFFS_REAL); -} - -/** - * ktime_get_boottime - Returns monotonic time since boot in ktime_t format - * - * This is similar to CLOCK_MONTONIC/ktime_get, but also includes the - * time spent in suspend. - */ -static inline ktime_t ktime_get_boottime(void) -{ - return ktime_get_with_offset(TK_OFFS_BOOT); -} - -/** - * ktime_get_clocktai - Returns the TAI time of day in ktime_t format - */ -static inline ktime_t ktime_get_clocktai(void) -{ - return ktime_get_with_offset(TK_OFFS_TAI); -} - -/** - * ktime_mono_to_real - Convert monotonic time to clock realtime - */ -static inline ktime_t ktime_mono_to_real(ktime_t mono) -{ - return ktime_mono_to_any(mono, TK_OFFS_REAL); -} - -static inline u64 ktime_get_ns(void) -{ - return ktime_to_ns(ktime_get()); -} - -static inline u64 ktime_get_real_ns(void) -{ - return ktime_to_ns(ktime_get_real()); -} - -static inline u64 ktime_get_boot_ns(void) -{ - return ktime_to_ns(ktime_get_boottime()); -} - -static inline u64 ktime_get_tai_ns(void) -{ - return ktime_to_ns(ktime_get_clocktai()); -} - -static inline u64 ktime_get_raw_ns(void) -{ - return ktime_to_ns(ktime_get_raw()); -} - -extern u64 ktime_get_mono_fast_ns(void); -extern u64 ktime_get_raw_fast_ns(void); - -/* - * Timespec interfaces utilizing the ktime based ones - */ -static inline void get_monotonic_boottime(struct timespec *ts) -{ - *ts = ktime_to_timespec(ktime_get_boottime()); -} - -static inline void get_monotonic_boottime64(struct timespec64 *ts) -{ - *ts = ktime_to_timespec64(ktime_get_boottime()); -} - -static inline void timekeeping_clocktai(struct timespec *ts) -{ - *ts = ktime_to_timespec(ktime_get_clocktai()); -} - -/* - * RTC specific - */ -extern bool timekeeping_rtc_skipsuspend(void); -extern bool timekeeping_rtc_skipresume(void); - -extern void timekeeping_inject_sleeptime64(struct timespec64 *delta); - -/* - * PPS accessor - */ -extern void ktime_get_raw_and_real_ts64(struct timespec64 *ts_raw, - struct timespec64 *ts_real); - -/* - * struct system_time_snapshot - simultaneous raw/real time capture with - * counter value - * @cycles: Clocksource counter value to produce the system times - * @real: Realtime system time - * @raw: Monotonic raw system time - * @clock_was_set_seq: The sequence number of clock was set events - * @cs_was_changed_seq: The sequence number of clocksource change events - */ -struct system_time_snapshot { - cycle_t cycles; - ktime_t real; - ktime_t raw; - unsigned int clock_was_set_seq; - u8 cs_was_changed_seq; -}; - -/* - * struct system_device_crosststamp - system/device cross-timestamp - * (syncronized capture) - * @device: Device time - * @sys_realtime: Realtime simultaneous with device time - * @sys_monoraw: Monotonic raw simultaneous with device time - */ -struct system_device_crosststamp { - ktime_t device; - ktime_t sys_realtime; - ktime_t sys_monoraw; -}; - -/* - * struct system_counterval_t - system counter value with the pointer to the - * corresponding clocksource - * @cycles: System counter value - * @cs: Clocksource corresponding to system counter value. Used by - * timekeeping code to verify comparibility of two cycle values - */ -struct system_counterval_t { - cycle_t cycles; - struct clocksource *cs; -}; - -/* - * Get cross timestamp between system clock and device clock - */ -extern int get_device_system_crosststamp( - int (*get_time_fn)(ktime_t *device_time, - struct system_counterval_t *system_counterval, - void *ctx), - void *ctx, - struct system_time_snapshot *history, - struct system_device_crosststamp *xtstamp); - -/* - * Simultaneously snapshot realtime and monotonic raw clocks - */ -extern void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot); - -/* - * Persistent clock related interfaces - */ -extern int persistent_clock_is_local; - -extern void read_persistent_clock(struct timespec *ts); -extern void read_persistent_clock64(struct timespec64 *ts); -extern void read_boot_clock64(struct timespec64 *ts); -extern int update_persistent_clock(struct timespec now); -extern int update_persistent_clock64(struct timespec64 now); - - -#endif diff --git a/src/linux/include/linux/timer.h b/src/linux/include/linux/timer.h deleted file mode 100644 index 51d601f..0000000 --- a/src/linux/include/linux/timer.h +++ /dev/null @@ -1,282 +0,0 @@ -#ifndef _LINUX_TIMER_H -#define _LINUX_TIMER_H - -#include -#include -#include -#include -#include - -struct tvec_base; - -struct timer_list { - /* - * All fields that change during normal runtime grouped to the - * same cacheline - */ - struct hlist_node entry; - unsigned long expires; - void (*function)(unsigned long); - unsigned long data; - u32 flags; - -#ifdef CONFIG_TIMER_STATS - int start_pid; - void *start_site; - char start_comm[16]; -#endif -#ifdef CONFIG_LOCKDEP - struct lockdep_map lockdep_map; -#endif -}; - -#ifdef CONFIG_LOCKDEP -/* - * NB: because we have to copy the lockdep_map, setting the lockdep_map key - * (second argument) here is required, otherwise it could be initialised to - * the copy of the lockdep_map later! We use the pointer to and the string - * ":" as the key resp. the name of the lockdep_map. - */ -#define __TIMER_LOCKDEP_MAP_INITIALIZER(_kn) \ - .lockdep_map = STATIC_LOCKDEP_MAP_INIT(_kn, &_kn), -#else -#define __TIMER_LOCKDEP_MAP_INITIALIZER(_kn) -#endif - -/* - * A deferrable timer will work normally when the system is busy, but - * will not cause a CPU to come out of idle just to service it; instead, - * the timer will be serviced when the CPU eventually wakes up with a - * subsequent non-deferrable timer. - * - * An irqsafe timer is executed with IRQ disabled and it's safe to wait for - * the completion of the running instance from IRQ handlers, for example, - * by calling del_timer_sync(). - * - * Note: The irq disabled callback execution is a special case for - * workqueue locking issues. It's not meant for executing random crap - * with interrupts disabled. Abuse is monitored! - */ -#define TIMER_CPUMASK 0x0003FFFF -#define TIMER_MIGRATING 0x00040000 -#define TIMER_BASEMASK (TIMER_CPUMASK | TIMER_MIGRATING) -#define TIMER_DEFERRABLE 0x00080000 -#define TIMER_PINNED 0x00100000 -#define TIMER_IRQSAFE 0x00200000 -#define TIMER_ARRAYSHIFT 22 -#define TIMER_ARRAYMASK 0xFFC00000 - -#define __TIMER_INITIALIZER(_function, _expires, _data, _flags) { \ - .entry = { .next = TIMER_ENTRY_STATIC }, \ - .function = (_function), \ - .expires = (_expires), \ - .data = (_data), \ - .flags = (_flags), \ - __TIMER_LOCKDEP_MAP_INITIALIZER( \ - __FILE__ ":" __stringify(__LINE__)) \ - } - -#define TIMER_INITIALIZER(_function, _expires, _data) \ - __TIMER_INITIALIZER((_function), (_expires), (_data), 0) - -#define TIMER_PINNED_INITIALIZER(_function, _expires, _data) \ - __TIMER_INITIALIZER((_function), (_expires), (_data), TIMER_PINNED) - -#define TIMER_DEFERRED_INITIALIZER(_function, _expires, _data) \ - __TIMER_INITIALIZER((_function), (_expires), (_data), TIMER_DEFERRABLE) - -#define TIMER_PINNED_DEFERRED_INITIALIZER(_function, _expires, _data) \ - __TIMER_INITIALIZER((_function), (_expires), (_data), TIMER_DEFERRABLE | TIMER_PINNED) - -#define DEFINE_TIMER(_name, _function, _expires, _data) \ - struct timer_list _name = \ - TIMER_INITIALIZER(_function, _expires, _data) - -void init_timer_key(struct timer_list *timer, unsigned int flags, - const char *name, struct lock_class_key *key); - -#ifdef CONFIG_DEBUG_OBJECTS_TIMERS -extern void init_timer_on_stack_key(struct timer_list *timer, - unsigned int flags, const char *name, - struct lock_class_key *key); -extern void destroy_timer_on_stack(struct timer_list *timer); -#else -static inline void destroy_timer_on_stack(struct timer_list *timer) { } -static inline void init_timer_on_stack_key(struct timer_list *timer, - unsigned int flags, const char *name, - struct lock_class_key *key) -{ - init_timer_key(timer, flags, name, key); -} -#endif - -#ifdef CONFIG_LOCKDEP -#define __init_timer(_timer, _flags) \ - do { \ - static struct lock_class_key __key; \ - init_timer_key((_timer), (_flags), #_timer, &__key); \ - } while (0) - -#define __init_timer_on_stack(_timer, _flags) \ - do { \ - static struct lock_class_key __key; \ - init_timer_on_stack_key((_timer), (_flags), #_timer, &__key); \ - } while (0) -#else -#define __init_timer(_timer, _flags) \ - init_timer_key((_timer), (_flags), NULL, NULL) -#define __init_timer_on_stack(_timer, _flags) \ - init_timer_on_stack_key((_timer), (_flags), NULL, NULL) -#endif - -#define init_timer(timer) \ - __init_timer((timer), 0) -#define init_timer_pinned(timer) \ - __init_timer((timer), TIMER_PINNED) -#define init_timer_deferrable(timer) \ - __init_timer((timer), TIMER_DEFERRABLE) -#define init_timer_pinned_deferrable(timer) \ - __init_timer((timer), TIMER_DEFERRABLE | TIMER_PINNED) -#define init_timer_on_stack(timer) \ - __init_timer_on_stack((timer), 0) - -#define __setup_timer(_timer, _fn, _data, _flags) \ - do { \ - __init_timer((_timer), (_flags)); \ - (_timer)->function = (_fn); \ - (_timer)->data = (_data); \ - } while (0) - -#define __setup_timer_on_stack(_timer, _fn, _data, _flags) \ - do { \ - __init_timer_on_stack((_timer), (_flags)); \ - (_timer)->function = (_fn); \ - (_timer)->data = (_data); \ - } while (0) - -#define setup_timer(timer, fn, data) \ - __setup_timer((timer), (fn), (data), 0) -#define setup_pinned_timer(timer, fn, data) \ - __setup_timer((timer), (fn), (data), TIMER_PINNED) -#define setup_deferrable_timer(timer, fn, data) \ - __setup_timer((timer), (fn), (data), TIMER_DEFERRABLE) -#define setup_pinned_deferrable_timer(timer, fn, data) \ - __setup_timer((timer), (fn), (data), TIMER_DEFERRABLE | TIMER_PINNED) -#define setup_timer_on_stack(timer, fn, data) \ - __setup_timer_on_stack((timer), (fn), (data), 0) -#define setup_pinned_timer_on_stack(timer, fn, data) \ - __setup_timer_on_stack((timer), (fn), (data), TIMER_PINNED) -#define setup_deferrable_timer_on_stack(timer, fn, data) \ - __setup_timer_on_stack((timer), (fn), (data), TIMER_DEFERRABLE) -#define setup_pinned_deferrable_timer_on_stack(timer, fn, data) \ - __setup_timer_on_stack((timer), (fn), (data), TIMER_DEFERRABLE | TIMER_PINNED) - -/** - * timer_pending - is a timer pending? - * @timer: the timer in question - * - * timer_pending will tell whether a given timer is currently pending, - * or not. Callers must ensure serialization wrt. other operations done - * to this timer, eg. interrupt contexts, or other CPUs on SMP. - * - * return value: 1 if the timer is pending, 0 if not. - */ -static inline int timer_pending(const struct timer_list * timer) -{ - return timer->entry.pprev != NULL; -} - -extern void add_timer_on(struct timer_list *timer, int cpu); -extern int del_timer(struct timer_list * timer); -extern int mod_timer(struct timer_list *timer, unsigned long expires); -extern int mod_timer_pending(struct timer_list *timer, unsigned long expires); - -/* - * The jiffies value which is added to now, when there is no timer - * in the timer wheel: - */ -#define NEXT_TIMER_MAX_DELTA ((1UL << 30) - 1) - -/* - * Timer-statistics info: - */ -#ifdef CONFIG_TIMER_STATS - -extern int timer_stats_active; - -extern void init_timer_stats(void); - -extern void timer_stats_update_stats(void *timer, pid_t pid, void *startf, - void *timerf, char *comm, u32 flags); - -extern void __timer_stats_timer_set_start_info(struct timer_list *timer, - void *addr); - -static inline void timer_stats_timer_set_start_info(struct timer_list *timer) -{ - if (likely(!timer_stats_active)) - return; - __timer_stats_timer_set_start_info(timer, __builtin_return_address(0)); -} - -static inline void timer_stats_timer_clear_start_info(struct timer_list *timer) -{ - timer->start_site = NULL; -} -#else -static inline void init_timer_stats(void) -{ -} - -static inline void timer_stats_timer_set_start_info(struct timer_list *timer) -{ -} - -static inline void timer_stats_timer_clear_start_info(struct timer_list *timer) -{ -} -#endif - -extern void add_timer(struct timer_list *timer); - -extern int try_to_del_timer_sync(struct timer_list *timer); - -#ifdef CONFIG_SMP - extern int del_timer_sync(struct timer_list *timer); -#else -# define del_timer_sync(t) del_timer(t) -#endif - -#define del_singleshot_timer_sync(t) del_timer_sync(t) - -extern void init_timers(void); -extern void run_local_timers(void); -struct hrtimer; -extern enum hrtimer_restart it_real_fn(struct hrtimer *); - -#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON) -#include - -extern unsigned int sysctl_timer_migration; -int timer_migration_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos); -#endif - -unsigned long __round_jiffies(unsigned long j, int cpu); -unsigned long __round_jiffies_relative(unsigned long j, int cpu); -unsigned long round_jiffies(unsigned long j); -unsigned long round_jiffies_relative(unsigned long j); - -unsigned long __round_jiffies_up(unsigned long j, int cpu); -unsigned long __round_jiffies_up_relative(unsigned long j, int cpu); -unsigned long round_jiffies_up(unsigned long j); -unsigned long round_jiffies_up_relative(unsigned long j); - -#ifdef CONFIG_HOTPLUG_CPU -int timers_dead_cpu(unsigned int cpu); -#else -#define timers_dead_cpu NULL -#endif - -#endif diff --git a/src/linux/include/linux/timerqueue.h b/src/linux/include/linux/timerqueue.h deleted file mode 100644 index 7eec17a..0000000 --- a/src/linux/include/linux/timerqueue.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef _LINUX_TIMERQUEUE_H -#define _LINUX_TIMERQUEUE_H - -#include -#include - - -struct timerqueue_node { - struct rb_node node; - ktime_t expires; -}; - -struct timerqueue_head { - struct rb_root head; - struct timerqueue_node *next; -}; - - -extern bool timerqueue_add(struct timerqueue_head *head, - struct timerqueue_node *node); -extern bool timerqueue_del(struct timerqueue_head *head, - struct timerqueue_node *node); -extern struct timerqueue_node *timerqueue_iterate_next( - struct timerqueue_node *node); - -/** - * timerqueue_getnext - Returns the timer with the earliest expiration time - * - * @head: head of timerqueue - * - * Returns a pointer to the timer node that has the - * earliest expiration time. - */ -static inline -struct timerqueue_node *timerqueue_getnext(struct timerqueue_head *head) -{ - return head->next; -} - -static inline void timerqueue_init(struct timerqueue_node *node) -{ - RB_CLEAR_NODE(&node->node); -} - -static inline void timerqueue_init_head(struct timerqueue_head *head) -{ - head->head = RB_ROOT; - head->next = NULL; -} -#endif /* _LINUX_TIMERQUEUE_H */ diff --git a/src/linux/include/linux/timex.h b/src/linux/include/linux/timex.h deleted file mode 100644 index 39c25db..0000000 --- a/src/linux/include/linux/timex.h +++ /dev/null @@ -1,163 +0,0 @@ -/***************************************************************************** - * * - * Copyright (c) David L. Mills 1993 * - * * - * Permission to use, copy, modify, and distribute this software and its * - * documentation for any purpose and without fee is hereby granted, provided * - * that the above copyright notice appears in all copies and that both the * - * copyright notice and this permission notice appear in supporting * - * documentation, and that the name University of Delaware not be used in * - * advertising or publicity pertaining to distribution of the software * - * without specific, written prior permission. The University of Delaware * - * makes no representations about the suitability this software for any * - * purpose. It is provided "as is" without express or implied warranty. * - * * - *****************************************************************************/ - -/* - * Modification history timex.h - * - * 29 Dec 97 Russell King - * Moved CLOCK_TICK_RATE, CLOCK_TICK_FACTOR and FINETUNE to asm/timex.h - * for ARM machines - * - * 9 Jan 97 Adrian Sun - * Shifted LATCH define to allow access to alpha machines. - * - * 26 Sep 94 David L. Mills - * Added defines for hybrid phase/frequency-lock loop. - * - * 19 Mar 94 David L. Mills - * Moved defines from kernel routines to header file and added new - * defines for PPS phase-lock loop. - * - * 20 Feb 94 David L. Mills - * Revised status codes and structures for external clock and PPS - * signal discipline. - * - * 28 Nov 93 David L. Mills - * Adjusted parameters to improve stability and increase poll - * interval. - * - * 17 Sep 93 David L. Mills - * Created file $NTP/include/sys/timex.h - * 07 Oct 93 Torsten Duwe - * Derived linux/timex.h - * 1995-08-13 Torsten Duwe - * kernel PLL updated to 1994-12-13 specs (rfc-1589) - * 1997-08-30 Ulrich Windl - * Added new constant NTP_PHASE_LIMIT - * 2004-08-12 Christoph Lameter - * Reworked time interpolation logic - */ -#ifndef _LINUX_TIMEX_H -#define _LINUX_TIMEX_H - -#include - -#define ADJ_ADJTIME 0x8000 /* switch between adjtime/adjtimex modes */ -#define ADJ_OFFSET_SINGLESHOT 0x0001 /* old-fashioned adjtime */ -#define ADJ_OFFSET_READONLY 0x2000 /* read-only adjtime */ -#include -#include -#include - -#include - -#ifndef random_get_entropy -/* - * The random_get_entropy() function is used by the /dev/random driver - * in order to extract entropy via the relative unpredictability of - * when an interrupt takes places versus a high speed, fine-grained - * timing source or cycle counter. Since it will be occurred on every - * single interrupt, it must have a very low cost/overhead. - * - * By default we use get_cycles() for this purpose, but individual - * architectures may override this in their asm/timex.h header file. - */ -#define random_get_entropy() get_cycles() -#endif - -/* - * SHIFT_PLL is used as a dampening factor to define how much we - * adjust the frequency correction for a given offset in PLL mode. - * It also used in dampening the offset correction, to define how - * much of the current value in time_offset we correct for each - * second. Changing this value changes the stiffness of the ntp - * adjustment code. A lower value makes it more flexible, reducing - * NTP convergence time. A higher value makes it stiffer, increasing - * convergence time, but making the clock more stable. - * - * In David Mills' nanokernel reference implementation SHIFT_PLL is 4. - * However this seems to increase convergence time much too long. - * - * https://lists.ntp.org/pipermail/hackers/2008-January/003487.html - * - * In the above mailing list discussion, it seems the value of 4 - * was appropriate for other Unix systems with HZ=100, and that - * SHIFT_PLL should be decreased as HZ increases. However, Linux's - * clock steering implementation is HZ independent. - * - * Through experimentation, a SHIFT_PLL value of 2 was found to allow - * for fast convergence (very similar to the NTPv3 code used prior to - * v2.6.19), with good clock stability. - * - * - * SHIFT_FLL is used as a dampening factor to define how much we - * adjust the frequency correction for a given offset in FLL mode. - * In David Mills' nanokernel reference implementation SHIFT_FLL is 2. - * - * MAXTC establishes the maximum time constant of the PLL. - */ -#define SHIFT_PLL 2 /* PLL frequency factor (shift) */ -#define SHIFT_FLL 2 /* FLL frequency factor (shift) */ -#define MAXTC 10 /* maximum time constant (shift) */ - -/* - * SHIFT_USEC defines the scaling (shift) of the time_freq and - * time_tolerance variables, which represent the current frequency - * offset and maximum frequency tolerance. - */ -#define SHIFT_USEC 16 /* frequency offset scale (shift) */ -#define PPM_SCALE ((s64)NSEC_PER_USEC << (NTP_SCALE_SHIFT - SHIFT_USEC)) -#define PPM_SCALE_INV_SHIFT 19 -#define PPM_SCALE_INV ((1LL << (PPM_SCALE_INV_SHIFT + NTP_SCALE_SHIFT)) / \ - PPM_SCALE + 1) - -#define MAXPHASE 500000000L /* max phase error (ns) */ -#define MAXFREQ 500000 /* max frequency error (ns/s) */ -#define MAXFREQ_SCALED ((s64)MAXFREQ << NTP_SCALE_SHIFT) -#define MINSEC 256 /* min interval between updates (s) */ -#define MAXSEC 2048 /* max interval between updates (s) */ -#define NTP_PHASE_LIMIT ((MAXPHASE / NSEC_PER_USEC) << 5) /* beyond max. dispersion */ - -/* - * kernel variables - * Note: maximum error = NTP synch distance = dispersion + delay / 2; - * estimated error = NTP dispersion. - */ -extern unsigned long tick_usec; /* USER_HZ period (usec) */ -extern unsigned long tick_nsec; /* SHIFTED_HZ period (nsec) */ - -/* Required to safely shift negative values */ -#define shift_right(x, s) ({ \ - __typeof__(x) __x = (x); \ - __typeof__(s) __s = (s); \ - __x < 0 ? -(-__x >> __s) : __x >> __s; \ -}) - -#define NTP_SCALE_SHIFT 32 - -#define NTP_INTERVAL_FREQ (HZ) -#define NTP_INTERVAL_LENGTH (NSEC_PER_SEC/NTP_INTERVAL_FREQ) - -extern int do_adjtimex(struct timex *); -extern void hardpps(const struct timespec64 *, const struct timespec64 *); - -int read_current_timer(unsigned long *timer_val); -void ntp_notify_cmos_timer(void); - -/* The clock frequency of the i8253/i8254 PIT */ -#define PIT_TICK_RATE 1193182ul - -#endif /* LINUX_TIMEX_H */ diff --git a/src/linux/include/linux/topology.h b/src/linux/include/linux/topology.h deleted file mode 100644 index cb0775e..0000000 --- a/src/linux/include/linux/topology.h +++ /dev/null @@ -1,210 +0,0 @@ -/* - * include/linux/topology.h - * - * Written by: Matthew Dobson, IBM Corporation - * - * Copyright (C) 2002, IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or - * NON INFRINGEMENT. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * Send feedback to - */ -#ifndef _LINUX_TOPOLOGY_H -#define _LINUX_TOPOLOGY_H - -#include -#include -#include -#include -#include -#include - -#ifndef nr_cpus_node -#define nr_cpus_node(node) cpumask_weight(cpumask_of_node(node)) -#endif - -#define for_each_node_with_cpus(node) \ - for_each_online_node(node) \ - if (nr_cpus_node(node)) - -int arch_update_cpu_topology(void); - -/* Conform to ACPI 2.0 SLIT distance definitions */ -#define LOCAL_DISTANCE 10 -#define REMOTE_DISTANCE 20 -#ifndef node_distance -#define node_distance(from,to) ((from) == (to) ? LOCAL_DISTANCE : REMOTE_DISTANCE) -#endif -#ifndef RECLAIM_DISTANCE -/* - * If the distance between nodes in a system is larger than RECLAIM_DISTANCE - * (in whatever arch specific measurement units returned by node_distance()) - * and node_reclaim_mode is enabled then the VM will only call node_reclaim() - * on nodes within this distance. - */ -#define RECLAIM_DISTANCE 30 -#endif -#ifndef PENALTY_FOR_NODE_WITH_CPUS -#define PENALTY_FOR_NODE_WITH_CPUS (1) -#endif - -#ifdef CONFIG_USE_PERCPU_NUMA_NODE_ID -DECLARE_PER_CPU(int, numa_node); - -#ifndef numa_node_id -/* Returns the number of the current Node. */ -static inline int numa_node_id(void) -{ - return raw_cpu_read(numa_node); -} -#endif - -#ifndef cpu_to_node -static inline int cpu_to_node(int cpu) -{ - return per_cpu(numa_node, cpu); -} -#endif - -#ifndef set_numa_node -static inline void set_numa_node(int node) -{ - this_cpu_write(numa_node, node); -} -#endif - -#ifndef set_cpu_numa_node -static inline void set_cpu_numa_node(int cpu, int node) -{ - per_cpu(numa_node, cpu) = node; -} -#endif - -#else /* !CONFIG_USE_PERCPU_NUMA_NODE_ID */ - -/* Returns the number of the current Node. */ -#ifndef numa_node_id -static inline int numa_node_id(void) -{ - return cpu_to_node(raw_smp_processor_id()); -} -#endif - -#endif /* [!]CONFIG_USE_PERCPU_NUMA_NODE_ID */ - -#ifdef CONFIG_HAVE_MEMORYLESS_NODES - -/* - * N.B., Do NOT reference the '_numa_mem_' per cpu variable directly. - * It will not be defined when CONFIG_HAVE_MEMORYLESS_NODES is not defined. - * Use the accessor functions set_numa_mem(), numa_mem_id() and cpu_to_mem(). - */ -DECLARE_PER_CPU(int, _numa_mem_); -extern int _node_numa_mem_[MAX_NUMNODES]; - -#ifndef set_numa_mem -static inline void set_numa_mem(int node) -{ - this_cpu_write(_numa_mem_, node); - _node_numa_mem_[numa_node_id()] = node; -} -#endif - -#ifndef node_to_mem_node -static inline int node_to_mem_node(int node) -{ - return _node_numa_mem_[node]; -} -#endif - -#ifndef numa_mem_id -/* Returns the number of the nearest Node with memory */ -static inline int numa_mem_id(void) -{ - return raw_cpu_read(_numa_mem_); -} -#endif - -#ifndef cpu_to_mem -static inline int cpu_to_mem(int cpu) -{ - return per_cpu(_numa_mem_, cpu); -} -#endif - -#ifndef set_cpu_numa_mem -static inline void set_cpu_numa_mem(int cpu, int node) -{ - per_cpu(_numa_mem_, cpu) = node; - _node_numa_mem_[cpu_to_node(cpu)] = node; -} -#endif - -#else /* !CONFIG_HAVE_MEMORYLESS_NODES */ - -#ifndef numa_mem_id -/* Returns the number of the nearest Node with memory */ -static inline int numa_mem_id(void) -{ - return numa_node_id(); -} -#endif - -#ifndef node_to_mem_node -static inline int node_to_mem_node(int node) -{ - return node; -} -#endif - -#ifndef cpu_to_mem -static inline int cpu_to_mem(int cpu) -{ - return cpu_to_node(cpu); -} -#endif - -#endif /* [!]CONFIG_HAVE_MEMORYLESS_NODES */ - -#ifndef topology_physical_package_id -#define topology_physical_package_id(cpu) ((void)(cpu), -1) -#endif -#ifndef topology_core_id -#define topology_core_id(cpu) ((void)(cpu), 0) -#endif -#ifndef topology_sibling_cpumask -#define topology_sibling_cpumask(cpu) cpumask_of(cpu) -#endif -#ifndef topology_core_cpumask -#define topology_core_cpumask(cpu) cpumask_of(cpu) -#endif - -#ifdef CONFIG_SCHED_SMT -static inline const struct cpumask *cpu_smt_mask(int cpu) -{ - return topology_sibling_cpumask(cpu); -} -#endif - -static inline const struct cpumask *cpu_cpu_mask(int cpu) -{ - return cpumask_of_node(cpu_to_node(cpu)); -} - - -#endif /* _LINUX_TOPOLOGY_H */ diff --git a/src/linux/include/linux/trace_clock.h b/src/linux/include/linux/trace_clock.h deleted file mode 100644 index 1d7ca27..0000000 --- a/src/linux/include/linux/trace_clock.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _LINUX_TRACE_CLOCK_H -#define _LINUX_TRACE_CLOCK_H - -/* - * 3 trace clock variants, with differing scalability/precision - * tradeoffs: - * - * - local: CPU-local trace clock - * - medium: scalable global clock with some jitter - * - global: globally monotonic, serialized clock - */ -#include -#include - -#include - -extern u64 notrace trace_clock_local(void); -extern u64 notrace trace_clock(void); -extern u64 notrace trace_clock_jiffies(void); -extern u64 notrace trace_clock_global(void); -extern u64 notrace trace_clock_counter(void); - -#endif /* _LINUX_TRACE_CLOCK_H */ diff --git a/src/linux/include/linux/trace_events.h b/src/linux/include/linux/trace_events.h deleted file mode 100644 index be00761..0000000 --- a/src/linux/include/linux/trace_events.h +++ /dev/null @@ -1,510 +0,0 @@ - -#ifndef _LINUX_TRACE_EVENT_H -#define _LINUX_TRACE_EVENT_H - -#include -#include -#include -#include -#include -#include - -struct trace_array; -struct trace_buffer; -struct tracer; -struct dentry; -struct bpf_prog; - -const char *trace_print_flags_seq(struct trace_seq *p, const char *delim, - unsigned long flags, - const struct trace_print_flags *flag_array); - -const char *trace_print_symbols_seq(struct trace_seq *p, unsigned long val, - const struct trace_print_flags *symbol_array); - -#if BITS_PER_LONG == 32 -const char *trace_print_symbols_seq_u64(struct trace_seq *p, - unsigned long long val, - const struct trace_print_flags_u64 - *symbol_array); -#endif - -const char *trace_print_bitmask_seq(struct trace_seq *p, void *bitmask_ptr, - unsigned int bitmask_size); - -const char *trace_print_hex_seq(struct trace_seq *p, - const unsigned char *buf, int len); - -const char *trace_print_array_seq(struct trace_seq *p, - const void *buf, int count, - size_t el_size); - -struct trace_iterator; -struct trace_event; - -int trace_raw_output_prep(struct trace_iterator *iter, - struct trace_event *event); - -/* - * The trace entry - the most basic unit of tracing. This is what - * is printed in the end as a single line in the trace output, such as: - * - * bash-15816 [01] 235.197585: idle_cpu <- irq_enter - */ -struct trace_entry { - unsigned short type; - unsigned char flags; - unsigned char preempt_count; - int pid; -}; - -#define TRACE_EVENT_TYPE_MAX \ - ((1 << (sizeof(((struct trace_entry *)0)->type) * 8)) - 1) - -/* - * Trace iterator - used by printout routines who present trace - * results to users and which routines might sleep, etc: - */ -struct trace_iterator { - struct trace_array *tr; - struct tracer *trace; - struct trace_buffer *trace_buffer; - void *private; - int cpu_file; - struct mutex mutex; - struct ring_buffer_iter **buffer_iter; - unsigned long iter_flags; - - /* trace_seq for __print_flags() and __print_symbolic() etc. */ - struct trace_seq tmp_seq; - - cpumask_var_t started; - - /* it's true when current open file is snapshot */ - bool snapshot; - - /* The below is zeroed out in pipe_read */ - struct trace_seq seq; - struct trace_entry *ent; - unsigned long lost_events; - int leftover; - int ent_size; - int cpu; - u64 ts; - - loff_t pos; - long idx; - - /* All new field here will be zeroed out in pipe_read */ -}; - -enum trace_iter_flags { - TRACE_FILE_LAT_FMT = 1, - TRACE_FILE_ANNOTATE = 2, - TRACE_FILE_TIME_IN_NS = 4, -}; - - -typedef enum print_line_t (*trace_print_func)(struct trace_iterator *iter, - int flags, struct trace_event *event); - -struct trace_event_functions { - trace_print_func trace; - trace_print_func raw; - trace_print_func hex; - trace_print_func binary; -}; - -struct trace_event { - struct hlist_node node; - struct list_head list; - int type; - struct trace_event_functions *funcs; -}; - -extern int register_trace_event(struct trace_event *event); -extern int unregister_trace_event(struct trace_event *event); - -/* Return values for print_line callback */ -enum print_line_t { - TRACE_TYPE_PARTIAL_LINE = 0, /* Retry after flushing the seq */ - TRACE_TYPE_HANDLED = 1, - TRACE_TYPE_UNHANDLED = 2, /* Relay to other output functions */ - TRACE_TYPE_NO_CONSUME = 3 /* Handled but ask to not consume */ -}; - -/* - * Several functions return TRACE_TYPE_PARTIAL_LINE if the trace_seq - * overflowed, and TRACE_TYPE_HANDLED otherwise. This helper function - * simplifies those functions and keeps them in sync. - */ -static inline enum print_line_t trace_handle_return(struct trace_seq *s) -{ - return trace_seq_has_overflowed(s) ? - TRACE_TYPE_PARTIAL_LINE : TRACE_TYPE_HANDLED; -} - -void tracing_generic_entry_update(struct trace_entry *entry, - unsigned long flags, - int pc); -struct trace_event_file; - -struct ring_buffer_event * -trace_event_buffer_lock_reserve(struct ring_buffer **current_buffer, - struct trace_event_file *trace_file, - int type, unsigned long len, - unsigned long flags, int pc); - -void tracing_record_cmdline(struct task_struct *tsk); - -int trace_output_call(struct trace_iterator *iter, char *name, char *fmt, ...); - -struct event_filter; - -enum trace_reg { - TRACE_REG_REGISTER, - TRACE_REG_UNREGISTER, -#ifdef CONFIG_PERF_EVENTS - TRACE_REG_PERF_REGISTER, - TRACE_REG_PERF_UNREGISTER, - TRACE_REG_PERF_OPEN, - TRACE_REG_PERF_CLOSE, - TRACE_REG_PERF_ADD, - TRACE_REG_PERF_DEL, -#endif -}; - -struct trace_event_call; - -struct trace_event_class { - const char *system; - void *probe; -#ifdef CONFIG_PERF_EVENTS - void *perf_probe; -#endif - int (*reg)(struct trace_event_call *event, - enum trace_reg type, void *data); - int (*define_fields)(struct trace_event_call *); - struct list_head *(*get_fields)(struct trace_event_call *); - struct list_head fields; - int (*raw_init)(struct trace_event_call *); -}; - -extern int trace_event_reg(struct trace_event_call *event, - enum trace_reg type, void *data); - -struct trace_event_buffer { - struct ring_buffer *buffer; - struct ring_buffer_event *event; - struct trace_event_file *trace_file; - void *entry; - unsigned long flags; - int pc; -}; - -void *trace_event_buffer_reserve(struct trace_event_buffer *fbuffer, - struct trace_event_file *trace_file, - unsigned long len); - -void trace_event_buffer_commit(struct trace_event_buffer *fbuffer); - -enum { - TRACE_EVENT_FL_FILTERED_BIT, - TRACE_EVENT_FL_CAP_ANY_BIT, - TRACE_EVENT_FL_NO_SET_FILTER_BIT, - TRACE_EVENT_FL_IGNORE_ENABLE_BIT, - TRACE_EVENT_FL_WAS_ENABLED_BIT, - TRACE_EVENT_FL_TRACEPOINT_BIT, - TRACE_EVENT_FL_KPROBE_BIT, - TRACE_EVENT_FL_UPROBE_BIT, -}; - -/* - * Event flags: - * FILTERED - The event has a filter attached - * CAP_ANY - Any user can enable for perf - * NO_SET_FILTER - Set when filter has error and is to be ignored - * IGNORE_ENABLE - For trace internal events, do not enable with debugfs file - * WAS_ENABLED - Set and stays set when an event was ever enabled - * (used for module unloading, if a module event is enabled, - * it is best to clear the buffers that used it). - * TRACEPOINT - Event is a tracepoint - * KPROBE - Event is a kprobe - * UPROBE - Event is a uprobe - */ -enum { - TRACE_EVENT_FL_FILTERED = (1 << TRACE_EVENT_FL_FILTERED_BIT), - TRACE_EVENT_FL_CAP_ANY = (1 << TRACE_EVENT_FL_CAP_ANY_BIT), - TRACE_EVENT_FL_NO_SET_FILTER = (1 << TRACE_EVENT_FL_NO_SET_FILTER_BIT), - TRACE_EVENT_FL_IGNORE_ENABLE = (1 << TRACE_EVENT_FL_IGNORE_ENABLE_BIT), - TRACE_EVENT_FL_WAS_ENABLED = (1 << TRACE_EVENT_FL_WAS_ENABLED_BIT), - TRACE_EVENT_FL_TRACEPOINT = (1 << TRACE_EVENT_FL_TRACEPOINT_BIT), - TRACE_EVENT_FL_KPROBE = (1 << TRACE_EVENT_FL_KPROBE_BIT), - TRACE_EVENT_FL_UPROBE = (1 << TRACE_EVENT_FL_UPROBE_BIT), -}; - -#define TRACE_EVENT_FL_UKPROBE (TRACE_EVENT_FL_KPROBE | TRACE_EVENT_FL_UPROBE) - -struct trace_event_call { - struct list_head list; - struct trace_event_class *class; - union { - char *name; - /* Set TRACE_EVENT_FL_TRACEPOINT flag when using "tp" */ - struct tracepoint *tp; - }; - struct trace_event event; - char *print_fmt; - struct event_filter *filter; - void *mod; - void *data; - /* - * bit 0: filter_active - * bit 1: allow trace by non root (cap any) - * bit 2: failed to apply filter - * bit 3: trace internal event (do not enable) - * bit 4: Event was enabled by module - * bit 5: use call filter rather than file filter - * bit 6: Event is a tracepoint - */ - int flags; /* static flags of different events */ - -#ifdef CONFIG_PERF_EVENTS - int perf_refcount; - struct hlist_head __percpu *perf_events; - struct bpf_prog *prog; - - int (*perf_perm)(struct trace_event_call *, - struct perf_event *); -#endif -}; - -static inline const char * -trace_event_name(struct trace_event_call *call) -{ - if (call->flags & TRACE_EVENT_FL_TRACEPOINT) - return call->tp ? call->tp->name : NULL; - else - return call->name; -} - -struct trace_array; -struct trace_subsystem_dir; - -enum { - EVENT_FILE_FL_ENABLED_BIT, - EVENT_FILE_FL_RECORDED_CMD_BIT, - EVENT_FILE_FL_FILTERED_BIT, - EVENT_FILE_FL_NO_SET_FILTER_BIT, - EVENT_FILE_FL_SOFT_MODE_BIT, - EVENT_FILE_FL_SOFT_DISABLED_BIT, - EVENT_FILE_FL_TRIGGER_MODE_BIT, - EVENT_FILE_FL_TRIGGER_COND_BIT, - EVENT_FILE_FL_PID_FILTER_BIT, -}; - -/* - * Event file flags: - * ENABLED - The event is enabled - * RECORDED_CMD - The comms should be recorded at sched_switch - * FILTERED - The event has a filter attached - * NO_SET_FILTER - Set when filter has error and is to be ignored - * SOFT_MODE - The event is enabled/disabled by SOFT_DISABLED - * SOFT_DISABLED - When set, do not trace the event (even though its - * tracepoint may be enabled) - * TRIGGER_MODE - When set, invoke the triggers associated with the event - * TRIGGER_COND - When set, one or more triggers has an associated filter - * PID_FILTER - When set, the event is filtered based on pid - */ -enum { - EVENT_FILE_FL_ENABLED = (1 << EVENT_FILE_FL_ENABLED_BIT), - EVENT_FILE_FL_RECORDED_CMD = (1 << EVENT_FILE_FL_RECORDED_CMD_BIT), - EVENT_FILE_FL_FILTERED = (1 << EVENT_FILE_FL_FILTERED_BIT), - EVENT_FILE_FL_NO_SET_FILTER = (1 << EVENT_FILE_FL_NO_SET_FILTER_BIT), - EVENT_FILE_FL_SOFT_MODE = (1 << EVENT_FILE_FL_SOFT_MODE_BIT), - EVENT_FILE_FL_SOFT_DISABLED = (1 << EVENT_FILE_FL_SOFT_DISABLED_BIT), - EVENT_FILE_FL_TRIGGER_MODE = (1 << EVENT_FILE_FL_TRIGGER_MODE_BIT), - EVENT_FILE_FL_TRIGGER_COND = (1 << EVENT_FILE_FL_TRIGGER_COND_BIT), - EVENT_FILE_FL_PID_FILTER = (1 << EVENT_FILE_FL_PID_FILTER_BIT), -}; - -struct trace_event_file { - struct list_head list; - struct trace_event_call *event_call; - struct event_filter *filter; - struct dentry *dir; - struct trace_array *tr; - struct trace_subsystem_dir *system; - struct list_head triggers; - - /* - * 32 bit flags: - * bit 0: enabled - * bit 1: enabled cmd record - * bit 2: enable/disable with the soft disable bit - * bit 3: soft disabled - * bit 4: trigger enabled - * - * Note: The bits must be set atomically to prevent races - * from other writers. Reads of flags do not need to be in - * sync as they occur in critical sections. But the way flags - * is currently used, these changes do not affect the code - * except that when a change is made, it may have a slight - * delay in propagating the changes to other CPUs due to - * caching and such. Which is mostly OK ;-) - */ - unsigned long flags; - atomic_t sm_ref; /* soft-mode reference counter */ - atomic_t tm_ref; /* trigger-mode reference counter */ -}; - -#define __TRACE_EVENT_FLAGS(name, value) \ - static int __init trace_init_flags_##name(void) \ - { \ - event_##name.flags |= value; \ - return 0; \ - } \ - early_initcall(trace_init_flags_##name); - -#define __TRACE_EVENT_PERF_PERM(name, expr...) \ - static int perf_perm_##name(struct trace_event_call *tp_event, \ - struct perf_event *p_event) \ - { \ - return ({ expr; }); \ - } \ - static int __init trace_init_perf_perm_##name(void) \ - { \ - event_##name.perf_perm = &perf_perm_##name; \ - return 0; \ - } \ - early_initcall(trace_init_perf_perm_##name); - -#define PERF_MAX_TRACE_SIZE 2048 - -#define MAX_FILTER_STR_VAL 256 /* Should handle KSYM_SYMBOL_LEN */ - -enum event_trigger_type { - ETT_NONE = (0), - ETT_TRACE_ONOFF = (1 << 0), - ETT_SNAPSHOT = (1 << 1), - ETT_STACKTRACE = (1 << 2), - ETT_EVENT_ENABLE = (1 << 3), - ETT_EVENT_HIST = (1 << 4), - ETT_HIST_ENABLE = (1 << 5), -}; - -extern int filter_match_preds(struct event_filter *filter, void *rec); - -extern enum event_trigger_type event_triggers_call(struct trace_event_file *file, - void *rec); -extern void event_triggers_post_call(struct trace_event_file *file, - enum event_trigger_type tt, - void *rec); - -bool trace_event_ignore_this_pid(struct trace_event_file *trace_file); - -/** - * trace_trigger_soft_disabled - do triggers and test if soft disabled - * @file: The file pointer of the event to test - * - * If any triggers without filters are attached to this event, they - * will be called here. If the event is soft disabled and has no - * triggers that require testing the fields, it will return true, - * otherwise false. - */ -static inline bool -trace_trigger_soft_disabled(struct trace_event_file *file) -{ - unsigned long eflags = file->flags; - - if (!(eflags & EVENT_FILE_FL_TRIGGER_COND)) { - if (eflags & EVENT_FILE_FL_TRIGGER_MODE) - event_triggers_call(file, NULL); - if (eflags & EVENT_FILE_FL_SOFT_DISABLED) - return true; - if (eflags & EVENT_FILE_FL_PID_FILTER) - return trace_event_ignore_this_pid(file); - } - return false; -} - -#ifdef CONFIG_BPF_EVENTS -unsigned int trace_call_bpf(struct bpf_prog *prog, void *ctx); -#else -static inline unsigned int trace_call_bpf(struct bpf_prog *prog, void *ctx) -{ - return 1; -} -#endif - -enum { - FILTER_OTHER = 0, - FILTER_STATIC_STRING, - FILTER_DYN_STRING, - FILTER_PTR_STRING, - FILTER_TRACE_FN, - FILTER_COMM, - FILTER_CPU, -}; - -extern int trace_event_raw_init(struct trace_event_call *call); -extern int trace_define_field(struct trace_event_call *call, const char *type, - const char *name, int offset, int size, - int is_signed, int filter_type); -extern int trace_add_event_call(struct trace_event_call *call); -extern int trace_remove_event_call(struct trace_event_call *call); -extern int trace_event_get_offsets(struct trace_event_call *call); - -#define is_signed_type(type) (((type)(-1)) < (type)1) - -int trace_set_clr_event(const char *system, const char *event, int set); - -/* - * The double __builtin_constant_p is because gcc will give us an error - * if we try to allocate the static variable to fmt if it is not a - * constant. Even with the outer if statement optimizing out. - */ -#define event_trace_printk(ip, fmt, args...) \ -do { \ - __trace_printk_check_format(fmt, ##args); \ - tracing_record_cmdline(current); \ - if (__builtin_constant_p(fmt)) { \ - static const char *trace_printk_fmt \ - __attribute__((section("__trace_printk_fmt"))) = \ - __builtin_constant_p(fmt) ? fmt : NULL; \ - \ - __trace_bprintk(ip, trace_printk_fmt, ##args); \ - } else \ - __trace_printk(ip, fmt, ##args); \ -} while (0) - -#ifdef CONFIG_PERF_EVENTS -struct perf_event; - -DECLARE_PER_CPU(struct pt_regs, perf_trace_regs); - -extern int perf_trace_init(struct perf_event *event); -extern void perf_trace_destroy(struct perf_event *event); -extern int perf_trace_add(struct perf_event *event, int flags); -extern void perf_trace_del(struct perf_event *event, int flags); -extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, - char *filter_str); -extern void ftrace_profile_free_filter(struct perf_event *event); -void perf_trace_buf_update(void *record, u16 type); -void *perf_trace_buf_alloc(int size, struct pt_regs **regs, int *rctxp); - -void perf_trace_run_bpf_submit(void *raw_data, int size, int rctx, - struct trace_event_call *call, u64 count, - struct pt_regs *regs, struct hlist_head *head, - struct task_struct *task); - -static inline void -perf_trace_buf_submit(void *raw_data, int size, int rctx, u16 type, - u64 count, struct pt_regs *regs, void *head, - struct task_struct *task) -{ - perf_tp_event(type, count, raw_data, size, regs, head, rctx, task); -} -#endif - -#endif /* _LINUX_TRACE_EVENT_H */ diff --git a/src/linux/include/linux/trace_seq.h b/src/linux/include/linux/trace_seq.h deleted file mode 100644 index cfaf5a1..0000000 --- a/src/linux/include/linux/trace_seq.h +++ /dev/null @@ -1,138 +0,0 @@ -#ifndef _LINUX_TRACE_SEQ_H -#define _LINUX_TRACE_SEQ_H - -#include - -#include - -/* - * Trace sequences are used to allow a function to call several other functions - * to create a string of data to use (up to a max of PAGE_SIZE). - */ - -struct trace_seq { - unsigned char buffer[PAGE_SIZE]; - struct seq_buf seq; - int full; -}; - -static inline void -trace_seq_init(struct trace_seq *s) -{ - seq_buf_init(&s->seq, s->buffer, PAGE_SIZE); - s->full = 0; -} - -/** - * trace_seq_used - amount of actual data written to buffer - * @s: trace sequence descriptor - * - * Returns the amount of data written to the buffer. - * - * IMPORTANT! - * - * Use this instead of @s->seq.len if you need to pass the amount - * of data from the buffer to another buffer (userspace, or what not). - * The @s->seq.len on overflow is bigger than the buffer size and - * using it can cause access to undefined memory. - */ -static inline int trace_seq_used(struct trace_seq *s) -{ - return seq_buf_used(&s->seq); -} - -/** - * trace_seq_buffer_ptr - return pointer to next location in buffer - * @s: trace sequence descriptor - * - * Returns the pointer to the buffer where the next write to - * the buffer will happen. This is useful to save the location - * that is about to be written to and then return the result - * of that write. - */ -static inline unsigned char * -trace_seq_buffer_ptr(struct trace_seq *s) -{ - return s->buffer + seq_buf_used(&s->seq); -} - -/** - * trace_seq_has_overflowed - return true if the trace_seq took too much - * @s: trace sequence descriptor - * - * Returns true if too much data was added to the trace_seq and it is - * now full and will not take anymore. - */ -static inline bool trace_seq_has_overflowed(struct trace_seq *s) -{ - return s->full || seq_buf_has_overflowed(&s->seq); -} - -/* - * Currently only defined when tracing is enabled. - */ -#ifdef CONFIG_TRACING -extern __printf(2, 3) -void trace_seq_printf(struct trace_seq *s, const char *fmt, ...); -extern __printf(2, 0) -void trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args); -extern void -trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary); -extern int trace_print_seq(struct seq_file *m, struct trace_seq *s); -extern int trace_seq_to_user(struct trace_seq *s, char __user *ubuf, - int cnt); -extern void trace_seq_puts(struct trace_seq *s, const char *str); -extern void trace_seq_putc(struct trace_seq *s, unsigned char c); -extern void trace_seq_putmem(struct trace_seq *s, const void *mem, unsigned int len); -extern void trace_seq_putmem_hex(struct trace_seq *s, const void *mem, - unsigned int len); -extern int trace_seq_path(struct trace_seq *s, const struct path *path); - -extern void trace_seq_bitmask(struct trace_seq *s, const unsigned long *maskp, - int nmaskbits); - -#else /* CONFIG_TRACING */ -static inline void trace_seq_printf(struct trace_seq *s, const char *fmt, ...) -{ -} -static inline void -trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary) -{ -} - -static inline void -trace_seq_bitmask(struct trace_seq *s, const unsigned long *maskp, - int nmaskbits) -{ -} - -static inline int trace_print_seq(struct seq_file *m, struct trace_seq *s) -{ - return 0; -} -static inline int trace_seq_to_user(struct trace_seq *s, char __user *ubuf, - int cnt) -{ - return 0; -} -static inline void trace_seq_puts(struct trace_seq *s, const char *str) -{ -} -static inline void trace_seq_putc(struct trace_seq *s, unsigned char c) -{ -} -static inline void -trace_seq_putmem(struct trace_seq *s, const void *mem, unsigned int len) -{ -} -static inline void trace_seq_putmem_hex(struct trace_seq *s, const void *mem, - unsigned int len) -{ -} -static inline int trace_seq_path(struct trace_seq *s, const struct path *path) -{ - return 0; -} -#endif /* CONFIG_TRACING */ - -#endif /* _LINUX_TRACE_SEQ_H */ diff --git a/src/linux/include/linux/tracehook.h b/src/linux/include/linux/tracehook.h deleted file mode 100644 index 26c1521..0000000 --- a/src/linux/include/linux/tracehook.h +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Tracing hooks - * - * Copyright (C) 2008-2009 Red Hat, Inc. All rights reserved. - * - * This copyrighted material is made available to anyone wishing to use, - * modify, copy, or redistribute it subject to the terms and conditions - * of the GNU General Public License v.2. - * - * This file defines hook entry points called by core code where - * user tracing/debugging support might need to do something. These - * entry points are called tracehook_*(). Each hook declared below - * has a detailed kerneldoc comment giving the context (locking et - * al) from which it is called, and the meaning of its return value. - * - * Each function here typically has only one call site, so it is ok - * to have some nontrivial tracehook_*() inlines. In all cases, the - * fast path when no tracing is enabled should be very short. - * - * The purpose of this file and the tracehook_* layer is to consolidate - * the interface that the kernel core and arch code uses to enable any - * user debugging or tracing facility (such as ptrace). The interfaces - * here are carefully documented so that maintainers of core and arch - * code do not need to think about the implementation details of the - * tracing facilities. Likewise, maintainers of the tracing code do not - * need to understand all the calling core or arch code in detail, just - * documented circumstances of each call, such as locking conditions. - * - * If the calling core code changes so that locking is different, then - * it is ok to change the interface documented here. The maintainer of - * core code changing should notify the maintainers of the tracing code - * that they need to work out the change. - * - * Some tracehook_*() inlines take arguments that the current tracing - * implementations might not necessarily use. These function signatures - * are chosen to pass in all the information that is on hand in the - * caller and might conceivably be relevant to a tracer, so that the - * core code won't have to be updated when tracing adds more features. - * If a call site changes so that some of those parameters are no longer - * already on hand without extra work, then the tracehook_* interface - * can change so there is no make-work burden on the core code. The - * maintainer of core code changing should notify the maintainers of the - * tracing code that they need to work out the change. - */ - -#ifndef _LINUX_TRACEHOOK_H -#define _LINUX_TRACEHOOK_H 1 - -#include -#include -#include -#include -#include -struct linux_binprm; - -/* - * ptrace report for syscall entry and exit looks identical. - */ -static inline int ptrace_report_syscall(struct pt_regs *regs) -{ - int ptrace = current->ptrace; - - if (!(ptrace & PT_PTRACED)) - return 0; - - ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0)); - - /* - * this isn't the same as continuing with a signal, but it will do - * for normal use. strace only continues with a signal if the - * stopping signal is not SIGTRAP. -brl - */ - if (current->exit_code) { - send_sig(current->exit_code, current, 1); - current->exit_code = 0; - } - - return fatal_signal_pending(current); -} - -/** - * tracehook_report_syscall_entry - task is about to attempt a system call - * @regs: user register state of current task - * - * This will be called if %TIF_SYSCALL_TRACE has been set, when the - * current task has just entered the kernel for a system call. - * Full user register state is available here. Changing the values - * in @regs can affect the system call number and arguments to be tried. - * It is safe to block here, preventing the system call from beginning. - * - * Returns zero normally, or nonzero if the calling arch code should abort - * the system call. That must prevent normal entry so no system call is - * made. If @task ever returns to user mode after this, its register state - * is unspecified, but should be something harmless like an %ENOSYS error - * return. It should preserve enough information so that syscall_rollback() - * can work (see asm-generic/syscall.h). - * - * Called without locks, just after entering kernel mode. - */ -static inline __must_check int tracehook_report_syscall_entry( - struct pt_regs *regs) -{ - return ptrace_report_syscall(regs); -} - -/** - * tracehook_report_syscall_exit - task has just finished a system call - * @regs: user register state of current task - * @step: nonzero if simulating single-step or block-step - * - * This will be called if %TIF_SYSCALL_TRACE has been set, when the - * current task has just finished an attempted system call. Full - * user register state is available here. It is safe to block here, - * preventing signals from being processed. - * - * If @step is nonzero, this report is also in lieu of the normal - * trap that would follow the system call instruction because - * user_enable_block_step() or user_enable_single_step() was used. - * In this case, %TIF_SYSCALL_TRACE might not be set. - * - * Called without locks, just before checking for pending signals. - */ -static inline void tracehook_report_syscall_exit(struct pt_regs *regs, int step) -{ - if (step) { - siginfo_t info; - user_single_step_siginfo(current, regs, &info); - force_sig_info(SIGTRAP, &info, current); - return; - } - - ptrace_report_syscall(regs); -} - -/** - * tracehook_signal_handler - signal handler setup is complete - * @stepping: nonzero if debugger single-step or block-step in use - * - * Called by the arch code after a signal handler has been set up. - * Register and stack state reflects the user handler about to run. - * Signal mask changes have already been made. - * - * Called without locks, shortly before returning to user mode - * (or handling more signals). - */ -static inline void tracehook_signal_handler(int stepping) -{ - if (stepping) - ptrace_notify(SIGTRAP); -} - -/** - * set_notify_resume - cause tracehook_notify_resume() to be called - * @task: task that will call tracehook_notify_resume() - * - * Calling this arranges that @task will call tracehook_notify_resume() - * before returning to user mode. If it's already running in user mode, - * it will enter the kernel and call tracehook_notify_resume() soon. - * If it's blocked, it will not be woken. - */ -static inline void set_notify_resume(struct task_struct *task) -{ -#ifdef TIF_NOTIFY_RESUME - if (!test_and_set_tsk_thread_flag(task, TIF_NOTIFY_RESUME)) - kick_process(task); -#endif -} - -/** - * tracehook_notify_resume - report when about to return to user mode - * @regs: user-mode registers of @current task - * - * This is called when %TIF_NOTIFY_RESUME has been set. Now we are - * about to return to user mode, and the user state in @regs can be - * inspected or adjusted. The caller in arch code has cleared - * %TIF_NOTIFY_RESUME before the call. If the flag gets set again - * asynchronously, this will be called again before we return to - * user mode. - * - * Called without locks. - */ -static inline void tracehook_notify_resume(struct pt_regs *regs) -{ - /* - * The caller just cleared TIF_NOTIFY_RESUME. This barrier - * pairs with task_work_add()->set_notify_resume() after - * hlist_add_head(task->task_works); - */ - smp_mb__after_atomic(); - if (unlikely(current->task_works)) - task_work_run(); - - mem_cgroup_handle_over_high(); -} - -#endif /* */ diff --git a/src/linux/include/linux/tracepoint-defs.h b/src/linux/include/linux/tracepoint-defs.h deleted file mode 100644 index 4ac89ac..0000000 --- a/src/linux/include/linux/tracepoint-defs.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef TRACEPOINT_DEFS_H -#define TRACEPOINT_DEFS_H 1 - -/* - * File can be included directly by headers who only want to access - * tracepoint->key to guard out of line trace calls, or the definition of - * trace_print_flags{_u64}. Otherwise linux/tracepoint.h should be used. - */ - -#include -#include - -struct trace_print_flags { - unsigned long mask; - const char *name; -}; - -struct trace_print_flags_u64 { - unsigned long long mask; - const char *name; -}; - -struct tracepoint_func { - void *func; - void *data; - int prio; -}; - -struct tracepoint { - const char *name; /* Tracepoint name */ - struct static_key key; - void (*regfunc)(void); - void (*unregfunc)(void); - struct tracepoint_func __rcu *funcs; -}; - -#endif diff --git a/src/linux/include/linux/tracepoint.h b/src/linux/include/linux/tracepoint.h deleted file mode 100644 index be586c6..0000000 --- a/src/linux/include/linux/tracepoint.h +++ /dev/null @@ -1,501 +0,0 @@ -#ifndef _LINUX_TRACEPOINT_H -#define _LINUX_TRACEPOINT_H - -/* - * Kernel Tracepoint API. - * - * See Documentation/trace/tracepoints.txt. - * - * Copyright (C) 2008-2014 Mathieu Desnoyers - * - * Heavily inspired from the Linux Kernel Markers. - * - * This file is released under the GPLv2. - * See the file COPYING for more details. - */ - -#include -#include -#include -#include -#include -#include - -struct module; -struct tracepoint; -struct notifier_block; - -struct trace_enum_map { - const char *system; - const char *enum_string; - unsigned long enum_value; -}; - -#define TRACEPOINT_DEFAULT_PRIO 10 - -extern int -tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data); -extern int -tracepoint_probe_register_prio(struct tracepoint *tp, void *probe, void *data, - int prio); -extern int -tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data); -extern void -for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv), - void *priv); - -#ifdef CONFIG_MODULES -struct tp_module { - struct list_head list; - struct module *mod; -}; - -bool trace_module_has_bad_taint(struct module *mod); -extern int register_tracepoint_module_notifier(struct notifier_block *nb); -extern int unregister_tracepoint_module_notifier(struct notifier_block *nb); -#else -static inline bool trace_module_has_bad_taint(struct module *mod) -{ - return false; -} -static inline -int register_tracepoint_module_notifier(struct notifier_block *nb) -{ - return 0; -} -static inline -int unregister_tracepoint_module_notifier(struct notifier_block *nb) -{ - return 0; -} -#endif /* CONFIG_MODULES */ - -/* - * tracepoint_synchronize_unregister must be called between the last tracepoint - * probe unregistration and the end of module exit to make sure there is no - * caller executing a probe when it is freed. - */ -static inline void tracepoint_synchronize_unregister(void) -{ - synchronize_sched(); -} - -#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS -extern void syscall_regfunc(void); -extern void syscall_unregfunc(void); -#endif /* CONFIG_HAVE_SYSCALL_TRACEPOINTS */ - -#define PARAMS(args...) args - -#define TRACE_DEFINE_ENUM(x) - -#endif /* _LINUX_TRACEPOINT_H */ - -/* - * Note: we keep the TRACE_EVENT and DECLARE_TRACE outside the include - * file ifdef protection. - * This is due to the way trace events work. If a file includes two - * trace event headers under one "CREATE_TRACE_POINTS" the first include - * will override the TRACE_EVENT and break the second include. - */ - -#ifndef DECLARE_TRACE - -#define TP_PROTO(args...) args -#define TP_ARGS(args...) args -#define TP_CONDITION(args...) args - -/* - * Individual subsystem my have a separate configuration to - * enable their tracepoints. By default, this file will create - * the tracepoints if CONFIG_TRACEPOINT is defined. If a subsystem - * wants to be able to disable its tracepoints from being created - * it can define NOTRACE before including the tracepoint headers. - */ -#if defined(CONFIG_TRACEPOINTS) && !defined(NOTRACE) -#define TRACEPOINTS_ENABLED -#endif - -#ifdef TRACEPOINTS_ENABLED - -/* - * it_func[0] is never NULL because there is at least one element in the array - * when the array itself is non NULL. - * - * Note, the proto and args passed in includes "__data" as the first parameter. - * The reason for this is to handle the "void" prototype. If a tracepoint - * has a "void" prototype, then it is invalid to declare a function - * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just - * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto". - */ -#define __DO_TRACE(tp, proto, args, cond, prercu, postrcu) \ - do { \ - struct tracepoint_func *it_func_ptr; \ - void *it_func; \ - void *__data; \ - \ - if (!(cond)) \ - return; \ - prercu; \ - rcu_read_lock_sched_notrace(); \ - it_func_ptr = rcu_dereference_sched((tp)->funcs); \ - if (it_func_ptr) { \ - do { \ - it_func = (it_func_ptr)->func; \ - __data = (it_func_ptr)->data; \ - ((void(*)(proto))(it_func))(args); \ - } while ((++it_func_ptr)->func); \ - } \ - rcu_read_unlock_sched_notrace(); \ - postrcu; \ - } while (0) - -#ifndef MODULE -#define __DECLARE_TRACE_RCU(name, proto, args, cond, data_proto, data_args) \ - static inline void trace_##name##_rcuidle(proto) \ - { \ - if (static_key_false(&__tracepoint_##name.key)) \ - __DO_TRACE(&__tracepoint_##name, \ - TP_PROTO(data_proto), \ - TP_ARGS(data_args), \ - TP_CONDITION(cond), \ - rcu_irq_enter_irqson(), \ - rcu_irq_exit_irqson()); \ - } -#else -#define __DECLARE_TRACE_RCU(name, proto, args, cond, data_proto, data_args) -#endif - -/* - * Make sure the alignment of the structure in the __tracepoints section will - * not add unwanted padding between the beginning of the section and the - * structure. Force alignment to the same alignment as the section start. - * - * When lockdep is enabled, we make sure to always do the RCU portions of - * the tracepoint code, regardless of whether tracing is on. However, - * don't check if the condition is false, due to interaction with idle - * instrumentation. This lets us find RCU issues triggered with tracepoints - * even when this tracepoint is off. This code has no purpose other than - * poking RCU a bit. - */ -#define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \ - extern struct tracepoint __tracepoint_##name; \ - static inline void trace_##name(proto) \ - { \ - if (static_key_false(&__tracepoint_##name.key)) \ - __DO_TRACE(&__tracepoint_##name, \ - TP_PROTO(data_proto), \ - TP_ARGS(data_args), \ - TP_CONDITION(cond),,); \ - if (IS_ENABLED(CONFIG_LOCKDEP) && (cond)) { \ - rcu_read_lock_sched_notrace(); \ - rcu_dereference_sched(__tracepoint_##name.funcs);\ - rcu_read_unlock_sched_notrace(); \ - } \ - } \ - __DECLARE_TRACE_RCU(name, PARAMS(proto), PARAMS(args), \ - PARAMS(cond), PARAMS(data_proto), PARAMS(data_args)) \ - static inline int \ - register_trace_##name(void (*probe)(data_proto), void *data) \ - { \ - return tracepoint_probe_register(&__tracepoint_##name, \ - (void *)probe, data); \ - } \ - static inline int \ - register_trace_prio_##name(void (*probe)(data_proto), void *data,\ - int prio) \ - { \ - return tracepoint_probe_register_prio(&__tracepoint_##name, \ - (void *)probe, data, prio); \ - } \ - static inline int \ - unregister_trace_##name(void (*probe)(data_proto), void *data) \ - { \ - return tracepoint_probe_unregister(&__tracepoint_##name,\ - (void *)probe, data); \ - } \ - static inline void \ - check_trace_callback_type_##name(void (*cb)(data_proto)) \ - { \ - } \ - static inline bool \ - trace_##name##_enabled(void) \ - { \ - return static_key_false(&__tracepoint_##name.key); \ - } - -/* - * We have no guarantee that gcc and the linker won't up-align the tracepoint - * structures, so we create an array of pointers that will be used for iteration - * on the tracepoints. - */ -#define DEFINE_TRACE_FN(name, reg, unreg) \ - static const char __tpstrtab_##name[] \ - __attribute__((section("__tracepoints_strings"))) = #name; \ - struct tracepoint __tracepoint_##name \ - __attribute__((section("__tracepoints"))) = \ - { __tpstrtab_##name, STATIC_KEY_INIT_FALSE, reg, unreg, NULL };\ - static struct tracepoint * const __tracepoint_ptr_##name __used \ - __attribute__((section("__tracepoints_ptrs"))) = \ - &__tracepoint_##name; - -#define DEFINE_TRACE(name) \ - DEFINE_TRACE_FN(name, NULL, NULL); - -#define EXPORT_TRACEPOINT_SYMBOL_GPL(name) \ - EXPORT_SYMBOL_GPL(__tracepoint_##name) -#define EXPORT_TRACEPOINT_SYMBOL(name) \ - EXPORT_SYMBOL(__tracepoint_##name) - -#else /* !TRACEPOINTS_ENABLED */ -#define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \ - static inline void trace_##name(proto) \ - { } \ - static inline void trace_##name##_rcuidle(proto) \ - { } \ - static inline int \ - register_trace_##name(void (*probe)(data_proto), \ - void *data) \ - { \ - return -ENOSYS; \ - } \ - static inline int \ - unregister_trace_##name(void (*probe)(data_proto), \ - void *data) \ - { \ - return -ENOSYS; \ - } \ - static inline void check_trace_callback_type_##name(void (*cb)(data_proto)) \ - { \ - } \ - static inline bool \ - trace_##name##_enabled(void) \ - { \ - return false; \ - } - -#define DEFINE_TRACE_FN(name, reg, unreg) -#define DEFINE_TRACE(name) -#define EXPORT_TRACEPOINT_SYMBOL_GPL(name) -#define EXPORT_TRACEPOINT_SYMBOL(name) - -#endif /* TRACEPOINTS_ENABLED */ - -#ifdef CONFIG_TRACING -/** - * tracepoint_string - register constant persistent string to trace system - * @str - a constant persistent string that will be referenced in tracepoints - * - * If constant strings are being used in tracepoints, it is faster and - * more efficient to just save the pointer to the string and reference - * that with a printf "%s" instead of saving the string in the ring buffer - * and wasting space and time. - * - * The problem with the above approach is that userspace tools that read - * the binary output of the trace buffers do not have access to the string. - * Instead they just show the address of the string which is not very - * useful to users. - * - * With tracepoint_string(), the string will be registered to the tracing - * system and exported to userspace via the debugfs/tracing/printk_formats - * file that maps the string address to the string text. This way userspace - * tools that read the binary buffers have a way to map the pointers to - * the ASCII strings they represent. - * - * The @str used must be a constant string and persistent as it would not - * make sense to show a string that no longer exists. But it is still fine - * to be used with modules, because when modules are unloaded, if they - * had tracepoints, the ring buffers are cleared too. As long as the string - * does not change during the life of the module, it is fine to use - * tracepoint_string() within a module. - */ -#define tracepoint_string(str) \ - ({ \ - static const char *___tp_str __tracepoint_string = str; \ - ___tp_str; \ - }) -#define __tracepoint_string __attribute__((section("__tracepoint_str"))) -#else -/* - * tracepoint_string() is used to save the string address for userspace - * tracing tools. When tracing isn't configured, there's no need to save - * anything. - */ -# define tracepoint_string(str) str -# define __tracepoint_string -#endif - -/* - * The need for the DECLARE_TRACE_NOARGS() is to handle the prototype - * (void). "void" is a special value in a function prototype and can - * not be combined with other arguments. Since the DECLARE_TRACE() - * macro adds a data element at the beginning of the prototype, - * we need a way to differentiate "(void *data, proto)" from - * "(void *data, void)". The second prototype is invalid. - * - * DECLARE_TRACE_NOARGS() passes "void" as the tracepoint prototype - * and "void *__data" as the callback prototype. - * - * DECLARE_TRACE() passes "proto" as the tracepoint protoype and - * "void *__data, proto" as the callback prototype. - */ -#define DECLARE_TRACE_NOARGS(name) \ - __DECLARE_TRACE(name, void, , \ - cpu_online(raw_smp_processor_id()), \ - void *__data, __data) - -#define DECLARE_TRACE(name, proto, args) \ - __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \ - cpu_online(raw_smp_processor_id()), \ - PARAMS(void *__data, proto), \ - PARAMS(__data, args)) - -#define DECLARE_TRACE_CONDITION(name, proto, args, cond) \ - __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \ - cpu_online(raw_smp_processor_id()) && (PARAMS(cond)), \ - PARAMS(void *__data, proto), \ - PARAMS(__data, args)) - -#define TRACE_EVENT_FLAGS(event, flag) - -#define TRACE_EVENT_PERF_PERM(event, expr...) - -#endif /* DECLARE_TRACE */ - -#ifndef TRACE_EVENT -/* - * For use with the TRACE_EVENT macro: - * - * We define a tracepoint, its arguments, its printk format - * and its 'fast binary record' layout. - * - * Firstly, name your tracepoint via TRACE_EVENT(name : the - * 'subsystem_event' notation is fine. - * - * Think about this whole construct as the - * 'trace_sched_switch() function' from now on. - * - * - * TRACE_EVENT(sched_switch, - * - * * - * * A function has a regular function arguments - * * prototype, declare it via TP_PROTO(): - * * - * - * TP_PROTO(struct rq *rq, struct task_struct *prev, - * struct task_struct *next), - * - * * - * * Define the call signature of the 'function'. - * * (Design sidenote: we use this instead of a - * * TP_PROTO1/TP_PROTO2/TP_PROTO3 ugliness.) - * * - * - * TP_ARGS(rq, prev, next), - * - * * - * * Fast binary tracing: define the trace record via - * * TP_STRUCT__entry(). You can think about it like a - * * regular C structure local variable definition. - * * - * * This is how the trace record is structured and will - * * be saved into the ring buffer. These are the fields - * * that will be exposed to user-space in - * * /sys/kernel/debug/tracing/events/<*>/format. - * * - * * The declared 'local variable' is called '__entry' - * * - * * __field(pid_t, prev_prid) is equivalent to a standard declariton: - * * - * * pid_t prev_pid; - * * - * * __array(char, prev_comm, TASK_COMM_LEN) is equivalent to: - * * - * * char prev_comm[TASK_COMM_LEN]; - * * - * - * TP_STRUCT__entry( - * __array( char, prev_comm, TASK_COMM_LEN ) - * __field( pid_t, prev_pid ) - * __field( int, prev_prio ) - * __array( char, next_comm, TASK_COMM_LEN ) - * __field( pid_t, next_pid ) - * __field( int, next_prio ) - * ), - * - * * - * * Assign the entry into the trace record, by embedding - * * a full C statement block into TP_fast_assign(). You - * * can refer to the trace record as '__entry' - - * * otherwise you can put arbitrary C code in here. - * * - * * Note: this C code will execute every time a trace event - * * happens, on an active tracepoint. - * * - * - * TP_fast_assign( - * memcpy(__entry->next_comm, next->comm, TASK_COMM_LEN); - * __entry->prev_pid = prev->pid; - * __entry->prev_prio = prev->prio; - * memcpy(__entry->prev_comm, prev->comm, TASK_COMM_LEN); - * __entry->next_pid = next->pid; - * __entry->next_prio = next->prio; - * ), - * - * * - * * Formatted output of a trace record via TP_printk(). - * * This is how the tracepoint will appear under ftrace - * * plugins that make use of this tracepoint. - * * - * * (raw-binary tracing wont actually perform this step.) - * * - * - * TP_printk("task %s:%d [%d] ==> %s:%d [%d]", - * __entry->prev_comm, __entry->prev_pid, __entry->prev_prio, - * __entry->next_comm, __entry->next_pid, __entry->next_prio), - * - * ); - * - * This macro construct is thus used for the regular printk format - * tracing setup, it is used to construct a function pointer based - * tracepoint callback (this is used by programmatic plugins and - * can also by used by generic instrumentation like SystemTap), and - * it is also used to expose a structured trace record in - * /sys/kernel/debug/tracing/events/. - * - * A set of (un)registration functions can be passed to the variant - * TRACE_EVENT_FN to perform any (un)registration work. - */ - -#define DECLARE_EVENT_CLASS(name, proto, args, tstruct, assign, print) -#define DEFINE_EVENT(template, name, proto, args) \ - DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) -#define DEFINE_EVENT_FN(template, name, proto, args, reg, unreg)\ - DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) -#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \ - DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) -#define DEFINE_EVENT_CONDITION(template, name, proto, \ - args, cond) \ - DECLARE_TRACE_CONDITION(name, PARAMS(proto), \ - PARAMS(args), PARAMS(cond)) - -#define TRACE_EVENT(name, proto, args, struct, assign, print) \ - DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) -#define TRACE_EVENT_FN(name, proto, args, struct, \ - assign, print, reg, unreg) \ - DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) -#define TRACE_EVENT_FN_COND(name, proto, args, cond, struct, \ - assign, print, reg, unreg) \ - DECLARE_TRACE_CONDITION(name, PARAMS(proto), \ - PARAMS(args), PARAMS(cond)) -#define TRACE_EVENT_CONDITION(name, proto, args, cond, \ - struct, assign, print) \ - DECLARE_TRACE_CONDITION(name, PARAMS(proto), \ - PARAMS(args), PARAMS(cond)) - -#define TRACE_EVENT_FLAGS(event, flag) - -#define TRACE_EVENT_PERF_PERM(event, expr...) - -#endif /* ifdef TRACE_EVENT (see note above) */ diff --git a/src/linux/include/linux/transport_class.h b/src/linux/include/linux/transport_class.h deleted file mode 100644 index 11087cd..0000000 --- a/src/linux/include/linux/transport_class.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * transport_class.h - a generic container for all transport classes - * - * Copyright (c) 2005 - James Bottomley - * - * This file is licensed under GPLv2 - */ - -#ifndef _TRANSPORT_CLASS_H_ -#define _TRANSPORT_CLASS_H_ - -#include -#include -#include - -struct transport_container; - -struct transport_class { - struct class class; - int (*setup)(struct transport_container *, struct device *, - struct device *); - int (*configure)(struct transport_container *, struct device *, - struct device *); - int (*remove)(struct transport_container *, struct device *, - struct device *); -}; - -#define DECLARE_TRANSPORT_CLASS(cls, nm, su, rm, cfg) \ -struct transport_class cls = { \ - .class = { \ - .name = nm, \ - }, \ - .setup = su, \ - .remove = rm, \ - .configure = cfg, \ -} - - -struct anon_transport_class { - struct transport_class tclass; - struct attribute_container container; -}; - -#define DECLARE_ANON_TRANSPORT_CLASS(cls, mtch, cfg) \ -struct anon_transport_class cls = { \ - .tclass = { \ - .configure = cfg, \ - }, \ - . container = { \ - .match = mtch, \ - }, \ -} - -#define class_to_transport_class(x) \ - container_of(x, struct transport_class, class) - -struct transport_container { - struct attribute_container ac; - const struct attribute_group *statistics; -}; - -#define attribute_container_to_transport_container(x) \ - container_of(x, struct transport_container, ac) - -void transport_remove_device(struct device *); -void transport_add_device(struct device *); -void transport_setup_device(struct device *); -void transport_configure_device(struct device *); -void transport_destroy_device(struct device *); - -static inline void -transport_register_device(struct device *dev) -{ - transport_setup_device(dev); - transport_add_device(dev); -} - -static inline void -transport_unregister_device(struct device *dev) -{ - transport_remove_device(dev); - transport_destroy_device(dev); -} - -static inline int transport_container_register(struct transport_container *tc) -{ - return attribute_container_register(&tc->ac); -} - -static inline void transport_container_unregister(struct transport_container *tc) -{ - if (unlikely(attribute_container_unregister(&tc->ac))) - BUG(); -} - -int transport_class_register(struct transport_class *); -int anon_transport_class_register(struct anon_transport_class *); -void transport_class_unregister(struct transport_class *); -void anon_transport_class_unregister(struct anon_transport_class *); - - -#endif diff --git a/src/linux/include/linux/tsacct_kern.h b/src/linux/include/linux/tsacct_kern.h deleted file mode 100644 index 3251965..0000000 --- a/src/linux/include/linux/tsacct_kern.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * tsacct_kern.h - kernel header for system accounting over taskstats interface - * - * Copyright (C) Jay Lan SGI - */ - -#ifndef _LINUX_TSACCT_KERN_H -#define _LINUX_TSACCT_KERN_H - -#include - -#ifdef CONFIG_TASKSTATS -extern void bacct_add_tsk(struct user_namespace *user_ns, - struct pid_namespace *pid_ns, - struct taskstats *stats, struct task_struct *tsk); -#else -static inline void bacct_add_tsk(struct user_namespace *user_ns, - struct pid_namespace *pid_ns, - struct taskstats *stats, struct task_struct *tsk) -{} -#endif /* CONFIG_TASKSTATS */ - -#ifdef CONFIG_TASK_XACCT -extern void xacct_add_tsk(struct taskstats *stats, struct task_struct *p); -extern void acct_update_integrals(struct task_struct *tsk); -extern void acct_account_cputime(struct task_struct *tsk); -extern void acct_clear_integrals(struct task_struct *tsk); -#else -static inline void xacct_add_tsk(struct taskstats *stats, struct task_struct *p) -{} -static inline void acct_update_integrals(struct task_struct *tsk) -{} -static inline void acct_account_cputime(struct task_struct *tsk) -{} -static inline void acct_clear_integrals(struct task_struct *tsk) -{} -#endif /* CONFIG_TASK_XACCT */ - -#endif - - diff --git a/src/linux/include/linux/tty.h b/src/linux/include/linux/tty.h deleted file mode 100644 index 40144f3..0000000 --- a/src/linux/include/linux/tty.h +++ /dev/null @@ -1,737 +0,0 @@ -#ifndef _LINUX_TTY_H -#define _LINUX_TTY_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * Lock subclasses for tty locks - * - * TTY_LOCK_NORMAL is for normal ttys and master ptys. - * TTY_LOCK_SLAVE is for slave ptys only. - * - * Lock subclasses are necessary for handling nested locking with pty pairs. - * tty locks which use nested locking: - * - * legacy_mutex - Nested tty locks are necessary for releasing pty pairs. - * The stable lock order is master pty first, then slave pty. - * termios_rwsem - The stable lock order is tty_buffer lock->termios_rwsem. - * Subclassing this lock enables the slave pty to hold its - * termios_rwsem when claiming the master tty_buffer lock. - * tty_buffer lock - slave ptys can claim nested buffer lock when handling - * signal chars. The stable lock order is slave pty, then - * master. - */ - -enum { - TTY_LOCK_NORMAL = 0, - TTY_LOCK_SLAVE, -}; - -/* - * (Note: the *_driver.minor_start values 1, 64, 128, 192 are - * hardcoded at present.) - */ -#define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ -#define NR_UNIX98_PTY_RESERVE 1024 /* Default reserve for main devpts */ -#define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ - -/* - * This character is the same as _POSIX_VDISABLE: it cannot be used as - * a c_cc[] character, but indicates that a particular special character - * isn't in use (eg VINTR has no character etc) - */ -#define __DISABLED_CHAR '\0' - -struct tty_buffer { - union { - struct tty_buffer *next; - struct llist_node free; - }; - int used; - int size; - int commit; - int read; - int flags; - /* Data points here */ - unsigned long data[0]; -}; - -/* Values for .flags field of tty_buffer */ -#define TTYB_NORMAL 1 /* buffer has no flags buffer */ - -static inline unsigned char *char_buf_ptr(struct tty_buffer *b, int ofs) -{ - return ((unsigned char *)b->data) + ofs; -} - -static inline char *flag_buf_ptr(struct tty_buffer *b, int ofs) -{ - return (char *)char_buf_ptr(b, ofs) + b->size; -} - -struct tty_bufhead { - struct tty_buffer *head; /* Queue head */ - struct work_struct work; - struct mutex lock; - atomic_t priority; - struct tty_buffer sentinel; - struct llist_head free; /* Free queue head */ - atomic_t mem_used; /* In-use buffers excluding free list */ - int mem_limit; - struct tty_buffer *tail; /* Active buffer */ -}; -/* - * When a break, frame error, or parity error happens, these codes are - * stuffed into the flags buffer. - */ -#define TTY_NORMAL 0 -#define TTY_BREAK 1 -#define TTY_FRAME 2 -#define TTY_PARITY 3 -#define TTY_OVERRUN 4 - -#define INTR_CHAR(tty) ((tty)->termios.c_cc[VINTR]) -#define QUIT_CHAR(tty) ((tty)->termios.c_cc[VQUIT]) -#define ERASE_CHAR(tty) ((tty)->termios.c_cc[VERASE]) -#define KILL_CHAR(tty) ((tty)->termios.c_cc[VKILL]) -#define EOF_CHAR(tty) ((tty)->termios.c_cc[VEOF]) -#define TIME_CHAR(tty) ((tty)->termios.c_cc[VTIME]) -#define MIN_CHAR(tty) ((tty)->termios.c_cc[VMIN]) -#define SWTC_CHAR(tty) ((tty)->termios.c_cc[VSWTC]) -#define START_CHAR(tty) ((tty)->termios.c_cc[VSTART]) -#define STOP_CHAR(tty) ((tty)->termios.c_cc[VSTOP]) -#define SUSP_CHAR(tty) ((tty)->termios.c_cc[VSUSP]) -#define EOL_CHAR(tty) ((tty)->termios.c_cc[VEOL]) -#define REPRINT_CHAR(tty) ((tty)->termios.c_cc[VREPRINT]) -#define DISCARD_CHAR(tty) ((tty)->termios.c_cc[VDISCARD]) -#define WERASE_CHAR(tty) ((tty)->termios.c_cc[VWERASE]) -#define LNEXT_CHAR(tty) ((tty)->termios.c_cc[VLNEXT]) -#define EOL2_CHAR(tty) ((tty)->termios.c_cc[VEOL2]) - -#define _I_FLAG(tty, f) ((tty)->termios.c_iflag & (f)) -#define _O_FLAG(tty, f) ((tty)->termios.c_oflag & (f)) -#define _C_FLAG(tty, f) ((tty)->termios.c_cflag & (f)) -#define _L_FLAG(tty, f) ((tty)->termios.c_lflag & (f)) - -#define I_IGNBRK(tty) _I_FLAG((tty), IGNBRK) -#define I_BRKINT(tty) _I_FLAG((tty), BRKINT) -#define I_IGNPAR(tty) _I_FLAG((tty), IGNPAR) -#define I_PARMRK(tty) _I_FLAG((tty), PARMRK) -#define I_INPCK(tty) _I_FLAG((tty), INPCK) -#define I_ISTRIP(tty) _I_FLAG((tty), ISTRIP) -#define I_INLCR(tty) _I_FLAG((tty), INLCR) -#define I_IGNCR(tty) _I_FLAG((tty), IGNCR) -#define I_ICRNL(tty) _I_FLAG((tty), ICRNL) -#define I_IUCLC(tty) _I_FLAG((tty), IUCLC) -#define I_IXON(tty) _I_FLAG((tty), IXON) -#define I_IXANY(tty) _I_FLAG((tty), IXANY) -#define I_IXOFF(tty) _I_FLAG((tty), IXOFF) -#define I_IMAXBEL(tty) _I_FLAG((tty), IMAXBEL) -#define I_IUTF8(tty) _I_FLAG((tty), IUTF8) - -#define O_OPOST(tty) _O_FLAG((tty), OPOST) -#define O_OLCUC(tty) _O_FLAG((tty), OLCUC) -#define O_ONLCR(tty) _O_FLAG((tty), ONLCR) -#define O_OCRNL(tty) _O_FLAG((tty), OCRNL) -#define O_ONOCR(tty) _O_FLAG((tty), ONOCR) -#define O_ONLRET(tty) _O_FLAG((tty), ONLRET) -#define O_OFILL(tty) _O_FLAG((tty), OFILL) -#define O_OFDEL(tty) _O_FLAG((tty), OFDEL) -#define O_NLDLY(tty) _O_FLAG((tty), NLDLY) -#define O_CRDLY(tty) _O_FLAG((tty), CRDLY) -#define O_TABDLY(tty) _O_FLAG((tty), TABDLY) -#define O_BSDLY(tty) _O_FLAG((tty), BSDLY) -#define O_VTDLY(tty) _O_FLAG((tty), VTDLY) -#define O_FFDLY(tty) _O_FLAG((tty), FFDLY) - -#define C_BAUD(tty) _C_FLAG((tty), CBAUD) -#define C_CSIZE(tty) _C_FLAG((tty), CSIZE) -#define C_CSTOPB(tty) _C_FLAG((tty), CSTOPB) -#define C_CREAD(tty) _C_FLAG((tty), CREAD) -#define C_PARENB(tty) _C_FLAG((tty), PARENB) -#define C_PARODD(tty) _C_FLAG((tty), PARODD) -#define C_HUPCL(tty) _C_FLAG((tty), HUPCL) -#define C_CLOCAL(tty) _C_FLAG((tty), CLOCAL) -#define C_CIBAUD(tty) _C_FLAG((tty), CIBAUD) -#define C_CRTSCTS(tty) _C_FLAG((tty), CRTSCTS) -#define C_CMSPAR(tty) _C_FLAG((tty), CMSPAR) - -#define L_ISIG(tty) _L_FLAG((tty), ISIG) -#define L_ICANON(tty) _L_FLAG((tty), ICANON) -#define L_XCASE(tty) _L_FLAG((tty), XCASE) -#define L_ECHO(tty) _L_FLAG((tty), ECHO) -#define L_ECHOE(tty) _L_FLAG((tty), ECHOE) -#define L_ECHOK(tty) _L_FLAG((tty), ECHOK) -#define L_ECHONL(tty) _L_FLAG((tty), ECHONL) -#define L_NOFLSH(tty) _L_FLAG((tty), NOFLSH) -#define L_TOSTOP(tty) _L_FLAG((tty), TOSTOP) -#define L_ECHOCTL(tty) _L_FLAG((tty), ECHOCTL) -#define L_ECHOPRT(tty) _L_FLAG((tty), ECHOPRT) -#define L_ECHOKE(tty) _L_FLAG((tty), ECHOKE) -#define L_FLUSHO(tty) _L_FLAG((tty), FLUSHO) -#define L_PENDIN(tty) _L_FLAG((tty), PENDIN) -#define L_IEXTEN(tty) _L_FLAG((tty), IEXTEN) -#define L_EXTPROC(tty) _L_FLAG((tty), EXTPROC) - -struct device; -struct signal_struct; - -/* - * Port level information. Each device keeps its own port level information - * so provide a common structure for those ports wanting to use common support - * routines. - * - * The tty port has a different lifetime to the tty so must be kept apart. - * In addition be careful as tty -> port mappings are valid for the life - * of the tty object but in many cases port -> tty mappings are valid only - * until a hangup so don't use the wrong path. - */ - -struct tty_port; - -struct tty_port_operations { - /* Return 1 if the carrier is raised */ - int (*carrier_raised)(struct tty_port *port); - /* Control the DTR line */ - void (*dtr_rts)(struct tty_port *port, int raise); - /* Called when the last close completes or a hangup finishes - IFF the port was initialized. Do not use to free resources. Called - under the port mutex to serialize against activate/shutdowns */ - void (*shutdown)(struct tty_port *port); - /* Called under the port mutex from tty_port_open, serialized using - the port mutex */ - /* FIXME: long term getting the tty argument *out* of this would be - good for consoles */ - int (*activate)(struct tty_port *port, struct tty_struct *tty); - /* Called on the final put of a port */ - void (*destruct)(struct tty_port *port); -}; - -struct tty_port { - struct tty_bufhead buf; /* Locked internally */ - struct tty_struct *tty; /* Back pointer */ - struct tty_struct *itty; /* internal back ptr */ - const struct tty_port_operations *ops; /* Port operations */ - spinlock_t lock; /* Lock protecting tty field */ - int blocked_open; /* Waiting to open */ - int count; /* Usage count */ - wait_queue_head_t open_wait; /* Open waiters */ - wait_queue_head_t delta_msr_wait; /* Modem status change */ - unsigned long flags; /* User TTY flags ASYNC_ */ - unsigned long iflags; /* Internal flags TTY_PORT_ */ - unsigned char console:1, /* port is a console */ - low_latency:1; /* optional: tune for latency */ - struct mutex mutex; /* Locking */ - struct mutex buf_mutex; /* Buffer alloc lock */ - unsigned char *xmit_buf; /* Optional buffer */ - unsigned int close_delay; /* Close port delay */ - unsigned int closing_wait; /* Delay for output */ - int drain_delay; /* Set to zero if no pure time - based drain is needed else - set to size of fifo */ - struct kref kref; /* Ref counter */ -}; - -/* tty_port::iflags bits -- use atomic bit ops */ -#define TTY_PORT_INITIALIZED 0 /* device is initialized */ -#define TTY_PORT_SUSPENDED 1 /* device is suspended */ -#define TTY_PORT_ACTIVE 2 /* device is open */ - -/* - * uart drivers: use the uart_port::status field and the UPSTAT_* defines - * for s/w-based flow control steering and carrier detection status - */ -#define TTY_PORT_CTS_FLOW 3 /* h/w flow control enabled */ -#define TTY_PORT_CHECK_CD 4 /* carrier detect enabled */ - -/* - * Where all of the state associated with a tty is kept while the tty - * is open. Since the termios state should be kept even if the tty - * has been closed --- for things like the baud rate, etc --- it is - * not stored here, but rather a pointer to the real state is stored - * here. Possible the winsize structure should have the same - * treatment, but (1) the default 80x24 is usually right and (2) it's - * most often used by a windowing system, which will set the correct - * size each time the window is created or resized anyway. - * - TYT, 9/14/92 - */ - -struct tty_operations; - -struct tty_struct { - int magic; - struct kref kref; - struct device *dev; - struct tty_driver *driver; - const struct tty_operations *ops; - int index; - - /* Protects ldisc changes: Lock tty not pty */ - struct ld_semaphore ldisc_sem; - struct tty_ldisc *ldisc; - - struct mutex atomic_write_lock; - struct mutex legacy_mutex; - struct mutex throttle_mutex; - struct rw_semaphore termios_rwsem; - struct mutex winsize_mutex; - spinlock_t ctrl_lock; - spinlock_t flow_lock; - /* Termios values are protected by the termios rwsem */ - struct ktermios termios, termios_locked; - struct termiox *termiox; /* May be NULL for unsupported */ - char name[64]; - struct pid *pgrp; /* Protected by ctrl lock */ - struct pid *session; - unsigned long flags; - int count; - struct winsize winsize; /* winsize_mutex */ - unsigned long stopped:1, /* flow_lock */ - flow_stopped:1, - unused:BITS_PER_LONG - 2; - int hw_stopped; - unsigned long ctrl_status:8, /* ctrl_lock */ - packet:1, - unused_ctrl:BITS_PER_LONG - 9; - unsigned int receive_room; /* Bytes free for queue */ - int flow_change; - - struct tty_struct *link; - struct fasync_struct *fasync; - int alt_speed; /* For magic substitution of 38400 bps */ - wait_queue_head_t write_wait; - wait_queue_head_t read_wait; - struct work_struct hangup_work; - void *disc_data; - void *driver_data; - spinlock_t files_lock; /* protects tty_files list */ - struct list_head tty_files; - -#define N_TTY_BUF_SIZE 4096 - - int closing; - unsigned char *write_buf; - int write_cnt; - /* If the tty has a pending do_SAK, queue it here - akpm */ - struct work_struct SAK_work; - struct tty_port *port; -}; - -/* Each of a tty's open files has private_data pointing to tty_file_private */ -struct tty_file_private { - struct tty_struct *tty; - struct file *file; - struct list_head list; -}; - -/* tty magic number */ -#define TTY_MAGIC 0x5401 - -/* - * These bits are used in the flags field of the tty structure. - * - * So that interrupts won't be able to mess up the queues, - * copy_to_cooked must be atomic with respect to itself, as must - * tty->write. Thus, you must use the inline functions set_bit() and - * clear_bit() to make things atomic. - */ -#define TTY_THROTTLED 0 /* Call unthrottle() at threshold min */ -#define TTY_IO_ERROR 1 /* Cause an I/O error (may be no ldisc too) */ -#define TTY_OTHER_CLOSED 2 /* Other side (if any) has closed */ -#define TTY_EXCLUSIVE 3 /* Exclusive open mode */ -#define TTY_DO_WRITE_WAKEUP 5 /* Call write_wakeup after queuing new */ -#define TTY_LDISC_OPEN 11 /* Line discipline is open */ -#define TTY_PTY_LOCK 16 /* pty private */ -#define TTY_NO_WRITE_SPLIT 17 /* Preserve write boundaries to driver */ -#define TTY_HUPPED 18 /* Post driver->hangup() */ -#define TTY_LDISC_HALTED 22 /* Line discipline is halted */ - -/* Values for tty->flow_change */ -#define TTY_THROTTLE_SAFE 1 -#define TTY_UNTHROTTLE_SAFE 2 - -static inline void __tty_set_flow_change(struct tty_struct *tty, int val) -{ - tty->flow_change = val; -} - -static inline void tty_set_flow_change(struct tty_struct *tty, int val) -{ - tty->flow_change = val; - smp_mb(); -} - -static inline bool tty_io_error(struct tty_struct *tty) -{ - return test_bit(TTY_IO_ERROR, &tty->flags); -} - -static inline bool tty_throttled(struct tty_struct *tty) -{ - return test_bit(TTY_THROTTLED, &tty->flags); -} - -#ifdef CONFIG_TTY -extern void console_init(void); -extern void tty_kref_put(struct tty_struct *tty); -extern struct pid *tty_get_pgrp(struct tty_struct *tty); -extern void tty_vhangup_self(void); -extern void disassociate_ctty(int priv); -extern dev_t tty_devnum(struct tty_struct *tty); -extern void proc_clear_tty(struct task_struct *p); -extern struct tty_struct *get_current_tty(void); -/* tty_io.c */ -extern int __init tty_init(void); -extern const char *tty_name(const struct tty_struct *tty); -#else -static inline void console_init(void) -{ } -static inline void tty_kref_put(struct tty_struct *tty) -{ } -static inline struct pid *tty_get_pgrp(struct tty_struct *tty) -{ return NULL; } -static inline void tty_vhangup_self(void) -{ } -static inline void disassociate_ctty(int priv) -{ } -static inline dev_t tty_devnum(struct tty_struct *tty) -{ return 0; } -static inline void proc_clear_tty(struct task_struct *p) -{ } -static inline struct tty_struct *get_current_tty(void) -{ return NULL; } -/* tty_io.c */ -static inline int __init tty_init(void) -{ return 0; } -static inline const char *tty_name(const struct tty_struct *tty) -{ return "(none)"; } -#endif - -extern struct ktermios tty_std_termios; - -extern int vcs_init(void); - -extern struct class *tty_class; - -/** - * tty_kref_get - get a tty reference - * @tty: tty device - * - * Return a new reference to a tty object. The caller must hold - * sufficient locks/counts to ensure that their existing reference cannot - * go away - */ - -static inline struct tty_struct *tty_kref_get(struct tty_struct *tty) -{ - if (tty) - kref_get(&tty->kref); - return tty; -} - -extern const char *tty_driver_name(const struct tty_struct *tty); -extern void tty_wait_until_sent(struct tty_struct *tty, long timeout); -extern int __tty_check_change(struct tty_struct *tty, int sig); -extern int tty_check_change(struct tty_struct *tty); -extern void __stop_tty(struct tty_struct *tty); -extern void stop_tty(struct tty_struct *tty); -extern void __start_tty(struct tty_struct *tty); -extern void start_tty(struct tty_struct *tty); -extern int tty_register_driver(struct tty_driver *driver); -extern int tty_unregister_driver(struct tty_driver *driver); -extern struct device *tty_register_device(struct tty_driver *driver, - unsigned index, struct device *dev); -extern struct device *tty_register_device_attr(struct tty_driver *driver, - unsigned index, struct device *device, - void *drvdata, - const struct attribute_group **attr_grp); -extern void tty_unregister_device(struct tty_driver *driver, unsigned index); -extern void tty_write_message(struct tty_struct *tty, char *msg); -extern int tty_send_xchar(struct tty_struct *tty, char ch); -extern int tty_put_char(struct tty_struct *tty, unsigned char c); -extern int tty_chars_in_buffer(struct tty_struct *tty); -extern int tty_write_room(struct tty_struct *tty); -extern void tty_driver_flush_buffer(struct tty_struct *tty); -extern void tty_throttle(struct tty_struct *tty); -extern void tty_unthrottle(struct tty_struct *tty); -extern int tty_throttle_safe(struct tty_struct *tty); -extern int tty_unthrottle_safe(struct tty_struct *tty); -extern int tty_do_resize(struct tty_struct *tty, struct winsize *ws); -extern int is_current_pgrp_orphaned(void); -extern void tty_hangup(struct tty_struct *tty); -extern void tty_vhangup(struct tty_struct *tty); -extern int tty_hung_up_p(struct file *filp); -extern void do_SAK(struct tty_struct *tty); -extern void __do_SAK(struct tty_struct *tty); -extern void no_tty(void); -extern void tty_buffer_free_all(struct tty_port *port); -extern void tty_buffer_flush(struct tty_struct *tty, struct tty_ldisc *ld); -extern void tty_buffer_init(struct tty_port *port); -extern void tty_buffer_set_lock_subclass(struct tty_port *port); -extern bool tty_buffer_restart_work(struct tty_port *port); -extern bool tty_buffer_cancel_work(struct tty_port *port); -extern void tty_buffer_flush_work(struct tty_port *port); -extern speed_t tty_termios_baud_rate(struct ktermios *termios); -extern speed_t tty_termios_input_baud_rate(struct ktermios *termios); -extern void tty_termios_encode_baud_rate(struct ktermios *termios, - speed_t ibaud, speed_t obaud); -extern void tty_encode_baud_rate(struct tty_struct *tty, - speed_t ibaud, speed_t obaud); - -/** - * tty_get_baud_rate - get tty bit rates - * @tty: tty to query - * - * Returns the baud rate as an integer for this terminal. The - * termios lock must be held by the caller and the terminal bit - * flags may be updated. - * - * Locking: none - */ -static inline speed_t tty_get_baud_rate(struct tty_struct *tty) -{ - return tty_termios_baud_rate(&tty->termios); -} - -extern void tty_termios_copy_hw(struct ktermios *new, struct ktermios *old); -extern int tty_termios_hw_change(struct ktermios *a, struct ktermios *b); -extern int tty_set_termios(struct tty_struct *tty, struct ktermios *kt); - -extern struct tty_ldisc *tty_ldisc_ref(struct tty_struct *); -extern void tty_ldisc_deref(struct tty_ldisc *); -extern struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *); -extern void tty_ldisc_hangup(struct tty_struct *tty, bool reset); -extern int tty_ldisc_reinit(struct tty_struct *tty, int disc); -extern const struct file_operations tty_ldiscs_proc_fops; - -extern void tty_wakeup(struct tty_struct *tty); -extern void tty_ldisc_flush(struct tty_struct *tty); - -extern long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -extern int tty_mode_ioctl(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); -extern int tty_perform_flush(struct tty_struct *tty, unsigned long arg); -extern void tty_default_fops(struct file_operations *fops); -extern struct tty_struct *alloc_tty_struct(struct tty_driver *driver, int idx); -extern int tty_alloc_file(struct file *file); -extern void tty_add_file(struct tty_struct *tty, struct file *file); -extern void tty_free_file(struct file *file); -extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx); -extern int tty_release(struct inode *inode, struct file *filp); -extern void tty_init_termios(struct tty_struct *tty); -extern int tty_standard_install(struct tty_driver *driver, - struct tty_struct *tty); - -extern struct mutex tty_mutex; - -#define tty_is_writelocked(tty) (mutex_is_locked(&tty->atomic_write_lock)) - -extern void tty_port_init(struct tty_port *port); -extern void tty_port_link_device(struct tty_port *port, - struct tty_driver *driver, unsigned index); -extern struct device *tty_port_register_device(struct tty_port *port, - struct tty_driver *driver, unsigned index, - struct device *device); -extern struct device *tty_port_register_device_attr(struct tty_port *port, - struct tty_driver *driver, unsigned index, - struct device *device, void *drvdata, - const struct attribute_group **attr_grp); -extern int tty_port_alloc_xmit_buf(struct tty_port *port); -extern void tty_port_free_xmit_buf(struct tty_port *port); -extern void tty_port_destroy(struct tty_port *port); -extern void tty_port_put(struct tty_port *port); - -static inline struct tty_port *tty_port_get(struct tty_port *port) -{ - if (port && kref_get_unless_zero(&port->kref)) - return port; - return NULL; -} - -/* If the cts flow control is enabled, return true. */ -static inline bool tty_port_cts_enabled(struct tty_port *port) -{ - return test_bit(TTY_PORT_CTS_FLOW, &port->iflags); -} - -static inline void tty_port_set_cts_flow(struct tty_port *port, bool val) -{ - if (val) - set_bit(TTY_PORT_CTS_FLOW, &port->iflags); - else - clear_bit(TTY_PORT_CTS_FLOW, &port->iflags); -} - -static inline bool tty_port_active(struct tty_port *port) -{ - return test_bit(TTY_PORT_ACTIVE, &port->iflags); -} - -static inline void tty_port_set_active(struct tty_port *port, bool val) -{ - if (val) - set_bit(TTY_PORT_ACTIVE, &port->iflags); - else - clear_bit(TTY_PORT_ACTIVE, &port->iflags); -} - -static inline bool tty_port_check_carrier(struct tty_port *port) -{ - return test_bit(TTY_PORT_CHECK_CD, &port->iflags); -} - -static inline void tty_port_set_check_carrier(struct tty_port *port, bool val) -{ - if (val) - set_bit(TTY_PORT_CHECK_CD, &port->iflags); - else - clear_bit(TTY_PORT_CHECK_CD, &port->iflags); -} - -static inline bool tty_port_suspended(struct tty_port *port) -{ - return test_bit(TTY_PORT_SUSPENDED, &port->iflags); -} - -static inline void tty_port_set_suspended(struct tty_port *port, bool val) -{ - if (val) - set_bit(TTY_PORT_SUSPENDED, &port->iflags); - else - clear_bit(TTY_PORT_SUSPENDED, &port->iflags); -} - -static inline bool tty_port_initialized(struct tty_port *port) -{ - return test_bit(TTY_PORT_INITIALIZED, &port->iflags); -} - -static inline void tty_port_set_initialized(struct tty_port *port, bool val) -{ - if (val) - set_bit(TTY_PORT_INITIALIZED, &port->iflags); - else - clear_bit(TTY_PORT_INITIALIZED, &port->iflags); -} - -extern struct tty_struct *tty_port_tty_get(struct tty_port *port); -extern void tty_port_tty_set(struct tty_port *port, struct tty_struct *tty); -extern int tty_port_carrier_raised(struct tty_port *port); -extern void tty_port_raise_dtr_rts(struct tty_port *port); -extern void tty_port_lower_dtr_rts(struct tty_port *port); -extern void tty_port_hangup(struct tty_port *port); -extern void tty_port_tty_hangup(struct tty_port *port, bool check_clocal); -extern void tty_port_tty_wakeup(struct tty_port *port); -extern int tty_port_block_til_ready(struct tty_port *port, - struct tty_struct *tty, struct file *filp); -extern int tty_port_close_start(struct tty_port *port, - struct tty_struct *tty, struct file *filp); -extern void tty_port_close_end(struct tty_port *port, struct tty_struct *tty); -extern void tty_port_close(struct tty_port *port, - struct tty_struct *tty, struct file *filp); -extern int tty_port_install(struct tty_port *port, struct tty_driver *driver, - struct tty_struct *tty); -extern int tty_port_open(struct tty_port *port, - struct tty_struct *tty, struct file *filp); -static inline int tty_port_users(struct tty_port *port) -{ - return port->count + port->blocked_open; -} - -extern int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc); -extern int tty_unregister_ldisc(int disc); -extern int tty_set_ldisc(struct tty_struct *tty, int disc); -extern int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty); -extern void tty_ldisc_release(struct tty_struct *tty); -extern void tty_ldisc_init(struct tty_struct *tty); -extern void tty_ldisc_deinit(struct tty_struct *tty); -extern int tty_ldisc_receive_buf(struct tty_ldisc *ld, unsigned char *p, - char *f, int count); - -/* n_tty.c */ -extern void n_tty_inherit_ops(struct tty_ldisc_ops *ops); -extern void __init n_tty_init(void); - -/* tty_audit.c */ -#ifdef CONFIG_AUDIT -extern void tty_audit_add_data(struct tty_struct *tty, const void *data, - size_t size); -extern void tty_audit_exit(void); -extern void tty_audit_fork(struct signal_struct *sig); -extern void tty_audit_tiocsti(struct tty_struct *tty, char ch); -extern int tty_audit_push(void); -#else -static inline void tty_audit_add_data(struct tty_struct *tty, const void *data, - size_t size) -{ -} -static inline void tty_audit_tiocsti(struct tty_struct *tty, char ch) -{ -} -static inline void tty_audit_exit(void) -{ -} -static inline void tty_audit_fork(struct signal_struct *sig) -{ -} -static inline int tty_audit_push(void) -{ - return 0; -} -#endif - -/* tty_ioctl.c */ -extern int n_tty_ioctl_helper(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); -extern long n_tty_compat_ioctl_helper(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); - -/* vt.c */ - -extern int vt_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); - -extern long vt_compat_ioctl(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); - -/* tty_mutex.c */ -/* functions for preparation of BKL removal */ -extern void tty_lock(struct tty_struct *tty); -extern int tty_lock_interruptible(struct tty_struct *tty); -extern void tty_unlock(struct tty_struct *tty); -extern void tty_lock_slave(struct tty_struct *tty); -extern void tty_unlock_slave(struct tty_struct *tty); -extern void tty_set_lock_subclass(struct tty_struct *tty); - -#ifdef CONFIG_PROC_FS -extern void proc_tty_register_driver(struct tty_driver *); -extern void proc_tty_unregister_driver(struct tty_driver *); -#else -static inline void proc_tty_register_driver(struct tty_driver *d) {} -static inline void proc_tty_unregister_driver(struct tty_driver *d) {} -#endif - -#define tty_msg(fn, tty, f, ...) \ - fn("%s %s: " f, tty_driver_name(tty), tty_name(tty), ##__VA_ARGS__) - -#define tty_debug(tty, f, ...) tty_msg(pr_debug, tty, f, ##__VA_ARGS__) -#define tty_info(tty, f, ...) tty_msg(pr_info, tty, f, ##__VA_ARGS__) -#define tty_notice(tty, f, ...) tty_msg(pr_notice, tty, f, ##__VA_ARGS__) -#define tty_warn(tty, f, ...) tty_msg(pr_warn, tty, f, ##__VA_ARGS__) -#define tty_err(tty, f, ...) tty_msg(pr_err, tty, f, ##__VA_ARGS__) - -#define tty_info_ratelimited(tty, f, ...) \ - tty_msg(pr_info_ratelimited, tty, f, ##__VA_ARGS__) - -#endif diff --git a/src/linux/include/linux/tty_driver.h b/src/linux/include/linux/tty_driver.h deleted file mode 100644 index b742b5e..0000000 --- a/src/linux/include/linux/tty_driver.h +++ /dev/null @@ -1,440 +0,0 @@ -#ifndef _LINUX_TTY_DRIVER_H -#define _LINUX_TTY_DRIVER_H - -/* - * This structure defines the interface between the low-level tty - * driver and the tty routines. The following routines can be - * defined; unless noted otherwise, they are optional, and can be - * filled in with a null pointer. - * - * struct tty_struct * (*lookup)(struct tty_driver *self, struct file *, int idx) - * - * Return the tty device corresponding to idx, NULL if there is not - * one currently in use and an ERR_PTR value on error. Called under - * tty_mutex (for now!) - * - * Optional method. Default behaviour is to use the ttys array - * - * int (*install)(struct tty_driver *self, struct tty_struct *tty) - * - * Install a new tty into the tty driver internal tables. Used in - * conjunction with lookup and remove methods. - * - * Optional method. Default behaviour is to use the ttys array - * - * void (*remove)(struct tty_driver *self, struct tty_struct *tty) - * - * Remove a closed tty from the tty driver internal tables. Used in - * conjunction with lookup and remove methods. - * - * Optional method. Default behaviour is to use the ttys array - * - * int (*open)(struct tty_struct * tty, struct file * filp); - * - * This routine is called when a particular tty device is opened. - * This routine is mandatory; if this routine is not filled in, - * the attempted open will fail with ENODEV. - * - * Required method. Called with tty lock held. - * - * void (*close)(struct tty_struct * tty, struct file * filp); - * - * This routine is called when a particular tty device is closed. - * Note: called even if the corresponding open() failed. - * - * Required method. Called with tty lock held. - * - * void (*shutdown)(struct tty_struct * tty); - * - * This routine is called under the tty lock when a particular tty device - * is closed for the last time. It executes before the tty resources - * are freed so may execute while another function holds a tty kref. - * - * void (*cleanup)(struct tty_struct * tty); - * - * This routine is called asynchronously when a particular tty device - * is closed for the last time freeing up the resources. This is - * actually the second part of shutdown for routines that might sleep. - * - * - * int (*write)(struct tty_struct * tty, - * const unsigned char *buf, int count); - * - * This routine is called by the kernel to write a series of - * characters to the tty device. The characters may come from - * user space or kernel space. This routine will return the - * number of characters actually accepted for writing. - * - * Optional: Required for writable devices. - * - * int (*put_char)(struct tty_struct *tty, unsigned char ch); - * - * This routine is called by the kernel to write a single - * character to the tty device. If the kernel uses this routine, - * it must call the flush_chars() routine (if defined) when it is - * done stuffing characters into the driver. If there is no room - * in the queue, the character is ignored. - * - * Optional: Kernel will use the write method if not provided. - * - * Note: Do not call this function directly, call tty_put_char - * - * void (*flush_chars)(struct tty_struct *tty); - * - * This routine is called by the kernel after it has written a - * series of characters to the tty device using put_char(). - * - * Optional: - * - * Note: Do not call this function directly, call tty_driver_flush_chars - * - * int (*write_room)(struct tty_struct *tty); - * - * This routine returns the numbers of characters the tty driver - * will accept for queuing to be written. This number is subject - * to change as output buffers get emptied, or if the output flow - * control is acted. - * - * Required if write method is provided else not needed. - * - * Note: Do not call this function directly, call tty_write_room - * - * int (*ioctl)(struct tty_struct *tty, unsigned int cmd, unsigned long arg); - * - * This routine allows the tty driver to implement - * device-specific ioctls. If the ioctl number passed in cmd - * is not recognized by the driver, it should return ENOIOCTLCMD. - * - * Optional - * - * long (*compat_ioctl)(struct tty_struct *tty,, - * unsigned int cmd, unsigned long arg); - * - * implement ioctl processing for 32 bit process on 64 bit system - * - * Optional - * - * void (*set_termios)(struct tty_struct *tty, struct ktermios * old); - * - * This routine allows the tty driver to be notified when - * device's termios settings have changed. - * - * Optional: Called under the termios lock - * - * - * void (*set_ldisc)(struct tty_struct *tty); - * - * This routine allows the tty driver to be notified when the - * device's termios settings have changed. - * - * Optional: Called under BKL (currently) - * - * void (*throttle)(struct tty_struct * tty); - * - * This routine notifies the tty driver that input buffers for - * the line discipline are close to full, and it should somehow - * signal that no more characters should be sent to the tty. - * - * Optional: Always invoke via tty_throttle(), called under the - * termios lock. - * - * void (*unthrottle)(struct tty_struct * tty); - * - * This routine notifies the tty drivers that it should signals - * that characters can now be sent to the tty without fear of - * overrunning the input buffers of the line disciplines. - * - * Optional: Always invoke via tty_unthrottle(), called under the - * termios lock. - * - * void (*stop)(struct tty_struct *tty); - * - * This routine notifies the tty driver that it should stop - * outputting characters to the tty device. - * - * Called with ->flow_lock held. Serialized with start() method. - * - * Optional: - * - * Note: Call stop_tty not this method. - * - * void (*start)(struct tty_struct *tty); - * - * This routine notifies the tty driver that it resume sending - * characters to the tty device. - * - * Called with ->flow_lock held. Serialized with stop() method. - * - * Optional: - * - * Note: Call start_tty not this method. - * - * void (*hangup)(struct tty_struct *tty); - * - * This routine notifies the tty driver that it should hang up the - * tty device. - * - * Optional: - * - * Called with tty lock held. - * - * int (*break_ctl)(struct tty_struct *tty, int state); - * - * This optional routine requests the tty driver to turn on or - * off BREAK status on the RS-232 port. If state is -1, - * then the BREAK status should be turned on; if state is 0, then - * BREAK should be turned off. - * - * If this routine is implemented, the high-level tty driver will - * handle the following ioctls: TCSBRK, TCSBRKP, TIOCSBRK, - * TIOCCBRK. - * - * If the driver sets TTY_DRIVER_HARDWARE_BREAK then the interface - * will also be called with actual times and the hardware is expected - * to do the delay work itself. 0 and -1 are still used for on/off. - * - * Optional: Required for TCSBRK/BRKP/etc handling. - * - * void (*wait_until_sent)(struct tty_struct *tty, int timeout); - * - * This routine waits until the device has written out all of the - * characters in its transmitter FIFO. - * - * Optional: If not provided the device is assumed to have no FIFO - * - * Note: Usually correct to call tty_wait_until_sent - * - * void (*send_xchar)(struct tty_struct *tty, char ch); - * - * This routine is used to send a high-priority XON/XOFF - * character to the device. - * - * Optional: If not provided then the write method is called under - * the atomic write lock to keep it serialized with the ldisc. - * - * int (*resize)(struct tty_struct *tty, struct winsize *ws) - * - * Called when a termios request is issued which changes the - * requested terminal geometry. - * - * Optional: the default action is to update the termios structure - * without error. This is usually the correct behaviour. Drivers should - * not force errors here if they are not resizable objects (eg a serial - * line). See tty_do_resize() if you need to wrap the standard method - * in your own logic - the usual case. - * - * void (*set_termiox)(struct tty_struct *tty, struct termiox *new); - * - * Called when the device receives a termiox based ioctl. Passes down - * the requested data from user space. This method will not be invoked - * unless the tty also has a valid tty->termiox pointer. - * - * Optional: Called under the termios lock - * - * int (*get_icount)(struct tty_struct *tty, struct serial_icounter *icount); - * - * Called when the device receives a TIOCGICOUNT ioctl. Passed a kernel - * structure to complete. This method is optional and will only be called - * if provided (otherwise EINVAL will be returned). - */ - -#include -#include -#include -#include -#include - -struct tty_struct; -struct tty_driver; -struct serial_icounter_struct; - -struct tty_operations { - struct tty_struct * (*lookup)(struct tty_driver *driver, - struct file *filp, int idx); - int (*install)(struct tty_driver *driver, struct tty_struct *tty); - void (*remove)(struct tty_driver *driver, struct tty_struct *tty); - int (*open)(struct tty_struct * tty, struct file * filp); - void (*close)(struct tty_struct * tty, struct file * filp); - void (*shutdown)(struct tty_struct *tty); - void (*cleanup)(struct tty_struct *tty); - int (*write)(struct tty_struct * tty, - const unsigned char *buf, int count); - int (*put_char)(struct tty_struct *tty, unsigned char ch); - void (*flush_chars)(struct tty_struct *tty); - int (*write_room)(struct tty_struct *tty); - int (*chars_in_buffer)(struct tty_struct *tty); - int (*ioctl)(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); - long (*compat_ioctl)(struct tty_struct *tty, - unsigned int cmd, unsigned long arg); - void (*set_termios)(struct tty_struct *tty, struct ktermios * old); - void (*throttle)(struct tty_struct * tty); - void (*unthrottle)(struct tty_struct * tty); - void (*stop)(struct tty_struct *tty); - void (*start)(struct tty_struct *tty); - void (*hangup)(struct tty_struct *tty); - int (*break_ctl)(struct tty_struct *tty, int state); - void (*flush_buffer)(struct tty_struct *tty); - void (*set_ldisc)(struct tty_struct *tty); - void (*wait_until_sent)(struct tty_struct *tty, int timeout); - void (*send_xchar)(struct tty_struct *tty, char ch); - int (*tiocmget)(struct tty_struct *tty); - int (*tiocmset)(struct tty_struct *tty, - unsigned int set, unsigned int clear); - int (*resize)(struct tty_struct *tty, struct winsize *ws); - int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew); - int (*get_icount)(struct tty_struct *tty, - struct serial_icounter_struct *icount); -#ifdef CONFIG_CONSOLE_POLL - int (*poll_init)(struct tty_driver *driver, int line, char *options); - int (*poll_get_char)(struct tty_driver *driver, int line); - void (*poll_put_char)(struct tty_driver *driver, int line, char ch); -#endif - const struct file_operations *proc_fops; -}; - -struct tty_driver { - int magic; /* magic number for this structure */ - struct kref kref; /* Reference management */ - struct cdev **cdevs; - struct module *owner; - const char *driver_name; - const char *name; - int name_base; /* offset of printed name */ - int major; /* major device number */ - int minor_start; /* start of minor device number */ - unsigned int num; /* number of devices allocated */ - short type; /* type of tty driver */ - short subtype; /* subtype of tty driver */ - struct ktermios init_termios; /* Initial termios */ - unsigned long flags; /* tty driver flags */ - struct proc_dir_entry *proc_entry; /* /proc fs entry */ - struct tty_driver *other; /* only used for the PTY driver */ - - /* - * Pointer to the tty data structures - */ - struct tty_struct **ttys; - struct tty_port **ports; - struct ktermios **termios; - void *driver_state; - - /* - * Driver methods - */ - - const struct tty_operations *ops; - struct list_head tty_drivers; -}; - -extern struct list_head tty_drivers; - -extern struct tty_driver *__tty_alloc_driver(unsigned int lines, - struct module *owner, unsigned long flags); -extern void put_tty_driver(struct tty_driver *driver); -extern void tty_set_operations(struct tty_driver *driver, - const struct tty_operations *op); -extern struct tty_driver *tty_find_polling_driver(char *name, int *line); - -extern void tty_driver_kref_put(struct tty_driver *driver); - -/* Use TTY_DRIVER_* flags below */ -#define tty_alloc_driver(lines, flags) \ - __tty_alloc_driver(lines, THIS_MODULE, flags) - -/* - * DEPRECATED Do not use this in new code, use tty_alloc_driver instead. - * (And change the return value checks.) - */ -static inline struct tty_driver *alloc_tty_driver(unsigned int lines) -{ - struct tty_driver *ret = tty_alloc_driver(lines, 0); - if (IS_ERR(ret)) - return NULL; - return ret; -} - -static inline struct tty_driver *tty_driver_kref_get(struct tty_driver *d) -{ - kref_get(&d->kref); - return d; -} - -/* tty driver magic number */ -#define TTY_DRIVER_MAGIC 0x5402 - -/* - * tty driver flags - * - * TTY_DRIVER_RESET_TERMIOS --- requests the tty layer to reset the - * termios setting when the last process has closed the device. - * Used for PTY's, in particular. - * - * TTY_DRIVER_REAL_RAW --- if set, indicates that the driver will - * guarantee never not to set any special character handling - * flags if ((IGNBRK || (!BRKINT && !PARMRK)) && (IGNPAR || - * !INPCK)). That is, if there is no reason for the driver to - * send notifications of parity and break characters up to the - * line driver, it won't do so. This allows the line driver to - * optimize for this case if this flag is set. (Note that there - * is also a promise, if the above case is true, not to signal - * overruns, either.) - * - * TTY_DRIVER_DYNAMIC_DEV --- if set, the individual tty devices need - * to be registered with a call to tty_register_device() when the - * device is found in the system and unregistered with a call to - * tty_unregister_device() so the devices will be show up - * properly in sysfs. If not set, driver->num entries will be - * created by the tty core in sysfs when tty_register_driver() is - * called. This is to be used by drivers that have tty devices - * that can appear and disappear while the main tty driver is - * registered with the tty core. - * - * TTY_DRIVER_DEVPTS_MEM -- don't use the standard arrays, instead - * use dynamic memory keyed through the devpts filesystem. This - * is only applicable to the pty driver. - * - * TTY_DRIVER_HARDWARE_BREAK -- hardware handles break signals. Pass - * the requested timeout to the caller instead of using a simple - * on/off interface. - * - * TTY_DRIVER_DYNAMIC_ALLOC -- do not allocate structures which are - * needed per line for this driver as it would waste memory. - * The driver will take care. - * - * TTY_DRIVER_UNNUMBERED_NODE -- do not create numbered /dev nodes. In - * other words create /dev/ttyprintk and not /dev/ttyprintk0. - * Applicable only when a driver for a single tty device is - * being allocated. - */ -#define TTY_DRIVER_INSTALLED 0x0001 -#define TTY_DRIVER_RESET_TERMIOS 0x0002 -#define TTY_DRIVER_REAL_RAW 0x0004 -#define TTY_DRIVER_DYNAMIC_DEV 0x0008 -#define TTY_DRIVER_DEVPTS_MEM 0x0010 -#define TTY_DRIVER_HARDWARE_BREAK 0x0020 -#define TTY_DRIVER_DYNAMIC_ALLOC 0x0040 -#define TTY_DRIVER_UNNUMBERED_NODE 0x0080 - -/* tty driver types */ -#define TTY_DRIVER_TYPE_SYSTEM 0x0001 -#define TTY_DRIVER_TYPE_CONSOLE 0x0002 -#define TTY_DRIVER_TYPE_SERIAL 0x0003 -#define TTY_DRIVER_TYPE_PTY 0x0004 -#define TTY_DRIVER_TYPE_SCC 0x0005 /* scc driver */ -#define TTY_DRIVER_TYPE_SYSCONS 0x0006 - -/* system subtypes (magic, used by tty_io.c) */ -#define SYSTEM_TYPE_TTY 0x0001 -#define SYSTEM_TYPE_CONSOLE 0x0002 -#define SYSTEM_TYPE_SYSCONS 0x0003 -#define SYSTEM_TYPE_SYSPTMX 0x0004 - -/* pty subtypes (magic, used by tty_io.c) */ -#define PTY_TYPE_MASTER 0x0001 -#define PTY_TYPE_SLAVE 0x0002 - -/* serial subtype definitions */ -#define SERIAL_TYPE_NORMAL 1 - -#endif /* #ifdef _LINUX_TTY_DRIVER_H */ diff --git a/src/linux/include/linux/tty_flip.h b/src/linux/include/linux/tty_flip.h deleted file mode 100644 index c28dd52..0000000 --- a/src/linux/include/linux/tty_flip.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef _LINUX_TTY_FLIP_H -#define _LINUX_TTY_FLIP_H - -extern int tty_buffer_set_limit(struct tty_port *port, int limit); -extern int tty_buffer_space_avail(struct tty_port *port); -extern int tty_buffer_request_room(struct tty_port *port, size_t size); -extern int tty_insert_flip_string_flags(struct tty_port *port, - const unsigned char *chars, const char *flags, size_t size); -extern int tty_insert_flip_string_fixed_flag(struct tty_port *port, - const unsigned char *chars, char flag, size_t size); -extern int tty_prepare_flip_string(struct tty_port *port, - unsigned char **chars, size_t size); -extern void tty_flip_buffer_push(struct tty_port *port); -void tty_schedule_flip(struct tty_port *port); - -static inline int tty_insert_flip_char(struct tty_port *port, - unsigned char ch, char flag) -{ - struct tty_buffer *tb = port->buf.tail; - int change; - - change = (tb->flags & TTYB_NORMAL) && (flag != TTY_NORMAL); - if (!change && tb->used < tb->size) { - if (~tb->flags & TTYB_NORMAL) - *flag_buf_ptr(tb, tb->used) = flag; - *char_buf_ptr(tb, tb->used++) = ch; - return 1; - } - return tty_insert_flip_string_flags(port, &ch, &flag, 1); -} - -static inline int tty_insert_flip_string(struct tty_port *port, - const unsigned char *chars, size_t size) -{ - return tty_insert_flip_string_fixed_flag(port, chars, TTY_NORMAL, size); -} - -extern void tty_buffer_lock_exclusive(struct tty_port *port); -extern void tty_buffer_unlock_exclusive(struct tty_port *port); - -#endif /* _LINUX_TTY_FLIP_H */ diff --git a/src/linux/include/linux/tty_ldisc.h b/src/linux/include/linux/tty_ldisc.h deleted file mode 100644 index 3971cf0..0000000 --- a/src/linux/include/linux/tty_ldisc.h +++ /dev/null @@ -1,220 +0,0 @@ -#ifndef _LINUX_TTY_LDISC_H -#define _LINUX_TTY_LDISC_H - -/* - * This structure defines the interface between the tty line discipline - * implementation and the tty routines. The following routines can be - * defined; unless noted otherwise, they are optional, and can be - * filled in with a null pointer. - * - * int (*open)(struct tty_struct *); - * - * This function is called when the line discipline is associated - * with the tty. The line discipline can use this as an - * opportunity to initialize any state needed by the ldisc routines. - * - * void (*close)(struct tty_struct *); - * - * This function is called when the line discipline is being - * shutdown, either because the tty is being closed or because - * the tty is being changed to use a new line discipline - * - * void (*flush_buffer)(struct tty_struct *tty); - * - * This function instructs the line discipline to clear its - * buffers of any input characters it may have queued to be - * delivered to the user mode process. - * - * ssize_t (*read)(struct tty_struct * tty, struct file * file, - * unsigned char * buf, size_t nr); - * - * This function is called when the user requests to read from - * the tty. The line discipline will return whatever characters - * it has buffered up for the user. If this function is not - * defined, the user will receive an EIO error. - * - * ssize_t (*write)(struct tty_struct * tty, struct file * file, - * const unsigned char * buf, size_t nr); - * - * This function is called when the user requests to write to the - * tty. The line discipline will deliver the characters to the - * low-level tty device for transmission, optionally performing - * some processing on the characters first. If this function is - * not defined, the user will receive an EIO error. - * - * int (*ioctl)(struct tty_struct * tty, struct file * file, - * unsigned int cmd, unsigned long arg); - * - * This function is called when the user requests an ioctl which - * is not handled by the tty layer or the low-level tty driver. - * It is intended for ioctls which affect line discpline - * operation. Note that the search order for ioctls is (1) tty - * layer, (2) tty low-level driver, (3) line discpline. So a - * low-level driver can "grab" an ioctl request before the line - * discpline has a chance to see it. - * - * long (*compat_ioctl)(struct tty_struct * tty, struct file * file, - * unsigned int cmd, unsigned long arg); - * - * Process ioctl calls from 32-bit process on 64-bit system - * - * void (*set_termios)(struct tty_struct *tty, struct ktermios * old); - * - * This function notifies the line discpline that a change has - * been made to the termios structure. - * - * int (*poll)(struct tty_struct * tty, struct file * file, - * poll_table *wait); - * - * This function is called when a user attempts to select/poll on a - * tty device. It is solely the responsibility of the line - * discipline to handle poll requests. - * - * void (*receive_buf)(struct tty_struct *, const unsigned char *cp, - * char *fp, int count); - * - * This function is called by the low-level tty driver to send - * characters received by the hardware to the line discpline for - * processing. is a pointer to the buffer of input - * character received by the device. is a pointer to a - * pointer of flag bytes which indicate whether a character was - * received with a parity error, etc. may be NULL to indicate - * all data received is TTY_NORMAL. - * - * void (*write_wakeup)(struct tty_struct *); - * - * This function is called by the low-level tty driver to signal - * that line discpline should try to send more characters to the - * low-level driver for transmission. If the line discpline does - * not have any more data to send, it can just return. If the line - * discipline does have some data to send, please arise a tasklet - * or workqueue to do the real data transfer. Do not send data in - * this hook, it may leads to a deadlock. - * - * int (*hangup)(struct tty_struct *) - * - * Called on a hangup. Tells the discipline that it should - * cease I/O to the tty driver. Can sleep. The driver should - * seek to perform this action quickly but should wait until - * any pending driver I/O is completed. - * - * void (*dcd_change)(struct tty_struct *tty, unsigned int status) - * - * Tells the discipline that the DCD pin has changed its status. - * Used exclusively by the N_PPS (Pulse-Per-Second) line discipline. - * - * int (*receive_buf2)(struct tty_struct *, const unsigned char *cp, - * char *fp, int count); - * - * This function is called by the low-level tty driver to send - * characters received by the hardware to the line discpline for - * processing. is a pointer to the buffer of input - * character received by the device. is a pointer to a - * pointer of flag bytes which indicate whether a character was - * received with a parity error, etc. may be NULL to indicate - * all data received is TTY_NORMAL. - * If assigned, prefer this function for automatic flow control. - */ - -#include -#include - - -/* - * the semaphore definition - */ -struct ld_semaphore { - long count; - raw_spinlock_t wait_lock; - unsigned int wait_readers; - struct list_head read_wait; - struct list_head write_wait; -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map dep_map; -#endif -}; - -extern void __init_ldsem(struct ld_semaphore *sem, const char *name, - struct lock_class_key *key); - -#define init_ldsem(sem) \ -do { \ - static struct lock_class_key __key; \ - \ - __init_ldsem((sem), #sem, &__key); \ -} while (0) - - -extern int ldsem_down_read(struct ld_semaphore *sem, long timeout); -extern int ldsem_down_read_trylock(struct ld_semaphore *sem); -extern int ldsem_down_write(struct ld_semaphore *sem, long timeout); -extern int ldsem_down_write_trylock(struct ld_semaphore *sem); -extern void ldsem_up_read(struct ld_semaphore *sem); -extern void ldsem_up_write(struct ld_semaphore *sem); - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -extern int ldsem_down_read_nested(struct ld_semaphore *sem, int subclass, - long timeout); -extern int ldsem_down_write_nested(struct ld_semaphore *sem, int subclass, - long timeout); -#else -# define ldsem_down_read_nested(sem, subclass, timeout) \ - ldsem_down_read(sem, timeout) -# define ldsem_down_write_nested(sem, subclass, timeout) \ - ldsem_down_write(sem, timeout) -#endif - - -struct tty_ldisc_ops { - int magic; - char *name; - int num; - int flags; - - /* - * The following routines are called from above. - */ - int (*open)(struct tty_struct *); - void (*close)(struct tty_struct *); - void (*flush_buffer)(struct tty_struct *tty); - ssize_t (*read)(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t nr); - ssize_t (*write)(struct tty_struct *tty, struct file *file, - const unsigned char *buf, size_t nr); - int (*ioctl)(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); - long (*compat_ioctl)(struct tty_struct *tty, struct file *file, - unsigned int cmd, unsigned long arg); - void (*set_termios)(struct tty_struct *tty, struct ktermios *old); - unsigned int (*poll)(struct tty_struct *, struct file *, - struct poll_table_struct *); - int (*hangup)(struct tty_struct *tty); - - /* - * The following routines are called from below. - */ - void (*receive_buf)(struct tty_struct *, const unsigned char *cp, - char *fp, int count); - void (*write_wakeup)(struct tty_struct *); - void (*dcd_change)(struct tty_struct *, unsigned int); - int (*receive_buf2)(struct tty_struct *, const unsigned char *cp, - char *fp, int count); - - struct module *owner; - - int refcount; -}; - -struct tty_ldisc { - struct tty_ldisc_ops *ops; - struct tty_struct *tty; -}; - -#define TTY_LDISC_MAGIC 0x5403 - -#define LDISC_FLAG_DEFINED 0x00000001 - -#define MODULE_ALIAS_LDISC(ldisc) \ - MODULE_ALIAS("tty-ldisc-" __stringify(ldisc)) - -#endif /* _LINUX_TTY_LDISC_H */ diff --git a/src/linux/include/linux/typecheck.h b/src/linux/include/linux/typecheck.h deleted file mode 100644 index eb5b74a..0000000 --- a/src/linux/include/linux/typecheck.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef TYPECHECK_H_INCLUDED -#define TYPECHECK_H_INCLUDED - -/* - * Check at compile time that something is of a particular type. - * Always evaluates to 1 so you may use it easily in comparisons. - */ -#define typecheck(type,x) \ -({ type __dummy; \ - typeof(x) __dummy2; \ - (void)(&__dummy == &__dummy2); \ - 1; \ -}) - -/* - * Check at compile time that 'function' is a certain type, or is a pointer - * to that type (needs to use typedef for the function type.) - */ -#define typecheck_fn(type,function) \ -({ typeof(type) __tmp = function; \ - (void)__tmp; \ -}) - -#endif /* TYPECHECK_H_INCLUDED */ diff --git a/src/linux/include/linux/types.h b/src/linux/include/linux/types.h deleted file mode 100644 index baf7183..0000000 --- a/src/linux/include/linux/types.h +++ /dev/null @@ -1,235 +0,0 @@ -#ifndef _LINUX_TYPES_H -#define _LINUX_TYPES_H - -#define __EXPORTED_HEADERS__ -#include - -#ifndef __ASSEMBLY__ - -#define DECLARE_BITMAP(name,bits) \ - unsigned long name[BITS_TO_LONGS(bits)] - -typedef __u32 __kernel_dev_t; - -typedef __kernel_fd_set fd_set; -typedef __kernel_dev_t dev_t; -typedef __kernel_ino_t ino_t; -typedef __kernel_mode_t mode_t; -typedef unsigned short umode_t; -typedef __u32 nlink_t; -typedef __kernel_off_t off_t; -typedef __kernel_pid_t pid_t; -typedef __kernel_daddr_t daddr_t; -typedef __kernel_key_t key_t; -typedef __kernel_suseconds_t suseconds_t; -typedef __kernel_timer_t timer_t; -typedef __kernel_clockid_t clockid_t; -typedef __kernel_mqd_t mqd_t; - -typedef _Bool bool; - -typedef __kernel_uid32_t uid_t; -typedef __kernel_gid32_t gid_t; -typedef __kernel_uid16_t uid16_t; -typedef __kernel_gid16_t gid16_t; - -typedef unsigned long uintptr_t; - -#ifdef CONFIG_HAVE_UID16 -/* This is defined by include/asm-{arch}/posix_types.h */ -typedef __kernel_old_uid_t old_uid_t; -typedef __kernel_old_gid_t old_gid_t; -#endif /* CONFIG_UID16 */ - -#if defined(__GNUC__) -typedef __kernel_loff_t loff_t; -#endif - -/* - * The following typedefs are also protected by individual ifdefs for - * historical reasons: - */ -#ifndef _SIZE_T -#define _SIZE_T -typedef __kernel_size_t size_t; -#endif - -#ifndef _SSIZE_T -#define _SSIZE_T -typedef __kernel_ssize_t ssize_t; -#endif - -#ifndef _PTRDIFF_T -#define _PTRDIFF_T -typedef __kernel_ptrdiff_t ptrdiff_t; -#endif - -#ifndef _TIME_T -#define _TIME_T -typedef __kernel_time_t time_t; -#endif - -#ifndef _CLOCK_T -#define _CLOCK_T -typedef __kernel_clock_t clock_t; -#endif - -#ifndef _CADDR_T -#define _CADDR_T -typedef __kernel_caddr_t caddr_t; -#endif - -/* bsd */ -typedef unsigned char u_char; -typedef unsigned short u_short; -typedef unsigned int u_int; -typedef unsigned long u_long; - -/* sysv */ -typedef unsigned char unchar; -typedef unsigned short ushort; -typedef unsigned int uint; -typedef unsigned long ulong; - -#ifndef __BIT_TYPES_DEFINED__ -#define __BIT_TYPES_DEFINED__ - -typedef __u8 u_int8_t; -typedef __s8 int8_t; -typedef __u16 u_int16_t; -typedef __s16 int16_t; -typedef __u32 u_int32_t; -typedef __s32 int32_t; - -#endif /* !(__BIT_TYPES_DEFINED__) */ - -typedef __u8 uint8_t; -typedef __u16 uint16_t; -typedef __u32 uint32_t; - -#if defined(__GNUC__) -typedef __u64 uint64_t; -typedef __u64 u_int64_t; -typedef __s64 int64_t; -#endif - -/* this is a special 64bit data type that is 8-byte aligned */ -#define aligned_u64 __u64 __attribute__((aligned(8))) -#define aligned_be64 __be64 __attribute__((aligned(8))) -#define aligned_le64 __le64 __attribute__((aligned(8))) - -/** - * The type used for indexing onto a disc or disc partition. - * - * Linux always considers sectors to be 512 bytes long independently - * of the devices real block size. - * - * blkcnt_t is the type of the inode's block count. - */ -#ifdef CONFIG_LBDAF -typedef u64 sector_t; -typedef u64 blkcnt_t; -#else -typedef unsigned long sector_t; -typedef unsigned long blkcnt_t; -#endif - -/* - * The type of an index into the pagecache. - */ -#define pgoff_t unsigned long - -/* - * A dma_addr_t can hold any valid DMA address, i.e., any address returned - * by the DMA API. - * - * If the DMA API only uses 32-bit addresses, dma_addr_t need only be 32 - * bits wide. Bus addresses, e.g., PCI BARs, may be wider than 32 bits, - * but drivers do memory-mapped I/O to ioremapped kernel virtual addresses, - * so they don't care about the size of the actual bus addresses. - */ -#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT -typedef u64 dma_addr_t; -#else -typedef u32 dma_addr_t; -#endif - -typedef unsigned __bitwise__ gfp_t; -typedef unsigned __bitwise__ fmode_t; - -#ifdef CONFIG_PHYS_ADDR_T_64BIT -typedef u64 phys_addr_t; -#else -typedef u32 phys_addr_t; -#endif - -typedef phys_addr_t resource_size_t; - -/* - * This type is the placeholder for a hardware interrupt number. It has to be - * big enough to enclose whatever representation is used by a given platform. - */ -typedef unsigned long irq_hw_number_t; - -typedef struct { - int counter; -} atomic_t; - -#ifdef CONFIG_64BIT -typedef struct { - long counter; -} atomic64_t; -#endif - -struct list_head { - struct list_head *next, *prev; -}; - -struct hlist_head { - struct hlist_node *first; -}; - -struct hlist_node { - struct hlist_node *next, **pprev; -}; - -struct ustat { - __kernel_daddr_t f_tfree; - __kernel_ino_t f_tinode; - char f_fname[6]; - char f_fpack[6]; -}; - -/** - * struct callback_head - callback structure for use with RCU and task_work - * @next: next update requests in a list - * @func: actual update function to call after the grace period. - * - * The struct is aligned to size of pointer. On most architectures it happens - * naturally due ABI requirements, but some architectures (like CRIS) have - * weird ABI and we need to ask it explicitly. - * - * The alignment is required to guarantee that bits 0 and 1 of @next will be - * clear under normal conditions -- as long as we use call_rcu(), - * call_rcu_bh(), call_rcu_sched(), or call_srcu() to queue callback. - * - * This guarantee is important for few reasons: - * - future call_rcu_lazy() will make use of lower bits in the pointer; - * - the structure shares storage spacer in struct page with @compound_head, - * which encode PageTail() in bit 0. The guarantee is needed to avoid - * false-positive PageTail(). - */ -struct callback_head { - struct callback_head *next; - void (*func)(struct callback_head *head); -} __attribute__((aligned(sizeof(void *)))); -#define rcu_head callback_head - -typedef void (*rcu_callback_t)(struct rcu_head *head); -typedef void (*call_rcu_func_t)(struct rcu_head *head, rcu_callback_t func); - -/* clocksource cycle base type */ -typedef u64 cycle_t; - -#endif /* __ASSEMBLY__ */ -#endif /* _LINUX_TYPES_H */ diff --git a/src/linux/include/linux/u64_stats_sync.h b/src/linux/include/linux/u64_stats_sync.h deleted file mode 100644 index 650f3dd..0000000 --- a/src/linux/include/linux/u64_stats_sync.h +++ /dev/null @@ -1,165 +0,0 @@ -#ifndef _LINUX_U64_STATS_SYNC_H -#define _LINUX_U64_STATS_SYNC_H - -/* - * To properly implement 64bits network statistics on 32bit and 64bit hosts, - * we provide a synchronization point, that is a noop on 64bit or UP kernels. - * - * Key points : - * 1) Use a seqcount on SMP 32bits, with low overhead. - * 2) Whole thing is a noop on 64bit arches or UP kernels. - * 3) Write side must ensure mutual exclusion or one seqcount update could - * be lost, thus blocking readers forever. - * If this synchronization point is not a mutex, but a spinlock or - * spinlock_bh() or disable_bh() : - * 3.1) Write side should not sleep. - * 3.2) Write side should not allow preemption. - * 3.3) If applicable, interrupts should be disabled. - * - * 4) If reader fetches several counters, there is no guarantee the whole values - * are consistent (remember point 1) : this is a noop on 64bit arches anyway) - * - * 5) readers are allowed to sleep or be preempted/interrupted : They perform - * pure reads. But if they have to fetch many values, it's better to not allow - * preemptions/interruptions to avoid many retries. - * - * 6) If counter might be written by an interrupt, readers should block interrupts. - * (On UP, there is no seqcount_t protection, a reader allowing interrupts could - * read partial values) - * - * 7) For irq and softirq uses, readers can use u64_stats_fetch_begin_irq() and - * u64_stats_fetch_retry_irq() helpers - * - * Usage : - * - * Stats producer (writer) should use following template granted it already got - * an exclusive access to counters (a lock is already taken, or per cpu - * data is used [in a non preemptable context]) - * - * spin_lock_bh(...) or other synchronization to get exclusive access - * ... - * u64_stats_update_begin(&stats->syncp); - * stats->bytes64 += len; // non atomic operation - * stats->packets64++; // non atomic operation - * u64_stats_update_end(&stats->syncp); - * - * While a consumer (reader) should use following template to get consistent - * snapshot for each variable (but no guarantee on several ones) - * - * u64 tbytes, tpackets; - * unsigned int start; - * - * do { - * start = u64_stats_fetch_begin(&stats->syncp); - * tbytes = stats->bytes64; // non atomic operation - * tpackets = stats->packets64; // non atomic operation - * } while (u64_stats_fetch_retry(&stats->syncp, start)); - * - * - * Example of use in drivers/net/loopback.c, using per_cpu containers, - * in BH disabled context. - */ -#include - -struct u64_stats_sync { -#if BITS_PER_LONG==32 && defined(CONFIG_SMP) - seqcount_t seq; -#endif -}; - - -static inline void u64_stats_init(struct u64_stats_sync *syncp) -{ -#if BITS_PER_LONG == 32 && defined(CONFIG_SMP) - seqcount_init(&syncp->seq); -#endif -} - -static inline void u64_stats_update_begin(struct u64_stats_sync *syncp) -{ -#if BITS_PER_LONG==32 && defined(CONFIG_SMP) - write_seqcount_begin(&syncp->seq); -#endif -} - -static inline void u64_stats_update_end(struct u64_stats_sync *syncp) -{ -#if BITS_PER_LONG==32 && defined(CONFIG_SMP) - write_seqcount_end(&syncp->seq); -#endif -} - -static inline void u64_stats_update_begin_raw(struct u64_stats_sync *syncp) -{ -#if BITS_PER_LONG==32 && defined(CONFIG_SMP) - raw_write_seqcount_begin(&syncp->seq); -#endif -} - -static inline void u64_stats_update_end_raw(struct u64_stats_sync *syncp) -{ -#if BITS_PER_LONG==32 && defined(CONFIG_SMP) - raw_write_seqcount_end(&syncp->seq); -#endif -} - -static inline unsigned int __u64_stats_fetch_begin(const struct u64_stats_sync *syncp) -{ -#if BITS_PER_LONG==32 && defined(CONFIG_SMP) - return read_seqcount_begin(&syncp->seq); -#else - return 0; -#endif -} - -static inline unsigned int u64_stats_fetch_begin(const struct u64_stats_sync *syncp) -{ -#if BITS_PER_LONG==32 && !defined(CONFIG_SMP) - preempt_disable(); -#endif - return __u64_stats_fetch_begin(syncp); -} - -static inline bool __u64_stats_fetch_retry(const struct u64_stats_sync *syncp, - unsigned int start) -{ -#if BITS_PER_LONG==32 && defined(CONFIG_SMP) - return read_seqcount_retry(&syncp->seq, start); -#else - return false; -#endif -} - -static inline bool u64_stats_fetch_retry(const struct u64_stats_sync *syncp, - unsigned int start) -{ -#if BITS_PER_LONG==32 && !defined(CONFIG_SMP) - preempt_enable(); -#endif - return __u64_stats_fetch_retry(syncp, start); -} - -/* - * In case irq handlers can update u64 counters, readers can use following helpers - * - SMP 32bit arches use seqcount protection, irq safe. - * - UP 32bit must disable irqs. - * - 64bit have no problem atomically reading u64 values, irq safe. - */ -static inline unsigned int u64_stats_fetch_begin_irq(const struct u64_stats_sync *syncp) -{ -#if BITS_PER_LONG==32 && !defined(CONFIG_SMP) - local_irq_disable(); -#endif - return __u64_stats_fetch_begin(syncp); -} - -static inline bool u64_stats_fetch_retry_irq(const struct u64_stats_sync *syncp, - unsigned int start) -{ -#if BITS_PER_LONG==32 && !defined(CONFIG_SMP) - local_irq_enable(); -#endif - return __u64_stats_fetch_retry(syncp, start); -} - -#endif /* _LINUX_U64_STATS_SYNC_H */ diff --git a/src/linux/include/linux/uaccess.h b/src/linux/include/linux/uaccess.h deleted file mode 100644 index f30c187..0000000 --- a/src/linux/include/linux/uaccess.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef __LINUX_UACCESS_H__ -#define __LINUX_UACCESS_H__ - -#include -#include - -static __always_inline void pagefault_disabled_inc(void) -{ - current->pagefault_disabled++; -} - -static __always_inline void pagefault_disabled_dec(void) -{ - current->pagefault_disabled--; - WARN_ON(current->pagefault_disabled < 0); -} - -/* - * These routines enable/disable the pagefault handler. If disabled, it will - * not take any locks and go straight to the fixup table. - * - * User access methods will not sleep when called from a pagefault_disabled() - * environment. - */ -static inline void pagefault_disable(void) -{ - pagefault_disabled_inc(); - /* - * make sure to have issued the store before a pagefault - * can hit. - */ - barrier(); -} - -static inline void pagefault_enable(void) -{ - /* - * make sure to issue those last loads/stores before enabling - * the pagefault handler again. - */ - barrier(); - pagefault_disabled_dec(); -} - -/* - * Is the pagefault handler disabled? If so, user access methods will not sleep. - */ -#define pagefault_disabled() (current->pagefault_disabled != 0) - -/* - * The pagefault handler is in general disabled by pagefault_disable() or - * when in irq context (via in_atomic()). - * - * This function should only be used by the fault handlers. Other users should - * stick to pagefault_disabled(). - * Please NEVER use preempt_disable() to disable the fault handler. With - * !CONFIG_PREEMPT_COUNT, this is like a NOP. So the handler won't be disabled. - * in_atomic() will report different values based on !CONFIG_PREEMPT_COUNT. - */ -#define faulthandler_disabled() (pagefault_disabled() || in_atomic()) - -#ifndef ARCH_HAS_NOCACHE_UACCESS - -static inline unsigned long __copy_from_user_inatomic_nocache(void *to, - const void __user *from, unsigned long n) -{ - return __copy_from_user_inatomic(to, from, n); -} - -static inline unsigned long __copy_from_user_nocache(void *to, - const void __user *from, unsigned long n) -{ - return __copy_from_user(to, from, n); -} - -#endif /* ARCH_HAS_NOCACHE_UACCESS */ - -/* - * probe_kernel_read(): safely attempt to read from a location - * @dst: pointer to the buffer that shall take the data - * @src: address to read from - * @size: size of the data chunk - * - * Safely read from address @src to the buffer at @dst. If a kernel fault - * happens, handle that and return -EFAULT. - */ -extern long probe_kernel_read(void *dst, const void *src, size_t size); -extern long __probe_kernel_read(void *dst, const void *src, size_t size); - -/* - * probe_kernel_write(): safely attempt to write to a location - * @dst: address to write to - * @src: pointer to the data that shall be written - * @size: size of the data chunk - * - * Safely write to address @dst from the buffer at @src. If a kernel fault - * happens, handle that and return -EFAULT. - */ -extern long notrace probe_kernel_write(void *dst, const void *src, size_t size); -extern long notrace __probe_kernel_write(void *dst, const void *src, size_t size); - -extern long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count); - -/** - * probe_kernel_address(): safely attempt to read from a location - * @addr: address to read from - * @retval: read into this variable - * - * Returns 0 on success, or -EFAULT. - */ -#define probe_kernel_address(addr, retval) \ - probe_kernel_read(&retval, addr, sizeof(retval)) - -#ifndef user_access_begin -#define user_access_begin() do { } while (0) -#define user_access_end() do { } while (0) -#define unsafe_get_user(x, ptr, err) do { if (unlikely(__get_user(x, ptr))) goto err; } while (0) -#define unsafe_put_user(x, ptr, err) do { if (unlikely(__put_user(x, ptr))) goto err; } while (0) -#endif - -#endif /* __LINUX_UACCESS_H__ */ diff --git a/src/linux/include/linux/udp.h b/src/linux/include/linux/udp.h deleted file mode 100644 index d1fd8cd..0000000 --- a/src/linux/include/linux/udp.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the UDP protocol. - * - * Version: @(#)udp.h 1.0.2 04/28/93 - * - * Author: Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_UDP_H -#define _LINUX_UDP_H - -#include -#include -#include -#include - -static inline struct udphdr *udp_hdr(const struct sk_buff *skb) -{ - return (struct udphdr *)skb_transport_header(skb); -} - -static inline struct udphdr *inner_udp_hdr(const struct sk_buff *skb) -{ - return (struct udphdr *)skb_inner_transport_header(skb); -} - -#define UDP_HTABLE_SIZE_MIN (CONFIG_BASE_SMALL ? 128 : 256) - -static inline u32 udp_hashfn(const struct net *net, u32 num, u32 mask) -{ - return (num + net_hash_mix(net)) & mask; -} - -struct udp_sock { - /* inet_sock has to be the first member */ - struct inet_sock inet; -#define udp_port_hash inet.sk.__sk_common.skc_u16hashes[0] -#define udp_portaddr_hash inet.sk.__sk_common.skc_u16hashes[1] -#define udp_portaddr_node inet.sk.__sk_common.skc_portaddr_node - int pending; /* Any pending frames ? */ - unsigned int corkflag; /* Cork is required */ - __u8 encap_type; /* Is this an Encapsulation socket? */ - unsigned char no_check6_tx:1,/* Send zero UDP6 checksums on TX? */ - no_check6_rx:1;/* Allow zero UDP6 checksums on RX? */ - /* - * Following member retains the information to create a UDP header - * when the socket is uncorked. - */ - __u16 len; /* total length of pending frames */ - /* - * Fields specific to UDP-Lite. - */ - __u16 pcslen; - __u16 pcrlen; -/* indicator bits used by pcflag: */ -#define UDPLITE_BIT 0x1 /* set by udplite proto init function */ -#define UDPLITE_SEND_CC 0x2 /* set via udplite setsockopt */ -#define UDPLITE_RECV_CC 0x4 /* set via udplite setsocktopt */ - __u8 pcflag; /* marks socket as UDP-Lite if > 0 */ - __u8 unused[3]; - /* - * For encapsulation sockets. - */ - int (*encap_rcv)(struct sock *sk, struct sk_buff *skb); - void (*encap_destroy)(struct sock *sk); - - /* GRO functions for UDP socket */ - struct sk_buff ** (*gro_receive)(struct sock *sk, - struct sk_buff **head, - struct sk_buff *skb); - int (*gro_complete)(struct sock *sk, - struct sk_buff *skb, - int nhoff); -}; - -static inline struct udp_sock *udp_sk(const struct sock *sk) -{ - return (struct udp_sock *)sk; -} - -static inline void udp_set_no_check6_tx(struct sock *sk, bool val) -{ - udp_sk(sk)->no_check6_tx = val; -} - -static inline void udp_set_no_check6_rx(struct sock *sk, bool val) -{ - udp_sk(sk)->no_check6_rx = val; -} - -static inline bool udp_get_no_check6_tx(struct sock *sk) -{ - return udp_sk(sk)->no_check6_tx; -} - -static inline bool udp_get_no_check6_rx(struct sock *sk) -{ - return udp_sk(sk)->no_check6_rx; -} - -#define udp_portaddr_for_each_entry(__sk, list) \ - hlist_for_each_entry(__sk, list, __sk_common.skc_portaddr_node) - -#define udp_portaddr_for_each_entry_rcu(__sk, list) \ - hlist_for_each_entry_rcu(__sk, list, __sk_common.skc_portaddr_node) - -#define IS_UDPLITE(__sk) (udp_sk(__sk)->pcflag) - -#endif /* _LINUX_UDP_H */ diff --git a/src/linux/include/linux/uidgid.h b/src/linux/include/linux/uidgid.h deleted file mode 100644 index 25e9d92..0000000 --- a/src/linux/include/linux/uidgid.h +++ /dev/null @@ -1,190 +0,0 @@ -#ifndef _LINUX_UIDGID_H -#define _LINUX_UIDGID_H - -/* - * A set of types for the internal kernel types representing uids and gids. - * - * The types defined in this header allow distinguishing which uids and gids in - * the kernel are values used by userspace and which uid and gid values are - * the internal kernel values. With the addition of user namespaces the values - * can be different. Using the type system makes it possible for the compiler - * to detect when we overlook these differences. - * - */ -#include -#include - -struct user_namespace; -extern struct user_namespace init_user_ns; - -typedef struct { - uid_t val; -} kuid_t; - - -typedef struct { - gid_t val; -} kgid_t; - -#define KUIDT_INIT(value) (kuid_t){ value } -#define KGIDT_INIT(value) (kgid_t){ value } - -#ifdef CONFIG_MULTIUSER -static inline uid_t __kuid_val(kuid_t uid) -{ - return uid.val; -} - -static inline gid_t __kgid_val(kgid_t gid) -{ - return gid.val; -} -#else -static inline uid_t __kuid_val(kuid_t uid) -{ - return 0; -} - -static inline gid_t __kgid_val(kgid_t gid) -{ - return 0; -} -#endif - -#define GLOBAL_ROOT_UID KUIDT_INIT(0) -#define GLOBAL_ROOT_GID KGIDT_INIT(0) - -#define INVALID_UID KUIDT_INIT(-1) -#define INVALID_GID KGIDT_INIT(-1) - -static inline bool uid_eq(kuid_t left, kuid_t right) -{ - return __kuid_val(left) == __kuid_val(right); -} - -static inline bool gid_eq(kgid_t left, kgid_t right) -{ - return __kgid_val(left) == __kgid_val(right); -} - -static inline bool uid_gt(kuid_t left, kuid_t right) -{ - return __kuid_val(left) > __kuid_val(right); -} - -static inline bool gid_gt(kgid_t left, kgid_t right) -{ - return __kgid_val(left) > __kgid_val(right); -} - -static inline bool uid_gte(kuid_t left, kuid_t right) -{ - return __kuid_val(left) >= __kuid_val(right); -} - -static inline bool gid_gte(kgid_t left, kgid_t right) -{ - return __kgid_val(left) >= __kgid_val(right); -} - -static inline bool uid_lt(kuid_t left, kuid_t right) -{ - return __kuid_val(left) < __kuid_val(right); -} - -static inline bool gid_lt(kgid_t left, kgid_t right) -{ - return __kgid_val(left) < __kgid_val(right); -} - -static inline bool uid_lte(kuid_t left, kuid_t right) -{ - return __kuid_val(left) <= __kuid_val(right); -} - -static inline bool gid_lte(kgid_t left, kgid_t right) -{ - return __kgid_val(left) <= __kgid_val(right); -} - -static inline bool uid_valid(kuid_t uid) -{ - return __kuid_val(uid) != (uid_t) -1; -} - -static inline bool gid_valid(kgid_t gid) -{ - return __kgid_val(gid) != (gid_t) -1; -} - -#ifdef CONFIG_USER_NS - -extern kuid_t make_kuid(struct user_namespace *from, uid_t uid); -extern kgid_t make_kgid(struct user_namespace *from, gid_t gid); - -extern uid_t from_kuid(struct user_namespace *to, kuid_t uid); -extern gid_t from_kgid(struct user_namespace *to, kgid_t gid); -extern uid_t from_kuid_munged(struct user_namespace *to, kuid_t uid); -extern gid_t from_kgid_munged(struct user_namespace *to, kgid_t gid); - -static inline bool kuid_has_mapping(struct user_namespace *ns, kuid_t uid) -{ - return from_kuid(ns, uid) != (uid_t) -1; -} - -static inline bool kgid_has_mapping(struct user_namespace *ns, kgid_t gid) -{ - return from_kgid(ns, gid) != (gid_t) -1; -} - -#else - -static inline kuid_t make_kuid(struct user_namespace *from, uid_t uid) -{ - return KUIDT_INIT(uid); -} - -static inline kgid_t make_kgid(struct user_namespace *from, gid_t gid) -{ - return KGIDT_INIT(gid); -} - -static inline uid_t from_kuid(struct user_namespace *to, kuid_t kuid) -{ - return __kuid_val(kuid); -} - -static inline gid_t from_kgid(struct user_namespace *to, kgid_t kgid) -{ - return __kgid_val(kgid); -} - -static inline uid_t from_kuid_munged(struct user_namespace *to, kuid_t kuid) -{ - uid_t uid = from_kuid(to, kuid); - if (uid == (uid_t)-1) - uid = overflowuid; - return uid; -} - -static inline gid_t from_kgid_munged(struct user_namespace *to, kgid_t kgid) -{ - gid_t gid = from_kgid(to, kgid); - if (gid == (gid_t)-1) - gid = overflowgid; - return gid; -} - -static inline bool kuid_has_mapping(struct user_namespace *ns, kuid_t uid) -{ - return uid_valid(uid); -} - -static inline bool kgid_has_mapping(struct user_namespace *ns, kgid_t gid) -{ - return gid_valid(gid); -} - -#endif /* CONFIG_USER_NS */ - -#endif /* _LINUX_UIDGID_H */ diff --git a/src/linux/include/linux/uio.h b/src/linux/include/linux/uio.h deleted file mode 100644 index 6e22b54..0000000 --- a/src/linux/include/linux/uio.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Berkeley style UIO structures - Alan Cox 1994. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef __LINUX_UIO_H -#define __LINUX_UIO_H - -#include -#include - -struct page; -struct pipe_inode_info; - -struct kvec { - void *iov_base; /* and that should *never* hold a userland pointer */ - size_t iov_len; -}; - -enum { - ITER_IOVEC = 0, - ITER_KVEC = 2, - ITER_BVEC = 4, - ITER_PIPE = 8, -}; - -struct iov_iter { - int type; - size_t iov_offset; - size_t count; - union { - const struct iovec *iov; - const struct kvec *kvec; - const struct bio_vec *bvec; - struct pipe_inode_info *pipe; - }; - union { - unsigned long nr_segs; - int idx; - }; -}; - -/* - * Total number of bytes covered by an iovec. - * - * NOTE that it is not safe to use this function until all the iovec's - * segment lengths have been validated. Because the individual lengths can - * overflow a size_t when added together. - */ -static inline size_t iov_length(const struct iovec *iov, unsigned long nr_segs) -{ - unsigned long seg; - size_t ret = 0; - - for (seg = 0; seg < nr_segs; seg++) - ret += iov[seg].iov_len; - return ret; -} - -static inline struct iovec iov_iter_iovec(const struct iov_iter *iter) -{ - return (struct iovec) { - .iov_base = iter->iov->iov_base + iter->iov_offset, - .iov_len = min(iter->count, - iter->iov->iov_len - iter->iov_offset), - }; -} - -#define iov_for_each(iov, iter, start) \ - if (!((start).type & (ITER_BVEC | ITER_PIPE))) \ - for (iter = (start); \ - (iter).count && \ - ((iov = iov_iter_iovec(&(iter))), 1); \ - iov_iter_advance(&(iter), (iov).iov_len)) - -unsigned long iov_shorten(struct iovec *iov, unsigned long nr_segs, size_t to); - -size_t iov_iter_copy_from_user_atomic(struct page *page, - struct iov_iter *i, unsigned long offset, size_t bytes); -void iov_iter_advance(struct iov_iter *i, size_t bytes); -int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes); -size_t iov_iter_single_seg_count(const struct iov_iter *i); -size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, - struct iov_iter *i); -size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes, - struct iov_iter *i); -size_t copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i); -size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i); -size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i); -size_t iov_iter_zero(size_t bytes, struct iov_iter *); -unsigned long iov_iter_alignment(const struct iov_iter *i); -unsigned long iov_iter_gap_alignment(const struct iov_iter *i); -void iov_iter_init(struct iov_iter *i, int direction, const struct iovec *iov, - unsigned long nr_segs, size_t count); -void iov_iter_kvec(struct iov_iter *i, int direction, const struct kvec *kvec, - unsigned long nr_segs, size_t count); -void iov_iter_bvec(struct iov_iter *i, int direction, const struct bio_vec *bvec, - unsigned long nr_segs, size_t count); -void iov_iter_pipe(struct iov_iter *i, int direction, struct pipe_inode_info *pipe, - size_t count); -ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages, - size_t maxsize, unsigned maxpages, size_t *start); -ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages, - size_t maxsize, size_t *start); -int iov_iter_npages(const struct iov_iter *i, int maxpages); - -const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags); - -static inline size_t iov_iter_count(const struct iov_iter *i) -{ - return i->count; -} - -static inline bool iter_is_iovec(const struct iov_iter *i) -{ - return !(i->type & (ITER_BVEC | ITER_KVEC | ITER_PIPE)); -} - -/* - * Get one of READ or WRITE out of iter->type without any other flags OR'd in - * with it. - * - * The ?: is just for type safety. - */ -#define iov_iter_rw(i) ((0 ? (struct iov_iter *)0 : (i))->type & RW_MASK) - -/* - * Cap the iov_iter by given limit; note that the second argument is - * *not* the new size - it's upper limit for such. Passing it a value - * greater than the amount of data in iov_iter is fine - it'll just do - * nothing in that case. - */ -static inline void iov_iter_truncate(struct iov_iter *i, u64 count) -{ - /* - * count doesn't have to fit in size_t - comparison extends both - * operands to u64 here and any value that would be truncated by - * conversion in assignement is by definition greater than all - * values of size_t, including old i->count. - */ - if (i->count > count) - i->count = count; -} - -/* - * reexpand a previously truncated iterator; count must be no more than how much - * we had shrunk it. - */ -static inline void iov_iter_reexpand(struct iov_iter *i, size_t count) -{ - i->count = count; -} -size_t csum_and_copy_to_iter(const void *addr, size_t bytes, __wsum *csum, struct iov_iter *i); -size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i); - -int import_iovec(int type, const struct iovec __user * uvector, - unsigned nr_segs, unsigned fast_segs, - struct iovec **iov, struct iov_iter *i); - -#ifdef CONFIG_COMPAT -struct compat_iovec; -int compat_import_iovec(int type, const struct compat_iovec __user * uvector, - unsigned nr_segs, unsigned fast_segs, - struct iovec **iov, struct iov_iter *i); -#endif - -int import_single_range(int type, void __user *buf, size_t len, - struct iovec *iov, struct iov_iter *i); - -#endif diff --git a/src/linux/include/linux/unaligned/be_byteshift.h b/src/linux/include/linux/unaligned/be_byteshift.h deleted file mode 100644 index 9356b24..0000000 --- a/src/linux/include/linux/unaligned/be_byteshift.h +++ /dev/null @@ -1,70 +0,0 @@ -#ifndef _LINUX_UNALIGNED_BE_BYTESHIFT_H -#define _LINUX_UNALIGNED_BE_BYTESHIFT_H - -#include - -static inline u16 __get_unaligned_be16(const u8 *p) -{ - return p[0] << 8 | p[1]; -} - -static inline u32 __get_unaligned_be32(const u8 *p) -{ - return p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; -} - -static inline u64 __get_unaligned_be64(const u8 *p) -{ - return (u64)__get_unaligned_be32(p) << 32 | - __get_unaligned_be32(p + 4); -} - -static inline void __put_unaligned_be16(u16 val, u8 *p) -{ - *p++ = val >> 8; - *p++ = val; -} - -static inline void __put_unaligned_be32(u32 val, u8 *p) -{ - __put_unaligned_be16(val >> 16, p); - __put_unaligned_be16(val, p + 2); -} - -static inline void __put_unaligned_be64(u64 val, u8 *p) -{ - __put_unaligned_be32(val >> 32, p); - __put_unaligned_be32(val, p + 4); -} - -static inline u16 get_unaligned_be16(const void *p) -{ - return __get_unaligned_be16((const u8 *)p); -} - -static inline u32 get_unaligned_be32(const void *p) -{ - return __get_unaligned_be32((const u8 *)p); -} - -static inline u64 get_unaligned_be64(const void *p) -{ - return __get_unaligned_be64((const u8 *)p); -} - -static inline void put_unaligned_be16(u16 val, void *p) -{ - __put_unaligned_be16(val, p); -} - -static inline void put_unaligned_be32(u32 val, void *p) -{ - __put_unaligned_be32(val, p); -} - -static inline void put_unaligned_be64(u64 val, void *p) -{ - __put_unaligned_be64(val, p); -} - -#endif /* _LINUX_UNALIGNED_BE_BYTESHIFT_H */ diff --git a/src/linux/include/linux/unaligned/generic.h b/src/linux/include/linux/unaligned/generic.h deleted file mode 100644 index 02d97ff..0000000 --- a/src/linux/include/linux/unaligned/generic.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef _LINUX_UNALIGNED_GENERIC_H -#define _LINUX_UNALIGNED_GENERIC_H - -/* - * Cause a link-time error if we try an unaligned access other than - * 1,2,4 or 8 bytes long - */ -extern void __bad_unaligned_access_size(void); - -#define __get_unaligned_le(ptr) ((__force typeof(*(ptr)))({ \ - __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \ - __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_le16((ptr)), \ - __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_le32((ptr)), \ - __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_le64((ptr)), \ - __bad_unaligned_access_size())))); \ - })) - -#define __get_unaligned_be(ptr) ((__force typeof(*(ptr)))({ \ - __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \ - __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_be16((ptr)), \ - __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_be32((ptr)), \ - __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_be64((ptr)), \ - __bad_unaligned_access_size())))); \ - })) - -#define __put_unaligned_le(val, ptr) ({ \ - void *__gu_p = (ptr); \ - switch (sizeof(*(ptr))) { \ - case 1: \ - *(u8 *)__gu_p = (__force u8)(val); \ - break; \ - case 2: \ - put_unaligned_le16((__force u16)(val), __gu_p); \ - break; \ - case 4: \ - put_unaligned_le32((__force u32)(val), __gu_p); \ - break; \ - case 8: \ - put_unaligned_le64((__force u64)(val), __gu_p); \ - break; \ - default: \ - __bad_unaligned_access_size(); \ - break; \ - } \ - (void)0; }) - -#define __put_unaligned_be(val, ptr) ({ \ - void *__gu_p = (ptr); \ - switch (sizeof(*(ptr))) { \ - case 1: \ - *(u8 *)__gu_p = (__force u8)(val); \ - break; \ - case 2: \ - put_unaligned_be16((__force u16)(val), __gu_p); \ - break; \ - case 4: \ - put_unaligned_be32((__force u32)(val), __gu_p); \ - break; \ - case 8: \ - put_unaligned_be64((__force u64)(val), __gu_p); \ - break; \ - default: \ - __bad_unaligned_access_size(); \ - break; \ - } \ - (void)0; }) - -#endif /* _LINUX_UNALIGNED_GENERIC_H */ diff --git a/src/linux/include/linux/unaligned/le_struct.h b/src/linux/include/linux/unaligned/le_struct.h deleted file mode 100644 index 088c457..0000000 --- a/src/linux/include/linux/unaligned/le_struct.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef _LINUX_UNALIGNED_LE_STRUCT_H -#define _LINUX_UNALIGNED_LE_STRUCT_H - -#include - -static inline u16 get_unaligned_le16(const void *p) -{ - return __get_unaligned_cpu16((const u8 *)p); -} - -static inline u32 get_unaligned_le32(const void *p) -{ - return __get_unaligned_cpu32((const u8 *)p); -} - -static inline u64 get_unaligned_le64(const void *p) -{ - return __get_unaligned_cpu64((const u8 *)p); -} - -static inline void put_unaligned_le16(u16 val, void *p) -{ - __put_unaligned_cpu16(val, p); -} - -static inline void put_unaligned_le32(u32 val, void *p) -{ - __put_unaligned_cpu32(val, p); -} - -static inline void put_unaligned_le64(u64 val, void *p) -{ - __put_unaligned_cpu64(val, p); -} - -#endif /* _LINUX_UNALIGNED_LE_STRUCT_H */ diff --git a/src/linux/include/linux/unaligned/packed_struct.h b/src/linux/include/linux/unaligned/packed_struct.h deleted file mode 100644 index c0d817d..0000000 --- a/src/linux/include/linux/unaligned/packed_struct.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef _LINUX_UNALIGNED_PACKED_STRUCT_H -#define _LINUX_UNALIGNED_PACKED_STRUCT_H - -#include - -struct __una_u16 { u16 x; } __packed; -struct __una_u32 { u32 x; } __packed; -struct __una_u64 { u64 x; } __packed; - -static inline u16 __get_unaligned_cpu16(const void *p) -{ - const struct __una_u16 *ptr = (const struct __una_u16 *)p; - return ptr->x; -} - -static inline u32 __get_unaligned_cpu32(const void *p) -{ - const struct __una_u32 *ptr = (const struct __una_u32 *)p; - return ptr->x; -} - -static inline u64 __get_unaligned_cpu64(const void *p) -{ - const struct __una_u64 *ptr = (const struct __una_u64 *)p; - return ptr->x; -} - -static inline void __put_unaligned_cpu16(u16 val, void *p) -{ - struct __una_u16 *ptr = (struct __una_u16 *)p; - ptr->x = val; -} - -static inline void __put_unaligned_cpu32(u32 val, void *p) -{ - struct __una_u32 *ptr = (struct __una_u32 *)p; - ptr->x = val; -} - -static inline void __put_unaligned_cpu64(u64 val, void *p) -{ - struct __una_u64 *ptr = (struct __una_u64 *)p; - ptr->x = val; -} - -#endif /* _LINUX_UNALIGNED_PACKED_STRUCT_H */ diff --git a/src/linux/include/linux/uprobes.h b/src/linux/include/linux/uprobes.h deleted file mode 100644 index 4a29c75..0000000 --- a/src/linux/include/linux/uprobes.h +++ /dev/null @@ -1,206 +0,0 @@ -#ifndef _LINUX_UPROBES_H -#define _LINUX_UPROBES_H -/* - * User-space Probes (UProbes) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) IBM Corporation, 2008-2012 - * Authors: - * Srikar Dronamraju - * Jim Keniston - * Copyright (C) 2011-2012 Red Hat, Inc., Peter Zijlstra - */ - -#include -#include -#include - -struct vm_area_struct; -struct mm_struct; -struct inode; -struct notifier_block; -struct page; - -#define UPROBE_HANDLER_REMOVE 1 -#define UPROBE_HANDLER_MASK 1 - -#define MAX_URETPROBE_DEPTH 64 - -enum uprobe_filter_ctx { - UPROBE_FILTER_REGISTER, - UPROBE_FILTER_UNREGISTER, - UPROBE_FILTER_MMAP, -}; - -struct uprobe_consumer { - int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs); - int (*ret_handler)(struct uprobe_consumer *self, - unsigned long func, - struct pt_regs *regs); - bool (*filter)(struct uprobe_consumer *self, - enum uprobe_filter_ctx ctx, - struct mm_struct *mm); - - struct uprobe_consumer *next; -}; - -#ifdef CONFIG_UPROBES -#include - -enum uprobe_task_state { - UTASK_RUNNING, - UTASK_SSTEP, - UTASK_SSTEP_ACK, - UTASK_SSTEP_TRAPPED, -}; - -/* - * uprobe_task: Metadata of a task while it singlesteps. - */ -struct uprobe_task { - enum uprobe_task_state state; - - union { - struct { - struct arch_uprobe_task autask; - unsigned long vaddr; - }; - - struct { - struct callback_head dup_xol_work; - unsigned long dup_xol_addr; - }; - }; - - struct uprobe *active_uprobe; - unsigned long xol_vaddr; - - struct return_instance *return_instances; - unsigned int depth; -}; - -struct return_instance { - struct uprobe *uprobe; - unsigned long func; - unsigned long stack; /* stack pointer */ - unsigned long orig_ret_vaddr; /* original return address */ - bool chained; /* true, if instance is nested */ - - struct return_instance *next; /* keep as stack */ -}; - -enum rp_check { - RP_CHECK_CALL, - RP_CHECK_CHAIN_CALL, - RP_CHECK_RET, -}; - -struct xol_area; - -struct uprobes_state { - struct xol_area *xol_area; -}; - -extern int set_swbp(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); -extern int set_orig_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long vaddr); -extern bool is_swbp_insn(uprobe_opcode_t *insn); -extern bool is_trap_insn(uprobe_opcode_t *insn); -extern unsigned long uprobe_get_swbp_addr(struct pt_regs *regs); -extern unsigned long uprobe_get_trap_addr(struct pt_regs *regs); -extern int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr, uprobe_opcode_t); -extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); -extern int uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool); -extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); -extern int uprobe_mmap(struct vm_area_struct *vma); -extern void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end); -extern void uprobe_start_dup_mmap(void); -extern void uprobe_end_dup_mmap(void); -extern void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm); -extern void uprobe_free_utask(struct task_struct *t); -extern void uprobe_copy_process(struct task_struct *t, unsigned long flags); -extern int uprobe_post_sstep_notifier(struct pt_regs *regs); -extern int uprobe_pre_sstep_notifier(struct pt_regs *regs); -extern void uprobe_notify_resume(struct pt_regs *regs); -extern bool uprobe_deny_signal(void); -extern bool arch_uprobe_skip_sstep(struct arch_uprobe *aup, struct pt_regs *regs); -extern void uprobe_clear_state(struct mm_struct *mm); -extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr); -extern int arch_uprobe_pre_xol(struct arch_uprobe *aup, struct pt_regs *regs); -extern int arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs); -extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk); -extern int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data); -extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs); -extern unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs *regs); -extern bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx, struct pt_regs *regs); -extern bool arch_uprobe_ignore(struct arch_uprobe *aup, struct pt_regs *regs); -extern void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr, - void *src, unsigned long len); -#else /* !CONFIG_UPROBES */ -struct uprobes_state { -}; - -#define uprobe_get_trap_addr(regs) instruction_pointer(regs) - -static inline int -uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer *uc) -{ - return -ENOSYS; -} -static inline int -uprobe_apply(struct inode *inode, loff_t offset, struct uprobe_consumer *uc, bool add) -{ - return -ENOSYS; -} -static inline void -uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc) -{ -} -static inline int uprobe_mmap(struct vm_area_struct *vma) -{ - return 0; -} -static inline void -uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end) -{ -} -static inline void uprobe_start_dup_mmap(void) -{ -} -static inline void uprobe_end_dup_mmap(void) -{ -} -static inline void -uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm) -{ -} -static inline void uprobe_notify_resume(struct pt_regs *regs) -{ -} -static inline bool uprobe_deny_signal(void) -{ - return false; -} -static inline void uprobe_free_utask(struct task_struct *t) -{ -} -static inline void uprobe_copy_process(struct task_struct *t, unsigned long flags) -{ -} -static inline void uprobe_clear_state(struct mm_struct *mm) -{ -} -#endif /* !CONFIG_UPROBES */ -#endif /* _LINUX_UPROBES_H */ diff --git a/src/linux/include/linux/user-return-notifier.h b/src/linux/include/linux/user-return-notifier.h deleted file mode 100644 index 9c4a445..0000000 --- a/src/linux/include/linux/user-return-notifier.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef _LINUX_USER_RETURN_NOTIFIER_H -#define _LINUX_USER_RETURN_NOTIFIER_H - -#ifdef CONFIG_USER_RETURN_NOTIFIER - -#include -#include - -struct user_return_notifier { - void (*on_user_return)(struct user_return_notifier *urn); - struct hlist_node link; -}; - - -void user_return_notifier_register(struct user_return_notifier *urn); -void user_return_notifier_unregister(struct user_return_notifier *urn); - -static inline void propagate_user_return_notify(struct task_struct *prev, - struct task_struct *next) -{ - if (test_tsk_thread_flag(prev, TIF_USER_RETURN_NOTIFY)) { - clear_tsk_thread_flag(prev, TIF_USER_RETURN_NOTIFY); - set_tsk_thread_flag(next, TIF_USER_RETURN_NOTIFY); - } -} - -void fire_user_return_notifiers(void); - -static inline void clear_user_return_notifier(struct task_struct *p) -{ - clear_tsk_thread_flag(p, TIF_USER_RETURN_NOTIFY); -} - -#else - -struct user_return_notifier {}; - -static inline void propagate_user_return_notify(struct task_struct *prev, - struct task_struct *next) -{ -} - -static inline void fire_user_return_notifiers(void) {} - -static inline void clear_user_return_notifier(struct task_struct *p) {} - -#endif - -#endif diff --git a/src/linux/include/linux/user_namespace.h b/src/linux/include/linux/user_namespace.h deleted file mode 100644 index eb209d4..0000000 --- a/src/linux/include/linux/user_namespace.h +++ /dev/null @@ -1,151 +0,0 @@ -#ifndef _LINUX_USER_NAMESPACE_H -#define _LINUX_USER_NAMESPACE_H - -#include -#include -#include -#include -#include - -#define UID_GID_MAP_MAX_EXTENTS 5 - -struct uid_gid_map { /* 64 bytes -- 1 cache line */ - u32 nr_extents; - struct uid_gid_extent { - u32 first; - u32 lower_first; - u32 count; - } extent[UID_GID_MAP_MAX_EXTENTS]; -}; - -#define USERNS_SETGROUPS_ALLOWED 1UL - -#define USERNS_INIT_FLAGS USERNS_SETGROUPS_ALLOWED - -struct ucounts; - -enum ucount_type { - UCOUNT_USER_NAMESPACES, - UCOUNT_PID_NAMESPACES, - UCOUNT_UTS_NAMESPACES, - UCOUNT_IPC_NAMESPACES, - UCOUNT_NET_NAMESPACES, - UCOUNT_MNT_NAMESPACES, - UCOUNT_CGROUP_NAMESPACES, - UCOUNT_COUNTS, -}; - -struct user_namespace { - struct uid_gid_map uid_map; - struct uid_gid_map gid_map; - struct uid_gid_map projid_map; - atomic_t count; - struct user_namespace *parent; - int level; - kuid_t owner; - kgid_t group; - struct ns_common ns; - unsigned long flags; - - /* Register of per-UID persistent keyrings for this namespace */ -#ifdef CONFIG_PERSISTENT_KEYRINGS - struct key *persistent_keyring_register; - struct rw_semaphore persistent_keyring_register_sem; -#endif - struct work_struct work; -#ifdef CONFIG_SYSCTL - struct ctl_table_set set; - struct ctl_table_header *sysctls; -#endif - struct ucounts *ucounts; - int ucount_max[UCOUNT_COUNTS]; -}; - -struct ucounts { - struct hlist_node node; - struct user_namespace *ns; - kuid_t uid; - atomic_t count; - atomic_t ucount[UCOUNT_COUNTS]; -}; - -extern struct user_namespace init_user_ns; - -bool setup_userns_sysctls(struct user_namespace *ns); -void retire_userns_sysctls(struct user_namespace *ns); -struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid, enum ucount_type type); -void dec_ucount(struct ucounts *ucounts, enum ucount_type type); - -#ifdef CONFIG_USER_NS - -static inline struct user_namespace *get_user_ns(struct user_namespace *ns) -{ - if (ns) - atomic_inc(&ns->count); - return ns; -} - -extern int create_user_ns(struct cred *new); -extern int unshare_userns(unsigned long unshare_flags, struct cred **new_cred); -extern void __put_user_ns(struct user_namespace *ns); - -static inline void put_user_ns(struct user_namespace *ns) -{ - if (ns && atomic_dec_and_test(&ns->count)) - __put_user_ns(ns); -} - -struct seq_operations; -extern const struct seq_operations proc_uid_seq_operations; -extern const struct seq_operations proc_gid_seq_operations; -extern const struct seq_operations proc_projid_seq_operations; -extern ssize_t proc_uid_map_write(struct file *, const char __user *, size_t, loff_t *); -extern ssize_t proc_gid_map_write(struct file *, const char __user *, size_t, loff_t *); -extern ssize_t proc_projid_map_write(struct file *, const char __user *, size_t, loff_t *); -extern ssize_t proc_setgroups_write(struct file *, const char __user *, size_t, loff_t *); -extern int proc_setgroups_show(struct seq_file *m, void *v); -extern bool userns_may_setgroups(const struct user_namespace *ns); -extern bool current_in_userns(const struct user_namespace *target_ns); - -struct ns_common *ns_get_owner(struct ns_common *ns); -#else - -static inline struct user_namespace *get_user_ns(struct user_namespace *ns) -{ - return &init_user_ns; -} - -static inline int create_user_ns(struct cred *new) -{ - return -EINVAL; -} - -static inline int unshare_userns(unsigned long unshare_flags, - struct cred **new_cred) -{ - if (unshare_flags & CLONE_NEWUSER) - return -EINVAL; - return 0; -} - -static inline void put_user_ns(struct user_namespace *ns) -{ -} - -static inline bool userns_may_setgroups(const struct user_namespace *ns) -{ - return true; -} - -static inline bool current_in_userns(const struct user_namespace *target_ns) -{ - return true; -} - -static inline struct ns_common *ns_get_owner(struct ns_common *ns) -{ - return ERR_PTR(-EPERM); -} -#endif - -#endif /* _LINUX_USER_H */ diff --git a/src/linux/include/linux/uts.h b/src/linux/include/linux/uts.h deleted file mode 100644 index 6ddbd86..0000000 --- a/src/linux/include/linux/uts.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _LINUX_UTS_H -#define _LINUX_UTS_H - -/* - * Defines for what uname() should return - */ -#ifndef UTS_SYSNAME -#define UTS_SYSNAME "Linux" -#endif - -#ifndef UTS_NODENAME -#define UTS_NODENAME CONFIG_DEFAULT_HOSTNAME /* set by sethostname() */ -#endif - -#ifndef UTS_DOMAINNAME -#define UTS_DOMAINNAME "(none)" /* set by setdomainname() */ -#endif - -#endif diff --git a/src/linux/include/linux/utsname.h b/src/linux/include/linux/utsname.h deleted file mode 100644 index 60f0bb8..0000000 --- a/src/linux/include/linux/utsname.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef _LINUX_UTSNAME_H -#define _LINUX_UTSNAME_H - - -#include -#include -#include -#include -#include -#include - -enum uts_proc { - UTS_PROC_OSTYPE, - UTS_PROC_OSRELEASE, - UTS_PROC_VERSION, - UTS_PROC_HOSTNAME, - UTS_PROC_DOMAINNAME, -}; - -struct user_namespace; -extern struct user_namespace init_user_ns; - -struct uts_namespace { - struct kref kref; - struct new_utsname name; - struct user_namespace *user_ns; - struct ucounts *ucounts; - struct ns_common ns; -}; -extern struct uts_namespace init_uts_ns; - -#ifdef CONFIG_UTS_NS -static inline void get_uts_ns(struct uts_namespace *ns) -{ - kref_get(&ns->kref); -} - -extern struct uts_namespace *copy_utsname(unsigned long flags, - struct user_namespace *user_ns, struct uts_namespace *old_ns); -extern void free_uts_ns(struct kref *kref); - -static inline void put_uts_ns(struct uts_namespace *ns) -{ - kref_put(&ns->kref, free_uts_ns); -} -#else -static inline void get_uts_ns(struct uts_namespace *ns) -{ -} - -static inline void put_uts_ns(struct uts_namespace *ns) -{ -} - -static inline struct uts_namespace *copy_utsname(unsigned long flags, - struct user_namespace *user_ns, struct uts_namespace *old_ns) -{ - if (flags & CLONE_NEWUTS) - return ERR_PTR(-EINVAL); - - return old_ns; -} -#endif - -#ifdef CONFIG_PROC_SYSCTL -extern void uts_proc_notify(enum uts_proc proc); -#else -static inline void uts_proc_notify(enum uts_proc proc) -{ -} -#endif - -static inline struct new_utsname *utsname(void) -{ - return ¤t->nsproxy->uts_ns->name; -} - -static inline struct new_utsname *init_utsname(void) -{ - return &init_uts_ns.name; -} - -extern struct rw_semaphore uts_sem; - -#endif /* _LINUX_UTSNAME_H */ diff --git a/src/linux/include/linux/uuid.h b/src/linux/include/linux/uuid.h deleted file mode 100644 index 2d095fc..0000000 --- a/src/linux/include/linux/uuid.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * UUID/GUID definition - * - * Copyright (C) 2010, 2016 Intel Corp. - * Huang Ying - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ -#ifndef _LINUX_UUID_H_ -#define _LINUX_UUID_H_ - -#include - -/* - * The length of a UUID string ("aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee") - * not including trailing NUL. - */ -#define UUID_STRING_LEN 36 - -static inline int uuid_le_cmp(const uuid_le u1, const uuid_le u2) -{ - return memcmp(&u1, &u2, sizeof(uuid_le)); -} - -static inline int uuid_be_cmp(const uuid_be u1, const uuid_be u2) -{ - return memcmp(&u1, &u2, sizeof(uuid_be)); -} - -void generate_random_uuid(unsigned char uuid[16]); - -extern void uuid_le_gen(uuid_le *u); -extern void uuid_be_gen(uuid_be *u); - -bool __must_check uuid_is_valid(const char *uuid); - -extern const u8 uuid_le_index[16]; -extern const u8 uuid_be_index[16]; - -int uuid_le_to_bin(const char *uuid, uuid_le *u); -int uuid_be_to_bin(const char *uuid, uuid_be *u); - -#endif diff --git a/src/linux/include/linux/vfs.h b/src/linux/include/linux/vfs.h deleted file mode 100644 index e701d05..0000000 --- a/src/linux/include/linux/vfs.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _LINUX_VFS_H -#define _LINUX_VFS_H - -#include - -#endif diff --git a/src/linux/include/linux/virtio.h b/src/linux/include/linux/virtio.h deleted file mode 100644 index d5eb547..0000000 --- a/src/linux/include/linux/virtio.h +++ /dev/null @@ -1,192 +0,0 @@ -#ifndef _LINUX_VIRTIO_H -#define _LINUX_VIRTIO_H -/* Everything a virtio driver needs to work with any particular virtio - * implementation. */ -#include -#include -#include -#include -#include -#include -#include - -/** - * virtqueue - a queue to register buffers for sending or receiving. - * @list: the chain of virtqueues for this device - * @callback: the function to call when buffers are consumed (can be NULL). - * @name: the name of this virtqueue (mainly for debugging) - * @vdev: the virtio device this queue was created for. - * @priv: a pointer for the virtqueue implementation to use. - * @index: the zero-based ordinal number for this queue. - * @num_free: number of elements we expect to be able to fit. - * - * A note on @num_free: with indirect buffers, each buffer needs one - * element in the queue, otherwise a buffer will need one element per - * sg element. - */ -struct virtqueue { - struct list_head list; - void (*callback)(struct virtqueue *vq); - const char *name; - struct virtio_device *vdev; - unsigned int index; - unsigned int num_free; - void *priv; -}; - -int virtqueue_add_outbuf(struct virtqueue *vq, - struct scatterlist sg[], unsigned int num, - void *data, - gfp_t gfp); - -int virtqueue_add_inbuf(struct virtqueue *vq, - struct scatterlist sg[], unsigned int num, - void *data, - gfp_t gfp); - -int virtqueue_add_sgs(struct virtqueue *vq, - struct scatterlist *sgs[], - unsigned int out_sgs, - unsigned int in_sgs, - void *data, - gfp_t gfp); - -bool virtqueue_kick(struct virtqueue *vq); - -bool virtqueue_kick_prepare(struct virtqueue *vq); - -bool virtqueue_notify(struct virtqueue *vq); - -void *virtqueue_get_buf(struct virtqueue *vq, unsigned int *len); - -void virtqueue_disable_cb(struct virtqueue *vq); - -bool virtqueue_enable_cb(struct virtqueue *vq); - -unsigned virtqueue_enable_cb_prepare(struct virtqueue *vq); - -bool virtqueue_poll(struct virtqueue *vq, unsigned); - -bool virtqueue_enable_cb_delayed(struct virtqueue *vq); - -void *virtqueue_detach_unused_buf(struct virtqueue *vq); - -unsigned int virtqueue_get_vring_size(struct virtqueue *vq); - -bool virtqueue_is_broken(struct virtqueue *vq); - -const struct vring *virtqueue_get_vring(struct virtqueue *vq); -dma_addr_t virtqueue_get_desc_addr(struct virtqueue *vq); -dma_addr_t virtqueue_get_avail_addr(struct virtqueue *vq); -dma_addr_t virtqueue_get_used_addr(struct virtqueue *vq); - -/* - * Legacy accessors -- in almost all cases, these are the wrong functions - * to use. - */ -static inline void *virtqueue_get_desc(struct virtqueue *vq) -{ - return virtqueue_get_vring(vq)->desc; -} -static inline void *virtqueue_get_avail(struct virtqueue *vq) -{ - return virtqueue_get_vring(vq)->avail; -} -static inline void *virtqueue_get_used(struct virtqueue *vq) -{ - return virtqueue_get_vring(vq)->used; -} - -/** - * virtio_device - representation of a device using virtio - * @index: unique position on the virtio bus - * @failed: saved value for VIRTIO_CONFIG_S_FAILED bit (for restore) - * @config_enabled: configuration change reporting enabled - * @config_change_pending: configuration change reported while disabled - * @config_lock: protects configuration change reporting - * @dev: underlying device. - * @id: the device type identification (used to match it with a driver). - * @config: the configuration ops for this device. - * @vringh_config: configuration ops for host vrings. - * @vqs: the list of virtqueues for this device. - * @features: the features supported by both driver and device. - * @priv: private pointer for the driver's use. - */ -struct virtio_device { - int index; - bool failed; - bool config_enabled; - bool config_change_pending; - spinlock_t config_lock; - struct device dev; - struct virtio_device_id id; - const struct virtio_config_ops *config; - const struct vringh_config_ops *vringh_config; - struct list_head vqs; - u64 features; - void *priv; -}; - -static inline struct virtio_device *dev_to_virtio(struct device *_dev) -{ - return container_of(_dev, struct virtio_device, dev); -} - -int register_virtio_device(struct virtio_device *dev); -void unregister_virtio_device(struct virtio_device *dev); - -void virtio_break_device(struct virtio_device *dev); - -void virtio_config_changed(struct virtio_device *dev); -#ifdef CONFIG_PM_SLEEP -int virtio_device_freeze(struct virtio_device *dev); -int virtio_device_restore(struct virtio_device *dev); -#endif - -/** - * virtio_driver - operations for a virtio I/O driver - * @driver: underlying device driver (populate name and owner). - * @id_table: the ids serviced by this driver. - * @feature_table: an array of feature numbers supported by this driver. - * @feature_table_size: number of entries in the feature table array. - * @feature_table_legacy: same as feature_table but when working in legacy mode. - * @feature_table_size_legacy: number of entries in feature table legacy array. - * @probe: the function to call when a device is found. Returns 0 or -errno. - * @remove: the function to call when a device is removed. - * @config_changed: optional function to call when the device configuration - * changes; may be called in interrupt context. - */ -struct virtio_driver { - struct device_driver driver; - const struct virtio_device_id *id_table; - const unsigned int *feature_table; - unsigned int feature_table_size; - const unsigned int *feature_table_legacy; - unsigned int feature_table_size_legacy; - int (*probe)(struct virtio_device *dev); - void (*scan)(struct virtio_device *dev); - void (*remove)(struct virtio_device *dev); - void (*config_changed)(struct virtio_device *dev); -#ifdef CONFIG_PM - int (*freeze)(struct virtio_device *dev); - int (*restore)(struct virtio_device *dev); -#endif -}; - -static inline struct virtio_driver *drv_to_virtio(struct device_driver *drv) -{ - return container_of(drv, struct virtio_driver, driver); -} - -int register_virtio_driver(struct virtio_driver *drv); -void unregister_virtio_driver(struct virtio_driver *drv); - -/* module_virtio_driver() - Helper macro for drivers that don't do - * anything special in module init/exit. This eliminates a lot of - * boilerplate. Each module may only use this macro once, and - * calling it replaces module_init() and module_exit() - */ -#define module_virtio_driver(__virtio_driver) \ - module_driver(__virtio_driver, register_virtio_driver, \ - unregister_virtio_driver) -#endif /* _LINUX_VIRTIO_H */ diff --git a/src/linux/include/linux/virtio_byteorder.h b/src/linux/include/linux/virtio_byteorder.h deleted file mode 100644 index ce63a2c..0000000 --- a/src/linux/include/linux/virtio_byteorder.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef _LINUX_VIRTIO_BYTEORDER_H -#define _LINUX_VIRTIO_BYTEORDER_H -#include -#include - -static inline bool virtio_legacy_is_little_endian(void) -{ -#ifdef __LITTLE_ENDIAN - return true; -#else - return false; -#endif -} - -static inline u16 __virtio16_to_cpu(bool little_endian, __virtio16 val) -{ - if (little_endian) - return le16_to_cpu((__force __le16)val); - else - return be16_to_cpu((__force __be16)val); -} - -static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val) -{ - if (little_endian) - return (__force __virtio16)cpu_to_le16(val); - else - return (__force __virtio16)cpu_to_be16(val); -} - -static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val) -{ - if (little_endian) - return le32_to_cpu((__force __le32)val); - else - return be32_to_cpu((__force __be32)val); -} - -static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val) -{ - if (little_endian) - return (__force __virtio32)cpu_to_le32(val); - else - return (__force __virtio32)cpu_to_be32(val); -} - -static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val) -{ - if (little_endian) - return le64_to_cpu((__force __le64)val); - else - return be64_to_cpu((__force __be64)val); -} - -static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val) -{ - if (little_endian) - return (__force __virtio64)cpu_to_le64(val); - else - return (__force __virtio64)cpu_to_be64(val); -} - -#endif /* _LINUX_VIRTIO_BYTEORDER */ diff --git a/src/linux/include/linux/virtio_config.h b/src/linux/include/linux/virtio_config.h deleted file mode 100644 index 26c155b..0000000 --- a/src/linux/include/linux/virtio_config.h +++ /dev/null @@ -1,417 +0,0 @@ -#ifndef _LINUX_VIRTIO_CONFIG_H -#define _LINUX_VIRTIO_CONFIG_H - -#include -#include -#include -#include -#include - -/** - * virtio_config_ops - operations for configuring a virtio device - * @get: read the value of a configuration field - * vdev: the virtio_device - * offset: the offset of the configuration field - * buf: the buffer to write the field value into. - * len: the length of the buffer - * @set: write the value of a configuration field - * vdev: the virtio_device - * offset: the offset of the configuration field - * buf: the buffer to read the field value from. - * len: the length of the buffer - * @generation: config generation counter - * vdev: the virtio_device - * Returns the config generation counter - * @get_status: read the status byte - * vdev: the virtio_device - * Returns the status byte - * @set_status: write the status byte - * vdev: the virtio_device - * status: the new status byte - * @reset: reset the device - * vdev: the virtio device - * After this, status and feature negotiation must be done again - * Device must not be reset from its vq/config callbacks, or in - * parallel with being added/removed. - * @find_vqs: find virtqueues and instantiate them. - * vdev: the virtio_device - * nvqs: the number of virtqueues to find - * vqs: on success, includes new virtqueues - * callbacks: array of callbacks, for each virtqueue - * include a NULL entry for vqs that do not need a callback - * names: array of virtqueue names (mainly for debugging) - * include a NULL entry for vqs unused by driver - * Returns 0 on success or error status - * @del_vqs: free virtqueues found by find_vqs(). - * @get_features: get the array of feature bits for this device. - * vdev: the virtio_device - * Returns the first 32 feature bits (all we currently need). - * @finalize_features: confirm what device features we'll be using. - * vdev: the virtio_device - * This gives the final feature bits for the device: it can change - * the dev->feature bits if it wants. - * Returns 0 on success or error status - * @bus_name: return the bus name associated with the device - * vdev: the virtio_device - * This returns a pointer to the bus name a la pci_name from which - * the caller can then copy. - * @set_vq_affinity: set the affinity for a virtqueue. - */ -typedef void vq_callback_t(struct virtqueue *); -struct virtio_config_ops { - void (*get)(struct virtio_device *vdev, unsigned offset, - void *buf, unsigned len); - void (*set)(struct virtio_device *vdev, unsigned offset, - const void *buf, unsigned len); - u32 (*generation)(struct virtio_device *vdev); - u8 (*get_status)(struct virtio_device *vdev); - void (*set_status)(struct virtio_device *vdev, u8 status); - void (*reset)(struct virtio_device *vdev); - int (*find_vqs)(struct virtio_device *, unsigned nvqs, - struct virtqueue *vqs[], - vq_callback_t *callbacks[], - const char * const names[]); - void (*del_vqs)(struct virtio_device *); - u64 (*get_features)(struct virtio_device *vdev); - int (*finalize_features)(struct virtio_device *vdev); - const char *(*bus_name)(struct virtio_device *vdev); - int (*set_vq_affinity)(struct virtqueue *vq, int cpu); -}; - -/* If driver didn't advertise the feature, it will never appear. */ -void virtio_check_driver_offered_feature(const struct virtio_device *vdev, - unsigned int fbit); - -/** - * __virtio_test_bit - helper to test feature bits. For use by transports. - * Devices should normally use virtio_has_feature, - * which includes more checks. - * @vdev: the device - * @fbit: the feature bit - */ -static inline bool __virtio_test_bit(const struct virtio_device *vdev, - unsigned int fbit) -{ - /* Did you forget to fix assumptions on max features? */ - if (__builtin_constant_p(fbit)) - BUILD_BUG_ON(fbit >= 64); - else - BUG_ON(fbit >= 64); - - return vdev->features & BIT_ULL(fbit); -} - -/** - * __virtio_set_bit - helper to set feature bits. For use by transports. - * @vdev: the device - * @fbit: the feature bit - */ -static inline void __virtio_set_bit(struct virtio_device *vdev, - unsigned int fbit) -{ - /* Did you forget to fix assumptions on max features? */ - if (__builtin_constant_p(fbit)) - BUILD_BUG_ON(fbit >= 64); - else - BUG_ON(fbit >= 64); - - vdev->features |= BIT_ULL(fbit); -} - -/** - * __virtio_clear_bit - helper to clear feature bits. For use by transports. - * @vdev: the device - * @fbit: the feature bit - */ -static inline void __virtio_clear_bit(struct virtio_device *vdev, - unsigned int fbit) -{ - /* Did you forget to fix assumptions on max features? */ - if (__builtin_constant_p(fbit)) - BUILD_BUG_ON(fbit >= 64); - else - BUG_ON(fbit >= 64); - - vdev->features &= ~BIT_ULL(fbit); -} - -/** - * virtio_has_feature - helper to determine if this device has this feature. - * @vdev: the device - * @fbit: the feature bit - */ -static inline bool virtio_has_feature(const struct virtio_device *vdev, - unsigned int fbit) -{ - if (fbit < VIRTIO_TRANSPORT_F_START) - virtio_check_driver_offered_feature(vdev, fbit); - - return __virtio_test_bit(vdev, fbit); -} - -/** - * virtio_has_iommu_quirk - determine whether this device has the iommu quirk - * @vdev: the device - */ -static inline bool virtio_has_iommu_quirk(const struct virtio_device *vdev) -{ - /* - * Note the reverse polarity of the quirk feature (compared to most - * other features), this is for compatibility with legacy systems. - */ - return !virtio_has_feature(vdev, VIRTIO_F_IOMMU_PLATFORM); -} - -static inline -struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev, - vq_callback_t *c, const char *n) -{ - vq_callback_t *callbacks[] = { c }; - const char *names[] = { n }; - struct virtqueue *vq; - int err = vdev->config->find_vqs(vdev, 1, &vq, callbacks, names); - if (err < 0) - return ERR_PTR(err); - return vq; -} - -/** - * virtio_device_ready - enable vq use in probe function - * @vdev: the device - * - * Driver must call this to use vqs in the probe function. - * - * Note: vqs are enabled automatically after probe returns. - */ -static inline -void virtio_device_ready(struct virtio_device *dev) -{ - unsigned status = dev->config->get_status(dev); - - BUG_ON(status & VIRTIO_CONFIG_S_DRIVER_OK); - dev->config->set_status(dev, status | VIRTIO_CONFIG_S_DRIVER_OK); -} - -static inline -const char *virtio_bus_name(struct virtio_device *vdev) -{ - if (!vdev->config->bus_name) - return "virtio"; - return vdev->config->bus_name(vdev); -} - -/** - * virtqueue_set_affinity - setting affinity for a virtqueue - * @vq: the virtqueue - * @cpu: the cpu no. - * - * Pay attention the function are best-effort: the affinity hint may not be set - * due to config support, irq type and sharing. - * - */ -static inline -int virtqueue_set_affinity(struct virtqueue *vq, int cpu) -{ - struct virtio_device *vdev = vq->vdev; - if (vdev->config->set_vq_affinity) - return vdev->config->set_vq_affinity(vq, cpu); - return 0; -} - -static inline bool virtio_is_little_endian(struct virtio_device *vdev) -{ - return virtio_has_feature(vdev, VIRTIO_F_VERSION_1) || - virtio_legacy_is_little_endian(); -} - -/* Memory accessors */ -static inline u16 virtio16_to_cpu(struct virtio_device *vdev, __virtio16 val) -{ - return __virtio16_to_cpu(virtio_is_little_endian(vdev), val); -} - -static inline __virtio16 cpu_to_virtio16(struct virtio_device *vdev, u16 val) -{ - return __cpu_to_virtio16(virtio_is_little_endian(vdev), val); -} - -static inline u32 virtio32_to_cpu(struct virtio_device *vdev, __virtio32 val) -{ - return __virtio32_to_cpu(virtio_is_little_endian(vdev), val); -} - -static inline __virtio32 cpu_to_virtio32(struct virtio_device *vdev, u32 val) -{ - return __cpu_to_virtio32(virtio_is_little_endian(vdev), val); -} - -static inline u64 virtio64_to_cpu(struct virtio_device *vdev, __virtio64 val) -{ - return __virtio64_to_cpu(virtio_is_little_endian(vdev), val); -} - -static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val) -{ - return __cpu_to_virtio64(virtio_is_little_endian(vdev), val); -} - -/* Config space accessors. */ -#define virtio_cread(vdev, structname, member, ptr) \ - do { \ - /* Must match the member's type, and be integer */ \ - if (!typecheck(typeof((((structname*)0)->member)), *(ptr))) \ - (*ptr) = 1; \ - \ - switch (sizeof(*ptr)) { \ - case 1: \ - *(ptr) = virtio_cread8(vdev, \ - offsetof(structname, member)); \ - break; \ - case 2: \ - *(ptr) = virtio_cread16(vdev, \ - offsetof(structname, member)); \ - break; \ - case 4: \ - *(ptr) = virtio_cread32(vdev, \ - offsetof(structname, member)); \ - break; \ - case 8: \ - *(ptr) = virtio_cread64(vdev, \ - offsetof(structname, member)); \ - break; \ - default: \ - BUG(); \ - } \ - } while(0) - -/* Config space accessors. */ -#define virtio_cwrite(vdev, structname, member, ptr) \ - do { \ - /* Must match the member's type, and be integer */ \ - if (!typecheck(typeof((((structname*)0)->member)), *(ptr))) \ - BUG_ON((*ptr) == 1); \ - \ - switch (sizeof(*ptr)) { \ - case 1: \ - virtio_cwrite8(vdev, \ - offsetof(structname, member), \ - *(ptr)); \ - break; \ - case 2: \ - virtio_cwrite16(vdev, \ - offsetof(structname, member), \ - *(ptr)); \ - break; \ - case 4: \ - virtio_cwrite32(vdev, \ - offsetof(structname, member), \ - *(ptr)); \ - break; \ - case 8: \ - virtio_cwrite64(vdev, \ - offsetof(structname, member), \ - *(ptr)); \ - break; \ - default: \ - BUG(); \ - } \ - } while(0) - -/* Read @count fields, @bytes each. */ -static inline void __virtio_cread_many(struct virtio_device *vdev, - unsigned int offset, - void *buf, size_t count, size_t bytes) -{ - u32 old, gen = vdev->config->generation ? - vdev->config->generation(vdev) : 0; - int i; - - do { - old = gen; - - for (i = 0; i < count; i++) - vdev->config->get(vdev, offset + bytes * i, - buf + i * bytes, bytes); - - gen = vdev->config->generation ? - vdev->config->generation(vdev) : 0; - } while (gen != old); -} - -static inline void virtio_cread_bytes(struct virtio_device *vdev, - unsigned int offset, - void *buf, size_t len) -{ - __virtio_cread_many(vdev, offset, buf, len, 1); -} - -static inline u8 virtio_cread8(struct virtio_device *vdev, unsigned int offset) -{ - u8 ret; - vdev->config->get(vdev, offset, &ret, sizeof(ret)); - return ret; -} - -static inline void virtio_cwrite8(struct virtio_device *vdev, - unsigned int offset, u8 val) -{ - vdev->config->set(vdev, offset, &val, sizeof(val)); -} - -static inline u16 virtio_cread16(struct virtio_device *vdev, - unsigned int offset) -{ - u16 ret; - vdev->config->get(vdev, offset, &ret, sizeof(ret)); - return virtio16_to_cpu(vdev, (__force __virtio16)ret); -} - -static inline void virtio_cwrite16(struct virtio_device *vdev, - unsigned int offset, u16 val) -{ - val = (__force u16)cpu_to_virtio16(vdev, val); - vdev->config->set(vdev, offset, &val, sizeof(val)); -} - -static inline u32 virtio_cread32(struct virtio_device *vdev, - unsigned int offset) -{ - u32 ret; - vdev->config->get(vdev, offset, &ret, sizeof(ret)); - return virtio32_to_cpu(vdev, (__force __virtio32)ret); -} - -static inline void virtio_cwrite32(struct virtio_device *vdev, - unsigned int offset, u32 val) -{ - val = (__force u32)cpu_to_virtio32(vdev, val); - vdev->config->set(vdev, offset, &val, sizeof(val)); -} - -static inline u64 virtio_cread64(struct virtio_device *vdev, - unsigned int offset) -{ - u64 ret; - __virtio_cread_many(vdev, offset, &ret, 1, sizeof(ret)); - return virtio64_to_cpu(vdev, (__force __virtio64)ret); -} - -static inline void virtio_cwrite64(struct virtio_device *vdev, - unsigned int offset, u64 val) -{ - val = (__force u64)cpu_to_virtio64(vdev, val); - vdev->config->set(vdev, offset, &val, sizeof(val)); -} - -/* Conditional config space accessors. */ -#define virtio_cread_feature(vdev, fbit, structname, member, ptr) \ - ({ \ - int _r = 0; \ - if (!virtio_has_feature(vdev, fbit)) \ - _r = -ENOENT; \ - else \ - virtio_cread((vdev), structname, member, ptr); \ - _r; \ - }) - -#endif /* _LINUX_VIRTIO_CONFIG_H */ diff --git a/src/linux/include/linux/virtio_mmio.h b/src/linux/include/linux/virtio_mmio.h deleted file mode 100644 index c4b0968..0000000 --- a/src/linux/include/linux/virtio_mmio.h +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Virtio platform device driver - * - * Copyright 2011, ARM Ltd. - * - * Based on Virtio PCI driver by Anthony Liguori, copyright IBM Corp. 2007 - * - * This header is BSD licensed so anyone can use the definitions to implement - * compatible drivers/servers. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of IBM nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _LINUX_VIRTIO_MMIO_H -#define _LINUX_VIRTIO_MMIO_H - -/* - * Control registers - */ - -/* Magic value ("virt" string) - Read Only */ -#define VIRTIO_MMIO_MAGIC_VALUE 0x000 - -/* Virtio device version - Read Only */ -#define VIRTIO_MMIO_VERSION 0x004 - -/* Virtio device ID - Read Only */ -#define VIRTIO_MMIO_DEVICE_ID 0x008 - -/* Virtio vendor ID - Read Only */ -#define VIRTIO_MMIO_VENDOR_ID 0x00c - -/* Bitmask of the features supported by the device (host) - * (32 bits per set) - Read Only */ -#define VIRTIO_MMIO_DEVICE_FEATURES 0x010 - -/* Device (host) features set selector - Write Only */ -#define VIRTIO_MMIO_DEVICE_FEATURES_SEL 0x014 - -/* Bitmask of features activated by the driver (guest) - * (32 bits per set) - Write Only */ -#define VIRTIO_MMIO_DRIVER_FEATURES 0x020 - -/* Activated features set selector - Write Only */ -#define VIRTIO_MMIO_DRIVER_FEATURES_SEL 0x024 - - -#ifndef VIRTIO_MMIO_NO_LEGACY /* LEGACY DEVICES ONLY! */ - -/* Guest's memory page size in bytes - Write Only */ -#define VIRTIO_MMIO_GUEST_PAGE_SIZE 0x028 - -#endif - - -/* Queue selector - Write Only */ -#define VIRTIO_MMIO_QUEUE_SEL 0x030 - -/* Maximum size of the currently selected queue - Read Only */ -#define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034 - -/* Queue size for the currently selected queue - Write Only */ -#define VIRTIO_MMIO_QUEUE_NUM 0x038 - - -#ifndef VIRTIO_MMIO_NO_LEGACY /* LEGACY DEVICES ONLY! */ - -/* Used Ring alignment for the currently selected queue - Write Only */ -#define VIRTIO_MMIO_QUEUE_ALIGN 0x03c - -/* Guest's PFN for the currently selected queue - Read Write */ -#define VIRTIO_MMIO_QUEUE_PFN 0x040 - -#endif - - -/* Ready bit for the currently selected queue - Read Write */ -#define VIRTIO_MMIO_QUEUE_READY 0x044 - -/* Queue notifier - Write Only */ -#define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 - -/* Interrupt status - Read Only */ -#define VIRTIO_MMIO_INTERRUPT_STATUS 0x060 - -/* Interrupt acknowledge - Write Only */ -#define VIRTIO_MMIO_INTERRUPT_ACK 0x064 - -/* Device status register - Read Write */ -#define VIRTIO_MMIO_STATUS 0x070 - -/* Selected queue's Descriptor Table address, 64 bits in two halves */ -#define VIRTIO_MMIO_QUEUE_DESC_LOW 0x080 -#define VIRTIO_MMIO_QUEUE_DESC_HIGH 0x084 - -/* Selected queue's Available Ring address, 64 bits in two halves */ -#define VIRTIO_MMIO_QUEUE_AVAIL_LOW 0x090 -#define VIRTIO_MMIO_QUEUE_AVAIL_HIGH 0x094 - -/* Selected queue's Used Ring address, 64 bits in two halves */ -#define VIRTIO_MMIO_QUEUE_USED_LOW 0x0a0 -#define VIRTIO_MMIO_QUEUE_USED_HIGH 0x0a4 - -/* Configuration atomicity value */ -#define VIRTIO_MMIO_CONFIG_GENERATION 0x0fc - -/* The config space is defined by each driver as - * the per-driver configuration space - Read Write */ -#define VIRTIO_MMIO_CONFIG 0x100 - - - -/* - * Interrupt flags (re: interrupt status & acknowledge registers) - */ - -#define VIRTIO_MMIO_INT_VRING (1 << 0) -#define VIRTIO_MMIO_INT_CONFIG (1 << 1) - -#endif diff --git a/src/linux/include/linux/virtio_net.h b/src/linux/include/linux/virtio_net.h deleted file mode 100644 index 1c912f8..0000000 --- a/src/linux/include/linux/virtio_net.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef _LINUX_VIRTIO_NET_H -#define _LINUX_VIRTIO_NET_H - -#include -#include - -static inline int virtio_net_hdr_to_skb(struct sk_buff *skb, - const struct virtio_net_hdr *hdr, - bool little_endian) -{ - unsigned short gso_type = 0; - - if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) { - switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) { - case VIRTIO_NET_HDR_GSO_TCPV4: - gso_type = SKB_GSO_TCPV4; - break; - case VIRTIO_NET_HDR_GSO_TCPV6: - gso_type = SKB_GSO_TCPV6; - break; - case VIRTIO_NET_HDR_GSO_UDP: - gso_type = SKB_GSO_UDP; - break; - default: - return -EINVAL; - } - - if (hdr->gso_type & VIRTIO_NET_HDR_GSO_ECN) - gso_type |= SKB_GSO_TCP_ECN; - - if (hdr->gso_size == 0) - return -EINVAL; - } - - if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) { - u16 start = __virtio16_to_cpu(little_endian, hdr->csum_start); - u16 off = __virtio16_to_cpu(little_endian, hdr->csum_offset); - - if (!skb_partial_csum_set(skb, start, off)) - return -EINVAL; - } - - if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) { - u16 gso_size = __virtio16_to_cpu(little_endian, hdr->gso_size); - - skb_shinfo(skb)->gso_size = gso_size; - skb_shinfo(skb)->gso_type = gso_type; - - /* Header must be checked, and gso_segs computed. */ - skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; - skb_shinfo(skb)->gso_segs = 0; - } - - return 0; -} - -static inline int virtio_net_hdr_from_skb(const struct sk_buff *skb, - struct virtio_net_hdr *hdr, - bool little_endian) -{ - memset(hdr, 0, sizeof(*hdr)); - - if (skb_is_gso(skb)) { - struct skb_shared_info *sinfo = skb_shinfo(skb); - - /* This is a hint as to how much should be linear. */ - hdr->hdr_len = __cpu_to_virtio16(little_endian, - skb_headlen(skb)); - hdr->gso_size = __cpu_to_virtio16(little_endian, - sinfo->gso_size); - if (sinfo->gso_type & SKB_GSO_TCPV4) - hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4; - else if (sinfo->gso_type & SKB_GSO_TCPV6) - hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6; - else if (sinfo->gso_type & SKB_GSO_UDP) - hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP; - else - return -EINVAL; - if (sinfo->gso_type & SKB_GSO_TCP_ECN) - hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN; - } else - hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE; - - if (skb->ip_summed == CHECKSUM_PARTIAL) { - hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; - if (skb_vlan_tag_present(skb)) - hdr->csum_start = __cpu_to_virtio16(little_endian, - skb_checksum_start_offset(skb) + VLAN_HLEN); - else - hdr->csum_start = __cpu_to_virtio16(little_endian, - skb_checksum_start_offset(skb)); - hdr->csum_offset = __cpu_to_virtio16(little_endian, - skb->csum_offset); - } else if (skb->ip_summed == CHECKSUM_UNNECESSARY) { - hdr->flags = VIRTIO_NET_HDR_F_DATA_VALID; - } /* else everything is zero */ - - return 0; -} - -#endif /* _LINUX_VIRTIO_BYTEORDER */ diff --git a/src/linux/include/linux/virtio_ring.h b/src/linux/include/linux/virtio_ring.h deleted file mode 100644 index e8d3693..0000000 --- a/src/linux/include/linux/virtio_ring.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef _LINUX_VIRTIO_RING_H -#define _LINUX_VIRTIO_RING_H - -#include -#include -#include - -/* - * Barriers in virtio are tricky. Non-SMP virtio guests can't assume - * they're not on an SMP host system, so they need to assume real - * barriers. Non-SMP virtio hosts could skip the barriers, but does - * anyone care? - * - * For virtio_pci on SMP, we don't need to order with respect to MMIO - * accesses through relaxed memory I/O windows, so virt_mb() et al are - * sufficient. - * - * For using virtio to talk to real devices (eg. other heterogeneous - * CPUs) we do need real barriers. In theory, we could be using both - * kinds of virtio, so it's a runtime decision, and the branch is - * actually quite cheap. - */ - -static inline void virtio_mb(bool weak_barriers) -{ - if (weak_barriers) - virt_mb(); - else - mb(); -} - -static inline void virtio_rmb(bool weak_barriers) -{ - if (weak_barriers) - virt_rmb(); - else - rmb(); -} - -static inline void virtio_wmb(bool weak_barriers) -{ - if (weak_barriers) - virt_wmb(); - else - wmb(); -} - -static inline void virtio_store_mb(bool weak_barriers, - __virtio16 *p, __virtio16 v) -{ - if (weak_barriers) { - virt_store_mb(*p, v); - } else { - WRITE_ONCE(*p, v); - mb(); - } -} - -struct virtio_device; -struct virtqueue; - -/* - * Creates a virtqueue and allocates the descriptor ring. If - * may_reduce_num is set, then this may allocate a smaller ring than - * expected. The caller should query virtqueue_get_ring_size to learn - * the actual size of the ring. - */ -struct virtqueue *vring_create_virtqueue(unsigned int index, - unsigned int num, - unsigned int vring_align, - struct virtio_device *vdev, - bool weak_barriers, - bool may_reduce_num, - bool (*notify)(struct virtqueue *vq), - void (*callback)(struct virtqueue *vq), - const char *name); - -/* Creates a virtqueue with a custom layout. */ -struct virtqueue *__vring_new_virtqueue(unsigned int index, - struct vring vring, - struct virtio_device *vdev, - bool weak_barriers, - bool (*notify)(struct virtqueue *), - void (*callback)(struct virtqueue *), - const char *name); - -/* - * Creates a virtqueue with a standard layout but a caller-allocated - * ring. - */ -struct virtqueue *vring_new_virtqueue(unsigned int index, - unsigned int num, - unsigned int vring_align, - struct virtio_device *vdev, - bool weak_barriers, - void *pages, - bool (*notify)(struct virtqueue *vq), - void (*callback)(struct virtqueue *vq), - const char *name); - -/* - * Destroys a virtqueue. If created with vring_create_virtqueue, this - * also frees the ring. - */ -void vring_del_virtqueue(struct virtqueue *vq); - -/* Filter out transport-specific feature bits. */ -void vring_transport_features(struct virtio_device *vdev); - -irqreturn_t vring_interrupt(int irq, void *_vq); -#endif /* _LINUX_VIRTIO_RING_H */ diff --git a/src/linux/include/linux/vm_event_item.h b/src/linux/include/linux/vm_event_item.h deleted file mode 100644 index 4d6ec58..0000000 --- a/src/linux/include/linux/vm_event_item.h +++ /dev/null @@ -1,112 +0,0 @@ -#ifndef VM_EVENT_ITEM_H_INCLUDED -#define VM_EVENT_ITEM_H_INCLUDED - -#ifdef CONFIG_ZONE_DMA -#define DMA_ZONE(xx) xx##_DMA, -#else -#define DMA_ZONE(xx) -#endif - -#ifdef CONFIG_ZONE_DMA32 -#define DMA32_ZONE(xx) xx##_DMA32, -#else -#define DMA32_ZONE(xx) -#endif - -#ifdef CONFIG_HIGHMEM -#define HIGHMEM_ZONE(xx) xx##_HIGH, -#else -#define HIGHMEM_ZONE(xx) -#endif - -#define FOR_ALL_ZONES(xx) DMA_ZONE(xx) DMA32_ZONE(xx) xx##_NORMAL, HIGHMEM_ZONE(xx) xx##_MOVABLE - -enum vm_event_item { PGPGIN, PGPGOUT, PSWPIN, PSWPOUT, - FOR_ALL_ZONES(PGALLOC), - FOR_ALL_ZONES(ALLOCSTALL), - FOR_ALL_ZONES(PGSCAN_SKIP), - PGFREE, PGACTIVATE, PGDEACTIVATE, - PGFAULT, PGMAJFAULT, - PGLAZYFREED, - PGREFILL, - PGSTEAL_KSWAPD, - PGSTEAL_DIRECT, - PGSCAN_KSWAPD, - PGSCAN_DIRECT, - PGSCAN_DIRECT_THROTTLE, -#ifdef CONFIG_NUMA - PGSCAN_ZONE_RECLAIM_FAILED, -#endif - PGINODESTEAL, SLABS_SCANNED, KSWAPD_INODESTEAL, - KSWAPD_LOW_WMARK_HIT_QUICKLY, KSWAPD_HIGH_WMARK_HIT_QUICKLY, - PAGEOUTRUN, PGROTATED, - DROP_PAGECACHE, DROP_SLAB, -#ifdef CONFIG_NUMA_BALANCING - NUMA_PTE_UPDATES, - NUMA_HUGE_PTE_UPDATES, - NUMA_HINT_FAULTS, - NUMA_HINT_FAULTS_LOCAL, - NUMA_PAGE_MIGRATE, -#endif -#ifdef CONFIG_MIGRATION - PGMIGRATE_SUCCESS, PGMIGRATE_FAIL, -#endif -#ifdef CONFIG_COMPACTION - COMPACTMIGRATE_SCANNED, COMPACTFREE_SCANNED, - COMPACTISOLATED, - COMPACTSTALL, COMPACTFAIL, COMPACTSUCCESS, - KCOMPACTD_WAKE, -#endif -#ifdef CONFIG_HUGETLB_PAGE - HTLB_BUDDY_PGALLOC, HTLB_BUDDY_PGALLOC_FAIL, -#endif - UNEVICTABLE_PGCULLED, /* culled to noreclaim list */ - UNEVICTABLE_PGSCANNED, /* scanned for reclaimability */ - UNEVICTABLE_PGRESCUED, /* rescued from noreclaim list */ - UNEVICTABLE_PGMLOCKED, - UNEVICTABLE_PGMUNLOCKED, - UNEVICTABLE_PGCLEARED, /* on COW, page truncate */ - UNEVICTABLE_PGSTRANDED, /* unable to isolate on unlock */ -#ifdef CONFIG_TRANSPARENT_HUGEPAGE - THP_FAULT_ALLOC, - THP_FAULT_FALLBACK, - THP_COLLAPSE_ALLOC, - THP_COLLAPSE_ALLOC_FAILED, - THP_FILE_ALLOC, - THP_FILE_MAPPED, - THP_SPLIT_PAGE, - THP_SPLIT_PAGE_FAILED, - THP_DEFERRED_SPLIT_PAGE, - THP_SPLIT_PMD, - THP_ZERO_PAGE_ALLOC, - THP_ZERO_PAGE_ALLOC_FAILED, -#endif -#ifdef CONFIG_MEMORY_BALLOON - BALLOON_INFLATE, - BALLOON_DEFLATE, -#ifdef CONFIG_BALLOON_COMPACTION - BALLOON_MIGRATE, -#endif -#endif -#ifdef CONFIG_DEBUG_TLBFLUSH -#ifdef CONFIG_SMP - NR_TLB_REMOTE_FLUSH, /* cpu tried to flush others' tlbs */ - NR_TLB_REMOTE_FLUSH_RECEIVED,/* cpu received ipi for flush */ -#endif /* CONFIG_SMP */ - NR_TLB_LOCAL_FLUSH_ALL, - NR_TLB_LOCAL_FLUSH_ONE, -#endif /* CONFIG_DEBUG_TLBFLUSH */ -#ifdef CONFIG_DEBUG_VM_VMACACHE - VMACACHE_FIND_CALLS, - VMACACHE_FIND_HITS, - VMACACHE_FULL_FLUSHES, -#endif - NR_VM_EVENT_ITEMS -}; - -#ifndef CONFIG_TRANSPARENT_HUGEPAGE -#define THP_FILE_ALLOC ({ BUILD_BUG(); 0; }) -#define THP_FILE_MAPPED ({ BUILD_BUG(); 0; }) -#endif - -#endif /* VM_EVENT_ITEM_H_INCLUDED */ diff --git a/src/linux/include/linux/vmacache.h b/src/linux/include/linux/vmacache.h deleted file mode 100644 index c3fa0fd..0000000 --- a/src/linux/include/linux/vmacache.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef __LINUX_VMACACHE_H -#define __LINUX_VMACACHE_H - -#include -#include - -/* - * Hash based on the page number. Provides a good hit rate for - * workloads with good locality and those with random accesses as well. - */ -#define VMACACHE_HASH(addr) ((addr >> PAGE_SHIFT) & VMACACHE_MASK) - -static inline void vmacache_flush(struct task_struct *tsk) -{ - memset(tsk->vmacache, 0, sizeof(tsk->vmacache)); -} - -extern void vmacache_flush_all(struct mm_struct *mm); -extern void vmacache_update(unsigned long addr, struct vm_area_struct *newvma); -extern struct vm_area_struct *vmacache_find(struct mm_struct *mm, - unsigned long addr); - -#ifndef CONFIG_MMU -extern struct vm_area_struct *vmacache_find_exact(struct mm_struct *mm, - unsigned long start, - unsigned long end); -#endif - -static inline void vmacache_invalidate(struct mm_struct *mm) -{ - mm->vmacache_seqnum++; - - /* deal with overflows */ - if (unlikely(mm->vmacache_seqnum == 0)) - vmacache_flush_all(mm); -} - -#endif /* __LINUX_VMACACHE_H */ diff --git a/src/linux/include/linux/vmalloc.h b/src/linux/include/linux/vmalloc.h deleted file mode 100644 index 3d9d786..0000000 --- a/src/linux/include/linux/vmalloc.h +++ /dev/null @@ -1,195 +0,0 @@ -#ifndef _LINUX_VMALLOC_H -#define _LINUX_VMALLOC_H - -#include -#include -#include -#include -#include /* pgprot_t */ -#include - -struct vm_area_struct; /* vma defining user mapping in mm_types.h */ -struct notifier_block; /* in notifier.h */ - -/* bits in flags of vmalloc's vm_struct below */ -#define VM_IOREMAP 0x00000001 /* ioremap() and friends */ -#define VM_ALLOC 0x00000002 /* vmalloc() */ -#define VM_MAP 0x00000004 /* vmap()ed pages */ -#define VM_USERMAP 0x00000008 /* suitable for remap_vmalloc_range */ -#define VM_UNINITIALIZED 0x00000020 /* vm_struct is not fully initialized */ -#define VM_NO_GUARD 0x00000040 /* don't add guard page */ -#define VM_KASAN 0x00000080 /* has allocated kasan shadow memory */ -/* bits [20..32] reserved for arch specific ioremap internals */ - -/* - * Maximum alignment for ioremap() regions. - * Can be overriden by arch-specific value. - */ -#ifndef IOREMAP_MAX_ORDER -#define IOREMAP_MAX_ORDER (7 + PAGE_SHIFT) /* 128 pages */ -#endif - -struct vm_struct { - struct vm_struct *next; - void *addr; - unsigned long size; - unsigned long flags; - struct page **pages; - unsigned int nr_pages; - phys_addr_t phys_addr; - const void *caller; -}; - -struct vmap_area { - unsigned long va_start; - unsigned long va_end; - unsigned long flags; - struct rb_node rb_node; /* address sorted rbtree */ - struct list_head list; /* address sorted list */ - struct llist_node purge_list; /* "lazy purge" list */ - struct vm_struct *vm; - struct rcu_head rcu_head; -}; - -/* - * Highlevel APIs for driver use - */ -extern void vm_unmap_ram(const void *mem, unsigned int count); -extern void *vm_map_ram(struct page **pages, unsigned int count, - int node, pgprot_t prot); -extern void vm_unmap_aliases(void); - -#ifdef CONFIG_MMU -extern void __init vmalloc_init(void); -#else -static inline void vmalloc_init(void) -{ -} -#endif - -extern void *vmalloc(unsigned long size); -extern void *vzalloc(unsigned long size); -extern void *vmalloc_user(unsigned long size); -extern void *vmalloc_node(unsigned long size, int node); -extern void *vzalloc_node(unsigned long size, int node); -extern void *vmalloc_exec(unsigned long size); -extern void *vmalloc_32(unsigned long size); -extern void *vmalloc_32_user(unsigned long size); -extern void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot); -extern void *__vmalloc_node_range(unsigned long size, unsigned long align, - unsigned long start, unsigned long end, gfp_t gfp_mask, - pgprot_t prot, unsigned long vm_flags, int node, - const void *caller); - -extern void vfree(const void *addr); - -extern void *vmap(struct page **pages, unsigned int count, - unsigned long flags, pgprot_t prot); -extern void vunmap(const void *addr); - -extern int remap_vmalloc_range_partial(struct vm_area_struct *vma, - unsigned long uaddr, void *kaddr, - unsigned long size); - -extern int remap_vmalloc_range(struct vm_area_struct *vma, void *addr, - unsigned long pgoff); -void vmalloc_sync_all(void); - -/* - * Lowlevel-APIs (not for driver use!) - */ - -static inline size_t get_vm_area_size(const struct vm_struct *area) -{ - if (!(area->flags & VM_NO_GUARD)) - /* return actual size without guard page */ - return area->size - PAGE_SIZE; - else - return area->size; - -} - -extern struct vm_struct *get_vm_area(unsigned long size, unsigned long flags); -extern struct vm_struct *get_vm_area_caller(unsigned long size, - unsigned long flags, const void *caller); -extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags, - unsigned long start, unsigned long end); -extern struct vm_struct *__get_vm_area_caller(unsigned long size, - unsigned long flags, - unsigned long start, unsigned long end, - const void *caller); -extern struct vm_struct *remove_vm_area(const void *addr); -extern struct vm_struct *find_vm_area(const void *addr); - -extern int map_vm_area(struct vm_struct *area, pgprot_t prot, - struct page **pages); -#ifdef CONFIG_MMU -extern int map_kernel_range_noflush(unsigned long start, unsigned long size, - pgprot_t prot, struct page **pages); -extern void unmap_kernel_range_noflush(unsigned long addr, unsigned long size); -extern void unmap_kernel_range(unsigned long addr, unsigned long size); -#else -static inline int -map_kernel_range_noflush(unsigned long start, unsigned long size, - pgprot_t prot, struct page **pages) -{ - return size >> PAGE_SHIFT; -} -static inline void -unmap_kernel_range_noflush(unsigned long addr, unsigned long size) -{ -} -static inline void -unmap_kernel_range(unsigned long addr, unsigned long size) -{ -} -#endif - -/* Allocate/destroy a 'vmalloc' VM area. */ -extern struct vm_struct *alloc_vm_area(size_t size, pte_t **ptes); -extern void free_vm_area(struct vm_struct *area); - -/* for /dev/kmem */ -extern long vread(char *buf, char *addr, unsigned long count); -extern long vwrite(char *buf, char *addr, unsigned long count); - -/* - * Internals. Dont't use.. - */ -extern struct list_head vmap_area_list; -extern __init void vm_area_add_early(struct vm_struct *vm); -extern __init void vm_area_register_early(struct vm_struct *vm, size_t align); - -#ifdef CONFIG_SMP -# ifdef CONFIG_MMU -struct vm_struct **pcpu_get_vm_areas(const unsigned long *offsets, - const size_t *sizes, int nr_vms, - size_t align); - -void pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms); -# else -static inline struct vm_struct ** -pcpu_get_vm_areas(const unsigned long *offsets, - const size_t *sizes, int nr_vms, - size_t align) -{ - return NULL; -} - -static inline void -pcpu_free_vm_areas(struct vm_struct **vms, int nr_vms) -{ -} -# endif -#endif - -#ifdef CONFIG_MMU -#define VMALLOC_TOTAL (VMALLOC_END - VMALLOC_START) -#else -#define VMALLOC_TOTAL 0UL -#endif - -int register_vmap_purge_notifier(struct notifier_block *nb); -int unregister_vmap_purge_notifier(struct notifier_block *nb); - -#endif /* _LINUX_VMALLOC_H */ diff --git a/src/linux/include/linux/vmpressure.h b/src/linux/include/linux/vmpressure.h deleted file mode 100644 index 3347cc3..0000000 --- a/src/linux/include/linux/vmpressure.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef __LINUX_VMPRESSURE_H -#define __LINUX_VMPRESSURE_H - -#include -#include -#include -#include -#include -#include -#include - -struct vmpressure { - unsigned long scanned; - unsigned long reclaimed; - - unsigned long tree_scanned; - unsigned long tree_reclaimed; - /* The lock is used to keep the scanned/reclaimed above in sync. */ - struct spinlock sr_lock; - - /* The list of vmpressure_event structs. */ - struct list_head events; - /* Have to grab the lock on events traversal or modifications. */ - struct mutex events_lock; - - struct work_struct work; -}; - -struct mem_cgroup; - -#ifdef CONFIG_MEMCG -extern void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree, - unsigned long scanned, unsigned long reclaimed); -extern void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, int prio); - -extern void vmpressure_init(struct vmpressure *vmpr); -extern void vmpressure_cleanup(struct vmpressure *vmpr); -extern struct vmpressure *memcg_to_vmpressure(struct mem_cgroup *memcg); -extern struct cgroup_subsys_state *vmpressure_to_css(struct vmpressure *vmpr); -extern int vmpressure_register_event(struct mem_cgroup *memcg, - struct eventfd_ctx *eventfd, - const char *args); -extern void vmpressure_unregister_event(struct mem_cgroup *memcg, - struct eventfd_ctx *eventfd); -#else -static inline void vmpressure(gfp_t gfp, struct mem_cgroup *memcg, bool tree, - unsigned long scanned, unsigned long reclaimed) {} -static inline void vmpressure_prio(gfp_t gfp, struct mem_cgroup *memcg, - int prio) {} -#endif /* CONFIG_MEMCG */ -#endif /* __LINUX_VMPRESSURE_H */ diff --git a/src/linux/include/linux/vmstat.h b/src/linux/include/linux/vmstat.h deleted file mode 100644 index 6137719..0000000 --- a/src/linux/include/linux/vmstat.h +++ /dev/null @@ -1,354 +0,0 @@ -#ifndef _LINUX_VMSTAT_H -#define _LINUX_VMSTAT_H - -#include -#include -#include -#include -#include -#include - -extern int sysctl_stat_interval; - -#ifdef CONFIG_VM_EVENT_COUNTERS -/* - * Light weight per cpu counter implementation. - * - * Counters should only be incremented and no critical kernel component - * should rely on the counter values. - * - * Counters are handled completely inline. On many platforms the code - * generated will simply be the increment of a global address. - */ - -struct vm_event_state { - unsigned long event[NR_VM_EVENT_ITEMS]; -}; - -DECLARE_PER_CPU(struct vm_event_state, vm_event_states); - -/* - * vm counters are allowed to be racy. Use raw_cpu_ops to avoid the - * local_irq_disable overhead. - */ -static inline void __count_vm_event(enum vm_event_item item) -{ - raw_cpu_inc(vm_event_states.event[item]); -} - -static inline void count_vm_event(enum vm_event_item item) -{ - this_cpu_inc(vm_event_states.event[item]); -} - -static inline void __count_vm_events(enum vm_event_item item, long delta) -{ - raw_cpu_add(vm_event_states.event[item], delta); -} - -static inline void count_vm_events(enum vm_event_item item, long delta) -{ - this_cpu_add(vm_event_states.event[item], delta); -} - -extern void all_vm_events(unsigned long *); - -extern void vm_events_fold_cpu(int cpu); - -#else - -/* Disable counters */ -static inline void count_vm_event(enum vm_event_item item) -{ -} -static inline void count_vm_events(enum vm_event_item item, long delta) -{ -} -static inline void __count_vm_event(enum vm_event_item item) -{ -} -static inline void __count_vm_events(enum vm_event_item item, long delta) -{ -} -static inline void all_vm_events(unsigned long *ret) -{ -} -static inline void vm_events_fold_cpu(int cpu) -{ -} - -#endif /* CONFIG_VM_EVENT_COUNTERS */ - -#ifdef CONFIG_NUMA_BALANCING -#define count_vm_numa_event(x) count_vm_event(x) -#define count_vm_numa_events(x, y) count_vm_events(x, y) -#else -#define count_vm_numa_event(x) do {} while (0) -#define count_vm_numa_events(x, y) do { (void)(y); } while (0) -#endif /* CONFIG_NUMA_BALANCING */ - -#ifdef CONFIG_DEBUG_TLBFLUSH -#define count_vm_tlb_event(x) count_vm_event(x) -#define count_vm_tlb_events(x, y) count_vm_events(x, y) -#else -#define count_vm_tlb_event(x) do {} while (0) -#define count_vm_tlb_events(x, y) do { (void)(y); } while (0) -#endif - -#ifdef CONFIG_DEBUG_VM_VMACACHE -#define count_vm_vmacache_event(x) count_vm_event(x) -#else -#define count_vm_vmacache_event(x) do {} while (0) -#endif - -#define __count_zid_vm_events(item, zid, delta) \ - __count_vm_events(item##_NORMAL - ZONE_NORMAL + zid, delta) - -/* - * Zone and node-based page accounting with per cpu differentials. - */ -extern atomic_long_t vm_zone_stat[NR_VM_ZONE_STAT_ITEMS]; -extern atomic_long_t vm_node_stat[NR_VM_NODE_STAT_ITEMS]; - -static inline void zone_page_state_add(long x, struct zone *zone, - enum zone_stat_item item) -{ - atomic_long_add(x, &zone->vm_stat[item]); - atomic_long_add(x, &vm_zone_stat[item]); -} - -static inline void node_page_state_add(long x, struct pglist_data *pgdat, - enum node_stat_item item) -{ - atomic_long_add(x, &pgdat->vm_stat[item]); - atomic_long_add(x, &vm_node_stat[item]); -} - -static inline unsigned long global_page_state(enum zone_stat_item item) -{ - long x = atomic_long_read(&vm_zone_stat[item]); -#ifdef CONFIG_SMP - if (x < 0) - x = 0; -#endif - return x; -} - -static inline unsigned long global_node_page_state(enum node_stat_item item) -{ - long x = atomic_long_read(&vm_node_stat[item]); -#ifdef CONFIG_SMP - if (x < 0) - x = 0; -#endif - return x; -} - -static inline unsigned long zone_page_state(struct zone *zone, - enum zone_stat_item item) -{ - long x = atomic_long_read(&zone->vm_stat[item]); -#ifdef CONFIG_SMP - if (x < 0) - x = 0; -#endif - return x; -} - -/* - * More accurate version that also considers the currently pending - * deltas. For that we need to loop over all cpus to find the current - * deltas. There is no synchronization so the result cannot be - * exactly accurate either. - */ -static inline unsigned long zone_page_state_snapshot(struct zone *zone, - enum zone_stat_item item) -{ - long x = atomic_long_read(&zone->vm_stat[item]); - -#ifdef CONFIG_SMP - int cpu; - for_each_online_cpu(cpu) - x += per_cpu_ptr(zone->pageset, cpu)->vm_stat_diff[item]; - - if (x < 0) - x = 0; -#endif - return x; -} - -static inline unsigned long node_page_state_snapshot(pg_data_t *pgdat, - enum node_stat_item item) -{ - long x = atomic_long_read(&pgdat->vm_stat[item]); - -#ifdef CONFIG_SMP - int cpu; - for_each_online_cpu(cpu) - x += per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->vm_node_stat_diff[item]; - - if (x < 0) - x = 0; -#endif - return x; -} - - -#ifdef CONFIG_NUMA -extern unsigned long sum_zone_node_page_state(int node, - enum zone_stat_item item); -extern unsigned long node_page_state(struct pglist_data *pgdat, - enum node_stat_item item); -#else -#define sum_zone_node_page_state(node, item) global_page_state(item) -#define node_page_state(node, item) global_node_page_state(item) -#endif /* CONFIG_NUMA */ - -#define add_zone_page_state(__z, __i, __d) mod_zone_page_state(__z, __i, __d) -#define sub_zone_page_state(__z, __i, __d) mod_zone_page_state(__z, __i, -(__d)) -#define add_node_page_state(__p, __i, __d) mod_node_page_state(__p, __i, __d) -#define sub_node_page_state(__p, __i, __d) mod_node_page_state(__p, __i, -(__d)) - -#ifdef CONFIG_SMP -void __mod_zone_page_state(struct zone *, enum zone_stat_item item, long); -void __inc_zone_page_state(struct page *, enum zone_stat_item); -void __dec_zone_page_state(struct page *, enum zone_stat_item); - -void __mod_node_page_state(struct pglist_data *, enum node_stat_item item, long); -void __inc_node_page_state(struct page *, enum node_stat_item); -void __dec_node_page_state(struct page *, enum node_stat_item); - -void mod_zone_page_state(struct zone *, enum zone_stat_item, long); -void inc_zone_page_state(struct page *, enum zone_stat_item); -void dec_zone_page_state(struct page *, enum zone_stat_item); - -void mod_node_page_state(struct pglist_data *, enum node_stat_item, long); -void inc_node_page_state(struct page *, enum node_stat_item); -void dec_node_page_state(struct page *, enum node_stat_item); - -extern void inc_node_state(struct pglist_data *, enum node_stat_item); -extern void __inc_zone_state(struct zone *, enum zone_stat_item); -extern void __inc_node_state(struct pglist_data *, enum node_stat_item); -extern void dec_zone_state(struct zone *, enum zone_stat_item); -extern void __dec_zone_state(struct zone *, enum zone_stat_item); -extern void __dec_node_state(struct pglist_data *, enum node_stat_item); - -void quiet_vmstat(void); -void cpu_vm_stats_fold(int cpu); -void refresh_zone_stat_thresholds(void); - -struct ctl_table; -int vmstat_refresh(struct ctl_table *, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); - -void drain_zonestat(struct zone *zone, struct per_cpu_pageset *); - -int calculate_pressure_threshold(struct zone *zone); -int calculate_normal_threshold(struct zone *zone); -void set_pgdat_percpu_threshold(pg_data_t *pgdat, - int (*calculate_pressure)(struct zone *)); -#else /* CONFIG_SMP */ - -/* - * We do not maintain differentials in a single processor configuration. - * The functions directly modify the zone and global counters. - */ -static inline void __mod_zone_page_state(struct zone *zone, - enum zone_stat_item item, long delta) -{ - zone_page_state_add(delta, zone, item); -} - -static inline void __mod_node_page_state(struct pglist_data *pgdat, - enum node_stat_item item, int delta) -{ - node_page_state_add(delta, pgdat, item); -} - -static inline void __inc_zone_state(struct zone *zone, enum zone_stat_item item) -{ - atomic_long_inc(&zone->vm_stat[item]); - atomic_long_inc(&vm_zone_stat[item]); -} - -static inline void __inc_node_state(struct pglist_data *pgdat, enum node_stat_item item) -{ - atomic_long_inc(&pgdat->vm_stat[item]); - atomic_long_inc(&vm_node_stat[item]); -} - -static inline void __dec_zone_state(struct zone *zone, enum zone_stat_item item) -{ - atomic_long_dec(&zone->vm_stat[item]); - atomic_long_dec(&vm_zone_stat[item]); -} - -static inline void __dec_node_state(struct pglist_data *pgdat, enum node_stat_item item) -{ - atomic_long_dec(&pgdat->vm_stat[item]); - atomic_long_dec(&vm_node_stat[item]); -} - -static inline void __inc_zone_page_state(struct page *page, - enum zone_stat_item item) -{ - __inc_zone_state(page_zone(page), item); -} - -static inline void __inc_node_page_state(struct page *page, - enum node_stat_item item) -{ - __inc_node_state(page_pgdat(page), item); -} - - -static inline void __dec_zone_page_state(struct page *page, - enum zone_stat_item item) -{ - __dec_zone_state(page_zone(page), item); -} - -static inline void __dec_node_page_state(struct page *page, - enum node_stat_item item) -{ - __dec_node_state(page_pgdat(page), item); -} - - -/* - * We only use atomic operations to update counters. So there is no need to - * disable interrupts. - */ -#define inc_zone_page_state __inc_zone_page_state -#define dec_zone_page_state __dec_zone_page_state -#define mod_zone_page_state __mod_zone_page_state - -#define inc_node_page_state __inc_node_page_state -#define dec_node_page_state __dec_node_page_state -#define mod_node_page_state __mod_node_page_state - -#define inc_zone_state __inc_zone_state -#define inc_node_state __inc_node_state -#define dec_zone_state __dec_zone_state - -#define set_pgdat_percpu_threshold(pgdat, callback) { } - -static inline void refresh_zone_stat_thresholds(void) { } -static inline void cpu_vm_stats_fold(int cpu) { } -static inline void quiet_vmstat(void) { } - -static inline void drain_zonestat(struct zone *zone, - struct per_cpu_pageset *pset) { } -#endif /* CONFIG_SMP */ - -static inline void __mod_zone_freepage_state(struct zone *zone, int nr_pages, - int migratetype) -{ - __mod_zone_page_state(zone, NR_FREE_PAGES, nr_pages); - if (is_migrate_cma(migratetype)) - __mod_zone_page_state(zone, NR_FREE_CMA_PAGES, nr_pages); -} - -extern const char * const vmstat_text[]; - -#endif /* _LINUX_VMSTAT_H */ diff --git a/src/linux/include/linux/vringh.h b/src/linux/include/linux/vringh.h deleted file mode 100644 index bc6c28d..0000000 --- a/src/linux/include/linux/vringh.h +++ /dev/null @@ -1,264 +0,0 @@ -/* - * Linux host-side vring helpers; for when the kernel needs to access - * someone else's vring. - * - * Copyright IBM Corporation, 2013. - * Parts taken from drivers/vhost/vhost.c Copyright 2009 Red Hat, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Written by: Rusty Russell - */ -#ifndef _LINUX_VRINGH_H -#define _LINUX_VRINGH_H -#include -#include -#include -#include -#include - -/* virtio_ring with information needed for host access. */ -struct vringh { - /* Everything is little endian */ - bool little_endian; - - /* Guest publishes used event idx (note: we always do). */ - bool event_indices; - - /* Can we get away with weak barriers? */ - bool weak_barriers; - - /* Last available index we saw (ie. where we're up to). */ - u16 last_avail_idx; - - /* Last index we used. */ - u16 last_used_idx; - - /* How many descriptors we've completed since last need_notify(). */ - u32 completed; - - /* The vring (note: it may contain user pointers!) */ - struct vring vring; - - /* The function to call to notify the guest about added buffers */ - void (*notify)(struct vringh *); -}; - -/** - * struct vringh_config_ops - ops for creating a host vring from a virtio driver - * @find_vrhs: find the host vrings and instantiate them - * vdev: the virtio_device - * nhvrs: the number of host vrings to find - * hvrs: on success, includes new host vrings - * callbacks: array of driver callbacks, for each host vring - * include a NULL entry for vqs that do not need a callback - * Returns 0 on success or error status - * @del_vrhs: free the host vrings found by find_vrhs(). - */ -struct virtio_device; -typedef void vrh_callback_t(struct virtio_device *, struct vringh *); -struct vringh_config_ops { - int (*find_vrhs)(struct virtio_device *vdev, unsigned nhvrs, - struct vringh *vrhs[], vrh_callback_t *callbacks[]); - void (*del_vrhs)(struct virtio_device *vdev); -}; - -/* The memory the vring can access, and what offset to apply. */ -struct vringh_range { - u64 start, end_incl; - u64 offset; -}; - -/** - * struct vringh_iov - iovec mangler. - * - * Mangles iovec in place, and restores it. - * Remaining data is iov + i, of used - i elements. - */ -struct vringh_iov { - struct iovec *iov; - size_t consumed; /* Within iov[i] */ - unsigned i, used, max_num; -}; - -/** - * struct vringh_iov - kvec mangler. - * - * Mangles kvec in place, and restores it. - * Remaining data is iov + i, of used - i elements. - */ -struct vringh_kiov { - struct kvec *iov; - size_t consumed; /* Within iov[i] */ - unsigned i, used, max_num; -}; - -/* Flag on max_num to indicate we're kmalloced. */ -#define VRINGH_IOV_ALLOCATED 0x8000000 - -/* Helpers for userspace vrings. */ -int vringh_init_user(struct vringh *vrh, u64 features, - unsigned int num, bool weak_barriers, - struct vring_desc __user *desc, - struct vring_avail __user *avail, - struct vring_used __user *used); - -static inline void vringh_iov_init(struct vringh_iov *iov, - struct iovec *iovec, unsigned num) -{ - iov->used = iov->i = 0; - iov->consumed = 0; - iov->max_num = num; - iov->iov = iovec; -} - -static inline void vringh_iov_reset(struct vringh_iov *iov) -{ - iov->iov[iov->i].iov_len += iov->consumed; - iov->iov[iov->i].iov_base -= iov->consumed; - iov->consumed = 0; - iov->i = 0; -} - -static inline void vringh_iov_cleanup(struct vringh_iov *iov) -{ - if (iov->max_num & VRINGH_IOV_ALLOCATED) - kfree(iov->iov); - iov->max_num = iov->used = iov->i = iov->consumed = 0; - iov->iov = NULL; -} - -/* Convert a descriptor into iovecs. */ -int vringh_getdesc_user(struct vringh *vrh, - struct vringh_iov *riov, - struct vringh_iov *wiov, - bool (*getrange)(struct vringh *vrh, - u64 addr, struct vringh_range *r), - u16 *head); - -/* Copy bytes from readable vsg, consuming it (and incrementing wiov->i). */ -ssize_t vringh_iov_pull_user(struct vringh_iov *riov, void *dst, size_t len); - -/* Copy bytes into writable vsg, consuming it (and incrementing wiov->i). */ -ssize_t vringh_iov_push_user(struct vringh_iov *wiov, - const void *src, size_t len); - -/* Mark a descriptor as used. */ -int vringh_complete_user(struct vringh *vrh, u16 head, u32 len); -int vringh_complete_multi_user(struct vringh *vrh, - const struct vring_used_elem used[], - unsigned num_used); - -/* Pretend we've never seen descriptor (for easy error handling). */ -void vringh_abandon_user(struct vringh *vrh, unsigned int num); - -/* Do we need to fire the eventfd to notify the other side? */ -int vringh_need_notify_user(struct vringh *vrh); - -bool vringh_notify_enable_user(struct vringh *vrh); -void vringh_notify_disable_user(struct vringh *vrh); - -/* Helpers for kernelspace vrings. */ -int vringh_init_kern(struct vringh *vrh, u64 features, - unsigned int num, bool weak_barriers, - struct vring_desc *desc, - struct vring_avail *avail, - struct vring_used *used); - -static inline void vringh_kiov_init(struct vringh_kiov *kiov, - struct kvec *kvec, unsigned num) -{ - kiov->used = kiov->i = 0; - kiov->consumed = 0; - kiov->max_num = num; - kiov->iov = kvec; -} - -static inline void vringh_kiov_reset(struct vringh_kiov *kiov) -{ - kiov->iov[kiov->i].iov_len += kiov->consumed; - kiov->iov[kiov->i].iov_base -= kiov->consumed; - kiov->consumed = 0; - kiov->i = 0; -} - -static inline void vringh_kiov_cleanup(struct vringh_kiov *kiov) -{ - if (kiov->max_num & VRINGH_IOV_ALLOCATED) - kfree(kiov->iov); - kiov->max_num = kiov->used = kiov->i = kiov->consumed = 0; - kiov->iov = NULL; -} - -int vringh_getdesc_kern(struct vringh *vrh, - struct vringh_kiov *riov, - struct vringh_kiov *wiov, - u16 *head, - gfp_t gfp); - -ssize_t vringh_iov_pull_kern(struct vringh_kiov *riov, void *dst, size_t len); -ssize_t vringh_iov_push_kern(struct vringh_kiov *wiov, - const void *src, size_t len); -void vringh_abandon_kern(struct vringh *vrh, unsigned int num); -int vringh_complete_kern(struct vringh *vrh, u16 head, u32 len); - -bool vringh_notify_enable_kern(struct vringh *vrh); -void vringh_notify_disable_kern(struct vringh *vrh); - -int vringh_need_notify_kern(struct vringh *vrh); - -/* Notify the guest about buffers added to the used ring */ -static inline void vringh_notify(struct vringh *vrh) -{ - if (vrh->notify) - vrh->notify(vrh); -} - -static inline bool vringh_is_little_endian(const struct vringh *vrh) -{ - return vrh->little_endian || - virtio_legacy_is_little_endian(); -} - -static inline u16 vringh16_to_cpu(const struct vringh *vrh, __virtio16 val) -{ - return __virtio16_to_cpu(vringh_is_little_endian(vrh), val); -} - -static inline __virtio16 cpu_to_vringh16(const struct vringh *vrh, u16 val) -{ - return __cpu_to_virtio16(vringh_is_little_endian(vrh), val); -} - -static inline u32 vringh32_to_cpu(const struct vringh *vrh, __virtio32 val) -{ - return __virtio32_to_cpu(vringh_is_little_endian(vrh), val); -} - -static inline __virtio32 cpu_to_vringh32(const struct vringh *vrh, u32 val) -{ - return __cpu_to_virtio32(vringh_is_little_endian(vrh), val); -} - -static inline u64 vringh64_to_cpu(const struct vringh *vrh, __virtio64 val) -{ - return __virtio64_to_cpu(vringh_is_little_endian(vrh), val); -} - -static inline __virtio64 cpu_to_vringh64(const struct vringh *vrh, u64 val) -{ - return __cpu_to_virtio64(vringh_is_little_endian(vrh), val); -} -#endif /* _LINUX_VRINGH_H */ diff --git a/src/linux/include/linux/vt.h b/src/linux/include/linux/vt.h deleted file mode 100644 index b186e04..0000000 --- a/src/linux/include/linux/vt.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _LINUX_VT_H -#define _LINUX_VT_H - -#include - - -/* Virtual Terminal events. */ -#define VT_ALLOCATE 0x0001 /* Console got allocated */ -#define VT_DEALLOCATE 0x0002 /* Console will be deallocated */ -#define VT_WRITE 0x0003 /* A char got output */ -#define VT_UPDATE 0x0004 /* A bigger update occurred */ -#define VT_PREWRITE 0x0005 /* A char is about to be written to the console */ - -#ifdef CONFIG_VT_CONSOLE - -extern int vt_kmsg_redirect(int new); - -#else - -static inline int vt_kmsg_redirect(int new) -{ - return 0; -} - -#endif - -#endif /* _LINUX_VT_H */ diff --git a/src/linux/include/linux/vt_buffer.h b/src/linux/include/linux/vt_buffer.h deleted file mode 100644 index f38c10b..0000000 --- a/src/linux/include/linux/vt_buffer.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * include/linux/vt_buffer.h -- Access to VT screen buffer - * - * (c) 1998 Martin Mares - * - * This is a set of macros and functions which are used in the - * console driver and related code to access the screen buffer. - * In most cases the console works with simple in-memory buffer, - * but when handling hardware text mode consoles, we store - * the foreground console directly in video memory. - */ - -#ifndef _LINUX_VT_BUFFER_H_ -#define _LINUX_VT_BUFFER_H_ - - -#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_MDA_CONSOLE) -#include -#endif - -#ifndef VT_BUF_HAVE_RW -#define scr_writew(val, addr) (*(addr) = (val)) -#define scr_readw(addr) (*(addr)) -#endif - -#ifndef VT_BUF_HAVE_MEMSETW -static inline void scr_memsetw(u16 *s, u16 c, unsigned int count) -{ - count /= 2; - while (count--) - scr_writew(c, s++); -} -#endif - -#ifndef VT_BUF_HAVE_MEMCPYW -static inline void scr_memcpyw(u16 *d, const u16 *s, unsigned int count) -{ - count /= 2; - while (count--) - scr_writew(scr_readw(s++), d++); -} -#endif - -#ifndef VT_BUF_HAVE_MEMMOVEW -static inline void scr_memmovew(u16 *d, const u16 *s, unsigned int count) -{ - if (d < s) - scr_memcpyw(d, s, count); - else { - count /= 2; - d += count; - s += count; - while (count--) - scr_writew(scr_readw(--s), --d); - } -} -#endif - -#endif diff --git a/src/linux/include/linux/vt_kern.h b/src/linux/include/linux/vt_kern.h deleted file mode 100644 index 6abd24f..0000000 --- a/src/linux/include/linux/vt_kern.h +++ /dev/null @@ -1,195 +0,0 @@ -#ifndef _VT_KERN_H -#define _VT_KERN_H - -/* - * this really is an extension of the vc_cons structure in console.c, but - * with information needed by the vt package - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Presently, a lot of graphics programs do not restore the contents of - * the higher font pages. Defining this flag will avoid use of them, but - * will lose support for PIO_FONTRESET. Note that many font operations are - * not likely to work with these programs anyway; they need to be - * fixed. The linux/Documentation directory includes a code snippet - * to save and restore the text font. - */ -#ifdef CONFIG_VGA_CONSOLE -#define BROKEN_GRAPHICS_PROGRAMS 1 -#endif - -extern void kd_mksound(unsigned int hz, unsigned int ticks); -extern int kbd_rate(struct kbd_repeat *rep); -extern int fg_console, last_console, want_console; - -/* console.c */ - -int vc_allocate(unsigned int console); -int vc_cons_allocated(unsigned int console); -int vc_resize(struct vc_data *vc, unsigned int cols, unsigned int lines); -struct vc_data *vc_deallocate(unsigned int console); -void reset_palette(struct vc_data *vc); -void do_blank_screen(int entering_gfx); -void do_unblank_screen(int leaving_gfx); -void unblank_screen(void); -void poke_blanked_console(void); -int con_font_op(struct vc_data *vc, struct console_font_op *op); -int con_set_cmap(unsigned char __user *cmap); -int con_get_cmap(unsigned char __user *cmap); -void scrollback(struct vc_data *vc); -void scrollfront(struct vc_data *vc, int lines); -void clear_buffer_attributes(struct vc_data *vc); -void update_region(struct vc_data *vc, unsigned long start, int count); -void redraw_screen(struct vc_data *vc, int is_switch); -#define update_screen(x) redraw_screen(x, 0) -#define switch_screen(x) redraw_screen(x, 1) - -struct tty_struct; -int tioclinux(struct tty_struct *tty, unsigned long arg); - -#ifdef CONFIG_CONSOLE_TRANSLATIONS -/* consolemap.c */ - -struct unipair; - -int con_set_trans_old(unsigned char __user * table); -int con_get_trans_old(unsigned char __user * table); -int con_set_trans_new(unsigned short __user * table); -int con_get_trans_new(unsigned short __user * table); -int con_clear_unimap(struct vc_data *vc); -int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list); -int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, struct unipair __user *list); -int con_set_default_unimap(struct vc_data *vc); -void con_free_unimap(struct vc_data *vc); -int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc); - -#define vc_translate(vc, c) ((vc)->vc_translate[(c) | \ - ((vc)->vc_toggle_meta ? 0x80 : 0)]) -#else -static inline int con_set_trans_old(unsigned char __user *table) -{ - return 0; -} -static inline int con_get_trans_old(unsigned char __user *table) -{ - return -EINVAL; -} -static inline int con_set_trans_new(unsigned short __user *table) -{ - return 0; -} -static inline int con_get_trans_new(unsigned short __user *table) -{ - return -EINVAL; -} -static inline int con_clear_unimap(struct vc_data *vc) -{ - return 0; -} -static inline -int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) -{ - return 0; -} -static inline -int con_get_unimap(struct vc_data *vc, ushort ct, ushort __user *uct, - struct unipair __user *list) -{ - return -EINVAL; -} -static inline int con_set_default_unimap(struct vc_data *vc) -{ - return 0; -} -static inline void con_free_unimap(struct vc_data *vc) -{ -} -static inline void con_protect_unimap(struct vc_data *vc, int rdonly) -{ -} -static inline -int con_copy_unimap(struct vc_data *dst_vc, struct vc_data *src_vc) -{ - return 0; -} - -#define vc_translate(vc, c) (c) -#endif - -/* vt.c */ -void vt_event_post(unsigned int event, unsigned int old, unsigned int new); -int vt_waitactive(int n); -void change_console(struct vc_data *new_vc); -void reset_vc(struct vc_data *vc); -extern int do_unbind_con_driver(const struct consw *csw, int first, int last, - int deflt); -int vty_init(const struct file_operations *console_fops); - -static inline bool vt_force_oops_output(struct vc_data *vc) -{ - if (oops_in_progress && vc->vc_panic_force_write && panic_timeout >= 0) - return true; - return false; -} - -extern char vt_dont_switch; -extern int default_utf8; -extern int global_cursor_default; - -struct vt_spawn_console { - spinlock_t lock; - struct pid *pid; - int sig; -}; -extern struct vt_spawn_console vt_spawn_con; - -extern int vt_move_to_console(unsigned int vt, int alloc); - -/* Interfaces for VC notification of character events (for accessibility etc) */ - -struct vt_notifier_param { - struct vc_data *vc; /* VC on which the update happened */ - unsigned int c; /* Printed char */ -}; - -extern int register_vt_notifier(struct notifier_block *nb); -extern int unregister_vt_notifier(struct notifier_block *nb); - -extern void hide_boot_cursor(bool hide); - -/* keyboard provided interfaces */ -extern int vt_do_diacrit(unsigned int cmd, void __user *up, int eperm); -extern int vt_do_kdskbmode(int console, unsigned int arg); -extern int vt_do_kdskbmeta(int console, unsigned int arg); -extern int vt_do_kbkeycode_ioctl(int cmd, struct kbkeycode __user *user_kbkc, - int perm); -extern int vt_do_kdsk_ioctl(int cmd, struct kbentry __user *user_kbe, - int perm, int console); -extern int vt_do_kdgkb_ioctl(int cmd, struct kbsentry __user *user_kdgkb, - int perm); -extern int vt_do_kdskled(int console, int cmd, unsigned long arg, int perm); -extern int vt_do_kdgkbmode(int console); -extern int vt_do_kdgkbmeta(int console); -extern void vt_reset_unicode(int console); -extern int vt_get_shift_state(void); -extern void vt_reset_keyboard(int console); -extern int vt_get_leds(int console, int flag); -extern int vt_get_kbd_mode_bit(int console, int bit); -extern void vt_set_kbd_mode_bit(int console, int bit); -extern void vt_clr_kbd_mode_bit(int console, int bit); -extern void vt_set_led_state(int console, int leds); -extern void vt_set_led_state(int console, int leds); -extern void vt_kbd_con_start(int console); -extern void vt_kbd_con_stop(int console); - - -#endif /* _VT_KERN_H */ diff --git a/src/linux/include/linux/vtime.h b/src/linux/include/linux/vtime.h deleted file mode 100644 index aa9bfea..0000000 --- a/src/linux/include/linux/vtime.h +++ /dev/null @@ -1,120 +0,0 @@ -#ifndef _LINUX_KERNEL_VTIME_H -#define _LINUX_KERNEL_VTIME_H - -#include -#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE -#include -#endif - - -struct task_struct; - -/* - * vtime_accounting_cpu_enabled() definitions/declarations - */ -#if defined(CONFIG_VIRT_CPU_ACCOUNTING_NATIVE) -static inline bool vtime_accounting_cpu_enabled(void) { return true; } -#elif defined(CONFIG_VIRT_CPU_ACCOUNTING_GEN) -/* - * Checks if vtime is enabled on some CPU. Cputime readers want to be careful - * in that case and compute the tickless cputime. - * For now vtime state is tied to context tracking. We might want to decouple - * those later if necessary. - */ -static inline bool vtime_accounting_enabled(void) -{ - return context_tracking_is_enabled(); -} - -static inline bool vtime_accounting_cpu_enabled(void) -{ - if (vtime_accounting_enabled()) { - if (context_tracking_cpu_is_enabled()) - return true; - } - - return false; -} -#else /* !CONFIG_VIRT_CPU_ACCOUNTING */ -static inline bool vtime_accounting_cpu_enabled(void) { return false; } -#endif - - -/* - * Common vtime APIs - */ -#ifdef CONFIG_VIRT_CPU_ACCOUNTING - -#ifdef __ARCH_HAS_VTIME_TASK_SWITCH -extern void vtime_task_switch(struct task_struct *prev); -#else -extern void vtime_common_task_switch(struct task_struct *prev); -static inline void vtime_task_switch(struct task_struct *prev) -{ - if (vtime_accounting_cpu_enabled()) - vtime_common_task_switch(prev); -} -#endif /* __ARCH_HAS_VTIME_TASK_SWITCH */ - -extern void vtime_account_system(struct task_struct *tsk); -extern void vtime_account_idle(struct task_struct *tsk); -extern void vtime_account_user(struct task_struct *tsk); - -#else /* !CONFIG_VIRT_CPU_ACCOUNTING */ - -static inline void vtime_task_switch(struct task_struct *prev) { } -static inline void vtime_account_system(struct task_struct *tsk) { } -static inline void vtime_account_user(struct task_struct *tsk) { } -#endif /* !CONFIG_VIRT_CPU_ACCOUNTING */ - -#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN -extern void arch_vtime_task_switch(struct task_struct *tsk); -extern void vtime_user_enter(struct task_struct *tsk); - -static inline void vtime_user_exit(struct task_struct *tsk) -{ - vtime_account_user(tsk); -} -extern void vtime_guest_enter(struct task_struct *tsk); -extern void vtime_guest_exit(struct task_struct *tsk); -extern void vtime_init_idle(struct task_struct *tsk, int cpu); -#else /* !CONFIG_VIRT_CPU_ACCOUNTING_GEN */ -static inline void vtime_user_enter(struct task_struct *tsk) { } -static inline void vtime_user_exit(struct task_struct *tsk) { } -static inline void vtime_guest_enter(struct task_struct *tsk) { } -static inline void vtime_guest_exit(struct task_struct *tsk) { } -static inline void vtime_init_idle(struct task_struct *tsk, int cpu) { } -#endif - -#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE -extern void vtime_account_irq_enter(struct task_struct *tsk); -static inline void vtime_account_irq_exit(struct task_struct *tsk) -{ - /* On hard|softirq exit we always account to hard|softirq cputime */ - vtime_account_system(tsk); -} -#else /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ -static inline void vtime_account_irq_enter(struct task_struct *tsk) { } -static inline void vtime_account_irq_exit(struct task_struct *tsk) { } -#endif - - -#ifdef CONFIG_IRQ_TIME_ACCOUNTING -extern void irqtime_account_irq(struct task_struct *tsk); -#else -static inline void irqtime_account_irq(struct task_struct *tsk) { } -#endif - -static inline void account_irq_enter_time(struct task_struct *tsk) -{ - vtime_account_irq_enter(tsk); - irqtime_account_irq(tsk); -} - -static inline void account_irq_exit_time(struct task_struct *tsk) -{ - vtime_account_irq_exit(tsk); - irqtime_account_irq(tsk); -} - -#endif /* _LINUX_KERNEL_VTIME_H */ diff --git a/src/linux/include/linux/wait.h b/src/linux/include/linux/wait.h deleted file mode 100644 index 2408e8d..0000000 --- a/src/linux/include/linux/wait.h +++ /dev/null @@ -1,1226 +0,0 @@ -#ifndef _LINUX_WAIT_H -#define _LINUX_WAIT_H -/* - * Linux wait queue related types and methods - */ -#include -#include -#include -#include -#include - -typedef struct __wait_queue wait_queue_t; -typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int flags, void *key); -int default_wake_function(wait_queue_t *wait, unsigned mode, int flags, void *key); - -/* __wait_queue::flags */ -#define WQ_FLAG_EXCLUSIVE 0x01 -#define WQ_FLAG_WOKEN 0x02 - -struct __wait_queue { - unsigned int flags; - void *private; - wait_queue_func_t func; - struct list_head task_list; -}; - -struct wait_bit_key { - void *flags; - int bit_nr; -#define WAIT_ATOMIC_T_BIT_NR -1 - unsigned long timeout; -}; - -struct wait_bit_queue { - struct wait_bit_key key; - wait_queue_t wait; -}; - -struct __wait_queue_head { - spinlock_t lock; - struct list_head task_list; -}; -typedef struct __wait_queue_head wait_queue_head_t; - -struct task_struct; - -/* - * Macros for declaration and initialisaton of the datatypes - */ - -#define __WAITQUEUE_INITIALIZER(name, tsk) { \ - .private = tsk, \ - .func = default_wake_function, \ - .task_list = { NULL, NULL } } - -#define DECLARE_WAITQUEUE(name, tsk) \ - wait_queue_t name = __WAITQUEUE_INITIALIZER(name, tsk) - -#define __WAIT_QUEUE_HEAD_INITIALIZER(name) { \ - .lock = __SPIN_LOCK_UNLOCKED(name.lock), \ - .task_list = { &(name).task_list, &(name).task_list } } - -#define DECLARE_WAIT_QUEUE_HEAD(name) \ - wait_queue_head_t name = __WAIT_QUEUE_HEAD_INITIALIZER(name) - -#define __WAIT_BIT_KEY_INITIALIZER(word, bit) \ - { .flags = word, .bit_nr = bit, } - -#define __WAIT_ATOMIC_T_KEY_INITIALIZER(p) \ - { .flags = p, .bit_nr = WAIT_ATOMIC_T_BIT_NR, } - -extern void __init_waitqueue_head(wait_queue_head_t *q, const char *name, struct lock_class_key *); - -#define init_waitqueue_head(q) \ - do { \ - static struct lock_class_key __key; \ - \ - __init_waitqueue_head((q), #q, &__key); \ - } while (0) - -#ifdef CONFIG_LOCKDEP -# define __WAIT_QUEUE_HEAD_INIT_ONSTACK(name) \ - ({ init_waitqueue_head(&name); name; }) -# define DECLARE_WAIT_QUEUE_HEAD_ONSTACK(name) \ - wait_queue_head_t name = __WAIT_QUEUE_HEAD_INIT_ONSTACK(name) -#else -# define DECLARE_WAIT_QUEUE_HEAD_ONSTACK(name) DECLARE_WAIT_QUEUE_HEAD(name) -#endif - -static inline void init_waitqueue_entry(wait_queue_t *q, struct task_struct *p) -{ - q->flags = 0; - q->private = p; - q->func = default_wake_function; -} - -static inline void -init_waitqueue_func_entry(wait_queue_t *q, wait_queue_func_t func) -{ - q->flags = 0; - q->private = NULL; - q->func = func; -} - -/** - * waitqueue_active -- locklessly test for waiters on the queue - * @q: the waitqueue to test for waiters - * - * returns true if the wait list is not empty - * - * NOTE: this function is lockless and requires care, incorrect usage _will_ - * lead to sporadic and non-obvious failure. - * - * Use either while holding wait_queue_head_t::lock or when used for wakeups - * with an extra smp_mb() like: - * - * CPU0 - waker CPU1 - waiter - * - * for (;;) { - * @cond = true; prepare_to_wait(&wq, &wait, state); - * smp_mb(); // smp_mb() from set_current_state() - * if (waitqueue_active(wq)) if (@cond) - * wake_up(wq); break; - * schedule(); - * } - * finish_wait(&wq, &wait); - * - * Because without the explicit smp_mb() it's possible for the - * waitqueue_active() load to get hoisted over the @cond store such that we'll - * observe an empty wait list while the waiter might not observe @cond. - * - * Also note that this 'optimization' trades a spin_lock() for an smp_mb(), - * which (when the lock is uncontended) are of roughly equal cost. - */ -static inline int waitqueue_active(wait_queue_head_t *q) -{ - return !list_empty(&q->task_list); -} - -/** - * wq_has_sleeper - check if there are any waiting processes - * @wq: wait queue head - * - * Returns true if wq has waiting processes - * - * Please refer to the comment for waitqueue_active. - */ -static inline bool wq_has_sleeper(wait_queue_head_t *wq) -{ - /* - * We need to be sure we are in sync with the - * add_wait_queue modifications to the wait queue. - * - * This memory barrier should be paired with one on the - * waiting side. - */ - smp_mb(); - return waitqueue_active(wq); -} - -extern void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait); -extern void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait); -extern void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait); - -static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new) -{ - list_add(&new->task_list, &head->task_list); -} - -/* - * Used for wake-one threads: - */ -static inline void -__add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait) -{ - wait->flags |= WQ_FLAG_EXCLUSIVE; - __add_wait_queue(q, wait); -} - -static inline void __add_wait_queue_tail(wait_queue_head_t *head, - wait_queue_t *new) -{ - list_add_tail(&new->task_list, &head->task_list); -} - -static inline void -__add_wait_queue_tail_exclusive(wait_queue_head_t *q, wait_queue_t *wait) -{ - wait->flags |= WQ_FLAG_EXCLUSIVE; - __add_wait_queue_tail(q, wait); -} - -static inline void -__remove_wait_queue(wait_queue_head_t *head, wait_queue_t *old) -{ - list_del(&old->task_list); -} - -typedef int wait_bit_action_f(struct wait_bit_key *, int mode); -void __wake_up(wait_queue_head_t *q, unsigned int mode, int nr, void *key); -void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, void *key); -void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode, int nr, void *key); -void __wake_up_locked(wait_queue_head_t *q, unsigned int mode, int nr); -void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr); -void __wake_up_bit(wait_queue_head_t *, void *, int); -int __wait_on_bit(wait_queue_head_t *, struct wait_bit_queue *, wait_bit_action_f *, unsigned); -int __wait_on_bit_lock(wait_queue_head_t *, struct wait_bit_queue *, wait_bit_action_f *, unsigned); -void wake_up_bit(void *, int); -void wake_up_atomic_t(atomic_t *); -int out_of_line_wait_on_bit(void *, int, wait_bit_action_f *, unsigned); -int out_of_line_wait_on_bit_timeout(void *, int, wait_bit_action_f *, unsigned, unsigned long); -int out_of_line_wait_on_bit_lock(void *, int, wait_bit_action_f *, unsigned); -int out_of_line_wait_on_atomic_t(atomic_t *, int (*)(atomic_t *), unsigned); -wait_queue_head_t *bit_waitqueue(void *, int); - -#define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL) -#define wake_up_nr(x, nr) __wake_up(x, TASK_NORMAL, nr, NULL) -#define wake_up_all(x) __wake_up(x, TASK_NORMAL, 0, NULL) -#define wake_up_locked(x) __wake_up_locked((x), TASK_NORMAL, 1) -#define wake_up_all_locked(x) __wake_up_locked((x), TASK_NORMAL, 0) - -#define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL) -#define wake_up_interruptible_nr(x, nr) __wake_up(x, TASK_INTERRUPTIBLE, nr, NULL) -#define wake_up_interruptible_all(x) __wake_up(x, TASK_INTERRUPTIBLE, 0, NULL) -#define wake_up_interruptible_sync(x) __wake_up_sync((x), TASK_INTERRUPTIBLE, 1) - -/* - * Wakeup macros to be used to report events to the targets. - */ -#define wake_up_poll(x, m) \ - __wake_up(x, TASK_NORMAL, 1, (void *) (m)) -#define wake_up_locked_poll(x, m) \ - __wake_up_locked_key((x), TASK_NORMAL, (void *) (m)) -#define wake_up_interruptible_poll(x, m) \ - __wake_up(x, TASK_INTERRUPTIBLE, 1, (void *) (m)) -#define wake_up_interruptible_sync_poll(x, m) \ - __wake_up_sync_key((x), TASK_INTERRUPTIBLE, 1, (void *) (m)) - -#define ___wait_cond_timeout(condition) \ -({ \ - bool __cond = (condition); \ - if (__cond && !__ret) \ - __ret = 1; \ - __cond || !__ret; \ -}) - -#define ___wait_is_interruptible(state) \ - (!__builtin_constant_p(state) || \ - state == TASK_INTERRUPTIBLE || state == TASK_KILLABLE) \ - -extern void init_wait_entry(wait_queue_t *__wait, int flags); - -/* - * The below macro ___wait_event() has an explicit shadow of the __ret - * variable when used from the wait_event_*() macros. - * - * This is so that both can use the ___wait_cond_timeout() construct - * to wrap the condition. - * - * The type inconsistency of the wait_event_*() __ret variable is also - * on purpose; we use long where we can return timeout values and int - * otherwise. - */ - -#define ___wait_event(wq, condition, state, exclusive, ret, cmd) \ -({ \ - __label__ __out; \ - wait_queue_t __wait; \ - long __ret = ret; /* explicit shadow */ \ - \ - init_wait_entry(&__wait, exclusive ? WQ_FLAG_EXCLUSIVE : 0); \ - for (;;) { \ - long __int = prepare_to_wait_event(&wq, &__wait, state);\ - \ - if (condition) \ - break; \ - \ - if (___wait_is_interruptible(state) && __int) { \ - __ret = __int; \ - goto __out; \ - } \ - \ - cmd; \ - } \ - finish_wait(&wq, &__wait); \ -__out: __ret; \ -}) - -#define __wait_event(wq, condition) \ - (void)___wait_event(wq, condition, TASK_UNINTERRUPTIBLE, 0, 0, \ - schedule()) - -/** - * wait_event - sleep until a condition gets true - * @wq: the waitqueue to wait on - * @condition: a C expression for the event to wait for - * - * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the - * @condition evaluates to true. The @condition is checked each time - * the waitqueue @wq is woken up. - * - * wake_up() has to be called after changing any variable that could - * change the result of the wait condition. - */ -#define wait_event(wq, condition) \ -do { \ - might_sleep(); \ - if (condition) \ - break; \ - __wait_event(wq, condition); \ -} while (0) - -#define __io_wait_event(wq, condition) \ - (void)___wait_event(wq, condition, TASK_UNINTERRUPTIBLE, 0, 0, \ - io_schedule()) - -/* - * io_wait_event() -- like wait_event() but with io_schedule() - */ -#define io_wait_event(wq, condition) \ -do { \ - might_sleep(); \ - if (condition) \ - break; \ - __io_wait_event(wq, condition); \ -} while (0) - -#define __wait_event_freezable(wq, condition) \ - ___wait_event(wq, condition, TASK_INTERRUPTIBLE, 0, 0, \ - schedule(); try_to_freeze()) - -/** - * wait_event_freezable - sleep (or freeze) until a condition gets true - * @wq: the waitqueue to wait on - * @condition: a C expression for the event to wait for - * - * The process is put to sleep (TASK_INTERRUPTIBLE -- so as not to contribute - * to system load) until the @condition evaluates to true. The - * @condition is checked each time the waitqueue @wq is woken up. - * - * wake_up() has to be called after changing any variable that could - * change the result of the wait condition. - */ -#define wait_event_freezable(wq, condition) \ -({ \ - int __ret = 0; \ - might_sleep(); \ - if (!(condition)) \ - __ret = __wait_event_freezable(wq, condition); \ - __ret; \ -}) - -#define __wait_event_timeout(wq, condition, timeout) \ - ___wait_event(wq, ___wait_cond_timeout(condition), \ - TASK_UNINTERRUPTIBLE, 0, timeout, \ - __ret = schedule_timeout(__ret)) - -/** - * wait_event_timeout - sleep until a condition gets true or a timeout elapses - * @wq: the waitqueue to wait on - * @condition: a C expression for the event to wait for - * @timeout: timeout, in jiffies - * - * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the - * @condition evaluates to true. The @condition is checked each time - * the waitqueue @wq is woken up. - * - * wake_up() has to be called after changing any variable that could - * change the result of the wait condition. - * - * Returns: - * 0 if the @condition evaluated to %false after the @timeout elapsed, - * 1 if the @condition evaluated to %true after the @timeout elapsed, - * or the remaining jiffies (at least 1) if the @condition evaluated - * to %true before the @timeout elapsed. - */ -#define wait_event_timeout(wq, condition, timeout) \ -({ \ - long __ret = timeout; \ - might_sleep(); \ - if (!___wait_cond_timeout(condition)) \ - __ret = __wait_event_timeout(wq, condition, timeout); \ - __ret; \ -}) - -#define __wait_event_freezable_timeout(wq, condition, timeout) \ - ___wait_event(wq, ___wait_cond_timeout(condition), \ - TASK_INTERRUPTIBLE, 0, timeout, \ - __ret = schedule_timeout(__ret); try_to_freeze()) - -/* - * like wait_event_timeout() -- except it uses TASK_INTERRUPTIBLE to avoid - * increasing load and is freezable. - */ -#define wait_event_freezable_timeout(wq, condition, timeout) \ -({ \ - long __ret = timeout; \ - might_sleep(); \ - if (!___wait_cond_timeout(condition)) \ - __ret = __wait_event_freezable_timeout(wq, condition, timeout); \ - __ret; \ -}) - -#define __wait_event_exclusive_cmd(wq, condition, cmd1, cmd2) \ - (void)___wait_event(wq, condition, TASK_UNINTERRUPTIBLE, 1, 0, \ - cmd1; schedule(); cmd2) -/* - * Just like wait_event_cmd(), except it sets exclusive flag - */ -#define wait_event_exclusive_cmd(wq, condition, cmd1, cmd2) \ -do { \ - if (condition) \ - break; \ - __wait_event_exclusive_cmd(wq, condition, cmd1, cmd2); \ -} while (0) - -#define __wait_event_cmd(wq, condition, cmd1, cmd2) \ - (void)___wait_event(wq, condition, TASK_UNINTERRUPTIBLE, 0, 0, \ - cmd1; schedule(); cmd2) - -/** - * wait_event_cmd - sleep until a condition gets true - * @wq: the waitqueue to wait on - * @condition: a C expression for the event to wait for - * @cmd1: the command will be executed before sleep - * @cmd2: the command will be executed after sleep - * - * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the - * @condition evaluates to true. The @condition is checked each time - * the waitqueue @wq is woken up. - * - * wake_up() has to be called after changing any variable that could - * change the result of the wait condition. - */ -#define wait_event_cmd(wq, condition, cmd1, cmd2) \ -do { \ - if (condition) \ - break; \ - __wait_event_cmd(wq, condition, cmd1, cmd2); \ -} while (0) - -#define __wait_event_interruptible(wq, condition) \ - ___wait_event(wq, condition, TASK_INTERRUPTIBLE, 0, 0, \ - schedule()) - -/** - * wait_event_interruptible - sleep until a condition gets true - * @wq: the waitqueue to wait on - * @condition: a C expression for the event to wait for - * - * The process is put to sleep (TASK_INTERRUPTIBLE) until the - * @condition evaluates to true or a signal is received. - * The @condition is checked each time the waitqueue @wq is woken up. - * - * wake_up() has to be called after changing any variable that could - * change the result of the wait condition. - * - * The function will return -ERESTARTSYS if it was interrupted by a - * signal and 0 if @condition evaluated to true. - */ -#define wait_event_interruptible(wq, condition) \ -({ \ - int __ret = 0; \ - might_sleep(); \ - if (!(condition)) \ - __ret = __wait_event_interruptible(wq, condition); \ - __ret; \ -}) - -#define __wait_event_interruptible_timeout(wq, condition, timeout) \ - ___wait_event(wq, ___wait_cond_timeout(condition), \ - TASK_INTERRUPTIBLE, 0, timeout, \ - __ret = schedule_timeout(__ret)) - -/** - * wait_event_interruptible_timeout - sleep until a condition gets true or a timeout elapses - * @wq: the waitqueue to wait on - * @condition: a C expression for the event to wait for - * @timeout: timeout, in jiffies - * - * The process is put to sleep (TASK_INTERRUPTIBLE) until the - * @condition evaluates to true or a signal is received. - * The @condition is checked each time the waitqueue @wq is woken up. - * - * wake_up() has to be called after changing any variable that could - * change the result of the wait condition. - * - * Returns: - * 0 if the @condition evaluated to %false after the @timeout elapsed, - * 1 if the @condition evaluated to %true after the @timeout elapsed, - * the remaining jiffies (at least 1) if the @condition evaluated - * to %true before the @timeout elapsed, or -%ERESTARTSYS if it was - * interrupted by a signal. - */ -#define wait_event_interruptible_timeout(wq, condition, timeout) \ -({ \ - long __ret = timeout; \ - might_sleep(); \ - if (!___wait_cond_timeout(condition)) \ - __ret = __wait_event_interruptible_timeout(wq, \ - condition, timeout); \ - __ret; \ -}) - -#define __wait_event_hrtimeout(wq, condition, timeout, state) \ -({ \ - int __ret = 0; \ - struct hrtimer_sleeper __t; \ - \ - hrtimer_init_on_stack(&__t.timer, CLOCK_MONOTONIC, \ - HRTIMER_MODE_REL); \ - hrtimer_init_sleeper(&__t, current); \ - if ((timeout).tv64 != KTIME_MAX) \ - hrtimer_start_range_ns(&__t.timer, timeout, \ - current->timer_slack_ns, \ - HRTIMER_MODE_REL); \ - \ - __ret = ___wait_event(wq, condition, state, 0, 0, \ - if (!__t.task) { \ - __ret = -ETIME; \ - break; \ - } \ - schedule()); \ - \ - hrtimer_cancel(&__t.timer); \ - destroy_hrtimer_on_stack(&__t.timer); \ - __ret; \ -}) - -/** - * wait_event_hrtimeout - sleep until a condition gets true or a timeout elapses - * @wq: the waitqueue to wait on - * @condition: a C expression for the event to wait for - * @timeout: timeout, as a ktime_t - * - * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the - * @condition evaluates to true or a signal is received. - * The @condition is checked each time the waitqueue @wq is woken up. - * - * wake_up() has to be called after changing any variable that could - * change the result of the wait condition. - * - * The function returns 0 if @condition became true, or -ETIME if the timeout - * elapsed. - */ -#define wait_event_hrtimeout(wq, condition, timeout) \ -({ \ - int __ret = 0; \ - might_sleep(); \ - if (!(condition)) \ - __ret = __wait_event_hrtimeout(wq, condition, timeout, \ - TASK_UNINTERRUPTIBLE); \ - __ret; \ -}) - -/** - * wait_event_interruptible_hrtimeout - sleep until a condition gets true or a timeout elapses - * @wq: the waitqueue to wait on - * @condition: a C expression for the event to wait for - * @timeout: timeout, as a ktime_t - * - * The process is put to sleep (TASK_INTERRUPTIBLE) until the - * @condition evaluates to true or a signal is received. - * The @condition is checked each time the waitqueue @wq is woken up. - * - * wake_up() has to be called after changing any variable that could - * change the result of the wait condition. - * - * The function returns 0 if @condition became true, -ERESTARTSYS if it was - * interrupted by a signal, or -ETIME if the timeout elapsed. - */ -#define wait_event_interruptible_hrtimeout(wq, condition, timeout) \ -({ \ - long __ret = 0; \ - might_sleep(); \ - if (!(condition)) \ - __ret = __wait_event_hrtimeout(wq, condition, timeout, \ - TASK_INTERRUPTIBLE); \ - __ret; \ -}) - -#define __wait_event_interruptible_exclusive(wq, condition) \ - ___wait_event(wq, condition, TASK_INTERRUPTIBLE, 1, 0, \ - schedule()) - -#define wait_event_interruptible_exclusive(wq, condition) \ -({ \ - int __ret = 0; \ - might_sleep(); \ - if (!(condition)) \ - __ret = __wait_event_interruptible_exclusive(wq, condition);\ - __ret; \ -}) - -#define __wait_event_killable_exclusive(wq, condition) \ - ___wait_event(wq, condition, TASK_KILLABLE, 1, 0, \ - schedule()) - -#define wait_event_killable_exclusive(wq, condition) \ -({ \ - int __ret = 0; \ - might_sleep(); \ - if (!(condition)) \ - __ret = __wait_event_killable_exclusive(wq, condition); \ - __ret; \ -}) - - -#define __wait_event_freezable_exclusive(wq, condition) \ - ___wait_event(wq, condition, TASK_INTERRUPTIBLE, 1, 0, \ - schedule(); try_to_freeze()) - -#define wait_event_freezable_exclusive(wq, condition) \ -({ \ - int __ret = 0; \ - might_sleep(); \ - if (!(condition)) \ - __ret = __wait_event_freezable_exclusive(wq, condition);\ - __ret; \ -}) - - -#define __wait_event_interruptible_locked(wq, condition, exclusive, irq) \ -({ \ - int __ret = 0; \ - DEFINE_WAIT(__wait); \ - if (exclusive) \ - __wait.flags |= WQ_FLAG_EXCLUSIVE; \ - do { \ - if (likely(list_empty(&__wait.task_list))) \ - __add_wait_queue_tail(&(wq), &__wait); \ - set_current_state(TASK_INTERRUPTIBLE); \ - if (signal_pending(current)) { \ - __ret = -ERESTARTSYS; \ - break; \ - } \ - if (irq) \ - spin_unlock_irq(&(wq).lock); \ - else \ - spin_unlock(&(wq).lock); \ - schedule(); \ - if (irq) \ - spin_lock_irq(&(wq).lock); \ - else \ - spin_lock(&(wq).lock); \ - } while (!(condition)); \ - __remove_wait_queue(&(wq), &__wait); \ - __set_current_state(TASK_RUNNING); \ - __ret; \ -}) - - -/** - * wait_event_interruptible_locked - sleep until a condition gets true - * @wq: the waitqueue to wait on - * @condition: a C expression for the event to wait for - * - * The process is put to sleep (TASK_INTERRUPTIBLE) until the - * @condition evaluates to true or a signal is received. - * The @condition is checked each time the waitqueue @wq is woken up. - * - * It must be called with wq.lock being held. This spinlock is - * unlocked while sleeping but @condition testing is done while lock - * is held and when this macro exits the lock is held. - * - * The lock is locked/unlocked using spin_lock()/spin_unlock() - * functions which must match the way they are locked/unlocked outside - * of this macro. - * - * wake_up_locked() has to be called after changing any variable that could - * change the result of the wait condition. - * - * The function will return -ERESTARTSYS if it was interrupted by a - * signal and 0 if @condition evaluated to true. - */ -#define wait_event_interruptible_locked(wq, condition) \ - ((condition) \ - ? 0 : __wait_event_interruptible_locked(wq, condition, 0, 0)) - -/** - * wait_event_interruptible_locked_irq - sleep until a condition gets true - * @wq: the waitqueue to wait on - * @condition: a C expression for the event to wait for - * - * The process is put to sleep (TASK_INTERRUPTIBLE) until the - * @condition evaluates to true or a signal is received. - * The @condition is checked each time the waitqueue @wq is woken up. - * - * It must be called with wq.lock being held. This spinlock is - * unlocked while sleeping but @condition testing is done while lock - * is held and when this macro exits the lock is held. - * - * The lock is locked/unlocked using spin_lock_irq()/spin_unlock_irq() - * functions which must match the way they are locked/unlocked outside - * of this macro. - * - * wake_up_locked() has to be called after changing any variable that could - * change the result of the wait condition. - * - * The function will return -ERESTARTSYS if it was interrupted by a - * signal and 0 if @condition evaluated to true. - */ -#define wait_event_interruptible_locked_irq(wq, condition) \ - ((condition) \ - ? 0 : __wait_event_interruptible_locked(wq, condition, 0, 1)) - -/** - * wait_event_interruptible_exclusive_locked - sleep exclusively until a condition gets true - * @wq: the waitqueue to wait on - * @condition: a C expression for the event to wait for - * - * The process is put to sleep (TASK_INTERRUPTIBLE) until the - * @condition evaluates to true or a signal is received. - * The @condition is checked each time the waitqueue @wq is woken up. - * - * It must be called with wq.lock being held. This spinlock is - * unlocked while sleeping but @condition testing is done while lock - * is held and when this macro exits the lock is held. - * - * The lock is locked/unlocked using spin_lock()/spin_unlock() - * functions which must match the way they are locked/unlocked outside - * of this macro. - * - * The process is put on the wait queue with an WQ_FLAG_EXCLUSIVE flag - * set thus when other process waits process on the list if this - * process is awaken further processes are not considered. - * - * wake_up_locked() has to be called after changing any variable that could - * change the result of the wait condition. - * - * The function will return -ERESTARTSYS if it was interrupted by a - * signal and 0 if @condition evaluated to true. - */ -#define wait_event_interruptible_exclusive_locked(wq, condition) \ - ((condition) \ - ? 0 : __wait_event_interruptible_locked(wq, condition, 1, 0)) - -/** - * wait_event_interruptible_exclusive_locked_irq - sleep until a condition gets true - * @wq: the waitqueue to wait on - * @condition: a C expression for the event to wait for - * - * The process is put to sleep (TASK_INTERRUPTIBLE) until the - * @condition evaluates to true or a signal is received. - * The @condition is checked each time the waitqueue @wq is woken up. - * - * It must be called with wq.lock being held. This spinlock is - * unlocked while sleeping but @condition testing is done while lock - * is held and when this macro exits the lock is held. - * - * The lock is locked/unlocked using spin_lock_irq()/spin_unlock_irq() - * functions which must match the way they are locked/unlocked outside - * of this macro. - * - * The process is put on the wait queue with an WQ_FLAG_EXCLUSIVE flag - * set thus when other process waits process on the list if this - * process is awaken further processes are not considered. - * - * wake_up_locked() has to be called after changing any variable that could - * change the result of the wait condition. - * - * The function will return -ERESTARTSYS if it was interrupted by a - * signal and 0 if @condition evaluated to true. - */ -#define wait_event_interruptible_exclusive_locked_irq(wq, condition) \ - ((condition) \ - ? 0 : __wait_event_interruptible_locked(wq, condition, 1, 1)) - - -#define __wait_event_killable(wq, condition) \ - ___wait_event(wq, condition, TASK_KILLABLE, 0, 0, schedule()) - -/** - * wait_event_killable - sleep until a condition gets true - * @wq: the waitqueue to wait on - * @condition: a C expression for the event to wait for - * - * The process is put to sleep (TASK_KILLABLE) until the - * @condition evaluates to true or a signal is received. - * The @condition is checked each time the waitqueue @wq is woken up. - * - * wake_up() has to be called after changing any variable that could - * change the result of the wait condition. - * - * The function will return -ERESTARTSYS if it was interrupted by a - * signal and 0 if @condition evaluated to true. - */ -#define wait_event_killable(wq, condition) \ -({ \ - int __ret = 0; \ - might_sleep(); \ - if (!(condition)) \ - __ret = __wait_event_killable(wq, condition); \ - __ret; \ -}) - - -#define __wait_event_lock_irq(wq, condition, lock, cmd) \ - (void)___wait_event(wq, condition, TASK_UNINTERRUPTIBLE, 0, 0, \ - spin_unlock_irq(&lock); \ - cmd; \ - schedule(); \ - spin_lock_irq(&lock)) - -/** - * wait_event_lock_irq_cmd - sleep until a condition gets true. The - * condition is checked under the lock. This - * is expected to be called with the lock - * taken. - * @wq: the waitqueue to wait on - * @condition: a C expression for the event to wait for - * @lock: a locked spinlock_t, which will be released before cmd - * and schedule() and reacquired afterwards. - * @cmd: a command which is invoked outside the critical section before - * sleep - * - * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the - * @condition evaluates to true. The @condition is checked each time - * the waitqueue @wq is woken up. - * - * wake_up() has to be called after changing any variable that could - * change the result of the wait condition. - * - * This is supposed to be called while holding the lock. The lock is - * dropped before invoking the cmd and going to sleep and is reacquired - * afterwards. - */ -#define wait_event_lock_irq_cmd(wq, condition, lock, cmd) \ -do { \ - if (condition) \ - break; \ - __wait_event_lock_irq(wq, condition, lock, cmd); \ -} while (0) - -/** - * wait_event_lock_irq - sleep until a condition gets true. The - * condition is checked under the lock. This - * is expected to be called with the lock - * taken. - * @wq: the waitqueue to wait on - * @condition: a C expression for the event to wait for - * @lock: a locked spinlock_t, which will be released before schedule() - * and reacquired afterwards. - * - * The process is put to sleep (TASK_UNINTERRUPTIBLE) until the - * @condition evaluates to true. The @condition is checked each time - * the waitqueue @wq is woken up. - * - * wake_up() has to be called after changing any variable that could - * change the result of the wait condition. - * - * This is supposed to be called while holding the lock. The lock is - * dropped before going to sleep and is reacquired afterwards. - */ -#define wait_event_lock_irq(wq, condition, lock) \ -do { \ - if (condition) \ - break; \ - __wait_event_lock_irq(wq, condition, lock, ); \ -} while (0) - - -#define __wait_event_interruptible_lock_irq(wq, condition, lock, cmd) \ - ___wait_event(wq, condition, TASK_INTERRUPTIBLE, 0, 0, \ - spin_unlock_irq(&lock); \ - cmd; \ - schedule(); \ - spin_lock_irq(&lock)) - -/** - * wait_event_interruptible_lock_irq_cmd - sleep until a condition gets true. - * The condition is checked under the lock. This is expected to - * be called with the lock taken. - * @wq: the waitqueue to wait on - * @condition: a C expression for the event to wait for - * @lock: a locked spinlock_t, which will be released before cmd and - * schedule() and reacquired afterwards. - * @cmd: a command which is invoked outside the critical section before - * sleep - * - * The process is put to sleep (TASK_INTERRUPTIBLE) until the - * @condition evaluates to true or a signal is received. The @condition is - * checked each time the waitqueue @wq is woken up. - * - * wake_up() has to be called after changing any variable that could - * change the result of the wait condition. - * - * This is supposed to be called while holding the lock. The lock is - * dropped before invoking the cmd and going to sleep and is reacquired - * afterwards. - * - * The macro will return -ERESTARTSYS if it was interrupted by a signal - * and 0 if @condition evaluated to true. - */ -#define wait_event_interruptible_lock_irq_cmd(wq, condition, lock, cmd) \ -({ \ - int __ret = 0; \ - if (!(condition)) \ - __ret = __wait_event_interruptible_lock_irq(wq, \ - condition, lock, cmd); \ - __ret; \ -}) - -/** - * wait_event_interruptible_lock_irq - sleep until a condition gets true. - * The condition is checked under the lock. This is expected - * to be called with the lock taken. - * @wq: the waitqueue to wait on - * @condition: a C expression for the event to wait for - * @lock: a locked spinlock_t, which will be released before schedule() - * and reacquired afterwards. - * - * The process is put to sleep (TASK_INTERRUPTIBLE) until the - * @condition evaluates to true or signal is received. The @condition is - * checked each time the waitqueue @wq is woken up. - * - * wake_up() has to be called after changing any variable that could - * change the result of the wait condition. - * - * This is supposed to be called while holding the lock. The lock is - * dropped before going to sleep and is reacquired afterwards. - * - * The macro will return -ERESTARTSYS if it was interrupted by a signal - * and 0 if @condition evaluated to true. - */ -#define wait_event_interruptible_lock_irq(wq, condition, lock) \ -({ \ - int __ret = 0; \ - if (!(condition)) \ - __ret = __wait_event_interruptible_lock_irq(wq, \ - condition, lock,); \ - __ret; \ -}) - -#define __wait_event_interruptible_lock_irq_timeout(wq, condition, \ - lock, timeout) \ - ___wait_event(wq, ___wait_cond_timeout(condition), \ - TASK_INTERRUPTIBLE, 0, timeout, \ - spin_unlock_irq(&lock); \ - __ret = schedule_timeout(__ret); \ - spin_lock_irq(&lock)); - -/** - * wait_event_interruptible_lock_irq_timeout - sleep until a condition gets - * true or a timeout elapses. The condition is checked under - * the lock. This is expected to be called with the lock taken. - * @wq: the waitqueue to wait on - * @condition: a C expression for the event to wait for - * @lock: a locked spinlock_t, which will be released before schedule() - * and reacquired afterwards. - * @timeout: timeout, in jiffies - * - * The process is put to sleep (TASK_INTERRUPTIBLE) until the - * @condition evaluates to true or signal is received. The @condition is - * checked each time the waitqueue @wq is woken up. - * - * wake_up() has to be called after changing any variable that could - * change the result of the wait condition. - * - * This is supposed to be called while holding the lock. The lock is - * dropped before going to sleep and is reacquired afterwards. - * - * The function returns 0 if the @timeout elapsed, -ERESTARTSYS if it - * was interrupted by a signal, and the remaining jiffies otherwise - * if the condition evaluated to true before the timeout elapsed. - */ -#define wait_event_interruptible_lock_irq_timeout(wq, condition, lock, \ - timeout) \ -({ \ - long __ret = timeout; \ - if (!___wait_cond_timeout(condition)) \ - __ret = __wait_event_interruptible_lock_irq_timeout( \ - wq, condition, lock, timeout); \ - __ret; \ -}) - -/* - * Waitqueues which are removed from the waitqueue_head at wakeup time - */ -void prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state); -void prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state); -long prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state); -void finish_wait(wait_queue_head_t *q, wait_queue_t *wait); -long wait_woken(wait_queue_t *wait, unsigned mode, long timeout); -int woken_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key); -int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key); -int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *key); - -#define DEFINE_WAIT_FUNC(name, function) \ - wait_queue_t name = { \ - .private = current, \ - .func = function, \ - .task_list = LIST_HEAD_INIT((name).task_list), \ - } - -#define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, autoremove_wake_function) - -#define DEFINE_WAIT_BIT(name, word, bit) \ - struct wait_bit_queue name = { \ - .key = __WAIT_BIT_KEY_INITIALIZER(word, bit), \ - .wait = { \ - .private = current, \ - .func = wake_bit_function, \ - .task_list = \ - LIST_HEAD_INIT((name).wait.task_list), \ - }, \ - } - -#define init_wait(wait) \ - do { \ - (wait)->private = current; \ - (wait)->func = autoremove_wake_function; \ - INIT_LIST_HEAD(&(wait)->task_list); \ - (wait)->flags = 0; \ - } while (0) - - -extern int bit_wait(struct wait_bit_key *, int); -extern int bit_wait_io(struct wait_bit_key *, int); -extern int bit_wait_timeout(struct wait_bit_key *, int); -extern int bit_wait_io_timeout(struct wait_bit_key *, int); - -/** - * wait_on_bit - wait for a bit to be cleared - * @word: the word being waited on, a kernel virtual address - * @bit: the bit of the word being waited on - * @mode: the task state to sleep in - * - * There is a standard hashed waitqueue table for generic use. This - * is the part of the hashtable's accessor API that waits on a bit. - * For instance, if one were to have waiters on a bitflag, one would - * call wait_on_bit() in threads waiting for the bit to clear. - * One uses wait_on_bit() where one is waiting for the bit to clear, - * but has no intention of setting it. - * Returned value will be zero if the bit was cleared, or non-zero - * if the process received a signal and the mode permitted wakeup - * on that signal. - */ -static inline int -wait_on_bit(unsigned long *word, int bit, unsigned mode) -{ - might_sleep(); - if (!test_bit(bit, word)) - return 0; - return out_of_line_wait_on_bit(word, bit, - bit_wait, - mode); -} - -/** - * wait_on_bit_io - wait for a bit to be cleared - * @word: the word being waited on, a kernel virtual address - * @bit: the bit of the word being waited on - * @mode: the task state to sleep in - * - * Use the standard hashed waitqueue table to wait for a bit - * to be cleared. This is similar to wait_on_bit(), but calls - * io_schedule() instead of schedule() for the actual waiting. - * - * Returned value will be zero if the bit was cleared, or non-zero - * if the process received a signal and the mode permitted wakeup - * on that signal. - */ -static inline int -wait_on_bit_io(unsigned long *word, int bit, unsigned mode) -{ - might_sleep(); - if (!test_bit(bit, word)) - return 0; - return out_of_line_wait_on_bit(word, bit, - bit_wait_io, - mode); -} - -/** - * wait_on_bit_timeout - wait for a bit to be cleared or a timeout elapses - * @word: the word being waited on, a kernel virtual address - * @bit: the bit of the word being waited on - * @mode: the task state to sleep in - * @timeout: timeout, in jiffies - * - * Use the standard hashed waitqueue table to wait for a bit - * to be cleared. This is similar to wait_on_bit(), except also takes a - * timeout parameter. - * - * Returned value will be zero if the bit was cleared before the - * @timeout elapsed, or non-zero if the @timeout elapsed or process - * received a signal and the mode permitted wakeup on that signal. - */ -static inline int -wait_on_bit_timeout(unsigned long *word, int bit, unsigned mode, - unsigned long timeout) -{ - might_sleep(); - if (!test_bit(bit, word)) - return 0; - return out_of_line_wait_on_bit_timeout(word, bit, - bit_wait_timeout, - mode, timeout); -} - -/** - * wait_on_bit_action - wait for a bit to be cleared - * @word: the word being waited on, a kernel virtual address - * @bit: the bit of the word being waited on - * @action: the function used to sleep, which may take special actions - * @mode: the task state to sleep in - * - * Use the standard hashed waitqueue table to wait for a bit - * to be cleared, and allow the waiting action to be specified. - * This is like wait_on_bit() but allows fine control of how the waiting - * is done. - * - * Returned value will be zero if the bit was cleared, or non-zero - * if the process received a signal and the mode permitted wakeup - * on that signal. - */ -static inline int -wait_on_bit_action(unsigned long *word, int bit, wait_bit_action_f *action, - unsigned mode) -{ - might_sleep(); - if (!test_bit(bit, word)) - return 0; - return out_of_line_wait_on_bit(word, bit, action, mode); -} - -/** - * wait_on_bit_lock - wait for a bit to be cleared, when wanting to set it - * @word: the word being waited on, a kernel virtual address - * @bit: the bit of the word being waited on - * @mode: the task state to sleep in - * - * There is a standard hashed waitqueue table for generic use. This - * is the part of the hashtable's accessor API that waits on a bit - * when one intends to set it, for instance, trying to lock bitflags. - * For instance, if one were to have waiters trying to set bitflag - * and waiting for it to clear before setting it, one would call - * wait_on_bit() in threads waiting to be able to set the bit. - * One uses wait_on_bit_lock() where one is waiting for the bit to - * clear with the intention of setting it, and when done, clearing it. - * - * Returns zero if the bit was (eventually) found to be clear and was - * set. Returns non-zero if a signal was delivered to the process and - * the @mode allows that signal to wake the process. - */ -static inline int -wait_on_bit_lock(unsigned long *word, int bit, unsigned mode) -{ - might_sleep(); - if (!test_and_set_bit(bit, word)) - return 0; - return out_of_line_wait_on_bit_lock(word, bit, bit_wait, mode); -} - -/** - * wait_on_bit_lock_io - wait for a bit to be cleared, when wanting to set it - * @word: the word being waited on, a kernel virtual address - * @bit: the bit of the word being waited on - * @mode: the task state to sleep in - * - * Use the standard hashed waitqueue table to wait for a bit - * to be cleared and then to atomically set it. This is similar - * to wait_on_bit(), but calls io_schedule() instead of schedule() - * for the actual waiting. - * - * Returns zero if the bit was (eventually) found to be clear and was - * set. Returns non-zero if a signal was delivered to the process and - * the @mode allows that signal to wake the process. - */ -static inline int -wait_on_bit_lock_io(unsigned long *word, int bit, unsigned mode) -{ - might_sleep(); - if (!test_and_set_bit(bit, word)) - return 0; - return out_of_line_wait_on_bit_lock(word, bit, bit_wait_io, mode); -} - -/** - * wait_on_bit_lock_action - wait for a bit to be cleared, when wanting to set it - * @word: the word being waited on, a kernel virtual address - * @bit: the bit of the word being waited on - * @action: the function used to sleep, which may take special actions - * @mode: the task state to sleep in - * - * Use the standard hashed waitqueue table to wait for a bit - * to be cleared and then to set it, and allow the waiting action - * to be specified. - * This is like wait_on_bit() but allows fine control of how the waiting - * is done. - * - * Returns zero if the bit was (eventually) found to be clear and was - * set. Returns non-zero if a signal was delivered to the process and - * the @mode allows that signal to wake the process. - */ -static inline int -wait_on_bit_lock_action(unsigned long *word, int bit, wait_bit_action_f *action, - unsigned mode) -{ - might_sleep(); - if (!test_and_set_bit(bit, word)) - return 0; - return out_of_line_wait_on_bit_lock(word, bit, action, mode); -} - -/** - * wait_on_atomic_t - Wait for an atomic_t to become 0 - * @val: The atomic value being waited on, a kernel virtual address - * @action: the function used to sleep, which may take special actions - * @mode: the task state to sleep in - * - * Wait for an atomic_t to become 0. We abuse the bit-wait waitqueue table for - * the purpose of getting a waitqueue, but we set the key to a bit number - * outside of the target 'word'. - */ -static inline -int wait_on_atomic_t(atomic_t *val, int (*action)(atomic_t *), unsigned mode) -{ - might_sleep(); - if (atomic_read(val) == 0) - return 0; - return out_of_line_wait_on_atomic_t(val, action, mode); -} - -#endif /* _LINUX_WAIT_H */ diff --git a/src/linux/include/linux/win_minmax.h b/src/linux/include/linux/win_minmax.h deleted file mode 100644 index 5656960..0000000 --- a/src/linux/include/linux/win_minmax.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * lib/minmax.c: windowed min/max tracker by Kathleen Nichols. - * - */ -#ifndef MINMAX_H -#define MINMAX_H - -#include - -/* A single data point for our parameterized min-max tracker */ -struct minmax_sample { - u32 t; /* time measurement was taken */ - u32 v; /* value measured */ -}; - -/* State for the parameterized min-max tracker */ -struct minmax { - struct minmax_sample s[3]; -}; - -static inline u32 minmax_get(const struct minmax *m) -{ - return m->s[0].v; -} - -static inline u32 minmax_reset(struct minmax *m, u32 t, u32 meas) -{ - struct minmax_sample val = { .t = t, .v = meas }; - - m->s[2] = m->s[1] = m->s[0] = val; - return m->s[0].v; -} - -u32 minmax_running_max(struct minmax *m, u32 win, u32 t, u32 meas); -u32 minmax_running_min(struct minmax *m, u32 win, u32 t, u32 meas); - -#endif diff --git a/src/linux/include/linux/wireless.h b/src/linux/include/linux/wireless.h deleted file mode 100644 index 4ea4c6e..0000000 --- a/src/linux/include/linux/wireless.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file define a set of standard wireless extensions - * - * Version : 22 16.3.07 - * - * Authors : Jean Tourrilhes - HPL - - * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. - */ -#ifndef _LINUX_WIRELESS_H -#define _LINUX_WIRELESS_H - -#include - -#ifdef CONFIG_COMPAT - -#include - -struct compat_iw_point { - compat_caddr_t pointer; - __u16 length; - __u16 flags; -}; -#endif -#ifdef CONFIG_COMPAT -struct __compat_iw_event { - __u16 len; /* Real length of this stuff */ - __u16 cmd; /* Wireless IOCTL */ - compat_caddr_t pointer; -}; -#define IW_EV_COMPAT_LCP_LEN offsetof(struct __compat_iw_event, pointer) -#define IW_EV_COMPAT_POINT_OFF offsetof(struct compat_iw_point, length) - -/* Size of the various events for compat */ -#define IW_EV_COMPAT_CHAR_LEN (IW_EV_COMPAT_LCP_LEN + IFNAMSIZ) -#define IW_EV_COMPAT_UINT_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(__u32)) -#define IW_EV_COMPAT_FREQ_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_freq)) -#define IW_EV_COMPAT_PARAM_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_param)) -#define IW_EV_COMPAT_ADDR_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct sockaddr)) -#define IW_EV_COMPAT_QUAL_LEN (IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_quality)) -#define IW_EV_COMPAT_POINT_LEN \ - (IW_EV_COMPAT_LCP_LEN + sizeof(struct compat_iw_point) - \ - IW_EV_COMPAT_POINT_OFF) -#endif -#endif /* _LINUX_WIRELESS_H */ diff --git a/src/linux/include/linux/workqueue.h b/src/linux/include/linux/workqueue.h deleted file mode 100644 index fc6e221..0000000 --- a/src/linux/include/linux/workqueue.h +++ /dev/null @@ -1,635 +0,0 @@ -/* - * workqueue.h --- work queue handling for Linux. - */ - -#ifndef _LINUX_WORKQUEUE_H -#define _LINUX_WORKQUEUE_H - -#include -#include -#include -#include -#include -#include -#include - -struct workqueue_struct; - -struct work_struct; -typedef void (*work_func_t)(struct work_struct *work); -void delayed_work_timer_fn(unsigned long __data); - -/* - * The first word is the work queue pointer and the flags rolled into - * one - */ -#define work_data_bits(work) ((unsigned long *)(&(work)->data)) - -enum { - WORK_STRUCT_PENDING_BIT = 0, /* work item is pending execution */ - WORK_STRUCT_DELAYED_BIT = 1, /* work item is delayed */ - WORK_STRUCT_PWQ_BIT = 2, /* data points to pwq */ - WORK_STRUCT_LINKED_BIT = 3, /* next work is linked to this one */ -#ifdef CONFIG_DEBUG_OBJECTS_WORK - WORK_STRUCT_STATIC_BIT = 4, /* static initializer (debugobjects) */ - WORK_STRUCT_COLOR_SHIFT = 5, /* color for workqueue flushing */ -#else - WORK_STRUCT_COLOR_SHIFT = 4, /* color for workqueue flushing */ -#endif - - WORK_STRUCT_COLOR_BITS = 4, - - WORK_STRUCT_PENDING = 1 << WORK_STRUCT_PENDING_BIT, - WORK_STRUCT_DELAYED = 1 << WORK_STRUCT_DELAYED_BIT, - WORK_STRUCT_PWQ = 1 << WORK_STRUCT_PWQ_BIT, - WORK_STRUCT_LINKED = 1 << WORK_STRUCT_LINKED_BIT, -#ifdef CONFIG_DEBUG_OBJECTS_WORK - WORK_STRUCT_STATIC = 1 << WORK_STRUCT_STATIC_BIT, -#else - WORK_STRUCT_STATIC = 0, -#endif - - /* - * The last color is no color used for works which don't - * participate in workqueue flushing. - */ - WORK_NR_COLORS = (1 << WORK_STRUCT_COLOR_BITS) - 1, - WORK_NO_COLOR = WORK_NR_COLORS, - - /* not bound to any CPU, prefer the local CPU */ - WORK_CPU_UNBOUND = NR_CPUS, - - /* - * Reserve 7 bits off of pwq pointer w/ debugobjects turned off. - * This makes pwqs aligned to 256 bytes and allows 15 workqueue - * flush colors. - */ - WORK_STRUCT_FLAG_BITS = WORK_STRUCT_COLOR_SHIFT + - WORK_STRUCT_COLOR_BITS, - - /* data contains off-queue information when !WORK_STRUCT_PWQ */ - WORK_OFFQ_FLAG_BASE = WORK_STRUCT_COLOR_SHIFT, - - __WORK_OFFQ_CANCELING = WORK_OFFQ_FLAG_BASE, - WORK_OFFQ_CANCELING = (1 << __WORK_OFFQ_CANCELING), - - /* - * When a work item is off queue, its high bits point to the last - * pool it was on. Cap at 31 bits and use the highest number to - * indicate that no pool is associated. - */ - WORK_OFFQ_FLAG_BITS = 1, - WORK_OFFQ_POOL_SHIFT = WORK_OFFQ_FLAG_BASE + WORK_OFFQ_FLAG_BITS, - WORK_OFFQ_LEFT = BITS_PER_LONG - WORK_OFFQ_POOL_SHIFT, - WORK_OFFQ_POOL_BITS = WORK_OFFQ_LEFT <= 31 ? WORK_OFFQ_LEFT : 31, - WORK_OFFQ_POOL_NONE = (1LU << WORK_OFFQ_POOL_BITS) - 1, - - /* convenience constants */ - WORK_STRUCT_FLAG_MASK = (1UL << WORK_STRUCT_FLAG_BITS) - 1, - WORK_STRUCT_WQ_DATA_MASK = ~WORK_STRUCT_FLAG_MASK, - WORK_STRUCT_NO_POOL = (unsigned long)WORK_OFFQ_POOL_NONE << WORK_OFFQ_POOL_SHIFT, - - /* bit mask for work_busy() return values */ - WORK_BUSY_PENDING = 1 << 0, - WORK_BUSY_RUNNING = 1 << 1, - - /* maximum string length for set_worker_desc() */ - WORKER_DESC_LEN = 24, -}; - -struct work_struct { - atomic_long_t data; - struct list_head entry; - work_func_t func; -#ifdef CONFIG_LOCKDEP - struct lockdep_map lockdep_map; -#endif -}; - -#define WORK_DATA_INIT() ATOMIC_LONG_INIT(WORK_STRUCT_NO_POOL) -#define WORK_DATA_STATIC_INIT() \ - ATOMIC_LONG_INIT(WORK_STRUCT_NO_POOL | WORK_STRUCT_STATIC) - -struct delayed_work { - struct work_struct work; - struct timer_list timer; - - /* target workqueue and CPU ->timer uses to queue ->work */ - struct workqueue_struct *wq; - int cpu; -}; - -/* - * A struct for workqueue attributes. This can be used to change - * attributes of an unbound workqueue. - * - * Unlike other fields, ->no_numa isn't a property of a worker_pool. It - * only modifies how apply_workqueue_attrs() select pools and thus doesn't - * participate in pool hash calculations or equality comparisons. - */ -struct workqueue_attrs { - int nice; /* nice level */ - cpumask_var_t cpumask; /* allowed CPUs */ - bool no_numa; /* disable NUMA affinity */ -}; - -static inline struct delayed_work *to_delayed_work(struct work_struct *work) -{ - return container_of(work, struct delayed_work, work); -} - -struct execute_work { - struct work_struct work; -}; - -#ifdef CONFIG_LOCKDEP -/* - * NB: because we have to copy the lockdep_map, setting _key - * here is required, otherwise it could get initialised to the - * copy of the lockdep_map! - */ -#define __WORK_INIT_LOCKDEP_MAP(n, k) \ - .lockdep_map = STATIC_LOCKDEP_MAP_INIT(n, k), -#else -#define __WORK_INIT_LOCKDEP_MAP(n, k) -#endif - -#define __WORK_INITIALIZER(n, f) { \ - .data = WORK_DATA_STATIC_INIT(), \ - .entry = { &(n).entry, &(n).entry }, \ - .func = (f), \ - __WORK_INIT_LOCKDEP_MAP(#n, &(n)) \ - } - -#define __DELAYED_WORK_INITIALIZER(n, f, tflags) { \ - .work = __WORK_INITIALIZER((n).work, (f)), \ - .timer = __TIMER_INITIALIZER(delayed_work_timer_fn, \ - 0, (unsigned long)&(n), \ - (tflags) | TIMER_IRQSAFE), \ - } - -#define DECLARE_WORK(n, f) \ - struct work_struct n = __WORK_INITIALIZER(n, f) - -#define DECLARE_DELAYED_WORK(n, f) \ - struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f, 0) - -#define DECLARE_DEFERRABLE_WORK(n, f) \ - struct delayed_work n = __DELAYED_WORK_INITIALIZER(n, f, TIMER_DEFERRABLE) - -#ifdef CONFIG_DEBUG_OBJECTS_WORK -extern void __init_work(struct work_struct *work, int onstack); -extern void destroy_work_on_stack(struct work_struct *work); -extern void destroy_delayed_work_on_stack(struct delayed_work *work); -static inline unsigned int work_static(struct work_struct *work) -{ - return *work_data_bits(work) & WORK_STRUCT_STATIC; -} -#else -static inline void __init_work(struct work_struct *work, int onstack) { } -static inline void destroy_work_on_stack(struct work_struct *work) { } -static inline void destroy_delayed_work_on_stack(struct delayed_work *work) { } -static inline unsigned int work_static(struct work_struct *work) { return 0; } -#endif - -/* - * initialize all of a work item in one go - * - * NOTE! No point in using "atomic_long_set()": using a direct - * assignment of the work data initializer allows the compiler - * to generate better code. - */ -#ifdef CONFIG_LOCKDEP -#define __INIT_WORK(_work, _func, _onstack) \ - do { \ - static struct lock_class_key __key; \ - \ - __init_work((_work), _onstack); \ - (_work)->data = (atomic_long_t) WORK_DATA_INIT(); \ - lockdep_init_map(&(_work)->lockdep_map, #_work, &__key, 0); \ - INIT_LIST_HEAD(&(_work)->entry); \ - (_work)->func = (_func); \ - } while (0) -#else -#define __INIT_WORK(_work, _func, _onstack) \ - do { \ - __init_work((_work), _onstack); \ - (_work)->data = (atomic_long_t) WORK_DATA_INIT(); \ - INIT_LIST_HEAD(&(_work)->entry); \ - (_work)->func = (_func); \ - } while (0) -#endif - -#define INIT_WORK(_work, _func) \ - __INIT_WORK((_work), (_func), 0) - -#define INIT_WORK_ONSTACK(_work, _func) \ - __INIT_WORK((_work), (_func), 1) - -#define __INIT_DELAYED_WORK(_work, _func, _tflags) \ - do { \ - INIT_WORK(&(_work)->work, (_func)); \ - __setup_timer(&(_work)->timer, delayed_work_timer_fn, \ - (unsigned long)(_work), \ - (_tflags) | TIMER_IRQSAFE); \ - } while (0) - -#define __INIT_DELAYED_WORK_ONSTACK(_work, _func, _tflags) \ - do { \ - INIT_WORK_ONSTACK(&(_work)->work, (_func)); \ - __setup_timer_on_stack(&(_work)->timer, \ - delayed_work_timer_fn, \ - (unsigned long)(_work), \ - (_tflags) | TIMER_IRQSAFE); \ - } while (0) - -#define INIT_DELAYED_WORK(_work, _func) \ - __INIT_DELAYED_WORK(_work, _func, 0) - -#define INIT_DELAYED_WORK_ONSTACK(_work, _func) \ - __INIT_DELAYED_WORK_ONSTACK(_work, _func, 0) - -#define INIT_DEFERRABLE_WORK(_work, _func) \ - __INIT_DELAYED_WORK(_work, _func, TIMER_DEFERRABLE) - -#define INIT_DEFERRABLE_WORK_ONSTACK(_work, _func) \ - __INIT_DELAYED_WORK_ONSTACK(_work, _func, TIMER_DEFERRABLE) - -/** - * work_pending - Find out whether a work item is currently pending - * @work: The work item in question - */ -#define work_pending(work) \ - test_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work)) - -/** - * delayed_work_pending - Find out whether a delayable work item is currently - * pending - * @w: The work item in question - */ -#define delayed_work_pending(w) \ - work_pending(&(w)->work) - -/* - * Workqueue flags and constants. For details, please refer to - * Documentation/workqueue.txt. - */ -enum { - WQ_UNBOUND = 1 << 1, /* not bound to any cpu */ - WQ_FREEZABLE = 1 << 2, /* freeze during suspend */ - WQ_MEM_RECLAIM = 1 << 3, /* may be used for memory reclaim */ - WQ_HIGHPRI = 1 << 4, /* high priority */ - WQ_CPU_INTENSIVE = 1 << 5, /* cpu intensive workqueue */ - WQ_SYSFS = 1 << 6, /* visible in sysfs, see wq_sysfs_register() */ - - /* - * Per-cpu workqueues are generally preferred because they tend to - * show better performance thanks to cache locality. Per-cpu - * workqueues exclude the scheduler from choosing the CPU to - * execute the worker threads, which has an unfortunate side effect - * of increasing power consumption. - * - * The scheduler considers a CPU idle if it doesn't have any task - * to execute and tries to keep idle cores idle to conserve power; - * however, for example, a per-cpu work item scheduled from an - * interrupt handler on an idle CPU will force the scheduler to - * excute the work item on that CPU breaking the idleness, which in - * turn may lead to more scheduling choices which are sub-optimal - * in terms of power consumption. - * - * Workqueues marked with WQ_POWER_EFFICIENT are per-cpu by default - * but become unbound if workqueue.power_efficient kernel param is - * specified. Per-cpu workqueues which are identified to - * contribute significantly to power-consumption are identified and - * marked with this flag and enabling the power_efficient mode - * leads to noticeable power saving at the cost of small - * performance disadvantage. - * - * http://thread.gmane.org/gmane.linux.kernel/1480396 - */ - WQ_POWER_EFFICIENT = 1 << 7, - - __WQ_DRAINING = 1 << 16, /* internal: workqueue is draining */ - __WQ_ORDERED = 1 << 17, /* internal: workqueue is ordered */ - __WQ_LEGACY = 1 << 18, /* internal: create*_workqueue() */ - - WQ_MAX_ACTIVE = 512, /* I like 512, better ideas? */ - WQ_MAX_UNBOUND_PER_CPU = 4, /* 4 * #cpus for unbound wq */ - WQ_DFL_ACTIVE = WQ_MAX_ACTIVE / 2, -}; - -/* unbound wq's aren't per-cpu, scale max_active according to #cpus */ -#define WQ_UNBOUND_MAX_ACTIVE \ - max_t(int, WQ_MAX_ACTIVE, num_possible_cpus() * WQ_MAX_UNBOUND_PER_CPU) - -/* - * System-wide workqueues which are always present. - * - * system_wq is the one used by schedule[_delayed]_work[_on](). - * Multi-CPU multi-threaded. There are users which expect relatively - * short queue flush time. Don't queue works which can run for too - * long. - * - * system_highpri_wq is similar to system_wq but for work items which - * require WQ_HIGHPRI. - * - * system_long_wq is similar to system_wq but may host long running - * works. Queue flushing might take relatively long. - * - * system_unbound_wq is unbound workqueue. Workers are not bound to - * any specific CPU, not concurrency managed, and all queued works are - * executed immediately as long as max_active limit is not reached and - * resources are available. - * - * system_freezable_wq is equivalent to system_wq except that it's - * freezable. - * - * *_power_efficient_wq are inclined towards saving power and converted - * into WQ_UNBOUND variants if 'wq_power_efficient' is enabled; otherwise, - * they are same as their non-power-efficient counterparts - e.g. - * system_power_efficient_wq is identical to system_wq if - * 'wq_power_efficient' is disabled. See WQ_POWER_EFFICIENT for more info. - */ -extern struct workqueue_struct *system_wq; -extern struct workqueue_struct *system_highpri_wq; -extern struct workqueue_struct *system_long_wq; -extern struct workqueue_struct *system_unbound_wq; -extern struct workqueue_struct *system_freezable_wq; -extern struct workqueue_struct *system_power_efficient_wq; -extern struct workqueue_struct *system_freezable_power_efficient_wq; - -extern struct workqueue_struct * -__alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active, - struct lock_class_key *key, const char *lock_name, ...) __printf(1, 6); - -/** - * alloc_workqueue - allocate a workqueue - * @fmt: printf format for the name of the workqueue - * @flags: WQ_* flags - * @max_active: max in-flight work items, 0 for default - * @args...: args for @fmt - * - * Allocate a workqueue with the specified parameters. For detailed - * information on WQ_* flags, please refer to Documentation/workqueue.txt. - * - * The __lock_name macro dance is to guarantee that single lock_class_key - * doesn't end up with different namesm, which isn't allowed by lockdep. - * - * RETURNS: - * Pointer to the allocated workqueue on success, %NULL on failure. - */ -#ifdef CONFIG_LOCKDEP -#define alloc_workqueue(fmt, flags, max_active, args...) \ -({ \ - static struct lock_class_key __key; \ - const char *__lock_name; \ - \ - __lock_name = #fmt#args; \ - \ - __alloc_workqueue_key((fmt), (flags), (max_active), \ - &__key, __lock_name, ##args); \ -}) -#else -#define alloc_workqueue(fmt, flags, max_active, args...) \ - __alloc_workqueue_key((fmt), (flags), (max_active), \ - NULL, NULL, ##args) -#endif - -/** - * alloc_ordered_workqueue - allocate an ordered workqueue - * @fmt: printf format for the name of the workqueue - * @flags: WQ_* flags (only WQ_FREEZABLE and WQ_MEM_RECLAIM are meaningful) - * @args...: args for @fmt - * - * Allocate an ordered workqueue. An ordered workqueue executes at - * most one work item at any given time in the queued order. They are - * implemented as unbound workqueues with @max_active of one. - * - * RETURNS: - * Pointer to the allocated workqueue on success, %NULL on failure. - */ -#define alloc_ordered_workqueue(fmt, flags, args...) \ - alloc_workqueue(fmt, WQ_UNBOUND | __WQ_ORDERED | (flags), 1, ##args) - -#define create_workqueue(name) \ - alloc_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, 1, (name)) -#define create_freezable_workqueue(name) \ - alloc_workqueue("%s", __WQ_LEGACY | WQ_FREEZABLE | WQ_UNBOUND | \ - WQ_MEM_RECLAIM, 1, (name)) -#define create_singlethread_workqueue(name) \ - alloc_ordered_workqueue("%s", __WQ_LEGACY | WQ_MEM_RECLAIM, name) - -extern void destroy_workqueue(struct workqueue_struct *wq); - -struct workqueue_attrs *alloc_workqueue_attrs(gfp_t gfp_mask); -void free_workqueue_attrs(struct workqueue_attrs *attrs); -int apply_workqueue_attrs(struct workqueue_struct *wq, - const struct workqueue_attrs *attrs); -int workqueue_set_unbound_cpumask(cpumask_var_t cpumask); - -extern bool queue_work_on(int cpu, struct workqueue_struct *wq, - struct work_struct *work); -extern bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq, - struct delayed_work *work, unsigned long delay); -extern bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq, - struct delayed_work *dwork, unsigned long delay); - -extern void flush_workqueue(struct workqueue_struct *wq); -extern void drain_workqueue(struct workqueue_struct *wq); - -extern int schedule_on_each_cpu(work_func_t func); - -int execute_in_process_context(work_func_t fn, struct execute_work *); - -extern bool flush_work(struct work_struct *work); -extern bool cancel_work(struct work_struct *work); -extern bool cancel_work_sync(struct work_struct *work); - -extern bool flush_delayed_work(struct delayed_work *dwork); -extern bool cancel_delayed_work(struct delayed_work *dwork); -extern bool cancel_delayed_work_sync(struct delayed_work *dwork); - -extern void workqueue_set_max_active(struct workqueue_struct *wq, - int max_active); -extern bool current_is_workqueue_rescuer(void); -extern bool workqueue_congested(int cpu, struct workqueue_struct *wq); -extern unsigned int work_busy(struct work_struct *work); -extern __printf(1, 2) void set_worker_desc(const char *fmt, ...); -extern void print_worker_info(const char *log_lvl, struct task_struct *task); -extern void show_workqueue_state(void); - -/** - * queue_work - queue work on a workqueue - * @wq: workqueue to use - * @work: work to queue - * - * Returns %false if @work was already on a queue, %true otherwise. - * - * We queue the work to the CPU on which it was submitted, but if the CPU dies - * it can be processed by another CPU. - */ -static inline bool queue_work(struct workqueue_struct *wq, - struct work_struct *work) -{ - return queue_work_on(WORK_CPU_UNBOUND, wq, work); -} - -/** - * queue_delayed_work - queue work on a workqueue after delay - * @wq: workqueue to use - * @dwork: delayable work to queue - * @delay: number of jiffies to wait before queueing - * - * Equivalent to queue_delayed_work_on() but tries to use the local CPU. - */ -static inline bool queue_delayed_work(struct workqueue_struct *wq, - struct delayed_work *dwork, - unsigned long delay) -{ - return queue_delayed_work_on(WORK_CPU_UNBOUND, wq, dwork, delay); -} - -/** - * mod_delayed_work - modify delay of or queue a delayed work - * @wq: workqueue to use - * @dwork: work to queue - * @delay: number of jiffies to wait before queueing - * - * mod_delayed_work_on() on local CPU. - */ -static inline bool mod_delayed_work(struct workqueue_struct *wq, - struct delayed_work *dwork, - unsigned long delay) -{ - return mod_delayed_work_on(WORK_CPU_UNBOUND, wq, dwork, delay); -} - -/** - * schedule_work_on - put work task on a specific cpu - * @cpu: cpu to put the work task on - * @work: job to be done - * - * This puts a job on a specific cpu - */ -static inline bool schedule_work_on(int cpu, struct work_struct *work) -{ - return queue_work_on(cpu, system_wq, work); -} - -/** - * schedule_work - put work task in global workqueue - * @work: job to be done - * - * Returns %false if @work was already on the kernel-global workqueue and - * %true otherwise. - * - * This puts a job in the kernel-global workqueue if it was not already - * queued and leaves it in the same position on the kernel-global - * workqueue otherwise. - */ -static inline bool schedule_work(struct work_struct *work) -{ - return queue_work(system_wq, work); -} - -/** - * flush_scheduled_work - ensure that any scheduled work has run to completion. - * - * Forces execution of the kernel-global workqueue and blocks until its - * completion. - * - * Think twice before calling this function! It's very easy to get into - * trouble if you don't take great care. Either of the following situations - * will lead to deadlock: - * - * One of the work items currently on the workqueue needs to acquire - * a lock held by your code or its caller. - * - * Your code is running in the context of a work routine. - * - * They will be detected by lockdep when they occur, but the first might not - * occur very often. It depends on what work items are on the workqueue and - * what locks they need, which you have no control over. - * - * In most situations flushing the entire workqueue is overkill; you merely - * need to know that a particular work item isn't queued and isn't running. - * In such cases you should use cancel_delayed_work_sync() or - * cancel_work_sync() instead. - */ -static inline void flush_scheduled_work(void) -{ - flush_workqueue(system_wq); -} - -/** - * schedule_delayed_work_on - queue work in global workqueue on CPU after delay - * @cpu: cpu to use - * @dwork: job to be done - * @delay: number of jiffies to wait - * - * After waiting for a given time this puts a job in the kernel-global - * workqueue on the specified CPU. - */ -static inline bool schedule_delayed_work_on(int cpu, struct delayed_work *dwork, - unsigned long delay) -{ - return queue_delayed_work_on(cpu, system_wq, dwork, delay); -} - -/** - * schedule_delayed_work - put work task in global workqueue after delay - * @dwork: job to be done - * @delay: number of jiffies to wait or 0 for immediate execution - * - * After waiting for a given time this puts a job in the kernel-global - * workqueue. - */ -static inline bool schedule_delayed_work(struct delayed_work *dwork, - unsigned long delay) -{ - return queue_delayed_work(system_wq, dwork, delay); -} - -/** - * keventd_up - is workqueue initialized yet? - */ -static inline bool keventd_up(void) -{ - return system_wq != NULL; -} - -#ifndef CONFIG_SMP -static inline long work_on_cpu(int cpu, long (*fn)(void *), void *arg) -{ - return fn(arg); -} -#else -long work_on_cpu(int cpu, long (*fn)(void *), void *arg); -#endif /* CONFIG_SMP */ - -#ifdef CONFIG_FREEZER -extern void freeze_workqueues_begin(void); -extern bool freeze_workqueues_busy(void); -extern void thaw_workqueues(void); -#endif /* CONFIG_FREEZER */ - -#ifdef CONFIG_SYSFS -int workqueue_sysfs_register(struct workqueue_struct *wq); -#else /* CONFIG_SYSFS */ -static inline int workqueue_sysfs_register(struct workqueue_struct *wq) -{ return 0; } -#endif /* CONFIG_SYSFS */ - -#ifdef CONFIG_WQ_WATCHDOG -void wq_watchdog_touch(int cpu); -#else /* CONFIG_WQ_WATCHDOG */ -static inline void wq_watchdog_touch(int cpu) { } -#endif /* CONFIG_WQ_WATCHDOG */ - -#ifdef CONFIG_SMP -int workqueue_prepare_cpu(unsigned int cpu); -int workqueue_online_cpu(unsigned int cpu); -int workqueue_offline_cpu(unsigned int cpu); -#endif - -#endif diff --git a/src/linux/include/linux/writeback.h b/src/linux/include/linux/writeback.h deleted file mode 100644 index 797100e..0000000 --- a/src/linux/include/linux/writeback.h +++ /dev/null @@ -1,389 +0,0 @@ -/* - * include/linux/writeback.h - */ -#ifndef WRITEBACK_H -#define WRITEBACK_H - -#include -#include -#include -#include -#include - -DECLARE_PER_CPU(int, dirty_throttle_leaks); - -/* - * The 1/4 region under the global dirty thresh is for smooth dirty throttling: - * - * (thresh - thresh/DIRTY_FULL_SCOPE, thresh) - * - * Further beyond, all dirtier tasks will enter a loop waiting (possibly long - * time) for the dirty pages to drop, unless written enough pages. - * - * The global dirty threshold is normally equal to the global dirty limit, - * except when the system suddenly allocates a lot of anonymous memory and - * knocks down the global dirty threshold quickly, in which case the global - * dirty limit will follow down slowly to prevent livelocking all dirtier tasks. - */ -#define DIRTY_SCOPE 8 -#define DIRTY_FULL_SCOPE (DIRTY_SCOPE / 2) - -struct backing_dev_info; - -/* - * fs/fs-writeback.c - */ -enum writeback_sync_modes { - WB_SYNC_NONE, /* Don't wait on anything */ - WB_SYNC_ALL, /* Wait on every mapping */ -}; - -/* - * why some writeback work was initiated - */ -enum wb_reason { - WB_REASON_BACKGROUND, - WB_REASON_TRY_TO_FREE_PAGES, - WB_REASON_SYNC, - WB_REASON_PERIODIC, - WB_REASON_LAPTOP_TIMER, - WB_REASON_FREE_MORE_MEM, - WB_REASON_FS_FREE_SPACE, - /* - * There is no bdi forker thread any more and works are done - * by emergency worker, however, this is TPs userland visible - * and we'll be exposing exactly the same information, - * so it has a mismatch name. - */ - WB_REASON_FORKER_THREAD, - - WB_REASON_MAX, -}; - -/* - * A control structure which tells the writeback code what to do. These are - * always on the stack, and hence need no locking. They are always initialised - * in a manner such that unspecified fields are set to zero. - */ -struct writeback_control { - long nr_to_write; /* Write this many pages, and decrement - this for each page written */ - long pages_skipped; /* Pages which were not written */ - - /* - * For a_ops->writepages(): if start or end are non-zero then this is - * a hint that the filesystem need only write out the pages inside that - * byterange. The byte at `end' is included in the writeout request. - */ - loff_t range_start; - loff_t range_end; - - enum writeback_sync_modes sync_mode; - - unsigned for_kupdate:1; /* A kupdate writeback */ - unsigned for_background:1; /* A background writeback */ - unsigned tagged_writepages:1; /* tag-and-write to avoid livelock */ - unsigned for_reclaim:1; /* Invoked from the page allocator */ - unsigned range_cyclic:1; /* range_start is cyclic */ - unsigned for_sync:1; /* sync(2) WB_SYNC_ALL writeback */ -#ifdef CONFIG_CGROUP_WRITEBACK - struct bdi_writeback *wb; /* wb this writeback is issued under */ - struct inode *inode; /* inode being written out */ - - /* foreign inode detection, see wbc_detach_inode() */ - int wb_id; /* current wb id */ - int wb_lcand_id; /* last foreign candidate wb id */ - int wb_tcand_id; /* this foreign candidate wb id */ - size_t wb_bytes; /* bytes written by current wb */ - size_t wb_lcand_bytes; /* bytes written by last candidate */ - size_t wb_tcand_bytes; /* bytes written by this candidate */ -#endif -}; - -/* - * A wb_domain represents a domain that wb's (bdi_writeback's) belong to - * and are measured against each other in. There always is one global - * domain, global_wb_domain, that every wb in the system is a member of. - * This allows measuring the relative bandwidth of each wb to distribute - * dirtyable memory accordingly. - */ -struct wb_domain { - spinlock_t lock; - - /* - * Scale the writeback cache size proportional to the relative - * writeout speed. - * - * We do this by keeping a floating proportion between BDIs, based - * on page writeback completions [end_page_writeback()]. Those - * devices that write out pages fastest will get the larger share, - * while the slower will get a smaller share. - * - * We use page writeout completions because we are interested in - * getting rid of dirty pages. Having them written out is the - * primary goal. - * - * We introduce a concept of time, a period over which we measure - * these events, because demand can/will vary over time. The length - * of this period itself is measured in page writeback completions. - */ - struct fprop_global completions; - struct timer_list period_timer; /* timer for aging of completions */ - unsigned long period_time; - - /* - * The dirtyable memory and dirty threshold could be suddenly - * knocked down by a large amount (eg. on the startup of KVM in a - * swapless system). This may throw the system into deep dirty - * exceeded state and throttle heavy/light dirtiers alike. To - * retain good responsiveness, maintain global_dirty_limit for - * tracking slowly down to the knocked down dirty threshold. - * - * Both fields are protected by ->lock. - */ - unsigned long dirty_limit_tstamp; - unsigned long dirty_limit; -}; - -/** - * wb_domain_size_changed - memory available to a wb_domain has changed - * @dom: wb_domain of interest - * - * This function should be called when the amount of memory available to - * @dom has changed. It resets @dom's dirty limit parameters to prevent - * the past values which don't match the current configuration from skewing - * dirty throttling. Without this, when memory size of a wb_domain is - * greatly reduced, the dirty throttling logic may allow too many pages to - * be dirtied leading to consecutive unnecessary OOMs and may get stuck in - * that situation. - */ -static inline void wb_domain_size_changed(struct wb_domain *dom) -{ - spin_lock(&dom->lock); - dom->dirty_limit_tstamp = jiffies; - dom->dirty_limit = 0; - spin_unlock(&dom->lock); -} - -/* - * fs/fs-writeback.c - */ -struct bdi_writeback; -void writeback_inodes_sb(struct super_block *, enum wb_reason reason); -void writeback_inodes_sb_nr(struct super_block *, unsigned long nr, - enum wb_reason reason); -bool try_to_writeback_inodes_sb(struct super_block *, enum wb_reason reason); -bool try_to_writeback_inodes_sb_nr(struct super_block *, unsigned long nr, - enum wb_reason reason); -void sync_inodes_sb(struct super_block *); -void wakeup_flusher_threads(long nr_pages, enum wb_reason reason); -void inode_wait_for_writeback(struct inode *inode); - -/* writeback.h requires fs.h; it, too, is not included from here. */ -static inline void wait_on_inode(struct inode *inode) -{ - might_sleep(); - wait_on_bit(&inode->i_state, __I_NEW, TASK_UNINTERRUPTIBLE); -} - -#ifdef CONFIG_CGROUP_WRITEBACK - -#include -#include - -void __inode_attach_wb(struct inode *inode, struct page *page); -void wbc_attach_and_unlock_inode(struct writeback_control *wbc, - struct inode *inode) - __releases(&inode->i_lock); -void wbc_detach_inode(struct writeback_control *wbc); -void wbc_account_io(struct writeback_control *wbc, struct page *page, - size_t bytes); -void cgroup_writeback_umount(void); - -/** - * inode_attach_wb - associate an inode with its wb - * @inode: inode of interest - * @page: page being dirtied (may be NULL) - * - * If @inode doesn't have its wb, associate it with the wb matching the - * memcg of @page or, if @page is NULL, %current. May be called w/ or w/o - * @inode->i_lock. - */ -static inline void inode_attach_wb(struct inode *inode, struct page *page) -{ - if (!inode->i_wb) - __inode_attach_wb(inode, page); -} - -/** - * inode_detach_wb - disassociate an inode from its wb - * @inode: inode of interest - * - * @inode is being freed. Detach from its wb. - */ -static inline void inode_detach_wb(struct inode *inode) -{ - if (inode->i_wb) { - wb_put(inode->i_wb); - inode->i_wb = NULL; - } -} - -/** - * wbc_attach_fdatawrite_inode - associate wbc and inode for fdatawrite - * @wbc: writeback_control of interest - * @inode: target inode - * - * This function is to be used by __filemap_fdatawrite_range(), which is an - * alternative entry point into writeback code, and first ensures @inode is - * associated with a bdi_writeback and attaches it to @wbc. - */ -static inline void wbc_attach_fdatawrite_inode(struct writeback_control *wbc, - struct inode *inode) -{ - spin_lock(&inode->i_lock); - inode_attach_wb(inode, NULL); - wbc_attach_and_unlock_inode(wbc, inode); -} - -/** - * wbc_init_bio - writeback specific initializtion of bio - * @wbc: writeback_control for the writeback in progress - * @bio: bio to be initialized - * - * @bio is a part of the writeback in progress controlled by @wbc. Perform - * writeback specific initialization. This is used to apply the cgroup - * writeback context. - */ -static inline void wbc_init_bio(struct writeback_control *wbc, struct bio *bio) -{ - /* - * pageout() path doesn't attach @wbc to the inode being written - * out. This is intentional as we don't want the function to block - * behind a slow cgroup. Ultimately, we want pageout() to kick off - * regular writeback instead of writing things out itself. - */ - if (wbc->wb) - bio_associate_blkcg(bio, wbc->wb->blkcg_css); -} - -#else /* CONFIG_CGROUP_WRITEBACK */ - -static inline void inode_attach_wb(struct inode *inode, struct page *page) -{ -} - -static inline void inode_detach_wb(struct inode *inode) -{ -} - -static inline void wbc_attach_and_unlock_inode(struct writeback_control *wbc, - struct inode *inode) - __releases(&inode->i_lock) -{ - spin_unlock(&inode->i_lock); -} - -static inline void wbc_attach_fdatawrite_inode(struct writeback_control *wbc, - struct inode *inode) -{ -} - -static inline void wbc_detach_inode(struct writeback_control *wbc) -{ -} - -static inline void wbc_init_bio(struct writeback_control *wbc, struct bio *bio) -{ -} - -static inline void wbc_account_io(struct writeback_control *wbc, - struct page *page, size_t bytes) -{ -} - -static inline void cgroup_writeback_umount(void) -{ -} - -#endif /* CONFIG_CGROUP_WRITEBACK */ - -/* - * mm/page-writeback.c - */ -#ifdef CONFIG_BLOCK -void laptop_io_completion(struct backing_dev_info *info); -void laptop_sync_completion(void); -void laptop_mode_sync(struct work_struct *work); -void laptop_mode_timer_fn(unsigned long data); -#else -static inline void laptop_sync_completion(void) { } -#endif -bool node_dirty_ok(struct pglist_data *pgdat); -int wb_domain_init(struct wb_domain *dom, gfp_t gfp); -#ifdef CONFIG_CGROUP_WRITEBACK -void wb_domain_exit(struct wb_domain *dom); -#endif - -extern struct wb_domain global_wb_domain; - -/* These are exported to sysctl. */ -extern int dirty_background_ratio; -extern unsigned long dirty_background_bytes; -extern int vm_dirty_ratio; -extern unsigned long vm_dirty_bytes; -extern unsigned int dirty_writeback_interval; -extern unsigned int dirty_expire_interval; -extern unsigned int dirtytime_expire_interval; -extern int vm_highmem_is_dirtyable; -extern int block_dump; -extern int laptop_mode; - -extern int dirty_background_ratio_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos); -extern int dirty_background_bytes_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos); -extern int dirty_ratio_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos); -extern int dirty_bytes_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos); -int dirtytime_interval_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); - -struct ctl_table; -int dirty_writeback_centisecs_handler(struct ctl_table *, int, - void __user *, size_t *, loff_t *); - -void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty); -unsigned long wb_calc_thresh(struct bdi_writeback *wb, unsigned long thresh); - -void wb_update_bandwidth(struct bdi_writeback *wb, unsigned long start_time); -void page_writeback_init(void); -void balance_dirty_pages_ratelimited(struct address_space *mapping); -bool wb_over_bg_thresh(struct bdi_writeback *wb); - -typedef int (*writepage_t)(struct page *page, struct writeback_control *wbc, - void *data); - -int generic_writepages(struct address_space *mapping, - struct writeback_control *wbc); -void tag_pages_for_writeback(struct address_space *mapping, - pgoff_t start, pgoff_t end); -int write_cache_pages(struct address_space *mapping, - struct writeback_control *wbc, writepage_t writepage, - void *data); -int do_writepages(struct address_space *mapping, struct writeback_control *wbc); -void writeback_set_ratelimit(void); -void tag_pages_for_writeback(struct address_space *mapping, - pgoff_t start, pgoff_t end); - -void account_page_redirty(struct page *page); - -void sb_mark_inode_writeback(struct inode *inode); -void sb_clear_inode_writeback(struct inode *inode); - -#endif /* WRITEBACK_H */ diff --git a/src/linux/include/linux/ww_mutex.h b/src/linux/include/linux/ww_mutex.h deleted file mode 100644 index 2bb5deb..0000000 --- a/src/linux/include/linux/ww_mutex.h +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Wound/Wait Mutexes: blocking mutual exclusion locks with deadlock avoidance - * - * Original mutex implementation started by Ingo Molnar: - * - * Copyright (C) 2004, 2005, 2006 Red Hat, Inc., Ingo Molnar - * - * Wound/wait implementation: - * Copyright (C) 2013 Canonical Ltd. - * - * This file contains the main data structure and API definitions. - */ - -#ifndef __LINUX_WW_MUTEX_H -#define __LINUX_WW_MUTEX_H - -#include - -struct ww_class { - atomic_long_t stamp; - struct lock_class_key acquire_key; - struct lock_class_key mutex_key; - const char *acquire_name; - const char *mutex_name; -}; - -struct ww_acquire_ctx { - struct task_struct *task; - unsigned long stamp; - unsigned acquired; -#ifdef CONFIG_DEBUG_MUTEXES - unsigned done_acquire; - struct ww_class *ww_class; - struct ww_mutex *contending_lock; -#endif -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map dep_map; -#endif -#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH - unsigned deadlock_inject_interval; - unsigned deadlock_inject_countdown; -#endif -}; - -struct ww_mutex { - struct mutex base; - struct ww_acquire_ctx *ctx; -#ifdef CONFIG_DEBUG_MUTEXES - struct ww_class *ww_class; -#endif -}; - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -# define __WW_CLASS_MUTEX_INITIALIZER(lockname, ww_class) \ - , .ww_class = &ww_class -#else -# define __WW_CLASS_MUTEX_INITIALIZER(lockname, ww_class) -#endif - -#define __WW_CLASS_INITIALIZER(ww_class) \ - { .stamp = ATOMIC_LONG_INIT(0) \ - , .acquire_name = #ww_class "_acquire" \ - , .mutex_name = #ww_class "_mutex" } - -#define __WW_MUTEX_INITIALIZER(lockname, class) \ - { .base = { \__MUTEX_INITIALIZER(lockname) } \ - __WW_CLASS_MUTEX_INITIALIZER(lockname, class) } - -#define DEFINE_WW_CLASS(classname) \ - struct ww_class classname = __WW_CLASS_INITIALIZER(classname) - -#define DEFINE_WW_MUTEX(mutexname, ww_class) \ - struct ww_mutex mutexname = __WW_MUTEX_INITIALIZER(mutexname, ww_class) - -/** - * ww_mutex_init - initialize the w/w mutex - * @lock: the mutex to be initialized - * @ww_class: the w/w class the mutex should belong to - * - * Initialize the w/w mutex to unlocked state and associate it with the given - * class. - * - * It is not allowed to initialize an already locked mutex. - */ -static inline void ww_mutex_init(struct ww_mutex *lock, - struct ww_class *ww_class) -{ - __mutex_init(&lock->base, ww_class->mutex_name, &ww_class->mutex_key); - lock->ctx = NULL; -#ifdef CONFIG_DEBUG_MUTEXES - lock->ww_class = ww_class; -#endif -} - -/** - * ww_acquire_init - initialize a w/w acquire context - * @ctx: w/w acquire context to initialize - * @ww_class: w/w class of the context - * - * Initializes an context to acquire multiple mutexes of the given w/w class. - * - * Context-based w/w mutex acquiring can be done in any order whatsoever within - * a given lock class. Deadlocks will be detected and handled with the - * wait/wound logic. - * - * Mixing of context-based w/w mutex acquiring and single w/w mutex locking can - * result in undetected deadlocks and is so forbidden. Mixing different contexts - * for the same w/w class when acquiring mutexes can also result in undetected - * deadlocks, and is hence also forbidden. Both types of abuse will be caught by - * enabling CONFIG_PROVE_LOCKING. - * - * Nesting of acquire contexts for _different_ w/w classes is possible, subject - * to the usual locking rules between different lock classes. - * - * An acquire context must be released with ww_acquire_fini by the same task - * before the memory is freed. It is recommended to allocate the context itself - * on the stack. - */ -static inline void ww_acquire_init(struct ww_acquire_ctx *ctx, - struct ww_class *ww_class) -{ - ctx->task = current; - ctx->stamp = atomic_long_inc_return(&ww_class->stamp); - ctx->acquired = 0; -#ifdef CONFIG_DEBUG_MUTEXES - ctx->ww_class = ww_class; - ctx->done_acquire = 0; - ctx->contending_lock = NULL; -#endif -#ifdef CONFIG_DEBUG_LOCK_ALLOC - debug_check_no_locks_freed((void *)ctx, sizeof(*ctx)); - lockdep_init_map(&ctx->dep_map, ww_class->acquire_name, - &ww_class->acquire_key, 0); - mutex_acquire(&ctx->dep_map, 0, 0, _RET_IP_); -#endif -#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH - ctx->deadlock_inject_interval = 1; - ctx->deadlock_inject_countdown = ctx->stamp & 0xf; -#endif -} - -/** - * ww_acquire_done - marks the end of the acquire phase - * @ctx: the acquire context - * - * Marks the end of the acquire phase, any further w/w mutex lock calls using - * this context are forbidden. - * - * Calling this function is optional, it is just useful to document w/w mutex - * code and clearly designated the acquire phase from actually using the locked - * data structures. - */ -static inline void ww_acquire_done(struct ww_acquire_ctx *ctx) -{ -#ifdef CONFIG_DEBUG_MUTEXES - lockdep_assert_held(ctx); - - DEBUG_LOCKS_WARN_ON(ctx->done_acquire); - ctx->done_acquire = 1; -#endif -} - -/** - * ww_acquire_fini - releases a w/w acquire context - * @ctx: the acquire context to free - * - * Releases a w/w acquire context. This must be called _after_ all acquired w/w - * mutexes have been released with ww_mutex_unlock. - */ -static inline void ww_acquire_fini(struct ww_acquire_ctx *ctx) -{ -#ifdef CONFIG_DEBUG_MUTEXES - mutex_release(&ctx->dep_map, 0, _THIS_IP_); - - DEBUG_LOCKS_WARN_ON(ctx->acquired); - if (!IS_ENABLED(CONFIG_PROVE_LOCKING)) - /* - * lockdep will normally handle this, - * but fail without anyway - */ - ctx->done_acquire = 1; - - if (!IS_ENABLED(CONFIG_DEBUG_LOCK_ALLOC)) - /* ensure ww_acquire_fini will still fail if called twice */ - ctx->acquired = ~0U; -#endif -} - -extern int __must_check __ww_mutex_lock(struct ww_mutex *lock, - struct ww_acquire_ctx *ctx); -extern int __must_check __ww_mutex_lock_interruptible(struct ww_mutex *lock, - struct ww_acquire_ctx *ctx); - -/** - * ww_mutex_lock - acquire the w/w mutex - * @lock: the mutex to be acquired - * @ctx: w/w acquire context, or NULL to acquire only a single lock. - * - * Lock the w/w mutex exclusively for this task. - * - * Deadlocks within a given w/w class of locks are detected and handled with the - * wait/wound algorithm. If the lock isn't immediately avaiable this function - * will either sleep until it is (wait case). Or it selects the current context - * for backing off by returning -EDEADLK (wound case). Trying to acquire the - * same lock with the same context twice is also detected and signalled by - * returning -EALREADY. Returns 0 if the mutex was successfully acquired. - * - * In the wound case the caller must release all currently held w/w mutexes for - * the given context and then wait for this contending lock to be available by - * calling ww_mutex_lock_slow. Alternatively callers can opt to not acquire this - * lock and proceed with trying to acquire further w/w mutexes (e.g. when - * scanning through lru lists trying to free resources). - * - * The mutex must later on be released by the same task that - * acquired it. The task may not exit without first unlocking the mutex. Also, - * kernel memory where the mutex resides must not be freed with the mutex still - * locked. The mutex must first be initialized (or statically defined) before it - * can be locked. memset()-ing the mutex to 0 is not allowed. The mutex must be - * of the same w/w lock class as was used to initialize the acquire context. - * - * A mutex acquired with this function must be released with ww_mutex_unlock. - */ -static inline int ww_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) -{ - if (ctx) - return __ww_mutex_lock(lock, ctx); - - mutex_lock(&lock->base); - return 0; -} - -/** - * ww_mutex_lock_interruptible - acquire the w/w mutex, interruptible - * @lock: the mutex to be acquired - * @ctx: w/w acquire context - * - * Lock the w/w mutex exclusively for this task. - * - * Deadlocks within a given w/w class of locks are detected and handled with the - * wait/wound algorithm. If the lock isn't immediately avaiable this function - * will either sleep until it is (wait case). Or it selects the current context - * for backing off by returning -EDEADLK (wound case). Trying to acquire the - * same lock with the same context twice is also detected and signalled by - * returning -EALREADY. Returns 0 if the mutex was successfully acquired. If a - * signal arrives while waiting for the lock then this function returns -EINTR. - * - * In the wound case the caller must release all currently held w/w mutexes for - * the given context and then wait for this contending lock to be available by - * calling ww_mutex_lock_slow_interruptible. Alternatively callers can opt to - * not acquire this lock and proceed with trying to acquire further w/w mutexes - * (e.g. when scanning through lru lists trying to free resources). - * - * The mutex must later on be released by the same task that - * acquired it. The task may not exit without first unlocking the mutex. Also, - * kernel memory where the mutex resides must not be freed with the mutex still - * locked. The mutex must first be initialized (or statically defined) before it - * can be locked. memset()-ing the mutex to 0 is not allowed. The mutex must be - * of the same w/w lock class as was used to initialize the acquire context. - * - * A mutex acquired with this function must be released with ww_mutex_unlock. - */ -static inline int __must_check ww_mutex_lock_interruptible(struct ww_mutex *lock, - struct ww_acquire_ctx *ctx) -{ - if (ctx) - return __ww_mutex_lock_interruptible(lock, ctx); - else - return mutex_lock_interruptible(&lock->base); -} - -/** - * ww_mutex_lock_slow - slowpath acquiring of the w/w mutex - * @lock: the mutex to be acquired - * @ctx: w/w acquire context - * - * Acquires a w/w mutex with the given context after a wound case. This function - * will sleep until the lock becomes available. - * - * The caller must have released all w/w mutexes already acquired with the - * context and then call this function on the contended lock. - * - * Afterwards the caller may continue to (re)acquire the other w/w mutexes it - * needs with ww_mutex_lock. Note that the -EALREADY return code from - * ww_mutex_lock can be used to avoid locking this contended mutex twice. - * - * It is forbidden to call this function with any other w/w mutexes associated - * with the context held. It is forbidden to call this on anything else than the - * contending mutex. - * - * Note that the slowpath lock acquiring can also be done by calling - * ww_mutex_lock directly. This function here is simply to help w/w mutex - * locking code readability by clearly denoting the slowpath. - */ -static inline void -ww_mutex_lock_slow(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) -{ - int ret; -#ifdef CONFIG_DEBUG_MUTEXES - DEBUG_LOCKS_WARN_ON(!ctx->contending_lock); -#endif - ret = ww_mutex_lock(lock, ctx); - (void)ret; -} - -/** - * ww_mutex_lock_slow_interruptible - slowpath acquiring of the w/w mutex, interruptible - * @lock: the mutex to be acquired - * @ctx: w/w acquire context - * - * Acquires a w/w mutex with the given context after a wound case. This function - * will sleep until the lock becomes available and returns 0 when the lock has - * been acquired. If a signal arrives while waiting for the lock then this - * function returns -EINTR. - * - * The caller must have released all w/w mutexes already acquired with the - * context and then call this function on the contended lock. - * - * Afterwards the caller may continue to (re)acquire the other w/w mutexes it - * needs with ww_mutex_lock. Note that the -EALREADY return code from - * ww_mutex_lock can be used to avoid locking this contended mutex twice. - * - * It is forbidden to call this function with any other w/w mutexes associated - * with the given context held. It is forbidden to call this on anything else - * than the contending mutex. - * - * Note that the slowpath lock acquiring can also be done by calling - * ww_mutex_lock_interruptible directly. This function here is simply to help - * w/w mutex locking code readability by clearly denoting the slowpath. - */ -static inline int __must_check -ww_mutex_lock_slow_interruptible(struct ww_mutex *lock, - struct ww_acquire_ctx *ctx) -{ -#ifdef CONFIG_DEBUG_MUTEXES - DEBUG_LOCKS_WARN_ON(!ctx->contending_lock); -#endif - return ww_mutex_lock_interruptible(lock, ctx); -} - -extern void ww_mutex_unlock(struct ww_mutex *lock); - -/** - * ww_mutex_trylock - tries to acquire the w/w mutex without acquire context - * @lock: mutex to lock - * - * Trylocks a mutex without acquire context, so no deadlock detection is - * possible. Returns 1 if the mutex has been acquired successfully, 0 otherwise. - */ -static inline int __must_check ww_mutex_trylock(struct ww_mutex *lock) -{ - return mutex_trylock(&lock->base); -} - -/*** - * ww_mutex_destroy - mark a w/w mutex unusable - * @lock: the mutex to be destroyed - * - * This function marks the mutex uninitialized, and any subsequent - * use of the mutex is forbidden. The mutex must not be locked when - * this function is called. - */ -static inline void ww_mutex_destroy(struct ww_mutex *lock) -{ - mutex_destroy(&lock->base); -} - -/** - * ww_mutex_is_locked - is the w/w mutex locked - * @lock: the mutex to be queried - * - * Returns 1 if the mutex is locked, 0 if unlocked. - */ -static inline bool ww_mutex_is_locked(struct ww_mutex *lock) -{ - return mutex_is_locked(&lock->base); -} - -#endif diff --git a/src/linux/include/linux/xattr.h b/src/linux/include/linux/xattr.h deleted file mode 100644 index e77605a..0000000 --- a/src/linux/include/linux/xattr.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - File: linux/xattr.h - - Extended attributes handling. - - Copyright (C) 2001 by Andreas Gruenbacher - Copyright (c) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. - Copyright (c) 2004 Red Hat, Inc., James Morris -*/ -#ifndef _LINUX_XATTR_H -#define _LINUX_XATTR_H - - -#include -#include -#include -#include - -struct inode; -struct dentry; - -/* - * struct xattr_handler: When @name is set, match attributes with exactly that - * name. When @prefix is set instead, match attributes with that prefix and - * with a non-empty suffix. - */ -struct xattr_handler { - const char *name; - const char *prefix; - int flags; /* fs private flags */ - bool (*list)(struct dentry *dentry); - int (*get)(const struct xattr_handler *, struct dentry *dentry, - struct inode *inode, const char *name, void *buffer, - size_t size); - int (*set)(const struct xattr_handler *, struct dentry *dentry, - struct inode *inode, const char *name, const void *buffer, - size_t size, int flags); -}; - -const char *xattr_full_name(const struct xattr_handler *, const char *); - -struct xattr { - const char *name; - void *value; - size_t value_len; -}; - -ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t); -ssize_t __vfs_getxattr(struct dentry *, struct inode *, const char *, void *, size_t); -ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t); -ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size); -int __vfs_setxattr(struct dentry *, struct inode *, const char *, const void *, size_t, int); -int __vfs_setxattr_noperm(struct dentry *, const char *, const void *, size_t, int); -int vfs_setxattr(struct dentry *, const char *, const void *, size_t, int); -int __vfs_removexattr(struct dentry *, const char *); -int vfs_removexattr(struct dentry *, const char *); - -ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size); -ssize_t vfs_getxattr_alloc(struct dentry *dentry, const char *name, - char **xattr_value, size_t size, gfp_t flags); - -static inline const char *xattr_prefix(const struct xattr_handler *handler) -{ - return handler->prefix ?: handler->name; -} - -struct simple_xattrs { - struct list_head head; - spinlock_t lock; -}; - -struct simple_xattr { - struct list_head list; - char *name; - size_t size; - char value[0]; -}; - -/* - * initialize the simple_xattrs structure - */ -static inline void simple_xattrs_init(struct simple_xattrs *xattrs) -{ - INIT_LIST_HEAD(&xattrs->head); - spin_lock_init(&xattrs->lock); -} - -/* - * free all the xattrs - */ -static inline void simple_xattrs_free(struct simple_xattrs *xattrs) -{ - struct simple_xattr *xattr, *node; - - list_for_each_entry_safe(xattr, node, &xattrs->head, list) { - kfree(xattr->name); - kfree(xattr); - } -} - -struct simple_xattr *simple_xattr_alloc(const void *value, size_t size); -int simple_xattr_get(struct simple_xattrs *xattrs, const char *name, - void *buffer, size_t size); -int simple_xattr_set(struct simple_xattrs *xattrs, const char *name, - const void *value, size_t size, int flags); -ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs, char *buffer, - size_t size); -void simple_xattr_list_add(struct simple_xattrs *xattrs, - struct simple_xattr *new_xattr); - -#endif /* _LINUX_XATTR_H */ diff --git a/src/linux/include/linux/zconf.h b/src/linux/include/linux/zconf.h deleted file mode 100644 index 0beb75e..0000000 --- a/src/linux/include/linux/zconf.h +++ /dev/null @@ -1,57 +0,0 @@ -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-1998 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#ifndef _ZCONF_H -#define _ZCONF_H - -/* The memory requirements for deflate are (in bytes): - (1 << (windowBits+2)) + (1 << (memLevel+9)) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus a few kilobytes - for small objects. -*/ - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# define MAX_MEM_LEVEL 8 -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2. - * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files - * created by gzip. (Files created by minigzip can still be extracted by - * gzip.) - */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* default windowBits for decompression. MAX_WBITS is for compression only */ -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif - -/* default memLevel */ -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif - - /* Type declarations */ - -typedef unsigned char Byte; /* 8 bits */ -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ -typedef void *voidp; - -#endif /* _ZCONF_H */ diff --git a/src/linux/include/linux/zlib.h b/src/linux/include/linux/zlib.h deleted file mode 100644 index 92dbbd3..0000000 --- a/src/linux/include/linux/zlib.h +++ /dev/null @@ -1,593 +0,0 @@ -/* zlib.h -- interface of the 'zlib' general purpose compression library - - Copyright (C) 1995-2005 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt - (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). -*/ - -#ifndef _ZLIB_H -#define _ZLIB_H - -#include - -/* zlib deflate based on ZLIB_VERSION "1.1.3" */ -/* zlib inflate based on ZLIB_VERSION "1.2.3" */ - -/* - This is a modified version of zlib for use inside the Linux kernel. - The main changes are to perform all memory allocation in advance. - - Inflation Changes: - * Z_PACKET_FLUSH is added and used by ppp_deflate. Before returning - this checks there is no more input data available and the next data - is a STORED block. It also resets the mode to be read for the next - data, all as per PPP requirements. - * Addition of zlib_inflateIncomp which copies incompressible data into - the history window and adjusts the accoutning without calling - zlib_inflate itself to inflate the data. -*/ - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed - data. This version of the library supports only one compression method - (deflation) but other algorithms will be added later and will have the same - stream interface. - - Compression can be done in a single step if the buffers are large - enough (for example if an input file is mmap'ed), or can be done by - repeated calls of the compression function. In the latter case, the - application must provide more input and/or consume the output - (providing more output space) before each call. - - The compressed data format used by default by the in-memory functions is - the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped - around a deflate stream, which is itself documented in RFC 1951. - - The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio. - - The zlib format was designed to be compact and fast for use in memory - and on communications channels. The gzip format was designed for single- - file compression on file systems, has a larger header than zlib to maintain - directory information, and uses a different, slower check method than zlib. - - The library does not install any signal handler. The decoder checks - the consistency of the compressed data, so the library should never - crash even in case of corrupted input. -*/ - -struct internal_state; - -typedef struct z_stream_s { - const Byte *next_in; /* next input byte */ - uLong avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total nb of input bytes read so far */ - - Byte *next_out; /* next output byte should be put there */ - uLong avail_out; /* remaining free space at next_out */ - uLong total_out; /* total nb of bytes output so far */ - - char *msg; /* last error message, NULL if no error */ - struct internal_state *state; /* not visible by applications */ - - void *workspace; /* memory allocated for this stream */ - - int data_type; /* best guess about the data type: ascii or binary */ - uLong adler; /* adler32 value of the uncompressed data */ - uLong reserved; /* reserved for future use */ -} z_stream; - -typedef z_stream *z_streamp; - -/* - The application must update next_in and avail_in when avail_in has - dropped to zero. It must update next_out and avail_out when avail_out - has dropped to zero. The application must initialize zalloc, zfree and - opaque before calling the init function. All other fields are set by the - compression library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return NULL if there is not enough memory for the object. - If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. - - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this - if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, - pointers returned by zalloc for objects of exactly 65536 bytes *must* - have their offset normalized to zero. The default allocation function - provided by this library ensures this (see zutil.c). To reduce memory - requirements and avoid any allocation of 64K objects, at the expense of - compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or - progress reports. After compression, total_in holds the total size of - the uncompressed data and may be saved for use in the decompressor - (particularly if the decompressor wants to decompress everything in - a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ -#define Z_PACKET_FLUSH 2 -#define Z_SYNC_FLUSH 3 -#define Z_FULL_FLUSH 4 -#define Z_FINISH 5 -#define Z_BLOCK 6 /* Only for inflate at present */ -/* Allowed flush values; see deflate() and inflate() below for details */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -#define Z_VERSION_ERROR (-6) -/* Return codes for the compression/decompression functions. Negative - * values are errors, positive values are used for special but normal events. - */ - -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_DEFAULT_STRATEGY 0 -/* compression strategy; see deflateInit2() below for details */ - -#define Z_BINARY 0 -#define Z_ASCII 1 -#define Z_UNKNOWN 2 -/* Possible values of the data_type field */ - -#define Z_DEFLATED 8 -/* The deflate compression method (the only one supported in this version) */ - - /* basic functions */ - -extern int zlib_deflate_workspacesize (int windowBits, int memLevel); -/* - Returns the number of bytes that needs to be allocated for a per- - stream workspace with the specified parameters. A pointer to this - number of bytes should be returned in stream->workspace before - you call zlib_deflateInit() or zlib_deflateInit2(). If you call - zlib_deflateInit(), specify windowBits = MAX_WBITS and memLevel = - MAX_MEM_LEVEL here. If you call zlib_deflateInit2(), the windowBits - and memLevel parameters passed to zlib_deflateInit2() must not - exceed those passed here. -*/ - -/* -extern int deflateInit (z_streamp strm, int level); - - Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. - If zalloc and zfree are set to NULL, deflateInit updates them to - use default allocation functions. - - The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at - all (the input data is simply copied a block at a time). - Z_DEFAULT_COMPRESSION requests a default compromise between speed and - compression (currently equivalent to level 6). - - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if level is not a valid compression level, - Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). - msg is set to null if there is no error message. deflateInit does not - perform any compression: this will be done by deflate(). -*/ - - -extern int zlib_deflate (z_streamp strm, int flush); -/* - deflate compresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce some - output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. deflate performs one or both of the - following actions: - - - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in and avail_in are updated and - processing will resume at this point for the next call of deflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. - Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary (in interactive applications). - Some output may be provided even if flush is not set. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating avail_in or avail_out accordingly; avail_out - should never be zero before the call. The application can consume the - compressed output when it wants, for example when the output buffer is full - (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK - and with zero avail_out, it must be called again after making room in the - output buffer because there might be more output pending. - - If the parameter flush is set to Z_SYNC_FLUSH, all pending output is - flushed to the output buffer and the output is aligned on a byte boundary, so - that the decompressor can get all input data available so far. (In particular - avail_in is zero after the call if enough output space has been provided - before the call.) Flushing may degrade compression for some compression - algorithms and so it should be used only when necessary. - - If flush is set to Z_FULL_FLUSH, all output is flushed as with - Z_SYNC_FLUSH, and the compression state is reset so that decompression can - restart from this point if previous compressed data has been damaged or if - random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - the compression. - - If deflate returns with avail_out == 0, this function must be called again - with the same value of the flush parameter and more output space (updated - avail_out), until the flush is complete (deflate returns with non-zero - avail_out). - - If the parameter flush is set to Z_FINISH, pending input is processed, - pending output is flushed and deflate returns with Z_STREAM_END if there - was enough output space; if deflate returns with Z_OK, this function must be - called again with Z_FINISH and more output space (updated avail_out) but no - more input data, until it returns with Z_STREAM_END or an error. After - deflate has returned Z_STREAM_END, the only possible operations on the - stream are deflateReset or deflateEnd. - - Z_FINISH can be used immediately after deflateInit if all the compression - is to be done in a single step. In this case, avail_out must be at least - 0.1% larger than avail_in plus 12 bytes. If deflate does not return - Z_STREAM_END, then it must be called again as described above. - - deflate() sets strm->adler to the adler32 checksum of all input read - so far (that is, total_in bytes). - - deflate() may update data_type if it can make a good guess about - the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered - binary. This field is only for information purposes and does not affect - the compression algorithm in any manner. - - deflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if all input has been - consumed and all output has been produced (only when flush is set to - Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible - (for example avail_in or avail_out was zero). -*/ - - -extern int zlib_deflateEnd (z_streamp strm); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the - stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, - msg may be set but then points to a static string (which must not be - deallocated). -*/ - - -extern int zlib_inflate_workspacesize (void); -/* - Returns the number of bytes that needs to be allocated for a per- - stream workspace. A pointer to this number of bytes should be - returned in stream->workspace before calling zlib_inflateInit(). -*/ - -/* -extern int zlib_inflateInit (z_streamp strm); - - Initializes the internal stream state for decompression. The fields - next_in, avail_in, and workspace must be initialized before by - the caller. If next_in is not NULL and avail_in is large enough (the exact - value depends on the compression method), inflateInit determines the - compression method from the zlib header and allocates all data structures - accordingly; otherwise the allocation will be deferred to the first call of - inflate. If zalloc and zfree are set to NULL, inflateInit updates them to - use default allocation functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller. msg is set to null if there is no error - message. inflateInit does not perform any decompression apart from reading - the zlib header if present: this will be done by inflate(). (So next_in and - avail_in may be modified, but next_out and avail_out are unchanged.) -*/ - - -extern int zlib_inflate (z_streamp strm, int flush); -/* - inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. inflate performs one or both of the - following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in is updated and processing - will resume at this point for the next call of inflate(). - - - Provide more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there - is no more input data or no more space in the output buffer (see below - about the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming - more output, and updating the next_* and avail_* values accordingly. - The application can consume the uncompressed output when it wants, for - example when the output buffer is full (avail_out == 0), or after each - call of inflate(). If inflate returns Z_OK and with zero avail_out, it - must be called again after making room in the output buffer because there - might be more output pending. - - The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, - Z_FINISH, or Z_BLOCK. Z_SYNC_FLUSH requests that inflate() flush as much - output as possible to the output buffer. Z_BLOCK requests that inflate() stop - if and when it gets to the next deflate block boundary. When decoding the - zlib or gzip format, this will cause inflate() to return immediately after - the header and before the first block. When doing a raw inflate, inflate() - will go ahead and process the first block, and will return when it gets to - the end of that block, or when it runs out of data. - - The Z_BLOCK option assists in appending to or combining deflate streams. - Also to assist in this, on return inflate() will set strm->data_type to the - number of unused bits in the last byte taken from strm->next_in, plus 64 - if inflate() is currently decoding the last block in the deflate stream, - plus 128 if inflate() returned immediately after decoding an end-of-block - code or decoding the complete header up to just before the first byte of the - deflate stream. The end-of-block will not be indicated until all of the - uncompressed data from that block has been written to strm->next_out. The - number of unused bits may in general be greater than seven, except when - bit 7 of data_type is set, in which case the number of unused bits will be - less than eight. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step - (a single call of inflate), the parameter flush should be set to - Z_FINISH. In this case all pending input is processed and all pending - output is flushed; avail_out must be large enough to hold all the - uncompressed data. (The size of the uncompressed data may have been saved - by the compressor for this purpose.) The next operation on this stream must - be inflateEnd to deallocate the decompression state. The use of Z_FINISH - is never required, but can be used to inform inflate that a faster approach - may be used for the single inflate() call. - - In this implementation, inflate() always flushes as much output as - possible to the output buffer, and always uses the faster approach on the - first call. So the only effect of the flush parameter in this implementation - is on the return value of inflate(), as noted below, or when it returns early - because Z_BLOCK is used. - - If a preset dictionary is needed after this call (see inflateSetDictionary - below), inflate sets strm->adler to the adler32 checksum of the dictionary - chosen by the compressor and returns Z_NEED_DICT; otherwise it sets - strm->adler to the adler32 checksum of all output produced so far (that is, - total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described - below. At the end of the stream, inflate() checks that its computed adler32 - checksum is equal to that saved by the compressor and returns Z_STREAM_END - only if the checksum is correct. - - inflate() will decompress and check either zlib-wrapped or gzip-wrapped - deflate data. The header type is detected automatically. Any information - contained in the gzip header is not retained, so applications that need that - information should instead use raw inflate, see inflateInit2() below, or - inflateBack() and perform their own processing of the gzip header and - trailer. - - inflate() returns Z_OK if some progress has been made (more input processed - or more output produced), Z_STREAM_END if the end of the compressed data has - been reached and all uncompressed output has been produced, Z_NEED_DICT if a - preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect check - value), Z_STREAM_ERROR if the stream structure was inconsistent (for example - if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, - Z_BUF_ERROR if no progress is possible or if there was not enough room in the - output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and - inflate() can be called again with more input and more output space to - continue decompressing. If Z_DATA_ERROR is returned, the application may then - call inflateSync() to look for a good compression block if a partial recovery - of the data is desired. -*/ - - -extern int zlib_inflateEnd (z_streamp strm); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any - pending output. - - inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state - was inconsistent. In the error case, msg may be set but then points to a - static string (which must not be deallocated). -*/ - - /* Advanced functions */ - -/* - The following functions are needed only in some special applications. -*/ - -/* -extern int deflateInit2 (z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy); - - This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by - the caller. - - The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. - - The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this - version of the library. Larger values of this parameter result in better - compression at the expense of memory usage. The default value is 15 if - deflateInit is used instead. - - The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but - is slow and reduces compression ratio; memLevel=9 uses maximum memory - for optimal speed. The default value is 8. See zconf.h for total memory - usage as a function of windowBits and memLevel. - - The strategy parameter is used to tune the compression algorithm. Use the - value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match). Filtered data consists mostly of small values with a - somewhat random distribution. In this case, the compression algorithm is - tuned to compress them better. The effect of Z_FILTERED is to force more - Huffman coding and less string matching; it is somewhat intermediate - between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects - the compression ratio but not the correctness of the compressed output even - if it is not set appropriately. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid - method). msg is set to null if there is no error message. deflateInit2 does - not perform any compression: this will be done by deflate(). -*/ - -extern int zlib_deflateReset (z_streamp strm); -/* - This function is equivalent to deflateEnd followed by deflateInit, - but does not free and reallocate all the internal compression state. - The stream will keep the same compression level and any other attributes - that may have been set by deflateInit2. - - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -static inline unsigned long deflateBound(unsigned long s) -{ - return s + ((s + 7) >> 3) + ((s + 63) >> 6) + 11; -} - -/* -extern int inflateInit2 (z_streamp strm, int windowBits); - - This is another version of inflateInit with an extra parameter. The - fields next_in, avail_in, zalloc, zfree and opaque must be initialized - before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library. The default value is 15 if inflateInit is used - instead. windowBits must be greater than or equal to the windowBits value - provided to deflateInit2() while compressing, or it must be equal to 15 if - deflateInit2() was not used. If a compressed stream with a larger window - size is given as input, inflate() will return with the error code - Z_DATA_ERROR instead of trying to allocate a larger window. - - windowBits can also be -8..-15 for raw inflate. In this case, -windowBits - determines the window size. inflate() will then process raw deflate data, - not looking for a zlib or gzip header, not generating a check value, and not - looking for any check values for comparison at the end of the stream. This - is for use with other formats that use the deflate compressed data format - such as zip. Those formats provide their own check values. If a custom - format is developed using the raw deflate format for compressed data, it is - recommended that a check value such as an adler32 or a crc32 be applied to - the uncompressed data as is done in the zlib, gzip, and zip formats. For - most applications, the zlib format should be used as is. Note that comments - above on the use in deflateInit2() applies to the magnitude of windowBits. - - windowBits can also be greater than 15 for optional gzip decoding. Add - 32 to windowBits to enable zlib and gzip decoding with automatic header - detection, or add 16 to decode only the gzip format (the zlib format will - return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is - a crc32 instead of an adler32. - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if a parameter is invalid (such as a null strm). msg - is set to null if there is no error message. inflateInit2 does not perform - any decompression apart from reading the zlib header if present: this will - be done by inflate(). (So next_in and avail_in may be modified, but next_out - and avail_out are unchanged.) -*/ - -extern int zlib_inflateReset (z_streamp strm); -/* - This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate all the internal decompression state. - The stream will keep attributes that may have been set by inflateInit2. - - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being NULL). -*/ - -extern int zlib_inflateIncomp (z_stream *strm); -/* - This function adds the data at next_in (avail_in bytes) to the output - history without performing any output. There must be no pending output, - and the decompressor must be expecting to see the start of a block. - Calling this function is equivalent to decompressing a stored block - containing the data at next_in (except that the data is not output). -*/ - -#define zlib_deflateInit(strm, level) \ - zlib_deflateInit2((strm), (level), Z_DEFLATED, MAX_WBITS, \ - DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY) -#define zlib_inflateInit(strm) \ - zlib_inflateInit2((strm), DEF_WBITS) - -extern int zlib_deflateInit2(z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy); -extern int zlib_inflateInit2(z_streamp strm, int windowBits); - -#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL) - struct internal_state {int dummy;}; /* hack for buggy compilers */ -#endif - -/* Utility function: initialize zlib, unpack binary blob, clean up zlib, - * return len or negative error code. */ -extern int zlib_inflate_blob(void *dst, unsigned dst_sz, const void *src, unsigned src_sz); - -#endif /* _ZLIB_H */ diff --git a/src/linux/include/linux/zutil.h b/src/linux/include/linux/zutil.h deleted file mode 100644 index 6636895..0000000 --- a/src/linux/include/linux/zutil.h +++ /dev/null @@ -1,106 +0,0 @@ -/* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-1998 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id: zutil.h,v 1.1 2000/01/01 03:32:23 davem Exp $ */ - -#ifndef _Z_UTIL_H -#define _Z_UTIL_H - -#include -#include -#include - -typedef unsigned char uch; -typedef unsigned short ush; -typedef unsigned long ulg; - - /* common constants */ - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - -#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ - - /* target dependencies */ - - /* Common defaults */ - -#ifndef OS_CODE -# define OS_CODE 0x03 /* assume Unix */ -#endif - - /* functions */ - -typedef uLong (*check_func) (uLong check, const Byte *buf, - uInt len); - - - /* checksum functions */ - -#define BASE 65521L /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ - -#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} -#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); -#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); -#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); -#define DO16(buf) DO8(buf,0); DO8(buf,8); - -/* ========================================================================= */ -/* - Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is NULL, this function returns - the required initial value for the checksum. - An Adler-32 checksum is almost as reliable as a CRC32 but can be computed - much faster. Usage example: - - uLong adler = zlib_adler32(0L, NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - adler = zlib_adler32(adler, buffer, length); - } - if (adler != original_adler) error(); -*/ -static inline uLong zlib_adler32(uLong adler, - const Byte *buf, - uInt len) -{ - unsigned long s1 = adler & 0xffff; - unsigned long s2 = (adler >> 16) & 0xffff; - int k; - - if (buf == NULL) return 1L; - - while (len > 0) { - k = len < NMAX ? len : NMAX; - len -= k; - while (k >= 16) { - DO16(buf); - buf += 16; - k -= 16; - } - if (k != 0) do { - s1 += *buf++; - s2 += s1; - } while (--k); - s1 %= BASE; - s2 %= BASE; - } - return (s2 << 16) | s1; -} - -#endif /* _Z_UTIL_H */ diff --git a/src/linux/include/net/6lowpan.h b/src/linux/include/net/6lowpan.h deleted file mode 100644 index 5ab4c99..0000000 --- a/src/linux/include/net/6lowpan.h +++ /dev/null @@ -1,315 +0,0 @@ -/* - * Copyright 2011, Siemens AG - * written by Alexander Smirnov - */ - -/* - * Based on patches from Jon Smirl - * Copyright (c) 2011 Jon Smirl - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/* Jon's code is based on 6lowpan implementation for Contiki which is: - * Copyright (c) 2008, Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the Institute nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef __6LOWPAN_H__ -#define __6LOWPAN_H__ - -#include - -#include -#include - -/* special link-layer handling */ -#include - -#define EUI64_ADDR_LEN 8 - -#define LOWPAN_NHC_MAX_ID_LEN 1 -/* Maximum next header compression length which we currently support inclusive - * possible inline data. - */ -#define LOWPAN_NHC_MAX_HDR_LEN (sizeof(struct udphdr)) -/* Max IPHC Header len without IPv6 hdr specific inline data. - * Useful for getting the "extra" bytes we need at worst case compression. - * - * LOWPAN_IPHC + CID + LOWPAN_NHC_MAX_ID_LEN - */ -#define LOWPAN_IPHC_MAX_HEADER_LEN (2 + 1 + LOWPAN_NHC_MAX_ID_LEN) -/* Maximum worst case IPHC header buffer size */ -#define LOWPAN_IPHC_MAX_HC_BUF_LEN (sizeof(struct ipv6hdr) + \ - LOWPAN_IPHC_MAX_HEADER_LEN + \ - LOWPAN_NHC_MAX_HDR_LEN) -/* SCI/DCI is 4 bit width, so we have maximum 16 entries */ -#define LOWPAN_IPHC_CTX_TABLE_SIZE (1 << 4) - -#define LOWPAN_DISPATCH_IPV6 0x41 /* 01000001 = 65 */ -#define LOWPAN_DISPATCH_IPHC 0x60 /* 011xxxxx = ... */ -#define LOWPAN_DISPATCH_IPHC_MASK 0xe0 - -static inline bool lowpan_is_ipv6(u8 dispatch) -{ - return dispatch == LOWPAN_DISPATCH_IPV6; -} - -static inline bool lowpan_is_iphc(u8 dispatch) -{ - return (dispatch & LOWPAN_DISPATCH_IPHC_MASK) == LOWPAN_DISPATCH_IPHC; -} - -#define LOWPAN_PRIV_SIZE(llpriv_size) \ - (sizeof(struct lowpan_dev) + llpriv_size) - -enum lowpan_lltypes { - LOWPAN_LLTYPE_BTLE, - LOWPAN_LLTYPE_IEEE802154, -}; - -enum lowpan_iphc_ctx_flags { - LOWPAN_IPHC_CTX_FLAG_ACTIVE, - LOWPAN_IPHC_CTX_FLAG_COMPRESSION, -}; - -struct lowpan_iphc_ctx { - u8 id; - struct in6_addr pfx; - u8 plen; - unsigned long flags; -}; - -struct lowpan_iphc_ctx_table { - spinlock_t lock; - const struct lowpan_iphc_ctx_ops *ops; - struct lowpan_iphc_ctx table[LOWPAN_IPHC_CTX_TABLE_SIZE]; -}; - -static inline bool lowpan_iphc_ctx_is_active(const struct lowpan_iphc_ctx *ctx) -{ - return test_bit(LOWPAN_IPHC_CTX_FLAG_ACTIVE, &ctx->flags); -} - -static inline bool -lowpan_iphc_ctx_is_compression(const struct lowpan_iphc_ctx *ctx) -{ - return test_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags); -} - -struct lowpan_dev { - enum lowpan_lltypes lltype; - struct dentry *iface_debugfs; - struct lowpan_iphc_ctx_table ctx; - - /* must be last */ - u8 priv[0] __aligned(sizeof(void *)); -}; - -struct lowpan_802154_neigh { - __le16 short_addr; -}; - -static inline -struct lowpan_802154_neigh *lowpan_802154_neigh(void *neigh_priv) -{ - return neigh_priv; -} - -static inline -struct lowpan_dev *lowpan_dev(const struct net_device *dev) -{ - return netdev_priv(dev); -} - -/* private device info */ -struct lowpan_802154_dev { - struct net_device *wdev; /* wpan device ptr */ - u16 fragment_tag; -}; - -static inline struct -lowpan_802154_dev *lowpan_802154_dev(const struct net_device *dev) -{ - return (struct lowpan_802154_dev *)lowpan_dev(dev)->priv; -} - -struct lowpan_802154_cb { - u16 d_tag; - unsigned int d_size; - u8 d_offset; -}; - -static inline -struct lowpan_802154_cb *lowpan_802154_cb(const struct sk_buff *skb) -{ - BUILD_BUG_ON(sizeof(struct lowpan_802154_cb) > sizeof(skb->cb)); - return (struct lowpan_802154_cb *)skb->cb; -} - -static inline void lowpan_iphc_uncompress_eui64_lladdr(struct in6_addr *ipaddr, - const void *lladdr) -{ - /* fe:80::XXXX:XXXX:XXXX:XXXX - * \_________________/ - * hwaddr - */ - ipaddr->s6_addr[0] = 0xFE; - ipaddr->s6_addr[1] = 0x80; - memcpy(&ipaddr->s6_addr[8], lladdr, EUI64_ADDR_LEN); - /* second bit-flip (Universe/Local) - * is done according RFC2464 - */ - ipaddr->s6_addr[8] ^= 0x02; -} - -#ifdef DEBUG -/* print data in line */ -static inline void raw_dump_inline(const char *caller, char *msg, - const unsigned char *buf, int len) -{ - if (msg) - pr_debug("%s():%s: ", caller, msg); - - print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, buf, len, false); -} - -/* print data in a table format: - * - * addr: xx xx xx xx xx xx - * addr: xx xx xx xx xx xx - * ... - */ -static inline void raw_dump_table(const char *caller, char *msg, - const unsigned char *buf, int len) -{ - if (msg) - pr_debug("%s():%s:\n", caller, msg); - - print_hex_dump_debug("\t", DUMP_PREFIX_OFFSET, 16, 1, buf, len, false); -} -#else -static inline void raw_dump_table(const char *caller, char *msg, - const unsigned char *buf, int len) { } -static inline void raw_dump_inline(const char *caller, char *msg, - const unsigned char *buf, int len) { } -#endif - -/** - * lowpan_fetch_skb - getting inline data from 6LoWPAN header - * - * This function will pull data from sk buffer and put it into data to - * remove the 6LoWPAN inline data. This function returns true if the - * sk buffer is too small to pull the amount of data which is specified - * by len. - * - * @skb: the buffer where the inline data should be pulled from. - * @data: destination buffer for the inline data. - * @len: amount of data which should be pulled in bytes. - */ -static inline bool lowpan_fetch_skb(struct sk_buff *skb, void *data, - unsigned int len) -{ - if (unlikely(!pskb_may_pull(skb, len))) - return true; - - skb_copy_from_linear_data(skb, data, len); - skb_pull(skb, len); - - return false; -} - -static inline bool lowpan_802154_is_valid_src_short_addr(__le16 addr) -{ - /* First bit of addr is multicast, reserved or 802.15.4 specific */ - return !(addr & cpu_to_le16(0x8000)); -} - -static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data, - const size_t len) -{ - memcpy(*hc_ptr, data, len); - *hc_ptr += len; -} - -int lowpan_register_netdevice(struct net_device *dev, - enum lowpan_lltypes lltype); -int lowpan_register_netdev(struct net_device *dev, - enum lowpan_lltypes lltype); -void lowpan_unregister_netdevice(struct net_device *dev); -void lowpan_unregister_netdev(struct net_device *dev); - -/** - * lowpan_header_decompress - replace 6LoWPAN header with IPv6 header - * - * This function replaces the IPHC 6LoWPAN header which should be pointed at - * skb->data and skb_network_header, with the IPv6 header. - * It would be nice that the caller have the necessary headroom of IPv6 header - * and greatest Transport layer header, this would reduce the overhead for - * reallocate headroom. - * - * @skb: the buffer which should be manipulate. - * @dev: the lowpan net device pointer. - * @daddr: destination lladdr of mac header which is used for compression - * methods. - * @saddr: source lladdr of mac header which is used for compression - * methods. - */ -int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev, - const void *daddr, const void *saddr); - -/** - * lowpan_header_compress - replace IPv6 header with 6LoWPAN header - * - * This function replaces the IPv6 header which should be pointed at - * skb->data and skb_network_header, with the IPHC 6LoWPAN header. - * The caller need to be sure that the sk buffer is not shared and at have - * at least a headroom which is smaller or equal LOWPAN_IPHC_MAX_HEADER_LEN, - * which is the IPHC "more bytes than IPv6 header" at worst case. - * - * @skb: the buffer which should be manipulate. - * @dev: the lowpan net device pointer. - * @daddr: destination lladdr of mac header which is used for compression - * methods. - * @saddr: source lladdr of mac header which is used for compression - * methods. - */ -int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev, - const void *daddr, const void *saddr); - -#endif /* __6LOWPAN_H__ */ diff --git a/src/linux/include/net/Space.h b/src/linux/include/net/Space.h deleted file mode 100644 index 8a32771..0000000 --- a/src/linux/include/net/Space.h +++ /dev/null @@ -1,31 +0,0 @@ -/* A unified ethernet device probe. This is the easiest way to have every - * ethernet adaptor have the name "eth[0123...]". - */ - -struct net_device *hp100_probe(int unit); -struct net_device *ultra_probe(int unit); -struct net_device *wd_probe(int unit); -struct net_device *ne_probe(int unit); -struct net_device *fmv18x_probe(int unit); -struct net_device *i82596_probe(int unit); -struct net_device *ni65_probe(int unit); -struct net_device *sonic_probe(int unit); -struct net_device *smc_init(int unit); -struct net_device *atarilance_probe(int unit); -struct net_device *sun3lance_probe(int unit); -struct net_device *sun3_82586_probe(int unit); -struct net_device *apne_probe(int unit); -struct net_device *cs89x0_probe(int unit); -struct net_device *mvme147lance_probe(int unit); -struct net_device *tc515_probe(int unit); -struct net_device *lance_probe(int unit); -struct net_device *mac8390_probe(int unit); -struct net_device *mac89x0_probe(int unit); -struct net_device *cops_probe(int unit); -struct net_device *ltpc_probe(void); - -/* Fibre Channel adapters */ -int iph5526_probe(struct net_device *dev); - -/* SBNI adapters */ -int sbni_probe(int unit); diff --git a/src/linux/include/net/addrconf.h b/src/linux/include/net/addrconf.h deleted file mode 100644 index 8f998af..0000000 --- a/src/linux/include/net/addrconf.h +++ /dev/null @@ -1,408 +0,0 @@ -#ifndef _ADDRCONF_H -#define _ADDRCONF_H - -#define MAX_RTR_SOLICITATIONS -1 /* unlimited */ -#define RTR_SOLICITATION_INTERVAL (4*HZ) -#define RTR_SOLICITATION_MAX_INTERVAL (3600*HZ) /* 1 hour */ - -#define MIN_VALID_LIFETIME (2*3600) /* 2 hours */ - -#define TEMP_VALID_LIFETIME (7*86400) -#define TEMP_PREFERRED_LIFETIME (86400) -#define REGEN_MAX_RETRY (3) -#define MAX_DESYNC_FACTOR (600) - -#define ADDR_CHECK_FREQUENCY (120*HZ) - -#define IPV6_MAX_ADDRESSES 16 - -#define ADDRCONF_TIMER_FUZZ_MINUS (HZ > 50 ? HZ / 50 : 1) -#define ADDRCONF_TIMER_FUZZ (HZ / 4) -#define ADDRCONF_TIMER_FUZZ_MAX (HZ) - -#include -#include - -struct prefix_info { - __u8 type; - __u8 length; - __u8 prefix_len; - -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 onlink : 1, - autoconf : 1, - reserved : 6; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 reserved : 6, - autoconf : 1, - onlink : 1; -#else -#error "Please fix " -#endif - __be32 valid; - __be32 prefered; - __be32 reserved2; - - struct in6_addr prefix; -}; - - -#include -#include -#include - -#define IN6_ADDR_HSIZE_SHIFT 4 -#define IN6_ADDR_HSIZE (1 << IN6_ADDR_HSIZE_SHIFT) - -int addrconf_init(void); -void addrconf_cleanup(void); - -int addrconf_add_ifaddr(struct net *net, void __user *arg); -int addrconf_del_ifaddr(struct net *net, void __user *arg); -int addrconf_set_dstaddr(struct net *net, void __user *arg); - -int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, - const struct net_device *dev, int strict); -int ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr, - const struct net_device *dev, int strict, - u32 banned_flags); - -#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) -int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr); -#endif - -bool ipv6_chk_custom_prefix(const struct in6_addr *addr, - const unsigned int prefix_len, - struct net_device *dev); - -int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev); - -struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, - const struct in6_addr *addr, - struct net_device *dev, int strict); - -int ipv6_dev_get_saddr(struct net *net, const struct net_device *dev, - const struct in6_addr *daddr, unsigned int srcprefs, - struct in6_addr *saddr); -int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr, - u32 banned_flags); -int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, - u32 banned_flags); -int ipv4_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2, - bool match_wildcard); -int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2, - bool match_wildcard); -void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr); -void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr); - -void addrconf_add_linklocal(struct inet6_dev *idev, - const struct in6_addr *addr, u32 flags); - -int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev, - const struct prefix_info *pinfo, - struct inet6_dev *in6_dev, - const struct in6_addr *addr, int addr_type, - u32 addr_flags, bool sllao, bool tokenized, - __u32 valid_lft, u32 prefered_lft); - -static inline int addrconf_ifid_eui48(u8 *eui, struct net_device *dev) -{ - if (dev->addr_len != ETH_ALEN) - return -1; - memcpy(eui, dev->dev_addr, 3); - memcpy(eui + 5, dev->dev_addr + 3, 3); - - /* - * The zSeries OSA network cards can be shared among various - * OS instances, but the OSA cards have only one MAC address. - * This leads to duplicate address conflicts in conjunction - * with IPv6 if more than one instance uses the same card. - * - * The driver for these cards can deliver a unique 16-bit - * identifier for each instance sharing the same card. It is - * placed instead of 0xFFFE in the interface identifier. The - * "u" bit of the interface identifier is not inverted in this - * case. Hence the resulting interface identifier has local - * scope according to RFC2373. - */ - if (dev->dev_id) { - eui[3] = (dev->dev_id >> 8) & 0xFF; - eui[4] = dev->dev_id & 0xFF; - } else { - eui[3] = 0xFF; - eui[4] = 0xFE; - eui[0] ^= 2; - } - return 0; -} - -static inline unsigned long addrconf_timeout_fixup(u32 timeout, - unsigned int unit) -{ - if (timeout == 0xffffffff) - return ~0UL; - - /* - * Avoid arithmetic overflow. - * Assuming unit is constant and non-zero, this "if" statement - * will go away on 64bit archs. - */ - if (0xfffffffe > LONG_MAX / unit && timeout > LONG_MAX / unit) - return LONG_MAX / unit; - - return timeout; -} - -static inline int addrconf_finite_timeout(unsigned long timeout) -{ - return ~timeout; -} - -/* - * IPv6 Address Label subsystem (addrlabel.c) - */ -int ipv6_addr_label_init(void); -void ipv6_addr_label_cleanup(void); -void ipv6_addr_label_rtnl_register(void); -u32 ipv6_addr_label(struct net *net, const struct in6_addr *addr, - int type, int ifindex); - -/* - * multicast prototypes (mcast.c) - */ -int ipv6_sock_mc_join(struct sock *sk, int ifindex, - const struct in6_addr *addr); -int ipv6_sock_mc_drop(struct sock *sk, int ifindex, - const struct in6_addr *addr); -void __ipv6_sock_mc_close(struct sock *sk); -void ipv6_sock_mc_close(struct sock *sk); -bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr, - const struct in6_addr *src_addr); - -int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr); -int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr); -int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr); -void ipv6_mc_up(struct inet6_dev *idev); -void ipv6_mc_down(struct inet6_dev *idev); -void ipv6_mc_unmap(struct inet6_dev *idev); -void ipv6_mc_remap(struct inet6_dev *idev); -void ipv6_mc_init_dev(struct inet6_dev *idev); -void ipv6_mc_destroy_dev(struct inet6_dev *idev); -int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed); -void addrconf_dad_failure(struct inet6_ifaddr *ifp); - -bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group, - const struct in6_addr *src_addr); - -void ipv6_mc_dad_complete(struct inet6_dev *idev); - -/* A stub used by vxlan module. This is ugly, ideally these - * symbols should be built into the core kernel. - */ -struct ipv6_stub { - int (*ipv6_sock_mc_join)(struct sock *sk, int ifindex, - const struct in6_addr *addr); - int (*ipv6_sock_mc_drop)(struct sock *sk, int ifindex, - const struct in6_addr *addr); - int (*ipv6_dst_lookup)(struct net *net, struct sock *sk, - struct dst_entry **dst, struct flowi6 *fl6); - void (*udpv6_encap_enable)(void); - void (*ndisc_send_na)(struct net_device *dev, const struct in6_addr *daddr, - const struct in6_addr *solicited_addr, - bool router, bool solicited, bool override, bool inc_opt); - struct neigh_table *nd_tbl; -}; -extern const struct ipv6_stub *ipv6_stub __read_mostly; - -/* - * identify MLD packets for MLD filter exceptions - */ -static inline bool ipv6_is_mld(struct sk_buff *skb, int nexthdr, int offset) -{ - struct icmp6hdr *hdr; - - if (nexthdr != IPPROTO_ICMPV6 || - !pskb_network_may_pull(skb, offset + sizeof(struct icmp6hdr))) - return false; - - hdr = (struct icmp6hdr *)(skb_network_header(skb) + offset); - - switch (hdr->icmp6_type) { - case ICMPV6_MGM_QUERY: - case ICMPV6_MGM_REPORT: - case ICMPV6_MGM_REDUCTION: - case ICMPV6_MLD2_REPORT: - return true; - default: - break; - } - return false; -} - -void addrconf_prefix_rcv(struct net_device *dev, - u8 *opt, int len, bool sllao); - -/* - * anycast prototypes (anycast.c) - */ -int ipv6_sock_ac_join(struct sock *sk, int ifindex, - const struct in6_addr *addr); -int ipv6_sock_ac_drop(struct sock *sk, int ifindex, - const struct in6_addr *addr); -void ipv6_sock_ac_close(struct sock *sk); - -int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr); -int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr); -void ipv6_ac_destroy_dev(struct inet6_dev *idev); -bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev, - const struct in6_addr *addr); -bool ipv6_chk_acast_addr_src(struct net *net, struct net_device *dev, - const struct in6_addr *addr); - -/* Device notifier */ -int register_inet6addr_notifier(struct notifier_block *nb); -int unregister_inet6addr_notifier(struct notifier_block *nb); -int inet6addr_notifier_call_chain(unsigned long val, void *v); - -void inet6_netconf_notify_devconf(struct net *net, int type, int ifindex, - struct ipv6_devconf *devconf); - -/** - * __in6_dev_get - get inet6_dev pointer from netdevice - * @dev: network device - * - * Caller must hold rcu_read_lock or RTNL, because this function - * does not take a reference on the inet6_dev. - */ -static inline struct inet6_dev *__in6_dev_get(const struct net_device *dev) -{ - return rcu_dereference_rtnl(dev->ip6_ptr); -} - -/** - * in6_dev_get - get inet6_dev pointer from netdevice - * @dev: network device - * - * This version can be used in any context, and takes a reference - * on the inet6_dev. Callers must use in6_dev_put() later to - * release this reference. - */ -static inline struct inet6_dev *in6_dev_get(const struct net_device *dev) -{ - struct inet6_dev *idev; - - rcu_read_lock(); - idev = rcu_dereference(dev->ip6_ptr); - if (idev) - atomic_inc(&idev->refcnt); - rcu_read_unlock(); - return idev; -} - -static inline struct neigh_parms *__in6_dev_nd_parms_get_rcu(const struct net_device *dev) -{ - struct inet6_dev *idev = __in6_dev_get(dev); - - return idev ? idev->nd_parms : NULL; -} - -void in6_dev_finish_destroy(struct inet6_dev *idev); - -static inline void in6_dev_put(struct inet6_dev *idev) -{ - if (atomic_dec_and_test(&idev->refcnt)) - in6_dev_finish_destroy(idev); -} - -static inline void __in6_dev_put(struct inet6_dev *idev) -{ - atomic_dec(&idev->refcnt); -} - -static inline void in6_dev_hold(struct inet6_dev *idev) -{ - atomic_inc(&idev->refcnt); -} - -void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp); - -static inline void in6_ifa_put(struct inet6_ifaddr *ifp) -{ - if (atomic_dec_and_test(&ifp->refcnt)) - inet6_ifa_finish_destroy(ifp); -} - -static inline void __in6_ifa_put(struct inet6_ifaddr *ifp) -{ - atomic_dec(&ifp->refcnt); -} - -static inline void in6_ifa_hold(struct inet6_ifaddr *ifp) -{ - atomic_inc(&ifp->refcnt); -} - - -/* - * compute link-local solicited-node multicast address - */ - -static inline void addrconf_addr_solict_mult(const struct in6_addr *addr, - struct in6_addr *solicited) -{ - ipv6_addr_set(solicited, - htonl(0xFF020000), 0, - htonl(0x1), - htonl(0xFF000000) | addr->s6_addr32[3]); -} - -static inline bool ipv6_addr_is_ll_all_nodes(const struct in6_addr *addr) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 - __be64 *p = (__be64 *)addr; - return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) | (p[1] ^ cpu_to_be64(1))) == 0UL; -#else - return ((addr->s6_addr32[0] ^ htonl(0xff020000)) | - addr->s6_addr32[1] | addr->s6_addr32[2] | - (addr->s6_addr32[3] ^ htonl(0x00000001))) == 0; -#endif -} - -static inline bool ipv6_addr_is_ll_all_routers(const struct in6_addr *addr) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 - __be64 *p = (__be64 *)addr; - return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) | (p[1] ^ cpu_to_be64(2))) == 0UL; -#else - return ((addr->s6_addr32[0] ^ htonl(0xff020000)) | - addr->s6_addr32[1] | addr->s6_addr32[2] | - (addr->s6_addr32[3] ^ htonl(0x00000002))) == 0; -#endif -} - -static inline bool ipv6_addr_is_isatap(const struct in6_addr *addr) -{ - return (addr->s6_addr32[2] | htonl(0x02000000)) == htonl(0x02005EFE); -} - -static inline bool ipv6_addr_is_solict_mult(const struct in6_addr *addr) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 - __be64 *p = (__be64 *)addr; - return ((p[0] ^ cpu_to_be64(0xff02000000000000UL)) | - ((p[1] ^ cpu_to_be64(0x00000001ff000000UL)) & - cpu_to_be64(0xffffffffff000000UL))) == 0UL; -#else - return ((addr->s6_addr32[0] ^ htonl(0xff020000)) | - addr->s6_addr32[1] | - (addr->s6_addr32[2] ^ htonl(0x00000001)) | - (addr->s6_addr[12] ^ 0xff)) == 0; -#endif -} - -#ifdef CONFIG_PROC_FS -int if6_proc_init(void); -void if6_proc_exit(void); -#endif - -#endif diff --git a/src/linux/include/net/af_ieee802154.h b/src/linux/include/net/af_ieee802154.h deleted file mode 100644 index a5563d2..0000000 --- a/src/linux/include/net/af_ieee802154.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * IEEE 802.15.4 interface for userspace - * - * Copyright 2007, 2008 Siemens AG - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Written by: - * Sergey Lapin - * Dmitry Eremin-Solenikov - */ - -#ifndef _AF_IEEE802154_H -#define _AF_IEEE802154_H - -#include /* for sa_family_t */ - -enum { - IEEE802154_ADDR_NONE = 0x0, - /* RESERVED = 0x01, */ - IEEE802154_ADDR_SHORT = 0x2, /* 16-bit address + PANid */ - IEEE802154_ADDR_LONG = 0x3, /* 64-bit address + PANid */ -}; - -/* address length, octets */ -#define IEEE802154_ADDR_LEN 8 - -struct ieee802154_addr_sa { - int addr_type; - u16 pan_id; - union { - u8 hwaddr[IEEE802154_ADDR_LEN]; - u16 short_addr; - }; -}; - -#define IEEE802154_PANID_BROADCAST 0xffff -#define IEEE802154_ADDR_BROADCAST 0xffff -#define IEEE802154_ADDR_UNDEF 0xfffe - -struct sockaddr_ieee802154 { - sa_family_t family; /* AF_IEEE802154 */ - struct ieee802154_addr_sa addr; -}; - -/* get/setsockopt */ -#define SOL_IEEE802154 0 - -#define WPAN_WANTACK 0 -#define WPAN_SECURITY 1 -#define WPAN_SECURITY_LEVEL 2 - -#define WPAN_SECURITY_DEFAULT 0 -#define WPAN_SECURITY_OFF 1 -#define WPAN_SECURITY_ON 2 - -#define WPAN_SECURITY_LEVEL_DEFAULT (-1) - -#endif diff --git a/src/linux/include/net/arp.h b/src/linux/include/net/arp.h deleted file mode 100644 index 5e0f891..0000000 --- a/src/linux/include/net/arp.h +++ /dev/null @@ -1,54 +0,0 @@ -/* linux/net/inet/arp.h */ -#ifndef _ARP_H -#define _ARP_H - -#include -#include -#include - - -extern struct neigh_table arp_tbl; - -static inline u32 arp_hashfn(const void *pkey, const struct net_device *dev, u32 *hash_rnd) -{ - u32 key = *(const u32 *)pkey; - u32 val = key ^ hash32_ptr(dev); - - return val * hash_rnd[0]; -} - -static inline struct neighbour *__ipv4_neigh_lookup_noref(struct net_device *dev, u32 key) -{ - return ___neigh_lookup_noref(&arp_tbl, neigh_key_eq32, arp_hashfn, &key, dev); -} - -static inline struct neighbour *__ipv4_neigh_lookup(struct net_device *dev, u32 key) -{ - struct neighbour *n; - - rcu_read_lock_bh(); - n = __ipv4_neigh_lookup_noref(dev, key); - if (n && !atomic_inc_not_zero(&n->refcnt)) - n = NULL; - rcu_read_unlock_bh(); - - return n; -} - -void arp_init(void); -int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg); -void arp_send(int type, int ptype, __be32 dest_ip, - struct net_device *dev, __be32 src_ip, - const unsigned char *dest_hw, - const unsigned char *src_hw, const unsigned char *th); -int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir); -void arp_ifdown(struct net_device *dev); - -struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, - struct net_device *dev, __be32 src_ip, - const unsigned char *dest_hw, - const unsigned char *src_hw, - const unsigned char *target_hw); -void arp_xmit(struct sk_buff *skb); - -#endif /* _ARP_H */ diff --git a/src/linux/include/net/ax25.h b/src/linux/include/net/ax25.h deleted file mode 100644 index e602f81..0000000 --- a/src/linux/include/net/ax25.h +++ /dev/null @@ -1,467 +0,0 @@ -/* - * Declarations of AX.25 type objects. - * - * Alan Cox (GW4PTS) 10/11/93 - */ -#ifndef _AX25_H -#define _AX25_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#define AX25_T1CLAMPLO 1 -#define AX25_T1CLAMPHI (30 * HZ) - -#define AX25_BPQ_HEADER_LEN 16 -#define AX25_KISS_HEADER_LEN 1 - -#define AX25_HEADER_LEN 17 -#define AX25_ADDR_LEN 7 -#define AX25_DIGI_HEADER_LEN (AX25_MAX_DIGIS * AX25_ADDR_LEN) -#define AX25_MAX_HEADER_LEN (AX25_HEADER_LEN + AX25_DIGI_HEADER_LEN) - -/* AX.25 Protocol IDs */ -#define AX25_P_ROSE 0x01 -#define AX25_P_VJCOMP 0x06 /* Compressed TCP/IP packet */ - /* Van Jacobsen (RFC 1144) */ -#define AX25_P_VJUNCOMP 0x07 /* Uncompressed TCP/IP packet */ - /* Van Jacobsen (RFC 1144) */ -#define AX25_P_SEGMENT 0x08 /* Segmentation fragment */ -#define AX25_P_TEXNET 0xc3 /* TEXTNET datagram protocol */ -#define AX25_P_LQ 0xc4 /* Link Quality Protocol */ -#define AX25_P_ATALK 0xca /* Appletalk */ -#define AX25_P_ATALK_ARP 0xcb /* Appletalk ARP */ -#define AX25_P_IP 0xcc /* ARPA Internet Protocol */ -#define AX25_P_ARP 0xcd /* ARPA Address Resolution */ -#define AX25_P_FLEXNET 0xce /* FlexNet */ -#define AX25_P_NETROM 0xcf /* NET/ROM */ -#define AX25_P_TEXT 0xF0 /* No layer 3 protocol impl. */ - -/* AX.25 Segment control values */ -#define AX25_SEG_REM 0x7F -#define AX25_SEG_FIRST 0x80 - -#define AX25_CBIT 0x80 /* Command/Response bit */ -#define AX25_EBIT 0x01 /* HDLC Address Extension bit */ -#define AX25_HBIT 0x80 /* Has been repeated bit */ - -#define AX25_SSSID_SPARE 0x60 /* Unused bits in SSID for standard AX.25 */ -#define AX25_ESSID_SPARE 0x20 /* Unused bits in SSID for extended AX.25 */ -#define AX25_DAMA_FLAG 0x20 /* Well, it is *NOT* unused! (dl1bke 951121 */ - -#define AX25_COND_ACK_PENDING 0x01 -#define AX25_COND_REJECT 0x02 -#define AX25_COND_PEER_RX_BUSY 0x04 -#define AX25_COND_OWN_RX_BUSY 0x08 -#define AX25_COND_DAMA_MODE 0x10 - -#ifndef _LINUX_NETDEVICE_H -#include -#endif - -/* Upper sub-layer (LAPB) definitions */ - -/* Control field templates */ -#define AX25_I 0x00 /* Information frames */ -#define AX25_S 0x01 /* Supervisory frames */ -#define AX25_RR 0x01 /* Receiver ready */ -#define AX25_RNR 0x05 /* Receiver not ready */ -#define AX25_REJ 0x09 /* Reject */ -#define AX25_U 0x03 /* Unnumbered frames */ -#define AX25_SABM 0x2f /* Set Asynchronous Balanced Mode */ -#define AX25_SABME 0x6f /* Set Asynchronous Balanced Mode Extended */ -#define AX25_DISC 0x43 /* Disconnect */ -#define AX25_DM 0x0f /* Disconnected mode */ -#define AX25_UA 0x63 /* Unnumbered acknowledge */ -#define AX25_FRMR 0x87 /* Frame reject */ -#define AX25_UI 0x03 /* Unnumbered information */ -#define AX25_XID 0xaf /* Exchange information */ -#define AX25_TEST 0xe3 /* Test */ - -#define AX25_PF 0x10 /* Poll/final bit for standard AX.25 */ -#define AX25_EPF 0x01 /* Poll/final bit for extended AX.25 */ - -#define AX25_ILLEGAL 0x100 /* Impossible to be a real frame type */ - -#define AX25_POLLOFF 0 -#define AX25_POLLON 1 - -/* AX25 L2 C-bit */ -#define AX25_COMMAND 1 -#define AX25_RESPONSE 2 - -/* Define Link State constants. */ - -enum { - AX25_STATE_0, /* Listening */ - AX25_STATE_1, /* SABM sent */ - AX25_STATE_2, /* DISC sent */ - AX25_STATE_3, /* Established */ - AX25_STATE_4 /* Recovery */ -}; - -#define AX25_MODULUS 8 /* Standard AX.25 modulus */ -#define AX25_EMODULUS 128 /* Extended AX.25 modulus */ - -enum { - AX25_PROTO_STD_SIMPLEX, - AX25_PROTO_STD_DUPLEX, -#ifdef CONFIG_AX25_DAMA_SLAVE - AX25_PROTO_DAMA_SLAVE, -#ifdef CONFIG_AX25_DAMA_MASTER - AX25_PROTO_DAMA_MASTER, -#define AX25_PROTO_MAX AX25_PROTO_DAMA_MASTER -#endif -#endif - __AX25_PROTO_MAX, - AX25_PROTO_MAX = __AX25_PROTO_MAX -1 -}; - -enum { - AX25_VALUES_IPDEFMODE, /* 0=DG 1=VC */ - AX25_VALUES_AXDEFMODE, /* 0=Normal 1=Extended Seq Nos */ - AX25_VALUES_BACKOFF, /* 0=None 1=Linear 2=Exponential */ - AX25_VALUES_CONMODE, /* Allow connected modes - 0=No 1=no "PID text" 2=all PIDs */ - AX25_VALUES_WINDOW, /* Default window size for standard AX.25 */ - AX25_VALUES_EWINDOW, /* Default window size for extended AX.25 */ - AX25_VALUES_T1, /* Default T1 timeout value */ - AX25_VALUES_T2, /* Default T2 timeout value */ - AX25_VALUES_T3, /* Default T3 timeout value */ - AX25_VALUES_IDLE, /* Connected mode idle timer */ - AX25_VALUES_N2, /* Default N2 value */ - AX25_VALUES_PACLEN, /* AX.25 MTU */ - AX25_VALUES_PROTOCOL, /* Std AX.25, DAMA Slave, DAMA Master */ - AX25_VALUES_DS_TIMEOUT, /* DAMA Slave timeout */ - AX25_MAX_VALUES /* THIS MUST REMAIN THE LAST ENTRY OF THIS LIST */ -}; - -#define AX25_DEF_IPDEFMODE 0 /* Datagram */ -#define AX25_DEF_AXDEFMODE 0 /* Normal */ -#define AX25_DEF_BACKOFF 1 /* Linear backoff */ -#define AX25_DEF_CONMODE 2 /* Connected mode allowed */ -#define AX25_DEF_WINDOW 2 /* Window=2 */ -#define AX25_DEF_EWINDOW 32 /* Module-128 Window=32 */ -#define AX25_DEF_T1 10000 /* T1=10s */ -#define AX25_DEF_T2 3000 /* T2=3s */ -#define AX25_DEF_T3 300000 /* T3=300s */ -#define AX25_DEF_N2 10 /* N2=10 */ -#define AX25_DEF_IDLE 0 /* Idle=None */ -#define AX25_DEF_PACLEN 256 /* Paclen=256 */ -#define AX25_DEF_PROTOCOL AX25_PROTO_STD_SIMPLEX /* Standard AX.25 */ -#define AX25_DEF_DS_TIMEOUT 180000 /* DAMA timeout 3 minutes */ - -typedef struct ax25_uid_assoc { - struct hlist_node uid_node; - atomic_t refcount; - kuid_t uid; - ax25_address call; -} ax25_uid_assoc; - -#define ax25_uid_for_each(__ax25, list) \ - hlist_for_each_entry(__ax25, list, uid_node) - -#define ax25_uid_hold(ax25) \ - atomic_inc(&((ax25)->refcount)) - -static inline void ax25_uid_put(ax25_uid_assoc *assoc) -{ - if (atomic_dec_and_test(&assoc->refcount)) { - kfree(assoc); - } -} - -typedef struct { - ax25_address calls[AX25_MAX_DIGIS]; - unsigned char repeated[AX25_MAX_DIGIS]; - unsigned char ndigi; - signed char lastrepeat; -} ax25_digi; - -typedef struct ax25_route { - struct ax25_route *next; - atomic_t refcount; - ax25_address callsign; - struct net_device *dev; - ax25_digi *digipeat; - char ip_mode; -} ax25_route; - -static inline void ax25_hold_route(ax25_route *ax25_rt) -{ - atomic_inc(&ax25_rt->refcount); -} - -void __ax25_put_route(ax25_route *ax25_rt); - -static inline void ax25_put_route(ax25_route *ax25_rt) -{ - if (atomic_dec_and_test(&ax25_rt->refcount)) - __ax25_put_route(ax25_rt); -} - -typedef struct { - char slave; /* slave_mode? */ - struct timer_list slave_timer; /* timeout timer */ - unsigned short slave_timeout; /* when? */ -} ax25_dama_info; - -struct ctl_table; - -typedef struct ax25_dev { - struct ax25_dev *next; - struct net_device *dev; - struct net_device *forward; - struct ctl_table_header *sysheader; - int values[AX25_MAX_VALUES]; -#if defined(CONFIG_AX25_DAMA_SLAVE) || defined(CONFIG_AX25_DAMA_MASTER) - ax25_dama_info dama; -#endif -} ax25_dev; - -typedef struct ax25_cb { - struct hlist_node ax25_node; - ax25_address source_addr, dest_addr; - ax25_digi *digipeat; - ax25_dev *ax25_dev; - unsigned char iamdigi; - unsigned char state, modulus, pidincl; - unsigned short vs, vr, va; - unsigned char condition, backoff; - unsigned char n2, n2count; - struct timer_list t1timer, t2timer, t3timer, idletimer; - unsigned long t1, t2, t3, idle, rtt; - unsigned short paclen, fragno, fraglen; - struct sk_buff_head write_queue; - struct sk_buff_head reseq_queue; - struct sk_buff_head ack_queue; - struct sk_buff_head frag_queue; - unsigned char window; - struct timer_list timer, dtimer; - struct sock *sk; /* Backlink to socket */ - atomic_t refcount; -} ax25_cb; - -struct ax25_sock { - struct sock sk; - struct ax25_cb *cb; -}; - -static inline struct ax25_sock *ax25_sk(const struct sock *sk) -{ - return (struct ax25_sock *) sk; -} - -static inline struct ax25_cb *sk_to_ax25(const struct sock *sk) -{ - return ax25_sk(sk)->cb; -} - -#define ax25_for_each(__ax25, list) \ - hlist_for_each_entry(__ax25, list, ax25_node) - -#define ax25_cb_hold(__ax25) \ - atomic_inc(&((__ax25)->refcount)) - -static __inline__ void ax25_cb_put(ax25_cb *ax25) -{ - if (atomic_dec_and_test(&ax25->refcount)) { - kfree(ax25->digipeat); - kfree(ax25); - } -} - -static inline __be16 ax25_type_trans(struct sk_buff *skb, struct net_device *dev) -{ - skb->dev = dev; - skb_reset_mac_header(skb); - skb->pkt_type = PACKET_HOST; - return htons(ETH_P_AX25); -} - -/* af_ax25.c */ -extern struct hlist_head ax25_list; -extern spinlock_t ax25_list_lock; -void ax25_cb_add(ax25_cb *); -struct sock *ax25_find_listener(ax25_address *, int, struct net_device *, int); -struct sock *ax25_get_socket(ax25_address *, ax25_address *, int); -ax25_cb *ax25_find_cb(ax25_address *, ax25_address *, ax25_digi *, - struct net_device *); -void ax25_send_to_raw(ax25_address *, struct sk_buff *, int); -void ax25_destroy_socket(ax25_cb *); -ax25_cb * __must_check ax25_create_cb(void); -void ax25_fillin_cb(ax25_cb *, ax25_dev *); -struct sock *ax25_make_new(struct sock *, struct ax25_dev *); - -/* ax25_addr.c */ -extern const ax25_address ax25_bcast; -extern const ax25_address ax25_defaddr; -extern const ax25_address null_ax25_address; -char *ax2asc(char *buf, const ax25_address *); -void asc2ax(ax25_address *addr, const char *callsign); -int ax25cmp(const ax25_address *, const ax25_address *); -int ax25digicmp(const ax25_digi *, const ax25_digi *); -const unsigned char *ax25_addr_parse(const unsigned char *, int, - ax25_address *, ax25_address *, ax25_digi *, int *, int *); -int ax25_addr_build(unsigned char *, const ax25_address *, - const ax25_address *, const ax25_digi *, int, int); -int ax25_addr_size(const ax25_digi *); -void ax25_digi_invert(const ax25_digi *, ax25_digi *); - -/* ax25_dev.c */ -extern ax25_dev *ax25_dev_list; -extern spinlock_t ax25_dev_lock; - -static inline ax25_dev *ax25_dev_ax25dev(struct net_device *dev) -{ - return dev->ax25_ptr; -} - -ax25_dev *ax25_addr_ax25dev(ax25_address *); -void ax25_dev_device_up(struct net_device *); -void ax25_dev_device_down(struct net_device *); -int ax25_fwd_ioctl(unsigned int, struct ax25_fwd_struct *); -struct net_device *ax25_fwd_dev(struct net_device *); -void ax25_dev_free(void); - -/* ax25_ds_in.c */ -int ax25_ds_frame_in(ax25_cb *, struct sk_buff *, int); - -/* ax25_ds_subr.c */ -void ax25_ds_nr_error_recovery(ax25_cb *); -void ax25_ds_enquiry_response(ax25_cb *); -void ax25_ds_establish_data_link(ax25_cb *); -void ax25_dev_dama_off(ax25_dev *); -void ax25_dama_on(ax25_cb *); -void ax25_dama_off(ax25_cb *); - -/* ax25_ds_timer.c */ -void ax25_ds_setup_timer(ax25_dev *); -void ax25_ds_set_timer(ax25_dev *); -void ax25_ds_del_timer(ax25_dev *); -void ax25_ds_timer(ax25_cb *); -void ax25_ds_t1_timeout(ax25_cb *); -void ax25_ds_heartbeat_expiry(ax25_cb *); -void ax25_ds_t3timer_expiry(ax25_cb *); -void ax25_ds_idletimer_expiry(ax25_cb *); - -/* ax25_iface.c */ - -struct ax25_protocol { - struct ax25_protocol *next; - unsigned int pid; - int (*func)(struct sk_buff *, ax25_cb *); -}; - -void ax25_register_pid(struct ax25_protocol *ap); -void ax25_protocol_release(unsigned int); - -struct ax25_linkfail { - struct hlist_node lf_node; - void (*func)(ax25_cb *, int); -}; - -void ax25_linkfail_register(struct ax25_linkfail *lf); -void ax25_linkfail_release(struct ax25_linkfail *lf); -int __must_check ax25_listen_register(ax25_address *, struct net_device *); -void ax25_listen_release(ax25_address *, struct net_device *); -int(*ax25_protocol_function(unsigned int))(struct sk_buff *, ax25_cb *); -int ax25_listen_mine(ax25_address *, struct net_device *); -void ax25_link_failed(ax25_cb *, int); -int ax25_protocol_is_registered(unsigned int); - -/* ax25_in.c */ -int ax25_rx_iframe(ax25_cb *, struct sk_buff *); -int ax25_kiss_rcv(struct sk_buff *, struct net_device *, struct packet_type *, - struct net_device *); - -/* ax25_ip.c */ -netdev_tx_t ax25_ip_xmit(struct sk_buff *skb); -extern const struct header_ops ax25_header_ops; - -/* ax25_out.c */ -ax25_cb *ax25_send_frame(struct sk_buff *, int, ax25_address *, ax25_address *, - ax25_digi *, struct net_device *); -void ax25_output(ax25_cb *, int, struct sk_buff *); -void ax25_kick(ax25_cb *); -void ax25_transmit_buffer(ax25_cb *, struct sk_buff *, int); -void ax25_queue_xmit(struct sk_buff *skb, struct net_device *dev); -int ax25_check_iframes_acked(ax25_cb *, unsigned short); - -/* ax25_route.c */ -void ax25_rt_device_down(struct net_device *); -int ax25_rt_ioctl(unsigned int, void __user *); -extern const struct file_operations ax25_route_fops; -ax25_route *ax25_get_route(ax25_address *addr, struct net_device *dev); -int ax25_rt_autobind(ax25_cb *, ax25_address *); -struct sk_buff *ax25_rt_build_path(struct sk_buff *, ax25_address *, - ax25_address *, ax25_digi *); -void ax25_rt_free(void); - -/* ax25_std_in.c */ -int ax25_std_frame_in(ax25_cb *, struct sk_buff *, int); - -/* ax25_std_subr.c */ -void ax25_std_nr_error_recovery(ax25_cb *); -void ax25_std_establish_data_link(ax25_cb *); -void ax25_std_transmit_enquiry(ax25_cb *); -void ax25_std_enquiry_response(ax25_cb *); -void ax25_std_timeout_response(ax25_cb *); - -/* ax25_std_timer.c */ -void ax25_std_heartbeat_expiry(ax25_cb *); -void ax25_std_t1timer_expiry(ax25_cb *); -void ax25_std_t2timer_expiry(ax25_cb *); -void ax25_std_t3timer_expiry(ax25_cb *); -void ax25_std_idletimer_expiry(ax25_cb *); - -/* ax25_subr.c */ -void ax25_clear_queues(ax25_cb *); -void ax25_frames_acked(ax25_cb *, unsigned short); -void ax25_requeue_frames(ax25_cb *); -int ax25_validate_nr(ax25_cb *, unsigned short); -int ax25_decode(ax25_cb *, struct sk_buff *, int *, int *, int *); -void ax25_send_control(ax25_cb *, int, int, int); -void ax25_return_dm(struct net_device *, ax25_address *, ax25_address *, - ax25_digi *); -void ax25_calculate_t1(ax25_cb *); -void ax25_calculate_rtt(ax25_cb *); -void ax25_disconnect(ax25_cb *, int); - -/* ax25_timer.c */ -void ax25_setup_timers(ax25_cb *); -void ax25_start_heartbeat(ax25_cb *); -void ax25_start_t1timer(ax25_cb *); -void ax25_start_t2timer(ax25_cb *); -void ax25_start_t3timer(ax25_cb *); -void ax25_start_idletimer(ax25_cb *); -void ax25_stop_heartbeat(ax25_cb *); -void ax25_stop_t1timer(ax25_cb *); -void ax25_stop_t2timer(ax25_cb *); -void ax25_stop_t3timer(ax25_cb *); -void ax25_stop_idletimer(ax25_cb *); -int ax25_t1timer_running(ax25_cb *); -unsigned long ax25_display_timer(struct timer_list *); - -/* ax25_uid.c */ -extern int ax25_uid_policy; -ax25_uid_assoc *ax25_findbyuid(kuid_t); -int __must_check ax25_uid_ioctl(int, struct sockaddr_ax25 *); -extern const struct file_operations ax25_uid_fops; -void ax25_uid_free(void); - -/* sysctl_net_ax25.c */ -#ifdef CONFIG_SYSCTL -int ax25_register_dev_sysctl(ax25_dev *ax25_dev); -void ax25_unregister_dev_sysctl(ax25_dev *ax25_dev); -#else -static inline int ax25_register_dev_sysctl(ax25_dev *ax25_dev) { return 0; } -static inline void ax25_unregister_dev_sysctl(ax25_dev *ax25_dev) {} -#endif /* CONFIG_SYSCTL */ - -#endif diff --git a/src/linux/include/net/busy_poll.h b/src/linux/include/net/busy_poll.h deleted file mode 100644 index 2fbeb13..0000000 --- a/src/linux/include/net/busy_poll.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * net busy poll support - * Copyright(c) 2013 Intel Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Author: Eliezer Tamir - * - * Contact Information: - * e1000-devel Mailing List - */ - -#ifndef _LINUX_NET_BUSY_POLL_H -#define _LINUX_NET_BUSY_POLL_H - -#include -#include - -#ifdef CONFIG_NET_RX_BUSY_POLL - -struct napi_struct; -extern unsigned int sysctl_net_busy_read __read_mostly; -extern unsigned int sysctl_net_busy_poll __read_mostly; - -/* return values from ndo_ll_poll */ -#define LL_FLUSH_FAILED -1 -#define LL_FLUSH_BUSY -2 - -static inline bool net_busy_loop_on(void) -{ - return sysctl_net_busy_poll; -} - -static inline u64 busy_loop_us_clock(void) -{ - return local_clock() >> 10; -} - -static inline unsigned long sk_busy_loop_end_time(struct sock *sk) -{ - return busy_loop_us_clock() + ACCESS_ONCE(sk->sk_ll_usec); -} - -/* in poll/select we use the global sysctl_net_ll_poll value */ -static inline unsigned long busy_loop_end_time(void) -{ - return busy_loop_us_clock() + ACCESS_ONCE(sysctl_net_busy_poll); -} - -static inline bool sk_can_busy_loop(struct sock *sk) -{ - return sk->sk_ll_usec && sk->sk_napi_id && - !need_resched() && !signal_pending(current); -} - - -static inline bool busy_loop_timeout(unsigned long end_time) -{ - unsigned long now = busy_loop_us_clock(); - - return time_after(now, end_time); -} - -bool sk_busy_loop(struct sock *sk, int nonblock); - -/* used in the NIC receive handler to mark the skb */ -static inline void skb_mark_napi_id(struct sk_buff *skb, - struct napi_struct *napi) -{ - skb->napi_id = napi->napi_id; -} - -/* used in the protocol hanlder to propagate the napi_id to the socket */ -static inline void sk_mark_napi_id(struct sock *sk, struct sk_buff *skb) -{ - sk->sk_napi_id = skb->napi_id; -} - -#else /* CONFIG_NET_RX_BUSY_POLL */ -static inline unsigned long net_busy_loop_on(void) -{ - return 0; -} - -static inline unsigned long busy_loop_end_time(void) -{ - return 0; -} - -static inline bool sk_can_busy_loop(struct sock *sk) -{ - return false; -} - -static inline void skb_mark_napi_id(struct sk_buff *skb, - struct napi_struct *napi) -{ -} - -static inline void sk_mark_napi_id(struct sock *sk, struct sk_buff *skb) -{ -} - -static inline bool busy_loop_timeout(unsigned long end_time) -{ - return true; -} - -static inline bool sk_busy_loop(struct sock *sk, int nonblock) -{ - return false; -} - -#endif /* CONFIG_NET_RX_BUSY_POLL */ -#endif /* _LINUX_NET_BUSY_POLL_H */ diff --git a/src/linux/include/net/calipso.h b/src/linux/include/net/calipso.h deleted file mode 100644 index b1b30cd..0000000 --- a/src/linux/include/net/calipso.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * CALIPSO - Common Architecture Label IPv6 Security Option - * - * This is an implementation of the CALIPSO protocol as specified in - * RFC 5570. - * - * Authors: Paul Moore - * Huw Davies - * - */ - -/* - * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - * (c) Copyright Huw Davies , 2015 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - * - */ - -#ifndef _CALIPSO_H -#define _CALIPSO_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* known doi values */ -#define CALIPSO_DOI_UNKNOWN 0x00000000 - -/* doi mapping types */ -#define CALIPSO_MAP_UNKNOWN 0 -#define CALIPSO_MAP_PASS 2 - -/* - * CALIPSO DOI definitions - */ - -/* DOI definition struct */ -struct calipso_doi { - u32 doi; - u32 type; - - atomic_t refcount; - struct list_head list; - struct rcu_head rcu; -}; - -/* - * Sysctl Variables - */ -extern int calipso_cache_enabled; -extern int calipso_cache_bucketsize; - -#ifdef CONFIG_NETLABEL -int __init calipso_init(void); -void calipso_exit(void); -bool calipso_validate(const struct sk_buff *skb, const unsigned char *option); -#else -static inline int __init calipso_init(void) -{ - return 0; -} - -static inline void calipso_exit(void) -{ -} -static inline bool calipso_validate(const struct sk_buff *skb, - const unsigned char *option) -{ - return true; -} -#endif /* CONFIG_NETLABEL */ - -#endif /* _CALIPSO_H */ diff --git a/src/linux/include/net/cfg802154.h b/src/linux/include/net/cfg802154.h deleted file mode 100644 index 795ca40..0000000 --- a/src/linux/include/net/cfg802154.h +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Copyright (C) 2007, 2008, 2009 Siemens AG - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * Written by: - * Dmitry Eremin-Solenikov - */ - -#ifndef __NET_CFG802154_H -#define __NET_CFG802154_H - -#include -#include -#include -#include - -#include - -struct wpan_phy; -struct wpan_phy_cca; - -#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL -struct ieee802154_llsec_device_key; -struct ieee802154_llsec_seclevel; -struct ieee802154_llsec_params; -struct ieee802154_llsec_device; -struct ieee802154_llsec_table; -struct ieee802154_llsec_key_id; -struct ieee802154_llsec_key; -#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ - -struct cfg802154_ops { - struct net_device * (*add_virtual_intf_deprecated)(struct wpan_phy *wpan_phy, - const char *name, - unsigned char name_assign_type, - int type); - void (*del_virtual_intf_deprecated)(struct wpan_phy *wpan_phy, - struct net_device *dev); - int (*suspend)(struct wpan_phy *wpan_phy); - int (*resume)(struct wpan_phy *wpan_phy); - int (*add_virtual_intf)(struct wpan_phy *wpan_phy, - const char *name, - unsigned char name_assign_type, - enum nl802154_iftype type, - __le64 extended_addr); - int (*del_virtual_intf)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev); - int (*set_channel)(struct wpan_phy *wpan_phy, u8 page, u8 channel); - int (*set_cca_mode)(struct wpan_phy *wpan_phy, - const struct wpan_phy_cca *cca); - int (*set_cca_ed_level)(struct wpan_phy *wpan_phy, s32 ed_level); - int (*set_tx_power)(struct wpan_phy *wpan_phy, s32 power); - int (*set_pan_id)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, __le16 pan_id); - int (*set_short_addr)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, __le16 short_addr); - int (*set_backoff_exponent)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, u8 min_be, - u8 max_be); - int (*set_max_csma_backoffs)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, - u8 max_csma_backoffs); - int (*set_max_frame_retries)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, - s8 max_frame_retries); - int (*set_lbt_mode)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, bool mode); - int (*set_ackreq_default)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, bool ackreq); -#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL - void (*get_llsec_table)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, - struct ieee802154_llsec_table **table); - void (*lock_llsec_table)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev); - void (*unlock_llsec_table)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev); - /* TODO remove locking/get table callbacks, this is part of the - * nl802154 interface and should be accessible from ieee802154 layer. - */ - int (*get_llsec_params)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, - struct ieee802154_llsec_params *params); - int (*set_llsec_params)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, - const struct ieee802154_llsec_params *params, - int changed); - int (*add_llsec_key)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, - const struct ieee802154_llsec_key_id *id, - const struct ieee802154_llsec_key *key); - int (*del_llsec_key)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, - const struct ieee802154_llsec_key_id *id); - int (*add_seclevel)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, - const struct ieee802154_llsec_seclevel *sl); - int (*del_seclevel)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, - const struct ieee802154_llsec_seclevel *sl); - int (*add_device)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, - const struct ieee802154_llsec_device *dev); - int (*del_device)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, __le64 extended_addr); - int (*add_devkey)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, - __le64 extended_addr, - const struct ieee802154_llsec_device_key *key); - int (*del_devkey)(struct wpan_phy *wpan_phy, - struct wpan_dev *wpan_dev, - __le64 extended_addr, - const struct ieee802154_llsec_device_key *key); -#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ -}; - -static inline bool -wpan_phy_supported_bool(bool b, enum nl802154_supported_bool_states st) -{ - switch (st) { - case NL802154_SUPPORTED_BOOL_TRUE: - return b; - case NL802154_SUPPORTED_BOOL_FALSE: - return !b; - case NL802154_SUPPORTED_BOOL_BOTH: - return true; - default: - WARN_ON(1); - } - - return false; -} - -struct wpan_phy_supported { - u32 channels[IEEE802154_MAX_PAGE + 1], - cca_modes, cca_opts, iftypes; - enum nl802154_supported_bool_states lbt; - u8 min_minbe, max_minbe, min_maxbe, max_maxbe, - min_csma_backoffs, max_csma_backoffs; - s8 min_frame_retries, max_frame_retries; - size_t tx_powers_size, cca_ed_levels_size; - const s32 *tx_powers, *cca_ed_levels; -}; - -struct wpan_phy_cca { - enum nl802154_cca_modes mode; - enum nl802154_cca_opts opt; -}; - -static inline bool -wpan_phy_cca_cmp(const struct wpan_phy_cca *a, const struct wpan_phy_cca *b) -{ - if (a->mode != b->mode) - return false; - - if (a->mode == NL802154_CCA_ENERGY_CARRIER) - return a->opt == b->opt; - - return true; -} - -/** - * @WPAN_PHY_FLAG_TRANSMIT_POWER: Indicates that transceiver will support - * transmit power setting. - * @WPAN_PHY_FLAG_CCA_ED_LEVEL: Indicates that transceiver will support cca ed - * level setting. - * @WPAN_PHY_FLAG_CCA_MODE: Indicates that transceiver will support cca mode - * setting. - */ -enum wpan_phy_flags { - WPAN_PHY_FLAG_TXPOWER = BIT(1), - WPAN_PHY_FLAG_CCA_ED_LEVEL = BIT(2), - WPAN_PHY_FLAG_CCA_MODE = BIT(3), -}; - -struct wpan_phy { - /* If multiple wpan_phys are registered and you're handed e.g. - * a regular netdev with assigned ieee802154_ptr, you won't - * know whether it points to a wpan_phy your driver has registered - * or not. Assign this to something global to your driver to - * help determine whether you own this wpan_phy or not. - */ - const void *privid; - - u32 flags; - - /* - * This is a PIB according to 802.15.4-2011. - * We do not provide timing-related variables, as they - * aren't used outside of driver - */ - u8 current_channel; - u8 current_page; - struct wpan_phy_supported supported; - /* current transmit_power in mBm */ - s32 transmit_power; - struct wpan_phy_cca cca; - - __le64 perm_extended_addr; - - /* current cca ed threshold in mBm */ - s32 cca_ed_level; - - /* PHY depended MAC PIB values */ - - /* 802.15.4 acronym: Tdsym in usec */ - u8 symbol_duration; - /* lifs and sifs periods timing */ - u16 lifs_period; - u16 sifs_period; - - struct device dev; - - /* the network namespace this phy lives in currently */ - possible_net_t _net; - - char priv[0] __aligned(NETDEV_ALIGN); -}; - -static inline struct net *wpan_phy_net(struct wpan_phy *wpan_phy) -{ - return read_pnet(&wpan_phy->_net); -} - -static inline void wpan_phy_net_set(struct wpan_phy *wpan_phy, struct net *net) -{ - write_pnet(&wpan_phy->_net, net); -} - -struct ieee802154_addr { - u8 mode; - __le16 pan_id; - union { - __le16 short_addr; - __le64 extended_addr; - }; -}; - -struct ieee802154_llsec_key_id { - u8 mode; - u8 id; - union { - struct ieee802154_addr device_addr; - __le32 short_source; - __le64 extended_source; - }; -}; - -#define IEEE802154_LLSEC_KEY_SIZE 16 - -struct ieee802154_llsec_key { - u8 frame_types; - u32 cmd_frame_ids; - /* TODO replace with NL802154_KEY_SIZE */ - u8 key[IEEE802154_LLSEC_KEY_SIZE]; -}; - -struct ieee802154_llsec_key_entry { - struct list_head list; - - struct ieee802154_llsec_key_id id; - struct ieee802154_llsec_key *key; -}; - -struct ieee802154_llsec_params { - bool enabled; - - __be32 frame_counter; - u8 out_level; - struct ieee802154_llsec_key_id out_key; - - __le64 default_key_source; - - __le16 pan_id; - __le64 hwaddr; - __le64 coord_hwaddr; - __le16 coord_shortaddr; -}; - -struct ieee802154_llsec_table { - struct list_head keys; - struct list_head devices; - struct list_head security_levels; -}; - -struct ieee802154_llsec_seclevel { - struct list_head list; - - u8 frame_type; - u8 cmd_frame_id; - bool device_override; - u32 sec_levels; -}; - -struct ieee802154_llsec_device { - struct list_head list; - - __le16 pan_id; - __le16 short_addr; - __le64 hwaddr; - u32 frame_counter; - bool seclevel_exempt; - - u8 key_mode; - struct list_head keys; -}; - -struct ieee802154_llsec_device_key { - struct list_head list; - - struct ieee802154_llsec_key_id key_id; - u32 frame_counter; -}; - -struct wpan_dev_header_ops { - /* TODO create callback currently assumes ieee802154_mac_cb inside - * skb->cb. This should be changed to give these information as - * parameter. - */ - int (*create)(struct sk_buff *skb, struct net_device *dev, - const struct ieee802154_addr *daddr, - const struct ieee802154_addr *saddr, - unsigned int len); -}; - -struct wpan_dev { - struct wpan_phy *wpan_phy; - int iftype; - - /* the remainder of this struct should be private to cfg802154 */ - struct list_head list; - struct net_device *netdev; - - const struct wpan_dev_header_ops *header_ops; - - /* lowpan interface, set when the wpan_dev belongs to one lowpan_dev */ - struct net_device *lowpan_dev; - - u32 identifier; - - /* MAC PIB */ - __le16 pan_id; - __le16 short_addr; - __le64 extended_addr; - - /* MAC BSN field */ - atomic_t bsn; - /* MAC DSN field */ - atomic_t dsn; - - u8 min_be; - u8 max_be; - u8 csma_retries; - s8 frame_retries; - - bool lbt; - - bool promiscuous_mode; - - /* fallback for acknowledgment bit setting */ - bool ackreq; -}; - -#define to_phy(_dev) container_of(_dev, struct wpan_phy, dev) - -static inline int -wpan_dev_hard_header(struct sk_buff *skb, struct net_device *dev, - const struct ieee802154_addr *daddr, - const struct ieee802154_addr *saddr, - unsigned int len) -{ - struct wpan_dev *wpan_dev = dev->ieee802154_ptr; - - return wpan_dev->header_ops->create(skb, dev, daddr, saddr, len); -} - -struct wpan_phy * -wpan_phy_new(const struct cfg802154_ops *ops, size_t priv_size); -static inline void wpan_phy_set_dev(struct wpan_phy *phy, struct device *dev) -{ - phy->dev.parent = dev; -} - -int wpan_phy_register(struct wpan_phy *phy); -void wpan_phy_unregister(struct wpan_phy *phy); -void wpan_phy_free(struct wpan_phy *phy); -/* Same semantics as for class_for_each_device */ -int wpan_phy_for_each(int (*fn)(struct wpan_phy *phy, void *data), void *data); - -static inline void *wpan_phy_priv(struct wpan_phy *phy) -{ - BUG_ON(!phy); - return &phy->priv; -} - -struct wpan_phy *wpan_phy_find(const char *str); - -static inline void wpan_phy_put(struct wpan_phy *phy) -{ - put_device(&phy->dev); -} - -static inline const char *wpan_phy_name(struct wpan_phy *phy) -{ - return dev_name(&phy->dev); -} - -#endif /* __NET_CFG802154_H */ diff --git a/src/linux/include/net/checksum.h b/src/linux/include/net/checksum.h deleted file mode 100644 index 5c30891..0000000 --- a/src/linux/include/net/checksum.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Checksumming functions for IP, TCP, UDP and so on - * - * Authors: Jorge Cwik, - * Arnt Gulbrandsen, - * Borrows very liberally from tcp.c and ip.c, see those - * files for more names. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _CHECKSUM_H -#define _CHECKSUM_H - -#include -#include -#include -#include -#include - -#ifndef _HAVE_ARCH_COPY_AND_CSUM_FROM_USER -static inline -__wsum csum_and_copy_from_user (const void __user *src, void *dst, - int len, __wsum sum, int *err_ptr) -{ - if (access_ok(VERIFY_READ, src, len)) - return csum_partial_copy_from_user(src, dst, len, sum, err_ptr); - - if (len) - *err_ptr = -EFAULT; - - return sum; -} -#endif - -#ifndef HAVE_CSUM_COPY_USER -static __inline__ __wsum csum_and_copy_to_user -(const void *src, void __user *dst, int len, __wsum sum, int *err_ptr) -{ - sum = csum_partial(src, len, sum); - - if (access_ok(VERIFY_WRITE, dst, len)) { - if (copy_to_user(dst, src, len) == 0) - return sum; - } - if (len) - *err_ptr = -EFAULT; - - return (__force __wsum)-1; /* invalid checksum */ -} -#endif - -#ifndef HAVE_ARCH_CSUM_ADD -static inline __wsum csum_add(__wsum csum, __wsum addend) -{ - u32 res = (__force u32)csum; - res += (__force u32)addend; - return (__force __wsum)(res + (res < (__force u32)addend)); -} -#endif - -static inline __wsum csum_sub(__wsum csum, __wsum addend) -{ - return csum_add(csum, ~addend); -} - -static inline __sum16 csum16_add(__sum16 csum, __be16 addend) -{ - u16 res = (__force u16)csum; - - res += (__force u16)addend; - return (__force __sum16)(res + (res < (__force u16)addend)); -} - -static inline __sum16 csum16_sub(__sum16 csum, __be16 addend) -{ - return csum16_add(csum, ~addend); -} - -static inline __wsum -csum_block_add(__wsum csum, __wsum csum2, int offset) -{ - u32 sum = (__force u32)csum2; - - /* rotate sum to align it with a 16b boundary */ - if (offset & 1) - sum = ror32(sum, 8); - - return csum_add(csum, (__force __wsum)sum); -} - -static inline __wsum -csum_block_add_ext(__wsum csum, __wsum csum2, int offset, int len) -{ - return csum_block_add(csum, csum2, offset); -} - -static inline __wsum -csum_block_sub(__wsum csum, __wsum csum2, int offset) -{ - return csum_block_add(csum, ~csum2, offset); -} - -static inline __wsum csum_unfold(__sum16 n) -{ - return (__force __wsum)n; -} - -static inline __wsum csum_partial_ext(const void *buff, int len, __wsum sum) -{ - return csum_partial(buff, len, sum); -} - -#define CSUM_MANGLED_0 ((__force __sum16)0xffff) - -static inline void csum_replace_by_diff(__sum16 *sum, __wsum diff) -{ - *sum = csum_fold(csum_add(diff, ~csum_unfold(*sum))); -} - -static inline void csum_replace4(__sum16 *sum, __be32 from, __be32 to) -{ - __wsum tmp = csum_sub(~csum_unfold(*sum), (__force __wsum)from); - - *sum = csum_fold(csum_add(tmp, (__force __wsum)to)); -} - -/* Implements RFC 1624 (Incremental Internet Checksum) - * 3. Discussion states : - * HC' = ~(~HC + ~m + m') - * m : old value of a 16bit field - * m' : new value of a 16bit field - */ -static inline void csum_replace2(__sum16 *sum, __be16 old, __be16 new) -{ - *sum = ~csum16_add(csum16_sub(~(*sum), old), new); -} - -struct sk_buff; -void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb, - __be32 from, __be32 to, bool pseudohdr); -void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb, - const __be32 *from, const __be32 *to, - bool pseudohdr); -void inet_proto_csum_replace_by_diff(__sum16 *sum, struct sk_buff *skb, - __wsum diff, bool pseudohdr); - -static inline void inet_proto_csum_replace2(__sum16 *sum, struct sk_buff *skb, - __be16 from, __be16 to, - bool pseudohdr) -{ - inet_proto_csum_replace4(sum, skb, (__force __be32)from, - (__force __be32)to, pseudohdr); -} - -static inline __wsum remcsum_adjust(void *ptr, __wsum csum, - int start, int offset) -{ - __sum16 *psum = (__sum16 *)(ptr + offset); - __wsum delta; - - /* Subtract out checksum up to start */ - csum = csum_sub(csum, csum_partial(ptr, start, 0)); - - /* Set derived checksum in packet */ - delta = csum_sub((__force __wsum)csum_fold(csum), - (__force __wsum)*psum); - *psum = csum_fold(csum); - - return delta; -} - -static inline void remcsum_unadjust(__sum16 *psum, __wsum delta) -{ - *psum = csum_fold(csum_sub(delta, *psum)); -} - -#endif diff --git a/src/linux/include/net/cipso_ipv4.h b/src/linux/include/net/cipso_ipv4.h deleted file mode 100644 index 3ebb168..0000000 --- a/src/linux/include/net/cipso_ipv4.h +++ /dev/null @@ -1,327 +0,0 @@ -/* - * CIPSO - Commercial IP Security Option - * - * This is an implementation of the CIPSO 2.2 protocol as specified in - * draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in - * FIPS-188, copies of both documents can be found in the Documentation - * directory. While CIPSO never became a full IETF RFC standard many vendors - * have chosen to adopt the protocol and over the years it has become a - * de-facto standard for labeled networking. - * - * Author: Paul Moore - * - */ - -/* - * (c) Copyright Hewlett-Packard Development Company, L.P., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - * - */ - -#ifndef _CIPSO_IPV4_H -#define _CIPSO_IPV4_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* known doi values */ -#define CIPSO_V4_DOI_UNKNOWN 0x00000000 - -/* standard tag types */ -#define CIPSO_V4_TAG_INVALID 0 -#define CIPSO_V4_TAG_RBITMAP 1 -#define CIPSO_V4_TAG_ENUM 2 -#define CIPSO_V4_TAG_RANGE 5 -#define CIPSO_V4_TAG_PBITMAP 6 -#define CIPSO_V4_TAG_FREEFORM 7 - -/* non-standard tag types (tags > 127) */ -#define CIPSO_V4_TAG_LOCAL 128 - -/* doi mapping types */ -#define CIPSO_V4_MAP_UNKNOWN 0 -#define CIPSO_V4_MAP_TRANS 1 -#define CIPSO_V4_MAP_PASS 2 -#define CIPSO_V4_MAP_LOCAL 3 - -/* limits */ -#define CIPSO_V4_MAX_REM_LVLS 255 -#define CIPSO_V4_INV_LVL 0x80000000 -#define CIPSO_V4_MAX_LOC_LVLS (CIPSO_V4_INV_LVL - 1) -#define CIPSO_V4_MAX_REM_CATS 65534 -#define CIPSO_V4_INV_CAT 0x80000000 -#define CIPSO_V4_MAX_LOC_CATS (CIPSO_V4_INV_CAT - 1) - -/* - * CIPSO DOI definitions - */ - -/* DOI definition struct */ -#define CIPSO_V4_TAG_MAXCNT 5 -struct cipso_v4_doi { - u32 doi; - u32 type; - union { - struct cipso_v4_std_map_tbl *std; - } map; - u8 tags[CIPSO_V4_TAG_MAXCNT]; - - atomic_t refcount; - struct list_head list; - struct rcu_head rcu; -}; - -/* Standard CIPSO mapping table */ -/* NOTE: the highest order bit (i.e. 0x80000000) is an 'invalid' flag, if the - * bit is set then consider that value as unspecified, meaning the - * mapping for that particular level/category is invalid */ -struct cipso_v4_std_map_tbl { - struct { - u32 *cipso; - u32 *local; - u32 cipso_size; - u32 local_size; - } lvl; - struct { - u32 *cipso; - u32 *local; - u32 cipso_size; - u32 local_size; - } cat; -}; - -/* - * Sysctl Variables - */ - -#ifdef CONFIG_NETLABEL -extern int cipso_v4_cache_enabled; -extern int cipso_v4_cache_bucketsize; -extern int cipso_v4_rbm_optfmt; -extern int cipso_v4_rbm_strictvalid; -#endif - -/* - * DOI List Functions - */ - -#ifdef CONFIG_NETLABEL -int cipso_v4_doi_add(struct cipso_v4_doi *doi_def, - struct netlbl_audit *audit_info); -void cipso_v4_doi_free(struct cipso_v4_doi *doi_def); -int cipso_v4_doi_remove(u32 doi, struct netlbl_audit *audit_info); -struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi); -void cipso_v4_doi_putdef(struct cipso_v4_doi *doi_def); -int cipso_v4_doi_walk(u32 *skip_cnt, - int (*callback) (struct cipso_v4_doi *doi_def, void *arg), - void *cb_arg); -#else -static inline int cipso_v4_doi_add(struct cipso_v4_doi *doi_def, - struct netlbl_audit *audit_info) -{ - return -ENOSYS; -} - -static inline void cipso_v4_doi_free(struct cipso_v4_doi *doi_def) -{ - return; -} - -static inline int cipso_v4_doi_remove(u32 doi, - struct netlbl_audit *audit_info) -{ - return 0; -} - -static inline struct cipso_v4_doi *cipso_v4_doi_getdef(u32 doi) -{ - return NULL; -} - -static inline int cipso_v4_doi_walk(u32 *skip_cnt, - int (*callback) (struct cipso_v4_doi *doi_def, void *arg), - void *cb_arg) -{ - return 0; -} - -static inline int cipso_v4_doi_domhsh_add(struct cipso_v4_doi *doi_def, - const char *domain) -{ - return -ENOSYS; -} - -static inline int cipso_v4_doi_domhsh_remove(struct cipso_v4_doi *doi_def, - const char *domain) -{ - return 0; -} -#endif /* CONFIG_NETLABEL */ - -/* - * Label Mapping Cache Functions - */ - -#ifdef CONFIG_NETLABEL -void cipso_v4_cache_invalidate(void); -int cipso_v4_cache_add(const unsigned char *cipso_ptr, - const struct netlbl_lsm_secattr *secattr); -#else -static inline void cipso_v4_cache_invalidate(void) -{ - return; -} - -static inline int cipso_v4_cache_add(const unsigned char *cipso_ptr, - const struct netlbl_lsm_secattr *secattr) -{ - return 0; -} -#endif /* CONFIG_NETLABEL */ - -/* - * Protocol Handling Functions - */ - -#ifdef CONFIG_NETLABEL -void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway); -int cipso_v4_getattr(const unsigned char *cipso, - struct netlbl_lsm_secattr *secattr); -int cipso_v4_sock_setattr(struct sock *sk, - const struct cipso_v4_doi *doi_def, - const struct netlbl_lsm_secattr *secattr); -void cipso_v4_sock_delattr(struct sock *sk); -int cipso_v4_sock_getattr(struct sock *sk, struct netlbl_lsm_secattr *secattr); -int cipso_v4_req_setattr(struct request_sock *req, - const struct cipso_v4_doi *doi_def, - const struct netlbl_lsm_secattr *secattr); -void cipso_v4_req_delattr(struct request_sock *req); -int cipso_v4_skbuff_setattr(struct sk_buff *skb, - const struct cipso_v4_doi *doi_def, - const struct netlbl_lsm_secattr *secattr); -int cipso_v4_skbuff_delattr(struct sk_buff *skb); -int cipso_v4_skbuff_getattr(const struct sk_buff *skb, - struct netlbl_lsm_secattr *secattr); -unsigned char *cipso_v4_optptr(const struct sk_buff *skb); -int cipso_v4_validate(const struct sk_buff *skb, unsigned char **option); -#else -static inline void cipso_v4_error(struct sk_buff *skb, - int error, - u32 gateway) -{ - return; -} - -static inline int cipso_v4_getattr(const unsigned char *cipso, - struct netlbl_lsm_secattr *secattr) -{ - return -ENOSYS; -} - -static inline int cipso_v4_sock_setattr(struct sock *sk, - const struct cipso_v4_doi *doi_def, - const struct netlbl_lsm_secattr *secattr) -{ - return -ENOSYS; -} - -static inline void cipso_v4_sock_delattr(struct sock *sk) -{ -} - -static inline int cipso_v4_sock_getattr(struct sock *sk, - struct netlbl_lsm_secattr *secattr) -{ - return -ENOSYS; -} - -static inline int cipso_v4_req_setattr(struct request_sock *req, - const struct cipso_v4_doi *doi_def, - const struct netlbl_lsm_secattr *secattr) -{ - return -ENOSYS; -} - -static inline void cipso_v4_req_delattr(struct request_sock *req) -{ - return; -} - -static inline int cipso_v4_skbuff_setattr(struct sk_buff *skb, - const struct cipso_v4_doi *doi_def, - const struct netlbl_lsm_secattr *secattr) -{ - return -ENOSYS; -} - -static inline int cipso_v4_skbuff_delattr(struct sk_buff *skb) -{ - return -ENOSYS; -} - -static inline int cipso_v4_skbuff_getattr(const struct sk_buff *skb, - struct netlbl_lsm_secattr *secattr) -{ - return -ENOSYS; -} - -static inline unsigned char *cipso_v4_optptr(const struct sk_buff *skb) -{ - return NULL; -} - -static inline int cipso_v4_validate(const struct sk_buff *skb, - unsigned char **option) -{ - unsigned char *opt = *option; - unsigned char err_offset = 0; - u8 opt_len = opt[1]; - u8 opt_iter; - u8 tag_len; - - if (opt_len < 8) { - err_offset = 1; - goto out; - } - - if (get_unaligned_be32(&opt[2]) == 0) { - err_offset = 2; - goto out; - } - - for (opt_iter = 6; opt_iter < opt_len;) { - tag_len = opt[opt_iter + 1]; - if ((tag_len == 0) || (tag_len > (opt_len - opt_iter))) { - err_offset = opt_iter + 1; - goto out; - } - opt_iter += tag_len; - } - -out: - *option = opt + err_offset; - return err_offset; - -} -#endif /* CONFIG_NETLABEL */ - -#endif /* _CIPSO_IPV4_H */ diff --git a/src/linux/include/net/cls_cgroup.h b/src/linux/include/net/cls_cgroup.h deleted file mode 100644 index 74c9693..0000000 --- a/src/linux/include/net/cls_cgroup.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * cls_cgroup.h Control Group Classifier - * - * Authors: Thomas Graf - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#ifndef _NET_CLS_CGROUP_H -#define _NET_CLS_CGROUP_H - -#include -#include -#include -#include -#include - -#ifdef CONFIG_CGROUP_NET_CLASSID -struct cgroup_cls_state { - struct cgroup_subsys_state css; - u32 classid; -}; - -struct cgroup_cls_state *task_cls_state(struct task_struct *p); - -static inline u32 task_cls_classid(struct task_struct *p) -{ - u32 classid; - - if (in_interrupt()) - return 0; - - rcu_read_lock(); - classid = container_of(task_css(p, net_cls_cgrp_id), - struct cgroup_cls_state, css)->classid; - rcu_read_unlock(); - - return classid; -} - -static inline void sock_update_classid(struct sock_cgroup_data *skcd) -{ - u32 classid; - - classid = task_cls_classid(current); - sock_cgroup_set_classid(skcd, classid); -} - -static inline u32 task_get_classid(const struct sk_buff *skb) -{ - u32 classid = task_cls_state(current)->classid; - - /* Due to the nature of the classifier it is required to ignore all - * packets originating from softirq context as accessing `current' - * would lead to false results. - * - * This test assumes that all callers of dev_queue_xmit() explicitly - * disable bh. Knowing this, it is possible to detect softirq based - * calls by looking at the number of nested bh disable calls because - * softirqs always disables bh. - */ - if (in_serving_softirq()) { - struct sock *sk = skb_to_full_sk(skb); - - /* If there is an sock_cgroup_classid we'll use that. */ - if (!sk || !sk_fullsock(sk)) - return 0; - - classid = sock_cgroup_classid(&sk->sk_cgrp_data); - } - - return classid; -} -#else /* !CONFIG_CGROUP_NET_CLASSID */ -static inline void sock_update_classid(struct sock_cgroup_data *skcd) -{ -} - -static inline u32 task_get_classid(const struct sk_buff *skb) -{ - return 0; -} -#endif /* CONFIG_CGROUP_NET_CLASSID */ -#endif /* _NET_CLS_CGROUP_H */ diff --git a/src/linux/include/net/compat.h b/src/linux/include/net/compat.h deleted file mode 100644 index 13de0cc..0000000 --- a/src/linux/include/net/compat.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef NET_COMPAT_H -#define NET_COMPAT_H - - -struct sock; - -#if defined(CONFIG_COMPAT) - -#include - -struct compat_msghdr { - compat_uptr_t msg_name; /* void * */ - compat_int_t msg_namelen; - compat_uptr_t msg_iov; /* struct compat_iovec * */ - compat_size_t msg_iovlen; - compat_uptr_t msg_control; /* void * */ - compat_size_t msg_controllen; - compat_uint_t msg_flags; -}; - -struct compat_mmsghdr { - struct compat_msghdr msg_hdr; - compat_uint_t msg_len; -}; - -struct compat_cmsghdr { - compat_size_t cmsg_len; - compat_int_t cmsg_level; - compat_int_t cmsg_type; -}; - -int compat_sock_get_timestamp(struct sock *, struct timeval __user *); -int compat_sock_get_timestampns(struct sock *, struct timespec __user *); - -#else /* defined(CONFIG_COMPAT) */ -/* - * To avoid compiler warnings: - */ -#define compat_msghdr msghdr -#define compat_mmsghdr mmsghdr -#endif /* defined(CONFIG_COMPAT) */ - -int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *, - struct sockaddr __user **, struct iovec **); -struct sock_fprog __user *get_compat_bpf_fprog(char __user *optval); -asmlinkage long compat_sys_sendmsg(int, struct compat_msghdr __user *, - unsigned int); -asmlinkage long compat_sys_sendmmsg(int, struct compat_mmsghdr __user *, - unsigned int, unsigned int); -asmlinkage long compat_sys_recvmsg(int, struct compat_msghdr __user *, - unsigned int); -asmlinkage long compat_sys_recvmmsg(int, struct compat_mmsghdr __user *, - unsigned int, unsigned int, - struct compat_timespec __user *); -asmlinkage long compat_sys_getsockopt(int, int, int, char __user *, - int __user *); -int put_cmsg_compat(struct msghdr*, int, int, int, void *); - -int cmsghdr_from_user_compat_to_kern(struct msghdr *, struct sock *, - unsigned char *, int); - -int compat_mc_setsockopt(struct sock *, int, int, char __user *, unsigned int, - int (*)(struct sock *, int, int, char __user *, - unsigned int)); -int compat_mc_getsockopt(struct sock *, int, int, char __user *, int __user *, - int (*)(struct sock *, int, int, char __user *, - int __user *)); - -#endif /* NET_COMPAT_H */ diff --git a/src/linux/include/net/dsa.h b/src/linux/include/net/dsa.h deleted file mode 100644 index b122196..0000000 --- a/src/linux/include/net/dsa.h +++ /dev/null @@ -1,418 +0,0 @@ -/* - * include/net/dsa.h - Driver for Distributed Switch Architecture switch chips - * Copyright (c) 2008-2009 Marvell Semiconductor - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef __LINUX_NET_DSA_H -#define __LINUX_NET_DSA_H - -#include -#include -#include -#include -#include -#include -#include -#include - -enum dsa_tag_protocol { - DSA_TAG_PROTO_NONE = 0, - DSA_TAG_PROTO_DSA, - DSA_TAG_PROTO_TRAILER, - DSA_TAG_PROTO_EDSA, - DSA_TAG_PROTO_BRCM, - DSA_TAG_PROTO_QCA, - DSA_TAG_LAST, /* MUST BE LAST */ -}; - -#define DSA_MAX_SWITCHES 4 -#define DSA_MAX_PORTS 12 - -#define DSA_RTABLE_NONE -1 - -struct dsa_chip_data { - /* - * How to access the switch configuration registers. - */ - struct device *host_dev; - int sw_addr; - - /* set to size of eeprom if supported by the switch */ - int eeprom_len; - - /* Device tree node pointer for this specific switch chip - * used during switch setup in case additional properties - * and resources needs to be used - */ - struct device_node *of_node; - - /* - * The names of the switch's ports. Use "cpu" to - * designate the switch port that the cpu is connected to, - * "dsa" to indicate that this port is a DSA link to - * another switch, NULL to indicate the port is unused, - * or any other string to indicate this is a physical port. - */ - char *port_names[DSA_MAX_PORTS]; - struct device_node *port_dn[DSA_MAX_PORTS]; - - /* - * An array of which element [a] indicates which port on this - * switch should be used to send packets to that are destined - * for switch a. Can be NULL if there is only one switch chip. - */ - s8 rtable[DSA_MAX_SWITCHES]; -}; - -struct dsa_platform_data { - /* - * Reference to a Linux network interface that connects - * to the root switch chip of the tree. - */ - struct device *netdev; - struct net_device *of_netdev; - - /* - * Info structs describing each of the switch chips - * connected via this network interface. - */ - int nr_chips; - struct dsa_chip_data *chip; -}; - -struct packet_type; - -struct dsa_switch_tree { - struct list_head list; - - /* Tree identifier */ - u32 tree; - - /* Number of switches attached to this tree */ - struct kref refcount; - - /* Has this tree been applied to the hardware? */ - bool applied; - - /* - * Configuration data for the platform device that owns - * this dsa switch tree instance. - */ - struct dsa_platform_data *pd; - - /* - * Reference to network device to use, and which tagging - * protocol to use. - */ - struct net_device *master_netdev; - int (*rcv)(struct sk_buff *skb, - struct net_device *dev, - struct packet_type *pt, - struct net_device *orig_dev); - - /* - * Original copy of the master netdev ethtool_ops - */ - struct ethtool_ops master_ethtool_ops; - const struct ethtool_ops *master_orig_ethtool_ops; - - /* - * The switch and port to which the CPU is attached. - */ - s8 cpu_switch; - s8 cpu_port; - - /* - * Data for the individual switch chips. - */ - struct dsa_switch *ds[DSA_MAX_SWITCHES]; - - /* - * Tagging protocol operations for adding and removing an - * encapsulation tag. - */ - const struct dsa_device_ops *tag_ops; -}; - -struct dsa_port { - struct net_device *netdev; - struct device_node *dn; - unsigned int ageing_time; - u8 stp_state; -}; - -struct dsa_switch { - struct device *dev; - - /* - * Parent switch tree, and switch index. - */ - struct dsa_switch_tree *dst; - int index; - - /* - * Give the switch driver somewhere to hang its private data - * structure. - */ - void *priv; - - /* - * Configuration data for this switch. - */ - struct dsa_chip_data *cd; - - /* - * The switch operations. - */ - struct dsa_switch_ops *ops; - - /* - * An array of which element [a] indicates which port on this - * switch should be used to send packets to that are destined - * for switch a. Can be NULL if there is only one switch chip. - */ - s8 rtable[DSA_MAX_SWITCHES]; - -#ifdef CONFIG_NET_DSA_HWMON - /* - * Hardware monitoring information - */ - char hwmon_name[IFNAMSIZ + 8]; - struct device *hwmon_dev; -#endif - - /* - * The lower device this switch uses to talk to the host - */ - struct net_device *master_netdev; - - /* - * Slave mii_bus and devices for the individual ports. - */ - u32 dsa_port_mask; - u32 cpu_port_mask; - u32 enabled_port_mask; - u32 phys_mii_mask; - struct dsa_port ports[DSA_MAX_PORTS]; - struct mii_bus *slave_mii_bus; -}; - -static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p) -{ - return !!(ds->index == ds->dst->cpu_switch && p == ds->dst->cpu_port); -} - -static inline bool dsa_is_dsa_port(struct dsa_switch *ds, int p) -{ - return !!((ds->dsa_port_mask) & (1 << p)); -} - -static inline bool dsa_is_port_initialized(struct dsa_switch *ds, int p) -{ - return ds->enabled_port_mask & (1 << p) && ds->ports[p].netdev; -} - -static inline u8 dsa_upstream_port(struct dsa_switch *ds) -{ - struct dsa_switch_tree *dst = ds->dst; - - /* - * If this is the root switch (i.e. the switch that connects - * to the CPU), return the cpu port number on this switch. - * Else return the (DSA) port number that connects to the - * switch that is one hop closer to the cpu. - */ - if (dst->cpu_switch == ds->index) - return dst->cpu_port; - else - return ds->rtable[dst->cpu_switch]; -} - -struct switchdev_trans; -struct switchdev_obj; -struct switchdev_obj_port_fdb; -struct switchdev_obj_port_mdb; -struct switchdev_obj_port_vlan; - -struct dsa_switch_ops { - struct list_head list; - - /* - * Probing and setup. - */ - const char *(*probe)(struct device *dsa_dev, - struct device *host_dev, int sw_addr, - void **priv); - - enum dsa_tag_protocol (*get_tag_protocol)(struct dsa_switch *ds); - - int (*setup)(struct dsa_switch *ds); - int (*set_addr)(struct dsa_switch *ds, u8 *addr); - u32 (*get_phy_flags)(struct dsa_switch *ds, int port); - - /* - * Access to the switch's PHY registers. - */ - int (*phy_read)(struct dsa_switch *ds, int port, int regnum); - int (*phy_write)(struct dsa_switch *ds, int port, - int regnum, u16 val); - - /* - * Link state adjustment (called from libphy) - */ - void (*adjust_link)(struct dsa_switch *ds, int port, - struct phy_device *phydev); - void (*fixed_link_update)(struct dsa_switch *ds, int port, - struct fixed_phy_status *st); - - /* - * ethtool hardware statistics. - */ - void (*get_strings)(struct dsa_switch *ds, int port, uint8_t *data); - void (*get_ethtool_stats)(struct dsa_switch *ds, - int port, uint64_t *data); - int (*get_sset_count)(struct dsa_switch *ds); - - /* - * ethtool Wake-on-LAN - */ - void (*get_wol)(struct dsa_switch *ds, int port, - struct ethtool_wolinfo *w); - int (*set_wol)(struct dsa_switch *ds, int port, - struct ethtool_wolinfo *w); - - /* - * Suspend and resume - */ - int (*suspend)(struct dsa_switch *ds); - int (*resume)(struct dsa_switch *ds); - - /* - * Port enable/disable - */ - int (*port_enable)(struct dsa_switch *ds, int port, - struct phy_device *phy); - void (*port_disable)(struct dsa_switch *ds, int port, - struct phy_device *phy); - - /* - * EEE setttings - */ - int (*set_eee)(struct dsa_switch *ds, int port, - struct phy_device *phydev, - struct ethtool_eee *e); - int (*get_eee)(struct dsa_switch *ds, int port, - struct ethtool_eee *e); - -#ifdef CONFIG_NET_DSA_HWMON - /* Hardware monitoring */ - int (*get_temp)(struct dsa_switch *ds, int *temp); - int (*get_temp_limit)(struct dsa_switch *ds, int *temp); - int (*set_temp_limit)(struct dsa_switch *ds, int temp); - int (*get_temp_alarm)(struct dsa_switch *ds, bool *alarm); -#endif - - /* EEPROM access */ - int (*get_eeprom_len)(struct dsa_switch *ds); - int (*get_eeprom)(struct dsa_switch *ds, - struct ethtool_eeprom *eeprom, u8 *data); - int (*set_eeprom)(struct dsa_switch *ds, - struct ethtool_eeprom *eeprom, u8 *data); - - /* - * Register access. - */ - int (*get_regs_len)(struct dsa_switch *ds, int port); - void (*get_regs)(struct dsa_switch *ds, int port, - struct ethtool_regs *regs, void *p); - - /* - * Bridge integration - */ - int (*set_ageing_time)(struct dsa_switch *ds, unsigned int msecs); - int (*port_bridge_join)(struct dsa_switch *ds, int port, - struct net_device *bridge); - void (*port_bridge_leave)(struct dsa_switch *ds, int port); - void (*port_stp_state_set)(struct dsa_switch *ds, int port, - u8 state); - void (*port_fast_age)(struct dsa_switch *ds, int port); - - /* - * VLAN support - */ - int (*port_vlan_filtering)(struct dsa_switch *ds, int port, - bool vlan_filtering); - int (*port_vlan_prepare)(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan, - struct switchdev_trans *trans); - void (*port_vlan_add)(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan, - struct switchdev_trans *trans); - int (*port_vlan_del)(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_vlan *vlan); - int (*port_vlan_dump)(struct dsa_switch *ds, int port, - struct switchdev_obj_port_vlan *vlan, - int (*cb)(struct switchdev_obj *obj)); - - /* - * Forwarding database - */ - int (*port_fdb_prepare)(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_fdb *fdb, - struct switchdev_trans *trans); - void (*port_fdb_add)(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_fdb *fdb, - struct switchdev_trans *trans); - int (*port_fdb_del)(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_fdb *fdb); - int (*port_fdb_dump)(struct dsa_switch *ds, int port, - struct switchdev_obj_port_fdb *fdb, - int (*cb)(struct switchdev_obj *obj)); - - /* - * Multicast database - */ - int (*port_mdb_prepare)(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_mdb *mdb, - struct switchdev_trans *trans); - void (*port_mdb_add)(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_mdb *mdb, - struct switchdev_trans *trans); - int (*port_mdb_del)(struct dsa_switch *ds, int port, - const struct switchdev_obj_port_mdb *mdb); - int (*port_mdb_dump)(struct dsa_switch *ds, int port, - struct switchdev_obj_port_mdb *mdb, - int (*cb)(struct switchdev_obj *obj)); -}; - -void register_switch_driver(struct dsa_switch_ops *type); -void unregister_switch_driver(struct dsa_switch_ops *type); -struct mii_bus *dsa_host_dev_to_mii_bus(struct device *dev); - -static inline bool dsa_uses_tagged_protocol(struct dsa_switch_tree *dst) -{ - return dst->rcv != NULL; -} - -void dsa_unregister_switch(struct dsa_switch *ds); -int dsa_register_switch(struct dsa_switch *ds, struct device_node *np); -#ifdef CONFIG_PM_SLEEP -int dsa_switch_suspend(struct dsa_switch *ds); -int dsa_switch_resume(struct dsa_switch *ds); -#else -static inline int dsa_switch_suspend(struct dsa_switch *ds) -{ - return 0; -} -static inline int dsa_switch_resume(struct dsa_switch *ds) -{ - return 0; -} -#endif /* CONFIG_PM_SLEEP */ - -#endif diff --git a/src/linux/include/net/dsfield.h b/src/linux/include/net/dsfield.h deleted file mode 100644 index e1ad903..0000000 --- a/src/linux/include/net/dsfield.h +++ /dev/null @@ -1,52 +0,0 @@ -/* include/net/dsfield.h - Manipulation of the Differentiated Services field */ - -/* Written 1998-2000 by Werner Almesberger, EPFL ICA */ - - -#ifndef __NET_DSFIELD_H -#define __NET_DSFIELD_H - -#include -#include -#include -#include - - -static inline __u8 ipv4_get_dsfield(const struct iphdr *iph) -{ - return iph->tos; -} - - -static inline __u8 ipv6_get_dsfield(const struct ipv6hdr *ipv6h) -{ - return ntohs(*(const __be16 *)ipv6h) >> 4; -} - - -static inline void ipv4_change_dsfield(struct iphdr *iph,__u8 mask, - __u8 value) -{ - __u32 check = ntohs((__force __be16)iph->check); - __u8 dsfield; - - dsfield = (iph->tos & mask) | value; - check += iph->tos; - if ((check+1) >> 16) check = (check+1) & 0xffff; - check -= dsfield; - check += check >> 16; /* adjust carry */ - iph->check = (__force __sum16)htons(check); - iph->tos = dsfield; -} - - -static inline void ipv6_change_dsfield(struct ipv6hdr *ipv6h,__u8 mask, - __u8 value) -{ - __be16 *p = (__force __be16 *)ipv6h; - - *p = (*p & htons((((u16)mask << 4) | 0xf00f))) | htons((u16)value << 4); -} - - -#endif diff --git a/src/linux/include/net/dst.h b/src/linux/include/net/dst.h deleted file mode 100644 index 6835d22..0000000 --- a/src/linux/include/net/dst.h +++ /dev/null @@ -1,567 +0,0 @@ -/* - * net/dst.h Protocol independent destination cache definitions. - * - * Authors: Alexey Kuznetsov, - * - */ - -#ifndef _NET_DST_H -#define _NET_DST_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#define DST_GC_MIN (HZ/10) -#define DST_GC_INC (HZ/2) -#define DST_GC_MAX (120*HZ) - -/* Each dst_entry has reference count and sits in some parent list(s). - * When it is removed from parent list, it is "freed" (dst_free). - * After this it enters dead state (dst->obsolete > 0) and if its refcnt - * is zero, it can be destroyed immediately, otherwise it is added - * to gc list and garbage collector periodically checks the refcnt. - */ - -struct sk_buff; - -struct dst_entry { - struct rcu_head rcu_head; - struct dst_entry *child; - struct net_device *dev; - struct dst_ops *ops; - unsigned long _metrics; - unsigned long expires; - struct dst_entry *path; - struct dst_entry *from; -#ifdef CONFIG_XFRM - struct xfrm_state *xfrm; -#else - void *__pad1; -#endif - int (*input)(struct sk_buff *); - int (*output)(struct net *net, struct sock *sk, struct sk_buff *skb); - - unsigned short flags; -#define DST_HOST 0x0001 -#define DST_NOXFRM 0x0002 -#define DST_NOPOLICY 0x0004 -#define DST_NOHASH 0x0008 -#define DST_NOCACHE 0x0010 -#define DST_NOCOUNT 0x0020 -#define DST_FAKE_RTABLE 0x0040 -#define DST_XFRM_TUNNEL 0x0080 -#define DST_XFRM_QUEUE 0x0100 -#define DST_METADATA 0x0200 - - unsigned short pending_confirm; - - short error; - - /* A non-zero value of dst->obsolete forces by-hand validation - * of the route entry. Positive values are set by the generic - * dst layer to indicate that the entry has been forcefully - * destroyed. - * - * Negative values are used by the implementation layer code to - * force invocation of the dst_ops->check() method. - */ - short obsolete; -#define DST_OBSOLETE_NONE 0 -#define DST_OBSOLETE_DEAD 2 -#define DST_OBSOLETE_FORCE_CHK -1 -#define DST_OBSOLETE_KILL -2 - unsigned short header_len; /* more space at head required */ - unsigned short trailer_len; /* space to reserve at tail */ -#ifdef CONFIG_IP_ROUTE_CLASSID - __u32 tclassid; -#else - __u32 __pad2; -#endif - -#ifdef CONFIG_64BIT - /* - * Align __refcnt to a 64 bytes alignment - * (L1_CACHE_SIZE would be too much) - */ - long __pad_to_align_refcnt[2]; -#endif - /* - * __refcnt wants to be on a different cache line from - * input/output/ops or performance tanks badly - */ - atomic_t __refcnt; /* client references */ - int __use; - unsigned long lastuse; - struct lwtunnel_state *lwtstate; - union { - struct dst_entry *next; - struct rtable __rcu *rt_next; - struct rt6_info *rt6_next; - struct dn_route __rcu *dn_next; - }; -}; - -u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old); -extern const u32 dst_default_metrics[]; - -#define DST_METRICS_READ_ONLY 0x1UL -#define DST_METRICS_FLAGS 0x3UL -#define __DST_METRICS_PTR(Y) \ - ((u32 *)((Y) & ~DST_METRICS_FLAGS)) -#define DST_METRICS_PTR(X) __DST_METRICS_PTR((X)->_metrics) - -static inline bool dst_metrics_read_only(const struct dst_entry *dst) -{ - return dst->_metrics & DST_METRICS_READ_ONLY; -} - -void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old); - -static inline void dst_destroy_metrics_generic(struct dst_entry *dst) -{ - unsigned long val = dst->_metrics; - if (!(val & DST_METRICS_READ_ONLY)) - __dst_destroy_metrics_generic(dst, val); -} - -static inline u32 *dst_metrics_write_ptr(struct dst_entry *dst) -{ - unsigned long p = dst->_metrics; - - BUG_ON(!p); - - if (p & DST_METRICS_READ_ONLY) - return dst->ops->cow_metrics(dst, p); - return __DST_METRICS_PTR(p); -} - -/* This may only be invoked before the entry has reached global - * visibility. - */ -static inline void dst_init_metrics(struct dst_entry *dst, - const u32 *src_metrics, - bool read_only) -{ - dst->_metrics = ((unsigned long) src_metrics) | - (read_only ? DST_METRICS_READ_ONLY : 0); -} - -static inline void dst_copy_metrics(struct dst_entry *dest, const struct dst_entry *src) -{ - u32 *dst_metrics = dst_metrics_write_ptr(dest); - - if (dst_metrics) { - u32 *src_metrics = DST_METRICS_PTR(src); - - memcpy(dst_metrics, src_metrics, RTAX_MAX * sizeof(u32)); - } -} - -static inline u32 *dst_metrics_ptr(struct dst_entry *dst) -{ - return DST_METRICS_PTR(dst); -} - -static inline u32 -dst_metric_raw(const struct dst_entry *dst, const int metric) -{ - u32 *p = DST_METRICS_PTR(dst); - - return p[metric-1]; -} - -static inline u32 -dst_metric(const struct dst_entry *dst, const int metric) -{ - WARN_ON_ONCE(metric == RTAX_HOPLIMIT || - metric == RTAX_ADVMSS || - metric == RTAX_MTU); - return dst_metric_raw(dst, metric); -} - -static inline u32 -dst_metric_advmss(const struct dst_entry *dst) -{ - u32 advmss = dst_metric_raw(dst, RTAX_ADVMSS); - - if (!advmss) - advmss = dst->ops->default_advmss(dst); - - return advmss; -} - -static inline void dst_metric_set(struct dst_entry *dst, int metric, u32 val) -{ - u32 *p = dst_metrics_write_ptr(dst); - - if (p) - p[metric-1] = val; -} - -/* Kernel-internal feature bits that are unallocated in user space. */ -#define DST_FEATURE_ECN_CA (1 << 31) - -#define DST_FEATURE_MASK (DST_FEATURE_ECN_CA) -#define DST_FEATURE_ECN_MASK (DST_FEATURE_ECN_CA | RTAX_FEATURE_ECN) - -static inline u32 -dst_feature(const struct dst_entry *dst, u32 feature) -{ - return dst_metric(dst, RTAX_FEATURES) & feature; -} - -static inline u32 dst_mtu(const struct dst_entry *dst) -{ - return dst->ops->mtu(dst); -} - -/* RTT metrics are stored in milliseconds for user ABI, but used as jiffies */ -static inline unsigned long dst_metric_rtt(const struct dst_entry *dst, int metric) -{ - return msecs_to_jiffies(dst_metric(dst, metric)); -} - -static inline u32 -dst_allfrag(const struct dst_entry *dst) -{ - int ret = dst_feature(dst, RTAX_FEATURE_ALLFRAG); - return ret; -} - -static inline int -dst_metric_locked(const struct dst_entry *dst, int metric) -{ - return dst_metric(dst, RTAX_LOCK) & (1<__refcnt); -} - -static inline void dst_use(struct dst_entry *dst, unsigned long time) -{ - dst_hold(dst); - dst->__use++; - dst->lastuse = time; -} - -static inline void dst_use_noref(struct dst_entry *dst, unsigned long time) -{ - dst->__use++; - dst->lastuse = time; -} - -static inline struct dst_entry *dst_clone(struct dst_entry *dst) -{ - if (dst) - atomic_inc(&dst->__refcnt); - return dst; -} - -void dst_release(struct dst_entry *dst); - -static inline void refdst_drop(unsigned long refdst) -{ - if (!(refdst & SKB_DST_NOREF)) - dst_release((struct dst_entry *)(refdst & SKB_DST_PTRMASK)); -} - -/** - * skb_dst_drop - drops skb dst - * @skb: buffer - * - * Drops dst reference count if a reference was taken. - */ -static inline void skb_dst_drop(struct sk_buff *skb) -{ - if (skb->_skb_refdst) { - refdst_drop(skb->_skb_refdst); - skb->_skb_refdst = 0UL; - } -} - -static inline void __skb_dst_copy(struct sk_buff *nskb, unsigned long refdst) -{ - nskb->_skb_refdst = refdst; - if (!(nskb->_skb_refdst & SKB_DST_NOREF)) - dst_clone(skb_dst(nskb)); -} - -static inline void skb_dst_copy(struct sk_buff *nskb, const struct sk_buff *oskb) -{ - __skb_dst_copy(nskb, oskb->_skb_refdst); -} - -/** - * skb_dst_force - makes sure skb dst is refcounted - * @skb: buffer - * - * If dst is not yet refcounted, let's do it - */ -static inline void skb_dst_force(struct sk_buff *skb) -{ - if (skb_dst_is_noref(skb)) { - WARN_ON(!rcu_read_lock_held()); - skb->_skb_refdst &= ~SKB_DST_NOREF; - dst_clone(skb_dst(skb)); - } -} - -/** - * dst_hold_safe - Take a reference on a dst if possible - * @dst: pointer to dst entry - * - * This helper returns false if it could not safely - * take a reference on a dst. - */ -static inline bool dst_hold_safe(struct dst_entry *dst) -{ - if (dst->flags & DST_NOCACHE) - return atomic_inc_not_zero(&dst->__refcnt); - dst_hold(dst); - return true; -} - -/** - * skb_dst_force_safe - makes sure skb dst is refcounted - * @skb: buffer - * - * If dst is not yet refcounted and not destroyed, grab a ref on it. - */ -static inline void skb_dst_force_safe(struct sk_buff *skb) -{ - if (skb_dst_is_noref(skb)) { - struct dst_entry *dst = skb_dst(skb); - - if (!dst_hold_safe(dst)) - dst = NULL; - - skb->_skb_refdst = (unsigned long)dst; - } -} - - -/** - * __skb_tunnel_rx - prepare skb for rx reinsert - * @skb: buffer - * @dev: tunnel device - * @net: netns for packet i/o - * - * After decapsulation, packet is going to re-enter (netif_rx()) our stack, - * so make some cleanups. (no accounting done) - */ -static inline void __skb_tunnel_rx(struct sk_buff *skb, struct net_device *dev, - struct net *net) -{ - skb->dev = dev; - - /* - * Clear hash so that we can recalulate the hash for the - * encapsulated packet, unless we have already determine the hash - * over the L4 4-tuple. - */ - skb_clear_hash_if_not_l4(skb); - skb_set_queue_mapping(skb, 0); - skb_scrub_packet(skb, !net_eq(net, dev_net(dev))); -} - -/** - * skb_tunnel_rx - prepare skb for rx reinsert - * @skb: buffer - * @dev: tunnel device - * - * After decapsulation, packet is going to re-enter (netif_rx()) our stack, - * so make some cleanups, and perform accounting. - * Note: this accounting is not SMP safe. - */ -static inline void skb_tunnel_rx(struct sk_buff *skb, struct net_device *dev, - struct net *net) -{ - /* TODO : stats should be SMP safe */ - dev->stats.rx_packets++; - dev->stats.rx_bytes += skb->len; - __skb_tunnel_rx(skb, dev, net); -} - -static inline u32 dst_tclassid(const struct sk_buff *skb) -{ -#ifdef CONFIG_IP_ROUTE_CLASSID - const struct dst_entry *dst; - - dst = skb_dst(skb); - if (dst) - return dst->tclassid; -#endif - return 0; -} - -int dst_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb); -static inline int dst_discard(struct sk_buff *skb) -{ - return dst_discard_out(&init_net, skb->sk, skb); -} -void *dst_alloc(struct dst_ops *ops, struct net_device *dev, int initial_ref, - int initial_obsolete, unsigned short flags); -void dst_init(struct dst_entry *dst, struct dst_ops *ops, - struct net_device *dev, int initial_ref, int initial_obsolete, - unsigned short flags); -void __dst_free(struct dst_entry *dst); -struct dst_entry *dst_destroy(struct dst_entry *dst); - -static inline void dst_free(struct dst_entry *dst) -{ - if (dst->obsolete > 0) - return; - if (!atomic_read(&dst->__refcnt)) { - dst = dst_destroy(dst); - if (!dst) - return; - } - __dst_free(dst); -} - -static inline void dst_rcu_free(struct rcu_head *head) -{ - struct dst_entry *dst = container_of(head, struct dst_entry, rcu_head); - dst_free(dst); -} - -static inline void dst_confirm(struct dst_entry *dst) -{ - dst->pending_confirm = 1; -} - -static inline int dst_neigh_output(struct dst_entry *dst, struct neighbour *n, - struct sk_buff *skb) -{ - const struct hh_cache *hh; - - if (dst->pending_confirm) { - unsigned long now = jiffies; - - dst->pending_confirm = 0; - /* avoid dirtying neighbour */ - if (n->confirmed != now) - n->confirmed = now; - } - - hh = &n->hh; - if ((n->nud_state & NUD_CONNECTED) && hh->hh_len) - return neigh_hh_output(hh, skb); - else - return n->output(n, skb); -} - -static inline struct neighbour *dst_neigh_lookup(const struct dst_entry *dst, const void *daddr) -{ - struct neighbour *n = dst->ops->neigh_lookup(dst, NULL, daddr); - return IS_ERR(n) ? NULL : n; -} - -static inline struct neighbour *dst_neigh_lookup_skb(const struct dst_entry *dst, - struct sk_buff *skb) -{ - struct neighbour *n = dst->ops->neigh_lookup(dst, skb, NULL); - return IS_ERR(n) ? NULL : n; -} - -static inline void dst_link_failure(struct sk_buff *skb) -{ - struct dst_entry *dst = skb_dst(skb); - if (dst && dst->ops && dst->ops->link_failure) - dst->ops->link_failure(skb); -} - -static inline void dst_set_expires(struct dst_entry *dst, int timeout) -{ - unsigned long expires = jiffies + timeout; - - if (expires == 0) - expires = 1; - - if (dst->expires == 0 || time_before(expires, dst->expires)) - dst->expires = expires; -} - -/* Output packet to network from transport. */ -static inline int dst_output(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - return skb_dst(skb)->output(net, sk, skb); -} - -/* Input packet from network to transport. */ -static inline int dst_input(struct sk_buff *skb) -{ - return skb_dst(skb)->input(skb); -} - -static inline struct dst_entry *dst_check(struct dst_entry *dst, u32 cookie) -{ - if (dst->obsolete) - dst = dst->ops->check(dst, cookie); - return dst; -} - -void dst_subsys_init(void); - -/* Flags for xfrm_lookup flags argument. */ -enum { - XFRM_LOOKUP_ICMP = 1 << 0, - XFRM_LOOKUP_QUEUE = 1 << 1, - XFRM_LOOKUP_KEEP_DST_REF = 1 << 2, -}; - -struct flowi; -#ifndef CONFIG_XFRM -static inline struct dst_entry *xfrm_lookup(struct net *net, - struct dst_entry *dst_orig, - const struct flowi *fl, - const struct sock *sk, - int flags) -{ - return dst_orig; -} - -static inline struct dst_entry *xfrm_lookup_route(struct net *net, - struct dst_entry *dst_orig, - const struct flowi *fl, - const struct sock *sk, - int flags) -{ - return dst_orig; -} - -static inline struct xfrm_state *dst_xfrm(const struct dst_entry *dst) -{ - return NULL; -} - -#else -struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, - const struct flowi *fl, const struct sock *sk, - int flags); - -struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig, - const struct flowi *fl, const struct sock *sk, - int flags); - -/* skb attached with this dst needs transformation if dst->xfrm is valid */ -static inline struct xfrm_state *dst_xfrm(const struct dst_entry *dst) -{ - return dst->xfrm; -} -#endif - -#endif /* _NET_DST_H */ diff --git a/src/linux/include/net/dst_cache.h b/src/linux/include/net/dst_cache.h deleted file mode 100644 index 151acca..0000000 --- a/src/linux/include/net/dst_cache.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef _NET_DST_CACHE_H -#define _NET_DST_CACHE_H - -#include -#include -#if IS_ENABLED(CONFIG_IPV6) -#include -#endif - -struct dst_cache { - struct dst_cache_pcpu __percpu *cache; - unsigned long reset_ts; -}; - -/** - * dst_cache_get - perform cache lookup - * @dst_cache: the cache - * - * The caller should use dst_cache_get_ip4() if it need to retrieve the - * source address to be used when xmitting to the cached dst. - * local BH must be disabled. - */ -struct dst_entry *dst_cache_get(struct dst_cache *dst_cache); - -/** - * dst_cache_get_ip4 - perform cache lookup and fetch ipv4 source address - * @dst_cache: the cache - * @saddr: return value for the retrieved source address - * - * local BH must be disabled. - */ -struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr); - -/** - * dst_cache_set_ip4 - store the ipv4 dst into the cache - * @dst_cache: the cache - * @dst: the entry to be cached - * @saddr: the source address to be stored inside the cache - * - * local BH must be disabled. - */ -void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst, - __be32 saddr); - -#if IS_ENABLED(CONFIG_IPV6) - -/** - * dst_cache_set_ip6 - store the ipv6 dst into the cache - * @dst_cache: the cache - * @dst: the entry to be cached - * @saddr: the source address to be stored inside the cache - * - * local BH must be disabled. - */ -void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst, - const struct in6_addr *addr); - -/** - * dst_cache_get_ip6 - perform cache lookup and fetch ipv6 source address - * @dst_cache: the cache - * @saddr: return value for the retrieved source address - * - * local BH must be disabled. - */ -struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache, - struct in6_addr *saddr); -#endif - -/** - * dst_cache_reset - invalidate the cache contents - * @dst_cache: the cache - * - * This do not free the cached dst to avoid races and contentions. - * the dst will be freed on later cache lookup. - */ -static inline void dst_cache_reset(struct dst_cache *dst_cache) -{ - dst_cache->reset_ts = jiffies; -} - -/** - * dst_cache_init - initialize the cache, allocating the required storage - * @dst_cache: the cache - * @gfp: allocation flags - */ -int dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp); - -/** - * dst_cache_destroy - empty the cache and free the allocated storage - * @dst_cache: the cache - * - * No synchronization is enforced: it must be called only when the cache - * is unsed. - */ -void dst_cache_destroy(struct dst_cache *dst_cache); - -#endif diff --git a/src/linux/include/net/dst_metadata.h b/src/linux/include/net/dst_metadata.h deleted file mode 100644 index 6965c8f..0000000 --- a/src/linux/include/net/dst_metadata.h +++ /dev/null @@ -1,189 +0,0 @@ -#ifndef __NET_DST_METADATA_H -#define __NET_DST_METADATA_H 1 - -#include -#include -#include - -struct metadata_dst { - struct dst_entry dst; - union { - struct ip_tunnel_info tun_info; - } u; -}; - -static inline struct metadata_dst *skb_metadata_dst(struct sk_buff *skb) -{ - struct metadata_dst *md_dst = (struct metadata_dst *) skb_dst(skb); - - if (md_dst && md_dst->dst.flags & DST_METADATA) - return md_dst; - - return NULL; -} - -static inline struct ip_tunnel_info *skb_tunnel_info(struct sk_buff *skb) -{ - struct metadata_dst *md_dst = skb_metadata_dst(skb); - struct dst_entry *dst; - - if (md_dst) - return &md_dst->u.tun_info; - - dst = skb_dst(skb); - if (dst && dst->lwtstate) - return lwt_tun_info(dst->lwtstate); - - return NULL; -} - -static inline bool skb_valid_dst(const struct sk_buff *skb) -{ - struct dst_entry *dst = skb_dst(skb); - - return dst && !(dst->flags & DST_METADATA); -} - -static inline int skb_metadata_dst_cmp(const struct sk_buff *skb_a, - const struct sk_buff *skb_b) -{ - const struct metadata_dst *a, *b; - - if (!(skb_a->_skb_refdst | skb_b->_skb_refdst)) - return 0; - - a = (const struct metadata_dst *) skb_dst(skb_a); - b = (const struct metadata_dst *) skb_dst(skb_b); - - if (!a != !b || a->u.tun_info.options_len != b->u.tun_info.options_len) - return 1; - - return memcmp(&a->u.tun_info, &b->u.tun_info, - sizeof(a->u.tun_info) + a->u.tun_info.options_len); -} - -void metadata_dst_free(struct metadata_dst *); -struct metadata_dst *metadata_dst_alloc(u8 optslen, gfp_t flags); -struct metadata_dst __percpu *metadata_dst_alloc_percpu(u8 optslen, gfp_t flags); - -static inline struct metadata_dst *tun_rx_dst(int md_size) -{ - struct metadata_dst *tun_dst; - - tun_dst = metadata_dst_alloc(md_size, GFP_ATOMIC); - if (!tun_dst) - return NULL; - - tun_dst->u.tun_info.options_len = 0; - tun_dst->u.tun_info.mode = 0; - return tun_dst; -} - -static inline struct metadata_dst *tun_dst_unclone(struct sk_buff *skb) -{ - struct metadata_dst *md_dst = skb_metadata_dst(skb); - int md_size; - struct metadata_dst *new_md; - - if (!md_dst) - return ERR_PTR(-EINVAL); - - md_size = md_dst->u.tun_info.options_len; - new_md = metadata_dst_alloc(md_size, GFP_ATOMIC); - if (!new_md) - return ERR_PTR(-ENOMEM); - - memcpy(&new_md->u.tun_info, &md_dst->u.tun_info, - sizeof(struct ip_tunnel_info) + md_size); - skb_dst_drop(skb); - dst_hold(&new_md->dst); - skb_dst_set(skb, &new_md->dst); - return new_md; -} - -static inline struct ip_tunnel_info *skb_tunnel_info_unclone(struct sk_buff *skb) -{ - struct metadata_dst *dst; - - dst = tun_dst_unclone(skb); - if (IS_ERR(dst)) - return NULL; - - return &dst->u.tun_info; -} - -static inline struct metadata_dst *__ip_tun_set_dst(__be32 saddr, - __be32 daddr, - __u8 tos, __u8 ttl, - __be16 flags, - __be64 tunnel_id, - int md_size) -{ - struct metadata_dst *tun_dst; - - tun_dst = tun_rx_dst(md_size); - if (!tun_dst) - return NULL; - - ip_tunnel_key_init(&tun_dst->u.tun_info.key, - saddr, daddr, tos, ttl, - 0, 0, 0, tunnel_id, flags); - return tun_dst; -} - -static inline struct metadata_dst *ip_tun_rx_dst(struct sk_buff *skb, - __be16 flags, - __be64 tunnel_id, - int md_size) -{ - const struct iphdr *iph = ip_hdr(skb); - - return __ip_tun_set_dst(iph->saddr, iph->daddr, iph->tos, iph->ttl, - flags, tunnel_id, md_size); -} - -static inline struct metadata_dst *__ipv6_tun_set_dst(const struct in6_addr *saddr, - const struct in6_addr *daddr, - __u8 tos, __u8 ttl, - __be32 label, - __be16 flags, - __be64 tunnel_id, - int md_size) -{ - struct metadata_dst *tun_dst; - struct ip_tunnel_info *info; - - tun_dst = tun_rx_dst(md_size); - if (!tun_dst) - return NULL; - - info = &tun_dst->u.tun_info; - info->mode = IP_TUNNEL_INFO_IPV6; - info->key.tun_flags = flags; - info->key.tun_id = tunnel_id; - info->key.tp_src = 0; - info->key.tp_dst = 0; - - info->key.u.ipv6.src = *saddr; - info->key.u.ipv6.dst = *daddr; - - info->key.tos = tos; - info->key.ttl = ttl; - info->key.label = label; - - return tun_dst; -} - -static inline struct metadata_dst *ipv6_tun_rx_dst(struct sk_buff *skb, - __be16 flags, - __be64 tunnel_id, - int md_size) -{ - const struct ipv6hdr *ip6h = ipv6_hdr(skb); - - return __ipv6_tun_set_dst(&ip6h->saddr, &ip6h->daddr, - ipv6_get_dsfield(ip6h), ip6h->hop_limit, - ip6_flowlabel(ip6h), flags, tunnel_id, - md_size); -} -#endif /* __NET_DST_METADATA_H */ diff --git a/src/linux/include/net/dst_ops.h b/src/linux/include/net/dst_ops.h deleted file mode 100644 index a0d443c..0000000 --- a/src/linux/include/net/dst_ops.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef _NET_DST_OPS_H -#define _NET_DST_OPS_H -#include -#include -#include - -struct dst_entry; -struct kmem_cachep; -struct net_device; -struct sk_buff; -struct sock; -struct net; - -struct dst_ops { - unsigned short family; - unsigned int gc_thresh; - - int (*gc)(struct dst_ops *ops); - struct dst_entry * (*check)(struct dst_entry *, __u32 cookie); - unsigned int (*default_advmss)(const struct dst_entry *); - unsigned int (*mtu)(const struct dst_entry *); - u32 * (*cow_metrics)(struct dst_entry *, unsigned long); - void (*destroy)(struct dst_entry *); - void (*ifdown)(struct dst_entry *, - struct net_device *dev, int how); - struct dst_entry * (*negative_advice)(struct dst_entry *); - void (*link_failure)(struct sk_buff *); - void (*update_pmtu)(struct dst_entry *dst, struct sock *sk, - struct sk_buff *skb, u32 mtu); - void (*redirect)(struct dst_entry *dst, struct sock *sk, - struct sk_buff *skb); - int (*local_out)(struct net *net, struct sock *sk, struct sk_buff *skb); - struct neighbour * (*neigh_lookup)(const struct dst_entry *dst, - struct sk_buff *skb, - const void *daddr); - - struct kmem_cache *kmem_cachep; - - struct percpu_counter pcpuc_entries ____cacheline_aligned_in_smp; -}; - -static inline int dst_entries_get_fast(struct dst_ops *dst) -{ - return percpu_counter_read_positive(&dst->pcpuc_entries); -} - -static inline int dst_entries_get_slow(struct dst_ops *dst) -{ - int res; - - local_bh_disable(); - res = percpu_counter_sum_positive(&dst->pcpuc_entries); - local_bh_enable(); - return res; -} - -static inline void dst_entries_add(struct dst_ops *dst, int val) -{ - local_bh_disable(); - percpu_counter_add(&dst->pcpuc_entries, val); - local_bh_enable(); -} - -static inline int dst_entries_init(struct dst_ops *dst) -{ - return percpu_counter_init(&dst->pcpuc_entries, 0, GFP_KERNEL); -} - -static inline void dst_entries_destroy(struct dst_ops *dst) -{ - percpu_counter_destroy(&dst->pcpuc_entries); -} - -#endif diff --git a/src/linux/include/net/fib_rules.h b/src/linux/include/net/fib_rules.h deleted file mode 100644 index 456e4a6..0000000 --- a/src/linux/include/net/fib_rules.h +++ /dev/null @@ -1,140 +0,0 @@ -#ifndef __NET_FIB_RULES_H -#define __NET_FIB_RULES_H - -#include -#include -#include -#include -#include -#include - -struct fib_rule { - struct list_head list; - int iifindex; - int oifindex; - u32 mark; - u32 mark_mask; - u32 flags; - u32 table; - u8 action; - u8 l3mdev; - /* 2 bytes hole, try to use */ - u32 target; - __be64 tun_id; - struct fib_rule __rcu *ctarget; - struct net *fr_net; - - atomic_t refcnt; - u32 pref; - int suppress_ifgroup; - int suppress_prefixlen; - char iifname[IFNAMSIZ]; - char oifname[IFNAMSIZ]; - struct rcu_head rcu; -}; - -struct fib_lookup_arg { - void *lookup_ptr; - void *result; - struct fib_rule *rule; - u32 table; - int flags; -#define FIB_LOOKUP_NOREF 1 -#define FIB_LOOKUP_IGNORE_LINKSTATE 2 -}; - -struct fib_rules_ops { - int family; - struct list_head list; - int rule_size; - int addr_size; - int unresolved_rules; - int nr_goto_rules; - - int (*action)(struct fib_rule *, - struct flowi *, int, - struct fib_lookup_arg *); - bool (*suppress)(struct fib_rule *, - struct fib_lookup_arg *); - int (*match)(struct fib_rule *, - struct flowi *, int); - int (*configure)(struct fib_rule *, - struct sk_buff *, - struct fib_rule_hdr *, - struct nlattr **); - int (*delete)(struct fib_rule *); - int (*compare)(struct fib_rule *, - struct fib_rule_hdr *, - struct nlattr **); - int (*fill)(struct fib_rule *, struct sk_buff *, - struct fib_rule_hdr *); - size_t (*nlmsg_payload)(struct fib_rule *); - - /* Called after modifications to the rules set, must flush - * the route cache if one exists. */ - void (*flush_cache)(struct fib_rules_ops *ops); - - int nlgroup; - const struct nla_policy *policy; - struct list_head rules_list; - struct module *owner; - struct net *fro_net; - struct rcu_head rcu; -}; - -#define FRA_GENERIC_POLICY \ - [FRA_IIFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, \ - [FRA_OIFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, \ - [FRA_PRIORITY] = { .type = NLA_U32 }, \ - [FRA_FWMARK] = { .type = NLA_U32 }, \ - [FRA_FWMASK] = { .type = NLA_U32 }, \ - [FRA_TABLE] = { .type = NLA_U32 }, \ - [FRA_SUPPRESS_PREFIXLEN] = { .type = NLA_U32 }, \ - [FRA_SUPPRESS_IFGROUP] = { .type = NLA_U32 }, \ - [FRA_GOTO] = { .type = NLA_U32 }, \ - [FRA_L3MDEV] = { .type = NLA_U8 } - -static inline void fib_rule_get(struct fib_rule *rule) -{ - atomic_inc(&rule->refcnt); -} - -static inline void fib_rule_put(struct fib_rule *rule) -{ - if (atomic_dec_and_test(&rule->refcnt)) - kfree_rcu(rule, rcu); -} - -#ifdef CONFIG_NET_L3_MASTER_DEV -static inline u32 fib_rule_get_table(struct fib_rule *rule, - struct fib_lookup_arg *arg) -{ - return rule->l3mdev ? arg->table : rule->table; -} -#else -static inline u32 fib_rule_get_table(struct fib_rule *rule, - struct fib_lookup_arg *arg) -{ - return rule->table; -} -#endif - -static inline u32 frh_get_table(struct fib_rule_hdr *frh, struct nlattr **nla) -{ - if (nla[FRA_TABLE]) - return nla_get_u32(nla[FRA_TABLE]); - return frh->table; -} - -struct fib_rules_ops *fib_rules_register(const struct fib_rules_ops *, - struct net *); -void fib_rules_unregister(struct fib_rules_ops *); - -int fib_rules_lookup(struct fib_rules_ops *, struct flowi *, int flags, - struct fib_lookup_arg *); -int fib_default_rule_add(struct fib_rules_ops *, u32 pref, u32 table, - u32 flags); - -int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr *nlh); -int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr *nlh); -#endif diff --git a/src/linux/include/net/firewire.h b/src/linux/include/net/firewire.h deleted file mode 100644 index 31bcbfe..0000000 --- a/src/linux/include/net/firewire.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _NET_FIREWIRE_H -#define _NET_FIREWIRE_H - -/* Pseudo L2 address */ -#define FWNET_ALEN 16 -union fwnet_hwaddr { - u8 u[FWNET_ALEN]; - /* "Hardware address" defined in RFC2734/RF3146 */ - struct { - __be64 uniq_id; /* EUI-64 */ - u8 max_rec; /* max packet size */ - u8 sspd; /* max speed */ - __be16 fifo_hi; /* hi 16bits of FIFO addr */ - __be32 fifo_lo; /* lo 32bits of FIFO addr */ - } __packed uc; -}; - -/* Pseudo L2 Header */ -#define FWNET_HLEN 18 -struct fwnet_header { - u8 h_dest[FWNET_ALEN]; /* destination address */ - __be16 h_proto; /* packet type ID field */ -} __packed; - -#endif diff --git a/src/linux/include/net/flow.h b/src/linux/include/net/flow.h deleted file mode 100644 index 035aa77..0000000 --- a/src/linux/include/net/flow.h +++ /dev/null @@ -1,265 +0,0 @@ -/* - * - * Generic internet FLOW. - * - */ - -#ifndef _NET_FLOW_H -#define _NET_FLOW_H - -#include -#include -#include -#include - -/* - * ifindex generation is per-net namespace, and loopback is - * always the 1st device in ns (see net_dev_init), thus any - * loopback device should get ifindex 1 - */ - -#define LOOPBACK_IFINDEX 1 - -struct flowi_tunnel { - __be64 tun_id; -}; - -struct flowi_common { - int flowic_oif; - int flowic_iif; - __u32 flowic_mark; - __u8 flowic_tos; - __u8 flowic_scope; - __u8 flowic_proto; - __u8 flowic_flags; -#define FLOWI_FLAG_ANYSRC 0x01 -#define FLOWI_FLAG_KNOWN_NH 0x02 -#define FLOWI_FLAG_SKIP_NH_OIF 0x04 - __u32 flowic_secid; - struct flowi_tunnel flowic_tun_key; -}; - -union flowi_uli { - struct { - __be16 dport; - __be16 sport; - } ports; - - struct { - __u8 type; - __u8 code; - } icmpt; - - struct { - __le16 dport; - __le16 sport; - } dnports; - - __be32 spi; - __be32 gre_key; - - struct { - __u8 type; - } mht; -}; - -struct flowi4 { - struct flowi_common __fl_common; -#define flowi4_oif __fl_common.flowic_oif -#define flowi4_iif __fl_common.flowic_iif -#define flowi4_mark __fl_common.flowic_mark -#define flowi4_tos __fl_common.flowic_tos -#define flowi4_scope __fl_common.flowic_scope -#define flowi4_proto __fl_common.flowic_proto -#define flowi4_flags __fl_common.flowic_flags -#define flowi4_secid __fl_common.flowic_secid -#define flowi4_tun_key __fl_common.flowic_tun_key - - /* (saddr,daddr) must be grouped, same order as in IP header */ - __be32 saddr; - __be32 daddr; - - union flowi_uli uli; -#define fl4_sport uli.ports.sport -#define fl4_dport uli.ports.dport -#define fl4_icmp_type uli.icmpt.type -#define fl4_icmp_code uli.icmpt.code -#define fl4_ipsec_spi uli.spi -#define fl4_mh_type uli.mht.type -#define fl4_gre_key uli.gre_key -} __attribute__((__aligned__(BITS_PER_LONG/8))); - -static inline void flowi4_init_output(struct flowi4 *fl4, int oif, - __u32 mark, __u8 tos, __u8 scope, - __u8 proto, __u8 flags, - __be32 daddr, __be32 saddr, - __be16 dport, __be16 sport) -{ - fl4->flowi4_oif = oif; - fl4->flowi4_iif = LOOPBACK_IFINDEX; - fl4->flowi4_mark = mark; - fl4->flowi4_tos = tos; - fl4->flowi4_scope = scope; - fl4->flowi4_proto = proto; - fl4->flowi4_flags = flags; - fl4->flowi4_secid = 0; - fl4->flowi4_tun_key.tun_id = 0; - fl4->daddr = daddr; - fl4->saddr = saddr; - fl4->fl4_dport = dport; - fl4->fl4_sport = sport; -} - -/* Reset some input parameters after previous lookup */ -static inline void flowi4_update_output(struct flowi4 *fl4, int oif, __u8 tos, - __be32 daddr, __be32 saddr) -{ - fl4->flowi4_oif = oif; - fl4->flowi4_tos = tos; - fl4->daddr = daddr; - fl4->saddr = saddr; -} - - -struct flowi6 { - struct flowi_common __fl_common; -#define flowi6_oif __fl_common.flowic_oif -#define flowi6_iif __fl_common.flowic_iif -#define flowi6_mark __fl_common.flowic_mark -#define flowi6_scope __fl_common.flowic_scope -#define flowi6_proto __fl_common.flowic_proto -#define flowi6_flags __fl_common.flowic_flags -#define flowi6_secid __fl_common.flowic_secid -#define flowi6_tun_key __fl_common.flowic_tun_key - struct in6_addr daddr; - struct in6_addr saddr; - /* Note: flowi6_tos is encoded in flowlabel, too. */ - __be32 flowlabel; - union flowi_uli uli; -#define fl6_sport uli.ports.sport -#define fl6_dport uli.ports.dport -#define fl6_icmp_type uli.icmpt.type -#define fl6_icmp_code uli.icmpt.code -#define fl6_ipsec_spi uli.spi -#define fl6_mh_type uli.mht.type -#define fl6_gre_key uli.gre_key -} __attribute__((__aligned__(BITS_PER_LONG/8))); - -struct flowidn { - struct flowi_common __fl_common; -#define flowidn_oif __fl_common.flowic_oif -#define flowidn_iif __fl_common.flowic_iif -#define flowidn_mark __fl_common.flowic_mark -#define flowidn_scope __fl_common.flowic_scope -#define flowidn_proto __fl_common.flowic_proto -#define flowidn_flags __fl_common.flowic_flags - __le16 daddr; - __le16 saddr; - union flowi_uli uli; -#define fld_sport uli.ports.sport -#define fld_dport uli.ports.dport -} __attribute__((__aligned__(BITS_PER_LONG/8))); - -struct flowi { - union { - struct flowi_common __fl_common; - struct flowi4 ip4; - struct flowi6 ip6; - struct flowidn dn; - } u; -#define flowi_oif u.__fl_common.flowic_oif -#define flowi_iif u.__fl_common.flowic_iif -#define flowi_mark u.__fl_common.flowic_mark -#define flowi_tos u.__fl_common.flowic_tos -#define flowi_scope u.__fl_common.flowic_scope -#define flowi_proto u.__fl_common.flowic_proto -#define flowi_flags u.__fl_common.flowic_flags -#define flowi_secid u.__fl_common.flowic_secid -#define flowi_tun_key u.__fl_common.flowic_tun_key -} __attribute__((__aligned__(BITS_PER_LONG/8))); - -static inline struct flowi *flowi4_to_flowi(struct flowi4 *fl4) -{ - return container_of(fl4, struct flowi, u.ip4); -} - -static inline struct flowi *flowi6_to_flowi(struct flowi6 *fl6) -{ - return container_of(fl6, struct flowi, u.ip6); -} - -static inline struct flowi *flowidn_to_flowi(struct flowidn *fldn) -{ - return container_of(fldn, struct flowi, u.dn); -} - -typedef unsigned long flow_compare_t; - -static inline size_t flow_key_size(u16 family) -{ - switch (family) { - case AF_INET: - BUILD_BUG_ON(sizeof(struct flowi4) % sizeof(flow_compare_t)); - return sizeof(struct flowi4) / sizeof(flow_compare_t); - case AF_INET6: - BUILD_BUG_ON(sizeof(struct flowi6) % sizeof(flow_compare_t)); - return sizeof(struct flowi6) / sizeof(flow_compare_t); - case AF_DECnet: - BUILD_BUG_ON(sizeof(struct flowidn) % sizeof(flow_compare_t)); - return sizeof(struct flowidn) / sizeof(flow_compare_t); - } - return 0; -} - -#define FLOW_DIR_IN 0 -#define FLOW_DIR_OUT 1 -#define FLOW_DIR_FWD 2 - -struct net; -struct sock; -struct flow_cache_ops; - -struct flow_cache_object { - const struct flow_cache_ops *ops; -}; - -struct flow_cache_ops { - struct flow_cache_object *(*get)(struct flow_cache_object *); - int (*check)(struct flow_cache_object *); - void (*delete)(struct flow_cache_object *); -}; - -typedef struct flow_cache_object *(*flow_resolve_t)( - struct net *net, const struct flowi *key, u16 family, - u8 dir, struct flow_cache_object *oldobj, void *ctx); - -struct flow_cache_object *flow_cache_lookup(struct net *net, - const struct flowi *key, u16 family, - u8 dir, flow_resolve_t resolver, - void *ctx); -int flow_cache_init(struct net *net); -void flow_cache_fini(struct net *net); - -void flow_cache_flush(struct net *net); -void flow_cache_flush_deferred(struct net *net); -extern atomic_t flow_cache_genid; - -__u32 __get_hash_from_flowi6(const struct flowi6 *fl6, struct flow_keys *keys); - -static inline __u32 get_hash_from_flowi6(const struct flowi6 *fl6) -{ - struct flow_keys keys; - - return __get_hash_from_flowi6(fl6, &keys); -} - -__u32 __get_hash_from_flowi4(const struct flowi4 *fl4, struct flow_keys *keys); - -static inline __u32 get_hash_from_flowi4(const struct flowi4 *fl4) -{ - struct flow_keys keys; - - return __get_hash_from_flowi4(fl4, &keys); -} - -#endif diff --git a/src/linux/include/net/flow_dissector.h b/src/linux/include/net/flow_dissector.h deleted file mode 100644 index d953492..0000000 --- a/src/linux/include/net/flow_dissector.h +++ /dev/null @@ -1,206 +0,0 @@ -#ifndef _NET_FLOW_DISSECTOR_H -#define _NET_FLOW_DISSECTOR_H - -#include -#include -#include - -/** - * struct flow_dissector_key_control: - * @thoff: Transport header offset - */ -struct flow_dissector_key_control { - u16 thoff; - u16 addr_type; - u32 flags; -}; - -#define FLOW_DIS_IS_FRAGMENT BIT(0) -#define FLOW_DIS_FIRST_FRAG BIT(1) -#define FLOW_DIS_ENCAPSULATION BIT(2) - -/** - * struct flow_dissector_key_basic: - * @thoff: Transport header offset - * @n_proto: Network header protocol (eg. IPv4/IPv6) - * @ip_proto: Transport header protocol (eg. TCP/UDP) - */ -struct flow_dissector_key_basic { - __be16 n_proto; - u8 ip_proto; - u8 padding; -}; - -struct flow_dissector_key_tags { - u32 flow_label; -}; - -struct flow_dissector_key_vlan { - u16 vlan_id:12, - vlan_priority:3; - u16 padding; -}; - -struct flow_dissector_key_keyid { - __be32 keyid; -}; - -/** - * struct flow_dissector_key_ipv4_addrs: - * @src: source ip address - * @dst: destination ip address - */ -struct flow_dissector_key_ipv4_addrs { - /* (src,dst) must be grouped, in the same way than in IP header */ - __be32 src; - __be32 dst; -}; - -/** - * struct flow_dissector_key_ipv6_addrs: - * @src: source ip address - * @dst: destination ip address - */ -struct flow_dissector_key_ipv6_addrs { - /* (src,dst) must be grouped, in the same way than in IP header */ - struct in6_addr src; - struct in6_addr dst; -}; - -/** - * struct flow_dissector_key_tipc_addrs: - * @srcnode: source node address - */ -struct flow_dissector_key_tipc_addrs { - __be32 srcnode; -}; - -/** - * struct flow_dissector_key_addrs: - * @v4addrs: IPv4 addresses - * @v6addrs: IPv6 addresses - */ -struct flow_dissector_key_addrs { - union { - struct flow_dissector_key_ipv4_addrs v4addrs; - struct flow_dissector_key_ipv6_addrs v6addrs; - struct flow_dissector_key_tipc_addrs tipcaddrs; - }; -}; - -/** - * flow_dissector_key_tp_ports: - * @ports: port numbers of Transport header - * src: source port number - * dst: destination port number - */ -struct flow_dissector_key_ports { - union { - __be32 ports; - struct { - __be16 src; - __be16 dst; - }; - }; -}; - - -/** - * struct flow_dissector_key_eth_addrs: - * @src: source Ethernet address - * @dst: destination Ethernet address - */ -struct flow_dissector_key_eth_addrs { - /* (dst,src) must be grouped, in the same way than in ETH header */ - unsigned char dst[ETH_ALEN]; - unsigned char src[ETH_ALEN]; -}; - -enum flow_dissector_key_id { - FLOW_DISSECTOR_KEY_CONTROL, /* struct flow_dissector_key_control */ - FLOW_DISSECTOR_KEY_BASIC, /* struct flow_dissector_key_basic */ - FLOW_DISSECTOR_KEY_IPV4_ADDRS, /* struct flow_dissector_key_ipv4_addrs */ - FLOW_DISSECTOR_KEY_IPV6_ADDRS, /* struct flow_dissector_key_ipv6_addrs */ - FLOW_DISSECTOR_KEY_PORTS, /* struct flow_dissector_key_ports */ - FLOW_DISSECTOR_KEY_ETH_ADDRS, /* struct flow_dissector_key_eth_addrs */ - FLOW_DISSECTOR_KEY_TIPC_ADDRS, /* struct flow_dissector_key_tipc_addrs */ - FLOW_DISSECTOR_KEY_VLAN, /* struct flow_dissector_key_flow_vlan */ - FLOW_DISSECTOR_KEY_FLOW_LABEL, /* struct flow_dissector_key_flow_tags */ - FLOW_DISSECTOR_KEY_GRE_KEYID, /* struct flow_dissector_key_keyid */ - FLOW_DISSECTOR_KEY_MPLS_ENTROPY, /* struct flow_dissector_key_keyid */ - - FLOW_DISSECTOR_KEY_MAX, -}; - -#define FLOW_DISSECTOR_F_PARSE_1ST_FRAG BIT(0) -#define FLOW_DISSECTOR_F_STOP_AT_L3 BIT(1) -#define FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL BIT(2) -#define FLOW_DISSECTOR_F_STOP_AT_ENCAP BIT(3) - -struct flow_dissector_key { - enum flow_dissector_key_id key_id; - size_t offset; /* offset of struct flow_dissector_key_* - in target the struct */ -}; - -struct flow_dissector { - unsigned int used_keys; /* each bit repesents presence of one key id */ - unsigned short int offset[FLOW_DISSECTOR_KEY_MAX]; -}; - -struct flow_keys { - struct flow_dissector_key_control control; -#define FLOW_KEYS_HASH_START_FIELD basic - struct flow_dissector_key_basic basic; - struct flow_dissector_key_tags tags; - struct flow_dissector_key_vlan vlan; - struct flow_dissector_key_keyid keyid; - struct flow_dissector_key_ports ports; - struct flow_dissector_key_addrs addrs; -}; - -#define FLOW_KEYS_HASH_OFFSET \ - offsetof(struct flow_keys, FLOW_KEYS_HASH_START_FIELD) - -__be32 flow_get_u32_src(const struct flow_keys *flow); -__be32 flow_get_u32_dst(const struct flow_keys *flow); - -extern struct flow_dissector flow_keys_dissector; -extern struct flow_dissector flow_keys_buf_dissector; - -/* struct flow_keys_digest: - * - * This structure is used to hold a digest of the full flow keys. This is a - * larger "hash" of a flow to allow definitively matching specific flows where - * the 32 bit skb->hash is not large enough. The size is limited to 16 bytes so - * that it can by used in CB of skb (see sch_choke for an example). - */ -#define FLOW_KEYS_DIGEST_LEN 16 -struct flow_keys_digest { - u8 data[FLOW_KEYS_DIGEST_LEN]; -}; - -void make_flow_keys_digest(struct flow_keys_digest *digest, - const struct flow_keys *flow); - -static inline bool flow_keys_have_l4(const struct flow_keys *keys) -{ - return (keys->ports.ports || keys->tags.flow_label); -} - -u32 flow_hash_from_keys(struct flow_keys *keys); - -static inline bool dissector_uses_key(const struct flow_dissector *flow_dissector, - enum flow_dissector_key_id key_id) -{ - return flow_dissector->used_keys & (1 << key_id); -} - -static inline void *skb_flow_dissector_target(struct flow_dissector *flow_dissector, - enum flow_dissector_key_id key_id, - void *target_container) -{ - return ((char *)target_container) + flow_dissector->offset[key_id]; -} - -#endif diff --git a/src/linux/include/net/flowcache.h b/src/linux/include/net/flowcache.h deleted file mode 100644 index c8f665e..0000000 --- a/src/linux/include/net/flowcache.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef _NET_FLOWCACHE_H -#define _NET_FLOWCACHE_H - -#include -#include -#include -#include - -struct flow_cache_percpu { - struct hlist_head *hash_table; - int hash_count; - u32 hash_rnd; - int hash_rnd_recalc; - struct tasklet_struct flush_tasklet; -}; - -struct flow_cache { - u32 hash_shift; - struct flow_cache_percpu __percpu *percpu; - struct notifier_block hotcpu_notifier; - int low_watermark; - int high_watermark; - struct timer_list rnd_timer; -}; -#endif /* _NET_FLOWCACHE_H */ diff --git a/src/linux/include/net/gen_stats.h b/src/linux/include/net/gen_stats.h deleted file mode 100644 index 231e121..0000000 --- a/src/linux/include/net/gen_stats.h +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef __NET_GEN_STATS_H -#define __NET_GEN_STATS_H - -#include -#include -#include -#include - -struct gnet_stats_basic_cpu { - struct gnet_stats_basic_packed bstats; - struct u64_stats_sync syncp; -}; - -struct gnet_dump { - spinlock_t * lock; - struct sk_buff * skb; - struct nlattr * tail; - - /* Backward compatibility */ - int compat_tc_stats; - int compat_xstats; - int padattr; - void * xstats; - int xstats_len; - struct tc_stats tc_stats; -}; - -int gnet_stats_start_copy(struct sk_buff *skb, int type, spinlock_t *lock, - struct gnet_dump *d, int padattr); - -int gnet_stats_start_copy_compat(struct sk_buff *skb, int type, - int tc_stats_type, int xstats_type, - spinlock_t *lock, struct gnet_dump *d, - int padattr); - -int gnet_stats_copy_basic(const seqcount_t *running, - struct gnet_dump *d, - struct gnet_stats_basic_cpu __percpu *cpu, - struct gnet_stats_basic_packed *b); -void __gnet_stats_copy_basic(const seqcount_t *running, - struct gnet_stats_basic_packed *bstats, - struct gnet_stats_basic_cpu __percpu *cpu, - struct gnet_stats_basic_packed *b); -int gnet_stats_copy_rate_est(struct gnet_dump *d, - const struct gnet_stats_basic_packed *b, - struct gnet_stats_rate_est64 *r); -int gnet_stats_copy_queue(struct gnet_dump *d, - struct gnet_stats_queue __percpu *cpu_q, - struct gnet_stats_queue *q, __u32 qlen); -int gnet_stats_copy_app(struct gnet_dump *d, void *st, int len); - -int gnet_stats_finish_copy(struct gnet_dump *d); - -int gen_new_estimator(struct gnet_stats_basic_packed *bstats, - struct gnet_stats_basic_cpu __percpu *cpu_bstats, - struct gnet_stats_rate_est64 *rate_est, - spinlock_t *stats_lock, - seqcount_t *running, struct nlattr *opt); -void gen_kill_estimator(struct gnet_stats_basic_packed *bstats, - struct gnet_stats_rate_est64 *rate_est); -int gen_replace_estimator(struct gnet_stats_basic_packed *bstats, - struct gnet_stats_basic_cpu __percpu *cpu_bstats, - struct gnet_stats_rate_est64 *rate_est, - spinlock_t *stats_lock, - seqcount_t *running, struct nlattr *opt); -bool gen_estimator_active(const struct gnet_stats_basic_packed *bstats, - const struct gnet_stats_rate_est64 *rate_est); -#endif diff --git a/src/linux/include/net/genetlink.h b/src/linux/include/net/genetlink.h deleted file mode 100644 index 8d4608c..0000000 --- a/src/linux/include/net/genetlink.h +++ /dev/null @@ -1,427 +0,0 @@ -#ifndef __NET_GENERIC_NETLINK_H -#define __NET_GENERIC_NETLINK_H - -#include -#include -#include - -#define GENLMSG_DEFAULT_SIZE (NLMSG_DEFAULT_SIZE - GENL_HDRLEN) - -/** - * struct genl_multicast_group - generic netlink multicast group - * @name: name of the multicast group, names are per-family - */ -struct genl_multicast_group { - char name[GENL_NAMSIZ]; -}; - -struct genl_ops; -struct genl_info; - -/** - * struct genl_family - generic netlink family - * @id: protocol family idenfitier - * @hdrsize: length of user specific header in bytes - * @name: name of family - * @version: protocol version - * @maxattr: maximum number of attributes supported - * @netnsok: set to true if the family can handle network - * namespaces and should be presented in all of them - * @parallel_ops: operations can be called in parallel and aren't - * synchronized by the core genetlink code - * @pre_doit: called before an operation's doit callback, it may - * do additional, common, filtering and return an error - * @post_doit: called after an operation's doit callback, it may - * undo operations done by pre_doit, for example release locks - * @mcast_bind: a socket bound to the given multicast group (which - * is given as the offset into the groups array) - * @mcast_unbind: a socket was unbound from the given multicast group. - * Note that unbind() will not be called symmetrically if the - * generic netlink family is removed while there are still open - * sockets. - * @attrbuf: buffer to store parsed attributes - * @family_list: family list - * @mcgrps: multicast groups used by this family (private) - * @n_mcgrps: number of multicast groups (private) - * @mcgrp_offset: starting number of multicast group IDs in this family - * @ops: the operations supported by this family (private) - * @n_ops: number of operations supported by this family (private) - */ -struct genl_family { - unsigned int id; - unsigned int hdrsize; - char name[GENL_NAMSIZ]; - unsigned int version; - unsigned int maxattr; - bool netnsok; - bool parallel_ops; - int (*pre_doit)(const struct genl_ops *ops, - struct sk_buff *skb, - struct genl_info *info); - void (*post_doit)(const struct genl_ops *ops, - struct sk_buff *skb, - struct genl_info *info); - int (*mcast_bind)(struct net *net, int group); - void (*mcast_unbind)(struct net *net, int group); - struct nlattr ** attrbuf; /* private */ - const struct genl_ops * ops; /* private */ - const struct genl_multicast_group *mcgrps; /* private */ - unsigned int n_ops; /* private */ - unsigned int n_mcgrps; /* private */ - unsigned int mcgrp_offset; /* private */ - struct list_head family_list; /* private */ - struct module *module; -}; - -/** - * struct genl_info - receiving information - * @snd_seq: sending sequence number - * @snd_portid: netlink portid of sender - * @nlhdr: netlink message header - * @genlhdr: generic netlink message header - * @userhdr: user specific header - * @attrs: netlink attributes - * @_net: network namespace - * @user_ptr: user pointers - */ -struct genl_info { - u32 snd_seq; - u32 snd_portid; - struct nlmsghdr * nlhdr; - struct genlmsghdr * genlhdr; - void * userhdr; - struct nlattr ** attrs; - possible_net_t _net; - void * user_ptr[2]; -}; - -static inline struct net *genl_info_net(struct genl_info *info) -{ - return read_pnet(&info->_net); -} - -static inline void genl_info_net_set(struct genl_info *info, struct net *net) -{ - write_pnet(&info->_net, net); -} - -/** - * struct genl_ops - generic netlink operations - * @cmd: command identifier - * @internal_flags: flags used by the family - * @flags: flags - * @policy: attribute validation policy - * @doit: standard command callback - * @start: start callback for dumps - * @dumpit: callback for dumpers - * @done: completion callback for dumps - * @ops_list: operations list - */ -struct genl_ops { - const struct nla_policy *policy; - int (*doit)(struct sk_buff *skb, - struct genl_info *info); - int (*start)(struct netlink_callback *cb); - int (*dumpit)(struct sk_buff *skb, - struct netlink_callback *cb); - int (*done)(struct netlink_callback *cb); - u8 cmd; - u8 internal_flags; - u8 flags; -}; - -int __genl_register_family(struct genl_family *family); - -static inline int genl_register_family(struct genl_family *family) -{ - family->module = THIS_MODULE; - return __genl_register_family(family); -} - -/** - * genl_register_family_with_ops - register a generic netlink family with ops - * @family: generic netlink family - * @ops: operations to be registered - * @n_ops: number of elements to register - * - * Registers the specified family and operations from the specified table. - * Only one family may be registered with the same family name or identifier. - * - * The family id may equal GENL_ID_GENERATE causing an unique id to - * be automatically generated and assigned. - * - * Either a doit or dumpit callback must be specified for every registered - * operation or the function will fail. Only one operation structure per - * command identifier may be registered. - * - * See include/net/genetlink.h for more documenation on the operations - * structure. - * - * Return 0 on success or a negative error code. - */ -static inline int -_genl_register_family_with_ops_grps(struct genl_family *family, - const struct genl_ops *ops, size_t n_ops, - const struct genl_multicast_group *mcgrps, - size_t n_mcgrps) -{ - family->module = THIS_MODULE; - family->ops = ops; - family->n_ops = n_ops; - family->mcgrps = mcgrps; - family->n_mcgrps = n_mcgrps; - return __genl_register_family(family); -} - -#define genl_register_family_with_ops(family, ops) \ - _genl_register_family_with_ops_grps((family), \ - (ops), ARRAY_SIZE(ops), \ - NULL, 0) -#define genl_register_family_with_ops_groups(family, ops, grps) \ - _genl_register_family_with_ops_grps((family), \ - (ops), ARRAY_SIZE(ops), \ - (grps), ARRAY_SIZE(grps)) - -int genl_unregister_family(struct genl_family *family); -void genl_notify(struct genl_family *family, struct sk_buff *skb, - struct genl_info *info, u32 group, gfp_t flags); - -void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, - struct genl_family *family, int flags, u8 cmd); - -/** - * genlmsg_nlhdr - Obtain netlink header from user specified header - * @user_hdr: user header as returned from genlmsg_put() - * @family: generic netlink family - * - * Returns pointer to netlink header. - */ -static inline struct nlmsghdr *genlmsg_nlhdr(void *user_hdr, - struct genl_family *family) -{ - return (struct nlmsghdr *)((char *)user_hdr - - family->hdrsize - - GENL_HDRLEN - - NLMSG_HDRLEN); -} - -/** - * genlmsg_parse - parse attributes of a genetlink message - * @nlh: netlink message header - * @family: genetlink message family - * @tb: destination array with maxtype+1 elements - * @maxtype: maximum attribute type to be expected - * @policy: validation policy - * */ -static inline int genlmsg_parse(const struct nlmsghdr *nlh, - const struct genl_family *family, - struct nlattr *tb[], int maxtype, - const struct nla_policy *policy) -{ - return nlmsg_parse(nlh, family->hdrsize + GENL_HDRLEN, tb, maxtype, - policy); -} - -/** - * genl_dump_check_consistent - check if sequence is consistent and advertise if not - * @cb: netlink callback structure that stores the sequence number - * @user_hdr: user header as returned from genlmsg_put() - * @family: generic netlink family - * - * Cf. nl_dump_check_consistent(), this just provides a wrapper to make it - * simpler to use with generic netlink. - */ -static inline void genl_dump_check_consistent(struct netlink_callback *cb, - void *user_hdr, - struct genl_family *family) -{ - nl_dump_check_consistent(cb, genlmsg_nlhdr(user_hdr, family)); -} - -/** - * genlmsg_put_reply - Add generic netlink header to a reply message - * @skb: socket buffer holding the message - * @info: receiver info - * @family: generic netlink family - * @flags: netlink message flags - * @cmd: generic netlink command - * - * Returns pointer to user specific header - */ -static inline void *genlmsg_put_reply(struct sk_buff *skb, - struct genl_info *info, - struct genl_family *family, - int flags, u8 cmd) -{ - return genlmsg_put(skb, info->snd_portid, info->snd_seq, family, - flags, cmd); -} - -/** - * genlmsg_end - Finalize a generic netlink message - * @skb: socket buffer the message is stored in - * @hdr: user specific header - */ -static inline void genlmsg_end(struct sk_buff *skb, void *hdr) -{ - nlmsg_end(skb, hdr - GENL_HDRLEN - NLMSG_HDRLEN); -} - -/** - * genlmsg_cancel - Cancel construction of a generic netlink message - * @skb: socket buffer the message is stored in - * @hdr: generic netlink message header - */ -static inline void genlmsg_cancel(struct sk_buff *skb, void *hdr) -{ - if (hdr) - nlmsg_cancel(skb, hdr - GENL_HDRLEN - NLMSG_HDRLEN); -} - -/** - * genlmsg_multicast_netns - multicast a netlink message to a specific netns - * @family: the generic netlink family - * @net: the net namespace - * @skb: netlink message as socket buffer - * @portid: own netlink portid to avoid sending to yourself - * @group: offset of multicast group in groups array - * @flags: allocation flags - */ -static inline int genlmsg_multicast_netns(struct genl_family *family, - struct net *net, struct sk_buff *skb, - u32 portid, unsigned int group, gfp_t flags) -{ - if (WARN_ON_ONCE(group >= family->n_mcgrps)) - return -EINVAL; - group = family->mcgrp_offset + group; - return nlmsg_multicast(net->genl_sock, skb, portid, group, flags); -} - -/** - * genlmsg_multicast - multicast a netlink message to the default netns - * @family: the generic netlink family - * @skb: netlink message as socket buffer - * @portid: own netlink portid to avoid sending to yourself - * @group: offset of multicast group in groups array - * @flags: allocation flags - */ -static inline int genlmsg_multicast(struct genl_family *family, - struct sk_buff *skb, u32 portid, - unsigned int group, gfp_t flags) -{ - return genlmsg_multicast_netns(family, &init_net, skb, - portid, group, flags); -} - -/** - * genlmsg_multicast_allns - multicast a netlink message to all net namespaces - * @family: the generic netlink family - * @skb: netlink message as socket buffer - * @portid: own netlink portid to avoid sending to yourself - * @group: offset of multicast group in groups array - * @flags: allocation flags - * - * This function must hold the RTNL or rcu_read_lock(). - */ -int genlmsg_multicast_allns(struct genl_family *family, - struct sk_buff *skb, u32 portid, - unsigned int group, gfp_t flags); - -/** - * genlmsg_unicast - unicast a netlink message - * @skb: netlink message as socket buffer - * @portid: netlink portid of the destination socket - */ -static inline int genlmsg_unicast(struct net *net, struct sk_buff *skb, u32 portid) -{ - return nlmsg_unicast(net->genl_sock, skb, portid); -} - -/** - * genlmsg_reply - reply to a request - * @skb: netlink message to be sent back - * @info: receiver information - */ -static inline int genlmsg_reply(struct sk_buff *skb, struct genl_info *info) -{ - return genlmsg_unicast(genl_info_net(info), skb, info->snd_portid); -} - -/** - * gennlmsg_data - head of message payload - * @gnlh: genetlink message header - */ -static inline void *genlmsg_data(const struct genlmsghdr *gnlh) -{ - return ((unsigned char *) gnlh + GENL_HDRLEN); -} - -/** - * genlmsg_len - length of message payload - * @gnlh: genetlink message header - */ -static inline int genlmsg_len(const struct genlmsghdr *gnlh) -{ - struct nlmsghdr *nlh = (struct nlmsghdr *)((unsigned char *)gnlh - - NLMSG_HDRLEN); - return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN); -} - -/** - * genlmsg_msg_size - length of genetlink message not including padding - * @payload: length of message payload - */ -static inline int genlmsg_msg_size(int payload) -{ - return GENL_HDRLEN + payload; -} - -/** - * genlmsg_total_size - length of genetlink message including padding - * @payload: length of message payload - */ -static inline int genlmsg_total_size(int payload) -{ - return NLMSG_ALIGN(genlmsg_msg_size(payload)); -} - -/** - * genlmsg_new - Allocate a new generic netlink message - * @payload: size of the message payload - * @flags: the type of memory to allocate. - */ -static inline struct sk_buff *genlmsg_new(size_t payload, gfp_t flags) -{ - return nlmsg_new(genlmsg_total_size(payload), flags); -} - -/** - * genl_set_err - report error to genetlink broadcast listeners - * @family: the generic netlink family - * @net: the network namespace to report the error to - * @portid: the PORTID of a process that we want to skip (if any) - * @group: the broadcast group that will notice the error - * (this is the offset of the multicast group in the groups array) - * @code: error code, must be negative (as usual in kernelspace) - * - * This function returns the number of broadcast listeners that have set the - * NETLINK_RECV_NO_ENOBUFS socket option. - */ -static inline int genl_set_err(struct genl_family *family, struct net *net, - u32 portid, u32 group, int code) -{ - if (WARN_ON_ONCE(group >= family->n_mcgrps)) - return -EINVAL; - group = family->mcgrp_offset + group; - return netlink_set_err(net->genl_sock, portid, group, code); -} - -static inline int genl_has_listeners(struct genl_family *family, - struct net *net, unsigned int group) -{ - if (WARN_ON_ONCE(group >= family->n_mcgrps)) - return -EINVAL; - group = family->mcgrp_offset + group; - return netlink_has_listeners(net->genl_sock, group); -} -#endif /* __NET_GENERIC_NETLINK_H */ diff --git a/src/linux/include/net/gre.h b/src/linux/include/net/gre.h deleted file mode 100644 index d25d836..0000000 --- a/src/linux/include/net/gre.h +++ /dev/null @@ -1,141 +0,0 @@ -#ifndef __LINUX_GRE_H -#define __LINUX_GRE_H - -#include -#include - -struct gre_base_hdr { - __be16 flags; - __be16 protocol; -} __packed; - -struct gre_full_hdr { - struct gre_base_hdr fixed_header; - __be16 csum; - __be16 reserved1; - __be32 key; - __be32 seq; -} __packed; -#define GRE_HEADER_SECTION 4 - -#define GREPROTO_CISCO 0 -#define GREPROTO_PPTP 1 -#define GREPROTO_MAX 2 -#define GRE_IP_PROTO_MAX 2 - -struct gre_protocol { - int (*handler)(struct sk_buff *skb); - void (*err_handler)(struct sk_buff *skb, u32 info); -}; - -int gre_add_protocol(const struct gre_protocol *proto, u8 version); -int gre_del_protocol(const struct gre_protocol *proto, u8 version); - -struct net_device *gretap_fb_dev_create(struct net *net, const char *name, - u8 name_assign_type); -int gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, - bool *csum_err, __be16 proto, int nhs); - -static inline int gre_calc_hlen(__be16 o_flags) -{ - int addend = 4; - - if (o_flags & TUNNEL_CSUM) - addend += 4; - if (o_flags & TUNNEL_KEY) - addend += 4; - if (o_flags & TUNNEL_SEQ) - addend += 4; - return addend; -} - -static inline __be16 gre_flags_to_tnl_flags(__be16 flags) -{ - __be16 tflags = 0; - - if (flags & GRE_CSUM) - tflags |= TUNNEL_CSUM; - if (flags & GRE_ROUTING) - tflags |= TUNNEL_ROUTING; - if (flags & GRE_KEY) - tflags |= TUNNEL_KEY; - if (flags & GRE_SEQ) - tflags |= TUNNEL_SEQ; - if (flags & GRE_STRICT) - tflags |= TUNNEL_STRICT; - if (flags & GRE_REC) - tflags |= TUNNEL_REC; - if (flags & GRE_VERSION) - tflags |= TUNNEL_VERSION; - - return tflags; -} - -static inline __be16 gre_tnl_flags_to_gre_flags(__be16 tflags) -{ - __be16 flags = 0; - - if (tflags & TUNNEL_CSUM) - flags |= GRE_CSUM; - if (tflags & TUNNEL_ROUTING) - flags |= GRE_ROUTING; - if (tflags & TUNNEL_KEY) - flags |= GRE_KEY; - if (tflags & TUNNEL_SEQ) - flags |= GRE_SEQ; - if (tflags & TUNNEL_STRICT) - flags |= GRE_STRICT; - if (tflags & TUNNEL_REC) - flags |= GRE_REC; - if (tflags & TUNNEL_VERSION) - flags |= GRE_VERSION; - - return flags; -} - -static inline __sum16 gre_checksum(struct sk_buff *skb) -{ - __wsum csum; - - if (skb->ip_summed == CHECKSUM_PARTIAL) - csum = lco_csum(skb); - else - csum = skb_checksum(skb, 0, skb->len, 0); - return csum_fold(csum); -} - -static inline void gre_build_header(struct sk_buff *skb, int hdr_len, - __be16 flags, __be16 proto, - __be32 key, __be32 seq) -{ - struct gre_base_hdr *greh; - - skb_push(skb, hdr_len); - - skb_set_inner_protocol(skb, proto); - skb_reset_transport_header(skb); - greh = (struct gre_base_hdr *)skb->data; - greh->flags = gre_tnl_flags_to_gre_flags(flags); - greh->protocol = proto; - - if (flags & (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ)) { - __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4); - - if (flags & TUNNEL_SEQ) { - *ptr = seq; - ptr--; - } - if (flags & TUNNEL_KEY) { - *ptr = key; - ptr--; - } - if (flags & TUNNEL_CSUM && - !(skb_shinfo(skb)->gso_type & - (SKB_GSO_GRE | SKB_GSO_GRE_CSUM))) { - *ptr = 0; - *(__sum16 *)ptr = gre_checksum(skb); - } - } -} - -#endif diff --git a/src/linux/include/net/gro_cells.h b/src/linux/include/net/gro_cells.h deleted file mode 100644 index 2a1abbf..0000000 --- a/src/linux/include/net/gro_cells.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef _NET_GRO_CELLS_H -#define _NET_GRO_CELLS_H - -#include -#include -#include - -struct gro_cell { - struct sk_buff_head napi_skbs; - struct napi_struct napi; -}; - -struct gro_cells { - struct gro_cell __percpu *cells; -}; - -static inline int gro_cells_receive(struct gro_cells *gcells, struct sk_buff *skb) -{ - struct gro_cell *cell; - struct net_device *dev = skb->dev; - - if (!gcells->cells || skb_cloned(skb) || !(dev->features & NETIF_F_GRO)) - return netif_rx(skb); - - cell = this_cpu_ptr(gcells->cells); - - if (skb_queue_len(&cell->napi_skbs) > netdev_max_backlog) { - atomic_long_inc(&dev->rx_dropped); - kfree_skb(skb); - return NET_RX_DROP; - } - - __skb_queue_tail(&cell->napi_skbs, skb); - if (skb_queue_len(&cell->napi_skbs) == 1) - napi_schedule(&cell->napi); - return NET_RX_SUCCESS; -} - -/* called under BH context */ -static inline int gro_cell_poll(struct napi_struct *napi, int budget) -{ - struct gro_cell *cell = container_of(napi, struct gro_cell, napi); - struct sk_buff *skb; - int work_done = 0; - - while (work_done < budget) { - skb = __skb_dequeue(&cell->napi_skbs); - if (!skb) - break; - napi_gro_receive(napi, skb); - work_done++; - } - - if (work_done < budget) - napi_complete_done(napi, work_done); - return work_done; -} - -static inline int gro_cells_init(struct gro_cells *gcells, struct net_device *dev) -{ - int i; - - gcells->cells = alloc_percpu(struct gro_cell); - if (!gcells->cells) - return -ENOMEM; - - for_each_possible_cpu(i) { - struct gro_cell *cell = per_cpu_ptr(gcells->cells, i); - - __skb_queue_head_init(&cell->napi_skbs); - - set_bit(NAPI_STATE_NO_BUSY_POLL, &cell->napi.state); - - netif_napi_add(dev, &cell->napi, gro_cell_poll, 64); - napi_enable(&cell->napi); - } - return 0; -} - -static inline void gro_cells_destroy(struct gro_cells *gcells) -{ - int i; - - if (!gcells->cells) - return; - for_each_possible_cpu(i) { - struct gro_cell *cell = per_cpu_ptr(gcells->cells, i); - - netif_napi_del(&cell->napi); - __skb_queue_purge(&cell->napi_skbs); - } - free_percpu(gcells->cells); - gcells->cells = NULL; -} - -#endif diff --git a/src/linux/include/net/icmp.h b/src/linux/include/net/icmp.h deleted file mode 100644 index 3ef2743..0000000 --- a/src/linux/include/net/icmp.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the ICMP module. - * - * Version: @(#)icmp.h 1.0.4 05/13/93 - * - * Authors: Ross Biro - * Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _ICMP_H -#define _ICMP_H - -#include - -#include -#include - -struct icmp_err { - int errno; - unsigned int fatal:1; -}; - -extern const struct icmp_err icmp_err_convert[]; -#define ICMP_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.icmp_statistics, field) -#define __ICMP_INC_STATS(net, field) __SNMP_INC_STATS((net)->mib.icmp_statistics, field) -#define ICMPMSGOUT_INC_STATS(net, field) SNMP_INC_STATS_ATOMIC_LONG((net)->mib.icmpmsg_statistics, field+256) -#define ICMPMSGIN_INC_STATS(net, field) SNMP_INC_STATS_ATOMIC_LONG((net)->mib.icmpmsg_statistics, field) - -struct dst_entry; -struct net_proto_family; -struct sk_buff; -struct net; - -void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info); -int icmp_rcv(struct sk_buff *skb); -void icmp_err(struct sk_buff *skb, u32 info); -int icmp_init(void); -void icmp_out_count(struct net *net, unsigned char type); - -#endif /* _ICMP_H */ diff --git a/src/linux/include/net/if_inet6.h b/src/linux/include/net/if_inet6.h deleted file mode 100644 index b0576cb..0000000 --- a/src/linux/include/net/if_inet6.h +++ /dev/null @@ -1,264 +0,0 @@ -/* - * inet6 interface/address list definitions - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _NET_IF_INET6_H -#define _NET_IF_INET6_H - -#include -#include - -/* inet6_dev.if_flags */ - -#define IF_RA_OTHERCONF 0x80 -#define IF_RA_MANAGED 0x40 -#define IF_RA_RCVD 0x20 -#define IF_RS_SENT 0x10 -#define IF_READY 0x80000000 - -/* prefix flags */ -#define IF_PREFIX_ONLINK 0x01 -#define IF_PREFIX_AUTOCONF 0x02 - -enum { - INET6_IFADDR_STATE_PREDAD, - INET6_IFADDR_STATE_DAD, - INET6_IFADDR_STATE_POSTDAD, - INET6_IFADDR_STATE_ERRDAD, - INET6_IFADDR_STATE_DEAD, -}; - -struct inet6_ifaddr { - struct in6_addr addr; - __u32 prefix_len; - - /* In seconds, relative to tstamp. Expiry is at tstamp + HZ * lft. */ - __u32 valid_lft; - __u32 prefered_lft; - atomic_t refcnt; - spinlock_t lock; - - int state; - - __u32 flags; - __u8 dad_probes; - __u8 stable_privacy_retry; - - __u16 scope; - - unsigned long cstamp; /* created timestamp */ - unsigned long tstamp; /* updated timestamp */ - - struct delayed_work dad_work; - - struct inet6_dev *idev; - struct rt6_info *rt; - - struct hlist_node addr_lst; - struct list_head if_list; - - struct list_head tmp_list; - struct inet6_ifaddr *ifpub; - int regen_count; - - bool tokenized; - - struct rcu_head rcu; - struct in6_addr peer_addr; -}; - -struct ip6_sf_socklist { - unsigned int sl_max; - unsigned int sl_count; - struct in6_addr sl_addr[0]; -}; - -#define IP6_SFLSIZE(count) (sizeof(struct ip6_sf_socklist) + \ - (count) * sizeof(struct in6_addr)) - -#define IP6_SFBLOCK 10 /* allocate this many at once */ - -struct ipv6_mc_socklist { - struct in6_addr addr; - int ifindex; - struct ipv6_mc_socklist __rcu *next; - rwlock_t sflock; - unsigned int sfmode; /* MCAST_{INCLUDE,EXCLUDE} */ - struct ip6_sf_socklist *sflist; - struct rcu_head rcu; -}; - -struct ip6_sf_list { - struct ip6_sf_list *sf_next; - struct in6_addr sf_addr; - unsigned long sf_count[2]; /* include/exclude counts */ - unsigned char sf_gsresp; /* include in g & s response? */ - unsigned char sf_oldin; /* change state */ - unsigned char sf_crcount; /* retrans. left to send */ -}; - -#define MAF_TIMER_RUNNING 0x01 -#define MAF_LAST_REPORTER 0x02 -#define MAF_LOADED 0x04 -#define MAF_NOREPORT 0x08 -#define MAF_GSQUERY 0x10 - -struct ifmcaddr6 { - struct in6_addr mca_addr; - struct inet6_dev *idev; - struct ifmcaddr6 *next; - struct ip6_sf_list *mca_sources; - struct ip6_sf_list *mca_tomb; - unsigned int mca_sfmode; - unsigned char mca_crcount; - unsigned long mca_sfcount[2]; - struct timer_list mca_timer; - unsigned int mca_flags; - int mca_users; - atomic_t mca_refcnt; - spinlock_t mca_lock; - unsigned long mca_cstamp; - unsigned long mca_tstamp; -}; - -/* Anycast stuff */ - -struct ipv6_ac_socklist { - struct in6_addr acl_addr; - int acl_ifindex; - struct ipv6_ac_socklist *acl_next; -}; - -struct ifacaddr6 { - struct in6_addr aca_addr; - struct inet6_dev *aca_idev; - struct rt6_info *aca_rt; - struct ifacaddr6 *aca_next; - int aca_users; - atomic_t aca_refcnt; - unsigned long aca_cstamp; - unsigned long aca_tstamp; -}; - -#define IFA_HOST IPV6_ADDR_LOOPBACK -#define IFA_LINK IPV6_ADDR_LINKLOCAL -#define IFA_SITE IPV6_ADDR_SITELOCAL - -struct ipv6_devstat { - struct proc_dir_entry *proc_dir_entry; - DEFINE_SNMP_STAT(struct ipstats_mib, ipv6); - DEFINE_SNMP_STAT_ATOMIC(struct icmpv6_mib_device, icmpv6dev); - DEFINE_SNMP_STAT_ATOMIC(struct icmpv6msg_mib_device, icmpv6msgdev); -}; - -struct inet6_dev { - struct net_device *dev; - - struct list_head addr_list; - - struct ifmcaddr6 *mc_list; - struct ifmcaddr6 *mc_tomb; - spinlock_t mc_lock; - - unsigned char mc_qrv; /* Query Robustness Variable */ - unsigned char mc_gq_running; - unsigned char mc_ifc_count; - unsigned char mc_dad_count; - - unsigned long mc_v1_seen; /* Max time we stay in MLDv1 mode */ - unsigned long mc_qi; /* Query Interval */ - unsigned long mc_qri; /* Query Response Interval */ - unsigned long mc_maxdelay; - - struct timer_list mc_gq_timer; /* general query timer */ - struct timer_list mc_ifc_timer; /* interface change timer */ - struct timer_list mc_dad_timer; /* dad complete mc timer */ - - struct ifacaddr6 *ac_list; - rwlock_t lock; - atomic_t refcnt; - __u32 if_flags; - int dead; - - u32 desync_factor; - u8 rndid[8]; - struct list_head tempaddr_list; - - struct in6_addr token; - - struct neigh_parms *nd_parms; - struct ipv6_devconf cnf; - struct ipv6_devstat stats; - - struct timer_list rs_timer; - __s32 rs_interval; /* in jiffies */ - __u8 rs_probes; - - __u8 addr_gen_mode; - unsigned long tstamp; /* ipv6InterfaceTable update timestamp */ - struct rcu_head rcu; -}; - -static inline void ipv6_eth_mc_map(const struct in6_addr *addr, char *buf) -{ - /* - * +-------+-------+-------+-------+-------+-------+ - * | 33 | 33 | DST13 | DST14 | DST15 | DST16 | - * +-------+-------+-------+-------+-------+-------+ - */ - - buf[0]= 0x33; - buf[1]= 0x33; - - memcpy(buf + 2, &addr->s6_addr32[3], sizeof(__u32)); -} - -static inline void ipv6_arcnet_mc_map(const struct in6_addr *addr, char *buf) -{ - buf[0] = 0x00; -} - -static inline void ipv6_ib_mc_map(const struct in6_addr *addr, - const unsigned char *broadcast, char *buf) -{ - unsigned char scope = broadcast[5] & 0xF; - - buf[0] = 0; /* Reserved */ - buf[1] = 0xff; /* Multicast QPN */ - buf[2] = 0xff; - buf[3] = 0xff; - buf[4] = 0xff; - buf[5] = 0x10 | scope; /* scope from broadcast address */ - buf[6] = 0x60; /* IPv6 signature */ - buf[7] = 0x1b; - buf[8] = broadcast[8]; /* P_Key */ - buf[9] = broadcast[9]; - memcpy(buf + 10, addr->s6_addr + 6, 10); -} - -static inline int ipv6_ipgre_mc_map(const struct in6_addr *addr, - const unsigned char *broadcast, char *buf) -{ - if ((broadcast[0] | broadcast[1] | broadcast[2] | broadcast[3]) != 0) { - memcpy(buf, broadcast, 4); - } else { - /* v4mapped? */ - if ((addr->s6_addr32[0] | addr->s6_addr32[1] | - (addr->s6_addr32[2] ^ htonl(0x0000ffff))) != 0) - return -EINVAL; - memcpy(buf, &addr->s6_addr32[3], 4); - } - return 0; -} - -#endif diff --git a/src/linux/include/net/inet6_connection_sock.h b/src/linux/include/net/inet6_connection_sock.h deleted file mode 100644 index 954ad6b..0000000 --- a/src/linux/include/net/inet6_connection_sock.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * NET Generic infrastructure for INET6 connection oriented protocols. - * - * Authors: Many people, see the TCPv6 sources - * - * From code originally in TCPv6 - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _INET6_CONNECTION_SOCK_H -#define _INET6_CONNECTION_SOCK_H - -#include - -struct inet_bind_bucket; -struct request_sock; -struct sk_buff; -struct sock; -struct sockaddr; - -int inet6_csk_bind_conflict(const struct sock *sk, - const struct inet_bind_bucket *tb, bool relax); - -struct dst_entry *inet6_csk_route_req(const struct sock *sk, struct flowi6 *fl6, - const struct request_sock *req, u8 proto); - -void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr); - -int inet6_csk_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl); - -struct dst_entry *inet6_csk_update_pmtu(struct sock *sk, u32 mtu); -#endif /* _INET6_CONNECTION_SOCK_H */ diff --git a/src/linux/include/net/inet6_hashtables.h b/src/linux/include/net/inet6_hashtables.h deleted file mode 100644 index b87beca..0000000 --- a/src/linux/include/net/inet6_hashtables.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Authors: Lotsa people, from code originally in tcp - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _INET6_HASHTABLES_H -#define _INET6_HASHTABLES_H - - -#if IS_ENABLED(CONFIG_IPV6) -#include -#include -#include -#include - -#include - -#include -#include - -struct inet_hashinfo; - -static inline unsigned int __inet6_ehashfn(const u32 lhash, - const u16 lport, - const u32 fhash, - const __be16 fport, - const u32 initval) -{ - const u32 ports = (((u32)lport) << 16) | (__force u32)fport; - return jhash_3words(lhash, fhash, ports, initval); -} - -/* - * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so - * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM - * - * The sockhash lock must be held as a reader here. - */ -struct sock *__inet6_lookup_established(struct net *net, - struct inet_hashinfo *hashinfo, - const struct in6_addr *saddr, - const __be16 sport, - const struct in6_addr *daddr, - const u16 hnum, const int dif); - -struct sock *inet6_lookup_listener(struct net *net, - struct inet_hashinfo *hashinfo, - struct sk_buff *skb, int doff, - const struct in6_addr *saddr, - const __be16 sport, - const struct in6_addr *daddr, - const unsigned short hnum, const int dif); - -static inline struct sock *__inet6_lookup(struct net *net, - struct inet_hashinfo *hashinfo, - struct sk_buff *skb, int doff, - const struct in6_addr *saddr, - const __be16 sport, - const struct in6_addr *daddr, - const u16 hnum, - const int dif, - bool *refcounted) -{ - struct sock *sk = __inet6_lookup_established(net, hashinfo, saddr, - sport, daddr, hnum, dif); - *refcounted = true; - if (sk) - return sk; - *refcounted = false; - return inet6_lookup_listener(net, hashinfo, skb, doff, saddr, sport, - daddr, hnum, dif); -} - -static inline struct sock *__inet6_lookup_skb(struct inet_hashinfo *hashinfo, - struct sk_buff *skb, int doff, - const __be16 sport, - const __be16 dport, - int iif, - bool *refcounted) -{ - struct sock *sk = skb_steal_sock(skb); - - *refcounted = true; - if (sk) - return sk; - - return __inet6_lookup(dev_net(skb_dst(skb)->dev), hashinfo, skb, - doff, &ipv6_hdr(skb)->saddr, sport, - &ipv6_hdr(skb)->daddr, ntohs(dport), - iif, refcounted); -} - -struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo, - struct sk_buff *skb, int doff, - const struct in6_addr *saddr, const __be16 sport, - const struct in6_addr *daddr, const __be16 dport, - const int dif); - -int inet6_hash(struct sock *sk); -#endif /* IS_ENABLED(CONFIG_IPV6) */ - -#define INET6_MATCH(__sk, __net, __saddr, __daddr, __ports, __dif) \ - (((__sk)->sk_portpair == (__ports)) && \ - ((__sk)->sk_family == AF_INET6) && \ - ipv6_addr_equal(&(__sk)->sk_v6_daddr, (__saddr)) && \ - ipv6_addr_equal(&(__sk)->sk_v6_rcv_saddr, (__daddr)) && \ - (!(__sk)->sk_bound_dev_if || \ - ((__sk)->sk_bound_dev_if == (__dif))) && \ - net_eq(sock_net(__sk), (__net))) - -#endif /* _INET6_HASHTABLES_H */ diff --git a/src/linux/include/net/inet_common.h b/src/linux/include/net/inet_common.h deleted file mode 100644 index 5d68342..0000000 --- a/src/linux/include/net/inet_common.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _INET_COMMON_H -#define _INET_COMMON_H - -extern const struct proto_ops inet_stream_ops; -extern const struct proto_ops inet_dgram_ops; - -/* - * INET4 prototypes used by INET6 - */ - -struct msghdr; -struct sock; -struct sockaddr; -struct socket; - -int inet_release(struct socket *sock); -int inet_stream_connect(struct socket *sock, struct sockaddr *uaddr, - int addr_len, int flags); -int __inet_stream_connect(struct socket *sock, struct sockaddr *uaddr, - int addr_len, int flags); -int inet_dgram_connect(struct socket *sock, struct sockaddr *uaddr, - int addr_len, int flags); -int inet_accept(struct socket *sock, struct socket *newsock, int flags); -int inet_sendmsg(struct socket *sock, struct msghdr *msg, size_t size); -ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset, - size_t size, int flags); -int inet_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, - int flags); -int inet_shutdown(struct socket *sock, int how); -int inet_listen(struct socket *sock, int backlog); -void inet_sock_destruct(struct sock *sk); -int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len); -int inet_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, - int peer); -int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); -int inet_ctl_sock_create(struct sock **sk, unsigned short family, - unsigned short type, unsigned char protocol, - struct net *net); -int inet_recv_error(struct sock *sk, struct msghdr *msg, int len, - int *addr_len); - -struct sk_buff **inet_gro_receive(struct sk_buff **head, struct sk_buff *skb); -int inet_gro_complete(struct sk_buff *skb, int nhoff); -struct sk_buff *inet_gso_segment(struct sk_buff *skb, - netdev_features_t features); - -static inline void inet_ctl_sock_destroy(struct sock *sk) -{ - if (sk) - sock_release(sk->sk_socket); -} - -#endif diff --git a/src/linux/include/net/inet_connection_sock.h b/src/linux/include/net/inet_connection_sock.h deleted file mode 100644 index 197a30d..0000000 --- a/src/linux/include/net/inet_connection_sock.h +++ /dev/null @@ -1,328 +0,0 @@ -/* - * NET Generic infrastructure for INET connection oriented protocols. - * - * Definitions for inet_connection_sock - * - * Authors: Many people, see the TCP sources - * - * From code originally in TCP - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _INET_CONNECTION_SOCK_H -#define _INET_CONNECTION_SOCK_H - -#include -#include -#include -#include - -#include -#include - -#define INET_CSK_DEBUG 1 - -/* Cancel timers, when they are not required. */ -#undef INET_CSK_CLEAR_TIMERS - -struct inet_bind_bucket; -struct tcp_congestion_ops; - -/* - * Pointers to address related TCP functions - * (i.e. things that depend on the address family) - */ -struct inet_connection_sock_af_ops { - int (*queue_xmit)(struct sock *sk, struct sk_buff *skb, struct flowi *fl); - void (*send_check)(struct sock *sk, struct sk_buff *skb); - int (*rebuild_header)(struct sock *sk); - void (*sk_rx_dst_set)(struct sock *sk, const struct sk_buff *skb); - int (*conn_request)(struct sock *sk, struct sk_buff *skb); - struct sock *(*syn_recv_sock)(const struct sock *sk, struct sk_buff *skb, - struct request_sock *req, - struct dst_entry *dst, - struct request_sock *req_unhash, - bool *own_req); - u16 net_header_len; - u16 net_frag_header_len; - u16 sockaddr_len; - int (*setsockopt)(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen); - int (*getsockopt)(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen); -#ifdef CONFIG_COMPAT - int (*compat_setsockopt)(struct sock *sk, - int level, int optname, - char __user *optval, unsigned int optlen); - int (*compat_getsockopt)(struct sock *sk, - int level, int optname, - char __user *optval, int __user *optlen); -#endif - void (*addr2sockaddr)(struct sock *sk, struct sockaddr *); - int (*bind_conflict)(const struct sock *sk, - const struct inet_bind_bucket *tb, bool relax); - void (*mtu_reduced)(struct sock *sk); -}; - -/** inet_connection_sock - INET connection oriented sock - * - * @icsk_accept_queue: FIFO of established children - * @icsk_bind_hash: Bind node - * @icsk_timeout: Timeout - * @icsk_retransmit_timer: Resend (no ack) - * @icsk_rto: Retransmit timeout - * @icsk_pmtu_cookie Last pmtu seen by socket - * @icsk_ca_ops Pluggable congestion control hook - * @icsk_af_ops Operations which are AF_INET{4,6} specific - * @icsk_ca_state: Congestion control state - * @icsk_retransmits: Number of unrecovered [RTO] timeouts - * @icsk_pending: Scheduled timer event - * @icsk_backoff: Backoff - * @icsk_syn_retries: Number of allowed SYN (or equivalent) retries - * @icsk_probes_out: unanswered 0 window probes - * @icsk_ext_hdr_len: Network protocol overhead (IP/IPv6 options) - * @icsk_ack: Delayed ACK control data - * @icsk_mtup; MTU probing control data - */ -struct inet_connection_sock { - /* inet_sock has to be the first member! */ - struct inet_sock icsk_inet; - struct request_sock_queue icsk_accept_queue; - struct inet_bind_bucket *icsk_bind_hash; - unsigned long icsk_timeout; - struct timer_list icsk_retransmit_timer; - struct timer_list icsk_delack_timer; - __u32 icsk_rto; - __u32 icsk_pmtu_cookie; - const struct tcp_congestion_ops *icsk_ca_ops; - const struct inet_connection_sock_af_ops *icsk_af_ops; - unsigned int (*icsk_sync_mss)(struct sock *sk, u32 pmtu); - __u8 icsk_ca_state:6, - icsk_ca_setsockopt:1, - icsk_ca_dst_locked:1; - __u8 icsk_retransmits; - __u8 icsk_pending; - __u8 icsk_backoff; - __u8 icsk_syn_retries; - __u8 icsk_probes_out; - __u16 icsk_ext_hdr_len; - struct { - __u8 pending; /* ACK is pending */ - __u8 quick; /* Scheduled number of quick acks */ - __u8 pingpong; /* The session is interactive */ - __u8 blocked; /* Delayed ACK was blocked by socket lock */ - __u32 ato; /* Predicted tick of soft clock */ - unsigned long timeout; /* Currently scheduled timeout */ - __u32 lrcvtime; /* timestamp of last received data packet */ - __u16 last_seg_size; /* Size of last incoming segment */ - __u16 rcv_mss; /* MSS used for delayed ACK decisions */ - } icsk_ack; - struct { - int enabled; - - /* Range of MTUs to search */ - int search_high; - int search_low; - - /* Information on the current probe. */ - int probe_size; - - u32 probe_timestamp; - } icsk_mtup; - u32 icsk_user_timeout; - - u64 icsk_ca_priv[88 / sizeof(u64)]; -#define ICSK_CA_PRIV_SIZE (11 * sizeof(u64)) -}; - -#define ICSK_TIME_RETRANS 1 /* Retransmit timer */ -#define ICSK_TIME_DACK 2 /* Delayed ack timer */ -#define ICSK_TIME_PROBE0 3 /* Zero window probe timer */ -#define ICSK_TIME_EARLY_RETRANS 4 /* Early retransmit timer */ -#define ICSK_TIME_LOSS_PROBE 5 /* Tail loss probe timer */ - -static inline struct inet_connection_sock *inet_csk(const struct sock *sk) -{ - return (struct inet_connection_sock *)sk; -} - -static inline void *inet_csk_ca(const struct sock *sk) -{ - return (void *)inet_csk(sk)->icsk_ca_priv; -} - -struct sock *inet_csk_clone_lock(const struct sock *sk, - const struct request_sock *req, - const gfp_t priority); - -enum inet_csk_ack_state_t { - ICSK_ACK_SCHED = 1, - ICSK_ACK_TIMER = 2, - ICSK_ACK_PUSHED = 4, - ICSK_ACK_PUSHED2 = 8 -}; - -void inet_csk_init_xmit_timers(struct sock *sk, - void (*retransmit_handler)(unsigned long), - void (*delack_handler)(unsigned long), - void (*keepalive_handler)(unsigned long)); -void inet_csk_clear_xmit_timers(struct sock *sk); - -static inline void inet_csk_schedule_ack(struct sock *sk) -{ - inet_csk(sk)->icsk_ack.pending |= ICSK_ACK_SCHED; -} - -static inline int inet_csk_ack_scheduled(const struct sock *sk) -{ - return inet_csk(sk)->icsk_ack.pending & ICSK_ACK_SCHED; -} - -static inline void inet_csk_delack_init(struct sock *sk) -{ - memset(&inet_csk(sk)->icsk_ack, 0, sizeof(inet_csk(sk)->icsk_ack)); -} - -void inet_csk_delete_keepalive_timer(struct sock *sk); -void inet_csk_reset_keepalive_timer(struct sock *sk, unsigned long timeout); - -#ifdef INET_CSK_DEBUG -extern const char inet_csk_timer_bug_msg[]; -#endif - -static inline void inet_csk_clear_xmit_timer(struct sock *sk, const int what) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - - if (what == ICSK_TIME_RETRANS || what == ICSK_TIME_PROBE0) { - icsk->icsk_pending = 0; -#ifdef INET_CSK_CLEAR_TIMERS - sk_stop_timer(sk, &icsk->icsk_retransmit_timer); -#endif - } else if (what == ICSK_TIME_DACK) { - icsk->icsk_ack.blocked = icsk->icsk_ack.pending = 0; -#ifdef INET_CSK_CLEAR_TIMERS - sk_stop_timer(sk, &icsk->icsk_delack_timer); -#endif - } -#ifdef INET_CSK_DEBUG - else { - pr_debug("%s", inet_csk_timer_bug_msg); - } -#endif -} - -/* - * Reset the retransmission timer - */ -static inline void inet_csk_reset_xmit_timer(struct sock *sk, const int what, - unsigned long when, - const unsigned long max_when) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - - if (when > max_when) { -#ifdef INET_CSK_DEBUG - pr_debug("reset_xmit_timer: sk=%p %d when=0x%lx, caller=%p\n", - sk, what, when, current_text_addr()); -#endif - when = max_when; - } - - if (what == ICSK_TIME_RETRANS || what == ICSK_TIME_PROBE0 || - what == ICSK_TIME_EARLY_RETRANS || what == ICSK_TIME_LOSS_PROBE) { - icsk->icsk_pending = what; - icsk->icsk_timeout = jiffies + when; - sk_reset_timer(sk, &icsk->icsk_retransmit_timer, icsk->icsk_timeout); - } else if (what == ICSK_TIME_DACK) { - icsk->icsk_ack.pending |= ICSK_ACK_TIMER; - icsk->icsk_ack.timeout = jiffies + when; - sk_reset_timer(sk, &icsk->icsk_delack_timer, icsk->icsk_ack.timeout); - } -#ifdef INET_CSK_DEBUG - else { - pr_debug("%s", inet_csk_timer_bug_msg); - } -#endif -} - -static inline unsigned long -inet_csk_rto_backoff(const struct inet_connection_sock *icsk, - unsigned long max_when) -{ - u64 when = (u64)icsk->icsk_rto << icsk->icsk_backoff; - - return (unsigned long)min_t(u64, when, max_when); -} - -struct sock *inet_csk_accept(struct sock *sk, int flags, int *err); - -int inet_csk_bind_conflict(const struct sock *sk, - const struct inet_bind_bucket *tb, bool relax); -int inet_csk_get_port(struct sock *sk, unsigned short snum); - -struct dst_entry *inet_csk_route_req(const struct sock *sk, struct flowi4 *fl4, - const struct request_sock *req); -struct dst_entry *inet_csk_route_child_sock(const struct sock *sk, - struct sock *newsk, - const struct request_sock *req); - -struct sock *inet_csk_reqsk_queue_add(struct sock *sk, - struct request_sock *req, - struct sock *child); -void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req, - unsigned long timeout); -struct sock *inet_csk_complete_hashdance(struct sock *sk, struct sock *child, - struct request_sock *req, - bool own_req); - -static inline void inet_csk_reqsk_queue_added(struct sock *sk) -{ - reqsk_queue_added(&inet_csk(sk)->icsk_accept_queue); -} - -static inline int inet_csk_reqsk_queue_len(const struct sock *sk) -{ - return reqsk_queue_len(&inet_csk(sk)->icsk_accept_queue); -} - -static inline int inet_csk_reqsk_queue_young(const struct sock *sk) -{ - return reqsk_queue_len_young(&inet_csk(sk)->icsk_accept_queue); -} - -static inline int inet_csk_reqsk_queue_is_full(const struct sock *sk) -{ - return inet_csk_reqsk_queue_len(sk) >= sk->sk_max_ack_backlog; -} - -void inet_csk_reqsk_queue_drop(struct sock *sk, struct request_sock *req); -void inet_csk_reqsk_queue_drop_and_put(struct sock *sk, struct request_sock *req); - -void inet_csk_destroy_sock(struct sock *sk); -void inet_csk_prepare_forced_close(struct sock *sk); - -/* - * LISTEN is a special case for poll.. - */ -static inline unsigned int inet_csk_listen_poll(const struct sock *sk) -{ - return !reqsk_queue_empty(&inet_csk(sk)->icsk_accept_queue) ? - (POLLIN | POLLRDNORM) : 0; -} - -int inet_csk_listen_start(struct sock *sk, int backlog); -void inet_csk_listen_stop(struct sock *sk); - -void inet_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr); - -int inet_csk_compat_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen); -int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen); - -struct dst_entry *inet_csk_update_pmtu(struct sock *sk, u32 mtu); -#endif /* _INET_CONNECTION_SOCK_H */ diff --git a/src/linux/include/net/inet_ecn.h b/src/linux/include/net/inet_ecn.h deleted file mode 100644 index dce2d58..0000000 --- a/src/linux/include/net/inet_ecn.h +++ /dev/null @@ -1,240 +0,0 @@ -#ifndef _INET_ECN_H_ -#define _INET_ECN_H_ - -#include -#include - -#include -#include - -enum { - INET_ECN_NOT_ECT = 0, - INET_ECN_ECT_1 = 1, - INET_ECN_ECT_0 = 2, - INET_ECN_CE = 3, - INET_ECN_MASK = 3, -}; - -extern int sysctl_tunnel_ecn_log; - -static inline int INET_ECN_is_ce(__u8 dsfield) -{ - return (dsfield & INET_ECN_MASK) == INET_ECN_CE; -} - -static inline int INET_ECN_is_not_ect(__u8 dsfield) -{ - return (dsfield & INET_ECN_MASK) == INET_ECN_NOT_ECT; -} - -static inline int INET_ECN_is_capable(__u8 dsfield) -{ - return dsfield & INET_ECN_ECT_0; -} - -/* - * RFC 3168 9.1.1 - * The full-functionality option for ECN encapsulation is to copy the - * ECN codepoint of the inside header to the outside header on - * encapsulation if the inside header is not-ECT or ECT, and to set the - * ECN codepoint of the outside header to ECT(0) if the ECN codepoint of - * the inside header is CE. - */ -static inline __u8 INET_ECN_encapsulate(__u8 outer, __u8 inner) -{ - outer &= ~INET_ECN_MASK; - outer |= !INET_ECN_is_ce(inner) ? (inner & INET_ECN_MASK) : - INET_ECN_ECT_0; - return outer; -} - -static inline void INET_ECN_xmit(struct sock *sk) -{ - inet_sk(sk)->tos |= INET_ECN_ECT_0; - if (inet6_sk(sk) != NULL) - inet6_sk(sk)->tclass |= INET_ECN_ECT_0; -} - -static inline void INET_ECN_dontxmit(struct sock *sk) -{ - inet_sk(sk)->tos &= ~INET_ECN_MASK; - if (inet6_sk(sk) != NULL) - inet6_sk(sk)->tclass &= ~INET_ECN_MASK; -} - -#define IP6_ECN_flow_init(label) do { \ - (label) &= ~htonl(INET_ECN_MASK << 20); \ - } while (0) - -#define IP6_ECN_flow_xmit(sk, label) do { \ - if (INET_ECN_is_capable(inet6_sk(sk)->tclass)) \ - (label) |= htonl(INET_ECN_ECT_0 << 20); \ - } while (0) - -static inline int IP_ECN_set_ce(struct iphdr *iph) -{ - u32 check = (__force u32)iph->check; - u32 ecn = (iph->tos + 1) & INET_ECN_MASK; - - /* - * After the last operation we have (in binary): - * INET_ECN_NOT_ECT => 01 - * INET_ECN_ECT_1 => 10 - * INET_ECN_ECT_0 => 11 - * INET_ECN_CE => 00 - */ - if (!(ecn & 2)) - return !ecn; - - /* - * The following gives us: - * INET_ECN_ECT_1 => check += htons(0xFFFD) - * INET_ECN_ECT_0 => check += htons(0xFFFE) - */ - check += (__force u16)htons(0xFFFB) + (__force u16)htons(ecn); - - iph->check = (__force __sum16)(check + (check>=0xFFFF)); - iph->tos |= INET_ECN_CE; - return 1; -} - -static inline void IP_ECN_clear(struct iphdr *iph) -{ - iph->tos &= ~INET_ECN_MASK; -} - -static inline void ipv4_copy_dscp(unsigned int dscp, struct iphdr *inner) -{ - dscp &= ~INET_ECN_MASK; - ipv4_change_dsfield(inner, INET_ECN_MASK, dscp); -} - -struct ipv6hdr; - -/* Note: - * IP_ECN_set_ce() has to tweak IPV4 checksum when setting CE, - * meaning both changes have no effect on skb->csum if/when CHECKSUM_COMPLETE - * In IPv6 case, no checksum compensates the change in IPv6 header, - * so we have to update skb->csum. - */ -static inline int IP6_ECN_set_ce(struct sk_buff *skb, struct ipv6hdr *iph) -{ - __be32 from, to; - - if (INET_ECN_is_not_ect(ipv6_get_dsfield(iph))) - return 0; - - from = *(__be32 *)iph; - to = from | htonl(INET_ECN_CE << 20); - *(__be32 *)iph = to; - if (skb->ip_summed == CHECKSUM_COMPLETE) - skb->csum = csum_add(csum_sub(skb->csum, (__force __wsum)from), - (__force __wsum)to); - return 1; -} - -static inline void IP6_ECN_clear(struct ipv6hdr *iph) -{ - *(__be32*)iph &= ~htonl(INET_ECN_MASK << 20); -} - -static inline void ipv6_copy_dscp(unsigned int dscp, struct ipv6hdr *inner) -{ - dscp &= ~INET_ECN_MASK; - ipv6_change_dsfield(inner, INET_ECN_MASK, dscp); -} - -static inline int INET_ECN_set_ce(struct sk_buff *skb) -{ - switch (skb->protocol) { - case cpu_to_be16(ETH_P_IP): - if (skb_network_header(skb) + sizeof(struct iphdr) <= - skb_tail_pointer(skb)) - return IP_ECN_set_ce(ip_hdr(skb)); - break; - - case cpu_to_be16(ETH_P_IPV6): - if (skb_network_header(skb) + sizeof(struct ipv6hdr) <= - skb_tail_pointer(skb)) - return IP6_ECN_set_ce(skb, ipv6_hdr(skb)); - break; - } - - return 0; -} - -/* - * RFC 6040 4.2 - * To decapsulate the inner header at the tunnel egress, a compliant - * tunnel egress MUST set the outgoing ECN field to the codepoint at the - * intersection of the appropriate arriving inner header (row) and outer - * header (column) in Figure 4 - * - * +---------+------------------------------------------------+ - * |Arriving | Arriving Outer Header | - * | Inner +---------+------------+------------+------------+ - * | Header | Not-ECT | ECT(0) | ECT(1) | CE | - * +---------+---------+------------+------------+------------+ - * | Not-ECT | Not-ECT |Not-ECT(!!!)|Not-ECT(!!!)| (!!!)| - * | ECT(0) | ECT(0) | ECT(0) | ECT(1) | CE | - * | ECT(1) | ECT(1) | ECT(1) (!) | ECT(1) | CE | - * | CE | CE | CE | CE(!!!)| CE | - * +---------+---------+------------+------------+------------+ - * - * Figure 4: New IP in IP Decapsulation Behaviour - * - * returns 0 on success - * 1 if something is broken and should be logged (!!! above) - * 2 if packet should be dropped - */ -static inline int INET_ECN_decapsulate(struct sk_buff *skb, - __u8 outer, __u8 inner) -{ - if (INET_ECN_is_not_ect(inner)) { - switch (outer & INET_ECN_MASK) { - case INET_ECN_NOT_ECT: - return 0; - case INET_ECN_ECT_0: - case INET_ECN_ECT_1: - return 1; - case INET_ECN_CE: - return 2; - } - } - - if (INET_ECN_is_ce(outer)) - INET_ECN_set_ce(skb); - - return 0; -} - -static inline int IP_ECN_decapsulate(const struct iphdr *oiph, - struct sk_buff *skb) -{ - __u8 inner; - - if (skb->protocol == htons(ETH_P_IP)) - inner = ip_hdr(skb)->tos; - else if (skb->protocol == htons(ETH_P_IPV6)) - inner = ipv6_get_dsfield(ipv6_hdr(skb)); - else - return 0; - - return INET_ECN_decapsulate(skb, oiph->tos, inner); -} - -static inline int IP6_ECN_decapsulate(const struct ipv6hdr *oipv6h, - struct sk_buff *skb) -{ - __u8 inner; - - if (skb->protocol == htons(ETH_P_IP)) - inner = ip_hdr(skb)->tos; - else if (skb->protocol == htons(ETH_P_IPV6)) - inner = ipv6_get_dsfield(ipv6_hdr(skb)); - else - return 0; - - return INET_ECN_decapsulate(skb, ipv6_get_dsfield(oipv6h), inner); -} -#endif diff --git a/src/linux/include/net/inet_frag.h b/src/linux/include/net/inet_frag.h deleted file mode 100644 index 909972a..0000000 --- a/src/linux/include/net/inet_frag.h +++ /dev/null @@ -1,187 +0,0 @@ -#ifndef __NET_FRAG_H__ -#define __NET_FRAG_H__ - -#include - -struct netns_frags { - /* The percpu_counter "mem" need to be cacheline aligned. - * mem.count must not share cacheline with other writers - */ - struct percpu_counter mem ____cacheline_aligned_in_smp; - - /* sysctls */ - int timeout; - int high_thresh; - int low_thresh; - int max_dist; -}; - -/** - * fragment queue flags - * - * @INET_FRAG_FIRST_IN: first fragment has arrived - * @INET_FRAG_LAST_IN: final fragment has arrived - * @INET_FRAG_COMPLETE: frag queue has been processed and is due for destruction - */ -enum { - INET_FRAG_FIRST_IN = BIT(0), - INET_FRAG_LAST_IN = BIT(1), - INET_FRAG_COMPLETE = BIT(2), -}; - -/** - * struct inet_frag_queue - fragment queue - * - * @lock: spinlock protecting the queue - * @timer: queue expiration timer - * @list: hash bucket list - * @refcnt: reference count of the queue - * @fragments: received fragments head - * @fragments_tail: received fragments tail - * @stamp: timestamp of the last received fragment - * @len: total length of the original datagram - * @meat: length of received fragments so far - * @flags: fragment queue flags - * @max_size: maximum received fragment size - * @net: namespace that this frag belongs to - * @list_evictor: list of queues to forcefully evict (e.g. due to low memory) - */ -struct inet_frag_queue { - spinlock_t lock; - struct timer_list timer; - struct hlist_node list; - atomic_t refcnt; - struct sk_buff *fragments; - struct sk_buff *fragments_tail; - ktime_t stamp; - int len; - int meat; - __u8 flags; - u16 max_size; - struct netns_frags *net; - struct hlist_node list_evictor; -}; - -#define INETFRAGS_HASHSZ 1024 - -/* averaged: - * max_depth = default ipfrag_high_thresh / INETFRAGS_HASHSZ / - * rounded up (SKB_TRUELEN(0) + sizeof(struct ipq or - * struct frag_queue)) - */ -#define INETFRAGS_MAXDEPTH 128 - -struct inet_frag_bucket { - struct hlist_head chain; - spinlock_t chain_lock; -}; - -struct inet_frags { - struct inet_frag_bucket hash[INETFRAGS_HASHSZ]; - - struct work_struct frags_work; - unsigned int next_bucket; - unsigned long last_rebuild_jiffies; - bool rebuild; - - /* The first call to hashfn is responsible to initialize - * rnd. This is best done with net_get_random_once. - * - * rnd_seqlock is used to let hash insertion detect - * when it needs to re-lookup the hash chain to use. - */ - u32 rnd; - seqlock_t rnd_seqlock; - int qsize; - - unsigned int (*hashfn)(const struct inet_frag_queue *); - bool (*match)(const struct inet_frag_queue *q, - const void *arg); - void (*constructor)(struct inet_frag_queue *q, - const void *arg); - void (*destructor)(struct inet_frag_queue *); - void (*frag_expire)(unsigned long data); - struct kmem_cache *frags_cachep; - const char *frags_cache_name; -}; - -int inet_frags_init(struct inet_frags *); -void inet_frags_fini(struct inet_frags *); - -static inline int inet_frags_init_net(struct netns_frags *nf) -{ - return percpu_counter_init(&nf->mem, 0, GFP_KERNEL); -} -static inline void inet_frags_uninit_net(struct netns_frags *nf) -{ - percpu_counter_destroy(&nf->mem); -} - -void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f); - -void inet_frag_kill(struct inet_frag_queue *q, struct inet_frags *f); -void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f); -struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, - struct inet_frags *f, void *key, unsigned int hash); - -void inet_frag_maybe_warn_overflow(struct inet_frag_queue *q, - const char *prefix); - -static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f) -{ - if (atomic_dec_and_test(&q->refcnt)) - inet_frag_destroy(q, f); -} - -static inline bool inet_frag_evicting(struct inet_frag_queue *q) -{ - return !hlist_unhashed(&q->list_evictor); -} - -/* Memory Tracking Functions. */ - -/* The default percpu_counter batch size is not big enough to scale to - * fragmentation mem acct sizes. - * The mem size of a 64K fragment is approx: - * (44 fragments * 2944 truesize) + frag_queue struct(200) = 129736 bytes - */ -static unsigned int frag_percpu_counter_batch = 130000; - -static inline int frag_mem_limit(struct netns_frags *nf) -{ - return percpu_counter_read(&nf->mem); -} - -static inline void sub_frag_mem_limit(struct netns_frags *nf, int i) -{ - __percpu_counter_add(&nf->mem, -i, frag_percpu_counter_batch); -} - -static inline void add_frag_mem_limit(struct netns_frags *nf, int i) -{ - __percpu_counter_add(&nf->mem, i, frag_percpu_counter_batch); -} - -static inline unsigned int sum_frag_mem_limit(struct netns_frags *nf) -{ - unsigned int res; - - local_bh_disable(); - res = percpu_counter_sum_positive(&nf->mem); - local_bh_enable(); - - return res; -} - -/* RFC 3168 support : - * We want to check ECN values of all fragments, do detect invalid combinations. - * In ipq->ecn, we store the OR value of each ip4_frag_ecn() fragment value. - */ -#define IPFRAG_ECN_NOT_ECT 0x01 /* one frag had ECN_NOT_ECT */ -#define IPFRAG_ECN_ECT_1 0x02 /* one frag had ECN_ECT_1 */ -#define IPFRAG_ECN_ECT_0 0x04 /* one frag had ECN_ECT_0 */ -#define IPFRAG_ECN_CE 0x08 /* one frag had ECN_CE */ - -extern const u8 ip_frag_ecn_table[16]; - -#endif diff --git a/src/linux/include/net/inet_hashtables.h b/src/linux/include/net/inet_hashtables.h deleted file mode 100644 index 0574493..0000000 --- a/src/linux/include/net/inet_hashtables.h +++ /dev/null @@ -1,386 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Authors: Lotsa people, from code originally in tcp - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _INET_HASHTABLES_H -#define _INET_HASHTABLES_H - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -/* This is for all connections with a full identity, no wildcards. - * The 'e' prefix stands for Establish, but we really put all sockets - * but LISTEN ones. - */ -struct inet_ehash_bucket { - struct hlist_nulls_head chain; -}; - -/* There are a few simple rules, which allow for local port reuse by - * an application. In essence: - * - * 1) Sockets bound to different interfaces may share a local port. - * Failing that, goto test 2. - * 2) If all sockets have sk->sk_reuse set, and none of them are in - * TCP_LISTEN state, the port may be shared. - * Failing that, goto test 3. - * 3) If all sockets are bound to a specific inet_sk(sk)->rcv_saddr local - * address, and none of them are the same, the port may be - * shared. - * Failing this, the port cannot be shared. - * - * The interesting point, is test #2. This is what an FTP server does - * all day. To optimize this case we use a specific flag bit defined - * below. As we add sockets to a bind bucket list, we perform a - * check of: (newsk->sk_reuse && (newsk->sk_state != TCP_LISTEN)) - * As long as all sockets added to a bind bucket pass this test, - * the flag bit will be set. - * The resulting situation is that tcp_v[46]_verify_bind() can just check - * for this flag bit, if it is set and the socket trying to bind has - * sk->sk_reuse set, we don't even have to walk the owners list at all, - * we return that it is ok to bind this socket to the requested local port. - * - * Sounds like a lot of work, but it is worth it. In a more naive - * implementation (ie. current FreeBSD etc.) the entire list of ports - * must be walked for each data port opened by an ftp server. Needless - * to say, this does not scale at all. With a couple thousand FTP - * users logged onto your box, isn't it nice to know that new data - * ports are created in O(1) time? I thought so. ;-) -DaveM - */ -struct inet_bind_bucket { - possible_net_t ib_net; - unsigned short port; - signed char fastreuse; - signed char fastreuseport; - kuid_t fastuid; - int num_owners; - struct hlist_node node; - struct hlist_head owners; -}; - -static inline struct net *ib_net(struct inet_bind_bucket *ib) -{ - return read_pnet(&ib->ib_net); -} - -#define inet_bind_bucket_for_each(tb, head) \ - hlist_for_each_entry(tb, head, node) - -struct inet_bind_hashbucket { - spinlock_t lock; - struct hlist_head chain; -}; - -/* - * Sockets can be hashed in established or listening table - */ -struct inet_listen_hashbucket { - spinlock_t lock; - struct hlist_head head; -}; - -/* This is for listening sockets, thus all sockets which possess wildcards. */ -#define INET_LHTABLE_SIZE 32 /* Yes, really, this is all you need. */ - -struct inet_hashinfo { - /* This is for sockets with full identity only. Sockets here will - * always be without wildcards and will have the following invariant: - * - * TCP_ESTABLISHED <= sk->sk_state < TCP_CLOSE - * - */ - struct inet_ehash_bucket *ehash; - spinlock_t *ehash_locks; - unsigned int ehash_mask; - unsigned int ehash_locks_mask; - - /* Ok, let's try this, I give up, we do need a local binding - * TCP hash as well as the others for fast bind/connect. - */ - struct inet_bind_hashbucket *bhash; - - unsigned int bhash_size; - /* 4 bytes hole on 64 bit */ - - struct kmem_cache *bind_bucket_cachep; - - /* All the above members are written once at bootup and - * never written again _or_ are predominantly read-access. - * - * Now align to a new cache line as all the following members - * might be often dirty. - */ - /* All sockets in TCP_LISTEN state will be in here. This is the only - * table where wildcard'd TCP sockets can exist. Hash function here - * is just local port number. - */ - struct inet_listen_hashbucket listening_hash[INET_LHTABLE_SIZE] - ____cacheline_aligned_in_smp; -}; - -static inline struct inet_ehash_bucket *inet_ehash_bucket( - struct inet_hashinfo *hashinfo, - unsigned int hash) -{ - return &hashinfo->ehash[hash & hashinfo->ehash_mask]; -} - -static inline spinlock_t *inet_ehash_lockp( - struct inet_hashinfo *hashinfo, - unsigned int hash) -{ - return &hashinfo->ehash_locks[hash & hashinfo->ehash_locks_mask]; -} - -int inet_ehash_locks_alloc(struct inet_hashinfo *hashinfo); - -static inline void inet_ehash_locks_free(struct inet_hashinfo *hashinfo) -{ - kvfree(hashinfo->ehash_locks); - hashinfo->ehash_locks = NULL; -} - -struct inet_bind_bucket * -inet_bind_bucket_create(struct kmem_cache *cachep, struct net *net, - struct inet_bind_hashbucket *head, - const unsigned short snum); -void inet_bind_bucket_destroy(struct kmem_cache *cachep, - struct inet_bind_bucket *tb); - -static inline u32 inet_bhashfn(const struct net *net, const __u16 lport, - const u32 bhash_size) -{ - return (lport + net_hash_mix(net)) & (bhash_size - 1); -} - -void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb, - const unsigned short snum); - -/* These can have wildcards, don't try too hard. */ -static inline u32 inet_lhashfn(const struct net *net, const unsigned short num) -{ - return (num + net_hash_mix(net)) & (INET_LHTABLE_SIZE - 1); -} - -static inline int inet_sk_listen_hashfn(const struct sock *sk) -{ - return inet_lhashfn(sock_net(sk), inet_sk(sk)->inet_num); -} - -/* Caller must disable local BH processing. */ -int __inet_inherit_port(const struct sock *sk, struct sock *child); - -void inet_put_port(struct sock *sk); - -void inet_hashinfo_init(struct inet_hashinfo *h); - -bool inet_ehash_insert(struct sock *sk, struct sock *osk); -bool inet_ehash_nolisten(struct sock *sk, struct sock *osk); -int __inet_hash(struct sock *sk, struct sock *osk, - int (*saddr_same)(const struct sock *sk1, - const struct sock *sk2, - bool match_wildcard)); -int inet_hash(struct sock *sk); -void inet_unhash(struct sock *sk); - -struct sock *__inet_lookup_listener(struct net *net, - struct inet_hashinfo *hashinfo, - struct sk_buff *skb, int doff, - const __be32 saddr, const __be16 sport, - const __be32 daddr, - const unsigned short hnum, - const int dif); - -static inline struct sock *inet_lookup_listener(struct net *net, - struct inet_hashinfo *hashinfo, - struct sk_buff *skb, int doff, - __be32 saddr, __be16 sport, - __be32 daddr, __be16 dport, int dif) -{ - return __inet_lookup_listener(net, hashinfo, skb, doff, saddr, sport, - daddr, ntohs(dport), dif); -} - -/* Socket demux engine toys. */ -/* What happens here is ugly; there's a pair of adjacent fields in - struct inet_sock; __be16 dport followed by __u16 num. We want to - search by pair, so we combine the keys into a single 32bit value - and compare with 32bit value read from &...->dport. Let's at least - make sure that it's not mixed with anything else... - On 64bit targets we combine comparisons with pair of adjacent __be32 - fields in the same way. -*/ -#ifdef __BIG_ENDIAN -#define INET_COMBINED_PORTS(__sport, __dport) \ - ((__force __portpair)(((__force __u32)(__be16)(__sport) << 16) | (__u32)(__dport))) -#else /* __LITTLE_ENDIAN */ -#define INET_COMBINED_PORTS(__sport, __dport) \ - ((__force __portpair)(((__u32)(__dport) << 16) | (__force __u32)(__be16)(__sport))) -#endif - -#if (BITS_PER_LONG == 64) -#ifdef __BIG_ENDIAN -#define INET_ADDR_COOKIE(__name, __saddr, __daddr) \ - const __addrpair __name = (__force __addrpair) ( \ - (((__force __u64)(__be32)(__saddr)) << 32) | \ - ((__force __u64)(__be32)(__daddr))) -#else /* __LITTLE_ENDIAN */ -#define INET_ADDR_COOKIE(__name, __saddr, __daddr) \ - const __addrpair __name = (__force __addrpair) ( \ - (((__force __u64)(__be32)(__daddr)) << 32) | \ - ((__force __u64)(__be32)(__saddr))) -#endif /* __BIG_ENDIAN */ -#define INET_MATCH(__sk, __net, __cookie, __saddr, __daddr, __ports, __dif) \ - (((__sk)->sk_portpair == (__ports)) && \ - ((__sk)->sk_addrpair == (__cookie)) && \ - (!(__sk)->sk_bound_dev_if || \ - ((__sk)->sk_bound_dev_if == (__dif))) && \ - net_eq(sock_net(__sk), (__net))) -#else /* 32-bit arch */ -#define INET_ADDR_COOKIE(__name, __saddr, __daddr) \ - const int __name __deprecated __attribute__((unused)) - -#define INET_MATCH(__sk, __net, __cookie, __saddr, __daddr, __ports, __dif) \ - (((__sk)->sk_portpair == (__ports)) && \ - ((__sk)->sk_daddr == (__saddr)) && \ - ((__sk)->sk_rcv_saddr == (__daddr)) && \ - (!(__sk)->sk_bound_dev_if || \ - ((__sk)->sk_bound_dev_if == (__dif))) && \ - net_eq(sock_net(__sk), (__net))) -#endif /* 64-bit arch */ - -/* Sockets in TCP_CLOSE state are _always_ taken out of the hash, so we need - * not check it for lookups anymore, thanks Alexey. -DaveM - */ -struct sock *__inet_lookup_established(struct net *net, - struct inet_hashinfo *hashinfo, - const __be32 saddr, const __be16 sport, - const __be32 daddr, const u16 hnum, - const int dif); - -static inline struct sock * - inet_lookup_established(struct net *net, struct inet_hashinfo *hashinfo, - const __be32 saddr, const __be16 sport, - const __be32 daddr, const __be16 dport, - const int dif) -{ - return __inet_lookup_established(net, hashinfo, saddr, sport, daddr, - ntohs(dport), dif); -} - -static inline struct sock *__inet_lookup(struct net *net, - struct inet_hashinfo *hashinfo, - struct sk_buff *skb, int doff, - const __be32 saddr, const __be16 sport, - const __be32 daddr, const __be16 dport, - const int dif, - bool *refcounted) -{ - u16 hnum = ntohs(dport); - struct sock *sk; - - sk = __inet_lookup_established(net, hashinfo, saddr, sport, - daddr, hnum, dif); - *refcounted = true; - if (sk) - return sk; - *refcounted = false; - return __inet_lookup_listener(net, hashinfo, skb, doff, saddr, - sport, daddr, hnum, dif); -} - -static inline struct sock *inet_lookup(struct net *net, - struct inet_hashinfo *hashinfo, - struct sk_buff *skb, int doff, - const __be32 saddr, const __be16 sport, - const __be32 daddr, const __be16 dport, - const int dif) -{ - struct sock *sk; - bool refcounted; - - sk = __inet_lookup(net, hashinfo, skb, doff, saddr, sport, daddr, - dport, dif, &refcounted); - - if (sk && !refcounted && !atomic_inc_not_zero(&sk->sk_refcnt)) - sk = NULL; - return sk; -} - -static inline struct sock *__inet_lookup_skb(struct inet_hashinfo *hashinfo, - struct sk_buff *skb, - int doff, - const __be16 sport, - const __be16 dport, - bool *refcounted) -{ - struct sock *sk = skb_steal_sock(skb); - const struct iphdr *iph = ip_hdr(skb); - - *refcounted = true; - if (sk) - return sk; - - return __inet_lookup(dev_net(skb_dst(skb)->dev), hashinfo, skb, - doff, iph->saddr, sport, - iph->daddr, dport, inet_iif(skb), - refcounted); -} - -u32 sk_ehashfn(const struct sock *sk); -u32 inet6_ehashfn(const struct net *net, - const struct in6_addr *laddr, const u16 lport, - const struct in6_addr *faddr, const __be16 fport); - -static inline void sk_daddr_set(struct sock *sk, __be32 addr) -{ - sk->sk_daddr = addr; /* alias of inet_daddr */ -#if IS_ENABLED(CONFIG_IPV6) - ipv6_addr_set_v4mapped(addr, &sk->sk_v6_daddr); -#endif -} - -static inline void sk_rcv_saddr_set(struct sock *sk, __be32 addr) -{ - sk->sk_rcv_saddr = addr; /* alias of inet_rcv_saddr */ -#if IS_ENABLED(CONFIG_IPV6) - ipv6_addr_set_v4mapped(addr, &sk->sk_v6_rcv_saddr); -#endif -} - -int __inet_hash_connect(struct inet_timewait_death_row *death_row, - struct sock *sk, u32 port_offset, - int (*check_established)(struct inet_timewait_death_row *, - struct sock *, __u16, - struct inet_timewait_sock **)); - -int inet_hash_connect(struct inet_timewait_death_row *death_row, - struct sock *sk); -#endif /* _INET_HASHTABLES_H */ diff --git a/src/linux/include/net/inet_sock.h b/src/linux/include/net/inet_sock.h deleted file mode 100644 index 236a810..0000000 --- a/src/linux/include/net/inet_sock.h +++ /dev/null @@ -1,326 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for inet_sock - * - * Authors: Many, reorganised here by - * Arnaldo Carvalho de Melo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _INET_SOCK_H -#define _INET_SOCK_H - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/** struct ip_options - IP Options - * - * @faddr - Saved first hop address - * @nexthop - Saved nexthop address in LSRR and SSRR - * @is_strictroute - Strict source route - * @srr_is_hit - Packet destination addr was our one - * @is_changed - IP checksum more not valid - * @rr_needaddr - Need to record addr of outgoing dev - * @ts_needtime - Need to record timestamp - * @ts_needaddr - Need to record addr of outgoing dev - */ -struct ip_options { - __be32 faddr; - __be32 nexthop; - unsigned char optlen; - unsigned char srr; - unsigned char rr; - unsigned char ts; - unsigned char is_strictroute:1, - srr_is_hit:1, - is_changed:1, - rr_needaddr:1, - ts_needtime:1, - ts_needaddr:1; - unsigned char router_alert; - unsigned char cipso; - unsigned char __pad2; - unsigned char __data[0]; -}; - -struct ip_options_rcu { - struct rcu_head rcu; - struct ip_options opt; -}; - -struct ip_options_data { - struct ip_options_rcu opt; - char data[40]; -}; - -struct inet_request_sock { - struct request_sock req; -#define ir_loc_addr req.__req_common.skc_rcv_saddr -#define ir_rmt_addr req.__req_common.skc_daddr -#define ir_num req.__req_common.skc_num -#define ir_rmt_port req.__req_common.skc_dport -#define ir_v6_rmt_addr req.__req_common.skc_v6_daddr -#define ir_v6_loc_addr req.__req_common.skc_v6_rcv_saddr -#define ir_iif req.__req_common.skc_bound_dev_if -#define ir_cookie req.__req_common.skc_cookie -#define ireq_net req.__req_common.skc_net -#define ireq_state req.__req_common.skc_state -#define ireq_family req.__req_common.skc_family - - kmemcheck_bitfield_begin(flags); - u16 snd_wscale : 4, - rcv_wscale : 4, - tstamp_ok : 1, - sack_ok : 1, - wscale_ok : 1, - ecn_ok : 1, - acked : 1, - no_srccheck: 1; - kmemcheck_bitfield_end(flags); - u32 ir_mark; - union { - struct ip_options_rcu *opt; -#if IS_ENABLED(CONFIG_IPV6) - struct { - struct ipv6_txoptions *ipv6_opt; - struct sk_buff *pktopts; - }; -#endif - }; -}; - -static inline struct inet_request_sock *inet_rsk(const struct request_sock *sk) -{ - return (struct inet_request_sock *)sk; -} - -static inline u32 inet_request_mark(const struct sock *sk, struct sk_buff *skb) -{ - if (!sk->sk_mark && sock_net(sk)->ipv4.sysctl_tcp_fwmark_accept) - return skb->mark; - - return sk->sk_mark; -} - -static inline int inet_request_bound_dev_if(const struct sock *sk, - struct sk_buff *skb) -{ -#ifdef CONFIG_NET_L3_MASTER_DEV - struct net *net = sock_net(sk); - - if (!sk->sk_bound_dev_if && net->ipv4.sysctl_tcp_l3mdev_accept) - return l3mdev_master_ifindex_by_index(net, skb->skb_iif); -#endif - - return sk->sk_bound_dev_if; -} - -struct inet_cork { - unsigned int flags; - __be32 addr; - struct ip_options *opt; - unsigned int fragsize; - int length; /* Total length of all frames */ - struct dst_entry *dst; - u8 tx_flags; - __u8 ttl; - __s16 tos; - char priority; -}; - -struct inet_cork_full { - struct inet_cork base; - struct flowi fl; -}; - -struct ip_mc_socklist; -struct ipv6_pinfo; -struct rtable; - -/** struct inet_sock - representation of INET sockets - * - * @sk - ancestor class - * @pinet6 - pointer to IPv6 control block - * @inet_daddr - Foreign IPv4 addr - * @inet_rcv_saddr - Bound local IPv4 addr - * @inet_dport - Destination port - * @inet_num - Local port - * @inet_saddr - Sending source - * @uc_ttl - Unicast TTL - * @inet_sport - Source port - * @inet_id - ID counter for DF pkts - * @tos - TOS - * @mc_ttl - Multicasting TTL - * @is_icsk - is this an inet_connection_sock? - * @uc_index - Unicast outgoing device index - * @mc_index - Multicast device index - * @mc_list - Group array - * @cork - info to build ip hdr on each ip frag while socket is corked - */ -struct inet_sock { - /* sk and pinet6 has to be the first two members of inet_sock */ - struct sock sk; -#if IS_ENABLED(CONFIG_IPV6) - struct ipv6_pinfo *pinet6; -#endif - /* Socket demultiplex comparisons on incoming packets. */ -#define inet_daddr sk.__sk_common.skc_daddr -#define inet_rcv_saddr sk.__sk_common.skc_rcv_saddr -#define inet_dport sk.__sk_common.skc_dport -#define inet_num sk.__sk_common.skc_num - - __be32 inet_saddr; - __s16 uc_ttl; - __u16 cmsg_flags; - __be16 inet_sport; - __u16 inet_id; - - struct ip_options_rcu __rcu *inet_opt; - int rx_dst_ifindex; - __u8 tos; - __u8 min_ttl; - __u8 mc_ttl; - __u8 pmtudisc; - __u8 recverr:1, - is_icsk:1, - freebind:1, - hdrincl:1, - mc_loop:1, - transparent:1, - mc_all:1, - nodefrag:1; - __u8 bind_address_no_port:1; - __u8 rcv_tos; - __u8 convert_csum; - int uc_index; - int mc_index; - __be32 mc_addr; - struct ip_mc_socklist __rcu *mc_list; - struct inet_cork_full cork; -}; - -#define IPCORK_OPT 1 /* ip-options has been held in ipcork.opt */ -#define IPCORK_ALLFRAG 2 /* always fragment (for ipv6 for now) */ - -/* cmsg flags for inet */ -#define IP_CMSG_PKTINFO BIT(0) -#define IP_CMSG_TTL BIT(1) -#define IP_CMSG_TOS BIT(2) -#define IP_CMSG_RECVOPTS BIT(3) -#define IP_CMSG_RETOPTS BIT(4) -#define IP_CMSG_PASSSEC BIT(5) -#define IP_CMSG_ORIGDSTADDR BIT(6) -#define IP_CMSG_CHECKSUM BIT(7) - -/** - * sk_to_full_sk - Access to a full socket - * @sk: pointer to a socket - * - * SYNACK messages might be attached to request sockets. - * Some places want to reach the listener in this case. - */ -static inline struct sock *sk_to_full_sk(struct sock *sk) -{ -#ifdef CONFIG_INET - if (sk && sk->sk_state == TCP_NEW_SYN_RECV) - sk = inet_reqsk(sk)->rsk_listener; -#endif - return sk; -} - -/* sk_to_full_sk() variant with a const argument */ -static inline const struct sock *sk_const_to_full_sk(const struct sock *sk) -{ -#ifdef CONFIG_INET - if (sk && sk->sk_state == TCP_NEW_SYN_RECV) - sk = ((const struct request_sock *)sk)->rsk_listener; -#endif - return sk; -} - -static inline struct sock *skb_to_full_sk(const struct sk_buff *skb) -{ - return sk_to_full_sk(skb->sk); -} - -static inline struct inet_sock *inet_sk(const struct sock *sk) -{ - return (struct inet_sock *)sk; -} - -static inline void __inet_sk_copy_descendant(struct sock *sk_to, - const struct sock *sk_from, - const int ancestor_size) -{ - memcpy(inet_sk(sk_to) + 1, inet_sk(sk_from) + 1, - sk_from->sk_prot->obj_size - ancestor_size); -} -#if !(IS_ENABLED(CONFIG_IPV6)) -static inline void inet_sk_copy_descendant(struct sock *sk_to, - const struct sock *sk_from) -{ - __inet_sk_copy_descendant(sk_to, sk_from, sizeof(struct inet_sock)); -} -#endif - -int inet_sk_rebuild_header(struct sock *sk); - -static inline unsigned int __inet_ehashfn(const __be32 laddr, - const __u16 lport, - const __be32 faddr, - const __be16 fport, - u32 initval) -{ - return jhash_3words((__force __u32) laddr, - (__force __u32) faddr, - ((__u32) lport) << 16 | (__force __u32)fport, - initval); -} - -struct request_sock *inet_reqsk_alloc(const struct request_sock_ops *ops, - struct sock *sk_listener, - bool attach_listener); - -static inline __u8 inet_sk_flowi_flags(const struct sock *sk) -{ - __u8 flags = 0; - - if (inet_sk(sk)->transparent || inet_sk(sk)->hdrincl) - flags |= FLOWI_FLAG_ANYSRC; - return flags; -} - -static inline void inet_inc_convert_csum(struct sock *sk) -{ - inet_sk(sk)->convert_csum++; -} - -static inline void inet_dec_convert_csum(struct sock *sk) -{ - if (inet_sk(sk)->convert_csum > 0) - inet_sk(sk)->convert_csum--; -} - -static inline bool inet_get_convert_csum(struct sock *sk) -{ - return !!inet_sk(sk)->convert_csum; -} - -#endif /* _INET_SOCK_H */ diff --git a/src/linux/include/net/inet_timewait_sock.h b/src/linux/include/net/inet_timewait_sock.h deleted file mode 100644 index c9b3eb7..0000000 --- a/src/linux/include/net/inet_timewait_sock.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for a generic INET TIMEWAIT sock - * - * From code originally in net/tcp.h - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _INET_TIMEWAIT_SOCK_ -#define _INET_TIMEWAIT_SOCK_ - - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -struct inet_hashinfo; - -struct inet_timewait_death_row { - atomic_t tw_count; - - struct inet_hashinfo *hashinfo ____cacheline_aligned_in_smp; - int sysctl_tw_recycle; - int sysctl_max_tw_buckets; -}; - -struct inet_bind_bucket; - -/* - * This is a TIME_WAIT sock. It works around the memory consumption - * problems of sockets in such a state on heavily loaded servers, but - * without violating the protocol specification. - */ -struct inet_timewait_sock { - /* - * Now struct sock also uses sock_common, so please just - * don't add nothing before this first member (__tw_common) --acme - */ - struct sock_common __tw_common; -#define tw_family __tw_common.skc_family -#define tw_state __tw_common.skc_state -#define tw_reuse __tw_common.skc_reuse -#define tw_ipv6only __tw_common.skc_ipv6only -#define tw_bound_dev_if __tw_common.skc_bound_dev_if -#define tw_node __tw_common.skc_nulls_node -#define tw_bind_node __tw_common.skc_bind_node -#define tw_refcnt __tw_common.skc_refcnt -#define tw_hash __tw_common.skc_hash -#define tw_prot __tw_common.skc_prot -#define tw_net __tw_common.skc_net -#define tw_daddr __tw_common.skc_daddr -#define tw_v6_daddr __tw_common.skc_v6_daddr -#define tw_rcv_saddr __tw_common.skc_rcv_saddr -#define tw_v6_rcv_saddr __tw_common.skc_v6_rcv_saddr -#define tw_dport __tw_common.skc_dport -#define tw_num __tw_common.skc_num -#define tw_cookie __tw_common.skc_cookie -#define tw_dr __tw_common.skc_tw_dr - - int tw_timeout; - volatile unsigned char tw_substate; - unsigned char tw_rcv_wscale; - - /* Socket demultiplex comparisons on incoming packets. */ - /* these three are in inet_sock */ - __be16 tw_sport; - kmemcheck_bitfield_begin(flags); - /* And these are ours. */ - unsigned int tw_kill : 1, - tw_transparent : 1, - tw_flowlabel : 20, - tw_pad : 2, /* 2 bits hole */ - tw_tos : 8; - kmemcheck_bitfield_end(flags); - struct timer_list tw_timer; - struct inet_bind_bucket *tw_tb; -}; -#define tw_tclass tw_tos - -static inline struct inet_timewait_sock *inet_twsk(const struct sock *sk) -{ - return (struct inet_timewait_sock *)sk; -} - -void inet_twsk_free(struct inet_timewait_sock *tw); -void inet_twsk_put(struct inet_timewait_sock *tw); - -void inet_twsk_bind_unhash(struct inet_timewait_sock *tw, - struct inet_hashinfo *hashinfo); - -struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, - struct inet_timewait_death_row *dr, - const int state); - -void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, - struct inet_hashinfo *hashinfo); - -void __inet_twsk_schedule(struct inet_timewait_sock *tw, int timeo, - bool rearm); - -static inline void inet_twsk_schedule(struct inet_timewait_sock *tw, int timeo) -{ - __inet_twsk_schedule(tw, timeo, false); -} - -static inline void inet_twsk_reschedule(struct inet_timewait_sock *tw, int timeo) -{ - __inet_twsk_schedule(tw, timeo, true); -} - -void inet_twsk_deschedule_put(struct inet_timewait_sock *tw); - -void inet_twsk_purge(struct inet_hashinfo *hashinfo, - struct inet_timewait_death_row *twdr, int family); - -static inline -struct net *twsk_net(const struct inet_timewait_sock *twsk) -{ - return read_pnet(&twsk->tw_net); -} - -static inline -void twsk_net_set(struct inet_timewait_sock *twsk, struct net *net) -{ - write_pnet(&twsk->tw_net, net); -} -#endif /* _INET_TIMEWAIT_SOCK_ */ diff --git a/src/linux/include/net/inetpeer.h b/src/linux/include/net/inetpeer.h deleted file mode 100644 index 235c781..0000000 --- a/src/linux/include/net/inetpeer.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * INETPEER - A storage for permanent information about peers - * - * Authors: Andrey V. Savochkin - */ - -#ifndef _NET_INETPEER_H -#define _NET_INETPEER_H - -#include -#include -#include -#include -#include -#include -#include - -/* IPv4 address key for cache lookups */ -struct ipv4_addr_key { - __be32 addr; - int vif; -}; - -#define INETPEER_MAXKEYSZ (sizeof(struct in6_addr) / sizeof(u32)) - -struct inetpeer_addr { - union { - struct ipv4_addr_key a4; - struct in6_addr a6; - u32 key[INETPEER_MAXKEYSZ]; - }; - __u16 family; -}; - -struct inet_peer { - /* group together avl_left,avl_right,v4daddr to speedup lookups */ - struct inet_peer __rcu *avl_left, *avl_right; - struct inetpeer_addr daddr; - __u32 avl_height; - - u32 metrics[RTAX_MAX]; - u32 rate_tokens; /* rate limiting for ICMP */ - unsigned long rate_last; - union { - struct list_head gc_list; - struct rcu_head gc_rcu; - }; - /* - * Once inet_peer is queued for deletion (refcnt == -1), following field - * is not available: rid - * We can share memory with rcu_head to help keep inet_peer small. - */ - union { - struct { - atomic_t rid; /* Frag reception counter */ - }; - struct rcu_head rcu; - struct inet_peer *gc_next; - }; - - /* following fields might be frequently dirtied */ - __u32 dtime; /* the time of last use of not referenced entries */ - atomic_t refcnt; -}; - -struct inet_peer_base { - struct inet_peer __rcu *root; - seqlock_t lock; - int total; -}; - -void inet_peer_base_init(struct inet_peer_base *); - -void inet_initpeers(void) __init; - -#define INETPEER_METRICS_NEW (~(u32) 0) - -static inline void inetpeer_set_addr_v4(struct inetpeer_addr *iaddr, __be32 ip) -{ - iaddr->a4.addr = ip; - iaddr->a4.vif = 0; - iaddr->family = AF_INET; -} - -static inline __be32 inetpeer_get_addr_v4(struct inetpeer_addr *iaddr) -{ - return iaddr->a4.addr; -} - -static inline void inetpeer_set_addr_v6(struct inetpeer_addr *iaddr, - struct in6_addr *in6) -{ - iaddr->a6 = *in6; - iaddr->family = AF_INET6; -} - -static inline struct in6_addr *inetpeer_get_addr_v6(struct inetpeer_addr *iaddr) -{ - return &iaddr->a6; -} - -/* can be called with or without local BH being disabled */ -struct inet_peer *inet_getpeer(struct inet_peer_base *base, - const struct inetpeer_addr *daddr, - int create); - -static inline struct inet_peer *inet_getpeer_v4(struct inet_peer_base *base, - __be32 v4daddr, - int vif, int create) -{ - struct inetpeer_addr daddr; - - daddr.a4.addr = v4daddr; - daddr.a4.vif = vif; - daddr.family = AF_INET; - return inet_getpeer(base, &daddr, create); -} - -static inline struct inet_peer *inet_getpeer_v6(struct inet_peer_base *base, - const struct in6_addr *v6daddr, - int create) -{ - struct inetpeer_addr daddr; - - daddr.a6 = *v6daddr; - daddr.family = AF_INET6; - return inet_getpeer(base, &daddr, create); -} - -static inline int inetpeer_addr_cmp(const struct inetpeer_addr *a, - const struct inetpeer_addr *b) -{ - int i, n; - - if (a->family == AF_INET) - n = sizeof(a->a4) / sizeof(u32); - else - n = sizeof(a->a6) / sizeof(u32); - - for (i = 0; i < n; i++) { - if (a->key[i] == b->key[i]) - continue; - if (a->key[i] < b->key[i]) - return -1; - return 1; - } - - return 0; -} - -/* can be called from BH context or outside */ -void inet_putpeer(struct inet_peer *p); -bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout); - -void inetpeer_invalidate_tree(struct inet_peer_base *); - -#endif /* _NET_INETPEER_H */ diff --git a/src/linux/include/net/ip.h b/src/linux/include/net/ip.h deleted file mode 100644 index d3a1078..0000000 --- a/src/linux/include/net/ip.h +++ /dev/null @@ -1,613 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the IP module. - * - * Version: @(#)ip.h 1.0.2 05/07/93 - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Alan Cox, - * - * Changes: - * Mike McLagan : Routing by source - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _IP_H -#define _IP_H - -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -struct sock; - -struct inet_skb_parm { - int iif; - struct ip_options opt; /* Compiled IP options */ - u16 flags; - -#define IPSKB_FORWARDED BIT(0) -#define IPSKB_XFRM_TUNNEL_SIZE BIT(1) -#define IPSKB_XFRM_TRANSFORMED BIT(2) -#define IPSKB_FRAG_COMPLETE BIT(3) -#define IPSKB_REROUTED BIT(4) -#define IPSKB_DOREDIRECT BIT(5) -#define IPSKB_FRAG_PMTU BIT(6) -#define IPSKB_L3SLAVE BIT(7) - - u16 frag_max_size; -}; - -static inline bool ipv4_l3mdev_skb(u16 flags) -{ - return !!(flags & IPSKB_L3SLAVE); -} - -static inline unsigned int ip_hdrlen(const struct sk_buff *skb) -{ - return ip_hdr(skb)->ihl * 4; -} - -struct ipcm_cookie { - struct sockcm_cookie sockc; - __be32 addr; - int oif; - struct ip_options_rcu *opt; - __u8 tx_flags; - __u8 ttl; - __s16 tos; - char priority; -}; - -#define IPCB(skb) ((struct inet_skb_parm*)((skb)->cb)) -#define PKTINFO_SKB_CB(skb) ((struct in_pktinfo *)((skb)->cb)) - -struct ip_ra_chain { - struct ip_ra_chain __rcu *next; - struct sock *sk; - union { - void (*destructor)(struct sock *); - struct sock *saved_sk; - }; - struct rcu_head rcu; -}; - -extern struct ip_ra_chain __rcu *ip_ra_chain; - -/* IP flags. */ -#define IP_CE 0x8000 /* Flag: "Congestion" */ -#define IP_DF 0x4000 /* Flag: "Don't Fragment" */ -#define IP_MF 0x2000 /* Flag: "More Fragments" */ -#define IP_OFFSET 0x1FFF /* "Fragment Offset" part */ - -#define IP_FRAG_TIME (30 * HZ) /* fragment lifetime */ - -struct msghdr; -struct net_device; -struct packet_type; -struct rtable; -struct sockaddr; - -int igmp_mc_init(void); - -/* - * Functions provided by ip.c - */ - -int ip_build_and_send_pkt(struct sk_buff *skb, const struct sock *sk, - __be32 saddr, __be32 daddr, - struct ip_options_rcu *opt); -int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, - struct net_device *orig_dev); -int ip_local_deliver(struct sk_buff *skb); -int ip_mr_input(struct sk_buff *skb); -int ip_output(struct net *net, struct sock *sk, struct sk_buff *skb); -int ip_mc_output(struct net *net, struct sock *sk, struct sk_buff *skb); -int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, - int (*output)(struct net *, struct sock *, struct sk_buff *)); -void ip_send_check(struct iphdr *ip); -int __ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb); -int ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb); - -int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl); -void ip_init(void); -int ip_append_data(struct sock *sk, struct flowi4 *fl4, - int getfrag(void *from, char *to, int offset, int len, - int odd, struct sk_buff *skb), - void *from, int len, int protolen, - struct ipcm_cookie *ipc, - struct rtable **rt, - unsigned int flags); -int ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, - struct sk_buff *skb); -ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, - int offset, size_t size, int flags); -struct sk_buff *__ip_make_skb(struct sock *sk, struct flowi4 *fl4, - struct sk_buff_head *queue, - struct inet_cork *cork); -int ip_send_skb(struct net *net, struct sk_buff *skb); -int ip_push_pending_frames(struct sock *sk, struct flowi4 *fl4); -void ip_flush_pending_frames(struct sock *sk); -struct sk_buff *ip_make_skb(struct sock *sk, struct flowi4 *fl4, - int getfrag(void *from, char *to, int offset, - int len, int odd, struct sk_buff *skb), - void *from, int length, int transhdrlen, - struct ipcm_cookie *ipc, struct rtable **rtp, - unsigned int flags); - -static inline struct sk_buff *ip_finish_skb(struct sock *sk, struct flowi4 *fl4) -{ - return __ip_make_skb(sk, fl4, &sk->sk_write_queue, &inet_sk(sk)->cork.base); -} - -static inline __u8 get_rttos(struct ipcm_cookie* ipc, struct inet_sock *inet) -{ - return (ipc->tos != -1) ? RT_TOS(ipc->tos) : RT_TOS(inet->tos); -} - -static inline __u8 get_rtconn_flags(struct ipcm_cookie* ipc, struct sock* sk) -{ - return (ipc->tos != -1) ? RT_CONN_FLAGS_TOS(sk, ipc->tos) : RT_CONN_FLAGS(sk); -} - -/* datagram.c */ -int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); -int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); - -void ip4_datagram_release_cb(struct sock *sk); - -struct ip_reply_arg { - struct kvec iov[1]; - int flags; - __wsum csum; - int csumoffset; /* u16 offset of csum in iov[0].iov_base */ - /* -1 if not needed */ - int bound_dev_if; - u8 tos; -}; - -#define IP_REPLY_ARG_NOSRCCHECK 1 - -static inline __u8 ip_reply_arg_flowi_flags(const struct ip_reply_arg *arg) -{ - return (arg->flags & IP_REPLY_ARG_NOSRCCHECK) ? FLOWI_FLAG_ANYSRC : 0; -} - -void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, - const struct ip_options *sopt, - __be32 daddr, __be32 saddr, - const struct ip_reply_arg *arg, - unsigned int len); - -#define IP_INC_STATS(net, field) SNMP_INC_STATS64((net)->mib.ip_statistics, field) -#define __IP_INC_STATS(net, field) __SNMP_INC_STATS64((net)->mib.ip_statistics, field) -#define IP_ADD_STATS(net, field, val) SNMP_ADD_STATS64((net)->mib.ip_statistics, field, val) -#define __IP_ADD_STATS(net, field, val) __SNMP_ADD_STATS64((net)->mib.ip_statistics, field, val) -#define IP_UPD_PO_STATS(net, field, val) SNMP_UPD_PO_STATS64((net)->mib.ip_statistics, field, val) -#define __IP_UPD_PO_STATS(net, field, val) __SNMP_UPD_PO_STATS64((net)->mib.ip_statistics, field, val) -#define NET_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.net_statistics, field) -#define __NET_INC_STATS(net, field) __SNMP_INC_STATS((net)->mib.net_statistics, field) -#define NET_ADD_STATS(net, field, adnd) SNMP_ADD_STATS((net)->mib.net_statistics, field, adnd) -#define __NET_ADD_STATS(net, field, adnd) __SNMP_ADD_STATS((net)->mib.net_statistics, field, adnd) - -u64 snmp_get_cpu_field(void __percpu *mib, int cpu, int offct); -unsigned long snmp_fold_field(void __percpu *mib, int offt); -#if BITS_PER_LONG==32 -u64 snmp_get_cpu_field64(void __percpu *mib, int cpu, int offct, - size_t syncp_offset); -u64 snmp_fold_field64(void __percpu *mib, int offt, size_t sync_off); -#else -static inline u64 snmp_get_cpu_field64(void __percpu *mib, int cpu, int offct, - size_t syncp_offset) -{ - return snmp_get_cpu_field(mib, cpu, offct); - -} - -static inline u64 snmp_fold_field64(void __percpu *mib, int offt, size_t syncp_off) -{ - return snmp_fold_field(mib, offt); -} -#endif - -#define snmp_get_cpu_field64_batch(buff64, stats_list, mib_statistic, offset) \ -{ \ - int i, c; \ - for_each_possible_cpu(c) { \ - for (i = 0; stats_list[i].name; i++) \ - buff64[i] += snmp_get_cpu_field64( \ - mib_statistic, \ - c, stats_list[i].entry, \ - offset); \ - } \ -} - -#define snmp_get_cpu_field_batch(buff, stats_list, mib_statistic) \ -{ \ - int i, c; \ - for_each_possible_cpu(c) { \ - for (i = 0; stats_list[i].name; i++) \ - buff[i] += snmp_get_cpu_field( \ - mib_statistic, \ - c, stats_list[i].entry); \ - } \ -} - -void inet_get_local_port_range(struct net *net, int *low, int *high); - -#ifdef CONFIG_SYSCTL -static inline int inet_is_local_reserved_port(struct net *net, int port) -{ - if (!net->ipv4.sysctl_local_reserved_ports) - return 0; - return test_bit(port, net->ipv4.sysctl_local_reserved_ports); -} - -static inline bool sysctl_dev_name_is_allowed(const char *name) -{ - return strcmp(name, "default") != 0 && strcmp(name, "all") != 0; -} - -#else -static inline int inet_is_local_reserved_port(struct net *net, int port) -{ - return 0; -} -#endif - -__be32 inet_current_timestamp(void); - -/* From inetpeer.c */ -extern int inet_peer_threshold; -extern int inet_peer_minttl; -extern int inet_peer_maxttl; - -void ipfrag_init(void); - -void ip_static_sysctl_init(void); - -#define IP4_REPLY_MARK(net, mark) \ - ((net)->ipv4.sysctl_fwmark_reflect ? (mark) : 0) - -static inline bool ip_is_fragment(const struct iphdr *iph) -{ - return (iph->frag_off & htons(IP_MF | IP_OFFSET)) != 0; -} - -#ifdef CONFIG_INET -#include - -/* The function in 2.2 was invalid, producing wrong result for - * check=0xFEFF. It was noticed by Arthur Skawina _year_ ago. --ANK(000625) */ -static inline -int ip_decrease_ttl(struct iphdr *iph) -{ - u32 check = (__force u32)iph->check; - check += (__force u32)htons(0x0100); - iph->check = (__force __sum16)(check + (check>=0xFFFF)); - return --iph->ttl; -} - -static inline -int ip_dont_fragment(const struct sock *sk, const struct dst_entry *dst) -{ - u8 pmtudisc = READ_ONCE(inet_sk(sk)->pmtudisc); - - return pmtudisc == IP_PMTUDISC_DO || - (pmtudisc == IP_PMTUDISC_WANT && - !(dst_metric_locked(dst, RTAX_MTU))); -} - -static inline bool ip_sk_accept_pmtu(const struct sock *sk) -{ - return inet_sk(sk)->pmtudisc != IP_PMTUDISC_INTERFACE && - inet_sk(sk)->pmtudisc != IP_PMTUDISC_OMIT; -} - -static inline bool ip_sk_use_pmtu(const struct sock *sk) -{ - return inet_sk(sk)->pmtudisc < IP_PMTUDISC_PROBE; -} - -static inline bool ip_sk_ignore_df(const struct sock *sk) -{ - return inet_sk(sk)->pmtudisc < IP_PMTUDISC_DO || - inet_sk(sk)->pmtudisc == IP_PMTUDISC_OMIT; -} - -static inline unsigned int ip_dst_mtu_maybe_forward(const struct dst_entry *dst, - bool forwarding) -{ - struct net *net = dev_net(dst->dev); - - if (net->ipv4.sysctl_ip_fwd_use_pmtu || - dst_metric_locked(dst, RTAX_MTU) || - !forwarding) - return dst_mtu(dst); - - return min(dst->dev->mtu, IP_MAX_MTU); -} - -static inline unsigned int ip_skb_dst_mtu(struct sock *sk, - const struct sk_buff *skb) -{ - if (!sk || !sk_fullsock(sk) || ip_sk_use_pmtu(sk)) { - bool forwarding = IPCB(skb)->flags & IPSKB_FORWARDED; - - return ip_dst_mtu_maybe_forward(skb_dst(skb), forwarding); - } - - return min(skb_dst(skb)->dev->mtu, IP_MAX_MTU); -} - -u32 ip_idents_reserve(u32 hash, int segs); -void __ip_select_ident(struct net *net, struct iphdr *iph, int segs); - -static inline void ip_select_ident_segs(struct net *net, struct sk_buff *skb, - struct sock *sk, int segs) -{ - struct iphdr *iph = ip_hdr(skb); - - if ((iph->frag_off & htons(IP_DF)) && !skb->ignore_df) { - /* This is only to work around buggy Windows95/2000 - * VJ compression implementations. If the ID field - * does not change, they drop every other packet in - * a TCP stream using header compression. - */ - if (sk && inet_sk(sk)->inet_daddr) { - iph->id = htons(inet_sk(sk)->inet_id); - inet_sk(sk)->inet_id += segs; - } else { - iph->id = 0; - } - } else { - __ip_select_ident(net, iph, segs); - } -} - -static inline void ip_select_ident(struct net *net, struct sk_buff *skb, - struct sock *sk) -{ - ip_select_ident_segs(net, skb, sk, 1); -} - -static inline __wsum inet_compute_pseudo(struct sk_buff *skb, int proto) -{ - return csum_tcpudp_nofold(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, - skb->len, proto, 0); -} - -/* copy IPv4 saddr & daddr to flow_keys, possibly using 64bit load/store - * Equivalent to : flow->v4addrs.src = iph->saddr; - * flow->v4addrs.dst = iph->daddr; - */ -static inline void iph_to_flow_copy_v4addrs(struct flow_keys *flow, - const struct iphdr *iph) -{ - BUILD_BUG_ON(offsetof(typeof(flow->addrs), v4addrs.dst) != - offsetof(typeof(flow->addrs), v4addrs.src) + - sizeof(flow->addrs.v4addrs.src)); - memcpy(&flow->addrs.v4addrs, &iph->saddr, sizeof(flow->addrs.v4addrs)); - flow->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; -} - -static inline __wsum inet_gro_compute_pseudo(struct sk_buff *skb, int proto) -{ - const struct iphdr *iph = skb_gro_network_header(skb); - - return csum_tcpudp_nofold(iph->saddr, iph->daddr, - skb_gro_len(skb), proto, 0); -} - -/* - * Map a multicast IP onto multicast MAC for type ethernet. - */ - -static inline void ip_eth_mc_map(__be32 naddr, char *buf) -{ - __u32 addr=ntohl(naddr); - buf[0]=0x01; - buf[1]=0x00; - buf[2]=0x5e; - buf[5]=addr&0xFF; - addr>>=8; - buf[4]=addr&0xFF; - addr>>=8; - buf[3]=addr&0x7F; -} - -/* - * Map a multicast IP onto multicast MAC for type IP-over-InfiniBand. - * Leave P_Key as 0 to be filled in by driver. - */ - -static inline void ip_ib_mc_map(__be32 naddr, const unsigned char *broadcast, char *buf) -{ - __u32 addr; - unsigned char scope = broadcast[5] & 0xF; - - buf[0] = 0; /* Reserved */ - buf[1] = 0xff; /* Multicast QPN */ - buf[2] = 0xff; - buf[3] = 0xff; - addr = ntohl(naddr); - buf[4] = 0xff; - buf[5] = 0x10 | scope; /* scope from broadcast address */ - buf[6] = 0x40; /* IPv4 signature */ - buf[7] = 0x1b; - buf[8] = broadcast[8]; /* P_Key */ - buf[9] = broadcast[9]; - buf[10] = 0; - buf[11] = 0; - buf[12] = 0; - buf[13] = 0; - buf[14] = 0; - buf[15] = 0; - buf[19] = addr & 0xff; - addr >>= 8; - buf[18] = addr & 0xff; - addr >>= 8; - buf[17] = addr & 0xff; - addr >>= 8; - buf[16] = addr & 0x0f; -} - -static inline void ip_ipgre_mc_map(__be32 naddr, const unsigned char *broadcast, char *buf) -{ - if ((broadcast[0] | broadcast[1] | broadcast[2] | broadcast[3]) != 0) - memcpy(buf, broadcast, 4); - else - memcpy(buf, &naddr, sizeof(naddr)); -} - -#if IS_ENABLED(CONFIG_IPV6) -#include -#endif - -static __inline__ void inet_reset_saddr(struct sock *sk) -{ - inet_sk(sk)->inet_rcv_saddr = inet_sk(sk)->inet_saddr = 0; -#if IS_ENABLED(CONFIG_IPV6) - if (sk->sk_family == PF_INET6) { - struct ipv6_pinfo *np = inet6_sk(sk); - - memset(&np->saddr, 0, sizeof(np->saddr)); - memset(&sk->sk_v6_rcv_saddr, 0, sizeof(sk->sk_v6_rcv_saddr)); - } -#endif -} - -#endif - -static inline unsigned int ipv4_addr_hash(__be32 ip) -{ - return (__force unsigned int) ip; -} - -bool ip_call_ra_chain(struct sk_buff *skb); - -/* - * Functions provided by ip_fragment.c - */ - -enum ip_defrag_users { - IP_DEFRAG_LOCAL_DELIVER, - IP_DEFRAG_CALL_RA_CHAIN, - IP_DEFRAG_CONNTRACK_IN, - __IP_DEFRAG_CONNTRACK_IN_END = IP_DEFRAG_CONNTRACK_IN + USHRT_MAX, - IP_DEFRAG_CONNTRACK_OUT, - __IP_DEFRAG_CONNTRACK_OUT_END = IP_DEFRAG_CONNTRACK_OUT + USHRT_MAX, - IP_DEFRAG_CONNTRACK_BRIDGE_IN, - __IP_DEFRAG_CONNTRACK_BRIDGE_IN = IP_DEFRAG_CONNTRACK_BRIDGE_IN + USHRT_MAX, - IP_DEFRAG_VS_IN, - IP_DEFRAG_VS_OUT, - IP_DEFRAG_VS_FWD, - IP_DEFRAG_AF_PACKET, - IP_DEFRAG_MACVLAN, -}; - -/* Return true if the value of 'user' is between 'lower_bond' - * and 'upper_bond' inclusively. - */ -static inline bool ip_defrag_user_in_between(u32 user, - enum ip_defrag_users lower_bond, - enum ip_defrag_users upper_bond) -{ - return user >= lower_bond && user <= upper_bond; -} - -int ip_defrag(struct net *net, struct sk_buff *skb, u32 user); -#ifdef CONFIG_INET -struct sk_buff *ip_check_defrag(struct net *net, struct sk_buff *skb, u32 user); -#else -static inline struct sk_buff *ip_check_defrag(struct net *net, struct sk_buff *skb, u32 user) -{ - return skb; -} -#endif -int ip_frag_mem(struct net *net); - -/* - * Functions provided by ip_forward.c - */ - -int ip_forward(struct sk_buff *skb); - -/* - * Functions provided by ip_options.c - */ - -void ip_options_build(struct sk_buff *skb, struct ip_options *opt, - __be32 daddr, struct rtable *rt, int is_frag); - -int __ip_options_echo(struct ip_options *dopt, struct sk_buff *skb, - const struct ip_options *sopt); -static inline int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb) -{ - return __ip_options_echo(dopt, skb, &IPCB(skb)->opt); -} - -void ip_options_fragment(struct sk_buff *skb); -int ip_options_compile(struct net *net, struct ip_options *opt, - struct sk_buff *skb); -int ip_options_get(struct net *net, struct ip_options_rcu **optp, - unsigned char *data, int optlen); -int ip_options_get_from_user(struct net *net, struct ip_options_rcu **optp, - unsigned char __user *data, int optlen); -void ip_options_undo(struct ip_options *opt); -void ip_forward_options(struct sk_buff *skb); -int ip_options_rcv_srr(struct sk_buff *skb); - -/* - * Functions provided by ip_sockglue.c - */ - -void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb); -void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, int tlen, int offset); -int ip_cmsg_send(struct sock *sk, struct msghdr *msg, - struct ipcm_cookie *ipc, bool allow_ipv6); -int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, - unsigned int optlen); -int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval, - int __user *optlen); -int compat_ip_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen); -int compat_ip_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen); -int ip_ra_control(struct sock *sk, unsigned char on, - void (*destructor)(struct sock *)); - -int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len); -void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err, __be16 port, - u32 info, u8 *payload); -void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 dport, - u32 info); - -static inline void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) -{ - ip_cmsg_recv_offset(msg, skb, 0, 0); -} - -bool icmp_global_allow(void); -extern int sysctl_icmp_msgs_per_sec; -extern int sysctl_icmp_msgs_burst; - -#ifdef CONFIG_PROC_FS -int ip_misc_proc_init(void); -#endif - -#endif /* _IP_H */ diff --git a/src/linux/include/net/ip6_checksum.h b/src/linux/include/net/ip6_checksum.h deleted file mode 100644 index cca8405..0000000 --- a/src/linux/include/net/ip6_checksum.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Checksumming functions for IPv6 - * - * Authors: Jorge Cwik, - * Arnt Gulbrandsen, - * Borrows very liberally from tcp.c and ip.c, see those - * files for more names. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -/* - * Fixes: - * - * Ralf Baechle : generic ipv6 checksum - * - */ - -#ifndef _CHECKSUM_IPV6_H -#define _CHECKSUM_IPV6_H - -#include -#include -#include -#include -#include -#include -#include - -#ifndef _HAVE_ARCH_IPV6_CSUM -__sum16 csum_ipv6_magic(const struct in6_addr *saddr, - const struct in6_addr *daddr, - __u32 len, __u8 proto, __wsum csum); -#endif - -static inline __wsum ip6_compute_pseudo(struct sk_buff *skb, int proto) -{ - return ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - skb->len, proto, 0)); -} - -static inline __wsum ip6_gro_compute_pseudo(struct sk_buff *skb, int proto) -{ - const struct ipv6hdr *iph = skb_gro_network_header(skb); - - return ~csum_unfold(csum_ipv6_magic(&iph->saddr, &iph->daddr, - skb_gro_len(skb), proto, 0)); -} - -static __inline__ __sum16 tcp_v6_check(int len, - const struct in6_addr *saddr, - const struct in6_addr *daddr, - __wsum base) -{ - return csum_ipv6_magic(saddr, daddr, len, IPPROTO_TCP, base); -} - -static inline void __tcp_v6_send_check(struct sk_buff *skb, - const struct in6_addr *saddr, - const struct in6_addr *daddr) -{ - struct tcphdr *th = tcp_hdr(skb); - - if (skb->ip_summed == CHECKSUM_PARTIAL) { - th->check = ~tcp_v6_check(skb->len, saddr, daddr, 0); - skb->csum_start = skb_transport_header(skb) - skb->head; - skb->csum_offset = offsetof(struct tcphdr, check); - } else { - th->check = tcp_v6_check(skb->len, saddr, daddr, - csum_partial(th, th->doff << 2, - skb->csum)); - } -} - -#if IS_ENABLED(CONFIG_IPV6) -static inline void tcp_v6_send_check(struct sock *sk, struct sk_buff *skb) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - - __tcp_v6_send_check(skb, &np->saddr, &sk->sk_v6_daddr); -} -#endif - -static inline __sum16 udp_v6_check(int len, - const struct in6_addr *saddr, - const struct in6_addr *daddr, - __wsum base) -{ - return csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, base); -} - -void udp6_set_csum(bool nocheck, struct sk_buff *skb, - const struct in6_addr *saddr, - const struct in6_addr *daddr, int len); - -int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto); -#endif diff --git a/src/linux/include/net/ip6_fib.h b/src/linux/include/net/ip6_fib.h deleted file mode 100644 index a74e2aa..0000000 --- a/src/linux/include/net/ip6_fib.h +++ /dev/null @@ -1,305 +0,0 @@ -/* - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _IP6_FIB_H -#define _IP6_FIB_H - -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_IPV6_MULTIPLE_TABLES -#define FIB6_TABLE_HASHSZ 256 -#else -#define FIB6_TABLE_HASHSZ 1 -#endif - -struct rt6_info; - -struct fib6_config { - u32 fc_table; - u32 fc_metric; - int fc_dst_len; - int fc_src_len; - int fc_ifindex; - u32 fc_flags; - u32 fc_protocol; - u32 fc_type; /* only 8 bits are used */ - - struct in6_addr fc_dst; - struct in6_addr fc_src; - struct in6_addr fc_prefsrc; - struct in6_addr fc_gateway; - - unsigned long fc_expires; - struct nlattr *fc_mx; - int fc_mx_len; - int fc_mp_len; - struct nlattr *fc_mp; - - struct nl_info fc_nlinfo; - struct nlattr *fc_encap; - u16 fc_encap_type; -}; - -struct fib6_node { - struct fib6_node *parent; - struct fib6_node *left; - struct fib6_node *right; -#ifdef CONFIG_IPV6_SUBTREES - struct fib6_node *subtree; -#endif - struct rt6_info *leaf; - - __u16 fn_bit; /* bit key */ - __u16 fn_flags; - int fn_sernum; - struct rt6_info *rr_ptr; -}; - -#ifndef CONFIG_IPV6_SUBTREES -#define FIB6_SUBTREE(fn) NULL -#else -#define FIB6_SUBTREE(fn) ((fn)->subtree) -#endif - -struct mx6_config { - const u32 *mx; - DECLARE_BITMAP(mx_valid, RTAX_MAX); -}; - -/* - * routing information - * - */ - -struct rt6key { - struct in6_addr addr; - int plen; -}; - -struct fib6_table; - -struct rt6_info { - struct dst_entry dst; - - /* - * Tail elements of dst_entry (__refcnt etc.) - * and these elements (rarely used in hot path) are in - * the same cache line. - */ - struct fib6_table *rt6i_table; - struct fib6_node *rt6i_node; - - struct in6_addr rt6i_gateway; - - /* Multipath routes: - * siblings is a list of rt6_info that have the the same metric/weight, - * destination, but not the same gateway. nsiblings is just a cache - * to speed up lookup. - */ - struct list_head rt6i_siblings; - unsigned int rt6i_nsiblings; - - atomic_t rt6i_ref; - - /* These are in a separate cache line. */ - struct rt6key rt6i_dst ____cacheline_aligned_in_smp; - u32 rt6i_flags; - struct rt6key rt6i_src; - struct rt6key rt6i_prefsrc; - - struct list_head rt6i_uncached; - struct uncached_list *rt6i_uncached_list; - - struct inet6_dev *rt6i_idev; - struct rt6_info * __percpu *rt6i_pcpu; - - u32 rt6i_metric; - u32 rt6i_pmtu; - /* more non-fragment space at head required */ - unsigned short rt6i_nfheader_len; - u8 rt6i_protocol; -}; - -static inline struct inet6_dev *ip6_dst_idev(struct dst_entry *dst) -{ - return ((struct rt6_info *)dst)->rt6i_idev; -} - -static inline void rt6_clean_expires(struct rt6_info *rt) -{ - rt->rt6i_flags &= ~RTF_EXPIRES; - rt->dst.expires = 0; -} - -static inline void rt6_set_expires(struct rt6_info *rt, unsigned long expires) -{ - rt->dst.expires = expires; - rt->rt6i_flags |= RTF_EXPIRES; -} - -static inline void rt6_update_expires(struct rt6_info *rt0, int timeout) -{ - struct rt6_info *rt; - - for (rt = rt0; rt && !(rt->rt6i_flags & RTF_EXPIRES); - rt = (struct rt6_info *)rt->dst.from); - if (rt && rt != rt0) - rt0->dst.expires = rt->dst.expires; - - dst_set_expires(&rt0->dst, timeout); - rt0->rt6i_flags |= RTF_EXPIRES; -} - -static inline u32 rt6_get_cookie(const struct rt6_info *rt) -{ - if (rt->rt6i_flags & RTF_PCPU || - (unlikely(rt->dst.flags & DST_NOCACHE) && rt->dst.from)) - rt = (struct rt6_info *)(rt->dst.from); - - return rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; -} - -static inline void ip6_rt_put(struct rt6_info *rt) -{ - /* dst_release() accepts a NULL parameter. - * We rely on dst being first structure in struct rt6_info - */ - BUILD_BUG_ON(offsetof(struct rt6_info, dst) != 0); - dst_release(&rt->dst); -} - -enum fib6_walk_state { -#ifdef CONFIG_IPV6_SUBTREES - FWS_S, -#endif - FWS_L, - FWS_R, - FWS_C, - FWS_U -}; - -struct fib6_walker { - struct list_head lh; - struct fib6_node *root, *node; - struct rt6_info *leaf; - enum fib6_walk_state state; - bool prune; - unsigned int skip; - unsigned int count; - int (*func)(struct fib6_walker *); - void *args; -}; - -struct rt6_statistics { - __u32 fib_nodes; - __u32 fib_route_nodes; - __u32 fib_rt_alloc; /* permanent routes */ - __u32 fib_rt_entries; /* rt entries in table */ - __u32 fib_rt_cache; /* cache routes */ - __u32 fib_discarded_routes; -}; - -#define RTN_TL_ROOT 0x0001 -#define RTN_ROOT 0x0002 /* tree root node */ -#define RTN_RTINFO 0x0004 /* node with valid routing info */ - -/* - * priority levels (or metrics) - * - */ - - -struct fib6_table { - struct hlist_node tb6_hlist; - u32 tb6_id; - rwlock_t tb6_lock; - struct fib6_node tb6_root; - struct inet_peer_base tb6_peers; - unsigned int flags; -#define RT6_TABLE_HAS_DFLT_ROUTER BIT(0) -}; - -#define RT6_TABLE_UNSPEC RT_TABLE_UNSPEC -#define RT6_TABLE_MAIN RT_TABLE_MAIN -#define RT6_TABLE_DFLT RT6_TABLE_MAIN -#define RT6_TABLE_INFO RT6_TABLE_MAIN -#define RT6_TABLE_PREFIX RT6_TABLE_MAIN - -#ifdef CONFIG_IPV6_MULTIPLE_TABLES -#define FIB6_TABLE_MIN 1 -#define FIB6_TABLE_MAX RT_TABLE_MAX -#define RT6_TABLE_LOCAL RT_TABLE_LOCAL -#else -#define FIB6_TABLE_MIN RT_TABLE_MAIN -#define FIB6_TABLE_MAX FIB6_TABLE_MIN -#define RT6_TABLE_LOCAL RT6_TABLE_MAIN -#endif - -typedef struct rt6_info *(*pol_lookup_t)(struct net *, - struct fib6_table *, - struct flowi6 *, int); - -/* - * exported functions - */ - -struct fib6_table *fib6_get_table(struct net *net, u32 id); -struct fib6_table *fib6_new_table(struct net *net, u32 id); -struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, - int flags, pol_lookup_t lookup); - -struct fib6_node *fib6_lookup(struct fib6_node *root, - const struct in6_addr *daddr, - const struct in6_addr *saddr); - -struct fib6_node *fib6_locate(struct fib6_node *root, - const struct in6_addr *daddr, int dst_len, - const struct in6_addr *saddr, int src_len); - -void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *arg), - void *arg); - -int fib6_add(struct fib6_node *root, struct rt6_info *rt, - struct nl_info *info, struct mx6_config *mxc); -int fib6_del(struct rt6_info *rt, struct nl_info *info); - -void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info, - unsigned int flags); - -void fib6_run_gc(unsigned long expires, struct net *net, bool force); - -void fib6_gc_cleanup(void); - -int fib6_init(void); - -int ipv6_route_open(struct inode *inode, struct file *file); - -#ifdef CONFIG_IPV6_MULTIPLE_TABLES -int fib6_rules_init(void); -void fib6_rules_cleanup(void); -#else -static inline int fib6_rules_init(void) -{ - return 0; -} -static inline void fib6_rules_cleanup(void) -{ - return ; -} -#endif -#endif diff --git a/src/linux/include/net/ip6_route.h b/src/linux/include/net/ip6_route.h deleted file mode 100644 index f83e78d..0000000 --- a/src/linux/include/net/ip6_route.h +++ /dev/null @@ -1,234 +0,0 @@ -#ifndef _NET_IP6_ROUTE_H -#define _NET_IP6_ROUTE_H - -struct route_info { - __u8 type; - __u8 length; - __u8 prefix_len; -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 reserved_h:3, - route_pref:2, - reserved_l:3; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 reserved_l:3, - route_pref:2, - reserved_h:3; -#endif - __be32 lifetime; - __u8 prefix[0]; /* 0,8 or 16 */ -}; - -#include -#include -#include -#include -#include -#include -#include - -#define RT6_LOOKUP_F_IFACE 0x00000001 -#define RT6_LOOKUP_F_REACHABLE 0x00000002 -#define RT6_LOOKUP_F_HAS_SADDR 0x00000004 -#define RT6_LOOKUP_F_SRCPREF_TMP 0x00000008 -#define RT6_LOOKUP_F_SRCPREF_PUBLIC 0x00000010 -#define RT6_LOOKUP_F_SRCPREF_COA 0x00000020 -#define RT6_LOOKUP_F_IGNORE_LINKSTATE 0x00000040 - -/* We do not (yet ?) support IPv6 jumbograms (RFC 2675) - * Unlike IPv4, hdr->seg_len doesn't include the IPv6 header - */ -#define IP6_MAX_MTU (0xFFFF + sizeof(struct ipv6hdr)) - -/* - * rt6_srcprefs2flags() and rt6_flags2srcprefs() translate - * between IPV6_ADDR_PREFERENCES socket option values - * IPV6_PREFER_SRC_TMP = 0x1 - * IPV6_PREFER_SRC_PUBLIC = 0x2 - * IPV6_PREFER_SRC_COA = 0x4 - * and above RT6_LOOKUP_F_SRCPREF_xxx flags. - */ -static inline int rt6_srcprefs2flags(unsigned int srcprefs) -{ - /* No need to bitmask because srcprefs have only 3 bits. */ - return srcprefs << 3; -} - -static inline unsigned int rt6_flags2srcprefs(int flags) -{ - return (flags >> 3) & 7; -} - -static inline bool rt6_need_strict(const struct in6_addr *daddr) -{ - return ipv6_addr_type(daddr) & - (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK); -} - -void ip6_route_input(struct sk_buff *skb); -struct dst_entry *ip6_route_input_lookup(struct net *net, - struct net_device *dev, - struct flowi6 *fl6, int flags); - -struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk, - struct flowi6 *fl6, int flags); - -static inline struct dst_entry *ip6_route_output(struct net *net, - const struct sock *sk, - struct flowi6 *fl6) -{ - return ip6_route_output_flags(net, sk, fl6, 0); -} - -struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6, - int flags); -struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, - int ifindex, struct flowi6 *fl6, int flags); - -int ip6_route_init(void); -void ip6_route_cleanup(void); - -int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg); - -int ip6_route_add(struct fib6_config *cfg); -int ip6_ins_rt(struct rt6_info *); -int ip6_del_rt(struct rt6_info *); - -static inline int ip6_route_get_saddr(struct net *net, struct rt6_info *rt, - const struct in6_addr *daddr, - unsigned int prefs, - struct in6_addr *saddr) -{ - struct inet6_dev *idev = - rt ? ip6_dst_idev((struct dst_entry *)rt) : NULL; - int err = 0; - - if (rt && rt->rt6i_prefsrc.plen) - *saddr = rt->rt6i_prefsrc.addr; - else - err = ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, - daddr, prefs, saddr); - - return err; -} - -struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr, - const struct in6_addr *saddr, int oif, int flags); - -struct dst_entry *icmp6_dst_alloc(struct net_device *dev, struct flowi6 *fl6); -int icmp6_dst_gc(void); - -void fib6_force_start_gc(struct net *net); - -struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, - const struct in6_addr *addr, bool anycast); - -struct rt6_info *ip6_dst_alloc(struct net *net, struct net_device *dev, - int flags); - -/* - * support functions for ND - * - */ -struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, - struct net_device *dev); -struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr, - struct net_device *dev, unsigned int pref); - -void rt6_purge_dflt_routers(struct net *net); - -int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, - const struct in6_addr *gwaddr); - -void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, int oif, - u32 mark); -void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu); -void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark); -void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif, - u32 mark); -void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk); - -struct netlink_callback; - -struct rt6_rtnl_dump_arg { - struct sk_buff *skb; - struct netlink_callback *cb; - struct net *net; -}; - -int rt6_dump_route(struct rt6_info *rt, void *p_arg); -void rt6_ifdown(struct net *net, struct net_device *dev); -void rt6_mtu_change(struct net_device *dev, unsigned int mtu); -void rt6_remove_prefsrc(struct inet6_ifaddr *ifp); -void rt6_clean_tohost(struct net *net, struct in6_addr *gateway); - - -/* - * Store a destination cache entry in a socket - */ -static inline void ip6_dst_store(struct sock *sk, struct dst_entry *dst, - const struct in6_addr *daddr, - const struct in6_addr *saddr) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - - np->dst_cookie = rt6_get_cookie((struct rt6_info *)dst); - sk_setup_caps(sk, dst); - np->daddr_cache = daddr; -#ifdef CONFIG_IPV6_SUBTREES - np->saddr_cache = saddr; -#endif -} - -static inline bool ipv6_unicast_destination(const struct sk_buff *skb) -{ - struct rt6_info *rt = (struct rt6_info *) skb_dst(skb); - - return rt->rt6i_flags & RTF_LOCAL; -} - -static inline bool ipv6_anycast_destination(const struct dst_entry *dst, - const struct in6_addr *daddr) -{ - struct rt6_info *rt = (struct rt6_info *)dst; - - return rt->rt6i_flags & RTF_ANYCAST || - (rt->rt6i_dst.plen != 128 && - ipv6_addr_equal(&rt->rt6i_dst.addr, daddr)); -} - -int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, - int (*output)(struct net *, struct sock *, struct sk_buff *)); - -static inline int ip6_skb_dst_mtu(struct sk_buff *skb) -{ - struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ? - inet6_sk(skb->sk) : NULL; - - return (np && np->pmtudisc >= IPV6_PMTUDISC_PROBE) ? - skb_dst(skb)->dev->mtu : dst_mtu(skb_dst(skb)); -} - -static inline bool ip6_sk_accept_pmtu(const struct sock *sk) -{ - return inet6_sk(sk)->pmtudisc != IPV6_PMTUDISC_INTERFACE && - inet6_sk(sk)->pmtudisc != IPV6_PMTUDISC_OMIT; -} - -static inline bool ip6_sk_ignore_df(const struct sock *sk) -{ - return inet6_sk(sk)->pmtudisc < IPV6_PMTUDISC_DO || - inet6_sk(sk)->pmtudisc == IPV6_PMTUDISC_OMIT; -} - -static inline struct in6_addr *rt6_nexthop(struct rt6_info *rt, - struct in6_addr *daddr) -{ - if (rt->rt6i_flags & RTF_GATEWAY) - return &rt->rt6i_gateway; - else if (unlikely(rt->rt6i_flags & RTF_CACHE)) - return &rt->rt6i_dst.addr; - else - return daddr; -} - -#endif diff --git a/src/linux/include/net/ip6_tunnel.h b/src/linux/include/net/ip6_tunnel.h deleted file mode 100644 index 1b1cf33..0000000 --- a/src/linux/include/net/ip6_tunnel.h +++ /dev/null @@ -1,157 +0,0 @@ -#ifndef _NET_IP6_TUNNEL_H -#define _NET_IP6_TUNNEL_H - -#include -#include -#include -#include -#include -#include - -#define IP6TUNNEL_ERR_TIMEO (30*HZ) - -/* capable of sending packets */ -#define IP6_TNL_F_CAP_XMIT 0x10000 -/* capable of receiving packets */ -#define IP6_TNL_F_CAP_RCV 0x20000 -/* determine capability on a per-packet basis */ -#define IP6_TNL_F_CAP_PER_PACKET 0x40000 - -struct __ip6_tnl_parm { - char name[IFNAMSIZ]; /* name of tunnel device */ - int link; /* ifindex of underlying L2 interface */ - __u8 proto; /* tunnel protocol */ - __u8 encap_limit; /* encapsulation limit for tunnel */ - __u8 hop_limit; /* hop limit for tunnel */ - bool collect_md; - __be32 flowinfo; /* traffic class and flowlabel for tunnel */ - __u32 flags; /* tunnel flags */ - struct in6_addr laddr; /* local tunnel end-point address */ - struct in6_addr raddr; /* remote tunnel end-point address */ - - __be16 i_flags; - __be16 o_flags; - __be32 i_key; - __be32 o_key; -}; - -/* IPv6 tunnel */ -struct ip6_tnl { - struct ip6_tnl __rcu *next; /* next tunnel in list */ - struct net_device *dev; /* virtual device associated with tunnel */ - struct net *net; /* netns for packet i/o */ - struct __ip6_tnl_parm parms; /* tunnel configuration parameters */ - struct flowi fl; /* flowi template for xmit */ - struct dst_cache dst_cache; /* cached dst */ - struct gro_cells gro_cells; - - int err_count; - unsigned long err_time; - - /* These fields used only by GRE */ - __u32 i_seqno; /* The last seen seqno */ - __u32 o_seqno; /* The last output seqno */ - int hlen; /* tun_hlen + encap_hlen */ - int tun_hlen; /* Precalculated header length */ - int encap_hlen; /* Encap header length (FOU,GUE) */ - struct ip_tunnel_encap encap; - int mlink; -}; - -struct ip6_tnl_encap_ops { - size_t (*encap_hlen)(struct ip_tunnel_encap *e); - int (*build_header)(struct sk_buff *skb, struct ip_tunnel_encap *e, - u8 *protocol, struct flowi6 *fl6); -}; - -#ifdef CONFIG_INET - -extern const struct ip6_tnl_encap_ops __rcu * - ip6tun_encaps[MAX_IPTUN_ENCAP_OPS]; - -int ip6_tnl_encap_add_ops(const struct ip6_tnl_encap_ops *ops, - unsigned int num); -int ip6_tnl_encap_del_ops(const struct ip6_tnl_encap_ops *ops, - unsigned int num); -int ip6_tnl_encap_setup(struct ip6_tnl *t, - struct ip_tunnel_encap *ipencap); - -static inline int ip6_encap_hlen(struct ip_tunnel_encap *e) -{ - const struct ip6_tnl_encap_ops *ops; - int hlen = -EINVAL; - - if (e->type == TUNNEL_ENCAP_NONE) - return 0; - - if (e->type >= MAX_IPTUN_ENCAP_OPS) - return -EINVAL; - - rcu_read_lock(); - ops = rcu_dereference(ip6tun_encaps[e->type]); - if (likely(ops && ops->encap_hlen)) - hlen = ops->encap_hlen(e); - rcu_read_unlock(); - - return hlen; -} - -static inline int ip6_tnl_encap(struct sk_buff *skb, struct ip6_tnl *t, - u8 *protocol, struct flowi6 *fl6) -{ - const struct ip6_tnl_encap_ops *ops; - int ret = -EINVAL; - - if (t->encap.type == TUNNEL_ENCAP_NONE) - return 0; - - if (t->encap.type >= MAX_IPTUN_ENCAP_OPS) - return -EINVAL; - - rcu_read_lock(); - ops = rcu_dereference(ip6tun_encaps[t->encap.type]); - if (likely(ops && ops->build_header)) - ret = ops->build_header(skb, &t->encap, protocol, fl6); - rcu_read_unlock(); - - return ret; -} - -/* Tunnel encapsulation limit destination sub-option */ - -struct ipv6_tlv_tnl_enc_lim { - __u8 type; /* type-code for option */ - __u8 length; /* option length */ - __u8 encap_limit; /* tunnel encapsulation limit */ -} __packed; - -int ip6_tnl_rcv_ctl(struct ip6_tnl *t, const struct in6_addr *laddr, - const struct in6_addr *raddr); -int ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, - const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst, - bool log_ecn_error); -int ip6_tnl_xmit_ctl(struct ip6_tnl *t, const struct in6_addr *laddr, - const struct in6_addr *raddr); -int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield, - struct flowi6 *fl6, int encap_limit, __u32 *pmtu, __u8 proto); -__u16 ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw); -__u32 ip6_tnl_get_cap(struct ip6_tnl *t, const struct in6_addr *laddr, - const struct in6_addr *raddr); -struct net *ip6_tnl_get_link_net(const struct net_device *dev); -int ip6_tnl_get_iflink(const struct net_device *dev); -int ip6_tnl_change_mtu(struct net_device *dev, int new_mtu); - -static inline void ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb, - struct net_device *dev) -{ - int pkt_len, err; - - memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); - pkt_len = skb->len - skb_inner_network_offset(skb); - err = ip6_local_out(dev_net(skb_dst(skb)->dev), sk, skb); - if (unlikely(net_xmit_eval(err))) - pkt_len = -1; - iptunnel_xmit_stats(dev, pkt_len); -} -#endif -#endif diff --git a/src/linux/include/net/ip_fib.h b/src/linux/include/net/ip_fib.h deleted file mode 100644 index f390c3b..0000000 --- a/src/linux/include/net/ip_fib.h +++ /dev/null @@ -1,419 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the Forwarding Information Base. - * - * Authors: A.N.Kuznetsov, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _NET_IP_FIB_H -#define _NET_IP_FIB_H - -#include -#include -#include -#include -#include -#include -#include - -struct fib_config { - u8 fc_dst_len; - u8 fc_tos; - u8 fc_protocol; - u8 fc_scope; - u8 fc_type; - /* 3 bytes unused */ - u32 fc_table; - __be32 fc_dst; - __be32 fc_gw; - int fc_oif; - u32 fc_flags; - u32 fc_priority; - __be32 fc_prefsrc; - struct nlattr *fc_mx; - struct rtnexthop *fc_mp; - int fc_mx_len; - int fc_mp_len; - u32 fc_flow; - u32 fc_nlflags; - struct nl_info fc_nlinfo; - struct nlattr *fc_encap; - u16 fc_encap_type; -}; - -struct fib_info; -struct rtable; - -struct fib_nh_exception { - struct fib_nh_exception __rcu *fnhe_next; - int fnhe_genid; - __be32 fnhe_daddr; - u32 fnhe_pmtu; - __be32 fnhe_gw; - unsigned long fnhe_expires; - struct rtable __rcu *fnhe_rth_input; - struct rtable __rcu *fnhe_rth_output; - unsigned long fnhe_stamp; - struct rcu_head rcu; -}; - -struct fnhe_hash_bucket { - struct fib_nh_exception __rcu *chain; -}; - -#define FNHE_HASH_SHIFT 11 -#define FNHE_HASH_SIZE (1 << FNHE_HASH_SHIFT) -#define FNHE_RECLAIM_DEPTH 5 - -struct fib_nh { - struct net_device *nh_dev; - struct hlist_node nh_hash; - struct fib_info *nh_parent; - unsigned int nh_flags; - unsigned char nh_scope; -#ifdef CONFIG_IP_ROUTE_MULTIPATH - int nh_weight; - atomic_t nh_upper_bound; -#endif -#ifdef CONFIG_IP_ROUTE_CLASSID - __u32 nh_tclassid; -#endif - int nh_oif; - __be32 nh_gw; - __be32 nh_saddr; - int nh_saddr_genid; - struct rtable __rcu * __percpu *nh_pcpu_rth_output; - struct rtable __rcu *nh_rth_input; - struct fnhe_hash_bucket __rcu *nh_exceptions; - struct lwtunnel_state *nh_lwtstate; -}; - -/* - * This structure contains data shared by many of routes. - */ - -struct fib_info { - struct hlist_node fib_hash; - struct hlist_node fib_lhash; - struct net *fib_net; - int fib_treeref; - atomic_t fib_clntref; - unsigned int fib_flags; - unsigned char fib_dead; - unsigned char fib_protocol; - unsigned char fib_scope; - unsigned char fib_type; - __be32 fib_prefsrc; - u32 fib_tb_id; - u32 fib_priority; - u32 *fib_metrics; -#define fib_mtu fib_metrics[RTAX_MTU-1] -#define fib_window fib_metrics[RTAX_WINDOW-1] -#define fib_rtt fib_metrics[RTAX_RTT-1] -#define fib_advmss fib_metrics[RTAX_ADVMSS-1] - int fib_nhs; -#ifdef CONFIG_IP_ROUTE_MULTIPATH - int fib_weight; -#endif - unsigned int fib_offload_cnt; - struct rcu_head rcu; - struct fib_nh fib_nh[0]; -#define fib_dev fib_nh[0].nh_dev -}; - - -#ifdef CONFIG_IP_MULTIPLE_TABLES -struct fib_rule; -#endif - -struct fib_table; -struct fib_result { - unsigned char prefixlen; - unsigned char nh_sel; - unsigned char type; - unsigned char scope; - u32 tclassid; - struct fib_info *fi; - struct fib_table *table; - struct hlist_head *fa_head; -}; - -struct fib_result_nl { - __be32 fl_addr; /* To be looked up*/ - u32 fl_mark; - unsigned char fl_tos; - unsigned char fl_scope; - unsigned char tb_id_in; - - unsigned char tb_id; /* Results */ - unsigned char prefixlen; - unsigned char nh_sel; - unsigned char type; - unsigned char scope; - int err; -}; - -#ifdef CONFIG_IP_ROUTE_MULTIPATH -#define FIB_RES_NH(res) ((res).fi->fib_nh[(res).nh_sel]) -#else /* CONFIG_IP_ROUTE_MULTIPATH */ -#define FIB_RES_NH(res) ((res).fi->fib_nh[0]) -#endif /* CONFIG_IP_ROUTE_MULTIPATH */ - -#ifdef CONFIG_IP_MULTIPLE_TABLES -#define FIB_TABLE_HASHSZ 256 -#else -#define FIB_TABLE_HASHSZ 2 -#endif - -__be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh); - -static inline void fib_info_offload_inc(struct fib_info *fi) -{ - fi->fib_offload_cnt++; - fi->fib_flags |= RTNH_F_OFFLOAD; -} - -static inline void fib_info_offload_dec(struct fib_info *fi) -{ - if (--fi->fib_offload_cnt == 0) - fi->fib_flags &= ~RTNH_F_OFFLOAD; -} - -#define FIB_RES_SADDR(net, res) \ - ((FIB_RES_NH(res).nh_saddr_genid == \ - atomic_read(&(net)->ipv4.dev_addr_genid)) ? \ - FIB_RES_NH(res).nh_saddr : \ - fib_info_update_nh_saddr((net), &FIB_RES_NH(res))) -#define FIB_RES_GW(res) (FIB_RES_NH(res).nh_gw) -#define FIB_RES_DEV(res) (FIB_RES_NH(res).nh_dev) -#define FIB_RES_OIF(res) (FIB_RES_NH(res).nh_oif) - -#define FIB_RES_PREFSRC(net, res) ((res).fi->fib_prefsrc ? : \ - FIB_RES_SADDR(net, res)) - -struct fib_notifier_info { - struct net *net; -}; - -struct fib_entry_notifier_info { - struct fib_notifier_info info; /* must be first */ - u32 dst; - int dst_len; - struct fib_info *fi; - u8 tos; - u8 type; - u32 tb_id; - u32 nlflags; -}; - -enum fib_event_type { - FIB_EVENT_ENTRY_ADD, - FIB_EVENT_ENTRY_DEL, - FIB_EVENT_RULE_ADD, - FIB_EVENT_RULE_DEL, -}; - -int register_fib_notifier(struct notifier_block *nb); -int unregister_fib_notifier(struct notifier_block *nb); -int call_fib_notifiers(struct net *net, enum fib_event_type event_type, - struct fib_notifier_info *info); - -struct fib_table { - struct hlist_node tb_hlist; - u32 tb_id; - int tb_num_default; - struct rcu_head rcu; - unsigned long *tb_data; - unsigned long __data[0]; -}; - -int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, - struct fib_result *res, int fib_flags); -int fib_table_insert(struct net *, struct fib_table *, struct fib_config *); -int fib_table_delete(struct net *, struct fib_table *, struct fib_config *); -int fib_table_dump(struct fib_table *table, struct sk_buff *skb, - struct netlink_callback *cb); -int fib_table_flush(struct net *net, struct fib_table *table); -struct fib_table *fib_trie_unmerge(struct fib_table *main_tb); -void fib_table_flush_external(struct fib_table *table); -void fib_free_table(struct fib_table *tb); - -#ifndef CONFIG_IP_MULTIPLE_TABLES - -#define TABLE_LOCAL_INDEX (RT_TABLE_LOCAL & (FIB_TABLE_HASHSZ - 1)) -#define TABLE_MAIN_INDEX (RT_TABLE_MAIN & (FIB_TABLE_HASHSZ - 1)) - -static inline struct fib_table *fib_get_table(struct net *net, u32 id) -{ - struct hlist_node *tb_hlist; - struct hlist_head *ptr; - - ptr = id == RT_TABLE_LOCAL ? - &net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX] : - &net->ipv4.fib_table_hash[TABLE_MAIN_INDEX]; - - tb_hlist = rcu_dereference_rtnl(hlist_first_rcu(ptr)); - - return hlist_entry(tb_hlist, struct fib_table, tb_hlist); -} - -static inline struct fib_table *fib_new_table(struct net *net, u32 id) -{ - return fib_get_table(net, id); -} - -static inline int fib_lookup(struct net *net, const struct flowi4 *flp, - struct fib_result *res, unsigned int flags) -{ - struct fib_table *tb; - int err = -ENETUNREACH; - - rcu_read_lock(); - - tb = fib_get_table(net, RT_TABLE_MAIN); - if (tb) - err = fib_table_lookup(tb, flp, res, flags | FIB_LOOKUP_NOREF); - - if (err == -EAGAIN) - err = -ENETUNREACH; - - rcu_read_unlock(); - - return err; -} - -#else /* CONFIG_IP_MULTIPLE_TABLES */ -int __net_init fib4_rules_init(struct net *net); -void __net_exit fib4_rules_exit(struct net *net); - -struct fib_table *fib_new_table(struct net *net, u32 id); -struct fib_table *fib_get_table(struct net *net, u32 id); - -int __fib_lookup(struct net *net, struct flowi4 *flp, - struct fib_result *res, unsigned int flags); - -static inline int fib_lookup(struct net *net, struct flowi4 *flp, - struct fib_result *res, unsigned int flags) -{ - struct fib_table *tb; - int err = -ENETUNREACH; - - flags |= FIB_LOOKUP_NOREF; - if (net->ipv4.fib_has_custom_rules) - return __fib_lookup(net, flp, res, flags); - - rcu_read_lock(); - - res->tclassid = 0; - - tb = rcu_dereference_rtnl(net->ipv4.fib_main); - if (tb) - err = fib_table_lookup(tb, flp, res, flags); - - if (!err) - goto out; - - tb = rcu_dereference_rtnl(net->ipv4.fib_default); - if (tb) - err = fib_table_lookup(tb, flp, res, flags); - -out: - if (err == -EAGAIN) - err = -ENETUNREACH; - - rcu_read_unlock(); - - return err; -} - -#endif /* CONFIG_IP_MULTIPLE_TABLES */ - -/* Exported by fib_frontend.c */ -extern const struct nla_policy rtm_ipv4_policy[]; -void ip_fib_init(void); -__be32 fib_compute_spec_dst(struct sk_buff *skb); -int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, - u8 tos, int oif, struct net_device *dev, - struct in_device *idev, u32 *itag); -void fib_select_default(const struct flowi4 *flp, struct fib_result *res); -#ifdef CONFIG_IP_ROUTE_CLASSID -static inline int fib_num_tclassid_users(struct net *net) -{ - return net->ipv4.fib_num_tclassid_users; -} -#else -static inline int fib_num_tclassid_users(struct net *net) -{ - return 0; -} -#endif -int fib_unmerge(struct net *net); - -/* Exported by fib_semantics.c */ -int ip_fib_check_default(__be32 gw, struct net_device *dev); -int fib_sync_down_dev(struct net_device *dev, unsigned long event, bool force); -int fib_sync_down_addr(struct net_device *dev, __be32 local); -int fib_sync_up(struct net_device *dev, unsigned int nh_flags); - -extern u32 fib_multipath_secret __read_mostly; - -static inline int fib_multipath_hash(__be32 saddr, __be32 daddr) -{ - return jhash_2words((__force u32)saddr, (__force u32)daddr, - fib_multipath_secret) >> 1; -} - -void fib_select_multipath(struct fib_result *res, int hash); -void fib_select_path(struct net *net, struct fib_result *res, - struct flowi4 *fl4, int mp_hash); - -/* Exported by fib_trie.c */ -void fib_trie_init(void); -struct fib_table *fib_trie_table(u32 id, struct fib_table *alias); - -static inline void fib_combine_itag(u32 *itag, const struct fib_result *res) -{ -#ifdef CONFIG_IP_ROUTE_CLASSID -#ifdef CONFIG_IP_MULTIPLE_TABLES - u32 rtag; -#endif - *itag = FIB_RES_NH(*res).nh_tclassid<<16; -#ifdef CONFIG_IP_MULTIPLE_TABLES - rtag = res->tclassid; - if (*itag == 0) - *itag = (rtag<<16); - *itag |= (rtag>>16); -#endif -#endif -} - -void free_fib_info(struct fib_info *fi); - -static inline void fib_info_put(struct fib_info *fi) -{ - if (atomic_dec_and_test(&fi->fib_clntref)) - free_fib_info(fi); -} - -#ifdef CONFIG_PROC_FS -int __net_init fib_proc_init(struct net *net); -void __net_exit fib_proc_exit(struct net *net); -#else -static inline int fib_proc_init(struct net *net) -{ - return 0; -} -static inline void fib_proc_exit(struct net *net) -{ -} -#endif - -#endif /* _NET_FIB_H */ diff --git a/src/linux/include/net/ip_tunnels.h b/src/linux/include/net/ip_tunnels.h deleted file mode 100644 index 59557c0..0000000 --- a/src/linux/include/net/ip_tunnels.h +++ /dev/null @@ -1,480 +0,0 @@ -#ifndef __NET_IP_TUNNELS_H -#define __NET_IP_TUNNELS_H 1 - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#if IS_ENABLED(CONFIG_IPV6) -#include -#include -#include -#endif - -/* Keep error state on tunnel for 30 sec */ -#define IPTUNNEL_ERR_TIMEO (30*HZ) - -/* Used to memset ip_tunnel padding. */ -#define IP_TUNNEL_KEY_SIZE offsetofend(struct ip_tunnel_key, tp_dst) - -/* Used to memset ipv4 address padding. */ -#define IP_TUNNEL_KEY_IPV4_PAD offsetofend(struct ip_tunnel_key, u.ipv4.dst) -#define IP_TUNNEL_KEY_IPV4_PAD_LEN \ - (FIELD_SIZEOF(struct ip_tunnel_key, u) - \ - FIELD_SIZEOF(struct ip_tunnel_key, u.ipv4)) - -struct ip_tunnel_key { - __be64 tun_id; - union { - struct { - __be32 src; - __be32 dst; - } ipv4; - struct { - struct in6_addr src; - struct in6_addr dst; - } ipv6; - } u; - __be16 tun_flags; - u8 tos; /* TOS for IPv4, TC for IPv6 */ - u8 ttl; /* TTL for IPv4, HL for IPv6 */ - __be32 label; /* Flow Label for IPv6 */ - __be16 tp_src; - __be16 tp_dst; -}; - -/* Flags for ip_tunnel_info mode. */ -#define IP_TUNNEL_INFO_TX 0x01 /* represents tx tunnel parameters */ -#define IP_TUNNEL_INFO_IPV6 0x02 /* key contains IPv6 addresses */ - -/* Maximum tunnel options length. */ -#define IP_TUNNEL_OPTS_MAX \ - GENMASK((FIELD_SIZEOF(struct ip_tunnel_info, \ - options_len) * BITS_PER_BYTE) - 1, 0) - -struct ip_tunnel_info { - struct ip_tunnel_key key; -#ifdef CONFIG_DST_CACHE - struct dst_cache dst_cache; -#endif - u8 options_len; - u8 mode; -}; - -/* 6rd prefix/relay information */ -#ifdef CONFIG_IPV6_SIT_6RD -struct ip_tunnel_6rd_parm { - struct in6_addr prefix; - __be32 relay_prefix; - u16 prefixlen; - u16 relay_prefixlen; -}; -#endif - -struct ip_tunnel_encap { - u16 type; - u16 flags; - __be16 sport; - __be16 dport; -}; - -struct ip_tunnel_prl_entry { - struct ip_tunnel_prl_entry __rcu *next; - __be32 addr; - u16 flags; - struct rcu_head rcu_head; -}; - -struct metadata_dst; - -struct ip_tunnel { - struct ip_tunnel __rcu *next; - struct hlist_node hash_node; - struct net_device *dev; - struct net *net; /* netns for packet i/o */ - - unsigned long err_time; /* Time when the last ICMP error - * arrived */ - int err_count; /* Number of arrived ICMP errors */ - - /* These four fields used only by GRE */ - u32 i_seqno; /* The last seen seqno */ - u32 o_seqno; /* The last output seqno */ - int tun_hlen; /* Precalculated header length */ - - struct dst_cache dst_cache; - - struct ip_tunnel_parm parms; - - int mlink; - int encap_hlen; /* Encap header length (FOU,GUE) */ - int hlen; /* tun_hlen + encap_hlen */ - struct ip_tunnel_encap encap; - - /* for SIT */ -#ifdef CONFIG_IPV6_SIT_6RD - struct ip_tunnel_6rd_parm ip6rd; -#endif - struct ip_tunnel_prl_entry __rcu *prl; /* potential router list */ - unsigned int prl_count; /* # of entries in PRL */ - int ip_tnl_net_id; - struct gro_cells gro_cells; - bool collect_md; - bool ignore_df; -}; - -#define TUNNEL_CSUM __cpu_to_be16(0x01) -#define TUNNEL_ROUTING __cpu_to_be16(0x02) -#define TUNNEL_KEY __cpu_to_be16(0x04) -#define TUNNEL_SEQ __cpu_to_be16(0x08) -#define TUNNEL_STRICT __cpu_to_be16(0x10) -#define TUNNEL_REC __cpu_to_be16(0x20) -#define TUNNEL_VERSION __cpu_to_be16(0x40) -#define TUNNEL_NO_KEY __cpu_to_be16(0x80) -#define TUNNEL_DONT_FRAGMENT __cpu_to_be16(0x0100) -#define TUNNEL_OAM __cpu_to_be16(0x0200) -#define TUNNEL_CRIT_OPT __cpu_to_be16(0x0400) -#define TUNNEL_GENEVE_OPT __cpu_to_be16(0x0800) -#define TUNNEL_VXLAN_OPT __cpu_to_be16(0x1000) -#define TUNNEL_NOCACHE __cpu_to_be16(0x2000) - -#define TUNNEL_OPTIONS_PRESENT (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT) - -struct tnl_ptk_info { - __be16 flags; - __be16 proto; - __be32 key; - __be32 seq; - int hdr_len; -}; - -#define PACKET_RCVD 0 -#define PACKET_REJECT 1 -#define PACKET_NEXT 2 - -#define IP_TNL_HASH_BITS 7 -#define IP_TNL_HASH_SIZE (1 << IP_TNL_HASH_BITS) - -struct ip_tunnel_net { - struct net_device *fb_tunnel_dev; - struct hlist_head tunnels[IP_TNL_HASH_SIZE]; - struct ip_tunnel __rcu *collect_md_tun; -}; - -static inline void ip_tunnel_key_init(struct ip_tunnel_key *key, - __be32 saddr, __be32 daddr, - u8 tos, u8 ttl, __be32 label, - __be16 tp_src, __be16 tp_dst, - __be64 tun_id, __be16 tun_flags) -{ - key->tun_id = tun_id; - key->u.ipv4.src = saddr; - key->u.ipv4.dst = daddr; - memset((unsigned char *)key + IP_TUNNEL_KEY_IPV4_PAD, - 0, IP_TUNNEL_KEY_IPV4_PAD_LEN); - key->tos = tos; - key->ttl = ttl; - key->label = label; - key->tun_flags = tun_flags; - - /* For the tunnel types on the top of IPsec, the tp_src and tp_dst of - * the upper tunnel are used. - * E.g: GRE over IPSEC, the tp_src and tp_port are zero. - */ - key->tp_src = tp_src; - key->tp_dst = tp_dst; - - /* Clear struct padding. */ - if (sizeof(*key) != IP_TUNNEL_KEY_SIZE) - memset((unsigned char *)key + IP_TUNNEL_KEY_SIZE, - 0, sizeof(*key) - IP_TUNNEL_KEY_SIZE); -} - -static inline bool -ip_tunnel_dst_cache_usable(const struct sk_buff *skb, - const struct ip_tunnel_info *info) -{ - if (skb->mark) - return false; - if (!info) - return true; - if (info->key.tun_flags & TUNNEL_NOCACHE) - return false; - - return true; -} - -static inline unsigned short ip_tunnel_info_af(const struct ip_tunnel_info - *tun_info) -{ - return tun_info->mode & IP_TUNNEL_INFO_IPV6 ? AF_INET6 : AF_INET; -} - -static inline __be64 key32_to_tunnel_id(__be32 key) -{ -#ifdef __BIG_ENDIAN - return (__force __be64)key; -#else - return (__force __be64)((__force u64)key << 32); -#endif -} - -/* Returns the least-significant 32 bits of a __be64. */ -static inline __be32 tunnel_id_to_key32(__be64 tun_id) -{ -#ifdef __BIG_ENDIAN - return (__force __be32)tun_id; -#else - return (__force __be32)((__force u64)tun_id >> 32); -#endif -} - -#ifdef CONFIG_INET - -int ip_tunnel_init(struct net_device *dev); -void ip_tunnel_uninit(struct net_device *dev); -void ip_tunnel_dellink(struct net_device *dev, struct list_head *head); -struct net *ip_tunnel_get_link_net(const struct net_device *dev); -int ip_tunnel_get_iflink(const struct net_device *dev); -int ip_tunnel_init_net(struct net *net, int ip_tnl_net_id, - struct rtnl_link_ops *ops, char *devname); - -void ip_tunnel_delete_net(struct ip_tunnel_net *itn, struct rtnl_link_ops *ops); - -void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, - const struct iphdr *tnl_params, const u8 protocol); -void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, - const u8 proto); -int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd); -int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict); -int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu); - -struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev, - struct rtnl_link_stats64 *tot); -struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, - int link, __be16 flags, - __be32 remote, __be32 local, - __be32 key); - -int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb, - const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst, - bool log_ecn_error); -int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[], - struct ip_tunnel_parm *p); -int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[], - struct ip_tunnel_parm *p); -void ip_tunnel_setup(struct net_device *dev, int net_id); - -struct ip_tunnel_encap_ops { - size_t (*encap_hlen)(struct ip_tunnel_encap *e); - int (*build_header)(struct sk_buff *skb, struct ip_tunnel_encap *e, - u8 *protocol, struct flowi4 *fl4); -}; - -#define MAX_IPTUN_ENCAP_OPS 8 - -extern const struct ip_tunnel_encap_ops __rcu * - iptun_encaps[MAX_IPTUN_ENCAP_OPS]; - -int ip_tunnel_encap_add_ops(const struct ip_tunnel_encap_ops *op, - unsigned int num); -int ip_tunnel_encap_del_ops(const struct ip_tunnel_encap_ops *op, - unsigned int num); - -int ip_tunnel_encap_setup(struct ip_tunnel *t, - struct ip_tunnel_encap *ipencap); - -static inline int ip_encap_hlen(struct ip_tunnel_encap *e) -{ - const struct ip_tunnel_encap_ops *ops; - int hlen = -EINVAL; - - if (e->type == TUNNEL_ENCAP_NONE) - return 0; - - if (e->type >= MAX_IPTUN_ENCAP_OPS) - return -EINVAL; - - rcu_read_lock(); - ops = rcu_dereference(iptun_encaps[e->type]); - if (likely(ops && ops->encap_hlen)) - hlen = ops->encap_hlen(e); - rcu_read_unlock(); - - return hlen; -} - -static inline int ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t, - u8 *protocol, struct flowi4 *fl4) -{ - const struct ip_tunnel_encap_ops *ops; - int ret = -EINVAL; - - if (t->encap.type == TUNNEL_ENCAP_NONE) - return 0; - - if (t->encap.type >= MAX_IPTUN_ENCAP_OPS) - return -EINVAL; - - rcu_read_lock(); - ops = rcu_dereference(iptun_encaps[t->encap.type]); - if (likely(ops && ops->build_header)) - ret = ops->build_header(skb, &t->encap, protocol, fl4); - rcu_read_unlock(); - - return ret; -} - -/* Extract dsfield from inner protocol */ -static inline u8 ip_tunnel_get_dsfield(const struct iphdr *iph, - const struct sk_buff *skb) -{ - if (skb->protocol == htons(ETH_P_IP)) - return iph->tos; - else if (skb->protocol == htons(ETH_P_IPV6)) - return ipv6_get_dsfield((const struct ipv6hdr *)iph); - else - return 0; -} - -/* Propogate ECN bits out */ -static inline u8 ip_tunnel_ecn_encap(u8 tos, const struct iphdr *iph, - const struct sk_buff *skb) -{ - u8 inner = ip_tunnel_get_dsfield(iph, skb); - - return INET_ECN_encapsulate(tos, inner); -} - -int __iptunnel_pull_header(struct sk_buff *skb, int hdr_len, - __be16 inner_proto, bool raw_proto, bool xnet); - -static inline int iptunnel_pull_header(struct sk_buff *skb, int hdr_len, - __be16 inner_proto, bool xnet) -{ - return __iptunnel_pull_header(skb, hdr_len, inner_proto, false, xnet); -} - -void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb, - __be32 src, __be32 dst, u8 proto, - u8 tos, u8 ttl, __be16 df, bool xnet); -struct metadata_dst *iptunnel_metadata_reply(struct metadata_dst *md, - gfp_t flags); - -int iptunnel_handle_offloads(struct sk_buff *skb, int gso_type_mask); - -static inline int iptunnel_pull_offloads(struct sk_buff *skb) -{ - if (skb_is_gso(skb)) { - int err; - - err = skb_unclone(skb, GFP_ATOMIC); - if (unlikely(err)) - return err; - skb_shinfo(skb)->gso_type &= ~(NETIF_F_GSO_ENCAP_ALL >> - NETIF_F_GSO_SHIFT); - } - - skb->encapsulation = 0; - return 0; -} - -static inline void iptunnel_xmit_stats(struct net_device *dev, int pkt_len) -{ - if (pkt_len > 0) { - struct pcpu_sw_netstats *tstats = get_cpu_ptr(dev->tstats); - - u64_stats_update_begin(&tstats->syncp); - tstats->tx_bytes += pkt_len; - tstats->tx_packets++; - u64_stats_update_end(&tstats->syncp); - put_cpu_ptr(tstats); - } else { - struct net_device_stats *err_stats = &dev->stats; - - if (pkt_len < 0) { - err_stats->tx_errors++; - err_stats->tx_aborted_errors++; - } else { - err_stats->tx_dropped++; - } - } -} - -static inline void *ip_tunnel_info_opts(struct ip_tunnel_info *info) -{ - return info + 1; -} - -static inline void ip_tunnel_info_opts_get(void *to, - const struct ip_tunnel_info *info) -{ - memcpy(to, info + 1, info->options_len); -} - -static inline void ip_tunnel_info_opts_set(struct ip_tunnel_info *info, - const void *from, int len) -{ - memcpy(ip_tunnel_info_opts(info), from, len); - info->options_len = len; -} - -static inline struct ip_tunnel_info *lwt_tun_info(struct lwtunnel_state *lwtstate) -{ - return (struct ip_tunnel_info *)lwtstate->data; -} - -extern struct static_key ip_tunnel_metadata_cnt; - -/* Returns > 0 if metadata should be collected */ -static inline int ip_tunnel_collect_metadata(void) -{ - return static_key_false(&ip_tunnel_metadata_cnt); -} - -void __init ip_tunnel_core_init(void); - -void ip_tunnel_need_metadata(void); -void ip_tunnel_unneed_metadata(void); - -#else /* CONFIG_INET */ - -static inline struct ip_tunnel_info *lwt_tun_info(struct lwtunnel_state *lwtstate) -{ - return NULL; -} - -static inline void ip_tunnel_need_metadata(void) -{ -} - -static inline void ip_tunnel_unneed_metadata(void) -{ -} - -static inline void ip_tunnel_info_opts_get(void *to, - const struct ip_tunnel_info *info) -{ -} - -static inline void ip_tunnel_info_opts_set(struct ip_tunnel_info *info, - const void *from, int len) -{ - info->options_len = 0; -} - -#endif /* CONFIG_INET */ - -#endif /* __NET_IP_TUNNELS_H */ diff --git a/src/linux/include/net/ipconfig.h b/src/linux/include/net/ipconfig.h deleted file mode 100644 index c74cc1b..0000000 --- a/src/linux/include/net/ipconfig.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 1997 Martin Mares - * - * Automatic IP Layer Configuration - */ - -/* The following are initdata: */ - -extern int ic_proto_enabled; /* Protocols enabled (see IC_xxx) */ -extern int ic_set_manually; /* IPconfig parameters set manually */ - -extern __be32 ic_myaddr; /* My IP address */ -extern __be32 ic_gateway; /* Gateway IP address */ - -extern __be32 ic_servaddr; /* Boot server IP address */ - -extern __be32 root_server_addr; /* Address of NFS server */ -extern u8 root_server_path[]; /* Path to mount as root */ - - -/* bits in ic_proto_{enabled,used} */ -#define IC_PROTO 0xFF /* Protocols mask: */ -#define IC_BOOTP 0x01 /* BOOTP (or DHCP, see below) */ -#define IC_RARP 0x02 /* RARP */ -#define IC_USE_DHCP 0x100 /* If on, use DHCP instead of BOOTP */ diff --git a/src/linux/include/net/ipv6.h b/src/linux/include/net/ipv6.h deleted file mode 100644 index f11ca83..0000000 --- a/src/linux/include/net/ipv6.h +++ /dev/null @@ -1,1050 +0,0 @@ -/* - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _NET_IPV6_H -#define _NET_IPV6_H - -#include -#include -#include -#include -#include -#include -#include -#include - -#define SIN6_LEN_RFC2133 24 - -#define IPV6_MAXPLEN 65535 - -/* - * NextHeader field of IPv6 header - */ - -#define NEXTHDR_HOP 0 /* Hop-by-hop option header. */ -#define NEXTHDR_TCP 6 /* TCP segment. */ -#define NEXTHDR_UDP 17 /* UDP message. */ -#define NEXTHDR_IPV6 41 /* IPv6 in IPv6 */ -#define NEXTHDR_ROUTING 43 /* Routing header. */ -#define NEXTHDR_FRAGMENT 44 /* Fragmentation/reassembly header. */ -#define NEXTHDR_GRE 47 /* GRE header. */ -#define NEXTHDR_ESP 50 /* Encapsulating security payload. */ -#define NEXTHDR_AUTH 51 /* Authentication header. */ -#define NEXTHDR_ICMP 58 /* ICMP for IPv6. */ -#define NEXTHDR_NONE 59 /* No next header */ -#define NEXTHDR_DEST 60 /* Destination options header. */ -#define NEXTHDR_SCTP 132 /* SCTP message. */ -#define NEXTHDR_MOBILITY 135 /* Mobility header. */ - -#define NEXTHDR_MAX 255 - -#define IPV6_DEFAULT_HOPLIMIT 64 -#define IPV6_DEFAULT_MCASTHOPS 1 - -/* - * Addr type - * - * type - unicast | multicast - * scope - local | site | global - * v4 - compat - * v4mapped - * any - * loopback - */ - -#define IPV6_ADDR_ANY 0x0000U - -#define IPV6_ADDR_UNICAST 0x0001U -#define IPV6_ADDR_MULTICAST 0x0002U - -#define IPV6_ADDR_LOOPBACK 0x0010U -#define IPV6_ADDR_LINKLOCAL 0x0020U -#define IPV6_ADDR_SITELOCAL 0x0040U - -#define IPV6_ADDR_COMPATv4 0x0080U - -#define IPV6_ADDR_SCOPE_MASK 0x00f0U - -#define IPV6_ADDR_MAPPED 0x1000U - -/* - * Addr scopes - */ -#define IPV6_ADDR_MC_SCOPE(a) \ - ((a)->s6_addr[1] & 0x0f) /* nonstandard */ -#define __IPV6_ADDR_SCOPE_INVALID -1 -#define IPV6_ADDR_SCOPE_NODELOCAL 0x01 -#define IPV6_ADDR_SCOPE_LINKLOCAL 0x02 -#define IPV6_ADDR_SCOPE_SITELOCAL 0x05 -#define IPV6_ADDR_SCOPE_ORGLOCAL 0x08 -#define IPV6_ADDR_SCOPE_GLOBAL 0x0e - -/* - * Addr flags - */ -#define IPV6_ADDR_MC_FLAG_TRANSIENT(a) \ - ((a)->s6_addr[1] & 0x10) -#define IPV6_ADDR_MC_FLAG_PREFIX(a) \ - ((a)->s6_addr[1] & 0x20) -#define IPV6_ADDR_MC_FLAG_RENDEZVOUS(a) \ - ((a)->s6_addr[1] & 0x40) - -/* - * fragmentation header - */ - -struct frag_hdr { - __u8 nexthdr; - __u8 reserved; - __be16 frag_off; - __be32 identification; -}; - -#define IP6_MF 0x0001 -#define IP6_OFFSET 0xFFF8 - -#define IP6_REPLY_MARK(net, mark) \ - ((net)->ipv6.sysctl.fwmark_reflect ? (mark) : 0) - -#include - -/* sysctls */ -extern int sysctl_mld_max_msf; -extern int sysctl_mld_qrv; - -#define _DEVINC(net, statname, mod, idev, field) \ -({ \ - struct inet6_dev *_idev = (idev); \ - if (likely(_idev != NULL)) \ - mod##SNMP_INC_STATS64((_idev)->stats.statname, (field));\ - mod##SNMP_INC_STATS64((net)->mib.statname##_statistics, (field));\ -}) - -/* per device counters are atomic_long_t */ -#define _DEVINCATOMIC(net, statname, mod, idev, field) \ -({ \ - struct inet6_dev *_idev = (idev); \ - if (likely(_idev != NULL)) \ - SNMP_INC_STATS_ATOMIC_LONG((_idev)->stats.statname##dev, (field)); \ - mod##SNMP_INC_STATS((net)->mib.statname##_statistics, (field));\ -}) - -/* per device and per net counters are atomic_long_t */ -#define _DEVINC_ATOMIC_ATOMIC(net, statname, idev, field) \ -({ \ - struct inet6_dev *_idev = (idev); \ - if (likely(_idev != NULL)) \ - SNMP_INC_STATS_ATOMIC_LONG((_idev)->stats.statname##dev, (field)); \ - SNMP_INC_STATS_ATOMIC_LONG((net)->mib.statname##_statistics, (field));\ -}) - -#define _DEVADD(net, statname, mod, idev, field, val) \ -({ \ - struct inet6_dev *_idev = (idev); \ - if (likely(_idev != NULL)) \ - mod##SNMP_ADD_STATS((_idev)->stats.statname, (field), (val)); \ - mod##SNMP_ADD_STATS((net)->mib.statname##_statistics, (field), (val));\ -}) - -#define _DEVUPD(net, statname, mod, idev, field, val) \ -({ \ - struct inet6_dev *_idev = (idev); \ - if (likely(_idev != NULL)) \ - mod##SNMP_UPD_PO_STATS((_idev)->stats.statname, field, (val)); \ - mod##SNMP_UPD_PO_STATS((net)->mib.statname##_statistics, field, (val));\ -}) - -/* MIBs */ - -#define IP6_INC_STATS(net, idev,field) \ - _DEVINC(net, ipv6, , idev, field) -#define __IP6_INC_STATS(net, idev,field) \ - _DEVINC(net, ipv6, __, idev, field) -#define IP6_ADD_STATS(net, idev,field,val) \ - _DEVADD(net, ipv6, , idev, field, val) -#define __IP6_ADD_STATS(net, idev,field,val) \ - _DEVADD(net, ipv6, __, idev, field, val) -#define IP6_UPD_PO_STATS(net, idev,field,val) \ - _DEVUPD(net, ipv6, , idev, field, val) -#define __IP6_UPD_PO_STATS(net, idev,field,val) \ - _DEVUPD(net, ipv6, __, idev, field, val) -#define ICMP6_INC_STATS(net, idev, field) \ - _DEVINCATOMIC(net, icmpv6, , idev, field) -#define __ICMP6_INC_STATS(net, idev, field) \ - _DEVINCATOMIC(net, icmpv6, __, idev, field) - -#define ICMP6MSGOUT_INC_STATS(net, idev, field) \ - _DEVINC_ATOMIC_ATOMIC(net, icmpv6msg, idev, field +256) -#define ICMP6MSGIN_INC_STATS(net, idev, field) \ - _DEVINC_ATOMIC_ATOMIC(net, icmpv6msg, idev, field) - -struct ip6_ra_chain { - struct ip6_ra_chain *next; - struct sock *sk; - int sel; - void (*destructor)(struct sock *); -}; - -extern struct ip6_ra_chain *ip6_ra_chain; -extern rwlock_t ip6_ra_lock; - -/* - This structure is prepared by protocol, when parsing - ancillary data and passed to IPv6. - */ - -struct ipv6_txoptions { - atomic_t refcnt; - /* Length of this structure */ - int tot_len; - - /* length of extension headers */ - - __u16 opt_flen; /* after fragment hdr */ - __u16 opt_nflen; /* before fragment hdr */ - - struct ipv6_opt_hdr *hopopt; - struct ipv6_opt_hdr *dst0opt; - struct ipv6_rt_hdr *srcrt; /* Routing Header */ - struct ipv6_opt_hdr *dst1opt; - struct rcu_head rcu; - /* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */ -}; - -struct ip6_flowlabel { - struct ip6_flowlabel __rcu *next; - __be32 label; - atomic_t users; - struct in6_addr dst; - struct ipv6_txoptions *opt; - unsigned long linger; - struct rcu_head rcu; - u8 share; - union { - struct pid *pid; - kuid_t uid; - } owner; - unsigned long lastuse; - unsigned long expires; - struct net *fl_net; -}; - -#define IPV6_FLOWINFO_MASK cpu_to_be32(0x0FFFFFFF) -#define IPV6_FLOWLABEL_MASK cpu_to_be32(0x000FFFFF) -#define IPV6_FLOWLABEL_STATELESS_FLAG cpu_to_be32(0x00080000) - -#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK) -#define IPV6_TCLASS_SHIFT 20 - -struct ipv6_fl_socklist { - struct ipv6_fl_socklist __rcu *next; - struct ip6_flowlabel *fl; - struct rcu_head rcu; -}; - -struct ipcm6_cookie { - __s16 hlimit; - __s16 tclass; - __s8 dontfrag; - struct ipv6_txoptions *opt; -}; - -static inline struct ipv6_txoptions *txopt_get(const struct ipv6_pinfo *np) -{ - struct ipv6_txoptions *opt; - - rcu_read_lock(); - opt = rcu_dereference(np->opt); - if (opt) { - if (!atomic_inc_not_zero(&opt->refcnt)) - opt = NULL; - else - opt = rcu_pointer_handoff(opt); - } - rcu_read_unlock(); - return opt; -} - -static inline void txopt_put(struct ipv6_txoptions *opt) -{ - if (opt && atomic_dec_and_test(&opt->refcnt)) - kfree_rcu(opt, rcu); -} - -struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label); -struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space, - struct ip6_flowlabel *fl, - struct ipv6_txoptions *fopt); -void fl6_free_socklist(struct sock *sk); -int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen); -int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq, - int flags); -int ip6_flowlabel_init(void); -void ip6_flowlabel_cleanup(void); - -static inline void fl6_sock_release(struct ip6_flowlabel *fl) -{ - if (fl) - atomic_dec(&fl->users); -} - -void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info); - -int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, - struct icmp6hdr *thdr, int len); - -int ip6_ra_control(struct sock *sk, int sel); - -int ipv6_parse_hopopts(struct sk_buff *skb); - -struct ipv6_txoptions *ipv6_dup_options(struct sock *sk, - struct ipv6_txoptions *opt); -struct ipv6_txoptions *ipv6_renew_options(struct sock *sk, - struct ipv6_txoptions *opt, - int newtype, - struct ipv6_opt_hdr __user *newopt, - int newoptlen); -struct ipv6_txoptions * -ipv6_renew_options_kern(struct sock *sk, - struct ipv6_txoptions *opt, - int newtype, - struct ipv6_opt_hdr *newopt, - int newoptlen); -struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space, - struct ipv6_txoptions *opt); - -bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb, - const struct inet6_skb_parm *opt); -struct ipv6_txoptions *ipv6_update_options(struct sock *sk, - struct ipv6_txoptions *opt); - -static inline bool ipv6_accept_ra(struct inet6_dev *idev) -{ - /* If forwarding is enabled, RA are not accepted unless the special - * hybrid mode (accept_ra=2) is enabled. - */ - return idev->cnf.forwarding ? idev->cnf.accept_ra == 2 : - idev->cnf.accept_ra; -} - -#if IS_ENABLED(CONFIG_IPV6) -static inline int ip6_frag_mem(struct net *net) -{ - return sum_frag_mem_limit(&net->ipv6.frags); -} -#endif - -#define IPV6_FRAG_HIGH_THRESH (4 * 1024*1024) /* 4194304 */ -#define IPV6_FRAG_LOW_THRESH (3 * 1024*1024) /* 3145728 */ -#define IPV6_FRAG_TIMEOUT (60 * HZ) /* 60 seconds */ - -int __ipv6_addr_type(const struct in6_addr *addr); -static inline int ipv6_addr_type(const struct in6_addr *addr) -{ - return __ipv6_addr_type(addr) & 0xffff; -} - -static inline int ipv6_addr_scope(const struct in6_addr *addr) -{ - return __ipv6_addr_type(addr) & IPV6_ADDR_SCOPE_MASK; -} - -static inline int __ipv6_addr_src_scope(int type) -{ - return (type == IPV6_ADDR_ANY) ? __IPV6_ADDR_SCOPE_INVALID : (type >> 16); -} - -static inline int ipv6_addr_src_scope(const struct in6_addr *addr) -{ - return __ipv6_addr_src_scope(__ipv6_addr_type(addr)); -} - -static inline bool __ipv6_addr_needs_scope_id(int type) -{ - return type & IPV6_ADDR_LINKLOCAL || - (type & IPV6_ADDR_MULTICAST && - (type & (IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL))); -} - -static inline __u32 ipv6_iface_scope_id(const struct in6_addr *addr, int iface) -{ - return __ipv6_addr_needs_scope_id(__ipv6_addr_type(addr)) ? iface : 0; -} - -static inline int ipv6_addr_cmp(const struct in6_addr *a1, const struct in6_addr *a2) -{ - return memcmp(a1, a2, sizeof(struct in6_addr)); -} - -static inline bool -ipv6_masked_addr_cmp(const struct in6_addr *a1, const struct in6_addr *m, - const struct in6_addr *a2) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 - const unsigned long *ul1 = (const unsigned long *)a1; - const unsigned long *ulm = (const unsigned long *)m; - const unsigned long *ul2 = (const unsigned long *)a2; - - return !!(((ul1[0] ^ ul2[0]) & ulm[0]) | - ((ul1[1] ^ ul2[1]) & ulm[1])); -#else - return !!(((a1->s6_addr32[0] ^ a2->s6_addr32[0]) & m->s6_addr32[0]) | - ((a1->s6_addr32[1] ^ a2->s6_addr32[1]) & m->s6_addr32[1]) | - ((a1->s6_addr32[2] ^ a2->s6_addr32[2]) & m->s6_addr32[2]) | - ((a1->s6_addr32[3] ^ a2->s6_addr32[3]) & m->s6_addr32[3])); -#endif -} - -static inline void ipv6_addr_prefix(struct in6_addr *pfx, - const struct in6_addr *addr, - int plen) -{ - /* caller must guarantee 0 <= plen <= 128 */ - int o = plen >> 3, - b = plen & 0x7; - - memset(pfx->s6_addr, 0, sizeof(pfx->s6_addr)); - memcpy(pfx->s6_addr, addr, o); - if (b != 0) - pfx->s6_addr[o] = addr->s6_addr[o] & (0xff00 >> b); -} - -static inline void ipv6_addr_prefix_copy(struct in6_addr *addr, - const struct in6_addr *pfx, - int plen) -{ - /* caller must guarantee 0 <= plen <= 128 */ - int o = plen >> 3, - b = plen & 0x7; - - memcpy(addr->s6_addr, pfx, o); - if (b != 0) { - addr->s6_addr[o] &= ~(0xff00 >> b); - addr->s6_addr[o] |= (pfx->s6_addr[o] & (0xff00 >> b)); - } -} - -static inline void __ipv6_addr_set_half(__be32 *addr, - __be32 wh, __be32 wl) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 -#if defined(__BIG_ENDIAN) - if (__builtin_constant_p(wh) && __builtin_constant_p(wl)) { - *(__force u64 *)addr = ((__force u64)(wh) << 32 | (__force u64)(wl)); - return; - } -#elif defined(__LITTLE_ENDIAN) - if (__builtin_constant_p(wl) && __builtin_constant_p(wh)) { - *(__force u64 *)addr = ((__force u64)(wl) << 32 | (__force u64)(wh)); - return; - } -#endif -#endif - addr[0] = wh; - addr[1] = wl; -} - -static inline void ipv6_addr_set(struct in6_addr *addr, - __be32 w1, __be32 w2, - __be32 w3, __be32 w4) -{ - __ipv6_addr_set_half(&addr->s6_addr32[0], w1, w2); - __ipv6_addr_set_half(&addr->s6_addr32[2], w3, w4); -} - -static inline bool ipv6_addr_equal(const struct in6_addr *a1, - const struct in6_addr *a2) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 - const unsigned long *ul1 = (const unsigned long *)a1; - const unsigned long *ul2 = (const unsigned long *)a2; - - return ((ul1[0] ^ ul2[0]) | (ul1[1] ^ ul2[1])) == 0UL; -#else - return ((a1->s6_addr32[0] ^ a2->s6_addr32[0]) | - (a1->s6_addr32[1] ^ a2->s6_addr32[1]) | - (a1->s6_addr32[2] ^ a2->s6_addr32[2]) | - (a1->s6_addr32[3] ^ a2->s6_addr32[3])) == 0; -#endif -} - -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 -static inline bool __ipv6_prefix_equal64_half(const __be64 *a1, - const __be64 *a2, - unsigned int len) -{ - if (len && ((*a1 ^ *a2) & cpu_to_be64((~0UL) << (64 - len)))) - return false; - return true; -} - -static inline bool ipv6_prefix_equal(const struct in6_addr *addr1, - const struct in6_addr *addr2, - unsigned int prefixlen) -{ - const __be64 *a1 = (const __be64 *)addr1; - const __be64 *a2 = (const __be64 *)addr2; - - if (prefixlen >= 64) { - if (a1[0] ^ a2[0]) - return false; - return __ipv6_prefix_equal64_half(a1 + 1, a2 + 1, prefixlen - 64); - } - return __ipv6_prefix_equal64_half(a1, a2, prefixlen); -} -#else -static inline bool ipv6_prefix_equal(const struct in6_addr *addr1, - const struct in6_addr *addr2, - unsigned int prefixlen) -{ - const __be32 *a1 = addr1->s6_addr32; - const __be32 *a2 = addr2->s6_addr32; - unsigned int pdw, pbi; - - /* check complete u32 in prefix */ - pdw = prefixlen >> 5; - if (pdw && memcmp(a1, a2, pdw << 2)) - return false; - - /* check incomplete u32 in prefix */ - pbi = prefixlen & 0x1f; - if (pbi && ((a1[pdw] ^ a2[pdw]) & htonl((0xffffffff) << (32 - pbi)))) - return false; - - return true; -} -#endif - -struct inet_frag_queue; - -enum ip6_defrag_users { - IP6_DEFRAG_LOCAL_DELIVER, - IP6_DEFRAG_CONNTRACK_IN, - __IP6_DEFRAG_CONNTRACK_IN = IP6_DEFRAG_CONNTRACK_IN + USHRT_MAX, - IP6_DEFRAG_CONNTRACK_OUT, - __IP6_DEFRAG_CONNTRACK_OUT = IP6_DEFRAG_CONNTRACK_OUT + USHRT_MAX, - IP6_DEFRAG_CONNTRACK_BRIDGE_IN, - __IP6_DEFRAG_CONNTRACK_BRIDGE_IN = IP6_DEFRAG_CONNTRACK_BRIDGE_IN + USHRT_MAX, -}; - -struct ip6_create_arg { - __be32 id; - u32 user; - const struct in6_addr *src; - const struct in6_addr *dst; - int iif; - u8 ecn; -}; - -void ip6_frag_init(struct inet_frag_queue *q, const void *a); -bool ip6_frag_match(const struct inet_frag_queue *q, const void *a); - -/* - * Equivalent of ipv4 struct ip - */ -struct frag_queue { - struct inet_frag_queue q; - - __be32 id; /* fragment id */ - u32 user; - struct in6_addr saddr; - struct in6_addr daddr; - - int iif; - unsigned int csum; - __u16 nhoffset; - u8 ecn; -}; - -void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq, - struct inet_frags *frags); - -static inline bool ipv6_addr_any(const struct in6_addr *a) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 - const unsigned long *ul = (const unsigned long *)a; - - return (ul[0] | ul[1]) == 0UL; -#else - return (a->s6_addr32[0] | a->s6_addr32[1] | - a->s6_addr32[2] | a->s6_addr32[3]) == 0; -#endif -} - -static inline u32 ipv6_addr_hash(const struct in6_addr *a) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 - const unsigned long *ul = (const unsigned long *)a; - unsigned long x = ul[0] ^ ul[1]; - - return (u32)(x ^ (x >> 32)); -#else - return (__force u32)(a->s6_addr32[0] ^ a->s6_addr32[1] ^ - a->s6_addr32[2] ^ a->s6_addr32[3]); -#endif -} - -/* more secured version of ipv6_addr_hash() */ -static inline u32 __ipv6_addr_jhash(const struct in6_addr *a, const u32 initval) -{ - u32 v = (__force u32)a->s6_addr32[0] ^ (__force u32)a->s6_addr32[1]; - - return jhash_3words(v, - (__force u32)a->s6_addr32[2], - (__force u32)a->s6_addr32[3], - initval); -} - -static inline bool ipv6_addr_loopback(const struct in6_addr *a) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 - const __be64 *be = (const __be64 *)a; - - return (be[0] | (be[1] ^ cpu_to_be64(1))) == 0UL; -#else - return (a->s6_addr32[0] | a->s6_addr32[1] | - a->s6_addr32[2] | (a->s6_addr32[3] ^ cpu_to_be32(1))) == 0; -#endif -} - -/* - * Note that we must __force cast these to unsigned long to make sparse happy, - * since all of the endian-annotated types are fixed size regardless of arch. - */ -static inline bool ipv6_addr_v4mapped(const struct in6_addr *a) -{ - return ( -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 - *(unsigned long *)a | -#else - (__force unsigned long)(a->s6_addr32[0] | a->s6_addr32[1]) | -#endif - (__force unsigned long)(a->s6_addr32[2] ^ - cpu_to_be32(0x0000ffff))) == 0UL; -} - -/* - * Check for a RFC 4843 ORCHID address - * (Overlay Routable Cryptographic Hash Identifiers) - */ -static inline bool ipv6_addr_orchid(const struct in6_addr *a) -{ - return (a->s6_addr32[0] & htonl(0xfffffff0)) == htonl(0x20010010); -} - -static inline bool ipv6_addr_is_multicast(const struct in6_addr *addr) -{ - return (addr->s6_addr32[0] & htonl(0xFF000000)) == htonl(0xFF000000); -} - -static inline void ipv6_addr_set_v4mapped(const __be32 addr, - struct in6_addr *v4mapped) -{ - ipv6_addr_set(v4mapped, - 0, 0, - htonl(0x0000FFFF), - addr); -} - -/* - * find the first different bit between two addresses - * length of address must be a multiple of 32bits - */ -static inline int __ipv6_addr_diff32(const void *token1, const void *token2, int addrlen) -{ - const __be32 *a1 = token1, *a2 = token2; - int i; - - addrlen >>= 2; - - for (i = 0; i < addrlen; i++) { - __be32 xb = a1[i] ^ a2[i]; - if (xb) - return i * 32 + 31 - __fls(ntohl(xb)); - } - - /* - * we should *never* get to this point since that - * would mean the addrs are equal - * - * However, we do get to it 8) And exacly, when - * addresses are equal 8) - * - * ip route add 1111::/128 via ... - * ip route add 1111::/64 via ... - * and we are here. - * - * Ideally, this function should stop comparison - * at prefix length. It does not, but it is still OK, - * if returned value is greater than prefix length. - * --ANK (980803) - */ - return addrlen << 5; -} - -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 -static inline int __ipv6_addr_diff64(const void *token1, const void *token2, int addrlen) -{ - const __be64 *a1 = token1, *a2 = token2; - int i; - - addrlen >>= 3; - - for (i = 0; i < addrlen; i++) { - __be64 xb = a1[i] ^ a2[i]; - if (xb) - return i * 64 + 63 - __fls(be64_to_cpu(xb)); - } - - return addrlen << 6; -} -#endif - -static inline int __ipv6_addr_diff(const void *token1, const void *token2, int addrlen) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 - if (__builtin_constant_p(addrlen) && !(addrlen & 7)) - return __ipv6_addr_diff64(token1, token2, addrlen); -#endif - return __ipv6_addr_diff32(token1, token2, addrlen); -} - -static inline int ipv6_addr_diff(const struct in6_addr *a1, const struct in6_addr *a2) -{ - return __ipv6_addr_diff(a1, a2, sizeof(struct in6_addr)); -} - -__be32 ipv6_select_ident(struct net *net, - const struct in6_addr *daddr, - const struct in6_addr *saddr); -void ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb); - -int ip6_dst_hoplimit(struct dst_entry *dst); - -static inline int ip6_sk_dst_hoplimit(struct ipv6_pinfo *np, struct flowi6 *fl6, - struct dst_entry *dst) -{ - int hlimit; - - if (ipv6_addr_is_multicast(&fl6->daddr)) - hlimit = np->mcast_hops; - else - hlimit = np->hop_limit; - if (hlimit < 0) - hlimit = ip6_dst_hoplimit(dst); - return hlimit; -} - -/* copy IPv6 saddr & daddr to flow_keys, possibly using 64bit load/store - * Equivalent to : flow->v6addrs.src = iph->saddr; - * flow->v6addrs.dst = iph->daddr; - */ -static inline void iph_to_flow_copy_v6addrs(struct flow_keys *flow, - const struct ipv6hdr *iph) -{ - BUILD_BUG_ON(offsetof(typeof(flow->addrs), v6addrs.dst) != - offsetof(typeof(flow->addrs), v6addrs.src) + - sizeof(flow->addrs.v6addrs.src)); - memcpy(&flow->addrs.v6addrs, &iph->saddr, sizeof(flow->addrs.v6addrs)); - flow->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; -} - -#if IS_ENABLED(CONFIG_IPV6) - -/* Sysctl settings for net ipv6.auto_flowlabels */ -#define IP6_AUTO_FLOW_LABEL_OFF 0 -#define IP6_AUTO_FLOW_LABEL_OPTOUT 1 -#define IP6_AUTO_FLOW_LABEL_OPTIN 2 -#define IP6_AUTO_FLOW_LABEL_FORCED 3 - -#define IP6_AUTO_FLOW_LABEL_MAX IP6_AUTO_FLOW_LABEL_FORCED - -#define IP6_DEFAULT_AUTO_FLOW_LABELS IP6_AUTO_FLOW_LABEL_OPTOUT - -static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb, - __be32 flowlabel, bool autolabel, - struct flowi6 *fl6) -{ - u32 hash; - - if (flowlabel || - net->ipv6.sysctl.auto_flowlabels == IP6_AUTO_FLOW_LABEL_OFF || - (!autolabel && - net->ipv6.sysctl.auto_flowlabels != IP6_AUTO_FLOW_LABEL_FORCED)) - return flowlabel; - - hash = skb_get_hash_flowi6(skb, fl6); - - /* Since this is being sent on the wire obfuscate hash a bit - * to minimize possbility that any useful information to an - * attacker is leaked. Only lower 20 bits are relevant. - */ - rol32(hash, 16); - - flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK; - - if (net->ipv6.sysctl.flowlabel_state_ranges) - flowlabel |= IPV6_FLOWLABEL_STATELESS_FLAG; - - return flowlabel; -} - -static inline int ip6_default_np_autolabel(struct net *net) -{ - switch (net->ipv6.sysctl.auto_flowlabels) { - case IP6_AUTO_FLOW_LABEL_OFF: - case IP6_AUTO_FLOW_LABEL_OPTIN: - default: - return 0; - case IP6_AUTO_FLOW_LABEL_OPTOUT: - case IP6_AUTO_FLOW_LABEL_FORCED: - return 1; - } -} -#else -static inline void ip6_set_txhash(struct sock *sk) { } -static inline __be32 ip6_make_flowlabel(struct net *net, struct sk_buff *skb, - __be32 flowlabel, bool autolabel, - struct flowi6 *fl6) -{ - return flowlabel; -} -static inline int ip6_default_np_autolabel(struct net *net) -{ - return 0; -} -#endif - - -/* - * Header manipulation - */ -static inline void ip6_flow_hdr(struct ipv6hdr *hdr, unsigned int tclass, - __be32 flowlabel) -{ - *(__be32 *)hdr = htonl(0x60000000 | (tclass << 20)) | flowlabel; -} - -static inline __be32 ip6_flowinfo(const struct ipv6hdr *hdr) -{ - return *(__be32 *)hdr & IPV6_FLOWINFO_MASK; -} - -static inline __be32 ip6_flowlabel(const struct ipv6hdr *hdr) -{ - return *(__be32 *)hdr & IPV6_FLOWLABEL_MASK; -} - -static inline u8 ip6_tclass(__be32 flowinfo) -{ - return ntohl(flowinfo & IPV6_TCLASS_MASK) >> IPV6_TCLASS_SHIFT; -} - -static inline __be32 ip6_make_flowinfo(unsigned int tclass, __be32 flowlabel) -{ - return htonl(tclass << IPV6_TCLASS_SHIFT) | flowlabel; -} - -/* - * Prototypes exported by ipv6 - */ - -/* - * rcv function (called from netdevice level) - */ - -int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *pt, struct net_device *orig_dev); - -int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb); - -/* - * upper-layer output functions - */ -int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, - struct ipv6_txoptions *opt, int tclass); - -int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr); - -int ip6_append_data(struct sock *sk, - int getfrag(void *from, char *to, int offset, int len, - int odd, struct sk_buff *skb), - void *from, int length, int transhdrlen, - struct ipcm6_cookie *ipc6, struct flowi6 *fl6, - struct rt6_info *rt, unsigned int flags, - const struct sockcm_cookie *sockc); - -int ip6_push_pending_frames(struct sock *sk); - -void ip6_flush_pending_frames(struct sock *sk); - -int ip6_send_skb(struct sk_buff *skb); - -struct sk_buff *__ip6_make_skb(struct sock *sk, struct sk_buff_head *queue, - struct inet_cork_full *cork, - struct inet6_cork *v6_cork); -struct sk_buff *ip6_make_skb(struct sock *sk, - int getfrag(void *from, char *to, int offset, - int len, int odd, struct sk_buff *skb), - void *from, int length, int transhdrlen, - struct ipcm6_cookie *ipc6, struct flowi6 *fl6, - struct rt6_info *rt, unsigned int flags, - const struct sockcm_cookie *sockc); - -static inline struct sk_buff *ip6_finish_skb(struct sock *sk) -{ - return __ip6_make_skb(sk, &sk->sk_write_queue, &inet_sk(sk)->cork, - &inet6_sk(sk)->cork); -} - -int ip6_dst_lookup(struct net *net, struct sock *sk, struct dst_entry **dst, - struct flowi6 *fl6); -struct dst_entry *ip6_dst_lookup_flow(const struct sock *sk, struct flowi6 *fl6, - const struct in6_addr *final_dst); -struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, - const struct in6_addr *final_dst); -struct dst_entry *ip6_blackhole_route(struct net *net, - struct dst_entry *orig_dst); - -/* - * skb processing functions - */ - -int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb); -int ip6_forward(struct sk_buff *skb); -int ip6_input(struct sk_buff *skb); -int ip6_mc_input(struct sk_buff *skb); - -int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb); -int ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb); - -/* - * Extension header (options) processing - */ - -void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, - u8 *proto, struct in6_addr **daddr_p); -void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, - u8 *proto); - -int ipv6_skip_exthdr(const struct sk_buff *, int start, u8 *nexthdrp, - __be16 *frag_offp); - -bool ipv6_ext_hdr(u8 nexthdr); - -enum { - IP6_FH_F_FRAG = (1 << 0), - IP6_FH_F_AUTH = (1 << 1), - IP6_FH_F_SKIP_RH = (1 << 2), -}; - -/* find specified header and get offset to it */ -int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, int target, - unsigned short *fragoff, int *fragflg); - -int ipv6_find_tlv(const struct sk_buff *skb, int offset, int type); - -struct in6_addr *fl6_update_dst(struct flowi6 *fl6, - const struct ipv6_txoptions *opt, - struct in6_addr *orig); - -/* - * socket options (ipv6_sockglue.c) - */ - -int ipv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen); -int ipv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen); -int compat_ipv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen); -int compat_ipv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen); - -int __ip6_datagram_connect(struct sock *sk, struct sockaddr *addr, - int addr_len); -int ip6_datagram_connect(struct sock *sk, struct sockaddr *addr, int addr_len); -int ip6_datagram_connect_v6_only(struct sock *sk, struct sockaddr *addr, - int addr_len); -int ip6_datagram_dst_update(struct sock *sk, bool fix_sk_saddr); -void ip6_datagram_release_cb(struct sock *sk); - -int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, - int *addr_len); -int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len, - int *addr_len); -void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, __be16 port, - u32 info, u8 *payload); -void ipv6_local_error(struct sock *sk, int err, struct flowi6 *fl6, u32 info); -void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu); - -int inet6_release(struct socket *sock); -int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len); -int inet6_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, - int peer); -int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); - -int inet6_hash_connect(struct inet_timewait_death_row *death_row, - struct sock *sk); - -/* - * reassembly.c - */ -extern const struct proto_ops inet6_stream_ops; -extern const struct proto_ops inet6_dgram_ops; - -struct group_source_req; -struct group_filter; - -int ip6_mc_source(int add, int omode, struct sock *sk, - struct group_source_req *pgsr); -int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf); -int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, - struct group_filter __user *optval, int __user *optlen); - -#ifdef CONFIG_PROC_FS -int ac6_proc_init(struct net *net); -void ac6_proc_exit(struct net *net); -int raw6_proc_init(void); -void raw6_proc_exit(void); -int tcp6_proc_init(struct net *net); -void tcp6_proc_exit(struct net *net); -int udp6_proc_init(struct net *net); -void udp6_proc_exit(struct net *net); -int udplite6_proc_init(void); -void udplite6_proc_exit(void); -int ipv6_misc_proc_init(void); -void ipv6_misc_proc_exit(void); -int snmp6_register_dev(struct inet6_dev *idev); -int snmp6_unregister_dev(struct inet6_dev *idev); - -#else -static inline int ac6_proc_init(struct net *net) { return 0; } -static inline void ac6_proc_exit(struct net *net) { } -static inline int snmp6_register_dev(struct inet6_dev *idev) { return 0; } -static inline int snmp6_unregister_dev(struct inet6_dev *idev) { return 0; } -#endif - -#ifdef CONFIG_SYSCTL -extern struct ctl_table ipv6_route_table_template[]; - -struct ctl_table *ipv6_icmp_sysctl_init(struct net *net); -struct ctl_table *ipv6_route_sysctl_init(struct net *net); -int ipv6_sysctl_register(void); -void ipv6_sysctl_unregister(void); -#endif - -int ipv6_sock_mc_join(struct sock *sk, int ifindex, - const struct in6_addr *addr); -int ipv6_sock_mc_drop(struct sock *sk, int ifindex, - const struct in6_addr *addr); -#endif /* _NET_IPV6_H */ diff --git a/src/linux/include/net/iw_handler.h b/src/linux/include/net/iw_handler.h deleted file mode 100644 index e0f4109..0000000 --- a/src/linux/include/net/iw_handler.h +++ /dev/null @@ -1,603 +0,0 @@ -/* - * This file define the new driver API for Wireless Extensions - * - * Version : 8 16.3.07 - * - * Authors : Jean Tourrilhes - HPL - - * Copyright (c) 2001-2007 Jean Tourrilhes, All Rights Reserved. - */ - -#ifndef _IW_HANDLER_H -#define _IW_HANDLER_H - -/************************** DOCUMENTATION **************************/ -/* - * Initial driver API (1996 -> onward) : - * ----------------------------------- - * The initial API just sends the IOCTL request received from user space - * to the driver (via the driver ioctl handler). The driver has to - * handle all the rest... - * - * The initial API also defines a specific handler in struct net_device - * to handle wireless statistics. - * - * The initial APIs served us well and has proven a reasonably good design. - * However, there is a few shortcommings : - * o No events, everything is a request to the driver. - * o Large ioctl function in driver with gigantic switch statement - * (i.e. spaghetti code). - * o Driver has to mess up with copy_to/from_user, and in many cases - * does it unproperly. Common mistakes are : - * * buffer overflows (no checks or off by one checks) - * * call copy_to/from_user with irq disabled - * o The user space interface is tied to ioctl because of the use - * copy_to/from_user. - * - * New driver API (2002 -> onward) : - * ------------------------------- - * The new driver API is just a bunch of standard functions (handlers), - * each handling a specific Wireless Extension. The driver just export - * the list of handler it supports, and those will be called apropriately. - * - * I tried to keep the main advantage of the previous API (simplicity, - * efficiency and light weight), and also I provide a good dose of backward - * compatibility (most structures are the same, driver can use both API - * simultaneously, ...). - * Hopefully, I've also addressed the shortcomming of the initial API. - * - * The advantage of the new API are : - * o Handling of Extensions in driver broken in small contained functions - * o Tighter checks of ioctl before calling the driver - * o Flexible commit strategy (at least, the start of it) - * o Backward compatibility (can be mixed with old API) - * o Driver doesn't have to worry about memory and user-space issues - * The last point is important for the following reasons : - * o You are now able to call the new driver API from any API you - * want (including from within other parts of the kernel). - * o Common mistakes are avoided (buffer overflow, user space copy - * with irq disabled and so on). - * - * The Drawback of the new API are : - * o bloat (especially kernel) - * o need to migrate existing drivers to new API - * My initial testing shows that the new API adds around 3kB to the kernel - * and save between 0 and 5kB from a typical driver. - * Also, as all structures and data types are unchanged, the migration is - * quite straightforward (but tedious). - * - * --- - * - * The new driver API is defined below in this file. User space should - * not be aware of what's happening down there... - * - * A new kernel wrapper is in charge of validating the IOCTLs and calling - * the appropriate driver handler. This is implemented in : - * # net/core/wireless.c - * - * The driver export the list of handlers in : - * # include/linux/netdevice.h (one place) - * - * The new driver API is available for WIRELESS_EXT >= 13. - * Good luck with migration to the new API ;-) - */ - -/* ---------------------- THE IMPLEMENTATION ---------------------- */ -/* - * Some of the choice I've made are pretty controversials. Defining an - * API is very much weighting compromises. This goes into some of the - * details and the thinking behind the implementation. - * - * Implementation goals : - * -------------------- - * The implementation goals were as follow : - * o Obvious : you should not need a PhD to understand what's happening, - * the benefit is easier maintenance. - * o Flexible : it should accommodate a wide variety of driver - * implementations and be as flexible as the old API. - * o Lean : it should be efficient memory wise to minimise the impact - * on kernel footprint. - * o Transparent to user space : the large number of user space - * applications that use Wireless Extensions should not need - * any modifications. - * - * Array of functions versus Struct of functions - * --------------------------------------------- - * 1) Having an array of functions allow the kernel code to access the - * handler in a single lookup, which is much more efficient (think hash - * table here). - * 2) The only drawback is that driver writer may put their handler in - * the wrong slot. This is trivial to test (I set the frequency, the - * bitrate changes). Once the handler is in the proper slot, it will be - * there forever, because the array is only extended at the end. - * 3) Backward/forward compatibility : adding new handler just require - * extending the array, so you can put newer driver in older kernel - * without having to patch the kernel code (and vice versa). - * - * All handler are of the same generic type - * ---------------------------------------- - * That's a feature !!! - * 1) Having a generic handler allow to have generic code, which is more - * efficient. If each of the handler was individually typed I would need - * to add a big switch in the kernel (== more bloat). This solution is - * more scalable, adding new Wireless Extensions doesn't add new code. - * 2) You can use the same handler in different slots of the array. For - * hardware, it may be more efficient or logical to handle multiple - * Wireless Extensions with a single function, and the API allow you to - * do that. (An example would be a single record on the card to control - * both bitrate and frequency, the handler would read the old record, - * modify it according to info->cmd and rewrite it). - * - * Functions prototype uses union iwreq_data - * ----------------------------------------- - * Some would have preferred functions defined this way : - * static int mydriver_ioctl_setrate(struct net_device *dev, - * long rate, int auto) - * 1) The kernel code doesn't "validate" the content of iwreq_data, and - * can't do it (different hardware may have different notion of what a - * valid frequency is), so we don't pretend that we do it. - * 2) The above form is not extendable. If I want to add a flag (for - * example to distinguish setting max rate and basic rate), I would - * break the prototype. Using iwreq_data is more flexible. - * 3) Also, the above form is not generic (see above). - * 4) I don't expect driver developper using the wrong field of the - * union (Doh !), so static typechecking doesn't add much value. - * 5) Lastly, you can skip the union by doing : - * static int mydriver_ioctl_setrate(struct net_device *dev, - * struct iw_request_info *info, - * struct iw_param *rrq, - * char *extra) - * And then adding the handler in the array like this : - * (iw_handler) mydriver_ioctl_setrate, // SIOCSIWRATE - * - * Using functions and not a registry - * ---------------------------------- - * Another implementation option would have been for every instance to - * define a registry (a struct containing all the Wireless Extensions) - * and only have a function to commit the registry to the hardware. - * 1) This approach can be emulated by the current code, but not - * vice versa. - * 2) Some drivers don't keep any configuration in the driver, for them - * adding such a registry would be a significant bloat. - * 3) The code to translate from Wireless Extension to native format is - * needed anyway, so it would not reduce significantely the amount of code. - * 4) The current approach only selectively translate Wireless Extensions - * to native format and only selectively set, whereas the registry approach - * would require to translate all WE and set all parameters for any single - * change. - * 5) For many Wireless Extensions, the GET operation return the current - * dynamic value, not the value that was set. - * - * This header is - * --------------------------------- - * 1) This header is kernel space only and should not be exported to - * user space. Headers in "include/linux/" are exported, headers in - * "include/net/" are not. - * - * Mixed 32/64 bit issues - * ---------------------- - * The Wireless Extensions are designed to be 64 bit clean, by using only - * datatypes with explicit storage size. - * There are some issues related to kernel and user space using different - * memory model, and in particular 64bit kernel with 32bit user space. - * The problem is related to struct iw_point, that contains a pointer - * that *may* need to be translated. - * This is quite messy. The new API doesn't solve this problem (it can't), - * but is a step in the right direction : - * 1) Meta data about each ioctl is easily available, so we know what type - * of translation is needed. - * 2) The move of data between kernel and user space is only done in a single - * place in the kernel, so adding specific hooks in there is possible. - * 3) In the long term, it allows to move away from using ioctl as the - * user space API. - * - * So many comments and so few code - * -------------------------------- - * That's a feature. Comments won't bloat the resulting kernel binary. - */ - -/***************************** INCLUDES *****************************/ - -#include /* IOCTL user space API */ -#include - -/***************************** VERSION *****************************/ -/* - * This constant is used to know which version of the driver API is - * available. Hopefully, this will be pretty stable and no changes - * will be needed... - * I just plan to increment with each new version. - */ -#define IW_HANDLER_VERSION 8 - -/* - * Changes : - * - * V2 to V3 - * -------- - * - Move event definition in - * - Add Wireless Event support : - * o wireless_send_event() prototype - * o iwe_stream_add_event/point() inline functions - * V3 to V4 - * -------- - * - Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes - * - * V4 to V5 - * -------- - * - Add new spy support : struct iw_spy_data & prototypes - * - * V5 to V6 - * -------- - * - Change the way we get to spy_data method for added safety - * - Remove spy #ifdef, they are always on -> cleaner code - * - Add IW_DESCR_FLAG_NOMAX flag for very large requests - * - Start migrating get_wireless_stats to struct iw_handler_def - * - * V6 to V7 - * -------- - * - Add struct ieee80211_device pointer in struct iw_public_data - * - Remove (struct iw_point *)->pointer from events and streams - * - Remove spy_offset from struct iw_handler_def - * - Add "check" version of event macros for ieee802.11 stack - * - * V7 to V8 - * ---------- - * - Prevent leaking of kernel space in stream on 64 bits. - */ - -/**************************** CONSTANTS ****************************/ - -/* Enhanced spy support available */ -#define IW_WIRELESS_SPY -#define IW_WIRELESS_THRSPY - -/* Special error message for the driver to indicate that we - * should do a commit after return from the iw_handler */ -#define EIWCOMMIT EINPROGRESS - -/* Flags available in struct iw_request_info */ -#define IW_REQUEST_FLAG_COMPAT 0x0001 /* Compat ioctl call */ - -/* Type of headers we know about (basically union iwreq_data) */ -#define IW_HEADER_TYPE_NULL 0 /* Not available */ -#define IW_HEADER_TYPE_CHAR 2 /* char [IFNAMSIZ] */ -#define IW_HEADER_TYPE_UINT 4 /* __u32 */ -#define IW_HEADER_TYPE_FREQ 5 /* struct iw_freq */ -#define IW_HEADER_TYPE_ADDR 6 /* struct sockaddr */ -#define IW_HEADER_TYPE_POINT 8 /* struct iw_point */ -#define IW_HEADER_TYPE_PARAM 9 /* struct iw_param */ -#define IW_HEADER_TYPE_QUAL 10 /* struct iw_quality */ - -/* Handling flags */ -/* Most are not implemented. I just use them as a reminder of some - * cool features we might need one day ;-) */ -#define IW_DESCR_FLAG_NONE 0x0000 /* Obvious */ -/* Wrapper level flags */ -#define IW_DESCR_FLAG_DUMP 0x0001 /* Not part of the dump command */ -#define IW_DESCR_FLAG_EVENT 0x0002 /* Generate an event on SET */ -#define IW_DESCR_FLAG_RESTRICT 0x0004 /* GET : request is ROOT only */ - /* SET : Omit payload from generated iwevent */ -#define IW_DESCR_FLAG_NOMAX 0x0008 /* GET : no limit on request size */ -/* Driver level flags */ -#define IW_DESCR_FLAG_WAIT 0x0100 /* Wait for driver event */ - -/****************************** TYPES ******************************/ - -/* ----------------------- WIRELESS HANDLER ----------------------- */ -/* - * A wireless handler is just a standard function, that looks like the - * ioctl handler. - * We also define there how a handler list look like... As the Wireless - * Extension space is quite dense, we use a simple array, which is faster - * (that's the perfect hash table ;-). - */ - -/* - * Meta data about the request passed to the iw_handler. - * Most handlers can safely ignore what's in there. - * The 'cmd' field might come handy if you want to use the same handler - * for multiple command... - * This struct is also my long term insurance. I can add new fields here - * without breaking the prototype of iw_handler... - */ -struct iw_request_info { - __u16 cmd; /* Wireless Extension command */ - __u16 flags; /* More to come ;-) */ -}; - -struct net_device; - -/* - * This is how a function handling a Wireless Extension should look - * like (both get and set, standard and private). - */ -typedef int (*iw_handler)(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); - -/* - * This define all the handler that the driver export. - * As you need only one per driver type, please use a static const - * shared by all driver instances... Same for the members... - * This will be linked from net_device in - */ -struct iw_handler_def { - - /* Array of handlers for standard ioctls - * We will call dev->wireless_handlers->standard[ioctl - SIOCIWFIRST] - */ - const iw_handler * standard; - /* Number of handlers defined (more precisely, index of the - * last defined handler + 1) */ - __u16 num_standard; - -#ifdef CONFIG_WEXT_PRIV - __u16 num_private; - /* Number of private arg description */ - __u16 num_private_args; - /* Array of handlers for private ioctls - * Will call dev->wireless_handlers->private[ioctl - SIOCIWFIRSTPRIV] - */ - const iw_handler * private; - - /* Arguments of private handler. This one is just a list, so you - * can put it in any order you want and should not leave holes... - * We will automatically export that to user space... */ - const struct iw_priv_args * private_args; -#endif - - /* New location of get_wireless_stats, to de-bloat struct net_device. - * The old pointer in struct net_device will be gradually phased - * out, and drivers are encouraged to use this one... */ - struct iw_statistics* (*get_wireless_stats)(struct net_device *dev); -}; - -/* ---------------------- IOCTL DESCRIPTION ---------------------- */ -/* - * One of the main goal of the new interface is to deal entirely with - * user space/kernel space memory move. - * For that, we need to know : - * o if iwreq is a pointer or contain the full data - * o what is the size of the data to copy - * - * For private IOCTLs, we use the same rules as used by iwpriv and - * defined in struct iw_priv_args. - * - * For standard IOCTLs, things are quite different and we need to - * use the stuctures below. Actually, this struct is also more - * efficient, but that's another story... - */ - -/* - * Describe how a standard IOCTL looks like. - */ -struct iw_ioctl_description { - __u8 header_type; /* NULL, iw_point or other */ - __u8 token_type; /* Future */ - __u16 token_size; /* Granularity of payload */ - __u16 min_tokens; /* Min acceptable token number */ - __u16 max_tokens; /* Max acceptable token number */ - __u32 flags; /* Special handling of the request */ -}; - -/* Need to think of short header translation table. Later. */ - -/* --------------------- ENHANCED SPY SUPPORT --------------------- */ -/* - * In the old days, the driver was handling spy support all by itself. - * Now, the driver can delegate this task to Wireless Extensions. - * It needs to include this struct in its private part and use the - * standard spy iw_handler. - */ - -/* - * Instance specific spy data, i.e. addresses spied and quality for them. - */ -struct iw_spy_data { - /* --- Standard spy support --- */ - int spy_number; - u_char spy_address[IW_MAX_SPY][ETH_ALEN]; - struct iw_quality spy_stat[IW_MAX_SPY]; - /* --- Enhanced spy support (event) */ - struct iw_quality spy_thr_low; /* Low threshold */ - struct iw_quality spy_thr_high; /* High threshold */ - u_char spy_thr_under[IW_MAX_SPY]; -}; - -/* --------------------- DEVICE WIRELESS DATA --------------------- */ -/* - * This is all the wireless data specific to a device instance that - * is managed by the core of Wireless Extensions or the 802.11 layer. - * We only keep pointer to those structures, so that a driver is free - * to share them between instances. - * This structure should be initialised before registering the device. - * Access to this data follow the same rules as any other struct net_device - * data (i.e. valid as long as struct net_device exist, same locking rules). - */ -/* Forward declaration */ -struct libipw_device; -/* The struct */ -struct iw_public_data { - /* Driver enhanced spy support */ - struct iw_spy_data * spy_data; - /* Legacy structure managed by the ipw2x00-specific IEEE 802.11 layer */ - struct libipw_device * libipw; -}; - -/**************************** PROTOTYPES ****************************/ -/* - * Functions part of the Wireless Extensions (defined in net/core/wireless.c). - * Those may be called only within the kernel. - */ - -/* First : function strictly used inside the kernel */ - -/* Handle /proc/net/wireless, called in net/code/dev.c */ -int dev_get_wireless_info(char *buffer, char **start, off_t offset, int length); - -/* Second : functions that may be called by driver modules */ - -/* Send a single event to user space */ -void wireless_send_event(struct net_device *dev, unsigned int cmd, - union iwreq_data *wrqu, const char *extra); -#ifdef CONFIG_WEXT_CORE -/* flush all previous wext events - if work is done from netdev notifiers */ -void wireless_nlevent_flush(void); -#else -static inline void wireless_nlevent_flush(void) {} -#endif - -/* We may need a function to send a stream of events to user space. - * More on that later... */ - -/* Standard handler for SIOCSIWSPY */ -int iw_handler_set_spy(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); -/* Standard handler for SIOCGIWSPY */ -int iw_handler_get_spy(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); -/* Standard handler for SIOCSIWTHRSPY */ -int iw_handler_set_thrspy(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); -/* Standard handler for SIOCGIWTHRSPY */ -int iw_handler_get_thrspy(struct net_device *dev, struct iw_request_info *info, - union iwreq_data *wrqu, char *extra); -/* Driver call to update spy records */ -void wireless_spy_update(struct net_device *dev, unsigned char *address, - struct iw_quality *wstats); - -/************************* INLINE FUNTIONS *************************/ -/* - * Function that are so simple that it's more efficient inlining them - */ - -static inline int iwe_stream_lcp_len(struct iw_request_info *info) -{ -#ifdef CONFIG_COMPAT - if (info->flags & IW_REQUEST_FLAG_COMPAT) - return IW_EV_COMPAT_LCP_LEN; -#endif - return IW_EV_LCP_LEN; -} - -static inline int iwe_stream_point_len(struct iw_request_info *info) -{ -#ifdef CONFIG_COMPAT - if (info->flags & IW_REQUEST_FLAG_COMPAT) - return IW_EV_COMPAT_POINT_LEN; -#endif - return IW_EV_POINT_LEN; -} - -static inline int iwe_stream_event_len_adjust(struct iw_request_info *info, - int event_len) -{ -#ifdef CONFIG_COMPAT - if (info->flags & IW_REQUEST_FLAG_COMPAT) { - event_len -= IW_EV_LCP_LEN; - event_len += IW_EV_COMPAT_LCP_LEN; - } -#endif - - return event_len; -} - -/*------------------------------------------------------------------*/ -/* - * Wrapper to add an Wireless Event to a stream of events. - */ -static inline char * -iwe_stream_add_event(struct iw_request_info *info, char *stream, char *ends, - struct iw_event *iwe, int event_len) -{ - int lcp_len = iwe_stream_lcp_len(info); - - event_len = iwe_stream_event_len_adjust(info, event_len); - - /* Check if it's possible */ - if(likely((stream + event_len) < ends)) { - iwe->len = event_len; - /* Beware of alignement issues on 64 bits */ - memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN); - memcpy(stream + lcp_len, &iwe->u, - event_len - lcp_len); - stream += event_len; - } - return stream; -} - -static inline char * -iwe_stream_add_event_check(struct iw_request_info *info, char *stream, - char *ends, struct iw_event *iwe, int event_len) -{ - char *res = iwe_stream_add_event(info, stream, ends, iwe, event_len); - - if (res == stream) - return ERR_PTR(-E2BIG); - return res; -} - -/*------------------------------------------------------------------*/ -/* - * Wrapper to add an short Wireless Event containing a pointer to a - * stream of events. - */ -static inline char * -iwe_stream_add_point(struct iw_request_info *info, char *stream, char *ends, - struct iw_event *iwe, char *extra) -{ - int event_len = iwe_stream_point_len(info) + iwe->u.data.length; - int point_len = iwe_stream_point_len(info); - int lcp_len = iwe_stream_lcp_len(info); - - /* Check if it's possible */ - if(likely((stream + event_len) < ends)) { - iwe->len = event_len; - memcpy(stream, (char *) iwe, IW_EV_LCP_PK_LEN); - memcpy(stream + lcp_len, - ((char *) &iwe->u) + IW_EV_POINT_OFF, - IW_EV_POINT_PK_LEN - IW_EV_LCP_PK_LEN); - memcpy(stream + point_len, extra, iwe->u.data.length); - stream += event_len; - } - return stream; -} - -static inline char * -iwe_stream_add_point_check(struct iw_request_info *info, char *stream, - char *ends, struct iw_event *iwe, char *extra) -{ - char *res = iwe_stream_add_point(info, stream, ends, iwe, extra); - - if (res == stream) - return ERR_PTR(-E2BIG); - return res; -} - -/*------------------------------------------------------------------*/ -/* - * Wrapper to add a value to a Wireless Event in a stream of events. - * Be careful, this one is tricky to use properly : - * At the first run, you need to have (value = event + IW_EV_LCP_LEN). - */ -static inline char * -iwe_stream_add_value(struct iw_request_info *info, char *event, char *value, - char *ends, struct iw_event *iwe, int event_len) -{ - int lcp_len = iwe_stream_lcp_len(info); - - /* Don't duplicate LCP */ - event_len -= IW_EV_LCP_LEN; - - /* Check if it's possible */ - if(likely((value + event_len) < ends)) { - /* Add new value */ - memcpy(value, &iwe->u, event_len); - value += event_len; - /* Patch LCP */ - iwe->len = value - event; - memcpy(event, (char *) iwe, lcp_len); - } - return value; -} - -#endif /* _IW_HANDLER_H */ diff --git a/src/linux/include/net/l3mdev.h b/src/linux/include/net/l3mdev.h deleted file mode 100644 index 3832099..0000000 --- a/src/linux/include/net/l3mdev.h +++ /dev/null @@ -1,276 +0,0 @@ -/* - * include/net/l3mdev.h - L3 master device API - * Copyright (c) 2015 Cumulus Networks - * Copyright (c) 2015 David Ahern - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#ifndef _NET_L3MDEV_H_ -#define _NET_L3MDEV_H_ - -#include -#include - -/** - * struct l3mdev_ops - l3mdev operations - * - * @l3mdev_fib_table: Get FIB table id to use for lookups - * - * @l3mdev_l3_rcv: Hook in L3 receive path - * - * @l3mdev_l3_out: Hook in L3 output path - * - * @l3mdev_link_scope_lookup: IPv6 lookup for linklocal and mcast destinations - */ - -struct l3mdev_ops { - u32 (*l3mdev_fib_table)(const struct net_device *dev); - struct sk_buff * (*l3mdev_l3_rcv)(struct net_device *dev, - struct sk_buff *skb, u16 proto); - struct sk_buff * (*l3mdev_l3_out)(struct net_device *dev, - struct sock *sk, struct sk_buff *skb, - u16 proto); - - /* IPv6 ops */ - struct dst_entry * (*l3mdev_link_scope_lookup)(const struct net_device *dev, - struct flowi6 *fl6); -}; - -#ifdef CONFIG_NET_L3_MASTER_DEV - -int l3mdev_fib_rule_match(struct net *net, struct flowi *fl, - struct fib_lookup_arg *arg); - -void l3mdev_update_flow(struct net *net, struct flowi *fl); - -int l3mdev_master_ifindex_rcu(const struct net_device *dev); -static inline int l3mdev_master_ifindex(struct net_device *dev) -{ - int ifindex; - - rcu_read_lock(); - ifindex = l3mdev_master_ifindex_rcu(dev); - rcu_read_unlock(); - - return ifindex; -} - -static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex) -{ - struct net_device *dev; - int rc = 0; - - if (likely(ifindex)) { - rcu_read_lock(); - - dev = dev_get_by_index_rcu(net, ifindex); - if (dev) - rc = l3mdev_master_ifindex_rcu(dev); - - rcu_read_unlock(); - } - - return rc; -} - -static inline -struct net_device *l3mdev_master_dev_rcu(const struct net_device *_dev) -{ - /* netdev_master_upper_dev_get_rcu calls - * list_first_or_null_rcu to walk the upper dev list. - * list_first_or_null_rcu does not handle a const arg. We aren't - * making changes, just want the master device from that list so - * typecast to remove the const - */ - struct net_device *dev = (struct net_device *)_dev; - struct net_device *master; - - if (!dev) - return NULL; - - if (netif_is_l3_master(dev)) - master = dev; - else if (netif_is_l3_slave(dev)) - master = netdev_master_upper_dev_get_rcu(dev); - else - master = NULL; - - return master; -} - -u32 l3mdev_fib_table_rcu(const struct net_device *dev); -u32 l3mdev_fib_table_by_index(struct net *net, int ifindex); -static inline u32 l3mdev_fib_table(const struct net_device *dev) -{ - u32 tb_id; - - rcu_read_lock(); - tb_id = l3mdev_fib_table_rcu(dev); - rcu_read_unlock(); - - return tb_id; -} - -static inline bool netif_index_is_l3_master(struct net *net, int ifindex) -{ - struct net_device *dev; - bool rc = false; - - if (ifindex == 0) - return false; - - rcu_read_lock(); - - dev = dev_get_by_index_rcu(net, ifindex); - if (dev) - rc = netif_is_l3_master(dev); - - rcu_read_unlock(); - - return rc; -} - -struct dst_entry *l3mdev_link_scope_lookup(struct net *net, struct flowi6 *fl6); - -static inline -struct sk_buff *l3mdev_l3_rcv(struct sk_buff *skb, u16 proto) -{ - struct net_device *master = NULL; - - if (netif_is_l3_slave(skb->dev)) - master = netdev_master_upper_dev_get_rcu(skb->dev); - else if (netif_is_l3_master(skb->dev)) - master = skb->dev; - - if (master && master->l3mdev_ops->l3mdev_l3_rcv) - skb = master->l3mdev_ops->l3mdev_l3_rcv(master, skb, proto); - - return skb; -} - -static inline -struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb) -{ - return l3mdev_l3_rcv(skb, AF_INET); -} - -static inline -struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb) -{ - return l3mdev_l3_rcv(skb, AF_INET6); -} - -static inline -struct sk_buff *l3mdev_l3_out(struct sock *sk, struct sk_buff *skb, u16 proto) -{ - struct net_device *dev = skb_dst(skb)->dev; - - if (netif_is_l3_slave(dev)) { - struct net_device *master; - - master = netdev_master_upper_dev_get_rcu(dev); - if (master && master->l3mdev_ops->l3mdev_l3_out) - skb = master->l3mdev_ops->l3mdev_l3_out(master, sk, - skb, proto); - } - - return skb; -} - -static inline -struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb) -{ - return l3mdev_l3_out(sk, skb, AF_INET); -} - -static inline -struct sk_buff *l3mdev_ip6_out(struct sock *sk, struct sk_buff *skb) -{ - return l3mdev_l3_out(sk, skb, AF_INET6); -} -#else - -static inline int l3mdev_master_ifindex_rcu(const struct net_device *dev) -{ - return 0; -} -static inline int l3mdev_master_ifindex(struct net_device *dev) -{ - return 0; -} - -static inline int l3mdev_master_ifindex_by_index(struct net *net, int ifindex) -{ - return 0; -} - -static inline -struct net_device *l3mdev_master_dev_rcu(const struct net_device *dev) -{ - return NULL; -} - -static inline u32 l3mdev_fib_table_rcu(const struct net_device *dev) -{ - return 0; -} -static inline u32 l3mdev_fib_table(const struct net_device *dev) -{ - return 0; -} -static inline u32 l3mdev_fib_table_by_index(struct net *net, int ifindex) -{ - return 0; -} - -static inline bool netif_index_is_l3_master(struct net *net, int ifindex) -{ - return false; -} - -static inline -struct dst_entry *l3mdev_link_scope_lookup(struct net *net, struct flowi6 *fl6) -{ - return NULL; -} - -static inline -struct sk_buff *l3mdev_ip_rcv(struct sk_buff *skb) -{ - return skb; -} - -static inline -struct sk_buff *l3mdev_ip6_rcv(struct sk_buff *skb) -{ - return skb; -} - -static inline -struct sk_buff *l3mdev_ip_out(struct sock *sk, struct sk_buff *skb) -{ - return skb; -} - -static inline -struct sk_buff *l3mdev_ip6_out(struct sock *sk, struct sk_buff *skb) -{ - return skb; -} - -static inline -int l3mdev_fib_rule_match(struct net *net, struct flowi *fl, - struct fib_lookup_arg *arg) -{ - return 1; -} -static inline -void l3mdev_update_flow(struct net *net, struct flowi *fl) -{ -} -#endif - -#endif /* _NET_L3MDEV_H_ */ diff --git a/src/linux/include/net/lwtunnel.h b/src/linux/include/net/lwtunnel.h deleted file mode 100644 index ea3f80f..0000000 --- a/src/linux/include/net/lwtunnel.h +++ /dev/null @@ -1,221 +0,0 @@ -#ifndef __NET_LWTUNNEL_H -#define __NET_LWTUNNEL_H 1 - -#include -#include -#include -#include -#include - -#define LWTUNNEL_HASH_BITS 7 -#define LWTUNNEL_HASH_SIZE (1 << LWTUNNEL_HASH_BITS) - -/* lw tunnel state flags */ -#define LWTUNNEL_STATE_OUTPUT_REDIRECT BIT(0) -#define LWTUNNEL_STATE_INPUT_REDIRECT BIT(1) -#define LWTUNNEL_STATE_XMIT_REDIRECT BIT(2) - -enum { - LWTUNNEL_XMIT_DONE, - LWTUNNEL_XMIT_CONTINUE, -}; - - -struct lwtunnel_state { - __u16 type; - __u16 flags; - atomic_t refcnt; - int (*orig_output)(struct net *net, struct sock *sk, struct sk_buff *skb); - int (*orig_input)(struct sk_buff *); - int len; - __u16 headroom; - __u8 data[0]; -}; - -struct lwtunnel_encap_ops { - int (*build_state)(struct net_device *dev, struct nlattr *encap, - unsigned int family, const void *cfg, - struct lwtunnel_state **ts); - int (*output)(struct net *net, struct sock *sk, struct sk_buff *skb); - int (*input)(struct sk_buff *skb); - int (*fill_encap)(struct sk_buff *skb, - struct lwtunnel_state *lwtstate); - int (*get_encap_size)(struct lwtunnel_state *lwtstate); - int (*cmp_encap)(struct lwtunnel_state *a, struct lwtunnel_state *b); - int (*xmit)(struct sk_buff *skb); -}; - -#ifdef CONFIG_LWTUNNEL -static inline void lwtstate_free(struct lwtunnel_state *lws) -{ - kfree(lws); -} - -static inline struct lwtunnel_state * -lwtstate_get(struct lwtunnel_state *lws) -{ - if (lws) - atomic_inc(&lws->refcnt); - - return lws; -} - -static inline void lwtstate_put(struct lwtunnel_state *lws) -{ - if (!lws) - return; - - if (atomic_dec_and_test(&lws->refcnt)) - lwtstate_free(lws); -} - -static inline bool lwtunnel_output_redirect(struct lwtunnel_state *lwtstate) -{ - if (lwtstate && (lwtstate->flags & LWTUNNEL_STATE_OUTPUT_REDIRECT)) - return true; - - return false; -} - -static inline bool lwtunnel_input_redirect(struct lwtunnel_state *lwtstate) -{ - if (lwtstate && (lwtstate->flags & LWTUNNEL_STATE_INPUT_REDIRECT)) - return true; - - return false; -} - -static inline bool lwtunnel_xmit_redirect(struct lwtunnel_state *lwtstate) -{ - if (lwtstate && (lwtstate->flags & LWTUNNEL_STATE_XMIT_REDIRECT)) - return true; - - return false; -} - -static inline unsigned int lwtunnel_headroom(struct lwtunnel_state *lwtstate, - unsigned int mtu) -{ - if (lwtunnel_xmit_redirect(lwtstate) && lwtstate->headroom < mtu) - return lwtstate->headroom; - - return 0; -} - -int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op, - unsigned int num); -int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op, - unsigned int num); -int lwtunnel_build_state(struct net_device *dev, u16 encap_type, - struct nlattr *encap, - unsigned int family, const void *cfg, - struct lwtunnel_state **lws); -int lwtunnel_fill_encap(struct sk_buff *skb, - struct lwtunnel_state *lwtstate); -int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate); -struct lwtunnel_state *lwtunnel_state_alloc(int hdr_len); -int lwtunnel_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b); -int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb); -int lwtunnel_input(struct sk_buff *skb); -int lwtunnel_xmit(struct sk_buff *skb); - -#else - -static inline void lwtstate_free(struct lwtunnel_state *lws) -{ -} - -static inline struct lwtunnel_state * -lwtstate_get(struct lwtunnel_state *lws) -{ - return lws; -} - -static inline void lwtstate_put(struct lwtunnel_state *lws) -{ -} - -static inline bool lwtunnel_output_redirect(struct lwtunnel_state *lwtstate) -{ - return false; -} - -static inline bool lwtunnel_input_redirect(struct lwtunnel_state *lwtstate) -{ - return false; -} - -static inline bool lwtunnel_xmit_redirect(struct lwtunnel_state *lwtstate) -{ - return false; -} - -static inline unsigned int lwtunnel_headroom(struct lwtunnel_state *lwtstate, - unsigned int mtu) -{ - return 0; -} - -static inline int lwtunnel_encap_add_ops(const struct lwtunnel_encap_ops *op, - unsigned int num) -{ - return -EOPNOTSUPP; - -} - -static inline int lwtunnel_encap_del_ops(const struct lwtunnel_encap_ops *op, - unsigned int num) -{ - return -EOPNOTSUPP; -} - -static inline int lwtunnel_build_state(struct net_device *dev, u16 encap_type, - struct nlattr *encap, - unsigned int family, const void *cfg, - struct lwtunnel_state **lws) -{ - return -EOPNOTSUPP; -} - -static inline int lwtunnel_fill_encap(struct sk_buff *skb, - struct lwtunnel_state *lwtstate) -{ - return 0; -} - -static inline int lwtunnel_get_encap_size(struct lwtunnel_state *lwtstate) -{ - return 0; -} - -static inline struct lwtunnel_state *lwtunnel_state_alloc(int hdr_len) -{ - return NULL; -} - -static inline int lwtunnel_cmp_encap(struct lwtunnel_state *a, - struct lwtunnel_state *b) -{ - return 0; -} - -static inline int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - return -EOPNOTSUPP; -} - -static inline int lwtunnel_input(struct sk_buff *skb) -{ - return -EOPNOTSUPP; -} - -static inline int lwtunnel_xmit(struct sk_buff *skb) -{ - return -EOPNOTSUPP; -} - -#endif /* CONFIG_LWTUNNEL */ - -#define MODULE_ALIAS_RTNL_LWT(encap_type) MODULE_ALIAS("rtnl-lwt-" __stringify(encap_type)) - -#endif /* __NET_LWTUNNEL_H */ diff --git a/src/linux/include/net/mac802154.h b/src/linux/include/net/mac802154.h deleted file mode 100644 index 286824a..0000000 --- a/src/linux/include/net/mac802154.h +++ /dev/null @@ -1,498 +0,0 @@ -/* - * IEEE802.15.4-2003 specification - * - * Copyright (C) 2007-2012 Siemens AG - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ -#ifndef NET_MAC802154_H -#define NET_MAC802154_H - -#include -#include -#include -#include - -#include - -/** - * enum ieee802154_hw_addr_filt_flags - hardware address filtering flags - * - * The following flags are used to indicate changed address settings from - * the stack to the hardware. - * - * @IEEE802154_AFILT_SADDR_CHANGED: Indicates that the short address will be - * change. - * - * @IEEE802154_AFILT_IEEEADDR_CHANGED: Indicates that the extended address - * will be change. - * - * @IEEE802154_AFILT_PANID_CHANGED: Indicates that the pan id will be change. - * - * @IEEE802154_AFILT_PANC_CHANGED: Indicates that the address filter will - * do frame address filtering as a pan coordinator. - */ -enum ieee802154_hw_addr_filt_flags { - IEEE802154_AFILT_SADDR_CHANGED = BIT(0), - IEEE802154_AFILT_IEEEADDR_CHANGED = BIT(1), - IEEE802154_AFILT_PANID_CHANGED = BIT(2), - IEEE802154_AFILT_PANC_CHANGED = BIT(3), -}; - -/** - * struct ieee802154_hw_addr_filt - hardware address filtering settings - * - * @pan_id: pan_id which should be set to the hardware address filter. - * - * @short_addr: short_addr which should be set to the hardware address filter. - * - * @ieee_addr: extended address which should be set to the hardware address - * filter. - * - * @pan_coord: boolean if hardware filtering should be operate as coordinator. - */ -struct ieee802154_hw_addr_filt { - __le16 pan_id; - __le16 short_addr; - __le64 ieee_addr; - bool pan_coord; -}; - -/** - * struct ieee802154_hw - ieee802154 hardware - * - * @extra_tx_headroom: headroom to reserve in each transmit skb for use by the - * driver (e.g. for transmit headers.) - * - * @flags: hardware flags, see &enum ieee802154_hw_flags - * - * @parent: parent device of the hardware. - * - * @priv: pointer to private area that was allocated for driver use along with - * this structure. - * - * @phy: This points to the &struct wpan_phy allocated for this 802.15.4 PHY. - */ -struct ieee802154_hw { - /* filled by the driver */ - int extra_tx_headroom; - u32 flags; - struct device *parent; - void *priv; - - /* filled by mac802154 core */ - struct wpan_phy *phy; -}; - -/** - * enum ieee802154_hw_flags - hardware flags - * - * These flags are used to indicate hardware capabilities to - * the stack. Generally, flags here should have their meaning - * done in a way that the simplest hardware doesn't need setting - * any particular flags. There are some exceptions to this rule, - * however, so you are advised to review these flags carefully. - * - * @IEEE802154_HW_TX_OMIT_CKSUM: Indicates that xmitter will add FCS on it's - * own. - * - * @IEEE802154_HW_LBT: Indicates that transceiver will support listen before - * transmit. - * - * @IEEE802154_HW_CSMA_PARAMS: Indicates that transceiver will support csma - * parameters (max_be, min_be, backoff exponents). - * - * @IEEE802154_HW_FRAME_RETRIES: Indicates that transceiver will support ARET - * frame retries setting. - * - * @IEEE802154_HW_AFILT: Indicates that transceiver will support hardware - * address filter setting. - * - * @IEEE802154_HW_PROMISCUOUS: Indicates that transceiver will support - * promiscuous mode setting. - * - * @IEEE802154_HW_RX_OMIT_CKSUM: Indicates that receiver omits FCS. - * - * @IEEE802154_HW_RX_DROP_BAD_CKSUM: Indicates that receiver will not filter - * frames with bad checksum. - */ -enum ieee802154_hw_flags { - IEEE802154_HW_TX_OMIT_CKSUM = BIT(0), - IEEE802154_HW_LBT = BIT(1), - IEEE802154_HW_CSMA_PARAMS = BIT(2), - IEEE802154_HW_FRAME_RETRIES = BIT(3), - IEEE802154_HW_AFILT = BIT(4), - IEEE802154_HW_PROMISCUOUS = BIT(5), - IEEE802154_HW_RX_OMIT_CKSUM = BIT(6), - IEEE802154_HW_RX_DROP_BAD_CKSUM = BIT(7), -}; - -/* Indicates that receiver omits FCS and xmitter will add FCS on it's own. */ -#define IEEE802154_HW_OMIT_CKSUM (IEEE802154_HW_TX_OMIT_CKSUM | \ - IEEE802154_HW_RX_OMIT_CKSUM) - -/* struct ieee802154_ops - callbacks from mac802154 to the driver - * - * This structure contains various callbacks that the driver may - * handle or, in some cases, must handle, for example to transmit - * a frame. - * - * start: Handler that 802.15.4 module calls for device initialization. - * This function is called before the first interface is attached. - * - * stop: Handler that 802.15.4 module calls for device cleanup. - * This function is called after the last interface is removed. - * - * xmit_sync: - * Handler that 802.15.4 module calls for each transmitted frame. - * skb cntains the buffer starting from the IEEE 802.15.4 header. - * The low-level driver should send the frame based on available - * configuration. This is called by a workqueue and useful for - * synchronous 802.15.4 drivers. - * This function should return zero or negative errno. - * - * WARNING: - * This will be deprecated soon. We don't accept synced xmit callbacks - * drivers anymore. - * - * xmit_async: - * Handler that 802.15.4 module calls for each transmitted frame. - * skb cntains the buffer starting from the IEEE 802.15.4 header. - * The low-level driver should send the frame based on available - * configuration. - * This function should return zero or negative errno. - * - * ed: Handler that 802.15.4 module calls for Energy Detection. - * This function should place the value for detected energy - * (usually device-dependant) in the level pointer and return - * either zero or negative errno. Called with pib_lock held. - * - * set_channel: - * Set radio for listening on specific channel. - * Set the device for listening on specified channel. - * Returns either zero, or negative errno. Called with pib_lock held. - * - * set_hw_addr_filt: - * Set radio for listening on specific address. - * Set the device for listening on specified address. - * Returns either zero, or negative errno. - * - * set_txpower: - * Set radio transmit power in mBm. Called with pib_lock held. - * Returns either zero, or negative errno. - * - * set_lbt - * Enables or disables listen before talk on the device. Called with - * pib_lock held. - * Returns either zero, or negative errno. - * - * set_cca_mode - * Sets the CCA mode used by the device. Called with pib_lock held. - * Returns either zero, or negative errno. - * - * set_cca_ed_level - * Sets the CCA energy detection threshold in mBm. Called with pib_lock - * held. - * Returns either zero, or negative errno. - * - * set_csma_params - * Sets the CSMA parameter set for the PHY. Called with pib_lock held. - * Returns either zero, or negative errno. - * - * set_frame_retries - * Sets the retransmission attempt limit. Called with pib_lock held. - * Returns either zero, or negative errno. - * - * set_promiscuous_mode - * Enables or disable promiscuous mode. - */ -struct ieee802154_ops { - struct module *owner; - int (*start)(struct ieee802154_hw *hw); - void (*stop)(struct ieee802154_hw *hw); - int (*xmit_sync)(struct ieee802154_hw *hw, - struct sk_buff *skb); - int (*xmit_async)(struct ieee802154_hw *hw, - struct sk_buff *skb); - int (*ed)(struct ieee802154_hw *hw, u8 *level); - int (*set_channel)(struct ieee802154_hw *hw, u8 page, - u8 channel); - int (*set_hw_addr_filt)(struct ieee802154_hw *hw, - struct ieee802154_hw_addr_filt *filt, - unsigned long changed); - int (*set_txpower)(struct ieee802154_hw *hw, s32 mbm); - int (*set_lbt)(struct ieee802154_hw *hw, bool on); - int (*set_cca_mode)(struct ieee802154_hw *hw, - const struct wpan_phy_cca *cca); - int (*set_cca_ed_level)(struct ieee802154_hw *hw, s32 mbm); - int (*set_csma_params)(struct ieee802154_hw *hw, - u8 min_be, u8 max_be, u8 retries); - int (*set_frame_retries)(struct ieee802154_hw *hw, - s8 retries); - int (*set_promiscuous_mode)(struct ieee802154_hw *hw, - const bool on); -}; - -/** - * ieee802154_get_fc_from_skb - get the frame control field from an skb - * @skb: skb where the frame control field will be get from - */ -static inline __le16 ieee802154_get_fc_from_skb(const struct sk_buff *skb) -{ - __le16 fc; - - /* check if we can fc at skb_mac_header of sk buffer */ - if (WARN_ON(!skb_mac_header_was_set(skb) || - (skb_tail_pointer(skb) - - skb_mac_header(skb)) < IEEE802154_FC_LEN)) - return cpu_to_le16(0); - - memcpy(&fc, skb_mac_header(skb), IEEE802154_FC_LEN); - return fc; -} - -/** - * ieee802154_skb_dst_pan - get the pointer to destination pan field - * @fc: mac header frame control field - * @skb: skb where the destination pan pointer will be get from - */ -static inline unsigned char *ieee802154_skb_dst_pan(__le16 fc, - const struct sk_buff *skb) -{ - unsigned char *dst_pan; - - switch (ieee802154_daddr_mode(fc)) { - case cpu_to_le16(IEEE802154_FCTL_ADDR_NONE): - dst_pan = NULL; - break; - case cpu_to_le16(IEEE802154_FCTL_DADDR_SHORT): - case cpu_to_le16(IEEE802154_FCTL_DADDR_EXTENDED): - dst_pan = skb_mac_header(skb) + - IEEE802154_FC_LEN + - IEEE802154_SEQ_LEN; - break; - default: - WARN_ONCE(1, "invalid addr mode detected"); - dst_pan = NULL; - break; - } - - return dst_pan; -} - -/** - * ieee802154_skb_src_pan - get the pointer to source pan field - * @fc: mac header frame control field - * @skb: skb where the source pan pointer will be get from - */ -static inline unsigned char *ieee802154_skb_src_pan(__le16 fc, - const struct sk_buff *skb) -{ - unsigned char *src_pan; - - switch (ieee802154_saddr_mode(fc)) { - case cpu_to_le16(IEEE802154_FCTL_ADDR_NONE): - src_pan = NULL; - break; - case cpu_to_le16(IEEE802154_FCTL_SADDR_SHORT): - case cpu_to_le16(IEEE802154_FCTL_SADDR_EXTENDED): - /* if intra-pan and source addr mode is non none, - * then source pan id is equal destination pan id. - */ - if (ieee802154_is_intra_pan(fc)) { - src_pan = ieee802154_skb_dst_pan(fc, skb); - break; - } - - switch (ieee802154_daddr_mode(fc)) { - case cpu_to_le16(IEEE802154_FCTL_ADDR_NONE): - src_pan = skb_mac_header(skb) + - IEEE802154_FC_LEN + - IEEE802154_SEQ_LEN; - break; - case cpu_to_le16(IEEE802154_FCTL_DADDR_SHORT): - src_pan = skb_mac_header(skb) + - IEEE802154_FC_LEN + - IEEE802154_SEQ_LEN + - IEEE802154_PAN_ID_LEN + - IEEE802154_SHORT_ADDR_LEN; - break; - case cpu_to_le16(IEEE802154_FCTL_DADDR_EXTENDED): - src_pan = skb_mac_header(skb) + - IEEE802154_FC_LEN + - IEEE802154_SEQ_LEN + - IEEE802154_PAN_ID_LEN + - IEEE802154_EXTENDED_ADDR_LEN; - break; - default: - WARN_ONCE(1, "invalid addr mode detected"); - src_pan = NULL; - break; - } - break; - default: - WARN_ONCE(1, "invalid addr mode detected"); - src_pan = NULL; - break; - } - - return src_pan; -} - -/** - * ieee802154_skb_is_intra_pan_addressing - checks whenever the mac addressing - * is an intra pan communication - * @fc: mac header frame control field - * @skb: skb where the source and destination pan should be get from - */ -static inline bool ieee802154_skb_is_intra_pan_addressing(__le16 fc, - const struct sk_buff *skb) -{ - unsigned char *dst_pan = ieee802154_skb_dst_pan(fc, skb), - *src_pan = ieee802154_skb_src_pan(fc, skb); - - /* if one is NULL is no intra pan addressing */ - if (!dst_pan || !src_pan) - return false; - - return !memcmp(dst_pan, src_pan, IEEE802154_PAN_ID_LEN); -} - -/** - * ieee802154_be64_to_le64 - copies and convert be64 to le64 - * @le64_dst: le64 destination pointer - * @be64_src: be64 source pointer - */ -static inline void ieee802154_be64_to_le64(void *le64_dst, const void *be64_src) -{ - put_unaligned_le64(get_unaligned_be64(be64_src), le64_dst); -} - -/** - * ieee802154_le64_to_be64 - copies and convert le64 to be64 - * @be64_dst: be64 destination pointer - * @le64_src: le64 source pointer - */ -static inline void ieee802154_le64_to_be64(void *be64_dst, const void *le64_src) -{ - put_unaligned_be64(get_unaligned_le64(le64_src), be64_dst); -} - -/** - * ieee802154_le16_to_be16 - copies and convert le16 to be16 - * @be16_dst: be16 destination pointer - * @le16_src: le16 source pointer - */ -static inline void ieee802154_le16_to_be16(void *be16_dst, const void *le16_src) -{ - put_unaligned_be16(get_unaligned_le16(le16_src), be16_dst); -} - -/** - * ieee802154_be16_to_le16 - copies and convert be16 to le16 - * @le16_dst: le16 destination pointer - * @be16_src: be16 source pointer - */ -static inline void ieee802154_be16_to_le16(void *le16_dst, const void *be16_src) -{ - put_unaligned_le16(get_unaligned_be16(be16_src), le16_dst); -} - -/** - * ieee802154_alloc_hw - Allocate a new hardware device - * - * This must be called once for each hardware device. The returned pointer - * must be used to refer to this device when calling other functions. - * mac802154 allocates a private data area for the driver pointed to by - * @priv in &struct ieee802154_hw, the size of this area is given as - * @priv_data_len. - * - * @priv_data_len: length of private data - * @ops: callbacks for this device - * - * Return: A pointer to the new hardware device, or %NULL on error. - */ -struct ieee802154_hw * -ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops); - -/** - * ieee802154_free_hw - free hardware descriptor - * - * This function frees everything that was allocated, including the - * private data for the driver. You must call ieee802154_unregister_hw() - * before calling this function. - * - * @hw: the hardware to free - */ -void ieee802154_free_hw(struct ieee802154_hw *hw); - -/** - * ieee802154_register_hw - Register hardware device - * - * You must call this function before any other functions in - * mac802154. Note that before a hardware can be registered, you - * need to fill the contained wpan_phy's information. - * - * @hw: the device to register as returned by ieee802154_alloc_hw() - * - * Return: 0 on success. An error code otherwise. - */ -int ieee802154_register_hw(struct ieee802154_hw *hw); - -/** - * ieee802154_unregister_hw - Unregister a hardware device - * - * This function instructs mac802154 to free allocated resources - * and unregister netdevices from the networking subsystem. - * - * @hw: the hardware to unregister - */ -void ieee802154_unregister_hw(struct ieee802154_hw *hw); - -/** - * ieee802154_rx_irqsafe - receive frame - * - * Like ieee802154_rx() but can be called in IRQ context - * (internally defers to a tasklet.) - * - * @hw: the hardware this frame came in on - * @skb: the buffer to receive, owned by mac802154 after this call - * @lqi: link quality indicator - */ -void ieee802154_rx_irqsafe(struct ieee802154_hw *hw, struct sk_buff *skb, - u8 lqi); -/** - * ieee802154_wake_queue - wake ieee802154 queue - * @hw: pointer as obtained from ieee802154_alloc_hw(). - * - * Drivers should use this function instead of netif_wake_queue. - */ -void ieee802154_wake_queue(struct ieee802154_hw *hw); - -/** - * ieee802154_stop_queue - stop ieee802154 queue - * @hw: pointer as obtained from ieee802154_alloc_hw(). - * - * Drivers should use this function instead of netif_stop_queue. - */ -void ieee802154_stop_queue(struct ieee802154_hw *hw); - -/** - * ieee802154_xmit_complete - frame transmission complete - * - * @hw: pointer as obtained from ieee802154_alloc_hw(). - * @skb: buffer for transmission - * @ifs_handling: indicate interframe space handling - */ -void ieee802154_xmit_complete(struct ieee802154_hw *hw, struct sk_buff *skb, - bool ifs_handling); - -#endif /* NET_MAC802154_H */ diff --git a/src/linux/include/net/mld.h b/src/linux/include/net/mld.h deleted file mode 100644 index 01d7513..0000000 --- a/src/linux/include/net/mld.h +++ /dev/null @@ -1,113 +0,0 @@ -#ifndef LINUX_MLD_H -#define LINUX_MLD_H - -#include -#include - -/* MLDv1 Query/Report/Done */ -struct mld_msg { - struct icmp6hdr mld_hdr; - struct in6_addr mld_mca; -}; - -#define mld_type mld_hdr.icmp6_type -#define mld_code mld_hdr.icmp6_code -#define mld_cksum mld_hdr.icmp6_cksum -#define mld_maxdelay mld_hdr.icmp6_maxdelay -#define mld_reserved mld_hdr.icmp6_dataun.un_data16[1] - -/* Multicast Listener Discovery version 2 headers */ -/* MLDv2 Report */ -struct mld2_grec { - __u8 grec_type; - __u8 grec_auxwords; - __be16 grec_nsrcs; - struct in6_addr grec_mca; - struct in6_addr grec_src[0]; -}; - -struct mld2_report { - struct icmp6hdr mld2r_hdr; - struct mld2_grec mld2r_grec[0]; -}; - -#define mld2r_type mld2r_hdr.icmp6_type -#define mld2r_resv1 mld2r_hdr.icmp6_code -#define mld2r_cksum mld2r_hdr.icmp6_cksum -#define mld2r_resv2 mld2r_hdr.icmp6_dataun.un_data16[0] -#define mld2r_ngrec mld2r_hdr.icmp6_dataun.un_data16[1] - -/* MLDv2 Query */ -struct mld2_query { - struct icmp6hdr mld2q_hdr; - struct in6_addr mld2q_mca; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 mld2q_qrv:3, - mld2q_suppress:1, - mld2q_resv2:4; -#elif defined(__BIG_ENDIAN_BITFIELD) - __u8 mld2q_resv2:4, - mld2q_suppress:1, - mld2q_qrv:3; -#else -#error "Please fix " -#endif - __u8 mld2q_qqic; - __be16 mld2q_nsrcs; - struct in6_addr mld2q_srcs[0]; -}; - -#define mld2q_type mld2q_hdr.icmp6_type -#define mld2q_code mld2q_hdr.icmp6_code -#define mld2q_cksum mld2q_hdr.icmp6_cksum -#define mld2q_mrc mld2q_hdr.icmp6_maxdelay -#define mld2q_resv1 mld2q_hdr.icmp6_dataun.un_data16[1] - -/* RFC3810, 5.1.3. Maximum Response Code: - * - * If Maximum Response Code >= 32768, Maximum Response Code represents a - * floating-point value as follows: - * - * 0 1 2 3 4 5 6 7 8 9 A B C D E F - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * |1| exp | mant | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ -#define MLDV2_MRC_EXP(value) (((value) >> 12) & 0x0007) -#define MLDV2_MRC_MAN(value) ((value) & 0x0fff) - -/* RFC3810, 5.1.9. QQIC (Querier's Query Interval Code): - * - * If QQIC >= 128, QQIC represents a floating-point value as follows: - * - * 0 1 2 3 4 5 6 7 - * +-+-+-+-+-+-+-+-+ - * |1| exp | mant | - * +-+-+-+-+-+-+-+-+ - */ -#define MLDV2_QQIC_EXP(value) (((value) >> 4) & 0x07) -#define MLDV2_QQIC_MAN(value) ((value) & 0x0f) - -#define MLD_EXP_MIN_LIMIT 32768UL -#define MLDV1_MRD_MAX_COMPAT (MLD_EXP_MIN_LIMIT - 1) - -static inline unsigned long mldv2_mrc(const struct mld2_query *mlh2) -{ - /* RFC3810, 5.1.3. Maximum Response Code */ - unsigned long ret, mc_mrc = ntohs(mlh2->mld2q_mrc); - - if (mc_mrc < MLD_EXP_MIN_LIMIT) { - ret = mc_mrc; - } else { - unsigned long mc_man, mc_exp; - - mc_exp = MLDV2_MRC_EXP(mc_mrc); - mc_man = MLDV2_MRC_MAN(mc_mrc); - - ret = (mc_man | 0x1000) << (mc_exp + 3); - } - - return ret; -} - -#endif diff --git a/src/linux/include/net/mpls.h b/src/linux/include/net/mpls.h deleted file mode 100644 index 1dbc669..0000000 --- a/src/linux/include/net/mpls.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2014 Nicira, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#ifndef _NET_MPLS_H -#define _NET_MPLS_H 1 - -#include -#include - -#define MPLS_HLEN 4 - -struct mpls_shim_hdr { - __be32 label_stack_entry; -}; - -static inline bool eth_p_mpls(__be16 eth_type) -{ - return eth_type == htons(ETH_P_MPLS_UC) || - eth_type == htons(ETH_P_MPLS_MC); -} - -static inline struct mpls_shim_hdr *mpls_hdr(const struct sk_buff *skb) -{ - return (struct mpls_shim_hdr *)skb_network_header(skb); -} -#endif diff --git a/src/linux/include/net/ndisc.h b/src/linux/include/net/ndisc.h deleted file mode 100644 index be1fe22..0000000 --- a/src/linux/include/net/ndisc.h +++ /dev/null @@ -1,440 +0,0 @@ -#ifndef _NDISC_H -#define _NDISC_H - -/* - * ICMP codes for neighbour discovery messages - */ - -#define NDISC_ROUTER_SOLICITATION 133 -#define NDISC_ROUTER_ADVERTISEMENT 134 -#define NDISC_NEIGHBOUR_SOLICITATION 135 -#define NDISC_NEIGHBOUR_ADVERTISEMENT 136 -#define NDISC_REDIRECT 137 - -/* - * Router type: cross-layer information from link-layer to - * IPv6 layer reported by certain link types (e.g., RFC4214). - */ -#define NDISC_NODETYPE_UNSPEC 0 /* unspecified (default) */ -#define NDISC_NODETYPE_HOST 1 /* host or unauthorized router */ -#define NDISC_NODETYPE_NODEFAULT 2 /* non-default router */ -#define NDISC_NODETYPE_DEFAULT 3 /* default router */ - -/* - * ndisc options - */ - -enum { - __ND_OPT_PREFIX_INFO_END = 0, - ND_OPT_SOURCE_LL_ADDR = 1, /* RFC2461 */ - ND_OPT_TARGET_LL_ADDR = 2, /* RFC2461 */ - ND_OPT_PREFIX_INFO = 3, /* RFC2461 */ - ND_OPT_REDIRECT_HDR = 4, /* RFC2461 */ - ND_OPT_MTU = 5, /* RFC2461 */ - __ND_OPT_ARRAY_MAX, - ND_OPT_ROUTE_INFO = 24, /* RFC4191 */ - ND_OPT_RDNSS = 25, /* RFC5006 */ - ND_OPT_DNSSL = 31, /* RFC6106 */ - ND_OPT_6CO = 34, /* RFC6775 */ - __ND_OPT_MAX -}; - -#define MAX_RTR_SOLICITATION_DELAY HZ - -#define ND_REACHABLE_TIME (30*HZ) -#define ND_RETRANS_TIMER HZ - -#include -#include -#include -#include -#include -#include -#include - -#include - -/* Set to 3 to get tracing... */ -#define ND_DEBUG 1 - -#define ND_PRINTK(val, level, fmt, ...) \ -do { \ - if (val <= ND_DEBUG) \ - net_##level##_ratelimited(fmt, ##__VA_ARGS__); \ -} while (0) - -struct ctl_table; -struct inet6_dev; -struct net_device; -struct net_proto_family; -struct sk_buff; -struct prefix_info; - -extern struct neigh_table nd_tbl; - -struct nd_msg { - struct icmp6hdr icmph; - struct in6_addr target; - __u8 opt[0]; -}; - -struct rs_msg { - struct icmp6hdr icmph; - __u8 opt[0]; -}; - -struct ra_msg { - struct icmp6hdr icmph; - __be32 reachable_time; - __be32 retrans_timer; -}; - -struct rd_msg { - struct icmp6hdr icmph; - struct in6_addr target; - struct in6_addr dest; - __u8 opt[0]; -}; - -struct nd_opt_hdr { - __u8 nd_opt_type; - __u8 nd_opt_len; -} __packed; - -/* ND options */ -struct ndisc_options { - struct nd_opt_hdr *nd_opt_array[__ND_OPT_ARRAY_MAX]; -#ifdef CONFIG_IPV6_ROUTE_INFO - struct nd_opt_hdr *nd_opts_ri; - struct nd_opt_hdr *nd_opts_ri_end; -#endif - struct nd_opt_hdr *nd_useropts; - struct nd_opt_hdr *nd_useropts_end; -#if IS_ENABLED(CONFIG_IEEE802154_6LOWPAN) - struct nd_opt_hdr *nd_802154_opt_array[ND_OPT_TARGET_LL_ADDR + 1]; -#endif -}; - -#define nd_opts_src_lladdr nd_opt_array[ND_OPT_SOURCE_LL_ADDR] -#define nd_opts_tgt_lladdr nd_opt_array[ND_OPT_TARGET_LL_ADDR] -#define nd_opts_pi nd_opt_array[ND_OPT_PREFIX_INFO] -#define nd_opts_pi_end nd_opt_array[__ND_OPT_PREFIX_INFO_END] -#define nd_opts_rh nd_opt_array[ND_OPT_REDIRECT_HDR] -#define nd_opts_mtu nd_opt_array[ND_OPT_MTU] -#define nd_802154_opts_src_lladdr nd_802154_opt_array[ND_OPT_SOURCE_LL_ADDR] -#define nd_802154_opts_tgt_lladdr nd_802154_opt_array[ND_OPT_TARGET_LL_ADDR] - -#define NDISC_OPT_SPACE(len) (((len)+2+7)&~7) - -struct ndisc_options *ndisc_parse_options(const struct net_device *dev, - u8 *opt, int opt_len, - struct ndisc_options *ndopts); - -void __ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data, - int data_len, int pad); - -#define NDISC_OPS_REDIRECT_DATA_SPACE 2 - -/* - * This structure defines the hooks for IPv6 neighbour discovery. - * The following hooks can be defined; unless noted otherwise, they are - * optional and can be filled with a null pointer. - * - * int (*is_useropt)(u8 nd_opt_type): - * This function is called when IPv6 decide RA userspace options. if - * this function returns 1 then the option given by nd_opt_type will - * be handled as userspace option additional to the IPv6 options. - * - * int (*parse_options)(const struct net_device *dev, - * struct nd_opt_hdr *nd_opt, - * struct ndisc_options *ndopts): - * This function is called while parsing ndisc ops and put each position - * as pointer into ndopts. If this function return unequal 0, then this - * function took care about the ndisc option, if 0 then the IPv6 ndisc - * option parser will take care about that option. - * - * void (*update)(const struct net_device *dev, struct neighbour *n, - * u32 flags, u8 icmp6_type, - * const struct ndisc_options *ndopts): - * This function is called when IPv6 ndisc updates the neighbour cache - * entry. Additional options which can be updated may be previously - * parsed by parse_opts callback and accessible over ndopts parameter. - * - * int (*opt_addr_space)(const struct net_device *dev, u8 icmp6_type, - * struct neighbour *neigh, u8 *ha_buf, - * u8 **ha): - * This function is called when the necessary option space will be - * calculated before allocating a skb. The parameters neigh, ha_buf - * abd ha are available on NDISC_REDIRECT messages only. - * - * void (*fill_addr_option)(const struct net_device *dev, - * struct sk_buff *skb, u8 icmp6_type, - * const u8 *ha): - * This function is called when the skb will finally fill the option - * fields inside skb. NOTE: this callback should fill the option - * fields to the skb which are previously indicated by opt_space - * parameter. That means the decision to add such option should - * not lost between these two callbacks, e.g. protected by interface - * up state. - * - * void (*prefix_rcv_add_addr)(struct net *net, struct net_device *dev, - * const struct prefix_info *pinfo, - * struct inet6_dev *in6_dev, - * struct in6_addr *addr, - * int addr_type, u32 addr_flags, - * bool sllao, bool tokenized, - * __u32 valid_lft, u32 prefered_lft, - * bool dev_addr_generated): - * This function is called when a RA messages is received with valid - * PIO option fields and an IPv6 address will be added to the interface - * for autoconfiguration. The parameter dev_addr_generated reports about - * if the address was based on dev->dev_addr or not. This can be used - * to add a second address if link-layer operates with two link layer - * addresses. E.g. 802.15.4 6LoWPAN. - */ -struct ndisc_ops { - int (*is_useropt)(u8 nd_opt_type); - int (*parse_options)(const struct net_device *dev, - struct nd_opt_hdr *nd_opt, - struct ndisc_options *ndopts); - void (*update)(const struct net_device *dev, struct neighbour *n, - u32 flags, u8 icmp6_type, - const struct ndisc_options *ndopts); - int (*opt_addr_space)(const struct net_device *dev, u8 icmp6_type, - struct neighbour *neigh, u8 *ha_buf, - u8 **ha); - void (*fill_addr_option)(const struct net_device *dev, - struct sk_buff *skb, u8 icmp6_type, - const u8 *ha); - void (*prefix_rcv_add_addr)(struct net *net, struct net_device *dev, - const struct prefix_info *pinfo, - struct inet6_dev *in6_dev, - struct in6_addr *addr, - int addr_type, u32 addr_flags, - bool sllao, bool tokenized, - __u32 valid_lft, u32 prefered_lft, - bool dev_addr_generated); -}; - -#if IS_ENABLED(CONFIG_IPV6) -static inline int ndisc_ops_is_useropt(const struct net_device *dev, - u8 nd_opt_type) -{ - if (dev->ndisc_ops && dev->ndisc_ops->is_useropt) - return dev->ndisc_ops->is_useropt(nd_opt_type); - else - return 0; -} - -static inline int ndisc_ops_parse_options(const struct net_device *dev, - struct nd_opt_hdr *nd_opt, - struct ndisc_options *ndopts) -{ - if (dev->ndisc_ops && dev->ndisc_ops->parse_options) - return dev->ndisc_ops->parse_options(dev, nd_opt, ndopts); - else - return 0; -} - -static inline void ndisc_ops_update(const struct net_device *dev, - struct neighbour *n, u32 flags, - u8 icmp6_type, - const struct ndisc_options *ndopts) -{ - if (dev->ndisc_ops && dev->ndisc_ops->update) - dev->ndisc_ops->update(dev, n, flags, icmp6_type, ndopts); -} - -static inline int ndisc_ops_opt_addr_space(const struct net_device *dev, - u8 icmp6_type) -{ - if (dev->ndisc_ops && dev->ndisc_ops->opt_addr_space && - icmp6_type != NDISC_REDIRECT) - return dev->ndisc_ops->opt_addr_space(dev, icmp6_type, NULL, - NULL, NULL); - else - return 0; -} - -static inline int ndisc_ops_redirect_opt_addr_space(const struct net_device *dev, - struct neighbour *neigh, - u8 *ha_buf, u8 **ha) -{ - if (dev->ndisc_ops && dev->ndisc_ops->opt_addr_space) - return dev->ndisc_ops->opt_addr_space(dev, NDISC_REDIRECT, - neigh, ha_buf, ha); - else - return 0; -} - -static inline void ndisc_ops_fill_addr_option(const struct net_device *dev, - struct sk_buff *skb, - u8 icmp6_type) -{ - if (dev->ndisc_ops && dev->ndisc_ops->fill_addr_option && - icmp6_type != NDISC_REDIRECT) - dev->ndisc_ops->fill_addr_option(dev, skb, icmp6_type, NULL); -} - -static inline void ndisc_ops_fill_redirect_addr_option(const struct net_device *dev, - struct sk_buff *skb, - const u8 *ha) -{ - if (dev->ndisc_ops && dev->ndisc_ops->fill_addr_option) - dev->ndisc_ops->fill_addr_option(dev, skb, NDISC_REDIRECT, ha); -} - -static inline void ndisc_ops_prefix_rcv_add_addr(struct net *net, - struct net_device *dev, - const struct prefix_info *pinfo, - struct inet6_dev *in6_dev, - struct in6_addr *addr, - int addr_type, u32 addr_flags, - bool sllao, bool tokenized, - __u32 valid_lft, - u32 prefered_lft, - bool dev_addr_generated) -{ - if (dev->ndisc_ops && dev->ndisc_ops->prefix_rcv_add_addr) - dev->ndisc_ops->prefix_rcv_add_addr(net, dev, pinfo, in6_dev, - addr, addr_type, - addr_flags, sllao, - tokenized, valid_lft, - prefered_lft, - dev_addr_generated); -} -#endif - -/* - * Return the padding between the option length and the start of the - * link addr. Currently only IP-over-InfiniBand needs this, although - * if RFC 3831 IPv6-over-Fibre Channel is ever implemented it may - * also need a pad of 2. - */ -static inline int ndisc_addr_option_pad(unsigned short type) -{ - switch (type) { - case ARPHRD_INFINIBAND: return 2; - default: return 0; - } -} - -static inline int __ndisc_opt_addr_space(unsigned char addr_len, int pad) -{ - return NDISC_OPT_SPACE(addr_len + pad); -} - -#if IS_ENABLED(CONFIG_IPV6) -static inline int ndisc_opt_addr_space(struct net_device *dev, u8 icmp6_type) -{ - return __ndisc_opt_addr_space(dev->addr_len, - ndisc_addr_option_pad(dev->type)) + - ndisc_ops_opt_addr_space(dev, icmp6_type); -} - -static inline int ndisc_redirect_opt_addr_space(struct net_device *dev, - struct neighbour *neigh, - u8 *ops_data_buf, - u8 **ops_data) -{ - return __ndisc_opt_addr_space(dev->addr_len, - ndisc_addr_option_pad(dev->type)) + - ndisc_ops_redirect_opt_addr_space(dev, neigh, ops_data_buf, - ops_data); -} -#endif - -static inline u8 *__ndisc_opt_addr_data(struct nd_opt_hdr *p, - unsigned char addr_len, int prepad) -{ - u8 *lladdr = (u8 *)(p + 1); - int lladdrlen = p->nd_opt_len << 3; - if (lladdrlen != __ndisc_opt_addr_space(addr_len, prepad)) - return NULL; - return lladdr + prepad; -} - -static inline u8 *ndisc_opt_addr_data(struct nd_opt_hdr *p, - struct net_device *dev) -{ - return __ndisc_opt_addr_data(p, dev->addr_len, - ndisc_addr_option_pad(dev->type)); -} - -static inline u32 ndisc_hashfn(const void *pkey, const struct net_device *dev, __u32 *hash_rnd) -{ - const u32 *p32 = pkey; - - return (((p32[0] ^ hash32_ptr(dev)) * hash_rnd[0]) + - (p32[1] * hash_rnd[1]) + - (p32[2] * hash_rnd[2]) + - (p32[3] * hash_rnd[3])); -} - -static inline struct neighbour *__ipv6_neigh_lookup_noref(struct net_device *dev, const void *pkey) -{ - return ___neigh_lookup_noref(&nd_tbl, neigh_key_eq128, ndisc_hashfn, pkey, dev); -} - -static inline struct neighbour *__ipv6_neigh_lookup(struct net_device *dev, const void *pkey) -{ - struct neighbour *n; - - rcu_read_lock_bh(); - n = __ipv6_neigh_lookup_noref(dev, pkey); - if (n && !atomic_inc_not_zero(&n->refcnt)) - n = NULL; - rcu_read_unlock_bh(); - - return n; -} - -int ndisc_init(void); -int ndisc_late_init(void); - -void ndisc_late_cleanup(void); -void ndisc_cleanup(void); - -int ndisc_rcv(struct sk_buff *skb); - -void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit, - const struct in6_addr *daddr, const struct in6_addr *saddr); - -void ndisc_send_rs(struct net_device *dev, - const struct in6_addr *saddr, const struct in6_addr *daddr); -void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr, - const struct in6_addr *solicited_addr, - bool router, bool solicited, bool override, bool inc_opt); - -void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target); - -int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, - int dir); - -void ndisc_update(const struct net_device *dev, struct neighbour *neigh, - const u8 *lladdr, u8 new, u32 flags, u8 icmp6_type, - struct ndisc_options *ndopts); - -/* - * IGMP - */ -int igmp6_init(void); - -void igmp6_cleanup(void); - -int igmp6_event_query(struct sk_buff *skb); - -int igmp6_event_report(struct sk_buff *skb); - - -#ifdef CONFIG_SYSCTL -int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); -int ndisc_ifinfo_sysctl_strategy(struct ctl_table *ctl, - void __user *oldval, size_t __user *oldlenp, - void __user *newval, size_t newlen); -#endif - -void inet6_ifinfo_notify(int event, struct inet6_dev *idev); - -#endif diff --git a/src/linux/include/net/neighbour.h b/src/linux/include/net/neighbour.h deleted file mode 100644 index 8b68384..0000000 --- a/src/linux/include/net/neighbour.h +++ /dev/null @@ -1,516 +0,0 @@ -#ifndef _NET_NEIGHBOUR_H -#define _NET_NEIGHBOUR_H - -#include - -/* - * Generic neighbour manipulation - * - * Authors: - * Pedro Roque - * Alexey Kuznetsov - * - * Changes: - * - * Harald Welte: - * - Add neighbour cache statistics like rtstat - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -/* - * NUD stands for "neighbor unreachability detection" - */ - -#define NUD_IN_TIMER (NUD_INCOMPLETE|NUD_REACHABLE|NUD_DELAY|NUD_PROBE) -#define NUD_VALID (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE|NUD_PROBE|NUD_STALE|NUD_DELAY) -#define NUD_CONNECTED (NUD_PERMANENT|NUD_NOARP|NUD_REACHABLE) - -struct neighbour; - -enum { - NEIGH_VAR_MCAST_PROBES, - NEIGH_VAR_UCAST_PROBES, - NEIGH_VAR_APP_PROBES, - NEIGH_VAR_MCAST_REPROBES, - NEIGH_VAR_RETRANS_TIME, - NEIGH_VAR_BASE_REACHABLE_TIME, - NEIGH_VAR_DELAY_PROBE_TIME, - NEIGH_VAR_GC_STALETIME, - NEIGH_VAR_QUEUE_LEN_BYTES, - NEIGH_VAR_PROXY_QLEN, - NEIGH_VAR_ANYCAST_DELAY, - NEIGH_VAR_PROXY_DELAY, - NEIGH_VAR_LOCKTIME, -#define NEIGH_VAR_DATA_MAX (NEIGH_VAR_LOCKTIME + 1) - /* Following are used as a second way to access one of the above */ - NEIGH_VAR_QUEUE_LEN, /* same data as NEIGH_VAR_QUEUE_LEN_BYTES */ - NEIGH_VAR_RETRANS_TIME_MS, /* same data as NEIGH_VAR_RETRANS_TIME */ - NEIGH_VAR_BASE_REACHABLE_TIME_MS, /* same data as NEIGH_VAR_BASE_REACHABLE_TIME */ - /* Following are used by "default" only */ - NEIGH_VAR_GC_INTERVAL, - NEIGH_VAR_GC_THRESH1, - NEIGH_VAR_GC_THRESH2, - NEIGH_VAR_GC_THRESH3, - NEIGH_VAR_MAX -}; - -struct neigh_parms { - possible_net_t net; - struct net_device *dev; - struct list_head list; - int (*neigh_setup)(struct neighbour *); - void (*neigh_cleanup)(struct neighbour *); - struct neigh_table *tbl; - - void *sysctl_table; - - int dead; - atomic_t refcnt; - struct rcu_head rcu_head; - - int reachable_time; - int data[NEIGH_VAR_DATA_MAX]; - DECLARE_BITMAP(data_state, NEIGH_VAR_DATA_MAX); -}; - -static inline void neigh_var_set(struct neigh_parms *p, int index, int val) -{ - set_bit(index, p->data_state); - p->data[index] = val; -} - -#define NEIGH_VAR(p, attr) ((p)->data[NEIGH_VAR_ ## attr]) - -/* In ndo_neigh_setup, NEIGH_VAR_INIT should be used. - * In other cases, NEIGH_VAR_SET should be used. - */ -#define NEIGH_VAR_INIT(p, attr, val) (NEIGH_VAR(p, attr) = val) -#define NEIGH_VAR_SET(p, attr, val) neigh_var_set(p, NEIGH_VAR_ ## attr, val) - -static inline void neigh_parms_data_state_setall(struct neigh_parms *p) -{ - bitmap_fill(p->data_state, NEIGH_VAR_DATA_MAX); -} - -static inline void neigh_parms_data_state_cleanall(struct neigh_parms *p) -{ - bitmap_zero(p->data_state, NEIGH_VAR_DATA_MAX); -} - -struct neigh_statistics { - unsigned long allocs; /* number of allocated neighs */ - unsigned long destroys; /* number of destroyed neighs */ - unsigned long hash_grows; /* number of hash resizes */ - - unsigned long res_failed; /* number of failed resolutions */ - - unsigned long lookups; /* number of lookups */ - unsigned long hits; /* number of hits (among lookups) */ - - unsigned long rcv_probes_mcast; /* number of received mcast ipv6 */ - unsigned long rcv_probes_ucast; /* number of received ucast ipv6 */ - - unsigned long periodic_gc_runs; /* number of periodic GC runs */ - unsigned long forced_gc_runs; /* number of forced GC runs */ - - unsigned long unres_discards; /* number of unresolved drops */ - unsigned long table_fulls; /* times even gc couldn't help */ -}; - -#define NEIGH_CACHE_STAT_INC(tbl, field) this_cpu_inc((tbl)->stats->field) - -struct neighbour { - struct neighbour __rcu *next; - struct neigh_table *tbl; - struct neigh_parms *parms; - unsigned long confirmed; - unsigned long updated; - rwlock_t lock; - atomic_t refcnt; - struct sk_buff_head arp_queue; - unsigned int arp_queue_len_bytes; - struct timer_list timer; - unsigned long used; - atomic_t probes; - __u8 flags; - __u8 nud_state; - __u8 type; - __u8 dead; - seqlock_t ha_lock; - unsigned char ha[ALIGN(MAX_ADDR_LEN, sizeof(unsigned long))]; - struct hh_cache hh; - int (*output)(struct neighbour *, struct sk_buff *); - const struct neigh_ops *ops; - struct rcu_head rcu; - struct net_device *dev; - u8 primary_key[0]; -}; - -struct neigh_ops { - int family; - void (*solicit)(struct neighbour *, struct sk_buff *); - void (*error_report)(struct neighbour *, struct sk_buff *); - int (*output)(struct neighbour *, struct sk_buff *); - int (*connected_output)(struct neighbour *, struct sk_buff *); -}; - -struct pneigh_entry { - struct pneigh_entry *next; - possible_net_t net; - struct net_device *dev; - u8 flags; - u8 key[0]; -}; - -/* - * neighbour table manipulation - */ - -#define NEIGH_NUM_HASH_RND 4 - -struct neigh_hash_table { - struct neighbour __rcu **hash_buckets; - unsigned int hash_shift; - __u32 hash_rnd[NEIGH_NUM_HASH_RND]; - struct rcu_head rcu; -}; - - -struct neigh_table { - int family; - int entry_size; - int key_len; - __be16 protocol; - __u32 (*hash)(const void *pkey, - const struct net_device *dev, - __u32 *hash_rnd); - bool (*key_eq)(const struct neighbour *, const void *pkey); - int (*constructor)(struct neighbour *); - int (*pconstructor)(struct pneigh_entry *); - void (*pdestructor)(struct pneigh_entry *); - void (*proxy_redo)(struct sk_buff *skb); - char *id; - struct neigh_parms parms; - struct list_head parms_list; - int gc_interval; - int gc_thresh1; - int gc_thresh2; - int gc_thresh3; - unsigned long last_flush; - struct delayed_work gc_work; - struct timer_list proxy_timer; - struct sk_buff_head proxy_queue; - atomic_t entries; - rwlock_t lock; - unsigned long last_rand; - struct neigh_statistics __percpu *stats; - struct neigh_hash_table __rcu *nht; - struct pneigh_entry **phash_buckets; -}; - -enum { - NEIGH_ARP_TABLE = 0, - NEIGH_ND_TABLE = 1, - NEIGH_DN_TABLE = 2, - NEIGH_NR_TABLES, - NEIGH_LINK_TABLE = NEIGH_NR_TABLES /* Pseudo table for neigh_xmit */ -}; - -static inline int neigh_parms_family(struct neigh_parms *p) -{ - return p->tbl->family; -} - -#define NEIGH_PRIV_ALIGN sizeof(long long) -#define NEIGH_ENTRY_SIZE(size) ALIGN((size), NEIGH_PRIV_ALIGN) - -static inline void *neighbour_priv(const struct neighbour *n) -{ - return (char *)n + n->tbl->entry_size; -} - -/* flags for neigh_update() */ -#define NEIGH_UPDATE_F_OVERRIDE 0x00000001 -#define NEIGH_UPDATE_F_WEAK_OVERRIDE 0x00000002 -#define NEIGH_UPDATE_F_OVERRIDE_ISROUTER 0x00000004 -#define NEIGH_UPDATE_F_ISROUTER 0x40000000 -#define NEIGH_UPDATE_F_ADMIN 0x80000000 - - -static inline bool neigh_key_eq16(const struct neighbour *n, const void *pkey) -{ - return *(const u16 *)n->primary_key == *(const u16 *)pkey; -} - -static inline bool neigh_key_eq32(const struct neighbour *n, const void *pkey) -{ - return *(const u32 *)n->primary_key == *(const u32 *)pkey; -} - -static inline bool neigh_key_eq128(const struct neighbour *n, const void *pkey) -{ - const u32 *n32 = (const u32 *)n->primary_key; - const u32 *p32 = pkey; - - return ((n32[0] ^ p32[0]) | (n32[1] ^ p32[1]) | - (n32[2] ^ p32[2]) | (n32[3] ^ p32[3])) == 0; -} - -static inline struct neighbour *___neigh_lookup_noref( - struct neigh_table *tbl, - bool (*key_eq)(const struct neighbour *n, const void *pkey), - __u32 (*hash)(const void *pkey, - const struct net_device *dev, - __u32 *hash_rnd), - const void *pkey, - struct net_device *dev) -{ - struct neigh_hash_table *nht = rcu_dereference_bh(tbl->nht); - struct neighbour *n; - u32 hash_val; - - hash_val = hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift); - for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]); - n != NULL; - n = rcu_dereference_bh(n->next)) { - if (n->dev == dev && key_eq(n, pkey)) - return n; - } - - return NULL; -} - -static inline struct neighbour *__neigh_lookup_noref(struct neigh_table *tbl, - const void *pkey, - struct net_device *dev) -{ - return ___neigh_lookup_noref(tbl, tbl->key_eq, tbl->hash, pkey, dev); -} - -void neigh_table_init(int index, struct neigh_table *tbl); -int neigh_table_clear(int index, struct neigh_table *tbl); -struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey, - struct net_device *dev); -struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net, - const void *pkey); -struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey, - struct net_device *dev, bool want_ref); -static inline struct neighbour *neigh_create(struct neigh_table *tbl, - const void *pkey, - struct net_device *dev) -{ - return __neigh_create(tbl, pkey, dev, true); -} -void neigh_destroy(struct neighbour *neigh); -int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb); -int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, u32 flags); -void __neigh_set_probe_once(struct neighbour *neigh); -void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev); -int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev); -int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb); -int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb); -int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb); -struct neighbour *neigh_event_ns(struct neigh_table *tbl, - u8 *lladdr, void *saddr, - struct net_device *dev); - -struct neigh_parms *neigh_parms_alloc(struct net_device *dev, - struct neigh_table *tbl); -void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms); - -static inline -struct net *neigh_parms_net(const struct neigh_parms *parms) -{ - return read_pnet(&parms->net); -} - -unsigned long neigh_rand_reach_time(unsigned long base); - -void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, - struct sk_buff *skb); -struct pneigh_entry *pneigh_lookup(struct neigh_table *tbl, struct net *net, - const void *key, struct net_device *dev, - int creat); -struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl, struct net *net, - const void *key, struct net_device *dev); -int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *key, - struct net_device *dev); - -static inline struct net *pneigh_net(const struct pneigh_entry *pneigh) -{ - return read_pnet(&pneigh->net); -} - -void neigh_app_ns(struct neighbour *n); -void neigh_for_each(struct neigh_table *tbl, - void (*cb)(struct neighbour *, void *), void *cookie); -void __neigh_for_each_release(struct neigh_table *tbl, - int (*cb)(struct neighbour *)); -int neigh_xmit(int fam, struct net_device *, const void *, struct sk_buff *); -void pneigh_for_each(struct neigh_table *tbl, - void (*cb)(struct pneigh_entry *)); - -struct neigh_seq_state { - struct seq_net_private p; - struct neigh_table *tbl; - struct neigh_hash_table *nht; - void *(*neigh_sub_iter)(struct neigh_seq_state *state, - struct neighbour *n, loff_t *pos); - unsigned int bucket; - unsigned int flags; -#define NEIGH_SEQ_NEIGH_ONLY 0x00000001 -#define NEIGH_SEQ_IS_PNEIGH 0x00000002 -#define NEIGH_SEQ_SKIP_NOARP 0x00000004 -}; -void *neigh_seq_start(struct seq_file *, loff_t *, struct neigh_table *, - unsigned int); -void *neigh_seq_next(struct seq_file *, void *, loff_t *); -void neigh_seq_stop(struct seq_file *, void *); - -int neigh_proc_dointvec(struct ctl_table *ctl, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); -int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos); -int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos); - -int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, - proc_handler *proc_handler); -void neigh_sysctl_unregister(struct neigh_parms *p); - -static inline void __neigh_parms_put(struct neigh_parms *parms) -{ - atomic_dec(&parms->refcnt); -} - -static inline struct neigh_parms *neigh_parms_clone(struct neigh_parms *parms) -{ - atomic_inc(&parms->refcnt); - return parms; -} - -/* - * Neighbour references - */ - -static inline void neigh_release(struct neighbour *neigh) -{ - if (atomic_dec_and_test(&neigh->refcnt)) - neigh_destroy(neigh); -} - -static inline struct neighbour * neigh_clone(struct neighbour *neigh) -{ - if (neigh) - atomic_inc(&neigh->refcnt); - return neigh; -} - -#define neigh_hold(n) atomic_inc(&(n)->refcnt) - -static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) -{ - unsigned long now = jiffies; - - if (neigh->used != now) - neigh->used = now; - if (!(neigh->nud_state&(NUD_CONNECTED|NUD_DELAY|NUD_PROBE))) - return __neigh_event_send(neigh, skb); - return 0; -} - -#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) -static inline int neigh_hh_bridge(struct hh_cache *hh, struct sk_buff *skb) -{ - unsigned int seq, hh_alen; - - do { - seq = read_seqbegin(&hh->hh_lock); - hh_alen = HH_DATA_ALIGN(ETH_HLEN); - memcpy(skb->data - hh_alen, hh->hh_data, ETH_ALEN + hh_alen - ETH_HLEN); - } while (read_seqretry(&hh->hh_lock, seq)); - return 0; -} -#endif - -static inline int neigh_hh_output(const struct hh_cache *hh, struct sk_buff *skb) -{ - unsigned int seq; - int hh_len; - - do { - seq = read_seqbegin(&hh->hh_lock); - hh_len = hh->hh_len; - if (likely(hh_len <= HH_DATA_MOD)) { - /* this is inlined by gcc */ - memcpy(skb->data - HH_DATA_MOD, hh->hh_data, HH_DATA_MOD); - } else { - int hh_alen = HH_DATA_ALIGN(hh_len); - - memcpy(skb->data - hh_alen, hh->hh_data, hh_alen); - } - } while (read_seqretry(&hh->hh_lock, seq)); - - skb_push(skb, hh_len); - return dev_queue_xmit(skb); -} - -static inline struct neighbour * -__neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat) -{ - struct neighbour *n = neigh_lookup(tbl, pkey, dev); - - if (n || !creat) - return n; - - n = neigh_create(tbl, pkey, dev); - return IS_ERR(n) ? NULL : n; -} - -static inline struct neighbour * -__neigh_lookup_errno(struct neigh_table *tbl, const void *pkey, - struct net_device *dev) -{ - struct neighbour *n = neigh_lookup(tbl, pkey, dev); - - if (n) - return n; - - return neigh_create(tbl, pkey, dev); -} - -struct neighbour_cb { - unsigned long sched_next; - unsigned int flags; -}; - -#define LOCALLY_ENQUEUED 0x1 - -#define NEIGH_CB(skb) ((struct neighbour_cb *)(skb)->cb) - -static inline void neigh_ha_snapshot(char *dst, const struct neighbour *n, - const struct net_device *dev) -{ - unsigned int seq; - - do { - seq = read_seqbegin(&n->ha_lock); - memcpy(dst, n->ha, dev->addr_len); - } while (read_seqretry(&n->ha_lock, seq)); -} - - -#endif diff --git a/src/linux/include/net/net_namespace.h b/src/linux/include/net/net_namespace.h deleted file mode 100644 index 0940598..0000000 --- a/src/linux/include/net/net_namespace.h +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Operations on the network namespace - */ -#ifndef __NET_NET_NAMESPACE_H -#define __NET_NET_NAMESPACE_H - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) -#include -#endif -#include -#include -#include -#include -#include -#include - -struct user_namespace; -struct proc_dir_entry; -struct net_device; -struct sock; -struct ctl_table_header; -struct net_generic; -struct sock; -struct netns_ipvs; - - -#define NETDEV_HASHBITS 8 -#define NETDEV_HASHENTRIES (1 << NETDEV_HASHBITS) - -struct net { - atomic_t passive; /* To decided when the network - * namespace should be freed. - */ - atomic_t count; /* To decided when the network - * namespace should be shut down. - */ - spinlock_t rules_mod_lock; - - atomic64_t cookie_gen; - - struct list_head list; /* list of network namespaces */ - struct list_head cleanup_list; /* namespaces on death row */ - struct list_head exit_list; /* Use only net_mutex */ - - struct user_namespace *user_ns; /* Owning user namespace */ - struct ucounts *ucounts; - spinlock_t nsid_lock; - struct idr netns_ids; - - struct ns_common ns; - - struct proc_dir_entry *proc_net; - struct proc_dir_entry *proc_net_stat; - -#ifdef CONFIG_SYSCTL - struct ctl_table_set sysctls; -#endif - - struct sock *rtnl; /* rtnetlink socket */ - struct sock *genl_sock; - - struct list_head dev_base_head; - struct hlist_head *dev_name_head; - struct hlist_head *dev_index_head; - unsigned int dev_base_seq; /* protected by rtnl_mutex */ - int ifindex; - unsigned int dev_unreg_count; - - /* core fib_rules */ - struct list_head rules_ops; - - - struct net_device *loopback_dev; /* The loopback */ - struct netns_core core; - struct netns_mib mib; - struct netns_packet packet; - struct netns_unix unx; - struct netns_ipv4 ipv4; -#if IS_ENABLED(CONFIG_IPV6) - struct netns_ipv6 ipv6; -#endif -#if IS_ENABLED(CONFIG_IEEE802154_6LOWPAN) - struct netns_ieee802154_lowpan ieee802154_lowpan; -#endif -#if defined(CONFIG_IP_SCTP) || defined(CONFIG_IP_SCTP_MODULE) - struct netns_sctp sctp; -#endif -#if defined(CONFIG_IP_DCCP) || defined(CONFIG_IP_DCCP_MODULE) - struct netns_dccp dccp; -#endif -#ifdef CONFIG_NETFILTER - struct netns_nf nf; - struct netns_xt xt; -#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) - struct netns_ct ct; -#endif -#if defined(CONFIG_NF_TABLES) || defined(CONFIG_NF_TABLES_MODULE) - struct netns_nftables nft; -#endif -#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) - struct netns_nf_frag nf_frag; -#endif - struct sock *nfnl; - struct sock *nfnl_stash; -#if IS_ENABLED(CONFIG_NETFILTER_NETLINK_ACCT) - struct list_head nfnl_acct_list; -#endif -#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) - struct list_head nfct_timeout_list; -#endif -#endif -#ifdef CONFIG_WEXT_CORE - struct sk_buff_head wext_nlevents; -#endif - struct net_generic __rcu *gen; - - /* Note : following structs are cache line aligned */ -#ifdef CONFIG_XFRM - struct netns_xfrm xfrm; -#endif -#if IS_ENABLED(CONFIG_IP_VS) - struct netns_ipvs *ipvs; -#endif -#if IS_ENABLED(CONFIG_MPLS) - struct netns_mpls mpls; -#endif - struct sock *diag_nlsk; - atomic_t fnhe_genid; -}; - -#include - -/* Init's network namespace */ -extern struct net init_net; - -#ifdef CONFIG_NET_NS -struct net *copy_net_ns(unsigned long flags, struct user_namespace *user_ns, - struct net *old_net); - -#else /* CONFIG_NET_NS */ -#include -#include -static inline struct net *copy_net_ns(unsigned long flags, - struct user_namespace *user_ns, struct net *old_net) -{ - if (flags & CLONE_NEWNET) - return ERR_PTR(-EINVAL); - return old_net; -} -#endif /* CONFIG_NET_NS */ - - -extern struct list_head net_namespace_list; - -struct net *get_net_ns_by_pid(pid_t pid); -struct net *get_net_ns_by_fd(int fd); - -#ifdef CONFIG_SYSCTL -void ipx_register_sysctl(void); -void ipx_unregister_sysctl(void); -#else -#define ipx_register_sysctl() -#define ipx_unregister_sysctl() -#endif - -#ifdef CONFIG_NET_NS -void __put_net(struct net *net); - -static inline struct net *get_net(struct net *net) -{ - atomic_inc(&net->count); - return net; -} - -static inline struct net *maybe_get_net(struct net *net) -{ - /* Used when we know struct net exists but we - * aren't guaranteed a previous reference count - * exists. If the reference count is zero this - * function fails and returns NULL. - */ - if (!atomic_inc_not_zero(&net->count)) - net = NULL; - return net; -} - -static inline void put_net(struct net *net) -{ - if (atomic_dec_and_test(&net->count)) - __put_net(net); -} - -static inline -int net_eq(const struct net *net1, const struct net *net2) -{ - return net1 == net2; -} - -void net_drop_ns(void *); - -#else - -static inline struct net *get_net(struct net *net) -{ - return net; -} - -static inline void put_net(struct net *net) -{ -} - -static inline struct net *maybe_get_net(struct net *net) -{ - return net; -} - -static inline -int net_eq(const struct net *net1, const struct net *net2) -{ - return 1; -} - -#define net_drop_ns NULL -#endif - - -typedef struct { -#ifdef CONFIG_NET_NS - struct net *net; -#endif -} possible_net_t; - -static inline void write_pnet(possible_net_t *pnet, struct net *net) -{ -#ifdef CONFIG_NET_NS - pnet->net = net; -#endif -} - -static inline struct net *read_pnet(const possible_net_t *pnet) -{ -#ifdef CONFIG_NET_NS - return pnet->net; -#else - return &init_net; -#endif -} - -#define for_each_net(VAR) \ - list_for_each_entry(VAR, &net_namespace_list, list) - -#define for_each_net_rcu(VAR) \ - list_for_each_entry_rcu(VAR, &net_namespace_list, list) - -#ifdef CONFIG_NET_NS -#define __net_init -#define __net_exit -#define __net_initdata -#define __net_initconst -#else -#define __net_init __init -#define __net_exit __ref -#define __net_initdata __initdata -#define __net_initconst __initconst -#endif - -int peernet2id_alloc(struct net *net, struct net *peer); -int peernet2id(struct net *net, struct net *peer); -bool peernet_has_id(struct net *net, struct net *peer); -struct net *get_net_ns_by_id(struct net *net, int id); - -struct pernet_operations { - struct list_head list; - int (*init)(struct net *net); - void (*exit)(struct net *net); - void (*exit_batch)(struct list_head *net_exit_list); - int *id; - size_t size; -}; - -/* - * Use these carefully. If you implement a network device and it - * needs per network namespace operations use device pernet operations, - * otherwise use pernet subsys operations. - * - * Network interfaces need to be removed from a dying netns _before_ - * subsys notifiers can be called, as most of the network code cleanup - * (which is done from subsys notifiers) runs with the assumption that - * dev_remove_pack has been called so no new packets will arrive during - * and after the cleanup functions have been called. dev_remove_pack - * is not per namespace so instead the guarantee of no more packets - * arriving in a network namespace is provided by ensuring that all - * network devices and all sockets have left the network namespace - * before the cleanup methods are called. - * - * For the longest time the ipv4 icmp code was registered as a pernet - * device which caused kernel oops, and panics during network - * namespace cleanup. So please don't get this wrong. - */ -int register_pernet_subsys(struct pernet_operations *); -void unregister_pernet_subsys(struct pernet_operations *); -int register_pernet_device(struct pernet_operations *); -void unregister_pernet_device(struct pernet_operations *); - -struct ctl_table; -struct ctl_table_header; - -#ifdef CONFIG_SYSCTL -int net_sysctl_init(void); -struct ctl_table_header *register_net_sysctl(struct net *net, const char *path, - struct ctl_table *table); -void unregister_net_sysctl_table(struct ctl_table_header *header); -#else -static inline int net_sysctl_init(void) { return 0; } -static inline struct ctl_table_header *register_net_sysctl(struct net *net, - const char *path, struct ctl_table *table) -{ - return NULL; -} -static inline void unregister_net_sysctl_table(struct ctl_table_header *header) -{ -} -#endif - -static inline int rt_genid_ipv4(struct net *net) -{ - return atomic_read(&net->ipv4.rt_genid); -} - -static inline void rt_genid_bump_ipv4(struct net *net) -{ - atomic_inc(&net->ipv4.rt_genid); -} - -extern void (*__fib6_flush_trees)(struct net *net); -static inline void rt_genid_bump_ipv6(struct net *net) -{ - if (__fib6_flush_trees) - __fib6_flush_trees(net); -} - -#if IS_ENABLED(CONFIG_IEEE802154_6LOWPAN) -static inline struct netns_ieee802154_lowpan * -net_ieee802154_lowpan(struct net *net) -{ - return &net->ieee802154_lowpan; -} -#endif - -/* For callers who don't really care about whether it's IPv4 or IPv6 */ -static inline void rt_genid_bump_all(struct net *net) -{ - rt_genid_bump_ipv4(net); - rt_genid_bump_ipv6(net); -} - -static inline int fnhe_genid(struct net *net) -{ - return atomic_read(&net->fnhe_genid); -} - -static inline void fnhe_genid_bump(struct net *net) -{ - atomic_inc(&net->fnhe_genid); -} - -#endif /* __NET_NET_NAMESPACE_H */ diff --git a/src/linux/include/net/net_ratelimit.h b/src/linux/include/net/net_ratelimit.h deleted file mode 100644 index 7727b42..0000000 --- a/src/linux/include/net/net_ratelimit.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _LINUX_NET_RATELIMIT_H -#define _LINUX_NET_RATELIMIT_H - -#include - -extern struct ratelimit_state net_ratelimit_state; - -#endif /* _LINUX_NET_RATELIMIT_H */ diff --git a/src/linux/include/net/netevent.h b/src/linux/include/net/netevent.h deleted file mode 100644 index f440df1..0000000 --- a/src/linux/include/net/netevent.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _NET_EVENT_H -#define _NET_EVENT_H - -/* - * Generic netevent notifiers - * - * Authors: - * Tom Tucker - * Steve Wise - * - * Changes: - */ - -struct dst_entry; -struct neighbour; - -struct netevent_redirect { - struct dst_entry *old; - struct dst_entry *new; - struct neighbour *neigh; - const void *daddr; -}; - -enum netevent_notif_type { - NETEVENT_NEIGH_UPDATE = 1, /* arg is struct neighbour ptr */ - NETEVENT_REDIRECT, /* arg is struct netevent_redirect ptr */ - NETEVENT_DELAY_PROBE_TIME_UPDATE, /* arg is struct neigh_parms ptr */ -}; - -int register_netevent_notifier(struct notifier_block *nb); -int unregister_netevent_notifier(struct notifier_block *nb); -int call_netevent_notifiers(unsigned long val, void *v); - -#endif diff --git a/src/linux/include/net/netlabel.h b/src/linux/include/net/netlabel.h deleted file mode 100644 index efe9806..0000000 --- a/src/linux/include/net/netlabel.h +++ /dev/null @@ -1,696 +0,0 @@ -/* - * NetLabel System - * - * The NetLabel system manages static and dynamic label mappings for network - * protocols such as CIPSO and RIPSO. - * - * Author: Paul Moore - * - */ - -/* - * (c) Copyright Hewlett-Packard Development Company, L.P., 2006, 2008 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - * - */ - -#ifndef _NETLABEL_H -#define _NETLABEL_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct cipso_v4_doi; -struct calipso_doi; - -/* - * NetLabel - A management interface for maintaining network packet label - * mapping tables for explicit packet labling protocols. - * - * Network protocols such as CIPSO and RIPSO require a label translation layer - * to convert the label on the packet into something meaningful on the host - * machine. In the current Linux implementation these mapping tables live - * inside the kernel; NetLabel provides a mechanism for user space applications - * to manage these mapping tables. - * - * NetLabel makes use of the Generic NETLINK mechanism as a transport layer to - * send messages between kernel and user space. The general format of a - * NetLabel message is shown below: - * - * +-----------------+-------------------+--------- --- -- - - * | struct nlmsghdr | struct genlmsghdr | payload - * +-----------------+-------------------+--------- --- -- - - * - * The 'nlmsghdr' and 'genlmsghdr' structs should be dealt with like normal. - * The payload is dependent on the subsystem specified in the - * 'nlmsghdr->nlmsg_type' and should be defined below, supporting functions - * should be defined in the corresponding net/netlabel/netlabel_.h|c - * file. All of the fields in the NetLabel payload are NETLINK attributes, see - * the include/net/netlink.h file for more information on NETLINK attributes. - * - */ - -/* - * NetLabel NETLINK protocol - */ - -/* NetLabel NETLINK protocol version - * 1: initial version - * 2: added static labels for unlabeled connections - * 3: network selectors added to the NetLabel/LSM domain mapping and the - * CIPSO_V4_MAP_LOCAL CIPSO mapping was added - */ -#define NETLBL_PROTO_VERSION 3 - -/* NetLabel NETLINK types/families */ -#define NETLBL_NLTYPE_NONE 0 -#define NETLBL_NLTYPE_MGMT 1 -#define NETLBL_NLTYPE_MGMT_NAME "NLBL_MGMT" -#define NETLBL_NLTYPE_RIPSO 2 -#define NETLBL_NLTYPE_RIPSO_NAME "NLBL_RIPSO" -#define NETLBL_NLTYPE_CIPSOV4 3 -#define NETLBL_NLTYPE_CIPSOV4_NAME "NLBL_CIPSOv4" -#define NETLBL_NLTYPE_CIPSOV6 4 -#define NETLBL_NLTYPE_CIPSOV6_NAME "NLBL_CIPSOv6" -#define NETLBL_NLTYPE_UNLABELED 5 -#define NETLBL_NLTYPE_UNLABELED_NAME "NLBL_UNLBL" -#define NETLBL_NLTYPE_ADDRSELECT 6 -#define NETLBL_NLTYPE_ADDRSELECT_NAME "NLBL_ADRSEL" -#define NETLBL_NLTYPE_CALIPSO 7 -#define NETLBL_NLTYPE_CALIPSO_NAME "NLBL_CALIPSO" - -/* - * NetLabel - Kernel API for accessing the network packet label mappings. - * - * The following functions are provided for use by other kernel modules, - * specifically kernel LSM modules, to provide a consistent, transparent API - * for dealing with explicit packet labeling protocols such as CIPSO and - * RIPSO. The functions defined here are implemented in the - * net/netlabel/netlabel_kapi.c file. - * - */ - -/* NetLabel audit information */ -struct netlbl_audit { - u32 secid; - kuid_t loginuid; - unsigned int sessionid; -}; - -/* - * LSM security attributes - */ - -/** - * struct netlbl_lsm_cache - NetLabel LSM security attribute cache - * @refcount: atomic reference counter - * @free: LSM supplied function to free the cache data - * @data: LSM supplied cache data - * - * Description: - * This structure is provided for LSMs which wish to make use of the NetLabel - * caching mechanism to store LSM specific data/attributes in the NetLabel - * cache. If the LSM has to perform a lot of translation from the NetLabel - * security attributes into it's own internal representation then the cache - * mechanism can provide a way to eliminate some or all of that translation - * overhead on a cache hit. - * - */ -struct netlbl_lsm_cache { - atomic_t refcount; - void (*free) (const void *data); - void *data; -}; - -/** - * struct netlbl_lsm_catmap - NetLabel LSM secattr category bitmap - * @startbit: the value of the lowest order bit in the bitmap - * @bitmap: the category bitmap - * @next: pointer to the next bitmap "node" or NULL - * - * Description: - * This structure is used to represent category bitmaps. Due to the large - * number of categories supported by most labeling protocols it is not - * practical to transfer a full bitmap internally so NetLabel adopts a sparse - * bitmap structure modeled after SELinux's ebitmap structure. - * The catmap bitmap field MUST be a power of two in length and large - * enough to hold at least 240 bits. Special care (i.e. check the code!) - * should be used when changing these values as the LSM implementation - * probably has functions which rely on the sizes of these types to speed - * processing. - * - */ -#define NETLBL_CATMAP_MAPTYPE u64 -#define NETLBL_CATMAP_MAPCNT 4 -#define NETLBL_CATMAP_MAPSIZE (sizeof(NETLBL_CATMAP_MAPTYPE) * 8) -#define NETLBL_CATMAP_SIZE (NETLBL_CATMAP_MAPSIZE * \ - NETLBL_CATMAP_MAPCNT) -#define NETLBL_CATMAP_BIT (NETLBL_CATMAP_MAPTYPE)0x01 -struct netlbl_lsm_catmap { - u32 startbit; - NETLBL_CATMAP_MAPTYPE bitmap[NETLBL_CATMAP_MAPCNT]; - struct netlbl_lsm_catmap *next; -}; - -/** - * struct netlbl_lsm_secattr - NetLabel LSM security attributes - * @flags: indicate structure attributes, see NETLBL_SECATTR_* - * @type: indicate the NLTYPE of the attributes - * @domain: the NetLabel LSM domain - * @cache: NetLabel LSM specific cache - * @attr.mls: MLS sensitivity label - * @attr.mls.cat: MLS category bitmap - * @attr.mls.lvl: MLS sensitivity level - * @attr.secid: LSM specific secid token - * - * Description: - * This structure is used to pass security attributes between NetLabel and the - * LSM modules. The flags field is used to specify which fields within the - * struct are valid and valid values can be created by bitwise OR'ing the - * NETLBL_SECATTR_* defines. The domain field is typically set by the LSM to - * specify domain specific configuration settings and is not usually used by - * NetLabel itself when returning security attributes to the LSM. - * - */ -struct netlbl_lsm_secattr { - u32 flags; - /* bitmap values for 'flags' */ -#define NETLBL_SECATTR_NONE 0x00000000 -#define NETLBL_SECATTR_DOMAIN 0x00000001 -#define NETLBL_SECATTR_DOMAIN_CPY (NETLBL_SECATTR_DOMAIN | \ - NETLBL_SECATTR_FREE_DOMAIN) -#define NETLBL_SECATTR_CACHE 0x00000002 -#define NETLBL_SECATTR_MLS_LVL 0x00000004 -#define NETLBL_SECATTR_MLS_CAT 0x00000008 -#define NETLBL_SECATTR_SECID 0x00000010 - /* bitmap meta-values for 'flags' */ -#define NETLBL_SECATTR_FREE_DOMAIN 0x01000000 -#define NETLBL_SECATTR_CACHEABLE (NETLBL_SECATTR_MLS_LVL | \ - NETLBL_SECATTR_MLS_CAT | \ - NETLBL_SECATTR_SECID) - u32 type; - char *domain; - struct netlbl_lsm_cache *cache; - struct { - struct { - struct netlbl_lsm_catmap *cat; - u32 lvl; - } mls; - u32 secid; - } attr; -}; - -/** - * struct netlbl_calipso_ops - NetLabel CALIPSO operations - * @doi_add: add a CALIPSO DOI - * @doi_free: free a CALIPSO DOI - * @doi_getdef: returns a reference to a DOI - * @doi_putdef: releases a reference of a DOI - * @doi_walk: enumerate the DOI list - * @sock_getattr: retrieve the socket's attr - * @sock_setattr: set the socket's attr - * @sock_delattr: remove the socket's attr - * @req_setattr: set the req socket's attr - * @req_delattr: remove the req socket's attr - * @opt_getattr: retrieve attr from memory block - * @skbuff_optptr: find option in packet - * @skbuff_setattr: set the skbuff's attr - * @skbuff_delattr: remove the skbuff's attr - * @cache_invalidate: invalidate cache - * @cache_add: add cache entry - * - * Description: - * This structure is filled out by the CALIPSO engine and passed - * to the NetLabel core via a call to netlbl_calipso_ops_register(). - * It enables the CALIPSO engine (and hence IPv6) to be compiled - * as a module. - */ -struct netlbl_calipso_ops { - int (*doi_add)(struct calipso_doi *doi_def, - struct netlbl_audit *audit_info); - void (*doi_free)(struct calipso_doi *doi_def); - int (*doi_remove)(u32 doi, struct netlbl_audit *audit_info); - struct calipso_doi *(*doi_getdef)(u32 doi); - void (*doi_putdef)(struct calipso_doi *doi_def); - int (*doi_walk)(u32 *skip_cnt, - int (*callback)(struct calipso_doi *doi_def, void *arg), - void *cb_arg); - int (*sock_getattr)(struct sock *sk, - struct netlbl_lsm_secattr *secattr); - int (*sock_setattr)(struct sock *sk, - const struct calipso_doi *doi_def, - const struct netlbl_lsm_secattr *secattr); - void (*sock_delattr)(struct sock *sk); - int (*req_setattr)(struct request_sock *req, - const struct calipso_doi *doi_def, - const struct netlbl_lsm_secattr *secattr); - void (*req_delattr)(struct request_sock *req); - int (*opt_getattr)(const unsigned char *calipso, - struct netlbl_lsm_secattr *secattr); - unsigned char *(*skbuff_optptr)(const struct sk_buff *skb); - int (*skbuff_setattr)(struct sk_buff *skb, - const struct calipso_doi *doi_def, - const struct netlbl_lsm_secattr *secattr); - int (*skbuff_delattr)(struct sk_buff *skb); - void (*cache_invalidate)(void); - int (*cache_add)(const unsigned char *calipso_ptr, - const struct netlbl_lsm_secattr *secattr); -}; - -/* - * LSM security attribute operations (inline) - */ - -/** - * netlbl_secattr_cache_alloc - Allocate and initialize a secattr cache - * @flags: the memory allocation flags - * - * Description: - * Allocate and initialize a netlbl_lsm_cache structure. Returns a pointer - * on success, NULL on failure. - * - */ -static inline struct netlbl_lsm_cache *netlbl_secattr_cache_alloc(gfp_t flags) -{ - struct netlbl_lsm_cache *cache; - - cache = kzalloc(sizeof(*cache), flags); - if (cache) - atomic_set(&cache->refcount, 1); - return cache; -} - -/** - * netlbl_secattr_cache_free - Frees a netlbl_lsm_cache struct - * @cache: the struct to free - * - * Description: - * Frees @secattr including all of the internal buffers. - * - */ -static inline void netlbl_secattr_cache_free(struct netlbl_lsm_cache *cache) -{ - if (!atomic_dec_and_test(&cache->refcount)) - return; - - if (cache->free) - cache->free(cache->data); - kfree(cache); -} - -/** - * netlbl_catmap_alloc - Allocate a LSM secattr catmap - * @flags: memory allocation flags - * - * Description: - * Allocate memory for a LSM secattr catmap, returns a pointer on success, NULL - * on failure. - * - */ -static inline struct netlbl_lsm_catmap *netlbl_catmap_alloc(gfp_t flags) -{ - return kzalloc(sizeof(struct netlbl_lsm_catmap), flags); -} - -/** - * netlbl_catmap_free - Free a LSM secattr catmap - * @catmap: the category bitmap - * - * Description: - * Free a LSM secattr catmap. - * - */ -static inline void netlbl_catmap_free(struct netlbl_lsm_catmap *catmap) -{ - struct netlbl_lsm_catmap *iter; - - while (catmap) { - iter = catmap; - catmap = catmap->next; - kfree(iter); - } -} - -/** - * netlbl_secattr_init - Initialize a netlbl_lsm_secattr struct - * @secattr: the struct to initialize - * - * Description: - * Initialize an already allocated netlbl_lsm_secattr struct. - * - */ -static inline void netlbl_secattr_init(struct netlbl_lsm_secattr *secattr) -{ - memset(secattr, 0, sizeof(*secattr)); -} - -/** - * netlbl_secattr_destroy - Clears a netlbl_lsm_secattr struct - * @secattr: the struct to clear - * - * Description: - * Destroys the @secattr struct, including freeing all of the internal buffers. - * The struct must be reset with a call to netlbl_secattr_init() before reuse. - * - */ -static inline void netlbl_secattr_destroy(struct netlbl_lsm_secattr *secattr) -{ - if (secattr->flags & NETLBL_SECATTR_FREE_DOMAIN) - kfree(secattr->domain); - if (secattr->flags & NETLBL_SECATTR_CACHE) - netlbl_secattr_cache_free(secattr->cache); - if (secattr->flags & NETLBL_SECATTR_MLS_CAT) - netlbl_catmap_free(secattr->attr.mls.cat); -} - -/** - * netlbl_secattr_alloc - Allocate and initialize a netlbl_lsm_secattr struct - * @flags: the memory allocation flags - * - * Description: - * Allocate and initialize a netlbl_lsm_secattr struct. Returns a valid - * pointer on success, or NULL on failure. - * - */ -static inline struct netlbl_lsm_secattr *netlbl_secattr_alloc(gfp_t flags) -{ - return kzalloc(sizeof(struct netlbl_lsm_secattr), flags); -} - -/** - * netlbl_secattr_free - Frees a netlbl_lsm_secattr struct - * @secattr: the struct to free - * - * Description: - * Frees @secattr including all of the internal buffers. - * - */ -static inline void netlbl_secattr_free(struct netlbl_lsm_secattr *secattr) -{ - netlbl_secattr_destroy(secattr); - kfree(secattr); -} - -#ifdef CONFIG_NETLABEL -/* - * LSM configuration operations - */ -int netlbl_cfg_map_del(const char *domain, - u16 family, - const void *addr, - const void *mask, - struct netlbl_audit *audit_info); -int netlbl_cfg_unlbl_map_add(const char *domain, - u16 family, - const void *addr, - const void *mask, - struct netlbl_audit *audit_info); -int netlbl_cfg_unlbl_static_add(struct net *net, - const char *dev_name, - const void *addr, - const void *mask, - u16 family, - u32 secid, - struct netlbl_audit *audit_info); -int netlbl_cfg_unlbl_static_del(struct net *net, - const char *dev_name, - const void *addr, - const void *mask, - u16 family, - struct netlbl_audit *audit_info); -int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def, - struct netlbl_audit *audit_info); -void netlbl_cfg_cipsov4_del(u32 doi, struct netlbl_audit *audit_info); -int netlbl_cfg_cipsov4_map_add(u32 doi, - const char *domain, - const struct in_addr *addr, - const struct in_addr *mask, - struct netlbl_audit *audit_info); -int netlbl_cfg_calipso_add(struct calipso_doi *doi_def, - struct netlbl_audit *audit_info); -void netlbl_cfg_calipso_del(u32 doi, struct netlbl_audit *audit_info); -int netlbl_cfg_calipso_map_add(u32 doi, - const char *domain, - const struct in6_addr *addr, - const struct in6_addr *mask, - struct netlbl_audit *audit_info); -/* - * LSM security attribute operations - */ -int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, u32 offset); -int netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap, u32 offset); -int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap, - u32 *offset, - unsigned long *bitmap); -int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap, - u32 bit, - gfp_t flags); -int netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap, - u32 start, - u32 end, - gfp_t flags); -int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap, - u32 offset, - unsigned long bitmap, - gfp_t flags); - -/* Bitmap functions - */ -int netlbl_bitmap_walk(const unsigned char *bitmap, u32 bitmap_len, - u32 offset, u8 state); -void netlbl_bitmap_setbit(unsigned char *bitmap, u32 bit, u8 state); - -/* - * LSM protocol operations (NetLabel LSM/kernel API) - */ -int netlbl_enabled(void); -int netlbl_sock_setattr(struct sock *sk, - u16 family, - const struct netlbl_lsm_secattr *secattr); -void netlbl_sock_delattr(struct sock *sk); -int netlbl_sock_getattr(struct sock *sk, - struct netlbl_lsm_secattr *secattr); -int netlbl_conn_setattr(struct sock *sk, - struct sockaddr *addr, - const struct netlbl_lsm_secattr *secattr); -int netlbl_req_setattr(struct request_sock *req, - const struct netlbl_lsm_secattr *secattr); -void netlbl_req_delattr(struct request_sock *req); -int netlbl_skbuff_setattr(struct sk_buff *skb, - u16 family, - const struct netlbl_lsm_secattr *secattr); -int netlbl_skbuff_getattr(const struct sk_buff *skb, - u16 family, - struct netlbl_lsm_secattr *secattr); -void netlbl_skbuff_err(struct sk_buff *skb, u16 family, int error, int gateway); - -/* - * LSM label mapping cache operations - */ -void netlbl_cache_invalidate(void); -int netlbl_cache_add(const struct sk_buff *skb, u16 family, - const struct netlbl_lsm_secattr *secattr); - -/* - * Protocol engine operations - */ -struct audit_buffer *netlbl_audit_start(int type, - struct netlbl_audit *audit_info); -#else -static inline int netlbl_cfg_map_del(const char *domain, - u16 family, - const void *addr, - const void *mask, - struct netlbl_audit *audit_info) -{ - return -ENOSYS; -} -static inline int netlbl_cfg_unlbl_map_add(const char *domain, - u16 family, - void *addr, - void *mask, - struct netlbl_audit *audit_info) -{ - return -ENOSYS; -} -static inline int netlbl_cfg_unlbl_static_add(struct net *net, - const char *dev_name, - const void *addr, - const void *mask, - u16 family, - u32 secid, - struct netlbl_audit *audit_info) -{ - return -ENOSYS; -} -static inline int netlbl_cfg_unlbl_static_del(struct net *net, - const char *dev_name, - const void *addr, - const void *mask, - u16 family, - struct netlbl_audit *audit_info) -{ - return -ENOSYS; -} -static inline int netlbl_cfg_cipsov4_add(struct cipso_v4_doi *doi_def, - struct netlbl_audit *audit_info) -{ - return -ENOSYS; -} -static inline void netlbl_cfg_cipsov4_del(u32 doi, - struct netlbl_audit *audit_info) -{ - return; -} -static inline int netlbl_cfg_cipsov4_map_add(u32 doi, - const char *domain, - const struct in_addr *addr, - const struct in_addr *mask, - struct netlbl_audit *audit_info) -{ - return -ENOSYS; -} -static inline int netlbl_cfg_calipso_add(struct calipso_doi *doi_def, - struct netlbl_audit *audit_info) -{ - return -ENOSYS; -} -static inline void netlbl_cfg_calipso_del(u32 doi, - struct netlbl_audit *audit_info) -{ - return; -} -static inline int netlbl_cfg_calipso_map_add(u32 doi, - const char *domain, - const struct in6_addr *addr, - const struct in6_addr *mask, - struct netlbl_audit *audit_info) -{ - return -ENOSYS; -} -static inline int netlbl_catmap_walk(struct netlbl_lsm_catmap *catmap, - u32 offset) -{ - return -ENOENT; -} -static inline int netlbl_catmap_walkrng(struct netlbl_lsm_catmap *catmap, - u32 offset) -{ - return -ENOENT; -} -static inline int netlbl_catmap_getlong(struct netlbl_lsm_catmap *catmap, - u32 *offset, - unsigned long *bitmap) -{ - return 0; -} -static inline int netlbl_catmap_setbit(struct netlbl_lsm_catmap **catmap, - u32 bit, - gfp_t flags) -{ - return 0; -} -static inline int netlbl_catmap_setrng(struct netlbl_lsm_catmap **catmap, - u32 start, - u32 end, - gfp_t flags) -{ - return 0; -} -static inline int netlbl_catmap_setlong(struct netlbl_lsm_catmap **catmap, - u32 offset, - unsigned long bitmap, - gfp_t flags) -{ - return 0; -} -static inline int netlbl_enabled(void) -{ - return 0; -} -static inline int netlbl_sock_setattr(struct sock *sk, - u16 family, - const struct netlbl_lsm_secattr *secattr) -{ - return -ENOSYS; -} -static inline void netlbl_sock_delattr(struct sock *sk) -{ -} -static inline int netlbl_sock_getattr(struct sock *sk, - struct netlbl_lsm_secattr *secattr) -{ - return -ENOSYS; -} -static inline int netlbl_conn_setattr(struct sock *sk, - struct sockaddr *addr, - const struct netlbl_lsm_secattr *secattr) -{ - return -ENOSYS; -} -static inline int netlbl_req_setattr(struct request_sock *req, - const struct netlbl_lsm_secattr *secattr) -{ - return -ENOSYS; -} -static inline void netlbl_req_delattr(struct request_sock *req) -{ - return; -} -static inline int netlbl_skbuff_setattr(struct sk_buff *skb, - u16 family, - const struct netlbl_lsm_secattr *secattr) -{ - return -ENOSYS; -} -static inline int netlbl_skbuff_getattr(const struct sk_buff *skb, - u16 family, - struct netlbl_lsm_secattr *secattr) -{ - return -ENOSYS; -} -static inline void netlbl_skbuff_err(struct sk_buff *skb, - int error, - int gateway) -{ - return; -} -static inline void netlbl_cache_invalidate(void) -{ - return; -} -static inline int netlbl_cache_add(const struct sk_buff *skb, u16 family, - const struct netlbl_lsm_secattr *secattr) -{ - return 0; -} -static inline struct audit_buffer *netlbl_audit_start(int type, - struct netlbl_audit *audit_info) -{ - return NULL; -} -#endif /* CONFIG_NETLABEL */ - -const struct netlbl_calipso_ops * -netlbl_calipso_ops_register(const struct netlbl_calipso_ops *ops); - -#endif /* _NETLABEL_H */ diff --git a/src/linux/include/net/netlink.h b/src/linux/include/net/netlink.h deleted file mode 100644 index 254a0fc..0000000 --- a/src/linux/include/net/netlink.h +++ /dev/null @@ -1,1343 +0,0 @@ -#ifndef __NET_NETLINK_H -#define __NET_NETLINK_H - -#include -#include -#include -#include - -/* ======================================================================== - * Netlink Messages and Attributes Interface (As Seen On TV) - * ------------------------------------------------------------------------ - * Messages Interface - * ------------------------------------------------------------------------ - * - * Message Format: - * <--- nlmsg_total_size(payload) ---> - * <-- nlmsg_msg_size(payload) -> - * +----------+- - -+-------------+- - -+-------- - - - * | nlmsghdr | Pad | Payload | Pad | nlmsghdr - * +----------+- - -+-------------+- - -+-------- - - - * nlmsg_data(nlh)---^ ^ - * nlmsg_next(nlh)-----------------------+ - * - * Payload Format: - * <---------------------- nlmsg_len(nlh) ---------------------> - * <------ hdrlen ------> <- nlmsg_attrlen(nlh, hdrlen) -> - * +----------------------+- - -+--------------------------------+ - * | Family Header | Pad | Attributes | - * +----------------------+- - -+--------------------------------+ - * nlmsg_attrdata(nlh, hdrlen)---^ - * - * Data Structures: - * struct nlmsghdr netlink message header - * - * Message Construction: - * nlmsg_new() create a new netlink message - * nlmsg_put() add a netlink message to an skb - * nlmsg_put_answer() callback based nlmsg_put() - * nlmsg_end() finalize netlink message - * nlmsg_get_pos() return current position in message - * nlmsg_trim() trim part of message - * nlmsg_cancel() cancel message construction - * nlmsg_free() free a netlink message - * - * Message Sending: - * nlmsg_multicast() multicast message to several groups - * nlmsg_unicast() unicast a message to a single socket - * nlmsg_notify() send notification message - * - * Message Length Calculations: - * nlmsg_msg_size(payload) length of message w/o padding - * nlmsg_total_size(payload) length of message w/ padding - * nlmsg_padlen(payload) length of padding at tail - * - * Message Payload Access: - * nlmsg_data(nlh) head of message payload - * nlmsg_len(nlh) length of message payload - * nlmsg_attrdata(nlh, hdrlen) head of attributes data - * nlmsg_attrlen(nlh, hdrlen) length of attributes data - * - * Message Parsing: - * nlmsg_ok(nlh, remaining) does nlh fit into remaining bytes? - * nlmsg_next(nlh, remaining) get next netlink message - * nlmsg_parse() parse attributes of a message - * nlmsg_find_attr() find an attribute in a message - * nlmsg_for_each_msg() loop over all messages - * nlmsg_validate() validate netlink message incl. attrs - * nlmsg_for_each_attr() loop over all attributes - * - * Misc: - * nlmsg_report() report back to application? - * - * ------------------------------------------------------------------------ - * Attributes Interface - * ------------------------------------------------------------------------ - * - * Attribute Format: - * <------- nla_total_size(payload) -------> - * <---- nla_attr_size(payload) -----> - * +----------+- - -+- - - - - - - - - +- - -+-------- - - - * | Header | Pad | Payload | Pad | Header - * +----------+- - -+- - - - - - - - - +- - -+-------- - - - * <- nla_len(nla) -> ^ - * nla_data(nla)----^ | - * nla_next(nla)-----------------------------' - * - * Data Structures: - * struct nlattr netlink attribute header - * - * Attribute Construction: - * nla_reserve(skb, type, len) reserve room for an attribute - * nla_reserve_nohdr(skb, len) reserve room for an attribute w/o hdr - * nla_put(skb, type, len, data) add attribute to skb - * nla_put_nohdr(skb, len, data) add attribute w/o hdr - * nla_append(skb, len, data) append data to skb - * - * Attribute Construction for Basic Types: - * nla_put_u8(skb, type, value) add u8 attribute to skb - * nla_put_u16(skb, type, value) add u16 attribute to skb - * nla_put_u32(skb, type, value) add u32 attribute to skb - * nla_put_u64_64bits(skb, type, - * value, padattr) add u64 attribute to skb - * nla_put_s8(skb, type, value) add s8 attribute to skb - * nla_put_s16(skb, type, value) add s16 attribute to skb - * nla_put_s32(skb, type, value) add s32 attribute to skb - * nla_put_s64(skb, type, value, - * padattr) add s64 attribute to skb - * nla_put_string(skb, type, str) add string attribute to skb - * nla_put_flag(skb, type) add flag attribute to skb - * nla_put_msecs(skb, type, jiffies, - * padattr) add msecs attribute to skb - * nla_put_in_addr(skb, type, addr) add IPv4 address attribute to skb - * nla_put_in6_addr(skb, type, addr) add IPv6 address attribute to skb - * - * Nested Attributes Construction: - * nla_nest_start(skb, type) start a nested attribute - * nla_nest_end(skb, nla) finalize a nested attribute - * nla_nest_cancel(skb, nla) cancel nested attribute construction - * - * Attribute Length Calculations: - * nla_attr_size(payload) length of attribute w/o padding - * nla_total_size(payload) length of attribute w/ padding - * nla_padlen(payload) length of padding - * - * Attribute Payload Access: - * nla_data(nla) head of attribute payload - * nla_len(nla) length of attribute payload - * - * Attribute Payload Access for Basic Types: - * nla_get_u8(nla) get payload for a u8 attribute - * nla_get_u16(nla) get payload for a u16 attribute - * nla_get_u32(nla) get payload for a u32 attribute - * nla_get_u64(nla) get payload for a u64 attribute - * nla_get_s8(nla) get payload for a s8 attribute - * nla_get_s16(nla) get payload for a s16 attribute - * nla_get_s32(nla) get payload for a s32 attribute - * nla_get_s64(nla) get payload for a s64 attribute - * nla_get_flag(nla) return 1 if flag is true - * nla_get_msecs(nla) get payload for a msecs attribute - * - * Attribute Misc: - * nla_memcpy(dest, nla, count) copy attribute into memory - * nla_memcmp(nla, data, size) compare attribute with memory area - * nla_strlcpy(dst, nla, size) copy attribute to a sized string - * nla_strcmp(nla, str) compare attribute with string - * - * Attribute Parsing: - * nla_ok(nla, remaining) does nla fit into remaining bytes? - * nla_next(nla, remaining) get next netlink attribute - * nla_validate() validate a stream of attributes - * nla_validate_nested() validate a stream of nested attributes - * nla_find() find attribute in stream of attributes - * nla_find_nested() find attribute in nested attributes - * nla_parse() parse and validate stream of attrs - * nla_parse_nested() parse nested attribuets - * nla_for_each_attr() loop over all attributes - * nla_for_each_nested() loop over the nested attributes - *========================================================================= - */ - - /** - * Standard attribute types to specify validation policy - */ -enum { - NLA_UNSPEC, - NLA_U8, - NLA_U16, - NLA_U32, - NLA_U64, - NLA_STRING, - NLA_FLAG, - NLA_MSECS, - NLA_NESTED, - NLA_NESTED_COMPAT, - NLA_NUL_STRING, - NLA_BINARY, - NLA_S8, - NLA_S16, - NLA_S32, - NLA_S64, - __NLA_TYPE_MAX, -}; - -#define NLA_TYPE_MAX (__NLA_TYPE_MAX - 1) - -/** - * struct nla_policy - attribute validation policy - * @type: Type of attribute or NLA_UNSPEC - * @len: Type specific length of payload - * - * Policies are defined as arrays of this struct, the array must be - * accessible by attribute type up to the highest identifier to be expected. - * - * Meaning of `len' field: - * NLA_STRING Maximum length of string - * NLA_NUL_STRING Maximum length of string (excluding NUL) - * NLA_FLAG Unused - * NLA_BINARY Maximum length of attribute payload - * NLA_NESTED Don't use `len' field -- length verification is - * done by checking len of nested header (or empty) - * NLA_NESTED_COMPAT Minimum length of structure payload - * NLA_U8, NLA_U16, - * NLA_U32, NLA_U64, - * NLA_S8, NLA_S16, - * NLA_S32, NLA_S64, - * NLA_MSECS Leaving the length field zero will verify the - * given type fits, using it verifies minimum length - * just like "All other" - * All other Minimum length of attribute payload - * - * Example: - * static const struct nla_policy my_policy[ATTR_MAX+1] = { - * [ATTR_FOO] = { .type = NLA_U16 }, - * [ATTR_BAR] = { .type = NLA_STRING, .len = BARSIZ }, - * [ATTR_BAZ] = { .len = sizeof(struct mystruct) }, - * }; - */ -struct nla_policy { - u16 type; - u16 len; -}; - -/** - * struct nl_info - netlink source information - * @nlh: Netlink message header of original request - * @portid: Netlink PORTID of requesting application - */ -struct nl_info { - struct nlmsghdr *nlh; - struct net *nl_net; - u32 portid; -}; - -int netlink_rcv_skb(struct sk_buff *skb, - int (*cb)(struct sk_buff *, struct nlmsghdr *)); -int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 portid, - unsigned int group, int report, gfp_t flags); - -int nla_validate(const struct nlattr *head, int len, int maxtype, - const struct nla_policy *policy); -int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head, - int len, const struct nla_policy *policy); -int nla_policy_len(const struct nla_policy *, int); -struct nlattr *nla_find(const struct nlattr *head, int len, int attrtype); -size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize); -int nla_memcpy(void *dest, const struct nlattr *src, int count); -int nla_memcmp(const struct nlattr *nla, const void *data, size_t size); -int nla_strcmp(const struct nlattr *nla, const char *str); -struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen); -struct nlattr *__nla_reserve_64bit(struct sk_buff *skb, int attrtype, - int attrlen, int padattr); -void *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen); -struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen); -struct nlattr *nla_reserve_64bit(struct sk_buff *skb, int attrtype, - int attrlen, int padattr); -void *nla_reserve_nohdr(struct sk_buff *skb, int attrlen); -void __nla_put(struct sk_buff *skb, int attrtype, int attrlen, - const void *data); -void __nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen, - const void *data, int padattr); -void __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data); -int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data); -int nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen, - const void *data, int padattr); -int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data); -int nla_append(struct sk_buff *skb, int attrlen, const void *data); - -/************************************************************************** - * Netlink Messages - **************************************************************************/ - -/** - * nlmsg_msg_size - length of netlink message not including padding - * @payload: length of message payload - */ -static inline int nlmsg_msg_size(int payload) -{ - return NLMSG_HDRLEN + payload; -} - -/** - * nlmsg_total_size - length of netlink message including padding - * @payload: length of message payload - */ -static inline int nlmsg_total_size(int payload) -{ - return NLMSG_ALIGN(nlmsg_msg_size(payload)); -} - -/** - * nlmsg_padlen - length of padding at the message's tail - * @payload: length of message payload - */ -static inline int nlmsg_padlen(int payload) -{ - return nlmsg_total_size(payload) - nlmsg_msg_size(payload); -} - -/** - * nlmsg_data - head of message payload - * @nlh: netlink message header - */ -static inline void *nlmsg_data(const struct nlmsghdr *nlh) -{ - return (unsigned char *) nlh + NLMSG_HDRLEN; -} - -/** - * nlmsg_len - length of message payload - * @nlh: netlink message header - */ -static inline int nlmsg_len(const struct nlmsghdr *nlh) -{ - return nlh->nlmsg_len - NLMSG_HDRLEN; -} - -/** - * nlmsg_attrdata - head of attributes data - * @nlh: netlink message header - * @hdrlen: length of family specific header - */ -static inline struct nlattr *nlmsg_attrdata(const struct nlmsghdr *nlh, - int hdrlen) -{ - unsigned char *data = nlmsg_data(nlh); - return (struct nlattr *) (data + NLMSG_ALIGN(hdrlen)); -} - -/** - * nlmsg_attrlen - length of attributes data - * @nlh: netlink message header - * @hdrlen: length of family specific header - */ -static inline int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen) -{ - return nlmsg_len(nlh) - NLMSG_ALIGN(hdrlen); -} - -/** - * nlmsg_ok - check if the netlink message fits into the remaining bytes - * @nlh: netlink message header - * @remaining: number of bytes remaining in message stream - */ -static inline int nlmsg_ok(const struct nlmsghdr *nlh, int remaining) -{ - return (remaining >= (int) sizeof(struct nlmsghdr) && - nlh->nlmsg_len >= sizeof(struct nlmsghdr) && - nlh->nlmsg_len <= remaining); -} - -/** - * nlmsg_next - next netlink message in message stream - * @nlh: netlink message header - * @remaining: number of bytes remaining in message stream - * - * Returns the next netlink message in the message stream and - * decrements remaining by the size of the current message. - */ -static inline struct nlmsghdr * -nlmsg_next(const struct nlmsghdr *nlh, int *remaining) -{ - int totlen = NLMSG_ALIGN(nlh->nlmsg_len); - - *remaining -= totlen; - - return (struct nlmsghdr *) ((unsigned char *) nlh + totlen); -} - -/** - * nlmsg_parse - parse attributes of a netlink message - * @nlh: netlink message header - * @hdrlen: length of family specific header - * @tb: destination array with maxtype+1 elements - * @maxtype: maximum attribute type to be expected - * @policy: validation policy - * - * See nla_parse() - */ -static inline int nlmsg_parse(const struct nlmsghdr *nlh, int hdrlen, - struct nlattr *tb[], int maxtype, - const struct nla_policy *policy) -{ - if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) - return -EINVAL; - - return nla_parse(tb, maxtype, nlmsg_attrdata(nlh, hdrlen), - nlmsg_attrlen(nlh, hdrlen), policy); -} - -/** - * nlmsg_find_attr - find a specific attribute in a netlink message - * @nlh: netlink message header - * @hdrlen: length of familiy specific header - * @attrtype: type of attribute to look for - * - * Returns the first attribute which matches the specified type. - */ -static inline struct nlattr *nlmsg_find_attr(const struct nlmsghdr *nlh, - int hdrlen, int attrtype) -{ - return nla_find(nlmsg_attrdata(nlh, hdrlen), - nlmsg_attrlen(nlh, hdrlen), attrtype); -} - -/** - * nlmsg_validate - validate a netlink message including attributes - * @nlh: netlinket message header - * @hdrlen: length of familiy specific header - * @maxtype: maximum attribute type to be expected - * @policy: validation policy - */ -static inline int nlmsg_validate(const struct nlmsghdr *nlh, - int hdrlen, int maxtype, - const struct nla_policy *policy) -{ - if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) - return -EINVAL; - - return nla_validate(nlmsg_attrdata(nlh, hdrlen), - nlmsg_attrlen(nlh, hdrlen), maxtype, policy); -} - -/** - * nlmsg_report - need to report back to application? - * @nlh: netlink message header - * - * Returns 1 if a report back to the application is requested. - */ -static inline int nlmsg_report(const struct nlmsghdr *nlh) -{ - return !!(nlh->nlmsg_flags & NLM_F_ECHO); -} - -/** - * nlmsg_for_each_attr - iterate over a stream of attributes - * @pos: loop counter, set to current attribute - * @nlh: netlink message header - * @hdrlen: length of familiy specific header - * @rem: initialized to len, holds bytes currently remaining in stream - */ -#define nlmsg_for_each_attr(pos, nlh, hdrlen, rem) \ - nla_for_each_attr(pos, nlmsg_attrdata(nlh, hdrlen), \ - nlmsg_attrlen(nlh, hdrlen), rem) - -/** - * nlmsg_put - Add a new netlink message to an skb - * @skb: socket buffer to store message in - * @portid: netlink PORTID of requesting application - * @seq: sequence number of message - * @type: message type - * @payload: length of message payload - * @flags: message flags - * - * Returns NULL if the tailroom of the skb is insufficient to store - * the message header and payload. - */ -static inline struct nlmsghdr *nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, - int type, int payload, int flags) -{ - if (unlikely(skb_tailroom(skb) < nlmsg_total_size(payload))) - return NULL; - - return __nlmsg_put(skb, portid, seq, type, payload, flags); -} - -/** - * nlmsg_put_answer - Add a new callback based netlink message to an skb - * @skb: socket buffer to store message in - * @cb: netlink callback - * @type: message type - * @payload: length of message payload - * @flags: message flags - * - * Returns NULL if the tailroom of the skb is insufficient to store - * the message header and payload. - */ -static inline struct nlmsghdr *nlmsg_put_answer(struct sk_buff *skb, - struct netlink_callback *cb, - int type, int payload, - int flags) -{ - return nlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, - type, payload, flags); -} - -/** - * nlmsg_new - Allocate a new netlink message - * @payload: size of the message payload - * @flags: the type of memory to allocate. - * - * Use NLMSG_DEFAULT_SIZE if the size of the payload isn't known - * and a good default is needed. - */ -static inline struct sk_buff *nlmsg_new(size_t payload, gfp_t flags) -{ - return alloc_skb(nlmsg_total_size(payload), flags); -} - -/** - * nlmsg_end - Finalize a netlink message - * @skb: socket buffer the message is stored in - * @nlh: netlink message header - * - * Corrects the netlink message header to include the appeneded - * attributes. Only necessary if attributes have been added to - * the message. - */ -static inline void nlmsg_end(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - nlh->nlmsg_len = skb_tail_pointer(skb) - (unsigned char *)nlh; -} - -/** - * nlmsg_get_pos - return current position in netlink message - * @skb: socket buffer the message is stored in - * - * Returns a pointer to the current tail of the message. - */ -static inline void *nlmsg_get_pos(struct sk_buff *skb) -{ - return skb_tail_pointer(skb); -} - -/** - * nlmsg_trim - Trim message to a mark - * @skb: socket buffer the message is stored in - * @mark: mark to trim to - * - * Trims the message to the provided mark. - */ -static inline void nlmsg_trim(struct sk_buff *skb, const void *mark) -{ - if (mark) { - WARN_ON((unsigned char *) mark < skb->data); - skb_trim(skb, (unsigned char *) mark - skb->data); - } -} - -/** - * nlmsg_cancel - Cancel construction of a netlink message - * @skb: socket buffer the message is stored in - * @nlh: netlink message header - * - * Removes the complete netlink message including all - * attributes from the socket buffer again. - */ -static inline void nlmsg_cancel(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - nlmsg_trim(skb, nlh); -} - -/** - * nlmsg_free - free a netlink message - * @skb: socket buffer of netlink message - */ -static inline void nlmsg_free(struct sk_buff *skb) -{ - kfree_skb(skb); -} - -/** - * nlmsg_multicast - multicast a netlink message - * @sk: netlink socket to spread messages to - * @skb: netlink message as socket buffer - * @portid: own netlink portid to avoid sending to yourself - * @group: multicast group id - * @flags: allocation flags - */ -static inline int nlmsg_multicast(struct sock *sk, struct sk_buff *skb, - u32 portid, unsigned int group, gfp_t flags) -{ - int err; - - NETLINK_CB(skb).dst_group = group; - - err = netlink_broadcast(sk, skb, portid, group, flags); - if (err > 0) - err = 0; - - return err; -} - -/** - * nlmsg_unicast - unicast a netlink message - * @sk: netlink socket to spread message to - * @skb: netlink message as socket buffer - * @portid: netlink portid of the destination socket - */ -static inline int nlmsg_unicast(struct sock *sk, struct sk_buff *skb, u32 portid) -{ - int err; - - err = netlink_unicast(sk, skb, portid, MSG_DONTWAIT); - if (err > 0) - err = 0; - - return err; -} - -/** - * nlmsg_for_each_msg - iterate over a stream of messages - * @pos: loop counter, set to current message - * @head: head of message stream - * @len: length of message stream - * @rem: initialized to len, holds bytes currently remaining in stream - */ -#define nlmsg_for_each_msg(pos, head, len, rem) \ - for (pos = head, rem = len; \ - nlmsg_ok(pos, rem); \ - pos = nlmsg_next(pos, &(rem))) - -/** - * nl_dump_check_consistent - check if sequence is consistent and advertise if not - * @cb: netlink callback structure that stores the sequence number - * @nlh: netlink message header to write the flag to - * - * This function checks if the sequence (generation) number changed during dump - * and if it did, advertises it in the netlink message header. - * - * The correct way to use it is to set cb->seq to the generation counter when - * all locks for dumping have been acquired, and then call this function for - * each message that is generated. - * - * Note that due to initialisation concerns, 0 is an invalid sequence number - * and must not be used by code that uses this functionality. - */ -static inline void -nl_dump_check_consistent(struct netlink_callback *cb, - struct nlmsghdr *nlh) -{ - if (cb->prev_seq && cb->seq != cb->prev_seq) - nlh->nlmsg_flags |= NLM_F_DUMP_INTR; - cb->prev_seq = cb->seq; -} - -/************************************************************************** - * Netlink Attributes - **************************************************************************/ - -/** - * nla_attr_size - length of attribute not including padding - * @payload: length of payload - */ -static inline int nla_attr_size(int payload) -{ - return NLA_HDRLEN + payload; -} - -/** - * nla_total_size - total length of attribute including padding - * @payload: length of payload - */ -static inline int nla_total_size(int payload) -{ - return NLA_ALIGN(nla_attr_size(payload)); -} - -/** - * nla_padlen - length of padding at the tail of attribute - * @payload: length of payload - */ -static inline int nla_padlen(int payload) -{ - return nla_total_size(payload) - nla_attr_size(payload); -} - -/** - * nla_type - attribute type - * @nla: netlink attribute - */ -static inline int nla_type(const struct nlattr *nla) -{ - return nla->nla_type & NLA_TYPE_MASK; -} - -/** - * nla_data - head of payload - * @nla: netlink attribute - */ -static inline void *nla_data(const struct nlattr *nla) -{ - return (char *) nla + NLA_HDRLEN; -} - -/** - * nla_len - length of payload - * @nla: netlink attribute - */ -static inline int nla_len(const struct nlattr *nla) -{ - return nla->nla_len - NLA_HDRLEN; -} - -/** - * nla_ok - check if the netlink attribute fits into the remaining bytes - * @nla: netlink attribute - * @remaining: number of bytes remaining in attribute stream - */ -static inline int nla_ok(const struct nlattr *nla, int remaining) -{ - return remaining >= (int) sizeof(*nla) && - nla->nla_len >= sizeof(*nla) && - nla->nla_len <= remaining; -} - -/** - * nla_next - next netlink attribute in attribute stream - * @nla: netlink attribute - * @remaining: number of bytes remaining in attribute stream - * - * Returns the next netlink attribute in the attribute stream and - * decrements remaining by the size of the current attribute. - */ -static inline struct nlattr *nla_next(const struct nlattr *nla, int *remaining) -{ - int totlen = NLA_ALIGN(nla->nla_len); - - *remaining -= totlen; - return (struct nlattr *) ((char *) nla + totlen); -} - -/** - * nla_find_nested - find attribute in a set of nested attributes - * @nla: attribute containing the nested attributes - * @attrtype: type of attribute to look for - * - * Returns the first attribute which matches the specified type. - */ -static inline struct nlattr * -nla_find_nested(const struct nlattr *nla, int attrtype) -{ - return nla_find(nla_data(nla), nla_len(nla), attrtype); -} - -/** - * nla_parse_nested - parse nested attributes - * @tb: destination array with maxtype+1 elements - * @maxtype: maximum attribute type to be expected - * @nla: attribute containing the nested attributes - * @policy: validation policy - * - * See nla_parse() - */ -static inline int nla_parse_nested(struct nlattr *tb[], int maxtype, - const struct nlattr *nla, - const struct nla_policy *policy) -{ - return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy); -} - -/** - * nla_put_u8 - Add a u8 netlink attribute to a socket buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @value: numeric value - */ -static inline int nla_put_u8(struct sk_buff *skb, int attrtype, u8 value) -{ - return nla_put(skb, attrtype, sizeof(u8), &value); -} - -/** - * nla_put_u16 - Add a u16 netlink attribute to a socket buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @value: numeric value - */ -static inline int nla_put_u16(struct sk_buff *skb, int attrtype, u16 value) -{ - return nla_put(skb, attrtype, sizeof(u16), &value); -} - -/** - * nla_put_be16 - Add a __be16 netlink attribute to a socket buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @value: numeric value - */ -static inline int nla_put_be16(struct sk_buff *skb, int attrtype, __be16 value) -{ - return nla_put(skb, attrtype, sizeof(__be16), &value); -} - -/** - * nla_put_net16 - Add 16-bit network byte order netlink attribute to a socket buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @value: numeric value - */ -static inline int nla_put_net16(struct sk_buff *skb, int attrtype, __be16 value) -{ - return nla_put_be16(skb, attrtype | NLA_F_NET_BYTEORDER, value); -} - -/** - * nla_put_le16 - Add a __le16 netlink attribute to a socket buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @value: numeric value - */ -static inline int nla_put_le16(struct sk_buff *skb, int attrtype, __le16 value) -{ - return nla_put(skb, attrtype, sizeof(__le16), &value); -} - -/** - * nla_put_u32 - Add a u32 netlink attribute to a socket buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @value: numeric value - */ -static inline int nla_put_u32(struct sk_buff *skb, int attrtype, u32 value) -{ - return nla_put(skb, attrtype, sizeof(u32), &value); -} - -/** - * nla_put_be32 - Add a __be32 netlink attribute to a socket buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @value: numeric value - */ -static inline int nla_put_be32(struct sk_buff *skb, int attrtype, __be32 value) -{ - return nla_put(skb, attrtype, sizeof(__be32), &value); -} - -/** - * nla_put_net32 - Add 32-bit network byte order netlink attribute to a socket buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @value: numeric value - */ -static inline int nla_put_net32(struct sk_buff *skb, int attrtype, __be32 value) -{ - return nla_put_be32(skb, attrtype | NLA_F_NET_BYTEORDER, value); -} - -/** - * nla_put_le32 - Add a __le32 netlink attribute to a socket buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @value: numeric value - */ -static inline int nla_put_le32(struct sk_buff *skb, int attrtype, __le32 value) -{ - return nla_put(skb, attrtype, sizeof(__le32), &value); -} - -/** - * nla_put_u64_64bit - Add a u64 netlink attribute to a skb and align it - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @value: numeric value - * @padattr: attribute type for the padding - */ -static inline int nla_put_u64_64bit(struct sk_buff *skb, int attrtype, - u64 value, int padattr) -{ - return nla_put_64bit(skb, attrtype, sizeof(u64), &value, padattr); -} - -/** - * nla_put_be64 - Add a __be64 netlink attribute to a socket buffer and align it - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @value: numeric value - * @padattr: attribute type for the padding - */ -static inline int nla_put_be64(struct sk_buff *skb, int attrtype, __be64 value, - int padattr) -{ - return nla_put_64bit(skb, attrtype, sizeof(__be64), &value, padattr); -} - -/** - * nla_put_net64 - Add 64-bit network byte order nlattr to a skb and align it - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @value: numeric value - * @padattr: attribute type for the padding - */ -static inline int nla_put_net64(struct sk_buff *skb, int attrtype, __be64 value, - int padattr) -{ - return nla_put_be64(skb, attrtype | NLA_F_NET_BYTEORDER, value, - padattr); -} - -/** - * nla_put_le64 - Add a __le64 netlink attribute to a socket buffer and align it - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @value: numeric value - * @padattr: attribute type for the padding - */ -static inline int nla_put_le64(struct sk_buff *skb, int attrtype, __le64 value, - int padattr) -{ - return nla_put_64bit(skb, attrtype, sizeof(__le64), &value, padattr); -} - -/** - * nla_put_s8 - Add a s8 netlink attribute to a socket buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @value: numeric value - */ -static inline int nla_put_s8(struct sk_buff *skb, int attrtype, s8 value) -{ - return nla_put(skb, attrtype, sizeof(s8), &value); -} - -/** - * nla_put_s16 - Add a s16 netlink attribute to a socket buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @value: numeric value - */ -static inline int nla_put_s16(struct sk_buff *skb, int attrtype, s16 value) -{ - return nla_put(skb, attrtype, sizeof(s16), &value); -} - -/** - * nla_put_s32 - Add a s32 netlink attribute to a socket buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @value: numeric value - */ -static inline int nla_put_s32(struct sk_buff *skb, int attrtype, s32 value) -{ - return nla_put(skb, attrtype, sizeof(s32), &value); -} - -/** - * nla_put_s64 - Add a s64 netlink attribute to a socket buffer and align it - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @value: numeric value - * @padattr: attribute type for the padding - */ -static inline int nla_put_s64(struct sk_buff *skb, int attrtype, s64 value, - int padattr) -{ - return nla_put_64bit(skb, attrtype, sizeof(s64), &value, padattr); -} - -/** - * nla_put_string - Add a string netlink attribute to a socket buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @str: NUL terminated string - */ -static inline int nla_put_string(struct sk_buff *skb, int attrtype, - const char *str) -{ - return nla_put(skb, attrtype, strlen(str) + 1, str); -} - -/** - * nla_put_flag - Add a flag netlink attribute to a socket buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - */ -static inline int nla_put_flag(struct sk_buff *skb, int attrtype) -{ - return nla_put(skb, attrtype, 0, NULL); -} - -/** - * nla_put_msecs - Add a msecs netlink attribute to a skb and align it - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @njiffies: number of jiffies to convert to msecs - * @padattr: attribute type for the padding - */ -static inline int nla_put_msecs(struct sk_buff *skb, int attrtype, - unsigned long njiffies, int padattr) -{ - u64 tmp = jiffies_to_msecs(njiffies); - - return nla_put_64bit(skb, attrtype, sizeof(u64), &tmp, padattr); -} - -/** - * nla_put_in_addr - Add an IPv4 address netlink attribute to a socket - * buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @addr: IPv4 address - */ -static inline int nla_put_in_addr(struct sk_buff *skb, int attrtype, - __be32 addr) -{ - return nla_put_be32(skb, attrtype, addr); -} - -/** - * nla_put_in6_addr - Add an IPv6 address netlink attribute to a socket - * buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @addr: IPv6 address - */ -static inline int nla_put_in6_addr(struct sk_buff *skb, int attrtype, - const struct in6_addr *addr) -{ - return nla_put(skb, attrtype, sizeof(*addr), addr); -} - -/** - * nla_get_u32 - return payload of u32 attribute - * @nla: u32 netlink attribute - */ -static inline u32 nla_get_u32(const struct nlattr *nla) -{ - return *(u32 *) nla_data(nla); -} - -/** - * nla_get_be32 - return payload of __be32 attribute - * @nla: __be32 netlink attribute - */ -static inline __be32 nla_get_be32(const struct nlattr *nla) -{ - return *(__be32 *) nla_data(nla); -} - -/** - * nla_get_le32 - return payload of __le32 attribute - * @nla: __le32 netlink attribute - */ -static inline __le32 nla_get_le32(const struct nlattr *nla) -{ - return *(__le32 *) nla_data(nla); -} - -/** - * nla_get_u16 - return payload of u16 attribute - * @nla: u16 netlink attribute - */ -static inline u16 nla_get_u16(const struct nlattr *nla) -{ - return *(u16 *) nla_data(nla); -} - -/** - * nla_get_be16 - return payload of __be16 attribute - * @nla: __be16 netlink attribute - */ -static inline __be16 nla_get_be16(const struct nlattr *nla) -{ - return *(__be16 *) nla_data(nla); -} - -/** - * nla_get_le16 - return payload of __le16 attribute - * @nla: __le16 netlink attribute - */ -static inline __le16 nla_get_le16(const struct nlattr *nla) -{ - return *(__le16 *) nla_data(nla); -} - -/** - * nla_get_u8 - return payload of u8 attribute - * @nla: u8 netlink attribute - */ -static inline u8 nla_get_u8(const struct nlattr *nla) -{ - return *(u8 *) nla_data(nla); -} - -/** - * nla_get_u64 - return payload of u64 attribute - * @nla: u64 netlink attribute - */ -static inline u64 nla_get_u64(const struct nlattr *nla) -{ - u64 tmp; - - nla_memcpy(&tmp, nla, sizeof(tmp)); - - return tmp; -} - -/** - * nla_get_be64 - return payload of __be64 attribute - * @nla: __be64 netlink attribute - */ -static inline __be64 nla_get_be64(const struct nlattr *nla) -{ - __be64 tmp; - - nla_memcpy(&tmp, nla, sizeof(tmp)); - - return tmp; -} - -/** - * nla_get_le64 - return payload of __le64 attribute - * @nla: __le64 netlink attribute - */ -static inline __le64 nla_get_le64(const struct nlattr *nla) -{ - return *(__le64 *) nla_data(nla); -} - -/** - * nla_get_s32 - return payload of s32 attribute - * @nla: s32 netlink attribute - */ -static inline s32 nla_get_s32(const struct nlattr *nla) -{ - return *(s32 *) nla_data(nla); -} - -/** - * nla_get_s16 - return payload of s16 attribute - * @nla: s16 netlink attribute - */ -static inline s16 nla_get_s16(const struct nlattr *nla) -{ - return *(s16 *) nla_data(nla); -} - -/** - * nla_get_s8 - return payload of s8 attribute - * @nla: s8 netlink attribute - */ -static inline s8 nla_get_s8(const struct nlattr *nla) -{ - return *(s8 *) nla_data(nla); -} - -/** - * nla_get_s64 - return payload of s64 attribute - * @nla: s64 netlink attribute - */ -static inline s64 nla_get_s64(const struct nlattr *nla) -{ - s64 tmp; - - nla_memcpy(&tmp, nla, sizeof(tmp)); - - return tmp; -} - -/** - * nla_get_flag - return payload of flag attribute - * @nla: flag netlink attribute - */ -static inline int nla_get_flag(const struct nlattr *nla) -{ - return !!nla; -} - -/** - * nla_get_msecs - return payload of msecs attribute - * @nla: msecs netlink attribute - * - * Returns the number of milliseconds in jiffies. - */ -static inline unsigned long nla_get_msecs(const struct nlattr *nla) -{ - u64 msecs = nla_get_u64(nla); - - return msecs_to_jiffies((unsigned long) msecs); -} - -/** - * nla_get_in_addr - return payload of IPv4 address attribute - * @nla: IPv4 address netlink attribute - */ -static inline __be32 nla_get_in_addr(const struct nlattr *nla) -{ - return *(__be32 *) nla_data(nla); -} - -/** - * nla_get_in6_addr - return payload of IPv6 address attribute - * @nla: IPv6 address netlink attribute - */ -static inline struct in6_addr nla_get_in6_addr(const struct nlattr *nla) -{ - struct in6_addr tmp; - - nla_memcpy(&tmp, nla, sizeof(tmp)); - return tmp; -} - -/** - * nla_nest_start - Start a new level of nested attributes - * @skb: socket buffer to add attributes to - * @attrtype: attribute type of container - * - * Returns the container attribute - */ -static inline struct nlattr *nla_nest_start(struct sk_buff *skb, int attrtype) -{ - struct nlattr *start = (struct nlattr *)skb_tail_pointer(skb); - - if (nla_put(skb, attrtype, 0, NULL) < 0) - return NULL; - - return start; -} - -/** - * nla_nest_end - Finalize nesting of attributes - * @skb: socket buffer the attributes are stored in - * @start: container attribute - * - * Corrects the container attribute header to include the all - * appeneded attributes. - * - * Returns the total data length of the skb. - */ -static inline int nla_nest_end(struct sk_buff *skb, struct nlattr *start) -{ - start->nla_len = skb_tail_pointer(skb) - (unsigned char *)start; - return skb->len; -} - -/** - * nla_nest_cancel - Cancel nesting of attributes - * @skb: socket buffer the message is stored in - * @start: container attribute - * - * Removes the container attribute and including all nested - * attributes. Returns -EMSGSIZE - */ -static inline void nla_nest_cancel(struct sk_buff *skb, struct nlattr *start) -{ - nlmsg_trim(skb, start); -} - -/** - * nla_validate_nested - Validate a stream of nested attributes - * @start: container attribute - * @maxtype: maximum attribute type to be expected - * @policy: validation policy - * - * Validates all attributes in the nested attribute stream against the - * specified policy. Attributes with a type exceeding maxtype will be - * ignored. See documenation of struct nla_policy for more details. - * - * Returns 0 on success or a negative error code. - */ -static inline int nla_validate_nested(const struct nlattr *start, int maxtype, - const struct nla_policy *policy) -{ - return nla_validate(nla_data(start), nla_len(start), maxtype, policy); -} - -/** - * nla_need_padding_for_64bit - test 64-bit alignment of the next attribute - * @skb: socket buffer the message is stored in - * - * Return true if padding is needed to align the next attribute (nla_data()) to - * a 64-bit aligned area. - */ -static inline bool nla_need_padding_for_64bit(struct sk_buff *skb) -{ -#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS - /* The nlattr header is 4 bytes in size, that's why we test - * if the skb->data _is_ aligned. A NOP attribute, plus - * nlattr header for next attribute, will make nla_data() - * 8-byte aligned. - */ - if (IS_ALIGNED((unsigned long)skb_tail_pointer(skb), 8)) - return true; -#endif - return false; -} - -/** - * nla_align_64bit - 64-bit align the nla_data() of next attribute - * @skb: socket buffer the message is stored in - * @padattr: attribute type for the padding - * - * Conditionally emit a padding netlink attribute in order to make - * the next attribute we emit have a 64-bit aligned nla_data() area. - * This will only be done in architectures which do not have - * CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS defined. - * - * Returns zero on success or a negative error code. - */ -static inline int nla_align_64bit(struct sk_buff *skb, int padattr) -{ - if (nla_need_padding_for_64bit(skb) && - !nla_reserve(skb, padattr, 0)) - return -EMSGSIZE; - - return 0; -} - -/** - * nla_total_size_64bit - total length of attribute including padding - * @payload: length of payload - */ -static inline int nla_total_size_64bit(int payload) -{ - return NLA_ALIGN(nla_attr_size(payload)) -#ifndef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS - + NLA_ALIGN(nla_attr_size(0)) -#endif - ; -} - -/** - * nla_for_each_attr - iterate over a stream of attributes - * @pos: loop counter, set to current attribute - * @head: head of attribute stream - * @len: length of attribute stream - * @rem: initialized to len, holds bytes currently remaining in stream - */ -#define nla_for_each_attr(pos, head, len, rem) \ - for (pos = head, rem = len; \ - nla_ok(pos, rem); \ - pos = nla_next(pos, &(rem))) - -/** - * nla_for_each_nested - iterate over nested attributes - * @pos: loop counter, set to current attribute - * @nla: attribute containing the nested attributes - * @rem: initialized to len, holds bytes currently remaining in stream - */ -#define nla_for_each_nested(pos, nla, rem) \ - nla_for_each_attr(pos, nla_data(nla), nla_len(nla), rem) - -/** - * nla_is_last - Test if attribute is last in stream - * @nla: attribute to test - * @rem: bytes remaining in stream - */ -static inline bool nla_is_last(const struct nlattr *nla, int rem) -{ - return nla->nla_len == rem; -} - -#endif diff --git a/src/linux/include/net/netns/core.h b/src/linux/include/net/netns/core.h deleted file mode 100644 index 78eb1ff..0000000 --- a/src/linux/include/net/netns/core.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef __NETNS_CORE_H__ -#define __NETNS_CORE_H__ - -struct ctl_table_header; -struct prot_inuse; - -struct netns_core { - /* core sysctls */ - struct ctl_table_header *sysctl_hdr; - - int sysctl_somaxconn; - - struct prot_inuse __percpu *inuse; -}; - -#endif diff --git a/src/linux/include/net/netns/dccp.h b/src/linux/include/net/netns/dccp.h deleted file mode 100644 index 98d2a7c..0000000 --- a/src/linux/include/net/netns/dccp.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __NETNS_DCCP_H__ -#define __NETNS_DCCP_H__ - -struct sock; - -struct netns_dccp { - struct sock *v4_ctl_sk; - struct sock *v6_ctl_sk; -}; - -#endif diff --git a/src/linux/include/net/netns/generic.h b/src/linux/include/net/netns/generic.h deleted file mode 100644 index 70e1585..0000000 --- a/src/linux/include/net/netns/generic.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * generic net pointers - */ - -#ifndef __NET_GENERIC_H__ -#define __NET_GENERIC_H__ - -#include -#include - -/* - * Generic net pointers are to be used by modules to put some private - * stuff on the struct net without explicit struct net modification - * - * The rules are simple: - * 1. set pernet_operations->id. After register_pernet_device you - * will have the id of your private pointer. - * 2. set pernet_operations->size to have the code allocate and free - * a private structure pointed to from struct net. - * 3. do not change this pointer while the net is alive; - * 4. do not try to have any private reference on the net_generic object. - * - * After accomplishing all of the above, the private pointer can be - * accessed with the net_generic() call. - */ - -struct net_generic { - unsigned int len; - struct rcu_head rcu; - - void *ptr[0]; -}; - -static inline void *net_generic(const struct net *net, int id) -{ - struct net_generic *ng; - void *ptr; - - rcu_read_lock(); - ng = rcu_dereference(net->gen); - ptr = ng->ptr[id - 1]; - rcu_read_unlock(); - - return ptr; -} -#endif diff --git a/src/linux/include/net/netns/hash.h b/src/linux/include/net/netns/hash.h deleted file mode 100644 index 69a6715..0000000 --- a/src/linux/include/net/netns/hash.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __NET_NS_HASH_H__ -#define __NET_NS_HASH_H__ - -#include - -struct net; - -static inline u32 net_hash_mix(const struct net *net) -{ -#ifdef CONFIG_NET_NS - /* - * shift this right to eliminate bits, that are - * always zeroed - */ - - return (u32)(((unsigned long)net) >> L1_CACHE_SHIFT); -#else - return 0; -#endif -} -#endif diff --git a/src/linux/include/net/netns/ieee802154_6lowpan.h b/src/linux/include/net/netns/ieee802154_6lowpan.h deleted file mode 100644 index 8170f8d..0000000 --- a/src/linux/include/net/netns/ieee802154_6lowpan.h +++ /dev/null @@ -1,21 +0,0 @@ -/* - * ieee802154 6lowpan in net namespaces - */ - -#include - -#ifndef __NETNS_IEEE802154_6LOWPAN_H__ -#define __NETNS_IEEE802154_6LOWPAN_H__ - -struct netns_sysctl_lowpan { -#ifdef CONFIG_SYSCTL - struct ctl_table_header *frags_hdr; -#endif -}; - -struct netns_ieee802154_lowpan { - struct netns_sysctl_lowpan sysctl; - struct netns_frags frags; -}; - -#endif diff --git a/src/linux/include/net/netns/ipv4.h b/src/linux/include/net/netns/ipv4.h deleted file mode 100644 index 7adf438..0000000 --- a/src/linux/include/net/netns/ipv4.h +++ /dev/null @@ -1,140 +0,0 @@ -/* - * ipv4 in net namespaces - */ - -#ifndef __NETNS_IPV4_H__ -#define __NETNS_IPV4_H__ - -#include -#include -#include - -struct tcpm_hash_bucket; -struct ctl_table_header; -struct ipv4_devconf; -struct fib_rules_ops; -struct hlist_head; -struct fib_table; -struct sock; -struct local_ports { - seqlock_t lock; - int range[2]; - bool warned; -}; - -struct ping_group_range { - seqlock_t lock; - kgid_t range[2]; -}; - -struct netns_ipv4 { -#ifdef CONFIG_SYSCTL - struct ctl_table_header *forw_hdr; - struct ctl_table_header *frags_hdr; - struct ctl_table_header *ipv4_hdr; - struct ctl_table_header *route_hdr; - struct ctl_table_header *xfrm4_hdr; -#endif - struct ipv4_devconf *devconf_all; - struct ipv4_devconf *devconf_dflt; -#ifdef CONFIG_IP_MULTIPLE_TABLES - struct fib_rules_ops *rules_ops; - bool fib_has_custom_rules; - struct fib_table __rcu *fib_main; - struct fib_table __rcu *fib_default; -#endif -#ifdef CONFIG_IP_ROUTE_CLASSID - int fib_num_tclassid_users; -#endif - struct hlist_head *fib_table_hash; - bool fib_offload_disabled; - struct sock *fibnl; - - struct sock * __percpu *icmp_sk; - struct sock *mc_autojoin_sk; - - struct inet_peer_base *peers; - struct sock * __percpu *tcp_sk; - struct netns_frags frags; -#ifdef CONFIG_NETFILTER - struct xt_table *iptable_filter; - struct xt_table *iptable_mangle; - struct xt_table *iptable_raw; - struct xt_table *arptable_filter; -#ifdef CONFIG_SECURITY - struct xt_table *iptable_security; -#endif - struct xt_table *nat_table; -#endif - - int sysctl_icmp_echo_ignore_all; - int sysctl_icmp_echo_ignore_broadcasts; - int sysctl_icmp_ignore_bogus_error_responses; - int sysctl_icmp_ratelimit; - int sysctl_icmp_ratemask; - int sysctl_icmp_errors_use_inbound_ifaddr; - - struct local_ports ip_local_ports; - - int sysctl_tcp_ecn; - int sysctl_tcp_ecn_fallback; - - int sysctl_ip_default_ttl; - int sysctl_ip_no_pmtu_disc; - int sysctl_ip_fwd_use_pmtu; - int sysctl_ip_nonlocal_bind; - /* Shall we try to damage output packets if routing dev changes? */ - int sysctl_ip_dynaddr; - int sysctl_ip_early_demux; - - int sysctl_fwmark_reflect; - int sysctl_tcp_fwmark_accept; -#ifdef CONFIG_NET_L3_MASTER_DEV - int sysctl_tcp_l3mdev_accept; -#endif - int sysctl_tcp_mtu_probing; - int sysctl_tcp_base_mss; - int sysctl_tcp_probe_threshold; - u32 sysctl_tcp_probe_interval; - - int sysctl_tcp_keepalive_time; - int sysctl_tcp_keepalive_probes; - int sysctl_tcp_keepalive_intvl; - - int sysctl_tcp_syn_retries; - int sysctl_tcp_synack_retries; - int sysctl_tcp_syncookies; - int sysctl_tcp_reordering; - int sysctl_tcp_retries1; - int sysctl_tcp_retries2; - int sysctl_tcp_orphan_retries; - int sysctl_tcp_fin_timeout; - unsigned int sysctl_tcp_notsent_lowat; - - int sysctl_igmp_max_memberships; - int sysctl_igmp_max_msf; - int sysctl_igmp_llm_reports; - int sysctl_igmp_qrv; - - struct ping_group_range ping_group_range; - - atomic_t dev_addr_genid; - -#ifdef CONFIG_SYSCTL - unsigned long *sysctl_local_reserved_ports; -#endif - -#ifdef CONFIG_IP_MROUTE -#ifndef CONFIG_IP_MROUTE_MULTIPLE_TABLES - struct mr_table *mrt; -#else - struct list_head mr_tables; - struct fib_rules_ops *mr_rules_ops; -#endif -#endif -#ifdef CONFIG_IP_ROUTE_MULTIPATH - int sysctl_fib_multipath_use_neigh; -#endif - atomic_t rt_genid; -}; -#endif diff --git a/src/linux/include/net/netns/ipv6.h b/src/linux/include/net/netns/ipv6.h deleted file mode 100644 index 10d0848..0000000 --- a/src/linux/include/net/netns/ipv6.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * ipv6 in net namespaces - */ - -#include - -#ifndef __NETNS_IPV6_H__ -#define __NETNS_IPV6_H__ -#include - -struct ctl_table_header; - -struct netns_sysctl_ipv6 { -#ifdef CONFIG_SYSCTL - struct ctl_table_header *hdr; - struct ctl_table_header *route_hdr; - struct ctl_table_header *icmp_hdr; - struct ctl_table_header *frags_hdr; - struct ctl_table_header *xfrm6_hdr; -#endif - int bindv6only; - int flush_delay; - int ip6_rt_max_size; - int ip6_rt_gc_min_interval; - int ip6_rt_gc_timeout; - int ip6_rt_gc_interval; - int ip6_rt_gc_elasticity; - int ip6_rt_mtu_expires; - int ip6_rt_min_advmss; - int flowlabel_consistency; - int auto_flowlabels; - int icmpv6_time; - int anycast_src_echo_reply; - int ip_nonlocal_bind; - int fwmark_reflect; - int idgen_retries; - int idgen_delay; - int flowlabel_state_ranges; -}; - -struct netns_ipv6 { - struct netns_sysctl_ipv6 sysctl; - struct ipv6_devconf *devconf_all; - struct ipv6_devconf *devconf_dflt; - struct inet_peer_base *peers; - struct netns_frags frags; -#ifdef CONFIG_NETFILTER - struct xt_table *ip6table_filter; - struct xt_table *ip6table_mangle; - struct xt_table *ip6table_raw; -#ifdef CONFIG_SECURITY - struct xt_table *ip6table_security; -#endif - struct xt_table *ip6table_nat; -#endif - struct rt6_info *ip6_null_entry; - struct rt6_statistics *rt6_stats; - struct timer_list ip6_fib_timer; - struct hlist_head *fib_table_hash; - struct fib6_table *fib6_main_tbl; - struct list_head fib6_walkers; - struct dst_ops ip6_dst_ops; - rwlock_t fib6_walker_lock; - spinlock_t fib6_gc_lock; - unsigned int ip6_rt_gc_expire; - unsigned long ip6_rt_last_gc; -#ifdef CONFIG_IPV6_MULTIPLE_TABLES - struct rt6_info *ip6_prohibit_entry; - struct rt6_info *ip6_blk_hole_entry; - struct fib6_table *fib6_local_tbl; - struct fib_rules_ops *fib6_rules_ops; -#endif - struct sock **icmp_sk; - struct sock *ndisc_sk; - struct sock *tcp_sk; - struct sock *igmp_sk; - struct sock *mc_autojoin_sk; -#ifdef CONFIG_IPV6_MROUTE -#ifndef CONFIG_IPV6_MROUTE_MULTIPLE_TABLES - struct mr6_table *mrt6; -#else - struct list_head mr6_tables; - struct fib_rules_ops *mr6_rules_ops; -#endif -#endif - atomic_t dev_addr_genid; - atomic_t fib6_sernum; -}; - -#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV6) -struct netns_nf_frag { - struct netns_sysctl_ipv6 sysctl; - struct netns_frags frags; -}; -#endif - -#endif diff --git a/src/linux/include/net/netns/mib.h b/src/linux/include/net/netns/mib.h deleted file mode 100644 index d542a4b..0000000 --- a/src/linux/include/net/netns/mib.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __NETNS_MIB_H__ -#define __NETNS_MIB_H__ - -#include - -struct netns_mib { - DEFINE_SNMP_STAT(struct tcp_mib, tcp_statistics); - DEFINE_SNMP_STAT(struct ipstats_mib, ip_statistics); - DEFINE_SNMP_STAT(struct linux_mib, net_statistics); - DEFINE_SNMP_STAT(struct udp_mib, udp_statistics); - DEFINE_SNMP_STAT(struct udp_mib, udplite_statistics); - DEFINE_SNMP_STAT(struct icmp_mib, icmp_statistics); - DEFINE_SNMP_STAT_ATOMIC(struct icmpmsg_mib, icmpmsg_statistics); - -#if IS_ENABLED(CONFIG_IPV6) - struct proc_dir_entry *proc_net_devsnmp6; - DEFINE_SNMP_STAT(struct udp_mib, udp_stats_in6); - DEFINE_SNMP_STAT(struct udp_mib, udplite_stats_in6); - DEFINE_SNMP_STAT(struct ipstats_mib, ipv6_statistics); - DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics); - DEFINE_SNMP_STAT_ATOMIC(struct icmpv6msg_mib, icmpv6msg_statistics); -#endif -#ifdef CONFIG_XFRM_STATISTICS - DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics); -#endif -}; - -#endif diff --git a/src/linux/include/net/netns/mpls.h b/src/linux/include/net/netns/mpls.h deleted file mode 100644 index d292036..0000000 --- a/src/linux/include/net/netns/mpls.h +++ /dev/null @@ -1,17 +0,0 @@ -/* - * mpls in net namespaces - */ - -#ifndef __NETNS_MPLS_H__ -#define __NETNS_MPLS_H__ - -struct mpls_route; -struct ctl_table_header; - -struct netns_mpls { - size_t platform_labels; - struct mpls_route __rcu * __rcu *platform_label; - struct ctl_table_header *ctl; -}; - -#endif /* __NETNS_MPLS_H__ */ diff --git a/src/linux/include/net/netns/netfilter.h b/src/linux/include/net/netns/netfilter.h deleted file mode 100644 index 58487b1..0000000 --- a/src/linux/include/net/netns/netfilter.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef __NETNS_NETFILTER_H -#define __NETNS_NETFILTER_H - -#include - -struct proc_dir_entry; -struct nf_logger; -struct nf_queue_handler; - -struct netns_nf { -#if defined CONFIG_PROC_FS - struct proc_dir_entry *proc_netfilter; -#endif - const struct nf_queue_handler __rcu *queue_handler; - const struct nf_logger __rcu *nf_loggers[NFPROTO_NUMPROTO]; -#ifdef CONFIG_SYSCTL - struct ctl_table_header *nf_log_dir_header; -#endif - struct nf_hook_entry __rcu *hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS]; -}; -#endif diff --git a/src/linux/include/net/netns/nftables.h b/src/linux/include/net/netns/nftables.h deleted file mode 100644 index c807811..0000000 --- a/src/linux/include/net/netns/nftables.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _NETNS_NFTABLES_H_ -#define _NETNS_NFTABLES_H_ - -#include - -struct nft_af_info; - -struct netns_nftables { - struct list_head af_info; - struct list_head commit_list; - struct nft_af_info *ipv4; - struct nft_af_info *ipv6; - struct nft_af_info *inet; - struct nft_af_info *arp; - struct nft_af_info *bridge; - struct nft_af_info *netdev; - unsigned int base_seq; - u8 gencursor; -}; - -#endif diff --git a/src/linux/include/net/netns/packet.h b/src/linux/include/net/netns/packet.h deleted file mode 100644 index 17ec2b9..0000000 --- a/src/linux/include/net/netns/packet.h +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Packet network namespace - */ -#ifndef __NETNS_PACKET_H__ -#define __NETNS_PACKET_H__ - -#include -#include - -struct netns_packet { - struct mutex sklist_lock; - struct hlist_head sklist; -}; - -#endif /* __NETNS_PACKET_H__ */ diff --git a/src/linux/include/net/netns/sctp.h b/src/linux/include/net/netns/sctp.h deleted file mode 100644 index c501d67..0000000 --- a/src/linux/include/net/netns/sctp.h +++ /dev/null @@ -1,142 +0,0 @@ -#ifndef __NETNS_SCTP_H__ -#define __NETNS_SCTP_H__ - -struct sock; -struct proc_dir_entry; -struct sctp_mib; -struct ctl_table_header; - -struct netns_sctp { - DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics); - -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *proc_net_sctp; -#endif -#ifdef CONFIG_SYSCTL - struct ctl_table_header *sysctl_header; -#endif - /* This is the global socket data structure used for responding to - * the Out-of-the-blue (OOTB) packets. A control sock will be created - * for this socket at the initialization time. - */ - struct sock *ctl_sock; - - /* This is the global local address list. - * We actively maintain this complete list of addresses on - * the system by catching address add/delete events. - * - * It is a list of sctp_sockaddr_entry. - */ - struct list_head local_addr_list; - struct list_head addr_waitq; - struct timer_list addr_wq_timer; - struct list_head auto_asconf_splist; - /* Lock that protects both addr_waitq and auto_asconf_splist */ - spinlock_t addr_wq_lock; - - /* Lock that protects the local_addr_list writers */ - spinlock_t local_addr_lock; - - /* RFC2960 Section 14. Suggested SCTP Protocol Parameter Values - * - * The following protocol parameters are RECOMMENDED: - * - * RTO.Initial - 3 seconds - * RTO.Min - 1 second - * RTO.Max - 60 seconds - * RTO.Alpha - 1/8 (3 when converted to right shifts.) - * RTO.Beta - 1/4 (2 when converted to right shifts.) - */ - unsigned int rto_initial; - unsigned int rto_min; - unsigned int rto_max; - - /* Note: rto_alpha and rto_beta are really defined as inverse - * powers of two to facilitate integer operations. - */ - int rto_alpha; - int rto_beta; - - /* Max.Burst - 4 */ - int max_burst; - - /* Whether Cookie Preservative is enabled(1) or not(0) */ - int cookie_preserve_enable; - - /* The namespace default hmac alg */ - char *sctp_hmac_alg; - - /* Valid.Cookie.Life - 60 seconds */ - unsigned int valid_cookie_life; - - /* Delayed SACK timeout 200ms default*/ - unsigned int sack_timeout; - - /* HB.interval - 30 seconds */ - unsigned int hb_interval; - - /* Association.Max.Retrans - 10 attempts - * Path.Max.Retrans - 5 attempts (per destination address) - * Max.Init.Retransmits - 8 attempts - */ - int max_retrans_association; - int max_retrans_path; - int max_retrans_init; - /* Potentially-Failed.Max.Retrans sysctl value - * taken from: - * http://tools.ietf.org/html/draft-nishida-tsvwg-sctp-failover-05 - */ - int pf_retrans; - - /* - * Disable Potentially-Failed feature, the feature is enabled by default - * pf_enable - 0 : disable pf - * - >0 : enable pf - */ - int pf_enable; - - /* - * Policy for preforming sctp/socket accounting - * 0 - do socket level accounting, all assocs share sk_sndbuf - * 1 - do sctp accounting, each asoc may use sk_sndbuf bytes - */ - int sndbuf_policy; - - /* - * Policy for preforming sctp/socket accounting - * 0 - do socket level accounting, all assocs share sk_rcvbuf - * 1 - do sctp accounting, each asoc may use sk_rcvbuf bytes - */ - int rcvbuf_policy; - - int default_auto_asconf; - - /* Flag to indicate if addip is enabled. */ - int addip_enable; - int addip_noauth; - - /* Flag to indicate if PR-SCTP is enabled. */ - int prsctp_enable; - - /* Flag to idicate if SCTP-AUTH is enabled */ - int auth_enable; - - /* - * Policy to control SCTP IPv4 address scoping - * 0 - Disable IPv4 address scoping - * 1 - Enable IPv4 address scoping - * 2 - Selectively allow only IPv4 private addresses - * 3 - Selectively allow only IPv4 link local address - */ - int scope_policy; - - /* Threshold for rwnd update SACKS. Receive buffer shifted this many - * bits is an indicator of when to send and window update SACK. - */ - int rwnd_upd_shift; - - /* Threshold for autoclose timeout, in seconds. */ - unsigned long max_autoclose; -}; - -#endif /* __NETNS_SCTP_H__ */ diff --git a/src/linux/include/net/netns/unix.h b/src/linux/include/net/netns/unix.h deleted file mode 100644 index 284649d..0000000 --- a/src/linux/include/net/netns/unix.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Unix network namespace - */ -#ifndef __NETNS_UNIX_H__ -#define __NETNS_UNIX_H__ - -struct ctl_table_header; -struct netns_unix { - int sysctl_max_dgram_qlen; - struct ctl_table_header *ctl; -}; - -#endif /* __NETNS_UNIX_H__ */ diff --git a/src/linux/include/net/netns/x_tables.h b/src/linux/include/net/netns/x_tables.h deleted file mode 100644 index c8a7681..0000000 --- a/src/linux/include/net/netns/x_tables.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef __NETNS_X_TABLES_H -#define __NETNS_X_TABLES_H - -#include -#include - -struct ebt_table; - -struct netns_xt { - struct list_head tables[NFPROTO_NUMPROTO]; - bool notrack_deprecated_warning; - bool clusterip_deprecated_warning; -#if defined(CONFIG_BRIDGE_NF_EBTABLES) || \ - defined(CONFIG_BRIDGE_NF_EBTABLES_MODULE) - struct ebt_table *broute_table; - struct ebt_table *frame_filter; - struct ebt_table *frame_nat; -#endif -}; -#endif diff --git a/src/linux/include/net/netns/xfrm.h b/src/linux/include/net/netns/xfrm.h deleted file mode 100644 index 27bb963..0000000 --- a/src/linux/include/net/netns/xfrm.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef __NETNS_XFRM_H -#define __NETNS_XFRM_H - -#include -#include -#include -#include -#include -#include - -struct ctl_table_header; - -struct xfrm_policy_hash { - struct hlist_head __rcu *table; - unsigned int hmask; - u8 dbits4; - u8 sbits4; - u8 dbits6; - u8 sbits6; -}; - -struct xfrm_policy_hthresh { - struct work_struct work; - seqlock_t lock; - u8 lbits4; - u8 rbits4; - u8 lbits6; - u8 rbits6; -}; - -struct netns_xfrm { - struct list_head state_all; - /* - * Hash table to find appropriate SA towards given target (endpoint of - * tunnel or destination of transport mode) allowed by selector. - * - * Main use is finding SA after policy selected tunnel or transport - * mode. Also, it can be used by ah/esp icmp error handler to find - * offending SA. - */ - struct hlist_head __rcu *state_bydst; - struct hlist_head __rcu *state_bysrc; - struct hlist_head __rcu *state_byspi; - unsigned int state_hmask; - unsigned int state_num; - struct work_struct state_hash_work; - - struct list_head policy_all; - struct hlist_head *policy_byidx; - unsigned int policy_idx_hmask; - struct hlist_head policy_inexact[XFRM_POLICY_MAX]; - struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX]; - unsigned int policy_count[XFRM_POLICY_MAX * 2]; - struct work_struct policy_hash_work; - struct xfrm_policy_hthresh policy_hthresh; - - - struct sock *nlsk; - struct sock *nlsk_stash; - - u32 sysctl_aevent_etime; - u32 sysctl_aevent_rseqth; - int sysctl_larval_drop; - u32 sysctl_acq_expires; -#ifdef CONFIG_SYSCTL - struct ctl_table_header *sysctl_hdr; -#endif - - struct dst_ops xfrm4_dst_ops; -#if IS_ENABLED(CONFIG_IPV6) - struct dst_ops xfrm6_dst_ops; -#endif - spinlock_t xfrm_state_lock; - spinlock_t xfrm_policy_lock; - struct mutex xfrm_cfg_mutex; - - /* flow cache part */ - struct flow_cache flow_cache_global; - atomic_t flow_cache_genid; - struct list_head flow_cache_gc_list; - atomic_t flow_cache_gc_count; - spinlock_t flow_cache_gc_lock; - struct work_struct flow_cache_gc_work; - struct work_struct flow_cache_flush_work; - struct mutex flow_flush_sem; -}; - -#endif diff --git a/src/linux/include/net/netprio_cgroup.h b/src/linux/include/net/netprio_cgroup.h deleted file mode 100644 index 6041905..0000000 --- a/src/linux/include/net/netprio_cgroup.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * netprio_cgroup.h Control Group Priority set - * - * - * Authors: Neil Horman - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#ifndef _NETPRIO_CGROUP_H -#define _NETPRIO_CGROUP_H - -#include -#include -#include - -#if IS_ENABLED(CONFIG_CGROUP_NET_PRIO) -struct netprio_map { - struct rcu_head rcu; - u32 priomap_len; - u32 priomap[]; -}; - -static inline u32 task_netprioidx(struct task_struct *p) -{ - struct cgroup_subsys_state *css; - u32 idx; - - rcu_read_lock(); - css = task_css(p, net_prio_cgrp_id); - idx = css->cgroup->id; - rcu_read_unlock(); - return idx; -} - -static inline void sock_update_netprioidx(struct sock_cgroup_data *skcd) -{ - if (in_interrupt()) - return; - - sock_cgroup_set_prioidx(skcd, task_netprioidx(current)); -} - -#else /* !CONFIG_CGROUP_NET_PRIO */ - -static inline u32 task_netprioidx(struct task_struct *p) -{ - return 0; -} - -static inline void sock_update_netprioidx(struct sock_cgroup_data *skcd) -{ -} - -#endif /* CONFIG_CGROUP_NET_PRIO */ -#endif /* _NET_CLS_CGROUP_H */ diff --git a/src/linux/include/net/netrom.h b/src/linux/include/net/netrom.h deleted file mode 100644 index 110350a..0000000 --- a/src/linux/include/net/netrom.h +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Declarations of NET/ROM type objects. - * - * Jonathan Naylor G4KLX 9/4/95 - */ - -#ifndef _NETROM_H -#define _NETROM_H - -#include -#include -#include -#include - -#define NR_NETWORK_LEN 15 -#define NR_TRANSPORT_LEN 5 - -#define NR_PROTO_IP 0x0C - -#define NR_PROTOEXT 0x00 -#define NR_CONNREQ 0x01 -#define NR_CONNACK 0x02 -#define NR_DISCREQ 0x03 -#define NR_DISCACK 0x04 -#define NR_INFO 0x05 -#define NR_INFOACK 0x06 -#define NR_RESET 0x07 - -#define NR_CHOKE_FLAG 0x80 -#define NR_NAK_FLAG 0x40 -#define NR_MORE_FLAG 0x20 - -/* Define Link State constants. */ -enum { - NR_STATE_0, - NR_STATE_1, - NR_STATE_2, - NR_STATE_3 -}; - -#define NR_COND_ACK_PENDING 0x01 -#define NR_COND_REJECT 0x02 -#define NR_COND_PEER_RX_BUSY 0x04 -#define NR_COND_OWN_RX_BUSY 0x08 - -#define NR_DEFAULT_T1 120000 /* Outstanding frames - 120 seconds */ -#define NR_DEFAULT_T2 5000 /* Response delay - 5 seconds */ -#define NR_DEFAULT_N2 3 /* Number of Retries - 3 */ -#define NR_DEFAULT_T4 180000 /* Busy Delay - 180 seconds */ -#define NR_DEFAULT_IDLE 0 /* No Activity Timeout - none */ -#define NR_DEFAULT_WINDOW 4 /* Default Window Size - 4 */ -#define NR_DEFAULT_OBS 6 /* Default Obsolescence Count - 6 */ -#define NR_DEFAULT_QUAL 10 /* Default Neighbour Quality - 10 */ -#define NR_DEFAULT_TTL 16 /* Default Time To Live - 16 */ -#define NR_DEFAULT_ROUTING 1 /* Is routing enabled ? */ -#define NR_DEFAULT_FAILS 2 /* Link fails until route fails */ -#define NR_DEFAULT_RESET 0 /* Sent / accept reset cmds? */ - -#define NR_MODULUS 256 -#define NR_MAX_WINDOW_SIZE 127 /* Maximum Window Allowable - 127 */ -#define NR_MAX_PACKET_SIZE 236 /* Maximum Packet Length - 236 */ - -struct nr_sock { - struct sock sock; - ax25_address user_addr, source_addr, dest_addr; - struct net_device *device; - unsigned char my_index, my_id; - unsigned char your_index, your_id; - unsigned char state, condition, bpqext, window; - unsigned short vs, vr, va, vl; - unsigned char n2, n2count; - unsigned long t1, t2, t4, idle; - unsigned short fraglen; - struct timer_list t1timer; - struct timer_list t2timer; - struct timer_list t4timer; - struct timer_list idletimer; - struct sk_buff_head ack_queue; - struct sk_buff_head reseq_queue; - struct sk_buff_head frag_queue; -}; - -#define nr_sk(sk) ((struct nr_sock *)(sk)) - -struct nr_neigh { - struct hlist_node neigh_node; - ax25_address callsign; - ax25_digi *digipeat; - ax25_cb *ax25; - struct net_device *dev; - unsigned char quality; - unsigned char locked; - unsigned short count; - unsigned int number; - unsigned char failed; - atomic_t refcount; -}; - -struct nr_route { - unsigned char quality; - unsigned char obs_count; - struct nr_neigh *neighbour; -}; - -struct nr_node { - struct hlist_node node_node; - ax25_address callsign; - char mnemonic[7]; - unsigned char which; - unsigned char count; - struct nr_route routes[3]; - atomic_t refcount; - spinlock_t node_lock; -}; - -/********************************************************************* - * nr_node & nr_neigh lists, refcounting and locking - *********************************************************************/ - -#define nr_node_hold(__nr_node) \ - atomic_inc(&((__nr_node)->refcount)) - -static __inline__ void nr_node_put(struct nr_node *nr_node) -{ - if (atomic_dec_and_test(&nr_node->refcount)) { - kfree(nr_node); - } -} - -#define nr_neigh_hold(__nr_neigh) \ - atomic_inc(&((__nr_neigh)->refcount)) - -static __inline__ void nr_neigh_put(struct nr_neigh *nr_neigh) -{ - if (atomic_dec_and_test(&nr_neigh->refcount)) { - if (nr_neigh->ax25) - ax25_cb_put(nr_neigh->ax25); - kfree(nr_neigh->digipeat); - kfree(nr_neigh); - } -} - -/* nr_node_lock and nr_node_unlock also hold/put the node's refcounter. - */ -static __inline__ void nr_node_lock(struct nr_node *nr_node) -{ - nr_node_hold(nr_node); - spin_lock_bh(&nr_node->node_lock); -} - -static __inline__ void nr_node_unlock(struct nr_node *nr_node) -{ - spin_unlock_bh(&nr_node->node_lock); - nr_node_put(nr_node); -} - -#define nr_neigh_for_each(__nr_neigh, list) \ - hlist_for_each_entry(__nr_neigh, list, neigh_node) - -#define nr_neigh_for_each_safe(__nr_neigh, node2, list) \ - hlist_for_each_entry_safe(__nr_neigh, node2, list, neigh_node) - -#define nr_node_for_each(__nr_node, list) \ - hlist_for_each_entry(__nr_node, list, node_node) - -#define nr_node_for_each_safe(__nr_node, node2, list) \ - hlist_for_each_entry_safe(__nr_node, node2, list, node_node) - - -/*********************************************************************/ - -/* af_netrom.c */ -extern int sysctl_netrom_default_path_quality; -extern int sysctl_netrom_obsolescence_count_initialiser; -extern int sysctl_netrom_network_ttl_initialiser; -extern int sysctl_netrom_transport_timeout; -extern int sysctl_netrom_transport_maximum_tries; -extern int sysctl_netrom_transport_acknowledge_delay; -extern int sysctl_netrom_transport_busy_delay; -extern int sysctl_netrom_transport_requested_window_size; -extern int sysctl_netrom_transport_no_activity_timeout; -extern int sysctl_netrom_routing_control; -extern int sysctl_netrom_link_fails_count; -extern int sysctl_netrom_reset_circuit; - -int nr_rx_frame(struct sk_buff *, struct net_device *); -void nr_destroy_socket(struct sock *); - -/* nr_dev.c */ -int nr_rx_ip(struct sk_buff *, struct net_device *); -void nr_setup(struct net_device *); - -/* nr_in.c */ -int nr_process_rx_frame(struct sock *, struct sk_buff *); - -/* nr_loopback.c */ -void nr_loopback_init(void); -void nr_loopback_clear(void); -int nr_loopback_queue(struct sk_buff *); - -/* nr_out.c */ -void nr_output(struct sock *, struct sk_buff *); -void nr_send_nak_frame(struct sock *); -void nr_kick(struct sock *); -void nr_transmit_buffer(struct sock *, struct sk_buff *); -void nr_establish_data_link(struct sock *); -void nr_enquiry_response(struct sock *); -void nr_check_iframes_acked(struct sock *, unsigned short); - -/* nr_route.c */ -void nr_rt_device_down(struct net_device *); -struct net_device *nr_dev_first(void); -struct net_device *nr_dev_get(ax25_address *); -int nr_rt_ioctl(unsigned int, void __user *); -void nr_link_failed(ax25_cb *, int); -int nr_route_frame(struct sk_buff *, ax25_cb *); -extern const struct file_operations nr_nodes_fops; -extern const struct file_operations nr_neigh_fops; -void nr_rt_free(void); - -/* nr_subr.c */ -void nr_clear_queues(struct sock *); -void nr_frames_acked(struct sock *, unsigned short); -void nr_requeue_frames(struct sock *); -int nr_validate_nr(struct sock *, unsigned short); -int nr_in_rx_window(struct sock *, unsigned short); -void nr_write_internal(struct sock *, int); - -void __nr_transmit_reply(struct sk_buff *skb, int mine, unsigned char cmdflags); - -/* - * This routine is called when a Connect Acknowledge with the Choke Flag - * set is needed to refuse a connection. - */ -#define nr_transmit_refusal(skb, mine) \ -do { \ - __nr_transmit_reply((skb), (mine), NR_CONNACK | NR_CHOKE_FLAG); \ -} while (0) - -/* - * This routine is called when we don't have a circuit matching an incoming - * NET/ROM packet. This is an G8PZT Xrouter extension. - */ -#define nr_transmit_reset(skb, mine) \ -do { \ - __nr_transmit_reply((skb), (mine), NR_RESET); \ -} while (0) - -void nr_disconnect(struct sock *, int); - -/* nr_timer.c */ -void nr_init_timers(struct sock *sk); -void nr_start_heartbeat(struct sock *); -void nr_start_t1timer(struct sock *); -void nr_start_t2timer(struct sock *); -void nr_start_t4timer(struct sock *); -void nr_start_idletimer(struct sock *); -void nr_stop_heartbeat(struct sock *); -void nr_stop_t1timer(struct sock *); -void nr_stop_t2timer(struct sock *); -void nr_stop_t4timer(struct sock *); -void nr_stop_idletimer(struct sock *); -int nr_t1timer_running(struct sock *); - -/* sysctl_net_netrom.c */ -void nr_register_sysctl(void); -void nr_unregister_sysctl(void); - -#endif diff --git a/src/linux/include/net/nexthop.h b/src/linux/include/net/nexthop.h deleted file mode 100644 index 3334dbf..0000000 --- a/src/linux/include/net/nexthop.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef __NET_NEXTHOP_H -#define __NET_NEXTHOP_H - -#include -#include - -static inline int rtnh_ok(const struct rtnexthop *rtnh, int remaining) -{ - return remaining >= sizeof(*rtnh) && - rtnh->rtnh_len >= sizeof(*rtnh) && - rtnh->rtnh_len <= remaining; -} - -static inline struct rtnexthop *rtnh_next(const struct rtnexthop *rtnh, - int *remaining) -{ - int totlen = NLA_ALIGN(rtnh->rtnh_len); - - *remaining -= totlen; - return (struct rtnexthop *) ((char *) rtnh + totlen); -} - -static inline struct nlattr *rtnh_attrs(const struct rtnexthop *rtnh) -{ - return (struct nlattr *) ((char *) rtnh + NLA_ALIGN(sizeof(*rtnh))); -} - -static inline int rtnh_attrlen(const struct rtnexthop *rtnh) -{ - return rtnh->rtnh_len - NLA_ALIGN(sizeof(*rtnh)); -} - -#endif diff --git a/src/linux/include/net/nl802154.h b/src/linux/include/net/nl802154.h deleted file mode 100644 index ddcee12..0000000 --- a/src/linux/include/net/nl802154.h +++ /dev/null @@ -1,452 +0,0 @@ -#ifndef __NL802154_H -#define __NL802154_H -/* - * 802.15.4 netlink interface public header - * - * Copyright 2014 Alexander Aring - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - * - */ - -#define NL802154_GENL_NAME "nl802154" - -enum nl802154_commands { -/* don't change the order or add anything between, this is ABI! */ -/* currently we don't shipping this file via uapi, ignore the above one */ - NL802154_CMD_UNSPEC, - - NL802154_CMD_GET_WPAN_PHY, /* can dump */ - NL802154_CMD_SET_WPAN_PHY, - NL802154_CMD_NEW_WPAN_PHY, - NL802154_CMD_DEL_WPAN_PHY, - - NL802154_CMD_GET_INTERFACE, /* can dump */ - NL802154_CMD_SET_INTERFACE, - NL802154_CMD_NEW_INTERFACE, - NL802154_CMD_DEL_INTERFACE, - - NL802154_CMD_SET_CHANNEL, - - NL802154_CMD_SET_PAN_ID, - NL802154_CMD_SET_SHORT_ADDR, - - NL802154_CMD_SET_TX_POWER, - NL802154_CMD_SET_CCA_MODE, - NL802154_CMD_SET_CCA_ED_LEVEL, - - NL802154_CMD_SET_MAX_FRAME_RETRIES, - - NL802154_CMD_SET_BACKOFF_EXPONENT, - NL802154_CMD_SET_MAX_CSMA_BACKOFFS, - - NL802154_CMD_SET_LBT_MODE, - - NL802154_CMD_SET_ACKREQ_DEFAULT, - - NL802154_CMD_SET_WPAN_PHY_NETNS, - - /* add new commands above here */ - -#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL - NL802154_CMD_SET_SEC_PARAMS, - NL802154_CMD_GET_SEC_KEY, /* can dump */ - NL802154_CMD_NEW_SEC_KEY, - NL802154_CMD_DEL_SEC_KEY, - NL802154_CMD_GET_SEC_DEV, /* can dump */ - NL802154_CMD_NEW_SEC_DEV, - NL802154_CMD_DEL_SEC_DEV, - NL802154_CMD_GET_SEC_DEVKEY, /* can dump */ - NL802154_CMD_NEW_SEC_DEVKEY, - NL802154_CMD_DEL_SEC_DEVKEY, - NL802154_CMD_GET_SEC_LEVEL, /* can dump */ - NL802154_CMD_NEW_SEC_LEVEL, - NL802154_CMD_DEL_SEC_LEVEL, -#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ - - /* used to define NL802154_CMD_MAX below */ - __NL802154_CMD_AFTER_LAST, - NL802154_CMD_MAX = __NL802154_CMD_AFTER_LAST - 1 -}; - -enum nl802154_attrs { -/* don't change the order or add anything between, this is ABI! */ -/* currently we don't shipping this file via uapi, ignore the above one */ - NL802154_ATTR_UNSPEC, - - NL802154_ATTR_WPAN_PHY, - NL802154_ATTR_WPAN_PHY_NAME, - - NL802154_ATTR_IFINDEX, - NL802154_ATTR_IFNAME, - NL802154_ATTR_IFTYPE, - - NL802154_ATTR_WPAN_DEV, - - NL802154_ATTR_PAGE, - NL802154_ATTR_CHANNEL, - - NL802154_ATTR_PAN_ID, - NL802154_ATTR_SHORT_ADDR, - - NL802154_ATTR_TX_POWER, - - NL802154_ATTR_CCA_MODE, - NL802154_ATTR_CCA_OPT, - NL802154_ATTR_CCA_ED_LEVEL, - - NL802154_ATTR_MAX_FRAME_RETRIES, - - NL802154_ATTR_MAX_BE, - NL802154_ATTR_MIN_BE, - NL802154_ATTR_MAX_CSMA_BACKOFFS, - - NL802154_ATTR_LBT_MODE, - - NL802154_ATTR_GENERATION, - - NL802154_ATTR_CHANNELS_SUPPORTED, - NL802154_ATTR_SUPPORTED_CHANNEL, - - NL802154_ATTR_EXTENDED_ADDR, - - NL802154_ATTR_WPAN_PHY_CAPS, - - NL802154_ATTR_SUPPORTED_COMMANDS, - - NL802154_ATTR_ACKREQ_DEFAULT, - - NL802154_ATTR_PAD, - - NL802154_ATTR_PID, - NL802154_ATTR_NETNS_FD, - - /* add attributes here, update the policy in nl802154.c */ - -#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL - NL802154_ATTR_SEC_ENABLED, - NL802154_ATTR_SEC_OUT_LEVEL, - NL802154_ATTR_SEC_OUT_KEY_ID, - NL802154_ATTR_SEC_FRAME_COUNTER, - - NL802154_ATTR_SEC_LEVEL, - NL802154_ATTR_SEC_DEVICE, - NL802154_ATTR_SEC_DEVKEY, - NL802154_ATTR_SEC_KEY, -#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ - - __NL802154_ATTR_AFTER_LAST, - NL802154_ATTR_MAX = __NL802154_ATTR_AFTER_LAST - 1 -}; - -enum nl802154_iftype { - /* for backwards compatibility TODO */ - NL802154_IFTYPE_UNSPEC = -1, - - NL802154_IFTYPE_NODE, - NL802154_IFTYPE_MONITOR, - NL802154_IFTYPE_COORD, - - /* keep last */ - NUM_NL802154_IFTYPES, - NL802154_IFTYPE_MAX = NUM_NL802154_IFTYPES - 1 -}; - -/** - * enum nl802154_wpan_phy_capability_attr - wpan phy capability attributes - * - * @__NL802154_CAP_ATTR_INVALID: attribute number 0 is reserved - * @NL802154_CAP_ATTR_CHANNELS: a nested attribute for nl802154_channel_attr - * @NL802154_CAP_ATTR_TX_POWERS: a nested attribute for - * nl802154_wpan_phy_tx_power - * @NL802154_CAP_ATTR_MIN_CCA_ED_LEVEL: minimum value for cca_ed_level - * @NL802154_CAP_ATTR_MAX_CCA_ED_LEVEL: maxmimum value for cca_ed_level - * @NL802154_CAP_ATTR_CCA_MODES: nl802154_cca_modes flags - * @NL802154_CAP_ATTR_CCA_OPTS: nl802154_cca_opts flags - * @NL802154_CAP_ATTR_MIN_MINBE: minimum of minbe value - * @NL802154_CAP_ATTR_MAX_MINBE: maximum of minbe value - * @NL802154_CAP_ATTR_MIN_MAXBE: minimum of maxbe value - * @NL802154_CAP_ATTR_MAX_MINBE: maximum of maxbe value - * @NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS: minimum of csma backoff value - * @NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS: maximum of csma backoffs value - * @NL802154_CAP_ATTR_MIN_FRAME_RETRIES: minimum of frame retries value - * @NL802154_CAP_ATTR_MAX_FRAME_RETRIES: maximum of frame retries value - * @NL802154_CAP_ATTR_IFTYPES: nl802154_iftype flags - * @NL802154_CAP_ATTR_LBT: nl802154_supported_bool_states flags - * @NL802154_CAP_ATTR_MAX: highest cap attribute currently defined - * @__NL802154_CAP_ATTR_AFTER_LAST: internal use - */ -enum nl802154_wpan_phy_capability_attr { - __NL802154_CAP_ATTR_INVALID, - - NL802154_CAP_ATTR_IFTYPES, - - NL802154_CAP_ATTR_CHANNELS, - NL802154_CAP_ATTR_TX_POWERS, - - NL802154_CAP_ATTR_CCA_ED_LEVELS, - NL802154_CAP_ATTR_CCA_MODES, - NL802154_CAP_ATTR_CCA_OPTS, - - NL802154_CAP_ATTR_MIN_MINBE, - NL802154_CAP_ATTR_MAX_MINBE, - - NL802154_CAP_ATTR_MIN_MAXBE, - NL802154_CAP_ATTR_MAX_MAXBE, - - NL802154_CAP_ATTR_MIN_CSMA_BACKOFFS, - NL802154_CAP_ATTR_MAX_CSMA_BACKOFFS, - - NL802154_CAP_ATTR_MIN_FRAME_RETRIES, - NL802154_CAP_ATTR_MAX_FRAME_RETRIES, - - NL802154_CAP_ATTR_LBT, - - /* keep last */ - __NL802154_CAP_ATTR_AFTER_LAST, - NL802154_CAP_ATTR_MAX = __NL802154_CAP_ATTR_AFTER_LAST - 1 -}; - -/** - * enum nl802154_cca_modes - cca modes - * - * @__NL802154_CCA_INVALID: cca mode number 0 is reserved - * @NL802154_CCA_ENERGY: Energy above threshold - * @NL802154_CCA_CARRIER: Carrier sense only - * @NL802154_CCA_ENERGY_CARRIER: Carrier sense with energy above threshold - * @NL802154_CCA_ALOHA: CCA shall always report an idle medium - * @NL802154_CCA_UWB_SHR: UWB preamble sense based on the SHR of a frame - * @NL802154_CCA_UWB_MULTIPLEXED: UWB preamble sense based on the packet with - * the multiplexed preamble - * @__NL802154_CCA_ATTR_AFTER_LAST: Internal - * @NL802154_CCA_ATTR_MAX: Maximum CCA attribute number - */ -enum nl802154_cca_modes { - __NL802154_CCA_INVALID, - NL802154_CCA_ENERGY, - NL802154_CCA_CARRIER, - NL802154_CCA_ENERGY_CARRIER, - NL802154_CCA_ALOHA, - NL802154_CCA_UWB_SHR, - NL802154_CCA_UWB_MULTIPLEXED, - - /* keep last */ - __NL802154_CCA_ATTR_AFTER_LAST, - NL802154_CCA_ATTR_MAX = __NL802154_CCA_ATTR_AFTER_LAST - 1 -}; - -/** - * enum nl802154_cca_opts - additional options for cca modes - * - * @NL802154_CCA_OPT_ENERGY_CARRIER_OR: NL802154_CCA_ENERGY_CARRIER with OR - * @NL802154_CCA_OPT_ENERGY_CARRIER_AND: NL802154_CCA_ENERGY_CARRIER with AND - */ -enum nl802154_cca_opts { - NL802154_CCA_OPT_ENERGY_CARRIER_AND, - NL802154_CCA_OPT_ENERGY_CARRIER_OR, - - /* keep last */ - __NL802154_CCA_OPT_ATTR_AFTER_LAST, - NL802154_CCA_OPT_ATTR_MAX = __NL802154_CCA_OPT_ATTR_AFTER_LAST - 1 -}; - -/** - * enum nl802154_supported_bool_states - bool states for bool capability entry - * - * @NL802154_SUPPORTED_BOOL_FALSE: indicates to set false - * @NL802154_SUPPORTED_BOOL_TRUE: indicates to set true - * @__NL802154_SUPPORTED_BOOL_INVALD: reserved - * @NL802154_SUPPORTED_BOOL_BOTH: indicates to set true and false - * @__NL802154_SUPPORTED_BOOL_AFTER_LAST: Internal - * @NL802154_SUPPORTED_BOOL_MAX: highest value for bool states - */ -enum nl802154_supported_bool_states { - NL802154_SUPPORTED_BOOL_FALSE, - NL802154_SUPPORTED_BOOL_TRUE, - /* to handle them in a mask */ - __NL802154_SUPPORTED_BOOL_INVALD, - NL802154_SUPPORTED_BOOL_BOTH, - - /* keep last */ - __NL802154_SUPPORTED_BOOL_AFTER_LAST, - NL802154_SUPPORTED_BOOL_MAX = __NL802154_SUPPORTED_BOOL_AFTER_LAST - 1 -}; - -#ifdef CONFIG_IEEE802154_NL802154_EXPERIMENTAL - -enum nl802154_dev_addr_modes { - NL802154_DEV_ADDR_NONE, - __NL802154_DEV_ADDR_INVALID, - NL802154_DEV_ADDR_SHORT, - NL802154_DEV_ADDR_EXTENDED, - - /* keep last */ - __NL802154_DEV_ADDR_AFTER_LAST, - NL802154_DEV_ADDR_MAX = __NL802154_DEV_ADDR_AFTER_LAST - 1 -}; - -enum nl802154_dev_addr_attrs { - NL802154_DEV_ADDR_ATTR_UNSPEC, - - NL802154_DEV_ADDR_ATTR_PAN_ID, - NL802154_DEV_ADDR_ATTR_MODE, - NL802154_DEV_ADDR_ATTR_SHORT, - NL802154_DEV_ADDR_ATTR_EXTENDED, - NL802154_DEV_ADDR_ATTR_PAD, - - /* keep last */ - __NL802154_DEV_ADDR_ATTR_AFTER_LAST, - NL802154_DEV_ADDR_ATTR_MAX = __NL802154_DEV_ADDR_ATTR_AFTER_LAST - 1 -}; - -enum nl802154_key_id_modes { - NL802154_KEY_ID_MODE_IMPLICIT, - NL802154_KEY_ID_MODE_INDEX, - NL802154_KEY_ID_MODE_INDEX_SHORT, - NL802154_KEY_ID_MODE_INDEX_EXTENDED, - - /* keep last */ - __NL802154_KEY_ID_MODE_AFTER_LAST, - NL802154_KEY_ID_MODE_MAX = __NL802154_KEY_ID_MODE_AFTER_LAST - 1 -}; - -enum nl802154_key_id_attrs { - NL802154_KEY_ID_ATTR_UNSPEC, - - NL802154_KEY_ID_ATTR_MODE, - NL802154_KEY_ID_ATTR_INDEX, - NL802154_KEY_ID_ATTR_IMPLICIT, - NL802154_KEY_ID_ATTR_SOURCE_SHORT, - NL802154_KEY_ID_ATTR_SOURCE_EXTENDED, - NL802154_KEY_ID_ATTR_PAD, - - /* keep last */ - __NL802154_KEY_ID_ATTR_AFTER_LAST, - NL802154_KEY_ID_ATTR_MAX = __NL802154_KEY_ID_ATTR_AFTER_LAST - 1 -}; - -enum nl802154_seclevels { - NL802154_SECLEVEL_NONE, - NL802154_SECLEVEL_MIC32, - NL802154_SECLEVEL_MIC64, - NL802154_SECLEVEL_MIC128, - NL802154_SECLEVEL_ENC, - NL802154_SECLEVEL_ENC_MIC32, - NL802154_SECLEVEL_ENC_MIC64, - NL802154_SECLEVEL_ENC_MIC128, - - /* keep last */ - __NL802154_SECLEVEL_AFTER_LAST, - NL802154_SECLEVEL_MAX = __NL802154_SECLEVEL_AFTER_LAST - 1 -}; - -enum nl802154_frames { - NL802154_FRAME_BEACON, - NL802154_FRAME_DATA, - NL802154_FRAME_ACK, - NL802154_FRAME_CMD, - - /* keep last */ - __NL802154_FRAME_AFTER_LAST, - NL802154_FRAME_MAX = __NL802154_FRAME_AFTER_LAST - 1 -}; - -enum nl802154_cmd_frames { - __NL802154_CMD_FRAME_INVALID, - NL802154_CMD_FRAME_ASSOC_REQUEST, - NL802154_CMD_FRAME_ASSOC_RESPONSE, - NL802154_CMD_FRAME_DISASSOC_NOTIFY, - NL802154_CMD_FRAME_DATA_REQUEST, - NL802154_CMD_FRAME_PAN_ID_CONFLICT_NOTIFY, - NL802154_CMD_FRAME_ORPHAN_NOTIFY, - NL802154_CMD_FRAME_BEACON_REQUEST, - NL802154_CMD_FRAME_COORD_REALIGNMENT, - NL802154_CMD_FRAME_GTS_REQUEST, - - /* keep last */ - __NL802154_CMD_FRAME_AFTER_LAST, - NL802154_CMD_FRAME_MAX = __NL802154_CMD_FRAME_AFTER_LAST - 1 -}; - -enum nl802154_seclevel_attrs { - NL802154_SECLEVEL_ATTR_UNSPEC, - - NL802154_SECLEVEL_ATTR_LEVELS, - NL802154_SECLEVEL_ATTR_FRAME, - NL802154_SECLEVEL_ATTR_CMD_FRAME, - NL802154_SECLEVEL_ATTR_DEV_OVERRIDE, - - /* keep last */ - __NL802154_SECLEVEL_ATTR_AFTER_LAST, - NL802154_SECLEVEL_ATTR_MAX = __NL802154_SECLEVEL_ATTR_AFTER_LAST - 1 -}; - -/* TODO what is this? couldn't find in mib */ -enum { - NL802154_DEVKEY_IGNORE, - NL802154_DEVKEY_RESTRICT, - NL802154_DEVKEY_RECORD, - - /* keep last */ - __NL802154_DEVKEY_AFTER_LAST, - NL802154_DEVKEY_MAX = __NL802154_DEVKEY_AFTER_LAST - 1 -}; - -enum nl802154_dev { - NL802154_DEV_ATTR_UNSPEC, - - NL802154_DEV_ATTR_FRAME_COUNTER, - NL802154_DEV_ATTR_PAN_ID, - NL802154_DEV_ATTR_SHORT_ADDR, - NL802154_DEV_ATTR_EXTENDED_ADDR, - NL802154_DEV_ATTR_SECLEVEL_EXEMPT, - NL802154_DEV_ATTR_KEY_MODE, - NL802154_DEV_ATTR_PAD, - - /* keep last */ - __NL802154_DEV_ATTR_AFTER_LAST, - NL802154_DEV_ATTR_MAX = __NL802154_DEV_ATTR_AFTER_LAST - 1 -}; - -enum nl802154_devkey { - NL802154_DEVKEY_ATTR_UNSPEC, - - NL802154_DEVKEY_ATTR_FRAME_COUNTER, - NL802154_DEVKEY_ATTR_EXTENDED_ADDR, - NL802154_DEVKEY_ATTR_ID, - NL802154_DEVKEY_ATTR_PAD, - - /* keep last */ - __NL802154_DEVKEY_ATTR_AFTER_LAST, - NL802154_DEVKEY_ATTR_MAX = __NL802154_DEVKEY_ATTR_AFTER_LAST - 1 -}; - -enum nl802154_key { - NL802154_KEY_ATTR_UNSPEC, - - NL802154_KEY_ATTR_ID, - NL802154_KEY_ATTR_USAGE_FRAMES, - NL802154_KEY_ATTR_USAGE_CMDS, - NL802154_KEY_ATTR_BYTES, - - /* keep last */ - __NL802154_KEY_ATTR_AFTER_LAST, - NL802154_KEY_ATTR_MAX = __NL802154_KEY_ATTR_AFTER_LAST - 1 -}; - -#define NL802154_KEY_SIZE 16 -#define NL802154_CMD_FRAME_NR_IDS 256 - -#endif /* CONFIG_IEEE802154_NL802154_EXPERIMENTAL */ - -#endif /* __NL802154_H */ diff --git a/src/linux/include/net/ping.h b/src/linux/include/net/ping.h deleted file mode 100644 index 4cd90d6..0000000 --- a/src/linux/include/net/ping.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the "ping" module. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _PING_H -#define _PING_H - -#include -#include - -/* PING_HTABLE_SIZE must be power of 2 */ -#define PING_HTABLE_SIZE 64 -#define PING_HTABLE_MASK (PING_HTABLE_SIZE-1) - -#define ping_portaddr_for_each_entry(__sk, node, list) \ - hlist_nulls_for_each_entry(__sk, node, list, sk_nulls_node) - -/* - * gid_t is either uint or ushort. We want to pass it to - * proc_dointvec_minmax(), so it must not be larger than MAX_INT - */ -#define GID_T_MAX (((gid_t)~0U) >> 1) - -/* Compatibility glue so we can support IPv6 when it's compiled as a module */ -struct pingv6_ops { - int (*ipv6_recv_error)(struct sock *sk, struct msghdr *msg, int len, - int *addr_len); - void (*ip6_datagram_recv_common_ctl)(struct sock *sk, - struct msghdr *msg, - struct sk_buff *skb); - void (*ip6_datagram_recv_specific_ctl)(struct sock *sk, - struct msghdr *msg, - struct sk_buff *skb); - int (*icmpv6_err_convert)(u8 type, u8 code, int *err); - void (*ipv6_icmp_error)(struct sock *sk, struct sk_buff *skb, int err, - __be16 port, u32 info, u8 *payload); - int (*ipv6_chk_addr)(struct net *net, const struct in6_addr *addr, - const struct net_device *dev, int strict); -}; - -struct ping_iter_state { - struct seq_net_private p; - int bucket; - sa_family_t family; -}; - -extern struct proto ping_prot; -#if IS_ENABLED(CONFIG_IPV6) -extern struct pingv6_ops pingv6_ops; -#endif - -struct pingfakehdr { - struct icmphdr icmph; - struct msghdr *msg; - sa_family_t family; - __wsum wcheck; -}; - -int ping_get_port(struct sock *sk, unsigned short ident); -int ping_hash(struct sock *sk); -void ping_unhash(struct sock *sk); - -int ping_init_sock(struct sock *sk); -void ping_close(struct sock *sk, long timeout); -int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len); -void ping_err(struct sk_buff *skb, int offset, u32 info); -int ping_getfrag(void *from, char *to, int offset, int fraglen, int odd, - struct sk_buff *); - -int ping_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock, - int flags, int *addr_len); -int ping_common_sendmsg(int family, struct msghdr *msg, size_t len, - void *user_icmph, size_t icmph_len); -int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); -bool ping_rcv(struct sk_buff *skb); - -#ifdef CONFIG_PROC_FS -struct ping_seq_afinfo { - char *name; - sa_family_t family; - const struct file_operations *seq_fops; - const struct seq_operations seq_ops; -}; - -extern const struct file_operations ping_seq_fops; - -void *ping_seq_start(struct seq_file *seq, loff_t *pos, sa_family_t family); -void *ping_seq_next(struct seq_file *seq, void *v, loff_t *pos); -void ping_seq_stop(struct seq_file *seq, void *v); -int ping_proc_register(struct net *net, struct ping_seq_afinfo *afinfo); -void ping_proc_unregister(struct net *net, struct ping_seq_afinfo *afinfo); - -int __init ping_proc_init(void); -void ping_proc_exit(void); -#endif - -void __init ping_init(void); -int __init pingv6_init(void); -void pingv6_exit(void); - -#endif /* _PING_H */ diff --git a/src/linux/include/net/pkt_sched.h b/src/linux/include/net/pkt_sched.h deleted file mode 100644 index cd334c9..0000000 --- a/src/linux/include/net/pkt_sched.h +++ /dev/null @@ -1,136 +0,0 @@ -#ifndef __NET_PKT_SCHED_H -#define __NET_PKT_SCHED_H - -#include -#include -#include -#include - -struct qdisc_walker { - int stop; - int skip; - int count; - int (*fn)(struct Qdisc *, unsigned long cl, struct qdisc_walker *); -}; - -#define QDISC_ALIGNTO 64 -#define QDISC_ALIGN(len) (((len) + QDISC_ALIGNTO-1) & ~(QDISC_ALIGNTO-1)) - -static inline void *qdisc_priv(struct Qdisc *q) -{ - return (char *) q + QDISC_ALIGN(sizeof(struct Qdisc)); -} - -/* - Timer resolution MUST BE < 10% of min_schedulable_packet_size/bandwidth - - Normal IP packet size ~ 512byte, hence: - - 0.5Kbyte/1Mbyte/sec = 0.5msec, so that we need 50usec timer for - 10Mbit ethernet. - - 10msec resolution -> <50Kbit/sec. - - The result: [34]86 is not good choice for QoS router :-( - - The things are not so bad, because we may use artificial - clock evaluated by integration of network data flow - in the most critical places. - */ - -typedef u64 psched_time_t; -typedef long psched_tdiff_t; - -/* Avoid doing 64 bit divide */ -#define PSCHED_SHIFT 6 -#define PSCHED_TICKS2NS(x) ((s64)(x) << PSCHED_SHIFT) -#define PSCHED_NS2TICKS(x) ((x) >> PSCHED_SHIFT) - -#define PSCHED_TICKS_PER_SEC PSCHED_NS2TICKS(NSEC_PER_SEC) -#define PSCHED_PASTPERFECT 0 - -static inline psched_time_t psched_get_time(void) -{ - return PSCHED_NS2TICKS(ktime_get_ns()); -} - -static inline psched_tdiff_t -psched_tdiff_bounded(psched_time_t tv1, psched_time_t tv2, psched_time_t bound) -{ - return min(tv1 - tv2, bound); -} - -struct qdisc_watchdog { - u64 last_expires; - struct hrtimer timer; - struct Qdisc *qdisc; -}; - -void qdisc_watchdog_init(struct qdisc_watchdog *wd, struct Qdisc *qdisc); -void qdisc_watchdog_schedule_ns(struct qdisc_watchdog *wd, u64 expires); - -static inline void qdisc_watchdog_schedule(struct qdisc_watchdog *wd, - psched_time_t expires) -{ - qdisc_watchdog_schedule_ns(wd, PSCHED_TICKS2NS(expires)); -} - -void qdisc_watchdog_cancel(struct qdisc_watchdog *wd); - -extern struct Qdisc_ops pfifo_qdisc_ops; -extern struct Qdisc_ops bfifo_qdisc_ops; -extern struct Qdisc_ops pfifo_head_drop_qdisc_ops; - -int fifo_set_limit(struct Qdisc *q, unsigned int limit); -struct Qdisc *fifo_create_dflt(struct Qdisc *sch, struct Qdisc_ops *ops, - unsigned int limit); - -int register_qdisc(struct Qdisc_ops *qops); -int unregister_qdisc(struct Qdisc_ops *qops); -void qdisc_get_default(char *id, size_t len); -int qdisc_set_default(const char *id); - -void qdisc_hash_add(struct Qdisc *q); -void qdisc_hash_del(struct Qdisc *q); -struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle); -struct Qdisc *qdisc_lookup_class(struct net_device *dev, u32 handle); -struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r, - struct nlattr *tab); -void qdisc_put_rtab(struct qdisc_rate_table *tab); -void qdisc_put_stab(struct qdisc_size_table *tab); -void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc); -int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, - struct net_device *dev, struct netdev_queue *txq, - spinlock_t *root_lock, bool validate); - -void __qdisc_run(struct Qdisc *q); - -static inline void qdisc_run(struct Qdisc *q) -{ - if (qdisc_run_begin(q)) - __qdisc_run(q); -} - -int tc_classify(struct sk_buff *skb, const struct tcf_proto *tp, - struct tcf_result *res, bool compat_mode); - -static inline __be16 tc_skb_protocol(const struct sk_buff *skb) -{ - /* We need to take extra care in case the skb came via - * vlan accelerated path. In that case, use skb->vlan_proto - * as the original vlan header was already stripped. - */ - if (skb_vlan_tag_present(skb)) - return skb->vlan_proto; - return skb->protocol; -} - -/* Calculate maximal size of packet seen by hard_start_xmit - routine of this device. - */ -static inline unsigned int psched_mtu(const struct net_device *dev) -{ - return dev->mtu + dev->hard_header_len; -} - -#endif diff --git a/src/linux/include/net/pptp.h b/src/linux/include/net/pptp.h deleted file mode 100644 index 92e9f1f..0000000 --- a/src/linux/include/net/pptp.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef _NET_PPTP_H -#define _NET_PPTP_H - -#define PPP_LCP_ECHOREQ 0x09 -#define PPP_LCP_ECHOREP 0x0A -#define SC_RCV_BITS (SC_RCV_B7_1|SC_RCV_B7_0|SC_RCV_ODDP|SC_RCV_EVNP) - -#define MISSING_WINDOW 20 -#define WRAPPED(curseq, lastseq)\ - ((((curseq) & 0xffffff00) == 0) &&\ - (((lastseq) & 0xffffff00) == 0xffffff00)) - -#define PPTP_HEADER_OVERHEAD (2+sizeof(struct pptp_gre_header)) -struct pptp_gre_header { - struct gre_base_hdr gre_hd; - __be16 payload_len; - __be16 call_id; - __be32 seq; - __be32 ack; -} __packed; - - -#endif diff --git a/src/linux/include/net/protocol.h b/src/linux/include/net/protocol.h deleted file mode 100644 index bf36ca3..0000000 --- a/src/linux/include/net/protocol.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the protocol dispatcher. - * - * Version: @(#)protocol.h 1.0.2 05/07/93 - * - * Author: Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Changes: - * Alan Cox : Added a name field and a frag handler - * field for later. - * Alan Cox : Cleaned up, and sorted types. - * Pedro Roque : inet6 protocols - */ - -#ifndef _PROTOCOL_H -#define _PROTOCOL_H - -#include -#include -#if IS_ENABLED(CONFIG_IPV6) -#include -#endif -#include - -/* This is one larger than the largest protocol value that can be - * found in an ipv4 or ipv6 header. Since in both cases the protocol - * value is presented in a __u8, this is defined to be 256. - */ -#define MAX_INET_PROTOS 256 - -/* This is used to register protocols. */ -struct net_protocol { - void (*early_demux)(struct sk_buff *skb); - int (*handler)(struct sk_buff *skb); - void (*err_handler)(struct sk_buff *skb, u32 info); - unsigned int no_policy:1, - netns_ok:1, - /* does the protocol do more stringent - * icmp tag validation than simple - * socket lookup? - */ - icmp_strict_tag_validation:1; -}; - -#if IS_ENABLED(CONFIG_IPV6) -struct inet6_protocol { - void (*early_demux)(struct sk_buff *skb); - - int (*handler)(struct sk_buff *skb); - - void (*err_handler)(struct sk_buff *skb, - struct inet6_skb_parm *opt, - u8 type, u8 code, int offset, - __be32 info); - unsigned int flags; /* INET6_PROTO_xxx */ -}; - -#define INET6_PROTO_NOPOLICY 0x1 -#define INET6_PROTO_FINAL 0x2 -#endif - -struct net_offload { - struct offload_callbacks callbacks; - unsigned int flags; /* Flags used by IPv6 for now */ -}; -/* This should be set for any extension header which is compatible with GSO. */ -#define INET6_PROTO_GSO_EXTHDR 0x1 - -/* This is used to register socket interfaces for IP protocols. */ -struct inet_protosw { - struct list_head list; - - /* These two fields form the lookup key. */ - unsigned short type; /* This is the 2nd argument to socket(2). */ - unsigned short protocol; /* This is the L4 protocol number. */ - - struct proto *prot; - const struct proto_ops *ops; - - unsigned char flags; /* See INET_PROTOSW_* below. */ -}; -#define INET_PROTOSW_REUSE 0x01 /* Are ports automatically reusable? */ -#define INET_PROTOSW_PERMANENT 0x02 /* Permanent protocols are unremovable. */ -#define INET_PROTOSW_ICSK 0x04 /* Is this an inet_connection_sock? */ - -extern const struct net_protocol __rcu *inet_protos[MAX_INET_PROTOS]; -extern const struct net_offload __rcu *inet_offloads[MAX_INET_PROTOS]; -extern const struct net_offload __rcu *inet6_offloads[MAX_INET_PROTOS]; - -#if IS_ENABLED(CONFIG_IPV6) -extern const struct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS]; -#endif - -int inet_add_protocol(const struct net_protocol *prot, unsigned char num); -int inet_del_protocol(const struct net_protocol *prot, unsigned char num); -int inet_add_offload(const struct net_offload *prot, unsigned char num); -int inet_del_offload(const struct net_offload *prot, unsigned char num); -void inet_register_protosw(struct inet_protosw *p); -void inet_unregister_protosw(struct inet_protosw *p); - -#if IS_ENABLED(CONFIG_IPV6) -int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char num); -int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char num); -int inet6_register_protosw(struct inet_protosw *p); -void inet6_unregister_protosw(struct inet_protosw *p); -#endif -int inet6_add_offload(const struct net_offload *prot, unsigned char num); -int inet6_del_offload(const struct net_offload *prot, unsigned char num); - -#endif /* _PROTOCOL_H */ diff --git a/src/linux/include/net/raw.h b/src/linux/include/net/raw.h deleted file mode 100644 index 3e78900..0000000 --- a/src/linux/include/net/raw.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the RAW-IP module. - * - * Version: @(#)raw.h 1.0.2 05/07/93 - * - * Author: Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _RAW_H -#define _RAW_H - - -#include -#include - -extern struct proto raw_prot; - -void raw_icmp_error(struct sk_buff *, int, u32); -int raw_local_deliver(struct sk_buff *, int); - -int raw_rcv(struct sock *, struct sk_buff *); - -#define RAW_HTABLE_SIZE MAX_INET_PROTOS - -struct raw_hashinfo { - rwlock_t lock; - struct hlist_head ht[RAW_HTABLE_SIZE]; -}; - -#ifdef CONFIG_PROC_FS -int raw_proc_init(void); -void raw_proc_exit(void); - -struct raw_iter_state { - struct seq_net_private p; - int bucket; - struct raw_hashinfo *h; -}; - -static inline struct raw_iter_state *raw_seq_private(struct seq_file *seq) -{ - return seq->private; -} -void *raw_seq_start(struct seq_file *seq, loff_t *pos); -void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos); -void raw_seq_stop(struct seq_file *seq, void *v); -int raw_seq_open(struct inode *ino, struct file *file, - struct raw_hashinfo *h, const struct seq_operations *ops); - -#endif - -int raw_hash_sk(struct sock *sk); -void raw_unhash_sk(struct sock *sk); - -struct raw_sock { - /* inet_sock has to be the first member */ - struct inet_sock inet; - struct icmp_filter filter; - u32 ipmr_table; -}; - -static inline struct raw_sock *raw_sk(const struct sock *sk) -{ - return (struct raw_sock *)sk; -} - -#endif /* _RAW_H */ diff --git a/src/linux/include/net/rawv6.h b/src/linux/include/net/rawv6.h deleted file mode 100644 index 87783de..0000000 --- a/src/linux/include/net/rawv6.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _NET_RAWV6_H -#define _NET_RAWV6_H - -#include - -void raw6_icmp_error(struct sk_buff *, int nexthdr, - u8 type, u8 code, int inner_offset, __be32); -bool raw6_local_deliver(struct sk_buff *, int); - -int rawv6_rcv(struct sock *sk, struct sk_buff *skb); - -#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) -int rawv6_mh_filter_register(int (*filter)(struct sock *sock, - struct sk_buff *skb)); -int rawv6_mh_filter_unregister(int (*filter)(struct sock *sock, - struct sk_buff *skb)); -#endif - -#endif diff --git a/src/linux/include/net/request_sock.h b/src/linux/include/net/request_sock.h deleted file mode 100644 index 6ebe13e..0000000 --- a/src/linux/include/net/request_sock.h +++ /dev/null @@ -1,229 +0,0 @@ -/* - * NET Generic infrastructure for Network protocols. - * - * Definitions for request_sock - * - * Authors: Arnaldo Carvalho de Melo - * - * From code originally in include/net/tcp.h - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _REQUEST_SOCK_H -#define _REQUEST_SOCK_H - -#include -#include -#include -#include - -#include - -struct request_sock; -struct sk_buff; -struct dst_entry; -struct proto; - -struct request_sock_ops { - int family; - int obj_size; - struct kmem_cache *slab; - char *slab_name; - int (*rtx_syn_ack)(const struct sock *sk, - struct request_sock *req); - void (*send_ack)(const struct sock *sk, struct sk_buff *skb, - struct request_sock *req); - void (*send_reset)(const struct sock *sk, - struct sk_buff *skb); - void (*destructor)(struct request_sock *req); - void (*syn_ack_timeout)(const struct request_sock *req); -}; - -int inet_rtx_syn_ack(const struct sock *parent, struct request_sock *req); - -/* struct request_sock - mini sock to represent a connection request - */ -struct request_sock { - struct sock_common __req_common; -#define rsk_refcnt __req_common.skc_refcnt -#define rsk_hash __req_common.skc_hash -#define rsk_listener __req_common.skc_listener -#define rsk_window_clamp __req_common.skc_window_clamp -#define rsk_rcv_wnd __req_common.skc_rcv_wnd - - struct request_sock *dl_next; - u16 mss; - u8 num_retrans; /* number of retransmits */ - u8 cookie_ts:1; /* syncookie: encode tcpopts in timestamp */ - u8 num_timeout:7; /* number of timeouts */ - u32 ts_recent; - struct timer_list rsk_timer; - const struct request_sock_ops *rsk_ops; - struct sock *sk; - u32 *saved_syn; - u32 secid; - u32 peer_secid; -}; - -static inline struct request_sock *inet_reqsk(const struct sock *sk) -{ - return (struct request_sock *)sk; -} - -static inline struct sock *req_to_sk(struct request_sock *req) -{ - return (struct sock *)req; -} - -static inline struct request_sock * -reqsk_alloc(const struct request_sock_ops *ops, struct sock *sk_listener, - bool attach_listener) -{ - struct request_sock *req; - - req = kmem_cache_alloc(ops->slab, GFP_ATOMIC | __GFP_NOWARN); - if (!req) - return NULL; - req->rsk_listener = NULL; - if (attach_listener) { - if (unlikely(!atomic_inc_not_zero(&sk_listener->sk_refcnt))) { - kmem_cache_free(ops->slab, req); - return NULL; - } - req->rsk_listener = sk_listener; - } - req->rsk_ops = ops; - req_to_sk(req)->sk_prot = sk_listener->sk_prot; - sk_node_init(&req_to_sk(req)->sk_node); - sk_tx_queue_clear(req_to_sk(req)); - req->saved_syn = NULL; - atomic_set(&req->rsk_refcnt, 0); - - return req; -} - -static inline void reqsk_free(struct request_sock *req) -{ - /* temporary debugging */ - WARN_ON_ONCE(atomic_read(&req->rsk_refcnt) != 0); - - req->rsk_ops->destructor(req); - if (req->rsk_listener) - sock_put(req->rsk_listener); - kfree(req->saved_syn); - kmem_cache_free(req->rsk_ops->slab, req); -} - -static inline void reqsk_put(struct request_sock *req) -{ - if (atomic_dec_and_test(&req->rsk_refcnt)) - reqsk_free(req); -} - -extern int sysctl_max_syn_backlog; - -/* - * For a TCP Fast Open listener - - * lock - protects the access to all the reqsk, which is co-owned by - * the listener and the child socket. - * qlen - pending TFO requests (still in TCP_SYN_RECV). - * max_qlen - max TFO reqs allowed before TFO is disabled. - * - * XXX (TFO) - ideally these fields can be made as part of "listen_sock" - * structure above. But there is some implementation difficulty due to - * listen_sock being part of request_sock_queue hence will be freed when - * a listener is stopped. But TFO related fields may continue to be - * accessed even after a listener is closed, until its sk_refcnt drops - * to 0 implying no more outstanding TFO reqs. One solution is to keep - * listen_opt around until sk_refcnt drops to 0. But there is some other - * complexity that needs to be resolved. E.g., a listener can be disabled - * temporarily through shutdown()->tcp_disconnect(), and re-enabled later. - */ -struct fastopen_queue { - struct request_sock *rskq_rst_head; /* Keep track of past TFO */ - struct request_sock *rskq_rst_tail; /* requests that caused RST. - * This is part of the defense - * against spoofing attack. - */ - spinlock_t lock; - int qlen; /* # of pending (TCP_SYN_RECV) reqs */ - int max_qlen; /* != 0 iff TFO is currently enabled */ -}; - -/** struct request_sock_queue - queue of request_socks - * - * @rskq_accept_head - FIFO head of established children - * @rskq_accept_tail - FIFO tail of established children - * @rskq_defer_accept - User waits for some data after accept() - * - */ -struct request_sock_queue { - spinlock_t rskq_lock; - u8 rskq_defer_accept; - - u32 synflood_warned; - atomic_t qlen; - atomic_t young; - - struct request_sock *rskq_accept_head; - struct request_sock *rskq_accept_tail; - struct fastopen_queue fastopenq; /* Check max_qlen != 0 to determine - * if TFO is enabled. - */ -}; - -void reqsk_queue_alloc(struct request_sock_queue *queue); - -void reqsk_fastopen_remove(struct sock *sk, struct request_sock *req, - bool reset); - -static inline bool reqsk_queue_empty(const struct request_sock_queue *queue) -{ - return queue->rskq_accept_head == NULL; -} - -static inline struct request_sock *reqsk_queue_remove(struct request_sock_queue *queue, - struct sock *parent) -{ - struct request_sock *req; - - spin_lock_bh(&queue->rskq_lock); - req = queue->rskq_accept_head; - if (req) { - sk_acceptq_removed(parent); - queue->rskq_accept_head = req->dl_next; - if (queue->rskq_accept_head == NULL) - queue->rskq_accept_tail = NULL; - } - spin_unlock_bh(&queue->rskq_lock); - return req; -} - -static inline void reqsk_queue_removed(struct request_sock_queue *queue, - const struct request_sock *req) -{ - if (req->num_timeout == 0) - atomic_dec(&queue->young); - atomic_dec(&queue->qlen); -} - -static inline void reqsk_queue_added(struct request_sock_queue *queue) -{ - atomic_inc(&queue->young); - atomic_inc(&queue->qlen); -} - -static inline int reqsk_queue_len(const struct request_sock_queue *queue) -{ - return atomic_read(&queue->qlen); -} - -static inline int reqsk_queue_len_young(const struct request_sock_queue *queue) -{ - return atomic_read(&queue->young); -} - -#endif /* _REQUEST_SOCK_H */ diff --git a/src/linux/include/net/route.h b/src/linux/include/net/route.h deleted file mode 100644 index 0429d47..0000000 --- a/src/linux/include/net/route.h +++ /dev/null @@ -1,336 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the IP router. - * - * Version: @(#)route.h 1.0.4 05/27/93 - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Fixes: - * Alan Cox : Reformatted. Added ip_rt_local() - * Alan Cox : Support for TCP parameters. - * Alexey Kuznetsov: Major changes for new routing code. - * Mike McLagan : Routing by source - * Robert Olsson : Added rt_cache statistics - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _ROUTE_H -#define _ROUTE_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* IPv4 datagram length is stored into 16bit field (tot_len) */ -#define IP_MAX_MTU 0xFFFFU - -#define RTO_ONLINK 0x01 - -#define RT_CONN_FLAGS(sk) (RT_TOS(inet_sk(sk)->tos) | sock_flag(sk, SOCK_LOCALROUTE)) -#define RT_CONN_FLAGS_TOS(sk,tos) (RT_TOS(tos) | sock_flag(sk, SOCK_LOCALROUTE)) - -struct fib_nh; -struct fib_info; -struct uncached_list; -struct rtable { - struct dst_entry dst; - - int rt_genid; - unsigned int rt_flags; - __u16 rt_type; - __u8 rt_is_input; - __u8 rt_uses_gateway; - - int rt_iif; - - /* Info on neighbour */ - __be32 rt_gateway; - - /* Miscellaneous cached information */ - u32 rt_pmtu; - - u32 rt_table_id; - - struct list_head rt_uncached; - struct uncached_list *rt_uncached_list; -}; - -static inline bool rt_is_input_route(const struct rtable *rt) -{ - return rt->rt_is_input != 0; -} - -static inline bool rt_is_output_route(const struct rtable *rt) -{ - return rt->rt_is_input == 0; -} - -static inline __be32 rt_nexthop(const struct rtable *rt, __be32 daddr) -{ - if (rt->rt_gateway) - return rt->rt_gateway; - return daddr; -} - -struct ip_rt_acct { - __u32 o_bytes; - __u32 o_packets; - __u32 i_bytes; - __u32 i_packets; -}; - -struct rt_cache_stat { - unsigned int in_slow_tot; - unsigned int in_slow_mc; - unsigned int in_no_route; - unsigned int in_brd; - unsigned int in_martian_dst; - unsigned int in_martian_src; - unsigned int out_slow_tot; - unsigned int out_slow_mc; -}; - -extern struct ip_rt_acct __percpu *ip_rt_acct; - -struct in_device; - -int ip_rt_init(void); -void rt_cache_flush(struct net *net); -void rt_flush_dev(struct net_device *dev); -struct rtable *__ip_route_output_key_hash(struct net *, struct flowi4 *flp, - int mp_hash); - -static inline struct rtable *__ip_route_output_key(struct net *net, - struct flowi4 *flp) -{ - return __ip_route_output_key_hash(net, flp, -1); -} - -struct rtable *ip_route_output_flow(struct net *, struct flowi4 *flp, - const struct sock *sk); -struct dst_entry *ipv4_blackhole_route(struct net *net, - struct dst_entry *dst_orig); - -static inline struct rtable *ip_route_output_key(struct net *net, struct flowi4 *flp) -{ - return ip_route_output_flow(net, flp, NULL); -} - -static inline struct rtable *ip_route_output(struct net *net, __be32 daddr, - __be32 saddr, u8 tos, int oif) -{ - struct flowi4 fl4 = { - .flowi4_oif = oif, - .flowi4_tos = tos, - .daddr = daddr, - .saddr = saddr, - }; - return ip_route_output_key(net, &fl4); -} - -static inline struct rtable *ip_route_output_ports(struct net *net, struct flowi4 *fl4, - struct sock *sk, - __be32 daddr, __be32 saddr, - __be16 dport, __be16 sport, - __u8 proto, __u8 tos, int oif) -{ - flowi4_init_output(fl4, oif, sk ? sk->sk_mark : 0, tos, - RT_SCOPE_UNIVERSE, proto, - sk ? inet_sk_flowi_flags(sk) : 0, - daddr, saddr, dport, sport); - if (sk) - security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); - return ip_route_output_flow(net, fl4, sk); -} - -static inline struct rtable *ip_route_output_gre(struct net *net, struct flowi4 *fl4, - __be32 daddr, __be32 saddr, - __be32 gre_key, __u8 tos, int oif) -{ - memset(fl4, 0, sizeof(*fl4)); - fl4->flowi4_oif = oif; - fl4->daddr = daddr; - fl4->saddr = saddr; - fl4->flowi4_tos = tos; - fl4->flowi4_proto = IPPROTO_GRE; - fl4->fl4_gre_key = gre_key; - return ip_route_output_key(net, fl4); -} - -int ip_route_input_noref(struct sk_buff *skb, __be32 dst, __be32 src, - u8 tos, struct net_device *devin); - -static inline int ip_route_input(struct sk_buff *skb, __be32 dst, __be32 src, - u8 tos, struct net_device *devin) -{ - int err; - - rcu_read_lock(); - err = ip_route_input_noref(skb, dst, src, tos, devin); - if (!err) - skb_dst_force(skb); - rcu_read_unlock(); - - return err; -} - -void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu, int oif, - u32 mark, u8 protocol, int flow_flags); -void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu); -void ipv4_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark, - u8 protocol, int flow_flags); -void ipv4_sk_redirect(struct sk_buff *skb, struct sock *sk); -void ip_rt_send_redirect(struct sk_buff *skb); - -unsigned int inet_addr_type(struct net *net, __be32 addr); -unsigned int inet_addr_type_table(struct net *net, __be32 addr, u32 tb_id); -unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev, - __be32 addr); -unsigned int inet_addr_type_dev_table(struct net *net, - const struct net_device *dev, - __be32 addr); -void ip_rt_multicast_event(struct in_device *); -int ip_rt_ioctl(struct net *, unsigned int cmd, void __user *arg); -void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt); -struct rtable *rt_dst_alloc(struct net_device *dev, - unsigned int flags, u16 type, - bool nopolicy, bool noxfrm, bool will_cache); - -struct in_ifaddr; -void fib_add_ifaddr(struct in_ifaddr *); -void fib_del_ifaddr(struct in_ifaddr *, struct in_ifaddr *); - -static inline void ip_rt_put(struct rtable *rt) -{ - /* dst_release() accepts a NULL parameter. - * We rely on dst being first structure in struct rtable - */ - BUILD_BUG_ON(offsetof(struct rtable, dst) != 0); - dst_release(&rt->dst); -} - -#define IPTOS_RT_MASK (IPTOS_TOS_MASK & ~3) - -extern const __u8 ip_tos2prio[16]; - -static inline char rt_tos2priority(u8 tos) -{ - return ip_tos2prio[IPTOS_TOS(tos)>>1]; -} - -/* ip_route_connect() and ip_route_newports() work in tandem whilst - * binding a socket for a new outgoing connection. - * - * In order to use IPSEC properly, we must, in the end, have a - * route that was looked up using all available keys including source - * and destination ports. - * - * However, if a source port needs to be allocated (the user specified - * a wildcard source port) we need to obtain addressing information - * in order to perform that allocation. - * - * So ip_route_connect() looks up a route using wildcarded source and - * destination ports in the key, simply so that we can get a pair of - * addresses to use for port allocation. - * - * Later, once the ports are allocated, ip_route_newports() will make - * another route lookup if needed to make sure we catch any IPSEC - * rules keyed on the port information. - * - * The callers allocate the flow key on their stack, and must pass in - * the same flowi4 object to both the ip_route_connect() and the - * ip_route_newports() calls. - */ - -static inline void ip_route_connect_init(struct flowi4 *fl4, __be32 dst, __be32 src, - u32 tos, int oif, u8 protocol, - __be16 sport, __be16 dport, - struct sock *sk) -{ - __u8 flow_flags = 0; - - if (inet_sk(sk)->transparent) - flow_flags |= FLOWI_FLAG_ANYSRC; - - flowi4_init_output(fl4, oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, - protocol, flow_flags, dst, src, dport, sport); -} - -static inline struct rtable *ip_route_connect(struct flowi4 *fl4, - __be32 dst, __be32 src, u32 tos, - int oif, u8 protocol, - __be16 sport, __be16 dport, - struct sock *sk) -{ - struct net *net = sock_net(sk); - struct rtable *rt; - - ip_route_connect_init(fl4, dst, src, tos, oif, protocol, - sport, dport, sk); - - if (!dst || !src) { - rt = __ip_route_output_key(net, fl4); - if (IS_ERR(rt)) - return rt; - ip_rt_put(rt); - flowi4_update_output(fl4, oif, tos, fl4->daddr, fl4->saddr); - } - security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); - return ip_route_output_flow(net, fl4, sk); -} - -static inline struct rtable *ip_route_newports(struct flowi4 *fl4, struct rtable *rt, - __be16 orig_sport, __be16 orig_dport, - __be16 sport, __be16 dport, - struct sock *sk) -{ - if (sport != orig_sport || dport != orig_dport) { - fl4->fl4_dport = dport; - fl4->fl4_sport = sport; - ip_rt_put(rt); - flowi4_update_output(fl4, sk->sk_bound_dev_if, - RT_CONN_FLAGS(sk), fl4->daddr, - fl4->saddr); - security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); - return ip_route_output_flow(sock_net(sk), fl4, sk); - } - return rt; -} - -static inline int inet_iif(const struct sk_buff *skb) -{ - struct rtable *rt = skb_rtable(skb); - - if (rt && rt->rt_iif) - return rt->rt_iif; - - return skb->skb_iif; -} - -static inline int ip4_dst_hoplimit(const struct dst_entry *dst) -{ - int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT); - struct net *net = dev_net(dst->dev); - - if (hoplimit == 0) - hoplimit = net->ipv4.sysctl_ip_default_ttl; - return hoplimit; -} - -#endif /* _ROUTE_H */ diff --git a/src/linux/include/net/rtnetlink.h b/src/linux/include/net/rtnetlink.h deleted file mode 100644 index 4113916..0000000 --- a/src/linux/include/net/rtnetlink.h +++ /dev/null @@ -1,161 +0,0 @@ -#ifndef __NET_RTNETLINK_H -#define __NET_RTNETLINK_H - -#include -#include - -typedef int (*rtnl_doit_func)(struct sk_buff *, struct nlmsghdr *); -typedef int (*rtnl_dumpit_func)(struct sk_buff *, struct netlink_callback *); -typedef u16 (*rtnl_calcit_func)(struct sk_buff *, struct nlmsghdr *); - -int __rtnl_register(int protocol, int msgtype, - rtnl_doit_func, rtnl_dumpit_func, rtnl_calcit_func); -void rtnl_register(int protocol, int msgtype, - rtnl_doit_func, rtnl_dumpit_func, rtnl_calcit_func); -int rtnl_unregister(int protocol, int msgtype); -void rtnl_unregister_all(int protocol); - -static inline int rtnl_msg_family(const struct nlmsghdr *nlh) -{ - if (nlmsg_len(nlh) >= sizeof(struct rtgenmsg)) - return ((struct rtgenmsg *) nlmsg_data(nlh))->rtgen_family; - else - return AF_UNSPEC; -} - -/** - * struct rtnl_link_ops - rtnetlink link operations - * - * @list: Used internally - * @kind: Identifier - * @maxtype: Highest device specific netlink attribute number - * @policy: Netlink policy for device specific attribute validation - * @validate: Optional validation function for netlink/changelink parameters - * @priv_size: sizeof net_device private space - * @setup: net_device setup function - * @newlink: Function for configuring and registering a new device - * @changelink: Function for changing parameters of an existing device - * @dellink: Function to remove a device - * @get_size: Function to calculate required room for dumping device - * specific netlink attributes - * @fill_info: Function to dump device specific netlink attributes - * @get_xstats_size: Function to calculate required room for dumping device - * specific statistics - * @fill_xstats: Function to dump device specific statistics - * @get_num_tx_queues: Function to determine number of transmit queues - * to create when creating a new device. - * @get_num_rx_queues: Function to determine number of receive queues - * to create when creating a new device. - * @get_link_net: Function to get the i/o netns of the device - * @get_linkxstats_size: Function to calculate the required room for - * dumping device-specific extended link stats - * @fill_linkxstats: Function to dump device-specific extended link stats - */ -struct rtnl_link_ops { - struct list_head list; - - const char *kind; - - size_t priv_size; - void (*setup)(struct net_device *dev); - - int maxtype; - const struct nla_policy *policy; - int (*validate)(struct nlattr *tb[], - struct nlattr *data[]); - - int (*newlink)(struct net *src_net, - struct net_device *dev, - struct nlattr *tb[], - struct nlattr *data[]); - int (*changelink)(struct net_device *dev, - struct nlattr *tb[], - struct nlattr *data[]); - void (*dellink)(struct net_device *dev, - struct list_head *head); - - size_t (*get_size)(const struct net_device *dev); - int (*fill_info)(struct sk_buff *skb, - const struct net_device *dev); - - size_t (*get_xstats_size)(const struct net_device *dev); - int (*fill_xstats)(struct sk_buff *skb, - const struct net_device *dev); - unsigned int (*get_num_tx_queues)(void); - unsigned int (*get_num_rx_queues)(void); - - int slave_maxtype; - const struct nla_policy *slave_policy; - int (*slave_validate)(struct nlattr *tb[], - struct nlattr *data[]); - int (*slave_changelink)(struct net_device *dev, - struct net_device *slave_dev, - struct nlattr *tb[], - struct nlattr *data[]); - size_t (*get_slave_size)(const struct net_device *dev, - const struct net_device *slave_dev); - int (*fill_slave_info)(struct sk_buff *skb, - const struct net_device *dev, - const struct net_device *slave_dev); - struct net *(*get_link_net)(const struct net_device *dev); - size_t (*get_linkxstats_size)(const struct net_device *dev, - int attr); - int (*fill_linkxstats)(struct sk_buff *skb, - const struct net_device *dev, - int *prividx, int attr); -}; - -int __rtnl_link_register(struct rtnl_link_ops *ops); -void __rtnl_link_unregister(struct rtnl_link_ops *ops); - -int rtnl_link_register(struct rtnl_link_ops *ops); -void rtnl_link_unregister(struct rtnl_link_ops *ops); - -/** - * struct rtnl_af_ops - rtnetlink address family operations - * - * @list: Used internally - * @family: Address family - * @fill_link_af: Function to fill IFLA_AF_SPEC with address family - * specific netlink attributes. - * @get_link_af_size: Function to calculate size of address family specific - * netlink attributes. - * @validate_link_af: Validate a IFLA_AF_SPEC attribute, must check attr - * for invalid configuration settings. - * @set_link_af: Function to parse a IFLA_AF_SPEC attribute and modify - * net_device accordingly. - */ -struct rtnl_af_ops { - struct list_head list; - int family; - - int (*fill_link_af)(struct sk_buff *skb, - const struct net_device *dev, - u32 ext_filter_mask); - size_t (*get_link_af_size)(const struct net_device *dev, - u32 ext_filter_mask); - - int (*validate_link_af)(const struct net_device *dev, - const struct nlattr *attr); - int (*set_link_af)(struct net_device *dev, - const struct nlattr *attr); -}; - -void __rtnl_af_unregister(struct rtnl_af_ops *ops); - -void rtnl_af_register(struct rtnl_af_ops *ops); -void rtnl_af_unregister(struct rtnl_af_ops *ops); - -struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]); -struct net_device *rtnl_create_link(struct net *net, const char *ifname, - unsigned char name_assign_type, - const struct rtnl_link_ops *ops, - struct nlattr *tb[]); -int rtnl_delete_link(struct net_device *dev); -int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm); - -int rtnl_nla_parse_ifla(struct nlattr **tb, const struct nlattr *head, int len); - -#define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind) - -#endif diff --git a/src/linux/include/net/sch_generic.h b/src/linux/include/net/sch_generic.h deleted file mode 100644 index e6aa0a2..0000000 --- a/src/linux/include/net/sch_generic.h +++ /dev/null @@ -1,847 +0,0 @@ -#ifndef __NET_SCHED_GENERIC_H -#define __NET_SCHED_GENERIC_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct Qdisc_ops; -struct qdisc_walker; -struct tcf_walker; -struct module; - -struct qdisc_rate_table { - struct tc_ratespec rate; - u32 data[256]; - struct qdisc_rate_table *next; - int refcnt; -}; - -enum qdisc_state_t { - __QDISC_STATE_SCHED, - __QDISC_STATE_DEACTIVATED, -}; - -struct qdisc_size_table { - struct rcu_head rcu; - struct list_head list; - struct tc_sizespec szopts; - int refcnt; - u16 data[]; -}; - -/* similar to sk_buff_head, but skb->prev pointer is undefined. */ -struct qdisc_skb_head { - struct sk_buff *head; - struct sk_buff *tail; - __u32 qlen; - spinlock_t lock; -}; - -struct Qdisc { - int (*enqueue)(struct sk_buff *skb, - struct Qdisc *sch, - struct sk_buff **to_free); - struct sk_buff * (*dequeue)(struct Qdisc *sch); - unsigned int flags; -#define TCQ_F_BUILTIN 1 -#define TCQ_F_INGRESS 2 -#define TCQ_F_CAN_BYPASS 4 -#define TCQ_F_MQROOT 8 -#define TCQ_F_ONETXQUEUE 0x10 /* dequeue_skb() can assume all skbs are for - * q->dev_queue : It can test - * netif_xmit_frozen_or_stopped() before - * dequeueing next packet. - * Its true for MQ/MQPRIO slaves, or non - * multiqueue device. - */ -#define TCQ_F_WARN_NONWC (1 << 16) -#define TCQ_F_CPUSTATS 0x20 /* run using percpu statistics */ -#define TCQ_F_NOPARENT 0x40 /* root of its hierarchy : - * qdisc_tree_decrease_qlen() should stop. - */ - u32 limit; - const struct Qdisc_ops *ops; - struct qdisc_size_table __rcu *stab; - struct hlist_node hash; - u32 handle; - u32 parent; - void *u32_node; - - struct netdev_queue *dev_queue; - - struct gnet_stats_rate_est64 rate_est; - struct gnet_stats_basic_cpu __percpu *cpu_bstats; - struct gnet_stats_queue __percpu *cpu_qstats; - - /* - * For performance sake on SMP, we put highly modified fields at the end - */ - struct sk_buff *gso_skb ____cacheline_aligned_in_smp; - struct qdisc_skb_head q; - struct gnet_stats_basic_packed bstats; - seqcount_t running; - struct gnet_stats_queue qstats; - unsigned long state; - struct Qdisc *next_sched; - struct sk_buff *skb_bad_txq; - struct rcu_head rcu_head; - int padded; - atomic_t refcnt; - - spinlock_t busylock ____cacheline_aligned_in_smp; -}; - -static inline bool qdisc_is_running(const struct Qdisc *qdisc) -{ - return (raw_read_seqcount(&qdisc->running) & 1) ? true : false; -} - -static inline bool qdisc_run_begin(struct Qdisc *qdisc) -{ - if (qdisc_is_running(qdisc)) - return false; - /* Variant of write_seqcount_begin() telling lockdep a trylock - * was attempted. - */ - raw_write_seqcount_begin(&qdisc->running); - seqcount_acquire(&qdisc->running.dep_map, 0, 1, _RET_IP_); - return true; -} - -static inline void qdisc_run_end(struct Qdisc *qdisc) -{ - write_seqcount_end(&qdisc->running); -} - -static inline bool qdisc_may_bulk(const struct Qdisc *qdisc) -{ - return qdisc->flags & TCQ_F_ONETXQUEUE; -} - -static inline int qdisc_avail_bulklimit(const struct netdev_queue *txq) -{ -#ifdef CONFIG_BQL - /* Non-BQL migrated drivers will return 0, too. */ - return dql_avail(&txq->dql); -#else - return 0; -#endif -} - -struct Qdisc_class_ops { - /* Child qdisc manipulation */ - struct netdev_queue * (*select_queue)(struct Qdisc *, struct tcmsg *); - int (*graft)(struct Qdisc *, unsigned long cl, - struct Qdisc *, struct Qdisc **); - struct Qdisc * (*leaf)(struct Qdisc *, unsigned long cl); - void (*qlen_notify)(struct Qdisc *, unsigned long); - - /* Class manipulation routines */ - unsigned long (*get)(struct Qdisc *, u32 classid); - void (*put)(struct Qdisc *, unsigned long); - int (*change)(struct Qdisc *, u32, u32, - struct nlattr **, unsigned long *); - int (*delete)(struct Qdisc *, unsigned long); - void (*walk)(struct Qdisc *, struct qdisc_walker * arg); - - /* Filter manipulation */ - struct tcf_proto __rcu ** (*tcf_chain)(struct Qdisc *, unsigned long); - bool (*tcf_cl_offload)(u32 classid); - unsigned long (*bind_tcf)(struct Qdisc *, unsigned long, - u32 classid); - void (*unbind_tcf)(struct Qdisc *, unsigned long); - - /* rtnetlink specific */ - int (*dump)(struct Qdisc *, unsigned long, - struct sk_buff *skb, struct tcmsg*); - int (*dump_stats)(struct Qdisc *, unsigned long, - struct gnet_dump *); -}; - -struct Qdisc_ops { - struct Qdisc_ops *next; - const struct Qdisc_class_ops *cl_ops; - char id[IFNAMSIZ]; - int priv_size; - - int (*enqueue)(struct sk_buff *skb, - struct Qdisc *sch, - struct sk_buff **to_free); - struct sk_buff * (*dequeue)(struct Qdisc *); - struct sk_buff * (*peek)(struct Qdisc *); - - int (*init)(struct Qdisc *, struct nlattr *arg); - void (*reset)(struct Qdisc *); - void (*destroy)(struct Qdisc *); - int (*change)(struct Qdisc *, struct nlattr *arg); - void (*attach)(struct Qdisc *); - - int (*dump)(struct Qdisc *, struct sk_buff *); - int (*dump_stats)(struct Qdisc *, struct gnet_dump *); - - struct module *owner; -}; - - -struct tcf_result { - unsigned long class; - u32 classid; -}; - -struct tcf_proto_ops { - struct list_head head; - char kind[IFNAMSIZ]; - - int (*classify)(struct sk_buff *, - const struct tcf_proto *, - struct tcf_result *); - int (*init)(struct tcf_proto*); - bool (*destroy)(struct tcf_proto*, bool); - - unsigned long (*get)(struct tcf_proto*, u32 handle); - int (*change)(struct net *net, struct sk_buff *, - struct tcf_proto*, unsigned long, - u32 handle, struct nlattr **, - unsigned long *, bool); - int (*delete)(struct tcf_proto*, unsigned long); - void (*walk)(struct tcf_proto*, struct tcf_walker *arg); - - /* rtnetlink specific */ - int (*dump)(struct net*, struct tcf_proto*, unsigned long, - struct sk_buff *skb, struct tcmsg*); - - struct module *owner; -}; - -struct tcf_proto { - /* Fast access part */ - struct tcf_proto __rcu *next; - void __rcu *root; - int (*classify)(struct sk_buff *, - const struct tcf_proto *, - struct tcf_result *); - __be16 protocol; - - /* All the rest */ - u32 prio; - u32 classid; - struct Qdisc *q; - void *data; - const struct tcf_proto_ops *ops; - struct rcu_head rcu; -}; - -struct qdisc_skb_cb { - unsigned int pkt_len; - u16 slave_dev_queue_mapping; - u16 tc_classid; -#define QDISC_CB_PRIV_LEN 20 - unsigned char data[QDISC_CB_PRIV_LEN]; -}; - -static inline void qdisc_cb_private_validate(const struct sk_buff *skb, int sz) -{ - struct qdisc_skb_cb *qcb; - - BUILD_BUG_ON(sizeof(skb->cb) < offsetof(struct qdisc_skb_cb, data) + sz); - BUILD_BUG_ON(sizeof(qcb->data) < sz); -} - -static inline int qdisc_qlen(const struct Qdisc *q) -{ - return q->q.qlen; -} - -static inline struct qdisc_skb_cb *qdisc_skb_cb(const struct sk_buff *skb) -{ - return (struct qdisc_skb_cb *)skb->cb; -} - -static inline spinlock_t *qdisc_lock(struct Qdisc *qdisc) -{ - return &qdisc->q.lock; -} - -static inline struct Qdisc *qdisc_root(const struct Qdisc *qdisc) -{ - struct Qdisc *q = rcu_dereference_rtnl(qdisc->dev_queue->qdisc); - - return q; -} - -static inline struct Qdisc *qdisc_root_sleeping(const struct Qdisc *qdisc) -{ - return qdisc->dev_queue->qdisc_sleeping; -} - -/* The qdisc root lock is a mechanism by which to top level - * of a qdisc tree can be locked from any qdisc node in the - * forest. This allows changing the configuration of some - * aspect of the qdisc tree while blocking out asynchronous - * qdisc access in the packet processing paths. - * - * It is only legal to do this when the root will not change - * on us. Otherwise we'll potentially lock the wrong qdisc - * root. This is enforced by holding the RTNL semaphore, which - * all users of this lock accessor must do. - */ -static inline spinlock_t *qdisc_root_lock(const struct Qdisc *qdisc) -{ - struct Qdisc *root = qdisc_root(qdisc); - - ASSERT_RTNL(); - return qdisc_lock(root); -} - -static inline spinlock_t *qdisc_root_sleeping_lock(const struct Qdisc *qdisc) -{ - struct Qdisc *root = qdisc_root_sleeping(qdisc); - - ASSERT_RTNL(); - return qdisc_lock(root); -} - -static inline seqcount_t *qdisc_root_sleeping_running(const struct Qdisc *qdisc) -{ - struct Qdisc *root = qdisc_root_sleeping(qdisc); - - ASSERT_RTNL(); - return &root->running; -} - -static inline struct net_device *qdisc_dev(const struct Qdisc *qdisc) -{ - return qdisc->dev_queue->dev; -} - -static inline void sch_tree_lock(const struct Qdisc *q) -{ - spin_lock_bh(qdisc_root_sleeping_lock(q)); -} - -static inline void sch_tree_unlock(const struct Qdisc *q) -{ - spin_unlock_bh(qdisc_root_sleeping_lock(q)); -} - -#define tcf_tree_lock(tp) sch_tree_lock((tp)->q) -#define tcf_tree_unlock(tp) sch_tree_unlock((tp)->q) - -extern struct Qdisc noop_qdisc; -extern struct Qdisc_ops noop_qdisc_ops; -extern struct Qdisc_ops pfifo_fast_ops; -extern struct Qdisc_ops mq_qdisc_ops; -extern struct Qdisc_ops noqueue_qdisc_ops; -extern const struct Qdisc_ops *default_qdisc_ops; -static inline const struct Qdisc_ops * -get_default_qdisc_ops(const struct net_device *dev, int ntx) -{ - return ntx < dev->real_num_tx_queues ? - default_qdisc_ops : &pfifo_fast_ops; -} - -struct Qdisc_class_common { - u32 classid; - struct hlist_node hnode; -}; - -struct Qdisc_class_hash { - struct hlist_head *hash; - unsigned int hashsize; - unsigned int hashmask; - unsigned int hashelems; -}; - -static inline unsigned int qdisc_class_hash(u32 id, u32 mask) -{ - id ^= id >> 8; - id ^= id >> 4; - return id & mask; -} - -static inline struct Qdisc_class_common * -qdisc_class_find(const struct Qdisc_class_hash *hash, u32 id) -{ - struct Qdisc_class_common *cl; - unsigned int h; - - h = qdisc_class_hash(id, hash->hashmask); - hlist_for_each_entry(cl, &hash->hash[h], hnode) { - if (cl->classid == id) - return cl; - } - return NULL; -} - -int qdisc_class_hash_init(struct Qdisc_class_hash *); -void qdisc_class_hash_insert(struct Qdisc_class_hash *, - struct Qdisc_class_common *); -void qdisc_class_hash_remove(struct Qdisc_class_hash *, - struct Qdisc_class_common *); -void qdisc_class_hash_grow(struct Qdisc *, struct Qdisc_class_hash *); -void qdisc_class_hash_destroy(struct Qdisc_class_hash *); - -void dev_init_scheduler(struct net_device *dev); -void dev_shutdown(struct net_device *dev); -void dev_activate(struct net_device *dev); -void dev_deactivate(struct net_device *dev); -void dev_deactivate_many(struct list_head *head); -struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, - struct Qdisc *qdisc); -void qdisc_reset(struct Qdisc *qdisc); -void qdisc_destroy(struct Qdisc *qdisc); -void qdisc_tree_reduce_backlog(struct Qdisc *qdisc, unsigned int n, - unsigned int len); -struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, - const struct Qdisc_ops *ops); -struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue, - const struct Qdisc_ops *ops, u32 parentid); -void __qdisc_calculate_pkt_len(struct sk_buff *skb, - const struct qdisc_size_table *stab); -bool tcf_destroy(struct tcf_proto *tp, bool force); -void tcf_destroy_chain(struct tcf_proto __rcu **fl); -int skb_do_redirect(struct sk_buff *); - -static inline bool skb_at_tc_ingress(const struct sk_buff *skb) -{ -#ifdef CONFIG_NET_CLS_ACT - return G_TC_AT(skb->tc_verd) & AT_INGRESS; -#else - return false; -#endif -} - -/* Reset all TX qdiscs greater then index of a device. */ -static inline void qdisc_reset_all_tx_gt(struct net_device *dev, unsigned int i) -{ - struct Qdisc *qdisc; - - for (; i < dev->num_tx_queues; i++) { - qdisc = rtnl_dereference(netdev_get_tx_queue(dev, i)->qdisc); - if (qdisc) { - spin_lock_bh(qdisc_lock(qdisc)); - qdisc_reset(qdisc); - spin_unlock_bh(qdisc_lock(qdisc)); - } - } -} - -static inline void qdisc_reset_all_tx(struct net_device *dev) -{ - qdisc_reset_all_tx_gt(dev, 0); -} - -/* Are all TX queues of the device empty? */ -static inline bool qdisc_all_tx_empty(const struct net_device *dev) -{ - unsigned int i; - - rcu_read_lock(); - for (i = 0; i < dev->num_tx_queues; i++) { - struct netdev_queue *txq = netdev_get_tx_queue(dev, i); - const struct Qdisc *q = rcu_dereference(txq->qdisc); - - if (q->q.qlen) { - rcu_read_unlock(); - return false; - } - } - rcu_read_unlock(); - return true; -} - -/* Are any of the TX qdiscs changing? */ -static inline bool qdisc_tx_changing(const struct net_device *dev) -{ - unsigned int i; - - for (i = 0; i < dev->num_tx_queues; i++) { - struct netdev_queue *txq = netdev_get_tx_queue(dev, i); - if (rcu_access_pointer(txq->qdisc) != txq->qdisc_sleeping) - return true; - } - return false; -} - -/* Is the device using the noop qdisc on all queues? */ -static inline bool qdisc_tx_is_noop(const struct net_device *dev) -{ - unsigned int i; - - for (i = 0; i < dev->num_tx_queues; i++) { - struct netdev_queue *txq = netdev_get_tx_queue(dev, i); - if (rcu_access_pointer(txq->qdisc) != &noop_qdisc) - return false; - } - return true; -} - -static inline unsigned int qdisc_pkt_len(const struct sk_buff *skb) -{ - return qdisc_skb_cb(skb)->pkt_len; -} - -/* additional qdisc xmit flags (NET_XMIT_MASK in linux/netdevice.h) */ -enum net_xmit_qdisc_t { - __NET_XMIT_STOLEN = 0x00010000, - __NET_XMIT_BYPASS = 0x00020000, -}; - -#ifdef CONFIG_NET_CLS_ACT -#define net_xmit_drop_count(e) ((e) & __NET_XMIT_STOLEN ? 0 : 1) -#else -#define net_xmit_drop_count(e) (1) -#endif - -static inline void qdisc_calculate_pkt_len(struct sk_buff *skb, - const struct Qdisc *sch) -{ -#ifdef CONFIG_NET_SCHED - struct qdisc_size_table *stab = rcu_dereference_bh(sch->stab); - - if (stab) - __qdisc_calculate_pkt_len(skb, stab); -#endif -} - -static inline int qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch, - struct sk_buff **to_free) -{ - qdisc_calculate_pkt_len(skb, sch); - return sch->enqueue(skb, sch, to_free); -} - -static inline bool qdisc_is_percpu_stats(const struct Qdisc *q) -{ - return q->flags & TCQ_F_CPUSTATS; -} - -static inline void _bstats_update(struct gnet_stats_basic_packed *bstats, - __u64 bytes, __u32 packets) -{ - bstats->bytes += bytes; - bstats->packets += packets; -} - -static inline void bstats_update(struct gnet_stats_basic_packed *bstats, - const struct sk_buff *skb) -{ - _bstats_update(bstats, - qdisc_pkt_len(skb), - skb_is_gso(skb) ? skb_shinfo(skb)->gso_segs : 1); -} - -static inline void _bstats_cpu_update(struct gnet_stats_basic_cpu *bstats, - __u64 bytes, __u32 packets) -{ - u64_stats_update_begin(&bstats->syncp); - _bstats_update(&bstats->bstats, bytes, packets); - u64_stats_update_end(&bstats->syncp); -} - -static inline void bstats_cpu_update(struct gnet_stats_basic_cpu *bstats, - const struct sk_buff *skb) -{ - u64_stats_update_begin(&bstats->syncp); - bstats_update(&bstats->bstats, skb); - u64_stats_update_end(&bstats->syncp); -} - -static inline void qdisc_bstats_cpu_update(struct Qdisc *sch, - const struct sk_buff *skb) -{ - bstats_cpu_update(this_cpu_ptr(sch->cpu_bstats), skb); -} - -static inline void qdisc_bstats_update(struct Qdisc *sch, - const struct sk_buff *skb) -{ - bstats_update(&sch->bstats, skb); -} - -static inline void qdisc_qstats_backlog_dec(struct Qdisc *sch, - const struct sk_buff *skb) -{ - sch->qstats.backlog -= qdisc_pkt_len(skb); -} - -static inline void qdisc_qstats_backlog_inc(struct Qdisc *sch, - const struct sk_buff *skb) -{ - sch->qstats.backlog += qdisc_pkt_len(skb); -} - -static inline void __qdisc_qstats_drop(struct Qdisc *sch, int count) -{ - sch->qstats.drops += count; -} - -static inline void qstats_drop_inc(struct gnet_stats_queue *qstats) -{ - qstats->drops++; -} - -static inline void qstats_overlimit_inc(struct gnet_stats_queue *qstats) -{ - qstats->overlimits++; -} - -static inline void qdisc_qstats_drop(struct Qdisc *sch) -{ - qstats_drop_inc(&sch->qstats); -} - -static inline void qdisc_qstats_cpu_drop(struct Qdisc *sch) -{ - this_cpu_inc(sch->cpu_qstats->drops); -} - -static inline void qdisc_qstats_overlimit(struct Qdisc *sch) -{ - sch->qstats.overlimits++; -} - -static inline void qdisc_skb_head_init(struct qdisc_skb_head *qh) -{ - qh->head = NULL; - qh->tail = NULL; - qh->qlen = 0; -} - -static inline int __qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch, - struct qdisc_skb_head *qh) -{ - struct sk_buff *last = qh->tail; - - if (last) { - skb->next = NULL; - last->next = skb; - qh->tail = skb; - } else { - qh->tail = skb; - qh->head = skb; - } - qh->qlen++; - qdisc_qstats_backlog_inc(sch, skb); - - return NET_XMIT_SUCCESS; -} - -static inline int qdisc_enqueue_tail(struct sk_buff *skb, struct Qdisc *sch) -{ - return __qdisc_enqueue_tail(skb, sch, &sch->q); -} - -static inline struct sk_buff *__qdisc_dequeue_head(struct qdisc_skb_head *qh) -{ - struct sk_buff *skb = qh->head; - - if (likely(skb != NULL)) { - qh->head = skb->next; - qh->qlen--; - if (qh->head == NULL) - qh->tail = NULL; - skb->next = NULL; - } - - return skb; -} - -static inline struct sk_buff *qdisc_dequeue_head(struct Qdisc *sch) -{ - struct sk_buff *skb = __qdisc_dequeue_head(&sch->q); - - if (likely(skb != NULL)) { - qdisc_qstats_backlog_dec(sch, skb); - qdisc_bstats_update(sch, skb); - } - - return skb; -} - -/* Instead of calling kfree_skb() while root qdisc lock is held, - * queue the skb for future freeing at end of __dev_xmit_skb() - */ -static inline void __qdisc_drop(struct sk_buff *skb, struct sk_buff **to_free) -{ - skb->next = *to_free; - *to_free = skb; -} - -static inline unsigned int __qdisc_queue_drop_head(struct Qdisc *sch, - struct qdisc_skb_head *qh, - struct sk_buff **to_free) -{ - struct sk_buff *skb = __qdisc_dequeue_head(qh); - - if (likely(skb != NULL)) { - unsigned int len = qdisc_pkt_len(skb); - - qdisc_qstats_backlog_dec(sch, skb); - __qdisc_drop(skb, to_free); - return len; - } - - return 0; -} - -static inline unsigned int qdisc_queue_drop_head(struct Qdisc *sch, - struct sk_buff **to_free) -{ - return __qdisc_queue_drop_head(sch, &sch->q, to_free); -} - -static inline struct sk_buff *qdisc_peek_head(struct Qdisc *sch) -{ - const struct qdisc_skb_head *qh = &sch->q; - - return qh->head; -} - -/* generic pseudo peek method for non-work-conserving qdisc */ -static inline struct sk_buff *qdisc_peek_dequeued(struct Qdisc *sch) -{ - /* we can reuse ->gso_skb because peek isn't called for root qdiscs */ - if (!sch->gso_skb) { - sch->gso_skb = sch->dequeue(sch); - if (sch->gso_skb) { - /* it's still part of the queue */ - qdisc_qstats_backlog_inc(sch, sch->gso_skb); - sch->q.qlen++; - } - } - - return sch->gso_skb; -} - -/* use instead of qdisc->dequeue() for all qdiscs queried with ->peek() */ -static inline struct sk_buff *qdisc_dequeue_peeked(struct Qdisc *sch) -{ - struct sk_buff *skb = sch->gso_skb; - - if (skb) { - sch->gso_skb = NULL; - qdisc_qstats_backlog_dec(sch, skb); - sch->q.qlen--; - } else { - skb = sch->dequeue(sch); - } - - return skb; -} - -static inline void __qdisc_reset_queue(struct qdisc_skb_head *qh) -{ - /* - * We do not know the backlog in bytes of this list, it - * is up to the caller to correct it - */ - ASSERT_RTNL(); - if (qh->qlen) { - rtnl_kfree_skbs(qh->head, qh->tail); - - qh->head = NULL; - qh->tail = NULL; - qh->qlen = 0; - } -} - -static inline void qdisc_reset_queue(struct Qdisc *sch) -{ - __qdisc_reset_queue(&sch->q); - sch->qstats.backlog = 0; -} - -static inline struct Qdisc *qdisc_replace(struct Qdisc *sch, struct Qdisc *new, - struct Qdisc **pold) -{ - struct Qdisc *old; - - sch_tree_lock(sch); - old = *pold; - *pold = new; - if (old != NULL) { - qdisc_tree_reduce_backlog(old, old->q.qlen, old->qstats.backlog); - qdisc_reset(old); - } - sch_tree_unlock(sch); - - return old; -} - -static inline void rtnl_qdisc_drop(struct sk_buff *skb, struct Qdisc *sch) -{ - rtnl_kfree_skbs(skb, skb); - qdisc_qstats_drop(sch); -} - - -static inline int qdisc_drop(struct sk_buff *skb, struct Qdisc *sch, - struct sk_buff **to_free) -{ - __qdisc_drop(skb, to_free); - qdisc_qstats_drop(sch); - - return NET_XMIT_DROP; -} - -/* Length to Time (L2T) lookup in a qdisc_rate_table, to determine how - long it will take to send a packet given its size. - */ -static inline u32 qdisc_l2t(struct qdisc_rate_table* rtab, unsigned int pktlen) -{ - int slot = pktlen + rtab->rate.cell_align + rtab->rate.overhead; - if (slot < 0) - slot = 0; - slot >>= rtab->rate.cell_log; - if (slot > 255) - return rtab->data[255]*(slot >> 8) + rtab->data[slot & 0xFF]; - return rtab->data[slot]; -} - -struct psched_ratecfg { - u64 rate_bytes_ps; /* bytes per second */ - u32 mult; - u16 overhead; - u8 linklayer; - u8 shift; -}; - -static inline u64 psched_l2t_ns(const struct psched_ratecfg *r, - unsigned int len) -{ - len += r->overhead; - - if (unlikely(r->linklayer == TC_LINKLAYER_ATM)) - return ((u64)(DIV_ROUND_UP(len,48)*53) * r->mult) >> r->shift; - - return ((u64)len * r->mult) >> r->shift; -} - -void psched_ratecfg_precompute(struct psched_ratecfg *r, - const struct tc_ratespec *conf, - u64 rate64); - -static inline void psched_ratecfg_getrate(struct tc_ratespec *res, - const struct psched_ratecfg *r) -{ - memset(res, 0, sizeof(*res)); - - /* legacy struct tc_ratespec has a 32bit @rate field - * Qdisc using 64bit rate should add new attributes - * in order to maintain compatibility. - */ - res->rate = min_t(u64, r->rate_bytes_ps, ~0U); - - res->overhead = r->overhead; - res->linklayer = (r->linklayer & TC_LINKLAYER_MASK); -} - -#endif diff --git a/src/linux/include/net/scm.h b/src/linux/include/net/scm.h deleted file mode 100644 index 59fa93c..0000000 --- a/src/linux/include/net/scm.h +++ /dev/null @@ -1,142 +0,0 @@ -#ifndef __LINUX_NET_SCM_H -#define __LINUX_NET_SCM_H - -#include -#include -#include -#include -#include - -/* Well, we should have at least one descriptor open - * to accept passed FDs 8) - */ -#define SCM_MAX_FD 253 - -struct scm_creds { - u32 pid; - kuid_t uid; - kgid_t gid; -}; - -struct scm_fp_list { - short count; - short max; - struct user_struct *user; - struct file *fp[SCM_MAX_FD]; -}; - -struct scm_cookie { - struct pid *pid; /* Skb credentials */ - struct scm_fp_list *fp; /* Passed files */ - struct scm_creds creds; /* Skb credentials */ -#ifdef CONFIG_SECURITY_NETWORK - u32 secid; /* Passed security ID */ -#endif -}; - -void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm); -void scm_detach_fds_compat(struct msghdr *msg, struct scm_cookie *scm); -int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm); -void __scm_destroy(struct scm_cookie *scm); -struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl); - -#ifdef CONFIG_SECURITY_NETWORK -static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm) -{ - security_socket_getpeersec_dgram(sock, NULL, &scm->secid); -} -#else -static __inline__ void unix_get_peersec_dgram(struct socket *sock, struct scm_cookie *scm) -{ } -#endif /* CONFIG_SECURITY_NETWORK */ - -static __inline__ void scm_set_cred(struct scm_cookie *scm, - struct pid *pid, kuid_t uid, kgid_t gid) -{ - scm->pid = get_pid(pid); - scm->creds.pid = pid_vnr(pid); - scm->creds.uid = uid; - scm->creds.gid = gid; -} - -static __inline__ void scm_destroy_cred(struct scm_cookie *scm) -{ - put_pid(scm->pid); - scm->pid = NULL; -} - -static __inline__ void scm_destroy(struct scm_cookie *scm) -{ - scm_destroy_cred(scm); - if (scm->fp) - __scm_destroy(scm); -} - -static __inline__ int scm_send(struct socket *sock, struct msghdr *msg, - struct scm_cookie *scm, bool forcecreds) -{ - memset(scm, 0, sizeof(*scm)); - scm->creds.uid = INVALID_UID; - scm->creds.gid = INVALID_GID; - if (forcecreds) - scm_set_cred(scm, task_tgid(current), current_uid(), current_gid()); - unix_get_peersec_dgram(sock, scm); - if (msg->msg_controllen <= 0) - return 0; - return __scm_send(sock, msg, scm); -} - -#ifdef CONFIG_SECURITY_NETWORK -static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm) -{ - char *secdata; - u32 seclen; - int err; - - if (test_bit(SOCK_PASSSEC, &sock->flags)) { - err = security_secid_to_secctx(scm->secid, &secdata, &seclen); - - if (!err) { - put_cmsg(msg, SOL_SOCKET, SCM_SECURITY, seclen, secdata); - security_release_secctx(secdata, seclen); - } - } -} -#else -static inline void scm_passec(struct socket *sock, struct msghdr *msg, struct scm_cookie *scm) -{ } -#endif /* CONFIG_SECURITY_NETWORK */ - -static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, - struct scm_cookie *scm, int flags) -{ - if (!msg->msg_control) { - if (test_bit(SOCK_PASSCRED, &sock->flags) || scm->fp) - msg->msg_flags |= MSG_CTRUNC; - scm_destroy(scm); - return; - } - - if (test_bit(SOCK_PASSCRED, &sock->flags)) { - struct user_namespace *current_ns = current_user_ns(); - struct ucred ucreds = { - .pid = scm->creds.pid, - .uid = from_kuid_munged(current_ns, scm->creds.uid), - .gid = from_kgid_munged(current_ns, scm->creds.gid), - }; - put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds); - } - - scm_destroy_cred(scm); - - scm_passec(sock, msg, scm); - - if (!scm->fp) - return; - - scm_detach_fds(msg, scm); -} - - -#endif /* __LINUX_NET_SCM_H */ - diff --git a/src/linux/include/net/secure_seq.h b/src/linux/include/net/secure_seq.h deleted file mode 100644 index 3f36d45..0000000 --- a/src/linux/include/net/secure_seq.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _NET_SECURE_SEQ -#define _NET_SECURE_SEQ - -#include - -u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport); -u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, - __be16 dport); -__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, - __be16 sport, __be16 dport); -__u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr, - __be16 sport, __be16 dport); -u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, - __be16 sport, __be16 dport); -u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr, - __be16 sport, __be16 dport); - -#endif /* _NET_SECURE_SEQ */ diff --git a/src/linux/include/net/snmp.h b/src/linux/include/net/snmp.h deleted file mode 100644 index c9228ad..0000000 --- a/src/linux/include/net/snmp.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * - * SNMP MIB entries for the IP subsystem. - * - * Alan Cox - * - * We don't chose to implement SNMP in the kernel (this would - * be silly as SNMP is a pain in the backside in places). We do - * however need to collect the MIB statistics and export them - * out of /proc (eventually) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#ifndef _SNMP_H -#define _SNMP_H - -#include -#include -#include - -/* - * Mibs are stored in array of unsigned long. - */ -/* - * struct snmp_mib{} - * - list of entries for particular API (such as /proc/net/snmp) - * - name of entries. - */ -struct snmp_mib { - const char *name; - int entry; -}; - -#define SNMP_MIB_ITEM(_name,_entry) { \ - .name = _name, \ - .entry = _entry, \ -} - -#define SNMP_MIB_SENTINEL { \ - .name = NULL, \ - .entry = 0, \ -} - -/* - * We use unsigned longs for most mibs but u64 for ipstats. - */ -#include - -/* IPstats */ -#define IPSTATS_MIB_MAX __IPSTATS_MIB_MAX -struct ipstats_mib { - /* mibs[] must be first field of struct ipstats_mib */ - u64 mibs[IPSTATS_MIB_MAX]; - struct u64_stats_sync syncp; -}; - -/* ICMP */ -#define ICMP_MIB_MAX __ICMP_MIB_MAX -struct icmp_mib { - unsigned long mibs[ICMP_MIB_MAX]; -}; - -#define ICMPMSG_MIB_MAX __ICMPMSG_MIB_MAX -struct icmpmsg_mib { - atomic_long_t mibs[ICMPMSG_MIB_MAX]; -}; - -/* ICMP6 (IPv6-ICMP) */ -#define ICMP6_MIB_MAX __ICMP6_MIB_MAX -/* per network ns counters */ -struct icmpv6_mib { - unsigned long mibs[ICMP6_MIB_MAX]; -}; -/* per device counters, (shared on all cpus) */ -struct icmpv6_mib_device { - atomic_long_t mibs[ICMP6_MIB_MAX]; -}; - -#define ICMP6MSG_MIB_MAX __ICMP6MSG_MIB_MAX -/* per network ns counters */ -struct icmpv6msg_mib { - atomic_long_t mibs[ICMP6MSG_MIB_MAX]; -}; -/* per device counters, (shared on all cpus) */ -struct icmpv6msg_mib_device { - atomic_long_t mibs[ICMP6MSG_MIB_MAX]; -}; - - -/* TCP */ -#define TCP_MIB_MAX __TCP_MIB_MAX -struct tcp_mib { - unsigned long mibs[TCP_MIB_MAX]; -}; - -/* UDP */ -#define UDP_MIB_MAX __UDP_MIB_MAX -struct udp_mib { - unsigned long mibs[UDP_MIB_MAX]; -}; - -/* Linux */ -#define LINUX_MIB_MAX __LINUX_MIB_MAX -struct linux_mib { - unsigned long mibs[LINUX_MIB_MAX]; -}; - -/* Linux Xfrm */ -#define LINUX_MIB_XFRMMAX __LINUX_MIB_XFRMMAX -struct linux_xfrm_mib { - unsigned long mibs[LINUX_MIB_XFRMMAX]; -}; - -#define DEFINE_SNMP_STAT(type, name) \ - __typeof__(type) __percpu *name -#define DEFINE_SNMP_STAT_ATOMIC(type, name) \ - __typeof__(type) *name -#define DECLARE_SNMP_STAT(type, name) \ - extern __typeof__(type) __percpu *name - -#define __SNMP_INC_STATS(mib, field) \ - __this_cpu_inc(mib->mibs[field]) - -#define SNMP_INC_STATS_ATOMIC_LONG(mib, field) \ - atomic_long_inc(&mib->mibs[field]) - -#define SNMP_INC_STATS(mib, field) \ - this_cpu_inc(mib->mibs[field]) - -#define SNMP_DEC_STATS(mib, field) \ - this_cpu_dec(mib->mibs[field]) - -#define __SNMP_ADD_STATS(mib, field, addend) \ - __this_cpu_add(mib->mibs[field], addend) - -#define SNMP_ADD_STATS(mib, field, addend) \ - this_cpu_add(mib->mibs[field], addend) -#define SNMP_UPD_PO_STATS(mib, basefield, addend) \ - do { \ - __typeof__((mib->mibs) + 0) ptr = mib->mibs; \ - this_cpu_inc(ptr[basefield##PKTS]); \ - this_cpu_add(ptr[basefield##OCTETS], addend); \ - } while (0) -#define __SNMP_UPD_PO_STATS(mib, basefield, addend) \ - do { \ - __typeof__((mib->mibs) + 0) ptr = mib->mibs; \ - __this_cpu_inc(ptr[basefield##PKTS]); \ - __this_cpu_add(ptr[basefield##OCTETS], addend); \ - } while (0) - - -#if BITS_PER_LONG==32 - -#define __SNMP_ADD_STATS64(mib, field, addend) \ - do { \ - __typeof__(*mib) *ptr = raw_cpu_ptr(mib); \ - u64_stats_update_begin(&ptr->syncp); \ - ptr->mibs[field] += addend; \ - u64_stats_update_end(&ptr->syncp); \ - } while (0) - -#define SNMP_ADD_STATS64(mib, field, addend) \ - do { \ - local_bh_disable(); \ - __SNMP_ADD_STATS64(mib, field, addend); \ - local_bh_enable(); \ - } while (0) - -#define __SNMP_INC_STATS64(mib, field) SNMP_ADD_STATS64(mib, field, 1) -#define SNMP_INC_STATS64(mib, field) SNMP_ADD_STATS64(mib, field, 1) -#define __SNMP_UPD_PO_STATS64(mib, basefield, addend) \ - do { \ - __typeof__(*mib) *ptr; \ - ptr = raw_cpu_ptr((mib)); \ - u64_stats_update_begin(&ptr->syncp); \ - ptr->mibs[basefield##PKTS]++; \ - ptr->mibs[basefield##OCTETS] += addend; \ - u64_stats_update_end(&ptr->syncp); \ - } while (0) -#define SNMP_UPD_PO_STATS64(mib, basefield, addend) \ - do { \ - local_bh_disable(); \ - __SNMP_UPD_PO_STATS64(mib, basefield, addend); \ - local_bh_enable(); \ - } while (0) -#else -#define __SNMP_INC_STATS64(mib, field) __SNMP_INC_STATS(mib, field) -#define SNMP_INC_STATS64(mib, field) SNMP_INC_STATS(mib, field) -#define SNMP_DEC_STATS64(mib, field) SNMP_DEC_STATS(mib, field) -#define __SNMP_ADD_STATS64(mib, field, addend) __SNMP_ADD_STATS(mib, field, addend) -#define SNMP_ADD_STATS64(mib, field, addend) SNMP_ADD_STATS(mib, field, addend) -#define SNMP_UPD_PO_STATS64(mib, basefield, addend) SNMP_UPD_PO_STATS(mib, basefield, addend) -#define __SNMP_UPD_PO_STATS64(mib, basefield, addend) __SNMP_UPD_PO_STATS(mib, basefield, addend) -#endif - -#endif diff --git a/src/linux/include/net/sock.h b/src/linux/include/net/sock.h deleted file mode 100644 index 92b2697..0000000 --- a/src/linux/include/net/sock.h +++ /dev/null @@ -1,2286 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the AF_INET socket handler. - * - * Version: @(#)sock.h 1.0.4 05/13/93 - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Corey Minyard - * Florian La Roche - * - * Fixes: - * Alan Cox : Volatiles in skbuff pointers. See - * skbuff comments. May be overdone, - * better to prove they can be removed - * than the reverse. - * Alan Cox : Added a zapped field for tcp to note - * a socket is reset and must stay shut up - * Alan Cox : New fields for options - * Pauline Middelink : identd support - * Alan Cox : Eliminate low level recv/recvfrom - * David S. Miller : New socket lookup architecture. - * Steve Whitehouse: Default routines for sock_ops - * Arnaldo C. Melo : removed net_pinfo, tp_pinfo and made - * protinfo be just a void pointer, as the - * protocol specific parts were moved to - * respective headers and ipv4/v6, etc now - * use private slabcaches for its socks - * Pedro Hortas : New flags field for socket options - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _SOCK_H -#define _SOCK_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* struct sk_buff */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -/* - * This structure really needs to be cleaned up. - * Most of it is for TCP, and not used by any of - * the other protocols. - */ - -/* Define this to get the SOCK_DBG debugging facility. */ -#define SOCK_DEBUGGING -#ifdef SOCK_DEBUGGING -#define SOCK_DEBUG(sk, msg...) do { if ((sk) && sock_flag((sk), SOCK_DBG)) \ - printk(KERN_DEBUG msg); } while (0) -#else -/* Validate arguments and do nothing */ -static inline __printf(2, 3) -void SOCK_DEBUG(const struct sock *sk, const char *msg, ...) -{ -} -#endif - -/* This is the per-socket lock. The spinlock provides a synchronization - * between user contexts and software interrupt processing, whereas the - * mini-semaphore synchronizes multiple users amongst themselves. - */ -typedef struct { - spinlock_t slock; - int owned; - wait_queue_head_t wq; - /* - * We express the mutex-alike socket_lock semantics - * to the lock validator by explicitly managing - * the slock as a lock variant (in addition to - * the slock itself): - */ -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map dep_map; -#endif -} socket_lock_t; - -struct sock; -struct proto; -struct net; - -typedef __u32 __bitwise __portpair; -typedef __u64 __bitwise __addrpair; - -/** - * struct sock_common - minimal network layer representation of sockets - * @skc_daddr: Foreign IPv4 addr - * @skc_rcv_saddr: Bound local IPv4 addr - * @skc_hash: hash value used with various protocol lookup tables - * @skc_u16hashes: two u16 hash values used by UDP lookup tables - * @skc_dport: placeholder for inet_dport/tw_dport - * @skc_num: placeholder for inet_num/tw_num - * @skc_family: network address family - * @skc_state: Connection state - * @skc_reuse: %SO_REUSEADDR setting - * @skc_reuseport: %SO_REUSEPORT setting - * @skc_bound_dev_if: bound device index if != 0 - * @skc_bind_node: bind hash linkage for various protocol lookup tables - * @skc_portaddr_node: second hash linkage for UDP/UDP-Lite protocol - * @skc_prot: protocol handlers inside a network family - * @skc_net: reference to the network namespace of this socket - * @skc_node: main hash linkage for various protocol lookup tables - * @skc_nulls_node: main hash linkage for TCP/UDP/UDP-Lite protocol - * @skc_tx_queue_mapping: tx queue number for this connection - * @skc_flags: place holder for sk_flags - * %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE, - * %SO_OOBINLINE settings, %SO_TIMESTAMPING settings - * @skc_incoming_cpu: record/match cpu processing incoming packets - * @skc_refcnt: reference count - * - * This is the minimal network layer representation of sockets, the header - * for struct sock and struct inet_timewait_sock. - */ -struct sock_common { - /* skc_daddr and skc_rcv_saddr must be grouped on a 8 bytes aligned - * address on 64bit arches : cf INET_MATCH() - */ - union { - __addrpair skc_addrpair; - struct { - __be32 skc_daddr; - __be32 skc_rcv_saddr; - }; - }; - union { - unsigned int skc_hash; - __u16 skc_u16hashes[2]; - }; - /* skc_dport && skc_num must be grouped as well */ - union { - __portpair skc_portpair; - struct { - __be16 skc_dport; - __u16 skc_num; - }; - }; - - unsigned short skc_family; - volatile unsigned char skc_state; - unsigned char skc_reuse:4; - unsigned char skc_reuseport:1; - unsigned char skc_ipv6only:1; - unsigned char skc_net_refcnt:1; - int skc_bound_dev_if; - union { - struct hlist_node skc_bind_node; - struct hlist_node skc_portaddr_node; - }; - struct proto *skc_prot; - possible_net_t skc_net; - -#if IS_ENABLED(CONFIG_IPV6) - struct in6_addr skc_v6_daddr; - struct in6_addr skc_v6_rcv_saddr; -#endif - - atomic64_t skc_cookie; - - /* following fields are padding to force - * offset(struct sock, sk_refcnt) == 128 on 64bit arches - * assuming IPV6 is enabled. We use this padding differently - * for different kind of 'sockets' - */ - union { - unsigned long skc_flags; - struct sock *skc_listener; /* request_sock */ - struct inet_timewait_death_row *skc_tw_dr; /* inet_timewait_sock */ - }; - /* - * fields between dontcopy_begin/dontcopy_end - * are not copied in sock_copy() - */ - /* private: */ - int skc_dontcopy_begin[0]; - /* public: */ - union { - struct hlist_node skc_node; - struct hlist_nulls_node skc_nulls_node; - }; - int skc_tx_queue_mapping; - union { - int skc_incoming_cpu; - u32 skc_rcv_wnd; - u32 skc_tw_rcv_nxt; /* struct tcp_timewait_sock */ - }; - - atomic_t skc_refcnt; - /* private: */ - int skc_dontcopy_end[0]; - union { - u32 skc_rxhash; - u32 skc_window_clamp; - u32 skc_tw_snd_nxt; /* struct tcp_timewait_sock */ - }; - /* public: */ -}; - -/** - * struct sock - network layer representation of sockets - * @__sk_common: shared layout with inet_timewait_sock - * @sk_shutdown: mask of %SEND_SHUTDOWN and/or %RCV_SHUTDOWN - * @sk_userlocks: %SO_SNDBUF and %SO_RCVBUF settings - * @sk_lock: synchronizer - * @sk_rcvbuf: size of receive buffer in bytes - * @sk_wq: sock wait queue and async head - * @sk_rx_dst: receive input route used by early demux - * @sk_dst_cache: destination cache - * @sk_policy: flow policy - * @sk_receive_queue: incoming packets - * @sk_wmem_alloc: transmit queue bytes committed - * @sk_write_queue: Packet sending queue - * @sk_omem_alloc: "o" is "option" or "other" - * @sk_wmem_queued: persistent queue size - * @sk_forward_alloc: space allocated forward - * @sk_napi_id: id of the last napi context to receive data for sk - * @sk_ll_usec: usecs to busypoll when there is no data - * @sk_allocation: allocation mode - * @sk_pacing_rate: Pacing rate (if supported by transport/packet scheduler) - * @sk_max_pacing_rate: Maximum pacing rate (%SO_MAX_PACING_RATE) - * @sk_sndbuf: size of send buffer in bytes - * @sk_padding: unused element for alignment - * @sk_no_check_tx: %SO_NO_CHECK setting, set checksum in TX packets - * @sk_no_check_rx: allow zero checksum in RX packets - * @sk_route_caps: route capabilities (e.g. %NETIF_F_TSO) - * @sk_route_nocaps: forbidden route capabilities (e.g NETIF_F_GSO_MASK) - * @sk_gso_type: GSO type (e.g. %SKB_GSO_TCPV4) - * @sk_gso_max_size: Maximum GSO segment size to build - * @sk_gso_max_segs: Maximum number of GSO segments - * @sk_lingertime: %SO_LINGER l_linger setting - * @sk_backlog: always used with the per-socket spinlock held - * @sk_callback_lock: used with the callbacks in the end of this struct - * @sk_error_queue: rarely used - * @sk_prot_creator: sk_prot of original sock creator (see ipv6_setsockopt, - * IPV6_ADDRFORM for instance) - * @sk_err: last error - * @sk_err_soft: errors that don't cause failure but are the cause of a - * persistent failure not just 'timed out' - * @sk_drops: raw/udp drops counter - * @sk_ack_backlog: current listen backlog - * @sk_max_ack_backlog: listen backlog set in listen() - * @sk_priority: %SO_PRIORITY setting - * @sk_type: socket type (%SOCK_STREAM, etc) - * @sk_protocol: which protocol this socket belongs in this network family - * @sk_peer_pid: &struct pid for this socket's peer - * @sk_peer_cred: %SO_PEERCRED setting - * @sk_rcvlowat: %SO_RCVLOWAT setting - * @sk_rcvtimeo: %SO_RCVTIMEO setting - * @sk_sndtimeo: %SO_SNDTIMEO setting - * @sk_txhash: computed flow hash for use on transmit - * @sk_filter: socket filtering instructions - * @sk_timer: sock cleanup timer - * @sk_stamp: time stamp of last packet received - * @sk_tsflags: SO_TIMESTAMPING socket options - * @sk_tskey: counter to disambiguate concurrent tstamp requests - * @sk_socket: Identd and reporting IO signals - * @sk_user_data: RPC layer private data - * @sk_frag: cached page frag - * @sk_peek_off: current peek_offset value - * @sk_send_head: front of stuff to transmit - * @sk_security: used by security modules - * @sk_mark: generic packet mark - * @sk_cgrp_data: cgroup data for this cgroup - * @sk_memcg: this socket's memory cgroup association - * @sk_write_pending: a write to stream socket waits to start - * @sk_state_change: callback to indicate change in the state of the sock - * @sk_data_ready: callback to indicate there is data to be processed - * @sk_write_space: callback to indicate there is bf sending space available - * @sk_error_report: callback to indicate errors (e.g. %MSG_ERRQUEUE) - * @sk_backlog_rcv: callback to process the backlog - * @sk_destruct: called at sock freeing time, i.e. when all refcnt == 0 - * @sk_reuseport_cb: reuseport group container - * @sk_rcu: used during RCU grace period - */ -struct sock { - /* - * Now struct inet_timewait_sock also uses sock_common, so please just - * don't add nothing before this first member (__sk_common) --acme - */ - struct sock_common __sk_common; -#define sk_node __sk_common.skc_node -#define sk_nulls_node __sk_common.skc_nulls_node -#define sk_refcnt __sk_common.skc_refcnt -#define sk_tx_queue_mapping __sk_common.skc_tx_queue_mapping - -#define sk_dontcopy_begin __sk_common.skc_dontcopy_begin -#define sk_dontcopy_end __sk_common.skc_dontcopy_end -#define sk_hash __sk_common.skc_hash -#define sk_portpair __sk_common.skc_portpair -#define sk_num __sk_common.skc_num -#define sk_dport __sk_common.skc_dport -#define sk_addrpair __sk_common.skc_addrpair -#define sk_daddr __sk_common.skc_daddr -#define sk_rcv_saddr __sk_common.skc_rcv_saddr -#define sk_family __sk_common.skc_family -#define sk_state __sk_common.skc_state -#define sk_reuse __sk_common.skc_reuse -#define sk_reuseport __sk_common.skc_reuseport -#define sk_ipv6only __sk_common.skc_ipv6only -#define sk_net_refcnt __sk_common.skc_net_refcnt -#define sk_bound_dev_if __sk_common.skc_bound_dev_if -#define sk_bind_node __sk_common.skc_bind_node -#define sk_prot __sk_common.skc_prot -#define sk_net __sk_common.skc_net -#define sk_v6_daddr __sk_common.skc_v6_daddr -#define sk_v6_rcv_saddr __sk_common.skc_v6_rcv_saddr -#define sk_cookie __sk_common.skc_cookie -#define sk_incoming_cpu __sk_common.skc_incoming_cpu -#define sk_flags __sk_common.skc_flags -#define sk_rxhash __sk_common.skc_rxhash - - socket_lock_t sk_lock; - struct sk_buff_head sk_receive_queue; - /* - * The backlog queue is special, it is always used with - * the per-socket spinlock held and requires low latency - * access. Therefore we special case it's implementation. - * Note : rmem_alloc is in this structure to fill a hole - * on 64bit arches, not because its logically part of - * backlog. - */ - struct { - atomic_t rmem_alloc; - int len; - struct sk_buff *head; - struct sk_buff *tail; - } sk_backlog; -#define sk_rmem_alloc sk_backlog.rmem_alloc - int sk_forward_alloc; - - __u32 sk_txhash; -#ifdef CONFIG_NET_RX_BUSY_POLL - unsigned int sk_napi_id; - unsigned int sk_ll_usec; -#endif - atomic_t sk_drops; - int sk_rcvbuf; - - struct sk_filter __rcu *sk_filter; - union { - struct socket_wq __rcu *sk_wq; - struct socket_wq *sk_wq_raw; - }; -#ifdef CONFIG_XFRM - struct xfrm_policy __rcu *sk_policy[2]; -#endif - struct dst_entry *sk_rx_dst; - struct dst_entry __rcu *sk_dst_cache; - /* Note: 32bit hole on 64bit arches */ - atomic_t sk_wmem_alloc; - atomic_t sk_omem_alloc; - int sk_sndbuf; - struct sk_buff_head sk_write_queue; - - /* - * Because of non atomicity rules, all - * changes are protected by socket lock. - */ - kmemcheck_bitfield_begin(flags); - unsigned int sk_padding : 2, - sk_no_check_tx : 1, - sk_no_check_rx : 1, - sk_userlocks : 4, - sk_protocol : 8, - sk_type : 16; -#define SK_PROTOCOL_MAX U8_MAX - kmemcheck_bitfield_end(flags); - - int sk_wmem_queued; - gfp_t sk_allocation; - u32 sk_pacing_rate; /* bytes per second */ - u32 sk_max_pacing_rate; - netdev_features_t sk_route_caps; - netdev_features_t sk_route_nocaps; - int sk_gso_type; - unsigned int sk_gso_max_size; - u16 sk_gso_max_segs; - int sk_rcvlowat; - unsigned long sk_lingertime; - struct sk_buff_head sk_error_queue; - struct proto *sk_prot_creator; - rwlock_t sk_callback_lock; - int sk_err, - sk_err_soft; - u32 sk_ack_backlog; - u32 sk_max_ack_backlog; - __u32 sk_priority; - __u32 sk_mark; - struct pid *sk_peer_pid; - const struct cred *sk_peer_cred; - long sk_rcvtimeo; - long sk_sndtimeo; - struct timer_list sk_timer; - ktime_t sk_stamp; - u16 sk_tsflags; - u8 sk_shutdown; - u32 sk_tskey; - struct socket *sk_socket; - void *sk_user_data; - struct page_frag sk_frag; - struct sk_buff *sk_send_head; - __s32 sk_peek_off; - int sk_write_pending; -#ifdef CONFIG_SECURITY - void *sk_security; -#endif - struct sock_cgroup_data sk_cgrp_data; - struct mem_cgroup *sk_memcg; - void (*sk_state_change)(struct sock *sk); - void (*sk_data_ready)(struct sock *sk); - void (*sk_write_space)(struct sock *sk); - void (*sk_error_report)(struct sock *sk); - int (*sk_backlog_rcv)(struct sock *sk, - struct sk_buff *skb); - void (*sk_destruct)(struct sock *sk); - struct sock_reuseport __rcu *sk_reuseport_cb; - struct rcu_head sk_rcu; -}; - -#define __sk_user_data(sk) ((*((void __rcu **)&(sk)->sk_user_data))) - -#define rcu_dereference_sk_user_data(sk) rcu_dereference(__sk_user_data((sk))) -#define rcu_assign_sk_user_data(sk, ptr) rcu_assign_pointer(__sk_user_data((sk)), ptr) - -/* - * SK_CAN_REUSE and SK_NO_REUSE on a socket mean that the socket is OK - * or not whether his port will be reused by someone else. SK_FORCE_REUSE - * on a socket means that the socket will reuse everybody else's port - * without looking at the other's sk_reuse value. - */ - -#define SK_NO_REUSE 0 -#define SK_CAN_REUSE 1 -#define SK_FORCE_REUSE 2 - -int sk_set_peek_off(struct sock *sk, int val); - -static inline int sk_peek_offset(struct sock *sk, int flags) -{ - if (unlikely(flags & MSG_PEEK)) { - s32 off = READ_ONCE(sk->sk_peek_off); - if (off >= 0) - return off; - } - - return 0; -} - -static inline void sk_peek_offset_bwd(struct sock *sk, int val) -{ - s32 off = READ_ONCE(sk->sk_peek_off); - - if (unlikely(off >= 0)) { - off = max_t(s32, off - val, 0); - WRITE_ONCE(sk->sk_peek_off, off); - } -} - -static inline void sk_peek_offset_fwd(struct sock *sk, int val) -{ - sk_peek_offset_bwd(sk, -val); -} - -/* - * Hashed lists helper routines - */ -static inline struct sock *sk_entry(const struct hlist_node *node) -{ - return hlist_entry(node, struct sock, sk_node); -} - -static inline struct sock *__sk_head(const struct hlist_head *head) -{ - return hlist_entry(head->first, struct sock, sk_node); -} - -static inline struct sock *sk_head(const struct hlist_head *head) -{ - return hlist_empty(head) ? NULL : __sk_head(head); -} - -static inline struct sock *__sk_nulls_head(const struct hlist_nulls_head *head) -{ - return hlist_nulls_entry(head->first, struct sock, sk_nulls_node); -} - -static inline struct sock *sk_nulls_head(const struct hlist_nulls_head *head) -{ - return hlist_nulls_empty(head) ? NULL : __sk_nulls_head(head); -} - -static inline struct sock *sk_next(const struct sock *sk) -{ - return sk->sk_node.next ? - hlist_entry(sk->sk_node.next, struct sock, sk_node) : NULL; -} - -static inline struct sock *sk_nulls_next(const struct sock *sk) -{ - return (!is_a_nulls(sk->sk_nulls_node.next)) ? - hlist_nulls_entry(sk->sk_nulls_node.next, - struct sock, sk_nulls_node) : - NULL; -} - -static inline bool sk_unhashed(const struct sock *sk) -{ - return hlist_unhashed(&sk->sk_node); -} - -static inline bool sk_hashed(const struct sock *sk) -{ - return !sk_unhashed(sk); -} - -static inline void sk_node_init(struct hlist_node *node) -{ - node->pprev = NULL; -} - -static inline void sk_nulls_node_init(struct hlist_nulls_node *node) -{ - node->pprev = NULL; -} - -static inline void __sk_del_node(struct sock *sk) -{ - __hlist_del(&sk->sk_node); -} - -/* NB: equivalent to hlist_del_init_rcu */ -static inline bool __sk_del_node_init(struct sock *sk) -{ - if (sk_hashed(sk)) { - __sk_del_node(sk); - sk_node_init(&sk->sk_node); - return true; - } - return false; -} - -/* Grab socket reference count. This operation is valid only - when sk is ALREADY grabbed f.e. it is found in hash table - or a list and the lookup is made under lock preventing hash table - modifications. - */ - -static __always_inline void sock_hold(struct sock *sk) -{ - atomic_inc(&sk->sk_refcnt); -} - -/* Ungrab socket in the context, which assumes that socket refcnt - cannot hit zero, f.e. it is true in context of any socketcall. - */ -static __always_inline void __sock_put(struct sock *sk) -{ - atomic_dec(&sk->sk_refcnt); -} - -static inline bool sk_del_node_init(struct sock *sk) -{ - bool rc = __sk_del_node_init(sk); - - if (rc) { - /* paranoid for a while -acme */ - WARN_ON(atomic_read(&sk->sk_refcnt) == 1); - __sock_put(sk); - } - return rc; -} -#define sk_del_node_init_rcu(sk) sk_del_node_init(sk) - -static inline bool __sk_nulls_del_node_init_rcu(struct sock *sk) -{ - if (sk_hashed(sk)) { - hlist_nulls_del_init_rcu(&sk->sk_nulls_node); - return true; - } - return false; -} - -static inline bool sk_nulls_del_node_init_rcu(struct sock *sk) -{ - bool rc = __sk_nulls_del_node_init_rcu(sk); - - if (rc) { - /* paranoid for a while -acme */ - WARN_ON(atomic_read(&sk->sk_refcnt) == 1); - __sock_put(sk); - } - return rc; -} - -static inline void __sk_add_node(struct sock *sk, struct hlist_head *list) -{ - hlist_add_head(&sk->sk_node, list); -} - -static inline void sk_add_node(struct sock *sk, struct hlist_head *list) -{ - sock_hold(sk); - __sk_add_node(sk, list); -} - -static inline void sk_add_node_rcu(struct sock *sk, struct hlist_head *list) -{ - sock_hold(sk); - if (IS_ENABLED(CONFIG_IPV6) && sk->sk_reuseport && - sk->sk_family == AF_INET6) - hlist_add_tail_rcu(&sk->sk_node, list); - else - hlist_add_head_rcu(&sk->sk_node, list); -} - -static inline void __sk_nulls_add_node_rcu(struct sock *sk, struct hlist_nulls_head *list) -{ - if (IS_ENABLED(CONFIG_IPV6) && sk->sk_reuseport && - sk->sk_family == AF_INET6) - hlist_nulls_add_tail_rcu(&sk->sk_nulls_node, list); - else - hlist_nulls_add_head_rcu(&sk->sk_nulls_node, list); -} - -static inline void sk_nulls_add_node_rcu(struct sock *sk, struct hlist_nulls_head *list) -{ - sock_hold(sk); - __sk_nulls_add_node_rcu(sk, list); -} - -static inline void __sk_del_bind_node(struct sock *sk) -{ - __hlist_del(&sk->sk_bind_node); -} - -static inline void sk_add_bind_node(struct sock *sk, - struct hlist_head *list) -{ - hlist_add_head(&sk->sk_bind_node, list); -} - -#define sk_for_each(__sk, list) \ - hlist_for_each_entry(__sk, list, sk_node) -#define sk_for_each_rcu(__sk, list) \ - hlist_for_each_entry_rcu(__sk, list, sk_node) -#define sk_nulls_for_each(__sk, node, list) \ - hlist_nulls_for_each_entry(__sk, node, list, sk_nulls_node) -#define sk_nulls_for_each_rcu(__sk, node, list) \ - hlist_nulls_for_each_entry_rcu(__sk, node, list, sk_nulls_node) -#define sk_for_each_from(__sk) \ - hlist_for_each_entry_from(__sk, sk_node) -#define sk_nulls_for_each_from(__sk, node) \ - if (__sk && ({ node = &(__sk)->sk_nulls_node; 1; })) \ - hlist_nulls_for_each_entry_from(__sk, node, sk_nulls_node) -#define sk_for_each_safe(__sk, tmp, list) \ - hlist_for_each_entry_safe(__sk, tmp, list, sk_node) -#define sk_for_each_bound(__sk, list) \ - hlist_for_each_entry(__sk, list, sk_bind_node) - -/** - * sk_for_each_entry_offset_rcu - iterate over a list at a given struct offset - * @tpos: the type * to use as a loop cursor. - * @pos: the &struct hlist_node to use as a loop cursor. - * @head: the head for your list. - * @offset: offset of hlist_node within the struct. - * - */ -#define sk_for_each_entry_offset_rcu(tpos, pos, head, offset) \ - for (pos = rcu_dereference((head)->first); \ - pos != NULL && \ - ({ tpos = (typeof(*tpos) *)((void *)pos - offset); 1;}); \ - pos = rcu_dereference(pos->next)) - -static inline struct user_namespace *sk_user_ns(struct sock *sk) -{ - /* Careful only use this in a context where these parameters - * can not change and must all be valid, such as recvmsg from - * userspace. - */ - return sk->sk_socket->file->f_cred->user_ns; -} - -/* Sock flags */ -enum sock_flags { - SOCK_DEAD, - SOCK_DONE, - SOCK_URGINLINE, - SOCK_KEEPOPEN, - SOCK_LINGER, - SOCK_DESTROY, - SOCK_BROADCAST, - SOCK_TIMESTAMP, - SOCK_ZAPPED, - SOCK_USE_WRITE_QUEUE, /* whether to call sk->sk_write_space in sock_wfree */ - SOCK_DBG, /* %SO_DEBUG setting */ - SOCK_RCVTSTAMP, /* %SO_TIMESTAMP setting */ - SOCK_RCVTSTAMPNS, /* %SO_TIMESTAMPNS setting */ - SOCK_LOCALROUTE, /* route locally only, %SO_DONTROUTE setting */ - SOCK_QUEUE_SHRUNK, /* write queue has been shrunk recently */ - SOCK_MEMALLOC, /* VM depends on this socket for swapping */ - SOCK_TIMESTAMPING_RX_SOFTWARE, /* %SOF_TIMESTAMPING_RX_SOFTWARE */ - SOCK_FASYNC, /* fasync() active */ - SOCK_RXQ_OVFL, - SOCK_ZEROCOPY, /* buffers from userspace */ - SOCK_WIFI_STATUS, /* push wifi status to userspace */ - SOCK_NOFCS, /* Tell NIC not to do the Ethernet FCS. - * Will use last 4 bytes of packet sent from - * user-space instead. - */ - SOCK_FILTER_LOCKED, /* Filter cannot be changed anymore */ - SOCK_SELECT_ERR_QUEUE, /* Wake select on error queue */ - SOCK_RCU_FREE, /* wait rcu grace period in sk_destruct() */ -}; - -#define SK_FLAGS_TIMESTAMP ((1UL << SOCK_TIMESTAMP) | (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)) - -static inline void sock_copy_flags(struct sock *nsk, struct sock *osk) -{ - nsk->sk_flags = osk->sk_flags; -} - -static inline void sock_set_flag(struct sock *sk, enum sock_flags flag) -{ - __set_bit(flag, &sk->sk_flags); -} - -static inline void sock_reset_flag(struct sock *sk, enum sock_flags flag) -{ - __clear_bit(flag, &sk->sk_flags); -} - -static inline bool sock_flag(const struct sock *sk, enum sock_flags flag) -{ - return test_bit(flag, &sk->sk_flags); -} - -#ifdef CONFIG_NET -extern struct static_key memalloc_socks; -static inline int sk_memalloc_socks(void) -{ - return static_key_false(&memalloc_socks); -} -#else - -static inline int sk_memalloc_socks(void) -{ - return 0; -} - -#endif - -static inline gfp_t sk_gfp_mask(const struct sock *sk, gfp_t gfp_mask) -{ - return gfp_mask | (sk->sk_allocation & __GFP_MEMALLOC); -} - -static inline void sk_acceptq_removed(struct sock *sk) -{ - sk->sk_ack_backlog--; -} - -static inline void sk_acceptq_added(struct sock *sk) -{ - sk->sk_ack_backlog++; -} - -static inline bool sk_acceptq_is_full(const struct sock *sk) -{ - return sk->sk_ack_backlog > sk->sk_max_ack_backlog; -} - -/* - * Compute minimal free write space needed to queue new packets. - */ -static inline int sk_stream_min_wspace(const struct sock *sk) -{ - return sk->sk_wmem_queued >> 1; -} - -static inline int sk_stream_wspace(const struct sock *sk) -{ - return sk->sk_sndbuf - sk->sk_wmem_queued; -} - -void sk_stream_write_space(struct sock *sk); - -/* OOB backlog add */ -static inline void __sk_add_backlog(struct sock *sk, struct sk_buff *skb) -{ - /* dont let skb dst not refcounted, we are going to leave rcu lock */ - skb_dst_force_safe(skb); - - if (!sk->sk_backlog.tail) - sk->sk_backlog.head = skb; - else - sk->sk_backlog.tail->next = skb; - - sk->sk_backlog.tail = skb; - skb->next = NULL; -} - -/* - * Take into account size of receive queue and backlog queue - * Do not take into account this skb truesize, - * to allow even a single big packet to come. - */ -static inline bool sk_rcvqueues_full(const struct sock *sk, unsigned int limit) -{ - unsigned int qsize = sk->sk_backlog.len + atomic_read(&sk->sk_rmem_alloc); - - return qsize > limit; -} - -/* The per-socket spinlock must be held here. */ -static inline __must_check int sk_add_backlog(struct sock *sk, struct sk_buff *skb, - unsigned int limit) -{ - if (sk_rcvqueues_full(sk, limit)) - return -ENOBUFS; - - /* - * If the skb was allocated from pfmemalloc reserves, only - * allow SOCK_MEMALLOC sockets to use it as this socket is - * helping free memory - */ - if (skb_pfmemalloc(skb) && !sock_flag(sk, SOCK_MEMALLOC)) - return -ENOMEM; - - __sk_add_backlog(sk, skb); - sk->sk_backlog.len += skb->truesize; - return 0; -} - -int __sk_backlog_rcv(struct sock *sk, struct sk_buff *skb); - -static inline int sk_backlog_rcv(struct sock *sk, struct sk_buff *skb) -{ - if (sk_memalloc_socks() && skb_pfmemalloc(skb)) - return __sk_backlog_rcv(sk, skb); - - return sk->sk_backlog_rcv(sk, skb); -} - -static inline void sk_incoming_cpu_update(struct sock *sk) -{ - sk->sk_incoming_cpu = raw_smp_processor_id(); -} - -static inline void sock_rps_record_flow_hash(__u32 hash) -{ -#ifdef CONFIG_RPS - struct rps_sock_flow_table *sock_flow_table; - - rcu_read_lock(); - sock_flow_table = rcu_dereference(rps_sock_flow_table); - rps_record_sock_flow(sock_flow_table, hash); - rcu_read_unlock(); -#endif -} - -static inline void sock_rps_record_flow(const struct sock *sk) -{ -#ifdef CONFIG_RPS - sock_rps_record_flow_hash(sk->sk_rxhash); -#endif -} - -static inline void sock_rps_save_rxhash(struct sock *sk, - const struct sk_buff *skb) -{ -#ifdef CONFIG_RPS - if (unlikely(sk->sk_rxhash != skb->hash)) - sk->sk_rxhash = skb->hash; -#endif -} - -static inline void sock_rps_reset_rxhash(struct sock *sk) -{ -#ifdef CONFIG_RPS - sk->sk_rxhash = 0; -#endif -} - -#define sk_wait_event(__sk, __timeo, __condition) \ - ({ int __rc; \ - release_sock(__sk); \ - __rc = __condition; \ - if (!__rc) { \ - *(__timeo) = schedule_timeout(*(__timeo)); \ - } \ - sched_annotate_sleep(); \ - lock_sock(__sk); \ - __rc = __condition; \ - __rc; \ - }) - -int sk_stream_wait_connect(struct sock *sk, long *timeo_p); -int sk_stream_wait_memory(struct sock *sk, long *timeo_p); -void sk_stream_wait_close(struct sock *sk, long timeo_p); -int sk_stream_error(struct sock *sk, int flags, int err); -void sk_stream_kill_queues(struct sock *sk); -void sk_set_memalloc(struct sock *sk); -void sk_clear_memalloc(struct sock *sk); - -void __sk_flush_backlog(struct sock *sk); - -static inline bool sk_flush_backlog(struct sock *sk) -{ - if (unlikely(READ_ONCE(sk->sk_backlog.tail))) { - __sk_flush_backlog(sk); - return true; - } - return false; -} - -int sk_wait_data(struct sock *sk, long *timeo, const struct sk_buff *skb); - -struct request_sock_ops; -struct timewait_sock_ops; -struct inet_hashinfo; -struct raw_hashinfo; -struct module; - -/* - * caches using SLAB_DESTROY_BY_RCU should let .next pointer from nulls nodes - * un-modified. Special care is taken when initializing object to zero. - */ -static inline void sk_prot_clear_nulls(struct sock *sk, int size) -{ - if (offsetof(struct sock, sk_node.next) != 0) - memset(sk, 0, offsetof(struct sock, sk_node.next)); - memset(&sk->sk_node.pprev, 0, - size - offsetof(struct sock, sk_node.pprev)); -} - -/* Networking protocol blocks we attach to sockets. - * socket layer -> transport layer interface - */ -struct proto { - void (*close)(struct sock *sk, - long timeout); - int (*connect)(struct sock *sk, - struct sockaddr *uaddr, - int addr_len); - int (*disconnect)(struct sock *sk, int flags); - - struct sock * (*accept)(struct sock *sk, int flags, int *err); - - int (*ioctl)(struct sock *sk, int cmd, - unsigned long arg); - int (*init)(struct sock *sk); - void (*destroy)(struct sock *sk); - void (*shutdown)(struct sock *sk, int how); - int (*setsockopt)(struct sock *sk, int level, - int optname, char __user *optval, - unsigned int optlen); - int (*getsockopt)(struct sock *sk, int level, - int optname, char __user *optval, - int __user *option); -#ifdef CONFIG_COMPAT - int (*compat_setsockopt)(struct sock *sk, - int level, - int optname, char __user *optval, - unsigned int optlen); - int (*compat_getsockopt)(struct sock *sk, - int level, - int optname, char __user *optval, - int __user *option); - int (*compat_ioctl)(struct sock *sk, - unsigned int cmd, unsigned long arg); -#endif - int (*sendmsg)(struct sock *sk, struct msghdr *msg, - size_t len); - int (*recvmsg)(struct sock *sk, struct msghdr *msg, - size_t len, int noblock, int flags, - int *addr_len); - int (*sendpage)(struct sock *sk, struct page *page, - int offset, size_t size, int flags); - int (*bind)(struct sock *sk, - struct sockaddr *uaddr, int addr_len); - - int (*backlog_rcv) (struct sock *sk, - struct sk_buff *skb); - - void (*release_cb)(struct sock *sk); - - /* Keeping track of sk's, looking them up, and port selection methods. */ - int (*hash)(struct sock *sk); - void (*unhash)(struct sock *sk); - void (*rehash)(struct sock *sk); - int (*get_port)(struct sock *sk, unsigned short snum); - - /* Keeping track of sockets in use */ -#ifdef CONFIG_PROC_FS - unsigned int inuse_idx; -#endif - - bool (*stream_memory_free)(const struct sock *sk); - /* Memory pressure */ - void (*enter_memory_pressure)(struct sock *sk); - atomic_long_t *memory_allocated; /* Current allocated memory. */ - struct percpu_counter *sockets_allocated; /* Current number of sockets. */ - /* - * Pressure flag: try to collapse. - * Technical note: it is used by multiple contexts non atomically. - * All the __sk_mem_schedule() is of this nature: accounting - * is strict, actions are advisory and have some latency. - */ - int *memory_pressure; - long *sysctl_mem; - int *sysctl_wmem; - int *sysctl_rmem; - int max_header; - bool no_autobind; - - struct kmem_cache *slab; - unsigned int obj_size; - int slab_flags; - - struct percpu_counter *orphan_count; - - struct request_sock_ops *rsk_prot; - struct timewait_sock_ops *twsk_prot; - - union { - struct inet_hashinfo *hashinfo; - struct udp_table *udp_table; - struct raw_hashinfo *raw_hash; - } h; - - struct module *owner; - - char name[32]; - - struct list_head node; -#ifdef SOCK_REFCNT_DEBUG - atomic_t socks; -#endif - int (*diag_destroy)(struct sock *sk, int err); -}; - -int proto_register(struct proto *prot, int alloc_slab); -void proto_unregister(struct proto *prot); - -#ifdef SOCK_REFCNT_DEBUG -static inline void sk_refcnt_debug_inc(struct sock *sk) -{ - atomic_inc(&sk->sk_prot->socks); -} - -static inline void sk_refcnt_debug_dec(struct sock *sk) -{ - atomic_dec(&sk->sk_prot->socks); - printk(KERN_DEBUG "%s socket %p released, %d are still alive\n", - sk->sk_prot->name, sk, atomic_read(&sk->sk_prot->socks)); -} - -static inline void sk_refcnt_debug_release(const struct sock *sk) -{ - if (atomic_read(&sk->sk_refcnt) != 1) - printk(KERN_DEBUG "Destruction of the %s socket %p delayed, refcnt=%d\n", - sk->sk_prot->name, sk, atomic_read(&sk->sk_refcnt)); -} -#else /* SOCK_REFCNT_DEBUG */ -#define sk_refcnt_debug_inc(sk) do { } while (0) -#define sk_refcnt_debug_dec(sk) do { } while (0) -#define sk_refcnt_debug_release(sk) do { } while (0) -#endif /* SOCK_REFCNT_DEBUG */ - -static inline bool sk_stream_memory_free(const struct sock *sk) -{ - if (sk->sk_wmem_queued >= sk->sk_sndbuf) - return false; - - return sk->sk_prot->stream_memory_free ? - sk->sk_prot->stream_memory_free(sk) : true; -} - -static inline bool sk_stream_is_writeable(const struct sock *sk) -{ - return sk_stream_wspace(sk) >= sk_stream_min_wspace(sk) && - sk_stream_memory_free(sk); -} - -static inline int sk_under_cgroup_hierarchy(struct sock *sk, - struct cgroup *ancestor) -{ -#ifdef CONFIG_SOCK_CGROUP_DATA - return cgroup_is_descendant(sock_cgroup_ptr(&sk->sk_cgrp_data), - ancestor); -#else - return -ENOTSUPP; -#endif -} - -static inline bool sk_has_memory_pressure(const struct sock *sk) -{ - return sk->sk_prot->memory_pressure != NULL; -} - -static inline bool sk_under_memory_pressure(const struct sock *sk) -{ - if (!sk->sk_prot->memory_pressure) - return false; - - if (mem_cgroup_sockets_enabled && sk->sk_memcg && - mem_cgroup_under_socket_pressure(sk->sk_memcg)) - return true; - - return !!*sk->sk_prot->memory_pressure; -} - -static inline void sk_leave_memory_pressure(struct sock *sk) -{ - int *memory_pressure = sk->sk_prot->memory_pressure; - - if (!memory_pressure) - return; - - if (*memory_pressure) - *memory_pressure = 0; -} - -static inline void sk_enter_memory_pressure(struct sock *sk) -{ - if (!sk->sk_prot->enter_memory_pressure) - return; - - sk->sk_prot->enter_memory_pressure(sk); -} - -static inline long sk_prot_mem_limits(const struct sock *sk, int index) -{ - return sk->sk_prot->sysctl_mem[index]; -} - -static inline long -sk_memory_allocated(const struct sock *sk) -{ - return atomic_long_read(sk->sk_prot->memory_allocated); -} - -static inline long -sk_memory_allocated_add(struct sock *sk, int amt) -{ - return atomic_long_add_return(amt, sk->sk_prot->memory_allocated); -} - -static inline void -sk_memory_allocated_sub(struct sock *sk, int amt) -{ - atomic_long_sub(amt, sk->sk_prot->memory_allocated); -} - -static inline void sk_sockets_allocated_dec(struct sock *sk) -{ - percpu_counter_dec(sk->sk_prot->sockets_allocated); -} - -static inline void sk_sockets_allocated_inc(struct sock *sk) -{ - percpu_counter_inc(sk->sk_prot->sockets_allocated); -} - -static inline int -sk_sockets_allocated_read_positive(struct sock *sk) -{ - return percpu_counter_read_positive(sk->sk_prot->sockets_allocated); -} - -static inline int -proto_sockets_allocated_sum_positive(struct proto *prot) -{ - return percpu_counter_sum_positive(prot->sockets_allocated); -} - -static inline long -proto_memory_allocated(struct proto *prot) -{ - return atomic_long_read(prot->memory_allocated); -} - -static inline bool -proto_memory_pressure(struct proto *prot) -{ - if (!prot->memory_pressure) - return false; - return !!*prot->memory_pressure; -} - - -#ifdef CONFIG_PROC_FS -/* Called with local bh disabled */ -void sock_prot_inuse_add(struct net *net, struct proto *prot, int inc); -int sock_prot_inuse_get(struct net *net, struct proto *proto); -#else -static inline void sock_prot_inuse_add(struct net *net, struct proto *prot, - int inc) -{ -} -#endif - - -/* With per-bucket locks this operation is not-atomic, so that - * this version is not worse. - */ -static inline int __sk_prot_rehash(struct sock *sk) -{ - sk->sk_prot->unhash(sk); - return sk->sk_prot->hash(sk); -} - -/* About 10 seconds */ -#define SOCK_DESTROY_TIME (10*HZ) - -/* Sockets 0-1023 can't be bound to unless you are superuser */ -#define PROT_SOCK 1024 - -#define SHUTDOWN_MASK 3 -#define RCV_SHUTDOWN 1 -#define SEND_SHUTDOWN 2 - -#define SOCK_SNDBUF_LOCK 1 -#define SOCK_RCVBUF_LOCK 2 -#define SOCK_BINDADDR_LOCK 4 -#define SOCK_BINDPORT_LOCK 8 - -struct socket_alloc { - struct socket socket; - struct inode vfs_inode; -}; - -static inline struct socket *SOCKET_I(struct inode *inode) -{ - return &container_of(inode, struct socket_alloc, vfs_inode)->socket; -} - -static inline struct inode *SOCK_INODE(struct socket *socket) -{ - return &container_of(socket, struct socket_alloc, socket)->vfs_inode; -} - -/* - * Functions for memory accounting - */ -int __sk_mem_schedule(struct sock *sk, int size, int kind); -void __sk_mem_reclaim(struct sock *sk, int amount); - -#define SK_MEM_QUANTUM ((int)PAGE_SIZE) -#define SK_MEM_QUANTUM_SHIFT ilog2(SK_MEM_QUANTUM) -#define SK_MEM_SEND 0 -#define SK_MEM_RECV 1 - -static inline int sk_mem_pages(int amt) -{ - return (amt + SK_MEM_QUANTUM - 1) >> SK_MEM_QUANTUM_SHIFT; -} - -static inline bool sk_has_account(struct sock *sk) -{ - /* return true if protocol supports memory accounting */ - return !!sk->sk_prot->memory_allocated; -} - -static inline bool sk_wmem_schedule(struct sock *sk, int size) -{ - if (!sk_has_account(sk)) - return true; - return size <= sk->sk_forward_alloc || - __sk_mem_schedule(sk, size, SK_MEM_SEND); -} - -static inline bool -sk_rmem_schedule(struct sock *sk, struct sk_buff *skb, int size) -{ - if (!sk_has_account(sk)) - return true; - return size<= sk->sk_forward_alloc || - __sk_mem_schedule(sk, size, SK_MEM_RECV) || - skb_pfmemalloc(skb); -} - -static inline void sk_mem_reclaim(struct sock *sk) -{ - if (!sk_has_account(sk)) - return; - if (sk->sk_forward_alloc >= SK_MEM_QUANTUM) - __sk_mem_reclaim(sk, sk->sk_forward_alloc); -} - -static inline void sk_mem_reclaim_partial(struct sock *sk) -{ - if (!sk_has_account(sk)) - return; - if (sk->sk_forward_alloc > SK_MEM_QUANTUM) - __sk_mem_reclaim(sk, sk->sk_forward_alloc - 1); -} - -static inline void sk_mem_charge(struct sock *sk, int size) -{ - if (!sk_has_account(sk)) - return; - sk->sk_forward_alloc -= size; -} - -static inline void sk_mem_uncharge(struct sock *sk, int size) -{ - if (!sk_has_account(sk)) - return; - sk->sk_forward_alloc += size; - - /* Avoid a possible overflow. - * TCP send queues can make this happen, if sk_mem_reclaim() - * is not called and more than 2 GBytes are released at once. - * - * If we reach 2 MBytes, reclaim 1 MBytes right now, there is - * no need to hold that much forward allocation anyway. - */ - if (unlikely(sk->sk_forward_alloc >= 1 << 21)) - __sk_mem_reclaim(sk, 1 << 20); -} - -static inline void sk_wmem_free_skb(struct sock *sk, struct sk_buff *skb) -{ - sock_set_flag(sk, SOCK_QUEUE_SHRUNK); - sk->sk_wmem_queued -= skb->truesize; - sk_mem_uncharge(sk, skb->truesize); - __kfree_skb(skb); -} - -static inline void sock_release_ownership(struct sock *sk) -{ - if (sk->sk_lock.owned) { - sk->sk_lock.owned = 0; - - /* The sk_lock has mutex_unlock() semantics: */ - mutex_release(&sk->sk_lock.dep_map, 1, _RET_IP_); - } -} - -/* - * Macro so as to not evaluate some arguments when - * lockdep is not enabled. - * - * Mark both the sk_lock and the sk_lock.slock as a - * per-address-family lock class. - */ -#define sock_lock_init_class_and_name(sk, sname, skey, name, key) \ -do { \ - sk->sk_lock.owned = 0; \ - init_waitqueue_head(&sk->sk_lock.wq); \ - spin_lock_init(&(sk)->sk_lock.slock); \ - debug_check_no_locks_freed((void *)&(sk)->sk_lock, \ - sizeof((sk)->sk_lock)); \ - lockdep_set_class_and_name(&(sk)->sk_lock.slock, \ - (skey), (sname)); \ - lockdep_init_map(&(sk)->sk_lock.dep_map, (name), (key), 0); \ -} while (0) - -#ifdef CONFIG_LOCKDEP -static inline bool lockdep_sock_is_held(const struct sock *csk) -{ - struct sock *sk = (struct sock *)csk; - - return lockdep_is_held(&sk->sk_lock) || - lockdep_is_held(&sk->sk_lock.slock); -} -#endif - -void lock_sock_nested(struct sock *sk, int subclass); - -static inline void lock_sock(struct sock *sk) -{ - lock_sock_nested(sk, 0); -} - -void release_sock(struct sock *sk); - -/* BH context may only use the following locking interface. */ -#define bh_lock_sock(__sk) spin_lock(&((__sk)->sk_lock.slock)) -#define bh_lock_sock_nested(__sk) \ - spin_lock_nested(&((__sk)->sk_lock.slock), \ - SINGLE_DEPTH_NESTING) -#define bh_unlock_sock(__sk) spin_unlock(&((__sk)->sk_lock.slock)) - -bool lock_sock_fast(struct sock *sk); -/** - * unlock_sock_fast - complement of lock_sock_fast - * @sk: socket - * @slow: slow mode - * - * fast unlock socket for user context. - * If slow mode is on, we call regular release_sock() - */ -static inline void unlock_sock_fast(struct sock *sk, bool slow) -{ - if (slow) - release_sock(sk); - else - spin_unlock_bh(&sk->sk_lock.slock); -} - -/* Used by processes to "lock" a socket state, so that - * interrupts and bottom half handlers won't change it - * from under us. It essentially blocks any incoming - * packets, so that we won't get any new data or any - * packets that change the state of the socket. - * - * While locked, BH processing will add new packets to - * the backlog queue. This queue is processed by the - * owner of the socket lock right before it is released. - * - * Since ~2.3.5 it is also exclusive sleep lock serializing - * accesses from user process context. - */ - -static inline void sock_owned_by_me(const struct sock *sk) -{ -#ifdef CONFIG_LOCKDEP - WARN_ON_ONCE(!lockdep_sock_is_held(sk) && debug_locks); -#endif -} - -static inline bool sock_owned_by_user(const struct sock *sk) -{ - sock_owned_by_me(sk); - return sk->sk_lock.owned; -} - -/* no reclassification while locks are held */ -static inline bool sock_allow_reclassification(const struct sock *csk) -{ - struct sock *sk = (struct sock *)csk; - - return !sk->sk_lock.owned && !spin_is_locked(&sk->sk_lock.slock); -} - -struct sock *sk_alloc(struct net *net, int family, gfp_t priority, - struct proto *prot, int kern); -void sk_free(struct sock *sk); -void sk_destruct(struct sock *sk); -struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority); - -struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, - gfp_t priority); -void __sock_wfree(struct sk_buff *skb); -void sock_wfree(struct sk_buff *skb); -void skb_orphan_partial(struct sk_buff *skb); -void sock_rfree(struct sk_buff *skb); -void sock_efree(struct sk_buff *skb); -#ifdef CONFIG_INET -void sock_edemux(struct sk_buff *skb); -#else -#define sock_edemux(skb) sock_efree(skb) -#endif - -int sock_setsockopt(struct socket *sock, int level, int op, - char __user *optval, unsigned int optlen); - -int sock_getsockopt(struct socket *sock, int level, int op, - char __user *optval, int __user *optlen); -struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, - int noblock, int *errcode); -struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len, - unsigned long data_len, int noblock, - int *errcode, int max_page_order); -void *sock_kmalloc(struct sock *sk, int size, gfp_t priority); -void sock_kfree_s(struct sock *sk, void *mem, int size); -void sock_kzfree_s(struct sock *sk, void *mem, int size); -void sk_send_sigurg(struct sock *sk); - -struct sockcm_cookie { - u32 mark; - u16 tsflags; -}; - -int __sock_cmsg_send(struct sock *sk, struct msghdr *msg, struct cmsghdr *cmsg, - struct sockcm_cookie *sockc); -int sock_cmsg_send(struct sock *sk, struct msghdr *msg, - struct sockcm_cookie *sockc); - -/* - * Functions to fill in entries in struct proto_ops when a protocol - * does not implement a particular function. - */ -int sock_no_bind(struct socket *, struct sockaddr *, int); -int sock_no_connect(struct socket *, struct sockaddr *, int, int); -int sock_no_socketpair(struct socket *, struct socket *); -int sock_no_accept(struct socket *, struct socket *, int); -int sock_no_getname(struct socket *, struct sockaddr *, int *, int); -unsigned int sock_no_poll(struct file *, struct socket *, - struct poll_table_struct *); -int sock_no_ioctl(struct socket *, unsigned int, unsigned long); -int sock_no_listen(struct socket *, int); -int sock_no_shutdown(struct socket *, int); -int sock_no_getsockopt(struct socket *, int , int, char __user *, int __user *); -int sock_no_setsockopt(struct socket *, int, int, char __user *, unsigned int); -int sock_no_sendmsg(struct socket *, struct msghdr *, size_t); -int sock_no_recvmsg(struct socket *, struct msghdr *, size_t, int); -int sock_no_mmap(struct file *file, struct socket *sock, - struct vm_area_struct *vma); -ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, - size_t size, int flags); - -/* - * Functions to fill in entries in struct proto_ops when a protocol - * uses the inet style. - */ -int sock_common_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen); -int sock_common_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, - int flags); -int sock_common_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, unsigned int optlen); -int compat_sock_common_getsockopt(struct socket *sock, int level, - int optname, char __user *optval, int __user *optlen); -int compat_sock_common_setsockopt(struct socket *sock, int level, - int optname, char __user *optval, unsigned int optlen); - -void sk_common_release(struct sock *sk); - -/* - * Default socket callbacks and setup code - */ - -/* Initialise core socket variables */ -void sock_init_data(struct socket *sock, struct sock *sk); - -/* - * Socket reference counting postulates. - * - * * Each user of socket SHOULD hold a reference count. - * * Each access point to socket (an hash table bucket, reference from a list, - * running timer, skb in flight MUST hold a reference count. - * * When reference count hits 0, it means it will never increase back. - * * When reference count hits 0, it means that no references from - * outside exist to this socket and current process on current CPU - * is last user and may/should destroy this socket. - * * sk_free is called from any context: process, BH, IRQ. When - * it is called, socket has no references from outside -> sk_free - * may release descendant resources allocated by the socket, but - * to the time when it is called, socket is NOT referenced by any - * hash tables, lists etc. - * * Packets, delivered from outside (from network or from another process) - * and enqueued on receive/error queues SHOULD NOT grab reference count, - * when they sit in queue. Otherwise, packets will leak to hole, when - * socket is looked up by one cpu and unhasing is made by another CPU. - * It is true for udp/raw, netlink (leak to receive and error queues), tcp - * (leak to backlog). Packet socket does all the processing inside - * BR_NETPROTO_LOCK, so that it has not this race condition. UNIX sockets - * use separate SMP lock, so that they are prone too. - */ - -/* Ungrab socket and destroy it, if it was the last reference. */ -static inline void sock_put(struct sock *sk) -{ - if (atomic_dec_and_test(&sk->sk_refcnt)) - sk_free(sk); -} -/* Generic version of sock_put(), dealing with all sockets - * (TCP_TIMEWAIT, TCP_NEW_SYN_RECV, ESTABLISHED...) - */ -void sock_gen_put(struct sock *sk); - -int __sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested, - unsigned int trim_cap, bool refcounted); -static inline int sk_receive_skb(struct sock *sk, struct sk_buff *skb, - const int nested) -{ - return __sk_receive_skb(sk, skb, nested, 1, true); -} - -static inline void sk_tx_queue_set(struct sock *sk, int tx_queue) -{ - sk->sk_tx_queue_mapping = tx_queue; -} - -static inline void sk_tx_queue_clear(struct sock *sk) -{ - sk->sk_tx_queue_mapping = -1; -} - -static inline int sk_tx_queue_get(const struct sock *sk) -{ - return sk ? sk->sk_tx_queue_mapping : -1; -} - -static inline void sk_set_socket(struct sock *sk, struct socket *sock) -{ - sk_tx_queue_clear(sk); - sk->sk_socket = sock; -} - -static inline wait_queue_head_t *sk_sleep(struct sock *sk) -{ - BUILD_BUG_ON(offsetof(struct socket_wq, wait) != 0); - return &rcu_dereference_raw(sk->sk_wq)->wait; -} -/* Detach socket from process context. - * Announce socket dead, detach it from wait queue and inode. - * Note that parent inode held reference count on this struct sock, - * we do not release it in this function, because protocol - * probably wants some additional cleanups or even continuing - * to work with this socket (TCP). - */ -static inline void sock_orphan(struct sock *sk) -{ - write_lock_bh(&sk->sk_callback_lock); - sock_set_flag(sk, SOCK_DEAD); - sk_set_socket(sk, NULL); - sk->sk_wq = NULL; - write_unlock_bh(&sk->sk_callback_lock); -} - -static inline void sock_graft(struct sock *sk, struct socket *parent) -{ - write_lock_bh(&sk->sk_callback_lock); - sk->sk_wq = parent->wq; - parent->sk = sk; - sk_set_socket(sk, parent); - security_sock_graft(sk, parent); - write_unlock_bh(&sk->sk_callback_lock); -} - -kuid_t sock_i_uid(struct sock *sk); -unsigned long sock_i_ino(struct sock *sk); - -static inline u32 net_tx_rndhash(void) -{ - u32 v = prandom_u32(); - - return v ?: 1; -} - -static inline void sk_set_txhash(struct sock *sk) -{ - sk->sk_txhash = net_tx_rndhash(); -} - -static inline void sk_rethink_txhash(struct sock *sk) -{ - if (sk->sk_txhash) - sk_set_txhash(sk); -} - -static inline struct dst_entry * -__sk_dst_get(struct sock *sk) -{ - return rcu_dereference_check(sk->sk_dst_cache, - lockdep_sock_is_held(sk)); -} - -static inline struct dst_entry * -sk_dst_get(struct sock *sk) -{ - struct dst_entry *dst; - - rcu_read_lock(); - dst = rcu_dereference(sk->sk_dst_cache); - if (dst && !atomic_inc_not_zero(&dst->__refcnt)) - dst = NULL; - rcu_read_unlock(); - return dst; -} - -static inline void dst_negative_advice(struct sock *sk) -{ - struct dst_entry *ndst, *dst = __sk_dst_get(sk); - - sk_rethink_txhash(sk); - - if (dst && dst->ops->negative_advice) { - ndst = dst->ops->negative_advice(dst); - - if (ndst != dst) { - rcu_assign_pointer(sk->sk_dst_cache, ndst); - sk_tx_queue_clear(sk); - } - } -} - -static inline void -__sk_dst_set(struct sock *sk, struct dst_entry *dst) -{ - struct dst_entry *old_dst; - - sk_tx_queue_clear(sk); - /* - * This can be called while sk is owned by the caller only, - * with no state that can be checked in a rcu_dereference_check() cond - */ - old_dst = rcu_dereference_raw(sk->sk_dst_cache); - rcu_assign_pointer(sk->sk_dst_cache, dst); - dst_release(old_dst); -} - -static inline void -sk_dst_set(struct sock *sk, struct dst_entry *dst) -{ - struct dst_entry *old_dst; - - sk_tx_queue_clear(sk); - old_dst = xchg((__force struct dst_entry **)&sk->sk_dst_cache, dst); - dst_release(old_dst); -} - -static inline void -__sk_dst_reset(struct sock *sk) -{ - __sk_dst_set(sk, NULL); -} - -static inline void -sk_dst_reset(struct sock *sk) -{ - sk_dst_set(sk, NULL); -} - -struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie); - -struct dst_entry *sk_dst_check(struct sock *sk, u32 cookie); - -bool sk_mc_loop(struct sock *sk); - -static inline bool sk_can_gso(const struct sock *sk) -{ - return net_gso_ok(sk->sk_route_caps, sk->sk_gso_type); -} - -void sk_setup_caps(struct sock *sk, struct dst_entry *dst); - -static inline void sk_nocaps_add(struct sock *sk, netdev_features_t flags) -{ - sk->sk_route_nocaps |= flags; - sk->sk_route_caps &= ~flags; -} - -static inline bool sk_check_csum_caps(struct sock *sk) -{ - return (sk->sk_route_caps & NETIF_F_HW_CSUM) || - (sk->sk_family == PF_INET && - (sk->sk_route_caps & NETIF_F_IP_CSUM)) || - (sk->sk_family == PF_INET6 && - (sk->sk_route_caps & NETIF_F_IPV6_CSUM)); -} - -static inline int skb_do_copy_data_nocache(struct sock *sk, struct sk_buff *skb, - struct iov_iter *from, char *to, - int copy, int offset) -{ - if (skb->ip_summed == CHECKSUM_NONE) { - __wsum csum = 0; - if (csum_and_copy_from_iter(to, copy, &csum, from) != copy) - return -EFAULT; - skb->csum = csum_block_add(skb->csum, csum, offset); - } else if (sk->sk_route_caps & NETIF_F_NOCACHE_COPY) { - if (copy_from_iter_nocache(to, copy, from) != copy) - return -EFAULT; - } else if (copy_from_iter(to, copy, from) != copy) - return -EFAULT; - - return 0; -} - -static inline int skb_add_data_nocache(struct sock *sk, struct sk_buff *skb, - struct iov_iter *from, int copy) -{ - int err, offset = skb->len; - - err = skb_do_copy_data_nocache(sk, skb, from, skb_put(skb, copy), - copy, offset); - if (err) - __skb_trim(skb, offset); - - return err; -} - -static inline int skb_copy_to_page_nocache(struct sock *sk, struct iov_iter *from, - struct sk_buff *skb, - struct page *page, - int off, int copy) -{ - int err; - - err = skb_do_copy_data_nocache(sk, skb, from, page_address(page) + off, - copy, skb->len); - if (err) - return err; - - skb->len += copy; - skb->data_len += copy; - skb->truesize += copy; - sk->sk_wmem_queued += copy; - sk_mem_charge(sk, copy); - return 0; -} - -/** - * sk_wmem_alloc_get - returns write allocations - * @sk: socket - * - * Returns sk_wmem_alloc minus initial offset of one - */ -static inline int sk_wmem_alloc_get(const struct sock *sk) -{ - return atomic_read(&sk->sk_wmem_alloc) - 1; -} - -/** - * sk_rmem_alloc_get - returns read allocations - * @sk: socket - * - * Returns sk_rmem_alloc - */ -static inline int sk_rmem_alloc_get(const struct sock *sk) -{ - return atomic_read(&sk->sk_rmem_alloc); -} - -/** - * sk_has_allocations - check if allocations are outstanding - * @sk: socket - * - * Returns true if socket has write or read allocations - */ -static inline bool sk_has_allocations(const struct sock *sk) -{ - return sk_wmem_alloc_get(sk) || sk_rmem_alloc_get(sk); -} - -/** - * skwq_has_sleeper - check if there are any waiting processes - * @wq: struct socket_wq - * - * Returns true if socket_wq has waiting processes - * - * The purpose of the skwq_has_sleeper and sock_poll_wait is to wrap the memory - * barrier call. They were added due to the race found within the tcp code. - * - * Consider following tcp code paths: - * - * CPU1 CPU2 - * - * sys_select receive packet - * ... ... - * __add_wait_queue update tp->rcv_nxt - * ... ... - * tp->rcv_nxt check sock_def_readable - * ... { - * schedule rcu_read_lock(); - * wq = rcu_dereference(sk->sk_wq); - * if (wq && waitqueue_active(&wq->wait)) - * wake_up_interruptible(&wq->wait) - * ... - * } - * - * The race for tcp fires when the __add_wait_queue changes done by CPU1 stay - * in its cache, and so does the tp->rcv_nxt update on CPU2 side. The CPU1 - * could then endup calling schedule and sleep forever if there are no more - * data on the socket. - * - */ -static inline bool skwq_has_sleeper(struct socket_wq *wq) -{ - return wq && wq_has_sleeper(&wq->wait); -} - -/** - * sock_poll_wait - place memory barrier behind the poll_wait call. - * @filp: file - * @wait_address: socket wait queue - * @p: poll_table - * - * See the comments in the wq_has_sleeper function. - */ -static inline void sock_poll_wait(struct file *filp, - wait_queue_head_t *wait_address, poll_table *p) -{ - if (!poll_does_not_wait(p) && wait_address) { - poll_wait(filp, wait_address, p); - /* We need to be sure we are in sync with the - * socket flags modification. - * - * This memory barrier is paired in the wq_has_sleeper. - */ - smp_mb(); - } -} - -static inline void skb_set_hash_from_sk(struct sk_buff *skb, struct sock *sk) -{ - if (sk->sk_txhash) { - skb->l4_hash = 1; - skb->hash = sk->sk_txhash; - } -} - -void skb_set_owner_w(struct sk_buff *skb, struct sock *sk); - -/* - * Queue a received datagram if it will fit. Stream and sequenced - * protocols can't normally use this as they need to fit buffers in - * and play with them. - * - * Inlined as it's very short and called for pretty much every - * packet ever received. - */ -static inline void skb_set_owner_r(struct sk_buff *skb, struct sock *sk) -{ - skb_orphan(skb); - skb->sk = sk; - skb->destructor = sock_rfree; - atomic_add(skb->truesize, &sk->sk_rmem_alloc); - sk_mem_charge(sk, skb->truesize); -} - -void sk_reset_timer(struct sock *sk, struct timer_list *timer, - unsigned long expires); - -void sk_stop_timer(struct sock *sk, struct timer_list *timer); - -int __sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); -int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); - -int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb); -struct sk_buff *sock_dequeue_err_skb(struct sock *sk); - -/* - * Recover an error report and clear atomically - */ - -static inline int sock_error(struct sock *sk) -{ - int err; - if (likely(!sk->sk_err)) - return 0; - err = xchg(&sk->sk_err, 0); - return -err; -} - -static inline unsigned long sock_wspace(struct sock *sk) -{ - int amt = 0; - - if (!(sk->sk_shutdown & SEND_SHUTDOWN)) { - amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); - if (amt < 0) - amt = 0; - } - return amt; -} - -/* Note: - * We use sk->sk_wq_raw, from contexts knowing this - * pointer is not NULL and cannot disappear/change. - */ -static inline void sk_set_bit(int nr, struct sock *sk) -{ - if ((nr == SOCKWQ_ASYNC_NOSPACE || nr == SOCKWQ_ASYNC_WAITDATA) && - !sock_flag(sk, SOCK_FASYNC)) - return; - - set_bit(nr, &sk->sk_wq_raw->flags); -} - -static inline void sk_clear_bit(int nr, struct sock *sk) -{ - if ((nr == SOCKWQ_ASYNC_NOSPACE || nr == SOCKWQ_ASYNC_WAITDATA) && - !sock_flag(sk, SOCK_FASYNC)) - return; - - clear_bit(nr, &sk->sk_wq_raw->flags); -} - -static inline void sk_wake_async(const struct sock *sk, int how, int band) -{ - if (sock_flag(sk, SOCK_FASYNC)) { - rcu_read_lock(); - sock_wake_async(rcu_dereference(sk->sk_wq), how, band); - rcu_read_unlock(); - } -} - -/* Since sk_{r,w}mem_alloc sums skb->truesize, even a small frame might - * need sizeof(sk_buff) + MTU + padding, unless net driver perform copybreak. - * Note: for send buffers, TCP works better if we can build two skbs at - * minimum. - */ -#define TCP_SKB_MIN_TRUESIZE (2048 + SKB_DATA_ALIGN(sizeof(struct sk_buff))) - -#define SOCK_MIN_SNDBUF (TCP_SKB_MIN_TRUESIZE * 2) -#define SOCK_MIN_RCVBUF TCP_SKB_MIN_TRUESIZE - -static inline void sk_stream_moderate_sndbuf(struct sock *sk) -{ - if (!(sk->sk_userlocks & SOCK_SNDBUF_LOCK)) { - sk->sk_sndbuf = min(sk->sk_sndbuf, sk->sk_wmem_queued >> 1); - sk->sk_sndbuf = max_t(u32, sk->sk_sndbuf, SOCK_MIN_SNDBUF); - } -} - -struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp, - bool force_schedule); - -/** - * sk_page_frag - return an appropriate page_frag - * @sk: socket - * - * If socket allocation mode allows current thread to sleep, it means its - * safe to use the per task page_frag instead of the per socket one. - */ -static inline struct page_frag *sk_page_frag(struct sock *sk) -{ - if (gfpflags_allow_blocking(sk->sk_allocation)) - return ¤t->task_frag; - - return &sk->sk_frag; -} - -bool sk_page_frag_refill(struct sock *sk, struct page_frag *pfrag); - -/* - * Default write policy as shown to user space via poll/select/SIGIO - */ -static inline bool sock_writeable(const struct sock *sk) -{ - return atomic_read(&sk->sk_wmem_alloc) < (sk->sk_sndbuf >> 1); -} - -static inline gfp_t gfp_any(void) -{ - return in_softirq() ? GFP_ATOMIC : GFP_KERNEL; -} - -static inline long sock_rcvtimeo(const struct sock *sk, bool noblock) -{ - return noblock ? 0 : sk->sk_rcvtimeo; -} - -static inline long sock_sndtimeo(const struct sock *sk, bool noblock) -{ - return noblock ? 0 : sk->sk_sndtimeo; -} - -static inline int sock_rcvlowat(const struct sock *sk, int waitall, int len) -{ - return (waitall ? len : min_t(int, sk->sk_rcvlowat, len)) ? : 1; -} - -/* Alas, with timeout socket operations are not restartable. - * Compare this to poll(). - */ -static inline int sock_intr_errno(long timeo) -{ - return timeo == MAX_SCHEDULE_TIMEOUT ? -ERESTARTSYS : -EINTR; -} - -struct sock_skb_cb { - u32 dropcount; -}; - -/* Store sock_skb_cb at the end of skb->cb[] so protocol families - * using skb->cb[] would keep using it directly and utilize its - * alignement guarantee. - */ -#define SOCK_SKB_CB_OFFSET ((FIELD_SIZEOF(struct sk_buff, cb) - \ - sizeof(struct sock_skb_cb))) - -#define SOCK_SKB_CB(__skb) ((struct sock_skb_cb *)((__skb)->cb + \ - SOCK_SKB_CB_OFFSET)) - -#define sock_skb_cb_check_size(size) \ - BUILD_BUG_ON((size) > SOCK_SKB_CB_OFFSET) - -static inline void -sock_skb_set_dropcount(const struct sock *sk, struct sk_buff *skb) -{ - SOCK_SKB_CB(skb)->dropcount = atomic_read(&sk->sk_drops); -} - -static inline void sk_drops_add(struct sock *sk, const struct sk_buff *skb) -{ - int segs = max_t(u16, 1, skb_shinfo(skb)->gso_segs); - - atomic_add(segs, &sk->sk_drops); -} - -void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, - struct sk_buff *skb); -void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk, - struct sk_buff *skb); - -static inline void -sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb) -{ - ktime_t kt = skb->tstamp; - struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb); - - /* - * generate control messages if - * - receive time stamping in software requested - * - software time stamp available and wanted - * - hardware time stamps available and wanted - */ - if (sock_flag(sk, SOCK_RCVTSTAMP) || - (sk->sk_tsflags & SOF_TIMESTAMPING_RX_SOFTWARE) || - (kt.tv64 && sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE) || - (hwtstamps->hwtstamp.tv64 && - (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE))) - __sock_recv_timestamp(msg, sk, skb); - else - sk->sk_stamp = kt; - - if (sock_flag(sk, SOCK_WIFI_STATUS) && skb->wifi_acked_valid) - __sock_recv_wifi_status(msg, sk, skb); -} - -void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, - struct sk_buff *skb); - -static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, - struct sk_buff *skb) -{ -#define FLAGS_TS_OR_DROPS ((1UL << SOCK_RXQ_OVFL) | \ - (1UL << SOCK_RCVTSTAMP)) -#define TSFLAGS_ANY (SOF_TIMESTAMPING_SOFTWARE | \ - SOF_TIMESTAMPING_RAW_HARDWARE) - - if (sk->sk_flags & FLAGS_TS_OR_DROPS || sk->sk_tsflags & TSFLAGS_ANY) - __sock_recv_ts_and_drops(msg, sk, skb); - else - sk->sk_stamp = skb->tstamp; -} - -void __sock_tx_timestamp(__u16 tsflags, __u8 *tx_flags); - -/** - * sock_tx_timestamp - checks whether the outgoing packet is to be time stamped - * @sk: socket sending this packet - * @tsflags: timestamping flags to use - * @tx_flags: completed with instructions for time stamping - * - * Note : callers should take care of initial *tx_flags value (usually 0) - */ -static inline void sock_tx_timestamp(const struct sock *sk, __u16 tsflags, - __u8 *tx_flags) -{ - if (unlikely(tsflags)) - __sock_tx_timestamp(tsflags, tx_flags); - if (unlikely(sock_flag(sk, SOCK_WIFI_STATUS))) - *tx_flags |= SKBTX_WIFI_STATUS; -} - -/** - * sk_eat_skb - Release a skb if it is no longer needed - * @sk: socket to eat this skb from - * @skb: socket buffer to eat - * - * This routine must be called with interrupts disabled or with the socket - * locked so that the sk_buff queue operation is ok. -*/ -static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb) -{ - __skb_unlink(skb, &sk->sk_receive_queue); - __kfree_skb(skb); -} - -static inline -struct net *sock_net(const struct sock *sk) -{ - return read_pnet(&sk->sk_net); -} - -static inline -void sock_net_set(struct sock *sk, struct net *net) -{ - write_pnet(&sk->sk_net, net); -} - -static inline struct sock *skb_steal_sock(struct sk_buff *skb) -{ - if (skb->sk) { - struct sock *sk = skb->sk; - - skb->destructor = NULL; - skb->sk = NULL; - return sk; - } - return NULL; -} - -/* This helper checks if a socket is a full socket, - * ie _not_ a timewait or request socket. - */ -static inline bool sk_fullsock(const struct sock *sk) -{ - return (1 << sk->sk_state) & ~(TCPF_TIME_WAIT | TCPF_NEW_SYN_RECV); -} - -/* This helper checks if a socket is a LISTEN or NEW_SYN_RECV - * SYNACK messages can be attached to either ones (depending on SYNCOOKIE) - */ -static inline bool sk_listener(const struct sock *sk) -{ - return (1 << sk->sk_state) & (TCPF_LISTEN | TCPF_NEW_SYN_RECV); -} - -/** - * sk_state_load - read sk->sk_state for lockless contexts - * @sk: socket pointer - * - * Paired with sk_state_store(). Used in places we do not hold socket lock : - * tcp_diag_get_info(), tcp_get_info(), tcp_poll(), get_tcp4_sock() ... - */ -static inline int sk_state_load(const struct sock *sk) -{ - return smp_load_acquire(&sk->sk_state); -} - -/** - * sk_state_store - update sk->sk_state - * @sk: socket pointer - * @newstate: new state - * - * Paired with sk_state_load(). Should be used in contexts where - * state change might impact lockless readers. - */ -static inline void sk_state_store(struct sock *sk, int newstate) -{ - smp_store_release(&sk->sk_state, newstate); -} - -void sock_enable_timestamp(struct sock *sk, int flag); -int sock_get_timestamp(struct sock *, struct timeval __user *); -int sock_get_timestampns(struct sock *, struct timespec __user *); -int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len, int level, - int type); - -bool sk_ns_capable(const struct sock *sk, - struct user_namespace *user_ns, int cap); -bool sk_capable(const struct sock *sk, int cap); -bool sk_net_capable(const struct sock *sk, int cap); - -extern __u32 sysctl_wmem_max; -extern __u32 sysctl_rmem_max; - -extern int sysctl_tstamp_allow_data; -extern int sysctl_optmem_max; - -extern __u32 sysctl_wmem_default; -extern __u32 sysctl_rmem_default; - -#endif /* _SOCK_H */ diff --git a/src/linux/include/net/sock_reuseport.h b/src/linux/include/net/sock_reuseport.h deleted file mode 100644 index aecd303..0000000 --- a/src/linux/include/net/sock_reuseport.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _SOCK_REUSEPORT_H -#define _SOCK_REUSEPORT_H - -#include -#include -#include -#include - -struct sock_reuseport { - struct rcu_head rcu; - - u16 max_socks; /* length of socks */ - u16 num_socks; /* elements in socks */ - struct bpf_prog __rcu *prog; /* optional BPF sock selector */ - struct sock *socks[0]; /* array of sock pointers */ -}; - -extern int reuseport_alloc(struct sock *sk); -extern int reuseport_add_sock(struct sock *sk, struct sock *sk2); -extern void reuseport_detach_sock(struct sock *sk); -extern struct sock *reuseport_select_sock(struct sock *sk, - u32 hash, - struct sk_buff *skb, - int hdr_len); -extern struct bpf_prog *reuseport_attach_prog(struct sock *sk, - struct bpf_prog *prog); - -#endif /* _SOCK_REUSEPORT_H */ diff --git a/src/linux/include/net/switchdev.h b/src/linux/include/net/switchdev.h deleted file mode 100644 index eba80c4..0000000 --- a/src/linux/include/net/switchdev.h +++ /dev/null @@ -1,318 +0,0 @@ -/* - * include/net/switchdev.h - Switch device API - * Copyright (c) 2014-2015 Jiri Pirko - * Copyright (c) 2014-2015 Scott Feldman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ -#ifndef _LINUX_SWITCHDEV_H_ -#define _LINUX_SWITCHDEV_H_ - -#include -#include -#include -#include - -#define SWITCHDEV_F_NO_RECURSE BIT(0) -#define SWITCHDEV_F_SKIP_EOPNOTSUPP BIT(1) -#define SWITCHDEV_F_DEFER BIT(2) - -struct switchdev_trans_item { - struct list_head list; - void *data; - void (*destructor)(const void *data); -}; - -struct switchdev_trans { - struct list_head item_list; - bool ph_prepare; -}; - -static inline bool switchdev_trans_ph_prepare(struct switchdev_trans *trans) -{ - return trans && trans->ph_prepare; -} - -static inline bool switchdev_trans_ph_commit(struct switchdev_trans *trans) -{ - return trans && !trans->ph_prepare; -} - -enum switchdev_attr_id { - SWITCHDEV_ATTR_ID_UNDEFINED, - SWITCHDEV_ATTR_ID_PORT_PARENT_ID, - SWITCHDEV_ATTR_ID_PORT_STP_STATE, - SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS, - SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME, - SWITCHDEV_ATTR_ID_BRIDGE_VLAN_FILTERING, -}; - -struct switchdev_attr { - struct net_device *orig_dev; - enum switchdev_attr_id id; - u32 flags; - void *complete_priv; - void (*complete)(struct net_device *dev, int err, void *priv); - union { - struct netdev_phys_item_id ppid; /* PORT_PARENT_ID */ - u8 stp_state; /* PORT_STP_STATE */ - unsigned long brport_flags; /* PORT_BRIDGE_FLAGS */ - clock_t ageing_time; /* BRIDGE_AGEING_TIME */ - bool vlan_filtering; /* BRIDGE_VLAN_FILTERING */ - } u; -}; - -enum switchdev_obj_id { - SWITCHDEV_OBJ_ID_UNDEFINED, - SWITCHDEV_OBJ_ID_PORT_VLAN, - SWITCHDEV_OBJ_ID_PORT_FDB, - SWITCHDEV_OBJ_ID_PORT_MDB, -}; - -struct switchdev_obj { - struct net_device *orig_dev; - enum switchdev_obj_id id; - u32 flags; - void *complete_priv; - void (*complete)(struct net_device *dev, int err, void *priv); -}; - -/* SWITCHDEV_OBJ_ID_PORT_VLAN */ -struct switchdev_obj_port_vlan { - struct switchdev_obj obj; - u16 flags; - u16 vid_begin; - u16 vid_end; -}; - -#define SWITCHDEV_OBJ_PORT_VLAN(obj) \ - container_of(obj, struct switchdev_obj_port_vlan, obj) - -/* SWITCHDEV_OBJ_ID_PORT_FDB */ -struct switchdev_obj_port_fdb { - struct switchdev_obj obj; - unsigned char addr[ETH_ALEN]; - u16 vid; - u16 ndm_state; -}; - -#define SWITCHDEV_OBJ_PORT_FDB(obj) \ - container_of(obj, struct switchdev_obj_port_fdb, obj) - -/* SWITCHDEV_OBJ_ID_PORT_MDB */ -struct switchdev_obj_port_mdb { - struct switchdev_obj obj; - unsigned char addr[ETH_ALEN]; - u16 vid; -}; - -#define SWITCHDEV_OBJ_PORT_MDB(obj) \ - container_of(obj, struct switchdev_obj_port_mdb, obj) - -void switchdev_trans_item_enqueue(struct switchdev_trans *trans, - void *data, void (*destructor)(void const *), - struct switchdev_trans_item *tritem); -void *switchdev_trans_item_dequeue(struct switchdev_trans *trans); - -typedef int switchdev_obj_dump_cb_t(struct switchdev_obj *obj); - -/** - * struct switchdev_ops - switchdev operations - * - * @switchdev_port_attr_get: Get a port attribute (see switchdev_attr). - * - * @switchdev_port_attr_set: Set a port attribute (see switchdev_attr). - * - * @switchdev_port_obj_add: Add an object to port (see switchdev_obj_*). - * - * @switchdev_port_obj_del: Delete an object from port (see switchdev_obj_*). - * - * @switchdev_port_obj_dump: Dump port objects (see switchdev_obj_*). - */ -struct switchdev_ops { - int (*switchdev_port_attr_get)(struct net_device *dev, - struct switchdev_attr *attr); - int (*switchdev_port_attr_set)(struct net_device *dev, - const struct switchdev_attr *attr, - struct switchdev_trans *trans); - int (*switchdev_port_obj_add)(struct net_device *dev, - const struct switchdev_obj *obj, - struct switchdev_trans *trans); - int (*switchdev_port_obj_del)(struct net_device *dev, - const struct switchdev_obj *obj); - int (*switchdev_port_obj_dump)(struct net_device *dev, - struct switchdev_obj *obj, - switchdev_obj_dump_cb_t *cb); -}; - -enum switchdev_notifier_type { - SWITCHDEV_FDB_ADD = 1, - SWITCHDEV_FDB_DEL, -}; - -struct switchdev_notifier_info { - struct net_device *dev; -}; - -struct switchdev_notifier_fdb_info { - struct switchdev_notifier_info info; /* must be first */ - const unsigned char *addr; - u16 vid; -}; - -static inline struct net_device * -switchdev_notifier_info_to_dev(const struct switchdev_notifier_info *info) -{ - return info->dev; -} - -#ifdef CONFIG_NET_SWITCHDEV - -void switchdev_deferred_process(void); -int switchdev_port_attr_get(struct net_device *dev, - struct switchdev_attr *attr); -int switchdev_port_attr_set(struct net_device *dev, - const struct switchdev_attr *attr); -int switchdev_port_obj_add(struct net_device *dev, - const struct switchdev_obj *obj); -int switchdev_port_obj_del(struct net_device *dev, - const struct switchdev_obj *obj); -int switchdev_port_obj_dump(struct net_device *dev, struct switchdev_obj *obj, - switchdev_obj_dump_cb_t *cb); -int register_switchdev_notifier(struct notifier_block *nb); -int unregister_switchdev_notifier(struct notifier_block *nb); -int call_switchdev_notifiers(unsigned long val, struct net_device *dev, - struct switchdev_notifier_info *info); -int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, - struct net_device *dev, u32 filter_mask, - int nlflags); -int switchdev_port_bridge_setlink(struct net_device *dev, - struct nlmsghdr *nlh, u16 flags); -int switchdev_port_bridge_dellink(struct net_device *dev, - struct nlmsghdr *nlh, u16 flags); -int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], - struct net_device *dev, const unsigned char *addr, - u16 vid, u16 nlm_flags); -int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], - struct net_device *dev, const unsigned char *addr, - u16 vid); -int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, - struct net_device *dev, - struct net_device *filter_dev, int *idx); -void switchdev_port_fwd_mark_set(struct net_device *dev, - struct net_device *group_dev, - bool joining); - -bool switchdev_port_same_parent_id(struct net_device *a, - struct net_device *b); -#else - -static inline void switchdev_deferred_process(void) -{ -} - -static inline int switchdev_port_attr_get(struct net_device *dev, - struct switchdev_attr *attr) -{ - return -EOPNOTSUPP; -} - -static inline int switchdev_port_attr_set(struct net_device *dev, - const struct switchdev_attr *attr) -{ - return -EOPNOTSUPP; -} - -static inline int switchdev_port_obj_add(struct net_device *dev, - const struct switchdev_obj *obj) -{ - return -EOPNOTSUPP; -} - -static inline int switchdev_port_obj_del(struct net_device *dev, - const struct switchdev_obj *obj) -{ - return -EOPNOTSUPP; -} - -static inline int switchdev_port_obj_dump(struct net_device *dev, - const struct switchdev_obj *obj, - switchdev_obj_dump_cb_t *cb) -{ - return -EOPNOTSUPP; -} - -static inline int register_switchdev_notifier(struct notifier_block *nb) -{ - return 0; -} - -static inline int unregister_switchdev_notifier(struct notifier_block *nb) -{ - return 0; -} - -static inline int call_switchdev_notifiers(unsigned long val, - struct net_device *dev, - struct switchdev_notifier_info *info) -{ - return NOTIFY_DONE; -} - -static inline int switchdev_port_bridge_getlink(struct sk_buff *skb, u32 pid, - u32 seq, struct net_device *dev, - u32 filter_mask, int nlflags) -{ - return -EOPNOTSUPP; -} - -static inline int switchdev_port_bridge_setlink(struct net_device *dev, - struct nlmsghdr *nlh, - u16 flags) -{ - return -EOPNOTSUPP; -} - -static inline int switchdev_port_bridge_dellink(struct net_device *dev, - struct nlmsghdr *nlh, - u16 flags) -{ - return -EOPNOTSUPP; -} - -static inline int switchdev_port_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], - struct net_device *dev, - const unsigned char *addr, - u16 vid, u16 nlm_flags) -{ - return -EOPNOTSUPP; -} - -static inline int switchdev_port_fdb_del(struct ndmsg *ndm, struct nlattr *tb[], - struct net_device *dev, - const unsigned char *addr, u16 vid) -{ - return -EOPNOTSUPP; -} - -static inline int switchdev_port_fdb_dump(struct sk_buff *skb, - struct netlink_callback *cb, - struct net_device *dev, - struct net_device *filter_dev, - int *idx) -{ - return *idx; -} - -static inline bool switchdev_port_same_parent_id(struct net_device *a, - struct net_device *b) -{ - return false; -} - -#endif - -#endif /* _LINUX_SWITCHDEV_H_ */ diff --git a/src/linux/include/net/tcp.h b/src/linux/include/net/tcp.h deleted file mode 100644 index 123979f..0000000 --- a/src/linux/include/net/tcp.h +++ /dev/null @@ -1,1938 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the TCP module. - * - * Version: @(#)tcp.h 1.0.5 05/23/93 - * - * Authors: Ross Biro - * Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _TCP_H -#define _TCP_H - -#define FASTRETRANS_DEBUG 1 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -extern struct inet_hashinfo tcp_hashinfo; - -extern struct percpu_counter tcp_orphan_count; -void tcp_time_wait(struct sock *sk, int state, int timeo); - -#define MAX_TCP_HEADER (128 + MAX_HEADER) -#define MAX_TCP_OPTION_SPACE 40 - -/* - * Never offer a window over 32767 without using window scaling. Some - * poor stacks do signed 16bit maths! - */ -#define MAX_TCP_WINDOW 32767U - -/* Minimal accepted MSS. It is (60+60+8) - (20+20). */ -#define TCP_MIN_MSS 88U - -/* The least MTU to use for probing */ -#define TCP_BASE_MSS 1024 - -/* probing interval, default to 10 minutes as per RFC4821 */ -#define TCP_PROBE_INTERVAL 600 - -/* Specify interval when tcp mtu probing will stop */ -#define TCP_PROBE_THRESHOLD 8 - -/* After receiving this amount of duplicate ACKs fast retransmit starts. */ -#define TCP_FASTRETRANS_THRESH 3 - -/* Maximal number of ACKs sent quickly to accelerate slow-start. */ -#define TCP_MAX_QUICKACKS 16U - -/* urg_data states */ -#define TCP_URG_VALID 0x0100 -#define TCP_URG_NOTYET 0x0200 -#define TCP_URG_READ 0x0400 - -#define TCP_RETR1 3 /* - * This is how many retries it does before it - * tries to figure out if the gateway is - * down. Minimal RFC value is 3; it corresponds - * to ~3sec-8min depending on RTO. - */ - -#define TCP_RETR2 15 /* - * This should take at least - * 90 minutes to time out. - * RFC1122 says that the limit is 100 sec. - * 15 is ~13-30min depending on RTO. - */ - -#define TCP_SYN_RETRIES 6 /* This is how many retries are done - * when active opening a connection. - * RFC1122 says the minimum retry MUST - * be at least 180secs. Nevertheless - * this value is corresponding to - * 63secs of retransmission with the - * current initial RTO. - */ - -#define TCP_SYNACK_RETRIES 5 /* This is how may retries are done - * when passive opening a connection. - * This is corresponding to 31secs of - * retransmission with the current - * initial RTO. - */ - -#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT - * state, about 60 seconds */ -#define TCP_FIN_TIMEOUT TCP_TIMEWAIT_LEN - /* BSD style FIN_WAIT2 deadlock breaker. - * It used to be 3min, new value is 60sec, - * to combine FIN-WAIT-2 timeout with - * TIME-WAIT timer. - */ - -#define TCP_DELACK_MAX ((unsigned)(HZ/5)) /* maximal time to delay before sending an ACK */ -#if HZ >= 100 -#define TCP_DELACK_MIN ((unsigned)(HZ/25)) /* minimal time to delay before sending an ACK */ -#define TCP_ATO_MIN ((unsigned)(HZ/25)) -#else -#define TCP_DELACK_MIN 4U -#define TCP_ATO_MIN 4U -#endif -#define TCP_RTO_MAX ((unsigned)(120*HZ)) -#define TCP_RTO_MIN ((unsigned)(HZ/5)) -#define TCP_TIMEOUT_INIT ((unsigned)(1*HZ)) /* RFC6298 2.1 initial RTO value */ -#define TCP_TIMEOUT_FALLBACK ((unsigned)(3*HZ)) /* RFC 1122 initial RTO value, now - * used as a fallback RTO for the - * initial data transmission if no - * valid RTT sample has been acquired, - * most likely due to retrans in 3WHS. - */ - -#define TCP_RESOURCE_PROBE_INTERVAL ((unsigned)(HZ/2U)) /* Maximal interval between probes - * for local resources. - */ - -#define TCP_KEEPALIVE_TIME (120*60*HZ) /* two hours */ -#define TCP_KEEPALIVE_PROBES 9 /* Max of 9 keepalive probes */ -#define TCP_KEEPALIVE_INTVL (75*HZ) - -#define MAX_TCP_KEEPIDLE 32767 -#define MAX_TCP_KEEPINTVL 32767 -#define MAX_TCP_KEEPCNT 127 -#define MAX_TCP_SYNCNT 127 - -#define TCP_SYNQ_INTERVAL (HZ/5) /* Period of SYNACK timer */ - -#define TCP_PAWS_24DAYS (60 * 60 * 24 * 24) -#define TCP_PAWS_MSL 60 /* Per-host timestamps are invalidated - * after this time. It should be equal - * (or greater than) TCP_TIMEWAIT_LEN - * to provide reliability equal to one - * provided by timewait state. - */ -#define TCP_PAWS_WINDOW 1 /* Replay window for per-host - * timestamps. It must be less than - * minimal timewait lifetime. - */ -/* - * TCP option - */ - -#define TCPOPT_NOP 1 /* Padding */ -#define TCPOPT_EOL 0 /* End of options */ -#define TCPOPT_MSS 2 /* Segment size negotiating */ -#define TCPOPT_WINDOW 3 /* Window scaling */ -#define TCPOPT_SACK_PERM 4 /* SACK Permitted */ -#define TCPOPT_SACK 5 /* SACK Block */ -#define TCPOPT_TIMESTAMP 8 /* Better RTT estimations/PAWS */ -#define TCPOPT_MD5SIG 19 /* MD5 Signature (RFC2385) */ -#define TCPOPT_FASTOPEN 34 /* Fast open (RFC7413) */ -#define TCPOPT_EXP 254 /* Experimental */ -/* Magic number to be after the option value for sharing TCP - * experimental options. See draft-ietf-tcpm-experimental-options-00.txt - */ -#define TCPOPT_FASTOPEN_MAGIC 0xF989 - -/* - * TCP option lengths - */ - -#define TCPOLEN_MSS 4 -#define TCPOLEN_WINDOW 3 -#define TCPOLEN_SACK_PERM 2 -#define TCPOLEN_TIMESTAMP 10 -#define TCPOLEN_MD5SIG 18 -#define TCPOLEN_FASTOPEN_BASE 2 -#define TCPOLEN_EXP_FASTOPEN_BASE 4 - -/* But this is what stacks really send out. */ -#define TCPOLEN_TSTAMP_ALIGNED 12 -#define TCPOLEN_WSCALE_ALIGNED 4 -#define TCPOLEN_SACKPERM_ALIGNED 4 -#define TCPOLEN_SACK_BASE 2 -#define TCPOLEN_SACK_BASE_ALIGNED 4 -#define TCPOLEN_SACK_PERBLOCK 8 -#define TCPOLEN_MD5SIG_ALIGNED 20 -#define TCPOLEN_MSS_ALIGNED 4 - -/* Flags in tp->nonagle */ -#define TCP_NAGLE_OFF 1 /* Nagle's algo is disabled */ -#define TCP_NAGLE_CORK 2 /* Socket is corked */ -#define TCP_NAGLE_PUSH 4 /* Cork is overridden for already queued data */ - -/* TCP thin-stream limits */ -#define TCP_THIN_LINEAR_RETRIES 6 /* After 6 linear retries, do exp. backoff */ - -/* TCP initial congestion window as per rfc6928 */ -#define TCP_INIT_CWND 10 - -/* Bit Flags for sysctl_tcp_fastopen */ -#define TFO_CLIENT_ENABLE 1 -#define TFO_SERVER_ENABLE 2 -#define TFO_CLIENT_NO_COOKIE 4 /* Data in SYN w/o cookie option */ - -/* Accept SYN data w/o any cookie option */ -#define TFO_SERVER_COOKIE_NOT_REQD 0x200 - -/* Force enable TFO on all listeners, i.e., not requiring the - * TCP_FASTOPEN socket option. - */ -#define TFO_SERVER_WO_SOCKOPT1 0x400 - -extern struct inet_timewait_death_row tcp_death_row; - -/* sysctl variables for tcp */ -extern int sysctl_tcp_timestamps; -extern int sysctl_tcp_window_scaling; -extern int sysctl_tcp_sack; -extern int sysctl_tcp_fastopen; -extern int sysctl_tcp_retrans_collapse; -extern int sysctl_tcp_stdurg; -extern int sysctl_tcp_rfc1337; -extern int sysctl_tcp_abort_on_overflow; -extern int sysctl_tcp_max_orphans; -extern int sysctl_tcp_fack; -extern int sysctl_tcp_reordering; -extern int sysctl_tcp_max_reordering; -extern int sysctl_tcp_dsack; -extern long sysctl_tcp_mem[3]; -extern int sysctl_tcp_wmem[3]; -extern int sysctl_tcp_rmem[3]; -extern int sysctl_tcp_app_win; -extern int sysctl_tcp_adv_win_scale; -extern int sysctl_tcp_tw_reuse; -extern int sysctl_tcp_frto; -extern int sysctl_tcp_low_latency; -extern int sysctl_tcp_nometrics_save; -extern int sysctl_tcp_moderate_rcvbuf; -extern int sysctl_tcp_tso_win_divisor; -extern int sysctl_tcp_workaround_signed_windows; -extern int sysctl_tcp_slow_start_after_idle; -extern int sysctl_tcp_thin_linear_timeouts; -extern int sysctl_tcp_thin_dupack; -extern int sysctl_tcp_early_retrans; -extern int sysctl_tcp_limit_output_bytes; -extern int sysctl_tcp_challenge_ack_limit; -extern int sysctl_tcp_min_tso_segs; -extern int sysctl_tcp_min_rtt_wlen; -extern int sysctl_tcp_autocorking; -extern int sysctl_tcp_invalid_ratelimit; -extern int sysctl_tcp_pacing_ss_ratio; -extern int sysctl_tcp_pacing_ca_ratio; - -extern atomic_long_t tcp_memory_allocated; -extern struct percpu_counter tcp_sockets_allocated; -extern int tcp_memory_pressure; - -/* optimized version of sk_under_memory_pressure() for TCP sockets */ -static inline bool tcp_under_memory_pressure(const struct sock *sk) -{ - if (mem_cgroup_sockets_enabled && sk->sk_memcg && - mem_cgroup_under_socket_pressure(sk->sk_memcg)) - return true; - - return tcp_memory_pressure; -} -/* - * The next routines deal with comparing 32 bit unsigned ints - * and worry about wraparound (automatic with unsigned arithmetic). - */ - -static inline bool before(__u32 seq1, __u32 seq2) -{ - return (__s32)(seq1-seq2) < 0; -} -#define after(seq2, seq1) before(seq1, seq2) - -/* is s2<=s1<=s3 ? */ -static inline bool between(__u32 seq1, __u32 seq2, __u32 seq3) -{ - return seq3 - seq2 >= seq1 - seq2; -} - -static inline bool tcp_out_of_memory(struct sock *sk) -{ - if (sk->sk_wmem_queued > SOCK_MIN_SNDBUF && - sk_memory_allocated(sk) > sk_prot_mem_limits(sk, 2)) - return true; - return false; -} - -void sk_forced_mem_schedule(struct sock *sk, int size); - -static inline bool tcp_too_many_orphans(struct sock *sk, int shift) -{ - struct percpu_counter *ocp = sk->sk_prot->orphan_count; - int orphans = percpu_counter_read_positive(ocp); - - if (orphans << shift > sysctl_tcp_max_orphans) { - orphans = percpu_counter_sum_positive(ocp); - if (orphans << shift > sysctl_tcp_max_orphans) - return true; - } - return false; -} - -bool tcp_check_oom(struct sock *sk, int shift); - - -extern struct proto tcp_prot; - -#define TCP_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.tcp_statistics, field) -#define __TCP_INC_STATS(net, field) __SNMP_INC_STATS((net)->mib.tcp_statistics, field) -#define TCP_DEC_STATS(net, field) SNMP_DEC_STATS((net)->mib.tcp_statistics, field) -#define TCP_ADD_STATS(net, field, val) SNMP_ADD_STATS((net)->mib.tcp_statistics, field, val) - -void tcp_tasklet_init(void); - -void tcp_v4_err(struct sk_buff *skb, u32); - -void tcp_shutdown(struct sock *sk, int how); - -void tcp_v4_early_demux(struct sk_buff *skb); -int tcp_v4_rcv(struct sk_buff *skb); - -int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw); -int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); -int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size, - int flags); -void tcp_release_cb(struct sock *sk); -void tcp_wfree(struct sk_buff *skb); -void tcp_write_timer_handler(struct sock *sk); -void tcp_delack_timer_handler(struct sock *sk); -int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg); -int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb); -void tcp_rcv_established(struct sock *sk, struct sk_buff *skb, - const struct tcphdr *th, unsigned int len); -void tcp_rcv_space_adjust(struct sock *sk); -int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp); -void tcp_twsk_destructor(struct sock *sk); -ssize_t tcp_splice_read(struct socket *sk, loff_t *ppos, - struct pipe_inode_info *pipe, size_t len, - unsigned int flags); - -static inline void tcp_dec_quickack_mode(struct sock *sk, - const unsigned int pkts) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - - if (icsk->icsk_ack.quick) { - if (pkts >= icsk->icsk_ack.quick) { - icsk->icsk_ack.quick = 0; - /* Leaving quickack mode we deflate ATO. */ - icsk->icsk_ack.ato = TCP_ATO_MIN; - } else - icsk->icsk_ack.quick -= pkts; - } -} - -#define TCP_ECN_OK 1 -#define TCP_ECN_QUEUE_CWR 2 -#define TCP_ECN_DEMAND_CWR 4 -#define TCP_ECN_SEEN 8 - -enum tcp_tw_status { - TCP_TW_SUCCESS = 0, - TCP_TW_RST = 1, - TCP_TW_ACK = 2, - TCP_TW_SYN = 3 -}; - - -enum tcp_tw_status tcp_timewait_state_process(struct inet_timewait_sock *tw, - struct sk_buff *skb, - const struct tcphdr *th); -struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, - struct request_sock *req, bool fastopen); -int tcp_child_process(struct sock *parent, struct sock *child, - struct sk_buff *skb); -void tcp_enter_loss(struct sock *sk); -void tcp_clear_retrans(struct tcp_sock *tp); -void tcp_update_metrics(struct sock *sk); -void tcp_init_metrics(struct sock *sk); -void tcp_metrics_init(void); -bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst, - bool paws_check, bool timestamps); -bool tcp_remember_stamp(struct sock *sk); -bool tcp_tw_remember_stamp(struct inet_timewait_sock *tw); -void tcp_fetch_timewait_stamp(struct sock *sk, struct dst_entry *dst); -void tcp_disable_fack(struct tcp_sock *tp); -void tcp_close(struct sock *sk, long timeout); -void tcp_init_sock(struct sock *sk); -unsigned int tcp_poll(struct file *file, struct socket *sock, - struct poll_table_struct *wait); -int tcp_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen); -int tcp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen); -int compat_tcp_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen); -int compat_tcp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen); -void tcp_set_keepalive(struct sock *sk, int val); -void tcp_syn_ack_timeout(const struct request_sock *req); -int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock, - int flags, int *addr_len); -void tcp_parse_options(const struct sk_buff *skb, - struct tcp_options_received *opt_rx, - int estab, struct tcp_fastopen_cookie *foc); -const u8 *tcp_parse_md5sig_option(const struct tcphdr *th); - -/* - * TCP v4 functions exported for the inet6 API - */ - -void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb); -void tcp_v4_mtu_reduced(struct sock *sk); -void tcp_req_err(struct sock *sk, u32 seq, bool abort); -int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb); -struct sock *tcp_create_openreq_child(const struct sock *sk, - struct request_sock *req, - struct sk_buff *skb); -void tcp_ca_openreq_child(struct sock *sk, const struct dst_entry *dst); -struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, - struct request_sock *req, - struct dst_entry *dst, - struct request_sock *req_unhash, - bool *own_req); -int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb); -int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); -int tcp_connect(struct sock *sk); -enum tcp_synack_type { - TCP_SYNACK_NORMAL, - TCP_SYNACK_FASTOPEN, - TCP_SYNACK_COOKIE, -}; -struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, - struct request_sock *req, - struct tcp_fastopen_cookie *foc, - enum tcp_synack_type synack_type); -int tcp_disconnect(struct sock *sk, int flags); - -void tcp_finish_connect(struct sock *sk, struct sk_buff *skb); -int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size); -void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb); - -/* From syncookies.c */ -struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb, - struct request_sock *req, - struct dst_entry *dst); -int __cookie_v4_check(const struct iphdr *iph, const struct tcphdr *th, - u32 cookie); -struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb); -#ifdef CONFIG_SYN_COOKIES - -/* Syncookies use a monotonic timer which increments every 60 seconds. - * This counter is used both as a hash input and partially encoded into - * the cookie value. A cookie is only validated further if the delta - * between the current counter value and the encoded one is less than this, - * i.e. a sent cookie is valid only at most for 2*60 seconds (or less if - * the counter advances immediately after a cookie is generated). - */ -#define MAX_SYNCOOKIE_AGE 2 -#define TCP_SYNCOOKIE_PERIOD (60 * HZ) -#define TCP_SYNCOOKIE_VALID (MAX_SYNCOOKIE_AGE * TCP_SYNCOOKIE_PERIOD) - -/* syncookies: remember time of last synqueue overflow - * But do not dirty this field too often (once per second is enough) - * It is racy as we do not hold a lock, but race is very minor. - */ -static inline void tcp_synq_overflow(const struct sock *sk) -{ - unsigned long last_overflow = tcp_sk(sk)->rx_opt.ts_recent_stamp; - unsigned long now = jiffies; - - if (time_after(now, last_overflow + HZ)) - tcp_sk(sk)->rx_opt.ts_recent_stamp = now; -} - -/* syncookies: no recent synqueue overflow on this listening socket? */ -static inline bool tcp_synq_no_recent_overflow(const struct sock *sk) -{ - unsigned long last_overflow = tcp_sk(sk)->rx_opt.ts_recent_stamp; - - return time_after(jiffies, last_overflow + TCP_SYNCOOKIE_VALID); -} - -static inline u32 tcp_cookie_time(void) -{ - u64 val = get_jiffies_64(); - - do_div(val, TCP_SYNCOOKIE_PERIOD); - return val; -} - -u32 __cookie_v4_init_sequence(const struct iphdr *iph, const struct tcphdr *th, - u16 *mssp); -__u32 cookie_v4_init_sequence(const struct sk_buff *skb, __u16 *mss); -__u32 cookie_init_timestamp(struct request_sock *req); -bool cookie_timestamp_decode(struct tcp_options_received *opt); -bool cookie_ecn_ok(const struct tcp_options_received *opt, - const struct net *net, const struct dst_entry *dst); - -/* From net/ipv6/syncookies.c */ -int __cookie_v6_check(const struct ipv6hdr *iph, const struct tcphdr *th, - u32 cookie); -struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb); - -u32 __cookie_v6_init_sequence(const struct ipv6hdr *iph, - const struct tcphdr *th, u16 *mssp); -__u32 cookie_v6_init_sequence(const struct sk_buff *skb, __u16 *mss); -#endif -/* tcp_output.c */ - -u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now, - int min_tso_segs); -void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss, - int nonagle); -bool tcp_may_send_now(struct sock *sk); -int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs); -int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs); -void tcp_retransmit_timer(struct sock *sk); -void tcp_xmit_retransmit_queue(struct sock *); -void tcp_simple_retransmit(struct sock *); -int tcp_trim_head(struct sock *, struct sk_buff *, u32); -int tcp_fragment(struct sock *, struct sk_buff *, u32, unsigned int, gfp_t); - -void tcp_send_probe0(struct sock *); -void tcp_send_partial(struct sock *); -int tcp_write_wakeup(struct sock *, int mib); -void tcp_send_fin(struct sock *sk); -void tcp_send_active_reset(struct sock *sk, gfp_t priority); -int tcp_send_synack(struct sock *); -void tcp_push_one(struct sock *, unsigned int mss_now); -void tcp_send_ack(struct sock *sk); -void tcp_send_delayed_ack(struct sock *sk); -void tcp_send_loss_probe(struct sock *sk); -bool tcp_schedule_loss_probe(struct sock *sk); -void tcp_skb_collapse_tstamp(struct sk_buff *skb, - const struct sk_buff *next_skb); - -/* tcp_input.c */ -void tcp_resume_early_retransmit(struct sock *sk); -void tcp_rearm_rto(struct sock *sk); -void tcp_synack_rtt_meas(struct sock *sk, struct request_sock *req); -void tcp_reset(struct sock *sk); -void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp, struct sk_buff *skb); -void tcp_fin(struct sock *sk); - -/* tcp_timer.c */ -void tcp_init_xmit_timers(struct sock *); -static inline void tcp_clear_xmit_timers(struct sock *sk) -{ - inet_csk_clear_xmit_timers(sk); -} - -unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu); -unsigned int tcp_current_mss(struct sock *sk); - -/* Bound MSS / TSO packet size with the half of the window */ -static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize) -{ - int cutoff; - - /* When peer uses tiny windows, there is no use in packetizing - * to sub-MSS pieces for the sake of SWS or making sure there - * are enough packets in the pipe for fast recovery. - * - * On the other hand, for extremely large MSS devices, handling - * smaller than MSS windows in this way does make sense. - */ - if (tp->max_window > TCP_MSS_DEFAULT) - cutoff = (tp->max_window >> 1); - else - cutoff = tp->max_window; - - if (cutoff && pktsize > cutoff) - return max_t(int, cutoff, 68U - tp->tcp_header_len); - else - return pktsize; -} - -/* tcp.c */ -void tcp_get_info(struct sock *, struct tcp_info *); - -/* Read 'sendfile()'-style from a TCP socket */ -int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor); - -void tcp_initialize_rcv_mss(struct sock *sk); - -int tcp_mtu_to_mss(struct sock *sk, int pmtu); -int tcp_mss_to_mtu(struct sock *sk, int mss); -void tcp_mtup_init(struct sock *sk); -void tcp_init_buffer_space(struct sock *sk); - -static inline void tcp_bound_rto(const struct sock *sk) -{ - if (inet_csk(sk)->icsk_rto > TCP_RTO_MAX) - inet_csk(sk)->icsk_rto = TCP_RTO_MAX; -} - -static inline u32 __tcp_set_rto(const struct tcp_sock *tp) -{ - return usecs_to_jiffies((tp->srtt_us >> 3) + tp->rttvar_us); -} - -static inline void __tcp_fast_path_on(struct tcp_sock *tp, u32 snd_wnd) -{ - tp->pred_flags = htonl((tp->tcp_header_len << 26) | - ntohl(TCP_FLAG_ACK) | - snd_wnd); -} - -static inline void tcp_fast_path_on(struct tcp_sock *tp) -{ - __tcp_fast_path_on(tp, tp->snd_wnd >> tp->rx_opt.snd_wscale); -} - -static inline void tcp_fast_path_check(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (RB_EMPTY_ROOT(&tp->out_of_order_queue) && - tp->rcv_wnd && - atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf && - !tp->urg_data) - tcp_fast_path_on(tp); -} - -/* Compute the actual rto_min value */ -static inline u32 tcp_rto_min(struct sock *sk) -{ - const struct dst_entry *dst = __sk_dst_get(sk); - u32 rto_min = TCP_RTO_MIN; - - if (dst && dst_metric_locked(dst, RTAX_RTO_MIN)) - rto_min = dst_metric_rtt(dst, RTAX_RTO_MIN); - return rto_min; -} - -static inline u32 tcp_rto_min_us(struct sock *sk) -{ - return jiffies_to_usecs(tcp_rto_min(sk)); -} - -static inline bool tcp_ca_dst_locked(const struct dst_entry *dst) -{ - return dst_metric_locked(dst, RTAX_CC_ALGO); -} - -/* Minimum RTT in usec. ~0 means not available. */ -static inline u32 tcp_min_rtt(const struct tcp_sock *tp) -{ - return minmax_get(&tp->rtt_min); -} - -/* Compute the actual receive window we are currently advertising. - * Rcv_nxt can be after the window if our peer push more data - * than the offered window. - */ -static inline u32 tcp_receive_window(const struct tcp_sock *tp) -{ - s32 win = tp->rcv_wup + tp->rcv_wnd - tp->rcv_nxt; - - if (win < 0) - win = 0; - return (u32) win; -} - -/* Choose a new window, without checks for shrinking, and without - * scaling applied to the result. The caller does these things - * if necessary. This is a "raw" window selection. - */ -u32 __tcp_select_window(struct sock *sk); - -void tcp_send_window_probe(struct sock *sk); - -/* TCP timestamps are only 32-bits, this causes a slight - * complication on 64-bit systems since we store a snapshot - * of jiffies in the buffer control blocks below. We decided - * to use only the low 32-bits of jiffies and hide the ugly - * casts with the following macro. - */ -#define tcp_time_stamp ((__u32)(jiffies)) - -static inline u32 tcp_skb_timestamp(const struct sk_buff *skb) -{ - return skb->skb_mstamp.stamp_jiffies; -} - - -#define tcp_flag_byte(th) (((u_int8_t *)th)[13]) - -#define TCPHDR_FIN 0x01 -#define TCPHDR_SYN 0x02 -#define TCPHDR_RST 0x04 -#define TCPHDR_PSH 0x08 -#define TCPHDR_ACK 0x10 -#define TCPHDR_URG 0x20 -#define TCPHDR_ECE 0x40 -#define TCPHDR_CWR 0x80 - -#define TCPHDR_SYN_ECN (TCPHDR_SYN | TCPHDR_ECE | TCPHDR_CWR) - -/* This is what the send packet queuing engine uses to pass - * TCP per-packet control information to the transmission code. - * We also store the host-order sequence numbers in here too. - * This is 44 bytes if IPV6 is enabled. - * If this grows please adjust skbuff.h:skbuff->cb[xxx] size appropriately. - */ -struct tcp_skb_cb { - __u32 seq; /* Starting sequence number */ - __u32 end_seq; /* SEQ + FIN + SYN + datalen */ - union { - /* Note : tcp_tw_isn is used in input path only - * (isn chosen by tcp_timewait_state_process()) - * - * tcp_gso_segs/size are used in write queue only, - * cf tcp_skb_pcount()/tcp_skb_mss() - */ - __u32 tcp_tw_isn; - struct { - u16 tcp_gso_segs; - u16 tcp_gso_size; - }; - }; - __u8 tcp_flags; /* TCP header flags. (tcp[13]) */ - - __u8 sacked; /* State flags for SACK/FACK. */ -#define TCPCB_SACKED_ACKED 0x01 /* SKB ACK'd by a SACK block */ -#define TCPCB_SACKED_RETRANS 0x02 /* SKB retransmitted */ -#define TCPCB_LOST 0x04 /* SKB is lost */ -#define TCPCB_TAGBITS 0x07 /* All tag bits */ -#define TCPCB_REPAIRED 0x10 /* SKB repaired (no skb_mstamp) */ -#define TCPCB_EVER_RETRANS 0x80 /* Ever retransmitted frame */ -#define TCPCB_RETRANS (TCPCB_SACKED_RETRANS|TCPCB_EVER_RETRANS| \ - TCPCB_REPAIRED) - - __u8 ip_dsfield; /* IPv4 tos or IPv6 dsfield */ - __u8 txstamp_ack:1, /* Record TX timestamp for ack? */ - eor:1, /* Is skb MSG_EOR marked? */ - unused:6; - __u32 ack_seq; /* Sequence number ACK'd */ - union { - struct { - /* There is space for up to 24 bytes */ - __u32 in_flight:30,/* Bytes in flight at transmit */ - is_app_limited:1, /* cwnd not fully used? */ - unused:1; - /* pkts S/ACKed so far upon tx of skb, incl retrans: */ - __u32 delivered; - /* start of send pipeline phase */ - struct skb_mstamp first_tx_mstamp; - /* when we reached the "delivered" count */ - struct skb_mstamp delivered_mstamp; - } tx; /* only used for outgoing skbs */ - union { - struct inet_skb_parm h4; -#if IS_ENABLED(CONFIG_IPV6) - struct inet6_skb_parm h6; -#endif - } header; /* For incoming skbs */ - }; -}; - -#define TCP_SKB_CB(__skb) ((struct tcp_skb_cb *)&((__skb)->cb[0])) - - -#if IS_ENABLED(CONFIG_IPV6) -/* This is the variant of inet6_iif() that must be used by TCP, - * as TCP moves IP6CB into a different location in skb->cb[] - */ -static inline int tcp_v6_iif(const struct sk_buff *skb) -{ - bool l3_slave = ipv6_l3mdev_skb(TCP_SKB_CB(skb)->header.h6.flags); - - return l3_slave ? skb->skb_iif : TCP_SKB_CB(skb)->header.h6.iif; -} -#endif - -/* TCP_SKB_CB reference means this can not be used from early demux */ -static inline bool inet_exact_dif_match(struct net *net, struct sk_buff *skb) -{ -#if IS_ENABLED(CONFIG_NET_L3_MASTER_DEV) - if (!net->ipv4.sysctl_tcp_l3mdev_accept && - skb && ipv4_l3mdev_skb(TCP_SKB_CB(skb)->header.h4.flags)) - return true; -#endif - return false; -} - -/* Due to TSO, an SKB can be composed of multiple actual - * packets. To keep these tracked properly, we use this. - */ -static inline int tcp_skb_pcount(const struct sk_buff *skb) -{ - return TCP_SKB_CB(skb)->tcp_gso_segs; -} - -static inline void tcp_skb_pcount_set(struct sk_buff *skb, int segs) -{ - TCP_SKB_CB(skb)->tcp_gso_segs = segs; -} - -static inline void tcp_skb_pcount_add(struct sk_buff *skb, int segs) -{ - TCP_SKB_CB(skb)->tcp_gso_segs += segs; -} - -/* This is valid iff skb is in write queue and tcp_skb_pcount() > 1. */ -static inline int tcp_skb_mss(const struct sk_buff *skb) -{ - return TCP_SKB_CB(skb)->tcp_gso_size; -} - -static inline bool tcp_skb_can_collapse_to(const struct sk_buff *skb) -{ - return likely(!TCP_SKB_CB(skb)->eor); -} - -/* Events passed to congestion control interface */ -enum tcp_ca_event { - CA_EVENT_TX_START, /* first transmit when no packets in flight */ - CA_EVENT_CWND_RESTART, /* congestion window restart */ - CA_EVENT_COMPLETE_CWR, /* end of congestion recovery */ - CA_EVENT_LOSS, /* loss timeout */ - CA_EVENT_ECN_NO_CE, /* ECT set, but not CE marked */ - CA_EVENT_ECN_IS_CE, /* received CE marked IP packet */ - CA_EVENT_DELAYED_ACK, /* Delayed ack is sent */ - CA_EVENT_NON_DELAYED_ACK, -}; - -/* Information about inbound ACK, passed to cong_ops->in_ack_event() */ -enum tcp_ca_ack_event_flags { - CA_ACK_SLOWPATH = (1 << 0), /* In slow path processing */ - CA_ACK_WIN_UPDATE = (1 << 1), /* ACK updated window */ - CA_ACK_ECE = (1 << 2), /* ECE bit is set on ack */ -}; - -/* - * Interface for adding new TCP congestion control handlers - */ -#define TCP_CA_NAME_MAX 16 -#define TCP_CA_MAX 128 -#define TCP_CA_BUF_MAX (TCP_CA_NAME_MAX*TCP_CA_MAX) - -#define TCP_CA_UNSPEC 0 - -/* Algorithm can be set on socket without CAP_NET_ADMIN privileges */ -#define TCP_CONG_NON_RESTRICTED 0x1 -/* Requires ECN/ECT set on all packets */ -#define TCP_CONG_NEEDS_ECN 0x2 - -union tcp_cc_info; - -struct ack_sample { - u32 pkts_acked; - s32 rtt_us; - u32 in_flight; -}; - -/* A rate sample measures the number of (original/retransmitted) data - * packets delivered "delivered" over an interval of time "interval_us". - * The tcp_rate.c code fills in the rate sample, and congestion - * control modules that define a cong_control function to run at the end - * of ACK processing can optionally chose to consult this sample when - * setting cwnd and pacing rate. - * A sample is invalid if "delivered" or "interval_us" is negative. - */ -struct rate_sample { - struct skb_mstamp prior_mstamp; /* starting timestamp for interval */ - u32 prior_delivered; /* tp->delivered at "prior_mstamp" */ - s32 delivered; /* number of packets delivered over interval */ - long interval_us; /* time for tp->delivered to incr "delivered" */ - long rtt_us; /* RTT of last (S)ACKed packet (or -1) */ - int losses; /* number of packets marked lost upon ACK */ - u32 acked_sacked; /* number of packets newly (S)ACKed upon ACK */ - u32 prior_in_flight; /* in flight before this ACK */ - bool is_app_limited; /* is sample from packet with bubble in pipe? */ - bool is_retrans; /* is sample from retransmission? */ -}; - -struct tcp_congestion_ops { - struct list_head list; - u32 key; - u32 flags; - - /* initialize private data (optional) */ - void (*init)(struct sock *sk); - /* cleanup private data (optional) */ - void (*release)(struct sock *sk); - - /* return slow start threshold (required) */ - u32 (*ssthresh)(struct sock *sk); - /* do new cwnd calculation (required) */ - void (*cong_avoid)(struct sock *sk, u32 ack, u32 acked); - /* call before changing ca_state (optional) */ - void (*set_state)(struct sock *sk, u8 new_state); - /* call when cwnd event occurs (optional) */ - void (*cwnd_event)(struct sock *sk, enum tcp_ca_event ev); - /* call when ack arrives (optional) */ - void (*in_ack_event)(struct sock *sk, u32 flags); - /* new value of cwnd after loss (optional) */ - u32 (*undo_cwnd)(struct sock *sk); - /* hook for packet ack accounting (optional) */ - void (*pkts_acked)(struct sock *sk, const struct ack_sample *sample); - /* suggest number of segments for each skb to transmit (optional) */ - u32 (*tso_segs_goal)(struct sock *sk); - /* returns the multiplier used in tcp_sndbuf_expand (optional) */ - u32 (*sndbuf_expand)(struct sock *sk); - /* call when packets are delivered to update cwnd and pacing rate, - * after all the ca_state processing. (optional) - */ - void (*cong_control)(struct sock *sk, const struct rate_sample *rs); - /* get info for inet_diag (optional) */ - size_t (*get_info)(struct sock *sk, u32 ext, int *attr, - union tcp_cc_info *info); - - char name[TCP_CA_NAME_MAX]; - struct module *owner; -}; - -int tcp_register_congestion_control(struct tcp_congestion_ops *type); -void tcp_unregister_congestion_control(struct tcp_congestion_ops *type); - -void tcp_assign_congestion_control(struct sock *sk); -void tcp_init_congestion_control(struct sock *sk); -void tcp_cleanup_congestion_control(struct sock *sk); -int tcp_set_default_congestion_control(const char *name); -void tcp_get_default_congestion_control(char *name); -void tcp_get_available_congestion_control(char *buf, size_t len); -void tcp_get_allowed_congestion_control(char *buf, size_t len); -int tcp_set_allowed_congestion_control(char *allowed); -int tcp_set_congestion_control(struct sock *sk, const char *name); -u32 tcp_slow_start(struct tcp_sock *tp, u32 acked); -void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w, u32 acked); - -u32 tcp_reno_ssthresh(struct sock *sk); -void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 acked); -extern struct tcp_congestion_ops tcp_reno; - -struct tcp_congestion_ops *tcp_ca_find_key(u32 key); -u32 tcp_ca_get_key_by_name(const char *name, bool *ecn_ca); -#ifdef CONFIG_INET -char *tcp_ca_get_name_by_key(u32 key, char *buffer); -#else -static inline char *tcp_ca_get_name_by_key(u32 key, char *buffer) -{ - return NULL; -} -#endif - -static inline bool tcp_ca_needs_ecn(const struct sock *sk) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - - return icsk->icsk_ca_ops->flags & TCP_CONG_NEEDS_ECN; -} - -static inline void tcp_set_ca_state(struct sock *sk, const u8 ca_state) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - - if (icsk->icsk_ca_ops->set_state) - icsk->icsk_ca_ops->set_state(sk, ca_state); - icsk->icsk_ca_state = ca_state; -} - -static inline void tcp_ca_event(struct sock *sk, const enum tcp_ca_event event) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - - if (icsk->icsk_ca_ops->cwnd_event) - icsk->icsk_ca_ops->cwnd_event(sk, event); -} - -/* From tcp_rate.c */ -void tcp_rate_skb_sent(struct sock *sk, struct sk_buff *skb); -void tcp_rate_skb_delivered(struct sock *sk, struct sk_buff *skb, - struct rate_sample *rs); -void tcp_rate_gen(struct sock *sk, u32 delivered, u32 lost, - struct skb_mstamp *now, struct rate_sample *rs); -void tcp_rate_check_app_limited(struct sock *sk); - -/* These functions determine how the current flow behaves in respect of SACK - * handling. SACK is negotiated with the peer, and therefore it can vary - * between different flows. - * - * tcp_is_sack - SACK enabled - * tcp_is_reno - No SACK - * tcp_is_fack - FACK enabled, implies SACK enabled - */ -static inline int tcp_is_sack(const struct tcp_sock *tp) -{ - return tp->rx_opt.sack_ok; -} - -static inline bool tcp_is_reno(const struct tcp_sock *tp) -{ - return !tcp_is_sack(tp); -} - -static inline bool tcp_is_fack(const struct tcp_sock *tp) -{ - return tp->rx_opt.sack_ok & TCP_FACK_ENABLED; -} - -static inline void tcp_enable_fack(struct tcp_sock *tp) -{ - tp->rx_opt.sack_ok |= TCP_FACK_ENABLED; -} - -/* TCP early-retransmit (ER) is similar to but more conservative than - * the thin-dupack feature. Enable ER only if thin-dupack is disabled. - */ -static inline void tcp_enable_early_retrans(struct tcp_sock *tp) -{ - struct net *net = sock_net((struct sock *)tp); - - tp->do_early_retrans = sysctl_tcp_early_retrans && - sysctl_tcp_early_retrans < 4 && !sysctl_tcp_thin_dupack && - net->ipv4.sysctl_tcp_reordering == 3; -} - -static inline void tcp_disable_early_retrans(struct tcp_sock *tp) -{ - tp->do_early_retrans = 0; -} - -static inline unsigned int tcp_left_out(const struct tcp_sock *tp) -{ - return tp->sacked_out + tp->lost_out; -} - -/* This determines how many packets are "in the network" to the best - * of our knowledge. In many cases it is conservative, but where - * detailed information is available from the receiver (via SACK - * blocks etc.) we can make more aggressive calculations. - * - * Use this for decisions involving congestion control, use just - * tp->packets_out to determine if the send queue is empty or not. - * - * Read this equation as: - * - * "Packets sent once on transmission queue" MINUS - * "Packets left network, but not honestly ACKed yet" PLUS - * "Packets fast retransmitted" - */ -static inline unsigned int tcp_packets_in_flight(const struct tcp_sock *tp) -{ - return tp->packets_out - tcp_left_out(tp) + tp->retrans_out; -} - -#define TCP_INFINITE_SSTHRESH 0x7fffffff - -static inline bool tcp_in_slow_start(const struct tcp_sock *tp) -{ - return tp->snd_cwnd < tp->snd_ssthresh; -} - -static inline bool tcp_in_initial_slowstart(const struct tcp_sock *tp) -{ - return tp->snd_ssthresh >= TCP_INFINITE_SSTHRESH; -} - -static inline bool tcp_in_cwnd_reduction(const struct sock *sk) -{ - return (TCPF_CA_CWR | TCPF_CA_Recovery) & - (1 << inet_csk(sk)->icsk_ca_state); -} - -/* If cwnd > ssthresh, we may raise ssthresh to be half-way to cwnd. - * The exception is cwnd reduction phase, when cwnd is decreasing towards - * ssthresh. - */ -static inline __u32 tcp_current_ssthresh(const struct sock *sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - - if (tcp_in_cwnd_reduction(sk)) - return tp->snd_ssthresh; - else - return max(tp->snd_ssthresh, - ((tp->snd_cwnd >> 1) + - (tp->snd_cwnd >> 2))); -} - -/* Use define here intentionally to get WARN_ON location shown at the caller */ -#define tcp_verify_left_out(tp) WARN_ON(tcp_left_out(tp) > tp->packets_out) - -void tcp_enter_cwr(struct sock *sk); -__u32 tcp_init_cwnd(const struct tcp_sock *tp, const struct dst_entry *dst); - -/* The maximum number of MSS of available cwnd for which TSO defers - * sending if not using sysctl_tcp_tso_win_divisor. - */ -static inline __u32 tcp_max_tso_deferred_mss(const struct tcp_sock *tp) -{ - return 3; -} - -/* Returns end sequence number of the receiver's advertised window */ -static inline u32 tcp_wnd_end(const struct tcp_sock *tp) -{ - return tp->snd_una + tp->snd_wnd; -} - -/* We follow the spirit of RFC2861 to validate cwnd but implement a more - * flexible approach. The RFC suggests cwnd should not be raised unless - * it was fully used previously. And that's exactly what we do in - * congestion avoidance mode. But in slow start we allow cwnd to grow - * as long as the application has used half the cwnd. - * Example : - * cwnd is 10 (IW10), but application sends 9 frames. - * We allow cwnd to reach 18 when all frames are ACKed. - * This check is safe because it's as aggressive as slow start which already - * risks 100% overshoot. The advantage is that we discourage application to - * either send more filler packets or data to artificially blow up the cwnd - * usage, and allow application-limited process to probe bw more aggressively. - */ -static inline bool tcp_is_cwnd_limited(const struct sock *sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - - /* If in slow start, ensure cwnd grows to twice what was ACKed. */ - if (tcp_in_slow_start(tp)) - return tp->snd_cwnd < 2 * tp->max_packets_out; - - return tp->is_cwnd_limited; -} - -/* Something is really bad, we could not queue an additional packet, - * because qdisc is full or receiver sent a 0 window. - * We do not want to add fuel to the fire, or abort too early, - * so make sure the timer we arm now is at least 200ms in the future, - * regardless of current icsk_rto value (as it could be ~2ms) - */ -static inline unsigned long tcp_probe0_base(const struct sock *sk) -{ - return max_t(unsigned long, inet_csk(sk)->icsk_rto, TCP_RTO_MIN); -} - -/* Variant of inet_csk_rto_backoff() used for zero window probes */ -static inline unsigned long tcp_probe0_when(const struct sock *sk, - unsigned long max_when) -{ - u64 when = (u64)tcp_probe0_base(sk) << inet_csk(sk)->icsk_backoff; - - return (unsigned long)min_t(u64, when, max_when); -} - -static inline void tcp_check_probe_timer(struct sock *sk) -{ - if (!tcp_sk(sk)->packets_out && !inet_csk(sk)->icsk_pending) - inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0, - tcp_probe0_base(sk), TCP_RTO_MAX); -} - -static inline void tcp_init_wl(struct tcp_sock *tp, u32 seq) -{ - tp->snd_wl1 = seq; -} - -static inline void tcp_update_wl(struct tcp_sock *tp, u32 seq) -{ - tp->snd_wl1 = seq; -} - -/* - * Calculate(/check) TCP checksum - */ -static inline __sum16 tcp_v4_check(int len, __be32 saddr, - __be32 daddr, __wsum base) -{ - return csum_tcpudp_magic(saddr,daddr,len,IPPROTO_TCP,base); -} - -static inline __sum16 __tcp_checksum_complete(struct sk_buff *skb) -{ - return __skb_checksum_complete(skb); -} - -static inline bool tcp_checksum_complete(struct sk_buff *skb) -{ - return !skb_csum_unnecessary(skb) && - __tcp_checksum_complete(skb); -} - -/* Prequeue for VJ style copy to user, combined with checksumming. */ - -static inline void tcp_prequeue_init(struct tcp_sock *tp) -{ - tp->ucopy.task = NULL; - tp->ucopy.len = 0; - tp->ucopy.memory = 0; - skb_queue_head_init(&tp->ucopy.prequeue); -} - -bool tcp_prequeue(struct sock *sk, struct sk_buff *skb); -bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb); -int tcp_filter(struct sock *sk, struct sk_buff *skb); - -#undef STATE_TRACE - -#ifdef STATE_TRACE -static const char *statename[]={ - "Unused","Established","Syn Sent","Syn Recv", - "Fin Wait 1","Fin Wait 2","Time Wait", "Close", - "Close Wait","Last ACK","Listen","Closing" -}; -#endif -void tcp_set_state(struct sock *sk, int state); - -void tcp_done(struct sock *sk); - -int tcp_abort(struct sock *sk, int err); - -static inline void tcp_sack_reset(struct tcp_options_received *rx_opt) -{ - rx_opt->dsack = 0; - rx_opt->num_sacks = 0; -} - -u32 tcp_default_init_rwnd(u32 mss); -void tcp_cwnd_restart(struct sock *sk, s32 delta); - -static inline void tcp_slow_start_after_idle_check(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - s32 delta; - - if (!sysctl_tcp_slow_start_after_idle || tp->packets_out) - return; - delta = tcp_time_stamp - tp->lsndtime; - if (delta > inet_csk(sk)->icsk_rto) - tcp_cwnd_restart(sk, delta); -} - -/* Determine a window scaling and initial window to offer. */ -void tcp_select_initial_window(int __space, __u32 mss, __u32 *rcv_wnd, - __u32 *window_clamp, int wscale_ok, - __u8 *rcv_wscale, __u32 init_rcv_wnd); - -static inline int tcp_win_from_space(int space) -{ - return sysctl_tcp_adv_win_scale<=0 ? - (space>>(-sysctl_tcp_adv_win_scale)) : - space - (space>>sysctl_tcp_adv_win_scale); -} - -/* Note: caller must be prepared to deal with negative returns */ -static inline int tcp_space(const struct sock *sk) -{ - return tcp_win_from_space(sk->sk_rcvbuf - - atomic_read(&sk->sk_rmem_alloc)); -} - -static inline int tcp_full_space(const struct sock *sk) -{ - return tcp_win_from_space(sk->sk_rcvbuf); -} - -extern void tcp_openreq_init_rwin(struct request_sock *req, - const struct sock *sk_listener, - const struct dst_entry *dst); - -void tcp_enter_memory_pressure(struct sock *sk); - -static inline int keepalive_intvl_when(const struct tcp_sock *tp) -{ - struct net *net = sock_net((struct sock *)tp); - - return tp->keepalive_intvl ? : net->ipv4.sysctl_tcp_keepalive_intvl; -} - -static inline int keepalive_time_when(const struct tcp_sock *tp) -{ - struct net *net = sock_net((struct sock *)tp); - - return tp->keepalive_time ? : net->ipv4.sysctl_tcp_keepalive_time; -} - -static inline int keepalive_probes(const struct tcp_sock *tp) -{ - struct net *net = sock_net((struct sock *)tp); - - return tp->keepalive_probes ? : net->ipv4.sysctl_tcp_keepalive_probes; -} - -static inline u32 keepalive_time_elapsed(const struct tcp_sock *tp) -{ - const struct inet_connection_sock *icsk = &tp->inet_conn; - - return min_t(u32, tcp_time_stamp - icsk->icsk_ack.lrcvtime, - tcp_time_stamp - tp->rcv_tstamp); -} - -static inline int tcp_fin_time(const struct sock *sk) -{ - int fin_timeout = tcp_sk(sk)->linger2 ? : sock_net(sk)->ipv4.sysctl_tcp_fin_timeout; - const int rto = inet_csk(sk)->icsk_rto; - - if (fin_timeout < (rto << 2) - (rto >> 1)) - fin_timeout = (rto << 2) - (rto >> 1); - - return fin_timeout; -} - -static inline bool tcp_paws_check(const struct tcp_options_received *rx_opt, - int paws_win) -{ - if ((s32)(rx_opt->ts_recent - rx_opt->rcv_tsval) <= paws_win) - return true; - if (unlikely(get_seconds() >= rx_opt->ts_recent_stamp + TCP_PAWS_24DAYS)) - return true; - /* - * Some OSes send SYN and SYNACK messages with tsval=0 tsecr=0, - * then following tcp messages have valid values. Ignore 0 value, - * or else 'negative' tsval might forbid us to accept their packets. - */ - if (!rx_opt->ts_recent) - return true; - return false; -} - -static inline bool tcp_paws_reject(const struct tcp_options_received *rx_opt, - int rst) -{ - if (tcp_paws_check(rx_opt, 0)) - return false; - - /* RST segments are not recommended to carry timestamp, - and, if they do, it is recommended to ignore PAWS because - "their cleanup function should take precedence over timestamps." - Certainly, it is mistake. It is necessary to understand the reasons - of this constraint to relax it: if peer reboots, clock may go - out-of-sync and half-open connections will not be reset. - Actually, the problem would be not existing if all - the implementations followed draft about maintaining clock - via reboots. Linux-2.2 DOES NOT! - - However, we can relax time bounds for RST segments to MSL. - */ - if (rst && get_seconds() >= rx_opt->ts_recent_stamp + TCP_PAWS_MSL) - return false; - return true; -} - -bool tcp_oow_rate_limited(struct net *net, const struct sk_buff *skb, - int mib_idx, u32 *last_oow_ack_time); - -static inline void tcp_mib_init(struct net *net) -{ - /* See RFC 2012 */ - TCP_ADD_STATS(net, TCP_MIB_RTOALGORITHM, 1); - TCP_ADD_STATS(net, TCP_MIB_RTOMIN, TCP_RTO_MIN*1000/HZ); - TCP_ADD_STATS(net, TCP_MIB_RTOMAX, TCP_RTO_MAX*1000/HZ); - TCP_ADD_STATS(net, TCP_MIB_MAXCONN, -1); -} - -/* from STCP */ -static inline void tcp_clear_retrans_hints_partial(struct tcp_sock *tp) -{ - tp->lost_skb_hint = NULL; -} - -static inline void tcp_clear_all_retrans_hints(struct tcp_sock *tp) -{ - tcp_clear_retrans_hints_partial(tp); - tp->retransmit_skb_hint = NULL; -} - -union tcp_md5_addr { - struct in_addr a4; -#if IS_ENABLED(CONFIG_IPV6) - struct in6_addr a6; -#endif -}; - -/* - key database */ -struct tcp_md5sig_key { - struct hlist_node node; - u8 keylen; - u8 family; /* AF_INET or AF_INET6 */ - union tcp_md5_addr addr; - u8 key[TCP_MD5SIG_MAXKEYLEN]; - struct rcu_head rcu; -}; - -/* - sock block */ -struct tcp_md5sig_info { - struct hlist_head head; - struct rcu_head rcu; -}; - -/* - pseudo header */ -struct tcp4_pseudohdr { - __be32 saddr; - __be32 daddr; - __u8 pad; - __u8 protocol; - __be16 len; -}; - -struct tcp6_pseudohdr { - struct in6_addr saddr; - struct in6_addr daddr; - __be32 len; - __be32 protocol; /* including padding */ -}; - -union tcp_md5sum_block { - struct tcp4_pseudohdr ip4; -#if IS_ENABLED(CONFIG_IPV6) - struct tcp6_pseudohdr ip6; -#endif -}; - -/* - pool: digest algorithm, hash description and scratch buffer */ -struct tcp_md5sig_pool { - struct ahash_request *md5_req; - void *scratch; -}; - -/* - functions */ -int tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key, - const struct sock *sk, const struct sk_buff *skb); -int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, - int family, const u8 *newkey, u8 newkeylen, gfp_t gfp); -int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, - int family); -struct tcp_md5sig_key *tcp_v4_md5_lookup(const struct sock *sk, - const struct sock *addr_sk); - -#ifdef CONFIG_TCP_MD5SIG -struct tcp_md5sig_key *tcp_md5_do_lookup(const struct sock *sk, - const union tcp_md5_addr *addr, - int family); -#define tcp_twsk_md5_key(twsk) ((twsk)->tw_md5_key) -#else -static inline struct tcp_md5sig_key *tcp_md5_do_lookup(const struct sock *sk, - const union tcp_md5_addr *addr, - int family) -{ - return NULL; -} -#define tcp_twsk_md5_key(twsk) NULL -#endif - -bool tcp_alloc_md5sig_pool(void); - -struct tcp_md5sig_pool *tcp_get_md5sig_pool(void); -static inline void tcp_put_md5sig_pool(void) -{ - local_bh_enable(); -} - -int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *, const struct sk_buff *, - unsigned int header_len); -int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, - const struct tcp_md5sig_key *key); - -/* From tcp_fastopen.c */ -void tcp_fastopen_cache_get(struct sock *sk, u16 *mss, - struct tcp_fastopen_cookie *cookie, int *syn_loss, - unsigned long *last_syn_loss); -void tcp_fastopen_cache_set(struct sock *sk, u16 mss, - struct tcp_fastopen_cookie *cookie, bool syn_lost, - u16 try_exp); -struct tcp_fastopen_request { - /* Fast Open cookie. Size 0 means a cookie request */ - struct tcp_fastopen_cookie cookie; - struct msghdr *data; /* data in MSG_FASTOPEN */ - size_t size; - int copied; /* queued in tcp_connect() */ -}; -void tcp_free_fastopen_req(struct tcp_sock *tp); - -extern struct tcp_fastopen_context __rcu *tcp_fastopen_ctx; -int tcp_fastopen_reset_cipher(void *key, unsigned int len); -void tcp_fastopen_add_skb(struct sock *sk, struct sk_buff *skb); -struct sock *tcp_try_fastopen(struct sock *sk, struct sk_buff *skb, - struct request_sock *req, - struct tcp_fastopen_cookie *foc, - struct dst_entry *dst); -void tcp_fastopen_init_key_once(bool publish); -#define TCP_FASTOPEN_KEY_LENGTH 16 - -/* Fastopen key context */ -struct tcp_fastopen_context { - struct crypto_cipher *tfm; - __u8 key[TCP_FASTOPEN_KEY_LENGTH]; - struct rcu_head rcu; -}; - -/* write queue abstraction */ -static inline void tcp_write_queue_purge(struct sock *sk) -{ - struct sk_buff *skb; - - while ((skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) - sk_wmem_free_skb(sk, skb); - sk_mem_reclaim(sk); - tcp_clear_all_retrans_hints(tcp_sk(sk)); -} - -static inline struct sk_buff *tcp_write_queue_head(const struct sock *sk) -{ - return skb_peek(&sk->sk_write_queue); -} - -static inline struct sk_buff *tcp_write_queue_tail(const struct sock *sk) -{ - return skb_peek_tail(&sk->sk_write_queue); -} - -static inline struct sk_buff *tcp_write_queue_next(const struct sock *sk, - const struct sk_buff *skb) -{ - return skb_queue_next(&sk->sk_write_queue, skb); -} - -static inline struct sk_buff *tcp_write_queue_prev(const struct sock *sk, - const struct sk_buff *skb) -{ - return skb_queue_prev(&sk->sk_write_queue, skb); -} - -#define tcp_for_write_queue(skb, sk) \ - skb_queue_walk(&(sk)->sk_write_queue, skb) - -#define tcp_for_write_queue_from(skb, sk) \ - skb_queue_walk_from(&(sk)->sk_write_queue, skb) - -#define tcp_for_write_queue_from_safe(skb, tmp, sk) \ - skb_queue_walk_from_safe(&(sk)->sk_write_queue, skb, tmp) - -static inline struct sk_buff *tcp_send_head(const struct sock *sk) -{ - return sk->sk_send_head; -} - -static inline bool tcp_skb_is_last(const struct sock *sk, - const struct sk_buff *skb) -{ - return skb_queue_is_last(&sk->sk_write_queue, skb); -} - -static inline void tcp_advance_send_head(struct sock *sk, const struct sk_buff *skb) -{ - if (tcp_skb_is_last(sk, skb)) - sk->sk_send_head = NULL; - else - sk->sk_send_head = tcp_write_queue_next(sk, skb); -} - -static inline void tcp_check_send_head(struct sock *sk, struct sk_buff *skb_unlinked) -{ - if (sk->sk_send_head == skb_unlinked) - sk->sk_send_head = NULL; - if (tcp_sk(sk)->highest_sack == skb_unlinked) - tcp_sk(sk)->highest_sack = NULL; -} - -static inline void tcp_init_send_head(struct sock *sk) -{ - sk->sk_send_head = NULL; -} - -static inline void __tcp_add_write_queue_tail(struct sock *sk, struct sk_buff *skb) -{ - __skb_queue_tail(&sk->sk_write_queue, skb); -} - -static inline void tcp_add_write_queue_tail(struct sock *sk, struct sk_buff *skb) -{ - __tcp_add_write_queue_tail(sk, skb); - - /* Queue it, remembering where we must start sending. */ - if (sk->sk_send_head == NULL) { - sk->sk_send_head = skb; - - if (tcp_sk(sk)->highest_sack == NULL) - tcp_sk(sk)->highest_sack = skb; - } -} - -static inline void __tcp_add_write_queue_head(struct sock *sk, struct sk_buff *skb) -{ - __skb_queue_head(&sk->sk_write_queue, skb); -} - -/* Insert buff after skb on the write queue of sk. */ -static inline void tcp_insert_write_queue_after(struct sk_buff *skb, - struct sk_buff *buff, - struct sock *sk) -{ - __skb_queue_after(&sk->sk_write_queue, skb, buff); -} - -/* Insert new before skb on the write queue of sk. */ -static inline void tcp_insert_write_queue_before(struct sk_buff *new, - struct sk_buff *skb, - struct sock *sk) -{ - __skb_queue_before(&sk->sk_write_queue, skb, new); - - if (sk->sk_send_head == skb) - sk->sk_send_head = new; -} - -static inline void tcp_unlink_write_queue(struct sk_buff *skb, struct sock *sk) -{ - __skb_unlink(skb, &sk->sk_write_queue); -} - -static inline bool tcp_write_queue_empty(struct sock *sk) -{ - return skb_queue_empty(&sk->sk_write_queue); -} - -static inline void tcp_push_pending_frames(struct sock *sk) -{ - if (tcp_send_head(sk)) { - struct tcp_sock *tp = tcp_sk(sk); - - __tcp_push_pending_frames(sk, tcp_current_mss(sk), tp->nonagle); - } -} - -/* Start sequence of the skb just after the highest skb with SACKed - * bit, valid only if sacked_out > 0 or when the caller has ensured - * validity by itself. - */ -static inline u32 tcp_highest_sack_seq(struct tcp_sock *tp) -{ - if (!tp->sacked_out) - return tp->snd_una; - - if (tp->highest_sack == NULL) - return tp->snd_nxt; - - return TCP_SKB_CB(tp->highest_sack)->seq; -} - -static inline void tcp_advance_highest_sack(struct sock *sk, struct sk_buff *skb) -{ - tcp_sk(sk)->highest_sack = tcp_skb_is_last(sk, skb) ? NULL : - tcp_write_queue_next(sk, skb); -} - -static inline struct sk_buff *tcp_highest_sack(struct sock *sk) -{ - return tcp_sk(sk)->highest_sack; -} - -static inline void tcp_highest_sack_reset(struct sock *sk) -{ - tcp_sk(sk)->highest_sack = tcp_write_queue_head(sk); -} - -/* Called when old skb is about to be deleted (to be combined with new skb) */ -static inline void tcp_highest_sack_combine(struct sock *sk, - struct sk_buff *old, - struct sk_buff *new) -{ - if (tcp_sk(sk)->sacked_out && (old == tcp_sk(sk)->highest_sack)) - tcp_sk(sk)->highest_sack = new; -} - -/* This helper checks if socket has IP_TRANSPARENT set */ -static inline bool inet_sk_transparent(const struct sock *sk) -{ - switch (sk->sk_state) { - case TCP_TIME_WAIT: - return inet_twsk(sk)->tw_transparent; - case TCP_NEW_SYN_RECV: - return inet_rsk(inet_reqsk(sk))->no_srccheck; - } - return inet_sk(sk)->transparent; -} - -/* Determines whether this is a thin stream (which may suffer from - * increased latency). Used to trigger latency-reducing mechanisms. - */ -static inline bool tcp_stream_is_thin(struct tcp_sock *tp) -{ - return tp->packets_out < 4 && !tcp_in_initial_slowstart(tp); -} - -/* /proc */ -enum tcp_seq_states { - TCP_SEQ_STATE_LISTENING, - TCP_SEQ_STATE_ESTABLISHED, -}; - -int tcp_seq_open(struct inode *inode, struct file *file); - -struct tcp_seq_afinfo { - char *name; - sa_family_t family; - const struct file_operations *seq_fops; - struct seq_operations seq_ops; -}; - -struct tcp_iter_state { - struct seq_net_private p; - sa_family_t family; - enum tcp_seq_states state; - struct sock *syn_wait_sk; - int bucket, offset, sbucket, num; - loff_t last_pos; -}; - -int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo); -void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo); - -extern struct request_sock_ops tcp_request_sock_ops; -extern struct request_sock_ops tcp6_request_sock_ops; - -void tcp_v4_destroy_sock(struct sock *sk); - -struct sk_buff *tcp_gso_segment(struct sk_buff *skb, - netdev_features_t features); -struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb); -int tcp_gro_complete(struct sk_buff *skb); - -void __tcp_v4_send_check(struct sk_buff *skb, __be32 saddr, __be32 daddr); - -static inline u32 tcp_notsent_lowat(const struct tcp_sock *tp) -{ - struct net *net = sock_net((struct sock *)tp); - return tp->notsent_lowat ?: net->ipv4.sysctl_tcp_notsent_lowat; -} - -static inline bool tcp_stream_memory_free(const struct sock *sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - u32 notsent_bytes = tp->write_seq - tp->snd_nxt; - - return notsent_bytes < tcp_notsent_lowat(tp); -} - -#ifdef CONFIG_PROC_FS -int tcp4_proc_init(void); -void tcp4_proc_exit(void); -#endif - -int tcp_rtx_synack(const struct sock *sk, struct request_sock *req); -int tcp_conn_request(struct request_sock_ops *rsk_ops, - const struct tcp_request_sock_ops *af_ops, - struct sock *sk, struct sk_buff *skb); - -/* TCP af-specific functions */ -struct tcp_sock_af_ops { -#ifdef CONFIG_TCP_MD5SIG - struct tcp_md5sig_key *(*md5_lookup) (const struct sock *sk, - const struct sock *addr_sk); - int (*calc_md5_hash)(char *location, - const struct tcp_md5sig_key *md5, - const struct sock *sk, - const struct sk_buff *skb); - int (*md5_parse)(struct sock *sk, - char __user *optval, - int optlen); -#endif -}; - -struct tcp_request_sock_ops { - u16 mss_clamp; -#ifdef CONFIG_TCP_MD5SIG - struct tcp_md5sig_key *(*req_md5_lookup)(const struct sock *sk, - const struct sock *addr_sk); - int (*calc_md5_hash) (char *location, - const struct tcp_md5sig_key *md5, - const struct sock *sk, - const struct sk_buff *skb); -#endif - void (*init_req)(struct request_sock *req, - const struct sock *sk_listener, - struct sk_buff *skb); -#ifdef CONFIG_SYN_COOKIES - __u32 (*cookie_init_seq)(const struct sk_buff *skb, - __u16 *mss); -#endif - struct dst_entry *(*route_req)(const struct sock *sk, struct flowi *fl, - const struct request_sock *req, - bool *strict); - __u32 (*init_seq)(const struct sk_buff *skb); - int (*send_synack)(const struct sock *sk, struct dst_entry *dst, - struct flowi *fl, struct request_sock *req, - struct tcp_fastopen_cookie *foc, - enum tcp_synack_type synack_type); -}; - -#ifdef CONFIG_SYN_COOKIES -static inline __u32 cookie_init_sequence(const struct tcp_request_sock_ops *ops, - const struct sock *sk, struct sk_buff *skb, - __u16 *mss) -{ - tcp_synq_overflow(sk); - __NET_INC_STATS(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT); - return ops->cookie_init_seq(skb, mss); -} -#else -static inline __u32 cookie_init_sequence(const struct tcp_request_sock_ops *ops, - const struct sock *sk, struct sk_buff *skb, - __u16 *mss) -{ - return 0; -} -#endif - -int tcpv4_offload_init(void); - -void tcp_v4_init(void); -void tcp_init(void); - -/* tcp_recovery.c */ - -/* Flags to enable various loss recovery features. See below */ -extern int sysctl_tcp_recovery; - -/* Use TCP RACK to detect (some) tail and retransmit losses */ -#define TCP_RACK_LOST_RETRANS 0x1 - -extern int tcp_rack_mark_lost(struct sock *sk); - -extern void tcp_rack_advance(struct tcp_sock *tp, - const struct skb_mstamp *xmit_time, u8 sacked); - -/* - * Save and compile IPv4 options, return a pointer to it - */ -static inline struct ip_options_rcu *tcp_v4_save_options(struct sk_buff *skb) -{ - const struct ip_options *opt = &TCP_SKB_CB(skb)->header.h4.opt; - struct ip_options_rcu *dopt = NULL; - - if (opt->optlen) { - int opt_size = sizeof(*dopt) + opt->optlen; - - dopt = kmalloc(opt_size, GFP_ATOMIC); - if (dopt && __ip_options_echo(&dopt->opt, skb, opt)) { - kfree(dopt); - dopt = NULL; - } - } - return dopt; -} - -/* locally generated TCP pure ACKs have skb->truesize == 2 - * (check tcp_send_ack() in net/ipv4/tcp_output.c ) - * This is much faster than dissecting the packet to find out. - * (Think of GRE encapsulations, IPv4, IPv6, ...) - */ -static inline bool skb_is_tcp_pure_ack(const struct sk_buff *skb) -{ - return skb->truesize == 2; -} - -static inline void skb_set_tcp_pure_ack(struct sk_buff *skb) -{ - skb->truesize = 2; -} - -static inline int tcp_inq(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - int answ; - - if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { - answ = 0; - } else if (sock_flag(sk, SOCK_URGINLINE) || - !tp->urg_data || - before(tp->urg_seq, tp->copied_seq) || - !before(tp->urg_seq, tp->rcv_nxt)) { - - answ = tp->rcv_nxt - tp->copied_seq; - - /* Subtract 1, if FIN was received */ - if (answ && sock_flag(sk, SOCK_DONE)) - answ--; - } else { - answ = tp->urg_seq - tp->copied_seq; - } - - return answ; -} - -int tcp_peek_len(struct socket *sock); - -static inline void tcp_segs_in(struct tcp_sock *tp, const struct sk_buff *skb) -{ - u16 segs_in; - - segs_in = max_t(u16, 1, skb_shinfo(skb)->gso_segs); - tp->segs_in += segs_in; - if (skb->len > tcp_hdrlen(skb)) - tp->data_segs_in += segs_in; -} - -/* - * TCP listen path runs lockless. - * We forced "struct sock" to be const qualified to make sure - * we don't modify one of its field by mistake. - * Here, we increment sk_drops which is an atomic_t, so we can safely - * make sock writable again. - */ -static inline void tcp_listendrop(const struct sock *sk) -{ - atomic_inc(&((struct sock *)sk)->sk_drops); - __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENDROPS); -} - -#endif /* _TCP_H */ diff --git a/src/linux/include/net/tcp_states.h b/src/linux/include/net/tcp_states.h deleted file mode 100644 index 50e78a7..0000000 --- a/src/linux/include/net/tcp_states.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the TCP protocol sk_state field. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_TCP_STATES_H -#define _LINUX_TCP_STATES_H - -enum { - TCP_ESTABLISHED = 1, - TCP_SYN_SENT, - TCP_SYN_RECV, - TCP_FIN_WAIT1, - TCP_FIN_WAIT2, - TCP_TIME_WAIT, - TCP_CLOSE, - TCP_CLOSE_WAIT, - TCP_LAST_ACK, - TCP_LISTEN, - TCP_CLOSING, /* Now a valid state */ - TCP_NEW_SYN_RECV, - - TCP_MAX_STATES /* Leave at the end! */ -}; - -#define TCP_STATE_MASK 0xF - -#define TCP_ACTION_FIN (1 << 7) - -enum { - TCPF_ESTABLISHED = (1 << 1), - TCPF_SYN_SENT = (1 << 2), - TCPF_SYN_RECV = (1 << 3), - TCPF_FIN_WAIT1 = (1 << 4), - TCPF_FIN_WAIT2 = (1 << 5), - TCPF_TIME_WAIT = (1 << 6), - TCPF_CLOSE = (1 << 7), - TCPF_CLOSE_WAIT = (1 << 8), - TCPF_LAST_ACK = (1 << 9), - TCPF_LISTEN = (1 << 10), - TCPF_CLOSING = (1 << 11), - TCPF_NEW_SYN_RECV = (1 << 12), -}; - -#endif /* _LINUX_TCP_STATES_H */ diff --git a/src/linux/include/net/timewait_sock.h b/src/linux/include/net/timewait_sock.h deleted file mode 100644 index 1a47946..0000000 --- a/src/linux/include/net/timewait_sock.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * NET Generic infrastructure for Network protocols. - * - * Authors: Arnaldo Carvalho de Melo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _TIMEWAIT_SOCK_H -#define _TIMEWAIT_SOCK_H - -#include -#include -#include - -struct timewait_sock_ops { - struct kmem_cache *twsk_slab; - char *twsk_slab_name; - unsigned int twsk_obj_size; - int (*twsk_unique)(struct sock *sk, - struct sock *sktw, void *twp); - void (*twsk_destructor)(struct sock *sk); -}; - -static inline int twsk_unique(struct sock *sk, struct sock *sktw, void *twp) -{ - if (sk->sk_prot->twsk_prot->twsk_unique != NULL) - return sk->sk_prot->twsk_prot->twsk_unique(sk, sktw, twp); - return 0; -} - -static inline void twsk_destructor(struct sock *sk) -{ - if (sk->sk_prot->twsk_prot->twsk_destructor != NULL) - sk->sk_prot->twsk_prot->twsk_destructor(sk); -} - -#endif /* _TIMEWAIT_SOCK_H */ diff --git a/src/linux/include/net/transp_v6.h b/src/linux/include/net/transp_v6.h deleted file mode 100644 index 276f976..0000000 --- a/src/linux/include/net/transp_v6.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef _TRANSP_V6_H -#define _TRANSP_V6_H - -#include - -/* IPv6 transport protocols */ -extern struct proto rawv6_prot; -extern struct proto udpv6_prot; -extern struct proto udplitev6_prot; -extern struct proto tcpv6_prot; -extern struct proto pingv6_prot; - -struct flowi6; - -/* extension headers */ -int ipv6_exthdrs_init(void); -void ipv6_exthdrs_exit(void); -int ipv6_frag_init(void); -void ipv6_frag_exit(void); - -/* transport protocols */ -int pingv6_init(void); -void pingv6_exit(void); -int rawv6_init(void); -void rawv6_exit(void); -int udpv6_init(void); -void udpv6_exit(void); -int udplitev6_init(void); -void udplitev6_exit(void); -int tcpv6_init(void); -void tcpv6_exit(void); - -int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len); - -/* this does all the common and the specific ctl work */ -void ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, - struct sk_buff *skb); -void ip6_datagram_recv_common_ctl(struct sock *sk, struct msghdr *msg, - struct sk_buff *skb); -void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg, - struct sk_buff *skb); - -int ip6_datagram_send_ctl(struct net *net, struct sock *sk, struct msghdr *msg, - struct flowi6 *fl6, struct ipcm6_cookie *ipc6, - struct sockcm_cookie *sockc); - -void ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp, - __u16 srcp, __u16 destp, int bucket); - -#define LOOPBACK4_IPV6 cpu_to_be32(0x7f000006) - -/* address family specific functions */ -extern const struct inet_connection_sock_af_ops ipv4_specific; - -void inet6_destroy_sock(struct sock *sk); - -#define IPV6_SEQ_DGRAM_HEADER \ - " sl " \ - "local_address " \ - "remote_address " \ - "st tx_queue rx_queue tr tm->when retrnsmt" \ - " uid timeout inode ref pointer drops\n" - -#endif diff --git a/src/linux/include/net/tso.h b/src/linux/include/net/tso.h deleted file mode 100644 index b7be852..0000000 --- a/src/linux/include/net/tso.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _TSO_H -#define _TSO_H - -#include - -struct tso_t { - int next_frag_idx; - void *data; - size_t size; - u16 ip_id; - bool ipv6; - u32 tcp_seq; -}; - -int tso_count_descs(struct sk_buff *skb); -void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso, - int size, bool is_last); -void tso_build_data(struct sk_buff *skb, struct tso_t *tso, int size); -void tso_start(struct sk_buff *skb, struct tso_t *tso); - -#endif /* _TSO_H */ diff --git a/src/linux/include/net/udp.h b/src/linux/include/net/udp.h deleted file mode 100644 index 4948790..0000000 --- a/src/linux/include/net/udp.h +++ /dev/null @@ -1,356 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the UDP module. - * - * Version: @(#)udp.h 1.0.2 05/07/93 - * - * Authors: Ross Biro - * Fred N. van Kempen, - * - * Fixes: - * Alan Cox : Turned on udp checksums. I don't want to - * chase 'memory corruption' bugs that aren't! - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _UDP_H -#define _UDP_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * struct udp_skb_cb - UDP(-Lite) private variables - * - * @header: private variables used by IPv4/IPv6 - * @cscov: checksum coverage length (UDP-Lite only) - * @partial_cov: if set indicates partial csum coverage - */ -struct udp_skb_cb { - union { - struct inet_skb_parm h4; -#if IS_ENABLED(CONFIG_IPV6) - struct inet6_skb_parm h6; -#endif - } header; - __u16 cscov; - __u8 partial_cov; -}; -#define UDP_SKB_CB(__skb) ((struct udp_skb_cb *)((__skb)->cb)) - -/** - * struct udp_hslot - UDP hash slot - * - * @head: head of list of sockets - * @count: number of sockets in 'head' list - * @lock: spinlock protecting changes to head/count - */ -struct udp_hslot { - struct hlist_head head; - int count; - spinlock_t lock; -} __attribute__((aligned(2 * sizeof(long)))); - -/** - * struct udp_table - UDP table - * - * @hash: hash table, sockets are hashed on (local port) - * @hash2: hash table, sockets are hashed on (local port, local address) - * @mask: number of slots in hash tables, minus 1 - * @log: log2(number of slots in hash table) - */ -struct udp_table { - struct udp_hslot *hash; - struct udp_hslot *hash2; - unsigned int mask; - unsigned int log; -}; -extern struct udp_table udp_table; -void udp_table_init(struct udp_table *, const char *); -static inline struct udp_hslot *udp_hashslot(struct udp_table *table, - struct net *net, unsigned int num) -{ - return &table->hash[udp_hashfn(net, num, table->mask)]; -} -/* - * For secondary hash, net_hash_mix() is performed before calling - * udp_hashslot2(), this explains difference with udp_hashslot() - */ -static inline struct udp_hslot *udp_hashslot2(struct udp_table *table, - unsigned int hash) -{ - return &table->hash2[hash & table->mask]; -} - -extern struct proto udp_prot; - -extern atomic_long_t udp_memory_allocated; - -/* sysctl variables for udp */ -extern long sysctl_udp_mem[3]; -extern int sysctl_udp_rmem_min; -extern int sysctl_udp_wmem_min; - -struct sk_buff; - -/* - * Generic checksumming routines for UDP(-Lite) v4 and v6 - */ -static inline __sum16 __udp_lib_checksum_complete(struct sk_buff *skb) -{ - return (UDP_SKB_CB(skb)->cscov == skb->len ? - __skb_checksum_complete(skb) : - __skb_checksum_complete_head(skb, UDP_SKB_CB(skb)->cscov)); -} - -static inline int udp_lib_checksum_complete(struct sk_buff *skb) -{ - return !skb_csum_unnecessary(skb) && - __udp_lib_checksum_complete(skb); -} - -/** - * udp_csum_outgoing - compute UDPv4/v6 checksum over fragments - * @sk: socket we are writing to - * @skb: sk_buff containing the filled-in UDP header - * (checksum field must be zeroed out) - */ -static inline __wsum udp_csum_outgoing(struct sock *sk, struct sk_buff *skb) -{ - __wsum csum = csum_partial(skb_transport_header(skb), - sizeof(struct udphdr), 0); - skb_queue_walk(&sk->sk_write_queue, skb) { - csum = csum_add(csum, skb->csum); - } - return csum; -} - -static inline __wsum udp_csum(struct sk_buff *skb) -{ - __wsum csum = csum_partial(skb_transport_header(skb), - sizeof(struct udphdr), skb->csum); - - for (skb = skb_shinfo(skb)->frag_list; skb; skb = skb->next) { - csum = csum_add(csum, skb->csum); - } - return csum; -} - -static inline __sum16 udp_v4_check(int len, __be32 saddr, - __be32 daddr, __wsum base) -{ - return csum_tcpudp_magic(saddr, daddr, len, IPPROTO_UDP, base); -} - -void udp_set_csum(bool nocheck, struct sk_buff *skb, - __be32 saddr, __be32 daddr, int len); - -static inline void udp_csum_pull_header(struct sk_buff *skb) -{ - if (!skb->csum_valid && skb->ip_summed == CHECKSUM_NONE) - skb->csum = csum_partial(skb->data, sizeof(struct udphdr), - skb->csum); - skb_pull_rcsum(skb, sizeof(struct udphdr)); - UDP_SKB_CB(skb)->cscov -= sizeof(struct udphdr); -} - -typedef struct sock *(*udp_lookup_t)(struct sk_buff *skb, __be16 sport, - __be16 dport); - -struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb, - struct udphdr *uh, udp_lookup_t lookup); -int udp_gro_complete(struct sk_buff *skb, int nhoff, udp_lookup_t lookup); - -static inline struct udphdr *udp_gro_udphdr(struct sk_buff *skb) -{ - struct udphdr *uh; - unsigned int hlen, off; - - off = skb_gro_offset(skb); - hlen = off + sizeof(*uh); - uh = skb_gro_header_fast(skb, off); - if (skb_gro_header_hard(skb, hlen)) - uh = skb_gro_header_slow(skb, hlen, off); - - return uh; -} - -/* hash routines shared between UDPv4/6 and UDP-Litev4/6 */ -static inline int udp_lib_hash(struct sock *sk) -{ - BUG(); - return 0; -} - -void udp_lib_unhash(struct sock *sk); -void udp_lib_rehash(struct sock *sk, u16 new_hash); - -static inline void udp_lib_close(struct sock *sk, long timeout) -{ - sk_common_release(sk); -} - -int udp_lib_get_port(struct sock *sk, unsigned short snum, - int (*)(const struct sock *, const struct sock *, bool), - unsigned int hash2_nulladdr); - -u32 udp_flow_hashrnd(void); - -static inline __be16 udp_flow_src_port(struct net *net, struct sk_buff *skb, - int min, int max, bool use_eth) -{ - u32 hash; - - if (min >= max) { - /* Use default range */ - inet_get_local_port_range(net, &min, &max); - } - - hash = skb_get_hash(skb); - if (unlikely(!hash)) { - if (use_eth) { - /* Can't find a normal hash, caller has indicated an - * Ethernet packet so use that to compute a hash. - */ - hash = jhash(skb->data, 2 * ETH_ALEN, - (__force u32) skb->protocol); - } else { - /* Can't derive any sort of hash for the packet, set - * to some consistent random value. - */ - hash = udp_flow_hashrnd(); - } - } - - /* Since this is being sent on the wire obfuscate hash a bit - * to minimize possbility that any useful information to an - * attacker is leaked. Only upper 16 bits are relevant in the - * computation for 16 bit port value. - */ - hash ^= hash << 16; - - return htons((((u64) hash * (max - min)) >> 32) + min); -} - -/* net/ipv4/udp.c */ -void udp_v4_early_demux(struct sk_buff *skb); -int udp_get_port(struct sock *sk, unsigned short snum, - int (*saddr_cmp)(const struct sock *, - const struct sock *)); -void udp_err(struct sk_buff *, u32); -int udp_abort(struct sock *sk, int err); -int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len); -int udp_push_pending_frames(struct sock *sk); -void udp_flush_pending_frames(struct sock *sk); -void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst); -int udp_rcv(struct sk_buff *skb); -int udp_ioctl(struct sock *sk, int cmd, unsigned long arg); -int __udp_disconnect(struct sock *sk, int flags); -int udp_disconnect(struct sock *sk, int flags); -unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait); -struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, - netdev_features_t features, - bool is_ipv6); -int udp_lib_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen); -int udp_lib_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen, - int (*push_pending_frames)(struct sock *)); -struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport, - __be32 daddr, __be16 dport, int dif); -struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport, - __be32 daddr, __be16 dport, int dif, - struct udp_table *tbl, struct sk_buff *skb); -struct sock *udp4_lib_lookup_skb(struct sk_buff *skb, - __be16 sport, __be16 dport); -struct sock *udp6_lib_lookup(struct net *net, - const struct in6_addr *saddr, __be16 sport, - const struct in6_addr *daddr, __be16 dport, - int dif); -struct sock *__udp6_lib_lookup(struct net *net, - const struct in6_addr *saddr, __be16 sport, - const struct in6_addr *daddr, __be16 dport, - int dif, struct udp_table *tbl, - struct sk_buff *skb); -struct sock *udp6_lib_lookup_skb(struct sk_buff *skb, - __be16 sport, __be16 dport); - -/* - * SNMP statistics for UDP and UDP-Lite - */ -#define UDP_INC_STATS(net, field, is_udplite) do { \ - if (is_udplite) SNMP_INC_STATS((net)->mib.udplite_statistics, field); \ - else SNMP_INC_STATS((net)->mib.udp_statistics, field); } while(0) -#define __UDP_INC_STATS(net, field, is_udplite) do { \ - if (is_udplite) __SNMP_INC_STATS((net)->mib.udplite_statistics, field); \ - else __SNMP_INC_STATS((net)->mib.udp_statistics, field); } while(0) - -#define __UDP6_INC_STATS(net, field, is_udplite) do { \ - if (is_udplite) __SNMP_INC_STATS((net)->mib.udplite_stats_in6, field);\ - else __SNMP_INC_STATS((net)->mib.udp_stats_in6, field); \ -} while(0) -#define UDP6_INC_STATS(net, field, __lite) do { \ - if (__lite) SNMP_INC_STATS((net)->mib.udplite_stats_in6, field); \ - else SNMP_INC_STATS((net)->mib.udp_stats_in6, field); \ -} while(0) - -#if IS_ENABLED(CONFIG_IPV6) -#define __UDPX_INC_STATS(sk, field) \ -do { \ - if ((sk)->sk_family == AF_INET) \ - __UDP_INC_STATS(sock_net(sk), field, 0); \ - else \ - __UDP6_INC_STATS(sock_net(sk), field, 0); \ -} while (0) -#else -#define __UDPX_INC_STATS(sk, field) __UDP_INC_STATS(sock_net(sk), field, 0) -#endif - -/* /proc */ -int udp_seq_open(struct inode *inode, struct file *file); - -struct udp_seq_afinfo { - char *name; - sa_family_t family; - struct udp_table *udp_table; - const struct file_operations *seq_fops; - struct seq_operations seq_ops; -}; - -struct udp_iter_state { - struct seq_net_private p; - sa_family_t family; - int bucket; - struct udp_table *udp_table; -}; - -#ifdef CONFIG_PROC_FS -int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo); -void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo); - -int udp4_proc_init(void); -void udp4_proc_exit(void); -#endif - -int udpv4_offload_init(void); - -void udp_init(void); - -void udp_encap_enable(void); -#if IS_ENABLED(CONFIG_IPV6) -void udpv6_encap_enable(void); -#endif -#endif /* _UDP_H */ diff --git a/src/linux/include/net/udplite.h b/src/linux/include/net/udplite.h deleted file mode 100644 index 8076193..0000000 --- a/src/linux/include/net/udplite.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Definitions for the UDP-Lite (RFC 3828) code. - */ -#ifndef _UDPLITE_H -#define _UDPLITE_H - -#include - -/* UDP-Lite socket options */ -#define UDPLITE_SEND_CSCOV 10 /* sender partial coverage (as sent) */ -#define UDPLITE_RECV_CSCOV 11 /* receiver partial coverage (threshold ) */ - -extern struct proto udplite_prot; -extern struct udp_table udplite_table; - -/* - * Checksum computation is all in software, hence simpler getfrag. - */ -static __inline__ int udplite_getfrag(void *from, char *to, int offset, - int len, int odd, struct sk_buff *skb) -{ - struct msghdr *msg = from; - return copy_from_iter(to, len, &msg->msg_iter) != len ? -EFAULT : 0; -} - -/* Designate sk as UDP-Lite socket */ -static inline int udplite_sk_init(struct sock *sk) -{ - udp_sk(sk)->pcflag = UDPLITE_BIT; - return 0; -} - -/* - * Checksumming routines - */ -static inline int udplite_checksum_init(struct sk_buff *skb, struct udphdr *uh) -{ - u16 cscov; - - /* In UDPv4 a zero checksum means that the transmitter generated no - * checksum. UDP-Lite (like IPv6) mandates checksums, hence packets - * with a zero checksum field are illegal. */ - if (uh->check == 0) { - net_dbg_ratelimited("UDPLite: zeroed checksum field\n"); - return 1; - } - - cscov = ntohs(uh->len); - - if (cscov == 0) /* Indicates that full coverage is required. */ - ; - else if (cscov < 8 || cscov > skb->len) { - /* - * Coverage length violates RFC 3828: log and discard silently. - */ - net_dbg_ratelimited("UDPLite: bad csum coverage %d/%d\n", - cscov, skb->len); - return 1; - - } else if (cscov < skb->len) { - UDP_SKB_CB(skb)->partial_cov = 1; - UDP_SKB_CB(skb)->cscov = cscov; - if (skb->ip_summed == CHECKSUM_COMPLETE) - skb->ip_summed = CHECKSUM_NONE; - } - - return 0; -} - -/* Slow-path computation of checksum. Socket is locked. */ -static inline __wsum udplite_csum_outgoing(struct sock *sk, struct sk_buff *skb) -{ - const struct udp_sock *up = udp_sk(skb->sk); - int cscov = up->len; - __wsum csum = 0; - - if (up->pcflag & UDPLITE_SEND_CC) { - /* - * Sender has set `partial coverage' option on UDP-Lite socket. - * The special case "up->pcslen == 0" signifies full coverage. - */ - if (up->pcslen < up->len) { - if (0 < up->pcslen) - cscov = up->pcslen; - udp_hdr(skb)->len = htons(up->pcslen); - } - /* - * NOTE: Causes for the error case `up->pcslen > up->len': - * (i) Application error (will not be penalized). - * (ii) Payload too big for send buffer: data is split - * into several packets, each with its own header. - * In this case (e.g. last segment), coverage may - * exceed packet length. - * Since packets with coverage length > packet length are - * illegal, we fall back to the defaults here. - */ - } - - skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */ - - skb_queue_walk(&sk->sk_write_queue, skb) { - const int off = skb_transport_offset(skb); - const int len = skb->len - off; - - csum = skb_checksum(skb, off, (cscov > len)? len : cscov, csum); - - if ((cscov -= len) <= 0) - break; - } - return csum; -} - -/* Fast-path computation of checksum. Socket may not be locked. */ -static inline __wsum udplite_csum(struct sk_buff *skb) -{ - const struct udp_sock *up = udp_sk(skb->sk); - const int off = skb_transport_offset(skb); - int len = skb->len - off; - - if ((up->pcflag & UDPLITE_SEND_CC) && up->pcslen < len) { - if (0 < up->pcslen) - len = up->pcslen; - udp_hdr(skb)->len = htons(up->pcslen); - } - skb->ip_summed = CHECKSUM_NONE; /* no HW support for checksumming */ - - return skb_checksum(skb, off, len, 0); -} - -void udplite4_register(void); -int udplite_get_port(struct sock *sk, unsigned short snum, - int (*scmp)(const struct sock *, const struct sock *)); -#endif /* _UDPLITE_H */ diff --git a/src/linux/include/net/wext.h b/src/linux/include/net/wext.h deleted file mode 100644 index 3459119..0000000 --- a/src/linux/include/net/wext.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef __NET_WEXT_H -#define __NET_WEXT_H - -#include - -struct net; - -#ifdef CONFIG_WEXT_CORE -int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, - void __user *arg); -int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, - unsigned long arg); - -struct iw_statistics *get_wireless_stats(struct net_device *dev); -int call_commit_handler(struct net_device *dev); -#else -static inline int wext_handle_ioctl(struct net *net, struct ifreq *ifr, unsigned int cmd, - void __user *arg) -{ - return -EINVAL; -} -static inline int compat_wext_handle_ioctl(struct net *net, unsigned int cmd, - unsigned long arg) -{ - return -EINVAL; -} -#endif - -#ifdef CONFIG_WEXT_PROC -int wext_proc_init(struct net *net); -void wext_proc_exit(struct net *net); -#else -static inline int wext_proc_init(struct net *net) -{ - return 0; -} -static inline void wext_proc_exit(struct net *net) -{ - return; -} -#endif - -#ifdef CONFIG_WEXT_PRIV -int ioctl_private_call(struct net_device *dev, struct iwreq *iwr, - unsigned int cmd, struct iw_request_info *info, - iw_handler handler); -int compat_private_call(struct net_device *dev, struct iwreq *iwr, - unsigned int cmd, struct iw_request_info *info, - iw_handler handler); -int iw_handler_get_private(struct net_device * dev, - struct iw_request_info * info, - union iwreq_data * wrqu, - char * extra); -#else -#define ioctl_private_call NULL -#define compat_private_call NULL -#endif - - -#endif /* __NET_WEXT_H */ diff --git a/src/linux/include/net/xfrm.h b/src/linux/include/net/xfrm.h deleted file mode 100644 index 31947b9..0000000 --- a/src/linux/include/net/xfrm.h +++ /dev/null @@ -1,1818 +0,0 @@ -#ifndef _NET_XFRM_H -#define _NET_XFRM_H - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef CONFIG_XFRM_STATISTICS -#include -#endif - -#define XFRM_PROTO_ESP 50 -#define XFRM_PROTO_AH 51 -#define XFRM_PROTO_COMP 108 -#define XFRM_PROTO_IPIP 4 -#define XFRM_PROTO_IPV6 41 -#define XFRM_PROTO_ROUTING IPPROTO_ROUTING -#define XFRM_PROTO_DSTOPTS IPPROTO_DSTOPTS - -#define XFRM_ALIGN4(len) (((len) + 3) & ~3) -#define XFRM_ALIGN8(len) (((len) + 7) & ~7) -#define MODULE_ALIAS_XFRM_MODE(family, encap) \ - MODULE_ALIAS("xfrm-mode-" __stringify(family) "-" __stringify(encap)) -#define MODULE_ALIAS_XFRM_TYPE(family, proto) \ - MODULE_ALIAS("xfrm-type-" __stringify(family) "-" __stringify(proto)) - -#ifdef CONFIG_XFRM_STATISTICS -#define XFRM_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.xfrm_statistics, field) -#else -#define XFRM_INC_STATS(net, field) ((void)(net)) -#endif - - -/* Organization of SPD aka "XFRM rules" - ------------------------------------ - - Basic objects: - - policy rule, struct xfrm_policy (=SPD entry) - - bundle of transformations, struct dst_entry == struct xfrm_dst (=SA bundle) - - instance of a transformer, struct xfrm_state (=SA) - - template to clone xfrm_state, struct xfrm_tmpl - - SPD is plain linear list of xfrm_policy rules, ordered by priority. - (To be compatible with existing pfkeyv2 implementations, - many rules with priority of 0x7fffffff are allowed to exist and - such rules are ordered in an unpredictable way, thanks to bsd folks.) - - Lookup is plain linear search until the first match with selector. - - If "action" is "block", then we prohibit the flow, otherwise: - if "xfrms_nr" is zero, the flow passes untransformed. Otherwise, - policy entry has list of up to XFRM_MAX_DEPTH transformations, - described by templates xfrm_tmpl. Each template is resolved - to a complete xfrm_state (see below) and we pack bundle of transformations - to a dst_entry returned to requestor. - - dst -. xfrm .-> xfrm_state #1 - |---. child .-> dst -. xfrm .-> xfrm_state #2 - |---. child .-> dst -. xfrm .-> xfrm_state #3 - |---. child .-> NULL - - Bundles are cached at xrfm_policy struct (field ->bundles). - - - Resolution of xrfm_tmpl - ----------------------- - Template contains: - 1. ->mode Mode: transport or tunnel - 2. ->id.proto Protocol: AH/ESP/IPCOMP - 3. ->id.daddr Remote tunnel endpoint, ignored for transport mode. - Q: allow to resolve security gateway? - 4. ->id.spi If not zero, static SPI. - 5. ->saddr Local tunnel endpoint, ignored for transport mode. - 6. ->algos List of allowed algos. Plain bitmask now. - Q: ealgos, aalgos, calgos. What a mess... - 7. ->share Sharing mode. - Q: how to implement private sharing mode? To add struct sock* to - flow id? - - Having this template we search through SAD searching for entries - with appropriate mode/proto/algo, permitted by selector. - If no appropriate entry found, it is requested from key manager. - - PROBLEMS: - Q: How to find all the bundles referring to a physical path for - PMTU discovery? Seems, dst should contain list of all parents... - and enter to infinite locking hierarchy disaster. - No! It is easier, we will not search for them, let them find us. - We add genid to each dst plus pointer to genid of raw IP route, - pmtu disc will update pmtu on raw IP route and increase its genid. - dst_check() will see this for top level and trigger resyncing - metrics. Plus, it will be made via sk->sk_dst_cache. Solved. - */ - -struct xfrm_state_walk { - struct list_head all; - u8 state; - u8 dying; - u8 proto; - u32 seq; - struct xfrm_address_filter *filter; -}; - -/* Full description of state of transformer. */ -struct xfrm_state { - possible_net_t xs_net; - union { - struct hlist_node gclist; - struct hlist_node bydst; - }; - struct hlist_node bysrc; - struct hlist_node byspi; - - atomic_t refcnt; - spinlock_t lock; - - struct xfrm_id id; - struct xfrm_selector sel; - struct xfrm_mark mark; - u32 tfcpad; - - u32 genid; - - /* Key manager bits */ - struct xfrm_state_walk km; - - /* Parameters of this state. */ - struct { - u32 reqid; - u8 mode; - u8 replay_window; - u8 aalgo, ealgo, calgo; - u8 flags; - u16 family; - xfrm_address_t saddr; - int header_len; - int trailer_len; - u32 extra_flags; - } props; - - struct xfrm_lifetime_cfg lft; - - /* Data for transformer */ - struct xfrm_algo_auth *aalg; - struct xfrm_algo *ealg; - struct xfrm_algo *calg; - struct xfrm_algo_aead *aead; - const char *geniv; - - /* Data for encapsulator */ - struct xfrm_encap_tmpl *encap; - - /* Data for care-of address */ - xfrm_address_t *coaddr; - - /* IPComp needs an IPIP tunnel for handling uncompressed packets */ - struct xfrm_state *tunnel; - - /* If a tunnel, number of users + 1 */ - atomic_t tunnel_users; - - /* State for replay detection */ - struct xfrm_replay_state replay; - struct xfrm_replay_state_esn *replay_esn; - - /* Replay detection state at the time we sent the last notification */ - struct xfrm_replay_state preplay; - struct xfrm_replay_state_esn *preplay_esn; - - /* The functions for replay detection. */ - const struct xfrm_replay *repl; - - /* internal flag that only holds state for delayed aevent at the - * moment - */ - u32 xflags; - - /* Replay detection notification settings */ - u32 replay_maxage; - u32 replay_maxdiff; - - /* Replay detection notification timer */ - struct timer_list rtimer; - - /* Statistics */ - struct xfrm_stats stats; - - struct xfrm_lifetime_cur curlft; - struct tasklet_hrtimer mtimer; - - /* used to fix curlft->add_time when changing date */ - long saved_tmo; - - /* Last used time */ - unsigned long lastused; - - /* Reference to data common to all the instances of this - * transformer. */ - const struct xfrm_type *type; - struct xfrm_mode *inner_mode; - struct xfrm_mode *inner_mode_iaf; - struct xfrm_mode *outer_mode; - - /* Security context */ - struct xfrm_sec_ctx *security; - - /* Private data of this transformer, format is opaque, - * interpreted by xfrm_type methods. */ - void *data; -}; - -static inline struct net *xs_net(struct xfrm_state *x) -{ - return read_pnet(&x->xs_net); -} - -/* xflags - make enum if more show up */ -#define XFRM_TIME_DEFER 1 -#define XFRM_SOFT_EXPIRE 2 - -enum { - XFRM_STATE_VOID, - XFRM_STATE_ACQ, - XFRM_STATE_VALID, - XFRM_STATE_ERROR, - XFRM_STATE_EXPIRED, - XFRM_STATE_DEAD -}; - -/* callback structure passed from either netlink or pfkey */ -struct km_event { - union { - u32 hard; - u32 proto; - u32 byid; - u32 aevent; - u32 type; - } data; - - u32 seq; - u32 portid; - u32 event; - struct net *net; -}; - -struct xfrm_replay { - void (*advance)(struct xfrm_state *x, __be32 net_seq); - int (*check)(struct xfrm_state *x, - struct sk_buff *skb, - __be32 net_seq); - int (*recheck)(struct xfrm_state *x, - struct sk_buff *skb, - __be32 net_seq); - void (*notify)(struct xfrm_state *x, int event); - int (*overflow)(struct xfrm_state *x, struct sk_buff *skb); -}; - -struct net_device; -struct xfrm_type; -struct xfrm_dst; -struct xfrm_policy_afinfo { - unsigned short family; - struct dst_ops *dst_ops; - void (*garbage_collect)(struct net *net); - struct dst_entry *(*dst_lookup)(struct net *net, - int tos, int oif, - const xfrm_address_t *saddr, - const xfrm_address_t *daddr); - int (*get_saddr)(struct net *net, int oif, - xfrm_address_t *saddr, - xfrm_address_t *daddr); - void (*decode_session)(struct sk_buff *skb, - struct flowi *fl, - int reverse); - int (*get_tos)(const struct flowi *fl); - int (*init_path)(struct xfrm_dst *path, - struct dst_entry *dst, - int nfheader_len); - int (*fill_dst)(struct xfrm_dst *xdst, - struct net_device *dev, - const struct flowi *fl); - struct dst_entry *(*blackhole_route)(struct net *net, struct dst_entry *orig); -}; - -int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo); -int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo); -void km_policy_notify(struct xfrm_policy *xp, int dir, - const struct km_event *c); -void km_state_notify(struct xfrm_state *x, const struct km_event *c); - -struct xfrm_tmpl; -int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, - struct xfrm_policy *pol); -void km_state_expired(struct xfrm_state *x, int hard, u32 portid); -int __xfrm_state_delete(struct xfrm_state *x); - -struct xfrm_state_afinfo { - unsigned int family; - unsigned int proto; - __be16 eth_proto; - struct module *owner; - const struct xfrm_type *type_map[IPPROTO_MAX]; - struct xfrm_mode *mode_map[XFRM_MODE_MAX]; - int (*init_flags)(struct xfrm_state *x); - void (*init_tempsel)(struct xfrm_selector *sel, - const struct flowi *fl); - void (*init_temprop)(struct xfrm_state *x, - const struct xfrm_tmpl *tmpl, - const xfrm_address_t *daddr, - const xfrm_address_t *saddr); - int (*tmpl_sort)(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n); - int (*state_sort)(struct xfrm_state **dst, struct xfrm_state **src, int n); - int (*output)(struct net *net, struct sock *sk, struct sk_buff *skb); - int (*output_finish)(struct sock *sk, struct sk_buff *skb); - int (*extract_input)(struct xfrm_state *x, - struct sk_buff *skb); - int (*extract_output)(struct xfrm_state *x, - struct sk_buff *skb); - int (*transport_finish)(struct sk_buff *skb, - int async); - void (*local_error)(struct sk_buff *skb, u32 mtu); -}; - -int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo); -int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo); -struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); -void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); - -struct xfrm_input_afinfo { - unsigned int family; - struct module *owner; - int (*callback)(struct sk_buff *skb, u8 protocol, - int err); -}; - -int xfrm_input_register_afinfo(struct xfrm_input_afinfo *afinfo); -int xfrm_input_unregister_afinfo(struct xfrm_input_afinfo *afinfo); - -void xfrm_state_delete_tunnel(struct xfrm_state *x); - -struct xfrm_type { - char *description; - struct module *owner; - u8 proto; - u8 flags; -#define XFRM_TYPE_NON_FRAGMENT 1 -#define XFRM_TYPE_REPLAY_PROT 2 -#define XFRM_TYPE_LOCAL_COADDR 4 -#define XFRM_TYPE_REMOTE_COADDR 8 - - int (*init_state)(struct xfrm_state *x); - void (*destructor)(struct xfrm_state *); - int (*input)(struct xfrm_state *, struct sk_buff *skb); - int (*output)(struct xfrm_state *, struct sk_buff *pskb); - int (*reject)(struct xfrm_state *, struct sk_buff *, - const struct flowi *); - int (*hdr_offset)(struct xfrm_state *, struct sk_buff *, u8 **); - /* Estimate maximal size of result of transformation of a dgram */ - u32 (*get_mtu)(struct xfrm_state *, int size); -}; - -int xfrm_register_type(const struct xfrm_type *type, unsigned short family); -int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family); - -struct xfrm_mode { - /* - * Remove encapsulation header. - * - * The IP header will be moved over the top of the encapsulation - * header. - * - * On entry, the transport header shall point to where the IP header - * should be and the network header shall be set to where the IP - * header currently is. skb->data shall point to the start of the - * payload. - */ - int (*input2)(struct xfrm_state *x, struct sk_buff *skb); - - /* - * This is the actual input entry point. - * - * For transport mode and equivalent this would be identical to - * input2 (which does not need to be set). While tunnel mode - * and equivalent would set this to the tunnel encapsulation function - * xfrm4_prepare_input that would in turn call input2. - */ - int (*input)(struct xfrm_state *x, struct sk_buff *skb); - - /* - * Add encapsulation header. - * - * On exit, the transport header will be set to the start of the - * encapsulation header to be filled in by x->type->output and - * the mac header will be set to the nextheader (protocol for - * IPv4) field of the extension header directly preceding the - * encapsulation header, or in its absence, that of the top IP - * header. The value of the network header will always point - * to the top IP header while skb->data will point to the payload. - */ - int (*output2)(struct xfrm_state *x,struct sk_buff *skb); - - /* - * This is the actual output entry point. - * - * For transport mode and equivalent this would be identical to - * output2 (which does not need to be set). While tunnel mode - * and equivalent would set this to a tunnel encapsulation function - * (xfrm4_prepare_output or xfrm6_prepare_output) that would in turn - * call output2. - */ - int (*output)(struct xfrm_state *x, struct sk_buff *skb); - - struct xfrm_state_afinfo *afinfo; - struct module *owner; - unsigned int encap; - int flags; -}; - -/* Flags for xfrm_mode. */ -enum { - XFRM_MODE_FLAG_TUNNEL = 1, -}; - -int xfrm_register_mode(struct xfrm_mode *mode, int family); -int xfrm_unregister_mode(struct xfrm_mode *mode, int family); - -static inline int xfrm_af2proto(unsigned int family) -{ - switch(family) { - case AF_INET: - return IPPROTO_IPIP; - case AF_INET6: - return IPPROTO_IPV6; - default: - return 0; - } -} - -static inline struct xfrm_mode *xfrm_ip2inner_mode(struct xfrm_state *x, int ipproto) -{ - if ((ipproto == IPPROTO_IPIP && x->props.family == AF_INET) || - (ipproto == IPPROTO_IPV6 && x->props.family == AF_INET6)) - return x->inner_mode; - else - return x->inner_mode_iaf; -} - -struct xfrm_tmpl { -/* id in template is interpreted as: - * daddr - destination of tunnel, may be zero for transport mode. - * spi - zero to acquire spi. Not zero if spi is static, then - * daddr must be fixed too. - * proto - AH/ESP/IPCOMP - */ - struct xfrm_id id; - -/* Source address of tunnel. Ignored, if it is not a tunnel. */ - xfrm_address_t saddr; - - unsigned short encap_family; - - u32 reqid; - -/* Mode: transport, tunnel etc. */ - u8 mode; - -/* Sharing mode: unique, this session only, this user only etc. */ - u8 share; - -/* May skip this transfomration if no SA is found */ - u8 optional; - -/* Skip aalgos/ealgos/calgos checks. */ - u8 allalgs; - -/* Bit mask of algos allowed for acquisition */ - u32 aalgos; - u32 ealgos; - u32 calgos; -}; - -#define XFRM_MAX_DEPTH 6 - -struct xfrm_policy_walk_entry { - struct list_head all; - u8 dead; -}; - -struct xfrm_policy_walk { - struct xfrm_policy_walk_entry walk; - u8 type; - u32 seq; -}; - -struct xfrm_policy_queue { - struct sk_buff_head hold_queue; - struct timer_list hold_timer; - unsigned long timeout; -}; - -struct xfrm_policy { - possible_net_t xp_net; - struct hlist_node bydst; - struct hlist_node byidx; - - /* This lock only affects elements except for entry. */ - rwlock_t lock; - atomic_t refcnt; - struct timer_list timer; - - struct flow_cache_object flo; - atomic_t genid; - u32 priority; - u32 index; - struct xfrm_mark mark; - struct xfrm_selector selector; - struct xfrm_lifetime_cfg lft; - struct xfrm_lifetime_cur curlft; - struct xfrm_policy_walk_entry walk; - struct xfrm_policy_queue polq; - u8 type; - u8 action; - u8 flags; - u8 xfrm_nr; - u16 family; - struct xfrm_sec_ctx *security; - struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH]; - struct rcu_head rcu; -}; - -static inline struct net *xp_net(const struct xfrm_policy *xp) -{ - return read_pnet(&xp->xp_net); -} - -struct xfrm_kmaddress { - xfrm_address_t local; - xfrm_address_t remote; - u32 reserved; - u16 family; -}; - -struct xfrm_migrate { - xfrm_address_t old_daddr; - xfrm_address_t old_saddr; - xfrm_address_t new_daddr; - xfrm_address_t new_saddr; - u8 proto; - u8 mode; - u16 reserved; - u32 reqid; - u16 old_family; - u16 new_family; -}; - -#define XFRM_KM_TIMEOUT 30 -/* what happened */ -#define XFRM_REPLAY_UPDATE XFRM_AE_CR -#define XFRM_REPLAY_TIMEOUT XFRM_AE_CE - -/* default aevent timeout in units of 100ms */ -#define XFRM_AE_ETIME 10 -/* Async Event timer multiplier */ -#define XFRM_AE_ETH_M 10 -/* default seq threshold size */ -#define XFRM_AE_SEQT_SIZE 2 - -struct xfrm_mgr { - struct list_head list; - char *id; - int (*notify)(struct xfrm_state *x, const struct km_event *c); - int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp); - struct xfrm_policy *(*compile_policy)(struct sock *sk, int opt, u8 *data, int len, int *dir); - int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport); - int (*notify_policy)(struct xfrm_policy *x, int dir, const struct km_event *c); - int (*report)(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr); - int (*migrate)(const struct xfrm_selector *sel, - u8 dir, u8 type, - const struct xfrm_migrate *m, - int num_bundles, - const struct xfrm_kmaddress *k); - bool (*is_alive)(const struct km_event *c); -}; - -int xfrm_register_km(struct xfrm_mgr *km); -int xfrm_unregister_km(struct xfrm_mgr *km); - -struct xfrm_tunnel_skb_cb { - union { - struct inet_skb_parm h4; - struct inet6_skb_parm h6; - } header; - - union { - struct ip_tunnel *ip4; - struct ip6_tnl *ip6; - } tunnel; -}; - -#define XFRM_TUNNEL_SKB_CB(__skb) ((struct xfrm_tunnel_skb_cb *)&((__skb)->cb[0])) - -/* - * This structure is used for the duration where packets are being - * transformed by IPsec. As soon as the packet leaves IPsec the - * area beyond the generic IP part may be overwritten. - */ -struct xfrm_skb_cb { - struct xfrm_tunnel_skb_cb header; - - /* Sequence number for replay protection. */ - union { - struct { - __u32 low; - __u32 hi; - } output; - struct { - __be32 low; - __be32 hi; - } input; - } seq; -}; - -#define XFRM_SKB_CB(__skb) ((struct xfrm_skb_cb *)&((__skb)->cb[0])) - -/* - * This structure is used by the afinfo prepare_input/prepare_output functions - * to transmit header information to the mode input/output functions. - */ -struct xfrm_mode_skb_cb { - struct xfrm_tunnel_skb_cb header; - - /* Copied from header for IPv4, always set to zero and DF for IPv6. */ - __be16 id; - __be16 frag_off; - - /* IP header length (excluding options or extension headers). */ - u8 ihl; - - /* TOS for IPv4, class for IPv6. */ - u8 tos; - - /* TTL for IPv4, hop limitfor IPv6. */ - u8 ttl; - - /* Protocol for IPv4, NH for IPv6. */ - u8 protocol; - - /* Option length for IPv4, zero for IPv6. */ - u8 optlen; - - /* Used by IPv6 only, zero for IPv4. */ - u8 flow_lbl[3]; -}; - -#define XFRM_MODE_SKB_CB(__skb) ((struct xfrm_mode_skb_cb *)&((__skb)->cb[0])) - -/* - * This structure is used by the input processing to locate the SPI and - * related information. - */ -struct xfrm_spi_skb_cb { - struct xfrm_tunnel_skb_cb header; - - unsigned int daddroff; - unsigned int family; -}; - -#define XFRM_SPI_SKB_CB(__skb) ((struct xfrm_spi_skb_cb *)&((__skb)->cb[0])) - -#ifdef CONFIG_AUDITSYSCALL -static inline struct audit_buffer *xfrm_audit_start(const char *op) -{ - struct audit_buffer *audit_buf = NULL; - - if (audit_enabled == 0) - return NULL; - audit_buf = audit_log_start(current->audit_context, GFP_ATOMIC, - AUDIT_MAC_IPSEC_EVENT); - if (audit_buf == NULL) - return NULL; - audit_log_format(audit_buf, "op=%s", op); - return audit_buf; -} - -static inline void xfrm_audit_helper_usrinfo(bool task_valid, - struct audit_buffer *audit_buf) -{ - const unsigned int auid = from_kuid(&init_user_ns, task_valid ? - audit_get_loginuid(current) : - INVALID_UID); - const unsigned int ses = task_valid ? audit_get_sessionid(current) : - (unsigned int) -1; - - audit_log_format(audit_buf, " auid=%u ses=%u", auid, ses); - audit_log_task_context(audit_buf); -} - -void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, bool task_valid); -void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, - bool task_valid); -void xfrm_audit_state_add(struct xfrm_state *x, int result, bool task_valid); -void xfrm_audit_state_delete(struct xfrm_state *x, int result, bool task_valid); -void xfrm_audit_state_replay_overflow(struct xfrm_state *x, - struct sk_buff *skb); -void xfrm_audit_state_replay(struct xfrm_state *x, struct sk_buff *skb, - __be32 net_seq); -void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family); -void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family, __be32 net_spi, - __be32 net_seq); -void xfrm_audit_state_icvfail(struct xfrm_state *x, struct sk_buff *skb, - u8 proto); -#else - -static inline void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, - bool task_valid) -{ -} - -static inline void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, - bool task_valid) -{ -} - -static inline void xfrm_audit_state_add(struct xfrm_state *x, int result, - bool task_valid) -{ -} - -static inline void xfrm_audit_state_delete(struct xfrm_state *x, int result, - bool task_valid) -{ -} - -static inline void xfrm_audit_state_replay_overflow(struct xfrm_state *x, - struct sk_buff *skb) -{ -} - -static inline void xfrm_audit_state_replay(struct xfrm_state *x, - struct sk_buff *skb, __be32 net_seq) -{ -} - -static inline void xfrm_audit_state_notfound_simple(struct sk_buff *skb, - u16 family) -{ -} - -static inline void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family, - __be32 net_spi, __be32 net_seq) -{ -} - -static inline void xfrm_audit_state_icvfail(struct xfrm_state *x, - struct sk_buff *skb, u8 proto) -{ -} -#endif /* CONFIG_AUDITSYSCALL */ - -static inline void xfrm_pol_hold(struct xfrm_policy *policy) -{ - if (likely(policy != NULL)) - atomic_inc(&policy->refcnt); -} - -void xfrm_policy_destroy(struct xfrm_policy *policy); - -static inline void xfrm_pol_put(struct xfrm_policy *policy) -{ - if (atomic_dec_and_test(&policy->refcnt)) - xfrm_policy_destroy(policy); -} - -static inline void xfrm_pols_put(struct xfrm_policy **pols, int npols) -{ - int i; - for (i = npols - 1; i >= 0; --i) - xfrm_pol_put(pols[i]); -} - -void __xfrm_state_destroy(struct xfrm_state *); - -static inline void __xfrm_state_put(struct xfrm_state *x) -{ - atomic_dec(&x->refcnt); -} - -static inline void xfrm_state_put(struct xfrm_state *x) -{ - if (atomic_dec_and_test(&x->refcnt)) - __xfrm_state_destroy(x); -} - -static inline void xfrm_state_hold(struct xfrm_state *x) -{ - atomic_inc(&x->refcnt); -} - -static inline bool addr_match(const void *token1, const void *token2, - int prefixlen) -{ - const __be32 *a1 = token1; - const __be32 *a2 = token2; - int pdw; - int pbi; - - pdw = prefixlen >> 5; /* num of whole u32 in prefix */ - pbi = prefixlen & 0x1f; /* num of bits in incomplete u32 in prefix */ - - if (pdw) - if (memcmp(a1, a2, pdw << 2)) - return false; - - if (pbi) { - __be32 mask; - - mask = htonl((0xffffffff) << (32 - pbi)); - - if ((a1[pdw] ^ a2[pdw]) & mask) - return false; - } - - return true; -} - -static inline bool addr4_match(__be32 a1, __be32 a2, u8 prefixlen) -{ - /* C99 6.5.7 (3): u32 << 32 is undefined behaviour */ - if (prefixlen == 0) - return true; - return !((a1 ^ a2) & htonl(0xFFFFFFFFu << (32 - prefixlen))); -} - -static __inline__ -__be16 xfrm_flowi_sport(const struct flowi *fl, const union flowi_uli *uli) -{ - __be16 port; - switch(fl->flowi_proto) { - case IPPROTO_TCP: - case IPPROTO_UDP: - case IPPROTO_UDPLITE: - case IPPROTO_SCTP: - port = uli->ports.sport; - break; - case IPPROTO_ICMP: - case IPPROTO_ICMPV6: - port = htons(uli->icmpt.type); - break; - case IPPROTO_MH: - port = htons(uli->mht.type); - break; - case IPPROTO_GRE: - port = htons(ntohl(uli->gre_key) >> 16); - break; - default: - port = 0; /*XXX*/ - } - return port; -} - -static __inline__ -__be16 xfrm_flowi_dport(const struct flowi *fl, const union flowi_uli *uli) -{ - __be16 port; - switch(fl->flowi_proto) { - case IPPROTO_TCP: - case IPPROTO_UDP: - case IPPROTO_UDPLITE: - case IPPROTO_SCTP: - port = uli->ports.dport; - break; - case IPPROTO_ICMP: - case IPPROTO_ICMPV6: - port = htons(uli->icmpt.code); - break; - case IPPROTO_GRE: - port = htons(ntohl(uli->gre_key) & 0xffff); - break; - default: - port = 0; /*XXX*/ - } - return port; -} - -bool xfrm_selector_match(const struct xfrm_selector *sel, - const struct flowi *fl, unsigned short family); - -#ifdef CONFIG_SECURITY_NETWORK_XFRM -/* If neither has a context --> match - * Otherwise, both must have a context and the sids, doi, alg must match - */ -static inline bool xfrm_sec_ctx_match(struct xfrm_sec_ctx *s1, struct xfrm_sec_ctx *s2) -{ - return ((!s1 && !s2) || - (s1 && s2 && - (s1->ctx_sid == s2->ctx_sid) && - (s1->ctx_doi == s2->ctx_doi) && - (s1->ctx_alg == s2->ctx_alg))); -} -#else -static inline bool xfrm_sec_ctx_match(struct xfrm_sec_ctx *s1, struct xfrm_sec_ctx *s2) -{ - return true; -} -#endif - -/* A struct encoding bundle of transformations to apply to some set of flow. - * - * dst->child points to the next element of bundle. - * dst->xfrm points to an instanse of transformer. - * - * Due to unfortunate limitations of current routing cache, which we - * have no time to fix, it mirrors struct rtable and bound to the same - * routing key, including saddr,daddr. However, we can have many of - * bundles differing by session id. All the bundles grow from a parent - * policy rule. - */ -struct xfrm_dst { - union { - struct dst_entry dst; - struct rtable rt; - struct rt6_info rt6; - } u; - struct dst_entry *route; - struct flow_cache_object flo; - struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; - int num_pols, num_xfrms; -#ifdef CONFIG_XFRM_SUB_POLICY - struct flowi *origin; - struct xfrm_selector *partner; -#endif - u32 xfrm_genid; - u32 policy_genid; - u32 route_mtu_cached; - u32 child_mtu_cached; - u32 route_cookie; - u32 path_cookie; -}; - -#ifdef CONFIG_XFRM -static inline void xfrm_dst_destroy(struct xfrm_dst *xdst) -{ - xfrm_pols_put(xdst->pols, xdst->num_pols); - dst_release(xdst->route); - if (likely(xdst->u.dst.xfrm)) - xfrm_state_put(xdst->u.dst.xfrm); -#ifdef CONFIG_XFRM_SUB_POLICY - kfree(xdst->origin); - xdst->origin = NULL; - kfree(xdst->partner); - xdst->partner = NULL; -#endif -} -#endif - -void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev); - -struct sec_path { - atomic_t refcnt; - int len; - struct xfrm_state *xvec[XFRM_MAX_DEPTH]; -}; - -static inline int secpath_exists(struct sk_buff *skb) -{ -#ifdef CONFIG_XFRM - return skb->sp != NULL; -#else - return 0; -#endif -} - -static inline struct sec_path * -secpath_get(struct sec_path *sp) -{ - if (sp) - atomic_inc(&sp->refcnt); - return sp; -} - -void __secpath_destroy(struct sec_path *sp); - -static inline void -secpath_put(struct sec_path *sp) -{ - if (sp && atomic_dec_and_test(&sp->refcnt)) - __secpath_destroy(sp); -} - -struct sec_path *secpath_dup(struct sec_path *src); - -static inline void -secpath_reset(struct sk_buff *skb) -{ -#ifdef CONFIG_XFRM - secpath_put(skb->sp); - skb->sp = NULL; -#endif -} - -static inline int -xfrm_addr_any(const xfrm_address_t *addr, unsigned short family) -{ - switch (family) { - case AF_INET: - return addr->a4 == 0; - case AF_INET6: - return ipv6_addr_any(&addr->in6); - } - return 0; -} - -static inline int -__xfrm4_state_addr_cmp(const struct xfrm_tmpl *tmpl, const struct xfrm_state *x) -{ - return (tmpl->saddr.a4 && - tmpl->saddr.a4 != x->props.saddr.a4); -} - -static inline int -__xfrm6_state_addr_cmp(const struct xfrm_tmpl *tmpl, const struct xfrm_state *x) -{ - return (!ipv6_addr_any((struct in6_addr*)&tmpl->saddr) && - !ipv6_addr_equal((struct in6_addr *)&tmpl->saddr, (struct in6_addr*)&x->props.saddr)); -} - -static inline int -xfrm_state_addr_cmp(const struct xfrm_tmpl *tmpl, const struct xfrm_state *x, unsigned short family) -{ - switch (family) { - case AF_INET: - return __xfrm4_state_addr_cmp(tmpl, x); - case AF_INET6: - return __xfrm6_state_addr_cmp(tmpl, x); - } - return !0; -} - -#ifdef CONFIG_XFRM -int __xfrm_policy_check(struct sock *, int dir, struct sk_buff *skb, - unsigned short family); - -static inline int __xfrm_policy_check2(struct sock *sk, int dir, - struct sk_buff *skb, - unsigned int family, int reverse) -{ - struct net *net = dev_net(skb->dev); - int ndir = dir | (reverse ? XFRM_POLICY_MASK + 1 : 0); - - if (sk && sk->sk_policy[XFRM_POLICY_IN]) - return __xfrm_policy_check(sk, ndir, skb, family); - - return (!net->xfrm.policy_count[dir] && !skb->sp) || - (skb_dst(skb)->flags & DST_NOPOLICY) || - __xfrm_policy_check(sk, ndir, skb, family); -} - -static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, unsigned short family) -{ - return __xfrm_policy_check2(sk, dir, skb, family, 0); -} - -static inline int xfrm4_policy_check(struct sock *sk, int dir, struct sk_buff *skb) -{ - return xfrm_policy_check(sk, dir, skb, AF_INET); -} - -static inline int xfrm6_policy_check(struct sock *sk, int dir, struct sk_buff *skb) -{ - return xfrm_policy_check(sk, dir, skb, AF_INET6); -} - -static inline int xfrm4_policy_check_reverse(struct sock *sk, int dir, - struct sk_buff *skb) -{ - return __xfrm_policy_check2(sk, dir, skb, AF_INET, 1); -} - -static inline int xfrm6_policy_check_reverse(struct sock *sk, int dir, - struct sk_buff *skb) -{ - return __xfrm_policy_check2(sk, dir, skb, AF_INET6, 1); -} - -int __xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, - unsigned int family, int reverse); - -static inline int xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, - unsigned int family) -{ - return __xfrm_decode_session(skb, fl, family, 0); -} - -static inline int xfrm_decode_session_reverse(struct sk_buff *skb, - struct flowi *fl, - unsigned int family) -{ - return __xfrm_decode_session(skb, fl, family, 1); -} - -int __xfrm_route_forward(struct sk_buff *skb, unsigned short family); - -static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family) -{ - struct net *net = dev_net(skb->dev); - - return !net->xfrm.policy_count[XFRM_POLICY_OUT] || - (skb_dst(skb)->flags & DST_NOXFRM) || - __xfrm_route_forward(skb, family); -} - -static inline int xfrm4_route_forward(struct sk_buff *skb) -{ - return xfrm_route_forward(skb, AF_INET); -} - -static inline int xfrm6_route_forward(struct sk_buff *skb) -{ - return xfrm_route_forward(skb, AF_INET6); -} - -int __xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk); - -static inline int xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk) -{ - sk->sk_policy[0] = NULL; - sk->sk_policy[1] = NULL; - if (unlikely(osk->sk_policy[0] || osk->sk_policy[1])) - return __xfrm_sk_clone_policy(sk, osk); - return 0; -} - -int xfrm_policy_delete(struct xfrm_policy *pol, int dir); - -static inline void xfrm_sk_free_policy(struct sock *sk) -{ - struct xfrm_policy *pol; - - pol = rcu_dereference_protected(sk->sk_policy[0], 1); - if (unlikely(pol != NULL)) { - xfrm_policy_delete(pol, XFRM_POLICY_MAX); - sk->sk_policy[0] = NULL; - } - pol = rcu_dereference_protected(sk->sk_policy[1], 1); - if (unlikely(pol != NULL)) { - xfrm_policy_delete(pol, XFRM_POLICY_MAX+1); - sk->sk_policy[1] = NULL; - } -} - -void xfrm_garbage_collect(struct net *net); - -#else - -static inline void xfrm_sk_free_policy(struct sock *sk) {} -static inline int xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk) { return 0; } -static inline int xfrm6_route_forward(struct sk_buff *skb) { return 1; } -static inline int xfrm4_route_forward(struct sk_buff *skb) { return 1; } -static inline int xfrm6_policy_check(struct sock *sk, int dir, struct sk_buff *skb) -{ - return 1; -} -static inline int xfrm4_policy_check(struct sock *sk, int dir, struct sk_buff *skb) -{ - return 1; -} -static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, unsigned short family) -{ - return 1; -} -static inline int xfrm_decode_session_reverse(struct sk_buff *skb, - struct flowi *fl, - unsigned int family) -{ - return -ENOSYS; -} -static inline int xfrm4_policy_check_reverse(struct sock *sk, int dir, - struct sk_buff *skb) -{ - return 1; -} -static inline int xfrm6_policy_check_reverse(struct sock *sk, int dir, - struct sk_buff *skb) -{ - return 1; -} -static inline void xfrm_garbage_collect(struct net *net) -{ -} -#endif - -static __inline__ -xfrm_address_t *xfrm_flowi_daddr(const struct flowi *fl, unsigned short family) -{ - switch (family){ - case AF_INET: - return (xfrm_address_t *)&fl->u.ip4.daddr; - case AF_INET6: - return (xfrm_address_t *)&fl->u.ip6.daddr; - } - return NULL; -} - -static __inline__ -xfrm_address_t *xfrm_flowi_saddr(const struct flowi *fl, unsigned short family) -{ - switch (family){ - case AF_INET: - return (xfrm_address_t *)&fl->u.ip4.saddr; - case AF_INET6: - return (xfrm_address_t *)&fl->u.ip6.saddr; - } - return NULL; -} - -static __inline__ -void xfrm_flowi_addr_get(const struct flowi *fl, - xfrm_address_t *saddr, xfrm_address_t *daddr, - unsigned short family) -{ - switch(family) { - case AF_INET: - memcpy(&saddr->a4, &fl->u.ip4.saddr, sizeof(saddr->a4)); - memcpy(&daddr->a4, &fl->u.ip4.daddr, sizeof(daddr->a4)); - break; - case AF_INET6: - saddr->in6 = fl->u.ip6.saddr; - daddr->in6 = fl->u.ip6.daddr; - break; - } -} - -static __inline__ int -__xfrm4_state_addr_check(const struct xfrm_state *x, - const xfrm_address_t *daddr, const xfrm_address_t *saddr) -{ - if (daddr->a4 == x->id.daddr.a4 && - (saddr->a4 == x->props.saddr.a4 || !saddr->a4 || !x->props.saddr.a4)) - return 1; - return 0; -} - -static __inline__ int -__xfrm6_state_addr_check(const struct xfrm_state *x, - const xfrm_address_t *daddr, const xfrm_address_t *saddr) -{ - if (ipv6_addr_equal((struct in6_addr *)daddr, (struct in6_addr *)&x->id.daddr) && - (ipv6_addr_equal((struct in6_addr *)saddr, (struct in6_addr *)&x->props.saddr) || - ipv6_addr_any((struct in6_addr *)saddr) || - ipv6_addr_any((struct in6_addr *)&x->props.saddr))) - return 1; - return 0; -} - -static __inline__ int -xfrm_state_addr_check(const struct xfrm_state *x, - const xfrm_address_t *daddr, const xfrm_address_t *saddr, - unsigned short family) -{ - switch (family) { - case AF_INET: - return __xfrm4_state_addr_check(x, daddr, saddr); - case AF_INET6: - return __xfrm6_state_addr_check(x, daddr, saddr); - } - return 0; -} - -static __inline__ int -xfrm_state_addr_flow_check(const struct xfrm_state *x, const struct flowi *fl, - unsigned short family) -{ - switch (family) { - case AF_INET: - return __xfrm4_state_addr_check(x, - (const xfrm_address_t *)&fl->u.ip4.daddr, - (const xfrm_address_t *)&fl->u.ip4.saddr); - case AF_INET6: - return __xfrm6_state_addr_check(x, - (const xfrm_address_t *)&fl->u.ip6.daddr, - (const xfrm_address_t *)&fl->u.ip6.saddr); - } - return 0; -} - -static inline int xfrm_state_kern(const struct xfrm_state *x) -{ - return atomic_read(&x->tunnel_users); -} - -static inline int xfrm_id_proto_match(u8 proto, u8 userproto) -{ - return (!userproto || proto == userproto || - (userproto == IPSEC_PROTO_ANY && (proto == IPPROTO_AH || - proto == IPPROTO_ESP || - proto == IPPROTO_COMP))); -} - -/* - * xfrm algorithm information - */ -struct xfrm_algo_aead_info { - char *geniv; - u16 icv_truncbits; -}; - -struct xfrm_algo_auth_info { - u16 icv_truncbits; - u16 icv_fullbits; -}; - -struct xfrm_algo_encr_info { - char *geniv; - u16 blockbits; - u16 defkeybits; -}; - -struct xfrm_algo_comp_info { - u16 threshold; -}; - -struct xfrm_algo_desc { - char *name; - char *compat; - u8 available:1; - u8 pfkey_supported:1; - union { - struct xfrm_algo_aead_info aead; - struct xfrm_algo_auth_info auth; - struct xfrm_algo_encr_info encr; - struct xfrm_algo_comp_info comp; - } uinfo; - struct sadb_alg desc; -}; - -/* XFRM protocol handlers. */ -struct xfrm4_protocol { - int (*handler)(struct sk_buff *skb); - int (*input_handler)(struct sk_buff *skb, int nexthdr, __be32 spi, - int encap_type); - int (*cb_handler)(struct sk_buff *skb, int err); - int (*err_handler)(struct sk_buff *skb, u32 info); - - struct xfrm4_protocol __rcu *next; - int priority; -}; - -struct xfrm6_protocol { - int (*handler)(struct sk_buff *skb); - int (*cb_handler)(struct sk_buff *skb, int err); - int (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, - u8 type, u8 code, int offset, __be32 info); - - struct xfrm6_protocol __rcu *next; - int priority; -}; - -/* XFRM tunnel handlers. */ -struct xfrm_tunnel { - int (*handler)(struct sk_buff *skb); - int (*err_handler)(struct sk_buff *skb, u32 info); - - struct xfrm_tunnel __rcu *next; - int priority; -}; - -struct xfrm6_tunnel { - int (*handler)(struct sk_buff *skb); - int (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, - u8 type, u8 code, int offset, __be32 info); - struct xfrm6_tunnel __rcu *next; - int priority; -}; - -void xfrm_init(void); -void xfrm4_init(void); -int xfrm_state_init(struct net *net); -void xfrm_state_fini(struct net *net); -void xfrm4_state_init(void); -void xfrm4_protocol_init(void); -#ifdef CONFIG_XFRM -int xfrm6_init(void); -void xfrm6_fini(void); -int xfrm6_state_init(void); -void xfrm6_state_fini(void); -int xfrm6_protocol_init(void); -void xfrm6_protocol_fini(void); -#else -static inline int xfrm6_init(void) -{ - return 0; -} -static inline void xfrm6_fini(void) -{ - ; -} -#endif - -#ifdef CONFIG_XFRM_STATISTICS -int xfrm_proc_init(struct net *net); -void xfrm_proc_fini(struct net *net); -#endif - -int xfrm_sysctl_init(struct net *net); -#ifdef CONFIG_SYSCTL -void xfrm_sysctl_fini(struct net *net); -#else -static inline void xfrm_sysctl_fini(struct net *net) -{ -} -#endif - -void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto, - struct xfrm_address_filter *filter); -int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, - int (*func)(struct xfrm_state *, int, void*), void *); -void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net); -struct xfrm_state *xfrm_state_alloc(struct net *net); -struct xfrm_state *xfrm_state_find(const xfrm_address_t *daddr, - const xfrm_address_t *saddr, - const struct flowi *fl, - struct xfrm_tmpl *tmpl, - struct xfrm_policy *pol, int *err, - unsigned short family); -struct xfrm_state *xfrm_stateonly_find(struct net *net, u32 mark, - xfrm_address_t *daddr, - xfrm_address_t *saddr, - unsigned short family, - u8 mode, u8 proto, u32 reqid); -struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi, - unsigned short family); -int xfrm_state_check_expire(struct xfrm_state *x); -void xfrm_state_insert(struct xfrm_state *x); -int xfrm_state_add(struct xfrm_state *x); -int xfrm_state_update(struct xfrm_state *x); -struct xfrm_state *xfrm_state_lookup(struct net *net, u32 mark, - const xfrm_address_t *daddr, __be32 spi, - u8 proto, unsigned short family); -struct xfrm_state *xfrm_state_lookup_byaddr(struct net *net, u32 mark, - const xfrm_address_t *daddr, - const xfrm_address_t *saddr, - u8 proto, - unsigned short family); -#ifdef CONFIG_XFRM_SUB_POLICY -int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, - unsigned short family, struct net *net); -int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, - unsigned short family); -#else -static inline int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, - int n, unsigned short family, struct net *net) -{ - return -ENOSYS; -} - -static inline int xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, - int n, unsigned short family) -{ - return -ENOSYS; -} -#endif - -struct xfrmk_sadinfo { - u32 sadhcnt; /* current hash bkts */ - u32 sadhmcnt; /* max allowed hash bkts */ - u32 sadcnt; /* current running count */ -}; - -struct xfrmk_spdinfo { - u32 incnt; - u32 outcnt; - u32 fwdcnt; - u32 inscnt; - u32 outscnt; - u32 fwdscnt; - u32 spdhcnt; - u32 spdhmcnt; -}; - -struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq); -int xfrm_state_delete(struct xfrm_state *x); -int xfrm_state_flush(struct net *net, u8 proto, bool task_valid); -void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si); -void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si); -u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq); -int xfrm_init_replay(struct xfrm_state *x); -int xfrm_state_mtu(struct xfrm_state *x, int mtu); -int __xfrm_init_state(struct xfrm_state *x, bool init_replay); -int xfrm_init_state(struct xfrm_state *x); -int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb); -int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type); -int xfrm_input_resume(struct sk_buff *skb, int nexthdr); -int xfrm_output_resume(struct sk_buff *skb, int err); -int xfrm_output(struct sock *sk, struct sk_buff *skb); -int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb); -void xfrm_local_error(struct sk_buff *skb, int mtu); -int xfrm4_extract_header(struct sk_buff *skb); -int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb); -int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, - int encap_type); -int xfrm4_transport_finish(struct sk_buff *skb, int async); -int xfrm4_rcv(struct sk_buff *skb); - -static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) -{ - XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; - XFRM_SPI_SKB_CB(skb)->family = AF_INET; - XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); - return xfrm_input(skb, nexthdr, spi, 0); -} - -int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb); -int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb); -int xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb); -int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb); -int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err); -int xfrm4_protocol_register(struct xfrm4_protocol *handler, unsigned char protocol); -int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, unsigned char protocol); -int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family); -int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family); -void xfrm4_local_error(struct sk_buff *skb, u32 mtu); -int xfrm6_extract_header(struct sk_buff *skb); -int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb); -int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi, - struct ip6_tnl *t); -int xfrm6_transport_finish(struct sk_buff *skb, int async); -int xfrm6_rcv_tnl(struct sk_buff *skb, struct ip6_tnl *t); -int xfrm6_rcv(struct sk_buff *skb); -int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, - xfrm_address_t *saddr, u8 proto); -void xfrm6_local_error(struct sk_buff *skb, u32 mtu); -int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err); -int xfrm6_protocol_register(struct xfrm6_protocol *handler, unsigned char protocol); -int xfrm6_protocol_deregister(struct xfrm6_protocol *handler, unsigned char protocol); -int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family); -int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family); -__be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr); -__be32 xfrm6_tunnel_spi_lookup(struct net *net, const xfrm_address_t *saddr); -int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb); -int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb); -int xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb); -int xfrm6_output_finish(struct sock *sk, struct sk_buff *skb); -int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, - u8 **prevhdr); - -#ifdef CONFIG_XFRM -int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb); -int xfrm_user_policy(struct sock *sk, int optname, - u8 __user *optval, int optlen); -#else -static inline int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) -{ - return -ENOPROTOOPT; -} - -static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb) -{ - /* should not happen */ - kfree_skb(skb); - return 0; -} -#endif - -struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp); - -void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type); -int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, - int (*func)(struct xfrm_policy *, int, int, void*), - void *); -void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net); -int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); -struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, - u8 type, int dir, - struct xfrm_selector *sel, - struct xfrm_sec_ctx *ctx, int delete, - int *err); -struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8, int dir, - u32 id, int delete, int *err); -int xfrm_policy_flush(struct net *net, u8 type, bool task_valid); -void xfrm_policy_hash_rebuild(struct net *net); -u32 xfrm_get_acqseq(void); -int verify_spi_info(u8 proto, u32 min, u32 max); -int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi); -struct xfrm_state *xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, - u8 mode, u32 reqid, u8 proto, - const xfrm_address_t *daddr, - const xfrm_address_t *saddr, int create, - unsigned short family); -int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); - -#ifdef CONFIG_XFRM_MIGRATE -int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, - const struct xfrm_migrate *m, int num_bundles, - const struct xfrm_kmaddress *k); -struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net); -struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x, - struct xfrm_migrate *m); -int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, - struct xfrm_migrate *m, int num_bundles, - struct xfrm_kmaddress *k, struct net *net); -#endif - -int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport); -void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid); -int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, - xfrm_address_t *addr); - -void xfrm_input_init(void); -int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq); - -void xfrm_probe_algs(void); -int xfrm_count_pfkey_auth_supported(void); -int xfrm_count_pfkey_enc_supported(void); -struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx); -struct xfrm_algo_desc *xfrm_ealg_get_byidx(unsigned int idx); -struct xfrm_algo_desc *xfrm_aalg_get_byid(int alg_id); -struct xfrm_algo_desc *xfrm_ealg_get_byid(int alg_id); -struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id); -struct xfrm_algo_desc *xfrm_aalg_get_byname(const char *name, int probe); -struct xfrm_algo_desc *xfrm_ealg_get_byname(const char *name, int probe); -struct xfrm_algo_desc *xfrm_calg_get_byname(const char *name, int probe); -struct xfrm_algo_desc *xfrm_aead_get_byname(const char *name, int icv_len, - int probe); - -static inline bool xfrm6_addr_equal(const xfrm_address_t *a, - const xfrm_address_t *b) -{ - return ipv6_addr_equal((const struct in6_addr *)a, - (const struct in6_addr *)b); -} - -static inline bool xfrm_addr_equal(const xfrm_address_t *a, - const xfrm_address_t *b, - sa_family_t family) -{ - switch (family) { - default: - case AF_INET: - return ((__force u32)a->a4 ^ (__force u32)b->a4) == 0; - case AF_INET6: - return xfrm6_addr_equal(a, b); - } -} - -static inline int xfrm_policy_id2dir(u32 index) -{ - return index & 7; -} - -#ifdef CONFIG_XFRM -static inline int xfrm_aevent_is_on(struct net *net) -{ - struct sock *nlsk; - int ret = 0; - - rcu_read_lock(); - nlsk = rcu_dereference(net->xfrm.nlsk); - if (nlsk) - ret = netlink_has_listeners(nlsk, XFRMNLGRP_AEVENTS); - rcu_read_unlock(); - return ret; -} - -static inline int xfrm_acquire_is_on(struct net *net) -{ - struct sock *nlsk; - int ret = 0; - - rcu_read_lock(); - nlsk = rcu_dereference(net->xfrm.nlsk); - if (nlsk) - ret = netlink_has_listeners(nlsk, XFRMNLGRP_ACQUIRE); - rcu_read_unlock(); - - return ret; -} -#endif - -static inline int aead_len(struct xfrm_algo_aead *alg) -{ - return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); -} - -static inline int xfrm_alg_len(const struct xfrm_algo *alg) -{ - return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); -} - -static inline int xfrm_alg_auth_len(const struct xfrm_algo_auth *alg) -{ - return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); -} - -static inline int xfrm_replay_state_esn_len(struct xfrm_replay_state_esn *replay_esn) -{ - return sizeof(*replay_esn) + replay_esn->bmp_len * sizeof(__u32); -} - -#ifdef CONFIG_XFRM_MIGRATE -static inline int xfrm_replay_clone(struct xfrm_state *x, - struct xfrm_state *orig) -{ - x->replay_esn = kzalloc(xfrm_replay_state_esn_len(orig->replay_esn), - GFP_KERNEL); - if (!x->replay_esn) - return -ENOMEM; - - x->replay_esn->bmp_len = orig->replay_esn->bmp_len; - x->replay_esn->replay_window = orig->replay_esn->replay_window; - - x->preplay_esn = kmemdup(x->replay_esn, - xfrm_replay_state_esn_len(x->replay_esn), - GFP_KERNEL); - if (!x->preplay_esn) { - kfree(x->replay_esn); - return -ENOMEM; - } - - return 0; -} - -static inline struct xfrm_algo_aead *xfrm_algo_aead_clone(struct xfrm_algo_aead *orig) -{ - return kmemdup(orig, aead_len(orig), GFP_KERNEL); -} - - -static inline struct xfrm_algo *xfrm_algo_clone(struct xfrm_algo *orig) -{ - return kmemdup(orig, xfrm_alg_len(orig), GFP_KERNEL); -} - -static inline struct xfrm_algo_auth *xfrm_algo_auth_clone(struct xfrm_algo_auth *orig) -{ - return kmemdup(orig, xfrm_alg_auth_len(orig), GFP_KERNEL); -} - -static inline void xfrm_states_put(struct xfrm_state **states, int n) -{ - int i; - for (i = 0; i < n; i++) - xfrm_state_put(*(states + i)); -} - -static inline void xfrm_states_delete(struct xfrm_state **states, int n) -{ - int i; - for (i = 0; i < n; i++) - xfrm_state_delete(*(states + i)); -} -#endif - -#ifdef CONFIG_XFRM -static inline struct xfrm_state *xfrm_input_state(struct sk_buff *skb) -{ - return skb->sp->xvec[skb->sp->len - 1]; -} -#endif - -static inline int xfrm_mark_get(struct nlattr **attrs, struct xfrm_mark *m) -{ - if (attrs[XFRMA_MARK]) - memcpy(m, nla_data(attrs[XFRMA_MARK]), sizeof(struct xfrm_mark)); - else - m->v = m->m = 0; - - return m->v & m->m; -} - -static inline int xfrm_mark_put(struct sk_buff *skb, const struct xfrm_mark *m) -{ - int ret = 0; - - if (m->m | m->v) - ret = nla_put(skb, XFRMA_MARK, sizeof(struct xfrm_mark), m); - return ret; -} - -static inline int xfrm_tunnel_check(struct sk_buff *skb, struct xfrm_state *x, - unsigned int family) -{ - bool tunnel = false; - - switch(family) { - case AF_INET: - if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4) - tunnel = true; - break; - case AF_INET6: - if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6) - tunnel = true; - break; - } - if (tunnel && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL)) - return -EINVAL; - - return 0; -} -#endif /* _NET_XFRM_H */ diff --git a/src/linux/include/scsi/fc/fc_fcoe.h b/src/linux/include/scsi/fc/fc_fcoe.h deleted file mode 100644 index d5dcd60..0000000 --- a/src/linux/include/scsi/fc/fc_fcoe.h +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright(c) 2007 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - * Maintained at www.Open-FCoE.org - */ - -#ifndef _FC_FCOE_H_ -#define _FC_FCOE_H_ - -/* - * FCoE - Fibre Channel over Ethernet. - * See T11 FC-BB-5 Rev 2.00 (09-056v5.pdf) - */ - -/* - * Default FC_FCOE_OUI / FC-MAP value. - */ -#define FC_FCOE_OUI 0x0efc00 /* upper 24 bits of FCOE MAC */ - -/* - * Fabric Login (FLOGI) MAC for non-FIP use. Non-FIP use is deprecated. - */ -#define FC_FCOE_FLOGI_MAC { 0x0e, 0xfc, 0x00, 0xff, 0xff, 0xfe } - -#define FC_FCOE_VER 0 /* version */ - -/* - * Ethernet Addresses based on FC S_ID and D_ID. - * Generated by FC_FCOE_OUI | S_ID/D_ID - */ -#define FC_FCOE_ENCAPS_ID(n) (((u64) FC_FCOE_OUI << 24) | (n)) -#define FC_FCOE_DECAPS_ID(n) ((n) >> 24) - -/* - * FCoE frame header - 14 bytes - * This follows the VLAN header, which includes the ethertype. - */ -struct fcoe_hdr { - __u8 fcoe_ver; /* version field - upper 4 bits */ - __u8 fcoe_resvd[12]; /* reserved - send zero and ignore */ - __u8 fcoe_sof; /* start of frame per RFC 3643 */ -}; - -#define FC_FCOE_DECAPS_VER(hp) ((hp)->fcoe_ver >> 4) -#define FC_FCOE_ENCAPS_VER(hp, ver) ((hp)->fcoe_ver = (ver) << 4) - -/* - * FCoE CRC & EOF - 8 bytes. - */ -struct fcoe_crc_eof { - __le32 fcoe_crc32; /* CRC for FC packet */ - __u8 fcoe_eof; /* EOF from RFC 3643 */ - __u8 fcoe_resvd[3]; /* reserved - send zero and ignore */ -} __attribute__((packed)); - -/* - * Minimum FCoE + FC header length - * 14 bytes FCoE header + 24 byte FC header = 38 bytes - */ -#define FCOE_HEADER_LEN 38 - -/* - * Minimum FCoE frame size - * 14 bytes FCoE header + 24 byte FC header + 8 byte FCoE trailer = 46 bytes - */ -#define FCOE_MIN_FRAME 46 - -/* - * FCoE Link Error Status Block: T11 FC-BB-5 Rev2.0, Clause 7.10. - */ -struct fcoe_fc_els_lesb { - __be32 lesb_link_fail; /* link failure count */ - __be32 lesb_vlink_fail; /* virtual link failure count */ - __be32 lesb_miss_fka; /* missing FIP keep-alive count */ - __be32 lesb_symb_err; /* symbol error during carrier count */ - __be32 lesb_err_block; /* errored block count */ - __be32 lesb_fcs_error; /* frame check sequence error count */ -}; - -/* - * fc_fcoe_set_mac - Store OUI + DID into MAC address field. - * @mac: mac address to be set - * @did: fc dest id to use - */ -static inline void fc_fcoe_set_mac(u8 *mac, u8 *did) -{ - mac[0] = (u8) (FC_FCOE_OUI >> 16); - mac[1] = (u8) (FC_FCOE_OUI >> 8); - mac[2] = (u8) FC_FCOE_OUI; - mac[3] = did[0]; - mac[4] = did[1]; - mac[5] = did[2]; -} - -#endif /* _FC_FCOE_H_ */ diff --git a/src/linux/include/scsi/scsi.h b/src/linux/include/scsi/scsi.h deleted file mode 100644 index 8ec7c30..0000000 --- a/src/linux/include/scsi/scsi.h +++ /dev/null @@ -1,290 +0,0 @@ -/* - * This header file contains public constants and structures used by - * the SCSI initiator code. - */ -#ifndef _SCSI_SCSI_H -#define _SCSI_SCSI_H - -#include -#include -#include -#include -#include - -struct scsi_cmnd; - -enum scsi_timeouts { - SCSI_DEFAULT_EH_TIMEOUT = 10 * HZ, -}; - -/* - * DIX-capable adapters effectively support infinite chaining for the - * protection information scatterlist - */ -#define SCSI_MAX_PROT_SG_SEGMENTS 0xFFFF - -/* - * Special value for scanning to specify scanning or rescanning of all - * possible channels, (target) ids, or luns on a given shost. - */ -#define SCAN_WILD_CARD ~0 - -#ifdef CONFIG_ACPI -struct acpi_bus_type; - -extern int -scsi_register_acpi_bus_type(struct acpi_bus_type *bus); - -extern void -scsi_unregister_acpi_bus_type(struct acpi_bus_type *bus); -#endif - -/** scsi_status_is_good - check the status return. - * - * @status: the status passed up from the driver (including host and - * driver components) - * - * This returns true for known good conditions that may be treated as - * command completed normally - */ -static inline int scsi_status_is_good(int status) -{ - /* - * FIXME: bit0 is listed as reserved in SCSI-2, but is - * significant in SCSI-3. For now, we follow the SCSI-2 - * behaviour and ignore reserved bits. - */ - status &= 0xfe; - return ((status == SAM_STAT_GOOD) || - (status == SAM_STAT_INTERMEDIATE) || - (status == SAM_STAT_INTERMEDIATE_CONDITION_MET) || - /* FIXME: this is obsolete in SAM-3 */ - (status == SAM_STAT_COMMAND_TERMINATED)); -} - - -/* - * standard mode-select header prepended to all mode-select commands - */ - -struct ccs_modesel_head { - __u8 _r1; /* reserved */ - __u8 medium; /* device-specific medium type */ - __u8 _r2; /* reserved */ - __u8 block_desc_length; /* block descriptor length */ - __u8 density; /* device-specific density code */ - __u8 number_blocks_hi; /* number of blocks in this block desc */ - __u8 number_blocks_med; - __u8 number_blocks_lo; - __u8 _r3; - __u8 block_length_hi; /* block length for blocks in this desc */ - __u8 block_length_med; - __u8 block_length_lo; -}; - -/* - * The Well Known LUNS (SAM-3) in our int representation of a LUN - */ -#define SCSI_W_LUN_BASE 0xc100 -#define SCSI_W_LUN_REPORT_LUNS (SCSI_W_LUN_BASE + 1) -#define SCSI_W_LUN_ACCESS_CONTROL (SCSI_W_LUN_BASE + 2) -#define SCSI_W_LUN_TARGET_LOG_PAGE (SCSI_W_LUN_BASE + 3) - -static inline int scsi_is_wlun(u64 lun) -{ - return (lun & 0xff00) == SCSI_W_LUN_BASE; -} - - -/* - * MESSAGE CODES - */ - -#define COMMAND_COMPLETE 0x00 -#define EXTENDED_MESSAGE 0x01 -#define EXTENDED_MODIFY_DATA_POINTER 0x00 -#define EXTENDED_SDTR 0x01 -#define EXTENDED_EXTENDED_IDENTIFY 0x02 /* SCSI-I only */ -#define EXTENDED_WDTR 0x03 -#define EXTENDED_PPR 0x04 -#define EXTENDED_MODIFY_BIDI_DATA_PTR 0x05 -#define SAVE_POINTERS 0x02 -#define RESTORE_POINTERS 0x03 -#define DISCONNECT 0x04 -#define INITIATOR_ERROR 0x05 -#define ABORT_TASK_SET 0x06 -#define MESSAGE_REJECT 0x07 -#define NOP 0x08 -#define MSG_PARITY_ERROR 0x09 -#define LINKED_CMD_COMPLETE 0x0a -#define LINKED_FLG_CMD_COMPLETE 0x0b -#define TARGET_RESET 0x0c -#define ABORT_TASK 0x0d -#define CLEAR_TASK_SET 0x0e -#define INITIATE_RECOVERY 0x0f /* SCSI-II only */ -#define RELEASE_RECOVERY 0x10 /* SCSI-II only */ -#define CLEAR_ACA 0x16 -#define LOGICAL_UNIT_RESET 0x17 -#define SIMPLE_QUEUE_TAG 0x20 -#define HEAD_OF_QUEUE_TAG 0x21 -#define ORDERED_QUEUE_TAG 0x22 -#define IGNORE_WIDE_RESIDUE 0x23 -#define ACA 0x24 -#define QAS_REQUEST 0x55 - -/* Old SCSI2 names, don't use in new code */ -#define BUS_DEVICE_RESET TARGET_RESET -#define ABORT ABORT_TASK_SET - -/* - * Host byte codes - */ - -#define DID_OK 0x00 /* NO error */ -#define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */ -#define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */ -#define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */ -#define DID_BAD_TARGET 0x04 /* BAD target. */ -#define DID_ABORT 0x05 /* Told to abort for some other reason */ -#define DID_PARITY 0x06 /* Parity error */ -#define DID_ERROR 0x07 /* Internal error */ -#define DID_RESET 0x08 /* Reset by somebody. */ -#define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */ -#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */ -#define DID_SOFT_ERROR 0x0b /* The low level driver just wish a retry */ -#define DID_IMM_RETRY 0x0c /* Retry without decrementing retry count */ -#define DID_REQUEUE 0x0d /* Requeue command (no immediate retry) also - * without decrementing the retry count */ -#define DID_TRANSPORT_DISRUPTED 0x0e /* Transport error disrupted execution - * and the driver blocked the port to - * recover the link. Transport class will - * retry or fail IO */ -#define DID_TRANSPORT_FAILFAST 0x0f /* Transport class fastfailed the io */ -#define DID_TARGET_FAILURE 0x10 /* Permanent target failure, do not retry on - * other paths */ -#define DID_NEXUS_FAILURE 0x11 /* Permanent nexus failure, retry on other - * paths might yield different results */ -#define DID_ALLOC_FAILURE 0x12 /* Space allocation on the device failed */ -#define DID_MEDIUM_ERROR 0x13 /* Medium error */ -#define DRIVER_OK 0x00 /* Driver status */ - -/* - * These indicate the error that occurred, and what is available. - */ - -#define DRIVER_BUSY 0x01 -#define DRIVER_SOFT 0x02 -#define DRIVER_MEDIA 0x03 -#define DRIVER_ERROR 0x04 - -#define DRIVER_INVALID 0x05 -#define DRIVER_TIMEOUT 0x06 -#define DRIVER_HARD 0x07 -#define DRIVER_SENSE 0x08 - -/* - * Internal return values. - */ - -#define NEEDS_RETRY 0x2001 -#define SUCCESS 0x2002 -#define FAILED 0x2003 -#define QUEUED 0x2004 -#define SOFT_ERROR 0x2005 -#define ADD_TO_MLQUEUE 0x2006 -#define TIMEOUT_ERROR 0x2007 -#define SCSI_RETURN_NOT_HANDLED 0x2008 -#define FAST_IO_FAIL 0x2009 - -/* - * Midlevel queue return values. - */ -#define SCSI_MLQUEUE_HOST_BUSY 0x1055 -#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056 -#define SCSI_MLQUEUE_EH_RETRY 0x1057 -#define SCSI_MLQUEUE_TARGET_BUSY 0x1058 - -/* - * Use these to separate status msg and our bytes - * - * These are set by: - * - * status byte = set from target device - * msg_byte = return status from host adapter itself. - * host_byte = set by low-level driver to indicate status. - * driver_byte = set by mid-level. - */ -#define status_byte(result) (((result) >> 1) & 0x7f) -#define msg_byte(result) (((result) >> 8) & 0xff) -#define host_byte(result) (((result) >> 16) & 0xff) -#define driver_byte(result) (((result) >> 24) & 0xff) - -#define sense_class(sense) (((sense) >> 4) & 0x7) -#define sense_error(sense) ((sense) & 0xf) -#define sense_valid(sense) ((sense) & 0x80) - -/* - * default timeouts -*/ -#define FORMAT_UNIT_TIMEOUT (2 * 60 * 60 * HZ) -#define START_STOP_TIMEOUT (60 * HZ) -#define MOVE_MEDIUM_TIMEOUT (5 * 60 * HZ) -#define READ_ELEMENT_STATUS_TIMEOUT (5 * 60 * HZ) -#define READ_DEFECT_DATA_TIMEOUT (60 * HZ ) - - -#define IDENTIFY_BASE 0x80 -#define IDENTIFY(can_disconnect, lun) (IDENTIFY_BASE |\ - ((can_disconnect) ? 0x40 : 0) |\ - ((lun) & 0x07)) - -/* - * struct scsi_device::scsi_level values. For SCSI devices other than those - * prior to SCSI-2 (i.e. over 12 years old) this value is (resp[2] + 1) - * where "resp" is a byte array of the response to an INQUIRY. The scsi_level - * variable is visible to the user via sysfs. - */ - -#define SCSI_UNKNOWN 0 -#define SCSI_1 1 -#define SCSI_1_CCS 2 -#define SCSI_2 3 -#define SCSI_3 4 /* SPC */ -#define SCSI_SPC_2 5 -#define SCSI_SPC_3 6 - -/* - * INQ PERIPHERAL QUALIFIERS - */ -#define SCSI_INQ_PQ_CON 0x00 -#define SCSI_INQ_PQ_NOT_CON 0x01 -#define SCSI_INQ_PQ_NOT_CAP 0x03 - - -/* - * Here are some scsi specific ioctl commands which are sometimes useful. - * - * Note that include/linux/cdrom.h also defines IOCTL 0x5300 - 0x5395 - */ - -/* Used to obtain PUN and LUN info. Conflicts with CDROMAUDIOBUFSIZ */ -#define SCSI_IOCTL_GET_IDLUN 0x5382 - -/* 0x5383 and 0x5384 were used for SCSI_IOCTL_TAGGED_{ENABLE,DISABLE} */ - -/* Used to obtain the host number of a device. */ -#define SCSI_IOCTL_PROBE_HOST 0x5385 - -/* Used to obtain the bus number for a device */ -#define SCSI_IOCTL_GET_BUS_NUMBER 0x5386 - -/* Used to obtain the PCI location of a device */ -#define SCSI_IOCTL_GET_PCI 0x5387 - -/* Pull a u32 out of a SCSI message (using BE SCSI conventions) */ -static inline __u32 scsi_to_u32(__u8 *ptr) -{ - return (ptr[0]<<24) + (ptr[1]<<16) + (ptr[2]<<8) + ptr[3]; -} - -#endif /* _SCSI_SCSI_H */ diff --git a/src/linux/include/scsi/scsi_cmnd.h b/src/linux/include/scsi/scsi_cmnd.h deleted file mode 100644 index 9fc1aec..0000000 --- a/src/linux/include/scsi/scsi_cmnd.h +++ /dev/null @@ -1,352 +0,0 @@ -#ifndef _SCSI_SCSI_CMND_H -#define _SCSI_SCSI_CMND_H - -#include -#include -#include -#include -#include -#include -#include - -struct Scsi_Host; -struct scsi_driver; - -#include - -/* - * MAX_COMMAND_SIZE is: - * The longest fixed-length SCSI CDB as per the SCSI standard. - * fixed-length means: commands that their size can be determined - * by their opcode and the CDB does not carry a length specifier, (unlike - * the VARIABLE_LENGTH_CMD(0x7f) command). This is actually not exactly - * true and the SCSI standard also defines extended commands and - * vendor specific commands that can be bigger than 16 bytes. The kernel - * will support these using the same infrastructure used for VARLEN CDB's. - * So in effect MAX_COMMAND_SIZE means the maximum size command scsi-ml - * supports without specifying a cmd_len by ULD's - */ -#define MAX_COMMAND_SIZE 16 -#if (MAX_COMMAND_SIZE > BLK_MAX_CDB) -# error MAX_COMMAND_SIZE can not be bigger than BLK_MAX_CDB -#endif - -struct scsi_data_buffer { - struct sg_table table; - unsigned length; - int resid; -}; - -/* embedded in scsi_cmnd */ -struct scsi_pointer { - char *ptr; /* data pointer */ - int this_residual; /* left in this buffer */ - struct scatterlist *buffer; /* which buffer */ - int buffers_residual; /* how many buffers left */ - - dma_addr_t dma_handle; - - volatile int Status; - volatile int Message; - volatile int have_data_in; - volatile int sent_command; - volatile int phase; -}; - -/* for scmd->flags */ -#define SCMD_TAGGED (1 << 0) - -struct scsi_cmnd { - struct scsi_device *device; - struct list_head list; /* scsi_cmnd participates in queue lists */ - struct list_head eh_entry; /* entry for the host eh_cmd_q */ - struct delayed_work abort_work; - int eh_eflags; /* Used by error handlr */ - - /* - * A SCSI Command is assigned a nonzero serial_number before passed - * to the driver's queue command function. The serial_number is - * cleared when scsi_done is entered indicating that the command - * has been completed. It is a bug for LLDDs to use this number - * for purposes other than printk (and even that is only useful - * for debugging). - */ - unsigned long serial_number; - - /* - * This is set to jiffies as it was when the command was first - * allocated. It is used to time how long the command has - * been outstanding - */ - unsigned long jiffies_at_alloc; - - int retries; - int allowed; - - unsigned char prot_op; - unsigned char prot_type; - unsigned char prot_flags; - - unsigned short cmd_len; - enum dma_data_direction sc_data_direction; - - /* These elements define the operation we are about to perform */ - unsigned char *cmnd; - - - /* These elements define the operation we ultimately want to perform */ - struct scsi_data_buffer sdb; - struct scsi_data_buffer *prot_sdb; - - unsigned underflow; /* Return error if less than - this amount is transferred */ - - unsigned transfersize; /* How much we are guaranteed to - transfer with each SCSI transfer - (ie, between disconnect / - reconnects. Probably == sector - size */ - - struct request *request; /* The command we are - working on */ - -#define SCSI_SENSE_BUFFERSIZE 96 - unsigned char *sense_buffer; - /* obtained by REQUEST SENSE when - * CHECK CONDITION is received on original - * command (auto-sense) */ - - /* Low-level done function - can be used by low-level driver to point - * to completion function. Not used by mid/upper level code. */ - void (*scsi_done) (struct scsi_cmnd *); - - /* - * The following fields can be written to by the host specific code. - * Everything else should be left alone. - */ - struct scsi_pointer SCp; /* Scratchpad used by some host adapters */ - - unsigned char *host_scribble; /* The host adapter is allowed to - * call scsi_malloc and get some memory - * and hang it here. The host adapter - * is also expected to call scsi_free - * to release this memory. (The memory - * obtained by scsi_malloc is guaranteed - * to be at an address < 16Mb). */ - - int result; /* Status code from lower level driver */ - int flags; /* Command flags */ - - unsigned char tag; /* SCSI-II queued command tag */ -}; - -/* - * Return the driver private allocation behind the command. - * Only works if cmd_size is set in the host template. - */ -static inline void *scsi_cmd_priv(struct scsi_cmnd *cmd) -{ - return cmd + 1; -} - -/* make sure not to use it with REQ_TYPE_BLOCK_PC commands */ -static inline struct scsi_driver *scsi_cmd_to_driver(struct scsi_cmnd *cmd) -{ - return *(struct scsi_driver **)cmd->request->rq_disk->private_data; -} - -extern struct scsi_cmnd *scsi_get_command(struct scsi_device *, gfp_t); -extern void scsi_put_command(struct scsi_cmnd *); -extern void scsi_finish_command(struct scsi_cmnd *cmd); - -extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count, - size_t *offset, size_t *len); -extern void scsi_kunmap_atomic_sg(void *virt); - -extern int scsi_init_io(struct scsi_cmnd *cmd); - -extern int scsi_dma_map(struct scsi_cmnd *cmd); -extern void scsi_dma_unmap(struct scsi_cmnd *cmd); - -static inline unsigned scsi_sg_count(struct scsi_cmnd *cmd) -{ - return cmd->sdb.table.nents; -} - -static inline struct scatterlist *scsi_sglist(struct scsi_cmnd *cmd) -{ - return cmd->sdb.table.sgl; -} - -static inline unsigned scsi_bufflen(struct scsi_cmnd *cmd) -{ - return cmd->sdb.length; -} - -static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid) -{ - cmd->sdb.resid = resid; -} - -static inline int scsi_get_resid(struct scsi_cmnd *cmd) -{ - return cmd->sdb.resid; -} - -#define scsi_for_each_sg(cmd, sg, nseg, __i) \ - for_each_sg(scsi_sglist(cmd), sg, nseg, __i) - -static inline int scsi_bidi_cmnd(struct scsi_cmnd *cmd) -{ - return blk_bidi_rq(cmd->request) && - (cmd->request->next_rq->special != NULL); -} - -static inline struct scsi_data_buffer *scsi_in(struct scsi_cmnd *cmd) -{ - return scsi_bidi_cmnd(cmd) ? - cmd->request->next_rq->special : &cmd->sdb; -} - -static inline struct scsi_data_buffer *scsi_out(struct scsi_cmnd *cmd) -{ - return &cmd->sdb; -} - -static inline int scsi_sg_copy_from_buffer(struct scsi_cmnd *cmd, - void *buf, int buflen) -{ - return sg_copy_from_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), - buf, buflen); -} - -static inline int scsi_sg_copy_to_buffer(struct scsi_cmnd *cmd, - void *buf, int buflen) -{ - return sg_copy_to_buffer(scsi_sglist(cmd), scsi_sg_count(cmd), - buf, buflen); -} - -/* - * The operations below are hints that tell the controller driver how - * to handle I/Os with DIF or similar types of protection information. - */ -enum scsi_prot_operations { - /* Normal I/O */ - SCSI_PROT_NORMAL = 0, - - /* OS-HBA: Protected, HBA-Target: Unprotected */ - SCSI_PROT_READ_INSERT, - SCSI_PROT_WRITE_STRIP, - - /* OS-HBA: Unprotected, HBA-Target: Protected */ - SCSI_PROT_READ_STRIP, - SCSI_PROT_WRITE_INSERT, - - /* OS-HBA: Protected, HBA-Target: Protected */ - SCSI_PROT_READ_PASS, - SCSI_PROT_WRITE_PASS, -}; - -static inline void scsi_set_prot_op(struct scsi_cmnd *scmd, unsigned char op) -{ - scmd->prot_op = op; -} - -static inline unsigned char scsi_get_prot_op(struct scsi_cmnd *scmd) -{ - return scmd->prot_op; -} - -enum scsi_prot_flags { - SCSI_PROT_TRANSFER_PI = 1 << 0, - SCSI_PROT_GUARD_CHECK = 1 << 1, - SCSI_PROT_REF_CHECK = 1 << 2, - SCSI_PROT_REF_INCREMENT = 1 << 3, - SCSI_PROT_IP_CHECKSUM = 1 << 4, -}; - -/* - * The controller usually does not know anything about the target it - * is communicating with. However, when DIX is enabled the controller - * must be know target type so it can verify the protection - * information passed along with the I/O. - */ -enum scsi_prot_target_type { - SCSI_PROT_DIF_TYPE0 = 0, - SCSI_PROT_DIF_TYPE1, - SCSI_PROT_DIF_TYPE2, - SCSI_PROT_DIF_TYPE3, -}; - -static inline void scsi_set_prot_type(struct scsi_cmnd *scmd, unsigned char type) -{ - scmd->prot_type = type; -} - -static inline unsigned char scsi_get_prot_type(struct scsi_cmnd *scmd) -{ - return scmd->prot_type; -} - -static inline sector_t scsi_get_lba(struct scsi_cmnd *scmd) -{ - return blk_rq_pos(scmd->request); -} - -static inline unsigned int scsi_prot_interval(struct scsi_cmnd *scmd) -{ - return scmd->device->sector_size; -} - -static inline u32 scsi_prot_ref_tag(struct scsi_cmnd *scmd) -{ - return blk_rq_pos(scmd->request) >> - (ilog2(scsi_prot_interval(scmd)) - 9) & 0xffffffff; -} - -static inline unsigned scsi_prot_sg_count(struct scsi_cmnd *cmd) -{ - return cmd->prot_sdb ? cmd->prot_sdb->table.nents : 0; -} - -static inline struct scatterlist *scsi_prot_sglist(struct scsi_cmnd *cmd) -{ - return cmd->prot_sdb ? cmd->prot_sdb->table.sgl : NULL; -} - -static inline struct scsi_data_buffer *scsi_prot(struct scsi_cmnd *cmd) -{ - return cmd->prot_sdb; -} - -#define scsi_for_each_prot_sg(cmd, sg, nseg, __i) \ - for_each_sg(scsi_prot_sglist(cmd), sg, nseg, __i) - -static inline void set_msg_byte(struct scsi_cmnd *cmd, char status) -{ - cmd->result = (cmd->result & 0xffff00ff) | (status << 8); -} - -static inline void set_host_byte(struct scsi_cmnd *cmd, char status) -{ - cmd->result = (cmd->result & 0xff00ffff) | (status << 16); -} - -static inline void set_driver_byte(struct scsi_cmnd *cmd, char status) -{ - cmd->result = (cmd->result & 0x00ffffff) | (status << 24); -} - -static inline unsigned scsi_transfer_length(struct scsi_cmnd *scmd) -{ - unsigned int xfer_len = scsi_out(scmd)->length; - unsigned int prot_interval = scsi_prot_interval(scmd); - - if (scmd->prot_flags & SCSI_PROT_TRANSFER_PI) - xfer_len += (xfer_len >> ilog2(prot_interval)) * 8; - - return xfer_len; -} - -#endif /* _SCSI_SCSI_CMND_H */ diff --git a/src/linux/include/scsi/scsi_common.h b/src/linux/include/scsi/scsi_common.h deleted file mode 100644 index 20bf7ea..0000000 --- a/src/linux/include/scsi/scsi_common.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Functions used by both the SCSI initiator code and the SCSI target code. - */ - -#ifndef _SCSI_COMMON_H_ -#define _SCSI_COMMON_H_ - -#include -#include - -static inline unsigned -scsi_varlen_cdb_length(const void *hdr) -{ - return ((struct scsi_varlen_cdb_hdr *)hdr)->additional_cdb_length + 8; -} - -extern const unsigned char scsi_command_size_tbl[8]; -#define COMMAND_SIZE(opcode) scsi_command_size_tbl[((opcode) >> 5) & 7] - -static inline unsigned -scsi_command_size(const unsigned char *cmnd) -{ - return (cmnd[0] == VARIABLE_LENGTH_CMD) ? - scsi_varlen_cdb_length(cmnd) : COMMAND_SIZE(cmnd[0]); -} - -/* Returns a human-readable name for the device */ -extern const char *scsi_device_type(unsigned type); - -extern void int_to_scsilun(u64, struct scsi_lun *); -extern u64 scsilun_to_int(struct scsi_lun *); - -/* - * This is a slightly modified SCSI sense "descriptor" format header. - * The addition is to allow the 0x70 and 0x71 response codes. The idea - * is to place the salient data from either "fixed" or "descriptor" sense - * format into one structure to ease application processing. - * - * The original sense buffer should be kept around for those cases - * in which more information is required (e.g. the LBA of a MEDIUM ERROR). - */ -struct scsi_sense_hdr { /* See SPC-3 section 4.5 */ - u8 response_code; /* permit: 0x0, 0x70, 0x71, 0x72, 0x73 */ - u8 sense_key; - u8 asc; - u8 ascq; - u8 byte4; - u8 byte5; - u8 byte6; - u8 additional_length; /* always 0 for fixed sense format */ -}; - -static inline bool scsi_sense_valid(const struct scsi_sense_hdr *sshdr) -{ - if (!sshdr) - return false; - - return (sshdr->response_code & 0x70) == 0x70; -} - -extern bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len, - struct scsi_sense_hdr *sshdr); - -extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq); -int scsi_set_sense_information(u8 *buf, int buf_len, u64 info); -int scsi_set_sense_field_pointer(u8 *buf, int buf_len, u16 fp, u8 bp, bool cd); -extern const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len, - int desc_type); - -#endif /* _SCSI_COMMON_H_ */ diff --git a/src/linux/include/scsi/scsi_device.h b/src/linux/include/scsi/scsi_device.h deleted file mode 100644 index 8a95631..0000000 --- a/src/linux/include/scsi/scsi_device.h +++ /dev/null @@ -1,555 +0,0 @@ -#ifndef _SCSI_SCSI_DEVICE_H -#define _SCSI_SCSI_DEVICE_H - -#include -#include -#include -#include -#include -#include - -struct device; -struct request_queue; -struct scsi_cmnd; -struct scsi_lun; -struct scsi_sense_hdr; - -struct scsi_mode_data { - __u32 length; - __u16 block_descriptor_length; - __u8 medium_type; - __u8 device_specific; - __u8 header_length; - __u8 longlba:1; -}; - -/* - * sdev state: If you alter this, you also need to alter scsi_sysfs.c - * (for the ascii descriptions) and the state model enforcer: - * scsi_lib:scsi_device_set_state(). - */ -enum scsi_device_state { - SDEV_CREATED = 1, /* device created but not added to sysfs - * Only internal commands allowed (for inq) */ - SDEV_RUNNING, /* device properly configured - * All commands allowed */ - SDEV_CANCEL, /* beginning to delete device - * Only error handler commands allowed */ - SDEV_DEL, /* device deleted - * no commands allowed */ - SDEV_QUIESCE, /* Device quiescent. No block commands - * will be accepted, only specials (which - * originate in the mid-layer) */ - SDEV_OFFLINE, /* Device offlined (by error handling or - * user request */ - SDEV_TRANSPORT_OFFLINE, /* Offlined by transport class error handler */ - SDEV_BLOCK, /* Device blocked by scsi lld. No - * scsi commands from user or midlayer - * should be issued to the scsi - * lld. */ - SDEV_CREATED_BLOCK, /* same as above but for created devices */ -}; - -enum scsi_scan_mode { - SCSI_SCAN_INITIAL = 0, - SCSI_SCAN_RESCAN, - SCSI_SCAN_MANUAL, -}; - -enum scsi_device_event { - SDEV_EVT_MEDIA_CHANGE = 1, /* media has changed */ - SDEV_EVT_INQUIRY_CHANGE_REPORTED, /* 3F 03 UA reported */ - SDEV_EVT_CAPACITY_CHANGE_REPORTED, /* 2A 09 UA reported */ - SDEV_EVT_SOFT_THRESHOLD_REACHED_REPORTED, /* 38 07 UA reported */ - SDEV_EVT_MODE_PARAMETER_CHANGE_REPORTED, /* 2A 01 UA reported */ - SDEV_EVT_LUN_CHANGE_REPORTED, /* 3F 0E UA reported */ - SDEV_EVT_ALUA_STATE_CHANGE_REPORTED, /* 2A 06 UA reported */ - - SDEV_EVT_FIRST = SDEV_EVT_MEDIA_CHANGE, - SDEV_EVT_LAST = SDEV_EVT_ALUA_STATE_CHANGE_REPORTED, - - SDEV_EVT_MAXBITS = SDEV_EVT_LAST + 1 -}; - -struct scsi_event { - enum scsi_device_event evt_type; - struct list_head node; - - /* put union of data structures, for non-simple event types, - * here - */ -}; - -struct scsi_device { - struct Scsi_Host *host; - struct request_queue *request_queue; - - /* the next two are protected by the host->host_lock */ - struct list_head siblings; /* list of all devices on this host */ - struct list_head same_target_siblings; /* just the devices sharing same target id */ - - atomic_t device_busy; /* commands actually active on LLDD */ - atomic_t device_blocked; /* Device returned QUEUE_FULL. */ - - spinlock_t list_lock; - struct list_head cmd_list; /* queue of in use SCSI Command structures */ - struct list_head starved_entry; - unsigned short queue_depth; /* How deep of a queue we want */ - unsigned short max_queue_depth; /* max queue depth */ - unsigned short last_queue_full_depth; /* These two are used by */ - unsigned short last_queue_full_count; /* scsi_track_queue_full() */ - unsigned long last_queue_full_time; /* last queue full time */ - unsigned long queue_ramp_up_period; /* ramp up period in jiffies */ -#define SCSI_DEFAULT_RAMP_UP_PERIOD (120 * HZ) - - unsigned long last_queue_ramp_up; /* last queue ramp up time */ - - unsigned int id, channel; - u64 lun; - unsigned int manufacturer; /* Manufacturer of device, for using - * vendor-specific cmd's */ - unsigned sector_size; /* size in bytes */ - - void *hostdata; /* available to low-level driver */ - char type; - char scsi_level; - char inq_periph_qual; /* PQ from INQUIRY data */ - struct mutex inquiry_mutex; - unsigned char inquiry_len; /* valid bytes in 'inquiry' */ - unsigned char * inquiry; /* INQUIRY response data */ - const char * vendor; /* [back_compat] point into 'inquiry' ... */ - const char * model; /* ... after scan; point to static string */ - const char * rev; /* ... "nullnullnullnull" before scan */ - -#define SCSI_VPD_PG_LEN 255 - int vpd_pg83_len; - unsigned char __rcu *vpd_pg83; - int vpd_pg80_len; - unsigned char __rcu *vpd_pg80; - unsigned char current_tag; /* current tag */ - struct scsi_target *sdev_target; /* used only for single_lun */ - - unsigned int sdev_bflags; /* black/white flags as also found in - * scsi_devinfo.[hc]. For now used only to - * pass settings from slave_alloc to scsi - * core. */ - unsigned int eh_timeout; /* Error handling timeout */ - unsigned removable:1; - unsigned changed:1; /* Data invalid due to media change */ - unsigned busy:1; /* Used to prevent races */ - unsigned lockable:1; /* Able to prevent media removal */ - unsigned locked:1; /* Media removal disabled */ - unsigned borken:1; /* Tell the Seagate driver to be - * painfully slow on this device */ - unsigned disconnect:1; /* can disconnect */ - unsigned soft_reset:1; /* Uses soft reset option */ - unsigned sdtr:1; /* Device supports SDTR messages */ - unsigned wdtr:1; /* Device supports WDTR messages */ - unsigned ppr:1; /* Device supports PPR messages */ - unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */ - unsigned simple_tags:1; /* simple queue tag messages are enabled */ - unsigned was_reset:1; /* There was a bus reset on the bus for - * this device */ - unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN - * because we did a bus reset. */ - unsigned use_10_for_rw:1; /* first try 10-byte read / write */ - unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */ - unsigned no_report_opcodes:1; /* no REPORT SUPPORTED OPERATION CODES */ - unsigned no_write_same:1; /* no WRITE SAME command */ - unsigned use_16_for_rw:1; /* Use read/write(16) over read/write(10) */ - unsigned skip_ms_page_8:1; /* do not use MODE SENSE page 0x08 */ - unsigned skip_ms_page_3f:1; /* do not use MODE SENSE page 0x3f */ - unsigned skip_vpd_pages:1; /* do not read VPD pages */ - unsigned try_vpd_pages:1; /* attempt to read VPD pages */ - unsigned use_192_bytes_for_3f:1; /* ask for 192 bytes from page 0x3f */ - unsigned no_start_on_add:1; /* do not issue start on add */ - unsigned allow_restart:1; /* issue START_UNIT in error handler */ - unsigned manage_start_stop:1; /* Let HLD (sd) manage start/stop */ - unsigned start_stop_pwr_cond:1; /* Set power cond. in START_STOP_UNIT */ - unsigned no_uld_attach:1; /* disable connecting to upper level drivers */ - unsigned select_no_atn:1; - unsigned fix_capacity:1; /* READ_CAPACITY is too high by 1 */ - unsigned guess_capacity:1; /* READ_CAPACITY might be too high by 1 */ - unsigned retry_hwerror:1; /* Retry HARDWARE_ERROR */ - unsigned last_sector_bug:1; /* do not use multisector accesses on - SD_LAST_BUGGY_SECTORS */ - unsigned no_read_disc_info:1; /* Avoid READ_DISC_INFO cmds */ - unsigned no_read_capacity_16:1; /* Avoid READ_CAPACITY_16 cmds */ - unsigned try_rc_10_first:1; /* Try READ_CAPACACITY_10 first */ - unsigned is_visible:1; /* is the device visible in sysfs */ - unsigned wce_default_on:1; /* Cache is ON by default */ - unsigned no_dif:1; /* T10 PI (DIF) should be disabled */ - unsigned broken_fua:1; /* Don't set FUA bit */ - unsigned lun_in_cdb:1; /* Store LUN bits in CDB[1] */ - unsigned synchronous_alua:1; /* Synchronous ALUA commands */ - - atomic_t disk_events_disable_depth; /* disable depth for disk events */ - - DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */ - DECLARE_BITMAP(pending_events, SDEV_EVT_MAXBITS); /* pending events */ - struct list_head event_list; /* asserted events */ - struct work_struct event_work; - - unsigned int max_device_blocked; /* what device_blocked counts down from */ -#define SCSI_DEFAULT_DEVICE_BLOCKED 3 - - atomic_t iorequest_cnt; - atomic_t iodone_cnt; - atomic_t ioerr_cnt; - - struct device sdev_gendev, - sdev_dev; - - struct execute_work ew; /* used to get process context on put */ - struct work_struct requeue_work; - - struct scsi_device_handler *handler; - void *handler_data; - - unsigned char access_state; - enum scsi_device_state sdev_state; - unsigned long sdev_data[0]; -} __attribute__((aligned(sizeof(unsigned long)))); - -#define to_scsi_device(d) \ - container_of(d, struct scsi_device, sdev_gendev) -#define class_to_sdev(d) \ - container_of(d, struct scsi_device, sdev_dev) -#define transport_class_to_sdev(class_dev) \ - to_scsi_device(class_dev->parent) - -#define sdev_dbg(sdev, fmt, a...) \ - dev_dbg(&(sdev)->sdev_gendev, fmt, ##a) - -/* - * like scmd_printk, but the device name is passed in - * as a string pointer - */ -__printf(4, 5) void -sdev_prefix_printk(const char *, const struct scsi_device *, const char *, - const char *, ...); - -#define sdev_printk(l, sdev, fmt, a...) \ - sdev_prefix_printk(l, sdev, NULL, fmt, ##a) - -__printf(3, 4) void -scmd_printk(const char *, const struct scsi_cmnd *, const char *, ...); - -#define scmd_dbg(scmd, fmt, a...) \ - do { \ - if ((scmd)->request->rq_disk) \ - sdev_dbg((scmd)->device, "[%s] " fmt, \ - (scmd)->request->rq_disk->disk_name, ##a);\ - else \ - sdev_dbg((scmd)->device, fmt, ##a); \ - } while (0) - -enum scsi_target_state { - STARGET_CREATED = 1, - STARGET_RUNNING, - STARGET_REMOVE, - STARGET_DEL, -}; - -/* - * scsi_target: representation of a scsi target, for now, this is only - * used for single_lun devices. If no one has active IO to the target, - * starget_sdev_user is NULL, else it points to the active sdev. - */ -struct scsi_target { - struct scsi_device *starget_sdev_user; - struct list_head siblings; - struct list_head devices; - struct device dev; - struct kref reap_ref; /* last put renders target invisible */ - unsigned int channel; - unsigned int id; /* target id ... replace - * scsi_device.id eventually */ - unsigned int create:1; /* signal that it needs to be added */ - unsigned int single_lun:1; /* Indicates we should only - * allow I/O to one of the luns - * for the device at a time. */ - unsigned int pdt_1f_for_no_lun:1; /* PDT = 0x1f - * means no lun present. */ - unsigned int no_report_luns:1; /* Don't use - * REPORT LUNS for scanning. */ - unsigned int expecting_lun_change:1; /* A device has reported - * a 3F/0E UA, other devices on - * the same target will also. */ - /* commands actually active on LLD. */ - atomic_t target_busy; - atomic_t target_blocked; - - /* - * LLDs should set this in the slave_alloc host template callout. - * If set to zero then there is not limit. - */ - unsigned int can_queue; - unsigned int max_target_blocked; -#define SCSI_DEFAULT_TARGET_BLOCKED 3 - - char scsi_level; - enum scsi_target_state state; - void *hostdata; /* available to low-level driver */ - unsigned long starget_data[0]; /* for the transport */ - /* starget_data must be the last element!!!! */ -} __attribute__((aligned(sizeof(unsigned long)))); - -#define to_scsi_target(d) container_of(d, struct scsi_target, dev) -static inline struct scsi_target *scsi_target(struct scsi_device *sdev) -{ - return to_scsi_target(sdev->sdev_gendev.parent); -} -#define transport_class_to_starget(class_dev) \ - to_scsi_target(class_dev->parent) - -#define starget_printk(prefix, starget, fmt, a...) \ - dev_printk(prefix, &(starget)->dev, fmt, ##a) - -extern struct scsi_device *__scsi_add_device(struct Scsi_Host *, - uint, uint, u64, void *hostdata); -extern int scsi_add_device(struct Scsi_Host *host, uint channel, - uint target, u64 lun); -extern int scsi_register_device_handler(struct scsi_device_handler *scsi_dh); -extern void scsi_remove_device(struct scsi_device *); -extern int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh); -void scsi_attach_vpd(struct scsi_device *sdev); - -extern int scsi_device_get(struct scsi_device *); -extern void scsi_device_put(struct scsi_device *); -extern struct scsi_device *scsi_device_lookup(struct Scsi_Host *, - uint, uint, u64); -extern struct scsi_device *__scsi_device_lookup(struct Scsi_Host *, - uint, uint, u64); -extern struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *, - u64); -extern struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *, - u64); -extern void starget_for_each_device(struct scsi_target *, void *, - void (*fn)(struct scsi_device *, void *)); -extern void __starget_for_each_device(struct scsi_target *, void *, - void (*fn)(struct scsi_device *, - void *)); - -/* only exposed to implement shost_for_each_device */ -extern struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *, - struct scsi_device *); - -/** - * shost_for_each_device - iterate over all devices of a host - * @sdev: the &struct scsi_device to use as a cursor - * @shost: the &struct scsi_host to iterate over - * - * Iterator that returns each device attached to @shost. This loop - * takes a reference on each device and releases it at the end. If - * you break out of the loop, you must call scsi_device_put(sdev). - */ -#define shost_for_each_device(sdev, shost) \ - for ((sdev) = __scsi_iterate_devices((shost), NULL); \ - (sdev); \ - (sdev) = __scsi_iterate_devices((shost), (sdev))) - -/** - * __shost_for_each_device - iterate over all devices of a host (UNLOCKED) - * @sdev: the &struct scsi_device to use as a cursor - * @shost: the &struct scsi_host to iterate over - * - * Iterator that returns each device attached to @shost. It does _not_ - * take a reference on the scsi_device, so the whole loop must be - * protected by shost->host_lock. - * - * Note: The only reason to use this is because you need to access the - * device list in interrupt context. Otherwise you really want to use - * shost_for_each_device instead. - */ -#define __shost_for_each_device(sdev, shost) \ - list_for_each_entry((sdev), &((shost)->__devices), siblings) - -extern int scsi_change_queue_depth(struct scsi_device *, int); -extern int scsi_track_queue_full(struct scsi_device *, int); - -extern int scsi_set_medium_removal(struct scsi_device *, char); - -extern int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, - unsigned char *buffer, int len, int timeout, - int retries, struct scsi_mode_data *data, - struct scsi_sense_hdr *); -extern int scsi_mode_select(struct scsi_device *sdev, int pf, int sp, - int modepage, unsigned char *buffer, int len, - int timeout, int retries, - struct scsi_mode_data *data, - struct scsi_sense_hdr *); -extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout, - int retries, struct scsi_sense_hdr *sshdr); -extern int scsi_get_vpd_page(struct scsi_device *, u8 page, unsigned char *buf, - int buf_len); -extern int scsi_report_opcode(struct scsi_device *sdev, unsigned char *buffer, - unsigned int len, unsigned char opcode); -extern int scsi_device_set_state(struct scsi_device *sdev, - enum scsi_device_state state); -extern struct scsi_event *sdev_evt_alloc(enum scsi_device_event evt_type, - gfp_t gfpflags); -extern void sdev_evt_send(struct scsi_device *sdev, struct scsi_event *evt); -extern void sdev_evt_send_simple(struct scsi_device *sdev, - enum scsi_device_event evt_type, gfp_t gfpflags); -extern int scsi_device_quiesce(struct scsi_device *sdev); -extern void scsi_device_resume(struct scsi_device *sdev); -extern void scsi_target_quiesce(struct scsi_target *); -extern void scsi_target_resume(struct scsi_target *); -extern void scsi_scan_target(struct device *parent, unsigned int channel, - unsigned int id, u64 lun, - enum scsi_scan_mode rescan); -extern void scsi_target_reap(struct scsi_target *); -extern void scsi_target_block(struct device *); -extern void scsi_target_unblock(struct device *, enum scsi_device_state); -extern void scsi_remove_target(struct device *); -extern const char *scsi_device_state_name(enum scsi_device_state); -extern int scsi_is_sdev_device(const struct device *); -extern int scsi_is_target_device(const struct device *); -extern void scsi_sanitize_inquiry_string(unsigned char *s, int len); -extern int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, - int data_direction, void *buffer, unsigned bufflen, - unsigned char *sense, int timeout, int retries, - u64 flags, int *resid); -extern int scsi_execute_req_flags(struct scsi_device *sdev, - const unsigned char *cmd, int data_direction, void *buffer, - unsigned bufflen, struct scsi_sense_hdr *sshdr, int timeout, - int retries, int *resid, u64 flags); -static inline int scsi_execute_req(struct scsi_device *sdev, - const unsigned char *cmd, int data_direction, void *buffer, - unsigned bufflen, struct scsi_sense_hdr *sshdr, int timeout, - int retries, int *resid) -{ - return scsi_execute_req_flags(sdev, cmd, data_direction, buffer, - bufflen, sshdr, timeout, retries, resid, 0); -} -extern void sdev_disable_disk_events(struct scsi_device *sdev); -extern void sdev_enable_disk_events(struct scsi_device *sdev); -extern int scsi_vpd_lun_id(struct scsi_device *, char *, size_t); -extern int scsi_vpd_tpg_id(struct scsi_device *, int *); - -#ifdef CONFIG_PM -extern int scsi_autopm_get_device(struct scsi_device *); -extern void scsi_autopm_put_device(struct scsi_device *); -#else -static inline int scsi_autopm_get_device(struct scsi_device *d) { return 0; } -static inline void scsi_autopm_put_device(struct scsi_device *d) {} -#endif /* CONFIG_PM */ - -static inline int __must_check scsi_device_reprobe(struct scsi_device *sdev) -{ - return device_reprobe(&sdev->sdev_gendev); -} - -static inline unsigned int sdev_channel(struct scsi_device *sdev) -{ - return sdev->channel; -} - -static inline unsigned int sdev_id(struct scsi_device *sdev) -{ - return sdev->id; -} - -#define scmd_id(scmd) sdev_id((scmd)->device) -#define scmd_channel(scmd) sdev_channel((scmd)->device) - -/* - * checks for positions of the SCSI state machine - */ -static inline int scsi_device_online(struct scsi_device *sdev) -{ - return (sdev->sdev_state != SDEV_OFFLINE && - sdev->sdev_state != SDEV_TRANSPORT_OFFLINE && - sdev->sdev_state != SDEV_DEL); -} -static inline int scsi_device_blocked(struct scsi_device *sdev) -{ - return sdev->sdev_state == SDEV_BLOCK || - sdev->sdev_state == SDEV_CREATED_BLOCK; -} -static inline int scsi_device_created(struct scsi_device *sdev) -{ - return sdev->sdev_state == SDEV_CREATED || - sdev->sdev_state == SDEV_CREATED_BLOCK; -} - -/* accessor functions for the SCSI parameters */ -static inline int scsi_device_sync(struct scsi_device *sdev) -{ - return sdev->sdtr; -} -static inline int scsi_device_wide(struct scsi_device *sdev) -{ - return sdev->wdtr; -} -static inline int scsi_device_dt(struct scsi_device *sdev) -{ - return sdev->ppr; -} -static inline int scsi_device_dt_only(struct scsi_device *sdev) -{ - if (sdev->inquiry_len < 57) - return 0; - return (sdev->inquiry[56] & 0x0c) == 0x04; -} -static inline int scsi_device_ius(struct scsi_device *sdev) -{ - if (sdev->inquiry_len < 57) - return 0; - return sdev->inquiry[56] & 0x01; -} -static inline int scsi_device_qas(struct scsi_device *sdev) -{ - if (sdev->inquiry_len < 57) - return 0; - return sdev->inquiry[56] & 0x02; -} -static inline int scsi_device_enclosure(struct scsi_device *sdev) -{ - return sdev->inquiry ? (sdev->inquiry[6] & (1<<6)) : 1; -} - -static inline int scsi_device_protection(struct scsi_device *sdev) -{ - if (sdev->no_dif) - return 0; - - return sdev->scsi_level > SCSI_2 && sdev->inquiry[5] & (1<<0); -} - -static inline int scsi_device_tpgs(struct scsi_device *sdev) -{ - return sdev->inquiry ? (sdev->inquiry[5] >> 4) & 0x3 : 0; -} - -/** - * scsi_device_supports_vpd - test if a device supports VPD pages - * @sdev: the &struct scsi_device to test - * - * If the 'try_vpd_pages' flag is set it takes precedence. - * Otherwise we will assume VPD pages are supported if the - * SCSI level is at least SPC-3 and 'skip_vpd_pages' is not set. - */ -static inline int scsi_device_supports_vpd(struct scsi_device *sdev) -{ - /* Attempt VPD inquiry if the device blacklist explicitly calls - * for it. - */ - if (sdev->try_vpd_pages) - return 1; - /* - * Although VPD inquiries can go to SCSI-2 type devices, - * some USB ones crash on receiving them, and the pages - * we currently ask for are mandatory for SPC-2 and beyond - */ - if (sdev->scsi_level >= SCSI_SPC_2 && !sdev->skip_vpd_pages) - return 1; - return 0; -} - -#define MODULE_ALIAS_SCSI_DEVICE(type) \ - MODULE_ALIAS("scsi:t-" __stringify(type) "*") -#define SCSI_DEVICE_MODALIAS_FMT "scsi:t-0x%02x" - -#endif /* _SCSI_SCSI_DEVICE_H */ diff --git a/src/linux/include/scsi/scsi_ioctl.h b/src/linux/include/scsi/scsi_ioctl.h deleted file mode 100644 index 8d19d1d..0000000 --- a/src/linux/include/scsi/scsi_ioctl.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef _SCSI_IOCTL_H -#define _SCSI_IOCTL_H - -#define SCSI_IOCTL_SEND_COMMAND 1 -#define SCSI_IOCTL_TEST_UNIT_READY 2 -#define SCSI_IOCTL_BENCHMARK_COMMAND 3 -#define SCSI_IOCTL_SYNC 4 /* Request synchronous parameters */ -#define SCSI_IOCTL_START_UNIT 5 -#define SCSI_IOCTL_STOP_UNIT 6 -/* The door lock/unlock constants are compatible with Sun constants for - the cdrom */ -#define SCSI_IOCTL_DOORLOCK 0x5380 /* lock the eject mechanism */ -#define SCSI_IOCTL_DOORUNLOCK 0x5381 /* unlock the mechanism */ - -#define SCSI_REMOVAL_PREVENT 1 -#define SCSI_REMOVAL_ALLOW 0 - -#ifdef __KERNEL__ - -struct scsi_device; - -/* - * Structures used for scsi_ioctl et al. - */ - -typedef struct scsi_ioctl_command { - unsigned int inlen; - unsigned int outlen; - unsigned char data[0]; -} Scsi_Ioctl_Command; - -typedef struct scsi_idlun { - __u32 dev_id; - __u32 host_unique_id; -} Scsi_Idlun; - -/* Fibre Channel WWN, port_id struct */ -typedef struct scsi_fctargaddress { - __u32 host_port_id; - unsigned char host_wwn[8]; // include NULL term. -} Scsi_FCTargAddress; - -int scsi_ioctl_block_when_processing_errors(struct scsi_device *sdev, - int cmd, bool ndelay); -extern int scsi_ioctl(struct scsi_device *, int, void __user *); - -#endif /* __KERNEL__ */ -#endif /* _SCSI_IOCTL_H */ diff --git a/src/linux/include/scsi/scsi_proto.h b/src/linux/include/scsi/scsi_proto.h deleted file mode 100644 index d1defd1..0000000 --- a/src/linux/include/scsi/scsi_proto.h +++ /dev/null @@ -1,302 +0,0 @@ -/* - * This header file contains public constants and structures used by - * both the SCSI initiator and the SCSI target code. - * - * For documentation on the OPCODES, MESSAGES, and SENSE values, - * please consult the SCSI standard. - */ - -#ifndef _SCSI_PROTO_H_ -#define _SCSI_PROTO_H_ - -#include - -/* - * SCSI opcodes - */ - -#define TEST_UNIT_READY 0x00 -#define REZERO_UNIT 0x01 -#define REQUEST_SENSE 0x03 -#define FORMAT_UNIT 0x04 -#define READ_BLOCK_LIMITS 0x05 -#define REASSIGN_BLOCKS 0x07 -#define INITIALIZE_ELEMENT_STATUS 0x07 -#define READ_6 0x08 -#define WRITE_6 0x0a -#define SEEK_6 0x0b -#define READ_REVERSE 0x0f -#define WRITE_FILEMARKS 0x10 -#define SPACE 0x11 -#define INQUIRY 0x12 -#define RECOVER_BUFFERED_DATA 0x14 -#define MODE_SELECT 0x15 -#define RESERVE 0x16 -#define RELEASE 0x17 -#define COPY 0x18 -#define ERASE 0x19 -#define MODE_SENSE 0x1a -#define START_STOP 0x1b -#define RECEIVE_DIAGNOSTIC 0x1c -#define SEND_DIAGNOSTIC 0x1d -#define ALLOW_MEDIUM_REMOVAL 0x1e - -#define READ_FORMAT_CAPACITIES 0x23 -#define SET_WINDOW 0x24 -#define READ_CAPACITY 0x25 -#define READ_10 0x28 -#define WRITE_10 0x2a -#define SEEK_10 0x2b -#define POSITION_TO_ELEMENT 0x2b -#define WRITE_VERIFY 0x2e -#define VERIFY 0x2f -#define SEARCH_HIGH 0x30 -#define SEARCH_EQUAL 0x31 -#define SEARCH_LOW 0x32 -#define SET_LIMITS 0x33 -#define PRE_FETCH 0x34 -#define READ_POSITION 0x34 -#define SYNCHRONIZE_CACHE 0x35 -#define LOCK_UNLOCK_CACHE 0x36 -#define READ_DEFECT_DATA 0x37 -#define MEDIUM_SCAN 0x38 -#define COMPARE 0x39 -#define COPY_VERIFY 0x3a -#define WRITE_BUFFER 0x3b -#define READ_BUFFER 0x3c -#define UPDATE_BLOCK 0x3d -#define READ_LONG 0x3e -#define WRITE_LONG 0x3f -#define CHANGE_DEFINITION 0x40 -#define WRITE_SAME 0x41 -#define UNMAP 0x42 -#define READ_TOC 0x43 -#define READ_HEADER 0x44 -#define GET_EVENT_STATUS_NOTIFICATION 0x4a -#define LOG_SELECT 0x4c -#define LOG_SENSE 0x4d -#define XDWRITEREAD_10 0x53 -#define MODE_SELECT_10 0x55 -#define RESERVE_10 0x56 -#define RELEASE_10 0x57 -#define MODE_SENSE_10 0x5a -#define PERSISTENT_RESERVE_IN 0x5e -#define PERSISTENT_RESERVE_OUT 0x5f -#define VARIABLE_LENGTH_CMD 0x7f -#define REPORT_LUNS 0xa0 -#define SECURITY_PROTOCOL_IN 0xa2 -#define MAINTENANCE_IN 0xa3 -#define MAINTENANCE_OUT 0xa4 -#define MOVE_MEDIUM 0xa5 -#define EXCHANGE_MEDIUM 0xa6 -#define READ_12 0xa8 -#define SERVICE_ACTION_OUT_12 0xa9 -#define WRITE_12 0xaa -#define READ_MEDIA_SERIAL_NUMBER 0xab /* Obsolete with SPC-2 */ -#define SERVICE_ACTION_IN_12 0xab -#define WRITE_VERIFY_12 0xae -#define VERIFY_12 0xaf -#define SEARCH_HIGH_12 0xb0 -#define SEARCH_EQUAL_12 0xb1 -#define SEARCH_LOW_12 0xb2 -#define SECURITY_PROTOCOL_OUT 0xb5 -#define READ_ELEMENT_STATUS 0xb8 -#define SEND_VOLUME_TAG 0xb6 -#define WRITE_LONG_2 0xea -#define EXTENDED_COPY 0x83 -#define RECEIVE_COPY_RESULTS 0x84 -#define ACCESS_CONTROL_IN 0x86 -#define ACCESS_CONTROL_OUT 0x87 -#define READ_16 0x88 -#define COMPARE_AND_WRITE 0x89 -#define WRITE_16 0x8a -#define READ_ATTRIBUTE 0x8c -#define WRITE_ATTRIBUTE 0x8d -#define VERIFY_16 0x8f -#define SYNCHRONIZE_CACHE_16 0x91 -#define WRITE_SAME_16 0x93 -#define ZBC_OUT 0x94 -#define ZBC_IN 0x95 -#define SERVICE_ACTION_BIDIRECTIONAL 0x9d -#define SERVICE_ACTION_IN_16 0x9e -#define SERVICE_ACTION_OUT_16 0x9f -/* values for service action in */ -#define SAI_READ_CAPACITY_16 0x10 -#define SAI_GET_LBA_STATUS 0x12 -#define SAI_REPORT_REFERRALS 0x13 -/* values for VARIABLE_LENGTH_CMD service action codes - * see spc4r17 Section D.3.5, table D.7 and D.8 */ -#define VLC_SA_RECEIVE_CREDENTIAL 0x1800 -/* values for maintenance in */ -#define MI_REPORT_IDENTIFYING_INFORMATION 0x05 -#define MI_REPORT_TARGET_PGS 0x0a -#define MI_REPORT_ALIASES 0x0b -#define MI_REPORT_SUPPORTED_OPERATION_CODES 0x0c -#define MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS 0x0d -#define MI_REPORT_PRIORITY 0x0e -#define MI_REPORT_TIMESTAMP 0x0f -#define MI_MANAGEMENT_PROTOCOL_IN 0x10 -/* value for MI_REPORT_TARGET_PGS ext header */ -#define MI_EXT_HDR_PARAM_FMT 0x20 -/* values for maintenance out */ -#define MO_SET_IDENTIFYING_INFORMATION 0x06 -#define MO_SET_TARGET_PGS 0x0a -#define MO_CHANGE_ALIASES 0x0b -#define MO_SET_PRIORITY 0x0e -#define MO_SET_TIMESTAMP 0x0f -#define MO_MANAGEMENT_PROTOCOL_OUT 0x10 -/* values for ZBC_IN */ -#define ZI_REPORT_ZONES 0x00 -/* values for ZBC_OUT */ -#define ZO_CLOSE_ZONE 0x01 -#define ZO_FINISH_ZONE 0x02 -#define ZO_OPEN_ZONE 0x03 -#define ZO_RESET_WRITE_POINTER 0x04 -/* values for variable length command */ -#define XDREAD_32 0x03 -#define XDWRITE_32 0x04 -#define XPWRITE_32 0x06 -#define XDWRITEREAD_32 0x07 -#define READ_32 0x09 -#define VERIFY_32 0x0a -#define WRITE_32 0x0b -#define WRITE_SAME_32 0x0d - -/* Values for T10/04-262r7 */ -#define ATA_16 0x85 /* 16-byte pass-thru */ -#define ATA_12 0xa1 /* 12-byte pass-thru */ - -/* Vendor specific CDBs start here */ -#define VENDOR_SPECIFIC_CDB 0xc0 - -/* - * SCSI command lengths - */ - -#define SCSI_MAX_VARLEN_CDB_SIZE 260 - -/* defined in T10 SCSI Primary Commands-2 (SPC2) */ -struct scsi_varlen_cdb_hdr { - __u8 opcode; /* opcode always == VARIABLE_LENGTH_CMD */ - __u8 control; - __u8 misc[5]; - __u8 additional_cdb_length; /* total cdb length - 8 */ - __be16 service_action; - /* service specific data follows */ -}; - -/* - * SCSI Architecture Model (SAM) Status codes. Taken from SAM-3 draft - * T10/1561-D Revision 4 Draft dated 7th November 2002. - */ -#define SAM_STAT_GOOD 0x00 -#define SAM_STAT_CHECK_CONDITION 0x02 -#define SAM_STAT_CONDITION_MET 0x04 -#define SAM_STAT_BUSY 0x08 -#define SAM_STAT_INTERMEDIATE 0x10 -#define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14 -#define SAM_STAT_RESERVATION_CONFLICT 0x18 -#define SAM_STAT_COMMAND_TERMINATED 0x22 /* obsolete in SAM-3 */ -#define SAM_STAT_TASK_SET_FULL 0x28 -#define SAM_STAT_ACA_ACTIVE 0x30 -#define SAM_STAT_TASK_ABORTED 0x40 - -/* - * Status codes. These are deprecated as they are shifted 1 bit right - * from those found in the SCSI standards. This causes confusion for - * applications that are ported to several OSes. Prefer SAM Status codes - * above. - */ - -#define GOOD 0x00 -#define CHECK_CONDITION 0x01 -#define CONDITION_GOOD 0x02 -#define BUSY 0x04 -#define INTERMEDIATE_GOOD 0x08 -#define INTERMEDIATE_C_GOOD 0x0a -#define RESERVATION_CONFLICT 0x0c -#define COMMAND_TERMINATED 0x11 -#define QUEUE_FULL 0x14 -#define ACA_ACTIVE 0x18 -#define TASK_ABORTED 0x20 - -#define STATUS_MASK 0xfe - -/* - * SENSE KEYS - */ - -#define NO_SENSE 0x00 -#define RECOVERED_ERROR 0x01 -#define NOT_READY 0x02 -#define MEDIUM_ERROR 0x03 -#define HARDWARE_ERROR 0x04 -#define ILLEGAL_REQUEST 0x05 -#define UNIT_ATTENTION 0x06 -#define DATA_PROTECT 0x07 -#define BLANK_CHECK 0x08 -#define COPY_ABORTED 0x0a -#define ABORTED_COMMAND 0x0b -#define VOLUME_OVERFLOW 0x0d -#define MISCOMPARE 0x0e - - -/* - * DEVICE TYPES - * Please keep them in 0x%02x format for $MODALIAS to work - */ - -#define TYPE_DISK 0x00 -#define TYPE_TAPE 0x01 -#define TYPE_PRINTER 0x02 -#define TYPE_PROCESSOR 0x03 /* HP scanners use this */ -#define TYPE_WORM 0x04 /* Treated as ROM by our system */ -#define TYPE_ROM 0x05 -#define TYPE_SCANNER 0x06 -#define TYPE_MOD 0x07 /* Magneto-optical disk - - * - treated as TYPE_DISK */ -#define TYPE_MEDIUM_CHANGER 0x08 -#define TYPE_COMM 0x09 /* Communications device */ -#define TYPE_RAID 0x0c -#define TYPE_ENCLOSURE 0x0d /* Enclosure Services Device */ -#define TYPE_RBC 0x0e -#define TYPE_OSD 0x11 -#define TYPE_ZBC 0x14 -#define TYPE_WLUN 0x1e /* well-known logical unit */ -#define TYPE_NO_LUN 0x7f - -/* SCSI protocols; these are taken from SPC-3 section 7.5 */ -enum scsi_protocol { - SCSI_PROTOCOL_FCP = 0, /* Fibre Channel */ - SCSI_PROTOCOL_SPI = 1, /* parallel SCSI */ - SCSI_PROTOCOL_SSA = 2, /* Serial Storage Architecture - Obsolete */ - SCSI_PROTOCOL_SBP = 3, /* firewire */ - SCSI_PROTOCOL_SRP = 4, /* Infiniband RDMA */ - SCSI_PROTOCOL_ISCSI = 5, - SCSI_PROTOCOL_SAS = 6, - SCSI_PROTOCOL_ADT = 7, /* Media Changers */ - SCSI_PROTOCOL_ATA = 8, - SCSI_PROTOCOL_UNSPEC = 0xf, /* No specific protocol */ -}; - -/* - * ScsiLun: 8 byte LUN. - */ -struct scsi_lun { - __u8 scsi_lun[8]; -}; - -/* SPC asymmetric access states */ -#define SCSI_ACCESS_STATE_OPTIMAL 0x00 -#define SCSI_ACCESS_STATE_ACTIVE 0x01 -#define SCSI_ACCESS_STATE_STANDBY 0x02 -#define SCSI_ACCESS_STATE_UNAVAILABLE 0x03 -#define SCSI_ACCESS_STATE_LBA 0x04 -#define SCSI_ACCESS_STATE_OFFLINE 0x0e -#define SCSI_ACCESS_STATE_TRANSITIONING 0x0f - -/* Values for REPORT TARGET GROUP STATES */ -#define SCSI_ACCESS_STATE_MASK 0x0f -#define SCSI_ACCESS_STATE_PREFERRED 0x80 - -#endif /* _SCSI_PROTO_H_ */ diff --git a/src/linux/include/scsi/sg.h b/src/linux/include/scsi/sg.h deleted file mode 100644 index 3afec70..0000000 --- a/src/linux/include/scsi/sg.h +++ /dev/null @@ -1,274 +0,0 @@ -#ifndef _SCSI_GENERIC_H -#define _SCSI_GENERIC_H - -#include - -/* - * History: - * Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user - * process control of SCSI devices. - * Development Sponsored by Killy Corp. NY NY - * - * Original driver (sg.h): - * Copyright (C) 1992 Lawrence Foard - * Version 2 and 3 extensions to driver: - * Copyright (C) 1998 - 2014 Douglas Gilbert - * - * Version: 3.5.36 (20140603) - * This version is for 2.6 and 3 series kernels. - * - * Documentation - * ============= - * A web site for the SG device driver can be found at: - * http://sg.danny.cz/sg [alternatively check the MAINTAINERS file] - * The documentation for the sg version 3 driver can be found at: - * http://sg.danny.cz/sg/p/sg_v3_ho.html - * Also see: /Documentation/scsi/scsi-generic.txt - * - * For utility and test programs see: http://sg.danny.cz/sg/sg3_utils.html - */ - -#ifdef __KERNEL__ -extern int sg_big_buff; /* for sysctl */ -#endif - - -typedef struct sg_iovec /* same structure as used by readv() Linux system */ -{ /* call. It defines one scatter-gather element. */ - void __user *iov_base; /* Starting address */ - size_t iov_len; /* Length in bytes */ -} sg_iovec_t; - - -typedef struct sg_io_hdr -{ - int interface_id; /* [i] 'S' for SCSI generic (required) */ - int dxfer_direction; /* [i] data transfer direction */ - unsigned char cmd_len; /* [i] SCSI command length */ - unsigned char mx_sb_len; /* [i] max length to write to sbp */ - unsigned short iovec_count; /* [i] 0 implies no scatter gather */ - unsigned int dxfer_len; /* [i] byte count of data transfer */ - void __user *dxferp; /* [i], [*io] points to data transfer memory - or scatter gather list */ - unsigned char __user *cmdp; /* [i], [*i] points to command to perform */ - void __user *sbp; /* [i], [*o] points to sense_buffer memory */ - unsigned int timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */ - unsigned int flags; /* [i] 0 -> default, see SG_FLAG... */ - int pack_id; /* [i->o] unused internally (normally) */ - void __user * usr_ptr; /* [i->o] unused internally */ - unsigned char status; /* [o] scsi status */ - unsigned char masked_status;/* [o] shifted, masked scsi status */ - unsigned char msg_status; /* [o] messaging level data (optional) */ - unsigned char sb_len_wr; /* [o] byte count actually written to sbp */ - unsigned short host_status; /* [o] errors from host adapter */ - unsigned short driver_status;/* [o] errors from software driver */ - int resid; /* [o] dxfer_len - actual_transferred */ - unsigned int duration; /* [o] time taken by cmd (unit: millisec) */ - unsigned int info; /* [o] auxiliary information */ -} sg_io_hdr_t; /* 64 bytes long (on i386) */ - -#define SG_INTERFACE_ID_ORIG 'S' - -/* Use negative values to flag difference from original sg_header structure */ -#define SG_DXFER_NONE (-1) /* e.g. a SCSI Test Unit Ready command */ -#define SG_DXFER_TO_DEV (-2) /* e.g. a SCSI WRITE command */ -#define SG_DXFER_FROM_DEV (-3) /* e.g. a SCSI READ command */ -#define SG_DXFER_TO_FROM_DEV (-4) /* treated like SG_DXFER_FROM_DEV with the - additional property than during indirect - IO the user buffer is copied into the - kernel buffers before the transfer */ -#define SG_DXFER_UNKNOWN (-5) /* Unknown data direction */ - -/* following flag values can be "or"-ed together */ -#define SG_FLAG_DIRECT_IO 1 /* default is indirect IO */ -#define SG_FLAG_UNUSED_LUN_INHIBIT 2 /* default is overwrite lun in SCSI */ - /* command block (when <= SCSI_2) */ -#define SG_FLAG_MMAP_IO 4 /* request memory mapped IO */ -#define SG_FLAG_NO_DXFER 0x10000 /* no transfer of kernel buffers to/from */ - /* user space (debug indirect IO) */ -/* defaults:: for sg driver: Q_AT_HEAD; for block layer: Q_AT_TAIL */ -#define SG_FLAG_Q_AT_TAIL 0x10 -#define SG_FLAG_Q_AT_HEAD 0x20 - -/* following 'info' values are "or"-ed together */ -#define SG_INFO_OK_MASK 0x1 -#define SG_INFO_OK 0x0 /* no sense, host nor driver "noise" */ -#define SG_INFO_CHECK 0x1 /* something abnormal happened */ - -#define SG_INFO_DIRECT_IO_MASK 0x6 -#define SG_INFO_INDIRECT_IO 0x0 /* data xfer via kernel buffers (or no xfer) */ -#define SG_INFO_DIRECT_IO 0x2 /* direct IO requested and performed */ -#define SG_INFO_MIXED_IO 0x4 /* part direct, part indirect IO */ - - -typedef struct sg_scsi_id { /* used by SG_GET_SCSI_ID ioctl() */ - int host_no; /* as in "scsi" where 'n' is one of 0, 1, 2 etc */ - int channel; - int scsi_id; /* scsi id of target device */ - int lun; - int scsi_type; /* TYPE_... defined in scsi/scsi.h */ - short h_cmd_per_lun;/* host (adapter) maximum commands per lun */ - short d_queue_depth;/* device (or adapter) maximum queue length */ - int unused[2]; /* probably find a good use, set 0 for now */ -} sg_scsi_id_t; /* 32 bytes long on i386 */ - -typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */ - char req_state; /* 0 -> not used, 1 -> written, 2 -> ready to read */ - char orphan; /* 0 -> normal request, 1 -> from interruped SG_IO */ - char sg_io_owned; /* 0 -> complete with read(), 1 -> owned by SG_IO */ - char problem; /* 0 -> no problem detected, 1 -> error to report */ - int pack_id; /* pack_id associated with request */ - void __user *usr_ptr; /* user provided pointer (in new interface) */ - unsigned int duration; /* millisecs elapsed since written (req_state==1) - or request duration (req_state==2) */ - int unused; -} sg_req_info_t; /* 20 bytes long on i386 */ - - -/* IOCTLs: Those ioctls that are relevant to the SG 3.x drivers follow. - [Those that only apply to the SG 2.x drivers are at the end of the file.] - (_GET_s yield result via 'int *' 3rd argument unless otherwise indicated) */ - -#define SG_EMULATED_HOST 0x2203 /* true for emulated host adapter (ATAPI) */ - -/* Used to configure SCSI command transformation layer for ATAPI devices */ -/* Only supported by the ide-scsi driver */ -#define SG_SET_TRANSFORM 0x2204 /* N.B. 3rd arg is not pointer but value: */ - /* 3rd arg = 0 to disable transform, 1 to enable it */ -#define SG_GET_TRANSFORM 0x2205 - -#define SG_SET_RESERVED_SIZE 0x2275 /* request a new reserved buffer size */ -#define SG_GET_RESERVED_SIZE 0x2272 /* actual size of reserved buffer */ - -/* The following ioctl has a 'sg_scsi_id_t *' object as its 3rd argument. */ -#define SG_GET_SCSI_ID 0x2276 /* Yields fd's bus, chan, dev, lun + type */ -/* SCSI id information can also be obtained from SCSI_IOCTL_GET_IDLUN */ - -/* Override host setting and always DMA using low memory ( <16MB on i386) */ -#define SG_SET_FORCE_LOW_DMA 0x2279 /* 0-> use adapter setting, 1-> force */ -#define SG_GET_LOW_DMA 0x227a /* 0-> use all ram for dma; 1-> low dma ram */ - -/* When SG_SET_FORCE_PACK_ID set to 1, pack_id is input to read() which - tries to fetch a packet with a matching pack_id, waits, or returns EAGAIN. - If pack_id is -1 then read oldest waiting. When ...FORCE_PACK_ID set to 0 - then pack_id ignored by read() and oldest readable fetched. */ -#define SG_SET_FORCE_PACK_ID 0x227b -#define SG_GET_PACK_ID 0x227c /* Yields oldest readable pack_id (or -1) */ - -#define SG_GET_NUM_WAITING 0x227d /* Number of commands awaiting read() */ - -/* Yields max scatter gather tablesize allowed by current host adapter */ -#define SG_GET_SG_TABLESIZE 0x227F /* 0 implies can't do scatter gather */ - -#define SG_GET_VERSION_NUM 0x2282 /* Example: version 2.1.34 yields 20134 */ - -/* Returns -EBUSY if occupied. 3rd argument pointer to int (see next) */ -#define SG_SCSI_RESET 0x2284 -/* Associated values that can be given to SG_SCSI_RESET follow. - * SG_SCSI_RESET_NO_ESCALATE may be OR-ed to the _DEVICE, _TARGET, _BUS - * or _HOST reset value so only that action is attempted. */ -#define SG_SCSI_RESET_NOTHING 0 -#define SG_SCSI_RESET_DEVICE 1 -#define SG_SCSI_RESET_BUS 2 -#define SG_SCSI_RESET_HOST 3 -#define SG_SCSI_RESET_TARGET 4 -#define SG_SCSI_RESET_NO_ESCALATE 0x100 - -/* synchronous SCSI command ioctl, (only in version 3 interface) */ -#define SG_IO 0x2285 /* similar effect as write() followed by read() */ - -#define SG_GET_REQUEST_TABLE 0x2286 /* yields table of active requests */ - -/* How to treat EINTR during SG_IO ioctl(), only in SG 3.x series */ -#define SG_SET_KEEP_ORPHAN 0x2287 /* 1 -> hold for read(), 0 -> drop (def) */ -#define SG_GET_KEEP_ORPHAN 0x2288 - -/* yields scsi midlevel's access_count for this SCSI device */ -#define SG_GET_ACCESS_COUNT 0x2289 - - -#define SG_SCATTER_SZ (8 * 4096) -/* Largest size (in bytes) a single scatter-gather list element can have. - The value used by the driver is 'max(SG_SCATTER_SZ, PAGE_SIZE)'. - This value should be a power of 2 (and may be rounded up internally). - If scatter-gather is not supported by adapter then this value is the - largest data block that can be read/written by a single scsi command. */ - -#define SG_DEFAULT_RETRIES 0 - -/* Defaults, commented if they differ from original sg driver */ -#define SG_DEF_FORCE_LOW_DMA 0 /* was 1 -> memory below 16MB on i386 */ -#define SG_DEF_FORCE_PACK_ID 0 -#define SG_DEF_KEEP_ORPHAN 0 -#define SG_DEF_RESERVED_SIZE SG_SCATTER_SZ /* load time option */ - -/* maximum outstanding requests, write() yields EDOM if exceeded */ -#define SG_MAX_QUEUE 16 - -#define SG_BIG_BUFF SG_DEF_RESERVED_SIZE /* for backward compatibility */ - -/* Alternate style type names, "..._t" variants preferred */ -typedef struct sg_io_hdr Sg_io_hdr; -typedef struct sg_io_vec Sg_io_vec; -typedef struct sg_scsi_id Sg_scsi_id; -typedef struct sg_req_info Sg_req_info; - - -/* vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv */ -/* The older SG interface based on the 'sg_header' structure follows. */ -/* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ */ - -#define SG_MAX_SENSE 16 /* this only applies to the sg_header interface */ - -struct sg_header -{ - int pack_len; /* [o] reply_len (ie useless), ignored as input */ - int reply_len; /* [i] max length of expected reply (inc. sg_header) */ - int pack_id; /* [io] id number of packet (use ints >= 0) */ - int result; /* [o] 0==ok, else (+ve) Unix errno (best ignored) */ - unsigned int twelve_byte:1; - /* [i] Force 12 byte command length for group 6 & 7 commands */ - unsigned int target_status:5; /* [o] scsi status from target */ - unsigned int host_status:8; /* [o] host status (see "DID" codes) */ - unsigned int driver_status:8; /* [o] driver status+suggestion */ - unsigned int other_flags:10; /* unused */ - unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] Output in 3 cases: - when target_status is CHECK_CONDITION or - when target_status is COMMAND_TERMINATED or - when (driver_status & DRIVER_SENSE) is true. */ -}; /* This structure is 36 bytes long on i386 */ - - -/* IOCTLs: The following are not required (or ignored) when the sg_io_hdr_t - interface is used. They are kept for backward compatibility with - the original and version 2 drivers. */ - -#define SG_SET_TIMEOUT 0x2201 /* unit: jiffies (10ms on i386) */ -#define SG_GET_TIMEOUT 0x2202 /* yield timeout as _return_ value */ - -/* Get/set command queuing state per fd (default is SG_DEF_COMMAND_Q. - Each time a sg_io_hdr_t object is seen on this file descriptor, this - command queuing flag is set on (overriding the previous setting). */ -#define SG_GET_COMMAND_Q 0x2270 /* Yields 0 (queuing off) or 1 (on) */ -#define SG_SET_COMMAND_Q 0x2271 /* Change queuing state with 0 or 1 */ - -/* Turn on/off error sense trace (1 and 0 respectively, default is off). - Try using: "# cat /proc/scsi/sg/debug" instead in the v3 driver */ -#define SG_SET_DEBUG 0x227e /* 0 -> turn off debug */ - -#define SG_NEXT_CMD_LEN 0x2283 /* override SCSI command length with given - number on the next write() on this file descriptor */ - - -/* Defaults, commented if they differ from original sg driver */ -#ifdef __KERNEL__ -#define SG_DEFAULT_TIMEOUT_USER (60*USER_HZ) /* HZ == 'jiffies in 1 second' */ -#else -#define SG_DEFAULT_TIMEOUT (60*HZ) /* HZ == 'jiffies in 1 second' */ -#endif - -#define SG_DEF_COMMAND_Q 0 /* command queuing is always on when - the new interface is used */ -#define SG_DEF_UNDERRUN_FLAG 0 - -#endif diff --git a/src/linux/include/trace/define_trace.h b/src/linux/include/trace/define_trace.h deleted file mode 100644 index 6e3945f..0000000 --- a/src/linux/include/trace/define_trace.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Trace files that want to automate creation of all tracepoints defined - * in their file should include this file. The following are macros that the - * trace file may define: - * - * TRACE_SYSTEM defines the system the tracepoint is for - * - * TRACE_INCLUDE_FILE if the file name is something other than TRACE_SYSTEM.h - * This macro may be defined to tell define_trace.h what file to include. - * Note, leave off the ".h". - * - * TRACE_INCLUDE_PATH if the path is something other than core kernel include/trace - * then this macro can define the path to use. Note, the path is relative to - * define_trace.h, not the file including it. Full path names for out of tree - * modules must be used. - */ - -#ifdef CREATE_TRACE_POINTS - -/* Prevent recursion */ -#undef CREATE_TRACE_POINTS - -#include - -#undef TRACE_EVENT -#define TRACE_EVENT(name, proto, args, tstruct, assign, print) \ - DEFINE_TRACE(name) - -#undef TRACE_EVENT_CONDITION -#define TRACE_EVENT_CONDITION(name, proto, args, cond, tstruct, assign, print) \ - TRACE_EVENT(name, \ - PARAMS(proto), \ - PARAMS(args), \ - PARAMS(tstruct), \ - PARAMS(assign), \ - PARAMS(print)) - -#undef TRACE_EVENT_FN -#define TRACE_EVENT_FN(name, proto, args, tstruct, \ - assign, print, reg, unreg) \ - DEFINE_TRACE_FN(name, reg, unreg) - -#undef TRACE_EVENT_FN_COND -#define TRACE_EVENT_FN_COND(name, proto, args, cond, tstruct, \ - assign, print, reg, unreg) \ - DEFINE_TRACE_FN(name, reg, unreg) - -#undef DEFINE_EVENT -#define DEFINE_EVENT(template, name, proto, args) \ - DEFINE_TRACE(name) - -#undef DEFINE_EVENT_FN -#define DEFINE_EVENT_FN(template, name, proto, args, reg, unreg) \ - DEFINE_TRACE_FN(name, reg, unreg) - -#undef DEFINE_EVENT_PRINT -#define DEFINE_EVENT_PRINT(template, name, proto, args, print) \ - DEFINE_TRACE(name) - -#undef DEFINE_EVENT_CONDITION -#define DEFINE_EVENT_CONDITION(template, name, proto, args, cond) \ - DEFINE_EVENT(template, name, PARAMS(proto), PARAMS(args)) - -#undef DECLARE_TRACE -#define DECLARE_TRACE(name, proto, args) \ - DEFINE_TRACE(name) - -#undef TRACE_INCLUDE -#undef __TRACE_INCLUDE - -#ifndef TRACE_INCLUDE_FILE -# define TRACE_INCLUDE_FILE TRACE_SYSTEM -# define UNDEF_TRACE_INCLUDE_FILE -#endif - -#ifndef TRACE_INCLUDE_PATH -# define __TRACE_INCLUDE(system) -# define UNDEF_TRACE_INCLUDE_PATH -#else -# define __TRACE_INCLUDE(system) __stringify(TRACE_INCLUDE_PATH/system.h) -#endif - -# define TRACE_INCLUDE(system) __TRACE_INCLUDE(system) - -/* Let the trace headers be reread */ -#define TRACE_HEADER_MULTI_READ - -#include TRACE_INCLUDE(TRACE_INCLUDE_FILE) - -/* Make all open coded DECLARE_TRACE nops */ -#undef DECLARE_TRACE -#define DECLARE_TRACE(name, proto, args) - -#ifdef TRACEPOINTS_ENABLED -#include -#include -#endif - -#undef TRACE_EVENT -#undef TRACE_EVENT_FN -#undef TRACE_EVENT_FN_COND -#undef TRACE_EVENT_CONDITION -#undef DECLARE_EVENT_CLASS -#undef DEFINE_EVENT -#undef DEFINE_EVENT_FN -#undef DEFINE_EVENT_PRINT -#undef DEFINE_EVENT_CONDITION -#undef TRACE_HEADER_MULTI_READ -#undef DECLARE_TRACE - -/* Only undef what we defined in this file */ -#ifdef UNDEF_TRACE_INCLUDE_FILE -# undef TRACE_INCLUDE_FILE -# undef UNDEF_TRACE_INCLUDE_FILE -#endif - -#ifdef UNDEF_TRACE_INCLUDE_PATH -# undef TRACE_INCLUDE_PATH -# undef UNDEF_TRACE_INCLUDE_PATH -#endif - -/* We may be processing more files */ -#define CREATE_TRACE_POINTS - -#endif /* CREATE_TRACE_POINTS */ diff --git a/src/linux/include/trace/events/block.h b/src/linux/include/trace/events/block.h deleted file mode 100644 index 8f3a163..0000000 --- a/src/linux/include/trace/events/block.h +++ /dev/null @@ -1,683 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM block - -#if !defined(_TRACE_BLOCK_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_BLOCK_H - -#include -#include -#include -#include - -#define RWBS_LEN 8 - -DECLARE_EVENT_CLASS(block_buffer, - - TP_PROTO(struct buffer_head *bh), - - TP_ARGS(bh), - - TP_STRUCT__entry ( - __field( dev_t, dev ) - __field( sector_t, sector ) - __field( size_t, size ) - ), - - TP_fast_assign( - __entry->dev = bh->b_bdev->bd_dev; - __entry->sector = bh->b_blocknr; - __entry->size = bh->b_size; - ), - - TP_printk("%d,%d sector=%llu size=%zu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long long)__entry->sector, __entry->size - ) -); - -/** - * block_touch_buffer - mark a buffer accessed - * @bh: buffer_head being touched - * - * Called from touch_buffer(). - */ -DEFINE_EVENT(block_buffer, block_touch_buffer, - - TP_PROTO(struct buffer_head *bh), - - TP_ARGS(bh) -); - -/** - * block_dirty_buffer - mark a buffer dirty - * @bh: buffer_head being dirtied - * - * Called from mark_buffer_dirty(). - */ -DEFINE_EVENT(block_buffer, block_dirty_buffer, - - TP_PROTO(struct buffer_head *bh), - - TP_ARGS(bh) -); - -DECLARE_EVENT_CLASS(block_rq_with_error, - - TP_PROTO(struct request_queue *q, struct request *rq), - - TP_ARGS(q, rq), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( sector_t, sector ) - __field( unsigned int, nr_sector ) - __field( int, errors ) - __array( char, rwbs, RWBS_LEN ) - __dynamic_array( char, cmd, blk_cmd_buf_len(rq) ) - ), - - TP_fast_assign( - __entry->dev = rq->rq_disk ? disk_devt(rq->rq_disk) : 0; - __entry->sector = (rq->cmd_type == REQ_TYPE_BLOCK_PC) ? - 0 : blk_rq_pos(rq); - __entry->nr_sector = (rq->cmd_type == REQ_TYPE_BLOCK_PC) ? - 0 : blk_rq_sectors(rq); - __entry->errors = rq->errors; - - blk_fill_rwbs(__entry->rwbs, req_op(rq), rq->cmd_flags, - blk_rq_bytes(rq)); - blk_dump_cmd(__get_str(cmd), rq); - ), - - TP_printk("%d,%d %s (%s) %llu + %u [%d]", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->rwbs, __get_str(cmd), - (unsigned long long)__entry->sector, - __entry->nr_sector, __entry->errors) -); - -/** - * block_rq_abort - abort block operation request - * @q: queue containing the block operation request - * @rq: block IO operation request - * - * Called immediately after pending block IO operation request @rq in - * queue @q is aborted. The fields in the operation request @rq - * can be examined to determine which device and sectors the pending - * operation would access. - */ -DEFINE_EVENT(block_rq_with_error, block_rq_abort, - - TP_PROTO(struct request_queue *q, struct request *rq), - - TP_ARGS(q, rq) -); - -/** - * block_rq_requeue - place block IO request back on a queue - * @q: queue holding operation - * @rq: block IO operation request - * - * The block operation request @rq is being placed back into queue - * @q. For some reason the request was not completed and needs to be - * put back in the queue. - */ -DEFINE_EVENT(block_rq_with_error, block_rq_requeue, - - TP_PROTO(struct request_queue *q, struct request *rq), - - TP_ARGS(q, rq) -); - -/** - * block_rq_complete - block IO operation completed by device driver - * @q: queue containing the block operation request - * @rq: block operations request - * @nr_bytes: number of completed bytes - * - * The block_rq_complete tracepoint event indicates that some portion - * of operation request has been completed by the device driver. If - * the @rq->bio is %NULL, then there is absolutely no additional work to - * do for the request. If @rq->bio is non-NULL then there is - * additional work required to complete the request. - */ -TRACE_EVENT(block_rq_complete, - - TP_PROTO(struct request_queue *q, struct request *rq, - unsigned int nr_bytes), - - TP_ARGS(q, rq, nr_bytes), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( sector_t, sector ) - __field( unsigned int, nr_sector ) - __field( int, errors ) - __array( char, rwbs, RWBS_LEN ) - __dynamic_array( char, cmd, blk_cmd_buf_len(rq) ) - ), - - TP_fast_assign( - __entry->dev = rq->rq_disk ? disk_devt(rq->rq_disk) : 0; - __entry->sector = blk_rq_pos(rq); - __entry->nr_sector = nr_bytes >> 9; - __entry->errors = rq->errors; - - blk_fill_rwbs(__entry->rwbs, req_op(rq), rq->cmd_flags, nr_bytes); - blk_dump_cmd(__get_str(cmd), rq); - ), - - TP_printk("%d,%d %s (%s) %llu + %u [%d]", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->rwbs, __get_str(cmd), - (unsigned long long)__entry->sector, - __entry->nr_sector, __entry->errors) -); - -DECLARE_EVENT_CLASS(block_rq, - - TP_PROTO(struct request_queue *q, struct request *rq), - - TP_ARGS(q, rq), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( sector_t, sector ) - __field( unsigned int, nr_sector ) - __field( unsigned int, bytes ) - __array( char, rwbs, RWBS_LEN ) - __array( char, comm, TASK_COMM_LEN ) - __dynamic_array( char, cmd, blk_cmd_buf_len(rq) ) - ), - - TP_fast_assign( - __entry->dev = rq->rq_disk ? disk_devt(rq->rq_disk) : 0; - __entry->sector = (rq->cmd_type == REQ_TYPE_BLOCK_PC) ? - 0 : blk_rq_pos(rq); - __entry->nr_sector = (rq->cmd_type == REQ_TYPE_BLOCK_PC) ? - 0 : blk_rq_sectors(rq); - __entry->bytes = (rq->cmd_type == REQ_TYPE_BLOCK_PC) ? - blk_rq_bytes(rq) : 0; - - blk_fill_rwbs(__entry->rwbs, req_op(rq), rq->cmd_flags, - blk_rq_bytes(rq)); - blk_dump_cmd(__get_str(cmd), rq); - memcpy(__entry->comm, current->comm, TASK_COMM_LEN); - ), - - TP_printk("%d,%d %s %u (%s) %llu + %u [%s]", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->rwbs, __entry->bytes, __get_str(cmd), - (unsigned long long)__entry->sector, - __entry->nr_sector, __entry->comm) -); - -/** - * block_rq_insert - insert block operation request into queue - * @q: target queue - * @rq: block IO operation request - * - * Called immediately before block operation request @rq is inserted - * into queue @q. The fields in the operation request @rq struct can - * be examined to determine which device and sectors the pending - * operation would access. - */ -DEFINE_EVENT(block_rq, block_rq_insert, - - TP_PROTO(struct request_queue *q, struct request *rq), - - TP_ARGS(q, rq) -); - -/** - * block_rq_issue - issue pending block IO request operation to device driver - * @q: queue holding operation - * @rq: block IO operation operation request - * - * Called when block operation request @rq from queue @q is sent to a - * device driver for processing. - */ -DEFINE_EVENT(block_rq, block_rq_issue, - - TP_PROTO(struct request_queue *q, struct request *rq), - - TP_ARGS(q, rq) -); - -/** - * block_bio_bounce - used bounce buffer when processing block operation - * @q: queue holding the block operation - * @bio: block operation - * - * A bounce buffer was used to handle the block operation @bio in @q. - * This occurs when hardware limitations prevent a direct transfer of - * data between the @bio data memory area and the IO device. Use of a - * bounce buffer requires extra copying of data and decreases - * performance. - */ -TRACE_EVENT(block_bio_bounce, - - TP_PROTO(struct request_queue *q, struct bio *bio), - - TP_ARGS(q, bio), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( sector_t, sector ) - __field( unsigned int, nr_sector ) - __array( char, rwbs, RWBS_LEN ) - __array( char, comm, TASK_COMM_LEN ) - ), - - TP_fast_assign( - __entry->dev = bio->bi_bdev ? - bio->bi_bdev->bd_dev : 0; - __entry->sector = bio->bi_iter.bi_sector; - __entry->nr_sector = bio_sectors(bio); - blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_opf, - bio->bi_iter.bi_size); - memcpy(__entry->comm, current->comm, TASK_COMM_LEN); - ), - - TP_printk("%d,%d %s %llu + %u [%s]", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs, - (unsigned long long)__entry->sector, - __entry->nr_sector, __entry->comm) -); - -/** - * block_bio_complete - completed all work on the block operation - * @q: queue holding the block operation - * @bio: block operation completed - * @error: io error value - * - * This tracepoint indicates there is no further work to do on this - * block IO operation @bio. - */ -TRACE_EVENT(block_bio_complete, - - TP_PROTO(struct request_queue *q, struct bio *bio, int error), - - TP_ARGS(q, bio, error), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( sector_t, sector ) - __field( unsigned, nr_sector ) - __field( int, error ) - __array( char, rwbs, RWBS_LEN) - ), - - TP_fast_assign( - __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_iter.bi_sector; - __entry->nr_sector = bio_sectors(bio); - __entry->error = error; - blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_opf, - bio->bi_iter.bi_size); - ), - - TP_printk("%d,%d %s %llu + %u [%d]", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs, - (unsigned long long)__entry->sector, - __entry->nr_sector, __entry->error) -); - -DECLARE_EVENT_CLASS(block_bio_merge, - - TP_PROTO(struct request_queue *q, struct request *rq, struct bio *bio), - - TP_ARGS(q, rq, bio), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( sector_t, sector ) - __field( unsigned int, nr_sector ) - __array( char, rwbs, RWBS_LEN ) - __array( char, comm, TASK_COMM_LEN ) - ), - - TP_fast_assign( - __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_iter.bi_sector; - __entry->nr_sector = bio_sectors(bio); - blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_opf, - bio->bi_iter.bi_size); - memcpy(__entry->comm, current->comm, TASK_COMM_LEN); - ), - - TP_printk("%d,%d %s %llu + %u [%s]", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs, - (unsigned long long)__entry->sector, - __entry->nr_sector, __entry->comm) -); - -/** - * block_bio_backmerge - merging block operation to the end of an existing operation - * @q: queue holding operation - * @rq: request bio is being merged into - * @bio: new block operation to merge - * - * Merging block request @bio to the end of an existing block request - * in queue @q. - */ -DEFINE_EVENT(block_bio_merge, block_bio_backmerge, - - TP_PROTO(struct request_queue *q, struct request *rq, struct bio *bio), - - TP_ARGS(q, rq, bio) -); - -/** - * block_bio_frontmerge - merging block operation to the beginning of an existing operation - * @q: queue holding operation - * @rq: request bio is being merged into - * @bio: new block operation to merge - * - * Merging block IO operation @bio to the beginning of an existing block - * operation in queue @q. - */ -DEFINE_EVENT(block_bio_merge, block_bio_frontmerge, - - TP_PROTO(struct request_queue *q, struct request *rq, struct bio *bio), - - TP_ARGS(q, rq, bio) -); - -/** - * block_bio_queue - putting new block IO operation in queue - * @q: queue holding operation - * @bio: new block operation - * - * About to place the block IO operation @bio into queue @q. - */ -TRACE_EVENT(block_bio_queue, - - TP_PROTO(struct request_queue *q, struct bio *bio), - - TP_ARGS(q, bio), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( sector_t, sector ) - __field( unsigned int, nr_sector ) - __array( char, rwbs, RWBS_LEN ) - __array( char, comm, TASK_COMM_LEN ) - ), - - TP_fast_assign( - __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_iter.bi_sector; - __entry->nr_sector = bio_sectors(bio); - blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_opf, - bio->bi_iter.bi_size); - memcpy(__entry->comm, current->comm, TASK_COMM_LEN); - ), - - TP_printk("%d,%d %s %llu + %u [%s]", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs, - (unsigned long long)__entry->sector, - __entry->nr_sector, __entry->comm) -); - -DECLARE_EVENT_CLASS(block_get_rq, - - TP_PROTO(struct request_queue *q, struct bio *bio, int rw), - - TP_ARGS(q, bio, rw), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( sector_t, sector ) - __field( unsigned int, nr_sector ) - __array( char, rwbs, RWBS_LEN ) - __array( char, comm, TASK_COMM_LEN ) - ), - - TP_fast_assign( - __entry->dev = bio ? bio->bi_bdev->bd_dev : 0; - __entry->sector = bio ? bio->bi_iter.bi_sector : 0; - __entry->nr_sector = bio ? bio_sectors(bio) : 0; - blk_fill_rwbs(__entry->rwbs, bio ? bio_op(bio) : 0, - bio ? bio->bi_opf : 0, __entry->nr_sector); - memcpy(__entry->comm, current->comm, TASK_COMM_LEN); - ), - - TP_printk("%d,%d %s %llu + %u [%s]", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs, - (unsigned long long)__entry->sector, - __entry->nr_sector, __entry->comm) -); - -/** - * block_getrq - get a free request entry in queue for block IO operations - * @q: queue for operations - * @bio: pending block IO operation - * @rw: low bit indicates a read (%0) or a write (%1) - * - * A request struct for queue @q has been allocated to handle the - * block IO operation @bio. - */ -DEFINE_EVENT(block_get_rq, block_getrq, - - TP_PROTO(struct request_queue *q, struct bio *bio, int rw), - - TP_ARGS(q, bio, rw) -); - -/** - * block_sleeprq - waiting to get a free request entry in queue for block IO operation - * @q: queue for operation - * @bio: pending block IO operation - * @rw: low bit indicates a read (%0) or a write (%1) - * - * In the case where a request struct cannot be provided for queue @q - * the process needs to wait for an request struct to become - * available. This tracepoint event is generated each time the - * process goes to sleep waiting for request struct become available. - */ -DEFINE_EVENT(block_get_rq, block_sleeprq, - - TP_PROTO(struct request_queue *q, struct bio *bio, int rw), - - TP_ARGS(q, bio, rw) -); - -/** - * block_plug - keep operations requests in request queue - * @q: request queue to plug - * - * Plug the request queue @q. Do not allow block operation requests - * to be sent to the device driver. Instead, accumulate requests in - * the queue to improve throughput performance of the block device. - */ -TRACE_EVENT(block_plug, - - TP_PROTO(struct request_queue *q), - - TP_ARGS(q), - - TP_STRUCT__entry( - __array( char, comm, TASK_COMM_LEN ) - ), - - TP_fast_assign( - memcpy(__entry->comm, current->comm, TASK_COMM_LEN); - ), - - TP_printk("[%s]", __entry->comm) -); - -DECLARE_EVENT_CLASS(block_unplug, - - TP_PROTO(struct request_queue *q, unsigned int depth, bool explicit), - - TP_ARGS(q, depth, explicit), - - TP_STRUCT__entry( - __field( int, nr_rq ) - __array( char, comm, TASK_COMM_LEN ) - ), - - TP_fast_assign( - __entry->nr_rq = depth; - memcpy(__entry->comm, current->comm, TASK_COMM_LEN); - ), - - TP_printk("[%s] %d", __entry->comm, __entry->nr_rq) -); - -/** - * block_unplug - release of operations requests in request queue - * @q: request queue to unplug - * @depth: number of requests just added to the queue - * @explicit: whether this was an explicit unplug, or one from schedule() - * - * Unplug request queue @q because device driver is scheduled to work - * on elements in the request queue. - */ -DEFINE_EVENT(block_unplug, block_unplug, - - TP_PROTO(struct request_queue *q, unsigned int depth, bool explicit), - - TP_ARGS(q, depth, explicit) -); - -/** - * block_split - split a single bio struct into two bio structs - * @q: queue containing the bio - * @bio: block operation being split - * @new_sector: The starting sector for the new bio - * - * The bio request @bio in request queue @q needs to be split into two - * bio requests. The newly created @bio request starts at - * @new_sector. This split may be required due to hardware limitation - * such as operation crossing device boundaries in a RAID system. - */ -TRACE_EVENT(block_split, - - TP_PROTO(struct request_queue *q, struct bio *bio, - unsigned int new_sector), - - TP_ARGS(q, bio, new_sector), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( sector_t, sector ) - __field( sector_t, new_sector ) - __array( char, rwbs, RWBS_LEN ) - __array( char, comm, TASK_COMM_LEN ) - ), - - TP_fast_assign( - __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_iter.bi_sector; - __entry->new_sector = new_sector; - blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_opf, - bio->bi_iter.bi_size); - memcpy(__entry->comm, current->comm, TASK_COMM_LEN); - ), - - TP_printk("%d,%d %s %llu / %llu [%s]", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs, - (unsigned long long)__entry->sector, - (unsigned long long)__entry->new_sector, - __entry->comm) -); - -/** - * block_bio_remap - map request for a logical device to the raw device - * @q: queue holding the operation - * @bio: revised operation - * @dev: device for the operation - * @from: original sector for the operation - * - * An operation for a logical device has been mapped to the - * raw block device. - */ -TRACE_EVENT(block_bio_remap, - - TP_PROTO(struct request_queue *q, struct bio *bio, dev_t dev, - sector_t from), - - TP_ARGS(q, bio, dev, from), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( sector_t, sector ) - __field( unsigned int, nr_sector ) - __field( dev_t, old_dev ) - __field( sector_t, old_sector ) - __array( char, rwbs, RWBS_LEN) - ), - - TP_fast_assign( - __entry->dev = bio->bi_bdev->bd_dev; - __entry->sector = bio->bi_iter.bi_sector; - __entry->nr_sector = bio_sectors(bio); - __entry->old_dev = dev; - __entry->old_sector = from; - blk_fill_rwbs(__entry->rwbs, bio_op(bio), bio->bi_opf, - bio->bi_iter.bi_size); - ), - - TP_printk("%d,%d %s %llu + %u <- (%d,%d) %llu", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs, - (unsigned long long)__entry->sector, - __entry->nr_sector, - MAJOR(__entry->old_dev), MINOR(__entry->old_dev), - (unsigned long long)__entry->old_sector) -); - -/** - * block_rq_remap - map request for a block operation request - * @q: queue holding the operation - * @rq: block IO operation request - * @dev: device for the operation - * @from: original sector for the operation - * - * The block operation request @rq in @q has been remapped. The block - * operation request @rq holds the current information and @from hold - * the original sector. - */ -TRACE_EVENT(block_rq_remap, - - TP_PROTO(struct request_queue *q, struct request *rq, dev_t dev, - sector_t from), - - TP_ARGS(q, rq, dev, from), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( sector_t, sector ) - __field( unsigned int, nr_sector ) - __field( dev_t, old_dev ) - __field( sector_t, old_sector ) - __field( unsigned int, nr_bios ) - __array( char, rwbs, RWBS_LEN) - ), - - TP_fast_assign( - __entry->dev = disk_devt(rq->rq_disk); - __entry->sector = blk_rq_pos(rq); - __entry->nr_sector = blk_rq_sectors(rq); - __entry->old_dev = dev; - __entry->old_sector = from; - __entry->nr_bios = blk_rq_count_bios(rq); - blk_fill_rwbs(__entry->rwbs, req_op(rq), rq->cmd_flags, - blk_rq_bytes(rq)); - ), - - TP_printk("%d,%d %s %llu + %u <- (%d,%d) %llu %u", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->rwbs, - (unsigned long long)__entry->sector, - __entry->nr_sector, - MAJOR(__entry->old_dev), MINOR(__entry->old_dev), - (unsigned long long)__entry->old_sector, __entry->nr_bios) -); - -#endif /* _TRACE_BLOCK_H */ - -/* This part must be outside protection */ -#include - diff --git a/src/linux/include/trace/events/btrfs.h b/src/linux/include/trace/events/btrfs.h deleted file mode 100644 index e030d6f..0000000 --- a/src/linux/include/trace/events/btrfs.h +++ /dev/null @@ -1,1474 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM btrfs - -#if !defined(_TRACE_BTRFS_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_BTRFS_H - -#include -#include -#include - -struct btrfs_root; -struct btrfs_fs_info; -struct btrfs_inode; -struct extent_map; -struct btrfs_ordered_extent; -struct btrfs_delayed_ref_node; -struct btrfs_delayed_tree_ref; -struct btrfs_delayed_data_ref; -struct btrfs_delayed_ref_head; -struct btrfs_block_group_cache; -struct btrfs_free_cluster; -struct map_lookup; -struct extent_buffer; -struct btrfs_work; -struct __btrfs_workqueue; -struct btrfs_qgroup_extent_record; - -#define show_ref_type(type) \ - __print_symbolic(type, \ - { BTRFS_TREE_BLOCK_REF_KEY, "TREE_BLOCK_REF" }, \ - { BTRFS_EXTENT_DATA_REF_KEY, "EXTENT_DATA_REF" }, \ - { BTRFS_EXTENT_REF_V0_KEY, "EXTENT_REF_V0" }, \ - { BTRFS_SHARED_BLOCK_REF_KEY, "SHARED_BLOCK_REF" }, \ - { BTRFS_SHARED_DATA_REF_KEY, "SHARED_DATA_REF" }) - -#define __show_root_type(obj) \ - __print_symbolic_u64(obj, \ - { BTRFS_ROOT_TREE_OBJECTID, "ROOT_TREE" }, \ - { BTRFS_EXTENT_TREE_OBJECTID, "EXTENT_TREE" }, \ - { BTRFS_CHUNK_TREE_OBJECTID, "CHUNK_TREE" }, \ - { BTRFS_DEV_TREE_OBJECTID, "DEV_TREE" }, \ - { BTRFS_FS_TREE_OBJECTID, "FS_TREE" }, \ - { BTRFS_ROOT_TREE_DIR_OBJECTID, "ROOT_TREE_DIR" }, \ - { BTRFS_CSUM_TREE_OBJECTID, "CSUM_TREE" }, \ - { BTRFS_TREE_LOG_OBJECTID, "TREE_LOG" }, \ - { BTRFS_QUOTA_TREE_OBJECTID, "QUOTA_TREE" }, \ - { BTRFS_TREE_RELOC_OBJECTID, "TREE_RELOC" }, \ - { BTRFS_UUID_TREE_OBJECTID, "UUID_TREE" }, \ - { BTRFS_FREE_SPACE_TREE_OBJECTID, "FREE_SPACE_TREE" }, \ - { BTRFS_DATA_RELOC_TREE_OBJECTID, "DATA_RELOC_TREE" }) - -#define show_root_type(obj) \ - obj, ((obj >= BTRFS_DATA_RELOC_TREE_OBJECTID) || \ - (obj >= BTRFS_ROOT_TREE_OBJECTID && \ - obj <= BTRFS_QUOTA_TREE_OBJECTID)) ? __show_root_type(obj) : "-" - -#define BTRFS_GROUP_FLAGS \ - { BTRFS_BLOCK_GROUP_DATA, "DATA"}, \ - { BTRFS_BLOCK_GROUP_SYSTEM, "SYSTEM"}, \ - { BTRFS_BLOCK_GROUP_METADATA, "METADATA"}, \ - { BTRFS_BLOCK_GROUP_RAID0, "RAID0"}, \ - { BTRFS_BLOCK_GROUP_RAID1, "RAID1"}, \ - { BTRFS_BLOCK_GROUP_DUP, "DUP"}, \ - { BTRFS_BLOCK_GROUP_RAID10, "RAID10"}, \ - { BTRFS_BLOCK_GROUP_RAID5, "RAID5"}, \ - { BTRFS_BLOCK_GROUP_RAID6, "RAID6"} - -#define BTRFS_UUID_SIZE 16 -#define TP_STRUCT__entry_fsid __array(u8, fsid, BTRFS_UUID_SIZE) - -#define TP_fast_assign_fsid(fs_info) \ - memcpy(__entry->fsid, fs_info->fsid, BTRFS_UUID_SIZE) - -#define TP_STRUCT__entry_btrfs(args...) \ - TP_STRUCT__entry( \ - TP_STRUCT__entry_fsid \ - args) -#define TP_fast_assign_btrfs(fs_info, args...) \ - TP_fast_assign( \ - TP_fast_assign_fsid(fs_info); \ - args) -#define TP_printk_btrfs(fmt, args...) \ - TP_printk("%pU: " fmt, __entry->fsid, args) - -TRACE_EVENT(btrfs_transaction_commit, - - TP_PROTO(struct btrfs_root *root), - - TP_ARGS(root), - - TP_STRUCT__entry_btrfs( - __field( u64, generation ) - __field( u64, root_objectid ) - ), - - TP_fast_assign_btrfs(root->fs_info, - __entry->generation = root->fs_info->generation; - __entry->root_objectid = root->root_key.objectid; - ), - - TP_printk_btrfs("root = %llu(%s), gen = %llu", - show_root_type(__entry->root_objectid), - (unsigned long long)__entry->generation) -); - -DECLARE_EVENT_CLASS(btrfs__inode, - - TP_PROTO(struct inode *inode), - - TP_ARGS(inode), - - TP_STRUCT__entry_btrfs( - __field( ino_t, ino ) - __field( blkcnt_t, blocks ) - __field( u64, disk_i_size ) - __field( u64, generation ) - __field( u64, last_trans ) - __field( u64, logged_trans ) - __field( u64, root_objectid ) - ), - - TP_fast_assign_btrfs(btrfs_sb(inode->i_sb), - __entry->ino = inode->i_ino; - __entry->blocks = inode->i_blocks; - __entry->disk_i_size = BTRFS_I(inode)->disk_i_size; - __entry->generation = BTRFS_I(inode)->generation; - __entry->last_trans = BTRFS_I(inode)->last_trans; - __entry->logged_trans = BTRFS_I(inode)->logged_trans; - __entry->root_objectid = - BTRFS_I(inode)->root->root_key.objectid; - ), - - TP_printk_btrfs("root = %llu(%s), gen = %llu, ino = %lu, blocks = %llu, " - "disk_i_size = %llu, last_trans = %llu, logged_trans = %llu", - show_root_type(__entry->root_objectid), - (unsigned long long)__entry->generation, - (unsigned long)__entry->ino, - (unsigned long long)__entry->blocks, - (unsigned long long)__entry->disk_i_size, - (unsigned long long)__entry->last_trans, - (unsigned long long)__entry->logged_trans) -); - -DEFINE_EVENT(btrfs__inode, btrfs_inode_new, - - TP_PROTO(struct inode *inode), - - TP_ARGS(inode) -); - -DEFINE_EVENT(btrfs__inode, btrfs_inode_request, - - TP_PROTO(struct inode *inode), - - TP_ARGS(inode) -); - -DEFINE_EVENT(btrfs__inode, btrfs_inode_evict, - - TP_PROTO(struct inode *inode), - - TP_ARGS(inode) -); - -#define __show_map_type(type) \ - __print_symbolic_u64(type, \ - { EXTENT_MAP_LAST_BYTE, "LAST_BYTE" }, \ - { EXTENT_MAP_HOLE, "HOLE" }, \ - { EXTENT_MAP_INLINE, "INLINE" }, \ - { EXTENT_MAP_DELALLOC, "DELALLOC" }) - -#define show_map_type(type) \ - type, (type >= EXTENT_MAP_LAST_BYTE) ? "-" : __show_map_type(type) - -#define show_map_flags(flag) \ - __print_flags(flag, "|", \ - { (1 << EXTENT_FLAG_PINNED), "PINNED" },\ - { (1 << EXTENT_FLAG_COMPRESSED), "COMPRESSED" },\ - { (1 << EXTENT_FLAG_VACANCY), "VACANCY" },\ - { (1 << EXTENT_FLAG_PREALLOC), "PREALLOC" },\ - { (1 << EXTENT_FLAG_LOGGING), "LOGGING" },\ - { (1 << EXTENT_FLAG_FILLING), "FILLING" },\ - { (1 << EXTENT_FLAG_FS_MAPPING), "FS_MAPPING" }) - -TRACE_EVENT_CONDITION(btrfs_get_extent, - - TP_PROTO(struct btrfs_root *root, struct extent_map *map), - - TP_ARGS(root, map), - - TP_CONDITION(map), - - TP_STRUCT__entry_btrfs( - __field( u64, root_objectid ) - __field( u64, start ) - __field( u64, len ) - __field( u64, orig_start ) - __field( u64, block_start ) - __field( u64, block_len ) - __field( unsigned long, flags ) - __field( int, refs ) - __field( unsigned int, compress_type ) - ), - - TP_fast_assign_btrfs(root->fs_info, - __entry->root_objectid = root->root_key.objectid; - __entry->start = map->start; - __entry->len = map->len; - __entry->orig_start = map->orig_start; - __entry->block_start = map->block_start; - __entry->block_len = map->block_len; - __entry->flags = map->flags; - __entry->refs = atomic_read(&map->refs); - __entry->compress_type = map->compress_type; - ), - - TP_printk_btrfs("root = %llu(%s), start = %llu, len = %llu, " - "orig_start = %llu, block_start = %llu(%s), " - "block_len = %llu, flags = %s, refs = %u, " - "compress_type = %u", - show_root_type(__entry->root_objectid), - (unsigned long long)__entry->start, - (unsigned long long)__entry->len, - (unsigned long long)__entry->orig_start, - show_map_type(__entry->block_start), - (unsigned long long)__entry->block_len, - show_map_flags(__entry->flags), - __entry->refs, __entry->compress_type) -); - -#define show_ordered_flags(flags) \ - __print_flags(flags, "|", \ - { (1 << BTRFS_ORDERED_IO_DONE), "IO_DONE" }, \ - { (1 << BTRFS_ORDERED_COMPLETE), "COMPLETE" }, \ - { (1 << BTRFS_ORDERED_NOCOW), "NOCOW" }, \ - { (1 << BTRFS_ORDERED_COMPRESSED), "COMPRESSED" }, \ - { (1 << BTRFS_ORDERED_PREALLOC), "PREALLOC" }, \ - { (1 << BTRFS_ORDERED_DIRECT), "DIRECT" }, \ - { (1 << BTRFS_ORDERED_IOERR), "IOERR" }, \ - { (1 << BTRFS_ORDERED_UPDATED_ISIZE), "UPDATED_ISIZE" }, \ - { (1 << BTRFS_ORDERED_LOGGED_CSUM), "LOGGED_CSUM" }, \ - { (1 << BTRFS_ORDERED_TRUNCATED), "TRUNCATED" }) - - -DECLARE_EVENT_CLASS(btrfs__ordered_extent, - - TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered), - - TP_ARGS(inode, ordered), - - TP_STRUCT__entry_btrfs( - __field( ino_t, ino ) - __field( u64, file_offset ) - __field( u64, start ) - __field( u64, len ) - __field( u64, disk_len ) - __field( u64, bytes_left ) - __field( unsigned long, flags ) - __field( int, compress_type ) - __field( int, refs ) - __field( u64, root_objectid ) - ), - - TP_fast_assign_btrfs(btrfs_sb(inode->i_sb), - __entry->ino = inode->i_ino; - __entry->file_offset = ordered->file_offset; - __entry->start = ordered->start; - __entry->len = ordered->len; - __entry->disk_len = ordered->disk_len; - __entry->bytes_left = ordered->bytes_left; - __entry->flags = ordered->flags; - __entry->compress_type = ordered->compress_type; - __entry->refs = atomic_read(&ordered->refs); - __entry->root_objectid = - BTRFS_I(inode)->root->root_key.objectid; - ), - - TP_printk_btrfs("root = %llu(%s), ino = %llu, file_offset = %llu, " - "start = %llu, len = %llu, disk_len = %llu, " - "bytes_left = %llu, flags = %s, compress_type = %d, " - "refs = %d", - show_root_type(__entry->root_objectid), - (unsigned long long)__entry->ino, - (unsigned long long)__entry->file_offset, - (unsigned long long)__entry->start, - (unsigned long long)__entry->len, - (unsigned long long)__entry->disk_len, - (unsigned long long)__entry->bytes_left, - show_ordered_flags(__entry->flags), - __entry->compress_type, __entry->refs) -); - -DEFINE_EVENT(btrfs__ordered_extent, btrfs_ordered_extent_add, - - TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered), - - TP_ARGS(inode, ordered) -); - -DEFINE_EVENT(btrfs__ordered_extent, btrfs_ordered_extent_remove, - - TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered), - - TP_ARGS(inode, ordered) -); - -DEFINE_EVENT(btrfs__ordered_extent, btrfs_ordered_extent_start, - - TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered), - - TP_ARGS(inode, ordered) -); - -DEFINE_EVENT(btrfs__ordered_extent, btrfs_ordered_extent_put, - - TP_PROTO(struct inode *inode, struct btrfs_ordered_extent *ordered), - - TP_ARGS(inode, ordered) -); - -DECLARE_EVENT_CLASS(btrfs__writepage, - - TP_PROTO(struct page *page, struct inode *inode, - struct writeback_control *wbc), - - TP_ARGS(page, inode, wbc), - - TP_STRUCT__entry_btrfs( - __field( ino_t, ino ) - __field( pgoff_t, index ) - __field( long, nr_to_write ) - __field( long, pages_skipped ) - __field( loff_t, range_start ) - __field( loff_t, range_end ) - __field( char, for_kupdate ) - __field( char, for_reclaim ) - __field( char, range_cyclic ) - __field( pgoff_t, writeback_index ) - __field( u64, root_objectid ) - ), - - TP_fast_assign_btrfs(btrfs_sb(inode->i_sb), - __entry->ino = inode->i_ino; - __entry->index = page->index; - __entry->nr_to_write = wbc->nr_to_write; - __entry->pages_skipped = wbc->pages_skipped; - __entry->range_start = wbc->range_start; - __entry->range_end = wbc->range_end; - __entry->for_kupdate = wbc->for_kupdate; - __entry->for_reclaim = wbc->for_reclaim; - __entry->range_cyclic = wbc->range_cyclic; - __entry->writeback_index = inode->i_mapping->writeback_index; - __entry->root_objectid = - BTRFS_I(inode)->root->root_key.objectid; - ), - - TP_printk_btrfs("root = %llu(%s), ino = %lu, page_index = %lu, " - "nr_to_write = %ld, pages_skipped = %ld, range_start = %llu, " - "range_end = %llu, for_kupdate = %d, " - "for_reclaim = %d, range_cyclic = %d, writeback_index = %lu", - show_root_type(__entry->root_objectid), - (unsigned long)__entry->ino, __entry->index, - __entry->nr_to_write, __entry->pages_skipped, - __entry->range_start, __entry->range_end, - __entry->for_kupdate, - __entry->for_reclaim, __entry->range_cyclic, - (unsigned long)__entry->writeback_index) -); - -DEFINE_EVENT(btrfs__writepage, __extent_writepage, - - TP_PROTO(struct page *page, struct inode *inode, - struct writeback_control *wbc), - - TP_ARGS(page, inode, wbc) -); - -TRACE_EVENT(btrfs_writepage_end_io_hook, - - TP_PROTO(struct page *page, u64 start, u64 end, int uptodate), - - TP_ARGS(page, start, end, uptodate), - - TP_STRUCT__entry_btrfs( - __field( ino_t, ino ) - __field( pgoff_t, index ) - __field( u64, start ) - __field( u64, end ) - __field( int, uptodate ) - __field( u64, root_objectid ) - ), - - TP_fast_assign_btrfs(btrfs_sb(page->mapping->host->i_sb), - __entry->ino = page->mapping->host->i_ino; - __entry->index = page->index; - __entry->start = start; - __entry->end = end; - __entry->uptodate = uptodate; - __entry->root_objectid = - BTRFS_I(page->mapping->host)->root->root_key.objectid; - ), - - TP_printk_btrfs("root = %llu(%s), ino = %lu, page_index = %lu, start = %llu, " - "end = %llu, uptodate = %d", - show_root_type(__entry->root_objectid), - (unsigned long)__entry->ino, (unsigned long)__entry->index, - (unsigned long long)__entry->start, - (unsigned long long)__entry->end, __entry->uptodate) -); - -TRACE_EVENT(btrfs_sync_file, - - TP_PROTO(struct file *file, int datasync), - - TP_ARGS(file, datasync), - - TP_STRUCT__entry_btrfs( - __field( ino_t, ino ) - __field( ino_t, parent ) - __field( int, datasync ) - __field( u64, root_objectid ) - ), - - TP_fast_assign( - struct dentry *dentry = file->f_path.dentry; - struct inode *inode = d_inode(dentry); - - TP_fast_assign_fsid(btrfs_sb(file->f_path.dentry->d_sb)); - __entry->ino = inode->i_ino; - __entry->parent = d_inode(dentry->d_parent)->i_ino; - __entry->datasync = datasync; - __entry->root_objectid = - BTRFS_I(inode)->root->root_key.objectid; - ), - - TP_printk_btrfs("root = %llu(%s), ino = %ld, parent = %ld, datasync = %d", - show_root_type(__entry->root_objectid), - (unsigned long)__entry->ino, (unsigned long)__entry->parent, - __entry->datasync) -); - -TRACE_EVENT(btrfs_sync_fs, - - TP_PROTO(struct btrfs_fs_info *fs_info, int wait), - - TP_ARGS(fs_info, wait), - - TP_STRUCT__entry_btrfs( - __field( int, wait ) - ), - - TP_fast_assign_btrfs(fs_info, - __entry->wait = wait; - ), - - TP_printk_btrfs("wait = %d", __entry->wait) -); - -TRACE_EVENT(btrfs_add_block_group, - - TP_PROTO(struct btrfs_fs_info *fs_info, - struct btrfs_block_group_cache *block_group, int create), - - TP_ARGS(fs_info, block_group, create), - - TP_STRUCT__entry( - __array( u8, fsid, BTRFS_UUID_SIZE ) - __field( u64, offset ) - __field( u64, size ) - __field( u64, flags ) - __field( u64, bytes_used ) - __field( u64, bytes_super ) - __field( int, create ) - ), - - TP_fast_assign( - memcpy(__entry->fsid, fs_info->fsid, BTRFS_UUID_SIZE); - __entry->offset = block_group->key.objectid; - __entry->size = block_group->key.offset; - __entry->flags = block_group->flags; - __entry->bytes_used = - btrfs_block_group_used(&block_group->item); - __entry->bytes_super = block_group->bytes_super; - __entry->create = create; - ), - - TP_printk("%pU: block_group offset = %llu, size = %llu, " - "flags = %llu(%s), bytes_used = %llu, bytes_super = %llu, " - "create = %d", __entry->fsid, - (unsigned long long)__entry->offset, - (unsigned long long)__entry->size, - (unsigned long long)__entry->flags, - __print_flags((unsigned long)__entry->flags, "|", - BTRFS_GROUP_FLAGS), - (unsigned long long)__entry->bytes_used, - (unsigned long long)__entry->bytes_super, __entry->create) -); - -#define show_ref_action(action) \ - __print_symbolic(action, \ - { BTRFS_ADD_DELAYED_REF, "ADD_DELAYED_REF" }, \ - { BTRFS_DROP_DELAYED_REF, "DROP_DELAYED_REF" }, \ - { BTRFS_ADD_DELAYED_EXTENT, "ADD_DELAYED_EXTENT" }, \ - { BTRFS_UPDATE_DELAYED_HEAD, "UPDATE_DELAYED_HEAD" }) - - -DECLARE_EVENT_CLASS(btrfs_delayed_tree_ref, - - TP_PROTO(struct btrfs_fs_info *fs_info, - struct btrfs_delayed_ref_node *ref, - struct btrfs_delayed_tree_ref *full_ref, - int action), - - TP_ARGS(fs_info, ref, full_ref, action), - - TP_STRUCT__entry_btrfs( - __field( u64, bytenr ) - __field( u64, num_bytes ) - __field( int, action ) - __field( u64, parent ) - __field( u64, ref_root ) - __field( int, level ) - __field( int, type ) - __field( u64, seq ) - ), - - TP_fast_assign_btrfs(fs_info, - __entry->bytenr = ref->bytenr; - __entry->num_bytes = ref->num_bytes; - __entry->action = action; - __entry->parent = full_ref->parent; - __entry->ref_root = full_ref->root; - __entry->level = full_ref->level; - __entry->type = ref->type; - __entry->seq = ref->seq; - ), - - TP_printk_btrfs("bytenr = %llu, num_bytes = %llu, action = %s, " - "parent = %llu(%s), ref_root = %llu(%s), level = %d, " - "type = %s, seq = %llu", - (unsigned long long)__entry->bytenr, - (unsigned long long)__entry->num_bytes, - show_ref_action(__entry->action), - show_root_type(__entry->parent), - show_root_type(__entry->ref_root), - __entry->level, show_ref_type(__entry->type), - (unsigned long long)__entry->seq) -); - -DEFINE_EVENT(btrfs_delayed_tree_ref, add_delayed_tree_ref, - - TP_PROTO(struct btrfs_fs_info *fs_info, - struct btrfs_delayed_ref_node *ref, - struct btrfs_delayed_tree_ref *full_ref, - int action), - - TP_ARGS(fs_info, ref, full_ref, action) -); - -DEFINE_EVENT(btrfs_delayed_tree_ref, run_delayed_tree_ref, - - TP_PROTO(struct btrfs_fs_info *fs_info, - struct btrfs_delayed_ref_node *ref, - struct btrfs_delayed_tree_ref *full_ref, - int action), - - TP_ARGS(fs_info, ref, full_ref, action) -); - -DECLARE_EVENT_CLASS(btrfs_delayed_data_ref, - - TP_PROTO(struct btrfs_fs_info *fs_info, - struct btrfs_delayed_ref_node *ref, - struct btrfs_delayed_data_ref *full_ref, - int action), - - TP_ARGS(fs_info, ref, full_ref, action), - - TP_STRUCT__entry_btrfs( - __field( u64, bytenr ) - __field( u64, num_bytes ) - __field( int, action ) - __field( u64, parent ) - __field( u64, ref_root ) - __field( u64, owner ) - __field( u64, offset ) - __field( int, type ) - __field( u64, seq ) - ), - - TP_fast_assign_btrfs(fs_info, - __entry->bytenr = ref->bytenr; - __entry->num_bytes = ref->num_bytes; - __entry->action = action; - __entry->parent = full_ref->parent; - __entry->ref_root = full_ref->root; - __entry->owner = full_ref->objectid; - __entry->offset = full_ref->offset; - __entry->type = ref->type; - __entry->seq = ref->seq; - ), - - TP_printk_btrfs("bytenr = %llu, num_bytes = %llu, action = %s, " - "parent = %llu(%s), ref_root = %llu(%s), owner = %llu, " - "offset = %llu, type = %s, seq = %llu", - (unsigned long long)__entry->bytenr, - (unsigned long long)__entry->num_bytes, - show_ref_action(__entry->action), - show_root_type(__entry->parent), - show_root_type(__entry->ref_root), - (unsigned long long)__entry->owner, - (unsigned long long)__entry->offset, - show_ref_type(__entry->type), - (unsigned long long)__entry->seq) -); - -DEFINE_EVENT(btrfs_delayed_data_ref, add_delayed_data_ref, - - TP_PROTO(struct btrfs_fs_info *fs_info, - struct btrfs_delayed_ref_node *ref, - struct btrfs_delayed_data_ref *full_ref, - int action), - - TP_ARGS(fs_info, ref, full_ref, action) -); - -DEFINE_EVENT(btrfs_delayed_data_ref, run_delayed_data_ref, - - TP_PROTO(struct btrfs_fs_info *fs_info, - struct btrfs_delayed_ref_node *ref, - struct btrfs_delayed_data_ref *full_ref, - int action), - - TP_ARGS(fs_info, ref, full_ref, action) -); - -DECLARE_EVENT_CLASS(btrfs_delayed_ref_head, - - TP_PROTO(struct btrfs_fs_info *fs_info, - struct btrfs_delayed_ref_node *ref, - struct btrfs_delayed_ref_head *head_ref, - int action), - - TP_ARGS(fs_info, ref, head_ref, action), - - TP_STRUCT__entry_btrfs( - __field( u64, bytenr ) - __field( u64, num_bytes ) - __field( int, action ) - __field( int, is_data ) - ), - - TP_fast_assign_btrfs(fs_info, - __entry->bytenr = ref->bytenr; - __entry->num_bytes = ref->num_bytes; - __entry->action = action; - __entry->is_data = head_ref->is_data; - ), - - TP_printk_btrfs("bytenr = %llu, num_bytes = %llu, action = %s, is_data = %d", - (unsigned long long)__entry->bytenr, - (unsigned long long)__entry->num_bytes, - show_ref_action(__entry->action), - __entry->is_data) -); - -DEFINE_EVENT(btrfs_delayed_ref_head, add_delayed_ref_head, - - TP_PROTO(struct btrfs_fs_info *fs_info, - struct btrfs_delayed_ref_node *ref, - struct btrfs_delayed_ref_head *head_ref, - int action), - - TP_ARGS(fs_info, ref, head_ref, action) -); - -DEFINE_EVENT(btrfs_delayed_ref_head, run_delayed_ref_head, - - TP_PROTO(struct btrfs_fs_info *fs_info, - struct btrfs_delayed_ref_node *ref, - struct btrfs_delayed_ref_head *head_ref, - int action), - - TP_ARGS(fs_info, ref, head_ref, action) -); - -#define show_chunk_type(type) \ - __print_flags(type, "|", \ - { BTRFS_BLOCK_GROUP_DATA, "DATA" }, \ - { BTRFS_BLOCK_GROUP_SYSTEM, "SYSTEM"}, \ - { BTRFS_BLOCK_GROUP_METADATA, "METADATA"}, \ - { BTRFS_BLOCK_GROUP_RAID0, "RAID0" }, \ - { BTRFS_BLOCK_GROUP_RAID1, "RAID1" }, \ - { BTRFS_BLOCK_GROUP_DUP, "DUP" }, \ - { BTRFS_BLOCK_GROUP_RAID10, "RAID10"}, \ - { BTRFS_BLOCK_GROUP_RAID5, "RAID5" }, \ - { BTRFS_BLOCK_GROUP_RAID6, "RAID6" }) - -DECLARE_EVENT_CLASS(btrfs__chunk, - - TP_PROTO(struct btrfs_root *root, struct map_lookup *map, - u64 offset, u64 size), - - TP_ARGS(root, map, offset, size), - - TP_STRUCT__entry_btrfs( - __field( int, num_stripes ) - __field( u64, type ) - __field( int, sub_stripes ) - __field( u64, offset ) - __field( u64, size ) - __field( u64, root_objectid ) - ), - - TP_fast_assign_btrfs(root->fs_info, - __entry->num_stripes = map->num_stripes; - __entry->type = map->type; - __entry->sub_stripes = map->sub_stripes; - __entry->offset = offset; - __entry->size = size; - __entry->root_objectid = root->root_key.objectid; - ), - - TP_printk_btrfs("root = %llu(%s), offset = %llu, size = %llu, " - "num_stripes = %d, sub_stripes = %d, type = %s", - show_root_type(__entry->root_objectid), - (unsigned long long)__entry->offset, - (unsigned long long)__entry->size, - __entry->num_stripes, __entry->sub_stripes, - show_chunk_type(__entry->type)) -); - -DEFINE_EVENT(btrfs__chunk, btrfs_chunk_alloc, - - TP_PROTO(struct btrfs_root *root, struct map_lookup *map, - u64 offset, u64 size), - - TP_ARGS(root, map, offset, size) -); - -DEFINE_EVENT(btrfs__chunk, btrfs_chunk_free, - - TP_PROTO(struct btrfs_root *root, struct map_lookup *map, - u64 offset, u64 size), - - TP_ARGS(root, map, offset, size) -); - -TRACE_EVENT(btrfs_cow_block, - - TP_PROTO(struct btrfs_root *root, struct extent_buffer *buf, - struct extent_buffer *cow), - - TP_ARGS(root, buf, cow), - - TP_STRUCT__entry_btrfs( - __field( u64, root_objectid ) - __field( u64, buf_start ) - __field( int, refs ) - __field( u64, cow_start ) - __field( int, buf_level ) - __field( int, cow_level ) - ), - - TP_fast_assign_btrfs(root->fs_info, - __entry->root_objectid = root->root_key.objectid; - __entry->buf_start = buf->start; - __entry->refs = atomic_read(&buf->refs); - __entry->cow_start = cow->start; - __entry->buf_level = btrfs_header_level(buf); - __entry->cow_level = btrfs_header_level(cow); - ), - - TP_printk_btrfs("root = %llu(%s), refs = %d, orig_buf = %llu " - "(orig_level = %d), cow_buf = %llu (cow_level = %d)", - show_root_type(__entry->root_objectid), - __entry->refs, - (unsigned long long)__entry->buf_start, - __entry->buf_level, - (unsigned long long)__entry->cow_start, - __entry->cow_level) -); - -TRACE_EVENT(btrfs_space_reservation, - - TP_PROTO(struct btrfs_fs_info *fs_info, char *type, u64 val, - u64 bytes, int reserve), - - TP_ARGS(fs_info, type, val, bytes, reserve), - - TP_STRUCT__entry_btrfs( - __string( type, type ) - __field( u64, val ) - __field( u64, bytes ) - __field( int, reserve ) - ), - - TP_fast_assign_btrfs(fs_info, - __assign_str(type, type); - __entry->val = val; - __entry->bytes = bytes; - __entry->reserve = reserve; - ), - - TP_printk_btrfs("%s: %Lu %s %Lu", __get_str(type), __entry->val, - __entry->reserve ? "reserve" : "release", - __entry->bytes) -); - -#define show_flush_action(action) \ - __print_symbolic(action, \ - { BTRFS_RESERVE_NO_FLUSH, "BTRFS_RESERVE_NO_FLUSH"}, \ - { BTRFS_RESERVE_FLUSH_LIMIT, "BTRFS_RESERVE_FLUSH_LIMIT"}, \ - { BTRFS_RESERVE_FLUSH_ALL, "BTRFS_RESERVE_FLUSH_ALL"}) - -TRACE_EVENT(btrfs_trigger_flush, - - TP_PROTO(struct btrfs_fs_info *fs_info, u64 flags, u64 bytes, - int flush, char *reason), - - TP_ARGS(fs_info, flags, bytes, flush, reason), - - TP_STRUCT__entry( - __array( u8, fsid, BTRFS_UUID_SIZE ) - __field( u64, flags ) - __field( u64, bytes ) - __field( int, flush ) - __string( reason, reason ) - ), - - TP_fast_assign( - memcpy(__entry->fsid, fs_info->fsid, BTRFS_UUID_SIZE); - __entry->flags = flags; - __entry->bytes = bytes; - __entry->flush = flush; - __assign_str(reason, reason) - ), - - TP_printk("%pU: %s: flush = %d(%s), flags = %llu(%s), bytes = %llu", - __entry->fsid, __get_str(reason), __entry->flush, - show_flush_action(__entry->flush), - (unsigned long long)__entry->flags, - __print_flags((unsigned long)__entry->flags, "|", - BTRFS_GROUP_FLAGS), - (unsigned long long)__entry->bytes) -); - -#define show_flush_state(state) \ - __print_symbolic(state, \ - { FLUSH_DELAYED_ITEMS_NR, "FLUSH_DELAYED_ITEMS_NR"}, \ - { FLUSH_DELAYED_ITEMS, "FLUSH_DELAYED_ITEMS"}, \ - { FLUSH_DELALLOC, "FLUSH_DELALLOC"}, \ - { FLUSH_DELALLOC_WAIT, "FLUSH_DELALLOC_WAIT"}, \ - { ALLOC_CHUNK, "ALLOC_CHUNK"}, \ - { COMMIT_TRANS, "COMMIT_TRANS"}) - -TRACE_EVENT(btrfs_flush_space, - - TP_PROTO(struct btrfs_fs_info *fs_info, u64 flags, u64 num_bytes, - u64 orig_bytes, int state, int ret), - - TP_ARGS(fs_info, flags, num_bytes, orig_bytes, state, ret), - - TP_STRUCT__entry( - __array( u8, fsid, BTRFS_UUID_SIZE ) - __field( u64, flags ) - __field( u64, num_bytes ) - __field( u64, orig_bytes ) - __field( int, state ) - __field( int, ret ) - ), - - TP_fast_assign( - memcpy(__entry->fsid, fs_info->fsid, BTRFS_UUID_SIZE); - __entry->flags = flags; - __entry->num_bytes = num_bytes; - __entry->orig_bytes = orig_bytes; - __entry->state = state; - __entry->ret = ret; - ), - - TP_printk("%pU: state = %d(%s), flags = %llu(%s), num_bytes = %llu, " - "orig_bytes = %llu, ret = %d", __entry->fsid, __entry->state, - show_flush_state(__entry->state), - (unsigned long long)__entry->flags, - __print_flags((unsigned long)__entry->flags, "|", - BTRFS_GROUP_FLAGS), - (unsigned long long)__entry->num_bytes, - (unsigned long long)__entry->orig_bytes, __entry->ret) -); - -DECLARE_EVENT_CLASS(btrfs__reserved_extent, - - TP_PROTO(struct btrfs_root *root, u64 start, u64 len), - - TP_ARGS(root, start, len), - - TP_STRUCT__entry_btrfs( - __field( u64, root_objectid ) - __field( u64, start ) - __field( u64, len ) - ), - - TP_fast_assign_btrfs(root->fs_info, - __entry->root_objectid = root->root_key.objectid; - __entry->start = start; - __entry->len = len; - ), - - TP_printk_btrfs("root = %llu(%s), start = %llu, len = %llu", - show_root_type(__entry->root_objectid), - (unsigned long long)__entry->start, - (unsigned long long)__entry->len) -); - -DEFINE_EVENT(btrfs__reserved_extent, btrfs_reserved_extent_alloc, - - TP_PROTO(struct btrfs_root *root, u64 start, u64 len), - - TP_ARGS(root, start, len) -); - -DEFINE_EVENT(btrfs__reserved_extent, btrfs_reserved_extent_free, - - TP_PROTO(struct btrfs_root *root, u64 start, u64 len), - - TP_ARGS(root, start, len) -); - -TRACE_EVENT(find_free_extent, - - TP_PROTO(struct btrfs_root *root, u64 num_bytes, u64 empty_size, - u64 data), - - TP_ARGS(root, num_bytes, empty_size, data), - - TP_STRUCT__entry_btrfs( - __field( u64, root_objectid ) - __field( u64, num_bytes ) - __field( u64, empty_size ) - __field( u64, data ) - ), - - TP_fast_assign_btrfs(root->fs_info, - __entry->root_objectid = root->root_key.objectid; - __entry->num_bytes = num_bytes; - __entry->empty_size = empty_size; - __entry->data = data; - ), - - TP_printk_btrfs("root = %Lu(%s), len = %Lu, empty_size = %Lu, " - "flags = %Lu(%s)", show_root_type(__entry->root_objectid), - __entry->num_bytes, __entry->empty_size, __entry->data, - __print_flags((unsigned long)__entry->data, "|", - BTRFS_GROUP_FLAGS)) -); - -DECLARE_EVENT_CLASS(btrfs__reserve_extent, - - TP_PROTO(struct btrfs_root *root, - struct btrfs_block_group_cache *block_group, u64 start, - u64 len), - - TP_ARGS(root, block_group, start, len), - - TP_STRUCT__entry_btrfs( - __field( u64, root_objectid ) - __field( u64, bg_objectid ) - __field( u64, flags ) - __field( u64, start ) - __field( u64, len ) - ), - - TP_fast_assign_btrfs(root->fs_info, - __entry->root_objectid = root->root_key.objectid; - __entry->bg_objectid = block_group->key.objectid; - __entry->flags = block_group->flags; - __entry->start = start; - __entry->len = len; - ), - - TP_printk_btrfs("root = %Lu(%s), block_group = %Lu, flags = %Lu(%s), " - "start = %Lu, len = %Lu", - show_root_type(__entry->root_objectid), __entry->bg_objectid, - __entry->flags, __print_flags((unsigned long)__entry->flags, - "|", BTRFS_GROUP_FLAGS), - __entry->start, __entry->len) -); - -DEFINE_EVENT(btrfs__reserve_extent, btrfs_reserve_extent, - - TP_PROTO(struct btrfs_root *root, - struct btrfs_block_group_cache *block_group, u64 start, - u64 len), - - TP_ARGS(root, block_group, start, len) -); - -DEFINE_EVENT(btrfs__reserve_extent, btrfs_reserve_extent_cluster, - - TP_PROTO(struct btrfs_root *root, - struct btrfs_block_group_cache *block_group, u64 start, - u64 len), - - TP_ARGS(root, block_group, start, len) -); - -TRACE_EVENT(btrfs_find_cluster, - - TP_PROTO(struct btrfs_block_group_cache *block_group, u64 start, - u64 bytes, u64 empty_size, u64 min_bytes), - - TP_ARGS(block_group, start, bytes, empty_size, min_bytes), - - TP_STRUCT__entry_btrfs( - __field( u64, bg_objectid ) - __field( u64, flags ) - __field( u64, start ) - __field( u64, bytes ) - __field( u64, empty_size ) - __field( u64, min_bytes ) - ), - - TP_fast_assign_btrfs(block_group->fs_info, - __entry->bg_objectid = block_group->key.objectid; - __entry->flags = block_group->flags; - __entry->start = start; - __entry->bytes = bytes; - __entry->empty_size = empty_size; - __entry->min_bytes = min_bytes; - ), - - TP_printk_btrfs("block_group = %Lu, flags = %Lu(%s), start = %Lu, len = %Lu," - " empty_size = %Lu, min_bytes = %Lu", __entry->bg_objectid, - __entry->flags, - __print_flags((unsigned long)__entry->flags, "|", - BTRFS_GROUP_FLAGS), __entry->start, - __entry->bytes, __entry->empty_size, __entry->min_bytes) -); - -TRACE_EVENT(btrfs_failed_cluster_setup, - - TP_PROTO(struct btrfs_block_group_cache *block_group), - - TP_ARGS(block_group), - - TP_STRUCT__entry_btrfs( - __field( u64, bg_objectid ) - ), - - TP_fast_assign_btrfs(block_group->fs_info, - __entry->bg_objectid = block_group->key.objectid; - ), - - TP_printk_btrfs("block_group = %Lu", __entry->bg_objectid) -); - -TRACE_EVENT(btrfs_setup_cluster, - - TP_PROTO(struct btrfs_block_group_cache *block_group, - struct btrfs_free_cluster *cluster, u64 size, int bitmap), - - TP_ARGS(block_group, cluster, size, bitmap), - - TP_STRUCT__entry_btrfs( - __field( u64, bg_objectid ) - __field( u64, flags ) - __field( u64, start ) - __field( u64, max_size ) - __field( u64, size ) - __field( int, bitmap ) - ), - - TP_fast_assign_btrfs(block_group->fs_info, - __entry->bg_objectid = block_group->key.objectid; - __entry->flags = block_group->flags; - __entry->start = cluster->window_start; - __entry->max_size = cluster->max_size; - __entry->size = size; - __entry->bitmap = bitmap; - ), - - TP_printk_btrfs("block_group = %Lu, flags = %Lu(%s), window_start = %Lu, " - "size = %Lu, max_size = %Lu, bitmap = %d", - __entry->bg_objectid, - __entry->flags, - __print_flags((unsigned long)__entry->flags, "|", - BTRFS_GROUP_FLAGS), __entry->start, - __entry->size, __entry->max_size, __entry->bitmap) -); - -struct extent_state; -TRACE_EVENT(alloc_extent_state, - - TP_PROTO(struct extent_state *state, gfp_t mask, unsigned long IP), - - TP_ARGS(state, mask, IP), - - TP_STRUCT__entry( - __field(struct extent_state *, state) - __field(gfp_t, mask) - __field(unsigned long, ip) - ), - - TP_fast_assign( - __entry->state = state, - __entry->mask = mask, - __entry->ip = IP - ), - - TP_printk("state=%p; mask = %s; caller = %pS", __entry->state, - show_gfp_flags(__entry->mask), (void *)__entry->ip) -); - -TRACE_EVENT(free_extent_state, - - TP_PROTO(struct extent_state *state, unsigned long IP), - - TP_ARGS(state, IP), - - TP_STRUCT__entry( - __field(struct extent_state *, state) - __field(unsigned long, ip) - ), - - TP_fast_assign( - __entry->state = state, - __entry->ip = IP - ), - - TP_printk(" state=%p; caller = %pS", __entry->state, - (void *)__entry->ip) -); - -DECLARE_EVENT_CLASS(btrfs__work, - - TP_PROTO(struct btrfs_work *work), - - TP_ARGS(work), - - TP_STRUCT__entry_btrfs( - __field( void *, work ) - __field( void *, wq ) - __field( void *, func ) - __field( void *, ordered_func ) - __field( void *, ordered_free ) - __field( void *, normal_work ) - ), - - TP_fast_assign_btrfs(btrfs_work_owner(work), - __entry->work = work; - __entry->wq = work->wq; - __entry->func = work->func; - __entry->ordered_func = work->ordered_func; - __entry->ordered_free = work->ordered_free; - __entry->normal_work = &work->normal_work; - ), - - TP_printk_btrfs("work=%p (normal_work=%p), wq=%p, func=%pf, ordered_func=%p," - " ordered_free=%p", - __entry->work, __entry->normal_work, __entry->wq, - __entry->func, __entry->ordered_func, __entry->ordered_free) -); - -/* For situiations that the work is freed */ -DECLARE_EVENT_CLASS(btrfs__work__done, - - TP_PROTO(struct btrfs_work *work), - - TP_ARGS(work), - - TP_STRUCT__entry_btrfs( - __field( void *, work ) - ), - - TP_fast_assign_btrfs(btrfs_work_owner(work), - __entry->work = work; - ), - - TP_printk_btrfs("work->%p", __entry->work) -); - -DEFINE_EVENT(btrfs__work, btrfs_work_queued, - - TP_PROTO(struct btrfs_work *work), - - TP_ARGS(work) -); - -DEFINE_EVENT(btrfs__work, btrfs_work_sched, - - TP_PROTO(struct btrfs_work *work), - - TP_ARGS(work) -); - -DEFINE_EVENT(btrfs__work__done, btrfs_all_work_done, - - TP_PROTO(struct btrfs_work *work), - - TP_ARGS(work) -); - -DEFINE_EVENT(btrfs__work, btrfs_ordered_sched, - - TP_PROTO(struct btrfs_work *work), - - TP_ARGS(work) -); - -DECLARE_EVENT_CLASS(btrfs__workqueue, - - TP_PROTO(struct __btrfs_workqueue *wq, const char *name, int high), - - TP_ARGS(wq, name, high), - - TP_STRUCT__entry_btrfs( - __field( void *, wq ) - __string( name, name ) - __field( int , high ) - ), - - TP_fast_assign_btrfs(btrfs_workqueue_owner(wq), - __entry->wq = wq; - __assign_str(name, name); - __entry->high = high; - ), - - TP_printk_btrfs("name=%s%s, wq=%p", __get_str(name), - __print_flags(__entry->high, "", - {(WQ_HIGHPRI), "-high"}), - __entry->wq) -); - -DEFINE_EVENT(btrfs__workqueue, btrfs_workqueue_alloc, - - TP_PROTO(struct __btrfs_workqueue *wq, const char *name, int high), - - TP_ARGS(wq, name, high) -); - -DECLARE_EVENT_CLASS(btrfs__workqueue_done, - - TP_PROTO(struct __btrfs_workqueue *wq), - - TP_ARGS(wq), - - TP_STRUCT__entry_btrfs( - __field( void *, wq ) - ), - - TP_fast_assign_btrfs(btrfs_workqueue_owner(wq), - __entry->wq = wq; - ), - - TP_printk_btrfs("wq=%p", __entry->wq) -); - -DEFINE_EVENT(btrfs__workqueue_done, btrfs_workqueue_destroy, - - TP_PROTO(struct __btrfs_workqueue *wq), - - TP_ARGS(wq) -); - -DECLARE_EVENT_CLASS(btrfs__qgroup_data_map, - - TP_PROTO(struct inode *inode, u64 free_reserved), - - TP_ARGS(inode, free_reserved), - - TP_STRUCT__entry_btrfs( - __field( u64, rootid ) - __field( unsigned long, ino ) - __field( u64, free_reserved ) - ), - - TP_fast_assign_btrfs(btrfs_sb(inode->i_sb), - __entry->rootid = BTRFS_I(inode)->root->objectid; - __entry->ino = inode->i_ino; - __entry->free_reserved = free_reserved; - ), - - TP_printk_btrfs("rootid=%llu, ino=%lu, free_reserved=%llu", - __entry->rootid, __entry->ino, __entry->free_reserved) -); - -DEFINE_EVENT(btrfs__qgroup_data_map, btrfs_qgroup_init_data_rsv_map, - - TP_PROTO(struct inode *inode, u64 free_reserved), - - TP_ARGS(inode, free_reserved) -); - -DEFINE_EVENT(btrfs__qgroup_data_map, btrfs_qgroup_free_data_rsv_map, - - TP_PROTO(struct inode *inode, u64 free_reserved), - - TP_ARGS(inode, free_reserved) -); - -#define BTRFS_QGROUP_OPERATIONS \ - { QGROUP_RESERVE, "reserve" }, \ - { QGROUP_RELEASE, "release" }, \ - { QGROUP_FREE, "free" } - -DECLARE_EVENT_CLASS(btrfs__qgroup_rsv_data, - - TP_PROTO(struct inode *inode, u64 start, u64 len, u64 reserved, int op), - - TP_ARGS(inode, start, len, reserved, op), - - TP_STRUCT__entry_btrfs( - __field( u64, rootid ) - __field( unsigned long, ino ) - __field( u64, start ) - __field( u64, len ) - __field( u64, reserved ) - __field( int, op ) - ), - - TP_fast_assign_btrfs(btrfs_sb(inode->i_sb), - __entry->rootid = BTRFS_I(inode)->root->objectid; - __entry->ino = inode->i_ino; - __entry->start = start; - __entry->len = len; - __entry->reserved = reserved; - __entry->op = op; - ), - - TP_printk_btrfs("root=%llu, ino=%lu, start=%llu, len=%llu, reserved=%llu, op=%s", - __entry->rootid, __entry->ino, __entry->start, __entry->len, - __entry->reserved, - __print_flags((unsigned long)__entry->op, "", - BTRFS_QGROUP_OPERATIONS) - ) -); - -DEFINE_EVENT(btrfs__qgroup_rsv_data, btrfs_qgroup_reserve_data, - - TP_PROTO(struct inode *inode, u64 start, u64 len, u64 reserved, int op), - - TP_ARGS(inode, start, len, reserved, op) -); - -DEFINE_EVENT(btrfs__qgroup_rsv_data, btrfs_qgroup_release_data, - - TP_PROTO(struct inode *inode, u64 start, u64 len, u64 reserved, int op), - - TP_ARGS(inode, start, len, reserved, op) -); - -DECLARE_EVENT_CLASS(btrfs__qgroup_delayed_ref, - - TP_PROTO(struct btrfs_fs_info *fs_info, u64 ref_root, u64 reserved), - - TP_ARGS(fs_info, ref_root, reserved), - - TP_STRUCT__entry_btrfs( - __field( u64, ref_root ) - __field( u64, reserved ) - ), - - TP_fast_assign_btrfs(fs_info, - __entry->ref_root = ref_root; - __entry->reserved = reserved; - ), - - TP_printk_btrfs("root=%llu, reserved=%llu, op=free", - __entry->ref_root, __entry->reserved) -); - -DEFINE_EVENT(btrfs__qgroup_delayed_ref, btrfs_qgroup_free_delayed_ref, - - TP_PROTO(struct btrfs_fs_info *fs_info, u64 ref_root, u64 reserved), - - TP_ARGS(fs_info, ref_root, reserved) -); - -DECLARE_EVENT_CLASS(btrfs_qgroup_extent, - TP_PROTO(struct btrfs_fs_info *fs_info, - struct btrfs_qgroup_extent_record *rec), - - TP_ARGS(fs_info, rec), - - TP_STRUCT__entry_btrfs( - __field( u64, bytenr ) - __field( u64, num_bytes ) - ), - - TP_fast_assign_btrfs(fs_info, - __entry->bytenr = rec->bytenr, - __entry->num_bytes = rec->num_bytes; - ), - - TP_printk_btrfs("bytenr = %llu, num_bytes = %llu", - (unsigned long long)__entry->bytenr, - (unsigned long long)__entry->num_bytes) -); - -DEFINE_EVENT(btrfs_qgroup_extent, btrfs_qgroup_account_extents, - - TP_PROTO(struct btrfs_fs_info *fs_info, - struct btrfs_qgroup_extent_record *rec), - - TP_ARGS(fs_info, rec) -); - -DEFINE_EVENT(btrfs_qgroup_extent, btrfs_qgroup_insert_dirty_extent, - - TP_PROTO(struct btrfs_fs_info *fs_info, - struct btrfs_qgroup_extent_record *rec), - - TP_ARGS(fs_info, rec) -); - -TRACE_EVENT(btrfs_qgroup_account_extent, - - TP_PROTO(struct btrfs_fs_info *fs_info, u64 bytenr, - u64 num_bytes, u64 nr_old_roots, u64 nr_new_roots), - - TP_ARGS(fs_info, bytenr, num_bytes, nr_old_roots, nr_new_roots), - - TP_STRUCT__entry_btrfs( - __field( u64, bytenr ) - __field( u64, num_bytes ) - __field( u64, nr_old_roots ) - __field( u64, nr_new_roots ) - ), - - TP_fast_assign_btrfs(fs_info, - __entry->bytenr = bytenr; - __entry->num_bytes = num_bytes; - __entry->nr_old_roots = nr_old_roots; - __entry->nr_new_roots = nr_new_roots; - ), - - TP_printk_btrfs("bytenr = %llu, num_bytes = %llu, nr_old_roots = %llu, " - "nr_new_roots = %llu", - __entry->bytenr, - __entry->num_bytes, - __entry->nr_old_roots, - __entry->nr_new_roots) -); - -TRACE_EVENT(qgroup_update_counters, - - TP_PROTO(struct btrfs_fs_info *fs_info, u64 qgid, - u64 cur_old_count, u64 cur_new_count), - - TP_ARGS(fs_info, qgid, cur_old_count, cur_new_count), - - TP_STRUCT__entry_btrfs( - __field( u64, qgid ) - __field( u64, cur_old_count ) - __field( u64, cur_new_count ) - ), - - TP_fast_assign_btrfs(fs_info, - __entry->qgid = qgid; - __entry->cur_old_count = cur_old_count; - __entry->cur_new_count = cur_new_count; - ), - - TP_printk_btrfs("qgid = %llu, cur_old_count = %llu, cur_new_count = %llu", - __entry->qgid, - __entry->cur_old_count, - __entry->cur_new_count) -); - -#endif /* _TRACE_BTRFS_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/cpuhp.h b/src/linux/include/trace/events/cpuhp.h deleted file mode 100644 index 996953d..0000000 --- a/src/linux/include/trace/events/cpuhp.h +++ /dev/null @@ -1,94 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM cpuhp - -#if !defined(_TRACE_CPUHP_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_CPUHP_H - -#include - -TRACE_EVENT(cpuhp_enter, - - TP_PROTO(unsigned int cpu, - int target, - int idx, - int (*fun)(unsigned int)), - - TP_ARGS(cpu, target, idx, fun), - - TP_STRUCT__entry( - __field( unsigned int, cpu ) - __field( int, target ) - __field( int, idx ) - __field( void *, fun ) - ), - - TP_fast_assign( - __entry->cpu = cpu; - __entry->target = target; - __entry->idx = idx; - __entry->fun = fun; - ), - - TP_printk("cpu: %04u target: %3d step: %3d (%pf)", - __entry->cpu, __entry->target, __entry->idx, __entry->fun) -); - -TRACE_EVENT(cpuhp_multi_enter, - - TP_PROTO(unsigned int cpu, - int target, - int idx, - int (*fun)(unsigned int, struct hlist_node *), - struct hlist_node *node), - - TP_ARGS(cpu, target, idx, fun, node), - - TP_STRUCT__entry( - __field( unsigned int, cpu ) - __field( int, target ) - __field( int, idx ) - __field( void *, fun ) - ), - - TP_fast_assign( - __entry->cpu = cpu; - __entry->target = target; - __entry->idx = idx; - __entry->fun = fun; - ), - - TP_printk("cpu: %04u target: %3d step: %3d (%pf)", - __entry->cpu, __entry->target, __entry->idx, __entry->fun) -); - -TRACE_EVENT(cpuhp_exit, - - TP_PROTO(unsigned int cpu, - int state, - int idx, - int ret), - - TP_ARGS(cpu, state, idx, ret), - - TP_STRUCT__entry( - __field( unsigned int, cpu ) - __field( int, state ) - __field( int, idx ) - __field( int, ret ) - ), - - TP_fast_assign( - __entry->cpu = cpu; - __entry->state = state; - __entry->idx = idx; - __entry->ret = ret; - ), - - TP_printk(" cpu: %04u state: %3d step: %3d ret: %d", - __entry->cpu, __entry->state, __entry->idx, __entry->ret) -); - -#endif - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/ext4.h b/src/linux/include/trace/events/ext4.h deleted file mode 100644 index 09c71e9..0000000 --- a/src/linux/include/trace/events/ext4.h +++ /dev/null @@ -1,2535 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM ext4 - -#if !defined(_TRACE_EXT4_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_EXT4_H - -#include -#include - -struct ext4_allocation_context; -struct ext4_allocation_request; -struct ext4_extent; -struct ext4_prealloc_space; -struct ext4_inode_info; -struct mpage_da_data; -struct ext4_map_blocks; -struct extent_status; - -#define EXT4_I(inode) (container_of(inode, struct ext4_inode_info, vfs_inode)) - -#define show_mballoc_flags(flags) __print_flags(flags, "|", \ - { EXT4_MB_HINT_MERGE, "HINT_MERGE" }, \ - { EXT4_MB_HINT_RESERVED, "HINT_RESV" }, \ - { EXT4_MB_HINT_METADATA, "HINT_MDATA" }, \ - { EXT4_MB_HINT_FIRST, "HINT_FIRST" }, \ - { EXT4_MB_HINT_BEST, "HINT_BEST" }, \ - { EXT4_MB_HINT_DATA, "HINT_DATA" }, \ - { EXT4_MB_HINT_NOPREALLOC, "HINT_NOPREALLOC" }, \ - { EXT4_MB_HINT_GROUP_ALLOC, "HINT_GRP_ALLOC" }, \ - { EXT4_MB_HINT_GOAL_ONLY, "HINT_GOAL_ONLY" }, \ - { EXT4_MB_HINT_TRY_GOAL, "HINT_TRY_GOAL" }, \ - { EXT4_MB_DELALLOC_RESERVED, "DELALLOC_RESV" }, \ - { EXT4_MB_STREAM_ALLOC, "STREAM_ALLOC" }, \ - { EXT4_MB_USE_ROOT_BLOCKS, "USE_ROOT_BLKS" }, \ - { EXT4_MB_USE_RESERVED, "USE_RESV" }) - -#define show_map_flags(flags) __print_flags(flags, "|", \ - { EXT4_GET_BLOCKS_CREATE, "CREATE" }, \ - { EXT4_GET_BLOCKS_UNWRIT_EXT, "UNWRIT" }, \ - { EXT4_GET_BLOCKS_DELALLOC_RESERVE, "DELALLOC" }, \ - { EXT4_GET_BLOCKS_PRE_IO, "PRE_IO" }, \ - { EXT4_GET_BLOCKS_CONVERT, "CONVERT" }, \ - { EXT4_GET_BLOCKS_METADATA_NOFAIL, "METADATA_NOFAIL" }, \ - { EXT4_GET_BLOCKS_NO_NORMALIZE, "NO_NORMALIZE" }, \ - { EXT4_GET_BLOCKS_KEEP_SIZE, "KEEP_SIZE" }, \ - { EXT4_GET_BLOCKS_ZERO, "ZERO" }) - -#define show_mflags(flags) __print_flags(flags, "", \ - { EXT4_MAP_NEW, "N" }, \ - { EXT4_MAP_MAPPED, "M" }, \ - { EXT4_MAP_UNWRITTEN, "U" }, \ - { EXT4_MAP_BOUNDARY, "B" }) - -#define show_free_flags(flags) __print_flags(flags, "|", \ - { EXT4_FREE_BLOCKS_METADATA, "METADATA" }, \ - { EXT4_FREE_BLOCKS_FORGET, "FORGET" }, \ - { EXT4_FREE_BLOCKS_VALIDATED, "VALIDATED" }, \ - { EXT4_FREE_BLOCKS_NO_QUOT_UPDATE, "NO_QUOTA" }, \ - { EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER,"1ST_CLUSTER" },\ - { EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER, "LAST_CLUSTER" }) - -#define show_extent_status(status) __print_flags(status, "", \ - { EXTENT_STATUS_WRITTEN, "W" }, \ - { EXTENT_STATUS_UNWRITTEN, "U" }, \ - { EXTENT_STATUS_DELAYED, "D" }, \ - { EXTENT_STATUS_HOLE, "H" }) - -#define show_falloc_mode(mode) __print_flags(mode, "|", \ - { FALLOC_FL_KEEP_SIZE, "KEEP_SIZE"}, \ - { FALLOC_FL_PUNCH_HOLE, "PUNCH_HOLE"}, \ - { FALLOC_FL_NO_HIDE_STALE, "NO_HIDE_STALE"}, \ - { FALLOC_FL_COLLAPSE_RANGE, "COLLAPSE_RANGE"}, \ - { FALLOC_FL_ZERO_RANGE, "ZERO_RANGE"}) - - -TRACE_EVENT(ext4_other_inode_update_time, - TP_PROTO(struct inode *inode, ino_t orig_ino), - - TP_ARGS(inode, orig_ino), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ino_t, orig_ino ) - __field( uid_t, uid ) - __field( gid_t, gid ) - __field( __u16, mode ) - ), - - TP_fast_assign( - __entry->orig_ino = orig_ino; - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->uid = i_uid_read(inode); - __entry->gid = i_gid_read(inode); - __entry->mode = inode->i_mode; - ), - - TP_printk("dev %d,%d orig_ino %lu ino %lu mode 0%o uid %u gid %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->orig_ino, - (unsigned long) __entry->ino, __entry->mode, - __entry->uid, __entry->gid) -); - -TRACE_EVENT(ext4_free_inode, - TP_PROTO(struct inode *inode), - - TP_ARGS(inode), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( uid_t, uid ) - __field( gid_t, gid ) - __field( __u64, blocks ) - __field( __u16, mode ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->uid = i_uid_read(inode); - __entry->gid = i_gid_read(inode); - __entry->blocks = inode->i_blocks; - __entry->mode = inode->i_mode; - ), - - TP_printk("dev %d,%d ino %lu mode 0%o uid %u gid %u blocks %llu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, __entry->mode, - __entry->uid, __entry->gid, __entry->blocks) -); - -TRACE_EVENT(ext4_request_inode, - TP_PROTO(struct inode *dir, int mode), - - TP_ARGS(dir, mode), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, dir ) - __field( __u16, mode ) - ), - - TP_fast_assign( - __entry->dev = dir->i_sb->s_dev; - __entry->dir = dir->i_ino; - __entry->mode = mode; - ), - - TP_printk("dev %d,%d dir %lu mode 0%o", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->dir, __entry->mode) -); - -TRACE_EVENT(ext4_allocate_inode, - TP_PROTO(struct inode *inode, struct inode *dir, int mode), - - TP_ARGS(inode, dir, mode), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ino_t, dir ) - __field( __u16, mode ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->dir = dir->i_ino; - __entry->mode = mode; - ), - - TP_printk("dev %d,%d ino %lu dir %lu mode 0%o", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned long) __entry->dir, __entry->mode) -); - -TRACE_EVENT(ext4_evict_inode, - TP_PROTO(struct inode *inode), - - TP_ARGS(inode), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( int, nlink ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->nlink = inode->i_nlink; - ), - - TP_printk("dev %d,%d ino %lu nlink %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, __entry->nlink) -); - -TRACE_EVENT(ext4_drop_inode, - TP_PROTO(struct inode *inode, int drop), - - TP_ARGS(inode, drop), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( int, drop ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->drop = drop; - ), - - TP_printk("dev %d,%d ino %lu drop %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, __entry->drop) -); - -TRACE_EVENT(ext4_mark_inode_dirty, - TP_PROTO(struct inode *inode, unsigned long IP), - - TP_ARGS(inode, IP), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field(unsigned long, ip ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->ip = IP; - ), - - TP_printk("dev %d,%d ino %lu caller %pS", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, (void *)__entry->ip) -); - -TRACE_EVENT(ext4_begin_ordered_truncate, - TP_PROTO(struct inode *inode, loff_t new_size), - - TP_ARGS(inode, new_size), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( loff_t, new_size ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->new_size = new_size; - ), - - TP_printk("dev %d,%d ino %lu new_size %lld", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->new_size) -); - -DECLARE_EVENT_CLASS(ext4__write_begin, - - TP_PROTO(struct inode *inode, loff_t pos, unsigned int len, - unsigned int flags), - - TP_ARGS(inode, pos, len, flags), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( loff_t, pos ) - __field( unsigned int, len ) - __field( unsigned int, flags ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->pos = pos; - __entry->len = len; - __entry->flags = flags; - ), - - TP_printk("dev %d,%d ino %lu pos %lld len %u flags %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->pos, __entry->len, __entry->flags) -); - -DEFINE_EVENT(ext4__write_begin, ext4_write_begin, - - TP_PROTO(struct inode *inode, loff_t pos, unsigned int len, - unsigned int flags), - - TP_ARGS(inode, pos, len, flags) -); - -DEFINE_EVENT(ext4__write_begin, ext4_da_write_begin, - - TP_PROTO(struct inode *inode, loff_t pos, unsigned int len, - unsigned int flags), - - TP_ARGS(inode, pos, len, flags) -); - -DECLARE_EVENT_CLASS(ext4__write_end, - TP_PROTO(struct inode *inode, loff_t pos, unsigned int len, - unsigned int copied), - - TP_ARGS(inode, pos, len, copied), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( loff_t, pos ) - __field( unsigned int, len ) - __field( unsigned int, copied ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->pos = pos; - __entry->len = len; - __entry->copied = copied; - ), - - TP_printk("dev %d,%d ino %lu pos %lld len %u copied %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->pos, __entry->len, __entry->copied) -); - -DEFINE_EVENT(ext4__write_end, ext4_write_end, - - TP_PROTO(struct inode *inode, loff_t pos, unsigned int len, - unsigned int copied), - - TP_ARGS(inode, pos, len, copied) -); - -DEFINE_EVENT(ext4__write_end, ext4_journalled_write_end, - - TP_PROTO(struct inode *inode, loff_t pos, unsigned int len, - unsigned int copied), - - TP_ARGS(inode, pos, len, copied) -); - -DEFINE_EVENT(ext4__write_end, ext4_da_write_end, - - TP_PROTO(struct inode *inode, loff_t pos, unsigned int len, - unsigned int copied), - - TP_ARGS(inode, pos, len, copied) -); - -TRACE_EVENT(ext4_writepages, - TP_PROTO(struct inode *inode, struct writeback_control *wbc), - - TP_ARGS(inode, wbc), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( long, nr_to_write ) - __field( long, pages_skipped ) - __field( loff_t, range_start ) - __field( loff_t, range_end ) - __field( pgoff_t, writeback_index ) - __field( int, sync_mode ) - __field( char, for_kupdate ) - __field( char, range_cyclic ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->nr_to_write = wbc->nr_to_write; - __entry->pages_skipped = wbc->pages_skipped; - __entry->range_start = wbc->range_start; - __entry->range_end = wbc->range_end; - __entry->writeback_index = inode->i_mapping->writeback_index; - __entry->sync_mode = wbc->sync_mode; - __entry->for_kupdate = wbc->for_kupdate; - __entry->range_cyclic = wbc->range_cyclic; - ), - - TP_printk("dev %d,%d ino %lu nr_to_write %ld pages_skipped %ld " - "range_start %lld range_end %lld sync_mode %d " - "for_kupdate %d range_cyclic %d writeback_index %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, __entry->nr_to_write, - __entry->pages_skipped, __entry->range_start, - __entry->range_end, __entry->sync_mode, - __entry->for_kupdate, __entry->range_cyclic, - (unsigned long) __entry->writeback_index) -); - -TRACE_EVENT(ext4_da_write_pages, - TP_PROTO(struct inode *inode, pgoff_t first_page, - struct writeback_control *wbc), - - TP_ARGS(inode, first_page, wbc), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( pgoff_t, first_page ) - __field( long, nr_to_write ) - __field( int, sync_mode ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->first_page = first_page; - __entry->nr_to_write = wbc->nr_to_write; - __entry->sync_mode = wbc->sync_mode; - ), - - TP_printk("dev %d,%d ino %lu first_page %lu nr_to_write %ld " - "sync_mode %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, __entry->first_page, - __entry->nr_to_write, __entry->sync_mode) -); - -TRACE_EVENT(ext4_da_write_pages_extent, - TP_PROTO(struct inode *inode, struct ext4_map_blocks *map), - - TP_ARGS(inode, map), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( __u64, lblk ) - __field( __u32, len ) - __field( __u32, flags ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->lblk = map->m_lblk; - __entry->len = map->m_len; - __entry->flags = map->m_flags; - ), - - TP_printk("dev %d,%d ino %lu lblk %llu len %u flags %s", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, __entry->lblk, __entry->len, - show_mflags(__entry->flags)) -); - -TRACE_EVENT(ext4_writepages_result, - TP_PROTO(struct inode *inode, struct writeback_control *wbc, - int ret, int pages_written), - - TP_ARGS(inode, wbc, ret, pages_written), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( int, ret ) - __field( int, pages_written ) - __field( long, pages_skipped ) - __field( pgoff_t, writeback_index ) - __field( int, sync_mode ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->ret = ret; - __entry->pages_written = pages_written; - __entry->pages_skipped = wbc->pages_skipped; - __entry->writeback_index = inode->i_mapping->writeback_index; - __entry->sync_mode = wbc->sync_mode; - ), - - TP_printk("dev %d,%d ino %lu ret %d pages_written %d pages_skipped %ld " - "sync_mode %d writeback_index %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, __entry->ret, - __entry->pages_written, __entry->pages_skipped, - __entry->sync_mode, - (unsigned long) __entry->writeback_index) -); - -DECLARE_EVENT_CLASS(ext4__page_op, - TP_PROTO(struct page *page), - - TP_ARGS(page), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( pgoff_t, index ) - - ), - - TP_fast_assign( - __entry->dev = page->mapping->host->i_sb->s_dev; - __entry->ino = page->mapping->host->i_ino; - __entry->index = page->index; - ), - - TP_printk("dev %d,%d ino %lu page_index %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned long) __entry->index) -); - -DEFINE_EVENT(ext4__page_op, ext4_writepage, - - TP_PROTO(struct page *page), - - TP_ARGS(page) -); - -DEFINE_EVENT(ext4__page_op, ext4_readpage, - - TP_PROTO(struct page *page), - - TP_ARGS(page) -); - -DEFINE_EVENT(ext4__page_op, ext4_releasepage, - - TP_PROTO(struct page *page), - - TP_ARGS(page) -); - -DECLARE_EVENT_CLASS(ext4_invalidatepage_op, - TP_PROTO(struct page *page, unsigned int offset, unsigned int length), - - TP_ARGS(page, offset, length), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( pgoff_t, index ) - __field( unsigned int, offset ) - __field( unsigned int, length ) - ), - - TP_fast_assign( - __entry->dev = page->mapping->host->i_sb->s_dev; - __entry->ino = page->mapping->host->i_ino; - __entry->index = page->index; - __entry->offset = offset; - __entry->length = length; - ), - - TP_printk("dev %d,%d ino %lu page_index %lu offset %u length %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned long) __entry->index, - __entry->offset, __entry->length) -); - -DEFINE_EVENT(ext4_invalidatepage_op, ext4_invalidatepage, - TP_PROTO(struct page *page, unsigned int offset, unsigned int length), - - TP_ARGS(page, offset, length) -); - -DEFINE_EVENT(ext4_invalidatepage_op, ext4_journalled_invalidatepage, - TP_PROTO(struct page *page, unsigned int offset, unsigned int length), - - TP_ARGS(page, offset, length) -); - -TRACE_EVENT(ext4_discard_blocks, - TP_PROTO(struct super_block *sb, unsigned long long blk, - unsigned long long count), - - TP_ARGS(sb, blk, count), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( __u64, blk ) - __field( __u64, count ) - - ), - - TP_fast_assign( - __entry->dev = sb->s_dev; - __entry->blk = blk; - __entry->count = count; - ), - - TP_printk("dev %d,%d blk %llu count %llu", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->blk, __entry->count) -); - -DECLARE_EVENT_CLASS(ext4__mb_new_pa, - TP_PROTO(struct ext4_allocation_context *ac, - struct ext4_prealloc_space *pa), - - TP_ARGS(ac, pa), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( __u64, pa_pstart ) - __field( __u64, pa_lstart ) - __field( __u32, pa_len ) - - ), - - TP_fast_assign( - __entry->dev = ac->ac_sb->s_dev; - __entry->ino = ac->ac_inode->i_ino; - __entry->pa_pstart = pa->pa_pstart; - __entry->pa_lstart = pa->pa_lstart; - __entry->pa_len = pa->pa_len; - ), - - TP_printk("dev %d,%d ino %lu pstart %llu len %u lstart %llu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->pa_pstart, __entry->pa_len, __entry->pa_lstart) -); - -DEFINE_EVENT(ext4__mb_new_pa, ext4_mb_new_inode_pa, - - TP_PROTO(struct ext4_allocation_context *ac, - struct ext4_prealloc_space *pa), - - TP_ARGS(ac, pa) -); - -DEFINE_EVENT(ext4__mb_new_pa, ext4_mb_new_group_pa, - - TP_PROTO(struct ext4_allocation_context *ac, - struct ext4_prealloc_space *pa), - - TP_ARGS(ac, pa) -); - -TRACE_EVENT(ext4_mb_release_inode_pa, - TP_PROTO(struct ext4_prealloc_space *pa, - unsigned long long block, unsigned int count), - - TP_ARGS(pa, block, count), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( __u64, block ) - __field( __u32, count ) - - ), - - TP_fast_assign( - __entry->dev = pa->pa_inode->i_sb->s_dev; - __entry->ino = pa->pa_inode->i_ino; - __entry->block = block; - __entry->count = count; - ), - - TP_printk("dev %d,%d ino %lu block %llu count %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->block, __entry->count) -); - -TRACE_EVENT(ext4_mb_release_group_pa, - TP_PROTO(struct super_block *sb, struct ext4_prealloc_space *pa), - - TP_ARGS(sb, pa), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( __u64, pa_pstart ) - __field( __u32, pa_len ) - - ), - - TP_fast_assign( - __entry->dev = sb->s_dev; - __entry->pa_pstart = pa->pa_pstart; - __entry->pa_len = pa->pa_len; - ), - - TP_printk("dev %d,%d pstart %llu len %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->pa_pstart, __entry->pa_len) -); - -TRACE_EVENT(ext4_discard_preallocations, - TP_PROTO(struct inode *inode), - - TP_ARGS(inode), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - ), - - TP_printk("dev %d,%d ino %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino) -); - -TRACE_EVENT(ext4_mb_discard_preallocations, - TP_PROTO(struct super_block *sb, int needed), - - TP_ARGS(sb, needed), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( int, needed ) - - ), - - TP_fast_assign( - __entry->dev = sb->s_dev; - __entry->needed = needed; - ), - - TP_printk("dev %d,%d needed %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->needed) -); - -TRACE_EVENT(ext4_request_blocks, - TP_PROTO(struct ext4_allocation_request *ar), - - TP_ARGS(ar), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( unsigned int, len ) - __field( __u32, logical ) - __field( __u32, lleft ) - __field( __u32, lright ) - __field( __u64, goal ) - __field( __u64, pleft ) - __field( __u64, pright ) - __field( unsigned int, flags ) - ), - - TP_fast_assign( - __entry->dev = ar->inode->i_sb->s_dev; - __entry->ino = ar->inode->i_ino; - __entry->len = ar->len; - __entry->logical = ar->logical; - __entry->goal = ar->goal; - __entry->lleft = ar->lleft; - __entry->lright = ar->lright; - __entry->pleft = ar->pleft; - __entry->pright = ar->pright; - __entry->flags = ar->flags; - ), - - TP_printk("dev %d,%d ino %lu flags %s len %u lblk %u goal %llu " - "lleft %u lright %u pleft %llu pright %llu ", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, show_mballoc_flags(__entry->flags), - __entry->len, __entry->logical, __entry->goal, - __entry->lleft, __entry->lright, __entry->pleft, - __entry->pright) -); - -TRACE_EVENT(ext4_allocate_blocks, - TP_PROTO(struct ext4_allocation_request *ar, unsigned long long block), - - TP_ARGS(ar, block), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( __u64, block ) - __field( unsigned int, len ) - __field( __u32, logical ) - __field( __u32, lleft ) - __field( __u32, lright ) - __field( __u64, goal ) - __field( __u64, pleft ) - __field( __u64, pright ) - __field( unsigned int, flags ) - ), - - TP_fast_assign( - __entry->dev = ar->inode->i_sb->s_dev; - __entry->ino = ar->inode->i_ino; - __entry->block = block; - __entry->len = ar->len; - __entry->logical = ar->logical; - __entry->goal = ar->goal; - __entry->lleft = ar->lleft; - __entry->lright = ar->lright; - __entry->pleft = ar->pleft; - __entry->pright = ar->pright; - __entry->flags = ar->flags; - ), - - TP_printk("dev %d,%d ino %lu flags %s len %u block %llu lblk %u " - "goal %llu lleft %u lright %u pleft %llu pright %llu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, show_mballoc_flags(__entry->flags), - __entry->len, __entry->block, __entry->logical, - __entry->goal, __entry->lleft, __entry->lright, - __entry->pleft, __entry->pright) -); - -TRACE_EVENT(ext4_free_blocks, - TP_PROTO(struct inode *inode, __u64 block, unsigned long count, - int flags), - - TP_ARGS(inode, block, count, flags), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( __u64, block ) - __field( unsigned long, count ) - __field( int, flags ) - __field( __u16, mode ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->block = block; - __entry->count = count; - __entry->flags = flags; - __entry->mode = inode->i_mode; - ), - - TP_printk("dev %d,%d ino %lu mode 0%o block %llu count %lu flags %s", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->mode, __entry->block, __entry->count, - show_free_flags(__entry->flags)) -); - -TRACE_EVENT(ext4_sync_file_enter, - TP_PROTO(struct file *file, int datasync), - - TP_ARGS(file, datasync), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ino_t, parent ) - __field( int, datasync ) - ), - - TP_fast_assign( - struct dentry *dentry = file->f_path.dentry; - - __entry->dev = dentry->d_sb->s_dev; - __entry->ino = d_inode(dentry)->i_ino; - __entry->datasync = datasync; - __entry->parent = d_inode(dentry->d_parent)->i_ino; - ), - - TP_printk("dev %d,%d ino %lu parent %lu datasync %d ", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned long) __entry->parent, __entry->datasync) -); - -TRACE_EVENT(ext4_sync_file_exit, - TP_PROTO(struct inode *inode, int ret), - - TP_ARGS(inode, ret), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( int, ret ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->ret = ret; - ), - - TP_printk("dev %d,%d ino %lu ret %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->ret) -); - -TRACE_EVENT(ext4_sync_fs, - TP_PROTO(struct super_block *sb, int wait), - - TP_ARGS(sb, wait), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( int, wait ) - - ), - - TP_fast_assign( - __entry->dev = sb->s_dev; - __entry->wait = wait; - ), - - TP_printk("dev %d,%d wait %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->wait) -); - -TRACE_EVENT(ext4_alloc_da_blocks, - TP_PROTO(struct inode *inode), - - TP_ARGS(inode), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( unsigned int, data_blocks ) - __field( unsigned int, meta_blocks ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->data_blocks = EXT4_I(inode)->i_reserved_data_blocks; - __entry->meta_blocks = EXT4_I(inode)->i_reserved_meta_blocks; - ), - - TP_printk("dev %d,%d ino %lu data_blocks %u meta_blocks %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->data_blocks, __entry->meta_blocks) -); - -TRACE_EVENT(ext4_mballoc_alloc, - TP_PROTO(struct ext4_allocation_context *ac), - - TP_ARGS(ac), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( __u32, orig_logical ) - __field( int, orig_start ) - __field( __u32, orig_group ) - __field( int, orig_len ) - __field( __u32, goal_logical ) - __field( int, goal_start ) - __field( __u32, goal_group ) - __field( int, goal_len ) - __field( __u32, result_logical ) - __field( int, result_start ) - __field( __u32, result_group ) - __field( int, result_len ) - __field( __u16, found ) - __field( __u16, groups ) - __field( __u16, buddy ) - __field( __u16, flags ) - __field( __u16, tail ) - __field( __u8, cr ) - ), - - TP_fast_assign( - __entry->dev = ac->ac_inode->i_sb->s_dev; - __entry->ino = ac->ac_inode->i_ino; - __entry->orig_logical = ac->ac_o_ex.fe_logical; - __entry->orig_start = ac->ac_o_ex.fe_start; - __entry->orig_group = ac->ac_o_ex.fe_group; - __entry->orig_len = ac->ac_o_ex.fe_len; - __entry->goal_logical = ac->ac_g_ex.fe_logical; - __entry->goal_start = ac->ac_g_ex.fe_start; - __entry->goal_group = ac->ac_g_ex.fe_group; - __entry->goal_len = ac->ac_g_ex.fe_len; - __entry->result_logical = ac->ac_f_ex.fe_logical; - __entry->result_start = ac->ac_f_ex.fe_start; - __entry->result_group = ac->ac_f_ex.fe_group; - __entry->result_len = ac->ac_f_ex.fe_len; - __entry->found = ac->ac_found; - __entry->flags = ac->ac_flags; - __entry->groups = ac->ac_groups_scanned; - __entry->buddy = ac->ac_buddy; - __entry->tail = ac->ac_tail; - __entry->cr = ac->ac_criteria; - ), - - TP_printk("dev %d,%d inode %lu orig %u/%d/%u@%u goal %u/%d/%u@%u " - "result %u/%d/%u@%u blks %u grps %u cr %u flags %s " - "tail %u broken %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->orig_group, __entry->orig_start, - __entry->orig_len, __entry->orig_logical, - __entry->goal_group, __entry->goal_start, - __entry->goal_len, __entry->goal_logical, - __entry->result_group, __entry->result_start, - __entry->result_len, __entry->result_logical, - __entry->found, __entry->groups, __entry->cr, - show_mballoc_flags(__entry->flags), __entry->tail, - __entry->buddy ? 1 << __entry->buddy : 0) -); - -TRACE_EVENT(ext4_mballoc_prealloc, - TP_PROTO(struct ext4_allocation_context *ac), - - TP_ARGS(ac), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( __u32, orig_logical ) - __field( int, orig_start ) - __field( __u32, orig_group ) - __field( int, orig_len ) - __field( __u32, result_logical ) - __field( int, result_start ) - __field( __u32, result_group ) - __field( int, result_len ) - ), - - TP_fast_assign( - __entry->dev = ac->ac_inode->i_sb->s_dev; - __entry->ino = ac->ac_inode->i_ino; - __entry->orig_logical = ac->ac_o_ex.fe_logical; - __entry->orig_start = ac->ac_o_ex.fe_start; - __entry->orig_group = ac->ac_o_ex.fe_group; - __entry->orig_len = ac->ac_o_ex.fe_len; - __entry->result_logical = ac->ac_b_ex.fe_logical; - __entry->result_start = ac->ac_b_ex.fe_start; - __entry->result_group = ac->ac_b_ex.fe_group; - __entry->result_len = ac->ac_b_ex.fe_len; - ), - - TP_printk("dev %d,%d inode %lu orig %u/%d/%u@%u result %u/%d/%u@%u", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->orig_group, __entry->orig_start, - __entry->orig_len, __entry->orig_logical, - __entry->result_group, __entry->result_start, - __entry->result_len, __entry->result_logical) -); - -DECLARE_EVENT_CLASS(ext4__mballoc, - TP_PROTO(struct super_block *sb, - struct inode *inode, - ext4_group_t group, - ext4_grpblk_t start, - ext4_grpblk_t len), - - TP_ARGS(sb, inode, group, start, len), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( int, result_start ) - __field( __u32, result_group ) - __field( int, result_len ) - ), - - TP_fast_assign( - __entry->dev = sb->s_dev; - __entry->ino = inode ? inode->i_ino : 0; - __entry->result_start = start; - __entry->result_group = group; - __entry->result_len = len; - ), - - TP_printk("dev %d,%d inode %lu extent %u/%d/%d ", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->result_group, __entry->result_start, - __entry->result_len) -); - -DEFINE_EVENT(ext4__mballoc, ext4_mballoc_discard, - - TP_PROTO(struct super_block *sb, - struct inode *inode, - ext4_group_t group, - ext4_grpblk_t start, - ext4_grpblk_t len), - - TP_ARGS(sb, inode, group, start, len) -); - -DEFINE_EVENT(ext4__mballoc, ext4_mballoc_free, - - TP_PROTO(struct super_block *sb, - struct inode *inode, - ext4_group_t group, - ext4_grpblk_t start, - ext4_grpblk_t len), - - TP_ARGS(sb, inode, group, start, len) -); - -TRACE_EVENT(ext4_forget, - TP_PROTO(struct inode *inode, int is_metadata, __u64 block), - - TP_ARGS(inode, is_metadata, block), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( __u64, block ) - __field( int, is_metadata ) - __field( __u16, mode ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->block = block; - __entry->is_metadata = is_metadata; - __entry->mode = inode->i_mode; - ), - - TP_printk("dev %d,%d ino %lu mode 0%o is_metadata %d block %llu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->mode, __entry->is_metadata, __entry->block) -); - -TRACE_EVENT(ext4_da_update_reserve_space, - TP_PROTO(struct inode *inode, int used_blocks, int quota_claim), - - TP_ARGS(inode, used_blocks, quota_claim), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( __u64, i_blocks ) - __field( int, used_blocks ) - __field( int, reserved_data_blocks ) - __field( int, reserved_meta_blocks ) - __field( int, allocated_meta_blocks ) - __field( int, quota_claim ) - __field( __u16, mode ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->i_blocks = inode->i_blocks; - __entry->used_blocks = used_blocks; - __entry->reserved_data_blocks = - EXT4_I(inode)->i_reserved_data_blocks; - __entry->reserved_meta_blocks = - EXT4_I(inode)->i_reserved_meta_blocks; - __entry->allocated_meta_blocks = - EXT4_I(inode)->i_allocated_meta_blocks; - __entry->quota_claim = quota_claim; - __entry->mode = inode->i_mode; - ), - - TP_printk("dev %d,%d ino %lu mode 0%o i_blocks %llu used_blocks %d " - "reserved_data_blocks %d reserved_meta_blocks %d " - "allocated_meta_blocks %d quota_claim %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->mode, __entry->i_blocks, - __entry->used_blocks, __entry->reserved_data_blocks, - __entry->reserved_meta_blocks, __entry->allocated_meta_blocks, - __entry->quota_claim) -); - -TRACE_EVENT(ext4_da_reserve_space, - TP_PROTO(struct inode *inode), - - TP_ARGS(inode), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( __u64, i_blocks ) - __field( int, reserved_data_blocks ) - __field( int, reserved_meta_blocks ) - __field( __u16, mode ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->i_blocks = inode->i_blocks; - __entry->reserved_data_blocks = EXT4_I(inode)->i_reserved_data_blocks; - __entry->reserved_meta_blocks = EXT4_I(inode)->i_reserved_meta_blocks; - __entry->mode = inode->i_mode; - ), - - TP_printk("dev %d,%d ino %lu mode 0%o i_blocks %llu " - "reserved_data_blocks %d reserved_meta_blocks %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->mode, __entry->i_blocks, - __entry->reserved_data_blocks, - __entry->reserved_meta_blocks) -); - -TRACE_EVENT(ext4_da_release_space, - TP_PROTO(struct inode *inode, int freed_blocks), - - TP_ARGS(inode, freed_blocks), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( __u64, i_blocks ) - __field( int, freed_blocks ) - __field( int, reserved_data_blocks ) - __field( int, reserved_meta_blocks ) - __field( int, allocated_meta_blocks ) - __field( __u16, mode ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->i_blocks = inode->i_blocks; - __entry->freed_blocks = freed_blocks; - __entry->reserved_data_blocks = EXT4_I(inode)->i_reserved_data_blocks; - __entry->reserved_meta_blocks = EXT4_I(inode)->i_reserved_meta_blocks; - __entry->allocated_meta_blocks = EXT4_I(inode)->i_allocated_meta_blocks; - __entry->mode = inode->i_mode; - ), - - TP_printk("dev %d,%d ino %lu mode 0%o i_blocks %llu freed_blocks %d " - "reserved_data_blocks %d reserved_meta_blocks %d " - "allocated_meta_blocks %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->mode, __entry->i_blocks, - __entry->freed_blocks, __entry->reserved_data_blocks, - __entry->reserved_meta_blocks, __entry->allocated_meta_blocks) -); - -DECLARE_EVENT_CLASS(ext4__bitmap_load, - TP_PROTO(struct super_block *sb, unsigned long group), - - TP_ARGS(sb, group), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( __u32, group ) - - ), - - TP_fast_assign( - __entry->dev = sb->s_dev; - __entry->group = group; - ), - - TP_printk("dev %d,%d group %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->group) -); - -DEFINE_EVENT(ext4__bitmap_load, ext4_mb_bitmap_load, - - TP_PROTO(struct super_block *sb, unsigned long group), - - TP_ARGS(sb, group) -); - -DEFINE_EVENT(ext4__bitmap_load, ext4_mb_buddy_bitmap_load, - - TP_PROTO(struct super_block *sb, unsigned long group), - - TP_ARGS(sb, group) -); - -DEFINE_EVENT(ext4__bitmap_load, ext4_read_block_bitmap_load, - - TP_PROTO(struct super_block *sb, unsigned long group), - - TP_ARGS(sb, group) -); - -DEFINE_EVENT(ext4__bitmap_load, ext4_load_inode_bitmap, - - TP_PROTO(struct super_block *sb, unsigned long group), - - TP_ARGS(sb, group) -); - -TRACE_EVENT(ext4_direct_IO_enter, - TP_PROTO(struct inode *inode, loff_t offset, unsigned long len, int rw), - - TP_ARGS(inode, offset, len, rw), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( loff_t, pos ) - __field( unsigned long, len ) - __field( int, rw ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->pos = offset; - __entry->len = len; - __entry->rw = rw; - ), - - TP_printk("dev %d,%d ino %lu pos %lld len %lu rw %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->pos, __entry->len, __entry->rw) -); - -TRACE_EVENT(ext4_direct_IO_exit, - TP_PROTO(struct inode *inode, loff_t offset, unsigned long len, - int rw, int ret), - - TP_ARGS(inode, offset, len, rw, ret), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( loff_t, pos ) - __field( unsigned long, len ) - __field( int, rw ) - __field( int, ret ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->pos = offset; - __entry->len = len; - __entry->rw = rw; - __entry->ret = ret; - ), - - TP_printk("dev %d,%d ino %lu pos %lld len %lu rw %d ret %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->pos, __entry->len, - __entry->rw, __entry->ret) -); - -DECLARE_EVENT_CLASS(ext4__fallocate_mode, - TP_PROTO(struct inode *inode, loff_t offset, loff_t len, int mode), - - TP_ARGS(inode, offset, len, mode), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( loff_t, offset ) - __field( loff_t, len ) - __field( int, mode ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->offset = offset; - __entry->len = len; - __entry->mode = mode; - ), - - TP_printk("dev %d,%d ino %lu offset %lld len %lld mode %s", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->offset, __entry->len, - show_falloc_mode(__entry->mode)) -); - -DEFINE_EVENT(ext4__fallocate_mode, ext4_fallocate_enter, - - TP_PROTO(struct inode *inode, loff_t offset, loff_t len, int mode), - - TP_ARGS(inode, offset, len, mode) -); - -DEFINE_EVENT(ext4__fallocate_mode, ext4_punch_hole, - - TP_PROTO(struct inode *inode, loff_t offset, loff_t len, int mode), - - TP_ARGS(inode, offset, len, mode) -); - -DEFINE_EVENT(ext4__fallocate_mode, ext4_zero_range, - - TP_PROTO(struct inode *inode, loff_t offset, loff_t len, int mode), - - TP_ARGS(inode, offset, len, mode) -); - -TRACE_EVENT(ext4_fallocate_exit, - TP_PROTO(struct inode *inode, loff_t offset, - unsigned int max_blocks, int ret), - - TP_ARGS(inode, offset, max_blocks, ret), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( loff_t, pos ) - __field( unsigned int, blocks ) - __field( int, ret ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->pos = offset; - __entry->blocks = max_blocks; - __entry->ret = ret; - ), - - TP_printk("dev %d,%d ino %lu pos %lld blocks %u ret %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->pos, __entry->blocks, - __entry->ret) -); - -TRACE_EVENT(ext4_unlink_enter, - TP_PROTO(struct inode *parent, struct dentry *dentry), - - TP_ARGS(parent, dentry), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ino_t, parent ) - __field( loff_t, size ) - ), - - TP_fast_assign( - __entry->dev = dentry->d_sb->s_dev; - __entry->ino = d_inode(dentry)->i_ino; - __entry->parent = parent->i_ino; - __entry->size = d_inode(dentry)->i_size; - ), - - TP_printk("dev %d,%d ino %lu size %lld parent %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, __entry->size, - (unsigned long) __entry->parent) -); - -TRACE_EVENT(ext4_unlink_exit, - TP_PROTO(struct dentry *dentry, int ret), - - TP_ARGS(dentry, ret), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( int, ret ) - ), - - TP_fast_assign( - __entry->dev = dentry->d_sb->s_dev; - __entry->ino = d_inode(dentry)->i_ino; - __entry->ret = ret; - ), - - TP_printk("dev %d,%d ino %lu ret %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->ret) -); - -DECLARE_EVENT_CLASS(ext4__truncate, - TP_PROTO(struct inode *inode), - - TP_ARGS(inode), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( __u64, blocks ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->blocks = inode->i_blocks; - ), - - TP_printk("dev %d,%d ino %lu blocks %llu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, __entry->blocks) -); - -DEFINE_EVENT(ext4__truncate, ext4_truncate_enter, - - TP_PROTO(struct inode *inode), - - TP_ARGS(inode) -); - -DEFINE_EVENT(ext4__truncate, ext4_truncate_exit, - - TP_PROTO(struct inode *inode), - - TP_ARGS(inode) -); - -/* 'ux' is the unwritten extent. */ -TRACE_EVENT(ext4_ext_convert_to_initialized_enter, - TP_PROTO(struct inode *inode, struct ext4_map_blocks *map, - struct ext4_extent *ux), - - TP_ARGS(inode, map, ux), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ext4_lblk_t, m_lblk ) - __field( unsigned, m_len ) - __field( ext4_lblk_t, u_lblk ) - __field( unsigned, u_len ) - __field( ext4_fsblk_t, u_pblk ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->m_lblk = map->m_lblk; - __entry->m_len = map->m_len; - __entry->u_lblk = le32_to_cpu(ux->ee_block); - __entry->u_len = ext4_ext_get_actual_len(ux); - __entry->u_pblk = ext4_ext_pblock(ux); - ), - - TP_printk("dev %d,%d ino %lu m_lblk %u m_len %u u_lblk %u u_len %u " - "u_pblk %llu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->m_lblk, __entry->m_len, - __entry->u_lblk, __entry->u_len, __entry->u_pblk) -); - -/* - * 'ux' is the unwritten extent. - * 'ix' is the initialized extent to which blocks are transferred. - */ -TRACE_EVENT(ext4_ext_convert_to_initialized_fastpath, - TP_PROTO(struct inode *inode, struct ext4_map_blocks *map, - struct ext4_extent *ux, struct ext4_extent *ix), - - TP_ARGS(inode, map, ux, ix), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ext4_lblk_t, m_lblk ) - __field( unsigned, m_len ) - __field( ext4_lblk_t, u_lblk ) - __field( unsigned, u_len ) - __field( ext4_fsblk_t, u_pblk ) - __field( ext4_lblk_t, i_lblk ) - __field( unsigned, i_len ) - __field( ext4_fsblk_t, i_pblk ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->m_lblk = map->m_lblk; - __entry->m_len = map->m_len; - __entry->u_lblk = le32_to_cpu(ux->ee_block); - __entry->u_len = ext4_ext_get_actual_len(ux); - __entry->u_pblk = ext4_ext_pblock(ux); - __entry->i_lblk = le32_to_cpu(ix->ee_block); - __entry->i_len = ext4_ext_get_actual_len(ix); - __entry->i_pblk = ext4_ext_pblock(ix); - ), - - TP_printk("dev %d,%d ino %lu m_lblk %u m_len %u " - "u_lblk %u u_len %u u_pblk %llu " - "i_lblk %u i_len %u i_pblk %llu ", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->m_lblk, __entry->m_len, - __entry->u_lblk, __entry->u_len, __entry->u_pblk, - __entry->i_lblk, __entry->i_len, __entry->i_pblk) -); - -DECLARE_EVENT_CLASS(ext4__map_blocks_enter, - TP_PROTO(struct inode *inode, ext4_lblk_t lblk, - unsigned int len, unsigned int flags), - - TP_ARGS(inode, lblk, len, flags), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ext4_lblk_t, lblk ) - __field( unsigned int, len ) - __field( unsigned int, flags ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->lblk = lblk; - __entry->len = len; - __entry->flags = flags; - ), - - TP_printk("dev %d,%d ino %lu lblk %u len %u flags %s", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->lblk, __entry->len, show_map_flags(__entry->flags)) -); - -DEFINE_EVENT(ext4__map_blocks_enter, ext4_ext_map_blocks_enter, - TP_PROTO(struct inode *inode, ext4_lblk_t lblk, - unsigned len, unsigned flags), - - TP_ARGS(inode, lblk, len, flags) -); - -DEFINE_EVENT(ext4__map_blocks_enter, ext4_ind_map_blocks_enter, - TP_PROTO(struct inode *inode, ext4_lblk_t lblk, - unsigned len, unsigned flags), - - TP_ARGS(inode, lblk, len, flags) -); - -DECLARE_EVENT_CLASS(ext4__map_blocks_exit, - TP_PROTO(struct inode *inode, unsigned flags, struct ext4_map_blocks *map, - int ret), - - TP_ARGS(inode, flags, map, ret), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( unsigned int, flags ) - __field( ext4_fsblk_t, pblk ) - __field( ext4_lblk_t, lblk ) - __field( unsigned int, len ) - __field( unsigned int, mflags ) - __field( int, ret ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->flags = flags; - __entry->pblk = map->m_pblk; - __entry->lblk = map->m_lblk; - __entry->len = map->m_len; - __entry->mflags = map->m_flags; - __entry->ret = ret; - ), - - TP_printk("dev %d,%d ino %lu flags %s lblk %u pblk %llu len %u " - "mflags %s ret %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - show_map_flags(__entry->flags), __entry->lblk, __entry->pblk, - __entry->len, show_mflags(__entry->mflags), __entry->ret) -); - -DEFINE_EVENT(ext4__map_blocks_exit, ext4_ext_map_blocks_exit, - TP_PROTO(struct inode *inode, unsigned flags, - struct ext4_map_blocks *map, int ret), - - TP_ARGS(inode, flags, map, ret) -); - -DEFINE_EVENT(ext4__map_blocks_exit, ext4_ind_map_blocks_exit, - TP_PROTO(struct inode *inode, unsigned flags, - struct ext4_map_blocks *map, int ret), - - TP_ARGS(inode, flags, map, ret) -); - -TRACE_EVENT(ext4_ext_load_extent, - TP_PROTO(struct inode *inode, ext4_lblk_t lblk, ext4_fsblk_t pblk), - - TP_ARGS(inode, lblk, pblk), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ext4_fsblk_t, pblk ) - __field( ext4_lblk_t, lblk ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->pblk = pblk; - __entry->lblk = lblk; - ), - - TP_printk("dev %d,%d ino %lu lblk %u pblk %llu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->lblk, __entry->pblk) -); - -TRACE_EVENT(ext4_load_inode, - TP_PROTO(struct inode *inode), - - TP_ARGS(inode), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - ), - - TP_printk("dev %d,%d ino %ld", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino) -); - -TRACE_EVENT(ext4_journal_start, - TP_PROTO(struct super_block *sb, int blocks, int rsv_blocks, - unsigned long IP), - - TP_ARGS(sb, blocks, rsv_blocks, IP), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field(unsigned long, ip ) - __field( int, blocks ) - __field( int, rsv_blocks ) - ), - - TP_fast_assign( - __entry->dev = sb->s_dev; - __entry->ip = IP; - __entry->blocks = blocks; - __entry->rsv_blocks = rsv_blocks; - ), - - TP_printk("dev %d,%d blocks, %d rsv_blocks, %d caller %pS", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->blocks, __entry->rsv_blocks, (void *)__entry->ip) -); - -TRACE_EVENT(ext4_journal_start_reserved, - TP_PROTO(struct super_block *sb, int blocks, unsigned long IP), - - TP_ARGS(sb, blocks, IP), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field(unsigned long, ip ) - __field( int, blocks ) - ), - - TP_fast_assign( - __entry->dev = sb->s_dev; - __entry->ip = IP; - __entry->blocks = blocks; - ), - - TP_printk("dev %d,%d blocks, %d caller %pS", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->blocks, (void *)__entry->ip) -); - -DECLARE_EVENT_CLASS(ext4__trim, - TP_PROTO(struct super_block *sb, - ext4_group_t group, - ext4_grpblk_t start, - ext4_grpblk_t len), - - TP_ARGS(sb, group, start, len), - - TP_STRUCT__entry( - __field( int, dev_major ) - __field( int, dev_minor ) - __field( __u32, group ) - __field( int, start ) - __field( int, len ) - ), - - TP_fast_assign( - __entry->dev_major = MAJOR(sb->s_dev); - __entry->dev_minor = MINOR(sb->s_dev); - __entry->group = group; - __entry->start = start; - __entry->len = len; - ), - - TP_printk("dev %d,%d group %u, start %d, len %d", - __entry->dev_major, __entry->dev_minor, - __entry->group, __entry->start, __entry->len) -); - -DEFINE_EVENT(ext4__trim, ext4_trim_extent, - - TP_PROTO(struct super_block *sb, - ext4_group_t group, - ext4_grpblk_t start, - ext4_grpblk_t len), - - TP_ARGS(sb, group, start, len) -); - -DEFINE_EVENT(ext4__trim, ext4_trim_all_free, - - TP_PROTO(struct super_block *sb, - ext4_group_t group, - ext4_grpblk_t start, - ext4_grpblk_t len), - - TP_ARGS(sb, group, start, len) -); - -TRACE_EVENT(ext4_ext_handle_unwritten_extents, - TP_PROTO(struct inode *inode, struct ext4_map_blocks *map, int flags, - unsigned int allocated, ext4_fsblk_t newblock), - - TP_ARGS(inode, map, flags, allocated, newblock), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( int, flags ) - __field( ext4_lblk_t, lblk ) - __field( ext4_fsblk_t, pblk ) - __field( unsigned int, len ) - __field( unsigned int, allocated ) - __field( ext4_fsblk_t, newblk ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->flags = flags; - __entry->lblk = map->m_lblk; - __entry->pblk = map->m_pblk; - __entry->len = map->m_len; - __entry->allocated = allocated; - __entry->newblk = newblock; - ), - - TP_printk("dev %d,%d ino %lu m_lblk %u m_pblk %llu m_len %u flags %s " - "allocated %d newblock %llu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned) __entry->lblk, (unsigned long long) __entry->pblk, - __entry->len, show_map_flags(__entry->flags), - (unsigned int) __entry->allocated, - (unsigned long long) __entry->newblk) -); - -TRACE_EVENT(ext4_get_implied_cluster_alloc_exit, - TP_PROTO(struct super_block *sb, struct ext4_map_blocks *map, int ret), - - TP_ARGS(sb, map, ret), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( unsigned int, flags ) - __field( ext4_lblk_t, lblk ) - __field( ext4_fsblk_t, pblk ) - __field( unsigned int, len ) - __field( int, ret ) - ), - - TP_fast_assign( - __entry->dev = sb->s_dev; - __entry->flags = map->m_flags; - __entry->lblk = map->m_lblk; - __entry->pblk = map->m_pblk; - __entry->len = map->m_len; - __entry->ret = ret; - ), - - TP_printk("dev %d,%d m_lblk %u m_pblk %llu m_len %u m_flags %s ret %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->lblk, (unsigned long long) __entry->pblk, - __entry->len, show_mflags(__entry->flags), __entry->ret) -); - -TRACE_EVENT(ext4_ext_put_in_cache, - TP_PROTO(struct inode *inode, ext4_lblk_t lblk, unsigned int len, - ext4_fsblk_t start), - - TP_ARGS(inode, lblk, len, start), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ext4_lblk_t, lblk ) - __field( unsigned int, len ) - __field( ext4_fsblk_t, start ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->lblk = lblk; - __entry->len = len; - __entry->start = start; - ), - - TP_printk("dev %d,%d ino %lu lblk %u len %u start %llu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned) __entry->lblk, - __entry->len, - (unsigned long long) __entry->start) -); - -TRACE_EVENT(ext4_ext_in_cache, - TP_PROTO(struct inode *inode, ext4_lblk_t lblk, int ret), - - TP_ARGS(inode, lblk, ret), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ext4_lblk_t, lblk ) - __field( int, ret ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->lblk = lblk; - __entry->ret = ret; - ), - - TP_printk("dev %d,%d ino %lu lblk %u ret %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned) __entry->lblk, - __entry->ret) - -); - -TRACE_EVENT(ext4_find_delalloc_range, - TP_PROTO(struct inode *inode, ext4_lblk_t from, ext4_lblk_t to, - int reverse, int found, ext4_lblk_t found_blk), - - TP_ARGS(inode, from, to, reverse, found, found_blk), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ext4_lblk_t, from ) - __field( ext4_lblk_t, to ) - __field( int, reverse ) - __field( int, found ) - __field( ext4_lblk_t, found_blk ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->from = from; - __entry->to = to; - __entry->reverse = reverse; - __entry->found = found; - __entry->found_blk = found_blk; - ), - - TP_printk("dev %d,%d ino %lu from %u to %u reverse %d found %d " - "(blk = %u)", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned) __entry->from, (unsigned) __entry->to, - __entry->reverse, __entry->found, - (unsigned) __entry->found_blk) -); - -TRACE_EVENT(ext4_get_reserved_cluster_alloc, - TP_PROTO(struct inode *inode, ext4_lblk_t lblk, unsigned int len), - - TP_ARGS(inode, lblk, len), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ext4_lblk_t, lblk ) - __field( unsigned int, len ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->lblk = lblk; - __entry->len = len; - ), - - TP_printk("dev %d,%d ino %lu lblk %u len %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned) __entry->lblk, - __entry->len) -); - -TRACE_EVENT(ext4_ext_show_extent, - TP_PROTO(struct inode *inode, ext4_lblk_t lblk, ext4_fsblk_t pblk, - unsigned short len), - - TP_ARGS(inode, lblk, pblk, len), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ext4_fsblk_t, pblk ) - __field( ext4_lblk_t, lblk ) - __field( unsigned short, len ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->pblk = pblk; - __entry->lblk = lblk; - __entry->len = len; - ), - - TP_printk("dev %d,%d ino %lu lblk %u pblk %llu len %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned) __entry->lblk, - (unsigned long long) __entry->pblk, - (unsigned short) __entry->len) -); - -TRACE_EVENT(ext4_remove_blocks, - TP_PROTO(struct inode *inode, struct ext4_extent *ex, - ext4_lblk_t from, ext4_fsblk_t to, - long long partial_cluster), - - TP_ARGS(inode, ex, from, to, partial_cluster), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ext4_lblk_t, from ) - __field( ext4_lblk_t, to ) - __field( long long, partial ) - __field( ext4_fsblk_t, ee_pblk ) - __field( ext4_lblk_t, ee_lblk ) - __field( unsigned short, ee_len ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->from = from; - __entry->to = to; - __entry->partial = partial_cluster; - __entry->ee_pblk = ext4_ext_pblock(ex); - __entry->ee_lblk = le32_to_cpu(ex->ee_block); - __entry->ee_len = ext4_ext_get_actual_len(ex); - ), - - TP_printk("dev %d,%d ino %lu extent [%u(%llu), %u]" - "from %u to %u partial_cluster %lld", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned) __entry->ee_lblk, - (unsigned long long) __entry->ee_pblk, - (unsigned short) __entry->ee_len, - (unsigned) __entry->from, - (unsigned) __entry->to, - (long long) __entry->partial) -); - -TRACE_EVENT(ext4_ext_rm_leaf, - TP_PROTO(struct inode *inode, ext4_lblk_t start, - struct ext4_extent *ex, - long long partial_cluster), - - TP_ARGS(inode, start, ex, partial_cluster), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( long long, partial ) - __field( ext4_lblk_t, start ) - __field( ext4_lblk_t, ee_lblk ) - __field( ext4_fsblk_t, ee_pblk ) - __field( short, ee_len ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->partial = partial_cluster; - __entry->start = start; - __entry->ee_lblk = le32_to_cpu(ex->ee_block); - __entry->ee_pblk = ext4_ext_pblock(ex); - __entry->ee_len = ext4_ext_get_actual_len(ex); - ), - - TP_printk("dev %d,%d ino %lu start_lblk %u last_extent [%u(%llu), %u]" - "partial_cluster %lld", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned) __entry->start, - (unsigned) __entry->ee_lblk, - (unsigned long long) __entry->ee_pblk, - (unsigned short) __entry->ee_len, - (long long) __entry->partial) -); - -TRACE_EVENT(ext4_ext_rm_idx, - TP_PROTO(struct inode *inode, ext4_fsblk_t pblk), - - TP_ARGS(inode, pblk), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ext4_fsblk_t, pblk ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->pblk = pblk; - ), - - TP_printk("dev %d,%d ino %lu index_pblk %llu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned long long) __entry->pblk) -); - -TRACE_EVENT(ext4_ext_remove_space, - TP_PROTO(struct inode *inode, ext4_lblk_t start, - ext4_lblk_t end, int depth), - - TP_ARGS(inode, start, end, depth), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ext4_lblk_t, start ) - __field( ext4_lblk_t, end ) - __field( int, depth ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->start = start; - __entry->end = end; - __entry->depth = depth; - ), - - TP_printk("dev %d,%d ino %lu since %u end %u depth %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned) __entry->start, - (unsigned) __entry->end, - __entry->depth) -); - -TRACE_EVENT(ext4_ext_remove_space_done, - TP_PROTO(struct inode *inode, ext4_lblk_t start, ext4_lblk_t end, - int depth, long long partial, __le16 eh_entries), - - TP_ARGS(inode, start, end, depth, partial, eh_entries), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ext4_lblk_t, start ) - __field( ext4_lblk_t, end ) - __field( int, depth ) - __field( long long, partial ) - __field( unsigned short, eh_entries ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->start = start; - __entry->end = end; - __entry->depth = depth; - __entry->partial = partial; - __entry->eh_entries = le16_to_cpu(eh_entries); - ), - - TP_printk("dev %d,%d ino %lu since %u end %u depth %d partial %lld " - "remaining_entries %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - (unsigned) __entry->start, - (unsigned) __entry->end, - __entry->depth, - (long long) __entry->partial, - (unsigned short) __entry->eh_entries) -); - -DECLARE_EVENT_CLASS(ext4__es_extent, - TP_PROTO(struct inode *inode, struct extent_status *es), - - TP_ARGS(inode, es), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ext4_lblk_t, lblk ) - __field( ext4_lblk_t, len ) - __field( ext4_fsblk_t, pblk ) - __field( char, status ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->lblk = es->es_lblk; - __entry->len = es->es_len; - __entry->pblk = ext4_es_pblock(es); - __entry->status = ext4_es_status(es); - ), - - TP_printk("dev %d,%d ino %lu es [%u/%u) mapped %llu status %s", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->lblk, __entry->len, - __entry->pblk, show_extent_status(__entry->status)) -); - -DEFINE_EVENT(ext4__es_extent, ext4_es_insert_extent, - TP_PROTO(struct inode *inode, struct extent_status *es), - - TP_ARGS(inode, es) -); - -DEFINE_EVENT(ext4__es_extent, ext4_es_cache_extent, - TP_PROTO(struct inode *inode, struct extent_status *es), - - TP_ARGS(inode, es) -); - -TRACE_EVENT(ext4_es_remove_extent, - TP_PROTO(struct inode *inode, ext4_lblk_t lblk, ext4_lblk_t len), - - TP_ARGS(inode, lblk, len), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( loff_t, lblk ) - __field( loff_t, len ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->lblk = lblk; - __entry->len = len; - ), - - TP_printk("dev %d,%d ino %lu es [%lld/%lld)", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->lblk, __entry->len) -); - -TRACE_EVENT(ext4_es_find_delayed_extent_range_enter, - TP_PROTO(struct inode *inode, ext4_lblk_t lblk), - - TP_ARGS(inode, lblk), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ext4_lblk_t, lblk ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->lblk = lblk; - ), - - TP_printk("dev %d,%d ino %lu lblk %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, __entry->lblk) -); - -TRACE_EVENT(ext4_es_find_delayed_extent_range_exit, - TP_PROTO(struct inode *inode, struct extent_status *es), - - TP_ARGS(inode, es), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ext4_lblk_t, lblk ) - __field( ext4_lblk_t, len ) - __field( ext4_fsblk_t, pblk ) - __field( char, status ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->lblk = es->es_lblk; - __entry->len = es->es_len; - __entry->pblk = ext4_es_pblock(es); - __entry->status = ext4_es_status(es); - ), - - TP_printk("dev %d,%d ino %lu es [%u/%u) mapped %llu status %s", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->lblk, __entry->len, - __entry->pblk, show_extent_status(__entry->status)) -); - -TRACE_EVENT(ext4_es_lookup_extent_enter, - TP_PROTO(struct inode *inode, ext4_lblk_t lblk), - - TP_ARGS(inode, lblk), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ext4_lblk_t, lblk ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->lblk = lblk; - ), - - TP_printk("dev %d,%d ino %lu lblk %u", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, __entry->lblk) -); - -TRACE_EVENT(ext4_es_lookup_extent_exit, - TP_PROTO(struct inode *inode, struct extent_status *es, - int found), - - TP_ARGS(inode, es, found), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - __field( ext4_lblk_t, lblk ) - __field( ext4_lblk_t, len ) - __field( ext4_fsblk_t, pblk ) - __field( char, status ) - __field( int, found ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->lblk = es->es_lblk; - __entry->len = es->es_len; - __entry->pblk = ext4_es_pblock(es); - __entry->status = ext4_es_status(es); - __entry->found = found; - ), - - TP_printk("dev %d,%d ino %lu found %d [%u/%u) %llu %s", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, __entry->found, - __entry->lblk, __entry->len, - __entry->found ? __entry->pblk : 0, - show_extent_status(__entry->found ? __entry->status : 0)) -); - -DECLARE_EVENT_CLASS(ext4__es_shrink_enter, - TP_PROTO(struct super_block *sb, int nr_to_scan, int cache_cnt), - - TP_ARGS(sb, nr_to_scan, cache_cnt), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( int, nr_to_scan ) - __field( int, cache_cnt ) - ), - - TP_fast_assign( - __entry->dev = sb->s_dev; - __entry->nr_to_scan = nr_to_scan; - __entry->cache_cnt = cache_cnt; - ), - - TP_printk("dev %d,%d nr_to_scan %d cache_cnt %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->nr_to_scan, __entry->cache_cnt) -); - -DEFINE_EVENT(ext4__es_shrink_enter, ext4_es_shrink_count, - TP_PROTO(struct super_block *sb, int nr_to_scan, int cache_cnt), - - TP_ARGS(sb, nr_to_scan, cache_cnt) -); - -DEFINE_EVENT(ext4__es_shrink_enter, ext4_es_shrink_scan_enter, - TP_PROTO(struct super_block *sb, int nr_to_scan, int cache_cnt), - - TP_ARGS(sb, nr_to_scan, cache_cnt) -); - -TRACE_EVENT(ext4_es_shrink_scan_exit, - TP_PROTO(struct super_block *sb, int nr_shrunk, int cache_cnt), - - TP_ARGS(sb, nr_shrunk, cache_cnt), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( int, nr_shrunk ) - __field( int, cache_cnt ) - ), - - TP_fast_assign( - __entry->dev = sb->s_dev; - __entry->nr_shrunk = nr_shrunk; - __entry->cache_cnt = cache_cnt; - ), - - TP_printk("dev %d,%d nr_shrunk %d cache_cnt %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->nr_shrunk, __entry->cache_cnt) -); - -TRACE_EVENT(ext4_collapse_range, - TP_PROTO(struct inode *inode, loff_t offset, loff_t len), - - TP_ARGS(inode, offset, len), - - TP_STRUCT__entry( - __field(dev_t, dev) - __field(ino_t, ino) - __field(loff_t, offset) - __field(loff_t, len) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->offset = offset; - __entry->len = len; - ), - - TP_printk("dev %d,%d ino %lu offset %lld len %lld", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->offset, __entry->len) -); - -TRACE_EVENT(ext4_insert_range, - TP_PROTO(struct inode *inode, loff_t offset, loff_t len), - - TP_ARGS(inode, offset, len), - - TP_STRUCT__entry( - __field(dev_t, dev) - __field(ino_t, ino) - __field(loff_t, offset) - __field(loff_t, len) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->offset = offset; - __entry->len = len; - ), - - TP_printk("dev %d,%d ino %lu offset %lld len %lld", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino, - __entry->offset, __entry->len) -); - -TRACE_EVENT(ext4_es_shrink, - TP_PROTO(struct super_block *sb, int nr_shrunk, u64 scan_time, - int nr_skipped, int retried), - - TP_ARGS(sb, nr_shrunk, scan_time, nr_skipped, retried), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( int, nr_shrunk ) - __field( unsigned long long, scan_time ) - __field( int, nr_skipped ) - __field( int, retried ) - ), - - TP_fast_assign( - __entry->dev = sb->s_dev; - __entry->nr_shrunk = nr_shrunk; - __entry->scan_time = div_u64(scan_time, 1000); - __entry->nr_skipped = nr_skipped; - __entry->retried = retried; - ), - - TP_printk("dev %d,%d nr_shrunk %d, scan_time %llu " - "nr_skipped %d retried %d", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->nr_shrunk, - __entry->scan_time, __entry->nr_skipped, __entry->retried) -); - -#endif /* _TRACE_EXT4_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/fib.h b/src/linux/include/trace/events/fib.h deleted file mode 100644 index 833cfcb..0000000 --- a/src/linux/include/trace/events/fib.h +++ /dev/null @@ -1,113 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM fib - -#if !defined(_TRACE_FIB_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_FIB_H - -#include -#include -#include -#include - -TRACE_EVENT(fib_table_lookup, - - TP_PROTO(u32 tb_id, const struct flowi4 *flp), - - TP_ARGS(tb_id, flp), - - TP_STRUCT__entry( - __field( u32, tb_id ) - __field( int, oif ) - __field( int, iif ) - __field( __u8, tos ) - __field( __u8, scope ) - __field( __u8, flags ) - __array( __u8, src, 4 ) - __array( __u8, dst, 4 ) - ), - - TP_fast_assign( - __be32 *p32; - - __entry->tb_id = tb_id; - __entry->oif = flp->flowi4_oif; - __entry->iif = flp->flowi4_iif; - __entry->tos = flp->flowi4_tos; - __entry->scope = flp->flowi4_scope; - __entry->flags = flp->flowi4_flags; - - p32 = (__be32 *) __entry->src; - *p32 = flp->saddr; - - p32 = (__be32 *) __entry->dst; - *p32 = flp->daddr; - ), - - TP_printk("table %u oif %d iif %d src %pI4 dst %pI4 tos %d scope %d flags %x", - __entry->tb_id, __entry->oif, __entry->iif, - __entry->src, __entry->dst, __entry->tos, __entry->scope, - __entry->flags) -); - -TRACE_EVENT(fib_table_lookup_nh, - - TP_PROTO(const struct fib_nh *nh), - - TP_ARGS(nh), - - TP_STRUCT__entry( - __string( name, nh->nh_dev->name) - __field( int, oif ) - __array( __u8, src, 4 ) - ), - - TP_fast_assign( - __be32 *p32 = (__be32 *) __entry->src; - - __assign_str(name, nh->nh_dev ? nh->nh_dev->name : "not set"); - __entry->oif = nh->nh_oif; - *p32 = nh->nh_saddr; - ), - - TP_printk("nexthop dev %s oif %d src %pI4", - __get_str(name), __entry->oif, __entry->src) -); - -TRACE_EVENT(fib_validate_source, - - TP_PROTO(const struct net_device *dev, const struct flowi4 *flp), - - TP_ARGS(dev, flp), - - TP_STRUCT__entry( - __string( name, dev->name ) - __field( int, oif ) - __field( int, iif ) - __field( __u8, tos ) - __array( __u8, src, 4 ) - __array( __u8, dst, 4 ) - ), - - TP_fast_assign( - __be32 *p32; - - __assign_str(name, dev ? dev->name : "not set"); - __entry->oif = flp->flowi4_oif; - __entry->iif = flp->flowi4_iif; - __entry->tos = flp->flowi4_tos; - - p32 = (__be32 *) __entry->src; - *p32 = flp->saddr; - - p32 = (__be32 *) __entry->dst; - *p32 = flp->daddr; - ), - - TP_printk("dev %s oif %d iif %d tos %d src %pI4 dst %pI4", - __get_str(name), __entry->oif, __entry->iif, __entry->tos, - __entry->src, __entry->dst) -); -#endif /* _TRACE_FIB_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/fib6.h b/src/linux/include/trace/events/fib6.h deleted file mode 100644 index d60096c..0000000 --- a/src/linux/include/trace/events/fib6.h +++ /dev/null @@ -1,76 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM fib6 - -#if !defined(_TRACE_FIB6_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_FIB6_H - -#include -#include -#include -#include - -TRACE_EVENT(fib6_table_lookup, - - TP_PROTO(const struct net *net, const struct rt6_info *rt, - u32 tb_id, const struct flowi6 *flp), - - TP_ARGS(net, rt, tb_id, flp), - - TP_STRUCT__entry( - __field( u32, tb_id ) - - __field( int, oif ) - __field( int, iif ) - __field( __u8, tos ) - __field( __u8, scope ) - __field( __u8, flags ) - __array( __u8, src, 16 ) - __array( __u8, dst, 16 ) - - __dynamic_array( char, name, IFNAMSIZ ) - __array( __u8, gw, 16 ) - ), - - TP_fast_assign( - struct in6_addr *in6; - - __entry->tb_id = tb_id; - __entry->oif = flp->flowi6_oif; - __entry->iif = flp->flowi6_iif; - __entry->tos = ip6_tclass(flp->flowlabel); - __entry->scope = flp->flowi6_scope; - __entry->flags = flp->flowi6_flags; - - in6 = (struct in6_addr *)__entry->src; - *in6 = flp->saddr; - - in6 = (struct in6_addr *)__entry->dst; - *in6 = flp->daddr; - - if (rt->rt6i_idev) { - __assign_str(name, rt->rt6i_idev->dev->name); - } else { - __assign_str(name, ""); - } - if (rt == net->ipv6.ip6_null_entry) { - struct in6_addr in6_zero = {}; - - in6 = (struct in6_addr *)__entry->gw; - *in6 = in6_zero; - - } else if (rt) { - in6 = (struct in6_addr *)__entry->gw; - *in6 = rt->rt6i_gateway; - } - ), - - TP_printk("table %3u oif %d iif %d src %pI6c dst %pI6c tos %d scope %d flags %x ==> dev %s gw %pI6c", - __entry->tb_id, __entry->oif, __entry->iif, - __entry->src, __entry->dst, __entry->tos, __entry->scope, - __entry->flags, __get_str(name), __entry->gw) -); - -#endif /* _TRACE_FIB6_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/filemap.h b/src/linux/include/trace/events/filemap.h deleted file mode 100644 index 42febb6..0000000 --- a/src/linux/include/trace/events/filemap.h +++ /dev/null @@ -1,58 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM filemap - -#if !defined(_TRACE_FILEMAP_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_FILEMAP_H - -#include -#include -#include -#include -#include -#include - -DECLARE_EVENT_CLASS(mm_filemap_op_page_cache, - - TP_PROTO(struct page *page), - - TP_ARGS(page), - - TP_STRUCT__entry( - __field(unsigned long, pfn) - __field(unsigned long, i_ino) - __field(unsigned long, index) - __field(dev_t, s_dev) - ), - - TP_fast_assign( - __entry->pfn = page_to_pfn(page); - __entry->i_ino = page->mapping->host->i_ino; - __entry->index = page->index; - if (page->mapping->host->i_sb) - __entry->s_dev = page->mapping->host->i_sb->s_dev; - else - __entry->s_dev = page->mapping->host->i_rdev; - ), - - TP_printk("dev %d:%d ino %lx page=%p pfn=%lu ofs=%lu", - MAJOR(__entry->s_dev), MINOR(__entry->s_dev), - __entry->i_ino, - pfn_to_page(__entry->pfn), - __entry->pfn, - __entry->index << PAGE_SHIFT) -); - -DEFINE_EVENT(mm_filemap_op_page_cache, mm_filemap_delete_from_page_cache, - TP_PROTO(struct page *page), - TP_ARGS(page) - ); - -DEFINE_EVENT(mm_filemap_op_page_cache, mm_filemap_add_to_page_cache, - TP_PROTO(struct page *page), - TP_ARGS(page) - ); - -#endif /* _TRACE_FILEMAP_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/irq.h b/src/linux/include/trace/events/irq.h deleted file mode 100644 index 1c41b74..0000000 --- a/src/linux/include/trace/events/irq.h +++ /dev/null @@ -1,165 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM irq - -#if !defined(_TRACE_IRQ_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_IRQ_H - -#include - -struct irqaction; -struct softirq_action; - -#define SOFTIRQ_NAME_LIST \ - softirq_name(HI) \ - softirq_name(TIMER) \ - softirq_name(NET_TX) \ - softirq_name(NET_RX) \ - softirq_name(BLOCK) \ - softirq_name(IRQ_POLL) \ - softirq_name(TASKLET) \ - softirq_name(SCHED) \ - softirq_name(HRTIMER) \ - softirq_name_end(RCU) - -#undef softirq_name -#undef softirq_name_end - -#define softirq_name(sirq) TRACE_DEFINE_ENUM(sirq##_SOFTIRQ); -#define softirq_name_end(sirq) TRACE_DEFINE_ENUM(sirq##_SOFTIRQ); - -SOFTIRQ_NAME_LIST - -#undef softirq_name -#undef softirq_name_end - -#define softirq_name(sirq) { sirq##_SOFTIRQ, #sirq }, -#define softirq_name_end(sirq) { sirq##_SOFTIRQ, #sirq } - -#define show_softirq_name(val) \ - __print_symbolic(val, SOFTIRQ_NAME_LIST) - -/** - * irq_handler_entry - called immediately before the irq action handler - * @irq: irq number - * @action: pointer to struct irqaction - * - * The struct irqaction pointed to by @action contains various - * information about the handler, including the device name, - * @action->name, and the device id, @action->dev_id. When used in - * conjunction with the irq_handler_exit tracepoint, we can figure - * out irq handler latencies. - */ -TRACE_EVENT(irq_handler_entry, - - TP_PROTO(int irq, struct irqaction *action), - - TP_ARGS(irq, action), - - TP_STRUCT__entry( - __field( int, irq ) - __string( name, action->name ) - ), - - TP_fast_assign( - __entry->irq = irq; - __assign_str(name, action->name); - ), - - TP_printk("irq=%d name=%s", __entry->irq, __get_str(name)) -); - -/** - * irq_handler_exit - called immediately after the irq action handler returns - * @irq: irq number - * @action: pointer to struct irqaction - * @ret: return value - * - * If the @ret value is set to IRQ_HANDLED, then we know that the corresponding - * @action->handler successfully handled this irq. Otherwise, the irq might be - * a shared irq line, or the irq was not handled successfully. Can be used in - * conjunction with the irq_handler_entry to understand irq handler latencies. - */ -TRACE_EVENT(irq_handler_exit, - - TP_PROTO(int irq, struct irqaction *action, int ret), - - TP_ARGS(irq, action, ret), - - TP_STRUCT__entry( - __field( int, irq ) - __field( int, ret ) - ), - - TP_fast_assign( - __entry->irq = irq; - __entry->ret = ret; - ), - - TP_printk("irq=%d ret=%s", - __entry->irq, __entry->ret ? "handled" : "unhandled") -); - -DECLARE_EVENT_CLASS(softirq, - - TP_PROTO(unsigned int vec_nr), - - TP_ARGS(vec_nr), - - TP_STRUCT__entry( - __field( unsigned int, vec ) - ), - - TP_fast_assign( - __entry->vec = vec_nr; - ), - - TP_printk("vec=%u [action=%s]", __entry->vec, - show_softirq_name(__entry->vec)) -); - -/** - * softirq_entry - called immediately before the softirq handler - * @vec_nr: softirq vector number - * - * When used in combination with the softirq_exit tracepoint - * we can determine the softirq handler routine. - */ -DEFINE_EVENT(softirq, softirq_entry, - - TP_PROTO(unsigned int vec_nr), - - TP_ARGS(vec_nr) -); - -/** - * softirq_exit - called immediately after the softirq handler returns - * @vec_nr: softirq vector number - * - * When used in combination with the softirq_entry tracepoint - * we can determine the softirq handler routine. - */ -DEFINE_EVENT(softirq, softirq_exit, - - TP_PROTO(unsigned int vec_nr), - - TP_ARGS(vec_nr) -); - -/** - * softirq_raise - called immediately when a softirq is raised - * @vec_nr: softirq vector number - * - * When used in combination with the softirq_entry tracepoint - * we can determine the softirq raise to run latency. - */ -DEFINE_EVENT(softirq, softirq_raise, - - TP_PROTO(unsigned int vec_nr), - - TP_ARGS(vec_nr) -); - -#endif /* _TRACE_IRQ_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/jbd2.h b/src/linux/include/trace/events/jbd2.h deleted file mode 100644 index c1d1f3e..0000000 --- a/src/linux/include/trace/events/jbd2.h +++ /dev/null @@ -1,385 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM jbd2 - -#if !defined(_TRACE_JBD2_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_JBD2_H - -#include -#include - -struct transaction_chp_stats_s; -struct transaction_run_stats_s; - -TRACE_EVENT(jbd2_checkpoint, - - TP_PROTO(journal_t *journal, int result), - - TP_ARGS(journal, result), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( int, result ) - ), - - TP_fast_assign( - __entry->dev = journal->j_fs_dev->bd_dev; - __entry->result = result; - ), - - TP_printk("dev %d,%d result %d", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->result) -); - -DECLARE_EVENT_CLASS(jbd2_commit, - - TP_PROTO(journal_t *journal, transaction_t *commit_transaction), - - TP_ARGS(journal, commit_transaction), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( char, sync_commit ) - __field( int, transaction ) - ), - - TP_fast_assign( - __entry->dev = journal->j_fs_dev->bd_dev; - __entry->sync_commit = commit_transaction->t_synchronous_commit; - __entry->transaction = commit_transaction->t_tid; - ), - - TP_printk("dev %d,%d transaction %d sync %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->transaction, __entry->sync_commit) -); - -DEFINE_EVENT(jbd2_commit, jbd2_start_commit, - - TP_PROTO(journal_t *journal, transaction_t *commit_transaction), - - TP_ARGS(journal, commit_transaction) -); - -DEFINE_EVENT(jbd2_commit, jbd2_commit_locking, - - TP_PROTO(journal_t *journal, transaction_t *commit_transaction), - - TP_ARGS(journal, commit_transaction) -); - -DEFINE_EVENT(jbd2_commit, jbd2_commit_flushing, - - TP_PROTO(journal_t *journal, transaction_t *commit_transaction), - - TP_ARGS(journal, commit_transaction) -); - -DEFINE_EVENT(jbd2_commit, jbd2_commit_logging, - - TP_PROTO(journal_t *journal, transaction_t *commit_transaction), - - TP_ARGS(journal, commit_transaction) -); - -DEFINE_EVENT(jbd2_commit, jbd2_drop_transaction, - - TP_PROTO(journal_t *journal, transaction_t *commit_transaction), - - TP_ARGS(journal, commit_transaction) -); - -TRACE_EVENT(jbd2_end_commit, - TP_PROTO(journal_t *journal, transaction_t *commit_transaction), - - TP_ARGS(journal, commit_transaction), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( char, sync_commit ) - __field( int, transaction ) - __field( int, head ) - ), - - TP_fast_assign( - __entry->dev = journal->j_fs_dev->bd_dev; - __entry->sync_commit = commit_transaction->t_synchronous_commit; - __entry->transaction = commit_transaction->t_tid; - __entry->head = journal->j_tail_sequence; - ), - - TP_printk("dev %d,%d transaction %d sync %d head %d", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->transaction, __entry->sync_commit, __entry->head) -); - -TRACE_EVENT(jbd2_submit_inode_data, - TP_PROTO(struct inode *inode), - - TP_ARGS(inode), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( ino_t, ino ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - ), - - TP_printk("dev %d,%d ino %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - (unsigned long) __entry->ino) -); - -TRACE_EVENT(jbd2_handle_start, - TP_PROTO(dev_t dev, unsigned long tid, unsigned int type, - unsigned int line_no, int requested_blocks), - - TP_ARGS(dev, tid, type, line_no, requested_blocks), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( unsigned long, tid ) - __field( unsigned int, type ) - __field( unsigned int, line_no ) - __field( int, requested_blocks) - ), - - TP_fast_assign( - __entry->dev = dev; - __entry->tid = tid; - __entry->type = type; - __entry->line_no = line_no; - __entry->requested_blocks = requested_blocks; - ), - - TP_printk("dev %d,%d tid %lu type %u line_no %u " - "requested_blocks %d", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid, - __entry->type, __entry->line_no, __entry->requested_blocks) -); - -TRACE_EVENT(jbd2_handle_extend, - TP_PROTO(dev_t dev, unsigned long tid, unsigned int type, - unsigned int line_no, int buffer_credits, - int requested_blocks), - - TP_ARGS(dev, tid, type, line_no, buffer_credits, requested_blocks), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( unsigned long, tid ) - __field( unsigned int, type ) - __field( unsigned int, line_no ) - __field( int, buffer_credits ) - __field( int, requested_blocks) - ), - - TP_fast_assign( - __entry->dev = dev; - __entry->tid = tid; - __entry->type = type; - __entry->line_no = line_no; - __entry->buffer_credits = buffer_credits; - __entry->requested_blocks = requested_blocks; - ), - - TP_printk("dev %d,%d tid %lu type %u line_no %u " - "buffer_credits %d requested_blocks %d", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid, - __entry->type, __entry->line_no, __entry->buffer_credits, - __entry->requested_blocks) -); - -TRACE_EVENT(jbd2_handle_stats, - TP_PROTO(dev_t dev, unsigned long tid, unsigned int type, - unsigned int line_no, int interval, int sync, - int requested_blocks, int dirtied_blocks), - - TP_ARGS(dev, tid, type, line_no, interval, sync, - requested_blocks, dirtied_blocks), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( unsigned long, tid ) - __field( unsigned int, type ) - __field( unsigned int, line_no ) - __field( int, interval ) - __field( int, sync ) - __field( int, requested_blocks) - __field( int, dirtied_blocks ) - ), - - TP_fast_assign( - __entry->dev = dev; - __entry->tid = tid; - __entry->type = type; - __entry->line_no = line_no; - __entry->interval = interval; - __entry->sync = sync; - __entry->requested_blocks = requested_blocks; - __entry->dirtied_blocks = dirtied_blocks; - ), - - TP_printk("dev %d,%d tid %lu type %u line_no %u interval %d " - "sync %d requested_blocks %d dirtied_blocks %d", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid, - __entry->type, __entry->line_no, __entry->interval, - __entry->sync, __entry->requested_blocks, - __entry->dirtied_blocks) -); - -TRACE_EVENT(jbd2_run_stats, - TP_PROTO(dev_t dev, unsigned long tid, - struct transaction_run_stats_s *stats), - - TP_ARGS(dev, tid, stats), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( unsigned long, tid ) - __field( unsigned long, wait ) - __field( unsigned long, request_delay ) - __field( unsigned long, running ) - __field( unsigned long, locked ) - __field( unsigned long, flushing ) - __field( unsigned long, logging ) - __field( __u32, handle_count ) - __field( __u32, blocks ) - __field( __u32, blocks_logged ) - ), - - TP_fast_assign( - __entry->dev = dev; - __entry->tid = tid; - __entry->wait = stats->rs_wait; - __entry->request_delay = stats->rs_request_delay; - __entry->running = stats->rs_running; - __entry->locked = stats->rs_locked; - __entry->flushing = stats->rs_flushing; - __entry->logging = stats->rs_logging; - __entry->handle_count = stats->rs_handle_count; - __entry->blocks = stats->rs_blocks; - __entry->blocks_logged = stats->rs_blocks_logged; - ), - - TP_printk("dev %d,%d tid %lu wait %u request_delay %u running %u " - "locked %u flushing %u logging %u handle_count %u " - "blocks %u blocks_logged %u", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid, - jiffies_to_msecs(__entry->wait), - jiffies_to_msecs(__entry->request_delay), - jiffies_to_msecs(__entry->running), - jiffies_to_msecs(__entry->locked), - jiffies_to_msecs(__entry->flushing), - jiffies_to_msecs(__entry->logging), - __entry->handle_count, __entry->blocks, - __entry->blocks_logged) -); - -TRACE_EVENT(jbd2_checkpoint_stats, - TP_PROTO(dev_t dev, unsigned long tid, - struct transaction_chp_stats_s *stats), - - TP_ARGS(dev, tid, stats), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( unsigned long, tid ) - __field( unsigned long, chp_time ) - __field( __u32, forced_to_close ) - __field( __u32, written ) - __field( __u32, dropped ) - ), - - TP_fast_assign( - __entry->dev = dev; - __entry->tid = tid; - __entry->chp_time = stats->cs_chp_time; - __entry->forced_to_close= stats->cs_forced_to_close; - __entry->written = stats->cs_written; - __entry->dropped = stats->cs_dropped; - ), - - TP_printk("dev %d,%d tid %lu chp_time %u forced_to_close %u " - "written %u dropped %u", - MAJOR(__entry->dev), MINOR(__entry->dev), __entry->tid, - jiffies_to_msecs(__entry->chp_time), - __entry->forced_to_close, __entry->written, __entry->dropped) -); - -TRACE_EVENT(jbd2_update_log_tail, - - TP_PROTO(journal_t *journal, tid_t first_tid, - unsigned long block_nr, unsigned long freed), - - TP_ARGS(journal, first_tid, block_nr, freed), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( tid_t, tail_sequence ) - __field( tid_t, first_tid ) - __field(unsigned long, block_nr ) - __field(unsigned long, freed ) - ), - - TP_fast_assign( - __entry->dev = journal->j_fs_dev->bd_dev; - __entry->tail_sequence = journal->j_tail_sequence; - __entry->first_tid = first_tid; - __entry->block_nr = block_nr; - __entry->freed = freed; - ), - - TP_printk("dev %d,%d from %u to %u offset %lu freed %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->tail_sequence, __entry->first_tid, - __entry->block_nr, __entry->freed) -); - -TRACE_EVENT(jbd2_write_superblock, - - TP_PROTO(journal_t *journal, int write_op), - - TP_ARGS(journal, write_op), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( int, write_op ) - ), - - TP_fast_assign( - __entry->dev = journal->j_fs_dev->bd_dev; - __entry->write_op = write_op; - ), - - TP_printk("dev %d,%d write_op %x", MAJOR(__entry->dev), - MINOR(__entry->dev), __entry->write_op) -); - -TRACE_EVENT(jbd2_lock_buffer_stall, - - TP_PROTO(dev_t dev, unsigned long stall_ms), - - TP_ARGS(dev, stall_ms), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field(unsigned long, stall_ms ) - ), - - TP_fast_assign( - __entry->dev = dev; - __entry->stall_ms = stall_ms; - ), - - TP_printk("dev %d,%d stall_ms %lu", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->stall_ms) -); - -#endif /* _TRACE_JBD2_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/kmem.h b/src/linux/include/trace/events/kmem.h deleted file mode 100644 index 6b2e154..0000000 --- a/src/linux/include/trace/events/kmem.h +++ /dev/null @@ -1,323 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM kmem - -#if !defined(_TRACE_KMEM_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_KMEM_H - -#include -#include -#include - -DECLARE_EVENT_CLASS(kmem_alloc, - - TP_PROTO(unsigned long call_site, - const void *ptr, - size_t bytes_req, - size_t bytes_alloc, - gfp_t gfp_flags), - - TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags), - - TP_STRUCT__entry( - __field( unsigned long, call_site ) - __field( const void *, ptr ) - __field( size_t, bytes_req ) - __field( size_t, bytes_alloc ) - __field( gfp_t, gfp_flags ) - ), - - TP_fast_assign( - __entry->call_site = call_site; - __entry->ptr = ptr; - __entry->bytes_req = bytes_req; - __entry->bytes_alloc = bytes_alloc; - __entry->gfp_flags = gfp_flags; - ), - - TP_printk("call_site=%lx ptr=%p bytes_req=%zu bytes_alloc=%zu gfp_flags=%s", - __entry->call_site, - __entry->ptr, - __entry->bytes_req, - __entry->bytes_alloc, - show_gfp_flags(__entry->gfp_flags)) -); - -DEFINE_EVENT(kmem_alloc, kmalloc, - - TP_PROTO(unsigned long call_site, const void *ptr, - size_t bytes_req, size_t bytes_alloc, gfp_t gfp_flags), - - TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags) -); - -DEFINE_EVENT(kmem_alloc, kmem_cache_alloc, - - TP_PROTO(unsigned long call_site, const void *ptr, - size_t bytes_req, size_t bytes_alloc, gfp_t gfp_flags), - - TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags) -); - -DECLARE_EVENT_CLASS(kmem_alloc_node, - - TP_PROTO(unsigned long call_site, - const void *ptr, - size_t bytes_req, - size_t bytes_alloc, - gfp_t gfp_flags, - int node), - - TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags, node), - - TP_STRUCT__entry( - __field( unsigned long, call_site ) - __field( const void *, ptr ) - __field( size_t, bytes_req ) - __field( size_t, bytes_alloc ) - __field( gfp_t, gfp_flags ) - __field( int, node ) - ), - - TP_fast_assign( - __entry->call_site = call_site; - __entry->ptr = ptr; - __entry->bytes_req = bytes_req; - __entry->bytes_alloc = bytes_alloc; - __entry->gfp_flags = gfp_flags; - __entry->node = node; - ), - - TP_printk("call_site=%lx ptr=%p bytes_req=%zu bytes_alloc=%zu gfp_flags=%s node=%d", - __entry->call_site, - __entry->ptr, - __entry->bytes_req, - __entry->bytes_alloc, - show_gfp_flags(__entry->gfp_flags), - __entry->node) -); - -DEFINE_EVENT(kmem_alloc_node, kmalloc_node, - - TP_PROTO(unsigned long call_site, const void *ptr, - size_t bytes_req, size_t bytes_alloc, - gfp_t gfp_flags, int node), - - TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags, node) -); - -DEFINE_EVENT(kmem_alloc_node, kmem_cache_alloc_node, - - TP_PROTO(unsigned long call_site, const void *ptr, - size_t bytes_req, size_t bytes_alloc, - gfp_t gfp_flags, int node), - - TP_ARGS(call_site, ptr, bytes_req, bytes_alloc, gfp_flags, node) -); - -DECLARE_EVENT_CLASS(kmem_free, - - TP_PROTO(unsigned long call_site, const void *ptr), - - TP_ARGS(call_site, ptr), - - TP_STRUCT__entry( - __field( unsigned long, call_site ) - __field( const void *, ptr ) - ), - - TP_fast_assign( - __entry->call_site = call_site; - __entry->ptr = ptr; - ), - - TP_printk("call_site=%lx ptr=%p", __entry->call_site, __entry->ptr) -); - -DEFINE_EVENT(kmem_free, kfree, - - TP_PROTO(unsigned long call_site, const void *ptr), - - TP_ARGS(call_site, ptr) -); - -DEFINE_EVENT(kmem_free, kmem_cache_free, - - TP_PROTO(unsigned long call_site, const void *ptr), - - TP_ARGS(call_site, ptr) -); - -TRACE_EVENT(mm_page_free, - - TP_PROTO(struct page *page, unsigned int order), - - TP_ARGS(page, order), - - TP_STRUCT__entry( - __field( unsigned long, pfn ) - __field( unsigned int, order ) - ), - - TP_fast_assign( - __entry->pfn = page_to_pfn(page); - __entry->order = order; - ), - - TP_printk("page=%p pfn=%lu order=%d", - pfn_to_page(__entry->pfn), - __entry->pfn, - __entry->order) -); - -TRACE_EVENT(mm_page_free_batched, - - TP_PROTO(struct page *page, int cold), - - TP_ARGS(page, cold), - - TP_STRUCT__entry( - __field( unsigned long, pfn ) - __field( int, cold ) - ), - - TP_fast_assign( - __entry->pfn = page_to_pfn(page); - __entry->cold = cold; - ), - - TP_printk("page=%p pfn=%lu order=0 cold=%d", - pfn_to_page(__entry->pfn), - __entry->pfn, - __entry->cold) -); - -TRACE_EVENT(mm_page_alloc, - - TP_PROTO(struct page *page, unsigned int order, - gfp_t gfp_flags, int migratetype), - - TP_ARGS(page, order, gfp_flags, migratetype), - - TP_STRUCT__entry( - __field( unsigned long, pfn ) - __field( unsigned int, order ) - __field( gfp_t, gfp_flags ) - __field( int, migratetype ) - ), - - TP_fast_assign( - __entry->pfn = page ? page_to_pfn(page) : -1UL; - __entry->order = order; - __entry->gfp_flags = gfp_flags; - __entry->migratetype = migratetype; - ), - - TP_printk("page=%p pfn=%lu order=%d migratetype=%d gfp_flags=%s", - __entry->pfn != -1UL ? pfn_to_page(__entry->pfn) : NULL, - __entry->pfn != -1UL ? __entry->pfn : 0, - __entry->order, - __entry->migratetype, - show_gfp_flags(__entry->gfp_flags)) -); - -DECLARE_EVENT_CLASS(mm_page, - - TP_PROTO(struct page *page, unsigned int order, int migratetype), - - TP_ARGS(page, order, migratetype), - - TP_STRUCT__entry( - __field( unsigned long, pfn ) - __field( unsigned int, order ) - __field( int, migratetype ) - ), - - TP_fast_assign( - __entry->pfn = page ? page_to_pfn(page) : -1UL; - __entry->order = order; - __entry->migratetype = migratetype; - ), - - TP_printk("page=%p pfn=%lu order=%u migratetype=%d percpu_refill=%d", - __entry->pfn != -1UL ? pfn_to_page(__entry->pfn) : NULL, - __entry->pfn != -1UL ? __entry->pfn : 0, - __entry->order, - __entry->migratetype, - __entry->order == 0) -); - -DEFINE_EVENT(mm_page, mm_page_alloc_zone_locked, - - TP_PROTO(struct page *page, unsigned int order, int migratetype), - - TP_ARGS(page, order, migratetype) -); - -TRACE_EVENT(mm_page_pcpu_drain, - - TP_PROTO(struct page *page, unsigned int order, int migratetype), - - TP_ARGS(page, order, migratetype), - - TP_STRUCT__entry( - __field( unsigned long, pfn ) - __field( unsigned int, order ) - __field( int, migratetype ) - ), - - TP_fast_assign( - __entry->pfn = page ? page_to_pfn(page) : -1UL; - __entry->order = order; - __entry->migratetype = migratetype; - ), - - TP_printk("page=%p pfn=%lu order=%d migratetype=%d", - pfn_to_page(__entry->pfn), __entry->pfn, - __entry->order, __entry->migratetype) -); - -TRACE_EVENT(mm_page_alloc_extfrag, - - TP_PROTO(struct page *page, - int alloc_order, int fallback_order, - int alloc_migratetype, int fallback_migratetype), - - TP_ARGS(page, - alloc_order, fallback_order, - alloc_migratetype, fallback_migratetype), - - TP_STRUCT__entry( - __field( unsigned long, pfn ) - __field( int, alloc_order ) - __field( int, fallback_order ) - __field( int, alloc_migratetype ) - __field( int, fallback_migratetype ) - __field( int, change_ownership ) - ), - - TP_fast_assign( - __entry->pfn = page_to_pfn(page); - __entry->alloc_order = alloc_order; - __entry->fallback_order = fallback_order; - __entry->alloc_migratetype = alloc_migratetype; - __entry->fallback_migratetype = fallback_migratetype; - __entry->change_ownership = (alloc_migratetype == - get_pageblock_migratetype(page)); - ), - - TP_printk("page=%p pfn=%lu alloc_order=%d fallback_order=%d pageblock_order=%d alloc_migratetype=%d fallback_migratetype=%d fragmenting=%d change_ownership=%d", - pfn_to_page(__entry->pfn), - __entry->pfn, - __entry->alloc_order, - __entry->fallback_order, - pageblock_order, - __entry->alloc_migratetype, - __entry->fallback_migratetype, - __entry->fallback_order < pageblock_order, - __entry->change_ownership) -); - -#endif /* _TRACE_KMEM_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/mmflags.h b/src/linux/include/trace/events/mmflags.h deleted file mode 100644 index 5a81ab4..0000000 --- a/src/linux/include/trace/events/mmflags.h +++ /dev/null @@ -1,174 +0,0 @@ -/* - * The order of these masks is important. Matching masks will be seen - * first and the left over flags will end up showing by themselves. - * - * For example, if we have GFP_KERNEL before GFP_USER we wil get: - * - * GFP_KERNEL|GFP_HARDWALL - * - * Thus most bits set go first. - */ - -#define __def_gfpflag_names \ - {(unsigned long)GFP_TRANSHUGE, "GFP_TRANSHUGE"}, \ - {(unsigned long)GFP_TRANSHUGE_LIGHT, "GFP_TRANSHUGE_LIGHT"}, \ - {(unsigned long)GFP_HIGHUSER_MOVABLE, "GFP_HIGHUSER_MOVABLE"},\ - {(unsigned long)GFP_HIGHUSER, "GFP_HIGHUSER"}, \ - {(unsigned long)GFP_USER, "GFP_USER"}, \ - {(unsigned long)GFP_TEMPORARY, "GFP_TEMPORARY"}, \ - {(unsigned long)GFP_KERNEL_ACCOUNT, "GFP_KERNEL_ACCOUNT"}, \ - {(unsigned long)GFP_KERNEL, "GFP_KERNEL"}, \ - {(unsigned long)GFP_NOFS, "GFP_NOFS"}, \ - {(unsigned long)GFP_ATOMIC, "GFP_ATOMIC"}, \ - {(unsigned long)GFP_NOIO, "GFP_NOIO"}, \ - {(unsigned long)GFP_NOWAIT, "GFP_NOWAIT"}, \ - {(unsigned long)GFP_DMA, "GFP_DMA"}, \ - {(unsigned long)__GFP_HIGHMEM, "__GFP_HIGHMEM"}, \ - {(unsigned long)GFP_DMA32, "GFP_DMA32"}, \ - {(unsigned long)__GFP_HIGH, "__GFP_HIGH"}, \ - {(unsigned long)__GFP_ATOMIC, "__GFP_ATOMIC"}, \ - {(unsigned long)__GFP_IO, "__GFP_IO"}, \ - {(unsigned long)__GFP_FS, "__GFP_FS"}, \ - {(unsigned long)__GFP_COLD, "__GFP_COLD"}, \ - {(unsigned long)__GFP_NOWARN, "__GFP_NOWARN"}, \ - {(unsigned long)__GFP_REPEAT, "__GFP_REPEAT"}, \ - {(unsigned long)__GFP_NOFAIL, "__GFP_NOFAIL"}, \ - {(unsigned long)__GFP_NORETRY, "__GFP_NORETRY"}, \ - {(unsigned long)__GFP_COMP, "__GFP_COMP"}, \ - {(unsigned long)__GFP_ZERO, "__GFP_ZERO"}, \ - {(unsigned long)__GFP_NOMEMALLOC, "__GFP_NOMEMALLOC"}, \ - {(unsigned long)__GFP_MEMALLOC, "__GFP_MEMALLOC"}, \ - {(unsigned long)__GFP_HARDWALL, "__GFP_HARDWALL"}, \ - {(unsigned long)__GFP_THISNODE, "__GFP_THISNODE"}, \ - {(unsigned long)__GFP_RECLAIMABLE, "__GFP_RECLAIMABLE"}, \ - {(unsigned long)__GFP_MOVABLE, "__GFP_MOVABLE"}, \ - {(unsigned long)__GFP_ACCOUNT, "__GFP_ACCOUNT"}, \ - {(unsigned long)__GFP_NOTRACK, "__GFP_NOTRACK"}, \ - {(unsigned long)__GFP_WRITE, "__GFP_WRITE"}, \ - {(unsigned long)__GFP_RECLAIM, "__GFP_RECLAIM"}, \ - {(unsigned long)__GFP_DIRECT_RECLAIM, "__GFP_DIRECT_RECLAIM"},\ - {(unsigned long)__GFP_KSWAPD_RECLAIM, "__GFP_KSWAPD_RECLAIM"},\ - {(unsigned long)__GFP_OTHER_NODE, "__GFP_OTHER_NODE"} \ - -#define show_gfp_flags(flags) \ - (flags) ? __print_flags(flags, "|", \ - __def_gfpflag_names \ - ) : "none" - -#ifdef CONFIG_MMU -#define IF_HAVE_PG_MLOCK(flag,string) ,{1UL << flag, string} -#else -#define IF_HAVE_PG_MLOCK(flag,string) -#endif - -#ifdef CONFIG_ARCH_USES_PG_UNCACHED -#define IF_HAVE_PG_UNCACHED(flag,string) ,{1UL << flag, string} -#else -#define IF_HAVE_PG_UNCACHED(flag,string) -#endif - -#ifdef CONFIG_MEMORY_FAILURE -#define IF_HAVE_PG_HWPOISON(flag,string) ,{1UL << flag, string} -#else -#define IF_HAVE_PG_HWPOISON(flag,string) -#endif - -#if defined(CONFIG_IDLE_PAGE_TRACKING) && defined(CONFIG_64BIT) -#define IF_HAVE_PG_IDLE(flag,string) ,{1UL << flag, string} -#else -#define IF_HAVE_PG_IDLE(flag,string) -#endif - -#define __def_pageflag_names \ - {1UL << PG_locked, "locked" }, \ - {1UL << PG_error, "error" }, \ - {1UL << PG_referenced, "referenced" }, \ - {1UL << PG_uptodate, "uptodate" }, \ - {1UL << PG_dirty, "dirty" }, \ - {1UL << PG_lru, "lru" }, \ - {1UL << PG_active, "active" }, \ - {1UL << PG_slab, "slab" }, \ - {1UL << PG_owner_priv_1, "owner_priv_1" }, \ - {1UL << PG_arch_1, "arch_1" }, \ - {1UL << PG_reserved, "reserved" }, \ - {1UL << PG_private, "private" }, \ - {1UL << PG_private_2, "private_2" }, \ - {1UL << PG_writeback, "writeback" }, \ - {1UL << PG_head, "head" }, \ - {1UL << PG_swapcache, "swapcache" }, \ - {1UL << PG_mappedtodisk, "mappedtodisk" }, \ - {1UL << PG_reclaim, "reclaim" }, \ - {1UL << PG_swapbacked, "swapbacked" }, \ - {1UL << PG_unevictable, "unevictable" } \ -IF_HAVE_PG_MLOCK(PG_mlocked, "mlocked" ) \ -IF_HAVE_PG_UNCACHED(PG_uncached, "uncached" ) \ -IF_HAVE_PG_HWPOISON(PG_hwpoison, "hwpoison" ) \ -IF_HAVE_PG_IDLE(PG_young, "young" ) \ -IF_HAVE_PG_IDLE(PG_idle, "idle" ) - -#define show_page_flags(flags) \ - (flags) ? __print_flags(flags, "|", \ - __def_pageflag_names \ - ) : "none" - -#if defined(CONFIG_X86) -#define __VM_ARCH_SPECIFIC_1 {VM_PAT, "pat" } -#elif defined(CONFIG_PPC) -#define __VM_ARCH_SPECIFIC_1 {VM_SAO, "sao" } -#elif defined(CONFIG_PARISC) || defined(CONFIG_METAG) || defined(CONFIG_IA64) -#define __VM_ARCH_SPECIFIC_1 {VM_GROWSUP, "growsup" } -#elif !defined(CONFIG_MMU) -#define __VM_ARCH_SPECIFIC_1 {VM_MAPPED_COPY,"mappedcopy" } -#else -#define __VM_ARCH_SPECIFIC_1 {VM_ARCH_1, "arch_1" } -#endif - -#if defined(CONFIG_X86) -#define __VM_ARCH_SPECIFIC_2 {VM_MPX, "mpx" } -#else -#define __VM_ARCH_SPECIFIC_2 {VM_ARCH_2, "arch_2" } -#endif - -#ifdef CONFIG_MEM_SOFT_DIRTY -#define IF_HAVE_VM_SOFTDIRTY(flag,name) {flag, name }, -#else -#define IF_HAVE_VM_SOFTDIRTY(flag,name) -#endif - -#define __def_vmaflag_names \ - {VM_READ, "read" }, \ - {VM_WRITE, "write" }, \ - {VM_EXEC, "exec" }, \ - {VM_SHARED, "shared" }, \ - {VM_MAYREAD, "mayread" }, \ - {VM_MAYWRITE, "maywrite" }, \ - {VM_MAYEXEC, "mayexec" }, \ - {VM_MAYSHARE, "mayshare" }, \ - {VM_GROWSDOWN, "growsdown" }, \ - {VM_UFFD_MISSING, "uffd_missing" }, \ - {VM_PFNMAP, "pfnmap" }, \ - {VM_DENYWRITE, "denywrite" }, \ - {VM_UFFD_WP, "uffd_wp" }, \ - {VM_LOCKED, "locked" }, \ - {VM_IO, "io" }, \ - {VM_SEQ_READ, "seqread" }, \ - {VM_RAND_READ, "randread" }, \ - {VM_DONTCOPY, "dontcopy" }, \ - {VM_DONTEXPAND, "dontexpand" }, \ - {VM_LOCKONFAULT, "lockonfault" }, \ - {VM_ACCOUNT, "account" }, \ - {VM_NORESERVE, "noreserve" }, \ - {VM_HUGETLB, "hugetlb" }, \ - __VM_ARCH_SPECIFIC_1 , \ - __VM_ARCH_SPECIFIC_2 , \ - {VM_DONTDUMP, "dontdump" }, \ -IF_HAVE_VM_SOFTDIRTY(VM_SOFTDIRTY, "softdirty" ) \ - {VM_MIXEDMAP, "mixedmap" }, \ - {VM_HUGEPAGE, "hugepage" }, \ - {VM_NOHUGEPAGE, "nohugepage" }, \ - {VM_MERGEABLE, "mergeable" } \ - -#define show_vma_flags(flags) \ - (flags) ? __print_flags(flags, "|", \ - __def_vmaflag_names \ - ) : "none" diff --git a/src/linux/include/trace/events/module.h b/src/linux/include/trace/events/module.h deleted file mode 100644 index 28c4599..0000000 --- a/src/linux/include/trace/events/module.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Because linux/module.h has tracepoints in the header, and ftrace.h - * used to include this file, define_trace.h includes linux/module.h - * But we do not want the module.h to override the TRACE_SYSTEM macro - * variable that define_trace.h is processing, so we only set it - * when module events are being processed, which would happen when - * CREATE_TRACE_POINTS is defined. - */ -#ifdef CREATE_TRACE_POINTS -#undef TRACE_SYSTEM -#define TRACE_SYSTEM module -#endif - -#if !defined(_TRACE_MODULE_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_MODULE_H - -#include - -#ifdef CONFIG_MODULES - -struct module; - -#define show_module_flags(flags) __print_flags(flags, "", \ - { (1UL << TAINT_PROPRIETARY_MODULE), "P" }, \ - { (1UL << TAINT_OOT_MODULE), "O" }, \ - { (1UL << TAINT_FORCED_MODULE), "F" }, \ - { (1UL << TAINT_CRAP), "C" }, \ - { (1UL << TAINT_UNSIGNED_MODULE), "E" }) - -TRACE_EVENT(module_load, - - TP_PROTO(struct module *mod), - - TP_ARGS(mod), - - TP_STRUCT__entry( - __field( unsigned int, taints ) - __string( name, mod->name ) - ), - - TP_fast_assign( - __entry->taints = mod->taints; - __assign_str(name, mod->name); - ), - - TP_printk("%s %s", __get_str(name), show_module_flags(__entry->taints)) -); - -TRACE_EVENT(module_free, - - TP_PROTO(struct module *mod), - - TP_ARGS(mod), - - TP_STRUCT__entry( - __string( name, mod->name ) - ), - - TP_fast_assign( - __assign_str(name, mod->name); - ), - - TP_printk("%s", __get_str(name)) -); - -#ifdef CONFIG_MODULE_UNLOAD -/* trace_module_get/put are only used if CONFIG_MODULE_UNLOAD is defined */ - -DECLARE_EVENT_CLASS(module_refcnt, - - TP_PROTO(struct module *mod, unsigned long ip), - - TP_ARGS(mod, ip), - - TP_STRUCT__entry( - __field( unsigned long, ip ) - __field( int, refcnt ) - __string( name, mod->name ) - ), - - TP_fast_assign( - __entry->ip = ip; - __entry->refcnt = atomic_read(&mod->refcnt); - __assign_str(name, mod->name); - ), - - TP_printk("%s call_site=%ps refcnt=%d", - __get_str(name), (void *)__entry->ip, __entry->refcnt) -); - -DEFINE_EVENT(module_refcnt, module_get, - - TP_PROTO(struct module *mod, unsigned long ip), - - TP_ARGS(mod, ip) -); - -DEFINE_EVENT(module_refcnt, module_put, - - TP_PROTO(struct module *mod, unsigned long ip), - - TP_ARGS(mod, ip) -); -#endif /* CONFIG_MODULE_UNLOAD */ - -TRACE_EVENT(module_request, - - TP_PROTO(char *name, bool wait, unsigned long ip), - - TP_ARGS(name, wait, ip), - - TP_STRUCT__entry( - __field( unsigned long, ip ) - __field( bool, wait ) - __string( name, name ) - ), - - TP_fast_assign( - __entry->ip = ip; - __entry->wait = wait; - __assign_str(name, name); - ), - - TP_printk("%s wait=%d call_site=%ps", - __get_str(name), (int)__entry->wait, (void *)__entry->ip) -); - -#endif /* CONFIG_MODULES */ - -#endif /* _TRACE_MODULE_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/napi.h b/src/linux/include/trace/events/napi.h deleted file mode 100644 index 0b9e513..0000000 --- a/src/linux/include/trace/events/napi.h +++ /dev/null @@ -1,43 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM napi - -#if !defined(_TRACE_NAPI_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_NAPI_H_ - -#include -#include -#include - -#define NO_DEV "(no_device)" - -TRACE_EVENT(napi_poll, - - TP_PROTO(struct napi_struct *napi, int work, int budget), - - TP_ARGS(napi, work, budget), - - TP_STRUCT__entry( - __field( struct napi_struct *, napi) - __string( dev_name, napi->dev ? napi->dev->name : NO_DEV) - __field( int, work) - __field( int, budget) - ), - - TP_fast_assign( - __entry->napi = napi; - __assign_str(dev_name, napi->dev ? napi->dev->name : NO_DEV); - __entry->work = work; - __entry->budget = budget; - ), - - TP_printk("napi poll on napi struct %p for device %s work %d budget %d", - __entry->napi, __get_str(dev_name), - __entry->work, __entry->budget) -); - -#undef NO_DEV - -#endif /* _TRACE_NAPI_H_ */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/net.h b/src/linux/include/trace/events/net.h deleted file mode 100644 index 49cc7c3..0000000 --- a/src/linux/include/trace/events/net.h +++ /dev/null @@ -1,242 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM net - -#if !defined(_TRACE_NET_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_NET_H - -#include -#include -#include -#include -#include - -TRACE_EVENT(net_dev_start_xmit, - - TP_PROTO(const struct sk_buff *skb, const struct net_device *dev), - - TP_ARGS(skb, dev), - - TP_STRUCT__entry( - __string( name, dev->name ) - __field( u16, queue_mapping ) - __field( const void *, skbaddr ) - __field( bool, vlan_tagged ) - __field( u16, vlan_proto ) - __field( u16, vlan_tci ) - __field( u16, protocol ) - __field( u8, ip_summed ) - __field( unsigned int, len ) - __field( unsigned int, data_len ) - __field( int, network_offset ) - __field( bool, transport_offset_valid) - __field( int, transport_offset) - __field( u8, tx_flags ) - __field( u16, gso_size ) - __field( u16, gso_segs ) - __field( u16, gso_type ) - ), - - TP_fast_assign( - __assign_str(name, dev->name); - __entry->queue_mapping = skb->queue_mapping; - __entry->skbaddr = skb; - __entry->vlan_tagged = skb_vlan_tag_present(skb); - __entry->vlan_proto = ntohs(skb->vlan_proto); - __entry->vlan_tci = skb_vlan_tag_get(skb); - __entry->protocol = ntohs(skb->protocol); - __entry->ip_summed = skb->ip_summed; - __entry->len = skb->len; - __entry->data_len = skb->data_len; - __entry->network_offset = skb_network_offset(skb); - __entry->transport_offset_valid = - skb_transport_header_was_set(skb); - __entry->transport_offset = skb_transport_offset(skb); - __entry->tx_flags = skb_shinfo(skb)->tx_flags; - __entry->gso_size = skb_shinfo(skb)->gso_size; - __entry->gso_segs = skb_shinfo(skb)->gso_segs; - __entry->gso_type = skb_shinfo(skb)->gso_type; - ), - - TP_printk("dev=%s queue_mapping=%u skbaddr=%p vlan_tagged=%d vlan_proto=0x%04x vlan_tci=0x%04x protocol=0x%04x ip_summed=%d len=%u data_len=%u network_offset=%d transport_offset_valid=%d transport_offset=%d tx_flags=%d gso_size=%d gso_segs=%d gso_type=%#x", - __get_str(name), __entry->queue_mapping, __entry->skbaddr, - __entry->vlan_tagged, __entry->vlan_proto, __entry->vlan_tci, - __entry->protocol, __entry->ip_summed, __entry->len, - __entry->data_len, - __entry->network_offset, __entry->transport_offset_valid, - __entry->transport_offset, __entry->tx_flags, - __entry->gso_size, __entry->gso_segs, __entry->gso_type) -); - -TRACE_EVENT(net_dev_xmit, - - TP_PROTO(struct sk_buff *skb, - int rc, - struct net_device *dev, - unsigned int skb_len), - - TP_ARGS(skb, rc, dev, skb_len), - - TP_STRUCT__entry( - __field( void *, skbaddr ) - __field( unsigned int, len ) - __field( int, rc ) - __string( name, dev->name ) - ), - - TP_fast_assign( - __entry->skbaddr = skb; - __entry->len = skb_len; - __entry->rc = rc; - __assign_str(name, dev->name); - ), - - TP_printk("dev=%s skbaddr=%p len=%u rc=%d", - __get_str(name), __entry->skbaddr, __entry->len, __entry->rc) -); - -DECLARE_EVENT_CLASS(net_dev_template, - - TP_PROTO(struct sk_buff *skb), - - TP_ARGS(skb), - - TP_STRUCT__entry( - __field( void *, skbaddr ) - __field( unsigned int, len ) - __string( name, skb->dev->name ) - ), - - TP_fast_assign( - __entry->skbaddr = skb; - __entry->len = skb->len; - __assign_str(name, skb->dev->name); - ), - - TP_printk("dev=%s skbaddr=%p len=%u", - __get_str(name), __entry->skbaddr, __entry->len) -) - -DEFINE_EVENT(net_dev_template, net_dev_queue, - - TP_PROTO(struct sk_buff *skb), - - TP_ARGS(skb) -); - -DEFINE_EVENT(net_dev_template, netif_receive_skb, - - TP_PROTO(struct sk_buff *skb), - - TP_ARGS(skb) -); - -DEFINE_EVENT(net_dev_template, netif_rx, - - TP_PROTO(struct sk_buff *skb), - - TP_ARGS(skb) -); - -DECLARE_EVENT_CLASS(net_dev_rx_verbose_template, - - TP_PROTO(const struct sk_buff *skb), - - TP_ARGS(skb), - - TP_STRUCT__entry( - __string( name, skb->dev->name ) - __field( unsigned int, napi_id ) - __field( u16, queue_mapping ) - __field( const void *, skbaddr ) - __field( bool, vlan_tagged ) - __field( u16, vlan_proto ) - __field( u16, vlan_tci ) - __field( u16, protocol ) - __field( u8, ip_summed ) - __field( u32, hash ) - __field( bool, l4_hash ) - __field( unsigned int, len ) - __field( unsigned int, data_len ) - __field( unsigned int, truesize ) - __field( bool, mac_header_valid) - __field( int, mac_header ) - __field( unsigned char, nr_frags ) - __field( u16, gso_size ) - __field( u16, gso_type ) - ), - - TP_fast_assign( - __assign_str(name, skb->dev->name); -#ifdef CONFIG_NET_RX_BUSY_POLL - __entry->napi_id = skb->napi_id; -#else - __entry->napi_id = 0; -#endif - __entry->queue_mapping = skb->queue_mapping; - __entry->skbaddr = skb; - __entry->vlan_tagged = skb_vlan_tag_present(skb); - __entry->vlan_proto = ntohs(skb->vlan_proto); - __entry->vlan_tci = skb_vlan_tag_get(skb); - __entry->protocol = ntohs(skb->protocol); - __entry->ip_summed = skb->ip_summed; - __entry->hash = skb->hash; - __entry->l4_hash = skb->l4_hash; - __entry->len = skb->len; - __entry->data_len = skb->data_len; - __entry->truesize = skb->truesize; - __entry->mac_header_valid = skb_mac_header_was_set(skb); - __entry->mac_header = skb_mac_header(skb) - skb->data; - __entry->nr_frags = skb_shinfo(skb)->nr_frags; - __entry->gso_size = skb_shinfo(skb)->gso_size; - __entry->gso_type = skb_shinfo(skb)->gso_type; - ), - - TP_printk("dev=%s napi_id=%#x queue_mapping=%u skbaddr=%p vlan_tagged=%d vlan_proto=0x%04x vlan_tci=0x%04x protocol=0x%04x ip_summed=%d hash=0x%08x l4_hash=%d len=%u data_len=%u truesize=%u mac_header_valid=%d mac_header=%d nr_frags=%d gso_size=%d gso_type=%#x", - __get_str(name), __entry->napi_id, __entry->queue_mapping, - __entry->skbaddr, __entry->vlan_tagged, __entry->vlan_proto, - __entry->vlan_tci, __entry->protocol, __entry->ip_summed, - __entry->hash, __entry->l4_hash, __entry->len, - __entry->data_len, __entry->truesize, - __entry->mac_header_valid, __entry->mac_header, - __entry->nr_frags, __entry->gso_size, __entry->gso_type) -); - -DEFINE_EVENT(net_dev_rx_verbose_template, napi_gro_frags_entry, - - TP_PROTO(const struct sk_buff *skb), - - TP_ARGS(skb) -); - -DEFINE_EVENT(net_dev_rx_verbose_template, napi_gro_receive_entry, - - TP_PROTO(const struct sk_buff *skb), - - TP_ARGS(skb) -); - -DEFINE_EVENT(net_dev_rx_verbose_template, netif_receive_skb_entry, - - TP_PROTO(const struct sk_buff *skb), - - TP_ARGS(skb) -); - -DEFINE_EVENT(net_dev_rx_verbose_template, netif_rx_entry, - - TP_PROTO(const struct sk_buff *skb), - - TP_ARGS(skb) -); - -DEFINE_EVENT(net_dev_rx_verbose_template, netif_rx_ni_entry, - - TP_PROTO(const struct sk_buff *skb), - - TP_ARGS(skb) -); - -#endif /* _TRACE_NET_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/oom.h b/src/linux/include/trace/events/oom.h deleted file mode 100644 index 1e97498..0000000 --- a/src/linux/include/trace/events/oom.h +++ /dev/null @@ -1,33 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM oom - -#if !defined(_TRACE_OOM_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_OOM_H -#include - -TRACE_EVENT(oom_score_adj_update, - - TP_PROTO(struct task_struct *task), - - TP_ARGS(task), - - TP_STRUCT__entry( - __field( pid_t, pid) - __array( char, comm, TASK_COMM_LEN ) - __field( short, oom_score_adj) - ), - - TP_fast_assign( - __entry->pid = task->pid; - memcpy(__entry->comm, task->comm, TASK_COMM_LEN); - __entry->oom_score_adj = task->signal->oom_score_adj; - ), - - TP_printk("pid=%d comm=%s oom_score_adj=%hd", - __entry->pid, __entry->comm, __entry->oom_score_adj) -); - -#endif - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/pagemap.h b/src/linux/include/trace/events/pagemap.h deleted file mode 100644 index ce0803b..0000000 --- a/src/linux/include/trace/events/pagemap.h +++ /dev/null @@ -1,87 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM pagemap - -#if !defined(_TRACE_PAGEMAP_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_PAGEMAP_H - -#include -#include - -#define PAGEMAP_MAPPED 0x0001u -#define PAGEMAP_ANONYMOUS 0x0002u -#define PAGEMAP_FILE 0x0004u -#define PAGEMAP_SWAPCACHE 0x0008u -#define PAGEMAP_SWAPBACKED 0x0010u -#define PAGEMAP_MAPPEDDISK 0x0020u -#define PAGEMAP_BUFFERS 0x0040u - -#define trace_pagemap_flags(page) ( \ - (PageAnon(page) ? PAGEMAP_ANONYMOUS : PAGEMAP_FILE) | \ - (page_mapped(page) ? PAGEMAP_MAPPED : 0) | \ - (PageSwapCache(page) ? PAGEMAP_SWAPCACHE : 0) | \ - (PageSwapBacked(page) ? PAGEMAP_SWAPBACKED : 0) | \ - (PageMappedToDisk(page) ? PAGEMAP_MAPPEDDISK : 0) | \ - (page_has_private(page) ? PAGEMAP_BUFFERS : 0) \ - ) - -TRACE_EVENT(mm_lru_insertion, - - TP_PROTO( - struct page *page, - int lru - ), - - TP_ARGS(page, lru), - - TP_STRUCT__entry( - __field(struct page *, page ) - __field(unsigned long, pfn ) - __field(int, lru ) - __field(unsigned long, flags ) - ), - - TP_fast_assign( - __entry->page = page; - __entry->pfn = page_to_pfn(page); - __entry->lru = lru; - __entry->flags = trace_pagemap_flags(page); - ), - - /* Flag format is based on page-types.c formatting for pagemap */ - TP_printk("page=%p pfn=%lu lru=%d flags=%s%s%s%s%s%s", - __entry->page, - __entry->pfn, - __entry->lru, - __entry->flags & PAGEMAP_MAPPED ? "M" : " ", - __entry->flags & PAGEMAP_ANONYMOUS ? "a" : "f", - __entry->flags & PAGEMAP_SWAPCACHE ? "s" : " ", - __entry->flags & PAGEMAP_SWAPBACKED ? "b" : " ", - __entry->flags & PAGEMAP_MAPPEDDISK ? "d" : " ", - __entry->flags & PAGEMAP_BUFFERS ? "B" : " ") -); - -TRACE_EVENT(mm_lru_activate, - - TP_PROTO(struct page *page), - - TP_ARGS(page), - - TP_STRUCT__entry( - __field(struct page *, page ) - __field(unsigned long, pfn ) - ), - - TP_fast_assign( - __entry->page = page; - __entry->pfn = page_to_pfn(page); - ), - - /* Flag format is based on page-types.c formatting for pagemap */ - TP_printk("page=%p pfn=%lu", __entry->page, __entry->pfn) - -); - -#endif /* _TRACE_PAGEMAP_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/power.h b/src/linux/include/trace/events/power.h deleted file mode 100644 index 54e3aad..0000000 --- a/src/linux/include/trace/events/power.h +++ /dev/null @@ -1,509 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM power - -#if !defined(_TRACE_POWER_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_POWER_H - -#include -#include -#include -#include - -#define TPS(x) tracepoint_string(x) - -DECLARE_EVENT_CLASS(cpu, - - TP_PROTO(unsigned int state, unsigned int cpu_id), - - TP_ARGS(state, cpu_id), - - TP_STRUCT__entry( - __field( u32, state ) - __field( u32, cpu_id ) - ), - - TP_fast_assign( - __entry->state = state; - __entry->cpu_id = cpu_id; - ), - - TP_printk("state=%lu cpu_id=%lu", (unsigned long)__entry->state, - (unsigned long)__entry->cpu_id) -); - -DEFINE_EVENT(cpu, cpu_idle, - - TP_PROTO(unsigned int state, unsigned int cpu_id), - - TP_ARGS(state, cpu_id) -); - -TRACE_EVENT(powernv_throttle, - - TP_PROTO(int chip_id, const char *reason, int pmax), - - TP_ARGS(chip_id, reason, pmax), - - TP_STRUCT__entry( - __field(int, chip_id) - __string(reason, reason) - __field(int, pmax) - ), - - TP_fast_assign( - __entry->chip_id = chip_id; - __assign_str(reason, reason); - __entry->pmax = pmax; - ), - - TP_printk("Chip %d Pmax %d %s", __entry->chip_id, - __entry->pmax, __get_str(reason)) -); - -TRACE_EVENT(pstate_sample, - - TP_PROTO(u32 core_busy, - u32 scaled_busy, - u32 from, - u32 to, - u64 mperf, - u64 aperf, - u64 tsc, - u32 freq, - u32 io_boost - ), - - TP_ARGS(core_busy, - scaled_busy, - from, - to, - mperf, - aperf, - tsc, - freq, - io_boost - ), - - TP_STRUCT__entry( - __field(u32, core_busy) - __field(u32, scaled_busy) - __field(u32, from) - __field(u32, to) - __field(u64, mperf) - __field(u64, aperf) - __field(u64, tsc) - __field(u32, freq) - __field(u32, io_boost) - ), - - TP_fast_assign( - __entry->core_busy = core_busy; - __entry->scaled_busy = scaled_busy; - __entry->from = from; - __entry->to = to; - __entry->mperf = mperf; - __entry->aperf = aperf; - __entry->tsc = tsc; - __entry->freq = freq; - __entry->io_boost = io_boost; - ), - - TP_printk("core_busy=%lu scaled=%lu from=%lu to=%lu mperf=%llu aperf=%llu tsc=%llu freq=%lu io_boost=%lu", - (unsigned long)__entry->core_busy, - (unsigned long)__entry->scaled_busy, - (unsigned long)__entry->from, - (unsigned long)__entry->to, - (unsigned long long)__entry->mperf, - (unsigned long long)__entry->aperf, - (unsigned long long)__entry->tsc, - (unsigned long)__entry->freq, - (unsigned long)__entry->io_boost - ) - -); - -/* This file can get included multiple times, TRACE_HEADER_MULTI_READ at top */ -#ifndef _PWR_EVENT_AVOID_DOUBLE_DEFINING -#define _PWR_EVENT_AVOID_DOUBLE_DEFINING - -#define PWR_EVENT_EXIT -1 -#endif - -#define pm_verb_symbolic(event) \ - __print_symbolic(event, \ - { PM_EVENT_SUSPEND, "suspend" }, \ - { PM_EVENT_RESUME, "resume" }, \ - { PM_EVENT_FREEZE, "freeze" }, \ - { PM_EVENT_QUIESCE, "quiesce" }, \ - { PM_EVENT_HIBERNATE, "hibernate" }, \ - { PM_EVENT_THAW, "thaw" }, \ - { PM_EVENT_RESTORE, "restore" }, \ - { PM_EVENT_RECOVER, "recover" }) - -DEFINE_EVENT(cpu, cpu_frequency, - - TP_PROTO(unsigned int frequency, unsigned int cpu_id), - - TP_ARGS(frequency, cpu_id) -); - -TRACE_EVENT(device_pm_callback_start, - - TP_PROTO(struct device *dev, const char *pm_ops, int event), - - TP_ARGS(dev, pm_ops, event), - - TP_STRUCT__entry( - __string(device, dev_name(dev)) - __string(driver, dev_driver_string(dev)) - __string(parent, dev->parent ? dev_name(dev->parent) : "none") - __string(pm_ops, pm_ops ? pm_ops : "none ") - __field(int, event) - ), - - TP_fast_assign( - __assign_str(device, dev_name(dev)); - __assign_str(driver, dev_driver_string(dev)); - __assign_str(parent, - dev->parent ? dev_name(dev->parent) : "none"); - __assign_str(pm_ops, pm_ops ? pm_ops : "none "); - __entry->event = event; - ), - - TP_printk("%s %s, parent: %s, %s[%s]", __get_str(driver), - __get_str(device), __get_str(parent), __get_str(pm_ops), - pm_verb_symbolic(__entry->event)) -); - -TRACE_EVENT(device_pm_callback_end, - - TP_PROTO(struct device *dev, int error), - - TP_ARGS(dev, error), - - TP_STRUCT__entry( - __string(device, dev_name(dev)) - __string(driver, dev_driver_string(dev)) - __field(int, error) - ), - - TP_fast_assign( - __assign_str(device, dev_name(dev)); - __assign_str(driver, dev_driver_string(dev)); - __entry->error = error; - ), - - TP_printk("%s %s, err=%d", - __get_str(driver), __get_str(device), __entry->error) -); - -TRACE_EVENT(suspend_resume, - - TP_PROTO(const char *action, int val, bool start), - - TP_ARGS(action, val, start), - - TP_STRUCT__entry( - __field(const char *, action) - __field(int, val) - __field(bool, start) - ), - - TP_fast_assign( - __entry->action = action; - __entry->val = val; - __entry->start = start; - ), - - TP_printk("%s[%u] %s", __entry->action, (unsigned int)__entry->val, - (__entry->start)?"begin":"end") -); - -DECLARE_EVENT_CLASS(wakeup_source, - - TP_PROTO(const char *name, unsigned int state), - - TP_ARGS(name, state), - - TP_STRUCT__entry( - __string( name, name ) - __field( u64, state ) - ), - - TP_fast_assign( - __assign_str(name, name); - __entry->state = state; - ), - - TP_printk("%s state=0x%lx", __get_str(name), - (unsigned long)__entry->state) -); - -DEFINE_EVENT(wakeup_source, wakeup_source_activate, - - TP_PROTO(const char *name, unsigned int state), - - TP_ARGS(name, state) -); - -DEFINE_EVENT(wakeup_source, wakeup_source_deactivate, - - TP_PROTO(const char *name, unsigned int state), - - TP_ARGS(name, state) -); - -/* - * The clock events are used for clock enable/disable and for - * clock rate change - */ -DECLARE_EVENT_CLASS(clock, - - TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id), - - TP_ARGS(name, state, cpu_id), - - TP_STRUCT__entry( - __string( name, name ) - __field( u64, state ) - __field( u64, cpu_id ) - ), - - TP_fast_assign( - __assign_str(name, name); - __entry->state = state; - __entry->cpu_id = cpu_id; - ), - - TP_printk("%s state=%lu cpu_id=%lu", __get_str(name), - (unsigned long)__entry->state, (unsigned long)__entry->cpu_id) -); - -DEFINE_EVENT(clock, clock_enable, - - TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id), - - TP_ARGS(name, state, cpu_id) -); - -DEFINE_EVENT(clock, clock_disable, - - TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id), - - TP_ARGS(name, state, cpu_id) -); - -DEFINE_EVENT(clock, clock_set_rate, - - TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id), - - TP_ARGS(name, state, cpu_id) -); - -/* - * The power domain events are used for power domains transitions - */ -DECLARE_EVENT_CLASS(power_domain, - - TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id), - - TP_ARGS(name, state, cpu_id), - - TP_STRUCT__entry( - __string( name, name ) - __field( u64, state ) - __field( u64, cpu_id ) - ), - - TP_fast_assign( - __assign_str(name, name); - __entry->state = state; - __entry->cpu_id = cpu_id; -), - - TP_printk("%s state=%lu cpu_id=%lu", __get_str(name), - (unsigned long)__entry->state, (unsigned long)__entry->cpu_id) -); - -DEFINE_EVENT(power_domain, power_domain_target, - - TP_PROTO(const char *name, unsigned int state, unsigned int cpu_id), - - TP_ARGS(name, state, cpu_id) -); - -/* - * The pm qos events are used for pm qos update - */ -DECLARE_EVENT_CLASS(pm_qos_request, - - TP_PROTO(int pm_qos_class, s32 value), - - TP_ARGS(pm_qos_class, value), - - TP_STRUCT__entry( - __field( int, pm_qos_class ) - __field( s32, value ) - ), - - TP_fast_assign( - __entry->pm_qos_class = pm_qos_class; - __entry->value = value; - ), - - TP_printk("pm_qos_class=%s value=%d", - __print_symbolic(__entry->pm_qos_class, - { PM_QOS_CPU_DMA_LATENCY, "CPU_DMA_LATENCY" }, - { PM_QOS_NETWORK_LATENCY, "NETWORK_LATENCY" }, - { PM_QOS_NETWORK_THROUGHPUT, "NETWORK_THROUGHPUT" }), - __entry->value) -); - -DEFINE_EVENT(pm_qos_request, pm_qos_add_request, - - TP_PROTO(int pm_qos_class, s32 value), - - TP_ARGS(pm_qos_class, value) -); - -DEFINE_EVENT(pm_qos_request, pm_qos_update_request, - - TP_PROTO(int pm_qos_class, s32 value), - - TP_ARGS(pm_qos_class, value) -); - -DEFINE_EVENT(pm_qos_request, pm_qos_remove_request, - - TP_PROTO(int pm_qos_class, s32 value), - - TP_ARGS(pm_qos_class, value) -); - -TRACE_EVENT(pm_qos_update_request_timeout, - - TP_PROTO(int pm_qos_class, s32 value, unsigned long timeout_us), - - TP_ARGS(pm_qos_class, value, timeout_us), - - TP_STRUCT__entry( - __field( int, pm_qos_class ) - __field( s32, value ) - __field( unsigned long, timeout_us ) - ), - - TP_fast_assign( - __entry->pm_qos_class = pm_qos_class; - __entry->value = value; - __entry->timeout_us = timeout_us; - ), - - TP_printk("pm_qos_class=%s value=%d, timeout_us=%ld", - __print_symbolic(__entry->pm_qos_class, - { PM_QOS_CPU_DMA_LATENCY, "CPU_DMA_LATENCY" }, - { PM_QOS_NETWORK_LATENCY, "NETWORK_LATENCY" }, - { PM_QOS_NETWORK_THROUGHPUT, "NETWORK_THROUGHPUT" }), - __entry->value, __entry->timeout_us) -); - -DECLARE_EVENT_CLASS(pm_qos_update, - - TP_PROTO(enum pm_qos_req_action action, int prev_value, int curr_value), - - TP_ARGS(action, prev_value, curr_value), - - TP_STRUCT__entry( - __field( enum pm_qos_req_action, action ) - __field( int, prev_value ) - __field( int, curr_value ) - ), - - TP_fast_assign( - __entry->action = action; - __entry->prev_value = prev_value; - __entry->curr_value = curr_value; - ), - - TP_printk("action=%s prev_value=%d curr_value=%d", - __print_symbolic(__entry->action, - { PM_QOS_ADD_REQ, "ADD_REQ" }, - { PM_QOS_UPDATE_REQ, "UPDATE_REQ" }, - { PM_QOS_REMOVE_REQ, "REMOVE_REQ" }), - __entry->prev_value, __entry->curr_value) -); - -DEFINE_EVENT(pm_qos_update, pm_qos_update_target, - - TP_PROTO(enum pm_qos_req_action action, int prev_value, int curr_value), - - TP_ARGS(action, prev_value, curr_value) -); - -DEFINE_EVENT_PRINT(pm_qos_update, pm_qos_update_flags, - - TP_PROTO(enum pm_qos_req_action action, int prev_value, int curr_value), - - TP_ARGS(action, prev_value, curr_value), - - TP_printk("action=%s prev_value=0x%x curr_value=0x%x", - __print_symbolic(__entry->action, - { PM_QOS_ADD_REQ, "ADD_REQ" }, - { PM_QOS_UPDATE_REQ, "UPDATE_REQ" }, - { PM_QOS_REMOVE_REQ, "REMOVE_REQ" }), - __entry->prev_value, __entry->curr_value) -); - -DECLARE_EVENT_CLASS(dev_pm_qos_request, - - TP_PROTO(const char *name, enum dev_pm_qos_req_type type, - s32 new_value), - - TP_ARGS(name, type, new_value), - - TP_STRUCT__entry( - __string( name, name ) - __field( enum dev_pm_qos_req_type, type ) - __field( s32, new_value ) - ), - - TP_fast_assign( - __assign_str(name, name); - __entry->type = type; - __entry->new_value = new_value; - ), - - TP_printk("device=%s type=%s new_value=%d", - __get_str(name), - __print_symbolic(__entry->type, - { DEV_PM_QOS_RESUME_LATENCY, "DEV_PM_QOS_RESUME_LATENCY" }, - { DEV_PM_QOS_FLAGS, "DEV_PM_QOS_FLAGS" }), - __entry->new_value) -); - -DEFINE_EVENT(dev_pm_qos_request, dev_pm_qos_add_request, - - TP_PROTO(const char *name, enum dev_pm_qos_req_type type, - s32 new_value), - - TP_ARGS(name, type, new_value) -); - -DEFINE_EVENT(dev_pm_qos_request, dev_pm_qos_update_request, - - TP_PROTO(const char *name, enum dev_pm_qos_req_type type, - s32 new_value), - - TP_ARGS(name, type, new_value) -); - -DEFINE_EVENT(dev_pm_qos_request, dev_pm_qos_remove_request, - - TP_PROTO(const char *name, enum dev_pm_qos_req_type type, - s32 new_value), - - TP_ARGS(name, type, new_value) -); -#endif /* _TRACE_POWER_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/printk.h b/src/linux/include/trace/events/printk.h deleted file mode 100644 index f350170..0000000 --- a/src/linux/include/trace/events/printk.h +++ /dev/null @@ -1,36 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM printk - -#if !defined(_TRACE_PRINTK_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_PRINTK_H - -#include - -TRACE_EVENT(console, - TP_PROTO(const char *text, size_t len), - - TP_ARGS(text, len), - - TP_STRUCT__entry( - __dynamic_array(char, msg, len + 1) - ), - - TP_fast_assign( - /* - * Each trace entry is printed in a new line. - * If the msg finishes with '\n', cut it off - * to avoid blank lines in the trace. - */ - if ((len > 0) && (text[len-1] == '\n')) - len -= 1; - - memcpy(__get_str(msg), text, len); - __get_str(msg)[len] = 0; - ), - - TP_printk("%s", __get_str(msg)) -); -#endif /* _TRACE_PRINTK_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/random.h b/src/linux/include/trace/events/random.h deleted file mode 100644 index 4684de3..0000000 --- a/src/linux/include/trace/events/random.h +++ /dev/null @@ -1,315 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM random - -#if !defined(_TRACE_RANDOM_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_RANDOM_H - -#include -#include - -TRACE_EVENT(add_device_randomness, - TP_PROTO(int bytes, unsigned long IP), - - TP_ARGS(bytes, IP), - - TP_STRUCT__entry( - __field( int, bytes ) - __field(unsigned long, IP ) - ), - - TP_fast_assign( - __entry->bytes = bytes; - __entry->IP = IP; - ), - - TP_printk("bytes %d caller %pS", - __entry->bytes, (void *)__entry->IP) -); - -DECLARE_EVENT_CLASS(random__mix_pool_bytes, - TP_PROTO(const char *pool_name, int bytes, unsigned long IP), - - TP_ARGS(pool_name, bytes, IP), - - TP_STRUCT__entry( - __field( const char *, pool_name ) - __field( int, bytes ) - __field(unsigned long, IP ) - ), - - TP_fast_assign( - __entry->pool_name = pool_name; - __entry->bytes = bytes; - __entry->IP = IP; - ), - - TP_printk("%s pool: bytes %d caller %pS", - __entry->pool_name, __entry->bytes, (void *)__entry->IP) -); - -DEFINE_EVENT(random__mix_pool_bytes, mix_pool_bytes, - TP_PROTO(const char *pool_name, int bytes, unsigned long IP), - - TP_ARGS(pool_name, bytes, IP) -); - -DEFINE_EVENT(random__mix_pool_bytes, mix_pool_bytes_nolock, - TP_PROTO(const char *pool_name, int bytes, unsigned long IP), - - TP_ARGS(pool_name, bytes, IP) -); - -TRACE_EVENT(credit_entropy_bits, - TP_PROTO(const char *pool_name, int bits, int entropy_count, - int entropy_total, unsigned long IP), - - TP_ARGS(pool_name, bits, entropy_count, entropy_total, IP), - - TP_STRUCT__entry( - __field( const char *, pool_name ) - __field( int, bits ) - __field( int, entropy_count ) - __field( int, entropy_total ) - __field(unsigned long, IP ) - ), - - TP_fast_assign( - __entry->pool_name = pool_name; - __entry->bits = bits; - __entry->entropy_count = entropy_count; - __entry->entropy_total = entropy_total; - __entry->IP = IP; - ), - - TP_printk("%s pool: bits %d entropy_count %d entropy_total %d " - "caller %pS", __entry->pool_name, __entry->bits, - __entry->entropy_count, __entry->entropy_total, - (void *)__entry->IP) -); - -TRACE_EVENT(push_to_pool, - TP_PROTO(const char *pool_name, int pool_bits, int input_bits), - - TP_ARGS(pool_name, pool_bits, input_bits), - - TP_STRUCT__entry( - __field( const char *, pool_name ) - __field( int, pool_bits ) - __field( int, input_bits ) - ), - - TP_fast_assign( - __entry->pool_name = pool_name; - __entry->pool_bits = pool_bits; - __entry->input_bits = input_bits; - ), - - TP_printk("%s: pool_bits %d input_pool_bits %d", - __entry->pool_name, __entry->pool_bits, - __entry->input_bits) -); - -TRACE_EVENT(debit_entropy, - TP_PROTO(const char *pool_name, int debit_bits), - - TP_ARGS(pool_name, debit_bits), - - TP_STRUCT__entry( - __field( const char *, pool_name ) - __field( int, debit_bits ) - ), - - TP_fast_assign( - __entry->pool_name = pool_name; - __entry->debit_bits = debit_bits; - ), - - TP_printk("%s: debit_bits %d", __entry->pool_name, - __entry->debit_bits) -); - -TRACE_EVENT(add_input_randomness, - TP_PROTO(int input_bits), - - TP_ARGS(input_bits), - - TP_STRUCT__entry( - __field( int, input_bits ) - ), - - TP_fast_assign( - __entry->input_bits = input_bits; - ), - - TP_printk("input_pool_bits %d", __entry->input_bits) -); - -TRACE_EVENT(add_disk_randomness, - TP_PROTO(dev_t dev, int input_bits), - - TP_ARGS(dev, input_bits), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field( int, input_bits ) - ), - - TP_fast_assign( - __entry->dev = dev; - __entry->input_bits = input_bits; - ), - - TP_printk("dev %d,%d input_pool_bits %d", MAJOR(__entry->dev), - MINOR(__entry->dev), __entry->input_bits) -); - -TRACE_EVENT(xfer_secondary_pool, - TP_PROTO(const char *pool_name, int xfer_bits, int request_bits, - int pool_entropy, int input_entropy), - - TP_ARGS(pool_name, xfer_bits, request_bits, pool_entropy, - input_entropy), - - TP_STRUCT__entry( - __field( const char *, pool_name ) - __field( int, xfer_bits ) - __field( int, request_bits ) - __field( int, pool_entropy ) - __field( int, input_entropy ) - ), - - TP_fast_assign( - __entry->pool_name = pool_name; - __entry->xfer_bits = xfer_bits; - __entry->request_bits = request_bits; - __entry->pool_entropy = pool_entropy; - __entry->input_entropy = input_entropy; - ), - - TP_printk("pool %s xfer_bits %d request_bits %d pool_entropy %d " - "input_entropy %d", __entry->pool_name, __entry->xfer_bits, - __entry->request_bits, __entry->pool_entropy, - __entry->input_entropy) -); - -DECLARE_EVENT_CLASS(random__get_random_bytes, - TP_PROTO(int nbytes, unsigned long IP), - - TP_ARGS(nbytes, IP), - - TP_STRUCT__entry( - __field( int, nbytes ) - __field(unsigned long, IP ) - ), - - TP_fast_assign( - __entry->nbytes = nbytes; - __entry->IP = IP; - ), - - TP_printk("nbytes %d caller %pS", __entry->nbytes, (void *)__entry->IP) -); - -DEFINE_EVENT(random__get_random_bytes, get_random_bytes, - TP_PROTO(int nbytes, unsigned long IP), - - TP_ARGS(nbytes, IP) -); - -DEFINE_EVENT(random__get_random_bytes, get_random_bytes_arch, - TP_PROTO(int nbytes, unsigned long IP), - - TP_ARGS(nbytes, IP) -); - -DECLARE_EVENT_CLASS(random__extract_entropy, - TP_PROTO(const char *pool_name, int nbytes, int entropy_count, - unsigned long IP), - - TP_ARGS(pool_name, nbytes, entropy_count, IP), - - TP_STRUCT__entry( - __field( const char *, pool_name ) - __field( int, nbytes ) - __field( int, entropy_count ) - __field(unsigned long, IP ) - ), - - TP_fast_assign( - __entry->pool_name = pool_name; - __entry->nbytes = nbytes; - __entry->entropy_count = entropy_count; - __entry->IP = IP; - ), - - TP_printk("%s pool: nbytes %d entropy_count %d caller %pS", - __entry->pool_name, __entry->nbytes, __entry->entropy_count, - (void *)__entry->IP) -); - - -DEFINE_EVENT(random__extract_entropy, extract_entropy, - TP_PROTO(const char *pool_name, int nbytes, int entropy_count, - unsigned long IP), - - TP_ARGS(pool_name, nbytes, entropy_count, IP) -); - -DEFINE_EVENT(random__extract_entropy, extract_entropy_user, - TP_PROTO(const char *pool_name, int nbytes, int entropy_count, - unsigned long IP), - - TP_ARGS(pool_name, nbytes, entropy_count, IP) -); - -TRACE_EVENT(random_read, - TP_PROTO(int got_bits, int need_bits, int pool_left, int input_left), - - TP_ARGS(got_bits, need_bits, pool_left, input_left), - - TP_STRUCT__entry( - __field( int, got_bits ) - __field( int, need_bits ) - __field( int, pool_left ) - __field( int, input_left ) - ), - - TP_fast_assign( - __entry->got_bits = got_bits; - __entry->need_bits = need_bits; - __entry->pool_left = pool_left; - __entry->input_left = input_left; - ), - - TP_printk("got_bits %d still_needed_bits %d " - "blocking_pool_entropy_left %d input_entropy_left %d", - __entry->got_bits, __entry->got_bits, __entry->pool_left, - __entry->input_left) -); - -TRACE_EVENT(urandom_read, - TP_PROTO(int got_bits, int pool_left, int input_left), - - TP_ARGS(got_bits, pool_left, input_left), - - TP_STRUCT__entry( - __field( int, got_bits ) - __field( int, pool_left ) - __field( int, input_left ) - ), - - TP_fast_assign( - __entry->got_bits = got_bits; - __entry->pool_left = pool_left; - __entry->input_left = input_left; - ), - - TP_printk("got_bits %d nonblocking_pool_entropy_left %d " - "input_entropy_left %d", __entry->got_bits, - __entry->pool_left, __entry->input_left) -); - -#endif /* _TRACE_RANDOM_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/rcu.h b/src/linux/include/trace/events/rcu.h deleted file mode 100644 index d3e7565..0000000 --- a/src/linux/include/trace/events/rcu.h +++ /dev/null @@ -1,814 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM rcu - -#if !defined(_TRACE_RCU_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_RCU_H - -#include - -/* - * Tracepoint for start/end markers used for utilization calculations. - * By convention, the string is of the following forms: - * - * "Start " -- Mark the start of the specified activity, - * such as "context switch". Nesting is permitted. - * "End " -- Mark the end of the specified activity. - * - * An "@" character within "" is a comment character: Data - * reduction scripts will ignore the "@" and the remainder of the line. - */ -TRACE_EVENT(rcu_utilization, - - TP_PROTO(const char *s), - - TP_ARGS(s), - - TP_STRUCT__entry( - __field(const char *, s) - ), - - TP_fast_assign( - __entry->s = s; - ), - - TP_printk("%s", __entry->s) -); - -#ifdef CONFIG_RCU_TRACE - -#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU) - -/* - * Tracepoint for grace-period events. Takes a string identifying the - * RCU flavor, the grace-period number, and a string identifying the - * grace-period-related event as follows: - * - * "AccReadyCB": CPU acclerates new callbacks to RCU_NEXT_READY_TAIL. - * "AccWaitCB": CPU accelerates new callbacks to RCU_WAIT_TAIL. - * "newreq": Request a new grace period. - * "start": Start a grace period. - * "cpustart": CPU first notices a grace-period start. - * "cpuqs": CPU passes through a quiescent state. - * "cpuonl": CPU comes online. - * "cpuofl": CPU goes offline. - * "reqwait": GP kthread sleeps waiting for grace-period request. - * "reqwaitsig": GP kthread awakened by signal from reqwait state. - * "fqswait": GP kthread waiting until time to force quiescent states. - * "fqsstart": GP kthread starts forcing quiescent states. - * "fqsend": GP kthread done forcing quiescent states. - * "fqswaitsig": GP kthread awakened by signal from fqswait state. - * "end": End a grace period. - * "cpuend": CPU first notices a grace-period end. - */ -TRACE_EVENT(rcu_grace_period, - - TP_PROTO(const char *rcuname, unsigned long gpnum, const char *gpevent), - - TP_ARGS(rcuname, gpnum, gpevent), - - TP_STRUCT__entry( - __field(const char *, rcuname) - __field(unsigned long, gpnum) - __field(const char *, gpevent) - ), - - TP_fast_assign( - __entry->rcuname = rcuname; - __entry->gpnum = gpnum; - __entry->gpevent = gpevent; - ), - - TP_printk("%s %lu %s", - __entry->rcuname, __entry->gpnum, __entry->gpevent) -); - -/* - * Tracepoint for future grace-period events, including those for no-callbacks - * CPUs. The caller should pull the data from the rcu_node structure, - * other than rcuname, which comes from the rcu_state structure, and event, - * which is one of the following: - * - * "Startleaf": Request a nocb grace period based on leaf-node data. - * "Startedleaf": Leaf-node start proved sufficient. - * "Startedleafroot": Leaf-node start proved sufficient after checking root. - * "Startedroot": Requested a nocb grace period based on root-node data. - * "StartWait": Start waiting for the requested grace period. - * "ResumeWait": Resume waiting after signal. - * "EndWait": Complete wait. - * "Cleanup": Clean up rcu_node structure after previous GP. - * "CleanupMore": Clean up, and another no-CB GP is needed. - */ -TRACE_EVENT(rcu_future_grace_period, - - TP_PROTO(const char *rcuname, unsigned long gpnum, unsigned long completed, - unsigned long c, u8 level, int grplo, int grphi, - const char *gpevent), - - TP_ARGS(rcuname, gpnum, completed, c, level, grplo, grphi, gpevent), - - TP_STRUCT__entry( - __field(const char *, rcuname) - __field(unsigned long, gpnum) - __field(unsigned long, completed) - __field(unsigned long, c) - __field(u8, level) - __field(int, grplo) - __field(int, grphi) - __field(const char *, gpevent) - ), - - TP_fast_assign( - __entry->rcuname = rcuname; - __entry->gpnum = gpnum; - __entry->completed = completed; - __entry->c = c; - __entry->level = level; - __entry->grplo = grplo; - __entry->grphi = grphi; - __entry->gpevent = gpevent; - ), - - TP_printk("%s %lu %lu %lu %u %d %d %s", - __entry->rcuname, __entry->gpnum, __entry->completed, - __entry->c, __entry->level, __entry->grplo, __entry->grphi, - __entry->gpevent) -); - -/* - * Tracepoint for grace-period-initialization events. These are - * distinguished by the type of RCU, the new grace-period number, the - * rcu_node structure level, the starting and ending CPU covered by the - * rcu_node structure, and the mask of CPUs that will be waited for. - * All but the type of RCU are extracted from the rcu_node structure. - */ -TRACE_EVENT(rcu_grace_period_init, - - TP_PROTO(const char *rcuname, unsigned long gpnum, u8 level, - int grplo, int grphi, unsigned long qsmask), - - TP_ARGS(rcuname, gpnum, level, grplo, grphi, qsmask), - - TP_STRUCT__entry( - __field(const char *, rcuname) - __field(unsigned long, gpnum) - __field(u8, level) - __field(int, grplo) - __field(int, grphi) - __field(unsigned long, qsmask) - ), - - TP_fast_assign( - __entry->rcuname = rcuname; - __entry->gpnum = gpnum; - __entry->level = level; - __entry->grplo = grplo; - __entry->grphi = grphi; - __entry->qsmask = qsmask; - ), - - TP_printk("%s %lu %u %d %d %lx", - __entry->rcuname, __entry->gpnum, __entry->level, - __entry->grplo, __entry->grphi, __entry->qsmask) -); - -/* - * Tracepoint for expedited grace-period events. Takes a string identifying - * the RCU flavor, the expedited grace-period sequence number, and a string - * identifying the grace-period-related event as follows: - * - * "snap": Captured snapshot of expedited grace period sequence number. - * "start": Started a real expedited grace period. - * "end": Ended a real expedited grace period. - * "endwake": Woke piggybackers up. - * "done": Someone else did the expedited grace period for us. - */ -TRACE_EVENT(rcu_exp_grace_period, - - TP_PROTO(const char *rcuname, unsigned long gpseq, const char *gpevent), - - TP_ARGS(rcuname, gpseq, gpevent), - - TP_STRUCT__entry( - __field(const char *, rcuname) - __field(unsigned long, gpseq) - __field(const char *, gpevent) - ), - - TP_fast_assign( - __entry->rcuname = rcuname; - __entry->gpseq = gpseq; - __entry->gpevent = gpevent; - ), - - TP_printk("%s %lu %s", - __entry->rcuname, __entry->gpseq, __entry->gpevent) -); - -/* - * Tracepoint for expedited grace-period funnel-locking events. Takes a - * string identifying the RCU flavor, an integer identifying the rcu_node - * combining-tree level, another pair of integers identifying the lowest- - * and highest-numbered CPU associated with the current rcu_node structure, - * and a string. identifying the grace-period-related event as follows: - * - * "nxtlvl": Advance to next level of rcu_node funnel - * "wait": Wait for someone else to do expedited GP - */ -TRACE_EVENT(rcu_exp_funnel_lock, - - TP_PROTO(const char *rcuname, u8 level, int grplo, int grphi, - const char *gpevent), - - TP_ARGS(rcuname, level, grplo, grphi, gpevent), - - TP_STRUCT__entry( - __field(const char *, rcuname) - __field(u8, level) - __field(int, grplo) - __field(int, grphi) - __field(const char *, gpevent) - ), - - TP_fast_assign( - __entry->rcuname = rcuname; - __entry->level = level; - __entry->grplo = grplo; - __entry->grphi = grphi; - __entry->gpevent = gpevent; - ), - - TP_printk("%s %d %d %d %s", - __entry->rcuname, __entry->level, __entry->grplo, - __entry->grphi, __entry->gpevent) -); - -/* - * Tracepoint for RCU no-CBs CPU callback handoffs. This event is intended - * to assist debugging of these handoffs. - * - * The first argument is the name of the RCU flavor, and the second is - * the number of the offloaded CPU are extracted. The third and final - * argument is a string as follows: - * - * "WakeEmpty": Wake rcuo kthread, first CB to empty list. - * "WakeEmptyIsDeferred": Wake rcuo kthread later, first CB to empty list. - * "WakeOvf": Wake rcuo kthread, CB list is huge. - * "WakeOvfIsDeferred": Wake rcuo kthread later, CB list is huge. - * "WakeNot": Don't wake rcuo kthread. - * "WakeNotPoll": Don't wake rcuo kthread because it is polling. - * "DeferredWake": Carried out the "IsDeferred" wakeup. - * "Poll": Start of new polling cycle for rcu_nocb_poll. - * "Sleep": Sleep waiting for CBs for !rcu_nocb_poll. - * "WokeEmpty": rcuo kthread woke to find empty list. - * "WokeNonEmpty": rcuo kthread woke to find non-empty list. - * "WaitQueue": Enqueue partially done, timed wait for it to complete. - * "WokeQueue": Partial enqueue now complete. - */ -TRACE_EVENT(rcu_nocb_wake, - - TP_PROTO(const char *rcuname, int cpu, const char *reason), - - TP_ARGS(rcuname, cpu, reason), - - TP_STRUCT__entry( - __field(const char *, rcuname) - __field(int, cpu) - __field(const char *, reason) - ), - - TP_fast_assign( - __entry->rcuname = rcuname; - __entry->cpu = cpu; - __entry->reason = reason; - ), - - TP_printk("%s %d %s", __entry->rcuname, __entry->cpu, __entry->reason) -); - -/* - * Tracepoint for tasks blocking within preemptible-RCU read-side - * critical sections. Track the type of RCU (which one day might - * include SRCU), the grace-period number that the task is blocking - * (the current or the next), and the task's PID. - */ -TRACE_EVENT(rcu_preempt_task, - - TP_PROTO(const char *rcuname, int pid, unsigned long gpnum), - - TP_ARGS(rcuname, pid, gpnum), - - TP_STRUCT__entry( - __field(const char *, rcuname) - __field(unsigned long, gpnum) - __field(int, pid) - ), - - TP_fast_assign( - __entry->rcuname = rcuname; - __entry->gpnum = gpnum; - __entry->pid = pid; - ), - - TP_printk("%s %lu %d", - __entry->rcuname, __entry->gpnum, __entry->pid) -); - -/* - * Tracepoint for tasks that blocked within a given preemptible-RCU - * read-side critical section exiting that critical section. Track the - * type of RCU (which one day might include SRCU) and the task's PID. - */ -TRACE_EVENT(rcu_unlock_preempted_task, - - TP_PROTO(const char *rcuname, unsigned long gpnum, int pid), - - TP_ARGS(rcuname, gpnum, pid), - - TP_STRUCT__entry( - __field(const char *, rcuname) - __field(unsigned long, gpnum) - __field(int, pid) - ), - - TP_fast_assign( - __entry->rcuname = rcuname; - __entry->gpnum = gpnum; - __entry->pid = pid; - ), - - TP_printk("%s %lu %d", __entry->rcuname, __entry->gpnum, __entry->pid) -); - -/* - * Tracepoint for quiescent-state-reporting events. These are - * distinguished by the type of RCU, the grace-period number, the - * mask of quiescent lower-level entities, the rcu_node structure level, - * the starting and ending CPU covered by the rcu_node structure, and - * whether there are any blocked tasks blocking the current grace period. - * All but the type of RCU are extracted from the rcu_node structure. - */ -TRACE_EVENT(rcu_quiescent_state_report, - - TP_PROTO(const char *rcuname, unsigned long gpnum, - unsigned long mask, unsigned long qsmask, - u8 level, int grplo, int grphi, int gp_tasks), - - TP_ARGS(rcuname, gpnum, mask, qsmask, level, grplo, grphi, gp_tasks), - - TP_STRUCT__entry( - __field(const char *, rcuname) - __field(unsigned long, gpnum) - __field(unsigned long, mask) - __field(unsigned long, qsmask) - __field(u8, level) - __field(int, grplo) - __field(int, grphi) - __field(u8, gp_tasks) - ), - - TP_fast_assign( - __entry->rcuname = rcuname; - __entry->gpnum = gpnum; - __entry->mask = mask; - __entry->qsmask = qsmask; - __entry->level = level; - __entry->grplo = grplo; - __entry->grphi = grphi; - __entry->gp_tasks = gp_tasks; - ), - - TP_printk("%s %lu %lx>%lx %u %d %d %u", - __entry->rcuname, __entry->gpnum, - __entry->mask, __entry->qsmask, __entry->level, - __entry->grplo, __entry->grphi, __entry->gp_tasks) -); - -/* - * Tracepoint for quiescent states detected by force_quiescent_state(). - * These trace events include the type of RCU, the grace-period number - * that was blocked by the CPU, the CPU itself, and the type of quiescent - * state, which can be "dti" for dyntick-idle mode, "ofl" for CPU offline, - * or "kick" when kicking a CPU that has been in dyntick-idle mode for - * too long. - */ -TRACE_EVENT(rcu_fqs, - - TP_PROTO(const char *rcuname, unsigned long gpnum, int cpu, const char *qsevent), - - TP_ARGS(rcuname, gpnum, cpu, qsevent), - - TP_STRUCT__entry( - __field(const char *, rcuname) - __field(unsigned long, gpnum) - __field(int, cpu) - __field(const char *, qsevent) - ), - - TP_fast_assign( - __entry->rcuname = rcuname; - __entry->gpnum = gpnum; - __entry->cpu = cpu; - __entry->qsevent = qsevent; - ), - - TP_printk("%s %lu %d %s", - __entry->rcuname, __entry->gpnum, - __entry->cpu, __entry->qsevent) -); - -#endif /* #if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU) */ - -/* - * Tracepoint for dyntick-idle entry/exit events. These take a string - * as argument: "Start" for entering dyntick-idle mode, "End" for - * leaving it, "--=" for events moving towards idle, and "++=" for events - * moving away from idle. "Error on entry: not idle task" and "Error on - * exit: not idle task" indicate that a non-idle task is erroneously - * toying with the idle loop. - * - * These events also take a pair of numbers, which indicate the nesting - * depth before and after the event of interest. Note that task-related - * events use the upper bits of each number, while interrupt-related - * events use the lower bits. - */ -TRACE_EVENT(rcu_dyntick, - - TP_PROTO(const char *polarity, long long oldnesting, long long newnesting), - - TP_ARGS(polarity, oldnesting, newnesting), - - TP_STRUCT__entry( - __field(const char *, polarity) - __field(long long, oldnesting) - __field(long long, newnesting) - ), - - TP_fast_assign( - __entry->polarity = polarity; - __entry->oldnesting = oldnesting; - __entry->newnesting = newnesting; - ), - - TP_printk("%s %llx %llx", __entry->polarity, - __entry->oldnesting, __entry->newnesting) -); - -/* - * Tracepoint for RCU preparation for idle, the goal being to get RCU - * processing done so that the current CPU can shut off its scheduling - * clock and enter dyntick-idle mode. One way to accomplish this is - * to drain all RCU callbacks from this CPU, and the other is to have - * done everything RCU requires for the current grace period. In this - * latter case, the CPU will be awakened at the end of the current grace - * period in order to process the remainder of its callbacks. - * - * These tracepoints take a string as argument: - * - * "No callbacks": Nothing to do, no callbacks on this CPU. - * "In holdoff": Nothing to do, holding off after unsuccessful attempt. - * "Begin holdoff": Attempt failed, don't retry until next jiffy. - * "Dyntick with callbacks": Entering dyntick-idle despite callbacks. - * "Dyntick with lazy callbacks": Entering dyntick-idle w/lazy callbacks. - * "More callbacks": Still more callbacks, try again to clear them out. - * "Callbacks drained": All callbacks processed, off to dyntick idle! - * "Timer": Timer fired to cause CPU to continue processing callbacks. - * "Demigrate": Timer fired on wrong CPU, woke up correct CPU. - * "Cleanup after idle": Idle exited, timer canceled. - */ -TRACE_EVENT(rcu_prep_idle, - - TP_PROTO(const char *reason), - - TP_ARGS(reason), - - TP_STRUCT__entry( - __field(const char *, reason) - ), - - TP_fast_assign( - __entry->reason = reason; - ), - - TP_printk("%s", __entry->reason) -); - -/* - * Tracepoint for the registration of a single RCU callback function. - * The first argument is the type of RCU, the second argument is - * a pointer to the RCU callback itself, the third element is the - * number of lazy callbacks queued, and the fourth element is the - * total number of callbacks queued. - */ -TRACE_EVENT(rcu_callback, - - TP_PROTO(const char *rcuname, struct rcu_head *rhp, long qlen_lazy, - long qlen), - - TP_ARGS(rcuname, rhp, qlen_lazy, qlen), - - TP_STRUCT__entry( - __field(const char *, rcuname) - __field(void *, rhp) - __field(void *, func) - __field(long, qlen_lazy) - __field(long, qlen) - ), - - TP_fast_assign( - __entry->rcuname = rcuname; - __entry->rhp = rhp; - __entry->func = rhp->func; - __entry->qlen_lazy = qlen_lazy; - __entry->qlen = qlen; - ), - - TP_printk("%s rhp=%p func=%pf %ld/%ld", - __entry->rcuname, __entry->rhp, __entry->func, - __entry->qlen_lazy, __entry->qlen) -); - -/* - * Tracepoint for the registration of a single RCU callback of the special - * kfree() form. The first argument is the RCU type, the second argument - * is a pointer to the RCU callback, the third argument is the offset - * of the callback within the enclosing RCU-protected data structure, - * the fourth argument is the number of lazy callbacks queued, and the - * fifth argument is the total number of callbacks queued. - */ -TRACE_EVENT(rcu_kfree_callback, - - TP_PROTO(const char *rcuname, struct rcu_head *rhp, unsigned long offset, - long qlen_lazy, long qlen), - - TP_ARGS(rcuname, rhp, offset, qlen_lazy, qlen), - - TP_STRUCT__entry( - __field(const char *, rcuname) - __field(void *, rhp) - __field(unsigned long, offset) - __field(long, qlen_lazy) - __field(long, qlen) - ), - - TP_fast_assign( - __entry->rcuname = rcuname; - __entry->rhp = rhp; - __entry->offset = offset; - __entry->qlen_lazy = qlen_lazy; - __entry->qlen = qlen; - ), - - TP_printk("%s rhp=%p func=%ld %ld/%ld", - __entry->rcuname, __entry->rhp, __entry->offset, - __entry->qlen_lazy, __entry->qlen) -); - -/* - * Tracepoint for marking the beginning rcu_do_batch, performed to start - * RCU callback invocation. The first argument is the RCU flavor, - * the second is the number of lazy callbacks queued, the third is - * the total number of callbacks queued, and the fourth argument is - * the current RCU-callback batch limit. - */ -TRACE_EVENT(rcu_batch_start, - - TP_PROTO(const char *rcuname, long qlen_lazy, long qlen, long blimit), - - TP_ARGS(rcuname, qlen_lazy, qlen, blimit), - - TP_STRUCT__entry( - __field(const char *, rcuname) - __field(long, qlen_lazy) - __field(long, qlen) - __field(long, blimit) - ), - - TP_fast_assign( - __entry->rcuname = rcuname; - __entry->qlen_lazy = qlen_lazy; - __entry->qlen = qlen; - __entry->blimit = blimit; - ), - - TP_printk("%s CBs=%ld/%ld bl=%ld", - __entry->rcuname, __entry->qlen_lazy, __entry->qlen, - __entry->blimit) -); - -/* - * Tracepoint for the invocation of a single RCU callback function. - * The first argument is the type of RCU, and the second argument is - * a pointer to the RCU callback itself. - */ -TRACE_EVENT(rcu_invoke_callback, - - TP_PROTO(const char *rcuname, struct rcu_head *rhp), - - TP_ARGS(rcuname, rhp), - - TP_STRUCT__entry( - __field(const char *, rcuname) - __field(void *, rhp) - __field(void *, func) - ), - - TP_fast_assign( - __entry->rcuname = rcuname; - __entry->rhp = rhp; - __entry->func = rhp->func; - ), - - TP_printk("%s rhp=%p func=%pf", - __entry->rcuname, __entry->rhp, __entry->func) -); - -/* - * Tracepoint for the invocation of a single RCU callback of the special - * kfree() form. The first argument is the RCU flavor, the second - * argument is a pointer to the RCU callback, and the third argument - * is the offset of the callback within the enclosing RCU-protected - * data structure. - */ -TRACE_EVENT(rcu_invoke_kfree_callback, - - TP_PROTO(const char *rcuname, struct rcu_head *rhp, unsigned long offset), - - TP_ARGS(rcuname, rhp, offset), - - TP_STRUCT__entry( - __field(const char *, rcuname) - __field(void *, rhp) - __field(unsigned long, offset) - ), - - TP_fast_assign( - __entry->rcuname = rcuname; - __entry->rhp = rhp; - __entry->offset = offset; - ), - - TP_printk("%s rhp=%p func=%ld", - __entry->rcuname, __entry->rhp, __entry->offset) -); - -/* - * Tracepoint for exiting rcu_do_batch after RCU callbacks have been - * invoked. The first argument is the name of the RCU flavor, - * the second argument is number of callbacks actually invoked, - * the third argument (cb) is whether or not any of the callbacks that - * were ready to invoke at the beginning of this batch are still - * queued, the fourth argument (nr) is the return value of need_resched(), - * the fifth argument (iit) is 1 if the current task is the idle task, - * and the sixth argument (risk) is the return value from - * rcu_is_callbacks_kthread(). - */ -TRACE_EVENT(rcu_batch_end, - - TP_PROTO(const char *rcuname, int callbacks_invoked, - char cb, char nr, char iit, char risk), - - TP_ARGS(rcuname, callbacks_invoked, cb, nr, iit, risk), - - TP_STRUCT__entry( - __field(const char *, rcuname) - __field(int, callbacks_invoked) - __field(char, cb) - __field(char, nr) - __field(char, iit) - __field(char, risk) - ), - - TP_fast_assign( - __entry->rcuname = rcuname; - __entry->callbacks_invoked = callbacks_invoked; - __entry->cb = cb; - __entry->nr = nr; - __entry->iit = iit; - __entry->risk = risk; - ), - - TP_printk("%s CBs-invoked=%d idle=%c%c%c%c", - __entry->rcuname, __entry->callbacks_invoked, - __entry->cb ? 'C' : '.', - __entry->nr ? 'S' : '.', - __entry->iit ? 'I' : '.', - __entry->risk ? 'R' : '.') -); - -/* - * Tracepoint for rcutorture readers. The first argument is the name - * of the RCU flavor from rcutorture's viewpoint and the second argument - * is the callback address. - */ -TRACE_EVENT(rcu_torture_read, - - TP_PROTO(const char *rcutorturename, struct rcu_head *rhp, - unsigned long secs, unsigned long c_old, unsigned long c), - - TP_ARGS(rcutorturename, rhp, secs, c_old, c), - - TP_STRUCT__entry( - __field(const char *, rcutorturename) - __field(struct rcu_head *, rhp) - __field(unsigned long, secs) - __field(unsigned long, c_old) - __field(unsigned long, c) - ), - - TP_fast_assign( - __entry->rcutorturename = rcutorturename; - __entry->rhp = rhp; - __entry->secs = secs; - __entry->c_old = c_old; - __entry->c = c; - ), - - TP_printk("%s torture read %p %luus c: %lu %lu", - __entry->rcutorturename, __entry->rhp, - __entry->secs, __entry->c_old, __entry->c) -); - -/* - * Tracepoint for _rcu_barrier() execution. The string "s" describes - * the _rcu_barrier phase: - * "Begin": _rcu_barrier() started. - * "EarlyExit": _rcu_barrier() piggybacked, thus early exit. - * "Inc1": _rcu_barrier() piggyback check counter incremented. - * "OfflineNoCB": _rcu_barrier() found callback on never-online CPU - * "OnlineNoCB": _rcu_barrier() found online no-CBs CPU. - * "OnlineQ": _rcu_barrier() found online CPU with callbacks. - * "OnlineNQ": _rcu_barrier() found online CPU, no callbacks. - * "IRQ": An rcu_barrier_callback() callback posted on remote CPU. - * "CB": An rcu_barrier_callback() invoked a callback, not the last. - * "LastCB": An rcu_barrier_callback() invoked the last callback. - * "Inc2": _rcu_barrier() piggyback check counter incremented. - * The "cpu" argument is the CPU or -1 if meaningless, the "cnt" argument - * is the count of remaining callbacks, and "done" is the piggybacking count. - */ -TRACE_EVENT(rcu_barrier, - - TP_PROTO(const char *rcuname, const char *s, int cpu, int cnt, unsigned long done), - - TP_ARGS(rcuname, s, cpu, cnt, done), - - TP_STRUCT__entry( - __field(const char *, rcuname) - __field(const char *, s) - __field(int, cpu) - __field(int, cnt) - __field(unsigned long, done) - ), - - TP_fast_assign( - __entry->rcuname = rcuname; - __entry->s = s; - __entry->cpu = cpu; - __entry->cnt = cnt; - __entry->done = done; - ), - - TP_printk("%s %s cpu %d remaining %d # %lu", - __entry->rcuname, __entry->s, __entry->cpu, __entry->cnt, - __entry->done) -); - -#else /* #ifdef CONFIG_RCU_TRACE */ - -#define trace_rcu_grace_period(rcuname, gpnum, gpevent) do { } while (0) -#define trace_rcu_future_grace_period(rcuname, gpnum, completed, c, \ - level, grplo, grphi, event) \ - do { } while (0) -#define trace_rcu_grace_period_init(rcuname, gpnum, level, grplo, grphi, \ - qsmask) do { } while (0) -#define trace_rcu_exp_grace_period(rcuname, gqseq, gpevent) \ - do { } while (0) -#define trace_rcu_exp_funnel_lock(rcuname, level, grplo, grphi, gpevent) \ - do { } while (0) -#define trace_rcu_nocb_wake(rcuname, cpu, reason) do { } while (0) -#define trace_rcu_preempt_task(rcuname, pid, gpnum) do { } while (0) -#define trace_rcu_unlock_preempted_task(rcuname, gpnum, pid) do { } while (0) -#define trace_rcu_quiescent_state_report(rcuname, gpnum, mask, qsmask, level, \ - grplo, grphi, gp_tasks) do { } \ - while (0) -#define trace_rcu_fqs(rcuname, gpnum, cpu, qsevent) do { } while (0) -#define trace_rcu_dyntick(polarity, oldnesting, newnesting) do { } while (0) -#define trace_rcu_prep_idle(reason) do { } while (0) -#define trace_rcu_callback(rcuname, rhp, qlen_lazy, qlen) do { } while (0) -#define trace_rcu_kfree_callback(rcuname, rhp, offset, qlen_lazy, qlen) \ - do { } while (0) -#define trace_rcu_batch_start(rcuname, qlen_lazy, qlen, blimit) \ - do { } while (0) -#define trace_rcu_invoke_callback(rcuname, rhp) do { } while (0) -#define trace_rcu_invoke_kfree_callback(rcuname, rhp, offset) do { } while (0) -#define trace_rcu_batch_end(rcuname, callbacks_invoked, cb, nr, iit, risk) \ - do { } while (0) -#define trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \ - do { } while (0) -#define trace_rcu_barrier(name, s, cpu, cnt, done) do { } while (0) - -#endif /* #else #ifdef CONFIG_RCU_TRACE */ - -#endif /* _TRACE_RCU_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/sched.h b/src/linux/include/trace/events/sched.h deleted file mode 100644 index 9b90c57..0000000 --- a/src/linux/include/trace/events/sched.h +++ /dev/null @@ -1,568 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM sched - -#if !defined(_TRACE_SCHED_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_SCHED_H - -#include -#include -#include - -/* - * Tracepoint for calling kthread_stop, performed to end a kthread: - */ -TRACE_EVENT(sched_kthread_stop, - - TP_PROTO(struct task_struct *t), - - TP_ARGS(t), - - TP_STRUCT__entry( - __array( char, comm, TASK_COMM_LEN ) - __field( pid_t, pid ) - ), - - TP_fast_assign( - memcpy(__entry->comm, t->comm, TASK_COMM_LEN); - __entry->pid = t->pid; - ), - - TP_printk("comm=%s pid=%d", __entry->comm, __entry->pid) -); - -/* - * Tracepoint for the return value of the kthread stopping: - */ -TRACE_EVENT(sched_kthread_stop_ret, - - TP_PROTO(int ret), - - TP_ARGS(ret), - - TP_STRUCT__entry( - __field( int, ret ) - ), - - TP_fast_assign( - __entry->ret = ret; - ), - - TP_printk("ret=%d", __entry->ret) -); - -/* - * Tracepoint for waking up a task: - */ -DECLARE_EVENT_CLASS(sched_wakeup_template, - - TP_PROTO(struct task_struct *p), - - TP_ARGS(__perf_task(p)), - - TP_STRUCT__entry( - __array( char, comm, TASK_COMM_LEN ) - __field( pid_t, pid ) - __field( int, prio ) - __field( int, success ) - __field( int, target_cpu ) - ), - - TP_fast_assign( - memcpy(__entry->comm, p->comm, TASK_COMM_LEN); - __entry->pid = p->pid; - __entry->prio = p->prio; - __entry->success = 1; /* rudiment, kill when possible */ - __entry->target_cpu = task_cpu(p); - ), - - TP_printk("comm=%s pid=%d prio=%d target_cpu=%03d", - __entry->comm, __entry->pid, __entry->prio, - __entry->target_cpu) -); - -/* - * Tracepoint called when waking a task; this tracepoint is guaranteed to be - * called from the waking context. - */ -DEFINE_EVENT(sched_wakeup_template, sched_waking, - TP_PROTO(struct task_struct *p), - TP_ARGS(p)); - -/* - * Tracepoint called when the task is actually woken; p->state == TASK_RUNNNG. - * It it not always called from the waking context. - */ -DEFINE_EVENT(sched_wakeup_template, sched_wakeup, - TP_PROTO(struct task_struct *p), - TP_ARGS(p)); - -/* - * Tracepoint for waking up a new task: - */ -DEFINE_EVENT(sched_wakeup_template, sched_wakeup_new, - TP_PROTO(struct task_struct *p), - TP_ARGS(p)); - -#ifdef CREATE_TRACE_POINTS -static inline long __trace_sched_switch_state(bool preempt, struct task_struct *p) -{ -#ifdef CONFIG_SCHED_DEBUG - BUG_ON(p != current); -#endif /* CONFIG_SCHED_DEBUG */ - - /* - * Preemption ignores task state, therefore preempted tasks are always - * RUNNING (we will not have dequeued if state != RUNNING). - */ - return preempt ? TASK_RUNNING | TASK_STATE_MAX : p->state; -} -#endif /* CREATE_TRACE_POINTS */ - -/* - * Tracepoint for task switches, performed by the scheduler: - */ -TRACE_EVENT(sched_switch, - - TP_PROTO(bool preempt, - struct task_struct *prev, - struct task_struct *next), - - TP_ARGS(preempt, prev, next), - - TP_STRUCT__entry( - __array( char, prev_comm, TASK_COMM_LEN ) - __field( pid_t, prev_pid ) - __field( int, prev_prio ) - __field( long, prev_state ) - __array( char, next_comm, TASK_COMM_LEN ) - __field( pid_t, next_pid ) - __field( int, next_prio ) - ), - - TP_fast_assign( - memcpy(__entry->next_comm, next->comm, TASK_COMM_LEN); - __entry->prev_pid = prev->pid; - __entry->prev_prio = prev->prio; - __entry->prev_state = __trace_sched_switch_state(preempt, prev); - memcpy(__entry->prev_comm, prev->comm, TASK_COMM_LEN); - __entry->next_pid = next->pid; - __entry->next_prio = next->prio; - ), - - TP_printk("prev_comm=%s prev_pid=%d prev_prio=%d prev_state=%s%s ==> next_comm=%s next_pid=%d next_prio=%d", - __entry->prev_comm, __entry->prev_pid, __entry->prev_prio, - __entry->prev_state & (TASK_STATE_MAX-1) ? - __print_flags(__entry->prev_state & (TASK_STATE_MAX-1), "|", - { 1, "S"} , { 2, "D" }, { 4, "T" }, { 8, "t" }, - { 16, "Z" }, { 32, "X" }, { 64, "x" }, - { 128, "K" }, { 256, "W" }, { 512, "P" }, - { 1024, "N" }) : "R", - __entry->prev_state & TASK_STATE_MAX ? "+" : "", - __entry->next_comm, __entry->next_pid, __entry->next_prio) -); - -/* - * Tracepoint for a task being migrated: - */ -TRACE_EVENT(sched_migrate_task, - - TP_PROTO(struct task_struct *p, int dest_cpu), - - TP_ARGS(p, dest_cpu), - - TP_STRUCT__entry( - __array( char, comm, TASK_COMM_LEN ) - __field( pid_t, pid ) - __field( int, prio ) - __field( int, orig_cpu ) - __field( int, dest_cpu ) - ), - - TP_fast_assign( - memcpy(__entry->comm, p->comm, TASK_COMM_LEN); - __entry->pid = p->pid; - __entry->prio = p->prio; - __entry->orig_cpu = task_cpu(p); - __entry->dest_cpu = dest_cpu; - ), - - TP_printk("comm=%s pid=%d prio=%d orig_cpu=%d dest_cpu=%d", - __entry->comm, __entry->pid, __entry->prio, - __entry->orig_cpu, __entry->dest_cpu) -); - -DECLARE_EVENT_CLASS(sched_process_template, - - TP_PROTO(struct task_struct *p), - - TP_ARGS(p), - - TP_STRUCT__entry( - __array( char, comm, TASK_COMM_LEN ) - __field( pid_t, pid ) - __field( int, prio ) - ), - - TP_fast_assign( - memcpy(__entry->comm, p->comm, TASK_COMM_LEN); - __entry->pid = p->pid; - __entry->prio = p->prio; - ), - - TP_printk("comm=%s pid=%d prio=%d", - __entry->comm, __entry->pid, __entry->prio) -); - -/* - * Tracepoint for freeing a task: - */ -DEFINE_EVENT(sched_process_template, sched_process_free, - TP_PROTO(struct task_struct *p), - TP_ARGS(p)); - - -/* - * Tracepoint for a task exiting: - */ -DEFINE_EVENT(sched_process_template, sched_process_exit, - TP_PROTO(struct task_struct *p), - TP_ARGS(p)); - -/* - * Tracepoint for waiting on task to unschedule: - */ -DEFINE_EVENT(sched_process_template, sched_wait_task, - TP_PROTO(struct task_struct *p), - TP_ARGS(p)); - -/* - * Tracepoint for a waiting task: - */ -TRACE_EVENT(sched_process_wait, - - TP_PROTO(struct pid *pid), - - TP_ARGS(pid), - - TP_STRUCT__entry( - __array( char, comm, TASK_COMM_LEN ) - __field( pid_t, pid ) - __field( int, prio ) - ), - - TP_fast_assign( - memcpy(__entry->comm, current->comm, TASK_COMM_LEN); - __entry->pid = pid_nr(pid); - __entry->prio = current->prio; - ), - - TP_printk("comm=%s pid=%d prio=%d", - __entry->comm, __entry->pid, __entry->prio) -); - -/* - * Tracepoint for do_fork: - */ -TRACE_EVENT(sched_process_fork, - - TP_PROTO(struct task_struct *parent, struct task_struct *child), - - TP_ARGS(parent, child), - - TP_STRUCT__entry( - __array( char, parent_comm, TASK_COMM_LEN ) - __field( pid_t, parent_pid ) - __array( char, child_comm, TASK_COMM_LEN ) - __field( pid_t, child_pid ) - ), - - TP_fast_assign( - memcpy(__entry->parent_comm, parent->comm, TASK_COMM_LEN); - __entry->parent_pid = parent->pid; - memcpy(__entry->child_comm, child->comm, TASK_COMM_LEN); - __entry->child_pid = child->pid; - ), - - TP_printk("comm=%s pid=%d child_comm=%s child_pid=%d", - __entry->parent_comm, __entry->parent_pid, - __entry->child_comm, __entry->child_pid) -); - -/* - * Tracepoint for exec: - */ -TRACE_EVENT(sched_process_exec, - - TP_PROTO(struct task_struct *p, pid_t old_pid, - struct linux_binprm *bprm), - - TP_ARGS(p, old_pid, bprm), - - TP_STRUCT__entry( - __string( filename, bprm->filename ) - __field( pid_t, pid ) - __field( pid_t, old_pid ) - ), - - TP_fast_assign( - __assign_str(filename, bprm->filename); - __entry->pid = p->pid; - __entry->old_pid = old_pid; - ), - - TP_printk("filename=%s pid=%d old_pid=%d", __get_str(filename), - __entry->pid, __entry->old_pid) -); - -/* - * XXX the below sched_stat tracepoints only apply to SCHED_OTHER/BATCH/IDLE - * adding sched_stat support to SCHED_FIFO/RR would be welcome. - */ -DECLARE_EVENT_CLASS(sched_stat_template, - - TP_PROTO(struct task_struct *tsk, u64 delay), - - TP_ARGS(__perf_task(tsk), __perf_count(delay)), - - TP_STRUCT__entry( - __array( char, comm, TASK_COMM_LEN ) - __field( pid_t, pid ) - __field( u64, delay ) - ), - - TP_fast_assign( - memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN); - __entry->pid = tsk->pid; - __entry->delay = delay; - ), - - TP_printk("comm=%s pid=%d delay=%Lu [ns]", - __entry->comm, __entry->pid, - (unsigned long long)__entry->delay) -); - - -/* - * Tracepoint for accounting wait time (time the task is runnable - * but not actually running due to scheduler contention). - */ -DEFINE_EVENT(sched_stat_template, sched_stat_wait, - TP_PROTO(struct task_struct *tsk, u64 delay), - TP_ARGS(tsk, delay)); - -/* - * Tracepoint for accounting sleep time (time the task is not runnable, - * including iowait, see below). - */ -DEFINE_EVENT(sched_stat_template, sched_stat_sleep, - TP_PROTO(struct task_struct *tsk, u64 delay), - TP_ARGS(tsk, delay)); - -/* - * Tracepoint for accounting iowait time (time the task is not runnable - * due to waiting on IO to complete). - */ -DEFINE_EVENT(sched_stat_template, sched_stat_iowait, - TP_PROTO(struct task_struct *tsk, u64 delay), - TP_ARGS(tsk, delay)); - -/* - * Tracepoint for accounting blocked time (time the task is in uninterruptible). - */ -DEFINE_EVENT(sched_stat_template, sched_stat_blocked, - TP_PROTO(struct task_struct *tsk, u64 delay), - TP_ARGS(tsk, delay)); - -/* - * Tracepoint for accounting runtime (time the task is executing - * on a CPU). - */ -DECLARE_EVENT_CLASS(sched_stat_runtime, - - TP_PROTO(struct task_struct *tsk, u64 runtime, u64 vruntime), - - TP_ARGS(tsk, __perf_count(runtime), vruntime), - - TP_STRUCT__entry( - __array( char, comm, TASK_COMM_LEN ) - __field( pid_t, pid ) - __field( u64, runtime ) - __field( u64, vruntime ) - ), - - TP_fast_assign( - memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN); - __entry->pid = tsk->pid; - __entry->runtime = runtime; - __entry->vruntime = vruntime; - ), - - TP_printk("comm=%s pid=%d runtime=%Lu [ns] vruntime=%Lu [ns]", - __entry->comm, __entry->pid, - (unsigned long long)__entry->runtime, - (unsigned long long)__entry->vruntime) -); - -DEFINE_EVENT(sched_stat_runtime, sched_stat_runtime, - TP_PROTO(struct task_struct *tsk, u64 runtime, u64 vruntime), - TP_ARGS(tsk, runtime, vruntime)); - -/* - * Tracepoint for showing priority inheritance modifying a tasks - * priority. - */ -TRACE_EVENT(sched_pi_setprio, - - TP_PROTO(struct task_struct *tsk, int newprio), - - TP_ARGS(tsk, newprio), - - TP_STRUCT__entry( - __array( char, comm, TASK_COMM_LEN ) - __field( pid_t, pid ) - __field( int, oldprio ) - __field( int, newprio ) - ), - - TP_fast_assign( - memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN); - __entry->pid = tsk->pid; - __entry->oldprio = tsk->prio; - __entry->newprio = newprio; - ), - - TP_printk("comm=%s pid=%d oldprio=%d newprio=%d", - __entry->comm, __entry->pid, - __entry->oldprio, __entry->newprio) -); - -#ifdef CONFIG_DETECT_HUNG_TASK -TRACE_EVENT(sched_process_hang, - TP_PROTO(struct task_struct *tsk), - TP_ARGS(tsk), - - TP_STRUCT__entry( - __array( char, comm, TASK_COMM_LEN ) - __field( pid_t, pid ) - ), - - TP_fast_assign( - memcpy(__entry->comm, tsk->comm, TASK_COMM_LEN); - __entry->pid = tsk->pid; - ), - - TP_printk("comm=%s pid=%d", __entry->comm, __entry->pid) -); -#endif /* CONFIG_DETECT_HUNG_TASK */ - -DECLARE_EVENT_CLASS(sched_move_task_template, - - TP_PROTO(struct task_struct *tsk, int src_cpu, int dst_cpu), - - TP_ARGS(tsk, src_cpu, dst_cpu), - - TP_STRUCT__entry( - __field( pid_t, pid ) - __field( pid_t, tgid ) - __field( pid_t, ngid ) - __field( int, src_cpu ) - __field( int, src_nid ) - __field( int, dst_cpu ) - __field( int, dst_nid ) - ), - - TP_fast_assign( - __entry->pid = task_pid_nr(tsk); - __entry->tgid = task_tgid_nr(tsk); - __entry->ngid = task_numa_group_id(tsk); - __entry->src_cpu = src_cpu; - __entry->src_nid = cpu_to_node(src_cpu); - __entry->dst_cpu = dst_cpu; - __entry->dst_nid = cpu_to_node(dst_cpu); - ), - - TP_printk("pid=%d tgid=%d ngid=%d src_cpu=%d src_nid=%d dst_cpu=%d dst_nid=%d", - __entry->pid, __entry->tgid, __entry->ngid, - __entry->src_cpu, __entry->src_nid, - __entry->dst_cpu, __entry->dst_nid) -); - -/* - * Tracks migration of tasks from one runqueue to another. Can be used to - * detect if automatic NUMA balancing is bouncing between nodes - */ -DEFINE_EVENT(sched_move_task_template, sched_move_numa, - TP_PROTO(struct task_struct *tsk, int src_cpu, int dst_cpu), - - TP_ARGS(tsk, src_cpu, dst_cpu) -); - -DEFINE_EVENT(sched_move_task_template, sched_stick_numa, - TP_PROTO(struct task_struct *tsk, int src_cpu, int dst_cpu), - - TP_ARGS(tsk, src_cpu, dst_cpu) -); - -TRACE_EVENT(sched_swap_numa, - - TP_PROTO(struct task_struct *src_tsk, int src_cpu, - struct task_struct *dst_tsk, int dst_cpu), - - TP_ARGS(src_tsk, src_cpu, dst_tsk, dst_cpu), - - TP_STRUCT__entry( - __field( pid_t, src_pid ) - __field( pid_t, src_tgid ) - __field( pid_t, src_ngid ) - __field( int, src_cpu ) - __field( int, src_nid ) - __field( pid_t, dst_pid ) - __field( pid_t, dst_tgid ) - __field( pid_t, dst_ngid ) - __field( int, dst_cpu ) - __field( int, dst_nid ) - ), - - TP_fast_assign( - __entry->src_pid = task_pid_nr(src_tsk); - __entry->src_tgid = task_tgid_nr(src_tsk); - __entry->src_ngid = task_numa_group_id(src_tsk); - __entry->src_cpu = src_cpu; - __entry->src_nid = cpu_to_node(src_cpu); - __entry->dst_pid = task_pid_nr(dst_tsk); - __entry->dst_tgid = task_tgid_nr(dst_tsk); - __entry->dst_ngid = task_numa_group_id(dst_tsk); - __entry->dst_cpu = dst_cpu; - __entry->dst_nid = cpu_to_node(dst_cpu); - ), - - TP_printk("src_pid=%d src_tgid=%d src_ngid=%d src_cpu=%d src_nid=%d dst_pid=%d dst_tgid=%d dst_ngid=%d dst_cpu=%d dst_nid=%d", - __entry->src_pid, __entry->src_tgid, __entry->src_ngid, - __entry->src_cpu, __entry->src_nid, - __entry->dst_pid, __entry->dst_tgid, __entry->dst_ngid, - __entry->dst_cpu, __entry->dst_nid) -); - -/* - * Tracepoint for waking a polling cpu without an IPI. - */ -TRACE_EVENT(sched_wake_idle_without_ipi, - - TP_PROTO(int cpu), - - TP_ARGS(cpu), - - TP_STRUCT__entry( - __field( int, cpu ) - ), - - TP_fast_assign( - __entry->cpu = cpu; - ), - - TP_printk("cpu=%d", __entry->cpu) -); -#endif /* _TRACE_SCHED_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/signal.h b/src/linux/include/trace/events/signal.h deleted file mode 100644 index 39a8a43..0000000 --- a/src/linux/include/trace/events/signal.h +++ /dev/null @@ -1,125 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM signal - -#if !defined(_TRACE_SIGNAL_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_SIGNAL_H - -#include -#include -#include - -#define TP_STORE_SIGINFO(__entry, info) \ - do { \ - if (info == SEND_SIG_NOINFO || \ - info == SEND_SIG_FORCED) { \ - __entry->errno = 0; \ - __entry->code = SI_USER; \ - } else if (info == SEND_SIG_PRIV) { \ - __entry->errno = 0; \ - __entry->code = SI_KERNEL; \ - } else { \ - __entry->errno = info->si_errno; \ - __entry->code = info->si_code; \ - } \ - } while (0) - -#ifndef TRACE_HEADER_MULTI_READ -enum { - TRACE_SIGNAL_DELIVERED, - TRACE_SIGNAL_IGNORED, - TRACE_SIGNAL_ALREADY_PENDING, - TRACE_SIGNAL_OVERFLOW_FAIL, - TRACE_SIGNAL_LOSE_INFO, -}; -#endif - -/** - * signal_generate - called when a signal is generated - * @sig: signal number - * @info: pointer to struct siginfo - * @task: pointer to struct task_struct - * @group: shared or private - * @result: TRACE_SIGNAL_* - * - * Current process sends a 'sig' signal to 'task' process with - * 'info' siginfo. If 'info' is SEND_SIG_NOINFO or SEND_SIG_PRIV, - * 'info' is not a pointer and you can't access its field. Instead, - * SEND_SIG_NOINFO means that si_code is SI_USER, and SEND_SIG_PRIV - * means that si_code is SI_KERNEL. - */ -TRACE_EVENT(signal_generate, - - TP_PROTO(int sig, struct siginfo *info, struct task_struct *task, - int group, int result), - - TP_ARGS(sig, info, task, group, result), - - TP_STRUCT__entry( - __field( int, sig ) - __field( int, errno ) - __field( int, code ) - __array( char, comm, TASK_COMM_LEN ) - __field( pid_t, pid ) - __field( int, group ) - __field( int, result ) - ), - - TP_fast_assign( - __entry->sig = sig; - TP_STORE_SIGINFO(__entry, info); - memcpy(__entry->comm, task->comm, TASK_COMM_LEN); - __entry->pid = task->pid; - __entry->group = group; - __entry->result = result; - ), - - TP_printk("sig=%d errno=%d code=%d comm=%s pid=%d grp=%d res=%d", - __entry->sig, __entry->errno, __entry->code, - __entry->comm, __entry->pid, __entry->group, - __entry->result) -); - -/** - * signal_deliver - called when a signal is delivered - * @sig: signal number - * @info: pointer to struct siginfo - * @ka: pointer to struct k_sigaction - * - * A 'sig' signal is delivered to current process with 'info' siginfo, - * and it will be handled by 'ka'. ka->sa.sa_handler can be SIG_IGN or - * SIG_DFL. - * Note that some signals reported by signal_generate tracepoint can be - * lost, ignored or modified (by debugger) before hitting this tracepoint. - * This means, this can show which signals are actually delivered, but - * matching generated signals and delivered signals may not be correct. - */ -TRACE_EVENT(signal_deliver, - - TP_PROTO(int sig, struct siginfo *info, struct k_sigaction *ka), - - TP_ARGS(sig, info, ka), - - TP_STRUCT__entry( - __field( int, sig ) - __field( int, errno ) - __field( int, code ) - __field( unsigned long, sa_handler ) - __field( unsigned long, sa_flags ) - ), - - TP_fast_assign( - __entry->sig = sig; - TP_STORE_SIGINFO(__entry, info); - __entry->sa_handler = (unsigned long)ka->sa.sa_handler; - __entry->sa_flags = ka->sa.sa_flags; - ), - - TP_printk("sig=%d errno=%d code=%d sa_handler=%lx sa_flags=%lx", - __entry->sig, __entry->errno, __entry->code, - __entry->sa_handler, __entry->sa_flags) -); - -#endif /* _TRACE_SIGNAL_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/skb.h b/src/linux/include/trace/events/skb.h deleted file mode 100644 index 0c68ae2..0000000 --- a/src/linux/include/trace/events/skb.h +++ /dev/null @@ -1,75 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM skb - -#if !defined(_TRACE_SKB_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_SKB_H - -#include -#include -#include - -/* - * Tracepoint for free an sk_buff: - */ -TRACE_EVENT(kfree_skb, - - TP_PROTO(struct sk_buff *skb, void *location), - - TP_ARGS(skb, location), - - TP_STRUCT__entry( - __field( void *, skbaddr ) - __field( void *, location ) - __field( unsigned short, protocol ) - ), - - TP_fast_assign( - __entry->skbaddr = skb; - __entry->location = location; - __entry->protocol = ntohs(skb->protocol); - ), - - TP_printk("skbaddr=%p protocol=%u location=%p", - __entry->skbaddr, __entry->protocol, __entry->location) -); - -TRACE_EVENT(consume_skb, - - TP_PROTO(struct sk_buff *skb), - - TP_ARGS(skb), - - TP_STRUCT__entry( - __field( void *, skbaddr ) - ), - - TP_fast_assign( - __entry->skbaddr = skb; - ), - - TP_printk("skbaddr=%p", __entry->skbaddr) -); - -TRACE_EVENT(skb_copy_datagram_iovec, - - TP_PROTO(const struct sk_buff *skb, int len), - - TP_ARGS(skb, len), - - TP_STRUCT__entry( - __field( const void *, skbaddr ) - __field( int, len ) - ), - - TP_fast_assign( - __entry->skbaddr = skb; - __entry->len = len; - ), - - TP_printk("skbaddr=%p len=%d", __entry->skbaddr, __entry->len) -); - -#endif /* _TRACE_SKB_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/sock.h b/src/linux/include/trace/events/sock.h deleted file mode 100644 index 779abb9..0000000 --- a/src/linux/include/trace/events/sock.h +++ /dev/null @@ -1,68 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM sock - -#if !defined(_TRACE_SOCK_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_SOCK_H - -#include -#include - -TRACE_EVENT(sock_rcvqueue_full, - - TP_PROTO(struct sock *sk, struct sk_buff *skb), - - TP_ARGS(sk, skb), - - TP_STRUCT__entry( - __field(int, rmem_alloc) - __field(unsigned int, truesize) - __field(int, sk_rcvbuf) - ), - - TP_fast_assign( - __entry->rmem_alloc = atomic_read(&sk->sk_rmem_alloc); - __entry->truesize = skb->truesize; - __entry->sk_rcvbuf = sk->sk_rcvbuf; - ), - - TP_printk("rmem_alloc=%d truesize=%u sk_rcvbuf=%d", - __entry->rmem_alloc, __entry->truesize, __entry->sk_rcvbuf) -); - -TRACE_EVENT(sock_exceed_buf_limit, - - TP_PROTO(struct sock *sk, struct proto *prot, long allocated), - - TP_ARGS(sk, prot, allocated), - - TP_STRUCT__entry( - __array(char, name, 32) - __field(long *, sysctl_mem) - __field(long, allocated) - __field(int, sysctl_rmem) - __field(int, rmem_alloc) - ), - - TP_fast_assign( - strncpy(__entry->name, prot->name, 32); - __entry->sysctl_mem = prot->sysctl_mem; - __entry->allocated = allocated; - __entry->sysctl_rmem = prot->sysctl_rmem[0]; - __entry->rmem_alloc = atomic_read(&sk->sk_rmem_alloc); - ), - - TP_printk("proto:%s sysctl_mem=%ld,%ld,%ld allocated=%ld " - "sysctl_rmem=%d rmem_alloc=%d", - __entry->name, - __entry->sysctl_mem[0], - __entry->sysctl_mem[1], - __entry->sysctl_mem[2], - __entry->allocated, - __entry->sysctl_rmem, - __entry->rmem_alloc) -); - -#endif /* _TRACE_SOCK_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/task.h b/src/linux/include/trace/events/task.h deleted file mode 100644 index 2cca6cd..0000000 --- a/src/linux/include/trace/events/task.h +++ /dev/null @@ -1,61 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM task - -#if !defined(_TRACE_TASK_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_TASK_H -#include - -TRACE_EVENT(task_newtask, - - TP_PROTO(struct task_struct *task, unsigned long clone_flags), - - TP_ARGS(task, clone_flags), - - TP_STRUCT__entry( - __field( pid_t, pid) - __array( char, comm, TASK_COMM_LEN) - __field( unsigned long, clone_flags) - __field( short, oom_score_adj) - ), - - TP_fast_assign( - __entry->pid = task->pid; - memcpy(__entry->comm, task->comm, TASK_COMM_LEN); - __entry->clone_flags = clone_flags; - __entry->oom_score_adj = task->signal->oom_score_adj; - ), - - TP_printk("pid=%d comm=%s clone_flags=%lx oom_score_adj=%hd", - __entry->pid, __entry->comm, - __entry->clone_flags, __entry->oom_score_adj) -); - -TRACE_EVENT(task_rename, - - TP_PROTO(struct task_struct *task, const char *comm), - - TP_ARGS(task, comm), - - TP_STRUCT__entry( - __field( pid_t, pid) - __array( char, oldcomm, TASK_COMM_LEN) - __array( char, newcomm, TASK_COMM_LEN) - __field( short, oom_score_adj) - ), - - TP_fast_assign( - __entry->pid = task->pid; - memcpy(entry->oldcomm, task->comm, TASK_COMM_LEN); - strlcpy(entry->newcomm, comm, TASK_COMM_LEN); - __entry->oom_score_adj = task->signal->oom_score_adj; - ), - - TP_printk("pid=%d oldcomm=%s newcomm=%s oom_score_adj=%hd", - __entry->pid, __entry->oldcomm, - __entry->newcomm, __entry->oom_score_adj) -); - -#endif - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/timer.h b/src/linux/include/trace/events/timer.h deleted file mode 100644 index 28c5da6..0000000 --- a/src/linux/include/trace/events/timer.h +++ /dev/null @@ -1,388 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM timer - -#if !defined(_TRACE_TIMER_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_TIMER_H - -#include -#include -#include - -DECLARE_EVENT_CLASS(timer_class, - - TP_PROTO(struct timer_list *timer), - - TP_ARGS(timer), - - TP_STRUCT__entry( - __field( void *, timer ) - ), - - TP_fast_assign( - __entry->timer = timer; - ), - - TP_printk("timer=%p", __entry->timer) -); - -/** - * timer_init - called when the timer is initialized - * @timer: pointer to struct timer_list - */ -DEFINE_EVENT(timer_class, timer_init, - - TP_PROTO(struct timer_list *timer), - - TP_ARGS(timer) -); - -/** - * timer_start - called when the timer is started - * @timer: pointer to struct timer_list - * @expires: the timers expiry time - */ -TRACE_EVENT(timer_start, - - TP_PROTO(struct timer_list *timer, - unsigned long expires, - unsigned int flags), - - TP_ARGS(timer, expires, flags), - - TP_STRUCT__entry( - __field( void *, timer ) - __field( void *, function ) - __field( unsigned long, expires ) - __field( unsigned long, now ) - __field( unsigned int, flags ) - ), - - TP_fast_assign( - __entry->timer = timer; - __entry->function = timer->function; - __entry->expires = expires; - __entry->now = jiffies; - __entry->flags = flags; - ), - - TP_printk("timer=%p function=%pf expires=%lu [timeout=%ld] flags=0x%08x", - __entry->timer, __entry->function, __entry->expires, - (long)__entry->expires - __entry->now, __entry->flags) -); - -/** - * timer_expire_entry - called immediately before the timer callback - * @timer: pointer to struct timer_list - * - * Allows to determine the timer latency. - */ -TRACE_EVENT(timer_expire_entry, - - TP_PROTO(struct timer_list *timer), - - TP_ARGS(timer), - - TP_STRUCT__entry( - __field( void *, timer ) - __field( unsigned long, now ) - __field( void *, function) - ), - - TP_fast_assign( - __entry->timer = timer; - __entry->now = jiffies; - __entry->function = timer->function; - ), - - TP_printk("timer=%p function=%pf now=%lu", __entry->timer, __entry->function,__entry->now) -); - -/** - * timer_expire_exit - called immediately after the timer callback returns - * @timer: pointer to struct timer_list - * - * When used in combination with the timer_expire_entry tracepoint we can - * determine the runtime of the timer callback function. - * - * NOTE: Do NOT derefernce timer in TP_fast_assign. The pointer might - * be invalid. We solely track the pointer. - */ -DEFINE_EVENT(timer_class, timer_expire_exit, - - TP_PROTO(struct timer_list *timer), - - TP_ARGS(timer) -); - -/** - * timer_cancel - called when the timer is canceled - * @timer: pointer to struct timer_list - */ -DEFINE_EVENT(timer_class, timer_cancel, - - TP_PROTO(struct timer_list *timer), - - TP_ARGS(timer) -); - -/** - * hrtimer_init - called when the hrtimer is initialized - * @hrtimer: pointer to struct hrtimer - * @clockid: the hrtimers clock - * @mode: the hrtimers mode - */ -TRACE_EVENT(hrtimer_init, - - TP_PROTO(struct hrtimer *hrtimer, clockid_t clockid, - enum hrtimer_mode mode), - - TP_ARGS(hrtimer, clockid, mode), - - TP_STRUCT__entry( - __field( void *, hrtimer ) - __field( clockid_t, clockid ) - __field( enum hrtimer_mode, mode ) - ), - - TP_fast_assign( - __entry->hrtimer = hrtimer; - __entry->clockid = clockid; - __entry->mode = mode; - ), - - TP_printk("hrtimer=%p clockid=%s mode=%s", __entry->hrtimer, - __entry->clockid == CLOCK_REALTIME ? - "CLOCK_REALTIME" : "CLOCK_MONOTONIC", - __entry->mode == HRTIMER_MODE_ABS ? - "HRTIMER_MODE_ABS" : "HRTIMER_MODE_REL") -); - -/** - * hrtimer_start - called when the hrtimer is started - * @hrtimer: pointer to struct hrtimer - */ -TRACE_EVENT(hrtimer_start, - - TP_PROTO(struct hrtimer *hrtimer), - - TP_ARGS(hrtimer), - - TP_STRUCT__entry( - __field( void *, hrtimer ) - __field( void *, function ) - __field( s64, expires ) - __field( s64, softexpires ) - ), - - TP_fast_assign( - __entry->hrtimer = hrtimer; - __entry->function = hrtimer->function; - __entry->expires = hrtimer_get_expires(hrtimer).tv64; - __entry->softexpires = hrtimer_get_softexpires(hrtimer).tv64; - ), - - TP_printk("hrtimer=%p function=%pf expires=%llu softexpires=%llu", - __entry->hrtimer, __entry->function, - (unsigned long long)ktime_to_ns((ktime_t) { - .tv64 = __entry->expires }), - (unsigned long long)ktime_to_ns((ktime_t) { - .tv64 = __entry->softexpires })) -); - -/** - * hrtimer_expire_entry - called immediately before the hrtimer callback - * @hrtimer: pointer to struct hrtimer - * @now: pointer to variable which contains current time of the - * timers base. - * - * Allows to determine the timer latency. - */ -TRACE_EVENT(hrtimer_expire_entry, - - TP_PROTO(struct hrtimer *hrtimer, ktime_t *now), - - TP_ARGS(hrtimer, now), - - TP_STRUCT__entry( - __field( void *, hrtimer ) - __field( s64, now ) - __field( void *, function) - ), - - TP_fast_assign( - __entry->hrtimer = hrtimer; - __entry->now = now->tv64; - __entry->function = hrtimer->function; - ), - - TP_printk("hrtimer=%p function=%pf now=%llu", __entry->hrtimer, __entry->function, - (unsigned long long)ktime_to_ns((ktime_t) { .tv64 = __entry->now })) - ); - -DECLARE_EVENT_CLASS(hrtimer_class, - - TP_PROTO(struct hrtimer *hrtimer), - - TP_ARGS(hrtimer), - - TP_STRUCT__entry( - __field( void *, hrtimer ) - ), - - TP_fast_assign( - __entry->hrtimer = hrtimer; - ), - - TP_printk("hrtimer=%p", __entry->hrtimer) -); - -/** - * hrtimer_expire_exit - called immediately after the hrtimer callback returns - * @hrtimer: pointer to struct hrtimer - * - * When used in combination with the hrtimer_expire_entry tracepoint we can - * determine the runtime of the callback function. - */ -DEFINE_EVENT(hrtimer_class, hrtimer_expire_exit, - - TP_PROTO(struct hrtimer *hrtimer), - - TP_ARGS(hrtimer) -); - -/** - * hrtimer_cancel - called when the hrtimer is canceled - * @hrtimer: pointer to struct hrtimer - */ -DEFINE_EVENT(hrtimer_class, hrtimer_cancel, - - TP_PROTO(struct hrtimer *hrtimer), - - TP_ARGS(hrtimer) -); - -/** - * itimer_state - called when itimer is started or canceled - * @which: name of the interval timer - * @value: the itimers value, itimer is canceled if value->it_value is - * zero, otherwise it is started - * @expires: the itimers expiry time - */ -TRACE_EVENT(itimer_state, - - TP_PROTO(int which, const struct itimerval *const value, - cputime_t expires), - - TP_ARGS(which, value, expires), - - TP_STRUCT__entry( - __field( int, which ) - __field( cputime_t, expires ) - __field( long, value_sec ) - __field( long, value_usec ) - __field( long, interval_sec ) - __field( long, interval_usec ) - ), - - TP_fast_assign( - __entry->which = which; - __entry->expires = expires; - __entry->value_sec = value->it_value.tv_sec; - __entry->value_usec = value->it_value.tv_usec; - __entry->interval_sec = value->it_interval.tv_sec; - __entry->interval_usec = value->it_interval.tv_usec; - ), - - TP_printk("which=%d expires=%llu it_value=%ld.%ld it_interval=%ld.%ld", - __entry->which, (unsigned long long)__entry->expires, - __entry->value_sec, __entry->value_usec, - __entry->interval_sec, __entry->interval_usec) -); - -/** - * itimer_expire - called when itimer expires - * @which: type of the interval timer - * @pid: pid of the process which owns the timer - * @now: current time, used to calculate the latency of itimer - */ -TRACE_EVENT(itimer_expire, - - TP_PROTO(int which, struct pid *pid, cputime_t now), - - TP_ARGS(which, pid, now), - - TP_STRUCT__entry( - __field( int , which ) - __field( pid_t, pid ) - __field( cputime_t, now ) - ), - - TP_fast_assign( - __entry->which = which; - __entry->now = now; - __entry->pid = pid_nr(pid); - ), - - TP_printk("which=%d pid=%d now=%llu", __entry->which, - (int) __entry->pid, (unsigned long long)__entry->now) -); - -#ifdef CONFIG_NO_HZ_COMMON - -#define TICK_DEP_NAMES \ - tick_dep_mask_name(NONE) \ - tick_dep_name(POSIX_TIMER) \ - tick_dep_name(PERF_EVENTS) \ - tick_dep_name(SCHED) \ - tick_dep_name_end(CLOCK_UNSTABLE) - -#undef tick_dep_name -#undef tick_dep_mask_name -#undef tick_dep_name_end - -/* The MASK will convert to their bits and they need to be processed too */ -#define tick_dep_name(sdep) TRACE_DEFINE_ENUM(TICK_DEP_BIT_##sdep); \ - TRACE_DEFINE_ENUM(TICK_DEP_MASK_##sdep); -#define tick_dep_name_end(sdep) TRACE_DEFINE_ENUM(TICK_DEP_BIT_##sdep); \ - TRACE_DEFINE_ENUM(TICK_DEP_MASK_##sdep); -/* NONE only has a mask defined for it */ -#define tick_dep_mask_name(sdep) TRACE_DEFINE_ENUM(TICK_DEP_MASK_##sdep); - -TICK_DEP_NAMES - -#undef tick_dep_name -#undef tick_dep_mask_name -#undef tick_dep_name_end - -#define tick_dep_name(sdep) { TICK_DEP_MASK_##sdep, #sdep }, -#define tick_dep_mask_name(sdep) { TICK_DEP_MASK_##sdep, #sdep }, -#define tick_dep_name_end(sdep) { TICK_DEP_MASK_##sdep, #sdep } - -#define show_tick_dep_name(val) \ - __print_symbolic(val, TICK_DEP_NAMES) - -TRACE_EVENT(tick_stop, - - TP_PROTO(int success, int dependency), - - TP_ARGS(success, dependency), - - TP_STRUCT__entry( - __field( int , success ) - __field( int , dependency ) - ), - - TP_fast_assign( - __entry->success = success; - __entry->dependency = dependency; - ), - - TP_printk("success=%d dependency=%s", __entry->success, \ - show_tick_dep_name(__entry->dependency)) -); -#endif - -#endif /* _TRACE_TIMER_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/udp.h b/src/linux/include/trace/events/udp.h deleted file mode 100644 index a664bb9..0000000 --- a/src/linux/include/trace/events/udp.h +++ /dev/null @@ -1,32 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM udp - -#if !defined(_TRACE_UDP_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_UDP_H - -#include -#include - -TRACE_EVENT(udp_fail_queue_rcv_skb, - - TP_PROTO(int rc, struct sock *sk), - - TP_ARGS(rc, sk), - - TP_STRUCT__entry( - __field(int, rc) - __field(__u16, lport) - ), - - TP_fast_assign( - __entry->rc = rc; - __entry->lport = inet_sk(sk)->inet_num; - ), - - TP_printk("rc=%d port=%hu", __entry->rc, __entry->lport) -); - -#endif /* _TRACE_UDP_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/vmscan.h b/src/linux/include/trace/events/vmscan.h deleted file mode 100644 index c88fd09..0000000 --- a/src/linux/include/trace/events/vmscan.h +++ /dev/null @@ -1,398 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM vmscan - -#if !defined(_TRACE_VMSCAN_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_VMSCAN_H - -#include -#include -#include -#include -#include - -#define RECLAIM_WB_ANON 0x0001u -#define RECLAIM_WB_FILE 0x0002u -#define RECLAIM_WB_MIXED 0x0010u -#define RECLAIM_WB_SYNC 0x0004u /* Unused, all reclaim async */ -#define RECLAIM_WB_ASYNC 0x0008u - -#define show_reclaim_flags(flags) \ - (flags) ? __print_flags(flags, "|", \ - {RECLAIM_WB_ANON, "RECLAIM_WB_ANON"}, \ - {RECLAIM_WB_FILE, "RECLAIM_WB_FILE"}, \ - {RECLAIM_WB_MIXED, "RECLAIM_WB_MIXED"}, \ - {RECLAIM_WB_SYNC, "RECLAIM_WB_SYNC"}, \ - {RECLAIM_WB_ASYNC, "RECLAIM_WB_ASYNC"} \ - ) : "RECLAIM_WB_NONE" - -#define trace_reclaim_flags(page) ( \ - (page_is_file_cache(page) ? RECLAIM_WB_FILE : RECLAIM_WB_ANON) | \ - (RECLAIM_WB_ASYNC) \ - ) - -#define trace_shrink_flags(file) \ - ( \ - (file ? RECLAIM_WB_FILE : RECLAIM_WB_ANON) | \ - (RECLAIM_WB_ASYNC) \ - ) - -TRACE_EVENT(mm_vmscan_kswapd_sleep, - - TP_PROTO(int nid), - - TP_ARGS(nid), - - TP_STRUCT__entry( - __field( int, nid ) - ), - - TP_fast_assign( - __entry->nid = nid; - ), - - TP_printk("nid=%d", __entry->nid) -); - -TRACE_EVENT(mm_vmscan_kswapd_wake, - - TP_PROTO(int nid, int zid, int order), - - TP_ARGS(nid, zid, order), - - TP_STRUCT__entry( - __field( int, nid ) - __field( int, zid ) - __field( int, order ) - ), - - TP_fast_assign( - __entry->nid = nid; - __entry->zid = zid; - __entry->order = order; - ), - - TP_printk("nid=%d zid=%d order=%d", __entry->nid, __entry->zid, __entry->order) -); - -TRACE_EVENT(mm_vmscan_wakeup_kswapd, - - TP_PROTO(int nid, int zid, int order), - - TP_ARGS(nid, zid, order), - - TP_STRUCT__entry( - __field( int, nid ) - __field( int, zid ) - __field( int, order ) - ), - - TP_fast_assign( - __entry->nid = nid; - __entry->zid = zid; - __entry->order = order; - ), - - TP_printk("nid=%d zid=%d order=%d", - __entry->nid, - __entry->zid, - __entry->order) -); - -DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_begin_template, - - TP_PROTO(int order, int may_writepage, gfp_t gfp_flags, int classzone_idx), - - TP_ARGS(order, may_writepage, gfp_flags, classzone_idx), - - TP_STRUCT__entry( - __field( int, order ) - __field( int, may_writepage ) - __field( gfp_t, gfp_flags ) - __field( int, classzone_idx ) - ), - - TP_fast_assign( - __entry->order = order; - __entry->may_writepage = may_writepage; - __entry->gfp_flags = gfp_flags; - __entry->classzone_idx = classzone_idx; - ), - - TP_printk("order=%d may_writepage=%d gfp_flags=%s classzone_idx=%d", - __entry->order, - __entry->may_writepage, - show_gfp_flags(__entry->gfp_flags), - __entry->classzone_idx) -); - -DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_direct_reclaim_begin, - - TP_PROTO(int order, int may_writepage, gfp_t gfp_flags, int classzone_idx), - - TP_ARGS(order, may_writepage, gfp_flags, classzone_idx) -); - -DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_memcg_reclaim_begin, - - TP_PROTO(int order, int may_writepage, gfp_t gfp_flags, int classzone_idx), - - TP_ARGS(order, may_writepage, gfp_flags, classzone_idx) -); - -DEFINE_EVENT(mm_vmscan_direct_reclaim_begin_template, mm_vmscan_memcg_softlimit_reclaim_begin, - - TP_PROTO(int order, int may_writepage, gfp_t gfp_flags, int classzone_idx), - - TP_ARGS(order, may_writepage, gfp_flags, classzone_idx) -); - -DECLARE_EVENT_CLASS(mm_vmscan_direct_reclaim_end_template, - - TP_PROTO(unsigned long nr_reclaimed), - - TP_ARGS(nr_reclaimed), - - TP_STRUCT__entry( - __field( unsigned long, nr_reclaimed ) - ), - - TP_fast_assign( - __entry->nr_reclaimed = nr_reclaimed; - ), - - TP_printk("nr_reclaimed=%lu", __entry->nr_reclaimed) -); - -DEFINE_EVENT(mm_vmscan_direct_reclaim_end_template, mm_vmscan_direct_reclaim_end, - - TP_PROTO(unsigned long nr_reclaimed), - - TP_ARGS(nr_reclaimed) -); - -DEFINE_EVENT(mm_vmscan_direct_reclaim_end_template, mm_vmscan_memcg_reclaim_end, - - TP_PROTO(unsigned long nr_reclaimed), - - TP_ARGS(nr_reclaimed) -); - -DEFINE_EVENT(mm_vmscan_direct_reclaim_end_template, mm_vmscan_memcg_softlimit_reclaim_end, - - TP_PROTO(unsigned long nr_reclaimed), - - TP_ARGS(nr_reclaimed) -); - -TRACE_EVENT(mm_shrink_slab_start, - TP_PROTO(struct shrinker *shr, struct shrink_control *sc, - long nr_objects_to_shrink, unsigned long pgs_scanned, - unsigned long lru_pgs, unsigned long cache_items, - unsigned long long delta, unsigned long total_scan), - - TP_ARGS(shr, sc, nr_objects_to_shrink, pgs_scanned, lru_pgs, - cache_items, delta, total_scan), - - TP_STRUCT__entry( - __field(struct shrinker *, shr) - __field(void *, shrink) - __field(int, nid) - __field(long, nr_objects_to_shrink) - __field(gfp_t, gfp_flags) - __field(unsigned long, pgs_scanned) - __field(unsigned long, lru_pgs) - __field(unsigned long, cache_items) - __field(unsigned long long, delta) - __field(unsigned long, total_scan) - ), - - TP_fast_assign( - __entry->shr = shr; - __entry->shrink = shr->scan_objects; - __entry->nid = sc->nid; - __entry->nr_objects_to_shrink = nr_objects_to_shrink; - __entry->gfp_flags = sc->gfp_mask; - __entry->pgs_scanned = pgs_scanned; - __entry->lru_pgs = lru_pgs; - __entry->cache_items = cache_items; - __entry->delta = delta; - __entry->total_scan = total_scan; - ), - - TP_printk("%pF %p: nid: %d objects to shrink %ld gfp_flags %s pgs_scanned %ld lru_pgs %ld cache items %ld delta %lld total_scan %ld", - __entry->shrink, - __entry->shr, - __entry->nid, - __entry->nr_objects_to_shrink, - show_gfp_flags(__entry->gfp_flags), - __entry->pgs_scanned, - __entry->lru_pgs, - __entry->cache_items, - __entry->delta, - __entry->total_scan) -); - -TRACE_EVENT(mm_shrink_slab_end, - TP_PROTO(struct shrinker *shr, int nid, int shrinker_retval, - long unused_scan_cnt, long new_scan_cnt, long total_scan), - - TP_ARGS(shr, nid, shrinker_retval, unused_scan_cnt, new_scan_cnt, - total_scan), - - TP_STRUCT__entry( - __field(struct shrinker *, shr) - __field(int, nid) - __field(void *, shrink) - __field(long, unused_scan) - __field(long, new_scan) - __field(int, retval) - __field(long, total_scan) - ), - - TP_fast_assign( - __entry->shr = shr; - __entry->nid = nid; - __entry->shrink = shr->scan_objects; - __entry->unused_scan = unused_scan_cnt; - __entry->new_scan = new_scan_cnt; - __entry->retval = shrinker_retval; - __entry->total_scan = total_scan; - ), - - TP_printk("%pF %p: nid: %d unused scan count %ld new scan count %ld total_scan %ld last shrinker return val %d", - __entry->shrink, - __entry->shr, - __entry->nid, - __entry->unused_scan, - __entry->new_scan, - __entry->total_scan, - __entry->retval) -); - -DECLARE_EVENT_CLASS(mm_vmscan_lru_isolate_template, - - TP_PROTO(int classzone_idx, - int order, - unsigned long nr_requested, - unsigned long nr_scanned, - unsigned long nr_taken, - isolate_mode_t isolate_mode, - int file), - - TP_ARGS(classzone_idx, order, nr_requested, nr_scanned, nr_taken, isolate_mode, file), - - TP_STRUCT__entry( - __field(int, classzone_idx) - __field(int, order) - __field(unsigned long, nr_requested) - __field(unsigned long, nr_scanned) - __field(unsigned long, nr_taken) - __field(isolate_mode_t, isolate_mode) - __field(int, file) - ), - - TP_fast_assign( - __entry->classzone_idx = classzone_idx; - __entry->order = order; - __entry->nr_requested = nr_requested; - __entry->nr_scanned = nr_scanned; - __entry->nr_taken = nr_taken; - __entry->isolate_mode = isolate_mode; - __entry->file = file; - ), - - TP_printk("isolate_mode=%d classzone=%d order=%d nr_requested=%lu nr_scanned=%lu nr_taken=%lu file=%d", - __entry->isolate_mode, - __entry->classzone_idx, - __entry->order, - __entry->nr_requested, - __entry->nr_scanned, - __entry->nr_taken, - __entry->file) -); - -DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_lru_isolate, - - TP_PROTO(int classzone_idx, - int order, - unsigned long nr_requested, - unsigned long nr_scanned, - unsigned long nr_taken, - isolate_mode_t isolate_mode, - int file), - - TP_ARGS(classzone_idx, order, nr_requested, nr_scanned, nr_taken, isolate_mode, file) - -); - -DEFINE_EVENT(mm_vmscan_lru_isolate_template, mm_vmscan_memcg_isolate, - - TP_PROTO(int classzone_idx, - int order, - unsigned long nr_requested, - unsigned long nr_scanned, - unsigned long nr_taken, - isolate_mode_t isolate_mode, - int file), - - TP_ARGS(classzone_idx, order, nr_requested, nr_scanned, nr_taken, isolate_mode, file) - -); - -TRACE_EVENT(mm_vmscan_writepage, - - TP_PROTO(struct page *page), - - TP_ARGS(page), - - TP_STRUCT__entry( - __field(unsigned long, pfn) - __field(int, reclaim_flags) - ), - - TP_fast_assign( - __entry->pfn = page_to_pfn(page); - __entry->reclaim_flags = trace_reclaim_flags(page); - ), - - TP_printk("page=%p pfn=%lu flags=%s", - pfn_to_page(__entry->pfn), - __entry->pfn, - show_reclaim_flags(__entry->reclaim_flags)) -); - -TRACE_EVENT(mm_vmscan_lru_shrink_inactive, - - TP_PROTO(int nid, - unsigned long nr_scanned, unsigned long nr_reclaimed, - int priority, int file), - - TP_ARGS(nid, nr_scanned, nr_reclaimed, priority, file), - - TP_STRUCT__entry( - __field(int, nid) - __field(unsigned long, nr_scanned) - __field(unsigned long, nr_reclaimed) - __field(int, priority) - __field(int, reclaim_flags) - ), - - TP_fast_assign( - __entry->nid = nid; - __entry->nr_scanned = nr_scanned; - __entry->nr_reclaimed = nr_reclaimed; - __entry->priority = priority; - __entry->reclaim_flags = trace_shrink_flags(file); - ), - - TP_printk("nid=%d nr_scanned=%ld nr_reclaimed=%ld priority=%d flags=%s", - __entry->nid, - __entry->nr_scanned, __entry->nr_reclaimed, - __entry->priority, - show_reclaim_flags(__entry->reclaim_flags)) -); - -#endif /* _TRACE_VMSCAN_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/workqueue.h b/src/linux/include/trace/events/workqueue.h deleted file mode 100644 index bf0e18b..0000000 --- a/src/linux/include/trace/events/workqueue.h +++ /dev/null @@ -1,121 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM workqueue - -#if !defined(_TRACE_WORKQUEUE_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_WORKQUEUE_H - -#include -#include - -DECLARE_EVENT_CLASS(workqueue_work, - - TP_PROTO(struct work_struct *work), - - TP_ARGS(work), - - TP_STRUCT__entry( - __field( void *, work ) - ), - - TP_fast_assign( - __entry->work = work; - ), - - TP_printk("work struct %p", __entry->work) -); - -/** - * workqueue_queue_work - called when a work gets queued - * @req_cpu: the requested cpu - * @pwq: pointer to struct pool_workqueue - * @work: pointer to struct work_struct - * - * This event occurs when a work is queued immediately or once a - * delayed work is actually queued on a workqueue (ie: once the delay - * has been reached). - */ -TRACE_EVENT(workqueue_queue_work, - - TP_PROTO(unsigned int req_cpu, struct pool_workqueue *pwq, - struct work_struct *work), - - TP_ARGS(req_cpu, pwq, work), - - TP_STRUCT__entry( - __field( void *, work ) - __field( void *, function) - __field( void *, workqueue) - __field( unsigned int, req_cpu ) - __field( unsigned int, cpu ) - ), - - TP_fast_assign( - __entry->work = work; - __entry->function = work->func; - __entry->workqueue = pwq->wq; - __entry->req_cpu = req_cpu; - __entry->cpu = pwq->pool->cpu; - ), - - TP_printk("work struct=%p function=%pf workqueue=%p req_cpu=%u cpu=%u", - __entry->work, __entry->function, __entry->workqueue, - __entry->req_cpu, __entry->cpu) -); - -/** - * workqueue_activate_work - called when a work gets activated - * @work: pointer to struct work_struct - * - * This event occurs when a queued work is put on the active queue, - * which happens immediately after queueing unless @max_active limit - * is reached. - */ -DEFINE_EVENT(workqueue_work, workqueue_activate_work, - - TP_PROTO(struct work_struct *work), - - TP_ARGS(work) -); - -/** - * workqueue_execute_start - called immediately before the workqueue callback - * @work: pointer to struct work_struct - * - * Allows to track workqueue execution. - */ -TRACE_EVENT(workqueue_execute_start, - - TP_PROTO(struct work_struct *work), - - TP_ARGS(work), - - TP_STRUCT__entry( - __field( void *, work ) - __field( void *, function) - ), - - TP_fast_assign( - __entry->work = work; - __entry->function = work->func; - ), - - TP_printk("work struct %p: function %pf", __entry->work, __entry->function) -); - -/** - * workqueue_execute_end - called immediately after the workqueue callback - * @work: pointer to struct work_struct - * - * Allows to track workqueue execution. - */ -DEFINE_EVENT(workqueue_work, workqueue_execute_end, - - TP_PROTO(struct work_struct *work), - - TP_ARGS(work) -); - -#endif /* _TRACE_WORKQUEUE_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/events/writeback.h b/src/linux/include/trace/events/writeback.h deleted file mode 100644 index 2ccd9cc..0000000 --- a/src/linux/include/trace/events/writeback.h +++ /dev/null @@ -1,762 +0,0 @@ -#undef TRACE_SYSTEM -#define TRACE_SYSTEM writeback - -#if !defined(_TRACE_WRITEBACK_H) || defined(TRACE_HEADER_MULTI_READ) -#define _TRACE_WRITEBACK_H - -#include -#include -#include - -#define show_inode_state(state) \ - __print_flags(state, "|", \ - {I_DIRTY_SYNC, "I_DIRTY_SYNC"}, \ - {I_DIRTY_DATASYNC, "I_DIRTY_DATASYNC"}, \ - {I_DIRTY_PAGES, "I_DIRTY_PAGES"}, \ - {I_NEW, "I_NEW"}, \ - {I_WILL_FREE, "I_WILL_FREE"}, \ - {I_FREEING, "I_FREEING"}, \ - {I_CLEAR, "I_CLEAR"}, \ - {I_SYNC, "I_SYNC"}, \ - {I_DIRTY_TIME, "I_DIRTY_TIME"}, \ - {I_DIRTY_TIME_EXPIRED, "I_DIRTY_TIME_EXPIRED"}, \ - {I_REFERENCED, "I_REFERENCED"} \ - ) - -/* enums need to be exported to user space */ -#undef EM -#undef EMe -#define EM(a,b) TRACE_DEFINE_ENUM(a); -#define EMe(a,b) TRACE_DEFINE_ENUM(a); - -#define WB_WORK_REASON \ - EM( WB_REASON_BACKGROUND, "background") \ - EM( WB_REASON_TRY_TO_FREE_PAGES, "try_to_free_pages") \ - EM( WB_REASON_SYNC, "sync") \ - EM( WB_REASON_PERIODIC, "periodic") \ - EM( WB_REASON_LAPTOP_TIMER, "laptop_timer") \ - EM( WB_REASON_FREE_MORE_MEM, "free_more_memory") \ - EM( WB_REASON_FS_FREE_SPACE, "fs_free_space") \ - EMe(WB_REASON_FORKER_THREAD, "forker_thread") - -WB_WORK_REASON - -/* - * Now redefine the EM() and EMe() macros to map the enums to the strings - * that will be printed in the output. - */ -#undef EM -#undef EMe -#define EM(a,b) { a, b }, -#define EMe(a,b) { a, b } - -struct wb_writeback_work; - -TRACE_EVENT(writeback_dirty_page, - - TP_PROTO(struct page *page, struct address_space *mapping), - - TP_ARGS(page, mapping), - - TP_STRUCT__entry ( - __array(char, name, 32) - __field(unsigned long, ino) - __field(pgoff_t, index) - ), - - TP_fast_assign( - strncpy(__entry->name, - mapping ? dev_name(inode_to_bdi(mapping->host)->dev) : "(unknown)", 32); - __entry->ino = mapping ? mapping->host->i_ino : 0; - __entry->index = page->index; - ), - - TP_printk("bdi %s: ino=%lu index=%lu", - __entry->name, - __entry->ino, - __entry->index - ) -); - -DECLARE_EVENT_CLASS(writeback_dirty_inode_template, - - TP_PROTO(struct inode *inode, int flags), - - TP_ARGS(inode, flags), - - TP_STRUCT__entry ( - __array(char, name, 32) - __field(unsigned long, ino) - __field(unsigned long, state) - __field(unsigned long, flags) - ), - - TP_fast_assign( - struct backing_dev_info *bdi = inode_to_bdi(inode); - - /* may be called for files on pseudo FSes w/ unregistered bdi */ - strncpy(__entry->name, - bdi->dev ? dev_name(bdi->dev) : "(unknown)", 32); - __entry->ino = inode->i_ino; - __entry->state = inode->i_state; - __entry->flags = flags; - ), - - TP_printk("bdi %s: ino=%lu state=%s flags=%s", - __entry->name, - __entry->ino, - show_inode_state(__entry->state), - show_inode_state(__entry->flags) - ) -); - -DEFINE_EVENT(writeback_dirty_inode_template, writeback_mark_inode_dirty, - - TP_PROTO(struct inode *inode, int flags), - - TP_ARGS(inode, flags) -); - -DEFINE_EVENT(writeback_dirty_inode_template, writeback_dirty_inode_start, - - TP_PROTO(struct inode *inode, int flags), - - TP_ARGS(inode, flags) -); - -DEFINE_EVENT(writeback_dirty_inode_template, writeback_dirty_inode, - - TP_PROTO(struct inode *inode, int flags), - - TP_ARGS(inode, flags) -); - -#ifdef CREATE_TRACE_POINTS -#ifdef CONFIG_CGROUP_WRITEBACK - -static inline unsigned int __trace_wb_assign_cgroup(struct bdi_writeback *wb) -{ - return wb->memcg_css->cgroup->kn->ino; -} - -static inline unsigned int __trace_wbc_assign_cgroup(struct writeback_control *wbc) -{ - if (wbc->wb) - return __trace_wb_assign_cgroup(wbc->wb); - else - return -1U; -} -#else /* CONFIG_CGROUP_WRITEBACK */ - -static inline unsigned int __trace_wb_assign_cgroup(struct bdi_writeback *wb) -{ - return -1U; -} - -static inline unsigned int __trace_wbc_assign_cgroup(struct writeback_control *wbc) -{ - return -1U; -} - -#endif /* CONFIG_CGROUP_WRITEBACK */ -#endif /* CREATE_TRACE_POINTS */ - -DECLARE_EVENT_CLASS(writeback_write_inode_template, - - TP_PROTO(struct inode *inode, struct writeback_control *wbc), - - TP_ARGS(inode, wbc), - - TP_STRUCT__entry ( - __array(char, name, 32) - __field(unsigned long, ino) - __field(int, sync_mode) - __field(unsigned int, cgroup_ino) - ), - - TP_fast_assign( - strncpy(__entry->name, - dev_name(inode_to_bdi(inode)->dev), 32); - __entry->ino = inode->i_ino; - __entry->sync_mode = wbc->sync_mode; - __entry->cgroup_ino = __trace_wbc_assign_cgroup(wbc); - ), - - TP_printk("bdi %s: ino=%lu sync_mode=%d cgroup_ino=%u", - __entry->name, - __entry->ino, - __entry->sync_mode, - __entry->cgroup_ino - ) -); - -DEFINE_EVENT(writeback_write_inode_template, writeback_write_inode_start, - - TP_PROTO(struct inode *inode, struct writeback_control *wbc), - - TP_ARGS(inode, wbc) -); - -DEFINE_EVENT(writeback_write_inode_template, writeback_write_inode, - - TP_PROTO(struct inode *inode, struct writeback_control *wbc), - - TP_ARGS(inode, wbc) -); - -DECLARE_EVENT_CLASS(writeback_work_class, - TP_PROTO(struct bdi_writeback *wb, struct wb_writeback_work *work), - TP_ARGS(wb, work), - TP_STRUCT__entry( - __array(char, name, 32) - __field(long, nr_pages) - __field(dev_t, sb_dev) - __field(int, sync_mode) - __field(int, for_kupdate) - __field(int, range_cyclic) - __field(int, for_background) - __field(int, reason) - __field(unsigned int, cgroup_ino) - ), - TP_fast_assign( - strncpy(__entry->name, - wb->bdi->dev ? dev_name(wb->bdi->dev) : "(unknown)", 32); - __entry->nr_pages = work->nr_pages; - __entry->sb_dev = work->sb ? work->sb->s_dev : 0; - __entry->sync_mode = work->sync_mode; - __entry->for_kupdate = work->for_kupdate; - __entry->range_cyclic = work->range_cyclic; - __entry->for_background = work->for_background; - __entry->reason = work->reason; - __entry->cgroup_ino = __trace_wb_assign_cgroup(wb); - ), - TP_printk("bdi %s: sb_dev %d:%d nr_pages=%ld sync_mode=%d " - "kupdate=%d range_cyclic=%d background=%d reason=%s cgroup_ino=%u", - __entry->name, - MAJOR(__entry->sb_dev), MINOR(__entry->sb_dev), - __entry->nr_pages, - __entry->sync_mode, - __entry->for_kupdate, - __entry->range_cyclic, - __entry->for_background, - __print_symbolic(__entry->reason, WB_WORK_REASON), - __entry->cgroup_ino - ) -); -#define DEFINE_WRITEBACK_WORK_EVENT(name) \ -DEFINE_EVENT(writeback_work_class, name, \ - TP_PROTO(struct bdi_writeback *wb, struct wb_writeback_work *work), \ - TP_ARGS(wb, work)) -DEFINE_WRITEBACK_WORK_EVENT(writeback_queue); -DEFINE_WRITEBACK_WORK_EVENT(writeback_exec); -DEFINE_WRITEBACK_WORK_EVENT(writeback_start); -DEFINE_WRITEBACK_WORK_EVENT(writeback_written); -DEFINE_WRITEBACK_WORK_EVENT(writeback_wait); - -TRACE_EVENT(writeback_pages_written, - TP_PROTO(long pages_written), - TP_ARGS(pages_written), - TP_STRUCT__entry( - __field(long, pages) - ), - TP_fast_assign( - __entry->pages = pages_written; - ), - TP_printk("%ld", __entry->pages) -); - -DECLARE_EVENT_CLASS(writeback_class, - TP_PROTO(struct bdi_writeback *wb), - TP_ARGS(wb), - TP_STRUCT__entry( - __array(char, name, 32) - __field(unsigned int, cgroup_ino) - ), - TP_fast_assign( - strncpy(__entry->name, dev_name(wb->bdi->dev), 32); - __entry->cgroup_ino = __trace_wb_assign_cgroup(wb); - ), - TP_printk("bdi %s: cgroup_ino=%u", - __entry->name, - __entry->cgroup_ino - ) -); -#define DEFINE_WRITEBACK_EVENT(name) \ -DEFINE_EVENT(writeback_class, name, \ - TP_PROTO(struct bdi_writeback *wb), \ - TP_ARGS(wb)) - -DEFINE_WRITEBACK_EVENT(writeback_nowork); -DEFINE_WRITEBACK_EVENT(writeback_wake_background); - -TRACE_EVENT(writeback_bdi_register, - TP_PROTO(struct backing_dev_info *bdi), - TP_ARGS(bdi), - TP_STRUCT__entry( - __array(char, name, 32) - ), - TP_fast_assign( - strncpy(__entry->name, dev_name(bdi->dev), 32); - ), - TP_printk("bdi %s", - __entry->name - ) -); - -DECLARE_EVENT_CLASS(wbc_class, - TP_PROTO(struct writeback_control *wbc, struct backing_dev_info *bdi), - TP_ARGS(wbc, bdi), - TP_STRUCT__entry( - __array(char, name, 32) - __field(long, nr_to_write) - __field(long, pages_skipped) - __field(int, sync_mode) - __field(int, for_kupdate) - __field(int, for_background) - __field(int, for_reclaim) - __field(int, range_cyclic) - __field(long, range_start) - __field(long, range_end) - __field(unsigned int, cgroup_ino) - ), - - TP_fast_assign( - strncpy(__entry->name, dev_name(bdi->dev), 32); - __entry->nr_to_write = wbc->nr_to_write; - __entry->pages_skipped = wbc->pages_skipped; - __entry->sync_mode = wbc->sync_mode; - __entry->for_kupdate = wbc->for_kupdate; - __entry->for_background = wbc->for_background; - __entry->for_reclaim = wbc->for_reclaim; - __entry->range_cyclic = wbc->range_cyclic; - __entry->range_start = (long)wbc->range_start; - __entry->range_end = (long)wbc->range_end; - __entry->cgroup_ino = __trace_wbc_assign_cgroup(wbc); - ), - - TP_printk("bdi %s: towrt=%ld skip=%ld mode=%d kupd=%d " - "bgrd=%d reclm=%d cyclic=%d " - "start=0x%lx end=0x%lx cgroup_ino=%u", - __entry->name, - __entry->nr_to_write, - __entry->pages_skipped, - __entry->sync_mode, - __entry->for_kupdate, - __entry->for_background, - __entry->for_reclaim, - __entry->range_cyclic, - __entry->range_start, - __entry->range_end, - __entry->cgroup_ino - ) -) - -#define DEFINE_WBC_EVENT(name) \ -DEFINE_EVENT(wbc_class, name, \ - TP_PROTO(struct writeback_control *wbc, struct backing_dev_info *bdi), \ - TP_ARGS(wbc, bdi)) -DEFINE_WBC_EVENT(wbc_writepage); - -TRACE_EVENT(writeback_queue_io, - TP_PROTO(struct bdi_writeback *wb, - struct wb_writeback_work *work, - int moved), - TP_ARGS(wb, work, moved), - TP_STRUCT__entry( - __array(char, name, 32) - __field(unsigned long, older) - __field(long, age) - __field(int, moved) - __field(int, reason) - __field(unsigned int, cgroup_ino) - ), - TP_fast_assign( - unsigned long *older_than_this = work->older_than_this; - strncpy(__entry->name, dev_name(wb->bdi->dev), 32); - __entry->older = older_than_this ? *older_than_this : 0; - __entry->age = older_than_this ? - (jiffies - *older_than_this) * 1000 / HZ : -1; - __entry->moved = moved; - __entry->reason = work->reason; - __entry->cgroup_ino = __trace_wb_assign_cgroup(wb); - ), - TP_printk("bdi %s: older=%lu age=%ld enqueue=%d reason=%s cgroup_ino=%u", - __entry->name, - __entry->older, /* older_than_this in jiffies */ - __entry->age, /* older_than_this in relative milliseconds */ - __entry->moved, - __print_symbolic(__entry->reason, WB_WORK_REASON), - __entry->cgroup_ino - ) -); - -TRACE_EVENT(global_dirty_state, - - TP_PROTO(unsigned long background_thresh, - unsigned long dirty_thresh - ), - - TP_ARGS(background_thresh, - dirty_thresh - ), - - TP_STRUCT__entry( - __field(unsigned long, nr_dirty) - __field(unsigned long, nr_writeback) - __field(unsigned long, nr_unstable) - __field(unsigned long, background_thresh) - __field(unsigned long, dirty_thresh) - __field(unsigned long, dirty_limit) - __field(unsigned long, nr_dirtied) - __field(unsigned long, nr_written) - ), - - TP_fast_assign( - __entry->nr_dirty = global_node_page_state(NR_FILE_DIRTY); - __entry->nr_writeback = global_node_page_state(NR_WRITEBACK); - __entry->nr_unstable = global_node_page_state(NR_UNSTABLE_NFS); - __entry->nr_dirtied = global_node_page_state(NR_DIRTIED); - __entry->nr_written = global_node_page_state(NR_WRITTEN); - __entry->background_thresh = background_thresh; - __entry->dirty_thresh = dirty_thresh; - __entry->dirty_limit = global_wb_domain.dirty_limit; - ), - - TP_printk("dirty=%lu writeback=%lu unstable=%lu " - "bg_thresh=%lu thresh=%lu limit=%lu " - "dirtied=%lu written=%lu", - __entry->nr_dirty, - __entry->nr_writeback, - __entry->nr_unstable, - __entry->background_thresh, - __entry->dirty_thresh, - __entry->dirty_limit, - __entry->nr_dirtied, - __entry->nr_written - ) -); - -#define KBps(x) ((x) << (PAGE_SHIFT - 10)) - -TRACE_EVENT(bdi_dirty_ratelimit, - - TP_PROTO(struct bdi_writeback *wb, - unsigned long dirty_rate, - unsigned long task_ratelimit), - - TP_ARGS(wb, dirty_rate, task_ratelimit), - - TP_STRUCT__entry( - __array(char, bdi, 32) - __field(unsigned long, write_bw) - __field(unsigned long, avg_write_bw) - __field(unsigned long, dirty_rate) - __field(unsigned long, dirty_ratelimit) - __field(unsigned long, task_ratelimit) - __field(unsigned long, balanced_dirty_ratelimit) - __field(unsigned int, cgroup_ino) - ), - - TP_fast_assign( - strlcpy(__entry->bdi, dev_name(wb->bdi->dev), 32); - __entry->write_bw = KBps(wb->write_bandwidth); - __entry->avg_write_bw = KBps(wb->avg_write_bandwidth); - __entry->dirty_rate = KBps(dirty_rate); - __entry->dirty_ratelimit = KBps(wb->dirty_ratelimit); - __entry->task_ratelimit = KBps(task_ratelimit); - __entry->balanced_dirty_ratelimit = - KBps(wb->balanced_dirty_ratelimit); - __entry->cgroup_ino = __trace_wb_assign_cgroup(wb); - ), - - TP_printk("bdi %s: " - "write_bw=%lu awrite_bw=%lu dirty_rate=%lu " - "dirty_ratelimit=%lu task_ratelimit=%lu " - "balanced_dirty_ratelimit=%lu cgroup_ino=%u", - __entry->bdi, - __entry->write_bw, /* write bandwidth */ - __entry->avg_write_bw, /* avg write bandwidth */ - __entry->dirty_rate, /* bdi dirty rate */ - __entry->dirty_ratelimit, /* base ratelimit */ - __entry->task_ratelimit, /* ratelimit with position control */ - __entry->balanced_dirty_ratelimit, /* the balanced ratelimit */ - __entry->cgroup_ino - ) -); - -TRACE_EVENT(balance_dirty_pages, - - TP_PROTO(struct bdi_writeback *wb, - unsigned long thresh, - unsigned long bg_thresh, - unsigned long dirty, - unsigned long bdi_thresh, - unsigned long bdi_dirty, - unsigned long dirty_ratelimit, - unsigned long task_ratelimit, - unsigned long dirtied, - unsigned long period, - long pause, - unsigned long start_time), - - TP_ARGS(wb, thresh, bg_thresh, dirty, bdi_thresh, bdi_dirty, - dirty_ratelimit, task_ratelimit, - dirtied, period, pause, start_time), - - TP_STRUCT__entry( - __array( char, bdi, 32) - __field(unsigned long, limit) - __field(unsigned long, setpoint) - __field(unsigned long, dirty) - __field(unsigned long, bdi_setpoint) - __field(unsigned long, bdi_dirty) - __field(unsigned long, dirty_ratelimit) - __field(unsigned long, task_ratelimit) - __field(unsigned int, dirtied) - __field(unsigned int, dirtied_pause) - __field(unsigned long, paused) - __field( long, pause) - __field(unsigned long, period) - __field( long, think) - __field(unsigned int, cgroup_ino) - ), - - TP_fast_assign( - unsigned long freerun = (thresh + bg_thresh) / 2; - strlcpy(__entry->bdi, dev_name(wb->bdi->dev), 32); - - __entry->limit = global_wb_domain.dirty_limit; - __entry->setpoint = (global_wb_domain.dirty_limit + - freerun) / 2; - __entry->dirty = dirty; - __entry->bdi_setpoint = __entry->setpoint * - bdi_thresh / (thresh + 1); - __entry->bdi_dirty = bdi_dirty; - __entry->dirty_ratelimit = KBps(dirty_ratelimit); - __entry->task_ratelimit = KBps(task_ratelimit); - __entry->dirtied = dirtied; - __entry->dirtied_pause = current->nr_dirtied_pause; - __entry->think = current->dirty_paused_when == 0 ? 0 : - (long)(jiffies - current->dirty_paused_when) * 1000/HZ; - __entry->period = period * 1000 / HZ; - __entry->pause = pause * 1000 / HZ; - __entry->paused = (jiffies - start_time) * 1000 / HZ; - __entry->cgroup_ino = __trace_wb_assign_cgroup(wb); - ), - - - TP_printk("bdi %s: " - "limit=%lu setpoint=%lu dirty=%lu " - "bdi_setpoint=%lu bdi_dirty=%lu " - "dirty_ratelimit=%lu task_ratelimit=%lu " - "dirtied=%u dirtied_pause=%u " - "paused=%lu pause=%ld period=%lu think=%ld cgroup_ino=%u", - __entry->bdi, - __entry->limit, - __entry->setpoint, - __entry->dirty, - __entry->bdi_setpoint, - __entry->bdi_dirty, - __entry->dirty_ratelimit, - __entry->task_ratelimit, - __entry->dirtied, - __entry->dirtied_pause, - __entry->paused, /* ms */ - __entry->pause, /* ms */ - __entry->period, /* ms */ - __entry->think, /* ms */ - __entry->cgroup_ino - ) -); - -TRACE_EVENT(writeback_sb_inodes_requeue, - - TP_PROTO(struct inode *inode), - TP_ARGS(inode), - - TP_STRUCT__entry( - __array(char, name, 32) - __field(unsigned long, ino) - __field(unsigned long, state) - __field(unsigned long, dirtied_when) - __field(unsigned int, cgroup_ino) - ), - - TP_fast_assign( - strncpy(__entry->name, - dev_name(inode_to_bdi(inode)->dev), 32); - __entry->ino = inode->i_ino; - __entry->state = inode->i_state; - __entry->dirtied_when = inode->dirtied_when; - __entry->cgroup_ino = __trace_wb_assign_cgroup(inode_to_wb(inode)); - ), - - TP_printk("bdi %s: ino=%lu state=%s dirtied_when=%lu age=%lu cgroup_ino=%u", - __entry->name, - __entry->ino, - show_inode_state(__entry->state), - __entry->dirtied_when, - (jiffies - __entry->dirtied_when) / HZ, - __entry->cgroup_ino - ) -); - -DECLARE_EVENT_CLASS(writeback_congest_waited_template, - - TP_PROTO(unsigned int usec_timeout, unsigned int usec_delayed), - - TP_ARGS(usec_timeout, usec_delayed), - - TP_STRUCT__entry( - __field( unsigned int, usec_timeout ) - __field( unsigned int, usec_delayed ) - ), - - TP_fast_assign( - __entry->usec_timeout = usec_timeout; - __entry->usec_delayed = usec_delayed; - ), - - TP_printk("usec_timeout=%u usec_delayed=%u", - __entry->usec_timeout, - __entry->usec_delayed) -); - -DEFINE_EVENT(writeback_congest_waited_template, writeback_congestion_wait, - - TP_PROTO(unsigned int usec_timeout, unsigned int usec_delayed), - - TP_ARGS(usec_timeout, usec_delayed) -); - -DEFINE_EVENT(writeback_congest_waited_template, writeback_wait_iff_congested, - - TP_PROTO(unsigned int usec_timeout, unsigned int usec_delayed), - - TP_ARGS(usec_timeout, usec_delayed) -); - -DECLARE_EVENT_CLASS(writeback_single_inode_template, - - TP_PROTO(struct inode *inode, - struct writeback_control *wbc, - unsigned long nr_to_write - ), - - TP_ARGS(inode, wbc, nr_to_write), - - TP_STRUCT__entry( - __array(char, name, 32) - __field(unsigned long, ino) - __field(unsigned long, state) - __field(unsigned long, dirtied_when) - __field(unsigned long, writeback_index) - __field(long, nr_to_write) - __field(unsigned long, wrote) - __field(unsigned int, cgroup_ino) - ), - - TP_fast_assign( - strncpy(__entry->name, - dev_name(inode_to_bdi(inode)->dev), 32); - __entry->ino = inode->i_ino; - __entry->state = inode->i_state; - __entry->dirtied_when = inode->dirtied_when; - __entry->writeback_index = inode->i_mapping->writeback_index; - __entry->nr_to_write = nr_to_write; - __entry->wrote = nr_to_write - wbc->nr_to_write; - __entry->cgroup_ino = __trace_wbc_assign_cgroup(wbc); - ), - - TP_printk("bdi %s: ino=%lu state=%s dirtied_when=%lu age=%lu " - "index=%lu to_write=%ld wrote=%lu cgroup_ino=%u", - __entry->name, - __entry->ino, - show_inode_state(__entry->state), - __entry->dirtied_when, - (jiffies - __entry->dirtied_when) / HZ, - __entry->writeback_index, - __entry->nr_to_write, - __entry->wrote, - __entry->cgroup_ino - ) -); - -DEFINE_EVENT(writeback_single_inode_template, writeback_single_inode_start, - TP_PROTO(struct inode *inode, - struct writeback_control *wbc, - unsigned long nr_to_write), - TP_ARGS(inode, wbc, nr_to_write) -); - -DEFINE_EVENT(writeback_single_inode_template, writeback_single_inode, - TP_PROTO(struct inode *inode, - struct writeback_control *wbc, - unsigned long nr_to_write), - TP_ARGS(inode, wbc, nr_to_write) -); - -DECLARE_EVENT_CLASS(writeback_inode_template, - TP_PROTO(struct inode *inode), - - TP_ARGS(inode), - - TP_STRUCT__entry( - __field( dev_t, dev ) - __field(unsigned long, ino ) - __field(unsigned long, state ) - __field( __u16, mode ) - __field(unsigned long, dirtied_when ) - ), - - TP_fast_assign( - __entry->dev = inode->i_sb->s_dev; - __entry->ino = inode->i_ino; - __entry->state = inode->i_state; - __entry->mode = inode->i_mode; - __entry->dirtied_when = inode->dirtied_when; - ), - - TP_printk("dev %d,%d ino %lu dirtied %lu state %s mode 0%o", - MAJOR(__entry->dev), MINOR(__entry->dev), - __entry->ino, __entry->dirtied_when, - show_inode_state(__entry->state), __entry->mode) -); - -DEFINE_EVENT(writeback_inode_template, writeback_lazytime, - TP_PROTO(struct inode *inode), - - TP_ARGS(inode) -); - -DEFINE_EVENT(writeback_inode_template, writeback_lazytime_iput, - TP_PROTO(struct inode *inode), - - TP_ARGS(inode) -); - -DEFINE_EVENT(writeback_inode_template, writeback_dirty_inode_enqueue, - - TP_PROTO(struct inode *inode), - - TP_ARGS(inode) -); - -/* - * Inode writeback list tracking. - */ - -DEFINE_EVENT(writeback_inode_template, sb_mark_inode_writeback, - TP_PROTO(struct inode *inode), - TP_ARGS(inode) -); - -DEFINE_EVENT(writeback_inode_template, sb_clear_inode_writeback, - TP_PROTO(struct inode *inode), - TP_ARGS(inode) -); - -#endif /* _TRACE_WRITEBACK_H */ - -/* This part must be outside protection */ -#include diff --git a/src/linux/include/trace/syscall.h b/src/linux/include/trace/syscall.h deleted file mode 100644 index 7434f0f..0000000 --- a/src/linux/include/trace/syscall.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef _TRACE_SYSCALL_H -#define _TRACE_SYSCALL_H - -#include -#include -#include -#include - -#include - - -/* - * A syscall entry in the ftrace syscalls array. - * - * @name: name of the syscall - * @syscall_nr: number of the syscall - * @nb_args: number of parameters it takes - * @types: list of types as strings - * @args: list of args as strings (args[i] matches types[i]) - * @enter_fields: list of fields for syscall_enter trace event - * @enter_event: associated syscall_enter trace event - * @exit_event: associated syscall_exit trace event - */ -struct syscall_metadata { - const char *name; - int syscall_nr; - int nb_args; - const char **types; - const char **args; - struct list_head enter_fields; - - struct trace_event_call *enter_event; - struct trace_event_call *exit_event; -}; - -#if defined(CONFIG_TRACEPOINTS) && defined(CONFIG_HAVE_SYSCALL_TRACEPOINTS) -static inline void syscall_tracepoint_update(struct task_struct *p) -{ - if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) - set_tsk_thread_flag(p, TIF_SYSCALL_TRACEPOINT); - else - clear_tsk_thread_flag(p, TIF_SYSCALL_TRACEPOINT); -} -#else -static inline void syscall_tracepoint_update(struct task_struct *p) -{ -} -#endif - -#endif /* _TRACE_SYSCALL_H */ diff --git a/src/linux/include/uapi/asm-generic/Kbuild.asm b/src/linux/include/uapi/asm-generic/Kbuild.asm deleted file mode 100644 index fcd50b7..0000000 --- a/src/linux/include/uapi/asm-generic/Kbuild.asm +++ /dev/null @@ -1,49 +0,0 @@ -# -# Headers that are optional in usr/include/asm/ -# -opt-header += kvm.h -opt-header += kvm_para.h -opt-header += a.out.h - -# -# Headers that are mandatory in usr/include/asm/ -# -header-y += auxvec.h -header-y += bitsperlong.h -header-y += byteorder.h -header-y += errno.h -header-y += fcntl.h -header-y += ioctl.h -header-y += ioctls.h -header-y += ipcbuf.h -header-y += mman.h -header-y += msgbuf.h -header-y += param.h -header-y += poll.h -header-y += posix_types.h -header-y += ptrace.h -header-y += resource.h -header-y += sembuf.h -header-y += setup.h -header-y += shmbuf.h -header-y += sigcontext.h -header-y += siginfo.h -header-y += signal.h -header-y += socket.h -header-y += sockios.h -header-y += stat.h -header-y += statfs.h -header-y += swab.h -header-y += termbits.h -header-y += termios.h -header-y += types.h -header-y += unistd.h - -header-y += $(foreach hdr,$(opt-header), \ - $(if \ - $(wildcard \ - $(srctree)/arch/$(SRCARCH)/include/uapi/asm/$(hdr) \ - $(srctree)/arch/$(SRCARCH)/include/asm/$(hdr) \ - ), \ - $(hdr) \ - )) diff --git a/src/linux/include/uapi/asm-generic/auxvec.h b/src/linux/include/uapi/asm-generic/auxvec.h deleted file mode 100644 index b99573b..0000000 --- a/src/linux/include/uapi/asm-generic/auxvec.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __ASM_GENERIC_AUXVEC_H -#define __ASM_GENERIC_AUXVEC_H -/* - * Not all architectures need their own auxvec.h, the most - * common definitions are already in linux/auxvec.h. - */ - -#endif /* __ASM_GENERIC_AUXVEC_H */ diff --git a/src/linux/include/uapi/asm-generic/errno-base.h b/src/linux/include/uapi/asm-generic/errno-base.h deleted file mode 100644 index 6511597..0000000 --- a/src/linux/include/uapi/asm-generic/errno-base.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _ASM_GENERIC_ERRNO_BASE_H -#define _ASM_GENERIC_ERRNO_BASE_H - -#define EPERM 1 /* Operation not permitted */ -#define ENOENT 2 /* No such file or directory */ -#define ESRCH 3 /* No such process */ -#define EINTR 4 /* Interrupted system call */ -#define EIO 5 /* I/O error */ -#define ENXIO 6 /* No such device or address */ -#define E2BIG 7 /* Argument list too long */ -#define ENOEXEC 8 /* Exec format error */ -#define EBADF 9 /* Bad file number */ -#define ECHILD 10 /* No child processes */ -#define EAGAIN 11 /* Try again */ -#define ENOMEM 12 /* Out of memory */ -#define EACCES 13 /* Permission denied */ -#define EFAULT 14 /* Bad address */ -#define ENOTBLK 15 /* Block device required */ -#define EBUSY 16 /* Device or resource busy */ -#define EEXIST 17 /* File exists */ -#define EXDEV 18 /* Cross-device link */ -#define ENODEV 19 /* No such device */ -#define ENOTDIR 20 /* Not a directory */ -#define EISDIR 21 /* Is a directory */ -#define EINVAL 22 /* Invalid argument */ -#define ENFILE 23 /* File table overflow */ -#define EMFILE 24 /* Too many open files */ -#define ENOTTY 25 /* Not a typewriter */ -#define ETXTBSY 26 /* Text file busy */ -#define EFBIG 27 /* File too large */ -#define ENOSPC 28 /* No space left on device */ -#define ESPIPE 29 /* Illegal seek */ -#define EROFS 30 /* Read-only file system */ -#define EMLINK 31 /* Too many links */ -#define EPIPE 32 /* Broken pipe */ -#define EDOM 33 /* Math argument out of domain of func */ -#define ERANGE 34 /* Math result not representable */ - -#endif diff --git a/src/linux/include/uapi/asm-generic/errno.h b/src/linux/include/uapi/asm-generic/errno.h deleted file mode 100644 index 88e0914..0000000 --- a/src/linux/include/uapi/asm-generic/errno.h +++ /dev/null @@ -1,122 +0,0 @@ -#ifndef _ASM_GENERIC_ERRNO_H -#define _ASM_GENERIC_ERRNO_H - -#include - -#define EDEADLK 35 /* Resource deadlock would occur */ -#define ENAMETOOLONG 36 /* File name too long */ -#define ENOLCK 37 /* No record locks available */ - -/* - * This error code is special: arch syscall entry code will return - * -ENOSYS if users try to call a syscall that doesn't exist. To keep - * failures of syscalls that really do exist distinguishable from - * failures due to attempts to use a nonexistent syscall, syscall - * implementations should refrain from returning -ENOSYS. - */ -#define ENOSYS 38 /* Invalid system call number */ - -#define ENOTEMPTY 39 /* Directory not empty */ -#define ELOOP 40 /* Too many symbolic links encountered */ -#define EWOULDBLOCK EAGAIN /* Operation would block */ -#define ENOMSG 42 /* No message of desired type */ -#define EIDRM 43 /* Identifier removed */ -#define ECHRNG 44 /* Channel number out of range */ -#define EL2NSYNC 45 /* Level 2 not synchronized */ -#define EL3HLT 46 /* Level 3 halted */ -#define EL3RST 47 /* Level 3 reset */ -#define ELNRNG 48 /* Link number out of range */ -#define EUNATCH 49 /* Protocol driver not attached */ -#define ENOCSI 50 /* No CSI structure available */ -#define EL2HLT 51 /* Level 2 halted */ -#define EBADE 52 /* Invalid exchange */ -#define EBADR 53 /* Invalid request descriptor */ -#define EXFULL 54 /* Exchange full */ -#define ENOANO 55 /* No anode */ -#define EBADRQC 56 /* Invalid request code */ -#define EBADSLT 57 /* Invalid slot */ - -#define EDEADLOCK EDEADLK - -#define EBFONT 59 /* Bad font file format */ -#define ENOSTR 60 /* Device not a stream */ -#define ENODATA 61 /* No data available */ -#define ETIME 62 /* Timer expired */ -#define ENOSR 63 /* Out of streams resources */ -#define ENONET 64 /* Machine is not on the network */ -#define ENOPKG 65 /* Package not installed */ -#define EREMOTE 66 /* Object is remote */ -#define ENOLINK 67 /* Link has been severed */ -#define EADV 68 /* Advertise error */ -#define ESRMNT 69 /* Srmount error */ -#define ECOMM 70 /* Communication error on send */ -#define EPROTO 71 /* Protocol error */ -#define EMULTIHOP 72 /* Multihop attempted */ -#define EDOTDOT 73 /* RFS specific error */ -#define EBADMSG 74 /* Not a data message */ -#define EOVERFLOW 75 /* Value too large for defined data type */ -#define ENOTUNIQ 76 /* Name not unique on network */ -#define EBADFD 77 /* File descriptor in bad state */ -#define EREMCHG 78 /* Remote address changed */ -#define ELIBACC 79 /* Can not access a needed shared library */ -#define ELIBBAD 80 /* Accessing a corrupted shared library */ -#define ELIBSCN 81 /* .lib section in a.out corrupted */ -#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ -#define ELIBEXEC 83 /* Cannot exec a shared library directly */ -#define EILSEQ 84 /* Illegal byte sequence */ -#define ERESTART 85 /* Interrupted system call should be restarted */ -#define ESTRPIPE 86 /* Streams pipe error */ -#define EUSERS 87 /* Too many users */ -#define ENOTSOCK 88 /* Socket operation on non-socket */ -#define EDESTADDRREQ 89 /* Destination address required */ -#define EMSGSIZE 90 /* Message too long */ -#define EPROTOTYPE 91 /* Protocol wrong type for socket */ -#define ENOPROTOOPT 92 /* Protocol not available */ -#define EPROTONOSUPPORT 93 /* Protocol not supported */ -#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ -#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ -#define EPFNOSUPPORT 96 /* Protocol family not supported */ -#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ -#define EADDRINUSE 98 /* Address already in use */ -#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ -#define ENETDOWN 100 /* Network is down */ -#define ENETUNREACH 101 /* Network is unreachable */ -#define ENETRESET 102 /* Network dropped connection because of reset */ -#define ECONNABORTED 103 /* Software caused connection abort */ -#define ECONNRESET 104 /* Connection reset by peer */ -#define ENOBUFS 105 /* No buffer space available */ -#define EISCONN 106 /* Transport endpoint is already connected */ -#define ENOTCONN 107 /* Transport endpoint is not connected */ -#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ -#define ETOOMANYREFS 109 /* Too many references: cannot splice */ -#define ETIMEDOUT 110 /* Connection timed out */ -#define ECONNREFUSED 111 /* Connection refused */ -#define EHOSTDOWN 112 /* Host is down */ -#define EHOSTUNREACH 113 /* No route to host */ -#define EALREADY 114 /* Operation already in progress */ -#define EINPROGRESS 115 /* Operation now in progress */ -#define ESTALE 116 /* Stale file handle */ -#define EUCLEAN 117 /* Structure needs cleaning */ -#define ENOTNAM 118 /* Not a XENIX named type file */ -#define ENAVAIL 119 /* No XENIX semaphores available */ -#define EISNAM 120 /* Is a named type file */ -#define EREMOTEIO 121 /* Remote I/O error */ -#define EDQUOT 122 /* Quota exceeded */ - -#define ENOMEDIUM 123 /* No medium found */ -#define EMEDIUMTYPE 124 /* Wrong medium type */ -#define ECANCELED 125 /* Operation Canceled */ -#define ENOKEY 126 /* Required key not available */ -#define EKEYEXPIRED 127 /* Key has expired */ -#define EKEYREVOKED 128 /* Key has been revoked */ -#define EKEYREJECTED 129 /* Key was rejected by service */ - -/* for robust mutexes */ -#define EOWNERDEAD 130 /* Owner died */ -#define ENOTRECOVERABLE 131 /* State not recoverable */ - -#define ERFKILL 132 /* Operation not possible due to RF-kill */ - -#define EHWPOISON 133 /* Memory page has hardware error */ - -#endif diff --git a/src/linux/include/uapi/asm-generic/fcntl.h b/src/linux/include/uapi/asm-generic/fcntl.h deleted file mode 100644 index e063eff..0000000 --- a/src/linux/include/uapi/asm-generic/fcntl.h +++ /dev/null @@ -1,220 +0,0 @@ -#ifndef _ASM_GENERIC_FCNTL_H -#define _ASM_GENERIC_FCNTL_H - -#include - -/* - * FMODE_EXEC is 0x20 - * FMODE_NONOTIFY is 0x4000000 - * These cannot be used by userspace O_* until internal and external open - * flags are split. - * -Eric Paris - */ - -/* - * When introducing new O_* bits, please check its uniqueness in fcntl_init(). - */ - -#define O_ACCMODE 00000003 -#define O_RDONLY 00000000 -#define O_WRONLY 00000001 -#define O_RDWR 00000002 -#ifndef O_CREAT -#define O_CREAT 00000100 /* not fcntl */ -#endif -#ifndef O_EXCL -#define O_EXCL 00000200 /* not fcntl */ -#endif -#ifndef O_NOCTTY -#define O_NOCTTY 00000400 /* not fcntl */ -#endif -#ifndef O_TRUNC -#define O_TRUNC 00001000 /* not fcntl */ -#endif -#ifndef O_APPEND -#define O_APPEND 00002000 -#endif -#ifndef O_NONBLOCK -#define O_NONBLOCK 00004000 -#endif -#ifndef O_DSYNC -#define O_DSYNC 00010000 /* used to be O_SYNC, see below */ -#endif -#ifndef FASYNC -#define FASYNC 00020000 /* fcntl, for BSD compatibility */ -#endif -#ifndef O_DIRECT -#define O_DIRECT 00040000 /* direct disk access hint */ -#endif -#ifndef O_LARGEFILE -#define O_LARGEFILE 00100000 -#endif -#ifndef O_DIRECTORY -#define O_DIRECTORY 00200000 /* must be a directory */ -#endif -#ifndef O_NOFOLLOW -#define O_NOFOLLOW 00400000 /* don't follow links */ -#endif -#ifndef O_NOATIME -#define O_NOATIME 01000000 -#endif -#ifndef O_CLOEXEC -#define O_CLOEXEC 02000000 /* set close_on_exec */ -#endif - -/* - * Before Linux 2.6.33 only O_DSYNC semantics were implemented, but using - * the O_SYNC flag. We continue to use the existing numerical value - * for O_DSYNC semantics now, but using the correct symbolic name for it. - * This new value is used to request true Posix O_SYNC semantics. It is - * defined in this strange way to make sure applications compiled against - * new headers get at least O_DSYNC semantics on older kernels. - * - * This has the nice side-effect that we can simply test for O_DSYNC - * wherever we do not care if O_DSYNC or O_SYNC is used. - * - * Note: __O_SYNC must never be used directly. - */ -#ifndef O_SYNC -#define __O_SYNC 04000000 -#define O_SYNC (__O_SYNC|O_DSYNC) -#endif - -#ifndef O_PATH -#define O_PATH 010000000 -#endif - -#ifndef __O_TMPFILE -#define __O_TMPFILE 020000000 -#endif - -/* a horrid kludge trying to make sure that this will fail on old kernels */ -#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY) -#define O_TMPFILE_MASK (__O_TMPFILE | O_DIRECTORY | O_CREAT) - -#ifndef O_NDELAY -#define O_NDELAY O_NONBLOCK -#endif - -#define F_DUPFD 0 /* dup */ -#define F_GETFD 1 /* get close_on_exec */ -#define F_SETFD 2 /* set/clear close_on_exec */ -#define F_GETFL 3 /* get file->f_flags */ -#define F_SETFL 4 /* set file->f_flags */ -#ifndef F_GETLK -#define F_GETLK 5 -#define F_SETLK 6 -#define F_SETLKW 7 -#endif -#ifndef F_SETOWN -#define F_SETOWN 8 /* for sockets. */ -#define F_GETOWN 9 /* for sockets. */ -#endif -#ifndef F_SETSIG -#define F_SETSIG 10 /* for sockets. */ -#define F_GETSIG 11 /* for sockets. */ -#endif - -#ifndef CONFIG_64BIT -#ifndef F_GETLK64 -#define F_GETLK64 12 /* using 'struct flock64' */ -#define F_SETLK64 13 -#define F_SETLKW64 14 -#endif -#endif - -#ifndef F_SETOWN_EX -#define F_SETOWN_EX 15 -#define F_GETOWN_EX 16 -#endif - -#ifndef F_GETOWNER_UIDS -#define F_GETOWNER_UIDS 17 -#endif - -/* - * Open File Description Locks - * - * Usually record locks held by a process are released on *any* close and are - * not inherited across a fork(). - * - * These cmd values will set locks that conflict with process-associated - * record locks, but are "owned" by the open file description, not the - * process. This means that they are inherited across fork() like BSD (flock) - * locks, and they are only released automatically when the last reference to - * the the open file against which they were acquired is put. - */ -#define F_OFD_GETLK 36 -#define F_OFD_SETLK 37 -#define F_OFD_SETLKW 38 - -#define F_OWNER_TID 0 -#define F_OWNER_PID 1 -#define F_OWNER_PGRP 2 - -struct f_owner_ex { - int type; - __kernel_pid_t pid; -}; - -/* for F_[GET|SET]FL */ -#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ - -/* for posix fcntl() and lockf() */ -#ifndef F_RDLCK -#define F_RDLCK 0 -#define F_WRLCK 1 -#define F_UNLCK 2 -#endif - -/* for old implementation of bsd flock () */ -#ifndef F_EXLCK -#define F_EXLCK 4 /* or 3 */ -#define F_SHLCK 8 /* or 4 */ -#endif - -/* operations for bsd flock(), also used by the kernel implementation */ -#define LOCK_SH 1 /* shared lock */ -#define LOCK_EX 2 /* exclusive lock */ -#define LOCK_NB 4 /* or'd with one of the above to prevent - blocking */ -#define LOCK_UN 8 /* remove lock */ - -#define LOCK_MAND 32 /* This is a mandatory flock ... */ -#define LOCK_READ 64 /* which allows concurrent read operations */ -#define LOCK_WRITE 128 /* which allows concurrent write operations */ -#define LOCK_RW 192 /* which allows concurrent read & write ops */ - -#define F_LINUX_SPECIFIC_BASE 1024 - -#ifndef HAVE_ARCH_STRUCT_FLOCK -#ifndef __ARCH_FLOCK_PAD -#define __ARCH_FLOCK_PAD -#endif - -struct flock { - short l_type; - short l_whence; - __kernel_off_t l_start; - __kernel_off_t l_len; - __kernel_pid_t l_pid; - __ARCH_FLOCK_PAD -}; -#endif - -#ifndef HAVE_ARCH_STRUCT_FLOCK64 -#ifndef __ARCH_FLOCK64_PAD -#define __ARCH_FLOCK64_PAD -#endif - -struct flock64 { - short l_type; - short l_whence; - __kernel_loff_t l_start; - __kernel_loff_t l_len; - __kernel_pid_t l_pid; - __ARCH_FLOCK64_PAD -}; -#endif - -#endif /* _ASM_GENERIC_FCNTL_H */ diff --git a/src/linux/include/uapi/asm-generic/int-ll64.h b/src/linux/include/uapi/asm-generic/int-ll64.h deleted file mode 100644 index a8658b2..0000000 --- a/src/linux/include/uapi/asm-generic/int-ll64.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * asm-generic/int-ll64.h - * - * Integer declarations for architectures which use "long long" - * for 64-bit types. - */ - -#ifndef _UAPI_ASM_GENERIC_INT_LL64_H -#define _UAPI_ASM_GENERIC_INT_LL64_H - -#include - -#ifndef __ASSEMBLY__ -/* - * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the - * header files exported to user space - */ - -typedef __signed__ char __s8; -typedef unsigned char __u8; - -typedef __signed__ short __s16; -typedef unsigned short __u16; - -typedef __signed__ int __s32; -typedef unsigned int __u32; - -#ifdef __GNUC__ -__extension__ typedef __signed__ long long __s64; -__extension__ typedef unsigned long long __u64; -#else -typedef __signed__ long long __s64; -typedef unsigned long long __u64; -#endif - -#endif /* __ASSEMBLY__ */ - - -#endif /* _UAPI_ASM_GENERIC_INT_LL64_H */ diff --git a/src/linux/include/uapi/asm-generic/ioctl.h b/src/linux/include/uapi/asm-generic/ioctl.h deleted file mode 100644 index 7e7c11b..0000000 --- a/src/linux/include/uapi/asm-generic/ioctl.h +++ /dev/null @@ -1,98 +0,0 @@ -#ifndef _UAPI_ASM_GENERIC_IOCTL_H -#define _UAPI_ASM_GENERIC_IOCTL_H - -/* ioctl command encoding: 32 bits total, command in lower 16 bits, - * size of the parameter structure in the lower 14 bits of the - * upper 16 bits. - * Encoding the size of the parameter structure in the ioctl request - * is useful for catching programs compiled with old versions - * and to avoid overwriting user space outside the user buffer area. - * The highest 2 bits are reserved for indicating the ``access mode''. - * NOTE: This limits the max parameter size to 16kB -1 ! - */ - -/* - * The following is for compatibility across the various Linux - * platforms. The generic ioctl numbering scheme doesn't really enforce - * a type field. De facto, however, the top 8 bits of the lower 16 - * bits are indeed used as a type field, so we might just as well make - * this explicit here. Please be sure to use the decoding macros - * below from now on. - */ -#define _IOC_NRBITS 8 -#define _IOC_TYPEBITS 8 - -/* - * Let any architecture override either of the following before - * including this file. - */ - -#ifndef _IOC_SIZEBITS -# define _IOC_SIZEBITS 14 -#endif - -#ifndef _IOC_DIRBITS -# define _IOC_DIRBITS 2 -#endif - -#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) -#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) -#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) -#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) - -#define _IOC_NRSHIFT 0 -#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS) -#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS) -#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) - -/* - * Direction bits, which any architecture can choose to override - * before including this file. - */ - -#ifndef _IOC_NONE -# define _IOC_NONE 0U -#endif - -#ifndef _IOC_WRITE -# define _IOC_WRITE 1U -#endif - -#ifndef _IOC_READ -# define _IOC_READ 2U -#endif - -#define _IOC(dir,type,nr,size) \ - (((dir) << _IOC_DIRSHIFT) | \ - ((type) << _IOC_TYPESHIFT) | \ - ((nr) << _IOC_NRSHIFT) | \ - ((size) << _IOC_SIZESHIFT)) - -#ifndef __KERNEL__ -#define _IOC_TYPECHECK(t) (sizeof(t)) -#endif - -/* used to create numbers */ -#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) -#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),(_IOC_TYPECHECK(size))) -#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size))) -#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),(_IOC_TYPECHECK(size))) -#define _IOR_BAD(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) -#define _IOW_BAD(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) -#define _IOWR_BAD(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) - -/* used to decode ioctl numbers.. */ -#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) -#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) -#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) -#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) - -/* ...and for the drivers/sound files... */ - -#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT) -#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT) -#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT) -#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT) -#define IOCSIZE_SHIFT (_IOC_SIZESHIFT) - -#endif /* _UAPI_ASM_GENERIC_IOCTL_H */ diff --git a/src/linux/include/uapi/asm-generic/ioctls.h b/src/linux/include/uapi/asm-generic/ioctls.h deleted file mode 100644 index 143dacb..0000000 --- a/src/linux/include/uapi/asm-generic/ioctls.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef __ASM_GENERIC_IOCTLS_H -#define __ASM_GENERIC_IOCTLS_H - -#include - -/* - * These are the most common definitions for tty ioctl numbers. - * Most of them do not use the recommended _IOC(), but there is - * probably some source code out there hardcoding the number, - * so we might as well use them for all new platforms. - * - * The architectures that use different values here typically - * try to be compatible with some Unix variants for the same - * architecture. - */ - -/* 0x54 is just a magic number to make these relatively unique ('T') */ - -#define TCGETS 0x5401 -#define TCSETS 0x5402 -#define TCSETSW 0x5403 -#define TCSETSF 0x5404 -#define TCGETA 0x5405 -#define TCSETA 0x5406 -#define TCSETAW 0x5407 -#define TCSETAF 0x5408 -#define TCSBRK 0x5409 -#define TCXONC 0x540A -#define TCFLSH 0x540B -#define TIOCEXCL 0x540C -#define TIOCNXCL 0x540D -#define TIOCSCTTY 0x540E -#define TIOCGPGRP 0x540F -#define TIOCSPGRP 0x5410 -#define TIOCOUTQ 0x5411 -#define TIOCSTI 0x5412 -#define TIOCGWINSZ 0x5413 -#define TIOCSWINSZ 0x5414 -#define TIOCMGET 0x5415 -#define TIOCMBIS 0x5416 -#define TIOCMBIC 0x5417 -#define TIOCMSET 0x5418 -#define TIOCGSOFTCAR 0x5419 -#define TIOCSSOFTCAR 0x541A -#define FIONREAD 0x541B -#define TIOCINQ FIONREAD -#define TIOCLINUX 0x541C -#define TIOCCONS 0x541D -#define TIOCGSERIAL 0x541E -#define TIOCSSERIAL 0x541F -#define TIOCPKT 0x5420 -#define FIONBIO 0x5421 -#define TIOCNOTTY 0x5422 -#define TIOCSETD 0x5423 -#define TIOCGETD 0x5424 -#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ -#define TIOCSBRK 0x5427 /* BSD compatibility */ -#define TIOCCBRK 0x5428 /* BSD compatibility */ -#define TIOCGSID 0x5429 /* Return the session ID of FD */ -#define TCGETS2 _IOR('T', 0x2A, struct termios2) -#define TCSETS2 _IOW('T', 0x2B, struct termios2) -#define TCSETSW2 _IOW('T', 0x2C, struct termios2) -#define TCSETSF2 _IOW('T', 0x2D, struct termios2) -#define TIOCGRS485 0x542E -#ifndef TIOCSRS485 -#define TIOCSRS485 0x542F -#endif -#define TIOCGPTN _IOR('T', 0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ -#define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */ -#define TIOCGDEV _IOR('T', 0x32, unsigned int) /* Get primary device node of /dev/console */ -#define TCGETX 0x5432 /* SYS5 TCGETX compatibility */ -#define TCSETX 0x5433 -#define TCSETXF 0x5434 -#define TCSETXW 0x5435 -#define TIOCSIG _IOW('T', 0x36, int) /* pty: generate signal */ -#define TIOCVHANGUP 0x5437 -#define TIOCGPKT _IOR('T', 0x38, int) /* Get packet mode state */ -#define TIOCGPTLCK _IOR('T', 0x39, int) /* Get Pty lock state */ -#define TIOCGEXCL _IOR('T', 0x40, int) /* Get exclusive mode state */ - -#define FIONCLEX 0x5450 -#define FIOCLEX 0x5451 -#define FIOASYNC 0x5452 -#define TIOCSERCONFIG 0x5453 -#define TIOCSERGWILD 0x5454 -#define TIOCSERSWILD 0x5455 -#define TIOCGLCKTRMIOS 0x5456 -#define TIOCSLCKTRMIOS 0x5457 -#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ -#define TIOCSERGETLSR 0x5459 /* Get line status register */ -#define TIOCSERGETMULTI 0x545A /* Get multiport config */ -#define TIOCSERSETMULTI 0x545B /* Set multiport config */ - -#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ -#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ - -/* - * Some arches already define FIOQSIZE due to a historical - * conflict with a Hayes modem-specific ioctl value. - */ -#ifndef FIOQSIZE -# define FIOQSIZE 0x5460 -#endif - -/* Used for packet mode */ -#define TIOCPKT_DATA 0 -#define TIOCPKT_FLUSHREAD 1 -#define TIOCPKT_FLUSHWRITE 2 -#define TIOCPKT_STOP 4 -#define TIOCPKT_START 8 -#define TIOCPKT_NOSTOP 16 -#define TIOCPKT_DOSTOP 32 -#define TIOCPKT_IOCTL 64 - -#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ - -#endif /* __ASM_GENERIC_IOCTLS_H */ diff --git a/src/linux/include/uapi/asm-generic/ipcbuf.h b/src/linux/include/uapi/asm-generic/ipcbuf.h deleted file mode 100644 index 3dbcc1e..0000000 --- a/src/linux/include/uapi/asm-generic/ipcbuf.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef __ASM_GENERIC_IPCBUF_H -#define __ASM_GENERIC_IPCBUF_H - -/* - * The generic ipc64_perm structure: - * Note extra padding because this structure is passed back and forth - * between kernel and user space. - * - * ipc64_perm was originally meant to be architecture specific, but - * everyone just ended up making identical copies without specific - * optimizations, so we may just as well all use the same one. - * - * Pad space is left for: - * - 32-bit mode_t on architectures that only had 16 bit - * - 32-bit seq - * - 2 miscellaneous 32-bit values - */ - -struct ipc64_perm { - __kernel_key_t key; - __kernel_uid32_t uid; - __kernel_gid32_t gid; - __kernel_uid32_t cuid; - __kernel_gid32_t cgid; - __kernel_mode_t mode; - /* pad if mode_t is u16: */ - unsigned char __pad1[4 - sizeof(__kernel_mode_t)]; - unsigned short seq; - unsigned short __pad2; - __kernel_ulong_t __unused1; - __kernel_ulong_t __unused2; -}; - -#endif /* __ASM_GENERIC_IPCBUF_H */ diff --git a/src/linux/include/uapi/asm-generic/mman-common.h b/src/linux/include/uapi/asm-generic/mman-common.h deleted file mode 100644 index 8c27db0..0000000 --- a/src/linux/include/uapi/asm-generic/mman-common.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef __ASM_GENERIC_MMAN_COMMON_H -#define __ASM_GENERIC_MMAN_COMMON_H - -/* - Author: Michael S. Tsirkin , Mellanox Technologies Ltd. - Based on: asm-xxx/mman.h -*/ - -#define PROT_READ 0x1 /* page can be read */ -#define PROT_WRITE 0x2 /* page can be written */ -#define PROT_EXEC 0x4 /* page can be executed */ -#define PROT_SEM 0x8 /* page may be used for atomic ops */ -#define PROT_NONE 0x0 /* page can not be accessed */ -#define PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */ -#define PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end of growsup vma */ - -#define MAP_SHARED 0x01 /* Share changes */ -#define MAP_PRIVATE 0x02 /* Changes are private */ -#define MAP_TYPE 0x0f /* Mask for type of mapping */ -#define MAP_FIXED 0x10 /* Interpret addr exactly */ -#define MAP_ANONYMOUS 0x20 /* don't use a file */ -#ifdef CONFIG_MMAP_ALLOW_UNINITIALIZED -# define MAP_UNINITIALIZED 0x4000000 /* For anonymous mmap, memory could be uninitialized */ -#else -# define MAP_UNINITIALIZED 0x0 /* Don't support this flag */ -#endif - -/* - * Flags for mlock - */ -#define MLOCK_ONFAULT 0x01 /* Lock pages in range after they are faulted in, do not prefault */ - -#define MS_ASYNC 1 /* sync memory asynchronously */ -#define MS_INVALIDATE 2 /* invalidate the caches */ -#define MS_SYNC 4 /* synchronous memory sync */ - -#define MADV_NORMAL 0 /* no further special treatment */ -#define MADV_RANDOM 1 /* expect random page references */ -#define MADV_SEQUENTIAL 2 /* expect sequential page references */ -#define MADV_WILLNEED 3 /* will need these pages */ -#define MADV_DONTNEED 4 /* don't need these pages */ - -/* common parameters: try to keep these consistent across architectures */ -#define MADV_FREE 8 /* free pages only if memory pressure */ -#define MADV_REMOVE 9 /* remove these pages & resources */ -#define MADV_DONTFORK 10 /* don't inherit across fork */ -#define MADV_DOFORK 11 /* do inherit across fork */ -#define MADV_HWPOISON 100 /* poison a page for testing */ -#define MADV_SOFT_OFFLINE 101 /* soft offline page for testing */ - -#define MADV_MERGEABLE 12 /* KSM may merge identical pages */ -#define MADV_UNMERGEABLE 13 /* KSM may not merge identical pages */ - -#define MADV_HUGEPAGE 14 /* Worth backing with hugepages */ -#define MADV_NOHUGEPAGE 15 /* Not worth backing with hugepages */ - -#define MADV_DONTDUMP 16 /* Explicity exclude from the core dump, - overrides the coredump filter bits */ -#define MADV_DODUMP 17 /* Clear the MADV_DONTDUMP flag */ - -/* compatibility flags */ -#define MAP_FILE 0 - -/* - * When MAP_HUGETLB is set bits [26:31] encode the log2 of the huge page size. - * This gives us 6 bits, which is enough until someone invents 128 bit address - * spaces. - * - * Assume these are all power of twos. - * When 0 use the default page size. - */ -#define MAP_HUGE_SHIFT 26 -#define MAP_HUGE_MASK 0x3f - -#define PKEY_DISABLE_ACCESS 0x1 -#define PKEY_DISABLE_WRITE 0x2 -#define PKEY_ACCESS_MASK (PKEY_DISABLE_ACCESS |\ - PKEY_DISABLE_WRITE) - -#endif /* __ASM_GENERIC_MMAN_COMMON_H */ diff --git a/src/linux/include/uapi/asm-generic/mman.h b/src/linux/include/uapi/asm-generic/mman.h deleted file mode 100644 index 7162cd4..0000000 --- a/src/linux/include/uapi/asm-generic/mman.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef __ASM_GENERIC_MMAN_H -#define __ASM_GENERIC_MMAN_H - -#include - -#define MAP_GROWSDOWN 0x0100 /* stack-like segment */ -#define MAP_DENYWRITE 0x0800 /* ETXTBSY */ -#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ -#define MAP_LOCKED 0x2000 /* pages are locked */ -#define MAP_NORESERVE 0x4000 /* don't check for reservations */ -#define MAP_POPULATE 0x8000 /* populate (prefault) pagetables */ -#define MAP_NONBLOCK 0x10000 /* do not block on IO */ -#define MAP_STACK 0x20000 /* give out an address that is best suited for process/thread stacks */ -#define MAP_HUGETLB 0x40000 /* create a huge page mapping */ - -/* Bits [26:31] are reserved, see mman-common.h for MAP_HUGETLB usage */ - -#define MCL_CURRENT 1 /* lock all current mappings */ -#define MCL_FUTURE 2 /* lock all future mappings */ -#define MCL_ONFAULT 4 /* lock all pages that are faulted in */ - -#endif /* __ASM_GENERIC_MMAN_H */ diff --git a/src/linux/include/uapi/asm-generic/msgbuf.h b/src/linux/include/uapi/asm-generic/msgbuf.h deleted file mode 100644 index f55ecc4..0000000 --- a/src/linux/include/uapi/asm-generic/msgbuf.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef __ASM_GENERIC_MSGBUF_H -#define __ASM_GENERIC_MSGBUF_H - -#include -/* - * generic msqid64_ds structure. - * - * Note extra padding because this structure is passed back and forth - * between kernel and user space. - * - * msqid64_ds was originally meant to be architecture specific, but - * everyone just ended up making identical copies without specific - * optimizations, so we may just as well all use the same one. - * - * 64 bit architectures typically define a 64 bit __kernel_time_t, - * so they do not need the first three padding words. - * On big-endian systems, the padding is in the wrong place. - * - * Pad space is left for: - * - 64-bit time_t to solve y2038 problem - * - 2 miscellaneous 32-bit values - */ - -struct msqid64_ds { - struct ipc64_perm msg_perm; - __kernel_time_t msg_stime; /* last msgsnd time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused1; -#endif - __kernel_time_t msg_rtime; /* last msgrcv time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused2; -#endif - __kernel_time_t msg_ctime; /* last change time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused3; -#endif - __kernel_ulong_t msg_cbytes; /* current number of bytes on queue */ - __kernel_ulong_t msg_qnum; /* number of messages in queue */ - __kernel_ulong_t msg_qbytes; /* max number of bytes on queue */ - __kernel_pid_t msg_lspid; /* pid of last msgsnd */ - __kernel_pid_t msg_lrpid; /* last receive pid */ - __kernel_ulong_t __unused4; - __kernel_ulong_t __unused5; -}; - -#endif /* __ASM_GENERIC_MSGBUF_H */ diff --git a/src/linux/include/uapi/asm-generic/param.h b/src/linux/include/uapi/asm-generic/param.h deleted file mode 100644 index 5becc84..0000000 --- a/src/linux/include/uapi/asm-generic/param.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef _UAPI__ASM_GENERIC_PARAM_H -#define _UAPI__ASM_GENERIC_PARAM_H - -#ifndef HZ -#define HZ 100 -#endif - -#ifndef EXEC_PAGESIZE -#define EXEC_PAGESIZE 4096 -#endif - -#ifndef NOGROUP -#define NOGROUP (-1) -#endif - -#define MAXHOSTNAMELEN 64 /* max length of hostname */ - - -#endif /* _UAPI__ASM_GENERIC_PARAM_H */ diff --git a/src/linux/include/uapi/asm-generic/poll.h b/src/linux/include/uapi/asm-generic/poll.h deleted file mode 100644 index a969498..0000000 --- a/src/linux/include/uapi/asm-generic/poll.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef __ASM_GENERIC_POLL_H -#define __ASM_GENERIC_POLL_H - -/* These are specified by iBCS2 */ -#define POLLIN 0x0001 -#define POLLPRI 0x0002 -#define POLLOUT 0x0004 -#define POLLERR 0x0008 -#define POLLHUP 0x0010 -#define POLLNVAL 0x0020 - -/* The rest seem to be more-or-less nonstandard. Check them! */ -#define POLLRDNORM 0x0040 -#define POLLRDBAND 0x0080 -#ifndef POLLWRNORM -#define POLLWRNORM 0x0100 -#endif -#ifndef POLLWRBAND -#define POLLWRBAND 0x0200 -#endif -#ifndef POLLMSG -#define POLLMSG 0x0400 -#endif -#ifndef POLLREMOVE -#define POLLREMOVE 0x1000 -#endif -#ifndef POLLRDHUP -#define POLLRDHUP 0x2000 -#endif - -#define POLLFREE 0x4000 /* currently only for epoll */ - -#define POLL_BUSY_LOOP 0x8000 - -struct pollfd { - int fd; - short events; - short revents; -}; - -#endif /* __ASM_GENERIC_POLL_H */ diff --git a/src/linux/include/uapi/asm-generic/posix_types.h b/src/linux/include/uapi/asm-generic/posix_types.h deleted file mode 100644 index fe74fcc..0000000 --- a/src/linux/include/uapi/asm-generic/posix_types.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef __ASM_GENERIC_POSIX_TYPES_H -#define __ASM_GENERIC_POSIX_TYPES_H - -#include -/* - * This file is generally used by user-level software, so you need to - * be a little careful about namespace pollution etc. - * - * First the types that are often defined in different ways across - * architectures, so that you can override them. - */ - -#ifndef __kernel_long_t -typedef long __kernel_long_t; -typedef unsigned long __kernel_ulong_t; -#endif - -#ifndef __kernel_ino_t -typedef __kernel_ulong_t __kernel_ino_t; -#endif - -#ifndef __kernel_mode_t -typedef unsigned int __kernel_mode_t; -#endif - -#ifndef __kernel_pid_t -typedef int __kernel_pid_t; -#endif - -#ifndef __kernel_ipc_pid_t -typedef int __kernel_ipc_pid_t; -#endif - -#ifndef __kernel_uid_t -typedef unsigned int __kernel_uid_t; -typedef unsigned int __kernel_gid_t; -#endif - -#ifndef __kernel_suseconds_t -typedef __kernel_long_t __kernel_suseconds_t; -#endif - -#ifndef __kernel_daddr_t -typedef int __kernel_daddr_t; -#endif - -#ifndef __kernel_uid32_t -typedef unsigned int __kernel_uid32_t; -typedef unsigned int __kernel_gid32_t; -#endif - -#ifndef __kernel_old_uid_t -typedef __kernel_uid_t __kernel_old_uid_t; -typedef __kernel_gid_t __kernel_old_gid_t; -#endif - -#ifndef __kernel_old_dev_t -typedef unsigned int __kernel_old_dev_t; -#endif - -/* - * Most 32 bit architectures use "unsigned int" size_t, - * and all 64 bit architectures use "unsigned long" size_t. - */ -#ifndef __kernel_size_t -#if __BITS_PER_LONG != 64 -typedef unsigned int __kernel_size_t; -typedef int __kernel_ssize_t; -typedef int __kernel_ptrdiff_t; -#else -typedef __kernel_ulong_t __kernel_size_t; -typedef __kernel_long_t __kernel_ssize_t; -typedef __kernel_long_t __kernel_ptrdiff_t; -#endif -#endif - -#ifndef __kernel_fsid_t -typedef struct { - int val[2]; -} __kernel_fsid_t; -#endif - -/* - * anything below here should be completely generic - */ -typedef __kernel_long_t __kernel_off_t; -typedef long long __kernel_loff_t; -typedef __kernel_long_t __kernel_time_t; -typedef __kernel_long_t __kernel_clock_t; -typedef int __kernel_timer_t; -typedef int __kernel_clockid_t; -typedef char * __kernel_caddr_t; -typedef unsigned short __kernel_uid16_t; -typedef unsigned short __kernel_gid16_t; - -#endif /* __ASM_GENERIC_POSIX_TYPES_H */ diff --git a/src/linux/include/uapi/asm-generic/resource.h b/src/linux/include/uapi/asm-generic/resource.h deleted file mode 100644 index c6d10af..0000000 --- a/src/linux/include/uapi/asm-generic/resource.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef _UAPI_ASM_GENERIC_RESOURCE_H -#define _UAPI_ASM_GENERIC_RESOURCE_H - -/* - * Resource limit IDs - * - * ( Compatibility detail: there are architectures that have - * a different rlimit ID order in the 5-9 range and want - * to keep that order for binary compatibility. The reasons - * are historic and all new rlimits are identical across all - * arches. If an arch has such special order for some rlimits - * then it defines them prior including asm-generic/resource.h. ) - */ - -#define RLIMIT_CPU 0 /* CPU time in sec */ -#define RLIMIT_FSIZE 1 /* Maximum filesize */ -#define RLIMIT_DATA 2 /* max data size */ -#define RLIMIT_STACK 3 /* max stack size */ -#define RLIMIT_CORE 4 /* max core file size */ - -#ifndef RLIMIT_RSS -# define RLIMIT_RSS 5 /* max resident set size */ -#endif - -#ifndef RLIMIT_NPROC -# define RLIMIT_NPROC 6 /* max number of processes */ -#endif - -#ifndef RLIMIT_NOFILE -# define RLIMIT_NOFILE 7 /* max number of open files */ -#endif - -#ifndef RLIMIT_MEMLOCK -# define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ -#endif - -#ifndef RLIMIT_AS -# define RLIMIT_AS 9 /* address space limit */ -#endif - -#define RLIMIT_LOCKS 10 /* maximum file locks held */ -#define RLIMIT_SIGPENDING 11 /* max number of pending signals */ -#define RLIMIT_MSGQUEUE 12 /* maximum bytes in POSIX mqueues */ -#define RLIMIT_NICE 13 /* max nice prio allowed to raise to - 0-39 for nice level 19 .. -20 */ -#define RLIMIT_RTPRIO 14 /* maximum realtime priority */ -#define RLIMIT_RTTIME 15 /* timeout for RT tasks in us */ -#define RLIM_NLIMITS 16 - -/* - * SuS says limits have to be unsigned. - * Which makes a ton more sense anyway. - * - * Some architectures override this (for compatibility reasons): - */ -#ifndef RLIM_INFINITY -# define RLIM_INFINITY (~0UL) -#endif - - -#endif /* _UAPI_ASM_GENERIC_RESOURCE_H */ diff --git a/src/linux/include/uapi/asm-generic/sembuf.h b/src/linux/include/uapi/asm-generic/sembuf.h deleted file mode 100644 index 4cb2c13..0000000 --- a/src/linux/include/uapi/asm-generic/sembuf.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef __ASM_GENERIC_SEMBUF_H -#define __ASM_GENERIC_SEMBUF_H - -#include - -/* - * The semid64_ds structure for x86 architecture. - * Note extra padding because this structure is passed back and forth - * between kernel and user space. - * - * semid64_ds was originally meant to be architecture specific, but - * everyone just ended up making identical copies without specific - * optimizations, so we may just as well all use the same one. - * - * 64 bit architectures typically define a 64 bit __kernel_time_t, - * so they do not need the first two padding words. - * On big-endian systems, the padding is in the wrong place. - * - * Pad space is left for: - * - 64-bit time_t to solve y2038 problem - * - 2 miscellaneous 32-bit values - */ -struct semid64_ds { - struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ - __kernel_time_t sem_otime; /* last semop time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused1; -#endif - __kernel_time_t sem_ctime; /* last change time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused2; -#endif - unsigned long sem_nsems; /* no. of semaphores in array */ - unsigned long __unused3; - unsigned long __unused4; -}; - -#endif /* __ASM_GENERIC_SEMBUF_H */ diff --git a/src/linux/include/uapi/asm-generic/shmbuf.h b/src/linux/include/uapi/asm-generic/shmbuf.h deleted file mode 100644 index 7e9fb2f..0000000 --- a/src/linux/include/uapi/asm-generic/shmbuf.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef __ASM_GENERIC_SHMBUF_H -#define __ASM_GENERIC_SHMBUF_H - -#include - -/* - * The shmid64_ds structure for x86 architecture. - * Note extra padding because this structure is passed back and forth - * between kernel and user space. - * - * shmid64_ds was originally meant to be architecture specific, but - * everyone just ended up making identical copies without specific - * optimizations, so we may just as well all use the same one. - * - * 64 bit architectures typically define a 64 bit __kernel_time_t, - * so they do not need the first two padding words. - * On big-endian systems, the padding is in the wrong place. - * - * - * Pad space is left for: - * - 64-bit time_t to solve y2038 problem - * - 2 miscellaneous 32-bit values - */ - -struct shmid64_ds { - struct ipc64_perm shm_perm; /* operation perms */ - size_t shm_segsz; /* size of segment (bytes) */ - __kernel_time_t shm_atime; /* last attach time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused1; -#endif - __kernel_time_t shm_dtime; /* last detach time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused2; -#endif - __kernel_time_t shm_ctime; /* last change time */ -#if __BITS_PER_LONG != 64 - unsigned long __unused3; -#endif - __kernel_pid_t shm_cpid; /* pid of creator */ - __kernel_pid_t shm_lpid; /* pid of last operator */ - __kernel_ulong_t shm_nattch; /* no. of current attaches */ - __kernel_ulong_t __unused4; - __kernel_ulong_t __unused5; -}; - -struct shminfo64 { - __kernel_ulong_t shmmax; - __kernel_ulong_t shmmin; - __kernel_ulong_t shmmni; - __kernel_ulong_t shmseg; - __kernel_ulong_t shmall; - __kernel_ulong_t __unused1; - __kernel_ulong_t __unused2; - __kernel_ulong_t __unused3; - __kernel_ulong_t __unused4; -}; - -#endif /* __ASM_GENERIC_SHMBUF_H */ diff --git a/src/linux/include/uapi/asm-generic/shmparam.h b/src/linux/include/uapi/asm-generic/shmparam.h deleted file mode 100644 index 51a3852..0000000 --- a/src/linux/include/uapi/asm-generic/shmparam.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef __ASM_GENERIC_SHMPARAM_H -#define __ASM_GENERIC_SHMPARAM_H - -#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */ - -#endif /* _ASM_GENERIC_SHMPARAM_H */ diff --git a/src/linux/include/uapi/asm-generic/siginfo.h b/src/linux/include/uapi/asm-generic/siginfo.h deleted file mode 100644 index 1abaf62..0000000 --- a/src/linux/include/uapi/asm-generic/siginfo.h +++ /dev/null @@ -1,312 +0,0 @@ -#ifndef _UAPI_ASM_GENERIC_SIGINFO_H -#define _UAPI_ASM_GENERIC_SIGINFO_H - -#include -#include - -typedef union sigval { - int sival_int; - void __user *sival_ptr; -} sigval_t; - -/* - * This is the size (including padding) of the part of the - * struct siginfo that is before the union. - */ -#ifndef __ARCH_SI_PREAMBLE_SIZE -#define __ARCH_SI_PREAMBLE_SIZE (3 * sizeof(int)) -#endif - -#define SI_MAX_SIZE 128 -#ifndef SI_PAD_SIZE -#define SI_PAD_SIZE ((SI_MAX_SIZE - __ARCH_SI_PREAMBLE_SIZE) / sizeof(int)) -#endif - -#ifndef __ARCH_SI_UID_T -#define __ARCH_SI_UID_T __kernel_uid32_t -#endif - -/* - * The default "si_band" type is "long", as specified by POSIX. - * However, some architectures want to override this to "int" - * for historical compatibility reasons, so we allow that. - */ -#ifndef __ARCH_SI_BAND_T -#define __ARCH_SI_BAND_T long -#endif - -#ifndef __ARCH_SI_CLOCK_T -#define __ARCH_SI_CLOCK_T __kernel_clock_t -#endif - -#ifndef __ARCH_SI_ATTRIBUTES -#define __ARCH_SI_ATTRIBUTES -#endif - -#ifndef HAVE_ARCH_SIGINFO_T - -typedef struct siginfo { - int si_signo; - int si_errno; - int si_code; - - union { - int _pad[SI_PAD_SIZE]; - - /* kill() */ - struct { - __kernel_pid_t _pid; /* sender's pid */ - __ARCH_SI_UID_T _uid; /* sender's uid */ - } _kill; - - /* POSIX.1b timers */ - struct { - __kernel_timer_t _tid; /* timer id */ - int _overrun; /* overrun count */ - char _pad[sizeof( __ARCH_SI_UID_T) - sizeof(int)]; - sigval_t _sigval; /* same as below */ - int _sys_private; /* not to be passed to user */ - } _timer; - - /* POSIX.1b signals */ - struct { - __kernel_pid_t _pid; /* sender's pid */ - __ARCH_SI_UID_T _uid; /* sender's uid */ - sigval_t _sigval; - } _rt; - - /* SIGCHLD */ - struct { - __kernel_pid_t _pid; /* which child */ - __ARCH_SI_UID_T _uid; /* sender's uid */ - int _status; /* exit code */ - __ARCH_SI_CLOCK_T _utime; - __ARCH_SI_CLOCK_T _stime; - } _sigchld; - - /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ - struct { - void __user *_addr; /* faulting insn/memory ref. */ -#ifdef __ARCH_SI_TRAPNO - int _trapno; /* TRAP # which caused the signal */ -#endif - short _addr_lsb; /* LSB of the reported address */ - union { - /* used when si_code=SEGV_BNDERR */ - struct { - void __user *_lower; - void __user *_upper; - } _addr_bnd; - /* used when si_code=SEGV_PKUERR */ - __u32 _pkey; - }; - } _sigfault; - - /* SIGPOLL */ - struct { - __ARCH_SI_BAND_T _band; /* POLL_IN, POLL_OUT, POLL_MSG */ - int _fd; - } _sigpoll; - - /* SIGSYS */ - struct { - void __user *_call_addr; /* calling user insn */ - int _syscall; /* triggering system call number */ - unsigned int _arch; /* AUDIT_ARCH_* of syscall */ - } _sigsys; - } _sifields; -} __ARCH_SI_ATTRIBUTES siginfo_t; - -/* If the arch shares siginfo, then it has SIGSYS. */ -#define __ARCH_SIGSYS -#endif - -/* - * How these fields are to be accessed. - */ -#define si_pid _sifields._kill._pid -#define si_uid _sifields._kill._uid -#define si_tid _sifields._timer._tid -#define si_overrun _sifields._timer._overrun -#define si_sys_private _sifields._timer._sys_private -#define si_status _sifields._sigchld._status -#define si_utime _sifields._sigchld._utime -#define si_stime _sifields._sigchld._stime -#define si_value _sifields._rt._sigval -#define si_int _sifields._rt._sigval.sival_int -#define si_ptr _sifields._rt._sigval.sival_ptr -#define si_addr _sifields._sigfault._addr -#ifdef __ARCH_SI_TRAPNO -#define si_trapno _sifields._sigfault._trapno -#endif -#define si_addr_lsb _sifields._sigfault._addr_lsb -#define si_lower _sifields._sigfault._addr_bnd._lower -#define si_upper _sifields._sigfault._addr_bnd._upper -#define si_pkey _sifields._sigfault._pkey -#define si_band _sifields._sigpoll._band -#define si_fd _sifields._sigpoll._fd -#ifdef __ARCH_SIGSYS -#define si_call_addr _sifields._sigsys._call_addr -#define si_syscall _sifields._sigsys._syscall -#define si_arch _sifields._sigsys._arch -#endif - -#ifndef __KERNEL__ -#define __SI_KILL 0 -#define __SI_TIMER 0 -#define __SI_POLL 0 -#define __SI_FAULT 0 -#define __SI_CHLD 0 -#define __SI_RT 0 -#define __SI_MESGQ 0 -#define __SI_SYS 0 -#define __SI_CODE(T,N) (N) -#endif - -/* - * si_code values - * Digital reserves positive values for kernel-generated signals. - */ -#define SI_USER 0 /* sent by kill, sigsend, raise */ -#define SI_KERNEL 0x80 /* sent by the kernel from somewhere */ -#define SI_QUEUE -1 /* sent by sigqueue */ -#define SI_TIMER __SI_CODE(__SI_TIMER,-2) /* sent by timer expiration */ -#define SI_MESGQ __SI_CODE(__SI_MESGQ,-3) /* sent by real time mesq state change */ -#define SI_ASYNCIO -4 /* sent by AIO completion */ -#define SI_SIGIO -5 /* sent by queued SIGIO */ -#define SI_TKILL -6 /* sent by tkill system call */ -#define SI_DETHREAD -7 /* sent by execve() killing subsidiary threads */ - -#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0) -#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0) - -/* - * SIGILL si_codes - */ -#define ILL_ILLOPC (__SI_FAULT|1) /* illegal opcode */ -#define ILL_ILLOPN (__SI_FAULT|2) /* illegal operand */ -#define ILL_ILLADR (__SI_FAULT|3) /* illegal addressing mode */ -#define ILL_ILLTRP (__SI_FAULT|4) /* illegal trap */ -#define ILL_PRVOPC (__SI_FAULT|5) /* privileged opcode */ -#define ILL_PRVREG (__SI_FAULT|6) /* privileged register */ -#define ILL_COPROC (__SI_FAULT|7) /* coprocessor error */ -#define ILL_BADSTK (__SI_FAULT|8) /* internal stack error */ -#define NSIGILL 8 - -/* - * SIGFPE si_codes - */ -#define FPE_INTDIV (__SI_FAULT|1) /* integer divide by zero */ -#define FPE_INTOVF (__SI_FAULT|2) /* integer overflow */ -#define FPE_FLTDIV (__SI_FAULT|3) /* floating point divide by zero */ -#define FPE_FLTOVF (__SI_FAULT|4) /* floating point overflow */ -#define FPE_FLTUND (__SI_FAULT|5) /* floating point underflow */ -#define FPE_FLTRES (__SI_FAULT|6) /* floating point inexact result */ -#define FPE_FLTINV (__SI_FAULT|7) /* floating point invalid operation */ -#define FPE_FLTSUB (__SI_FAULT|8) /* subscript out of range */ -#define NSIGFPE 8 - -/* - * SIGSEGV si_codes - */ -#define SEGV_MAPERR (__SI_FAULT|1) /* address not mapped to object */ -#define SEGV_ACCERR (__SI_FAULT|2) /* invalid permissions for mapped object */ -#define SEGV_BNDERR (__SI_FAULT|3) /* failed address bound checks */ -#define SEGV_PKUERR (__SI_FAULT|4) /* failed protection key checks */ -#define NSIGSEGV 4 - -/* - * SIGBUS si_codes - */ -#define BUS_ADRALN (__SI_FAULT|1) /* invalid address alignment */ -#define BUS_ADRERR (__SI_FAULT|2) /* non-existent physical address */ -#define BUS_OBJERR (__SI_FAULT|3) /* object specific hardware error */ -/* hardware memory error consumed on a machine check: action required */ -#define BUS_MCEERR_AR (__SI_FAULT|4) -/* hardware memory error detected in process but not consumed: action optional*/ -#define BUS_MCEERR_AO (__SI_FAULT|5) -#define NSIGBUS 5 - -/* - * SIGTRAP si_codes - */ -#define TRAP_BRKPT (__SI_FAULT|1) /* process breakpoint */ -#define TRAP_TRACE (__SI_FAULT|2) /* process trace trap */ -#define TRAP_BRANCH (__SI_FAULT|3) /* process taken branch trap */ -#define TRAP_HWBKPT (__SI_FAULT|4) /* hardware breakpoint/watchpoint */ -#define NSIGTRAP 4 - -/* - * SIGCHLD si_codes - */ -#define CLD_EXITED (__SI_CHLD|1) /* child has exited */ -#define CLD_KILLED (__SI_CHLD|2) /* child was killed */ -#define CLD_DUMPED (__SI_CHLD|3) /* child terminated abnormally */ -#define CLD_TRAPPED (__SI_CHLD|4) /* traced child has trapped */ -#define CLD_STOPPED (__SI_CHLD|5) /* child has stopped */ -#define CLD_CONTINUED (__SI_CHLD|6) /* stopped child has continued */ -#define NSIGCHLD 6 - -/* - * SIGPOLL si_codes - */ -#define POLL_IN (__SI_POLL|1) /* data input available */ -#define POLL_OUT (__SI_POLL|2) /* output buffers available */ -#define POLL_MSG (__SI_POLL|3) /* input message available */ -#define POLL_ERR (__SI_POLL|4) /* i/o error */ -#define POLL_PRI (__SI_POLL|5) /* high priority input available */ -#define POLL_HUP (__SI_POLL|6) /* device disconnected */ -#define NSIGPOLL 6 - -/* - * SIGSYS si_codes - */ -#define SYS_SECCOMP (__SI_SYS|1) /* seccomp triggered */ -#define NSIGSYS 1 - -/* - * sigevent definitions - * - * It seems likely that SIGEV_THREAD will have to be handled from - * userspace, libpthread transmuting it to SIGEV_SIGNAL, which the - * thread manager then catches and does the appropriate nonsense. - * However, everything is written out here so as to not get lost. - */ -#define SIGEV_SIGNAL 0 /* notify via signal */ -#define SIGEV_NONE 1 /* other notification: meaningless */ -#define SIGEV_THREAD 2 /* deliver via thread creation */ -#define SIGEV_THREAD_ID 4 /* deliver to thread */ - -/* - * This works because the alignment is ok on all current architectures - * but we leave open this being overridden in the future - */ -#ifndef __ARCH_SIGEV_PREAMBLE_SIZE -#define __ARCH_SIGEV_PREAMBLE_SIZE (sizeof(int) * 2 + sizeof(sigval_t)) -#endif - -#define SIGEV_MAX_SIZE 64 -#define SIGEV_PAD_SIZE ((SIGEV_MAX_SIZE - __ARCH_SIGEV_PREAMBLE_SIZE) \ - / sizeof(int)) - -typedef struct sigevent { - sigval_t sigev_value; - int sigev_signo; - int sigev_notify; - union { - int _pad[SIGEV_PAD_SIZE]; - int _tid; - - struct { - void (*_function)(sigval_t); - void *_attribute; /* really pthread_attr_t */ - } _sigev_thread; - } _sigev_un; -} sigevent_t; - -#define sigev_notify_function _sigev_un._sigev_thread._function -#define sigev_notify_attributes _sigev_un._sigev_thread._attribute -#define sigev_notify_thread_id _sigev_un._tid - - -#endif /* _UAPI_ASM_GENERIC_SIGINFO_H */ diff --git a/src/linux/include/uapi/asm-generic/signal-defs.h b/src/linux/include/uapi/asm-generic/signal-defs.h deleted file mode 100644 index 00f95df..0000000 --- a/src/linux/include/uapi/asm-generic/signal-defs.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef __ASM_GENERIC_SIGNAL_DEFS_H -#define __ASM_GENERIC_SIGNAL_DEFS_H - -#include - -#ifndef SIG_BLOCK -#define SIG_BLOCK 0 /* for blocking signals */ -#endif -#ifndef SIG_UNBLOCK -#define SIG_UNBLOCK 1 /* for unblocking signals */ -#endif -#ifndef SIG_SETMASK -#define SIG_SETMASK 2 /* for setting the signal mask */ -#endif - -#ifndef __ASSEMBLY__ -typedef void __signalfn_t(int); -typedef __signalfn_t __user *__sighandler_t; - -typedef void __restorefn_t(void); -typedef __restorefn_t __user *__sigrestore_t; - -#define SIG_DFL ((__force __sighandler_t)0) /* default signal handling */ -#define SIG_IGN ((__force __sighandler_t)1) /* ignore signal */ -#define SIG_ERR ((__force __sighandler_t)-1) /* error return from signal */ -#endif - -#endif /* __ASM_GENERIC_SIGNAL_DEFS_H */ diff --git a/src/linux/include/uapi/asm-generic/signal.h b/src/linux/include/uapi/asm-generic/signal.h deleted file mode 100644 index 3094618..0000000 --- a/src/linux/include/uapi/asm-generic/signal.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef _UAPI__ASM_GENERIC_SIGNAL_H -#define _UAPI__ASM_GENERIC_SIGNAL_H - -#include - -#define _NSIG 64 -#define _NSIG_BPW __BITS_PER_LONG -#define _NSIG_WORDS (_NSIG / _NSIG_BPW) - -#define SIGHUP 1 -#define SIGINT 2 -#define SIGQUIT 3 -#define SIGILL 4 -#define SIGTRAP 5 -#define SIGABRT 6 -#define SIGIOT 6 -#define SIGBUS 7 -#define SIGFPE 8 -#define SIGKILL 9 -#define SIGUSR1 10 -#define SIGSEGV 11 -#define SIGUSR2 12 -#define SIGPIPE 13 -#define SIGALRM 14 -#define SIGTERM 15 -#define SIGSTKFLT 16 -#define SIGCHLD 17 -#define SIGCONT 18 -#define SIGSTOP 19 -#define SIGTSTP 20 -#define SIGTTIN 21 -#define SIGTTOU 22 -#define SIGURG 23 -#define SIGXCPU 24 -#define SIGXFSZ 25 -#define SIGVTALRM 26 -#define SIGPROF 27 -#define SIGWINCH 28 -#define SIGIO 29 -#define SIGPOLL SIGIO -/* -#define SIGLOST 29 -*/ -#define SIGPWR 30 -#define SIGSYS 31 -#define SIGUNUSED 31 - -/* These should not be considered constants from userland. */ -#define SIGRTMIN 32 -#ifndef SIGRTMAX -#define SIGRTMAX _NSIG -#endif - -/* - * SA_FLAGS values: - * - * SA_ONSTACK indicates that a registered stack_t will be used. - * SA_RESTART flag to get restarting signals (which were the default long ago) - * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. - * SA_RESETHAND clears the handler when the signal is delivered. - * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. - * SA_NODEFER prevents the current signal from being masked in the handler. - * - * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single - * Unix names RESETHAND and NODEFER respectively. - */ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002 -#define SA_SIGINFO 0x00000004 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 - -#define SA_NOMASK SA_NODEFER -#define SA_ONESHOT SA_RESETHAND - -/* - * New architectures should not define the obsolete - * SA_RESTORER 0x04000000 - */ - -#if !defined MINSIGSTKSZ || !defined SIGSTKSZ -#define MINSIGSTKSZ 2048 -#define SIGSTKSZ 8192 -#endif - -#ifndef __ASSEMBLY__ -typedef struct { - unsigned long sig[_NSIG_WORDS]; -} sigset_t; - -/* not actually used, but required for linux/syscalls.h */ -typedef unsigned long old_sigset_t; - -#include - -#ifdef SA_RESTORER -#define __ARCH_HAS_SA_RESTORER -#endif - -#ifndef __KERNEL__ -struct sigaction { - __sighandler_t sa_handler; - unsigned long sa_flags; -#ifdef SA_RESTORER - __sigrestore_t sa_restorer; -#endif - sigset_t sa_mask; /* mask last for extensibility */ -}; -#endif - -typedef struct sigaltstack { - void __user *ss_sp; - int ss_flags; - size_t ss_size; -} stack_t; - -#endif /* __ASSEMBLY__ */ - -#endif /* _UAPI__ASM_GENERIC_SIGNAL_H */ diff --git a/src/linux/include/uapi/asm-generic/socket.h b/src/linux/include/uapi/asm-generic/socket.h deleted file mode 100644 index 67d632f..0000000 --- a/src/linux/include/uapi/asm-generic/socket.h +++ /dev/null @@ -1,95 +0,0 @@ -#ifndef __ASM_GENERIC_SOCKET_H -#define __ASM_GENERIC_SOCKET_H - -#include - -/* For setsockopt(2) */ -#define SOL_SOCKET 1 - -#define SO_DEBUG 1 -#define SO_REUSEADDR 2 -#define SO_TYPE 3 -#define SO_ERROR 4 -#define SO_DONTROUTE 5 -#define SO_BROADCAST 6 -#define SO_SNDBUF 7 -#define SO_RCVBUF 8 -#define SO_SNDBUFFORCE 32 -#define SO_RCVBUFFORCE 33 -#define SO_KEEPALIVE 9 -#define SO_OOBINLINE 10 -#define SO_NO_CHECK 11 -#define SO_PRIORITY 12 -#define SO_LINGER 13 -#define SO_BSDCOMPAT 14 -#define SO_REUSEPORT 15 -#ifndef SO_PASSCRED /* powerpc only differs in these */ -#define SO_PASSCRED 16 -#define SO_PEERCRED 17 -#define SO_RCVLOWAT 18 -#define SO_SNDLOWAT 19 -#define SO_RCVTIMEO 20 -#define SO_SNDTIMEO 21 -#endif - -/* Security levels - as per NRL IPv6 - don't actually do anything */ -#define SO_SECURITY_AUTHENTICATION 22 -#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 -#define SO_SECURITY_ENCRYPTION_NETWORK 24 - -#define SO_BINDTODEVICE 25 - -/* Socket filtering */ -#define SO_ATTACH_FILTER 26 -#define SO_DETACH_FILTER 27 -#define SO_GET_FILTER SO_ATTACH_FILTER - -#define SO_PEERNAME 28 -#define SO_TIMESTAMP 29 -#define SCM_TIMESTAMP SO_TIMESTAMP - -#define SO_ACCEPTCONN 30 - -#define SO_PEERSEC 31 -#define SO_PASSSEC 34 -#define SO_TIMESTAMPNS 35 -#define SCM_TIMESTAMPNS SO_TIMESTAMPNS - -#define SO_MARK 36 - -#define SO_TIMESTAMPING 37 -#define SCM_TIMESTAMPING SO_TIMESTAMPING - -#define SO_PROTOCOL 38 -#define SO_DOMAIN 39 - -#define SO_RXQ_OVFL 40 - -#define SO_WIFI_STATUS 41 -#define SCM_WIFI_STATUS SO_WIFI_STATUS -#define SO_PEEK_OFF 42 - -/* Instruct lower device to use last 4-bytes of skb data as FCS */ -#define SO_NOFCS 43 - -#define SO_LOCK_FILTER 44 - -#define SO_SELECT_ERR_QUEUE 45 - -#define SO_BUSY_POLL 46 - -#define SO_MAX_PACING_RATE 47 - -#define SO_BPF_EXTENSIONS 48 - -#define SO_INCOMING_CPU 49 - -#define SO_ATTACH_BPF 50 -#define SO_DETACH_BPF SO_DETACH_FILTER - -#define SO_ATTACH_REUSEPORT_CBPF 51 -#define SO_ATTACH_REUSEPORT_EBPF 52 - -#define SO_CNX_ADVICE 53 - -#endif /* __ASM_GENERIC_SOCKET_H */ diff --git a/src/linux/include/uapi/asm-generic/sockios.h b/src/linux/include/uapi/asm-generic/sockios.h deleted file mode 100644 index 9a61a36..0000000 --- a/src/linux/include/uapi/asm-generic/sockios.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __ASM_GENERIC_SOCKIOS_H -#define __ASM_GENERIC_SOCKIOS_H - -/* Socket-level I/O control calls. */ -#define FIOSETOWN 0x8901 -#define SIOCSPGRP 0x8902 -#define FIOGETOWN 0x8903 -#define SIOCGPGRP 0x8904 -#define SIOCATMARK 0x8905 -#define SIOCGSTAMP 0x8906 /* Get stamp (timeval) */ -#define SIOCGSTAMPNS 0x8907 /* Get stamp (timespec) */ - -#endif /* __ASM_GENERIC_SOCKIOS_H */ diff --git a/src/linux/include/uapi/asm-generic/stat.h b/src/linux/include/uapi/asm-generic/stat.h deleted file mode 100644 index bd8cad2..0000000 --- a/src/linux/include/uapi/asm-generic/stat.h +++ /dev/null @@ -1,72 +0,0 @@ -#ifndef __ASM_GENERIC_STAT_H -#define __ASM_GENERIC_STAT_H - -/* - * Everybody gets this wrong and has to stick with it for all - * eternity. Hopefully, this version gets used by new architectures - * so they don't fall into the same traps. - * - * stat64 is copied from powerpc64, with explicit padding added. - * stat is the same structure layout on 64-bit, without the 'long long' - * types. - * - * By convention, 64 bit architectures use the stat interface, while - * 32 bit architectures use the stat64 interface. Note that we don't - * provide an __old_kernel_stat here, which new architecture should - * not have to start with. - */ - -#include - -#define STAT_HAVE_NSEC 1 - -struct stat { - unsigned long st_dev; /* Device. */ - unsigned long st_ino; /* File serial number. */ - unsigned int st_mode; /* File mode. */ - unsigned int st_nlink; /* Link count. */ - unsigned int st_uid; /* User ID of the file's owner. */ - unsigned int st_gid; /* Group ID of the file's group. */ - unsigned long st_rdev; /* Device number, if device. */ - unsigned long __pad1; - long st_size; /* Size of file, in bytes. */ - int st_blksize; /* Optimal block size for I/O. */ - int __pad2; - long st_blocks; /* Number 512-byte blocks allocated. */ - long st_atime; /* Time of last access. */ - unsigned long st_atime_nsec; - long st_mtime; /* Time of last modification. */ - unsigned long st_mtime_nsec; - long st_ctime; /* Time of last status change. */ - unsigned long st_ctime_nsec; - unsigned int __unused4; - unsigned int __unused5; -}; - -/* This matches struct stat64 in glibc2.1. Only used for 32 bit. */ -#if __BITS_PER_LONG != 64 || defined(__ARCH_WANT_STAT64) -struct stat64 { - unsigned long long st_dev; /* Device. */ - unsigned long long st_ino; /* File serial number. */ - unsigned int st_mode; /* File mode. */ - unsigned int st_nlink; /* Link count. */ - unsigned int st_uid; /* User ID of the file's owner. */ - unsigned int st_gid; /* Group ID of the file's group. */ - unsigned long long st_rdev; /* Device number, if device. */ - unsigned long long __pad1; - long long st_size; /* Size of file, in bytes. */ - int st_blksize; /* Optimal block size for I/O. */ - int __pad2; - long long st_blocks; /* Number 512-byte blocks allocated. */ - int st_atime; /* Time of last access. */ - unsigned int st_atime_nsec; - int st_mtime; /* Time of last modification. */ - unsigned int st_mtime_nsec; - int st_ctime; /* Time of last status change. */ - unsigned int st_ctime_nsec; - unsigned int __unused4; - unsigned int __unused5; -}; -#endif - -#endif /* __ASM_GENERIC_STAT_H */ diff --git a/src/linux/include/uapi/asm-generic/statfs.h b/src/linux/include/uapi/asm-generic/statfs.h deleted file mode 100644 index cb89cc7..0000000 --- a/src/linux/include/uapi/asm-generic/statfs.h +++ /dev/null @@ -1,83 +0,0 @@ -#ifndef _UAPI_GENERIC_STATFS_H -#define _UAPI_GENERIC_STATFS_H - -#include - - -/* - * Most 64-bit platforms use 'long', while most 32-bit platforms use '__u32'. - * Yes, they differ in signedness as well as size. - * Special cases can override it for themselves -- except for S390x, which - * is just a little too special for us. And MIPS, which I'm not touching - * with a 10' pole. - */ -#ifndef __statfs_word -#if __BITS_PER_LONG == 64 -#define __statfs_word __kernel_long_t -#else -#define __statfs_word __u32 -#endif -#endif - -struct statfs { - __statfs_word f_type; - __statfs_word f_bsize; - __statfs_word f_blocks; - __statfs_word f_bfree; - __statfs_word f_bavail; - __statfs_word f_files; - __statfs_word f_ffree; - __kernel_fsid_t f_fsid; - __statfs_word f_namelen; - __statfs_word f_frsize; - __statfs_word f_flags; - __statfs_word f_spare[4]; -}; - -/* - * ARM needs to avoid the 32-bit padding at the end, for consistency - * between EABI and OABI - */ -#ifndef ARCH_PACK_STATFS64 -#define ARCH_PACK_STATFS64 -#endif - -struct statfs64 { - __statfs_word f_type; - __statfs_word f_bsize; - __u64 f_blocks; - __u64 f_bfree; - __u64 f_bavail; - __u64 f_files; - __u64 f_ffree; - __kernel_fsid_t f_fsid; - __statfs_word f_namelen; - __statfs_word f_frsize; - __statfs_word f_flags; - __statfs_word f_spare[4]; -} ARCH_PACK_STATFS64; - -/* - * IA64 and x86_64 need to avoid the 32-bit padding at the end, - * to be compatible with the i386 ABI - */ -#ifndef ARCH_PACK_COMPAT_STATFS64 -#define ARCH_PACK_COMPAT_STATFS64 -#endif - -struct compat_statfs64 { - __u32 f_type; - __u32 f_bsize; - __u64 f_blocks; - __u64 f_bfree; - __u64 f_bavail; - __u64 f_files; - __u64 f_ffree; - __kernel_fsid_t f_fsid; - __u32 f_namelen; - __u32 f_frsize; - __u32 f_flags; - __u32 f_spare[4]; -} ARCH_PACK_COMPAT_STATFS64; - -#endif /* _UAPI_GENERIC_STATFS_H */ diff --git a/src/linux/include/uapi/asm-generic/swab.h b/src/linux/include/uapi/asm-generic/swab.h deleted file mode 100644 index a8e9029..0000000 --- a/src/linux/include/uapi/asm-generic/swab.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _ASM_GENERIC_SWAB_H -#define _ASM_GENERIC_SWAB_H - -#include - -/* - * 32 bit architectures typically (but not always) want to - * set __SWAB_64_THRU_32__. In user space, this is only - * valid if the compiler supports 64 bit data types. - */ - -#if __BITS_PER_LONG == 32 -#if defined(__GNUC__) && !defined(__STRICT_ANSI__) || defined(__KERNEL__) -#define __SWAB_64_THRU_32__ -#endif -#endif - -#endif /* _ASM_GENERIC_SWAB_H */ diff --git a/src/linux/include/uapi/asm-generic/termbits.h b/src/linux/include/uapi/asm-generic/termbits.h deleted file mode 100644 index 232b478..0000000 --- a/src/linux/include/uapi/asm-generic/termbits.h +++ /dev/null @@ -1,199 +0,0 @@ -#ifndef __ASM_GENERIC_TERMBITS_H -#define __ASM_GENERIC_TERMBITS_H - -#include - -typedef unsigned char cc_t; -typedef unsigned int speed_t; -typedef unsigned int tcflag_t; - -#define NCCS 19 -struct termios { - tcflag_t c_iflag; /* input mode flags */ - tcflag_t c_oflag; /* output mode flags */ - tcflag_t c_cflag; /* control mode flags */ - tcflag_t c_lflag; /* local mode flags */ - cc_t c_line; /* line discipline */ - cc_t c_cc[NCCS]; /* control characters */ -}; - -struct termios2 { - tcflag_t c_iflag; /* input mode flags */ - tcflag_t c_oflag; /* output mode flags */ - tcflag_t c_cflag; /* control mode flags */ - tcflag_t c_lflag; /* local mode flags */ - cc_t c_line; /* line discipline */ - cc_t c_cc[NCCS]; /* control characters */ - speed_t c_ispeed; /* input speed */ - speed_t c_ospeed; /* output speed */ -}; - -struct ktermios { - tcflag_t c_iflag; /* input mode flags */ - tcflag_t c_oflag; /* output mode flags */ - tcflag_t c_cflag; /* control mode flags */ - tcflag_t c_lflag; /* local mode flags */ - cc_t c_line; /* line discipline */ - cc_t c_cc[NCCS]; /* control characters */ - speed_t c_ispeed; /* input speed */ - speed_t c_ospeed; /* output speed */ -}; - -/* c_cc characters */ -#define VINTR 0 -#define VQUIT 1 -#define VERASE 2 -#define VKILL 3 -#define VEOF 4 -#define VTIME 5 -#define VMIN 6 -#define VSWTC 7 -#define VSTART 8 -#define VSTOP 9 -#define VSUSP 10 -#define VEOL 11 -#define VREPRINT 12 -#define VDISCARD 13 -#define VWERASE 14 -#define VLNEXT 15 -#define VEOL2 16 - -/* c_iflag bits */ -#define IGNBRK 0000001 -#define BRKINT 0000002 -#define IGNPAR 0000004 -#define PARMRK 0000010 -#define INPCK 0000020 -#define ISTRIP 0000040 -#define INLCR 0000100 -#define IGNCR 0000200 -#define ICRNL 0000400 -#define IUCLC 0001000 -#define IXON 0002000 -#define IXANY 0004000 -#define IXOFF 0010000 -#define IMAXBEL 0020000 -#define IUTF8 0040000 - -/* c_oflag bits */ -#define OPOST 0000001 -#define OLCUC 0000002 -#define ONLCR 0000004 -#define OCRNL 0000010 -#define ONOCR 0000020 -#define ONLRET 0000040 -#define OFILL 0000100 -#define OFDEL 0000200 -#define NLDLY 0000400 -#define NL0 0000000 -#define NL1 0000400 -#define CRDLY 0003000 -#define CR0 0000000 -#define CR1 0001000 -#define CR2 0002000 -#define CR3 0003000 -#define TABDLY 0014000 -#define TAB0 0000000 -#define TAB1 0004000 -#define TAB2 0010000 -#define TAB3 0014000 -#define XTABS 0014000 -#define BSDLY 0020000 -#define BS0 0000000 -#define BS1 0020000 -#define VTDLY 0040000 -#define VT0 0000000 -#define VT1 0040000 -#define FFDLY 0100000 -#define FF0 0000000 -#define FF1 0100000 - -/* c_cflag bit meaning */ -#define CBAUD 0010017 -#define B0 0000000 /* hang up */ -#define B50 0000001 -#define B75 0000002 -#define B110 0000003 -#define B134 0000004 -#define B150 0000005 -#define B200 0000006 -#define B300 0000007 -#define B600 0000010 -#define B1200 0000011 -#define B1800 0000012 -#define B2400 0000013 -#define B4800 0000014 -#define B9600 0000015 -#define B19200 0000016 -#define B38400 0000017 -#define EXTA B19200 -#define EXTB B38400 -#define CSIZE 0000060 -#define CS5 0000000 -#define CS6 0000020 -#define CS7 0000040 -#define CS8 0000060 -#define CSTOPB 0000100 -#define CREAD 0000200 -#define PARENB 0000400 -#define PARODD 0001000 -#define HUPCL 0002000 -#define CLOCAL 0004000 -#define CBAUDEX 0010000 -#define BOTHER 0010000 -#define B57600 0010001 -#define B115200 0010002 -#define B230400 0010003 -#define B460800 0010004 -#define B500000 0010005 -#define B576000 0010006 -#define B921600 0010007 -#define B1000000 0010010 -#define B1152000 0010011 -#define B1500000 0010012 -#define B2000000 0010013 -#define B2500000 0010014 -#define B3000000 0010015 -#define B3500000 0010016 -#define B4000000 0010017 -#define CIBAUD 002003600000 /* input baud rate */ -#define CMSPAR 010000000000 /* mark or space (stick) parity */ -#define CRTSCTS 020000000000 /* flow control */ - -#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */ - -/* c_lflag bits */ -#define ISIG 0000001 -#define ICANON 0000002 -#define XCASE 0000004 -#define ECHO 0000010 -#define ECHOE 0000020 -#define ECHOK 0000040 -#define ECHONL 0000100 -#define NOFLSH 0000200 -#define TOSTOP 0000400 -#define ECHOCTL 0001000 -#define ECHOPRT 0002000 -#define ECHOKE 0004000 -#define FLUSHO 0010000 -#define PENDIN 0040000 -#define IEXTEN 0100000 -#define EXTPROC 0200000 - -/* tcflow() and TCXONC use these */ -#define TCOOFF 0 -#define TCOON 1 -#define TCIOFF 2 -#define TCION 3 - -/* tcflush() and TCFLSH use these */ -#define TCIFLUSH 0 -#define TCOFLUSH 1 -#define TCIOFLUSH 2 - -/* tcsetattr uses these */ -#define TCSANOW 0 -#define TCSADRAIN 1 -#define TCSAFLUSH 2 - -#endif /* __ASM_GENERIC_TERMBITS_H */ diff --git a/src/linux/include/uapi/asm-generic/termios.h b/src/linux/include/uapi/asm-generic/termios.h deleted file mode 100644 index 0881760..0000000 --- a/src/linux/include/uapi/asm-generic/termios.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef _UAPI_ASM_GENERIC_TERMIOS_H -#define _UAPI_ASM_GENERIC_TERMIOS_H -/* - * Most architectures have straight copies of the x86 code, with - * varying levels of bug fixes on top. Usually it's a good idea - * to use this generic version instead, but be careful to avoid - * ABI changes. - * New architectures should not provide their own version. - */ - -#include -#include - -struct winsize { - unsigned short ws_row; - unsigned short ws_col; - unsigned short ws_xpixel; - unsigned short ws_ypixel; -}; - -#define NCC 8 -struct termio { - unsigned short c_iflag; /* input mode flags */ - unsigned short c_oflag; /* output mode flags */ - unsigned short c_cflag; /* control mode flags */ - unsigned short c_lflag; /* local mode flags */ - unsigned char c_line; /* line discipline */ - unsigned char c_cc[NCC]; /* control characters */ -}; - -/* modem lines */ -#define TIOCM_LE 0x001 -#define TIOCM_DTR 0x002 -#define TIOCM_RTS 0x004 -#define TIOCM_ST 0x008 -#define TIOCM_SR 0x010 -#define TIOCM_CTS 0x020 -#define TIOCM_CAR 0x040 -#define TIOCM_RNG 0x080 -#define TIOCM_DSR 0x100 -#define TIOCM_CD TIOCM_CAR -#define TIOCM_RI TIOCM_RNG -#define TIOCM_OUT1 0x2000 -#define TIOCM_OUT2 0x4000 -#define TIOCM_LOOP 0x8000 - -/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ - - -#endif /* _UAPI_ASM_GENERIC_TERMIOS_H */ diff --git a/src/linux/include/uapi/asm-generic/types.h b/src/linux/include/uapi/asm-generic/types.h deleted file mode 100644 index a387792..0000000 --- a/src/linux/include/uapi/asm-generic/types.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _ASM_GENERIC_TYPES_H -#define _ASM_GENERIC_TYPES_H -/* - * int-ll64 is used everywhere now. - */ -#include - -#endif /* _ASM_GENERIC_TYPES_H */ diff --git a/src/linux/include/uapi/asm-generic/unistd.h b/src/linux/include/uapi/asm-generic/unistd.h deleted file mode 100644 index 9b1462e..0000000 --- a/src/linux/include/uapi/asm-generic/unistd.h +++ /dev/null @@ -1,942 +0,0 @@ -#include - -/* - * This file contains the system call numbers, based on the - * layout of the x86-64 architecture, which embeds the - * pointer to the syscall in the table. - * - * As a basic principle, no duplication of functionality - * should be added, e.g. we don't use lseek when llseek - * is present. New architectures should use this file - * and implement the less feature-full calls in user space. - */ - -#ifndef __SYSCALL -#define __SYSCALL(x, y) -#endif - -#if __BITS_PER_LONG == 32 || defined(__SYSCALL_COMPAT) -#define __SC_3264(_nr, _32, _64) __SYSCALL(_nr, _32) -#else -#define __SC_3264(_nr, _32, _64) __SYSCALL(_nr, _64) -#endif - -#ifdef __SYSCALL_COMPAT -#define __SC_COMP(_nr, _sys, _comp) __SYSCALL(_nr, _comp) -#define __SC_COMP_3264(_nr, _32, _64, _comp) __SYSCALL(_nr, _comp) -#else -#define __SC_COMP(_nr, _sys, _comp) __SYSCALL(_nr, _sys) -#define __SC_COMP_3264(_nr, _32, _64, _comp) __SC_3264(_nr, _32, _64) -#endif - -#define __NR_io_setup 0 -__SC_COMP(__NR_io_setup, sys_io_setup, compat_sys_io_setup) -#define __NR_io_destroy 1 -__SYSCALL(__NR_io_destroy, sys_io_destroy) -#define __NR_io_submit 2 -__SC_COMP(__NR_io_submit, sys_io_submit, compat_sys_io_submit) -#define __NR_io_cancel 3 -__SYSCALL(__NR_io_cancel, sys_io_cancel) -#define __NR_io_getevents 4 -__SC_COMP(__NR_io_getevents, sys_io_getevents, compat_sys_io_getevents) - -/* fs/xattr.c */ -#define __NR_setxattr 5 -__SYSCALL(__NR_setxattr, sys_setxattr) -#define __NR_lsetxattr 6 -__SYSCALL(__NR_lsetxattr, sys_lsetxattr) -#define __NR_fsetxattr 7 -__SYSCALL(__NR_fsetxattr, sys_fsetxattr) -#define __NR_getxattr 8 -__SYSCALL(__NR_getxattr, sys_getxattr) -#define __NR_lgetxattr 9 -__SYSCALL(__NR_lgetxattr, sys_lgetxattr) -#define __NR_fgetxattr 10 -__SYSCALL(__NR_fgetxattr, sys_fgetxattr) -#define __NR_listxattr 11 -__SYSCALL(__NR_listxattr, sys_listxattr) -#define __NR_llistxattr 12 -__SYSCALL(__NR_llistxattr, sys_llistxattr) -#define __NR_flistxattr 13 -__SYSCALL(__NR_flistxattr, sys_flistxattr) -#define __NR_removexattr 14 -__SYSCALL(__NR_removexattr, sys_removexattr) -#define __NR_lremovexattr 15 -__SYSCALL(__NR_lremovexattr, sys_lremovexattr) -#define __NR_fremovexattr 16 -__SYSCALL(__NR_fremovexattr, sys_fremovexattr) - -/* fs/dcache.c */ -#define __NR_getcwd 17 -__SYSCALL(__NR_getcwd, sys_getcwd) - -/* fs/cookies.c */ -#define __NR_lookup_dcookie 18 -__SC_COMP(__NR_lookup_dcookie, sys_lookup_dcookie, compat_sys_lookup_dcookie) - -/* fs/eventfd.c */ -#define __NR_eventfd2 19 -__SYSCALL(__NR_eventfd2, sys_eventfd2) - -/* fs/eventpoll.c */ -#define __NR_epoll_create1 20 -__SYSCALL(__NR_epoll_create1, sys_epoll_create1) -#define __NR_epoll_ctl 21 -__SYSCALL(__NR_epoll_ctl, sys_epoll_ctl) -#define __NR_epoll_pwait 22 -__SC_COMP(__NR_epoll_pwait, sys_epoll_pwait, compat_sys_epoll_pwait) - -/* fs/fcntl.c */ -#define __NR_dup 23 -__SYSCALL(__NR_dup, sys_dup) -#define __NR_dup3 24 -__SYSCALL(__NR_dup3, sys_dup3) -#define __NR3264_fcntl 25 -__SC_COMP_3264(__NR3264_fcntl, sys_fcntl64, sys_fcntl, compat_sys_fcntl64) - -/* fs/inotify_user.c */ -#define __NR_inotify_init1 26 -__SYSCALL(__NR_inotify_init1, sys_inotify_init1) -#define __NR_inotify_add_watch 27 -__SYSCALL(__NR_inotify_add_watch, sys_inotify_add_watch) -#define __NR_inotify_rm_watch 28 -__SYSCALL(__NR_inotify_rm_watch, sys_inotify_rm_watch) - -/* fs/ioctl.c */ -#define __NR_ioctl 29 -__SC_COMP(__NR_ioctl, sys_ioctl, compat_sys_ioctl) - -/* fs/ioprio.c */ -#define __NR_ioprio_set 30 -__SYSCALL(__NR_ioprio_set, sys_ioprio_set) -#define __NR_ioprio_get 31 -__SYSCALL(__NR_ioprio_get, sys_ioprio_get) - -/* fs/locks.c */ -#define __NR_flock 32 -__SYSCALL(__NR_flock, sys_flock) - -/* fs/namei.c */ -#define __NR_mknodat 33 -__SYSCALL(__NR_mknodat, sys_mknodat) -#define __NR_mkdirat 34 -__SYSCALL(__NR_mkdirat, sys_mkdirat) -#define __NR_unlinkat 35 -__SYSCALL(__NR_unlinkat, sys_unlinkat) -#define __NR_symlinkat 36 -__SYSCALL(__NR_symlinkat, sys_symlinkat) -#define __NR_linkat 37 -__SYSCALL(__NR_linkat, sys_linkat) -#ifdef __ARCH_WANT_RENAMEAT -/* renameat is superseded with flags by renameat2 */ -#define __NR_renameat 38 -__SYSCALL(__NR_renameat, sys_renameat) -#endif /* __ARCH_WANT_RENAMEAT */ - -/* fs/namespace.c */ -#define __NR_umount2 39 -__SYSCALL(__NR_umount2, sys_umount) -#define __NR_mount 40 -__SC_COMP(__NR_mount, sys_mount, compat_sys_mount) -#define __NR_pivot_root 41 -__SYSCALL(__NR_pivot_root, sys_pivot_root) - -/* fs/nfsctl.c */ -#define __NR_nfsservctl 42 -__SYSCALL(__NR_nfsservctl, sys_ni_syscall) - -/* fs/open.c */ -#define __NR3264_statfs 43 -__SC_COMP_3264(__NR3264_statfs, sys_statfs64, sys_statfs, \ - compat_sys_statfs64) -#define __NR3264_fstatfs 44 -__SC_COMP_3264(__NR3264_fstatfs, sys_fstatfs64, sys_fstatfs, \ - compat_sys_fstatfs64) -#define __NR3264_truncate 45 -__SC_COMP_3264(__NR3264_truncate, sys_truncate64, sys_truncate, \ - compat_sys_truncate64) -#define __NR3264_ftruncate 46 -__SC_COMP_3264(__NR3264_ftruncate, sys_ftruncate64, sys_ftruncate, \ - compat_sys_ftruncate64) - -#define __NR_fallocate 47 -__SC_COMP(__NR_fallocate, sys_fallocate, compat_sys_fallocate) -#define __NR_faccessat 48 -__SYSCALL(__NR_faccessat, sys_faccessat) -#define __NR_chdir 49 -__SYSCALL(__NR_chdir, sys_chdir) -#define __NR_fchdir 50 -__SYSCALL(__NR_fchdir, sys_fchdir) -#define __NR_chroot 51 -__SYSCALL(__NR_chroot, sys_chroot) -#define __NR_fchmod 52 -__SYSCALL(__NR_fchmod, sys_fchmod) -#define __NR_fchmodat 53 -__SYSCALL(__NR_fchmodat, sys_fchmodat) -#define __NR_fchownat 54 -__SYSCALL(__NR_fchownat, sys_fchownat) -#define __NR_fchown 55 -__SYSCALL(__NR_fchown, sys_fchown) -#define __NR_openat 56 -__SC_COMP(__NR_openat, sys_openat, compat_sys_openat) -#define __NR_close 57 -__SYSCALL(__NR_close, sys_close) -#define __NR_vhangup 58 -__SYSCALL(__NR_vhangup, sys_vhangup) - -/* fs/pipe.c */ -#define __NR_pipe2 59 -__SYSCALL(__NR_pipe2, sys_pipe2) - -/* fs/quota.c */ -#define __NR_quotactl 60 -__SYSCALL(__NR_quotactl, sys_quotactl) - -/* fs/readdir.c */ -#define __NR_getdents64 61 -#define __ARCH_WANT_COMPAT_SYS_GETDENTS64 -__SC_COMP(__NR_getdents64, sys_getdents64, compat_sys_getdents64) - -/* fs/read_write.c */ -#define __NR3264_lseek 62 -__SC_3264(__NR3264_lseek, sys_llseek, sys_lseek) -#define __NR_read 63 -__SYSCALL(__NR_read, sys_read) -#define __NR_write 64 -__SYSCALL(__NR_write, sys_write) -#define __NR_readv 65 -__SC_COMP(__NR_readv, sys_readv, compat_sys_readv) -#define __NR_writev 66 -__SC_COMP(__NR_writev, sys_writev, compat_sys_writev) -#define __NR_pread64 67 -__SC_COMP(__NR_pread64, sys_pread64, compat_sys_pread64) -#define __NR_pwrite64 68 -__SC_COMP(__NR_pwrite64, sys_pwrite64, compat_sys_pwrite64) -#define __NR_preadv 69 -__SC_COMP(__NR_preadv, sys_preadv, compat_sys_preadv) -#define __NR_pwritev 70 -__SC_COMP(__NR_pwritev, sys_pwritev, compat_sys_pwritev) - -/* fs/sendfile.c */ -#define __NR3264_sendfile 71 -__SYSCALL(__NR3264_sendfile, sys_sendfile64) - -/* fs/select.c */ -#define __NR_pselect6 72 -__SC_COMP(__NR_pselect6, sys_pselect6, compat_sys_pselect6) -#define __NR_ppoll 73 -__SC_COMP(__NR_ppoll, sys_ppoll, compat_sys_ppoll) - -/* fs/signalfd.c */ -#define __NR_signalfd4 74 -__SC_COMP(__NR_signalfd4, sys_signalfd4, compat_sys_signalfd4) - -/* fs/splice.c */ -#define __NR_vmsplice 75 -__SC_COMP(__NR_vmsplice, sys_vmsplice, compat_sys_vmsplice) -#define __NR_splice 76 -__SYSCALL(__NR_splice, sys_splice) -#define __NR_tee 77 -__SYSCALL(__NR_tee, sys_tee) - -/* fs/stat.c */ -#define __NR_readlinkat 78 -__SYSCALL(__NR_readlinkat, sys_readlinkat) -#define __NR3264_fstatat 79 -__SC_3264(__NR3264_fstatat, sys_fstatat64, sys_newfstatat) -#define __NR3264_fstat 80 -__SC_3264(__NR3264_fstat, sys_fstat64, sys_newfstat) - -/* fs/sync.c */ -#define __NR_sync 81 -__SYSCALL(__NR_sync, sys_sync) -#define __NR_fsync 82 -__SYSCALL(__NR_fsync, sys_fsync) -#define __NR_fdatasync 83 -__SYSCALL(__NR_fdatasync, sys_fdatasync) -#ifdef __ARCH_WANT_SYNC_FILE_RANGE2 -#define __NR_sync_file_range2 84 -__SC_COMP(__NR_sync_file_range2, sys_sync_file_range2, \ - compat_sys_sync_file_range2) -#else -#define __NR_sync_file_range 84 -__SC_COMP(__NR_sync_file_range, sys_sync_file_range, \ - compat_sys_sync_file_range) -#endif - -/* fs/timerfd.c */ -#define __NR_timerfd_create 85 -__SYSCALL(__NR_timerfd_create, sys_timerfd_create) -#define __NR_timerfd_settime 86 -__SC_COMP(__NR_timerfd_settime, sys_timerfd_settime, \ - compat_sys_timerfd_settime) -#define __NR_timerfd_gettime 87 -__SC_COMP(__NR_timerfd_gettime, sys_timerfd_gettime, \ - compat_sys_timerfd_gettime) - -/* fs/utimes.c */ -#define __NR_utimensat 88 -__SC_COMP(__NR_utimensat, sys_utimensat, compat_sys_utimensat) - -/* kernel/acct.c */ -#define __NR_acct 89 -__SYSCALL(__NR_acct, sys_acct) - -/* kernel/capability.c */ -#define __NR_capget 90 -__SYSCALL(__NR_capget, sys_capget) -#define __NR_capset 91 -__SYSCALL(__NR_capset, sys_capset) - -/* kernel/exec_domain.c */ -#define __NR_personality 92 -__SYSCALL(__NR_personality, sys_personality) - -/* kernel/exit.c */ -#define __NR_exit 93 -__SYSCALL(__NR_exit, sys_exit) -#define __NR_exit_group 94 -__SYSCALL(__NR_exit_group, sys_exit_group) -#define __NR_waitid 95 -__SC_COMP(__NR_waitid, sys_waitid, compat_sys_waitid) - -/* kernel/fork.c */ -#define __NR_set_tid_address 96 -__SYSCALL(__NR_set_tid_address, sys_set_tid_address) -#define __NR_unshare 97 -__SYSCALL(__NR_unshare, sys_unshare) - -/* kernel/futex.c */ -#define __NR_futex 98 -__SC_COMP(__NR_futex, sys_futex, compat_sys_futex) -#define __NR_set_robust_list 99 -__SC_COMP(__NR_set_robust_list, sys_set_robust_list, \ - compat_sys_set_robust_list) -#define __NR_get_robust_list 100 -__SC_COMP(__NR_get_robust_list, sys_get_robust_list, \ - compat_sys_get_robust_list) - -/* kernel/hrtimer.c */ -#define __NR_nanosleep 101 -__SC_COMP(__NR_nanosleep, sys_nanosleep, compat_sys_nanosleep) - -/* kernel/itimer.c */ -#define __NR_getitimer 102 -__SC_COMP(__NR_getitimer, sys_getitimer, compat_sys_getitimer) -#define __NR_setitimer 103 -__SC_COMP(__NR_setitimer, sys_setitimer, compat_sys_setitimer) - -/* kernel/kexec.c */ -#define __NR_kexec_load 104 -__SC_COMP(__NR_kexec_load, sys_kexec_load, compat_sys_kexec_load) - -/* kernel/module.c */ -#define __NR_init_module 105 -__SYSCALL(__NR_init_module, sys_init_module) -#define __NR_delete_module 106 -__SYSCALL(__NR_delete_module, sys_delete_module) - -/* kernel/posix-timers.c */ -#define __NR_timer_create 107 -__SC_COMP(__NR_timer_create, sys_timer_create, compat_sys_timer_create) -#define __NR_timer_gettime 108 -__SC_COMP(__NR_timer_gettime, sys_timer_gettime, compat_sys_timer_gettime) -#define __NR_timer_getoverrun 109 -__SYSCALL(__NR_timer_getoverrun, sys_timer_getoverrun) -#define __NR_timer_settime 110 -__SC_COMP(__NR_timer_settime, sys_timer_settime, compat_sys_timer_settime) -#define __NR_timer_delete 111 -__SYSCALL(__NR_timer_delete, sys_timer_delete) -#define __NR_clock_settime 112 -__SC_COMP(__NR_clock_settime, sys_clock_settime, compat_sys_clock_settime) -#define __NR_clock_gettime 113 -__SC_COMP(__NR_clock_gettime, sys_clock_gettime, compat_sys_clock_gettime) -#define __NR_clock_getres 114 -__SC_COMP(__NR_clock_getres, sys_clock_getres, compat_sys_clock_getres) -#define __NR_clock_nanosleep 115 -__SC_COMP(__NR_clock_nanosleep, sys_clock_nanosleep, \ - compat_sys_clock_nanosleep) - -/* kernel/printk.c */ -#define __NR_syslog 116 -__SYSCALL(__NR_syslog, sys_syslog) - -/* kernel/ptrace.c */ -#define __NR_ptrace 117 -__SYSCALL(__NR_ptrace, sys_ptrace) - -/* kernel/sched/core.c */ -#define __NR_sched_setparam 118 -__SYSCALL(__NR_sched_setparam, sys_sched_setparam) -#define __NR_sched_setscheduler 119 -__SYSCALL(__NR_sched_setscheduler, sys_sched_setscheduler) -#define __NR_sched_getscheduler 120 -__SYSCALL(__NR_sched_getscheduler, sys_sched_getscheduler) -#define __NR_sched_getparam 121 -__SYSCALL(__NR_sched_getparam, sys_sched_getparam) -#define __NR_sched_setaffinity 122 -__SC_COMP(__NR_sched_setaffinity, sys_sched_setaffinity, \ - compat_sys_sched_setaffinity) -#define __NR_sched_getaffinity 123 -__SC_COMP(__NR_sched_getaffinity, sys_sched_getaffinity, \ - compat_sys_sched_getaffinity) -#define __NR_sched_yield 124 -__SYSCALL(__NR_sched_yield, sys_sched_yield) -#define __NR_sched_get_priority_max 125 -__SYSCALL(__NR_sched_get_priority_max, sys_sched_get_priority_max) -#define __NR_sched_get_priority_min 126 -__SYSCALL(__NR_sched_get_priority_min, sys_sched_get_priority_min) -#define __NR_sched_rr_get_interval 127 -__SC_COMP(__NR_sched_rr_get_interval, sys_sched_rr_get_interval, \ - compat_sys_sched_rr_get_interval) - -/* kernel/signal.c */ -#define __NR_restart_syscall 128 -__SYSCALL(__NR_restart_syscall, sys_restart_syscall) -#define __NR_kill 129 -__SYSCALL(__NR_kill, sys_kill) -#define __NR_tkill 130 -__SYSCALL(__NR_tkill, sys_tkill) -#define __NR_tgkill 131 -__SYSCALL(__NR_tgkill, sys_tgkill) -#define __NR_sigaltstack 132 -__SC_COMP(__NR_sigaltstack, sys_sigaltstack, compat_sys_sigaltstack) -#define __NR_rt_sigsuspend 133 -__SC_COMP(__NR_rt_sigsuspend, sys_rt_sigsuspend, compat_sys_rt_sigsuspend) -#define __NR_rt_sigaction 134 -__SC_COMP(__NR_rt_sigaction, sys_rt_sigaction, compat_sys_rt_sigaction) -#define __NR_rt_sigprocmask 135 -__SC_COMP(__NR_rt_sigprocmask, sys_rt_sigprocmask, compat_sys_rt_sigprocmask) -#define __NR_rt_sigpending 136 -__SC_COMP(__NR_rt_sigpending, sys_rt_sigpending, compat_sys_rt_sigpending) -#define __NR_rt_sigtimedwait 137 -__SC_COMP(__NR_rt_sigtimedwait, sys_rt_sigtimedwait, \ - compat_sys_rt_sigtimedwait) -#define __NR_rt_sigqueueinfo 138 -__SC_COMP(__NR_rt_sigqueueinfo, sys_rt_sigqueueinfo, \ - compat_sys_rt_sigqueueinfo) -#define __NR_rt_sigreturn 139 -__SC_COMP(__NR_rt_sigreturn, sys_rt_sigreturn, compat_sys_rt_sigreturn) - -/* kernel/sys.c */ -#define __NR_setpriority 140 -__SYSCALL(__NR_setpriority, sys_setpriority) -#define __NR_getpriority 141 -__SYSCALL(__NR_getpriority, sys_getpriority) -#define __NR_reboot 142 -__SYSCALL(__NR_reboot, sys_reboot) -#define __NR_setregid 143 -__SYSCALL(__NR_setregid, sys_setregid) -#define __NR_setgid 144 -__SYSCALL(__NR_setgid, sys_setgid) -#define __NR_setreuid 145 -__SYSCALL(__NR_setreuid, sys_setreuid) -#define __NR_setuid 146 -__SYSCALL(__NR_setuid, sys_setuid) -#define __NR_setresuid 147 -__SYSCALL(__NR_setresuid, sys_setresuid) -#define __NR_getresuid 148 -__SYSCALL(__NR_getresuid, sys_getresuid) -#define __NR_setresgid 149 -__SYSCALL(__NR_setresgid, sys_setresgid) -#define __NR_getresgid 150 -__SYSCALL(__NR_getresgid, sys_getresgid) -#define __NR_setfsuid 151 -__SYSCALL(__NR_setfsuid, sys_setfsuid) -#define __NR_setfsgid 152 -__SYSCALL(__NR_setfsgid, sys_setfsgid) -#define __NR_times 153 -__SC_COMP(__NR_times, sys_times, compat_sys_times) -#define __NR_setpgid 154 -__SYSCALL(__NR_setpgid, sys_setpgid) -#define __NR_getpgid 155 -__SYSCALL(__NR_getpgid, sys_getpgid) -#define __NR_getsid 156 -__SYSCALL(__NR_getsid, sys_getsid) -#define __NR_setsid 157 -__SYSCALL(__NR_setsid, sys_setsid) -#define __NR_getgroups 158 -__SYSCALL(__NR_getgroups, sys_getgroups) -#define __NR_setgroups 159 -__SYSCALL(__NR_setgroups, sys_setgroups) -#define __NR_uname 160 -__SYSCALL(__NR_uname, sys_newuname) -#define __NR_sethostname 161 -__SYSCALL(__NR_sethostname, sys_sethostname) -#define __NR_setdomainname 162 -__SYSCALL(__NR_setdomainname, sys_setdomainname) -#define __NR_getrlimit 163 -__SC_COMP(__NR_getrlimit, sys_getrlimit, compat_sys_getrlimit) -#define __NR_setrlimit 164 -__SC_COMP(__NR_setrlimit, sys_setrlimit, compat_sys_setrlimit) -#define __NR_getrusage 165 -__SC_COMP(__NR_getrusage, sys_getrusage, compat_sys_getrusage) -#define __NR_umask 166 -__SYSCALL(__NR_umask, sys_umask) -#define __NR_prctl 167 -__SYSCALL(__NR_prctl, sys_prctl) -#define __NR_getcpu 168 -__SYSCALL(__NR_getcpu, sys_getcpu) - -/* kernel/time.c */ -#define __NR_gettimeofday 169 -__SC_COMP(__NR_gettimeofday, sys_gettimeofday, compat_sys_gettimeofday) -#define __NR_settimeofday 170 -__SC_COMP(__NR_settimeofday, sys_settimeofday, compat_sys_settimeofday) -#define __NR_adjtimex 171 -__SC_COMP(__NR_adjtimex, sys_adjtimex, compat_sys_adjtimex) - -/* kernel/timer.c */ -#define __NR_getpid 172 -__SYSCALL(__NR_getpid, sys_getpid) -#define __NR_getppid 173 -__SYSCALL(__NR_getppid, sys_getppid) -#define __NR_getuid 174 -__SYSCALL(__NR_getuid, sys_getuid) -#define __NR_geteuid 175 -__SYSCALL(__NR_geteuid, sys_geteuid) -#define __NR_getgid 176 -__SYSCALL(__NR_getgid, sys_getgid) -#define __NR_getegid 177 -__SYSCALL(__NR_getegid, sys_getegid) -#define __NR_gettid 178 -__SYSCALL(__NR_gettid, sys_gettid) -#define __NR_sysinfo 179 -__SC_COMP(__NR_sysinfo, sys_sysinfo, compat_sys_sysinfo) - -/* ipc/mqueue.c */ -#define __NR_mq_open 180 -__SC_COMP(__NR_mq_open, sys_mq_open, compat_sys_mq_open) -#define __NR_mq_unlink 181 -__SYSCALL(__NR_mq_unlink, sys_mq_unlink) -#define __NR_mq_timedsend 182 -__SC_COMP(__NR_mq_timedsend, sys_mq_timedsend, compat_sys_mq_timedsend) -#define __NR_mq_timedreceive 183 -__SC_COMP(__NR_mq_timedreceive, sys_mq_timedreceive, \ - compat_sys_mq_timedreceive) -#define __NR_mq_notify 184 -__SC_COMP(__NR_mq_notify, sys_mq_notify, compat_sys_mq_notify) -#define __NR_mq_getsetattr 185 -__SC_COMP(__NR_mq_getsetattr, sys_mq_getsetattr, compat_sys_mq_getsetattr) - -/* ipc/msg.c */ -#define __NR_msgget 186 -__SYSCALL(__NR_msgget, sys_msgget) -#define __NR_msgctl 187 -__SC_COMP(__NR_msgctl, sys_msgctl, compat_sys_msgctl) -#define __NR_msgrcv 188 -__SC_COMP(__NR_msgrcv, sys_msgrcv, compat_sys_msgrcv) -#define __NR_msgsnd 189 -__SC_COMP(__NR_msgsnd, sys_msgsnd, compat_sys_msgsnd) - -/* ipc/sem.c */ -#define __NR_semget 190 -__SYSCALL(__NR_semget, sys_semget) -#define __NR_semctl 191 -__SC_COMP(__NR_semctl, sys_semctl, compat_sys_semctl) -#define __NR_semtimedop 192 -__SC_COMP(__NR_semtimedop, sys_semtimedop, compat_sys_semtimedop) -#define __NR_semop 193 -__SYSCALL(__NR_semop, sys_semop) - -/* ipc/shm.c */ -#define __NR_shmget 194 -__SYSCALL(__NR_shmget, sys_shmget) -#define __NR_shmctl 195 -__SC_COMP(__NR_shmctl, sys_shmctl, compat_sys_shmctl) -#define __NR_shmat 196 -__SC_COMP(__NR_shmat, sys_shmat, compat_sys_shmat) -#define __NR_shmdt 197 -__SYSCALL(__NR_shmdt, sys_shmdt) - -/* net/socket.c */ -#define __NR_socket 198 -__SYSCALL(__NR_socket, sys_socket) -#define __NR_socketpair 199 -__SYSCALL(__NR_socketpair, sys_socketpair) -#define __NR_bind 200 -__SYSCALL(__NR_bind, sys_bind) -#define __NR_listen 201 -__SYSCALL(__NR_listen, sys_listen) -#define __NR_accept 202 -__SYSCALL(__NR_accept, sys_accept) -#define __NR_connect 203 -__SYSCALL(__NR_connect, sys_connect) -#define __NR_getsockname 204 -__SYSCALL(__NR_getsockname, sys_getsockname) -#define __NR_getpeername 205 -__SYSCALL(__NR_getpeername, sys_getpeername) -#define __NR_sendto 206 -__SYSCALL(__NR_sendto, sys_sendto) -#define __NR_recvfrom 207 -__SC_COMP(__NR_recvfrom, sys_recvfrom, compat_sys_recvfrom) -#define __NR_setsockopt 208 -__SC_COMP(__NR_setsockopt, sys_setsockopt, compat_sys_setsockopt) -#define __NR_getsockopt 209 -__SC_COMP(__NR_getsockopt, sys_getsockopt, compat_sys_getsockopt) -#define __NR_shutdown 210 -__SYSCALL(__NR_shutdown, sys_shutdown) -#define __NR_sendmsg 211 -__SC_COMP(__NR_sendmsg, sys_sendmsg, compat_sys_sendmsg) -#define __NR_recvmsg 212 -__SC_COMP(__NR_recvmsg, sys_recvmsg, compat_sys_recvmsg) - -/* mm/filemap.c */ -#define __NR_readahead 213 -__SC_COMP(__NR_readahead, sys_readahead, compat_sys_readahead) - -/* mm/nommu.c, also with MMU */ -#define __NR_brk 214 -__SYSCALL(__NR_brk, sys_brk) -#define __NR_munmap 215 -__SYSCALL(__NR_munmap, sys_munmap) -#define __NR_mremap 216 -__SYSCALL(__NR_mremap, sys_mremap) - -/* security/keys/keyctl.c */ -#define __NR_add_key 217 -__SYSCALL(__NR_add_key, sys_add_key) -#define __NR_request_key 218 -__SYSCALL(__NR_request_key, sys_request_key) -#define __NR_keyctl 219 -__SC_COMP(__NR_keyctl, sys_keyctl, compat_sys_keyctl) - -/* arch/example/kernel/sys_example.c */ -#define __NR_clone 220 -__SYSCALL(__NR_clone, sys_clone) -#define __NR_execve 221 -__SC_COMP(__NR_execve, sys_execve, compat_sys_execve) - -#define __NR3264_mmap 222 -__SC_3264(__NR3264_mmap, sys_mmap2, sys_mmap) -/* mm/fadvise.c */ -#define __NR3264_fadvise64 223 -__SC_COMP(__NR3264_fadvise64, sys_fadvise64_64, compat_sys_fadvise64_64) - -/* mm/, CONFIG_MMU only */ -#ifndef __ARCH_NOMMU -#define __NR_swapon 224 -__SYSCALL(__NR_swapon, sys_swapon) -#define __NR_swapoff 225 -__SYSCALL(__NR_swapoff, sys_swapoff) -#define __NR_mprotect 226 -__SYSCALL(__NR_mprotect, sys_mprotect) -#define __NR_msync 227 -__SYSCALL(__NR_msync, sys_msync) -#define __NR_mlock 228 -__SYSCALL(__NR_mlock, sys_mlock) -#define __NR_munlock 229 -__SYSCALL(__NR_munlock, sys_munlock) -#define __NR_mlockall 230 -__SYSCALL(__NR_mlockall, sys_mlockall) -#define __NR_munlockall 231 -__SYSCALL(__NR_munlockall, sys_munlockall) -#define __NR_mincore 232 -__SYSCALL(__NR_mincore, sys_mincore) -#define __NR_madvise 233 -__SYSCALL(__NR_madvise, sys_madvise) -#define __NR_remap_file_pages 234 -__SYSCALL(__NR_remap_file_pages, sys_remap_file_pages) -#define __NR_mbind 235 -__SC_COMP(__NR_mbind, sys_mbind, compat_sys_mbind) -#define __NR_get_mempolicy 236 -__SC_COMP(__NR_get_mempolicy, sys_get_mempolicy, compat_sys_get_mempolicy) -#define __NR_set_mempolicy 237 -__SC_COMP(__NR_set_mempolicy, sys_set_mempolicy, compat_sys_set_mempolicy) -#define __NR_migrate_pages 238 -__SC_COMP(__NR_migrate_pages, sys_migrate_pages, compat_sys_migrate_pages) -#define __NR_move_pages 239 -__SC_COMP(__NR_move_pages, sys_move_pages, compat_sys_move_pages) -#endif - -#define __NR_rt_tgsigqueueinfo 240 -__SC_COMP(__NR_rt_tgsigqueueinfo, sys_rt_tgsigqueueinfo, \ - compat_sys_rt_tgsigqueueinfo) -#define __NR_perf_event_open 241 -__SYSCALL(__NR_perf_event_open, sys_perf_event_open) -#define __NR_accept4 242 -__SYSCALL(__NR_accept4, sys_accept4) -#define __NR_recvmmsg 243 -__SC_COMP(__NR_recvmmsg, sys_recvmmsg, compat_sys_recvmmsg) - -/* - * Architectures may provide up to 16 syscalls of their own - * starting with this value. - */ -#define __NR_arch_specific_syscall 244 - -#define __NR_wait4 260 -__SC_COMP(__NR_wait4, sys_wait4, compat_sys_wait4) -#define __NR_prlimit64 261 -__SYSCALL(__NR_prlimit64, sys_prlimit64) -#define __NR_fanotify_init 262 -__SYSCALL(__NR_fanotify_init, sys_fanotify_init) -#define __NR_fanotify_mark 263 -__SYSCALL(__NR_fanotify_mark, sys_fanotify_mark) -#define __NR_name_to_handle_at 264 -__SYSCALL(__NR_name_to_handle_at, sys_name_to_handle_at) -#define __NR_open_by_handle_at 265 -__SC_COMP(__NR_open_by_handle_at, sys_open_by_handle_at, \ - compat_sys_open_by_handle_at) -#define __NR_clock_adjtime 266 -__SC_COMP(__NR_clock_adjtime, sys_clock_adjtime, compat_sys_clock_adjtime) -#define __NR_syncfs 267 -__SYSCALL(__NR_syncfs, sys_syncfs) -#define __NR_setns 268 -__SYSCALL(__NR_setns, sys_setns) -#define __NR_sendmmsg 269 -__SC_COMP(__NR_sendmmsg, sys_sendmmsg, compat_sys_sendmmsg) -#define __NR_process_vm_readv 270 -__SC_COMP(__NR_process_vm_readv, sys_process_vm_readv, \ - compat_sys_process_vm_readv) -#define __NR_process_vm_writev 271 -__SC_COMP(__NR_process_vm_writev, sys_process_vm_writev, \ - compat_sys_process_vm_writev) -#define __NR_kcmp 272 -__SYSCALL(__NR_kcmp, sys_kcmp) -#define __NR_finit_module 273 -__SYSCALL(__NR_finit_module, sys_finit_module) -#define __NR_sched_setattr 274 -__SYSCALL(__NR_sched_setattr, sys_sched_setattr) -#define __NR_sched_getattr 275 -__SYSCALL(__NR_sched_getattr, sys_sched_getattr) -#define __NR_renameat2 276 -__SYSCALL(__NR_renameat2, sys_renameat2) -#define __NR_seccomp 277 -__SYSCALL(__NR_seccomp, sys_seccomp) -#define __NR_getrandom 278 -__SYSCALL(__NR_getrandom, sys_getrandom) -#define __NR_memfd_create 279 -__SYSCALL(__NR_memfd_create, sys_memfd_create) -#define __NR_bpf 280 -__SYSCALL(__NR_bpf, sys_bpf) -#define __NR_execveat 281 -__SC_COMP(__NR_execveat, sys_execveat, compat_sys_execveat) -#define __NR_userfaultfd 282 -__SYSCALL(__NR_userfaultfd, sys_userfaultfd) -#define __NR_membarrier 283 -__SYSCALL(__NR_membarrier, sys_membarrier) -#define __NR_mlock2 284 -__SYSCALL(__NR_mlock2, sys_mlock2) -#define __NR_copy_file_range 285 -__SYSCALL(__NR_copy_file_range, sys_copy_file_range) -#define __NR_preadv2 286 -__SC_COMP(__NR_preadv2, sys_preadv2, compat_sys_preadv2) -#define __NR_pwritev2 287 -__SC_COMP(__NR_pwritev2, sys_pwritev2, compat_sys_pwritev2) -#define __NR_pkey_mprotect 288 -__SYSCALL(__NR_pkey_mprotect, sys_pkey_mprotect) -#define __NR_pkey_alloc 289 -__SYSCALL(__NR_pkey_alloc, sys_pkey_alloc) -#define __NR_pkey_free 290 -__SYSCALL(__NR_pkey_free, sys_pkey_free) - -#undef __NR_syscalls -#define __NR_syscalls 291 - -/* - * All syscalls below here should go away really, - * these are provided for both review and as a porting - * help for the C library version. - * - * Last chance: are any of these important enough to - * enable by default? - */ -#ifdef __ARCH_WANT_SYSCALL_NO_AT -#define __NR_open 1024 -__SYSCALL(__NR_open, sys_open) -#define __NR_link 1025 -__SYSCALL(__NR_link, sys_link) -#define __NR_unlink 1026 -__SYSCALL(__NR_unlink, sys_unlink) -#define __NR_mknod 1027 -__SYSCALL(__NR_mknod, sys_mknod) -#define __NR_chmod 1028 -__SYSCALL(__NR_chmod, sys_chmod) -#define __NR_chown 1029 -__SYSCALL(__NR_chown, sys_chown) -#define __NR_mkdir 1030 -__SYSCALL(__NR_mkdir, sys_mkdir) -#define __NR_rmdir 1031 -__SYSCALL(__NR_rmdir, sys_rmdir) -#define __NR_lchown 1032 -__SYSCALL(__NR_lchown, sys_lchown) -#define __NR_access 1033 -__SYSCALL(__NR_access, sys_access) -#define __NR_rename 1034 -__SYSCALL(__NR_rename, sys_rename) -#define __NR_readlink 1035 -__SYSCALL(__NR_readlink, sys_readlink) -#define __NR_symlink 1036 -__SYSCALL(__NR_symlink, sys_symlink) -#define __NR_utimes 1037 -__SYSCALL(__NR_utimes, sys_utimes) -#define __NR3264_stat 1038 -__SC_3264(__NR3264_stat, sys_stat64, sys_newstat) -#define __NR3264_lstat 1039 -__SC_3264(__NR3264_lstat, sys_lstat64, sys_newlstat) - -#undef __NR_syscalls -#define __NR_syscalls (__NR3264_lstat+1) -#endif /* __ARCH_WANT_SYSCALL_NO_AT */ - -#ifdef __ARCH_WANT_SYSCALL_NO_FLAGS -#define __NR_pipe 1040 -__SYSCALL(__NR_pipe, sys_pipe) -#define __NR_dup2 1041 -__SYSCALL(__NR_dup2, sys_dup2) -#define __NR_epoll_create 1042 -__SYSCALL(__NR_epoll_create, sys_epoll_create) -#define __NR_inotify_init 1043 -__SYSCALL(__NR_inotify_init, sys_inotify_init) -#define __NR_eventfd 1044 -__SYSCALL(__NR_eventfd, sys_eventfd) -#define __NR_signalfd 1045 -__SYSCALL(__NR_signalfd, sys_signalfd) - -#undef __NR_syscalls -#define __NR_syscalls (__NR_signalfd+1) -#endif /* __ARCH_WANT_SYSCALL_NO_FLAGS */ - -#if (__BITS_PER_LONG == 32 || defined(__SYSCALL_COMPAT)) && \ - defined(__ARCH_WANT_SYSCALL_OFF_T) -#define __NR_sendfile 1046 -__SYSCALL(__NR_sendfile, sys_sendfile) -#define __NR_ftruncate 1047 -__SYSCALL(__NR_ftruncate, sys_ftruncate) -#define __NR_truncate 1048 -__SYSCALL(__NR_truncate, sys_truncate) -#define __NR_stat 1049 -__SYSCALL(__NR_stat, sys_newstat) -#define __NR_lstat 1050 -__SYSCALL(__NR_lstat, sys_newlstat) -#define __NR_fstat 1051 -__SYSCALL(__NR_fstat, sys_newfstat) -#define __NR_fcntl 1052 -__SYSCALL(__NR_fcntl, sys_fcntl) -#define __NR_fadvise64 1053 -#define __ARCH_WANT_SYS_FADVISE64 -__SYSCALL(__NR_fadvise64, sys_fadvise64) -#define __NR_newfstatat 1054 -#define __ARCH_WANT_SYS_NEWFSTATAT -__SYSCALL(__NR_newfstatat, sys_newfstatat) -#define __NR_fstatfs 1055 -__SYSCALL(__NR_fstatfs, sys_fstatfs) -#define __NR_statfs 1056 -__SYSCALL(__NR_statfs, sys_statfs) -#define __NR_lseek 1057 -__SYSCALL(__NR_lseek, sys_lseek) -#define __NR_mmap 1058 -__SYSCALL(__NR_mmap, sys_mmap) - -#undef __NR_syscalls -#define __NR_syscalls (__NR_mmap+1) -#endif /* 32 bit off_t syscalls */ - -#ifdef __ARCH_WANT_SYSCALL_DEPRECATED -#define __NR_alarm 1059 -#define __ARCH_WANT_SYS_ALARM -__SYSCALL(__NR_alarm, sys_alarm) -#define __NR_getpgrp 1060 -#define __ARCH_WANT_SYS_GETPGRP -__SYSCALL(__NR_getpgrp, sys_getpgrp) -#define __NR_pause 1061 -#define __ARCH_WANT_SYS_PAUSE -__SYSCALL(__NR_pause, sys_pause) -#define __NR_time 1062 -#define __ARCH_WANT_SYS_TIME -#define __ARCH_WANT_COMPAT_SYS_TIME -__SYSCALL(__NR_time, sys_time) -#define __NR_utime 1063 -#define __ARCH_WANT_SYS_UTIME -__SYSCALL(__NR_utime, sys_utime) - -#define __NR_creat 1064 -__SYSCALL(__NR_creat, sys_creat) -#define __NR_getdents 1065 -#define __ARCH_WANT_SYS_GETDENTS -__SYSCALL(__NR_getdents, sys_getdents) -#define __NR_futimesat 1066 -__SYSCALL(__NR_futimesat, sys_futimesat) -#define __NR_select 1067 -#define __ARCH_WANT_SYS_SELECT -__SYSCALL(__NR_select, sys_select) -#define __NR_poll 1068 -__SYSCALL(__NR_poll, sys_poll) -#define __NR_epoll_wait 1069 -__SYSCALL(__NR_epoll_wait, sys_epoll_wait) -#define __NR_ustat 1070 -__SYSCALL(__NR_ustat, sys_ustat) -#define __NR_vfork 1071 -__SYSCALL(__NR_vfork, sys_vfork) -#define __NR_oldwait4 1072 -__SYSCALL(__NR_oldwait4, sys_wait4) -#define __NR_recv 1073 -__SYSCALL(__NR_recv, sys_recv) -#define __NR_send 1074 -__SYSCALL(__NR_send, sys_send) -#define __NR_bdflush 1075 -__SYSCALL(__NR_bdflush, sys_bdflush) -#define __NR_umount 1076 -__SYSCALL(__NR_umount, sys_oldumount) -#define __ARCH_WANT_SYS_OLDUMOUNT -#define __NR_uselib 1077 -__SYSCALL(__NR_uselib, sys_uselib) -#define __NR__sysctl 1078 -__SYSCALL(__NR__sysctl, sys_sysctl) - -#define __NR_fork 1079 -#ifdef CONFIG_MMU -__SYSCALL(__NR_fork, sys_fork) -#else -__SYSCALL(__NR_fork, sys_ni_syscall) -#endif /* CONFIG_MMU */ - -#undef __NR_syscalls -#define __NR_syscalls (__NR_fork+1) - -#endif /* __ARCH_WANT_SYSCALL_DEPRECATED */ - -/* - * 32 bit systems traditionally used different - * syscalls for off_t and loff_t arguments, while - * 64 bit systems only need the off_t version. - * For new 32 bit platforms, there is no need to - * implement the old 32 bit off_t syscalls, so - * they take different names. - * Here we map the numbers so that both versions - * use the same syscall table layout. - */ -#if __BITS_PER_LONG == 64 && !defined(__SYSCALL_COMPAT) -#define __NR_fcntl __NR3264_fcntl -#define __NR_statfs __NR3264_statfs -#define __NR_fstatfs __NR3264_fstatfs -#define __NR_truncate __NR3264_truncate -#define __NR_ftruncate __NR3264_ftruncate -#define __NR_lseek __NR3264_lseek -#define __NR_sendfile __NR3264_sendfile -#define __NR_newfstatat __NR3264_fstatat -#define __NR_fstat __NR3264_fstat -#define __NR_mmap __NR3264_mmap -#define __NR_fadvise64 __NR3264_fadvise64 -#ifdef __NR3264_stat -#define __NR_stat __NR3264_stat -#define __NR_lstat __NR3264_lstat -#endif -#else -#define __NR_fcntl64 __NR3264_fcntl -#define __NR_statfs64 __NR3264_statfs -#define __NR_fstatfs64 __NR3264_fstatfs -#define __NR_truncate64 __NR3264_truncate -#define __NR_ftruncate64 __NR3264_ftruncate -#define __NR_llseek __NR3264_lseek -#define __NR_sendfile64 __NR3264_sendfile -#define __NR_fstatat64 __NR3264_fstatat -#define __NR_fstat64 __NR3264_fstat -#define __NR_mmap2 __NR3264_mmap -#define __NR_fadvise64_64 __NR3264_fadvise64 -#ifdef __NR3264_stat -#define __NR_stat64 __NR3264_stat -#define __NR_lstat64 __NR3264_lstat -#endif -#endif diff --git a/src/linux/include/uapi/linux/acct.h b/src/linux/include/uapi/linux/acct.h deleted file mode 100644 index df2f9a0..0000000 --- a/src/linux/include/uapi/linux/acct.h +++ /dev/null @@ -1,124 +0,0 @@ -/* - * BSD Process Accounting for Linux - Definitions - * - * Author: Marco van Wieringen (mvw@planets.elm.net) - * - * This header file contains the definitions needed to implement - * BSD-style process accounting. The kernel accounting code and all - * user-level programs that try to do something useful with the - * process accounting log must include this file. - * - * Copyright (C) 1995 - 1997 Marco van Wieringen - ELM Consultancy B.V. - * - */ - -#ifndef _UAPI_LINUX_ACCT_H -#define _UAPI_LINUX_ACCT_H - -#include - -#include -#include - -/* - * comp_t is a 16-bit "floating" point number with a 3-bit base 8 - * exponent and a 13-bit fraction. - * comp2_t is 24-bit with 5-bit base 2 exponent and 20 bit fraction - * (leading 1 not stored). - * See linux/kernel/acct.c for the specific encoding systems used. - */ - -typedef __u16 comp_t; -typedef __u32 comp2_t; - -/* - * accounting file record - * - * This structure contains all of the information written out to the - * process accounting file whenever a process exits. - */ - -#define ACCT_COMM 16 - -struct acct -{ - char ac_flag; /* Flags */ - char ac_version; /* Always set to ACCT_VERSION */ - /* for binary compatibility back until 2.0 */ - __u16 ac_uid16; /* LSB of Real User ID */ - __u16 ac_gid16; /* LSB of Real Group ID */ - __u16 ac_tty; /* Control Terminal */ - __u32 ac_btime; /* Process Creation Time */ - comp_t ac_utime; /* User Time */ - comp_t ac_stime; /* System Time */ - comp_t ac_etime; /* Elapsed Time */ - comp_t ac_mem; /* Average Memory Usage */ - comp_t ac_io; /* Chars Transferred */ - comp_t ac_rw; /* Blocks Read or Written */ - comp_t ac_minflt; /* Minor Pagefaults */ - comp_t ac_majflt; /* Major Pagefaults */ - comp_t ac_swaps; /* Number of Swaps */ -/* m68k had no padding here. */ -#if !defined(CONFIG_M68K) || !defined(__KERNEL__) - __u16 ac_ahz; /* AHZ */ -#endif - __u32 ac_exitcode; /* Exitcode */ - char ac_comm[ACCT_COMM + 1]; /* Command Name */ - __u8 ac_etime_hi; /* Elapsed Time MSB */ - __u16 ac_etime_lo; /* Elapsed Time LSB */ - __u32 ac_uid; /* Real User ID */ - __u32 ac_gid; /* Real Group ID */ -}; - -struct acct_v3 -{ - char ac_flag; /* Flags */ - char ac_version; /* Always set to ACCT_VERSION */ - __u16 ac_tty; /* Control Terminal */ - __u32 ac_exitcode; /* Exitcode */ - __u32 ac_uid; /* Real User ID */ - __u32 ac_gid; /* Real Group ID */ - __u32 ac_pid; /* Process ID */ - __u32 ac_ppid; /* Parent Process ID */ - __u32 ac_btime; /* Process Creation Time */ -#ifdef __KERNEL__ - __u32 ac_etime; /* Elapsed Time */ -#else - float ac_etime; /* Elapsed Time */ -#endif - comp_t ac_utime; /* User Time */ - comp_t ac_stime; /* System Time */ - comp_t ac_mem; /* Average Memory Usage */ - comp_t ac_io; /* Chars Transferred */ - comp_t ac_rw; /* Blocks Read or Written */ - comp_t ac_minflt; /* Minor Pagefaults */ - comp_t ac_majflt; /* Major Pagefaults */ - comp_t ac_swaps; /* Number of Swaps */ - char ac_comm[ACCT_COMM]; /* Command Name */ -}; - -/* - * accounting flags - */ - /* bit set when the process ... */ -#define AFORK 0x01 /* ... executed fork, but did not exec */ -#define ASU 0x02 /* ... used super-user privileges */ -#define ACOMPAT 0x04 /* ... used compatibility mode (VAX only not used) */ -#define ACORE 0x08 /* ... dumped core */ -#define AXSIG 0x10 /* ... was killed by a signal */ - -#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __BIG_ENDIAN : defined(__BIG_ENDIAN) -#define ACCT_BYTEORDER 0x80 /* accounting file is big endian */ -#elif defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : defined(__LITTLE_ENDIAN) -#define ACCT_BYTEORDER 0x00 /* accounting file is little endian */ -#else -#error unspecified endianness -#endif - -#ifndef __KERNEL__ -#define ACCT_VERSION 2 -#define AHZ (HZ) -#endif /* __KERNEL */ - - -#endif /* _UAPI_LINUX_ACCT_H */ diff --git a/src/linux/include/uapi/linux/aio_abi.h b/src/linux/include/uapi/linux/aio_abi.h deleted file mode 100644 index bb2554f..0000000 --- a/src/linux/include/uapi/linux/aio_abi.h +++ /dev/null @@ -1,111 +0,0 @@ -/* include/linux/aio_abi.h - * - * Copyright 2000,2001,2002 Red Hat. - * - * Written by Benjamin LaHaise - * - * Distribute under the terms of the GPLv2 (see ../../COPYING) or under - * the following terms. - * - * Permission to use, copy, modify, and distribute this software and its - * documentation is hereby granted, provided that the above copyright - * notice appears in all copies. This software is provided without any - * warranty, express or implied. Red Hat makes no representations about - * the suitability of this software for any purpose. - * - * IN NO EVENT SHALL RED HAT BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, - * SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF - * THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF RED HAT HAS BEEN ADVISED - * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * RED HAT DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND - * RED HAT HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, - * ENHANCEMENTS, OR MODIFICATIONS. - */ -#ifndef __LINUX__AIO_ABI_H -#define __LINUX__AIO_ABI_H - -#include -#include - -typedef __kernel_ulong_t aio_context_t; - -enum { - IOCB_CMD_PREAD = 0, - IOCB_CMD_PWRITE = 1, - IOCB_CMD_FSYNC = 2, - IOCB_CMD_FDSYNC = 3, - /* These two are experimental. - * IOCB_CMD_PREADX = 4, - * IOCB_CMD_POLL = 5, - */ - IOCB_CMD_NOOP = 6, - IOCB_CMD_PREADV = 7, - IOCB_CMD_PWRITEV = 8, -}; - -/* - * Valid flags for the "aio_flags" member of the "struct iocb". - * - * IOCB_FLAG_RESFD - Set if the "aio_resfd" member of the "struct iocb" - * is valid. - */ -#define IOCB_FLAG_RESFD (1 << 0) - -/* read() from /dev/aio returns these structures. */ -struct io_event { - __u64 data; /* the data field from the iocb */ - __u64 obj; /* what iocb this event came from */ - __s64 res; /* result code for this event */ - __s64 res2; /* secondary result */ -}; - -#if defined(__BYTE_ORDER) ? __BYTE_ORDER == __LITTLE_ENDIAN : defined(__LITTLE_ENDIAN) -#define PADDED(x,y) x, y -#elif defined(__BYTE_ORDER) ? __BYTE_ORDER == __BIG_ENDIAN : defined(__BIG_ENDIAN) -#define PADDED(x,y) y, x -#else -#error edit for your odd byteorder. -#endif - -/* - * we always use a 64bit off_t when communicating - * with userland. its up to libraries to do the - * proper padding and aio_error abstraction - */ - -struct iocb { - /* these are internal to the kernel/libc. */ - __u64 aio_data; /* data to be returned in event's data */ - __u32 PADDED(aio_key, aio_reserved1); - /* the kernel sets aio_key to the req # */ - - /* common fields */ - __u16 aio_lio_opcode; /* see IOCB_CMD_ above */ - __s16 aio_reqprio; - __u32 aio_fildes; - - __u64 aio_buf; - __u64 aio_nbytes; - __s64 aio_offset; - - /* extra parameters */ - __u64 aio_reserved2; /* TODO: use this for a (struct sigevent *) */ - - /* flags for the "struct iocb" */ - __u32 aio_flags; - - /* - * if the IOCB_FLAG_RESFD flag of "aio_flags" is set, this is an - * eventfd to signal AIO readiness to - */ - __u32 aio_resfd; -}; /* 64 bytes */ - -#undef IFBIG -#undef IFLITTLE - -#endif /* __LINUX__AIO_ABI_H */ - diff --git a/src/linux/include/uapi/linux/atalk.h b/src/linux/include/uapi/linux/atalk.h deleted file mode 100644 index 4bcd596..0000000 --- a/src/linux/include/uapi/linux/atalk.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef _UAPI__LINUX_ATALK_H__ -#define _UAPI__LINUX_ATALK_H__ - -#include -#include -#include - -/* - * AppleTalk networking structures - * - * The following are directly referenced from the University Of Michigan - * netatalk for compatibility reasons. - */ -#define ATPORT_FIRST 1 -#define ATPORT_RESERVED 128 -#define ATPORT_LAST 254 /* 254 is only legal on localtalk */ -#define ATADDR_ANYNET (__u16)0 -#define ATADDR_ANYNODE (__u8)0 -#define ATADDR_ANYPORT (__u8)0 -#define ATADDR_BCAST (__u8)255 -#define DDP_MAXSZ 587 -#define DDP_MAXHOPS 15 /* 4 bits of hop counter */ - -#define SIOCATALKDIFADDR (SIOCPROTOPRIVATE + 0) - -struct atalk_addr { - __be16 s_net; - __u8 s_node; -}; - -struct sockaddr_at { - __kernel_sa_family_t sat_family; - __u8 sat_port; - struct atalk_addr sat_addr; - char sat_zero[8]; -}; - -struct atalk_netrange { - __u8 nr_phase; - __be16 nr_firstnet; - __be16 nr_lastnet; -}; - -#endif /* _UAPI__LINUX_ATALK_H__ */ diff --git a/src/linux/include/uapi/linux/audit.h b/src/linux/include/uapi/linux/audit.h deleted file mode 100644 index 208df7b..0000000 --- a/src/linux/include/uapi/linux/audit.h +++ /dev/null @@ -1,471 +0,0 @@ -/* audit.h -- Auditing support - * - * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Written by Rickard E. (Rik) Faith - * - */ - -#ifndef _UAPI_LINUX_AUDIT_H_ -#define _UAPI_LINUX_AUDIT_H_ - -#include -#include - -/* The netlink messages for the audit system is divided into blocks: - * 1000 - 1099 are for commanding the audit system - * 1100 - 1199 user space trusted application messages - * 1200 - 1299 messages internal to the audit daemon - * 1300 - 1399 audit event messages - * 1400 - 1499 SE Linux use - * 1500 - 1599 kernel LSPP events - * 1600 - 1699 kernel crypto events - * 1700 - 1799 kernel anomaly records - * 1800 - 1899 kernel integrity events - * 1900 - 1999 future kernel use - * 2000 is for otherwise unclassified kernel audit messages (legacy) - * 2001 - 2099 unused (kernel) - * 2100 - 2199 user space anomaly records - * 2200 - 2299 user space actions taken in response to anomalies - * 2300 - 2399 user space generated LSPP events - * 2400 - 2499 user space crypto events - * 2500 - 2999 future user space (maybe integrity labels and related events) - * - * Messages from 1000-1199 are bi-directional. 1200-1299 & 2100 - 2999 are - * exclusively user space. 1300-2099 is kernel --> user space - * communication. - */ -#define AUDIT_GET 1000 /* Get status */ -#define AUDIT_SET 1001 /* Set status (enable/disable/auditd) */ -#define AUDIT_LIST 1002 /* List syscall rules -- deprecated */ -#define AUDIT_ADD 1003 /* Add syscall rule -- deprecated */ -#define AUDIT_DEL 1004 /* Delete syscall rule -- deprecated */ -#define AUDIT_USER 1005 /* Message from userspace -- deprecated */ -#define AUDIT_LOGIN 1006 /* Define the login id and information */ -#define AUDIT_WATCH_INS 1007 /* Insert file/dir watch entry */ -#define AUDIT_WATCH_REM 1008 /* Remove file/dir watch entry */ -#define AUDIT_WATCH_LIST 1009 /* List all file/dir watches */ -#define AUDIT_SIGNAL_INFO 1010 /* Get info about sender of signal to auditd */ -#define AUDIT_ADD_RULE 1011 /* Add syscall filtering rule */ -#define AUDIT_DEL_RULE 1012 /* Delete syscall filtering rule */ -#define AUDIT_LIST_RULES 1013 /* List syscall filtering rules */ -#define AUDIT_TRIM 1014 /* Trim junk from watched tree */ -#define AUDIT_MAKE_EQUIV 1015 /* Append to watched tree */ -#define AUDIT_TTY_GET 1016 /* Get TTY auditing status */ -#define AUDIT_TTY_SET 1017 /* Set TTY auditing status */ -#define AUDIT_SET_FEATURE 1018 /* Turn an audit feature on or off */ -#define AUDIT_GET_FEATURE 1019 /* Get which features are enabled */ - -#define AUDIT_FIRST_USER_MSG 1100 /* Userspace messages mostly uninteresting to kernel */ -#define AUDIT_USER_AVC 1107 /* We filter this differently */ -#define AUDIT_USER_TTY 1124 /* Non-ICANON TTY input meaning */ -#define AUDIT_LAST_USER_MSG 1199 -#define AUDIT_FIRST_USER_MSG2 2100 /* More user space messages */ -#define AUDIT_LAST_USER_MSG2 2999 - -#define AUDIT_DAEMON_START 1200 /* Daemon startup record */ -#define AUDIT_DAEMON_END 1201 /* Daemon normal stop record */ -#define AUDIT_DAEMON_ABORT 1202 /* Daemon error stop record */ -#define AUDIT_DAEMON_CONFIG 1203 /* Daemon config change */ - -#define AUDIT_SYSCALL 1300 /* Syscall event */ -/* #define AUDIT_FS_WATCH 1301 * Deprecated */ -#define AUDIT_PATH 1302 /* Filename path information */ -#define AUDIT_IPC 1303 /* IPC record */ -#define AUDIT_SOCKETCALL 1304 /* sys_socketcall arguments */ -#define AUDIT_CONFIG_CHANGE 1305 /* Audit system configuration change */ -#define AUDIT_SOCKADDR 1306 /* sockaddr copied as syscall arg */ -#define AUDIT_CWD 1307 /* Current working directory */ -#define AUDIT_EXECVE 1309 /* execve arguments */ -#define AUDIT_IPC_SET_PERM 1311 /* IPC new permissions record type */ -#define AUDIT_MQ_OPEN 1312 /* POSIX MQ open record type */ -#define AUDIT_MQ_SENDRECV 1313 /* POSIX MQ send/receive record type */ -#define AUDIT_MQ_NOTIFY 1314 /* POSIX MQ notify record type */ -#define AUDIT_MQ_GETSETATTR 1315 /* POSIX MQ get/set attribute record type */ -#define AUDIT_KERNEL_OTHER 1316 /* For use by 3rd party modules */ -#define AUDIT_FD_PAIR 1317 /* audit record for pipe/socketpair */ -#define AUDIT_OBJ_PID 1318 /* ptrace target */ -#define AUDIT_TTY 1319 /* Input on an administrative TTY */ -#define AUDIT_EOE 1320 /* End of multi-record event */ -#define AUDIT_BPRM_FCAPS 1321 /* Information about fcaps increasing perms */ -#define AUDIT_CAPSET 1322 /* Record showing argument to sys_capset */ -#define AUDIT_MMAP 1323 /* Record showing descriptor and flags in mmap */ -#define AUDIT_NETFILTER_PKT 1324 /* Packets traversing netfilter chains */ -#define AUDIT_NETFILTER_CFG 1325 /* Netfilter chain modifications */ -#define AUDIT_SECCOMP 1326 /* Secure Computing event */ -#define AUDIT_PROCTITLE 1327 /* Proctitle emit event */ -#define AUDIT_FEATURE_CHANGE 1328 /* audit log listing feature changes */ -#define AUDIT_REPLACE 1329 /* Replace auditd if this packet unanswerd */ - -#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */ -#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */ -#define AUDIT_AVC_PATH 1402 /* dentry, vfsmount pair from avc */ -#define AUDIT_MAC_POLICY_LOAD 1403 /* Policy file load */ -#define AUDIT_MAC_STATUS 1404 /* Changed enforcing,permissive,off */ -#define AUDIT_MAC_CONFIG_CHANGE 1405 /* Changes to booleans */ -#define AUDIT_MAC_UNLBL_ALLOW 1406 /* NetLabel: allow unlabeled traffic */ -#define AUDIT_MAC_CIPSOV4_ADD 1407 /* NetLabel: add CIPSOv4 DOI entry */ -#define AUDIT_MAC_CIPSOV4_DEL 1408 /* NetLabel: del CIPSOv4 DOI entry */ -#define AUDIT_MAC_MAP_ADD 1409 /* NetLabel: add LSM domain mapping */ -#define AUDIT_MAC_MAP_DEL 1410 /* NetLabel: del LSM domain mapping */ -#define AUDIT_MAC_IPSEC_ADDSA 1411 /* Not used */ -#define AUDIT_MAC_IPSEC_DELSA 1412 /* Not used */ -#define AUDIT_MAC_IPSEC_ADDSPD 1413 /* Not used */ -#define AUDIT_MAC_IPSEC_DELSPD 1414 /* Not used */ -#define AUDIT_MAC_IPSEC_EVENT 1415 /* Audit an IPSec event */ -#define AUDIT_MAC_UNLBL_STCADD 1416 /* NetLabel: add a static label */ -#define AUDIT_MAC_UNLBL_STCDEL 1417 /* NetLabel: del a static label */ -#define AUDIT_MAC_CALIPSO_ADD 1418 /* NetLabel: add CALIPSO DOI entry */ -#define AUDIT_MAC_CALIPSO_DEL 1419 /* NetLabel: del CALIPSO DOI entry */ - -#define AUDIT_FIRST_KERN_ANOM_MSG 1700 -#define AUDIT_LAST_KERN_ANOM_MSG 1799 -#define AUDIT_ANOM_PROMISCUOUS 1700 /* Device changed promiscuous mode */ -#define AUDIT_ANOM_ABEND 1701 /* Process ended abnormally */ -#define AUDIT_ANOM_LINK 1702 /* Suspicious use of file links */ -#define AUDIT_INTEGRITY_DATA 1800 /* Data integrity verification */ -#define AUDIT_INTEGRITY_METADATA 1801 /* Metadata integrity verification */ -#define AUDIT_INTEGRITY_STATUS 1802 /* Integrity enable status */ -#define AUDIT_INTEGRITY_HASH 1803 /* Integrity HASH type */ -#define AUDIT_INTEGRITY_PCR 1804 /* PCR invalidation msgs */ -#define AUDIT_INTEGRITY_RULE 1805 /* policy rule */ - -#define AUDIT_KERNEL 2000 /* Asynchronous audit record. NOT A REQUEST. */ - -/* Rule flags */ -#define AUDIT_FILTER_USER 0x00 /* Apply rule to user-generated messages */ -#define AUDIT_FILTER_TASK 0x01 /* Apply rule at task creation (not syscall) */ -#define AUDIT_FILTER_ENTRY 0x02 /* Apply rule at syscall entry */ -#define AUDIT_FILTER_WATCH 0x03 /* Apply rule to file system watches */ -#define AUDIT_FILTER_EXIT 0x04 /* Apply rule at syscall exit */ -#define AUDIT_FILTER_TYPE 0x05 /* Apply rule at audit_log_start */ - -#define AUDIT_NR_FILTERS 6 - -#define AUDIT_FILTER_PREPEND 0x10 /* Prepend to front of list */ - -/* Rule actions */ -#define AUDIT_NEVER 0 /* Do not build context if rule matches */ -#define AUDIT_POSSIBLE 1 /* Build context if rule matches */ -#define AUDIT_ALWAYS 2 /* Generate audit record if rule matches */ - -/* Rule structure sizes -- if these change, different AUDIT_ADD and - * AUDIT_LIST commands must be implemented. */ -#define AUDIT_MAX_FIELDS 64 -#define AUDIT_MAX_KEY_LEN 256 -#define AUDIT_BITMASK_SIZE 64 -#define AUDIT_WORD(nr) ((__u32)((nr)/32)) -#define AUDIT_BIT(nr) (1 << ((nr) - AUDIT_WORD(nr)*32)) - -#define AUDIT_SYSCALL_CLASSES 16 -#define AUDIT_CLASS_DIR_WRITE 0 -#define AUDIT_CLASS_DIR_WRITE_32 1 -#define AUDIT_CLASS_CHATTR 2 -#define AUDIT_CLASS_CHATTR_32 3 -#define AUDIT_CLASS_READ 4 -#define AUDIT_CLASS_READ_32 5 -#define AUDIT_CLASS_WRITE 6 -#define AUDIT_CLASS_WRITE_32 7 -#define AUDIT_CLASS_SIGNAL 8 -#define AUDIT_CLASS_SIGNAL_32 9 - -/* This bitmask is used to validate user input. It represents all bits that - * are currently used in an audit field constant understood by the kernel. - * If you are adding a new #define AUDIT_, please ensure that - * AUDIT_UNUSED_BITS is updated if need be. */ -#define AUDIT_UNUSED_BITS 0x07FFFC00 - -/* AUDIT_FIELD_COMPARE rule list */ -#define AUDIT_COMPARE_UID_TO_OBJ_UID 1 -#define AUDIT_COMPARE_GID_TO_OBJ_GID 2 -#define AUDIT_COMPARE_EUID_TO_OBJ_UID 3 -#define AUDIT_COMPARE_EGID_TO_OBJ_GID 4 -#define AUDIT_COMPARE_AUID_TO_OBJ_UID 5 -#define AUDIT_COMPARE_SUID_TO_OBJ_UID 6 -#define AUDIT_COMPARE_SGID_TO_OBJ_GID 7 -#define AUDIT_COMPARE_FSUID_TO_OBJ_UID 8 -#define AUDIT_COMPARE_FSGID_TO_OBJ_GID 9 - -#define AUDIT_COMPARE_UID_TO_AUID 10 -#define AUDIT_COMPARE_UID_TO_EUID 11 -#define AUDIT_COMPARE_UID_TO_FSUID 12 -#define AUDIT_COMPARE_UID_TO_SUID 13 - -#define AUDIT_COMPARE_AUID_TO_FSUID 14 -#define AUDIT_COMPARE_AUID_TO_SUID 15 -#define AUDIT_COMPARE_AUID_TO_EUID 16 - -#define AUDIT_COMPARE_EUID_TO_SUID 17 -#define AUDIT_COMPARE_EUID_TO_FSUID 18 - -#define AUDIT_COMPARE_SUID_TO_FSUID 19 - -#define AUDIT_COMPARE_GID_TO_EGID 20 -#define AUDIT_COMPARE_GID_TO_FSGID 21 -#define AUDIT_COMPARE_GID_TO_SGID 22 - -#define AUDIT_COMPARE_EGID_TO_FSGID 23 -#define AUDIT_COMPARE_EGID_TO_SGID 24 -#define AUDIT_COMPARE_SGID_TO_FSGID 25 - -#define AUDIT_MAX_FIELD_COMPARE AUDIT_COMPARE_SGID_TO_FSGID - -/* Rule fields */ - /* These are useful when checking the - * task structure at task creation time - * (AUDIT_PER_TASK). */ -#define AUDIT_PID 0 -#define AUDIT_UID 1 -#define AUDIT_EUID 2 -#define AUDIT_SUID 3 -#define AUDIT_FSUID 4 -#define AUDIT_GID 5 -#define AUDIT_EGID 6 -#define AUDIT_SGID 7 -#define AUDIT_FSGID 8 -#define AUDIT_LOGINUID 9 -#define AUDIT_PERS 10 -#define AUDIT_ARCH 11 -#define AUDIT_MSGTYPE 12 -#define AUDIT_SUBJ_USER 13 /* security label user */ -#define AUDIT_SUBJ_ROLE 14 /* security label role */ -#define AUDIT_SUBJ_TYPE 15 /* security label type */ -#define AUDIT_SUBJ_SEN 16 /* security label sensitivity label */ -#define AUDIT_SUBJ_CLR 17 /* security label clearance label */ -#define AUDIT_PPID 18 -#define AUDIT_OBJ_USER 19 -#define AUDIT_OBJ_ROLE 20 -#define AUDIT_OBJ_TYPE 21 -#define AUDIT_OBJ_LEV_LOW 22 -#define AUDIT_OBJ_LEV_HIGH 23 -#define AUDIT_LOGINUID_SET 24 - - /* These are ONLY useful when checking - * at syscall exit time (AUDIT_AT_EXIT). */ -#define AUDIT_DEVMAJOR 100 -#define AUDIT_DEVMINOR 101 -#define AUDIT_INODE 102 -#define AUDIT_EXIT 103 -#define AUDIT_SUCCESS 104 /* exit >= 0; value ignored */ -#define AUDIT_WATCH 105 -#define AUDIT_PERM 106 -#define AUDIT_DIR 107 -#define AUDIT_FILETYPE 108 -#define AUDIT_OBJ_UID 109 -#define AUDIT_OBJ_GID 110 -#define AUDIT_FIELD_COMPARE 111 -#define AUDIT_EXE 112 - -#define AUDIT_ARG0 200 -#define AUDIT_ARG1 (AUDIT_ARG0+1) -#define AUDIT_ARG2 (AUDIT_ARG0+2) -#define AUDIT_ARG3 (AUDIT_ARG0+3) - -#define AUDIT_FILTERKEY 210 - -#define AUDIT_NEGATE 0x80000000 - -/* These are the supported operators. - * 4 2 1 8 - * = > < ? - * ---------- - * 0 0 0 0 00 nonsense - * 0 0 0 1 08 & bit mask - * 0 0 1 0 10 < - * 0 1 0 0 20 > - * 0 1 1 0 30 != - * 1 0 0 0 40 = - * 1 0 0 1 48 &= bit test - * 1 0 1 0 50 <= - * 1 1 0 0 60 >= - * 1 1 1 1 78 all operators - */ -#define AUDIT_BIT_MASK 0x08000000 -#define AUDIT_LESS_THAN 0x10000000 -#define AUDIT_GREATER_THAN 0x20000000 -#define AUDIT_NOT_EQUAL 0x30000000 -#define AUDIT_EQUAL 0x40000000 -#define AUDIT_BIT_TEST (AUDIT_BIT_MASK|AUDIT_EQUAL) -#define AUDIT_LESS_THAN_OR_EQUAL (AUDIT_LESS_THAN|AUDIT_EQUAL) -#define AUDIT_GREATER_THAN_OR_EQUAL (AUDIT_GREATER_THAN|AUDIT_EQUAL) -#define AUDIT_OPERATORS (AUDIT_EQUAL|AUDIT_NOT_EQUAL|AUDIT_BIT_MASK) - -enum { - Audit_equal, - Audit_not_equal, - Audit_bitmask, - Audit_bittest, - Audit_lt, - Audit_gt, - Audit_le, - Audit_ge, - Audit_bad -}; - -/* Status symbols */ - /* Mask values */ -#define AUDIT_STATUS_ENABLED 0x0001 -#define AUDIT_STATUS_FAILURE 0x0002 -#define AUDIT_STATUS_PID 0x0004 -#define AUDIT_STATUS_RATE_LIMIT 0x0008 -#define AUDIT_STATUS_BACKLOG_LIMIT 0x0010 -#define AUDIT_STATUS_BACKLOG_WAIT_TIME 0x0020 - -#define AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT 0x00000001 -#define AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME 0x00000002 -#define AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH 0x00000004 -#define AUDIT_FEATURE_BITMAP_EXCLUDE_EXTEND 0x00000008 -#define AUDIT_FEATURE_BITMAP_ALL (AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT | \ - AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME | \ - AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH | \ - AUDIT_FEATURE_BITMAP_EXCLUDE_EXTEND) - -/* deprecated: AUDIT_VERSION_* */ -#define AUDIT_VERSION_LATEST AUDIT_FEATURE_BITMAP_ALL -#define AUDIT_VERSION_BACKLOG_LIMIT AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT -#define AUDIT_VERSION_BACKLOG_WAIT_TIME AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME - - /* Failure-to-log actions */ -#define AUDIT_FAIL_SILENT 0 -#define AUDIT_FAIL_PRINTK 1 -#define AUDIT_FAIL_PANIC 2 - -/* - * These bits disambiguate different calling conventions that share an - * ELF machine type, bitness, and endianness - */ -#define __AUDIT_ARCH_CONVENTION_MASK 0x30000000 -#define __AUDIT_ARCH_CONVENTION_MIPS64_N32 0x20000000 - -/* distinguish syscall tables */ -#define __AUDIT_ARCH_64BIT 0x80000000 -#define __AUDIT_ARCH_LE 0x40000000 - -#define AUDIT_ARCH_AARCH64 (EM_AARCH64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) -#define AUDIT_ARCH_ALPHA (EM_ALPHA|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) -#define AUDIT_ARCH_ARM (EM_ARM|__AUDIT_ARCH_LE) -#define AUDIT_ARCH_ARMEB (EM_ARM) -#define AUDIT_ARCH_CRIS (EM_CRIS|__AUDIT_ARCH_LE) -#define AUDIT_ARCH_FRV (EM_FRV) -#define AUDIT_ARCH_I386 (EM_386|__AUDIT_ARCH_LE) -#define AUDIT_ARCH_IA64 (EM_IA_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) -#define AUDIT_ARCH_M32R (EM_M32R) -#define AUDIT_ARCH_M68K (EM_68K) -#define AUDIT_ARCH_MICROBLAZE (EM_MICROBLAZE) -#define AUDIT_ARCH_MIPS (EM_MIPS) -#define AUDIT_ARCH_MIPSEL (EM_MIPS|__AUDIT_ARCH_LE) -#define AUDIT_ARCH_MIPS64 (EM_MIPS|__AUDIT_ARCH_64BIT) -#define AUDIT_ARCH_MIPS64N32 (EM_MIPS|__AUDIT_ARCH_64BIT|\ - __AUDIT_ARCH_CONVENTION_MIPS64_N32) -#define AUDIT_ARCH_MIPSEL64 (EM_MIPS|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) -#define AUDIT_ARCH_MIPSEL64N32 (EM_MIPS|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE|\ - __AUDIT_ARCH_CONVENTION_MIPS64_N32) -#define AUDIT_ARCH_OPENRISC (EM_OPENRISC) -#define AUDIT_ARCH_PARISC (EM_PARISC) -#define AUDIT_ARCH_PARISC64 (EM_PARISC|__AUDIT_ARCH_64BIT) -#define AUDIT_ARCH_PPC (EM_PPC) -/* do not define AUDIT_ARCH_PPCLE since it is not supported by audit */ -#define AUDIT_ARCH_PPC64 (EM_PPC64|__AUDIT_ARCH_64BIT) -#define AUDIT_ARCH_PPC64LE (EM_PPC64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) -#define AUDIT_ARCH_S390 (EM_S390) -#define AUDIT_ARCH_S390X (EM_S390|__AUDIT_ARCH_64BIT) -#define AUDIT_ARCH_SH (EM_SH) -#define AUDIT_ARCH_SHEL (EM_SH|__AUDIT_ARCH_LE) -#define AUDIT_ARCH_SH64 (EM_SH|__AUDIT_ARCH_64BIT) -#define AUDIT_ARCH_SHEL64 (EM_SH|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) -#define AUDIT_ARCH_SPARC (EM_SPARC) -#define AUDIT_ARCH_SPARC64 (EM_SPARCV9|__AUDIT_ARCH_64BIT) -#define AUDIT_ARCH_TILEGX (EM_TILEGX|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) -#define AUDIT_ARCH_TILEGX32 (EM_TILEGX|__AUDIT_ARCH_LE) -#define AUDIT_ARCH_TILEPRO (EM_TILEPRO|__AUDIT_ARCH_LE) -#define AUDIT_ARCH_X86_64 (EM_X86_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE) - -#define AUDIT_PERM_EXEC 1 -#define AUDIT_PERM_WRITE 2 -#define AUDIT_PERM_READ 4 -#define AUDIT_PERM_ATTR 8 - -/* MAX_AUDIT_MESSAGE_LENGTH is set in audit:lib/libaudit.h as: - * 8970 // PATH_MAX*2+CONTEXT_SIZE*2+11+256+1 - * max header+body+tailer: 44 + 29 + 32 + 262 + 7 + pad - */ -#define AUDIT_MESSAGE_TEXT_MAX 8560 - -/* Multicast Netlink socket groups (default up to 32) */ -enum audit_nlgrps { - AUDIT_NLGRP_NONE, /* Group 0 not used */ - AUDIT_NLGRP_READLOG, /* "best effort" read only socket */ - __AUDIT_NLGRP_MAX -}; -#define AUDIT_NLGRP_MAX (__AUDIT_NLGRP_MAX - 1) - -struct audit_status { - __u32 mask; /* Bit mask for valid entries */ - __u32 enabled; /* 1 = enabled, 0 = disabled */ - __u32 failure; /* Failure-to-log action */ - __u32 pid; /* pid of auditd process */ - __u32 rate_limit; /* messages rate limit (per second) */ - __u32 backlog_limit; /* waiting messages limit */ - __u32 lost; /* messages lost */ - __u32 backlog; /* messages waiting in queue */ - union { - __u32 version; /* deprecated: audit api version num */ - __u32 feature_bitmap; /* bitmap of kernel audit features */ - }; - __u32 backlog_wait_time;/* message queue wait timeout */ -}; - -struct audit_features { -#define AUDIT_FEATURE_VERSION 1 - __u32 vers; - __u32 mask; /* which bits we are dealing with */ - __u32 features; /* which feature to enable/disable */ - __u32 lock; /* which features to lock */ -}; - -#define AUDIT_FEATURE_ONLY_UNSET_LOGINUID 0 -#define AUDIT_FEATURE_LOGINUID_IMMUTABLE 1 -#define AUDIT_LAST_FEATURE AUDIT_FEATURE_LOGINUID_IMMUTABLE - -#define audit_feature_valid(x) ((x) >= 0 && (x) <= AUDIT_LAST_FEATURE) -#define AUDIT_FEATURE_TO_MASK(x) (1 << ((x) & 31)) /* mask for __u32 */ - -struct audit_tty_status { - __u32 enabled; /* 1 = enabled, 0 = disabled */ - __u32 log_passwd; /* 1 = enabled, 0 = disabled */ -}; - -#define AUDIT_UID_UNSET (unsigned int)-1 - -/* audit_rule_data supports filter rules with both integer and string - * fields. It corresponds with AUDIT_ADD_RULE, AUDIT_DEL_RULE and - * AUDIT_LIST_RULES requests. - */ -struct audit_rule_data { - __u32 flags; /* AUDIT_PER_{TASK,CALL}, AUDIT_PREPEND */ - __u32 action; /* AUDIT_NEVER, AUDIT_POSSIBLE, AUDIT_ALWAYS */ - __u32 field_count; - __u32 mask[AUDIT_BITMASK_SIZE]; /* syscall(s) affected */ - __u32 fields[AUDIT_MAX_FIELDS]; - __u32 values[AUDIT_MAX_FIELDS]; - __u32 fieldflags[AUDIT_MAX_FIELDS]; - __u32 buflen; /* total length of string fields */ - char buf[0]; /* string fields buffer */ -}; - -#endif /* _UAPI_LINUX_AUDIT_H_ */ diff --git a/src/linux/include/uapi/linux/auxvec.h b/src/linux/include/uapi/linux/auxvec.h deleted file mode 100644 index 835c065..0000000 --- a/src/linux/include/uapi/linux/auxvec.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef _UAPI_LINUX_AUXVEC_H -#define _UAPI_LINUX_AUXVEC_H - -#include - -/* Symbolic values for the entries in the auxiliary table - put on the initial stack */ -#define AT_NULL 0 /* end of vector */ -#define AT_IGNORE 1 /* entry should be ignored */ -#define AT_EXECFD 2 /* file descriptor of program */ -#define AT_PHDR 3 /* program headers for program */ -#define AT_PHENT 4 /* size of program header entry */ -#define AT_PHNUM 5 /* number of program headers */ -#define AT_PAGESZ 6 /* system page size */ -#define AT_BASE 7 /* base address of interpreter */ -#define AT_FLAGS 8 /* flags */ -#define AT_ENTRY 9 /* entry point of program */ -#define AT_NOTELF 10 /* program is not ELF */ -#define AT_UID 11 /* real uid */ -#define AT_EUID 12 /* effective uid */ -#define AT_GID 13 /* real gid */ -#define AT_EGID 14 /* effective gid */ -#define AT_PLATFORM 15 /* string identifying CPU for optimizations */ -#define AT_HWCAP 16 /* arch dependent hints at CPU capabilities */ -#define AT_CLKTCK 17 /* frequency at which times() increments */ -/* AT_* values 18 through 22 are reserved */ -#define AT_SECURE 23 /* secure mode boolean */ -#define AT_BASE_PLATFORM 24 /* string identifying real platform, may - * differ from AT_PLATFORM. */ -#define AT_RANDOM 25 /* address of 16 random bytes */ -#define AT_HWCAP2 26 /* extension of AT_HWCAP */ - -#define AT_EXECFN 31 /* filename of program */ - - -#endif /* _UAPI_LINUX_AUXVEC_H */ diff --git a/src/linux/include/uapi/linux/ax25.h b/src/linux/include/uapi/linux/ax25.h deleted file mode 100644 index 74c89a4..0000000 --- a/src/linux/include/uapi/linux/ax25.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * These are the public elements of the Linux kernel AX.25 code. A similar - * file netrom.h exists for the NET/ROM protocol. - */ - -#ifndef AX25_KERNEL_H -#define AX25_KERNEL_H - -#include - -#define AX25_MTU 256 -#define AX25_MAX_DIGIS 8 - -#define AX25_WINDOW 1 -#define AX25_T1 2 -#define AX25_N2 3 -#define AX25_T3 4 -#define AX25_T2 5 -#define AX25_BACKOFF 6 -#define AX25_EXTSEQ 7 -#define AX25_PIDINCL 8 -#define AX25_IDLE 9 -#define AX25_PACLEN 10 -#define AX25_IAMDIGI 12 - -#define AX25_KILL 99 - -#define SIOCAX25GETUID (SIOCPROTOPRIVATE+0) -#define SIOCAX25ADDUID (SIOCPROTOPRIVATE+1) -#define SIOCAX25DELUID (SIOCPROTOPRIVATE+2) -#define SIOCAX25NOUID (SIOCPROTOPRIVATE+3) -#define SIOCAX25OPTRT (SIOCPROTOPRIVATE+7) -#define SIOCAX25CTLCON (SIOCPROTOPRIVATE+8) -#define SIOCAX25GETINFOOLD (SIOCPROTOPRIVATE+9) -#define SIOCAX25ADDFWD (SIOCPROTOPRIVATE+10) -#define SIOCAX25DELFWD (SIOCPROTOPRIVATE+11) -#define SIOCAX25DEVCTL (SIOCPROTOPRIVATE+12) -#define SIOCAX25GETINFO (SIOCPROTOPRIVATE+13) - -#define AX25_SET_RT_IPMODE 2 - -#define AX25_NOUID_DEFAULT 0 -#define AX25_NOUID_BLOCK 1 - -typedef struct { - char ax25_call[7]; /* 6 call + SSID (shifted ascii!) */ -} ax25_address; - -struct sockaddr_ax25 { - __kernel_sa_family_t sax25_family; - ax25_address sax25_call; - int sax25_ndigis; - /* Digipeater ax25_address sets follow */ -}; - -#define sax25_uid sax25_ndigis - -struct full_sockaddr_ax25 { - struct sockaddr_ax25 fsa_ax25; - ax25_address fsa_digipeater[AX25_MAX_DIGIS]; -}; - -struct ax25_routes_struct { - ax25_address port_addr; - ax25_address dest_addr; - unsigned char digi_count; - ax25_address digi_addr[AX25_MAX_DIGIS]; -}; - -struct ax25_route_opt_struct { - ax25_address port_addr; - ax25_address dest_addr; - int cmd; - int arg; -}; - -struct ax25_ctl_struct { - ax25_address port_addr; - ax25_address source_addr; - ax25_address dest_addr; - unsigned int cmd; - unsigned long arg; - unsigned char digi_count; - ax25_address digi_addr[AX25_MAX_DIGIS]; -}; - -/* this will go away. Please do not export to user land */ -struct ax25_info_struct_deprecated { - unsigned int n2, n2count; - unsigned int t1, t1timer; - unsigned int t2, t2timer; - unsigned int t3, t3timer; - unsigned int idle, idletimer; - unsigned int state; - unsigned int rcv_q, snd_q; -}; - -struct ax25_info_struct { - unsigned int n2, n2count; - unsigned int t1, t1timer; - unsigned int t2, t2timer; - unsigned int t3, t3timer; - unsigned int idle, idletimer; - unsigned int state; - unsigned int rcv_q, snd_q; - unsigned int vs, vr, va, vs_max; - unsigned int paclen; - unsigned int window; -}; - -struct ax25_fwd_struct { - ax25_address port_from; - ax25_address port_to; -}; - -#endif diff --git a/src/linux/include/uapi/linux/binfmts.h b/src/linux/include/uapi/linux/binfmts.h deleted file mode 100644 index 4eb5972..0000000 --- a/src/linux/include/uapi/linux/binfmts.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _UAPI_LINUX_BINFMTS_H -#define _UAPI_LINUX_BINFMTS_H - -#include - -struct pt_regs; - -/* - * These are the maximum length and maximum number of strings passed to the - * execve() system call. MAX_ARG_STRLEN is essentially random but serves to - * prevent the kernel from being unduly impacted by misaddressed pointers. - * MAX_ARG_STRINGS is chosen to fit in a signed 32-bit integer. - */ -#define MAX_ARG_STRLEN (PAGE_SIZE * 32) -#define MAX_ARG_STRINGS 0x7FFFFFFF - -/* sizeof(linux_binprm->buf) */ -#define BINPRM_BUF_SIZE 128 - -#endif /* _UAPI_LINUX_BINFMTS_H */ diff --git a/src/linux/include/uapi/linux/blkpg.h b/src/linux/include/uapi/linux/blkpg.h deleted file mode 100644 index 63739a0..0000000 --- a/src/linux/include/uapi/linux/blkpg.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef _UAPI__LINUX_BLKPG_H -#define _UAPI__LINUX_BLKPG_H - -/* - * Partition table and disk geometry handling - * - * A single ioctl with lots of subfunctions: - * - * Device number stuff: - * get_whole_disk() (given the device number of a partition, - * find the device number of the encompassing disk) - * get_all_partitions() (given the device number of a disk, return the - * device numbers of all its known partitions) - * - * Partition stuff: - * add_partition() - * delete_partition() - * test_partition_in_use() (also for test_disk_in_use) - * - * Geometry stuff: - * get_geometry() - * set_geometry() - * get_bios_drivedata() - * - * For today, only the partition stuff - aeb, 990515 - */ -#include -#include - -#define BLKPG _IO(0x12,105) - -/* The argument structure */ -struct blkpg_ioctl_arg { - int op; - int flags; - int datalen; - void __user *data; -}; - -/* The subfunctions (for the op field) */ -#define BLKPG_ADD_PARTITION 1 -#define BLKPG_DEL_PARTITION 2 -#define BLKPG_RESIZE_PARTITION 3 - -/* Sizes of name fields. Unused at present. */ -#define BLKPG_DEVNAMELTH 64 -#define BLKPG_VOLNAMELTH 64 - -/* The data structure for ADD_PARTITION and DEL_PARTITION */ -struct blkpg_partition { - long long start; /* starting offset in bytes */ - long long length; /* length in bytes */ - int pno; /* partition number */ - char devname[BLKPG_DEVNAMELTH]; /* partition name, like sda5 or c0d1p2, - to be used in kernel messages */ - char volname[BLKPG_VOLNAMELTH]; /* volume label */ -}; - -#endif /* _UAPI__LINUX_BLKPG_H */ diff --git a/src/linux/include/uapi/linux/blktrace_api.h b/src/linux/include/uapi/linux/blktrace_api.h deleted file mode 100644 index c590ca6..0000000 --- a/src/linux/include/uapi/linux/blktrace_api.h +++ /dev/null @@ -1,142 +0,0 @@ -#ifndef _UAPIBLKTRACE_H -#define _UAPIBLKTRACE_H - -#include - -/* - * Trace categories - */ -enum blktrace_cat { - BLK_TC_READ = 1 << 0, /* reads */ - BLK_TC_WRITE = 1 << 1, /* writes */ - BLK_TC_FLUSH = 1 << 2, /* flush */ - BLK_TC_SYNC = 1 << 3, /* sync IO */ - BLK_TC_SYNCIO = BLK_TC_SYNC, - BLK_TC_QUEUE = 1 << 4, /* queueing/merging */ - BLK_TC_REQUEUE = 1 << 5, /* requeueing */ - BLK_TC_ISSUE = 1 << 6, /* issue */ - BLK_TC_COMPLETE = 1 << 7, /* completions */ - BLK_TC_FS = 1 << 8, /* fs requests */ - BLK_TC_PC = 1 << 9, /* pc requests */ - BLK_TC_NOTIFY = 1 << 10, /* special message */ - BLK_TC_AHEAD = 1 << 11, /* readahead */ - BLK_TC_META = 1 << 12, /* metadata */ - BLK_TC_DISCARD = 1 << 13, /* discard requests */ - BLK_TC_DRV_DATA = 1 << 14, /* binary per-driver data */ - BLK_TC_FUA = 1 << 15, /* fua requests */ - - BLK_TC_END = 1 << 15, /* we've run out of bits! */ -}; - -#define BLK_TC_SHIFT (16) -#define BLK_TC_ACT(act) ((act) << BLK_TC_SHIFT) - -/* - * Basic trace actions - */ -enum blktrace_act { - __BLK_TA_QUEUE = 1, /* queued */ - __BLK_TA_BACKMERGE, /* back merged to existing rq */ - __BLK_TA_FRONTMERGE, /* front merge to existing rq */ - __BLK_TA_GETRQ, /* allocated new request */ - __BLK_TA_SLEEPRQ, /* sleeping on rq allocation */ - __BLK_TA_REQUEUE, /* request requeued */ - __BLK_TA_ISSUE, /* sent to driver */ - __BLK_TA_COMPLETE, /* completed by driver */ - __BLK_TA_PLUG, /* queue was plugged */ - __BLK_TA_UNPLUG_IO, /* queue was unplugged by io */ - __BLK_TA_UNPLUG_TIMER, /* queue was unplugged by timer */ - __BLK_TA_INSERT, /* insert request */ - __BLK_TA_SPLIT, /* bio was split */ - __BLK_TA_BOUNCE, /* bio was bounced */ - __BLK_TA_REMAP, /* bio was remapped */ - __BLK_TA_ABORT, /* request aborted */ - __BLK_TA_DRV_DATA, /* driver-specific binary data */ -}; - -/* - * Notify events. - */ -enum blktrace_notify { - __BLK_TN_PROCESS = 0, /* establish pid/name mapping */ - __BLK_TN_TIMESTAMP, /* include system clock */ - __BLK_TN_MESSAGE, /* Character string message */ -}; - - -/* - * Trace actions in full. Additionally, read or write is masked - */ -#define BLK_TA_QUEUE (__BLK_TA_QUEUE | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_BACKMERGE (__BLK_TA_BACKMERGE | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_FRONTMERGE (__BLK_TA_FRONTMERGE | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_GETRQ (__BLK_TA_GETRQ | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_SLEEPRQ (__BLK_TA_SLEEPRQ | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_REQUEUE (__BLK_TA_REQUEUE | BLK_TC_ACT(BLK_TC_REQUEUE)) -#define BLK_TA_ISSUE (__BLK_TA_ISSUE | BLK_TC_ACT(BLK_TC_ISSUE)) -#define BLK_TA_COMPLETE (__BLK_TA_COMPLETE| BLK_TC_ACT(BLK_TC_COMPLETE)) -#define BLK_TA_PLUG (__BLK_TA_PLUG | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_UNPLUG_IO (__BLK_TA_UNPLUG_IO | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_UNPLUG_TIMER (__BLK_TA_UNPLUG_TIMER | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_INSERT (__BLK_TA_INSERT | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_SPLIT (__BLK_TA_SPLIT) -#define BLK_TA_BOUNCE (__BLK_TA_BOUNCE) -#define BLK_TA_REMAP (__BLK_TA_REMAP | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_ABORT (__BLK_TA_ABORT | BLK_TC_ACT(BLK_TC_QUEUE)) -#define BLK_TA_DRV_DATA (__BLK_TA_DRV_DATA | BLK_TC_ACT(BLK_TC_DRV_DATA)) - -#define BLK_TN_PROCESS (__BLK_TN_PROCESS | BLK_TC_ACT(BLK_TC_NOTIFY)) -#define BLK_TN_TIMESTAMP (__BLK_TN_TIMESTAMP | BLK_TC_ACT(BLK_TC_NOTIFY)) -#define BLK_TN_MESSAGE (__BLK_TN_MESSAGE | BLK_TC_ACT(BLK_TC_NOTIFY)) - -#define BLK_IO_TRACE_MAGIC 0x65617400 -#define BLK_IO_TRACE_VERSION 0x07 - -/* - * The trace itself - */ -struct blk_io_trace { - __u32 magic; /* MAGIC << 8 | version */ - __u32 sequence; /* event number */ - __u64 time; /* in microseconds */ - __u64 sector; /* disk offset */ - __u32 bytes; /* transfer length */ - __u32 action; /* what happened */ - __u32 pid; /* who did it */ - __u32 device; /* device number */ - __u32 cpu; /* on what cpu did it happen */ - __u16 error; /* completion error */ - __u16 pdu_len; /* length of data after this trace */ -}; - -/* - * The remap event - */ -struct blk_io_trace_remap { - __be32 device_from; - __be32 device_to; - __be64 sector_from; -}; - -enum { - Blktrace_setup = 1, - Blktrace_running, - Blktrace_stopped, -}; - -#define BLKTRACE_BDEV_SIZE 32 - -/* - * User setup structure passed with BLKTRACESTART - */ -struct blk_user_trace_setup { - char name[BLKTRACE_BDEV_SIZE]; /* output */ - __u16 act_mask; /* input */ - __u32 buf_size; /* input */ - __u32 buf_nr; /* input */ - __u64 start_lba; - __u64 end_lba; - __u32 pid; -}; - -#endif /* _UAPIBLKTRACE_H */ diff --git a/src/linux/include/uapi/linux/bpf.h b/src/linux/include/uapi/linux/bpf.h deleted file mode 100644 index f09c70b..0000000 --- a/src/linux/include/uapi/linux/bpf.h +++ /dev/null @@ -1,524 +0,0 @@ -/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - */ -#ifndef _UAPI__LINUX_BPF_H__ -#define _UAPI__LINUX_BPF_H__ - -#include -#include - -/* Extended instruction set based on top of classic BPF */ - -/* instruction classes */ -#define BPF_ALU64 0x07 /* alu mode in double word width */ - -/* ld/ldx fields */ -#define BPF_DW 0x18 /* double word */ -#define BPF_XADD 0xc0 /* exclusive add */ - -/* alu/jmp fields */ -#define BPF_MOV 0xb0 /* mov reg to reg */ -#define BPF_ARSH 0xc0 /* sign extending arithmetic shift right */ - -/* change endianness of a register */ -#define BPF_END 0xd0 /* flags for endianness conversion: */ -#define BPF_TO_LE 0x00 /* convert to little-endian */ -#define BPF_TO_BE 0x08 /* convert to big-endian */ -#define BPF_FROM_LE BPF_TO_LE -#define BPF_FROM_BE BPF_TO_BE - -#define BPF_JNE 0x50 /* jump != */ -#define BPF_JSGT 0x60 /* SGT is signed '>', GT in x86 */ -#define BPF_JSGE 0x70 /* SGE is signed '>=', GE in x86 */ -#define BPF_CALL 0x80 /* function call */ -#define BPF_EXIT 0x90 /* function return */ - -/* Register numbers */ -enum { - BPF_REG_0 = 0, - BPF_REG_1, - BPF_REG_2, - BPF_REG_3, - BPF_REG_4, - BPF_REG_5, - BPF_REG_6, - BPF_REG_7, - BPF_REG_8, - BPF_REG_9, - BPF_REG_10, - __MAX_BPF_REG, -}; - -/* BPF has 10 general purpose 64-bit registers and stack frame. */ -#define MAX_BPF_REG __MAX_BPF_REG - -struct bpf_insn { - __u8 code; /* opcode */ - __u8 dst_reg:4; /* dest register */ - __u8 src_reg:4; /* source register */ - __s16 off; /* signed offset */ - __s32 imm; /* signed immediate constant */ -}; - -/* BPF syscall commands, see bpf(2) man-page for details. */ -enum bpf_cmd { - BPF_MAP_CREATE, - BPF_MAP_LOOKUP_ELEM, - BPF_MAP_UPDATE_ELEM, - BPF_MAP_DELETE_ELEM, - BPF_MAP_GET_NEXT_KEY, - BPF_PROG_LOAD, - BPF_OBJ_PIN, - BPF_OBJ_GET, -}; - -enum bpf_map_type { - BPF_MAP_TYPE_UNSPEC, - BPF_MAP_TYPE_HASH, - BPF_MAP_TYPE_ARRAY, - BPF_MAP_TYPE_PROG_ARRAY, - BPF_MAP_TYPE_PERF_EVENT_ARRAY, - BPF_MAP_TYPE_PERCPU_HASH, - BPF_MAP_TYPE_PERCPU_ARRAY, - BPF_MAP_TYPE_STACK_TRACE, - BPF_MAP_TYPE_CGROUP_ARRAY, -}; - -enum bpf_prog_type { - BPF_PROG_TYPE_UNSPEC, - BPF_PROG_TYPE_SOCKET_FILTER, - BPF_PROG_TYPE_KPROBE, - BPF_PROG_TYPE_SCHED_CLS, - BPF_PROG_TYPE_SCHED_ACT, - BPF_PROG_TYPE_TRACEPOINT, - BPF_PROG_TYPE_XDP, - BPF_PROG_TYPE_PERF_EVENT, -}; - -#define BPF_PSEUDO_MAP_FD 1 - -/* flags for BPF_MAP_UPDATE_ELEM command */ -#define BPF_ANY 0 /* create new element or update existing */ -#define BPF_NOEXIST 1 /* create new element if it didn't exist */ -#define BPF_EXIST 2 /* update existing element */ - -#define BPF_F_NO_PREALLOC (1U << 0) - -union bpf_attr { - struct { /* anonymous struct used by BPF_MAP_CREATE command */ - __u32 map_type; /* one of enum bpf_map_type */ - __u32 key_size; /* size of key in bytes */ - __u32 value_size; /* size of value in bytes */ - __u32 max_entries; /* max number of entries in a map */ - __u32 map_flags; /* prealloc or not */ - }; - - struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ - __u32 map_fd; - __aligned_u64 key; - union { - __aligned_u64 value; - __aligned_u64 next_key; - }; - __u64 flags; - }; - - struct { /* anonymous struct used by BPF_PROG_LOAD command */ - __u32 prog_type; /* one of enum bpf_prog_type */ - __u32 insn_cnt; - __aligned_u64 insns; - __aligned_u64 license; - __u32 log_level; /* verbosity level of verifier */ - __u32 log_size; /* size of user buffer */ - __aligned_u64 log_buf; /* user supplied buffer */ - __u32 kern_version; /* checked when prog_type=kprobe */ - }; - - struct { /* anonymous struct used by BPF_OBJ_* commands */ - __aligned_u64 pathname; - __u32 bpf_fd; - }; -} __attribute__((aligned(8))); - -/* integer value in 'imm' field of BPF_CALL instruction selects which helper - * function eBPF program intends to call - */ -enum bpf_func_id { - BPF_FUNC_unspec, - BPF_FUNC_map_lookup_elem, /* void *map_lookup_elem(&map, &key) */ - BPF_FUNC_map_update_elem, /* int map_update_elem(&map, &key, &value, flags) */ - BPF_FUNC_map_delete_elem, /* int map_delete_elem(&map, &key) */ - BPF_FUNC_probe_read, /* int bpf_probe_read(void *dst, int size, void *src) */ - BPF_FUNC_ktime_get_ns, /* u64 bpf_ktime_get_ns(void) */ - BPF_FUNC_trace_printk, /* int bpf_trace_printk(const char *fmt, int fmt_size, ...) */ - BPF_FUNC_get_prandom_u32, /* u32 prandom_u32(void) */ - BPF_FUNC_get_smp_processor_id, /* u32 raw_smp_processor_id(void) */ - - /** - * skb_store_bytes(skb, offset, from, len, flags) - store bytes into packet - * @skb: pointer to skb - * @offset: offset within packet from skb->mac_header - * @from: pointer where to copy bytes from - * @len: number of bytes to store into packet - * @flags: bit 0 - if true, recompute skb->csum - * other bits - reserved - * Return: 0 on success - */ - BPF_FUNC_skb_store_bytes, - - /** - * l3_csum_replace(skb, offset, from, to, flags) - recompute IP checksum - * @skb: pointer to skb - * @offset: offset within packet where IP checksum is located - * @from: old value of header field - * @to: new value of header field - * @flags: bits 0-3 - size of header field - * other bits - reserved - * Return: 0 on success - */ - BPF_FUNC_l3_csum_replace, - - /** - * l4_csum_replace(skb, offset, from, to, flags) - recompute TCP/UDP checksum - * @skb: pointer to skb - * @offset: offset within packet where TCP/UDP checksum is located - * @from: old value of header field - * @to: new value of header field - * @flags: bits 0-3 - size of header field - * bit 4 - is pseudo header - * other bits - reserved - * Return: 0 on success - */ - BPF_FUNC_l4_csum_replace, - - /** - * bpf_tail_call(ctx, prog_array_map, index) - jump into another BPF program - * @ctx: context pointer passed to next program - * @prog_array_map: pointer to map which type is BPF_MAP_TYPE_PROG_ARRAY - * @index: index inside array that selects specific program to run - * Return: 0 on success - */ - BPF_FUNC_tail_call, - - /** - * bpf_clone_redirect(skb, ifindex, flags) - redirect to another netdev - * @skb: pointer to skb - * @ifindex: ifindex of the net device - * @flags: bit 0 - if set, redirect to ingress instead of egress - * other bits - reserved - * Return: 0 on success - */ - BPF_FUNC_clone_redirect, - - /** - * u64 bpf_get_current_pid_tgid(void) - * Return: current->tgid << 32 | current->pid - */ - BPF_FUNC_get_current_pid_tgid, - - /** - * u64 bpf_get_current_uid_gid(void) - * Return: current_gid << 32 | current_uid - */ - BPF_FUNC_get_current_uid_gid, - - /** - * bpf_get_current_comm(char *buf, int size_of_buf) - * stores current->comm into buf - * Return: 0 on success - */ - BPF_FUNC_get_current_comm, - - /** - * bpf_get_cgroup_classid(skb) - retrieve a proc's classid - * @skb: pointer to skb - * Return: classid if != 0 - */ - BPF_FUNC_get_cgroup_classid, - BPF_FUNC_skb_vlan_push, /* bpf_skb_vlan_push(skb, vlan_proto, vlan_tci) */ - BPF_FUNC_skb_vlan_pop, /* bpf_skb_vlan_pop(skb) */ - - /** - * bpf_skb_[gs]et_tunnel_key(skb, key, size, flags) - * retrieve or populate tunnel metadata - * @skb: pointer to skb - * @key: pointer to 'struct bpf_tunnel_key' - * @size: size of 'struct bpf_tunnel_key' - * @flags: room for future extensions - * Retrun: 0 on success - */ - BPF_FUNC_skb_get_tunnel_key, - BPF_FUNC_skb_set_tunnel_key, - BPF_FUNC_perf_event_read, /* u64 bpf_perf_event_read(&map, index) */ - /** - * bpf_redirect(ifindex, flags) - redirect to another netdev - * @ifindex: ifindex of the net device - * @flags: bit 0 - if set, redirect to ingress instead of egress - * other bits - reserved - * Return: TC_ACT_REDIRECT - */ - BPF_FUNC_redirect, - - /** - * bpf_get_route_realm(skb) - retrieve a dst's tclassid - * @skb: pointer to skb - * Return: realm if != 0 - */ - BPF_FUNC_get_route_realm, - - /** - * bpf_perf_event_output(ctx, map, index, data, size) - output perf raw sample - * @ctx: struct pt_regs* - * @map: pointer to perf_event_array map - * @index: index of event in the map - * @data: data on stack to be output as raw data - * @size: size of data - * Return: 0 on success - */ - BPF_FUNC_perf_event_output, - BPF_FUNC_skb_load_bytes, - - /** - * bpf_get_stackid(ctx, map, flags) - walk user or kernel stack and return id - * @ctx: struct pt_regs* - * @map: pointer to stack_trace map - * @flags: bits 0-7 - numer of stack frames to skip - * bit 8 - collect user stack instead of kernel - * bit 9 - compare stacks by hash only - * bit 10 - if two different stacks hash into the same stackid - * discard old - * other bits - reserved - * Return: >= 0 stackid on success or negative error - */ - BPF_FUNC_get_stackid, - - /** - * bpf_csum_diff(from, from_size, to, to_size, seed) - calculate csum diff - * @from: raw from buffer - * @from_size: length of from buffer - * @to: raw to buffer - * @to_size: length of to buffer - * @seed: optional seed - * Return: csum result - */ - BPF_FUNC_csum_diff, - - /** - * bpf_skb_[gs]et_tunnel_opt(skb, opt, size) - * retrieve or populate tunnel options metadata - * @skb: pointer to skb - * @opt: pointer to raw tunnel option data - * @size: size of @opt - * Return: 0 on success for set, option size for get - */ - BPF_FUNC_skb_get_tunnel_opt, - BPF_FUNC_skb_set_tunnel_opt, - - /** - * bpf_skb_change_proto(skb, proto, flags) - * Change protocol of the skb. Currently supported is - * v4 -> v6, v6 -> v4 transitions. The helper will also - * resize the skb. eBPF program is expected to fill the - * new headers via skb_store_bytes and lX_csum_replace. - * @skb: pointer to skb - * @proto: new skb->protocol type - * @flags: reserved - * Return: 0 on success or negative error - */ - BPF_FUNC_skb_change_proto, - - /** - * bpf_skb_change_type(skb, type) - * Change packet type of skb. - * @skb: pointer to skb - * @type: new skb->pkt_type type - * Return: 0 on success or negative error - */ - BPF_FUNC_skb_change_type, - - /** - * bpf_skb_under_cgroup(skb, map, index) - Check cgroup2 membership of skb - * @skb: pointer to skb - * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type - * @index: index of the cgroup in the bpf_map - * Return: - * == 0 skb failed the cgroup2 descendant test - * == 1 skb succeeded the cgroup2 descendant test - * < 0 error - */ - BPF_FUNC_skb_under_cgroup, - - /** - * bpf_get_hash_recalc(skb) - * Retrieve and possibly recalculate skb->hash. - * @skb: pointer to skb - * Return: hash - */ - BPF_FUNC_get_hash_recalc, - - /** - * u64 bpf_get_current_task(void) - * Returns current task_struct - * Return: current - */ - BPF_FUNC_get_current_task, - - /** - * bpf_probe_write_user(void *dst, void *src, int len) - * safely attempt to write to a location - * @dst: destination address in userspace - * @src: source address on stack - * @len: number of bytes to copy - * Return: 0 on success or negative error - */ - BPF_FUNC_probe_write_user, - - /** - * bpf_current_task_under_cgroup(map, index) - Check cgroup2 membership of current task - * @map: pointer to bpf_map in BPF_MAP_TYPE_CGROUP_ARRAY type - * @index: index of the cgroup in the bpf_map - * Return: - * == 0 current failed the cgroup2 descendant test - * == 1 current succeeded the cgroup2 descendant test - * < 0 error - */ - BPF_FUNC_current_task_under_cgroup, - - /** - * bpf_skb_change_tail(skb, len, flags) - * The helper will resize the skb to the given new size, - * to be used f.e. with control messages. - * @skb: pointer to skb - * @len: new skb length - * @flags: reserved - * Return: 0 on success or negative error - */ - BPF_FUNC_skb_change_tail, - - /** - * bpf_skb_pull_data(skb, len) - * The helper will pull in non-linear data in case the - * skb is non-linear and not all of len are part of the - * linear section. Only needed for read/write with direct - * packet access. - * @skb: pointer to skb - * @len: len to make read/writeable - * Return: 0 on success or negative error - */ - BPF_FUNC_skb_pull_data, - - /** - * bpf_csum_update(skb, csum) - * Adds csum into skb->csum in case of CHECKSUM_COMPLETE. - * @skb: pointer to skb - * @csum: csum to add - * Return: csum on success or negative error - */ - BPF_FUNC_csum_update, - - /** - * bpf_set_hash_invalid(skb) - * Invalidate current skb>hash. - * @skb: pointer to skb - */ - BPF_FUNC_set_hash_invalid, - - __BPF_FUNC_MAX_ID, -}; - -/* All flags used by eBPF helper functions, placed here. */ - -/* BPF_FUNC_skb_store_bytes flags. */ -#define BPF_F_RECOMPUTE_CSUM (1ULL << 0) -#define BPF_F_INVALIDATE_HASH (1ULL << 1) - -/* BPF_FUNC_l3_csum_replace and BPF_FUNC_l4_csum_replace flags. - * First 4 bits are for passing the header field size. - */ -#define BPF_F_HDR_FIELD_MASK 0xfULL - -/* BPF_FUNC_l4_csum_replace flags. */ -#define BPF_F_PSEUDO_HDR (1ULL << 4) -#define BPF_F_MARK_MANGLED_0 (1ULL << 5) - -/* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */ -#define BPF_F_INGRESS (1ULL << 0) - -/* BPF_FUNC_skb_set_tunnel_key and BPF_FUNC_skb_get_tunnel_key flags. */ -#define BPF_F_TUNINFO_IPV6 (1ULL << 0) - -/* BPF_FUNC_get_stackid flags. */ -#define BPF_F_SKIP_FIELD_MASK 0xffULL -#define BPF_F_USER_STACK (1ULL << 8) -#define BPF_F_FAST_STACK_CMP (1ULL << 9) -#define BPF_F_REUSE_STACKID (1ULL << 10) - -/* BPF_FUNC_skb_set_tunnel_key flags. */ -#define BPF_F_ZERO_CSUM_TX (1ULL << 1) -#define BPF_F_DONT_FRAGMENT (1ULL << 2) - -/* BPF_FUNC_perf_event_output and BPF_FUNC_perf_event_read flags. */ -#define BPF_F_INDEX_MASK 0xffffffffULL -#define BPF_F_CURRENT_CPU BPF_F_INDEX_MASK -/* BPF_FUNC_perf_event_output for sk_buff input context. */ -#define BPF_F_CTXLEN_MASK (0xfffffULL << 32) - -/* user accessible mirror of in-kernel sk_buff. - * new fields can only be added to the end of this structure - */ -struct __sk_buff { - __u32 len; - __u32 pkt_type; - __u32 mark; - __u32 queue_mapping; - __u32 protocol; - __u32 vlan_present; - __u32 vlan_tci; - __u32 vlan_proto; - __u32 priority; - __u32 ingress_ifindex; - __u32 ifindex; - __u32 tc_index; - __u32 cb[5]; - __u32 hash; - __u32 tc_classid; - __u32 data; - __u32 data_end; -}; - -struct bpf_tunnel_key { - __u32 tunnel_id; - union { - __u32 remote_ipv4; - __u32 remote_ipv6[4]; - }; - __u8 tunnel_tos; - __u8 tunnel_ttl; - __u16 tunnel_ext; - __u32 tunnel_label; -}; - -/* User return codes for XDP prog type. - * A valid XDP program must return one of these defined values. All other - * return codes are reserved for future use. Unknown return codes will result - * in packet drop. - */ -enum xdp_action { - XDP_ABORTED = 0, - XDP_DROP, - XDP_PASS, - XDP_TX, -}; - -/* user accessible metadata for XDP packet hook - * new fields must be added to the end of this structure - */ -struct xdp_md { - __u32 data; - __u32 data_end; -}; - -#endif /* _UAPI__LINUX_BPF_H__ */ diff --git a/src/linux/include/uapi/linux/bpf_common.h b/src/linux/include/uapi/linux/bpf_common.h deleted file mode 100644 index a5c220e..0000000 --- a/src/linux/include/uapi/linux/bpf_common.h +++ /dev/null @@ -1,55 +0,0 @@ -#ifndef _UAPI__LINUX_BPF_COMMON_H__ -#define _UAPI__LINUX_BPF_COMMON_H__ - -/* Instruction classes */ -#define BPF_CLASS(code) ((code) & 0x07) -#define BPF_LD 0x00 -#define BPF_LDX 0x01 -#define BPF_ST 0x02 -#define BPF_STX 0x03 -#define BPF_ALU 0x04 -#define BPF_JMP 0x05 -#define BPF_RET 0x06 -#define BPF_MISC 0x07 - -/* ld/ldx fields */ -#define BPF_SIZE(code) ((code) & 0x18) -#define BPF_W 0x00 -#define BPF_H 0x08 -#define BPF_B 0x10 -#define BPF_MODE(code) ((code) & 0xe0) -#define BPF_IMM 0x00 -#define BPF_ABS 0x20 -#define BPF_IND 0x40 -#define BPF_MEM 0x60 -#define BPF_LEN 0x80 -#define BPF_MSH 0xa0 - -/* alu/jmp fields */ -#define BPF_OP(code) ((code) & 0xf0) -#define BPF_ADD 0x00 -#define BPF_SUB 0x10 -#define BPF_MUL 0x20 -#define BPF_DIV 0x30 -#define BPF_OR 0x40 -#define BPF_AND 0x50 -#define BPF_LSH 0x60 -#define BPF_RSH 0x70 -#define BPF_NEG 0x80 -#define BPF_MOD 0x90 -#define BPF_XOR 0xa0 - -#define BPF_JA 0x00 -#define BPF_JEQ 0x10 -#define BPF_JGT 0x20 -#define BPF_JGE 0x30 -#define BPF_JSET 0x40 -#define BPF_SRC(code) ((code) & 0x08) -#define BPF_K 0x00 -#define BPF_X 0x08 - -#ifndef BPF_MAXINSNS -#define BPF_MAXINSNS 4096 -#endif - -#endif /* _UAPI__LINUX_BPF_COMMON_H__ */ diff --git a/src/linux/include/uapi/linux/bsg.h b/src/linux/include/uapi/linux/bsg.h deleted file mode 100644 index 02986cf..0000000 --- a/src/linux/include/uapi/linux/bsg.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef _UAPIBSG_H -#define _UAPIBSG_H - -#include - -#define BSG_PROTOCOL_SCSI 0 - -#define BSG_SUB_PROTOCOL_SCSI_CMD 0 -#define BSG_SUB_PROTOCOL_SCSI_TMF 1 -#define BSG_SUB_PROTOCOL_SCSI_TRANSPORT 2 - -/* - * For flag constants below: - * sg.h sg_io_hdr also has bits defined for it's flags member. These - * two flag values (0x10 and 0x20) have the same meaning in sg.h . For - * bsg the BSG_FLAG_Q_AT_HEAD flag is ignored since it is the deafult. - */ -#define BSG_FLAG_Q_AT_TAIL 0x10 /* default is Q_AT_HEAD */ -#define BSG_FLAG_Q_AT_HEAD 0x20 - -struct sg_io_v4 { - __s32 guard; /* [i] 'Q' to differentiate from v3 */ - __u32 protocol; /* [i] 0 -> SCSI , .... */ - __u32 subprotocol; /* [i] 0 -> SCSI command, 1 -> SCSI task - management function, .... */ - - __u32 request_len; /* [i] in bytes */ - __u64 request; /* [i], [*i] {SCSI: cdb} */ - __u64 request_tag; /* [i] {SCSI: task tag (only if flagged)} */ - __u32 request_attr; /* [i] {SCSI: task attribute} */ - __u32 request_priority; /* [i] {SCSI: task priority} */ - __u32 request_extra; /* [i] {spare, for padding} */ - __u32 max_response_len; /* [i] in bytes */ - __u64 response; /* [i], [*o] {SCSI: (auto)sense data} */ - - /* "dout_": data out (to device); "din_": data in (from device) */ - __u32 dout_iovec_count; /* [i] 0 -> "flat" dout transfer else - dout_xfer points to array of iovec */ - __u32 dout_xfer_len; /* [i] bytes to be transferred to device */ - __u32 din_iovec_count; /* [i] 0 -> "flat" din transfer */ - __u32 din_xfer_len; /* [i] bytes to be transferred from device */ - __u64 dout_xferp; /* [i], [*i] */ - __u64 din_xferp; /* [i], [*o] */ - - __u32 timeout; /* [i] units: millisecond */ - __u32 flags; /* [i] bit mask */ - __u64 usr_ptr; /* [i->o] unused internally */ - __u32 spare_in; /* [i] */ - - __u32 driver_status; /* [o] 0 -> ok */ - __u32 transport_status; /* [o] 0 -> ok */ - __u32 device_status; /* [o] {SCSI: command completion status} */ - __u32 retry_delay; /* [o] {SCSI: status auxiliary information} */ - __u32 info; /* [o] additional information */ - __u32 duration; /* [o] time to complete, in milliseconds */ - __u32 response_len; /* [o] bytes of response actually written */ - __s32 din_resid; /* [o] din_xfer_len - actual_din_xfer_len */ - __s32 dout_resid; /* [o] dout_xfer_len - actual_dout_xfer_len */ - __u64 generated_tag; /* [o] {SCSI: transport generated task tag} */ - __u32 spare_out; /* [o] */ - - __u32 padding; -}; - - -#endif /* _UAPIBSG_H */ diff --git a/src/linux/include/uapi/linux/btrfs.h b/src/linux/include/uapi/linux/btrfs.h deleted file mode 100644 index db4c253..0000000 --- a/src/linux/include/uapi/linux/btrfs.h +++ /dev/null @@ -1,849 +0,0 @@ -/* - * Copyright (C) 2007 Oracle. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 021110-1307, USA. - */ - -#ifndef _UAPI_LINUX_BTRFS_H -#define _UAPI_LINUX_BTRFS_H -#include -#include - -#define BTRFS_IOCTL_MAGIC 0x94 -#define BTRFS_VOL_NAME_MAX 255 -#define BTRFS_LABEL_SIZE 256 - -/* this should be 4k */ -#define BTRFS_PATH_NAME_MAX 4087 -struct btrfs_ioctl_vol_args { - __s64 fd; - char name[BTRFS_PATH_NAME_MAX + 1]; -}; - -#define BTRFS_DEVICE_PATH_NAME_MAX 1024 - -#define BTRFS_DEVICE_SPEC_BY_ID (1ULL << 3) - -#define BTRFS_VOL_ARG_V2_FLAGS_SUPPORTED \ - (BTRFS_SUBVOL_CREATE_ASYNC | \ - BTRFS_SUBVOL_RDONLY | \ - BTRFS_SUBVOL_QGROUP_INHERIT | \ - BTRFS_DEVICE_SPEC_BY_ID) - -#define BTRFS_FSID_SIZE 16 -#define BTRFS_UUID_SIZE 16 -#define BTRFS_UUID_UNPARSED_SIZE 37 - -/* - * flags definition for qgroup limits - * - * Used by: - * struct btrfs_qgroup_limit.flags - * struct btrfs_qgroup_limit_item.flags - */ -#define BTRFS_QGROUP_LIMIT_MAX_RFER (1ULL << 0) -#define BTRFS_QGROUP_LIMIT_MAX_EXCL (1ULL << 1) -#define BTRFS_QGROUP_LIMIT_RSV_RFER (1ULL << 2) -#define BTRFS_QGROUP_LIMIT_RSV_EXCL (1ULL << 3) -#define BTRFS_QGROUP_LIMIT_RFER_CMPR (1ULL << 4) -#define BTRFS_QGROUP_LIMIT_EXCL_CMPR (1ULL << 5) - -struct btrfs_qgroup_limit { - __u64 flags; - __u64 max_rfer; - __u64 max_excl; - __u64 rsv_rfer; - __u64 rsv_excl; -}; - -/* - * flags definition for qgroup inheritance - * - * Used by: - * struct btrfs_qgroup_inherit.flags - */ -#define BTRFS_QGROUP_INHERIT_SET_LIMITS (1ULL << 0) - -struct btrfs_qgroup_inherit { - __u64 flags; - __u64 num_qgroups; - __u64 num_ref_copies; - __u64 num_excl_copies; - struct btrfs_qgroup_limit lim; - __u64 qgroups[0]; -}; - -struct btrfs_ioctl_qgroup_limit_args { - __u64 qgroupid; - struct btrfs_qgroup_limit lim; -}; - -/* - * flags for subvolumes - * - * Used by: - * struct btrfs_ioctl_vol_args_v2.flags - * - * BTRFS_SUBVOL_RDONLY is also provided/consumed by the following ioctls: - * - BTRFS_IOC_SUBVOL_GETFLAGS - * - BTRFS_IOC_SUBVOL_SETFLAGS - */ -#define BTRFS_SUBVOL_CREATE_ASYNC (1ULL << 0) -#define BTRFS_SUBVOL_RDONLY (1ULL << 1) -#define BTRFS_SUBVOL_QGROUP_INHERIT (1ULL << 2) - -#define BTRFS_SUBVOL_NAME_MAX 4039 -struct btrfs_ioctl_vol_args_v2 { - __s64 fd; - __u64 transid; - __u64 flags; - union { - struct { - __u64 size; - struct btrfs_qgroup_inherit __user *qgroup_inherit; - }; - __u64 unused[4]; - }; - union { - char name[BTRFS_SUBVOL_NAME_MAX + 1]; - __u64 devid; - }; -}; - -/* - * structure to report errors and progress to userspace, either as a - * result of a finished scrub, a canceled scrub or a progress inquiry - */ -struct btrfs_scrub_progress { - __u64 data_extents_scrubbed; /* # of data extents scrubbed */ - __u64 tree_extents_scrubbed; /* # of tree extents scrubbed */ - __u64 data_bytes_scrubbed; /* # of data bytes scrubbed */ - __u64 tree_bytes_scrubbed; /* # of tree bytes scrubbed */ - __u64 read_errors; /* # of read errors encountered (EIO) */ - __u64 csum_errors; /* # of failed csum checks */ - __u64 verify_errors; /* # of occurences, where the metadata - * of a tree block did not match the - * expected values, like generation or - * logical */ - __u64 no_csum; /* # of 4k data block for which no csum - * is present, probably the result of - * data written with nodatasum */ - __u64 csum_discards; /* # of csum for which no data was found - * in the extent tree. */ - __u64 super_errors; /* # of bad super blocks encountered */ - __u64 malloc_errors; /* # of internal kmalloc errors. These - * will likely cause an incomplete - * scrub */ - __u64 uncorrectable_errors; /* # of errors where either no intact - * copy was found or the writeback - * failed */ - __u64 corrected_errors; /* # of errors corrected */ - __u64 last_physical; /* last physical address scrubbed. In - * case a scrub was aborted, this can - * be used to restart the scrub */ - __u64 unverified_errors; /* # of occurences where a read for a - * full (64k) bio failed, but the re- - * check succeeded for each 4k piece. - * Intermittent error. */ -}; - -#define BTRFS_SCRUB_READONLY 1 -struct btrfs_ioctl_scrub_args { - __u64 devid; /* in */ - __u64 start; /* in */ - __u64 end; /* in */ - __u64 flags; /* in */ - struct btrfs_scrub_progress progress; /* out */ - /* pad to 1k */ - __u64 unused[(1024-32-sizeof(struct btrfs_scrub_progress))/8]; -}; - -#define BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_ALWAYS 0 -#define BTRFS_IOCTL_DEV_REPLACE_CONT_READING_FROM_SRCDEV_MODE_AVOID 1 -struct btrfs_ioctl_dev_replace_start_params { - __u64 srcdevid; /* in, if 0, use srcdev_name instead */ - __u64 cont_reading_from_srcdev_mode; /* in, see #define - * above */ - __u8 srcdev_name[BTRFS_DEVICE_PATH_NAME_MAX + 1]; /* in */ - __u8 tgtdev_name[BTRFS_DEVICE_PATH_NAME_MAX + 1]; /* in */ -}; - -#define BTRFS_IOCTL_DEV_REPLACE_STATE_NEVER_STARTED 0 -#define BTRFS_IOCTL_DEV_REPLACE_STATE_STARTED 1 -#define BTRFS_IOCTL_DEV_REPLACE_STATE_FINISHED 2 -#define BTRFS_IOCTL_DEV_REPLACE_STATE_CANCELED 3 -#define BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED 4 -struct btrfs_ioctl_dev_replace_status_params { - __u64 replace_state; /* out, see #define above */ - __u64 progress_1000; /* out, 0 <= x <= 1000 */ - __u64 time_started; /* out, seconds since 1-Jan-1970 */ - __u64 time_stopped; /* out, seconds since 1-Jan-1970 */ - __u64 num_write_errors; /* out */ - __u64 num_uncorrectable_read_errors; /* out */ -}; - -#define BTRFS_IOCTL_DEV_REPLACE_CMD_START 0 -#define BTRFS_IOCTL_DEV_REPLACE_CMD_STATUS 1 -#define BTRFS_IOCTL_DEV_REPLACE_CMD_CANCEL 2 -#define BTRFS_IOCTL_DEV_REPLACE_RESULT_NO_ERROR 0 -#define BTRFS_IOCTL_DEV_REPLACE_RESULT_NOT_STARTED 1 -#define BTRFS_IOCTL_DEV_REPLACE_RESULT_ALREADY_STARTED 2 -#define BTRFS_IOCTL_DEV_REPLACE_RESULT_SCRUB_INPROGRESS 3 -struct btrfs_ioctl_dev_replace_args { - __u64 cmd; /* in */ - __u64 result; /* out */ - - union { - struct btrfs_ioctl_dev_replace_start_params start; - struct btrfs_ioctl_dev_replace_status_params status; - }; /* in/out */ - - __u64 spare[64]; -}; - -struct btrfs_ioctl_dev_info_args { - __u64 devid; /* in/out */ - __u8 uuid[BTRFS_UUID_SIZE]; /* in/out */ - __u64 bytes_used; /* out */ - __u64 total_bytes; /* out */ - __u64 unused[379]; /* pad to 4k */ - __u8 path[BTRFS_DEVICE_PATH_NAME_MAX]; /* out */ -}; - -struct btrfs_ioctl_fs_info_args { - __u64 max_id; /* out */ - __u64 num_devices; /* out */ - __u8 fsid[BTRFS_FSID_SIZE]; /* out */ - __u32 nodesize; /* out */ - __u32 sectorsize; /* out */ - __u32 clone_alignment; /* out */ - __u32 reserved32; - __u64 reserved[122]; /* pad to 1k */ -}; - -/* - * feature flags - * - * Used by: - * struct btrfs_ioctl_feature_flags - */ -#define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE (1ULL << 0) -/* - * Older kernels (< 4.9) on big-endian systems produced broken free space tree - * bitmaps, and btrfs-progs also used to corrupt the free space tree (versions - * < 4.7.3). If this bit is clear, then the free space tree cannot be trusted. - * btrfs-progs can also intentionally clear this bit to ask the kernel to - * rebuild the free space tree, however this might not work on older kernels - * that do not know about this bit. If not sure, clear the cache manually on - * first mount when booting older kernel versions. - */ -#define BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE_VALID (1ULL << 1) - -#define BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF (1ULL << 0) -#define BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL (1ULL << 1) -#define BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS (1ULL << 2) -#define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO (1ULL << 3) -/* - * some patches floated around with a second compression method - * lets save that incompat here for when they do get in - * Note we don't actually support it, we're just reserving the - * number - */ -#define BTRFS_FEATURE_INCOMPAT_COMPRESS_LZOv2 (1ULL << 4) - -/* - * older kernels tried to do bigger metadata blocks, but the - * code was pretty buggy. Lets not let them try anymore. - */ -#define BTRFS_FEATURE_INCOMPAT_BIG_METADATA (1ULL << 5) - -#define BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF (1ULL << 6) -#define BTRFS_FEATURE_INCOMPAT_RAID56 (1ULL << 7) -#define BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA (1ULL << 8) -#define BTRFS_FEATURE_INCOMPAT_NO_HOLES (1ULL << 9) - -struct btrfs_ioctl_feature_flags { - __u64 compat_flags; - __u64 compat_ro_flags; - __u64 incompat_flags; -}; - -/* balance control ioctl modes */ -#define BTRFS_BALANCE_CTL_PAUSE 1 -#define BTRFS_BALANCE_CTL_CANCEL 2 - -/* - * this is packed, because it should be exactly the same as its disk - * byte order counterpart (struct btrfs_disk_balance_args) - */ -struct btrfs_balance_args { - __u64 profiles; - union { - __le64 usage; - struct { - __le32 usage_min; - __le32 usage_max; - }; - }; - __u64 devid; - __u64 pstart; - __u64 pend; - __u64 vstart; - __u64 vend; - - __u64 target; - - __u64 flags; - - /* - * BTRFS_BALANCE_ARGS_LIMIT with value 'limit' - * BTRFS_BALANCE_ARGS_LIMIT_RANGE - the extend version can use minimum - * and maximum - */ - union { - __u64 limit; /* limit number of processed chunks */ - struct { - __u32 limit_min; - __u32 limit_max; - }; - }; - - /* - * Process chunks that cross stripes_min..stripes_max devices, - * BTRFS_BALANCE_ARGS_STRIPES_RANGE - */ - __le32 stripes_min; - __le32 stripes_max; - - __u64 unused[6]; -} __attribute__ ((__packed__)); - -/* report balance progress to userspace */ -struct btrfs_balance_progress { - __u64 expected; /* estimated # of chunks that will be - * relocated to fulfill the request */ - __u64 considered; /* # of chunks we have considered so far */ - __u64 completed; /* # of chunks relocated so far */ -}; - -/* - * flags definition for balance - * - * Restriper's general type filter - * - * Used by: - * btrfs_ioctl_balance_args.flags - * btrfs_balance_control.flags (internal) - */ -#define BTRFS_BALANCE_DATA (1ULL << 0) -#define BTRFS_BALANCE_SYSTEM (1ULL << 1) -#define BTRFS_BALANCE_METADATA (1ULL << 2) - -#define BTRFS_BALANCE_TYPE_MASK (BTRFS_BALANCE_DATA | \ - BTRFS_BALANCE_SYSTEM | \ - BTRFS_BALANCE_METADATA) - -#define BTRFS_BALANCE_FORCE (1ULL << 3) -#define BTRFS_BALANCE_RESUME (1ULL << 4) - -/* - * flags definitions for per-type balance args - * - * Balance filters - * - * Used by: - * struct btrfs_balance_args - */ -#define BTRFS_BALANCE_ARGS_PROFILES (1ULL << 0) -#define BTRFS_BALANCE_ARGS_USAGE (1ULL << 1) -#define BTRFS_BALANCE_ARGS_DEVID (1ULL << 2) -#define BTRFS_BALANCE_ARGS_DRANGE (1ULL << 3) -#define BTRFS_BALANCE_ARGS_VRANGE (1ULL << 4) -#define BTRFS_BALANCE_ARGS_LIMIT (1ULL << 5) -#define BTRFS_BALANCE_ARGS_LIMIT_RANGE (1ULL << 6) -#define BTRFS_BALANCE_ARGS_STRIPES_RANGE (1ULL << 7) -#define BTRFS_BALANCE_ARGS_USAGE_RANGE (1ULL << 10) - -#define BTRFS_BALANCE_ARGS_MASK \ - (BTRFS_BALANCE_ARGS_PROFILES | \ - BTRFS_BALANCE_ARGS_USAGE | \ - BTRFS_BALANCE_ARGS_DEVID | \ - BTRFS_BALANCE_ARGS_DRANGE | \ - BTRFS_BALANCE_ARGS_VRANGE | \ - BTRFS_BALANCE_ARGS_LIMIT | \ - BTRFS_BALANCE_ARGS_LIMIT_RANGE | \ - BTRFS_BALANCE_ARGS_STRIPES_RANGE | \ - BTRFS_BALANCE_ARGS_USAGE_RANGE) - -/* - * Profile changing flags. When SOFT is set we won't relocate chunk if - * it already has the target profile (even though it may be - * half-filled). - */ -#define BTRFS_BALANCE_ARGS_CONVERT (1ULL << 8) -#define BTRFS_BALANCE_ARGS_SOFT (1ULL << 9) - - -/* - * flags definition for balance state - * - * Used by: - * struct btrfs_ioctl_balance_args.state - */ -#define BTRFS_BALANCE_STATE_RUNNING (1ULL << 0) -#define BTRFS_BALANCE_STATE_PAUSE_REQ (1ULL << 1) -#define BTRFS_BALANCE_STATE_CANCEL_REQ (1ULL << 2) - -struct btrfs_ioctl_balance_args { - __u64 flags; /* in/out */ - __u64 state; /* out */ - - struct btrfs_balance_args data; /* in/out */ - struct btrfs_balance_args meta; /* in/out */ - struct btrfs_balance_args sys; /* in/out */ - - struct btrfs_balance_progress stat; /* out */ - - __u64 unused[72]; /* pad to 1k */ -}; - -#define BTRFS_INO_LOOKUP_PATH_MAX 4080 -struct btrfs_ioctl_ino_lookup_args { - __u64 treeid; - __u64 objectid; - char name[BTRFS_INO_LOOKUP_PATH_MAX]; -}; - -struct btrfs_ioctl_search_key { - /* which root are we searching. 0 is the tree of tree roots */ - __u64 tree_id; - - /* keys returned will be >= min and <= max */ - __u64 min_objectid; - __u64 max_objectid; - - /* keys returned will be >= min and <= max */ - __u64 min_offset; - __u64 max_offset; - - /* max and min transids to search for */ - __u64 min_transid; - __u64 max_transid; - - /* keys returned will be >= min and <= max */ - __u32 min_type; - __u32 max_type; - - /* - * how many items did userland ask for, and how many are we - * returning - */ - __u32 nr_items; - - /* align to 64 bits */ - __u32 unused; - - /* some extra for later */ - __u64 unused1; - __u64 unused2; - __u64 unused3; - __u64 unused4; -}; - -struct btrfs_ioctl_search_header { - __u64 transid; - __u64 objectid; - __u64 offset; - __u32 type; - __u32 len; -}; - -#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key)) -/* - * the buf is an array of search headers where - * each header is followed by the actual item - * the type field is expanded to 32 bits for alignment - */ -struct btrfs_ioctl_search_args { - struct btrfs_ioctl_search_key key; - char buf[BTRFS_SEARCH_ARGS_BUFSIZE]; -}; - -struct btrfs_ioctl_search_args_v2 { - struct btrfs_ioctl_search_key key; /* in/out - search parameters */ - __u64 buf_size; /* in - size of buffer - * out - on EOVERFLOW: needed size - * to store item */ - __u64 buf[0]; /* out - found items */ -}; - -struct btrfs_ioctl_clone_range_args { - __s64 src_fd; - __u64 src_offset, src_length; - __u64 dest_offset; -}; - -/* - * flags definition for the defrag range ioctl - * - * Used by: - * struct btrfs_ioctl_defrag_range_args.flags - */ -#define BTRFS_DEFRAG_RANGE_COMPRESS 1 -#define BTRFS_DEFRAG_RANGE_START_IO 2 -struct btrfs_ioctl_defrag_range_args { - /* start of the defrag operation */ - __u64 start; - - /* number of bytes to defrag, use (u64)-1 to say all */ - __u64 len; - - /* - * flags for the operation, which can include turning - * on compression for this one defrag - */ - __u64 flags; - - /* - * any extent bigger than this will be considered - * already defragged. Use 0 to take the kernel default - * Use 1 to say every single extent must be rewritten - */ - __u32 extent_thresh; - - /* - * which compression method to use if turning on compression - * for this defrag operation. If unspecified, zlib will - * be used - */ - __u32 compress_type; - - /* spare for later */ - __u32 unused[4]; -}; - - -#define BTRFS_SAME_DATA_DIFFERS 1 -/* For extent-same ioctl */ -struct btrfs_ioctl_same_extent_info { - __s64 fd; /* in - destination file */ - __u64 logical_offset; /* in - start of extent in destination */ - __u64 bytes_deduped; /* out - total # of bytes we were able - * to dedupe from this file */ - /* status of this dedupe operation: - * 0 if dedup succeeds - * < 0 for error - * == BTRFS_SAME_DATA_DIFFERS if data differs - */ - __s32 status; /* out - see above description */ - __u32 reserved; -}; - -struct btrfs_ioctl_same_args { - __u64 logical_offset; /* in - start of extent in source */ - __u64 length; /* in - length of extent */ - __u16 dest_count; /* in - total elements in info array */ - __u16 reserved1; - __u32 reserved2; - struct btrfs_ioctl_same_extent_info info[0]; -}; - -struct btrfs_ioctl_space_info { - __u64 flags; - __u64 total_bytes; - __u64 used_bytes; -}; - -struct btrfs_ioctl_space_args { - __u64 space_slots; - __u64 total_spaces; - struct btrfs_ioctl_space_info spaces[0]; -}; - -struct btrfs_data_container { - __u32 bytes_left; /* out -- bytes not needed to deliver output */ - __u32 bytes_missing; /* out -- additional bytes needed for result */ - __u32 elem_cnt; /* out */ - __u32 elem_missed; /* out */ - __u64 val[0]; /* out */ -}; - -struct btrfs_ioctl_ino_path_args { - __u64 inum; /* in */ - __u64 size; /* in */ - __u64 reserved[4]; - /* struct btrfs_data_container *fspath; out */ - __u64 fspath; /* out */ -}; - -struct btrfs_ioctl_logical_ino_args { - __u64 logical; /* in */ - __u64 size; /* in */ - __u64 reserved[4]; - /* struct btrfs_data_container *inodes; out */ - __u64 inodes; -}; - -enum btrfs_dev_stat_values { - /* disk I/O failure stats */ - BTRFS_DEV_STAT_WRITE_ERRS, /* EIO or EREMOTEIO from lower layers */ - BTRFS_DEV_STAT_READ_ERRS, /* EIO or EREMOTEIO from lower layers */ - BTRFS_DEV_STAT_FLUSH_ERRS, /* EIO or EREMOTEIO from lower layers */ - - /* stats for indirect indications for I/O failures */ - BTRFS_DEV_STAT_CORRUPTION_ERRS, /* checksum error, bytenr error or - * contents is illegal: this is an - * indication that the block was damaged - * during read or write, or written to - * wrong location or read from wrong - * location */ - BTRFS_DEV_STAT_GENERATION_ERRS, /* an indication that blocks have not - * been written */ - - BTRFS_DEV_STAT_VALUES_MAX -}; - -/* Reset statistics after reading; needs SYS_ADMIN capability */ -#define BTRFS_DEV_STATS_RESET (1ULL << 0) - -struct btrfs_ioctl_get_dev_stats { - __u64 devid; /* in */ - __u64 nr_items; /* in/out */ - __u64 flags; /* in/out */ - - /* out values: */ - __u64 values[BTRFS_DEV_STAT_VALUES_MAX]; - - __u64 unused[128 - 2 - BTRFS_DEV_STAT_VALUES_MAX]; /* pad to 1k */ -}; - -#define BTRFS_QUOTA_CTL_ENABLE 1 -#define BTRFS_QUOTA_CTL_DISABLE 2 -#define BTRFS_QUOTA_CTL_RESCAN__NOTUSED 3 -struct btrfs_ioctl_quota_ctl_args { - __u64 cmd; - __u64 status; -}; - -struct btrfs_ioctl_quota_rescan_args { - __u64 flags; - __u64 progress; - __u64 reserved[6]; -}; - -struct btrfs_ioctl_qgroup_assign_args { - __u64 assign; - __u64 src; - __u64 dst; -}; - -struct btrfs_ioctl_qgroup_create_args { - __u64 create; - __u64 qgroupid; -}; -struct btrfs_ioctl_timespec { - __u64 sec; - __u32 nsec; -}; - -struct btrfs_ioctl_received_subvol_args { - char uuid[BTRFS_UUID_SIZE]; /* in */ - __u64 stransid; /* in */ - __u64 rtransid; /* out */ - struct btrfs_ioctl_timespec stime; /* in */ - struct btrfs_ioctl_timespec rtime; /* out */ - __u64 flags; /* in */ - __u64 reserved[16]; /* in */ -}; - -/* - * Caller doesn't want file data in the send stream, even if the - * search of clone sources doesn't find an extent. UPDATE_EXTENT - * commands will be sent instead of WRITE commands. - */ -#define BTRFS_SEND_FLAG_NO_FILE_DATA 0x1 - -/* - * Do not add the leading stream header. Used when multiple snapshots - * are sent back to back. - */ -#define BTRFS_SEND_FLAG_OMIT_STREAM_HEADER 0x2 - -/* - * Omit the command at the end of the stream that indicated the end - * of the stream. This option is used when multiple snapshots are - * sent back to back. - */ -#define BTRFS_SEND_FLAG_OMIT_END_CMD 0x4 - -#define BTRFS_SEND_FLAG_MASK \ - (BTRFS_SEND_FLAG_NO_FILE_DATA | \ - BTRFS_SEND_FLAG_OMIT_STREAM_HEADER | \ - BTRFS_SEND_FLAG_OMIT_END_CMD) - -struct btrfs_ioctl_send_args { - __s64 send_fd; /* in */ - __u64 clone_sources_count; /* in */ - __u64 __user *clone_sources; /* in */ - __u64 parent_root; /* in */ - __u64 flags; /* in */ - __u64 reserved[4]; /* in */ -}; - -/* Error codes as returned by the kernel */ -enum btrfs_err_code { - BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET = 1, - BTRFS_ERROR_DEV_RAID10_MIN_NOT_MET, - BTRFS_ERROR_DEV_RAID5_MIN_NOT_MET, - BTRFS_ERROR_DEV_RAID6_MIN_NOT_MET, - BTRFS_ERROR_DEV_TGT_REPLACE, - BTRFS_ERROR_DEV_MISSING_NOT_FOUND, - BTRFS_ERROR_DEV_ONLY_WRITABLE, - BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS -}; -/* An error code to error string mapping for the kernel -* error codes -*/ -static inline char *btrfs_err_str(enum btrfs_err_code err_code) -{ - switch (err_code) { - case BTRFS_ERROR_DEV_RAID1_MIN_NOT_MET: - return "unable to go below two devices on raid1"; - case BTRFS_ERROR_DEV_RAID10_MIN_NOT_MET: - return "unable to go below four devices on raid10"; - case BTRFS_ERROR_DEV_RAID5_MIN_NOT_MET: - return "unable to go below two devices on raid5"; - case BTRFS_ERROR_DEV_RAID6_MIN_NOT_MET: - return "unable to go below three devices on raid6"; - case BTRFS_ERROR_DEV_TGT_REPLACE: - return "unable to remove the dev_replace target dev"; - case BTRFS_ERROR_DEV_MISSING_NOT_FOUND: - return "no missing devices found to remove"; - case BTRFS_ERROR_DEV_ONLY_WRITABLE: - return "unable to remove the only writeable device"; - case BTRFS_ERROR_DEV_EXCL_RUN_IN_PROGRESS: - return "add/delete/balance/replace/resize operation "\ - "in progress"; - default: - return NULL; - } -} - -#define BTRFS_IOC_SNAP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 1, \ - struct btrfs_ioctl_vol_args) -#define BTRFS_IOC_DEFRAG _IOW(BTRFS_IOCTL_MAGIC, 2, \ - struct btrfs_ioctl_vol_args) -#define BTRFS_IOC_RESIZE _IOW(BTRFS_IOCTL_MAGIC, 3, \ - struct btrfs_ioctl_vol_args) -#define BTRFS_IOC_SCAN_DEV _IOW(BTRFS_IOCTL_MAGIC, 4, \ - struct btrfs_ioctl_vol_args) -/* trans start and trans end are dangerous, and only for - * use by applications that know how to avoid the - * resulting deadlocks - */ -#define BTRFS_IOC_TRANS_START _IO(BTRFS_IOCTL_MAGIC, 6) -#define BTRFS_IOC_TRANS_END _IO(BTRFS_IOCTL_MAGIC, 7) -#define BTRFS_IOC_SYNC _IO(BTRFS_IOCTL_MAGIC, 8) - -#define BTRFS_IOC_CLONE _IOW(BTRFS_IOCTL_MAGIC, 9, int) -#define BTRFS_IOC_ADD_DEV _IOW(BTRFS_IOCTL_MAGIC, 10, \ - struct btrfs_ioctl_vol_args) -#define BTRFS_IOC_RM_DEV _IOW(BTRFS_IOCTL_MAGIC, 11, \ - struct btrfs_ioctl_vol_args) -#define BTRFS_IOC_BALANCE _IOW(BTRFS_IOCTL_MAGIC, 12, \ - struct btrfs_ioctl_vol_args) - -#define BTRFS_IOC_CLONE_RANGE _IOW(BTRFS_IOCTL_MAGIC, 13, \ - struct btrfs_ioctl_clone_range_args) - -#define BTRFS_IOC_SUBVOL_CREATE _IOW(BTRFS_IOCTL_MAGIC, 14, \ - struct btrfs_ioctl_vol_args) -#define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \ - struct btrfs_ioctl_vol_args) -#define BTRFS_IOC_DEFRAG_RANGE _IOW(BTRFS_IOCTL_MAGIC, 16, \ - struct btrfs_ioctl_defrag_range_args) -#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \ - struct btrfs_ioctl_search_args) -#define BTRFS_IOC_TREE_SEARCH_V2 _IOWR(BTRFS_IOCTL_MAGIC, 17, \ - struct btrfs_ioctl_search_args_v2) -#define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \ - struct btrfs_ioctl_ino_lookup_args) -#define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, __u64) -#define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \ - struct btrfs_ioctl_space_args) -#define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64) -#define BTRFS_IOC_WAIT_SYNC _IOW(BTRFS_IOCTL_MAGIC, 22, __u64) -#define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \ - struct btrfs_ioctl_vol_args_v2) -#define BTRFS_IOC_SUBVOL_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 24, \ - struct btrfs_ioctl_vol_args_v2) -#define BTRFS_IOC_SUBVOL_GETFLAGS _IOR(BTRFS_IOCTL_MAGIC, 25, __u64) -#define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64) -#define BTRFS_IOC_SCRUB _IOWR(BTRFS_IOCTL_MAGIC, 27, \ - struct btrfs_ioctl_scrub_args) -#define BTRFS_IOC_SCRUB_CANCEL _IO(BTRFS_IOCTL_MAGIC, 28) -#define BTRFS_IOC_SCRUB_PROGRESS _IOWR(BTRFS_IOCTL_MAGIC, 29, \ - struct btrfs_ioctl_scrub_args) -#define BTRFS_IOC_DEV_INFO _IOWR(BTRFS_IOCTL_MAGIC, 30, \ - struct btrfs_ioctl_dev_info_args) -#define BTRFS_IOC_FS_INFO _IOR(BTRFS_IOCTL_MAGIC, 31, \ - struct btrfs_ioctl_fs_info_args) -#define BTRFS_IOC_BALANCE_V2 _IOWR(BTRFS_IOCTL_MAGIC, 32, \ - struct btrfs_ioctl_balance_args) -#define BTRFS_IOC_BALANCE_CTL _IOW(BTRFS_IOCTL_MAGIC, 33, int) -#define BTRFS_IOC_BALANCE_PROGRESS _IOR(BTRFS_IOCTL_MAGIC, 34, \ - struct btrfs_ioctl_balance_args) -#define BTRFS_IOC_INO_PATHS _IOWR(BTRFS_IOCTL_MAGIC, 35, \ - struct btrfs_ioctl_ino_path_args) -#define BTRFS_IOC_LOGICAL_INO _IOWR(BTRFS_IOCTL_MAGIC, 36, \ - struct btrfs_ioctl_logical_ino_args) -#define BTRFS_IOC_SET_RECEIVED_SUBVOL _IOWR(BTRFS_IOCTL_MAGIC, 37, \ - struct btrfs_ioctl_received_subvol_args) -#define BTRFS_IOC_SEND _IOW(BTRFS_IOCTL_MAGIC, 38, struct btrfs_ioctl_send_args) -#define BTRFS_IOC_DEVICES_READY _IOR(BTRFS_IOCTL_MAGIC, 39, \ - struct btrfs_ioctl_vol_args) -#define BTRFS_IOC_QUOTA_CTL _IOWR(BTRFS_IOCTL_MAGIC, 40, \ - struct btrfs_ioctl_quota_ctl_args) -#define BTRFS_IOC_QGROUP_ASSIGN _IOW(BTRFS_IOCTL_MAGIC, 41, \ - struct btrfs_ioctl_qgroup_assign_args) -#define BTRFS_IOC_QGROUP_CREATE _IOW(BTRFS_IOCTL_MAGIC, 42, \ - struct btrfs_ioctl_qgroup_create_args) -#define BTRFS_IOC_QGROUP_LIMIT _IOR(BTRFS_IOCTL_MAGIC, 43, \ - struct btrfs_ioctl_qgroup_limit_args) -#define BTRFS_IOC_QUOTA_RESCAN _IOW(BTRFS_IOCTL_MAGIC, 44, \ - struct btrfs_ioctl_quota_rescan_args) -#define BTRFS_IOC_QUOTA_RESCAN_STATUS _IOR(BTRFS_IOCTL_MAGIC, 45, \ - struct btrfs_ioctl_quota_rescan_args) -#define BTRFS_IOC_QUOTA_RESCAN_WAIT _IO(BTRFS_IOCTL_MAGIC, 46) -#define BTRFS_IOC_GET_FSLABEL _IOR(BTRFS_IOCTL_MAGIC, 49, \ - char[BTRFS_LABEL_SIZE]) -#define BTRFS_IOC_SET_FSLABEL _IOW(BTRFS_IOCTL_MAGIC, 50, \ - char[BTRFS_LABEL_SIZE]) -#define BTRFS_IOC_GET_DEV_STATS _IOWR(BTRFS_IOCTL_MAGIC, 52, \ - struct btrfs_ioctl_get_dev_stats) -#define BTRFS_IOC_DEV_REPLACE _IOWR(BTRFS_IOCTL_MAGIC, 53, \ - struct btrfs_ioctl_dev_replace_args) -#define BTRFS_IOC_FILE_EXTENT_SAME _IOWR(BTRFS_IOCTL_MAGIC, 54, \ - struct btrfs_ioctl_same_args) -#define BTRFS_IOC_GET_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \ - struct btrfs_ioctl_feature_flags) -#define BTRFS_IOC_SET_FEATURES _IOW(BTRFS_IOCTL_MAGIC, 57, \ - struct btrfs_ioctl_feature_flags[2]) -#define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \ - struct btrfs_ioctl_feature_flags[3]) -#define BTRFS_IOC_RM_DEV_V2 _IOW(BTRFS_IOCTL_MAGIC, 58, \ - struct btrfs_ioctl_vol_args_v2) - -#endif /* _UAPI_LINUX_BTRFS_H */ diff --git a/src/linux/include/uapi/linux/btrfs_tree.h b/src/linux/include/uapi/linux/btrfs_tree.h deleted file mode 100644 index d5ad15a..0000000 --- a/src/linux/include/uapi/linux/btrfs_tree.h +++ /dev/null @@ -1,966 +0,0 @@ -#ifndef _BTRFS_CTREE_H_ -#define _BTRFS_CTREE_H_ - -/* - * This header contains the structure definitions and constants used - * by file system objects that can be retrieved using - * the BTRFS_IOC_SEARCH_TREE ioctl. That means basically anything that - * is needed to describe a leaf node's key or item contents. - */ - -/* holds pointers to all of the tree roots */ -#define BTRFS_ROOT_TREE_OBJECTID 1ULL - -/* stores information about which extents are in use, and reference counts */ -#define BTRFS_EXTENT_TREE_OBJECTID 2ULL - -/* - * chunk tree stores translations from logical -> physical block numbering - * the super block points to the chunk tree - */ -#define BTRFS_CHUNK_TREE_OBJECTID 3ULL - -/* - * stores information about which areas of a given device are in use. - * one per device. The tree of tree roots points to the device tree - */ -#define BTRFS_DEV_TREE_OBJECTID 4ULL - -/* one per subvolume, storing files and directories */ -#define BTRFS_FS_TREE_OBJECTID 5ULL - -/* directory objectid inside the root tree */ -#define BTRFS_ROOT_TREE_DIR_OBJECTID 6ULL - -/* holds checksums of all the data extents */ -#define BTRFS_CSUM_TREE_OBJECTID 7ULL - -/* holds quota configuration and tracking */ -#define BTRFS_QUOTA_TREE_OBJECTID 8ULL - -/* for storing items that use the BTRFS_UUID_KEY* types */ -#define BTRFS_UUID_TREE_OBJECTID 9ULL - -/* tracks free space in block groups. */ -#define BTRFS_FREE_SPACE_TREE_OBJECTID 10ULL - -/* device stats in the device tree */ -#define BTRFS_DEV_STATS_OBJECTID 0ULL - -/* for storing balance parameters in the root tree */ -#define BTRFS_BALANCE_OBJECTID -4ULL - -/* orhpan objectid for tracking unlinked/truncated files */ -#define BTRFS_ORPHAN_OBJECTID -5ULL - -/* does write ahead logging to speed up fsyncs */ -#define BTRFS_TREE_LOG_OBJECTID -6ULL -#define BTRFS_TREE_LOG_FIXUP_OBJECTID -7ULL - -/* for space balancing */ -#define BTRFS_TREE_RELOC_OBJECTID -8ULL -#define BTRFS_DATA_RELOC_TREE_OBJECTID -9ULL - -/* - * extent checksums all have this objectid - * this allows them to share the logging tree - * for fsyncs - */ -#define BTRFS_EXTENT_CSUM_OBJECTID -10ULL - -/* For storing free space cache */ -#define BTRFS_FREE_SPACE_OBJECTID -11ULL - -/* - * The inode number assigned to the special inode for storing - * free ino cache - */ -#define BTRFS_FREE_INO_OBJECTID -12ULL - -/* dummy objectid represents multiple objectids */ -#define BTRFS_MULTIPLE_OBJECTIDS -255ULL - -/* - * All files have objectids in this range. - */ -#define BTRFS_FIRST_FREE_OBJECTID 256ULL -#define BTRFS_LAST_FREE_OBJECTID -256ULL -#define BTRFS_FIRST_CHUNK_TREE_OBJECTID 256ULL - - -/* - * the device items go into the chunk tree. The key is in the form - * [ 1 BTRFS_DEV_ITEM_KEY device_id ] - */ -#define BTRFS_DEV_ITEMS_OBJECTID 1ULL - -#define BTRFS_BTREE_INODE_OBJECTID 1 - -#define BTRFS_EMPTY_SUBVOL_DIR_OBJECTID 2 - -#define BTRFS_DEV_REPLACE_DEVID 0ULL - -/* - * inode items have the data typically returned from stat and store other - * info about object characteristics. There is one for every file and dir in - * the FS - */ -#define BTRFS_INODE_ITEM_KEY 1 -#define BTRFS_INODE_REF_KEY 12 -#define BTRFS_INODE_EXTREF_KEY 13 -#define BTRFS_XATTR_ITEM_KEY 24 -#define BTRFS_ORPHAN_ITEM_KEY 48 -/* reserve 2-15 close to the inode for later flexibility */ - -/* - * dir items are the name -> inode pointers in a directory. There is one - * for every name in a directory. - */ -#define BTRFS_DIR_LOG_ITEM_KEY 60 -#define BTRFS_DIR_LOG_INDEX_KEY 72 -#define BTRFS_DIR_ITEM_KEY 84 -#define BTRFS_DIR_INDEX_KEY 96 -/* - * extent data is for file data - */ -#define BTRFS_EXTENT_DATA_KEY 108 - -/* - * extent csums are stored in a separate tree and hold csums for - * an entire extent on disk. - */ -#define BTRFS_EXTENT_CSUM_KEY 128 - -/* - * root items point to tree roots. They are typically in the root - * tree used by the super block to find all the other trees - */ -#define BTRFS_ROOT_ITEM_KEY 132 - -/* - * root backrefs tie subvols and snapshots to the directory entries that - * reference them - */ -#define BTRFS_ROOT_BACKREF_KEY 144 - -/* - * root refs make a fast index for listing all of the snapshots and - * subvolumes referenced by a given root. They point directly to the - * directory item in the root that references the subvol - */ -#define BTRFS_ROOT_REF_KEY 156 - -/* - * extent items are in the extent map tree. These record which blocks - * are used, and how many references there are to each block - */ -#define BTRFS_EXTENT_ITEM_KEY 168 - -/* - * The same as the BTRFS_EXTENT_ITEM_KEY, except it's metadata we already know - * the length, so we save the level in key->offset instead of the length. - */ -#define BTRFS_METADATA_ITEM_KEY 169 - -#define BTRFS_TREE_BLOCK_REF_KEY 176 - -#define BTRFS_EXTENT_DATA_REF_KEY 178 - -#define BTRFS_EXTENT_REF_V0_KEY 180 - -#define BTRFS_SHARED_BLOCK_REF_KEY 182 - -#define BTRFS_SHARED_DATA_REF_KEY 184 - -/* - * block groups give us hints into the extent allocation trees. Which - * blocks are free etc etc - */ -#define BTRFS_BLOCK_GROUP_ITEM_KEY 192 - -/* - * Every block group is represented in the free space tree by a free space info - * item, which stores some accounting information. It is keyed on - * (block_group_start, FREE_SPACE_INFO, block_group_length). - */ -#define BTRFS_FREE_SPACE_INFO_KEY 198 - -/* - * A free space extent tracks an extent of space that is free in a block group. - * It is keyed on (start, FREE_SPACE_EXTENT, length). - */ -#define BTRFS_FREE_SPACE_EXTENT_KEY 199 - -/* - * When a block group becomes very fragmented, we convert it to use bitmaps - * instead of extents. A free space bitmap is keyed on - * (start, FREE_SPACE_BITMAP, length); the corresponding item is a bitmap with - * (length / sectorsize) bits. - */ -#define BTRFS_FREE_SPACE_BITMAP_KEY 200 - -#define BTRFS_DEV_EXTENT_KEY 204 -#define BTRFS_DEV_ITEM_KEY 216 -#define BTRFS_CHUNK_ITEM_KEY 228 - -/* - * Records the overall state of the qgroups. - * There's only one instance of this key present, - * (0, BTRFS_QGROUP_STATUS_KEY, 0) - */ -#define BTRFS_QGROUP_STATUS_KEY 240 -/* - * Records the currently used space of the qgroup. - * One key per qgroup, (0, BTRFS_QGROUP_INFO_KEY, qgroupid). - */ -#define BTRFS_QGROUP_INFO_KEY 242 -/* - * Contains the user configured limits for the qgroup. - * One key per qgroup, (0, BTRFS_QGROUP_LIMIT_KEY, qgroupid). - */ -#define BTRFS_QGROUP_LIMIT_KEY 244 -/* - * Records the child-parent relationship of qgroups. For - * each relation, 2 keys are present: - * (childid, BTRFS_QGROUP_RELATION_KEY, parentid) - * (parentid, BTRFS_QGROUP_RELATION_KEY, childid) - */ -#define BTRFS_QGROUP_RELATION_KEY 246 - -/* - * Obsolete name, see BTRFS_TEMPORARY_ITEM_KEY. - */ -#define BTRFS_BALANCE_ITEM_KEY 248 - -/* - * The key type for tree items that are stored persistently, but do not need to - * exist for extended period of time. The items can exist in any tree. - * - * [subtype, BTRFS_TEMPORARY_ITEM_KEY, data] - * - * Existing items: - * - * - balance status item - * (BTRFS_BALANCE_OBJECTID, BTRFS_TEMPORARY_ITEM_KEY, 0) - */ -#define BTRFS_TEMPORARY_ITEM_KEY 248 - -/* - * Obsolete name, see BTRFS_PERSISTENT_ITEM_KEY - */ -#define BTRFS_DEV_STATS_KEY 249 - -/* - * The key type for tree items that are stored persistently and usually exist - * for a long period, eg. filesystem lifetime. The item kinds can be status - * information, stats or preference values. The item can exist in any tree. - * - * [subtype, BTRFS_PERSISTENT_ITEM_KEY, data] - * - * Existing items: - * - * - device statistics, store IO stats in the device tree, one key for all - * stats - * (BTRFS_DEV_STATS_OBJECTID, BTRFS_DEV_STATS_KEY, 0) - */ -#define BTRFS_PERSISTENT_ITEM_KEY 249 - -/* - * Persistantly stores the device replace state in the device tree. - * The key is built like this: (0, BTRFS_DEV_REPLACE_KEY, 0). - */ -#define BTRFS_DEV_REPLACE_KEY 250 - -/* - * Stores items that allow to quickly map UUIDs to something else. - * These items are part of the filesystem UUID tree. - * The key is built like this: - * (UUID_upper_64_bits, BTRFS_UUID_KEY*, UUID_lower_64_bits). - */ -#if BTRFS_UUID_SIZE != 16 -#error "UUID items require BTRFS_UUID_SIZE == 16!" -#endif -#define BTRFS_UUID_KEY_SUBVOL 251 /* for UUIDs assigned to subvols */ -#define BTRFS_UUID_KEY_RECEIVED_SUBVOL 252 /* for UUIDs assigned to - * received subvols */ - -/* - * string items are for debugging. They just store a short string of - * data in the FS - */ -#define BTRFS_STRING_ITEM_KEY 253 - - - -/* 32 bytes in various csum fields */ -#define BTRFS_CSUM_SIZE 32 - -/* csum types */ -#define BTRFS_CSUM_TYPE_CRC32 0 - -/* - * flags definitions for directory entry item type - * - * Used by: - * struct btrfs_dir_item.type - */ -#define BTRFS_FT_UNKNOWN 0 -#define BTRFS_FT_REG_FILE 1 -#define BTRFS_FT_DIR 2 -#define BTRFS_FT_CHRDEV 3 -#define BTRFS_FT_BLKDEV 4 -#define BTRFS_FT_FIFO 5 -#define BTRFS_FT_SOCK 6 -#define BTRFS_FT_SYMLINK 7 -#define BTRFS_FT_XATTR 8 -#define BTRFS_FT_MAX 9 - -/* - * The key defines the order in the tree, and so it also defines (optimal) - * block layout. - * - * objectid corresponds to the inode number. - * - * type tells us things about the object, and is a kind of stream selector. - * so for a given inode, keys with type of 1 might refer to the inode data, - * type of 2 may point to file data in the btree and type == 3 may point to - * extents. - * - * offset is the starting byte offset for this key in the stream. - * - * btrfs_disk_key is in disk byte order. struct btrfs_key is always - * in cpu native order. Otherwise they are identical and their sizes - * should be the same (ie both packed) - */ -struct btrfs_disk_key { - __le64 objectid; - __u8 type; - __le64 offset; -} __attribute__ ((__packed__)); - -struct btrfs_key { - __u64 objectid; - __u8 type; - __u64 offset; -} __attribute__ ((__packed__)); - -struct btrfs_dev_item { - /* the internal btrfs device id */ - __le64 devid; - - /* size of the device */ - __le64 total_bytes; - - /* bytes used */ - __le64 bytes_used; - - /* optimal io alignment for this device */ - __le32 io_align; - - /* optimal io width for this device */ - __le32 io_width; - - /* minimal io size for this device */ - __le32 sector_size; - - /* type and info about this device */ - __le64 type; - - /* expected generation for this device */ - __le64 generation; - - /* - * starting byte of this partition on the device, - * to allow for stripe alignment in the future - */ - __le64 start_offset; - - /* grouping information for allocation decisions */ - __le32 dev_group; - - /* seek speed 0-100 where 100 is fastest */ - __u8 seek_speed; - - /* bandwidth 0-100 where 100 is fastest */ - __u8 bandwidth; - - /* btrfs generated uuid for this device */ - __u8 uuid[BTRFS_UUID_SIZE]; - - /* uuid of FS who owns this device */ - __u8 fsid[BTRFS_UUID_SIZE]; -} __attribute__ ((__packed__)); - -struct btrfs_stripe { - __le64 devid; - __le64 offset; - __u8 dev_uuid[BTRFS_UUID_SIZE]; -} __attribute__ ((__packed__)); - -struct btrfs_chunk { - /* size of this chunk in bytes */ - __le64 length; - - /* objectid of the root referencing this chunk */ - __le64 owner; - - __le64 stripe_len; - __le64 type; - - /* optimal io alignment for this chunk */ - __le32 io_align; - - /* optimal io width for this chunk */ - __le32 io_width; - - /* minimal io size for this chunk */ - __le32 sector_size; - - /* 2^16 stripes is quite a lot, a second limit is the size of a single - * item in the btree - */ - __le16 num_stripes; - - /* sub stripes only matter for raid10 */ - __le16 sub_stripes; - struct btrfs_stripe stripe; - /* additional stripes go here */ -} __attribute__ ((__packed__)); - -#define BTRFS_FREE_SPACE_EXTENT 1 -#define BTRFS_FREE_SPACE_BITMAP 2 - -struct btrfs_free_space_entry { - __le64 offset; - __le64 bytes; - __u8 type; -} __attribute__ ((__packed__)); - -struct btrfs_free_space_header { - struct btrfs_disk_key location; - __le64 generation; - __le64 num_entries; - __le64 num_bitmaps; -} __attribute__ ((__packed__)); - -#define BTRFS_HEADER_FLAG_WRITTEN (1ULL << 0) -#define BTRFS_HEADER_FLAG_RELOC (1ULL << 1) - -/* Super block flags */ -/* Errors detected */ -#define BTRFS_SUPER_FLAG_ERROR (1ULL << 2) - -#define BTRFS_SUPER_FLAG_SEEDING (1ULL << 32) -#define BTRFS_SUPER_FLAG_METADUMP (1ULL << 33) - - -/* - * items in the extent btree are used to record the objectid of the - * owner of the block and the number of references - */ - -struct btrfs_extent_item { - __le64 refs; - __le64 generation; - __le64 flags; -} __attribute__ ((__packed__)); - -struct btrfs_extent_item_v0 { - __le32 refs; -} __attribute__ ((__packed__)); - - -#define BTRFS_EXTENT_FLAG_DATA (1ULL << 0) -#define BTRFS_EXTENT_FLAG_TREE_BLOCK (1ULL << 1) - -/* following flags only apply to tree blocks */ - -/* use full backrefs for extent pointers in the block */ -#define BTRFS_BLOCK_FLAG_FULL_BACKREF (1ULL << 8) - -/* - * this flag is only used internally by scrub and may be changed at any time - * it is only declared here to avoid collisions - */ -#define BTRFS_EXTENT_FLAG_SUPER (1ULL << 48) - -struct btrfs_tree_block_info { - struct btrfs_disk_key key; - __u8 level; -} __attribute__ ((__packed__)); - -struct btrfs_extent_data_ref { - __le64 root; - __le64 objectid; - __le64 offset; - __le32 count; -} __attribute__ ((__packed__)); - -struct btrfs_shared_data_ref { - __le32 count; -} __attribute__ ((__packed__)); - -struct btrfs_extent_inline_ref { - __u8 type; - __le64 offset; -} __attribute__ ((__packed__)); - -/* old style backrefs item */ -struct btrfs_extent_ref_v0 { - __le64 root; - __le64 generation; - __le64 objectid; - __le32 count; -} __attribute__ ((__packed__)); - - -/* dev extents record free space on individual devices. The owner - * field points back to the chunk allocation mapping tree that allocated - * the extent. The chunk tree uuid field is a way to double check the owner - */ -struct btrfs_dev_extent { - __le64 chunk_tree; - __le64 chunk_objectid; - __le64 chunk_offset; - __le64 length; - __u8 chunk_tree_uuid[BTRFS_UUID_SIZE]; -} __attribute__ ((__packed__)); - -struct btrfs_inode_ref { - __le64 index; - __le16 name_len; - /* name goes here */ -} __attribute__ ((__packed__)); - -struct btrfs_inode_extref { - __le64 parent_objectid; - __le64 index; - __le16 name_len; - __u8 name[0]; - /* name goes here */ -} __attribute__ ((__packed__)); - -struct btrfs_timespec { - __le64 sec; - __le32 nsec; -} __attribute__ ((__packed__)); - -struct btrfs_inode_item { - /* nfs style generation number */ - __le64 generation; - /* transid that last touched this inode */ - __le64 transid; - __le64 size; - __le64 nbytes; - __le64 block_group; - __le32 nlink; - __le32 uid; - __le32 gid; - __le32 mode; - __le64 rdev; - __le64 flags; - - /* modification sequence number for NFS */ - __le64 sequence; - - /* - * a little future expansion, for more than this we can - * just grow the inode item and version it - */ - __le64 reserved[4]; - struct btrfs_timespec atime; - struct btrfs_timespec ctime; - struct btrfs_timespec mtime; - struct btrfs_timespec otime; -} __attribute__ ((__packed__)); - -struct btrfs_dir_log_item { - __le64 end; -} __attribute__ ((__packed__)); - -struct btrfs_dir_item { - struct btrfs_disk_key location; - __le64 transid; - __le16 data_len; - __le16 name_len; - __u8 type; -} __attribute__ ((__packed__)); - -#define BTRFS_ROOT_SUBVOL_RDONLY (1ULL << 0) - -/* - * Internal in-memory flag that a subvolume has been marked for deletion but - * still visible as a directory - */ -#define BTRFS_ROOT_SUBVOL_DEAD (1ULL << 48) - -struct btrfs_root_item { - struct btrfs_inode_item inode; - __le64 generation; - __le64 root_dirid; - __le64 bytenr; - __le64 byte_limit; - __le64 bytes_used; - __le64 last_snapshot; - __le64 flags; - __le32 refs; - struct btrfs_disk_key drop_progress; - __u8 drop_level; - __u8 level; - - /* - * The following fields appear after subvol_uuids+subvol_times - * were introduced. - */ - - /* - * This generation number is used to test if the new fields are valid - * and up to date while reading the root item. Every time the root item - * is written out, the "generation" field is copied into this field. If - * anyone ever mounted the fs with an older kernel, we will have - * mismatching generation values here and thus must invalidate the - * new fields. See btrfs_update_root and btrfs_find_last_root for - * details. - * the offset of generation_v2 is also used as the start for the memset - * when invalidating the fields. - */ - __le64 generation_v2; - __u8 uuid[BTRFS_UUID_SIZE]; - __u8 parent_uuid[BTRFS_UUID_SIZE]; - __u8 received_uuid[BTRFS_UUID_SIZE]; - __le64 ctransid; /* updated when an inode changes */ - __le64 otransid; /* trans when created */ - __le64 stransid; /* trans when sent. non-zero for received subvol */ - __le64 rtransid; /* trans when received. non-zero for received subvol */ - struct btrfs_timespec ctime; - struct btrfs_timespec otime; - struct btrfs_timespec stime; - struct btrfs_timespec rtime; - __le64 reserved[8]; /* for future */ -} __attribute__ ((__packed__)); - -/* - * this is used for both forward and backward root refs - */ -struct btrfs_root_ref { - __le64 dirid; - __le64 sequence; - __le16 name_len; -} __attribute__ ((__packed__)); - -struct btrfs_disk_balance_args { - /* - * profiles to operate on, single is denoted by - * BTRFS_AVAIL_ALLOC_BIT_SINGLE - */ - __le64 profiles; - - /* - * usage filter - * BTRFS_BALANCE_ARGS_USAGE with a single value means '0..N' - * BTRFS_BALANCE_ARGS_USAGE_RANGE - range syntax, min..max - */ - union { - __le64 usage; - struct { - __le32 usage_min; - __le32 usage_max; - }; - }; - - /* devid filter */ - __le64 devid; - - /* devid subset filter [pstart..pend) */ - __le64 pstart; - __le64 pend; - - /* btrfs virtual address space subset filter [vstart..vend) */ - __le64 vstart; - __le64 vend; - - /* - * profile to convert to, single is denoted by - * BTRFS_AVAIL_ALLOC_BIT_SINGLE - */ - __le64 target; - - /* BTRFS_BALANCE_ARGS_* */ - __le64 flags; - - /* - * BTRFS_BALANCE_ARGS_LIMIT with value 'limit' - * BTRFS_BALANCE_ARGS_LIMIT_RANGE - the extend version can use minimum - * and maximum - */ - union { - __le64 limit; - struct { - __le32 limit_min; - __le32 limit_max; - }; - }; - - /* - * Process chunks that cross stripes_min..stripes_max devices, - * BTRFS_BALANCE_ARGS_STRIPES_RANGE - */ - __le32 stripes_min; - __le32 stripes_max; - - __le64 unused[6]; -} __attribute__ ((__packed__)); - -/* - * store balance parameters to disk so that balance can be properly - * resumed after crash or unmount - */ -struct btrfs_balance_item { - /* BTRFS_BALANCE_* */ - __le64 flags; - - struct btrfs_disk_balance_args data; - struct btrfs_disk_balance_args meta; - struct btrfs_disk_balance_args sys; - - __le64 unused[4]; -} __attribute__ ((__packed__)); - -#define BTRFS_FILE_EXTENT_INLINE 0 -#define BTRFS_FILE_EXTENT_REG 1 -#define BTRFS_FILE_EXTENT_PREALLOC 2 - -struct btrfs_file_extent_item { - /* - * transaction id that created this extent - */ - __le64 generation; - /* - * max number of bytes to hold this extent in ram - * when we split a compressed extent we can't know how big - * each of the resulting pieces will be. So, this is - * an upper limit on the size of the extent in ram instead of - * an exact limit. - */ - __le64 ram_bytes; - - /* - * 32 bits for the various ways we might encode the data, - * including compression and encryption. If any of these - * are set to something a given disk format doesn't understand - * it is treated like an incompat flag for reading and writing, - * but not for stat. - */ - __u8 compression; - __u8 encryption; - __le16 other_encoding; /* spare for later use */ - - /* are we inline data or a real extent? */ - __u8 type; - - /* - * disk space consumed by the extent, checksum blocks are included - * in these numbers - * - * At this offset in the structure, the inline extent data start. - */ - __le64 disk_bytenr; - __le64 disk_num_bytes; - /* - * the logical offset in file blocks (no csums) - * this extent record is for. This allows a file extent to point - * into the middle of an existing extent on disk, sharing it - * between two snapshots (useful if some bytes in the middle of the - * extent have changed - */ - __le64 offset; - /* - * the logical number of file blocks (no csums included). This - * always reflects the size uncompressed and without encoding. - */ - __le64 num_bytes; - -} __attribute__ ((__packed__)); - -struct btrfs_csum_item { - __u8 csum; -} __attribute__ ((__packed__)); - -struct btrfs_dev_stats_item { - /* - * grow this item struct at the end for future enhancements and keep - * the existing values unchanged - */ - __le64 values[BTRFS_DEV_STAT_VALUES_MAX]; -} __attribute__ ((__packed__)); - -#define BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_ALWAYS 0 -#define BTRFS_DEV_REPLACE_ITEM_CONT_READING_FROM_SRCDEV_MODE_AVOID 1 -#define BTRFS_DEV_REPLACE_ITEM_STATE_NEVER_STARTED 0 -#define BTRFS_DEV_REPLACE_ITEM_STATE_STARTED 1 -#define BTRFS_DEV_REPLACE_ITEM_STATE_SUSPENDED 2 -#define BTRFS_DEV_REPLACE_ITEM_STATE_FINISHED 3 -#define BTRFS_DEV_REPLACE_ITEM_STATE_CANCELED 4 - -struct btrfs_dev_replace_item { - /* - * grow this item struct at the end for future enhancements and keep - * the existing values unchanged - */ - __le64 src_devid; - __le64 cursor_left; - __le64 cursor_right; - __le64 cont_reading_from_srcdev_mode; - - __le64 replace_state; - __le64 time_started; - __le64 time_stopped; - __le64 num_write_errors; - __le64 num_uncorrectable_read_errors; -} __attribute__ ((__packed__)); - -/* different types of block groups (and chunks) */ -#define BTRFS_BLOCK_GROUP_DATA (1ULL << 0) -#define BTRFS_BLOCK_GROUP_SYSTEM (1ULL << 1) -#define BTRFS_BLOCK_GROUP_METADATA (1ULL << 2) -#define BTRFS_BLOCK_GROUP_RAID0 (1ULL << 3) -#define BTRFS_BLOCK_GROUP_RAID1 (1ULL << 4) -#define BTRFS_BLOCK_GROUP_DUP (1ULL << 5) -#define BTRFS_BLOCK_GROUP_RAID10 (1ULL << 6) -#define BTRFS_BLOCK_GROUP_RAID5 (1ULL << 7) -#define BTRFS_BLOCK_GROUP_RAID6 (1ULL << 8) -#define BTRFS_BLOCK_GROUP_RESERVED (BTRFS_AVAIL_ALLOC_BIT_SINGLE | \ - BTRFS_SPACE_INFO_GLOBAL_RSV) - -enum btrfs_raid_types { - BTRFS_RAID_RAID10, - BTRFS_RAID_RAID1, - BTRFS_RAID_DUP, - BTRFS_RAID_RAID0, - BTRFS_RAID_SINGLE, - BTRFS_RAID_RAID5, - BTRFS_RAID_RAID6, - BTRFS_NR_RAID_TYPES -}; - -#define BTRFS_BLOCK_GROUP_TYPE_MASK (BTRFS_BLOCK_GROUP_DATA | \ - BTRFS_BLOCK_GROUP_SYSTEM | \ - BTRFS_BLOCK_GROUP_METADATA) - -#define BTRFS_BLOCK_GROUP_PROFILE_MASK (BTRFS_BLOCK_GROUP_RAID0 | \ - BTRFS_BLOCK_GROUP_RAID1 | \ - BTRFS_BLOCK_GROUP_RAID5 | \ - BTRFS_BLOCK_GROUP_RAID6 | \ - BTRFS_BLOCK_GROUP_DUP | \ - BTRFS_BLOCK_GROUP_RAID10) -#define BTRFS_BLOCK_GROUP_RAID56_MASK (BTRFS_BLOCK_GROUP_RAID5 | \ - BTRFS_BLOCK_GROUP_RAID6) - -/* - * We need a bit for restriper to be able to tell when chunks of type - * SINGLE are available. This "extended" profile format is used in - * fs_info->avail_*_alloc_bits (in-memory) and balance item fields - * (on-disk). The corresponding on-disk bit in chunk.type is reserved - * to avoid remappings between two formats in future. - */ -#define BTRFS_AVAIL_ALLOC_BIT_SINGLE (1ULL << 48) - -/* - * A fake block group type that is used to communicate global block reserve - * size to userspace via the SPACE_INFO ioctl. - */ -#define BTRFS_SPACE_INFO_GLOBAL_RSV (1ULL << 49) - -#define BTRFS_EXTENDED_PROFILE_MASK (BTRFS_BLOCK_GROUP_PROFILE_MASK | \ - BTRFS_AVAIL_ALLOC_BIT_SINGLE) - -static inline __u64 chunk_to_extended(__u64 flags) -{ - if ((flags & BTRFS_BLOCK_GROUP_PROFILE_MASK) == 0) - flags |= BTRFS_AVAIL_ALLOC_BIT_SINGLE; - - return flags; -} -static inline __u64 extended_to_chunk(__u64 flags) -{ - return flags & ~BTRFS_AVAIL_ALLOC_BIT_SINGLE; -} - -struct btrfs_block_group_item { - __le64 used; - __le64 chunk_objectid; - __le64 flags; -} __attribute__ ((__packed__)); - -struct btrfs_free_space_info { - __le32 extent_count; - __le32 flags; -} __attribute__ ((__packed__)); - -#define BTRFS_FREE_SPACE_USING_BITMAPS (1ULL << 0) - -#define BTRFS_QGROUP_LEVEL_SHIFT 48 -static inline __u64 btrfs_qgroup_level(__u64 qgroupid) -{ - return qgroupid >> BTRFS_QGROUP_LEVEL_SHIFT; -} - -/* - * is subvolume quota turned on? - */ -#define BTRFS_QGROUP_STATUS_FLAG_ON (1ULL << 0) -/* - * RESCAN is set during the initialization phase - */ -#define BTRFS_QGROUP_STATUS_FLAG_RESCAN (1ULL << 1) -/* - * Some qgroup entries are known to be out of date, - * either because the configuration has changed in a way that - * makes a rescan necessary, or because the fs has been mounted - * with a non-qgroup-aware version. - * Turning qouta off and on again makes it inconsistent, too. - */ -#define BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT (1ULL << 2) - -#define BTRFS_QGROUP_STATUS_VERSION 1 - -struct btrfs_qgroup_status_item { - __le64 version; - /* - * the generation is updated during every commit. As older - * versions of btrfs are not aware of qgroups, it will be - * possible to detect inconsistencies by checking the - * generation on mount time - */ - __le64 generation; - - /* flag definitions see above */ - __le64 flags; - - /* - * only used during scanning to record the progress - * of the scan. It contains a logical address - */ - __le64 rescan; -} __attribute__ ((__packed__)); - -struct btrfs_qgroup_info_item { - __le64 generation; - __le64 rfer; - __le64 rfer_cmpr; - __le64 excl; - __le64 excl_cmpr; -} __attribute__ ((__packed__)); - -struct btrfs_qgroup_limit_item { - /* - * only updated when any of the other values change - */ - __le64 flags; - __le64 max_rfer; - __le64 max_excl; - __le64 rsv_rfer; - __le64 rsv_excl; -} __attribute__ ((__packed__)); - -#endif /* _BTRFS_CTREE_H_ */ diff --git a/src/linux/include/uapi/linux/byteorder/big_endian.h b/src/linux/include/uapi/linux/byteorder/big_endian.h deleted file mode 100644 index cdab17a..0000000 --- a/src/linux/include/uapi/linux/byteorder/big_endian.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef _UAPI_LINUX_BYTEORDER_BIG_ENDIAN_H -#define _UAPI_LINUX_BYTEORDER_BIG_ENDIAN_H - -#ifndef __BIG_ENDIAN -#define __BIG_ENDIAN 4321 -#endif -#ifndef __BIG_ENDIAN_BITFIELD -#define __BIG_ENDIAN_BITFIELD -#endif - -#include -#include - -#define __constant_htonl(x) ((__force __be32)(__u32)(x)) -#define __constant_ntohl(x) ((__force __u32)(__be32)(x)) -#define __constant_htons(x) ((__force __be16)(__u16)(x)) -#define __constant_ntohs(x) ((__force __u16)(__be16)(x)) -#define __constant_cpu_to_le64(x) ((__force __le64)___constant_swab64((x))) -#define __constant_le64_to_cpu(x) ___constant_swab64((__force __u64)(__le64)(x)) -#define __constant_cpu_to_le32(x) ((__force __le32)___constant_swab32((x))) -#define __constant_le32_to_cpu(x) ___constant_swab32((__force __u32)(__le32)(x)) -#define __constant_cpu_to_le16(x) ((__force __le16)___constant_swab16((x))) -#define __constant_le16_to_cpu(x) ___constant_swab16((__force __u16)(__le16)(x)) -#define __constant_cpu_to_be64(x) ((__force __be64)(__u64)(x)) -#define __constant_be64_to_cpu(x) ((__force __u64)(__be64)(x)) -#define __constant_cpu_to_be32(x) ((__force __be32)(__u32)(x)) -#define __constant_be32_to_cpu(x) ((__force __u32)(__be32)(x)) -#define __constant_cpu_to_be16(x) ((__force __be16)(__u16)(x)) -#define __constant_be16_to_cpu(x) ((__force __u16)(__be16)(x)) -#define __cpu_to_le64(x) ((__force __le64)__swab64((x))) -#define __le64_to_cpu(x) __swab64((__force __u64)(__le64)(x)) -#define __cpu_to_le32(x) ((__force __le32)__swab32((x))) -#define __le32_to_cpu(x) __swab32((__force __u32)(__le32)(x)) -#define __cpu_to_le16(x) ((__force __le16)__swab16((x))) -#define __le16_to_cpu(x) __swab16((__force __u16)(__le16)(x)) -#define __cpu_to_be64(x) ((__force __be64)(__u64)(x)) -#define __be64_to_cpu(x) ((__force __u64)(__be64)(x)) -#define __cpu_to_be32(x) ((__force __be32)(__u32)(x)) -#define __be32_to_cpu(x) ((__force __u32)(__be32)(x)) -#define __cpu_to_be16(x) ((__force __be16)(__u16)(x)) -#define __be16_to_cpu(x) ((__force __u16)(__be16)(x)) - -static __always_inline __le64 __cpu_to_le64p(const __u64 *p) -{ - return (__force __le64)__swab64p(p); -} -static __always_inline __u64 __le64_to_cpup(const __le64 *p) -{ - return __swab64p((__u64 *)p); -} -static __always_inline __le32 __cpu_to_le32p(const __u32 *p) -{ - return (__force __le32)__swab32p(p); -} -static __always_inline __u32 __le32_to_cpup(const __le32 *p) -{ - return __swab32p((__u32 *)p); -} -static __always_inline __le16 __cpu_to_le16p(const __u16 *p) -{ - return (__force __le16)__swab16p(p); -} -static __always_inline __u16 __le16_to_cpup(const __le16 *p) -{ - return __swab16p((__u16 *)p); -} -static __always_inline __be64 __cpu_to_be64p(const __u64 *p) -{ - return (__force __be64)*p; -} -static __always_inline __u64 __be64_to_cpup(const __be64 *p) -{ - return (__force __u64)*p; -} -static __always_inline __be32 __cpu_to_be32p(const __u32 *p) -{ - return (__force __be32)*p; -} -static __always_inline __u32 __be32_to_cpup(const __be32 *p) -{ - return (__force __u32)*p; -} -static __always_inline __be16 __cpu_to_be16p(const __u16 *p) -{ - return (__force __be16)*p; -} -static __always_inline __u16 __be16_to_cpup(const __be16 *p) -{ - return (__force __u16)*p; -} -#define __cpu_to_le64s(x) __swab64s((x)) -#define __le64_to_cpus(x) __swab64s((x)) -#define __cpu_to_le32s(x) __swab32s((x)) -#define __le32_to_cpus(x) __swab32s((x)) -#define __cpu_to_le16s(x) __swab16s((x)) -#define __le16_to_cpus(x) __swab16s((x)) -#define __cpu_to_be64s(x) do { (void)(x); } while (0) -#define __be64_to_cpus(x) do { (void)(x); } while (0) -#define __cpu_to_be32s(x) do { (void)(x); } while (0) -#define __be32_to_cpus(x) do { (void)(x); } while (0) -#define __cpu_to_be16s(x) do { (void)(x); } while (0) -#define __be16_to_cpus(x) do { (void)(x); } while (0) - - -#endif /* _UAPI_LINUX_BYTEORDER_BIG_ENDIAN_H */ diff --git a/src/linux/include/uapi/linux/byteorder/little_endian.h b/src/linux/include/uapi/linux/byteorder/little_endian.h deleted file mode 100644 index 4b93f2b..0000000 --- a/src/linux/include/uapi/linux/byteorder/little_endian.h +++ /dev/null @@ -1,105 +0,0 @@ -#ifndef _UAPI_LINUX_BYTEORDER_LITTLE_ENDIAN_H -#define _UAPI_LINUX_BYTEORDER_LITTLE_ENDIAN_H - -#ifndef __LITTLE_ENDIAN -#define __LITTLE_ENDIAN 1234 -#endif -#ifndef __LITTLE_ENDIAN_BITFIELD -#define __LITTLE_ENDIAN_BITFIELD -#endif - -#include -#include - -#define __constant_htonl(x) ((__force __be32)___constant_swab32((x))) -#define __constant_ntohl(x) ___constant_swab32((__force __be32)(x)) -#define __constant_htons(x) ((__force __be16)___constant_swab16((x))) -#define __constant_ntohs(x) ___constant_swab16((__force __be16)(x)) -#define __constant_cpu_to_le64(x) ((__force __le64)(__u64)(x)) -#define __constant_le64_to_cpu(x) ((__force __u64)(__le64)(x)) -#define __constant_cpu_to_le32(x) ((__force __le32)(__u32)(x)) -#define __constant_le32_to_cpu(x) ((__force __u32)(__le32)(x)) -#define __constant_cpu_to_le16(x) ((__force __le16)(__u16)(x)) -#define __constant_le16_to_cpu(x) ((__force __u16)(__le16)(x)) -#define __constant_cpu_to_be64(x) ((__force __be64)___constant_swab64((x))) -#define __constant_be64_to_cpu(x) ___constant_swab64((__force __u64)(__be64)(x)) -#define __constant_cpu_to_be32(x) ((__force __be32)___constant_swab32((x))) -#define __constant_be32_to_cpu(x) ___constant_swab32((__force __u32)(__be32)(x)) -#define __constant_cpu_to_be16(x) ((__force __be16)___constant_swab16((x))) -#define __constant_be16_to_cpu(x) ___constant_swab16((__force __u16)(__be16)(x)) -#define __cpu_to_le64(x) ((__force __le64)(__u64)(x)) -#define __le64_to_cpu(x) ((__force __u64)(__le64)(x)) -#define __cpu_to_le32(x) ((__force __le32)(__u32)(x)) -#define __le32_to_cpu(x) ((__force __u32)(__le32)(x)) -#define __cpu_to_le16(x) ((__force __le16)(__u16)(x)) -#define __le16_to_cpu(x) ((__force __u16)(__le16)(x)) -#define __cpu_to_be64(x) ((__force __be64)__swab64((x))) -#define __be64_to_cpu(x) __swab64((__force __u64)(__be64)(x)) -#define __cpu_to_be32(x) ((__force __be32)__swab32((x))) -#define __be32_to_cpu(x) __swab32((__force __u32)(__be32)(x)) -#define __cpu_to_be16(x) ((__force __be16)__swab16((x))) -#define __be16_to_cpu(x) __swab16((__force __u16)(__be16)(x)) - -static __always_inline __le64 __cpu_to_le64p(const __u64 *p) -{ - return (__force __le64)*p; -} -static __always_inline __u64 __le64_to_cpup(const __le64 *p) -{ - return (__force __u64)*p; -} -static __always_inline __le32 __cpu_to_le32p(const __u32 *p) -{ - return (__force __le32)*p; -} -static __always_inline __u32 __le32_to_cpup(const __le32 *p) -{ - return (__force __u32)*p; -} -static __always_inline __le16 __cpu_to_le16p(const __u16 *p) -{ - return (__force __le16)*p; -} -static __always_inline __u16 __le16_to_cpup(const __le16 *p) -{ - return (__force __u16)*p; -} -static __always_inline __be64 __cpu_to_be64p(const __u64 *p) -{ - return (__force __be64)__swab64p(p); -} -static __always_inline __u64 __be64_to_cpup(const __be64 *p) -{ - return __swab64p((__u64 *)p); -} -static __always_inline __be32 __cpu_to_be32p(const __u32 *p) -{ - return (__force __be32)__swab32p(p); -} -static __always_inline __u32 __be32_to_cpup(const __be32 *p) -{ - return __swab32p((__u32 *)p); -} -static __always_inline __be16 __cpu_to_be16p(const __u16 *p) -{ - return (__force __be16)__swab16p(p); -} -static __always_inline __u16 __be16_to_cpup(const __be16 *p) -{ - return __swab16p((__u16 *)p); -} -#define __cpu_to_le64s(x) do { (void)(x); } while (0) -#define __le64_to_cpus(x) do { (void)(x); } while (0) -#define __cpu_to_le32s(x) do { (void)(x); } while (0) -#define __le32_to_cpus(x) do { (void)(x); } while (0) -#define __cpu_to_le16s(x) do { (void)(x); } while (0) -#define __le16_to_cpus(x) do { (void)(x); } while (0) -#define __cpu_to_be64s(x) __swab64s((x)) -#define __be64_to_cpus(x) __swab64s((x)) -#define __cpu_to_be32s(x) __swab32s((x)) -#define __be32_to_cpus(x) __swab32s((x)) -#define __cpu_to_be16s(x) __swab16s((x)) -#define __be16_to_cpus(x) __swab16s((x)) - - -#endif /* _UAPI_LINUX_BYTEORDER_LITTLE_ENDIAN_H */ diff --git a/src/linux/include/uapi/linux/capability.h b/src/linux/include/uapi/linux/capability.h deleted file mode 100644 index 49bc062..0000000 --- a/src/linux/include/uapi/linux/capability.h +++ /dev/null @@ -1,365 +0,0 @@ -/* - * This is - * - * Andrew G. Morgan - * Alexander Kjeldaas - * with help from Aleph1, Roland Buresund and Andrew Main. - * - * See here for the libcap library ("POSIX draft" compliance): - * - * ftp://www.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.6/ - */ - -#ifndef _UAPI_LINUX_CAPABILITY_H -#define _UAPI_LINUX_CAPABILITY_H - -#include - -/* User-level do most of the mapping between kernel and user - capabilities based on the version tag given by the kernel. The - kernel might be somewhat backwards compatible, but don't bet on - it. */ - -/* Note, cap_t, is defined by POSIX (draft) to be an "opaque" pointer to - a set of three capability sets. The transposition of 3*the - following structure to such a composite is better handled in a user - library since the draft standard requires the use of malloc/free - etc.. */ - -#define _LINUX_CAPABILITY_VERSION_1 0x19980330 -#define _LINUX_CAPABILITY_U32S_1 1 - -#define _LINUX_CAPABILITY_VERSION_2 0x20071026 /* deprecated - use v3 */ -#define _LINUX_CAPABILITY_U32S_2 2 - -#define _LINUX_CAPABILITY_VERSION_3 0x20080522 -#define _LINUX_CAPABILITY_U32S_3 2 - -typedef struct __user_cap_header_struct { - __u32 version; - int pid; -} __user *cap_user_header_t; - -typedef struct __user_cap_data_struct { - __u32 effective; - __u32 permitted; - __u32 inheritable; -} __user *cap_user_data_t; - - -#define VFS_CAP_REVISION_MASK 0xFF000000 -#define VFS_CAP_REVISION_SHIFT 24 -#define VFS_CAP_FLAGS_MASK ~VFS_CAP_REVISION_MASK -#define VFS_CAP_FLAGS_EFFECTIVE 0x000001 - -#define VFS_CAP_REVISION_1 0x01000000 -#define VFS_CAP_U32_1 1 -#define XATTR_CAPS_SZ_1 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_1)) - -#define VFS_CAP_REVISION_2 0x02000000 -#define VFS_CAP_U32_2 2 -#define XATTR_CAPS_SZ_2 (sizeof(__le32)*(1 + 2*VFS_CAP_U32_2)) - -#define XATTR_CAPS_SZ XATTR_CAPS_SZ_2 -#define VFS_CAP_U32 VFS_CAP_U32_2 -#define VFS_CAP_REVISION VFS_CAP_REVISION_2 - -struct vfs_cap_data { - __le32 magic_etc; /* Little endian */ - struct { - __le32 permitted; /* Little endian */ - __le32 inheritable; /* Little endian */ - } data[VFS_CAP_U32]; -}; - -#ifndef __KERNEL__ - -/* - * Backwardly compatible definition for source code - trapped in a - * 32-bit world. If you find you need this, please consider using - * libcap to untrap yourself... - */ -#define _LINUX_CAPABILITY_VERSION _LINUX_CAPABILITY_VERSION_1 -#define _LINUX_CAPABILITY_U32S _LINUX_CAPABILITY_U32S_1 - -#endif - - -/** - ** POSIX-draft defined capabilities. - **/ - -/* In a system with the [_POSIX_CHOWN_RESTRICTED] option defined, this - overrides the restriction of changing file ownership and group - ownership. */ - -#define CAP_CHOWN 0 - -/* Override all DAC access, including ACL execute access if - [_POSIX_ACL] is defined. Excluding DAC access covered by - CAP_LINUX_IMMUTABLE. */ - -#define CAP_DAC_OVERRIDE 1 - -/* Overrides all DAC restrictions regarding read and search on files - and directories, including ACL restrictions if [_POSIX_ACL] is - defined. Excluding DAC access covered by CAP_LINUX_IMMUTABLE. */ - -#define CAP_DAC_READ_SEARCH 2 - -/* Overrides all restrictions about allowed operations on files, where - file owner ID must be equal to the user ID, except where CAP_FSETID - is applicable. It doesn't override MAC and DAC restrictions. */ - -#define CAP_FOWNER 3 - -/* Overrides the following restrictions that the effective user ID - shall match the file owner ID when setting the S_ISUID and S_ISGID - bits on that file; that the effective group ID (or one of the - supplementary group IDs) shall match the file owner ID when setting - the S_ISGID bit on that file; that the S_ISUID and S_ISGID bits are - cleared on successful return from chown(2) (not implemented). */ - -#define CAP_FSETID 4 - -/* Overrides the restriction that the real or effective user ID of a - process sending a signal must match the real or effective user ID - of the process receiving the signal. */ - -#define CAP_KILL 5 - -/* Allows setgid(2) manipulation */ -/* Allows setgroups(2) */ -/* Allows forged gids on socket credentials passing. */ - -#define CAP_SETGID 6 - -/* Allows set*uid(2) manipulation (including fsuid). */ -/* Allows forged pids on socket credentials passing. */ - -#define CAP_SETUID 7 - - -/** - ** Linux-specific capabilities - **/ - -/* Without VFS support for capabilities: - * Transfer any capability in your permitted set to any pid, - * remove any capability in your permitted set from any pid - * With VFS support for capabilities (neither of above, but) - * Add any capability from current's capability bounding set - * to the current process' inheritable set - * Allow taking bits out of capability bounding set - * Allow modification of the securebits for a process - */ - -#define CAP_SETPCAP 8 - -/* Allow modification of S_IMMUTABLE and S_APPEND file attributes */ - -#define CAP_LINUX_IMMUTABLE 9 - -/* Allows binding to TCP/UDP sockets below 1024 */ -/* Allows binding to ATM VCIs below 32 */ - -#define CAP_NET_BIND_SERVICE 10 - -/* Allow broadcasting, listen to multicast */ - -#define CAP_NET_BROADCAST 11 - -/* Allow interface configuration */ -/* Allow administration of IP firewall, masquerading and accounting */ -/* Allow setting debug option on sockets */ -/* Allow modification of routing tables */ -/* Allow setting arbitrary process / process group ownership on - sockets */ -/* Allow binding to any address for transparent proxying (also via NET_RAW) */ -/* Allow setting TOS (type of service) */ -/* Allow setting promiscuous mode */ -/* Allow clearing driver statistics */ -/* Allow multicasting */ -/* Allow read/write of device-specific registers */ -/* Allow activation of ATM control sockets */ - -#define CAP_NET_ADMIN 12 - -/* Allow use of RAW sockets */ -/* Allow use of PACKET sockets */ -/* Allow binding to any address for transparent proxying (also via NET_ADMIN) */ - -#define CAP_NET_RAW 13 - -/* Allow locking of shared memory segments */ -/* Allow mlock and mlockall (which doesn't really have anything to do - with IPC) */ - -#define CAP_IPC_LOCK 14 - -/* Override IPC ownership checks */ - -#define CAP_IPC_OWNER 15 - -/* Insert and remove kernel modules - modify kernel without limit */ -#define CAP_SYS_MODULE 16 - -/* Allow ioperm/iopl access */ -/* Allow sending USB messages to any device via /proc/bus/usb */ - -#define CAP_SYS_RAWIO 17 - -/* Allow use of chroot() */ - -#define CAP_SYS_CHROOT 18 - -/* Allow ptrace() of any process */ - -#define CAP_SYS_PTRACE 19 - -/* Allow configuration of process accounting */ - -#define CAP_SYS_PACCT 20 - -/* Allow configuration of the secure attention key */ -/* Allow administration of the random device */ -/* Allow examination and configuration of disk quotas */ -/* Allow setting the domainname */ -/* Allow setting the hostname */ -/* Allow calling bdflush() */ -/* Allow mount() and umount(), setting up new smb connection */ -/* Allow some autofs root ioctls */ -/* Allow nfsservctl */ -/* Allow VM86_REQUEST_IRQ */ -/* Allow to read/write pci config on alpha */ -/* Allow irix_prctl on mips (setstacksize) */ -/* Allow flushing all cache on m68k (sys_cacheflush) */ -/* Allow removing semaphores */ -/* Used instead of CAP_CHOWN to "chown" IPC message queues, semaphores - and shared memory */ -/* Allow locking/unlocking of shared memory segment */ -/* Allow turning swap on/off */ -/* Allow forged pids on socket credentials passing */ -/* Allow setting readahead and flushing buffers on block devices */ -/* Allow setting geometry in floppy driver */ -/* Allow turning DMA on/off in xd driver */ -/* Allow administration of md devices (mostly the above, but some - extra ioctls) */ -/* Allow tuning the ide driver */ -/* Allow access to the nvram device */ -/* Allow administration of apm_bios, serial and bttv (TV) device */ -/* Allow manufacturer commands in isdn CAPI support driver */ -/* Allow reading non-standardized portions of pci configuration space */ -/* Allow DDI debug ioctl on sbpcd driver */ -/* Allow setting up serial ports */ -/* Allow sending raw qic-117 commands */ -/* Allow enabling/disabling tagged queuing on SCSI controllers and sending - arbitrary SCSI commands */ -/* Allow setting encryption key on loopback filesystem */ -/* Allow setting zone reclaim policy */ - -#define CAP_SYS_ADMIN 21 - -/* Allow use of reboot() */ - -#define CAP_SYS_BOOT 22 - -/* Allow raising priority and setting priority on other (different - UID) processes */ -/* Allow use of FIFO and round-robin (realtime) scheduling on own - processes and setting the scheduling algorithm used by another - process. */ -/* Allow setting cpu affinity on other processes */ - -#define CAP_SYS_NICE 23 - -/* Override resource limits. Set resource limits. */ -/* Override quota limits. */ -/* Override reserved space on ext2 filesystem */ -/* Modify data journaling mode on ext3 filesystem (uses journaling - resources) */ -/* NOTE: ext2 honors fsuid when checking for resource overrides, so - you can override using fsuid too */ -/* Override size restrictions on IPC message queues */ -/* Allow more than 64hz interrupts from the real-time clock */ -/* Override max number of consoles on console allocation */ -/* Override max number of keymaps */ - -#define CAP_SYS_RESOURCE 24 - -/* Allow manipulation of system clock */ -/* Allow irix_stime on mips */ -/* Allow setting the real-time clock */ - -#define CAP_SYS_TIME 25 - -/* Allow configuration of tty devices */ -/* Allow vhangup() of tty */ - -#define CAP_SYS_TTY_CONFIG 26 - -/* Allow the privileged aspects of mknod() */ - -#define CAP_MKNOD 27 - -/* Allow taking of leases on files */ - -#define CAP_LEASE 28 - -/* Allow writing the audit log via unicast netlink socket */ - -#define CAP_AUDIT_WRITE 29 - -/* Allow configuration of audit via unicast netlink socket */ - -#define CAP_AUDIT_CONTROL 30 - -#define CAP_SETFCAP 31 - -/* Override MAC access. - The base kernel enforces no MAC policy. - An LSM may enforce a MAC policy, and if it does and it chooses - to implement capability based overrides of that policy, this is - the capability it should use to do so. */ - -#define CAP_MAC_OVERRIDE 32 - -/* Allow MAC configuration or state changes. - The base kernel requires no MAC configuration. - An LSM may enforce a MAC policy, and if it does and it chooses - to implement capability based checks on modifications to that - policy or the data required to maintain it, this is the - capability it should use to do so. */ - -#define CAP_MAC_ADMIN 33 - -/* Allow configuring the kernel's syslog (printk behaviour) */ - -#define CAP_SYSLOG 34 - -/* Allow triggering something that will wake the system */ - -#define CAP_WAKE_ALARM 35 - -/* Allow preventing system suspends */ - -#define CAP_BLOCK_SUSPEND 36 - -/* Allow reading the audit log via multicast netlink socket */ - -#define CAP_AUDIT_READ 37 - - -#define CAP_LAST_CAP CAP_AUDIT_READ - -#define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP) - -/* - * Bit location of each capability (used by user-space library and kernel) - */ - -#define CAP_TO_INDEX(x) ((x) >> 5) /* 1 << 5 == bits in __u32 */ -#define CAP_TO_MASK(x) (1 << ((x) & 31)) /* mask for indexed __u32 */ - - -#endif /* _UAPI_LINUX_CAPABILITY_H */ diff --git a/src/linux/include/uapi/linux/cdrom.h b/src/linux/include/uapi/linux/cdrom.h deleted file mode 100644 index bd17ad5..0000000 --- a/src/linux/include/uapi/linux/cdrom.h +++ /dev/null @@ -1,946 +0,0 @@ -/* - * -- - * General header file for linux CD-ROM drivers - * Copyright (C) 1992 David Giller, rafetmad@oxy.edu - * 1994, 1995 Eberhard Mönkeberg, emoenke@gwdg.de - * 1996 David van Leeuwen, david@tm.tno.nl - * 1997, 1998 Erik Andersen, andersee@debian.org - * 1998-2002 Jens Axboe, axboe@suse.de - */ - -#ifndef _UAPI_LINUX_CDROM_H -#define _UAPI_LINUX_CDROM_H - -#include -#include - -/******************************************************* - * As of Linux 2.1.x, all Linux CD-ROM application programs will use this - * (and only this) include file. It is my hope to provide Linux with - * a uniform interface between software accessing CD-ROMs and the various - * device drivers that actually talk to the drives. There may still be - * 23 different kinds of strange CD-ROM drives, but at least there will - * now be one, and only one, Linux CD-ROM interface. - * - * Additionally, as of Linux 2.1.x, all Linux application programs - * should use the O_NONBLOCK option when opening a CD-ROM device - * for subsequent ioctl commands. This allows for neat system errors - * like "No medium found" or "Wrong medium type" upon attempting to - * mount or play an empty slot, mount an audio disc, or play a data disc. - * Generally, changing an application program to support O_NONBLOCK - * is as easy as the following: - * - drive = open("/dev/cdrom", O_RDONLY); - * + drive = open("/dev/cdrom", O_RDONLY | O_NONBLOCK); - * It is worth the small change. - * - * Patches for many common CD programs (provided by David A. van Leeuwen) - * can be found at: ftp://ftp.gwdg.de/pub/linux/cdrom/drivers/cm206/ - * - *******************************************************/ - -/* When a driver supports a certain function, but the cdrom drive we are - * using doesn't, we will return the error EDRIVE_CANT_DO_THIS. We will - * borrow the "Operation not supported" error from the network folks to - * accomplish this. Maybe someday we will get a more targeted error code, - * but this will do for now... */ -#define EDRIVE_CANT_DO_THIS EOPNOTSUPP - -/******************************************************* - * The CD-ROM IOCTL commands -- these should be supported by - * all the various cdrom drivers. For the CD-ROM ioctls, we - * will commandeer byte 0x53, or 'S'. - *******************************************************/ -#define CDROMPAUSE 0x5301 /* Pause Audio Operation */ -#define CDROMRESUME 0x5302 /* Resume paused Audio Operation */ -#define CDROMPLAYMSF 0x5303 /* Play Audio MSF (struct cdrom_msf) */ -#define CDROMPLAYTRKIND 0x5304 /* Play Audio Track/index - (struct cdrom_ti) */ -#define CDROMREADTOCHDR 0x5305 /* Read TOC header - (struct cdrom_tochdr) */ -#define CDROMREADTOCENTRY 0x5306 /* Read TOC entry - (struct cdrom_tocentry) */ -#define CDROMSTOP 0x5307 /* Stop the cdrom drive */ -#define CDROMSTART 0x5308 /* Start the cdrom drive */ -#define CDROMEJECT 0x5309 /* Ejects the cdrom media */ -#define CDROMVOLCTRL 0x530a /* Control output volume - (struct cdrom_volctrl) */ -#define CDROMSUBCHNL 0x530b /* Read subchannel data - (struct cdrom_subchnl) */ -#define CDROMREADMODE2 0x530c /* Read CDROM mode 2 data (2336 Bytes) - (struct cdrom_read) */ -#define CDROMREADMODE1 0x530d /* Read CDROM mode 1 data (2048 Bytes) - (struct cdrom_read) */ -#define CDROMREADAUDIO 0x530e /* (struct cdrom_read_audio) */ -#define CDROMEJECT_SW 0x530f /* enable(1)/disable(0) auto-ejecting */ -#define CDROMMULTISESSION 0x5310 /* Obtain the start-of-last-session - address of multi session disks - (struct cdrom_multisession) */ -#define CDROM_GET_MCN 0x5311 /* Obtain the "Universal Product Code" - if available (struct cdrom_mcn) */ -#define CDROM_GET_UPC CDROM_GET_MCN /* This one is deprecated, - but here anyway for compatibility */ -#define CDROMRESET 0x5312 /* hard-reset the drive */ -#define CDROMVOLREAD 0x5313 /* Get the drive's volume setting - (struct cdrom_volctrl) */ -#define CDROMREADRAW 0x5314 /* read data in raw mode (2352 Bytes) - (struct cdrom_read) */ -/* - * These ioctls are used only used in aztcd.c and optcd.c - */ -#define CDROMREADCOOKED 0x5315 /* read data in cooked mode */ -#define CDROMSEEK 0x5316 /* seek msf address */ - -/* - * This ioctl is only used by the scsi-cd driver. - It is for playing audio in logical block addressing mode. - */ -#define CDROMPLAYBLK 0x5317 /* (struct cdrom_blk) */ - -/* - * These ioctls are only used in optcd.c - */ -#define CDROMREADALL 0x5318 /* read all 2646 bytes */ - -/* - * These ioctls are (now) only in ide-cd.c for controlling - * drive spindown time. They should be implemented in the - * Uniform driver, via generic packet commands, GPCMD_MODE_SELECT_10, - * GPCMD_MODE_SENSE_10 and the GPMODE_POWER_PAGE... - * -Erik - */ -#define CDROMGETSPINDOWN 0x531d -#define CDROMSETSPINDOWN 0x531e - -/* - * These ioctls are implemented through the uniform CD-ROM driver - * They _will_ be adopted by all CD-ROM drivers, when all the CD-ROM - * drivers are eventually ported to the uniform CD-ROM driver interface. - */ -#define CDROMCLOSETRAY 0x5319 /* pendant of CDROMEJECT */ -#define CDROM_SET_OPTIONS 0x5320 /* Set behavior options */ -#define CDROM_CLEAR_OPTIONS 0x5321 /* Clear behavior options */ -#define CDROM_SELECT_SPEED 0x5322 /* Set the CD-ROM speed */ -#define CDROM_SELECT_DISC 0x5323 /* Select disc (for juke-boxes) */ -#define CDROM_MEDIA_CHANGED 0x5325 /* Check is media changed */ -#define CDROM_DRIVE_STATUS 0x5326 /* Get tray position, etc. */ -#define CDROM_DISC_STATUS 0x5327 /* Get disc type, etc. */ -#define CDROM_CHANGER_NSLOTS 0x5328 /* Get number of slots */ -#define CDROM_LOCKDOOR 0x5329 /* lock or unlock door */ -#define CDROM_DEBUG 0x5330 /* Turn debug messages on/off */ -#define CDROM_GET_CAPABILITY 0x5331 /* get capabilities */ - -/* Note that scsi/scsi_ioctl.h also uses 0x5382 - 0x5386. - * Future CDROM ioctls should be kept below 0x537F - */ - -/* This ioctl is only used by sbpcd at the moment */ -#define CDROMAUDIOBUFSIZ 0x5382 /* set the audio buffer size */ - /* conflict with SCSI_IOCTL_GET_IDLUN */ - -/* DVD-ROM Specific ioctls */ -#define DVD_READ_STRUCT 0x5390 /* Read structure */ -#define DVD_WRITE_STRUCT 0x5391 /* Write structure */ -#define DVD_AUTH 0x5392 /* Authentication */ - -#define CDROM_SEND_PACKET 0x5393 /* send a packet to the drive */ -#define CDROM_NEXT_WRITABLE 0x5394 /* get next writable block */ -#define CDROM_LAST_WRITTEN 0x5395 /* get last block written on disc */ - -/******************************************************* - * CDROM IOCTL structures - *******************************************************/ - -/* Address in MSF format */ -struct cdrom_msf0 -{ - __u8 minute; - __u8 second; - __u8 frame; -}; - -/* Address in either MSF or logical format */ -union cdrom_addr -{ - struct cdrom_msf0 msf; - int lba; -}; - -/* This struct is used by the CDROMPLAYMSF ioctl */ -struct cdrom_msf -{ - __u8 cdmsf_min0; /* start minute */ - __u8 cdmsf_sec0; /* start second */ - __u8 cdmsf_frame0; /* start frame */ - __u8 cdmsf_min1; /* end minute */ - __u8 cdmsf_sec1; /* end second */ - __u8 cdmsf_frame1; /* end frame */ -}; - -/* This struct is used by the CDROMPLAYTRKIND ioctl */ -struct cdrom_ti -{ - __u8 cdti_trk0; /* start track */ - __u8 cdti_ind0; /* start index */ - __u8 cdti_trk1; /* end track */ - __u8 cdti_ind1; /* end index */ -}; - -/* This struct is used by the CDROMREADTOCHDR ioctl */ -struct cdrom_tochdr -{ - __u8 cdth_trk0; /* start track */ - __u8 cdth_trk1; /* end track */ -}; - -/* This struct is used by the CDROMVOLCTRL and CDROMVOLREAD ioctls */ -struct cdrom_volctrl -{ - __u8 channel0; - __u8 channel1; - __u8 channel2; - __u8 channel3; -}; - -/* This struct is used by the CDROMSUBCHNL ioctl */ -struct cdrom_subchnl -{ - __u8 cdsc_format; - __u8 cdsc_audiostatus; - __u8 cdsc_adr: 4; - __u8 cdsc_ctrl: 4; - __u8 cdsc_trk; - __u8 cdsc_ind; - union cdrom_addr cdsc_absaddr; - union cdrom_addr cdsc_reladdr; -}; - - -/* This struct is used by the CDROMREADTOCENTRY ioctl */ -struct cdrom_tocentry -{ - __u8 cdte_track; - __u8 cdte_adr :4; - __u8 cdte_ctrl :4; - __u8 cdte_format; - union cdrom_addr cdte_addr; - __u8 cdte_datamode; -}; - -/* This struct is used by the CDROMREADMODE1, and CDROMREADMODE2 ioctls */ -struct cdrom_read -{ - int cdread_lba; - char *cdread_bufaddr; - int cdread_buflen; -}; - -/* This struct is used by the CDROMREADAUDIO ioctl */ -struct cdrom_read_audio -{ - union cdrom_addr addr; /* frame address */ - __u8 addr_format; /* CDROM_LBA or CDROM_MSF */ - int nframes; /* number of 2352-byte-frames to read at once */ - __u8 __user *buf; /* frame buffer (size: nframes*2352 bytes) */ -}; - -/* This struct is used with the CDROMMULTISESSION ioctl */ -struct cdrom_multisession -{ - union cdrom_addr addr; /* frame address: start-of-last-session - (not the new "frame 16"!). Only valid - if the "xa_flag" is true. */ - __u8 xa_flag; /* 1: "is XA disk" */ - __u8 addr_format; /* CDROM_LBA or CDROM_MSF */ -}; - -/* This struct is used with the CDROM_GET_MCN ioctl. - * Very few audio discs actually have Universal Product Code information, - * which should just be the Medium Catalog Number on the box. Also note - * that the way the codeis written on CD is _not_ uniform across all discs! - */ -struct cdrom_mcn -{ - __u8 medium_catalog_number[14]; /* 13 ASCII digits, null-terminated */ -}; - -/* This is used by the CDROMPLAYBLK ioctl */ -struct cdrom_blk -{ - unsigned from; - unsigned short len; -}; - -#define CDROM_PACKET_SIZE 12 - -#define CGC_DATA_UNKNOWN 0 -#define CGC_DATA_WRITE 1 -#define CGC_DATA_READ 2 -#define CGC_DATA_NONE 3 - -/* for CDROM_PACKET_COMMAND ioctl */ -struct cdrom_generic_command -{ - unsigned char cmd[CDROM_PACKET_SIZE]; - unsigned char __user *buffer; - unsigned int buflen; - int stat; - struct request_sense __user *sense; - unsigned char data_direction; - int quiet; - int timeout; - void __user *reserved[1]; /* unused, actually */ -}; - -/* - * A CD-ROM physical sector size is 2048, 2052, 2056, 2324, 2332, 2336, - * 2340, or 2352 bytes long. - -* Sector types of the standard CD-ROM data formats: - * - * format sector type user data size (bytes) - * ----------------------------------------------------------------------------- - * 1 (Red Book) CD-DA 2352 (CD_FRAMESIZE_RAW) - * 2 (Yellow Book) Mode1 Form1 2048 (CD_FRAMESIZE) - * 3 (Yellow Book) Mode1 Form2 2336 (CD_FRAMESIZE_RAW0) - * 4 (Green Book) Mode2 Form1 2048 (CD_FRAMESIZE) - * 5 (Green Book) Mode2 Form2 2328 (2324+4 spare bytes) - * - * - * The layout of the standard CD-ROM data formats: - * ----------------------------------------------------------------------------- - * - audio (red): | audio_sample_bytes | - * | 2352 | - * - * - data (yellow, mode1): | sync - head - data - EDC - zero - ECC | - * | 12 - 4 - 2048 - 4 - 8 - 276 | - * - * - data (yellow, mode2): | sync - head - data | - * | 12 - 4 - 2336 | - * - * - XA data (green, mode2 form1): | sync - head - sub - data - EDC - ECC | - * | 12 - 4 - 8 - 2048 - 4 - 276 | - * - * - XA data (green, mode2 form2): | sync - head - sub - data - Spare | - * | 12 - 4 - 8 - 2324 - 4 | - * - */ - -/* Some generally useful CD-ROM information -- mostly based on the above */ -#define CD_MINS 74 /* max. minutes per CD, not really a limit */ -#define CD_SECS 60 /* seconds per minute */ -#define CD_FRAMES 75 /* frames per second */ -#define CD_SYNC_SIZE 12 /* 12 sync bytes per raw data frame */ -#define CD_MSF_OFFSET 150 /* MSF numbering offset of first frame */ -#define CD_CHUNK_SIZE 24 /* lowest-level "data bytes piece" */ -#define CD_NUM_OF_CHUNKS 98 /* chunks per frame */ -#define CD_FRAMESIZE_SUB 96 /* subchannel data "frame" size */ -#define CD_HEAD_SIZE 4 /* header (address) bytes per raw data frame */ -#define CD_SUBHEAD_SIZE 8 /* subheader bytes per raw XA data frame */ -#define CD_EDC_SIZE 4 /* bytes EDC per most raw data frame types */ -#define CD_ZERO_SIZE 8 /* bytes zero per yellow book mode 1 frame */ -#define CD_ECC_SIZE 276 /* bytes ECC per most raw data frame types */ -#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ -#define CD_FRAMESIZE_RAW 2352 /* bytes per frame, "raw" mode */ -#define CD_FRAMESIZE_RAWER 2646 /* The maximum possible returned bytes */ -/* most drives don't deliver everything: */ -#define CD_FRAMESIZE_RAW1 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE) /*2340*/ -#define CD_FRAMESIZE_RAW0 (CD_FRAMESIZE_RAW-CD_SYNC_SIZE-CD_HEAD_SIZE) /*2336*/ - -#define CD_XA_HEAD (CD_HEAD_SIZE+CD_SUBHEAD_SIZE) /* "before data" part of raw XA frame */ -#define CD_XA_TAIL (CD_EDC_SIZE+CD_ECC_SIZE) /* "after data" part of raw XA frame */ -#define CD_XA_SYNC_HEAD (CD_SYNC_SIZE+CD_XA_HEAD) /* sync bytes + header of XA frame */ - -/* CD-ROM address types (cdrom_tocentry.cdte_format) */ -#define CDROM_LBA 0x01 /* "logical block": first frame is #0 */ -#define CDROM_MSF 0x02 /* "minute-second-frame": binary, not bcd here! */ - -/* bit to tell whether track is data or audio (cdrom_tocentry.cdte_ctrl) */ -#define CDROM_DATA_TRACK 0x04 - -/* The leadout track is always 0xAA, regardless of # of tracks on disc */ -#define CDROM_LEADOUT 0xAA - -/* audio states (from SCSI-2, but seen with other drives, too) */ -#define CDROM_AUDIO_INVALID 0x00 /* audio status not supported */ -#define CDROM_AUDIO_PLAY 0x11 /* audio play operation in progress */ -#define CDROM_AUDIO_PAUSED 0x12 /* audio play operation paused */ -#define CDROM_AUDIO_COMPLETED 0x13 /* audio play successfully completed */ -#define CDROM_AUDIO_ERROR 0x14 /* audio play stopped due to error */ -#define CDROM_AUDIO_NO_STATUS 0x15 /* no current audio status to return */ - -/* capability flags used with the uniform CD-ROM driver */ -#define CDC_CLOSE_TRAY 0x1 /* caddy systems _can't_ close */ -#define CDC_OPEN_TRAY 0x2 /* but _can_ eject. */ -#define CDC_LOCK 0x4 /* disable manual eject */ -#define CDC_SELECT_SPEED 0x8 /* programmable speed */ -#define CDC_SELECT_DISC 0x10 /* select disc from juke-box */ -#define CDC_MULTI_SESSION 0x20 /* read sessions>1 */ -#define CDC_MCN 0x40 /* Medium Catalog Number */ -#define CDC_MEDIA_CHANGED 0x80 /* media changed */ -#define CDC_PLAY_AUDIO 0x100 /* audio functions */ -#define CDC_RESET 0x200 /* hard reset device */ -#define CDC_DRIVE_STATUS 0x800 /* driver implements drive status */ -#define CDC_GENERIC_PACKET 0x1000 /* driver implements generic packets */ -#define CDC_CD_R 0x2000 /* drive is a CD-R */ -#define CDC_CD_RW 0x4000 /* drive is a CD-RW */ -#define CDC_DVD 0x8000 /* drive is a DVD */ -#define CDC_DVD_R 0x10000 /* drive can write DVD-R */ -#define CDC_DVD_RAM 0x20000 /* drive can write DVD-RAM */ -#define CDC_MO_DRIVE 0x40000 /* drive is an MO device */ -#define CDC_MRW 0x80000 /* drive can read MRW */ -#define CDC_MRW_W 0x100000 /* drive can write MRW */ -#define CDC_RAM 0x200000 /* ok to open for WRITE */ - -/* drive status possibilities returned by CDROM_DRIVE_STATUS ioctl */ -#define CDS_NO_INFO 0 /* if not implemented */ -#define CDS_NO_DISC 1 -#define CDS_TRAY_OPEN 2 -#define CDS_DRIVE_NOT_READY 3 -#define CDS_DISC_OK 4 - -/* return values for the CDROM_DISC_STATUS ioctl */ -/* can also return CDS_NO_[INFO|DISC], from above */ -#define CDS_AUDIO 100 -#define CDS_DATA_1 101 -#define CDS_DATA_2 102 -#define CDS_XA_2_1 103 -#define CDS_XA_2_2 104 -#define CDS_MIXED 105 - -/* User-configurable behavior options for the uniform CD-ROM driver */ -#define CDO_AUTO_CLOSE 0x1 /* close tray on first open() */ -#define CDO_AUTO_EJECT 0x2 /* open tray on last release() */ -#define CDO_USE_FFLAGS 0x4 /* use O_NONBLOCK information on open */ -#define CDO_LOCK 0x8 /* lock tray on open files */ -#define CDO_CHECK_TYPE 0x10 /* check type on open for data */ - -/* Special codes used when specifying changer slots. */ -#define CDSL_NONE (INT_MAX-1) -#define CDSL_CURRENT INT_MAX - -/* For partition based multisession access. IDE can handle 64 partitions - * per drive - SCSI CD-ROM's use minors to differentiate between the - * various drives, so we can't do multisessions the same way there. - * Use the -o session=x option to mount on them. - */ -#define CD_PART_MAX 64 -#define CD_PART_MASK (CD_PART_MAX - 1) - -/********************************************************************* - * Generic Packet commands, MMC commands, and such - *********************************************************************/ - - /* The generic packet command opcodes for CD/DVD Logical Units, - * From Table 57 of the SFF8090 Ver. 3 (Mt. Fuji) draft standard. */ -#define GPCMD_BLANK 0xa1 -#define GPCMD_CLOSE_TRACK 0x5b -#define GPCMD_FLUSH_CACHE 0x35 -#define GPCMD_FORMAT_UNIT 0x04 -#define GPCMD_GET_CONFIGURATION 0x46 -#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a -#define GPCMD_GET_PERFORMANCE 0xac -#define GPCMD_INQUIRY 0x12 -#define GPCMD_LOAD_UNLOAD 0xa6 -#define GPCMD_MECHANISM_STATUS 0xbd -#define GPCMD_MODE_SELECT_10 0x55 -#define GPCMD_MODE_SENSE_10 0x5a -#define GPCMD_PAUSE_RESUME 0x4b -#define GPCMD_PLAY_AUDIO_10 0x45 -#define GPCMD_PLAY_AUDIO_MSF 0x47 -#define GPCMD_PLAY_AUDIO_TI 0x48 -#define GPCMD_PLAY_CD 0xbc -#define GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1e -#define GPCMD_READ_10 0x28 -#define GPCMD_READ_12 0xa8 -#define GPCMD_READ_BUFFER 0x3c -#define GPCMD_READ_BUFFER_CAPACITY 0x5c -#define GPCMD_READ_CDVD_CAPACITY 0x25 -#define GPCMD_READ_CD 0xbe -#define GPCMD_READ_CD_MSF 0xb9 -#define GPCMD_READ_DISC_INFO 0x51 -#define GPCMD_READ_DVD_STRUCTURE 0xad -#define GPCMD_READ_FORMAT_CAPACITIES 0x23 -#define GPCMD_READ_HEADER 0x44 -#define GPCMD_READ_TRACK_RZONE_INFO 0x52 -#define GPCMD_READ_SUBCHANNEL 0x42 -#define GPCMD_READ_TOC_PMA_ATIP 0x43 -#define GPCMD_REPAIR_RZONE_TRACK 0x58 -#define GPCMD_REPORT_KEY 0xa4 -#define GPCMD_REQUEST_SENSE 0x03 -#define GPCMD_RESERVE_RZONE_TRACK 0x53 -#define GPCMD_SEND_CUE_SHEET 0x5d -#define GPCMD_SCAN 0xba -#define GPCMD_SEEK 0x2b -#define GPCMD_SEND_DVD_STRUCTURE 0xbf -#define GPCMD_SEND_EVENT 0xa2 -#define GPCMD_SEND_KEY 0xa3 -#define GPCMD_SEND_OPC 0x54 -#define GPCMD_SET_READ_AHEAD 0xa7 -#define GPCMD_SET_STREAMING 0xb6 -#define GPCMD_START_STOP_UNIT 0x1b -#define GPCMD_STOP_PLAY_SCAN 0x4e -#define GPCMD_TEST_UNIT_READY 0x00 -#define GPCMD_VERIFY_10 0x2f -#define GPCMD_WRITE_10 0x2a -#define GPCMD_WRITE_12 0xaa -#define GPCMD_WRITE_AND_VERIFY_10 0x2e -#define GPCMD_WRITE_BUFFER 0x3b -/* This is listed as optional in ATAPI 2.6, but is (curiously) - * missing from Mt. Fuji, Table 57. It _is_ mentioned in Mt. Fuji - * Table 377 as an MMC command for SCSi devices though... Most ATAPI - * drives support it. */ -#define GPCMD_SET_SPEED 0xbb -/* This seems to be a SCSI specific CD-ROM opcode - * to play data at track/index */ -#define GPCMD_PLAYAUDIO_TI 0x48 -/* - * From MS Media Status Notification Support Specification. For - * older drives only. - */ -#define GPCMD_GET_MEDIA_STATUS 0xda - -/* Mode page codes for mode sense/set */ -#define GPMODE_VENDOR_PAGE 0x00 -#define GPMODE_R_W_ERROR_PAGE 0x01 -#define GPMODE_WRITE_PARMS_PAGE 0x05 -#define GPMODE_WCACHING_PAGE 0x08 -#define GPMODE_AUDIO_CTL_PAGE 0x0e -#define GPMODE_POWER_PAGE 0x1a -#define GPMODE_FAULT_FAIL_PAGE 0x1c -#define GPMODE_TO_PROTECT_PAGE 0x1d -#define GPMODE_CAPABILITIES_PAGE 0x2a -#define GPMODE_ALL_PAGES 0x3f -/* Not in Mt. Fuji, but in ATAPI 2.6 -- deprecated now in favor - * of MODE_SENSE_POWER_PAGE */ -#define GPMODE_CDROM_PAGE 0x0d - - - -/* DVD struct types */ -#define DVD_STRUCT_PHYSICAL 0x00 -#define DVD_STRUCT_COPYRIGHT 0x01 -#define DVD_STRUCT_DISCKEY 0x02 -#define DVD_STRUCT_BCA 0x03 -#define DVD_STRUCT_MANUFACT 0x04 - -struct dvd_layer { - __u8 book_version : 4; - __u8 book_type : 4; - __u8 min_rate : 4; - __u8 disc_size : 4; - __u8 layer_type : 4; - __u8 track_path : 1; - __u8 nlayers : 2; - __u8 track_density : 4; - __u8 linear_density : 4; - __u8 bca : 1; - __u32 start_sector; - __u32 end_sector; - __u32 end_sector_l0; -}; - -#define DVD_LAYERS 4 - -struct dvd_physical { - __u8 type; - __u8 layer_num; - struct dvd_layer layer[DVD_LAYERS]; -}; - -struct dvd_copyright { - __u8 type; - - __u8 layer_num; - __u8 cpst; - __u8 rmi; -}; - -struct dvd_disckey { - __u8 type; - - unsigned agid : 2; - __u8 value[2048]; -}; - -struct dvd_bca { - __u8 type; - - int len; - __u8 value[188]; -}; - -struct dvd_manufact { - __u8 type; - - __u8 layer_num; - int len; - __u8 value[2048]; -}; - -typedef union { - __u8 type; - - struct dvd_physical physical; - struct dvd_copyright copyright; - struct dvd_disckey disckey; - struct dvd_bca bca; - struct dvd_manufact manufact; -} dvd_struct; - -/* - * DVD authentication ioctl - */ - -/* Authentication states */ -#define DVD_LU_SEND_AGID 0 -#define DVD_HOST_SEND_CHALLENGE 1 -#define DVD_LU_SEND_KEY1 2 -#define DVD_LU_SEND_CHALLENGE 3 -#define DVD_HOST_SEND_KEY2 4 - -/* Termination states */ -#define DVD_AUTH_ESTABLISHED 5 -#define DVD_AUTH_FAILURE 6 - -/* Other functions */ -#define DVD_LU_SEND_TITLE_KEY 7 -#define DVD_LU_SEND_ASF 8 -#define DVD_INVALIDATE_AGID 9 -#define DVD_LU_SEND_RPC_STATE 10 -#define DVD_HOST_SEND_RPC_STATE 11 - -/* State data */ -typedef __u8 dvd_key[5]; /* 40-bit value, MSB is first elem. */ -typedef __u8 dvd_challenge[10]; /* 80-bit value, MSB is first elem. */ - -struct dvd_lu_send_agid { - __u8 type; - unsigned agid : 2; -}; - -struct dvd_host_send_challenge { - __u8 type; - unsigned agid : 2; - - dvd_challenge chal; -}; - -struct dvd_send_key { - __u8 type; - unsigned agid : 2; - - dvd_key key; -}; - -struct dvd_lu_send_challenge { - __u8 type; - unsigned agid : 2; - - dvd_challenge chal; -}; - -#define DVD_CPM_NO_COPYRIGHT 0 -#define DVD_CPM_COPYRIGHTED 1 - -#define DVD_CP_SEC_NONE 0 -#define DVD_CP_SEC_EXIST 1 - -#define DVD_CGMS_UNRESTRICTED 0 -#define DVD_CGMS_SINGLE 2 -#define DVD_CGMS_RESTRICTED 3 - -struct dvd_lu_send_title_key { - __u8 type; - unsigned agid : 2; - - dvd_key title_key; - int lba; - unsigned cpm : 1; - unsigned cp_sec : 1; - unsigned cgms : 2; -}; - -struct dvd_lu_send_asf { - __u8 type; - unsigned agid : 2; - - unsigned asf : 1; -}; - -struct dvd_host_send_rpcstate { - __u8 type; - __u8 pdrc; -}; - -struct dvd_lu_send_rpcstate { - __u8 type : 2; - __u8 vra : 3; - __u8 ucca : 3; - __u8 region_mask; - __u8 rpc_scheme; -}; - -typedef union { - __u8 type; - - struct dvd_lu_send_agid lsa; - struct dvd_host_send_challenge hsc; - struct dvd_send_key lsk; - struct dvd_lu_send_challenge lsc; - struct dvd_send_key hsk; - struct dvd_lu_send_title_key lstk; - struct dvd_lu_send_asf lsasf; - struct dvd_host_send_rpcstate hrpcs; - struct dvd_lu_send_rpcstate lrpcs; -} dvd_authinfo; - -struct request_sense { -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 valid : 1; - __u8 error_code : 7; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 error_code : 7; - __u8 valid : 1; -#endif - __u8 segment_number; -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 reserved1 : 2; - __u8 ili : 1; - __u8 reserved2 : 1; - __u8 sense_key : 4; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 sense_key : 4; - __u8 reserved2 : 1; - __u8 ili : 1; - __u8 reserved1 : 2; -#endif - __u8 information[4]; - __u8 add_sense_len; - __u8 command_info[4]; - __u8 asc; - __u8 ascq; - __u8 fruc; - __u8 sks[3]; - __u8 asb[46]; -}; - -/* - * feature profile - */ -#define CDF_RWRT 0x0020 /* "Random Writable" */ -#define CDF_HWDM 0x0024 /* "Hardware Defect Management" */ -#define CDF_MRW 0x0028 - -/* - * media status bits - */ -#define CDM_MRW_NOTMRW 0 -#define CDM_MRW_BGFORMAT_INACTIVE 1 -#define CDM_MRW_BGFORMAT_ACTIVE 2 -#define CDM_MRW_BGFORMAT_COMPLETE 3 - -/* - * mrw address spaces - */ -#define MRW_LBA_DMA 0 -#define MRW_LBA_GAA 1 - -/* - * mrw mode pages (first is deprecated) -- probed at init time and - * cdi->mrw_mode_page is set - */ -#define MRW_MODE_PC_PRE1 0x2c -#define MRW_MODE_PC 0x03 - -struct mrw_feature_desc { - __be16 feature_code; -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 reserved1 : 2; - __u8 feature_version : 4; - __u8 persistent : 1; - __u8 curr : 1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 curr : 1; - __u8 persistent : 1; - __u8 feature_version : 4; - __u8 reserved1 : 2; -#endif - __u8 add_len; -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 reserved2 : 7; - __u8 write : 1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 write : 1; - __u8 reserved2 : 7; -#endif - __u8 reserved3; - __u8 reserved4; - __u8 reserved5; -}; - -/* cf. mmc4r02g.pdf 5.3.10 Random Writable Feature (0020h) pg 197 of 635 */ -struct rwrt_feature_desc { - __be16 feature_code; -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 reserved1 : 2; - __u8 feature_version : 4; - __u8 persistent : 1; - __u8 curr : 1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 curr : 1; - __u8 persistent : 1; - __u8 feature_version : 4; - __u8 reserved1 : 2; -#endif - __u8 add_len; - __u32 last_lba; - __u32 block_size; - __u16 blocking; -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 reserved2 : 7; - __u8 page_present : 1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 page_present : 1; - __u8 reserved2 : 7; -#endif - __u8 reserved3; -}; - -typedef struct { - __be16 disc_information_length; -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 reserved1 : 3; - __u8 erasable : 1; - __u8 border_status : 2; - __u8 disc_status : 2; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 disc_status : 2; - __u8 border_status : 2; - __u8 erasable : 1; - __u8 reserved1 : 3; -#else -#error "Please fix " -#endif - __u8 n_first_track; - __u8 n_sessions_lsb; - __u8 first_track_lsb; - __u8 last_track_lsb; -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 did_v : 1; - __u8 dbc_v : 1; - __u8 uru : 1; - __u8 reserved2 : 2; - __u8 dbit : 1; - __u8 mrw_status : 2; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 mrw_status : 2; - __u8 dbit : 1; - __u8 reserved2 : 2; - __u8 uru : 1; - __u8 dbc_v : 1; - __u8 did_v : 1; -#endif - __u8 disc_type; - __u8 n_sessions_msb; - __u8 first_track_msb; - __u8 last_track_msb; - __u32 disc_id; - __u32 lead_in; - __u32 lead_out; - __u8 disc_bar_code[8]; - __u8 reserved3; - __u8 n_opc; -} disc_information; - -typedef struct { - __be16 track_information_length; - __u8 track_lsb; - __u8 session_lsb; - __u8 reserved1; -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 reserved2 : 2; - __u8 damage : 1; - __u8 copy : 1; - __u8 track_mode : 4; - __u8 rt : 1; - __u8 blank : 1; - __u8 packet : 1; - __u8 fp : 1; - __u8 data_mode : 4; - __u8 reserved3 : 6; - __u8 lra_v : 1; - __u8 nwa_v : 1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 track_mode : 4; - __u8 copy : 1; - __u8 damage : 1; - __u8 reserved2 : 2; - __u8 data_mode : 4; - __u8 fp : 1; - __u8 packet : 1; - __u8 blank : 1; - __u8 rt : 1; - __u8 nwa_v : 1; - __u8 lra_v : 1; - __u8 reserved3 : 6; -#endif - __be32 track_start; - __be32 next_writable; - __be32 free_blocks; - __be32 fixed_packet_size; - __be32 track_size; - __be32 last_rec_address; -} track_information; - -struct feature_header { - __u32 data_len; - __u8 reserved1; - __u8 reserved2; - __u16 curr_profile; -}; - -struct mode_page_header { - __be16 mode_data_length; - __u8 medium_type; - __u8 reserved1; - __u8 reserved2; - __u8 reserved3; - __be16 desc_length; -}; - -/* removable medium feature descriptor */ -struct rm_feature_desc { - __be16 feature_code; -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 reserved1:2; - __u8 feature_version:4; - __u8 persistent:1; - __u8 curr:1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 curr:1; - __u8 persistent:1; - __u8 feature_version:4; - __u8 reserved1:2; -#endif - __u8 add_len; -#if defined(__BIG_ENDIAN_BITFIELD) - __u8 mech_type:3; - __u8 load:1; - __u8 eject:1; - __u8 pvnt_jmpr:1; - __u8 dbml:1; - __u8 lock:1; -#elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 lock:1; - __u8 dbml:1; - __u8 pvnt_jmpr:1; - __u8 eject:1; - __u8 load:1; - __u8 mech_type:3; -#endif - __u8 reserved2; - __u8 reserved3; - __u8 reserved4; -}; - -#endif /* _UAPI_LINUX_CDROM_H */ diff --git a/src/linux/include/uapi/linux/cgroupstats.h b/src/linux/include/uapi/linux/cgroupstats.h deleted file mode 100644 index 3753c33..0000000 --- a/src/linux/include/uapi/linux/cgroupstats.h +++ /dev/null @@ -1,71 +0,0 @@ -/* cgroupstats.h - exporting per-cgroup statistics - * - * Copyright IBM Corporation, 2007 - * Author Balbir Singh - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#ifndef _LINUX_CGROUPSTATS_H -#define _LINUX_CGROUPSTATS_H - -#include -#include - -/* - * Data shared between user space and kernel space on a per cgroup - * basis. This data is shared using taskstats. - * - * Most of these states are derived by looking at the task->state value - * For the nr_io_wait state, a flag in the delay accounting structure - * indicates that the task is waiting on IO - * - * Each member is aligned to a 8 byte boundary. - */ -struct cgroupstats { - __u64 nr_sleeping; /* Number of tasks sleeping */ - __u64 nr_running; /* Number of tasks running */ - __u64 nr_stopped; /* Number of tasks in stopped state */ - __u64 nr_uninterruptible; /* Number of tasks in uninterruptible */ - /* state */ - __u64 nr_io_wait; /* Number of tasks waiting on IO */ -}; - -/* - * Commands sent from userspace - * Not versioned. New commands should only be inserted at the enum's end - * prior to __CGROUPSTATS_CMD_MAX - */ - -enum { - CGROUPSTATS_CMD_UNSPEC = __TASKSTATS_CMD_MAX, /* Reserved */ - CGROUPSTATS_CMD_GET, /* user->kernel request/get-response */ - CGROUPSTATS_CMD_NEW, /* kernel->user event */ - __CGROUPSTATS_CMD_MAX, -}; - -#define CGROUPSTATS_CMD_MAX (__CGROUPSTATS_CMD_MAX - 1) - -enum { - CGROUPSTATS_TYPE_UNSPEC = 0, /* Reserved */ - CGROUPSTATS_TYPE_CGROUP_STATS, /* contains name + stats */ - __CGROUPSTATS_TYPE_MAX, -}; - -#define CGROUPSTATS_TYPE_MAX (__CGROUPSTATS_TYPE_MAX - 1) - -enum { - CGROUPSTATS_CMD_ATTR_UNSPEC = 0, - CGROUPSTATS_CMD_ATTR_FD, - __CGROUPSTATS_CMD_ATTR_MAX, -}; - -#define CGROUPSTATS_CMD_ATTR_MAX (__CGROUPSTATS_CMD_ATTR_MAX - 1) - -#endif /* _LINUX_CGROUPSTATS_H */ diff --git a/src/linux/include/uapi/linux/cn_proc.h b/src/linux/include/uapi/linux/cn_proc.h deleted file mode 100644 index f6c2710..0000000 --- a/src/linux/include/uapi/linux/cn_proc.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * cn_proc.h - process events connector - * - * Copyright (C) Matt Helsley, IBM Corp. 2005 - * Based on cn_fork.h by Nguyen Anh Quynh and Guillaume Thouvenin - * Copyright (C) 2005 Nguyen Anh Quynh - * Copyright (C) 2005 Guillaume Thouvenin - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#ifndef _UAPICN_PROC_H -#define _UAPICN_PROC_H - -#include - -/* - * Userspace sends this enum to register with the kernel that it is listening - * for events on the connector. - */ -enum proc_cn_mcast_op { - PROC_CN_MCAST_LISTEN = 1, - PROC_CN_MCAST_IGNORE = 2 -}; - -/* - * From the user's point of view, the process - * ID is the thread group ID and thread ID is the internal - * kernel "pid". So, fields are assigned as follow: - * - * In user space - In kernel space - * - * parent process ID = parent->tgid - * parent thread ID = parent->pid - * child process ID = child->tgid - * child thread ID = child->pid - */ - -struct proc_event { - enum what { - /* Use successive bits so the enums can be used to record - * sets of events as well - */ - PROC_EVENT_NONE = 0x00000000, - PROC_EVENT_FORK = 0x00000001, - PROC_EVENT_EXEC = 0x00000002, - PROC_EVENT_UID = 0x00000004, - PROC_EVENT_GID = 0x00000040, - PROC_EVENT_SID = 0x00000080, - PROC_EVENT_PTRACE = 0x00000100, - PROC_EVENT_COMM = 0x00000200, - /* "next" should be 0x00000400 */ - /* "last" is the last process event: exit, - * while "next to last" is coredumping event */ - PROC_EVENT_COREDUMP = 0x40000000, - PROC_EVENT_EXIT = 0x80000000 - } what; - __u32 cpu; - __u64 __attribute__((aligned(8))) timestamp_ns; - /* Number of nano seconds since system boot */ - union { /* must be last field of proc_event struct */ - struct { - __u32 err; - } ack; - - struct fork_proc_event { - __kernel_pid_t parent_pid; - __kernel_pid_t parent_tgid; - __kernel_pid_t child_pid; - __kernel_pid_t child_tgid; - } fork; - - struct exec_proc_event { - __kernel_pid_t process_pid; - __kernel_pid_t process_tgid; - } exec; - - struct id_proc_event { - __kernel_pid_t process_pid; - __kernel_pid_t process_tgid; - union { - __u32 ruid; /* task uid */ - __u32 rgid; /* task gid */ - } r; - union { - __u32 euid; - __u32 egid; - } e; - } id; - - struct sid_proc_event { - __kernel_pid_t process_pid; - __kernel_pid_t process_tgid; - } sid; - - struct ptrace_proc_event { - __kernel_pid_t process_pid; - __kernel_pid_t process_tgid; - __kernel_pid_t tracer_pid; - __kernel_pid_t tracer_tgid; - } ptrace; - - struct comm_proc_event { - __kernel_pid_t process_pid; - __kernel_pid_t process_tgid; - char comm[16]; - } comm; - - struct coredump_proc_event { - __kernel_pid_t process_pid; - __kernel_pid_t process_tgid; - } coredump; - - struct exit_proc_event { - __kernel_pid_t process_pid; - __kernel_pid_t process_tgid; - __u32 exit_code, exit_signal; - } exit; - - } event_data; -}; - -#endif /* _UAPICN_PROC_H */ diff --git a/src/linux/include/uapi/linux/const.h b/src/linux/include/uapi/linux/const.h deleted file mode 100644 index c872bfd..0000000 --- a/src/linux/include/uapi/linux/const.h +++ /dev/null @@ -1,27 +0,0 @@ -/* const.h: Macros for dealing with constants. */ - -#ifndef _LINUX_CONST_H -#define _LINUX_CONST_H - -/* Some constant macros are used in both assembler and - * C code. Therefore we cannot annotate them always with - * 'UL' and other type specifiers unilaterally. We - * use the following macros to deal with this. - * - * Similarly, _AT() will cast an expression with a type in C, but - * leave it unchanged in asm. - */ - -#ifdef __ASSEMBLY__ -#define _AC(X,Y) X -#define _AT(T,X) X -#else -#define __AC(X,Y) (X##Y) -#define _AC(X,Y) __AC(X,Y) -#define _AT(T,X) ((T)(X)) -#endif - -#define _BITUL(x) (_AC(1,UL) << (x)) -#define _BITULL(x) (_AC(1,ULL) << (x)) - -#endif /* !(_LINUX_CONST_H) */ diff --git a/src/linux/include/uapi/linux/cryptouser.h b/src/linux/include/uapi/linux/cryptouser.h deleted file mode 100644 index 79b5ded..0000000 --- a/src/linux/include/uapi/linux/cryptouser.h +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Crypto user configuration API. - * - * Copyright (C) 2011 secunet Security Networks AG - * Copyright (C) 2011 Steffen Klassert - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - */ - -/* Netlink configuration messages. */ -enum { - CRYPTO_MSG_BASE = 0x10, - CRYPTO_MSG_NEWALG = 0x10, - CRYPTO_MSG_DELALG, - CRYPTO_MSG_UPDATEALG, - CRYPTO_MSG_GETALG, - CRYPTO_MSG_DELRNG, - __CRYPTO_MSG_MAX -}; -#define CRYPTO_MSG_MAX (__CRYPTO_MSG_MAX - 1) -#define CRYPTO_NR_MSGTYPES (CRYPTO_MSG_MAX + 1 - CRYPTO_MSG_BASE) - -#define CRYPTO_MAX_NAME CRYPTO_MAX_ALG_NAME - -/* Netlink message attributes. */ -enum crypto_attr_type_t { - CRYPTOCFGA_UNSPEC, - CRYPTOCFGA_PRIORITY_VAL, /* __u32 */ - CRYPTOCFGA_REPORT_LARVAL, /* struct crypto_report_larval */ - CRYPTOCFGA_REPORT_HASH, /* struct crypto_report_hash */ - CRYPTOCFGA_REPORT_BLKCIPHER, /* struct crypto_report_blkcipher */ - CRYPTOCFGA_REPORT_AEAD, /* struct crypto_report_aead */ - CRYPTOCFGA_REPORT_COMPRESS, /* struct crypto_report_comp */ - CRYPTOCFGA_REPORT_RNG, /* struct crypto_report_rng */ - CRYPTOCFGA_REPORT_CIPHER, /* struct crypto_report_cipher */ - CRYPTOCFGA_REPORT_AKCIPHER, /* struct crypto_report_akcipher */ - CRYPTOCFGA_REPORT_KPP, /* struct crypto_report_kpp */ - __CRYPTOCFGA_MAX - -#define CRYPTOCFGA_MAX (__CRYPTOCFGA_MAX - 1) -}; - -struct crypto_user_alg { - char cru_name[CRYPTO_MAX_ALG_NAME]; - char cru_driver_name[CRYPTO_MAX_ALG_NAME]; - char cru_module_name[CRYPTO_MAX_ALG_NAME]; - __u32 cru_type; - __u32 cru_mask; - __u32 cru_refcnt; - __u32 cru_flags; -}; - -struct crypto_report_larval { - char type[CRYPTO_MAX_NAME]; -}; - -struct crypto_report_hash { - char type[CRYPTO_MAX_NAME]; - unsigned int blocksize; - unsigned int digestsize; -}; - -struct crypto_report_cipher { - char type[CRYPTO_MAX_ALG_NAME]; - unsigned int blocksize; - unsigned int min_keysize; - unsigned int max_keysize; -}; - -struct crypto_report_blkcipher { - char type[CRYPTO_MAX_NAME]; - char geniv[CRYPTO_MAX_NAME]; - unsigned int blocksize; - unsigned int min_keysize; - unsigned int max_keysize; - unsigned int ivsize; -}; - -struct crypto_report_aead { - char type[CRYPTO_MAX_NAME]; - char geniv[CRYPTO_MAX_NAME]; - unsigned int blocksize; - unsigned int maxauthsize; - unsigned int ivsize; -}; - -struct crypto_report_comp { - char type[CRYPTO_MAX_NAME]; -}; - -struct crypto_report_rng { - char type[CRYPTO_MAX_NAME]; - unsigned int seedsize; -}; - -struct crypto_report_akcipher { - char type[CRYPTO_MAX_NAME]; -}; - -struct crypto_report_kpp { - char type[CRYPTO_MAX_NAME]; -}; - -#define CRYPTO_REPORT_MAXSIZE (sizeof(struct crypto_user_alg) + \ - sizeof(struct crypto_report_blkcipher)) diff --git a/src/linux/include/uapi/linux/dccp.h b/src/linux/include/uapi/linux/dccp.h deleted file mode 100644 index 52a9cd7..0000000 --- a/src/linux/include/uapi/linux/dccp.h +++ /dev/null @@ -1,237 +0,0 @@ -#ifndef _UAPI_LINUX_DCCP_H -#define _UAPI_LINUX_DCCP_H - -#include -#include - -/** - * struct dccp_hdr - generic part of DCCP packet header - * - * @dccph_sport - Relevant port on the endpoint that sent this packet - * @dccph_dport - Relevant port on the other endpoint - * @dccph_doff - Data Offset from the start of the DCCP header, in 32-bit words - * @dccph_ccval - Used by the HC-Sender CCID - * @dccph_cscov - Parts of the packet that are covered by the Checksum field - * @dccph_checksum - Internet checksum, depends on dccph_cscov - * @dccph_x - 0 = 24 bit sequence number, 1 = 48 - * @dccph_type - packet type, see DCCP_PKT_ prefixed macros - * @dccph_seq - sequence number high or low order 24 bits, depends on dccph_x - */ -struct dccp_hdr { - __be16 dccph_sport, - dccph_dport; - __u8 dccph_doff; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 dccph_cscov:4, - dccph_ccval:4; -#elif defined(__BIG_ENDIAN_BITFIELD) - __u8 dccph_ccval:4, - dccph_cscov:4; -#else -#error "Adjust your defines" -#endif - __sum16 dccph_checksum; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 dccph_x:1, - dccph_type:4, - dccph_reserved:3; -#elif defined(__BIG_ENDIAN_BITFIELD) - __u8 dccph_reserved:3, - dccph_type:4, - dccph_x:1; -#else -#error "Adjust your defines" -#endif - __u8 dccph_seq2; - __be16 dccph_seq; -}; - -/** - * struct dccp_hdr_ext - the low bits of a 48 bit seq packet - * - * @dccph_seq_low - low 24 bits of a 48 bit seq packet - */ -struct dccp_hdr_ext { - __be32 dccph_seq_low; -}; - -/** - * struct dccp_hdr_request - Connection initiation request header - * - * @dccph_req_service - Service to which the client app wants to connect - */ -struct dccp_hdr_request { - __be32 dccph_req_service; -}; -/** - * struct dccp_hdr_ack_bits - acknowledgment bits common to most packets - * - * @dccph_resp_ack_nr_high - 48 bit ack number high order bits, contains GSR - * @dccph_resp_ack_nr_low - 48 bit ack number low order bits, contains GSR - */ -struct dccp_hdr_ack_bits { - __be16 dccph_reserved1; - __be16 dccph_ack_nr_high; - __be32 dccph_ack_nr_low; -}; -/** - * struct dccp_hdr_response - Connection initiation response header - * - * @dccph_resp_ack - 48 bit Acknowledgment Number Subheader (5.3) - * @dccph_resp_service - Echoes the Service Code on a received DCCP-Request - */ -struct dccp_hdr_response { - struct dccp_hdr_ack_bits dccph_resp_ack; - __be32 dccph_resp_service; -}; - -/** - * struct dccp_hdr_reset - Unconditionally shut down a connection - * - * @dccph_reset_ack - 48 bit Acknowledgment Number Subheader (5.6) - * @dccph_reset_code - one of %dccp_reset_codes - * @dccph_reset_data - the Data 1 ... Data 3 fields from 5.6 - */ -struct dccp_hdr_reset { - struct dccp_hdr_ack_bits dccph_reset_ack; - __u8 dccph_reset_code, - dccph_reset_data[3]; -}; - -enum dccp_pkt_type { - DCCP_PKT_REQUEST = 0, - DCCP_PKT_RESPONSE, - DCCP_PKT_DATA, - DCCP_PKT_ACK, - DCCP_PKT_DATAACK, - DCCP_PKT_CLOSEREQ, - DCCP_PKT_CLOSE, - DCCP_PKT_RESET, - DCCP_PKT_SYNC, - DCCP_PKT_SYNCACK, - DCCP_PKT_INVALID, -}; - -#define DCCP_NR_PKT_TYPES DCCP_PKT_INVALID - -static inline unsigned int dccp_packet_hdr_len(const __u8 type) -{ - if (type == DCCP_PKT_DATA) - return 0; - if (type == DCCP_PKT_DATAACK || - type == DCCP_PKT_ACK || - type == DCCP_PKT_SYNC || - type == DCCP_PKT_SYNCACK || - type == DCCP_PKT_CLOSE || - type == DCCP_PKT_CLOSEREQ) - return sizeof(struct dccp_hdr_ack_bits); - if (type == DCCP_PKT_REQUEST) - return sizeof(struct dccp_hdr_request); - if (type == DCCP_PKT_RESPONSE) - return sizeof(struct dccp_hdr_response); - return sizeof(struct dccp_hdr_reset); -} -enum dccp_reset_codes { - DCCP_RESET_CODE_UNSPECIFIED = 0, - DCCP_RESET_CODE_CLOSED, - DCCP_RESET_CODE_ABORTED, - DCCP_RESET_CODE_NO_CONNECTION, - DCCP_RESET_CODE_PACKET_ERROR, - DCCP_RESET_CODE_OPTION_ERROR, - DCCP_RESET_CODE_MANDATORY_ERROR, - DCCP_RESET_CODE_CONNECTION_REFUSED, - DCCP_RESET_CODE_BAD_SERVICE_CODE, - DCCP_RESET_CODE_TOO_BUSY, - DCCP_RESET_CODE_BAD_INIT_COOKIE, - DCCP_RESET_CODE_AGGRESSION_PENALTY, - - DCCP_MAX_RESET_CODES /* Leave at the end! */ -}; - -/* DCCP options */ -enum { - DCCPO_PADDING = 0, - DCCPO_MANDATORY = 1, - DCCPO_MIN_RESERVED = 3, - DCCPO_MAX_RESERVED = 31, - DCCPO_CHANGE_L = 32, - DCCPO_CONFIRM_L = 33, - DCCPO_CHANGE_R = 34, - DCCPO_CONFIRM_R = 35, - DCCPO_NDP_COUNT = 37, - DCCPO_ACK_VECTOR_0 = 38, - DCCPO_ACK_VECTOR_1 = 39, - DCCPO_TIMESTAMP = 41, - DCCPO_TIMESTAMP_ECHO = 42, - DCCPO_ELAPSED_TIME = 43, - DCCPO_MAX = 45, - DCCPO_MIN_RX_CCID_SPECIFIC = 128, /* from sender to receiver */ - DCCPO_MAX_RX_CCID_SPECIFIC = 191, - DCCPO_MIN_TX_CCID_SPECIFIC = 192, /* from receiver to sender */ - DCCPO_MAX_TX_CCID_SPECIFIC = 255, -}; -/* maximum size of a single TLV-encoded DCCP option (sans type/len bytes) */ -#define DCCP_SINGLE_OPT_MAXLEN 253 - -/* DCCP CCIDS */ -enum { - DCCPC_CCID2 = 2, - DCCPC_CCID3 = 3, -}; - -/* DCCP features (RFC 4340 section 6.4) */ -enum dccp_feature_numbers { - DCCPF_RESERVED = 0, - DCCPF_CCID = 1, - DCCPF_SHORT_SEQNOS = 2, - DCCPF_SEQUENCE_WINDOW = 3, - DCCPF_ECN_INCAPABLE = 4, - DCCPF_ACK_RATIO = 5, - DCCPF_SEND_ACK_VECTOR = 6, - DCCPF_SEND_NDP_COUNT = 7, - DCCPF_MIN_CSUM_COVER = 8, - DCCPF_DATA_CHECKSUM = 9, - /* 10-127 reserved */ - DCCPF_MIN_CCID_SPECIFIC = 128, - DCCPF_SEND_LEV_RATE = 192, /* RFC 4342, sec. 8.4 */ - DCCPF_MAX_CCID_SPECIFIC = 255, -}; - -/* DCCP socket control message types for cmsg */ -enum dccp_cmsg_type { - DCCP_SCM_PRIORITY = 1, - DCCP_SCM_QPOLICY_MAX = 0xFFFF, - /* ^-- Up to here reserved exclusively for qpolicy parameters */ - DCCP_SCM_MAX -}; - -/* DCCP priorities for outgoing/queued packets */ -enum dccp_packet_dequeueing_policy { - DCCPQ_POLICY_SIMPLE, - DCCPQ_POLICY_PRIO, - DCCPQ_POLICY_MAX -}; - -/* DCCP socket options */ -#define DCCP_SOCKOPT_PACKET_SIZE 1 /* XXX deprecated, without effect */ -#define DCCP_SOCKOPT_SERVICE 2 -#define DCCP_SOCKOPT_CHANGE_L 3 -#define DCCP_SOCKOPT_CHANGE_R 4 -#define DCCP_SOCKOPT_GET_CUR_MPS 5 -#define DCCP_SOCKOPT_SERVER_TIMEWAIT 6 -#define DCCP_SOCKOPT_SEND_CSCOV 10 -#define DCCP_SOCKOPT_RECV_CSCOV 11 -#define DCCP_SOCKOPT_AVAILABLE_CCIDS 12 -#define DCCP_SOCKOPT_CCID 13 -#define DCCP_SOCKOPT_TX_CCID 14 -#define DCCP_SOCKOPT_RX_CCID 15 -#define DCCP_SOCKOPT_QPOLICY_ID 16 -#define DCCP_SOCKOPT_QPOLICY_TXQLEN 17 -#define DCCP_SOCKOPT_CCID_RX_INFO 128 -#define DCCP_SOCKOPT_CCID_TX_INFO 192 - -/* maximum number of services provided on the same listening port */ -#define DCCP_SERVICE_LIST_MAX_LEN 32 - - -#endif /* _UAPI_LINUX_DCCP_H */ diff --git a/src/linux/include/uapi/linux/dqblk_xfs.h b/src/linux/include/uapi/linux/dqblk_xfs.h deleted file mode 100644 index 11b3b31..0000000 --- a/src/linux/include/uapi/linux/dqblk_xfs.h +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 1995-2001,2004 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesset General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef _LINUX_DQBLK_XFS_H -#define _LINUX_DQBLK_XFS_H - -#include - -/* - * Disk quota - quotactl(2) commands for the XFS Quota Manager (XQM). - */ - -#define XQM_CMD(x) (('X'<<8)+(x)) /* note: forms first QCMD argument */ -#define XQM_COMMAND(x) (((x) & (0xff<<8)) == ('X'<<8)) /* test if for XFS */ - -#define XQM_USRQUOTA 0 /* system call user quota type */ -#define XQM_GRPQUOTA 1 /* system call group quota type */ -#define XQM_PRJQUOTA 2 /* system call project quota type */ -#define XQM_MAXQUOTAS 3 - -#define Q_XQUOTAON XQM_CMD(1) /* enable accounting/enforcement */ -#define Q_XQUOTAOFF XQM_CMD(2) /* disable accounting/enforcement */ -#define Q_XGETQUOTA XQM_CMD(3) /* get disk limits and usage */ -#define Q_XSETQLIM XQM_CMD(4) /* set disk limits */ -#define Q_XGETQSTAT XQM_CMD(5) /* get quota subsystem status */ -#define Q_XQUOTARM XQM_CMD(6) /* free disk space used by dquots */ -#define Q_XQUOTASYNC XQM_CMD(7) /* delalloc flush, updates dquots */ -#define Q_XGETQSTATV XQM_CMD(8) /* newer version of get quota */ -#define Q_XGETNEXTQUOTA XQM_CMD(9) /* get disk limits and usage >= ID */ - -/* - * fs_disk_quota structure: - * - * This contains the current quota information regarding a user/proj/group. - * It is 64-bit aligned, and all the blk units are in BBs (Basic Blocks) of - * 512 bytes. - */ -#define FS_DQUOT_VERSION 1 /* fs_disk_quota.d_version */ -typedef struct fs_disk_quota { - __s8 d_version; /* version of this structure */ - __s8 d_flags; /* FS_{USER,PROJ,GROUP}_QUOTA */ - __u16 d_fieldmask; /* field specifier */ - __u32 d_id; /* user, project, or group ID */ - __u64 d_blk_hardlimit;/* absolute limit on disk blks */ - __u64 d_blk_softlimit;/* preferred limit on disk blks */ - __u64 d_ino_hardlimit;/* maximum # allocated inodes */ - __u64 d_ino_softlimit;/* preferred inode limit */ - __u64 d_bcount; /* # disk blocks owned by the user */ - __u64 d_icount; /* # inodes owned by the user */ - __s32 d_itimer; /* zero if within inode limits */ - /* if not, we refuse service */ - __s32 d_btimer; /* similar to above; for disk blocks */ - __u16 d_iwarns; /* # warnings issued wrt num inodes */ - __u16 d_bwarns; /* # warnings issued wrt disk blocks */ - __s32 d_padding2; /* padding2 - for future use */ - __u64 d_rtb_hardlimit;/* absolute limit on realtime blks */ - __u64 d_rtb_softlimit;/* preferred limit on RT disk blks */ - __u64 d_rtbcount; /* # realtime blocks owned */ - __s32 d_rtbtimer; /* similar to above; for RT disk blks */ - __u16 d_rtbwarns; /* # warnings issued wrt RT disk blks */ - __s16 d_padding3; /* padding3 - for future use */ - char d_padding4[8]; /* yet more padding */ -} fs_disk_quota_t; - -/* - * These fields are sent to Q_XSETQLIM to specify fields that need to change. - */ -#define FS_DQ_ISOFT (1<<0) -#define FS_DQ_IHARD (1<<1) -#define FS_DQ_BSOFT (1<<2) -#define FS_DQ_BHARD (1<<3) -#define FS_DQ_RTBSOFT (1<<4) -#define FS_DQ_RTBHARD (1<<5) -#define FS_DQ_LIMIT_MASK (FS_DQ_ISOFT | FS_DQ_IHARD | FS_DQ_BSOFT | \ - FS_DQ_BHARD | FS_DQ_RTBSOFT | FS_DQ_RTBHARD) -/* - * These timers can only be set in super user's dquot. For others, timers are - * automatically started and stopped. Superusers timer values set the limits - * for the rest. In case these values are zero, the DQ_{F,B}TIMELIMIT values - * defined below are used. - * These values also apply only to the d_fieldmask field for Q_XSETQLIM. - */ -#define FS_DQ_BTIMER (1<<6) -#define FS_DQ_ITIMER (1<<7) -#define FS_DQ_RTBTIMER (1<<8) -#define FS_DQ_TIMER_MASK (FS_DQ_BTIMER | FS_DQ_ITIMER | FS_DQ_RTBTIMER) - -/* - * Warning counts are set in both super user's dquot and others. For others, - * warnings are set/cleared by the administrators (or automatically by going - * below the soft limit). Superusers warning values set the warning limits - * for the rest. In case these values are zero, the DQ_{F,B}WARNLIMIT values - * defined below are used. - * These values also apply only to the d_fieldmask field for Q_XSETQLIM. - */ -#define FS_DQ_BWARNS (1<<9) -#define FS_DQ_IWARNS (1<<10) -#define FS_DQ_RTBWARNS (1<<11) -#define FS_DQ_WARNS_MASK (FS_DQ_BWARNS | FS_DQ_IWARNS | FS_DQ_RTBWARNS) - -/* - * Accounting values. These can only be set for filesystem with - * non-transactional quotas that require quotacheck(8) in userspace. - */ -#define FS_DQ_BCOUNT (1<<12) -#define FS_DQ_ICOUNT (1<<13) -#define FS_DQ_RTBCOUNT (1<<14) -#define FS_DQ_ACCT_MASK (FS_DQ_BCOUNT | FS_DQ_ICOUNT | FS_DQ_RTBCOUNT) - -/* - * Various flags related to quotactl(2). - */ -#define FS_QUOTA_UDQ_ACCT (1<<0) /* user quota accounting */ -#define FS_QUOTA_UDQ_ENFD (1<<1) /* user quota limits enforcement */ -#define FS_QUOTA_GDQ_ACCT (1<<2) /* group quota accounting */ -#define FS_QUOTA_GDQ_ENFD (1<<3) /* group quota limits enforcement */ -#define FS_QUOTA_PDQ_ACCT (1<<4) /* project quota accounting */ -#define FS_QUOTA_PDQ_ENFD (1<<5) /* project quota limits enforcement */ - -#define FS_USER_QUOTA (1<<0) /* user quota type */ -#define FS_PROJ_QUOTA (1<<1) /* project quota type */ -#define FS_GROUP_QUOTA (1<<2) /* group quota type */ - -/* - * fs_quota_stat is the struct returned in Q_XGETQSTAT for a given file system. - * Provides a centralized way to get meta information about the quota subsystem. - * eg. space taken up for user and group quotas, number of dquots currently - * incore. - */ -#define FS_QSTAT_VERSION 1 /* fs_quota_stat.qs_version */ - -/* - * Some basic information about 'quota files'. - */ -typedef struct fs_qfilestat { - __u64 qfs_ino; /* inode number */ - __u64 qfs_nblks; /* number of BBs 512-byte-blks */ - __u32 qfs_nextents; /* number of extents */ -} fs_qfilestat_t; - -typedef struct fs_quota_stat { - __s8 qs_version; /* version number for future changes */ - __u16 qs_flags; /* FS_QUOTA_{U,P,G}DQ_{ACCT,ENFD} */ - __s8 qs_pad; /* unused */ - fs_qfilestat_t qs_uquota; /* user quota storage information */ - fs_qfilestat_t qs_gquota; /* group quota storage information */ - __u32 qs_incoredqs; /* number of dquots incore */ - __s32 qs_btimelimit; /* limit for blks timer */ - __s32 qs_itimelimit; /* limit for inodes timer */ - __s32 qs_rtbtimelimit;/* limit for rt blks timer */ - __u16 qs_bwarnlimit; /* limit for num warnings */ - __u16 qs_iwarnlimit; /* limit for num warnings */ -} fs_quota_stat_t; - -/* - * fs_quota_statv is used by Q_XGETQSTATV for a given file system. It provides - * a centralized way to get meta information about the quota subsystem. eg. - * space taken up for user, group, and project quotas, number of dquots - * currently incore. - * - * This version has proper versioning support with appropriate padding for - * future expansions, and ability to expand for future without creating any - * backward compatibility issues. - * - * Q_XGETQSTATV uses the passed in value of the requested version via - * fs_quota_statv.qs_version to determine the return data layout of - * fs_quota_statv. The kernel will fill the data fields relevant to that - * version. - * - * If kernel does not support user space caller specified version, EINVAL will - * be returned. User space caller can then reduce the version number and retry - * the same command. - */ -#define FS_QSTATV_VERSION1 1 /* fs_quota_statv.qs_version */ -/* - * Some basic information about 'quota files' for Q_XGETQSTATV command - */ -struct fs_qfilestatv { - __u64 qfs_ino; /* inode number */ - __u64 qfs_nblks; /* number of BBs 512-byte-blks */ - __u32 qfs_nextents; /* number of extents */ - __u32 qfs_pad; /* pad for 8-byte alignment */ -}; - -struct fs_quota_statv { - __s8 qs_version; /* version for future changes */ - __u8 qs_pad1; /* pad for 16bit alignment */ - __u16 qs_flags; /* FS_QUOTA_.* flags */ - __u32 qs_incoredqs; /* number of dquots incore */ - struct fs_qfilestatv qs_uquota; /* user quota information */ - struct fs_qfilestatv qs_gquota; /* group quota information */ - struct fs_qfilestatv qs_pquota; /* project quota information */ - __s32 qs_btimelimit; /* limit for blks timer */ - __s32 qs_itimelimit; /* limit for inodes timer */ - __s32 qs_rtbtimelimit;/* limit for rt blks timer */ - __u16 qs_bwarnlimit; /* limit for num warnings */ - __u16 qs_iwarnlimit; /* limit for num warnings */ - __u64 qs_pad2[8]; /* for future proofing */ -}; - -#endif /* _LINUX_DQBLK_XFS_H */ diff --git a/src/linux/include/uapi/linux/elf-em.h b/src/linux/include/uapi/linux/elf-em.h deleted file mode 100644 index cb5d1a5..0000000 --- a/src/linux/include/uapi/linux/elf-em.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef _LINUX_ELF_EM_H -#define _LINUX_ELF_EM_H - -/* These constants define the various ELF target machines */ -#define EM_NONE 0 -#define EM_M32 1 -#define EM_SPARC 2 -#define EM_386 3 -#define EM_68K 4 -#define EM_88K 5 -#define EM_486 6 /* Perhaps disused */ -#define EM_860 7 -#define EM_MIPS 8 /* MIPS R3000 (officially, big-endian only) */ - /* Next two are historical and binaries and - modules of these types will be rejected by - Linux. */ -#define EM_MIPS_RS3_LE 10 /* MIPS R3000 little-endian */ -#define EM_MIPS_RS4_BE 10 /* MIPS R4000 big-endian */ - -#define EM_PARISC 15 /* HPPA */ -#define EM_SPARC32PLUS 18 /* Sun's "v8plus" */ -#define EM_PPC 20 /* PowerPC */ -#define EM_PPC64 21 /* PowerPC64 */ -#define EM_SPU 23 /* Cell BE SPU */ -#define EM_ARM 40 /* ARM 32 bit */ -#define EM_SH 42 /* SuperH */ -#define EM_SPARCV9 43 /* SPARC v9 64-bit */ -#define EM_H8_300 46 /* Renesas H8/300 */ -#define EM_IA_64 50 /* HP/Intel IA-64 */ -#define EM_X86_64 62 /* AMD x86-64 */ -#define EM_S390 22 /* IBM S/390 */ -#define EM_CRIS 76 /* Axis Communications 32-bit embedded processor */ -#define EM_M32R 88 /* Renesas M32R */ -#define EM_MN10300 89 /* Panasonic/MEI MN10300, AM33 */ -#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */ -#define EM_BLACKFIN 106 /* ADI Blackfin Processor */ -#define EM_ALTERA_NIOS2 113 /* Altera Nios II soft-core processor */ -#define EM_TI_C6000 140 /* TI C6X DSPs */ -#define EM_AARCH64 183 /* ARM 64 bit */ -#define EM_TILEPRO 188 /* Tilera TILEPro */ -#define EM_MICROBLAZE 189 /* Xilinx MicroBlaze */ -#define EM_TILEGX 191 /* Tilera TILE-Gx */ -#define EM_BPF 247 /* Linux BPF - in-kernel virtual machine */ -#define EM_FRV 0x5441 /* Fujitsu FR-V */ -#define EM_AVR32 0x18ad /* Atmel AVR32 */ - -/* - * This is an interim value that we will use until the committee comes - * up with a final number. - */ -#define EM_ALPHA 0x9026 - -/* Bogus old m32r magic number, used by old tools. */ -#define EM_CYGNUS_M32R 0x9041 -/* This is the old interim value for S/390 architecture */ -#define EM_S390_OLD 0xA390 -/* Also Panasonic/MEI MN10300, AM33 */ -#define EM_CYGNUS_MN10300 0xbeef - - -#endif /* _LINUX_ELF_EM_H */ diff --git a/src/linux/include/uapi/linux/elf.h b/src/linux/include/uapi/linux/elf.h deleted file mode 100644 index b59ee07..0000000 --- a/src/linux/include/uapi/linux/elf.h +++ /dev/null @@ -1,436 +0,0 @@ -#ifndef _UAPI_LINUX_ELF_H -#define _UAPI_LINUX_ELF_H - -#include -#include - -/* 32-bit ELF base types. */ -typedef __u32 Elf32_Addr; -typedef __u16 Elf32_Half; -typedef __u32 Elf32_Off; -typedef __s32 Elf32_Sword; -typedef __u32 Elf32_Word; - -/* 64-bit ELF base types. */ -typedef __u64 Elf64_Addr; -typedef __u16 Elf64_Half; -typedef __s16 Elf64_SHalf; -typedef __u64 Elf64_Off; -typedef __s32 Elf64_Sword; -typedef __u32 Elf64_Word; -typedef __u64 Elf64_Xword; -typedef __s64 Elf64_Sxword; - -/* These constants are for the segment types stored in the image headers */ -#define PT_NULL 0 -#define PT_LOAD 1 -#define PT_DYNAMIC 2 -#define PT_INTERP 3 -#define PT_NOTE 4 -#define PT_SHLIB 5 -#define PT_PHDR 6 -#define PT_TLS 7 /* Thread local storage segment */ -#define PT_LOOS 0x60000000 /* OS-specific */ -#define PT_HIOS 0x6fffffff /* OS-specific */ -#define PT_LOPROC 0x70000000 -#define PT_HIPROC 0x7fffffff -#define PT_GNU_EH_FRAME 0x6474e550 - -#define PT_GNU_STACK (PT_LOOS + 0x474e551) - -/* - * Extended Numbering - * - * If the real number of program header table entries is larger than - * or equal to PN_XNUM(0xffff), it is set to sh_info field of the - * section header at index 0, and PN_XNUM is set to e_phnum - * field. Otherwise, the section header at index 0 is zero - * initialized, if it exists. - * - * Specifications are available in: - * - * - Oracle: Linker and Libraries. - * Part No: 817–1984–19, August 2011. - * http://docs.oracle.com/cd/E18752_01/pdf/817-1984.pdf - * - * - System V ABI AMD64 Architecture Processor Supplement - * Draft Version 0.99.4, - * January 13, 2010. - * http://www.cs.washington.edu/education/courses/cse351/12wi/supp-docs/abi.pdf - */ -#define PN_XNUM 0xffff - -/* These constants define the different elf file types */ -#define ET_NONE 0 -#define ET_REL 1 -#define ET_EXEC 2 -#define ET_DYN 3 -#define ET_CORE 4 -#define ET_LOPROC 0xff00 -#define ET_HIPROC 0xffff - -/* This is the info that is needed to parse the dynamic section of the file */ -#define DT_NULL 0 -#define DT_NEEDED 1 -#define DT_PLTRELSZ 2 -#define DT_PLTGOT 3 -#define DT_HASH 4 -#define DT_STRTAB 5 -#define DT_SYMTAB 6 -#define DT_RELA 7 -#define DT_RELASZ 8 -#define DT_RELAENT 9 -#define DT_STRSZ 10 -#define DT_SYMENT 11 -#define DT_INIT 12 -#define DT_FINI 13 -#define DT_SONAME 14 -#define DT_RPATH 15 -#define DT_SYMBOLIC 16 -#define DT_REL 17 -#define DT_RELSZ 18 -#define DT_RELENT 19 -#define DT_PLTREL 20 -#define DT_DEBUG 21 -#define DT_TEXTREL 22 -#define DT_JMPREL 23 -#define DT_ENCODING 32 -#define OLD_DT_LOOS 0x60000000 -#define DT_LOOS 0x6000000d -#define DT_HIOS 0x6ffff000 -#define DT_VALRNGLO 0x6ffffd00 -#define DT_VALRNGHI 0x6ffffdff -#define DT_ADDRRNGLO 0x6ffffe00 -#define DT_ADDRRNGHI 0x6ffffeff -#define DT_VERSYM 0x6ffffff0 -#define DT_RELACOUNT 0x6ffffff9 -#define DT_RELCOUNT 0x6ffffffa -#define DT_FLAGS_1 0x6ffffffb -#define DT_VERDEF 0x6ffffffc -#define DT_VERDEFNUM 0x6ffffffd -#define DT_VERNEED 0x6ffffffe -#define DT_VERNEEDNUM 0x6fffffff -#define OLD_DT_HIOS 0x6fffffff -#define DT_LOPROC 0x70000000 -#define DT_HIPROC 0x7fffffff - -/* This info is needed when parsing the symbol table */ -#define STB_LOCAL 0 -#define STB_GLOBAL 1 -#define STB_WEAK 2 - -#define STT_NOTYPE 0 -#define STT_OBJECT 1 -#define STT_FUNC 2 -#define STT_SECTION 3 -#define STT_FILE 4 -#define STT_COMMON 5 -#define STT_TLS 6 - -#define ELF_ST_BIND(x) ((x) >> 4) -#define ELF_ST_TYPE(x) (((unsigned int) x) & 0xf) -#define ELF32_ST_BIND(x) ELF_ST_BIND(x) -#define ELF32_ST_TYPE(x) ELF_ST_TYPE(x) -#define ELF64_ST_BIND(x) ELF_ST_BIND(x) -#define ELF64_ST_TYPE(x) ELF_ST_TYPE(x) - -typedef struct dynamic{ - Elf32_Sword d_tag; - union{ - Elf32_Sword d_val; - Elf32_Addr d_ptr; - } d_un; -} Elf32_Dyn; - -typedef struct { - Elf64_Sxword d_tag; /* entry tag value */ - union { - Elf64_Xword d_val; - Elf64_Addr d_ptr; - } d_un; -} Elf64_Dyn; - -/* The following are used with relocations */ -#define ELF32_R_SYM(x) ((x) >> 8) -#define ELF32_R_TYPE(x) ((x) & 0xff) - -#define ELF64_R_SYM(i) ((i) >> 32) -#define ELF64_R_TYPE(i) ((i) & 0xffffffff) - -typedef struct elf32_rel { - Elf32_Addr r_offset; - Elf32_Word r_info; -} Elf32_Rel; - -typedef struct elf64_rel { - Elf64_Addr r_offset; /* Location at which to apply the action */ - Elf64_Xword r_info; /* index and type of relocation */ -} Elf64_Rel; - -typedef struct elf32_rela{ - Elf32_Addr r_offset; - Elf32_Word r_info; - Elf32_Sword r_addend; -} Elf32_Rela; - -typedef struct elf64_rela { - Elf64_Addr r_offset; /* Location at which to apply the action */ - Elf64_Xword r_info; /* index and type of relocation */ - Elf64_Sxword r_addend; /* Constant addend used to compute value */ -} Elf64_Rela; - -typedef struct elf32_sym{ - Elf32_Word st_name; - Elf32_Addr st_value; - Elf32_Word st_size; - unsigned char st_info; - unsigned char st_other; - Elf32_Half st_shndx; -} Elf32_Sym; - -typedef struct elf64_sym { - Elf64_Word st_name; /* Symbol name, index in string tbl */ - unsigned char st_info; /* Type and binding attributes */ - unsigned char st_other; /* No defined meaning, 0 */ - Elf64_Half st_shndx; /* Associated section index */ - Elf64_Addr st_value; /* Value of the symbol */ - Elf64_Xword st_size; /* Associated symbol size */ -} Elf64_Sym; - - -#define EI_NIDENT 16 - -typedef struct elf32_hdr{ - unsigned char e_ident[EI_NIDENT]; - Elf32_Half e_type; - Elf32_Half e_machine; - Elf32_Word e_version; - Elf32_Addr e_entry; /* Entry point */ - Elf32_Off e_phoff; - Elf32_Off e_shoff; - Elf32_Word e_flags; - Elf32_Half e_ehsize; - Elf32_Half e_phentsize; - Elf32_Half e_phnum; - Elf32_Half e_shentsize; - Elf32_Half e_shnum; - Elf32_Half e_shstrndx; -} Elf32_Ehdr; - -typedef struct elf64_hdr { - unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */ - Elf64_Half e_type; - Elf64_Half e_machine; - Elf64_Word e_version; - Elf64_Addr e_entry; /* Entry point virtual address */ - Elf64_Off e_phoff; /* Program header table file offset */ - Elf64_Off e_shoff; /* Section header table file offset */ - Elf64_Word e_flags; - Elf64_Half e_ehsize; - Elf64_Half e_phentsize; - Elf64_Half e_phnum; - Elf64_Half e_shentsize; - Elf64_Half e_shnum; - Elf64_Half e_shstrndx; -} Elf64_Ehdr; - -/* These constants define the permissions on sections in the program - header, p_flags. */ -#define PF_R 0x4 -#define PF_W 0x2 -#define PF_X 0x1 - -typedef struct elf32_phdr{ - Elf32_Word p_type; - Elf32_Off p_offset; - Elf32_Addr p_vaddr; - Elf32_Addr p_paddr; - Elf32_Word p_filesz; - Elf32_Word p_memsz; - Elf32_Word p_flags; - Elf32_Word p_align; -} Elf32_Phdr; - -typedef struct elf64_phdr { - Elf64_Word p_type; - Elf64_Word p_flags; - Elf64_Off p_offset; /* Segment file offset */ - Elf64_Addr p_vaddr; /* Segment virtual address */ - Elf64_Addr p_paddr; /* Segment physical address */ - Elf64_Xword p_filesz; /* Segment size in file */ - Elf64_Xword p_memsz; /* Segment size in memory */ - Elf64_Xword p_align; /* Segment alignment, file & memory */ -} Elf64_Phdr; - -/* sh_type */ -#define SHT_NULL 0 -#define SHT_PROGBITS 1 -#define SHT_SYMTAB 2 -#define SHT_STRTAB 3 -#define SHT_RELA 4 -#define SHT_HASH 5 -#define SHT_DYNAMIC 6 -#define SHT_NOTE 7 -#define SHT_NOBITS 8 -#define SHT_REL 9 -#define SHT_SHLIB 10 -#define SHT_DYNSYM 11 -#define SHT_NUM 12 -#define SHT_LOPROC 0x70000000 -#define SHT_HIPROC 0x7fffffff -#define SHT_LOUSER 0x80000000 -#define SHT_HIUSER 0xffffffff - -/* sh_flags */ -#define SHF_WRITE 0x1 -#define SHF_ALLOC 0x2 -#define SHF_EXECINSTR 0x4 -#define SHF_RELA_LIVEPATCH 0x00100000 -#define SHF_RO_AFTER_INIT 0x00200000 -#define SHF_MASKPROC 0xf0000000 - -/* special section indexes */ -#define SHN_UNDEF 0 -#define SHN_LORESERVE 0xff00 -#define SHN_LOPROC 0xff00 -#define SHN_HIPROC 0xff1f -#define SHN_LIVEPATCH 0xff20 -#define SHN_ABS 0xfff1 -#define SHN_COMMON 0xfff2 -#define SHN_HIRESERVE 0xffff - -typedef struct elf32_shdr { - Elf32_Word sh_name; - Elf32_Word sh_type; - Elf32_Word sh_flags; - Elf32_Addr sh_addr; - Elf32_Off sh_offset; - Elf32_Word sh_size; - Elf32_Word sh_link; - Elf32_Word sh_info; - Elf32_Word sh_addralign; - Elf32_Word sh_entsize; -} Elf32_Shdr; - -typedef struct elf64_shdr { - Elf64_Word sh_name; /* Section name, index in string tbl */ - Elf64_Word sh_type; /* Type of section */ - Elf64_Xword sh_flags; /* Miscellaneous section attributes */ - Elf64_Addr sh_addr; /* Section virtual addr at execution */ - Elf64_Off sh_offset; /* Section file offset */ - Elf64_Xword sh_size; /* Size of section in bytes */ - Elf64_Word sh_link; /* Index of another section */ - Elf64_Word sh_info; /* Additional section information */ - Elf64_Xword sh_addralign; /* Section alignment */ - Elf64_Xword sh_entsize; /* Entry size if section holds table */ -} Elf64_Shdr; - -#define EI_MAG0 0 /* e_ident[] indexes */ -#define EI_MAG1 1 -#define EI_MAG2 2 -#define EI_MAG3 3 -#define EI_CLASS 4 -#define EI_DATA 5 -#define EI_VERSION 6 -#define EI_OSABI 7 -#define EI_PAD 8 - -#define ELFMAG0 0x7f /* EI_MAG */ -#define ELFMAG1 'E' -#define ELFMAG2 'L' -#define ELFMAG3 'F' -#define ELFMAG "\177ELF" -#define SELFMAG 4 - -#define ELFCLASSNONE 0 /* EI_CLASS */ -#define ELFCLASS32 1 -#define ELFCLASS64 2 -#define ELFCLASSNUM 3 - -#define ELFDATANONE 0 /* e_ident[EI_DATA] */ -#define ELFDATA2LSB 1 -#define ELFDATA2MSB 2 - -#define EV_NONE 0 /* e_version, EI_VERSION */ -#define EV_CURRENT 1 -#define EV_NUM 2 - -#define ELFOSABI_NONE 0 -#define ELFOSABI_LINUX 3 - -#ifndef ELF_OSABI -#define ELF_OSABI ELFOSABI_NONE -#endif - -/* - * Notes used in ET_CORE. Architectures export some of the arch register sets - * using the corresponding note types via the PTRACE_GETREGSET and - * PTRACE_SETREGSET requests. - */ -#define NT_PRSTATUS 1 -#define NT_PRFPREG 2 -#define NT_PRPSINFO 3 -#define NT_TASKSTRUCT 4 -#define NT_AUXV 6 -/* - * Note to userspace developers: size of NT_SIGINFO note may increase - * in the future to accomodate more fields, don't assume it is fixed! - */ -#define NT_SIGINFO 0x53494749 -#define NT_FILE 0x46494c45 -#define NT_PRXFPREG 0x46e62b7f /* copied from gdb5.1/include/elf/common.h */ -#define NT_PPC_VMX 0x100 /* PowerPC Altivec/VMX registers */ -#define NT_PPC_SPE 0x101 /* PowerPC SPE/EVR registers */ -#define NT_PPC_VSX 0x102 /* PowerPC VSX registers */ -#define NT_PPC_TAR 0x103 /* Target Address Register */ -#define NT_PPC_PPR 0x104 /* Program Priority Register */ -#define NT_PPC_DSCR 0x105 /* Data Stream Control Register */ -#define NT_PPC_EBB 0x106 /* Event Based Branch Registers */ -#define NT_PPC_PMU 0x107 /* Performance Monitor Registers */ -#define NT_PPC_TM_CGPR 0x108 /* TM checkpointed GPR Registers */ -#define NT_PPC_TM_CFPR 0x109 /* TM checkpointed FPR Registers */ -#define NT_PPC_TM_CVMX 0x10a /* TM checkpointed VMX Registers */ -#define NT_PPC_TM_CVSX 0x10b /* TM checkpointed VSX Registers */ -#define NT_PPC_TM_SPR 0x10c /* TM Special Purpose Registers */ -#define NT_PPC_TM_CTAR 0x10d /* TM checkpointed Target Address Register */ -#define NT_PPC_TM_CPPR 0x10e /* TM checkpointed Program Priority Register */ -#define NT_PPC_TM_CDSCR 0x10f /* TM checkpointed Data Stream Control Register */ -#define NT_386_TLS 0x200 /* i386 TLS slots (struct user_desc) */ -#define NT_386_IOPERM 0x201 /* x86 io permission bitmap (1=deny) */ -#define NT_X86_XSTATE 0x202 /* x86 extended state using xsave */ -#define NT_S390_HIGH_GPRS 0x300 /* s390 upper register halves */ -#define NT_S390_TIMER 0x301 /* s390 timer register */ -#define NT_S390_TODCMP 0x302 /* s390 TOD clock comparator register */ -#define NT_S390_TODPREG 0x303 /* s390 TOD programmable register */ -#define NT_S390_CTRS 0x304 /* s390 control registers */ -#define NT_S390_PREFIX 0x305 /* s390 prefix register */ -#define NT_S390_LAST_BREAK 0x306 /* s390 breaking event address */ -#define NT_S390_SYSTEM_CALL 0x307 /* s390 system call restart data */ -#define NT_S390_TDB 0x308 /* s390 transaction diagnostic block */ -#define NT_S390_VXRS_LOW 0x309 /* s390 vector registers 0-15 upper half */ -#define NT_S390_VXRS_HIGH 0x30a /* s390 vector registers 16-31 */ -#define NT_ARM_VFP 0x400 /* ARM VFP/NEON registers */ -#define NT_ARM_TLS 0x401 /* ARM TLS register */ -#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */ -#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */ -#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */ -#define NT_METAG_CBUF 0x500 /* Metag catch buffer registers */ -#define NT_METAG_RPIPE 0x501 /* Metag read pipeline state */ -#define NT_METAG_TLS 0x502 /* Metag TLS pointer */ - - -/* Note header in a PT_NOTE section */ -typedef struct elf32_note { - Elf32_Word n_namesz; /* Name size */ - Elf32_Word n_descsz; /* Content size */ - Elf32_Word n_type; /* Content type */ -} Elf32_Nhdr; - -/* Note header in a PT_NOTE section */ -typedef struct elf64_note { - Elf64_Word n_namesz; /* Name size */ - Elf64_Word n_descsz; /* Content size */ - Elf64_Word n_type; /* Content type */ -} Elf64_Nhdr; - -#endif /* _UAPI_LINUX_ELF_H */ diff --git a/src/linux/include/uapi/linux/errno.h b/src/linux/include/uapi/linux/errno.h deleted file mode 100644 index 70f2bd3..0000000 --- a/src/linux/include/uapi/linux/errno.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/src/linux/include/uapi/linux/errqueue.h b/src/linux/include/uapi/linux/errqueue.h deleted file mode 100644 index 07bdce1..0000000 --- a/src/linux/include/uapi/linux/errqueue.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef _UAPI_LINUX_ERRQUEUE_H -#define _UAPI_LINUX_ERRQUEUE_H - -#include - -struct sock_extended_err { - __u32 ee_errno; - __u8 ee_origin; - __u8 ee_type; - __u8 ee_code; - __u8 ee_pad; - __u32 ee_info; - __u32 ee_data; -}; - -#define SO_EE_ORIGIN_NONE 0 -#define SO_EE_ORIGIN_LOCAL 1 -#define SO_EE_ORIGIN_ICMP 2 -#define SO_EE_ORIGIN_ICMP6 3 -#define SO_EE_ORIGIN_TXSTATUS 4 -#define SO_EE_ORIGIN_TIMESTAMPING SO_EE_ORIGIN_TXSTATUS - -#define SO_EE_OFFENDER(ee) ((struct sockaddr*)((ee)+1)) - -/** - * struct scm_timestamping - timestamps exposed through cmsg - * - * The timestamping interfaces SO_TIMESTAMPING, MSG_TSTAMP_* - * communicate network timestamps by passing this struct in a cmsg with - * recvmsg(). See Documentation/networking/timestamping.txt for details. - */ -struct scm_timestamping { - struct timespec ts[3]; -}; - -/* The type of scm_timestamping, passed in sock_extended_err ee_info. - * This defines the type of ts[0]. For SCM_TSTAMP_SND only, if ts[0] - * is zero, then this is a hardware timestamp and recorded in ts[2]. - */ -enum { - SCM_TSTAMP_SND, /* driver passed skb to NIC, or HW */ - SCM_TSTAMP_SCHED, /* data entered the packet scheduler */ - SCM_TSTAMP_ACK, /* data acknowledged by peer */ -}; - -#endif /* _UAPI_LINUX_ERRQUEUE_H */ diff --git a/src/linux/include/uapi/linux/ethtool.h b/src/linux/include/uapi/linux/ethtool.h deleted file mode 100644 index 8e54723..0000000 --- a/src/linux/include/uapi/linux/ethtool.h +++ /dev/null @@ -1,1747 +0,0 @@ -/* - * ethtool.h: Defines for Linux ethtool. - * - * Copyright (C) 1998 David S. Miller (davem@redhat.com) - * Copyright 2001 Jeff Garzik - * Portions Copyright 2001 Sun Microsystems (thockin@sun.com) - * Portions Copyright 2002 Intel (eli.kupermann@intel.com, - * christopher.leech@intel.com, - * scott.feldman@intel.com) - * Portions Copyright (C) Sun Microsystems 2008 - */ - -#ifndef _UAPI_LINUX_ETHTOOL_H -#define _UAPI_LINUX_ETHTOOL_H - -#include -#include -#include - -#ifndef __KERNEL__ -#include /* for INT_MAX */ -#endif - -/* All structures exposed to userland should be defined such that they - * have the same layout for 32-bit and 64-bit userland. - */ - -/** - * struct ethtool_cmd - DEPRECATED, link control and status - * This structure is DEPRECATED, please use struct ethtool_link_settings. - * @cmd: Command number = %ETHTOOL_GSET or %ETHTOOL_SSET - * @supported: Bitmask of %SUPPORTED_* flags for the link modes, - * physical connectors and other link features for which the - * interface supports autonegotiation or auto-detection. - * Read-only. - * @advertising: Bitmask of %ADVERTISED_* flags for the link modes, - * physical connectors and other link features that are - * advertised through autonegotiation or enabled for - * auto-detection. - * @speed: Low bits of the speed, 1Mb units, 0 to INT_MAX or SPEED_UNKNOWN - * @duplex: Duplex mode; one of %DUPLEX_* - * @port: Physical connector type; one of %PORT_* - * @phy_address: MDIO address of PHY (transceiver); 0 or 255 if not - * applicable. For clause 45 PHYs this is the PRTAD. - * @transceiver: Historically used to distinguish different possible - * PHY types, but not in a consistent way. Deprecated. - * @autoneg: Enable/disable autonegotiation and auto-detection; - * either %AUTONEG_DISABLE or %AUTONEG_ENABLE - * @mdio_support: Bitmask of %ETH_MDIO_SUPPORTS_* flags for the MDIO - * protocols supported by the interface; 0 if unknown. - * Read-only. - * @maxtxpkt: Historically used to report TX IRQ coalescing; now - * obsoleted by &struct ethtool_coalesce. Read-only; deprecated. - * @maxrxpkt: Historically used to report RX IRQ coalescing; now - * obsoleted by &struct ethtool_coalesce. Read-only; deprecated. - * @speed_hi: High bits of the speed, 1Mb units, 0 to INT_MAX or SPEED_UNKNOWN - * @eth_tp_mdix: Ethernet twisted-pair MDI(-X) status; one of - * %ETH_TP_MDI_*. If the status is unknown or not applicable, the - * value will be %ETH_TP_MDI_INVALID. Read-only. - * @eth_tp_mdix_ctrl: Ethernet twisted pair MDI(-X) control; one of - * %ETH_TP_MDI_*. If MDI(-X) control is not implemented, reads - * yield %ETH_TP_MDI_INVALID and writes may be ignored or rejected. - * When written successfully, the link should be renegotiated if - * necessary. - * @lp_advertising: Bitmask of %ADVERTISED_* flags for the link modes - * and other link features that the link partner advertised - * through autonegotiation; 0 if unknown or not applicable. - * Read-only. - * - * The link speed in Mbps is split between @speed and @speed_hi. Use - * the ethtool_cmd_speed() and ethtool_cmd_speed_set() functions to - * access it. - * - * If autonegotiation is disabled, the speed and @duplex represent the - * fixed link mode and are writable if the driver supports multiple - * link modes. If it is enabled then they are read-only; if the link - * is up they represent the negotiated link mode; if the link is down, - * the speed is 0, %SPEED_UNKNOWN or the highest enabled speed and - * @duplex is %DUPLEX_UNKNOWN or the best enabled duplex mode. - * - * Some hardware interfaces may have multiple PHYs and/or physical - * connectors fitted or do not allow the driver to detect which are - * fitted. For these interfaces @port and/or @phy_address may be - * writable, possibly dependent on @autoneg being %AUTONEG_DISABLE. - * Otherwise, attempts to write different values may be ignored or - * rejected. - * - * Users should assume that all fields not marked read-only are - * writable and subject to validation by the driver. They should use - * %ETHTOOL_GSET to get the current values before making specific - * changes and then applying them with %ETHTOOL_SSET. - * - * Drivers that implement set_settings() should validate all fields - * other than @cmd that are not described as read-only or deprecated, - * and must ignore all fields described as read-only. - * - * Deprecated fields should be ignored by both users and drivers. - */ -struct ethtool_cmd { - __u32 cmd; - __u32 supported; - __u32 advertising; - __u16 speed; - __u8 duplex; - __u8 port; - __u8 phy_address; - __u8 transceiver; - __u8 autoneg; - __u8 mdio_support; - __u32 maxtxpkt; - __u32 maxrxpkt; - __u16 speed_hi; - __u8 eth_tp_mdix; - __u8 eth_tp_mdix_ctrl; - __u32 lp_advertising; - __u32 reserved[2]; -}; - -static inline void ethtool_cmd_speed_set(struct ethtool_cmd *ep, - __u32 speed) -{ - ep->speed = (__u16)(speed & 0xFFFF); - ep->speed_hi = (__u16)(speed >> 16); -} - -static inline __u32 ethtool_cmd_speed(const struct ethtool_cmd *ep) -{ - return (ep->speed_hi << 16) | ep->speed; -} - -/* Device supports clause 22 register access to PHY or peripherals - * using the interface defined in . This should not be - * set if there are known to be no such peripherals present or if - * the driver only emulates clause 22 registers for compatibility. - */ -#define ETH_MDIO_SUPPORTS_C22 1 - -/* Device supports clause 45 register access to PHY or peripherals - * using the interface defined in and . - * This should not be set if there are known to be no such peripherals - * present. - */ -#define ETH_MDIO_SUPPORTS_C45 2 - -#define ETHTOOL_FWVERS_LEN 32 -#define ETHTOOL_BUSINFO_LEN 32 -#define ETHTOOL_EROMVERS_LEN 32 - -/** - * struct ethtool_drvinfo - general driver and device information - * @cmd: Command number = %ETHTOOL_GDRVINFO - * @driver: Driver short name. This should normally match the name - * in its bus driver structure (e.g. pci_driver::name). Must - * not be an empty string. - * @version: Driver version string; may be an empty string - * @fw_version: Firmware version string; may be an empty string - * @erom_version: Expansion ROM version string; may be an empty string - * @bus_info: Device bus address. This should match the dev_name() - * string for the underlying bus device, if there is one. May be - * an empty string. - * @n_priv_flags: Number of flags valid for %ETHTOOL_GPFLAGS and - * %ETHTOOL_SPFLAGS commands; also the number of strings in the - * %ETH_SS_PRIV_FLAGS set - * @n_stats: Number of u64 statistics returned by the %ETHTOOL_GSTATS - * command; also the number of strings in the %ETH_SS_STATS set - * @testinfo_len: Number of results returned by the %ETHTOOL_TEST - * command; also the number of strings in the %ETH_SS_TEST set - * @eedump_len: Size of EEPROM accessible through the %ETHTOOL_GEEPROM - * and %ETHTOOL_SEEPROM commands, in bytes - * @regdump_len: Size of register dump returned by the %ETHTOOL_GREGS - * command, in bytes - * - * Users can use the %ETHTOOL_GSSET_INFO command to get the number of - * strings in any string set (from Linux 2.6.34). - * - * Drivers should set at most @driver, @version, @fw_version and - * @bus_info in their get_drvinfo() implementation. The ethtool - * core fills in the other fields using other driver operations. - */ -struct ethtool_drvinfo { - __u32 cmd; - char driver[32]; - char version[32]; - char fw_version[ETHTOOL_FWVERS_LEN]; - char bus_info[ETHTOOL_BUSINFO_LEN]; - char erom_version[ETHTOOL_EROMVERS_LEN]; - char reserved2[12]; - __u32 n_priv_flags; - __u32 n_stats; - __u32 testinfo_len; - __u32 eedump_len; - __u32 regdump_len; -}; - -#define SOPASS_MAX 6 - -/** - * struct ethtool_wolinfo - Wake-On-Lan configuration - * @cmd: Command number = %ETHTOOL_GWOL or %ETHTOOL_SWOL - * @supported: Bitmask of %WAKE_* flags for supported Wake-On-Lan modes. - * Read-only. - * @wolopts: Bitmask of %WAKE_* flags for enabled Wake-On-Lan modes. - * @sopass: SecureOn(tm) password; meaningful only if %WAKE_MAGICSECURE - * is set in @wolopts. - */ -struct ethtool_wolinfo { - __u32 cmd; - __u32 supported; - __u32 wolopts; - __u8 sopass[SOPASS_MAX]; -}; - -/* for passing single values */ -struct ethtool_value { - __u32 cmd; - __u32 data; -}; - -enum tunable_id { - ETHTOOL_ID_UNSPEC, - ETHTOOL_RX_COPYBREAK, - ETHTOOL_TX_COPYBREAK, - /* - * Add your fresh new tubale attribute above and remember to update - * tunable_strings[] in net/core/ethtool.c - */ - __ETHTOOL_TUNABLE_COUNT, -}; - -enum tunable_type_id { - ETHTOOL_TUNABLE_UNSPEC, - ETHTOOL_TUNABLE_U8, - ETHTOOL_TUNABLE_U16, - ETHTOOL_TUNABLE_U32, - ETHTOOL_TUNABLE_U64, - ETHTOOL_TUNABLE_STRING, - ETHTOOL_TUNABLE_S8, - ETHTOOL_TUNABLE_S16, - ETHTOOL_TUNABLE_S32, - ETHTOOL_TUNABLE_S64, -}; - -struct ethtool_tunable { - __u32 cmd; - __u32 id; - __u32 type_id; - __u32 len; - void *data[0]; -}; - -/** - * struct ethtool_regs - hardware register dump - * @cmd: Command number = %ETHTOOL_GREGS - * @version: Dump format version. This is driver-specific and may - * distinguish different chips/revisions. Drivers must use new - * version numbers whenever the dump format changes in an - * incompatible way. - * @len: On entry, the real length of @data. On return, the number of - * bytes used. - * @data: Buffer for the register dump - * - * Users should use %ETHTOOL_GDRVINFO to find the maximum length of - * a register dump for the interface. They must allocate the buffer - * immediately following this structure. - */ -struct ethtool_regs { - __u32 cmd; - __u32 version; - __u32 len; - __u8 data[0]; -}; - -/** - * struct ethtool_eeprom - EEPROM dump - * @cmd: Command number = %ETHTOOL_GEEPROM, %ETHTOOL_GMODULEEEPROM or - * %ETHTOOL_SEEPROM - * @magic: A 'magic cookie' value to guard against accidental changes. - * The value passed in to %ETHTOOL_SEEPROM must match the value - * returned by %ETHTOOL_GEEPROM for the same device. This is - * unused when @cmd is %ETHTOOL_GMODULEEEPROM. - * @offset: Offset within the EEPROM to begin reading/writing, in bytes - * @len: On entry, number of bytes to read/write. On successful - * return, number of bytes actually read/written. In case of - * error, this may indicate at what point the error occurred. - * @data: Buffer to read/write from - * - * Users may use %ETHTOOL_GDRVINFO or %ETHTOOL_GMODULEINFO to find - * the length of an on-board or module EEPROM, respectively. They - * must allocate the buffer immediately following this structure. - */ -struct ethtool_eeprom { - __u32 cmd; - __u32 magic; - __u32 offset; - __u32 len; - __u8 data[0]; -}; - -/** - * struct ethtool_eee - Energy Efficient Ethernet information - * @cmd: ETHTOOL_{G,S}EEE - * @supported: Mask of %SUPPORTED_* flags for the speed/duplex combinations - * for which there is EEE support. - * @advertised: Mask of %ADVERTISED_* flags for the speed/duplex combinations - * advertised as eee capable. - * @lp_advertised: Mask of %ADVERTISED_* flags for the speed/duplex - * combinations advertised by the link partner as eee capable. - * @eee_active: Result of the eee auto negotiation. - * @eee_enabled: EEE configured mode (enabled/disabled). - * @tx_lpi_enabled: Whether the interface should assert its tx lpi, given - * that eee was negotiated. - * @tx_lpi_timer: Time in microseconds the interface delays prior to asserting - * its tx lpi (after reaching 'idle' state). Effective only when eee - * was negotiated and tx_lpi_enabled was set. - */ -struct ethtool_eee { - __u32 cmd; - __u32 supported; - __u32 advertised; - __u32 lp_advertised; - __u32 eee_active; - __u32 eee_enabled; - __u32 tx_lpi_enabled; - __u32 tx_lpi_timer; - __u32 reserved[2]; -}; - -/** - * struct ethtool_modinfo - plugin module eeprom information - * @cmd: %ETHTOOL_GMODULEINFO - * @type: Standard the module information conforms to %ETH_MODULE_SFF_xxxx - * @eeprom_len: Length of the eeprom - * - * This structure is used to return the information to - * properly size memory for a subsequent call to %ETHTOOL_GMODULEEEPROM. - * The type code indicates the eeprom data format - */ -struct ethtool_modinfo { - __u32 cmd; - __u32 type; - __u32 eeprom_len; - __u32 reserved[8]; -}; - -/** - * struct ethtool_coalesce - coalescing parameters for IRQs and stats updates - * @cmd: ETHTOOL_{G,S}COALESCE - * @rx_coalesce_usecs: How many usecs to delay an RX interrupt after - * a packet arrives. - * @rx_max_coalesced_frames: Maximum number of packets to receive - * before an RX interrupt. - * @rx_coalesce_usecs_irq: Same as @rx_coalesce_usecs, except that - * this value applies while an IRQ is being serviced by the host. - * @rx_max_coalesced_frames_irq: Same as @rx_max_coalesced_frames, - * except that this value applies while an IRQ is being serviced - * by the host. - * @tx_coalesce_usecs: How many usecs to delay a TX interrupt after - * a packet is sent. - * @tx_max_coalesced_frames: Maximum number of packets to be sent - * before a TX interrupt. - * @tx_coalesce_usecs_irq: Same as @tx_coalesce_usecs, except that - * this value applies while an IRQ is being serviced by the host. - * @tx_max_coalesced_frames_irq: Same as @tx_max_coalesced_frames, - * except that this value applies while an IRQ is being serviced - * by the host. - * @stats_block_coalesce_usecs: How many usecs to delay in-memory - * statistics block updates. Some drivers do not have an - * in-memory statistic block, and in such cases this value is - * ignored. This value must not be zero. - * @use_adaptive_rx_coalesce: Enable adaptive RX coalescing. - * @use_adaptive_tx_coalesce: Enable adaptive TX coalescing. - * @pkt_rate_low: Threshold for low packet rate (packets per second). - * @rx_coalesce_usecs_low: How many usecs to delay an RX interrupt after - * a packet arrives, when the packet rate is below @pkt_rate_low. - * @rx_max_coalesced_frames_low: Maximum number of packets to be received - * before an RX interrupt, when the packet rate is below @pkt_rate_low. - * @tx_coalesce_usecs_low: How many usecs to delay a TX interrupt after - * a packet is sent, when the packet rate is below @pkt_rate_low. - * @tx_max_coalesced_frames_low: Maximum nuumber of packets to be sent before - * a TX interrupt, when the packet rate is below @pkt_rate_low. - * @pkt_rate_high: Threshold for high packet rate (packets per second). - * @rx_coalesce_usecs_high: How many usecs to delay an RX interrupt after - * a packet arrives, when the packet rate is above @pkt_rate_high. - * @rx_max_coalesced_frames_high: Maximum number of packets to be received - * before an RX interrupt, when the packet rate is above @pkt_rate_high. - * @tx_coalesce_usecs_high: How many usecs to delay a TX interrupt after - * a packet is sent, when the packet rate is above @pkt_rate_high. - * @tx_max_coalesced_frames_high: Maximum number of packets to be sent before - * a TX interrupt, when the packet rate is above @pkt_rate_high. - * @rate_sample_interval: How often to do adaptive coalescing packet rate - * sampling, measured in seconds. Must not be zero. - * - * Each pair of (usecs, max_frames) fields specifies that interrupts - * should be coalesced until - * (usecs > 0 && time_since_first_completion >= usecs) || - * (max_frames > 0 && completed_frames >= max_frames) - * - * It is illegal to set both usecs and max_frames to zero as this - * would cause interrupts to never be generated. To disable - * coalescing, set usecs = 0 and max_frames = 1. - * - * Some implementations ignore the value of max_frames and use the - * condition time_since_first_completion >= usecs - * - * This is deprecated. Drivers for hardware that does not support - * counting completions should validate that max_frames == !rx_usecs. - * - * Adaptive RX/TX coalescing is an algorithm implemented by some - * drivers to improve latency under low packet rates and improve - * throughput under high packet rates. Some drivers only implement - * one of RX or TX adaptive coalescing. Anything not implemented by - * the driver causes these values to be silently ignored. - * - * When the packet rate is below @pkt_rate_high but above - * @pkt_rate_low (both measured in packets per second) the - * normal {rx,tx}_* coalescing parameters are used. - */ -struct ethtool_coalesce { - __u32 cmd; - __u32 rx_coalesce_usecs; - __u32 rx_max_coalesced_frames; - __u32 rx_coalesce_usecs_irq; - __u32 rx_max_coalesced_frames_irq; - __u32 tx_coalesce_usecs; - __u32 tx_max_coalesced_frames; - __u32 tx_coalesce_usecs_irq; - __u32 tx_max_coalesced_frames_irq; - __u32 stats_block_coalesce_usecs; - __u32 use_adaptive_rx_coalesce; - __u32 use_adaptive_tx_coalesce; - __u32 pkt_rate_low; - __u32 rx_coalesce_usecs_low; - __u32 rx_max_coalesced_frames_low; - __u32 tx_coalesce_usecs_low; - __u32 tx_max_coalesced_frames_low; - __u32 pkt_rate_high; - __u32 rx_coalesce_usecs_high; - __u32 rx_max_coalesced_frames_high; - __u32 tx_coalesce_usecs_high; - __u32 tx_max_coalesced_frames_high; - __u32 rate_sample_interval; -}; - -/** - * struct ethtool_ringparam - RX/TX ring parameters - * @cmd: Command number = %ETHTOOL_GRINGPARAM or %ETHTOOL_SRINGPARAM - * @rx_max_pending: Maximum supported number of pending entries per - * RX ring. Read-only. - * @rx_mini_max_pending: Maximum supported number of pending entries - * per RX mini ring. Read-only. - * @rx_jumbo_max_pending: Maximum supported number of pending entries - * per RX jumbo ring. Read-only. - * @tx_max_pending: Maximum supported number of pending entries per - * TX ring. Read-only. - * @rx_pending: Current maximum number of pending entries per RX ring - * @rx_mini_pending: Current maximum number of pending entries per RX - * mini ring - * @rx_jumbo_pending: Current maximum number of pending entries per RX - * jumbo ring - * @tx_pending: Current maximum supported number of pending entries - * per TX ring - * - * If the interface does not have separate RX mini and/or jumbo rings, - * @rx_mini_max_pending and/or @rx_jumbo_max_pending will be 0. - * - * There may also be driver-dependent minimum values for the number - * of entries per ring. - */ -struct ethtool_ringparam { - __u32 cmd; - __u32 rx_max_pending; - __u32 rx_mini_max_pending; - __u32 rx_jumbo_max_pending; - __u32 tx_max_pending; - __u32 rx_pending; - __u32 rx_mini_pending; - __u32 rx_jumbo_pending; - __u32 tx_pending; -}; - -/** - * struct ethtool_channels - configuring number of network channel - * @cmd: ETHTOOL_{G,S}CHANNELS - * @max_rx: Read only. Maximum number of receive channel the driver support. - * @max_tx: Read only. Maximum number of transmit channel the driver support. - * @max_other: Read only. Maximum number of other channel the driver support. - * @max_combined: Read only. Maximum number of combined channel the driver - * support. Set of queues RX, TX or other. - * @rx_count: Valid values are in the range 1 to the max_rx. - * @tx_count: Valid values are in the range 1 to the max_tx. - * @other_count: Valid values are in the range 1 to the max_other. - * @combined_count: Valid values are in the range 1 to the max_combined. - * - * This can be used to configure RX, TX and other channels. - */ - -struct ethtool_channels { - __u32 cmd; - __u32 max_rx; - __u32 max_tx; - __u32 max_other; - __u32 max_combined; - __u32 rx_count; - __u32 tx_count; - __u32 other_count; - __u32 combined_count; -}; - -/** - * struct ethtool_pauseparam - Ethernet pause (flow control) parameters - * @cmd: Command number = %ETHTOOL_GPAUSEPARAM or %ETHTOOL_SPAUSEPARAM - * @autoneg: Flag to enable autonegotiation of pause frame use - * @rx_pause: Flag to enable reception of pause frames - * @tx_pause: Flag to enable transmission of pause frames - * - * Drivers should reject a non-zero setting of @autoneg when - * autoneogotiation is disabled (or not supported) for the link. - * - * If the link is autonegotiated, drivers should use - * mii_advertise_flowctrl() or similar code to set the advertised - * pause frame capabilities based on the @rx_pause and @tx_pause flags, - * even if @autoneg is zero. They should also allow the advertised - * pause frame capabilities to be controlled directly through the - * advertising field of &struct ethtool_cmd. - * - * If @autoneg is non-zero, the MAC is configured to send and/or - * receive pause frames according to the result of autonegotiation. - * Otherwise, it is configured directly based on the @rx_pause and - * @tx_pause flags. - */ -struct ethtool_pauseparam { - __u32 cmd; - __u32 autoneg; - __u32 rx_pause; - __u32 tx_pause; -}; - -#define ETH_GSTRING_LEN 32 - -/** - * enum ethtool_stringset - string set ID - * @ETH_SS_TEST: Self-test result names, for use with %ETHTOOL_TEST - * @ETH_SS_STATS: Statistic names, for use with %ETHTOOL_GSTATS - * @ETH_SS_PRIV_FLAGS: Driver private flag names, for use with - * %ETHTOOL_GPFLAGS and %ETHTOOL_SPFLAGS - * @ETH_SS_NTUPLE_FILTERS: Previously used with %ETHTOOL_GRXNTUPLE; - * now deprecated - * @ETH_SS_FEATURES: Device feature names - * @ETH_SS_RSS_HASH_FUNCS: RSS hush function names - * @ETH_SS_PHY_STATS: Statistic names, for use with %ETHTOOL_GPHYSTATS - */ -enum ethtool_stringset { - ETH_SS_TEST = 0, - ETH_SS_STATS, - ETH_SS_PRIV_FLAGS, - ETH_SS_NTUPLE_FILTERS, - ETH_SS_FEATURES, - ETH_SS_RSS_HASH_FUNCS, - ETH_SS_TUNABLES, - ETH_SS_PHY_STATS, -}; - -/** - * struct ethtool_gstrings - string set for data tagging - * @cmd: Command number = %ETHTOOL_GSTRINGS - * @string_set: String set ID; one of &enum ethtool_stringset - * @len: On return, the number of strings in the string set - * @data: Buffer for strings. Each string is null-padded to a size of - * %ETH_GSTRING_LEN. - * - * Users must use %ETHTOOL_GSSET_INFO to find the number of strings in - * the string set. They must allocate a buffer of the appropriate - * size immediately following this structure. - */ -struct ethtool_gstrings { - __u32 cmd; - __u32 string_set; - __u32 len; - __u8 data[0]; -}; - -/** - * struct ethtool_sset_info - string set information - * @cmd: Command number = %ETHTOOL_GSSET_INFO - * @sset_mask: On entry, a bitmask of string sets to query, with bits - * numbered according to &enum ethtool_stringset. On return, a - * bitmask of those string sets queried that are supported. - * @data: Buffer for string set sizes. On return, this contains the - * size of each string set that was queried and supported, in - * order of ID. - * - * Example: The user passes in @sset_mask = 0x7 (sets 0, 1, 2) and on - * return @sset_mask == 0x6 (sets 1, 2). Then @data[0] contains the - * size of set 1 and @data[1] contains the size of set 2. - * - * Users must allocate a buffer of the appropriate size (4 * number of - * sets queried) immediately following this structure. - */ -struct ethtool_sset_info { - __u32 cmd; - __u32 reserved; - __u64 sset_mask; - __u32 data[0]; -}; - -/** - * enum ethtool_test_flags - flags definition of ethtool_test - * @ETH_TEST_FL_OFFLINE: if set perform online and offline tests, otherwise - * only online tests. - * @ETH_TEST_FL_FAILED: Driver set this flag if test fails. - * @ETH_TEST_FL_EXTERNAL_LB: Application request to perform external loopback - * test. - * @ETH_TEST_FL_EXTERNAL_LB_DONE: Driver performed the external loopback test - */ - -enum ethtool_test_flags { - ETH_TEST_FL_OFFLINE = (1 << 0), - ETH_TEST_FL_FAILED = (1 << 1), - ETH_TEST_FL_EXTERNAL_LB = (1 << 2), - ETH_TEST_FL_EXTERNAL_LB_DONE = (1 << 3), -}; - -/** - * struct ethtool_test - device self-test invocation - * @cmd: Command number = %ETHTOOL_TEST - * @flags: A bitmask of flags from &enum ethtool_test_flags. Some - * flags may be set by the user on entry; others may be set by - * the driver on return. - * @len: On return, the number of test results - * @data: Array of test results - * - * Users must use %ETHTOOL_GSSET_INFO or %ETHTOOL_GDRVINFO to find the - * number of test results that will be returned. They must allocate a - * buffer of the appropriate size (8 * number of results) immediately - * following this structure. - */ -struct ethtool_test { - __u32 cmd; - __u32 flags; - __u32 reserved; - __u32 len; - __u64 data[0]; -}; - -/** - * struct ethtool_stats - device-specific statistics - * @cmd: Command number = %ETHTOOL_GSTATS - * @n_stats: On return, the number of statistics - * @data: Array of statistics - * - * Users must use %ETHTOOL_GSSET_INFO or %ETHTOOL_GDRVINFO to find the - * number of statistics that will be returned. They must allocate a - * buffer of the appropriate size (8 * number of statistics) - * immediately following this structure. - */ -struct ethtool_stats { - __u32 cmd; - __u32 n_stats; - __u64 data[0]; -}; - -/** - * struct ethtool_perm_addr - permanent hardware address - * @cmd: Command number = %ETHTOOL_GPERMADDR - * @size: On entry, the size of the buffer. On return, the size of the - * address. The command fails if the buffer is too small. - * @data: Buffer for the address - * - * Users must allocate the buffer immediately following this structure. - * A buffer size of %MAX_ADDR_LEN should be sufficient for any address - * type. - */ -struct ethtool_perm_addr { - __u32 cmd; - __u32 size; - __u8 data[0]; -}; - -/* boolean flags controlling per-interface behavior characteristics. - * When reading, the flag indicates whether or not a certain behavior - * is enabled/present. When writing, the flag indicates whether - * or not the driver should turn on (set) or off (clear) a behavior. - * - * Some behaviors may read-only (unconditionally absent or present). - * If such is the case, return EINVAL in the set-flags operation if the - * flag differs from the read-only value. - */ -enum ethtool_flags { - ETH_FLAG_TXVLAN = (1 << 7), /* TX VLAN offload enabled */ - ETH_FLAG_RXVLAN = (1 << 8), /* RX VLAN offload enabled */ - ETH_FLAG_LRO = (1 << 15), /* LRO is enabled */ - ETH_FLAG_NTUPLE = (1 << 27), /* N-tuple filters enabled */ - ETH_FLAG_RXHASH = (1 << 28), -}; - -/* The following structures are for supporting RX network flow - * classification and RX n-tuple configuration. Note, all multibyte - * fields, e.g., ip4src, ip4dst, psrc, pdst, spi, etc. are expected to - * be in network byte order. - */ - -/** - * struct ethtool_tcpip4_spec - flow specification for TCP/IPv4 etc. - * @ip4src: Source host - * @ip4dst: Destination host - * @psrc: Source port - * @pdst: Destination port - * @tos: Type-of-service - * - * This can be used to specify a TCP/IPv4, UDP/IPv4 or SCTP/IPv4 flow. - */ -struct ethtool_tcpip4_spec { - __be32 ip4src; - __be32 ip4dst; - __be16 psrc; - __be16 pdst; - __u8 tos; -}; - -/** - * struct ethtool_ah_espip4_spec - flow specification for IPsec/IPv4 - * @ip4src: Source host - * @ip4dst: Destination host - * @spi: Security parameters index - * @tos: Type-of-service - * - * This can be used to specify an IPsec transport or tunnel over IPv4. - */ -struct ethtool_ah_espip4_spec { - __be32 ip4src; - __be32 ip4dst; - __be32 spi; - __u8 tos; -}; - -#define ETH_RX_NFC_IP4 1 - -/** - * struct ethtool_usrip4_spec - general flow specification for IPv4 - * @ip4src: Source host - * @ip4dst: Destination host - * @l4_4_bytes: First 4 bytes of transport (layer 4) header - * @tos: Type-of-service - * @ip_ver: Value must be %ETH_RX_NFC_IP4; mask must be 0 - * @proto: Transport protocol number; mask must be 0 - */ -struct ethtool_usrip4_spec { - __be32 ip4src; - __be32 ip4dst; - __be32 l4_4_bytes; - __u8 tos; - __u8 ip_ver; - __u8 proto; -}; - -/** - * struct ethtool_tcpip6_spec - flow specification for TCP/IPv6 etc. - * @ip6src: Source host - * @ip6dst: Destination host - * @psrc: Source port - * @pdst: Destination port - * @tclass: Traffic Class - * - * This can be used to specify a TCP/IPv6, UDP/IPv6 or SCTP/IPv6 flow. - */ -struct ethtool_tcpip6_spec { - __be32 ip6src[4]; - __be32 ip6dst[4]; - __be16 psrc; - __be16 pdst; - __u8 tclass; -}; - -/** - * struct ethtool_ah_espip6_spec - flow specification for IPsec/IPv6 - * @ip6src: Source host - * @ip6dst: Destination host - * @spi: Security parameters index - * @tclass: Traffic Class - * - * This can be used to specify an IPsec transport or tunnel over IPv6. - */ -struct ethtool_ah_espip6_spec { - __be32 ip6src[4]; - __be32 ip6dst[4]; - __be32 spi; - __u8 tclass; -}; - -/** - * struct ethtool_usrip6_spec - general flow specification for IPv6 - * @ip6src: Source host - * @ip6dst: Destination host - * @l4_4_bytes: First 4 bytes of transport (layer 4) header - * @tclass: Traffic Class - * @l4_proto: Transport protocol number (nexthdr after any Extension Headers) - */ -struct ethtool_usrip6_spec { - __be32 ip6src[4]; - __be32 ip6dst[4]; - __be32 l4_4_bytes; - __u8 tclass; - __u8 l4_proto; -}; - -union ethtool_flow_union { - struct ethtool_tcpip4_spec tcp_ip4_spec; - struct ethtool_tcpip4_spec udp_ip4_spec; - struct ethtool_tcpip4_spec sctp_ip4_spec; - struct ethtool_ah_espip4_spec ah_ip4_spec; - struct ethtool_ah_espip4_spec esp_ip4_spec; - struct ethtool_usrip4_spec usr_ip4_spec; - struct ethtool_tcpip6_spec tcp_ip6_spec; - struct ethtool_tcpip6_spec udp_ip6_spec; - struct ethtool_tcpip6_spec sctp_ip6_spec; - struct ethtool_ah_espip6_spec ah_ip6_spec; - struct ethtool_ah_espip6_spec esp_ip6_spec; - struct ethtool_usrip6_spec usr_ip6_spec; - struct ethhdr ether_spec; - __u8 hdata[52]; -}; - -/** - * struct ethtool_flow_ext - additional RX flow fields - * @h_dest: destination MAC address - * @vlan_etype: VLAN EtherType - * @vlan_tci: VLAN tag control information - * @data: user defined data - * - * Note, @vlan_etype, @vlan_tci, and @data are only valid if %FLOW_EXT - * is set in &struct ethtool_rx_flow_spec @flow_type. - * @h_dest is valid if %FLOW_MAC_EXT is set. - */ -struct ethtool_flow_ext { - __u8 padding[2]; - unsigned char h_dest[ETH_ALEN]; - __be16 vlan_etype; - __be16 vlan_tci; - __be32 data[2]; -}; - -/** - * struct ethtool_rx_flow_spec - classification rule for RX flows - * @flow_type: Type of match to perform, e.g. %TCP_V4_FLOW - * @h_u: Flow fields to match (dependent on @flow_type) - * @h_ext: Additional fields to match - * @m_u: Masks for flow field bits to be matched - * @m_ext: Masks for additional field bits to be matched - * Note, all additional fields must be ignored unless @flow_type - * includes the %FLOW_EXT or %FLOW_MAC_EXT flag - * (see &struct ethtool_flow_ext description). - * @ring_cookie: RX ring/queue index to deliver to, or %RX_CLS_FLOW_DISC - * if packets should be discarded - * @location: Location of rule in the table. Locations must be - * numbered such that a flow matching multiple rules will be - * classified according to the first (lowest numbered) rule. - */ -struct ethtool_rx_flow_spec { - __u32 flow_type; - union ethtool_flow_union h_u; - struct ethtool_flow_ext h_ext; - union ethtool_flow_union m_u; - struct ethtool_flow_ext m_ext; - __u64 ring_cookie; - __u32 location; -}; - -/* How rings are layed out when accessing virtual functions or - * offloaded queues is device specific. To allow users to do flow - * steering and specify these queues the ring cookie is partitioned - * into a 32bit queue index with an 8 bit virtual function id. - * This also leaves the 3bytes for further specifiers. It is possible - * future devices may support more than 256 virtual functions if - * devices start supporting PCIe w/ARI. However at the moment I - * do not know of any devices that support this so I do not reserve - * space for this at this time. If a future patch consumes the next - * byte it should be aware of this possiblity. - */ -#define ETHTOOL_RX_FLOW_SPEC_RING 0x00000000FFFFFFFFLL -#define ETHTOOL_RX_FLOW_SPEC_RING_VF 0x000000FF00000000LL -#define ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF 32 -static inline __u64 ethtool_get_flow_spec_ring(__u64 ring_cookie) -{ - return ETHTOOL_RX_FLOW_SPEC_RING & ring_cookie; -}; - -static inline __u64 ethtool_get_flow_spec_ring_vf(__u64 ring_cookie) -{ - return (ETHTOOL_RX_FLOW_SPEC_RING_VF & ring_cookie) >> - ETHTOOL_RX_FLOW_SPEC_RING_VF_OFF; -}; - -/** - * struct ethtool_rxnfc - command to get or set RX flow classification rules - * @cmd: Specific command number - %ETHTOOL_GRXFH, %ETHTOOL_SRXFH, - * %ETHTOOL_GRXRINGS, %ETHTOOL_GRXCLSRLCNT, %ETHTOOL_GRXCLSRULE, - * %ETHTOOL_GRXCLSRLALL, %ETHTOOL_SRXCLSRLDEL or %ETHTOOL_SRXCLSRLINS - * @flow_type: Type of flow to be affected, e.g. %TCP_V4_FLOW - * @data: Command-dependent value - * @fs: Flow classification rule - * @rule_cnt: Number of rules to be affected - * @rule_locs: Array of used rule locations - * - * For %ETHTOOL_GRXFH and %ETHTOOL_SRXFH, @data is a bitmask indicating - * the fields included in the flow hash, e.g. %RXH_IP_SRC. The following - * structure fields must not be used. - * - * For %ETHTOOL_GRXRINGS, @data is set to the number of RX rings/queues - * on return. - * - * For %ETHTOOL_GRXCLSRLCNT, @rule_cnt is set to the number of defined - * rules on return. If @data is non-zero on return then it is the - * size of the rule table, plus the flag %RX_CLS_LOC_SPECIAL if the - * driver supports any special location values. If that flag is not - * set in @data then special location values should not be used. - * - * For %ETHTOOL_GRXCLSRULE, @fs.@location specifies the location of an - * existing rule on entry and @fs contains the rule on return. - * - * For %ETHTOOL_GRXCLSRLALL, @rule_cnt specifies the array size of the - * user buffer for @rule_locs on entry. On return, @data is the size - * of the rule table, @rule_cnt is the number of defined rules, and - * @rule_locs contains the locations of the defined rules. Drivers - * must use the second parameter to get_rxnfc() instead of @rule_locs. - * - * For %ETHTOOL_SRXCLSRLINS, @fs specifies the rule to add or update. - * @fs.@location either specifies the location to use or is a special - * location value with %RX_CLS_LOC_SPECIAL flag set. On return, - * @fs.@location is the actual rule location. - * - * For %ETHTOOL_SRXCLSRLDEL, @fs.@location specifies the location of an - * existing rule on entry. - * - * A driver supporting the special location values for - * %ETHTOOL_SRXCLSRLINS may add the rule at any suitable unused - * location, and may remove a rule at a later location (lower - * priority) that matches exactly the same set of flows. The special - * values are %RX_CLS_LOC_ANY, selecting any location; - * %RX_CLS_LOC_FIRST, selecting the first suitable location (maximum - * priority); and %RX_CLS_LOC_LAST, selecting the last suitable - * location (minimum priority). Additional special values may be - * defined in future and drivers must return -%EINVAL for any - * unrecognised value. - */ -struct ethtool_rxnfc { - __u32 cmd; - __u32 flow_type; - __u64 data; - struct ethtool_rx_flow_spec fs; - __u32 rule_cnt; - __u32 rule_locs[0]; -}; - - -/** - * struct ethtool_rxfh_indir - command to get or set RX flow hash indirection - * @cmd: Specific command number - %ETHTOOL_GRXFHINDIR or %ETHTOOL_SRXFHINDIR - * @size: On entry, the array size of the user buffer, which may be zero. - * On return from %ETHTOOL_GRXFHINDIR, the array size of the hardware - * indirection table. - * @ring_index: RX ring/queue index for each hash value - * - * For %ETHTOOL_GRXFHINDIR, a @size of zero means that only the size - * should be returned. For %ETHTOOL_SRXFHINDIR, a @size of zero means - * the table should be reset to default values. This last feature - * is not supported by the original implementations. - */ -struct ethtool_rxfh_indir { - __u32 cmd; - __u32 size; - __u32 ring_index[0]; -}; - -/** - * struct ethtool_rxfh - command to get/set RX flow hash indir or/and hash key. - * @cmd: Specific command number - %ETHTOOL_GRSSH or %ETHTOOL_SRSSH - * @rss_context: RSS context identifier. - * @indir_size: On entry, the array size of the user buffer for the - * indirection table, which may be zero, or (for %ETHTOOL_SRSSH), - * %ETH_RXFH_INDIR_NO_CHANGE. On return from %ETHTOOL_GRSSH, - * the array size of the hardware indirection table. - * @key_size: On entry, the array size of the user buffer for the hash key, - * which may be zero. On return from %ETHTOOL_GRSSH, the size of the - * hardware hash key. - * @hfunc: Defines the current RSS hash function used by HW (or to be set to). - * Valid values are one of the %ETH_RSS_HASH_*. - * @rsvd: Reserved for future extensions. - * @rss_config: RX ring/queue index for each hash value i.e., indirection table - * of @indir_size __u32 elements, followed by hash key of @key_size - * bytes. - * - * For %ETHTOOL_GRSSH, a @indir_size and key_size of zero means that only the - * size should be returned. For %ETHTOOL_SRSSH, an @indir_size of - * %ETH_RXFH_INDIR_NO_CHANGE means that indir table setting is not requested - * and a @indir_size of zero means the indir table should be reset to default - * values. An hfunc of zero means that hash function setting is not requested. - */ -struct ethtool_rxfh { - __u32 cmd; - __u32 rss_context; - __u32 indir_size; - __u32 key_size; - __u8 hfunc; - __u8 rsvd8[3]; - __u32 rsvd32; - __u32 rss_config[0]; -}; -#define ETH_RXFH_INDIR_NO_CHANGE 0xffffffff - -/** - * struct ethtool_rx_ntuple_flow_spec - specification for RX flow filter - * @flow_type: Type of match to perform, e.g. %TCP_V4_FLOW - * @h_u: Flow field values to match (dependent on @flow_type) - * @m_u: Masks for flow field value bits to be ignored - * @vlan_tag: VLAN tag to match - * @vlan_tag_mask: Mask for VLAN tag bits to be ignored - * @data: Driver-dependent data to match - * @data_mask: Mask for driver-dependent data bits to be ignored - * @action: RX ring/queue index to deliver to (non-negative) or other action - * (negative, e.g. %ETHTOOL_RXNTUPLE_ACTION_DROP) - * - * For flow types %TCP_V4_FLOW, %UDP_V4_FLOW and %SCTP_V4_FLOW, where - * a field value and mask are both zero this is treated as if all mask - * bits are set i.e. the field is ignored. - */ -struct ethtool_rx_ntuple_flow_spec { - __u32 flow_type; - union { - struct ethtool_tcpip4_spec tcp_ip4_spec; - struct ethtool_tcpip4_spec udp_ip4_spec; - struct ethtool_tcpip4_spec sctp_ip4_spec; - struct ethtool_ah_espip4_spec ah_ip4_spec; - struct ethtool_ah_espip4_spec esp_ip4_spec; - struct ethtool_usrip4_spec usr_ip4_spec; - struct ethhdr ether_spec; - __u8 hdata[72]; - } h_u, m_u; - - __u16 vlan_tag; - __u16 vlan_tag_mask; - __u64 data; - __u64 data_mask; - - __s32 action; -#define ETHTOOL_RXNTUPLE_ACTION_DROP (-1) /* drop packet */ -#define ETHTOOL_RXNTUPLE_ACTION_CLEAR (-2) /* clear filter */ -}; - -/** - * struct ethtool_rx_ntuple - command to set or clear RX flow filter - * @cmd: Command number - %ETHTOOL_SRXNTUPLE - * @fs: Flow filter specification - */ -struct ethtool_rx_ntuple { - __u32 cmd; - struct ethtool_rx_ntuple_flow_spec fs; -}; - -#define ETHTOOL_FLASH_MAX_FILENAME 128 -enum ethtool_flash_op_type { - ETHTOOL_FLASH_ALL_REGIONS = 0, -}; - -/* for passing firmware flashing related parameters */ -struct ethtool_flash { - __u32 cmd; - __u32 region; - char data[ETHTOOL_FLASH_MAX_FILENAME]; -}; - -/** - * struct ethtool_dump - used for retrieving, setting device dump - * @cmd: Command number - %ETHTOOL_GET_DUMP_FLAG, %ETHTOOL_GET_DUMP_DATA, or - * %ETHTOOL_SET_DUMP - * @version: FW version of the dump, filled in by driver - * @flag: driver dependent flag for dump setting, filled in by driver during - * get and filled in by ethtool for set operation. - * flag must be initialized by macro ETH_FW_DUMP_DISABLE value when - * firmware dump is disabled. - * @len: length of dump data, used as the length of the user buffer on entry to - * %ETHTOOL_GET_DUMP_DATA and this is returned as dump length by driver - * for %ETHTOOL_GET_DUMP_FLAG command - * @data: data collected for get dump data operation - */ -struct ethtool_dump { - __u32 cmd; - __u32 version; - __u32 flag; - __u32 len; - __u8 data[0]; -}; - -#define ETH_FW_DUMP_DISABLE 0 - -/* for returning and changing feature sets */ - -/** - * struct ethtool_get_features_block - block with state of 32 features - * @available: mask of changeable features - * @requested: mask of features requested to be enabled if possible - * @active: mask of currently enabled features - * @never_changed: mask of features not changeable for any device - */ -struct ethtool_get_features_block { - __u32 available; - __u32 requested; - __u32 active; - __u32 never_changed; -}; - -/** - * struct ethtool_gfeatures - command to get state of device's features - * @cmd: command number = %ETHTOOL_GFEATURES - * @size: On entry, the number of elements in the features[] array; - * on return, the number of elements in features[] needed to hold - * all features - * @features: state of features - */ -struct ethtool_gfeatures { - __u32 cmd; - __u32 size; - struct ethtool_get_features_block features[0]; -}; - -/** - * struct ethtool_set_features_block - block with request for 32 features - * @valid: mask of features to be changed - * @requested: values of features to be changed - */ -struct ethtool_set_features_block { - __u32 valid; - __u32 requested; -}; - -/** - * struct ethtool_sfeatures - command to request change in device's features - * @cmd: command number = %ETHTOOL_SFEATURES - * @size: array size of the features[] array - * @features: feature change masks - */ -struct ethtool_sfeatures { - __u32 cmd; - __u32 size; - struct ethtool_set_features_block features[0]; -}; - -/** - * struct ethtool_ts_info - holds a device's timestamping and PHC association - * @cmd: command number = %ETHTOOL_GET_TS_INFO - * @so_timestamping: bit mask of the sum of the supported SO_TIMESTAMPING flags - * @phc_index: device index of the associated PHC, or -1 if there is none - * @tx_types: bit mask of the supported hwtstamp_tx_types enumeration values - * @rx_filters: bit mask of the supported hwtstamp_rx_filters enumeration values - * - * The bits in the 'tx_types' and 'rx_filters' fields correspond to - * the 'hwtstamp_tx_types' and 'hwtstamp_rx_filters' enumeration values, - * respectively. For example, if the device supports HWTSTAMP_TX_ON, - * then (1 << HWTSTAMP_TX_ON) in 'tx_types' will be set. - * - * Drivers should only report the filters they actually support without - * upscaling in the SIOCSHWTSTAMP ioctl. If the SIOCSHWSTAMP request for - * HWTSTAMP_FILTER_V1_SYNC is supported by HWTSTAMP_FILTER_V1_EVENT, then the - * driver should only report HWTSTAMP_FILTER_V1_EVENT in this op. - */ -struct ethtool_ts_info { - __u32 cmd; - __u32 so_timestamping; - __s32 phc_index; - __u32 tx_types; - __u32 tx_reserved[3]; - __u32 rx_filters; - __u32 rx_reserved[3]; -}; - -/* - * %ETHTOOL_SFEATURES changes features present in features[].valid to the - * values of corresponding bits in features[].requested. Bits in .requested - * not set in .valid or not changeable are ignored. - * - * Returns %EINVAL when .valid contains undefined or never-changeable bits - * or size is not equal to required number of features words (32-bit blocks). - * Returns >= 0 if request was completed; bits set in the value mean: - * %ETHTOOL_F_UNSUPPORTED - there were bits set in .valid that are not - * changeable (not present in %ETHTOOL_GFEATURES' features[].available) - * those bits were ignored. - * %ETHTOOL_F_WISH - some or all changes requested were recorded but the - * resulting state of bits masked by .valid is not equal to .requested. - * Probably there are other device-specific constraints on some features - * in the set. When %ETHTOOL_F_UNSUPPORTED is set, .valid is considered - * here as though ignored bits were cleared. - * %ETHTOOL_F_COMPAT - some or all changes requested were made by calling - * compatibility functions. Requested offload state cannot be properly - * managed by kernel. - * - * Meaning of bits in the masks are obtained by %ETHTOOL_GSSET_INFO (number of - * bits in the arrays - always multiple of 32) and %ETHTOOL_GSTRINGS commands - * for ETH_SS_FEATURES string set. First entry in the table corresponds to least - * significant bit in features[0] fields. Empty strings mark undefined features. - */ -enum ethtool_sfeatures_retval_bits { - ETHTOOL_F_UNSUPPORTED__BIT, - ETHTOOL_F_WISH__BIT, - ETHTOOL_F_COMPAT__BIT, -}; - -#define ETHTOOL_F_UNSUPPORTED (1 << ETHTOOL_F_UNSUPPORTED__BIT) -#define ETHTOOL_F_WISH (1 << ETHTOOL_F_WISH__BIT) -#define ETHTOOL_F_COMPAT (1 << ETHTOOL_F_COMPAT__BIT) - -#define MAX_NUM_QUEUE 4096 - -/** - * struct ethtool_per_queue_op - apply sub command to the queues in mask. - * @cmd: ETHTOOL_PERQUEUE - * @sub_command: the sub command which apply to each queues - * @queue_mask: Bitmap of the queues which sub command apply to - * @data: A complete command structure following for each of the queues addressed - */ -struct ethtool_per_queue_op { - __u32 cmd; - __u32 sub_command; - __u32 queue_mask[__KERNEL_DIV_ROUND_UP(MAX_NUM_QUEUE, 32)]; - char data[]; -}; - -/* CMDs currently supported */ -#define ETHTOOL_GSET 0x00000001 /* DEPRECATED, Get settings. - * Please use ETHTOOL_GLINKSETTINGS - */ -#define ETHTOOL_SSET 0x00000002 /* DEPRECATED, Set settings. - * Please use ETHTOOL_SLINKSETTINGS - */ -#define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */ -#define ETHTOOL_GREGS 0x00000004 /* Get NIC registers. */ -#define ETHTOOL_GWOL 0x00000005 /* Get wake-on-lan options. */ -#define ETHTOOL_SWOL 0x00000006 /* Set wake-on-lan options. */ -#define ETHTOOL_GMSGLVL 0x00000007 /* Get driver message level */ -#define ETHTOOL_SMSGLVL 0x00000008 /* Set driver msg level. */ -#define ETHTOOL_NWAY_RST 0x00000009 /* Restart autonegotiation. */ -/* Get link status for host, i.e. whether the interface *and* the - * physical port (if there is one) are up (ethtool_value). */ -#define ETHTOOL_GLINK 0x0000000a -#define ETHTOOL_GEEPROM 0x0000000b /* Get EEPROM data */ -#define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data. */ -#define ETHTOOL_GCOALESCE 0x0000000e /* Get coalesce config */ -#define ETHTOOL_SCOALESCE 0x0000000f /* Set coalesce config. */ -#define ETHTOOL_GRINGPARAM 0x00000010 /* Get ring parameters */ -#define ETHTOOL_SRINGPARAM 0x00000011 /* Set ring parameters. */ -#define ETHTOOL_GPAUSEPARAM 0x00000012 /* Get pause parameters */ -#define ETHTOOL_SPAUSEPARAM 0x00000013 /* Set pause parameters. */ -#define ETHTOOL_GRXCSUM 0x00000014 /* Get RX hw csum enable (ethtool_value) */ -#define ETHTOOL_SRXCSUM 0x00000015 /* Set RX hw csum enable (ethtool_value) */ -#define ETHTOOL_GTXCSUM 0x00000016 /* Get TX hw csum enable (ethtool_value) */ -#define ETHTOOL_STXCSUM 0x00000017 /* Set TX hw csum enable (ethtool_value) */ -#define ETHTOOL_GSG 0x00000018 /* Get scatter-gather enable - * (ethtool_value) */ -#define ETHTOOL_SSG 0x00000019 /* Set scatter-gather enable - * (ethtool_value). */ -#define ETHTOOL_TEST 0x0000001a /* execute NIC self-test. */ -#define ETHTOOL_GSTRINGS 0x0000001b /* get specified string set */ -#define ETHTOOL_PHYS_ID 0x0000001c /* identify the NIC */ -#define ETHTOOL_GSTATS 0x0000001d /* get NIC-specific statistics */ -#define ETHTOOL_GTSO 0x0000001e /* Get TSO enable (ethtool_value) */ -#define ETHTOOL_STSO 0x0000001f /* Set TSO enable (ethtool_value) */ -#define ETHTOOL_GPERMADDR 0x00000020 /* Get permanent hardware address */ -#define ETHTOOL_GUFO 0x00000021 /* Get UFO enable (ethtool_value) */ -#define ETHTOOL_SUFO 0x00000022 /* Set UFO enable (ethtool_value) */ -#define ETHTOOL_GGSO 0x00000023 /* Get GSO enable (ethtool_value) */ -#define ETHTOOL_SGSO 0x00000024 /* Set GSO enable (ethtool_value) */ -#define ETHTOOL_GFLAGS 0x00000025 /* Get flags bitmap(ethtool_value) */ -#define ETHTOOL_SFLAGS 0x00000026 /* Set flags bitmap(ethtool_value) */ -#define ETHTOOL_GPFLAGS 0x00000027 /* Get driver-private flags bitmap */ -#define ETHTOOL_SPFLAGS 0x00000028 /* Set driver-private flags bitmap */ - -#define ETHTOOL_GRXFH 0x00000029 /* Get RX flow hash configuration */ -#define ETHTOOL_SRXFH 0x0000002a /* Set RX flow hash configuration */ -#define ETHTOOL_GGRO 0x0000002b /* Get GRO enable (ethtool_value) */ -#define ETHTOOL_SGRO 0x0000002c /* Set GRO enable (ethtool_value) */ -#define ETHTOOL_GRXRINGS 0x0000002d /* Get RX rings available for LB */ -#define ETHTOOL_GRXCLSRLCNT 0x0000002e /* Get RX class rule count */ -#define ETHTOOL_GRXCLSRULE 0x0000002f /* Get RX classification rule */ -#define ETHTOOL_GRXCLSRLALL 0x00000030 /* Get all RX classification rule */ -#define ETHTOOL_SRXCLSRLDEL 0x00000031 /* Delete RX classification rule */ -#define ETHTOOL_SRXCLSRLINS 0x00000032 /* Insert RX classification rule */ -#define ETHTOOL_FLASHDEV 0x00000033 /* Flash firmware to device */ -#define ETHTOOL_RESET 0x00000034 /* Reset hardware */ -#define ETHTOOL_SRXNTUPLE 0x00000035 /* Add an n-tuple filter to device */ -#define ETHTOOL_GRXNTUPLE 0x00000036 /* deprecated */ -#define ETHTOOL_GSSET_INFO 0x00000037 /* Get string set info */ -#define ETHTOOL_GRXFHINDIR 0x00000038 /* Get RX flow hash indir'n table */ -#define ETHTOOL_SRXFHINDIR 0x00000039 /* Set RX flow hash indir'n table */ - -#define ETHTOOL_GFEATURES 0x0000003a /* Get device offload settings */ -#define ETHTOOL_SFEATURES 0x0000003b /* Change device offload settings */ -#define ETHTOOL_GCHANNELS 0x0000003c /* Get no of channels */ -#define ETHTOOL_SCHANNELS 0x0000003d /* Set no of channels */ -#define ETHTOOL_SET_DUMP 0x0000003e /* Set dump settings */ -#define ETHTOOL_GET_DUMP_FLAG 0x0000003f /* Get dump settings */ -#define ETHTOOL_GET_DUMP_DATA 0x00000040 /* Get dump data */ -#define ETHTOOL_GET_TS_INFO 0x00000041 /* Get time stamping and PHC info */ -#define ETHTOOL_GMODULEINFO 0x00000042 /* Get plug-in module information */ -#define ETHTOOL_GMODULEEEPROM 0x00000043 /* Get plug-in module eeprom */ -#define ETHTOOL_GEEE 0x00000044 /* Get EEE settings */ -#define ETHTOOL_SEEE 0x00000045 /* Set EEE settings */ - -#define ETHTOOL_GRSSH 0x00000046 /* Get RX flow hash configuration */ -#define ETHTOOL_SRSSH 0x00000047 /* Set RX flow hash configuration */ -#define ETHTOOL_GTUNABLE 0x00000048 /* Get tunable configuration */ -#define ETHTOOL_STUNABLE 0x00000049 /* Set tunable configuration */ -#define ETHTOOL_GPHYSTATS 0x0000004a /* get PHY-specific statistics */ - -#define ETHTOOL_PERQUEUE 0x0000004b /* Set per queue options */ - -#define ETHTOOL_GLINKSETTINGS 0x0000004c /* Get ethtool_link_settings */ -#define ETHTOOL_SLINKSETTINGS 0x0000004d /* Set ethtool_link_settings */ - - -/* compatibility with older code */ -#define SPARC_ETH_GSET ETHTOOL_GSET -#define SPARC_ETH_SSET ETHTOOL_SSET - -/* Link mode bit indices */ -enum ethtool_link_mode_bit_indices { - ETHTOOL_LINK_MODE_10baseT_Half_BIT = 0, - ETHTOOL_LINK_MODE_10baseT_Full_BIT = 1, - ETHTOOL_LINK_MODE_100baseT_Half_BIT = 2, - ETHTOOL_LINK_MODE_100baseT_Full_BIT = 3, - ETHTOOL_LINK_MODE_1000baseT_Half_BIT = 4, - ETHTOOL_LINK_MODE_1000baseT_Full_BIT = 5, - ETHTOOL_LINK_MODE_Autoneg_BIT = 6, - ETHTOOL_LINK_MODE_TP_BIT = 7, - ETHTOOL_LINK_MODE_AUI_BIT = 8, - ETHTOOL_LINK_MODE_MII_BIT = 9, - ETHTOOL_LINK_MODE_FIBRE_BIT = 10, - ETHTOOL_LINK_MODE_BNC_BIT = 11, - ETHTOOL_LINK_MODE_10000baseT_Full_BIT = 12, - ETHTOOL_LINK_MODE_Pause_BIT = 13, - ETHTOOL_LINK_MODE_Asym_Pause_BIT = 14, - ETHTOOL_LINK_MODE_2500baseX_Full_BIT = 15, - ETHTOOL_LINK_MODE_Backplane_BIT = 16, - ETHTOOL_LINK_MODE_1000baseKX_Full_BIT = 17, - ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT = 18, - ETHTOOL_LINK_MODE_10000baseKR_Full_BIT = 19, - ETHTOOL_LINK_MODE_10000baseR_FEC_BIT = 20, - ETHTOOL_LINK_MODE_20000baseMLD2_Full_BIT = 21, - ETHTOOL_LINK_MODE_20000baseKR2_Full_BIT = 22, - ETHTOOL_LINK_MODE_40000baseKR4_Full_BIT = 23, - ETHTOOL_LINK_MODE_40000baseCR4_Full_BIT = 24, - ETHTOOL_LINK_MODE_40000baseSR4_Full_BIT = 25, - ETHTOOL_LINK_MODE_40000baseLR4_Full_BIT = 26, - ETHTOOL_LINK_MODE_56000baseKR4_Full_BIT = 27, - ETHTOOL_LINK_MODE_56000baseCR4_Full_BIT = 28, - ETHTOOL_LINK_MODE_56000baseSR4_Full_BIT = 29, - ETHTOOL_LINK_MODE_56000baseLR4_Full_BIT = 30, - ETHTOOL_LINK_MODE_25000baseCR_Full_BIT = 31, - ETHTOOL_LINK_MODE_25000baseKR_Full_BIT = 32, - ETHTOOL_LINK_MODE_25000baseSR_Full_BIT = 33, - ETHTOOL_LINK_MODE_50000baseCR2_Full_BIT = 34, - ETHTOOL_LINK_MODE_50000baseKR2_Full_BIT = 35, - ETHTOOL_LINK_MODE_100000baseKR4_Full_BIT = 36, - ETHTOOL_LINK_MODE_100000baseSR4_Full_BIT = 37, - ETHTOOL_LINK_MODE_100000baseCR4_Full_BIT = 38, - ETHTOOL_LINK_MODE_100000baseLR4_ER4_Full_BIT = 39, - ETHTOOL_LINK_MODE_50000baseSR2_Full_BIT = 40, - ETHTOOL_LINK_MODE_1000baseX_Full_BIT = 41, - ETHTOOL_LINK_MODE_10000baseCR_Full_BIT = 42, - ETHTOOL_LINK_MODE_10000baseSR_Full_BIT = 43, - ETHTOOL_LINK_MODE_10000baseLR_Full_BIT = 44, - ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT = 45, - ETHTOOL_LINK_MODE_10000baseER_Full_BIT = 46, - - - /* Last allowed bit for __ETHTOOL_LINK_MODE_LEGACY_MASK is bit - * 31. Please do NOT define any SUPPORTED_* or ADVERTISED_* - * macro for bits > 31. The only way to use indices > 31 is to - * use the new ETHTOOL_GLINKSETTINGS/ETHTOOL_SLINKSETTINGS API. - */ - - __ETHTOOL_LINK_MODE_LAST - = ETHTOOL_LINK_MODE_10000baseER_Full_BIT, -}; - -#define __ETHTOOL_LINK_MODE_LEGACY_MASK(base_name) \ - (1UL << (ETHTOOL_LINK_MODE_ ## base_name ## _BIT)) - -/* DEPRECATED macros. Please migrate to - * ETHTOOL_GLINKSETTINGS/ETHTOOL_SLINKSETTINGS API. Please do NOT - * define any new SUPPORTED_* macro for bits > 31. - */ -#define SUPPORTED_10baseT_Half __ETHTOOL_LINK_MODE_LEGACY_MASK(10baseT_Half) -#define SUPPORTED_10baseT_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(10baseT_Full) -#define SUPPORTED_100baseT_Half __ETHTOOL_LINK_MODE_LEGACY_MASK(100baseT_Half) -#define SUPPORTED_100baseT_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(100baseT_Full) -#define SUPPORTED_1000baseT_Half __ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseT_Half) -#define SUPPORTED_1000baseT_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseT_Full) -#define SUPPORTED_Autoneg __ETHTOOL_LINK_MODE_LEGACY_MASK(Autoneg) -#define SUPPORTED_TP __ETHTOOL_LINK_MODE_LEGACY_MASK(TP) -#define SUPPORTED_AUI __ETHTOOL_LINK_MODE_LEGACY_MASK(AUI) -#define SUPPORTED_MII __ETHTOOL_LINK_MODE_LEGACY_MASK(MII) -#define SUPPORTED_FIBRE __ETHTOOL_LINK_MODE_LEGACY_MASK(FIBRE) -#define SUPPORTED_BNC __ETHTOOL_LINK_MODE_LEGACY_MASK(BNC) -#define SUPPORTED_10000baseT_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseT_Full) -#define SUPPORTED_Pause __ETHTOOL_LINK_MODE_LEGACY_MASK(Pause) -#define SUPPORTED_Asym_Pause __ETHTOOL_LINK_MODE_LEGACY_MASK(Asym_Pause) -#define SUPPORTED_2500baseX_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(2500baseX_Full) -#define SUPPORTED_Backplane __ETHTOOL_LINK_MODE_LEGACY_MASK(Backplane) -#define SUPPORTED_1000baseKX_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseKX_Full) -#define SUPPORTED_10000baseKX4_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseKX4_Full) -#define SUPPORTED_10000baseKR_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseKR_Full) -#define SUPPORTED_10000baseR_FEC __ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseR_FEC) -#define SUPPORTED_20000baseMLD2_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(20000baseMLD2_Full) -#define SUPPORTED_20000baseKR2_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(20000baseKR2_Full) -#define SUPPORTED_40000baseKR4_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseKR4_Full) -#define SUPPORTED_40000baseCR4_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseCR4_Full) -#define SUPPORTED_40000baseSR4_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseSR4_Full) -#define SUPPORTED_40000baseLR4_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseLR4_Full) -#define SUPPORTED_56000baseKR4_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseKR4_Full) -#define SUPPORTED_56000baseCR4_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseCR4_Full) -#define SUPPORTED_56000baseSR4_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseSR4_Full) -#define SUPPORTED_56000baseLR4_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseLR4_Full) -/* Please do not define any new SUPPORTED_* macro for bits > 31, see - * notice above. - */ - -/* - * DEPRECATED macros. Please migrate to - * ETHTOOL_GLINKSETTINGS/ETHTOOL_SLINKSETTINGS API. Please do NOT - * define any new ADERTISE_* macro for bits > 31. - */ -#define ADVERTISED_10baseT_Half __ETHTOOL_LINK_MODE_LEGACY_MASK(10baseT_Half) -#define ADVERTISED_10baseT_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(10baseT_Full) -#define ADVERTISED_100baseT_Half __ETHTOOL_LINK_MODE_LEGACY_MASK(100baseT_Half) -#define ADVERTISED_100baseT_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(100baseT_Full) -#define ADVERTISED_1000baseT_Half __ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseT_Half) -#define ADVERTISED_1000baseT_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseT_Full) -#define ADVERTISED_Autoneg __ETHTOOL_LINK_MODE_LEGACY_MASK(Autoneg) -#define ADVERTISED_TP __ETHTOOL_LINK_MODE_LEGACY_MASK(TP) -#define ADVERTISED_AUI __ETHTOOL_LINK_MODE_LEGACY_MASK(AUI) -#define ADVERTISED_MII __ETHTOOL_LINK_MODE_LEGACY_MASK(MII) -#define ADVERTISED_FIBRE __ETHTOOL_LINK_MODE_LEGACY_MASK(FIBRE) -#define ADVERTISED_BNC __ETHTOOL_LINK_MODE_LEGACY_MASK(BNC) -#define ADVERTISED_10000baseT_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseT_Full) -#define ADVERTISED_Pause __ETHTOOL_LINK_MODE_LEGACY_MASK(Pause) -#define ADVERTISED_Asym_Pause __ETHTOOL_LINK_MODE_LEGACY_MASK(Asym_Pause) -#define ADVERTISED_2500baseX_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(2500baseX_Full) -#define ADVERTISED_Backplane __ETHTOOL_LINK_MODE_LEGACY_MASK(Backplane) -#define ADVERTISED_1000baseKX_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(1000baseKX_Full) -#define ADVERTISED_10000baseKX4_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseKX4_Full) -#define ADVERTISED_10000baseKR_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseKR_Full) -#define ADVERTISED_10000baseR_FEC __ETHTOOL_LINK_MODE_LEGACY_MASK(10000baseR_FEC) -#define ADVERTISED_20000baseMLD2_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(20000baseMLD2_Full) -#define ADVERTISED_20000baseKR2_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(20000baseKR2_Full) -#define ADVERTISED_40000baseKR4_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseKR4_Full) -#define ADVERTISED_40000baseCR4_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseCR4_Full) -#define ADVERTISED_40000baseSR4_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseSR4_Full) -#define ADVERTISED_40000baseLR4_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(40000baseLR4_Full) -#define ADVERTISED_56000baseKR4_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseKR4_Full) -#define ADVERTISED_56000baseCR4_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseCR4_Full) -#define ADVERTISED_56000baseSR4_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseSR4_Full) -#define ADVERTISED_56000baseLR4_Full __ETHTOOL_LINK_MODE_LEGACY_MASK(56000baseLR4_Full) -/* Please do not define any new ADVERTISED_* macro for bits > 31, see - * notice above. - */ - -/* The following are all involved in forcing a particular link - * mode for the device for setting things. When getting the - * devices settings, these indicate the current mode and whether - * it was forced up into this mode or autonegotiated. - */ - -/* The forced speed, in units of 1Mb. All values 0 to INT_MAX are legal. */ -#define SPEED_10 10 -#define SPEED_100 100 -#define SPEED_1000 1000 -#define SPEED_2500 2500 -#define SPEED_5000 5000 -#define SPEED_10000 10000 -#define SPEED_20000 20000 -#define SPEED_25000 25000 -#define SPEED_40000 40000 -#define SPEED_50000 50000 -#define SPEED_56000 56000 -#define SPEED_100000 100000 - -#define SPEED_UNKNOWN -1 - -static inline int ethtool_validate_speed(__u32 speed) -{ - return speed <= INT_MAX || speed == SPEED_UNKNOWN; -} - -/* Duplex, half or full. */ -#define DUPLEX_HALF 0x00 -#define DUPLEX_FULL 0x01 -#define DUPLEX_UNKNOWN 0xff - -static inline int ethtool_validate_duplex(__u8 duplex) -{ - switch (duplex) { - case DUPLEX_HALF: - case DUPLEX_FULL: - case DUPLEX_UNKNOWN: - return 1; - } - - return 0; -} - -/* Which connector port. */ -#define PORT_TP 0x00 -#define PORT_AUI 0x01 -#define PORT_MII 0x02 -#define PORT_FIBRE 0x03 -#define PORT_BNC 0x04 -#define PORT_DA 0x05 -#define PORT_NONE 0xef -#define PORT_OTHER 0xff - -/* Which transceiver to use. */ -#define XCVR_INTERNAL 0x00 /* PHY and MAC are in the same package */ -#define XCVR_EXTERNAL 0x01 /* PHY and MAC are in different packages */ -#define XCVR_DUMMY1 0x02 -#define XCVR_DUMMY2 0x03 -#define XCVR_DUMMY3 0x04 - -/* Enable or disable autonegotiation. */ -#define AUTONEG_DISABLE 0x00 -#define AUTONEG_ENABLE 0x01 - -/* MDI or MDI-X status/control - if MDI/MDI_X/AUTO is set then - * the driver is required to renegotiate link - */ -#define ETH_TP_MDI_INVALID 0x00 /* status: unknown; control: unsupported */ -#define ETH_TP_MDI 0x01 /* status: MDI; control: force MDI */ -#define ETH_TP_MDI_X 0x02 /* status: MDI-X; control: force MDI-X */ -#define ETH_TP_MDI_AUTO 0x03 /* control: auto-select */ - -/* Wake-On-Lan options. */ -#define WAKE_PHY (1 << 0) -#define WAKE_UCAST (1 << 1) -#define WAKE_MCAST (1 << 2) -#define WAKE_BCAST (1 << 3) -#define WAKE_ARP (1 << 4) -#define WAKE_MAGIC (1 << 5) -#define WAKE_MAGICSECURE (1 << 6) /* only meaningful if WAKE_MAGIC */ - -/* L2-L4 network traffic flow types */ -#define TCP_V4_FLOW 0x01 /* hash or spec (tcp_ip4_spec) */ -#define UDP_V4_FLOW 0x02 /* hash or spec (udp_ip4_spec) */ -#define SCTP_V4_FLOW 0x03 /* hash or spec (sctp_ip4_spec) */ -#define AH_ESP_V4_FLOW 0x04 /* hash only */ -#define TCP_V6_FLOW 0x05 /* hash or spec (tcp_ip6_spec; nfc only) */ -#define UDP_V6_FLOW 0x06 /* hash or spec (udp_ip6_spec; nfc only) */ -#define SCTP_V6_FLOW 0x07 /* hash or spec (sctp_ip6_spec; nfc only) */ -#define AH_ESP_V6_FLOW 0x08 /* hash only */ -#define AH_V4_FLOW 0x09 /* hash or spec (ah_ip4_spec) */ -#define ESP_V4_FLOW 0x0a /* hash or spec (esp_ip4_spec) */ -#define AH_V6_FLOW 0x0b /* hash or spec (ah_ip6_spec; nfc only) */ -#define ESP_V6_FLOW 0x0c /* hash or spec (esp_ip6_spec; nfc only) */ -#define IPV4_USER_FLOW 0x0d /* spec only (usr_ip4_spec) */ -#define IP_USER_FLOW IPV4_USER_FLOW -#define IPV6_USER_FLOW 0x0e /* spec only (usr_ip6_spec; nfc only) */ -#define IPV4_FLOW 0x10 /* hash only */ -#define IPV6_FLOW 0x11 /* hash only */ -#define ETHER_FLOW 0x12 /* spec only (ether_spec) */ -/* Flag to enable additional fields in struct ethtool_rx_flow_spec */ -#define FLOW_EXT 0x80000000 -#define FLOW_MAC_EXT 0x40000000 - -/* L3-L4 network traffic flow hash options */ -#define RXH_L2DA (1 << 1) -#define RXH_VLAN (1 << 2) -#define RXH_L3_PROTO (1 << 3) -#define RXH_IP_SRC (1 << 4) -#define RXH_IP_DST (1 << 5) -#define RXH_L4_B_0_1 (1 << 6) /* src port in case of TCP/UDP/SCTP */ -#define RXH_L4_B_2_3 (1 << 7) /* dst port in case of TCP/UDP/SCTP */ -#define RXH_DISCARD (1 << 31) - -#define RX_CLS_FLOW_DISC 0xffffffffffffffffULL - -/* Special RX classification rule insert location values */ -#define RX_CLS_LOC_SPECIAL 0x80000000 /* flag */ -#define RX_CLS_LOC_ANY 0xffffffff -#define RX_CLS_LOC_FIRST 0xfffffffe -#define RX_CLS_LOC_LAST 0xfffffffd - -/* EEPROM Standards for plug in modules */ -#define ETH_MODULE_SFF_8079 0x1 -#define ETH_MODULE_SFF_8079_LEN 256 -#define ETH_MODULE_SFF_8472 0x2 -#define ETH_MODULE_SFF_8472_LEN 512 -#define ETH_MODULE_SFF_8636 0x3 -#define ETH_MODULE_SFF_8636_LEN 256 -#define ETH_MODULE_SFF_8436 0x4 -#define ETH_MODULE_SFF_8436_LEN 256 - -/* Reset flags */ -/* The reset() operation must clear the flags for the components which - * were actually reset. On successful return, the flags indicate the - * components which were not reset, either because they do not exist - * in the hardware or because they cannot be reset independently. The - * driver must never reset any components that were not requested. - */ -enum ethtool_reset_flags { - /* These flags represent components dedicated to the interface - * the command is addressed to. Shift any flag left by - * ETH_RESET_SHARED_SHIFT to reset a shared component of the - * same type. - */ - ETH_RESET_MGMT = 1 << 0, /* Management processor */ - ETH_RESET_IRQ = 1 << 1, /* Interrupt requester */ - ETH_RESET_DMA = 1 << 2, /* DMA engine */ - ETH_RESET_FILTER = 1 << 3, /* Filtering/flow direction */ - ETH_RESET_OFFLOAD = 1 << 4, /* Protocol offload */ - ETH_RESET_MAC = 1 << 5, /* Media access controller */ - ETH_RESET_PHY = 1 << 6, /* Transceiver/PHY */ - ETH_RESET_RAM = 1 << 7, /* RAM shared between - * multiple components */ - - ETH_RESET_DEDICATED = 0x0000ffff, /* All components dedicated to - * this interface */ - ETH_RESET_ALL = 0xffffffff, /* All components used by this - * interface, even if shared */ -}; -#define ETH_RESET_SHARED_SHIFT 16 - - -/** - * struct ethtool_link_settings - link control and status - * - * IMPORTANT, Backward compatibility notice: When implementing new - * user-space tools, please first try %ETHTOOL_GLINKSETTINGS, and - * if it succeeds use %ETHTOOL_SLINKSETTINGS to change link - * settings; do not use %ETHTOOL_SSET if %ETHTOOL_GLINKSETTINGS - * succeeded: stick to %ETHTOOL_GLINKSETTINGS/%SLINKSETTINGS in - * that case. Conversely, if %ETHTOOL_GLINKSETTINGS fails, use - * %ETHTOOL_GSET to query and %ETHTOOL_SSET to change link - * settings; do not use %ETHTOOL_SLINKSETTINGS if - * %ETHTOOL_GLINKSETTINGS failed: stick to - * %ETHTOOL_GSET/%ETHTOOL_SSET in that case. - * - * @cmd: Command number = %ETHTOOL_GLINKSETTINGS or %ETHTOOL_SLINKSETTINGS - * @speed: Link speed (Mbps) - * @duplex: Duplex mode; one of %DUPLEX_* - * @port: Physical connector type; one of %PORT_* - * @phy_address: MDIO address of PHY (transceiver); 0 or 255 if not - * applicable. For clause 45 PHYs this is the PRTAD. - * @autoneg: Enable/disable autonegotiation and auto-detection; - * either %AUTONEG_DISABLE or %AUTONEG_ENABLE - * @mdio_support: Bitmask of %ETH_MDIO_SUPPORTS_* flags for the MDIO - * protocols supported by the interface; 0 if unknown. - * Read-only. - * @eth_tp_mdix: Ethernet twisted-pair MDI(-X) status; one of - * %ETH_TP_MDI_*. If the status is unknown or not applicable, the - * value will be %ETH_TP_MDI_INVALID. Read-only. - * @eth_tp_mdix_ctrl: Ethernet twisted pair MDI(-X) control; one of - * %ETH_TP_MDI_*. If MDI(-X) control is not implemented, reads - * yield %ETH_TP_MDI_INVALID and writes may be ignored or rejected. - * When written successfully, the link should be renegotiated if - * necessary. - * @link_mode_masks_nwords: Number of 32-bit words for each of the - * supported, advertising, lp_advertising link mode bitmaps. For - * %ETHTOOL_GLINKSETTINGS: on entry, number of words passed by user - * (>= 0); on return, if handshake in progress, negative if - * request size unsupported by kernel: absolute value indicates - * kernel expected size and all the other fields but cmd - * are 0; otherwise (handshake completed), strictly positive - * to indicate size used by kernel and cmd field stays - * %ETHTOOL_GLINKSETTINGS, all other fields populated by driver. For - * %ETHTOOL_SLINKSETTINGS: must be valid on entry, ie. a positive - * value returned previously by %ETHTOOL_GLINKSETTINGS, otherwise - * refused. For drivers: ignore this field (use kernel's - * __ETHTOOL_LINK_MODE_MASK_NBITS instead), any change to it will - * be overwritten by kernel. - * @supported: Bitmap with each bit meaning given by - * %ethtool_link_mode_bit_indices for the link modes, physical - * connectors and other link features for which the interface - * supports autonegotiation or auto-detection. Read-only. - * @advertising: Bitmap with each bit meaning given by - * %ethtool_link_mode_bit_indices for the link modes, physical - * connectors and other link features that are advertised through - * autonegotiation or enabled for auto-detection. - * @lp_advertising: Bitmap with each bit meaning given by - * %ethtool_link_mode_bit_indices for the link modes, and other - * link features that the link partner advertised through - * autonegotiation; 0 if unknown or not applicable. Read-only. - * - * If autonegotiation is disabled, the speed and @duplex represent the - * fixed link mode and are writable if the driver supports multiple - * link modes. If it is enabled then they are read-only; if the link - * is up they represent the negotiated link mode; if the link is down, - * the speed is 0, %SPEED_UNKNOWN or the highest enabled speed and - * @duplex is %DUPLEX_UNKNOWN or the best enabled duplex mode. - * - * Some hardware interfaces may have multiple PHYs and/or physical - * connectors fitted or do not allow the driver to detect which are - * fitted. For these interfaces @port and/or @phy_address may be - * writable, possibly dependent on @autoneg being %AUTONEG_DISABLE. - * Otherwise, attempts to write different values may be ignored or - * rejected. - * - * Deprecated %ethtool_cmd fields transceiver, maxtxpkt and maxrxpkt - * are not available in %ethtool_link_settings. Until all drivers are - * converted to ignore them or to the new %ethtool_link_settings API, - * for both queries and changes, users should always try - * %ETHTOOL_GLINKSETTINGS first, and if it fails with -ENOTSUPP stick - * only to %ETHTOOL_GSET and %ETHTOOL_SSET consistently. If it - * succeeds, then users should stick to %ETHTOOL_GLINKSETTINGS and - * %ETHTOOL_SLINKSETTINGS (which would support drivers implementing - * either %ethtool_cmd or %ethtool_link_settings). - * - * Users should assume that all fields not marked read-only are - * writable and subject to validation by the driver. They should use - * %ETHTOOL_GLINKSETTINGS to get the current values before making specific - * changes and then applying them with %ETHTOOL_SLINKSETTINGS. - * - * Drivers that implement %get_link_ksettings and/or - * %set_link_ksettings should ignore the @cmd - * and @link_mode_masks_nwords fields (any change to them overwritten - * by kernel), and rely only on kernel's internal - * %__ETHTOOL_LINK_MODE_MASK_NBITS and - * %ethtool_link_mode_mask_t. Drivers that implement - * %set_link_ksettings() should validate all fields other than @cmd - * and @link_mode_masks_nwords that are not described as read-only or - * deprecated, and must ignore all fields described as read-only. - */ -struct ethtool_link_settings { - __u32 cmd; - __u32 speed; - __u8 duplex; - __u8 port; - __u8 phy_address; - __u8 autoneg; - __u8 mdio_support; - __u8 eth_tp_mdix; - __u8 eth_tp_mdix_ctrl; - __s8 link_mode_masks_nwords; - __u32 reserved[8]; - __u32 link_mode_masks[0]; - /* layout of link_mode_masks fields: - * __u32 map_supported[link_mode_masks_nwords]; - * __u32 map_advertising[link_mode_masks_nwords]; - * __u32 map_lp_advertising[link_mode_masks_nwords]; - */ -}; -#endif /* _UAPI_LINUX_ETHTOOL_H */ diff --git a/src/linux/include/uapi/linux/eventpoll.h b/src/linux/include/uapi/linux/eventpoll.h deleted file mode 100644 index 1c31549..0000000 --- a/src/linux/include/uapi/linux/eventpoll.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * include/linux/eventpoll.h ( Efficient event polling implementation ) - * Copyright (C) 2001,...,2006 Davide Libenzi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * Davide Libenzi - * - */ - -#ifndef _UAPI_LINUX_EVENTPOLL_H -#define _UAPI_LINUX_EVENTPOLL_H - -/* For O_CLOEXEC */ -#include -#include - -/* Flags for epoll_create1. */ -#define EPOLL_CLOEXEC O_CLOEXEC - -/* Valid opcodes to issue to sys_epoll_ctl() */ -#define EPOLL_CTL_ADD 1 -#define EPOLL_CTL_DEL 2 -#define EPOLL_CTL_MOD 3 - -/* Set exclusive wakeup mode for the target file descriptor */ -#define EPOLLEXCLUSIVE (1 << 28) - -/* - * Request the handling of system wakeup events so as to prevent system suspends - * from happening while those events are being processed. - * - * Assuming neither EPOLLET nor EPOLLONESHOT is set, system suspends will not be - * re-allowed until epoll_wait is called again after consuming the wakeup - * event(s). - * - * Requires CAP_BLOCK_SUSPEND - */ -#define EPOLLWAKEUP (1 << 29) - -/* Set the One Shot behaviour for the target file descriptor */ -#define EPOLLONESHOT (1 << 30) - -/* Set the Edge Triggered behaviour for the target file descriptor */ -#define EPOLLET (1 << 31) - -/* - * On x86-64 make the 64bit structure have the same alignment as the - * 32bit structure. This makes 32bit emulation easier. - * - * UML/x86_64 needs the same packing as x86_64 - */ -#ifdef __x86_64__ -#define EPOLL_PACKED __attribute__((packed)) -#else -#define EPOLL_PACKED -#endif - -struct epoll_event { - __u32 events; - __u64 data; -} EPOLL_PACKED; - -#ifdef CONFIG_PM_SLEEP -static inline void ep_take_care_of_epollwakeup(struct epoll_event *epev) -{ - if ((epev->events & EPOLLWAKEUP) && !capable(CAP_BLOCK_SUSPEND)) - epev->events &= ~EPOLLWAKEUP; -} -#else -static inline void ep_take_care_of_epollwakeup(struct epoll_event *epev) -{ - epev->events &= ~EPOLLWAKEUP; -} -#endif -#endif /* _UAPI_LINUX_EVENTPOLL_H */ diff --git a/src/linux/include/uapi/linux/falloc.h b/src/linux/include/uapi/linux/falloc.h deleted file mode 100644 index b075f60..0000000 --- a/src/linux/include/uapi/linux/falloc.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef _UAPI_FALLOC_H_ -#define _UAPI_FALLOC_H_ - -#define FALLOC_FL_KEEP_SIZE 0x01 /* default is extend size */ -#define FALLOC_FL_PUNCH_HOLE 0x02 /* de-allocates range */ -#define FALLOC_FL_NO_HIDE_STALE 0x04 /* reserved codepoint */ - -/* - * FALLOC_FL_COLLAPSE_RANGE is used to remove a range of a file - * without leaving a hole in the file. The contents of the file beyond - * the range being removed is appended to the start offset of the range - * being removed (i.e. the hole that was punched is "collapsed"), - * resulting in a file layout that looks like the range that was - * removed never existed. As such collapsing a range of a file changes - * the size of the file, reducing it by the same length of the range - * that has been removed by the operation. - * - * Different filesystems may implement different limitations on the - * granularity of the operation. Most will limit operations to - * filesystem block size boundaries, but this boundary may be larger or - * smaller depending on the filesystem and/or the configuration of the - * filesystem or file. - * - * Attempting to collapse a range that crosses the end of the file is - * considered an illegal operation - just use ftruncate(2) if you need - * to collapse a range that crosses EOF. - */ -#define FALLOC_FL_COLLAPSE_RANGE 0x08 - -/* - * FALLOC_FL_ZERO_RANGE is used to convert a range of file to zeros preferably - * without issuing data IO. Blocks should be preallocated for the regions that - * span holes in the file, and the entire range is preferable converted to - * unwritten extents - even though file system may choose to zero out the - * extent or do whatever which will result in reading zeros from the range - * while the range remains allocated for the file. - * - * This can be also used to preallocate blocks past EOF in the same way as - * with fallocate. Flag FALLOC_FL_KEEP_SIZE should cause the inode - * size to remain the same. - */ -#define FALLOC_FL_ZERO_RANGE 0x10 - -/* - * FALLOC_FL_INSERT_RANGE is use to insert space within the file size without - * overwriting any existing data. The contents of the file beyond offset are - * shifted towards right by len bytes to create a hole. As such, this - * operation will increase the size of the file by len bytes. - * - * Different filesystems may implement different limitations on the granularity - * of the operation. Most will limit operations to filesystem block size - * boundaries, but this boundary may be larger or smaller depending on - * the filesystem and/or the configuration of the filesystem or file. - * - * Attempting to insert space using this flag at OR beyond the end of - * the file is considered an illegal operation - just use ftruncate(2) or - * fallocate(2) with mode 0 for such type of operations. - */ -#define FALLOC_FL_INSERT_RANGE 0x20 - -/* - * FALLOC_FL_UNSHARE_RANGE is used to unshare shared blocks within the - * file size without overwriting any existing data. The purpose of this - * call is to preemptively reallocate any blocks that are subject to - * copy-on-write. - * - * Different filesystems may implement different limitations on the - * granularity of the operation. Most will limit operations to filesystem - * block size boundaries, but this boundary may be larger or smaller - * depending on the filesystem and/or the configuration of the filesystem - * or file. - * - * This flag can only be used with allocate-mode fallocate, which is - * to say that it cannot be used with the punch, zero, collapse, or - * insert range modes. - */ -#define FALLOC_FL_UNSHARE_RANGE 0x40 - -#endif /* _UAPI_FALLOC_H_ */ diff --git a/src/linux/include/uapi/linux/fcntl.h b/src/linux/include/uapi/linux/fcntl.h deleted file mode 100644 index beed138..0000000 --- a/src/linux/include/uapi/linux/fcntl.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef _UAPI_LINUX_FCNTL_H -#define _UAPI_LINUX_FCNTL_H - -#include - -#define F_SETLEASE (F_LINUX_SPECIFIC_BASE + 0) -#define F_GETLEASE (F_LINUX_SPECIFIC_BASE + 1) - -/* - * Cancel a blocking posix lock; internal use only until we expose an - * asynchronous lock api to userspace: - */ -#define F_CANCELLK (F_LINUX_SPECIFIC_BASE + 5) - -/* Create a file descriptor with FD_CLOEXEC set. */ -#define F_DUPFD_CLOEXEC (F_LINUX_SPECIFIC_BASE + 6) - -/* - * Request nofications on a directory. - * See below for events that may be notified. - */ -#define F_NOTIFY (F_LINUX_SPECIFIC_BASE+2) - -/* - * Set and get of pipe page size array - */ -#define F_SETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 7) -#define F_GETPIPE_SZ (F_LINUX_SPECIFIC_BASE + 8) - -/* - * Set/Get seals - */ -#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9) -#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10) - -/* - * Types of seals - */ -#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */ -#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */ -#define F_SEAL_GROW 0x0004 /* prevent file from growing */ -#define F_SEAL_WRITE 0x0008 /* prevent writes */ -/* (1U << 31) is reserved for signed error codes */ - -/* - * Types of directory notifications that may be requested. - */ -#define DN_ACCESS 0x00000001 /* File accessed */ -#define DN_MODIFY 0x00000002 /* File modified */ -#define DN_CREATE 0x00000004 /* File created */ -#define DN_DELETE 0x00000008 /* File removed */ -#define DN_RENAME 0x00000010 /* File renamed */ -#define DN_ATTRIB 0x00000020 /* File changed attibutes */ -#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */ - -#define AT_FDCWD -100 /* Special value used to indicate - openat should use the current - working directory. */ -#define AT_SYMLINK_NOFOLLOW 0x100 /* Do not follow symbolic links. */ -#define AT_REMOVEDIR 0x200 /* Remove directory instead of - unlinking file. */ -#define AT_SYMLINK_FOLLOW 0x400 /* Follow symbolic links. */ -#define AT_NO_AUTOMOUNT 0x800 /* Suppress terminal automount traversal */ -#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */ - - -#endif /* _UAPI_LINUX_FCNTL_H */ diff --git a/src/linux/include/uapi/linux/fd.h b/src/linux/include/uapi/linux/fd.h deleted file mode 100644 index 84c517c..0000000 --- a/src/linux/include/uapi/linux/fd.h +++ /dev/null @@ -1,383 +0,0 @@ -#ifndef _UAPI_LINUX_FD_H -#define _UAPI_LINUX_FD_H - -#include -#include - -/* New file layout: Now the ioctl definitions immediately follow the - * definitions of the structures that they use */ - -/* - * Geometry - */ -struct floppy_struct { - unsigned int size, /* nr of sectors total */ - sect, /* sectors per track */ - head, /* nr of heads */ - track, /* nr of tracks */ - stretch; /* bit 0 !=0 means double track steps */ - /* bit 1 != 0 means swap sides */ - /* bits 2..9 give the first sector */ - /* number (the LSB is flipped) */ -#define FD_STRETCH 1 -#define FD_SWAPSIDES 2 -#define FD_ZEROBASED 4 -#define FD_SECTBASEMASK 0x3FC -#define FD_MKSECTBASE(s) (((s) ^ 1) << 2) -#define FD_SECTBASE(floppy) ((((floppy)->stretch & FD_SECTBASEMASK) >> 2) ^ 1) - - unsigned char gap, /* gap1 size */ - - rate, /* data rate. |= 0x40 for perpendicular */ -#define FD_2M 0x4 -#define FD_SIZECODEMASK 0x38 -#define FD_SIZECODE(floppy) (((((floppy)->rate&FD_SIZECODEMASK)>> 3)+ 2) %8) -#define FD_SECTSIZE(floppy) ( (floppy)->rate & FD_2M ? \ - 512 : 128 << FD_SIZECODE(floppy) ) -#define FD_PERP 0x40 - - spec1, /* stepping rate, head unload time */ - fmt_gap; /* gap2 size */ - const char * name; /* used only for predefined formats */ -}; - - -/* commands needing write access have 0x40 set */ -/* commands needing super user access have 0x80 set */ - -#define FDCLRPRM _IO(2, 0x41) -/* clear user-defined parameters */ - -#define FDSETPRM _IOW(2, 0x42, struct floppy_struct) -#define FDSETMEDIAPRM FDSETPRM -/* set user-defined parameters for current media */ - -#define FDDEFPRM _IOW(2, 0x43, struct floppy_struct) -#define FDGETPRM _IOR(2, 0x04, struct floppy_struct) -#define FDDEFMEDIAPRM FDDEFPRM -#define FDGETMEDIAPRM FDGETPRM -/* set/get disk parameters */ - - -#define FDMSGON _IO(2,0x45) -#define FDMSGOFF _IO(2,0x46) -/* issue/don't issue kernel messages on media type change */ - - -/* - * Formatting (obsolete) - */ -#define FD_FILL_BYTE 0xF6 /* format fill byte. */ - -struct format_descr { - unsigned int device,head,track; -}; - -#define FDFMTBEG _IO(2,0x47) -/* begin formatting a disk */ -#define FDFMTTRK _IOW(2,0x48, struct format_descr) -/* format the specified track */ -#define FDFMTEND _IO(2,0x49) -/* end formatting a disk */ - - -/* - * Error thresholds - */ -struct floppy_max_errors { - unsigned int - abort, /* number of errors to be reached before aborting */ - read_track, /* maximal number of errors permitted to read an - * entire track at once */ - reset, /* maximal number of errors before a reset is tried */ - recal, /* maximal number of errors before a recalibrate is - * tried */ - - /* - * Threshold for reporting FDC errors to the console. - * Setting this to zero may flood your screen when using - * ultra cheap floppies ;-) - */ - reporting; - -}; - -#define FDSETEMSGTRESH _IO(2,0x4a) -/* set fdc error reporting threshold */ - -#define FDFLUSH _IO(2,0x4b) -/* flush buffers for media; either for verifying media, or for - * handling a media change without closing the file descriptor */ - -#define FDSETMAXERRS _IOW(2, 0x4c, struct floppy_max_errors) -#define FDGETMAXERRS _IOR(2, 0x0e, struct floppy_max_errors) -/* set/get abortion and read_track threshold. See also floppy_drive_params - * structure */ - - -typedef char floppy_drive_name[16]; -#define FDGETDRVTYP _IOR(2, 0x0f, floppy_drive_name) -/* get drive type: 5 1/4 or 3 1/2 */ - - -/* - * Drive parameters (user modifiable) - */ -struct floppy_drive_params { - signed char cmos; /* CMOS type */ - - /* Spec2 is (HLD<<1 | ND), where HLD is head load time (1=2ms, 2=4 ms - * etc) and ND is set means no DMA. Hardcoded to 6 (HLD=6ms, use DMA). - */ - unsigned long max_dtr; /* Step rate, usec */ - unsigned long hlt; /* Head load/settle time, msec */ - unsigned long hut; /* Head unload time (remnant of - * 8" drives) */ - unsigned long srt; /* Step rate, usec */ - - unsigned long spinup; /* time needed for spinup (expressed - * in jiffies) */ - unsigned long spindown; /* timeout needed for spindown */ - unsigned char spindown_offset; /* decides in which position the disk - * will stop */ - unsigned char select_delay; /* delay to wait after select */ - unsigned char rps; /* rotations per second */ - unsigned char tracks; /* maximum number of tracks */ - unsigned long timeout; /* timeout for interrupt requests */ - - unsigned char interleave_sect; /* if there are more sectors, use - * interleave */ - - struct floppy_max_errors max_errors; - - char flags; /* various flags, including ftd_msg */ -/* - * Announce successful media type detection and media information loss after - * disk changes. - * Also used to enable/disable printing of overrun warnings. - */ - -#define FTD_MSG 0x10 -#define FD_BROKEN_DCL 0x20 -#define FD_DEBUG 0x02 -#define FD_SILENT_DCL_CLEAR 0x4 -#define FD_INVERTED_DCL 0x80 /* must be 0x80, because of hardware - considerations */ - - char read_track; /* use readtrack during probing? */ - -/* - * Auto-detection. Each drive type has eight formats which are - * used in succession to try to read the disk. If the FDC cannot lock onto - * the disk, the next format is tried. This uses the variable 'probing'. - */ - short autodetect[8]; /* autodetected formats */ - - int checkfreq; /* how often should the drive be checked for disk - * changes */ - int native_format; /* native format of this drive */ -}; - -enum { - FD_NEED_TWADDLE_BIT, /* more magic */ - FD_VERIFY_BIT, /* inquire for write protection */ - FD_DISK_NEWCHANGE_BIT, /* change detected, and no action undertaken yet - * to clear media change status */ - FD_UNUSED_BIT, - FD_DISK_CHANGED_BIT, /* disk has been changed since last i/o */ - FD_DISK_WRITABLE_BIT, /* disk is writable */ - FD_OPEN_SHOULD_FAIL_BIT -}; - -#define FDSETDRVPRM _IOW(2, 0x90, struct floppy_drive_params) -#define FDGETDRVPRM _IOR(2, 0x11, struct floppy_drive_params) -/* set/get drive parameters */ - - -/* - * Current drive state (not directly modifiable by user, readonly) - */ -struct floppy_drive_struct { - unsigned long flags; -/* values for these flags */ -#define FD_NEED_TWADDLE (1 << FD_NEED_TWADDLE_BIT) -#define FD_VERIFY (1 << FD_VERIFY_BIT) -#define FD_DISK_NEWCHANGE (1 << FD_DISK_NEWCHANGE_BIT) -#define FD_DISK_CHANGED (1 << FD_DISK_CHANGED_BIT) -#define FD_DISK_WRITABLE (1 << FD_DISK_WRITABLE_BIT) - - unsigned long spinup_date; - unsigned long select_date; - unsigned long first_read_date; - short probed_format; - short track; /* current track */ - short maxblock; /* id of highest block read */ - short maxtrack; /* id of highest half track read */ - int generation; /* how many diskchanges? */ - -/* - * (User-provided) media information is _not_ discarded after a media change - * if the corresponding keep_data flag is non-zero. Positive values are - * decremented after each probe. - */ - int keep_data; - - /* Prevent "aliased" accesses. */ - int fd_ref; - int fd_device; - unsigned long last_checked; /* when was the drive last checked for a disk - * change? */ - - char *dmabuf; - int bufblocks; -}; - -#define FDGETDRVSTAT _IOR(2, 0x12, struct floppy_drive_struct) -#define FDPOLLDRVSTAT _IOR(2, 0x13, struct floppy_drive_struct) -/* get drive state: GET returns the cached state, POLL polls for new state */ - - -/* - * reset FDC - */ -enum reset_mode { - FD_RESET_IF_NEEDED, /* reset only if the reset flags is set */ - FD_RESET_IF_RAWCMD, /* obsolete */ - FD_RESET_ALWAYS /* reset always */ -}; -#define FDRESET _IO(2, 0x54) - - -/* - * FDC state - */ -struct floppy_fdc_state { - int spec1; /* spec1 value last used */ - int spec2; /* spec2 value last used */ - int dtr; - unsigned char version; /* FDC version code */ - unsigned char dor; - unsigned long address; /* io address */ - unsigned int rawcmd:2; - unsigned int reset:1; - unsigned int need_configure:1; - unsigned int perp_mode:2; - unsigned int has_fifo:1; - unsigned int driver_version; /* version code for floppy driver */ -#define FD_DRIVER_VERSION 0x100 -/* user programs using the floppy API should use floppy_fdc_state to - * get the version number of the floppy driver that they are running - * on. If this version number is bigger than the one compiled into the - * user program (the FD_DRIVER_VERSION define), it should be prepared - * to bigger structures - */ - - unsigned char track[4]; - /* Position of the heads of the 4 units attached to this FDC, - * as stored on the FDC. In the future, the position as stored - * on the FDC might not agree with the actual physical - * position of these drive heads. By allowing such - * disagreement, it will be possible to reset the FDC without - * incurring the expensive cost of repositioning all heads. - * Right now, these positions are hard wired to 0. */ - -}; - -#define FDGETFDCSTAT _IOR(2, 0x15, struct floppy_fdc_state) - - -/* - * Asynchronous Write error tracking - */ -struct floppy_write_errors { - /* Write error logging. - * - * These fields can be cleared with the FDWERRORCLR ioctl. - * Only writes that were attempted but failed due to a physical media - * error are logged. write(2) calls that fail and return an error code - * to the user process are not counted. - */ - - unsigned int write_errors; /* number of physical write errors - * encountered */ - - /* position of first and last write errors */ - unsigned long first_error_sector; - int first_error_generation; - unsigned long last_error_sector; - int last_error_generation; - - unsigned int badness; /* highest retry count for a read or write - * operation */ -}; - -#define FDWERRORCLR _IO(2, 0x56) -/* clear write error and badness information */ -#define FDWERRORGET _IOR(2, 0x17, struct floppy_write_errors) -/* get write error and badness information */ - - -/* - * Raw commands - */ -/* new interface flag: now we can do them in batches */ -#define FDHAVEBATCHEDRAWCMD - -struct floppy_raw_cmd { - unsigned int flags; -#define FD_RAW_READ 1 -#define FD_RAW_WRITE 2 -#define FD_RAW_NO_MOTOR 4 -#define FD_RAW_DISK_CHANGE 4 /* out: disk change flag was set */ -#define FD_RAW_INTR 8 /* wait for an interrupt */ -#define FD_RAW_SPIN 0x10 /* spin up the disk for this command */ -#define FD_RAW_NO_MOTOR_AFTER 0x20 /* switch the motor off after command - * completion */ -#define FD_RAW_NEED_DISK 0x40 /* this command needs a disk to be present */ -#define FD_RAW_NEED_SEEK 0x80 /* this command uses an implied seek (soft) */ - -/* more "in" flags */ -#define FD_RAW_MORE 0x100 /* more records follow */ -#define FD_RAW_STOP_IF_FAILURE 0x200 /* stop if we encounter a failure */ -#define FD_RAW_STOP_IF_SUCCESS 0x400 /* stop if command successful */ -#define FD_RAW_SOFTFAILURE 0x800 /* consider the return value for failure - * detection too */ - -/* more "out" flags */ -#define FD_RAW_FAILURE 0x10000 /* command sent to fdc, fdc returned error */ -#define FD_RAW_HARDFAILURE 0x20000 /* fdc had to be reset, or timed out */ - - void __user *data; - char *kernel_data; /* location of data buffer in the kernel */ - struct floppy_raw_cmd *next; /* used for chaining of raw cmd's - * within the kernel */ - long length; /* in: length of dma transfer. out: remaining bytes */ - long phys_length; /* physical length, if different from dma length */ - int buffer_length; /* length of allocated buffer */ - - unsigned char rate; - unsigned char cmd_count; - unsigned char cmd[16]; - unsigned char reply_count; - unsigned char reply[16]; - int track; - int resultcode; - - int reserved1; - int reserved2; -}; - -#define FDRAWCMD _IO(2, 0x58) -/* send a raw command to the fdc. Structure size not included, because of - * batches */ - -#define FDTWADDLE _IO(2, 0x59) -/* flicker motor-on bit before reading a sector. Experimental */ - - -#define FDEJECT _IO(2, 0x5a) -/* eject the disk */ - - - -#endif /* _UAPI_LINUX_FD_H */ diff --git a/src/linux/include/uapi/linux/fib_rules.h b/src/linux/include/uapi/linux/fib_rules.h deleted file mode 100644 index 14404b3..0000000 --- a/src/linux/include/uapi/linux/fib_rules.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef __LINUX_FIB_RULES_H -#define __LINUX_FIB_RULES_H - -#include -#include - -/* rule is permanent, and cannot be deleted */ -#define FIB_RULE_PERMANENT 0x00000001 -#define FIB_RULE_INVERT 0x00000002 -#define FIB_RULE_UNRESOLVED 0x00000004 -#define FIB_RULE_IIF_DETACHED 0x00000008 -#define FIB_RULE_DEV_DETACHED FIB_RULE_IIF_DETACHED -#define FIB_RULE_OIF_DETACHED 0x00000010 - -/* try to find source address in routing lookups */ -#define FIB_RULE_FIND_SADDR 0x00010000 - -struct fib_rule_hdr { - __u8 family; - __u8 dst_len; - __u8 src_len; - __u8 tos; - - __u8 table; - __u8 res1; /* reserved */ - __u8 res2; /* reserved */ - __u8 action; - - __u32 flags; -}; - -enum { - FRA_UNSPEC, - FRA_DST, /* destination address */ - FRA_SRC, /* source address */ - FRA_IIFNAME, /* interface name */ -#define FRA_IFNAME FRA_IIFNAME - FRA_GOTO, /* target to jump to (FR_ACT_GOTO) */ - FRA_UNUSED2, - FRA_PRIORITY, /* priority/preference */ - FRA_UNUSED3, - FRA_UNUSED4, - FRA_UNUSED5, - FRA_FWMARK, /* mark */ - FRA_FLOW, /* flow/class id */ - FRA_TUN_ID, - FRA_SUPPRESS_IFGROUP, - FRA_SUPPRESS_PREFIXLEN, - FRA_TABLE, /* Extended table id */ - FRA_FWMASK, /* mask for netfilter mark */ - FRA_OIFNAME, - FRA_PAD, - FRA_L3MDEV, /* iif or oif is l3mdev goto its table */ - __FRA_MAX -}; - -#define FRA_MAX (__FRA_MAX - 1) - -enum { - FR_ACT_UNSPEC, - FR_ACT_TO_TBL, /* Pass to fixed table */ - FR_ACT_GOTO, /* Jump to another rule */ - FR_ACT_NOP, /* No operation */ - FR_ACT_RES3, - FR_ACT_RES4, - FR_ACT_BLACKHOLE, /* Drop without notification */ - FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */ - FR_ACT_PROHIBIT, /* Drop with EACCES */ - __FR_ACT_MAX, -}; - -#define FR_ACT_MAX (__FR_ACT_MAX - 1) - -#endif diff --git a/src/linux/include/uapi/linux/fiemap.h b/src/linux/include/uapi/linux/fiemap.h deleted file mode 100644 index 0c51d61..0000000 --- a/src/linux/include/uapi/linux/fiemap.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * FS_IOC_FIEMAP ioctl infrastructure. - * - * Some portions copyright (C) 2007 Cluster File Systems, Inc - * - * Authors: Mark Fasheh - * Kalpak Shah - * Andreas Dilger - */ - -#ifndef _LINUX_FIEMAP_H -#define _LINUX_FIEMAP_H - -#include - -struct fiemap_extent { - __u64 fe_logical; /* logical offset in bytes for the start of - * the extent from the beginning of the file */ - __u64 fe_physical; /* physical offset in bytes for the start - * of the extent from the beginning of the disk */ - __u64 fe_length; /* length in bytes for this extent */ - __u64 fe_reserved64[2]; - __u32 fe_flags; /* FIEMAP_EXTENT_* flags for this extent */ - __u32 fe_reserved[3]; -}; - -struct fiemap { - __u64 fm_start; /* logical offset (inclusive) at - * which to start mapping (in) */ - __u64 fm_length; /* logical length of mapping which - * userspace wants (in) */ - __u32 fm_flags; /* FIEMAP_FLAG_* flags for request (in/out) */ - __u32 fm_mapped_extents;/* number of extents that were mapped (out) */ - __u32 fm_extent_count; /* size of fm_extents array (in) */ - __u32 fm_reserved; - struct fiemap_extent fm_extents[0]; /* array of mapped extents (out) */ -}; - -#define FIEMAP_MAX_OFFSET (~0ULL) - -#define FIEMAP_FLAG_SYNC 0x00000001 /* sync file data before map */ -#define FIEMAP_FLAG_XATTR 0x00000002 /* map extended attribute tree */ -#define FIEMAP_FLAG_CACHE 0x00000004 /* request caching of the extents */ - -#define FIEMAP_FLAGS_COMPAT (FIEMAP_FLAG_SYNC | FIEMAP_FLAG_XATTR) - -#define FIEMAP_EXTENT_LAST 0x00000001 /* Last extent in file. */ -#define FIEMAP_EXTENT_UNKNOWN 0x00000002 /* Data location unknown. */ -#define FIEMAP_EXTENT_DELALLOC 0x00000004 /* Location still pending. - * Sets EXTENT_UNKNOWN. */ -#define FIEMAP_EXTENT_ENCODED 0x00000008 /* Data can not be read - * while fs is unmounted */ -#define FIEMAP_EXTENT_DATA_ENCRYPTED 0x00000080 /* Data is encrypted by fs. - * Sets EXTENT_NO_BYPASS. */ -#define FIEMAP_EXTENT_NOT_ALIGNED 0x00000100 /* Extent offsets may not be - * block aligned. */ -#define FIEMAP_EXTENT_DATA_INLINE 0x00000200 /* Data mixed with metadata. - * Sets EXTENT_NOT_ALIGNED.*/ -#define FIEMAP_EXTENT_DATA_TAIL 0x00000400 /* Multiple files in block. - * Sets EXTENT_NOT_ALIGNED.*/ -#define FIEMAP_EXTENT_UNWRITTEN 0x00000800 /* Space allocated, but - * no data (i.e. zero). */ -#define FIEMAP_EXTENT_MERGED 0x00001000 /* File does not natively - * support extents. Result - * merged for efficiency. */ -#define FIEMAP_EXTENT_SHARED 0x00002000 /* Space shared with other - * files. */ - -#endif /* _LINUX_FIEMAP_H */ diff --git a/src/linux/include/uapi/linux/filter.h b/src/linux/include/uapi/linux/filter.h deleted file mode 100644 index c97340e..0000000 --- a/src/linux/include/uapi/linux/filter.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Linux Socket Filter Data Structures - */ - -#ifndef _UAPI__LINUX_FILTER_H__ -#define _UAPI__LINUX_FILTER_H__ - -#include -#include -#include - -/* - * Current version of the filter code architecture. - */ -#define BPF_MAJOR_VERSION 1 -#define BPF_MINOR_VERSION 1 - -/* - * Try and keep these values and structures similar to BSD, especially - * the BPF code definitions which need to match so you can share filters - */ - -struct sock_filter { /* Filter block */ - __u16 code; /* Actual filter code */ - __u8 jt; /* Jump true */ - __u8 jf; /* Jump false */ - __u32 k; /* Generic multiuse field */ -}; - -struct sock_fprog { /* Required for SO_ATTACH_FILTER. */ - unsigned short len; /* Number of filter blocks */ - struct sock_filter __user *filter; -}; - -/* ret - BPF_K and BPF_X also apply */ -#define BPF_RVAL(code) ((code) & 0x18) -#define BPF_A 0x10 - -/* misc */ -#define BPF_MISCOP(code) ((code) & 0xf8) -#define BPF_TAX 0x00 -#define BPF_TXA 0x80 - -/* - * Macros for filter block array initializers. - */ -#ifndef BPF_STMT -#define BPF_STMT(code, k) { (unsigned short)(code), 0, 0, k } -#endif -#ifndef BPF_JUMP -#define BPF_JUMP(code, k, jt, jf) { (unsigned short)(code), jt, jf, k } -#endif - -/* - * Number of scratch memory words for: BPF_ST and BPF_STX - */ -#define BPF_MEMWORDS 16 - -/* RATIONALE. Negative offsets are invalid in BPF. - We use them to reference ancillary data. - Unlike introduction new instructions, it does not break - existing compilers/optimizers. - */ -#define SKF_AD_OFF (-0x1000) -#define SKF_AD_PROTOCOL 0 -#define SKF_AD_PKTTYPE 4 -#define SKF_AD_IFINDEX 8 -#define SKF_AD_NLATTR 12 -#define SKF_AD_NLATTR_NEST 16 -#define SKF_AD_MARK 20 -#define SKF_AD_QUEUE 24 -#define SKF_AD_HATYPE 28 -#define SKF_AD_RXHASH 32 -#define SKF_AD_CPU 36 -#define SKF_AD_ALU_XOR_X 40 -#define SKF_AD_VLAN_TAG 44 -#define SKF_AD_VLAN_TAG_PRESENT 48 -#define SKF_AD_PAY_OFFSET 52 -#define SKF_AD_RANDOM 56 -#define SKF_AD_VLAN_TPID 60 -#define SKF_AD_MAX 64 - -#define SKF_NET_OFF (-0x100000) -#define SKF_LL_OFF (-0x200000) - -#define BPF_NET_OFF SKF_NET_OFF -#define BPF_LL_OFF SKF_LL_OFF - -#endif /* _UAPI__LINUX_FILTER_H__ */ diff --git a/src/linux/include/uapi/linux/fs.h b/src/linux/include/uapi/linux/fs.h deleted file mode 100644 index acb2b61..0000000 --- a/src/linux/include/uapi/linux/fs.h +++ /dev/null @@ -1,332 +0,0 @@ -#ifndef _UAPI_LINUX_FS_H -#define _UAPI_LINUX_FS_H - -/* - * This file has definitions for some important file table structures - * and constants and structures used by various generic file system - * ioctl's. Please do not make any changes in this file before - * sending patches for review to linux-fsdevel@vger.kernel.org and - * linux-api@vger.kernel.org. - */ - -#include -#include -#include - -/* - * It's silly to have NR_OPEN bigger than NR_FILE, but you can change - * the file limit at runtime and only root can increase the per-process - * nr_file rlimit, so it's safe to set up a ridiculously high absolute - * upper limit on files-per-process. - * - * Some programs (notably those using select()) may have to be - * recompiled to take full advantage of the new limits.. - */ - -/* Fixed constants first: */ -#undef NR_OPEN -#define INR_OPEN_CUR 1024 /* Initial setting for nfile rlimits */ -#define INR_OPEN_MAX 4096 /* Hard limit for nfile rlimits */ - -#define BLOCK_SIZE_BITS 10 -#define BLOCK_SIZE (1< -#include - -/* Second argument to futex syscall */ - - -#define FUTEX_WAIT 0 -#define FUTEX_WAKE 1 -#define FUTEX_FD 2 -#define FUTEX_REQUEUE 3 -#define FUTEX_CMP_REQUEUE 4 -#define FUTEX_WAKE_OP 5 -#define FUTEX_LOCK_PI 6 -#define FUTEX_UNLOCK_PI 7 -#define FUTEX_TRYLOCK_PI 8 -#define FUTEX_WAIT_BITSET 9 -#define FUTEX_WAKE_BITSET 10 -#define FUTEX_WAIT_REQUEUE_PI 11 -#define FUTEX_CMP_REQUEUE_PI 12 - -#define FUTEX_PRIVATE_FLAG 128 -#define FUTEX_CLOCK_REALTIME 256 -#define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME) - -#define FUTEX_WAIT_PRIVATE (FUTEX_WAIT | FUTEX_PRIVATE_FLAG) -#define FUTEX_WAKE_PRIVATE (FUTEX_WAKE | FUTEX_PRIVATE_FLAG) -#define FUTEX_REQUEUE_PRIVATE (FUTEX_REQUEUE | FUTEX_PRIVATE_FLAG) -#define FUTEX_CMP_REQUEUE_PRIVATE (FUTEX_CMP_REQUEUE | FUTEX_PRIVATE_FLAG) -#define FUTEX_WAKE_OP_PRIVATE (FUTEX_WAKE_OP | FUTEX_PRIVATE_FLAG) -#define FUTEX_LOCK_PI_PRIVATE (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG) -#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG) -#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG) -#define FUTEX_WAIT_BITSET_PRIVATE (FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG) -#define FUTEX_WAKE_BITSET_PRIVATE (FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG) -#define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_WAIT_REQUEUE_PI | \ - FUTEX_PRIVATE_FLAG) -#define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | \ - FUTEX_PRIVATE_FLAG) - -/* - * Support for robust futexes: the kernel cleans up held futexes at - * thread exit time. - */ - -/* - * Per-lock list entry - embedded in user-space locks, somewhere close - * to the futex field. (Note: user-space uses a double-linked list to - * achieve O(1) list add and remove, but the kernel only needs to know - * about the forward link) - * - * NOTE: this structure is part of the syscall ABI, and must not be - * changed. - */ -struct robust_list { - struct robust_list __user *next; -}; - -/* - * Per-thread list head: - * - * NOTE: this structure is part of the syscall ABI, and must only be - * changed if the change is first communicated with the glibc folks. - * (When an incompatible change is done, we'll increase the structure - * size, which glibc will detect) - */ -struct robust_list_head { - /* - * The head of the list. Points back to itself if empty: - */ - struct robust_list list; - - /* - * This relative offset is set by user-space, it gives the kernel - * the relative position of the futex field to examine. This way - * we keep userspace flexible, to freely shape its data-structure, - * without hardcoding any particular offset into the kernel: - */ - long futex_offset; - - /* - * The death of the thread may race with userspace setting - * up a lock's links. So to handle this race, userspace first - * sets this field to the address of the to-be-taken lock, - * then does the lock acquire, and then adds itself to the - * list, and then clears this field. Hence the kernel will - * always have full knowledge of all locks that the thread - * _might_ have taken. We check the owner TID in any case, - * so only truly owned locks will be handled. - */ - struct robust_list __user *list_op_pending; -}; - -/* - * Are there any waiters for this robust futex: - */ -#define FUTEX_WAITERS 0x80000000 - -/* - * The kernel signals via this bit that a thread holding a futex - * has exited without unlocking the futex. The kernel also does - * a FUTEX_WAKE on such futexes, after setting the bit, to wake - * up any possible waiters: - */ -#define FUTEX_OWNER_DIED 0x40000000 - -/* - * The rest of the robust-futex field is for the TID: - */ -#define FUTEX_TID_MASK 0x3fffffff - -/* - * This limit protects against a deliberately circular list. - * (Not worth introducing an rlimit for it) - */ -#define ROBUST_LIST_LIMIT 2048 - -/* - * bitset with all bits set for the FUTEX_xxx_BITSET OPs to request a - * match of any bit. - */ -#define FUTEX_BITSET_MATCH_ANY 0xffffffff - - -#define FUTEX_OP_SET 0 /* *(int *)UADDR2 = OPARG; */ -#define FUTEX_OP_ADD 1 /* *(int *)UADDR2 += OPARG; */ -#define FUTEX_OP_OR 2 /* *(int *)UADDR2 |= OPARG; */ -#define FUTEX_OP_ANDN 3 /* *(int *)UADDR2 &= ~OPARG; */ -#define FUTEX_OP_XOR 4 /* *(int *)UADDR2 ^= OPARG; */ - -#define FUTEX_OP_OPARG_SHIFT 8 /* Use (1 << OPARG) instead of OPARG. */ - -#define FUTEX_OP_CMP_EQ 0 /* if (oldval == CMPARG) wake */ -#define FUTEX_OP_CMP_NE 1 /* if (oldval != CMPARG) wake */ -#define FUTEX_OP_CMP_LT 2 /* if (oldval < CMPARG) wake */ -#define FUTEX_OP_CMP_LE 3 /* if (oldval <= CMPARG) wake */ -#define FUTEX_OP_CMP_GT 4 /* if (oldval > CMPARG) wake */ -#define FUTEX_OP_CMP_GE 5 /* if (oldval >= CMPARG) wake */ - -/* FUTEX_WAKE_OP will perform atomically - int oldval = *(int *)UADDR2; - *(int *)UADDR2 = oldval OP OPARG; - if (oldval CMP CMPARG) - wake UADDR2; */ - -#define FUTEX_OP(op, oparg, cmp, cmparg) \ - (((op & 0xf) << 28) | ((cmp & 0xf) << 24) \ - | ((oparg & 0xfff) << 12) | (cmparg & 0xfff)) - -#endif /* _UAPI_LINUX_FUTEX_H */ diff --git a/src/linux/include/uapi/linux/gen_stats.h b/src/linux/include/uapi/linux/gen_stats.h deleted file mode 100644 index 52deccc..0000000 --- a/src/linux/include/uapi/linux/gen_stats.h +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef __LINUX_GEN_STATS_H -#define __LINUX_GEN_STATS_H - -#include - -enum { - TCA_STATS_UNSPEC, - TCA_STATS_BASIC, - TCA_STATS_RATE_EST, - TCA_STATS_QUEUE, - TCA_STATS_APP, - TCA_STATS_RATE_EST64, - TCA_STATS_PAD, - __TCA_STATS_MAX, -}; -#define TCA_STATS_MAX (__TCA_STATS_MAX - 1) - -/** - * struct gnet_stats_basic - byte/packet throughput statistics - * @bytes: number of seen bytes - * @packets: number of seen packets - */ -struct gnet_stats_basic { - __u64 bytes; - __u32 packets; -}; -struct gnet_stats_basic_packed { - __u64 bytes; - __u32 packets; -} __attribute__ ((packed)); - -/** - * struct gnet_stats_rate_est - rate estimator - * @bps: current byte rate - * @pps: current packet rate - */ -struct gnet_stats_rate_est { - __u32 bps; - __u32 pps; -}; - -/** - * struct gnet_stats_rate_est64 - rate estimator - * @bps: current byte rate - * @pps: current packet rate - */ -struct gnet_stats_rate_est64 { - __u64 bps; - __u64 pps; -}; - -/** - * struct gnet_stats_queue - queuing statistics - * @qlen: queue length - * @backlog: backlog size of queue - * @drops: number of dropped packets - * @requeues: number of requeues - * @overlimits: number of enqueues over the limit - */ -struct gnet_stats_queue { - __u32 qlen; - __u32 backlog; - __u32 drops; - __u32 requeues; - __u32 overlimits; -}; - -/** - * struct gnet_estimator - rate estimator configuration - * @interval: sampling period - * @ewma_log: the log of measurement window weight - */ -struct gnet_estimator { - signed char interval; - unsigned char ewma_log; -}; - - -#endif /* __LINUX_GEN_STATS_H */ diff --git a/src/linux/include/uapi/linux/genetlink.h b/src/linux/include/uapi/linux/genetlink.h deleted file mode 100644 index 5512c90..0000000 --- a/src/linux/include/uapi/linux/genetlink.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef _UAPI__LINUX_GENERIC_NETLINK_H -#define _UAPI__LINUX_GENERIC_NETLINK_H - -#include -#include - -#define GENL_NAMSIZ 16 /* length of family name */ - -#define GENL_MIN_ID NLMSG_MIN_TYPE -#define GENL_MAX_ID 1023 - -struct genlmsghdr { - __u8 cmd; - __u8 version; - __u16 reserved; -}; - -#define GENL_HDRLEN NLMSG_ALIGN(sizeof(struct genlmsghdr)) - -#define GENL_ADMIN_PERM 0x01 -#define GENL_CMD_CAP_DO 0x02 -#define GENL_CMD_CAP_DUMP 0x04 -#define GENL_CMD_CAP_HASPOL 0x08 -#define GENL_UNS_ADMIN_PERM 0x10 - -/* - * List of reserved static generic netlink identifiers: - */ -#define GENL_ID_GENERATE 0 -#define GENL_ID_CTRL NLMSG_MIN_TYPE -#define GENL_ID_VFS_DQUOT (NLMSG_MIN_TYPE + 1) -#define GENL_ID_PMCRAID (NLMSG_MIN_TYPE + 2) - -/************************************************************************** - * Controller - **************************************************************************/ - -enum { - CTRL_CMD_UNSPEC, - CTRL_CMD_NEWFAMILY, - CTRL_CMD_DELFAMILY, - CTRL_CMD_GETFAMILY, - CTRL_CMD_NEWOPS, - CTRL_CMD_DELOPS, - CTRL_CMD_GETOPS, - CTRL_CMD_NEWMCAST_GRP, - CTRL_CMD_DELMCAST_GRP, - CTRL_CMD_GETMCAST_GRP, /* unused */ - __CTRL_CMD_MAX, -}; - -#define CTRL_CMD_MAX (__CTRL_CMD_MAX - 1) - -enum { - CTRL_ATTR_UNSPEC, - CTRL_ATTR_FAMILY_ID, - CTRL_ATTR_FAMILY_NAME, - CTRL_ATTR_VERSION, - CTRL_ATTR_HDRSIZE, - CTRL_ATTR_MAXATTR, - CTRL_ATTR_OPS, - CTRL_ATTR_MCAST_GROUPS, - __CTRL_ATTR_MAX, -}; - -#define CTRL_ATTR_MAX (__CTRL_ATTR_MAX - 1) - -enum { - CTRL_ATTR_OP_UNSPEC, - CTRL_ATTR_OP_ID, - CTRL_ATTR_OP_FLAGS, - __CTRL_ATTR_OP_MAX, -}; - -#define CTRL_ATTR_OP_MAX (__CTRL_ATTR_OP_MAX - 1) - -enum { - CTRL_ATTR_MCAST_GRP_UNSPEC, - CTRL_ATTR_MCAST_GRP_NAME, - CTRL_ATTR_MCAST_GRP_ID, - __CTRL_ATTR_MCAST_GRP_MAX, -}; - -#define CTRL_ATTR_MCAST_GRP_MAX (__CTRL_ATTR_MCAST_GRP_MAX - 1) - - -#endif /* _UAPI__LINUX_GENERIC_NETLINK_H */ diff --git a/src/linux/include/uapi/linux/hdlc/ioctl.h b/src/linux/include/uapi/linux/hdlc/ioctl.h deleted file mode 100644 index 04bc027..0000000 --- a/src/linux/include/uapi/linux/hdlc/ioctl.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef __HDLC_IOCTL_H__ -#define __HDLC_IOCTL_H__ - - -#define GENERIC_HDLC_VERSION 4 /* For synchronization with sethdlc utility */ - -#define CLOCK_DEFAULT 0 /* Default setting */ -#define CLOCK_EXT 1 /* External TX and RX clock - DTE */ -#define CLOCK_INT 2 /* Internal TX and RX clock - DCE */ -#define CLOCK_TXINT 3 /* Internal TX and external RX clock */ -#define CLOCK_TXFROMRX 4 /* TX clock derived from external RX clock */ - - -#define ENCODING_DEFAULT 0 /* Default setting */ -#define ENCODING_NRZ 1 -#define ENCODING_NRZI 2 -#define ENCODING_FM_MARK 3 -#define ENCODING_FM_SPACE 4 -#define ENCODING_MANCHESTER 5 - - -#define PARITY_DEFAULT 0 /* Default setting */ -#define PARITY_NONE 1 /* No parity */ -#define PARITY_CRC16_PR0 2 /* CRC16, initial value 0x0000 */ -#define PARITY_CRC16_PR1 3 /* CRC16, initial value 0xFFFF */ -#define PARITY_CRC16_PR0_CCITT 4 /* CRC16, initial 0x0000, ITU-T version */ -#define PARITY_CRC16_PR1_CCITT 5 /* CRC16, initial 0xFFFF, ITU-T version */ -#define PARITY_CRC32_PR0_CCITT 6 /* CRC32, initial value 0x00000000 */ -#define PARITY_CRC32_PR1_CCITT 7 /* CRC32, initial value 0xFFFFFFFF */ - -#define LMI_DEFAULT 0 /* Default setting */ -#define LMI_NONE 1 /* No LMI, all PVCs are static */ -#define LMI_ANSI 2 /* ANSI Annex D */ -#define LMI_CCITT 3 /* ITU-T Annex A */ -#define LMI_CISCO 4 /* The "original" LMI, aka Gang of Four */ - -#ifndef __ASSEMBLY__ - -typedef struct { - unsigned int clock_rate; /* bits per second */ - unsigned int clock_type; /* internal, external, TX-internal etc. */ - unsigned short loopback; -} sync_serial_settings; /* V.35, V.24, X.21 */ - -typedef struct { - unsigned int clock_rate; /* bits per second */ - unsigned int clock_type; /* internal, external, TX-internal etc. */ - unsigned short loopback; - unsigned int slot_map; -} te1_settings; /* T1, E1 */ - -typedef struct { - unsigned short encoding; - unsigned short parity; -} raw_hdlc_proto; - -typedef struct { - unsigned int t391; - unsigned int t392; - unsigned int n391; - unsigned int n392; - unsigned int n393; - unsigned short lmi; - unsigned short dce; /* 1 for DCE (network side) operation */ -} fr_proto; - -typedef struct { - unsigned int dlci; -} fr_proto_pvc; /* for creating/deleting FR PVCs */ - -typedef struct { - unsigned int dlci; - char master[IFNAMSIZ]; /* Name of master FRAD device */ -}fr_proto_pvc_info; /* for returning PVC information only */ - -typedef struct { - unsigned int interval; - unsigned int timeout; -} cisco_proto; - -/* PPP doesn't need any info now - supply length = 0 to ioctl */ - -#endif /* __ASSEMBLY__ */ -#endif /* __HDLC_IOCTL_H__ */ diff --git a/src/linux/include/uapi/linux/hdreg.h b/src/linux/include/uapi/linux/hdreg.h deleted file mode 100644 index 29ee287..0000000 --- a/src/linux/include/uapi/linux/hdreg.h +++ /dev/null @@ -1,658 +0,0 @@ -#ifndef _LINUX_HDREG_H -#define _LINUX_HDREG_H - -#include - -/* - * Command Header sizes for IOCTL commands - */ - -#define HDIO_DRIVE_CMD_HDR_SIZE (4 * sizeof(__u8)) -#define HDIO_DRIVE_HOB_HDR_SIZE (8 * sizeof(__u8)) -#define HDIO_DRIVE_TASK_HDR_SIZE (8 * sizeof(__u8)) - -#define IDE_DRIVE_TASK_NO_DATA 0 -#ifndef __KERNEL__ -#define IDE_DRIVE_TASK_INVALID -1 -#define IDE_DRIVE_TASK_SET_XFER 1 -#define IDE_DRIVE_TASK_IN 2 -#define IDE_DRIVE_TASK_OUT 3 -#endif -#define IDE_DRIVE_TASK_RAW_WRITE 4 - -/* - * Define standard taskfile in/out register - */ -#define IDE_TASKFILE_STD_IN_FLAGS 0xFE -#define IDE_HOB_STD_IN_FLAGS 0x3C -#ifndef __KERNEL__ -#define IDE_TASKFILE_STD_OUT_FLAGS 0xFE -#define IDE_HOB_STD_OUT_FLAGS 0x3C - -typedef unsigned char task_ioreg_t; -typedef unsigned long sata_ioreg_t; -#endif - -typedef union ide_reg_valid_s { - unsigned all : 16; - struct { - unsigned data : 1; - unsigned error_feature : 1; - unsigned sector : 1; - unsigned nsector : 1; - unsigned lcyl : 1; - unsigned hcyl : 1; - unsigned select : 1; - unsigned status_command : 1; - - unsigned data_hob : 1; - unsigned error_feature_hob : 1; - unsigned sector_hob : 1; - unsigned nsector_hob : 1; - unsigned lcyl_hob : 1; - unsigned hcyl_hob : 1; - unsigned select_hob : 1; - unsigned control_hob : 1; - } b; -} ide_reg_valid_t; - -typedef struct ide_task_request_s { - __u8 io_ports[8]; - __u8 hob_ports[8]; /* bytes 6 and 7 are unused */ - ide_reg_valid_t out_flags; - ide_reg_valid_t in_flags; - int data_phase; - int req_cmd; - unsigned long out_size; - unsigned long in_size; -} ide_task_request_t; - -typedef struct ide_ioctl_request_s { - ide_task_request_t *task_request; - unsigned char *out_buffer; - unsigned char *in_buffer; -} ide_ioctl_request_t; - -struct hd_drive_cmd_hdr { - __u8 command; - __u8 sector_number; - __u8 feature; - __u8 sector_count; -}; - -#ifndef __KERNEL__ -typedef struct hd_drive_task_hdr { - __u8 data; - __u8 feature; - __u8 sector_count; - __u8 sector_number; - __u8 low_cylinder; - __u8 high_cylinder; - __u8 device_head; - __u8 command; -} task_struct_t; - -typedef struct hd_drive_hob_hdr { - __u8 data; - __u8 feature; - __u8 sector_count; - __u8 sector_number; - __u8 low_cylinder; - __u8 high_cylinder; - __u8 device_head; - __u8 control; -} hob_struct_t; -#endif - -#define TASKFILE_NO_DATA 0x0000 - -#define TASKFILE_IN 0x0001 -#define TASKFILE_MULTI_IN 0x0002 - -#define TASKFILE_OUT 0x0004 -#define TASKFILE_MULTI_OUT 0x0008 -#define TASKFILE_IN_OUT 0x0010 - -#define TASKFILE_IN_DMA 0x0020 -#define TASKFILE_OUT_DMA 0x0040 -#define TASKFILE_IN_DMAQ 0x0080 -#define TASKFILE_OUT_DMAQ 0x0100 - -#ifndef __KERNEL__ -#define TASKFILE_P_IN 0x0200 -#define TASKFILE_P_OUT 0x0400 -#define TASKFILE_P_IN_DMA 0x0800 -#define TASKFILE_P_OUT_DMA 0x1000 -#define TASKFILE_P_IN_DMAQ 0x2000 -#define TASKFILE_P_OUT_DMAQ 0x4000 -#define TASKFILE_48 0x8000 -#define TASKFILE_INVALID 0x7fff -#endif - -#ifndef __KERNEL__ -/* ATA/ATAPI Commands pre T13 Spec */ -#define WIN_NOP 0x00 -/* - * 0x01->0x02 Reserved - */ -#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */ -/* - * 0x04->0x07 Reserved - */ -#define WIN_SRST 0x08 /* ATAPI soft reset command */ -#define WIN_DEVICE_RESET 0x08 -/* - * 0x09->0x0F Reserved - */ -#define WIN_RECAL 0x10 -#define WIN_RESTORE WIN_RECAL -/* - * 0x10->0x1F Reserved - */ -#define WIN_READ 0x20 /* 28-Bit */ -#define WIN_READ_ONCE 0x21 /* 28-Bit without retries */ -#define WIN_READ_LONG 0x22 /* 28-Bit */ -#define WIN_READ_LONG_ONCE 0x23 /* 28-Bit without retries */ -#define WIN_READ_EXT 0x24 /* 48-Bit */ -#define WIN_READDMA_EXT 0x25 /* 48-Bit */ -#define WIN_READDMA_QUEUED_EXT 0x26 /* 48-Bit */ -#define WIN_READ_NATIVE_MAX_EXT 0x27 /* 48-Bit */ -/* - * 0x28 - */ -#define WIN_MULTREAD_EXT 0x29 /* 48-Bit */ -/* - * 0x2A->0x2F Reserved - */ -#define WIN_WRITE 0x30 /* 28-Bit */ -#define WIN_WRITE_ONCE 0x31 /* 28-Bit without retries */ -#define WIN_WRITE_LONG 0x32 /* 28-Bit */ -#define WIN_WRITE_LONG_ONCE 0x33 /* 28-Bit without retries */ -#define WIN_WRITE_EXT 0x34 /* 48-Bit */ -#define WIN_WRITEDMA_EXT 0x35 /* 48-Bit */ -#define WIN_WRITEDMA_QUEUED_EXT 0x36 /* 48-Bit */ -#define WIN_SET_MAX_EXT 0x37 /* 48-Bit */ -#define CFA_WRITE_SECT_WO_ERASE 0x38 /* CFA Write Sectors without erase */ -#define WIN_MULTWRITE_EXT 0x39 /* 48-Bit */ -/* - * 0x3A->0x3B Reserved - */ -#define WIN_WRITE_VERIFY 0x3C /* 28-Bit */ -/* - * 0x3D->0x3F Reserved - */ -#define WIN_VERIFY 0x40 /* 28-Bit - Read Verify Sectors */ -#define WIN_VERIFY_ONCE 0x41 /* 28-Bit - without retries */ -#define WIN_VERIFY_EXT 0x42 /* 48-Bit */ -/* - * 0x43->0x4F Reserved - */ -#define WIN_FORMAT 0x50 -/* - * 0x51->0x5F Reserved - */ -#define WIN_INIT 0x60 -/* - * 0x61->0x5F Reserved - */ -#define WIN_SEEK 0x70 /* 0x70-0x7F Reserved */ - -#define CFA_TRANSLATE_SECTOR 0x87 /* CFA Translate Sector */ -#define WIN_DIAGNOSE 0x90 -#define WIN_SPECIFY 0x91 /* set drive geometry translation */ -#define WIN_DOWNLOAD_MICROCODE 0x92 -#define WIN_STANDBYNOW2 0x94 -#define WIN_STANDBY2 0x96 -#define WIN_SETIDLE2 0x97 -#define WIN_CHECKPOWERMODE2 0x98 -#define WIN_SLEEPNOW2 0x99 -/* - * 0x9A VENDOR - */ -#define WIN_PACKETCMD 0xA0 /* Send a packet command. */ -#define WIN_PIDENTIFY 0xA1 /* identify ATAPI device */ -#define WIN_QUEUED_SERVICE 0xA2 -#define WIN_SMART 0xB0 /* self-monitoring and reporting */ -#define CFA_ERASE_SECTORS 0xC0 -#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/ -#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */ -#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */ -#define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers */ -#define WIN_READDMA 0xC8 /* read sectors using DMA transfers */ -#define WIN_READDMA_ONCE 0xC9 /* 28-Bit - without retries */ -#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */ -#define WIN_WRITEDMA_ONCE 0xCB /* 28-Bit - without retries */ -#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */ -#define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */ -#define WIN_GETMEDIASTATUS 0xDA -#define WIN_ACKMEDIACHANGE 0xDB /* ATA-1, ATA-2 vendor */ -#define WIN_POSTBOOT 0xDC -#define WIN_PREBOOT 0xDD -#define WIN_DOORLOCK 0xDE /* lock door on removable drives */ -#define WIN_DOORUNLOCK 0xDF /* unlock door on removable drives */ -#define WIN_STANDBYNOW1 0xE0 -#define WIN_IDLEIMMEDIATE 0xE1 /* force drive to become "ready" */ -#define WIN_STANDBY 0xE2 /* Set device in Standby Mode */ -#define WIN_SETIDLE1 0xE3 -#define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */ -#define WIN_CHECKPOWERMODE1 0xE5 -#define WIN_SLEEPNOW1 0xE6 -#define WIN_FLUSH_CACHE 0xE7 -#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */ -#define WIN_WRITE_SAME 0xE9 /* read ata-2 to use */ - /* SET_FEATURES 0x22 or 0xDD */ -#define WIN_FLUSH_CACHE_EXT 0xEA /* 48-Bit */ -#define WIN_IDENTIFY 0xEC /* ask drive to identify itself */ -#define WIN_MEDIAEJECT 0xED -#define WIN_IDENTIFY_DMA 0xEE /* same as WIN_IDENTIFY, but DMA */ -#define WIN_SETFEATURES 0xEF /* set special drive features */ -#define EXABYTE_ENABLE_NEST 0xF0 -#define WIN_SECURITY_SET_PASS 0xF1 -#define WIN_SECURITY_UNLOCK 0xF2 -#define WIN_SECURITY_ERASE_PREPARE 0xF3 -#define WIN_SECURITY_ERASE_UNIT 0xF4 -#define WIN_SECURITY_FREEZE_LOCK 0xF5 -#define WIN_SECURITY_DISABLE 0xF6 -#define WIN_READ_NATIVE_MAX 0xF8 /* return the native maximum address */ -#define WIN_SET_MAX 0xF9 -#define DISABLE_SEAGATE 0xFB - -/* WIN_SMART sub-commands */ - -#define SMART_READ_VALUES 0xD0 -#define SMART_READ_THRESHOLDS 0xD1 -#define SMART_AUTOSAVE 0xD2 -#define SMART_SAVE 0xD3 -#define SMART_IMMEDIATE_OFFLINE 0xD4 -#define SMART_READ_LOG_SECTOR 0xD5 -#define SMART_WRITE_LOG_SECTOR 0xD6 -#define SMART_WRITE_THRESHOLDS 0xD7 -#define SMART_ENABLE 0xD8 -#define SMART_DISABLE 0xD9 -#define SMART_STATUS 0xDA -#define SMART_AUTO_OFFLINE 0xDB - -/* Password used in TF4 & TF5 executing SMART commands */ - -#define SMART_LCYL_PASS 0x4F -#define SMART_HCYL_PASS 0xC2 - -/* WIN_SETFEATURES sub-commands */ -#define SETFEATURES_EN_8BIT 0x01 /* Enable 8-Bit Transfers */ -#define SETFEATURES_EN_WCACHE 0x02 /* Enable write cache */ -#define SETFEATURES_DIS_DEFECT 0x04 /* Disable Defect Management */ -#define SETFEATURES_EN_APM 0x05 /* Enable advanced power management */ -#define SETFEATURES_EN_SAME_R 0x22 /* for a region ATA-1 */ -#define SETFEATURES_DIS_MSN 0x31 /* Disable Media Status Notification */ -#define SETFEATURES_DIS_RETRY 0x33 /* Disable Retry */ -#define SETFEATURES_EN_AAM 0x42 /* Enable Automatic Acoustic Management */ -#define SETFEATURES_RW_LONG 0x44 /* Set Length of VS bytes */ -#define SETFEATURES_SET_CACHE 0x54 /* Set Cache segments to SC Reg. Val */ -#define SETFEATURES_DIS_RLA 0x55 /* Disable read look-ahead feature */ -#define SETFEATURES_EN_RI 0x5D /* Enable release interrupt */ -#define SETFEATURES_EN_SI 0x5E /* Enable SERVICE interrupt */ -#define SETFEATURES_DIS_RPOD 0x66 /* Disable reverting to power on defaults */ -#define SETFEATURES_DIS_ECC 0x77 /* Disable ECC byte count */ -#define SETFEATURES_DIS_8BIT 0x81 /* Disable 8-Bit Transfers */ -#define SETFEATURES_DIS_WCACHE 0x82 /* Disable write cache */ -#define SETFEATURES_EN_DEFECT 0x84 /* Enable Defect Management */ -#define SETFEATURES_DIS_APM 0x85 /* Disable advanced power management */ -#define SETFEATURES_EN_ECC 0x88 /* Enable ECC byte count */ -#define SETFEATURES_EN_MSN 0x95 /* Enable Media Status Notification */ -#define SETFEATURES_EN_RETRY 0x99 /* Enable Retry */ -#define SETFEATURES_EN_RLA 0xAA /* Enable read look-ahead feature */ -#define SETFEATURES_PREFETCH 0xAB /* Sets drive prefetch value */ -#define SETFEATURES_EN_REST 0xAC /* ATA-1 */ -#define SETFEATURES_4B_RW_LONG 0xBB /* Set Length of 4 bytes */ -#define SETFEATURES_DIS_AAM 0xC2 /* Disable Automatic Acoustic Management */ -#define SETFEATURES_EN_RPOD 0xCC /* Enable reverting to power on defaults */ -#define SETFEATURES_DIS_RI 0xDD /* Disable release interrupt ATAPI */ -#define SETFEATURES_EN_SAME_M 0xDD /* for a entire device ATA-1 */ -#define SETFEATURES_DIS_SI 0xDE /* Disable SERVICE interrupt ATAPI */ - -/* WIN_SECURITY sub-commands */ - -#define SECURITY_SET_PASSWORD 0xBA -#define SECURITY_UNLOCK 0xBB -#define SECURITY_ERASE_PREPARE 0xBC -#define SECURITY_ERASE_UNIT 0xBD -#define SECURITY_FREEZE_LOCK 0xBE -#define SECURITY_DISABLE_PASSWORD 0xBF -#endif /* __KERNEL__ */ - -struct hd_geometry { - unsigned char heads; - unsigned char sectors; - unsigned short cylinders; - unsigned long start; -}; - -/* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x030n/0x031n */ -#define HDIO_GETGEO 0x0301 /* get device geometry */ -#define HDIO_GET_UNMASKINTR 0x0302 /* get current unmask setting */ -#define HDIO_GET_MULTCOUNT 0x0304 /* get current IDE blockmode setting */ -#define HDIO_GET_QDMA 0x0305 /* get use-qdma flag */ - -#define HDIO_SET_XFER 0x0306 /* set transfer rate via proc */ - -#define HDIO_OBSOLETE_IDENTITY 0x0307 /* OBSOLETE, DO NOT USE: returns 142 bytes */ -#define HDIO_GET_KEEPSETTINGS 0x0308 /* get keep-settings-on-reset flag */ -#define HDIO_GET_32BIT 0x0309 /* get current io_32bit setting */ -#define HDIO_GET_NOWERR 0x030a /* get ignore-write-error flag */ -#define HDIO_GET_DMA 0x030b /* get use-dma flag */ -#define HDIO_GET_NICE 0x030c /* get nice flags */ -#define HDIO_GET_IDENTITY 0x030d /* get IDE identification info */ -#define HDIO_GET_WCACHE 0x030e /* get write cache mode on|off */ -#define HDIO_GET_ACOUSTIC 0x030f /* get acoustic value */ -#define HDIO_GET_ADDRESS 0x0310 /* */ - -#define HDIO_GET_BUSSTATE 0x031a /* get the bus state of the hwif */ -#define HDIO_TRISTATE_HWIF 0x031b /* execute a channel tristate */ -#define HDIO_DRIVE_RESET 0x031c /* execute a device reset */ -#define HDIO_DRIVE_TASKFILE 0x031d /* execute raw taskfile */ -#define HDIO_DRIVE_TASK 0x031e /* execute task and special drive command */ -#define HDIO_DRIVE_CMD 0x031f /* execute a special drive command */ -#define HDIO_DRIVE_CMD_AEB HDIO_DRIVE_TASK - -/* hd/ide ctl's that pass (arg) non-ptr values are numbered 0x032n/0x033n */ -#define HDIO_SET_MULTCOUNT 0x0321 /* change IDE blockmode */ -#define HDIO_SET_UNMASKINTR 0x0322 /* permit other irqs during I/O */ -#define HDIO_SET_KEEPSETTINGS 0x0323 /* keep ioctl settings on reset */ -#define HDIO_SET_32BIT 0x0324 /* change io_32bit flags */ -#define HDIO_SET_NOWERR 0x0325 /* change ignore-write-error flag */ -#define HDIO_SET_DMA 0x0326 /* change use-dma flag */ -#define HDIO_SET_PIO_MODE 0x0327 /* reconfig interface to new speed */ -#ifndef __KERNEL__ -#define HDIO_SCAN_HWIF 0x0328 /* register and (re)scan interface */ -#define HDIO_UNREGISTER_HWIF 0x032a /* unregister interface */ -#endif -#define HDIO_SET_NICE 0x0329 /* set nice flags */ -#define HDIO_SET_WCACHE 0x032b /* change write cache enable-disable */ -#define HDIO_SET_ACOUSTIC 0x032c /* change acoustic behavior */ -#define HDIO_SET_BUSSTATE 0x032d /* set the bus state of the hwif */ -#define HDIO_SET_QDMA 0x032e /* change use-qdma flag */ -#define HDIO_SET_ADDRESS 0x032f /* change lba addressing modes */ - -/* bus states */ -enum { - BUSSTATE_OFF = 0, - BUSSTATE_ON, - BUSSTATE_TRISTATE -}; - -/* hd/ide ctl's that pass (arg) ptrs to user space are numbered 0x033n/0x033n */ -/* 0x330 is reserved - used to be HDIO_GETGEO_BIG */ -/* 0x331 is reserved - used to be HDIO_GETGEO_BIG_RAW */ -/* 0x338 is reserved - used to be HDIO_SET_IDE_SCSI */ -/* 0x339 is reserved - used to be HDIO_SET_SCSI_IDE */ - -#define __NEW_HD_DRIVE_ID - -#ifndef __KERNEL__ -/* - * Structure returned by HDIO_GET_IDENTITY, as per ANSI NCITS ATA6 rev.1b spec. - * - * If you change something here, please remember to update fix_driveid() in - * ide/probe.c. - */ -struct hd_driveid { - unsigned short config; /* lots of obsolete bit flags */ - unsigned short cyls; /* Obsolete, "physical" cyls */ - unsigned short reserved2; /* reserved (word 2) */ - unsigned short heads; /* Obsolete, "physical" heads */ - unsigned short track_bytes; /* unformatted bytes per track */ - unsigned short sector_bytes; /* unformatted bytes per sector */ - unsigned short sectors; /* Obsolete, "physical" sectors per track */ - unsigned short vendor0; /* vendor unique */ - unsigned short vendor1; /* vendor unique */ - unsigned short vendor2; /* Retired vendor unique */ - unsigned char serial_no[20]; /* 0 = not_specified */ - unsigned short buf_type; /* Retired */ - unsigned short buf_size; /* Retired, 512 byte increments - * 0 = not_specified - */ - unsigned short ecc_bytes; /* for r/w long cmds; 0 = not_specified */ - unsigned char fw_rev[8]; /* 0 = not_specified */ - unsigned char model[40]; /* 0 = not_specified */ - unsigned char max_multsect; /* 0=not_implemented */ - unsigned char vendor3; /* vendor unique */ - unsigned short dword_io; /* 0=not_implemented; 1=implemented */ - unsigned char vendor4; /* vendor unique */ - unsigned char capability; /* (upper byte of word 49) - * 3: IORDYsup - * 2: IORDYsw - * 1: LBA - * 0: DMA - */ - unsigned short reserved50; /* reserved (word 50) */ - unsigned char vendor5; /* Obsolete, vendor unique */ - unsigned char tPIO; /* Obsolete, 0=slow, 1=medium, 2=fast */ - unsigned char vendor6; /* Obsolete, vendor unique */ - unsigned char tDMA; /* Obsolete, 0=slow, 1=medium, 2=fast */ - unsigned short field_valid; /* (word 53) - * 2: ultra_ok word 88 - * 1: eide_ok words 64-70 - * 0: cur_ok words 54-58 - */ - unsigned short cur_cyls; /* Obsolete, logical cylinders */ - unsigned short cur_heads; /* Obsolete, l heads */ - unsigned short cur_sectors; /* Obsolete, l sectors per track */ - unsigned short cur_capacity0; /* Obsolete, l total sectors on drive */ - unsigned short cur_capacity1; /* Obsolete, (2 words, misaligned int) */ - unsigned char multsect; /* current multiple sector count */ - unsigned char multsect_valid; /* when (bit0==1) multsect is ok */ - unsigned int lba_capacity; /* Obsolete, total number of sectors */ - unsigned short dma_1word; /* Obsolete, single-word dma info */ - unsigned short dma_mword; /* multiple-word dma info */ - unsigned short eide_pio_modes; /* bits 0:mode3 1:mode4 */ - unsigned short eide_dma_min; /* min mword dma cycle time (ns) */ - unsigned short eide_dma_time; /* recommended mword dma cycle time (ns) */ - unsigned short eide_pio; /* min cycle time (ns), no IORDY */ - unsigned short eide_pio_iordy; /* min cycle time (ns), with IORDY */ - unsigned short words69_70[2]; /* reserved words 69-70 - * future command overlap and queuing - */ - unsigned short words71_74[4]; /* reserved words 71-74 - * for IDENTIFY PACKET DEVICE command - */ - unsigned short queue_depth; /* (word 75) - * 15:5 reserved - * 4:0 Maximum queue depth -1 - */ - unsigned short words76_79[4]; /* reserved words 76-79 */ - unsigned short major_rev_num; /* (word 80) */ - unsigned short minor_rev_num; /* (word 81) */ - unsigned short command_set_1; /* (word 82) supported - * 15: Obsolete - * 14: NOP command - * 13: READ_BUFFER - * 12: WRITE_BUFFER - * 11: Obsolete - * 10: Host Protected Area - * 9: DEVICE Reset - * 8: SERVICE Interrupt - * 7: Release Interrupt - * 6: look-ahead - * 5: write cache - * 4: PACKET Command - * 3: Power Management Feature Set - * 2: Removable Feature Set - * 1: Security Feature Set - * 0: SMART Feature Set - */ - unsigned short command_set_2; /* (word 83) - * 15: Shall be ZERO - * 14: Shall be ONE - * 13: FLUSH CACHE EXT - * 12: FLUSH CACHE - * 11: Device Configuration Overlay - * 10: 48-bit Address Feature Set - * 9: Automatic Acoustic Management - * 8: SET MAX security - * 7: reserved 1407DT PARTIES - * 6: SetF sub-command Power-Up - * 5: Power-Up in Standby Feature Set - * 4: Removable Media Notification - * 3: APM Feature Set - * 2: CFA Feature Set - * 1: READ/WRITE DMA QUEUED - * 0: Download MicroCode - */ - unsigned short cfsse; /* (word 84) - * cmd set-feature supported extensions - * 15: Shall be ZERO - * 14: Shall be ONE - * 13:6 reserved - * 5: General Purpose Logging - * 4: Streaming Feature Set - * 3: Media Card Pass Through - * 2: Media Serial Number Valid - * 1: SMART selt-test supported - * 0: SMART error logging - */ - unsigned short cfs_enable_1; /* (word 85) - * command set-feature enabled - * 15: Obsolete - * 14: NOP command - * 13: READ_BUFFER - * 12: WRITE_BUFFER - * 11: Obsolete - * 10: Host Protected Area - * 9: DEVICE Reset - * 8: SERVICE Interrupt - * 7: Release Interrupt - * 6: look-ahead - * 5: write cache - * 4: PACKET Command - * 3: Power Management Feature Set - * 2: Removable Feature Set - * 1: Security Feature Set - * 0: SMART Feature Set - */ - unsigned short cfs_enable_2; /* (word 86) - * command set-feature enabled - * 15: Shall be ZERO - * 14: Shall be ONE - * 13: FLUSH CACHE EXT - * 12: FLUSH CACHE - * 11: Device Configuration Overlay - * 10: 48-bit Address Feature Set - * 9: Automatic Acoustic Management - * 8: SET MAX security - * 7: reserved 1407DT PARTIES - * 6: SetF sub-command Power-Up - * 5: Power-Up in Standby Feature Set - * 4: Removable Media Notification - * 3: APM Feature Set - * 2: CFA Feature Set - * 1: READ/WRITE DMA QUEUED - * 0: Download MicroCode - */ - unsigned short csf_default; /* (word 87) - * command set-feature default - * 15: Shall be ZERO - * 14: Shall be ONE - * 13:6 reserved - * 5: General Purpose Logging enabled - * 4: Valid CONFIGURE STREAM executed - * 3: Media Card Pass Through enabled - * 2: Media Serial Number Valid - * 1: SMART selt-test supported - * 0: SMART error logging - */ - unsigned short dma_ultra; /* (word 88) */ - unsigned short trseuc; /* time required for security erase */ - unsigned short trsEuc; /* time required for enhanced erase */ - unsigned short CurAPMvalues; /* current APM values */ - unsigned short mprc; /* master password revision code */ - unsigned short hw_config; /* hardware config (word 93) - * 15: Shall be ZERO - * 14: Shall be ONE - * 13: - * 12: - * 11: - * 10: - * 9: - * 8: - * 7: - * 6: - * 5: - * 4: - * 3: - * 2: - * 1: - * 0: Shall be ONE - */ - unsigned short acoustic; /* (word 94) - * 15:8 Vendor's recommended value - * 7:0 current value - */ - unsigned short msrqs; /* min stream request size */ - unsigned short sxfert; /* stream transfer time */ - unsigned short sal; /* stream access latency */ - unsigned int spg; /* stream performance granularity */ - unsigned long long lba_capacity_2;/* 48-bit total number of sectors */ - unsigned short words104_125[22];/* reserved words 104-125 */ - unsigned short last_lun; /* (word 126) */ - unsigned short word127; /* (word 127) Feature Set - * Removable Media Notification - * 15:2 reserved - * 1:0 00 = not supported - * 01 = supported - * 10 = reserved - * 11 = reserved - */ - unsigned short dlf; /* (word 128) - * device lock function - * 15:9 reserved - * 8 security level 1:max 0:high - * 7:6 reserved - * 5 enhanced erase - * 4 expire - * 3 frozen - * 2 locked - * 1 en/disabled - * 0 capability - */ - unsigned short csfo; /* (word 129) - * current set features options - * 15:4 reserved - * 3: auto reassign - * 2: reverting - * 1: read-look-ahead - * 0: write cache - */ - unsigned short words130_155[26];/* reserved vendor words 130-155 */ - unsigned short word156; /* reserved vendor word 156 */ - unsigned short words157_159[3];/* reserved vendor words 157-159 */ - unsigned short cfa_power; /* (word 160) CFA Power Mode - * 15 word 160 supported - * 14 reserved - * 13 - * 12 - * 11:0 - */ - unsigned short words161_175[15];/* Reserved for CFA */ - unsigned short words176_205[30];/* Current Media Serial Number */ - unsigned short words206_254[49];/* reserved words 206-254 */ - unsigned short integrity_word; /* (word 255) - * 15:8 Checksum - * 7:0 Signature - */ -}; -#endif /* __KERNEL__ */ - -/* - * IDE "nice" flags. These are used on a per drive basis to determine - * when to be nice and give more bandwidth to the other devices which - * share the same IDE bus. - */ -#define IDE_NICE_DSC_OVERLAP (0) /* per the DSC overlap protocol */ -#define IDE_NICE_ATAPI_OVERLAP (1) /* not supported yet */ -#define IDE_NICE_1 (3) /* when probably won't affect us much */ -#ifndef __KERNEL__ -#define IDE_NICE_0 (2) /* when sure that it won't affect us */ -#define IDE_NICE_2 (4) /* when we know it's on our expense */ -#endif - -#endif /* _LINUX_HDREG_H */ diff --git a/src/linux/include/uapi/linux/hid.h b/src/linux/include/uapi/linux/hid.h deleted file mode 100644 index b60f484..0000000 --- a/src/linux/include/uapi/linux/hid.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 1999 Andreas Gal - * Copyright (c) 2000-2001 Vojtech Pavlik - * Copyright (c) 2006-2007 Jiri Kosina - */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic - */ -#ifndef _UAPI__HID_H -#define _UAPI__HID_H - - - -/* - * USB HID (Human Interface Device) interface class code - */ - -#define USB_INTERFACE_CLASS_HID 3 - -/* - * USB HID interface subclass and protocol codes - */ - -#define USB_INTERFACE_SUBCLASS_BOOT 1 -#define USB_INTERFACE_PROTOCOL_KEYBOARD 1 -#define USB_INTERFACE_PROTOCOL_MOUSE 2 - -/* - * HID class requests - */ - -#define HID_REQ_GET_REPORT 0x01 -#define HID_REQ_GET_IDLE 0x02 -#define HID_REQ_GET_PROTOCOL 0x03 -#define HID_REQ_SET_REPORT 0x09 -#define HID_REQ_SET_IDLE 0x0A -#define HID_REQ_SET_PROTOCOL 0x0B - -/* - * HID class descriptor types - */ - -#define HID_DT_HID (USB_TYPE_CLASS | 0x01) -#define HID_DT_REPORT (USB_TYPE_CLASS | 0x02) -#define HID_DT_PHYSICAL (USB_TYPE_CLASS | 0x03) - -#define HID_MAX_DESCRIPTOR_SIZE 4096 - - -#endif /* _UAPI__HID_H */ diff --git a/src/linux/include/uapi/linux/hiddev.h b/src/linux/include/uapi/linux/hiddev.h deleted file mode 100644 index 7df7884..0000000 --- a/src/linux/include/uapi/linux/hiddev.h +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (c) 1999-2000 Vojtech Pavlik - * - * Sponsored by SuSE - */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic - */ -#ifndef _UAPI_HIDDEV_H -#define _UAPI_HIDDEV_H - - - -#include - -/* - * The event structure itself - */ - -struct hiddev_event { - unsigned hid; - signed int value; -}; - -struct hiddev_devinfo { - __u32 bustype; - __u32 busnum; - __u32 devnum; - __u32 ifnum; - __s16 vendor; - __s16 product; - __s16 version; - __u32 num_applications; -}; - -struct hiddev_collection_info { - __u32 index; - __u32 type; - __u32 usage; - __u32 level; -}; - -#define HID_STRING_SIZE 256 -struct hiddev_string_descriptor { - __s32 index; - char value[HID_STRING_SIZE]; -}; - -struct hiddev_report_info { - __u32 report_type; - __u32 report_id; - __u32 num_fields; -}; - -/* To do a GUSAGE/SUSAGE, fill in at least usage_code, report_type and - * report_id. Set report_id to REPORT_ID_UNKNOWN if the rest of the fields - * are unknown. Otherwise use a usage_ref struct filled in from a previous - * successful GUSAGE call to save time. To actually send a value to the - * device, perform a SUSAGE first, followed by a SREPORT. An INITREPORT or a - * GREPORT isn't necessary for a GUSAGE to return valid data. - */ -#define HID_REPORT_ID_UNKNOWN 0xffffffff -#define HID_REPORT_ID_FIRST 0x00000100 -#define HID_REPORT_ID_NEXT 0x00000200 -#define HID_REPORT_ID_MASK 0x000000ff -#define HID_REPORT_ID_MAX 0x000000ff - -#define HID_REPORT_TYPE_INPUT 1 -#define HID_REPORT_TYPE_OUTPUT 2 -#define HID_REPORT_TYPE_FEATURE 3 -#define HID_REPORT_TYPE_MIN 1 -#define HID_REPORT_TYPE_MAX 3 - -struct hiddev_field_info { - __u32 report_type; - __u32 report_id; - __u32 field_index; - __u32 maxusage; - __u32 flags; - __u32 physical; /* physical usage for this field */ - __u32 logical; /* logical usage for this field */ - __u32 application; /* application usage for this field */ - __s32 logical_minimum; - __s32 logical_maximum; - __s32 physical_minimum; - __s32 physical_maximum; - __u32 unit_exponent; - __u32 unit; -}; - -/* Fill in report_type, report_id and field_index to get the information on a - * field. - */ -#define HID_FIELD_CONSTANT 0x001 -#define HID_FIELD_VARIABLE 0x002 -#define HID_FIELD_RELATIVE 0x004 -#define HID_FIELD_WRAP 0x008 -#define HID_FIELD_NONLINEAR 0x010 -#define HID_FIELD_NO_PREFERRED 0x020 -#define HID_FIELD_NULL_STATE 0x040 -#define HID_FIELD_VOLATILE 0x080 -#define HID_FIELD_BUFFERED_BYTE 0x100 - -struct hiddev_usage_ref { - __u32 report_type; - __u32 report_id; - __u32 field_index; - __u32 usage_index; - __u32 usage_code; - __s32 value; -}; - -/* hiddev_usage_ref_multi is used for sending multiple bytes to a control. - * It really manifests itself as setting the value of consecutive usages */ -#define HID_MAX_MULTI_USAGES 1024 -struct hiddev_usage_ref_multi { - struct hiddev_usage_ref uref; - __u32 num_values; - __s32 values[HID_MAX_MULTI_USAGES]; -}; - -/* FIELD_INDEX_NONE is returned in read() data from the kernel when flags - * is set to (HIDDEV_FLAG_UREF | HIDDEV_FLAG_REPORT) and a new report has - * been sent by the device - */ -#define HID_FIELD_INDEX_NONE 0xffffffff - -/* - * Protocol version. - */ - -#define HID_VERSION 0x010004 - -/* - * IOCTLs (0x00 - 0x7f) - */ - -#define HIDIOCGVERSION _IOR('H', 0x01, int) -#define HIDIOCAPPLICATION _IO('H', 0x02) -#define HIDIOCGDEVINFO _IOR('H', 0x03, struct hiddev_devinfo) -#define HIDIOCGSTRING _IOR('H', 0x04, struct hiddev_string_descriptor) -#define HIDIOCINITREPORT _IO('H', 0x05) -#define HIDIOCGNAME(len) _IOC(_IOC_READ, 'H', 0x06, len) -#define HIDIOCGREPORT _IOW('H', 0x07, struct hiddev_report_info) -#define HIDIOCSREPORT _IOW('H', 0x08, struct hiddev_report_info) -#define HIDIOCGREPORTINFO _IOWR('H', 0x09, struct hiddev_report_info) -#define HIDIOCGFIELDINFO _IOWR('H', 0x0A, struct hiddev_field_info) -#define HIDIOCGUSAGE _IOWR('H', 0x0B, struct hiddev_usage_ref) -#define HIDIOCSUSAGE _IOW('H', 0x0C, struct hiddev_usage_ref) -#define HIDIOCGUCODE _IOWR('H', 0x0D, struct hiddev_usage_ref) -#define HIDIOCGFLAG _IOR('H', 0x0E, int) -#define HIDIOCSFLAG _IOW('H', 0x0F, int) -#define HIDIOCGCOLLECTIONINDEX _IOW('H', 0x10, struct hiddev_usage_ref) -#define HIDIOCGCOLLECTIONINFO _IOWR('H', 0x11, struct hiddev_collection_info) -#define HIDIOCGPHYS(len) _IOC(_IOC_READ, 'H', 0x12, len) - -/* For writing/reading to multiple/consecutive usages */ -#define HIDIOCGUSAGES _IOWR('H', 0x13, struct hiddev_usage_ref_multi) -#define HIDIOCSUSAGES _IOW('H', 0x14, struct hiddev_usage_ref_multi) - -/* - * Flags to be used in HIDIOCSFLAG - */ -#define HIDDEV_FLAG_UREF 0x1 -#define HIDDEV_FLAG_REPORT 0x2 -#define HIDDEV_FLAGS 0x3 - -/* To traverse the input report descriptor info for a HID device, perform the - * following: - * - * rinfo.report_type = HID_REPORT_TYPE_INPUT; - * rinfo.report_id = HID_REPORT_ID_FIRST; - * ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo); - * - * while (ret >= 0) { - * for (i = 0; i < rinfo.num_fields; i++) { - * finfo.report_type = rinfo.report_type; - * finfo.report_id = rinfo.report_id; - * finfo.field_index = i; - * ioctl(fd, HIDIOCGFIELDINFO, &finfo); - * for (j = 0; j < finfo.maxusage; j++) { - * uref.report_type = rinfo.report_type; - * uref.report_id = rinfo.report_id; - * uref.field_index = i; - * uref.usage_index = j; - * ioctl(fd, HIDIOCGUCODE, &uref); - * ioctl(fd, HIDIOCGUSAGE, &uref); - * } - * } - * rinfo.report_id |= HID_REPORT_ID_NEXT; - * ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo); - * } - */ - - -#endif /* _UAPI_HIDDEV_H */ diff --git a/src/linux/include/uapi/linux/hidraw.h b/src/linux/include/uapi/linux/hidraw.h deleted file mode 100644 index f5b7329..0000000 --- a/src/linux/include/uapi/linux/hidraw.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2007 Jiri Kosina - */ -/* - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef _UAPI_HIDRAW_H -#define _UAPI_HIDRAW_H - - - -#include -#include - -struct hidraw_report_descriptor { - __u32 size; - __u8 value[HID_MAX_DESCRIPTOR_SIZE]; -}; - -struct hidraw_devinfo { - __u32 bustype; - __s16 vendor; - __s16 product; -}; - -/* ioctl interface */ -#define HIDIOCGRDESCSIZE _IOR('H', 0x01, int) -#define HIDIOCGRDESC _IOR('H', 0x02, struct hidraw_report_descriptor) -#define HIDIOCGRAWINFO _IOR('H', 0x03, struct hidraw_devinfo) -#define HIDIOCGRAWNAME(len) _IOC(_IOC_READ, 'H', 0x04, len) -#define HIDIOCGRAWPHYS(len) _IOC(_IOC_READ, 'H', 0x05, len) -/* The first byte of SFEATURE and GFEATURE is the report number */ -#define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len) -#define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len) - -#define HIDRAW_FIRST_MINOR 0 -#define HIDRAW_MAX_DEVICES 64 -/* number of reports to buffer */ -#define HIDRAW_BUFFER_SIZE 64 - - -/* kernel-only API declarations */ - -#endif /* _UAPI_HIDRAW_H */ diff --git a/src/linux/include/uapi/linux/hw_breakpoint.h b/src/linux/include/uapi/linux/hw_breakpoint.h deleted file mode 100644 index b04000a..0000000 --- a/src/linux/include/uapi/linux/hw_breakpoint.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _UAPI_LINUX_HW_BREAKPOINT_H -#define _UAPI_LINUX_HW_BREAKPOINT_H - -enum { - HW_BREAKPOINT_LEN_1 = 1, - HW_BREAKPOINT_LEN_2 = 2, - HW_BREAKPOINT_LEN_4 = 4, - HW_BREAKPOINT_LEN_8 = 8, -}; - -enum { - HW_BREAKPOINT_EMPTY = 0, - HW_BREAKPOINT_R = 1, - HW_BREAKPOINT_W = 2, - HW_BREAKPOINT_RW = HW_BREAKPOINT_R | HW_BREAKPOINT_W, - HW_BREAKPOINT_X = 4, - HW_BREAKPOINT_INVALID = HW_BREAKPOINT_RW | HW_BREAKPOINT_X, -}; - -enum bp_type_idx { - TYPE_INST = 0, -#ifdef CONFIG_HAVE_MIXED_BREAKPOINTS_REGS - TYPE_DATA = 0, -#else - TYPE_DATA = 1, -#endif - TYPE_MAX -}; - -#endif /* _UAPI_LINUX_HW_BREAKPOINT_H */ diff --git a/src/linux/include/uapi/linux/icmp.h b/src/linux/include/uapi/linux/icmp.h deleted file mode 100644 index fddd9d7..0000000 --- a/src/linux/include/uapi/linux/icmp.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the ICMP protocol. - * - * Version: @(#)icmp.h 1.0.3 04/28/93 - * - * Author: Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _UAPI_LINUX_ICMP_H -#define _UAPI_LINUX_ICMP_H - -#include - -#define ICMP_ECHOREPLY 0 /* Echo Reply */ -#define ICMP_DEST_UNREACH 3 /* Destination Unreachable */ -#define ICMP_SOURCE_QUENCH 4 /* Source Quench */ -#define ICMP_REDIRECT 5 /* Redirect (change route) */ -#define ICMP_ECHO 8 /* Echo Request */ -#define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */ -#define ICMP_PARAMETERPROB 12 /* Parameter Problem */ -#define ICMP_TIMESTAMP 13 /* Timestamp Request */ -#define ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */ -#define ICMP_INFO_REQUEST 15 /* Information Request */ -#define ICMP_INFO_REPLY 16 /* Information Reply */ -#define ICMP_ADDRESS 17 /* Address Mask Request */ -#define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */ -#define NR_ICMP_TYPES 18 - - -/* Codes for UNREACH. */ -#define ICMP_NET_UNREACH 0 /* Network Unreachable */ -#define ICMP_HOST_UNREACH 1 /* Host Unreachable */ -#define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */ -#define ICMP_PORT_UNREACH 3 /* Port Unreachable */ -#define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */ -#define ICMP_SR_FAILED 5 /* Source Route failed */ -#define ICMP_NET_UNKNOWN 6 -#define ICMP_HOST_UNKNOWN 7 -#define ICMP_HOST_ISOLATED 8 -#define ICMP_NET_ANO 9 -#define ICMP_HOST_ANO 10 -#define ICMP_NET_UNR_TOS 11 -#define ICMP_HOST_UNR_TOS 12 -#define ICMP_PKT_FILTERED 13 /* Packet filtered */ -#define ICMP_PREC_VIOLATION 14 /* Precedence violation */ -#define ICMP_PREC_CUTOFF 15 /* Precedence cut off */ -#define NR_ICMP_UNREACH 15 /* instead of hardcoding immediate value */ - -/* Codes for REDIRECT. */ -#define ICMP_REDIR_NET 0 /* Redirect Net */ -#define ICMP_REDIR_HOST 1 /* Redirect Host */ -#define ICMP_REDIR_NETTOS 2 /* Redirect Net for TOS */ -#define ICMP_REDIR_HOSTTOS 3 /* Redirect Host for TOS */ - -/* Codes for TIME_EXCEEDED. */ -#define ICMP_EXC_TTL 0 /* TTL count exceeded */ -#define ICMP_EXC_FRAGTIME 1 /* Fragment Reass time exceeded */ - - -struct icmphdr { - __u8 type; - __u8 code; - __sum16 checksum; - union { - struct { - __be16 id; - __be16 sequence; - } echo; - __be32 gateway; - struct { - __be16 __unused; - __be16 mtu; - } frag; - __u8 reserved[4]; - } un; -}; - - -/* - * constants for (set|get)sockopt - */ - -#define ICMP_FILTER 1 - -struct icmp_filter { - __u32 data; -}; - - -#endif /* _UAPI_LINUX_ICMP_H */ diff --git a/src/linux/include/uapi/linux/icmpv6.h b/src/linux/include/uapi/linux/icmpv6.h deleted file mode 100644 index 590beda..0000000 --- a/src/linux/include/uapi/linux/icmpv6.h +++ /dev/null @@ -1,166 +0,0 @@ -#ifndef _UAPI_LINUX_ICMPV6_H -#define _UAPI_LINUX_ICMPV6_H - -#include -#include - -struct icmp6hdr { - - __u8 icmp6_type; - __u8 icmp6_code; - __sum16 icmp6_cksum; - - - union { - __be32 un_data32[1]; - __be16 un_data16[2]; - __u8 un_data8[4]; - - struct icmpv6_echo { - __be16 identifier; - __be16 sequence; - } u_echo; - - struct icmpv6_nd_advt { -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u32 reserved:5, - override:1, - solicited:1, - router:1, - reserved2:24; -#elif defined(__BIG_ENDIAN_BITFIELD) - __u32 router:1, - solicited:1, - override:1, - reserved:29; -#else -#error "Please fix " -#endif - } u_nd_advt; - - struct icmpv6_nd_ra { - __u8 hop_limit; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 reserved:3, - router_pref:2, - home_agent:1, - other:1, - managed:1; - -#elif defined(__BIG_ENDIAN_BITFIELD) - __u8 managed:1, - other:1, - home_agent:1, - router_pref:2, - reserved:3; -#else -#error "Please fix " -#endif - __be16 rt_lifetime; - } u_nd_ra; - - } icmp6_dataun; - -#define icmp6_identifier icmp6_dataun.u_echo.identifier -#define icmp6_sequence icmp6_dataun.u_echo.sequence -#define icmp6_pointer icmp6_dataun.un_data32[0] -#define icmp6_mtu icmp6_dataun.un_data32[0] -#define icmp6_unused icmp6_dataun.un_data32[0] -#define icmp6_maxdelay icmp6_dataun.un_data16[0] -#define icmp6_router icmp6_dataun.u_nd_advt.router -#define icmp6_solicited icmp6_dataun.u_nd_advt.solicited -#define icmp6_override icmp6_dataun.u_nd_advt.override -#define icmp6_ndiscreserved icmp6_dataun.u_nd_advt.reserved -#define icmp6_hop_limit icmp6_dataun.u_nd_ra.hop_limit -#define icmp6_addrconf_managed icmp6_dataun.u_nd_ra.managed -#define icmp6_addrconf_other icmp6_dataun.u_nd_ra.other -#define icmp6_rt_lifetime icmp6_dataun.u_nd_ra.rt_lifetime -#define icmp6_router_pref icmp6_dataun.u_nd_ra.router_pref -}; - - -#define ICMPV6_ROUTER_PREF_LOW 0x3 -#define ICMPV6_ROUTER_PREF_MEDIUM 0x0 -#define ICMPV6_ROUTER_PREF_HIGH 0x1 -#define ICMPV6_ROUTER_PREF_INVALID 0x2 - -#define ICMPV6_DEST_UNREACH 1 -#define ICMPV6_PKT_TOOBIG 2 -#define ICMPV6_TIME_EXCEED 3 -#define ICMPV6_PARAMPROB 4 - -#define ICMPV6_INFOMSG_MASK 0x80 - -#define ICMPV6_ECHO_REQUEST 128 -#define ICMPV6_ECHO_REPLY 129 -#define ICMPV6_MGM_QUERY 130 -#define ICMPV6_MGM_REPORT 131 -#define ICMPV6_MGM_REDUCTION 132 - -#define ICMPV6_NI_QUERY 139 -#define ICMPV6_NI_REPLY 140 - -#define ICMPV6_MLD2_REPORT 143 - -#define ICMPV6_DHAAD_REQUEST 144 -#define ICMPV6_DHAAD_REPLY 145 -#define ICMPV6_MOBILE_PREFIX_SOL 146 -#define ICMPV6_MOBILE_PREFIX_ADV 147 - -/* - * Codes for Destination Unreachable - */ -#define ICMPV6_NOROUTE 0 -#define ICMPV6_ADM_PROHIBITED 1 -#define ICMPV6_NOT_NEIGHBOUR 2 -#define ICMPV6_ADDR_UNREACH 3 -#define ICMPV6_PORT_UNREACH 4 -#define ICMPV6_POLICY_FAIL 5 -#define ICMPV6_REJECT_ROUTE 6 - -/* - * Codes for Time Exceeded - */ -#define ICMPV6_EXC_HOPLIMIT 0 -#define ICMPV6_EXC_FRAGTIME 1 - -/* - * Codes for Parameter Problem - */ -#define ICMPV6_HDR_FIELD 0 -#define ICMPV6_UNK_NEXTHDR 1 -#define ICMPV6_UNK_OPTION 2 - -/* - * constants for (set|get)sockopt - */ - -#define ICMPV6_FILTER 1 - -/* - * ICMPV6 filter - */ - -#define ICMPV6_FILTER_BLOCK 1 -#define ICMPV6_FILTER_PASS 2 -#define ICMPV6_FILTER_BLOCKOTHERS 3 -#define ICMPV6_FILTER_PASSONLY 4 - -struct icmp6_filter { - __u32 data[8]; -}; - -/* - * Definitions for MLDv2 - */ -#define MLD2_MODE_IS_INCLUDE 1 -#define MLD2_MODE_IS_EXCLUDE 2 -#define MLD2_CHANGE_TO_INCLUDE 3 -#define MLD2_CHANGE_TO_EXCLUDE 4 -#define MLD2_ALLOW_NEW_SOURCES 5 -#define MLD2_BLOCK_OLD_SOURCES 6 - -#define MLD2_ALL_MCR_INIT { { { 0xff,0x02,0,0,0,0,0,0,0,0,0,0,0,0,0,0x16 } } } - - -#endif /* _UAPI_LINUX_ICMPV6_H */ diff --git a/src/linux/include/uapi/linux/if.h b/src/linux/include/uapi/linux/if.h deleted file mode 100644 index 1158a04..0000000 --- a/src/linux/include/uapi/linux/if.h +++ /dev/null @@ -1,290 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Global definitions for the INET interface module. - * - * Version: @(#)if.h 1.0.2 04/18/93 - * - * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1982-1988 - * Ross Biro - * Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_IF_H -#define _LINUX_IF_H - -#include /* for compatibility with glibc */ -#include /* for "__kernel_caddr_t" et al */ -#include /* for "struct sockaddr" et al */ -#include /* for "__user" et al */ - -#if __UAPI_DEF_IF_IFNAMSIZ -#define IFNAMSIZ 16 -#endif /* __UAPI_DEF_IF_IFNAMSIZ */ -#define IFALIASZ 256 -#include - -/* For glibc compatibility. An empty enum does not compile. */ -#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 || \ - __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 -/** - * enum net_device_flags - &struct net_device flags - * - * These are the &struct net_device flags, they can be set by drivers, the - * kernel and some can be triggered by userspace. Userspace can query and - * set these flags using userspace utilities but there is also a sysfs - * entry available for all dev flags which can be queried and set. These flags - * are shared for all types of net_devices. The sysfs entries are available - * via /sys/class/net//flags. Flags which can be toggled through sysfs - * are annotated below, note that only a few flags can be toggled and some - * other flags are always preserved from the original net_device flags - * even if you try to set them via sysfs. Flags which are always preserved - * are kept under the flag grouping @IFF_VOLATILE. Flags which are volatile - * are annotated below as such. - * - * You should have a pretty good reason to be extending these flags. - * - * @IFF_UP: interface is up. Can be toggled through sysfs. - * @IFF_BROADCAST: broadcast address valid. Volatile. - * @IFF_DEBUG: turn on debugging. Can be toggled through sysfs. - * @IFF_LOOPBACK: is a loopback net. Volatile. - * @IFF_POINTOPOINT: interface is has p-p link. Volatile. - * @IFF_NOTRAILERS: avoid use of trailers. Can be toggled through sysfs. - * Volatile. - * @IFF_RUNNING: interface RFC2863 OPER_UP. Volatile. - * @IFF_NOARP: no ARP protocol. Can be toggled through sysfs. Volatile. - * @IFF_PROMISC: receive all packets. Can be toggled through sysfs. - * @IFF_ALLMULTI: receive all multicast packets. Can be toggled through - * sysfs. - * @IFF_MASTER: master of a load balancer. Volatile. - * @IFF_SLAVE: slave of a load balancer. Volatile. - * @IFF_MULTICAST: Supports multicast. Can be toggled through sysfs. - * @IFF_PORTSEL: can set media type. Can be toggled through sysfs. - * @IFF_AUTOMEDIA: auto media select active. Can be toggled through sysfs. - * @IFF_DYNAMIC: dialup device with changing addresses. Can be toggled - * through sysfs. - * @IFF_LOWER_UP: driver signals L1 up. Volatile. - * @IFF_DORMANT: driver signals dormant. Volatile. - * @IFF_ECHO: echo sent packets. Volatile. - */ -enum net_device_flags { -/* for compatibility with glibc net/if.h */ -#if __UAPI_DEF_IF_NET_DEVICE_FLAGS - IFF_UP = 1<<0, /* sysfs */ - IFF_BROADCAST = 1<<1, /* volatile */ - IFF_DEBUG = 1<<2, /* sysfs */ - IFF_LOOPBACK = 1<<3, /* volatile */ - IFF_POINTOPOINT = 1<<4, /* volatile */ - IFF_NOTRAILERS = 1<<5, /* sysfs */ - IFF_RUNNING = 1<<6, /* volatile */ - IFF_NOARP = 1<<7, /* sysfs */ - IFF_PROMISC = 1<<8, /* sysfs */ - IFF_ALLMULTI = 1<<9, /* sysfs */ - IFF_MASTER = 1<<10, /* volatile */ - IFF_SLAVE = 1<<11, /* volatile */ - IFF_MULTICAST = 1<<12, /* sysfs */ - IFF_PORTSEL = 1<<13, /* sysfs */ - IFF_AUTOMEDIA = 1<<14, /* sysfs */ - IFF_DYNAMIC = 1<<15, /* sysfs */ -#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */ -#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO - IFF_LOWER_UP = 1<<16, /* volatile */ - IFF_DORMANT = 1<<17, /* volatile */ - IFF_ECHO = 1<<18, /* volatile */ -#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ -}; -#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO != 0 || __UAPI_DEF_IF_NET_DEVICE_FLAGS != 0 */ - -/* for compatibility with glibc net/if.h */ -#if __UAPI_DEF_IF_NET_DEVICE_FLAGS -#define IFF_UP IFF_UP -#define IFF_BROADCAST IFF_BROADCAST -#define IFF_DEBUG IFF_DEBUG -#define IFF_LOOPBACK IFF_LOOPBACK -#define IFF_POINTOPOINT IFF_POINTOPOINT -#define IFF_NOTRAILERS IFF_NOTRAILERS -#define IFF_RUNNING IFF_RUNNING -#define IFF_NOARP IFF_NOARP -#define IFF_PROMISC IFF_PROMISC -#define IFF_ALLMULTI IFF_ALLMULTI -#define IFF_MASTER IFF_MASTER -#define IFF_SLAVE IFF_SLAVE -#define IFF_MULTICAST IFF_MULTICAST -#define IFF_PORTSEL IFF_PORTSEL -#define IFF_AUTOMEDIA IFF_AUTOMEDIA -#define IFF_DYNAMIC IFF_DYNAMIC -#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS */ - -#if __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO -#define IFF_LOWER_UP IFF_LOWER_UP -#define IFF_DORMANT IFF_DORMANT -#define IFF_ECHO IFF_ECHO -#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ - -#define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_ECHO|\ - IFF_MASTER|IFF_SLAVE|IFF_RUNNING|IFF_LOWER_UP|IFF_DORMANT) - -#define IF_GET_IFACE 0x0001 /* for querying only */ -#define IF_GET_PROTO 0x0002 - -/* For definitions see hdlc.h */ -#define IF_IFACE_V35 0x1000 /* V.35 serial interface */ -#define IF_IFACE_V24 0x1001 /* V.24 serial interface */ -#define IF_IFACE_X21 0x1002 /* X.21 serial interface */ -#define IF_IFACE_T1 0x1003 /* T1 telco serial interface */ -#define IF_IFACE_E1 0x1004 /* E1 telco serial interface */ -#define IF_IFACE_SYNC_SERIAL 0x1005 /* can't be set by software */ -#define IF_IFACE_X21D 0x1006 /* X.21 Dual Clocking (FarSite) */ - -/* For definitions see hdlc.h */ -#define IF_PROTO_HDLC 0x2000 /* raw HDLC protocol */ -#define IF_PROTO_PPP 0x2001 /* PPP protocol */ -#define IF_PROTO_CISCO 0x2002 /* Cisco HDLC protocol */ -#define IF_PROTO_FR 0x2003 /* Frame Relay protocol */ -#define IF_PROTO_FR_ADD_PVC 0x2004 /* Create FR PVC */ -#define IF_PROTO_FR_DEL_PVC 0x2005 /* Delete FR PVC */ -#define IF_PROTO_X25 0x2006 /* X.25 */ -#define IF_PROTO_HDLC_ETH 0x2007 /* raw HDLC, Ethernet emulation */ -#define IF_PROTO_FR_ADD_ETH_PVC 0x2008 /* Create FR Ethernet-bridged PVC */ -#define IF_PROTO_FR_DEL_ETH_PVC 0x2009 /* Delete FR Ethernet-bridged PVC */ -#define IF_PROTO_FR_PVC 0x200A /* for reading PVC status */ -#define IF_PROTO_FR_ETH_PVC 0x200B -#define IF_PROTO_RAW 0x200C /* RAW Socket */ - -/* RFC 2863 operational status */ -enum { - IF_OPER_UNKNOWN, - IF_OPER_NOTPRESENT, - IF_OPER_DOWN, - IF_OPER_LOWERLAYERDOWN, - IF_OPER_TESTING, - IF_OPER_DORMANT, - IF_OPER_UP, -}; - -/* link modes */ -enum { - IF_LINK_MODE_DEFAULT, - IF_LINK_MODE_DORMANT, /* limit upward transition to dormant */ -}; - -/* - * Device mapping structure. I'd just gone off and designed a - * beautiful scheme using only loadable modules with arguments - * for driver options and along come the PCMCIA people 8) - * - * Ah well. The get() side of this is good for WDSETUP, and it'll - * be handy for debugging things. The set side is fine for now and - * being very small might be worth keeping for clean configuration. - */ - -/* for compatibility with glibc net/if.h */ -#if __UAPI_DEF_IF_IFMAP -struct ifmap { - unsigned long mem_start; - unsigned long mem_end; - unsigned short base_addr; - unsigned char irq; - unsigned char dma; - unsigned char port; - /* 3 bytes spare */ -}; -#endif /* __UAPI_DEF_IF_IFMAP */ - -struct if_settings { - unsigned int type; /* Type of physical device or protocol */ - unsigned int size; /* Size of the data allocated by the caller */ - union { - /* {atm/eth/dsl}_settings anyone ? */ - raw_hdlc_proto __user *raw_hdlc; - cisco_proto __user *cisco; - fr_proto __user *fr; - fr_proto_pvc __user *fr_pvc; - fr_proto_pvc_info __user *fr_pvc_info; - - /* interface settings */ - sync_serial_settings __user *sync; - te1_settings __user *te1; - } ifs_ifsu; -}; - -/* - * Interface request structure used for socket - * ioctl's. All interface ioctl's must have parameter - * definitions which begin with ifr_name. The - * remainder may be interface specific. - */ - -/* for compatibility with glibc net/if.h */ -#if __UAPI_DEF_IF_IFREQ -struct ifreq { -#define IFHWADDRLEN 6 - union - { - char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - } ifr_ifrn; - - union { - struct sockaddr ifru_addr; - struct sockaddr ifru_dstaddr; - struct sockaddr ifru_broadaddr; - struct sockaddr ifru_netmask; - struct sockaddr ifru_hwaddr; - short ifru_flags; - int ifru_ivalue; - int ifru_mtu; - struct ifmap ifru_map; - char ifru_slave[IFNAMSIZ]; /* Just fits the size */ - char ifru_newname[IFNAMSIZ]; - void __user * ifru_data; - struct if_settings ifru_settings; - } ifr_ifru; -}; -#endif /* __UAPI_DEF_IF_IFREQ */ - -#define ifr_name ifr_ifrn.ifrn_name /* interface name */ -#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */ -#define ifr_addr ifr_ifru.ifru_addr /* address */ -#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */ -#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */ -#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */ -#define ifr_flags ifr_ifru.ifru_flags /* flags */ -#define ifr_metric ifr_ifru.ifru_ivalue /* metric */ -#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ -#define ifr_map ifr_ifru.ifru_map /* device map */ -#define ifr_slave ifr_ifru.ifru_slave /* slave device */ -#define ifr_data ifr_ifru.ifru_data /* for use by interface */ -#define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */ -#define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */ -#define ifr_qlen ifr_ifru.ifru_ivalue /* Queue length */ -#define ifr_newname ifr_ifru.ifru_newname /* New name */ -#define ifr_settings ifr_ifru.ifru_settings /* Device/proto settings*/ - -/* - * Structure used in SIOCGIFCONF request. - * Used to retrieve interface configuration - * for machine (useful for programs which - * must know all networks accessible). - */ - -/* for compatibility with glibc net/if.h */ -#if __UAPI_DEF_IF_IFCONF -struct ifconf { - int ifc_len; /* size of buffer */ - union { - char __user *ifcu_buf; - struct ifreq __user *ifcu_req; - } ifc_ifcu; -}; -#endif /* __UAPI_DEF_IF_IFCONF */ - -#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ -#define ifc_req ifc_ifcu.ifcu_req /* array of structures */ - -#endif /* _LINUX_IF_H */ diff --git a/src/linux/include/uapi/linux/if_addr.h b/src/linux/include/uapi/linux/if_addr.h deleted file mode 100644 index 4318ab1..0000000 --- a/src/linux/include/uapi/linux/if_addr.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef __LINUX_IF_ADDR_H -#define __LINUX_IF_ADDR_H - -#include -#include - -struct ifaddrmsg { - __u8 ifa_family; - __u8 ifa_prefixlen; /* The prefix length */ - __u8 ifa_flags; /* Flags */ - __u8 ifa_scope; /* Address scope */ - __u32 ifa_index; /* Link index */ -}; - -/* - * Important comment: - * IFA_ADDRESS is prefix address, rather than local interface address. - * It makes no difference for normally configured broadcast interfaces, - * but for point-to-point IFA_ADDRESS is DESTINATION address, - * local address is supplied in IFA_LOCAL attribute. - * - * IFA_FLAGS is a u32 attribute that extends the u8 field ifa_flags. - * If present, the value from struct ifaddrmsg will be ignored. - */ -enum { - IFA_UNSPEC, - IFA_ADDRESS, - IFA_LOCAL, - IFA_LABEL, - IFA_BROADCAST, - IFA_ANYCAST, - IFA_CACHEINFO, - IFA_MULTICAST, - IFA_FLAGS, - __IFA_MAX, -}; - -#define IFA_MAX (__IFA_MAX - 1) - -/* ifa_flags */ -#define IFA_F_SECONDARY 0x01 -#define IFA_F_TEMPORARY IFA_F_SECONDARY - -#define IFA_F_NODAD 0x02 -#define IFA_F_OPTIMISTIC 0x04 -#define IFA_F_DADFAILED 0x08 -#define IFA_F_HOMEADDRESS 0x10 -#define IFA_F_DEPRECATED 0x20 -#define IFA_F_TENTATIVE 0x40 -#define IFA_F_PERMANENT 0x80 -#define IFA_F_MANAGETEMPADDR 0x100 -#define IFA_F_NOPREFIXROUTE 0x200 -#define IFA_F_MCAUTOJOIN 0x400 -#define IFA_F_STABLE_PRIVACY 0x800 - -struct ifa_cacheinfo { - __u32 ifa_prefered; - __u32 ifa_valid; - __u32 cstamp; /* created timestamp, hundredths of seconds */ - __u32 tstamp; /* updated timestamp, hundredths of seconds */ -}; - -/* backwards compatibility for userspace */ -#ifndef __KERNEL__ -#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg)))) -#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg)) -#endif - -#endif diff --git a/src/linux/include/uapi/linux/if_addrlabel.h b/src/linux/include/uapi/linux/if_addrlabel.h deleted file mode 100644 index 54580c2..0000000 --- a/src/linux/include/uapi/linux/if_addrlabel.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * if_addrlabel.h - netlink interface for address labels - * - * Copyright (C)2007 USAGI/WIDE Project, All Rights Reserved. - * - * Authors: - * YOSHIFUJI Hideaki @ USAGI/WIDE - */ - -#ifndef __LINUX_IF_ADDRLABEL_H -#define __LINUX_IF_ADDRLABEL_H - -#include - -struct ifaddrlblmsg { - __u8 ifal_family; /* Address family */ - __u8 __ifal_reserved; /* Reserved */ - __u8 ifal_prefixlen; /* Prefix length */ - __u8 ifal_flags; /* Flags */ - __u32 ifal_index; /* Link index */ - __u32 ifal_seq; /* sequence number */ -}; - -enum { - IFAL_ADDRESS = 1, - IFAL_LABEL = 2, - __IFAL_MAX -}; - -#define IFAL_MAX (__IFAL_MAX - 1) - -#endif diff --git a/src/linux/include/uapi/linux/if_arcnet.h b/src/linux/include/uapi/linux/if_arcnet.h deleted file mode 100644 index cfb642f..0000000 --- a/src/linux/include/uapi/linux/if_arcnet.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Global definitions for the ARCnet interface. - * - * Authors: David Woodhouse and Avery Pennarun - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _LINUX_IF_ARCNET_H -#define _LINUX_IF_ARCNET_H - -#include -#include - -/* - * These are the defined ARCnet Protocol ID's. - */ - -/* CAP mode */ -/* No macro but uses 1-8 */ - -/* RFC1201 Protocol ID's */ -#define ARC_P_IP 212 /* 0xD4 */ -#define ARC_P_IPV6 196 /* 0xC4: RFC2497 */ -#define ARC_P_ARP 213 /* 0xD5 */ -#define ARC_P_RARP 214 /* 0xD6 */ -#define ARC_P_IPX 250 /* 0xFA */ -#define ARC_P_NOVELL_EC 236 /* 0xEC */ - -/* Old RFC1051 Protocol ID's */ -#define ARC_P_IP_RFC1051 240 /* 0xF0 */ -#define ARC_P_ARP_RFC1051 241 /* 0xF1 */ - -/* MS LanMan/WfWg "NDIS" encapsulation */ -#define ARC_P_ETHER 232 /* 0xE8 */ - -/* Unsupported/indirectly supported protocols */ -#define ARC_P_DATAPOINT_BOOT 0 /* very old Datapoint equipment */ -#define ARC_P_DATAPOINT_MOUNT 1 -#define ARC_P_POWERLAN_BEACON 8 /* Probably ATA-Netbios related */ -#define ARC_P_POWERLAN_BEACON2 243 /* 0xF3 */ -#define ARC_P_LANSOFT 251 /* 0xFB - what is this? */ -#define ARC_P_ATALK 0xDD - -/* Hardware address length */ -#define ARCNET_ALEN 1 - -/* - * The RFC1201-specific components of an arcnet packet header. - */ -struct arc_rfc1201 { - __u8 proto; /* protocol ID field - varies */ - __u8 split_flag; /* for use with split packets */ - __be16 sequence; /* sequence number */ - __u8 payload[0]; /* space remaining in packet (504 bytes)*/ -}; -#define RFC1201_HDR_SIZE 4 - -/* - * The RFC1051-specific components. - */ -struct arc_rfc1051 { - __u8 proto; /* ARC_P_RFC1051_ARP/RFC1051_IP */ - __u8 payload[0]; /* 507 bytes */ -}; -#define RFC1051_HDR_SIZE 1 - -/* - * The ethernet-encap-specific components. We have a real ethernet header - * and some data. - */ -struct arc_eth_encap { - __u8 proto; /* Always ARC_P_ETHER */ - struct ethhdr eth; /* standard ethernet header (yuck!) */ - __u8 payload[0]; /* 493 bytes */ -}; -#define ETH_ENCAP_HDR_SIZE 14 - -struct arc_cap { - __u8 proto; - __u8 cookie[sizeof(int)]; - /* Actually NOT sent over the network */ - union { - __u8 ack; - __u8 raw[0]; /* 507 bytes */ - } mes; -}; - -/* - * The data needed by the actual arcnet hardware. - * - * Now, in the real arcnet hardware, the third and fourth bytes are the - * 'offset' specification instead of the length, and the soft data is at - * the _end_ of the 512-byte buffer. We hide this complexity inside the - * driver. - */ -struct arc_hardware { - __u8 source; /* source ARCnet - filled in automagically */ - __u8 dest; /* destination ARCnet - 0 for broadcast */ - __u8 offset[2]; /* offset bytes (some weird semantics) */ -}; -#define ARC_HDR_SIZE 4 - -/* - * This is an ARCnet frame header, as seen by the kernel (and userspace, - * when you do a raw packet capture). - */ -struct archdr { - /* hardware requirements */ - struct arc_hardware hard; - - /* arcnet encapsulation-specific bits */ - union { - struct arc_rfc1201 rfc1201; - struct arc_rfc1051 rfc1051; - struct arc_eth_encap eth_encap; - struct arc_cap cap; - __u8 raw[0]; /* 508 bytes */ - } soft; -}; - -#endif /* _LINUX_IF_ARCNET_H */ diff --git a/src/linux/include/uapi/linux/if_arp.h b/src/linux/include/uapi/linux/if_arp.h deleted file mode 100644 index 4d024d7..0000000 --- a/src/linux/include/uapi/linux/if_arp.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Global definitions for the ARP (RFC 826) protocol. - * - * Version: @(#)if_arp.h 1.0.1 04/16/93 - * - * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988 - * Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source. - * Ross Biro - * Fred N. van Kempen, - * Florian La Roche, - * Jonathan Layes - * Arnaldo Carvalho de Melo ARPHRD_HWX25 - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _UAPI_LINUX_IF_ARP_H -#define _UAPI_LINUX_IF_ARP_H - -#include - -/* ARP protocol HARDWARE identifiers. */ -#define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */ -#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */ -#define ARPHRD_EETHER 2 /* Experimental Ethernet */ -#define ARPHRD_AX25 3 /* AX.25 Level 2 */ -#define ARPHRD_PRONET 4 /* PROnet token ring */ -#define ARPHRD_CHAOS 5 /* Chaosnet */ -#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet/TR/TB */ -#define ARPHRD_ARCNET 7 /* ARCnet */ -#define ARPHRD_APPLETLK 8 /* APPLEtalk */ -#define ARPHRD_DLCI 15 /* Frame Relay DLCI */ -#define ARPHRD_ATM 19 /* ATM */ -#define ARPHRD_METRICOM 23 /* Metricom STRIP (new IANA id) */ -#define ARPHRD_IEEE1394 24 /* IEEE 1394 IPv4 - RFC 2734 */ -#define ARPHRD_EUI64 27 /* EUI-64 */ -#define ARPHRD_INFINIBAND 32 /* InfiniBand */ - -/* Dummy types for non ARP hardware */ -#define ARPHRD_SLIP 256 -#define ARPHRD_CSLIP 257 -#define ARPHRD_SLIP6 258 -#define ARPHRD_CSLIP6 259 -#define ARPHRD_RSRVD 260 /* Notional KISS type */ -#define ARPHRD_ADAPT 264 -#define ARPHRD_ROSE 270 -#define ARPHRD_X25 271 /* CCITT X.25 */ -#define ARPHRD_HWX25 272 /* Boards with X.25 in firmware */ -#define ARPHRD_CAN 280 /* Controller Area Network */ -#define ARPHRD_PPP 512 -#define ARPHRD_CISCO 513 /* Cisco HDLC */ -#define ARPHRD_HDLC ARPHRD_CISCO -#define ARPHRD_LAPB 516 /* LAPB */ -#define ARPHRD_DDCMP 517 /* Digital's DDCMP protocol */ -#define ARPHRD_RAWHDLC 518 /* Raw HDLC */ - -#define ARPHRD_TUNNEL 768 /* IPIP tunnel */ -#define ARPHRD_TUNNEL6 769 /* IP6IP6 tunnel */ -#define ARPHRD_FRAD 770 /* Frame Relay Access Device */ -#define ARPHRD_SKIP 771 /* SKIP vif */ -#define ARPHRD_LOOPBACK 772 /* Loopback device */ -#define ARPHRD_LOCALTLK 773 /* Localtalk device */ -#define ARPHRD_FDDI 774 /* Fiber Distributed Data Interface */ -#define ARPHRD_BIF 775 /* AP1000 BIF */ -#define ARPHRD_SIT 776 /* sit0 device - IPv6-in-IPv4 */ -#define ARPHRD_IPDDP 777 /* IP over DDP tunneller */ -#define ARPHRD_IPGRE 778 /* GRE over IP */ -#define ARPHRD_PIMREG 779 /* PIMSM register interface */ -#define ARPHRD_HIPPI 780 /* High Performance Parallel Interface */ -#define ARPHRD_ASH 781 /* Nexus 64Mbps Ash */ -#define ARPHRD_ECONET 782 /* Acorn Econet */ -#define ARPHRD_IRDA 783 /* Linux-IrDA */ -/* ARP works differently on different FC media .. so */ -#define ARPHRD_FCPP 784 /* Point to point fibrechannel */ -#define ARPHRD_FCAL 785 /* Fibrechannel arbitrated loop */ -#define ARPHRD_FCPL 786 /* Fibrechannel public loop */ -#define ARPHRD_FCFABRIC 787 /* Fibrechannel fabric */ - /* 787->799 reserved for fibrechannel media types */ -#define ARPHRD_IEEE802_TR 800 /* Magic type ident for TR */ -#define ARPHRD_IEEE80211 801 /* IEEE 802.11 */ -#define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */ -#define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */ -#define ARPHRD_IEEE802154 804 -#define ARPHRD_IEEE802154_MONITOR 805 /* IEEE 802.15.4 network monitor */ - -#define ARPHRD_PHONET 820 /* PhoNet media type */ -#define ARPHRD_PHONET_PIPE 821 /* PhoNet pipe header */ -#define ARPHRD_CAIF 822 /* CAIF media type */ -#define ARPHRD_IP6GRE 823 /* GRE over IPv6 */ -#define ARPHRD_NETLINK 824 /* Netlink header */ -#define ARPHRD_6LOWPAN 825 /* IPv6 over LoWPAN */ - -#define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */ -#define ARPHRD_NONE 0xFFFE /* zero header length */ - -/* ARP protocol opcodes. */ -#define ARPOP_REQUEST 1 /* ARP request */ -#define ARPOP_REPLY 2 /* ARP reply */ -#define ARPOP_RREQUEST 3 /* RARP request */ -#define ARPOP_RREPLY 4 /* RARP reply */ -#define ARPOP_InREQUEST 8 /* InARP request */ -#define ARPOP_InREPLY 9 /* InARP reply */ -#define ARPOP_NAK 10 /* (ATM)ARP NAK */ - - -/* ARP ioctl request. */ -struct arpreq { - struct sockaddr arp_pa; /* protocol address */ - struct sockaddr arp_ha; /* hardware address */ - int arp_flags; /* flags */ - struct sockaddr arp_netmask; /* netmask (only for proxy arps) */ - char arp_dev[16]; -}; - -struct arpreq_old { - struct sockaddr arp_pa; /* protocol address */ - struct sockaddr arp_ha; /* hardware address */ - int arp_flags; /* flags */ - struct sockaddr arp_netmask; /* netmask (only for proxy arps) */ -}; - -/* ARP Flag values. */ -#define ATF_COM 0x02 /* completed entry (ha valid) */ -#define ATF_PERM 0x04 /* permanent entry */ -#define ATF_PUBL 0x08 /* publish entry */ -#define ATF_USETRAILERS 0x10 /* has requested trailers */ -#define ATF_NETMASK 0x20 /* want to use a netmask (only - for proxy entries) */ -#define ATF_DONTPUB 0x40 /* don't answer this addresses */ - -/* - * This structure defines an ethernet arp header. - */ - -struct arphdr { - __be16 ar_hrd; /* format of hardware address */ - __be16 ar_pro; /* format of protocol address */ - unsigned char ar_hln; /* length of hardware address */ - unsigned char ar_pln; /* length of protocol address */ - __be16 ar_op; /* ARP opcode (command) */ - -#if 0 - /* - * Ethernet looks like this : This bit is variable sized however... - */ - unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ - unsigned char ar_sip[4]; /* sender IP address */ - unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ - unsigned char ar_tip[4]; /* target IP address */ -#endif - -}; - - -#endif /* _UAPI_LINUX_IF_ARP_H */ diff --git a/src/linux/include/uapi/linux/if_bonding.h b/src/linux/include/uapi/linux/if_bonding.h deleted file mode 100644 index 9635a62..0000000 --- a/src/linux/include/uapi/linux/if_bonding.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Bond several ethernet interfaces into a Cisco, running 'Etherchannel'. - * - * - * Portions are (c) Copyright 1995 Simon "Guru Aleph-Null" Janes - * NCM: Network and Communications Management, Inc. - * - * BUT, I'm the one who modified it for ethernet, so: - * (c) Copyright 1999, Thomas Davis, tadavis@lbl.gov - * - * This software may be used and distributed according to the terms - * of the GNU Public License, incorporated herein by reference. - * - * 2003/03/18 - Amir Noam - * - Added support for getting slave's speed and duplex via ethtool. - * Needed for 802.3ad and other future modes. - * - * 2003/03/18 - Tsippy Mendelson and - * Shmulik Hen - * - Enable support of modes that need to use the unique mac address of - * each slave. - * - * 2003/03/18 - Tsippy Mendelson and - * Amir Noam - * - Moved driver's private data types to bonding.h - * - * 2003/03/18 - Amir Noam , - * Tsippy Mendelson and - * Shmulik Hen - * - Added support for IEEE 802.3ad Dynamic link aggregation mode. - * - * 2003/05/01 - Amir Noam - * - Added ABI version control to restore compatibility between - * new/old ifenslave and new/old bonding. - * - * 2003/12/01 - Shmulik Hen - * - Code cleanup and style changes - * - * 2005/05/05 - Jason Gabler - * - added definitions for various XOR hashing policies - */ - -#ifndef _LINUX_IF_BONDING_H -#define _LINUX_IF_BONDING_H - -#include -#include -#include - -/* userland - kernel ABI version (2003/05/08) */ -#define BOND_ABI_VERSION 2 - -/* - * We can remove these ioctl definitions in 2.5. People should use the - * SIOC*** versions of them instead - */ -#define BOND_ENSLAVE_OLD (SIOCDEVPRIVATE) -#define BOND_RELEASE_OLD (SIOCDEVPRIVATE + 1) -#define BOND_SETHWADDR_OLD (SIOCDEVPRIVATE + 2) -#define BOND_SLAVE_INFO_QUERY_OLD (SIOCDEVPRIVATE + 11) -#define BOND_INFO_QUERY_OLD (SIOCDEVPRIVATE + 12) -#define BOND_CHANGE_ACTIVE_OLD (SIOCDEVPRIVATE + 13) - -#define BOND_CHECK_MII_STATUS (SIOCGMIIPHY) - -#define BOND_MODE_ROUNDROBIN 0 -#define BOND_MODE_ACTIVEBACKUP 1 -#define BOND_MODE_XOR 2 -#define BOND_MODE_BROADCAST 3 -#define BOND_MODE_8023AD 4 -#define BOND_MODE_TLB 5 -#define BOND_MODE_ALB 6 /* TLB + RLB (receive load balancing) */ - -/* each slave's link has 4 states */ -#define BOND_LINK_UP 0 /* link is up and running */ -#define BOND_LINK_FAIL 1 /* link has just gone down */ -#define BOND_LINK_DOWN 2 /* link has been down for too long time */ -#define BOND_LINK_BACK 3 /* link is going back */ - -/* each slave has several states */ -#define BOND_STATE_ACTIVE 0 /* link is active */ -#define BOND_STATE_BACKUP 1 /* link is backup */ - -#define BOND_DEFAULT_MAX_BONDS 1 /* Default maximum number of devices to support */ - -#define BOND_DEFAULT_TX_QUEUES 16 /* Default number of tx queues per device */ - -#define BOND_DEFAULT_RESEND_IGMP 1 /* Default number of IGMP membership reports */ - -/* hashing types */ -#define BOND_XMIT_POLICY_LAYER2 0 /* layer 2 (MAC only), default */ -#define BOND_XMIT_POLICY_LAYER34 1 /* layer 3+4 (IP ^ (TCP || UDP)) */ -#define BOND_XMIT_POLICY_LAYER23 2 /* layer 2+3 (IP ^ MAC) */ -#define BOND_XMIT_POLICY_ENCAP23 3 /* encapsulated layer 2+3 */ -#define BOND_XMIT_POLICY_ENCAP34 4 /* encapsulated layer 3+4 */ - -typedef struct ifbond { - __s32 bond_mode; - __s32 num_slaves; - __s32 miimon; -} ifbond; - -typedef struct ifslave { - __s32 slave_id; /* Used as an IN param to the BOND_SLAVE_INFO_QUERY ioctl */ - char slave_name[IFNAMSIZ]; - __s8 link; - __s8 state; - __u32 link_failure_count; -} ifslave; - -struct ad_info { - __u16 aggregator_id; - __u16 ports; - __u16 actor_key; - __u16 partner_key; - __u8 partner_system[ETH_ALEN]; -}; - -#endif /* _LINUX_IF_BONDING_H */ - -/* - * Local variables: - * version-control: t - * kept-new-versions: 5 - * c-indent-level: 8 - * c-basic-offset: 8 - * tab-width: 8 - * End: - */ - diff --git a/src/linux/include/uapi/linux/if_bridge.h b/src/linux/include/uapi/linux/if_bridge.h deleted file mode 100644 index ab92bca..0000000 --- a/src/linux/include/uapi/linux/if_bridge.h +++ /dev/null @@ -1,283 +0,0 @@ -/* - * Linux ethernet bridge - * - * Authors: - * Lennert Buytenhek - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _UAPI_LINUX_IF_BRIDGE_H -#define _UAPI_LINUX_IF_BRIDGE_H - -#include -#include -#include - -#define SYSFS_BRIDGE_ATTR "bridge" -#define SYSFS_BRIDGE_FDB "brforward" -#define SYSFS_BRIDGE_PORT_SUBDIR "brif" -#define SYSFS_BRIDGE_PORT_ATTR "brport" -#define SYSFS_BRIDGE_PORT_LINK "bridge" - -#define BRCTL_VERSION 1 - -#define BRCTL_GET_VERSION 0 -#define BRCTL_GET_BRIDGES 1 -#define BRCTL_ADD_BRIDGE 2 -#define BRCTL_DEL_BRIDGE 3 -#define BRCTL_ADD_IF 4 -#define BRCTL_DEL_IF 5 -#define BRCTL_GET_BRIDGE_INFO 6 -#define BRCTL_GET_PORT_LIST 7 -#define BRCTL_SET_BRIDGE_FORWARD_DELAY 8 -#define BRCTL_SET_BRIDGE_HELLO_TIME 9 -#define BRCTL_SET_BRIDGE_MAX_AGE 10 -#define BRCTL_SET_AGEING_TIME 11 -#define BRCTL_SET_GC_INTERVAL 12 -#define BRCTL_GET_PORT_INFO 13 -#define BRCTL_SET_BRIDGE_STP_STATE 14 -#define BRCTL_SET_BRIDGE_PRIORITY 15 -#define BRCTL_SET_PORT_PRIORITY 16 -#define BRCTL_SET_PATH_COST 17 -#define BRCTL_GET_FDB_ENTRIES 18 - -#define BR_STATE_DISABLED 0 -#define BR_STATE_LISTENING 1 -#define BR_STATE_LEARNING 2 -#define BR_STATE_FORWARDING 3 -#define BR_STATE_BLOCKING 4 - -struct __bridge_info { - __u64 designated_root; - __u64 bridge_id; - __u32 root_path_cost; - __u32 max_age; - __u32 hello_time; - __u32 forward_delay; - __u32 bridge_max_age; - __u32 bridge_hello_time; - __u32 bridge_forward_delay; - __u8 topology_change; - __u8 topology_change_detected; - __u8 root_port; - __u8 stp_enabled; - __u32 ageing_time; - __u32 gc_interval; - __u32 hello_timer_value; - __u32 tcn_timer_value; - __u32 topology_change_timer_value; - __u32 gc_timer_value; -}; - -struct __port_info { - __u64 designated_root; - __u64 designated_bridge; - __u16 port_id; - __u16 designated_port; - __u32 path_cost; - __u32 designated_cost; - __u8 state; - __u8 top_change_ack; - __u8 config_pending; - __u8 unused0; - __u32 message_age_timer_value; - __u32 forward_delay_timer_value; - __u32 hold_timer_value; -}; - -struct __fdb_entry { - __u8 mac_addr[ETH_ALEN]; - __u8 port_no; - __u8 is_local; - __u32 ageing_timer_value; - __u8 port_hi; - __u8 pad0; - __u16 unused; -}; - -/* Bridge Flags */ -#define BRIDGE_FLAGS_MASTER 1 /* Bridge command to/from master */ -#define BRIDGE_FLAGS_SELF 2 /* Bridge command to/from lowerdev */ - -#define BRIDGE_MODE_VEB 0 /* Default loopback mode */ -#define BRIDGE_MODE_VEPA 1 /* 802.1Qbg defined VEPA mode */ -#define BRIDGE_MODE_UNDEF 0xFFFF /* mode undefined */ - -/* Bridge management nested attributes - * [IFLA_AF_SPEC] = { - * [IFLA_BRIDGE_FLAGS] - * [IFLA_BRIDGE_MODE] - * [IFLA_BRIDGE_VLAN_INFO] - * } - */ -enum { - IFLA_BRIDGE_FLAGS, - IFLA_BRIDGE_MODE, - IFLA_BRIDGE_VLAN_INFO, - __IFLA_BRIDGE_MAX, -}; -#define IFLA_BRIDGE_MAX (__IFLA_BRIDGE_MAX - 1) - -#define BRIDGE_VLAN_INFO_MASTER (1<<0) /* Operate on Bridge device as well */ -#define BRIDGE_VLAN_INFO_PVID (1<<1) /* VLAN is PVID, ingress untagged */ -#define BRIDGE_VLAN_INFO_UNTAGGED (1<<2) /* VLAN egresses untagged */ -#define BRIDGE_VLAN_INFO_RANGE_BEGIN (1<<3) /* VLAN is start of vlan range */ -#define BRIDGE_VLAN_INFO_RANGE_END (1<<4) /* VLAN is end of vlan range */ -#define BRIDGE_VLAN_INFO_BRENTRY (1<<5) /* Global bridge VLAN entry */ - -struct bridge_vlan_info { - __u16 flags; - __u16 vid; -}; - -struct bridge_vlan_xstats { - __u64 rx_bytes; - __u64 rx_packets; - __u64 tx_bytes; - __u64 tx_packets; - __u16 vid; - __u16 flags; - __u32 pad2; -}; - -/* Bridge multicast database attributes - * [MDBA_MDB] = { - * [MDBA_MDB_ENTRY] = { - * [MDBA_MDB_ENTRY_INFO] { - * struct br_mdb_entry - * [MDBA_MDB_EATTR attributes] - * } - * } - * } - * [MDBA_ROUTER] = { - * [MDBA_ROUTER_PORT] = { - * u32 ifindex - * [MDBA_ROUTER_PATTR attributes] - * } - * } - */ -enum { - MDBA_UNSPEC, - MDBA_MDB, - MDBA_ROUTER, - __MDBA_MAX, -}; -#define MDBA_MAX (__MDBA_MAX - 1) - -enum { - MDBA_MDB_UNSPEC, - MDBA_MDB_ENTRY, - __MDBA_MDB_MAX, -}; -#define MDBA_MDB_MAX (__MDBA_MDB_MAX - 1) - -enum { - MDBA_MDB_ENTRY_UNSPEC, - MDBA_MDB_ENTRY_INFO, - __MDBA_MDB_ENTRY_MAX, -}; -#define MDBA_MDB_ENTRY_MAX (__MDBA_MDB_ENTRY_MAX - 1) - -/* per mdb entry additional attributes */ -enum { - MDBA_MDB_EATTR_UNSPEC, - MDBA_MDB_EATTR_TIMER, - __MDBA_MDB_EATTR_MAX -}; -#define MDBA_MDB_EATTR_MAX (__MDBA_MDB_EATTR_MAX - 1) - -/* multicast router types */ -enum { - MDB_RTR_TYPE_DISABLED, - MDB_RTR_TYPE_TEMP_QUERY, - MDB_RTR_TYPE_PERM, - MDB_RTR_TYPE_TEMP -}; - -enum { - MDBA_ROUTER_UNSPEC, - MDBA_ROUTER_PORT, - __MDBA_ROUTER_MAX, -}; -#define MDBA_ROUTER_MAX (__MDBA_ROUTER_MAX - 1) - -/* router port attributes */ -enum { - MDBA_ROUTER_PATTR_UNSPEC, - MDBA_ROUTER_PATTR_TIMER, - MDBA_ROUTER_PATTR_TYPE, - __MDBA_ROUTER_PATTR_MAX -}; -#define MDBA_ROUTER_PATTR_MAX (__MDBA_ROUTER_PATTR_MAX - 1) - -struct br_port_msg { - __u8 family; - __u32 ifindex; -}; - -struct br_mdb_entry { - __u32 ifindex; -#define MDB_TEMPORARY 0 -#define MDB_PERMANENT 1 - __u8 state; -#define MDB_FLAGS_OFFLOAD (1 << 0) - __u8 flags; - __u16 vid; - struct { - union { - __be32 ip4; - struct in6_addr ip6; - } u; - __be16 proto; - } addr; -}; - -enum { - MDBA_SET_ENTRY_UNSPEC, - MDBA_SET_ENTRY, - __MDBA_SET_ENTRY_MAX, -}; -#define MDBA_SET_ENTRY_MAX (__MDBA_SET_ENTRY_MAX - 1) - -/* Embedded inside LINK_XSTATS_TYPE_BRIDGE */ -enum { - BRIDGE_XSTATS_UNSPEC, - BRIDGE_XSTATS_VLAN, - BRIDGE_XSTATS_MCAST, - BRIDGE_XSTATS_PAD, - __BRIDGE_XSTATS_MAX -}; -#define BRIDGE_XSTATS_MAX (__BRIDGE_XSTATS_MAX - 1) - -enum { - BR_MCAST_DIR_RX, - BR_MCAST_DIR_TX, - BR_MCAST_DIR_SIZE -}; - -/* IGMP/MLD statistics */ -struct br_mcast_stats { - __u64 igmp_v1queries[BR_MCAST_DIR_SIZE]; - __u64 igmp_v2queries[BR_MCAST_DIR_SIZE]; - __u64 igmp_v3queries[BR_MCAST_DIR_SIZE]; - __u64 igmp_leaves[BR_MCAST_DIR_SIZE]; - __u64 igmp_v1reports[BR_MCAST_DIR_SIZE]; - __u64 igmp_v2reports[BR_MCAST_DIR_SIZE]; - __u64 igmp_v3reports[BR_MCAST_DIR_SIZE]; - __u64 igmp_parse_errors; - - __u64 mld_v1queries[BR_MCAST_DIR_SIZE]; - __u64 mld_v2queries[BR_MCAST_DIR_SIZE]; - __u64 mld_leaves[BR_MCAST_DIR_SIZE]; - __u64 mld_v1reports[BR_MCAST_DIR_SIZE]; - __u64 mld_v2reports[BR_MCAST_DIR_SIZE]; - __u64 mld_parse_errors; - - __u64 mcast_bytes[BR_MCAST_DIR_SIZE]; - __u64 mcast_packets[BR_MCAST_DIR_SIZE]; -}; -#endif /* _UAPI_LINUX_IF_BRIDGE_H */ diff --git a/src/linux/include/uapi/linux/if_ether.h b/src/linux/include/uapi/linux/if_ether.h deleted file mode 100644 index 117d02e..0000000 --- a/src/linux/include/uapi/linux/if_ether.h +++ /dev/null @@ -1,148 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Global definitions for the Ethernet IEEE 802.3 interface. - * - * Version: @(#)if_ether.h 1.0.1a 02/08/94 - * - * Author: Fred N. van Kempen, - * Donald Becker, - * Alan Cox, - * Steve Whitehouse, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _UAPI_LINUX_IF_ETHER_H -#define _UAPI_LINUX_IF_ETHER_H - -#include - -/* - * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble - * and FCS/CRC (frame check sequence). - */ - -#define ETH_ALEN 6 /* Octets in one ethernet addr */ -#define ETH_HLEN 14 /* Total octets in header. */ -#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */ -#define ETH_DATA_LEN 1500 /* Max. octets in payload */ -#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */ -#define ETH_FCS_LEN 4 /* Octets in the FCS */ - -/* - * These are the defined Ethernet Protocol ID's. - */ - -#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */ -#define ETH_P_PUP 0x0200 /* Xerox PUP packet */ -#define ETH_P_PUPAT 0x0201 /* Xerox PUP Addr Trans packet */ -#define ETH_P_TSN 0x22F0 /* TSN (IEEE 1722) packet */ -#define ETH_P_IP 0x0800 /* Internet Protocol packet */ -#define ETH_P_X25 0x0805 /* CCITT X.25 */ -#define ETH_P_ARP 0x0806 /* Address Resolution packet */ -#define ETH_P_BPQ 0x08FF /* G8BPQ AX.25 Ethernet Packet [ NOT AN OFFICIALLY REGISTERED ID ] */ -#define ETH_P_IEEEPUP 0x0a00 /* Xerox IEEE802.3 PUP packet */ -#define ETH_P_IEEEPUPAT 0x0a01 /* Xerox IEEE802.3 PUP Addr Trans packet */ -#define ETH_P_BATMAN 0x4305 /* B.A.T.M.A.N.-Advanced packet [ NOT AN OFFICIALLY REGISTERED ID ] */ -#define ETH_P_DEC 0x6000 /* DEC Assigned proto */ -#define ETH_P_DNA_DL 0x6001 /* DEC DNA Dump/Load */ -#define ETH_P_DNA_RC 0x6002 /* DEC DNA Remote Console */ -#define ETH_P_DNA_RT 0x6003 /* DEC DNA Routing */ -#define ETH_P_LAT 0x6004 /* DEC LAT */ -#define ETH_P_DIAG 0x6005 /* DEC Diagnostics */ -#define ETH_P_CUST 0x6006 /* DEC Customer use */ -#define ETH_P_SCA 0x6007 /* DEC Systems Comms Arch */ -#define ETH_P_TEB 0x6558 /* Trans Ether Bridging */ -#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */ -#define ETH_P_ATALK 0x809B /* Appletalk DDP */ -#define ETH_P_AARP 0x80F3 /* Appletalk AARP */ -#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */ -#define ETH_P_IPX 0x8137 /* IPX over DIX */ -#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */ -#define ETH_P_PAUSE 0x8808 /* IEEE Pause frames. See 802.3 31B */ -#define ETH_P_SLOW 0x8809 /* Slow Protocol. See 802.3ad 43B */ -#define ETH_P_WCCP 0x883E /* Web-cache coordination protocol - * defined in draft-wilson-wrec-wccp-v2-00.txt */ -#define ETH_P_MPLS_UC 0x8847 /* MPLS Unicast traffic */ -#define ETH_P_MPLS_MC 0x8848 /* MPLS Multicast traffic */ -#define ETH_P_ATMMPOA 0x884c /* MultiProtocol Over ATM */ -#define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */ -#define ETH_P_PPP_SES 0x8864 /* PPPoE session messages */ -#define ETH_P_LINK_CTL 0x886c /* HPNA, wlan link local tunnel */ -#define ETH_P_ATMFATE 0x8884 /* Frame-based ATM Transport - * over Ethernet - */ -#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ -#define ETH_P_AOE 0x88A2 /* ATA over Ethernet */ -#define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */ -#define ETH_P_802_EX1 0x88B5 /* 802.1 Local Experimental 1. */ -#define ETH_P_TIPC 0x88CA /* TIPC */ -#define ETH_P_MACSEC 0x88E5 /* 802.1ae MACsec */ -#define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */ -#define ETH_P_MVRP 0x88F5 /* 802.1Q MVRP */ -#define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */ -#define ETH_P_NCSI 0x88F8 /* NCSI protocol */ -#define ETH_P_PRP 0x88FB /* IEC 62439-3 PRP/HSRv0 */ -#define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */ -#define ETH_P_TDLS 0x890D /* TDLS */ -#define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */ -#define ETH_P_80221 0x8917 /* IEEE 802.21 Media Independent Handover Protocol */ -#define ETH_P_HSR 0x892F /* IEC 62439-3 HSRv1 */ -#define ETH_P_LOOPBACK 0x9000 /* Ethernet loopback packet, per IEEE 802.3 */ -#define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ -#define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ -#define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */ -#define ETH_P_EDSA 0xDADA /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */ -#define ETH_P_AF_IUCV 0xFBFB /* IBM af_iucv [ NOT AN OFFICIALLY REGISTERED ID ] */ - -#define ETH_P_802_3_MIN 0x0600 /* If the value in the ethernet type is less than this value - * then the frame is Ethernet II. Else it is 802.3 */ - -/* - * Non DIX types. Won't clash for 1500 types. - */ - -#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */ -#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */ -#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ -#define ETH_P_802_2 0x0004 /* 802.2 frames */ -#define ETH_P_SNAP 0x0005 /* Internal only */ -#define ETH_P_DDCMP 0x0006 /* DEC DDCMP: Internal only */ -#define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/ -#define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */ -#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */ -#define ETH_P_CAN 0x000C /* CAN: Controller Area Network */ -#define ETH_P_CANFD 0x000D /* CANFD: CAN flexible data rate*/ -#define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/ -#define ETH_P_TR_802_2 0x0011 /* 802.2 frames */ -#define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */ -#define ETH_P_CONTROL 0x0016 /* Card specific control frames */ -#define ETH_P_IRDA 0x0017 /* Linux-IrDA */ -#define ETH_P_ECONET 0x0018 /* Acorn Econet */ -#define ETH_P_HDLC 0x0019 /* HDLC frames */ -#define ETH_P_ARCNET 0x001A /* 1A for ArcNet :-) */ -#define ETH_P_DSA 0x001B /* Distributed Switch Arch. */ -#define ETH_P_TRAILER 0x001C /* Trailer switch tagging */ -#define ETH_P_PHONET 0x00F5 /* Nokia Phonet frames */ -#define ETH_P_IEEE802154 0x00F6 /* IEEE802.15.4 frame */ -#define ETH_P_CAIF 0x00F7 /* ST-Ericsson CAIF protocol */ -#define ETH_P_XDSA 0x00F8 /* Multiplexed DSA protocol */ - -/* - * This is an Ethernet frame header. - */ - -struct ethhdr { - unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ - unsigned char h_source[ETH_ALEN]; /* source ether addr */ - __be16 h_proto; /* packet type ID field */ -} __attribute__((packed)); - - -#endif /* _UAPI_LINUX_IF_ETHER_H */ diff --git a/src/linux/include/uapi/linux/if_fddi.h b/src/linux/include/uapi/linux/if_fddi.h deleted file mode 100644 index 1086cd9..0000000 --- a/src/linux/include/uapi/linux/if_fddi.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Global definitions for the ANSI FDDI interface. - * - * Version: @(#)if_fddi.h 1.0.2 Sep 29 2004 - * - * Author: Lawrence V. Stefani, - * - * if_fddi.h is based on previous if_ether.h and if_tr.h work by - * Fred N. van Kempen, - * Donald Becker, - * Alan Cox, - * Steve Whitehouse, - * Peter De Schrijver, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _UAPI_LINUX_IF_FDDI_H -#define _UAPI_LINUX_IF_FDDI_H - -#include - -/* - * Define max and min legal sizes. The frame sizes do not include - * 4 byte FCS/CRC (frame check sequence). - */ -#define FDDI_K_ALEN 6 /* Octets in one FDDI address */ -#define FDDI_K_8022_HLEN 16 /* Total octets in 802.2 header */ -#define FDDI_K_SNAP_HLEN 21 /* Total octets in 802.2 SNAP header */ -#define FDDI_K_8022_ZLEN 16 /* Min octets in 802.2 frame sans - FCS */ -#define FDDI_K_SNAP_ZLEN 21 /* Min octets in 802.2 SNAP frame sans - FCS */ -#define FDDI_K_8022_DLEN 4475 /* Max octets in 802.2 payload */ -#define FDDI_K_SNAP_DLEN 4470 /* Max octets in 802.2 SNAP payload */ -#define FDDI_K_LLC_ZLEN 13 /* Min octets in LLC frame sans FCS */ -#define FDDI_K_LLC_LEN 4491 /* Max octets in LLC frame sans FCS */ -#define FDDI_K_OUI_LEN 3 /* Octets in OUI in 802.2 SNAP - header */ - -/* Define FDDI Frame Control (FC) Byte values */ -#define FDDI_FC_K_VOID 0x00 -#define FDDI_FC_K_NON_RESTRICTED_TOKEN 0x80 -#define FDDI_FC_K_RESTRICTED_TOKEN 0xC0 -#define FDDI_FC_K_SMT_MIN 0x41 -#define FDDI_FC_K_SMT_MAX 0x4F -#define FDDI_FC_K_MAC_MIN 0xC1 -#define FDDI_FC_K_MAC_MAX 0xCF -#define FDDI_FC_K_ASYNC_LLC_MIN 0x50 -#define FDDI_FC_K_ASYNC_LLC_DEF 0x54 -#define FDDI_FC_K_ASYNC_LLC_MAX 0x5F -#define FDDI_FC_K_SYNC_LLC_MIN 0xD0 -#define FDDI_FC_K_SYNC_LLC_MAX 0xD7 -#define FDDI_FC_K_IMPLEMENTOR_MIN 0x60 -#define FDDI_FC_K_IMPLEMENTOR_MAX 0x6F -#define FDDI_FC_K_RESERVED_MIN 0x70 -#define FDDI_FC_K_RESERVED_MAX 0x7F - -/* Define LLC and SNAP constants */ -#define FDDI_EXTENDED_SAP 0xAA -#define FDDI_UI_CMD 0x03 - -/* Define 802.2 Type 1 header */ -struct fddi_8022_1_hdr { - __u8 dsap; /* destination service access point */ - __u8 ssap; /* source service access point */ - __u8 ctrl; /* control byte #1 */ -} __attribute__((packed)); - -/* Define 802.2 Type 2 header */ -struct fddi_8022_2_hdr { - __u8 dsap; /* destination service access point */ - __u8 ssap; /* source service access point */ - __u8 ctrl_1; /* control byte #1 */ - __u8 ctrl_2; /* control byte #2 */ -} __attribute__((packed)); - -/* Define 802.2 SNAP header */ -struct fddi_snap_hdr { - __u8 dsap; /* always 0xAA */ - __u8 ssap; /* always 0xAA */ - __u8 ctrl; /* always 0x03 */ - __u8 oui[FDDI_K_OUI_LEN]; /* organizational universal id */ - __be16 ethertype; /* packet type ID field */ -} __attribute__((packed)); - -/* Define FDDI LLC frame header */ -struct fddihdr { - __u8 fc; /* frame control */ - __u8 daddr[FDDI_K_ALEN]; /* destination address */ - __u8 saddr[FDDI_K_ALEN]; /* source address */ - union { - struct fddi_8022_1_hdr llc_8022_1; - struct fddi_8022_2_hdr llc_8022_2; - struct fddi_snap_hdr llc_snap; - } hdr; -} __attribute__((packed)); - - -#endif /* _UAPI_LINUX_IF_FDDI_H */ diff --git a/src/linux/include/uapi/linux/if_frad.h b/src/linux/include/uapi/linux/if_frad.h deleted file mode 100644 index f25b08d..0000000 --- a/src/linux/include/uapi/linux/if_frad.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * DLCI/FRAD Definitions for Frame Relay Access Devices. DLCI devices are - * created for each DLCI associated with a FRAD. The FRAD driver - * is not truly a network device, but the lower level device - * handler. This allows other FRAD manufacturers to use the DLCI - * code, including its RFC1490 encapsulation alongside the current - * implementation for the Sangoma cards. - * - * Version: @(#)if_ifrad.h 0.15 31 Mar 96 - * - * Author: Mike McLagan - * - * Changes: - * 0.15 Mike McLagan changed structure defs (packed) - * re-arranged flags - * added DLCI_RET vars - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _UAPI_FRAD_H_ -#define _UAPI_FRAD_H_ - -#include - -/* Structures and constants associated with the DLCI device driver */ - -struct dlci_add -{ - char devname[IFNAMSIZ]; - short dlci; -}; - -#define DLCI_GET_CONF (SIOCDEVPRIVATE + 2) -#define DLCI_SET_CONF (SIOCDEVPRIVATE + 3) - -/* - * These are related to the Sangoma SDLA and should remain in order. - * Code within the SDLA module is based on the specifics of this - * structure. Change at your own peril. - */ -struct dlci_conf { - short flags; - short CIR_fwd; - short Bc_fwd; - short Be_fwd; - short CIR_bwd; - short Bc_bwd; - short Be_bwd; - -/* these are part of the status read */ - short Tc_fwd; - short Tc_bwd; - short Tf_max; - short Tb_max; - -/* add any new fields here above is a mirror of sdla_dlci_conf */ -}; - -#define DLCI_GET_SLAVE (SIOCDEVPRIVATE + 4) - -/* configuration flags for DLCI */ -#define DLCI_IGNORE_CIR_OUT 0x0001 -#define DLCI_ACCOUNT_CIR_IN 0x0002 -#define DLCI_BUFFER_IF 0x0008 - -#define DLCI_VALID_FLAGS 0x000B - -/* defines for the actual Frame Relay hardware */ -#define FRAD_GET_CONF (SIOCDEVPRIVATE) -#define FRAD_SET_CONF (SIOCDEVPRIVATE + 1) - -#define FRAD_LAST_IOCTL FRAD_SET_CONF - -/* - * Based on the setup for the Sangoma SDLA. If changes are - * necessary to this structure, a routine will need to be - * added to that module to copy fields. - */ -struct frad_conf -{ - short station; - short flags; - short kbaud; - short clocking; - short mtu; - short T391; - short T392; - short N391; - short N392; - short N393; - short CIR_fwd; - short Bc_fwd; - short Be_fwd; - short CIR_bwd; - short Bc_bwd; - short Be_bwd; - -/* Add new fields here, above is a mirror of the sdla_conf */ - -}; - -#define FRAD_STATION_CPE 0x0000 -#define FRAD_STATION_NODE 0x0001 - -#define FRAD_TX_IGNORE_CIR 0x0001 -#define FRAD_RX_ACCOUNT_CIR 0x0002 -#define FRAD_DROP_ABORTED 0x0004 -#define FRAD_BUFFERIF 0x0008 -#define FRAD_STATS 0x0010 -#define FRAD_MCI 0x0100 -#define FRAD_AUTODLCI 0x8000 -#define FRAD_VALID_FLAGS 0x811F - -#define FRAD_CLOCK_INT 0x0001 -#define FRAD_CLOCK_EXT 0x0000 - - -#endif /* _UAPI_FRAD_H_ */ diff --git a/src/linux/include/uapi/linux/if_infiniband.h b/src/linux/include/uapi/linux/if_infiniband.h deleted file mode 100644 index 7d95847..0000000 --- a/src/linux/include/uapi/linux/if_infiniband.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * This software is available to you under a choice of one of two - * licenses. You may choose to be licensed under the terms of the GNU - * General Public License (GPL) Version 2, available at - * , or the OpenIB.org BSD - * license, available in the LICENSE.TXT file accompanying this - * software. These details are also available at - * . - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS - * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN - * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - * - * Copyright (c) 2004 Topspin Communications. All rights reserved. - * - * $Id$ - */ - -#ifndef _LINUX_IF_INFINIBAND_H -#define _LINUX_IF_INFINIBAND_H - -#define INFINIBAND_ALEN 20 /* Octets in IPoIB HW addr */ - -#endif /* _LINUX_IF_INFINIBAND_H */ diff --git a/src/linux/include/uapi/linux/if_link.h b/src/linux/include/uapi/linux/if_link.h deleted file mode 100644 index b4fba66..0000000 --- a/src/linux/include/uapi/linux/if_link.h +++ /dev/null @@ -1,886 +0,0 @@ -#ifndef _UAPI_LINUX_IF_LINK_H -#define _UAPI_LINUX_IF_LINK_H - -#include -#include - -/* This struct should be in sync with struct rtnl_link_stats64 */ -struct rtnl_link_stats { - __u32 rx_packets; /* total packets received */ - __u32 tx_packets; /* total packets transmitted */ - __u32 rx_bytes; /* total bytes received */ - __u32 tx_bytes; /* total bytes transmitted */ - __u32 rx_errors; /* bad packets received */ - __u32 tx_errors; /* packet transmit problems */ - __u32 rx_dropped; /* no space in linux buffers */ - __u32 tx_dropped; /* no space available in linux */ - __u32 multicast; /* multicast packets received */ - __u32 collisions; - - /* detailed rx_errors: */ - __u32 rx_length_errors; - __u32 rx_over_errors; /* receiver ring buff overflow */ - __u32 rx_crc_errors; /* recved pkt with crc error */ - __u32 rx_frame_errors; /* recv'd frame alignment error */ - __u32 rx_fifo_errors; /* recv'r fifo overrun */ - __u32 rx_missed_errors; /* receiver missed packet */ - - /* detailed tx_errors */ - __u32 tx_aborted_errors; - __u32 tx_carrier_errors; - __u32 tx_fifo_errors; - __u32 tx_heartbeat_errors; - __u32 tx_window_errors; - - /* for cslip etc */ - __u32 rx_compressed; - __u32 tx_compressed; - - __u32 rx_nohandler; /* dropped, no handler found */ -}; - -/* The main device statistics structure */ -struct rtnl_link_stats64 { - __u64 rx_packets; /* total packets received */ - __u64 tx_packets; /* total packets transmitted */ - __u64 rx_bytes; /* total bytes received */ - __u64 tx_bytes; /* total bytes transmitted */ - __u64 rx_errors; /* bad packets received */ - __u64 tx_errors; /* packet transmit problems */ - __u64 rx_dropped; /* no space in linux buffers */ - __u64 tx_dropped; /* no space available in linux */ - __u64 multicast; /* multicast packets received */ - __u64 collisions; - - /* detailed rx_errors: */ - __u64 rx_length_errors; - __u64 rx_over_errors; /* receiver ring buff overflow */ - __u64 rx_crc_errors; /* recved pkt with crc error */ - __u64 rx_frame_errors; /* recv'd frame alignment error */ - __u64 rx_fifo_errors; /* recv'r fifo overrun */ - __u64 rx_missed_errors; /* receiver missed packet */ - - /* detailed tx_errors */ - __u64 tx_aborted_errors; - __u64 tx_carrier_errors; - __u64 tx_fifo_errors; - __u64 tx_heartbeat_errors; - __u64 tx_window_errors; - - /* for cslip etc */ - __u64 rx_compressed; - __u64 tx_compressed; - - __u64 rx_nohandler; /* dropped, no handler found */ -}; - -/* The struct should be in sync with struct ifmap */ -struct rtnl_link_ifmap { - __u64 mem_start; - __u64 mem_end; - __u64 base_addr; - __u16 irq; - __u8 dma; - __u8 port; -}; - -/* - * IFLA_AF_SPEC - * Contains nested attributes for address family specific attributes. - * Each address family may create a attribute with the address family - * number as type and create its own attribute structure in it. - * - * Example: - * [IFLA_AF_SPEC] = { - * [AF_INET] = { - * [IFLA_INET_CONF] = ..., - * }, - * [AF_INET6] = { - * [IFLA_INET6_FLAGS] = ..., - * [IFLA_INET6_CONF] = ..., - * } - * } - */ - -enum { - IFLA_UNSPEC, - IFLA_ADDRESS, - IFLA_BROADCAST, - IFLA_IFNAME, - IFLA_MTU, - IFLA_LINK, - IFLA_QDISC, - IFLA_STATS, - IFLA_COST, -#define IFLA_COST IFLA_COST - IFLA_PRIORITY, -#define IFLA_PRIORITY IFLA_PRIORITY - IFLA_MASTER, -#define IFLA_MASTER IFLA_MASTER - IFLA_WIRELESS, /* Wireless Extension event - see wireless.h */ -#define IFLA_WIRELESS IFLA_WIRELESS - IFLA_PROTINFO, /* Protocol specific information for a link */ -#define IFLA_PROTINFO IFLA_PROTINFO - IFLA_TXQLEN, -#define IFLA_TXQLEN IFLA_TXQLEN - IFLA_MAP, -#define IFLA_MAP IFLA_MAP - IFLA_WEIGHT, -#define IFLA_WEIGHT IFLA_WEIGHT - IFLA_OPERSTATE, - IFLA_LINKMODE, - IFLA_LINKINFO, -#define IFLA_LINKINFO IFLA_LINKINFO - IFLA_NET_NS_PID, - IFLA_IFALIAS, - IFLA_NUM_VF, /* Number of VFs if device is SR-IOV PF */ - IFLA_VFINFO_LIST, - IFLA_STATS64, - IFLA_VF_PORTS, - IFLA_PORT_SELF, - IFLA_AF_SPEC, - IFLA_GROUP, /* Group the device belongs to */ - IFLA_NET_NS_FD, - IFLA_EXT_MASK, /* Extended info mask, VFs, etc */ - IFLA_PROMISCUITY, /* Promiscuity count: > 0 means acts PROMISC */ -#define IFLA_PROMISCUITY IFLA_PROMISCUITY - IFLA_NUM_TX_QUEUES, - IFLA_NUM_RX_QUEUES, - IFLA_CARRIER, - IFLA_PHYS_PORT_ID, - IFLA_CARRIER_CHANGES, - IFLA_PHYS_SWITCH_ID, - IFLA_LINK_NETNSID, - IFLA_PHYS_PORT_NAME, - IFLA_PROTO_DOWN, - IFLA_GSO_MAX_SEGS, - IFLA_GSO_MAX_SIZE, - IFLA_PAD, - IFLA_XDP, - __IFLA_MAX -}; - - -#define IFLA_MAX (__IFLA_MAX - 1) - -/* backwards compatibility for userspace */ -#ifndef __KERNEL__ -#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg)))) -#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg)) -#endif - -enum { - IFLA_INET_UNSPEC, - IFLA_INET_CONF, - __IFLA_INET_MAX, -}; - -#define IFLA_INET_MAX (__IFLA_INET_MAX - 1) - -/* ifi_flags. - - IFF_* flags. - - The only change is: - IFF_LOOPBACK, IFF_BROADCAST and IFF_POINTOPOINT are - more not changeable by user. They describe link media - characteristics and set by device driver. - - Comments: - - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid - - If neither of these three flags are set; - the interface is NBMA. - - - IFF_MULTICAST does not mean anything special: - multicasts can be used on all not-NBMA links. - IFF_MULTICAST means that this media uses special encapsulation - for multicast frames. Apparently, all IFF_POINTOPOINT and - IFF_BROADCAST devices are able to use multicasts too. - */ - -/* IFLA_LINK. - For usual devices it is equal ifi_index. - If it is a "virtual interface" (f.e. tunnel), ifi_link - can point to real physical interface (f.e. for bandwidth calculations), - or maybe 0, what means, that real media is unknown (usual - for IPIP tunnels, when route to endpoint is allowed to change) - */ - -/* Subtype attributes for IFLA_PROTINFO */ -enum { - IFLA_INET6_UNSPEC, - IFLA_INET6_FLAGS, /* link flags */ - IFLA_INET6_CONF, /* sysctl parameters */ - IFLA_INET6_STATS, /* statistics */ - IFLA_INET6_MCAST, /* MC things. What of them? */ - IFLA_INET6_CACHEINFO, /* time values and max reasm size */ - IFLA_INET6_ICMP6STATS, /* statistics (icmpv6) */ - IFLA_INET6_TOKEN, /* device token */ - IFLA_INET6_ADDR_GEN_MODE, /* implicit address generator mode */ - __IFLA_INET6_MAX -}; - -#define IFLA_INET6_MAX (__IFLA_INET6_MAX - 1) - -enum in6_addr_gen_mode { - IN6_ADDR_GEN_MODE_EUI64, - IN6_ADDR_GEN_MODE_NONE, - IN6_ADDR_GEN_MODE_STABLE_PRIVACY, - IN6_ADDR_GEN_MODE_RANDOM, -}; - -/* Bridge section */ - -enum { - IFLA_BR_UNSPEC, - IFLA_BR_FORWARD_DELAY, - IFLA_BR_HELLO_TIME, - IFLA_BR_MAX_AGE, - IFLA_BR_AGEING_TIME, - IFLA_BR_STP_STATE, - IFLA_BR_PRIORITY, - IFLA_BR_VLAN_FILTERING, - IFLA_BR_VLAN_PROTOCOL, - IFLA_BR_GROUP_FWD_MASK, - IFLA_BR_ROOT_ID, - IFLA_BR_BRIDGE_ID, - IFLA_BR_ROOT_PORT, - IFLA_BR_ROOT_PATH_COST, - IFLA_BR_TOPOLOGY_CHANGE, - IFLA_BR_TOPOLOGY_CHANGE_DETECTED, - IFLA_BR_HELLO_TIMER, - IFLA_BR_TCN_TIMER, - IFLA_BR_TOPOLOGY_CHANGE_TIMER, - IFLA_BR_GC_TIMER, - IFLA_BR_GROUP_ADDR, - IFLA_BR_FDB_FLUSH, - IFLA_BR_MCAST_ROUTER, - IFLA_BR_MCAST_SNOOPING, - IFLA_BR_MCAST_QUERY_USE_IFADDR, - IFLA_BR_MCAST_QUERIER, - IFLA_BR_MCAST_HASH_ELASTICITY, - IFLA_BR_MCAST_HASH_MAX, - IFLA_BR_MCAST_LAST_MEMBER_CNT, - IFLA_BR_MCAST_STARTUP_QUERY_CNT, - IFLA_BR_MCAST_LAST_MEMBER_INTVL, - IFLA_BR_MCAST_MEMBERSHIP_INTVL, - IFLA_BR_MCAST_QUERIER_INTVL, - IFLA_BR_MCAST_QUERY_INTVL, - IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, - IFLA_BR_MCAST_STARTUP_QUERY_INTVL, - IFLA_BR_NF_CALL_IPTABLES, - IFLA_BR_NF_CALL_IP6TABLES, - IFLA_BR_NF_CALL_ARPTABLES, - IFLA_BR_VLAN_DEFAULT_PVID, - IFLA_BR_PAD, - IFLA_BR_VLAN_STATS_ENABLED, - IFLA_BR_MCAST_STATS_ENABLED, - __IFLA_BR_MAX, -}; - -#define IFLA_BR_MAX (__IFLA_BR_MAX - 1) - -struct ifla_bridge_id { - __u8 prio[2]; - __u8 addr[6]; /* ETH_ALEN */ -}; - -enum { - BRIDGE_MODE_UNSPEC, - BRIDGE_MODE_HAIRPIN, -}; - -enum { - IFLA_BRPORT_UNSPEC, - IFLA_BRPORT_STATE, /* Spanning tree state */ - IFLA_BRPORT_PRIORITY, /* " priority */ - IFLA_BRPORT_COST, /* " cost */ - IFLA_BRPORT_MODE, /* mode (hairpin) */ - IFLA_BRPORT_GUARD, /* bpdu guard */ - IFLA_BRPORT_PROTECT, /* root port protection */ - IFLA_BRPORT_FAST_LEAVE, /* multicast fast leave */ - IFLA_BRPORT_LEARNING, /* mac learning */ - IFLA_BRPORT_UNICAST_FLOOD, /* flood unicast traffic */ - IFLA_BRPORT_PROXYARP, /* proxy ARP */ - IFLA_BRPORT_LEARNING_SYNC, /* mac learning sync from device */ - IFLA_BRPORT_PROXYARP_WIFI, /* proxy ARP for Wi-Fi */ - IFLA_BRPORT_ROOT_ID, /* designated root */ - IFLA_BRPORT_BRIDGE_ID, /* designated bridge */ - IFLA_BRPORT_DESIGNATED_PORT, - IFLA_BRPORT_DESIGNATED_COST, - IFLA_BRPORT_ID, - IFLA_BRPORT_NO, - IFLA_BRPORT_TOPOLOGY_CHANGE_ACK, - IFLA_BRPORT_CONFIG_PENDING, - IFLA_BRPORT_MESSAGE_AGE_TIMER, - IFLA_BRPORT_FORWARD_DELAY_TIMER, - IFLA_BRPORT_HOLD_TIMER, - IFLA_BRPORT_FLUSH, - IFLA_BRPORT_MULTICAST_ROUTER, - IFLA_BRPORT_PAD, - IFLA_BRPORT_MCAST_FLOOD, - __IFLA_BRPORT_MAX -}; -#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) - -struct ifla_cacheinfo { - __u32 max_reasm_len; - __u32 tstamp; /* ipv6InterfaceTable updated timestamp */ - __u32 reachable_time; - __u32 retrans_time; -}; - -enum { - IFLA_INFO_UNSPEC, - IFLA_INFO_KIND, - IFLA_INFO_DATA, - IFLA_INFO_XSTATS, - IFLA_INFO_SLAVE_KIND, - IFLA_INFO_SLAVE_DATA, - __IFLA_INFO_MAX, -}; - -#define IFLA_INFO_MAX (__IFLA_INFO_MAX - 1) - -/* VLAN section */ - -enum { - IFLA_VLAN_UNSPEC, - IFLA_VLAN_ID, - IFLA_VLAN_FLAGS, - IFLA_VLAN_EGRESS_QOS, - IFLA_VLAN_INGRESS_QOS, - IFLA_VLAN_PROTOCOL, - __IFLA_VLAN_MAX, -}; - -#define IFLA_VLAN_MAX (__IFLA_VLAN_MAX - 1) - -struct ifla_vlan_flags { - __u32 flags; - __u32 mask; -}; - -enum { - IFLA_VLAN_QOS_UNSPEC, - IFLA_VLAN_QOS_MAPPING, - __IFLA_VLAN_QOS_MAX -}; - -#define IFLA_VLAN_QOS_MAX (__IFLA_VLAN_QOS_MAX - 1) - -struct ifla_vlan_qos_mapping { - __u32 from; - __u32 to; -}; - -/* MACVLAN section */ -enum { - IFLA_MACVLAN_UNSPEC, - IFLA_MACVLAN_MODE, - IFLA_MACVLAN_FLAGS, - IFLA_MACVLAN_MACADDR_MODE, - IFLA_MACVLAN_MACADDR, - IFLA_MACVLAN_MACADDR_DATA, - IFLA_MACVLAN_MACADDR_COUNT, - __IFLA_MACVLAN_MAX, -}; - -#define IFLA_MACVLAN_MAX (__IFLA_MACVLAN_MAX - 1) - -enum macvlan_mode { - MACVLAN_MODE_PRIVATE = 1, /* don't talk to other macvlans */ - MACVLAN_MODE_VEPA = 2, /* talk to other ports through ext bridge */ - MACVLAN_MODE_BRIDGE = 4, /* talk to bridge ports directly */ - MACVLAN_MODE_PASSTHRU = 8,/* take over the underlying device */ - MACVLAN_MODE_SOURCE = 16,/* use source MAC address list to assign */ -}; - -enum macvlan_macaddr_mode { - MACVLAN_MACADDR_ADD, - MACVLAN_MACADDR_DEL, - MACVLAN_MACADDR_FLUSH, - MACVLAN_MACADDR_SET, -}; - -#define MACVLAN_FLAG_NOPROMISC 1 - -/* VRF section */ -enum { - IFLA_VRF_UNSPEC, - IFLA_VRF_TABLE, - __IFLA_VRF_MAX -}; - -#define IFLA_VRF_MAX (__IFLA_VRF_MAX - 1) - -enum { - IFLA_VRF_PORT_UNSPEC, - IFLA_VRF_PORT_TABLE, - __IFLA_VRF_PORT_MAX -}; - -#define IFLA_VRF_PORT_MAX (__IFLA_VRF_PORT_MAX - 1) - -/* MACSEC section */ -enum { - IFLA_MACSEC_UNSPEC, - IFLA_MACSEC_SCI, - IFLA_MACSEC_PORT, - IFLA_MACSEC_ICV_LEN, - IFLA_MACSEC_CIPHER_SUITE, - IFLA_MACSEC_WINDOW, - IFLA_MACSEC_ENCODING_SA, - IFLA_MACSEC_ENCRYPT, - IFLA_MACSEC_PROTECT, - IFLA_MACSEC_INC_SCI, - IFLA_MACSEC_ES, - IFLA_MACSEC_SCB, - IFLA_MACSEC_REPLAY_PROTECT, - IFLA_MACSEC_VALIDATION, - IFLA_MACSEC_PAD, - __IFLA_MACSEC_MAX, -}; - -#define IFLA_MACSEC_MAX (__IFLA_MACSEC_MAX - 1) - -enum macsec_validation_type { - MACSEC_VALIDATE_DISABLED = 0, - MACSEC_VALIDATE_CHECK = 1, - MACSEC_VALIDATE_STRICT = 2, - __MACSEC_VALIDATE_END, - MACSEC_VALIDATE_MAX = __MACSEC_VALIDATE_END - 1, -}; - -/* IPVLAN section */ -enum { - IFLA_IPVLAN_UNSPEC, - IFLA_IPVLAN_MODE, - __IFLA_IPVLAN_MAX -}; - -#define IFLA_IPVLAN_MAX (__IFLA_IPVLAN_MAX - 1) - -enum ipvlan_mode { - IPVLAN_MODE_L2 = 0, - IPVLAN_MODE_L3, - IPVLAN_MODE_L3S, - IPVLAN_MODE_MAX -}; - -/* VXLAN section */ -enum { - IFLA_VXLAN_UNSPEC, - IFLA_VXLAN_ID, - IFLA_VXLAN_GROUP, /* group or remote address */ - IFLA_VXLAN_LINK, - IFLA_VXLAN_LOCAL, - IFLA_VXLAN_TTL, - IFLA_VXLAN_TOS, - IFLA_VXLAN_LEARNING, - IFLA_VXLAN_AGEING, - IFLA_VXLAN_LIMIT, - IFLA_VXLAN_PORT_RANGE, /* source port */ - IFLA_VXLAN_PROXY, - IFLA_VXLAN_RSC, - IFLA_VXLAN_L2MISS, - IFLA_VXLAN_L3MISS, - IFLA_VXLAN_PORT, /* destination port */ - IFLA_VXLAN_GROUP6, - IFLA_VXLAN_LOCAL6, - IFLA_VXLAN_UDP_CSUM, - IFLA_VXLAN_UDP_ZERO_CSUM6_TX, - IFLA_VXLAN_UDP_ZERO_CSUM6_RX, - IFLA_VXLAN_REMCSUM_TX, - IFLA_VXLAN_REMCSUM_RX, - IFLA_VXLAN_GBP, - IFLA_VXLAN_REMCSUM_NOPARTIAL, - IFLA_VXLAN_COLLECT_METADATA, - IFLA_VXLAN_LABEL, - IFLA_VXLAN_GPE, - __IFLA_VXLAN_MAX -}; -#define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) - -struct ifla_vxlan_port_range { - __be16 low; - __be16 high; -}; - -/* GENEVE section */ -enum { - IFLA_GENEVE_UNSPEC, - IFLA_GENEVE_ID, - IFLA_GENEVE_REMOTE, - IFLA_GENEVE_TTL, - IFLA_GENEVE_TOS, - IFLA_GENEVE_PORT, /* destination port */ - IFLA_GENEVE_COLLECT_METADATA, - IFLA_GENEVE_REMOTE6, - IFLA_GENEVE_UDP_CSUM, - IFLA_GENEVE_UDP_ZERO_CSUM6_TX, - IFLA_GENEVE_UDP_ZERO_CSUM6_RX, - IFLA_GENEVE_LABEL, - __IFLA_GENEVE_MAX -}; -#define IFLA_GENEVE_MAX (__IFLA_GENEVE_MAX - 1) - -/* PPP section */ -enum { - IFLA_PPP_UNSPEC, - IFLA_PPP_DEV_FD, - __IFLA_PPP_MAX -}; -#define IFLA_PPP_MAX (__IFLA_PPP_MAX - 1) - -/* GTP section */ -enum { - IFLA_GTP_UNSPEC, - IFLA_GTP_FD0, - IFLA_GTP_FD1, - IFLA_GTP_PDP_HASHSIZE, - __IFLA_GTP_MAX, -}; -#define IFLA_GTP_MAX (__IFLA_GTP_MAX - 1) - -/* Bonding section */ - -enum { - IFLA_BOND_UNSPEC, - IFLA_BOND_MODE, - IFLA_BOND_ACTIVE_SLAVE, - IFLA_BOND_MIIMON, - IFLA_BOND_UPDELAY, - IFLA_BOND_DOWNDELAY, - IFLA_BOND_USE_CARRIER, - IFLA_BOND_ARP_INTERVAL, - IFLA_BOND_ARP_IP_TARGET, - IFLA_BOND_ARP_VALIDATE, - IFLA_BOND_ARP_ALL_TARGETS, - IFLA_BOND_PRIMARY, - IFLA_BOND_PRIMARY_RESELECT, - IFLA_BOND_FAIL_OVER_MAC, - IFLA_BOND_XMIT_HASH_POLICY, - IFLA_BOND_RESEND_IGMP, - IFLA_BOND_NUM_PEER_NOTIF, - IFLA_BOND_ALL_SLAVES_ACTIVE, - IFLA_BOND_MIN_LINKS, - IFLA_BOND_LP_INTERVAL, - IFLA_BOND_PACKETS_PER_SLAVE, - IFLA_BOND_AD_LACP_RATE, - IFLA_BOND_AD_SELECT, - IFLA_BOND_AD_INFO, - IFLA_BOND_AD_ACTOR_SYS_PRIO, - IFLA_BOND_AD_USER_PORT_KEY, - IFLA_BOND_AD_ACTOR_SYSTEM, - IFLA_BOND_TLB_DYNAMIC_LB, - __IFLA_BOND_MAX, -}; - -#define IFLA_BOND_MAX (__IFLA_BOND_MAX - 1) - -enum { - IFLA_BOND_AD_INFO_UNSPEC, - IFLA_BOND_AD_INFO_AGGREGATOR, - IFLA_BOND_AD_INFO_NUM_PORTS, - IFLA_BOND_AD_INFO_ACTOR_KEY, - IFLA_BOND_AD_INFO_PARTNER_KEY, - IFLA_BOND_AD_INFO_PARTNER_MAC, - __IFLA_BOND_AD_INFO_MAX, -}; - -#define IFLA_BOND_AD_INFO_MAX (__IFLA_BOND_AD_INFO_MAX - 1) - -enum { - IFLA_BOND_SLAVE_UNSPEC, - IFLA_BOND_SLAVE_STATE, - IFLA_BOND_SLAVE_MII_STATUS, - IFLA_BOND_SLAVE_LINK_FAILURE_COUNT, - IFLA_BOND_SLAVE_PERM_HWADDR, - IFLA_BOND_SLAVE_QUEUE_ID, - IFLA_BOND_SLAVE_AD_AGGREGATOR_ID, - IFLA_BOND_SLAVE_AD_ACTOR_OPER_PORT_STATE, - IFLA_BOND_SLAVE_AD_PARTNER_OPER_PORT_STATE, - __IFLA_BOND_SLAVE_MAX, -}; - -#define IFLA_BOND_SLAVE_MAX (__IFLA_BOND_SLAVE_MAX - 1) - -/* SR-IOV virtual function management section */ - -enum { - IFLA_VF_INFO_UNSPEC, - IFLA_VF_INFO, - __IFLA_VF_INFO_MAX, -}; - -#define IFLA_VF_INFO_MAX (__IFLA_VF_INFO_MAX - 1) - -enum { - IFLA_VF_UNSPEC, - IFLA_VF_MAC, /* Hardware queue specific attributes */ - IFLA_VF_VLAN, /* VLAN ID and QoS */ - IFLA_VF_TX_RATE, /* Max TX Bandwidth Allocation */ - IFLA_VF_SPOOFCHK, /* Spoof Checking on/off switch */ - IFLA_VF_LINK_STATE, /* link state enable/disable/auto switch */ - IFLA_VF_RATE, /* Min and Max TX Bandwidth Allocation */ - IFLA_VF_RSS_QUERY_EN, /* RSS Redirection Table and Hash Key query - * on/off switch - */ - IFLA_VF_STATS, /* network device statistics */ - IFLA_VF_TRUST, /* Trust VF */ - IFLA_VF_IB_NODE_GUID, /* VF Infiniband node GUID */ - IFLA_VF_IB_PORT_GUID, /* VF Infiniband port GUID */ - IFLA_VF_VLAN_LIST, /* nested list of vlans, option for QinQ */ - __IFLA_VF_MAX, -}; - -#define IFLA_VF_MAX (__IFLA_VF_MAX - 1) - -struct ifla_vf_mac { - __u32 vf; - __u8 mac[32]; /* MAX_ADDR_LEN */ -}; - -struct ifla_vf_vlan { - __u32 vf; - __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */ - __u32 qos; -}; - -enum { - IFLA_VF_VLAN_INFO_UNSPEC, - IFLA_VF_VLAN_INFO, /* VLAN ID, QoS and VLAN protocol */ - __IFLA_VF_VLAN_INFO_MAX, -}; - -#define IFLA_VF_VLAN_INFO_MAX (__IFLA_VF_VLAN_INFO_MAX - 1) -#define MAX_VLAN_LIST_LEN 1 - -struct ifla_vf_vlan_info { - __u32 vf; - __u32 vlan; /* 0 - 4095, 0 disables VLAN filter */ - __u32 qos; - __be16 vlan_proto; /* VLAN protocol either 802.1Q or 802.1ad */ -}; - -struct ifla_vf_tx_rate { - __u32 vf; - __u32 rate; /* Max TX bandwidth in Mbps, 0 disables throttling */ -}; - -struct ifla_vf_rate { - __u32 vf; - __u32 min_tx_rate; /* Min Bandwidth in Mbps */ - __u32 max_tx_rate; /* Max Bandwidth in Mbps */ -}; - -struct ifla_vf_spoofchk { - __u32 vf; - __u32 setting; -}; - -struct ifla_vf_guid { - __u32 vf; - __u64 guid; -}; - -enum { - IFLA_VF_LINK_STATE_AUTO, /* link state of the uplink */ - IFLA_VF_LINK_STATE_ENABLE, /* link always up */ - IFLA_VF_LINK_STATE_DISABLE, /* link always down */ - __IFLA_VF_LINK_STATE_MAX, -}; - -struct ifla_vf_link_state { - __u32 vf; - __u32 link_state; -}; - -struct ifla_vf_rss_query_en { - __u32 vf; - __u32 setting; -}; - -enum { - IFLA_VF_STATS_RX_PACKETS, - IFLA_VF_STATS_TX_PACKETS, - IFLA_VF_STATS_RX_BYTES, - IFLA_VF_STATS_TX_BYTES, - IFLA_VF_STATS_BROADCAST, - IFLA_VF_STATS_MULTICAST, - IFLA_VF_STATS_PAD, - __IFLA_VF_STATS_MAX, -}; - -#define IFLA_VF_STATS_MAX (__IFLA_VF_STATS_MAX - 1) - -struct ifla_vf_trust { - __u32 vf; - __u32 setting; -}; - -/* VF ports management section - * - * Nested layout of set/get msg is: - * - * [IFLA_NUM_VF] - * [IFLA_VF_PORTS] - * [IFLA_VF_PORT] - * [IFLA_PORT_*], ... - * [IFLA_VF_PORT] - * [IFLA_PORT_*], ... - * ... - * [IFLA_PORT_SELF] - * [IFLA_PORT_*], ... - */ - -enum { - IFLA_VF_PORT_UNSPEC, - IFLA_VF_PORT, /* nest */ - __IFLA_VF_PORT_MAX, -}; - -#define IFLA_VF_PORT_MAX (__IFLA_VF_PORT_MAX - 1) - -enum { - IFLA_PORT_UNSPEC, - IFLA_PORT_VF, /* __u32 */ - IFLA_PORT_PROFILE, /* string */ - IFLA_PORT_VSI_TYPE, /* 802.1Qbg (pre-)standard VDP */ - IFLA_PORT_INSTANCE_UUID, /* binary UUID */ - IFLA_PORT_HOST_UUID, /* binary UUID */ - IFLA_PORT_REQUEST, /* __u8 */ - IFLA_PORT_RESPONSE, /* __u16, output only */ - __IFLA_PORT_MAX, -}; - -#define IFLA_PORT_MAX (__IFLA_PORT_MAX - 1) - -#define PORT_PROFILE_MAX 40 -#define PORT_UUID_MAX 16 -#define PORT_SELF_VF -1 - -enum { - PORT_REQUEST_PREASSOCIATE = 0, - PORT_REQUEST_PREASSOCIATE_RR, - PORT_REQUEST_ASSOCIATE, - PORT_REQUEST_DISASSOCIATE, -}; - -enum { - PORT_VDP_RESPONSE_SUCCESS = 0, - PORT_VDP_RESPONSE_INVALID_FORMAT, - PORT_VDP_RESPONSE_INSUFFICIENT_RESOURCES, - PORT_VDP_RESPONSE_UNUSED_VTID, - PORT_VDP_RESPONSE_VTID_VIOLATION, - PORT_VDP_RESPONSE_VTID_VERSION_VIOALTION, - PORT_VDP_RESPONSE_OUT_OF_SYNC, - /* 0x08-0xFF reserved for future VDP use */ - PORT_PROFILE_RESPONSE_SUCCESS = 0x100, - PORT_PROFILE_RESPONSE_INPROGRESS, - PORT_PROFILE_RESPONSE_INVALID, - PORT_PROFILE_RESPONSE_BADSTATE, - PORT_PROFILE_RESPONSE_INSUFFICIENT_RESOURCES, - PORT_PROFILE_RESPONSE_ERROR, -}; - -struct ifla_port_vsi { - __u8 vsi_mgr_id; - __u8 vsi_type_id[3]; - __u8 vsi_type_version; - __u8 pad[3]; -}; - - -/* IPoIB section */ - -enum { - IFLA_IPOIB_UNSPEC, - IFLA_IPOIB_PKEY, - IFLA_IPOIB_MODE, - IFLA_IPOIB_UMCAST, - __IFLA_IPOIB_MAX -}; - -enum { - IPOIB_MODE_DATAGRAM = 0, /* using unreliable datagram QPs */ - IPOIB_MODE_CONNECTED = 1, /* using connected QPs */ -}; - -#define IFLA_IPOIB_MAX (__IFLA_IPOIB_MAX - 1) - - -/* HSR section */ - -enum { - IFLA_HSR_UNSPEC, - IFLA_HSR_SLAVE1, - IFLA_HSR_SLAVE2, - IFLA_HSR_MULTICAST_SPEC, /* Last byte of supervision addr */ - IFLA_HSR_SUPERVISION_ADDR, /* Supervision frame multicast addr */ - IFLA_HSR_SEQ_NR, - IFLA_HSR_VERSION, /* HSR version */ - __IFLA_HSR_MAX, -}; - -#define IFLA_HSR_MAX (__IFLA_HSR_MAX - 1) - -/* STATS section */ - -struct if_stats_msg { - __u8 family; - __u8 pad1; - __u16 pad2; - __u32 ifindex; - __u32 filter_mask; -}; - -/* A stats attribute can be netdev specific or a global stat. - * For netdev stats, lets use the prefix IFLA_STATS_LINK_* - */ -enum { - IFLA_STATS_UNSPEC, /* also used as 64bit pad attribute */ - IFLA_STATS_LINK_64, - IFLA_STATS_LINK_XSTATS, - IFLA_STATS_LINK_XSTATS_SLAVE, - IFLA_STATS_LINK_OFFLOAD_XSTATS, - __IFLA_STATS_MAX, -}; - -#define IFLA_STATS_MAX (__IFLA_STATS_MAX - 1) - -#define IFLA_STATS_FILTER_BIT(ATTR) (1 << (ATTR - 1)) - -/* These are embedded into IFLA_STATS_LINK_XSTATS: - * [IFLA_STATS_LINK_XSTATS] - * -> [LINK_XSTATS_TYPE_xxx] - * -> [rtnl link type specific attributes] - */ -enum { - LINK_XSTATS_TYPE_UNSPEC, - LINK_XSTATS_TYPE_BRIDGE, - __LINK_XSTATS_TYPE_MAX -}; -#define LINK_XSTATS_TYPE_MAX (__LINK_XSTATS_TYPE_MAX - 1) - -/* These are stats embedded into IFLA_STATS_LINK_OFFLOAD_XSTATS */ -enum { - IFLA_OFFLOAD_XSTATS_UNSPEC, - IFLA_OFFLOAD_XSTATS_CPU_HIT, /* struct rtnl_link_stats64 */ - __IFLA_OFFLOAD_XSTATS_MAX -}; -#define IFLA_OFFLOAD_XSTATS_MAX (__IFLA_OFFLOAD_XSTATS_MAX - 1) - -/* XDP section */ - -enum { - IFLA_XDP_UNSPEC, - IFLA_XDP_FD, - IFLA_XDP_ATTACHED, - __IFLA_XDP_MAX, -}; - -#define IFLA_XDP_MAX (__IFLA_XDP_MAX - 1) - -#endif /* _UAPI_LINUX_IF_LINK_H */ diff --git a/src/linux/include/uapi/linux/if_packet.h b/src/linux/include/uapi/linux/if_packet.h deleted file mode 100644 index 9e7edfd..0000000 --- a/src/linux/include/uapi/linux/if_packet.h +++ /dev/null @@ -1,301 +0,0 @@ -#ifndef __LINUX_IF_PACKET_H -#define __LINUX_IF_PACKET_H - -#include - -struct sockaddr_pkt { - unsigned short spkt_family; - unsigned char spkt_device[14]; - __be16 spkt_protocol; -}; - -struct sockaddr_ll { - unsigned short sll_family; - __be16 sll_protocol; - int sll_ifindex; - unsigned short sll_hatype; - unsigned char sll_pkttype; - unsigned char sll_halen; - unsigned char sll_addr[8]; -}; - -/* Packet types */ - -#define PACKET_HOST 0 /* To us */ -#define PACKET_BROADCAST 1 /* To all */ -#define PACKET_MULTICAST 2 /* To group */ -#define PACKET_OTHERHOST 3 /* To someone else */ -#define PACKET_OUTGOING 4 /* Outgoing of any type */ -#define PACKET_LOOPBACK 5 /* MC/BRD frame looped back */ -#define PACKET_USER 6 /* To user space */ -#define PACKET_KERNEL 7 /* To kernel space */ -/* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */ -#define PACKET_FASTROUTE 6 /* Fastrouted frame */ - -/* Packet socket options */ - -#define PACKET_ADD_MEMBERSHIP 1 -#define PACKET_DROP_MEMBERSHIP 2 -#define PACKET_RECV_OUTPUT 3 -/* Value 4 is still used by obsolete turbo-packet. */ -#define PACKET_RX_RING 5 -#define PACKET_STATISTICS 6 -#define PACKET_COPY_THRESH 7 -#define PACKET_AUXDATA 8 -#define PACKET_ORIGDEV 9 -#define PACKET_VERSION 10 -#define PACKET_HDRLEN 11 -#define PACKET_RESERVE 12 -#define PACKET_TX_RING 13 -#define PACKET_LOSS 14 -#define PACKET_VNET_HDR 15 -#define PACKET_TX_TIMESTAMP 16 -#define PACKET_TIMESTAMP 17 -#define PACKET_FANOUT 18 -#define PACKET_TX_HAS_OFF 19 -#define PACKET_QDISC_BYPASS 20 -#define PACKET_ROLLOVER_STATS 21 -#define PACKET_FANOUT_DATA 22 - -#define PACKET_FANOUT_HASH 0 -#define PACKET_FANOUT_LB 1 -#define PACKET_FANOUT_CPU 2 -#define PACKET_FANOUT_ROLLOVER 3 -#define PACKET_FANOUT_RND 4 -#define PACKET_FANOUT_QM 5 -#define PACKET_FANOUT_CBPF 6 -#define PACKET_FANOUT_EBPF 7 -#define PACKET_FANOUT_FLAG_ROLLOVER 0x1000 -#define PACKET_FANOUT_FLAG_DEFRAG 0x8000 - -struct tpacket_stats { - unsigned int tp_packets; - unsigned int tp_drops; -}; - -struct tpacket_stats_v3 { - unsigned int tp_packets; - unsigned int tp_drops; - unsigned int tp_freeze_q_cnt; -}; - -struct tpacket_rollover_stats { - __aligned_u64 tp_all; - __aligned_u64 tp_huge; - __aligned_u64 tp_failed; -}; - -union tpacket_stats_u { - struct tpacket_stats stats1; - struct tpacket_stats_v3 stats3; -}; - -struct tpacket_auxdata { - __u32 tp_status; - __u32 tp_len; - __u32 tp_snaplen; - __u16 tp_mac; - __u16 tp_net; - __u16 tp_vlan_tci; - __u16 tp_vlan_tpid; -}; - -/* Rx ring - header status */ -#define TP_STATUS_KERNEL 0 -#define TP_STATUS_USER (1 << 0) -#define TP_STATUS_COPY (1 << 1) -#define TP_STATUS_LOSING (1 << 2) -#define TP_STATUS_CSUMNOTREADY (1 << 3) -#define TP_STATUS_VLAN_VALID (1 << 4) /* auxdata has valid tp_vlan_tci */ -#define TP_STATUS_BLK_TMO (1 << 5) -#define TP_STATUS_VLAN_TPID_VALID (1 << 6) /* auxdata has valid tp_vlan_tpid */ -#define TP_STATUS_CSUM_VALID (1 << 7) - -/* Tx ring - header status */ -#define TP_STATUS_AVAILABLE 0 -#define TP_STATUS_SEND_REQUEST (1 << 0) -#define TP_STATUS_SENDING (1 << 1) -#define TP_STATUS_WRONG_FORMAT (1 << 2) - -/* Rx and Tx ring - header status */ -#define TP_STATUS_TS_SOFTWARE (1 << 29) -#define TP_STATUS_TS_SYS_HARDWARE (1 << 30) /* deprecated, never set */ -#define TP_STATUS_TS_RAW_HARDWARE (1 << 31) - -/* Rx ring - feature request bits */ -#define TP_FT_REQ_FILL_RXHASH 0x1 - -struct tpacket_hdr { - unsigned long tp_status; - unsigned int tp_len; - unsigned int tp_snaplen; - unsigned short tp_mac; - unsigned short tp_net; - unsigned int tp_sec; - unsigned int tp_usec; -}; - -#define TPACKET_ALIGNMENT 16 -#define TPACKET_ALIGN(x) (((x)+TPACKET_ALIGNMENT-1)&~(TPACKET_ALIGNMENT-1)) -#define TPACKET_HDRLEN (TPACKET_ALIGN(sizeof(struct tpacket_hdr)) + sizeof(struct sockaddr_ll)) - -struct tpacket2_hdr { - __u32 tp_status; - __u32 tp_len; - __u32 tp_snaplen; - __u16 tp_mac; - __u16 tp_net; - __u32 tp_sec; - __u32 tp_nsec; - __u16 tp_vlan_tci; - __u16 tp_vlan_tpid; - __u8 tp_padding[4]; -}; - -struct tpacket_hdr_variant1 { - __u32 tp_rxhash; - __u32 tp_vlan_tci; - __u16 tp_vlan_tpid; - __u16 tp_padding; -}; - -struct tpacket3_hdr { - __u32 tp_next_offset; - __u32 tp_sec; - __u32 tp_nsec; - __u32 tp_snaplen; - __u32 tp_len; - __u32 tp_status; - __u16 tp_mac; - __u16 tp_net; - /* pkt_hdr variants */ - union { - struct tpacket_hdr_variant1 hv1; - }; - __u8 tp_padding[8]; -}; - -struct tpacket_bd_ts { - unsigned int ts_sec; - union { - unsigned int ts_usec; - unsigned int ts_nsec; - }; -}; - -struct tpacket_hdr_v1 { - __u32 block_status; - __u32 num_pkts; - __u32 offset_to_first_pkt; - - /* Number of valid bytes (including padding) - * blk_len <= tp_block_size - */ - __u32 blk_len; - - /* - * Quite a few uses of sequence number: - * 1. Make sure cache flush etc worked. - * Well, one can argue - why not use the increasing ts below? - * But look at 2. below first. - * 2. When you pass around blocks to other user space decoders, - * you can see which blk[s] is[are] outstanding etc. - * 3. Validate kernel code. - */ - __aligned_u64 seq_num; - - /* - * ts_last_pkt: - * - * Case 1. Block has 'N'(N >=1) packets and TMO'd(timed out) - * ts_last_pkt == 'time-stamp of last packet' and NOT the - * time when the timer fired and the block was closed. - * By providing the ts of the last packet we can absolutely - * guarantee that time-stamp wise, the first packet in the - * next block will never precede the last packet of the - * previous block. - * Case 2. Block has zero packets and TMO'd - * ts_last_pkt = time when the timer fired and the block - * was closed. - * Case 3. Block has 'N' packets and NO TMO. - * ts_last_pkt = time-stamp of the last pkt in the block. - * - * ts_first_pkt: - * Is always the time-stamp when the block was opened. - * Case a) ZERO packets - * No packets to deal with but atleast you know the - * time-interval of this block. - * Case b) Non-zero packets - * Use the ts of the first packet in the block. - * - */ - struct tpacket_bd_ts ts_first_pkt, ts_last_pkt; -}; - -union tpacket_bd_header_u { - struct tpacket_hdr_v1 bh1; -}; - -struct tpacket_block_desc { - __u32 version; - __u32 offset_to_priv; - union tpacket_bd_header_u hdr; -}; - -#define TPACKET2_HDRLEN (TPACKET_ALIGN(sizeof(struct tpacket2_hdr)) + sizeof(struct sockaddr_ll)) -#define TPACKET3_HDRLEN (TPACKET_ALIGN(sizeof(struct tpacket3_hdr)) + sizeof(struct sockaddr_ll)) - -enum tpacket_versions { - TPACKET_V1, - TPACKET_V2, - TPACKET_V3 -}; - -/* - Frame structure: - - - Start. Frame must be aligned to TPACKET_ALIGNMENT=16 - - struct tpacket_hdr - - pad to TPACKET_ALIGNMENT=16 - - struct sockaddr_ll - - Gap, chosen so that packet data (Start+tp_net) alignes to TPACKET_ALIGNMENT=16 - - Start+tp_mac: [ Optional MAC header ] - - Start+tp_net: Packet data, aligned to TPACKET_ALIGNMENT=16. - - Pad to align to TPACKET_ALIGNMENT=16 - */ - -struct tpacket_req { - unsigned int tp_block_size; /* Minimal size of contiguous block */ - unsigned int tp_block_nr; /* Number of blocks */ - unsigned int tp_frame_size; /* Size of frame */ - unsigned int tp_frame_nr; /* Total number of frames */ -}; - -struct tpacket_req3 { - unsigned int tp_block_size; /* Minimal size of contiguous block */ - unsigned int tp_block_nr; /* Number of blocks */ - unsigned int tp_frame_size; /* Size of frame */ - unsigned int tp_frame_nr; /* Total number of frames */ - unsigned int tp_retire_blk_tov; /* timeout in msecs */ - unsigned int tp_sizeof_priv; /* offset to private data area */ - unsigned int tp_feature_req_word; -}; - -union tpacket_req_u { - struct tpacket_req req; - struct tpacket_req3 req3; -}; - -struct packet_mreq { - int mr_ifindex; - unsigned short mr_type; - unsigned short mr_alen; - unsigned char mr_address[8]; -}; - -#define PACKET_MR_MULTICAST 0 -#define PACKET_MR_PROMISC 1 -#define PACKET_MR_ALLMULTI 2 -#define PACKET_MR_UNICAST 3 - -#endif diff --git a/src/linux/include/uapi/linux/if_pppol2tp.h b/src/linux/include/uapi/linux/if_pppol2tp.h deleted file mode 100644 index 4bd1f55..0000000 --- a/src/linux/include/uapi/linux/if_pppol2tp.h +++ /dev/null @@ -1,105 +0,0 @@ -/*************************************************************************** - * Linux PPP over L2TP (PPPoL2TP) Socket Implementation (RFC 2661) - * - * This file supplies definitions required by the PPP over L2TP driver - * (l2tp_ppp.c). All version information wrt this file is located in l2tp_ppp.c - * - * License: - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#ifndef _UAPI__LINUX_IF_PPPOL2TP_H -#define _UAPI__LINUX_IF_PPPOL2TP_H - -#include -#include -#include - -/* Structure used to connect() the socket to a particular tunnel UDP - * socket over IPv4. - */ -struct pppol2tp_addr { - __kernel_pid_t pid; /* pid that owns the fd. - * 0 => current */ - int fd; /* FD of UDP socket to use */ - - struct sockaddr_in addr; /* IP address and port to send to */ - - __u16 s_tunnel, s_session; /* For matching incoming packets */ - __u16 d_tunnel, d_session; /* For sending outgoing packets */ -}; - -/* Structure used to connect() the socket to a particular tunnel UDP - * socket over IPv6. - */ -struct pppol2tpin6_addr { - __kernel_pid_t pid; /* pid that owns the fd. - * 0 => current */ - int fd; /* FD of UDP socket to use */ - - __u16 s_tunnel, s_session; /* For matching incoming packets */ - __u16 d_tunnel, d_session; /* For sending outgoing packets */ - - struct sockaddr_in6 addr; /* IP address and port to send to */ -}; - -/* The L2TPv3 protocol changes tunnel and session ids from 16 to 32 - * bits. So we need a different sockaddr structure. - */ -struct pppol2tpv3_addr { - __kernel_pid_t pid; /* pid that owns the fd. - * 0 => current */ - int fd; /* FD of UDP or IP socket to use */ - - struct sockaddr_in addr; /* IP address and port to send to */ - - __u32 s_tunnel, s_session; /* For matching incoming packets */ - __u32 d_tunnel, d_session; /* For sending outgoing packets */ -}; - -struct pppol2tpv3in6_addr { - __kernel_pid_t pid; /* pid that owns the fd. - * 0 => current */ - int fd; /* FD of UDP or IP socket to use */ - - __u32 s_tunnel, s_session; /* For matching incoming packets */ - __u32 d_tunnel, d_session; /* For sending outgoing packets */ - - struct sockaddr_in6 addr; /* IP address and port to send to */ -}; - -/* Socket options: - * DEBUG - bitmask of debug message categories - * SENDSEQ - 0 => don't send packets with sequence numbers - * 1 => send packets with sequence numbers - * RECVSEQ - 0 => receive packet sequence numbers are optional - * 1 => drop receive packets without sequence numbers - * LNSMODE - 0 => act as LAC. - * 1 => act as LNS. - * REORDERTO - reorder timeout (in millisecs). If 0, don't try to reorder. - */ -enum { - PPPOL2TP_SO_DEBUG = 1, - PPPOL2TP_SO_RECVSEQ = 2, - PPPOL2TP_SO_SENDSEQ = 3, - PPPOL2TP_SO_LNSMODE = 4, - PPPOL2TP_SO_REORDERTO = 5, -}; - -/* Debug message categories for the DEBUG socket option */ -enum { - PPPOL2TP_MSG_DEBUG = (1 << 0), /* verbose debug (if - * compiled in) */ - PPPOL2TP_MSG_CONTROL = (1 << 1), /* userspace - kernel - * interface */ - PPPOL2TP_MSG_SEQ = (1 << 2), /* sequence numbers */ - PPPOL2TP_MSG_DATA = (1 << 3), /* data packets */ -}; - - - -#endif /* _UAPI__LINUX_IF_PPPOL2TP_H */ diff --git a/src/linux/include/uapi/linux/if_pppox.h b/src/linux/include/uapi/linux/if_pppox.h deleted file mode 100644 index d37bbb1..0000000 --- a/src/linux/include/uapi/linux/if_pppox.h +++ /dev/null @@ -1,159 +0,0 @@ -/*************************************************************************** - * Linux PPP over X - Generic PPP transport layer sockets - * Linux PPP over Ethernet (PPPoE) Socket Implementation (RFC 2516) - * - * This file supplies definitions required by the PPP over Ethernet driver - * (pppox.c). All version information wrt this file is located in pppox.c - * - * License: - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#ifndef _UAPI__LINUX_IF_PPPOX_H -#define _UAPI__LINUX_IF_PPPOX_H - - -#include -#include - -#include -#include -#include -#include -#include -#include - -/* For user-space programs to pick up these definitions - * which they wouldn't get otherwise without defining __KERNEL__ - */ -#ifndef AF_PPPOX -#define AF_PPPOX 24 -#define PF_PPPOX AF_PPPOX -#endif /* !(AF_PPPOX) */ - -/************************************************************************ - * PPPoE addressing definition - */ -typedef __be16 sid_t; -struct pppoe_addr { - sid_t sid; /* Session identifier */ - unsigned char remote[ETH_ALEN]; /* Remote address */ - char dev[IFNAMSIZ]; /* Local device to use */ -}; - -/************************************************************************ - * PPTP addressing definition - */ -struct pptp_addr { - __u16 call_id; - struct in_addr sin_addr; -}; - -/************************************************************************ - * Protocols supported by AF_PPPOX - */ -#define PX_PROTO_OE 0 /* Currently just PPPoE */ -#define PX_PROTO_OL2TP 1 /* Now L2TP also */ -#define PX_PROTO_PPTP 2 -#define PX_MAX_PROTO 3 - -struct sockaddr_pppox { - __kernel_sa_family_t sa_family; /* address family, AF_PPPOX */ - unsigned int sa_protocol; /* protocol identifier */ - union { - struct pppoe_addr pppoe; - struct pptp_addr pptp; - } sa_addr; -} __packed; - -/* The use of the above union isn't viable because the size of this - * struct must stay fixed over time -- applications use sizeof(struct - * sockaddr_pppox) to fill it. We use a protocol specific sockaddr - * type instead. - */ -struct sockaddr_pppol2tp { - __kernel_sa_family_t sa_family; /* address family, AF_PPPOX */ - unsigned int sa_protocol; /* protocol identifier */ - struct pppol2tp_addr pppol2tp; -} __packed; - -struct sockaddr_pppol2tpin6 { - __kernel_sa_family_t sa_family; /* address family, AF_PPPOX */ - unsigned int sa_protocol; /* protocol identifier */ - struct pppol2tpin6_addr pppol2tp; -} __packed; - -/* The L2TPv3 protocol changes tunnel and session ids from 16 to 32 - * bits. So we need a different sockaddr structure. - */ -struct sockaddr_pppol2tpv3 { - __kernel_sa_family_t sa_family; /* address family, AF_PPPOX */ - unsigned int sa_protocol; /* protocol identifier */ - struct pppol2tpv3_addr pppol2tp; -} __packed; - -struct sockaddr_pppol2tpv3in6 { - __kernel_sa_family_t sa_family; /* address family, AF_PPPOX */ - unsigned int sa_protocol; /* protocol identifier */ - struct pppol2tpv3in6_addr pppol2tp; -} __packed; - -/********************************************************************* - * - * ioctl interface for defining forwarding of connections - * - ********************************************************************/ - -#define PPPOEIOCSFWD _IOW(0xB1 ,0, size_t) -#define PPPOEIOCDFWD _IO(0xB1 ,1) -/*#define PPPOEIOCGFWD _IOWR(0xB1,2, size_t)*/ - -/* Codes to identify message types */ -#define PADI_CODE 0x09 -#define PADO_CODE 0x07 -#define PADR_CODE 0x19 -#define PADS_CODE 0x65 -#define PADT_CODE 0xa7 -struct pppoe_tag { - __be16 tag_type; - __be16 tag_len; - char tag_data[0]; -} __attribute__ ((packed)); - -/* Tag identifiers */ -#define PTT_EOL __cpu_to_be16(0x0000) -#define PTT_SRV_NAME __cpu_to_be16(0x0101) -#define PTT_AC_NAME __cpu_to_be16(0x0102) -#define PTT_HOST_UNIQ __cpu_to_be16(0x0103) -#define PTT_AC_COOKIE __cpu_to_be16(0x0104) -#define PTT_VENDOR __cpu_to_be16(0x0105) -#define PTT_RELAY_SID __cpu_to_be16(0x0110) -#define PTT_SRV_ERR __cpu_to_be16(0x0201) -#define PTT_SYS_ERR __cpu_to_be16(0x0202) -#define PTT_GEN_ERR __cpu_to_be16(0x0203) - -struct pppoe_hdr { -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 type : 4; - __u8 ver : 4; -#elif defined(__BIG_ENDIAN_BITFIELD) - __u8 ver : 4; - __u8 type : 4; -#else -#error "Please fix " -#endif - __u8 code; - __be16 sid; - __be16 length; - struct pppoe_tag tag[0]; -} __packed; - -/* Length of entire PPPoE + PPP header */ -#define PPPOE_SES_HLEN 8 - - -#endif /* _UAPI__LINUX_IF_PPPOX_H */ diff --git a/src/linux/include/uapi/linux/if_tun.h b/src/linux/include/uapi/linux/if_tun.h deleted file mode 100644 index 3cb5e1d..0000000 --- a/src/linux/include/uapi/linux/if_tun.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Universal TUN/TAP device driver. - * Copyright (C) 1999-2000 Maxim Krasnyansky - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _UAPI__IF_TUN_H -#define _UAPI__IF_TUN_H - -#include -#include -#include - -/* Read queue size */ -#define TUN_READQ_SIZE 500 -/* TUN device type flags: deprecated. Use IFF_TUN/IFF_TAP instead. */ -#define TUN_TUN_DEV IFF_TUN -#define TUN_TAP_DEV IFF_TAP -#define TUN_TYPE_MASK 0x000f - -/* Ioctl defines */ -#define TUNSETNOCSUM _IOW('T', 200, int) -#define TUNSETDEBUG _IOW('T', 201, int) -#define TUNSETIFF _IOW('T', 202, int) -#define TUNSETPERSIST _IOW('T', 203, int) -#define TUNSETOWNER _IOW('T', 204, int) -#define TUNSETLINK _IOW('T', 205, int) -#define TUNSETGROUP _IOW('T', 206, int) -#define TUNGETFEATURES _IOR('T', 207, unsigned int) -#define TUNSETOFFLOAD _IOW('T', 208, unsigned int) -#define TUNSETTXFILTER _IOW('T', 209, unsigned int) -#define TUNGETIFF _IOR('T', 210, unsigned int) -#define TUNGETSNDBUF _IOR('T', 211, int) -#define TUNSETSNDBUF _IOW('T', 212, int) -#define TUNATTACHFILTER _IOW('T', 213, struct sock_fprog) -#define TUNDETACHFILTER _IOW('T', 214, struct sock_fprog) -#define TUNGETVNETHDRSZ _IOR('T', 215, int) -#define TUNSETVNETHDRSZ _IOW('T', 216, int) -#define TUNSETQUEUE _IOW('T', 217, int) -#define TUNSETIFINDEX _IOW('T', 218, unsigned int) -#define TUNGETFILTER _IOR('T', 219, struct sock_fprog) -#define TUNSETVNETLE _IOW('T', 220, int) -#define TUNGETVNETLE _IOR('T', 221, int) -/* The TUNSETVNETBE and TUNGETVNETBE ioctls are for cross-endian support on - * little-endian hosts. Not all kernel configurations support them, but all - * configurations that support SET also support GET. - */ -#define TUNSETVNETBE _IOW('T', 222, int) -#define TUNGETVNETBE _IOR('T', 223, int) - -/* TUNSETIFF ifr flags */ -#define IFF_TUN 0x0001 -#define IFF_TAP 0x0002 -#define IFF_NO_PI 0x1000 -/* This flag has no real effect */ -#define IFF_ONE_QUEUE 0x2000 -#define IFF_VNET_HDR 0x4000 -#define IFF_TUN_EXCL 0x8000 -#define IFF_MULTI_QUEUE 0x0100 -#define IFF_ATTACH_QUEUE 0x0200 -#define IFF_DETACH_QUEUE 0x0400 -/* read-only flag */ -#define IFF_PERSIST 0x0800 -#define IFF_NOFILTER 0x1000 - -/* Socket options */ -#define TUN_TX_TIMESTAMP 1 - -/* Features for GSO (TUNSETOFFLOAD). */ -#define TUN_F_CSUM 0x01 /* You can hand me unchecksummed packets. */ -#define TUN_F_TSO4 0x02 /* I can handle TSO for IPv4 packets */ -#define TUN_F_TSO6 0x04 /* I can handle TSO for IPv6 packets */ -#define TUN_F_TSO_ECN 0x08 /* I can handle TSO with ECN bits. */ -#define TUN_F_UFO 0x10 /* I can handle UFO packets */ - -/* Protocol info prepended to the packets (when IFF_NO_PI is not set) */ -#define TUN_PKT_STRIP 0x0001 -struct tun_pi { - __u16 flags; - __be16 proto; -}; - -/* - * Filter spec (used for SETXXFILTER ioctls) - * This stuff is applicable only to the TAP (Ethernet) devices. - * If the count is zero the filter is disabled and the driver accepts - * all packets (promisc mode). - * If the filter is enabled in order to accept broadcast packets - * broadcast addr must be explicitly included in the addr list. - */ -#define TUN_FLT_ALLMULTI 0x0001 /* Accept all multicast packets */ -struct tun_filter { - __u16 flags; /* TUN_FLT_ flags see above */ - __u16 count; /* Number of addresses */ - __u8 addr[0][ETH_ALEN]; -}; - -#endif /* _UAPI__IF_TUN_H */ diff --git a/src/linux/include/uapi/linux/if_tunnel.h b/src/linux/include/uapi/linux/if_tunnel.h deleted file mode 100644 index 92f3c86..0000000 --- a/src/linux/include/uapi/linux/if_tunnel.h +++ /dev/null @@ -1,154 +0,0 @@ -#ifndef _UAPI_IF_TUNNEL_H_ -#define _UAPI_IF_TUNNEL_H_ - -#include -#include -#include -#include -#include - - -#define SIOCGETTUNNEL (SIOCDEVPRIVATE + 0) -#define SIOCADDTUNNEL (SIOCDEVPRIVATE + 1) -#define SIOCDELTUNNEL (SIOCDEVPRIVATE + 2) -#define SIOCCHGTUNNEL (SIOCDEVPRIVATE + 3) -#define SIOCGETPRL (SIOCDEVPRIVATE + 4) -#define SIOCADDPRL (SIOCDEVPRIVATE + 5) -#define SIOCDELPRL (SIOCDEVPRIVATE + 6) -#define SIOCCHGPRL (SIOCDEVPRIVATE + 7) -#define SIOCGET6RD (SIOCDEVPRIVATE + 8) -#define SIOCADD6RD (SIOCDEVPRIVATE + 9) -#define SIOCDEL6RD (SIOCDEVPRIVATE + 10) -#define SIOCCHG6RD (SIOCDEVPRIVATE + 11) - -#define GRE_CSUM __cpu_to_be16(0x8000) -#define GRE_ROUTING __cpu_to_be16(0x4000) -#define GRE_KEY __cpu_to_be16(0x2000) -#define GRE_SEQ __cpu_to_be16(0x1000) -#define GRE_STRICT __cpu_to_be16(0x0800) -#define GRE_REC __cpu_to_be16(0x0700) -#define GRE_ACK __cpu_to_be16(0x0080) -#define GRE_FLAGS __cpu_to_be16(0x0078) -#define GRE_VERSION __cpu_to_be16(0x0007) - -#define GRE_IS_CSUM(f) ((f) & GRE_CSUM) -#define GRE_IS_ROUTING(f) ((f) & GRE_ROUTING) -#define GRE_IS_KEY(f) ((f) & GRE_KEY) -#define GRE_IS_SEQ(f) ((f) & GRE_SEQ) -#define GRE_IS_STRICT(f) ((f) & GRE_STRICT) -#define GRE_IS_REC(f) ((f) & GRE_REC) -#define GRE_IS_ACK(f) ((f) & GRE_ACK) - -#define GRE_VERSION_0 __cpu_to_be16(0x0000) -#define GRE_VERSION_1 __cpu_to_be16(0x0001) -#define GRE_PROTO_PPP __cpu_to_be16(0x880b) -#define GRE_PPTP_KEY_MASK __cpu_to_be32(0xffff) - -struct ip_tunnel_parm { - char name[IFNAMSIZ]; - int link; - __be16 i_flags; - __be16 o_flags; - __be32 i_key; - __be32 o_key; - struct iphdr iph; -}; - -enum { - IFLA_IPTUN_UNSPEC, - IFLA_IPTUN_LINK, - IFLA_IPTUN_LOCAL, - IFLA_IPTUN_REMOTE, - IFLA_IPTUN_TTL, - IFLA_IPTUN_TOS, - IFLA_IPTUN_ENCAP_LIMIT, - IFLA_IPTUN_FLOWINFO, - IFLA_IPTUN_FLAGS, - IFLA_IPTUN_PROTO, - IFLA_IPTUN_PMTUDISC, - IFLA_IPTUN_6RD_PREFIX, - IFLA_IPTUN_6RD_RELAY_PREFIX, - IFLA_IPTUN_6RD_PREFIXLEN, - IFLA_IPTUN_6RD_RELAY_PREFIXLEN, - IFLA_IPTUN_ENCAP_TYPE, - IFLA_IPTUN_ENCAP_FLAGS, - IFLA_IPTUN_ENCAP_SPORT, - IFLA_IPTUN_ENCAP_DPORT, - IFLA_IPTUN_COLLECT_METADATA, - __IFLA_IPTUN_MAX, -}; -#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1) - -enum tunnel_encap_types { - TUNNEL_ENCAP_NONE, - TUNNEL_ENCAP_FOU, - TUNNEL_ENCAP_GUE, -}; - -#define TUNNEL_ENCAP_FLAG_CSUM (1<<0) -#define TUNNEL_ENCAP_FLAG_CSUM6 (1<<1) -#define TUNNEL_ENCAP_FLAG_REMCSUM (1<<2) - -/* SIT-mode i_flags */ -#define SIT_ISATAP 0x0001 - -struct ip_tunnel_prl { - __be32 addr; - __u16 flags; - __u16 __reserved; - __u32 datalen; - __u32 __reserved2; - /* data follows */ -}; - -/* PRL flags */ -#define PRL_DEFAULT 0x0001 - -struct ip_tunnel_6rd { - struct in6_addr prefix; - __be32 relay_prefix; - __u16 prefixlen; - __u16 relay_prefixlen; -}; - -enum { - IFLA_GRE_UNSPEC, - IFLA_GRE_LINK, - IFLA_GRE_IFLAGS, - IFLA_GRE_OFLAGS, - IFLA_GRE_IKEY, - IFLA_GRE_OKEY, - IFLA_GRE_LOCAL, - IFLA_GRE_REMOTE, - IFLA_GRE_TTL, - IFLA_GRE_TOS, - IFLA_GRE_PMTUDISC, - IFLA_GRE_ENCAP_LIMIT, - IFLA_GRE_FLOWINFO, - IFLA_GRE_FLAGS, - IFLA_GRE_ENCAP_TYPE, - IFLA_GRE_ENCAP_FLAGS, - IFLA_GRE_ENCAP_SPORT, - IFLA_GRE_ENCAP_DPORT, - IFLA_GRE_COLLECT_METADATA, - IFLA_GRE_IGNORE_DF, - __IFLA_GRE_MAX, -}; - -#define IFLA_GRE_MAX (__IFLA_GRE_MAX - 1) - -/* VTI-mode i_flags */ -#define VTI_ISVTI ((__force __be16)0x0001) - -enum { - IFLA_VTI_UNSPEC, - IFLA_VTI_LINK, - IFLA_VTI_IKEY, - IFLA_VTI_OKEY, - IFLA_VTI_LOCAL, - IFLA_VTI_REMOTE, - __IFLA_VTI_MAX, -}; - -#define IFLA_VTI_MAX (__IFLA_VTI_MAX - 1) -#endif /* _UAPI_IF_TUNNEL_H_ */ diff --git a/src/linux/include/uapi/linux/if_vlan.h b/src/linux/include/uapi/linux/if_vlan.h deleted file mode 100644 index 7e5e6b3..0000000 --- a/src/linux/include/uapi/linux/if_vlan.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * VLAN An implementation of 802.1Q VLAN tagging. - * - * Authors: Ben Greear - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#ifndef _UAPI_LINUX_IF_VLAN_H_ -#define _UAPI_LINUX_IF_VLAN_H_ - - -/* VLAN IOCTLs are found in sockios.h */ - -/* Passed in vlan_ioctl_args structure to determine behaviour. */ -enum vlan_ioctl_cmds { - ADD_VLAN_CMD, - DEL_VLAN_CMD, - SET_VLAN_INGRESS_PRIORITY_CMD, - SET_VLAN_EGRESS_PRIORITY_CMD, - GET_VLAN_INGRESS_PRIORITY_CMD, - GET_VLAN_EGRESS_PRIORITY_CMD, - SET_VLAN_NAME_TYPE_CMD, - SET_VLAN_FLAG_CMD, - GET_VLAN_REALDEV_NAME_CMD, /* If this works, you know it's a VLAN device, btw */ - GET_VLAN_VID_CMD /* Get the VID of this VLAN (specified by name) */ -}; - -enum vlan_flags { - VLAN_FLAG_REORDER_HDR = 0x1, - VLAN_FLAG_GVRP = 0x2, - VLAN_FLAG_LOOSE_BINDING = 0x4, - VLAN_FLAG_MVRP = 0x8, -}; - -enum vlan_name_types { - VLAN_NAME_TYPE_PLUS_VID, /* Name will look like: vlan0005 */ - VLAN_NAME_TYPE_RAW_PLUS_VID, /* name will look like: eth1.0005 */ - VLAN_NAME_TYPE_PLUS_VID_NO_PAD, /* Name will look like: vlan5 */ - VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, /* Name will look like: eth0.5 */ - VLAN_NAME_TYPE_HIGHEST -}; - -struct vlan_ioctl_args { - int cmd; /* Should be one of the vlan_ioctl_cmds enum above. */ - char device1[24]; - - union { - char device2[24]; - int VID; - unsigned int skb_priority; - unsigned int name_type; - unsigned int bind_type; - unsigned int flag; /* Matches vlan_dev_priv flags */ - } u; - - short vlan_qos; -}; - -#endif /* _UAPI_LINUX_IF_VLAN_H_ */ diff --git a/src/linux/include/uapi/linux/igmp.h b/src/linux/include/uapi/linux/igmp.h deleted file mode 100644 index ccbb32a..0000000 --- a/src/linux/include/uapi/linux/igmp.h +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Linux NET3: Internet Group Management Protocol [IGMP] - * - * Authors: - * Alan Cox - * - * Extended to talk the BSD extended IGMP protocol of mrouted 3.6 - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _UAPI_LINUX_IGMP_H -#define _UAPI_LINUX_IGMP_H - -#include -#include - -/* - * IGMP protocol structures - */ - -/* - * Header in on cable format - */ - -struct igmphdr { - __u8 type; - __u8 code; /* For newer IGMP */ - __sum16 csum; - __be32 group; -}; - -/* V3 group record types [grec_type] */ -#define IGMPV3_MODE_IS_INCLUDE 1 -#define IGMPV3_MODE_IS_EXCLUDE 2 -#define IGMPV3_CHANGE_TO_INCLUDE 3 -#define IGMPV3_CHANGE_TO_EXCLUDE 4 -#define IGMPV3_ALLOW_NEW_SOURCES 5 -#define IGMPV3_BLOCK_OLD_SOURCES 6 - -struct igmpv3_grec { - __u8 grec_type; - __u8 grec_auxwords; - __be16 grec_nsrcs; - __be32 grec_mca; - __be32 grec_src[0]; -}; - -struct igmpv3_report { - __u8 type; - __u8 resv1; - __be16 csum; - __be16 resv2; - __be16 ngrec; - struct igmpv3_grec grec[0]; -}; - -struct igmpv3_query { - __u8 type; - __u8 code; - __be16 csum; - __be32 group; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 qrv:3, - suppress:1, - resv:4; -#elif defined(__BIG_ENDIAN_BITFIELD) - __u8 resv:4, - suppress:1, - qrv:3; -#else -#error "Please fix " -#endif - __u8 qqic; - __be16 nsrcs; - __be32 srcs[0]; -}; - -#define IGMP_HOST_MEMBERSHIP_QUERY 0x11 /* From RFC1112 */ -#define IGMP_HOST_MEMBERSHIP_REPORT 0x12 /* Ditto */ -#define IGMP_DVMRP 0x13 /* DVMRP routing */ -#define IGMP_PIM 0x14 /* PIM routing */ -#define IGMP_TRACE 0x15 -#define IGMPV2_HOST_MEMBERSHIP_REPORT 0x16 /* V2 version of 0x12 */ -#define IGMP_HOST_LEAVE_MESSAGE 0x17 -#define IGMPV3_HOST_MEMBERSHIP_REPORT 0x22 /* V3 version of 0x12 */ - -#define IGMP_MTRACE_RESP 0x1e -#define IGMP_MTRACE 0x1f - - -/* - * Use the BSD names for these for compatibility - */ - -#define IGMP_DELAYING_MEMBER 0x01 -#define IGMP_IDLE_MEMBER 0x02 -#define IGMP_LAZY_MEMBER 0x03 -#define IGMP_SLEEPING_MEMBER 0x04 -#define IGMP_AWAKENING_MEMBER 0x05 - -#define IGMP_MINLEN 8 - -#define IGMP_MAX_HOST_REPORT_DELAY 10 /* max delay for response to */ - /* query (in seconds) */ - -#define IGMP_TIMER_SCALE 10 /* denotes that the igmphdr->timer field */ - /* specifies time in 10th of seconds */ - -#define IGMP_AGE_THRESHOLD 400 /* If this host don't hear any IGMP V1 */ - /* message in this period of time, */ - /* revert to IGMP v2 router. */ - -#define IGMP_ALL_HOSTS htonl(0xE0000001L) -#define IGMP_ALL_ROUTER htonl(0xE0000002L) -#define IGMPV3_ALL_MCR htonl(0xE0000016L) -#define IGMP_LOCAL_GROUP htonl(0xE0000000L) -#define IGMP_LOCAL_GROUP_MASK htonl(0xFFFFFF00L) - -/* - * struct for keeping the multicast list in - */ - -#endif /* _UAPI_LINUX_IGMP_H */ diff --git a/src/linux/include/uapi/linux/in.h b/src/linux/include/uapi/linux/in.h deleted file mode 100644 index eaf9491..0000000 --- a/src/linux/include/uapi/linux/in.h +++ /dev/null @@ -1,299 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions of the Internet Protocol. - * - * Version: @(#)in.h 1.0.1 04/21/93 - * - * Authors: Original taken from the GNU Project file. - * Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _UAPI_LINUX_IN_H -#define _UAPI_LINUX_IN_H - -#include -#include -#include - -#if __UAPI_DEF_IN_IPPROTO -/* Standard well-defined IP protocols. */ -enum { - IPPROTO_IP = 0, /* Dummy protocol for TCP */ -#define IPPROTO_IP IPPROTO_IP - IPPROTO_ICMP = 1, /* Internet Control Message Protocol */ -#define IPPROTO_ICMP IPPROTO_ICMP - IPPROTO_IGMP = 2, /* Internet Group Management Protocol */ -#define IPPROTO_IGMP IPPROTO_IGMP - IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */ -#define IPPROTO_IPIP IPPROTO_IPIP - IPPROTO_TCP = 6, /* Transmission Control Protocol */ -#define IPPROTO_TCP IPPROTO_TCP - IPPROTO_EGP = 8, /* Exterior Gateway Protocol */ -#define IPPROTO_EGP IPPROTO_EGP - IPPROTO_PUP = 12, /* PUP protocol */ -#define IPPROTO_PUP IPPROTO_PUP - IPPROTO_UDP = 17, /* User Datagram Protocol */ -#define IPPROTO_UDP IPPROTO_UDP - IPPROTO_IDP = 22, /* XNS IDP protocol */ -#define IPPROTO_IDP IPPROTO_IDP - IPPROTO_TP = 29, /* SO Transport Protocol Class 4 */ -#define IPPROTO_TP IPPROTO_TP - IPPROTO_DCCP = 33, /* Datagram Congestion Control Protocol */ -#define IPPROTO_DCCP IPPROTO_DCCP - IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */ -#define IPPROTO_IPV6 IPPROTO_IPV6 - IPPROTO_RSVP = 46, /* RSVP Protocol */ -#define IPPROTO_RSVP IPPROTO_RSVP - IPPROTO_GRE = 47, /* Cisco GRE tunnels (rfc 1701,1702) */ -#define IPPROTO_GRE IPPROTO_GRE - IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */ -#define IPPROTO_ESP IPPROTO_ESP - IPPROTO_AH = 51, /* Authentication Header protocol */ -#define IPPROTO_AH IPPROTO_AH - IPPROTO_MTP = 92, /* Multicast Transport Protocol */ -#define IPPROTO_MTP IPPROTO_MTP - IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */ -#define IPPROTO_BEETPH IPPROTO_BEETPH - IPPROTO_ENCAP = 98, /* Encapsulation Header */ -#define IPPROTO_ENCAP IPPROTO_ENCAP - IPPROTO_PIM = 103, /* Protocol Independent Multicast */ -#define IPPROTO_PIM IPPROTO_PIM - IPPROTO_COMP = 108, /* Compression Header Protocol */ -#define IPPROTO_COMP IPPROTO_COMP - IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */ -#define IPPROTO_SCTP IPPROTO_SCTP - IPPROTO_UDPLITE = 136, /* UDP-Lite (RFC 3828) */ -#define IPPROTO_UDPLITE IPPROTO_UDPLITE - IPPROTO_MPLS = 137, /* MPLS in IP (RFC 4023) */ -#define IPPROTO_MPLS IPPROTO_MPLS - IPPROTO_RAW = 255, /* Raw IP packets */ -#define IPPROTO_RAW IPPROTO_RAW - IPPROTO_MAX -}; -#endif - -#if __UAPI_DEF_IN_ADDR -/* Internet address. */ -struct in_addr { - __be32 s_addr; -}; -#endif - -#define IP_TOS 1 -#define IP_TTL 2 -#define IP_HDRINCL 3 -#define IP_OPTIONS 4 -#define IP_ROUTER_ALERT 5 -#define IP_RECVOPTS 6 -#define IP_RETOPTS 7 -#define IP_PKTINFO 8 -#define IP_PKTOPTIONS 9 -#define IP_MTU_DISCOVER 10 -#define IP_RECVERR 11 -#define IP_RECVTTL 12 -#define IP_RECVTOS 13 -#define IP_MTU 14 -#define IP_FREEBIND 15 -#define IP_IPSEC_POLICY 16 -#define IP_XFRM_POLICY 17 -#define IP_PASSSEC 18 -#define IP_TRANSPARENT 19 - -/* BSD compatibility */ -#define IP_RECVRETOPTS IP_RETOPTS - -/* TProxy original addresses */ -#define IP_ORIGDSTADDR 20 -#define IP_RECVORIGDSTADDR IP_ORIGDSTADDR - -#define IP_MINTTL 21 -#define IP_NODEFRAG 22 -#define IP_CHECKSUM 23 -#define IP_BIND_ADDRESS_NO_PORT 24 - -/* IP_MTU_DISCOVER values */ -#define IP_PMTUDISC_DONT 0 /* Never send DF frames */ -#define IP_PMTUDISC_WANT 1 /* Use per route hints */ -#define IP_PMTUDISC_DO 2 /* Always DF */ -#define IP_PMTUDISC_PROBE 3 /* Ignore dst pmtu */ -/* Always use interface mtu (ignores dst pmtu) but don't set DF flag. - * Also incoming ICMP frag_needed notifications will be ignored on - * this socket to prevent accepting spoofed ones. - */ -#define IP_PMTUDISC_INTERFACE 4 -/* weaker version of IP_PMTUDISC_INTERFACE, which allos packets to get - * fragmented if they exeed the interface mtu - */ -#define IP_PMTUDISC_OMIT 5 - -#define IP_MULTICAST_IF 32 -#define IP_MULTICAST_TTL 33 -#define IP_MULTICAST_LOOP 34 -#define IP_ADD_MEMBERSHIP 35 -#define IP_DROP_MEMBERSHIP 36 -#define IP_UNBLOCK_SOURCE 37 -#define IP_BLOCK_SOURCE 38 -#define IP_ADD_SOURCE_MEMBERSHIP 39 -#define IP_DROP_SOURCE_MEMBERSHIP 40 -#define IP_MSFILTER 41 -#define MCAST_JOIN_GROUP 42 -#define MCAST_BLOCK_SOURCE 43 -#define MCAST_UNBLOCK_SOURCE 44 -#define MCAST_LEAVE_GROUP 45 -#define MCAST_JOIN_SOURCE_GROUP 46 -#define MCAST_LEAVE_SOURCE_GROUP 47 -#define MCAST_MSFILTER 48 -#define IP_MULTICAST_ALL 49 -#define IP_UNICAST_IF 50 - -#define MCAST_EXCLUDE 0 -#define MCAST_INCLUDE 1 - -/* These need to appear somewhere around here */ -#define IP_DEFAULT_MULTICAST_TTL 1 -#define IP_DEFAULT_MULTICAST_LOOP 1 - -/* Request struct for multicast socket ops */ - -#if __UAPI_DEF_IP_MREQ -struct ip_mreq { - struct in_addr imr_multiaddr; /* IP multicast address of group */ - struct in_addr imr_interface; /* local IP address of interface */ -}; - -struct ip_mreqn { - struct in_addr imr_multiaddr; /* IP multicast address of group */ - struct in_addr imr_address; /* local IP address of interface */ - int imr_ifindex; /* Interface index */ -}; - -struct ip_mreq_source { - __be32 imr_multiaddr; - __be32 imr_interface; - __be32 imr_sourceaddr; -}; - -struct ip_msfilter { - __be32 imsf_multiaddr; - __be32 imsf_interface; - __u32 imsf_fmode; - __u32 imsf_numsrc; - __be32 imsf_slist[1]; -}; - -#define IP_MSFILTER_SIZE(numsrc) \ - (sizeof(struct ip_msfilter) - sizeof(__u32) \ - + (numsrc) * sizeof(__u32)) - -struct group_req { - __u32 gr_interface; /* interface index */ - struct __kernel_sockaddr_storage gr_group; /* group address */ -}; - -struct group_source_req { - __u32 gsr_interface; /* interface index */ - struct __kernel_sockaddr_storage gsr_group; /* group address */ - struct __kernel_sockaddr_storage gsr_source; /* source address */ -}; - -struct group_filter { - __u32 gf_interface; /* interface index */ - struct __kernel_sockaddr_storage gf_group; /* multicast address */ - __u32 gf_fmode; /* filter mode */ - __u32 gf_numsrc; /* number of sources */ - struct __kernel_sockaddr_storage gf_slist[1]; /* interface index */ -}; - -#define GROUP_FILTER_SIZE(numsrc) \ - (sizeof(struct group_filter) - sizeof(struct __kernel_sockaddr_storage) \ - + (numsrc) * sizeof(struct __kernel_sockaddr_storage)) -#endif - -#if __UAPI_DEF_IN_PKTINFO -struct in_pktinfo { - int ipi_ifindex; - struct in_addr ipi_spec_dst; - struct in_addr ipi_addr; -}; -#endif - -/* Structure describing an Internet (IP) socket address. */ -#if __UAPI_DEF_SOCKADDR_IN -#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */ -struct sockaddr_in { - __kernel_sa_family_t sin_family; /* Address family */ - __be16 sin_port; /* Port number */ - struct in_addr sin_addr; /* Internet address */ - - /* Pad to size of `struct sockaddr'. */ - unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - - sizeof(unsigned short int) - sizeof(struct in_addr)]; -}; -#define sin_zero __pad /* for BSD UNIX comp. -FvK */ -#endif - -#if __UAPI_DEF_IN_CLASS -/* - * Definitions of the bits in an Internet address integer. - * On subnets, host and network parts are found according - * to the subnet mask, not these masks. - */ -#define IN_CLASSA(a) ((((long int) (a)) & 0x80000000) == 0) -#define IN_CLASSA_NET 0xff000000 -#define IN_CLASSA_NSHIFT 24 -#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) -#define IN_CLASSA_MAX 128 - -#define IN_CLASSB(a) ((((long int) (a)) & 0xc0000000) == 0x80000000) -#define IN_CLASSB_NET 0xffff0000 -#define IN_CLASSB_NSHIFT 16 -#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) -#define IN_CLASSB_MAX 65536 - -#define IN_CLASSC(a) ((((long int) (a)) & 0xe0000000) == 0xc0000000) -#define IN_CLASSC_NET 0xffffff00 -#define IN_CLASSC_NSHIFT 8 -#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) - -#define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000) -#define IN_MULTICAST(a) IN_CLASSD(a) -#define IN_MULTICAST_NET 0xF0000000 - -#define IN_EXPERIMENTAL(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000) -#define IN_BADCLASS(a) IN_EXPERIMENTAL((a)) - -/* Address to accept any incoming messages. */ -#define INADDR_ANY ((unsigned long int) 0x00000000) - -/* Address to send to all hosts. */ -#define INADDR_BROADCAST ((unsigned long int) 0xffffffff) - -/* Address indicating an error return. */ -#define INADDR_NONE ((unsigned long int) 0xffffffff) - -/* Network number for local host loopback. */ -#define IN_LOOPBACKNET 127 - -/* Address to loopback in software to local host. */ -#define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */ -#define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000) - -/* Defines for Multicast INADDR */ -#define INADDR_UNSPEC_GROUP 0xe0000000U /* 224.0.0.0 */ -#define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */ -#define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */ -#define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */ -#endif - -/* contains the htonl type stuff.. */ -#include - - -#endif /* _UAPI_LINUX_IN_H */ diff --git a/src/linux/include/uapi/linux/in6.h b/src/linux/include/uapi/linux/in6.h deleted file mode 100644 index b39ea4f..0000000 --- a/src/linux/include/uapi/linux/in6.h +++ /dev/null @@ -1,295 +0,0 @@ -/* - * Types and definitions for AF_INET6 - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * Sources: - * IPv6 Program Interfaces for BSD Systems - * - * - * Advanced Sockets API for IPv6 - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _UAPI_LINUX_IN6_H -#define _UAPI_LINUX_IN6_H - -#include -#include - -/* - * IPv6 address structure - */ - -#if __UAPI_DEF_IN6_ADDR -struct in6_addr { - union { - __u8 u6_addr8[16]; -#if __UAPI_DEF_IN6_ADDR_ALT - __be16 u6_addr16[8]; - __be32 u6_addr32[4]; -#endif - } in6_u; -#define s6_addr in6_u.u6_addr8 -#if __UAPI_DEF_IN6_ADDR_ALT -#define s6_addr16 in6_u.u6_addr16 -#define s6_addr32 in6_u.u6_addr32 -#endif -}; -#endif /* __UAPI_DEF_IN6_ADDR */ - -#if __UAPI_DEF_SOCKADDR_IN6 -struct sockaddr_in6 { - unsigned short int sin6_family; /* AF_INET6 */ - __be16 sin6_port; /* Transport layer port # */ - __be32 sin6_flowinfo; /* IPv6 flow information */ - struct in6_addr sin6_addr; /* IPv6 address */ - __u32 sin6_scope_id; /* scope id (new in RFC2553) */ -}; -#endif /* __UAPI_DEF_SOCKADDR_IN6 */ - -#if __UAPI_DEF_IPV6_MREQ -struct ipv6_mreq { - /* IPv6 multicast address of group */ - struct in6_addr ipv6mr_multiaddr; - - /* local IPv6 address of interface */ - int ipv6mr_ifindex; -}; -#endif /* __UAPI_DEF_IVP6_MREQ */ - -#define ipv6mr_acaddr ipv6mr_multiaddr - -struct in6_flowlabel_req { - struct in6_addr flr_dst; - __be32 flr_label; - __u8 flr_action; - __u8 flr_share; - __u16 flr_flags; - __u16 flr_expires; - __u16 flr_linger; - __u32 __flr_pad; - /* Options in format of IPV6_PKTOPTIONS */ -}; - -#define IPV6_FL_A_GET 0 -#define IPV6_FL_A_PUT 1 -#define IPV6_FL_A_RENEW 2 - -#define IPV6_FL_F_CREATE 1 -#define IPV6_FL_F_EXCL 2 -#define IPV6_FL_F_REFLECT 4 -#define IPV6_FL_F_REMOTE 8 - -#define IPV6_FL_S_NONE 0 -#define IPV6_FL_S_EXCL 1 -#define IPV6_FL_S_PROCESS 2 -#define IPV6_FL_S_USER 3 -#define IPV6_FL_S_ANY 255 - - -/* - * Bitmask constant declarations to help applications select out the - * flow label and priority fields. - * - * Note that this are in host byte order while the flowinfo field of - * sockaddr_in6 is in network byte order. - */ - -#define IPV6_FLOWINFO_FLOWLABEL 0x000fffff -#define IPV6_FLOWINFO_PRIORITY 0x0ff00000 - -/* These definitions are obsolete */ -#define IPV6_PRIORITY_UNCHARACTERIZED 0x0000 -#define IPV6_PRIORITY_FILLER 0x0100 -#define IPV6_PRIORITY_UNATTENDED 0x0200 -#define IPV6_PRIORITY_RESERVED1 0x0300 -#define IPV6_PRIORITY_BULK 0x0400 -#define IPV6_PRIORITY_RESERVED2 0x0500 -#define IPV6_PRIORITY_INTERACTIVE 0x0600 -#define IPV6_PRIORITY_CONTROL 0x0700 -#define IPV6_PRIORITY_8 0x0800 -#define IPV6_PRIORITY_9 0x0900 -#define IPV6_PRIORITY_10 0x0a00 -#define IPV6_PRIORITY_11 0x0b00 -#define IPV6_PRIORITY_12 0x0c00 -#define IPV6_PRIORITY_13 0x0d00 -#define IPV6_PRIORITY_14 0x0e00 -#define IPV6_PRIORITY_15 0x0f00 - -/* - * IPV6 extension headers - */ -#if __UAPI_DEF_IPPROTO_V6 -#define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */ -#define IPPROTO_ROUTING 43 /* IPv6 routing header */ -#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */ -#define IPPROTO_ICMPV6 58 /* ICMPv6 */ -#define IPPROTO_NONE 59 /* IPv6 no next header */ -#define IPPROTO_DSTOPTS 60 /* IPv6 destination options */ -#define IPPROTO_MH 135 /* IPv6 mobility header */ -#endif /* __UAPI_DEF_IPPROTO_V6 */ - -/* - * IPv6 TLV options. - */ -#define IPV6_TLV_PAD1 0 -#define IPV6_TLV_PADN 1 -#define IPV6_TLV_ROUTERALERT 5 -#define IPV6_TLV_CALIPSO 7 /* RFC 5570 */ -#define IPV6_TLV_JUMBO 194 -#define IPV6_TLV_HAO 201 /* home address option */ - -/* - * IPV6 socket options - */ -#if __UAPI_DEF_IPV6_OPTIONS -#define IPV6_ADDRFORM 1 -#define IPV6_2292PKTINFO 2 -#define IPV6_2292HOPOPTS 3 -#define IPV6_2292DSTOPTS 4 -#define IPV6_2292RTHDR 5 -#define IPV6_2292PKTOPTIONS 6 -#define IPV6_CHECKSUM 7 -#define IPV6_2292HOPLIMIT 8 -#define IPV6_NEXTHOP 9 -#define IPV6_AUTHHDR 10 /* obsolete */ -#define IPV6_FLOWINFO 11 - -#define IPV6_UNICAST_HOPS 16 -#define IPV6_MULTICAST_IF 17 -#define IPV6_MULTICAST_HOPS 18 -#define IPV6_MULTICAST_LOOP 19 -#define IPV6_ADD_MEMBERSHIP 20 -#define IPV6_DROP_MEMBERSHIP 21 -#define IPV6_ROUTER_ALERT 22 -#define IPV6_MTU_DISCOVER 23 -#define IPV6_MTU 24 -#define IPV6_RECVERR 25 -#define IPV6_V6ONLY 26 -#define IPV6_JOIN_ANYCAST 27 -#define IPV6_LEAVE_ANYCAST 28 - -/* IPV6_MTU_DISCOVER values */ -#define IPV6_PMTUDISC_DONT 0 -#define IPV6_PMTUDISC_WANT 1 -#define IPV6_PMTUDISC_DO 2 -#define IPV6_PMTUDISC_PROBE 3 -/* same as IPV6_PMTUDISC_PROBE, provided for symetry with IPv4 - * also see comments on IP_PMTUDISC_INTERFACE - */ -#define IPV6_PMTUDISC_INTERFACE 4 -/* weaker version of IPV6_PMTUDISC_INTERFACE, which allows packets to - * get fragmented if they exceed the interface mtu - */ -#define IPV6_PMTUDISC_OMIT 5 - -/* Flowlabel */ -#define IPV6_FLOWLABEL_MGR 32 -#define IPV6_FLOWINFO_SEND 33 - -#define IPV6_IPSEC_POLICY 34 -#define IPV6_XFRM_POLICY 35 -#define IPV6_HDRINCL 36 -#endif - -/* - * Multicast: - * Following socket options are shared between IPv4 and IPv6. - * - * MCAST_JOIN_GROUP 42 - * MCAST_BLOCK_SOURCE 43 - * MCAST_UNBLOCK_SOURCE 44 - * MCAST_LEAVE_GROUP 45 - * MCAST_JOIN_SOURCE_GROUP 46 - * MCAST_LEAVE_SOURCE_GROUP 47 - * MCAST_MSFILTER 48 - */ - -/* - * Advanced API (RFC3542) (1) - * - * Note: IPV6_RECVRTHDRDSTOPTS does not exist. see net/ipv6/datagram.c. - */ - -#define IPV6_RECVPKTINFO 49 -#define IPV6_PKTINFO 50 -#define IPV6_RECVHOPLIMIT 51 -#define IPV6_HOPLIMIT 52 -#define IPV6_RECVHOPOPTS 53 -#define IPV6_HOPOPTS 54 -#define IPV6_RTHDRDSTOPTS 55 -#define IPV6_RECVRTHDR 56 -#define IPV6_RTHDR 57 -#define IPV6_RECVDSTOPTS 58 -#define IPV6_DSTOPTS 59 -#define IPV6_RECVPATHMTU 60 -#define IPV6_PATHMTU 61 -#define IPV6_DONTFRAG 62 -#if 0 /* not yet */ -#define IPV6_USE_MIN_MTU 63 -#endif - -/* - * Netfilter (1) - * - * Following socket options are used in ip6_tables; - * see include/linux/netfilter_ipv6/ip6_tables.h. - * - * IP6T_SO_SET_REPLACE / IP6T_SO_GET_INFO 64 - * IP6T_SO_SET_ADD_COUNTERS / IP6T_SO_GET_ENTRIES 65 - */ - -/* - * Advanced API (RFC3542) (2) - */ -#define IPV6_RECVTCLASS 66 -#define IPV6_TCLASS 67 - -/* - * Netfilter (2) - * - * Following socket options are used in ip6_tables; - * see include/linux/netfilter_ipv6/ip6_tables.h. - * - * IP6T_SO_GET_REVISION_MATCH 68 - * IP6T_SO_GET_REVISION_TARGET 69 - * IP6T_SO_ORIGINAL_DST 80 - */ - -#define IPV6_AUTOFLOWLABEL 70 -/* RFC5014: Source address selection */ -#define IPV6_ADDR_PREFERENCES 72 - -#define IPV6_PREFER_SRC_TMP 0x0001 -#define IPV6_PREFER_SRC_PUBLIC 0x0002 -#define IPV6_PREFER_SRC_PUBTMP_DEFAULT 0x0100 -#define IPV6_PREFER_SRC_COA 0x0004 -#define IPV6_PREFER_SRC_HOME 0x0400 -#define IPV6_PREFER_SRC_CGA 0x0008 -#define IPV6_PREFER_SRC_NONCGA 0x0800 - -/* RFC5082: Generalized Ttl Security Mechanism */ -#define IPV6_MINHOPCOUNT 73 - -#define IPV6_ORIGDSTADDR 74 -#define IPV6_RECVORIGDSTADDR IPV6_ORIGDSTADDR -#define IPV6_TRANSPARENT 75 -#define IPV6_UNICAST_IF 76 - -/* - * Multicast Routing: - * see include/uapi/linux/mroute6.h. - * - * MRT6_BASE 200 - * ... - * MRT6_MAX - */ -#endif /* _UAPI_LINUX_IN6_H */ diff --git a/src/linux/include/uapi/linux/in_route.h b/src/linux/include/uapi/linux/in_route.h deleted file mode 100644 index b261b8c..0000000 --- a/src/linux/include/uapi/linux/in_route.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _LINUX_IN_ROUTE_H -#define _LINUX_IN_ROUTE_H - -/* IPv4 routing cache flags */ - -#define RTCF_DEAD RTNH_F_DEAD -#define RTCF_ONLINK RTNH_F_ONLINK - -/* Obsolete flag. About to be deleted */ -#define RTCF_NOPMTUDISC RTM_F_NOPMTUDISC - -#define RTCF_NOTIFY 0x00010000 -#define RTCF_DIRECTDST 0x00020000 /* unused */ -#define RTCF_REDIRECTED 0x00040000 -#define RTCF_TPROXY 0x00080000 /* unused */ - -#define RTCF_FAST 0x00200000 /* unused */ -#define RTCF_MASQ 0x00400000 /* unused */ -#define RTCF_SNAT 0x00800000 /* unused */ -#define RTCF_DOREDIRECT 0x01000000 -#define RTCF_DIRECTSRC 0x04000000 -#define RTCF_DNAT 0x08000000 -#define RTCF_BROADCAST 0x10000000 -#define RTCF_MULTICAST 0x20000000 -#define RTCF_REJECT 0x40000000 /* unused */ -#define RTCF_LOCAL 0x80000000 - -#define RTCF_NAT (RTCF_DNAT|RTCF_SNAT) - -#define RT_TOS(tos) ((tos)&IPTOS_TOS_MASK) - -#endif /* _LINUX_IN_ROUTE_H */ diff --git a/src/linux/include/uapi/linux/inet_diag.h b/src/linux/include/uapi/linux/inet_diag.h deleted file mode 100644 index 509cd96..0000000 --- a/src/linux/include/uapi/linux/inet_diag.h +++ /dev/null @@ -1,177 +0,0 @@ -#ifndef _UAPI_INET_DIAG_H_ -#define _UAPI_INET_DIAG_H_ - -#include - -/* Just some random number */ -#define TCPDIAG_GETSOCK 18 -#define DCCPDIAG_GETSOCK 19 - -#define INET_DIAG_GETSOCK_MAX 24 - -/* Socket identity */ -struct inet_diag_sockid { - __be16 idiag_sport; - __be16 idiag_dport; - __be32 idiag_src[4]; - __be32 idiag_dst[4]; - __u32 idiag_if; - __u32 idiag_cookie[2]; -#define INET_DIAG_NOCOOKIE (~0U) -}; - -/* Request structure */ - -struct inet_diag_req { - __u8 idiag_family; /* Family of addresses. */ - __u8 idiag_src_len; - __u8 idiag_dst_len; - __u8 idiag_ext; /* Query extended information */ - - struct inet_diag_sockid id; - - __u32 idiag_states; /* States to dump */ - __u32 idiag_dbs; /* Tables to dump (NI) */ -}; - -struct inet_diag_req_v2 { - __u8 sdiag_family; - __u8 sdiag_protocol; - __u8 idiag_ext; - __u8 pad; - __u32 idiag_states; - struct inet_diag_sockid id; -}; - -enum { - INET_DIAG_REQ_NONE, - INET_DIAG_REQ_BYTECODE, -}; - -#define INET_DIAG_REQ_MAX INET_DIAG_REQ_BYTECODE - -/* Bytecode is sequence of 4 byte commands followed by variable arguments. - * All the commands identified by "code" are conditional jumps forward: - * to offset cc+"yes" or to offset cc+"no". "yes" is supposed to be - * length of the command and its arguments. - */ - -struct inet_diag_bc_op { - unsigned char code; - unsigned char yes; - unsigned short no; -}; - -enum { - INET_DIAG_BC_NOP, - INET_DIAG_BC_JMP, - INET_DIAG_BC_S_GE, - INET_DIAG_BC_S_LE, - INET_DIAG_BC_D_GE, - INET_DIAG_BC_D_LE, - INET_DIAG_BC_AUTO, - INET_DIAG_BC_S_COND, - INET_DIAG_BC_D_COND, - INET_DIAG_BC_DEV_COND, /* u32 ifindex */ - INET_DIAG_BC_MARK_COND, -}; - -struct inet_diag_hostcond { - __u8 family; - __u8 prefix_len; - int port; - __be32 addr[0]; -}; - -struct inet_diag_markcond { - __u32 mark; - __u32 mask; -}; - -/* Base info structure. It contains socket identity (addrs/ports/cookie) - * and, alas, the information shown by netstat. */ -struct inet_diag_msg { - __u8 idiag_family; - __u8 idiag_state; - __u8 idiag_timer; - __u8 idiag_retrans; - - struct inet_diag_sockid id; - - __u32 idiag_expires; - __u32 idiag_rqueue; - __u32 idiag_wqueue; - __u32 idiag_uid; - __u32 idiag_inode; -}; - -/* Extensions */ - -enum { - INET_DIAG_NONE, - INET_DIAG_MEMINFO, - INET_DIAG_INFO, - INET_DIAG_VEGASINFO, - INET_DIAG_CONG, - INET_DIAG_TOS, - INET_DIAG_TCLASS, - INET_DIAG_SKMEMINFO, - INET_DIAG_SHUTDOWN, - INET_DIAG_DCTCPINFO, - INET_DIAG_PROTOCOL, /* response attribute only */ - INET_DIAG_SKV6ONLY, - INET_DIAG_LOCALS, - INET_DIAG_PEERS, - INET_DIAG_PAD, - INET_DIAG_MARK, - INET_DIAG_BBRINFO, - __INET_DIAG_MAX, -}; - -#define INET_DIAG_MAX (__INET_DIAG_MAX - 1) - -/* INET_DIAG_MEM */ - -struct inet_diag_meminfo { - __u32 idiag_rmem; - __u32 idiag_wmem; - __u32 idiag_fmem; - __u32 idiag_tmem; -}; - -/* INET_DIAG_VEGASINFO */ - -struct tcpvegas_info { - __u32 tcpv_enabled; - __u32 tcpv_rttcnt; - __u32 tcpv_rtt; - __u32 tcpv_minrtt; -}; - -/* INET_DIAG_DCTCPINFO */ - -struct tcp_dctcp_info { - __u16 dctcp_enabled; - __u16 dctcp_ce_state; - __u32 dctcp_alpha; - __u32 dctcp_ab_ecn; - __u32 dctcp_ab_tot; -}; - -/* INET_DIAG_BBRINFO */ - -struct tcp_bbr_info { - /* u64 bw: max-filtered BW (app throughput) estimate in Byte per sec: */ - __u32 bbr_bw_lo; /* lower 32 bits of bw */ - __u32 bbr_bw_hi; /* upper 32 bits of bw */ - __u32 bbr_min_rtt; /* min-filtered RTT in uSec */ - __u32 bbr_pacing_gain; /* pacing gain shifted left 8 bits */ - __u32 bbr_cwnd_gain; /* cwnd gain shifted left 8 bits */ -}; - -union tcp_cc_info { - struct tcpvegas_info vegas; - struct tcp_dctcp_info dctcp; - struct tcp_bbr_info bbr; -}; -#endif /* _UAPI_INET_DIAG_H_ */ diff --git a/src/linux/include/uapi/linux/input-event-codes.h b/src/linux/include/uapi/linux/input-event-codes.h deleted file mode 100644 index 3af60ee..0000000 --- a/src/linux/include/uapi/linux/input-event-codes.h +++ /dev/null @@ -1,837 +0,0 @@ -/* - * Input event codes - * - * *** IMPORTANT *** - * This file is not only included from C-code but also from devicetree source - * files. As such this file MUST only contain comments and defines. - * - * Copyright (c) 1999-2002 Vojtech Pavlik - * Copyright (c) 2015 Hans de Goede - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ -#ifndef _UAPI_INPUT_EVENT_CODES_H -#define _UAPI_INPUT_EVENT_CODES_H - -/* - * Device properties and quirks - */ - -#define INPUT_PROP_POINTER 0x00 /* needs a pointer */ -#define INPUT_PROP_DIRECT 0x01 /* direct input devices */ -#define INPUT_PROP_BUTTONPAD 0x02 /* has button(s) under pad */ -#define INPUT_PROP_SEMI_MT 0x03 /* touch rectangle only */ -#define INPUT_PROP_TOPBUTTONPAD 0x04 /* softbuttons at top of pad */ -#define INPUT_PROP_POINTING_STICK 0x05 /* is a pointing stick */ -#define INPUT_PROP_ACCELEROMETER 0x06 /* has accelerometer */ - -#define INPUT_PROP_MAX 0x1f -#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1) - -/* - * Event types - */ - -#define EV_SYN 0x00 -#define EV_KEY 0x01 -#define EV_REL 0x02 -#define EV_ABS 0x03 -#define EV_MSC 0x04 -#define EV_SW 0x05 -#define EV_LED 0x11 -#define EV_SND 0x12 -#define EV_REP 0x14 -#define EV_FF 0x15 -#define EV_PWR 0x16 -#define EV_FF_STATUS 0x17 -#define EV_MAX 0x1f -#define EV_CNT (EV_MAX+1) - -/* - * Synchronization events. - */ - -#define SYN_REPORT 0 -#define SYN_CONFIG 1 -#define SYN_MT_REPORT 2 -#define SYN_DROPPED 3 -#define SYN_MAX 0xf -#define SYN_CNT (SYN_MAX+1) - -/* - * Keys and buttons - * - * Most of the keys/buttons are modeled after USB HUT 1.12 - * (see http://www.usb.org/developers/hidpage). - * Abbreviations in the comments: - * AC - Application Control - * AL - Application Launch Button - * SC - System Control - */ - -#define KEY_RESERVED 0 -#define KEY_ESC 1 -#define KEY_1 2 -#define KEY_2 3 -#define KEY_3 4 -#define KEY_4 5 -#define KEY_5 6 -#define KEY_6 7 -#define KEY_7 8 -#define KEY_8 9 -#define KEY_9 10 -#define KEY_0 11 -#define KEY_MINUS 12 -#define KEY_EQUAL 13 -#define KEY_BACKSPACE 14 -#define KEY_TAB 15 -#define KEY_Q 16 -#define KEY_W 17 -#define KEY_E 18 -#define KEY_R 19 -#define KEY_T 20 -#define KEY_Y 21 -#define KEY_U 22 -#define KEY_I 23 -#define KEY_O 24 -#define KEY_P 25 -#define KEY_LEFTBRACE 26 -#define KEY_RIGHTBRACE 27 -#define KEY_ENTER 28 -#define KEY_LEFTCTRL 29 -#define KEY_A 30 -#define KEY_S 31 -#define KEY_D 32 -#define KEY_F 33 -#define KEY_G 34 -#define KEY_H 35 -#define KEY_J 36 -#define KEY_K 37 -#define KEY_L 38 -#define KEY_SEMICOLON 39 -#define KEY_APOSTROPHE 40 -#define KEY_GRAVE 41 -#define KEY_LEFTSHIFT 42 -#define KEY_BACKSLASH 43 -#define KEY_Z 44 -#define KEY_X 45 -#define KEY_C 46 -#define KEY_V 47 -#define KEY_B 48 -#define KEY_N 49 -#define KEY_M 50 -#define KEY_COMMA 51 -#define KEY_DOT 52 -#define KEY_SLASH 53 -#define KEY_RIGHTSHIFT 54 -#define KEY_KPASTERISK 55 -#define KEY_LEFTALT 56 -#define KEY_SPACE 57 -#define KEY_CAPSLOCK 58 -#define KEY_F1 59 -#define KEY_F2 60 -#define KEY_F3 61 -#define KEY_F4 62 -#define KEY_F5 63 -#define KEY_F6 64 -#define KEY_F7 65 -#define KEY_F8 66 -#define KEY_F9 67 -#define KEY_F10 68 -#define KEY_NUMLOCK 69 -#define KEY_SCROLLLOCK 70 -#define KEY_KP7 71 -#define KEY_KP8 72 -#define KEY_KP9 73 -#define KEY_KPMINUS 74 -#define KEY_KP4 75 -#define KEY_KP5 76 -#define KEY_KP6 77 -#define KEY_KPPLUS 78 -#define KEY_KP1 79 -#define KEY_KP2 80 -#define KEY_KP3 81 -#define KEY_KP0 82 -#define KEY_KPDOT 83 - -#define KEY_ZENKAKUHANKAKU 85 -#define KEY_102ND 86 -#define KEY_F11 87 -#define KEY_F12 88 -#define KEY_RO 89 -#define KEY_KATAKANA 90 -#define KEY_HIRAGANA 91 -#define KEY_HENKAN 92 -#define KEY_KATAKANAHIRAGANA 93 -#define KEY_MUHENKAN 94 -#define KEY_KPJPCOMMA 95 -#define KEY_KPENTER 96 -#define KEY_RIGHTCTRL 97 -#define KEY_KPSLASH 98 -#define KEY_SYSRQ 99 -#define KEY_RIGHTALT 100 -#define KEY_LINEFEED 101 -#define KEY_HOME 102 -#define KEY_UP 103 -#define KEY_PAGEUP 104 -#define KEY_LEFT 105 -#define KEY_RIGHT 106 -#define KEY_END 107 -#define KEY_DOWN 108 -#define KEY_PAGEDOWN 109 -#define KEY_INSERT 110 -#define KEY_DELETE 111 -#define KEY_MACRO 112 -#define KEY_MUTE 113 -#define KEY_VOLUMEDOWN 114 -#define KEY_VOLUMEUP 115 -#define KEY_POWER 116 /* SC System Power Down */ -#define KEY_KPEQUAL 117 -#define KEY_KPPLUSMINUS 118 -#define KEY_PAUSE 119 -#define KEY_SCALE 120 /* AL Compiz Scale (Expose) */ - -#define KEY_KPCOMMA 121 -#define KEY_HANGEUL 122 -#define KEY_HANGUEL KEY_HANGEUL -#define KEY_HANJA 123 -#define KEY_YEN 124 -#define KEY_LEFTMETA 125 -#define KEY_RIGHTMETA 126 -#define KEY_COMPOSE 127 - -#define KEY_STOP 128 /* AC Stop */ -#define KEY_AGAIN 129 -#define KEY_PROPS 130 /* AC Properties */ -#define KEY_UNDO 131 /* AC Undo */ -#define KEY_FRONT 132 -#define KEY_COPY 133 /* AC Copy */ -#define KEY_OPEN 134 /* AC Open */ -#define KEY_PASTE 135 /* AC Paste */ -#define KEY_FIND 136 /* AC Search */ -#define KEY_CUT 137 /* AC Cut */ -#define KEY_HELP 138 /* AL Integrated Help Center */ -#define KEY_MENU 139 /* Menu (show menu) */ -#define KEY_CALC 140 /* AL Calculator */ -#define KEY_SETUP 141 -#define KEY_SLEEP 142 /* SC System Sleep */ -#define KEY_WAKEUP 143 /* System Wake Up */ -#define KEY_FILE 144 /* AL Local Machine Browser */ -#define KEY_SENDFILE 145 -#define KEY_DELETEFILE 146 -#define KEY_XFER 147 -#define KEY_PROG1 148 -#define KEY_PROG2 149 -#define KEY_WWW 150 /* AL Internet Browser */ -#define KEY_MSDOS 151 -#define KEY_COFFEE 152 /* AL Terminal Lock/Screensaver */ -#define KEY_SCREENLOCK KEY_COFFEE -#define KEY_ROTATE_DISPLAY 153 /* Display orientation for e.g. tablets */ -#define KEY_DIRECTION KEY_ROTATE_DISPLAY -#define KEY_CYCLEWINDOWS 154 -#define KEY_MAIL 155 -#define KEY_BOOKMARKS 156 /* AC Bookmarks */ -#define KEY_COMPUTER 157 -#define KEY_BACK 158 /* AC Back */ -#define KEY_FORWARD 159 /* AC Forward */ -#define KEY_CLOSECD 160 -#define KEY_EJECTCD 161 -#define KEY_EJECTCLOSECD 162 -#define KEY_NEXTSONG 163 -#define KEY_PLAYPAUSE 164 -#define KEY_PREVIOUSSONG 165 -#define KEY_STOPCD 166 -#define KEY_RECORD 167 -#define KEY_REWIND 168 -#define KEY_PHONE 169 /* Media Select Telephone */ -#define KEY_ISO 170 -#define KEY_CONFIG 171 /* AL Consumer Control Configuration */ -#define KEY_HOMEPAGE 172 /* AC Home */ -#define KEY_REFRESH 173 /* AC Refresh */ -#define KEY_EXIT 174 /* AC Exit */ -#define KEY_MOVE 175 -#define KEY_EDIT 176 -#define KEY_SCROLLUP 177 -#define KEY_SCROLLDOWN 178 -#define KEY_KPLEFTPAREN 179 -#define KEY_KPRIGHTPAREN 180 -#define KEY_NEW 181 /* AC New */ -#define KEY_REDO 182 /* AC Redo/Repeat */ - -#define KEY_F13 183 -#define KEY_F14 184 -#define KEY_F15 185 -#define KEY_F16 186 -#define KEY_F17 187 -#define KEY_F18 188 -#define KEY_F19 189 -#define KEY_F20 190 -#define KEY_F21 191 -#define KEY_F22 192 -#define KEY_F23 193 -#define KEY_F24 194 - -#define KEY_PLAYCD 200 -#define KEY_PAUSECD 201 -#define KEY_PROG3 202 -#define KEY_PROG4 203 -#define KEY_DASHBOARD 204 /* AL Dashboard */ -#define KEY_SUSPEND 205 -#define KEY_CLOSE 206 /* AC Close */ -#define KEY_PLAY 207 -#define KEY_FASTFORWARD 208 -#define KEY_BASSBOOST 209 -#define KEY_PRINT 210 /* AC Print */ -#define KEY_HP 211 -#define KEY_CAMERA 212 -#define KEY_SOUND 213 -#define KEY_QUESTION 214 -#define KEY_EMAIL 215 -#define KEY_CHAT 216 -#define KEY_SEARCH 217 -#define KEY_CONNECT 218 -#define KEY_FINANCE 219 /* AL Checkbook/Finance */ -#define KEY_SPORT 220 -#define KEY_SHOP 221 -#define KEY_ALTERASE 222 -#define KEY_CANCEL 223 /* AC Cancel */ -#define KEY_BRIGHTNESSDOWN 224 -#define KEY_BRIGHTNESSUP 225 -#define KEY_MEDIA 226 - -#define KEY_SWITCHVIDEOMODE 227 /* Cycle between available video - outputs (Monitor/LCD/TV-out/etc) */ -#define KEY_KBDILLUMTOGGLE 228 -#define KEY_KBDILLUMDOWN 229 -#define KEY_KBDILLUMUP 230 - -#define KEY_SEND 231 /* AC Send */ -#define KEY_REPLY 232 /* AC Reply */ -#define KEY_FORWARDMAIL 233 /* AC Forward Msg */ -#define KEY_SAVE 234 /* AC Save */ -#define KEY_DOCUMENTS 235 - -#define KEY_BATTERY 236 - -#define KEY_BLUETOOTH 237 -#define KEY_WLAN 238 -#define KEY_UWB 239 - -#define KEY_UNKNOWN 240 - -#define KEY_VIDEO_NEXT 241 /* drive next video source */ -#define KEY_VIDEO_PREV 242 /* drive previous video source */ -#define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */ -#define KEY_BRIGHTNESS_AUTO 244 /* Set Auto Brightness: manual - brightness control is off, - rely on ambient */ -#define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO -#define KEY_DISPLAY_OFF 245 /* display device to off state */ - -#define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */ -#define KEY_WIMAX KEY_WWAN -#define KEY_RFKILL 247 /* Key that controls all radios */ - -#define KEY_MICMUTE 248 /* Mute / unmute the microphone */ - -/* Code 255 is reserved for special needs of AT keyboard driver */ - -#define BTN_MISC 0x100 -#define BTN_0 0x100 -#define BTN_1 0x101 -#define BTN_2 0x102 -#define BTN_3 0x103 -#define BTN_4 0x104 -#define BTN_5 0x105 -#define BTN_6 0x106 -#define BTN_7 0x107 -#define BTN_8 0x108 -#define BTN_9 0x109 - -#define BTN_MOUSE 0x110 -#define BTN_LEFT 0x110 -#define BTN_RIGHT 0x111 -#define BTN_MIDDLE 0x112 -#define BTN_SIDE 0x113 -#define BTN_EXTRA 0x114 -#define BTN_FORWARD 0x115 -#define BTN_BACK 0x116 -#define BTN_TASK 0x117 - -#define BTN_JOYSTICK 0x120 -#define BTN_TRIGGER 0x120 -#define BTN_THUMB 0x121 -#define BTN_THUMB2 0x122 -#define BTN_TOP 0x123 -#define BTN_TOP2 0x124 -#define BTN_PINKIE 0x125 -#define BTN_BASE 0x126 -#define BTN_BASE2 0x127 -#define BTN_BASE3 0x128 -#define BTN_BASE4 0x129 -#define BTN_BASE5 0x12a -#define BTN_BASE6 0x12b -#define BTN_DEAD 0x12f - -#define BTN_GAMEPAD 0x130 -#define BTN_SOUTH 0x130 -#define BTN_A BTN_SOUTH -#define BTN_EAST 0x131 -#define BTN_B BTN_EAST -#define BTN_C 0x132 -#define BTN_NORTH 0x133 -#define BTN_X BTN_NORTH -#define BTN_WEST 0x134 -#define BTN_Y BTN_WEST -#define BTN_Z 0x135 -#define BTN_TL 0x136 -#define BTN_TR 0x137 -#define BTN_TL2 0x138 -#define BTN_TR2 0x139 -#define BTN_SELECT 0x13a -#define BTN_START 0x13b -#define BTN_MODE 0x13c -#define BTN_THUMBL 0x13d -#define BTN_THUMBR 0x13e - -#define BTN_DIGI 0x140 -#define BTN_TOOL_PEN 0x140 -#define BTN_TOOL_RUBBER 0x141 -#define BTN_TOOL_BRUSH 0x142 -#define BTN_TOOL_PENCIL 0x143 -#define BTN_TOOL_AIRBRUSH 0x144 -#define BTN_TOOL_FINGER 0x145 -#define BTN_TOOL_MOUSE 0x146 -#define BTN_TOOL_LENS 0x147 -#define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */ -#define BTN_TOUCH 0x14a -#define BTN_STYLUS 0x14b -#define BTN_STYLUS2 0x14c -#define BTN_TOOL_DOUBLETAP 0x14d -#define BTN_TOOL_TRIPLETAP 0x14e -#define BTN_TOOL_QUADTAP 0x14f /* Four fingers on trackpad */ - -#define BTN_WHEEL 0x150 -#define BTN_GEAR_DOWN 0x150 -#define BTN_GEAR_UP 0x151 - -#define KEY_OK 0x160 -#define KEY_SELECT 0x161 -#define KEY_GOTO 0x162 -#define KEY_CLEAR 0x163 -#define KEY_POWER2 0x164 -#define KEY_OPTION 0x165 -#define KEY_INFO 0x166 /* AL OEM Features/Tips/Tutorial */ -#define KEY_TIME 0x167 -#define KEY_VENDOR 0x168 -#define KEY_ARCHIVE 0x169 -#define KEY_PROGRAM 0x16a /* Media Select Program Guide */ -#define KEY_CHANNEL 0x16b -#define KEY_FAVORITES 0x16c -#define KEY_EPG 0x16d -#define KEY_PVR 0x16e /* Media Select Home */ -#define KEY_MHP 0x16f -#define KEY_LANGUAGE 0x170 -#define KEY_TITLE 0x171 -#define KEY_SUBTITLE 0x172 -#define KEY_ANGLE 0x173 -#define KEY_ZOOM 0x174 -#define KEY_MODE 0x175 -#define KEY_KEYBOARD 0x176 -#define KEY_SCREEN 0x177 -#define KEY_PC 0x178 /* Media Select Computer */ -#define KEY_TV 0x179 /* Media Select TV */ -#define KEY_TV2 0x17a /* Media Select Cable */ -#define KEY_VCR 0x17b /* Media Select VCR */ -#define KEY_VCR2 0x17c /* VCR Plus */ -#define KEY_SAT 0x17d /* Media Select Satellite */ -#define KEY_SAT2 0x17e -#define KEY_CD 0x17f /* Media Select CD */ -#define KEY_TAPE 0x180 /* Media Select Tape */ -#define KEY_RADIO 0x181 -#define KEY_TUNER 0x182 /* Media Select Tuner */ -#define KEY_PLAYER 0x183 -#define KEY_TEXT 0x184 -#define KEY_DVD 0x185 /* Media Select DVD */ -#define KEY_AUX 0x186 -#define KEY_MP3 0x187 -#define KEY_AUDIO 0x188 /* AL Audio Browser */ -#define KEY_VIDEO 0x189 /* AL Movie Browser */ -#define KEY_DIRECTORY 0x18a -#define KEY_LIST 0x18b -#define KEY_MEMO 0x18c /* Media Select Messages */ -#define KEY_CALENDAR 0x18d -#define KEY_RED 0x18e -#define KEY_GREEN 0x18f -#define KEY_YELLOW 0x190 -#define KEY_BLUE 0x191 -#define KEY_CHANNELUP 0x192 /* Channel Increment */ -#define KEY_CHANNELDOWN 0x193 /* Channel Decrement */ -#define KEY_FIRST 0x194 -#define KEY_LAST 0x195 /* Recall Last */ -#define KEY_AB 0x196 -#define KEY_NEXT 0x197 -#define KEY_RESTART 0x198 -#define KEY_SLOW 0x199 -#define KEY_SHUFFLE 0x19a -#define KEY_BREAK 0x19b -#define KEY_PREVIOUS 0x19c -#define KEY_DIGITS 0x19d -#define KEY_TEEN 0x19e -#define KEY_TWEN 0x19f -#define KEY_VIDEOPHONE 0x1a0 /* Media Select Video Phone */ -#define KEY_GAMES 0x1a1 /* Media Select Games */ -#define KEY_ZOOMIN 0x1a2 /* AC Zoom In */ -#define KEY_ZOOMOUT 0x1a3 /* AC Zoom Out */ -#define KEY_ZOOMRESET 0x1a4 /* AC Zoom */ -#define KEY_WORDPROCESSOR 0x1a5 /* AL Word Processor */ -#define KEY_EDITOR 0x1a6 /* AL Text Editor */ -#define KEY_SPREADSHEET 0x1a7 /* AL Spreadsheet */ -#define KEY_GRAPHICSEDITOR 0x1a8 /* AL Graphics Editor */ -#define KEY_PRESENTATION 0x1a9 /* AL Presentation App */ -#define KEY_DATABASE 0x1aa /* AL Database App */ -#define KEY_NEWS 0x1ab /* AL Newsreader */ -#define KEY_VOICEMAIL 0x1ac /* AL Voicemail */ -#define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */ -#define KEY_MESSENGER 0x1ae /* AL Instant Messaging */ -#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */ -#define KEY_BRIGHTNESS_TOGGLE KEY_DISPLAYTOGGLE -#define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */ -#define KEY_LOGOFF 0x1b1 /* AL Logoff */ - -#define KEY_DOLLAR 0x1b2 -#define KEY_EURO 0x1b3 - -#define KEY_FRAMEBACK 0x1b4 /* Consumer - transport controls */ -#define KEY_FRAMEFORWARD 0x1b5 -#define KEY_CONTEXT_MENU 0x1b6 /* GenDesc - system context menu */ -#define KEY_MEDIA_REPEAT 0x1b7 /* Consumer - transport control */ -#define KEY_10CHANNELSUP 0x1b8 /* 10 channels up (10+) */ -#define KEY_10CHANNELSDOWN 0x1b9 /* 10 channels down (10-) */ -#define KEY_IMAGES 0x1ba /* AL Image Browser */ - -#define KEY_DEL_EOL 0x1c0 -#define KEY_DEL_EOS 0x1c1 -#define KEY_INS_LINE 0x1c2 -#define KEY_DEL_LINE 0x1c3 - -#define KEY_FN 0x1d0 -#define KEY_FN_ESC 0x1d1 -#define KEY_FN_F1 0x1d2 -#define KEY_FN_F2 0x1d3 -#define KEY_FN_F3 0x1d4 -#define KEY_FN_F4 0x1d5 -#define KEY_FN_F5 0x1d6 -#define KEY_FN_F6 0x1d7 -#define KEY_FN_F7 0x1d8 -#define KEY_FN_F8 0x1d9 -#define KEY_FN_F9 0x1da -#define KEY_FN_F10 0x1db -#define KEY_FN_F11 0x1dc -#define KEY_FN_F12 0x1dd -#define KEY_FN_1 0x1de -#define KEY_FN_2 0x1df -#define KEY_FN_D 0x1e0 -#define KEY_FN_E 0x1e1 -#define KEY_FN_F 0x1e2 -#define KEY_FN_S 0x1e3 -#define KEY_FN_B 0x1e4 - -#define KEY_BRL_DOT1 0x1f1 -#define KEY_BRL_DOT2 0x1f2 -#define KEY_BRL_DOT3 0x1f3 -#define KEY_BRL_DOT4 0x1f4 -#define KEY_BRL_DOT5 0x1f5 -#define KEY_BRL_DOT6 0x1f6 -#define KEY_BRL_DOT7 0x1f7 -#define KEY_BRL_DOT8 0x1f8 -#define KEY_BRL_DOT9 0x1f9 -#define KEY_BRL_DOT10 0x1fa - -#define KEY_NUMERIC_0 0x200 /* used by phones, remote controls, */ -#define KEY_NUMERIC_1 0x201 /* and other keypads */ -#define KEY_NUMERIC_2 0x202 -#define KEY_NUMERIC_3 0x203 -#define KEY_NUMERIC_4 0x204 -#define KEY_NUMERIC_5 0x205 -#define KEY_NUMERIC_6 0x206 -#define KEY_NUMERIC_7 0x207 -#define KEY_NUMERIC_8 0x208 -#define KEY_NUMERIC_9 0x209 -#define KEY_NUMERIC_STAR 0x20a -#define KEY_NUMERIC_POUND 0x20b -#define KEY_NUMERIC_A 0x20c /* Phone key A - HUT Telephony 0xb9 */ -#define KEY_NUMERIC_B 0x20d -#define KEY_NUMERIC_C 0x20e -#define KEY_NUMERIC_D 0x20f - -#define KEY_CAMERA_FOCUS 0x210 -#define KEY_WPS_BUTTON 0x211 /* WiFi Protected Setup key */ - -#define KEY_TOUCHPAD_TOGGLE 0x212 /* Request switch touchpad on or off */ -#define KEY_TOUCHPAD_ON 0x213 -#define KEY_TOUCHPAD_OFF 0x214 - -#define KEY_CAMERA_ZOOMIN 0x215 -#define KEY_CAMERA_ZOOMOUT 0x216 -#define KEY_CAMERA_UP 0x217 -#define KEY_CAMERA_DOWN 0x218 -#define KEY_CAMERA_LEFT 0x219 -#define KEY_CAMERA_RIGHT 0x21a - -#define KEY_ATTENDANT_ON 0x21b -#define KEY_ATTENDANT_OFF 0x21c -#define KEY_ATTENDANT_TOGGLE 0x21d /* Attendant call on or off */ -#define KEY_LIGHTS_TOGGLE 0x21e /* Reading light on or off */ - -#define BTN_DPAD_UP 0x220 -#define BTN_DPAD_DOWN 0x221 -#define BTN_DPAD_LEFT 0x222 -#define BTN_DPAD_RIGHT 0x223 - -#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */ - -#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */ -#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */ -#define KEY_JOURNAL 0x242 /* AL Log/Journal/Timecard */ -#define KEY_CONTROLPANEL 0x243 /* AL Control Panel */ -#define KEY_APPSELECT 0x244 /* AL Select Task/Application */ -#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */ -#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */ - -#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */ -#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */ - -#define KEY_KBDINPUTASSIST_PREV 0x260 -#define KEY_KBDINPUTASSIST_NEXT 0x261 -#define KEY_KBDINPUTASSIST_PREVGROUP 0x262 -#define KEY_KBDINPUTASSIST_NEXTGROUP 0x263 -#define KEY_KBDINPUTASSIST_ACCEPT 0x264 -#define KEY_KBDINPUTASSIST_CANCEL 0x265 - -/* Diagonal movement keys */ -#define KEY_RIGHT_UP 0x266 -#define KEY_RIGHT_DOWN 0x267 -#define KEY_LEFT_UP 0x268 -#define KEY_LEFT_DOWN 0x269 - -#define KEY_ROOT_MENU 0x26a /* Show Device's Root Menu */ -/* Show Top Menu of the Media (e.g. DVD) */ -#define KEY_MEDIA_TOP_MENU 0x26b -#define KEY_NUMERIC_11 0x26c -#define KEY_NUMERIC_12 0x26d -/* - * Toggle Audio Description: refers to an audio service that helps blind and - * visually impaired consumers understand the action in a program. Note: in - * some countries this is referred to as "Video Description". - */ -#define KEY_AUDIO_DESC 0x26e -#define KEY_3D_MODE 0x26f -#define KEY_NEXT_FAVORITE 0x270 -#define KEY_STOP_RECORD 0x271 -#define KEY_PAUSE_RECORD 0x272 -#define KEY_VOD 0x273 /* Video on Demand */ -#define KEY_UNMUTE 0x274 -#define KEY_FASTREVERSE 0x275 -#define KEY_SLOWREVERSE 0x276 -/* - * Control a data application associated with the currently viewed channel, - * e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.) - */ -#define KEY_DATA 0x277 - -#define BTN_TRIGGER_HAPPY 0x2c0 -#define BTN_TRIGGER_HAPPY1 0x2c0 -#define BTN_TRIGGER_HAPPY2 0x2c1 -#define BTN_TRIGGER_HAPPY3 0x2c2 -#define BTN_TRIGGER_HAPPY4 0x2c3 -#define BTN_TRIGGER_HAPPY5 0x2c4 -#define BTN_TRIGGER_HAPPY6 0x2c5 -#define BTN_TRIGGER_HAPPY7 0x2c6 -#define BTN_TRIGGER_HAPPY8 0x2c7 -#define BTN_TRIGGER_HAPPY9 0x2c8 -#define BTN_TRIGGER_HAPPY10 0x2c9 -#define BTN_TRIGGER_HAPPY11 0x2ca -#define BTN_TRIGGER_HAPPY12 0x2cb -#define BTN_TRIGGER_HAPPY13 0x2cc -#define BTN_TRIGGER_HAPPY14 0x2cd -#define BTN_TRIGGER_HAPPY15 0x2ce -#define BTN_TRIGGER_HAPPY16 0x2cf -#define BTN_TRIGGER_HAPPY17 0x2d0 -#define BTN_TRIGGER_HAPPY18 0x2d1 -#define BTN_TRIGGER_HAPPY19 0x2d2 -#define BTN_TRIGGER_HAPPY20 0x2d3 -#define BTN_TRIGGER_HAPPY21 0x2d4 -#define BTN_TRIGGER_HAPPY22 0x2d5 -#define BTN_TRIGGER_HAPPY23 0x2d6 -#define BTN_TRIGGER_HAPPY24 0x2d7 -#define BTN_TRIGGER_HAPPY25 0x2d8 -#define BTN_TRIGGER_HAPPY26 0x2d9 -#define BTN_TRIGGER_HAPPY27 0x2da -#define BTN_TRIGGER_HAPPY28 0x2db -#define BTN_TRIGGER_HAPPY29 0x2dc -#define BTN_TRIGGER_HAPPY30 0x2dd -#define BTN_TRIGGER_HAPPY31 0x2de -#define BTN_TRIGGER_HAPPY32 0x2df -#define BTN_TRIGGER_HAPPY33 0x2e0 -#define BTN_TRIGGER_HAPPY34 0x2e1 -#define BTN_TRIGGER_HAPPY35 0x2e2 -#define BTN_TRIGGER_HAPPY36 0x2e3 -#define BTN_TRIGGER_HAPPY37 0x2e4 -#define BTN_TRIGGER_HAPPY38 0x2e5 -#define BTN_TRIGGER_HAPPY39 0x2e6 -#define BTN_TRIGGER_HAPPY40 0x2e7 - -/* We avoid low common keys in module aliases so they don't get huge. */ -#define KEY_MIN_INTERESTING KEY_MUTE -#define KEY_MAX 0x2ff -#define KEY_CNT (KEY_MAX+1) - -/* - * Relative axes - */ - -#define REL_X 0x00 -#define REL_Y 0x01 -#define REL_Z 0x02 -#define REL_RX 0x03 -#define REL_RY 0x04 -#define REL_RZ 0x05 -#define REL_HWHEEL 0x06 -#define REL_DIAL 0x07 -#define REL_WHEEL 0x08 -#define REL_MISC 0x09 -#define REL_MAX 0x0f -#define REL_CNT (REL_MAX+1) - -/* - * Absolute axes - */ - -#define ABS_X 0x00 -#define ABS_Y 0x01 -#define ABS_Z 0x02 -#define ABS_RX 0x03 -#define ABS_RY 0x04 -#define ABS_RZ 0x05 -#define ABS_THROTTLE 0x06 -#define ABS_RUDDER 0x07 -#define ABS_WHEEL 0x08 -#define ABS_GAS 0x09 -#define ABS_BRAKE 0x0a -#define ABS_HAT0X 0x10 -#define ABS_HAT0Y 0x11 -#define ABS_HAT1X 0x12 -#define ABS_HAT1Y 0x13 -#define ABS_HAT2X 0x14 -#define ABS_HAT2Y 0x15 -#define ABS_HAT3X 0x16 -#define ABS_HAT3Y 0x17 -#define ABS_PRESSURE 0x18 -#define ABS_DISTANCE 0x19 -#define ABS_TILT_X 0x1a -#define ABS_TILT_Y 0x1b -#define ABS_TOOL_WIDTH 0x1c - -#define ABS_VOLUME 0x20 - -#define ABS_MISC 0x28 - -#define ABS_MT_SLOT 0x2f /* MT slot being modified */ -#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */ -#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */ -#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */ -#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */ -#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */ -#define ABS_MT_POSITION_X 0x35 /* Center X touch position */ -#define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */ -#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */ -#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */ -#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */ -#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */ -#define ABS_MT_DISTANCE 0x3b /* Contact hover distance */ -#define ABS_MT_TOOL_X 0x3c /* Center X tool position */ -#define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */ - - -#define ABS_MAX 0x3f -#define ABS_CNT (ABS_MAX+1) - -/* - * Switch events - */ - -#define SW_LID 0x00 /* set = lid shut */ -#define SW_TABLET_MODE 0x01 /* set = tablet mode */ -#define SW_HEADPHONE_INSERT 0x02 /* set = inserted */ -#define SW_RFKILL_ALL 0x03 /* rfkill master switch, type "any" - set = radio enabled */ -#define SW_RADIO SW_RFKILL_ALL /* deprecated */ -#define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ -#define SW_DOCK 0x05 /* set = plugged into dock */ -#define SW_LINEOUT_INSERT 0x06 /* set = inserted */ -#define SW_JACK_PHYSICAL_INSERT 0x07 /* set = mechanical switch set */ -#define SW_VIDEOOUT_INSERT 0x08 /* set = inserted */ -#define SW_CAMERA_LENS_COVER 0x09 /* set = lens covered */ -#define SW_KEYPAD_SLIDE 0x0a /* set = keypad slide out */ -#define SW_FRONT_PROXIMITY 0x0b /* set = front proximity sensor active */ -#define SW_ROTATE_LOCK 0x0c /* set = rotate locked/disabled */ -#define SW_LINEIN_INSERT 0x0d /* set = inserted */ -#define SW_MUTE_DEVICE 0x0e /* set = device disabled */ -#define SW_PEN_INSERTED 0x0f /* set = pen inserted */ -#define SW_MAX 0x0f -#define SW_CNT (SW_MAX+1) - -/* - * Misc events - */ - -#define MSC_SERIAL 0x00 -#define MSC_PULSELED 0x01 -#define MSC_GESTURE 0x02 -#define MSC_RAW 0x03 -#define MSC_SCAN 0x04 -#define MSC_TIMESTAMP 0x05 -#define MSC_MAX 0x07 -#define MSC_CNT (MSC_MAX+1) - -/* - * LEDs - */ - -#define LED_NUML 0x00 -#define LED_CAPSL 0x01 -#define LED_SCROLLL 0x02 -#define LED_COMPOSE 0x03 -#define LED_KANA 0x04 -#define LED_SLEEP 0x05 -#define LED_SUSPEND 0x06 -#define LED_MUTE 0x07 -#define LED_MISC 0x08 -#define LED_MAIL 0x09 -#define LED_CHARGING 0x0a -#define LED_MAX 0x0f -#define LED_CNT (LED_MAX+1) - -/* - * Autorepeat values - */ - -#define REP_DELAY 0x00 -#define REP_PERIOD 0x01 -#define REP_MAX 0x01 -#define REP_CNT (REP_MAX+1) - -/* - * Sounds - */ - -#define SND_CLICK 0x00 -#define SND_BELL 0x01 -#define SND_TONE 0x02 -#define SND_MAX 0x07 -#define SND_CNT (SND_MAX+1) - -#endif diff --git a/src/linux/include/uapi/linux/input.h b/src/linux/include/uapi/linux/input.h deleted file mode 100644 index e794f7b..0000000 --- a/src/linux/include/uapi/linux/input.h +++ /dev/null @@ -1,491 +0,0 @@ -/* - * Copyright (c) 1999-2002 Vojtech Pavlik - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ -#ifndef _UAPI_INPUT_H -#define _UAPI_INPUT_H - - -#ifndef __KERNEL__ -#include -#include -#include -#include -#endif - -#include "input-event-codes.h" - -/* - * The event structure itself - */ - -struct input_event { - struct timeval time; - __u16 type; - __u16 code; - __s32 value; -}; - -/* - * Protocol version. - */ - -#define EV_VERSION 0x010001 - -/* - * IOCTLs (0x00 - 0x7f) - */ - -struct input_id { - __u16 bustype; - __u16 vendor; - __u16 product; - __u16 version; -}; - -/** - * struct input_absinfo - used by EVIOCGABS/EVIOCSABS ioctls - * @value: latest reported value for the axis. - * @minimum: specifies minimum value for the axis. - * @maximum: specifies maximum value for the axis. - * @fuzz: specifies fuzz value that is used to filter noise from - * the event stream. - * @flat: values that are within this value will be discarded by - * joydev interface and reported as 0 instead. - * @resolution: specifies resolution for the values reported for - * the axis. - * - * Note that input core does not clamp reported values to the - * [minimum, maximum] limits, such task is left to userspace. - * - * Resolution for main axes (ABS_X, ABS_Y, ABS_Z) is reported in - * units per millimeter (units/mm), resolution for rotational axes - * (ABS_RX, ABS_RY, ABS_RZ) is reported in units per radian. - */ -struct input_absinfo { - __s32 value; - __s32 minimum; - __s32 maximum; - __s32 fuzz; - __s32 flat; - __s32 resolution; -}; - -/** - * struct input_keymap_entry - used by EVIOCGKEYCODE/EVIOCSKEYCODE ioctls - * @scancode: scancode represented in machine-endian form. - * @len: length of the scancode that resides in @scancode buffer. - * @index: index in the keymap, may be used instead of scancode - * @flags: allows to specify how kernel should handle the request. For - * example, setting INPUT_KEYMAP_BY_INDEX flag indicates that kernel - * should perform lookup in keymap by @index instead of @scancode - * @keycode: key code assigned to this scancode - * - * The structure is used to retrieve and modify keymap data. Users have - * option of performing lookup either by @scancode itself or by @index - * in keymap entry. EVIOCGKEYCODE will also return scancode or index - * (depending on which element was used to perform lookup). - */ -struct input_keymap_entry { -#define INPUT_KEYMAP_BY_INDEX (1 << 0) - __u8 flags; - __u8 len; - __u16 index; - __u32 keycode; - __u8 scancode[32]; -}; - -struct input_mask { - __u32 type; - __u32 codes_size; - __u64 codes_ptr; -}; - -#define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */ -#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */ -#define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) /* get repeat settings */ -#define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) /* set repeat settings */ - -#define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2]) /* get keycode */ -#define EVIOCGKEYCODE_V2 _IOR('E', 0x04, struct input_keymap_entry) -#define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) /* set keycode */ -#define EVIOCSKEYCODE_V2 _IOW('E', 0x04, struct input_keymap_entry) - -#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */ -#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */ -#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */ -#define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len) /* get device properties */ - -/** - * EVIOCGMTSLOTS(len) - get MT slot values - * @len: size of the data buffer in bytes - * - * The ioctl buffer argument should be binary equivalent to - * - * struct input_mt_request_layout { - * __u32 code; - * __s32 values[num_slots]; - * }; - * - * where num_slots is the (arbitrary) number of MT slots to extract. - * - * The ioctl size argument (len) is the size of the buffer, which - * should satisfy len = (num_slots + 1) * sizeof(__s32). If len is - * too small to fit all available slots, the first num_slots are - * returned. - * - * Before the call, code is set to the wanted ABS_MT event type. On - * return, values[] is filled with the slot values for the specified - * ABS_MT code. - * - * If the request code is not an ABS_MT value, -EINVAL is returned. - */ -#define EVIOCGMTSLOTS(len) _IOC(_IOC_READ, 'E', 0x0a, len) - -#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global key state */ -#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */ -#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */ -#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */ - -#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + (ev), len) /* get event bits */ -#define EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo) /* get abs value/limits */ -#define EVIOCSABS(abs) _IOW('E', 0xc0 + (abs), struct input_absinfo) /* set abs value/limits */ - -#define EVIOCSFF _IOW('E', 0x80, struct ff_effect) /* send a force effect to a force feedback device */ -#define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */ -#define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */ - -#define EVIOCGRAB _IOW('E', 0x90, int) /* Grab/Release device */ -#define EVIOCREVOKE _IOW('E', 0x91, int) /* Revoke device access */ - -/** - * EVIOCGMASK - Retrieve current event mask - * - * This ioctl allows user to retrieve the current event mask for specific - * event type. The argument must be of type "struct input_mask" and - * specifies the event type to query, the address of the receive buffer and - * the size of the receive buffer. - * - * The event mask is a per-client mask that specifies which events are - * forwarded to the client. Each event code is represented by a single bit - * in the event mask. If the bit is set, the event is passed to the client - * normally. Otherwise, the event is filtered and will never be queued on - * the client's receive buffer. - * - * Event masks do not affect global state of the input device. They only - * affect the file descriptor they are applied to. - * - * The default event mask for a client has all bits set, i.e. all events - * are forwarded to the client. If the kernel is queried for an unknown - * event type or if the receive buffer is larger than the number of - * event codes known to the kernel, the kernel returns all zeroes for those - * codes. - * - * At maximum, codes_size bytes are copied. - * - * This ioctl may fail with ENODEV in case the file is revoked, EFAULT - * if the receive-buffer points to invalid memory, or EINVAL if the kernel - * does not implement the ioctl. - */ -#define EVIOCGMASK _IOR('E', 0x92, struct input_mask) /* Get event-masks */ - -/** - * EVIOCSMASK - Set event mask - * - * This ioctl is the counterpart to EVIOCGMASK. Instead of receiving the - * current event mask, this changes the client's event mask for a specific - * type. See EVIOCGMASK for a description of event-masks and the - * argument-type. - * - * This ioctl provides full forward compatibility. If the passed event type - * is unknown to the kernel, or if the number of event codes specified in - * the mask is bigger than what is known to the kernel, the ioctl is still - * accepted and applied. However, any unknown codes are left untouched and - * stay cleared. That means, the kernel always filters unknown codes - * regardless of what the client requests. If the new mask doesn't cover - * all known event-codes, all remaining codes are automatically cleared and - * thus filtered. - * - * This ioctl may fail with ENODEV in case the file is revoked. EFAULT is - * returned if the receive-buffer points to invalid memory. EINVAL is returned - * if the kernel does not implement the ioctl. - */ -#define EVIOCSMASK _IOW('E', 0x93, struct input_mask) /* Set event-masks */ - -#define EVIOCSCLOCKID _IOW('E', 0xa0, int) /* Set clockid to be used for timestamps */ - -/* - * IDs. - */ - -#define ID_BUS 0 -#define ID_VENDOR 1 -#define ID_PRODUCT 2 -#define ID_VERSION 3 - -#define BUS_PCI 0x01 -#define BUS_ISAPNP 0x02 -#define BUS_USB 0x03 -#define BUS_HIL 0x04 -#define BUS_BLUETOOTH 0x05 -#define BUS_VIRTUAL 0x06 - -#define BUS_ISA 0x10 -#define BUS_I8042 0x11 -#define BUS_XTKBD 0x12 -#define BUS_RS232 0x13 -#define BUS_GAMEPORT 0x14 -#define BUS_PARPORT 0x15 -#define BUS_AMIGA 0x16 -#define BUS_ADB 0x17 -#define BUS_I2C 0x18 -#define BUS_HOST 0x19 -#define BUS_GSC 0x1A -#define BUS_ATARI 0x1B -#define BUS_SPI 0x1C -#define BUS_RMI 0x1D -#define BUS_CEC 0x1E -#define BUS_INTEL_ISHTP 0x1F - -/* - * MT_TOOL types - */ -#define MT_TOOL_FINGER 0 -#define MT_TOOL_PEN 1 -#define MT_TOOL_PALM 2 -#define MT_TOOL_MAX 2 - -/* - * Values describing the status of a force-feedback effect - */ -#define FF_STATUS_STOPPED 0x00 -#define FF_STATUS_PLAYING 0x01 -#define FF_STATUS_MAX 0x01 - -/* - * Structures used in ioctls to upload effects to a device - * They are pieces of a bigger structure (called ff_effect) - */ - -/* - * All duration values are expressed in ms. Values above 32767 ms (0x7fff) - * should not be used and have unspecified results. - */ - -/** - * struct ff_replay - defines scheduling of the force-feedback effect - * @length: duration of the effect - * @delay: delay before effect should start playing - */ -struct ff_replay { - __u16 length; - __u16 delay; -}; - -/** - * struct ff_trigger - defines what triggers the force-feedback effect - * @button: number of the button triggering the effect - * @interval: controls how soon the effect can be re-triggered - */ -struct ff_trigger { - __u16 button; - __u16 interval; -}; - -/** - * struct ff_envelope - generic force-feedback effect envelope - * @attack_length: duration of the attack (ms) - * @attack_level: level at the beginning of the attack - * @fade_length: duration of fade (ms) - * @fade_level: level at the end of fade - * - * The @attack_level and @fade_level are absolute values; when applying - * envelope force-feedback core will convert to positive/negative - * value based on polarity of the default level of the effect. - * Valid range for the attack and fade levels is 0x0000 - 0x7fff - */ -struct ff_envelope { - __u16 attack_length; - __u16 attack_level; - __u16 fade_length; - __u16 fade_level; -}; - -/** - * struct ff_constant_effect - defines parameters of a constant force-feedback effect - * @level: strength of the effect; may be negative - * @envelope: envelope data - */ -struct ff_constant_effect { - __s16 level; - struct ff_envelope envelope; -}; - -/** - * struct ff_ramp_effect - defines parameters of a ramp force-feedback effect - * @start_level: beginning strength of the effect; may be negative - * @end_level: final strength of the effect; may be negative - * @envelope: envelope data - */ -struct ff_ramp_effect { - __s16 start_level; - __s16 end_level; - struct ff_envelope envelope; -}; - -/** - * struct ff_condition_effect - defines a spring or friction force-feedback effect - * @right_saturation: maximum level when joystick moved all way to the right - * @left_saturation: same for the left side - * @right_coeff: controls how fast the force grows when the joystick moves - * to the right - * @left_coeff: same for the left side - * @deadband: size of the dead zone, where no force is produced - * @center: position of the dead zone - */ -struct ff_condition_effect { - __u16 right_saturation; - __u16 left_saturation; - - __s16 right_coeff; - __s16 left_coeff; - - __u16 deadband; - __s16 center; -}; - -/** - * struct ff_periodic_effect - defines parameters of a periodic force-feedback effect - * @waveform: kind of the effect (wave) - * @period: period of the wave (ms) - * @magnitude: peak value - * @offset: mean value of the wave (roughly) - * @phase: 'horizontal' shift - * @envelope: envelope data - * @custom_len: number of samples (FF_CUSTOM only) - * @custom_data: buffer of samples (FF_CUSTOM only) - * - * Known waveforms - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, - * FF_SAW_DOWN, FF_CUSTOM. The exact syntax FF_CUSTOM is undefined - * for the time being as no driver supports it yet. - * - * Note: the data pointed by custom_data is copied by the driver. - * You can therefore dispose of the memory after the upload/update. - */ -struct ff_periodic_effect { - __u16 waveform; - __u16 period; - __s16 magnitude; - __s16 offset; - __u16 phase; - - struct ff_envelope envelope; - - __u32 custom_len; - __s16 __user *custom_data; -}; - -/** - * struct ff_rumble_effect - defines parameters of a periodic force-feedback effect - * @strong_magnitude: magnitude of the heavy motor - * @weak_magnitude: magnitude of the light one - * - * Some rumble pads have two motors of different weight. Strong_magnitude - * represents the magnitude of the vibration generated by the heavy one. - */ -struct ff_rumble_effect { - __u16 strong_magnitude; - __u16 weak_magnitude; -}; - -/** - * struct ff_effect - defines force feedback effect - * @type: type of the effect (FF_CONSTANT, FF_PERIODIC, FF_RAMP, FF_SPRING, - * FF_FRICTION, FF_DAMPER, FF_RUMBLE, FF_INERTIA, or FF_CUSTOM) - * @id: an unique id assigned to an effect - * @direction: direction of the effect - * @trigger: trigger conditions (struct ff_trigger) - * @replay: scheduling of the effect (struct ff_replay) - * @u: effect-specific structure (one of ff_constant_effect, ff_ramp_effect, - * ff_periodic_effect, ff_condition_effect, ff_rumble_effect) further - * defining effect parameters - * - * This structure is sent through ioctl from the application to the driver. - * To create a new effect application should set its @id to -1; the kernel - * will return assigned @id which can later be used to update or delete - * this effect. - * - * Direction of the effect is encoded as follows: - * 0 deg -> 0x0000 (down) - * 90 deg -> 0x4000 (left) - * 180 deg -> 0x8000 (up) - * 270 deg -> 0xC000 (right) - */ -struct ff_effect { - __u16 type; - __s16 id; - __u16 direction; - struct ff_trigger trigger; - struct ff_replay replay; - - union { - struct ff_constant_effect constant; - struct ff_ramp_effect ramp; - struct ff_periodic_effect periodic; - struct ff_condition_effect condition[2]; /* One for each axis */ - struct ff_rumble_effect rumble; - } u; -}; - -/* - * Force feedback effect types - */ - -#define FF_RUMBLE 0x50 -#define FF_PERIODIC 0x51 -#define FF_CONSTANT 0x52 -#define FF_SPRING 0x53 -#define FF_FRICTION 0x54 -#define FF_DAMPER 0x55 -#define FF_INERTIA 0x56 -#define FF_RAMP 0x57 - -#define FF_EFFECT_MIN FF_RUMBLE -#define FF_EFFECT_MAX FF_RAMP - -/* - * Force feedback periodic effect types - */ - -#define FF_SQUARE 0x58 -#define FF_TRIANGLE 0x59 -#define FF_SINE 0x5a -#define FF_SAW_UP 0x5b -#define FF_SAW_DOWN 0x5c -#define FF_CUSTOM 0x5d - -#define FF_WAVEFORM_MIN FF_SQUARE -#define FF_WAVEFORM_MAX FF_CUSTOM - -/* - * Set ff device properties - */ - -#define FF_GAIN 0x60 -#define FF_AUTOCENTER 0x61 - -/* - * ff->playback(effect_id = FF_GAIN) is the first effect_id to - * cause a collision with another ff method, in this case ff->set_gain(). - * Therefore the greatest safe value for effect_id is FF_GAIN - 1, - * and thus the total number of effects should never exceed FF_GAIN. - */ -#define FF_MAX_EFFECTS FF_GAIN - -#define FF_MAX 0x7f -#define FF_CNT (FF_MAX+1) - -#endif /* _UAPI_INPUT_H */ diff --git a/src/linux/include/uapi/linux/ioctl.h b/src/linux/include/uapi/linux/ioctl.h deleted file mode 100644 index aa91eb3..0000000 --- a/src/linux/include/uapi/linux/ioctl.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _LINUX_IOCTL_H -#define _LINUX_IOCTL_H - -#include - -#endif /* _LINUX_IOCTL_H */ - diff --git a/src/linux/include/uapi/linux/ip.h b/src/linux/include/uapi/linux/ip.h deleted file mode 100644 index f291569..0000000 --- a/src/linux/include/uapi/linux/ip.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the IP protocol. - * - * Version: @(#)ip.h 1.0.2 04/28/93 - * - * Authors: Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _UAPI_LINUX_IP_H -#define _UAPI_LINUX_IP_H -#include -#include - -#define IPTOS_TOS_MASK 0x1E -#define IPTOS_TOS(tos) ((tos)&IPTOS_TOS_MASK) -#define IPTOS_LOWDELAY 0x10 -#define IPTOS_THROUGHPUT 0x08 -#define IPTOS_RELIABILITY 0x04 -#define IPTOS_MINCOST 0x02 - -#define IPTOS_PREC_MASK 0xE0 -#define IPTOS_PREC(tos) ((tos)&IPTOS_PREC_MASK) -#define IPTOS_PREC_NETCONTROL 0xe0 -#define IPTOS_PREC_INTERNETCONTROL 0xc0 -#define IPTOS_PREC_CRITIC_ECP 0xa0 -#define IPTOS_PREC_FLASHOVERRIDE 0x80 -#define IPTOS_PREC_FLASH 0x60 -#define IPTOS_PREC_IMMEDIATE 0x40 -#define IPTOS_PREC_PRIORITY 0x20 -#define IPTOS_PREC_ROUTINE 0x00 - - -/* IP options */ -#define IPOPT_COPY 0x80 -#define IPOPT_CLASS_MASK 0x60 -#define IPOPT_NUMBER_MASK 0x1f - -#define IPOPT_COPIED(o) ((o)&IPOPT_COPY) -#define IPOPT_CLASS(o) ((o)&IPOPT_CLASS_MASK) -#define IPOPT_NUMBER(o) ((o)&IPOPT_NUMBER_MASK) - -#define IPOPT_CONTROL 0x00 -#define IPOPT_RESERVED1 0x20 -#define IPOPT_MEASUREMENT 0x40 -#define IPOPT_RESERVED2 0x60 - -#define IPOPT_END (0 |IPOPT_CONTROL) -#define IPOPT_NOOP (1 |IPOPT_CONTROL) -#define IPOPT_SEC (2 |IPOPT_CONTROL|IPOPT_COPY) -#define IPOPT_LSRR (3 |IPOPT_CONTROL|IPOPT_COPY) -#define IPOPT_TIMESTAMP (4 |IPOPT_MEASUREMENT) -#define IPOPT_CIPSO (6 |IPOPT_CONTROL|IPOPT_COPY) -#define IPOPT_RR (7 |IPOPT_CONTROL) -#define IPOPT_SID (8 |IPOPT_CONTROL|IPOPT_COPY) -#define IPOPT_SSRR (9 |IPOPT_CONTROL|IPOPT_COPY) -#define IPOPT_RA (20|IPOPT_CONTROL|IPOPT_COPY) - -#define IPVERSION 4 -#define MAXTTL 255 -#define IPDEFTTL 64 - -#define IPOPT_OPTVAL 0 -#define IPOPT_OLEN 1 -#define IPOPT_OFFSET 2 -#define IPOPT_MINOFF 4 -#define MAX_IPOPTLEN 40 -#define IPOPT_NOP IPOPT_NOOP -#define IPOPT_EOL IPOPT_END -#define IPOPT_TS IPOPT_TIMESTAMP - -#define IPOPT_TS_TSONLY 0 /* timestamps only */ -#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ -#define IPOPT_TS_PRESPEC 3 /* specified modules only */ - -#define IPV4_BEET_PHMAXLEN 8 - -struct iphdr { -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 ihl:4, - version:4; -#elif defined (__BIG_ENDIAN_BITFIELD) - __u8 version:4, - ihl:4; -#else -#error "Please fix " -#endif - __u8 tos; - __be16 tot_len; - __be16 id; - __be16 frag_off; - __u8 ttl; - __u8 protocol; - __sum16 check; - __be32 saddr; - __be32 daddr; - /*The options start here. */ -}; - - -struct ip_auth_hdr { - __u8 nexthdr; - __u8 hdrlen; /* This one is measured in 32 bit units! */ - __be16 reserved; - __be32 spi; - __be32 seq_no; /* Sequence number */ - __u8 auth_data[0]; /* Variable len but >=4. Mind the 64 bit alignment! */ -}; - -struct ip_esp_hdr { - __be32 spi; - __be32 seq_no; /* Sequence number */ - __u8 enc_data[0]; /* Variable len but >=8. Mind the 64 bit alignment! */ -}; - -struct ip_comp_hdr { - __u8 nexthdr; - __u8 flags; - __be16 cpi; -}; - -struct ip_beet_phdr { - __u8 nexthdr; - __u8 hdrlen; - __u8 padlen; - __u8 reserved; -}; - -/* index values for the variables in ipv4_devconf */ -enum -{ - IPV4_DEVCONF_FORWARDING=1, - IPV4_DEVCONF_MC_FORWARDING, - IPV4_DEVCONF_PROXY_ARP, - IPV4_DEVCONF_ACCEPT_REDIRECTS, - IPV4_DEVCONF_SECURE_REDIRECTS, - IPV4_DEVCONF_SEND_REDIRECTS, - IPV4_DEVCONF_SHARED_MEDIA, - IPV4_DEVCONF_RP_FILTER, - IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE, - IPV4_DEVCONF_BOOTP_RELAY, - IPV4_DEVCONF_LOG_MARTIANS, - IPV4_DEVCONF_TAG, - IPV4_DEVCONF_ARPFILTER, - IPV4_DEVCONF_MEDIUM_ID, - IPV4_DEVCONF_NOXFRM, - IPV4_DEVCONF_NOPOLICY, - IPV4_DEVCONF_FORCE_IGMP_VERSION, - IPV4_DEVCONF_ARP_ANNOUNCE, - IPV4_DEVCONF_ARP_IGNORE, - IPV4_DEVCONF_PROMOTE_SECONDARIES, - IPV4_DEVCONF_ARP_ACCEPT, - IPV4_DEVCONF_ARP_NOTIFY, - IPV4_DEVCONF_ACCEPT_LOCAL, - IPV4_DEVCONF_SRC_VMARK, - IPV4_DEVCONF_PROXY_ARP_PVLAN, - IPV4_DEVCONF_ROUTE_LOCALNET, - IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL, - IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL, - IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN, - IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST, - IPV4_DEVCONF_DROP_GRATUITOUS_ARP, - __IPV4_DEVCONF_MAX -}; - -#define IPV4_DEVCONF_MAX (__IPV4_DEVCONF_MAX - 1) - -#endif /* _UAPI_LINUX_IP_H */ diff --git a/src/linux/include/uapi/linux/ip6_tunnel.h b/src/linux/include/uapi/linux/ip6_tunnel.h deleted file mode 100644 index 48af63c..0000000 --- a/src/linux/include/uapi/linux/ip6_tunnel.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef _IP6_TUNNEL_H -#define _IP6_TUNNEL_H - -#include - -#define IPV6_TLV_TNL_ENCAP_LIMIT 4 -#define IPV6_DEFAULT_TNL_ENCAP_LIMIT 4 - -/* don't add encapsulation limit if one isn't present in inner packet */ -#define IP6_TNL_F_IGN_ENCAP_LIMIT 0x1 -/* copy the traffic class field from the inner packet */ -#define IP6_TNL_F_USE_ORIG_TCLASS 0x2 -/* copy the flowlabel from the inner packet */ -#define IP6_TNL_F_USE_ORIG_FLOWLABEL 0x4 -/* being used for Mobile IPv6 */ -#define IP6_TNL_F_MIP6_DEV 0x8 -/* copy DSCP from the outer packet */ -#define IP6_TNL_F_RCV_DSCP_COPY 0x10 -/* copy fwmark from inner packet */ -#define IP6_TNL_F_USE_ORIG_FWMARK 0x20 - -struct ip6_tnl_parm { - char name[IFNAMSIZ]; /* name of tunnel device */ - int link; /* ifindex of underlying L2 interface */ - __u8 proto; /* tunnel protocol */ - __u8 encap_limit; /* encapsulation limit for tunnel */ - __u8 hop_limit; /* hop limit for tunnel */ - __be32 flowinfo; /* traffic class and flowlabel for tunnel */ - __u32 flags; /* tunnel flags */ - struct in6_addr laddr; /* local tunnel end-point address */ - struct in6_addr raddr; /* remote tunnel end-point address */ -}; - -struct ip6_tnl_parm2 { - char name[IFNAMSIZ]; /* name of tunnel device */ - int link; /* ifindex of underlying L2 interface */ - __u8 proto; /* tunnel protocol */ - __u8 encap_limit; /* encapsulation limit for tunnel */ - __u8 hop_limit; /* hop limit for tunnel */ - __be32 flowinfo; /* traffic class and flowlabel for tunnel */ - __u32 flags; /* tunnel flags */ - struct in6_addr laddr; /* local tunnel end-point address */ - struct in6_addr raddr; /* remote tunnel end-point address */ - - __be16 i_flags; - __be16 o_flags; - __be32 i_key; - __be32 o_key; -}; - -#endif diff --git a/src/linux/include/uapi/linux/ipc.h b/src/linux/include/uapi/linux/ipc.h deleted file mode 100644 index de08dd4..0000000 --- a/src/linux/include/uapi/linux/ipc.h +++ /dev/null @@ -1,81 +0,0 @@ -#ifndef _UAPI_LINUX_IPC_H -#define _UAPI_LINUX_IPC_H - -#include - -#define IPC_PRIVATE ((__kernel_key_t) 0) - -/* Obsolete, used only for backwards compatibility and libc5 compiles */ -struct ipc_perm -{ - __kernel_key_t key; - __kernel_uid_t uid; - __kernel_gid_t gid; - __kernel_uid_t cuid; - __kernel_gid_t cgid; - __kernel_mode_t mode; - unsigned short seq; -}; - -/* Include the definition of ipc64_perm */ -#include - -/* resource get request flags */ -#define IPC_CREAT 00001000 /* create if key is nonexistent */ -#define IPC_EXCL 00002000 /* fail if key exists */ -#define IPC_NOWAIT 00004000 /* return error on wait */ - -/* these fields are used by the DIPC package so the kernel as standard - should avoid using them if possible */ - -#define IPC_DIPC 00010000 /* make it distributed */ -#define IPC_OWN 00020000 /* this machine is the DIPC owner */ - -/* - * Control commands used with semctl, msgctl and shmctl - * see also specific commands in sem.h, msg.h and shm.h - */ -#define IPC_RMID 0 /* remove resource */ -#define IPC_SET 1 /* set ipc_perm options */ -#define IPC_STAT 2 /* get ipc_perm options */ -#define IPC_INFO 3 /* see ipcs */ - -/* - * Version flags for semctl, msgctl, and shmctl commands - * These are passed as bitflags or-ed with the actual command - */ -#define IPC_OLD 0 /* Old version (no 32-bit UID support on many - architectures) */ -#define IPC_64 0x0100 /* New version (support 32-bit UIDs, bigger - message sizes, etc. */ - -/* - * These are used to wrap system calls. - * - * See architecture code for ugly details.. - */ -struct ipc_kludge { - struct msgbuf __user *msgp; - long msgtyp; -}; - -#define SEMOP 1 -#define SEMGET 2 -#define SEMCTL 3 -#define SEMTIMEDOP 4 -#define MSGSND 11 -#define MSGRCV 12 -#define MSGGET 13 -#define MSGCTL 14 -#define SHMAT 21 -#define SHMDT 22 -#define SHMGET 23 -#define SHMCTL 24 - -/* Used by the DIPC package, try and avoid reusing it */ -#define DIPC 25 - -#define IPCCALL(version,op) ((version)<<16 | (op)) - - -#endif /* _UAPI_LINUX_IPC_H */ diff --git a/src/linux/include/uapi/linux/ipsec.h b/src/linux/include/uapi/linux/ipsec.h deleted file mode 100644 index d17a630..0000000 --- a/src/linux/include/uapi/linux/ipsec.h +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef _LINUX_IPSEC_H -#define _LINUX_IPSEC_H - -/* The definitions, required to talk to KAME racoon IKE. */ - -#include - -#define IPSEC_PORT_ANY 0 -#define IPSEC_ULPROTO_ANY 255 -#define IPSEC_PROTO_ANY 255 - -enum { - IPSEC_MODE_ANY = 0, /* We do not support this for SA */ - IPSEC_MODE_TRANSPORT = 1, - IPSEC_MODE_TUNNEL = 2, - IPSEC_MODE_BEET = 3 -}; - -enum { - IPSEC_DIR_ANY = 0, - IPSEC_DIR_INBOUND = 1, - IPSEC_DIR_OUTBOUND = 2, - IPSEC_DIR_FWD = 3, /* It is our own */ - IPSEC_DIR_MAX = 4, - IPSEC_DIR_INVALID = 5 -}; - -enum { - IPSEC_POLICY_DISCARD = 0, - IPSEC_POLICY_NONE = 1, - IPSEC_POLICY_IPSEC = 2, - IPSEC_POLICY_ENTRUST = 3, - IPSEC_POLICY_BYPASS = 4 -}; - -enum { - IPSEC_LEVEL_DEFAULT = 0, - IPSEC_LEVEL_USE = 1, - IPSEC_LEVEL_REQUIRE = 2, - IPSEC_LEVEL_UNIQUE = 3 -}; - -#define IPSEC_MANUAL_REQID_MAX 0x3fff - -#define IPSEC_REPLAYWSIZE 32 - -#endif /* _LINUX_IPSEC_H */ diff --git a/src/linux/include/uapi/linux/ipv6.h b/src/linux/include/uapi/linux/ipv6.h deleted file mode 100644 index 8c27723..0000000 --- a/src/linux/include/uapi/linux/ipv6.h +++ /dev/null @@ -1,185 +0,0 @@ -#ifndef _UAPI_IPV6_H -#define _UAPI_IPV6_H - -#include -#include -#include -#include - -/* The latest drafts declared increase in minimal mtu up to 1280. */ - -#define IPV6_MIN_MTU 1280 - -/* - * Advanced API - * source interface/address selection, source routing, etc... - * *under construction* - */ - -#if __UAPI_DEF_IN6_PKTINFO -struct in6_pktinfo { - struct in6_addr ipi6_addr; - int ipi6_ifindex; -}; -#endif - -#if __UAPI_DEF_IP6_MTUINFO -struct ip6_mtuinfo { - struct sockaddr_in6 ip6m_addr; - __u32 ip6m_mtu; -}; -#endif - -struct in6_ifreq { - struct in6_addr ifr6_addr; - __u32 ifr6_prefixlen; - int ifr6_ifindex; -}; - -#define IPV6_SRCRT_STRICT 0x01 /* Deprecated; will be removed */ -#define IPV6_SRCRT_TYPE_0 0 /* Deprecated; will be removed */ -#define IPV6_SRCRT_TYPE_2 2 /* IPv6 type 2 Routing Header */ - -/* - * routing header - */ -struct ipv6_rt_hdr { - __u8 nexthdr; - __u8 hdrlen; - __u8 type; - __u8 segments_left; - - /* - * type specific data - * variable length field - */ -}; - - -struct ipv6_opt_hdr { - __u8 nexthdr; - __u8 hdrlen; - /* - * TLV encoded option data follows. - */ -} __attribute__((packed)); /* required for some archs */ - -#define ipv6_destopt_hdr ipv6_opt_hdr -#define ipv6_hopopt_hdr ipv6_opt_hdr - -/* Router Alert option values (RFC2711) */ -#define IPV6_OPT_ROUTERALERT_MLD 0x0000 /* MLD(RFC2710) */ - -/* - * routing header type 0 (used in cmsghdr struct) - */ - -struct rt0_hdr { - struct ipv6_rt_hdr rt_hdr; - __u32 reserved; - struct in6_addr addr[0]; - -#define rt0_type rt_hdr.type -}; - -/* - * routing header type 2 - */ - -struct rt2_hdr { - struct ipv6_rt_hdr rt_hdr; - __u32 reserved; - struct in6_addr addr; - -#define rt2_type rt_hdr.type -}; - -/* - * home address option in destination options header - */ - -struct ipv6_destopt_hao { - __u8 type; - __u8 length; - struct in6_addr addr; -} __attribute__((packed)); - -/* - * IPv6 fixed header - * - * BEWARE, it is incorrect. The first 4 bits of flow_lbl - * are glued to priority now, forming "class". - */ - -struct ipv6hdr { -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u8 priority:4, - version:4; -#elif defined(__BIG_ENDIAN_BITFIELD) - __u8 version:4, - priority:4; -#else -#error "Please fix " -#endif - __u8 flow_lbl[3]; - - __be16 payload_len; - __u8 nexthdr; - __u8 hop_limit; - - struct in6_addr saddr; - struct in6_addr daddr; -}; - - -/* index values for the variables in ipv6_devconf */ -enum { - DEVCONF_FORWARDING = 0, - DEVCONF_HOPLIMIT, - DEVCONF_MTU6, - DEVCONF_ACCEPT_RA, - DEVCONF_ACCEPT_REDIRECTS, - DEVCONF_AUTOCONF, - DEVCONF_DAD_TRANSMITS, - DEVCONF_RTR_SOLICITS, - DEVCONF_RTR_SOLICIT_INTERVAL, - DEVCONF_RTR_SOLICIT_DELAY, - DEVCONF_USE_TEMPADDR, - DEVCONF_TEMP_VALID_LFT, - DEVCONF_TEMP_PREFERED_LFT, - DEVCONF_REGEN_MAX_RETRY, - DEVCONF_MAX_DESYNC_FACTOR, - DEVCONF_MAX_ADDRESSES, - DEVCONF_FORCE_MLD_VERSION, - DEVCONF_ACCEPT_RA_DEFRTR, - DEVCONF_ACCEPT_RA_PINFO, - DEVCONF_ACCEPT_RA_RTR_PREF, - DEVCONF_RTR_PROBE_INTERVAL, - DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN, - DEVCONF_PROXY_NDP, - DEVCONF_OPTIMISTIC_DAD, - DEVCONF_ACCEPT_SOURCE_ROUTE, - DEVCONF_MC_FORWARDING, - DEVCONF_DISABLE_IPV6, - DEVCONF_ACCEPT_DAD, - DEVCONF_FORCE_TLLAO, - DEVCONF_NDISC_NOTIFY, - DEVCONF_MLDV1_UNSOLICITED_REPORT_INTERVAL, - DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL, - DEVCONF_SUPPRESS_FRAG_NDISC, - DEVCONF_ACCEPT_RA_FROM_LOCAL, - DEVCONF_USE_OPTIMISTIC, - DEVCONF_ACCEPT_RA_MTU, - DEVCONF_STABLE_SECRET, - DEVCONF_USE_OIF_ADDRS_ONLY, - DEVCONF_ACCEPT_RA_MIN_HOP_LIMIT, - DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN, - DEVCONF_DROP_UNICAST_IN_L2_MULTICAST, - DEVCONF_DROP_UNSOLICITED_NA, - DEVCONF_KEEP_ADDR_ON_DOWN, - DEVCONF_RTR_SOLICIT_MAX_INTERVAL, - DEVCONF_MAX -}; - - -#endif /* _UAPI_IPV6_H */ diff --git a/src/linux/include/uapi/linux/ipv6_route.h b/src/linux/include/uapi/linux/ipv6_route.h deleted file mode 100644 index f6598d1..0000000 --- a/src/linux/include/uapi/linux/ipv6_route.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _UAPI_LINUX_IPV6_ROUTE_H -#define _UAPI_LINUX_IPV6_ROUTE_H - -#include - -#define RTF_DEFAULT 0x00010000 /* default - learned via ND */ -#define RTF_ALLONLINK 0x00020000 /* (deprecated and will be removed) - fallback, no routers on link */ -#define RTF_ADDRCONF 0x00040000 /* addrconf route - RA */ -#define RTF_PREFIX_RT 0x00080000 /* A prefix only route - RA */ -#define RTF_ANYCAST 0x00100000 /* Anycast */ - -#define RTF_NONEXTHOP 0x00200000 /* route with no nexthop */ -#define RTF_EXPIRES 0x00400000 - -#define RTF_ROUTEINFO 0x00800000 /* route information - RA */ - -#define RTF_CACHE 0x01000000 /* cache entry */ -#define RTF_FLOW 0x02000000 /* flow significant route */ -#define RTF_POLICY 0x04000000 /* policy route */ - -#define RTF_PREF(pref) ((pref) << 27) -#define RTF_PREF_MASK 0x18000000 - -#define RTF_PCPU 0x40000000 -#define RTF_LOCAL 0x80000000 - - -struct in6_rtmsg { - struct in6_addr rtmsg_dst; - struct in6_addr rtmsg_src; - struct in6_addr rtmsg_gateway; - __u32 rtmsg_type; - __u16 rtmsg_dst_len; - __u16 rtmsg_src_len; - __u32 rtmsg_metric; - unsigned long rtmsg_info; - __u32 rtmsg_flags; - int rtmsg_ifindex; -}; - -#define RTMSG_NEWDEVICE 0x11 -#define RTMSG_DELDEVICE 0x12 -#define RTMSG_NEWROUTE 0x21 -#define RTMSG_DELROUTE 0x22 - -#define IP6_RT_PRIO_USER 1024 -#define IP6_RT_PRIO_ADDRCONF 256 - -#endif /* _UAPI_LINUX_IPV6_ROUTE_H */ diff --git a/src/linux/include/uapi/linux/irqnr.h b/src/linux/include/uapi/linux/irqnr.h deleted file mode 100644 index ae5704f..0000000 --- a/src/linux/include/uapi/linux/irqnr.h +++ /dev/null @@ -1,4 +0,0 @@ -/* - * There isn't anything here anymore, but the file must not be empty or patch - * will delete it. - */ diff --git a/src/linux/include/uapi/linux/kcov.h b/src/linux/include/uapi/linux/kcov.h deleted file mode 100644 index 574e22e..0000000 --- a/src/linux/include/uapi/linux/kcov.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _LINUX_KCOV_IOCTLS_H -#define _LINUX_KCOV_IOCTLS_H - -#include - -#define KCOV_INIT_TRACE _IOR('c', 1, unsigned long) -#define KCOV_ENABLE _IO('c', 100) -#define KCOV_DISABLE _IO('c', 101) - -#endif /* _LINUX_KCOV_IOCTLS_H */ diff --git a/src/linux/include/uapi/linux/kd.h b/src/linux/include/uapi/linux/kd.h deleted file mode 100644 index 87b7cc4..0000000 --- a/src/linux/include/uapi/linux/kd.h +++ /dev/null @@ -1,183 +0,0 @@ -#ifndef _UAPI_LINUX_KD_H -#define _UAPI_LINUX_KD_H -#include -#include - -/* 0x4B is 'K', to avoid collision with termios and vt */ - -#define GIO_FONT 0x4B60 /* gets font in expanded form */ -#define PIO_FONT 0x4B61 /* use font in expanded form */ - -#define GIO_FONTX 0x4B6B /* get font using struct consolefontdesc */ -#define PIO_FONTX 0x4B6C /* set font using struct consolefontdesc */ -struct consolefontdesc { - unsigned short charcount; /* characters in font (256 or 512) */ - unsigned short charheight; /* scan lines per character (1-32) */ - char __user *chardata; /* font data in expanded form */ -}; - -#define PIO_FONTRESET 0x4B6D /* reset to default font */ - -#define GIO_CMAP 0x4B70 /* gets colour palette on VGA+ */ -#define PIO_CMAP 0x4B71 /* sets colour palette on VGA+ */ - -#define KIOCSOUND 0x4B2F /* start sound generation (0 for off) */ -#define KDMKTONE 0x4B30 /* generate tone */ - -#define KDGETLED 0x4B31 /* return current led state */ -#define KDSETLED 0x4B32 /* set led state [lights, not flags] */ -#define LED_SCR 0x01 /* scroll lock led */ -#define LED_NUM 0x02 /* num lock led */ -#define LED_CAP 0x04 /* caps lock led */ - -#define KDGKBTYPE 0x4B33 /* get keyboard type */ -#define KB_84 0x01 -#define KB_101 0x02 /* this is what we always answer */ -#define KB_OTHER 0x03 - -#define KDADDIO 0x4B34 /* add i/o port as valid */ -#define KDDELIO 0x4B35 /* del i/o port as valid */ -#define KDENABIO 0x4B36 /* enable i/o to video board */ -#define KDDISABIO 0x4B37 /* disable i/o to video board */ - -#define KDSETMODE 0x4B3A /* set text/graphics mode */ -#define KD_TEXT 0x00 -#define KD_GRAPHICS 0x01 -#define KD_TEXT0 0x02 /* obsolete */ -#define KD_TEXT1 0x03 /* obsolete */ -#define KDGETMODE 0x4B3B /* get current mode */ - -#define KDMAPDISP 0x4B3C /* map display into address space */ -#define KDUNMAPDISP 0x4B3D /* unmap display from address space */ - -typedef char scrnmap_t; -#define E_TABSZ 256 -#define GIO_SCRNMAP 0x4B40 /* get screen mapping from kernel */ -#define PIO_SCRNMAP 0x4B41 /* put screen mapping table in kernel */ -#define GIO_UNISCRNMAP 0x4B69 /* get full Unicode screen mapping */ -#define PIO_UNISCRNMAP 0x4B6A /* set full Unicode screen mapping */ - -#define GIO_UNIMAP 0x4B66 /* get unicode-to-font mapping from kernel */ -struct unipair { - unsigned short unicode; - unsigned short fontpos; -}; -struct unimapdesc { - unsigned short entry_ct; - struct unipair __user *entries; -}; -#define PIO_UNIMAP 0x4B67 /* put unicode-to-font mapping in kernel */ -#define PIO_UNIMAPCLR 0x4B68 /* clear table, possibly advise hash algorithm */ -struct unimapinit { - unsigned short advised_hashsize; /* 0 if no opinion */ - unsigned short advised_hashstep; /* 0 if no opinion */ - unsigned short advised_hashlevel; /* 0 if no opinion */ -}; - -#define UNI_DIRECT_BASE 0xF000 /* start of Direct Font Region */ -#define UNI_DIRECT_MASK 0x01FF /* Direct Font Region bitmask */ - -#define K_RAW 0x00 -#define K_XLATE 0x01 -#define K_MEDIUMRAW 0x02 -#define K_UNICODE 0x03 -#define K_OFF 0x04 -#define KDGKBMODE 0x4B44 /* gets current keyboard mode */ -#define KDSKBMODE 0x4B45 /* sets current keyboard mode */ - -#define K_METABIT 0x03 -#define K_ESCPREFIX 0x04 -#define KDGKBMETA 0x4B62 /* gets meta key handling mode */ -#define KDSKBMETA 0x4B63 /* sets meta key handling mode */ - -#define K_SCROLLLOCK 0x01 -#define K_NUMLOCK 0x02 -#define K_CAPSLOCK 0x04 -#define KDGKBLED 0x4B64 /* get led flags (not lights) */ -#define KDSKBLED 0x4B65 /* set led flags (not lights) */ - -struct kbentry { - unsigned char kb_table; - unsigned char kb_index; - unsigned short kb_value; -}; -#define K_NORMTAB 0x00 -#define K_SHIFTTAB 0x01 -#define K_ALTTAB 0x02 -#define K_ALTSHIFTTAB 0x03 - -#define KDGKBENT 0x4B46 /* gets one entry in translation table */ -#define KDSKBENT 0x4B47 /* sets one entry in translation table */ - -struct kbsentry { - unsigned char kb_func; - unsigned char kb_string[512]; -}; -#define KDGKBSENT 0x4B48 /* gets one function key string entry */ -#define KDSKBSENT 0x4B49 /* sets one function key string entry */ - -struct kbdiacr { - unsigned char diacr, base, result; -}; -struct kbdiacrs { - unsigned int kb_cnt; /* number of entries in following array */ - struct kbdiacr kbdiacr[256]; /* MAX_DIACR from keyboard.h */ -}; -#define KDGKBDIACR 0x4B4A /* read kernel accent table */ -#define KDSKBDIACR 0x4B4B /* write kernel accent table */ - -struct kbdiacruc { - unsigned int diacr, base, result; -}; -struct kbdiacrsuc { - unsigned int kb_cnt; /* number of entries in following array */ - struct kbdiacruc kbdiacruc[256]; /* MAX_DIACR from keyboard.h */ -}; -#define KDGKBDIACRUC 0x4BFA /* read kernel accent table - UCS */ -#define KDSKBDIACRUC 0x4BFB /* write kernel accent table - UCS */ - -struct kbkeycode { - unsigned int scancode, keycode; -}; -#define KDGETKEYCODE 0x4B4C /* read kernel keycode table entry */ -#define KDSETKEYCODE 0x4B4D /* write kernel keycode table entry */ - -#define KDSIGACCEPT 0x4B4E /* accept kbd generated signals */ - -struct kbd_repeat { - int delay; /* in msec; <= 0: don't change */ - int period; /* in msec; <= 0: don't change */ - /* earlier this field was misnamed "rate" */ -}; - -#define KDKBDREP 0x4B52 /* set keyboard delay/repeat rate; - * actually used values are returned */ - -#define KDFONTOP 0x4B72 /* font operations */ - -struct console_font_op { - unsigned int op; /* operation code KD_FONT_OP_* */ - unsigned int flags; /* KD_FONT_FLAG_* */ - unsigned int width, height; /* font size */ - unsigned int charcount; - unsigned char __user *data; /* font data with height fixed to 32 */ -}; - -struct console_font { - unsigned int width, height; /* font size */ - unsigned int charcount; - unsigned char *data; /* font data with height fixed to 32 */ -}; - -#define KD_FONT_OP_SET 0 /* Set font */ -#define KD_FONT_OP_GET 1 /* Get font */ -#define KD_FONT_OP_SET_DEFAULT 2 /* Set font to default, data points to name / NULL */ -#define KD_FONT_OP_COPY 3 /* Copy from another console */ - -#define KD_FONT_FLAG_DONT_RECALC 1 /* Don't recalculate hw charcell size [compat] */ - -/* note: 0x4B00-0x4B4E all have had a value at some time; - don't reuse for the time being */ -/* note: 0x4B60-0x4B6D, 0x4B70-0x4B72 used above */ - -#endif /* _UAPI_LINUX_KD_H */ diff --git a/src/linux/include/uapi/linux/kdev_t.h b/src/linux/include/uapi/linux/kdev_t.h deleted file mode 100644 index 0d881fa..0000000 --- a/src/linux/include/uapi/linux/kdev_t.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _UAPI_LINUX_KDEV_T_H -#define _UAPI_LINUX_KDEV_T_H -#ifndef __KERNEL__ - -/* -Some programs want their definitions of MAJOR and MINOR and MKDEV -from the kernel sources. These must be the externally visible ones. -*/ -#define MAJOR(dev) ((dev)>>8) -#define MINOR(dev) ((dev) & 0xff) -#define MKDEV(ma,mi) ((ma)<<8 | (mi)) -#endif /* __KERNEL__ */ -#endif /* _UAPI_LINUX_KDEV_T_H */ diff --git a/src/linux/include/uapi/linux/kernel.h b/src/linux/include/uapi/linux/kernel.h deleted file mode 100644 index 466073f..0000000 --- a/src/linux/include/uapi/linux/kernel.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _UAPI_LINUX_KERNEL_H -#define _UAPI_LINUX_KERNEL_H - -#include - -/* - * 'kernel.h' contains some often-used function prototypes etc - */ -#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1) -#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) - -#define __KERNEL_DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) - -#endif /* _UAPI_LINUX_KERNEL_H */ diff --git a/src/linux/include/uapi/linux/kexec.h b/src/linux/include/uapi/linux/kexec.h deleted file mode 100644 index aae5ebf..0000000 --- a/src/linux/include/uapi/linux/kexec.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef _UAPILINUX_KEXEC_H -#define _UAPILINUX_KEXEC_H - -/* kexec system call - It loads the new kernel to boot into. - * kexec does not sync, or unmount filesystems so if you need - * that to happen you need to do that yourself. - */ - -#include - -/* kexec flags for different usage scenarios */ -#define KEXEC_ON_CRASH 0x00000001 -#define KEXEC_PRESERVE_CONTEXT 0x00000002 -#define KEXEC_ARCH_MASK 0xffff0000 - -/* - * Kexec file load interface flags. - * KEXEC_FILE_UNLOAD : Unload already loaded kexec/kdump image. - * KEXEC_FILE_ON_CRASH : Load/unload operation belongs to kdump image. - * KEXEC_FILE_NO_INITRAMFS : No initramfs is being loaded. Ignore the initrd - * fd field. - */ -#define KEXEC_FILE_UNLOAD 0x00000001 -#define KEXEC_FILE_ON_CRASH 0x00000002 -#define KEXEC_FILE_NO_INITRAMFS 0x00000004 - -/* These values match the ELF architecture values. - * Unless there is a good reason that should continue to be the case. - */ -#define KEXEC_ARCH_DEFAULT ( 0 << 16) -#define KEXEC_ARCH_386 ( 3 << 16) -#define KEXEC_ARCH_68K ( 4 << 16) -#define KEXEC_ARCH_X86_64 (62 << 16) -#define KEXEC_ARCH_PPC (20 << 16) -#define KEXEC_ARCH_PPC64 (21 << 16) -#define KEXEC_ARCH_IA_64 (50 << 16) -#define KEXEC_ARCH_ARM (40 << 16) -#define KEXEC_ARCH_S390 (22 << 16) -#define KEXEC_ARCH_SH (42 << 16) -#define KEXEC_ARCH_MIPS_LE (10 << 16) -#define KEXEC_ARCH_MIPS ( 8 << 16) -#define KEXEC_ARCH_AARCH64 (183 << 16) - -/* The artificial cap on the number of segments passed to kexec_load. */ -#define KEXEC_SEGMENT_MAX 16 - -#ifndef __KERNEL__ -/* - * This structure is used to hold the arguments that are used when - * loading kernel binaries. - */ -struct kexec_segment { - const void *buf; - size_t bufsz; - const void *mem; - size_t memsz; -}; - -#endif /* __KERNEL__ */ - -#endif /* _UAPILINUX_KEXEC_H */ diff --git a/src/linux/include/uapi/linux/keyboard.h b/src/linux/include/uapi/linux/keyboard.h deleted file mode 100644 index 5a68497..0000000 --- a/src/linux/include/uapi/linux/keyboard.h +++ /dev/null @@ -1,443 +0,0 @@ -#ifndef _UAPI__LINUX_KEYBOARD_H -#define _UAPI__LINUX_KEYBOARD_H - -#include - -#define KG_SHIFT 0 -#define KG_CTRL 2 -#define KG_ALT 3 -#define KG_ALTGR 1 -#define KG_SHIFTL 4 -#define KG_KANASHIFT 4 -#define KG_SHIFTR 5 -#define KG_CTRLL 6 -#define KG_CTRLR 7 -#define KG_CAPSSHIFT 8 - -#define NR_SHIFT 9 - -#define NR_KEYS 256 -#define MAX_NR_KEYMAPS 256 -/* This means 128Kb if all keymaps are allocated. Only the superuser - may increase the number of keymaps beyond MAX_NR_OF_USER_KEYMAPS. */ -#define MAX_NR_OF_USER_KEYMAPS 256 /* should be at least 7 */ - - -#define MAX_NR_FUNC 256 /* max nr of strings assigned to keys */ - -#define KT_LATIN 0 /* we depend on this being zero */ -#define KT_LETTER 11 /* symbol that can be acted upon by CapsLock */ -#define KT_FN 1 -#define KT_SPEC 2 -#define KT_PAD 3 -#define KT_DEAD 4 -#define KT_CONS 5 -#define KT_CUR 6 -#define KT_SHIFT 7 -#define KT_META 8 -#define KT_ASCII 9 -#define KT_LOCK 10 -#define KT_SLOCK 12 -#define KT_DEAD2 13 -#define KT_BRL 14 - -#define K(t,v) (((t)<<8)|(v)) -#define KTYP(x) ((x) >> 8) -#define KVAL(x) ((x) & 0xff) - -#define K_F1 K(KT_FN,0) -#define K_F2 K(KT_FN,1) -#define K_F3 K(KT_FN,2) -#define K_F4 K(KT_FN,3) -#define K_F5 K(KT_FN,4) -#define K_F6 K(KT_FN,5) -#define K_F7 K(KT_FN,6) -#define K_F8 K(KT_FN,7) -#define K_F9 K(KT_FN,8) -#define K_F10 K(KT_FN,9) -#define K_F11 K(KT_FN,10) -#define K_F12 K(KT_FN,11) -#define K_F13 K(KT_FN,12) -#define K_F14 K(KT_FN,13) -#define K_F15 K(KT_FN,14) -#define K_F16 K(KT_FN,15) -#define K_F17 K(KT_FN,16) -#define K_F18 K(KT_FN,17) -#define K_F19 K(KT_FN,18) -#define K_F20 K(KT_FN,19) -#define K_FIND K(KT_FN,20) -#define K_INSERT K(KT_FN,21) -#define K_REMOVE K(KT_FN,22) -#define K_SELECT K(KT_FN,23) -#define K_PGUP K(KT_FN,24) /* PGUP is a synonym for PRIOR */ -#define K_PGDN K(KT_FN,25) /* PGDN is a synonym for NEXT */ -#define K_MACRO K(KT_FN,26) -#define K_HELP K(KT_FN,27) -#define K_DO K(KT_FN,28) -#define K_PAUSE K(KT_FN,29) -#define K_F21 K(KT_FN,30) -#define K_F22 K(KT_FN,31) -#define K_F23 K(KT_FN,32) -#define K_F24 K(KT_FN,33) -#define K_F25 K(KT_FN,34) -#define K_F26 K(KT_FN,35) -#define K_F27 K(KT_FN,36) -#define K_F28 K(KT_FN,37) -#define K_F29 K(KT_FN,38) -#define K_F30 K(KT_FN,39) -#define K_F31 K(KT_FN,40) -#define K_F32 K(KT_FN,41) -#define K_F33 K(KT_FN,42) -#define K_F34 K(KT_FN,43) -#define K_F35 K(KT_FN,44) -#define K_F36 K(KT_FN,45) -#define K_F37 K(KT_FN,46) -#define K_F38 K(KT_FN,47) -#define K_F39 K(KT_FN,48) -#define K_F40 K(KT_FN,49) -#define K_F41 K(KT_FN,50) -#define K_F42 K(KT_FN,51) -#define K_F43 K(KT_FN,52) -#define K_F44 K(KT_FN,53) -#define K_F45 K(KT_FN,54) -#define K_F46 K(KT_FN,55) -#define K_F47 K(KT_FN,56) -#define K_F48 K(KT_FN,57) -#define K_F49 K(KT_FN,58) -#define K_F50 K(KT_FN,59) -#define K_F51 K(KT_FN,60) -#define K_F52 K(KT_FN,61) -#define K_F53 K(KT_FN,62) -#define K_F54 K(KT_FN,63) -#define K_F55 K(KT_FN,64) -#define K_F56 K(KT_FN,65) -#define K_F57 K(KT_FN,66) -#define K_F58 K(KT_FN,67) -#define K_F59 K(KT_FN,68) -#define K_F60 K(KT_FN,69) -#define K_F61 K(KT_FN,70) -#define K_F62 K(KT_FN,71) -#define K_F63 K(KT_FN,72) -#define K_F64 K(KT_FN,73) -#define K_F65 K(KT_FN,74) -#define K_F66 K(KT_FN,75) -#define K_F67 K(KT_FN,76) -#define K_F68 K(KT_FN,77) -#define K_F69 K(KT_FN,78) -#define K_F70 K(KT_FN,79) -#define K_F71 K(KT_FN,80) -#define K_F72 K(KT_FN,81) -#define K_F73 K(KT_FN,82) -#define K_F74 K(KT_FN,83) -#define K_F75 K(KT_FN,84) -#define K_F76 K(KT_FN,85) -#define K_F77 K(KT_FN,86) -#define K_F78 K(KT_FN,87) -#define K_F79 K(KT_FN,88) -#define K_F80 K(KT_FN,89) -#define K_F81 K(KT_FN,90) -#define K_F82 K(KT_FN,91) -#define K_F83 K(KT_FN,92) -#define K_F84 K(KT_FN,93) -#define K_F85 K(KT_FN,94) -#define K_F86 K(KT_FN,95) -#define K_F87 K(KT_FN,96) -#define K_F88 K(KT_FN,97) -#define K_F89 K(KT_FN,98) -#define K_F90 K(KT_FN,99) -#define K_F91 K(KT_FN,100) -#define K_F92 K(KT_FN,101) -#define K_F93 K(KT_FN,102) -#define K_F94 K(KT_FN,103) -#define K_F95 K(KT_FN,104) -#define K_F96 K(KT_FN,105) -#define K_F97 K(KT_FN,106) -#define K_F98 K(KT_FN,107) -#define K_F99 K(KT_FN,108) -#define K_F100 K(KT_FN,109) -#define K_F101 K(KT_FN,110) -#define K_F102 K(KT_FN,111) -#define K_F103 K(KT_FN,112) -#define K_F104 K(KT_FN,113) -#define K_F105 K(KT_FN,114) -#define K_F106 K(KT_FN,115) -#define K_F107 K(KT_FN,116) -#define K_F108 K(KT_FN,117) -#define K_F109 K(KT_FN,118) -#define K_F110 K(KT_FN,119) -#define K_F111 K(KT_FN,120) -#define K_F112 K(KT_FN,121) -#define K_F113 K(KT_FN,122) -#define K_F114 K(KT_FN,123) -#define K_F115 K(KT_FN,124) -#define K_F116 K(KT_FN,125) -#define K_F117 K(KT_FN,126) -#define K_F118 K(KT_FN,127) -#define K_F119 K(KT_FN,128) -#define K_F120 K(KT_FN,129) -#define K_F121 K(KT_FN,130) -#define K_F122 K(KT_FN,131) -#define K_F123 K(KT_FN,132) -#define K_F124 K(KT_FN,133) -#define K_F125 K(KT_FN,134) -#define K_F126 K(KT_FN,135) -#define K_F127 K(KT_FN,136) -#define K_F128 K(KT_FN,137) -#define K_F129 K(KT_FN,138) -#define K_F130 K(KT_FN,139) -#define K_F131 K(KT_FN,140) -#define K_F132 K(KT_FN,141) -#define K_F133 K(KT_FN,142) -#define K_F134 K(KT_FN,143) -#define K_F135 K(KT_FN,144) -#define K_F136 K(KT_FN,145) -#define K_F137 K(KT_FN,146) -#define K_F138 K(KT_FN,147) -#define K_F139 K(KT_FN,148) -#define K_F140 K(KT_FN,149) -#define K_F141 K(KT_FN,150) -#define K_F142 K(KT_FN,151) -#define K_F143 K(KT_FN,152) -#define K_F144 K(KT_FN,153) -#define K_F145 K(KT_FN,154) -#define K_F146 K(KT_FN,155) -#define K_F147 K(KT_FN,156) -#define K_F148 K(KT_FN,157) -#define K_F149 K(KT_FN,158) -#define K_F150 K(KT_FN,159) -#define K_F151 K(KT_FN,160) -#define K_F152 K(KT_FN,161) -#define K_F153 K(KT_FN,162) -#define K_F154 K(KT_FN,163) -#define K_F155 K(KT_FN,164) -#define K_F156 K(KT_FN,165) -#define K_F157 K(KT_FN,166) -#define K_F158 K(KT_FN,167) -#define K_F159 K(KT_FN,168) -#define K_F160 K(KT_FN,169) -#define K_F161 K(KT_FN,170) -#define K_F162 K(KT_FN,171) -#define K_F163 K(KT_FN,172) -#define K_F164 K(KT_FN,173) -#define K_F165 K(KT_FN,174) -#define K_F166 K(KT_FN,175) -#define K_F167 K(KT_FN,176) -#define K_F168 K(KT_FN,177) -#define K_F169 K(KT_FN,178) -#define K_F170 K(KT_FN,179) -#define K_F171 K(KT_FN,180) -#define K_F172 K(KT_FN,181) -#define K_F173 K(KT_FN,182) -#define K_F174 K(KT_FN,183) -#define K_F175 K(KT_FN,184) -#define K_F176 K(KT_FN,185) -#define K_F177 K(KT_FN,186) -#define K_F178 K(KT_FN,187) -#define K_F179 K(KT_FN,188) -#define K_F180 K(KT_FN,189) -#define K_F181 K(KT_FN,190) -#define K_F182 K(KT_FN,191) -#define K_F183 K(KT_FN,192) -#define K_F184 K(KT_FN,193) -#define K_F185 K(KT_FN,194) -#define K_F186 K(KT_FN,195) -#define K_F187 K(KT_FN,196) -#define K_F188 K(KT_FN,197) -#define K_F189 K(KT_FN,198) -#define K_F190 K(KT_FN,199) -#define K_F191 K(KT_FN,200) -#define K_F192 K(KT_FN,201) -#define K_F193 K(KT_FN,202) -#define K_F194 K(KT_FN,203) -#define K_F195 K(KT_FN,204) -#define K_F196 K(KT_FN,205) -#define K_F197 K(KT_FN,206) -#define K_F198 K(KT_FN,207) -#define K_F199 K(KT_FN,208) -#define K_F200 K(KT_FN,209) -#define K_F201 K(KT_FN,210) -#define K_F202 K(KT_FN,211) -#define K_F203 K(KT_FN,212) -#define K_F204 K(KT_FN,213) -#define K_F205 K(KT_FN,214) -#define K_F206 K(KT_FN,215) -#define K_F207 K(KT_FN,216) -#define K_F208 K(KT_FN,217) -#define K_F209 K(KT_FN,218) -#define K_F210 K(KT_FN,219) -#define K_F211 K(KT_FN,220) -#define K_F212 K(KT_FN,221) -#define K_F213 K(KT_FN,222) -#define K_F214 K(KT_FN,223) -#define K_F215 K(KT_FN,224) -#define K_F216 K(KT_FN,225) -#define K_F217 K(KT_FN,226) -#define K_F218 K(KT_FN,227) -#define K_F219 K(KT_FN,228) -#define K_F220 K(KT_FN,229) -#define K_F221 K(KT_FN,230) -#define K_F222 K(KT_FN,231) -#define K_F223 K(KT_FN,232) -#define K_F224 K(KT_FN,233) -#define K_F225 K(KT_FN,234) -#define K_F226 K(KT_FN,235) -#define K_F227 K(KT_FN,236) -#define K_F228 K(KT_FN,237) -#define K_F229 K(KT_FN,238) -#define K_F230 K(KT_FN,239) -#define K_F231 K(KT_FN,240) -#define K_F232 K(KT_FN,241) -#define K_F233 K(KT_FN,242) -#define K_F234 K(KT_FN,243) -#define K_F235 K(KT_FN,244) -#define K_F236 K(KT_FN,245) -#define K_F237 K(KT_FN,246) -#define K_F238 K(KT_FN,247) -#define K_F239 K(KT_FN,248) -#define K_F240 K(KT_FN,249) -#define K_F241 K(KT_FN,250) -#define K_F242 K(KT_FN,251) -#define K_F243 K(KT_FN,252) -#define K_F244 K(KT_FN,253) -#define K_F245 K(KT_FN,254) -#define K_UNDO K(KT_FN,255) - - -#define K_HOLE K(KT_SPEC,0) -#define K_ENTER K(KT_SPEC,1) -#define K_SH_REGS K(KT_SPEC,2) -#define K_SH_MEM K(KT_SPEC,3) -#define K_SH_STAT K(KT_SPEC,4) -#define K_BREAK K(KT_SPEC,5) -#define K_CONS K(KT_SPEC,6) -#define K_CAPS K(KT_SPEC,7) -#define K_NUM K(KT_SPEC,8) -#define K_HOLD K(KT_SPEC,9) -#define K_SCROLLFORW K(KT_SPEC,10) -#define K_SCROLLBACK K(KT_SPEC,11) -#define K_BOOT K(KT_SPEC,12) -#define K_CAPSON K(KT_SPEC,13) -#define K_COMPOSE K(KT_SPEC,14) -#define K_SAK K(KT_SPEC,15) -#define K_DECRCONSOLE K(KT_SPEC,16) -#define K_INCRCONSOLE K(KT_SPEC,17) -#define K_SPAWNCONSOLE K(KT_SPEC,18) -#define K_BARENUMLOCK K(KT_SPEC,19) - -#define K_ALLOCATED K(KT_SPEC,126) /* dynamically allocated keymap */ -#define K_NOSUCHMAP K(KT_SPEC,127) /* returned by KDGKBENT */ - -#define K_P0 K(KT_PAD,0) -#define K_P1 K(KT_PAD,1) -#define K_P2 K(KT_PAD,2) -#define K_P3 K(KT_PAD,3) -#define K_P4 K(KT_PAD,4) -#define K_P5 K(KT_PAD,5) -#define K_P6 K(KT_PAD,6) -#define K_P7 K(KT_PAD,7) -#define K_P8 K(KT_PAD,8) -#define K_P9 K(KT_PAD,9) -#define K_PPLUS K(KT_PAD,10) /* key-pad plus */ -#define K_PMINUS K(KT_PAD,11) /* key-pad minus */ -#define K_PSTAR K(KT_PAD,12) /* key-pad asterisk (star) */ -#define K_PSLASH K(KT_PAD,13) /* key-pad slash */ -#define K_PENTER K(KT_PAD,14) /* key-pad enter */ -#define K_PCOMMA K(KT_PAD,15) /* key-pad comma: kludge... */ -#define K_PDOT K(KT_PAD,16) /* key-pad dot (period): kludge... */ -#define K_PPLUSMINUS K(KT_PAD,17) /* key-pad plus/minus */ -#define K_PPARENL K(KT_PAD,18) /* key-pad left parenthesis */ -#define K_PPARENR K(KT_PAD,19) /* key-pad right parenthesis */ - -#define NR_PAD 20 - -#define K_DGRAVE K(KT_DEAD,0) -#define K_DACUTE K(KT_DEAD,1) -#define K_DCIRCM K(KT_DEAD,2) -#define K_DTILDE K(KT_DEAD,3) -#define K_DDIERE K(KT_DEAD,4) -#define K_DCEDIL K(KT_DEAD,5) - -#define NR_DEAD 6 - -#define K_DOWN K(KT_CUR,0) -#define K_LEFT K(KT_CUR,1) -#define K_RIGHT K(KT_CUR,2) -#define K_UP K(KT_CUR,3) - -#define K_SHIFT K(KT_SHIFT,KG_SHIFT) -#define K_CTRL K(KT_SHIFT,KG_CTRL) -#define K_ALT K(KT_SHIFT,KG_ALT) -#define K_ALTGR K(KT_SHIFT,KG_ALTGR) -#define K_SHIFTL K(KT_SHIFT,KG_SHIFTL) -#define K_SHIFTR K(KT_SHIFT,KG_SHIFTR) -#define K_CTRLL K(KT_SHIFT,KG_CTRLL) -#define K_CTRLR K(KT_SHIFT,KG_CTRLR) -#define K_CAPSSHIFT K(KT_SHIFT,KG_CAPSSHIFT) - -#define K_ASC0 K(KT_ASCII,0) -#define K_ASC1 K(KT_ASCII,1) -#define K_ASC2 K(KT_ASCII,2) -#define K_ASC3 K(KT_ASCII,3) -#define K_ASC4 K(KT_ASCII,4) -#define K_ASC5 K(KT_ASCII,5) -#define K_ASC6 K(KT_ASCII,6) -#define K_ASC7 K(KT_ASCII,7) -#define K_ASC8 K(KT_ASCII,8) -#define K_ASC9 K(KT_ASCII,9) -#define K_HEX0 K(KT_ASCII,10) -#define K_HEX1 K(KT_ASCII,11) -#define K_HEX2 K(KT_ASCII,12) -#define K_HEX3 K(KT_ASCII,13) -#define K_HEX4 K(KT_ASCII,14) -#define K_HEX5 K(KT_ASCII,15) -#define K_HEX6 K(KT_ASCII,16) -#define K_HEX7 K(KT_ASCII,17) -#define K_HEX8 K(KT_ASCII,18) -#define K_HEX9 K(KT_ASCII,19) -#define K_HEXa K(KT_ASCII,20) -#define K_HEXb K(KT_ASCII,21) -#define K_HEXc K(KT_ASCII,22) -#define K_HEXd K(KT_ASCII,23) -#define K_HEXe K(KT_ASCII,24) -#define K_HEXf K(KT_ASCII,25) - -#define NR_ASCII 26 - -#define K_SHIFTLOCK K(KT_LOCK,KG_SHIFT) -#define K_CTRLLOCK K(KT_LOCK,KG_CTRL) -#define K_ALTLOCK K(KT_LOCK,KG_ALT) -#define K_ALTGRLOCK K(KT_LOCK,KG_ALTGR) -#define K_SHIFTLLOCK K(KT_LOCK,KG_SHIFTL) -#define K_SHIFTRLOCK K(KT_LOCK,KG_SHIFTR) -#define K_CTRLLLOCK K(KT_LOCK,KG_CTRLL) -#define K_CTRLRLOCK K(KT_LOCK,KG_CTRLR) -#define K_CAPSSHIFTLOCK K(KT_LOCK,KG_CAPSSHIFT) - -#define K_SHIFT_SLOCK K(KT_SLOCK,KG_SHIFT) -#define K_CTRL_SLOCK K(KT_SLOCK,KG_CTRL) -#define K_ALT_SLOCK K(KT_SLOCK,KG_ALT) -#define K_ALTGR_SLOCK K(KT_SLOCK,KG_ALTGR) -#define K_SHIFTL_SLOCK K(KT_SLOCK,KG_SHIFTL) -#define K_SHIFTR_SLOCK K(KT_SLOCK,KG_SHIFTR) -#define K_CTRLL_SLOCK K(KT_SLOCK,KG_CTRLL) -#define K_CTRLR_SLOCK K(KT_SLOCK,KG_CTRLR) -#define K_CAPSSHIFT_SLOCK K(KT_SLOCK,KG_CAPSSHIFT) - -#define NR_LOCK 9 - -#define K_BRL_BLANK K(KT_BRL, 0) -#define K_BRL_DOT1 K(KT_BRL, 1) -#define K_BRL_DOT2 K(KT_BRL, 2) -#define K_BRL_DOT3 K(KT_BRL, 3) -#define K_BRL_DOT4 K(KT_BRL, 4) -#define K_BRL_DOT5 K(KT_BRL, 5) -#define K_BRL_DOT6 K(KT_BRL, 6) -#define K_BRL_DOT7 K(KT_BRL, 7) -#define K_BRL_DOT8 K(KT_BRL, 8) -#define K_BRL_DOT9 K(KT_BRL, 9) -#define K_BRL_DOT10 K(KT_BRL, 10) - -#define NR_BRL 11 - -#define MAX_DIACR 256 -#endif /* _UAPI__LINUX_KEYBOARD_H */ diff --git a/src/linux/include/uapi/linux/keyctl.h b/src/linux/include/uapi/linux/keyctl.h deleted file mode 100644 index 86eddd6..0000000 --- a/src/linux/include/uapi/linux/keyctl.h +++ /dev/null @@ -1,71 +0,0 @@ -/* keyctl.h: keyctl command IDs - * - * Copyright (C) 2004, 2008 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef _LINUX_KEYCTL_H -#define _LINUX_KEYCTL_H - -#include - -/* special process keyring shortcut IDs */ -#define KEY_SPEC_THREAD_KEYRING -1 /* - key ID for thread-specific keyring */ -#define KEY_SPEC_PROCESS_KEYRING -2 /* - key ID for process-specific keyring */ -#define KEY_SPEC_SESSION_KEYRING -3 /* - key ID for session-specific keyring */ -#define KEY_SPEC_USER_KEYRING -4 /* - key ID for UID-specific keyring */ -#define KEY_SPEC_USER_SESSION_KEYRING -5 /* - key ID for UID-session keyring */ -#define KEY_SPEC_GROUP_KEYRING -6 /* - key ID for GID-specific keyring */ -#define KEY_SPEC_REQKEY_AUTH_KEY -7 /* - key ID for assumed request_key auth key */ -#define KEY_SPEC_REQUESTOR_KEYRING -8 /* - key ID for request_key() dest keyring */ - -/* request-key default keyrings */ -#define KEY_REQKEY_DEFL_NO_CHANGE -1 -#define KEY_REQKEY_DEFL_DEFAULT 0 -#define KEY_REQKEY_DEFL_THREAD_KEYRING 1 -#define KEY_REQKEY_DEFL_PROCESS_KEYRING 2 -#define KEY_REQKEY_DEFL_SESSION_KEYRING 3 -#define KEY_REQKEY_DEFL_USER_KEYRING 4 -#define KEY_REQKEY_DEFL_USER_SESSION_KEYRING 5 -#define KEY_REQKEY_DEFL_GROUP_KEYRING 6 -#define KEY_REQKEY_DEFL_REQUESTOR_KEYRING 7 - -/* keyctl commands */ -#define KEYCTL_GET_KEYRING_ID 0 /* ask for a keyring's ID */ -#define KEYCTL_JOIN_SESSION_KEYRING 1 /* join or start named session keyring */ -#define KEYCTL_UPDATE 2 /* update a key */ -#define KEYCTL_REVOKE 3 /* revoke a key */ -#define KEYCTL_CHOWN 4 /* set ownership of a key */ -#define KEYCTL_SETPERM 5 /* set perms on a key */ -#define KEYCTL_DESCRIBE 6 /* describe a key */ -#define KEYCTL_CLEAR 7 /* clear contents of a keyring */ -#define KEYCTL_LINK 8 /* link a key into a keyring */ -#define KEYCTL_UNLINK 9 /* unlink a key from a keyring */ -#define KEYCTL_SEARCH 10 /* search for a key in a keyring */ -#define KEYCTL_READ 11 /* read a key or keyring's contents */ -#define KEYCTL_INSTANTIATE 12 /* instantiate a partially constructed key */ -#define KEYCTL_NEGATE 13 /* negate a partially constructed key */ -#define KEYCTL_SET_REQKEY_KEYRING 14 /* set default request-key keyring */ -#define KEYCTL_SET_TIMEOUT 15 /* set key timeout */ -#define KEYCTL_ASSUME_AUTHORITY 16 /* assume request_key() authorisation */ -#define KEYCTL_GET_SECURITY 17 /* get key security label */ -#define KEYCTL_SESSION_TO_PARENT 18 /* apply session keyring to parent process */ -#define KEYCTL_REJECT 19 /* reject a partially constructed key */ -#define KEYCTL_INSTANTIATE_IOV 20 /* instantiate a partially constructed key */ -#define KEYCTL_INVALIDATE 21 /* invalidate a key */ -#define KEYCTL_GET_PERSISTENT 22 /* get a user's persistent keyring */ -#define KEYCTL_DH_COMPUTE 23 /* Compute Diffie-Hellman values */ - -/* keyctl structures */ -struct keyctl_dh_params { - __s32 private; - __s32 prime; - __s32 base; -}; - -#endif /* _LINUX_KEYCTL_H */ diff --git a/src/linux/include/uapi/linux/libc-compat.h b/src/linux/include/uapi/linux/libc-compat.h deleted file mode 100644 index 44b8a6b..0000000 --- a/src/linux/include/uapi/linux/libc-compat.h +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Compatibility interface for userspace libc header coordination: - * - * Define compatibility macros that are used to control the inclusion or - * exclusion of UAPI structures and definitions in coordination with another - * userspace C library. - * - * This header is intended to solve the problem of UAPI definitions that - * conflict with userspace definitions. If a UAPI header has such conflicting - * definitions then the solution is as follows: - * - * * Synchronize the UAPI header and the libc headers so either one can be - * used and such that the ABI is preserved. If this is not possible then - * no simple compatibility interface exists (you need to write translating - * wrappers and rename things) and you can't use this interface. - * - * Then follow this process: - * - * (a) Include libc-compat.h in the UAPI header. - * e.g. #include - * This include must be as early as possible. - * - * (b) In libc-compat.h add enough code to detect that the comflicting - * userspace libc header has been included first. - * - * (c) If the userspace libc header has been included first define a set of - * guard macros of the form __UAPI_DEF_FOO and set their values to 1, else - * set their values to 0. - * - * (d) Back in the UAPI header with the conflicting definitions, guard the - * definitions with: - * #if __UAPI_DEF_FOO - * ... - * #endif - * - * This fixes the situation where the linux headers are included *after* the - * libc headers. To fix the problem with the inclusion in the other order the - * userspace libc headers must be fixed like this: - * - * * For all definitions that conflict with kernel definitions wrap those - * defines in the following: - * #if !__UAPI_DEF_FOO - * ... - * #endif - * - * This prevents the redefinition of a construct already defined by the kernel. - */ -#ifndef _UAPI_LIBC_COMPAT_H -#define _UAPI_LIBC_COMPAT_H - -/* We have included glibc headers... */ -#if defined(__GLIBC__) - -/* Coordinate with glibc net/if.h header. */ -#if defined(_NET_IF_H) && defined(__USE_MISC) - -/* GLIBC headers included first so don't define anything - * that would already be defined. */ - -#define __UAPI_DEF_IF_IFCONF 0 -#define __UAPI_DEF_IF_IFMAP 0 -#define __UAPI_DEF_IF_IFNAMSIZ 0 -#define __UAPI_DEF_IF_IFREQ 0 -/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */ -#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 0 -/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */ -#ifndef __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO -#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1 -#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */ - -#else /* _NET_IF_H */ - -/* Linux headers included first, and we must define everything - * we need. The expectation is that glibc will check the - * __UAPI_DEF_* defines and adjust appropriately. */ - -#define __UAPI_DEF_IF_IFCONF 1 -#define __UAPI_DEF_IF_IFMAP 1 -#define __UAPI_DEF_IF_IFNAMSIZ 1 -#define __UAPI_DEF_IF_IFREQ 1 -/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */ -#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1 -/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */ -#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1 - -#endif /* _NET_IF_H */ - -/* Coordinate with glibc netinet/in.h header. */ -#if defined(_NETINET_IN_H) - -/* GLIBC headers included first so don't define anything - * that would already be defined. */ -#define __UAPI_DEF_IN_ADDR 0 -#define __UAPI_DEF_IN_IPPROTO 0 -#define __UAPI_DEF_IN_PKTINFO 0 -#define __UAPI_DEF_IP_MREQ 0 -#define __UAPI_DEF_SOCKADDR_IN 0 -#define __UAPI_DEF_IN_CLASS 0 - -#define __UAPI_DEF_IN6_ADDR 0 -/* The exception is the in6_addr macros which must be defined - * if the glibc code didn't define them. This guard matches - * the guard in glibc/inet/netinet/in.h which defines the - * additional in6_addr macros e.g. s6_addr16, and s6_addr32. */ -#if defined(__USE_MISC) || defined (__USE_GNU) -#define __UAPI_DEF_IN6_ADDR_ALT 0 -#else -#define __UAPI_DEF_IN6_ADDR_ALT 1 -#endif -#define __UAPI_DEF_SOCKADDR_IN6 0 -#define __UAPI_DEF_IPV6_MREQ 0 -#define __UAPI_DEF_IPPROTO_V6 0 -#define __UAPI_DEF_IPV6_OPTIONS 0 -#define __UAPI_DEF_IN6_PKTINFO 0 -#define __UAPI_DEF_IP6_MTUINFO 0 - -#else - -/* Linux headers included first, and we must define everything - * we need. The expectation is that glibc will check the - * __UAPI_DEF_* defines and adjust appropriately. */ -#define __UAPI_DEF_IN_ADDR 1 -#define __UAPI_DEF_IN_IPPROTO 1 -#define __UAPI_DEF_IN_PKTINFO 1 -#define __UAPI_DEF_IP_MREQ 1 -#define __UAPI_DEF_SOCKADDR_IN 1 -#define __UAPI_DEF_IN_CLASS 1 - -#define __UAPI_DEF_IN6_ADDR 1 -/* We unconditionally define the in6_addr macros and glibc must - * coordinate. */ -#define __UAPI_DEF_IN6_ADDR_ALT 1 -#define __UAPI_DEF_SOCKADDR_IN6 1 -#define __UAPI_DEF_IPV6_MREQ 1 -#define __UAPI_DEF_IPPROTO_V6 1 -#define __UAPI_DEF_IPV6_OPTIONS 1 -#define __UAPI_DEF_IN6_PKTINFO 1 -#define __UAPI_DEF_IP6_MTUINFO 1 - -#endif /* _NETINET_IN_H */ - -/* Coordinate with glibc netipx/ipx.h header. */ -#if defined(__NETIPX_IPX_H) - -#define __UAPI_DEF_SOCKADDR_IPX 0 -#define __UAPI_DEF_IPX_ROUTE_DEFINITION 0 -#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 0 -#define __UAPI_DEF_IPX_CONFIG_DATA 0 -#define __UAPI_DEF_IPX_ROUTE_DEF 0 - -#else /* defined(__NETIPX_IPX_H) */ - -#define __UAPI_DEF_SOCKADDR_IPX 1 -#define __UAPI_DEF_IPX_ROUTE_DEFINITION 1 -#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 1 -#define __UAPI_DEF_IPX_CONFIG_DATA 1 -#define __UAPI_DEF_IPX_ROUTE_DEF 1 - -#endif /* defined(__NETIPX_IPX_H) */ - -/* Definitions for xattr.h */ -#if defined(_SYS_XATTR_H) -#define __UAPI_DEF_XATTR 0 -#else -#define __UAPI_DEF_XATTR 1 -#endif - -/* If we did not see any headers from any supported C libraries, - * or we are being included in the kernel, then define everything - * that we need. */ -#else /* !defined(__GLIBC__) */ - -/* Definitions for if.h */ -#define __UAPI_DEF_IF_IFCONF 1 -#define __UAPI_DEF_IF_IFMAP 1 -#define __UAPI_DEF_IF_IFNAMSIZ 1 -#define __UAPI_DEF_IF_IFREQ 1 -/* Everything up to IFF_DYNAMIC, matches net/if.h until glibc 2.23 */ -#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 1 -/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */ -#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1 - -/* Definitions for in.h */ -#define __UAPI_DEF_IN_ADDR 1 -#define __UAPI_DEF_IN_IPPROTO 1 -#define __UAPI_DEF_IN_PKTINFO 1 -#define __UAPI_DEF_IP_MREQ 1 -#define __UAPI_DEF_SOCKADDR_IN 1 -#define __UAPI_DEF_IN_CLASS 1 - -/* Definitions for in6.h */ -#define __UAPI_DEF_IN6_ADDR 1 -#define __UAPI_DEF_IN6_ADDR_ALT 1 -#define __UAPI_DEF_SOCKADDR_IN6 1 -#define __UAPI_DEF_IPV6_MREQ 1 -#define __UAPI_DEF_IPPROTO_V6 1 -#define __UAPI_DEF_IPV6_OPTIONS 1 -#define __UAPI_DEF_IN6_PKTINFO 1 -#define __UAPI_DEF_IP6_MTUINFO 1 - -/* Definitions for ipx.h */ -#define __UAPI_DEF_SOCKADDR_IPX 1 -#define __UAPI_DEF_IPX_ROUTE_DEFINITION 1 -#define __UAPI_DEF_IPX_INTERFACE_DEFINITION 1 -#define __UAPI_DEF_IPX_CONFIG_DATA 1 -#define __UAPI_DEF_IPX_ROUTE_DEF 1 - -/* Definitions for xattr.h */ -#define __UAPI_DEF_XATTR 1 - -#endif /* __GLIBC__ */ - -#endif /* _UAPI_LIBC_COMPAT_H */ diff --git a/src/linux/include/uapi/linux/limits.h b/src/linux/include/uapi/linux/limits.h deleted file mode 100644 index 2d0f941..0000000 --- a/src/linux/include/uapi/linux/limits.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _LINUX_LIMITS_H -#define _LINUX_LIMITS_H - -#define NR_OPEN 1024 - -#define NGROUPS_MAX 65536 /* supplemental group IDs are available */ -#define ARG_MAX 131072 /* # bytes of args + environ for exec() */ -#define LINK_MAX 127 /* # links a file may have */ -#define MAX_CANON 255 /* size of the canonical input queue */ -#define MAX_INPUT 255 /* size of the type-ahead buffer */ -#define NAME_MAX 255 /* # chars in a file name */ -#define PATH_MAX 4096 /* # chars in a path name including nul */ -#define PIPE_BUF 4096 /* # bytes in atomic write to a pipe */ -#define XATTR_NAME_MAX 255 /* # chars in an extended attribute name */ -#define XATTR_SIZE_MAX 65536 /* size of an extended attribute value (64k) */ -#define XATTR_LIST_MAX 65536 /* size of extended attribute namelist (64k) */ - -#define RTSIG_MAX 32 - -#endif diff --git a/src/linux/include/uapi/linux/lwtunnel.h b/src/linux/include/uapi/linux/lwtunnel.h deleted file mode 100644 index a478fe8..0000000 --- a/src/linux/include/uapi/linux/lwtunnel.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _UAPI_LWTUNNEL_H_ -#define _UAPI_LWTUNNEL_H_ - -#include - -enum lwtunnel_encap_types { - LWTUNNEL_ENCAP_NONE, - LWTUNNEL_ENCAP_MPLS, - LWTUNNEL_ENCAP_IP, - LWTUNNEL_ENCAP_ILA, - LWTUNNEL_ENCAP_IP6, - __LWTUNNEL_ENCAP_MAX, -}; - -#define LWTUNNEL_ENCAP_MAX (__LWTUNNEL_ENCAP_MAX - 1) - -enum lwtunnel_ip_t { - LWTUNNEL_IP_UNSPEC, - LWTUNNEL_IP_ID, - LWTUNNEL_IP_DST, - LWTUNNEL_IP_SRC, - LWTUNNEL_IP_TTL, - LWTUNNEL_IP_TOS, - LWTUNNEL_IP_FLAGS, - LWTUNNEL_IP_PAD, - __LWTUNNEL_IP_MAX, -}; - -#define LWTUNNEL_IP_MAX (__LWTUNNEL_IP_MAX - 1) - -enum lwtunnel_ip6_t { - LWTUNNEL_IP6_UNSPEC, - LWTUNNEL_IP6_ID, - LWTUNNEL_IP6_DST, - LWTUNNEL_IP6_SRC, - LWTUNNEL_IP6_HOPLIMIT, - LWTUNNEL_IP6_TC, - LWTUNNEL_IP6_FLAGS, - LWTUNNEL_IP6_PAD, - __LWTUNNEL_IP6_MAX, -}; - -#define LWTUNNEL_IP6_MAX (__LWTUNNEL_IP6_MAX - 1) - -#endif /* _UAPI_LWTUNNEL_H_ */ diff --git a/src/linux/include/uapi/linux/magic.h b/src/linux/include/uapi/linux/magic.h deleted file mode 100644 index 9bd5594..0000000 --- a/src/linux/include/uapi/linux/magic.h +++ /dev/null @@ -1,87 +0,0 @@ -#ifndef __LINUX_MAGIC_H__ -#define __LINUX_MAGIC_H__ - -#define ADFS_SUPER_MAGIC 0xadf5 -#define AFFS_SUPER_MAGIC 0xadff -#define AFS_SUPER_MAGIC 0x5346414F -#define AUTOFS_SUPER_MAGIC 0x0187 -#define CODA_SUPER_MAGIC 0x73757245 -#define CRAMFS_MAGIC 0x28cd3d45 /* some random number */ -#define CRAMFS_MAGIC_WEND 0x453dcd28 /* magic number with the wrong endianess */ -#define DEBUGFS_MAGIC 0x64626720 -#define SECURITYFS_MAGIC 0x73636673 -#define SELINUX_MAGIC 0xf97cff8c -#define SMACK_MAGIC 0x43415d53 /* "SMAC" */ -#define RAMFS_MAGIC 0x858458f6 /* some random number */ -#define TMPFS_MAGIC 0x01021994 -#define HUGETLBFS_MAGIC 0x958458f6 /* some random number */ -#define SQUASHFS_MAGIC 0x73717368 -#define ECRYPTFS_SUPER_MAGIC 0xf15f -#define EFS_SUPER_MAGIC 0x414A53 -#define EXT2_SUPER_MAGIC 0xEF53 -#define EXT3_SUPER_MAGIC 0xEF53 -#define XENFS_SUPER_MAGIC 0xabba1974 -#define EXT4_SUPER_MAGIC 0xEF53 -#define BTRFS_SUPER_MAGIC 0x9123683E -#define NILFS_SUPER_MAGIC 0x3434 -#define F2FS_SUPER_MAGIC 0xF2F52010 -#define HPFS_SUPER_MAGIC 0xf995e849 -#define ISOFS_SUPER_MAGIC 0x9660 -#define JFFS2_SUPER_MAGIC 0x72b6 -#define PSTOREFS_MAGIC 0x6165676C -#define EFIVARFS_MAGIC 0xde5e81e4 -#define HOSTFS_SUPER_MAGIC 0x00c0ffee -#define OVERLAYFS_SUPER_MAGIC 0x794c7630 - -#define MINIX_SUPER_MAGIC 0x137F /* minix v1 fs, 14 char names */ -#define MINIX_SUPER_MAGIC2 0x138F /* minix v1 fs, 30 char names */ -#define MINIX2_SUPER_MAGIC 0x2468 /* minix v2 fs, 14 char names */ -#define MINIX2_SUPER_MAGIC2 0x2478 /* minix v2 fs, 30 char names */ -#define MINIX3_SUPER_MAGIC 0x4d5a /* minix v3 fs, 60 char names */ - -#define MSDOS_SUPER_MAGIC 0x4d44 /* MD */ -#define NCP_SUPER_MAGIC 0x564c /* Guess, what 0x564c is :-) */ -#define NFS_SUPER_MAGIC 0x6969 -#define OPENPROM_SUPER_MAGIC 0x9fa1 -#define QNX4_SUPER_MAGIC 0x002f /* qnx4 fs detection */ -#define QNX6_SUPER_MAGIC 0x68191122 /* qnx6 fs detection */ - -#define REISERFS_SUPER_MAGIC 0x52654973 /* used by gcc */ - /* used by file system utilities that - look at the superblock, etc. */ -#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs" -#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs" -#define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs" - -#define SMB_SUPER_MAGIC 0x517B -#define CGROUP_SUPER_MAGIC 0x27e0eb -#define CGROUP2_SUPER_MAGIC 0x63677270 - - -#define STACK_END_MAGIC 0x57AC6E9D - -#define TRACEFS_MAGIC 0x74726163 - -#define V9FS_MAGIC 0x01021997 - -#define BDEVFS_MAGIC 0x62646576 -#define DAXFS_MAGIC 0x64646178 -#define BINFMTFS_MAGIC 0x42494e4d -#define DEVPTS_SUPER_MAGIC 0x1cd1 -#define FUTEXFS_SUPER_MAGIC 0xBAD1DEA -#define PIPEFS_MAGIC 0x50495045 -#define PROC_SUPER_MAGIC 0x9fa0 -#define SOCKFS_MAGIC 0x534F434B -#define SYSFS_MAGIC 0x62656572 -#define USBDEVICE_SUPER_MAGIC 0x9fa2 -#define MTD_INODE_FS_MAGIC 0x11307854 -#define ANON_INODE_FS_MAGIC 0x09041934 -#define BTRFS_TEST_MAGIC 0x73727279 -#define NSFS_MAGIC 0x6e736673 -#define BPF_FS_MAGIC 0xcafe4a11 -/* Since UDF 2.01 is ISO 13346 based... */ -#define UDF_SUPER_MAGIC 0x15013346 -#define BALLOON_KVM_MAGIC 0x13661366 -#define ZSMALLOC_MAGIC 0x58295829 - -#endif /* __LINUX_MAGIC_H__ */ diff --git a/src/linux/include/uapi/linux/major.h b/src/linux/include/uapi/linux/major.h deleted file mode 100644 index 620252e..0000000 --- a/src/linux/include/uapi/linux/major.h +++ /dev/null @@ -1,179 +0,0 @@ -#ifndef _LINUX_MAJOR_H -#define _LINUX_MAJOR_H - -/* - * This file has definitions for major device numbers. - * For the device number assignments, see Documentation/devices.txt. - */ - -#define UNNAMED_MAJOR 0 -#define MEM_MAJOR 1 -#define RAMDISK_MAJOR 1 -#define FLOPPY_MAJOR 2 -#define PTY_MASTER_MAJOR 2 -#define IDE0_MAJOR 3 -#define HD_MAJOR IDE0_MAJOR -#define PTY_SLAVE_MAJOR 3 -#define TTY_MAJOR 4 -#define TTYAUX_MAJOR 5 -#define LP_MAJOR 6 -#define VCS_MAJOR 7 -#define LOOP_MAJOR 7 -#define SCSI_DISK0_MAJOR 8 -#define SCSI_TAPE_MAJOR 9 -#define MD_MAJOR 9 -#define MISC_MAJOR 10 -#define SCSI_CDROM_MAJOR 11 -#define MUX_MAJOR 11 /* PA-RISC only */ -#define XT_DISK_MAJOR 13 -#define INPUT_MAJOR 13 -#define SOUND_MAJOR 14 -#define CDU31A_CDROM_MAJOR 15 -#define JOYSTICK_MAJOR 15 -#define GOLDSTAR_CDROM_MAJOR 16 -#define OPTICS_CDROM_MAJOR 17 -#define SANYO_CDROM_MAJOR 18 -#define CYCLADES_MAJOR 19 -#define CYCLADESAUX_MAJOR 20 -#define MITSUMI_X_CDROM_MAJOR 20 -#define MFM_ACORN_MAJOR 21 /* ARM Linux /dev/mfm */ -#define SCSI_GENERIC_MAJOR 21 -#define IDE1_MAJOR 22 -#define DIGICU_MAJOR 22 -#define DIGI_MAJOR 23 -#define MITSUMI_CDROM_MAJOR 23 -#define CDU535_CDROM_MAJOR 24 -#define STL_SERIALMAJOR 24 -#define MATSUSHITA_CDROM_MAJOR 25 -#define STL_CALLOUTMAJOR 25 -#define MATSUSHITA_CDROM2_MAJOR 26 -#define QIC117_TAPE_MAJOR 27 -#define MATSUSHITA_CDROM3_MAJOR 27 -#define MATSUSHITA_CDROM4_MAJOR 28 -#define STL_SIOMEMMAJOR 28 -#define ACSI_MAJOR 28 -#define AZTECH_CDROM_MAJOR 29 -#define FB_MAJOR 29 /* /dev/fb* framebuffers */ -#define MTD_BLOCK_MAJOR 31 -#define CM206_CDROM_MAJOR 32 -#define IDE2_MAJOR 33 -#define IDE3_MAJOR 34 -#define Z8530_MAJOR 34 -#define XPRAM_MAJOR 35 /* Expanded storage on S/390: "slow ram"*/ -#define NETLINK_MAJOR 36 -#define PS2ESDI_MAJOR 36 -#define IDETAPE_MAJOR 37 -#define Z2RAM_MAJOR 37 -#define APBLOCK_MAJOR 38 /* AP1000 Block device */ -#define DDV_MAJOR 39 /* AP1000 DDV block device */ -#define NBD_MAJOR 43 /* Network block device */ -#define RISCOM8_NORMAL_MAJOR 48 -#define DAC960_MAJOR 48 /* 48..55 */ -#define RISCOM8_CALLOUT_MAJOR 49 -#define MKISS_MAJOR 55 -#define DSP56K_MAJOR 55 /* DSP56001 processor device */ - -#define IDE4_MAJOR 56 -#define IDE5_MAJOR 57 - -#define SCSI_DISK1_MAJOR 65 -#define SCSI_DISK2_MAJOR 66 -#define SCSI_DISK3_MAJOR 67 -#define SCSI_DISK4_MAJOR 68 -#define SCSI_DISK5_MAJOR 69 -#define SCSI_DISK6_MAJOR 70 -#define SCSI_DISK7_MAJOR 71 - -#define COMPAQ_SMART2_MAJOR 72 -#define COMPAQ_SMART2_MAJOR1 73 -#define COMPAQ_SMART2_MAJOR2 74 -#define COMPAQ_SMART2_MAJOR3 75 -#define COMPAQ_SMART2_MAJOR4 76 -#define COMPAQ_SMART2_MAJOR5 77 -#define COMPAQ_SMART2_MAJOR6 78 -#define COMPAQ_SMART2_MAJOR7 79 - -#define SPECIALIX_NORMAL_MAJOR 75 -#define SPECIALIX_CALLOUT_MAJOR 76 - -#define AURORA_MAJOR 79 - -#define I2O_MAJOR 80 /* 80->87 */ - -#define SHMIQ_MAJOR 85 /* Linux/mips, SGI /dev/shmiq */ -#define SCSI_CHANGER_MAJOR 86 - -#define IDE6_MAJOR 88 -#define IDE7_MAJOR 89 -#define IDE8_MAJOR 90 -#define MTD_CHAR_MAJOR 90 -#define IDE9_MAJOR 91 - -#define DASD_MAJOR 94 - -#define MDISK_MAJOR 95 - -#define UBD_MAJOR 98 - -#define PP_MAJOR 99 -#define JSFD_MAJOR 99 - -#define PHONE_MAJOR 100 - -#define COMPAQ_CISS_MAJOR 104 -#define COMPAQ_CISS_MAJOR1 105 -#define COMPAQ_CISS_MAJOR2 106 -#define COMPAQ_CISS_MAJOR3 107 -#define COMPAQ_CISS_MAJOR4 108 -#define COMPAQ_CISS_MAJOR5 109 -#define COMPAQ_CISS_MAJOR6 110 -#define COMPAQ_CISS_MAJOR7 111 - -#define VIODASD_MAJOR 112 -#define VIOCD_MAJOR 113 - -#define ATARAID_MAJOR 114 - -#define SCSI_DISK8_MAJOR 128 -#define SCSI_DISK9_MAJOR 129 -#define SCSI_DISK10_MAJOR 130 -#define SCSI_DISK11_MAJOR 131 -#define SCSI_DISK12_MAJOR 132 -#define SCSI_DISK13_MAJOR 133 -#define SCSI_DISK14_MAJOR 134 -#define SCSI_DISK15_MAJOR 135 - -#define UNIX98_PTY_MASTER_MAJOR 128 -#define UNIX98_PTY_MAJOR_COUNT 8 -#define UNIX98_PTY_SLAVE_MAJOR (UNIX98_PTY_MASTER_MAJOR+UNIX98_PTY_MAJOR_COUNT) - -#define DRBD_MAJOR 147 -#define RTF_MAJOR 150 -#define RAW_MAJOR 162 - -#define USB_ACM_MAJOR 166 -#define USB_ACM_AUX_MAJOR 167 -#define USB_CHAR_MAJOR 180 - -#define MMC_BLOCK_MAJOR 179 - -#define VXVM_MAJOR 199 /* VERITAS volume i/o driver */ -#define VXSPEC_MAJOR 200 /* VERITAS volume config driver */ -#define VXDMP_MAJOR 201 /* VERITAS volume multipath driver */ - -#define XENVBD_MAJOR 202 /* Xen virtual block device */ - -#define MSR_MAJOR 202 -#define CPUID_MAJOR 203 - -#define OSST_MAJOR 206 /* OnStream-SCx0 SCSI tape */ - -#define IBM_TTY3270_MAJOR 227 -#define IBM_FS3270_MAJOR 228 - -#define VIOTAPE_MAJOR 230 - -#define BLOCK_EXT_MAJOR 259 -#define SCSI_OSD_MAJOR 260 /* open-osd's OSD scsi device */ - -#endif diff --git a/src/linux/include/uapi/linux/mdio.h b/src/linux/include/uapi/linux/mdio.h deleted file mode 100644 index c94a510..0000000 --- a/src/linux/include/uapi/linux/mdio.h +++ /dev/null @@ -1,297 +0,0 @@ -/* - * linux/mdio.h: definitions for MDIO (clause 45) transceivers - * Copyright 2006-2009 Solarflare Communications Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published - * by the Free Software Foundation, incorporated herein by reference. - */ - -#ifndef _UAPI__LINUX_MDIO_H__ -#define _UAPI__LINUX_MDIO_H__ - -#include -#include - -/* MDIO Manageable Devices (MMDs). */ -#define MDIO_MMD_PMAPMD 1 /* Physical Medium Attachment/ - * Physical Medium Dependent */ -#define MDIO_MMD_WIS 2 /* WAN Interface Sublayer */ -#define MDIO_MMD_PCS 3 /* Physical Coding Sublayer */ -#define MDIO_MMD_PHYXS 4 /* PHY Extender Sublayer */ -#define MDIO_MMD_DTEXS 5 /* DTE Extender Sublayer */ -#define MDIO_MMD_TC 6 /* Transmission Convergence */ -#define MDIO_MMD_AN 7 /* Auto-Negotiation */ -#define MDIO_MMD_C22EXT 29 /* Clause 22 extension */ -#define MDIO_MMD_VEND1 30 /* Vendor specific 1 */ -#define MDIO_MMD_VEND2 31 /* Vendor specific 2 */ - -/* Generic MDIO registers. */ -#define MDIO_CTRL1 MII_BMCR -#define MDIO_STAT1 MII_BMSR -#define MDIO_DEVID1 MII_PHYSID1 -#define MDIO_DEVID2 MII_PHYSID2 -#define MDIO_SPEED 4 /* Speed ability */ -#define MDIO_DEVS1 5 /* Devices in package */ -#define MDIO_DEVS2 6 -#define MDIO_CTRL2 7 /* 10G control 2 */ -#define MDIO_STAT2 8 /* 10G status 2 */ -#define MDIO_PMA_TXDIS 9 /* 10G PMA/PMD transmit disable */ -#define MDIO_PMA_RXDET 10 /* 10G PMA/PMD receive signal detect */ -#define MDIO_PMA_EXTABLE 11 /* 10G PMA/PMD extended ability */ -#define MDIO_PKGID1 14 /* Package identifier */ -#define MDIO_PKGID2 15 -#define MDIO_AN_ADVERTISE 16 /* AN advertising (base page) */ -#define MDIO_AN_LPA 19 /* AN LP abilities (base page) */ -#define MDIO_PCS_EEE_ABLE 20 /* EEE Capability register */ -#define MDIO_PCS_EEE_WK_ERR 22 /* EEE wake error counter */ -#define MDIO_PHYXS_LNSTAT 24 /* PHY XGXS lane state */ -#define MDIO_AN_EEE_ADV 60 /* EEE advertisement */ -#define MDIO_AN_EEE_LPABLE 61 /* EEE link partner ability */ - -/* Media-dependent registers. */ -#define MDIO_PMA_10GBT_SWAPPOL 130 /* 10GBASE-T pair swap & polarity */ -#define MDIO_PMA_10GBT_TXPWR 131 /* 10GBASE-T TX power control */ -#define MDIO_PMA_10GBT_SNR 133 /* 10GBASE-T SNR margin, lane A. - * Lanes B-D are numbered 134-136. */ -#define MDIO_PMA_10GBR_FECABLE 170 /* 10GBASE-R FEC ability */ -#define MDIO_PCS_10GBX_STAT1 24 /* 10GBASE-X PCS status 1 */ -#define MDIO_PCS_10GBRT_STAT1 32 /* 10GBASE-R/-T PCS status 1 */ -#define MDIO_PCS_10GBRT_STAT2 33 /* 10GBASE-R/-T PCS status 2 */ -#define MDIO_AN_10GBT_CTRL 32 /* 10GBASE-T auto-negotiation control */ -#define MDIO_AN_10GBT_STAT 33 /* 10GBASE-T auto-negotiation status */ - -/* LASI (Link Alarm Status Interrupt) registers, defined by XENPAK MSA. */ -#define MDIO_PMA_LASI_RXCTRL 0x9000 /* RX_ALARM control */ -#define MDIO_PMA_LASI_TXCTRL 0x9001 /* TX_ALARM control */ -#define MDIO_PMA_LASI_CTRL 0x9002 /* LASI control */ -#define MDIO_PMA_LASI_RXSTAT 0x9003 /* RX_ALARM status */ -#define MDIO_PMA_LASI_TXSTAT 0x9004 /* TX_ALARM status */ -#define MDIO_PMA_LASI_STAT 0x9005 /* LASI status */ - -/* Control register 1. */ -/* Enable extended speed selection */ -#define MDIO_CTRL1_SPEEDSELEXT (BMCR_SPEED1000 | BMCR_SPEED100) -/* All speed selection bits */ -#define MDIO_CTRL1_SPEEDSEL (MDIO_CTRL1_SPEEDSELEXT | 0x003c) -#define MDIO_CTRL1_FULLDPLX BMCR_FULLDPLX -#define MDIO_CTRL1_LPOWER BMCR_PDOWN -#define MDIO_CTRL1_RESET BMCR_RESET -#define MDIO_PMA_CTRL1_LOOPBACK 0x0001 -#define MDIO_PMA_CTRL1_SPEED1000 BMCR_SPEED1000 -#define MDIO_PMA_CTRL1_SPEED100 BMCR_SPEED100 -#define MDIO_PCS_CTRL1_LOOPBACK BMCR_LOOPBACK -#define MDIO_PHYXS_CTRL1_LOOPBACK BMCR_LOOPBACK -#define MDIO_AN_CTRL1_RESTART BMCR_ANRESTART -#define MDIO_AN_CTRL1_ENABLE BMCR_ANENABLE -#define MDIO_AN_CTRL1_XNP 0x2000 /* Enable extended next page */ -#define MDIO_PCS_CTRL1_CLKSTOP_EN 0x400 /* Stop the clock during LPI */ - -/* 10 Gb/s */ -#define MDIO_CTRL1_SPEED10G (MDIO_CTRL1_SPEEDSELEXT | 0x00) -/* 10PASS-TS/2BASE-TL */ -#define MDIO_CTRL1_SPEED10P2B (MDIO_CTRL1_SPEEDSELEXT | 0x04) - -/* Status register 1. */ -#define MDIO_STAT1_LPOWERABLE 0x0002 /* Low-power ability */ -#define MDIO_STAT1_LSTATUS BMSR_LSTATUS -#define MDIO_STAT1_FAULT 0x0080 /* Fault */ -#define MDIO_AN_STAT1_LPABLE 0x0001 /* Link partner AN ability */ -#define MDIO_AN_STAT1_ABLE BMSR_ANEGCAPABLE -#define MDIO_AN_STAT1_RFAULT BMSR_RFAULT -#define MDIO_AN_STAT1_COMPLETE BMSR_ANEGCOMPLETE -#define MDIO_AN_STAT1_PAGE 0x0040 /* Page received */ -#define MDIO_AN_STAT1_XNP 0x0080 /* Extended next page status */ - -/* Speed register. */ -#define MDIO_SPEED_10G 0x0001 /* 10G capable */ -#define MDIO_PMA_SPEED_2B 0x0002 /* 2BASE-TL capable */ -#define MDIO_PMA_SPEED_10P 0x0004 /* 10PASS-TS capable */ -#define MDIO_PMA_SPEED_1000 0x0010 /* 1000M capable */ -#define MDIO_PMA_SPEED_100 0x0020 /* 100M capable */ -#define MDIO_PMA_SPEED_10 0x0040 /* 10M capable */ -#define MDIO_PCS_SPEED_10P2B 0x0002 /* 10PASS-TS/2BASE-TL capable */ - -/* Device present registers. */ -#define MDIO_DEVS_PRESENT(devad) (1 << (devad)) -#define MDIO_DEVS_PMAPMD MDIO_DEVS_PRESENT(MDIO_MMD_PMAPMD) -#define MDIO_DEVS_WIS MDIO_DEVS_PRESENT(MDIO_MMD_WIS) -#define MDIO_DEVS_PCS MDIO_DEVS_PRESENT(MDIO_MMD_PCS) -#define MDIO_DEVS_PHYXS MDIO_DEVS_PRESENT(MDIO_MMD_PHYXS) -#define MDIO_DEVS_DTEXS MDIO_DEVS_PRESENT(MDIO_MMD_DTEXS) -#define MDIO_DEVS_TC MDIO_DEVS_PRESENT(MDIO_MMD_TC) -#define MDIO_DEVS_AN MDIO_DEVS_PRESENT(MDIO_MMD_AN) -#define MDIO_DEVS_C22EXT MDIO_DEVS_PRESENT(MDIO_MMD_C22EXT) - -/* Control register 2. */ -#define MDIO_PMA_CTRL2_TYPE 0x000f /* PMA/PMD type selection */ -#define MDIO_PMA_CTRL2_10GBCX4 0x0000 /* 10GBASE-CX4 type */ -#define MDIO_PMA_CTRL2_10GBEW 0x0001 /* 10GBASE-EW type */ -#define MDIO_PMA_CTRL2_10GBLW 0x0002 /* 10GBASE-LW type */ -#define MDIO_PMA_CTRL2_10GBSW 0x0003 /* 10GBASE-SW type */ -#define MDIO_PMA_CTRL2_10GBLX4 0x0004 /* 10GBASE-LX4 type */ -#define MDIO_PMA_CTRL2_10GBER 0x0005 /* 10GBASE-ER type */ -#define MDIO_PMA_CTRL2_10GBLR 0x0006 /* 10GBASE-LR type */ -#define MDIO_PMA_CTRL2_10GBSR 0x0007 /* 10GBASE-SR type */ -#define MDIO_PMA_CTRL2_10GBLRM 0x0008 /* 10GBASE-LRM type */ -#define MDIO_PMA_CTRL2_10GBT 0x0009 /* 10GBASE-T type */ -#define MDIO_PMA_CTRL2_10GBKX4 0x000a /* 10GBASE-KX4 type */ -#define MDIO_PMA_CTRL2_10GBKR 0x000b /* 10GBASE-KR type */ -#define MDIO_PMA_CTRL2_1000BT 0x000c /* 1000BASE-T type */ -#define MDIO_PMA_CTRL2_1000BKX 0x000d /* 1000BASE-KX type */ -#define MDIO_PMA_CTRL2_100BTX 0x000e /* 100BASE-TX type */ -#define MDIO_PMA_CTRL2_10BT 0x000f /* 10BASE-T type */ -#define MDIO_PCS_CTRL2_TYPE 0x0003 /* PCS type selection */ -#define MDIO_PCS_CTRL2_10GBR 0x0000 /* 10GBASE-R type */ -#define MDIO_PCS_CTRL2_10GBX 0x0001 /* 10GBASE-X type */ -#define MDIO_PCS_CTRL2_10GBW 0x0002 /* 10GBASE-W type */ -#define MDIO_PCS_CTRL2_10GBT 0x0003 /* 10GBASE-T type */ - -/* Status register 2. */ -#define MDIO_STAT2_RXFAULT 0x0400 /* Receive fault */ -#define MDIO_STAT2_TXFAULT 0x0800 /* Transmit fault */ -#define MDIO_STAT2_DEVPRST 0xc000 /* Device present */ -#define MDIO_STAT2_DEVPRST_VAL 0x8000 /* Device present value */ -#define MDIO_PMA_STAT2_LBABLE 0x0001 /* PMA loopback ability */ -#define MDIO_PMA_STAT2_10GBEW 0x0002 /* 10GBASE-EW ability */ -#define MDIO_PMA_STAT2_10GBLW 0x0004 /* 10GBASE-LW ability */ -#define MDIO_PMA_STAT2_10GBSW 0x0008 /* 10GBASE-SW ability */ -#define MDIO_PMA_STAT2_10GBLX4 0x0010 /* 10GBASE-LX4 ability */ -#define MDIO_PMA_STAT2_10GBER 0x0020 /* 10GBASE-ER ability */ -#define MDIO_PMA_STAT2_10GBLR 0x0040 /* 10GBASE-LR ability */ -#define MDIO_PMA_STAT2_10GBSR 0x0080 /* 10GBASE-SR ability */ -#define MDIO_PMD_STAT2_TXDISAB 0x0100 /* PMD TX disable ability */ -#define MDIO_PMA_STAT2_EXTABLE 0x0200 /* Extended abilities */ -#define MDIO_PMA_STAT2_RXFLTABLE 0x1000 /* Receive fault ability */ -#define MDIO_PMA_STAT2_TXFLTABLE 0x2000 /* Transmit fault ability */ -#define MDIO_PCS_STAT2_10GBR 0x0001 /* 10GBASE-R capable */ -#define MDIO_PCS_STAT2_10GBX 0x0002 /* 10GBASE-X capable */ -#define MDIO_PCS_STAT2_10GBW 0x0004 /* 10GBASE-W capable */ -#define MDIO_PCS_STAT2_RXFLTABLE 0x1000 /* Receive fault ability */ -#define MDIO_PCS_STAT2_TXFLTABLE 0x2000 /* Transmit fault ability */ - -/* Transmit disable register. */ -#define MDIO_PMD_TXDIS_GLOBAL 0x0001 /* Global PMD TX disable */ -#define MDIO_PMD_TXDIS_0 0x0002 /* PMD TX disable 0 */ -#define MDIO_PMD_TXDIS_1 0x0004 /* PMD TX disable 1 */ -#define MDIO_PMD_TXDIS_2 0x0008 /* PMD TX disable 2 */ -#define MDIO_PMD_TXDIS_3 0x0010 /* PMD TX disable 3 */ - -/* Receive signal detect register. */ -#define MDIO_PMD_RXDET_GLOBAL 0x0001 /* Global PMD RX signal detect */ -#define MDIO_PMD_RXDET_0 0x0002 /* PMD RX signal detect 0 */ -#define MDIO_PMD_RXDET_1 0x0004 /* PMD RX signal detect 1 */ -#define MDIO_PMD_RXDET_2 0x0008 /* PMD RX signal detect 2 */ -#define MDIO_PMD_RXDET_3 0x0010 /* PMD RX signal detect 3 */ - -/* Extended abilities register. */ -#define MDIO_PMA_EXTABLE_10GCX4 0x0001 /* 10GBASE-CX4 ability */ -#define MDIO_PMA_EXTABLE_10GBLRM 0x0002 /* 10GBASE-LRM ability */ -#define MDIO_PMA_EXTABLE_10GBT 0x0004 /* 10GBASE-T ability */ -#define MDIO_PMA_EXTABLE_10GBKX4 0x0008 /* 10GBASE-KX4 ability */ -#define MDIO_PMA_EXTABLE_10GBKR 0x0010 /* 10GBASE-KR ability */ -#define MDIO_PMA_EXTABLE_1000BT 0x0020 /* 1000BASE-T ability */ -#define MDIO_PMA_EXTABLE_1000BKX 0x0040 /* 1000BASE-KX ability */ -#define MDIO_PMA_EXTABLE_100BTX 0x0080 /* 100BASE-TX ability */ -#define MDIO_PMA_EXTABLE_10BT 0x0100 /* 10BASE-T ability */ - -/* PHY XGXS lane state register. */ -#define MDIO_PHYXS_LNSTAT_SYNC0 0x0001 -#define MDIO_PHYXS_LNSTAT_SYNC1 0x0002 -#define MDIO_PHYXS_LNSTAT_SYNC2 0x0004 -#define MDIO_PHYXS_LNSTAT_SYNC3 0x0008 -#define MDIO_PHYXS_LNSTAT_ALIGN 0x1000 - -/* PMA 10GBASE-T pair swap & polarity */ -#define MDIO_PMA_10GBT_SWAPPOL_ABNX 0x0001 /* Pair A/B uncrossed */ -#define MDIO_PMA_10GBT_SWAPPOL_CDNX 0x0002 /* Pair C/D uncrossed */ -#define MDIO_PMA_10GBT_SWAPPOL_AREV 0x0100 /* Pair A polarity reversed */ -#define MDIO_PMA_10GBT_SWAPPOL_BREV 0x0200 /* Pair B polarity reversed */ -#define MDIO_PMA_10GBT_SWAPPOL_CREV 0x0400 /* Pair C polarity reversed */ -#define MDIO_PMA_10GBT_SWAPPOL_DREV 0x0800 /* Pair D polarity reversed */ - -/* PMA 10GBASE-T TX power register. */ -#define MDIO_PMA_10GBT_TXPWR_SHORT 0x0001 /* Short-reach mode */ - -/* PMA 10GBASE-T SNR registers. */ -/* Value is SNR margin in dB, clamped to range [-127, 127], plus 0x8000. */ -#define MDIO_PMA_10GBT_SNR_BIAS 0x8000 -#define MDIO_PMA_10GBT_SNR_MAX 127 - -/* PMA 10GBASE-R FEC ability register. */ -#define MDIO_PMA_10GBR_FECABLE_ABLE 0x0001 /* FEC ability */ -#define MDIO_PMA_10GBR_FECABLE_ERRABLE 0x0002 /* FEC error indic. ability */ - -/* PCS 10GBASE-R/-T status register 1. */ -#define MDIO_PCS_10GBRT_STAT1_BLKLK 0x0001 /* Block lock attained */ - -/* PCS 10GBASE-R/-T status register 2. */ -#define MDIO_PCS_10GBRT_STAT2_ERR 0x00ff -#define MDIO_PCS_10GBRT_STAT2_BER 0x3f00 - -/* AN 10GBASE-T control register. */ -#define MDIO_AN_10GBT_CTRL_ADV10G 0x1000 /* Advertise 10GBASE-T */ - -/* AN 10GBASE-T status register. */ -#define MDIO_AN_10GBT_STAT_LPTRR 0x0200 /* LP training reset req. */ -#define MDIO_AN_10GBT_STAT_LPLTABLE 0x0400 /* LP loop timing ability */ -#define MDIO_AN_10GBT_STAT_LP10G 0x0800 /* LP is 10GBT capable */ -#define MDIO_AN_10GBT_STAT_REMOK 0x1000 /* Remote OK */ -#define MDIO_AN_10GBT_STAT_LOCOK 0x2000 /* Local OK */ -#define MDIO_AN_10GBT_STAT_MS 0x4000 /* Master/slave config */ -#define MDIO_AN_10GBT_STAT_MSFLT 0x8000 /* Master/slave config fault */ - -/* EEE Supported/Advertisement/LP Advertisement registers. - * - * EEE capability Register (3.20), Advertisement (7.60) and - * Link partner ability (7.61) registers have and can use the same identical - * bit masks. - */ -#define MDIO_AN_EEE_ADV_100TX 0x0002 /* Advertise 100TX EEE cap */ -#define MDIO_AN_EEE_ADV_1000T 0x0004 /* Advertise 1000T EEE cap */ -/* Note: the two defines above can be potentially used by the user-land - * and cannot remove them now. - * So, we define the new generic MDIO_EEE_100TX and MDIO_EEE_1000T macros - * using the previous ones (that can be considered obsolete). - */ -#define MDIO_EEE_100TX MDIO_AN_EEE_ADV_100TX /* 100TX EEE cap */ -#define MDIO_EEE_1000T MDIO_AN_EEE_ADV_1000T /* 1000T EEE cap */ -#define MDIO_EEE_10GT 0x0008 /* 10GT EEE cap */ -#define MDIO_EEE_1000KX 0x0010 /* 1000KX EEE cap */ -#define MDIO_EEE_10GKX4 0x0020 /* 10G KX4 EEE cap */ -#define MDIO_EEE_10GKR 0x0040 /* 10G KR EEE cap */ - -/* LASI RX_ALARM control/status registers. */ -#define MDIO_PMA_LASI_RX_PHYXSLFLT 0x0001 /* PHY XS RX local fault */ -#define MDIO_PMA_LASI_RX_PCSLFLT 0x0008 /* PCS RX local fault */ -#define MDIO_PMA_LASI_RX_PMALFLT 0x0010 /* PMA/PMD RX local fault */ -#define MDIO_PMA_LASI_RX_OPTICPOWERFLT 0x0020 /* RX optical power fault */ -#define MDIO_PMA_LASI_RX_WISLFLT 0x0200 /* WIS local fault */ - -/* LASI TX_ALARM control/status registers. */ -#define MDIO_PMA_LASI_TX_PHYXSLFLT 0x0001 /* PHY XS TX local fault */ -#define MDIO_PMA_LASI_TX_PCSLFLT 0x0008 /* PCS TX local fault */ -#define MDIO_PMA_LASI_TX_PMALFLT 0x0010 /* PMA/PMD TX local fault */ -#define MDIO_PMA_LASI_TX_LASERPOWERFLT 0x0080 /* Laser output power fault */ -#define MDIO_PMA_LASI_TX_LASERTEMPFLT 0x0100 /* Laser temperature fault */ -#define MDIO_PMA_LASI_TX_LASERBICURRFLT 0x0200 /* Laser bias current fault */ - -/* LASI control/status registers. */ -#define MDIO_PMA_LASI_LSALARM 0x0001 /* LS_ALARM enable/status */ -#define MDIO_PMA_LASI_TXALARM 0x0002 /* TX_ALARM enable/status */ -#define MDIO_PMA_LASI_RXALARM 0x0004 /* RX_ALARM enable/status */ - -/* Mapping between MDIO PRTAD/DEVAD and mii_ioctl_data::phy_id */ - -#define MDIO_PHY_ID_C45 0x8000 -#define MDIO_PHY_ID_PRTAD 0x03e0 -#define MDIO_PHY_ID_DEVAD 0x001f -#define MDIO_PHY_ID_C45_MASK \ - (MDIO_PHY_ID_C45 | MDIO_PHY_ID_PRTAD | MDIO_PHY_ID_DEVAD) - -static inline __u16 mdio_phy_id_c45(int prtad, int devad) -{ - return MDIO_PHY_ID_C45 | (prtad << 5) | devad; -} - -#endif /* _UAPI__LINUX_MDIO_H__ */ diff --git a/src/linux/include/uapi/linux/membarrier.h b/src/linux/include/uapi/linux/membarrier.h deleted file mode 100644 index e0b108b..0000000 --- a/src/linux/include/uapi/linux/membarrier.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _UAPI_LINUX_MEMBARRIER_H -#define _UAPI_LINUX_MEMBARRIER_H - -/* - * linux/membarrier.h - * - * membarrier system call API - * - * Copyright (c) 2010, 2015 Mathieu Desnoyers - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/** - * enum membarrier_cmd - membarrier system call command - * @MEMBARRIER_CMD_QUERY: Query the set of supported commands. It returns - * a bitmask of valid commands. - * @MEMBARRIER_CMD_SHARED: Execute a memory barrier on all running threads. - * Upon return from system call, the caller thread - * is ensured that all running threads have passed - * through a state where all memory accesses to - * user-space addresses match program order between - * entry to and return from the system call - * (non-running threads are de facto in such a - * state). This covers threads from all processes - * running on the system. This command returns 0. - * - * Command to be passed to the membarrier system call. The commands need to - * be a single bit each, except for MEMBARRIER_CMD_QUERY which is assigned to - * the value 0. - */ -enum membarrier_cmd { - MEMBARRIER_CMD_QUERY = 0, - MEMBARRIER_CMD_SHARED = (1 << 0), -}; - -#endif /* _UAPI_LINUX_MEMBARRIER_H */ diff --git a/src/linux/include/uapi/linux/mempolicy.h b/src/linux/include/uapi/linux/mempolicy.h deleted file mode 100644 index 9cd8b21..0000000 --- a/src/linux/include/uapi/linux/mempolicy.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * NUMA memory policies for Linux. - * Copyright 2003,2004 Andi Kleen SuSE Labs - */ -#ifndef _UAPI_LINUX_MEMPOLICY_H -#define _UAPI_LINUX_MEMPOLICY_H - -#include - - -/* - * Both the MPOL_* mempolicy mode and the MPOL_F_* optional mode flags are - * passed by the user to either set_mempolicy() or mbind() in an 'int' actual. - * The MPOL_MODE_FLAGS macro determines the legal set of optional mode flags. - */ - -/* Policies */ -enum { - MPOL_DEFAULT, - MPOL_PREFERRED, - MPOL_BIND, - MPOL_INTERLEAVE, - MPOL_LOCAL, - MPOL_MAX, /* always last member of enum */ -}; - -enum mpol_rebind_step { - MPOL_REBIND_ONCE, /* do rebind work at once(not by two step) */ - MPOL_REBIND_STEP1, /* first step(set all the newly nodes) */ - MPOL_REBIND_STEP2, /* second step(clean all the disallowed nodes)*/ - MPOL_REBIND_NSTEP, -}; - -/* Flags for set_mempolicy */ -#define MPOL_F_STATIC_NODES (1 << 15) -#define MPOL_F_RELATIVE_NODES (1 << 14) - -/* - * MPOL_MODE_FLAGS is the union of all possible optional mode flags passed to - * either set_mempolicy() or mbind(). - */ -#define MPOL_MODE_FLAGS (MPOL_F_STATIC_NODES | MPOL_F_RELATIVE_NODES) - -/* Flags for get_mempolicy */ -#define MPOL_F_NODE (1<<0) /* return next IL mode instead of node mask */ -#define MPOL_F_ADDR (1<<1) /* look up vma using address */ -#define MPOL_F_MEMS_ALLOWED (1<<2) /* return allowed memories */ - -/* Flags for mbind */ -#define MPOL_MF_STRICT (1<<0) /* Verify existing pages in the mapping */ -#define MPOL_MF_MOVE (1<<1) /* Move pages owned by this process to conform - to policy */ -#define MPOL_MF_MOVE_ALL (1<<2) /* Move every page to conform to policy */ -#define MPOL_MF_LAZY (1<<3) /* Modifies '_MOVE: lazy migrate on fault */ -#define MPOL_MF_INTERNAL (1<<4) /* Internal flags start here */ - -#define MPOL_MF_VALID (MPOL_MF_STRICT | \ - MPOL_MF_MOVE | \ - MPOL_MF_MOVE_ALL) - -/* - * Internal flags that share the struct mempolicy flags word with - * "mode flags". These flags are allocated from bit 0 up, as they - * are never OR'ed into the mode in mempolicy API arguments. - */ -#define MPOL_F_SHARED (1 << 0) /* identify shared policies */ -#define MPOL_F_LOCAL (1 << 1) /* preferred local allocation */ -#define MPOL_F_REBINDING (1 << 2) /* identify policies in rebinding */ -#define MPOL_F_MOF (1 << 3) /* this policy wants migrate on fault */ -#define MPOL_F_MORON (1 << 4) /* Migrate On protnone Reference On Node */ - - -#endif /* _UAPI_LINUX_MEMPOLICY_H */ diff --git a/src/linux/include/uapi/linux/mii.h b/src/linux/include/uapi/linux/mii.h deleted file mode 100644 index 15d8510..0000000 --- a/src/linux/include/uapi/linux/mii.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * linux/mii.h: definitions for MII-compatible transceivers - * Originally drivers/net/sunhme.h. - * - * Copyright (C) 1996, 1999, 2001 David S. Miller (davem@redhat.com) - */ - -#ifndef _UAPI__LINUX_MII_H__ -#define _UAPI__LINUX_MII_H__ - -#include -#include - -/* Generic MII registers. */ -#define MII_BMCR 0x00 /* Basic mode control register */ -#define MII_BMSR 0x01 /* Basic mode status register */ -#define MII_PHYSID1 0x02 /* PHYS ID 1 */ -#define MII_PHYSID2 0x03 /* PHYS ID 2 */ -#define MII_ADVERTISE 0x04 /* Advertisement control reg */ -#define MII_LPA 0x05 /* Link partner ability reg */ -#define MII_EXPANSION 0x06 /* Expansion register */ -#define MII_CTRL1000 0x09 /* 1000BASE-T control */ -#define MII_STAT1000 0x0a /* 1000BASE-T status */ -#define MII_MMD_CTRL 0x0d /* MMD Access Control Register */ -#define MII_MMD_DATA 0x0e /* MMD Access Data Register */ -#define MII_ESTATUS 0x0f /* Extended Status */ -#define MII_DCOUNTER 0x12 /* Disconnect counter */ -#define MII_FCSCOUNTER 0x13 /* False carrier counter */ -#define MII_NWAYTEST 0x14 /* N-way auto-neg test reg */ -#define MII_RERRCOUNTER 0x15 /* Receive error counter */ -#define MII_SREVISION 0x16 /* Silicon revision */ -#define MII_RESV1 0x17 /* Reserved... */ -#define MII_LBRERROR 0x18 /* Lpback, rx, bypass error */ -#define MII_PHYADDR 0x19 /* PHY address */ -#define MII_RESV2 0x1a /* Reserved... */ -#define MII_TPISTATUS 0x1b /* TPI status for 10mbps */ -#define MII_NCONFIG 0x1c /* Network interface config */ - -/* Basic mode control register. */ -#define BMCR_RESV 0x003f /* Unused... */ -#define BMCR_SPEED1000 0x0040 /* MSB of Speed (1000) */ -#define BMCR_CTST 0x0080 /* Collision test */ -#define BMCR_FULLDPLX 0x0100 /* Full duplex */ -#define BMCR_ANRESTART 0x0200 /* Auto negotiation restart */ -#define BMCR_ISOLATE 0x0400 /* Isolate data paths from MII */ -#define BMCR_PDOWN 0x0800 /* Enable low power state */ -#define BMCR_ANENABLE 0x1000 /* Enable auto negotiation */ -#define BMCR_SPEED100 0x2000 /* Select 100Mbps */ -#define BMCR_LOOPBACK 0x4000 /* TXD loopback bits */ -#define BMCR_RESET 0x8000 /* Reset to default state */ -#define BMCR_SPEED10 0x0000 /* Select 10Mbps */ - -/* Basic mode status register. */ -#define BMSR_ERCAP 0x0001 /* Ext-reg capability */ -#define BMSR_JCD 0x0002 /* Jabber detected */ -#define BMSR_LSTATUS 0x0004 /* Link status */ -#define BMSR_ANEGCAPABLE 0x0008 /* Able to do auto-negotiation */ -#define BMSR_RFAULT 0x0010 /* Remote fault detected */ -#define BMSR_ANEGCOMPLETE 0x0020 /* Auto-negotiation complete */ -#define BMSR_RESV 0x00c0 /* Unused... */ -#define BMSR_ESTATEN 0x0100 /* Extended Status in R15 */ -#define BMSR_100HALF2 0x0200 /* Can do 100BASE-T2 HDX */ -#define BMSR_100FULL2 0x0400 /* Can do 100BASE-T2 FDX */ -#define BMSR_10HALF 0x0800 /* Can do 10mbps, half-duplex */ -#define BMSR_10FULL 0x1000 /* Can do 10mbps, full-duplex */ -#define BMSR_100HALF 0x2000 /* Can do 100mbps, half-duplex */ -#define BMSR_100FULL 0x4000 /* Can do 100mbps, full-duplex */ -#define BMSR_100BASE4 0x8000 /* Can do 100mbps, 4k packets */ - -/* Advertisement control register. */ -#define ADVERTISE_SLCT 0x001f /* Selector bits */ -#define ADVERTISE_CSMA 0x0001 /* Only selector supported */ -#define ADVERTISE_10HALF 0x0020 /* Try for 10mbps half-duplex */ -#define ADVERTISE_1000XFULL 0x0020 /* Try for 1000BASE-X full-duplex */ -#define ADVERTISE_10FULL 0x0040 /* Try for 10mbps full-duplex */ -#define ADVERTISE_1000XHALF 0x0040 /* Try for 1000BASE-X half-duplex */ -#define ADVERTISE_100HALF 0x0080 /* Try for 100mbps half-duplex */ -#define ADVERTISE_1000XPAUSE 0x0080 /* Try for 1000BASE-X pause */ -#define ADVERTISE_100FULL 0x0100 /* Try for 100mbps full-duplex */ -#define ADVERTISE_1000XPSE_ASYM 0x0100 /* Try for 1000BASE-X asym pause */ -#define ADVERTISE_100BASE4 0x0200 /* Try for 100mbps 4k packets */ -#define ADVERTISE_PAUSE_CAP 0x0400 /* Try for pause */ -#define ADVERTISE_PAUSE_ASYM 0x0800 /* Try for asymetric pause */ -#define ADVERTISE_RESV 0x1000 /* Unused... */ -#define ADVERTISE_RFAULT 0x2000 /* Say we can detect faults */ -#define ADVERTISE_LPACK 0x4000 /* Ack link partners response */ -#define ADVERTISE_NPAGE 0x8000 /* Next page bit */ - -#define ADVERTISE_FULL (ADVERTISE_100FULL | ADVERTISE_10FULL | \ - ADVERTISE_CSMA) -#define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \ - ADVERTISE_100HALF | ADVERTISE_100FULL) - -/* Link partner ability register. */ -#define LPA_SLCT 0x001f /* Same as advertise selector */ -#define LPA_10HALF 0x0020 /* Can do 10mbps half-duplex */ -#define LPA_1000XFULL 0x0020 /* Can do 1000BASE-X full-duplex */ -#define LPA_10FULL 0x0040 /* Can do 10mbps full-duplex */ -#define LPA_1000XHALF 0x0040 /* Can do 1000BASE-X half-duplex */ -#define LPA_100HALF 0x0080 /* Can do 100mbps half-duplex */ -#define LPA_1000XPAUSE 0x0080 /* Can do 1000BASE-X pause */ -#define LPA_100FULL 0x0100 /* Can do 100mbps full-duplex */ -#define LPA_1000XPAUSE_ASYM 0x0100 /* Can do 1000BASE-X pause asym*/ -#define LPA_100BASE4 0x0200 /* Can do 100mbps 4k packets */ -#define LPA_PAUSE_CAP 0x0400 /* Can pause */ -#define LPA_PAUSE_ASYM 0x0800 /* Can pause asymetrically */ -#define LPA_RESV 0x1000 /* Unused... */ -#define LPA_RFAULT 0x2000 /* Link partner faulted */ -#define LPA_LPACK 0x4000 /* Link partner acked us */ -#define LPA_NPAGE 0x8000 /* Next page bit */ - -#define LPA_DUPLEX (LPA_10FULL | LPA_100FULL) -#define LPA_100 (LPA_100FULL | LPA_100HALF | LPA_100BASE4) - -/* Expansion register for auto-negotiation. */ -#define EXPANSION_NWAY 0x0001 /* Can do N-way auto-nego */ -#define EXPANSION_LCWP 0x0002 /* Got new RX page code word */ -#define EXPANSION_ENABLENPAGE 0x0004 /* This enables npage words */ -#define EXPANSION_NPCAPABLE 0x0008 /* Link partner supports npage */ -#define EXPANSION_MFAULTS 0x0010 /* Multiple faults detected */ -#define EXPANSION_RESV 0xffe0 /* Unused... */ - -#define ESTATUS_1000_TFULL 0x2000 /* Can do 1000BT Full */ -#define ESTATUS_1000_THALF 0x1000 /* Can do 1000BT Half */ - -/* N-way test register. */ -#define NWAYTEST_RESV1 0x00ff /* Unused... */ -#define NWAYTEST_LOOPBACK 0x0100 /* Enable loopback for N-way */ -#define NWAYTEST_RESV2 0xfe00 /* Unused... */ - -/* 1000BASE-T Control register */ -#define ADVERTISE_1000FULL 0x0200 /* Advertise 1000BASE-T full duplex */ -#define ADVERTISE_1000HALF 0x0100 /* Advertise 1000BASE-T half duplex */ -#define CTL1000_AS_MASTER 0x0800 -#define CTL1000_ENABLE_MASTER 0x1000 - -/* 1000BASE-T Status register */ -#define LPA_1000LOCALRXOK 0x2000 /* Link partner local receiver status */ -#define LPA_1000REMRXOK 0x1000 /* Link partner remote receiver status */ -#define LPA_1000FULL 0x0800 /* Link partner 1000BASE-T full duplex */ -#define LPA_1000HALF 0x0400 /* Link partner 1000BASE-T half duplex */ - -/* Flow control flags */ -#define FLOW_CTRL_TX 0x01 -#define FLOW_CTRL_RX 0x02 - -/* MMD Access Control register fields */ -#define MII_MMD_CTRL_DEVAD_MASK 0x1f /* Mask MMD DEVAD*/ -#define MII_MMD_CTRL_ADDR 0x0000 /* Address */ -#define MII_MMD_CTRL_NOINCR 0x4000 /* no post increment */ -#define MII_MMD_CTRL_INCR_RDWT 0x8000 /* post increment on reads & writes */ -#define MII_MMD_CTRL_INCR_ON_WT 0xC000 /* post increment on writes only */ - -/* This structure is used in all SIOCxMIIxxx ioctl calls */ -struct mii_ioctl_data { - __u16 phy_id; - __u16 reg_num; - __u16 val_in; - __u16 val_out; -}; - -#endif /* _UAPI__LINUX_MII_H__ */ diff --git a/src/linux/include/uapi/linux/mman.h b/src/linux/include/uapi/linux/mman.h deleted file mode 100644 index ade4acd..0000000 --- a/src/linux/include/uapi/linux/mman.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _UAPI_LINUX_MMAN_H -#define _UAPI_LINUX_MMAN_H - -#include - -#define MREMAP_MAYMOVE 1 -#define MREMAP_FIXED 2 - -#define OVERCOMMIT_GUESS 0 -#define OVERCOMMIT_ALWAYS 1 -#define OVERCOMMIT_NEVER 2 - -#endif /* _UAPI_LINUX_MMAN_H */ diff --git a/src/linux/include/uapi/linux/mpls.h b/src/linux/include/uapi/linux/mpls.h deleted file mode 100644 index 24a6cb1..0000000 --- a/src/linux/include/uapi/linux/mpls.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef _UAPI_MPLS_H -#define _UAPI_MPLS_H - -#include -#include - -/* Reference: RFC 5462, RFC 3032 - * - * 0 1 2 3 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Label | TC |S| TTL | - * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * - * Label: Label Value, 20 bits - * TC: Traffic Class field, 3 bits - * S: Bottom of Stack, 1 bit - * TTL: Time to Live, 8 bits - */ - -struct mpls_label { - __be32 entry; -}; - -#define MPLS_LS_LABEL_MASK 0xFFFFF000 -#define MPLS_LS_LABEL_SHIFT 12 -#define MPLS_LS_TC_MASK 0x00000E00 -#define MPLS_LS_TC_SHIFT 9 -#define MPLS_LS_S_MASK 0x00000100 -#define MPLS_LS_S_SHIFT 8 -#define MPLS_LS_TTL_MASK 0x000000FF -#define MPLS_LS_TTL_SHIFT 0 - -/* Reserved labels */ -#define MPLS_LABEL_IPV4NULL 0 /* RFC3032 */ -#define MPLS_LABEL_RTALERT 1 /* RFC3032 */ -#define MPLS_LABEL_IPV6NULL 2 /* RFC3032 */ -#define MPLS_LABEL_IMPLNULL 3 /* RFC3032 */ -#define MPLS_LABEL_ENTROPY 7 /* RFC6790 */ -#define MPLS_LABEL_GAL 13 /* RFC5586 */ -#define MPLS_LABEL_OAMALERT 14 /* RFC3429 */ -#define MPLS_LABEL_EXTENSION 15 /* RFC7274 */ - -#define MPLS_LABEL_FIRST_UNRESERVED 16 /* RFC3032 */ - -#endif /* _UAPI_MPLS_H */ diff --git a/src/linux/include/uapi/linux/mqueue.h b/src/linux/include/uapi/linux/mqueue.h deleted file mode 100644 index d0a2b8e..0000000 --- a/src/linux/include/uapi/linux/mqueue.h +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright (C) 2003 Krzysztof Benedyczak & Michal Wronski - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - It is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this software; if not, write to the Free - Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - 02111-1307 USA. */ - -#ifndef _LINUX_MQUEUE_H -#define _LINUX_MQUEUE_H - -#define MQ_PRIO_MAX 32768 -/* per-uid limit of kernel memory used by mqueue, in bytes */ -#define MQ_BYTES_MAX 819200 - -struct mq_attr { - __kernel_long_t mq_flags; /* message queue flags */ - __kernel_long_t mq_maxmsg; /* maximum number of messages */ - __kernel_long_t mq_msgsize; /* maximum message size */ - __kernel_long_t mq_curmsgs; /* number of messages currently queued */ - __kernel_long_t __reserved[4]; /* ignored for input, zeroed for output */ -}; - -/* - * SIGEV_THREAD implementation: - * SIGEV_THREAD must be implemented in user space. If SIGEV_THREAD is passed - * to mq_notify, then - * - sigev_signo must be the file descriptor of an AF_NETLINK socket. It's not - * necessary that the socket is bound. - * - sigev_value.sival_ptr must point to a cookie that is NOTIFY_COOKIE_LEN - * bytes long. - * If the notification is triggered, then the cookie is sent to the netlink - * socket. The last byte of the cookie is replaced with the NOTIFY_?? codes: - * NOTIFY_WOKENUP if the notification got triggered, NOTIFY_REMOVED if it was - * removed, either due to a close() on the message queue fd or due to a - * mq_notify() that removed the notification. - */ -#define NOTIFY_NONE 0 -#define NOTIFY_WOKENUP 1 -#define NOTIFY_REMOVED 2 - -#define NOTIFY_COOKIE_LEN 32 - -#endif diff --git a/src/linux/include/uapi/linux/mroute.h b/src/linux/include/uapi/linux/mroute.h deleted file mode 100644 index cf94301..0000000 --- a/src/linux/include/uapi/linux/mroute.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef _UAPI__LINUX_MROUTE_H -#define _UAPI__LINUX_MROUTE_H - -#include -#include - -/* Based on the MROUTING 3.5 defines primarily to keep - * source compatibility with BSD. - * - * See the mrouted code for the original history. - * - * Protocol Independent Multicast (PIM) data structures included - * Carlos Picoto (cap@di.fc.ul.pt) - */ - -#define MRT_BASE 200 -#define MRT_INIT (MRT_BASE) /* Activate the kernel mroute code */ -#define MRT_DONE (MRT_BASE+1) /* Shutdown the kernel mroute */ -#define MRT_ADD_VIF (MRT_BASE+2) /* Add a virtual interface */ -#define MRT_DEL_VIF (MRT_BASE+3) /* Delete a virtual interface */ -#define MRT_ADD_MFC (MRT_BASE+4) /* Add a multicast forwarding entry */ -#define MRT_DEL_MFC (MRT_BASE+5) /* Delete a multicast forwarding entry */ -#define MRT_VERSION (MRT_BASE+6) /* Get the kernel multicast version */ -#define MRT_ASSERT (MRT_BASE+7) /* Activate PIM assert mode */ -#define MRT_PIM (MRT_BASE+8) /* enable PIM code */ -#define MRT_TABLE (MRT_BASE+9) /* Specify mroute table ID */ -#define MRT_ADD_MFC_PROXY (MRT_BASE+10) /* Add a (*,*|G) mfc entry */ -#define MRT_DEL_MFC_PROXY (MRT_BASE+11) /* Del a (*,*|G) mfc entry */ -#define MRT_MAX (MRT_BASE+11) - -#define SIOCGETVIFCNT SIOCPROTOPRIVATE /* IP protocol privates */ -#define SIOCGETSGCNT (SIOCPROTOPRIVATE+1) -#define SIOCGETRPF (SIOCPROTOPRIVATE+2) - -#define MAXVIFS 32 -typedef unsigned long vifbitmap_t; /* User mode code depends on this lot */ -typedef unsigned short vifi_t; -#define ALL_VIFS ((vifi_t)(-1)) - -/* Same idea as select */ - -#define VIFM_SET(n,m) ((m)|=(1<<(n))) -#define VIFM_CLR(n,m) ((m)&=~(1<<(n))) -#define VIFM_ISSET(n,m) ((m)&(1<<(n))) -#define VIFM_CLRALL(m) ((m)=0) -#define VIFM_COPY(mfrom,mto) ((mto)=(mfrom)) -#define VIFM_SAME(m1,m2) ((m1)==(m2)) - -/* Passed by mrouted for an MRT_ADD_VIF - again we use the - * mrouted 3.6 structures for compatibility - */ -struct vifctl { - vifi_t vifc_vifi; /* Index of VIF */ - unsigned char vifc_flags; /* VIFF_ flags */ - unsigned char vifc_threshold; /* ttl limit */ - unsigned int vifc_rate_limit; /* Rate limiter values (NI) */ - union { - struct in_addr vifc_lcl_addr; /* Local interface address */ - int vifc_lcl_ifindex; /* Local interface index */ - }; - struct in_addr vifc_rmt_addr; /* IPIP tunnel addr */ -}; - -#define VIFF_TUNNEL 0x1 /* IPIP tunnel */ -#define VIFF_SRCRT 0x2 /* NI */ -#define VIFF_REGISTER 0x4 /* register vif */ -#define VIFF_USE_IFINDEX 0x8 /* use vifc_lcl_ifindex instead of - vifc_lcl_addr to find an interface */ - -/* Cache manipulation structures for mrouted and PIMd */ -struct mfcctl { - struct in_addr mfcc_origin; /* Origin of mcast */ - struct in_addr mfcc_mcastgrp; /* Group in question */ - vifi_t mfcc_parent; /* Where it arrived */ - unsigned char mfcc_ttls[MAXVIFS]; /* Where it is going */ - unsigned int mfcc_pkt_cnt; /* pkt count for src-grp */ - unsigned int mfcc_byte_cnt; - unsigned int mfcc_wrong_if; - int mfcc_expire; -}; - -/* Group count retrieval for mrouted */ -struct sioc_sg_req { - struct in_addr src; - struct in_addr grp; - unsigned long pktcnt; - unsigned long bytecnt; - unsigned long wrong_if; -}; - -/* To get vif packet counts */ -struct sioc_vif_req { - vifi_t vifi; /* Which iface */ - unsigned long icount; /* In packets */ - unsigned long ocount; /* Out packets */ - unsigned long ibytes; /* In bytes */ - unsigned long obytes; /* Out bytes */ -}; - -/* This is the format the mroute daemon expects to see IGMP control - * data. Magically happens to be like an IP packet as per the original - */ -struct igmpmsg { - __u32 unused1,unused2; - unsigned char im_msgtype; /* What is this */ - unsigned char im_mbz; /* Must be zero */ - unsigned char im_vif; /* Interface (this ought to be a vifi_t!) */ - unsigned char unused3; - struct in_addr im_src,im_dst; -}; - -/* That's all usermode folks */ - -#define MFC_ASSERT_THRESH (3*HZ) /* Maximal freq. of asserts */ - -/* Pseudo messages used by mrouted */ -#define IGMPMSG_NOCACHE 1 /* Kern cache fill request to mrouted */ -#define IGMPMSG_WRONGVIF 2 /* For PIM assert processing (unused) */ -#define IGMPMSG_WHOLEPKT 3 /* For PIM Register processing */ - -#endif /* _UAPI__LINUX_MROUTE_H */ diff --git a/src/linux/include/uapi/linux/mroute6.h b/src/linux/include/uapi/linux/mroute6.h deleted file mode 100644 index 5062fb5..0000000 --- a/src/linux/include/uapi/linux/mroute6.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef _UAPI__LINUX_MROUTE6_H -#define _UAPI__LINUX_MROUTE6_H - -#include -#include -#include - -/* - * Based on the MROUTING 3.5 defines primarily to keep - * source compatibility with BSD. - * - * See the pim6sd code for the original history. - * - * Protocol Independent Multicast (PIM) data structures included - * Carlos Picoto (cap@di.fc.ul.pt) - * - */ - -#define MRT6_BASE 200 -#define MRT6_INIT (MRT6_BASE) /* Activate the kernel mroute code */ -#define MRT6_DONE (MRT6_BASE+1) /* Shutdown the kernel mroute */ -#define MRT6_ADD_MIF (MRT6_BASE+2) /* Add a virtual interface */ -#define MRT6_DEL_MIF (MRT6_BASE+3) /* Delete a virtual interface */ -#define MRT6_ADD_MFC (MRT6_BASE+4) /* Add a multicast forwarding entry */ -#define MRT6_DEL_MFC (MRT6_BASE+5) /* Delete a multicast forwarding entry */ -#define MRT6_VERSION (MRT6_BASE+6) /* Get the kernel multicast version */ -#define MRT6_ASSERT (MRT6_BASE+7) /* Activate PIM assert mode */ -#define MRT6_PIM (MRT6_BASE+8) /* enable PIM code */ -#define MRT6_TABLE (MRT6_BASE+9) /* Specify mroute table ID */ -#define MRT6_ADD_MFC_PROXY (MRT6_BASE+10) /* Add a (*,*|G) mfc entry */ -#define MRT6_DEL_MFC_PROXY (MRT6_BASE+11) /* Del a (*,*|G) mfc entry */ -#define MRT6_MAX (MRT6_BASE+11) - -#define SIOCGETMIFCNT_IN6 SIOCPROTOPRIVATE /* IP protocol privates */ -#define SIOCGETSGCNT_IN6 (SIOCPROTOPRIVATE+1) -#define SIOCGETRPF (SIOCPROTOPRIVATE+2) - -#define MAXMIFS 32 -typedef unsigned long mifbitmap_t; /* User mode code depends on this lot */ -typedef unsigned short mifi_t; -#define ALL_MIFS ((mifi_t)(-1)) - -#ifndef IF_SETSIZE -#define IF_SETSIZE 256 -#endif - -typedef __u32 if_mask; -#define NIFBITS (sizeof(if_mask) * 8) /* bits per mask */ - -typedef struct if_set { - if_mask ifs_bits[__KERNEL_DIV_ROUND_UP(IF_SETSIZE, NIFBITS)]; -} if_set; - -#define IF_SET(n, p) ((p)->ifs_bits[(n)/NIFBITS] |= (1 << ((n) % NIFBITS))) -#define IF_CLR(n, p) ((p)->ifs_bits[(n)/NIFBITS] &= ~(1 << ((n) % NIFBITS))) -#define IF_ISSET(n, p) ((p)->ifs_bits[(n)/NIFBITS] & (1 << ((n) % NIFBITS))) -#define IF_COPY(f, t) bcopy(f, t, sizeof(*(f))) -#define IF_ZERO(p) bzero(p, sizeof(*(p))) - -/* - * Passed by mrouted for an MRT_ADD_MIF - again we use the - * mrouted 3.6 structures for compatibility - */ - -struct mif6ctl { - mifi_t mif6c_mifi; /* Index of MIF */ - unsigned char mif6c_flags; /* MIFF_ flags */ - unsigned char vifc_threshold; /* ttl limit */ - __u16 mif6c_pifi; /* the index of the physical IF */ - unsigned int vifc_rate_limit; /* Rate limiter values (NI) */ -}; - -#define MIFF_REGISTER 0x1 /* register vif */ - -/* - * Cache manipulation structures for mrouted and PIMd - */ - -struct mf6cctl { - struct sockaddr_in6 mf6cc_origin; /* Origin of mcast */ - struct sockaddr_in6 mf6cc_mcastgrp; /* Group in question */ - mifi_t mf6cc_parent; /* Where it arrived */ - struct if_set mf6cc_ifset; /* Where it is going */ -}; - -/* - * Group count retrieval for pim6sd - */ - -struct sioc_sg_req6 { - struct sockaddr_in6 src; - struct sockaddr_in6 grp; - unsigned long pktcnt; - unsigned long bytecnt; - unsigned long wrong_if; -}; - -/* - * To get vif packet counts - */ - -struct sioc_mif_req6 { - mifi_t mifi; /* Which iface */ - unsigned long icount; /* In packets */ - unsigned long ocount; /* Out packets */ - unsigned long ibytes; /* In bytes */ - unsigned long obytes; /* Out bytes */ -}; - -/* - * That's all usermode folks - */ - - - -/* - * Structure used to communicate from kernel to multicast router. - * We'll overlay the structure onto an MLD header (not an IPv6 heder like igmpmsg{} - * used for IPv4 implementation). This is because this structure will be passed via an - * IPv6 raw socket, on which an application will only receiver the payload i.e the data after - * the IPv6 header and all the extension headers. (See section 3 of RFC 3542) - */ - -struct mrt6msg { -#define MRT6MSG_NOCACHE 1 -#define MRT6MSG_WRONGMIF 2 -#define MRT6MSG_WHOLEPKT 3 /* used for use level encap */ - __u8 im6_mbz; /* must be zero */ - __u8 im6_msgtype; /* what type of message */ - __u16 im6_mif; /* mif rec'd on */ - __u32 im6_pad; /* padding for 64 bit arch */ - struct in6_addr im6_src, im6_dst; -}; - -#endif /* _UAPI__LINUX_MROUTE6_H */ diff --git a/src/linux/include/uapi/linux/msdos_fs.h b/src/linux/include/uapi/linux/msdos_fs.h deleted file mode 100644 index e956704..0000000 --- a/src/linux/include/uapi/linux/msdos_fs.h +++ /dev/null @@ -1,199 +0,0 @@ -#ifndef _UAPI_LINUX_MSDOS_FS_H -#define _UAPI_LINUX_MSDOS_FS_H - -#include -#include -#include - -/* - * The MS-DOS filesystem constants/structures - */ - -#define SECTOR_SIZE 512 /* sector size (bytes) */ -#define SECTOR_BITS 9 /* log2(SECTOR_SIZE) */ -#define MSDOS_DPB (MSDOS_DPS) /* dir entries per block */ -#define MSDOS_DPB_BITS 4 /* log2(MSDOS_DPB) */ -#define MSDOS_DPS (SECTOR_SIZE / sizeof(struct msdos_dir_entry)) -#define MSDOS_DPS_BITS 4 /* log2(MSDOS_DPS) */ -#define MSDOS_LONGNAME 256 /* maximum name length */ -#define CF_LE_W(v) le16_to_cpu(v) -#define CF_LE_L(v) le32_to_cpu(v) -#define CT_LE_W(v) cpu_to_le16(v) -#define CT_LE_L(v) cpu_to_le32(v) - -#define MSDOS_ROOT_INO 1 /* The root inode number */ -#define MSDOS_FSINFO_INO 2 /* Used for managing the FSINFO block */ - -#define MSDOS_DIR_BITS 5 /* log2(sizeof(struct msdos_dir_entry)) */ - -/* directory limit */ -#define FAT_MAX_DIR_ENTRIES (65536) -#define FAT_MAX_DIR_SIZE (FAT_MAX_DIR_ENTRIES << MSDOS_DIR_BITS) - -#define ATTR_NONE 0 /* no attribute bits */ -#define ATTR_RO 1 /* read-only */ -#define ATTR_HIDDEN 2 /* hidden */ -#define ATTR_SYS 4 /* system */ -#define ATTR_VOLUME 8 /* volume label */ -#define ATTR_DIR 16 /* directory */ -#define ATTR_ARCH 32 /* archived */ - -/* attribute bits that are copied "as is" */ -#define ATTR_UNUSED (ATTR_VOLUME | ATTR_ARCH | ATTR_SYS | ATTR_HIDDEN) -/* bits that are used by the Windows 95/Windows NT extended FAT */ -#define ATTR_EXT (ATTR_RO | ATTR_HIDDEN | ATTR_SYS | ATTR_VOLUME) - -#define CASE_LOWER_BASE 8 /* base is lower case */ -#define CASE_LOWER_EXT 16 /* extension is lower case */ - -#define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */ -#define IS_FREE(n) (!*(n) || *(n) == DELETED_FLAG) - -#define FAT_LFN_LEN 255 /* maximum long name length */ -#define MSDOS_NAME 11 /* maximum name length */ -#define MSDOS_SLOTS 21 /* max # of slots for short and long names */ -#define MSDOS_DOT ". " /* ".", padded to MSDOS_NAME chars */ -#define MSDOS_DOTDOT ".. " /* "..", padded to MSDOS_NAME chars */ - -#define FAT_FIRST_ENT(s, x) ((MSDOS_SB(s)->fat_bits == 32 ? 0x0FFFFF00 : \ - MSDOS_SB(s)->fat_bits == 16 ? 0xFF00 : 0xF00) | (x)) - -/* start of data cluster's entry (number of reserved clusters) */ -#define FAT_START_ENT 2 - -/* maximum number of clusters */ -#define MAX_FAT12 0xFF4 -#define MAX_FAT16 0xFFF4 -#define MAX_FAT32 0x0FFFFFF6 -#define MAX_FAT(s) (MSDOS_SB(s)->fat_bits == 32 ? MAX_FAT32 : \ - MSDOS_SB(s)->fat_bits == 16 ? MAX_FAT16 : MAX_FAT12) - -/* bad cluster mark */ -#define BAD_FAT12 0xFF7 -#define BAD_FAT16 0xFFF7 -#define BAD_FAT32 0x0FFFFFF7 - -/* standard EOF */ -#define EOF_FAT12 0xFFF -#define EOF_FAT16 0xFFFF -#define EOF_FAT32 0x0FFFFFFF - -#define FAT_ENT_FREE (0) -#define FAT_ENT_BAD (BAD_FAT32) -#define FAT_ENT_EOF (EOF_FAT32) - -#define FAT_FSINFO_SIG1 0x41615252 -#define FAT_FSINFO_SIG2 0x61417272 -#define IS_FSINFO(x) (le32_to_cpu((x)->signature1) == FAT_FSINFO_SIG1 \ - && le32_to_cpu((x)->signature2) == FAT_FSINFO_SIG2) - -#define FAT_STATE_DIRTY 0x01 - -struct __fat_dirent { - long d_ino; - __kernel_off_t d_off; - unsigned short d_reclen; - char d_name[256]; /* We must not include limits.h! */ -}; - -/* - * ioctl commands - */ -#define VFAT_IOCTL_READDIR_BOTH _IOR('r', 1, struct __fat_dirent[2]) -#define VFAT_IOCTL_READDIR_SHORT _IOR('r', 2, struct __fat_dirent[2]) -/* has used 0x72 ('r') in collision, so skip a few */ -#define FAT_IOCTL_GET_ATTRIBUTES _IOR('r', 0x10, __u32) -#define FAT_IOCTL_SET_ATTRIBUTES _IOW('r', 0x11, __u32) -/*Android kernel has used 0x12, so we use 0x13*/ -#define FAT_IOCTL_GET_VOLUME_ID _IOR('r', 0x13, __u32) - -struct fat_boot_sector { - __u8 ignored[3]; /* Boot strap short or near jump */ - __u8 system_id[8]; /* Name - can be used to special case - partition manager volumes */ - __u8 sector_size[2]; /* bytes per logical sector */ - __u8 sec_per_clus; /* sectors/cluster */ - __le16 reserved; /* reserved sectors */ - __u8 fats; /* number of FATs */ - __u8 dir_entries[2]; /* root directory entries */ - __u8 sectors[2]; /* number of sectors */ - __u8 media; /* media code */ - __le16 fat_length; /* sectors/FAT */ - __le16 secs_track; /* sectors per track */ - __le16 heads; /* number of heads */ - __le32 hidden; /* hidden sectors (unused) */ - __le32 total_sect; /* number of sectors (if sectors == 0) */ - - union { - struct { - /* Extended BPB Fields for FAT16 */ - __u8 drive_number; /* Physical drive number */ - __u8 state; /* undocumented, but used - for mount state. */ - __u8 signature; /* extended boot signature */ - __u8 vol_id[4]; /* volume ID */ - __u8 vol_label[11]; /* volume label */ - __u8 fs_type[8]; /* file system type */ - /* other fields are not added here */ - } fat16; - - struct { - /* only used by FAT32 */ - __le32 length; /* sectors/FAT */ - __le16 flags; /* bit 8: fat mirroring, - low 4: active fat */ - __u8 version[2]; /* major, minor filesystem - version */ - __le32 root_cluster; /* first cluster in - root directory */ - __le16 info_sector; /* filesystem info sector */ - __le16 backup_boot; /* backup boot sector */ - __le16 reserved2[6]; /* Unused */ - /* Extended BPB Fields for FAT32 */ - __u8 drive_number; /* Physical drive number */ - __u8 state; /* undocumented, but used - for mount state. */ - __u8 signature; /* extended boot signature */ - __u8 vol_id[4]; /* volume ID */ - __u8 vol_label[11]; /* volume label */ - __u8 fs_type[8]; /* file system type */ - /* other fields are not added here */ - } fat32; - }; -}; - -struct fat_boot_fsinfo { - __le32 signature1; /* 0x41615252L */ - __le32 reserved1[120]; /* Nothing as far as I can tell */ - __le32 signature2; /* 0x61417272L */ - __le32 free_clusters; /* Free cluster count. -1 if unknown */ - __le32 next_cluster; /* Most recently allocated cluster */ - __le32 reserved2[4]; -}; - -struct msdos_dir_entry { - __u8 name[MSDOS_NAME];/* name and extension */ - __u8 attr; /* attribute bits */ - __u8 lcase; /* Case for base and extension */ - __u8 ctime_cs; /* Creation time, centiseconds (0-199) */ - __le16 ctime; /* Creation time */ - __le16 cdate; /* Creation date */ - __le16 adate; /* Last access date */ - __le16 starthi; /* High 16 bits of cluster in FAT32 */ - __le16 time,date,start;/* time, date and first cluster */ - __le32 size; /* file size (in bytes) */ -}; - -/* Up to 13 characters of the name */ -struct msdos_dir_slot { - __u8 id; /* sequence number for slot */ - __u8 name0_4[10]; /* first 5 characters in name */ - __u8 attr; /* attribute byte */ - __u8 reserved; /* always 0 */ - __u8 alias_checksum; /* checksum for 8.3 alias */ - __u8 name5_10[12]; /* 6 more characters in name */ - __le16 start; /* starting cluster number, 0 in long slots */ - __u8 name11_12[4]; /* last 2 characters in name */ -}; - -#endif /* _UAPI_LINUX_MSDOS_FS_H */ diff --git a/src/linux/include/uapi/linux/msg.h b/src/linux/include/uapi/linux/msg.h deleted file mode 100644 index f51c800..0000000 --- a/src/linux/include/uapi/linux/msg.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef _UAPI_LINUX_MSG_H -#define _UAPI_LINUX_MSG_H - -#include - -/* ipcs ctl commands */ -#define MSG_STAT 11 -#define MSG_INFO 12 - -/* msgrcv options */ -#define MSG_NOERROR 010000 /* no error if message is too big */ -#define MSG_EXCEPT 020000 /* recv any msg except of specified type.*/ -#define MSG_COPY 040000 /* copy (not remove) all queue messages */ - -/* Obsolete, used only for backwards compatibility and libc5 compiles */ -struct msqid_ds { - struct ipc_perm msg_perm; - struct msg *msg_first; /* first message on queue,unused */ - struct msg *msg_last; /* last message in queue,unused */ - __kernel_time_t msg_stime; /* last msgsnd time */ - __kernel_time_t msg_rtime; /* last msgrcv time */ - __kernel_time_t msg_ctime; /* last change time */ - unsigned long msg_lcbytes; /* Reuse junk fields for 32 bit */ - unsigned long msg_lqbytes; /* ditto */ - unsigned short msg_cbytes; /* current number of bytes on queue */ - unsigned short msg_qnum; /* number of messages in queue */ - unsigned short msg_qbytes; /* max number of bytes on queue */ - __kernel_ipc_pid_t msg_lspid; /* pid of last msgsnd */ - __kernel_ipc_pid_t msg_lrpid; /* last receive pid */ -}; - -/* Include the definition of msqid64_ds */ -#include - -/* message buffer for msgsnd and msgrcv calls */ -struct msgbuf { - __kernel_long_t mtype; /* type of message */ - char mtext[1]; /* message text */ -}; - -/* buffer for msgctl calls IPC_INFO, MSG_INFO */ -struct msginfo { - int msgpool; - int msgmap; - int msgmax; - int msgmnb; - int msgmni; - int msgssz; - int msgtql; - unsigned short msgseg; -}; - -/* - * MSGMNI, MSGMAX and MSGMNB are default values which can be - * modified by sysctl. - * - * MSGMNI is the upper limit for the number of messages queues per - * namespace. - * It has been chosen to be as large possible without facilitating - * scenarios where userspace causes overflows when adjusting the limits via - * operations of the form retrieve current limit; add X; update limit". - * - * MSGMNB is the default size of a new message queue. Non-root tasks can - * decrease the size with msgctl(IPC_SET), root tasks - * (actually: CAP_SYS_RESOURCE) can both increase and decrease the queue - * size. The optimal value is application dependent. - * 16384 is used because it was always used (since 0.99.10) - * - * MAXMAX is the maximum size of an individual message, it's a global - * (per-namespace) limit that applies for all message queues. - * It's set to 1/2 of MSGMNB, to ensure that at least two messages fit into - * the queue. This is also an arbitrary choice (since 2.6.0). - */ - -#define MSGMNI 32000 /* <= IPCMNI */ /* max # of msg queue identifiers */ -#define MSGMAX 8192 /* <= INT_MAX */ /* max size of message (bytes) */ -#define MSGMNB 16384 /* <= INT_MAX */ /* default max size of a message queue */ - -/* unused */ -#define MSGPOOL (MSGMNI * MSGMNB / 1024) /* size in kbytes of message pool */ -#define MSGTQL MSGMNB /* number of system message headers */ -#define MSGMAP MSGMNB /* number of entries in message map */ -#define MSGSSZ 16 /* message segment size */ -#define __MSGSEG ((MSGPOOL * 1024) / MSGSSZ) /* max no. of segments */ -#define MSGSEG (__MSGSEG <= 0xffff ? __MSGSEG : 0xffff) - - -#endif /* _UAPI_LINUX_MSG_H */ diff --git a/src/linux/include/uapi/linux/neighbour.h b/src/linux/include/uapi/linux/neighbour.h deleted file mode 100644 index bd99a8d..0000000 --- a/src/linux/include/uapi/linux/neighbour.h +++ /dev/null @@ -1,169 +0,0 @@ -#ifndef __LINUX_NEIGHBOUR_H -#define __LINUX_NEIGHBOUR_H - -#include -#include - -struct ndmsg { - __u8 ndm_family; - __u8 ndm_pad1; - __u16 ndm_pad2; - __s32 ndm_ifindex; - __u16 ndm_state; - __u8 ndm_flags; - __u8 ndm_type; -}; - -enum { - NDA_UNSPEC, - NDA_DST, - NDA_LLADDR, - NDA_CACHEINFO, - NDA_PROBES, - NDA_VLAN, - NDA_PORT, - NDA_VNI, - NDA_IFINDEX, - NDA_MASTER, - NDA_LINK_NETNSID, - __NDA_MAX -}; - -#define NDA_MAX (__NDA_MAX - 1) - -/* - * Neighbor Cache Entry Flags - */ - -#define NTF_USE 0x01 -#define NTF_SELF 0x02 -#define NTF_MASTER 0x04 -#define NTF_PROXY 0x08 /* == ATF_PUBL */ -#define NTF_EXT_LEARNED 0x10 -#define NTF_ROUTER 0x80 - -/* - * Neighbor Cache Entry States. - */ - -#define NUD_INCOMPLETE 0x01 -#define NUD_REACHABLE 0x02 -#define NUD_STALE 0x04 -#define NUD_DELAY 0x08 -#define NUD_PROBE 0x10 -#define NUD_FAILED 0x20 - -/* Dummy states */ -#define NUD_NOARP 0x40 -#define NUD_PERMANENT 0x80 -#define NUD_NONE 0x00 - -/* NUD_NOARP & NUD_PERMANENT are pseudostates, they never change - and make no address resolution or NUD. - NUD_PERMANENT also cannot be deleted by garbage collectors. - */ - -struct nda_cacheinfo { - __u32 ndm_confirmed; - __u32 ndm_used; - __u32 ndm_updated; - __u32 ndm_refcnt; -}; - -/***************************************************************** - * Neighbour tables specific messages. - * - * To retrieve the neighbour tables send RTM_GETNEIGHTBL with the - * NLM_F_DUMP flag set. Every neighbour table configuration is - * spread over multiple messages to avoid running into message - * size limits on systems with many interfaces. The first message - * in the sequence transports all not device specific data such as - * statistics, configuration, and the default parameter set. - * This message is followed by 0..n messages carrying device - * specific parameter sets. - * Although the ordering should be sufficient, NDTA_NAME can be - * used to identify sequences. The initial message can be identified - * by checking for NDTA_CONFIG. The device specific messages do - * not contain this TLV but have NDTPA_IFINDEX set to the - * corresponding interface index. - * - * To change neighbour table attributes, send RTM_SETNEIGHTBL - * with NDTA_NAME set. Changeable attribute include NDTA_THRESH[1-3], - * NDTA_GC_INTERVAL, and all TLVs in NDTA_PARMS unless marked - * otherwise. Device specific parameter sets can be changed by - * setting NDTPA_IFINDEX to the interface index of the corresponding - * device. - ****/ - -struct ndt_stats { - __u64 ndts_allocs; - __u64 ndts_destroys; - __u64 ndts_hash_grows; - __u64 ndts_res_failed; - __u64 ndts_lookups; - __u64 ndts_hits; - __u64 ndts_rcv_probes_mcast; - __u64 ndts_rcv_probes_ucast; - __u64 ndts_periodic_gc_runs; - __u64 ndts_forced_gc_runs; - __u64 ndts_table_fulls; -}; - -enum { - NDTPA_UNSPEC, - NDTPA_IFINDEX, /* u32, unchangeable */ - NDTPA_REFCNT, /* u32, read-only */ - NDTPA_REACHABLE_TIME, /* u64, read-only, msecs */ - NDTPA_BASE_REACHABLE_TIME, /* u64, msecs */ - NDTPA_RETRANS_TIME, /* u64, msecs */ - NDTPA_GC_STALETIME, /* u64, msecs */ - NDTPA_DELAY_PROBE_TIME, /* u64, msecs */ - NDTPA_QUEUE_LEN, /* u32 */ - NDTPA_APP_PROBES, /* u32 */ - NDTPA_UCAST_PROBES, /* u32 */ - NDTPA_MCAST_PROBES, /* u32 */ - NDTPA_ANYCAST_DELAY, /* u64, msecs */ - NDTPA_PROXY_DELAY, /* u64, msecs */ - NDTPA_PROXY_QLEN, /* u32 */ - NDTPA_LOCKTIME, /* u64, msecs */ - NDTPA_QUEUE_LENBYTES, /* u32 */ - NDTPA_MCAST_REPROBES, /* u32 */ - NDTPA_PAD, - __NDTPA_MAX -}; -#define NDTPA_MAX (__NDTPA_MAX - 1) - -struct ndtmsg { - __u8 ndtm_family; - __u8 ndtm_pad1; - __u16 ndtm_pad2; -}; - -struct ndt_config { - __u16 ndtc_key_len; - __u16 ndtc_entry_size; - __u32 ndtc_entries; - __u32 ndtc_last_flush; /* delta to now in msecs */ - __u32 ndtc_last_rand; /* delta to now in msecs */ - __u32 ndtc_hash_rnd; - __u32 ndtc_hash_mask; - __u32 ndtc_hash_chain_gc; - __u32 ndtc_proxy_qlen; -}; - -enum { - NDTA_UNSPEC, - NDTA_NAME, /* char *, unchangeable */ - NDTA_THRESH1, /* u32 */ - NDTA_THRESH2, /* u32 */ - NDTA_THRESH3, /* u32 */ - NDTA_CONFIG, /* struct ndt_config, read-only */ - NDTA_PARMS, /* nested TLV NDTPA_* */ - NDTA_STATS, /* struct ndt_stats, read-only */ - NDTA_GC_INTERVAL, /* u64, msecs */ - NDTA_PAD, - __NDTA_MAX -}; -#define NDTA_MAX (__NDTA_MAX - 1) - -#endif diff --git a/src/linux/include/uapi/linux/net.h b/src/linux/include/uapi/linux/net.h deleted file mode 100644 index 9457239..0000000 --- a/src/linux/include/uapi/linux/net.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * NET An implementation of the SOCKET network access protocol. - * This is the master header file for the Linux NET layer, - * or, in plain English: the networking handling part of the - * kernel. - * - * Version: @(#)net.h 1.0.3 05/25/93 - * - * Authors: Orest Zborowski, - * Ross Biro - * Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _UAPI_LINUX_NET_H -#define _UAPI_LINUX_NET_H - -#include -#include - -#define NPROTO AF_MAX - -#define SYS_SOCKET 1 /* sys_socket(2) */ -#define SYS_BIND 2 /* sys_bind(2) */ -#define SYS_CONNECT 3 /* sys_connect(2) */ -#define SYS_LISTEN 4 /* sys_listen(2) */ -#define SYS_ACCEPT 5 /* sys_accept(2) */ -#define SYS_GETSOCKNAME 6 /* sys_getsockname(2) */ -#define SYS_GETPEERNAME 7 /* sys_getpeername(2) */ -#define SYS_SOCKETPAIR 8 /* sys_socketpair(2) */ -#define SYS_SEND 9 /* sys_send(2) */ -#define SYS_RECV 10 /* sys_recv(2) */ -#define SYS_SENDTO 11 /* sys_sendto(2) */ -#define SYS_RECVFROM 12 /* sys_recvfrom(2) */ -#define SYS_SHUTDOWN 13 /* sys_shutdown(2) */ -#define SYS_SETSOCKOPT 14 /* sys_setsockopt(2) */ -#define SYS_GETSOCKOPT 15 /* sys_getsockopt(2) */ -#define SYS_SENDMSG 16 /* sys_sendmsg(2) */ -#define SYS_RECVMSG 17 /* sys_recvmsg(2) */ -#define SYS_ACCEPT4 18 /* sys_accept4(2) */ -#define SYS_RECVMMSG 19 /* sys_recvmmsg(2) */ -#define SYS_SENDMMSG 20 /* sys_sendmmsg(2) */ - -typedef enum { - SS_FREE = 0, /* not allocated */ - SS_UNCONNECTED, /* unconnected to any socket */ - SS_CONNECTING, /* in process of connecting */ - SS_CONNECTED, /* connected to socket */ - SS_DISCONNECTING /* in process of disconnecting */ -} socket_state; - -#define __SO_ACCEPTCON (1 << 16) /* performed a listen */ - -#endif /* _UAPI_LINUX_NET_H */ diff --git a/src/linux/include/uapi/linux/net_namespace.h b/src/linux/include/uapi/linux/net_namespace.h deleted file mode 100644 index 778cd2c..0000000 --- a/src/linux/include/uapi/linux/net_namespace.h +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright (c) 2015 6WIND S.A. - * Author: Nicolas Dichtel - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - */ -#ifndef _UAPI_LINUX_NET_NAMESPACE_H_ -#define _UAPI_LINUX_NET_NAMESPACE_H_ - -/* Attributes of RTM_NEWNSID/RTM_GETNSID messages */ -enum { - NETNSA_NONE, -#define NETNSA_NSID_NOT_ASSIGNED -1 - NETNSA_NSID, - NETNSA_PID, - NETNSA_FD, - __NETNSA_MAX, -}; - -#define NETNSA_MAX (__NETNSA_MAX - 1) - -#endif /* _UAPI_LINUX_NET_NAMESPACE_H_ */ diff --git a/src/linux/include/uapi/linux/net_tstamp.h b/src/linux/include/uapi/linux/net_tstamp.h deleted file mode 100644 index 264e515..0000000 --- a/src/linux/include/uapi/linux/net_tstamp.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Userspace API for hardware time stamping of network packets - * - * Copyright (C) 2008,2009 Intel Corporation - * Author: Patrick Ohly - * - */ - -#ifndef _NET_TIMESTAMPING_H -#define _NET_TIMESTAMPING_H - -#include /* for SO_TIMESTAMPING */ - -/* SO_TIMESTAMPING gets an integer bit field comprised of these values */ -enum { - SOF_TIMESTAMPING_TX_HARDWARE = (1<<0), - SOF_TIMESTAMPING_TX_SOFTWARE = (1<<1), - SOF_TIMESTAMPING_RX_HARDWARE = (1<<2), - SOF_TIMESTAMPING_RX_SOFTWARE = (1<<3), - SOF_TIMESTAMPING_SOFTWARE = (1<<4), - SOF_TIMESTAMPING_SYS_HARDWARE = (1<<5), - SOF_TIMESTAMPING_RAW_HARDWARE = (1<<6), - SOF_TIMESTAMPING_OPT_ID = (1<<7), - SOF_TIMESTAMPING_TX_SCHED = (1<<8), - SOF_TIMESTAMPING_TX_ACK = (1<<9), - SOF_TIMESTAMPING_OPT_CMSG = (1<<10), - SOF_TIMESTAMPING_OPT_TSONLY = (1<<11), - - SOF_TIMESTAMPING_LAST = SOF_TIMESTAMPING_OPT_TSONLY, - SOF_TIMESTAMPING_MASK = (SOF_TIMESTAMPING_LAST - 1) | - SOF_TIMESTAMPING_LAST -}; - -/* - * SO_TIMESTAMPING flags are either for recording a packet timestamp or for - * reporting the timestamp to user space. - * Recording flags can be set both via socket options and control messages. - */ -#define SOF_TIMESTAMPING_TX_RECORD_MASK (SOF_TIMESTAMPING_TX_HARDWARE | \ - SOF_TIMESTAMPING_TX_SOFTWARE | \ - SOF_TIMESTAMPING_TX_SCHED | \ - SOF_TIMESTAMPING_TX_ACK) - -/** - * struct hwtstamp_config - %SIOCGHWTSTAMP and %SIOCSHWTSTAMP parameter - * - * @flags: no flags defined right now, must be zero for %SIOCSHWTSTAMP - * @tx_type: one of HWTSTAMP_TX_* - * @rx_filter: one of HWTSTAMP_FILTER_* - * - * %SIOCGHWTSTAMP and %SIOCSHWTSTAMP expect a &struct ifreq with a - * ifr_data pointer to this structure. For %SIOCSHWTSTAMP, if the - * driver or hardware does not support the requested @rx_filter value, - * the driver may use a more general filter mode. In this case - * @rx_filter will indicate the actual mode on return. - */ -struct hwtstamp_config { - int flags; - int tx_type; - int rx_filter; -}; - -/* possible values for hwtstamp_config->tx_type */ -enum hwtstamp_tx_types { - /* - * No outgoing packet will need hardware time stamping; - * should a packet arrive which asks for it, no hardware - * time stamping will be done. - */ - HWTSTAMP_TX_OFF, - - /* - * Enables hardware time stamping for outgoing packets; - * the sender of the packet decides which are to be - * time stamped by setting %SOF_TIMESTAMPING_TX_SOFTWARE - * before sending the packet. - */ - HWTSTAMP_TX_ON, - - /* - * Enables time stamping for outgoing packets just as - * HWTSTAMP_TX_ON does, but also enables time stamp insertion - * directly into Sync packets. In this case, transmitted Sync - * packets will not received a time stamp via the socket error - * queue. - */ - HWTSTAMP_TX_ONESTEP_SYNC, -}; - -/* possible values for hwtstamp_config->rx_filter */ -enum hwtstamp_rx_filters { - /* time stamp no incoming packet at all */ - HWTSTAMP_FILTER_NONE, - - /* time stamp any incoming packet */ - HWTSTAMP_FILTER_ALL, - - /* return value: time stamp all packets requested plus some others */ - HWTSTAMP_FILTER_SOME, - - /* PTP v1, UDP, any kind of event packet */ - HWTSTAMP_FILTER_PTP_V1_L4_EVENT, - /* PTP v1, UDP, Sync packet */ - HWTSTAMP_FILTER_PTP_V1_L4_SYNC, - /* PTP v1, UDP, Delay_req packet */ - HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ, - /* PTP v2, UDP, any kind of event packet */ - HWTSTAMP_FILTER_PTP_V2_L4_EVENT, - /* PTP v2, UDP, Sync packet */ - HWTSTAMP_FILTER_PTP_V2_L4_SYNC, - /* PTP v2, UDP, Delay_req packet */ - HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ, - - /* 802.AS1, Ethernet, any kind of event packet */ - HWTSTAMP_FILTER_PTP_V2_L2_EVENT, - /* 802.AS1, Ethernet, Sync packet */ - HWTSTAMP_FILTER_PTP_V2_L2_SYNC, - /* 802.AS1, Ethernet, Delay_req packet */ - HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ, - - /* PTP v2/802.AS1, any layer, any kind of event packet */ - HWTSTAMP_FILTER_PTP_V2_EVENT, - /* PTP v2/802.AS1, any layer, Sync packet */ - HWTSTAMP_FILTER_PTP_V2_SYNC, - /* PTP v2/802.AS1, any layer, Delay_req packet */ - HWTSTAMP_FILTER_PTP_V2_DELAY_REQ, -}; - -#endif /* _NET_TIMESTAMPING_H */ diff --git a/src/linux/include/uapi/linux/netconf.h b/src/linux/include/uapi/linux/netconf.h deleted file mode 100644 index 45dfad5..0000000 --- a/src/linux/include/uapi/linux/netconf.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef _UAPI_LINUX_NETCONF_H_ -#define _UAPI_LINUX_NETCONF_H_ - -#include -#include - -struct netconfmsg { - __u8 ncm_family; -}; - -enum { - NETCONFA_UNSPEC, - NETCONFA_IFINDEX, - NETCONFA_FORWARDING, - NETCONFA_RP_FILTER, - NETCONFA_MC_FORWARDING, - NETCONFA_PROXY_NEIGH, - NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, - __NETCONFA_MAX -}; -#define NETCONFA_MAX (__NETCONFA_MAX - 1) -#define NETCONFA_ALL -1 - -#define NETCONFA_IFINDEX_ALL -1 -#define NETCONFA_IFINDEX_DEFAULT -2 - -#endif /* _UAPI_LINUX_NETCONF_H_ */ diff --git a/src/linux/include/uapi/linux/netdevice.h b/src/linux/include/uapi/linux/netdevice.h deleted file mode 100644 index 5581854..0000000 --- a/src/linux/include/uapi/linux/netdevice.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the Interfaces handler. - * - * Version: @(#)dev.h 1.0.10 08/12/93 - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Corey Minyard - * Donald J. Becker, - * Alan Cox, - * Bjorn Ekwall. - * Pekka Riikonen - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Moved to /usr/include/linux for NET3 - */ -#ifndef _UAPI_LINUX_NETDEVICE_H -#define _UAPI_LINUX_NETDEVICE_H - -#include -#include -#include -#include - - -#define MAX_ADDR_LEN 32 /* Largest hardware address length */ - -/* Initial net device group. All devices belong to group 0 by default. */ -#define INIT_NETDEV_GROUP 0 - - -/* interface name assignment types (sysfs name_assign_type attribute) */ -#define NET_NAME_UNKNOWN 0 /* unknown origin (not exposed to userspace) */ -#define NET_NAME_ENUM 1 /* enumerated by kernel */ -#define NET_NAME_PREDICTABLE 2 /* predictably named by the kernel */ -#define NET_NAME_USER 3 /* provided by user-space */ -#define NET_NAME_RENAMED 4 /* renamed by user-space */ - -/* Media selection options. */ -enum { - IF_PORT_UNKNOWN = 0, - IF_PORT_10BASE2, - IF_PORT_10BASET, - IF_PORT_AUI, - IF_PORT_100BASET, - IF_PORT_100BASETX, - IF_PORT_100BASEFX -}; - -/* hardware address assignment types */ -#define NET_ADDR_PERM 0 /* address is permanent (default) */ -#define NET_ADDR_RANDOM 1 /* address is generated randomly */ -#define NET_ADDR_STOLEN 2 /* address is stolen from other device */ -#define NET_ADDR_SET 3 /* address is set using - * dev_set_mac_address() */ - -#endif /* _UAPI_LINUX_NETDEVICE_H */ diff --git a/src/linux/include/uapi/linux/netfilter.h b/src/linux/include/uapi/linux/netfilter.h deleted file mode 100644 index d93f949..0000000 --- a/src/linux/include/uapi/linux/netfilter.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef _UAPI__LINUX_NETFILTER_H -#define _UAPI__LINUX_NETFILTER_H - -#include -#include -#include -#include -#include - -/* Responses from hook functions. */ -#define NF_DROP 0 -#define NF_ACCEPT 1 -#define NF_STOLEN 2 -#define NF_QUEUE 3 -#define NF_REPEAT 4 -#define NF_STOP 5 -#define NF_MAX_VERDICT NF_STOP - -/* we overload the higher bits for encoding auxiliary data such as the queue - * number or errno values. Not nice, but better than additional function - * arguments. */ -#define NF_VERDICT_MASK 0x000000ff - -/* extra verdict flags have mask 0x0000ff00 */ -#define NF_VERDICT_FLAG_QUEUE_BYPASS 0x00008000 - -/* queue number (NF_QUEUE) or errno (NF_DROP) */ -#define NF_VERDICT_QMASK 0xffff0000 -#define NF_VERDICT_QBITS 16 - -#define NF_QUEUE_NR(x) ((((x) << 16) & NF_VERDICT_QMASK) | NF_QUEUE) - -#define NF_DROP_ERR(x) (((-x) << 16) | NF_DROP) - -/* only for userspace compatibility */ -#ifndef __KERNEL__ -/* Generic cache responses from hook functions. - <= 0x2000 is used for protocol-flags. */ -#define NFC_UNKNOWN 0x4000 -#define NFC_ALTERED 0x8000 - -/* NF_VERDICT_BITS should be 8 now, but userspace might break if this changes */ -#define NF_VERDICT_BITS 16 -#endif - -enum nf_inet_hooks { - NF_INET_PRE_ROUTING, - NF_INET_LOCAL_IN, - NF_INET_FORWARD, - NF_INET_LOCAL_OUT, - NF_INET_POST_ROUTING, - NF_INET_NUMHOOKS -}; - -enum nf_dev_hooks { - NF_NETDEV_INGRESS, - NF_NETDEV_NUMHOOKS -}; - -enum { - NFPROTO_UNSPEC = 0, - NFPROTO_INET = 1, - NFPROTO_IPV4 = 2, - NFPROTO_ARP = 3, - NFPROTO_NETDEV = 5, - NFPROTO_BRIDGE = 7, - NFPROTO_IPV6 = 10, - NFPROTO_DECNET = 12, - NFPROTO_NUMPROTO, -}; - -union nf_inet_addr { - __u32 all[4]; - __be32 ip; - __be32 ip6[4]; - struct in_addr in; - struct in6_addr in6; -}; - -#endif /* _UAPI__LINUX_NETFILTER_H */ diff --git a/src/linux/include/uapi/linux/netfilter_arp.h b/src/linux/include/uapi/linux/netfilter_arp.h deleted file mode 100644 index 92bc6dd..0000000 --- a/src/linux/include/uapi/linux/netfilter_arp.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef __LINUX_ARP_NETFILTER_H -#define __LINUX_ARP_NETFILTER_H - -/* ARP-specific defines for netfilter. - * (C)2002 Rusty Russell IBM -- This code is GPL. - */ - -#include - -/* There is no PF_ARP. */ -#define NF_ARP 0 - -/* ARP Hooks */ -#define NF_ARP_IN 0 -#define NF_ARP_OUT 1 -#define NF_ARP_FORWARD 2 -#define NF_ARP_NUMHOOKS 3 - -#endif /* __LINUX_ARP_NETFILTER_H */ diff --git a/src/linux/include/uapi/linux/netfilter_bridge.h b/src/linux/include/uapi/linux/netfilter_bridge.h deleted file mode 100644 index 514519b..0000000 --- a/src/linux/include/uapi/linux/netfilter_bridge.h +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef _UAPI__LINUX_BRIDGE_NETFILTER_H -#define _UAPI__LINUX_BRIDGE_NETFILTER_H - -/* bridge-specific defines for netfilter. - */ - -#include -#include -#include -#include -#include - -/* Bridge Hooks */ -/* After promisc drops, checksum checks. */ -#define NF_BR_PRE_ROUTING 0 -/* If the packet is destined for this box. */ -#define NF_BR_LOCAL_IN 1 -/* If the packet is destined for another interface. */ -#define NF_BR_FORWARD 2 -/* Packets coming from a local process. */ -#define NF_BR_LOCAL_OUT 3 -/* Packets about to hit the wire. */ -#define NF_BR_POST_ROUTING 4 -/* Not really a hook, but used for the ebtables broute table */ -#define NF_BR_BROUTING 5 -#define NF_BR_NUMHOOKS 6 - -#endif /* _UAPI__LINUX_BRIDGE_NETFILTER_H */ diff --git a/src/linux/include/uapi/linux/netfilter_ipv4.h b/src/linux/include/uapi/linux/netfilter_ipv4.h deleted file mode 100644 index 91ddd1f..0000000 --- a/src/linux/include/uapi/linux/netfilter_ipv4.h +++ /dev/null @@ -1,81 +0,0 @@ -/* IPv4-specific defines for netfilter. - * (C)1998 Rusty Russell -- This code is GPL. - */ -#ifndef _UAPI__LINUX_IP_NETFILTER_H -#define _UAPI__LINUX_IP_NETFILTER_H - - -#include - -/* only for userspace compatibility */ -#ifndef __KERNEL__ - -#include /* for INT_MIN, INT_MAX */ - -/* IP Cache bits. */ -/* Src IP address. */ -#define NFC_IP_SRC 0x0001 -/* Dest IP address. */ -#define NFC_IP_DST 0x0002 -/* Input device. */ -#define NFC_IP_IF_IN 0x0004 -/* Output device. */ -#define NFC_IP_IF_OUT 0x0008 -/* TOS. */ -#define NFC_IP_TOS 0x0010 -/* Protocol. */ -#define NFC_IP_PROTO 0x0020 -/* IP options. */ -#define NFC_IP_OPTIONS 0x0040 -/* Frag & flags. */ -#define NFC_IP_FRAG 0x0080 - -/* Per-protocol information: only matters if proto match. */ -/* TCP flags. */ -#define NFC_IP_TCPFLAGS 0x0100 -/* Source port. */ -#define NFC_IP_SRC_PT 0x0200 -/* Dest port. */ -#define NFC_IP_DST_PT 0x0400 -/* Something else about the proto */ -#define NFC_IP_PROTO_UNKNOWN 0x2000 - -/* IP Hooks */ -/* After promisc drops, checksum checks. */ -#define NF_IP_PRE_ROUTING 0 -/* If the packet is destined for this box. */ -#define NF_IP_LOCAL_IN 1 -/* If the packet is destined for another interface. */ -#define NF_IP_FORWARD 2 -/* Packets coming from a local process. */ -#define NF_IP_LOCAL_OUT 3 -/* Packets about to hit the wire. */ -#define NF_IP_POST_ROUTING 4 -#define NF_IP_NUMHOOKS 5 -#endif /* ! __KERNEL__ */ - -enum nf_ip_hook_priorities { - NF_IP_PRI_FIRST = INT_MIN, - NF_IP_PRI_CONNTRACK_DEFRAG = -400, - NF_IP_PRI_RAW = -300, - NF_IP_PRI_SELINUX_FIRST = -225, - NF_IP_PRI_CONNTRACK = -200, - NF_IP_PRI_MANGLE = -150, - NF_IP_PRI_NAT_DST = -100, - NF_IP_PRI_FILTER = 0, - NF_IP_PRI_SECURITY = 50, - NF_IP_PRI_NAT_SRC = 100, - NF_IP_PRI_SELINUX_LAST = 225, - NF_IP_PRI_CONNTRACK_HELPER = 300, - NF_IP_PRI_CONNTRACK_CONFIRM = INT_MAX, - NF_IP_PRI_LAST = INT_MAX, -}; - -/* Arguments for setsockopt SOL_IP: */ -/* 2.0 firewalling went from 64 through 71 (and +256, +512, etc). */ -/* 2.2 firewalling (+ masq) went from 64 through 76 */ -/* 2.4 firewalling went 64 through 67. */ -#define SO_ORIGINAL_DST 80 - - -#endif /* _UAPI__LINUX_IP_NETFILTER_H */ diff --git a/src/linux/include/uapi/linux/netfilter_ipv6.h b/src/linux/include/uapi/linux/netfilter_ipv6.h deleted file mode 100644 index 12497c6..0000000 --- a/src/linux/include/uapi/linux/netfilter_ipv6.h +++ /dev/null @@ -1,79 +0,0 @@ -/* IPv6-specific defines for netfilter. - * (C)1998 Rusty Russell -- This code is GPL. - * (C)1999 David Jeffery - * this header was blatantly ripped from netfilter_ipv4.h - * it's amazing what adding a bunch of 6s can do =8^) - */ -#ifndef _UAPI__LINUX_IP6_NETFILTER_H -#define _UAPI__LINUX_IP6_NETFILTER_H - - -#include - -/* only for userspace compatibility */ -#ifndef __KERNEL__ - -#include /* for INT_MIN, INT_MAX */ - -/* IP Cache bits. */ -/* Src IP address. */ -#define NFC_IP6_SRC 0x0001 -/* Dest IP address. */ -#define NFC_IP6_DST 0x0002 -/* Input device. */ -#define NFC_IP6_IF_IN 0x0004 -/* Output device. */ -#define NFC_IP6_IF_OUT 0x0008 -/* TOS. */ -#define NFC_IP6_TOS 0x0010 -/* Protocol. */ -#define NFC_IP6_PROTO 0x0020 -/* IP options. */ -#define NFC_IP6_OPTIONS 0x0040 -/* Frag & flags. */ -#define NFC_IP6_FRAG 0x0080 - - -/* Per-protocol information: only matters if proto match. */ -/* TCP flags. */ -#define NFC_IP6_TCPFLAGS 0x0100 -/* Source port. */ -#define NFC_IP6_SRC_PT 0x0200 -/* Dest port. */ -#define NFC_IP6_DST_PT 0x0400 -/* Something else about the proto */ -#define NFC_IP6_PROTO_UNKNOWN 0x2000 - -/* IP6 Hooks */ -/* After promisc drops, checksum checks. */ -#define NF_IP6_PRE_ROUTING 0 -/* If the packet is destined for this box. */ -#define NF_IP6_LOCAL_IN 1 -/* If the packet is destined for another interface. */ -#define NF_IP6_FORWARD 2 -/* Packets coming from a local process. */ -#define NF_IP6_LOCAL_OUT 3 -/* Packets about to hit the wire. */ -#define NF_IP6_POST_ROUTING 4 -#define NF_IP6_NUMHOOKS 5 -#endif /* ! __KERNEL__ */ - - -enum nf_ip6_hook_priorities { - NF_IP6_PRI_FIRST = INT_MIN, - NF_IP6_PRI_CONNTRACK_DEFRAG = -400, - NF_IP6_PRI_RAW = -300, - NF_IP6_PRI_SELINUX_FIRST = -225, - NF_IP6_PRI_CONNTRACK = -200, - NF_IP6_PRI_MANGLE = -150, - NF_IP6_PRI_NAT_DST = -100, - NF_IP6_PRI_FILTER = 0, - NF_IP6_PRI_SECURITY = 50, - NF_IP6_PRI_NAT_SRC = 100, - NF_IP6_PRI_SELINUX_LAST = 225, - NF_IP6_PRI_CONNTRACK_HELPER = 300, - NF_IP6_PRI_LAST = INT_MAX, -}; - - -#endif /* _UAPI__LINUX_IP6_NETFILTER_H */ diff --git a/src/linux/include/uapi/linux/netlink.h b/src/linux/include/uapi/linux/netlink.h deleted file mode 100644 index 0dba4e4..0000000 --- a/src/linux/include/uapi/linux/netlink.h +++ /dev/null @@ -1,193 +0,0 @@ -#ifndef _UAPI__LINUX_NETLINK_H -#define _UAPI__LINUX_NETLINK_H - -#include -#include /* for __kernel_sa_family_t */ -#include - -#define NETLINK_ROUTE 0 /* Routing/device hook */ -#define NETLINK_UNUSED 1 /* Unused number */ -#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */ -#define NETLINK_FIREWALL 3 /* Unused number, formerly ip_queue */ -#define NETLINK_SOCK_DIAG 4 /* socket monitoring */ -#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */ -#define NETLINK_XFRM 6 /* ipsec */ -#define NETLINK_SELINUX 7 /* SELinux event notifications */ -#define NETLINK_ISCSI 8 /* Open-iSCSI */ -#define NETLINK_AUDIT 9 /* auditing */ -#define NETLINK_FIB_LOOKUP 10 -#define NETLINK_CONNECTOR 11 -#define NETLINK_NETFILTER 12 /* netfilter subsystem */ -#define NETLINK_IP6_FW 13 -#define NETLINK_DNRTMSG 14 /* DECnet routing messages */ -#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */ -#define NETLINK_GENERIC 16 -/* leave room for NETLINK_DM (DM Events) */ -#define NETLINK_SCSITRANSPORT 18 /* SCSI Transports */ -#define NETLINK_ECRYPTFS 19 -#define NETLINK_RDMA 20 -#define NETLINK_CRYPTO 21 /* Crypto layer */ - -#define NETLINK_INET_DIAG NETLINK_SOCK_DIAG - -#define MAX_LINKS 32 - -struct sockaddr_nl { - __kernel_sa_family_t nl_family; /* AF_NETLINK */ - unsigned short nl_pad; /* zero */ - __u32 nl_pid; /* port ID */ - __u32 nl_groups; /* multicast groups mask */ -}; - -struct nlmsghdr { - __u32 nlmsg_len; /* Length of message including header */ - __u16 nlmsg_type; /* Message content */ - __u16 nlmsg_flags; /* Additional flags */ - __u32 nlmsg_seq; /* Sequence number */ - __u32 nlmsg_pid; /* Sending process port ID */ -}; - -/* Flags values */ - -#define NLM_F_REQUEST 1 /* It is request message. */ -#define NLM_F_MULTI 2 /* Multipart message, terminated by NLMSG_DONE */ -#define NLM_F_ACK 4 /* Reply with ack, with zero or error code */ -#define NLM_F_ECHO 8 /* Echo this request */ -#define NLM_F_DUMP_INTR 16 /* Dump was inconsistent due to sequence change */ -#define NLM_F_DUMP_FILTERED 32 /* Dump was filtered as requested */ - -/* Modifiers to GET request */ -#define NLM_F_ROOT 0x100 /* specify tree root */ -#define NLM_F_MATCH 0x200 /* return all matching */ -#define NLM_F_ATOMIC 0x400 /* atomic GET */ -#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH) - -/* Modifiers to NEW request */ -#define NLM_F_REPLACE 0x100 /* Override existing */ -#define NLM_F_EXCL 0x200 /* Do not touch, if it exists */ -#define NLM_F_CREATE 0x400 /* Create, if it does not exist */ -#define NLM_F_APPEND 0x800 /* Add to end of list */ - -/* - 4.4BSD ADD NLM_F_CREATE|NLM_F_EXCL - 4.4BSD CHANGE NLM_F_REPLACE - - True CHANGE NLM_F_CREATE|NLM_F_REPLACE - Append NLM_F_CREATE - Check NLM_F_EXCL - */ - -#define NLMSG_ALIGNTO 4U -#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) ) -#define NLMSG_HDRLEN ((int) NLMSG_ALIGN(sizeof(struct nlmsghdr))) -#define NLMSG_LENGTH(len) ((len) + NLMSG_HDRLEN) -#define NLMSG_SPACE(len) NLMSG_ALIGN(NLMSG_LENGTH(len)) -#define NLMSG_DATA(nlh) ((void*)(((char*)nlh) + NLMSG_LENGTH(0))) -#define NLMSG_NEXT(nlh,len) ((len) -= NLMSG_ALIGN((nlh)->nlmsg_len), \ - (struct nlmsghdr*)(((char*)(nlh)) + NLMSG_ALIGN((nlh)->nlmsg_len))) -#define NLMSG_OK(nlh,len) ((len) >= (int)sizeof(struct nlmsghdr) && \ - (nlh)->nlmsg_len >= sizeof(struct nlmsghdr) && \ - (nlh)->nlmsg_len <= (len)) -#define NLMSG_PAYLOAD(nlh,len) ((nlh)->nlmsg_len - NLMSG_SPACE((len))) - -#define NLMSG_NOOP 0x1 /* Nothing. */ -#define NLMSG_ERROR 0x2 /* Error */ -#define NLMSG_DONE 0x3 /* End of a dump */ -#define NLMSG_OVERRUN 0x4 /* Data lost */ - -#define NLMSG_MIN_TYPE 0x10 /* < 0x10: reserved control messages */ - -struct nlmsgerr { - int error; - struct nlmsghdr msg; -}; - -#define NETLINK_ADD_MEMBERSHIP 1 -#define NETLINK_DROP_MEMBERSHIP 2 -#define NETLINK_PKTINFO 3 -#define NETLINK_BROADCAST_ERROR 4 -#define NETLINK_NO_ENOBUFS 5 -#ifndef __KERNEL__ -#define NETLINK_RX_RING 6 -#define NETLINK_TX_RING 7 -#endif -#define NETLINK_LISTEN_ALL_NSID 8 -#define NETLINK_LIST_MEMBERSHIPS 9 -#define NETLINK_CAP_ACK 10 - -struct nl_pktinfo { - __u32 group; -}; - -struct nl_mmap_req { - unsigned int nm_block_size; - unsigned int nm_block_nr; - unsigned int nm_frame_size; - unsigned int nm_frame_nr; -}; - -struct nl_mmap_hdr { - unsigned int nm_status; - unsigned int nm_len; - __u32 nm_group; - /* credentials */ - __u32 nm_pid; - __u32 nm_uid; - __u32 nm_gid; -}; - -#ifndef __KERNEL__ -enum nl_mmap_status { - NL_MMAP_STATUS_UNUSED, - NL_MMAP_STATUS_RESERVED, - NL_MMAP_STATUS_VALID, - NL_MMAP_STATUS_COPY, - NL_MMAP_STATUS_SKIP, -}; - -#define NL_MMAP_MSG_ALIGNMENT NLMSG_ALIGNTO -#define NL_MMAP_MSG_ALIGN(sz) __ALIGN_KERNEL(sz, NL_MMAP_MSG_ALIGNMENT) -#define NL_MMAP_HDRLEN NL_MMAP_MSG_ALIGN(sizeof(struct nl_mmap_hdr)) -#endif - -#define NET_MAJOR 36 /* Major 36 is reserved for networking */ - -enum { - NETLINK_UNCONNECTED = 0, - NETLINK_CONNECTED, -}; - -/* - * <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)--> - * +---------------------+- - -+- - - - - - - - - -+- - -+ - * | Header | Pad | Payload | Pad | - * | (struct nlattr) | ing | | ing | - * +---------------------+- - -+- - - - - - - - - -+- - -+ - * <-------------- nlattr->nla_len --------------> - */ - -struct nlattr { - __u16 nla_len; - __u16 nla_type; -}; - -/* - * nla_type (16 bits) - * +---+---+-------------------------------+ - * | N | O | Attribute Type | - * +---+---+-------------------------------+ - * N := Carries nested attributes - * O := Payload stored in network byte order - * - * Note: The N and O flag are mutually exclusive. - */ -#define NLA_F_NESTED (1 << 15) -#define NLA_F_NET_BYTEORDER (1 << 14) -#define NLA_TYPE_MASK ~(NLA_F_NESTED | NLA_F_NET_BYTEORDER) - -#define NLA_ALIGNTO 4 -#define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1)) -#define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr))) - - -#endif /* _UAPI__LINUX_NETLINK_H */ diff --git a/src/linux/include/uapi/linux/netrom.h b/src/linux/include/uapi/linux/netrom.h deleted file mode 100644 index af7313c..0000000 --- a/src/linux/include/uapi/linux/netrom.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * These are the public elements of the Linux kernel NET/ROM implementation. - * For kernel AX.25 see the file ax25.h. This file requires ax25.h for the - * definition of the ax25_address structure. - */ - -#ifndef NETROM_KERNEL_H -#define NETROM_KERNEL_H - -#include - -#define NETROM_MTU 236 - -#define NETROM_T1 1 -#define NETROM_T2 2 -#define NETROM_N2 3 -#define NETROM_T4 6 -#define NETROM_IDLE 7 - -#define SIOCNRDECOBS (SIOCPROTOPRIVATE+2) - -struct nr_route_struct { -#define NETROM_NEIGH 0 -#define NETROM_NODE 1 - int type; - ax25_address callsign; - char device[16]; - unsigned int quality; - char mnemonic[7]; - ax25_address neighbour; - unsigned int obs_count; - unsigned int ndigis; - ax25_address digipeaters[AX25_MAX_DIGIS]; -}; - -#endif diff --git a/src/linux/include/uapi/linux/nfs.h b/src/linux/include/uapi/linux/nfs.h deleted file mode 100644 index 5e62961..0000000 --- a/src/linux/include/uapi/linux/nfs.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * NFS protocol definitions - * - * This file contains constants mostly for Version 2 of the protocol, - * but also has a couple of NFSv3 bits in (notably the error codes). - */ -#ifndef _UAPI_LINUX_NFS_H -#define _UAPI_LINUX_NFS_H - -#include - -#define NFS_PROGRAM 100003 -#define NFS_PORT 2049 -#define NFS_MAXDATA 8192 -#define NFS_MAXPATHLEN 1024 -#define NFS_MAXNAMLEN 255 -#define NFS_MAXGROUPS 16 -#define NFS_FHSIZE 32 -#define NFS_COOKIESIZE 4 -#define NFS_FIFO_DEV (-1) -#define NFSMODE_FMT 0170000 -#define NFSMODE_DIR 0040000 -#define NFSMODE_CHR 0020000 -#define NFSMODE_BLK 0060000 -#define NFSMODE_REG 0100000 -#define NFSMODE_LNK 0120000 -#define NFSMODE_SOCK 0140000 -#define NFSMODE_FIFO 0010000 - -#define NFS_MNT_PROGRAM 100005 -#define NFS_MNT_VERSION 1 -#define NFS_MNT3_VERSION 3 - -#define NFS_PIPE_DIRNAME "nfs" - -/* - * NFS stats. The good thing with these values is that NFSv3 errors are - * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which - * no-one uses anyway), so we can happily mix code as long as we make sure - * no NFSv3 errors are returned to NFSv2 clients. - * Error codes that have a `--' in the v2 column are not part of the - * standard, but seem to be widely used nevertheless. - */ - enum nfs_stat { - NFS_OK = 0, /* v2 v3 v4 */ - NFSERR_PERM = 1, /* v2 v3 v4 */ - NFSERR_NOENT = 2, /* v2 v3 v4 */ - NFSERR_IO = 5, /* v2 v3 v4 */ - NFSERR_NXIO = 6, /* v2 v3 v4 */ - NFSERR_EAGAIN = 11, /* v2 v3 */ - NFSERR_ACCES = 13, /* v2 v3 v4 */ - NFSERR_EXIST = 17, /* v2 v3 v4 */ - NFSERR_XDEV = 18, /* v3 v4 */ - NFSERR_NODEV = 19, /* v2 v3 v4 */ - NFSERR_NOTDIR = 20, /* v2 v3 v4 */ - NFSERR_ISDIR = 21, /* v2 v3 v4 */ - NFSERR_INVAL = 22, /* v2 v3 v4 */ - NFSERR_FBIG = 27, /* v2 v3 v4 */ - NFSERR_NOSPC = 28, /* v2 v3 v4 */ - NFSERR_ROFS = 30, /* v2 v3 v4 */ - NFSERR_MLINK = 31, /* v3 v4 */ - NFSERR_OPNOTSUPP = 45, /* v2 v3 */ - NFSERR_NAMETOOLONG = 63, /* v2 v3 v4 */ - NFSERR_NOTEMPTY = 66, /* v2 v3 v4 */ - NFSERR_DQUOT = 69, /* v2 v3 v4 */ - NFSERR_STALE = 70, /* v2 v3 v4 */ - NFSERR_REMOTE = 71, /* v2 v3 */ - NFSERR_WFLUSH = 99, /* v2 */ - NFSERR_BADHANDLE = 10001, /* v3 v4 */ - NFSERR_NOT_SYNC = 10002, /* v3 */ - NFSERR_BAD_COOKIE = 10003, /* v3 v4 */ - NFSERR_NOTSUPP = 10004, /* v3 v4 */ - NFSERR_TOOSMALL = 10005, /* v3 v4 */ - NFSERR_SERVERFAULT = 10006, /* v3 v4 */ - NFSERR_BADTYPE = 10007, /* v3 v4 */ - NFSERR_JUKEBOX = 10008, /* v3 v4 */ - NFSERR_SAME = 10009, /* v4 */ - NFSERR_DENIED = 10010, /* v4 */ - NFSERR_EXPIRED = 10011, /* v4 */ - NFSERR_LOCKED = 10012, /* v4 */ - NFSERR_GRACE = 10013, /* v4 */ - NFSERR_FHEXPIRED = 10014, /* v4 */ - NFSERR_SHARE_DENIED = 10015, /* v4 */ - NFSERR_WRONGSEC = 10016, /* v4 */ - NFSERR_CLID_INUSE = 10017, /* v4 */ - NFSERR_RESOURCE = 10018, /* v4 */ - NFSERR_MOVED = 10019, /* v4 */ - NFSERR_NOFILEHANDLE = 10020, /* v4 */ - NFSERR_MINOR_VERS_MISMATCH = 10021, /* v4 */ - NFSERR_STALE_CLIENTID = 10022, /* v4 */ - NFSERR_STALE_STATEID = 10023, /* v4 */ - NFSERR_OLD_STATEID = 10024, /* v4 */ - NFSERR_BAD_STATEID = 10025, /* v4 */ - NFSERR_BAD_SEQID = 10026, /* v4 */ - NFSERR_NOT_SAME = 10027, /* v4 */ - NFSERR_LOCK_RANGE = 10028, /* v4 */ - NFSERR_SYMLINK = 10029, /* v4 */ - NFSERR_RESTOREFH = 10030, /* v4 */ - NFSERR_LEASE_MOVED = 10031, /* v4 */ - NFSERR_ATTRNOTSUPP = 10032, /* v4 */ - NFSERR_NO_GRACE = 10033, /* v4 */ - NFSERR_RECLAIM_BAD = 10034, /* v4 */ - NFSERR_RECLAIM_CONFLICT = 10035,/* v4 */ - NFSERR_BAD_XDR = 10036, /* v4 */ - NFSERR_LOCKS_HELD = 10037, /* v4 */ - NFSERR_OPENMODE = 10038, /* v4 */ - NFSERR_BADOWNER = 10039, /* v4 */ - NFSERR_BADCHAR = 10040, /* v4 */ - NFSERR_BADNAME = 10041, /* v4 */ - NFSERR_BAD_RANGE = 10042, /* v4 */ - NFSERR_LOCK_NOTSUPP = 10043, /* v4 */ - NFSERR_OP_ILLEGAL = 10044, /* v4 */ - NFSERR_DEADLOCK = 10045, /* v4 */ - NFSERR_FILE_OPEN = 10046, /* v4 */ - NFSERR_ADMIN_REVOKED = 10047, /* v4 */ - NFSERR_CB_PATH_DOWN = 10048, /* v4 */ -}; - -/* NFSv2 file types - beware, these are not the same in NFSv3 */ - -enum nfs_ftype { - NFNON = 0, - NFREG = 1, - NFDIR = 2, - NFBLK = 3, - NFCHR = 4, - NFLNK = 5, - NFSOCK = 6, - NFBAD = 7, - NFFIFO = 8 -}; - -#endif /* _UAPI_LINUX_NFS_H */ diff --git a/src/linux/include/uapi/linux/nfs2.h b/src/linux/include/uapi/linux/nfs2.h deleted file mode 100644 index fde24b3..0000000 --- a/src/linux/include/uapi/linux/nfs2.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * NFS protocol definitions - * - * This file contains constants for Version 2 of the protocol. - */ -#ifndef _LINUX_NFS2_H -#define _LINUX_NFS2_H - -#define NFS2_PORT 2049 -#define NFS2_MAXDATA 8192 -#define NFS2_MAXPATHLEN 1024 -#define NFS2_MAXNAMLEN 255 -#define NFS2_MAXGROUPS 16 -#define NFS2_FHSIZE 32 -#define NFS2_COOKIESIZE 4 -#define NFS2_FIFO_DEV (-1) -#define NFS2MODE_FMT 0170000 -#define NFS2MODE_DIR 0040000 -#define NFS2MODE_CHR 0020000 -#define NFS2MODE_BLK 0060000 -#define NFS2MODE_REG 0100000 -#define NFS2MODE_LNK 0120000 -#define NFS2MODE_SOCK 0140000 -#define NFS2MODE_FIFO 0010000 - - -/* NFSv2 file types - beware, these are not the same in NFSv3 */ -enum nfs2_ftype { - NF2NON = 0, - NF2REG = 1, - NF2DIR = 2, - NF2BLK = 3, - NF2CHR = 4, - NF2LNK = 5, - NF2SOCK = 6, - NF2BAD = 7, - NF2FIFO = 8 -}; - -struct nfs2_fh { - char data[NFS2_FHSIZE]; -}; - -/* - * Procedure numbers for NFSv2 - */ -#define NFS2_VERSION 2 -#define NFSPROC_NULL 0 -#define NFSPROC_GETATTR 1 -#define NFSPROC_SETATTR 2 -#define NFSPROC_ROOT 3 -#define NFSPROC_LOOKUP 4 -#define NFSPROC_READLINK 5 -#define NFSPROC_READ 6 -#define NFSPROC_WRITECACHE 7 -#define NFSPROC_WRITE 8 -#define NFSPROC_CREATE 9 -#define NFSPROC_REMOVE 10 -#define NFSPROC_RENAME 11 -#define NFSPROC_LINK 12 -#define NFSPROC_SYMLINK 13 -#define NFSPROC_MKDIR 14 -#define NFSPROC_RMDIR 15 -#define NFSPROC_READDIR 16 -#define NFSPROC_STATFS 17 - -#endif /* _LINUX_NFS2_H */ diff --git a/src/linux/include/uapi/linux/nfs3.h b/src/linux/include/uapi/linux/nfs3.h deleted file mode 100644 index 231ef4e..0000000 --- a/src/linux/include/uapi/linux/nfs3.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * NFSv3 protocol definitions - */ -#ifndef _UAPI_LINUX_NFS3_H -#define _UAPI_LINUX_NFS3_H - -#define NFS3_PORT 2049 -#define NFS3_MAXDATA 32768 -#define NFS3_MAXPATHLEN PATH_MAX -#define NFS3_MAXNAMLEN NAME_MAX -#define NFS3_MAXGROUPS 16 -#define NFS3_FHSIZE 64 -#define NFS3_COOKIESIZE 4 -#define NFS3_CREATEVERFSIZE 8 -#define NFS3_COOKIEVERFSIZE 8 -#define NFS3_WRITEVERFSIZE 8 -#define NFS3_FIFO_DEV (-1) -#define NFS3MODE_FMT 0170000 -#define NFS3MODE_DIR 0040000 -#define NFS3MODE_CHR 0020000 -#define NFS3MODE_BLK 0060000 -#define NFS3MODE_REG 0100000 -#define NFS3MODE_LNK 0120000 -#define NFS3MODE_SOCK 0140000 -#define NFS3MODE_FIFO 0010000 - -/* Flags for access() call */ -#define NFS3_ACCESS_READ 0x0001 -#define NFS3_ACCESS_LOOKUP 0x0002 -#define NFS3_ACCESS_MODIFY 0x0004 -#define NFS3_ACCESS_EXTEND 0x0008 -#define NFS3_ACCESS_DELETE 0x0010 -#define NFS3_ACCESS_EXECUTE 0x0020 -#define NFS3_ACCESS_FULL 0x003f - -/* Flags for create mode */ -enum nfs3_createmode { - NFS3_CREATE_UNCHECKED = 0, - NFS3_CREATE_GUARDED = 1, - NFS3_CREATE_EXCLUSIVE = 2 -}; - -/* NFSv3 file system properties */ -#define NFS3_FSF_LINK 0x0001 -#define NFS3_FSF_SYMLINK 0x0002 -#define NFS3_FSF_HOMOGENEOUS 0x0008 -#define NFS3_FSF_CANSETTIME 0x0010 -/* Some shorthands. See fs/nfsd/nfs3proc.c */ -#define NFS3_FSF_DEFAULT 0x001B -#define NFS3_FSF_BILLYBOY 0x0018 -#define NFS3_FSF_READONLY 0x0008 - -enum nfs3_ftype { - NF3NON = 0, - NF3REG = 1, - NF3DIR = 2, - NF3BLK = 3, - NF3CHR = 4, - NF3LNK = 5, - NF3SOCK = 6, - NF3FIFO = 7, /* changed from NFSv2 (was 8) */ - NF3BAD = 8 -}; - -struct nfs3_fh { - unsigned short size; - unsigned char data[NFS3_FHSIZE]; -}; - -#define NFS3_VERSION 3 -#define NFS3PROC_NULL 0 -#define NFS3PROC_GETATTR 1 -#define NFS3PROC_SETATTR 2 -#define NFS3PROC_LOOKUP 3 -#define NFS3PROC_ACCESS 4 -#define NFS3PROC_READLINK 5 -#define NFS3PROC_READ 6 -#define NFS3PROC_WRITE 7 -#define NFS3PROC_CREATE 8 -#define NFS3PROC_MKDIR 9 -#define NFS3PROC_SYMLINK 10 -#define NFS3PROC_MKNOD 11 -#define NFS3PROC_REMOVE 12 -#define NFS3PROC_RMDIR 13 -#define NFS3PROC_RENAME 14 -#define NFS3PROC_LINK 15 -#define NFS3PROC_READDIR 16 -#define NFS3PROC_READDIRPLUS 17 -#define NFS3PROC_FSSTAT 18 -#define NFS3PROC_FSINFO 19 -#define NFS3PROC_PATHCONF 20 -#define NFS3PROC_COMMIT 21 - -#define NFS_MNT3_VERSION 3 - - -#endif /* _UAPI_LINUX_NFS3_H */ diff --git a/src/linux/include/uapi/linux/nfs4.h b/src/linux/include/uapi/linux/nfs4.h deleted file mode 100644 index 4ae6279..0000000 --- a/src/linux/include/uapi/linux/nfs4.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * include/linux/nfs4.h - * - * NFSv4 protocol definitions. - * - * Copyright (c) 2002 The Regents of the University of Michigan. - * All rights reserved. - * - * Kendrick Smith - * Andy Adamson - */ - -#ifndef _UAPI_LINUX_NFS4_H -#define _UAPI_LINUX_NFS4_H - -#include - -#define NFS4_BITMAP_SIZE 3 -#define NFS4_VERIFIER_SIZE 8 -#define NFS4_STATEID_SEQID_SIZE 4 -#define NFS4_STATEID_OTHER_SIZE 12 -#define NFS4_STATEID_SIZE (NFS4_STATEID_SEQID_SIZE + NFS4_STATEID_OTHER_SIZE) -#define NFS4_FHSIZE 128 -#define NFS4_MAXPATHLEN PATH_MAX -#define NFS4_MAXNAMLEN NAME_MAX -#define NFS4_OPAQUE_LIMIT 1024 -#define NFS4_MAX_SESSIONID_LEN 16 - -#define NFS4_ACCESS_READ 0x0001 -#define NFS4_ACCESS_LOOKUP 0x0002 -#define NFS4_ACCESS_MODIFY 0x0004 -#define NFS4_ACCESS_EXTEND 0x0008 -#define NFS4_ACCESS_DELETE 0x0010 -#define NFS4_ACCESS_EXECUTE 0x0020 - -#define NFS4_FH_PERSISTENT 0x0000 -#define NFS4_FH_NOEXPIRE_WITH_OPEN 0x0001 -#define NFS4_FH_VOLATILE_ANY 0x0002 -#define NFS4_FH_VOL_MIGRATION 0x0004 -#define NFS4_FH_VOL_RENAME 0x0008 - -#define NFS4_OPEN_RESULT_CONFIRM 0x0002 -#define NFS4_OPEN_RESULT_LOCKTYPE_POSIX 0x0004 -#define NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK 0x0020 - -#define NFS4_SHARE_ACCESS_MASK 0x000F -#define NFS4_SHARE_ACCESS_READ 0x0001 -#define NFS4_SHARE_ACCESS_WRITE 0x0002 -#define NFS4_SHARE_ACCESS_BOTH 0x0003 -#define NFS4_SHARE_DENY_READ 0x0001 -#define NFS4_SHARE_DENY_WRITE 0x0002 -#define NFS4_SHARE_DENY_BOTH 0x0003 - -/* nfs41 */ -#define NFS4_SHARE_WANT_MASK 0xFF00 -#define NFS4_SHARE_WANT_NO_PREFERENCE 0x0000 -#define NFS4_SHARE_WANT_READ_DELEG 0x0100 -#define NFS4_SHARE_WANT_WRITE_DELEG 0x0200 -#define NFS4_SHARE_WANT_ANY_DELEG 0x0300 -#define NFS4_SHARE_WANT_NO_DELEG 0x0400 -#define NFS4_SHARE_WANT_CANCEL 0x0500 - -#define NFS4_SHARE_WHEN_MASK 0xF0000 -#define NFS4_SHARE_SIGNAL_DELEG_WHEN_RESRC_AVAIL 0x10000 -#define NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED 0x20000 - -#define NFS4_CDFC4_FORE 0x1 -#define NFS4_CDFC4_BACK 0x2 -#define NFS4_CDFC4_BOTH 0x3 -#define NFS4_CDFC4_FORE_OR_BOTH 0x3 -#define NFS4_CDFC4_BACK_OR_BOTH 0x7 - -#define NFS4_CDFS4_FORE 0x1 -#define NFS4_CDFS4_BACK 0x2 -#define NFS4_CDFS4_BOTH 0x3 - -#define NFS4_SET_TO_SERVER_TIME 0 -#define NFS4_SET_TO_CLIENT_TIME 1 - -#define NFS4_ACE_ACCESS_ALLOWED_ACE_TYPE 0 -#define NFS4_ACE_ACCESS_DENIED_ACE_TYPE 1 -#define NFS4_ACE_SYSTEM_AUDIT_ACE_TYPE 2 -#define NFS4_ACE_SYSTEM_ALARM_ACE_TYPE 3 - -#define ACL4_SUPPORT_ALLOW_ACL 0x01 -#define ACL4_SUPPORT_DENY_ACL 0x02 -#define ACL4_SUPPORT_AUDIT_ACL 0x04 -#define ACL4_SUPPORT_ALARM_ACL 0x08 - -#define NFS4_ACL_AUTO_INHERIT 0x00000001 -#define NFS4_ACL_PROTECTED 0x00000002 -#define NFS4_ACL_DEFAULTED 0x00000004 - -#define NFS4_ACE_FILE_INHERIT_ACE 0x00000001 -#define NFS4_ACE_DIRECTORY_INHERIT_ACE 0x00000002 -#define NFS4_ACE_NO_PROPAGATE_INHERIT_ACE 0x00000004 -#define NFS4_ACE_INHERIT_ONLY_ACE 0x00000008 -#define NFS4_ACE_SUCCESSFUL_ACCESS_ACE_FLAG 0x00000010 -#define NFS4_ACE_FAILED_ACCESS_ACE_FLAG 0x00000020 -#define NFS4_ACE_IDENTIFIER_GROUP 0x00000040 -#define NFS4_ACE_INHERITED_ACE 0x00000080 - -#define NFS4_ACE_READ_DATA 0x00000001 -#define NFS4_ACE_LIST_DIRECTORY 0x00000001 -#define NFS4_ACE_WRITE_DATA 0x00000002 -#define NFS4_ACE_ADD_FILE 0x00000002 -#define NFS4_ACE_APPEND_DATA 0x00000004 -#define NFS4_ACE_ADD_SUBDIRECTORY 0x00000004 -#define NFS4_ACE_READ_NAMED_ATTRS 0x00000008 -#define NFS4_ACE_WRITE_NAMED_ATTRS 0x00000010 -#define NFS4_ACE_EXECUTE 0x00000020 -#define NFS4_ACE_DELETE_CHILD 0x00000040 -#define NFS4_ACE_READ_ATTRIBUTES 0x00000080 -#define NFS4_ACE_WRITE_ATTRIBUTES 0x00000100 -#define NFS4_ACE_WRITE_RETENTION 0x00000200 -#define NFS4_ACE_WRITE_RETENTION_HOLD 0x00000400 -#define NFS4_ACE_DELETE 0x00010000 -#define NFS4_ACE_READ_ACL 0x00020000 -#define NFS4_ACE_WRITE_ACL 0x00040000 -#define NFS4_ACE_WRITE_OWNER 0x00080000 -#define NFS4_ACE_SYNCHRONIZE 0x00100000 -#define NFS4_ACE_GENERIC_READ 0x00120081 -#define NFS4_ACE_GENERIC_WRITE 0x00160106 -#define NFS4_ACE_GENERIC_EXECUTE 0x001200A0 -#define NFS4_ACE_MASK_ALL 0x001F01FF - -#define EXCHGID4_FLAG_SUPP_MOVED_REFER 0x00000001 -#define EXCHGID4_FLAG_SUPP_MOVED_MIGR 0x00000002 -#define EXCHGID4_FLAG_BIND_PRINC_STATEID 0x00000100 - -#define EXCHGID4_FLAG_USE_NON_PNFS 0x00010000 -#define EXCHGID4_FLAG_USE_PNFS_MDS 0x00020000 -#define EXCHGID4_FLAG_USE_PNFS_DS 0x00040000 -#define EXCHGID4_FLAG_MASK_PNFS 0x00070000 - -#define EXCHGID4_FLAG_UPD_CONFIRMED_REC_A 0x40000000 -#define EXCHGID4_FLAG_CONFIRMED_R 0x80000000 -/* - * Since the validity of these bits depends on whether - * they're set in the argument or response, have separate - * invalid flag masks for arg (_A) and resp (_R). - */ -#define EXCHGID4_FLAG_MASK_A 0x40070103 -#define EXCHGID4_FLAG_MASK_R 0x80070103 - -#define SEQ4_STATUS_CB_PATH_DOWN 0x00000001 -#define SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRING 0x00000002 -#define SEQ4_STATUS_CB_GSS_CONTEXTS_EXPIRED 0x00000004 -#define SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED 0x00000008 -#define SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED 0x00000010 -#define SEQ4_STATUS_ADMIN_STATE_REVOKED 0x00000020 -#define SEQ4_STATUS_RECALLABLE_STATE_REVOKED 0x00000040 -#define SEQ4_STATUS_LEASE_MOVED 0x00000080 -#define SEQ4_STATUS_RESTART_RECLAIM_NEEDED 0x00000100 -#define SEQ4_STATUS_CB_PATH_DOWN_SESSION 0x00000200 -#define SEQ4_STATUS_BACKCHANNEL_FAULT 0x00000400 - -#define NFS4_SECINFO_STYLE4_CURRENT_FH 0 -#define NFS4_SECINFO_STYLE4_PARENT 1 - -#define NFS4_MAX_UINT64 (~(__u64)0) - -/* An NFS4 sessions server must support at least NFS4_MAX_OPS operations. - * If a compound requires more operations, adjust NFS4_MAX_OPS accordingly. - */ -#define NFS4_MAX_OPS 8 - -/* Our NFS4 client back channel server only wants the cb_sequene and the - * actual operation per compound - */ -#define NFS4_MAX_BACK_CHANNEL_OPS 2 - -#endif /* _UAPI_LINUX_NFS4_H */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/src/linux/include/uapi/linux/nfs_fs.h b/src/linux/include/uapi/linux/nfs_fs.h deleted file mode 100644 index 4914228..0000000 --- a/src/linux/include/uapi/linux/nfs_fs.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * linux/include/linux/nfs_fs.h - * - * Copyright (C) 1992 Rick Sladkey - * - * OS-specific nfs filesystem definitions and declarations - */ - -#ifndef _UAPI_LINUX_NFS_FS_H -#define _UAPI_LINUX_NFS_FS_H - -#include - -/* Default timeout values */ -#define NFS_DEF_UDP_TIMEO (11) -#define NFS_DEF_UDP_RETRANS (3) -#define NFS_DEF_TCP_TIMEO (600) -#define NFS_DEF_TCP_RETRANS (2) - -#define NFS_MAX_UDP_TIMEOUT (60*HZ) -#define NFS_MAX_TCP_TIMEOUT (600*HZ) - -#define NFS_DEF_ACREGMIN (3) -#define NFS_DEF_ACREGMAX (60) -#define NFS_DEF_ACDIRMIN (30) -#define NFS_DEF_ACDIRMAX (60) - -/* - * When flushing a cluster of dirty pages, there can be different - * strategies: - */ -#define FLUSH_SYNC 1 /* file being synced, or contention */ -#define FLUSH_STABLE 4 /* commit to stable storage */ -#define FLUSH_LOWPRI 8 /* low priority background flush */ -#define FLUSH_HIGHPRI 16 /* high priority memory reclaim flush */ -#define FLUSH_COND_STABLE 32 /* conditional stable write - only stable - * if everything fits in one RPC */ - - -/* - * NFS debug flags - */ -#define NFSDBG_VFS 0x0001 -#define NFSDBG_DIRCACHE 0x0002 -#define NFSDBG_LOOKUPCACHE 0x0004 -#define NFSDBG_PAGECACHE 0x0008 -#define NFSDBG_PROC 0x0010 -#define NFSDBG_XDR 0x0020 -#define NFSDBG_FILE 0x0040 -#define NFSDBG_ROOT 0x0080 -#define NFSDBG_CALLBACK 0x0100 -#define NFSDBG_CLIENT 0x0200 -#define NFSDBG_MOUNT 0x0400 -#define NFSDBG_FSCACHE 0x0800 -#define NFSDBG_PNFS 0x1000 -#define NFSDBG_PNFS_LD 0x2000 -#define NFSDBG_STATE 0x4000 -#define NFSDBG_ALL 0xFFFF - - -#endif /* _UAPI_LINUX_NFS_FS_H */ diff --git a/src/linux/include/uapi/linux/nfs_mount.h b/src/linux/include/uapi/linux/nfs_mount.h deleted file mode 100644 index 64b0f22..0000000 --- a/src/linux/include/uapi/linux/nfs_mount.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef _LINUX_NFS_MOUNT_H -#define _LINUX_NFS_MOUNT_H - -/* - * linux/include/linux/nfs_mount.h - * - * Copyright (C) 1992 Rick Sladkey - * - * structure passed from user-space to kernel-space during an nfs mount - */ -#include -#include -#include -#include - -/* - * WARNING! Do not delete or change the order of these fields. If - * a new field is required then add it to the end. The version field - * tracks which fields are present. This will ensure some measure of - * mount-to-kernel version compatibility. Some of these aren't used yet - * but here they are anyway. - */ -#define NFS_MOUNT_VERSION 6 -#define NFS_MAX_CONTEXT_LEN 256 - -struct nfs_mount_data { - int version; /* 1 */ - int fd; /* 1 */ - struct nfs2_fh old_root; /* 1 */ - int flags; /* 1 */ - int rsize; /* 1 */ - int wsize; /* 1 */ - int timeo; /* 1 */ - int retrans; /* 1 */ - int acregmin; /* 1 */ - int acregmax; /* 1 */ - int acdirmin; /* 1 */ - int acdirmax; /* 1 */ - struct sockaddr_in addr; /* 1 */ - char hostname[NFS_MAXNAMLEN + 1]; /* 1 */ - int namlen; /* 2 */ - unsigned int bsize; /* 3 */ - struct nfs3_fh root; /* 4 */ - int pseudoflavor; /* 5 */ - char context[NFS_MAX_CONTEXT_LEN + 1]; /* 6 */ -}; - -/* bits in the flags field visible to user space */ - -#define NFS_MOUNT_SOFT 0x0001 /* 1 */ -#define NFS_MOUNT_INTR 0x0002 /* 1 */ /* now unused, but ABI */ -#define NFS_MOUNT_SECURE 0x0004 /* 1 */ -#define NFS_MOUNT_POSIX 0x0008 /* 1 */ -#define NFS_MOUNT_NOCTO 0x0010 /* 1 */ -#define NFS_MOUNT_NOAC 0x0020 /* 1 */ -#define NFS_MOUNT_TCP 0x0040 /* 2 */ -#define NFS_MOUNT_VER3 0x0080 /* 3 */ -#define NFS_MOUNT_KERBEROS 0x0100 /* 3 */ -#define NFS_MOUNT_NONLM 0x0200 /* 3 */ -#define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */ -#define NFS_MOUNT_NOACL 0x0800 /* 4 */ -#define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */ -#define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 non-text parsed mount data only */ -#define NFS_MOUNT_NORDIRPLUS 0x4000 /* 5 */ -#define NFS_MOUNT_UNSHARED 0x8000 /* 5 */ -#define NFS_MOUNT_FLAGMASK 0xFFFF - -/* The following are for internal use only */ -#define NFS_MOUNT_LOOKUP_CACHE_NONEG 0x10000 -#define NFS_MOUNT_LOOKUP_CACHE_NONE 0x20000 -#define NFS_MOUNT_NORESVPORT 0x40000 -#define NFS_MOUNT_LEGACY_INTERFACE 0x80000 - -#define NFS_MOUNT_LOCAL_FLOCK 0x100000 -#define NFS_MOUNT_LOCAL_FCNTL 0x200000 - -#endif diff --git a/src/linux/include/uapi/linux/nfsacl.h b/src/linux/include/uapi/linux/nfsacl.h deleted file mode 100644 index 5527266..0000000 --- a/src/linux/include/uapi/linux/nfsacl.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * File: linux/nfsacl.h - * - * (C) 2003 Andreas Gruenbacher - */ -#ifndef _UAPI__LINUX_NFSACL_H -#define _UAPI__LINUX_NFSACL_H - -#define NFS_ACL_PROGRAM 100227 - -#define ACLPROC2_GETACL 1 -#define ACLPROC2_SETACL 2 -#define ACLPROC2_GETATTR 3 -#define ACLPROC2_ACCESS 4 - -#define ACLPROC3_GETACL 1 -#define ACLPROC3_SETACL 2 - - -/* Flags for the getacl/setacl mode */ -#define NFS_ACL 0x0001 -#define NFS_ACLCNT 0x0002 -#define NFS_DFACL 0x0004 -#define NFS_DFACLCNT 0x0008 -#define NFS_ACL_MASK 0x000f - -/* Flag for Default ACL entries */ -#define NFS_ACL_DEFAULT 0x1000 - -#endif /* _UAPI__LINUX_NFSACL_H */ diff --git a/src/linux/include/uapi/linux/nsfs.h b/src/linux/include/uapi/linux/nsfs.h deleted file mode 100644 index 3af6172..0000000 --- a/src/linux/include/uapi/linux/nsfs.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef __LINUX_NSFS_H -#define __LINUX_NSFS_H - -#include - -#define NSIO 0xb7 - -/* Returns a file descriptor that refers to an owning user namespace */ -#define NS_GET_USERNS _IO(NSIO, 0x1) -/* Returns a file descriptor that refers to a parent namespace */ -#define NS_GET_PARENT _IO(NSIO, 0x2) - -#endif /* __LINUX_NSFS_H */ diff --git a/src/linux/include/uapi/linux/oom.h b/src/linux/include/uapi/linux/oom.h deleted file mode 100644 index b29272d..0000000 --- a/src/linux/include/uapi/linux/oom.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef _UAPI__INCLUDE_LINUX_OOM_H -#define _UAPI__INCLUDE_LINUX_OOM_H - -/* - * /proc//oom_score_adj set to OOM_SCORE_ADJ_MIN disables oom killing for - * pid. - */ -#define OOM_SCORE_ADJ_MIN (-1000) -#define OOM_SCORE_ADJ_MAX 1000 - -/* - * /proc//oom_adj set to -17 protects from the oom killer for legacy - * purposes. - */ -#define OOM_DISABLE (-17) -/* inclusive */ -#define OOM_ADJUST_MIN (-16) -#define OOM_ADJUST_MAX 15 - -#endif /* _UAPI__INCLUDE_LINUX_OOM_H */ diff --git a/src/linux/include/uapi/linux/param.h b/src/linux/include/uapi/linux/param.h deleted file mode 100644 index 092e92f..0000000 --- a/src/linux/include/uapi/linux/param.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _LINUX_PARAM_H -#define _LINUX_PARAM_H - -#include - -#endif diff --git a/src/linux/include/uapi/linux/pci.h b/src/linux/include/uapi/linux/pci.h deleted file mode 100644 index 3c292bc..0000000 --- a/src/linux/include/uapi/linux/pci.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * pci.h - * - * PCI defines and function prototypes - * Copyright 1994, Drew Eckhardt - * Copyright 1997--1999 Martin Mares - * - * For more information, please consult the following manuals (look at - * http://www.pcisig.com/ for how to get them): - * - * PCI BIOS Specification - * PCI Local Bus Specification - * PCI to PCI Bridge Specification - * PCI System Design Guide - */ - -#ifndef _UAPILINUX_PCI_H -#define _UAPILINUX_PCI_H - -#include /* The pci register defines */ - -/* - * The PCI interface treats multi-function devices as independent - * devices. The slot/function address of each device is encoded - * in a single byte as follows: - * - * 7:3 = slot - * 2:0 = function - */ -#define PCI_DEVFN(slot, func) ((((slot) & 0x1f) << 3) | ((func) & 0x07)) -#define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) -#define PCI_FUNC(devfn) ((devfn) & 0x07) - -/* Ioctls for /proc/bus/pci/X/Y nodes. */ -#define PCIIOC_BASE ('P' << 24 | 'C' << 16 | 'I' << 8) -#define PCIIOC_CONTROLLER (PCIIOC_BASE | 0x00) /* Get controller for PCI device. */ -#define PCIIOC_MMAP_IS_IO (PCIIOC_BASE | 0x01) /* Set mmap state to I/O space. */ -#define PCIIOC_MMAP_IS_MEM (PCIIOC_BASE | 0x02) /* Set mmap state to MEM space. */ -#define PCIIOC_WRITE_COMBINE (PCIIOC_BASE | 0x03) /* Enable/disable write-combining. */ - -#endif /* _UAPILINUX_PCI_H */ diff --git a/src/linux/include/uapi/linux/pci_regs.h b/src/linux/include/uapi/linux/pci_regs.h deleted file mode 100644 index e5a2e68..0000000 --- a/src/linux/include/uapi/linux/pci_regs.h +++ /dev/null @@ -1,980 +0,0 @@ -/* - * pci_regs.h - * - * PCI standard defines - * Copyright 1994, Drew Eckhardt - * Copyright 1997--1999 Martin Mares - * - * For more information, please consult the following manuals (look at - * http://www.pcisig.com/ for how to get them): - * - * PCI BIOS Specification - * PCI Local Bus Specification - * PCI to PCI Bridge Specification - * PCI System Design Guide - * - * For HyperTransport information, please consult the following manuals - * from http://www.hypertransport.org - * - * The HyperTransport I/O Link Specification - */ - -#ifndef LINUX_PCI_REGS_H -#define LINUX_PCI_REGS_H - -/* - * Under PCI, each device has 256 bytes of configuration address space, - * of which the first 64 bytes are standardized as follows: - */ -#define PCI_STD_HEADER_SIZEOF 64 -#define PCI_VENDOR_ID 0x00 /* 16 bits */ -#define PCI_DEVICE_ID 0x02 /* 16 bits */ -#define PCI_COMMAND 0x04 /* 16 bits */ -#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ -#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ -#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */ -#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */ -#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */ -#define PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */ -#define PCI_COMMAND_PARITY 0x40 /* Enable parity checking */ -#define PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ -#define PCI_COMMAND_SERR 0x100 /* Enable SERR */ -#define PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ -#define PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ - -#define PCI_STATUS 0x06 /* 16 bits */ -#define PCI_STATUS_INTERRUPT 0x08 /* Interrupt status */ -#define PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ -#define PCI_STATUS_66MHZ 0x20 /* Support 66 MHz PCI 2.1 bus */ -#define PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ -#define PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */ -#define PCI_STATUS_PARITY 0x100 /* Detected parity error */ -#define PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */ -#define PCI_STATUS_DEVSEL_FAST 0x000 -#define PCI_STATUS_DEVSEL_MEDIUM 0x200 -#define PCI_STATUS_DEVSEL_SLOW 0x400 -#define PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */ -#define PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */ -#define PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */ -#define PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */ -#define PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */ - -#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8 revision */ -#define PCI_REVISION_ID 0x08 /* Revision ID */ -#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */ -#define PCI_CLASS_DEVICE 0x0a /* Device class */ - -#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */ -#define PCI_LATENCY_TIMER 0x0d /* 8 bits */ -#define PCI_HEADER_TYPE 0x0e /* 8 bits */ -#define PCI_HEADER_TYPE_NORMAL 0 -#define PCI_HEADER_TYPE_BRIDGE 1 -#define PCI_HEADER_TYPE_CARDBUS 2 - -#define PCI_BIST 0x0f /* 8 bits */ -#define PCI_BIST_CODE_MASK 0x0f /* Return result */ -#define PCI_BIST_START 0x40 /* 1 to start BIST, 2 secs or less */ -#define PCI_BIST_CAPABLE 0x80 /* 1 if BIST capable */ - -/* - * Base addresses specify locations in memory or I/O space. - * Decoded size can be determined by writing a value of - * 0xffffffff to the register, and reading it back. Only - * 1 bits are decoded. - */ -#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */ -#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits [htype 0,1 only] */ -#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits [htype 0 only] */ -#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */ -#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */ -#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */ -#define PCI_BASE_ADDRESS_SPACE 0x01 /* 0 = memory, 1 = I/O */ -#define PCI_BASE_ADDRESS_SPACE_IO 0x01 -#define PCI_BASE_ADDRESS_SPACE_MEMORY 0x00 -#define PCI_BASE_ADDRESS_MEM_TYPE_MASK 0x06 -#define PCI_BASE_ADDRESS_MEM_TYPE_32 0x00 /* 32 bit address */ -#define PCI_BASE_ADDRESS_MEM_TYPE_1M 0x02 /* Below 1M [obsolete] */ -#define PCI_BASE_ADDRESS_MEM_TYPE_64 0x04 /* 64 bit address */ -#define PCI_BASE_ADDRESS_MEM_PREFETCH 0x08 /* prefetchable? */ -#define PCI_BASE_ADDRESS_MEM_MASK (~0x0fUL) -#define PCI_BASE_ADDRESS_IO_MASK (~0x03UL) -/* bit 1 is reserved if address_space = 1 */ - -/* Header type 0 (normal devices) */ -#define PCI_CARDBUS_CIS 0x28 -#define PCI_SUBSYSTEM_VENDOR_ID 0x2c -#define PCI_SUBSYSTEM_ID 0x2e -#define PCI_ROM_ADDRESS 0x30 /* Bits 31..11 are address, 10..1 reserved */ -#define PCI_ROM_ADDRESS_ENABLE 0x01 -#define PCI_ROM_ADDRESS_MASK (~0x7ffUL) - -#define PCI_CAPABILITY_LIST 0x34 /* Offset of first capability list entry */ - -/* 0x35-0x3b are reserved */ -#define PCI_INTERRUPT_LINE 0x3c /* 8 bits */ -#define PCI_INTERRUPT_PIN 0x3d /* 8 bits */ -#define PCI_MIN_GNT 0x3e /* 8 bits */ -#define PCI_MAX_LAT 0x3f /* 8 bits */ - -/* Header type 1 (PCI-to-PCI bridges) */ -#define PCI_PRIMARY_BUS 0x18 /* Primary bus number */ -#define PCI_SECONDARY_BUS 0x19 /* Secondary bus number */ -#define PCI_SUBORDINATE_BUS 0x1a /* Highest bus number behind the bridge */ -#define PCI_SEC_LATENCY_TIMER 0x1b /* Latency timer for secondary interface */ -#define PCI_IO_BASE 0x1c /* I/O range behind the bridge */ -#define PCI_IO_LIMIT 0x1d -#define PCI_IO_RANGE_TYPE_MASK 0x0fUL /* I/O bridging type */ -#define PCI_IO_RANGE_TYPE_16 0x00 -#define PCI_IO_RANGE_TYPE_32 0x01 -#define PCI_IO_RANGE_MASK (~0x0fUL) /* Standard 4K I/O windows */ -#define PCI_IO_1K_RANGE_MASK (~0x03UL) /* Intel 1K I/O windows */ -#define PCI_SEC_STATUS 0x1e /* Secondary status register, only bit 14 used */ -#define PCI_MEMORY_BASE 0x20 /* Memory range behind */ -#define PCI_MEMORY_LIMIT 0x22 -#define PCI_MEMORY_RANGE_TYPE_MASK 0x0fUL -#define PCI_MEMORY_RANGE_MASK (~0x0fUL) -#define PCI_PREF_MEMORY_BASE 0x24 /* Prefetchable memory range behind */ -#define PCI_PREF_MEMORY_LIMIT 0x26 -#define PCI_PREF_RANGE_TYPE_MASK 0x0fUL -#define PCI_PREF_RANGE_TYPE_32 0x00 -#define PCI_PREF_RANGE_TYPE_64 0x01 -#define PCI_PREF_RANGE_MASK (~0x0fUL) -#define PCI_PREF_BASE_UPPER32 0x28 /* Upper half of prefetchable memory range */ -#define PCI_PREF_LIMIT_UPPER32 0x2c -#define PCI_IO_BASE_UPPER16 0x30 /* Upper half of I/O addresses */ -#define PCI_IO_LIMIT_UPPER16 0x32 -/* 0x34 same as for htype 0 */ -/* 0x35-0x3b is reserved */ -#define PCI_ROM_ADDRESS1 0x38 /* Same as PCI_ROM_ADDRESS, but for htype 1 */ -/* 0x3c-0x3d are same as for htype 0 */ -#define PCI_BRIDGE_CONTROL 0x3e -#define PCI_BRIDGE_CTL_PARITY 0x01 /* Enable parity detection on secondary interface */ -#define PCI_BRIDGE_CTL_SERR 0x02 /* The same for SERR forwarding */ -#define PCI_BRIDGE_CTL_ISA 0x04 /* Enable ISA mode */ -#define PCI_BRIDGE_CTL_VGA 0x08 /* Forward VGA addresses */ -#define PCI_BRIDGE_CTL_MASTER_ABORT 0x20 /* Report master aborts */ -#define PCI_BRIDGE_CTL_BUS_RESET 0x40 /* Secondary bus reset */ -#define PCI_BRIDGE_CTL_FAST_BACK 0x80 /* Fast Back2Back enabled on secondary interface */ - -/* Header type 2 (CardBus bridges) */ -#define PCI_CB_CAPABILITY_LIST 0x14 -/* 0x15 reserved */ -#define PCI_CB_SEC_STATUS 0x16 /* Secondary status */ -#define PCI_CB_PRIMARY_BUS 0x18 /* PCI bus number */ -#define PCI_CB_CARD_BUS 0x19 /* CardBus bus number */ -#define PCI_CB_SUBORDINATE_BUS 0x1a /* Subordinate bus number */ -#define PCI_CB_LATENCY_TIMER 0x1b /* CardBus latency timer */ -#define PCI_CB_MEMORY_BASE_0 0x1c -#define PCI_CB_MEMORY_LIMIT_0 0x20 -#define PCI_CB_MEMORY_BASE_1 0x24 -#define PCI_CB_MEMORY_LIMIT_1 0x28 -#define PCI_CB_IO_BASE_0 0x2c -#define PCI_CB_IO_BASE_0_HI 0x2e -#define PCI_CB_IO_LIMIT_0 0x30 -#define PCI_CB_IO_LIMIT_0_HI 0x32 -#define PCI_CB_IO_BASE_1 0x34 -#define PCI_CB_IO_BASE_1_HI 0x36 -#define PCI_CB_IO_LIMIT_1 0x38 -#define PCI_CB_IO_LIMIT_1_HI 0x3a -#define PCI_CB_IO_RANGE_MASK (~0x03UL) -/* 0x3c-0x3d are same as for htype 0 */ -#define PCI_CB_BRIDGE_CONTROL 0x3e -#define PCI_CB_BRIDGE_CTL_PARITY 0x01 /* Similar to standard bridge control register */ -#define PCI_CB_BRIDGE_CTL_SERR 0x02 -#define PCI_CB_BRIDGE_CTL_ISA 0x04 -#define PCI_CB_BRIDGE_CTL_VGA 0x08 -#define PCI_CB_BRIDGE_CTL_MASTER_ABORT 0x20 -#define PCI_CB_BRIDGE_CTL_CB_RESET 0x40 /* CardBus reset */ -#define PCI_CB_BRIDGE_CTL_16BIT_INT 0x80 /* Enable interrupt for 16-bit cards */ -#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 0x100 /* Prefetch enable for both memory regions */ -#define PCI_CB_BRIDGE_CTL_PREFETCH_MEM1 0x200 -#define PCI_CB_BRIDGE_CTL_POST_WRITES 0x400 -#define PCI_CB_SUBSYSTEM_VENDOR_ID 0x40 -#define PCI_CB_SUBSYSTEM_ID 0x42 -#define PCI_CB_LEGACY_MODE_BASE 0x44 /* 16-bit PC Card legacy mode base address (ExCa) */ -/* 0x48-0x7f reserved */ - -/* Capability lists */ - -#define PCI_CAP_LIST_ID 0 /* Capability ID */ -#define PCI_CAP_ID_PM 0x01 /* Power Management */ -#define PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */ -#define PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ -#define PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ -#define PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ -#define PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ -#define PCI_CAP_ID_PCIX 0x07 /* PCI-X */ -#define PCI_CAP_ID_HT 0x08 /* HyperTransport */ -#define PCI_CAP_ID_VNDR 0x09 /* Vendor-Specific */ -#define PCI_CAP_ID_DBG 0x0A /* Debug port */ -#define PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */ -#define PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ -#define PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */ -#define PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ -#define PCI_CAP_ID_SECDEV 0x0F /* Secure Device */ -#define PCI_CAP_ID_EXP 0x10 /* PCI Express */ -#define PCI_CAP_ID_MSIX 0x11 /* MSI-X */ -#define PCI_CAP_ID_SATA 0x12 /* SATA Data/Index Conf. */ -#define PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */ -#define PCI_CAP_ID_EA 0x14 /* PCI Enhanced Allocation */ -#define PCI_CAP_ID_MAX PCI_CAP_ID_EA -#define PCI_CAP_LIST_NEXT 1 /* Next capability in the list */ -#define PCI_CAP_FLAGS 2 /* Capability defined flags (16 bits) */ -#define PCI_CAP_SIZEOF 4 - -/* Power Management Registers */ - -#define PCI_PM_PMC 2 /* PM Capabilities Register */ -#define PCI_PM_CAP_VER_MASK 0x0007 /* Version */ -#define PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */ -#define PCI_PM_CAP_RESERVED 0x0010 /* Reserved field */ -#define PCI_PM_CAP_DSI 0x0020 /* Device specific initialization */ -#define PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxiliary power support mask */ -#define PCI_PM_CAP_D1 0x0200 /* D1 power state support */ -#define PCI_PM_CAP_D2 0x0400 /* D2 power state support */ -#define PCI_PM_CAP_PME 0x0800 /* PME pin supported */ -#define PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */ -#define PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */ -#define PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */ -#define PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */ -#define PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */ -#define PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */ -#define PCI_PM_CAP_PME_SHIFT 11 /* Start of the PME Mask in PMC */ -#define PCI_PM_CTRL 4 /* PM control and status register */ -#define PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */ -#define PCI_PM_CTRL_NO_SOFT_RESET 0x0008 /* No reset for D3hot->D0 */ -#define PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */ -#define PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */ -#define PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */ -#define PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */ -#define PCI_PM_PPB_EXTENSIONS 6 /* PPB support extensions (??) */ -#define PCI_PM_PPB_B2_B3 0x40 /* Stop clock when in D3hot (??) */ -#define PCI_PM_BPCC_ENABLE 0x80 /* Bus power/clock control enable (??) */ -#define PCI_PM_DATA_REGISTER 7 /* (??) */ -#define PCI_PM_SIZEOF 8 - -/* AGP registers */ - -#define PCI_AGP_VERSION 2 /* BCD version number */ -#define PCI_AGP_RFU 3 /* Rest of capability flags */ -#define PCI_AGP_STATUS 4 /* Status register */ -#define PCI_AGP_STATUS_RQ_MASK 0xff000000 /* Maximum number of requests - 1 */ -#define PCI_AGP_STATUS_SBA 0x0200 /* Sideband addressing supported */ -#define PCI_AGP_STATUS_64BIT 0x0020 /* 64-bit addressing supported */ -#define PCI_AGP_STATUS_FW 0x0010 /* FW transfers supported */ -#define PCI_AGP_STATUS_RATE4 0x0004 /* 4x transfer rate supported */ -#define PCI_AGP_STATUS_RATE2 0x0002 /* 2x transfer rate supported */ -#define PCI_AGP_STATUS_RATE1 0x0001 /* 1x transfer rate supported */ -#define PCI_AGP_COMMAND 8 /* Control register */ -#define PCI_AGP_COMMAND_RQ_MASK 0xff000000 /* Master: Maximum number of requests */ -#define PCI_AGP_COMMAND_SBA 0x0200 /* Sideband addressing enabled */ -#define PCI_AGP_COMMAND_AGP 0x0100 /* Allow processing of AGP transactions */ -#define PCI_AGP_COMMAND_64BIT 0x0020 /* Allow processing of 64-bit addresses */ -#define PCI_AGP_COMMAND_FW 0x0010 /* Force FW transfers */ -#define PCI_AGP_COMMAND_RATE4 0x0004 /* Use 4x rate */ -#define PCI_AGP_COMMAND_RATE2 0x0002 /* Use 2x rate */ -#define PCI_AGP_COMMAND_RATE1 0x0001 /* Use 1x rate */ -#define PCI_AGP_SIZEOF 12 - -/* Vital Product Data */ - -#define PCI_VPD_ADDR 2 /* Address to access (15 bits!) */ -#define PCI_VPD_ADDR_MASK 0x7fff /* Address mask */ -#define PCI_VPD_ADDR_F 0x8000 /* Write 0, 1 indicates completion */ -#define PCI_VPD_DATA 4 /* 32-bits of data returned here */ -#define PCI_CAP_VPD_SIZEOF 8 - -/* Slot Identification */ - -#define PCI_SID_ESR 2 /* Expansion Slot Register */ -#define PCI_SID_ESR_NSLOTS 0x1f /* Number of expansion slots available */ -#define PCI_SID_ESR_FIC 0x20 /* First In Chassis Flag */ -#define PCI_SID_CHASSIS_NR 3 /* Chassis Number */ - -/* Message Signalled Interrupts registers */ - -#define PCI_MSI_FLAGS 2 /* Message Control */ -#define PCI_MSI_FLAGS_ENABLE 0x0001 /* MSI feature enabled */ -#define PCI_MSI_FLAGS_QMASK 0x000e /* Maximum queue size available */ -#define PCI_MSI_FLAGS_QSIZE 0x0070 /* Message queue size configured */ -#define PCI_MSI_FLAGS_64BIT 0x0080 /* 64-bit addresses allowed */ -#define PCI_MSI_FLAGS_MASKBIT 0x0100 /* Per-vector masking capable */ -#define PCI_MSI_RFU 3 /* Rest of capability flags */ -#define PCI_MSI_ADDRESS_LO 4 /* Lower 32 bits */ -#define PCI_MSI_ADDRESS_HI 8 /* Upper 32 bits (if PCI_MSI_FLAGS_64BIT set) */ -#define PCI_MSI_DATA_32 8 /* 16 bits of data for 32-bit devices */ -#define PCI_MSI_MASK_32 12 /* Mask bits register for 32-bit devices */ -#define PCI_MSI_PENDING_32 16 /* Pending intrs for 32-bit devices */ -#define PCI_MSI_DATA_64 12 /* 16 bits of data for 64-bit devices */ -#define PCI_MSI_MASK_64 16 /* Mask bits register for 64-bit devices */ -#define PCI_MSI_PENDING_64 20 /* Pending intrs for 64-bit devices */ - -/* MSI-X registers */ -#define PCI_MSIX_FLAGS 2 /* Message Control */ -#define PCI_MSIX_FLAGS_QSIZE 0x07FF /* Table size */ -#define PCI_MSIX_FLAGS_MASKALL 0x4000 /* Mask all vectors for this function */ -#define PCI_MSIX_FLAGS_ENABLE 0x8000 /* MSI-X enable */ -#define PCI_MSIX_TABLE 4 /* Table offset */ -#define PCI_MSIX_TABLE_BIR 0x00000007 /* BAR index */ -#define PCI_MSIX_TABLE_OFFSET 0xfffffff8 /* Offset into specified BAR */ -#define PCI_MSIX_PBA 8 /* Pending Bit Array offset */ -#define PCI_MSIX_PBA_BIR 0x00000007 /* BAR index */ -#define PCI_MSIX_PBA_OFFSET 0xfffffff8 /* Offset into specified BAR */ -#define PCI_MSIX_FLAGS_BIRMASK PCI_MSIX_PBA_BIR /* deprecated */ -#define PCI_CAP_MSIX_SIZEOF 12 /* size of MSIX registers */ - -/* MSI-X Table entry format */ -#define PCI_MSIX_ENTRY_SIZE 16 -#define PCI_MSIX_ENTRY_LOWER_ADDR 0 -#define PCI_MSIX_ENTRY_UPPER_ADDR 4 -#define PCI_MSIX_ENTRY_DATA 8 -#define PCI_MSIX_ENTRY_VECTOR_CTRL 12 -#define PCI_MSIX_ENTRY_CTRL_MASKBIT 1 - -/* CompactPCI Hotswap Register */ - -#define PCI_CHSWP_CSR 2 /* Control and Status Register */ -#define PCI_CHSWP_DHA 0x01 /* Device Hiding Arm */ -#define PCI_CHSWP_EIM 0x02 /* ENUM# Signal Mask */ -#define PCI_CHSWP_PIE 0x04 /* Pending Insert or Extract */ -#define PCI_CHSWP_LOO 0x08 /* LED On / Off */ -#define PCI_CHSWP_PI 0x30 /* Programming Interface */ -#define PCI_CHSWP_EXT 0x40 /* ENUM# status - extraction */ -#define PCI_CHSWP_INS 0x80 /* ENUM# status - insertion */ - -/* PCI Advanced Feature registers */ - -#define PCI_AF_LENGTH 2 -#define PCI_AF_CAP 3 -#define PCI_AF_CAP_TP 0x01 -#define PCI_AF_CAP_FLR 0x02 -#define PCI_AF_CTRL 4 -#define PCI_AF_CTRL_FLR 0x01 -#define PCI_AF_STATUS 5 -#define PCI_AF_STATUS_TP 0x01 -#define PCI_CAP_AF_SIZEOF 6 /* size of AF registers */ - -/* PCI Enhanced Allocation registers */ - -#define PCI_EA_NUM_ENT 2 /* Number of Capability Entries */ -#define PCI_EA_NUM_ENT_MASK 0x3f /* Num Entries Mask */ -#define PCI_EA_FIRST_ENT 4 /* First EA Entry in List */ -#define PCI_EA_FIRST_ENT_BRIDGE 8 /* First EA Entry for Bridges */ -#define PCI_EA_ES 0x00000007 /* Entry Size */ -#define PCI_EA_BEI 0x000000f0 /* BAR Equivalent Indicator */ -/* 0-5 map to BARs 0-5 respectively */ -#define PCI_EA_BEI_BAR0 0 -#define PCI_EA_BEI_BAR5 5 -#define PCI_EA_BEI_BRIDGE 6 /* Resource behind bridge */ -#define PCI_EA_BEI_ENI 7 /* Equivalent Not Indicated */ -#define PCI_EA_BEI_ROM 8 /* Expansion ROM */ -/* 9-14 map to VF BARs 0-5 respectively */ -#define PCI_EA_BEI_VF_BAR0 9 -#define PCI_EA_BEI_VF_BAR5 14 -#define PCI_EA_BEI_RESERVED 15 /* Reserved - Treat like ENI */ -#define PCI_EA_PP 0x0000ff00 /* Primary Properties */ -#define PCI_EA_SP 0x00ff0000 /* Secondary Properties */ -#define PCI_EA_P_MEM 0x00 /* Non-Prefetch Memory */ -#define PCI_EA_P_MEM_PREFETCH 0x01 /* Prefetchable Memory */ -#define PCI_EA_P_IO 0x02 /* I/O Space */ -#define PCI_EA_P_VF_MEM_PREFETCH 0x03 /* VF Prefetchable Memory */ -#define PCI_EA_P_VF_MEM 0x04 /* VF Non-Prefetch Memory */ -#define PCI_EA_P_BRIDGE_MEM 0x05 /* Bridge Non-Prefetch Memory */ -#define PCI_EA_P_BRIDGE_MEM_PREFETCH 0x06 /* Bridge Prefetchable Memory */ -#define PCI_EA_P_BRIDGE_IO 0x07 /* Bridge I/O Space */ -/* 0x08-0xfc reserved */ -#define PCI_EA_P_MEM_RESERVED 0xfd /* Reserved Memory */ -#define PCI_EA_P_IO_RESERVED 0xfe /* Reserved I/O Space */ -#define PCI_EA_P_UNAVAILABLE 0xff /* Entry Unavailable */ -#define PCI_EA_WRITABLE 0x40000000 /* Writable: 1 = RW, 0 = HwInit */ -#define PCI_EA_ENABLE 0x80000000 /* Enable for this entry */ -#define PCI_EA_BASE 4 /* Base Address Offset */ -#define PCI_EA_MAX_OFFSET 8 /* MaxOffset (resource length) */ -/* bit 0 is reserved */ -#define PCI_EA_IS_64 0x00000002 /* 64-bit field flag */ -#define PCI_EA_FIELD_MASK 0xfffffffc /* For Base & Max Offset */ - -/* PCI-X registers (Type 0 (non-bridge) devices) */ - -#define PCI_X_CMD 2 /* Modes & Features */ -#define PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable */ -#define PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */ -#define PCI_X_CMD_READ_512 0x0000 /* 512 byte maximum read byte count */ -#define PCI_X_CMD_READ_1K 0x0004 /* 1Kbyte maximum read byte count */ -#define PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte count */ -#define PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte count */ -#define PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */ - /* Max # of outstanding split transactions */ -#define PCI_X_CMD_SPLIT_1 0x0000 /* Max 1 */ -#define PCI_X_CMD_SPLIT_2 0x0010 /* Max 2 */ -#define PCI_X_CMD_SPLIT_3 0x0020 /* Max 3 */ -#define PCI_X_CMD_SPLIT_4 0x0030 /* Max 4 */ -#define PCI_X_CMD_SPLIT_8 0x0040 /* Max 8 */ -#define PCI_X_CMD_SPLIT_12 0x0050 /* Max 12 */ -#define PCI_X_CMD_SPLIT_16 0x0060 /* Max 16 */ -#define PCI_X_CMD_SPLIT_32 0x0070 /* Max 32 */ -#define PCI_X_CMD_MAX_SPLIT 0x0070 /* Max Outstanding Split Transactions */ -#define PCI_X_CMD_VERSION(x) (((x) >> 12) & 3) /* Version */ -#define PCI_X_STATUS 4 /* PCI-X capabilities */ -#define PCI_X_STATUS_DEVFN 0x000000ff /* A copy of devfn */ -#define PCI_X_STATUS_BUS 0x0000ff00 /* A copy of bus nr */ -#define PCI_X_STATUS_64BIT 0x00010000 /* 64-bit device */ -#define PCI_X_STATUS_133MHZ 0x00020000 /* 133 MHz capable */ -#define PCI_X_STATUS_SPL_DISC 0x00040000 /* Split Completion Discarded */ -#define PCI_X_STATUS_UNX_SPL 0x00080000 /* Unexpected Split Completion */ -#define PCI_X_STATUS_COMPLEX 0x00100000 /* Device Complexity */ -#define PCI_X_STATUS_MAX_READ 0x00600000 /* Designed Max Memory Read Count */ -#define PCI_X_STATUS_MAX_SPLIT 0x03800000 /* Designed Max Outstanding Split Transactions */ -#define PCI_X_STATUS_MAX_CUM 0x1c000000 /* Designed Max Cumulative Read Size */ -#define PCI_X_STATUS_SPL_ERR 0x20000000 /* Rcvd Split Completion Error Msg */ -#define PCI_X_STATUS_266MHZ 0x40000000 /* 266 MHz capable */ -#define PCI_X_STATUS_533MHZ 0x80000000 /* 533 MHz capable */ -#define PCI_X_ECC_CSR 8 /* ECC control and status */ -#define PCI_CAP_PCIX_SIZEOF_V0 8 /* size of registers for Version 0 */ -#define PCI_CAP_PCIX_SIZEOF_V1 24 /* size for Version 1 */ -#define PCI_CAP_PCIX_SIZEOF_V2 PCI_CAP_PCIX_SIZEOF_V1 /* Same for v2 */ - -/* PCI-X registers (Type 1 (bridge) devices) */ - -#define PCI_X_BRIDGE_SSTATUS 2 /* Secondary Status */ -#define PCI_X_SSTATUS_64BIT 0x0001 /* Secondary AD interface is 64 bits */ -#define PCI_X_SSTATUS_133MHZ 0x0002 /* 133 MHz capable */ -#define PCI_X_SSTATUS_FREQ 0x03c0 /* Secondary Bus Mode and Frequency */ -#define PCI_X_SSTATUS_VERS 0x3000 /* PCI-X Capability Version */ -#define PCI_X_SSTATUS_V1 0x1000 /* Mode 2, not Mode 1 */ -#define PCI_X_SSTATUS_V2 0x2000 /* Mode 1 or Modes 1 and 2 */ -#define PCI_X_SSTATUS_266MHZ 0x4000 /* 266 MHz capable */ -#define PCI_X_SSTATUS_533MHZ 0x8000 /* 533 MHz capable */ -#define PCI_X_BRIDGE_STATUS 4 /* Bridge Status */ - -/* PCI Bridge Subsystem ID registers */ - -#define PCI_SSVID_VENDOR_ID 4 /* PCI Bridge subsystem vendor ID */ -#define PCI_SSVID_DEVICE_ID 6 /* PCI Bridge subsystem device ID */ - -/* PCI Express capability registers */ - -#define PCI_EXP_FLAGS 2 /* Capabilities register */ -#define PCI_EXP_FLAGS_VERS 0x000f /* Capability version */ -#define PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */ -#define PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */ -#define PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */ -#define PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */ -#define PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */ -#define PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */ -#define PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCIe to PCI/PCI-X Bridge */ -#define PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIe Bridge */ -#define PCI_EXP_TYPE_RC_END 0x9 /* Root Complex Integrated Endpoint */ -#define PCI_EXP_TYPE_RC_EC 0xa /* Root Complex Event Collector */ -#define PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */ -#define PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */ -#define PCI_EXP_DEVCAP 4 /* Device capabilities */ -#define PCI_EXP_DEVCAP_PAYLOAD 0x00000007 /* Max_Payload_Size */ -#define PCI_EXP_DEVCAP_PHANTOM 0x00000018 /* Phantom functions */ -#define PCI_EXP_DEVCAP_EXT_TAG 0x00000020 /* Extended tags */ -#define PCI_EXP_DEVCAP_L0S 0x000001c0 /* L0s Acceptable Latency */ -#define PCI_EXP_DEVCAP_L1 0x00000e00 /* L1 Acceptable Latency */ -#define PCI_EXP_DEVCAP_ATN_BUT 0x00001000 /* Attention Button Present */ -#define PCI_EXP_DEVCAP_ATN_IND 0x00002000 /* Attention Indicator Present */ -#define PCI_EXP_DEVCAP_PWR_IND 0x00004000 /* Power Indicator Present */ -#define PCI_EXP_DEVCAP_RBER 0x00008000 /* Role-Based Error Reporting */ -#define PCI_EXP_DEVCAP_PWR_VAL 0x03fc0000 /* Slot Power Limit Value */ -#define PCI_EXP_DEVCAP_PWR_SCL 0x0c000000 /* Slot Power Limit Scale */ -#define PCI_EXP_DEVCAP_FLR 0x10000000 /* Function Level Reset */ -#define PCI_EXP_DEVCTL 8 /* Device Control */ -#define PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */ -#define PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */ -#define PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enable */ -#define PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En. */ -#define PCI_EXP_DEVCTL_RELAX_EN 0x0010 /* Enable relaxed ordering */ -#define PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */ -#define PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable */ -#define PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */ -#define PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */ -#define PCI_EXP_DEVCTL_NOSNOOP_EN 0x0800 /* Enable No Snoop */ -#define PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ -#define PCI_EXP_DEVCTL_READRQ_128B 0x0000 /* 128 Bytes */ -#define PCI_EXP_DEVCTL_READRQ_256B 0x1000 /* 256 Bytes */ -#define PCI_EXP_DEVCTL_READRQ_512B 0x2000 /* 512 Bytes */ -#define PCI_EXP_DEVCTL_READRQ_1024B 0x3000 /* 1024 Bytes */ -#define PCI_EXP_DEVCTL_BCR_FLR 0x8000 /* Bridge Configuration Retry / FLR */ -#define PCI_EXP_DEVSTA 10 /* Device Status */ -#define PCI_EXP_DEVSTA_CED 0x0001 /* Correctable Error Detected */ -#define PCI_EXP_DEVSTA_NFED 0x0002 /* Non-Fatal Error Detected */ -#define PCI_EXP_DEVSTA_FED 0x0004 /* Fatal Error Detected */ -#define PCI_EXP_DEVSTA_URD 0x0008 /* Unsupported Request Detected */ -#define PCI_EXP_DEVSTA_AUXPD 0x0010 /* AUX Power Detected */ -#define PCI_EXP_DEVSTA_TRPND 0x0020 /* Transactions Pending */ -#define PCI_EXP_LNKCAP 12 /* Link Capabilities */ -#define PCI_EXP_LNKCAP_SLS 0x0000000f /* Supported Link Speeds */ -#define PCI_EXP_LNKCAP_SLS_2_5GB 0x00000001 /* LNKCAP2 SLS Vector bit 0 */ -#define PCI_EXP_LNKCAP_SLS_5_0GB 0x00000002 /* LNKCAP2 SLS Vector bit 1 */ -#define PCI_EXP_LNKCAP_MLW 0x000003f0 /* Maximum Link Width */ -#define PCI_EXP_LNKCAP_ASPMS 0x00000c00 /* ASPM Support */ -#define PCI_EXP_LNKCAP_L0SEL 0x00007000 /* L0s Exit Latency */ -#define PCI_EXP_LNKCAP_L1EL 0x00038000 /* L1 Exit Latency */ -#define PCI_EXP_LNKCAP_CLKPM 0x00040000 /* Clock Power Management */ -#define PCI_EXP_LNKCAP_SDERC 0x00080000 /* Surprise Down Error Reporting Capable */ -#define PCI_EXP_LNKCAP_DLLLARC 0x00100000 /* Data Link Layer Link Active Reporting Capable */ -#define PCI_EXP_LNKCAP_LBNC 0x00200000 /* Link Bandwidth Notification Capability */ -#define PCI_EXP_LNKCAP_PN 0xff000000 /* Port Number */ -#define PCI_EXP_LNKCTL 16 /* Link Control */ -#define PCI_EXP_LNKCTL_ASPMC 0x0003 /* ASPM Control */ -#define PCI_EXP_LNKCTL_ASPM_L0S 0x0001 /* L0s Enable */ -#define PCI_EXP_LNKCTL_ASPM_L1 0x0002 /* L1 Enable */ -#define PCI_EXP_LNKCTL_RCB 0x0008 /* Read Completion Boundary */ -#define PCI_EXP_LNKCTL_LD 0x0010 /* Link Disable */ -#define PCI_EXP_LNKCTL_RL 0x0020 /* Retrain Link */ -#define PCI_EXP_LNKCTL_CCC 0x0040 /* Common Clock Configuration */ -#define PCI_EXP_LNKCTL_ES 0x0080 /* Extended Synch */ -#define PCI_EXP_LNKCTL_CLKREQ_EN 0x0100 /* Enable clkreq */ -#define PCI_EXP_LNKCTL_HAWD 0x0200 /* Hardware Autonomous Width Disable */ -#define PCI_EXP_LNKCTL_LBMIE 0x0400 /* Link Bandwidth Management Interrupt Enable */ -#define PCI_EXP_LNKCTL_LABIE 0x0800 /* Link Autonomous Bandwidth Interrupt Enable */ -#define PCI_EXP_LNKSTA 18 /* Link Status */ -#define PCI_EXP_LNKSTA_CLS 0x000f /* Current Link Speed */ -#define PCI_EXP_LNKSTA_CLS_2_5GB 0x0001 /* Current Link Speed 2.5GT/s */ -#define PCI_EXP_LNKSTA_CLS_5_0GB 0x0002 /* Current Link Speed 5.0GT/s */ -#define PCI_EXP_LNKSTA_CLS_8_0GB 0x0003 /* Current Link Speed 8.0GT/s */ -#define PCI_EXP_LNKSTA_NLW 0x03f0 /* Negotiated Link Width */ -#define PCI_EXP_LNKSTA_NLW_X1 0x0010 /* Current Link Width x1 */ -#define PCI_EXP_LNKSTA_NLW_X2 0x0020 /* Current Link Width x2 */ -#define PCI_EXP_LNKSTA_NLW_X4 0x0040 /* Current Link Width x4 */ -#define PCI_EXP_LNKSTA_NLW_X8 0x0080 /* Current Link Width x8 */ -#define PCI_EXP_LNKSTA_NLW_SHIFT 4 /* start of NLW mask in link status */ -#define PCI_EXP_LNKSTA_LT 0x0800 /* Link Training */ -#define PCI_EXP_LNKSTA_SLC 0x1000 /* Slot Clock Configuration */ -#define PCI_EXP_LNKSTA_DLLLA 0x2000 /* Data Link Layer Link Active */ -#define PCI_EXP_LNKSTA_LBMS 0x4000 /* Link Bandwidth Management Status */ -#define PCI_EXP_LNKSTA_LABS 0x8000 /* Link Autonomous Bandwidth Status */ -#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V1 20 /* v1 endpoints end here */ -#define PCI_EXP_SLTCAP 20 /* Slot Capabilities */ -#define PCI_EXP_SLTCAP_ABP 0x00000001 /* Attention Button Present */ -#define PCI_EXP_SLTCAP_PCP 0x00000002 /* Power Controller Present */ -#define PCI_EXP_SLTCAP_MRLSP 0x00000004 /* MRL Sensor Present */ -#define PCI_EXP_SLTCAP_AIP 0x00000008 /* Attention Indicator Present */ -#define PCI_EXP_SLTCAP_PIP 0x00000010 /* Power Indicator Present */ -#define PCI_EXP_SLTCAP_HPS 0x00000020 /* Hot-Plug Surprise */ -#define PCI_EXP_SLTCAP_HPC 0x00000040 /* Hot-Plug Capable */ -#define PCI_EXP_SLTCAP_SPLV 0x00007f80 /* Slot Power Limit Value */ -#define PCI_EXP_SLTCAP_SPLS 0x00018000 /* Slot Power Limit Scale */ -#define PCI_EXP_SLTCAP_EIP 0x00020000 /* Electromechanical Interlock Present */ -#define PCI_EXP_SLTCAP_NCCS 0x00040000 /* No Command Completed Support */ -#define PCI_EXP_SLTCAP_PSN 0xfff80000 /* Physical Slot Number */ -#define PCI_EXP_SLTCTL 24 /* Slot Control */ -#define PCI_EXP_SLTCTL_ABPE 0x0001 /* Attention Button Pressed Enable */ -#define PCI_EXP_SLTCTL_PFDE 0x0002 /* Power Fault Detected Enable */ -#define PCI_EXP_SLTCTL_MRLSCE 0x0004 /* MRL Sensor Changed Enable */ -#define PCI_EXP_SLTCTL_PDCE 0x0008 /* Presence Detect Changed Enable */ -#define PCI_EXP_SLTCTL_CCIE 0x0010 /* Command Completed Interrupt Enable */ -#define PCI_EXP_SLTCTL_HPIE 0x0020 /* Hot-Plug Interrupt Enable */ -#define PCI_EXP_SLTCTL_AIC 0x00c0 /* Attention Indicator Control */ -#define PCI_EXP_SLTCTL_ATTN_IND_ON 0x0040 /* Attention Indicator on */ -#define PCI_EXP_SLTCTL_ATTN_IND_BLINK 0x0080 /* Attention Indicator blinking */ -#define PCI_EXP_SLTCTL_ATTN_IND_OFF 0x00c0 /* Attention Indicator off */ -#define PCI_EXP_SLTCTL_PIC 0x0300 /* Power Indicator Control */ -#define PCI_EXP_SLTCTL_PWR_IND_ON 0x0100 /* Power Indicator on */ -#define PCI_EXP_SLTCTL_PWR_IND_BLINK 0x0200 /* Power Indicator blinking */ -#define PCI_EXP_SLTCTL_PWR_IND_OFF 0x0300 /* Power Indicator off */ -#define PCI_EXP_SLTCTL_PCC 0x0400 /* Power Controller Control */ -#define PCI_EXP_SLTCTL_PWR_ON 0x0000 /* Power On */ -#define PCI_EXP_SLTCTL_PWR_OFF 0x0400 /* Power Off */ -#define PCI_EXP_SLTCTL_EIC 0x0800 /* Electromechanical Interlock Control */ -#define PCI_EXP_SLTCTL_DLLSCE 0x1000 /* Data Link Layer State Changed Enable */ -#define PCI_EXP_SLTSTA 26 /* Slot Status */ -#define PCI_EXP_SLTSTA_ABP 0x0001 /* Attention Button Pressed */ -#define PCI_EXP_SLTSTA_PFD 0x0002 /* Power Fault Detected */ -#define PCI_EXP_SLTSTA_MRLSC 0x0004 /* MRL Sensor Changed */ -#define PCI_EXP_SLTSTA_PDC 0x0008 /* Presence Detect Changed */ -#define PCI_EXP_SLTSTA_CC 0x0010 /* Command Completed */ -#define PCI_EXP_SLTSTA_MRLSS 0x0020 /* MRL Sensor State */ -#define PCI_EXP_SLTSTA_PDS 0x0040 /* Presence Detect State */ -#define PCI_EXP_SLTSTA_EIS 0x0080 /* Electromechanical Interlock Status */ -#define PCI_EXP_SLTSTA_DLLSC 0x0100 /* Data Link Layer State Changed */ -#define PCI_EXP_RTCTL 28 /* Root Control */ -#define PCI_EXP_RTCTL_SECEE 0x0001 /* System Error on Correctable Error */ -#define PCI_EXP_RTCTL_SENFEE 0x0002 /* System Error on Non-Fatal Error */ -#define PCI_EXP_RTCTL_SEFEE 0x0004 /* System Error on Fatal Error */ -#define PCI_EXP_RTCTL_PMEIE 0x0008 /* PME Interrupt Enable */ -#define PCI_EXP_RTCTL_CRSSVE 0x0010 /* CRS Software Visibility Enable */ -#define PCI_EXP_RTCAP 30 /* Root Capabilities */ -#define PCI_EXP_RTCAP_CRSVIS 0x0001 /* CRS Software Visibility capability */ -#define PCI_EXP_RTSTA 32 /* Root Status */ -#define PCI_EXP_RTSTA_PME 0x00010000 /* PME status */ -#define PCI_EXP_RTSTA_PENDING 0x00020000 /* PME pending */ -/* - * The Device Capabilities 2, Device Status 2, Device Control 2, - * Link Capabilities 2, Link Status 2, Link Control 2, - * Slot Capabilities 2, Slot Status 2, and Slot Control 2 registers - * are only present on devices with PCIe Capability version 2. - * Use pcie_capability_read_word() and similar interfaces to use them - * safely. - */ -#define PCI_EXP_DEVCAP2 36 /* Device Capabilities 2 */ -#define PCI_EXP_DEVCAP2_ARI 0x00000020 /* Alternative Routing-ID */ -#define PCI_EXP_DEVCAP2_ATOMIC_ROUTE 0x00000040 /* Atomic Op routing */ -#define PCI_EXP_DEVCAP2_ATOMIC_COMP64 0x00000100 /* Atomic 64-bit compare */ -#define PCI_EXP_DEVCAP2_LTR 0x00000800 /* Latency tolerance reporting */ -#define PCI_EXP_DEVCAP2_OBFF_MASK 0x000c0000 /* OBFF support mechanism */ -#define PCI_EXP_DEVCAP2_OBFF_MSG 0x00040000 /* New message signaling */ -#define PCI_EXP_DEVCAP2_OBFF_WAKE 0x00080000 /* Re-use WAKE# for OBFF */ -#define PCI_EXP_DEVCTL2 40 /* Device Control 2 */ -#define PCI_EXP_DEVCTL2_COMP_TIMEOUT 0x000f /* Completion Timeout Value */ -#define PCI_EXP_DEVCTL2_ARI 0x0020 /* Alternative Routing-ID */ -#define PCI_EXP_DEVCTL2_ATOMIC_REQ 0x0040 /* Set Atomic requests */ -#define PCI_EXP_DEVCTL2_IDO_REQ_EN 0x0100 /* Allow IDO for requests */ -#define PCI_EXP_DEVCTL2_IDO_CMP_EN 0x0200 /* Allow IDO for completions */ -#define PCI_EXP_DEVCTL2_LTR_EN 0x0400 /* Enable LTR mechanism */ -#define PCI_EXP_DEVCTL2_OBFF_MSGA_EN 0x2000 /* Enable OBFF Message type A */ -#define PCI_EXP_DEVCTL2_OBFF_MSGB_EN 0x4000 /* Enable OBFF Message type B */ -#define PCI_EXP_DEVCTL2_OBFF_WAKE_EN 0x6000 /* OBFF using WAKE# signaling */ -#define PCI_EXP_DEVSTA2 42 /* Device Status 2 */ -#define PCI_CAP_EXP_ENDPOINT_SIZEOF_V2 44 /* v2 endpoints end here */ -#define PCI_EXP_LNKCAP2 44 /* Link Capabilities 2 */ -#define PCI_EXP_LNKCAP2_SLS_2_5GB 0x00000002 /* Supported Speed 2.5GT/s */ -#define PCI_EXP_LNKCAP2_SLS_5_0GB 0x00000004 /* Supported Speed 5.0GT/s */ -#define PCI_EXP_LNKCAP2_SLS_8_0GB 0x00000008 /* Supported Speed 8.0GT/s */ -#define PCI_EXP_LNKCAP2_CROSSLINK 0x00000100 /* Crosslink supported */ -#define PCI_EXP_LNKCTL2 48 /* Link Control 2 */ -#define PCI_EXP_LNKSTA2 50 /* Link Status 2 */ -#define PCI_EXP_SLTCAP2 52 /* Slot Capabilities 2 */ -#define PCI_EXP_SLTCTL2 56 /* Slot Control 2 */ -#define PCI_EXP_SLTSTA2 58 /* Slot Status 2 */ - -/* Extended Capabilities (PCI-X 2.0 and Express) */ -#define PCI_EXT_CAP_ID(header) (header & 0x0000ffff) -#define PCI_EXT_CAP_VER(header) ((header >> 16) & 0xf) -#define PCI_EXT_CAP_NEXT(header) ((header >> 20) & 0xffc) - -#define PCI_EXT_CAP_ID_ERR 0x01 /* Advanced Error Reporting */ -#define PCI_EXT_CAP_ID_VC 0x02 /* Virtual Channel Capability */ -#define PCI_EXT_CAP_ID_DSN 0x03 /* Device Serial Number */ -#define PCI_EXT_CAP_ID_PWR 0x04 /* Power Budgeting */ -#define PCI_EXT_CAP_ID_RCLD 0x05 /* Root Complex Link Declaration */ -#define PCI_EXT_CAP_ID_RCILC 0x06 /* Root Complex Internal Link Control */ -#define PCI_EXT_CAP_ID_RCEC 0x07 /* Root Complex Event Collector */ -#define PCI_EXT_CAP_ID_MFVC 0x08 /* Multi-Function VC Capability */ -#define PCI_EXT_CAP_ID_VC9 0x09 /* same as _VC */ -#define PCI_EXT_CAP_ID_RCRB 0x0A /* Root Complex RB? */ -#define PCI_EXT_CAP_ID_VNDR 0x0B /* Vendor-Specific */ -#define PCI_EXT_CAP_ID_CAC 0x0C /* Config Access - obsolete */ -#define PCI_EXT_CAP_ID_ACS 0x0D /* Access Control Services */ -#define PCI_EXT_CAP_ID_ARI 0x0E /* Alternate Routing ID */ -#define PCI_EXT_CAP_ID_ATS 0x0F /* Address Translation Services */ -#define PCI_EXT_CAP_ID_SRIOV 0x10 /* Single Root I/O Virtualization */ -#define PCI_EXT_CAP_ID_MRIOV 0x11 /* Multi Root I/O Virtualization */ -#define PCI_EXT_CAP_ID_MCAST 0x12 /* Multicast */ -#define PCI_EXT_CAP_ID_PRI 0x13 /* Page Request Interface */ -#define PCI_EXT_CAP_ID_AMD_XXX 0x14 /* Reserved for AMD */ -#define PCI_EXT_CAP_ID_REBAR 0x15 /* Resizable BAR */ -#define PCI_EXT_CAP_ID_DPA 0x16 /* Dynamic Power Allocation */ -#define PCI_EXT_CAP_ID_TPH 0x17 /* TPH Requester */ -#define PCI_EXT_CAP_ID_LTR 0x18 /* Latency Tolerance Reporting */ -#define PCI_EXT_CAP_ID_SECPCI 0x19 /* Secondary PCIe Capability */ -#define PCI_EXT_CAP_ID_PMUX 0x1A /* Protocol Multiplexing */ -#define PCI_EXT_CAP_ID_PASID 0x1B /* Process Address Space ID */ -#define PCI_EXT_CAP_ID_DPC 0x1D /* Downstream Port Containment */ -#define PCI_EXT_CAP_ID_PTM 0x1F /* Precision Time Measurement */ -#define PCI_EXT_CAP_ID_MAX PCI_EXT_CAP_ID_PTM - -#define PCI_EXT_CAP_DSN_SIZEOF 12 -#define PCI_EXT_CAP_MCAST_ENDPOINT_SIZEOF 40 - -/* Advanced Error Reporting */ -#define PCI_ERR_UNCOR_STATUS 4 /* Uncorrectable Error Status */ -#define PCI_ERR_UNC_UND 0x00000001 /* Undefined */ -#define PCI_ERR_UNC_DLP 0x00000010 /* Data Link Protocol */ -#define PCI_ERR_UNC_SURPDN 0x00000020 /* Surprise Down */ -#define PCI_ERR_UNC_POISON_TLP 0x00001000 /* Poisoned TLP */ -#define PCI_ERR_UNC_FCP 0x00002000 /* Flow Control Protocol */ -#define PCI_ERR_UNC_COMP_TIME 0x00004000 /* Completion Timeout */ -#define PCI_ERR_UNC_COMP_ABORT 0x00008000 /* Completer Abort */ -#define PCI_ERR_UNC_UNX_COMP 0x00010000 /* Unexpected Completion */ -#define PCI_ERR_UNC_RX_OVER 0x00020000 /* Receiver Overflow */ -#define PCI_ERR_UNC_MALF_TLP 0x00040000 /* Malformed TLP */ -#define PCI_ERR_UNC_ECRC 0x00080000 /* ECRC Error Status */ -#define PCI_ERR_UNC_UNSUP 0x00100000 /* Unsupported Request */ -#define PCI_ERR_UNC_ACSV 0x00200000 /* ACS Violation */ -#define PCI_ERR_UNC_INTN 0x00400000 /* internal error */ -#define PCI_ERR_UNC_MCBTLP 0x00800000 /* MC blocked TLP */ -#define PCI_ERR_UNC_ATOMEG 0x01000000 /* Atomic egress blocked */ -#define PCI_ERR_UNC_TLPPRE 0x02000000 /* TLP prefix blocked */ -#define PCI_ERR_UNCOR_MASK 8 /* Uncorrectable Error Mask */ - /* Same bits as above */ -#define PCI_ERR_UNCOR_SEVER 12 /* Uncorrectable Error Severity */ - /* Same bits as above */ -#define PCI_ERR_COR_STATUS 16 /* Correctable Error Status */ -#define PCI_ERR_COR_RCVR 0x00000001 /* Receiver Error Status */ -#define PCI_ERR_COR_BAD_TLP 0x00000040 /* Bad TLP Status */ -#define PCI_ERR_COR_BAD_DLLP 0x00000080 /* Bad DLLP Status */ -#define PCI_ERR_COR_REP_ROLL 0x00000100 /* REPLAY_NUM Rollover */ -#define PCI_ERR_COR_REP_TIMER 0x00001000 /* Replay Timer Timeout */ -#define PCI_ERR_COR_ADV_NFAT 0x00002000 /* Advisory Non-Fatal */ -#define PCI_ERR_COR_INTERNAL 0x00004000 /* Corrected Internal */ -#define PCI_ERR_COR_LOG_OVER 0x00008000 /* Header Log Overflow */ -#define PCI_ERR_COR_MASK 20 /* Correctable Error Mask */ - /* Same bits as above */ -#define PCI_ERR_CAP 24 /* Advanced Error Capabilities */ -#define PCI_ERR_CAP_FEP(x) ((x) & 31) /* First Error Pointer */ -#define PCI_ERR_CAP_ECRC_GENC 0x00000020 /* ECRC Generation Capable */ -#define PCI_ERR_CAP_ECRC_GENE 0x00000040 /* ECRC Generation Enable */ -#define PCI_ERR_CAP_ECRC_CHKC 0x00000080 /* ECRC Check Capable */ -#define PCI_ERR_CAP_ECRC_CHKE 0x00000100 /* ECRC Check Enable */ -#define PCI_ERR_HEADER_LOG 28 /* Header Log Register (16 bytes) */ -#define PCI_ERR_ROOT_COMMAND 44 /* Root Error Command */ -/* Correctable Err Reporting Enable */ -#define PCI_ERR_ROOT_CMD_COR_EN 0x00000001 -/* Non-fatal Err Reporting Enable */ -#define PCI_ERR_ROOT_CMD_NONFATAL_EN 0x00000002 -/* Fatal Err Reporting Enable */ -#define PCI_ERR_ROOT_CMD_FATAL_EN 0x00000004 -#define PCI_ERR_ROOT_STATUS 48 -#define PCI_ERR_ROOT_COR_RCV 0x00000001 /* ERR_COR Received */ -/* Multi ERR_COR Received */ -#define PCI_ERR_ROOT_MULTI_COR_RCV 0x00000002 -/* ERR_FATAL/NONFATAL Received */ -#define PCI_ERR_ROOT_UNCOR_RCV 0x00000004 -/* Multi ERR_FATAL/NONFATAL Received */ -#define PCI_ERR_ROOT_MULTI_UNCOR_RCV 0x00000008 -#define PCI_ERR_ROOT_FIRST_FATAL 0x00000010 /* First Fatal */ -#define PCI_ERR_ROOT_NONFATAL_RCV 0x00000020 /* Non-Fatal Received */ -#define PCI_ERR_ROOT_FATAL_RCV 0x00000040 /* Fatal Received */ -#define PCI_ERR_ROOT_ERR_SRC 52 /* Error Source Identification */ - -/* Virtual Channel */ -#define PCI_VC_PORT_CAP1 4 -#define PCI_VC_CAP1_EVCC 0x00000007 /* extended VC count */ -#define PCI_VC_CAP1_LPEVCC 0x00000070 /* low prio extended VC count */ -#define PCI_VC_CAP1_ARB_SIZE 0x00000c00 -#define PCI_VC_PORT_CAP2 8 -#define PCI_VC_CAP2_32_PHASE 0x00000002 -#define PCI_VC_CAP2_64_PHASE 0x00000004 -#define PCI_VC_CAP2_128_PHASE 0x00000008 -#define PCI_VC_CAP2_ARB_OFF 0xff000000 -#define PCI_VC_PORT_CTRL 12 -#define PCI_VC_PORT_CTRL_LOAD_TABLE 0x00000001 -#define PCI_VC_PORT_STATUS 14 -#define PCI_VC_PORT_STATUS_TABLE 0x00000001 -#define PCI_VC_RES_CAP 16 -#define PCI_VC_RES_CAP_32_PHASE 0x00000002 -#define PCI_VC_RES_CAP_64_PHASE 0x00000004 -#define PCI_VC_RES_CAP_128_PHASE 0x00000008 -#define PCI_VC_RES_CAP_128_PHASE_TB 0x00000010 -#define PCI_VC_RES_CAP_256_PHASE 0x00000020 -#define PCI_VC_RES_CAP_ARB_OFF 0xff000000 -#define PCI_VC_RES_CTRL 20 -#define PCI_VC_RES_CTRL_LOAD_TABLE 0x00010000 -#define PCI_VC_RES_CTRL_ARB_SELECT 0x000e0000 -#define PCI_VC_RES_CTRL_ID 0x07000000 -#define PCI_VC_RES_CTRL_ENABLE 0x80000000 -#define PCI_VC_RES_STATUS 26 -#define PCI_VC_RES_STATUS_TABLE 0x00000001 -#define PCI_VC_RES_STATUS_NEGO 0x00000002 -#define PCI_CAP_VC_BASE_SIZEOF 0x10 -#define PCI_CAP_VC_PER_VC_SIZEOF 0x0C - -/* Power Budgeting */ -#define PCI_PWR_DSR 4 /* Data Select Register */ -#define PCI_PWR_DATA 8 /* Data Register */ -#define PCI_PWR_DATA_BASE(x) ((x) & 0xff) /* Base Power */ -#define PCI_PWR_DATA_SCALE(x) (((x) >> 8) & 3) /* Data Scale */ -#define PCI_PWR_DATA_PM_SUB(x) (((x) >> 10) & 7) /* PM Sub State */ -#define PCI_PWR_DATA_PM_STATE(x) (((x) >> 13) & 3) /* PM State */ -#define PCI_PWR_DATA_TYPE(x) (((x) >> 15) & 7) /* Type */ -#define PCI_PWR_DATA_RAIL(x) (((x) >> 18) & 7) /* Power Rail */ -#define PCI_PWR_CAP 12 /* Capability */ -#define PCI_PWR_CAP_BUDGET(x) ((x) & 1) /* Included in system budget */ -#define PCI_EXT_CAP_PWR_SIZEOF 16 - -/* Vendor-Specific (VSEC, PCI_EXT_CAP_ID_VNDR) */ -#define PCI_VNDR_HEADER 4 /* Vendor-Specific Header */ -#define PCI_VNDR_HEADER_ID(x) ((x) & 0xffff) -#define PCI_VNDR_HEADER_REV(x) (((x) >> 16) & 0xf) -#define PCI_VNDR_HEADER_LEN(x) (((x) >> 20) & 0xfff) - -/* - * HyperTransport sub capability types - * - * Unfortunately there are both 3 bit and 5 bit capability types defined - * in the HT spec, catering for that is a little messy. You probably don't - * want to use these directly, just use pci_find_ht_capability() and it - * will do the right thing for you. - */ -#define HT_3BIT_CAP_MASK 0xE0 -#define HT_CAPTYPE_SLAVE 0x00 /* Slave/Primary link configuration */ -#define HT_CAPTYPE_HOST 0x20 /* Host/Secondary link configuration */ - -#define HT_5BIT_CAP_MASK 0xF8 -#define HT_CAPTYPE_IRQ 0x80 /* IRQ Configuration */ -#define HT_CAPTYPE_REMAPPING_40 0xA0 /* 40 bit address remapping */ -#define HT_CAPTYPE_REMAPPING_64 0xA2 /* 64 bit address remapping */ -#define HT_CAPTYPE_UNITID_CLUMP 0x90 /* Unit ID clumping */ -#define HT_CAPTYPE_EXTCONF 0x98 /* Extended Configuration Space Access */ -#define HT_CAPTYPE_MSI_MAPPING 0xA8 /* MSI Mapping Capability */ -#define HT_MSI_FLAGS 0x02 /* Offset to flags */ -#define HT_MSI_FLAGS_ENABLE 0x1 /* Mapping enable */ -#define HT_MSI_FLAGS_FIXED 0x2 /* Fixed mapping only */ -#define HT_MSI_FIXED_ADDR 0x00000000FEE00000ULL /* Fixed addr */ -#define HT_MSI_ADDR_LO 0x04 /* Offset to low addr bits */ -#define HT_MSI_ADDR_LO_MASK 0xFFF00000 /* Low address bit mask */ -#define HT_MSI_ADDR_HI 0x08 /* Offset to high addr bits */ -#define HT_CAPTYPE_DIRECT_ROUTE 0xB0 /* Direct routing configuration */ -#define HT_CAPTYPE_VCSET 0xB8 /* Virtual Channel configuration */ -#define HT_CAPTYPE_ERROR_RETRY 0xC0 /* Retry on error configuration */ -#define HT_CAPTYPE_GEN3 0xD0 /* Generation 3 HyperTransport configuration */ -#define HT_CAPTYPE_PM 0xE0 /* HyperTransport power management configuration */ -#define HT_CAP_SIZEOF_LONG 28 /* slave & primary */ -#define HT_CAP_SIZEOF_SHORT 24 /* host & secondary */ - -/* Alternative Routing-ID Interpretation */ -#define PCI_ARI_CAP 0x04 /* ARI Capability Register */ -#define PCI_ARI_CAP_MFVC 0x0001 /* MFVC Function Groups Capability */ -#define PCI_ARI_CAP_ACS 0x0002 /* ACS Function Groups Capability */ -#define PCI_ARI_CAP_NFN(x) (((x) >> 8) & 0xff) /* Next Function Number */ -#define PCI_ARI_CTRL 0x06 /* ARI Control Register */ -#define PCI_ARI_CTRL_MFVC 0x0001 /* MFVC Function Groups Enable */ -#define PCI_ARI_CTRL_ACS 0x0002 /* ACS Function Groups Enable */ -#define PCI_ARI_CTRL_FG(x) (((x) >> 4) & 7) /* Function Group */ -#define PCI_EXT_CAP_ARI_SIZEOF 8 - -/* Address Translation Service */ -#define PCI_ATS_CAP 0x04 /* ATS Capability Register */ -#define PCI_ATS_CAP_QDEP(x) ((x) & 0x1f) /* Invalidate Queue Depth */ -#define PCI_ATS_MAX_QDEP 32 /* Max Invalidate Queue Depth */ -#define PCI_ATS_CTRL 0x06 /* ATS Control Register */ -#define PCI_ATS_CTRL_ENABLE 0x8000 /* ATS Enable */ -#define PCI_ATS_CTRL_STU(x) ((x) & 0x1f) /* Smallest Translation Unit */ -#define PCI_ATS_MIN_STU 12 /* shift of minimum STU block */ -#define PCI_EXT_CAP_ATS_SIZEOF 8 - -/* Page Request Interface */ -#define PCI_PRI_CTRL 0x04 /* PRI control register */ -#define PCI_PRI_CTRL_ENABLE 0x01 /* Enable */ -#define PCI_PRI_CTRL_RESET 0x02 /* Reset */ -#define PCI_PRI_STATUS 0x06 /* PRI status register */ -#define PCI_PRI_STATUS_RF 0x001 /* Response Failure */ -#define PCI_PRI_STATUS_UPRGI 0x002 /* Unexpected PRG index */ -#define PCI_PRI_STATUS_STOPPED 0x100 /* PRI Stopped */ -#define PCI_PRI_MAX_REQ 0x08 /* PRI max reqs supported */ -#define PCI_PRI_ALLOC_REQ 0x0c /* PRI max reqs allowed */ -#define PCI_EXT_CAP_PRI_SIZEOF 16 - -/* Process Address Space ID */ -#define PCI_PASID_CAP 0x04 /* PASID feature register */ -#define PCI_PASID_CAP_EXEC 0x02 /* Exec permissions Supported */ -#define PCI_PASID_CAP_PRIV 0x04 /* Privilege Mode Supported */ -#define PCI_PASID_CTRL 0x06 /* PASID control register */ -#define PCI_PASID_CTRL_ENABLE 0x01 /* Enable bit */ -#define PCI_PASID_CTRL_EXEC 0x02 /* Exec permissions Enable */ -#define PCI_PASID_CTRL_PRIV 0x04 /* Privilege Mode Enable */ -#define PCI_EXT_CAP_PASID_SIZEOF 8 - -/* Single Root I/O Virtualization */ -#define PCI_SRIOV_CAP 0x04 /* SR-IOV Capabilities */ -#define PCI_SRIOV_CAP_VFM 0x01 /* VF Migration Capable */ -#define PCI_SRIOV_CAP_INTR(x) ((x) >> 21) /* Interrupt Message Number */ -#define PCI_SRIOV_CTRL 0x08 /* SR-IOV Control */ -#define PCI_SRIOV_CTRL_VFE 0x01 /* VF Enable */ -#define PCI_SRIOV_CTRL_VFM 0x02 /* VF Migration Enable */ -#define PCI_SRIOV_CTRL_INTR 0x04 /* VF Migration Interrupt Enable */ -#define PCI_SRIOV_CTRL_MSE 0x08 /* VF Memory Space Enable */ -#define PCI_SRIOV_CTRL_ARI 0x10 /* ARI Capable Hierarchy */ -#define PCI_SRIOV_STATUS 0x0a /* SR-IOV Status */ -#define PCI_SRIOV_STATUS_VFM 0x01 /* VF Migration Status */ -#define PCI_SRIOV_INITIAL_VF 0x0c /* Initial VFs */ -#define PCI_SRIOV_TOTAL_VF 0x0e /* Total VFs */ -#define PCI_SRIOV_NUM_VF 0x10 /* Number of VFs */ -#define PCI_SRIOV_FUNC_LINK 0x12 /* Function Dependency Link */ -#define PCI_SRIOV_VF_OFFSET 0x14 /* First VF Offset */ -#define PCI_SRIOV_VF_STRIDE 0x16 /* Following VF Stride */ -#define PCI_SRIOV_VF_DID 0x1a /* VF Device ID */ -#define PCI_SRIOV_SUP_PGSIZE 0x1c /* Supported Page Sizes */ -#define PCI_SRIOV_SYS_PGSIZE 0x20 /* System Page Size */ -#define PCI_SRIOV_BAR 0x24 /* VF BAR0 */ -#define PCI_SRIOV_NUM_BARS 6 /* Number of VF BARs */ -#define PCI_SRIOV_VFM 0x3c /* VF Migration State Array Offset*/ -#define PCI_SRIOV_VFM_BIR(x) ((x) & 7) /* State BIR */ -#define PCI_SRIOV_VFM_OFFSET(x) ((x) & ~7) /* State Offset */ -#define PCI_SRIOV_VFM_UA 0x0 /* Inactive.Unavailable */ -#define PCI_SRIOV_VFM_MI 0x1 /* Dormant.MigrateIn */ -#define PCI_SRIOV_VFM_MO 0x2 /* Active.MigrateOut */ -#define PCI_SRIOV_VFM_AV 0x3 /* Active.Available */ -#define PCI_EXT_CAP_SRIOV_SIZEOF 64 - -#define PCI_LTR_MAX_SNOOP_LAT 0x4 -#define PCI_LTR_MAX_NOSNOOP_LAT 0x6 -#define PCI_LTR_VALUE_MASK 0x000003ff -#define PCI_LTR_SCALE_MASK 0x00001c00 -#define PCI_LTR_SCALE_SHIFT 10 -#define PCI_EXT_CAP_LTR_SIZEOF 8 - -/* Access Control Service */ -#define PCI_ACS_CAP 0x04 /* ACS Capability Register */ -#define PCI_ACS_SV 0x01 /* Source Validation */ -#define PCI_ACS_TB 0x02 /* Translation Blocking */ -#define PCI_ACS_RR 0x04 /* P2P Request Redirect */ -#define PCI_ACS_CR 0x08 /* P2P Completion Redirect */ -#define PCI_ACS_UF 0x10 /* Upstream Forwarding */ -#define PCI_ACS_EC 0x20 /* P2P Egress Control */ -#define PCI_ACS_DT 0x40 /* Direct Translated P2P */ -#define PCI_ACS_EGRESS_BITS 0x05 /* ACS Egress Control Vector Size */ -#define PCI_ACS_CTRL 0x06 /* ACS Control Register */ -#define PCI_ACS_EGRESS_CTL_V 0x08 /* ACS Egress Control Vector */ - -#define PCI_VSEC_HDR 4 /* extended cap - vendor-specific */ -#define PCI_VSEC_HDR_LEN_SHIFT 20 /* shift for length field */ - -/* SATA capability */ -#define PCI_SATA_REGS 4 /* SATA REGs specifier */ -#define PCI_SATA_REGS_MASK 0xF /* location - BAR#/inline */ -#define PCI_SATA_REGS_INLINE 0xF /* REGS in config space */ -#define PCI_SATA_SIZEOF_SHORT 8 -#define PCI_SATA_SIZEOF_LONG 16 - -/* Resizable BARs */ -#define PCI_REBAR_CTRL 8 /* control register */ -#define PCI_REBAR_CTRL_NBAR_MASK (7 << 5) /* mask for # bars */ -#define PCI_REBAR_CTRL_NBAR_SHIFT 5 /* shift for # bars */ - -/* Dynamic Power Allocation */ -#define PCI_DPA_CAP 4 /* capability register */ -#define PCI_DPA_CAP_SUBSTATE_MASK 0x1F /* # substates - 1 */ -#define PCI_DPA_BASE_SIZEOF 16 /* size with 0 substates */ - -/* TPH Requester */ -#define PCI_TPH_CAP 4 /* capability register */ -#define PCI_TPH_CAP_LOC_MASK 0x600 /* location mask */ -#define PCI_TPH_LOC_NONE 0x000 /* no location */ -#define PCI_TPH_LOC_CAP 0x200 /* in capability */ -#define PCI_TPH_LOC_MSIX 0x400 /* in MSI-X */ -#define PCI_TPH_CAP_ST_MASK 0x07FF0000 /* st table mask */ -#define PCI_TPH_CAP_ST_SHIFT 16 /* st table shift */ -#define PCI_TPH_BASE_SIZEOF 12 /* size with no st table */ - -/* Downstream Port Containment */ -#define PCI_EXP_DPC_CAP 4 /* DPC Capability */ -#define PCI_EXP_DPC_CAP_RP_EXT 0x20 /* Root Port Extensions for DPC */ -#define PCI_EXP_DPC_CAP_POISONED_TLP 0x40 /* Poisoned TLP Egress Blocking Supported */ -#define PCI_EXP_DPC_CAP_SW_TRIGGER 0x80 /* Software Triggering Supported */ -#define PCI_EXP_DPC_CAP_DL_ACTIVE 0x1000 /* ERR_COR signal on DL_Active supported */ - -#define PCI_EXP_DPC_CTL 6 /* DPC control */ -#define PCI_EXP_DPC_CTL_EN_NONFATAL 0x02 /* Enable trigger on ERR_NONFATAL message */ -#define PCI_EXP_DPC_CTL_INT_EN 0x08 /* DPC Interrupt Enable */ - -#define PCI_EXP_DPC_STATUS 8 /* DPC Status */ -#define PCI_EXP_DPC_STATUS_TRIGGER 0x01 /* Trigger Status */ -#define PCI_EXP_DPC_STATUS_INTERRUPT 0x08 /* Interrupt Status */ - -#define PCI_EXP_DPC_SOURCE_ID 10 /* DPC Source Identifier */ - -/* Precision Time Measurement */ -#define PCI_PTM_CAP 0x04 /* PTM Capability */ -#define PCI_PTM_CAP_REQ 0x00000001 /* Requester capable */ -#define PCI_PTM_CAP_ROOT 0x00000004 /* Root capable */ -#define PCI_PTM_GRANULARITY_MASK 0x0000FF00 /* Clock granularity */ -#define PCI_PTM_CTRL 0x08 /* PTM Control */ -#define PCI_PTM_CTRL_ENABLE 0x00000001 /* PTM enable */ -#define PCI_PTM_CTRL_ROOT 0x00000002 /* Root select */ - -#endif /* LINUX_PCI_REGS_H */ diff --git a/src/linux/include/uapi/linux/perf_event.h b/src/linux/include/uapi/linux/perf_event.h deleted file mode 100644 index c66a485..0000000 --- a/src/linux/include/uapi/linux/perf_event.h +++ /dev/null @@ -1,983 +0,0 @@ -/* - * Performance events: - * - * Copyright (C) 2008-2009, Thomas Gleixner - * Copyright (C) 2008-2011, Red Hat, Inc., Ingo Molnar - * Copyright (C) 2008-2011, Red Hat, Inc., Peter Zijlstra - * - * Data type definitions, declarations, prototypes. - * - * Started by: Thomas Gleixner and Ingo Molnar - * - * For licencing details see kernel-base/COPYING - */ -#ifndef _UAPI_LINUX_PERF_EVENT_H -#define _UAPI_LINUX_PERF_EVENT_H - -#include -#include -#include - -/* - * User-space ABI bits: - */ - -/* - * attr.type - */ -enum perf_type_id { - PERF_TYPE_HARDWARE = 0, - PERF_TYPE_SOFTWARE = 1, - PERF_TYPE_TRACEPOINT = 2, - PERF_TYPE_HW_CACHE = 3, - PERF_TYPE_RAW = 4, - PERF_TYPE_BREAKPOINT = 5, - - PERF_TYPE_MAX, /* non-ABI */ -}; - -/* - * Generalized performance event event_id types, used by the - * attr.event_id parameter of the sys_perf_event_open() - * syscall: - */ -enum perf_hw_id { - /* - * Common hardware events, generalized by the kernel: - */ - PERF_COUNT_HW_CPU_CYCLES = 0, - PERF_COUNT_HW_INSTRUCTIONS = 1, - PERF_COUNT_HW_CACHE_REFERENCES = 2, - PERF_COUNT_HW_CACHE_MISSES = 3, - PERF_COUNT_HW_BRANCH_INSTRUCTIONS = 4, - PERF_COUNT_HW_BRANCH_MISSES = 5, - PERF_COUNT_HW_BUS_CYCLES = 6, - PERF_COUNT_HW_STALLED_CYCLES_FRONTEND = 7, - PERF_COUNT_HW_STALLED_CYCLES_BACKEND = 8, - PERF_COUNT_HW_REF_CPU_CYCLES = 9, - - PERF_COUNT_HW_MAX, /* non-ABI */ -}; - -/* - * Generalized hardware cache events: - * - * { L1-D, L1-I, LLC, ITLB, DTLB, BPU, NODE } x - * { read, write, prefetch } x - * { accesses, misses } - */ -enum perf_hw_cache_id { - PERF_COUNT_HW_CACHE_L1D = 0, - PERF_COUNT_HW_CACHE_L1I = 1, - PERF_COUNT_HW_CACHE_LL = 2, - PERF_COUNT_HW_CACHE_DTLB = 3, - PERF_COUNT_HW_CACHE_ITLB = 4, - PERF_COUNT_HW_CACHE_BPU = 5, - PERF_COUNT_HW_CACHE_NODE = 6, - - PERF_COUNT_HW_CACHE_MAX, /* non-ABI */ -}; - -enum perf_hw_cache_op_id { - PERF_COUNT_HW_CACHE_OP_READ = 0, - PERF_COUNT_HW_CACHE_OP_WRITE = 1, - PERF_COUNT_HW_CACHE_OP_PREFETCH = 2, - - PERF_COUNT_HW_CACHE_OP_MAX, /* non-ABI */ -}; - -enum perf_hw_cache_op_result_id { - PERF_COUNT_HW_CACHE_RESULT_ACCESS = 0, - PERF_COUNT_HW_CACHE_RESULT_MISS = 1, - - PERF_COUNT_HW_CACHE_RESULT_MAX, /* non-ABI */ -}; - -/* - * Special "software" events provided by the kernel, even if the hardware - * does not support performance events. These events measure various - * physical and sw events of the kernel (and allow the profiling of them as - * well): - */ -enum perf_sw_ids { - PERF_COUNT_SW_CPU_CLOCK = 0, - PERF_COUNT_SW_TASK_CLOCK = 1, - PERF_COUNT_SW_PAGE_FAULTS = 2, - PERF_COUNT_SW_CONTEXT_SWITCHES = 3, - PERF_COUNT_SW_CPU_MIGRATIONS = 4, - PERF_COUNT_SW_PAGE_FAULTS_MIN = 5, - PERF_COUNT_SW_PAGE_FAULTS_MAJ = 6, - PERF_COUNT_SW_ALIGNMENT_FAULTS = 7, - PERF_COUNT_SW_EMULATION_FAULTS = 8, - PERF_COUNT_SW_DUMMY = 9, - PERF_COUNT_SW_BPF_OUTPUT = 10, - - PERF_COUNT_SW_MAX, /* non-ABI */ -}; - -/* - * Bits that can be set in attr.sample_type to request information - * in the overflow packets. - */ -enum perf_event_sample_format { - PERF_SAMPLE_IP = 1U << 0, - PERF_SAMPLE_TID = 1U << 1, - PERF_SAMPLE_TIME = 1U << 2, - PERF_SAMPLE_ADDR = 1U << 3, - PERF_SAMPLE_READ = 1U << 4, - PERF_SAMPLE_CALLCHAIN = 1U << 5, - PERF_SAMPLE_ID = 1U << 6, - PERF_SAMPLE_CPU = 1U << 7, - PERF_SAMPLE_PERIOD = 1U << 8, - PERF_SAMPLE_STREAM_ID = 1U << 9, - PERF_SAMPLE_RAW = 1U << 10, - PERF_SAMPLE_BRANCH_STACK = 1U << 11, - PERF_SAMPLE_REGS_USER = 1U << 12, - PERF_SAMPLE_STACK_USER = 1U << 13, - PERF_SAMPLE_WEIGHT = 1U << 14, - PERF_SAMPLE_DATA_SRC = 1U << 15, - PERF_SAMPLE_IDENTIFIER = 1U << 16, - PERF_SAMPLE_TRANSACTION = 1U << 17, - PERF_SAMPLE_REGS_INTR = 1U << 18, - - PERF_SAMPLE_MAX = 1U << 19, /* non-ABI */ -}; - -/* - * values to program into branch_sample_type when PERF_SAMPLE_BRANCH is set - * - * If the user does not pass priv level information via branch_sample_type, - * the kernel uses the event's priv level. Branch and event priv levels do - * not have to match. Branch priv level is checked for permissions. - * - * The branch types can be combined, however BRANCH_ANY covers all types - * of branches and therefore it supersedes all the other types. - */ -enum perf_branch_sample_type_shift { - PERF_SAMPLE_BRANCH_USER_SHIFT = 0, /* user branches */ - PERF_SAMPLE_BRANCH_KERNEL_SHIFT = 1, /* kernel branches */ - PERF_SAMPLE_BRANCH_HV_SHIFT = 2, /* hypervisor branches */ - - PERF_SAMPLE_BRANCH_ANY_SHIFT = 3, /* any branch types */ - PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT = 4, /* any call branch */ - PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT = 5, /* any return branch */ - PERF_SAMPLE_BRANCH_IND_CALL_SHIFT = 6, /* indirect calls */ - PERF_SAMPLE_BRANCH_ABORT_TX_SHIFT = 7, /* transaction aborts */ - PERF_SAMPLE_BRANCH_IN_TX_SHIFT = 8, /* in transaction */ - PERF_SAMPLE_BRANCH_NO_TX_SHIFT = 9, /* not in transaction */ - PERF_SAMPLE_BRANCH_COND_SHIFT = 10, /* conditional branches */ - - PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT = 11, /* call/ret stack */ - PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT = 12, /* indirect jumps */ - PERF_SAMPLE_BRANCH_CALL_SHIFT = 13, /* direct call */ - - PERF_SAMPLE_BRANCH_NO_FLAGS_SHIFT = 14, /* no flags */ - PERF_SAMPLE_BRANCH_NO_CYCLES_SHIFT = 15, /* no cycles */ - - PERF_SAMPLE_BRANCH_MAX_SHIFT /* non-ABI */ -}; - -enum perf_branch_sample_type { - PERF_SAMPLE_BRANCH_USER = 1U << PERF_SAMPLE_BRANCH_USER_SHIFT, - PERF_SAMPLE_BRANCH_KERNEL = 1U << PERF_SAMPLE_BRANCH_KERNEL_SHIFT, - PERF_SAMPLE_BRANCH_HV = 1U << PERF_SAMPLE_BRANCH_HV_SHIFT, - - PERF_SAMPLE_BRANCH_ANY = 1U << PERF_SAMPLE_BRANCH_ANY_SHIFT, - PERF_SAMPLE_BRANCH_ANY_CALL = 1U << PERF_SAMPLE_BRANCH_ANY_CALL_SHIFT, - PERF_SAMPLE_BRANCH_ANY_RETURN = 1U << PERF_SAMPLE_BRANCH_ANY_RETURN_SHIFT, - PERF_SAMPLE_BRANCH_IND_CALL = 1U << PERF_SAMPLE_BRANCH_IND_CALL_SHIFT, - PERF_SAMPLE_BRANCH_ABORT_TX = 1U << PERF_SAMPLE_BRANCH_ABORT_TX_SHIFT, - PERF_SAMPLE_BRANCH_IN_TX = 1U << PERF_SAMPLE_BRANCH_IN_TX_SHIFT, - PERF_SAMPLE_BRANCH_NO_TX = 1U << PERF_SAMPLE_BRANCH_NO_TX_SHIFT, - PERF_SAMPLE_BRANCH_COND = 1U << PERF_SAMPLE_BRANCH_COND_SHIFT, - - PERF_SAMPLE_BRANCH_CALL_STACK = 1U << PERF_SAMPLE_BRANCH_CALL_STACK_SHIFT, - PERF_SAMPLE_BRANCH_IND_JUMP = 1U << PERF_SAMPLE_BRANCH_IND_JUMP_SHIFT, - PERF_SAMPLE_BRANCH_CALL = 1U << PERF_SAMPLE_BRANCH_CALL_SHIFT, - - PERF_SAMPLE_BRANCH_NO_FLAGS = 1U << PERF_SAMPLE_BRANCH_NO_FLAGS_SHIFT, - PERF_SAMPLE_BRANCH_NO_CYCLES = 1U << PERF_SAMPLE_BRANCH_NO_CYCLES_SHIFT, - - PERF_SAMPLE_BRANCH_MAX = 1U << PERF_SAMPLE_BRANCH_MAX_SHIFT, -}; - -#define PERF_SAMPLE_BRANCH_PLM_ALL \ - (PERF_SAMPLE_BRANCH_USER|\ - PERF_SAMPLE_BRANCH_KERNEL|\ - PERF_SAMPLE_BRANCH_HV) - -/* - * Values to determine ABI of the registers dump. - */ -enum perf_sample_regs_abi { - PERF_SAMPLE_REGS_ABI_NONE = 0, - PERF_SAMPLE_REGS_ABI_32 = 1, - PERF_SAMPLE_REGS_ABI_64 = 2, -}; - -/* - * Values for the memory transaction event qualifier, mostly for - * abort events. Multiple bits can be set. - */ -enum { - PERF_TXN_ELISION = (1 << 0), /* From elision */ - PERF_TXN_TRANSACTION = (1 << 1), /* From transaction */ - PERF_TXN_SYNC = (1 << 2), /* Instruction is related */ - PERF_TXN_ASYNC = (1 << 3), /* Instruction not related */ - PERF_TXN_RETRY = (1 << 4), /* Retry possible */ - PERF_TXN_CONFLICT = (1 << 5), /* Conflict abort */ - PERF_TXN_CAPACITY_WRITE = (1 << 6), /* Capacity write abort */ - PERF_TXN_CAPACITY_READ = (1 << 7), /* Capacity read abort */ - - PERF_TXN_MAX = (1 << 8), /* non-ABI */ - - /* bits 32..63 are reserved for the abort code */ - - PERF_TXN_ABORT_MASK = (0xffffffffULL << 32), - PERF_TXN_ABORT_SHIFT = 32, -}; - -/* - * The format of the data returned by read() on a perf event fd, - * as specified by attr.read_format: - * - * struct read_format { - * { u64 value; - * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED - * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING - * { u64 id; } && PERF_FORMAT_ID - * } && !PERF_FORMAT_GROUP - * - * { u64 nr; - * { u64 time_enabled; } && PERF_FORMAT_TOTAL_TIME_ENABLED - * { u64 time_running; } && PERF_FORMAT_TOTAL_TIME_RUNNING - * { u64 value; - * { u64 id; } && PERF_FORMAT_ID - * } cntr[nr]; - * } && PERF_FORMAT_GROUP - * }; - */ -enum perf_event_read_format { - PERF_FORMAT_TOTAL_TIME_ENABLED = 1U << 0, - PERF_FORMAT_TOTAL_TIME_RUNNING = 1U << 1, - PERF_FORMAT_ID = 1U << 2, - PERF_FORMAT_GROUP = 1U << 3, - - PERF_FORMAT_MAX = 1U << 4, /* non-ABI */ -}; - -#define PERF_ATTR_SIZE_VER0 64 /* sizeof first published struct */ -#define PERF_ATTR_SIZE_VER1 72 /* add: config2 */ -#define PERF_ATTR_SIZE_VER2 80 /* add: branch_sample_type */ -#define PERF_ATTR_SIZE_VER3 96 /* add: sample_regs_user */ - /* add: sample_stack_user */ -#define PERF_ATTR_SIZE_VER4 104 /* add: sample_regs_intr */ -#define PERF_ATTR_SIZE_VER5 112 /* add: aux_watermark */ - -/* - * Hardware event_id to monitor via a performance monitoring event: - * - * @sample_max_stack: Max number of frame pointers in a callchain, - * should be < /proc/sys/kernel/perf_event_max_stack - */ -struct perf_event_attr { - - /* - * Major type: hardware/software/tracepoint/etc. - */ - __u32 type; - - /* - * Size of the attr structure, for fwd/bwd compat. - */ - __u32 size; - - /* - * Type specific configuration information. - */ - __u64 config; - - union { - __u64 sample_period; - __u64 sample_freq; - }; - - __u64 sample_type; - __u64 read_format; - - __u64 disabled : 1, /* off by default */ - inherit : 1, /* children inherit it */ - pinned : 1, /* must always be on PMU */ - exclusive : 1, /* only group on PMU */ - exclude_user : 1, /* don't count user */ - exclude_kernel : 1, /* ditto kernel */ - exclude_hv : 1, /* ditto hypervisor */ - exclude_idle : 1, /* don't count when idle */ - mmap : 1, /* include mmap data */ - comm : 1, /* include comm data */ - freq : 1, /* use freq, not period */ - inherit_stat : 1, /* per task counts */ - enable_on_exec : 1, /* next exec enables */ - task : 1, /* trace fork/exit */ - watermark : 1, /* wakeup_watermark */ - /* - * precise_ip: - * - * 0 - SAMPLE_IP can have arbitrary skid - * 1 - SAMPLE_IP must have constant skid - * 2 - SAMPLE_IP requested to have 0 skid - * 3 - SAMPLE_IP must have 0 skid - * - * See also PERF_RECORD_MISC_EXACT_IP - */ - precise_ip : 2, /* skid constraint */ - mmap_data : 1, /* non-exec mmap data */ - sample_id_all : 1, /* sample_type all events */ - - exclude_host : 1, /* don't count in host */ - exclude_guest : 1, /* don't count in guest */ - - exclude_callchain_kernel : 1, /* exclude kernel callchains */ - exclude_callchain_user : 1, /* exclude user callchains */ - mmap2 : 1, /* include mmap with inode data */ - comm_exec : 1, /* flag comm events that are due to an exec */ - use_clockid : 1, /* use @clockid for time fields */ - context_switch : 1, /* context switch data */ - write_backward : 1, /* Write ring buffer from end to beginning */ - __reserved_1 : 36; - - union { - __u32 wakeup_events; /* wakeup every n events */ - __u32 wakeup_watermark; /* bytes before wakeup */ - }; - - __u32 bp_type; - union { - __u64 bp_addr; - __u64 config1; /* extension of config */ - }; - union { - __u64 bp_len; - __u64 config2; /* extension of config1 */ - }; - __u64 branch_sample_type; /* enum perf_branch_sample_type */ - - /* - * Defines set of user regs to dump on samples. - * See asm/perf_regs.h for details. - */ - __u64 sample_regs_user; - - /* - * Defines size of the user stack to dump on samples. - */ - __u32 sample_stack_user; - - __s32 clockid; - /* - * Defines set of regs to dump for each sample - * state captured on: - * - precise = 0: PMU interrupt - * - precise > 0: sampled instruction - * - * See asm/perf_regs.h for details. - */ - __u64 sample_regs_intr; - - /* - * Wakeup watermark for AUX area - */ - __u32 aux_watermark; - __u16 sample_max_stack; - __u16 __reserved_2; /* align to __u64 */ -}; - -#define perf_flags(attr) (*(&(attr)->read_format + 1)) - -/* - * Ioctls that can be done on a perf event fd: - */ -#define PERF_EVENT_IOC_ENABLE _IO ('$', 0) -#define PERF_EVENT_IOC_DISABLE _IO ('$', 1) -#define PERF_EVENT_IOC_REFRESH _IO ('$', 2) -#define PERF_EVENT_IOC_RESET _IO ('$', 3) -#define PERF_EVENT_IOC_PERIOD _IOW('$', 4, __u64) -#define PERF_EVENT_IOC_SET_OUTPUT _IO ('$', 5) -#define PERF_EVENT_IOC_SET_FILTER _IOW('$', 6, char *) -#define PERF_EVENT_IOC_ID _IOR('$', 7, __u64 *) -#define PERF_EVENT_IOC_SET_BPF _IOW('$', 8, __u32) -#define PERF_EVENT_IOC_PAUSE_OUTPUT _IOW('$', 9, __u32) - -enum perf_event_ioc_flags { - PERF_IOC_FLAG_GROUP = 1U << 0, -}; - -/* - * Structure of the page that can be mapped via mmap - */ -struct perf_event_mmap_page { - __u32 version; /* version number of this structure */ - __u32 compat_version; /* lowest version this is compat with */ - - /* - * Bits needed to read the hw events in user-space. - * - * u32 seq, time_mult, time_shift, index, width; - * u64 count, enabled, running; - * u64 cyc, time_offset; - * s64 pmc = 0; - * - * do { - * seq = pc->lock; - * barrier() - * - * enabled = pc->time_enabled; - * running = pc->time_running; - * - * if (pc->cap_usr_time && enabled != running) { - * cyc = rdtsc(); - * time_offset = pc->time_offset; - * time_mult = pc->time_mult; - * time_shift = pc->time_shift; - * } - * - * index = pc->index; - * count = pc->offset; - * if (pc->cap_user_rdpmc && index) { - * width = pc->pmc_width; - * pmc = rdpmc(index - 1); - * } - * - * barrier(); - * } while (pc->lock != seq); - * - * NOTE: for obvious reason this only works on self-monitoring - * processes. - */ - __u32 lock; /* seqlock for synchronization */ - __u32 index; /* hardware event identifier */ - __s64 offset; /* add to hardware event value */ - __u64 time_enabled; /* time event active */ - __u64 time_running; /* time event on cpu */ - union { - __u64 capabilities; - struct { - __u64 cap_bit0 : 1, /* Always 0, deprecated, see commit 860f085b74e9 */ - cap_bit0_is_deprecated : 1, /* Always 1, signals that bit 0 is zero */ - - cap_user_rdpmc : 1, /* The RDPMC instruction can be used to read counts */ - cap_user_time : 1, /* The time_* fields are used */ - cap_user_time_zero : 1, /* The time_zero field is used */ - cap_____res : 59; - }; - }; - - /* - * If cap_user_rdpmc this field provides the bit-width of the value - * read using the rdpmc() or equivalent instruction. This can be used - * to sign extend the result like: - * - * pmc <<= 64 - width; - * pmc >>= 64 - width; // signed shift right - * count += pmc; - */ - __u16 pmc_width; - - /* - * If cap_usr_time the below fields can be used to compute the time - * delta since time_enabled (in ns) using rdtsc or similar. - * - * u64 quot, rem; - * u64 delta; - * - * quot = (cyc >> time_shift); - * rem = cyc & (((u64)1 << time_shift) - 1); - * delta = time_offset + quot * time_mult + - * ((rem * time_mult) >> time_shift); - * - * Where time_offset,time_mult,time_shift and cyc are read in the - * seqcount loop described above. This delta can then be added to - * enabled and possible running (if index), improving the scaling: - * - * enabled += delta; - * if (index) - * running += delta; - * - * quot = count / running; - * rem = count % running; - * count = quot * enabled + (rem * enabled) / running; - */ - __u16 time_shift; - __u32 time_mult; - __u64 time_offset; - /* - * If cap_usr_time_zero, the hardware clock (e.g. TSC) can be calculated - * from sample timestamps. - * - * time = timestamp - time_zero; - * quot = time / time_mult; - * rem = time % time_mult; - * cyc = (quot << time_shift) + (rem << time_shift) / time_mult; - * - * And vice versa: - * - * quot = cyc >> time_shift; - * rem = cyc & (((u64)1 << time_shift) - 1); - * timestamp = time_zero + quot * time_mult + - * ((rem * time_mult) >> time_shift); - */ - __u64 time_zero; - __u32 size; /* Header size up to __reserved[] fields. */ - - /* - * Hole for extension of the self monitor capabilities - */ - - __u8 __reserved[118*8+4]; /* align to 1k. */ - - /* - * Control data for the mmap() data buffer. - * - * User-space reading the @data_head value should issue an smp_rmb(), - * after reading this value. - * - * When the mapping is PROT_WRITE the @data_tail value should be - * written by userspace to reflect the last read data, after issueing - * an smp_mb() to separate the data read from the ->data_tail store. - * In this case the kernel will not over-write unread data. - * - * See perf_output_put_handle() for the data ordering. - * - * data_{offset,size} indicate the location and size of the perf record - * buffer within the mmapped area. - */ - __u64 data_head; /* head in the data section */ - __u64 data_tail; /* user-space written tail */ - __u64 data_offset; /* where the buffer starts */ - __u64 data_size; /* data buffer size */ - - /* - * AUX area is defined by aux_{offset,size} fields that should be set - * by the userspace, so that - * - * aux_offset >= data_offset + data_size - * - * prior to mmap()ing it. Size of the mmap()ed area should be aux_size. - * - * Ring buffer pointers aux_{head,tail} have the same semantics as - * data_{head,tail} and same ordering rules apply. - */ - __u64 aux_head; - __u64 aux_tail; - __u64 aux_offset; - __u64 aux_size; -}; - -#define PERF_RECORD_MISC_CPUMODE_MASK (7 << 0) -#define PERF_RECORD_MISC_CPUMODE_UNKNOWN (0 << 0) -#define PERF_RECORD_MISC_KERNEL (1 << 0) -#define PERF_RECORD_MISC_USER (2 << 0) -#define PERF_RECORD_MISC_HYPERVISOR (3 << 0) -#define PERF_RECORD_MISC_GUEST_KERNEL (4 << 0) -#define PERF_RECORD_MISC_GUEST_USER (5 << 0) - -/* - * Indicates that /proc/PID/maps parsing are truncated by time out. - */ -#define PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT (1 << 12) -/* - * PERF_RECORD_MISC_MMAP_DATA and PERF_RECORD_MISC_COMM_EXEC are used on - * different events so can reuse the same bit position. - * Ditto PERF_RECORD_MISC_SWITCH_OUT. - */ -#define PERF_RECORD_MISC_MMAP_DATA (1 << 13) -#define PERF_RECORD_MISC_COMM_EXEC (1 << 13) -#define PERF_RECORD_MISC_SWITCH_OUT (1 << 13) -/* - * Indicates that the content of PERF_SAMPLE_IP points to - * the actual instruction that triggered the event. See also - * perf_event_attr::precise_ip. - */ -#define PERF_RECORD_MISC_EXACT_IP (1 << 14) -/* - * Reserve the last bit to indicate some extended misc field - */ -#define PERF_RECORD_MISC_EXT_RESERVED (1 << 15) - -struct perf_event_header { - __u32 type; - __u16 misc; - __u16 size; -}; - -enum perf_event_type { - - /* - * If perf_event_attr.sample_id_all is set then all event types will - * have the sample_type selected fields related to where/when - * (identity) an event took place (TID, TIME, ID, STREAM_ID, CPU, - * IDENTIFIER) described in PERF_RECORD_SAMPLE below, it will be stashed - * just after the perf_event_header and the fields already present for - * the existing fields, i.e. at the end of the payload. That way a newer - * perf.data file will be supported by older perf tools, with these new - * optional fields being ignored. - * - * struct sample_id { - * { u32 pid, tid; } && PERF_SAMPLE_TID - * { u64 time; } && PERF_SAMPLE_TIME - * { u64 id; } && PERF_SAMPLE_ID - * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID - * { u32 cpu, res; } && PERF_SAMPLE_CPU - * { u64 id; } && PERF_SAMPLE_IDENTIFIER - * } && perf_event_attr::sample_id_all - * - * Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. The - * advantage of PERF_SAMPLE_IDENTIFIER is that its position is fixed - * relative to header.size. - */ - - /* - * The MMAP events record the PROT_EXEC mappings so that we can - * correlate userspace IPs to code. They have the following structure: - * - * struct { - * struct perf_event_header header; - * - * u32 pid, tid; - * u64 addr; - * u64 len; - * u64 pgoff; - * char filename[]; - * struct sample_id sample_id; - * }; - */ - PERF_RECORD_MMAP = 1, - - /* - * struct { - * struct perf_event_header header; - * u64 id; - * u64 lost; - * struct sample_id sample_id; - * }; - */ - PERF_RECORD_LOST = 2, - - /* - * struct { - * struct perf_event_header header; - * - * u32 pid, tid; - * char comm[]; - * struct sample_id sample_id; - * }; - */ - PERF_RECORD_COMM = 3, - - /* - * struct { - * struct perf_event_header header; - * u32 pid, ppid; - * u32 tid, ptid; - * u64 time; - * struct sample_id sample_id; - * }; - */ - PERF_RECORD_EXIT = 4, - - /* - * struct { - * struct perf_event_header header; - * u64 time; - * u64 id; - * u64 stream_id; - * struct sample_id sample_id; - * }; - */ - PERF_RECORD_THROTTLE = 5, - PERF_RECORD_UNTHROTTLE = 6, - - /* - * struct { - * struct perf_event_header header; - * u32 pid, ppid; - * u32 tid, ptid; - * u64 time; - * struct sample_id sample_id; - * }; - */ - PERF_RECORD_FORK = 7, - - /* - * struct { - * struct perf_event_header header; - * u32 pid, tid; - * - * struct read_format values; - * struct sample_id sample_id; - * }; - */ - PERF_RECORD_READ = 8, - - /* - * struct { - * struct perf_event_header header; - * - * # - * # Note that PERF_SAMPLE_IDENTIFIER duplicates PERF_SAMPLE_ID. - * # The advantage of PERF_SAMPLE_IDENTIFIER is that its position - * # is fixed relative to header. - * # - * - * { u64 id; } && PERF_SAMPLE_IDENTIFIER - * { u64 ip; } && PERF_SAMPLE_IP - * { u32 pid, tid; } && PERF_SAMPLE_TID - * { u64 time; } && PERF_SAMPLE_TIME - * { u64 addr; } && PERF_SAMPLE_ADDR - * { u64 id; } && PERF_SAMPLE_ID - * { u64 stream_id;} && PERF_SAMPLE_STREAM_ID - * { u32 cpu, res; } && PERF_SAMPLE_CPU - * { u64 period; } && PERF_SAMPLE_PERIOD - * - * { struct read_format values; } && PERF_SAMPLE_READ - * - * { u64 nr, - * u64 ips[nr]; } && PERF_SAMPLE_CALLCHAIN - * - * # - * # The RAW record below is opaque data wrt the ABI - * # - * # That is, the ABI doesn't make any promises wrt to - * # the stability of its content, it may vary depending - * # on event, hardware, kernel version and phase of - * # the moon. - * # - * # In other words, PERF_SAMPLE_RAW contents are not an ABI. - * # - * - * { u32 size; - * char data[size];}&& PERF_SAMPLE_RAW - * - * { u64 nr; - * { u64 from, to, flags } lbr[nr];} && PERF_SAMPLE_BRANCH_STACK - * - * { u64 abi; # enum perf_sample_regs_abi - * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_USER - * - * { u64 size; - * char data[size]; - * u64 dyn_size; } && PERF_SAMPLE_STACK_USER - * - * { u64 weight; } && PERF_SAMPLE_WEIGHT - * { u64 data_src; } && PERF_SAMPLE_DATA_SRC - * { u64 transaction; } && PERF_SAMPLE_TRANSACTION - * { u64 abi; # enum perf_sample_regs_abi - * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_INTR - * }; - */ - PERF_RECORD_SAMPLE = 9, - - /* - * The MMAP2 records are an augmented version of MMAP, they add - * maj, min, ino numbers to be used to uniquely identify each mapping - * - * struct { - * struct perf_event_header header; - * - * u32 pid, tid; - * u64 addr; - * u64 len; - * u64 pgoff; - * u32 maj; - * u32 min; - * u64 ino; - * u64 ino_generation; - * u32 prot, flags; - * char filename[]; - * struct sample_id sample_id; - * }; - */ - PERF_RECORD_MMAP2 = 10, - - /* - * Records that new data landed in the AUX buffer part. - * - * struct { - * struct perf_event_header header; - * - * u64 aux_offset; - * u64 aux_size; - * u64 flags; - * struct sample_id sample_id; - * }; - */ - PERF_RECORD_AUX = 11, - - /* - * Indicates that instruction trace has started - * - * struct { - * struct perf_event_header header; - * u32 pid; - * u32 tid; - * }; - */ - PERF_RECORD_ITRACE_START = 12, - - /* - * Records the dropped/lost sample number. - * - * struct { - * struct perf_event_header header; - * - * u64 lost; - * struct sample_id sample_id; - * }; - */ - PERF_RECORD_LOST_SAMPLES = 13, - - /* - * Records a context switch in or out (flagged by - * PERF_RECORD_MISC_SWITCH_OUT). See also - * PERF_RECORD_SWITCH_CPU_WIDE. - * - * struct { - * struct perf_event_header header; - * struct sample_id sample_id; - * }; - */ - PERF_RECORD_SWITCH = 14, - - /* - * CPU-wide version of PERF_RECORD_SWITCH with next_prev_pid and - * next_prev_tid that are the next (switching out) or previous - * (switching in) pid/tid. - * - * struct { - * struct perf_event_header header; - * u32 next_prev_pid; - * u32 next_prev_tid; - * struct sample_id sample_id; - * }; - */ - PERF_RECORD_SWITCH_CPU_WIDE = 15, - - PERF_RECORD_MAX, /* non-ABI */ -}; - -#define PERF_MAX_STACK_DEPTH 127 -#define PERF_MAX_CONTEXTS_PER_STACK 8 - -enum perf_callchain_context { - PERF_CONTEXT_HV = (__u64)-32, - PERF_CONTEXT_KERNEL = (__u64)-128, - PERF_CONTEXT_USER = (__u64)-512, - - PERF_CONTEXT_GUEST = (__u64)-2048, - PERF_CONTEXT_GUEST_KERNEL = (__u64)-2176, - PERF_CONTEXT_GUEST_USER = (__u64)-2560, - - PERF_CONTEXT_MAX = (__u64)-4095, -}; - -/** - * PERF_RECORD_AUX::flags bits - */ -#define PERF_AUX_FLAG_TRUNCATED 0x01 /* record was truncated to fit */ -#define PERF_AUX_FLAG_OVERWRITE 0x02 /* snapshot from overwrite mode */ - -#define PERF_FLAG_FD_NO_GROUP (1UL << 0) -#define PERF_FLAG_FD_OUTPUT (1UL << 1) -#define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */ -#define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */ - -union perf_mem_data_src { - __u64 val; - struct { - __u64 mem_op:5, /* type of opcode */ - mem_lvl:14, /* memory hierarchy level */ - mem_snoop:5, /* snoop mode */ - mem_lock:2, /* lock instr */ - mem_dtlb:7, /* tlb access */ - mem_rsvd:31; - }; -}; - -/* type of opcode (load/store/prefetch,code) */ -#define PERF_MEM_OP_NA 0x01 /* not available */ -#define PERF_MEM_OP_LOAD 0x02 /* load instruction */ -#define PERF_MEM_OP_STORE 0x04 /* store instruction */ -#define PERF_MEM_OP_PFETCH 0x08 /* prefetch */ -#define PERF_MEM_OP_EXEC 0x10 /* code (execution) */ -#define PERF_MEM_OP_SHIFT 0 - -/* memory hierarchy (memory level, hit or miss) */ -#define PERF_MEM_LVL_NA 0x01 /* not available */ -#define PERF_MEM_LVL_HIT 0x02 /* hit level */ -#define PERF_MEM_LVL_MISS 0x04 /* miss level */ -#define PERF_MEM_LVL_L1 0x08 /* L1 */ -#define PERF_MEM_LVL_LFB 0x10 /* Line Fill Buffer */ -#define PERF_MEM_LVL_L2 0x20 /* L2 */ -#define PERF_MEM_LVL_L3 0x40 /* L3 */ -#define PERF_MEM_LVL_LOC_RAM 0x80 /* Local DRAM */ -#define PERF_MEM_LVL_REM_RAM1 0x100 /* Remote DRAM (1 hop) */ -#define PERF_MEM_LVL_REM_RAM2 0x200 /* Remote DRAM (2 hops) */ -#define PERF_MEM_LVL_REM_CCE1 0x400 /* Remote Cache (1 hop) */ -#define PERF_MEM_LVL_REM_CCE2 0x800 /* Remote Cache (2 hops) */ -#define PERF_MEM_LVL_IO 0x1000 /* I/O memory */ -#define PERF_MEM_LVL_UNC 0x2000 /* Uncached memory */ -#define PERF_MEM_LVL_SHIFT 5 - -/* snoop mode */ -#define PERF_MEM_SNOOP_NA 0x01 /* not available */ -#define PERF_MEM_SNOOP_NONE 0x02 /* no snoop */ -#define PERF_MEM_SNOOP_HIT 0x04 /* snoop hit */ -#define PERF_MEM_SNOOP_MISS 0x08 /* snoop miss */ -#define PERF_MEM_SNOOP_HITM 0x10 /* snoop hit modified */ -#define PERF_MEM_SNOOP_SHIFT 19 - -/* locked instruction */ -#define PERF_MEM_LOCK_NA 0x01 /* not available */ -#define PERF_MEM_LOCK_LOCKED 0x02 /* locked transaction */ -#define PERF_MEM_LOCK_SHIFT 24 - -/* TLB access */ -#define PERF_MEM_TLB_NA 0x01 /* not available */ -#define PERF_MEM_TLB_HIT 0x02 /* hit level */ -#define PERF_MEM_TLB_MISS 0x04 /* miss level */ -#define PERF_MEM_TLB_L1 0x08 /* L1 */ -#define PERF_MEM_TLB_L2 0x10 /* L2 */ -#define PERF_MEM_TLB_WK 0x20 /* Hardware Walker*/ -#define PERF_MEM_TLB_OS 0x40 /* OS fault handler */ -#define PERF_MEM_TLB_SHIFT 26 - -#define PERF_MEM_S(a, s) \ - (((__u64)PERF_MEM_##a##_##s) << PERF_MEM_##a##_SHIFT) - -/* - * single taken branch record layout: - * - * from: source instruction (may not always be a branch insn) - * to: branch target - * mispred: branch target was mispredicted - * predicted: branch target was predicted - * - * support for mispred, predicted is optional. In case it - * is not supported mispred = predicted = 0. - * - * in_tx: running in a hardware transaction - * abort: aborting a hardware transaction - * cycles: cycles from last branch (or 0 if not supported) - */ -struct perf_branch_entry { - __u64 from; - __u64 to; - __u64 mispred:1, /* target mispredicted */ - predicted:1,/* target predicted */ - in_tx:1, /* in transaction */ - abort:1, /* transaction abort */ - cycles:16, /* cycle count to last branch */ - reserved:44; -}; - -#endif /* _UAPI_LINUX_PERF_EVENT_H */ diff --git a/src/linux/include/uapi/linux/personality.h b/src/linux/include/uapi/linux/personality.h deleted file mode 100644 index aa169c4..0000000 --- a/src/linux/include/uapi/linux/personality.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef _UAPI_LINUX_PERSONALITY_H -#define _UAPI_LINUX_PERSONALITY_H - - -/* - * Flags for bug emulation. - * - * These occupy the top three bytes. - */ -enum { - UNAME26 = 0x0020000, - ADDR_NO_RANDOMIZE = 0x0040000, /* disable randomization of VA space */ - FDPIC_FUNCPTRS = 0x0080000, /* userspace function ptrs point to descriptors - * (signal handling) - */ - MMAP_PAGE_ZERO = 0x0100000, - ADDR_COMPAT_LAYOUT = 0x0200000, - READ_IMPLIES_EXEC = 0x0400000, - ADDR_LIMIT_32BIT = 0x0800000, - SHORT_INODE = 0x1000000, - WHOLE_SECONDS = 0x2000000, - STICKY_TIMEOUTS = 0x4000000, - ADDR_LIMIT_3GB = 0x8000000, -}; - -/* - * Security-relevant compatibility flags that must be - * cleared upon setuid or setgid exec: - */ -#define PER_CLEAR_ON_SETID (READ_IMPLIES_EXEC | \ - ADDR_NO_RANDOMIZE | \ - ADDR_COMPAT_LAYOUT | \ - MMAP_PAGE_ZERO) - -/* - * Personality types. - * - * These go in the low byte. Avoid using the top bit, it will - * conflict with error returns. - */ -enum { - PER_LINUX = 0x0000, - PER_LINUX_32BIT = 0x0000 | ADDR_LIMIT_32BIT, - PER_LINUX_FDPIC = 0x0000 | FDPIC_FUNCPTRS, - PER_SVR4 = 0x0001 | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, - PER_SVR3 = 0x0002 | STICKY_TIMEOUTS | SHORT_INODE, - PER_SCOSVR3 = 0x0003 | STICKY_TIMEOUTS | - WHOLE_SECONDS | SHORT_INODE, - PER_OSR5 = 0x0003 | STICKY_TIMEOUTS | WHOLE_SECONDS, - PER_WYSEV386 = 0x0004 | STICKY_TIMEOUTS | SHORT_INODE, - PER_ISCR4 = 0x0005 | STICKY_TIMEOUTS, - PER_BSD = 0x0006, - PER_SUNOS = 0x0006 | STICKY_TIMEOUTS, - PER_XENIX = 0x0007 | STICKY_TIMEOUTS | SHORT_INODE, - PER_LINUX32 = 0x0008, - PER_LINUX32_3GB = 0x0008 | ADDR_LIMIT_3GB, - PER_IRIX32 = 0x0009 | STICKY_TIMEOUTS,/* IRIX5 32-bit */ - PER_IRIXN32 = 0x000a | STICKY_TIMEOUTS,/* IRIX6 new 32-bit */ - PER_IRIX64 = 0x000b | STICKY_TIMEOUTS,/* IRIX6 64-bit */ - PER_RISCOS = 0x000c, - PER_SOLARIS = 0x000d | STICKY_TIMEOUTS, - PER_UW7 = 0x000e | STICKY_TIMEOUTS | MMAP_PAGE_ZERO, - PER_OSF4 = 0x000f, /* OSF/1 v4 */ - PER_HPUX = 0x0010, - PER_MASK = 0x00ff, -}; - - -#endif /* _UAPI_LINUX_PERSONALITY_H */ diff --git a/src/linux/include/uapi/linux/pfkeyv2.h b/src/linux/include/uapi/linux/pfkeyv2.h deleted file mode 100644 index ada7f01..0000000 --- a/src/linux/include/uapi/linux/pfkeyv2.h +++ /dev/null @@ -1,383 +0,0 @@ -/* PF_KEY user interface, this is defined by rfc2367 so - * do not make arbitrary modifications or else this header - * file will not be compliant. - */ - -#ifndef _LINUX_PFKEY2_H -#define _LINUX_PFKEY2_H - -#include - -#define PF_KEY_V2 2 -#define PFKEYV2_REVISION 199806L - -struct sadb_msg { - __u8 sadb_msg_version; - __u8 sadb_msg_type; - __u8 sadb_msg_errno; - __u8 sadb_msg_satype; - __u16 sadb_msg_len; - __u16 sadb_msg_reserved; - __u32 sadb_msg_seq; - __u32 sadb_msg_pid; -} __attribute__((packed)); -/* sizeof(struct sadb_msg) == 16 */ - -struct sadb_ext { - __u16 sadb_ext_len; - __u16 sadb_ext_type; -} __attribute__((packed)); -/* sizeof(struct sadb_ext) == 4 */ - -struct sadb_sa { - __u16 sadb_sa_len; - __u16 sadb_sa_exttype; - __be32 sadb_sa_spi; - __u8 sadb_sa_replay; - __u8 sadb_sa_state; - __u8 sadb_sa_auth; - __u8 sadb_sa_encrypt; - __u32 sadb_sa_flags; -} __attribute__((packed)); -/* sizeof(struct sadb_sa) == 16 */ - -struct sadb_lifetime { - __u16 sadb_lifetime_len; - __u16 sadb_lifetime_exttype; - __u32 sadb_lifetime_allocations; - __u64 sadb_lifetime_bytes; - __u64 sadb_lifetime_addtime; - __u64 sadb_lifetime_usetime; -} __attribute__((packed)); -/* sizeof(struct sadb_lifetime) == 32 */ - -struct sadb_address { - __u16 sadb_address_len; - __u16 sadb_address_exttype; - __u8 sadb_address_proto; - __u8 sadb_address_prefixlen; - __u16 sadb_address_reserved; -} __attribute__((packed)); -/* sizeof(struct sadb_address) == 8 */ - -struct sadb_key { - __u16 sadb_key_len; - __u16 sadb_key_exttype; - __u16 sadb_key_bits; - __u16 sadb_key_reserved; -} __attribute__((packed)); -/* sizeof(struct sadb_key) == 8 */ - -struct sadb_ident { - __u16 sadb_ident_len; - __u16 sadb_ident_exttype; - __u16 sadb_ident_type; - __u16 sadb_ident_reserved; - __u64 sadb_ident_id; -} __attribute__((packed)); -/* sizeof(struct sadb_ident) == 16 */ - -struct sadb_sens { - __u16 sadb_sens_len; - __u16 sadb_sens_exttype; - __u32 sadb_sens_dpd; - __u8 sadb_sens_sens_level; - __u8 sadb_sens_sens_len; - __u8 sadb_sens_integ_level; - __u8 sadb_sens_integ_len; - __u32 sadb_sens_reserved; -} __attribute__((packed)); -/* sizeof(struct sadb_sens) == 16 */ - -/* followed by: - __u64 sadb_sens_bitmap[sens_len]; - __u64 sadb_integ_bitmap[integ_len]; */ - -struct sadb_prop { - __u16 sadb_prop_len; - __u16 sadb_prop_exttype; - __u8 sadb_prop_replay; - __u8 sadb_prop_reserved[3]; -} __attribute__((packed)); -/* sizeof(struct sadb_prop) == 8 */ - -/* followed by: - struct sadb_comb sadb_combs[(sadb_prop_len + - sizeof(__u64) - sizeof(struct sadb_prop)) / - sizeof(struct sadb_comb)]; */ - -struct sadb_comb { - __u8 sadb_comb_auth; - __u8 sadb_comb_encrypt; - __u16 sadb_comb_flags; - __u16 sadb_comb_auth_minbits; - __u16 sadb_comb_auth_maxbits; - __u16 sadb_comb_encrypt_minbits; - __u16 sadb_comb_encrypt_maxbits; - __u32 sadb_comb_reserved; - __u32 sadb_comb_soft_allocations; - __u32 sadb_comb_hard_allocations; - __u64 sadb_comb_soft_bytes; - __u64 sadb_comb_hard_bytes; - __u64 sadb_comb_soft_addtime; - __u64 sadb_comb_hard_addtime; - __u64 sadb_comb_soft_usetime; - __u64 sadb_comb_hard_usetime; -} __attribute__((packed)); -/* sizeof(struct sadb_comb) == 72 */ - -struct sadb_supported { - __u16 sadb_supported_len; - __u16 sadb_supported_exttype; - __u32 sadb_supported_reserved; -} __attribute__((packed)); -/* sizeof(struct sadb_supported) == 8 */ - -/* followed by: - struct sadb_alg sadb_algs[(sadb_supported_len + - sizeof(__u64) - sizeof(struct sadb_supported)) / - sizeof(struct sadb_alg)]; */ - -struct sadb_alg { - __u8 sadb_alg_id; - __u8 sadb_alg_ivlen; - __u16 sadb_alg_minbits; - __u16 sadb_alg_maxbits; - __u16 sadb_alg_reserved; -} __attribute__((packed)); -/* sizeof(struct sadb_alg) == 8 */ - -struct sadb_spirange { - __u16 sadb_spirange_len; - __u16 sadb_spirange_exttype; - __u32 sadb_spirange_min; - __u32 sadb_spirange_max; - __u32 sadb_spirange_reserved; -} __attribute__((packed)); -/* sizeof(struct sadb_spirange) == 16 */ - -struct sadb_x_kmprivate { - __u16 sadb_x_kmprivate_len; - __u16 sadb_x_kmprivate_exttype; - __u32 sadb_x_kmprivate_reserved; -} __attribute__((packed)); -/* sizeof(struct sadb_x_kmprivate) == 8 */ - -struct sadb_x_sa2 { - __u16 sadb_x_sa2_len; - __u16 sadb_x_sa2_exttype; - __u8 sadb_x_sa2_mode; - __u8 sadb_x_sa2_reserved1; - __u16 sadb_x_sa2_reserved2; - __u32 sadb_x_sa2_sequence; - __u32 sadb_x_sa2_reqid; -} __attribute__((packed)); -/* sizeof(struct sadb_x_sa2) == 16 */ - -struct sadb_x_policy { - __u16 sadb_x_policy_len; - __u16 sadb_x_policy_exttype; - __u16 sadb_x_policy_type; - __u8 sadb_x_policy_dir; - __u8 sadb_x_policy_reserved; - __u32 sadb_x_policy_id; - __u32 sadb_x_policy_priority; -} __attribute__((packed)); -/* sizeof(struct sadb_x_policy) == 16 */ - -struct sadb_x_ipsecrequest { - __u16 sadb_x_ipsecrequest_len; - __u16 sadb_x_ipsecrequest_proto; - __u8 sadb_x_ipsecrequest_mode; - __u8 sadb_x_ipsecrequest_level; - __u16 sadb_x_ipsecrequest_reserved1; - __u32 sadb_x_ipsecrequest_reqid; - __u32 sadb_x_ipsecrequest_reserved2; -} __attribute__((packed)); -/* sizeof(struct sadb_x_ipsecrequest) == 16 */ - -/* This defines the TYPE of Nat Traversal in use. Currently only one - * type of NAT-T is supported, draft-ietf-ipsec-udp-encaps-06 - */ -struct sadb_x_nat_t_type { - __u16 sadb_x_nat_t_type_len; - __u16 sadb_x_nat_t_type_exttype; - __u8 sadb_x_nat_t_type_type; - __u8 sadb_x_nat_t_type_reserved[3]; -} __attribute__((packed)); -/* sizeof(struct sadb_x_nat_t_type) == 8 */ - -/* Pass a NAT Traversal port (Source or Dest port) */ -struct sadb_x_nat_t_port { - __u16 sadb_x_nat_t_port_len; - __u16 sadb_x_nat_t_port_exttype; - __be16 sadb_x_nat_t_port_port; - __u16 sadb_x_nat_t_port_reserved; -} __attribute__((packed)); -/* sizeof(struct sadb_x_nat_t_port) == 8 */ - -/* Generic LSM security context */ -struct sadb_x_sec_ctx { - __u16 sadb_x_sec_len; - __u16 sadb_x_sec_exttype; - __u8 sadb_x_ctx_alg; /* LSMs: e.g., selinux == 1 */ - __u8 sadb_x_ctx_doi; - __u16 sadb_x_ctx_len; -} __attribute__((packed)); -/* sizeof(struct sadb_sec_ctx) = 8 */ - -/* Used by MIGRATE to pass addresses IKE will use to perform - * negotiation with the peer */ -struct sadb_x_kmaddress { - __u16 sadb_x_kmaddress_len; - __u16 sadb_x_kmaddress_exttype; - __u32 sadb_x_kmaddress_reserved; -} __attribute__((packed)); -/* sizeof(struct sadb_x_kmaddress) == 8 */ - -/* To specify the SA dump filter */ -struct sadb_x_filter { - __u16 sadb_x_filter_len; - __u16 sadb_x_filter_exttype; - __u32 sadb_x_filter_saddr[4]; - __u32 sadb_x_filter_daddr[4]; - __u16 sadb_x_filter_family; - __u8 sadb_x_filter_splen; - __u8 sadb_x_filter_dplen; -} __attribute__((packed)); -/* sizeof(struct sadb_x_filter) == 40 */ - -/* Message types */ -#define SADB_RESERVED 0 -#define SADB_GETSPI 1 -#define SADB_UPDATE 2 -#define SADB_ADD 3 -#define SADB_DELETE 4 -#define SADB_GET 5 -#define SADB_ACQUIRE 6 -#define SADB_REGISTER 7 -#define SADB_EXPIRE 8 -#define SADB_FLUSH 9 -#define SADB_DUMP 10 -#define SADB_X_PROMISC 11 -#define SADB_X_PCHANGE 12 -#define SADB_X_SPDUPDATE 13 -#define SADB_X_SPDADD 14 -#define SADB_X_SPDDELETE 15 -#define SADB_X_SPDGET 16 -#define SADB_X_SPDACQUIRE 17 -#define SADB_X_SPDDUMP 18 -#define SADB_X_SPDFLUSH 19 -#define SADB_X_SPDSETIDX 20 -#define SADB_X_SPDEXPIRE 21 -#define SADB_X_SPDDELETE2 22 -#define SADB_X_NAT_T_NEW_MAPPING 23 -#define SADB_X_MIGRATE 24 -#define SADB_MAX 24 - -/* Security Association flags */ -#define SADB_SAFLAGS_PFS 1 -#define SADB_SAFLAGS_NOPMTUDISC 0x20000000 -#define SADB_SAFLAGS_DECAP_DSCP 0x40000000 -#define SADB_SAFLAGS_NOECN 0x80000000 - -/* Security Association states */ -#define SADB_SASTATE_LARVAL 0 -#define SADB_SASTATE_MATURE 1 -#define SADB_SASTATE_DYING 2 -#define SADB_SASTATE_DEAD 3 -#define SADB_SASTATE_MAX 3 - -/* Security Association types */ -#define SADB_SATYPE_UNSPEC 0 -#define SADB_SATYPE_AH 2 -#define SADB_SATYPE_ESP 3 -#define SADB_SATYPE_RSVP 5 -#define SADB_SATYPE_OSPFV2 6 -#define SADB_SATYPE_RIPV2 7 -#define SADB_SATYPE_MIP 8 -#define SADB_X_SATYPE_IPCOMP 9 -#define SADB_SATYPE_MAX 9 - -/* Authentication algorithms */ -#define SADB_AALG_NONE 0 -#define SADB_AALG_MD5HMAC 2 -#define SADB_AALG_SHA1HMAC 3 -#define SADB_X_AALG_SHA2_256HMAC 5 -#define SADB_X_AALG_SHA2_384HMAC 6 -#define SADB_X_AALG_SHA2_512HMAC 7 -#define SADB_X_AALG_RIPEMD160HMAC 8 -#define SADB_X_AALG_AES_XCBC_MAC 9 -#define SADB_X_AALG_NULL 251 /* kame */ -#define SADB_AALG_MAX 251 - -/* Encryption algorithms */ -#define SADB_EALG_NONE 0 -#define SADB_EALG_DESCBC 2 -#define SADB_EALG_3DESCBC 3 -#define SADB_X_EALG_CASTCBC 6 -#define SADB_X_EALG_BLOWFISHCBC 7 -#define SADB_EALG_NULL 11 -#define SADB_X_EALG_AESCBC 12 -#define SADB_X_EALG_AESCTR 13 -#define SADB_X_EALG_AES_CCM_ICV8 14 -#define SADB_X_EALG_AES_CCM_ICV12 15 -#define SADB_X_EALG_AES_CCM_ICV16 16 -#define SADB_X_EALG_AES_GCM_ICV8 18 -#define SADB_X_EALG_AES_GCM_ICV12 19 -#define SADB_X_EALG_AES_GCM_ICV16 20 -#define SADB_X_EALG_CAMELLIACBC 22 -#define SADB_X_EALG_NULL_AES_GMAC 23 -#define SADB_EALG_MAX 253 /* last EALG */ -/* private allocations should use 249-255 (RFC2407) */ -#define SADB_X_EALG_SERPENTCBC 252 /* draft-ietf-ipsec-ciph-aes-cbc-00 */ -#define SADB_X_EALG_TWOFISHCBC 253 /* draft-ietf-ipsec-ciph-aes-cbc-00 */ - -/* Compression algorithms */ -#define SADB_X_CALG_NONE 0 -#define SADB_X_CALG_OUI 1 -#define SADB_X_CALG_DEFLATE 2 -#define SADB_X_CALG_LZS 3 -#define SADB_X_CALG_LZJH 4 -#define SADB_X_CALG_MAX 4 - -/* Extension Header values */ -#define SADB_EXT_RESERVED 0 -#define SADB_EXT_SA 1 -#define SADB_EXT_LIFETIME_CURRENT 2 -#define SADB_EXT_LIFETIME_HARD 3 -#define SADB_EXT_LIFETIME_SOFT 4 -#define SADB_EXT_ADDRESS_SRC 5 -#define SADB_EXT_ADDRESS_DST 6 -#define SADB_EXT_ADDRESS_PROXY 7 -#define SADB_EXT_KEY_AUTH 8 -#define SADB_EXT_KEY_ENCRYPT 9 -#define SADB_EXT_IDENTITY_SRC 10 -#define SADB_EXT_IDENTITY_DST 11 -#define SADB_EXT_SENSITIVITY 12 -#define SADB_EXT_PROPOSAL 13 -#define SADB_EXT_SUPPORTED_AUTH 14 -#define SADB_EXT_SUPPORTED_ENCRYPT 15 -#define SADB_EXT_SPIRANGE 16 -#define SADB_X_EXT_KMPRIVATE 17 -#define SADB_X_EXT_POLICY 18 -#define SADB_X_EXT_SA2 19 -/* The next four entries are for setting up NAT Traversal */ -#define SADB_X_EXT_NAT_T_TYPE 20 -#define SADB_X_EXT_NAT_T_SPORT 21 -#define SADB_X_EXT_NAT_T_DPORT 22 -#define SADB_X_EXT_NAT_T_OA 23 -#define SADB_X_EXT_SEC_CTX 24 -/* Used with MIGRATE to pass @ to IKE for negotiation */ -#define SADB_X_EXT_KMADDRESS 25 -#define SADB_X_EXT_FILTER 26 -#define SADB_EXT_MAX 26 - -/* Identity Extension values */ -#define SADB_IDENTTYPE_RESERVED 0 -#define SADB_IDENTTYPE_PREFIX 1 -#define SADB_IDENTTYPE_FQDN 2 -#define SADB_IDENTTYPE_USERFQDN 3 -#define SADB_IDENTTYPE_MAX 3 - -#endif /* !(_LINUX_PFKEY2_H) */ diff --git a/src/linux/include/uapi/linux/pkt_cls.h b/src/linux/include/uapi/linux/pkt_cls.h deleted file mode 100644 index 8fd715f..0000000 --- a/src/linux/include/uapi/linux/pkt_cls.h +++ /dev/null @@ -1,545 +0,0 @@ -#ifndef __LINUX_PKT_CLS_H -#define __LINUX_PKT_CLS_H - -#include -#include - -#ifdef __KERNEL__ -/* I think i could have done better macros ; for now this is stolen from - * some arch/mips code - jhs -*/ -#define _TC_MAKE32(x) ((x)) - -#define _TC_MAKEMASK1(n) (_TC_MAKE32(1) << _TC_MAKE32(n)) -#define _TC_MAKEMASK(v,n) (_TC_MAKE32((_TC_MAKE32(1)<<(v))-1) << _TC_MAKE32(n)) -#define _TC_MAKEVALUE(v,n) (_TC_MAKE32(v) << _TC_MAKE32(n)) -#define _TC_GETVALUE(v,n,m) ((_TC_MAKE32(v) & _TC_MAKE32(m)) >> _TC_MAKE32(n)) - -/* verdict bit breakdown - * -bit 0: when set -> this packet has been munged already - -bit 1: when set -> It is ok to munge this packet - -bit 2,3,4,5: Reclassify counter - sort of reverse TTL - if exceeded -assume loop - -bit 6,7: Where this packet was last seen -0: Above the transmit example at the socket level -1: on the Ingress -2: on the Egress - -bit 8: when set --> Request not to classify on ingress. - -bits 9,10,11: redirect counter - redirect TTL. Loop avoidance - - * - * */ - -#define S_TC_FROM _TC_MAKE32(6) -#define M_TC_FROM _TC_MAKEMASK(2,S_TC_FROM) -#define G_TC_FROM(x) _TC_GETVALUE(x,S_TC_FROM,M_TC_FROM) -#define V_TC_FROM(x) _TC_MAKEVALUE(x,S_TC_FROM) -#define SET_TC_FROM(v,n) ((V_TC_FROM(n)) | (v & ~M_TC_FROM)) -#define AT_STACK 0x0 -#define AT_INGRESS 0x1 -#define AT_EGRESS 0x2 - -#define TC_NCLS _TC_MAKEMASK1(8) -#define SET_TC_NCLS(v) ( TC_NCLS | (v & ~TC_NCLS)) -#define CLR_TC_NCLS(v) ( v & ~TC_NCLS) - -#define S_TC_AT _TC_MAKE32(12) -#define M_TC_AT _TC_MAKEMASK(2,S_TC_AT) -#define G_TC_AT(x) _TC_GETVALUE(x,S_TC_AT,M_TC_AT) -#define V_TC_AT(x) _TC_MAKEVALUE(x,S_TC_AT) -#define SET_TC_AT(v,n) ((V_TC_AT(n)) | (v & ~M_TC_AT)) - -#define MAX_REC_LOOP 4 -#define MAX_RED_LOOP 4 -#endif - -/* Action attributes */ -enum { - TCA_ACT_UNSPEC, - TCA_ACT_KIND, - TCA_ACT_OPTIONS, - TCA_ACT_INDEX, - TCA_ACT_STATS, - TCA_ACT_PAD, - __TCA_ACT_MAX -}; - -#define TCA_ACT_MAX __TCA_ACT_MAX -#define TCA_OLD_COMPAT (TCA_ACT_MAX+1) -#define TCA_ACT_MAX_PRIO 32 -#define TCA_ACT_BIND 1 -#define TCA_ACT_NOBIND 0 -#define TCA_ACT_UNBIND 1 -#define TCA_ACT_NOUNBIND 0 -#define TCA_ACT_REPLACE 1 -#define TCA_ACT_NOREPLACE 0 - -#define TC_ACT_UNSPEC (-1) -#define TC_ACT_OK 0 -#define TC_ACT_RECLASSIFY 1 -#define TC_ACT_SHOT 2 -#define TC_ACT_PIPE 3 -#define TC_ACT_STOLEN 4 -#define TC_ACT_QUEUED 5 -#define TC_ACT_REPEAT 6 -#define TC_ACT_REDIRECT 7 -#define TC_ACT_JUMP 0x10000000 - -/* Action type identifiers*/ -enum { - TCA_ID_UNSPEC=0, - TCA_ID_POLICE=1, - /* other actions go here */ - __TCA_ID_MAX=255 -}; - -#define TCA_ID_MAX __TCA_ID_MAX - -struct tc_police { - __u32 index; - int action; -#define TC_POLICE_UNSPEC TC_ACT_UNSPEC -#define TC_POLICE_OK TC_ACT_OK -#define TC_POLICE_RECLASSIFY TC_ACT_RECLASSIFY -#define TC_POLICE_SHOT TC_ACT_SHOT -#define TC_POLICE_PIPE TC_ACT_PIPE - - __u32 limit; - __u32 burst; - __u32 mtu; - struct tc_ratespec rate; - struct tc_ratespec peakrate; - int refcnt; - int bindcnt; - __u32 capab; -}; - -struct tcf_t { - __u64 install; - __u64 lastuse; - __u64 expires; - __u64 firstuse; -}; - -struct tc_cnt { - int refcnt; - int bindcnt; -}; - -#define tc_gen \ - __u32 index; \ - __u32 capab; \ - int action; \ - int refcnt; \ - int bindcnt - -enum { - TCA_POLICE_UNSPEC, - TCA_POLICE_TBF, - TCA_POLICE_RATE, - TCA_POLICE_PEAKRATE, - TCA_POLICE_AVRATE, - TCA_POLICE_RESULT, - TCA_POLICE_TM, - TCA_POLICE_PAD, - __TCA_POLICE_MAX -#define TCA_POLICE_RESULT TCA_POLICE_RESULT -}; - -#define TCA_POLICE_MAX (__TCA_POLICE_MAX - 1) - -/* tca flags definitions */ -#define TCA_CLS_FLAGS_SKIP_HW (1 << 0) -#define TCA_CLS_FLAGS_SKIP_SW (1 << 1) - -/* U32 filters */ - -#define TC_U32_HTID(h) ((h)&0xFFF00000) -#define TC_U32_USERHTID(h) (TC_U32_HTID(h)>>20) -#define TC_U32_HASH(h) (((h)>>12)&0xFF) -#define TC_U32_NODE(h) ((h)&0xFFF) -#define TC_U32_KEY(h) ((h)&0xFFFFF) -#define TC_U32_UNSPEC 0 -#define TC_U32_ROOT (0xFFF00000) - -enum { - TCA_U32_UNSPEC, - TCA_U32_CLASSID, - TCA_U32_HASH, - TCA_U32_LINK, - TCA_U32_DIVISOR, - TCA_U32_SEL, - TCA_U32_POLICE, - TCA_U32_ACT, - TCA_U32_INDEV, - TCA_U32_PCNT, - TCA_U32_MARK, - TCA_U32_FLAGS, - TCA_U32_PAD, - __TCA_U32_MAX -}; - -#define TCA_U32_MAX (__TCA_U32_MAX - 1) - -struct tc_u32_key { - __be32 mask; - __be32 val; - int off; - int offmask; -}; - -struct tc_u32_sel { - unsigned char flags; - unsigned char offshift; - unsigned char nkeys; - - __be16 offmask; - __u16 off; - short offoff; - - short hoff; - __be32 hmask; - struct tc_u32_key keys[0]; -}; - -struct tc_u32_mark { - __u32 val; - __u32 mask; - __u32 success; -}; - -struct tc_u32_pcnt { - __u64 rcnt; - __u64 rhit; - __u64 kcnts[0]; -}; - -/* Flags */ - -#define TC_U32_TERMINAL 1 -#define TC_U32_OFFSET 2 -#define TC_U32_VAROFFSET 4 -#define TC_U32_EAT 8 - -#define TC_U32_MAXDEPTH 8 - - -/* RSVP filter */ - -enum { - TCA_RSVP_UNSPEC, - TCA_RSVP_CLASSID, - TCA_RSVP_DST, - TCA_RSVP_SRC, - TCA_RSVP_PINFO, - TCA_RSVP_POLICE, - TCA_RSVP_ACT, - __TCA_RSVP_MAX -}; - -#define TCA_RSVP_MAX (__TCA_RSVP_MAX - 1 ) - -struct tc_rsvp_gpi { - __u32 key; - __u32 mask; - int offset; -}; - -struct tc_rsvp_pinfo { - struct tc_rsvp_gpi dpi; - struct tc_rsvp_gpi spi; - __u8 protocol; - __u8 tunnelid; - __u8 tunnelhdr; - __u8 pad; -}; - -/* ROUTE filter */ - -enum { - TCA_ROUTE4_UNSPEC, - TCA_ROUTE4_CLASSID, - TCA_ROUTE4_TO, - TCA_ROUTE4_FROM, - TCA_ROUTE4_IIF, - TCA_ROUTE4_POLICE, - TCA_ROUTE4_ACT, - __TCA_ROUTE4_MAX -}; - -#define TCA_ROUTE4_MAX (__TCA_ROUTE4_MAX - 1) - - -/* FW filter */ - -enum { - TCA_FW_UNSPEC, - TCA_FW_CLASSID, - TCA_FW_POLICE, - TCA_FW_INDEV, /* used by CONFIG_NET_CLS_IND */ - TCA_FW_ACT, /* used by CONFIG_NET_CLS_ACT */ - TCA_FW_MASK, - __TCA_FW_MAX -}; - -#define TCA_FW_MAX (__TCA_FW_MAX - 1) - -/* TC index filter */ - -enum { - TCA_TCINDEX_UNSPEC, - TCA_TCINDEX_HASH, - TCA_TCINDEX_MASK, - TCA_TCINDEX_SHIFT, - TCA_TCINDEX_FALL_THROUGH, - TCA_TCINDEX_CLASSID, - TCA_TCINDEX_POLICE, - TCA_TCINDEX_ACT, - __TCA_TCINDEX_MAX -}; - -#define TCA_TCINDEX_MAX (__TCA_TCINDEX_MAX - 1) - -/* Flow filter */ - -enum { - FLOW_KEY_SRC, - FLOW_KEY_DST, - FLOW_KEY_PROTO, - FLOW_KEY_PROTO_SRC, - FLOW_KEY_PROTO_DST, - FLOW_KEY_IIF, - FLOW_KEY_PRIORITY, - FLOW_KEY_MARK, - FLOW_KEY_NFCT, - FLOW_KEY_NFCT_SRC, - FLOW_KEY_NFCT_DST, - FLOW_KEY_NFCT_PROTO_SRC, - FLOW_KEY_NFCT_PROTO_DST, - FLOW_KEY_RTCLASSID, - FLOW_KEY_SKUID, - FLOW_KEY_SKGID, - FLOW_KEY_VLAN_TAG, - FLOW_KEY_RXHASH, - __FLOW_KEY_MAX, -}; - -#define FLOW_KEY_MAX (__FLOW_KEY_MAX - 1) - -enum { - FLOW_MODE_MAP, - FLOW_MODE_HASH, -}; - -enum { - TCA_FLOW_UNSPEC, - TCA_FLOW_KEYS, - TCA_FLOW_MODE, - TCA_FLOW_BASECLASS, - TCA_FLOW_RSHIFT, - TCA_FLOW_ADDEND, - TCA_FLOW_MASK, - TCA_FLOW_XOR, - TCA_FLOW_DIVISOR, - TCA_FLOW_ACT, - TCA_FLOW_POLICE, - TCA_FLOW_EMATCHES, - TCA_FLOW_PERTURB, - __TCA_FLOW_MAX -}; - -#define TCA_FLOW_MAX (__TCA_FLOW_MAX - 1) - -/* Basic filter */ - -enum { - TCA_BASIC_UNSPEC, - TCA_BASIC_CLASSID, - TCA_BASIC_EMATCHES, - TCA_BASIC_ACT, - TCA_BASIC_POLICE, - __TCA_BASIC_MAX -}; - -#define TCA_BASIC_MAX (__TCA_BASIC_MAX - 1) - - -/* Cgroup classifier */ - -enum { - TCA_CGROUP_UNSPEC, - TCA_CGROUP_ACT, - TCA_CGROUP_POLICE, - TCA_CGROUP_EMATCHES, - __TCA_CGROUP_MAX, -}; - -#define TCA_CGROUP_MAX (__TCA_CGROUP_MAX - 1) - -/* BPF classifier */ - -#define TCA_BPF_FLAG_ACT_DIRECT (1 << 0) - -enum { - TCA_BPF_UNSPEC, - TCA_BPF_ACT, - TCA_BPF_POLICE, - TCA_BPF_CLASSID, - TCA_BPF_OPS_LEN, - TCA_BPF_OPS, - TCA_BPF_FD, - TCA_BPF_NAME, - TCA_BPF_FLAGS, - TCA_BPF_FLAGS_GEN, - __TCA_BPF_MAX, -}; - -#define TCA_BPF_MAX (__TCA_BPF_MAX - 1) - -/* Flower classifier */ - -enum { - TCA_FLOWER_UNSPEC, - TCA_FLOWER_CLASSID, - TCA_FLOWER_INDEV, - TCA_FLOWER_ACT, - TCA_FLOWER_KEY_ETH_DST, /* ETH_ALEN */ - TCA_FLOWER_KEY_ETH_DST_MASK, /* ETH_ALEN */ - TCA_FLOWER_KEY_ETH_SRC, /* ETH_ALEN */ - TCA_FLOWER_KEY_ETH_SRC_MASK, /* ETH_ALEN */ - TCA_FLOWER_KEY_ETH_TYPE, /* be16 */ - TCA_FLOWER_KEY_IP_PROTO, /* u8 */ - TCA_FLOWER_KEY_IPV4_SRC, /* be32 */ - TCA_FLOWER_KEY_IPV4_SRC_MASK, /* be32 */ - TCA_FLOWER_KEY_IPV4_DST, /* be32 */ - TCA_FLOWER_KEY_IPV4_DST_MASK, /* be32 */ - TCA_FLOWER_KEY_IPV6_SRC, /* struct in6_addr */ - TCA_FLOWER_KEY_IPV6_SRC_MASK, /* struct in6_addr */ - TCA_FLOWER_KEY_IPV6_DST, /* struct in6_addr */ - TCA_FLOWER_KEY_IPV6_DST_MASK, /* struct in6_addr */ - TCA_FLOWER_KEY_TCP_SRC, /* be16 */ - TCA_FLOWER_KEY_TCP_DST, /* be16 */ - TCA_FLOWER_KEY_UDP_SRC, /* be16 */ - TCA_FLOWER_KEY_UDP_DST, /* be16 */ - - TCA_FLOWER_FLAGS, - TCA_FLOWER_KEY_VLAN_ID, /* be16 */ - TCA_FLOWER_KEY_VLAN_PRIO, /* u8 */ - TCA_FLOWER_KEY_VLAN_ETH_TYPE, /* be16 */ - - TCA_FLOWER_KEY_ENC_KEY_ID, /* be32 */ - TCA_FLOWER_KEY_ENC_IPV4_SRC, /* be32 */ - TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,/* be32 */ - TCA_FLOWER_KEY_ENC_IPV4_DST, /* be32 */ - TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,/* be32 */ - TCA_FLOWER_KEY_ENC_IPV6_SRC, /* struct in6_addr */ - TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,/* struct in6_addr */ - TCA_FLOWER_KEY_ENC_IPV6_DST, /* struct in6_addr */ - TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,/* struct in6_addr */ - - TCA_FLOWER_KEY_TCP_SRC_MASK, /* be16 */ - TCA_FLOWER_KEY_TCP_DST_MASK, /* be16 */ - TCA_FLOWER_KEY_UDP_SRC_MASK, /* be16 */ - TCA_FLOWER_KEY_UDP_DST_MASK, /* be16 */ - __TCA_FLOWER_MAX, -}; - -#define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1) - -/* Match-all classifier */ - -enum { - TCA_MATCHALL_UNSPEC, - TCA_MATCHALL_CLASSID, - TCA_MATCHALL_ACT, - TCA_MATCHALL_FLAGS, - __TCA_MATCHALL_MAX, -}; - -#define TCA_MATCHALL_MAX (__TCA_MATCHALL_MAX - 1) - -/* Extended Matches */ - -struct tcf_ematch_tree_hdr { - __u16 nmatches; - __u16 progid; -}; - -enum { - TCA_EMATCH_TREE_UNSPEC, - TCA_EMATCH_TREE_HDR, - TCA_EMATCH_TREE_LIST, - __TCA_EMATCH_TREE_MAX -}; -#define TCA_EMATCH_TREE_MAX (__TCA_EMATCH_TREE_MAX - 1) - -struct tcf_ematch_hdr { - __u16 matchid; - __u16 kind; - __u16 flags; - __u16 pad; /* currently unused */ -}; - -/* 0 1 - * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 - * +-----------------------+-+-+---+ - * | Unused |S|I| R | - * +-----------------------+-+-+---+ - * - * R(2) ::= relation to next ematch - * where: 0 0 END (last ematch) - * 0 1 AND - * 1 0 OR - * 1 1 Unused (invalid) - * I(1) ::= invert result - * S(1) ::= simple payload - */ -#define TCF_EM_REL_END 0 -#define TCF_EM_REL_AND (1<<0) -#define TCF_EM_REL_OR (1<<1) -#define TCF_EM_INVERT (1<<2) -#define TCF_EM_SIMPLE (1<<3) - -#define TCF_EM_REL_MASK 3 -#define TCF_EM_REL_VALID(v) (((v) & TCF_EM_REL_MASK) != TCF_EM_REL_MASK) - -enum { - TCF_LAYER_LINK, - TCF_LAYER_NETWORK, - TCF_LAYER_TRANSPORT, - __TCF_LAYER_MAX -}; -#define TCF_LAYER_MAX (__TCF_LAYER_MAX - 1) - -/* Ematch type assignments - * 1..32767 Reserved for ematches inside kernel tree - * 32768..65535 Free to use, not reliable - */ -#define TCF_EM_CONTAINER 0 -#define TCF_EM_CMP 1 -#define TCF_EM_NBYTE 2 -#define TCF_EM_U32 3 -#define TCF_EM_META 4 -#define TCF_EM_TEXT 5 -#define TCF_EM_VLAN 6 -#define TCF_EM_CANID 7 -#define TCF_EM_IPSET 8 -#define TCF_EM_MAX 8 - -enum { - TCF_EM_PROG_TC -}; - -enum { - TCF_EM_OPND_EQ, - TCF_EM_OPND_GT, - TCF_EM_OPND_LT -}; - -#endif diff --git a/src/linux/include/uapi/linux/pkt_sched.h b/src/linux/include/uapi/linux/pkt_sched.h deleted file mode 100644 index df7451d..0000000 --- a/src/linux/include/uapi/linux/pkt_sched.h +++ /dev/null @@ -1,866 +0,0 @@ -#ifndef __LINUX_PKT_SCHED_H -#define __LINUX_PKT_SCHED_H - -#include - -/* Logical priority bands not depending on specific packet scheduler. - Every scheduler will map them to real traffic classes, if it has - no more precise mechanism to classify packets. - - These numbers have no special meaning, though their coincidence - with obsolete IPv6 values is not occasional :-). New IPv6 drafts - preferred full anarchy inspired by diffserv group. - - Note: TC_PRIO_BESTEFFORT does not mean that it is the most unhappy - class, actually, as rule it will be handled with more care than - filler or even bulk. - */ - -#define TC_PRIO_BESTEFFORT 0 -#define TC_PRIO_FILLER 1 -#define TC_PRIO_BULK 2 -#define TC_PRIO_INTERACTIVE_BULK 4 -#define TC_PRIO_INTERACTIVE 6 -#define TC_PRIO_CONTROL 7 - -#define TC_PRIO_MAX 15 - -/* Generic queue statistics, available for all the elements. - Particular schedulers may have also their private records. - */ - -struct tc_stats { - __u64 bytes; /* Number of enqueued bytes */ - __u32 packets; /* Number of enqueued packets */ - __u32 drops; /* Packets dropped because of lack of resources */ - __u32 overlimits; /* Number of throttle events when this - * flow goes out of allocated bandwidth */ - __u32 bps; /* Current flow byte rate */ - __u32 pps; /* Current flow packet rate */ - __u32 qlen; - __u32 backlog; -}; - -struct tc_estimator { - signed char interval; - unsigned char ewma_log; -}; - -/* "Handles" - --------- - - All the traffic control objects have 32bit identifiers, or "handles". - - They can be considered as opaque numbers from user API viewpoint, - but actually they always consist of two fields: major and - minor numbers, which are interpreted by kernel specially, - that may be used by applications, though not recommended. - - F.e. qdisc handles always have minor number equal to zero, - classes (or flows) have major equal to parent qdisc major, and - minor uniquely identifying class inside qdisc. - - Macros to manipulate handles: - */ - -#define TC_H_MAJ_MASK (0xFFFF0000U) -#define TC_H_MIN_MASK (0x0000FFFFU) -#define TC_H_MAJ(h) ((h)&TC_H_MAJ_MASK) -#define TC_H_MIN(h) ((h)&TC_H_MIN_MASK) -#define TC_H_MAKE(maj,min) (((maj)&TC_H_MAJ_MASK)|((min)&TC_H_MIN_MASK)) - -#define TC_H_UNSPEC (0U) -#define TC_H_ROOT (0xFFFFFFFFU) -#define TC_H_INGRESS (0xFFFFFFF1U) -#define TC_H_CLSACT TC_H_INGRESS - -#define TC_H_MIN_INGRESS 0xFFF2U -#define TC_H_MIN_EGRESS 0xFFF3U - -/* Need to corrospond to iproute2 tc/tc_core.h "enum link_layer" */ -enum tc_link_layer { - TC_LINKLAYER_UNAWARE, /* Indicate unaware old iproute2 util */ - TC_LINKLAYER_ETHERNET, - TC_LINKLAYER_ATM, -}; -#define TC_LINKLAYER_MASK 0x0F /* limit use to lower 4 bits */ - -struct tc_ratespec { - unsigned char cell_log; - __u8 linklayer; /* lower 4 bits */ - unsigned short overhead; - short cell_align; - unsigned short mpu; - __u32 rate; -}; - -#define TC_RTAB_SIZE 1024 - -struct tc_sizespec { - unsigned char cell_log; - unsigned char size_log; - short cell_align; - int overhead; - unsigned int linklayer; - unsigned int mpu; - unsigned int mtu; - unsigned int tsize; -}; - -enum { - TCA_STAB_UNSPEC, - TCA_STAB_BASE, - TCA_STAB_DATA, - __TCA_STAB_MAX -}; - -#define TCA_STAB_MAX (__TCA_STAB_MAX - 1) - -/* FIFO section */ - -struct tc_fifo_qopt { - __u32 limit; /* Queue length: bytes for bfifo, packets for pfifo */ -}; - -/* PRIO section */ - -#define TCQ_PRIO_BANDS 16 -#define TCQ_MIN_PRIO_BANDS 2 - -struct tc_prio_qopt { - int bands; /* Number of bands */ - __u8 priomap[TC_PRIO_MAX+1]; /* Map: logical priority -> PRIO band */ -}; - -/* MULTIQ section */ - -struct tc_multiq_qopt { - __u16 bands; /* Number of bands */ - __u16 max_bands; /* Maximum number of queues */ -}; - -/* PLUG section */ - -#define TCQ_PLUG_BUFFER 0 -#define TCQ_PLUG_RELEASE_ONE 1 -#define TCQ_PLUG_RELEASE_INDEFINITE 2 -#define TCQ_PLUG_LIMIT 3 - -struct tc_plug_qopt { - /* TCQ_PLUG_BUFFER: Inset a plug into the queue and - * buffer any incoming packets - * TCQ_PLUG_RELEASE_ONE: Dequeue packets from queue head - * to beginning of the next plug. - * TCQ_PLUG_RELEASE_INDEFINITE: Dequeue all packets from queue. - * Stop buffering packets until the next TCQ_PLUG_BUFFER - * command is received (just act as a pass-thru queue). - * TCQ_PLUG_LIMIT: Increase/decrease queue size - */ - int action; - __u32 limit; -}; - -/* TBF section */ - -struct tc_tbf_qopt { - struct tc_ratespec rate; - struct tc_ratespec peakrate; - __u32 limit; - __u32 buffer; - __u32 mtu; -}; - -enum { - TCA_TBF_UNSPEC, - TCA_TBF_PARMS, - TCA_TBF_RTAB, - TCA_TBF_PTAB, - TCA_TBF_RATE64, - TCA_TBF_PRATE64, - TCA_TBF_BURST, - TCA_TBF_PBURST, - TCA_TBF_PAD, - __TCA_TBF_MAX, -}; - -#define TCA_TBF_MAX (__TCA_TBF_MAX - 1) - - -/* TEQL section */ - -/* TEQL does not require any parameters */ - -/* SFQ section */ - -struct tc_sfq_qopt { - unsigned quantum; /* Bytes per round allocated to flow */ - int perturb_period; /* Period of hash perturbation */ - __u32 limit; /* Maximal packets in queue */ - unsigned divisor; /* Hash divisor */ - unsigned flows; /* Maximal number of flows */ -}; - -struct tc_sfqred_stats { - __u32 prob_drop; /* Early drops, below max threshold */ - __u32 forced_drop; /* Early drops, after max threshold */ - __u32 prob_mark; /* Marked packets, below max threshold */ - __u32 forced_mark; /* Marked packets, after max threshold */ - __u32 prob_mark_head; /* Marked packets, below max threshold */ - __u32 forced_mark_head;/* Marked packets, after max threshold */ -}; - -struct tc_sfq_qopt_v1 { - struct tc_sfq_qopt v0; - unsigned int depth; /* max number of packets per flow */ - unsigned int headdrop; -/* SFQRED parameters */ - __u32 limit; /* HARD maximal flow queue length (bytes) */ - __u32 qth_min; /* Min average length threshold (bytes) */ - __u32 qth_max; /* Max average length threshold (bytes) */ - unsigned char Wlog; /* log(W) */ - unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */ - unsigned char Scell_log; /* cell size for idle damping */ - unsigned char flags; - __u32 max_P; /* probability, high resolution */ -/* SFQRED stats */ - struct tc_sfqred_stats stats; -}; - - -struct tc_sfq_xstats { - __s32 allot; -}; - -/* RED section */ - -enum { - TCA_RED_UNSPEC, - TCA_RED_PARMS, - TCA_RED_STAB, - TCA_RED_MAX_P, - __TCA_RED_MAX, -}; - -#define TCA_RED_MAX (__TCA_RED_MAX - 1) - -struct tc_red_qopt { - __u32 limit; /* HARD maximal queue length (bytes) */ - __u32 qth_min; /* Min average length threshold (bytes) */ - __u32 qth_max; /* Max average length threshold (bytes) */ - unsigned char Wlog; /* log(W) */ - unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */ - unsigned char Scell_log; /* cell size for idle damping */ - unsigned char flags; -#define TC_RED_ECN 1 -#define TC_RED_HARDDROP 2 -#define TC_RED_ADAPTATIVE 4 -}; - -struct tc_red_xstats { - __u32 early; /* Early drops */ - __u32 pdrop; /* Drops due to queue limits */ - __u32 other; /* Drops due to drop() calls */ - __u32 marked; /* Marked packets */ -}; - -/* GRED section */ - -#define MAX_DPs 16 - -enum { - TCA_GRED_UNSPEC, - TCA_GRED_PARMS, - TCA_GRED_STAB, - TCA_GRED_DPS, - TCA_GRED_MAX_P, - TCA_GRED_LIMIT, - __TCA_GRED_MAX, -}; - -#define TCA_GRED_MAX (__TCA_GRED_MAX - 1) - -struct tc_gred_qopt { - __u32 limit; /* HARD maximal queue length (bytes) */ - __u32 qth_min; /* Min average length threshold (bytes) */ - __u32 qth_max; /* Max average length threshold (bytes) */ - __u32 DP; /* up to 2^32 DPs */ - __u32 backlog; - __u32 qave; - __u32 forced; - __u32 early; - __u32 other; - __u32 pdrop; - __u8 Wlog; /* log(W) */ - __u8 Plog; /* log(P_max/(qth_max-qth_min)) */ - __u8 Scell_log; /* cell size for idle damping */ - __u8 prio; /* prio of this VQ */ - __u32 packets; - __u32 bytesin; -}; - -/* gred setup */ -struct tc_gred_sopt { - __u32 DPs; - __u32 def_DP; - __u8 grio; - __u8 flags; - __u16 pad1; -}; - -/* CHOKe section */ - -enum { - TCA_CHOKE_UNSPEC, - TCA_CHOKE_PARMS, - TCA_CHOKE_STAB, - TCA_CHOKE_MAX_P, - __TCA_CHOKE_MAX, -}; - -#define TCA_CHOKE_MAX (__TCA_CHOKE_MAX - 1) - -struct tc_choke_qopt { - __u32 limit; /* Hard queue length (packets) */ - __u32 qth_min; /* Min average threshold (packets) */ - __u32 qth_max; /* Max average threshold (packets) */ - unsigned char Wlog; /* log(W) */ - unsigned char Plog; /* log(P_max/(qth_max-qth_min)) */ - unsigned char Scell_log; /* cell size for idle damping */ - unsigned char flags; /* see RED flags */ -}; - -struct tc_choke_xstats { - __u32 early; /* Early drops */ - __u32 pdrop; /* Drops due to queue limits */ - __u32 other; /* Drops due to drop() calls */ - __u32 marked; /* Marked packets */ - __u32 matched; /* Drops due to flow match */ -}; - -/* HTB section */ -#define TC_HTB_NUMPRIO 8 -#define TC_HTB_MAXDEPTH 8 -#define TC_HTB_PROTOVER 3 /* the same as HTB and TC's major */ - -struct tc_htb_opt { - struct tc_ratespec rate; - struct tc_ratespec ceil; - __u32 buffer; - __u32 cbuffer; - __u32 quantum; - __u32 level; /* out only */ - __u32 prio; -}; -struct tc_htb_glob { - __u32 version; /* to match HTB/TC */ - __u32 rate2quantum; /* bps->quantum divisor */ - __u32 defcls; /* default class number */ - __u32 debug; /* debug flags */ - - /* stats */ - __u32 direct_pkts; /* count of non shaped packets */ -}; -enum { - TCA_HTB_UNSPEC, - TCA_HTB_PARMS, - TCA_HTB_INIT, - TCA_HTB_CTAB, - TCA_HTB_RTAB, - TCA_HTB_DIRECT_QLEN, - TCA_HTB_RATE64, - TCA_HTB_CEIL64, - TCA_HTB_PAD, - __TCA_HTB_MAX, -}; - -#define TCA_HTB_MAX (__TCA_HTB_MAX - 1) - -struct tc_htb_xstats { - __u32 lends; - __u32 borrows; - __u32 giants; /* too big packets (rate will not be accurate) */ - __u32 tokens; - __u32 ctokens; -}; - -/* HFSC section */ - -struct tc_hfsc_qopt { - __u16 defcls; /* default class */ -}; - -struct tc_service_curve { - __u32 m1; /* slope of the first segment in bps */ - __u32 d; /* x-projection of the first segment in us */ - __u32 m2; /* slope of the second segment in bps */ -}; - -struct tc_hfsc_stats { - __u64 work; /* total work done */ - __u64 rtwork; /* work done by real-time criteria */ - __u32 period; /* current period */ - __u32 level; /* class level in hierarchy */ -}; - -enum { - TCA_HFSC_UNSPEC, - TCA_HFSC_RSC, - TCA_HFSC_FSC, - TCA_HFSC_USC, - __TCA_HFSC_MAX, -}; - -#define TCA_HFSC_MAX (__TCA_HFSC_MAX - 1) - - -/* CBQ section */ - -#define TC_CBQ_MAXPRIO 8 -#define TC_CBQ_MAXLEVEL 8 -#define TC_CBQ_DEF_EWMA 5 - -struct tc_cbq_lssopt { - unsigned char change; - unsigned char flags; -#define TCF_CBQ_LSS_BOUNDED 1 -#define TCF_CBQ_LSS_ISOLATED 2 - unsigned char ewma_log; - unsigned char level; -#define TCF_CBQ_LSS_FLAGS 1 -#define TCF_CBQ_LSS_EWMA 2 -#define TCF_CBQ_LSS_MAXIDLE 4 -#define TCF_CBQ_LSS_MINIDLE 8 -#define TCF_CBQ_LSS_OFFTIME 0x10 -#define TCF_CBQ_LSS_AVPKT 0x20 - __u32 maxidle; - __u32 minidle; - __u32 offtime; - __u32 avpkt; -}; - -struct tc_cbq_wrropt { - unsigned char flags; - unsigned char priority; - unsigned char cpriority; - unsigned char __reserved; - __u32 allot; - __u32 weight; -}; - -struct tc_cbq_ovl { - unsigned char strategy; -#define TC_CBQ_OVL_CLASSIC 0 -#define TC_CBQ_OVL_DELAY 1 -#define TC_CBQ_OVL_LOWPRIO 2 -#define TC_CBQ_OVL_DROP 3 -#define TC_CBQ_OVL_RCLASSIC 4 - unsigned char priority2; - __u16 pad; - __u32 penalty; -}; - -struct tc_cbq_police { - unsigned char police; - unsigned char __res1; - unsigned short __res2; -}; - -struct tc_cbq_fopt { - __u32 split; - __u32 defmap; - __u32 defchange; -}; - -struct tc_cbq_xstats { - __u32 borrows; - __u32 overactions; - __s32 avgidle; - __s32 undertime; -}; - -enum { - TCA_CBQ_UNSPEC, - TCA_CBQ_LSSOPT, - TCA_CBQ_WRROPT, - TCA_CBQ_FOPT, - TCA_CBQ_OVL_STRATEGY, - TCA_CBQ_RATE, - TCA_CBQ_RTAB, - TCA_CBQ_POLICE, - __TCA_CBQ_MAX, -}; - -#define TCA_CBQ_MAX (__TCA_CBQ_MAX - 1) - -/* dsmark section */ - -enum { - TCA_DSMARK_UNSPEC, - TCA_DSMARK_INDICES, - TCA_DSMARK_DEFAULT_INDEX, - TCA_DSMARK_SET_TC_INDEX, - TCA_DSMARK_MASK, - TCA_DSMARK_VALUE, - __TCA_DSMARK_MAX, -}; - -#define TCA_DSMARK_MAX (__TCA_DSMARK_MAX - 1) - -/* ATM section */ - -enum { - TCA_ATM_UNSPEC, - TCA_ATM_FD, /* file/socket descriptor */ - TCA_ATM_PTR, /* pointer to descriptor - later */ - TCA_ATM_HDR, /* LL header */ - TCA_ATM_EXCESS, /* excess traffic class (0 for CLP) */ - TCA_ATM_ADDR, /* PVC address (for output only) */ - TCA_ATM_STATE, /* VC state (ATM_VS_*; for output only) */ - __TCA_ATM_MAX, -}; - -#define TCA_ATM_MAX (__TCA_ATM_MAX - 1) - -/* Network emulator */ - -enum { - TCA_NETEM_UNSPEC, - TCA_NETEM_CORR, - TCA_NETEM_DELAY_DIST, - TCA_NETEM_REORDER, - TCA_NETEM_CORRUPT, - TCA_NETEM_LOSS, - TCA_NETEM_RATE, - TCA_NETEM_ECN, - TCA_NETEM_RATE64, - TCA_NETEM_PAD, - __TCA_NETEM_MAX, -}; - -#define TCA_NETEM_MAX (__TCA_NETEM_MAX - 1) - -struct tc_netem_qopt { - __u32 latency; /* added delay (us) */ - __u32 limit; /* fifo limit (packets) */ - __u32 loss; /* random packet loss (0=none ~0=100%) */ - __u32 gap; /* re-ordering gap (0 for none) */ - __u32 duplicate; /* random packet dup (0=none ~0=100%) */ - __u32 jitter; /* random jitter in latency (us) */ -}; - -struct tc_netem_corr { - __u32 delay_corr; /* delay correlation */ - __u32 loss_corr; /* packet loss correlation */ - __u32 dup_corr; /* duplicate correlation */ -}; - -struct tc_netem_reorder { - __u32 probability; - __u32 correlation; -}; - -struct tc_netem_corrupt { - __u32 probability; - __u32 correlation; -}; - -struct tc_netem_rate { - __u32 rate; /* byte/s */ - __s32 packet_overhead; - __u32 cell_size; - __s32 cell_overhead; -}; - -enum { - NETEM_LOSS_UNSPEC, - NETEM_LOSS_GI, /* General Intuitive - 4 state model */ - NETEM_LOSS_GE, /* Gilbert Elliot models */ - __NETEM_LOSS_MAX -}; -#define NETEM_LOSS_MAX (__NETEM_LOSS_MAX - 1) - -/* State transition probabilities for 4 state model */ -struct tc_netem_gimodel { - __u32 p13; - __u32 p31; - __u32 p32; - __u32 p14; - __u32 p23; -}; - -/* Gilbert-Elliot models */ -struct tc_netem_gemodel { - __u32 p; - __u32 r; - __u32 h; - __u32 k1; -}; - -#define NETEM_DIST_SCALE 8192 -#define NETEM_DIST_MAX 16384 - -/* DRR */ - -enum { - TCA_DRR_UNSPEC, - TCA_DRR_QUANTUM, - __TCA_DRR_MAX -}; - -#define TCA_DRR_MAX (__TCA_DRR_MAX - 1) - -struct tc_drr_stats { - __u32 deficit; -}; - -/* MQPRIO */ -#define TC_QOPT_BITMASK 15 -#define TC_QOPT_MAX_QUEUE 16 - -struct tc_mqprio_qopt { - __u8 num_tc; - __u8 prio_tc_map[TC_QOPT_BITMASK + 1]; - __u8 hw; - __u16 count[TC_QOPT_MAX_QUEUE]; - __u16 offset[TC_QOPT_MAX_QUEUE]; -}; - -/* SFB */ - -enum { - TCA_SFB_UNSPEC, - TCA_SFB_PARMS, - __TCA_SFB_MAX, -}; - -#define TCA_SFB_MAX (__TCA_SFB_MAX - 1) - -/* - * Note: increment, decrement are Q0.16 fixed-point values. - */ -struct tc_sfb_qopt { - __u32 rehash_interval; /* delay between hash move, in ms */ - __u32 warmup_time; /* double buffering warmup time in ms (warmup_time < rehash_interval) */ - __u32 max; /* max len of qlen_min */ - __u32 bin_size; /* maximum queue length per bin */ - __u32 increment; /* probability increment, (d1 in Blue) */ - __u32 decrement; /* probability decrement, (d2 in Blue) */ - __u32 limit; /* max SFB queue length */ - __u32 penalty_rate; /* inelastic flows are rate limited to 'rate' pps */ - __u32 penalty_burst; -}; - -struct tc_sfb_xstats { - __u32 earlydrop; - __u32 penaltydrop; - __u32 bucketdrop; - __u32 queuedrop; - __u32 childdrop; /* drops in child qdisc */ - __u32 marked; - __u32 maxqlen; - __u32 maxprob; - __u32 avgprob; -}; - -#define SFB_MAX_PROB 0xFFFF - -/* QFQ */ -enum { - TCA_QFQ_UNSPEC, - TCA_QFQ_WEIGHT, - TCA_QFQ_LMAX, - __TCA_QFQ_MAX -}; - -#define TCA_QFQ_MAX (__TCA_QFQ_MAX - 1) - -struct tc_qfq_stats { - __u32 weight; - __u32 lmax; -}; - -/* CODEL */ - -enum { - TCA_CODEL_UNSPEC, - TCA_CODEL_TARGET, - TCA_CODEL_LIMIT, - TCA_CODEL_INTERVAL, - TCA_CODEL_ECN, - TCA_CODEL_CE_THRESHOLD, - __TCA_CODEL_MAX -}; - -#define TCA_CODEL_MAX (__TCA_CODEL_MAX - 1) - -struct tc_codel_xstats { - __u32 maxpacket; /* largest packet we've seen so far */ - __u32 count; /* how many drops we've done since the last time we - * entered dropping state - */ - __u32 lastcount; /* count at entry to dropping state */ - __u32 ldelay; /* in-queue delay seen by most recently dequeued packet */ - __s32 drop_next; /* time to drop next packet */ - __u32 drop_overlimit; /* number of time max qdisc packet limit was hit */ - __u32 ecn_mark; /* number of packets we ECN marked instead of dropped */ - __u32 dropping; /* are we in dropping state ? */ - __u32 ce_mark; /* number of CE marked packets because of ce_threshold */ -}; - -/* FQ_CODEL */ - -enum { - TCA_FQ_CODEL_UNSPEC, - TCA_FQ_CODEL_TARGET, - TCA_FQ_CODEL_LIMIT, - TCA_FQ_CODEL_INTERVAL, - TCA_FQ_CODEL_ECN, - TCA_FQ_CODEL_FLOWS, - TCA_FQ_CODEL_QUANTUM, - TCA_FQ_CODEL_CE_THRESHOLD, - TCA_FQ_CODEL_DROP_BATCH_SIZE, - TCA_FQ_CODEL_MEMORY_LIMIT, - __TCA_FQ_CODEL_MAX -}; - -#define TCA_FQ_CODEL_MAX (__TCA_FQ_CODEL_MAX - 1) - -enum { - TCA_FQ_CODEL_XSTATS_QDISC, - TCA_FQ_CODEL_XSTATS_CLASS, -}; - -struct tc_fq_codel_qd_stats { - __u32 maxpacket; /* largest packet we've seen so far */ - __u32 drop_overlimit; /* number of time max qdisc - * packet limit was hit - */ - __u32 ecn_mark; /* number of packets we ECN marked - * instead of being dropped - */ - __u32 new_flow_count; /* number of time packets - * created a 'new flow' - */ - __u32 new_flows_len; /* count of flows in new list */ - __u32 old_flows_len; /* count of flows in old list */ - __u32 ce_mark; /* packets above ce_threshold */ - __u32 memory_usage; /* in bytes */ - __u32 drop_overmemory; -}; - -struct tc_fq_codel_cl_stats { - __s32 deficit; - __u32 ldelay; /* in-queue delay seen by most recently - * dequeued packet - */ - __u32 count; - __u32 lastcount; - __u32 dropping; - __s32 drop_next; -}; - -struct tc_fq_codel_xstats { - __u32 type; - union { - struct tc_fq_codel_qd_stats qdisc_stats; - struct tc_fq_codel_cl_stats class_stats; - }; -}; - -/* FQ */ - -enum { - TCA_FQ_UNSPEC, - - TCA_FQ_PLIMIT, /* limit of total number of packets in queue */ - - TCA_FQ_FLOW_PLIMIT, /* limit of packets per flow */ - - TCA_FQ_QUANTUM, /* RR quantum */ - - TCA_FQ_INITIAL_QUANTUM, /* RR quantum for new flow */ - - TCA_FQ_RATE_ENABLE, /* enable/disable rate limiting */ - - TCA_FQ_FLOW_DEFAULT_RATE,/* obsolete, do not use */ - - TCA_FQ_FLOW_MAX_RATE, /* per flow max rate */ - - TCA_FQ_BUCKETS_LOG, /* log2(number of buckets) */ - - TCA_FQ_FLOW_REFILL_DELAY, /* flow credit refill delay in usec */ - - TCA_FQ_ORPHAN_MASK, /* mask applied to orphaned skb hashes */ - - TCA_FQ_LOW_RATE_THRESHOLD, /* per packet delay under this rate */ - - __TCA_FQ_MAX -}; - -#define TCA_FQ_MAX (__TCA_FQ_MAX - 1) - -struct tc_fq_qd_stats { - __u64 gc_flows; - __u64 highprio_packets; - __u64 tcp_retrans; - __u64 throttled; - __u64 flows_plimit; - __u64 pkts_too_long; - __u64 allocation_errors; - __s64 time_next_delayed_flow; - __u32 flows; - __u32 inactive_flows; - __u32 throttled_flows; - __u32 unthrottle_latency_ns; -}; - -/* Heavy-Hitter Filter */ - -enum { - TCA_HHF_UNSPEC, - TCA_HHF_BACKLOG_LIMIT, - TCA_HHF_QUANTUM, - TCA_HHF_HH_FLOWS_LIMIT, - TCA_HHF_RESET_TIMEOUT, - TCA_HHF_ADMIT_BYTES, - TCA_HHF_EVICT_TIMEOUT, - TCA_HHF_NON_HH_WEIGHT, - __TCA_HHF_MAX -}; - -#define TCA_HHF_MAX (__TCA_HHF_MAX - 1) - -struct tc_hhf_xstats { - __u32 drop_overlimit; /* number of times max qdisc packet limit - * was hit - */ - __u32 hh_overlimit; /* number of times max heavy-hitters was hit */ - __u32 hh_tot_count; /* number of captured heavy-hitters so far */ - __u32 hh_cur_count; /* number of current heavy-hitters */ -}; - -/* PIE */ -enum { - TCA_PIE_UNSPEC, - TCA_PIE_TARGET, - TCA_PIE_LIMIT, - TCA_PIE_TUPDATE, - TCA_PIE_ALPHA, - TCA_PIE_BETA, - TCA_PIE_ECN, - TCA_PIE_BYTEMODE, - __TCA_PIE_MAX -}; -#define TCA_PIE_MAX (__TCA_PIE_MAX - 1) - -struct tc_pie_xstats { - __u32 prob; /* current probability */ - __u32 delay; /* current delay in ms */ - __u32 avg_dq_rate; /* current average dq_rate in bits/pie_time */ - __u32 packets_in; /* total number of packets enqueued */ - __u32 dropped; /* packets dropped due to pie_action */ - __u32 overlimit; /* dropped due to lack of space in queue */ - __u32 maxq; /* maximum queue size */ - __u32 ecn_mark; /* packets marked with ecn*/ -}; -#endif diff --git a/src/linux/include/uapi/linux/poll.h b/src/linux/include/uapi/linux/poll.h deleted file mode 100644 index 2001fed..0000000 --- a/src/linux/include/uapi/linux/poll.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/src/linux/include/uapi/linux/posix_acl.h b/src/linux/include/uapi/linux/posix_acl.h deleted file mode 100644 index 1037cb1..0000000 --- a/src/linux/include/uapi/linux/posix_acl.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (C) 2002 Andreas Gruenbacher - * Copyright (C) 2016 Red Hat, Inc. - * - * This file is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - */ - -#ifndef __UAPI_POSIX_ACL_H -#define __UAPI_POSIX_ACL_H - -#define ACL_UNDEFINED_ID (-1) - -/* a_type field in acl_user_posix_entry_t */ -#define ACL_TYPE_ACCESS (0x8000) -#define ACL_TYPE_DEFAULT (0x4000) - -/* e_tag entry in struct posix_acl_entry */ -#define ACL_USER_OBJ (0x01) -#define ACL_USER (0x02) -#define ACL_GROUP_OBJ (0x04) -#define ACL_GROUP (0x08) -#define ACL_MASK (0x10) -#define ACL_OTHER (0x20) - -/* permissions in the e_perm field */ -#define ACL_READ (0x04) -#define ACL_WRITE (0x02) -#define ACL_EXECUTE (0x01) - -#endif /* __UAPI_POSIX_ACL_H */ diff --git a/src/linux/include/uapi/linux/posix_acl_xattr.h b/src/linux/include/uapi/linux/posix_acl_xattr.h deleted file mode 100644 index 8b57984..0000000 --- a/src/linux/include/uapi/linux/posix_acl_xattr.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2002 Andreas Gruenbacher - * Copyright (C) 2016 Red Hat, Inc. - * - * This file is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This file is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - */ - -#ifndef __UAPI_POSIX_ACL_XATTR_H -#define __UAPI_POSIX_ACL_XATTR_H - -#include - -/* Supported ACL a_version fields */ -#define POSIX_ACL_XATTR_VERSION 0x0002 - -/* An undefined entry e_id value */ -#define ACL_UNDEFINED_ID (-1) - -struct posix_acl_xattr_entry { - __le16 e_tag; - __le16 e_perm; - __le32 e_id; -}; - -struct posix_acl_xattr_header { - __le32 a_version; -}; - -#endif /* __UAPI_POSIX_ACL_XATTR_H */ diff --git a/src/linux/include/uapi/linux/posix_types.h b/src/linux/include/uapi/linux/posix_types.h deleted file mode 100644 index 988f76e..0000000 --- a/src/linux/include/uapi/linux/posix_types.h +++ /dev/null @@ -1,37 +0,0 @@ -#ifndef _LINUX_POSIX_TYPES_H -#define _LINUX_POSIX_TYPES_H - -#include - -/* - * This allows for 1024 file descriptors: if NR_OPEN is ever grown - * beyond that you'll have to change this too. But 1024 fd's seem to be - * enough even for such "real" unices like OSF/1, so hopefully this is - * one limit that doesn't have to be changed [again]. - * - * Note that POSIX wants the FD_CLEAR(fd,fdsetp) defines to be in - * (and thus ) - but this is a more logical - * place for them. Solved by having dummy defines in . - */ - -/* - * This macro may have been defined in . But we always - * use the one here. - */ -#undef __FD_SETSIZE -#define __FD_SETSIZE 1024 - -typedef struct { - unsigned long fds_bits[__FD_SETSIZE / (8 * sizeof(long))]; -} __kernel_fd_set; - -/* Type of a signal handler. */ -typedef void (*__kernel_sighandler_t)(int); - -/* Type of a SYSV IPC key. */ -typedef int __kernel_key_t; -typedef int __kernel_mqd_t; - -#include - -#endif /* _LINUX_POSIX_TYPES_H */ diff --git a/src/linux/include/uapi/linux/ppp_defs.h b/src/linux/include/uapi/linux/ppp_defs.h deleted file mode 100644 index 283fc05..0000000 --- a/src/linux/include/uapi/linux/ppp_defs.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - * ppp_defs.h - PPP definitions. - * - * Copyright 1994-2000 Paul Mackerras. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - */ -#include - -#ifndef _UAPI_PPP_DEFS_H_ -#define _UAPI_PPP_DEFS_H_ - -/* - * The basic PPP frame. - */ -#define PPP_HDRLEN 4 /* octets for standard ppp header */ -#define PPP_FCSLEN 2 /* octets for FCS */ -#define PPP_MRU 1500 /* default MRU = max length of info field */ - -#define PPP_ADDRESS(p) (((__u8 *)(p))[0]) -#define PPP_CONTROL(p) (((__u8 *)(p))[1]) -#define PPP_PROTOCOL(p) ((((__u8 *)(p))[2] << 8) + ((__u8 *)(p))[3]) - -/* - * Significant octet values. - */ -#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ -#define PPP_UI 0x03 /* Unnumbered Information */ -#define PPP_FLAG 0x7e /* Flag Sequence */ -#define PPP_ESCAPE 0x7d /* Asynchronous Control Escape */ -#define PPP_TRANS 0x20 /* Asynchronous transparency modifier */ - -/* - * Protocol field values. - */ -#define PPP_IP 0x21 /* Internet Protocol */ -#define PPP_AT 0x29 /* AppleTalk Protocol */ -#define PPP_IPX 0x2b /* IPX protocol */ -#define PPP_VJC_COMP 0x2d /* VJ compressed TCP */ -#define PPP_VJC_UNCOMP 0x2f /* VJ uncompressed TCP */ -#define PPP_MP 0x3d /* Multilink protocol */ -#define PPP_IPV6 0x57 /* Internet Protocol Version 6 */ -#define PPP_COMPFRAG 0xfb /* fragment compressed below bundle */ -#define PPP_COMP 0xfd /* compressed packet */ -#define PPP_MPLS_UC 0x0281 /* Multi Protocol Label Switching - Unicast */ -#define PPP_MPLS_MC 0x0283 /* Multi Protocol Label Switching - Multicast */ -#define PPP_IPCP 0x8021 /* IP Control Protocol */ -#define PPP_ATCP 0x8029 /* AppleTalk Control Protocol */ -#define PPP_IPXCP 0x802b /* IPX Control Protocol */ -#define PPP_IPV6CP 0x8057 /* IPv6 Control Protocol */ -#define PPP_CCPFRAG 0x80fb /* CCP at link level (below MP bundle) */ -#define PPP_CCP 0x80fd /* Compression Control Protocol */ -#define PPP_MPLSCP 0x80fd /* MPLS Control Protocol */ -#define PPP_LCP 0xc021 /* Link Control Protocol */ -#define PPP_PAP 0xc023 /* Password Authentication Protocol */ -#define PPP_LQR 0xc025 /* Link Quality Report protocol */ -#define PPP_CHAP 0xc223 /* Cryptographic Handshake Auth. Protocol */ -#define PPP_CBCP 0xc029 /* Callback Control Protocol */ - -/* - * Values for FCS calculations. - */ - -#define PPP_INITFCS 0xffff /* Initial FCS value */ -#define PPP_GOODFCS 0xf0b8 /* Good final FCS value */ - - -/* - * Extended asyncmap - allows any character to be escaped. - */ - -typedef __u32 ext_accm[8]; - -/* - * What to do with network protocol (NP) packets. - */ -enum NPmode { - NPMODE_PASS, /* pass the packet through */ - NPMODE_DROP, /* silently drop the packet */ - NPMODE_ERROR, /* return an error */ - NPMODE_QUEUE /* save it up for later. */ -}; - -/* - * Statistics for LQRP and pppstats - */ -struct pppstat { - __u32 ppp_discards; /* # frames discarded */ - - __u32 ppp_ibytes; /* bytes received */ - __u32 ppp_ioctects; /* bytes received not in error */ - __u32 ppp_ipackets; /* packets received */ - __u32 ppp_ierrors; /* receive errors */ - __u32 ppp_ilqrs; /* # LQR frames received */ - - __u32 ppp_obytes; /* raw bytes sent */ - __u32 ppp_ooctects; /* frame bytes sent */ - __u32 ppp_opackets; /* packets sent */ - __u32 ppp_oerrors; /* transmit errors */ - __u32 ppp_olqrs; /* # LQR frames sent */ -}; - -struct vjstat { - __u32 vjs_packets; /* outbound packets */ - __u32 vjs_compressed; /* outbound compressed packets */ - __u32 vjs_searches; /* searches for connection state */ - __u32 vjs_misses; /* times couldn't find conn. state */ - __u32 vjs_uncompressedin; /* inbound uncompressed packets */ - __u32 vjs_compressedin; /* inbound compressed packets */ - __u32 vjs_errorin; /* inbound unknown type packets */ - __u32 vjs_tossed; /* inbound packets tossed because of error */ -}; - -struct compstat { - __u32 unc_bytes; /* total uncompressed bytes */ - __u32 unc_packets; /* total uncompressed packets */ - __u32 comp_bytes; /* compressed bytes */ - __u32 comp_packets; /* compressed packets */ - __u32 inc_bytes; /* incompressible bytes */ - __u32 inc_packets; /* incompressible packets */ - - /* the compression ratio is defined as in_count / bytes_out */ - __u32 in_count; /* Bytes received */ - __u32 bytes_out; /* Bytes transmitted */ - - double ratio; /* not computed in kernel. */ -}; - -struct ppp_stats { - struct pppstat p; /* basic PPP statistics */ - struct vjstat vj; /* VJ header compression statistics */ -}; - -struct ppp_comp_stats { - struct compstat c; /* packet compression statistics */ - struct compstat d; /* packet decompression statistics */ -}; - -/* - * The following structure records the time in seconds since - * the last NP packet was sent or received. - */ -struct ppp_idle { - __kernel_time_t xmit_idle; /* time since last NP packet sent */ - __kernel_time_t recv_idle; /* time since last NP packet received */ -}; - -#endif /* _UAPI_PPP_DEFS_H_ */ diff --git a/src/linux/include/uapi/linux/pr.h b/src/linux/include/uapi/linux/pr.h deleted file mode 100644 index 57d7c0f..0000000 --- a/src/linux/include/uapi/linux/pr.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef _UAPI_PR_H -#define _UAPI_PR_H - -enum pr_type { - PR_WRITE_EXCLUSIVE = 1, - PR_EXCLUSIVE_ACCESS = 2, - PR_WRITE_EXCLUSIVE_REG_ONLY = 3, - PR_EXCLUSIVE_ACCESS_REG_ONLY = 4, - PR_WRITE_EXCLUSIVE_ALL_REGS = 5, - PR_EXCLUSIVE_ACCESS_ALL_REGS = 6, -}; - -struct pr_reservation { - __u64 key; - __u32 type; - __u32 flags; -}; - -struct pr_registration { - __u64 old_key; - __u64 new_key; - __u32 flags; - __u32 __pad; -}; - -struct pr_preempt { - __u64 old_key; - __u64 new_key; - __u32 type; - __u32 flags; -}; - -struct pr_clear { - __u64 key; - __u32 flags; - __u32 __pad; -}; - -#define PR_FL_IGNORE_KEY (1 << 0) /* ignore existing key */ - -#define IOC_PR_REGISTER _IOW('p', 200, struct pr_registration) -#define IOC_PR_RESERVE _IOW('p', 201, struct pr_reservation) -#define IOC_PR_RELEASE _IOW('p', 202, struct pr_reservation) -#define IOC_PR_PREEMPT _IOW('p', 203, struct pr_preempt) -#define IOC_PR_PREEMPT_ABORT _IOW('p', 204, struct pr_preempt) -#define IOC_PR_CLEAR _IOW('p', 205, struct pr_clear) - -#endif /* _UAPI_PR_H */ diff --git a/src/linux/include/uapi/linux/prctl.h b/src/linux/include/uapi/linux/prctl.h deleted file mode 100644 index a8d0759..0000000 --- a/src/linux/include/uapi/linux/prctl.h +++ /dev/null @@ -1,200 +0,0 @@ -#ifndef _LINUX_PRCTL_H -#define _LINUX_PRCTL_H - -#include - -/* Values to pass as first argument to prctl() */ - -#define PR_SET_PDEATHSIG 1 /* Second arg is a signal */ -#define PR_GET_PDEATHSIG 2 /* Second arg is a ptr to return the signal */ - -/* Get/set current->mm->dumpable */ -#define PR_GET_DUMPABLE 3 -#define PR_SET_DUMPABLE 4 - -/* Get/set unaligned access control bits (if meaningful) */ -#define PR_GET_UNALIGN 5 -#define PR_SET_UNALIGN 6 -# define PR_UNALIGN_NOPRINT 1 /* silently fix up unaligned user accesses */ -# define PR_UNALIGN_SIGBUS 2 /* generate SIGBUS on unaligned user access */ - -/* Get/set whether or not to drop capabilities on setuid() away from - * uid 0 (as per security/commoncap.c) */ -#define PR_GET_KEEPCAPS 7 -#define PR_SET_KEEPCAPS 8 - -/* Get/set floating-point emulation control bits (if meaningful) */ -#define PR_GET_FPEMU 9 -#define PR_SET_FPEMU 10 -# define PR_FPEMU_NOPRINT 1 /* silently emulate fp operations accesses */ -# define PR_FPEMU_SIGFPE 2 /* don't emulate fp operations, send SIGFPE instead */ - -/* Get/set floating-point exception mode (if meaningful) */ -#define PR_GET_FPEXC 11 -#define PR_SET_FPEXC 12 -# define PR_FP_EXC_SW_ENABLE 0x80 /* Use FPEXC for FP exception enables */ -# define PR_FP_EXC_DIV 0x010000 /* floating point divide by zero */ -# define PR_FP_EXC_OVF 0x020000 /* floating point overflow */ -# define PR_FP_EXC_UND 0x040000 /* floating point underflow */ -# define PR_FP_EXC_RES 0x080000 /* floating point inexact result */ -# define PR_FP_EXC_INV 0x100000 /* floating point invalid operation */ -# define PR_FP_EXC_DISABLED 0 /* FP exceptions disabled */ -# define PR_FP_EXC_NONRECOV 1 /* async non-recoverable exc. mode */ -# define PR_FP_EXC_ASYNC 2 /* async recoverable exception mode */ -# define PR_FP_EXC_PRECISE 3 /* precise exception mode */ - -/* Get/set whether we use statistical process timing or accurate timestamp - * based process timing */ -#define PR_GET_TIMING 13 -#define PR_SET_TIMING 14 -# define PR_TIMING_STATISTICAL 0 /* Normal, traditional, - statistical process timing */ -# define PR_TIMING_TIMESTAMP 1 /* Accurate timestamp based - process timing */ - -#define PR_SET_NAME 15 /* Set process name */ -#define PR_GET_NAME 16 /* Get process name */ - -/* Get/set process endian */ -#define PR_GET_ENDIAN 19 -#define PR_SET_ENDIAN 20 -# define PR_ENDIAN_BIG 0 -# define PR_ENDIAN_LITTLE 1 /* True little endian mode */ -# define PR_ENDIAN_PPC_LITTLE 2 /* "PowerPC" pseudo little endian */ - -/* Get/set process seccomp mode */ -#define PR_GET_SECCOMP 21 -#define PR_SET_SECCOMP 22 - -/* Get/set the capability bounding set (as per security/commoncap.c) */ -#define PR_CAPBSET_READ 23 -#define PR_CAPBSET_DROP 24 - -/* Get/set the process' ability to use the timestamp counter instruction */ -#define PR_GET_TSC 25 -#define PR_SET_TSC 26 -# define PR_TSC_ENABLE 1 /* allow the use of the timestamp counter */ -# define PR_TSC_SIGSEGV 2 /* throw a SIGSEGV instead of reading the TSC */ - -/* Get/set securebits (as per security/commoncap.c) */ -#define PR_GET_SECUREBITS 27 -#define PR_SET_SECUREBITS 28 - -/* - * Get/set the timerslack as used by poll/select/nanosleep - * A value of 0 means "use default" - */ -#define PR_SET_TIMERSLACK 29 -#define PR_GET_TIMERSLACK 30 - -#define PR_TASK_PERF_EVENTS_DISABLE 31 -#define PR_TASK_PERF_EVENTS_ENABLE 32 - -/* - * Set early/late kill mode for hwpoison memory corruption. - * This influences when the process gets killed on a memory corruption. - */ -#define PR_MCE_KILL 33 -# define PR_MCE_KILL_CLEAR 0 -# define PR_MCE_KILL_SET 1 - -# define PR_MCE_KILL_LATE 0 -# define PR_MCE_KILL_EARLY 1 -# define PR_MCE_KILL_DEFAULT 2 - -#define PR_MCE_KILL_GET 34 - -/* - * Tune up process memory map specifics. - */ -#define PR_SET_MM 35 -# define PR_SET_MM_START_CODE 1 -# define PR_SET_MM_END_CODE 2 -# define PR_SET_MM_START_DATA 3 -# define PR_SET_MM_END_DATA 4 -# define PR_SET_MM_START_STACK 5 -# define PR_SET_MM_START_BRK 6 -# define PR_SET_MM_BRK 7 -# define PR_SET_MM_ARG_START 8 -# define PR_SET_MM_ARG_END 9 -# define PR_SET_MM_ENV_START 10 -# define PR_SET_MM_ENV_END 11 -# define PR_SET_MM_AUXV 12 -# define PR_SET_MM_EXE_FILE 13 -# define PR_SET_MM_MAP 14 -# define PR_SET_MM_MAP_SIZE 15 - -/* - * This structure provides new memory descriptor - * map which mostly modifies /proc/pid/stat[m] - * output for a task. This mostly done in a - * sake of checkpoint/restore functionality. - */ -struct prctl_mm_map { - __u64 start_code; /* code section bounds */ - __u64 end_code; - __u64 start_data; /* data section bounds */ - __u64 end_data; - __u64 start_brk; /* heap for brk() syscall */ - __u64 brk; - __u64 start_stack; /* stack starts at */ - __u64 arg_start; /* command line arguments bounds */ - __u64 arg_end; - __u64 env_start; /* environment variables bounds */ - __u64 env_end; - __u64 *auxv; /* auxiliary vector */ - __u32 auxv_size; /* vector size */ - __u32 exe_fd; /* /proc/$pid/exe link file */ -}; - -/* - * Set specific pid that is allowed to ptrace the current task. - * A value of 0 mean "no process". - */ -#define PR_SET_PTRACER 0x59616d61 -# define PR_SET_PTRACER_ANY ((unsigned long)-1) - -#define PR_SET_CHILD_SUBREAPER 36 -#define PR_GET_CHILD_SUBREAPER 37 - -/* - * If no_new_privs is set, then operations that grant new privileges (i.e. - * execve) will either fail or not grant them. This affects suid/sgid, - * file capabilities, and LSMs. - * - * Operations that merely manipulate or drop existing privileges (setresuid, - * capset, etc.) will still work. Drop those privileges if you want them gone. - * - * Changing LSM security domain is considered a new privilege. So, for example, - * asking selinux for a specific new context (e.g. with runcon) will result - * in execve returning -EPERM. - * - * See Documentation/prctl/no_new_privs.txt for more details. - */ -#define PR_SET_NO_NEW_PRIVS 38 -#define PR_GET_NO_NEW_PRIVS 39 - -#define PR_GET_TID_ADDRESS 40 - -#define PR_SET_THP_DISABLE 41 -#define PR_GET_THP_DISABLE 42 - -/* - * Tell the kernel to start/stop helping userspace manage bounds tables. - */ -#define PR_MPX_ENABLE_MANAGEMENT 43 -#define PR_MPX_DISABLE_MANAGEMENT 44 - -#define PR_SET_FP_MODE 45 -#define PR_GET_FP_MODE 46 -# define PR_FP_MODE_FR (1 << 0) /* 64b FP registers */ -# define PR_FP_MODE_FRE (1 << 1) /* 32b compatibility */ - -/* Control the ambient capability set */ -#define PR_CAP_AMBIENT 47 -# define PR_CAP_AMBIENT_IS_SET 1 -# define PR_CAP_AMBIENT_RAISE 2 -# define PR_CAP_AMBIENT_LOWER 3 -# define PR_CAP_AMBIENT_CLEAR_ALL 4 - -#endif /* _LINUX_PRCTL_H */ diff --git a/src/linux/include/uapi/linux/ptrace.h b/src/linux/include/uapi/linux/ptrace.h deleted file mode 100644 index fb81065..0000000 --- a/src/linux/include/uapi/linux/ptrace.h +++ /dev/null @@ -1,103 +0,0 @@ -#ifndef _UAPI_LINUX_PTRACE_H -#define _UAPI_LINUX_PTRACE_H -/* ptrace.h */ -/* structs and defines to help the user use the ptrace system call. */ - -/* has the defines to get at the registers. */ - -#include - -#define PTRACE_TRACEME 0 -#define PTRACE_PEEKTEXT 1 -#define PTRACE_PEEKDATA 2 -#define PTRACE_PEEKUSR 3 -#define PTRACE_POKETEXT 4 -#define PTRACE_POKEDATA 5 -#define PTRACE_POKEUSR 6 -#define PTRACE_CONT 7 -#define PTRACE_KILL 8 -#define PTRACE_SINGLESTEP 9 - -#define PTRACE_ATTACH 16 -#define PTRACE_DETACH 17 - -#define PTRACE_SYSCALL 24 - -/* 0x4200-0x4300 are reserved for architecture-independent additions. */ -#define PTRACE_SETOPTIONS 0x4200 -#define PTRACE_GETEVENTMSG 0x4201 -#define PTRACE_GETSIGINFO 0x4202 -#define PTRACE_SETSIGINFO 0x4203 - -/* - * Generic ptrace interface that exports the architecture specific regsets - * using the corresponding NT_* types (which are also used in the core dump). - * Please note that the NT_PRSTATUS note type in a core dump contains a full - * 'struct elf_prstatus'. But the user_regset for NT_PRSTATUS contains just the - * elf_gregset_t that is the pr_reg field of 'struct elf_prstatus'. For all the - * other user_regset flavors, the user_regset layout and the ELF core dump note - * payload are exactly the same layout. - * - * This interface usage is as follows: - * struct iovec iov = { buf, len}; - * - * ret = ptrace(PTRACE_GETREGSET/PTRACE_SETREGSET, pid, NT_XXX_TYPE, &iov); - * - * On the successful completion, iov.len will be updated by the kernel, - * specifying how much the kernel has written/read to/from the user's iov.buf. - */ -#define PTRACE_GETREGSET 0x4204 -#define PTRACE_SETREGSET 0x4205 - -#define PTRACE_SEIZE 0x4206 -#define PTRACE_INTERRUPT 0x4207 -#define PTRACE_LISTEN 0x4208 - -#define PTRACE_PEEKSIGINFO 0x4209 - -struct ptrace_peeksiginfo_args { - __u64 off; /* from which siginfo to start */ - __u32 flags; - __s32 nr; /* how may siginfos to take */ -}; - -#define PTRACE_GETSIGMASK 0x420a -#define PTRACE_SETSIGMASK 0x420b - -#define PTRACE_SECCOMP_GET_FILTER 0x420c - -/* Read signals from a shared (process wide) queue */ -#define PTRACE_PEEKSIGINFO_SHARED (1 << 0) - -/* Wait extended result codes for the above trace options. */ -#define PTRACE_EVENT_FORK 1 -#define PTRACE_EVENT_VFORK 2 -#define PTRACE_EVENT_CLONE 3 -#define PTRACE_EVENT_EXEC 4 -#define PTRACE_EVENT_VFORK_DONE 5 -#define PTRACE_EVENT_EXIT 6 -#define PTRACE_EVENT_SECCOMP 7 -/* Extended result codes which enabled by means other than options. */ -#define PTRACE_EVENT_STOP 128 - -/* Options set using PTRACE_SETOPTIONS or using PTRACE_SEIZE @data param */ -#define PTRACE_O_TRACESYSGOOD 1 -#define PTRACE_O_TRACEFORK (1 << PTRACE_EVENT_FORK) -#define PTRACE_O_TRACEVFORK (1 << PTRACE_EVENT_VFORK) -#define PTRACE_O_TRACECLONE (1 << PTRACE_EVENT_CLONE) -#define PTRACE_O_TRACEEXEC (1 << PTRACE_EVENT_EXEC) -#define PTRACE_O_TRACEVFORKDONE (1 << PTRACE_EVENT_VFORK_DONE) -#define PTRACE_O_TRACEEXIT (1 << PTRACE_EVENT_EXIT) -#define PTRACE_O_TRACESECCOMP (1 << PTRACE_EVENT_SECCOMP) - -/* eventless options */ -#define PTRACE_O_EXITKILL (1 << 20) -#define PTRACE_O_SUSPEND_SECCOMP (1 << 21) - -#define PTRACE_O_MASK (\ - 0x000000ff | PTRACE_O_EXITKILL | PTRACE_O_SUSPEND_SECCOMP) - -#include - - -#endif /* _UAPI_LINUX_PTRACE_H */ diff --git a/src/linux/include/uapi/linux/quota.h b/src/linux/include/uapi/linux/quota.h deleted file mode 100644 index 4d2489e..0000000 --- a/src/linux/include/uapi/linux/quota.h +++ /dev/null @@ -1,200 +0,0 @@ -/* - * Copyright (c) 1982, 1986 Regents of the University of California. - * All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Robert Elz at The University of Melbourne. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _UAPI_LINUX_QUOTA_ -#define _UAPI_LINUX_QUOTA_ - -#include -#include - -#define __DQUOT_VERSION__ "dquot_6.6.0" - -#define MAXQUOTAS 3 -#define USRQUOTA 0 /* element used for user quotas */ -#define GRPQUOTA 1 /* element used for group quotas */ -#define PRJQUOTA 2 /* element used for project quotas */ - -/* - * Definitions for the default names of the quotas files. - */ -#define INITQFNAMES { \ - "user", /* USRQUOTA */ \ - "group", /* GRPQUOTA */ \ - "project", /* PRJQUOTA */ \ - "undefined", \ -}; - -/* - * Command definitions for the 'quotactl' system call. - * The commands are broken into a main command defined below - * and a subcommand that is used to convey the type of - * quota that is being manipulated (see above). - */ -#define SUBCMDMASK 0x00ff -#define SUBCMDSHIFT 8 -#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK)) - -#define Q_SYNC 0x800001 /* sync disk copy of a filesystems quotas */ -#define Q_QUOTAON 0x800002 /* turn quotas on */ -#define Q_QUOTAOFF 0x800003 /* turn quotas off */ -#define Q_GETFMT 0x800004 /* get quota format used on given filesystem */ -#define Q_GETINFO 0x800005 /* get information about quota files */ -#define Q_SETINFO 0x800006 /* set information about quota files */ -#define Q_GETQUOTA 0x800007 /* get user quota structure */ -#define Q_SETQUOTA 0x800008 /* set user quota structure */ -#define Q_GETNEXTQUOTA 0x800009 /* get disk limits and usage >= ID */ - -/* Quota format type IDs */ -#define QFMT_VFS_OLD 1 -#define QFMT_VFS_V0 2 -#define QFMT_OCFS2 3 -#define QFMT_VFS_V1 4 - -/* Size of block in which space limits are passed through the quota - * interface */ -#define QIF_DQBLKSIZE_BITS 10 -#define QIF_DQBLKSIZE (1 << QIF_DQBLKSIZE_BITS) - -/* - * Quota structure used for communication with userspace via quotactl - * Following flags are used to specify which fields are valid - */ -enum { - QIF_BLIMITS_B = 0, - QIF_SPACE_B, - QIF_ILIMITS_B, - QIF_INODES_B, - QIF_BTIME_B, - QIF_ITIME_B, -}; - -#define QIF_BLIMITS (1 << QIF_BLIMITS_B) -#define QIF_SPACE (1 << QIF_SPACE_B) -#define QIF_ILIMITS (1 << QIF_ILIMITS_B) -#define QIF_INODES (1 << QIF_INODES_B) -#define QIF_BTIME (1 << QIF_BTIME_B) -#define QIF_ITIME (1 << QIF_ITIME_B) -#define QIF_LIMITS (QIF_BLIMITS | QIF_ILIMITS) -#define QIF_USAGE (QIF_SPACE | QIF_INODES) -#define QIF_TIMES (QIF_BTIME | QIF_ITIME) -#define QIF_ALL (QIF_LIMITS | QIF_USAGE | QIF_TIMES) - -struct if_dqblk { - __u64 dqb_bhardlimit; - __u64 dqb_bsoftlimit; - __u64 dqb_curspace; - __u64 dqb_ihardlimit; - __u64 dqb_isoftlimit; - __u64 dqb_curinodes; - __u64 dqb_btime; - __u64 dqb_itime; - __u32 dqb_valid; -}; - -struct if_nextdqblk { - __u64 dqb_bhardlimit; - __u64 dqb_bsoftlimit; - __u64 dqb_curspace; - __u64 dqb_ihardlimit; - __u64 dqb_isoftlimit; - __u64 dqb_curinodes; - __u64 dqb_btime; - __u64 dqb_itime; - __u32 dqb_valid; - __u32 dqb_id; -}; - -/* - * Structure used for setting quota information about file via quotactl - * Following flags are used to specify which fields are valid - */ -#define IIF_BGRACE 1 -#define IIF_IGRACE 2 -#define IIF_FLAGS 4 -#define IIF_ALL (IIF_BGRACE | IIF_IGRACE | IIF_FLAGS) - -enum { - DQF_ROOT_SQUASH_B = 0, - DQF_SYS_FILE_B = 16, - /* Kernel internal flags invisible to userspace */ - DQF_PRIVATE -}; - -/* Root squash enabled (for v1 quota format) */ -#define DQF_ROOT_SQUASH (1 << DQF_ROOT_SQUASH_B) -/* Quota stored in a system file */ -#define DQF_SYS_FILE (1 << DQF_SYS_FILE_B) - -struct if_dqinfo { - __u64 dqi_bgrace; - __u64 dqi_igrace; - __u32 dqi_flags; /* DFQ_* */ - __u32 dqi_valid; -}; - -/* - * Definitions for quota netlink interface - */ -#define QUOTA_NL_NOWARN 0 -#define QUOTA_NL_IHARDWARN 1 /* Inode hardlimit reached */ -#define QUOTA_NL_ISOFTLONGWARN 2 /* Inode grace time expired */ -#define QUOTA_NL_ISOFTWARN 3 /* Inode softlimit reached */ -#define QUOTA_NL_BHARDWARN 4 /* Block hardlimit reached */ -#define QUOTA_NL_BSOFTLONGWARN 5 /* Block grace time expired */ -#define QUOTA_NL_BSOFTWARN 6 /* Block softlimit reached */ -#define QUOTA_NL_IHARDBELOW 7 /* Usage got below inode hardlimit */ -#define QUOTA_NL_ISOFTBELOW 8 /* Usage got below inode softlimit */ -#define QUOTA_NL_BHARDBELOW 9 /* Usage got below block hardlimit */ -#define QUOTA_NL_BSOFTBELOW 10 /* Usage got below block softlimit */ - -enum { - QUOTA_NL_C_UNSPEC, - QUOTA_NL_C_WARNING, - __QUOTA_NL_C_MAX, -}; -#define QUOTA_NL_C_MAX (__QUOTA_NL_C_MAX - 1) - -enum { - QUOTA_NL_A_UNSPEC, - QUOTA_NL_A_QTYPE, - QUOTA_NL_A_EXCESS_ID, - QUOTA_NL_A_WARNING, - QUOTA_NL_A_DEV_MAJOR, - QUOTA_NL_A_DEV_MINOR, - QUOTA_NL_A_CAUSED_ID, - QUOTA_NL_A_PAD, - __QUOTA_NL_A_MAX, -}; -#define QUOTA_NL_A_MAX (__QUOTA_NL_A_MAX - 1) - - -#endif /* _UAPI_LINUX_QUOTA_ */ diff --git a/src/linux/include/uapi/linux/random.h b/src/linux/include/uapi/linux/random.h deleted file mode 100644 index 3f93d16..0000000 --- a/src/linux/include/uapi/linux/random.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * include/linux/random.h - * - * Include file for the random number generator. - */ - -#ifndef _UAPI_LINUX_RANDOM_H -#define _UAPI_LINUX_RANDOM_H - -#include -#include -#include - -/* ioctl()'s for the random number generator */ - -/* Get the entropy count. */ -#define RNDGETENTCNT _IOR( 'R', 0x00, int ) - -/* Add to (or subtract from) the entropy count. (Superuser only.) */ -#define RNDADDTOENTCNT _IOW( 'R', 0x01, int ) - -/* Get the contents of the entropy pool. (Superuser only.) */ -#define RNDGETPOOL _IOR( 'R', 0x02, int [2] ) - -/* - * Write bytes into the entropy pool and add to the entropy count. - * (Superuser only.) - */ -#define RNDADDENTROPY _IOW( 'R', 0x03, int [2] ) - -/* Clear entropy count to 0. (Superuser only.) */ -#define RNDZAPENTCNT _IO( 'R', 0x04 ) - -/* Clear the entropy pool and associated counters. (Superuser only.) */ -#define RNDCLEARPOOL _IO( 'R', 0x06 ) - -struct rand_pool_info { - int entropy_count; - int buf_size; - __u32 buf[0]; -}; - -/* - * Flags for getrandom(2) - * - * GRND_NONBLOCK Don't block and return EAGAIN instead - * GRND_RANDOM Use the /dev/random pool instead of /dev/urandom - */ -#define GRND_NONBLOCK 0x0001 -#define GRND_RANDOM 0x0002 - -#endif /* _UAPI_LINUX_RANDOM_H */ diff --git a/src/linux/include/uapi/linux/raw.h b/src/linux/include/uapi/linux/raw.h deleted file mode 100644 index 62d543e..0000000 --- a/src/linux/include/uapi/linux/raw.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef __LINUX_RAW_H -#define __LINUX_RAW_H - -#include - -#define RAW_SETBIND _IO( 0xac, 0 ) -#define RAW_GETBIND _IO( 0xac, 1 ) - -struct raw_config_request -{ - int raw_minor; - __u64 block_major; - __u64 block_minor; -}; - -#define MAX_RAW_MINORS CONFIG_MAX_RAW_DEVS - -#endif /* __LINUX_RAW_H */ diff --git a/src/linux/include/uapi/linux/reboot.h b/src/linux/include/uapi/linux/reboot.h deleted file mode 100644 index 09d056d..0000000 --- a/src/linux/include/uapi/linux/reboot.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _UAPI_LINUX_REBOOT_H -#define _UAPI_LINUX_REBOOT_H - -/* - * Magic values required to use _reboot() system call. - */ - -#define LINUX_REBOOT_MAGIC1 0xfee1dead -#define LINUX_REBOOT_MAGIC2 672274793 -#define LINUX_REBOOT_MAGIC2A 85072278 -#define LINUX_REBOOT_MAGIC2B 369367448 -#define LINUX_REBOOT_MAGIC2C 537993216 - - -/* - * Commands accepted by the _reboot() system call. - * - * RESTART Restart system using default command and mode. - * HALT Stop OS and give system control to ROM monitor, if any. - * CAD_ON Ctrl-Alt-Del sequence causes RESTART command. - * CAD_OFF Ctrl-Alt-Del sequence sends SIGINT to init task. - * POWER_OFF Stop OS and remove all power from system, if possible. - * RESTART2 Restart system using given command string. - * SW_SUSPEND Suspend system using software suspend if compiled in. - * KEXEC Restart system using a previously loaded Linux kernel - */ - -#define LINUX_REBOOT_CMD_RESTART 0x01234567 -#define LINUX_REBOOT_CMD_HALT 0xCDEF0123 -#define LINUX_REBOOT_CMD_CAD_ON 0x89ABCDEF -#define LINUX_REBOOT_CMD_CAD_OFF 0x00000000 -#define LINUX_REBOOT_CMD_POWER_OFF 0x4321FEDC -#define LINUX_REBOOT_CMD_RESTART2 0xA1B2C3D4 -#define LINUX_REBOOT_CMD_SW_SUSPEND 0xD000FCE2 -#define LINUX_REBOOT_CMD_KEXEC 0x45584543 - - - -#endif /* _UAPI_LINUX_REBOOT_H */ diff --git a/src/linux/include/uapi/linux/resource.h b/src/linux/include/uapi/linux/resource.h deleted file mode 100644 index 36fb3b5..0000000 --- a/src/linux/include/uapi/linux/resource.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef _UAPI_LINUX_RESOURCE_H -#define _UAPI_LINUX_RESOURCE_H - -#include -#include - -/* - * Resource control/accounting header file for linux - */ - -/* - * Definition of struct rusage taken from BSD 4.3 Reno - * - * We don't support all of these yet, but we might as well have them.... - * Otherwise, each time we add new items, programs which depend on this - * structure will lose. This reduces the chances of that happening. - */ -#define RUSAGE_SELF 0 -#define RUSAGE_CHILDREN (-1) -#define RUSAGE_BOTH (-2) /* sys_wait4() uses this */ -#define RUSAGE_THREAD 1 /* only the calling thread */ - -struct rusage { - struct timeval ru_utime; /* user time used */ - struct timeval ru_stime; /* system time used */ - __kernel_long_t ru_maxrss; /* maximum resident set size */ - __kernel_long_t ru_ixrss; /* integral shared memory size */ - __kernel_long_t ru_idrss; /* integral unshared data size */ - __kernel_long_t ru_isrss; /* integral unshared stack size */ - __kernel_long_t ru_minflt; /* page reclaims */ - __kernel_long_t ru_majflt; /* page faults */ - __kernel_long_t ru_nswap; /* swaps */ - __kernel_long_t ru_inblock; /* block input operations */ - __kernel_long_t ru_oublock; /* block output operations */ - __kernel_long_t ru_msgsnd; /* messages sent */ - __kernel_long_t ru_msgrcv; /* messages received */ - __kernel_long_t ru_nsignals; /* signals received */ - __kernel_long_t ru_nvcsw; /* voluntary context switches */ - __kernel_long_t ru_nivcsw; /* involuntary " */ -}; - -struct rlimit { - __kernel_ulong_t rlim_cur; - __kernel_ulong_t rlim_max; -}; - -#define RLIM64_INFINITY (~0ULL) - -struct rlimit64 { - __u64 rlim_cur; - __u64 rlim_max; -}; - -#define PRIO_MIN (-20) -#define PRIO_MAX 20 - -#define PRIO_PROCESS 0 -#define PRIO_PGRP 1 -#define PRIO_USER 2 - -/* - * Limit the stack by to some sane default: root can always - * increase this limit if needed.. 8MB seems reasonable. - */ -#define _STK_LIM (8*1024*1024) - -/* - * GPG2 wants 64kB of mlocked memory, to make sure pass phrases - * and other sensitive information are never written to disk. - */ -#define MLOCK_LIMIT ((PAGE_SIZE > 64*1024) ? PAGE_SIZE : 64*1024) - -/* - * Due to binary compatibility, the actual resource numbers - * may be different for different linux versions.. - */ -#include - - -#endif /* _UAPI_LINUX_RESOURCE_H */ diff --git a/src/linux/include/uapi/linux/route.h b/src/linux/include/uapi/linux/route.h deleted file mode 100644 index 6600708..0000000 --- a/src/linux/include/uapi/linux/route.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Global definitions for the IP router interface. - * - * Version: @(#)route.h 1.0.3 05/27/93 - * - * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988 - * for the purposes of compatibility only. - * - * Fred N. van Kempen, - * - * Changes: - * Mike McLagan : Routing by source - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_ROUTE_H -#define _LINUX_ROUTE_H - -#include -#include - -/* This structure gets passed by the SIOCADDRT and SIOCDELRT calls. */ -struct rtentry { - unsigned long rt_pad1; - struct sockaddr rt_dst; /* target address */ - struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ - struct sockaddr rt_genmask; /* target network mask (IP) */ - unsigned short rt_flags; - short rt_pad2; - unsigned long rt_pad3; - void *rt_pad4; - short rt_metric; /* +1 for binary compatibility! */ - char __user *rt_dev; /* forcing the device at add */ - unsigned long rt_mtu; /* per route MTU/Window */ -#ifndef __KERNEL__ -#define rt_mss rt_mtu /* Compatibility :-( */ -#endif - unsigned long rt_window; /* Window clamping */ - unsigned short rt_irtt; /* Initial RTT */ -}; - - -#define RTF_UP 0x0001 /* route usable */ -#define RTF_GATEWAY 0x0002 /* destination is a gateway */ -#define RTF_HOST 0x0004 /* host entry (net otherwise) */ -#define RTF_REINSTATE 0x0008 /* reinstate route after tmout */ -#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */ -#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */ -#define RTF_MTU 0x0040 /* specific MTU for this route */ -#define RTF_MSS RTF_MTU /* Compatibility :-( */ -#define RTF_WINDOW 0x0080 /* per route window clamping */ -#define RTF_IRTT 0x0100 /* Initial round trip time */ -#define RTF_REJECT 0x0200 /* Reject route */ - -/* - * uses RTF values >= 64k - */ - - - -#endif /* _LINUX_ROUTE_H */ - diff --git a/src/linux/include/uapi/linux/rtc.h b/src/linux/include/uapi/linux/rtc.h deleted file mode 100644 index f8c82e6..0000000 --- a/src/linux/include/uapi/linux/rtc.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Generic RTC interface. - * This version contains the part of the user interface to the Real Time Clock - * service. It is used with both the legacy mc146818 and also EFI - * Struct rtc_time and first 12 ioctl by Paul Gortmaker, 1996 - separated out - * from to this file for 2.4 kernels. - * - * Copyright (C) 1999 Hewlett-Packard Co. - * Copyright (C) 1999 Stephane Eranian - */ -#ifndef _UAPI_LINUX_RTC_H_ -#define _UAPI_LINUX_RTC_H_ - -/* - * The struct used to pass data via the following ioctl. Similar to the - * struct tm in , but it needs to be here so that the kernel - * source is self contained, allowing cross-compiles, etc. etc. - */ - -struct rtc_time { - int tm_sec; - int tm_min; - int tm_hour; - int tm_mday; - int tm_mon; - int tm_year; - int tm_wday; - int tm_yday; - int tm_isdst; -}; - -/* - * This data structure is inspired by the EFI (v0.92) wakeup - * alarm API. - */ -struct rtc_wkalrm { - unsigned char enabled; /* 0 = alarm disabled, 1 = alarm enabled */ - unsigned char pending; /* 0 = alarm not pending, 1 = alarm pending */ - struct rtc_time time; /* time the alarm is set to */ -}; - -/* - * Data structure to control PLL correction some better RTC feature - * pll_value is used to get or set current value of correction, - * the rest of the struct is used to query HW capabilities. - * This is modeled after the RTC used in Q40/Q60 computers but - * should be sufficiently flexible for other devices - * - * +ve pll_value means clock will run faster by - * pll_value*pll_posmult/pll_clock - * -ve pll_value means clock will run slower by - * pll_value*pll_negmult/pll_clock - */ - -struct rtc_pll_info { - int pll_ctrl; /* placeholder for fancier control */ - int pll_value; /* get/set correction value */ - int pll_max; /* max +ve (faster) adjustment value */ - int pll_min; /* max -ve (slower) adjustment value */ - int pll_posmult; /* factor for +ve correction */ - int pll_negmult; /* factor for -ve correction */ - long pll_clock; /* base PLL frequency */ -}; - -/* - * ioctl calls that are permitted to the /dev/rtc interface, if - * any of the RTC drivers are enabled. - */ - -#define RTC_AIE_ON _IO('p', 0x01) /* Alarm int. enable on */ -#define RTC_AIE_OFF _IO('p', 0x02) /* ... off */ -#define RTC_UIE_ON _IO('p', 0x03) /* Update int. enable on */ -#define RTC_UIE_OFF _IO('p', 0x04) /* ... off */ -#define RTC_PIE_ON _IO('p', 0x05) /* Periodic int. enable on */ -#define RTC_PIE_OFF _IO('p', 0x06) /* ... off */ -#define RTC_WIE_ON _IO('p', 0x0f) /* Watchdog int. enable on */ -#define RTC_WIE_OFF _IO('p', 0x10) /* ... off */ - -#define RTC_ALM_SET _IOW('p', 0x07, struct rtc_time) /* Set alarm time */ -#define RTC_ALM_READ _IOR('p', 0x08, struct rtc_time) /* Read alarm time */ -#define RTC_RD_TIME _IOR('p', 0x09, struct rtc_time) /* Read RTC time */ -#define RTC_SET_TIME _IOW('p', 0x0a, struct rtc_time) /* Set RTC time */ -#define RTC_IRQP_READ _IOR('p', 0x0b, unsigned long) /* Read IRQ rate */ -#define RTC_IRQP_SET _IOW('p', 0x0c, unsigned long) /* Set IRQ rate */ -#define RTC_EPOCH_READ _IOR('p', 0x0d, unsigned long) /* Read epoch */ -#define RTC_EPOCH_SET _IOW('p', 0x0e, unsigned long) /* Set epoch */ - -#define RTC_WKALM_SET _IOW('p', 0x0f, struct rtc_wkalrm)/* Set wakeup alarm*/ -#define RTC_WKALM_RD _IOR('p', 0x10, struct rtc_wkalrm)/* Get wakeup alarm*/ - -#define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */ -#define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */ - -#define RTC_VL_READ _IOR('p', 0x13, int) /* Voltage low detector */ -#define RTC_VL_CLR _IO('p', 0x14) /* Clear voltage low information */ - -/* interrupt flags */ -#define RTC_IRQF 0x80 /* Any of the following is active */ -#define RTC_PF 0x40 /* Periodic interrupt */ -#define RTC_AF 0x20 /* Alarm interrupt */ -#define RTC_UF 0x10 /* Update interrupt for 1Hz RTC */ - - -#define RTC_MAX_FREQ 8192 - - -#endif /* _UAPI_LINUX_RTC_H_ */ diff --git a/src/linux/include/uapi/linux/rtnetlink.h b/src/linux/include/uapi/linux/rtnetlink.h deleted file mode 100644 index 5a78be5..0000000 --- a/src/linux/include/uapi/linux/rtnetlink.h +++ /dev/null @@ -1,684 +0,0 @@ -#ifndef _UAPI__LINUX_RTNETLINK_H -#define _UAPI__LINUX_RTNETLINK_H - -#include -#include -#include -#include -#include - -/* rtnetlink families. Values up to 127 are reserved for real address - * families, values above 128 may be used arbitrarily. - */ -#define RTNL_FAMILY_IPMR 128 -#define RTNL_FAMILY_IP6MR 129 -#define RTNL_FAMILY_MAX 129 - -/**** - * Routing/neighbour discovery messages. - ****/ - -/* Types of messages */ - -enum { - RTM_BASE = 16, -#define RTM_BASE RTM_BASE - - RTM_NEWLINK = 16, -#define RTM_NEWLINK RTM_NEWLINK - RTM_DELLINK, -#define RTM_DELLINK RTM_DELLINK - RTM_GETLINK, -#define RTM_GETLINK RTM_GETLINK - RTM_SETLINK, -#define RTM_SETLINK RTM_SETLINK - - RTM_NEWADDR = 20, -#define RTM_NEWADDR RTM_NEWADDR - RTM_DELADDR, -#define RTM_DELADDR RTM_DELADDR - RTM_GETADDR, -#define RTM_GETADDR RTM_GETADDR - - RTM_NEWROUTE = 24, -#define RTM_NEWROUTE RTM_NEWROUTE - RTM_DELROUTE, -#define RTM_DELROUTE RTM_DELROUTE - RTM_GETROUTE, -#define RTM_GETROUTE RTM_GETROUTE - - RTM_NEWNEIGH = 28, -#define RTM_NEWNEIGH RTM_NEWNEIGH - RTM_DELNEIGH, -#define RTM_DELNEIGH RTM_DELNEIGH - RTM_GETNEIGH, -#define RTM_GETNEIGH RTM_GETNEIGH - - RTM_NEWRULE = 32, -#define RTM_NEWRULE RTM_NEWRULE - RTM_DELRULE, -#define RTM_DELRULE RTM_DELRULE - RTM_GETRULE, -#define RTM_GETRULE RTM_GETRULE - - RTM_NEWQDISC = 36, -#define RTM_NEWQDISC RTM_NEWQDISC - RTM_DELQDISC, -#define RTM_DELQDISC RTM_DELQDISC - RTM_GETQDISC, -#define RTM_GETQDISC RTM_GETQDISC - - RTM_NEWTCLASS = 40, -#define RTM_NEWTCLASS RTM_NEWTCLASS - RTM_DELTCLASS, -#define RTM_DELTCLASS RTM_DELTCLASS - RTM_GETTCLASS, -#define RTM_GETTCLASS RTM_GETTCLASS - - RTM_NEWTFILTER = 44, -#define RTM_NEWTFILTER RTM_NEWTFILTER - RTM_DELTFILTER, -#define RTM_DELTFILTER RTM_DELTFILTER - RTM_GETTFILTER, -#define RTM_GETTFILTER RTM_GETTFILTER - - RTM_NEWACTION = 48, -#define RTM_NEWACTION RTM_NEWACTION - RTM_DELACTION, -#define RTM_DELACTION RTM_DELACTION - RTM_GETACTION, -#define RTM_GETACTION RTM_GETACTION - - RTM_NEWPREFIX = 52, -#define RTM_NEWPREFIX RTM_NEWPREFIX - - RTM_GETMULTICAST = 58, -#define RTM_GETMULTICAST RTM_GETMULTICAST - - RTM_GETANYCAST = 62, -#define RTM_GETANYCAST RTM_GETANYCAST - - RTM_NEWNEIGHTBL = 64, -#define RTM_NEWNEIGHTBL RTM_NEWNEIGHTBL - RTM_GETNEIGHTBL = 66, -#define RTM_GETNEIGHTBL RTM_GETNEIGHTBL - RTM_SETNEIGHTBL, -#define RTM_SETNEIGHTBL RTM_SETNEIGHTBL - - RTM_NEWNDUSEROPT = 68, -#define RTM_NEWNDUSEROPT RTM_NEWNDUSEROPT - - RTM_NEWADDRLABEL = 72, -#define RTM_NEWADDRLABEL RTM_NEWADDRLABEL - RTM_DELADDRLABEL, -#define RTM_DELADDRLABEL RTM_DELADDRLABEL - RTM_GETADDRLABEL, -#define RTM_GETADDRLABEL RTM_GETADDRLABEL - - RTM_GETDCB = 78, -#define RTM_GETDCB RTM_GETDCB - RTM_SETDCB, -#define RTM_SETDCB RTM_SETDCB - - RTM_NEWNETCONF = 80, -#define RTM_NEWNETCONF RTM_NEWNETCONF - RTM_GETNETCONF = 82, -#define RTM_GETNETCONF RTM_GETNETCONF - - RTM_NEWMDB = 84, -#define RTM_NEWMDB RTM_NEWMDB - RTM_DELMDB = 85, -#define RTM_DELMDB RTM_DELMDB - RTM_GETMDB = 86, -#define RTM_GETMDB RTM_GETMDB - - RTM_NEWNSID = 88, -#define RTM_NEWNSID RTM_NEWNSID - RTM_DELNSID = 89, -#define RTM_DELNSID RTM_DELNSID - RTM_GETNSID = 90, -#define RTM_GETNSID RTM_GETNSID - - RTM_NEWSTATS = 92, -#define RTM_NEWSTATS RTM_NEWSTATS - RTM_GETSTATS = 94, -#define RTM_GETSTATS RTM_GETSTATS - - __RTM_MAX, -#define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) -}; - -#define RTM_NR_MSGTYPES (RTM_MAX + 1 - RTM_BASE) -#define RTM_NR_FAMILIES (RTM_NR_MSGTYPES >> 2) -#define RTM_FAM(cmd) (((cmd) - RTM_BASE) >> 2) - -/* - Generic structure for encapsulation of optional route information. - It is reminiscent of sockaddr, but with sa_family replaced - with attribute type. - */ - -struct rtattr { - unsigned short rta_len; - unsigned short rta_type; -}; - -/* Macros to handle rtattributes */ - -#define RTA_ALIGNTO 4U -#define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) ) -#define RTA_OK(rta,len) ((len) >= (int)sizeof(struct rtattr) && \ - (rta)->rta_len >= sizeof(struct rtattr) && \ - (rta)->rta_len <= (len)) -#define RTA_NEXT(rta,attrlen) ((attrlen) -= RTA_ALIGN((rta)->rta_len), \ - (struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len))) -#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len)) -#define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len)) -#define RTA_DATA(rta) ((void*)(((char*)(rta)) + RTA_LENGTH(0))) -#define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0)) - - - - -/****************************************************************************** - * Definitions used in routing table administration. - ****/ - -struct rtmsg { - unsigned char rtm_family; - unsigned char rtm_dst_len; - unsigned char rtm_src_len; - unsigned char rtm_tos; - - unsigned char rtm_table; /* Routing table id */ - unsigned char rtm_protocol; /* Routing protocol; see below */ - unsigned char rtm_scope; /* See below */ - unsigned char rtm_type; /* See below */ - - unsigned rtm_flags; -}; - -/* rtm_type */ - -enum { - RTN_UNSPEC, - RTN_UNICAST, /* Gateway or direct route */ - RTN_LOCAL, /* Accept locally */ - RTN_BROADCAST, /* Accept locally as broadcast, - send as broadcast */ - RTN_ANYCAST, /* Accept locally as broadcast, - but send as unicast */ - RTN_MULTICAST, /* Multicast route */ - RTN_BLACKHOLE, /* Drop */ - RTN_UNREACHABLE, /* Destination is unreachable */ - RTN_PROHIBIT, /* Administratively prohibited */ - RTN_THROW, /* Not in this table */ - RTN_NAT, /* Translate this address */ - RTN_XRESOLVE, /* Use external resolver */ - __RTN_MAX -}; - -#define RTN_MAX (__RTN_MAX - 1) - - -/* rtm_protocol */ - -#define RTPROT_UNSPEC 0 -#define RTPROT_REDIRECT 1 /* Route installed by ICMP redirects; - not used by current IPv4 */ -#define RTPROT_KERNEL 2 /* Route installed by kernel */ -#define RTPROT_BOOT 3 /* Route installed during boot */ -#define RTPROT_STATIC 4 /* Route installed by administrator */ - -/* Values of protocol >= RTPROT_STATIC are not interpreted by kernel; - they are just passed from user and back as is. - It will be used by hypothetical multiple routing daemons. - Note that protocol values should be standardized in order to - avoid conflicts. - */ - -#define RTPROT_GATED 8 /* Apparently, GateD */ -#define RTPROT_RA 9 /* RDISC/ND router advertisements */ -#define RTPROT_MRT 10 /* Merit MRT */ -#define RTPROT_ZEBRA 11 /* Zebra */ -#define RTPROT_BIRD 12 /* BIRD */ -#define RTPROT_DNROUTED 13 /* DECnet routing daemon */ -#define RTPROT_XORP 14 /* XORP */ -#define RTPROT_NTK 15 /* Netsukuku */ -#define RTPROT_DHCP 16 /* DHCP client */ -#define RTPROT_MROUTED 17 /* Multicast daemon */ -#define RTPROT_BABEL 42 /* Babel daemon */ - -/* rtm_scope - - Really it is not scope, but sort of distance to the destination. - NOWHERE are reserved for not existing destinations, HOST is our - local addresses, LINK are destinations, located on directly attached - link and UNIVERSE is everywhere in the Universe. - - Intermediate values are also possible f.e. interior routes - could be assigned a value between UNIVERSE and LINK. -*/ - -enum rt_scope_t { - RT_SCOPE_UNIVERSE=0, -/* User defined values */ - RT_SCOPE_SITE=200, - RT_SCOPE_LINK=253, - RT_SCOPE_HOST=254, - RT_SCOPE_NOWHERE=255 -}; - -/* rtm_flags */ - -#define RTM_F_NOTIFY 0x100 /* Notify user of route change */ -#define RTM_F_CLONED 0x200 /* This route is cloned */ -#define RTM_F_EQUALIZE 0x400 /* Multipath equalizer: NI */ -#define RTM_F_PREFIX 0x800 /* Prefix addresses */ -#define RTM_F_LOOKUP_TABLE 0x1000 /* set rtm_table to FIB lookup result */ - -/* Reserved table identifiers */ - -enum rt_class_t { - RT_TABLE_UNSPEC=0, -/* User defined values */ - RT_TABLE_COMPAT=252, - RT_TABLE_DEFAULT=253, - RT_TABLE_MAIN=254, - RT_TABLE_LOCAL=255, - RT_TABLE_MAX=0xFFFFFFFF -}; - - -/* Routing message attributes */ - -enum rtattr_type_t { - RTA_UNSPEC, - RTA_DST, - RTA_SRC, - RTA_IIF, - RTA_OIF, - RTA_GATEWAY, - RTA_PRIORITY, - RTA_PREFSRC, - RTA_METRICS, - RTA_MULTIPATH, - RTA_PROTOINFO, /* no longer used */ - RTA_FLOW, - RTA_CACHEINFO, - RTA_SESSION, /* no longer used */ - RTA_MP_ALGO, /* no longer used */ - RTA_TABLE, - RTA_MARK, - RTA_MFC_STATS, - RTA_VIA, - RTA_NEWDST, - RTA_PREF, - RTA_ENCAP_TYPE, - RTA_ENCAP, - RTA_EXPIRES, - RTA_PAD, - __RTA_MAX -}; - -#define RTA_MAX (__RTA_MAX - 1) - -#define RTM_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct rtmsg)))) -#define RTM_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct rtmsg)) - -/* RTM_MULTIPATH --- array of struct rtnexthop. - * - * "struct rtnexthop" describes all necessary nexthop information, - * i.e. parameters of path to a destination via this nexthop. - * - * At the moment it is impossible to set different prefsrc, mtu, window - * and rtt for different paths from multipath. - */ - -struct rtnexthop { - unsigned short rtnh_len; - unsigned char rtnh_flags; - unsigned char rtnh_hops; - int rtnh_ifindex; -}; - -/* rtnh_flags */ - -#define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */ -#define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */ -#define RTNH_F_ONLINK 4 /* Gateway is forced on link */ -#define RTNH_F_OFFLOAD 8 /* offloaded route */ -#define RTNH_F_LINKDOWN 16 /* carrier-down on nexthop */ - -#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN | RTNH_F_OFFLOAD) - -/* Macros to handle hexthops */ - -#define RTNH_ALIGNTO 4 -#define RTNH_ALIGN(len) ( ((len)+RTNH_ALIGNTO-1) & ~(RTNH_ALIGNTO-1) ) -#define RTNH_OK(rtnh,len) ((rtnh)->rtnh_len >= sizeof(struct rtnexthop) && \ - ((int)(rtnh)->rtnh_len) <= (len)) -#define RTNH_NEXT(rtnh) ((struct rtnexthop*)(((char*)(rtnh)) + RTNH_ALIGN((rtnh)->rtnh_len))) -#define RTNH_LENGTH(len) (RTNH_ALIGN(sizeof(struct rtnexthop)) + (len)) -#define RTNH_SPACE(len) RTNH_ALIGN(RTNH_LENGTH(len)) -#define RTNH_DATA(rtnh) ((struct rtattr*)(((char*)(rtnh)) + RTNH_LENGTH(0))) - -/* RTA_VIA */ -struct rtvia { - __kernel_sa_family_t rtvia_family; - __u8 rtvia_addr[0]; -}; - -/* RTM_CACHEINFO */ - -struct rta_cacheinfo { - __u32 rta_clntref; - __u32 rta_lastuse; - __s32 rta_expires; - __u32 rta_error; - __u32 rta_used; - -#define RTNETLINK_HAVE_PEERINFO 1 - __u32 rta_id; - __u32 rta_ts; - __u32 rta_tsage; -}; - -/* RTM_METRICS --- array of struct rtattr with types of RTAX_* */ - -enum { - RTAX_UNSPEC, -#define RTAX_UNSPEC RTAX_UNSPEC - RTAX_LOCK, -#define RTAX_LOCK RTAX_LOCK - RTAX_MTU, -#define RTAX_MTU RTAX_MTU - RTAX_WINDOW, -#define RTAX_WINDOW RTAX_WINDOW - RTAX_RTT, -#define RTAX_RTT RTAX_RTT - RTAX_RTTVAR, -#define RTAX_RTTVAR RTAX_RTTVAR - RTAX_SSTHRESH, -#define RTAX_SSTHRESH RTAX_SSTHRESH - RTAX_CWND, -#define RTAX_CWND RTAX_CWND - RTAX_ADVMSS, -#define RTAX_ADVMSS RTAX_ADVMSS - RTAX_REORDERING, -#define RTAX_REORDERING RTAX_REORDERING - RTAX_HOPLIMIT, -#define RTAX_HOPLIMIT RTAX_HOPLIMIT - RTAX_INITCWND, -#define RTAX_INITCWND RTAX_INITCWND - RTAX_FEATURES, -#define RTAX_FEATURES RTAX_FEATURES - RTAX_RTO_MIN, -#define RTAX_RTO_MIN RTAX_RTO_MIN - RTAX_INITRWND, -#define RTAX_INITRWND RTAX_INITRWND - RTAX_QUICKACK, -#define RTAX_QUICKACK RTAX_QUICKACK - RTAX_CC_ALGO, -#define RTAX_CC_ALGO RTAX_CC_ALGO - __RTAX_MAX -}; - -#define RTAX_MAX (__RTAX_MAX - 1) - -#define RTAX_FEATURE_ECN (1 << 0) -#define RTAX_FEATURE_SACK (1 << 1) -#define RTAX_FEATURE_TIMESTAMP (1 << 2) -#define RTAX_FEATURE_ALLFRAG (1 << 3) - -#define RTAX_FEATURE_MASK (RTAX_FEATURE_ECN | RTAX_FEATURE_SACK | \ - RTAX_FEATURE_TIMESTAMP | RTAX_FEATURE_ALLFRAG) - -struct rta_session { - __u8 proto; - __u8 pad1; - __u16 pad2; - - union { - struct { - __u16 sport; - __u16 dport; - } ports; - - struct { - __u8 type; - __u8 code; - __u16 ident; - } icmpt; - - __u32 spi; - } u; -}; - -struct rta_mfc_stats { - __u64 mfcs_packets; - __u64 mfcs_bytes; - __u64 mfcs_wrong_if; -}; - -/**** - * General form of address family dependent message. - ****/ - -struct rtgenmsg { - unsigned char rtgen_family; -}; - -/***************************************************************** - * Link layer specific messages. - ****/ - -/* struct ifinfomsg - * passes link level specific information, not dependent - * on network protocol. - */ - -struct ifinfomsg { - unsigned char ifi_family; - unsigned char __ifi_pad; - unsigned short ifi_type; /* ARPHRD_* */ - int ifi_index; /* Link index */ - unsigned ifi_flags; /* IFF_* flags */ - unsigned ifi_change; /* IFF_* change mask */ -}; - -/******************************************************************** - * prefix information - ****/ - -struct prefixmsg { - unsigned char prefix_family; - unsigned char prefix_pad1; - unsigned short prefix_pad2; - int prefix_ifindex; - unsigned char prefix_type; - unsigned char prefix_len; - unsigned char prefix_flags; - unsigned char prefix_pad3; -}; - -enum -{ - PREFIX_UNSPEC, - PREFIX_ADDRESS, - PREFIX_CACHEINFO, - __PREFIX_MAX -}; - -#define PREFIX_MAX (__PREFIX_MAX - 1) - -struct prefix_cacheinfo { - __u32 preferred_time; - __u32 valid_time; -}; - - -/***************************************************************** - * Traffic control messages. - ****/ - -struct tcmsg { - unsigned char tcm_family; - unsigned char tcm__pad1; - unsigned short tcm__pad2; - int tcm_ifindex; - __u32 tcm_handle; - __u32 tcm_parent; - __u32 tcm_info; -}; - -enum { - TCA_UNSPEC, - TCA_KIND, - TCA_OPTIONS, - TCA_STATS, - TCA_XSTATS, - TCA_RATE, - TCA_FCNT, - TCA_STATS2, - TCA_STAB, - TCA_PAD, - __TCA_MAX -}; - -#define TCA_MAX (__TCA_MAX - 1) - -#define TCA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcmsg)))) -#define TCA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcmsg)) - -/******************************************************************** - * Neighbor Discovery userland options - ****/ - -struct nduseroptmsg { - unsigned char nduseropt_family; - unsigned char nduseropt_pad1; - unsigned short nduseropt_opts_len; /* Total length of options */ - int nduseropt_ifindex; - __u8 nduseropt_icmp_type; - __u8 nduseropt_icmp_code; - unsigned short nduseropt_pad2; - unsigned int nduseropt_pad3; - /* Followed by one or more ND options */ -}; - -enum { - NDUSEROPT_UNSPEC, - NDUSEROPT_SRCADDR, - __NDUSEROPT_MAX -}; - -#define NDUSEROPT_MAX (__NDUSEROPT_MAX - 1) - -#ifndef __KERNEL__ -/* RTnetlink multicast groups - backwards compatibility for userspace */ -#define RTMGRP_LINK 1 -#define RTMGRP_NOTIFY 2 -#define RTMGRP_NEIGH 4 -#define RTMGRP_TC 8 - -#define RTMGRP_IPV4_IFADDR 0x10 -#define RTMGRP_IPV4_MROUTE 0x20 -#define RTMGRP_IPV4_ROUTE 0x40 -#define RTMGRP_IPV4_RULE 0x80 - -#define RTMGRP_IPV6_IFADDR 0x100 -#define RTMGRP_IPV6_MROUTE 0x200 -#define RTMGRP_IPV6_ROUTE 0x400 -#define RTMGRP_IPV6_IFINFO 0x800 - -#define RTMGRP_DECnet_IFADDR 0x1000 -#define RTMGRP_DECnet_ROUTE 0x4000 - -#define RTMGRP_IPV6_PREFIX 0x20000 -#endif - -/* RTnetlink multicast groups */ -enum rtnetlink_groups { - RTNLGRP_NONE, -#define RTNLGRP_NONE RTNLGRP_NONE - RTNLGRP_LINK, -#define RTNLGRP_LINK RTNLGRP_LINK - RTNLGRP_NOTIFY, -#define RTNLGRP_NOTIFY RTNLGRP_NOTIFY - RTNLGRP_NEIGH, -#define RTNLGRP_NEIGH RTNLGRP_NEIGH - RTNLGRP_TC, -#define RTNLGRP_TC RTNLGRP_TC - RTNLGRP_IPV4_IFADDR, -#define RTNLGRP_IPV4_IFADDR RTNLGRP_IPV4_IFADDR - RTNLGRP_IPV4_MROUTE, -#define RTNLGRP_IPV4_MROUTE RTNLGRP_IPV4_MROUTE - RTNLGRP_IPV4_ROUTE, -#define RTNLGRP_IPV4_ROUTE RTNLGRP_IPV4_ROUTE - RTNLGRP_IPV4_RULE, -#define RTNLGRP_IPV4_RULE RTNLGRP_IPV4_RULE - RTNLGRP_IPV6_IFADDR, -#define RTNLGRP_IPV6_IFADDR RTNLGRP_IPV6_IFADDR - RTNLGRP_IPV6_MROUTE, -#define RTNLGRP_IPV6_MROUTE RTNLGRP_IPV6_MROUTE - RTNLGRP_IPV6_ROUTE, -#define RTNLGRP_IPV6_ROUTE RTNLGRP_IPV6_ROUTE - RTNLGRP_IPV6_IFINFO, -#define RTNLGRP_IPV6_IFINFO RTNLGRP_IPV6_IFINFO - RTNLGRP_DECnet_IFADDR, -#define RTNLGRP_DECnet_IFADDR RTNLGRP_DECnet_IFADDR - RTNLGRP_NOP2, - RTNLGRP_DECnet_ROUTE, -#define RTNLGRP_DECnet_ROUTE RTNLGRP_DECnet_ROUTE - RTNLGRP_DECnet_RULE, -#define RTNLGRP_DECnet_RULE RTNLGRP_DECnet_RULE - RTNLGRP_NOP4, - RTNLGRP_IPV6_PREFIX, -#define RTNLGRP_IPV6_PREFIX RTNLGRP_IPV6_PREFIX - RTNLGRP_IPV6_RULE, -#define RTNLGRP_IPV6_RULE RTNLGRP_IPV6_RULE - RTNLGRP_ND_USEROPT, -#define RTNLGRP_ND_USEROPT RTNLGRP_ND_USEROPT - RTNLGRP_PHONET_IFADDR, -#define RTNLGRP_PHONET_IFADDR RTNLGRP_PHONET_IFADDR - RTNLGRP_PHONET_ROUTE, -#define RTNLGRP_PHONET_ROUTE RTNLGRP_PHONET_ROUTE - RTNLGRP_DCB, -#define RTNLGRP_DCB RTNLGRP_DCB - RTNLGRP_IPV4_NETCONF, -#define RTNLGRP_IPV4_NETCONF RTNLGRP_IPV4_NETCONF - RTNLGRP_IPV6_NETCONF, -#define RTNLGRP_IPV6_NETCONF RTNLGRP_IPV6_NETCONF - RTNLGRP_MDB, -#define RTNLGRP_MDB RTNLGRP_MDB - RTNLGRP_MPLS_ROUTE, -#define RTNLGRP_MPLS_ROUTE RTNLGRP_MPLS_ROUTE - RTNLGRP_NSID, -#define RTNLGRP_NSID RTNLGRP_NSID - __RTNLGRP_MAX -}; -#define RTNLGRP_MAX (__RTNLGRP_MAX - 1) - -/* TC action piece */ -struct tcamsg { - unsigned char tca_family; - unsigned char tca__pad1; - unsigned short tca__pad2; -}; -#define TA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct tcamsg)))) -#define TA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct tcamsg)) -#define TCA_ACT_TAB 1 /* attr type must be >=1 */ -#define TCAA_MAX 1 - -/* New extended info filters for IFLA_EXT_MASK */ -#define RTEXT_FILTER_VF (1 << 0) -#define RTEXT_FILTER_BRVLAN (1 << 1) -#define RTEXT_FILTER_BRVLAN_COMPRESSED (1 << 2) -#define RTEXT_FILTER_SKIP_STATS (1 << 3) - -/* End of information exported to user level */ - - - -#endif /* _UAPI__LINUX_RTNETLINK_H */ diff --git a/src/linux/include/uapi/linux/sched.h b/src/linux/include/uapi/linux/sched.h deleted file mode 100644 index 5f0fe01..0000000 --- a/src/linux/include/uapi/linux/sched.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef _UAPI_LINUX_SCHED_H -#define _UAPI_LINUX_SCHED_H - -/* - * cloning flags: - */ -#define CSIGNAL 0x000000ff /* signal mask to be sent at exit */ -#define CLONE_VM 0x00000100 /* set if VM shared between processes */ -#define CLONE_FS 0x00000200 /* set if fs info shared between processes */ -#define CLONE_FILES 0x00000400 /* set if open files shared between processes */ -#define CLONE_SIGHAND 0x00000800 /* set if signal handlers and blocked signals shared */ -#define CLONE_PTRACE 0x00002000 /* set if we want to let tracing continue on the child too */ -#define CLONE_VFORK 0x00004000 /* set if the parent wants the child to wake it up on mm_release */ -#define CLONE_PARENT 0x00008000 /* set if we want to have the same parent as the cloner */ -#define CLONE_THREAD 0x00010000 /* Same thread group? */ -#define CLONE_NEWNS 0x00020000 /* New mount namespace group */ -#define CLONE_SYSVSEM 0x00040000 /* share system V SEM_UNDO semantics */ -#define CLONE_SETTLS 0x00080000 /* create a new TLS for the child */ -#define CLONE_PARENT_SETTID 0x00100000 /* set the TID in the parent */ -#define CLONE_CHILD_CLEARTID 0x00200000 /* clear the TID in the child */ -#define CLONE_DETACHED 0x00400000 /* Unused, ignored */ -#define CLONE_UNTRACED 0x00800000 /* set if the tracing process can't force CLONE_PTRACE on this clone */ -#define CLONE_CHILD_SETTID 0x01000000 /* set the TID in the child */ -#define CLONE_NEWCGROUP 0x02000000 /* New cgroup namespace */ -#define CLONE_NEWUTS 0x04000000 /* New utsname namespace */ -#define CLONE_NEWIPC 0x08000000 /* New ipc namespace */ -#define CLONE_NEWUSER 0x10000000 /* New user namespace */ -#define CLONE_NEWPID 0x20000000 /* New pid namespace */ -#define CLONE_NEWNET 0x40000000 /* New network namespace */ -#define CLONE_IO 0x80000000 /* Clone io context */ - -/* - * Scheduling policies - */ -#define SCHED_NORMAL 0 -#define SCHED_FIFO 1 -#define SCHED_RR 2 -#define SCHED_BATCH 3 -/* SCHED_ISO: reserved but not implemented yet */ -#define SCHED_IDLE 5 -#define SCHED_DEADLINE 6 - -/* Can be ORed in to make sure the process is reverted back to SCHED_NORMAL on fork */ -#define SCHED_RESET_ON_FORK 0x40000000 - -/* - * For the sched_{set,get}attr() calls - */ -#define SCHED_FLAG_RESET_ON_FORK 0x01 - -#endif /* _UAPI_LINUX_SCHED_H */ diff --git a/src/linux/include/uapi/linux/screen_info.h b/src/linux/include/uapi/linux/screen_info.h deleted file mode 100644 index 8b8d39d..0000000 --- a/src/linux/include/uapi/linux/screen_info.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef _UAPI_SCREEN_INFO_H -#define _UAPI_SCREEN_INFO_H - -#include - -/* - * These are set up by the setup-routine at boot-time: - */ - -struct screen_info { - __u8 orig_x; /* 0x00 */ - __u8 orig_y; /* 0x01 */ - __u16 ext_mem_k; /* 0x02 */ - __u16 orig_video_page; /* 0x04 */ - __u8 orig_video_mode; /* 0x06 */ - __u8 orig_video_cols; /* 0x07 */ - __u8 flags; /* 0x08 */ - __u8 unused2; /* 0x09 */ - __u16 orig_video_ega_bx;/* 0x0a */ - __u16 unused3; /* 0x0c */ - __u8 orig_video_lines; /* 0x0e */ - __u8 orig_video_isVGA; /* 0x0f */ - __u16 orig_video_points;/* 0x10 */ - - /* VESA graphic mode -- linear frame buffer */ - __u16 lfb_width; /* 0x12 */ - __u16 lfb_height; /* 0x14 */ - __u16 lfb_depth; /* 0x16 */ - __u32 lfb_base; /* 0x18 */ - __u32 lfb_size; /* 0x1c */ - __u16 cl_magic, cl_offset; /* 0x20 */ - __u16 lfb_linelength; /* 0x24 */ - __u8 red_size; /* 0x26 */ - __u8 red_pos; /* 0x27 */ - __u8 green_size; /* 0x28 */ - __u8 green_pos; /* 0x29 */ - __u8 blue_size; /* 0x2a */ - __u8 blue_pos; /* 0x2b */ - __u8 rsvd_size; /* 0x2c */ - __u8 rsvd_pos; /* 0x2d */ - __u16 vesapm_seg; /* 0x2e */ - __u16 vesapm_off; /* 0x30 */ - __u16 pages; /* 0x32 */ - __u16 vesa_attributes; /* 0x34 */ - __u32 capabilities; /* 0x36 */ - __u32 ext_lfb_base; /* 0x3a */ - __u8 _reserved[2]; /* 0x3e */ -} __attribute__((packed)); - -#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */ -#define VIDEO_TYPE_CGA 0x11 /* CGA Display */ -#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */ -#define VIDEO_TYPE_EGAC 0x21 /* EGA in Color Mode */ -#define VIDEO_TYPE_VGAC 0x22 /* VGA+ in Color Mode */ -#define VIDEO_TYPE_VLFB 0x23 /* VESA VGA in graphic mode */ - -#define VIDEO_TYPE_PICA_S3 0x30 /* ACER PICA-61 local S3 video */ -#define VIDEO_TYPE_MIPS_G364 0x31 /* MIPS Magnum 4000 G364 video */ -#define VIDEO_TYPE_SGI 0x33 /* Various SGI graphics hardware */ - -#define VIDEO_TYPE_TGAC 0x40 /* DEC TGA */ - -#define VIDEO_TYPE_SUN 0x50 /* Sun frame buffer. */ -#define VIDEO_TYPE_SUNPCI 0x51 /* Sun PCI based frame buffer. */ - -#define VIDEO_TYPE_PMAC 0x60 /* PowerMacintosh frame buffer. */ - -#define VIDEO_TYPE_EFI 0x70 /* EFI graphic mode */ - -#define VIDEO_FLAGS_NOCURSOR (1 << 0) /* The video mode has no cursor set */ - -#define VIDEO_CAPABILITY_SKIP_QUIRKS (1 << 0) -#define VIDEO_CAPABILITY_64BIT_BASE (1 << 1) /* Frame buffer base is 64-bit */ - -#endif /* _UAPI_SCREEN_INFO_H */ diff --git a/src/linux/include/uapi/linux/sctp.h b/src/linux/include/uapi/linux/sctp.h deleted file mode 100644 index a406adc..0000000 --- a/src/linux/include/uapi/linux/sctp.h +++ /dev/null @@ -1,1011 +0,0 @@ -/* SCTP kernel implementation - * (C) Copyright IBM Corp. 2001, 2004 - * Copyright (c) 1999-2000 Cisco, Inc. - * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2002 Intel Corp. - * - * This file is part of the SCTP kernel implementation - * - * This header represents the structures and constants needed to support - * the SCTP Extension to the Sockets API. - * - * This SCTP implementation is free software; - * you can redistribute it and/or modify it under the terms of - * the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This SCTP implementation is distributed in the hope that it - * will be useful, but WITHOUT ANY WARRANTY; without even the implied - * ************************ - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with GNU CC; see the file COPYING. If not, see - * . - * - * Please send any bug reports or fixes you make to the - * email address(es): - * lksctp developers - * - * Or submit a bug report through the following website: - * http://www.sf.net/projects/lksctp - * - * Written or modified by: - * La Monte H.P. Yarroll - * R. Stewart - * K. Morneau - * Q. Xie - * Karl Knutson - * Jon Grimm - * Daisy Chang - * Ryan Layer - * Ardelle Fan - * Sridhar Samudrala - * Inaky Perez-Gonzalez - * Vlad Yasevich - * - * Any bugs reported given to us we will try to fix... any fixes shared will - * be incorporated into the next SCTP release. - */ - -#ifndef _UAPI_SCTP_H -#define _UAPI_SCTP_H - -#include -#include - -typedef __s32 sctp_assoc_t; - -/* The following symbols come from the Sockets API Extensions for - * SCTP . - */ -#define SCTP_RTOINFO 0 -#define SCTP_ASSOCINFO 1 -#define SCTP_INITMSG 2 -#define SCTP_NODELAY 3 /* Get/set nodelay option. */ -#define SCTP_AUTOCLOSE 4 -#define SCTP_SET_PEER_PRIMARY_ADDR 5 -#define SCTP_PRIMARY_ADDR 6 -#define SCTP_ADAPTATION_LAYER 7 -#define SCTP_DISABLE_FRAGMENTS 8 -#define SCTP_PEER_ADDR_PARAMS 9 -#define SCTP_DEFAULT_SEND_PARAM 10 -#define SCTP_EVENTS 11 -#define SCTP_I_WANT_MAPPED_V4_ADDR 12 /* Turn on/off mapped v4 addresses */ -#define SCTP_MAXSEG 13 /* Get/set maximum fragment. */ -#define SCTP_STATUS 14 -#define SCTP_GET_PEER_ADDR_INFO 15 -#define SCTP_DELAYED_ACK_TIME 16 -#define SCTP_DELAYED_ACK SCTP_DELAYED_ACK_TIME -#define SCTP_DELAYED_SACK SCTP_DELAYED_ACK_TIME -#define SCTP_CONTEXT 17 -#define SCTP_FRAGMENT_INTERLEAVE 18 -#define SCTP_PARTIAL_DELIVERY_POINT 19 /* Set/Get partial delivery point */ -#define SCTP_MAX_BURST 20 /* Set/Get max burst */ -#define SCTP_AUTH_CHUNK 21 /* Set only: add a chunk type to authenticate */ -#define SCTP_HMAC_IDENT 22 -#define SCTP_AUTH_KEY 23 -#define SCTP_AUTH_ACTIVE_KEY 24 -#define SCTP_AUTH_DELETE_KEY 25 -#define SCTP_PEER_AUTH_CHUNKS 26 /* Read only */ -#define SCTP_LOCAL_AUTH_CHUNKS 27 /* Read only */ -#define SCTP_GET_ASSOC_NUMBER 28 /* Read only */ -#define SCTP_GET_ASSOC_ID_LIST 29 /* Read only */ -#define SCTP_AUTO_ASCONF 30 -#define SCTP_PEER_ADDR_THLDS 31 -#define SCTP_RECVRCVINFO 32 -#define SCTP_RECVNXTINFO 33 -#define SCTP_DEFAULT_SNDINFO 34 - -/* Internal Socket Options. Some of the sctp library functions are - * implemented using these socket options. - */ -#define SCTP_SOCKOPT_BINDX_ADD 100 /* BINDX requests for adding addrs */ -#define SCTP_SOCKOPT_BINDX_REM 101 /* BINDX requests for removing addrs. */ -#define SCTP_SOCKOPT_PEELOFF 102 /* peel off association. */ -/* Options 104-106 are deprecated and removed. Do not use this space */ -#define SCTP_SOCKOPT_CONNECTX_OLD 107 /* CONNECTX old requests. */ -#define SCTP_GET_PEER_ADDRS 108 /* Get all peer address. */ -#define SCTP_GET_LOCAL_ADDRS 109 /* Get all local address. */ -#define SCTP_SOCKOPT_CONNECTX 110 /* CONNECTX requests. */ -#define SCTP_SOCKOPT_CONNECTX3 111 /* CONNECTX requests (updated) */ -#define SCTP_GET_ASSOC_STATS 112 /* Read only */ -#define SCTP_PR_SUPPORTED 113 -#define SCTP_DEFAULT_PRINFO 114 -#define SCTP_PR_ASSOC_STATUS 115 - -/* PR-SCTP policies */ -#define SCTP_PR_SCTP_NONE 0x0000 -#define SCTP_PR_SCTP_TTL 0x0010 -#define SCTP_PR_SCTP_RTX 0x0020 -#define SCTP_PR_SCTP_PRIO 0x0030 -#define SCTP_PR_SCTP_MAX SCTP_PR_SCTP_PRIO -#define SCTP_PR_SCTP_MASK 0x0030 - -#define __SCTP_PR_INDEX(x) ((x >> 4) - 1) -#define SCTP_PR_INDEX(x) __SCTP_PR_INDEX(SCTP_PR_SCTP_ ## x) - -#define SCTP_PR_POLICY(x) ((x) & SCTP_PR_SCTP_MASK) -#define SCTP_PR_SET_POLICY(flags, x) \ - do { \ - flags &= ~SCTP_PR_SCTP_MASK; \ - flags |= x; \ - } while (0) - -#define SCTP_PR_TTL_ENABLED(x) (SCTP_PR_POLICY(x) == SCTP_PR_SCTP_TTL) -#define SCTP_PR_RTX_ENABLED(x) (SCTP_PR_POLICY(x) == SCTP_PR_SCTP_RTX) -#define SCTP_PR_PRIO_ENABLED(x) (SCTP_PR_POLICY(x) == SCTP_PR_SCTP_PRIO) - -/* These are bit fields for msghdr->msg_flags. See section 5.1. */ -/* On user space Linux, these live in as an enum. */ -enum sctp_msg_flags { - MSG_NOTIFICATION = 0x8000, -#define MSG_NOTIFICATION MSG_NOTIFICATION -}; - -/* 5.3.1 SCTP Initiation Structure (SCTP_INIT) - * - * This cmsghdr structure provides information for initializing new - * SCTP associations with sendmsg(). The SCTP_INITMSG socket option - * uses this same data structure. This structure is not used for - * recvmsg(). - * - * cmsg_level cmsg_type cmsg_data[] - * ------------ ------------ ---------------------- - * IPPROTO_SCTP SCTP_INIT struct sctp_initmsg - */ -struct sctp_initmsg { - __u16 sinit_num_ostreams; - __u16 sinit_max_instreams; - __u16 sinit_max_attempts; - __u16 sinit_max_init_timeo; -}; - -/* 5.3.2 SCTP Header Information Structure (SCTP_SNDRCV) - * - * This cmsghdr structure specifies SCTP options for sendmsg() and - * describes SCTP header information about a received message through - * recvmsg(). - * - * cmsg_level cmsg_type cmsg_data[] - * ------------ ------------ ---------------------- - * IPPROTO_SCTP SCTP_SNDRCV struct sctp_sndrcvinfo - */ -struct sctp_sndrcvinfo { - __u16 sinfo_stream; - __u16 sinfo_ssn; - __u16 sinfo_flags; - __u32 sinfo_ppid; - __u32 sinfo_context; - __u32 sinfo_timetolive; - __u32 sinfo_tsn; - __u32 sinfo_cumtsn; - sctp_assoc_t sinfo_assoc_id; -}; - -/* 5.3.4 SCTP Send Information Structure (SCTP_SNDINFO) - * - * This cmsghdr structure specifies SCTP options for sendmsg(). - * - * cmsg_level cmsg_type cmsg_data[] - * ------------ ------------ ------------------- - * IPPROTO_SCTP SCTP_SNDINFO struct sctp_sndinfo - */ -struct sctp_sndinfo { - __u16 snd_sid; - __u16 snd_flags; - __u32 snd_ppid; - __u32 snd_context; - sctp_assoc_t snd_assoc_id; -}; - -/* 5.3.5 SCTP Receive Information Structure (SCTP_RCVINFO) - * - * This cmsghdr structure describes SCTP receive information - * about a received message through recvmsg(). - * - * cmsg_level cmsg_type cmsg_data[] - * ------------ ------------ ------------------- - * IPPROTO_SCTP SCTP_RCVINFO struct sctp_rcvinfo - */ -struct sctp_rcvinfo { - __u16 rcv_sid; - __u16 rcv_ssn; - __u16 rcv_flags; - __u32 rcv_ppid; - __u32 rcv_tsn; - __u32 rcv_cumtsn; - __u32 rcv_context; - sctp_assoc_t rcv_assoc_id; -}; - -/* 5.3.6 SCTP Next Receive Information Structure (SCTP_NXTINFO) - * - * This cmsghdr structure describes SCTP receive information - * of the next message that will be delivered through recvmsg() - * if this information is already available when delivering - * the current message. - * - * cmsg_level cmsg_type cmsg_data[] - * ------------ ------------ ------------------- - * IPPROTO_SCTP SCTP_NXTINFO struct sctp_nxtinfo - */ -struct sctp_nxtinfo { - __u16 nxt_sid; - __u16 nxt_flags; - __u32 nxt_ppid; - __u32 nxt_length; - sctp_assoc_t nxt_assoc_id; -}; - -/* - * sinfo_flags: 16 bits (unsigned integer) - * - * This field may contain any of the following flags and is composed of - * a bitwise OR of these values. - */ -enum sctp_sinfo_flags { - SCTP_UNORDERED = (1 << 0), /* Send/receive message unordered. */ - SCTP_ADDR_OVER = (1 << 1), /* Override the primary destination. */ - SCTP_ABORT = (1 << 2), /* Send an ABORT message to the peer. */ - SCTP_SACK_IMMEDIATELY = (1 << 3), /* SACK should be sent without delay. */ - SCTP_NOTIFICATION = MSG_NOTIFICATION, /* Next message is not user msg but notification. */ - SCTP_EOF = MSG_FIN, /* Initiate graceful shutdown process. */ -}; - -typedef union { - __u8 raw; - struct sctp_initmsg init; - struct sctp_sndrcvinfo sndrcv; -} sctp_cmsg_data_t; - -/* These are cmsg_types. */ -typedef enum sctp_cmsg_type { - SCTP_INIT, /* 5.2.1 SCTP Initiation Structure */ -#define SCTP_INIT SCTP_INIT - SCTP_SNDRCV, /* 5.2.2 SCTP Header Information Structure */ -#define SCTP_SNDRCV SCTP_SNDRCV - SCTP_SNDINFO, /* 5.3.4 SCTP Send Information Structure */ -#define SCTP_SNDINFO SCTP_SNDINFO - SCTP_RCVINFO, /* 5.3.5 SCTP Receive Information Structure */ -#define SCTP_RCVINFO SCTP_RCVINFO - SCTP_NXTINFO, /* 5.3.6 SCTP Next Receive Information Structure */ -#define SCTP_NXTINFO SCTP_NXTINFO -} sctp_cmsg_t; - -/* - * 5.3.1.1 SCTP_ASSOC_CHANGE - * - * Communication notifications inform the ULP that an SCTP association - * has either begun or ended. The identifier for a new association is - * provided by this notificaion. The notification information has the - * following format: - * - */ -struct sctp_assoc_change { - __u16 sac_type; - __u16 sac_flags; - __u32 sac_length; - __u16 sac_state; - __u16 sac_error; - __u16 sac_outbound_streams; - __u16 sac_inbound_streams; - sctp_assoc_t sac_assoc_id; - __u8 sac_info[0]; -}; - -/* - * sac_state: 32 bits (signed integer) - * - * This field holds one of a number of values that communicate the - * event that happened to the association. They include: - * - * Note: The following state names deviate from the API draft as - * the names clash too easily with other kernel symbols. - */ -enum sctp_sac_state { - SCTP_COMM_UP, - SCTP_COMM_LOST, - SCTP_RESTART, - SCTP_SHUTDOWN_COMP, - SCTP_CANT_STR_ASSOC, -}; - -/* - * 5.3.1.2 SCTP_PEER_ADDR_CHANGE - * - * When a destination address on a multi-homed peer encounters a change - * an interface details event is sent. The information has the - * following structure: - */ -struct sctp_paddr_change { - __u16 spc_type; - __u16 spc_flags; - __u32 spc_length; - struct sockaddr_storage spc_aaddr; - int spc_state; - int spc_error; - sctp_assoc_t spc_assoc_id; -} __attribute__((packed, aligned(4))); - -/* - * spc_state: 32 bits (signed integer) - * - * This field holds one of a number of values that communicate the - * event that happened to the address. They include: - */ -enum sctp_spc_state { - SCTP_ADDR_AVAILABLE, - SCTP_ADDR_UNREACHABLE, - SCTP_ADDR_REMOVED, - SCTP_ADDR_ADDED, - SCTP_ADDR_MADE_PRIM, - SCTP_ADDR_CONFIRMED, -}; - - -/* - * 5.3.1.3 SCTP_REMOTE_ERROR - * - * A remote peer may send an Operational Error message to its peer. - * This message indicates a variety of error conditions on an - * association. The entire error TLV as it appears on the wire is - * included in a SCTP_REMOTE_ERROR event. Please refer to the SCTP - * specification [SCTP] and any extensions for a list of possible - * error formats. SCTP error TLVs have the format: - */ -struct sctp_remote_error { - __u16 sre_type; - __u16 sre_flags; - __u32 sre_length; - __u16 sre_error; - sctp_assoc_t sre_assoc_id; - __u8 sre_data[0]; -}; - - -/* - * 5.3.1.4 SCTP_SEND_FAILED - * - * If SCTP cannot deliver a message it may return the message as a - * notification. - */ -struct sctp_send_failed { - __u16 ssf_type; - __u16 ssf_flags; - __u32 ssf_length; - __u32 ssf_error; - struct sctp_sndrcvinfo ssf_info; - sctp_assoc_t ssf_assoc_id; - __u8 ssf_data[0]; -}; - -/* - * ssf_flags: 16 bits (unsigned integer) - * - * The flag value will take one of the following values - * - * SCTP_DATA_UNSENT - Indicates that the data was never put on - * the wire. - * - * SCTP_DATA_SENT - Indicates that the data was put on the wire. - * Note that this does not necessarily mean that the - * data was (or was not) successfully delivered. - */ -enum sctp_ssf_flags { - SCTP_DATA_UNSENT, - SCTP_DATA_SENT, -}; - -/* - * 5.3.1.5 SCTP_SHUTDOWN_EVENT - * - * When a peer sends a SHUTDOWN, SCTP delivers this notification to - * inform the application that it should cease sending data. - */ -struct sctp_shutdown_event { - __u16 sse_type; - __u16 sse_flags; - __u32 sse_length; - sctp_assoc_t sse_assoc_id; -}; - -/* - * 5.3.1.6 SCTP_ADAPTATION_INDICATION - * - * When a peer sends a Adaptation Layer Indication parameter , SCTP - * delivers this notification to inform the application - * that of the peers requested adaptation layer. - */ -struct sctp_adaptation_event { - __u16 sai_type; - __u16 sai_flags; - __u32 sai_length; - __u32 sai_adaptation_ind; - sctp_assoc_t sai_assoc_id; -}; - -/* - * 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT - * - * When a receiver is engaged in a partial delivery of a - * message this notification will be used to indicate - * various events. - */ -struct sctp_pdapi_event { - __u16 pdapi_type; - __u16 pdapi_flags; - __u32 pdapi_length; - __u32 pdapi_indication; - sctp_assoc_t pdapi_assoc_id; -}; - -enum { SCTP_PARTIAL_DELIVERY_ABORTED=0, }; - -/* - * 5.3.1.8. SCTP_AUTHENTICATION_EVENT - * - * When a receiver is using authentication this message will provide - * notifications regarding new keys being made active as well as errors. - */ -struct sctp_authkey_event { - __u16 auth_type; - __u16 auth_flags; - __u32 auth_length; - __u16 auth_keynumber; - __u16 auth_altkeynumber; - __u32 auth_indication; - sctp_assoc_t auth_assoc_id; -}; - -enum { SCTP_AUTH_NEWKEY = 0, }; - -/* - * 6.1.9. SCTP_SENDER_DRY_EVENT - * - * When the SCTP stack has no more user data to send or retransmit, this - * notification is given to the user. Also, at the time when a user app - * subscribes to this event, if there is no data to be sent or - * retransmit, the stack will immediately send up this notification. - */ -struct sctp_sender_dry_event { - __u16 sender_dry_type; - __u16 sender_dry_flags; - __u32 sender_dry_length; - sctp_assoc_t sender_dry_assoc_id; -}; - -/* - * Described in Section 7.3 - * Ancillary Data and Notification Interest Options - */ -struct sctp_event_subscribe { - __u8 sctp_data_io_event; - __u8 sctp_association_event; - __u8 sctp_address_event; - __u8 sctp_send_failure_event; - __u8 sctp_peer_error_event; - __u8 sctp_shutdown_event; - __u8 sctp_partial_delivery_event; - __u8 sctp_adaptation_layer_event; - __u8 sctp_authentication_event; - __u8 sctp_sender_dry_event; -}; - -/* - * 5.3.1 SCTP Notification Structure - * - * The notification structure is defined as the union of all - * notification types. - * - */ -union sctp_notification { - struct { - __u16 sn_type; /* Notification type. */ - __u16 sn_flags; - __u32 sn_length; - } sn_header; - struct sctp_assoc_change sn_assoc_change; - struct sctp_paddr_change sn_paddr_change; - struct sctp_remote_error sn_remote_error; - struct sctp_send_failed sn_send_failed; - struct sctp_shutdown_event sn_shutdown_event; - struct sctp_adaptation_event sn_adaptation_event; - struct sctp_pdapi_event sn_pdapi_event; - struct sctp_authkey_event sn_authkey_event; - struct sctp_sender_dry_event sn_sender_dry_event; -}; - -/* Section 5.3.1 - * All standard values for sn_type flags are greater than 2^15. - * Values from 2^15 and down are reserved. - */ - -enum sctp_sn_type { - SCTP_SN_TYPE_BASE = (1<<15), - SCTP_ASSOC_CHANGE, -#define SCTP_ASSOC_CHANGE SCTP_ASSOC_CHANGE - SCTP_PEER_ADDR_CHANGE, -#define SCTP_PEER_ADDR_CHANGE SCTP_PEER_ADDR_CHANGE - SCTP_SEND_FAILED, -#define SCTP_SEND_FAILED SCTP_SEND_FAILED - SCTP_REMOTE_ERROR, -#define SCTP_REMOTE_ERROR SCTP_REMOTE_ERROR - SCTP_SHUTDOWN_EVENT, -#define SCTP_SHUTDOWN_EVENT SCTP_SHUTDOWN_EVENT - SCTP_PARTIAL_DELIVERY_EVENT, -#define SCTP_PARTIAL_DELIVERY_EVENT SCTP_PARTIAL_DELIVERY_EVENT - SCTP_ADAPTATION_INDICATION, -#define SCTP_ADAPTATION_INDICATION SCTP_ADAPTATION_INDICATION - SCTP_AUTHENTICATION_EVENT, -#define SCTP_AUTHENTICATION_INDICATION SCTP_AUTHENTICATION_EVENT - SCTP_SENDER_DRY_EVENT, -#define SCTP_SENDER_DRY_EVENT SCTP_SENDER_DRY_EVENT -}; - -/* Notification error codes used to fill up the error fields in some - * notifications. - * SCTP_PEER_ADDRESS_CHAGE : spc_error - * SCTP_ASSOC_CHANGE : sac_error - * These names should be potentially included in the draft 04 of the SCTP - * sockets API specification. - */ -typedef enum sctp_sn_error { - SCTP_FAILED_THRESHOLD, - SCTP_RECEIVED_SACK, - SCTP_HEARTBEAT_SUCCESS, - SCTP_RESPONSE_TO_USER_REQ, - SCTP_INTERNAL_ERROR, - SCTP_SHUTDOWN_GUARD_EXPIRES, - SCTP_PEER_FAULTY, -} sctp_sn_error_t; - -/* - * 7.1.1 Retransmission Timeout Parameters (SCTP_RTOINFO) - * - * The protocol parameters used to initialize and bound retransmission - * timeout (RTO) are tunable. See [SCTP] for more information on how - * these parameters are used in RTO calculation. - */ -struct sctp_rtoinfo { - sctp_assoc_t srto_assoc_id; - __u32 srto_initial; - __u32 srto_max; - __u32 srto_min; -}; - -/* - * 7.1.2 Association Parameters (SCTP_ASSOCINFO) - * - * This option is used to both examine and set various association and - * endpoint parameters. - */ -struct sctp_assocparams { - sctp_assoc_t sasoc_assoc_id; - __u16 sasoc_asocmaxrxt; - __u16 sasoc_number_peer_destinations; - __u32 sasoc_peer_rwnd; - __u32 sasoc_local_rwnd; - __u32 sasoc_cookie_life; -}; - -/* - * 7.1.9 Set Peer Primary Address (SCTP_SET_PEER_PRIMARY_ADDR) - * - * Requests that the peer mark the enclosed address as the association - * primary. The enclosed address must be one of the association's - * locally bound addresses. The following structure is used to make a - * set primary request: - */ -struct sctp_setpeerprim { - sctp_assoc_t sspp_assoc_id; - struct sockaddr_storage sspp_addr; -} __attribute__((packed, aligned(4))); - -/* - * 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR) - * - * Requests that the local SCTP stack use the enclosed peer address as - * the association primary. The enclosed address must be one of the - * association peer's addresses. The following structure is used to - * make a set peer primary request: - */ -struct sctp_prim { - sctp_assoc_t ssp_assoc_id; - struct sockaddr_storage ssp_addr; -} __attribute__((packed, aligned(4))); - -/* For backward compatibility use, define the old name too */ -#define sctp_setprim sctp_prim - -/* - * 7.1.11 Set Adaptation Layer Indicator (SCTP_ADAPTATION_LAYER) - * - * Requests that the local endpoint set the specified Adaptation Layer - * Indication parameter for all future INIT and INIT-ACK exchanges. - */ -struct sctp_setadaptation { - __u32 ssb_adaptation_ind; -}; - -/* - * 7.1.13 Peer Address Parameters (SCTP_PEER_ADDR_PARAMS) - * - * Applications can enable or disable heartbeats for any peer address - * of an association, modify an address's heartbeat interval, force a - * heartbeat to be sent immediately, and adjust the address's maximum - * number of retransmissions sent before an address is considered - * unreachable. The following structure is used to access and modify an - * address's parameters: - */ -enum sctp_spp_flags { - SPP_HB_ENABLE = 1<<0, /*Enable heartbeats*/ - SPP_HB_DISABLE = 1<<1, /*Disable heartbeats*/ - SPP_HB = SPP_HB_ENABLE | SPP_HB_DISABLE, - SPP_HB_DEMAND = 1<<2, /*Send heartbeat immediately*/ - SPP_PMTUD_ENABLE = 1<<3, /*Enable PMTU discovery*/ - SPP_PMTUD_DISABLE = 1<<4, /*Disable PMTU discovery*/ - SPP_PMTUD = SPP_PMTUD_ENABLE | SPP_PMTUD_DISABLE, - SPP_SACKDELAY_ENABLE = 1<<5, /*Enable SACK*/ - SPP_SACKDELAY_DISABLE = 1<<6, /*Disable SACK*/ - SPP_SACKDELAY = SPP_SACKDELAY_ENABLE | SPP_SACKDELAY_DISABLE, - SPP_HB_TIME_IS_ZERO = 1<<7, /* Set HB delay to 0 */ -}; - -struct sctp_paddrparams { - sctp_assoc_t spp_assoc_id; - struct sockaddr_storage spp_address; - __u32 spp_hbinterval; - __u16 spp_pathmaxrxt; - __u32 spp_pathmtu; - __u32 spp_sackdelay; - __u32 spp_flags; -} __attribute__((packed, aligned(4))); - -/* - * 7.1.18. Add a chunk that must be authenticated (SCTP_AUTH_CHUNK) - * - * This set option adds a chunk type that the user is requesting to be - * received only in an authenticated way. Changes to the list of chunks - * will only effect future associations on the socket. - */ -struct sctp_authchunk { - __u8 sauth_chunk; -}; - -/* - * 7.1.19. Get or set the list of supported HMAC Identifiers (SCTP_HMAC_IDENT) - * - * This option gets or sets the list of HMAC algorithms that the local - * endpoint requires the peer to use. - */ -#ifndef __KERNEL__ -/* This here is only used by user space as is. It might not be a good idea - * to export/reveal the whole structure with reserved fields etc. - */ -enum { - SCTP_AUTH_HMAC_ID_SHA1 = 1, - SCTP_AUTH_HMAC_ID_SHA256 = 3, -}; -#endif - -struct sctp_hmacalgo { - __u32 shmac_num_idents; - __u16 shmac_idents[]; -}; - -/* Sadly, user and kernel space have different names for - * this structure member, so this is to not break anything. - */ -#define shmac_number_of_idents shmac_num_idents - -/* - * 7.1.20. Set a shared key (SCTP_AUTH_KEY) - * - * This option will set a shared secret key which is used to build an - * association shared key. - */ -struct sctp_authkey { - sctp_assoc_t sca_assoc_id; - __u16 sca_keynumber; - __u16 sca_keylength; - __u8 sca_key[]; -}; - -/* - * 7.1.21. Get or set the active shared key (SCTP_AUTH_ACTIVE_KEY) - * - * This option will get or set the active shared key to be used to build - * the association shared key. - */ - -struct sctp_authkeyid { - sctp_assoc_t scact_assoc_id; - __u16 scact_keynumber; -}; - - -/* - * 7.1.23. Get or set delayed ack timer (SCTP_DELAYED_SACK) - * - * This option will effect the way delayed acks are performed. This - * option allows you to get or set the delayed ack time, in - * milliseconds. It also allows changing the delayed ack frequency. - * Changing the frequency to 1 disables the delayed sack algorithm. If - * the assoc_id is 0, then this sets or gets the endpoints default - * values. If the assoc_id field is non-zero, then the set or get - * effects the specified association for the one to many model (the - * assoc_id field is ignored by the one to one model). Note that if - * sack_delay or sack_freq are 0 when setting this option, then the - * current values will remain unchanged. - */ -struct sctp_sack_info { - sctp_assoc_t sack_assoc_id; - uint32_t sack_delay; - uint32_t sack_freq; -}; - -struct sctp_assoc_value { - sctp_assoc_t assoc_id; - uint32_t assoc_value; -}; - -/* - * 7.2.2 Peer Address Information - * - * Applications can retrieve information about a specific peer address - * of an association, including its reachability state, congestion - * window, and retransmission timer values. This information is - * read-only. The following structure is used to access this - * information: - */ -struct sctp_paddrinfo { - sctp_assoc_t spinfo_assoc_id; - struct sockaddr_storage spinfo_address; - __s32 spinfo_state; - __u32 spinfo_cwnd; - __u32 spinfo_srtt; - __u32 spinfo_rto; - __u32 spinfo_mtu; -} __attribute__((packed, aligned(4))); - -/* Peer addresses's state. */ -/* UNKNOWN: Peer address passed by the upper layer in sendmsg or connect[x] - * calls. - * UNCONFIRMED: Peer address received in INIT/INIT-ACK address parameters. - * Not yet confirmed by a heartbeat and not available for data - * transfers. - * ACTIVE : Peer address confirmed, active and available for data transfers. - * INACTIVE: Peer address inactive and not available for data transfers. - */ -enum sctp_spinfo_state { - SCTP_INACTIVE, - SCTP_PF, - SCTP_ACTIVE, - SCTP_UNCONFIRMED, - SCTP_UNKNOWN = 0xffff /* Value used for transport state unknown */ -}; - -/* - * 7.2.1 Association Status (SCTP_STATUS) - * - * Applications can retrieve current status information about an - * association, including association state, peer receiver window size, - * number of unacked data chunks, and number of data chunks pending - * receipt. This information is read-only. The following structure is - * used to access this information: - */ -struct sctp_status { - sctp_assoc_t sstat_assoc_id; - __s32 sstat_state; - __u32 sstat_rwnd; - __u16 sstat_unackdata; - __u16 sstat_penddata; - __u16 sstat_instrms; - __u16 sstat_outstrms; - __u32 sstat_fragmentation_point; - struct sctp_paddrinfo sstat_primary; -}; - -/* - * 7.2.3. Get the list of chunks the peer requires to be authenticated - * (SCTP_PEER_AUTH_CHUNKS) - * - * This option gets a list of chunks for a specified association that - * the peer requires to be received authenticated only. - */ -struct sctp_authchunks { - sctp_assoc_t gauth_assoc_id; - __u32 gauth_number_of_chunks; - uint8_t gauth_chunks[]; -}; - -/* The broken spelling has been released already in lksctp-tools header, - * so don't break anyone, now that it's fixed. - */ -#define guth_number_of_chunks gauth_number_of_chunks - -/* Association states. */ -enum sctp_sstat_state { - SCTP_EMPTY = 0, - SCTP_CLOSED = 1, - SCTP_COOKIE_WAIT = 2, - SCTP_COOKIE_ECHOED = 3, - SCTP_ESTABLISHED = 4, - SCTP_SHUTDOWN_PENDING = 5, - SCTP_SHUTDOWN_SENT = 6, - SCTP_SHUTDOWN_RECEIVED = 7, - SCTP_SHUTDOWN_ACK_SENT = 8, -}; - -/* - * 8.2.6. Get the Current Identifiers of Associations - * (SCTP_GET_ASSOC_ID_LIST) - * - * This option gets the current list of SCTP association identifiers of - * the SCTP associations handled by a one-to-many style socket. - */ -struct sctp_assoc_ids { - __u32 gaids_number_of_ids; - sctp_assoc_t gaids_assoc_id[]; -}; - -/* - * 8.3, 8.5 get all peer/local addresses in an association. - * This parameter struct is used by SCTP_GET_PEER_ADDRS and - * SCTP_GET_LOCAL_ADDRS socket options used internally to implement - * sctp_getpaddrs() and sctp_getladdrs() API. - */ -struct sctp_getaddrs_old { - sctp_assoc_t assoc_id; - int addr_num; -#ifdef __KERNEL__ - struct sockaddr __user *addrs; -#else - struct sockaddr *addrs; -#endif -}; - -struct sctp_getaddrs { - sctp_assoc_t assoc_id; /*input*/ - __u32 addr_num; /*output*/ - __u8 addrs[0]; /*output, variable size*/ -}; - -/* A socket user request obtained via SCTP_GET_ASSOC_STATS that retrieves - * association stats. All stats are counts except sas_maxrto and - * sas_obs_rto_ipaddr. maxrto is the max observed rto + transport since - * the last call. Will return 0 when RTO was not update since last call - */ -struct sctp_assoc_stats { - sctp_assoc_t sas_assoc_id; /* Input */ - /* Transport of observed max RTO */ - struct sockaddr_storage sas_obs_rto_ipaddr; - __u64 sas_maxrto; /* Maximum Observed RTO for period */ - __u64 sas_isacks; /* SACKs received */ - __u64 sas_osacks; /* SACKs sent */ - __u64 sas_opackets; /* Packets sent */ - __u64 sas_ipackets; /* Packets received */ - __u64 sas_rtxchunks; /* Retransmitted Chunks */ - __u64 sas_outofseqtsns;/* TSN received > next expected */ - __u64 sas_idupchunks; /* Dups received (ordered+unordered) */ - __u64 sas_gapcnt; /* Gap Acknowledgements Received */ - __u64 sas_ouodchunks; /* Unordered data chunks sent */ - __u64 sas_iuodchunks; /* Unordered data chunks received */ - __u64 sas_oodchunks; /* Ordered data chunks sent */ - __u64 sas_iodchunks; /* Ordered data chunks received */ - __u64 sas_octrlchunks; /* Control chunks sent */ - __u64 sas_ictrlchunks; /* Control chunks received */ -}; - -/* - * 8.1 sctp_bindx() - * - * The flags parameter is formed from the bitwise OR of zero or more of the - * following currently defined flags: - */ -#define SCTP_BINDX_ADD_ADDR 0x01 -#define SCTP_BINDX_REM_ADDR 0x02 - -/* This is the structure that is passed as an argument(optval) to - * getsockopt(SCTP_SOCKOPT_PEELOFF). - */ -typedef struct { - sctp_assoc_t associd; - int sd; -} sctp_peeloff_arg_t; - -/* - * Peer Address Thresholds socket option - */ -struct sctp_paddrthlds { - sctp_assoc_t spt_assoc_id; - struct sockaddr_storage spt_address; - __u16 spt_pathmaxrxt; - __u16 spt_pathpfthld; -}; - -/* - * Socket Option for Getting the Association/Stream-Specific PR-SCTP Status - */ -struct sctp_prstatus { - sctp_assoc_t sprstat_assoc_id; - __u16 sprstat_sid; - __u16 sprstat_policy; - __u64 sprstat_abandoned_unsent; - __u64 sprstat_abandoned_sent; -}; - -struct sctp_default_prinfo { - sctp_assoc_t pr_assoc_id; - __u32 pr_value; - __u16 pr_policy; -}; - -struct sctp_info { - __u32 sctpi_tag; - __u32 sctpi_state; - __u32 sctpi_rwnd; - __u16 sctpi_unackdata; - __u16 sctpi_penddata; - __u16 sctpi_instrms; - __u16 sctpi_outstrms; - __u32 sctpi_fragmentation_point; - __u32 sctpi_inqueue; - __u32 sctpi_outqueue; - __u32 sctpi_overall_error; - __u32 sctpi_max_burst; - __u32 sctpi_maxseg; - __u32 sctpi_peer_rwnd; - __u32 sctpi_peer_tag; - __u8 sctpi_peer_capable; - __u8 sctpi_peer_sack; - __u16 __reserved1; - - /* assoc status info */ - __u64 sctpi_isacks; - __u64 sctpi_osacks; - __u64 sctpi_opackets; - __u64 sctpi_ipackets; - __u64 sctpi_rtxchunks; - __u64 sctpi_outofseqtsns; - __u64 sctpi_idupchunks; - __u64 sctpi_gapcnt; - __u64 sctpi_ouodchunks; - __u64 sctpi_iuodchunks; - __u64 sctpi_oodchunks; - __u64 sctpi_iodchunks; - __u64 sctpi_octrlchunks; - __u64 sctpi_ictrlchunks; - - /* primary transport info */ - struct sockaddr_storage sctpi_p_address; - __s32 sctpi_p_state; - __u32 sctpi_p_cwnd; - __u32 sctpi_p_srtt; - __u32 sctpi_p_rto; - __u32 sctpi_p_hbinterval; - __u32 sctpi_p_pathmaxrxt; - __u32 sctpi_p_sackdelay; - __u32 sctpi_p_sackfreq; - __u32 sctpi_p_ssthresh; - __u32 sctpi_p_partial_bytes_acked; - __u32 sctpi_p_flight_size; - __u16 sctpi_p_error; - __u16 __reserved2; - - /* sctp sock info */ - __u32 sctpi_s_autoclose; - __u32 sctpi_s_adaptation_ind; - __u32 sctpi_s_pd_point; - __u8 sctpi_s_nodelay; - __u8 sctpi_s_disable_fragments; - __u8 sctpi_s_v4mapped; - __u8 sctpi_s_frag_interleave; - __u32 sctpi_s_type; - __u32 __reserved3; -}; - -#endif /* _UAPI_SCTP_H */ diff --git a/src/linux/include/uapi/linux/seccomp.h b/src/linux/include/uapi/linux/seccomp.h deleted file mode 100644 index 0f238a4..0000000 --- a/src/linux/include/uapi/linux/seccomp.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef _UAPI_LINUX_SECCOMP_H -#define _UAPI_LINUX_SECCOMP_H - -#include -#include - - -/* Valid values for seccomp.mode and prctl(PR_SET_SECCOMP, ) */ -#define SECCOMP_MODE_DISABLED 0 /* seccomp is not in use. */ -#define SECCOMP_MODE_STRICT 1 /* uses hard-coded filter. */ -#define SECCOMP_MODE_FILTER 2 /* uses user-supplied filter. */ - -/* Valid operations for seccomp syscall. */ -#define SECCOMP_SET_MODE_STRICT 0 -#define SECCOMP_SET_MODE_FILTER 1 - -/* Valid flags for SECCOMP_SET_MODE_FILTER */ -#define SECCOMP_FILTER_FLAG_TSYNC 1 - -/* - * All BPF programs must return a 32-bit value. - * The bottom 16-bits are for optional return data. - * The upper 16-bits are ordered from least permissive values to most. - * - * The ordering ensures that a min_t() over composed return values always - * selects the least permissive choice. - */ -#define SECCOMP_RET_KILL 0x00000000U /* kill the task immediately */ -#define SECCOMP_RET_TRAP 0x00030000U /* disallow and force a SIGSYS */ -#define SECCOMP_RET_ERRNO 0x00050000U /* returns an errno */ -#define SECCOMP_RET_TRACE 0x7ff00000U /* pass to a tracer or disallow */ -#define SECCOMP_RET_ALLOW 0x7fff0000U /* allow */ - -/* Masks for the return value sections. */ -#define SECCOMP_RET_ACTION 0x7fff0000U -#define SECCOMP_RET_DATA 0x0000ffffU - -/** - * struct seccomp_data - the format the BPF program executes over. - * @nr: the system call number - * @arch: indicates system call convention as an AUDIT_ARCH_* value - * as defined in . - * @instruction_pointer: at the time of the system call. - * @args: up to 6 system call arguments always stored as 64-bit values - * regardless of the architecture. - */ -struct seccomp_data { - int nr; - __u32 arch; - __u64 instruction_pointer; - __u64 args[6]; -}; - -#endif /* _UAPI_LINUX_SECCOMP_H */ diff --git a/src/linux/include/uapi/linux/securebits.h b/src/linux/include/uapi/linux/securebits.h deleted file mode 100644 index 35ac35c..0000000 --- a/src/linux/include/uapi/linux/securebits.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef _UAPI_LINUX_SECUREBITS_H -#define _UAPI_LINUX_SECUREBITS_H - -/* Each securesetting is implemented using two bits. One bit specifies - whether the setting is on or off. The other bit specify whether the - setting is locked or not. A setting which is locked cannot be - changed from user-level. */ -#define issecure_mask(X) (1 << (X)) - -#define SECUREBITS_DEFAULT 0x00000000 - -/* When set UID 0 has no special privileges. When unset, we support - inheritance of root-permissions and suid-root executable under - compatibility mode. We raise the effective and inheritable bitmasks - *of the executable file* if the effective uid of the new process is - 0. If the real uid is 0, we raise the effective (legacy) bit of the - executable file. */ -#define SECURE_NOROOT 0 -#define SECURE_NOROOT_LOCKED 1 /* make bit-0 immutable */ - -#define SECBIT_NOROOT (issecure_mask(SECURE_NOROOT)) -#define SECBIT_NOROOT_LOCKED (issecure_mask(SECURE_NOROOT_LOCKED)) - -/* When set, setuid to/from uid 0 does not trigger capability-"fixup". - When unset, to provide compatiblility with old programs relying on - set*uid to gain/lose privilege, transitions to/from uid 0 cause - capabilities to be gained/lost. */ -#define SECURE_NO_SETUID_FIXUP 2 -#define SECURE_NO_SETUID_FIXUP_LOCKED 3 /* make bit-2 immutable */ - -#define SECBIT_NO_SETUID_FIXUP (issecure_mask(SECURE_NO_SETUID_FIXUP)) -#define SECBIT_NO_SETUID_FIXUP_LOCKED \ - (issecure_mask(SECURE_NO_SETUID_FIXUP_LOCKED)) - -/* When set, a process can retain its capabilities even after - transitioning to a non-root user (the set-uid fixup suppressed by - bit 2). Bit-4 is cleared when a process calls exec(); setting both - bit 4 and 5 will create a barrier through exec that no exec()'d - child can use this feature again. */ -#define SECURE_KEEP_CAPS 4 -#define SECURE_KEEP_CAPS_LOCKED 5 /* make bit-4 immutable */ - -#define SECBIT_KEEP_CAPS (issecure_mask(SECURE_KEEP_CAPS)) -#define SECBIT_KEEP_CAPS_LOCKED (issecure_mask(SECURE_KEEP_CAPS_LOCKED)) - -/* When set, a process cannot add new capabilities to its ambient set. */ -#define SECURE_NO_CAP_AMBIENT_RAISE 6 -#define SECURE_NO_CAP_AMBIENT_RAISE_LOCKED 7 /* make bit-6 immutable */ - -#define SECBIT_NO_CAP_AMBIENT_RAISE (issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE)) -#define SECBIT_NO_CAP_AMBIENT_RAISE_LOCKED \ - (issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE_LOCKED)) - -#define SECURE_ALL_BITS (issecure_mask(SECURE_NOROOT) | \ - issecure_mask(SECURE_NO_SETUID_FIXUP) | \ - issecure_mask(SECURE_KEEP_CAPS) | \ - issecure_mask(SECURE_NO_CAP_AMBIENT_RAISE)) -#define SECURE_ALL_LOCKS (SECURE_ALL_BITS << 1) - -#endif /* _UAPI_LINUX_SECUREBITS_H */ diff --git a/src/linux/include/uapi/linux/sem.h b/src/linux/include/uapi/linux/sem.h deleted file mode 100644 index dd73b90..0000000 --- a/src/linux/include/uapi/linux/sem.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef _UAPI_LINUX_SEM_H -#define _UAPI_LINUX_SEM_H - -#include - -/* semop flags */ -#define SEM_UNDO 0x1000 /* undo the operation on exit */ - -/* semctl Command Definitions. */ -#define GETPID 11 /* get sempid */ -#define GETVAL 12 /* get semval */ -#define GETALL 13 /* get all semval's */ -#define GETNCNT 14 /* get semncnt */ -#define GETZCNT 15 /* get semzcnt */ -#define SETVAL 16 /* set semval */ -#define SETALL 17 /* set all semval's */ - -/* ipcs ctl cmds */ -#define SEM_STAT 18 -#define SEM_INFO 19 - -/* Obsolete, used only for backwards compatibility and libc5 compiles */ -struct semid_ds { - struct ipc_perm sem_perm; /* permissions .. see ipc.h */ - __kernel_time_t sem_otime; /* last semop time */ - __kernel_time_t sem_ctime; /* last change time */ - struct sem *sem_base; /* ptr to first semaphore in array */ - struct sem_queue *sem_pending; /* pending operations to be processed */ - struct sem_queue **sem_pending_last; /* last pending operation */ - struct sem_undo *undo; /* undo requests on this array */ - unsigned short sem_nsems; /* no. of semaphores in array */ -}; - -/* Include the definition of semid64_ds */ -#include - -/* semop system calls takes an array of these. */ -struct sembuf { - unsigned short sem_num; /* semaphore index in array */ - short sem_op; /* semaphore operation */ - short sem_flg; /* operation flags */ -}; - -/* arg for semctl system calls. */ -union semun { - int val; /* value for SETVAL */ - struct semid_ds __user *buf; /* buffer for IPC_STAT & IPC_SET */ - unsigned short __user *array; /* array for GETALL & SETALL */ - struct seminfo __user *__buf; /* buffer for IPC_INFO */ - void __user *__pad; -}; - -struct seminfo { - int semmap; - int semmni; - int semmns; - int semmnu; - int semmsl; - int semopm; - int semume; - int semusz; - int semvmx; - int semaem; -}; - -/* - * SEMMNI, SEMMSL and SEMMNS are default values which can be - * modified by sysctl. - * The values has been chosen to be larger than necessary for any - * known configuration. - * - * SEMOPM should not be increased beyond 1000, otherwise there is the - * risk that semop()/semtimedop() fails due to kernel memory fragmentation when - * allocating the sop array. - */ - - -#define SEMMNI 32000 /* <= IPCMNI max # of semaphore identifiers */ -#define SEMMSL 32000 /* <= INT_MAX max num of semaphores per id */ -#define SEMMNS (SEMMNI*SEMMSL) /* <= INT_MAX max # of semaphores in system */ -#define SEMOPM 500 /* <= 1 000 max num of ops per semop call */ -#define SEMVMX 32767 /* <= 32767 semaphore maximum value */ -#define SEMAEM SEMVMX /* adjust on exit max value */ - -/* unused */ -#define SEMUME SEMOPM /* max num of undo entries per process */ -#define SEMMNU SEMMNS /* num of undo structures system wide */ -#define SEMMAP SEMMNS /* # of entries in semaphore map */ -#define SEMUSZ 20 /* sizeof struct sem_undo */ - - -#endif /* _UAPI_LINUX_SEM_H */ diff --git a/src/linux/include/uapi/linux/serial.h b/src/linux/include/uapi/linux/serial.h deleted file mode 100644 index 5d59c3e..0000000 --- a/src/linux/include/uapi/linux/serial.h +++ /dev/null @@ -1,131 +0,0 @@ -/* - * include/linux/serial.h - * - * Copyright (C) 1992 by Theodore Ts'o. - * - * Redistribution of this file is permitted under the terms of the GNU - * Public License (GPL) - */ - -#ifndef _UAPI_LINUX_SERIAL_H -#define _UAPI_LINUX_SERIAL_H - -#include - -#include - - -struct serial_struct { - int type; - int line; - unsigned int port; - int irq; - int flags; - int xmit_fifo_size; - int custom_divisor; - int baud_base; - unsigned short close_delay; - char io_type; - char reserved_char[1]; - int hub6; - unsigned short closing_wait; /* time to wait before closing */ - unsigned short closing_wait2; /* no longer used... */ - unsigned char *iomem_base; - unsigned short iomem_reg_shift; - unsigned int port_high; - unsigned long iomap_base; /* cookie passed into ioremap */ -}; - -/* - * For the close wait times, 0 means wait forever for serial port to - * flush its output. 65535 means don't wait at all. - */ -#define ASYNC_CLOSING_WAIT_INF 0 -#define ASYNC_CLOSING_WAIT_NONE 65535 - -/* - * These are the supported serial types. - */ -#define PORT_UNKNOWN 0 -#define PORT_8250 1 -#define PORT_16450 2 -#define PORT_16550 3 -#define PORT_16550A 4 -#define PORT_CIRRUS 5 /* usurped by cyclades.c */ -#define PORT_16650 6 -#define PORT_16650V2 7 -#define PORT_16750 8 -#define PORT_STARTECH 9 /* usurped by cyclades.c */ -#define PORT_16C950 10 /* Oxford Semiconductor */ -#define PORT_16654 11 -#define PORT_16850 12 -#define PORT_RSA 13 /* RSA-DV II/S card */ -#define PORT_MAX 13 - -#define SERIAL_IO_PORT 0 -#define SERIAL_IO_HUB6 1 -#define SERIAL_IO_MEM 2 -#define SERIAL_IO_MEM32 3 -#define SERIAL_IO_AU 4 -#define SERIAL_IO_TSI 5 -#define SERIAL_IO_MEM32BE 6 -#define SERIAL_IO_MEM16 7 - -#define UART_CLEAR_FIFO 0x01 -#define UART_USE_FIFO 0x02 -#define UART_STARTECH 0x04 -#define UART_NATSEMI 0x08 - - -/* - * Multiport serial configuration structure --- external structure - */ -struct serial_multiport_struct { - int irq; - int port1; - unsigned char mask1, match1; - int port2; - unsigned char mask2, match2; - int port3; - unsigned char mask3, match3; - int port4; - unsigned char mask4, match4; - int port_monitor; - int reserved[32]; -}; - -/* - * Serial input interrupt line counters -- external structure - * Four lines can interrupt: CTS, DSR, RI, DCD - */ -struct serial_icounter_struct { - int cts, dsr, rng, dcd; - int rx, tx; - int frame, overrun, parity, brk; - int buf_overrun; - int reserved[9]; -}; - -/* - * Serial interface for controlling RS485 settings on chips with suitable - * support. Set with TIOCSRS485 and get with TIOCGRS485 if supported by your - * platform. The set function returns the new state, with any unsupported bits - * reverted appropriately. - */ - -struct serial_rs485 { - __u32 flags; /* RS485 feature flags */ -#define SER_RS485_ENABLED (1 << 0) /* If enabled */ -#define SER_RS485_RTS_ON_SEND (1 << 1) /* Logical level for - RTS pin when - sending */ -#define SER_RS485_RTS_AFTER_SEND (1 << 2) /* Logical level for - RTS pin after sent*/ -#define SER_RS485_RX_DURING_TX (1 << 4) - __u32 delay_rts_before_send; /* Delay before send (milliseconds) */ - __u32 delay_rts_after_send; /* Delay after send (milliseconds) */ - __u32 padding[5]; /* Memory is cheap, new structs - are a royal PITA .. */ -}; - -#endif /* _UAPI_LINUX_SERIAL_H */ diff --git a/src/linux/include/uapi/linux/serio.h b/src/linux/include/uapi/linux/serio.h deleted file mode 100644 index f2447a8..0000000 --- a/src/linux/include/uapi/linux/serio.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 1999-2002 Vojtech Pavlik -* - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as published by - * the Free Software Foundation. - */ -#ifndef _UAPI_SERIO_H -#define _UAPI_SERIO_H - - -#include - -#define SPIOCSTYPE _IOW('q', 0x01, unsigned long) - - -/* - * bit masks for use in "interrupt" flags (3rd argument) - */ -#define SERIO_TIMEOUT 1 -#define SERIO_PARITY 2 -#define SERIO_FRAME 4 - -/* - * Serio types - */ -#define SERIO_XT 0x00 -#define SERIO_8042 0x01 -#define SERIO_RS232 0x02 -#define SERIO_HIL_MLC 0x03 -#define SERIO_PS_PSTHRU 0x05 -#define SERIO_8042_XL 0x06 - -/* - * Serio protocols - */ -#define SERIO_UNKNOWN 0x00 -#define SERIO_MSC 0x01 -#define SERIO_SUN 0x02 -#define SERIO_MS 0x03 -#define SERIO_MP 0x04 -#define SERIO_MZ 0x05 -#define SERIO_MZP 0x06 -#define SERIO_MZPP 0x07 -#define SERIO_VSXXXAA 0x08 -#define SERIO_SUNKBD 0x10 -#define SERIO_WARRIOR 0x18 -#define SERIO_SPACEORB 0x19 -#define SERIO_MAGELLAN 0x1a -#define SERIO_SPACEBALL 0x1b -#define SERIO_GUNZE 0x1c -#define SERIO_IFORCE 0x1d -#define SERIO_STINGER 0x1e -#define SERIO_NEWTON 0x1f -#define SERIO_STOWAWAY 0x20 -#define SERIO_H3600 0x21 -#define SERIO_PS2SER 0x22 -#define SERIO_TWIDKBD 0x23 -#define SERIO_TWIDJOY 0x24 -#define SERIO_HIL 0x25 -#define SERIO_SNES232 0x26 -#define SERIO_SEMTECH 0x27 -#define SERIO_LKKBD 0x28 -#define SERIO_ELO 0x29 -#define SERIO_MICROTOUCH 0x30 -#define SERIO_PENMOUNT 0x31 -#define SERIO_TOUCHRIGHT 0x32 -#define SERIO_TOUCHWIN 0x33 -#define SERIO_TAOSEVM 0x34 -#define SERIO_FUJITSU 0x35 -#define SERIO_ZHENHUA 0x36 -#define SERIO_INEXIO 0x37 -#define SERIO_TOUCHIT213 0x38 -#define SERIO_W8001 0x39 -#define SERIO_DYNAPRO 0x3a -#define SERIO_HAMPSHIRE 0x3b -#define SERIO_PS2MULT 0x3c -#define SERIO_TSC40 0x3d -#define SERIO_WACOM_IV 0x3e -#define SERIO_EGALAX 0x3f -#define SERIO_PULSE8_CEC 0x40 - -#endif /* _UAPI_SERIO_H */ diff --git a/src/linux/include/uapi/linux/shm.h b/src/linux/include/uapi/linux/shm.h deleted file mode 100644 index 1fbf24e..0000000 --- a/src/linux/include/uapi/linux/shm.h +++ /dev/null @@ -1,80 +0,0 @@ -#ifndef _UAPI_LINUX_SHM_H_ -#define _UAPI_LINUX_SHM_H_ - -#include -#include -#ifndef __KERNEL__ -#include -#endif - -/* - * SHMMNI, SHMMAX and SHMALL are default upper limits which can be - * modified by sysctl. The SHMMAX and SHMALL values have been chosen to - * be as large possible without facilitating scenarios where userspace - * causes overflows when adjusting the limits via operations of the form - * "retrieve current limit; add X; update limit". It is therefore not - * advised to make SHMMAX and SHMALL any larger. These limits are - * suitable for both 32 and 64-bit systems. - */ -#define SHMMIN 1 /* min shared seg size (bytes) */ -#define SHMMNI 4096 /* max num of segs system wide */ -#define SHMMAX (ULONG_MAX - (1UL << 24)) /* max shared seg size (bytes) */ -#define SHMALL (ULONG_MAX - (1UL << 24)) /* max shm system wide (pages) */ -#define SHMSEG SHMMNI /* max shared segs per process */ - -/* Obsolete, used only for backwards compatibility and libc5 compiles */ -struct shmid_ds { - struct ipc_perm shm_perm; /* operation perms */ - int shm_segsz; /* size of segment (bytes) */ - __kernel_time_t shm_atime; /* last attach time */ - __kernel_time_t shm_dtime; /* last detach time */ - __kernel_time_t shm_ctime; /* last change time */ - __kernel_ipc_pid_t shm_cpid; /* pid of creator */ - __kernel_ipc_pid_t shm_lpid; /* pid of last operator */ - unsigned short shm_nattch; /* no. of current attaches */ - unsigned short shm_unused; /* compatibility */ - void *shm_unused2; /* ditto - used by DIPC */ - void *shm_unused3; /* unused */ -}; - -/* Include the definition of shmid64_ds and shminfo64 */ -#include - -/* permission flag for shmget */ -#define SHM_R 0400 /* or S_IRUGO from */ -#define SHM_W 0200 /* or S_IWUGO from */ - -/* mode for attach */ -#define SHM_RDONLY 010000 /* read-only access */ -#define SHM_RND 020000 /* round attach address to SHMLBA boundary */ -#define SHM_REMAP 040000 /* take-over region on attach */ -#define SHM_EXEC 0100000 /* execution access */ - -/* super user shmctl commands */ -#define SHM_LOCK 11 -#define SHM_UNLOCK 12 - -/* ipcs ctl commands */ -#define SHM_STAT 13 -#define SHM_INFO 14 - -/* Obsolete, used only for backwards compatibility */ -struct shminfo { - int shmmax; - int shmmin; - int shmmni; - int shmseg; - int shmall; -}; - -struct shm_info { - int used_ids; - __kernel_ulong_t shm_tot; /* total allocated shm */ - __kernel_ulong_t shm_rss; /* total resident shm */ - __kernel_ulong_t shm_swp; /* total swapped shm */ - __kernel_ulong_t swap_attempts; - __kernel_ulong_t swap_successes; -}; - - -#endif /* _UAPI_LINUX_SHM_H_ */ diff --git a/src/linux/include/uapi/linux/signal.h b/src/linux/include/uapi/linux/signal.h deleted file mode 100644 index cd0804b..0000000 --- a/src/linux/include/uapi/linux/signal.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _UAPI_LINUX_SIGNAL_H -#define _UAPI_LINUX_SIGNAL_H - -#include -#include - -#define SS_ONSTACK 1 -#define SS_DISABLE 2 - -/* bit-flags */ -#define SS_AUTODISARM (1U << 31) /* disable sas during sighandling */ -/* mask for all SS_xxx flags */ -#define SS_FLAG_BITS SS_AUTODISARM - -#endif /* _UAPI_LINUX_SIGNAL_H */ diff --git a/src/linux/include/uapi/linux/signalfd.h b/src/linux/include/uapi/linux/signalfd.h deleted file mode 100644 index 492c6de..0000000 --- a/src/linux/include/uapi/linux/signalfd.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * include/linux/signalfd.h - * - * Copyright (C) 2007 Davide Libenzi - * - */ - -#ifndef _UAPI_LINUX_SIGNALFD_H -#define _UAPI_LINUX_SIGNALFD_H - -#include -/* For O_CLOEXEC and O_NONBLOCK */ -#include - -/* Flags for signalfd4. */ -#define SFD_CLOEXEC O_CLOEXEC -#define SFD_NONBLOCK O_NONBLOCK - -struct signalfd_siginfo { - __u32 ssi_signo; - __s32 ssi_errno; - __s32 ssi_code; - __u32 ssi_pid; - __u32 ssi_uid; - __s32 ssi_fd; - __u32 ssi_tid; - __u32 ssi_band; - __u32 ssi_overrun; - __u32 ssi_trapno; - __s32 ssi_status; - __s32 ssi_int; - __u64 ssi_ptr; - __u64 ssi_utime; - __u64 ssi_stime; - __u64 ssi_addr; - __u16 ssi_addr_lsb; - - /* - * Pad strcture to 128 bytes. Remember to update the - * pad size when you add new members. We use a fixed - * size structure to avoid compatibility problems with - * future versions, and we leave extra space for additional - * members. We use fixed size members because this strcture - * comes out of a read(2) and we really don't want to have - * a compat on read(2). - */ - __u8 __pad[46]; -}; - - - -#endif /* _UAPI_LINUX_SIGNALFD_H */ diff --git a/src/linux/include/uapi/linux/snmp.h b/src/linux/include/uapi/linux/snmp.h deleted file mode 100644 index e7a31f8..0000000 --- a/src/linux/include/uapi/linux/snmp.h +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Definitions for MIBs - * - * Author: Hideaki YOSHIFUJI - */ - -#ifndef _LINUX_SNMP_H -#define _LINUX_SNMP_H - -/* ipstats mib definitions */ -/* - * RFC 1213: MIB-II - * RFC 2011 (updates 1213): SNMPv2-MIB-IP - * RFC 2863: Interfaces Group MIB - * RFC 2465: IPv6 MIB: General Group - * draft-ietf-ipv6-rfc2011-update-10.txt: MIB for IP: IP Statistics Tables - */ -enum -{ - IPSTATS_MIB_NUM = 0, -/* frequently written fields in fast path, kept in same cache line */ - IPSTATS_MIB_INPKTS, /* InReceives */ - IPSTATS_MIB_INOCTETS, /* InOctets */ - IPSTATS_MIB_INDELIVERS, /* InDelivers */ - IPSTATS_MIB_OUTFORWDATAGRAMS, /* OutForwDatagrams */ - IPSTATS_MIB_OUTPKTS, /* OutRequests */ - IPSTATS_MIB_OUTOCTETS, /* OutOctets */ -/* other fields */ - IPSTATS_MIB_INHDRERRORS, /* InHdrErrors */ - IPSTATS_MIB_INTOOBIGERRORS, /* InTooBigErrors */ - IPSTATS_MIB_INNOROUTES, /* InNoRoutes */ - IPSTATS_MIB_INADDRERRORS, /* InAddrErrors */ - IPSTATS_MIB_INUNKNOWNPROTOS, /* InUnknownProtos */ - IPSTATS_MIB_INTRUNCATEDPKTS, /* InTruncatedPkts */ - IPSTATS_MIB_INDISCARDS, /* InDiscards */ - IPSTATS_MIB_OUTDISCARDS, /* OutDiscards */ - IPSTATS_MIB_OUTNOROUTES, /* OutNoRoutes */ - IPSTATS_MIB_REASMTIMEOUT, /* ReasmTimeout */ - IPSTATS_MIB_REASMREQDS, /* ReasmReqds */ - IPSTATS_MIB_REASMOKS, /* ReasmOKs */ - IPSTATS_MIB_REASMFAILS, /* ReasmFails */ - IPSTATS_MIB_FRAGOKS, /* FragOKs */ - IPSTATS_MIB_FRAGFAILS, /* FragFails */ - IPSTATS_MIB_FRAGCREATES, /* FragCreates */ - IPSTATS_MIB_INMCASTPKTS, /* InMcastPkts */ - IPSTATS_MIB_OUTMCASTPKTS, /* OutMcastPkts */ - IPSTATS_MIB_INBCASTPKTS, /* InBcastPkts */ - IPSTATS_MIB_OUTBCASTPKTS, /* OutBcastPkts */ - IPSTATS_MIB_INMCASTOCTETS, /* InMcastOctets */ - IPSTATS_MIB_OUTMCASTOCTETS, /* OutMcastOctets */ - IPSTATS_MIB_INBCASTOCTETS, /* InBcastOctets */ - IPSTATS_MIB_OUTBCASTOCTETS, /* OutBcastOctets */ - IPSTATS_MIB_CSUMERRORS, /* InCsumErrors */ - IPSTATS_MIB_NOECTPKTS, /* InNoECTPkts */ - IPSTATS_MIB_ECT1PKTS, /* InECT1Pkts */ - IPSTATS_MIB_ECT0PKTS, /* InECT0Pkts */ - IPSTATS_MIB_CEPKTS, /* InCEPkts */ - __IPSTATS_MIB_MAX -}; - -/* icmp mib definitions */ -/* - * RFC 1213: MIB-II ICMP Group - * RFC 2011 (updates 1213): SNMPv2 MIB for IP: ICMP group - */ -enum -{ - ICMP_MIB_NUM = 0, - ICMP_MIB_INMSGS, /* InMsgs */ - ICMP_MIB_INERRORS, /* InErrors */ - ICMP_MIB_INDESTUNREACHS, /* InDestUnreachs */ - ICMP_MIB_INTIMEEXCDS, /* InTimeExcds */ - ICMP_MIB_INPARMPROBS, /* InParmProbs */ - ICMP_MIB_INSRCQUENCHS, /* InSrcQuenchs */ - ICMP_MIB_INREDIRECTS, /* InRedirects */ - ICMP_MIB_INECHOS, /* InEchos */ - ICMP_MIB_INECHOREPS, /* InEchoReps */ - ICMP_MIB_INTIMESTAMPS, /* InTimestamps */ - ICMP_MIB_INTIMESTAMPREPS, /* InTimestampReps */ - ICMP_MIB_INADDRMASKS, /* InAddrMasks */ - ICMP_MIB_INADDRMASKREPS, /* InAddrMaskReps */ - ICMP_MIB_OUTMSGS, /* OutMsgs */ - ICMP_MIB_OUTERRORS, /* OutErrors */ - ICMP_MIB_OUTDESTUNREACHS, /* OutDestUnreachs */ - ICMP_MIB_OUTTIMEEXCDS, /* OutTimeExcds */ - ICMP_MIB_OUTPARMPROBS, /* OutParmProbs */ - ICMP_MIB_OUTSRCQUENCHS, /* OutSrcQuenchs */ - ICMP_MIB_OUTREDIRECTS, /* OutRedirects */ - ICMP_MIB_OUTECHOS, /* OutEchos */ - ICMP_MIB_OUTECHOREPS, /* OutEchoReps */ - ICMP_MIB_OUTTIMESTAMPS, /* OutTimestamps */ - ICMP_MIB_OUTTIMESTAMPREPS, /* OutTimestampReps */ - ICMP_MIB_OUTADDRMASKS, /* OutAddrMasks */ - ICMP_MIB_OUTADDRMASKREPS, /* OutAddrMaskReps */ - ICMP_MIB_CSUMERRORS, /* InCsumErrors */ - __ICMP_MIB_MAX -}; - -#define __ICMPMSG_MIB_MAX 512 /* Out+In for all 8-bit ICMP types */ - -/* icmp6 mib definitions */ -/* - * RFC 2466: ICMPv6-MIB - */ -enum -{ - ICMP6_MIB_NUM = 0, - ICMP6_MIB_INMSGS, /* InMsgs */ - ICMP6_MIB_INERRORS, /* InErrors */ - ICMP6_MIB_OUTMSGS, /* OutMsgs */ - ICMP6_MIB_OUTERRORS, /* OutErrors */ - ICMP6_MIB_CSUMERRORS, /* InCsumErrors */ - __ICMP6_MIB_MAX -}; - -#define __ICMP6MSG_MIB_MAX 512 /* Out+In for all 8-bit ICMPv6 types */ - -/* tcp mib definitions */ -/* - * RFC 1213: MIB-II TCP group - * RFC 2012 (updates 1213): SNMPv2-MIB-TCP - */ -enum -{ - TCP_MIB_NUM = 0, - TCP_MIB_RTOALGORITHM, /* RtoAlgorithm */ - TCP_MIB_RTOMIN, /* RtoMin */ - TCP_MIB_RTOMAX, /* RtoMax */ - TCP_MIB_MAXCONN, /* MaxConn */ - TCP_MIB_ACTIVEOPENS, /* ActiveOpens */ - TCP_MIB_PASSIVEOPENS, /* PassiveOpens */ - TCP_MIB_ATTEMPTFAILS, /* AttemptFails */ - TCP_MIB_ESTABRESETS, /* EstabResets */ - TCP_MIB_CURRESTAB, /* CurrEstab */ - TCP_MIB_INSEGS, /* InSegs */ - TCP_MIB_OUTSEGS, /* OutSegs */ - TCP_MIB_RETRANSSEGS, /* RetransSegs */ - TCP_MIB_INERRS, /* InErrs */ - TCP_MIB_OUTRSTS, /* OutRsts */ - TCP_MIB_CSUMERRORS, /* InCsumErrors */ - __TCP_MIB_MAX -}; - -/* udp mib definitions */ -/* - * RFC 1213: MIB-II UDP group - * RFC 2013 (updates 1213): SNMPv2-MIB-UDP - */ -enum -{ - UDP_MIB_NUM = 0, - UDP_MIB_INDATAGRAMS, /* InDatagrams */ - UDP_MIB_NOPORTS, /* NoPorts */ - UDP_MIB_INERRORS, /* InErrors */ - UDP_MIB_OUTDATAGRAMS, /* OutDatagrams */ - UDP_MIB_RCVBUFERRORS, /* RcvbufErrors */ - UDP_MIB_SNDBUFERRORS, /* SndbufErrors */ - UDP_MIB_CSUMERRORS, /* InCsumErrors */ - UDP_MIB_IGNOREDMULTI, /* IgnoredMulti */ - __UDP_MIB_MAX -}; - -/* linux mib definitions */ -enum -{ - LINUX_MIB_NUM = 0, - LINUX_MIB_SYNCOOKIESSENT, /* SyncookiesSent */ - LINUX_MIB_SYNCOOKIESRECV, /* SyncookiesRecv */ - LINUX_MIB_SYNCOOKIESFAILED, /* SyncookiesFailed */ - LINUX_MIB_EMBRYONICRSTS, /* EmbryonicRsts */ - LINUX_MIB_PRUNECALLED, /* PruneCalled */ - LINUX_MIB_RCVPRUNED, /* RcvPruned */ - LINUX_MIB_OFOPRUNED, /* OfoPruned */ - LINUX_MIB_OUTOFWINDOWICMPS, /* OutOfWindowIcmps */ - LINUX_MIB_LOCKDROPPEDICMPS, /* LockDroppedIcmps */ - LINUX_MIB_ARPFILTER, /* ArpFilter */ - LINUX_MIB_TIMEWAITED, /* TimeWaited */ - LINUX_MIB_TIMEWAITRECYCLED, /* TimeWaitRecycled */ - LINUX_MIB_TIMEWAITKILLED, /* TimeWaitKilled */ - LINUX_MIB_PAWSPASSIVEREJECTED, /* PAWSPassiveRejected */ - LINUX_MIB_PAWSACTIVEREJECTED, /* PAWSActiveRejected */ - LINUX_MIB_PAWSESTABREJECTED, /* PAWSEstabRejected */ - LINUX_MIB_DELAYEDACKS, /* DelayedACKs */ - LINUX_MIB_DELAYEDACKLOCKED, /* DelayedACKLocked */ - LINUX_MIB_DELAYEDACKLOST, /* DelayedACKLost */ - LINUX_MIB_LISTENOVERFLOWS, /* ListenOverflows */ - LINUX_MIB_LISTENDROPS, /* ListenDrops */ - LINUX_MIB_TCPPREQUEUED, /* TCPPrequeued */ - LINUX_MIB_TCPDIRECTCOPYFROMBACKLOG, /* TCPDirectCopyFromBacklog */ - LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE, /* TCPDirectCopyFromPrequeue */ - LINUX_MIB_TCPPREQUEUEDROPPED, /* TCPPrequeueDropped */ - LINUX_MIB_TCPHPHITS, /* TCPHPHits */ - LINUX_MIB_TCPHPHITSTOUSER, /* TCPHPHitsToUser */ - LINUX_MIB_TCPPUREACKS, /* TCPPureAcks */ - LINUX_MIB_TCPHPACKS, /* TCPHPAcks */ - LINUX_MIB_TCPRENORECOVERY, /* TCPRenoRecovery */ - LINUX_MIB_TCPSACKRECOVERY, /* TCPSackRecovery */ - LINUX_MIB_TCPSACKRENEGING, /* TCPSACKReneging */ - LINUX_MIB_TCPFACKREORDER, /* TCPFACKReorder */ - LINUX_MIB_TCPSACKREORDER, /* TCPSACKReorder */ - LINUX_MIB_TCPRENOREORDER, /* TCPRenoReorder */ - LINUX_MIB_TCPTSREORDER, /* TCPTSReorder */ - LINUX_MIB_TCPFULLUNDO, /* TCPFullUndo */ - LINUX_MIB_TCPPARTIALUNDO, /* TCPPartialUndo */ - LINUX_MIB_TCPDSACKUNDO, /* TCPDSACKUndo */ - LINUX_MIB_TCPLOSSUNDO, /* TCPLossUndo */ - LINUX_MIB_TCPLOSTRETRANSMIT, /* TCPLostRetransmit */ - LINUX_MIB_TCPRENOFAILURES, /* TCPRenoFailures */ - LINUX_MIB_TCPSACKFAILURES, /* TCPSackFailures */ - LINUX_MIB_TCPLOSSFAILURES, /* TCPLossFailures */ - LINUX_MIB_TCPFASTRETRANS, /* TCPFastRetrans */ - LINUX_MIB_TCPFORWARDRETRANS, /* TCPForwardRetrans */ - LINUX_MIB_TCPSLOWSTARTRETRANS, /* TCPSlowStartRetrans */ - LINUX_MIB_TCPTIMEOUTS, /* TCPTimeouts */ - LINUX_MIB_TCPLOSSPROBES, /* TCPLossProbes */ - LINUX_MIB_TCPLOSSPROBERECOVERY, /* TCPLossProbeRecovery */ - LINUX_MIB_TCPRENORECOVERYFAIL, /* TCPRenoRecoveryFail */ - LINUX_MIB_TCPSACKRECOVERYFAIL, /* TCPSackRecoveryFail */ - LINUX_MIB_TCPSCHEDULERFAILED, /* TCPSchedulerFailed */ - LINUX_MIB_TCPRCVCOLLAPSED, /* TCPRcvCollapsed */ - LINUX_MIB_TCPDSACKOLDSENT, /* TCPDSACKOldSent */ - LINUX_MIB_TCPDSACKOFOSENT, /* TCPDSACKOfoSent */ - LINUX_MIB_TCPDSACKRECV, /* TCPDSACKRecv */ - LINUX_MIB_TCPDSACKOFORECV, /* TCPDSACKOfoRecv */ - LINUX_MIB_TCPABORTONDATA, /* TCPAbortOnData */ - LINUX_MIB_TCPABORTONCLOSE, /* TCPAbortOnClose */ - LINUX_MIB_TCPABORTONMEMORY, /* TCPAbortOnMemory */ - LINUX_MIB_TCPABORTONTIMEOUT, /* TCPAbortOnTimeout */ - LINUX_MIB_TCPABORTONLINGER, /* TCPAbortOnLinger */ - LINUX_MIB_TCPABORTFAILED, /* TCPAbortFailed */ - LINUX_MIB_TCPMEMORYPRESSURES, /* TCPMemoryPressures */ - LINUX_MIB_TCPSACKDISCARD, /* TCPSACKDiscard */ - LINUX_MIB_TCPDSACKIGNOREDOLD, /* TCPSACKIgnoredOld */ - LINUX_MIB_TCPDSACKIGNOREDNOUNDO, /* TCPSACKIgnoredNoUndo */ - LINUX_MIB_TCPSPURIOUSRTOS, /* TCPSpuriousRTOs */ - LINUX_MIB_TCPMD5NOTFOUND, /* TCPMD5NotFound */ - LINUX_MIB_TCPMD5UNEXPECTED, /* TCPMD5Unexpected */ - LINUX_MIB_TCPMD5FAILURE, /* TCPMD5Failure */ - LINUX_MIB_SACKSHIFTED, - LINUX_MIB_SACKMERGED, - LINUX_MIB_SACKSHIFTFALLBACK, - LINUX_MIB_TCPBACKLOGDROP, - LINUX_MIB_TCPMINTTLDROP, /* RFC 5082 */ - LINUX_MIB_TCPDEFERACCEPTDROP, - LINUX_MIB_IPRPFILTER, /* IP Reverse Path Filter (rp_filter) */ - LINUX_MIB_TCPTIMEWAITOVERFLOW, /* TCPTimeWaitOverflow */ - LINUX_MIB_TCPREQQFULLDOCOOKIES, /* TCPReqQFullDoCookies */ - LINUX_MIB_TCPREQQFULLDROP, /* TCPReqQFullDrop */ - LINUX_MIB_TCPRETRANSFAIL, /* TCPRetransFail */ - LINUX_MIB_TCPRCVCOALESCE, /* TCPRcvCoalesce */ - LINUX_MIB_TCPOFOQUEUE, /* TCPOFOQueue */ - LINUX_MIB_TCPOFODROP, /* TCPOFODrop */ - LINUX_MIB_TCPOFOMERGE, /* TCPOFOMerge */ - LINUX_MIB_TCPCHALLENGEACK, /* TCPChallengeACK */ - LINUX_MIB_TCPSYNCHALLENGE, /* TCPSYNChallenge */ - LINUX_MIB_TCPFASTOPENACTIVE, /* TCPFastOpenActive */ - LINUX_MIB_TCPFASTOPENACTIVEFAIL, /* TCPFastOpenActiveFail */ - LINUX_MIB_TCPFASTOPENPASSIVE, /* TCPFastOpenPassive*/ - LINUX_MIB_TCPFASTOPENPASSIVEFAIL, /* TCPFastOpenPassiveFail */ - LINUX_MIB_TCPFASTOPENLISTENOVERFLOW, /* TCPFastOpenListenOverflow */ - LINUX_MIB_TCPFASTOPENCOOKIEREQD, /* TCPFastOpenCookieReqd */ - LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES, /* TCPSpuriousRtxHostQueues */ - LINUX_MIB_BUSYPOLLRXPACKETS, /* BusyPollRxPackets */ - LINUX_MIB_TCPAUTOCORKING, /* TCPAutoCorking */ - LINUX_MIB_TCPFROMZEROWINDOWADV, /* TCPFromZeroWindowAdv */ - LINUX_MIB_TCPTOZEROWINDOWADV, /* TCPToZeroWindowAdv */ - LINUX_MIB_TCPWANTZEROWINDOWADV, /* TCPWantZeroWindowAdv */ - LINUX_MIB_TCPSYNRETRANS, /* TCPSynRetrans */ - LINUX_MIB_TCPORIGDATASENT, /* TCPOrigDataSent */ - LINUX_MIB_TCPHYSTARTTRAINDETECT, /* TCPHystartTrainDetect */ - LINUX_MIB_TCPHYSTARTTRAINCWND, /* TCPHystartTrainCwnd */ - LINUX_MIB_TCPHYSTARTDELAYDETECT, /* TCPHystartDelayDetect */ - LINUX_MIB_TCPHYSTARTDELAYCWND, /* TCPHystartDelayCwnd */ - LINUX_MIB_TCPACKSKIPPEDSYNRECV, /* TCPACKSkippedSynRecv */ - LINUX_MIB_TCPACKSKIPPEDPAWS, /* TCPACKSkippedPAWS */ - LINUX_MIB_TCPACKSKIPPEDSEQ, /* TCPACKSkippedSeq */ - LINUX_MIB_TCPACKSKIPPEDFINWAIT2, /* TCPACKSkippedFinWait2 */ - LINUX_MIB_TCPACKSKIPPEDTIMEWAIT, /* TCPACKSkippedTimeWait */ - LINUX_MIB_TCPACKSKIPPEDCHALLENGE, /* TCPACKSkippedChallenge */ - LINUX_MIB_TCPWINPROBE, /* TCPWinProbe */ - LINUX_MIB_TCPKEEPALIVE, /* TCPKeepAlive */ - LINUX_MIB_TCPMTUPFAIL, /* TCPMTUPFail */ - LINUX_MIB_TCPMTUPSUCCESS, /* TCPMTUPSuccess */ - __LINUX_MIB_MAX -}; - -/* linux Xfrm mib definitions */ -enum -{ - LINUX_MIB_XFRMNUM = 0, - LINUX_MIB_XFRMINERROR, /* XfrmInError */ - LINUX_MIB_XFRMINBUFFERERROR, /* XfrmInBufferError */ - LINUX_MIB_XFRMINHDRERROR, /* XfrmInHdrError */ - LINUX_MIB_XFRMINNOSTATES, /* XfrmInNoStates */ - LINUX_MIB_XFRMINSTATEPROTOERROR, /* XfrmInStateProtoError */ - LINUX_MIB_XFRMINSTATEMODEERROR, /* XfrmInStateModeError */ - LINUX_MIB_XFRMINSTATESEQERROR, /* XfrmInStateSeqError */ - LINUX_MIB_XFRMINSTATEEXPIRED, /* XfrmInStateExpired */ - LINUX_MIB_XFRMINSTATEMISMATCH, /* XfrmInStateMismatch */ - LINUX_MIB_XFRMINSTATEINVALID, /* XfrmInStateInvalid */ - LINUX_MIB_XFRMINTMPLMISMATCH, /* XfrmInTmplMismatch */ - LINUX_MIB_XFRMINNOPOLS, /* XfrmInNoPols */ - LINUX_MIB_XFRMINPOLBLOCK, /* XfrmInPolBlock */ - LINUX_MIB_XFRMINPOLERROR, /* XfrmInPolError */ - LINUX_MIB_XFRMOUTERROR, /* XfrmOutError */ - LINUX_MIB_XFRMOUTBUNDLEGENERROR, /* XfrmOutBundleGenError */ - LINUX_MIB_XFRMOUTBUNDLECHECKERROR, /* XfrmOutBundleCheckError */ - LINUX_MIB_XFRMOUTNOSTATES, /* XfrmOutNoStates */ - LINUX_MIB_XFRMOUTSTATEPROTOERROR, /* XfrmOutStateProtoError */ - LINUX_MIB_XFRMOUTSTATEMODEERROR, /* XfrmOutStateModeError */ - LINUX_MIB_XFRMOUTSTATESEQERROR, /* XfrmOutStateSeqError */ - LINUX_MIB_XFRMOUTSTATEEXPIRED, /* XfrmOutStateExpired */ - LINUX_MIB_XFRMOUTPOLBLOCK, /* XfrmOutPolBlock */ - LINUX_MIB_XFRMOUTPOLDEAD, /* XfrmOutPolDead */ - LINUX_MIB_XFRMOUTPOLERROR, /* XfrmOutPolError */ - LINUX_MIB_XFRMFWDHDRERROR, /* XfrmFwdHdrError*/ - LINUX_MIB_XFRMOUTSTATEINVALID, /* XfrmOutStateInvalid */ - LINUX_MIB_XFRMACQUIREERROR, /* XfrmAcquireError */ - __LINUX_MIB_XFRMMAX -}; - -#endif /* _LINUX_SNMP_H */ diff --git a/src/linux/include/uapi/linux/sock_diag.h b/src/linux/include/uapi/linux/sock_diag.h deleted file mode 100644 index 7ff505d..0000000 --- a/src/linux/include/uapi/linux/sock_diag.h +++ /dev/null @@ -1,38 +0,0 @@ -#ifndef _UAPI__SOCK_DIAG_H__ -#define _UAPI__SOCK_DIAG_H__ - -#include - -#define SOCK_DIAG_BY_FAMILY 20 -#define SOCK_DESTROY 21 - -struct sock_diag_req { - __u8 sdiag_family; - __u8 sdiag_protocol; -}; - -enum { - SK_MEMINFO_RMEM_ALLOC, - SK_MEMINFO_RCVBUF, - SK_MEMINFO_WMEM_ALLOC, - SK_MEMINFO_SNDBUF, - SK_MEMINFO_FWD_ALLOC, - SK_MEMINFO_WMEM_QUEUED, - SK_MEMINFO_OPTMEM, - SK_MEMINFO_BACKLOG, - SK_MEMINFO_DROPS, - - SK_MEMINFO_VARS, -}; - -enum sknetlink_groups { - SKNLGRP_NONE, - SKNLGRP_INET_TCP_DESTROY, - SKNLGRP_INET_UDP_DESTROY, - SKNLGRP_INET6_TCP_DESTROY, - SKNLGRP_INET6_UDP_DESTROY, - __SKNLGRP_MAX, -}; -#define SKNLGRP_MAX (__SKNLGRP_MAX - 1) - -#endif /* _UAPI__SOCK_DIAG_H__ */ diff --git a/src/linux/include/uapi/linux/socket.h b/src/linux/include/uapi/linux/socket.h deleted file mode 100644 index 76ab0c6..0000000 --- a/src/linux/include/uapi/linux/socket.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _UAPI_LINUX_SOCKET_H -#define _UAPI_LINUX_SOCKET_H - -/* - * Desired design of maximum size and alignment (see RFC2553) - */ -#define _K_SS_MAXSIZE 128 /* Implementation specific max size */ -#define _K_SS_ALIGNSIZE (__alignof__ (struct sockaddr *)) - /* Implementation specific desired alignment */ - -typedef unsigned short __kernel_sa_family_t; - -struct __kernel_sockaddr_storage { - __kernel_sa_family_t ss_family; /* address family */ - /* Following field(s) are implementation specific */ - char __data[_K_SS_MAXSIZE - sizeof(unsigned short)]; - /* space to achieve desired size, */ - /* _SS_MAXSIZE value minus size of ss_family */ -} __attribute__ ((aligned(_K_SS_ALIGNSIZE))); /* force desired alignment */ - -#endif /* _UAPI_LINUX_SOCKET_H */ diff --git a/src/linux/include/uapi/linux/sockios.h b/src/linux/include/uapi/linux/sockios.h deleted file mode 100644 index 8e7890b..0000000 --- a/src/linux/include/uapi/linux/sockios.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions of the socket-level I/O control calls. - * - * Version: @(#)sockios.h 1.0.2 03/09/93 - * - * Authors: Ross Biro - * Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _LINUX_SOCKIOS_H -#define _LINUX_SOCKIOS_H - -#include - -/* Linux-specific socket ioctls */ -#define SIOCINQ FIONREAD -#define SIOCOUTQ TIOCOUTQ /* output queue size (not sent + not acked) */ - -/* Routing table calls. */ -#define SIOCADDRT 0x890B /* add routing table entry */ -#define SIOCDELRT 0x890C /* delete routing table entry */ -#define SIOCRTMSG 0x890D /* unused */ - -/* Socket configuration controls. */ -#define SIOCGIFNAME 0x8910 /* get iface name */ -#define SIOCSIFLINK 0x8911 /* set iface channel */ -#define SIOCGIFCONF 0x8912 /* get iface list */ -#define SIOCGIFFLAGS 0x8913 /* get flags */ -#define SIOCSIFFLAGS 0x8914 /* set flags */ -#define SIOCGIFADDR 0x8915 /* get PA address */ -#define SIOCSIFADDR 0x8916 /* set PA address */ -#define SIOCGIFDSTADDR 0x8917 /* get remote PA address */ -#define SIOCSIFDSTADDR 0x8918 /* set remote PA address */ -#define SIOCGIFBRDADDR 0x8919 /* get broadcast PA address */ -#define SIOCSIFBRDADDR 0x891a /* set broadcast PA address */ -#define SIOCGIFNETMASK 0x891b /* get network PA mask */ -#define SIOCSIFNETMASK 0x891c /* set network PA mask */ -#define SIOCGIFMETRIC 0x891d /* get metric */ -#define SIOCSIFMETRIC 0x891e /* set metric */ -#define SIOCGIFMEM 0x891f /* get memory address (BSD) */ -#define SIOCSIFMEM 0x8920 /* set memory address (BSD) */ -#define SIOCGIFMTU 0x8921 /* get MTU size */ -#define SIOCSIFMTU 0x8922 /* set MTU size */ -#define SIOCSIFNAME 0x8923 /* set interface name */ -#define SIOCSIFHWADDR 0x8924 /* set hardware address */ -#define SIOCGIFENCAP 0x8925 /* get/set encapsulations */ -#define SIOCSIFENCAP 0x8926 -#define SIOCGIFHWADDR 0x8927 /* Get hardware address */ -#define SIOCGIFSLAVE 0x8929 /* Driver slaving support */ -#define SIOCSIFSLAVE 0x8930 -#define SIOCADDMULTI 0x8931 /* Multicast address lists */ -#define SIOCDELMULTI 0x8932 -#define SIOCGIFINDEX 0x8933 /* name -> if_index mapping */ -#define SIOGIFINDEX SIOCGIFINDEX /* misprint compatibility :-) */ -#define SIOCSIFPFLAGS 0x8934 /* set/get extended flags set */ -#define SIOCGIFPFLAGS 0x8935 -#define SIOCDIFADDR 0x8936 /* delete PA address */ -#define SIOCSIFHWBROADCAST 0x8937 /* set hardware broadcast addr */ -#define SIOCGIFCOUNT 0x8938 /* get number of devices */ - -#define SIOCGIFBR 0x8940 /* Bridging support */ -#define SIOCSIFBR 0x8941 /* Set bridging options */ - -#define SIOCGIFTXQLEN 0x8942 /* Get the tx queue length */ -#define SIOCSIFTXQLEN 0x8943 /* Set the tx queue length */ - -/* SIOCGIFDIVERT was: 0x8944 Frame diversion support */ -/* SIOCSIFDIVERT was: 0x8945 Set frame diversion options */ - -#define SIOCETHTOOL 0x8946 /* Ethtool interface */ - -#define SIOCGMIIPHY 0x8947 /* Get address of MII PHY in use. */ -#define SIOCGMIIREG 0x8948 /* Read MII PHY register. */ -#define SIOCSMIIREG 0x8949 /* Write MII PHY register. */ - -#define SIOCWANDEV 0x894A /* get/set netdev parameters */ - -#define SIOCOUTQNSD 0x894B /* output queue size (not sent only) */ - -/* ARP cache control calls. */ - /* 0x8950 - 0x8952 * obsolete calls, don't re-use */ -#define SIOCDARP 0x8953 /* delete ARP table entry */ -#define SIOCGARP 0x8954 /* get ARP table entry */ -#define SIOCSARP 0x8955 /* set ARP table entry */ - -/* RARP cache control calls. */ -#define SIOCDRARP 0x8960 /* delete RARP table entry */ -#define SIOCGRARP 0x8961 /* get RARP table entry */ -#define SIOCSRARP 0x8962 /* set RARP table entry */ - -/* Driver configuration calls */ - -#define SIOCGIFMAP 0x8970 /* Get device parameters */ -#define SIOCSIFMAP 0x8971 /* Set device parameters */ - -/* DLCI configuration calls */ - -#define SIOCADDDLCI 0x8980 /* Create new DLCI device */ -#define SIOCDELDLCI 0x8981 /* Delete DLCI device */ - -#define SIOCGIFVLAN 0x8982 /* 802.1Q VLAN support */ -#define SIOCSIFVLAN 0x8983 /* Set 802.1Q VLAN options */ - -/* bonding calls */ - -#define SIOCBONDENSLAVE 0x8990 /* enslave a device to the bond */ -#define SIOCBONDRELEASE 0x8991 /* release a slave from the bond*/ -#define SIOCBONDSETHWADDR 0x8992 /* set the hw addr of the bond */ -#define SIOCBONDSLAVEINFOQUERY 0x8993 /* rtn info about slave state */ -#define SIOCBONDINFOQUERY 0x8994 /* rtn info about bond state */ -#define SIOCBONDCHANGEACTIVE 0x8995 /* update to a new active slave */ - -/* bridge calls */ -#define SIOCBRADDBR 0x89a0 /* create new bridge device */ -#define SIOCBRDELBR 0x89a1 /* remove bridge device */ -#define SIOCBRADDIF 0x89a2 /* add interface to bridge */ -#define SIOCBRDELIF 0x89a3 /* remove interface from bridge */ - -/* hardware time stamping: parameters in linux/net_tstamp.h */ -#define SIOCSHWTSTAMP 0x89b0 /* set and get config */ -#define SIOCGHWTSTAMP 0x89b1 /* get config */ - -/* Device private ioctl calls */ - -/* - * These 16 ioctls are available to devices via the do_ioctl() device - * vector. Each device should include this file and redefine these names - * as their own. Because these are device dependent it is a good idea - * _NOT_ to issue them to random objects and hope. - * - * THESE IOCTLS ARE _DEPRECATED_ AND WILL DISAPPEAR IN 2.5.X -DaveM - */ - -#define SIOCDEVPRIVATE 0x89F0 /* to 89FF */ - -/* - * These 16 ioctl calls are protocol private - */ - -#define SIOCPROTOPRIVATE 0x89E0 /* to 89EF */ -#endif /* _LINUX_SOCKIOS_H */ diff --git a/src/linux/include/uapi/linux/stat.h b/src/linux/include/uapi/linux/stat.h deleted file mode 100644 index 7fec7e3..0000000 --- a/src/linux/include/uapi/linux/stat.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _UAPI_LINUX_STAT_H -#define _UAPI_LINUX_STAT_H - - -#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) - -#define S_IFMT 00170000 -#define S_IFSOCK 0140000 -#define S_IFLNK 0120000 -#define S_IFREG 0100000 -#define S_IFBLK 0060000 -#define S_IFDIR 0040000 -#define S_IFCHR 0020000 -#define S_IFIFO 0010000 -#define S_ISUID 0004000 -#define S_ISGID 0002000 -#define S_ISVTX 0001000 - -#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) -#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) -#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) -#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) -#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) -#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) - -#define S_IRWXU 00700 -#define S_IRUSR 00400 -#define S_IWUSR 00200 -#define S_IXUSR 00100 - -#define S_IRWXG 00070 -#define S_IRGRP 00040 -#define S_IWGRP 00020 -#define S_IXGRP 00010 - -#define S_IRWXO 00007 -#define S_IROTH 00004 -#define S_IWOTH 00002 -#define S_IXOTH 00001 - -#endif - - -#endif /* _UAPI_LINUX_STAT_H */ diff --git a/src/linux/include/uapi/linux/stddef.h b/src/linux/include/uapi/linux/stddef.h deleted file mode 100644 index 621fa8a..0000000 --- a/src/linux/include/uapi/linux/stddef.h +++ /dev/null @@ -1,5 +0,0 @@ -#include - -#ifndef __always_inline -#define __always_inline inline -#endif diff --git a/src/linux/include/uapi/linux/string.h b/src/linux/include/uapi/linux/string.h deleted file mode 100644 index e32e545..0000000 --- a/src/linux/include/uapi/linux/string.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _UAPI_LINUX_STRING_H_ -#define _UAPI_LINUX_STRING_H_ - -/* We don't want strings.h stuff being used by user stuff by accident */ - -#ifndef __KERNEL__ -#include -#endif /* __KERNEL__ */ -#endif /* _UAPI_LINUX_STRING_H_ */ diff --git a/src/linux/include/uapi/linux/sunrpc/debug.h b/src/linux/include/uapi/linux/sunrpc/debug.h deleted file mode 100644 index 830e344..0000000 --- a/src/linux/include/uapi/linux/sunrpc/debug.h +++ /dev/null @@ -1,48 +0,0 @@ -/* - * linux/include/linux/sunrpc/debug.h - * - * Debugging support for sunrpc module - * - * Copyright (C) 1996, Olaf Kirch - */ - -#ifndef _UAPI_LINUX_SUNRPC_DEBUG_H_ -#define _UAPI_LINUX_SUNRPC_DEBUG_H_ - -/* - * RPC debug facilities - */ -#define RPCDBG_XPRT 0x0001 -#define RPCDBG_CALL 0x0002 -#define RPCDBG_DEBUG 0x0004 -#define RPCDBG_NFS 0x0008 -#define RPCDBG_AUTH 0x0010 -#define RPCDBG_BIND 0x0020 -#define RPCDBG_SCHED 0x0040 -#define RPCDBG_TRANS 0x0080 -#define RPCDBG_SVCXPRT 0x0100 -#define RPCDBG_SVCDSP 0x0200 -#define RPCDBG_MISC 0x0400 -#define RPCDBG_CACHE 0x0800 -#define RPCDBG_ALL 0x7fff - - -/* - * Declarations for the sysctl debug interface, which allows to read or - * change the debug flags for rpc, nfs, nfsd, and lockd. Since the sunrpc - * module currently registers its sysctl table dynamically, the sysctl path - * for module FOO is . - */ - -enum { - CTL_RPCDEBUG = 1, - CTL_NFSDEBUG, - CTL_NFSDDEBUG, - CTL_NLMDEBUG, - CTL_SLOTTABLE_UDP, - CTL_SLOTTABLE_TCP, - CTL_MIN_RESVPORT, - CTL_MAX_RESVPORT, -}; - -#endif /* _UAPI_LINUX_SUNRPC_DEBUG_H_ */ diff --git a/src/linux/include/uapi/linux/swab.h b/src/linux/include/uapi/linux/swab.h deleted file mode 100644 index 8f3a8f6..0000000 --- a/src/linux/include/uapi/linux/swab.h +++ /dev/null @@ -1,294 +0,0 @@ -#ifndef _UAPI_LINUX_SWAB_H -#define _UAPI_LINUX_SWAB_H - -#include -#include -#include - -/* - * casts are necessary for constants, because we never know how for sure - * how U/UL/ULL map to __u16, __u32, __u64. At least not in a portable way. - */ -#define ___constant_swab16(x) ((__u16)( \ - (((__u16)(x) & (__u16)0x00ffU) << 8) | \ - (((__u16)(x) & (__u16)0xff00U) >> 8))) - -#define ___constant_swab32(x) ((__u32)( \ - (((__u32)(x) & (__u32)0x000000ffUL) << 24) | \ - (((__u32)(x) & (__u32)0x0000ff00UL) << 8) | \ - (((__u32)(x) & (__u32)0x00ff0000UL) >> 8) | \ - (((__u32)(x) & (__u32)0xff000000UL) >> 24))) - -#define ___constant_swab64(x) ((__u64)( \ - (((__u64)(x) & (__u64)0x00000000000000ffULL) << 56) | \ - (((__u64)(x) & (__u64)0x000000000000ff00ULL) << 40) | \ - (((__u64)(x) & (__u64)0x0000000000ff0000ULL) << 24) | \ - (((__u64)(x) & (__u64)0x00000000ff000000ULL) << 8) | \ - (((__u64)(x) & (__u64)0x000000ff00000000ULL) >> 8) | \ - (((__u64)(x) & (__u64)0x0000ff0000000000ULL) >> 24) | \ - (((__u64)(x) & (__u64)0x00ff000000000000ULL) >> 40) | \ - (((__u64)(x) & (__u64)0xff00000000000000ULL) >> 56))) - -#define ___constant_swahw32(x) ((__u32)( \ - (((__u32)(x) & (__u32)0x0000ffffUL) << 16) | \ - (((__u32)(x) & (__u32)0xffff0000UL) >> 16))) - -#define ___constant_swahb32(x) ((__u32)( \ - (((__u32)(x) & (__u32)0x00ff00ffUL) << 8) | \ - (((__u32)(x) & (__u32)0xff00ff00UL) >> 8))) - -/* - * Implement the following as inlines, but define the interface using - * macros to allow constant folding when possible: - * ___swab16, ___swab32, ___swab64, ___swahw32, ___swahb32 - */ - -static inline __attribute_const__ __u16 __fswab16(__u16 val) -{ -#if defined (__arch_swab16) - return __arch_swab16(val); -#else - return ___constant_swab16(val); -#endif -} - -static inline __attribute_const__ __u32 __fswab32(__u32 val) -{ -#if defined(__arch_swab32) - return __arch_swab32(val); -#else - return ___constant_swab32(val); -#endif -} - -static inline __attribute_const__ __u64 __fswab64(__u64 val) -{ -#if defined (__arch_swab64) - return __arch_swab64(val); -#elif defined(__SWAB_64_THRU_32__) - __u32 h = val >> 32; - __u32 l = val & ((1ULL << 32) - 1); - return (((__u64)__fswab32(l)) << 32) | ((__u64)(__fswab32(h))); -#else - return ___constant_swab64(val); -#endif -} - -static inline __attribute_const__ __u32 __fswahw32(__u32 val) -{ -#ifdef __arch_swahw32 - return __arch_swahw32(val); -#else - return ___constant_swahw32(val); -#endif -} - -static inline __attribute_const__ __u32 __fswahb32(__u32 val) -{ -#ifdef __arch_swahb32 - return __arch_swahb32(val); -#else - return ___constant_swahb32(val); -#endif -} - -/** - * __swab16 - return a byteswapped 16-bit value - * @x: value to byteswap - */ -#ifdef __HAVE_BUILTIN_BSWAP16__ -#define __swab16(x) (__u16)__builtin_bswap16((__u16)(x)) -#else -#define __swab16(x) \ - (__builtin_constant_p((__u16)(x)) ? \ - ___constant_swab16(x) : \ - __fswab16(x)) -#endif - -/** - * __swab32 - return a byteswapped 32-bit value - * @x: value to byteswap - */ -#ifdef __HAVE_BUILTIN_BSWAP32__ -#define __swab32(x) (__u32)__builtin_bswap32((__u32)(x)) -#else -#define __swab32(x) \ - (__builtin_constant_p((__u32)(x)) ? \ - ___constant_swab32(x) : \ - __fswab32(x)) -#endif - -/** - * __swab64 - return a byteswapped 64-bit value - * @x: value to byteswap - */ -#ifdef __HAVE_BUILTIN_BSWAP64__ -#define __swab64(x) (__u64)__builtin_bswap64((__u64)(x)) -#else -#define __swab64(x) \ - (__builtin_constant_p((__u64)(x)) ? \ - ___constant_swab64(x) : \ - __fswab64(x)) -#endif - -/** - * __swahw32 - return a word-swapped 32-bit value - * @x: value to wordswap - * - * __swahw32(0x12340000) is 0x00001234 - */ -#define __swahw32(x) \ - (__builtin_constant_p((__u32)(x)) ? \ - ___constant_swahw32(x) : \ - __fswahw32(x)) - -/** - * __swahb32 - return a high and low byte-swapped 32-bit value - * @x: value to byteswap - * - * __swahb32(0x12345678) is 0x34127856 - */ -#define __swahb32(x) \ - (__builtin_constant_p((__u32)(x)) ? \ - ___constant_swahb32(x) : \ - __fswahb32(x)) - -/** - * __swab16p - return a byteswapped 16-bit value from a pointer - * @p: pointer to a naturally-aligned 16-bit value - */ -static __always_inline __u16 __swab16p(const __u16 *p) -{ -#ifdef __arch_swab16p - return __arch_swab16p(p); -#else - return __swab16(*p); -#endif -} - -/** - * __swab32p - return a byteswapped 32-bit value from a pointer - * @p: pointer to a naturally-aligned 32-bit value - */ -static __always_inline __u32 __swab32p(const __u32 *p) -{ -#ifdef __arch_swab32p - return __arch_swab32p(p); -#else - return __swab32(*p); -#endif -} - -/** - * __swab64p - return a byteswapped 64-bit value from a pointer - * @p: pointer to a naturally-aligned 64-bit value - */ -static __always_inline __u64 __swab64p(const __u64 *p) -{ -#ifdef __arch_swab64p - return __arch_swab64p(p); -#else - return __swab64(*p); -#endif -} - -/** - * __swahw32p - return a wordswapped 32-bit value from a pointer - * @p: pointer to a naturally-aligned 32-bit value - * - * See __swahw32() for details of wordswapping. - */ -static inline __u32 __swahw32p(const __u32 *p) -{ -#ifdef __arch_swahw32p - return __arch_swahw32p(p); -#else - return __swahw32(*p); -#endif -} - -/** - * __swahb32p - return a high and low byteswapped 32-bit value from a pointer - * @p: pointer to a naturally-aligned 32-bit value - * - * See __swahb32() for details of high/low byteswapping. - */ -static inline __u32 __swahb32p(const __u32 *p) -{ -#ifdef __arch_swahb32p - return __arch_swahb32p(p); -#else - return __swahb32(*p); -#endif -} - -/** - * __swab16s - byteswap a 16-bit value in-place - * @p: pointer to a naturally-aligned 16-bit value - */ -static inline void __swab16s(__u16 *p) -{ -#ifdef __arch_swab16s - __arch_swab16s(p); -#else - *p = __swab16p(p); -#endif -} -/** - * __swab32s - byteswap a 32-bit value in-place - * @p: pointer to a naturally-aligned 32-bit value - */ -static __always_inline void __swab32s(__u32 *p) -{ -#ifdef __arch_swab32s - __arch_swab32s(p); -#else - *p = __swab32p(p); -#endif -} - -/** - * __swab64s - byteswap a 64-bit value in-place - * @p: pointer to a naturally-aligned 64-bit value - */ -static __always_inline void __swab64s(__u64 *p) -{ -#ifdef __arch_swab64s - __arch_swab64s(p); -#else - *p = __swab64p(p); -#endif -} - -/** - * __swahw32s - wordswap a 32-bit value in-place - * @p: pointer to a naturally-aligned 32-bit value - * - * See __swahw32() for details of wordswapping - */ -static inline void __swahw32s(__u32 *p) -{ -#ifdef __arch_swahw32s - __arch_swahw32s(p); -#else - *p = __swahw32p(p); -#endif -} - -/** - * __swahb32s - high and low byteswap a 32-bit value in-place - * @p: pointer to a naturally-aligned 32-bit value - * - * See __swahb32() for details of high and low byte swapping - */ -static inline void __swahb32s(__u32 *p) -{ -#ifdef __arch_swahb32s - __arch_swahb32s(p); -#else - *p = __swahb32p(p); -#endif -} - - -#endif /* _UAPI_LINUX_SWAB_H */ diff --git a/src/linux/include/uapi/linux/sysctl.h b/src/linux/include/uapi/linux/sysctl.h deleted file mode 100644 index d2b1215..0000000 --- a/src/linux/include/uapi/linux/sysctl.h +++ /dev/null @@ -1,932 +0,0 @@ -/* - * sysctl.h: General linux system control interface - * - * Begun 24 March 1995, Stephen Tweedie - * - **************************************************************** - **************************************************************** - ** - ** WARNING: - ** The values in this file are exported to user space via - ** the sysctl() binary interface. Do *NOT* change the - ** numbering of any existing values here, and do not change - ** any numbers within any one set of values. If you have to - ** redefine an existing interface, use a new number for it. - ** The kernel will then return -ENOTDIR to any application using - ** the old binary interface. - ** - **************************************************************** - **************************************************************** - */ - -#ifndef _UAPI_LINUX_SYSCTL_H -#define _UAPI_LINUX_SYSCTL_H - -#include -#include -#include - -#define CTL_MAXNAME 10 /* how many path components do we allow in a - call to sysctl? In other words, what is - the largest acceptable value for the nlen - member of a struct __sysctl_args to have? */ - -struct __sysctl_args { - int __user *name; - int nlen; - void __user *oldval; - size_t __user *oldlenp; - void __user *newval; - size_t newlen; - unsigned long __unused[4]; -}; - -/* Define sysctl names first */ - -/* Top-level names: */ - -enum -{ - CTL_KERN=1, /* General kernel info and control */ - CTL_VM=2, /* VM management */ - CTL_NET=3, /* Networking */ - CTL_PROC=4, /* removal breaks strace(1) compilation */ - CTL_FS=5, /* Filesystems */ - CTL_DEBUG=6, /* Debugging */ - CTL_DEV=7, /* Devices */ - CTL_BUS=8, /* Busses */ - CTL_ABI=9, /* Binary emulation */ - CTL_CPU=10, /* CPU stuff (speed scaling, etc) */ - CTL_ARLAN=254, /* arlan wireless driver */ - CTL_S390DBF=5677, /* s390 debug */ - CTL_SUNRPC=7249, /* sunrpc debug */ - CTL_PM=9899, /* frv power management */ - CTL_FRV=9898, /* frv specific sysctls */ -}; - -/* CTL_BUS names: */ -enum -{ - CTL_BUS_ISA=1 /* ISA */ -}; - -/* /proc/sys/fs/inotify/ */ -enum -{ - INOTIFY_MAX_USER_INSTANCES=1, /* max instances per user */ - INOTIFY_MAX_USER_WATCHES=2, /* max watches per user */ - INOTIFY_MAX_QUEUED_EVENTS=3 /* max queued events per instance */ -}; - -/* CTL_KERN names: */ -enum -{ - KERN_OSTYPE=1, /* string: system version */ - KERN_OSRELEASE=2, /* string: system release */ - KERN_OSREV=3, /* int: system revision */ - KERN_VERSION=4, /* string: compile time info */ - KERN_SECUREMASK=5, /* struct: maximum rights mask */ - KERN_PROF=6, /* table: profiling information */ - KERN_NODENAME=7, /* string: hostname */ - KERN_DOMAINNAME=8, /* string: domainname */ - - KERN_PANIC=15, /* int: panic timeout */ - KERN_REALROOTDEV=16, /* real root device to mount after initrd */ - - KERN_SPARC_REBOOT=21, /* reboot command on Sparc */ - KERN_CTLALTDEL=22, /* int: allow ctl-alt-del to reboot */ - KERN_PRINTK=23, /* struct: control printk logging parameters */ - KERN_NAMETRANS=24, /* Name translation */ - KERN_PPC_HTABRECLAIM=25, /* turn htab reclaimation on/off on PPC */ - KERN_PPC_ZEROPAGED=26, /* turn idle page zeroing on/off on PPC */ - KERN_PPC_POWERSAVE_NAP=27, /* use nap mode for power saving */ - KERN_MODPROBE=28, /* string: modprobe path */ - KERN_SG_BIG_BUFF=29, /* int: sg driver reserved buffer size */ - KERN_ACCT=30, /* BSD process accounting parameters */ - KERN_PPC_L2CR=31, /* l2cr register on PPC */ - - KERN_RTSIGNR=32, /* Number of rt sigs queued */ - KERN_RTSIGMAX=33, /* Max queuable */ - - KERN_SHMMAX=34, /* long: Maximum shared memory segment */ - KERN_MSGMAX=35, /* int: Maximum size of a messege */ - KERN_MSGMNB=36, /* int: Maximum message queue size */ - KERN_MSGPOOL=37, /* int: Maximum system message pool size */ - KERN_SYSRQ=38, /* int: Sysreq enable */ - KERN_MAX_THREADS=39, /* int: Maximum nr of threads in the system */ - KERN_RANDOM=40, /* Random driver */ - KERN_SHMALL=41, /* int: Maximum size of shared memory */ - KERN_MSGMNI=42, /* int: msg queue identifiers */ - KERN_SEM=43, /* struct: sysv semaphore limits */ - KERN_SPARC_STOP_A=44, /* int: Sparc Stop-A enable */ - KERN_SHMMNI=45, /* int: shm array identifiers */ - KERN_OVERFLOWUID=46, /* int: overflow UID */ - KERN_OVERFLOWGID=47, /* int: overflow GID */ - KERN_SHMPATH=48, /* string: path to shm fs */ - KERN_HOTPLUG=49, /* string: path to uevent helper (deprecated) */ - KERN_IEEE_EMULATION_WARNINGS=50, /* int: unimplemented ieee instructions */ - KERN_S390_USER_DEBUG_LOGGING=51, /* int: dumps of user faults */ - KERN_CORE_USES_PID=52, /* int: use core or core.%pid */ - KERN_TAINTED=53, /* int: various kernel tainted flags */ - KERN_CADPID=54, /* int: PID of the process to notify on CAD */ - KERN_PIDMAX=55, /* int: PID # limit */ - KERN_CORE_PATTERN=56, /* string: pattern for core-file names */ - KERN_PANIC_ON_OOPS=57, /* int: whether we will panic on an oops */ - KERN_HPPA_PWRSW=58, /* int: hppa soft-power enable */ - KERN_HPPA_UNALIGNED=59, /* int: hppa unaligned-trap enable */ - KERN_PRINTK_RATELIMIT=60, /* int: tune printk ratelimiting */ - KERN_PRINTK_RATELIMIT_BURST=61, /* int: tune printk ratelimiting */ - KERN_PTY=62, /* dir: pty driver */ - KERN_NGROUPS_MAX=63, /* int: NGROUPS_MAX */ - KERN_SPARC_SCONS_PWROFF=64, /* int: serial console power-off halt */ - KERN_HZ_TIMER=65, /* int: hz timer on or off */ - KERN_UNKNOWN_NMI_PANIC=66, /* int: unknown nmi panic flag */ - KERN_BOOTLOADER_TYPE=67, /* int: boot loader type */ - KERN_RANDOMIZE=68, /* int: randomize virtual address space */ - KERN_SETUID_DUMPABLE=69, /* int: behaviour of dumps for setuid core */ - KERN_SPIN_RETRY=70, /* int: number of spinlock retries */ - KERN_ACPI_VIDEO_FLAGS=71, /* int: flags for setting up video after ACPI sleep */ - KERN_IA64_UNALIGNED=72, /* int: ia64 unaligned userland trap enable */ - KERN_COMPAT_LOG=73, /* int: print compat layer messages */ - KERN_MAX_LOCK_DEPTH=74, /* int: rtmutex's maximum lock depth */ - KERN_NMI_WATCHDOG=75, /* int: enable/disable nmi watchdog */ - KERN_PANIC_ON_NMI=76, /* int: whether we will panic on an unrecovered */ - KERN_PANIC_ON_WARN=77, /* int: call panic() in WARN() functions */ -}; - - - -/* CTL_VM names: */ -enum -{ - VM_UNUSED1=1, /* was: struct: Set vm swapping control */ - VM_UNUSED2=2, /* was; int: Linear or sqrt() swapout for hogs */ - VM_UNUSED3=3, /* was: struct: Set free page thresholds */ - VM_UNUSED4=4, /* Spare */ - VM_OVERCOMMIT_MEMORY=5, /* Turn off the virtual memory safety limit */ - VM_UNUSED5=6, /* was: struct: Set buffer memory thresholds */ - VM_UNUSED7=7, /* was: struct: Set cache memory thresholds */ - VM_UNUSED8=8, /* was: struct: Control kswapd behaviour */ - VM_UNUSED9=9, /* was: struct: Set page table cache parameters */ - VM_PAGE_CLUSTER=10, /* int: set number of pages to swap together */ - VM_DIRTY_BACKGROUND=11, /* dirty_background_ratio */ - VM_DIRTY_RATIO=12, /* dirty_ratio */ - VM_DIRTY_WB_CS=13, /* dirty_writeback_centisecs */ - VM_DIRTY_EXPIRE_CS=14, /* dirty_expire_centisecs */ - VM_NR_PDFLUSH_THREADS=15, /* nr_pdflush_threads */ - VM_OVERCOMMIT_RATIO=16, /* percent of RAM to allow overcommit in */ - VM_PAGEBUF=17, /* struct: Control pagebuf parameters */ - VM_HUGETLB_PAGES=18, /* int: Number of available Huge Pages */ - VM_SWAPPINESS=19, /* Tendency to steal mapped memory */ - VM_LOWMEM_RESERVE_RATIO=20,/* reservation ratio for lower memory zones */ - VM_MIN_FREE_KBYTES=21, /* Minimum free kilobytes to maintain */ - VM_MAX_MAP_COUNT=22, /* int: Maximum number of mmaps/address-space */ - VM_LAPTOP_MODE=23, /* vm laptop mode */ - VM_BLOCK_DUMP=24, /* block dump mode */ - VM_HUGETLB_GROUP=25, /* permitted hugetlb group */ - VM_VFS_CACHE_PRESSURE=26, /* dcache/icache reclaim pressure */ - VM_LEGACY_VA_LAYOUT=27, /* legacy/compatibility virtual address space layout */ - VM_SWAP_TOKEN_TIMEOUT=28, /* default time for token time out */ - VM_DROP_PAGECACHE=29, /* int: nuke lots of pagecache */ - VM_PERCPU_PAGELIST_FRACTION=30,/* int: fraction of pages in each percpu_pagelist */ - VM_ZONE_RECLAIM_MODE=31, /* reclaim local zone memory before going off node */ - VM_MIN_UNMAPPED=32, /* Set min percent of unmapped pages */ - VM_PANIC_ON_OOM=33, /* panic at out-of-memory */ - VM_VDSO_ENABLED=34, /* map VDSO into new processes? */ - VM_MIN_SLAB=35, /* Percent pages ignored by zone reclaim */ -}; - - -/* CTL_NET names: */ -enum -{ - NET_CORE=1, - NET_ETHER=2, - NET_802=3, - NET_UNIX=4, - NET_IPV4=5, - NET_IPX=6, - NET_ATALK=7, - NET_NETROM=8, - NET_AX25=9, - NET_BRIDGE=10, - NET_ROSE=11, - NET_IPV6=12, - NET_X25=13, - NET_TR=14, - NET_DECNET=15, - NET_ECONET=16, - NET_SCTP=17, - NET_LLC=18, - NET_NETFILTER=19, - NET_DCCP=20, - NET_IRDA=412, -}; - -/* /proc/sys/kernel/random */ -enum -{ - RANDOM_POOLSIZE=1, - RANDOM_ENTROPY_COUNT=2, - RANDOM_READ_THRESH=3, - RANDOM_WRITE_THRESH=4, - RANDOM_BOOT_ID=5, - RANDOM_UUID=6 -}; - -/* /proc/sys/kernel/pty */ -enum -{ - PTY_MAX=1, - PTY_NR=2 -}; - -/* /proc/sys/bus/isa */ -enum -{ - BUS_ISA_MEM_BASE=1, - BUS_ISA_PORT_BASE=2, - BUS_ISA_PORT_SHIFT=3 -}; - -/* /proc/sys/net/core */ -enum -{ - NET_CORE_WMEM_MAX=1, - NET_CORE_RMEM_MAX=2, - NET_CORE_WMEM_DEFAULT=3, - NET_CORE_RMEM_DEFAULT=4, -/* was NET_CORE_DESTROY_DELAY */ - NET_CORE_MAX_BACKLOG=6, - NET_CORE_FASTROUTE=7, - NET_CORE_MSG_COST=8, - NET_CORE_MSG_BURST=9, - NET_CORE_OPTMEM_MAX=10, - NET_CORE_HOT_LIST_LENGTH=11, - NET_CORE_DIVERT_VERSION=12, - NET_CORE_NO_CONG_THRESH=13, - NET_CORE_NO_CONG=14, - NET_CORE_LO_CONG=15, - NET_CORE_MOD_CONG=16, - NET_CORE_DEV_WEIGHT=17, - NET_CORE_SOMAXCONN=18, - NET_CORE_BUDGET=19, - NET_CORE_AEVENT_ETIME=20, - NET_CORE_AEVENT_RSEQTH=21, - NET_CORE_WARNINGS=22, -}; - -/* /proc/sys/net/ethernet */ - -/* /proc/sys/net/802 */ - -/* /proc/sys/net/unix */ - -enum -{ - NET_UNIX_DESTROY_DELAY=1, - NET_UNIX_DELETE_DELAY=2, - NET_UNIX_MAX_DGRAM_QLEN=3, -}; - -/* /proc/sys/net/netfilter */ -enum -{ - NET_NF_CONNTRACK_MAX=1, - NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT=2, - NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV=3, - NET_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED=4, - NET_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT=5, - NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT=6, - NET_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK=7, - NET_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT=8, - NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE=9, - NET_NF_CONNTRACK_UDP_TIMEOUT=10, - NET_NF_CONNTRACK_UDP_TIMEOUT_STREAM=11, - NET_NF_CONNTRACK_ICMP_TIMEOUT=12, - NET_NF_CONNTRACK_GENERIC_TIMEOUT=13, - NET_NF_CONNTRACK_BUCKETS=14, - NET_NF_CONNTRACK_LOG_INVALID=15, - NET_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS=16, - NET_NF_CONNTRACK_TCP_LOOSE=17, - NET_NF_CONNTRACK_TCP_BE_LIBERAL=18, - NET_NF_CONNTRACK_TCP_MAX_RETRANS=19, - NET_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED=20, - NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT=21, - NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED=22, - NET_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED=23, - NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT=24, - NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD=25, - NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT=26, - NET_NF_CONNTRACK_COUNT=27, - NET_NF_CONNTRACK_ICMPV6_TIMEOUT=28, - NET_NF_CONNTRACK_FRAG6_TIMEOUT=29, - NET_NF_CONNTRACK_FRAG6_LOW_THRESH=30, - NET_NF_CONNTRACK_FRAG6_HIGH_THRESH=31, - NET_NF_CONNTRACK_CHECKSUM=32, -}; - -/* /proc/sys/net/ipv4 */ -enum -{ - /* v2.0 compatibile variables */ - NET_IPV4_FORWARD=8, - NET_IPV4_DYNADDR=9, - - NET_IPV4_CONF=16, - NET_IPV4_NEIGH=17, - NET_IPV4_ROUTE=18, - NET_IPV4_FIB_HASH=19, - NET_IPV4_NETFILTER=20, - - NET_IPV4_TCP_TIMESTAMPS=33, - NET_IPV4_TCP_WINDOW_SCALING=34, - NET_IPV4_TCP_SACK=35, - NET_IPV4_TCP_RETRANS_COLLAPSE=36, - NET_IPV4_DEFAULT_TTL=37, - NET_IPV4_AUTOCONFIG=38, - NET_IPV4_NO_PMTU_DISC=39, - NET_IPV4_TCP_SYN_RETRIES=40, - NET_IPV4_IPFRAG_HIGH_THRESH=41, - NET_IPV4_IPFRAG_LOW_THRESH=42, - NET_IPV4_IPFRAG_TIME=43, - NET_IPV4_TCP_MAX_KA_PROBES=44, - NET_IPV4_TCP_KEEPALIVE_TIME=45, - NET_IPV4_TCP_KEEPALIVE_PROBES=46, - NET_IPV4_TCP_RETRIES1=47, - NET_IPV4_TCP_RETRIES2=48, - NET_IPV4_TCP_FIN_TIMEOUT=49, - NET_IPV4_IP_MASQ_DEBUG=50, - NET_TCP_SYNCOOKIES=51, - NET_TCP_STDURG=52, - NET_TCP_RFC1337=53, - NET_TCP_SYN_TAILDROP=54, - NET_TCP_MAX_SYN_BACKLOG=55, - NET_IPV4_LOCAL_PORT_RANGE=56, - NET_IPV4_ICMP_ECHO_IGNORE_ALL=57, - NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS=58, - NET_IPV4_ICMP_SOURCEQUENCH_RATE=59, - NET_IPV4_ICMP_DESTUNREACH_RATE=60, - NET_IPV4_ICMP_TIMEEXCEED_RATE=61, - NET_IPV4_ICMP_PARAMPROB_RATE=62, - NET_IPV4_ICMP_ECHOREPLY_RATE=63, - NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES=64, - NET_IPV4_IGMP_MAX_MEMBERSHIPS=65, - NET_TCP_TW_RECYCLE=66, - NET_IPV4_ALWAYS_DEFRAG=67, - NET_IPV4_TCP_KEEPALIVE_INTVL=68, - NET_IPV4_INET_PEER_THRESHOLD=69, - NET_IPV4_INET_PEER_MINTTL=70, - NET_IPV4_INET_PEER_MAXTTL=71, - NET_IPV4_INET_PEER_GC_MINTIME=72, - NET_IPV4_INET_PEER_GC_MAXTIME=73, - NET_TCP_ORPHAN_RETRIES=74, - NET_TCP_ABORT_ON_OVERFLOW=75, - NET_TCP_SYNACK_RETRIES=76, - NET_TCP_MAX_ORPHANS=77, - NET_TCP_MAX_TW_BUCKETS=78, - NET_TCP_FACK=79, - NET_TCP_REORDERING=80, - NET_TCP_ECN=81, - NET_TCP_DSACK=82, - NET_TCP_MEM=83, - NET_TCP_WMEM=84, - NET_TCP_RMEM=85, - NET_TCP_APP_WIN=86, - NET_TCP_ADV_WIN_SCALE=87, - NET_IPV4_NONLOCAL_BIND=88, - NET_IPV4_ICMP_RATELIMIT=89, - NET_IPV4_ICMP_RATEMASK=90, - NET_TCP_TW_REUSE=91, - NET_TCP_FRTO=92, - NET_TCP_LOW_LATENCY=93, - NET_IPV4_IPFRAG_SECRET_INTERVAL=94, - NET_IPV4_IGMP_MAX_MSF=96, - NET_TCP_NO_METRICS_SAVE=97, - NET_TCP_DEFAULT_WIN_SCALE=105, - NET_TCP_MODERATE_RCVBUF=106, - NET_TCP_TSO_WIN_DIVISOR=107, - NET_TCP_BIC_BETA=108, - NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR=109, - NET_TCP_CONG_CONTROL=110, - NET_TCP_ABC=111, - NET_IPV4_IPFRAG_MAX_DIST=112, - NET_TCP_MTU_PROBING=113, - NET_TCP_BASE_MSS=114, - NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS=115, - NET_TCP_DMA_COPYBREAK=116, - NET_TCP_SLOW_START_AFTER_IDLE=117, - NET_CIPSOV4_CACHE_ENABLE=118, - NET_CIPSOV4_CACHE_BUCKET_SIZE=119, - NET_CIPSOV4_RBM_OPTFMT=120, - NET_CIPSOV4_RBM_STRICTVALID=121, - NET_TCP_AVAIL_CONG_CONTROL=122, - NET_TCP_ALLOWED_CONG_CONTROL=123, - NET_TCP_MAX_SSTHRESH=124, - NET_TCP_FRTO_RESPONSE=125, -}; - -enum { - NET_IPV4_ROUTE_FLUSH=1, - NET_IPV4_ROUTE_MIN_DELAY=2, /* obsolete since 2.6.25 */ - NET_IPV4_ROUTE_MAX_DELAY=3, /* obsolete since 2.6.25 */ - NET_IPV4_ROUTE_GC_THRESH=4, - NET_IPV4_ROUTE_MAX_SIZE=5, - NET_IPV4_ROUTE_GC_MIN_INTERVAL=6, - NET_IPV4_ROUTE_GC_TIMEOUT=7, - NET_IPV4_ROUTE_GC_INTERVAL=8, /* obsolete since 2.6.38 */ - NET_IPV4_ROUTE_REDIRECT_LOAD=9, - NET_IPV4_ROUTE_REDIRECT_NUMBER=10, - NET_IPV4_ROUTE_REDIRECT_SILENCE=11, - NET_IPV4_ROUTE_ERROR_COST=12, - NET_IPV4_ROUTE_ERROR_BURST=13, - NET_IPV4_ROUTE_GC_ELASTICITY=14, - NET_IPV4_ROUTE_MTU_EXPIRES=15, - NET_IPV4_ROUTE_MIN_PMTU=16, - NET_IPV4_ROUTE_MIN_ADVMSS=17, - NET_IPV4_ROUTE_SECRET_INTERVAL=18, - NET_IPV4_ROUTE_GC_MIN_INTERVAL_MS=19, -}; - -enum -{ - NET_PROTO_CONF_ALL=-2, - NET_PROTO_CONF_DEFAULT=-3 - - /* And device ifindices ... */ -}; - -enum -{ - NET_IPV4_CONF_FORWARDING=1, - NET_IPV4_CONF_MC_FORWARDING=2, - NET_IPV4_CONF_PROXY_ARP=3, - NET_IPV4_CONF_ACCEPT_REDIRECTS=4, - NET_IPV4_CONF_SECURE_REDIRECTS=5, - NET_IPV4_CONF_SEND_REDIRECTS=6, - NET_IPV4_CONF_SHARED_MEDIA=7, - NET_IPV4_CONF_RP_FILTER=8, - NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE=9, - NET_IPV4_CONF_BOOTP_RELAY=10, - NET_IPV4_CONF_LOG_MARTIANS=11, - NET_IPV4_CONF_TAG=12, - NET_IPV4_CONF_ARPFILTER=13, - NET_IPV4_CONF_MEDIUM_ID=14, - NET_IPV4_CONF_NOXFRM=15, - NET_IPV4_CONF_NOPOLICY=16, - NET_IPV4_CONF_FORCE_IGMP_VERSION=17, - NET_IPV4_CONF_ARP_ANNOUNCE=18, - NET_IPV4_CONF_ARP_IGNORE=19, - NET_IPV4_CONF_PROMOTE_SECONDARIES=20, - NET_IPV4_CONF_ARP_ACCEPT=21, - NET_IPV4_CONF_ARP_NOTIFY=22, -}; - -/* /proc/sys/net/ipv4/netfilter */ -enum -{ - NET_IPV4_NF_CONNTRACK_MAX=1, - NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT=2, - NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV=3, - NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED=4, - NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT=5, - NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT=6, - NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK=7, - NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT=8, - NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE=9, - NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT=10, - NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM=11, - NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT=12, - NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT=13, - NET_IPV4_NF_CONNTRACK_BUCKETS=14, - NET_IPV4_NF_CONNTRACK_LOG_INVALID=15, - NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS=16, - NET_IPV4_NF_CONNTRACK_TCP_LOOSE=17, - NET_IPV4_NF_CONNTRACK_TCP_BE_LIBERAL=18, - NET_IPV4_NF_CONNTRACK_TCP_MAX_RETRANS=19, - NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED=20, - NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT=21, - NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED=22, - NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED=23, - NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT=24, - NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD=25, - NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT=26, - NET_IPV4_NF_CONNTRACK_COUNT=27, - NET_IPV4_NF_CONNTRACK_CHECKSUM=28, -}; - -/* /proc/sys/net/ipv6 */ -enum { - NET_IPV6_CONF=16, - NET_IPV6_NEIGH=17, - NET_IPV6_ROUTE=18, - NET_IPV6_ICMP=19, - NET_IPV6_BINDV6ONLY=20, - NET_IPV6_IP6FRAG_HIGH_THRESH=21, - NET_IPV6_IP6FRAG_LOW_THRESH=22, - NET_IPV6_IP6FRAG_TIME=23, - NET_IPV6_IP6FRAG_SECRET_INTERVAL=24, - NET_IPV6_MLD_MAX_MSF=25, -}; - -enum { - NET_IPV6_ROUTE_FLUSH=1, - NET_IPV6_ROUTE_GC_THRESH=2, - NET_IPV6_ROUTE_MAX_SIZE=3, - NET_IPV6_ROUTE_GC_MIN_INTERVAL=4, - NET_IPV6_ROUTE_GC_TIMEOUT=5, - NET_IPV6_ROUTE_GC_INTERVAL=6, - NET_IPV6_ROUTE_GC_ELASTICITY=7, - NET_IPV6_ROUTE_MTU_EXPIRES=8, - NET_IPV6_ROUTE_MIN_ADVMSS=9, - NET_IPV6_ROUTE_GC_MIN_INTERVAL_MS=10 -}; - -enum { - NET_IPV6_FORWARDING=1, - NET_IPV6_HOP_LIMIT=2, - NET_IPV6_MTU=3, - NET_IPV6_ACCEPT_RA=4, - NET_IPV6_ACCEPT_REDIRECTS=5, - NET_IPV6_AUTOCONF=6, - NET_IPV6_DAD_TRANSMITS=7, - NET_IPV6_RTR_SOLICITS=8, - NET_IPV6_RTR_SOLICIT_INTERVAL=9, - NET_IPV6_RTR_SOLICIT_DELAY=10, - NET_IPV6_USE_TEMPADDR=11, - NET_IPV6_TEMP_VALID_LFT=12, - NET_IPV6_TEMP_PREFERED_LFT=13, - NET_IPV6_REGEN_MAX_RETRY=14, - NET_IPV6_MAX_DESYNC_FACTOR=15, - NET_IPV6_MAX_ADDRESSES=16, - NET_IPV6_FORCE_MLD_VERSION=17, - NET_IPV6_ACCEPT_RA_DEFRTR=18, - NET_IPV6_ACCEPT_RA_PINFO=19, - NET_IPV6_ACCEPT_RA_RTR_PREF=20, - NET_IPV6_RTR_PROBE_INTERVAL=21, - NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN=22, - NET_IPV6_PROXY_NDP=23, - NET_IPV6_ACCEPT_SOURCE_ROUTE=25, - NET_IPV6_ACCEPT_RA_FROM_LOCAL=26, - __NET_IPV6_MAX -}; - -/* /proc/sys/net/ipv6/icmp */ -enum { - NET_IPV6_ICMP_RATELIMIT=1 -}; - -/* /proc/sys/net//neigh/ */ -enum { - NET_NEIGH_MCAST_SOLICIT=1, - NET_NEIGH_UCAST_SOLICIT=2, - NET_NEIGH_APP_SOLICIT=3, - NET_NEIGH_RETRANS_TIME=4, - NET_NEIGH_REACHABLE_TIME=5, - NET_NEIGH_DELAY_PROBE_TIME=6, - NET_NEIGH_GC_STALE_TIME=7, - NET_NEIGH_UNRES_QLEN=8, - NET_NEIGH_PROXY_QLEN=9, - NET_NEIGH_ANYCAST_DELAY=10, - NET_NEIGH_PROXY_DELAY=11, - NET_NEIGH_LOCKTIME=12, - NET_NEIGH_GC_INTERVAL=13, - NET_NEIGH_GC_THRESH1=14, - NET_NEIGH_GC_THRESH2=15, - NET_NEIGH_GC_THRESH3=16, - NET_NEIGH_RETRANS_TIME_MS=17, - NET_NEIGH_REACHABLE_TIME_MS=18, -}; - -/* /proc/sys/net/dccp */ -enum { - NET_DCCP_DEFAULT=1, -}; - -/* /proc/sys/net/ipx */ -enum { - NET_IPX_PPROP_BROADCASTING=1, - NET_IPX_FORWARDING=2 -}; - -/* /proc/sys/net/llc */ -enum { - NET_LLC2=1, - NET_LLC_STATION=2, -}; - -/* /proc/sys/net/llc/llc2 */ -enum { - NET_LLC2_TIMEOUT=1, -}; - -/* /proc/sys/net/llc/station */ -enum { - NET_LLC_STATION_ACK_TIMEOUT=1, -}; - -/* /proc/sys/net/llc/llc2/timeout */ -enum { - NET_LLC2_ACK_TIMEOUT=1, - NET_LLC2_P_TIMEOUT=2, - NET_LLC2_REJ_TIMEOUT=3, - NET_LLC2_BUSY_TIMEOUT=4, -}; - -/* /proc/sys/net/appletalk */ -enum { - NET_ATALK_AARP_EXPIRY_TIME=1, - NET_ATALK_AARP_TICK_TIME=2, - NET_ATALK_AARP_RETRANSMIT_LIMIT=3, - NET_ATALK_AARP_RESOLVE_TIME=4 -}; - - -/* /proc/sys/net/netrom */ -enum { - NET_NETROM_DEFAULT_PATH_QUALITY=1, - NET_NETROM_OBSOLESCENCE_COUNT_INITIALISER=2, - NET_NETROM_NETWORK_TTL_INITIALISER=3, - NET_NETROM_TRANSPORT_TIMEOUT=4, - NET_NETROM_TRANSPORT_MAXIMUM_TRIES=5, - NET_NETROM_TRANSPORT_ACKNOWLEDGE_DELAY=6, - NET_NETROM_TRANSPORT_BUSY_DELAY=7, - NET_NETROM_TRANSPORT_REQUESTED_WINDOW_SIZE=8, - NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT=9, - NET_NETROM_ROUTING_CONTROL=10, - NET_NETROM_LINK_FAILS_COUNT=11, - NET_NETROM_RESET=12 -}; - -/* /proc/sys/net/ax25 */ -enum { - NET_AX25_IP_DEFAULT_MODE=1, - NET_AX25_DEFAULT_MODE=2, - NET_AX25_BACKOFF_TYPE=3, - NET_AX25_CONNECT_MODE=4, - NET_AX25_STANDARD_WINDOW=5, - NET_AX25_EXTENDED_WINDOW=6, - NET_AX25_T1_TIMEOUT=7, - NET_AX25_T2_TIMEOUT=8, - NET_AX25_T3_TIMEOUT=9, - NET_AX25_IDLE_TIMEOUT=10, - NET_AX25_N2=11, - NET_AX25_PACLEN=12, - NET_AX25_PROTOCOL=13, - NET_AX25_DAMA_SLAVE_TIMEOUT=14 -}; - -/* /proc/sys/net/rose */ -enum { - NET_ROSE_RESTART_REQUEST_TIMEOUT=1, - NET_ROSE_CALL_REQUEST_TIMEOUT=2, - NET_ROSE_RESET_REQUEST_TIMEOUT=3, - NET_ROSE_CLEAR_REQUEST_TIMEOUT=4, - NET_ROSE_ACK_HOLD_BACK_TIMEOUT=5, - NET_ROSE_ROUTING_CONTROL=6, - NET_ROSE_LINK_FAIL_TIMEOUT=7, - NET_ROSE_MAX_VCS=8, - NET_ROSE_WINDOW_SIZE=9, - NET_ROSE_NO_ACTIVITY_TIMEOUT=10 -}; - -/* /proc/sys/net/x25 */ -enum { - NET_X25_RESTART_REQUEST_TIMEOUT=1, - NET_X25_CALL_REQUEST_TIMEOUT=2, - NET_X25_RESET_REQUEST_TIMEOUT=3, - NET_X25_CLEAR_REQUEST_TIMEOUT=4, - NET_X25_ACK_HOLD_BACK_TIMEOUT=5, - NET_X25_FORWARD=6 -}; - -/* /proc/sys/net/token-ring */ -enum -{ - NET_TR_RIF_TIMEOUT=1 -}; - -/* /proc/sys/net/decnet/ */ -enum { - NET_DECNET_NODE_TYPE = 1, - NET_DECNET_NODE_ADDRESS = 2, - NET_DECNET_NODE_NAME = 3, - NET_DECNET_DEFAULT_DEVICE = 4, - NET_DECNET_TIME_WAIT = 5, - NET_DECNET_DN_COUNT = 6, - NET_DECNET_DI_COUNT = 7, - NET_DECNET_DR_COUNT = 8, - NET_DECNET_DST_GC_INTERVAL = 9, - NET_DECNET_CONF = 10, - NET_DECNET_NO_FC_MAX_CWND = 11, - NET_DECNET_MEM = 12, - NET_DECNET_RMEM = 13, - NET_DECNET_WMEM = 14, - NET_DECNET_DEBUG_LEVEL = 255 -}; - -/* /proc/sys/net/decnet/conf/ */ -enum { - NET_DECNET_CONF_LOOPBACK = -2, - NET_DECNET_CONF_DDCMP = -3, - NET_DECNET_CONF_PPP = -4, - NET_DECNET_CONF_X25 = -5, - NET_DECNET_CONF_GRE = -6, - NET_DECNET_CONF_ETHER = -7 - - /* ... and ifindex of devices */ -}; - -/* /proc/sys/net/decnet/conf// */ -enum { - NET_DECNET_CONF_DEV_PRIORITY = 1, - NET_DECNET_CONF_DEV_T1 = 2, - NET_DECNET_CONF_DEV_T2 = 3, - NET_DECNET_CONF_DEV_T3 = 4, - NET_DECNET_CONF_DEV_FORWARDING = 5, - NET_DECNET_CONF_DEV_BLKSIZE = 6, - NET_DECNET_CONF_DEV_STATE = 7 -}; - -/* /proc/sys/net/sctp */ -enum { - NET_SCTP_RTO_INITIAL = 1, - NET_SCTP_RTO_MIN = 2, - NET_SCTP_RTO_MAX = 3, - NET_SCTP_RTO_ALPHA = 4, - NET_SCTP_RTO_BETA = 5, - NET_SCTP_VALID_COOKIE_LIFE = 6, - NET_SCTP_ASSOCIATION_MAX_RETRANS = 7, - NET_SCTP_PATH_MAX_RETRANS = 8, - NET_SCTP_MAX_INIT_RETRANSMITS = 9, - NET_SCTP_HB_INTERVAL = 10, - NET_SCTP_PRESERVE_ENABLE = 11, - NET_SCTP_MAX_BURST = 12, - NET_SCTP_ADDIP_ENABLE = 13, - NET_SCTP_PRSCTP_ENABLE = 14, - NET_SCTP_SNDBUF_POLICY = 15, - NET_SCTP_SACK_TIMEOUT = 16, - NET_SCTP_RCVBUF_POLICY = 17, -}; - -/* /proc/sys/net/bridge */ -enum { - NET_BRIDGE_NF_CALL_ARPTABLES = 1, - NET_BRIDGE_NF_CALL_IPTABLES = 2, - NET_BRIDGE_NF_CALL_IP6TABLES = 3, - NET_BRIDGE_NF_FILTER_VLAN_TAGGED = 4, - NET_BRIDGE_NF_FILTER_PPPOE_TAGGED = 5, -}; - -/* proc/sys/net/irda */ -enum { - NET_IRDA_DISCOVERY=1, - NET_IRDA_DEVNAME=2, - NET_IRDA_DEBUG=3, - NET_IRDA_FAST_POLL=4, - NET_IRDA_DISCOVERY_SLOTS=5, - NET_IRDA_DISCOVERY_TIMEOUT=6, - NET_IRDA_SLOT_TIMEOUT=7, - NET_IRDA_MAX_BAUD_RATE=8, - NET_IRDA_MIN_TX_TURN_TIME=9, - NET_IRDA_MAX_TX_DATA_SIZE=10, - NET_IRDA_MAX_TX_WINDOW=11, - NET_IRDA_MAX_NOREPLY_TIME=12, - NET_IRDA_WARN_NOREPLY_TIME=13, - NET_IRDA_LAP_KEEPALIVE_TIME=14, -}; - - -/* CTL_FS names: */ -enum -{ - FS_NRINODE=1, /* int:current number of allocated inodes */ - FS_STATINODE=2, - FS_MAXINODE=3, /* int:maximum number of inodes that can be allocated */ - FS_NRDQUOT=4, /* int:current number of allocated dquots */ - FS_MAXDQUOT=5, /* int:maximum number of dquots that can be allocated */ - FS_NRFILE=6, /* int:current number of allocated filedescriptors */ - FS_MAXFILE=7, /* int:maximum number of filedescriptors that can be allocated */ - FS_DENTRY=8, - FS_NRSUPER=9, /* int:current number of allocated super_blocks */ - FS_MAXSUPER=10, /* int:maximum number of super_blocks that can be allocated */ - FS_OVERFLOWUID=11, /* int: overflow UID */ - FS_OVERFLOWGID=12, /* int: overflow GID */ - FS_LEASES=13, /* int: leases enabled */ - FS_DIR_NOTIFY=14, /* int: directory notification enabled */ - FS_LEASE_TIME=15, /* int: maximum time to wait for a lease break */ - FS_DQSTATS=16, /* disc quota usage statistics and control */ - FS_XFS=17, /* struct: control xfs parameters */ - FS_AIO_NR=18, /* current system-wide number of aio requests */ - FS_AIO_MAX_NR=19, /* system-wide maximum number of aio requests */ - FS_INOTIFY=20, /* inotify submenu */ - FS_OCFS2=988, /* ocfs2 */ -}; - -/* /proc/sys/fs/quota/ */ -enum { - FS_DQ_LOOKUPS = 1, - FS_DQ_DROPS = 2, - FS_DQ_READS = 3, - FS_DQ_WRITES = 4, - FS_DQ_CACHE_HITS = 5, - FS_DQ_ALLOCATED = 6, - FS_DQ_FREE = 7, - FS_DQ_SYNCS = 8, - FS_DQ_WARNINGS = 9, -}; - -/* CTL_DEBUG names: */ - -/* CTL_DEV names: */ -enum { - DEV_CDROM=1, - DEV_HWMON=2, - DEV_PARPORT=3, - DEV_RAID=4, - DEV_MAC_HID=5, - DEV_SCSI=6, - DEV_IPMI=7, -}; - -/* /proc/sys/dev/cdrom */ -enum { - DEV_CDROM_INFO=1, - DEV_CDROM_AUTOCLOSE=2, - DEV_CDROM_AUTOEJECT=3, - DEV_CDROM_DEBUG=4, - DEV_CDROM_LOCK=5, - DEV_CDROM_CHECK_MEDIA=6 -}; - -/* /proc/sys/dev/parport */ -enum { - DEV_PARPORT_DEFAULT=-3 -}; - -/* /proc/sys/dev/raid */ -enum { - DEV_RAID_SPEED_LIMIT_MIN=1, - DEV_RAID_SPEED_LIMIT_MAX=2 -}; - -/* /proc/sys/dev/parport/default */ -enum { - DEV_PARPORT_DEFAULT_TIMESLICE=1, - DEV_PARPORT_DEFAULT_SPINTIME=2 -}; - -/* /proc/sys/dev/parport/parport n */ -enum { - DEV_PARPORT_SPINTIME=1, - DEV_PARPORT_BASE_ADDR=2, - DEV_PARPORT_IRQ=3, - DEV_PARPORT_DMA=4, - DEV_PARPORT_MODES=5, - DEV_PARPORT_DEVICES=6, - DEV_PARPORT_AUTOPROBE=16 -}; - -/* /proc/sys/dev/parport/parport n/devices/ */ -enum { - DEV_PARPORT_DEVICES_ACTIVE=-3, -}; - -/* /proc/sys/dev/parport/parport n/devices/device n */ -enum { - DEV_PARPORT_DEVICE_TIMESLICE=1, -}; - -/* /proc/sys/dev/mac_hid */ -enum { - DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES=1, - DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES=2, - DEV_MAC_HID_MOUSE_BUTTON_EMULATION=3, - DEV_MAC_HID_MOUSE_BUTTON2_KEYCODE=4, - DEV_MAC_HID_MOUSE_BUTTON3_KEYCODE=5, - DEV_MAC_HID_ADB_MOUSE_SENDS_KEYCODES=6 -}; - -/* /proc/sys/dev/scsi */ -enum { - DEV_SCSI_LOGGING_LEVEL=1, -}; - -/* /proc/sys/dev/ipmi */ -enum { - DEV_IPMI_POWEROFF_POWERCYCLE=1, -}; - -/* /proc/sys/abi */ -enum -{ - ABI_DEFHANDLER_COFF=1, /* default handler for coff binaries */ - ABI_DEFHANDLER_ELF=2, /* default handler for ELF binaries */ - ABI_DEFHANDLER_LCALL7=3,/* default handler for procs using lcall7 */ - ABI_DEFHANDLER_LIBCSO=4,/* default handler for an libc.so ELF interp */ - ABI_TRACE=5, /* tracing flags */ - ABI_FAKE_UTSNAME=6, /* fake target utsname information */ -}; - - -#endif /* _UAPI_LINUX_SYSCTL_H */ diff --git a/src/linux/include/uapi/linux/sysinfo.h b/src/linux/include/uapi/linux/sysinfo.h deleted file mode 100644 index 934335a..0000000 --- a/src/linux/include/uapi/linux/sysinfo.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef _LINUX_SYSINFO_H -#define _LINUX_SYSINFO_H - -#include - -#define SI_LOAD_SHIFT 16 -struct sysinfo { - __kernel_long_t uptime; /* Seconds since boot */ - __kernel_ulong_t loads[3]; /* 1, 5, and 15 minute load averages */ - __kernel_ulong_t totalram; /* Total usable main memory size */ - __kernel_ulong_t freeram; /* Available memory size */ - __kernel_ulong_t sharedram; /* Amount of shared memory */ - __kernel_ulong_t bufferram; /* Memory used by buffers */ - __kernel_ulong_t totalswap; /* Total swap space size */ - __kernel_ulong_t freeswap; /* swap space still available */ - __u16 procs; /* Number of current processes */ - __u16 pad; /* Explicit padding for m68k */ - __kernel_ulong_t totalhigh; /* Total high memory size */ - __kernel_ulong_t freehigh; /* Available high memory size */ - __u32 mem_unit; /* Memory unit size in bytes */ - char _f[20-2*sizeof(__kernel_ulong_t)-sizeof(__u32)]; /* Padding: libc5 uses this.. */ -}; - -#endif /* _LINUX_SYSINFO_H */ diff --git a/src/linux/include/uapi/linux/taskstats.h b/src/linux/include/uapi/linux/taskstats.h deleted file mode 100644 index 2466e55..0000000 --- a/src/linux/include/uapi/linux/taskstats.h +++ /dev/null @@ -1,213 +0,0 @@ -/* taskstats.h - exporting per-task statistics - * - * Copyright (C) Shailabh Nagar, IBM Corp. 2006 - * (C) Balbir Singh, IBM Corp. 2006 - * (C) Jay Lan, SGI, 2006 - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2.1 of the GNU Lesser General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#ifndef _LINUX_TASKSTATS_H -#define _LINUX_TASKSTATS_H - -#include - -/* Format for per-task data returned to userland when - * - a task exits - * - listener requests stats for a task - * - * The struct is versioned. Newer versions should only add fields to - * the bottom of the struct to maintain backward compatibility. - * - * - * To add new fields - * a) bump up TASKSTATS_VERSION - * b) add comment indicating new version number at end of struct - * c) add new fields after version comment; maintain 64-bit alignment - */ - - -#define TASKSTATS_VERSION 8 -#define TS_COMM_LEN 32 /* should be >= TASK_COMM_LEN - * in linux/sched.h */ - -struct taskstats { - - /* The version number of this struct. This field is always set to - * TAKSTATS_VERSION, which is defined in . - * Each time the struct is changed, the value should be incremented. - */ - __u16 version; - __u32 ac_exitcode; /* Exit status */ - - /* The accounting flags of a task as defined in - * Defined values are AFORK, ASU, ACOMPAT, ACORE, and AXSIG. - */ - __u8 ac_flag; /* Record flags */ - __u8 ac_nice; /* task_nice */ - - /* Delay accounting fields start - * - * All values, until comment "Delay accounting fields end" are - * available only if delay accounting is enabled, even though the last - * few fields are not delays - * - * xxx_count is the number of delay values recorded - * xxx_delay_total is the corresponding cumulative delay in nanoseconds - * - * xxx_delay_total wraps around to zero on overflow - * xxx_count incremented regardless of overflow - */ - - /* Delay waiting for cpu, while runnable - * count, delay_total NOT updated atomically - */ - __u64 cpu_count __attribute__((aligned(8))); - __u64 cpu_delay_total; - - /* Following four fields atomically updated using task->delays->lock */ - - /* Delay waiting for synchronous block I/O to complete - * does not account for delays in I/O submission - */ - __u64 blkio_count; - __u64 blkio_delay_total; - - /* Delay waiting for page fault I/O (swap in only) */ - __u64 swapin_count; - __u64 swapin_delay_total; - - /* cpu "wall-clock" running time - * On some architectures, value will adjust for cpu time stolen - * from the kernel in involuntary waits due to virtualization. - * Value is cumulative, in nanoseconds, without a corresponding count - * and wraps around to zero silently on overflow - */ - __u64 cpu_run_real_total; - - /* cpu "virtual" running time - * Uses time intervals seen by the kernel i.e. no adjustment - * for kernel's involuntary waits due to virtualization. - * Value is cumulative, in nanoseconds, without a corresponding count - * and wraps around to zero silently on overflow - */ - __u64 cpu_run_virtual_total; - /* Delay accounting fields end */ - /* version 1 ends here */ - - /* Basic Accounting Fields start */ - char ac_comm[TS_COMM_LEN]; /* Command name */ - __u8 ac_sched __attribute__((aligned(8))); - /* Scheduling discipline */ - __u8 ac_pad[3]; - __u32 ac_uid __attribute__((aligned(8))); - /* User ID */ - __u32 ac_gid; /* Group ID */ - __u32 ac_pid; /* Process ID */ - __u32 ac_ppid; /* Parent process ID */ - __u32 ac_btime; /* Begin time [sec since 1970] */ - __u64 ac_etime __attribute__((aligned(8))); - /* Elapsed time [usec] */ - __u64 ac_utime; /* User CPU time [usec] */ - __u64 ac_stime; /* SYstem CPU time [usec] */ - __u64 ac_minflt; /* Minor Page Fault Count */ - __u64 ac_majflt; /* Major Page Fault Count */ - /* Basic Accounting Fields end */ - - /* Extended accounting fields start */ - /* Accumulated RSS usage in duration of a task, in MBytes-usecs. - * The current rss usage is added to this counter every time - * a tick is charged to a task's system time. So, at the end we - * will have memory usage multiplied by system time. Thus an - * average usage per system time unit can be calculated. - */ - __u64 coremem; /* accumulated RSS usage in MB-usec */ - /* Accumulated virtual memory usage in duration of a task. - * Same as acct_rss_mem1 above except that we keep track of VM usage. - */ - __u64 virtmem; /* accumulated VM usage in MB-usec */ - - /* High watermark of RSS and virtual memory usage in duration of - * a task, in KBytes. - */ - __u64 hiwater_rss; /* High-watermark of RSS usage, in KB */ - __u64 hiwater_vm; /* High-water VM usage, in KB */ - - /* The following four fields are I/O statistics of a task. */ - __u64 read_char; /* bytes read */ - __u64 write_char; /* bytes written */ - __u64 read_syscalls; /* read syscalls */ - __u64 write_syscalls; /* write syscalls */ - /* Extended accounting fields end */ - -#define TASKSTATS_HAS_IO_ACCOUNTING - /* Per-task storage I/O accounting starts */ - __u64 read_bytes; /* bytes of read I/O */ - __u64 write_bytes; /* bytes of write I/O */ - __u64 cancelled_write_bytes; /* bytes of cancelled write I/O */ - - __u64 nvcsw; /* voluntary_ctxt_switches */ - __u64 nivcsw; /* nonvoluntary_ctxt_switches */ - - /* time accounting for SMT machines */ - __u64 ac_utimescaled; /* utime scaled on frequency etc */ - __u64 ac_stimescaled; /* stime scaled on frequency etc */ - __u64 cpu_scaled_run_real_total; /* scaled cpu_run_real_total */ - - /* Delay waiting for memory reclaim */ - __u64 freepages_count; - __u64 freepages_delay_total; -}; - - -/* - * Commands sent from userspace - * Not versioned. New commands should only be inserted at the enum's end - * prior to __TASKSTATS_CMD_MAX - */ - -enum { - TASKSTATS_CMD_UNSPEC = 0, /* Reserved */ - TASKSTATS_CMD_GET, /* user->kernel request/get-response */ - TASKSTATS_CMD_NEW, /* kernel->user event */ - __TASKSTATS_CMD_MAX, -}; - -#define TASKSTATS_CMD_MAX (__TASKSTATS_CMD_MAX - 1) - -enum { - TASKSTATS_TYPE_UNSPEC = 0, /* Reserved */ - TASKSTATS_TYPE_PID, /* Process id */ - TASKSTATS_TYPE_TGID, /* Thread group id */ - TASKSTATS_TYPE_STATS, /* taskstats structure */ - TASKSTATS_TYPE_AGGR_PID, /* contains pid + stats */ - TASKSTATS_TYPE_AGGR_TGID, /* contains tgid + stats */ - TASKSTATS_TYPE_NULL, /* contains nothing */ - __TASKSTATS_TYPE_MAX, -}; - -#define TASKSTATS_TYPE_MAX (__TASKSTATS_TYPE_MAX - 1) - -enum { - TASKSTATS_CMD_ATTR_UNSPEC = 0, - TASKSTATS_CMD_ATTR_PID, - TASKSTATS_CMD_ATTR_TGID, - TASKSTATS_CMD_ATTR_REGISTER_CPUMASK, - TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK, - __TASKSTATS_CMD_ATTR_MAX, -}; - -#define TASKSTATS_CMD_ATTR_MAX (__TASKSTATS_CMD_ATTR_MAX - 1) - -/* NETLINK_GENERIC related info */ - -#define TASKSTATS_GENL_NAME "TASKSTATS" -#define TASKSTATS_GENL_VERSION 0x1 - -#endif /* _LINUX_TASKSTATS_H */ diff --git a/src/linux/include/uapi/linux/tcp.h b/src/linux/include/uapi/linux/tcp.h deleted file mode 100644 index 73ac0db..0000000 --- a/src/linux/include/uapi/linux/tcp.h +++ /dev/null @@ -1,230 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the TCP protocol. - * - * Version: @(#)tcp.h 1.0.2 04/28/93 - * - * Author: Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _UAPI_LINUX_TCP_H -#define _UAPI_LINUX_TCP_H - -#include -#include -#include - -struct tcphdr { - __be16 source; - __be16 dest; - __be32 seq; - __be32 ack_seq; -#if defined(__LITTLE_ENDIAN_BITFIELD) - __u16 res1:4, - doff:4, - fin:1, - syn:1, - rst:1, - psh:1, - ack:1, - urg:1, - ece:1, - cwr:1; -#elif defined(__BIG_ENDIAN_BITFIELD) - __u16 doff:4, - res1:4, - cwr:1, - ece:1, - urg:1, - ack:1, - psh:1, - rst:1, - syn:1, - fin:1; -#else -#error "Adjust your defines" -#endif - __be16 window; - __sum16 check; - __be16 urg_ptr; -}; - -/* - * The union cast uses a gcc extension to avoid aliasing problems - * (union is compatible to any of its members) - * This means this part of the code is -fstrict-aliasing safe now. - */ -union tcp_word_hdr { - struct tcphdr hdr; - __be32 words[5]; -}; - -#define tcp_flag_word(tp) ( ((union tcp_word_hdr *)(tp))->words [3]) - -enum { - TCP_FLAG_CWR = __constant_cpu_to_be32(0x00800000), - TCP_FLAG_ECE = __constant_cpu_to_be32(0x00400000), - TCP_FLAG_URG = __constant_cpu_to_be32(0x00200000), - TCP_FLAG_ACK = __constant_cpu_to_be32(0x00100000), - TCP_FLAG_PSH = __constant_cpu_to_be32(0x00080000), - TCP_FLAG_RST = __constant_cpu_to_be32(0x00040000), - TCP_FLAG_SYN = __constant_cpu_to_be32(0x00020000), - TCP_FLAG_FIN = __constant_cpu_to_be32(0x00010000), - TCP_RESERVED_BITS = __constant_cpu_to_be32(0x0F000000), - TCP_DATA_OFFSET = __constant_cpu_to_be32(0xF0000000) -}; - -/* - * TCP general constants - */ -#define TCP_MSS_DEFAULT 536U /* IPv4 (RFC1122, RFC2581) */ -#define TCP_MSS_DESIRED 1220U /* IPv6 (tunneled), EDNS0 (RFC3226) */ - -/* TCP socket options */ -#define TCP_NODELAY 1 /* Turn off Nagle's algorithm. */ -#define TCP_MAXSEG 2 /* Limit MSS */ -#define TCP_CORK 3 /* Never send partially complete segments */ -#define TCP_KEEPIDLE 4 /* Start keeplives after this period */ -#define TCP_KEEPINTVL 5 /* Interval between keepalives */ -#define TCP_KEEPCNT 6 /* Number of keepalives before death */ -#define TCP_SYNCNT 7 /* Number of SYN retransmits */ -#define TCP_LINGER2 8 /* Life time of orphaned FIN-WAIT-2 state */ -#define TCP_DEFER_ACCEPT 9 /* Wake up listener only when data arrive */ -#define TCP_WINDOW_CLAMP 10 /* Bound advertised window */ -#define TCP_INFO 11 /* Information about this connection. */ -#define TCP_QUICKACK 12 /* Block/reenable quick acks */ -#define TCP_CONGESTION 13 /* Congestion control algorithm */ -#define TCP_MD5SIG 14 /* TCP MD5 Signature (RFC2385) */ -#define TCP_THIN_LINEAR_TIMEOUTS 16 /* Use linear timeouts for thin streams*/ -#define TCP_THIN_DUPACK 17 /* Fast retrans. after 1 dupack */ -#define TCP_USER_TIMEOUT 18 /* How long for loss retry before timeout */ -#define TCP_REPAIR 19 /* TCP sock is under repair right now */ -#define TCP_REPAIR_QUEUE 20 -#define TCP_QUEUE_SEQ 21 -#define TCP_REPAIR_OPTIONS 22 -#define TCP_FASTOPEN 23 /* Enable FastOpen on listeners */ -#define TCP_TIMESTAMP 24 -#define TCP_NOTSENT_LOWAT 25 /* limit number of unsent bytes in write queue */ -#define TCP_CC_INFO 26 /* Get Congestion Control (optional) info */ -#define TCP_SAVE_SYN 27 /* Record SYN headers for new connections */ -#define TCP_SAVED_SYN 28 /* Get SYN headers recorded for connection */ -#define TCP_REPAIR_WINDOW 29 /* Get/set window parameters */ - -struct tcp_repair_opt { - __u32 opt_code; - __u32 opt_val; -}; - -struct tcp_repair_window { - __u32 snd_wl1; - __u32 snd_wnd; - __u32 max_window; - - __u32 rcv_wnd; - __u32 rcv_wup; -}; - -enum { - TCP_NO_QUEUE, - TCP_RECV_QUEUE, - TCP_SEND_QUEUE, - TCP_QUEUES_NR, -}; - -/* for TCP_INFO socket option */ -#define TCPI_OPT_TIMESTAMPS 1 -#define TCPI_OPT_SACK 2 -#define TCPI_OPT_WSCALE 4 -#define TCPI_OPT_ECN 8 /* ECN was negociated at TCP session init */ -#define TCPI_OPT_ECN_SEEN 16 /* we received at least one packet with ECT */ -#define TCPI_OPT_SYN_DATA 32 /* SYN-ACK acked data in SYN sent or rcvd */ - -enum tcp_ca_state { - TCP_CA_Open = 0, -#define TCPF_CA_Open (1< - -/* NETLINK_GENERIC related info - */ -#define TCP_METRICS_GENL_NAME "tcp_metrics" -#define TCP_METRICS_GENL_VERSION 0x1 - -enum tcp_metric_index { - TCP_METRIC_RTT, /* in ms units */ - TCP_METRIC_RTTVAR, /* in ms units */ - TCP_METRIC_SSTHRESH, - TCP_METRIC_CWND, - TCP_METRIC_REORDERING, - - TCP_METRIC_RTT_US, /* in usec units */ - TCP_METRIC_RTTVAR_US, /* in usec units */ - - /* Always last. */ - __TCP_METRIC_MAX, -}; - -#define TCP_METRIC_MAX (__TCP_METRIC_MAX - 1) - -enum { - TCP_METRICS_ATTR_UNSPEC, - TCP_METRICS_ATTR_ADDR_IPV4, /* u32 */ - TCP_METRICS_ATTR_ADDR_IPV6, /* binary */ - TCP_METRICS_ATTR_AGE, /* msecs */ - TCP_METRICS_ATTR_TW_TSVAL, /* u32, raw, rcv tsval */ - TCP_METRICS_ATTR_TW_TS_STAMP, /* s32, sec age */ - TCP_METRICS_ATTR_VALS, /* nested +1, u32 */ - TCP_METRICS_ATTR_FOPEN_MSS, /* u16 */ - TCP_METRICS_ATTR_FOPEN_SYN_DROPS, /* u16, count of drops */ - TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS, /* msecs age */ - TCP_METRICS_ATTR_FOPEN_COOKIE, /* binary */ - TCP_METRICS_ATTR_SADDR_IPV4, /* u32 */ - TCP_METRICS_ATTR_SADDR_IPV6, /* binary */ - TCP_METRICS_ATTR_PAD, - - __TCP_METRICS_ATTR_MAX, -}; - -#define TCP_METRICS_ATTR_MAX (__TCP_METRICS_ATTR_MAX - 1) - -enum { - TCP_METRICS_CMD_UNSPEC, - TCP_METRICS_CMD_GET, - TCP_METRICS_CMD_DEL, - - __TCP_METRICS_CMD_MAX, -}; - -#define TCP_METRICS_CMD_MAX (__TCP_METRICS_CMD_MAX - 1) - -#endif /* _LINUX_TCP_METRICS_H */ diff --git a/src/linux/include/uapi/linux/termios.h b/src/linux/include/uapi/linux/termios.h deleted file mode 100644 index 2acd0c1..0000000 --- a/src/linux/include/uapi/linux/termios.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef _LINUX_TERMIOS_H -#define _LINUX_TERMIOS_H - -#include -#include - -#define NFF 5 - -struct termiox -{ - __u16 x_hflag; - __u16 x_cflag; - __u16 x_rflag[NFF]; - __u16 x_sflag; -}; - -#define RTSXOFF 0x0001 /* RTS flow control on input */ -#define CTSXON 0x0002 /* CTS flow control on output */ -#define DTRXOFF 0x0004 /* DTR flow control on input */ -#define DSRXON 0x0008 /* DCD flow control on output */ - -#endif diff --git a/src/linux/include/uapi/linux/thermal.h b/src/linux/include/uapi/linux/thermal.h deleted file mode 100644 index ac55358..0000000 --- a/src/linux/include/uapi/linux/thermal.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _UAPI_LINUX_THERMAL_H -#define _UAPI_LINUX_THERMAL_H - -#define THERMAL_NAME_LENGTH 20 - -/* Adding event notification support elements */ -#define THERMAL_GENL_FAMILY_NAME "thermal_event" -#define THERMAL_GENL_VERSION 0x01 -#define THERMAL_GENL_MCAST_GROUP_NAME "thermal_mc_grp" - -/* Events supported by Thermal Netlink */ -enum events { - THERMAL_AUX0, - THERMAL_AUX1, - THERMAL_CRITICAL, - THERMAL_DEV_FAULT, -}; - -/* attributes of thermal_genl_family */ -enum { - THERMAL_GENL_ATTR_UNSPEC, - THERMAL_GENL_ATTR_EVENT, - __THERMAL_GENL_ATTR_MAX, -}; -#define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1) - -/* commands supported by the thermal_genl_family */ -enum { - THERMAL_GENL_CMD_UNSPEC, - THERMAL_GENL_CMD_EVENT, - __THERMAL_GENL_CMD_MAX, -}; -#define THERMAL_GENL_CMD_MAX (__THERMAL_GENL_CMD_MAX - 1) - -#endif /* _UAPI_LINUX_THERMAL_H */ diff --git a/src/linux/include/uapi/linux/time.h b/src/linux/include/uapi/linux/time.h deleted file mode 100644 index e75e1b6..0000000 --- a/src/linux/include/uapi/linux/time.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef _UAPI_LINUX_TIME_H -#define _UAPI_LINUX_TIME_H - -#include - - -#ifndef _STRUCT_TIMESPEC -#define _STRUCT_TIMESPEC -struct timespec { - __kernel_time_t tv_sec; /* seconds */ - long tv_nsec; /* nanoseconds */ -}; -#endif - -struct timeval { - __kernel_time_t tv_sec; /* seconds */ - __kernel_suseconds_t tv_usec; /* microseconds */ -}; - -struct timezone { - int tz_minuteswest; /* minutes west of Greenwich */ - int tz_dsttime; /* type of dst correction */ -}; - - -/* - * Names of the interval timers, and structure - * defining a timer setting: - */ -#define ITIMER_REAL 0 -#define ITIMER_VIRTUAL 1 -#define ITIMER_PROF 2 - -struct itimerspec { - struct timespec it_interval; /* timer period */ - struct timespec it_value; /* timer expiration */ -}; - -struct itimerval { - struct timeval it_interval; /* timer interval */ - struct timeval it_value; /* current value */ -}; - -/* - * The IDs of the various system clocks (for POSIX.1b interval timers): - */ -#define CLOCK_REALTIME 0 -#define CLOCK_MONOTONIC 1 -#define CLOCK_PROCESS_CPUTIME_ID 2 -#define CLOCK_THREAD_CPUTIME_ID 3 -#define CLOCK_MONOTONIC_RAW 4 -#define CLOCK_REALTIME_COARSE 5 -#define CLOCK_MONOTONIC_COARSE 6 -#define CLOCK_BOOTTIME 7 -#define CLOCK_REALTIME_ALARM 8 -#define CLOCK_BOOTTIME_ALARM 9 -#define CLOCK_SGI_CYCLE 10 /* Hardware specific */ -#define CLOCK_TAI 11 - -#define MAX_CLOCKS 16 -#define CLOCKS_MASK (CLOCK_REALTIME | CLOCK_MONOTONIC) -#define CLOCKS_MONO CLOCK_MONOTONIC - -/* - * The various flags for setting POSIX.1b interval timers: - */ -#define TIMER_ABSTIME 0x01 - -#endif /* _UAPI_LINUX_TIME_H */ diff --git a/src/linux/include/uapi/linux/times.h b/src/linux/include/uapi/linux/times.h deleted file mode 100644 index 87b6261..0000000 --- a/src/linux/include/uapi/linux/times.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _LINUX_TIMES_H -#define _LINUX_TIMES_H - -#include - -struct tms { - __kernel_clock_t tms_utime; - __kernel_clock_t tms_stime; - __kernel_clock_t tms_cutime; - __kernel_clock_t tms_cstime; -}; - -#endif diff --git a/src/linux/include/uapi/linux/timex.h b/src/linux/include/uapi/linux/timex.h deleted file mode 100644 index 92685d8..0000000 --- a/src/linux/include/uapi/linux/timex.h +++ /dev/null @@ -1,166 +0,0 @@ -/***************************************************************************** - * * - * Copyright (c) David L. Mills 1993 * - * * - * Permission to use, copy, modify, and distribute this software and its * - * documentation for any purpose and without fee is hereby granted, provided * - * that the above copyright notice appears in all copies and that both the * - * copyright notice and this permission notice appear in supporting * - * documentation, and that the name University of Delaware not be used in * - * advertising or publicity pertaining to distribution of the software * - * without specific, written prior permission. The University of Delaware * - * makes no representations about the suitability this software for any * - * purpose. It is provided "as is" without express or implied warranty. * - * * - *****************************************************************************/ - -/* - * Modification history timex.h - * - * 29 Dec 97 Russell King - * Moved CLOCK_TICK_RATE, CLOCK_TICK_FACTOR and FINETUNE to asm/timex.h - * for ARM machines - * - * 9 Jan 97 Adrian Sun - * Shifted LATCH define to allow access to alpha machines. - * - * 26 Sep 94 David L. Mills - * Added defines for hybrid phase/frequency-lock loop. - * - * 19 Mar 94 David L. Mills - * Moved defines from kernel routines to header file and added new - * defines for PPS phase-lock loop. - * - * 20 Feb 94 David L. Mills - * Revised status codes and structures for external clock and PPS - * signal discipline. - * - * 28 Nov 93 David L. Mills - * Adjusted parameters to improve stability and increase poll - * interval. - * - * 17 Sep 93 David L. Mills - * Created file $NTP/include/sys/timex.h - * 07 Oct 93 Torsten Duwe - * Derived linux/timex.h - * 1995-08-13 Torsten Duwe - * kernel PLL updated to 1994-12-13 specs (rfc-1589) - * 1997-08-30 Ulrich Windl - * Added new constant NTP_PHASE_LIMIT - * 2004-08-12 Christoph Lameter - * Reworked time interpolation logic - */ -#ifndef _UAPI_LINUX_TIMEX_H -#define _UAPI_LINUX_TIMEX_H - -#include - -#define NTP_API 4 /* NTP API version */ - -/* - * syscall interface - used (mainly by NTP daemon) - * to discipline kernel clock oscillator - */ -struct timex { - unsigned int modes; /* mode selector */ - __kernel_long_t offset; /* time offset (usec) */ - __kernel_long_t freq; /* frequency offset (scaled ppm) */ - __kernel_long_t maxerror;/* maximum error (usec) */ - __kernel_long_t esterror;/* estimated error (usec) */ - int status; /* clock command/status */ - __kernel_long_t constant;/* pll time constant */ - __kernel_long_t precision;/* clock precision (usec) (read only) */ - __kernel_long_t tolerance;/* clock frequency tolerance (ppm) - * (read only) - */ - struct timeval time; /* (read only, except for ADJ_SETOFFSET) */ - __kernel_long_t tick; /* (modified) usecs between clock ticks */ - - __kernel_long_t ppsfreq;/* pps frequency (scaled ppm) (ro) */ - __kernel_long_t jitter; /* pps jitter (us) (ro) */ - int shift; /* interval duration (s) (shift) (ro) */ - __kernel_long_t stabil; /* pps stability (scaled ppm) (ro) */ - __kernel_long_t jitcnt; /* jitter limit exceeded (ro) */ - __kernel_long_t calcnt; /* calibration intervals (ro) */ - __kernel_long_t errcnt; /* calibration errors (ro) */ - __kernel_long_t stbcnt; /* stability limit exceeded (ro) */ - - int tai; /* TAI offset (ro) */ - - int :32; int :32; int :32; int :32; - int :32; int :32; int :32; int :32; - int :32; int :32; int :32; -}; - -/* - * Mode codes (timex.mode) - */ -#define ADJ_OFFSET 0x0001 /* time offset */ -#define ADJ_FREQUENCY 0x0002 /* frequency offset */ -#define ADJ_MAXERROR 0x0004 /* maximum time error */ -#define ADJ_ESTERROR 0x0008 /* estimated time error */ -#define ADJ_STATUS 0x0010 /* clock status */ -#define ADJ_TIMECONST 0x0020 /* pll time constant */ -#define ADJ_TAI 0x0080 /* set TAI offset */ -#define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */ -#define ADJ_MICRO 0x1000 /* select microsecond resolution */ -#define ADJ_NANO 0x2000 /* select nanosecond resolution */ -#define ADJ_TICK 0x4000 /* tick value */ - -#ifndef __KERNEL__ -#define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */ -#define ADJ_OFFSET_SS_READ 0xa001 /* read-only adjtime */ -#endif - -/* NTP userland likes the MOD_ prefix better */ -#define MOD_OFFSET ADJ_OFFSET -#define MOD_FREQUENCY ADJ_FREQUENCY -#define MOD_MAXERROR ADJ_MAXERROR -#define MOD_ESTERROR ADJ_ESTERROR -#define MOD_STATUS ADJ_STATUS -#define MOD_TIMECONST ADJ_TIMECONST -#define MOD_TAI ADJ_TAI -#define MOD_MICRO ADJ_MICRO -#define MOD_NANO ADJ_NANO - - -/* - * Status codes (timex.status) - */ -#define STA_PLL 0x0001 /* enable PLL updates (rw) */ -#define STA_PPSFREQ 0x0002 /* enable PPS freq discipline (rw) */ -#define STA_PPSTIME 0x0004 /* enable PPS time discipline (rw) */ -#define STA_FLL 0x0008 /* select frequency-lock mode (rw) */ - -#define STA_INS 0x0010 /* insert leap (rw) */ -#define STA_DEL 0x0020 /* delete leap (rw) */ -#define STA_UNSYNC 0x0040 /* clock unsynchronized (rw) */ -#define STA_FREQHOLD 0x0080 /* hold frequency (rw) */ - -#define STA_PPSSIGNAL 0x0100 /* PPS signal present (ro) */ -#define STA_PPSJITTER 0x0200 /* PPS signal jitter exceeded (ro) */ -#define STA_PPSWANDER 0x0400 /* PPS signal wander exceeded (ro) */ -#define STA_PPSERROR 0x0800 /* PPS signal calibration error (ro) */ - -#define STA_CLOCKERR 0x1000 /* clock hardware fault (ro) */ -#define STA_NANO 0x2000 /* resolution (0 = us, 1 = ns) (ro) */ -#define STA_MODE 0x4000 /* mode (0 = PLL, 1 = FLL) (ro) */ -#define STA_CLK 0x8000 /* clock source (0 = A, 1 = B) (ro) */ - -/* read-only bits */ -#define STA_RONLY (STA_PPSSIGNAL | STA_PPSJITTER | STA_PPSWANDER | \ - STA_PPSERROR | STA_CLOCKERR | STA_NANO | STA_MODE | STA_CLK) - -/* - * Clock states (time_state) - */ -#define TIME_OK 0 /* clock synchronized, no leap second */ -#define TIME_INS 1 /* insert leap second */ -#define TIME_DEL 2 /* delete leap second */ -#define TIME_OOP 3 /* leap second in progress */ -#define TIME_WAIT 4 /* leap second has occurred */ -#define TIME_ERROR 5 /* clock not synchronized */ -#define TIME_BAD TIME_ERROR /* bw compat */ - - -#endif /* _UAPI_LINUX_TIMEX_H */ diff --git a/src/linux/include/uapi/linux/tiocl.h b/src/linux/include/uapi/linux/tiocl.h deleted file mode 100644 index 4756862..0000000 --- a/src/linux/include/uapi/linux/tiocl.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _LINUX_TIOCL_H -#define _LINUX_TIOCL_H - -#define TIOCL_SETSEL 2 /* set a selection */ -#define TIOCL_SELCHAR 0 /* select characters */ -#define TIOCL_SELWORD 1 /* select whole words */ -#define TIOCL_SELLINE 2 /* select whole lines */ -#define TIOCL_SELPOINTER 3 /* show the pointer */ -#define TIOCL_SELCLEAR 4 /* clear visibility of selection */ -#define TIOCL_SELMOUSEREPORT 16 /* report beginning of selection */ -#define TIOCL_SELBUTTONMASK 15 /* button mask for report */ -/* selection extent */ -struct tiocl_selection { - unsigned short xs; /* X start */ - unsigned short ys; /* Y start */ - unsigned short xe; /* X end */ - unsigned short ye; /* Y end */ - unsigned short sel_mode; /* selection mode */ -}; - -#define TIOCL_PASTESEL 3 /* paste previous selection */ -#define TIOCL_UNBLANKSCREEN 4 /* unblank screen */ - -#define TIOCL_SELLOADLUT 5 - /* set characters to be considered alphabetic when selecting */ - /* u32[8] bit array, 4 bytes-aligned with type */ - -/* these two don't return a value: they write it back in the type */ -#define TIOCL_GETSHIFTSTATE 6 /* write shift state */ -#define TIOCL_GETMOUSEREPORTING 7 /* write whether mouse event are reported */ -#define TIOCL_SETVESABLANK 10 /* set vesa blanking mode */ -#define TIOCL_SETKMSGREDIRECT 11 /* restrict kernel messages to a vt */ -#define TIOCL_GETFGCONSOLE 12 /* get foreground vt */ -#define TIOCL_SCROLLCONSOLE 13 /* scroll console */ -#define TIOCL_BLANKSCREEN 14 /* keep screen blank even if a key is pressed */ -#define TIOCL_BLANKEDSCREEN 15 /* return which vt was blanked */ -#define TIOCL_GETKMSGREDIRECT 17 /* get the vt the kernel messages are restricted to */ - -#endif /* _LINUX_TIOCL_H */ diff --git a/src/linux/include/uapi/linux/tty.h b/src/linux/include/uapi/linux/tty.h deleted file mode 100644 index 01c4410..0000000 --- a/src/linux/include/uapi/linux/tty.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef _UAPI_LINUX_TTY_H -#define _UAPI_LINUX_TTY_H - -/* - * 'tty.h' defines some structures used by tty_io.c and some defines. - */ - -#define NR_LDISCS 30 - -/* line disciplines */ -#define N_TTY 0 -#define N_SLIP 1 -#define N_MOUSE 2 -#define N_PPP 3 -#define N_STRIP 4 -#define N_AX25 5 -#define N_X25 6 /* X.25 async */ -#define N_6PACK 7 -#define N_MASC 8 /* Reserved for Mobitex module */ -#define N_R3964 9 /* Reserved for Simatic R3964 module */ -#define N_PROFIBUS_FDL 10 /* Reserved for Profibus */ -#define N_IRDA 11 /* Linux IrDa - http://irda.sourceforge.net/ */ -#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data */ - /* cards about SMS messages */ -#define N_HDLC 13 /* synchronous HDLC */ -#define N_SYNC_PPP 14 /* synchronous PPP */ -#define N_HCI 15 /* Bluetooth HCI UART */ -#define N_GIGASET_M101 16 /* Siemens Gigaset M101 serial DECT adapter */ -#define N_SLCAN 17 /* Serial / USB serial CAN Adaptors */ -#define N_PPS 18 /* Pulse per Second */ -#define N_V253 19 /* Codec control over voice modem */ -#define N_CAIF 20 /* CAIF protocol for talking to modems */ -#define N_GSM0710 21 /* GSM 0710 Mux */ -#define N_TI_WL 22 /* for TI's WL BT, FM, GPS combo chips */ -#define N_TRACESINK 23 /* Trace data routing for MIPI P1149.7 */ -#define N_TRACEROUTER 24 /* Trace data routing for MIPI P1149.7 */ -#define N_NCI 25 /* NFC NCI UART */ - -#endif /* _UAPI_LINUX_TTY_H */ diff --git a/src/linux/include/uapi/linux/tty_flags.h b/src/linux/include/uapi/linux/tty_flags.h deleted file mode 100644 index 66e4d8b..0000000 --- a/src/linux/include/uapi/linux/tty_flags.h +++ /dev/null @@ -1,96 +0,0 @@ -#ifndef _LINUX_TTY_FLAGS_H -#define _LINUX_TTY_FLAGS_H - -/* - * Definitions for async_struct (and serial_struct) flags field also - * shared by the tty_port flags structures. - * - * Define ASYNCB_* for convenient use with {test,set,clear}_bit. - * - * Bits [0..ASYNCB_LAST_USER] are userspace defined/visible/changeable - * [x] in the bit comments indicates the flag is defunct and no longer used. - */ -#define ASYNCB_HUP_NOTIFY 0 /* Notify getty on hangups and closes - * on the callout port */ -#define ASYNCB_FOURPORT 1 /* Set OU1, OUT2 per AST Fourport settings */ -#define ASYNCB_SAK 2 /* Secure Attention Key (Orange book) */ -#define ASYNCB_SPLIT_TERMIOS 3 /* [x] Separate termios for dialin/callout */ -#define ASYNCB_SPD_HI 4 /* Use 57600 instead of 38400 bps */ -#define ASYNCB_SPD_VHI 5 /* Use 115200 instead of 38400 bps */ -#define ASYNCB_SKIP_TEST 6 /* Skip UART test during autoconfiguration */ -#define ASYNCB_AUTO_IRQ 7 /* Do automatic IRQ during - * autoconfiguration */ -#define ASYNCB_SESSION_LOCKOUT 8 /* [x] Lock out cua opens based on session */ -#define ASYNCB_PGRP_LOCKOUT 9 /* [x] Lock out cua opens based on pgrp */ -#define ASYNCB_CALLOUT_NOHUP 10 /* [x] Don't do hangups for cua device */ -#define ASYNCB_HARDPPS_CD 11 /* Call hardpps when CD goes high */ -#define ASYNCB_SPD_SHI 12 /* Use 230400 instead of 38400 bps */ -#define ASYNCB_LOW_LATENCY 13 /* Request low latency behaviour */ -#define ASYNCB_BUGGY_UART 14 /* This is a buggy UART, skip some safety - * checks. Note: can be dangerous! */ -#define ASYNCB_AUTOPROBE 15 /* [x] Port was autoprobed by PCI/PNP code */ -#define ASYNCB_MAGIC_MULTIPLIER 16 /* Use special CLK or divisor */ -#define ASYNCB_LAST_USER 16 - -/* - * Internal flags used only by kernel (read-only) - * - * WARNING: These flags are no longer used and have been superceded by the - * TTY_PORT_ flags in the iflags field (and not userspace-visible) - */ -#ifndef _KERNEL_ -#define ASYNCB_INITIALIZED 31 /* Serial port was initialized */ -#define ASYNCB_SUSPENDED 30 /* Serial port is suspended */ -#define ASYNCB_NORMAL_ACTIVE 29 /* Normal device is active */ -#define ASYNCB_BOOT_AUTOCONF 28 /* Autoconfigure port on bootup */ -#define ASYNCB_CLOSING 27 /* Serial port is closing */ -#define ASYNCB_CTS_FLOW 26 /* Do CTS flow control */ -#define ASYNCB_CHECK_CD 25 /* i.e., CLOCAL */ -#define ASYNCB_SHARE_IRQ 24 /* for multifunction cards, no longer used */ -#define ASYNCB_CONS_FLOW 23 /* flow control for console */ -#define ASYNCB_FIRST_KERNEL 22 -#endif - -/* Masks */ -#define ASYNC_HUP_NOTIFY (1U << ASYNCB_HUP_NOTIFY) -#define ASYNC_SUSPENDED (1U << ASYNCB_SUSPENDED) -#define ASYNC_FOURPORT (1U << ASYNCB_FOURPORT) -#define ASYNC_SAK (1U << ASYNCB_SAK) -#define ASYNC_SPLIT_TERMIOS (1U << ASYNCB_SPLIT_TERMIOS) -#define ASYNC_SPD_HI (1U << ASYNCB_SPD_HI) -#define ASYNC_SPD_VHI (1U << ASYNCB_SPD_VHI) -#define ASYNC_SKIP_TEST (1U << ASYNCB_SKIP_TEST) -#define ASYNC_AUTO_IRQ (1U << ASYNCB_AUTO_IRQ) -#define ASYNC_SESSION_LOCKOUT (1U << ASYNCB_SESSION_LOCKOUT) -#define ASYNC_PGRP_LOCKOUT (1U << ASYNCB_PGRP_LOCKOUT) -#define ASYNC_CALLOUT_NOHUP (1U << ASYNCB_CALLOUT_NOHUP) -#define ASYNC_HARDPPS_CD (1U << ASYNCB_HARDPPS_CD) -#define ASYNC_SPD_SHI (1U << ASYNCB_SPD_SHI) -#define ASYNC_LOW_LATENCY (1U << ASYNCB_LOW_LATENCY) -#define ASYNC_BUGGY_UART (1U << ASYNCB_BUGGY_UART) -#define ASYNC_AUTOPROBE (1U << ASYNCB_AUTOPROBE) -#define ASYNC_MAGIC_MULTIPLIER (1U << ASYNCB_MAGIC_MULTIPLIER) - -#define ASYNC_FLAGS ((1U << (ASYNCB_LAST_USER + 1)) - 1) -#define ASYNC_DEPRECATED (ASYNC_SESSION_LOCKOUT | ASYNC_PGRP_LOCKOUT | \ - ASYNC_CALLOUT_NOHUP | ASYNC_AUTOPROBE) -#define ASYNC_USR_MASK (ASYNC_SPD_MASK|ASYNC_CALLOUT_NOHUP| \ - ASYNC_LOW_LATENCY) -#define ASYNC_SPD_CUST (ASYNC_SPD_HI|ASYNC_SPD_VHI) -#define ASYNC_SPD_WARP (ASYNC_SPD_HI|ASYNC_SPD_SHI) -#define ASYNC_SPD_MASK (ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI) - -#ifndef _KERNEL_ -/* These flags are no longer used (and were always masked from userspace) */ -#define ASYNC_INITIALIZED (1U << ASYNCB_INITIALIZED) -#define ASYNC_NORMAL_ACTIVE (1U << ASYNCB_NORMAL_ACTIVE) -#define ASYNC_BOOT_AUTOCONF (1U << ASYNCB_BOOT_AUTOCONF) -#define ASYNC_CLOSING (1U << ASYNCB_CLOSING) -#define ASYNC_CTS_FLOW (1U << ASYNCB_CTS_FLOW) -#define ASYNC_CHECK_CD (1U << ASYNCB_CHECK_CD) -#define ASYNC_SHARE_IRQ (1U << ASYNCB_SHARE_IRQ) -#define ASYNC_CONS_FLOW (1U << ASYNCB_CONS_FLOW) -#define ASYNC_INTERNAL_FLAGS (~((1U << ASYNCB_FIRST_KERNEL) - 1)) -#endif - -#endif diff --git a/src/linux/include/uapi/linux/types.h b/src/linux/include/uapi/linux/types.h deleted file mode 100644 index acf0979..0000000 --- a/src/linux/include/uapi/linux/types.h +++ /dev/null @@ -1,56 +0,0 @@ -#ifndef _UAPI_LINUX_TYPES_H -#define _UAPI_LINUX_TYPES_H - -#include - -#ifndef __ASSEMBLY__ -#ifndef __KERNEL__ -#ifndef __EXPORTED_HEADERS__ -#warning "Attempt to use kernel headers from user space, see http://kernelnewbies.org/KernelHeaders" -#endif /* __EXPORTED_HEADERS__ */ -#endif - -#include - - -/* - * Below are truly Linux-specific types that should never collide with - * any application/library that wants linux/types.h. - */ - -#ifdef __CHECKER__ -#define __bitwise__ __attribute__((bitwise)) -#else -#define __bitwise__ -#endif -#ifdef __CHECK_ENDIAN__ -#define __bitwise __bitwise__ -#else -#define __bitwise -#endif - -typedef __u16 __bitwise __le16; -typedef __u16 __bitwise __be16; -typedef __u32 __bitwise __le32; -typedef __u32 __bitwise __be32; -typedef __u64 __bitwise __le64; -typedef __u64 __bitwise __be64; - -typedef __u16 __bitwise __sum16; -typedef __u32 __bitwise __wsum; - -/* - * aligned_u64 should be used in defining kernel<->userspace ABIs to avoid - * common 32/64-bit compat problems. - * 64-bit values align to 4-byte boundaries on x86_32 (and possibly other - * architectures) and to 8-byte boundaries on 64-bit architectures. The new - * aligned_64 type enforces 8-byte alignment so that structs containing - * aligned_64 values have the same alignment on 32-bit and 64-bit architectures. - * No conversions are necessary between 32-bit user-space and a 64-bit kernel. - */ -#define __aligned_u64 __u64 __attribute__((aligned(8))) -#define __aligned_be64 __be64 __attribute__((aligned(8))) -#define __aligned_le64 __le64 __attribute__((aligned(8))) - -#endif /* __ASSEMBLY__ */ -#endif /* _UAPI_LINUX_TYPES_H */ diff --git a/src/linux/include/uapi/linux/udp.h b/src/linux/include/uapi/linux/udp.h deleted file mode 100644 index 2c8180f..0000000 --- a/src/linux/include/uapi/linux/udp.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Definitions for the UDP protocol. - * - * Version: @(#)udp.h 1.0.2 04/28/93 - * - * Author: Fred N. van Kempen, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _UAPI_LINUX_UDP_H -#define _UAPI_LINUX_UDP_H - -#include - -struct udphdr { - __be16 source; - __be16 dest; - __be16 len; - __sum16 check; -}; - -/* UDP socket options */ -#define UDP_CORK 1 /* Never send partially complete segments */ -#define UDP_ENCAP 100 /* Set the socket to accept encapsulated packets */ -#define UDP_NO_CHECK6_TX 101 /* Disable sending checksum for UDP6X */ -#define UDP_NO_CHECK6_RX 102 /* Disable accpeting checksum for UDP6 */ - -/* UDP encapsulation types */ -#define UDP_ENCAP_ESPINUDP_NON_IKE 1 /* draft-ietf-ipsec-nat-t-ike-00/01 */ -#define UDP_ENCAP_ESPINUDP 2 /* draft-ietf-ipsec-udp-encaps-06 */ -#define UDP_ENCAP_L2TPINUDP 3 /* rfc2661 */ -#define UDP_ENCAP_GTP0 4 /* GSM TS 09.60 */ -#define UDP_ENCAP_GTP1U 5 /* 3GPP TS 29.060 */ - -#endif /* _UAPI_LINUX_UDP_H */ diff --git a/src/linux/include/uapi/linux/uio.h b/src/linux/include/uapi/linux/uio.h deleted file mode 100644 index 2731d56..0000000 --- a/src/linux/include/uapi/linux/uio.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Berkeley style UIO structures - Alan Cox 1994. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef _UAPI__LINUX_UIO_H -#define _UAPI__LINUX_UIO_H - -#include -#include - - -struct iovec -{ - void __user *iov_base; /* BSD uses caddr_t (1003.1g requires void *) */ - __kernel_size_t iov_len; /* Must be size_t (1003.1g) */ -}; - -/* - * UIO_MAXIOV shall be at least 16 1003.1g (5.4.1.1) - */ - -#define UIO_FASTIOV 8 -#define UIO_MAXIOV 1024 - - -#endif /* _UAPI__LINUX_UIO_H */ diff --git a/src/linux/include/uapi/linux/un.h b/src/linux/include/uapi/linux/un.h deleted file mode 100644 index 3ed3e46..0000000 --- a/src/linux/include/uapi/linux/un.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _LINUX_UN_H -#define _LINUX_UN_H - -#include - -#define UNIX_PATH_MAX 108 - -struct sockaddr_un { - __kernel_sa_family_t sun_family; /* AF_UNIX */ - char sun_path[UNIX_PATH_MAX]; /* pathname */ -}; - -#endif /* _LINUX_UN_H */ diff --git a/src/linux/include/uapi/linux/unistd.h b/src/linux/include/uapi/linux/unistd.h deleted file mode 100644 index aa8d5b5..0000000 --- a/src/linux/include/uapi/linux/unistd.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef _LINUX_UNISTD_H_ -#define _LINUX_UNISTD_H_ - -/* - * Include machine specific syscall numbers - */ -#include - -#endif /* _LINUX_UNISTD_H_ */ diff --git a/src/linux/include/uapi/linux/utime.h b/src/linux/include/uapi/linux/utime.h deleted file mode 100644 index 5cdf673..0000000 --- a/src/linux/include/uapi/linux/utime.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _LINUX_UTIME_H -#define _LINUX_UTIME_H - -#include - -struct utimbuf { - __kernel_time_t actime; - __kernel_time_t modtime; -}; - -#endif diff --git a/src/linux/include/uapi/linux/utsname.h b/src/linux/include/uapi/linux/utsname.h deleted file mode 100644 index 872c2df..0000000 --- a/src/linux/include/uapi/linux/utsname.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _UAPI_LINUX_UTSNAME_H -#define _UAPI_LINUX_UTSNAME_H - -#define __OLD_UTS_LEN 8 - -struct oldold_utsname { - char sysname[9]; - char nodename[9]; - char release[9]; - char version[9]; - char machine[9]; -}; - -#define __NEW_UTS_LEN 64 - -struct old_utsname { - char sysname[65]; - char nodename[65]; - char release[65]; - char version[65]; - char machine[65]; -}; - -struct new_utsname { - char sysname[__NEW_UTS_LEN + 1]; - char nodename[__NEW_UTS_LEN + 1]; - char release[__NEW_UTS_LEN + 1]; - char version[__NEW_UTS_LEN + 1]; - char machine[__NEW_UTS_LEN + 1]; - char domainname[__NEW_UTS_LEN + 1]; -}; - - -#endif /* _UAPI_LINUX_UTSNAME_H */ diff --git a/src/linux/include/uapi/linux/uuid.h b/src/linux/include/uapi/linux/uuid.h deleted file mode 100644 index 3738e5f..0000000 --- a/src/linux/include/uapi/linux/uuid.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * UUID/GUID definition - * - * Copyright (C) 2010, Intel Corp. - * Huang Ying - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#ifndef _UAPI_LINUX_UUID_H_ -#define _UAPI_LINUX_UUID_H_ - -#include -#include - -typedef struct { - __u8 b[16]; -} uuid_le; - -typedef struct { - __u8 b[16]; -} uuid_be; - -#define UUID_LE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ -((uuid_le) \ -{{ (a) & 0xff, ((a) >> 8) & 0xff, ((a) >> 16) & 0xff, ((a) >> 24) & 0xff, \ - (b) & 0xff, ((b) >> 8) & 0xff, \ - (c) & 0xff, ((c) >> 8) & 0xff, \ - (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}) - -#define UUID_BE(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \ -((uuid_be) \ -{{ ((a) >> 24) & 0xff, ((a) >> 16) & 0xff, ((a) >> 8) & 0xff, (a) & 0xff, \ - ((b) >> 8) & 0xff, (b) & 0xff, \ - ((c) >> 8) & 0xff, (c) & 0xff, \ - (d0), (d1), (d2), (d3), (d4), (d5), (d6), (d7) }}) - -#define NULL_UUID_LE \ - UUID_LE(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00) - -#define NULL_UUID_BE \ - UUID_BE(0x00000000, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00) - - -#endif /* _UAPI_LINUX_UUID_H_ */ diff --git a/src/linux/include/uapi/linux/virtio_blk.h b/src/linux/include/uapi/linux/virtio_blk.h deleted file mode 100644 index 9ebe4d9..0000000 --- a/src/linux/include/uapi/linux/virtio_blk.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef _LINUX_VIRTIO_BLK_H -#define _LINUX_VIRTIO_BLK_H -/* This header is BSD licensed so anyone can use the definitions to implement - * compatible drivers/servers. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of IBM nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. */ -#include -#include -#include -#include - -/* Feature bits */ -#define VIRTIO_BLK_F_SIZE_MAX 1 /* Indicates maximum segment size */ -#define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */ -#define VIRTIO_BLK_F_GEOMETRY 4 /* Legacy geometry available */ -#define VIRTIO_BLK_F_RO 5 /* Disk is read-only */ -#define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/ -#define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */ -#define VIRTIO_BLK_F_MQ 12 /* support more than one vq */ - -/* Legacy feature bits */ -#ifndef VIRTIO_BLK_NO_LEGACY -#define VIRTIO_BLK_F_BARRIER 0 /* Does host support barriers? */ -#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */ -#define VIRTIO_BLK_F_FLUSH 9 /* Flush command supported */ -#define VIRTIO_BLK_F_CONFIG_WCE 11 /* Writeback mode available in config */ -#ifndef __KERNEL__ -/* Old (deprecated) name for VIRTIO_BLK_F_FLUSH. */ -#define VIRTIO_BLK_F_WCE VIRTIO_BLK_F_FLUSH -#endif -#endif /* !VIRTIO_BLK_NO_LEGACY */ - -#define VIRTIO_BLK_ID_BYTES 20 /* ID string length */ - -struct virtio_blk_config { - /* The capacity (in 512-byte sectors). */ - __u64 capacity; - /* The maximum segment size (if VIRTIO_BLK_F_SIZE_MAX) */ - __u32 size_max; - /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */ - __u32 seg_max; - /* geometry of the device (if VIRTIO_BLK_F_GEOMETRY) */ - struct virtio_blk_geometry { - __u16 cylinders; - __u8 heads; - __u8 sectors; - } geometry; - - /* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */ - __u32 blk_size; - - /* the next 4 entries are guarded by VIRTIO_BLK_F_TOPOLOGY */ - /* exponent for physical block per logical block. */ - __u8 physical_block_exp; - /* alignment offset in logical blocks. */ - __u8 alignment_offset; - /* minimum I/O size without performance penalty in logical blocks. */ - __u16 min_io_size; - /* optimal sustained I/O size in logical blocks. */ - __u32 opt_io_size; - - /* writeback mode (if VIRTIO_BLK_F_CONFIG_WCE) */ - __u8 wce; - __u8 unused; - - /* number of vqs, only available when VIRTIO_BLK_F_MQ is set */ - __u16 num_queues; -} __attribute__((packed)); - -/* - * Command types - * - * Usage is a bit tricky as some bits are used as flags and some are not. - * - * Rules: - * VIRTIO_BLK_T_OUT may be combined with VIRTIO_BLK_T_SCSI_CMD or - * VIRTIO_BLK_T_BARRIER. VIRTIO_BLK_T_FLUSH is a command of its own - * and may not be combined with any of the other flags. - */ - -/* These two define direction. */ -#define VIRTIO_BLK_T_IN 0 -#define VIRTIO_BLK_T_OUT 1 - -#ifndef VIRTIO_BLK_NO_LEGACY -/* This bit says it's a scsi command, not an actual read or write. */ -#define VIRTIO_BLK_T_SCSI_CMD 2 -#endif /* VIRTIO_BLK_NO_LEGACY */ - -/* Cache flush command */ -#define VIRTIO_BLK_T_FLUSH 4 - -/* Get device ID command */ -#define VIRTIO_BLK_T_GET_ID 8 - -#ifndef VIRTIO_BLK_NO_LEGACY -/* Barrier before this op. */ -#define VIRTIO_BLK_T_BARRIER 0x80000000 -#endif /* !VIRTIO_BLK_NO_LEGACY */ - -/* - * This comes first in the read scatter-gather list. - * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated, - * this is the first element of the read scatter-gather list. - */ -struct virtio_blk_outhdr { - /* VIRTIO_BLK_T* */ - __virtio32 type; - /* io priority. */ - __virtio32 ioprio; - /* Sector (ie. 512 byte offset) */ - __virtio64 sector; -}; - -#ifndef VIRTIO_BLK_NO_LEGACY -struct virtio_scsi_inhdr { - __virtio32 errors; - __virtio32 data_len; - __virtio32 sense_len; - __virtio32 residual; -}; -#endif /* !VIRTIO_BLK_NO_LEGACY */ - -/* And this is the final byte of the write scatter-gather list. */ -#define VIRTIO_BLK_S_OK 0 -#define VIRTIO_BLK_S_IOERR 1 -#define VIRTIO_BLK_S_UNSUPP 2 -#endif /* _LINUX_VIRTIO_BLK_H */ diff --git a/src/linux/include/uapi/linux/virtio_config.h b/src/linux/include/uapi/linux/virtio_config.h deleted file mode 100644 index 308e209..0000000 --- a/src/linux/include/uapi/linux/virtio_config.h +++ /dev/null @@ -1,74 +0,0 @@ -#ifndef _UAPI_LINUX_VIRTIO_CONFIG_H -#define _UAPI_LINUX_VIRTIO_CONFIG_H -/* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so - * anyone can use the definitions to implement compatible drivers/servers. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of IBM nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. */ - -/* Virtio devices use a standardized configuration space to define their - * features and pass configuration information, but each implementation can - * store and access that space differently. */ -#include - -/* Status byte for guest to report progress, and synchronize features. */ -/* We have seen device and processed generic fields (VIRTIO_CONFIG_F_VIRTIO) */ -#define VIRTIO_CONFIG_S_ACKNOWLEDGE 1 -/* We have found a driver for the device. */ -#define VIRTIO_CONFIG_S_DRIVER 2 -/* Driver has used its parts of the config, and is happy */ -#define VIRTIO_CONFIG_S_DRIVER_OK 4 -/* Driver has finished configuring features */ -#define VIRTIO_CONFIG_S_FEATURES_OK 8 -/* Device entered invalid state, driver must reset it */ -#define VIRTIO_CONFIG_S_NEEDS_RESET 0x40 -/* We've given up on this device. */ -#define VIRTIO_CONFIG_S_FAILED 0x80 - -/* Some virtio feature bits (currently bits 28 through 32) are reserved for the - * transport being used (eg. virtio_ring), the rest are per-device feature - * bits. */ -#define VIRTIO_TRANSPORT_F_START 28 -#define VIRTIO_TRANSPORT_F_END 34 - -#ifndef VIRTIO_CONFIG_NO_LEGACY -/* Do we get callbacks when the ring is completely used, even if we've - * suppressed them? */ -#define VIRTIO_F_NOTIFY_ON_EMPTY 24 - -/* Can the device handle any descriptor layout? */ -#define VIRTIO_F_ANY_LAYOUT 27 -#endif /* VIRTIO_CONFIG_NO_LEGACY */ - -/* v1.0 compliant. */ -#define VIRTIO_F_VERSION_1 32 - -/* - * If clear - device has the IOMMU bypass quirk feature. - * If set - use platform tools to detect the IOMMU. - * - * Note the reverse polarity (compared to most other features), - * this is for compatibility with legacy systems. - */ -#define VIRTIO_F_IOMMU_PLATFORM 33 -#endif /* _UAPI_LINUX_VIRTIO_CONFIG_H */ diff --git a/src/linux/include/uapi/linux/virtio_ids.h b/src/linux/include/uapi/linux/virtio_ids.h deleted file mode 100644 index 3228d58..0000000 --- a/src/linux/include/uapi/linux/virtio_ids.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef _LINUX_VIRTIO_IDS_H -#define _LINUX_VIRTIO_IDS_H -/* - * Virtio IDs - * - * This header is BSD licensed so anyone can use the definitions to implement - * compatible drivers/servers. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of IBM nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. */ - -#define VIRTIO_ID_NET 1 /* virtio net */ -#define VIRTIO_ID_BLOCK 2 /* virtio block */ -#define VIRTIO_ID_CONSOLE 3 /* virtio console */ -#define VIRTIO_ID_RNG 4 /* virtio rng */ -#define VIRTIO_ID_BALLOON 5 /* virtio balloon */ -#define VIRTIO_ID_RPMSG 7 /* virtio remote processor messaging */ -#define VIRTIO_ID_SCSI 8 /* virtio scsi */ -#define VIRTIO_ID_9P 9 /* 9p virtio console */ -#define VIRTIO_ID_RPROC_SERIAL 11 /* virtio remoteproc serial link */ -#define VIRTIO_ID_CAIF 12 /* Virtio caif */ -#define VIRTIO_ID_GPU 16 /* virtio GPU */ -#define VIRTIO_ID_INPUT 18 /* virtio input */ -#define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */ - -#endif /* _LINUX_VIRTIO_IDS_H */ diff --git a/src/linux/include/uapi/linux/virtio_net.h b/src/linux/include/uapi/linux/virtio_net.h deleted file mode 100644 index fc353b5..0000000 --- a/src/linux/include/uapi/linux/virtio_net.h +++ /dev/null @@ -1,248 +0,0 @@ -#ifndef _UAPI_LINUX_VIRTIO_NET_H -#define _UAPI_LINUX_VIRTIO_NET_H -/* This header is BSD licensed so anyone can use the definitions to implement - * compatible drivers/servers. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of IBM nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. */ -#include -#include -#include -#include -#include - -/* The feature bitmap for virtio net */ -#define VIRTIO_NET_F_CSUM 0 /* Host handles pkts w/ partial csum */ -#define VIRTIO_NET_F_GUEST_CSUM 1 /* Guest handles pkts w/ partial csum */ -#define VIRTIO_NET_F_CTRL_GUEST_OFFLOADS 2 /* Dynamic offload configuration. */ -#define VIRTIO_NET_F_MTU 3 /* Initial MTU advice */ -#define VIRTIO_NET_F_MAC 5 /* Host has given MAC address. */ -#define VIRTIO_NET_F_GUEST_TSO4 7 /* Guest can handle TSOv4 in. */ -#define VIRTIO_NET_F_GUEST_TSO6 8 /* Guest can handle TSOv6 in. */ -#define VIRTIO_NET_F_GUEST_ECN 9 /* Guest can handle TSO[6] w/ ECN in. */ -#define VIRTIO_NET_F_GUEST_UFO 10 /* Guest can handle UFO in. */ -#define VIRTIO_NET_F_HOST_TSO4 11 /* Host can handle TSOv4 in. */ -#define VIRTIO_NET_F_HOST_TSO6 12 /* Host can handle TSOv6 in. */ -#define VIRTIO_NET_F_HOST_ECN 13 /* Host can handle TSO[6] w/ ECN in. */ -#define VIRTIO_NET_F_HOST_UFO 14 /* Host can handle UFO in. */ -#define VIRTIO_NET_F_MRG_RXBUF 15 /* Host can merge receive buffers. */ -#define VIRTIO_NET_F_STATUS 16 /* virtio_net_config.status available */ -#define VIRTIO_NET_F_CTRL_VQ 17 /* Control channel available */ -#define VIRTIO_NET_F_CTRL_RX 18 /* Control channel RX mode support */ -#define VIRTIO_NET_F_CTRL_VLAN 19 /* Control channel VLAN filtering */ -#define VIRTIO_NET_F_CTRL_RX_EXTRA 20 /* Extra RX mode control support */ -#define VIRTIO_NET_F_GUEST_ANNOUNCE 21 /* Guest can announce device on the - * network */ -#define VIRTIO_NET_F_MQ 22 /* Device supports Receive Flow - * Steering */ -#define VIRTIO_NET_F_CTRL_MAC_ADDR 23 /* Set MAC address */ - -#ifndef VIRTIO_NET_NO_LEGACY -#define VIRTIO_NET_F_GSO 6 /* Host handles pkts w/ any GSO type */ -#endif /* VIRTIO_NET_NO_LEGACY */ - -#define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ -#define VIRTIO_NET_S_ANNOUNCE 2 /* Announcement is needed */ - -struct virtio_net_config { - /* The config defining mac address (if VIRTIO_NET_F_MAC) */ - __u8 mac[ETH_ALEN]; - /* See VIRTIO_NET_F_STATUS and VIRTIO_NET_S_* above */ - __u16 status; - /* Maximum number of each of transmit and receive queues; - * see VIRTIO_NET_F_MQ and VIRTIO_NET_CTRL_MQ. - * Legal values are between 1 and 0x8000 - */ - __u16 max_virtqueue_pairs; - /* Default maximum transmit unit advice */ - __u16 mtu; -} __attribute__((packed)); - -/* - * This header comes first in the scatter-gather list. If you don't - * specify GSO or CSUM features, you can simply ignore the header. - * - * This is bitwise-equivalent to the legacy struct virtio_net_hdr_mrg_rxbuf, - * only flattened. - */ -struct virtio_net_hdr_v1 { -#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 /* Use csum_start, csum_offset */ -#define VIRTIO_NET_HDR_F_DATA_VALID 2 /* Csum is valid */ - __u8 flags; -#define VIRTIO_NET_HDR_GSO_NONE 0 /* Not a GSO frame */ -#define VIRTIO_NET_HDR_GSO_TCPV4 1 /* GSO frame, IPv4 TCP (TSO) */ -#define VIRTIO_NET_HDR_GSO_UDP 3 /* GSO frame, IPv4 UDP (UFO) */ -#define VIRTIO_NET_HDR_GSO_TCPV6 4 /* GSO frame, IPv6 TCP */ -#define VIRTIO_NET_HDR_GSO_ECN 0x80 /* TCP has ECN set */ - __u8 gso_type; - __virtio16 hdr_len; /* Ethernet + IP + tcp/udp hdrs */ - __virtio16 gso_size; /* Bytes to append to hdr_len per frame */ - __virtio16 csum_start; /* Position to start checksumming from */ - __virtio16 csum_offset; /* Offset after that to place checksum */ - __virtio16 num_buffers; /* Number of merged rx buffers */ -}; - -#ifndef VIRTIO_NET_NO_LEGACY -/* This header comes first in the scatter-gather list. - * For legacy virtio, if VIRTIO_F_ANY_LAYOUT is not negotiated, it must - * be the first element of the scatter-gather list. If you don't - * specify GSO or CSUM features, you can simply ignore the header. */ -struct virtio_net_hdr { - /* See VIRTIO_NET_HDR_F_* */ - __u8 flags; - /* See VIRTIO_NET_HDR_GSO_* */ - __u8 gso_type; - __virtio16 hdr_len; /* Ethernet + IP + tcp/udp hdrs */ - __virtio16 gso_size; /* Bytes to append to hdr_len per frame */ - __virtio16 csum_start; /* Position to start checksumming from */ - __virtio16 csum_offset; /* Offset after that to place checksum */ -}; - -/* This is the version of the header to use when the MRG_RXBUF - * feature has been negotiated. */ -struct virtio_net_hdr_mrg_rxbuf { - struct virtio_net_hdr hdr; - __virtio16 num_buffers; /* Number of merged rx buffers */ -}; -#endif /* ...VIRTIO_NET_NO_LEGACY */ - -/* - * Control virtqueue data structures - * - * The control virtqueue expects a header in the first sg entry - * and an ack/status response in the last entry. Data for the - * command goes in between. - */ -struct virtio_net_ctrl_hdr { - __u8 class; - __u8 cmd; -} __attribute__((packed)); - -typedef __u8 virtio_net_ctrl_ack; - -#define VIRTIO_NET_OK 0 -#define VIRTIO_NET_ERR 1 - -/* - * Control the RX mode, ie. promisucous, allmulti, etc... - * All commands require an "out" sg entry containing a 1 byte - * state value, zero = disable, non-zero = enable. Commands - * 0 and 1 are supported with the VIRTIO_NET_F_CTRL_RX feature. - * Commands 2-5 are added with VIRTIO_NET_F_CTRL_RX_EXTRA. - */ -#define VIRTIO_NET_CTRL_RX 0 - #define VIRTIO_NET_CTRL_RX_PROMISC 0 - #define VIRTIO_NET_CTRL_RX_ALLMULTI 1 - #define VIRTIO_NET_CTRL_RX_ALLUNI 2 - #define VIRTIO_NET_CTRL_RX_NOMULTI 3 - #define VIRTIO_NET_CTRL_RX_NOUNI 4 - #define VIRTIO_NET_CTRL_RX_NOBCAST 5 - -/* - * Control the MAC - * - * The MAC filter table is managed by the hypervisor, the guest should - * assume the size is infinite. Filtering should be considered - * non-perfect, ie. based on hypervisor resources, the guest may - * received packets from sources not specified in the filter list. - * - * In addition to the class/cmd header, the TABLE_SET command requires - * two out scatterlists. Each contains a 4 byte count of entries followed - * by a concatenated byte stream of the ETH_ALEN MAC addresses. The - * first sg list contains unicast addresses, the second is for multicast. - * This functionality is present if the VIRTIO_NET_F_CTRL_RX feature - * is available. - * - * The ADDR_SET command requests one out scatterlist, it contains a - * 6 bytes MAC address. This functionality is present if the - * VIRTIO_NET_F_CTRL_MAC_ADDR feature is available. - */ -struct virtio_net_ctrl_mac { - __virtio32 entries; - __u8 macs[][ETH_ALEN]; -} __attribute__((packed)); - -#define VIRTIO_NET_CTRL_MAC 1 - #define VIRTIO_NET_CTRL_MAC_TABLE_SET 0 - #define VIRTIO_NET_CTRL_MAC_ADDR_SET 1 - -/* - * Control VLAN filtering - * - * The VLAN filter table is controlled via a simple ADD/DEL interface. - * VLAN IDs not added may be filterd by the hypervisor. Del is the - * opposite of add. Both commands expect an out entry containing a 2 - * byte VLAN ID. VLAN filterting is available with the - * VIRTIO_NET_F_CTRL_VLAN feature bit. - */ -#define VIRTIO_NET_CTRL_VLAN 2 - #define VIRTIO_NET_CTRL_VLAN_ADD 0 - #define VIRTIO_NET_CTRL_VLAN_DEL 1 - -/* - * Control link announce acknowledgement - * - * The command VIRTIO_NET_CTRL_ANNOUNCE_ACK is used to indicate that - * driver has recevied the notification; device would clear the - * VIRTIO_NET_S_ANNOUNCE bit in the status field after it receives - * this command. - */ -#define VIRTIO_NET_CTRL_ANNOUNCE 3 - #define VIRTIO_NET_CTRL_ANNOUNCE_ACK 0 - -/* - * Control Receive Flow Steering - * - * The command VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET - * enables Receive Flow Steering, specifying the number of the transmit and - * receive queues that will be used. After the command is consumed and acked by - * the device, the device will not steer new packets on receive virtqueues - * other than specified nor read from transmit virtqueues other than specified. - * Accordingly, driver should not transmit new packets on virtqueues other than - * specified. - */ -struct virtio_net_ctrl_mq { - __virtio16 virtqueue_pairs; -}; - -#define VIRTIO_NET_CTRL_MQ 4 - #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET 0 - #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN 1 - #define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX 0x8000 - -/* - * Control network offloads - * - * Reconfigures the network offloads that Guest can handle. - * - * Available with the VIRTIO_NET_F_CTRL_GUEST_OFFLOADS feature bit. - * - * Command data format matches the feature bit mask exactly. - * - * See VIRTIO_NET_F_GUEST_* for the list of offloads - * that can be enabled/disabled. - */ -#define VIRTIO_NET_CTRL_GUEST_OFFLOADS 5 -#define VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET 0 - -#endif /* _UAPI_LINUX_VIRTIO_NET_H */ diff --git a/src/linux/include/uapi/linux/virtio_ring.h b/src/linux/include/uapi/linux/virtio_ring.h deleted file mode 100644 index c072959..0000000 --- a/src/linux/include/uapi/linux/virtio_ring.h +++ /dev/null @@ -1,174 +0,0 @@ -#ifndef _UAPI_LINUX_VIRTIO_RING_H -#define _UAPI_LINUX_VIRTIO_RING_H -/* An interface for efficient virtio implementation, currently for use by KVM - * and lguest, but hopefully others soon. Do NOT change this since it will - * break existing servers and clients. - * - * This header is BSD licensed so anyone can use the definitions to implement - * compatible drivers/servers. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of IBM nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Copyright Rusty Russell IBM Corporation 2007. */ -#ifndef __KERNEL__ -#include -#endif -#include -#include - -/* This marks a buffer as continuing via the next field. */ -#define VRING_DESC_F_NEXT 1 -/* This marks a buffer as write-only (otherwise read-only). */ -#define VRING_DESC_F_WRITE 2 -/* This means the buffer contains a list of buffer descriptors. */ -#define VRING_DESC_F_INDIRECT 4 - -/* The Host uses this in used->flags to advise the Guest: don't kick me when - * you add a buffer. It's unreliable, so it's simply an optimization. Guest - * will still kick if it's out of buffers. */ -#define VRING_USED_F_NO_NOTIFY 1 -/* The Guest uses this in avail->flags to advise the Host: don't interrupt me - * when you consume a buffer. It's unreliable, so it's simply an - * optimization. */ -#define VRING_AVAIL_F_NO_INTERRUPT 1 - -/* We support indirect buffer descriptors */ -#define VIRTIO_RING_F_INDIRECT_DESC 28 - -/* The Guest publishes the used index for which it expects an interrupt - * at the end of the avail ring. Host should ignore the avail->flags field. */ -/* The Host publishes the avail index for which it expects a kick - * at the end of the used ring. Guest should ignore the used->flags field. */ -#define VIRTIO_RING_F_EVENT_IDX 29 - -/* Virtio ring descriptors: 16 bytes. These can chain together via "next". */ -struct vring_desc { - /* Address (guest-physical). */ - __virtio64 addr; - /* Length. */ - __virtio32 len; - /* The flags as indicated above. */ - __virtio16 flags; - /* We chain unused descriptors via this, too */ - __virtio16 next; -}; - -struct vring_avail { - __virtio16 flags; - __virtio16 idx; - __virtio16 ring[]; -}; - -/* u32 is used here for ids for padding reasons. */ -struct vring_used_elem { - /* Index of start of used descriptor chain. */ - __virtio32 id; - /* Total length of the descriptor chain which was used (written to) */ - __virtio32 len; -}; - -struct vring_used { - __virtio16 flags; - __virtio16 idx; - struct vring_used_elem ring[]; -}; - -struct vring { - unsigned int num; - - struct vring_desc *desc; - - struct vring_avail *avail; - - struct vring_used *used; -}; - -/* Alignment requirements for vring elements. - * When using pre-virtio 1.0 layout, these fall out naturally. - */ -#define VRING_AVAIL_ALIGN_SIZE 2 -#define VRING_USED_ALIGN_SIZE 4 -#define VRING_DESC_ALIGN_SIZE 16 - -/* The standard layout for the ring is a continuous chunk of memory which looks - * like this. We assume num is a power of 2. - * - * struct vring - * { - * // The actual descriptors (16 bytes each) - * struct vring_desc desc[num]; - * - * // A ring of available descriptor heads with free-running index. - * __virtio16 avail_flags; - * __virtio16 avail_idx; - * __virtio16 available[num]; - * __virtio16 used_event_idx; - * - * // Padding to the next align boundary. - * char pad[]; - * - * // A ring of used descriptor heads with free-running index. - * __virtio16 used_flags; - * __virtio16 used_idx; - * struct vring_used_elem used[num]; - * __virtio16 avail_event_idx; - * }; - */ -/* We publish the used event index at the end of the available ring, and vice - * versa. They are at the end for backwards compatibility. */ -#define vring_used_event(vr) ((vr)->avail->ring[(vr)->num]) -#define vring_avail_event(vr) (*(__virtio16 *)&(vr)->used->ring[(vr)->num]) - -static inline void vring_init(struct vring *vr, unsigned int num, void *p, - unsigned long align) -{ - vr->num = num; - vr->desc = p; - vr->avail = p + num*sizeof(struct vring_desc); - vr->used = (void *)(((uintptr_t)&vr->avail->ring[num] + sizeof(__virtio16) - + align-1) & ~(align - 1)); -} - -static inline unsigned vring_size(unsigned int num, unsigned long align) -{ - return ((sizeof(struct vring_desc) * num + sizeof(__virtio16) * (3 + num) - + align - 1) & ~(align - 1)) - + sizeof(__virtio16) * 3 + sizeof(struct vring_used_elem) * num; -} - -/* The following is used with USED_EVENT_IDX and AVAIL_EVENT_IDX */ -/* Assuming a given event_idx value from the other side, if - * we have just incremented index from old to new_idx, - * should we trigger an event? */ -static inline int vring_need_event(__u16 event_idx, __u16 new_idx, __u16 old) -{ - /* Note: Xen has similar logic for notification hold-off - * in include/xen/interface/io/ring.h with req_event and req_prod - * corresponding to event_idx + 1 and new_idx respectively. - * Note also that req_event and req_prod in Xen start at 1, - * event indexes in virtio start at 0. */ - return (__u16)(new_idx - event_idx - 1) < (__u16)(new_idx - old); -} - -#endif /* _UAPI_LINUX_VIRTIO_RING_H */ diff --git a/src/linux/include/uapi/linux/virtio_types.h b/src/linux/include/uapi/linux/virtio_types.h deleted file mode 100644 index e845e8c..0000000 --- a/src/linux/include/uapi/linux/virtio_types.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef _UAPI_LINUX_VIRTIO_TYPES_H -#define _UAPI_LINUX_VIRTIO_TYPES_H -/* Type definitions for virtio implementations. - * - * This header is BSD licensed so anyone can use the definitions to implement - * compatible drivers/servers. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of IBM nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * Copyright (C) 2014 Red Hat, Inc. - * Author: Michael S. Tsirkin - */ -#include - -/* - * __virtio{16,32,64} have the following meaning: - * - __u{16,32,64} for virtio devices in legacy mode, accessed in native endian - * - __le{16,32,64} for standard-compliant virtio devices - */ - -typedef __u16 __bitwise__ __virtio16; -typedef __u32 __bitwise__ __virtio32; -typedef __u64 __bitwise__ __virtio64; - -#endif /* _UAPI_LINUX_VIRTIO_TYPES_H */ diff --git a/src/linux/include/uapi/linux/vt.h b/src/linux/include/uapi/linux/vt.h deleted file mode 100644 index f690348..0000000 --- a/src/linux/include/uapi/linux/vt.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef _UAPI_LINUX_VT_H -#define _UAPI_LINUX_VT_H - - -/* - * These constants are also useful for user-level apps (e.g., VC - * resizing). - */ -#define MIN_NR_CONSOLES 1 /* must be at least 1 */ -#define MAX_NR_CONSOLES 63 /* serial lines start at 64 */ - /* Note: the ioctl VT_GETSTATE does not work for - consoles 16 and higher (since it returns a short) */ - -/* 0x56 is 'V', to avoid collision with termios and kd */ - -#define VT_OPENQRY 0x5600 /* find available vt */ - -struct vt_mode { - char mode; /* vt mode */ - char waitv; /* if set, hang on writes if not active */ - short relsig; /* signal to raise on release req */ - short acqsig; /* signal to raise on acquisition */ - short frsig; /* unused (set to 0) */ -}; -#define VT_GETMODE 0x5601 /* get mode of active vt */ -#define VT_SETMODE 0x5602 /* set mode of active vt */ -#define VT_AUTO 0x00 /* auto vt switching */ -#define VT_PROCESS 0x01 /* process controls switching */ -#define VT_ACKACQ 0x02 /* acknowledge switch */ - -struct vt_stat { - unsigned short v_active; /* active vt */ - unsigned short v_signal; /* signal to send */ - unsigned short v_state; /* vt bitmask */ -}; -#define VT_GETSTATE 0x5603 /* get global vt state info */ -#define VT_SENDSIG 0x5604 /* signal to send to bitmask of vts */ - -#define VT_RELDISP 0x5605 /* release display */ - -#define VT_ACTIVATE 0x5606 /* make vt active */ -#define VT_WAITACTIVE 0x5607 /* wait for vt active */ -#define VT_DISALLOCATE 0x5608 /* free memory associated to vt */ - -struct vt_sizes { - unsigned short v_rows; /* number of rows */ - unsigned short v_cols; /* number of columns */ - unsigned short v_scrollsize; /* number of lines of scrollback */ -}; -#define VT_RESIZE 0x5609 /* set kernel's idea of screensize */ - -struct vt_consize { - unsigned short v_rows; /* number of rows */ - unsigned short v_cols; /* number of columns */ - unsigned short v_vlin; /* number of pixel rows on screen */ - unsigned short v_clin; /* number of pixel rows per character */ - unsigned short v_vcol; /* number of pixel columns on screen */ - unsigned short v_ccol; /* number of pixel columns per character */ -}; -#define VT_RESIZEX 0x560A /* set kernel's idea of screensize + more */ -#define VT_LOCKSWITCH 0x560B /* disallow vt switching */ -#define VT_UNLOCKSWITCH 0x560C /* allow vt switching */ -#define VT_GETHIFONTMASK 0x560D /* return hi font mask */ - -struct vt_event { - unsigned int event; -#define VT_EVENT_SWITCH 0x0001 /* Console switch */ -#define VT_EVENT_BLANK 0x0002 /* Screen blank */ -#define VT_EVENT_UNBLANK 0x0004 /* Screen unblank */ -#define VT_EVENT_RESIZE 0x0008 /* Resize display */ -#define VT_MAX_EVENT 0x000F - unsigned int oldev; /* Old console */ - unsigned int newev; /* New console (if changing) */ - unsigned int pad[4]; /* Padding for expansion */ -}; - -#define VT_WAITEVENT 0x560E /* Wait for an event */ - -struct vt_setactivate { - unsigned int console; - struct vt_mode mode; -}; - -#define VT_SETACTIVATE 0x560F /* Activate and set the mode of a console */ - -#endif /* _UAPI_LINUX_VT_H */ diff --git a/src/linux/include/uapi/linux/wait.h b/src/linux/include/uapi/linux/wait.h deleted file mode 100644 index 9393eea..0000000 --- a/src/linux/include/uapi/linux/wait.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef _UAPI_LINUX_WAIT_H -#define _UAPI_LINUX_WAIT_H - -#define WNOHANG 0x00000001 -#define WUNTRACED 0x00000002 -#define WSTOPPED WUNTRACED -#define WEXITED 0x00000004 -#define WCONTINUED 0x00000008 -#define WNOWAIT 0x01000000 /* Don't reap, just poll status. */ - -#define __WNOTHREAD 0x20000000 /* Don't wait on children of other threads in this group */ -#define __WALL 0x40000000 /* Wait on all children, regardless of type */ -#define __WCLONE 0x80000000 /* Wait only on non-SIGCHLD children */ - -/* First argument to waitid: */ -#define P_ALL 0 -#define P_PID 1 -#define P_PGID 2 - - -#endif /* _UAPI_LINUX_WAIT_H */ diff --git a/src/linux/include/uapi/linux/wireless.h b/src/linux/include/uapi/linux/wireless.h deleted file mode 100644 index d9ecd7c..0000000 --- a/src/linux/include/uapi/linux/wireless.h +++ /dev/null @@ -1,1109 +0,0 @@ -/* - * This file define a set of standard wireless extensions - * - * Version : 22 16.3.07 - * - * Authors : Jean Tourrilhes - HPL - - * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved. - */ - -#ifndef _UAPI_LINUX_WIRELESS_H -#define _UAPI_LINUX_WIRELESS_H - -/************************** DOCUMENTATION **************************/ -/* - * Initial APIs (1996 -> onward) : - * ----------------------------- - * Basically, the wireless extensions are for now a set of standard ioctl - * call + /proc/net/wireless - * - * The entry /proc/net/wireless give statistics and information on the - * driver. - * This is better than having each driver having its entry because - * its centralised and we may remove the driver module safely. - * - * Ioctl are used to configure the driver and issue commands. This is - * better than command line options of insmod because we may want to - * change dynamically (while the driver is running) some parameters. - * - * The ioctl mechanimsm are copied from standard devices ioctl. - * We have the list of command plus a structure descibing the - * data exchanged... - * Note that to add these ioctl, I was obliged to modify : - * # net/core/dev.c (two place + add include) - * # net/ipv4/af_inet.c (one place + add include) - * - * /proc/net/wireless is a copy of /proc/net/dev. - * We have a structure for data passed from the driver to /proc/net/wireless - * Too add this, I've modified : - * # net/core/dev.c (two other places) - * # include/linux/netdevice.h (one place) - * # include/linux/proc_fs.h (one place) - * - * New driver API (2002 -> onward) : - * ------------------------------- - * This file is only concerned with the user space API and common definitions. - * The new driver API is defined and documented in : - * # include/net/iw_handler.h - * - * Note as well that /proc/net/wireless implementation has now moved in : - * # net/core/wireless.c - * - * Wireless Events (2002 -> onward) : - * -------------------------------- - * Events are defined at the end of this file, and implemented in : - * # net/core/wireless.c - * - * Other comments : - * -------------- - * Do not add here things that are redundant with other mechanisms - * (drivers init, ifconfig, /proc/net/dev, ...) and with are not - * wireless specific. - * - * These wireless extensions are not magic : each driver has to provide - * support for them... - * - * IMPORTANT NOTE : As everything in the kernel, this is very much a - * work in progress. Contact me if you have ideas of improvements... - */ - -/***************************** INCLUDES *****************************/ - -#include /* for __u* and __s* typedefs */ -#include /* for "struct sockaddr" et al */ -#include /* for IFNAMSIZ and co... */ - -/***************************** VERSION *****************************/ -/* - * This constant is used to know the availability of the wireless - * extensions and to know which version of wireless extensions it is - * (there is some stuff that will be added in the future...) - * I just plan to increment with each new version. - */ -#define WIRELESS_EXT 22 - -/* - * Changes : - * - * V2 to V3 - * -------- - * Alan Cox start some incompatibles changes. I've integrated a bit more. - * - Encryption renamed to Encode to avoid US regulation problems - * - Frequency changed from float to struct to avoid problems on old 386 - * - * V3 to V4 - * -------- - * - Add sensitivity - * - * V4 to V5 - * -------- - * - Missing encoding definitions in range - * - Access points stuff - * - * V5 to V6 - * -------- - * - 802.11 support (ESSID ioctls) - * - * V6 to V7 - * -------- - * - define IW_ESSID_MAX_SIZE and IW_MAX_AP - * - * V7 to V8 - * -------- - * - Changed my e-mail address - * - More 802.11 support (nickname, rate, rts, frag) - * - List index in frequencies - * - * V8 to V9 - * -------- - * - Support for 'mode of operation' (ad-hoc, managed...) - * - Support for unicast and multicast power saving - * - Change encoding to support larger tokens (>64 bits) - * - Updated iw_params (disable, flags) and use it for NWID - * - Extracted iw_point from iwreq for clarity - * - * V9 to V10 - * --------- - * - Add PM capability to range structure - * - Add PM modifier : MAX/MIN/RELATIVE - * - Add encoding option : IW_ENCODE_NOKEY - * - Add TxPower ioctls (work like TxRate) - * - * V10 to V11 - * ---------- - * - Add WE version in range (help backward/forward compatibility) - * - Add retry ioctls (work like PM) - * - * V11 to V12 - * ---------- - * - Add SIOCSIWSTATS to get /proc/net/wireless programatically - * - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space - * - Add new statistics (frag, retry, beacon) - * - Add average quality (for user space calibration) - * - * V12 to V13 - * ---------- - * - Document creation of new driver API. - * - Extract union iwreq_data from struct iwreq (for new driver API). - * - Rename SIOCSIWNAME as SIOCSIWCOMMIT - * - * V13 to V14 - * ---------- - * - Wireless Events support : define struct iw_event - * - Define additional specific event numbers - * - Add "addr" and "param" fields in union iwreq_data - * - AP scanning stuff (SIOCSIWSCAN and friends) - * - * V14 to V15 - * ---------- - * - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg - * - Make struct iw_freq signed (both m & e), add explicit padding - * - Add IWEVCUSTOM for driver specific event/scanning token - * - Add IW_MAX_GET_SPY for driver returning a lot of addresses - * - Add IW_TXPOW_RANGE for range of Tx Powers - * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points - * - Add IW_MODE_MONITOR for passive monitor - * - * V15 to V16 - * ---------- - * - Increase the number of bitrates in iw_range to 32 (for 802.11g) - * - Increase the number of frequencies in iw_range to 32 (for 802.11b+a) - * - Reshuffle struct iw_range for increases, add filler - * - Increase IW_MAX_AP to 64 for driver returning a lot of addresses - * - Remove IW_MAX_GET_SPY because conflict with enhanced spy support - * - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy" - * - Add IW_ENCODE_TEMP and iw_range->encoding_login_index - * - * V16 to V17 - * ---------- - * - Add flags to frequency -> auto/fixed - * - Document (struct iw_quality *)->updated, add new flags (INVALID) - * - Wireless Event capability in struct iw_range - * - Add support for relative TxPower (yick !) - * - * V17 to V18 (From Jouni Malinen ) - * ---------- - * - Add support for WPA/WPA2 - * - Add extended encoding configuration (SIOCSIWENCODEEXT and - * SIOCGIWENCODEEXT) - * - Add SIOCSIWGENIE/SIOCGIWGENIE - * - Add SIOCSIWMLME - * - Add SIOCSIWPMKSA - * - Add struct iw_range bit field for supported encoding capabilities - * - Add optional scan request parameters for SIOCSIWSCAN - * - Add SIOCSIWAUTH/SIOCGIWAUTH for setting authentication and WPA - * related parameters (extensible up to 4096 parameter values) - * - Add wireless events: IWEVGENIE, IWEVMICHAELMICFAILURE, - * IWEVASSOCREQIE, IWEVASSOCRESPIE, IWEVPMKIDCAND - * - * V18 to V19 - * ---------- - * - Remove (struct iw_point *)->pointer from events and streams - * - Remove header includes to help user space - * - Increase IW_ENCODING_TOKEN_MAX from 32 to 64 - * - Add IW_QUAL_ALL_UPDATED and IW_QUAL_ALL_INVALID macros - * - Add explicit flag to tell stats are in dBm : IW_QUAL_DBM - * - Add IW_IOCTL_IDX() and IW_EVENT_IDX() macros - * - * V19 to V20 - * ---------- - * - RtNetlink requests support (SET/GET) - * - * V20 to V21 - * ---------- - * - Remove (struct net_device *)->get_wireless_stats() - * - Change length in ESSID and NICK to strlen() instead of strlen()+1 - * - Add IW_RETRY_SHORT/IW_RETRY_LONG retry modifiers - * - Power/Retry relative values no longer * 100000 - * - Add explicit flag to tell stats are in 802.11k RCPI : IW_QUAL_RCPI - * - * V21 to V22 - * ---------- - * - Prevent leaking of kernel space in stream on 64 bits. - */ - -/**************************** CONSTANTS ****************************/ - -/* -------------------------- IOCTL LIST -------------------------- */ - -/* Wireless Identification */ -#define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */ -#define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */ -/* SIOCGIWNAME is used to verify the presence of Wireless Extensions. - * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"... - * Don't put the name of your driver there, it's useless. */ - -/* Basic operations */ -#define SIOCSIWNWID 0x8B02 /* set network id (pre-802.11) */ -#define SIOCGIWNWID 0x8B03 /* get network id (the cell) */ -#define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */ -#define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */ -#define SIOCSIWMODE 0x8B06 /* set operation mode */ -#define SIOCGIWMODE 0x8B07 /* get operation mode */ -#define SIOCSIWSENS 0x8B08 /* set sensitivity (dBm) */ -#define SIOCGIWSENS 0x8B09 /* get sensitivity (dBm) */ - -/* Informative stuff */ -#define SIOCSIWRANGE 0x8B0A /* Unused */ -#define SIOCGIWRANGE 0x8B0B /* Get range of parameters */ -#define SIOCSIWPRIV 0x8B0C /* Unused */ -#define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */ -#define SIOCSIWSTATS 0x8B0E /* Unused */ -#define SIOCGIWSTATS 0x8B0F /* Get /proc/net/wireless stats */ -/* SIOCGIWSTATS is strictly used between user space and the kernel, and - * is never passed to the driver (i.e. the driver will never see it). */ - -/* Spy support (statistics per MAC address - used for Mobile IP support) */ -#define SIOCSIWSPY 0x8B10 /* set spy addresses */ -#define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */ -#define SIOCSIWTHRSPY 0x8B12 /* set spy threshold (spy event) */ -#define SIOCGIWTHRSPY 0x8B13 /* get spy threshold */ - -/* Access Point manipulation */ -#define SIOCSIWAP 0x8B14 /* set access point MAC addresses */ -#define SIOCGIWAP 0x8B15 /* get access point MAC addresses */ -#define SIOCGIWAPLIST 0x8B17 /* Deprecated in favor of scanning */ -#define SIOCSIWSCAN 0x8B18 /* trigger scanning (list cells) */ -#define SIOCGIWSCAN 0x8B19 /* get scanning results */ - -/* 802.11 specific support */ -#define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */ -#define SIOCGIWESSID 0x8B1B /* get ESSID */ -#define SIOCSIWNICKN 0x8B1C /* set node name/nickname */ -#define SIOCGIWNICKN 0x8B1D /* get node name/nickname */ -/* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit - * within the 'iwreq' structure, so we need to use the 'data' member to - * point to a string in user space, like it is done for RANGE... */ - -/* Other parameters useful in 802.11 and some other devices */ -#define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */ -#define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */ -#define SIOCSIWRTS 0x8B22 /* set RTS/CTS threshold (bytes) */ -#define SIOCGIWRTS 0x8B23 /* get RTS/CTS threshold (bytes) */ -#define SIOCSIWFRAG 0x8B24 /* set fragmentation thr (bytes) */ -#define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */ -#define SIOCSIWTXPOW 0x8B26 /* set transmit power (dBm) */ -#define SIOCGIWTXPOW 0x8B27 /* get transmit power (dBm) */ -#define SIOCSIWRETRY 0x8B28 /* set retry limits and lifetime */ -#define SIOCGIWRETRY 0x8B29 /* get retry limits and lifetime */ - -/* Encoding stuff (scrambling, hardware security, WEP...) */ -#define SIOCSIWENCODE 0x8B2A /* set encoding token & mode */ -#define SIOCGIWENCODE 0x8B2B /* get encoding token & mode */ -/* Power saving stuff (power management, unicast and multicast) */ -#define SIOCSIWPOWER 0x8B2C /* set Power Management settings */ -#define SIOCGIWPOWER 0x8B2D /* get Power Management settings */ - -/* WPA : Generic IEEE 802.11 informatiom element (e.g., for WPA/RSN/WMM). - * This ioctl uses struct iw_point and data buffer that includes IE id and len - * fields. More than one IE may be included in the request. Setting the generic - * IE to empty buffer (len=0) removes the generic IE from the driver. Drivers - * are allowed to generate their own WPA/RSN IEs, but in these cases, drivers - * are required to report the used IE as a wireless event, e.g., when - * associating with an AP. */ -#define SIOCSIWGENIE 0x8B30 /* set generic IE */ -#define SIOCGIWGENIE 0x8B31 /* get generic IE */ - -/* WPA : IEEE 802.11 MLME requests */ -#define SIOCSIWMLME 0x8B16 /* request MLME operation; uses - * struct iw_mlme */ -/* WPA : Authentication mode parameters */ -#define SIOCSIWAUTH 0x8B32 /* set authentication mode params */ -#define SIOCGIWAUTH 0x8B33 /* get authentication mode params */ - -/* WPA : Extended version of encoding configuration */ -#define SIOCSIWENCODEEXT 0x8B34 /* set encoding token & mode */ -#define SIOCGIWENCODEEXT 0x8B35 /* get encoding token & mode */ - -/* WPA2 : PMKSA cache management */ -#define SIOCSIWPMKSA 0x8B36 /* PMKSA cache operation */ - -/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */ - -/* These 32 ioctl are wireless device private, for 16 commands. - * Each driver is free to use them for whatever purpose it chooses, - * however the driver *must* export the description of those ioctls - * with SIOCGIWPRIV and *must* use arguments as defined below. - * If you don't follow those rules, DaveM is going to hate you (reason : - * it make mixed 32/64bit operation impossible). - */ -#define SIOCIWFIRSTPRIV 0x8BE0 -#define SIOCIWLASTPRIV 0x8BFF -/* Previously, we were using SIOCDEVPRIVATE, but we now have our - * separate range because of collisions with other tools such as - * 'mii-tool'. - * We now have 32 commands, so a bit more space ;-). - * Also, all 'even' commands are only usable by root and don't return the - * content of ifr/iwr to user (but you are not obliged to use the set/get - * convention, just use every other two command). More details in iwpriv.c. - * And I repeat : you are not forced to use them with iwpriv, but you - * must be compliant with it. - */ - -/* ------------------------- IOCTL STUFF ------------------------- */ - -/* The first and the last (range) */ -#define SIOCIWFIRST 0x8B00 -#define SIOCIWLAST SIOCIWLASTPRIV /* 0x8BFF */ -#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST) -#define IW_HANDLER(id, func) \ - [IW_IOCTL_IDX(id)] = func - -/* Odd : get (world access), even : set (root access) */ -#define IW_IS_SET(cmd) (!((cmd) & 0x1)) -#define IW_IS_GET(cmd) ((cmd) & 0x1) - -/* ----------------------- WIRELESS EVENTS ----------------------- */ -/* Those are *NOT* ioctls, do not issue request on them !!! */ -/* Most events use the same identifier as ioctl requests */ - -#define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */ -#define IWEVQUAL 0x8C01 /* Quality part of statistics (scan) */ -#define IWEVCUSTOM 0x8C02 /* Driver specific ascii string */ -#define IWEVREGISTERED 0x8C03 /* Discovered a new node (AP mode) */ -#define IWEVEXPIRED 0x8C04 /* Expired a node (AP mode) */ -#define IWEVGENIE 0x8C05 /* Generic IE (WPA, RSN, WMM, ..) - * (scan results); This includes id and - * length fields. One IWEVGENIE may - * contain more than one IE. Scan - * results may contain one or more - * IWEVGENIE events. */ -#define IWEVMICHAELMICFAILURE 0x8C06 /* Michael MIC failure - * (struct iw_michaelmicfailure) - */ -#define IWEVASSOCREQIE 0x8C07 /* IEs used in (Re)Association Request. - * The data includes id and length - * fields and may contain more than one - * IE. This event is required in - * Managed mode if the driver - * generates its own WPA/RSN IE. This - * should be sent just before - * IWEVREGISTERED event for the - * association. */ -#define IWEVASSOCRESPIE 0x8C08 /* IEs used in (Re)Association - * Response. The data includes id and - * length fields and may contain more - * than one IE. This may be sent - * between IWEVASSOCREQIE and - * IWEVREGISTERED events for the - * association. */ -#define IWEVPMKIDCAND 0x8C09 /* PMKID candidate for RSN - * pre-authentication - * (struct iw_pmkid_cand) */ - -#define IWEVFIRST 0x8C00 -#define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST) - -/* ------------------------- PRIVATE INFO ------------------------- */ -/* - * The following is used with SIOCGIWPRIV. It allow a driver to define - * the interface (name, type of data) for its private ioctl. - * Privates ioctl are SIOCIWFIRSTPRIV -> SIOCIWLASTPRIV - */ - -#define IW_PRIV_TYPE_MASK 0x7000 /* Type of arguments */ -#define IW_PRIV_TYPE_NONE 0x0000 -#define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */ -#define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */ -#define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */ -#define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */ -#define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */ - -#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed number of args */ - -#define IW_PRIV_SIZE_MASK 0x07FF /* Max number of those args */ - -/* - * Note : if the number of args is fixed and the size < 16 octets, - * instead of passing a pointer we will put args in the iwreq struct... - */ - -/* ----------------------- OTHER CONSTANTS ----------------------- */ - -/* Maximum frequencies in the range struct */ -#define IW_MAX_FREQUENCIES 32 -/* Note : if you have something like 80 frequencies, - * don't increase this constant and don't fill the frequency list. - * The user will be able to set by channel anyway... */ - -/* Maximum bit rates in the range struct */ -#define IW_MAX_BITRATES 32 - -/* Maximum tx powers in the range struct */ -#define IW_MAX_TXPOWER 8 -/* Note : if you more than 8 TXPowers, just set the max and min or - * a few of them in the struct iw_range. */ - -/* Maximum of address that you may set with SPY */ -#define IW_MAX_SPY 8 - -/* Maximum of address that you may get in the - list of access points in range */ -#define IW_MAX_AP 64 - -/* Maximum size of the ESSID and NICKN strings */ -#define IW_ESSID_MAX_SIZE 32 - -/* Modes of operation */ -#define IW_MODE_AUTO 0 /* Let the driver decides */ -#define IW_MODE_ADHOC 1 /* Single cell network */ -#define IW_MODE_INFRA 2 /* Multi cell network, roaming, ... */ -#define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */ -#define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */ -#define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */ -#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */ -#define IW_MODE_MESH 7 /* Mesh (IEEE 802.11s) network */ - -/* Statistics flags (bitmask in updated) */ -#define IW_QUAL_QUAL_UPDATED 0x01 /* Value was updated since last read */ -#define IW_QUAL_LEVEL_UPDATED 0x02 -#define IW_QUAL_NOISE_UPDATED 0x04 -#define IW_QUAL_ALL_UPDATED 0x07 -#define IW_QUAL_DBM 0x08 /* Level + Noise are dBm */ -#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */ -#define IW_QUAL_LEVEL_INVALID 0x20 -#define IW_QUAL_NOISE_INVALID 0x40 -#define IW_QUAL_RCPI 0x80 /* Level + Noise are 802.11k RCPI */ -#define IW_QUAL_ALL_INVALID 0x70 - -/* Frequency flags */ -#define IW_FREQ_AUTO 0x00 /* Let the driver decides */ -#define IW_FREQ_FIXED 0x01 /* Force a specific value */ - -/* Maximum number of size of encoding token available - * they are listed in the range structure */ -#define IW_MAX_ENCODING_SIZES 8 - -/* Maximum size of the encoding token in bytes */ -#define IW_ENCODING_TOKEN_MAX 64 /* 512 bits (for now) */ - -/* Flags for encoding (along with the token) */ -#define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */ -#define IW_ENCODE_FLAGS 0xFF00 /* Flags defined below */ -#define IW_ENCODE_MODE 0xF000 /* Modes defined below */ -#define IW_ENCODE_DISABLED 0x8000 /* Encoding disabled */ -#define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */ -#define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */ -#define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */ -#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */ -#define IW_ENCODE_TEMP 0x0400 /* Temporary key */ - -/* Power management flags available (along with the value, if any) */ -#define IW_POWER_ON 0x0000 /* No details... */ -#define IW_POWER_TYPE 0xF000 /* Type of parameter */ -#define IW_POWER_PERIOD 0x1000 /* Value is a period/duration of */ -#define IW_POWER_TIMEOUT 0x2000 /* Value is a timeout (to go asleep) */ -#define IW_POWER_MODE 0x0F00 /* Power Management mode */ -#define IW_POWER_UNICAST_R 0x0100 /* Receive only unicast messages */ -#define IW_POWER_MULTICAST_R 0x0200 /* Receive only multicast messages */ -#define IW_POWER_ALL_R 0x0300 /* Receive all messages though PM */ -#define IW_POWER_FORCE_S 0x0400 /* Force PM procedure for sending unicast */ -#define IW_POWER_REPEATER 0x0800 /* Repeat broadcast messages in PM period */ -#define IW_POWER_MODIFIER 0x000F /* Modify a parameter */ -#define IW_POWER_MIN 0x0001 /* Value is a minimum */ -#define IW_POWER_MAX 0x0002 /* Value is a maximum */ -#define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ - -/* Transmit Power flags available */ -#define IW_TXPOW_TYPE 0x00FF /* Type of value */ -#define IW_TXPOW_DBM 0x0000 /* Value is in dBm */ -#define IW_TXPOW_MWATT 0x0001 /* Value is in mW */ -#define IW_TXPOW_RELATIVE 0x0002 /* Value is in arbitrary units */ -#define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */ - -/* Retry limits and lifetime flags available */ -#define IW_RETRY_ON 0x0000 /* No details... */ -#define IW_RETRY_TYPE 0xF000 /* Type of parameter */ -#define IW_RETRY_LIMIT 0x1000 /* Maximum number of retries*/ -#define IW_RETRY_LIFETIME 0x2000 /* Maximum duration of retries in us */ -#define IW_RETRY_MODIFIER 0x00FF /* Modify a parameter */ -#define IW_RETRY_MIN 0x0001 /* Value is a minimum */ -#define IW_RETRY_MAX 0x0002 /* Value is a maximum */ -#define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */ -#define IW_RETRY_SHORT 0x0010 /* Value is for short packets */ -#define IW_RETRY_LONG 0x0020 /* Value is for long packets */ - -/* Scanning request flags */ -#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */ -#define IW_SCAN_ALL_ESSID 0x0001 /* Scan all ESSIDs */ -#define IW_SCAN_THIS_ESSID 0x0002 /* Scan only this ESSID */ -#define IW_SCAN_ALL_FREQ 0x0004 /* Scan all Frequencies */ -#define IW_SCAN_THIS_FREQ 0x0008 /* Scan only this Frequency */ -#define IW_SCAN_ALL_MODE 0x0010 /* Scan all Modes */ -#define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */ -#define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */ -#define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */ -/* struct iw_scan_req scan_type */ -#define IW_SCAN_TYPE_ACTIVE 0 -#define IW_SCAN_TYPE_PASSIVE 1 -/* Maximum size of returned data */ -#define IW_SCAN_MAX_DATA 4096 /* In bytes */ - -/* Scan capability flags - in (struct iw_range *)->scan_capa */ -#define IW_SCAN_CAPA_NONE 0x00 -#define IW_SCAN_CAPA_ESSID 0x01 -#define IW_SCAN_CAPA_BSSID 0x02 -#define IW_SCAN_CAPA_CHANNEL 0x04 -#define IW_SCAN_CAPA_MODE 0x08 -#define IW_SCAN_CAPA_RATE 0x10 -#define IW_SCAN_CAPA_TYPE 0x20 -#define IW_SCAN_CAPA_TIME 0x40 - -/* Max number of char in custom event - use multiple of them if needed */ -#define IW_CUSTOM_MAX 256 /* In bytes */ - -/* Generic information element */ -#define IW_GENERIC_IE_MAX 1024 - -/* MLME requests (SIOCSIWMLME / struct iw_mlme) */ -#define IW_MLME_DEAUTH 0 -#define IW_MLME_DISASSOC 1 -#define IW_MLME_AUTH 2 -#define IW_MLME_ASSOC 3 - -/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */ -#define IW_AUTH_INDEX 0x0FFF -#define IW_AUTH_FLAGS 0xF000 -/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095) - * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the - * parameter that is being set/get to; value will be read/written to - * struct iw_param value field) */ -#define IW_AUTH_WPA_VERSION 0 -#define IW_AUTH_CIPHER_PAIRWISE 1 -#define IW_AUTH_CIPHER_GROUP 2 -#define IW_AUTH_KEY_MGMT 3 -#define IW_AUTH_TKIP_COUNTERMEASURES 4 -#define IW_AUTH_DROP_UNENCRYPTED 5 -#define IW_AUTH_80211_AUTH_ALG 6 -#define IW_AUTH_WPA_ENABLED 7 -#define IW_AUTH_RX_UNENCRYPTED_EAPOL 8 -#define IW_AUTH_ROAMING_CONTROL 9 -#define IW_AUTH_PRIVACY_INVOKED 10 -#define IW_AUTH_CIPHER_GROUP_MGMT 11 -#define IW_AUTH_MFP 12 - -/* IW_AUTH_WPA_VERSION values (bit field) */ -#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001 -#define IW_AUTH_WPA_VERSION_WPA 0x00000002 -#define IW_AUTH_WPA_VERSION_WPA2 0x00000004 - -/* IW_AUTH_PAIRWISE_CIPHER, IW_AUTH_GROUP_CIPHER, and IW_AUTH_CIPHER_GROUP_MGMT - * values (bit field) */ -#define IW_AUTH_CIPHER_NONE 0x00000001 -#define IW_AUTH_CIPHER_WEP40 0x00000002 -#define IW_AUTH_CIPHER_TKIP 0x00000004 -#define IW_AUTH_CIPHER_CCMP 0x00000008 -#define IW_AUTH_CIPHER_WEP104 0x00000010 -#define IW_AUTH_CIPHER_AES_CMAC 0x00000020 - -/* IW_AUTH_KEY_MGMT values (bit field) */ -#define IW_AUTH_KEY_MGMT_802_1X 1 -#define IW_AUTH_KEY_MGMT_PSK 2 - -/* IW_AUTH_80211_AUTH_ALG values (bit field) */ -#define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001 -#define IW_AUTH_ALG_SHARED_KEY 0x00000002 -#define IW_AUTH_ALG_LEAP 0x00000004 - -/* IW_AUTH_ROAMING_CONTROL values */ -#define IW_AUTH_ROAMING_ENABLE 0 /* driver/firmware based roaming */ -#define IW_AUTH_ROAMING_DISABLE 1 /* user space program used for roaming - * control */ - -/* IW_AUTH_MFP (management frame protection) values */ -#define IW_AUTH_MFP_DISABLED 0 /* MFP disabled */ -#define IW_AUTH_MFP_OPTIONAL 1 /* MFP optional */ -#define IW_AUTH_MFP_REQUIRED 2 /* MFP required */ - -/* SIOCSIWENCODEEXT definitions */ -#define IW_ENCODE_SEQ_MAX_SIZE 8 -/* struct iw_encode_ext ->alg */ -#define IW_ENCODE_ALG_NONE 0 -#define IW_ENCODE_ALG_WEP 1 -#define IW_ENCODE_ALG_TKIP 2 -#define IW_ENCODE_ALG_CCMP 3 -#define IW_ENCODE_ALG_PMK 4 -#define IW_ENCODE_ALG_AES_CMAC 5 -/* struct iw_encode_ext ->ext_flags */ -#define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001 -#define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002 -#define IW_ENCODE_EXT_GROUP_KEY 0x00000004 -#define IW_ENCODE_EXT_SET_TX_KEY 0x00000008 - -/* IWEVMICHAELMICFAILURE : struct iw_michaelmicfailure ->flags */ -#define IW_MICFAILURE_KEY_ID 0x00000003 /* Key ID 0..3 */ -#define IW_MICFAILURE_GROUP 0x00000004 -#define IW_MICFAILURE_PAIRWISE 0x00000008 -#define IW_MICFAILURE_STAKEY 0x00000010 -#define IW_MICFAILURE_COUNT 0x00000060 /* 1 or 2 (0 = count not supported) - */ - -/* Bit field values for enc_capa in struct iw_range */ -#define IW_ENC_CAPA_WPA 0x00000001 -#define IW_ENC_CAPA_WPA2 0x00000002 -#define IW_ENC_CAPA_CIPHER_TKIP 0x00000004 -#define IW_ENC_CAPA_CIPHER_CCMP 0x00000008 -#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010 - -/* Event capability macros - in (struct iw_range *)->event_capa - * Because we have more than 32 possible events, we use an array of - * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */ -#define IW_EVENT_CAPA_BASE(cmd) ((cmd >= SIOCIWFIRSTPRIV) ? \ - (cmd - SIOCIWFIRSTPRIV + 0x60) : \ - (cmd - SIOCIWFIRST)) -#define IW_EVENT_CAPA_INDEX(cmd) (IW_EVENT_CAPA_BASE(cmd) >> 5) -#define IW_EVENT_CAPA_MASK(cmd) (1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F)) -/* Event capability constants - event autogenerated by the kernel - * This list is valid for most 802.11 devices, customise as needed... */ -#define IW_EVENT_CAPA_K_0 (IW_EVENT_CAPA_MASK(0x8B04) | \ - IW_EVENT_CAPA_MASK(0x8B06) | \ - IW_EVENT_CAPA_MASK(0x8B1A)) -#define IW_EVENT_CAPA_K_1 (IW_EVENT_CAPA_MASK(0x8B2A)) -/* "Easy" macro to set events in iw_range (less efficient) */ -#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd)) -#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; } - - -/****************************** TYPES ******************************/ - -/* --------------------------- SUBTYPES --------------------------- */ -/* - * Generic format for most parameters that fit in an int - */ -struct iw_param { - __s32 value; /* The value of the parameter itself */ - __u8 fixed; /* Hardware should not use auto select */ - __u8 disabled; /* Disable the feature */ - __u16 flags; /* Various specifc flags (if any) */ -}; - -/* - * For all data larger than 16 octets, we need to use a - * pointer to memory allocated in user space. - */ -struct iw_point { - void __user *pointer; /* Pointer to the data (in user space) */ - __u16 length; /* number of fields or size in bytes */ - __u16 flags; /* Optional params */ -}; - - -/* - * A frequency - * For numbers lower than 10^9, we encode the number in 'm' and - * set 'e' to 0 - * For number greater than 10^9, we divide it by the lowest power - * of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')... - * The power of 10 is in 'e', the result of the division is in 'm'. - */ -struct iw_freq { - __s32 m; /* Mantissa */ - __s16 e; /* Exponent */ - __u8 i; /* List index (when in range struct) */ - __u8 flags; /* Flags (fixed/auto) */ -}; - -/* - * Quality of the link - */ -struct iw_quality { - __u8 qual; /* link quality (%retries, SNR, - %missed beacons or better...) */ - __u8 level; /* signal level (dBm) */ - __u8 noise; /* noise level (dBm) */ - __u8 updated; /* Flags to know if updated */ -}; - -/* - * Packet discarded in the wireless adapter due to - * "wireless" specific problems... - * Note : the list of counter and statistics in net_device_stats - * is already pretty exhaustive, and you should use that first. - * This is only additional stats... - */ -struct iw_discarded { - __u32 nwid; /* Rx : Wrong nwid/essid */ - __u32 code; /* Rx : Unable to code/decode (WEP) */ - __u32 fragment; /* Rx : Can't perform MAC reassembly */ - __u32 retries; /* Tx : Max MAC retries num reached */ - __u32 misc; /* Others cases */ -}; - -/* - * Packet/Time period missed in the wireless adapter due to - * "wireless" specific problems... - */ -struct iw_missed { - __u32 beacon; /* Missed beacons/superframe */ -}; - -/* - * Quality range (for spy threshold) - */ -struct iw_thrspy { - struct sockaddr addr; /* Source address (hw/mac) */ - struct iw_quality qual; /* Quality of the link */ - struct iw_quality low; /* Low threshold */ - struct iw_quality high; /* High threshold */ -}; - -/* - * Optional data for scan request - * - * Note: these optional parameters are controlling parameters for the - * scanning behavior, these do not apply to getting scan results - * (SIOCGIWSCAN). Drivers are expected to keep a local BSS table and - * provide a merged results with all BSSes even if the previous scan - * request limited scanning to a subset, e.g., by specifying an SSID. - * Especially, scan results are required to include an entry for the - * current BSS if the driver is in Managed mode and associated with an AP. - */ -struct iw_scan_req { - __u8 scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} */ - __u8 essid_len; - __u8 num_channels; /* num entries in channel_list; - * 0 = scan all allowed channels */ - __u8 flags; /* reserved as padding; use zero, this may - * be used in the future for adding flags - * to request different scan behavior */ - struct sockaddr bssid; /* ff:ff:ff:ff:ff:ff for broadcast BSSID or - * individual address of a specific BSS */ - - /* - * Use this ESSID if IW_SCAN_THIS_ESSID flag is used instead of using - * the current ESSID. This allows scan requests for specific ESSID - * without having to change the current ESSID and potentially breaking - * the current association. - */ - __u8 essid[IW_ESSID_MAX_SIZE]; - - /* - * Optional parameters for changing the default scanning behavior. - * These are based on the MLME-SCAN.request from IEEE Std 802.11. - * TU is 1.024 ms. If these are set to 0, driver is expected to use - * reasonable default values. min_channel_time defines the time that - * will be used to wait for the first reply on each channel. If no - * replies are received, next channel will be scanned after this. If - * replies are received, total time waited on the channel is defined by - * max_channel_time. - */ - __u32 min_channel_time; /* in TU */ - __u32 max_channel_time; /* in TU */ - - struct iw_freq channel_list[IW_MAX_FREQUENCIES]; -}; - -/* ------------------------- WPA SUPPORT ------------------------- */ - -/* - * Extended data structure for get/set encoding (this is used with - * SIOCSIWENCODEEXT/SIOCGIWENCODEEXT. struct iw_point and IW_ENCODE_* - * flags are used in the same way as with SIOCSIWENCODE/SIOCGIWENCODE and - * only the data contents changes (key data -> this structure, including - * key data). - * - * If the new key is the first group key, it will be set as the default - * TX key. Otherwise, default TX key index is only changed if - * IW_ENCODE_EXT_SET_TX_KEY flag is set. - * - * Key will be changed with SIOCSIWENCODEEXT in all cases except for - * special "change TX key index" operation which is indicated by setting - * key_len = 0 and ext_flags |= IW_ENCODE_EXT_SET_TX_KEY. - * - * tx_seq/rx_seq are only used when respective - * IW_ENCODE_EXT_{TX,RX}_SEQ_VALID flag is set in ext_flags. Normal - * TKIP/CCMP operation is to set RX seq with SIOCSIWENCODEEXT and start - * TX seq from zero whenever key is changed. SIOCGIWENCODEEXT is normally - * used only by an Authenticator (AP or an IBSS station) to get the - * current TX sequence number. Using TX_SEQ_VALID for SIOCSIWENCODEEXT and - * RX_SEQ_VALID for SIOCGIWENCODEEXT are optional, but can be useful for - * debugging/testing. - */ -struct iw_encode_ext { - __u32 ext_flags; /* IW_ENCODE_EXT_* */ - __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ - __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ - struct sockaddr addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast - * (group) keys or unicast address for - * individual keys */ - __u16 alg; /* IW_ENCODE_ALG_* */ - __u16 key_len; - __u8 key[0]; -}; - -/* SIOCSIWMLME data */ -struct iw_mlme { - __u16 cmd; /* IW_MLME_* */ - __u16 reason_code; - struct sockaddr addr; -}; - -/* SIOCSIWPMKSA data */ -#define IW_PMKSA_ADD 1 -#define IW_PMKSA_REMOVE 2 -#define IW_PMKSA_FLUSH 3 - -#define IW_PMKID_LEN 16 - -struct iw_pmksa { - __u32 cmd; /* IW_PMKSA_* */ - struct sockaddr bssid; - __u8 pmkid[IW_PMKID_LEN]; -}; - -/* IWEVMICHAELMICFAILURE data */ -struct iw_michaelmicfailure { - __u32 flags; - struct sockaddr src_addr; - __u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */ -}; - -/* IWEVPMKIDCAND data */ -#define IW_PMKID_CAND_PREAUTH 0x00000001 /* RNS pre-authentication enabled */ -struct iw_pmkid_cand { - __u32 flags; /* IW_PMKID_CAND_* */ - __u32 index; /* the smaller the index, the higher the - * priority */ - struct sockaddr bssid; -}; - -/* ------------------------ WIRELESS STATS ------------------------ */ -/* - * Wireless statistics (used for /proc/net/wireless) - */ -struct iw_statistics { - __u16 status; /* Status - * - device dependent for now */ - - struct iw_quality qual; /* Quality of the link - * (instant/mean/max) */ - struct iw_discarded discard; /* Packet discarded counts */ - struct iw_missed miss; /* Packet missed counts */ -}; - -/* ------------------------ IOCTL REQUEST ------------------------ */ -/* - * This structure defines the payload of an ioctl, and is used - * below. - * - * Note that this structure should fit on the memory footprint - * of iwreq (which is the same as ifreq), which mean a max size of - * 16 octets = 128 bits. Warning, pointers might be 64 bits wide... - * You should check this when increasing the structures defined - * above in this file... - */ -union iwreq_data { - /* Config - generic */ - char name[IFNAMSIZ]; - /* Name : used to verify the presence of wireless extensions. - * Name of the protocol/provider... */ - - struct iw_point essid; /* Extended network name */ - struct iw_param nwid; /* network id (or domain - the cell) */ - struct iw_freq freq; /* frequency or channel : - * 0-1000 = channel - * > 1000 = frequency in Hz */ - - struct iw_param sens; /* signal level threshold */ - struct iw_param bitrate; /* default bit rate */ - struct iw_param txpower; /* default transmit power */ - struct iw_param rts; /* RTS threshold threshold */ - struct iw_param frag; /* Fragmentation threshold */ - __u32 mode; /* Operation mode */ - struct iw_param retry; /* Retry limits & lifetime */ - - struct iw_point encoding; /* Encoding stuff : tokens */ - struct iw_param power; /* PM duration/timeout */ - struct iw_quality qual; /* Quality part of statistics */ - - struct sockaddr ap_addr; /* Access point address */ - struct sockaddr addr; /* Destination address (hw/mac) */ - - struct iw_param param; /* Other small parameters */ - struct iw_point data; /* Other large parameters */ -}; - -/* - * The structure to exchange data for ioctl. - * This structure is the same as 'struct ifreq', but (re)defined for - * convenience... - * Do I need to remind you about structure size (32 octets) ? - */ -struct iwreq { - union - { - char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */ - } ifr_ifrn; - - /* Data part (defined just above) */ - union iwreq_data u; -}; - -/* -------------------------- IOCTL DATA -------------------------- */ -/* - * For those ioctl which want to exchange mode data that what could - * fit in the above structure... - */ - -/* - * Range of parameters - */ - -struct iw_range { - /* Informative stuff (to choose between different interface) */ - __u32 throughput; /* To give an idea... */ - /* In theory this value should be the maximum benchmarked - * TCP/IP throughput, because with most of these devices the - * bit rate is meaningless (overhead an co) to estimate how - * fast the connection will go and pick the fastest one. - * I suggest people to play with Netperf or any benchmark... - */ - - /* NWID (or domain id) */ - __u32 min_nwid; /* Minimal NWID we are able to set */ - __u32 max_nwid; /* Maximal NWID we are able to set */ - - /* Old Frequency (backward compat - moved lower ) */ - __u16 old_num_channels; - __u8 old_num_frequency; - - /* Scan capabilities */ - __u8 scan_capa; /* IW_SCAN_CAPA_* bit field */ - - /* Wireless event capability bitmasks */ - __u32 event_capa[6]; - - /* signal level threshold range */ - __s32 sensitivity; - - /* Quality of link & SNR stuff */ - /* Quality range (link, level, noise) - * If the quality is absolute, it will be in the range [0 ; max_qual], - * if the quality is dBm, it will be in the range [max_qual ; 0]. - * Don't forget that we use 8 bit arithmetics... */ - struct iw_quality max_qual; /* Quality of the link */ - /* This should contain the average/typical values of the quality - * indicator. This should be the threshold between a "good" and - * a "bad" link (example : monitor going from green to orange). - * Currently, user space apps like quality monitors don't have any - * way to calibrate the measurement. With this, they can split - * the range between 0 and max_qual in different quality level - * (using a geometric subdivision centered on the average). - * I expect that people doing the user space apps will feedback - * us on which value we need to put in each driver... */ - struct iw_quality avg_qual; /* Quality of the link */ - - /* Rates */ - __u8 num_bitrates; /* Number of entries in the list */ - __s32 bitrate[IW_MAX_BITRATES]; /* list, in bps */ - - /* RTS threshold */ - __s32 min_rts; /* Minimal RTS threshold */ - __s32 max_rts; /* Maximal RTS threshold */ - - /* Frag threshold */ - __s32 min_frag; /* Minimal frag threshold */ - __s32 max_frag; /* Maximal frag threshold */ - - /* Power Management duration & timeout */ - __s32 min_pmp; /* Minimal PM period */ - __s32 max_pmp; /* Maximal PM period */ - __s32 min_pmt; /* Minimal PM timeout */ - __s32 max_pmt; /* Maximal PM timeout */ - __u16 pmp_flags; /* How to decode max/min PM period */ - __u16 pmt_flags; /* How to decode max/min PM timeout */ - __u16 pm_capa; /* What PM options are supported */ - - /* Encoder stuff */ - __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */ - __u8 num_encoding_sizes; /* Number of entry in the list */ - __u8 max_encoding_tokens; /* Max number of tokens */ - /* For drivers that need a "login/passwd" form */ - __u8 encoding_login_index; /* token index for login token */ - - /* Transmit power */ - __u16 txpower_capa; /* What options are supported */ - __u8 num_txpower; /* Number of entries in the list */ - __s32 txpower[IW_MAX_TXPOWER]; /* list, in bps */ - - /* Wireless Extension version info */ - __u8 we_version_compiled; /* Must be WIRELESS_EXT */ - __u8 we_version_source; /* Last update of source */ - - /* Retry limits and lifetime */ - __u16 retry_capa; /* What retry options are supported */ - __u16 retry_flags; /* How to decode max/min retry limit */ - __u16 r_time_flags; /* How to decode max/min retry life */ - __s32 min_retry; /* Minimal number of retries */ - __s32 max_retry; /* Maximal number of retries */ - __s32 min_r_time; /* Minimal retry lifetime */ - __s32 max_r_time; /* Maximal retry lifetime */ - - /* Frequency */ - __u16 num_channels; /* Number of channels [0; num - 1] */ - __u8 num_frequency; /* Number of entry in the list */ - struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */ - /* Note : this frequency list doesn't need to fit channel numbers, - * because each entry contain its channel index */ - - __u32 enc_capa; /* IW_ENC_CAPA_* bit field */ -}; - -/* - * Private ioctl interface information - */ - -struct iw_priv_args { - __u32 cmd; /* Number of the ioctl to issue */ - __u16 set_args; /* Type and number of args */ - __u16 get_args; /* Type and number of args */ - char name[IFNAMSIZ]; /* Name of the extension */ -}; - -/* ----------------------- WIRELESS EVENTS ----------------------- */ -/* - * Wireless events are carried through the rtnetlink socket to user - * space. They are encapsulated in the IFLA_WIRELESS field of - * a RTM_NEWLINK message. - */ - -/* - * A Wireless Event. Contains basically the same data as the ioctl... - */ -struct iw_event { - __u16 len; /* Real length of this stuff */ - __u16 cmd; /* Wireless IOCTL */ - union iwreq_data u; /* IOCTL fixed payload */ -}; - -/* Size of the Event prefix (including padding and alignement junk) */ -#define IW_EV_LCP_LEN (sizeof(struct iw_event) - sizeof(union iwreq_data)) -/* Size of the various events */ -#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ) -#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32)) -#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq)) -#define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param)) -#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr)) -#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality)) - -/* iw_point events are special. First, the payload (extra data) come at - * the end of the event, so they are bigger than IW_EV_POINT_LEN. Second, - * we omit the pointer, so start at an offset. */ -#define IW_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \ - (char *) NULL) -#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point) - \ - IW_EV_POINT_OFF) - - -/* Size of the Event prefix when packed in stream */ -#define IW_EV_LCP_PK_LEN (4) -/* Size of the various events when packed in stream */ -#define IW_EV_CHAR_PK_LEN (IW_EV_LCP_PK_LEN + IFNAMSIZ) -#define IW_EV_UINT_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(__u32)) -#define IW_EV_FREQ_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_freq)) -#define IW_EV_PARAM_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_param)) -#define IW_EV_ADDR_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct sockaddr)) -#define IW_EV_QUAL_PK_LEN (IW_EV_LCP_PK_LEN + sizeof(struct iw_quality)) -#define IW_EV_POINT_PK_LEN (IW_EV_LCP_PK_LEN + 4) - -#endif /* _UAPI_LINUX_WIRELESS_H */ diff --git a/src/linux/include/uapi/linux/xattr.h b/src/linux/include/uapi/linux/xattr.h deleted file mode 100644 index 1590c49..0000000 --- a/src/linux/include/uapi/linux/xattr.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - File: linux/xattr.h - - Extended attributes handling. - - Copyright (C) 2001 by Andreas Gruenbacher - Copyright (c) 2001-2002 Silicon Graphics, Inc. All Rights Reserved. - Copyright (c) 2004 Red Hat, Inc., James Morris -*/ - -#include - -#ifndef _UAPI_LINUX_XATTR_H -#define _UAPI_LINUX_XATTR_H - -#if __UAPI_DEF_XATTR -#define __USE_KERNEL_XATTR_DEFS - -#define XATTR_CREATE 0x1 /* set value, fail if attr already exists */ -#define XATTR_REPLACE 0x2 /* set value, fail if attr does not exist */ -#endif - -/* Namespaces */ -#define XATTR_OS2_PREFIX "os2." -#define XATTR_OS2_PREFIX_LEN (sizeof(XATTR_OS2_PREFIX) - 1) - -#define XATTR_MAC_OSX_PREFIX "osx." -#define XATTR_MAC_OSX_PREFIX_LEN (sizeof(XATTR_MAC_OSX_PREFIX) - 1) - -#define XATTR_BTRFS_PREFIX "btrfs." -#define XATTR_BTRFS_PREFIX_LEN (sizeof(XATTR_BTRFS_PREFIX) - 1) - -#define XATTR_SECURITY_PREFIX "security." -#define XATTR_SECURITY_PREFIX_LEN (sizeof(XATTR_SECURITY_PREFIX) - 1) - -#define XATTR_SYSTEM_PREFIX "system." -#define XATTR_SYSTEM_PREFIX_LEN (sizeof(XATTR_SYSTEM_PREFIX) - 1) - -#define XATTR_TRUSTED_PREFIX "trusted." -#define XATTR_TRUSTED_PREFIX_LEN (sizeof(XATTR_TRUSTED_PREFIX) - 1) - -#define XATTR_USER_PREFIX "user." -#define XATTR_USER_PREFIX_LEN (sizeof(XATTR_USER_PREFIX) - 1) - -/* Security namespace */ -#define XATTR_EVM_SUFFIX "evm" -#define XATTR_NAME_EVM XATTR_SECURITY_PREFIX XATTR_EVM_SUFFIX - -#define XATTR_IMA_SUFFIX "ima" -#define XATTR_NAME_IMA XATTR_SECURITY_PREFIX XATTR_IMA_SUFFIX - -#define XATTR_SELINUX_SUFFIX "selinux" -#define XATTR_NAME_SELINUX XATTR_SECURITY_PREFIX XATTR_SELINUX_SUFFIX - -#define XATTR_SMACK_SUFFIX "SMACK64" -#define XATTR_SMACK_IPIN "SMACK64IPIN" -#define XATTR_SMACK_IPOUT "SMACK64IPOUT" -#define XATTR_SMACK_EXEC "SMACK64EXEC" -#define XATTR_SMACK_TRANSMUTE "SMACK64TRANSMUTE" -#define XATTR_SMACK_MMAP "SMACK64MMAP" -#define XATTR_NAME_SMACK XATTR_SECURITY_PREFIX XATTR_SMACK_SUFFIX -#define XATTR_NAME_SMACKIPIN XATTR_SECURITY_PREFIX XATTR_SMACK_IPIN -#define XATTR_NAME_SMACKIPOUT XATTR_SECURITY_PREFIX XATTR_SMACK_IPOUT -#define XATTR_NAME_SMACKEXEC XATTR_SECURITY_PREFIX XATTR_SMACK_EXEC -#define XATTR_NAME_SMACKTRANSMUTE XATTR_SECURITY_PREFIX XATTR_SMACK_TRANSMUTE -#define XATTR_NAME_SMACKMMAP XATTR_SECURITY_PREFIX XATTR_SMACK_MMAP - -#define XATTR_CAPS_SUFFIX "capability" -#define XATTR_NAME_CAPS XATTR_SECURITY_PREFIX XATTR_CAPS_SUFFIX - -#define XATTR_POSIX_ACL_ACCESS "posix_acl_access" -#define XATTR_NAME_POSIX_ACL_ACCESS XATTR_SYSTEM_PREFIX XATTR_POSIX_ACL_ACCESS -#define XATTR_POSIX_ACL_DEFAULT "posix_acl_default" -#define XATTR_NAME_POSIX_ACL_DEFAULT XATTR_SYSTEM_PREFIX XATTR_POSIX_ACL_DEFAULT - - -#endif /* _UAPI_LINUX_XATTR_H */ diff --git a/src/linux/include/uapi/linux/xfrm.h b/src/linux/include/uapi/linux/xfrm.h deleted file mode 100644 index 1fc62b2..0000000 --- a/src/linux/include/uapi/linux/xfrm.h +++ /dev/null @@ -1,529 +0,0 @@ -#ifndef _LINUX_XFRM_H -#define _LINUX_XFRM_H - -#include -#include - -/* All of the structures in this file may not change size as they are - * passed into the kernel from userspace via netlink sockets. - */ - -/* Structure to encapsulate addresses. I do not want to use - * "standard" structure. My apologies. - */ -typedef union { - __be32 a4; - __be32 a6[4]; - struct in6_addr in6; -} xfrm_address_t; - -/* Ident of a specific xfrm_state. It is used on input to lookup - * the state by (spi,daddr,ah/esp) or to store information about - * spi, protocol and tunnel address on output. - */ -struct xfrm_id { - xfrm_address_t daddr; - __be32 spi; - __u8 proto; -}; - -struct xfrm_sec_ctx { - __u8 ctx_doi; - __u8 ctx_alg; - __u16 ctx_len; - __u32 ctx_sid; - char ctx_str[0]; -}; - -/* Security Context Domains of Interpretation */ -#define XFRM_SC_DOI_RESERVED 0 -#define XFRM_SC_DOI_LSM 1 - -/* Security Context Algorithms */ -#define XFRM_SC_ALG_RESERVED 0 -#define XFRM_SC_ALG_SELINUX 1 - -/* Selector, used as selector both on policy rules (SPD) and SAs. */ - -struct xfrm_selector { - xfrm_address_t daddr; - xfrm_address_t saddr; - __be16 dport; - __be16 dport_mask; - __be16 sport; - __be16 sport_mask; - __u16 family; - __u8 prefixlen_d; - __u8 prefixlen_s; - __u8 proto; - int ifindex; - __kernel_uid32_t user; -}; - -#define XFRM_INF (~(__u64)0) - -struct xfrm_lifetime_cfg { - __u64 soft_byte_limit; - __u64 hard_byte_limit; - __u64 soft_packet_limit; - __u64 hard_packet_limit; - __u64 soft_add_expires_seconds; - __u64 hard_add_expires_seconds; - __u64 soft_use_expires_seconds; - __u64 hard_use_expires_seconds; -}; - -struct xfrm_lifetime_cur { - __u64 bytes; - __u64 packets; - __u64 add_time; - __u64 use_time; -}; - -struct xfrm_replay_state { - __u32 oseq; - __u32 seq; - __u32 bitmap; -}; - -#define XFRMA_REPLAY_ESN_MAX 4096 - -struct xfrm_replay_state_esn { - unsigned int bmp_len; - __u32 oseq; - __u32 seq; - __u32 oseq_hi; - __u32 seq_hi; - __u32 replay_window; - __u32 bmp[0]; -}; - -struct xfrm_algo { - char alg_name[64]; - unsigned int alg_key_len; /* in bits */ - char alg_key[0]; -}; - -struct xfrm_algo_auth { - char alg_name[64]; - unsigned int alg_key_len; /* in bits */ - unsigned int alg_trunc_len; /* in bits */ - char alg_key[0]; -}; - -struct xfrm_algo_aead { - char alg_name[64]; - unsigned int alg_key_len; /* in bits */ - unsigned int alg_icv_len; /* in bits */ - char alg_key[0]; -}; - -struct xfrm_stats { - __u32 replay_window; - __u32 replay; - __u32 integrity_failed; -}; - -enum { - XFRM_POLICY_TYPE_MAIN = 0, - XFRM_POLICY_TYPE_SUB = 1, - XFRM_POLICY_TYPE_MAX = 2, - XFRM_POLICY_TYPE_ANY = 255 -}; - -enum { - XFRM_POLICY_IN = 0, - XFRM_POLICY_OUT = 1, - XFRM_POLICY_FWD = 2, - XFRM_POLICY_MASK = 3, - XFRM_POLICY_MAX = 3 -}; - -enum { - XFRM_SHARE_ANY, /* No limitations */ - XFRM_SHARE_SESSION, /* For this session only */ - XFRM_SHARE_USER, /* For this user only */ - XFRM_SHARE_UNIQUE /* Use once */ -}; - -#define XFRM_MODE_TRANSPORT 0 -#define XFRM_MODE_TUNNEL 1 -#define XFRM_MODE_ROUTEOPTIMIZATION 2 -#define XFRM_MODE_IN_TRIGGER 3 -#define XFRM_MODE_BEET 4 -#define XFRM_MODE_MAX 5 - -/* Netlink configuration messages. */ -enum { - XFRM_MSG_BASE = 0x10, - - XFRM_MSG_NEWSA = 0x10, -#define XFRM_MSG_NEWSA XFRM_MSG_NEWSA - XFRM_MSG_DELSA, -#define XFRM_MSG_DELSA XFRM_MSG_DELSA - XFRM_MSG_GETSA, -#define XFRM_MSG_GETSA XFRM_MSG_GETSA - - XFRM_MSG_NEWPOLICY, -#define XFRM_MSG_NEWPOLICY XFRM_MSG_NEWPOLICY - XFRM_MSG_DELPOLICY, -#define XFRM_MSG_DELPOLICY XFRM_MSG_DELPOLICY - XFRM_MSG_GETPOLICY, -#define XFRM_MSG_GETPOLICY XFRM_MSG_GETPOLICY - - XFRM_MSG_ALLOCSPI, -#define XFRM_MSG_ALLOCSPI XFRM_MSG_ALLOCSPI - XFRM_MSG_ACQUIRE, -#define XFRM_MSG_ACQUIRE XFRM_MSG_ACQUIRE - XFRM_MSG_EXPIRE, -#define XFRM_MSG_EXPIRE XFRM_MSG_EXPIRE - - XFRM_MSG_UPDPOLICY, -#define XFRM_MSG_UPDPOLICY XFRM_MSG_UPDPOLICY - XFRM_MSG_UPDSA, -#define XFRM_MSG_UPDSA XFRM_MSG_UPDSA - - XFRM_MSG_POLEXPIRE, -#define XFRM_MSG_POLEXPIRE XFRM_MSG_POLEXPIRE - - XFRM_MSG_FLUSHSA, -#define XFRM_MSG_FLUSHSA XFRM_MSG_FLUSHSA - XFRM_MSG_FLUSHPOLICY, -#define XFRM_MSG_FLUSHPOLICY XFRM_MSG_FLUSHPOLICY - - XFRM_MSG_NEWAE, -#define XFRM_MSG_NEWAE XFRM_MSG_NEWAE - XFRM_MSG_GETAE, -#define XFRM_MSG_GETAE XFRM_MSG_GETAE - - XFRM_MSG_REPORT, -#define XFRM_MSG_REPORT XFRM_MSG_REPORT - - XFRM_MSG_MIGRATE, -#define XFRM_MSG_MIGRATE XFRM_MSG_MIGRATE - - XFRM_MSG_NEWSADINFO, -#define XFRM_MSG_NEWSADINFO XFRM_MSG_NEWSADINFO - XFRM_MSG_GETSADINFO, -#define XFRM_MSG_GETSADINFO XFRM_MSG_GETSADINFO - - XFRM_MSG_NEWSPDINFO, -#define XFRM_MSG_NEWSPDINFO XFRM_MSG_NEWSPDINFO - XFRM_MSG_GETSPDINFO, -#define XFRM_MSG_GETSPDINFO XFRM_MSG_GETSPDINFO - - XFRM_MSG_MAPPING, -#define XFRM_MSG_MAPPING XFRM_MSG_MAPPING - __XFRM_MSG_MAX -}; -#define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1) - -#define XFRM_NR_MSGTYPES (XFRM_MSG_MAX + 1 - XFRM_MSG_BASE) - -/* - * Generic LSM security context for comunicating to user space - * NOTE: Same format as sadb_x_sec_ctx - */ -struct xfrm_user_sec_ctx { - __u16 len; - __u16 exttype; - __u8 ctx_alg; /* LSMs: e.g., selinux == 1 */ - __u8 ctx_doi; - __u16 ctx_len; -}; - -struct xfrm_user_tmpl { - struct xfrm_id id; - __u16 family; - xfrm_address_t saddr; - __u32 reqid; - __u8 mode; - __u8 share; - __u8 optional; - __u32 aalgos; - __u32 ealgos; - __u32 calgos; -}; - -struct xfrm_encap_tmpl { - __u16 encap_type; - __be16 encap_sport; - __be16 encap_dport; - xfrm_address_t encap_oa; -}; - -/* AEVENT flags */ -enum xfrm_ae_ftype_t { - XFRM_AE_UNSPEC, - XFRM_AE_RTHR=1, /* replay threshold*/ - XFRM_AE_RVAL=2, /* replay value */ - XFRM_AE_LVAL=4, /* lifetime value */ - XFRM_AE_ETHR=8, /* expiry timer threshold */ - XFRM_AE_CR=16, /* Event cause is replay update */ - XFRM_AE_CE=32, /* Event cause is timer expiry */ - XFRM_AE_CU=64, /* Event cause is policy update */ - __XFRM_AE_MAX - -#define XFRM_AE_MAX (__XFRM_AE_MAX - 1) -}; - -struct xfrm_userpolicy_type { - __u8 type; - __u16 reserved1; - __u8 reserved2; -}; - -/* Netlink message attributes. */ -enum xfrm_attr_type_t { - XFRMA_UNSPEC, - XFRMA_ALG_AUTH, /* struct xfrm_algo */ - XFRMA_ALG_CRYPT, /* struct xfrm_algo */ - XFRMA_ALG_COMP, /* struct xfrm_algo */ - XFRMA_ENCAP, /* struct xfrm_algo + struct xfrm_encap_tmpl */ - XFRMA_TMPL, /* 1 or more struct xfrm_user_tmpl */ - XFRMA_SA, /* struct xfrm_usersa_info */ - XFRMA_POLICY, /*struct xfrm_userpolicy_info */ - XFRMA_SEC_CTX, /* struct xfrm_sec_ctx */ - XFRMA_LTIME_VAL, - XFRMA_REPLAY_VAL, - XFRMA_REPLAY_THRESH, - XFRMA_ETIMER_THRESH, - XFRMA_SRCADDR, /* xfrm_address_t */ - XFRMA_COADDR, /* xfrm_address_t */ - XFRMA_LASTUSED, /* unsigned long */ - XFRMA_POLICY_TYPE, /* struct xfrm_userpolicy_type */ - XFRMA_MIGRATE, - XFRMA_ALG_AEAD, /* struct xfrm_algo_aead */ - XFRMA_KMADDRESS, /* struct xfrm_user_kmaddress */ - XFRMA_ALG_AUTH_TRUNC, /* struct xfrm_algo_auth */ - XFRMA_MARK, /* struct xfrm_mark */ - XFRMA_TFCPAD, /* __u32 */ - XFRMA_REPLAY_ESN_VAL, /* struct xfrm_replay_state_esn */ - XFRMA_SA_EXTRA_FLAGS, /* __u32 */ - XFRMA_PROTO, /* __u8 */ - XFRMA_ADDRESS_FILTER, /* struct xfrm_address_filter */ - XFRMA_PAD, - __XFRMA_MAX - -#define XFRMA_MAX (__XFRMA_MAX - 1) -}; - -struct xfrm_mark { - __u32 v; /* value */ - __u32 m; /* mask */ -}; - -enum xfrm_sadattr_type_t { - XFRMA_SAD_UNSPEC, - XFRMA_SAD_CNT, - XFRMA_SAD_HINFO, - __XFRMA_SAD_MAX - -#define XFRMA_SAD_MAX (__XFRMA_SAD_MAX - 1) -}; - -struct xfrmu_sadhinfo { - __u32 sadhcnt; /* current hash bkts */ - __u32 sadhmcnt; /* max allowed hash bkts */ -}; - -enum xfrm_spdattr_type_t { - XFRMA_SPD_UNSPEC, - XFRMA_SPD_INFO, - XFRMA_SPD_HINFO, - XFRMA_SPD_IPV4_HTHRESH, - XFRMA_SPD_IPV6_HTHRESH, - __XFRMA_SPD_MAX - -#define XFRMA_SPD_MAX (__XFRMA_SPD_MAX - 1) -}; - -struct xfrmu_spdinfo { - __u32 incnt; - __u32 outcnt; - __u32 fwdcnt; - __u32 inscnt; - __u32 outscnt; - __u32 fwdscnt; -}; - -struct xfrmu_spdhinfo { - __u32 spdhcnt; - __u32 spdhmcnt; -}; - -struct xfrmu_spdhthresh { - __u8 lbits; - __u8 rbits; -}; - -struct xfrm_usersa_info { - struct xfrm_selector sel; - struct xfrm_id id; - xfrm_address_t saddr; - struct xfrm_lifetime_cfg lft; - struct xfrm_lifetime_cur curlft; - struct xfrm_stats stats; - __u32 seq; - __u32 reqid; - __u16 family; - __u8 mode; /* XFRM_MODE_xxx */ - __u8 replay_window; - __u8 flags; -#define XFRM_STATE_NOECN 1 -#define XFRM_STATE_DECAP_DSCP 2 -#define XFRM_STATE_NOPMTUDISC 4 -#define XFRM_STATE_WILDRECV 8 -#define XFRM_STATE_ICMP 16 -#define XFRM_STATE_AF_UNSPEC 32 -#define XFRM_STATE_ALIGN4 64 -#define XFRM_STATE_ESN 128 -}; - -#define XFRM_SA_XFLAG_DONT_ENCAP_DSCP 1 - -struct xfrm_usersa_id { - xfrm_address_t daddr; - __be32 spi; - __u16 family; - __u8 proto; -}; - -struct xfrm_aevent_id { - struct xfrm_usersa_id sa_id; - xfrm_address_t saddr; - __u32 flags; - __u32 reqid; -}; - -struct xfrm_userspi_info { - struct xfrm_usersa_info info; - __u32 min; - __u32 max; -}; - -struct xfrm_userpolicy_info { - struct xfrm_selector sel; - struct xfrm_lifetime_cfg lft; - struct xfrm_lifetime_cur curlft; - __u32 priority; - __u32 index; - __u8 dir; - __u8 action; -#define XFRM_POLICY_ALLOW 0 -#define XFRM_POLICY_BLOCK 1 - __u8 flags; -#define XFRM_POLICY_LOCALOK 1 /* Allow user to override global policy */ - /* Automatically expand selector to include matching ICMP payloads. */ -#define XFRM_POLICY_ICMP 2 - __u8 share; -}; - -struct xfrm_userpolicy_id { - struct xfrm_selector sel; - __u32 index; - __u8 dir; -}; - -struct xfrm_user_acquire { - struct xfrm_id id; - xfrm_address_t saddr; - struct xfrm_selector sel; - struct xfrm_userpolicy_info policy; - __u32 aalgos; - __u32 ealgos; - __u32 calgos; - __u32 seq; -}; - -struct xfrm_user_expire { - struct xfrm_usersa_info state; - __u8 hard; -}; - -struct xfrm_user_polexpire { - struct xfrm_userpolicy_info pol; - __u8 hard; -}; - -struct xfrm_usersa_flush { - __u8 proto; -}; - -struct xfrm_user_report { - __u8 proto; - struct xfrm_selector sel; -}; - -/* Used by MIGRATE to pass addresses IKE should use to perform - * SA negotiation with the peer */ -struct xfrm_user_kmaddress { - xfrm_address_t local; - xfrm_address_t remote; - __u32 reserved; - __u16 family; -}; - -struct xfrm_user_migrate { - xfrm_address_t old_daddr; - xfrm_address_t old_saddr; - xfrm_address_t new_daddr; - xfrm_address_t new_saddr; - __u8 proto; - __u8 mode; - __u16 reserved; - __u32 reqid; - __u16 old_family; - __u16 new_family; -}; - -struct xfrm_user_mapping { - struct xfrm_usersa_id id; - __u32 reqid; - xfrm_address_t old_saddr; - xfrm_address_t new_saddr; - __be16 old_sport; - __be16 new_sport; -}; - -struct xfrm_address_filter { - xfrm_address_t saddr; - xfrm_address_t daddr; - __u16 family; - __u8 splen; - __u8 dplen; -}; - -#ifndef __KERNEL__ -/* backwards compatibility for userspace */ -#define XFRMGRP_ACQUIRE 1 -#define XFRMGRP_EXPIRE 2 -#define XFRMGRP_SA 4 -#define XFRMGRP_POLICY 8 -#define XFRMGRP_REPORT 0x20 -#endif - -enum xfrm_nlgroups { - XFRMNLGRP_NONE, -#define XFRMNLGRP_NONE XFRMNLGRP_NONE - XFRMNLGRP_ACQUIRE, -#define XFRMNLGRP_ACQUIRE XFRMNLGRP_ACQUIRE - XFRMNLGRP_EXPIRE, -#define XFRMNLGRP_EXPIRE XFRMNLGRP_EXPIRE - XFRMNLGRP_SA, -#define XFRMNLGRP_SA XFRMNLGRP_SA - XFRMNLGRP_POLICY, -#define XFRMNLGRP_POLICY XFRMNLGRP_POLICY - XFRMNLGRP_AEVENTS, -#define XFRMNLGRP_AEVENTS XFRMNLGRP_AEVENTS - XFRMNLGRP_REPORT, -#define XFRMNLGRP_REPORT XFRMNLGRP_REPORT - XFRMNLGRP_MIGRATE, -#define XFRMNLGRP_MIGRATE XFRMNLGRP_MIGRATE - XFRMNLGRP_MAPPING, -#define XFRMNLGRP_MAPPING XFRMNLGRP_MAPPING - __XFRMNLGRP_MAX -}; -#define XFRMNLGRP_MAX (__XFRMNLGRP_MAX - 1) - -#endif /* _LINUX_XFRM_H */ diff --git a/src/linux/include/xen/xen.h b/src/linux/include/xen/xen.h deleted file mode 100644 index f0f0252..0000000 --- a/src/linux/include/xen/xen.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _XEN_XEN_H -#define _XEN_XEN_H - -enum xen_domain_type { - XEN_NATIVE, /* running on bare hardware */ - XEN_PV_DOMAIN, /* running in a PV domain */ - XEN_HVM_DOMAIN, /* running in a Xen hvm domain */ -}; - -#ifdef CONFIG_XEN -extern enum xen_domain_type xen_domain_type; -#else -#define xen_domain_type XEN_NATIVE -#endif - -#define xen_domain() (xen_domain_type != XEN_NATIVE) -#define xen_pv_domain() (xen_domain() && \ - xen_domain_type == XEN_PV_DOMAIN) -#define xen_hvm_domain() (xen_domain() && \ - xen_domain_type == XEN_HVM_DOMAIN) - -#ifdef CONFIG_XEN_DOM0 -#include -#include - -#define xen_initial_domain() (xen_domain() && \ - xen_start_info && xen_start_info->flags & SIF_INITDOMAIN) -#else /* !CONFIG_XEN_DOM0 */ -#define xen_initial_domain() (0) -#endif /* CONFIG_XEN_DOM0 */ - -#ifdef CONFIG_XEN_PVH -/* This functionality exists only for x86. The XEN_PVHVM support exists - * only in x86 world - hence on ARM it will be always disabled. - * N.B. ARM guests are neither PV nor HVM nor PVHVM. - * It's a bit like PVH but is different also (it's further towards the H - * end of the spectrum than even PVH). - */ -#include -#define xen_pvh_domain() (xen_pv_domain() && \ - xen_feature(XENFEAT_auto_translated_physmap)) -#else -#define xen_pvh_domain() (0) -#endif -#endif /* _XEN_XEN_H */ diff --git a/src/linux/init/Kconfig b/src/linux/init/Kconfig deleted file mode 100644 index df24155..0000000 --- a/src/linux/init/Kconfig +++ /dev/null @@ -1,2142 +0,0 @@ -config ARCH - string - option env="ARCH" - -config KERNELVERSION - string - option env="KERNELVERSION" - -config DEFCONFIG_LIST - string - depends on !UML - option defconfig_list - default "/lib/modules/$UNAME_RELEASE/.config" - default "/etc/kernel-config" - default "/boot/config-$UNAME_RELEASE" - default "$ARCH_DEFCONFIG" - default "arch/$ARCH/defconfig" - -config CONSTRUCTORS - bool - depends on !UML - -config IRQ_WORK - bool - -config BUILDTIME_EXTABLE_SORT - bool - -config THREAD_INFO_IN_TASK - bool - help - Select this to move thread_info off the stack into task_struct. To - make this work, an arch will need to remove all thread_info fields - except flags and fix any runtime bugs. - - One subtle change that will be needed is to use try_get_task_stack() - and put_task_stack() in save_thread_stack_tsk() and get_wchan(). - -menu "General setup" - -config BROKEN - bool - -config BROKEN_ON_SMP - bool - depends on BROKEN || !SMP - default y - -config INIT_ENV_ARG_LIMIT - int - default 32 if !UML - default 128 if UML - help - Maximum of each of the number of arguments and environment - variables passed to init from the kernel command line. - - -config CROSS_COMPILE - string "Cross-compiler tool prefix" - help - Same as running 'make CROSS_COMPILE=prefix-' but stored for - default make runs in this kernel build directory. You don't - need to set this unless you want the configured kernel build - directory to select the cross-compiler automatically. - -config COMPILE_TEST - bool "Compile also drivers which will not load" - depends on !UML - default n - help - Some drivers can be compiled on a different platform than they are - intended to be run on. Despite they cannot be loaded there (or even - when they load they cannot be used due to missing HW support), - developers still, opposing to distributors, might want to build such - drivers to compile-test them. - - If you are a developer and want to build everything available, say Y - here. If you are a user/distributor, say N here to exclude useless - drivers to be distributed. - -config LOCALVERSION - string "Local version - append to kernel release" - help - Append an extra string to the end of your kernel version. - This will show up when you type uname, for example. - The string you set here will be appended after the contents of - any files with a filename matching localversion* in your - object and source tree, in that order. Your total string can - be a maximum of 64 characters. - -config LOCALVERSION_AUTO - bool "Automatically append version information to the version string" - default y - depends on !COMPILE_TEST - help - This will try to automatically determine if the current tree is a - release tree by looking for git tags that belong to the current - top of tree revision. - - A string of the format -gxxxxxxxx will be added to the localversion - if a git-based tree is found. The string generated by this will be - appended after any matching localversion* files, and after the value - set in CONFIG_LOCALVERSION. - - (The actual string used here is the first eight characters produced - by running the command: - - $ git rev-parse --verify HEAD - - which is done within the script "scripts/setlocalversion".) - -config HAVE_KERNEL_GZIP - bool - -config HAVE_KERNEL_BZIP2 - bool - -config HAVE_KERNEL_LZMA - bool - -config HAVE_KERNEL_XZ - bool - -config HAVE_KERNEL_LZO - bool - -config HAVE_KERNEL_LZ4 - bool - -choice - prompt "Kernel compression mode" - default KERNEL_GZIP - depends on HAVE_KERNEL_GZIP || HAVE_KERNEL_BZIP2 || HAVE_KERNEL_LZMA || HAVE_KERNEL_XZ || HAVE_KERNEL_LZO || HAVE_KERNEL_LZ4 - help - The linux kernel is a kind of self-extracting executable. - Several compression algorithms are available, which differ - in efficiency, compression and decompression speed. - Compression speed is only relevant when building a kernel. - Decompression speed is relevant at each boot. - - If you have any problems with bzip2 or lzma compressed - kernels, mail me (Alain Knaff) . (An older - version of this functionality (bzip2 only), for 2.4, was - supplied by Christian Ludwig) - - High compression options are mostly useful for users, who - are low on disk space (embedded systems), but for whom ram - size matters less. - - If in doubt, select 'gzip' - -config KERNEL_GZIP - bool "Gzip" - depends on HAVE_KERNEL_GZIP - help - The old and tried gzip compression. It provides a good balance - between compression ratio and decompression speed. - -config KERNEL_BZIP2 - bool "Bzip2" - depends on HAVE_KERNEL_BZIP2 - help - Its compression ratio and speed is intermediate. - Decompression speed is slowest among the choices. The kernel - size is about 10% smaller with bzip2, in comparison to gzip. - Bzip2 uses a large amount of memory. For modern kernels you - will need at least 8MB RAM or more for booting. - -config KERNEL_LZMA - bool "LZMA" - depends on HAVE_KERNEL_LZMA - help - This compression algorithm's ratio is best. Decompression speed - is between gzip and bzip2. Compression is slowest. - The kernel size is about 33% smaller with LZMA in comparison to gzip. - -config KERNEL_XZ - bool "XZ" - depends on HAVE_KERNEL_XZ - help - XZ uses the LZMA2 algorithm and instruction set specific - BCJ filters which can improve compression ratio of executable - code. The size of the kernel is about 30% smaller with XZ in - comparison to gzip. On architectures for which there is a BCJ - filter (i386, x86_64, ARM, IA-64, PowerPC, and SPARC), XZ - will create a few percent smaller kernel than plain LZMA. - - The speed is about the same as with LZMA: The decompression - speed of XZ is better than that of bzip2 but worse than gzip - and LZO. Compression is slow. - -config KERNEL_LZO - bool "LZO" - depends on HAVE_KERNEL_LZO - help - Its compression ratio is the poorest among the choices. The kernel - size is about 10% bigger than gzip; however its speed - (both compression and decompression) is the fastest. - -config KERNEL_LZ4 - bool "LZ4" - depends on HAVE_KERNEL_LZ4 - help - LZ4 is an LZ77-type compressor with a fixed, byte-oriented encoding. - A preliminary version of LZ4 de/compression tool is available at - . - - Its compression ratio is worse than LZO. The size of the kernel - is about 8% bigger than LZO. But the decompression speed is - faster than LZO. - -endchoice - -config DEFAULT_HOSTNAME - string "Default hostname" - default "(none)" - help - This option determines the default system hostname before userspace - calls sethostname(2). The kernel traditionally uses "(none)" here, - but you may wish to use a different default here to make a minimal - system more usable with less configuration. - -config SWAP - bool "Support for paging of anonymous memory (swap)" - depends on MMU && BLOCK - default y - help - This option allows you to choose whether you want to have support - for so called swap devices or swap files in your kernel that are - used to provide more virtual memory than the actual RAM present - in your computer. If unsure say Y. - -config SYSVIPC - bool "System V IPC" - ---help--- - Inter Process Communication is a suite of library functions and - system calls which let processes (running programs) synchronize and - exchange information. It is generally considered to be a good thing, - and some programs won't run unless you say Y here. In particular, if - you want to run the DOS emulator dosemu under Linux (read the - DOSEMU-HOWTO, available from ), - you'll need to say Y here. - - You can find documentation about IPC with "info ipc" and also in - section 6.4 of the Linux Programmer's Guide, available from - . - -config SYSVIPC_SYSCTL - bool - depends on SYSVIPC - depends on SYSCTL - default y - -config POSIX_MQUEUE - bool "POSIX Message Queues" - depends on NET - ---help--- - POSIX variant of message queues is a part of IPC. In POSIX message - queues every message has a priority which decides about succession - of receiving it by a process. If you want to compile and run - programs written e.g. for Solaris with use of its POSIX message - queues (functions mq_*) say Y here. - - POSIX message queues are visible as a filesystem called 'mqueue' - and can be mounted somewhere if you want to do filesystem - operations on message queues. - - If unsure, say Y. - -config POSIX_MQUEUE_SYSCTL - bool - depends on POSIX_MQUEUE - depends on SYSCTL - default y - -config CROSS_MEMORY_ATTACH - bool "Enable process_vm_readv/writev syscalls" - depends on MMU - default y - help - Enabling this option adds the system calls process_vm_readv and - process_vm_writev which allow a process with the correct privileges - to directly read from or write to another process' address space. - See the man page for more details. - -config FHANDLE - bool "open by fhandle syscalls" if EXPERT - select EXPORTFS - default y - help - If you say Y here, a user level program will be able to map - file names to handle and then later use the handle for - different file system operations. This is useful in implementing - userspace file servers, which now track files using handles instead - of names. The handle would remain the same even if file names - get renamed. Enables open_by_handle_at(2) and name_to_handle_at(2) - syscalls. - -config USELIB - bool "uselib syscall" - def_bool ALPHA || M68K || SPARC || X86_32 || IA32_EMULATION - help - This option enables the uselib syscall, a system call used in the - dynamic linker from libc5 and earlier. glibc does not use this - system call. If you intend to run programs built on libc5 or - earlier, you may need to enable this syscall. Current systems - running glibc can safely disable this. - -config AUDIT - bool "Auditing support" - depends on NET - help - Enable auditing infrastructure that can be used with another - kernel subsystem, such as SELinux (which requires this for - logging of avc messages output). System call auditing is included - on architectures which support it. - -config HAVE_ARCH_AUDITSYSCALL - bool - -config AUDITSYSCALL - def_bool y - depends on AUDIT && HAVE_ARCH_AUDITSYSCALL - -config AUDIT_WATCH - def_bool y - depends on AUDITSYSCALL - select FSNOTIFY - -config AUDIT_TREE - def_bool y - depends on AUDITSYSCALL - select FSNOTIFY - -source "kernel/irq/Kconfig" -source "kernel/time/Kconfig" - -menu "CPU/Task time and stats accounting" - -config VIRT_CPU_ACCOUNTING - bool - -choice - prompt "Cputime accounting" - default TICK_CPU_ACCOUNTING if !PPC64 - default VIRT_CPU_ACCOUNTING_NATIVE if PPC64 - -# Kind of a stub config for the pure tick based cputime accounting -config TICK_CPU_ACCOUNTING - bool "Simple tick based cputime accounting" - depends on !S390 && !NO_HZ_FULL - help - This is the basic tick based cputime accounting that maintains - statistics about user, system and idle time spent on per jiffies - granularity. - - If unsure, say Y. - -config VIRT_CPU_ACCOUNTING_NATIVE - bool "Deterministic task and CPU time accounting" - depends on HAVE_VIRT_CPU_ACCOUNTING && !NO_HZ_FULL - select VIRT_CPU_ACCOUNTING - help - Select this option to enable more accurate task and CPU time - accounting. This is done by reading a CPU counter on each - kernel entry and exit and on transitions within the kernel - between system, softirq and hardirq state, so there is a - small performance impact. In the case of s390 or IBM POWER > 5, - this also enables accounting of stolen time on logically-partitioned - systems. - -config VIRT_CPU_ACCOUNTING_GEN - bool "Full dynticks CPU time accounting" - depends on HAVE_CONTEXT_TRACKING - depends on HAVE_VIRT_CPU_ACCOUNTING_GEN - select VIRT_CPU_ACCOUNTING - select CONTEXT_TRACKING - help - Select this option to enable task and CPU time accounting on full - dynticks systems. This accounting is implemented by watching every - kernel-user boundaries using the context tracking subsystem. - The accounting is thus performed at the expense of some significant - overhead. - - For now this is only useful if you are working on the full - dynticks subsystem development. - - If unsure, say N. - -endchoice - -config IRQ_TIME_ACCOUNTING - bool "Fine granularity task level IRQ time accounting" - depends on HAVE_IRQ_TIME_ACCOUNTING && !VIRT_CPU_ACCOUNTING_NATIVE - help - Select this option to enable fine granularity task irq time - accounting. This is done by reading a timestamp on each - transitions between softirq and hardirq state, so there can be a - small performance impact. - - If in doubt, say N here. - -config BSD_PROCESS_ACCT - bool "BSD Process Accounting" - depends on MULTIUSER - help - If you say Y here, a user level program will be able to instruct the - kernel (via a special system call) to write process accounting - information to a file: whenever a process exits, information about - that process will be appended to the file by the kernel. The - information includes things such as creation time, owning user, - command name, memory usage, controlling terminal etc. (the complete - list is in the struct acct in ). It is - up to the user level program to do useful things with this - information. This is generally a good idea, so say Y. - -config BSD_PROCESS_ACCT_V3 - bool "BSD Process Accounting version 3 file format" - depends on BSD_PROCESS_ACCT - default n - help - If you say Y here, the process accounting information is written - in a new file format that also logs the process IDs of each - process and it's parent. Note that this file format is incompatible - with previous v0/v1/v2 file formats, so you will need updated tools - for processing it. A preliminary version of these tools is available - at . - -config TASKSTATS - bool "Export task/process statistics through netlink" - depends on NET - depends on MULTIUSER - default n - help - Export selected statistics for tasks/processes through the - generic netlink interface. Unlike BSD process accounting, the - statistics are available during the lifetime of tasks/processes as - responses to commands. Like BSD accounting, they are sent to user - space on task exit. - - Say N if unsure. - -config TASK_DELAY_ACCT - bool "Enable per-task delay accounting" - depends on TASKSTATS - select SCHED_INFO - help - Collect information on time spent by a task waiting for system - resources like cpu, synchronous block I/O completion and swapping - in pages. Such statistics can help in setting a task's priorities - relative to other tasks for cpu, io, rss limits etc. - - Say N if unsure. - -config TASK_XACCT - bool "Enable extended accounting over taskstats" - depends on TASKSTATS - help - Collect extended task accounting data and send the data - to userland for processing over the taskstats interface. - - Say N if unsure. - -config TASK_IO_ACCOUNTING - bool "Enable per-task storage I/O accounting" - depends on TASK_XACCT - help - Collect information on the number of bytes of storage I/O which this - task has caused. - - Say N if unsure. - -endmenu # "CPU/Task time and stats accounting" - -menu "RCU Subsystem" - -config TREE_RCU - bool - default y if !PREEMPT && SMP - help - This option selects the RCU implementation that is - designed for very large SMP system with hundreds or - thousands of CPUs. It also scales down nicely to - smaller systems. - -config PREEMPT_RCU - bool - default y if PREEMPT - help - This option selects the RCU implementation that is - designed for very large SMP systems with hundreds or - thousands of CPUs, but for which real-time response - is also required. It also scales down nicely to - smaller systems. - - Select this option if you are unsure. - -config TINY_RCU - bool - default y if !PREEMPT && !SMP - help - This option selects the RCU implementation that is - designed for UP systems from which real-time response - is not required. This option greatly reduces the - memory footprint of RCU. - -config RCU_EXPERT - bool "Make expert-level adjustments to RCU configuration" - default n - help - This option needs to be enabled if you wish to make - expert-level adjustments to RCU configuration. By default, - no such adjustments can be made, which has the often-beneficial - side-effect of preventing "make oldconfig" from asking you all - sorts of detailed questions about how you would like numerous - obscure RCU options to be set up. - - Say Y if you need to make expert-level adjustments to RCU. - - Say N if you are unsure. - -config SRCU - bool - help - This option selects the sleepable version of RCU. This version - permits arbitrary sleeping or blocking within RCU read-side critical - sections. - -config TASKS_RCU - bool - default n - depends on !UML - select SRCU - help - This option enables a task-based RCU implementation that uses - only voluntary context switch (not preemption!), idle, and - user-mode execution as quiescent states. - -config RCU_STALL_COMMON - def_bool ( TREE_RCU || PREEMPT_RCU || RCU_TRACE ) - help - This option enables RCU CPU stall code that is common between - the TINY and TREE variants of RCU. The purpose is to allow - the tiny variants to disable RCU CPU stall warnings, while - making these warnings mandatory for the tree variants. - -config CONTEXT_TRACKING - bool - -config CONTEXT_TRACKING_FORCE - bool "Force context tracking" - depends on CONTEXT_TRACKING - default y if !NO_HZ_FULL - help - The major pre-requirement for full dynticks to work is to - support the context tracking subsystem. But there are also - other dependencies to provide in order to make the full - dynticks working. - - This option stands for testing when an arch implements the - context tracking backend but doesn't yet fullfill all the - requirements to make the full dynticks feature working. - Without the full dynticks, there is no way to test the support - for context tracking and the subsystems that rely on it: RCU - userspace extended quiescent state and tickless cputime - accounting. This option copes with the absence of the full - dynticks subsystem by forcing the context tracking on all - CPUs in the system. - - Say Y only if you're working on the development of an - architecture backend for the context tracking. - - Say N otherwise, this option brings an overhead that you - don't want in production. - - -config RCU_FANOUT - int "Tree-based hierarchical RCU fanout value" - range 2 64 if 64BIT - range 2 32 if !64BIT - depends on (TREE_RCU || PREEMPT_RCU) && RCU_EXPERT - default 64 if 64BIT - default 32 if !64BIT - help - This option controls the fanout of hierarchical implementations - of RCU, allowing RCU to work efficiently on machines with - large numbers of CPUs. This value must be at least the fourth - root of NR_CPUS, which allows NR_CPUS to be insanely large. - The default value of RCU_FANOUT should be used for production - systems, but if you are stress-testing the RCU implementation - itself, small RCU_FANOUT values allow you to test large-system - code paths on small(er) systems. - - Select a specific number if testing RCU itself. - Take the default if unsure. - -config RCU_FANOUT_LEAF - int "Tree-based hierarchical RCU leaf-level fanout value" - range 2 64 if 64BIT - range 2 32 if !64BIT - depends on (TREE_RCU || PREEMPT_RCU) && RCU_EXPERT - default 16 - help - This option controls the leaf-level fanout of hierarchical - implementations of RCU, and allows trading off cache misses - against lock contention. Systems that synchronize their - scheduling-clock interrupts for energy-efficiency reasons will - want the default because the smaller leaf-level fanout keeps - lock contention levels acceptably low. Very large systems - (hundreds or thousands of CPUs) will instead want to set this - value to the maximum value possible in order to reduce the - number of cache misses incurred during RCU's grace-period - initialization. These systems tend to run CPU-bound, and thus - are not helped by synchronized interrupts, and thus tend to - skew them, which reduces lock contention enough that large - leaf-level fanouts work well. - - Select a specific number if testing RCU itself. - - Select the maximum permissible value for large systems. - - Take the default if unsure. - -config RCU_FAST_NO_HZ - bool "Accelerate last non-dyntick-idle CPU's grace periods" - depends on NO_HZ_COMMON && SMP && RCU_EXPERT - default n - help - This option permits CPUs to enter dynticks-idle state even if - they have RCU callbacks queued, and prevents RCU from waking - these CPUs up more than roughly once every four jiffies (by - default, you can adjust this using the rcutree.rcu_idle_gp_delay - parameter), thus improving energy efficiency. On the other - hand, this option increases the duration of RCU grace periods, - for example, slowing down synchronize_rcu(). - - Say Y if energy efficiency is critically important, and you - don't care about increased grace-period durations. - - Say N if you are unsure. - -config TREE_RCU_TRACE - def_bool RCU_TRACE && ( TREE_RCU || PREEMPT_RCU ) - select DEBUG_FS - help - This option provides tracing for the TREE_RCU and - PREEMPT_RCU implementations, permitting Makefile to - trivially select kernel/rcutree_trace.c. - -config RCU_BOOST - bool "Enable RCU priority boosting" - depends on RT_MUTEXES && PREEMPT_RCU && RCU_EXPERT - default n - help - This option boosts the priority of preempted RCU readers that - block the current preemptible RCU grace period for too long. - This option also prevents heavy loads from blocking RCU - callback invocation for all flavors of RCU. - - Say Y here if you are working with real-time apps or heavy loads - Say N here if you are unsure. - -config RCU_KTHREAD_PRIO - int "Real-time priority to use for RCU worker threads" - range 1 99 if RCU_BOOST - range 0 99 if !RCU_BOOST - default 1 if RCU_BOOST - default 0 if !RCU_BOOST - depends on RCU_EXPERT - help - This option specifies the SCHED_FIFO priority value that will be - assigned to the rcuc/n and rcub/n threads and is also the value - used for RCU_BOOST (if enabled). If you are working with a - real-time application that has one or more CPU-bound threads - running at a real-time priority level, you should set - RCU_KTHREAD_PRIO to a priority higher than the highest-priority - real-time CPU-bound application thread. The default RCU_KTHREAD_PRIO - value of 1 is appropriate in the common case, which is real-time - applications that do not have any CPU-bound threads. - - Some real-time applications might not have a single real-time - thread that saturates a given CPU, but instead might have - multiple real-time threads that, taken together, fully utilize - that CPU. In this case, you should set RCU_KTHREAD_PRIO to - a priority higher than the lowest-priority thread that is - conspiring to prevent the CPU from running any non-real-time - tasks. For example, if one thread at priority 10 and another - thread at priority 5 are between themselves fully consuming - the CPU time on a given CPU, then RCU_KTHREAD_PRIO should be - set to priority 6 or higher. - - Specify the real-time priority, or take the default if unsure. - -config RCU_BOOST_DELAY - int "Milliseconds to delay boosting after RCU grace-period start" - range 0 3000 - depends on RCU_BOOST - default 500 - help - This option specifies the time to wait after the beginning of - a given grace period before priority-boosting preempted RCU - readers blocking that grace period. Note that any RCU reader - blocking an expedited RCU grace period is boosted immediately. - - Accept the default if unsure. - -config RCU_NOCB_CPU - bool "Offload RCU callback processing from boot-selected CPUs" - depends on TREE_RCU || PREEMPT_RCU - depends on RCU_EXPERT || NO_HZ_FULL - default n - help - Use this option to reduce OS jitter for aggressive HPC or - real-time workloads. It can also be used to offload RCU - callback invocation to energy-efficient CPUs in battery-powered - asymmetric multiprocessors. - - This option offloads callback invocation from the set of - CPUs specified at boot time by the rcu_nocbs parameter. - For each such CPU, a kthread ("rcuox/N") will be created to - invoke callbacks, where the "N" is the CPU being offloaded, - and where the "x" is "b" for RCU-bh, "p" for RCU-preempt, and - "s" for RCU-sched. Nothing prevents this kthread from running - on the specified CPUs, but (1) the kthreads may be preempted - between each callback, and (2) affinity or cgroups can be used - to force the kthreads to run on whatever set of CPUs is desired. - - Say Y here if you want to help to debug reduced OS jitter. - Say N here if you are unsure. - -choice - prompt "Build-forced no-CBs CPUs" - default RCU_NOCB_CPU_NONE - depends on RCU_NOCB_CPU - help - This option allows no-CBs CPUs (whose RCU callbacks are invoked - from kthreads rather than from softirq context) to be specified - at build time. Additional no-CBs CPUs may be specified by - the rcu_nocbs= boot parameter. - -config RCU_NOCB_CPU_NONE - bool "No build_forced no-CBs CPUs" - help - This option does not force any of the CPUs to be no-CBs CPUs. - Only CPUs designated by the rcu_nocbs= boot parameter will be - no-CBs CPUs, whose RCU callbacks will be invoked by per-CPU - kthreads whose names begin with "rcuo". All other CPUs will - invoke their own RCU callbacks in softirq context. - - Select this option if you want to choose no-CBs CPUs at - boot time, for example, to allow testing of different no-CBs - configurations without having to rebuild the kernel each time. - -config RCU_NOCB_CPU_ZERO - bool "CPU 0 is a build_forced no-CBs CPU" - help - This option forces CPU 0 to be a no-CBs CPU, so that its RCU - callbacks are invoked by a per-CPU kthread whose name begins - with "rcuo". Additional CPUs may be designated as no-CBs - CPUs using the rcu_nocbs= boot parameter will be no-CBs CPUs. - All other CPUs will invoke their own RCU callbacks in softirq - context. - - Select this if CPU 0 needs to be a no-CBs CPU for real-time - or energy-efficiency reasons, but the real reason it exists - is to ensure that randconfig testing covers mixed systems. - -config RCU_NOCB_CPU_ALL - bool "All CPUs are build_forced no-CBs CPUs" - help - This option forces all CPUs to be no-CBs CPUs. The rcu_nocbs= - boot parameter will be ignored. All CPUs' RCU callbacks will - be executed in the context of per-CPU rcuo kthreads created for - this purpose. Assuming that the kthreads whose names start with - "rcuo" are bound to "housekeeping" CPUs, this reduces OS jitter - on the remaining CPUs, but might decrease memory locality during - RCU-callback invocation, thus potentially degrading throughput. - - Select this if all CPUs need to be no-CBs CPUs for real-time - or energy-efficiency reasons. - -endchoice - -config RCU_EXPEDITE_BOOT - bool - default n - help - This option enables expedited grace periods at boot time, - as if rcu_expedite_gp() had been invoked early in boot. - The corresponding rcu_unexpedite_gp() is invoked from - rcu_end_inkernel_boot(), which is intended to be invoked - at the end of the kernel-only boot sequence, just before - init is exec'ed. - - Accept the default if unsure. - -endmenu # "RCU Subsystem" - -config BUILD_BIN2C - bool - default n - -config IKCONFIG - tristate "Kernel .config support" - select BUILD_BIN2C - ---help--- - This option enables the complete Linux kernel ".config" file - contents to be saved in the kernel. It provides documentation - of which kernel options are used in a running kernel or in an - on-disk kernel. This information can be extracted from the kernel - image file with the script scripts/extract-ikconfig and used as - input to rebuild the current kernel or to build another kernel. - It can also be extracted from a running kernel by reading - /proc/config.gz if enabled (below). - -config IKCONFIG_PROC - bool "Enable access to .config through /proc/config.gz" - depends on IKCONFIG && PROC_FS - ---help--- - This option enables access to the kernel configuration file - through /proc/config.gz. - -config LOG_BUF_SHIFT - int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" - range 12 25 - default 17 - depends on PRINTK - help - Select the minimal kernel log buffer size as a power of 2. - The final size is affected by LOG_CPU_MAX_BUF_SHIFT config - parameter, see below. Any higher size also might be forced - by "log_buf_len" boot parameter. - - Examples: - 17 => 128 KB - 16 => 64 KB - 15 => 32 KB - 14 => 16 KB - 13 => 8 KB - 12 => 4 KB - -config LOG_CPU_MAX_BUF_SHIFT - int "CPU kernel log buffer size contribution (13 => 8 KB, 17 => 128KB)" - depends on SMP - range 0 21 - default 12 if !BASE_SMALL - default 0 if BASE_SMALL - depends on PRINTK - help - This option allows to increase the default ring buffer size - according to the number of CPUs. The value defines the contribution - of each CPU as a power of 2. The used space is typically only few - lines however it might be much more when problems are reported, - e.g. backtraces. - - The increased size means that a new buffer has to be allocated and - the original static one is unused. It makes sense only on systems - with more CPUs. Therefore this value is used only when the sum of - contributions is greater than the half of the default kernel ring - buffer as defined by LOG_BUF_SHIFT. The default values are set - so that more than 64 CPUs are needed to trigger the allocation. - - Also this option is ignored when "log_buf_len" kernel parameter is - used as it forces an exact (power of two) size of the ring buffer. - - The number of possible CPUs is used for this computation ignoring - hotplugging making the computation optimal for the worst case - scenario while allowing a simple algorithm to be used from bootup. - - Examples shift values and their meaning: - 17 => 128 KB for each CPU - 16 => 64 KB for each CPU - 15 => 32 KB for each CPU - 14 => 16 KB for each CPU - 13 => 8 KB for each CPU - 12 => 4 KB for each CPU - -config NMI_LOG_BUF_SHIFT - int "Temporary per-CPU NMI log buffer size (12 => 4KB, 13 => 8KB)" - range 10 21 - default 13 - depends on PRINTK_NMI - help - Select the size of a per-CPU buffer where NMI messages are temporary - stored. They are copied to the main log buffer in a safe context - to avoid a deadlock. The value defines the size as a power of 2. - - NMI messages are rare and limited. The largest one is when - a backtrace is printed. It usually fits into 4KB. Select - 8KB if you want to be on the safe side. - - Examples: - 17 => 128 KB for each CPU - 16 => 64 KB for each CPU - 15 => 32 KB for each CPU - 14 => 16 KB for each CPU - 13 => 8 KB for each CPU - 12 => 4 KB for each CPU - -# -# Architectures with an unreliable sched_clock() should select this: -# -config HAVE_UNSTABLE_SCHED_CLOCK - bool - -config GENERIC_SCHED_CLOCK - bool - -# -# For architectures that want to enable the support for NUMA-affine scheduler -# balancing logic: -# -config ARCH_SUPPORTS_NUMA_BALANCING - bool - -# -# For architectures that prefer to flush all TLBs after a number of pages -# are unmapped instead of sending one IPI per page to flush. The architecture -# must provide guarantees on what happens if a clean TLB cache entry is -# written after the unmap. Details are in mm/rmap.c near the check for -# should_defer_flush. The architecture should also consider if the full flush -# and the refill costs are offset by the savings of sending fewer IPIs. -config ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH - bool - -# -# For architectures that know their GCC __int128 support is sound -# -config ARCH_SUPPORTS_INT128 - bool - -# For architectures that (ab)use NUMA to represent different memory regions -# all cpu-local but of different latencies, such as SuperH. -# -config ARCH_WANT_NUMA_VARIABLE_LOCALITY - bool - -config NUMA_BALANCING - bool "Memory placement aware NUMA scheduler" - depends on ARCH_SUPPORTS_NUMA_BALANCING - depends on !ARCH_WANT_NUMA_VARIABLE_LOCALITY - depends on SMP && NUMA && MIGRATION - help - This option adds support for automatic NUMA aware memory/task placement. - The mechanism is quite primitive and is based on migrating memory when - it has references to the node the task is running on. - - This system will be inactive on UMA systems. - -config NUMA_BALANCING_DEFAULT_ENABLED - bool "Automatically enable NUMA aware memory/task placement" - default y - depends on NUMA_BALANCING - help - If set, automatic NUMA balancing will be enabled if running on a NUMA - machine. - -menuconfig CGROUPS - bool "Control Group support" - select KERNFS - help - This option adds support for grouping sets of processes together, for - use with process control subsystems such as Cpusets, CFS, memory - controls or device isolation. - See - - Documentation/scheduler/sched-design-CFS.txt (CFS) - - Documentation/cgroup-v1/ (features for grouping, isolation - and resource control) - - Say N if unsure. - -if CGROUPS - -config PAGE_COUNTER - bool - -config MEMCG - bool "Memory controller" - select PAGE_COUNTER - select EVENTFD - help - Provides control over the memory footprint of tasks in a cgroup. - -config MEMCG_SWAP - bool "Swap controller" - depends on MEMCG && SWAP - help - Provides control over the swap space consumed by tasks in a cgroup. - -config MEMCG_SWAP_ENABLED - bool "Swap controller enabled by default" - depends on MEMCG_SWAP - default y - help - Memory Resource Controller Swap Extension comes with its price in - a bigger memory consumption. General purpose distribution kernels - which want to enable the feature but keep it disabled by default - and let the user enable it by swapaccount=1 boot command line - parameter should have this option unselected. - For those who want to have the feature enabled by default should - select this option (if, for some reason, they need to disable it - then swapaccount=0 does the trick). - -config BLK_CGROUP - bool "IO controller" - depends on BLOCK - default n - ---help--- - Generic block IO controller cgroup interface. This is the common - cgroup interface which should be used by various IO controlling - policies. - - Currently, CFQ IO scheduler uses it to recognize task groups and - control disk bandwidth allocation (proportional time slice allocation) - to such task groups. It is also used by bio throttling logic in - block layer to implement upper limit in IO rates on a device. - - This option only enables generic Block IO controller infrastructure. - One needs to also enable actual IO controlling logic/policy. For - enabling proportional weight division of disk bandwidth in CFQ, set - CONFIG_CFQ_GROUP_IOSCHED=y; for enabling throttling policy, set - CONFIG_BLK_DEV_THROTTLING=y. - - See Documentation/cgroup-v1/blkio-controller.txt for more information. - -config DEBUG_BLK_CGROUP - bool "IO controller debugging" - depends on BLK_CGROUP - default n - ---help--- - Enable some debugging help. Currently it exports additional stat - files in a cgroup which can be useful for debugging. - -config CGROUP_WRITEBACK - bool - depends on MEMCG && BLK_CGROUP - default y - -menuconfig CGROUP_SCHED - bool "CPU controller" - default n - help - This feature lets CPU scheduler recognize task groups and control CPU - bandwidth allocation to such task groups. It uses cgroups to group - tasks. - -if CGROUP_SCHED -config FAIR_GROUP_SCHED - bool "Group scheduling for SCHED_OTHER" - depends on CGROUP_SCHED - default CGROUP_SCHED - -config CFS_BANDWIDTH - bool "CPU bandwidth provisioning for FAIR_GROUP_SCHED" - depends on FAIR_GROUP_SCHED - default n - help - This option allows users to define CPU bandwidth rates (limits) for - tasks running within the fair group scheduler. Groups with no limit - set are considered to be unconstrained and will run with no - restriction. - See tip/Documentation/scheduler/sched-bwc.txt for more information. - -config RT_GROUP_SCHED - bool "Group scheduling for SCHED_RR/FIFO" - depends on CGROUP_SCHED - default n - help - This feature lets you explicitly allocate real CPU bandwidth - to task groups. If enabled, it will also make it impossible to - schedule realtime tasks for non-root users until you allocate - realtime bandwidth for them. - See Documentation/scheduler/sched-rt-group.txt for more information. - -endif #CGROUP_SCHED - -config CGROUP_PIDS - bool "PIDs controller" - help - Provides enforcement of process number limits in the scope of a - cgroup. Any attempt to fork more processes than is allowed in the - cgroup will fail. PIDs are fundamentally a global resource because it - is fairly trivial to reach PID exhaustion before you reach even a - conservative kmemcg limit. As a result, it is possible to grind a - system to halt without being limited by other cgroup policies. The - PIDs controller is designed to stop this from happening. - - It should be noted that organisational operations (such as attaching - to a cgroup hierarchy will *not* be blocked by the PIDs controller), - since the PIDs limit only affects a process's ability to fork, not to - attach to a cgroup. - -config CGROUP_FREEZER - bool "Freezer controller" - help - Provides a way to freeze and unfreeze all tasks in a - cgroup. - - This option affects the ORIGINAL cgroup interface. The cgroup2 memory - controller includes important in-kernel memory consumers per default. - - If you're using cgroup2, say N. - -config CGROUP_HUGETLB - bool "HugeTLB controller" - depends on HUGETLB_PAGE - select PAGE_COUNTER - default n - help - Provides a cgroup controller for HugeTLB pages. - When you enable this, you can put a per cgroup limit on HugeTLB usage. - The limit is enforced during page fault. Since HugeTLB doesn't - support page reclaim, enforcing the limit at page fault time implies - that, the application will get SIGBUS signal if it tries to access - HugeTLB pages beyond its limit. This requires the application to know - beforehand how much HugeTLB pages it would require for its use. The - control group is tracked in the third page lru pointer. This means - that we cannot use the controller with huge page less than 3 pages. - -config CPUSETS - bool "Cpuset controller" - help - This option will let you create and manage CPUSETs which - allow dynamically partitioning a system into sets of CPUs and - Memory Nodes and assigning tasks to run only within those sets. - This is primarily useful on large SMP or NUMA systems. - - Say N if unsure. - -config PROC_PID_CPUSET - bool "Include legacy /proc//cpuset file" - depends on CPUSETS - default y - -config CGROUP_DEVICE - bool "Device controller" - help - Provides a cgroup controller implementing whitelists for - devices which a process in the cgroup can mknod or open. - -config CGROUP_CPUACCT - bool "Simple CPU accounting controller" - help - Provides a simple controller for monitoring the - total CPU consumed by the tasks in a cgroup. - -config CGROUP_PERF - bool "Perf controller" - depends on PERF_EVENTS - help - This option extends the perf per-cpu mode to restrict monitoring - to threads which belong to the cgroup specified and run on the - designated cpu. - - Say N if unsure. - -config CGROUP_DEBUG - bool "Example controller" - default n - help - This option enables a simple controller that exports - debugging information about the cgroups framework. - - Say N. - -endif # CGROUPS - -config CHECKPOINT_RESTORE - bool "Checkpoint/restore support" if EXPERT - select PROC_CHILDREN - default n - help - Enables additional kernel features in a sake of checkpoint/restore. - In particular it adds auxiliary prctl codes to setup process text, - data and heap segment sizes, and a few additional /proc filesystem - entries. - - If unsure, say N here. - -menuconfig NAMESPACES - bool "Namespaces support" if EXPERT - depends on MULTIUSER - default !EXPERT - help - Provides the way to make tasks work with different objects using - the same id. For example same IPC id may refer to different objects - or same user id or pid may refer to different tasks when used in - different namespaces. - -if NAMESPACES - -config UTS_NS - bool "UTS namespace" - default y - help - In this namespace tasks see different info provided with the - uname() system call - -config IPC_NS - bool "IPC namespace" - depends on (SYSVIPC || POSIX_MQUEUE) - default y - help - In this namespace tasks work with IPC ids which correspond to - different IPC objects in different namespaces. - -config USER_NS - bool "User namespace" - default n - help - This allows containers, i.e. vservers, to use user namespaces - to provide different user info for different servers. - - When user namespaces are enabled in the kernel it is - recommended that the MEMCG option also be enabled and that - user-space use the memory control groups to limit the amount - of memory a memory unprivileged users can use. - - If unsure, say N. - -config PID_NS - bool "PID Namespaces" - default y - help - Support process id namespaces. This allows having multiple - processes with the same pid as long as they are in different - pid namespaces. This is a building block of containers. - -config NET_NS - bool "Network namespace" - depends on NET - default y - help - Allow user space to create what appear to be multiple instances - of the network stack. - -endif # NAMESPACES - -config SCHED_AUTOGROUP - bool "Automatic process group scheduling" - select CGROUPS - select CGROUP_SCHED - select FAIR_GROUP_SCHED - help - This option optimizes the scheduler for common desktop workloads by - automatically creating and populating task groups. This separation - of workloads isolates aggressive CPU burners (like build jobs) from - desktop applications. Task group autogeneration is currently based - upon task session. - -config SYSFS_DEPRECATED - bool "Enable deprecated sysfs features to support old userspace tools" - depends on SYSFS - default n - help - This option adds code that switches the layout of the "block" class - devices, to not show up in /sys/class/block/, but only in - /sys/block/. - - This switch is only active when the sysfs.deprecated=1 boot option is - passed or the SYSFS_DEPRECATED_V2 option is set. - - This option allows new kernels to run on old distributions and tools, - which might get confused by /sys/class/block/. Since 2007/2008 all - major distributions and tools handle this just fine. - - Recent distributions and userspace tools after 2009/2010 depend on - the existence of /sys/class/block/, and will not work with this - option enabled. - - Only if you are using a new kernel on an old distribution, you might - need to say Y here. - -config SYSFS_DEPRECATED_V2 - bool "Enable deprecated sysfs features by default" - default n - depends on SYSFS - depends on SYSFS_DEPRECATED - help - Enable deprecated sysfs by default. - - See the CONFIG_SYSFS_DEPRECATED option for more details about this - option. - - Only if you are using a new kernel on an old distribution, you might - need to say Y here. Even then, odds are you would not need it - enabled, you can always pass the boot option if absolutely necessary. - -config RELAY - bool "Kernel->user space relay support (formerly relayfs)" - select IRQ_WORK - help - This option enables support for relay interface support in - certain file systems (such as debugfs). - It is designed to provide an efficient mechanism for tools and - facilities to relay large amounts of data from kernel space to - user space. - - If unsure, say N. - -config BLK_DEV_INITRD - bool "Initial RAM filesystem and RAM disk (initramfs/initrd) support" - depends on BROKEN || !FRV - help - The initial RAM filesystem is a ramfs which is loaded by the - boot loader (loadlin or lilo) and that is mounted as root - before the normal boot procedure. It is typically used to - load modules needed to mount the "real" root file system, - etc. See for details. - - If RAM disk support (BLK_DEV_RAM) is also included, this - also enables initial RAM disk (initrd) support and adds - 15 Kbytes (more on some other architectures) to the kernel size. - - If unsure say Y. - -if BLK_DEV_INITRD - -source "usr/Kconfig" - -endif - -choice - prompt "Compiler optimization level" - default CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE - -config CC_OPTIMIZE_FOR_PERFORMANCE - bool "Optimize for performance" - help - This is the default optimization level for the kernel, building - with the "-O2" compiler flag for best performance and most - helpful compile-time warnings. - -config CC_OPTIMIZE_FOR_SIZE - bool "Optimize for size" - help - Enabling this option will pass "-Os" instead of "-O2" to - your compiler resulting in a smaller kernel. - - If unsure, say N. - -endchoice - -config SYSCTL - bool - -config ANON_INODES - bool - -config HAVE_UID16 - bool - -config SYSCTL_EXCEPTION_TRACE - bool - help - Enable support for /proc/sys/debug/exception-trace. - -config SYSCTL_ARCH_UNALIGN_NO_WARN - bool - help - Enable support for /proc/sys/kernel/ignore-unaligned-usertrap - Allows arch to define/use @no_unaligned_warning to possibly warn - about unaligned access emulation going on under the hood. - -config SYSCTL_ARCH_UNALIGN_ALLOW - bool - help - Enable support for /proc/sys/kernel/unaligned-trap - Allows arches to define/use @unaligned_enabled to runtime toggle - the unaligned access emulation. - see arch/parisc/kernel/unaligned.c for reference - -config HAVE_PCSPKR_PLATFORM - bool - -# interpreter that classic socket filters depend on -config BPF - bool - -menuconfig EXPERT - bool "Configure standard kernel features (expert users)" - # Unhide debug options, to make the on-by-default options visible - select DEBUG_KERNEL - help - This option allows certain base kernel options and settings - to be disabled or tweaked. This is for specialized - environments which can tolerate a "non-standard" kernel. - Only use this if you really know what you are doing. - -config UID16 - bool "Enable 16-bit UID system calls" if EXPERT - depends on HAVE_UID16 && MULTIUSER - default y - help - This enables the legacy 16-bit UID syscall wrappers. - -config MULTIUSER - bool "Multiple users, groups and capabilities support" if EXPERT - default y - help - This option enables support for non-root users, groups and - capabilities. - - If you say N here, all processes will run with UID 0, GID 0, and all - possible capabilities. Saying N here also compiles out support for - system calls related to UIDs, GIDs, and capabilities, such as setuid, - setgid, and capset. - - If unsure, say Y here. - -config SGETMASK_SYSCALL - bool "sgetmask/ssetmask syscalls support" if EXPERT - def_bool PARISC || MN10300 || BLACKFIN || M68K || PPC || MIPS || X86 || SPARC || CRIS || MICROBLAZE || SUPERH - ---help--- - sys_sgetmask and sys_ssetmask are obsolete system calls - no longer supported in libc but still enabled by default in some - architectures. - - If unsure, leave the default option here. - -config SYSFS_SYSCALL - bool "Sysfs syscall support" if EXPERT - default y - ---help--- - sys_sysfs is an obsolete system call no longer supported in libc. - Note that disabling this option is more secure but might break - compatibility with some systems. - - If unsure say Y here. - -config SYSCTL_SYSCALL - bool "Sysctl syscall support" if EXPERT - depends on PROC_SYSCTL - default n - select SYSCTL - ---help--- - sys_sysctl uses binary paths that have been found challenging - to properly maintain and use. The interface in /proc/sys - using paths with ascii names is now the primary path to this - information. - - Almost nothing using the binary sysctl interface so if you are - trying to save some space it is probably safe to disable this, - making your kernel marginally smaller. - - If unsure say N here. - -config KALLSYMS - bool "Load all symbols for debugging/ksymoops" if EXPERT - default y - help - Say Y here to let the kernel print out symbolic crash information and - symbolic stack backtraces. This increases the size of the kernel - somewhat, as all symbols have to be loaded into the kernel image. - -config KALLSYMS_ALL - bool "Include all symbols in kallsyms" - depends on DEBUG_KERNEL && KALLSYMS - help - Normally kallsyms only contains the symbols of functions for nicer - OOPS messages and backtraces (i.e., symbols from the text and inittext - sections). This is sufficient for most cases. And only in very rare - cases (e.g., when a debugger is used) all symbols are required (e.g., - names of variables from the data sections, etc). - - This option makes sure that all symbols are loaded into the kernel - image (i.e., symbols from all sections) in cost of increased kernel - size (depending on the kernel configuration, it may be 300KiB or - something like this). - - Say N unless you really need all symbols. - -config KALLSYMS_ABSOLUTE_PERCPU - bool - depends on KALLSYMS - default X86_64 && SMP - -config KALLSYMS_BASE_RELATIVE - bool - depends on KALLSYMS - default !IA64 && !(TILE && 64BIT) - help - Instead of emitting them as absolute values in the native word size, - emit the symbol references in the kallsyms table as 32-bit entries, - each containing a relative value in the range [base, base + U32_MAX] - or, when KALLSYMS_ABSOLUTE_PERCPU is in effect, each containing either - an absolute value in the range [0, S32_MAX] or a relative value in the - range [base, base + S32_MAX], where base is the lowest relative symbol - address encountered in the image. - - On 64-bit builds, this reduces the size of the address table by 50%, - but more importantly, it results in entries whose values are build - time constants, and no relocation pass is required at runtime to fix - up the entries based on the runtime load address of the kernel. - -config KALLSYMS_USE_DATA_SECTION - bool "Use .data instead of .rodata section for kallsyms" - depends on KALLSYMS - default n - help - Enabling this option will put the kallsyms data in the .data section - instead of the .rodata section. - - This is useful when building the kernel as a library, as it avoids - relocations in the text segment that could otherwise occur if the - .rodata section is in the same segment as the .text section. - -config PRINTK - default y - bool "Enable support for printk" if EXPERT - select IRQ_WORK - help - This option enables normal printk support. Removing it - eliminates most of the message strings from the kernel image - and makes the kernel more or less silent. As this makes it - very difficult to diagnose system problems, saying N here is - strongly discouraged. - -config PRINTK_NMI - def_bool y - depends on PRINTK - depends on HAVE_NMI - -config BUG - bool "BUG() support" if EXPERT - default y - help - Disabling this option eliminates support for BUG and WARN, reducing - the size of your kernel image and potentially quietly ignoring - numerous fatal conditions. You should only consider disabling this - option for embedded systems with no facilities for reporting errors. - Just say Y. - -config ELF_CORE - depends on COREDUMP - default y - bool "Enable ELF core dumps" if EXPERT - help - Enable support for generating core dumps. Disabling saves about 4k. - - -config PCSPKR_PLATFORM - bool "Enable PC-Speaker support" if EXPERT - depends on HAVE_PCSPKR_PLATFORM - select I8253_LOCK - default y - help - This option allows to disable the internal PC-Speaker - support, saving some memory. - -config BASE_FULL - default y - bool "Enable full-sized data structures for core" if EXPERT - help - Disabling this option reduces the size of miscellaneous core - kernel data structures. This saves memory on small machines, - but may reduce performance. - -config FUTEX - bool "Enable futex support" if EXPERT - default y - select RT_MUTEXES - help - Disabling this option will cause the kernel to be built without - support for "fast userspace mutexes". The resulting kernel may not - run glibc-based applications correctly. - -config HAVE_FUTEX_CMPXCHG - bool - depends on FUTEX - help - Architectures should select this if futex_atomic_cmpxchg_inatomic() - is implemented and always working. This removes a couple of runtime - checks. - -config EPOLL - bool "Enable eventpoll support" if EXPERT - default y - select ANON_INODES - help - Disabling this option will cause the kernel to be built without - support for epoll family of system calls. - -config SIGNALFD - bool "Enable signalfd() system call" if EXPERT - select ANON_INODES - default y - help - Enable the signalfd() system call that allows to receive signals - on a file descriptor. - - If unsure, say Y. - -config TIMERFD - bool "Enable timerfd() system call" if EXPERT - select ANON_INODES - default y - help - Enable the timerfd() system call that allows to receive timer - events on a file descriptor. - - If unsure, say Y. - -config EVENTFD - bool "Enable eventfd() system call" if EXPERT - select ANON_INODES - default y - help - Enable the eventfd() system call that allows to receive both - kernel notification (ie. KAIO) or userspace notifications. - - If unsure, say Y. - -# syscall, maps, verifier -config BPF_SYSCALL - bool "Enable bpf() system call" - select ANON_INODES - select BPF - default n - help - Enable the bpf() system call that allows to manipulate eBPF - programs and maps via file descriptors. - -config SHMEM - bool "Use full shmem filesystem" if EXPERT - default y - depends on MMU - help - The shmem is an internal filesystem used to manage shared memory. - It is backed by swap and manages resource limits. It is also exported - to userspace as tmpfs if TMPFS is enabled. Disabling this - option replaces shmem and tmpfs with the much simpler ramfs code, - which may be appropriate on small systems without swap. - -config AIO - bool "Enable AIO support" if EXPERT - default y - help - This option enables POSIX asynchronous I/O which may by used - by some high performance threaded applications. Disabling - this option saves about 7k. - -config ADVISE_SYSCALLS - bool "Enable madvise/fadvise syscalls" if EXPERT - default y - help - This option enables the madvise and fadvise syscalls, used by - applications to advise the kernel about their future memory or file - usage, improving performance. If building an embedded system where no - applications use these syscalls, you can disable this option to save - space. - -config USERFAULTFD - bool "Enable userfaultfd() system call" - select ANON_INODES - depends on MMU - help - Enable the userfaultfd() system call that allows to intercept and - handle page faults in userland. - -config PCI_QUIRKS - default y - bool "Enable PCI quirk workarounds" if EXPERT - depends on PCI - help - This enables workarounds for various PCI chipset - bugs/quirks. Disable this only if your target machine is - unaffected by PCI quirks. - -config MEMBARRIER - bool "Enable membarrier() system call" if EXPERT - default y - help - Enable the membarrier() system call that allows issuing memory - barriers across all running threads, which can be used to distribute - the cost of user-space memory barriers asymmetrically by transforming - pairs of memory barriers into pairs consisting of membarrier() and a - compiler barrier. - - If unsure, say Y. - -config EMBEDDED - bool "Embedded system" - option allnoconfig_y - select EXPERT - help - This option should be enabled if compiling the kernel for - an embedded system so certain expert options are available - for configuration. - -config HAVE_PERF_EVENTS - bool - help - See tools/perf/design.txt for details. - -config PERF_USE_VMALLOC - bool - help - See tools/perf/design.txt for details - -menu "Kernel Performance Events And Counters" - -config PERF_EVENTS - bool "Kernel performance events and counters" - default y if PROFILING - depends on HAVE_PERF_EVENTS - select ANON_INODES - select IRQ_WORK - select SRCU - help - Enable kernel support for various performance events provided - by software and hardware. - - Software events are supported either built-in or via the - use of generic tracepoints. - - Most modern CPUs support performance events via performance - counter registers. These registers count the number of certain - types of hw events: such as instructions executed, cachemisses - suffered, or branches mis-predicted - without slowing down the - kernel or applications. These registers can also trigger interrupts - when a threshold number of events have passed - and can thus be - used to profile the code that runs on that CPU. - - The Linux Performance Event subsystem provides an abstraction of - these software and hardware event capabilities, available via a - system call and used by the "perf" utility in tools/perf/. It - provides per task and per CPU counters, and it provides event - capabilities on top of those. - - Say Y if unsure. - -config DEBUG_PERF_USE_VMALLOC - default n - bool "Debug: use vmalloc to back perf mmap() buffers" - depends on PERF_EVENTS && DEBUG_KERNEL && !PPC - select PERF_USE_VMALLOC - help - Use vmalloc memory to back perf mmap() buffers. - - Mostly useful for debugging the vmalloc code on platforms - that don't require it. - - Say N if unsure. - -endmenu - -config VM_EVENT_COUNTERS - default y - bool "Enable VM event counters for /proc/vmstat" if EXPERT - help - VM event counters are needed for event counts to be shown. - This option allows the disabling of the VM event counters - on EXPERT systems. /proc/vmstat will only show page counts - if VM event counters are disabled. - -config SLUB_DEBUG - default y - bool "Enable SLUB debugging support" if EXPERT - depends on SLUB && SYSFS - help - SLUB has extensive debug support features. Disabling these can - result in significant savings in code size. This also disables - SLUB sysfs support. /sys/slab will not exist and there will be - no support for cache validation etc. - -config COMPAT_BRK - bool "Disable heap randomization" - default y - help - Randomizing heap placement makes heap exploits harder, but it - also breaks ancient binaries (including anything libc5 based). - This option changes the bootup default to heap randomization - disabled, and can be overridden at runtime by setting - /proc/sys/kernel/randomize_va_space to 2. - - On non-ancient distros (post-2000 ones) N is usually a safe choice. - -choice - prompt "Choose SLAB allocator" - default SLUB - help - This option allows to select a slab allocator. - -config SLAB - bool "SLAB" - select HAVE_HARDENED_USERCOPY_ALLOCATOR - help - The regular slab allocator that is established and known to work - well in all environments. It organizes cache hot objects in - per cpu and per node queues. - -config SLUB - bool "SLUB (Unqueued Allocator)" - select HAVE_HARDENED_USERCOPY_ALLOCATOR - help - SLUB is a slab allocator that minimizes cache line usage - instead of managing queues of cached objects (SLAB approach). - Per cpu caching is realized using slabs of objects instead - of queues of objects. SLUB can use memory efficiently - and has enhanced diagnostics. SLUB is the default choice for - a slab allocator. - -config SLOB - depends on EXPERT - bool "SLOB (Simple Allocator)" - help - SLOB replaces the stock allocator with a drastically simpler - allocator. SLOB is generally more space efficient but - does not perform as well on large systems. - -endchoice - -config SLAB_FREELIST_RANDOM - default n - depends on SLAB || SLUB - bool "SLAB freelist randomization" - help - Randomizes the freelist order used on creating new pages. This - security feature reduces the predictability of the kernel slab - allocator against heap overflows. - -config SLUB_CPU_PARTIAL - default y - depends on SLUB && SMP - bool "SLUB per cpu partial cache" - help - Per cpu partial caches accellerate objects allocation and freeing - that is local to a processor at the price of more indeterminism - in the latency of the free. On overflow these caches will be cleared - which requires the taking of locks that may cause latency spikes. - Typically one would choose no for a realtime system. - -config MMAP_ALLOW_UNINITIALIZED - bool "Allow mmapped anonymous memory to be uninitialized" - depends on EXPERT && !MMU - default n - help - Normally, and according to the Linux spec, anonymous memory obtained - from mmap() has it's contents cleared before it is passed to - userspace. Enabling this config option allows you to request that - mmap() skip that if it is given an MAP_UNINITIALIZED flag, thus - providing a huge performance boost. If this option is not enabled, - then the flag will be ignored. - - This is taken advantage of by uClibc's malloc(), and also by - ELF-FDPIC binfmt's brk and stack allocator. - - Because of the obvious security issues, this option should only be - enabled on embedded devices where you control what is run in - userspace. Since that isn't generally a problem on no-MMU systems, - it is normally safe to say Y here. - - See Documentation/nommu-mmap.txt for more information. - -config SYSTEM_DATA_VERIFICATION - def_bool n - select SYSTEM_TRUSTED_KEYRING - select KEYS - select CRYPTO - select CRYPTO_RSA - select ASYMMETRIC_KEY_TYPE - select ASYMMETRIC_PUBLIC_KEY_SUBTYPE - select ASN1 - select OID_REGISTRY - select X509_CERTIFICATE_PARSER - select PKCS7_MESSAGE_PARSER - help - Provide PKCS#7 message verification using the contents of the system - trusted keyring to provide public keys. This then can be used for - module verification, kexec image verification and firmware blob - verification. - -config PROFILING - bool "Profiling support" - help - Say Y here to enable the extended profiling support mechanisms used - by profilers such as OProfile. - -# -# Place an empty function call at each tracepoint site. Can be -# dynamically changed for a probe function. -# -config TRACEPOINTS - bool - -source "arch/Kconfig" - -endmenu # General setup - -config HAVE_GENERIC_DMA_COHERENT - bool - default n - -config SLABINFO - bool - depends on PROC_FS - depends on SLAB || SLUB_DEBUG - default y - -config RT_MUTEXES - bool - -config BASE_SMALL - int - default 0 if BASE_FULL - default 1 if !BASE_FULL - -menuconfig MODULES - bool "Enable loadable module support" - option modules - help - Kernel modules are small pieces of compiled code which can - be inserted in the running kernel, rather than being - permanently built into the kernel. You use the "modprobe" - tool to add (and sometimes remove) them. If you say Y here, - many parts of the kernel can be built as modules (by - answering M instead of Y where indicated): this is most - useful for infrequently used options which are not required - for booting. For more information, see the man pages for - modprobe, lsmod, modinfo, insmod and rmmod. - - If you say Y here, you will need to run "make - modules_install" to put the modules under /lib/modules/ - where modprobe can find them (you may need to be root to do - this). - - If unsure, say Y. - -if MODULES - -config MODULE_FORCE_LOAD - bool "Forced module loading" - default n - help - Allow loading of modules without version information (ie. modprobe - --force). Forced module loading sets the 'F' (forced) taint flag and - is usually a really bad idea. - -config MODULE_UNLOAD - bool "Module unloading" - help - Without this option you will not be able to unload any - modules (note that some modules may not be unloadable - anyway), which makes your kernel smaller, faster - and simpler. If unsure, say Y. - -config MODULE_FORCE_UNLOAD - bool "Forced module unloading" - depends on MODULE_UNLOAD - help - This option allows you to force a module to unload, even if the - kernel believes it is unsafe: the kernel will remove the module - without waiting for anyone to stop using it (using the -f option to - rmmod). This is mainly for kernel developers and desperate users. - If unsure, say N. - -config MODVERSIONS - bool "Module versioning support" - help - Usually, you have to use modules compiled with your kernel. - Saying Y here makes it sometimes possible to use modules - compiled for different kernels, by adding enough information - to the modules to (hopefully) spot any changes which would - make them incompatible with the kernel you are running. If - unsure, say N. - -config MODULE_SRCVERSION_ALL - bool "Source checksum for all modules" - help - Modules which contain a MODULE_VERSION get an extra "srcversion" - field inserted into their modinfo section, which contains a - sum of the source files which made it. This helps maintainers - see exactly which source was used to build a module (since - others sometimes change the module source without updating - the version). With this option, such a "srcversion" field - will be created for all modules. If unsure, say N. - -config MODULE_SIG - bool "Module signature verification" - depends on MODULES - select SYSTEM_DATA_VERIFICATION - help - Check modules for valid signatures upon load: the signature - is simply appended to the module. For more information see - Documentation/module-signing.txt. - - Note that this option adds the OpenSSL development packages as a - kernel build dependency so that the signing tool can use its crypto - library. - - !!!WARNING!!! If you enable this option, you MUST make sure that the - module DOES NOT get stripped after being signed. This includes the - debuginfo strip done by some packagers (such as rpmbuild) and - inclusion into an initramfs that wants the module size reduced. - -config MODULE_SIG_FORCE - bool "Require modules to be validly signed" - depends on MODULE_SIG - help - Reject unsigned modules or signed modules for which we don't have a - key. Without this, such modules will simply taint the kernel. - -config MODULE_SIG_ALL - bool "Automatically sign all modules" - default y - depends on MODULE_SIG - help - Sign all modules during make modules_install. Without this option, - modules must be signed manually, using the scripts/sign-file tool. - -comment "Do not forget to sign required modules with scripts/sign-file" - depends on MODULE_SIG_FORCE && !MODULE_SIG_ALL - -choice - prompt "Which hash algorithm should modules be signed with?" - depends on MODULE_SIG - help - This determines which sort of hashing algorithm will be used during - signature generation. This algorithm _must_ be built into the kernel - directly so that signature verification can take place. It is not - possible to load a signed module containing the algorithm to check - the signature on that module. - -config MODULE_SIG_SHA1 - bool "Sign modules with SHA-1" - select CRYPTO_SHA1 - -config MODULE_SIG_SHA224 - bool "Sign modules with SHA-224" - select CRYPTO_SHA256 - -config MODULE_SIG_SHA256 - bool "Sign modules with SHA-256" - select CRYPTO_SHA256 - -config MODULE_SIG_SHA384 - bool "Sign modules with SHA-384" - select CRYPTO_SHA512 - -config MODULE_SIG_SHA512 - bool "Sign modules with SHA-512" - select CRYPTO_SHA512 - -endchoice - -config MODULE_SIG_HASH - string - depends on MODULE_SIG - default "sha1" if MODULE_SIG_SHA1 - default "sha224" if MODULE_SIG_SHA224 - default "sha256" if MODULE_SIG_SHA256 - default "sha384" if MODULE_SIG_SHA384 - default "sha512" if MODULE_SIG_SHA512 - -config MODULE_COMPRESS - bool "Compress modules on installation" - depends on MODULES - help - - Compresses kernel modules when 'make modules_install' is run; gzip or - xz depending on "Compression algorithm" below. - - module-init-tools MAY support gzip, and kmod MAY support gzip and xz. - - Out-of-tree kernel modules installed using Kbuild will also be - compressed upon installation. - - Note: for modules inside an initrd or initramfs, it's more efficient - to compress the whole initrd or initramfs instead. - - Note: This is fully compatible with signed modules. - - If in doubt, say N. - -choice - prompt "Compression algorithm" - depends on MODULE_COMPRESS - default MODULE_COMPRESS_GZIP - help - This determines which sort of compression will be used during - 'make modules_install'. - - GZIP (default) and XZ are supported. - -config MODULE_COMPRESS_GZIP - bool "GZIP" - -config MODULE_COMPRESS_XZ - bool "XZ" - -endchoice - -config TRIM_UNUSED_KSYMS - bool "Trim unused exported kernel symbols" - depends on MODULES && !UNUSED_SYMBOLS - help - The kernel and some modules make many symbols available for - other modules to use via EXPORT_SYMBOL() and variants. Depending - on the set of modules being selected in your kernel configuration, - many of those exported symbols might never be used. - - This option allows for unused exported symbols to be dropped from - the build. In turn, this provides the compiler more opportunities - (especially when using LTO) for optimizing the code and reducing - binary size. This might have some security advantages as well. - - If unsure, or if you need to build out-of-tree modules, say N. - -endif # MODULES - -config MODULES_TREE_LOOKUP - def_bool y - depends on PERF_EVENTS || TRACING - -config INIT_ALL_POSSIBLE - bool - help - Back when each arch used to define their own cpu_online_mask and - cpu_possible_mask, some of them chose to initialize cpu_possible_mask - with all 1s, and others with all 0s. When they were centralised, - it was better to provide this option than to break all the archs - and have several arch maintainers pursuing me down dark alleys. - -source "block/Kconfig" - -config PREEMPT_NOTIFIERS - bool - -config PADATA - depends on SMP - bool - -config ASN1 - tristate - help - Build a simple ASN.1 grammar compiler that produces a bytecode output - that can be interpreted by the ASN.1 stream decoder and used to - inform it as to what tags are to be expected in a stream and what - functions to call on what tags. - -source "kernel/Kconfig.locks" diff --git a/src/linux/init/Makefile b/src/linux/init/Makefile deleted file mode 100644 index c4fb455..0000000 --- a/src/linux/init/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -# -# Makefile for the linux kernel. -# - -ccflags-y := -fno-function-sections -fno-data-sections - -obj-y := main.o version.o mounts.o -ifneq ($(CONFIG_BLK_DEV_INITRD),y) -obj-y += noinitramfs.o -else -obj-$(CONFIG_BLK_DEV_INITRD) += initramfs.o -endif -obj-$(CONFIG_GENERIC_CALIBRATE_DELAY) += calibrate.o - -ifneq ($(CONFIG_ARCH_INIT_TASK),y) -obj-y += init_task.o -endif - -mounts-y := do_mounts.o -mounts-$(CONFIG_BLK_DEV_RAM) += do_mounts_rd.o -mounts-$(CONFIG_BLK_DEV_INITRD) += do_mounts_initrd.o -mounts-$(CONFIG_BLK_DEV_MD) += do_mounts_md.o - -# dependencies on generated files need to be listed explicitly -$(obj)/version.o: include/generated/compile.h - -# compile.h changes depending on hostname, generation number, etc, -# so we regenerate it always. -# mkcompile_h will make sure to only update the -# actual file if its content has changed. - - chk_compile.h = : - quiet_chk_compile.h = echo ' CHK $@' -silent_chk_compile.h = : -include/generated/compile.h: FORCE - @$($(quiet)chk_compile.h) - $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkcompile_h $@ \ - "$(UTS_MACHINE)" "$(CONFIG_SMP)" "$(CONFIG_PREEMPT)" "$(CC) $(KBUILD_CFLAGS)" diff --git a/src/linux/init/do_mounts.c b/src/linux/init/do_mounts.c deleted file mode 100644 index dea5de9..0000000 --- a/src/linux/init/do_mounts.c +++ /dev/null @@ -1,648 +0,0 @@ -/* - * Many of the syscalls used in this file expect some of the arguments - * to be __user pointers not __kernel pointers. To limit the sparse - * noise, turn off sparse checking for this file. - */ -#ifdef __CHECKER__ -#undef __CHECKER__ -#warning "Sparse checking disabled for this file" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "do_mounts.h" - -int __initdata rd_doload; /* 1 = load RAM disk, 0 = don't load */ - -int root_mountflags = MS_RDONLY | MS_SILENT; -static char * __initdata root_device_name; -static char __initdata saved_root_name[64]; -static int root_wait; - -dev_t ROOT_DEV; - -static int __init load_ramdisk(char *str) -{ - rd_doload = simple_strtol(str,NULL,0) & 3; - return 1; -} -__setup("load_ramdisk=", load_ramdisk); - -static int __init readonly(char *str) -{ - if (*str) - return 0; - root_mountflags |= MS_RDONLY; - return 1; -} - -static int __init readwrite(char *str) -{ - if (*str) - return 0; - root_mountflags &= ~MS_RDONLY; - return 1; -} - -__setup("ro", readonly); -__setup("rw", readwrite); - -#ifdef CONFIG_BLOCK -struct uuidcmp { - const char *uuid; - int len; -}; - -/** - * match_dev_by_uuid - callback for finding a partition using its uuid - * @dev: device passed in by the caller - * @data: opaque pointer to the desired struct uuidcmp to match - * - * Returns 1 if the device matches, and 0 otherwise. - */ -static int match_dev_by_uuid(struct device *dev, const void *data) -{ - const struct uuidcmp *cmp = data; - struct hd_struct *part = dev_to_part(dev); - - if (!part->info) - goto no_match; - - if (strncasecmp(cmp->uuid, part->info->uuid, cmp->len)) - goto no_match; - - return 1; -no_match: - return 0; -} - - -/** - * devt_from_partuuid - looks up the dev_t of a partition by its UUID - * @uuid_str: char array containing ascii UUID - * - * The function will return the first partition which contains a matching - * UUID value in its partition_meta_info struct. This does not search - * by filesystem UUIDs. - * - * If @uuid_str is followed by a "/PARTNROFF=%d", then the number will be - * extracted and used as an offset from the partition identified by the UUID. - * - * Returns the matching dev_t on success or 0 on failure. - */ -static dev_t devt_from_partuuid(const char *uuid_str) -{ - dev_t res = 0; - struct uuidcmp cmp; - struct device *dev = NULL; - struct gendisk *disk; - struct hd_struct *part; - int offset = 0; - bool clear_root_wait = false; - char *slash; - - cmp.uuid = uuid_str; - - slash = strchr(uuid_str, '/'); - /* Check for optional partition number offset attributes. */ - if (slash) { - char c = 0; - /* Explicitly fail on poor PARTUUID syntax. */ - if (sscanf(slash + 1, - "PARTNROFF=%d%c", &offset, &c) != 1) { - clear_root_wait = true; - goto done; - } - cmp.len = slash - uuid_str; - } else { - cmp.len = strlen(uuid_str); - } - - if (!cmp.len) { - clear_root_wait = true; - goto done; - } - - dev = class_find_device(&block_class, NULL, &cmp, - &match_dev_by_uuid); - if (!dev) - goto done; - - res = dev->devt; - - /* Attempt to find the partition by offset. */ - if (!offset) - goto no_offset; - - res = 0; - disk = part_to_disk(dev_to_part(dev)); - part = disk_get_part(disk, dev_to_part(dev)->partno + offset); - if (part) { - res = part_devt(part); - put_device(part_to_dev(part)); - } - -no_offset: - put_device(dev); -done: - if (clear_root_wait) { - pr_err("VFS: PARTUUID= is invalid.\n" - "Expected PARTUUID=[/PARTNROFF=%%d]\n"); - if (root_wait) - pr_err("Disabling rootwait; root= is invalid.\n"); - root_wait = 0; - } - return res; -} -#endif - -/* - * Convert a name into device number. We accept the following variants: - * - * 1) device number in hexadecimal represents itself - * no leading 0x, for example b302. - * 2) /dev/nfs represents Root_NFS (0xff) - * 3) /dev/ represents the device number of disk - * 4) /dev/ represents the device number - * of partition - device number of disk plus the partition number - * 5) /dev/p - same as the above, that form is - * used when disk name of partitioned disk ends on a digit. - * 6) PARTUUID=00112233-4455-6677-8899-AABBCCDDEEFF representing the - * unique id of a partition if the partition table provides it. - * The UUID may be either an EFI/GPT UUID, or refer to an MSDOS - * partition using the format SSSSSSSS-PP, where SSSSSSSS is a zero- - * filled hex representation of the 32-bit "NT disk signature", and PP - * is a zero-filled hex representation of the 1-based partition number. - * 7) PARTUUID=/PARTNROFF= to select a partition in relation to - * a partition with a known unique id. - * 8) : major and minor number of the device separated by - * a colon. - * - * If name doesn't have fall into the categories above, we return (0,0). - * block_class is used to check if something is a disk name. If the disk - * name contains slashes, the device name has them replaced with - * bangs. - */ - -dev_t name_to_dev_t(const char *name) -{ - char s[32]; - char *p; - dev_t res = 0; - int part; - -#ifdef CONFIG_BLOCK - if (strncmp(name, "PARTUUID=", 9) == 0) { - name += 9; - res = devt_from_partuuid(name); - if (!res) - goto fail; - goto done; - } -#endif - - if (strncmp(name, "/dev/", 5) != 0) { - unsigned maj, min, offset; - char dummy; - - if ((sscanf(name, "%u:%u%c", &maj, &min, &dummy) == 2) || - (sscanf(name, "%u:%u:%u:%c", &maj, &min, &offset, &dummy) == 3)) { - res = MKDEV(maj, min); - if (maj != MAJOR(res) || min != MINOR(res)) - goto fail; - } else { - res = new_decode_dev(simple_strtoul(name, &p, 16)); - if (*p) - goto fail; - } - goto done; - } - - name += 5; - res = Root_NFS; - if (strcmp(name, "nfs") == 0) - goto done; - res = Root_RAM0; - if (strcmp(name, "ram") == 0) - goto done; - - if (strlen(name) > 31) - goto fail; - strcpy(s, name); - for (p = s; *p; p++) - if (*p == '/') - *p = '!'; - res = blk_lookup_devt(s, 0); - if (res) - goto done; - - /* - * try non-existent, but valid partition, which may only exist - * after revalidating the disk, like partitioned md devices - */ - while (p > s && isdigit(p[-1])) - p--; - if (p == s || !*p || *p == '0') - goto fail; - - /* try disk name without */ - part = simple_strtoul(p, NULL, 10); - *p = '\0'; - res = blk_lookup_devt(s, part); - if (res) - goto done; - - /* try disk name without p */ - if (p < s + 2 || !isdigit(p[-2]) || p[-1] != 'p') - goto fail; - p[-1] = '\0'; - res = blk_lookup_devt(s, part); - if (res) - goto done; - -fail: - return 0; -done: - return res; -} -EXPORT_SYMBOL_GPL(name_to_dev_t); - -static int __init root_dev_setup(char *line) -{ - strlcpy(saved_root_name, line, sizeof(saved_root_name)); - return 1; -} - -__setup("root=", root_dev_setup); - -static int __init rootwait_setup(char *str) -{ - if (*str) - return 0; - root_wait = 1; - return 1; -} - -__setup("rootwait", rootwait_setup); - -static char * __initdata root_mount_data; -static int __init root_data_setup(char *str) -{ - root_mount_data = str; - return 1; -} - -static char * __initdata root_fs_names; -static int __init fs_names_setup(char *str) -{ - root_fs_names = str; - return 1; -} - -static unsigned int __initdata root_delay; -static int __init root_delay_setup(char *str) -{ - root_delay = simple_strtoul(str, NULL, 0); - return 1; -} - -__setup("rootflags=", root_data_setup); -__setup("rootfstype=", fs_names_setup); -__setup("rootdelay=", root_delay_setup); - -static void __init get_fs_names(char *page) -{ - char *s = page; - - if (root_fs_names) { - strcpy(page, root_fs_names); - while (*s++) { - if (s[-1] == ',') - s[-1] = '\0'; - } - } else { - int len = get_filesystem_list(page); - char *p, *next; - - page[len] = '\0'; - for (p = page-1; p; p = next) { - next = strchr(++p, '\n'); - if (*p++ != '\t') - continue; - while ((*s++ = *p++) != '\n') - ; - s[-1] = '\0'; - } - } - *s = '\0'; -} - -static int __init do_mount_root(char *name, char *fs, int flags, void *data) -{ - struct super_block *s; - int err = sys_mount(name, "/root", fs, flags, data); - if (err) - return err; - - sys_chdir("/root"); - s = current->fs->pwd.dentry->d_sb; - ROOT_DEV = s->s_dev; - printk(KERN_INFO - "VFS: Mounted root (%s filesystem)%s on device %u:%u.\n", - s->s_type->name, - s->s_flags & MS_RDONLY ? " readonly" : "", - MAJOR(ROOT_DEV), MINOR(ROOT_DEV)); - return 0; -} - -void __init mount_block_root(char *name, int flags) -{ - struct page *page = alloc_page(GFP_KERNEL | - __GFP_NOTRACK_FALSE_POSITIVE); - char *fs_names = page_address(page); - char *p; -#ifdef CONFIG_BLOCK - char b[BDEVNAME_SIZE]; -#else - const char *b = name; -#endif - - get_fs_names(fs_names); -retry: - for (p = fs_names; *p; p += strlen(p)+1) { - int err = do_mount_root(name, p, flags, root_mount_data); - switch (err) { - case 0: - goto out; - case -EACCES: - case -EINVAL: - continue; - } - /* - * Allow the user to distinguish between failed sys_open - * and bad superblock on root device. - * and give them a list of the available devices - */ -#ifdef CONFIG_BLOCK - __bdevname(ROOT_DEV, b); -#endif - printk("VFS: Cannot open root device \"%s\" or %s: error %d\n", - root_device_name, b, err); - printk("Please append a correct \"root=\" boot option; here are the available partitions:\n"); - - printk_all_partitions(); -#ifdef CONFIG_DEBUG_BLOCK_EXT_DEVT - printk("DEBUG_BLOCK_EXT_DEVT is enabled, you need to specify " - "explicit textual name for \"root=\" boot option.\n"); -#endif - panic("VFS: Unable to mount root fs on %s", b); - } - if (!(flags & MS_RDONLY)) { - flags |= MS_RDONLY; - goto retry; - } - - printk("List of all partitions:\n"); - printk_all_partitions(); - printk("No filesystem could mount root, tried: "); - for (p = fs_names; *p; p += strlen(p)+1) - printk(" %s", p); - printk("\n"); -#ifdef CONFIG_BLOCK - __bdevname(ROOT_DEV, b); -#endif - panic("VFS: Unable to mount root fs on %s", b); -out: - put_page(page); -} - -#ifdef CONFIG_ROOT_NFS - -#define NFSROOT_TIMEOUT_MIN 5 -#define NFSROOT_TIMEOUT_MAX 30 -#define NFSROOT_RETRY_MAX 5 - -static int __init mount_nfs_root(void) -{ - char *root_dev, *root_data; - unsigned int timeout; - int try, err; - - err = nfs_root_data(&root_dev, &root_data); - if (err != 0) - return 0; - - /* - * The server or network may not be ready, so try several - * times. Stop after a few tries in case the client wants - * to fall back to other boot methods. - */ - timeout = NFSROOT_TIMEOUT_MIN; - for (try = 1; ; try++) { - err = do_mount_root(root_dev, "nfs", - root_mountflags, root_data); - if (err == 0) - return 1; - if (try > NFSROOT_RETRY_MAX) - break; - - /* Wait, in case the server refused us immediately */ - ssleep(timeout); - timeout <<= 1; - if (timeout > NFSROOT_TIMEOUT_MAX) - timeout = NFSROOT_TIMEOUT_MAX; - } - return 0; -} -#endif - -#if defined(CONFIG_BLK_DEV_RAM) || defined(CONFIG_BLK_DEV_FD) -void __init change_floppy(char *fmt, ...) -{ - struct termios termios; - char buf[80]; - char c; - int fd; - va_list args; - va_start(args, fmt); - vsprintf(buf, fmt, args); - va_end(args); - fd = sys_open("/dev/root", O_RDWR | O_NDELAY, 0); - if (fd >= 0) { - sys_ioctl(fd, FDEJECT, 0); - sys_close(fd); - } - printk(KERN_NOTICE "VFS: Insert %s and press ENTER\n", buf); - fd = sys_open("/dev/console", O_RDWR, 0); - if (fd >= 0) { - sys_ioctl(fd, TCGETS, (long)&termios); - termios.c_lflag &= ~ICANON; - sys_ioctl(fd, TCSETSF, (long)&termios); - sys_read(fd, &c, 1); - termios.c_lflag |= ICANON; - sys_ioctl(fd, TCSETSF, (long)&termios); - sys_close(fd); - } -} -#endif - -void __init mount_root(void) -{ -#ifdef CONFIG_ROOT_NFS - if (ROOT_DEV == Root_NFS) { - if (mount_nfs_root()) - return; - - printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n"); - ROOT_DEV = Root_FD0; - } -#endif -#ifdef CONFIG_BLK_DEV_FD - if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { - /* rd_doload is 2 for a dual initrd/ramload setup */ - if (rd_doload==2) { - if (rd_load_disk(1)) { - ROOT_DEV = Root_RAM1; - root_device_name = NULL; - } - } else - change_floppy("root floppy"); - } -#endif -#ifdef CONFIG_BLOCK - { - int err = create_dev("/dev/root", ROOT_DEV); - - if (err < 0) - pr_emerg("Failed to create /dev/root: %d\n", err); - mount_block_root("/dev/root", root_mountflags); - } -#endif -} - -/* - * Prepare the namespace - decide what/where to mount, load ramdisks, etc. - */ -void __init prepare_namespace(void) -{ - int is_floppy; - - if (root_delay) { - printk(KERN_INFO "Waiting %d sec before mounting root device...\n", - root_delay); - ssleep(root_delay); - } - - /* - * wait for the known devices to complete their probing - * - * Note: this is a potential source of long boot delays. - * For example, it is not atypical to wait 5 seconds here - * for the touchpad of a laptop to initialize. - */ - wait_for_device_probe(); - - md_run_setup(); - - if (saved_root_name[0]) { - root_device_name = saved_root_name; - if (!strncmp(root_device_name, "mtd", 3) || - !strncmp(root_device_name, "ubi", 3)) { - mount_block_root(root_device_name, root_mountflags); - goto out; - } - ROOT_DEV = name_to_dev_t(root_device_name); - if (strncmp(root_device_name, "/dev/", 5) == 0) - root_device_name += 5; - } - - if (initrd_load()) - goto out; - - /* wait for any asynchronous scanning to complete */ - if ((ROOT_DEV == 0) && root_wait) { - printk(KERN_INFO "Waiting for root device %s...\n", - saved_root_name); - while (driver_probe_done() != 0 || - (ROOT_DEV = name_to_dev_t(saved_root_name)) == 0) - msleep(100); - async_synchronize_full(); - } - - is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR; - - if (is_floppy && rd_doload && rd_load_disk(0)) - ROOT_DEV = Root_RAM0; - - mount_root(); -out: - devtmpfs_mount("dev"); - sys_mount(".", "/", NULL, MS_MOVE, NULL); - sys_chroot("."); -} - -static bool is_tmpfs; -static struct dentry *rootfs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - static unsigned long once; - void *fill = ramfs_fill_super; - - if (test_and_set_bit(0, &once)) - return ERR_PTR(-ENODEV); - - if (IS_ENABLED(CONFIG_TMPFS) && is_tmpfs) - fill = shmem_fill_super; - - return mount_nodev(fs_type, flags, data, fill); -} - -static struct file_system_type rootfs_fs_type = { - .name = "rootfs", - .mount = rootfs_mount, - .kill_sb = kill_litter_super, -}; - -int __init init_rootfs(void) -{ - int err = register_filesystem(&rootfs_fs_type); - - if (err) - return err; - - if (IS_ENABLED(CONFIG_TMPFS) && !saved_root_name[0] && - (!root_fs_names || strstr(root_fs_names, "tmpfs"))) { - err = shmem_init(); - is_tmpfs = true; - } else { - err = init_ramfs_fs(); - } - - if (err) - unregister_filesystem(&rootfs_fs_type); - - return err; -} diff --git a/src/linux/init/do_mounts.h b/src/linux/init/do_mounts.h deleted file mode 100644 index 067af1d..0000000 --- a/src/linux/init/do_mounts.h +++ /dev/null @@ -1,76 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -void change_floppy(char *fmt, ...); -void mount_block_root(char *name, int flags); -void mount_root(void); -extern int root_mountflags; - -static inline int create_dev(char *name, dev_t dev) -{ - sys_unlink(name); - return sys_mknod(name, S_IFBLK|0600, new_encode_dev(dev)); -} - -#if BITS_PER_LONG == 32 -static inline u32 bstat(char *name) -{ - struct stat64 stat; - if (sys_stat64(name, &stat) != 0) - return 0; - if (!S_ISBLK(stat.st_mode)) - return 0; - if (stat.st_rdev != (u32)stat.st_rdev) - return 0; - return stat.st_rdev; -} -#else -static inline u32 bstat(char *name) -{ - struct stat stat; - if (sys_newstat(name, &stat) != 0) - return 0; - if (!S_ISBLK(stat.st_mode)) - return 0; - return stat.st_rdev; -} -#endif - -#ifdef CONFIG_BLK_DEV_RAM - -int __init rd_load_disk(int n); -int __init rd_load_image(char *from); - -#else - -static inline int rd_load_disk(int n) { return 0; } -static inline int rd_load_image(char *from) { return 0; } - -#endif - -#ifdef CONFIG_BLK_DEV_INITRD - -bool __init initrd_load(void); - -#else - -static inline bool initrd_load(void) { return false; } - -#endif - -#ifdef CONFIG_BLK_DEV_MD - -void md_run_setup(void); - -#else - -static inline void md_run_setup(void) {} - -#endif diff --git a/src/linux/init/init_task.c b/src/linux/init/init_task.c deleted file mode 100644 index 11f83be..0000000 --- a/src/linux/init/init_task.c +++ /dev/null @@ -1,29 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static struct signal_struct init_signals = INIT_SIGNALS(init_signals); -static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); - -/* Initial task structure */ -struct task_struct init_task = INIT_TASK(init_task); -EXPORT_SYMBOL(init_task); - -/* - * Initial thread structure. Alignment of this is handled by a special - * linker map entry. - */ -union thread_union init_thread_union __init_task_data = { -#ifndef CONFIG_THREAD_INFO_IN_TASK - INIT_THREAD_INFO(init_task) -#endif -}; diff --git a/src/linux/init/main.c b/src/linux/init/main.c deleted file mode 100644 index 2858be7..0000000 --- a/src/linux/init/main.c +++ /dev/null @@ -1,1049 +0,0 @@ -/* - * linux/init/main.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * GK 2/5/95 - Changed to support mounting root fs via NFS - * Added initrd & change_root: Werner Almesberger & Hans Lermen, Feb '96 - * Moan early if gcc is old, avoiding bogus kernels - Paul Gortmaker, May '96 - * Simplified starting of init: Michael A. Griffith - */ - -#define DEBUG /* Enable initcall_debug */ - -#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 -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -static int kernel_init(void *); - -extern void init_IRQ(void); -extern void fork_init(void); -extern void radix_tree_init(void); - -/* - * Debug helper: via this flag we know that we are in 'early bootup code' - * where only the boot processor is running with IRQ disabled. This means - * two things - IRQ must not be enabled before the flag is cleared and some - * operations which are not allowed with IRQ disabled are allowed while the - * flag is set. - */ -bool early_boot_irqs_disabled __read_mostly; - -enum system_states system_state __read_mostly; -EXPORT_SYMBOL(system_state); - -/* - * Boot command-line arguments - */ -#define MAX_INIT_ARGS CONFIG_INIT_ENV_ARG_LIMIT -#define MAX_INIT_ENVS CONFIG_INIT_ENV_ARG_LIMIT - -extern void time_init(void); -/* Default late time init is NULL. archs can override this later. */ -void (*__initdata late_time_init)(void); - -/* Untouched command line saved by arch-specific code. */ -char __initdata boot_command_line[COMMAND_LINE_SIZE]; -/* Untouched saved command line (eg. for /proc) */ -char *saved_command_line; -/* Command line for parameter parsing */ -static char *static_command_line; -/* Command line for per-initcall parameter parsing */ -static char *initcall_command_line; - -static char *execute_command; -static char *ramdisk_execute_command; - -/* - * Used to generate warnings if static_key manipulation functions are used - * before jump_label_init is called. - */ -bool static_key_initialized __read_mostly; -EXPORT_SYMBOL_GPL(static_key_initialized); - -/* - * If set, this is an indication to the drivers that reset the underlying - * device before going ahead with the initialization otherwise driver might - * rely on the BIOS and skip the reset operation. - * - * This is useful if kernel is booting in an unreliable environment. - * For ex. kdump situation where previous kernel has crashed, BIOS has been - * skipped and devices will be in unknown state. - */ -unsigned int reset_devices; -EXPORT_SYMBOL(reset_devices); - -static int __init set_reset_devices(char *str) -{ - reset_devices = 1; - return 1; -} - -__setup("reset_devices", set_reset_devices); - -static const char *argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; -const char *envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; -static const char *panic_later, *panic_param; - -extern const struct obs_kernel_param __setup_start[], __setup_end[]; - -static bool __init obsolete_checksetup(char *line) -{ - const struct obs_kernel_param *p; - bool had_early_param = false; - - p = __setup_start; - do { - int n = strlen(p->str); - if (parameqn(line, p->str, n)) { - if (p->early) { - /* Already done in parse_early_param? - * (Needs exact match on param part). - * Keep iterating, as we can have early - * params and __setups of same names 8( */ - if (line[n] == '\0' || line[n] == '=') - had_early_param = true; - } else if (!p->setup_func) { - pr_warn("Parameter %s is obsolete, ignored\n", - p->str); - return true; - } else if (p->setup_func(line + n)) - return true; - } - p++; - } while (p < __setup_end); - - return had_early_param; -} - -/* - * This should be approx 2 Bo*oMips to start (note initial shift), and will - * still work even if initially too large, it will just take slightly longer - */ -unsigned long loops_per_jiffy = (1<<12); -EXPORT_SYMBOL(loops_per_jiffy); - -static int __init debug_kernel(char *str) -{ - console_loglevel = CONSOLE_LOGLEVEL_DEBUG; - return 0; -} - -static int __init quiet_kernel(char *str) -{ - console_loglevel = CONSOLE_LOGLEVEL_QUIET; - return 0; -} - -early_param("debug", debug_kernel); -early_param("quiet", quiet_kernel); - -static int __init loglevel(char *str) -{ - int newlevel; - - /* - * Only update loglevel value when a correct setting was passed, - * to prevent blind crashes (when loglevel being set to 0) that - * are quite hard to debug - */ - if (get_option(&str, &newlevel)) { - console_loglevel = newlevel; - return 0; - } - - return -EINVAL; -} - -early_param("loglevel", loglevel); - -/* Change NUL term back to "=", to make "param" the whole string. */ -static int __init repair_env_string(char *param, char *val, - const char *unused, void *arg) -{ - if (val) { - /* param=val or param="val"? */ - if (val == param+strlen(param)+1) - val[-1] = '='; - else if (val == param+strlen(param)+2) { - val[-2] = '='; - memmove(val-1, val, strlen(val)+1); - val--; - } else - BUG(); - } - return 0; -} - -/* Anything after -- gets handed straight to init. */ -static int __init set_init_arg(char *param, char *val, - const char *unused, void *arg) -{ - unsigned int i; - - if (panic_later) - return 0; - - repair_env_string(param, val, unused, NULL); - - for (i = 0; argv_init[i]; i++) { - if (i == MAX_INIT_ARGS) { - panic_later = "init"; - panic_param = param; - return 0; - } - } - argv_init[i] = param; - return 0; -} - -/* - * Unknown boot options get handed to init, unless they look like - * unused parameters (modprobe will find them in /proc/cmdline). - */ -static int __init unknown_bootoption(char *param, char *val, - const char *unused, void *arg) -{ - repair_env_string(param, val, unused, NULL); - - /* Handle obsolete-style parameters */ - if (obsolete_checksetup(param)) - return 0; - - /* Unused module parameter. */ - if (strchr(param, '.') && (!val || strchr(param, '.') < val)) - return 0; - - if (panic_later) - return 0; - - if (val) { - /* Environment option */ - unsigned int i; - for (i = 0; envp_init[i]; i++) { - if (i == MAX_INIT_ENVS) { - panic_later = "env"; - panic_param = param; - } - if (!strncmp(param, envp_init[i], val - param)) - break; - } - envp_init[i] = param; - } else { - /* Command line option */ - unsigned int i; - for (i = 0; argv_init[i]; i++) { - if (i == MAX_INIT_ARGS) { - panic_later = "init"; - panic_param = param; - } - } - argv_init[i] = param; - } - return 0; -} - -static int __init init_setup(char *str) -{ - unsigned int i; - - execute_command = str; - /* - * In case LILO is going to boot us with default command line, - * it prepends "auto" before the whole cmdline which makes - * the shell think it should execute a script with such name. - * So we ignore all arguments entered _before_ init=... [MJ] - */ - for (i = 1; i < MAX_INIT_ARGS; i++) - argv_init[i] = NULL; - return 1; -} -__setup("init=", init_setup); - -static int __init rdinit_setup(char *str) -{ - unsigned int i; - - ramdisk_execute_command = str; - /* See "auto" comment in init_setup */ - for (i = 1; i < MAX_INIT_ARGS; i++) - argv_init[i] = NULL; - return 1; -} -__setup("rdinit=", rdinit_setup); - -#ifndef CONFIG_SMP -static const unsigned int setup_max_cpus = NR_CPUS; -static inline void setup_nr_cpu_ids(void) { } -static inline void smp_prepare_cpus(unsigned int maxcpus) { } -#endif - -/* - * We need to store the untouched command line for future reference. - * We also need to store the touched command line since the parameter - * parsing is performed in place, and we should allow a component to - * store reference of name/value for future reference. - */ -static void __init setup_command_line(char *command_line) -{ - saved_command_line = - memblock_virt_alloc(strlen(boot_command_line) + 1, 0); - initcall_command_line = - memblock_virt_alloc(strlen(boot_command_line) + 1, 0); - static_command_line = memblock_virt_alloc(strlen(command_line) + 1, 0); - strcpy(saved_command_line, boot_command_line); - strcpy(static_command_line, command_line); -} - -/* - * We need to finalize in a non-__init function or else race conditions - * between the root thread and the init thread may cause start_kernel to - * be reaped by free_initmem before the root thread has proceeded to - * cpu_idle. - * - * gcc-3.4 accidentally inlines this function, so use noinline. - */ - -static __initdata DECLARE_COMPLETION(kthreadd_done); - -static noinline void __ref rest_init(void) -{ - int pid; - - rcu_scheduler_starting(); - /* - * We need to spawn init first so that it obtains pid 1, however - * the init task will end up wanting to create kthreads, which, if - * we schedule it before we create kthreadd, will OOPS. - */ - kernel_thread(kernel_init, NULL, CLONE_FS); - numa_default_policy(); - pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES); - rcu_read_lock(); - kthreadd_task = find_task_by_pid_ns(pid, &init_pid_ns); - rcu_read_unlock(); - complete(&kthreadd_done); - - /* - * The boot idle thread must execute schedule() - * at least once to get things moving: - */ - init_idle_bootup_task(current); - schedule_preempt_disabled(); - /* Call into cpu_idle with preempt disabled */ - cpu_startup_entry(CPUHP_ONLINE); -} - -/* Check for early params. */ -static int __init do_early_param(char *param, char *val, - const char *unused, void *arg) -{ - const struct obs_kernel_param *p; - - for (p = __setup_start; p < __setup_end; p++) { - if ((p->early && parameq(param, p->str)) || - (strcmp(param, "console") == 0 && - strcmp(p->str, "earlycon") == 0) - ) { - if (p->setup_func(val) != 0) - pr_warn("Malformed early option '%s'\n", param); - } - } - /* We accept everything at this stage. */ - return 0; -} - -void __init parse_early_options(char *cmdline) -{ - parse_args("early options", cmdline, NULL, 0, 0, 0, NULL, - do_early_param); -} - -/* Arch code calls this early on, or if not, just before other parsing. */ -void __init parse_early_param(void) -{ - static int done __initdata; - static char tmp_cmdline[COMMAND_LINE_SIZE] __initdata; - - if (done) - return; - - /* All fall through to do_early_param. */ - strlcpy(tmp_cmdline, boot_command_line, COMMAND_LINE_SIZE); - parse_early_options(tmp_cmdline); - done = 1; -} - -void __init __weak smp_setup_processor_id(void) -{ -} - -# if THREAD_SIZE >= PAGE_SIZE -void __init __weak thread_stack_cache_init(void) -{ -} -#endif - -/* - * Set up kernel memory allocators - */ -static void __init mm_init(void) -{ - /* - * page_ext requires contiguous pages, - * bigger than MAX_ORDER unless SPARSEMEM. - */ - page_ext_init_flatmem(); - mem_init(); - kmem_cache_init(); - percpu_init_late(); - pgtable_init(); - vmalloc_init(); - ioremap_huge_init(); -} - -asmlinkage __visible void __init start_kernel(void) -{ - char *command_line; - char *after_dashes; - - set_task_stack_end_magic(&init_task); - smp_setup_processor_id(); - debug_objects_early_init(); - - /* - * Set up the the initial canary ASAP: - */ - boot_init_stack_canary(); - - cgroup_init_early(); - - local_irq_disable(); - early_boot_irqs_disabled = true; - -/* - * Interrupts are still disabled. Do necessary setups, then - * enable them - */ - boot_cpu_init(); - page_address_init(); - pr_notice("%s", linux_banner); - setup_arch(&command_line); - mm_init_cpumask(&init_mm); - setup_command_line(command_line); - setup_nr_cpu_ids(); - setup_per_cpu_areas(); - boot_cpu_state_init(); - smp_prepare_boot_cpu(); /* arch-specific boot-cpu hooks */ - - build_all_zonelists(NULL, NULL); - page_alloc_init(); - - pr_notice("Kernel command line: %s\n", boot_command_line); - parse_early_param(); - after_dashes = parse_args("Booting kernel", - static_command_line, __start___param, - __stop___param - __start___param, - -1, -1, NULL, &unknown_bootoption); - if (!IS_ERR_OR_NULL(after_dashes)) - parse_args("Setting init args", after_dashes, NULL, 0, -1, -1, - NULL, set_init_arg); - - jump_label_init(); - - /* - * These use large bootmem allocations and must precede - * kmem_cache_init() - */ - setup_log_buf(0); - pidhash_init(); - vfs_caches_init_early(); - sort_main_extable(); - trap_init(); - mm_init(); - - /* - * Set up the scheduler prior starting any interrupts (such as the - * timer interrupt). Full topology setup happens at smp_init() - * time - but meanwhile we still have a functioning scheduler. - */ - sched_init(); - /* - * Disable preemption - early bootup scheduling is extremely - * fragile until we cpu_idle() for the first time. - */ - preempt_disable(); - if (WARN(!irqs_disabled(), - "Interrupts were enabled *very* early, fixing it\n")) - local_irq_disable(); - idr_init_cache(); - rcu_init(); - - /* trace_printk() and trace points may be used after this */ - trace_init(); - - context_tracking_init(); - radix_tree_init(); - /* init some links before init_ISA_irqs() */ - early_irq_init(); - init_IRQ(); - tick_init(); - rcu_init_nohz(); - init_timers(); - hrtimers_init(); - softirq_init(); - timekeeping_init(); - time_init(); - sched_clock_postinit(); - printk_nmi_init(); - perf_event_init(); - profile_init(); - call_function_init(); - WARN(!irqs_disabled(), "Interrupts were enabled early\n"); - early_boot_irqs_disabled = false; - local_irq_enable(); - - kmem_cache_init_late(); - - /* - * HACK ALERT! This is early. We're enabling the console before - * we've done PCI setups etc, and console_init() must be aware of - * this. But we do want output early, in case something goes wrong. - */ - console_init(); - if (panic_later) - panic("Too many boot %s vars at `%s'", panic_later, - panic_param); - - lockdep_info(); - - /* - * Need to run this when irqs are enabled, because it wants - * to self-test [hard/soft]-irqs on/off lock inversion bugs - * too: - */ - locking_selftest(); - -#ifdef CONFIG_BLK_DEV_INITRD - if (initrd_start && !initrd_below_start_ok && - page_to_pfn(virt_to_page((void *)initrd_start)) < min_low_pfn) { - pr_crit("initrd overwritten (0x%08lx < 0x%08lx) - disabling it.\n", - page_to_pfn(virt_to_page((void *)initrd_start)), - min_low_pfn); - initrd_start = 0; - } -#endif - page_ext_init(); - debug_objects_mem_init(); - kmemleak_init(); - setup_per_cpu_pageset(); - numa_policy_init(); - if (late_time_init) - late_time_init(); - sched_clock_init(); - calibrate_delay(); - pidmap_init(); - anon_vma_init(); - acpi_early_init(); -#ifdef CONFIG_X86 - if (efi_enabled(EFI_RUNTIME_SERVICES)) - efi_enter_virtual_mode(); -#endif -#ifdef CONFIG_X86_ESPFIX64 - /* Should be run before the first non-init thread is created */ - init_espfix_bsp(); -#endif - thread_stack_cache_init(); - cred_init(); - fork_init(); - proc_caches_init(); - buffer_init(); - key_init(); - security_init(); - dbg_late_init(); - vfs_caches_init(); - signals_init(); - /* rootfs populating might need page-writeback */ - page_writeback_init(); - proc_root_init(); - nsfs_init(); - cpuset_init(); - cgroup_init(); - taskstats_init_early(); - delayacct_init(); - - check_bugs(); - - acpi_subsystem_init(); - sfi_init_late(); - - if (efi_enabled(EFI_RUNTIME_SERVICES)) { - efi_late_init(); - efi_free_boot_services(); - } - - ftrace_init(); - - /* Do the rest non-__init'ed, we're now alive */ - rest_init(); -} - -/* Call all constructor functions linked into the kernel. */ -static void __init do_ctors(void) -{ -#ifdef CONFIG_CONSTRUCTORS - ctor_fn_t *fn = (ctor_fn_t *) __ctors_start; - - for (; fn < (ctor_fn_t *) __ctors_end; fn++) - (*fn)(); -#endif -} - -bool initcall_debug; -core_param(initcall_debug, initcall_debug, bool, 0644); - -#ifdef CONFIG_KALLSYMS -struct blacklist_entry { - struct list_head next; - char *buf; -}; - -static __initdata_or_module LIST_HEAD(blacklisted_initcalls); - -static int __init initcall_blacklist(char *str) -{ - char *str_entry; - struct blacklist_entry *entry; - - /* str argument is a comma-separated list of functions */ - do { - str_entry = strsep(&str, ","); - if (str_entry) { - pr_debug("blacklisting initcall %s\n", str_entry); - entry = alloc_bootmem(sizeof(*entry)); - entry->buf = alloc_bootmem(strlen(str_entry) + 1); - strcpy(entry->buf, str_entry); - list_add(&entry->next, &blacklisted_initcalls); - } - } while (str_entry); - - return 0; -} - -static bool __init_or_module initcall_blacklisted(initcall_t fn) -{ - struct blacklist_entry *entry; - char fn_name[KSYM_SYMBOL_LEN]; - unsigned long addr; - - if (list_empty(&blacklisted_initcalls)) - return false; - - addr = (unsigned long) dereference_function_descriptor(fn); - sprint_symbol_no_offset(fn_name, addr); - - /* - * fn will be "function_name [module_name]" where [module_name] is not - * displayed for built-in init functions. Strip off the [module_name]. - */ - strreplace(fn_name, ' ', '\0'); - - list_for_each_entry(entry, &blacklisted_initcalls, next) { - if (!strcmp(fn_name, entry->buf)) { - pr_debug("initcall %s blacklisted\n", fn_name); - return true; - } - } - - return false; -} -#else -static int __init initcall_blacklist(char *str) -{ - pr_warn("initcall_blacklist requires CONFIG_KALLSYMS\n"); - return 0; -} - -static bool __init_or_module initcall_blacklisted(initcall_t fn) -{ - return false; -} -#endif -__setup("initcall_blacklist=", initcall_blacklist); - -static int __init_or_module do_one_initcall_debug(initcall_t fn) -{ - ktime_t calltime, delta, rettime; - unsigned long long duration; - int ret; - - printk(KERN_DEBUG "calling %pF @ %i\n", fn, task_pid_nr(current)); - calltime = ktime_get(); - ret = fn(); - rettime = ktime_get(); - delta = ktime_sub(rettime, calltime); - duration = (unsigned long long) ktime_to_ns(delta) >> 10; - printk(KERN_DEBUG "initcall %pF returned %d after %lld usecs\n", - fn, ret, duration); - - return ret; -} - -int __init_or_module do_one_initcall(initcall_t fn) -{ - int count = preempt_count(); - int ret; - char msgbuf[64]; - - if (initcall_blacklisted(fn)) - return -EPERM; - - if (initcall_debug) - ret = do_one_initcall_debug(fn); - else - ret = fn(); - - msgbuf[0] = 0; - - if (preempt_count() != count) { - sprintf(msgbuf, "preemption imbalance "); - preempt_count_set(count); - } - if (irqs_disabled()) { - strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf)); - local_irq_enable(); - } - WARN(msgbuf[0], "initcall %pF returned with %s\n", fn, msgbuf); - - add_latent_entropy(); - return ret; -} - - -extern initcall_t __initcall_start[]; -extern initcall_t __initcall0_start[]; -extern initcall_t __initcall1_start[]; -extern initcall_t __initcall2_start[]; -extern initcall_t __initcall3_start[]; -extern initcall_t __initcall4_start[]; -extern initcall_t __initcall5_start[]; -extern initcall_t __initcall6_start[]; -extern initcall_t __initcall7_start[]; -extern initcall_t __initcall_end[]; - -static initcall_t *initcall_levels[] __initdata = { - __initcall0_start, - __initcall1_start, - __initcall2_start, - __initcall3_start, - __initcall4_start, - __initcall5_start, - __initcall6_start, - __initcall7_start, - __initcall_end, -}; - -/* Keep these in sync with initcalls in include/linux/init.h */ -static char *initcall_level_names[] __initdata = { - "early", - "core", - "postcore", - "arch", - "subsys", - "fs", - "device", - "late", -}; - -static void __init do_initcall_level(int level) -{ - initcall_t *fn; - - strcpy(initcall_command_line, saved_command_line); - parse_args(initcall_level_names[level], - initcall_command_line, __start___param, - __stop___param - __start___param, - level, level, - NULL, &repair_env_string); - - for (fn = initcall_levels[level]; fn < initcall_levels[level+1]; fn++) - do_one_initcall(*fn); -} - -static void __init do_initcalls(void) -{ - int level; - - for (level = 0; level < ARRAY_SIZE(initcall_levels) - 1; level++) - do_initcall_level(level); -} - -/* - * Ok, the machine is now initialized. None of the devices - * have been touched yet, but the CPU subsystem is up and - * running, and memory and process management works. - * - * Now we can finally start doing some real work.. - */ -static void __init do_basic_setup(void) -{ - cpuset_init_smp(); - shmem_init(); - driver_init(); - init_irq_proc(); - do_ctors(); - usermodehelper_enable(); - do_initcalls(); - random_int_secret_init(); -} - -static void __init do_pre_smp_initcalls(void) -{ - initcall_t *fn; - - for (fn = __initcall_start; fn < __initcall0_start; fn++) - do_one_initcall(*fn); -} - -/* - * This function requests modules which should be loaded by default and is - * called twice right after initrd is mounted and right before init is - * exec'd. If such modules are on either initrd or rootfs, they will be - * loaded before control is passed to userland. - */ -void __init load_default_modules(void) -{ - load_default_elevator_module(); -} - -static int run_init_process(const char *init_filename) -{ - argv_init[0] = init_filename; - return do_execve(getname_kernel(init_filename), - (const char __user *const __user *)argv_init, - (const char __user *const __user *)envp_init); -} - -static int try_to_run_init_process(const char *init_filename) -{ - int ret; - - ret = run_init_process(init_filename); - - if (ret && ret != -ENOENT) { - pr_err("Starting init: %s exists but couldn't execute it (error %d)\n", - init_filename, ret); - } - - return ret; -} - -static noinline void __init kernel_init_freeable(void); - -#ifdef CONFIG_DEBUG_RODATA -static bool rodata_enabled = true; -static int __init set_debug_rodata(char *str) -{ - return strtobool(str, &rodata_enabled); -} -__setup("rodata=", set_debug_rodata); - -static void mark_readonly(void) -{ - if (rodata_enabled) - mark_rodata_ro(); - else - pr_info("Kernel memory protection disabled.\n"); -} -#else -static inline void mark_readonly(void) -{ - pr_warn("This architecture does not have kernel memory protection.\n"); -} -#endif - -static int __ref kernel_init(void *unused) -{ - int ret; - - kernel_init_freeable(); - /* need to finish all async __init code before freeing the memory */ - async_synchronize_full(); - free_initmem(); - mark_readonly(); - system_state = SYSTEM_RUNNING; - numa_default_policy(); - - flush_delayed_fput(); - - rcu_end_inkernel_boot(); - - if (ramdisk_execute_command) { - ret = run_init_process(ramdisk_execute_command); - if (!ret) - return 0; - pr_err("Failed to execute %s (error %d)\n", - ramdisk_execute_command, ret); - } - - /* - * We try each of these until one succeeds. - * - * The Bourne shell can be used instead of init if we are - * trying to recover a really broken machine. - */ - if (execute_command) { - ret = run_init_process(execute_command); - if (!ret) - return 0; - panic("Requested init %s failed (error %d).", - execute_command, ret); - } - if (!try_to_run_init_process("/sbin/init") || - !try_to_run_init_process("/etc/init") || - !try_to_run_init_process("/bin/init") || - !try_to_run_init_process("/bin/sh")) - return 0; - - panic("No working init found. Try passing init= option to kernel. " - "See Linux Documentation/init.txt for guidance."); -} - -static noinline void __init kernel_init_freeable(void) -{ - /* - * Wait until kthreadd is all set-up. - */ - wait_for_completion(&kthreadd_done); - - /* Now the scheduler is fully set up and can do blocking allocations */ - gfp_allowed_mask = __GFP_BITS_MASK; - - /* - * init can allocate pages on any node - */ - set_mems_allowed(node_states[N_MEMORY]); - /* - * init can run on any cpu. - */ - set_cpus_allowed_ptr(current, cpu_all_mask); - - cad_pid = task_pid(current); - - smp_prepare_cpus(setup_max_cpus); - - do_pre_smp_initcalls(); - lockup_detector_init(); - - smp_init(); - sched_init_smp(); - - page_alloc_init_late(); - - do_basic_setup(); - - /* Open the /dev/console on the rootfs, this should never fail */ - if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0) - pr_err("Warning: unable to open an initial console.\n"); - - (void) sys_dup(0); - (void) sys_dup(0); - /* - * check if there is an early userspace init. If yes, let it do all - * the work - */ - - if (!ramdisk_execute_command) - ramdisk_execute_command = "/init"; - - if (sys_access((const char __user *) ramdisk_execute_command, 0) != 0) { - ramdisk_execute_command = NULL; - prepare_namespace(); - } - - /* - * Ok, we have completed the initial bootup, and - * we're essentially up and running. Get rid of the - * initmem segments and start the user-mode stuff.. - * - * rootfs is available now, try loading the public keys - * and default modules - */ - - integrity_load_keys(); - load_default_modules(); -} diff --git a/src/linux/init/noinitramfs.c b/src/linux/init/noinitramfs.c deleted file mode 100644 index 267739d..0000000 --- a/src/linux/init/noinitramfs.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * init/noinitramfs.c - * - * Copyright (C) 2006, NXP Semiconductors, All Rights Reserved - * Author: Jean-Paul Saman - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include -#include - -/* - * Create a simple rootfs that is similar to the default initramfs - */ -static int __init default_rootfs(void) -{ - int err; - - err = sys_mkdir((const char __user __force *) "/dev", 0755); - if (err < 0) - goto out; - - err = sys_mknod((const char __user __force *) "/dev/console", - S_IFCHR | S_IRUSR | S_IWUSR, - new_encode_dev(MKDEV(5, 1))); - if (err < 0) - goto out; - - err = sys_mkdir((const char __user __force *) "/root", 0700); - if (err < 0) - goto out; - - return 0; - -out: - printk(KERN_WARNING "Failed to create a rootfs\n"); - return err; -} -rootfs_initcall(default_rootfs); diff --git a/src/linux/init/version.c b/src/linux/init/version.c deleted file mode 100644 index fe41a63..0000000 --- a/src/linux/init/version.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * linux/init/version.c - * - * Copyright (C) 1992 Theodore Ts'o - * - * May be freely distributed as part of Linux. - */ - -#include -#include -#include -#include -#include -#include -#include - -#ifndef CONFIG_KALLSYMS -#define version(a) Version_ ## a -#define version_string(a) version(a) - -extern int version_string(LINUX_VERSION_CODE); -int version_string(LINUX_VERSION_CODE); -#endif - -struct uts_namespace init_uts_ns = { - .kref = { - .refcount = ATOMIC_INIT(2), - }, - .name = { - .sysname = UTS_SYSNAME, - .nodename = UTS_NODENAME, - .release = UTS_RELEASE, - .version = UTS_VERSION, - .machine = UTS_MACHINE, - .domainname = UTS_DOMAINNAME, - }, - .user_ns = &init_user_ns, - .ns.inum = PROC_UTS_INIT_INO, -#ifdef CONFIG_UTS_NS - .ns.ops = &utsns_operations, -#endif -}; -EXPORT_SYMBOL_GPL(init_uts_ns); - -/* FIXED STRINGS! Don't touch! */ -const char linux_banner[] = - "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" - LINUX_COMPILE_HOST ") (" LINUX_COMPILER ") " UTS_VERSION "\n"; - -const char linux_proc_banner[] = - "%s version %s" - " (" LINUX_COMPILE_BY "@" LINUX_COMPILE_HOST ")" - " (" LINUX_COMPILER ") %s\n"; diff --git a/src/linux/ipc/Makefile b/src/linux/ipc/Makefile deleted file mode 100644 index 86c7300..0000000 --- a/src/linux/ipc/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# -# Makefile for the linux ipc. -# - -obj-$(CONFIG_SYSVIPC_COMPAT) += compat.o -obj-$(CONFIG_SYSVIPC) += util.o msgutil.o msg.o sem.o shm.o syscall.o -obj-$(CONFIG_SYSVIPC_SYSCTL) += ipc_sysctl.o -obj_mq-$(CONFIG_COMPAT) += compat_mq.o -obj-$(CONFIG_POSIX_MQUEUE) += mqueue.o msgutil.o $(obj_mq-y) -obj-$(CONFIG_IPC_NS) += namespace.o -obj-$(CONFIG_POSIX_MQUEUE_SYSCTL) += mq_sysctl.o - diff --git a/src/linux/kernel/.gitignore b/src/linux/kernel/.gitignore deleted file mode 100644 index b3097bd..0000000 --- a/src/linux/kernel/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# -# Generated files -# -config_data.h -config_data.gz -timeconst.h -hz.bc diff --git a/src/linux/kernel/Kconfig.hz b/src/linux/kernel/Kconfig.hz deleted file mode 100644 index 2a202a8..0000000 --- a/src/linux/kernel/Kconfig.hz +++ /dev/null @@ -1,58 +0,0 @@ -# -# Timer Interrupt Frequency Configuration -# - -choice - prompt "Timer frequency" - default HZ_250 - help - Allows the configuration of the timer frequency. It is customary - to have the timer interrupt run at 1000 Hz but 100 Hz may be more - beneficial for servers and NUMA systems that do not need to have - a fast response for user interaction and that may experience bus - contention and cacheline bounces as a result of timer interrupts. - Note that the timer interrupt occurs on each processor in an SMP - environment leading to NR_CPUS * HZ number of timer interrupts - per second. - - - config HZ_100 - bool "100 HZ" - help - 100 Hz is a typical choice for servers, SMP and NUMA systems - with lots of processors that may show reduced performance if - too many timer interrupts are occurring. - - config HZ_250 - bool "250 HZ" - help - 250 Hz is a good compromise choice allowing server performance - while also showing good interactive responsiveness even - on SMP and NUMA systems. If you are going to be using NTSC video - or multimedia, selected 300Hz instead. - - config HZ_300 - bool "300 HZ" - help - 300 Hz is a good compromise choice allowing server performance - while also showing good interactive responsiveness even - on SMP and NUMA systems and exactly dividing by both PAL and - NTSC frame rates for video and multimedia work. - - config HZ_1000 - bool "1000 HZ" - help - 1000 Hz is the preferred choice for desktop systems and other - systems requiring fast interactive responses to events. - -endchoice - -config HZ - int - default 100 if HZ_100 - default 250 if HZ_250 - default 300 if HZ_300 - default 1000 if HZ_1000 - -config SCHED_HRTICK - def_bool HIGH_RES_TIMERS diff --git a/src/linux/kernel/Kconfig.locks b/src/linux/kernel/Kconfig.locks deleted file mode 100644 index ebdb004..0000000 --- a/src/linux/kernel/Kconfig.locks +++ /dev/null @@ -1,250 +0,0 @@ -# -# The ARCH_INLINE foo is necessary because select ignores "depends on" -# -config ARCH_INLINE_SPIN_TRYLOCK - bool - -config ARCH_INLINE_SPIN_TRYLOCK_BH - bool - -config ARCH_INLINE_SPIN_LOCK - bool - -config ARCH_INLINE_SPIN_LOCK_BH - bool - -config ARCH_INLINE_SPIN_LOCK_IRQ - bool - -config ARCH_INLINE_SPIN_LOCK_IRQSAVE - bool - -config ARCH_INLINE_SPIN_UNLOCK - bool - -config ARCH_INLINE_SPIN_UNLOCK_BH - bool - -config ARCH_INLINE_SPIN_UNLOCK_IRQ - bool - -config ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE - bool - - -config ARCH_INLINE_READ_TRYLOCK - bool - -config ARCH_INLINE_READ_LOCK - bool - -config ARCH_INLINE_READ_LOCK_BH - bool - -config ARCH_INLINE_READ_LOCK_IRQ - bool - -config ARCH_INLINE_READ_LOCK_IRQSAVE - bool - -config ARCH_INLINE_READ_UNLOCK - bool - -config ARCH_INLINE_READ_UNLOCK_BH - bool - -config ARCH_INLINE_READ_UNLOCK_IRQ - bool - -config ARCH_INLINE_READ_UNLOCK_IRQRESTORE - bool - - -config ARCH_INLINE_WRITE_TRYLOCK - bool - -config ARCH_INLINE_WRITE_LOCK - bool - -config ARCH_INLINE_WRITE_LOCK_BH - bool - -config ARCH_INLINE_WRITE_LOCK_IRQ - bool - -config ARCH_INLINE_WRITE_LOCK_IRQSAVE - bool - -config ARCH_INLINE_WRITE_UNLOCK - bool - -config ARCH_INLINE_WRITE_UNLOCK_BH - bool - -config ARCH_INLINE_WRITE_UNLOCK_IRQ - bool - -config ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE - bool - -config UNINLINE_SPIN_UNLOCK - bool - -# -# lock_* functions are inlined when: -# - DEBUG_SPINLOCK=n and GENERIC_LOCKBREAK=n and ARCH_INLINE_*LOCK=y -# -# trylock_* functions are inlined when: -# - DEBUG_SPINLOCK=n and ARCH_INLINE_*LOCK=y -# -# unlock and unlock_irq functions are inlined when: -# - DEBUG_SPINLOCK=n and ARCH_INLINE_*LOCK=y -# or -# - DEBUG_SPINLOCK=n and PREEMPT=n -# -# unlock_bh and unlock_irqrestore functions are inlined when: -# - DEBUG_SPINLOCK=n and ARCH_INLINE_*LOCK=y -# - -if !DEBUG_SPINLOCK - -config INLINE_SPIN_TRYLOCK - def_bool y - depends on ARCH_INLINE_SPIN_TRYLOCK - -config INLINE_SPIN_TRYLOCK_BH - def_bool y - depends on ARCH_INLINE_SPIN_TRYLOCK_BH - -config INLINE_SPIN_LOCK - def_bool y - depends on !GENERIC_LOCKBREAK && ARCH_INLINE_SPIN_LOCK - -config INLINE_SPIN_LOCK_BH - def_bool y - depends on !GENERIC_LOCKBREAK && ARCH_INLINE_SPIN_LOCK_BH - -config INLINE_SPIN_LOCK_IRQ - def_bool y - depends on !GENERIC_LOCKBREAK && ARCH_INLINE_SPIN_LOCK_IRQ - -config INLINE_SPIN_LOCK_IRQSAVE - def_bool y - depends on !GENERIC_LOCKBREAK && ARCH_INLINE_SPIN_LOCK_IRQSAVE - -config INLINE_SPIN_UNLOCK_BH - def_bool y - depends on ARCH_INLINE_SPIN_UNLOCK_BH - -config INLINE_SPIN_UNLOCK_IRQ - def_bool y - depends on !PREEMPT || ARCH_INLINE_SPIN_UNLOCK_IRQ - -config INLINE_SPIN_UNLOCK_IRQRESTORE - def_bool y - depends on ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE - - -config INLINE_READ_TRYLOCK - def_bool y - depends on ARCH_INLINE_READ_TRYLOCK - -config INLINE_READ_LOCK - def_bool y - depends on !GENERIC_LOCKBREAK && ARCH_INLINE_READ_LOCK - -config INLINE_READ_LOCK_BH - def_bool y - depends on !GENERIC_LOCKBREAK && ARCH_INLINE_READ_LOCK_BH - -config INLINE_READ_LOCK_IRQ - def_bool y - depends on !GENERIC_LOCKBREAK && ARCH_INLINE_READ_LOCK_IRQ - -config INLINE_READ_LOCK_IRQSAVE - def_bool y - depends on !GENERIC_LOCKBREAK && ARCH_INLINE_READ_LOCK_IRQSAVE - -config INLINE_READ_UNLOCK - def_bool y - depends on !PREEMPT || ARCH_INLINE_READ_UNLOCK - -config INLINE_READ_UNLOCK_BH - def_bool y - depends on ARCH_INLINE_READ_UNLOCK_BH - -config INLINE_READ_UNLOCK_IRQ - def_bool y - depends on !PREEMPT || ARCH_INLINE_READ_UNLOCK_IRQ - -config INLINE_READ_UNLOCK_IRQRESTORE - def_bool y - depends on ARCH_INLINE_READ_UNLOCK_IRQRESTORE - - -config INLINE_WRITE_TRYLOCK - def_bool y - depends on ARCH_INLINE_WRITE_TRYLOCK - -config INLINE_WRITE_LOCK - def_bool y - depends on !GENERIC_LOCKBREAK && ARCH_INLINE_WRITE_LOCK - -config INLINE_WRITE_LOCK_BH - def_bool y - depends on !GENERIC_LOCKBREAK && ARCH_INLINE_WRITE_LOCK_BH - -config INLINE_WRITE_LOCK_IRQ - def_bool y - depends on !GENERIC_LOCKBREAK && ARCH_INLINE_WRITE_LOCK_IRQ - -config INLINE_WRITE_LOCK_IRQSAVE - def_bool y - depends on !GENERIC_LOCKBREAK && ARCH_INLINE_WRITE_LOCK_IRQSAVE - -config INLINE_WRITE_UNLOCK - def_bool y - depends on !PREEMPT || ARCH_INLINE_WRITE_UNLOCK - -config INLINE_WRITE_UNLOCK_BH - def_bool y - depends on ARCH_INLINE_WRITE_UNLOCK_BH - -config INLINE_WRITE_UNLOCK_IRQ - def_bool y - depends on !PREEMPT || ARCH_INLINE_WRITE_UNLOCK_IRQ - -config INLINE_WRITE_UNLOCK_IRQRESTORE - def_bool y - depends on ARCH_INLINE_WRITE_UNLOCK_IRQRESTORE - -endif - -config ARCH_SUPPORTS_ATOMIC_RMW - bool - -config MUTEX_SPIN_ON_OWNER - def_bool y - depends on SMP && !DEBUG_MUTEXES && ARCH_SUPPORTS_ATOMIC_RMW - -config RWSEM_SPIN_ON_OWNER - def_bool y - depends on SMP && RWSEM_XCHGADD_ALGORITHM && ARCH_SUPPORTS_ATOMIC_RMW - -config LOCK_SPIN_ON_OWNER - def_bool y - depends on MUTEX_SPIN_ON_OWNER || RWSEM_SPIN_ON_OWNER - -config ARCH_USE_QUEUED_SPINLOCKS - bool - -config QUEUED_SPINLOCKS - def_bool y if ARCH_USE_QUEUED_SPINLOCKS - depends on SMP - -config ARCH_USE_QUEUED_RWLOCKS - bool - -config QUEUED_RWLOCKS - def_bool y if ARCH_USE_QUEUED_RWLOCKS - depends on SMP diff --git a/src/linux/kernel/Kconfig.preempt b/src/linux/kernel/Kconfig.preempt deleted file mode 100644 index 3f9c974..0000000 --- a/src/linux/kernel/Kconfig.preempt +++ /dev/null @@ -1,58 +0,0 @@ - -choice - prompt "Preemption Model" - default PREEMPT_NONE - -config PREEMPT_NONE - bool "No Forced Preemption (Server)" - help - This is the traditional Linux preemption model, geared towards - throughput. It will still provide good latencies most of the - time, but there are no guarantees and occasional longer delays - are possible. - - Select this option if you are building a kernel for a server or - scientific/computation system, or if you want to maximize the - raw processing power of the kernel, irrespective of scheduling - latencies. - -config PREEMPT_VOLUNTARY - bool "Voluntary Kernel Preemption (Desktop)" - help - This option reduces the latency of the kernel by adding more - "explicit preemption points" to the kernel code. These new - preemption points have been selected to reduce the maximum - latency of rescheduling, providing faster application reactions, - at the cost of slightly lower throughput. - - This allows reaction to interactive events by allowing a - low priority process to voluntarily preempt itself even if it - is in kernel mode executing a system call. This allows - applications to run more 'smoothly' even when the system is - under load. - - Select this if you are building a kernel for a desktop system. - -config PREEMPT - bool "Preemptible Kernel (Low-Latency Desktop)" - select PREEMPT_COUNT - select UNINLINE_SPIN_UNLOCK if !ARCH_INLINE_SPIN_UNLOCK - help - This option reduces the latency of the kernel by making - all kernel code (that is not executing in a critical section) - preemptible. This allows reaction to interactive events by - permitting a low priority process to be preempted involuntarily - even if it is in kernel mode executing a system call and would - otherwise not be about to reach a natural preemption point. - This allows applications to run more 'smoothly' even when the - system is under load, at the cost of slightly lower throughput - and a slight runtime overhead to kernel code. - - Select this if you are building a kernel for a desktop or - embedded system with latency requirements in the milliseconds - range. - -endchoice - -config PREEMPT_COUNT - bool \ No newline at end of file diff --git a/src/linux/kernel/Makefile b/src/linux/kernel/Makefile deleted file mode 100644 index eb26e12..0000000 --- a/src/linux/kernel/Makefile +++ /dev/null @@ -1,127 +0,0 @@ -# -# Makefile for the linux kernel. -# - -obj-y = fork.o exec_domain.o panic.o \ - cpu.o exit.o softirq.o resource.o \ - sysctl.o sysctl_binary.o capability.o ptrace.o user.o \ - signal.o sys.o kmod.o workqueue.o pid.o task_work.o \ - extable.o params.o \ - kthread.o sys_ni.o nsproxy.o \ - notifier.o ksysfs.o cred.o reboot.o \ - async.o range.o smpboot.o ucount.o - -obj-$(CONFIG_MULTIUSER) += groups.o - -ifdef CONFIG_FUNCTION_TRACER -# Do not trace internal ftrace files -CFLAGS_REMOVE_irq_work.o = $(CC_FLAGS_FTRACE) -endif - -# Prevents flicker of uninteresting __do_softirq()/__local_bh_disable_ip() -# in coverage traces. -KCOV_INSTRUMENT_softirq.o := n -# These are called from save_stack_trace() on slub debug path, -# and produce insane amounts of uninteresting coverage. -KCOV_INSTRUMENT_module.o := n -KCOV_INSTRUMENT_extable.o := n -# Don't self-instrument. -KCOV_INSTRUMENT_kcov.o := n -KASAN_SANITIZE_kcov.o := n - -# cond_syscall is currently not LTO compatible -CFLAGS_sys_ni.o = $(DISABLE_LTO) - -obj-y += sched/ -obj-y += locking/ -obj-y += power/ -obj-y += printk/ -obj-y += irq/ -obj-y += rcu/ -obj-y += livepatch/ - -obj-$(CONFIG_CHECKPOINT_RESTORE) += kcmp.o -obj-$(CONFIG_FREEZER) += freezer.o -obj-$(CONFIG_PROFILING) += profile.o -obj-$(CONFIG_STACKTRACE) += stacktrace.o -obj-y += time/ -obj-$(CONFIG_FUTEX) += futex.o -ifeq ($(CONFIG_COMPAT),y) -obj-$(CONFIG_FUTEX) += futex_compat.o -endif -obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o -obj-$(CONFIG_SMP) += smp.o -ifneq ($(CONFIG_SMP),y) -obj-y += up.o -endif -obj-$(CONFIG_UID16) += uid16.o -obj-$(CONFIG_MODULES) += module.o -obj-$(CONFIG_MODULE_SIG) += module_signing.o -obj-$(CONFIG_KALLSYMS) += kallsyms.o -obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o -obj-$(CONFIG_KEXEC_CORE) += kexec_core.o -obj-$(CONFIG_KEXEC) += kexec.o -obj-$(CONFIG_KEXEC_FILE) += kexec_file.o -obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o -obj-$(CONFIG_COMPAT) += compat.o -obj-$(CONFIG_CGROUPS) += cgroup.o -obj-$(CONFIG_CGROUP_FREEZER) += cgroup_freezer.o -obj-$(CONFIG_CGROUP_PIDS) += cgroup_pids.o -obj-$(CONFIG_CPUSETS) += cpuset.o -obj-$(CONFIG_UTS_NS) += utsname.o -obj-$(CONFIG_USER_NS) += user_namespace.o -obj-$(CONFIG_PID_NS) += pid_namespace.o -obj-$(CONFIG_IKCONFIG) += configs.o -obj-$(CONFIG_SMP) += stop_machine.o -obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o -obj-$(CONFIG_AUDIT) += audit.o auditfilter.o -obj-$(CONFIG_AUDITSYSCALL) += auditsc.o -obj-$(CONFIG_AUDIT_WATCH) += audit_watch.o audit_fsnotify.o -obj-$(CONFIG_AUDIT_TREE) += audit_tree.o -obj-$(CONFIG_GCOV_KERNEL) += gcov/ -obj-$(CONFIG_KCOV) += kcov.o -obj-$(CONFIG_KPROBES) += kprobes.o -obj-$(CONFIG_KGDB) += debug/ -obj-$(CONFIG_DETECT_HUNG_TASK) += hung_task.o -obj-$(CONFIG_LOCKUP_DETECTOR) += watchdog.o -obj-$(CONFIG_SECCOMP) += seccomp.o -obj-$(CONFIG_RELAY) += relay.o -obj-$(CONFIG_SYSCTL) += utsname_sysctl.o -obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o -obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o -obj-$(CONFIG_TRACEPOINTS) += tracepoint.o -obj-$(CONFIG_LATENCYTOP) += latencytop.o -obj-$(CONFIG_ELFCORE) += elfcore.o -obj-$(CONFIG_FUNCTION_TRACER) += trace/ -obj-$(CONFIG_TRACING) += trace/ -obj-$(CONFIG_TRACE_CLOCK) += trace/ -obj-$(CONFIG_RING_BUFFER) += trace/ -obj-$(CONFIG_TRACEPOINTS) += trace/ -obj-$(CONFIG_IRQ_WORK) += irq_work.o -obj-$(CONFIG_CPU_PM) += cpu_pm.o -obj-$(CONFIG_BPF) += bpf/ - -obj-$(CONFIG_PERF_EVENTS) += events/ - -obj-$(CONFIG_USER_RETURN_NOTIFIER) += user-return-notifier.o -obj-$(CONFIG_PADATA) += padata.o -obj-$(CONFIG_CRASH_DUMP) += crash_dump.o -obj-$(CONFIG_JUMP_LABEL) += jump_label.o -obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o -obj-$(CONFIG_TORTURE_TEST) += torture.o -obj-$(CONFIG_MEMBARRIER) += membarrier.o - -obj-$(CONFIG_HAS_IOMEM) += memremap.o - -$(obj)/configs.o: $(obj)/config_data.h - -# config_data.h contains the same information as ikconfig.h but gzipped. -# Info from config_data can be extracted from /proc/config* -targets += config_data.gz -$(obj)/config_data.gz: $(KCONFIG_CONFIG) FORCE - $(call if_changed,gzip) - - filechk_ikconfiggz = (echo "static const char kernel_config_data[] __used = MAGIC_START"; cat $< | scripts/basic/bin2c; echo "MAGIC_END;") -targets += config_data.h -$(obj)/config_data.h: $(obj)/config_data.gz FORCE - $(call filechk,ikconfiggz) diff --git a/src/linux/kernel/async.c b/src/linux/kernel/async.c deleted file mode 100644 index d2edd6e..0000000 --- a/src/linux/kernel/async.c +++ /dev/null @@ -1,329 +0,0 @@ -/* - * async.c: Asynchronous function calls for boot performance - * - * (C) Copyright 2009 Intel Corporation - * Author: Arjan van de Ven - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; version 2 - * of the License. - */ - - -/* - -Goals and Theory of Operation - -The primary goal of this feature is to reduce the kernel boot time, -by doing various independent hardware delays and discovery operations -decoupled and not strictly serialized. - -More specifically, the asynchronous function call concept allows -certain operations (primarily during system boot) to happen -asynchronously, out of order, while these operations still -have their externally visible parts happen sequentially and in-order. -(not unlike how out-of-order CPUs retire their instructions in order) - -Key to the asynchronous function call implementation is the concept of -a "sequence cookie" (which, although it has an abstracted type, can be -thought of as a monotonically incrementing number). - -The async core will assign each scheduled event such a sequence cookie and -pass this to the called functions. - -The asynchronously called function should before doing a globally visible -operation, such as registering device numbers, call the -async_synchronize_cookie() function and pass in its own cookie. The -async_synchronize_cookie() function will make sure that all asynchronous -operations that were scheduled prior to the operation corresponding with the -cookie have completed. - -Subsystem/driver initialization code that scheduled asynchronous probe -functions, but which shares global resources with other drivers/subsystems -that do not use the asynchronous call feature, need to do a full -synchronization with the async_synchronize_full() function, before returning -from their init function. This is to maintain strict ordering between the -asynchronous and synchronous parts of the kernel. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "workqueue_internal.h" - -static async_cookie_t next_cookie = 1; - -#define MAX_WORK 32768 -#define ASYNC_COOKIE_MAX ULLONG_MAX /* infinity cookie */ - -static LIST_HEAD(async_global_pending); /* pending from all registered doms */ -static ASYNC_DOMAIN(async_dfl_domain); -static DEFINE_SPINLOCK(async_lock); - -struct async_entry { - struct list_head domain_list; - struct list_head global_list; - struct work_struct work; - async_cookie_t cookie; - async_func_t func; - void *data; - struct async_domain *domain; -}; - -static DECLARE_WAIT_QUEUE_HEAD(async_done); - -static atomic_t entry_count; - -static async_cookie_t lowest_in_progress(struct async_domain *domain) -{ - struct list_head *pending; - async_cookie_t ret = ASYNC_COOKIE_MAX; - unsigned long flags; - - spin_lock_irqsave(&async_lock, flags); - - if (domain) - pending = &domain->pending; - else - pending = &async_global_pending; - - if (!list_empty(pending)) - ret = list_first_entry(pending, struct async_entry, - domain_list)->cookie; - - spin_unlock_irqrestore(&async_lock, flags); - return ret; -} - -/* - * pick the first pending entry and run it - */ -static void async_run_entry_fn(struct work_struct *work) -{ - struct async_entry *entry = - container_of(work, struct async_entry, work); - unsigned long flags; - ktime_t uninitialized_var(calltime), delta, rettime; - - /* 1) run (and print duration) */ - if (initcall_debug && system_state == SYSTEM_BOOTING) { - pr_debug("calling %lli_%pF @ %i\n", - (long long)entry->cookie, - entry->func, task_pid_nr(current)); - calltime = ktime_get(); - } - entry->func(entry->data, entry->cookie); - if (initcall_debug && system_state == SYSTEM_BOOTING) { - rettime = ktime_get(); - delta = ktime_sub(rettime, calltime); - pr_debug("initcall %lli_%pF returned 0 after %lld usecs\n", - (long long)entry->cookie, - entry->func, - (long long)ktime_to_ns(delta) >> 10); - } - - /* 2) remove self from the pending queues */ - spin_lock_irqsave(&async_lock, flags); - list_del_init(&entry->domain_list); - list_del_init(&entry->global_list); - - /* 3) free the entry */ - kfree(entry); - atomic_dec(&entry_count); - - spin_unlock_irqrestore(&async_lock, flags); - - /* 4) wake up any waiters */ - wake_up(&async_done); -} - -static async_cookie_t __async_schedule(async_func_t func, void *data, struct async_domain *domain) -{ - struct async_entry *entry; - unsigned long flags; - async_cookie_t newcookie; - - /* allow irq-off callers */ - entry = kzalloc(sizeof(struct async_entry), GFP_ATOMIC); - - /* - * If we're out of memory or if there's too much work - * pending already, we execute synchronously. - */ - if (!entry || atomic_read(&entry_count) > MAX_WORK) { - kfree(entry); - spin_lock_irqsave(&async_lock, flags); - newcookie = next_cookie++; - spin_unlock_irqrestore(&async_lock, flags); - - /* low on memory.. run synchronously */ - func(data, newcookie); - return newcookie; - } - INIT_LIST_HEAD(&entry->domain_list); - INIT_LIST_HEAD(&entry->global_list); - INIT_WORK(&entry->work, async_run_entry_fn); - entry->func = func; - entry->data = data; - entry->domain = domain; - - spin_lock_irqsave(&async_lock, flags); - - /* allocate cookie and queue */ - newcookie = entry->cookie = next_cookie++; - - list_add_tail(&entry->domain_list, &domain->pending); - if (domain->registered) - list_add_tail(&entry->global_list, &async_global_pending); - - atomic_inc(&entry_count); - spin_unlock_irqrestore(&async_lock, flags); - - /* mark that this task has queued an async job, used by module init */ - current->flags |= PF_USED_ASYNC; - - /* schedule for execution */ - queue_work(system_unbound_wq, &entry->work); - - return newcookie; -} - -/** - * async_schedule - schedule a function for asynchronous execution - * @func: function to execute asynchronously - * @data: data pointer to pass to the function - * - * Returns an async_cookie_t that may be used for checkpointing later. - * Note: This function may be called from atomic or non-atomic contexts. - */ -async_cookie_t async_schedule(async_func_t func, void *data) -{ - return __async_schedule(func, data, &async_dfl_domain); -} -EXPORT_SYMBOL_GPL(async_schedule); - -/** - * async_schedule_domain - schedule a function for asynchronous execution within a certain domain - * @func: function to execute asynchronously - * @data: data pointer to pass to the function - * @domain: the domain - * - * Returns an async_cookie_t that may be used for checkpointing later. - * @domain may be used in the async_synchronize_*_domain() functions to - * wait within a certain synchronization domain rather than globally. A - * synchronization domain is specified via @domain. Note: This function - * may be called from atomic or non-atomic contexts. - */ -async_cookie_t async_schedule_domain(async_func_t func, void *data, - struct async_domain *domain) -{ - return __async_schedule(func, data, domain); -} -EXPORT_SYMBOL_GPL(async_schedule_domain); - -/** - * async_synchronize_full - synchronize all asynchronous function calls - * - * This function waits until all asynchronous function calls have been done. - */ -void async_synchronize_full(void) -{ - async_synchronize_full_domain(NULL); -} -EXPORT_SYMBOL_GPL(async_synchronize_full); - -/** - * async_unregister_domain - ensure no more anonymous waiters on this domain - * @domain: idle domain to flush out of any async_synchronize_full instances - * - * async_synchronize_{cookie|full}_domain() are not flushed since callers - * of these routines should know the lifetime of @domain - * - * Prefer ASYNC_DOMAIN_EXCLUSIVE() declarations over flushing - */ -void async_unregister_domain(struct async_domain *domain) -{ - spin_lock_irq(&async_lock); - WARN_ON(!domain->registered || !list_empty(&domain->pending)); - domain->registered = 0; - spin_unlock_irq(&async_lock); -} -EXPORT_SYMBOL_GPL(async_unregister_domain); - -/** - * async_synchronize_full_domain - synchronize all asynchronous function within a certain domain - * @domain: the domain to synchronize - * - * This function waits until all asynchronous function calls for the - * synchronization domain specified by @domain have been done. - */ -void async_synchronize_full_domain(struct async_domain *domain) -{ - async_synchronize_cookie_domain(ASYNC_COOKIE_MAX, domain); -} -EXPORT_SYMBOL_GPL(async_synchronize_full_domain); - -/** - * async_synchronize_cookie_domain - synchronize asynchronous function calls within a certain domain with cookie checkpointing - * @cookie: async_cookie_t to use as checkpoint - * @domain: the domain to synchronize (%NULL for all registered domains) - * - * This function waits until all asynchronous function calls for the - * synchronization domain specified by @domain submitted prior to @cookie - * have been done. - */ -void async_synchronize_cookie_domain(async_cookie_t cookie, struct async_domain *domain) -{ - ktime_t uninitialized_var(starttime), delta, endtime; - - if (initcall_debug && system_state == SYSTEM_BOOTING) { - pr_debug("async_waiting @ %i\n", task_pid_nr(current)); - starttime = ktime_get(); - } - - wait_event(async_done, lowest_in_progress(domain) >= cookie); - - if (initcall_debug && system_state == SYSTEM_BOOTING) { - endtime = ktime_get(); - delta = ktime_sub(endtime, starttime); - - pr_debug("async_continuing @ %i after %lli usec\n", - task_pid_nr(current), - (long long)ktime_to_ns(delta) >> 10); - } -} -EXPORT_SYMBOL_GPL(async_synchronize_cookie_domain); - -/** - * async_synchronize_cookie - synchronize asynchronous function calls with cookie checkpointing - * @cookie: async_cookie_t to use as checkpoint - * - * This function waits until all asynchronous function calls prior to @cookie - * have been done. - */ -void async_synchronize_cookie(async_cookie_t cookie) -{ - async_synchronize_cookie_domain(cookie, &async_dfl_domain); -} -EXPORT_SYMBOL_GPL(async_synchronize_cookie); - -/** - * current_is_async - is %current an async worker task? - * - * Returns %true if %current is an async worker task. - */ -bool current_is_async(void) -{ - struct worker *worker = current_wq_worker(); - - return worker && worker->current_func == async_run_entry_fn; -} -EXPORT_SYMBOL_GPL(current_is_async); diff --git a/src/linux/kernel/audit.h b/src/linux/kernel/audit.h deleted file mode 100644 index 431444c..0000000 --- a/src/linux/kernel/audit.h +++ /dev/null @@ -1,352 +0,0 @@ -/* audit -- definition of audit_context structure and supporting types - * - * Copyright 2003-2004 Red Hat, Inc. - * Copyright 2005 Hewlett-Packard Development Company, L.P. - * Copyright 2005 IBM Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include -#include - -/* AUDIT_NAMES is the number of slots we reserve in the audit_context - * for saving names from getname(). If we get more names we will allocate - * a name dynamically and also add those to the list anchored by names_list. */ -#define AUDIT_NAMES 5 - -/* At task start time, the audit_state is set in the audit_context using - a per-task filter. At syscall entry, the audit_state is augmented by - the syscall filter. */ -enum audit_state { - AUDIT_DISABLED, /* Do not create per-task audit_context. - * No syscall-specific audit records can - * be generated. */ - AUDIT_BUILD_CONTEXT, /* Create the per-task audit_context, - * and fill it in at syscall - * entry time. This makes a full - * syscall record available if some - * other part of the kernel decides it - * should be recorded. */ - AUDIT_RECORD_CONTEXT /* Create the per-task audit_context, - * always fill it in at syscall entry - * time, and always write out the audit - * record at syscall exit time. */ -}; - -/* Rule lists */ -struct audit_watch; -struct audit_fsnotify_mark; -struct audit_tree; -struct audit_chunk; - -struct audit_entry { - struct list_head list; - struct rcu_head rcu; - struct audit_krule rule; -}; - -struct audit_cap_data { - kernel_cap_t permitted; - kernel_cap_t inheritable; - union { - unsigned int fE; /* effective bit of file cap */ - kernel_cap_t effective; /* effective set of process */ - }; -}; - -/* When fs/namei.c:getname() is called, we store the pointer in name and bump - * the refcnt in the associated filename struct. - * - * Further, in fs/namei.c:path_lookup() we store the inode and device. - */ -struct audit_names { - struct list_head list; /* audit_context->names_list */ - - struct filename *name; - int name_len; /* number of chars to log */ - bool hidden; /* don't log this record */ - - unsigned long ino; - dev_t dev; - umode_t mode; - kuid_t uid; - kgid_t gid; - dev_t rdev; - u32 osid; - struct audit_cap_data fcap; - unsigned int fcap_ver; - unsigned char type; /* record type */ - /* - * This was an allocated audit_names and not from the array of - * names allocated in the task audit context. Thus this name - * should be freed on syscall exit. - */ - bool should_free; -}; - -struct audit_proctitle { - int len; /* length of the cmdline field. */ - char *value; /* the cmdline field */ -}; - -/* The per-task audit context. */ -struct audit_context { - int dummy; /* must be the first element */ - int in_syscall; /* 1 if task is in a syscall */ - enum audit_state state, current_state; - unsigned int serial; /* serial number for record */ - int major; /* syscall number */ - struct timespec ctime; /* time of syscall entry */ - unsigned long argv[4]; /* syscall arguments */ - long return_code;/* syscall return code */ - u64 prio; - int return_valid; /* return code is valid */ - /* - * The names_list is the list of all audit_names collected during this - * syscall. The first AUDIT_NAMES entries in the names_list will - * actually be from the preallocated_names array for performance - * reasons. Except during allocation they should never be referenced - * through the preallocated_names array and should only be found/used - * by running the names_list. - */ - struct audit_names preallocated_names[AUDIT_NAMES]; - int name_count; /* total records in names_list */ - struct list_head names_list; /* struct audit_names->list anchor */ - char *filterkey; /* key for rule that triggered record */ - struct path pwd; - struct audit_aux_data *aux; - struct audit_aux_data *aux_pids; - struct sockaddr_storage *sockaddr; - size_t sockaddr_len; - /* Save things to print about task_struct */ - pid_t pid, ppid; - kuid_t uid, euid, suid, fsuid; - kgid_t gid, egid, sgid, fsgid; - unsigned long personality; - int arch; - - pid_t target_pid; - kuid_t target_auid; - kuid_t target_uid; - unsigned int target_sessionid; - u32 target_sid; - char target_comm[TASK_COMM_LEN]; - - struct audit_tree_refs *trees, *first_trees; - struct list_head killed_trees; - int tree_count; - - int type; - union { - struct { - int nargs; - long args[6]; - } socketcall; - struct { - kuid_t uid; - kgid_t gid; - umode_t mode; - u32 osid; - int has_perm; - uid_t perm_uid; - gid_t perm_gid; - umode_t perm_mode; - unsigned long qbytes; - } ipc; - struct { - mqd_t mqdes; - struct mq_attr mqstat; - } mq_getsetattr; - struct { - mqd_t mqdes; - int sigev_signo; - } mq_notify; - struct { - mqd_t mqdes; - size_t msg_len; - unsigned int msg_prio; - struct timespec abs_timeout; - } mq_sendrecv; - struct { - int oflag; - umode_t mode; - struct mq_attr attr; - } mq_open; - struct { - pid_t pid; - struct audit_cap_data cap; - } capset; - struct { - int fd; - int flags; - } mmap; - struct { - int argc; - } execve; - }; - int fds[2]; - struct audit_proctitle proctitle; -}; - -extern u32 audit_ever_enabled; - -extern void audit_copy_inode(struct audit_names *name, - const struct dentry *dentry, - struct inode *inode); -extern void audit_log_cap(struct audit_buffer *ab, char *prefix, - kernel_cap_t *cap); -extern void audit_log_name(struct audit_context *context, - struct audit_names *n, struct path *path, - int record_num, int *call_panic); - -extern int audit_pid; - -#define AUDIT_INODE_BUCKETS 32 -extern struct list_head audit_inode_hash[AUDIT_INODE_BUCKETS]; - -static inline int audit_hash_ino(u32 ino) -{ - return (ino & (AUDIT_INODE_BUCKETS-1)); -} - -/* Indicates that audit should log the full pathname. */ -#define AUDIT_NAME_FULL -1 - -extern int audit_match_class(int class, unsigned syscall); -extern int audit_comparator(const u32 left, const u32 op, const u32 right); -extern int audit_uid_comparator(kuid_t left, u32 op, kuid_t right); -extern int audit_gid_comparator(kgid_t left, u32 op, kgid_t right); -extern int parent_len(const char *path); -extern int audit_compare_dname_path(const char *dname, const char *path, int plen); -extern struct sk_buff *audit_make_reply(__u32 portid, int seq, int type, - int done, int multi, - const void *payload, int size); -extern void audit_panic(const char *message); - -struct audit_netlink_list { - __u32 portid; - struct net *net; - struct sk_buff_head q; -}; - -int audit_send_list(void *); - -struct audit_net { - struct sock *nlsk; -}; - -extern int selinux_audit_rule_update(void); - -extern struct mutex audit_filter_mutex; -extern int audit_del_rule(struct audit_entry *); -extern void audit_free_rule_rcu(struct rcu_head *); -extern struct list_head audit_filter_list[]; - -extern struct audit_entry *audit_dupe_rule(struct audit_krule *old); - -extern void audit_log_d_path_exe(struct audit_buffer *ab, - struct mm_struct *mm); - -extern struct tty_struct *audit_get_tty(struct task_struct *tsk); -extern void audit_put_tty(struct tty_struct *tty); - -/* audit watch functions */ -#ifdef CONFIG_AUDIT_WATCH -extern void audit_put_watch(struct audit_watch *watch); -extern void audit_get_watch(struct audit_watch *watch); -extern int audit_to_watch(struct audit_krule *krule, char *path, int len, u32 op); -extern int audit_add_watch(struct audit_krule *krule, struct list_head **list); -extern void audit_remove_watch_rule(struct audit_krule *krule); -extern char *audit_watch_path(struct audit_watch *watch); -extern int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev); - -extern struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *pathname, int len); -extern char *audit_mark_path(struct audit_fsnotify_mark *mark); -extern void audit_remove_mark(struct audit_fsnotify_mark *audit_mark); -extern void audit_remove_mark_rule(struct audit_krule *krule); -extern int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned long ino, dev_t dev); -extern int audit_dupe_exe(struct audit_krule *new, struct audit_krule *old); -extern int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark *mark); - -#else -#define audit_put_watch(w) {} -#define audit_get_watch(w) {} -#define audit_to_watch(k, p, l, o) (-EINVAL) -#define audit_add_watch(k, l) (-EINVAL) -#define audit_remove_watch_rule(k) BUG() -#define audit_watch_path(w) "" -#define audit_watch_compare(w, i, d) 0 - -#define audit_alloc_mark(k, p, l) (ERR_PTR(-EINVAL)) -#define audit_mark_path(m) "" -#define audit_remove_mark(m) -#define audit_remove_mark_rule(k) -#define audit_mark_compare(m, i, d) 0 -#define audit_exe_compare(t, m) (-EINVAL) -#define audit_dupe_exe(n, o) (-EINVAL) -#endif /* CONFIG_AUDIT_WATCH */ - -#ifdef CONFIG_AUDIT_TREE -extern struct audit_chunk *audit_tree_lookup(const struct inode *); -extern void audit_put_chunk(struct audit_chunk *); -extern bool audit_tree_match(struct audit_chunk *, struct audit_tree *); -extern int audit_make_tree(struct audit_krule *, char *, u32); -extern int audit_add_tree_rule(struct audit_krule *); -extern int audit_remove_tree_rule(struct audit_krule *); -extern void audit_trim_trees(void); -extern int audit_tag_tree(char *old, char *new); -extern const char *audit_tree_path(struct audit_tree *); -extern void audit_put_tree(struct audit_tree *); -extern void audit_kill_trees(struct list_head *); -#else -#define audit_remove_tree_rule(rule) BUG() -#define audit_add_tree_rule(rule) -EINVAL -#define audit_make_tree(rule, str, op) -EINVAL -#define audit_trim_trees() (void)0 -#define audit_put_tree(tree) (void)0 -#define audit_tag_tree(old, new) -EINVAL -#define audit_tree_path(rule) "" /* never called */ -#define audit_kill_trees(list) BUG() -#endif - -extern char *audit_unpack_string(void **, size_t *, size_t); - -extern pid_t audit_sig_pid; -extern kuid_t audit_sig_uid; -extern u32 audit_sig_sid; - -extern int audit_filter(int msgtype, unsigned int listtype); - -#ifdef CONFIG_AUDITSYSCALL -extern int __audit_signal_info(int sig, struct task_struct *t); -static inline int audit_signal_info(int sig, struct task_struct *t) -{ - if (unlikely((audit_pid && t->tgid == audit_pid) || - (audit_signals && !audit_dummy_context()))) - return __audit_signal_info(sig, t); - return 0; -} -extern void audit_filter_inodes(struct task_struct *, struct audit_context *); -extern struct list_head *audit_killed_trees(void); -#else -#define audit_signal_info(s,t) AUDIT_DISABLED -#define audit_filter_inodes(t,c) AUDIT_DISABLED -#endif - -extern struct mutex audit_cmd_mutex; diff --git a/src/linux/kernel/bounds.c b/src/linux/kernel/bounds.c deleted file mode 100644 index e1d1d19..0000000 --- a/src/linux/kernel/bounds.c +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Generate definitions needed by the preprocessor. - * This code generates raw asm output which is post-processed - * to extract and format the required data. - */ - -#define __GENERATING_BOUNDS_H -/* Include headers that define the enum constants of interest */ -#include -#include -#include -#include -#include - -void foo(void) -{ - /* The enum constants to put into include/generated/bounds.h */ - DEFINE(NR_PAGEFLAGS, __NR_PAGEFLAGS); - DEFINE(MAX_NR_ZONES, __MAX_NR_ZONES); -#ifdef CONFIG_SMP - DEFINE(NR_CPUS_BITS, ilog2(CONFIG_NR_CPUS)); -#endif - DEFINE(SPINLOCK_SIZE, sizeof(spinlock_t)); - /* End of constants */ -} diff --git a/src/linux/kernel/bpf/Makefile b/src/linux/kernel/bpf/Makefile deleted file mode 100644 index eed911d..0000000 --- a/src/linux/kernel/bpf/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -obj-y := core.o - -obj-$(CONFIG_BPF_SYSCALL) += syscall.o verifier.o inode.o helpers.o -obj-$(CONFIG_BPF_SYSCALL) += hashtab.o arraymap.o percpu_freelist.o -ifeq ($(CONFIG_PERF_EVENTS),y) -obj-$(CONFIG_BPF_SYSCALL) += stackmap.o -endif diff --git a/src/linux/kernel/bpf/core.c b/src/linux/kernel/bpf/core.c deleted file mode 100644 index aa6d981..0000000 --- a/src/linux/kernel/bpf/core.c +++ /dev/null @@ -1,1092 +0,0 @@ -/* - * Linux Socket Filter - Kernel level socket filtering - * - * Based on the design of the Berkeley Packet Filter. The new - * internal format has been designed by PLUMgrid: - * - * Copyright (c) 2011 - 2014 PLUMgrid, http://plumgrid.com - * - * Authors: - * - * Jay Schulist - * Alexei Starovoitov - * Daniel Borkmann - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Andi Kleen - Fix a few bad bugs and races. - * Kris Katterjohn - Added many additional checks in bpf_check_classic() - */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -/* Registers */ -#define BPF_R0 regs[BPF_REG_0] -#define BPF_R1 regs[BPF_REG_1] -#define BPF_R2 regs[BPF_REG_2] -#define BPF_R3 regs[BPF_REG_3] -#define BPF_R4 regs[BPF_REG_4] -#define BPF_R5 regs[BPF_REG_5] -#define BPF_R6 regs[BPF_REG_6] -#define BPF_R7 regs[BPF_REG_7] -#define BPF_R8 regs[BPF_REG_8] -#define BPF_R9 regs[BPF_REG_9] -#define BPF_R10 regs[BPF_REG_10] - -/* Named registers */ -#define DST regs[insn->dst_reg] -#define SRC regs[insn->src_reg] -#define FP regs[BPF_REG_FP] -#define ARG1 regs[BPF_REG_ARG1] -#define CTX regs[BPF_REG_CTX] -#define IMM insn->imm - -/* No hurry in this branch - * - * Exported for the bpf jit load helper. - */ -void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb, int k, unsigned int size) -{ - u8 *ptr = NULL; - - if (k >= SKF_NET_OFF) - ptr = skb_network_header(skb) + k - SKF_NET_OFF; - else if (k >= SKF_LL_OFF) - ptr = skb_mac_header(skb) + k - SKF_LL_OFF; - - if (ptr >= skb->head && ptr + size <= skb_tail_pointer(skb)) - return ptr; - - return NULL; -} - -struct bpf_prog *bpf_prog_alloc(unsigned int size, gfp_t gfp_extra_flags) -{ - gfp_t gfp_flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO | - gfp_extra_flags; - struct bpf_prog_aux *aux; - struct bpf_prog *fp; - - size = round_up(size, PAGE_SIZE); - fp = __vmalloc(size, gfp_flags, PAGE_KERNEL); - if (fp == NULL) - return NULL; - - kmemcheck_annotate_bitfield(fp, meta); - - aux = kzalloc(sizeof(*aux), GFP_KERNEL | gfp_extra_flags); - if (aux == NULL) { - vfree(fp); - return NULL; - } - - fp->pages = size / PAGE_SIZE; - fp->aux = aux; - fp->aux->prog = fp; - - return fp; -} -EXPORT_SYMBOL_GPL(bpf_prog_alloc); - -struct bpf_prog *bpf_prog_realloc(struct bpf_prog *fp_old, unsigned int size, - gfp_t gfp_extra_flags) -{ - gfp_t gfp_flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO | - gfp_extra_flags; - struct bpf_prog *fp; - - BUG_ON(fp_old == NULL); - - size = round_up(size, PAGE_SIZE); - if (size <= fp_old->pages * PAGE_SIZE) - return fp_old; - - fp = __vmalloc(size, gfp_flags, PAGE_KERNEL); - if (fp != NULL) { - kmemcheck_annotate_bitfield(fp, meta); - - memcpy(fp, fp_old, fp_old->pages * PAGE_SIZE); - fp->pages = size / PAGE_SIZE; - fp->aux->prog = fp; - - /* We keep fp->aux from fp_old around in the new - * reallocated structure. - */ - fp_old->aux = NULL; - __bpf_prog_free(fp_old); - } - - return fp; -} - -void __bpf_prog_free(struct bpf_prog *fp) -{ - kfree(fp->aux); - vfree(fp); -} - -static bool bpf_is_jmp_and_has_target(const struct bpf_insn *insn) -{ - return BPF_CLASS(insn->code) == BPF_JMP && - /* Call and Exit are both special jumps with no - * target inside the BPF instruction image. - */ - BPF_OP(insn->code) != BPF_CALL && - BPF_OP(insn->code) != BPF_EXIT; -} - -static void bpf_adj_branches(struct bpf_prog *prog, u32 pos, u32 delta) -{ - struct bpf_insn *insn = prog->insnsi; - u32 i, insn_cnt = prog->len; - - for (i = 0; i < insn_cnt; i++, insn++) { - if (!bpf_is_jmp_and_has_target(insn)) - continue; - - /* Adjust offset of jmps if we cross boundaries. */ - if (i < pos && i + insn->off + 1 > pos) - insn->off += delta; - else if (i > pos + delta && i + insn->off + 1 <= pos + delta) - insn->off -= delta; - } -} - -struct bpf_prog *bpf_patch_insn_single(struct bpf_prog *prog, u32 off, - const struct bpf_insn *patch, u32 len) -{ - u32 insn_adj_cnt, insn_rest, insn_delta = len - 1; - struct bpf_prog *prog_adj; - - /* Since our patchlet doesn't expand the image, we're done. */ - if (insn_delta == 0) { - memcpy(prog->insnsi + off, patch, sizeof(*patch)); - return prog; - } - - insn_adj_cnt = prog->len + insn_delta; - - /* Several new instructions need to be inserted. Make room - * for them. Likely, there's no need for a new allocation as - * last page could have large enough tailroom. - */ - prog_adj = bpf_prog_realloc(prog, bpf_prog_size(insn_adj_cnt), - GFP_USER); - if (!prog_adj) - return NULL; - - prog_adj->len = insn_adj_cnt; - - /* Patching happens in 3 steps: - * - * 1) Move over tail of insnsi from next instruction onwards, - * so we can patch the single target insn with one or more - * new ones (patching is always from 1 to n insns, n > 0). - * 2) Inject new instructions at the target location. - * 3) Adjust branch offsets if necessary. - */ - insn_rest = insn_adj_cnt - off - len; - - memmove(prog_adj->insnsi + off + len, prog_adj->insnsi + off + 1, - sizeof(*patch) * insn_rest); - memcpy(prog_adj->insnsi + off, patch, sizeof(*patch) * len); - - bpf_adj_branches(prog_adj, off, insn_delta); - - return prog_adj; -} - -#ifdef CONFIG_BPF_JIT -struct bpf_binary_header * -bpf_jit_binary_alloc(unsigned int proglen, u8 **image_ptr, - unsigned int alignment, - bpf_jit_fill_hole_t bpf_fill_ill_insns) -{ - struct bpf_binary_header *hdr; - unsigned int size, hole, start; - - /* Most of BPF filters are really small, but if some of them - * fill a page, allow at least 128 extra bytes to insert a - * random section of illegal instructions. - */ - size = round_up(proglen + sizeof(*hdr) + 128, PAGE_SIZE); - hdr = module_alloc(size); - if (hdr == NULL) - return NULL; - - /* Fill space with illegal/arch-dep instructions. */ - bpf_fill_ill_insns(hdr, size); - - hdr->pages = size / PAGE_SIZE; - hole = min_t(unsigned int, size - (proglen + sizeof(*hdr)), - PAGE_SIZE - sizeof(*hdr)); - start = (get_random_int() % hole) & ~(alignment - 1); - - /* Leave a random number of instructions before BPF code. */ - *image_ptr = &hdr->image[start]; - - return hdr; -} - -void bpf_jit_binary_free(struct bpf_binary_header *hdr) -{ - module_memfree(hdr); -} - -int bpf_jit_harden __read_mostly; - -static int bpf_jit_blind_insn(const struct bpf_insn *from, - const struct bpf_insn *aux, - struct bpf_insn *to_buff) -{ - struct bpf_insn *to = to_buff; - u32 imm_rnd = get_random_int(); - s16 off; - - BUILD_BUG_ON(BPF_REG_AX + 1 != MAX_BPF_JIT_REG); - BUILD_BUG_ON(MAX_BPF_REG + 1 != MAX_BPF_JIT_REG); - - if (from->imm == 0 && - (from->code == (BPF_ALU | BPF_MOV | BPF_K) || - from->code == (BPF_ALU64 | BPF_MOV | BPF_K))) { - *to++ = BPF_ALU64_REG(BPF_XOR, from->dst_reg, from->dst_reg); - goto out; - } - - switch (from->code) { - case BPF_ALU | BPF_ADD | BPF_K: - case BPF_ALU | BPF_SUB | BPF_K: - case BPF_ALU | BPF_AND | BPF_K: - case BPF_ALU | BPF_OR | BPF_K: - case BPF_ALU | BPF_XOR | BPF_K: - case BPF_ALU | BPF_MUL | BPF_K: - case BPF_ALU | BPF_MOV | BPF_K: - case BPF_ALU | BPF_DIV | BPF_K: - case BPF_ALU | BPF_MOD | BPF_K: - *to++ = BPF_ALU32_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm); - *to++ = BPF_ALU32_IMM(BPF_XOR, BPF_REG_AX, imm_rnd); - *to++ = BPF_ALU32_REG(from->code, from->dst_reg, BPF_REG_AX); - break; - - case BPF_ALU64 | BPF_ADD | BPF_K: - case BPF_ALU64 | BPF_SUB | BPF_K: - case BPF_ALU64 | BPF_AND | BPF_K: - case BPF_ALU64 | BPF_OR | BPF_K: - case BPF_ALU64 | BPF_XOR | BPF_K: - case BPF_ALU64 | BPF_MUL | BPF_K: - case BPF_ALU64 | BPF_MOV | BPF_K: - case BPF_ALU64 | BPF_DIV | BPF_K: - case BPF_ALU64 | BPF_MOD | BPF_K: - *to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm); - *to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd); - *to++ = BPF_ALU64_REG(from->code, from->dst_reg, BPF_REG_AX); - break; - - case BPF_JMP | BPF_JEQ | BPF_K: - case BPF_JMP | BPF_JNE | BPF_K: - case BPF_JMP | BPF_JGT | BPF_K: - case BPF_JMP | BPF_JGE | BPF_K: - case BPF_JMP | BPF_JSGT | BPF_K: - case BPF_JMP | BPF_JSGE | BPF_K: - case BPF_JMP | BPF_JSET | BPF_K: - /* Accommodate for extra offset in case of a backjump. */ - off = from->off; - if (off < 0) - off -= 2; - *to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm); - *to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd); - *to++ = BPF_JMP_REG(from->code, from->dst_reg, BPF_REG_AX, off); - break; - - case BPF_LD | BPF_ABS | BPF_W: - case BPF_LD | BPF_ABS | BPF_H: - case BPF_LD | BPF_ABS | BPF_B: - *to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm); - *to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd); - *to++ = BPF_LD_IND(from->code, BPF_REG_AX, 0); - break; - - case BPF_LD | BPF_IND | BPF_W: - case BPF_LD | BPF_IND | BPF_H: - case BPF_LD | BPF_IND | BPF_B: - *to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm); - *to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd); - *to++ = BPF_ALU32_REG(BPF_ADD, BPF_REG_AX, from->src_reg); - *to++ = BPF_LD_IND(from->code, BPF_REG_AX, 0); - break; - - case BPF_LD | BPF_IMM | BPF_DW: - *to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ aux[1].imm); - *to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd); - *to++ = BPF_ALU64_IMM(BPF_LSH, BPF_REG_AX, 32); - *to++ = BPF_ALU64_REG(BPF_MOV, aux[0].dst_reg, BPF_REG_AX); - break; - case 0: /* Part 2 of BPF_LD | BPF_IMM | BPF_DW. */ - *to++ = BPF_ALU32_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ aux[0].imm); - *to++ = BPF_ALU32_IMM(BPF_XOR, BPF_REG_AX, imm_rnd); - *to++ = BPF_ALU64_REG(BPF_OR, aux[0].dst_reg, BPF_REG_AX); - break; - - case BPF_ST | BPF_MEM | BPF_DW: - case BPF_ST | BPF_MEM | BPF_W: - case BPF_ST | BPF_MEM | BPF_H: - case BPF_ST | BPF_MEM | BPF_B: - *to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm); - *to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd); - *to++ = BPF_STX_MEM(from->code, from->dst_reg, BPF_REG_AX, from->off); - break; - } -out: - return to - to_buff; -} - -static struct bpf_prog *bpf_prog_clone_create(struct bpf_prog *fp_other, - gfp_t gfp_extra_flags) -{ - gfp_t gfp_flags = GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO | - gfp_extra_flags; - struct bpf_prog *fp; - - fp = __vmalloc(fp_other->pages * PAGE_SIZE, gfp_flags, PAGE_KERNEL); - if (fp != NULL) { - kmemcheck_annotate_bitfield(fp, meta); - - /* aux->prog still points to the fp_other one, so - * when promoting the clone to the real program, - * this still needs to be adapted. - */ - memcpy(fp, fp_other, fp_other->pages * PAGE_SIZE); - } - - return fp; -} - -static void bpf_prog_clone_free(struct bpf_prog *fp) -{ - /* aux was stolen by the other clone, so we cannot free - * it from this path! It will be freed eventually by the - * other program on release. - * - * At this point, we don't need a deferred release since - * clone is guaranteed to not be locked. - */ - fp->aux = NULL; - __bpf_prog_free(fp); -} - -void bpf_jit_prog_release_other(struct bpf_prog *fp, struct bpf_prog *fp_other) -{ - /* We have to repoint aux->prog to self, as we don't - * know whether fp here is the clone or the original. - */ - fp->aux->prog = fp; - bpf_prog_clone_free(fp_other); -} - -struct bpf_prog *bpf_jit_blind_constants(struct bpf_prog *prog) -{ - struct bpf_insn insn_buff[16], aux[2]; - struct bpf_prog *clone, *tmp; - int insn_delta, insn_cnt; - struct bpf_insn *insn; - int i, rewritten; - - if (!bpf_jit_blinding_enabled()) - return prog; - - clone = bpf_prog_clone_create(prog, GFP_USER); - if (!clone) - return ERR_PTR(-ENOMEM); - - insn_cnt = clone->len; - insn = clone->insnsi; - - for (i = 0; i < insn_cnt; i++, insn++) { - /* We temporarily need to hold the original ld64 insn - * so that we can still access the first part in the - * second blinding run. - */ - if (insn[0].code == (BPF_LD | BPF_IMM | BPF_DW) && - insn[1].code == 0) - memcpy(aux, insn, sizeof(aux)); - - rewritten = bpf_jit_blind_insn(insn, aux, insn_buff); - if (!rewritten) - continue; - - tmp = bpf_patch_insn_single(clone, i, insn_buff, rewritten); - if (!tmp) { - /* Patching may have repointed aux->prog during - * realloc from the original one, so we need to - * fix it up here on error. - */ - bpf_jit_prog_release_other(prog, clone); - return ERR_PTR(-ENOMEM); - } - - clone = tmp; - insn_delta = rewritten - 1; - - /* Walk new program and skip insns we just inserted. */ - insn = clone->insnsi + i + insn_delta; - insn_cnt += insn_delta; - i += insn_delta; - } - - return clone; -} -#endif /* CONFIG_BPF_JIT */ - -/* Base function for offset calculation. Needs to go into .text section, - * therefore keeping it non-static as well; will also be used by JITs - * anyway later on, so do not let the compiler omit it. - */ -noinline u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5) -{ - return 0; -} -EXPORT_SYMBOL_GPL(__bpf_call_base); - -/** - * __bpf_prog_run - run eBPF program on a given context - * @ctx: is the data we are operating on - * @insn: is the array of eBPF instructions - * - * Decode and execute eBPF instructions. - */ -static unsigned int __bpf_prog_run(void *ctx, const struct bpf_insn *insn) -{ - u64 stack[MAX_BPF_STACK / sizeof(u64)]; - u64 regs[MAX_BPF_REG], tmp; - static const void *jumptable[256] = { - [0 ... 255] = &&default_label, - /* Now overwrite non-defaults ... */ - /* 32 bit ALU operations */ - [BPF_ALU | BPF_ADD | BPF_X] = &&ALU_ADD_X, - [BPF_ALU | BPF_ADD | BPF_K] = &&ALU_ADD_K, - [BPF_ALU | BPF_SUB | BPF_X] = &&ALU_SUB_X, - [BPF_ALU | BPF_SUB | BPF_K] = &&ALU_SUB_K, - [BPF_ALU | BPF_AND | BPF_X] = &&ALU_AND_X, - [BPF_ALU | BPF_AND | BPF_K] = &&ALU_AND_K, - [BPF_ALU | BPF_OR | BPF_X] = &&ALU_OR_X, - [BPF_ALU | BPF_OR | BPF_K] = &&ALU_OR_K, - [BPF_ALU | BPF_LSH | BPF_X] = &&ALU_LSH_X, - [BPF_ALU | BPF_LSH | BPF_K] = &&ALU_LSH_K, - [BPF_ALU | BPF_RSH | BPF_X] = &&ALU_RSH_X, - [BPF_ALU | BPF_RSH | BPF_K] = &&ALU_RSH_K, - [BPF_ALU | BPF_XOR | BPF_X] = &&ALU_XOR_X, - [BPF_ALU | BPF_XOR | BPF_K] = &&ALU_XOR_K, - [BPF_ALU | BPF_MUL | BPF_X] = &&ALU_MUL_X, - [BPF_ALU | BPF_MUL | BPF_K] = &&ALU_MUL_K, - [BPF_ALU | BPF_MOV | BPF_X] = &&ALU_MOV_X, - [BPF_ALU | BPF_MOV | BPF_K] = &&ALU_MOV_K, - [BPF_ALU | BPF_DIV | BPF_X] = &&ALU_DIV_X, - [BPF_ALU | BPF_DIV | BPF_K] = &&ALU_DIV_K, - [BPF_ALU | BPF_MOD | BPF_X] = &&ALU_MOD_X, - [BPF_ALU | BPF_MOD | BPF_K] = &&ALU_MOD_K, - [BPF_ALU | BPF_NEG] = &&ALU_NEG, - [BPF_ALU | BPF_END | BPF_TO_BE] = &&ALU_END_TO_BE, - [BPF_ALU | BPF_END | BPF_TO_LE] = &&ALU_END_TO_LE, - /* 64 bit ALU operations */ - [BPF_ALU64 | BPF_ADD | BPF_X] = &&ALU64_ADD_X, - [BPF_ALU64 | BPF_ADD | BPF_K] = &&ALU64_ADD_K, - [BPF_ALU64 | BPF_SUB | BPF_X] = &&ALU64_SUB_X, - [BPF_ALU64 | BPF_SUB | BPF_K] = &&ALU64_SUB_K, - [BPF_ALU64 | BPF_AND | BPF_X] = &&ALU64_AND_X, - [BPF_ALU64 | BPF_AND | BPF_K] = &&ALU64_AND_K, - [BPF_ALU64 | BPF_OR | BPF_X] = &&ALU64_OR_X, - [BPF_ALU64 | BPF_OR | BPF_K] = &&ALU64_OR_K, - [BPF_ALU64 | BPF_LSH | BPF_X] = &&ALU64_LSH_X, - [BPF_ALU64 | BPF_LSH | BPF_K] = &&ALU64_LSH_K, - [BPF_ALU64 | BPF_RSH | BPF_X] = &&ALU64_RSH_X, - [BPF_ALU64 | BPF_RSH | BPF_K] = &&ALU64_RSH_K, - [BPF_ALU64 | BPF_XOR | BPF_X] = &&ALU64_XOR_X, - [BPF_ALU64 | BPF_XOR | BPF_K] = &&ALU64_XOR_K, - [BPF_ALU64 | BPF_MUL | BPF_X] = &&ALU64_MUL_X, - [BPF_ALU64 | BPF_MUL | BPF_K] = &&ALU64_MUL_K, - [BPF_ALU64 | BPF_MOV | BPF_X] = &&ALU64_MOV_X, - [BPF_ALU64 | BPF_MOV | BPF_K] = &&ALU64_MOV_K, - [BPF_ALU64 | BPF_ARSH | BPF_X] = &&ALU64_ARSH_X, - [BPF_ALU64 | BPF_ARSH | BPF_K] = &&ALU64_ARSH_K, - [BPF_ALU64 | BPF_DIV | BPF_X] = &&ALU64_DIV_X, - [BPF_ALU64 | BPF_DIV | BPF_K] = &&ALU64_DIV_K, - [BPF_ALU64 | BPF_MOD | BPF_X] = &&ALU64_MOD_X, - [BPF_ALU64 | BPF_MOD | BPF_K] = &&ALU64_MOD_K, - [BPF_ALU64 | BPF_NEG] = &&ALU64_NEG, - /* Call instruction */ - [BPF_JMP | BPF_CALL] = &&JMP_CALL, - [BPF_JMP | BPF_CALL | BPF_X] = &&JMP_TAIL_CALL, - /* Jumps */ - [BPF_JMP | BPF_JA] = &&JMP_JA, - [BPF_JMP | BPF_JEQ | BPF_X] = &&JMP_JEQ_X, - [BPF_JMP | BPF_JEQ | BPF_K] = &&JMP_JEQ_K, - [BPF_JMP | BPF_JNE | BPF_X] = &&JMP_JNE_X, - [BPF_JMP | BPF_JNE | BPF_K] = &&JMP_JNE_K, - [BPF_JMP | BPF_JGT | BPF_X] = &&JMP_JGT_X, - [BPF_JMP | BPF_JGT | BPF_K] = &&JMP_JGT_K, - [BPF_JMP | BPF_JGE | BPF_X] = &&JMP_JGE_X, - [BPF_JMP | BPF_JGE | BPF_K] = &&JMP_JGE_K, - [BPF_JMP | BPF_JSGT | BPF_X] = &&JMP_JSGT_X, - [BPF_JMP | BPF_JSGT | BPF_K] = &&JMP_JSGT_K, - [BPF_JMP | BPF_JSGE | BPF_X] = &&JMP_JSGE_X, - [BPF_JMP | BPF_JSGE | BPF_K] = &&JMP_JSGE_K, - [BPF_JMP | BPF_JSET | BPF_X] = &&JMP_JSET_X, - [BPF_JMP | BPF_JSET | BPF_K] = &&JMP_JSET_K, - /* Program return */ - [BPF_JMP | BPF_EXIT] = &&JMP_EXIT, - /* Store instructions */ - [BPF_STX | BPF_MEM | BPF_B] = &&STX_MEM_B, - [BPF_STX | BPF_MEM | BPF_H] = &&STX_MEM_H, - [BPF_STX | BPF_MEM | BPF_W] = &&STX_MEM_W, - [BPF_STX | BPF_MEM | BPF_DW] = &&STX_MEM_DW, - [BPF_STX | BPF_XADD | BPF_W] = &&STX_XADD_W, - [BPF_STX | BPF_XADD | BPF_DW] = &&STX_XADD_DW, - [BPF_ST | BPF_MEM | BPF_B] = &&ST_MEM_B, - [BPF_ST | BPF_MEM | BPF_H] = &&ST_MEM_H, - [BPF_ST | BPF_MEM | BPF_W] = &&ST_MEM_W, - [BPF_ST | BPF_MEM | BPF_DW] = &&ST_MEM_DW, - /* Load instructions */ - [BPF_LDX | BPF_MEM | BPF_B] = &&LDX_MEM_B, - [BPF_LDX | BPF_MEM | BPF_H] = &&LDX_MEM_H, - [BPF_LDX | BPF_MEM | BPF_W] = &&LDX_MEM_W, - [BPF_LDX | BPF_MEM | BPF_DW] = &&LDX_MEM_DW, - [BPF_LD | BPF_ABS | BPF_W] = &&LD_ABS_W, - [BPF_LD | BPF_ABS | BPF_H] = &&LD_ABS_H, - [BPF_LD | BPF_ABS | BPF_B] = &&LD_ABS_B, - [BPF_LD | BPF_IND | BPF_W] = &&LD_IND_W, - [BPF_LD | BPF_IND | BPF_H] = &&LD_IND_H, - [BPF_LD | BPF_IND | BPF_B] = &&LD_IND_B, - [BPF_LD | BPF_IMM | BPF_DW] = &&LD_IMM_DW, - }; - u32 tail_call_cnt = 0; - void *ptr; - int off; - -#define CONT ({ insn++; goto select_insn; }) -#define CONT_JMP ({ insn++; goto select_insn; }) - - FP = (u64) (unsigned long) &stack[ARRAY_SIZE(stack)]; - ARG1 = (u64) (unsigned long) ctx; - -select_insn: - goto *jumptable[insn->code]; - - /* ALU */ -#define ALU(OPCODE, OP) \ - ALU64_##OPCODE##_X: \ - DST = DST OP SRC; \ - CONT; \ - ALU_##OPCODE##_X: \ - DST = (u32) DST OP (u32) SRC; \ - CONT; \ - ALU64_##OPCODE##_K: \ - DST = DST OP IMM; \ - CONT; \ - ALU_##OPCODE##_K: \ - DST = (u32) DST OP (u32) IMM; \ - CONT; - - ALU(ADD, +) - ALU(SUB, -) - ALU(AND, &) - ALU(OR, |) - ALU(LSH, <<) - ALU(RSH, >>) - ALU(XOR, ^) - ALU(MUL, *) -#undef ALU - ALU_NEG: - DST = (u32) -DST; - CONT; - ALU64_NEG: - DST = -DST; - CONT; - ALU_MOV_X: - DST = (u32) SRC; - CONT; - ALU_MOV_K: - DST = (u32) IMM; - CONT; - ALU64_MOV_X: - DST = SRC; - CONT; - ALU64_MOV_K: - DST = IMM; - CONT; - LD_IMM_DW: - DST = (u64) (u32) insn[0].imm | ((u64) (u32) insn[1].imm) << 32; - insn++; - CONT; - ALU64_ARSH_X: - (*(s64 *) &DST) >>= SRC; - CONT; - ALU64_ARSH_K: - (*(s64 *) &DST) >>= IMM; - CONT; - ALU64_MOD_X: - if (unlikely(SRC == 0)) - return 0; - div64_u64_rem(DST, SRC, &tmp); - DST = tmp; - CONT; - ALU_MOD_X: - if (unlikely(SRC == 0)) - return 0; - tmp = (u32) DST; - DST = do_div(tmp, (u32) SRC); - CONT; - ALU64_MOD_K: - div64_u64_rem(DST, IMM, &tmp); - DST = tmp; - CONT; - ALU_MOD_K: - tmp = (u32) DST; - DST = do_div(tmp, (u32) IMM); - CONT; - ALU64_DIV_X: - if (unlikely(SRC == 0)) - return 0; - DST = div64_u64(DST, SRC); - CONT; - ALU_DIV_X: - if (unlikely(SRC == 0)) - return 0; - tmp = (u32) DST; - do_div(tmp, (u32) SRC); - DST = (u32) tmp; - CONT; - ALU64_DIV_K: - DST = div64_u64(DST, IMM); - CONT; - ALU_DIV_K: - tmp = (u32) DST; - do_div(tmp, (u32) IMM); - DST = (u32) tmp; - CONT; - ALU_END_TO_BE: - switch (IMM) { - case 16: - DST = (__force u16) cpu_to_be16(DST); - break; - case 32: - DST = (__force u32) cpu_to_be32(DST); - break; - case 64: - DST = (__force u64) cpu_to_be64(DST); - break; - } - CONT; - ALU_END_TO_LE: - switch (IMM) { - case 16: - DST = (__force u16) cpu_to_le16(DST); - break; - case 32: - DST = (__force u32) cpu_to_le32(DST); - break; - case 64: - DST = (__force u64) cpu_to_le64(DST); - break; - } - CONT; - - /* CALL */ - JMP_CALL: - /* Function call scratches BPF_R1-BPF_R5 registers, - * preserves BPF_R6-BPF_R9, and stores return value - * into BPF_R0. - */ - BPF_R0 = (__bpf_call_base + insn->imm)(BPF_R1, BPF_R2, BPF_R3, - BPF_R4, BPF_R5); - CONT; - - JMP_TAIL_CALL: { - struct bpf_map *map = (struct bpf_map *) (unsigned long) BPF_R2; - struct bpf_array *array = container_of(map, struct bpf_array, map); - struct bpf_prog *prog; - u64 index = BPF_R3; - - if (unlikely(index >= array->map.max_entries)) - goto out; - if (unlikely(tail_call_cnt > MAX_TAIL_CALL_CNT)) - goto out; - - tail_call_cnt++; - - prog = READ_ONCE(array->ptrs[index]); - if (!prog) - goto out; - - /* ARG1 at this point is guaranteed to point to CTX from - * the verifier side due to the fact that the tail call is - * handeled like a helper, that is, bpf_tail_call_proto, - * where arg1_type is ARG_PTR_TO_CTX. - */ - insn = prog->insnsi; - goto select_insn; -out: - CONT; - } - /* JMP */ - JMP_JA: - insn += insn->off; - CONT; - JMP_JEQ_X: - if (DST == SRC) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JEQ_K: - if (DST == IMM) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JNE_X: - if (DST != SRC) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JNE_K: - if (DST != IMM) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JGT_X: - if (DST > SRC) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JGT_K: - if (DST > IMM) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JGE_X: - if (DST >= SRC) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JGE_K: - if (DST >= IMM) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JSGT_X: - if (((s64) DST) > ((s64) SRC)) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JSGT_K: - if (((s64) DST) > ((s64) IMM)) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JSGE_X: - if (((s64) DST) >= ((s64) SRC)) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JSGE_K: - if (((s64) DST) >= ((s64) IMM)) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JSET_X: - if (DST & SRC) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_JSET_K: - if (DST & IMM) { - insn += insn->off; - CONT_JMP; - } - CONT; - JMP_EXIT: - return BPF_R0; - - /* STX and ST and LDX*/ -#define LDST(SIZEOP, SIZE) \ - STX_MEM_##SIZEOP: \ - *(SIZE *)(unsigned long) (DST + insn->off) = SRC; \ - CONT; \ - ST_MEM_##SIZEOP: \ - *(SIZE *)(unsigned long) (DST + insn->off) = IMM; \ - CONT; \ - LDX_MEM_##SIZEOP: \ - DST = *(SIZE *)(unsigned long) (SRC + insn->off); \ - CONT; - - LDST(B, u8) - LDST(H, u16) - LDST(W, u32) - LDST(DW, u64) -#undef LDST - STX_XADD_W: /* lock xadd *(u32 *)(dst_reg + off16) += src_reg */ - atomic_add((u32) SRC, (atomic_t *)(unsigned long) - (DST + insn->off)); - CONT; - STX_XADD_DW: /* lock xadd *(u64 *)(dst_reg + off16) += src_reg */ - atomic64_add((u64) SRC, (atomic64_t *)(unsigned long) - (DST + insn->off)); - CONT; - LD_ABS_W: /* BPF_R0 = ntohl(*(u32 *) (skb->data + imm32)) */ - off = IMM; -load_word: - /* BPF_LD + BPD_ABS and BPF_LD + BPF_IND insns are - * only appearing in the programs where ctx == - * skb. All programs keep 'ctx' in regs[BPF_REG_CTX] - * == BPF_R6, bpf_convert_filter() saves it in BPF_R6, - * internal BPF verifier will check that BPF_R6 == - * ctx. - * - * BPF_ABS and BPF_IND are wrappers of function calls, - * so they scratch BPF_R1-BPF_R5 registers, preserve - * BPF_R6-BPF_R9, and store return value into BPF_R0. - * - * Implicit input: - * ctx == skb == BPF_R6 == CTX - * - * Explicit input: - * SRC == any register - * IMM == 32-bit immediate - * - * Output: - * BPF_R0 - 8/16/32-bit skb data converted to cpu endianness - */ - - ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 4, &tmp); - if (likely(ptr != NULL)) { - BPF_R0 = get_unaligned_be32(ptr); - CONT; - } - - return 0; - LD_ABS_H: /* BPF_R0 = ntohs(*(u16 *) (skb->data + imm32)) */ - off = IMM; -load_half: - ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 2, &tmp); - if (likely(ptr != NULL)) { - BPF_R0 = get_unaligned_be16(ptr); - CONT; - } - - return 0; - LD_ABS_B: /* BPF_R0 = *(u8 *) (skb->data + imm32) */ - off = IMM; -load_byte: - ptr = bpf_load_pointer((struct sk_buff *) (unsigned long) CTX, off, 1, &tmp); - if (likely(ptr != NULL)) { - BPF_R0 = *(u8 *)ptr; - CONT; - } - - return 0; - LD_IND_W: /* BPF_R0 = ntohl(*(u32 *) (skb->data + src_reg + imm32)) */ - off = IMM + SRC; - goto load_word; - LD_IND_H: /* BPF_R0 = ntohs(*(u16 *) (skb->data + src_reg + imm32)) */ - off = IMM + SRC; - goto load_half; - LD_IND_B: /* BPF_R0 = *(u8 *) (skb->data + src_reg + imm32) */ - off = IMM + SRC; - goto load_byte; - - default_label: - /* If we ever reach this, we have a bug somewhere. */ - WARN_RATELIMIT(1, "unknown opcode %02x\n", insn->code); - return 0; -} -STACK_FRAME_NON_STANDARD(__bpf_prog_run); /* jump table */ - -bool bpf_prog_array_compatible(struct bpf_array *array, - const struct bpf_prog *fp) -{ - if (!array->owner_prog_type) { - /* There's no owner yet where we could check for - * compatibility. - */ - array->owner_prog_type = fp->type; - array->owner_jited = fp->jited; - - return true; - } - - return array->owner_prog_type == fp->type && - array->owner_jited == fp->jited; -} - -static int bpf_check_tail_call(const struct bpf_prog *fp) -{ - struct bpf_prog_aux *aux = fp->aux; - int i; - - for (i = 0; i < aux->used_map_cnt; i++) { - struct bpf_map *map = aux->used_maps[i]; - struct bpf_array *array; - - if (map->map_type != BPF_MAP_TYPE_PROG_ARRAY) - continue; - - array = container_of(map, struct bpf_array, map); - if (!bpf_prog_array_compatible(array, fp)) - return -EINVAL; - } - - return 0; -} - -/** - * bpf_prog_select_runtime - select exec runtime for BPF program - * @fp: bpf_prog populated with internal BPF program - * @err: pointer to error variable - * - * Try to JIT eBPF program, if JIT is not available, use interpreter. - * The BPF program will be executed via BPF_PROG_RUN() macro. - */ -struct bpf_prog *bpf_prog_select_runtime(struct bpf_prog *fp, int *err) -{ - fp->bpf_func = (void *) __bpf_prog_run; - - /* eBPF JITs can rewrite the program in case constant - * blinding is active. However, in case of error during - * blinding, bpf_int_jit_compile() must always return a - * valid program, which in this case would simply not - * be JITed, but falls back to the interpreter. - */ - fp = bpf_int_jit_compile(fp); - bpf_prog_lock_ro(fp); - - /* The tail call compatibility check can only be done at - * this late stage as we need to determine, if we deal - * with JITed or non JITed program concatenations and not - * all eBPF JITs might immediately support all features. - */ - *err = bpf_check_tail_call(fp); - - return fp; -} -EXPORT_SYMBOL_GPL(bpf_prog_select_runtime); - -static void bpf_prog_free_deferred(struct work_struct *work) -{ - struct bpf_prog_aux *aux; - - aux = container_of(work, struct bpf_prog_aux, work); - bpf_jit_free(aux->prog); -} - -/* Free internal BPF program */ -void bpf_prog_free(struct bpf_prog *fp) -{ - struct bpf_prog_aux *aux = fp->aux; - - INIT_WORK(&aux->work, bpf_prog_free_deferred); - schedule_work(&aux->work); -} -EXPORT_SYMBOL_GPL(bpf_prog_free); - -/* RNG for unpriviledged user space with separated state from prandom_u32(). */ -static DEFINE_PER_CPU(struct rnd_state, bpf_user_rnd_state); - -void bpf_user_rnd_init_once(void) -{ - prandom_init_once(&bpf_user_rnd_state); -} - -BPF_CALL_0(bpf_user_rnd_u32) -{ - /* Should someone ever have the rather unwise idea to use some - * of the registers passed into this function, then note that - * this function is called from native eBPF and classic-to-eBPF - * transformations. Register assignments from both sides are - * different, f.e. classic always sets fn(ctx, A, X) here. - */ - struct rnd_state *state; - u32 res; - - state = &get_cpu_var(bpf_user_rnd_state); - res = prandom_u32_state(state); - put_cpu_var(bpf_user_rnd_state); - - return res; -} - -/* Weak definitions of helper functions in case we don't have bpf syscall. */ -const struct bpf_func_proto bpf_map_lookup_elem_proto __weak; -const struct bpf_func_proto bpf_map_update_elem_proto __weak; -const struct bpf_func_proto bpf_map_delete_elem_proto __weak; - -const struct bpf_func_proto bpf_get_prandom_u32_proto __weak; -const struct bpf_func_proto bpf_get_smp_processor_id_proto __weak; -const struct bpf_func_proto bpf_ktime_get_ns_proto __weak; - -const struct bpf_func_proto bpf_get_current_pid_tgid_proto __weak; -const struct bpf_func_proto bpf_get_current_uid_gid_proto __weak; -const struct bpf_func_proto bpf_get_current_comm_proto __weak; - -const struct bpf_func_proto * __weak bpf_get_trace_printk_proto(void) -{ - return NULL; -} - -u64 __weak -bpf_event_output(struct bpf_map *map, u64 flags, void *meta, u64 meta_size, - void *ctx, u64 ctx_size, bpf_ctx_copy_t ctx_copy) -{ - return -ENOTSUPP; -} - -/* Always built-in helper functions. */ -const struct bpf_func_proto bpf_tail_call_proto = { - .func = NULL, - .gpl_only = false, - .ret_type = RET_VOID, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_CONST_MAP_PTR, - .arg3_type = ARG_ANYTHING, -}; - -/* For classic BPF JITs that don't implement bpf_int_jit_compile(). */ -struct bpf_prog * __weak bpf_int_jit_compile(struct bpf_prog *prog) -{ - return prog; -} - -bool __weak bpf_helper_changes_skb_data(void *func) -{ - return false; -} - -/* To execute LD_ABS/LD_IND instructions __bpf_prog_run() may call - * skb_copy_bits(), so provide a weak definition of it for NET-less config. - */ -int __weak skb_copy_bits(const struct sk_buff *skb, int offset, void *to, - int len) -{ - return -EFAULT; -} diff --git a/src/linux/kernel/capability.c b/src/linux/kernel/capability.c deleted file mode 100644 index 00411c8..0000000 --- a/src/linux/kernel/capability.c +++ /dev/null @@ -1,475 +0,0 @@ -/* - * linux/kernel/capability.c - * - * Copyright (C) 1997 Andrew Main - * - * Integrated into 2.1.97+, Andrew G. Morgan - * 30 May 2002: Cleanup, Robert M. Love - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Leveraged for setting/resetting capabilities - */ - -const kernel_cap_t __cap_empty_set = CAP_EMPTY_SET; -EXPORT_SYMBOL(__cap_empty_set); - -int file_caps_enabled = 1; - -static int __init file_caps_disable(char *str) -{ - file_caps_enabled = 0; - return 1; -} -__setup("no_file_caps", file_caps_disable); - -#ifdef CONFIG_MULTIUSER -/* - * More recent versions of libcap are available from: - * - * http://www.kernel.org/pub/linux/libs/security/linux-privs/ - */ - -static void warn_legacy_capability_use(void) -{ - char name[sizeof(current->comm)]; - - pr_info_once("warning: `%s' uses 32-bit capabilities (legacy support in use)\n", - get_task_comm(name, current)); -} - -/* - * Version 2 capabilities worked fine, but the linux/capability.h file - * that accompanied their introduction encouraged their use without - * the necessary user-space source code changes. As such, we have - * created a version 3 with equivalent functionality to version 2, but - * with a header change to protect legacy source code from using - * version 2 when it wanted to use version 1. If your system has code - * that trips the following warning, it is using version 2 specific - * capabilities and may be doing so insecurely. - * - * The remedy is to either upgrade your version of libcap (to 2.10+, - * if the application is linked against it), or recompile your - * application with modern kernel headers and this warning will go - * away. - */ - -static void warn_deprecated_v2(void) -{ - char name[sizeof(current->comm)]; - - pr_info_once("warning: `%s' uses deprecated v2 capabilities in a way that may be insecure\n", - get_task_comm(name, current)); -} - -/* - * Version check. Return the number of u32s in each capability flag - * array, or a negative value on error. - */ -static int cap_validate_magic(cap_user_header_t header, unsigned *tocopy) -{ - __u32 version; - - if (get_user(version, &header->version)) - return -EFAULT; - - switch (version) { - case _LINUX_CAPABILITY_VERSION_1: - warn_legacy_capability_use(); - *tocopy = _LINUX_CAPABILITY_U32S_1; - break; - case _LINUX_CAPABILITY_VERSION_2: - warn_deprecated_v2(); - /* - * fall through - v3 is otherwise equivalent to v2. - */ - case _LINUX_CAPABILITY_VERSION_3: - *tocopy = _LINUX_CAPABILITY_U32S_3; - break; - default: - if (put_user((u32)_KERNEL_CAPABILITY_VERSION, &header->version)) - return -EFAULT; - return -EINVAL; - } - - return 0; -} - -/* - * The only thing that can change the capabilities of the current - * process is the current process. As such, we can't be in this code - * at the same time as we are in the process of setting capabilities - * in this process. The net result is that we can limit our use of - * locks to when we are reading the caps of another process. - */ -static inline int cap_get_target_pid(pid_t pid, kernel_cap_t *pEp, - kernel_cap_t *pIp, kernel_cap_t *pPp) -{ - int ret; - - if (pid && (pid != task_pid_vnr(current))) { - struct task_struct *target; - - rcu_read_lock(); - - target = find_task_by_vpid(pid); - if (!target) - ret = -ESRCH; - else - ret = security_capget(target, pEp, pIp, pPp); - - rcu_read_unlock(); - } else - ret = security_capget(current, pEp, pIp, pPp); - - return ret; -} - -/** - * sys_capget - get the capabilities of a given process. - * @header: pointer to struct that contains capability version and - * target pid data - * @dataptr: pointer to struct that contains the effective, permitted, - * and inheritable capabilities that are returned - * - * Returns 0 on success and < 0 on error. - */ -SYSCALL_DEFINE2(capget, cap_user_header_t, header, cap_user_data_t, dataptr) -{ - int ret = 0; - pid_t pid; - unsigned tocopy; - kernel_cap_t pE, pI, pP; - - ret = cap_validate_magic(header, &tocopy); - if ((dataptr == NULL) || (ret != 0)) - return ((dataptr == NULL) && (ret == -EINVAL)) ? 0 : ret; - - if (get_user(pid, &header->pid)) - return -EFAULT; - - if (pid < 0) - return -EINVAL; - - ret = cap_get_target_pid(pid, &pE, &pI, &pP); - if (!ret) { - struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S]; - unsigned i; - - for (i = 0; i < tocopy; i++) { - kdata[i].effective = pE.cap[i]; - kdata[i].permitted = pP.cap[i]; - kdata[i].inheritable = pI.cap[i]; - } - - /* - * Note, in the case, tocopy < _KERNEL_CAPABILITY_U32S, - * we silently drop the upper capabilities here. This - * has the effect of making older libcap - * implementations implicitly drop upper capability - * bits when they perform a: capget/modify/capset - * sequence. - * - * This behavior is considered fail-safe - * behavior. Upgrading the application to a newer - * version of libcap will enable access to the newer - * capabilities. - * - * An alternative would be to return an error here - * (-ERANGE), but that causes legacy applications to - * unexpectedly fail; the capget/modify/capset aborts - * before modification is attempted and the application - * fails. - */ - if (copy_to_user(dataptr, kdata, tocopy - * sizeof(struct __user_cap_data_struct))) { - return -EFAULT; - } - } - - return ret; -} - -/** - * sys_capset - set capabilities for a process or (*) a group of processes - * @header: pointer to struct that contains capability version and - * target pid data - * @data: pointer to struct that contains the effective, permitted, - * and inheritable capabilities - * - * Set capabilities for the current process only. The ability to any other - * process(es) has been deprecated and removed. - * - * The restrictions on setting capabilities are specified as: - * - * I: any raised capabilities must be a subset of the old permitted - * P: any raised capabilities must be a subset of the old permitted - * E: must be set to a subset of new permitted - * - * Returns 0 on success and < 0 on error. - */ -SYSCALL_DEFINE2(capset, cap_user_header_t, header, const cap_user_data_t, data) -{ - struct __user_cap_data_struct kdata[_KERNEL_CAPABILITY_U32S]; - unsigned i, tocopy, copybytes; - kernel_cap_t inheritable, permitted, effective; - struct cred *new; - int ret; - pid_t pid; - - ret = cap_validate_magic(header, &tocopy); - if (ret != 0) - return ret; - - if (get_user(pid, &header->pid)) - return -EFAULT; - - /* may only affect current now */ - if (pid != 0 && pid != task_pid_vnr(current)) - return -EPERM; - - copybytes = tocopy * sizeof(struct __user_cap_data_struct); - if (copybytes > sizeof(kdata)) - return -EFAULT; - - if (copy_from_user(&kdata, data, copybytes)) - return -EFAULT; - - for (i = 0; i < tocopy; i++) { - effective.cap[i] = kdata[i].effective; - permitted.cap[i] = kdata[i].permitted; - inheritable.cap[i] = kdata[i].inheritable; - } - while (i < _KERNEL_CAPABILITY_U32S) { - effective.cap[i] = 0; - permitted.cap[i] = 0; - inheritable.cap[i] = 0; - i++; - } - - effective.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; - permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; - inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - - ret = security_capset(new, current_cred(), - &effective, &inheritable, &permitted); - if (ret < 0) - goto error; - - audit_log_capset(new, current_cred()); - - return commit_creds(new); - -error: - abort_creds(new); - return ret; -} - -/** - * has_ns_capability - Does a task have a capability in a specific user ns - * @t: The task in question - * @ns: target user namespace - * @cap: The capability to be tested for - * - * Return true if the specified task has the given superior capability - * currently in effect to the specified user namespace, false if not. - * - * Note that this does not set PF_SUPERPRIV on the task. - */ -bool has_ns_capability(struct task_struct *t, - struct user_namespace *ns, int cap) -{ - int ret; - - rcu_read_lock(); - ret = security_capable(__task_cred(t), ns, cap); - rcu_read_unlock(); - - return (ret == 0); -} - -/** - * has_capability - Does a task have a capability in init_user_ns - * @t: The task in question - * @cap: The capability to be tested for - * - * Return true if the specified task has the given superior capability - * currently in effect to the initial user namespace, false if not. - * - * Note that this does not set PF_SUPERPRIV on the task. - */ -bool has_capability(struct task_struct *t, int cap) -{ - return has_ns_capability(t, &init_user_ns, cap); -} - -/** - * has_ns_capability_noaudit - Does a task have a capability (unaudited) - * in a specific user ns. - * @t: The task in question - * @ns: target user namespace - * @cap: The capability to be tested for - * - * Return true if the specified task has the given superior capability - * currently in effect to the specified user namespace, false if not. - * Do not write an audit message for the check. - * - * Note that this does not set PF_SUPERPRIV on the task. - */ -bool has_ns_capability_noaudit(struct task_struct *t, - struct user_namespace *ns, int cap) -{ - int ret; - - rcu_read_lock(); - ret = security_capable_noaudit(__task_cred(t), ns, cap); - rcu_read_unlock(); - - return (ret == 0); -} - -/** - * has_capability_noaudit - Does a task have a capability (unaudited) in the - * initial user ns - * @t: The task in question - * @cap: The capability to be tested for - * - * Return true if the specified task has the given superior capability - * currently in effect to init_user_ns, false if not. Don't write an - * audit message for the check. - * - * Note that this does not set PF_SUPERPRIV on the task. - */ -bool has_capability_noaudit(struct task_struct *t, int cap) -{ - return has_ns_capability_noaudit(t, &init_user_ns, cap); -} - -static bool ns_capable_common(struct user_namespace *ns, int cap, bool audit) -{ - int capable; - - if (unlikely(!cap_valid(cap))) { - pr_crit("capable() called with invalid cap=%u\n", cap); - BUG(); - } - - capable = audit ? security_capable(current_cred(), ns, cap) : - security_capable_noaudit(current_cred(), ns, cap); - if (capable == 0) { - current->flags |= PF_SUPERPRIV; - return true; - } - return false; -} - -/** - * ns_capable - Determine if the current task has a superior capability in effect - * @ns: The usernamespace we want the capability in - * @cap: The capability to be tested for - * - * Return true if the current task has the given superior capability currently - * available for use, false if not. - * - * This sets PF_SUPERPRIV on the task if the capability is available on the - * assumption that it's about to be used. - */ -bool ns_capable(struct user_namespace *ns, int cap) -{ - return ns_capable_common(ns, cap, true); -} -EXPORT_SYMBOL(ns_capable); - -/** - * ns_capable_noaudit - Determine if the current task has a superior capability - * (unaudited) in effect - * @ns: The usernamespace we want the capability in - * @cap: The capability to be tested for - * - * Return true if the current task has the given superior capability currently - * available for use, false if not. - * - * This sets PF_SUPERPRIV on the task if the capability is available on the - * assumption that it's about to be used. - */ -bool ns_capable_noaudit(struct user_namespace *ns, int cap) -{ - return ns_capable_common(ns, cap, false); -} -EXPORT_SYMBOL(ns_capable_noaudit); - -/** - * capable - Determine if the current task has a superior capability in effect - * @cap: The capability to be tested for - * - * Return true if the current task has the given superior capability currently - * available for use, false if not. - * - * This sets PF_SUPERPRIV on the task if the capability is available on the - * assumption that it's about to be used. - */ -bool capable(int cap) -{ - return ns_capable(&init_user_ns, cap); -} -EXPORT_SYMBOL(capable); -#endif /* CONFIG_MULTIUSER */ - -/** - * file_ns_capable - Determine if the file's opener had a capability in effect - * @file: The file we want to check - * @ns: The usernamespace we want the capability in - * @cap: The capability to be tested for - * - * Return true if task that opened the file had a capability in effect - * when the file was opened. - * - * This does not set PF_SUPERPRIV because the caller may not - * actually be privileged. - */ -bool file_ns_capable(const struct file *file, struct user_namespace *ns, - int cap) -{ - if (WARN_ON_ONCE(!cap_valid(cap))) - return false; - - if (security_capable(file->f_cred, ns, cap) == 0) - return true; - - return false; -} -EXPORT_SYMBOL(file_ns_capable); - -/** - * capable_wrt_inode_uidgid - Check nsown_capable and uid and gid mapped - * @inode: The inode in question - * @cap: The capability in question - * - * Return true if the current task has the given capability targeted at - * its own user namespace and that the given inode's uid and gid are - * mapped into the current user namespace. - */ -bool capable_wrt_inode_uidgid(const struct inode *inode, int cap) -{ - struct user_namespace *ns = current_user_ns(); - - return ns_capable(ns, cap) && kuid_has_mapping(ns, inode->i_uid) && - kgid_has_mapping(ns, inode->i_gid); -} -EXPORT_SYMBOL(capable_wrt_inode_uidgid); diff --git a/src/linux/kernel/cpu.c b/src/linux/kernel/cpu.c deleted file mode 100644 index a9eee32..0000000 --- a/src/linux/kernel/cpu.c +++ /dev/null @@ -1,1939 +0,0 @@ -/* CPU control. - * (C) 2001, 2002, 2003, 2004 Rusty Russell - * - * This code is licenced under the GPL. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#define CREATE_TRACE_POINTS -#include - -#include "smpboot.h" - -/** - * cpuhp_cpu_state - Per cpu hotplug state storage - * @state: The current cpu state - * @target: The target state - * @thread: Pointer to the hotplug thread - * @should_run: Thread should execute - * @rollback: Perform a rollback - * @single: Single callback invocation - * @bringup: Single callback bringup or teardown selector - * @cb_state: The state for a single callback (install/uninstall) - * @result: Result of the operation - * @done: Signal completion to the issuer of the task - */ -struct cpuhp_cpu_state { - enum cpuhp_state state; - enum cpuhp_state target; -#ifdef CONFIG_SMP - struct task_struct *thread; - bool should_run; - bool rollback; - bool single; - bool bringup; - struct hlist_node *node; - enum cpuhp_state cb_state; - int result; - struct completion done; -#endif -}; - -static DEFINE_PER_CPU(struct cpuhp_cpu_state, cpuhp_state); - -/** - * cpuhp_step - Hotplug state machine step - * @name: Name of the step - * @startup: Startup function of the step - * @teardown: Teardown function of the step - * @skip_onerr: Do not invoke the functions on error rollback - * Will go away once the notifiers are gone - * @cant_stop: Bringup/teardown can't be stopped at this step - */ -struct cpuhp_step { - const char *name; - union { - int (*single)(unsigned int cpu); - int (*multi)(unsigned int cpu, - struct hlist_node *node); - } startup; - union { - int (*single)(unsigned int cpu); - int (*multi)(unsigned int cpu, - struct hlist_node *node); - } teardown; - struct hlist_head list; - bool skip_onerr; - bool cant_stop; - bool multi_instance; -}; - -static DEFINE_MUTEX(cpuhp_state_mutex); -static struct cpuhp_step cpuhp_bp_states[]; -static struct cpuhp_step cpuhp_ap_states[]; - -static bool cpuhp_is_ap_state(enum cpuhp_state state) -{ - /* - * The extra check for CPUHP_TEARDOWN_CPU is only for documentation - * purposes as that state is handled explicitly in cpu_down. - */ - return state > CPUHP_BRINGUP_CPU && state != CPUHP_TEARDOWN_CPU; -} - -static struct cpuhp_step *cpuhp_get_step(enum cpuhp_state state) -{ - struct cpuhp_step *sp; - - sp = cpuhp_is_ap_state(state) ? cpuhp_ap_states : cpuhp_bp_states; - return sp + state; -} - -/** - * cpuhp_invoke_callback _ Invoke the callbacks for a given state - * @cpu: The cpu for which the callback should be invoked - * @step: The step in the state machine - * @bringup: True if the bringup callback should be invoked - * - * Called from cpu hotplug and from the state register machinery. - */ -static int cpuhp_invoke_callback(unsigned int cpu, enum cpuhp_state state, - bool bringup, struct hlist_node *node) -{ - struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); - struct cpuhp_step *step = cpuhp_get_step(state); - int (*cbm)(unsigned int cpu, struct hlist_node *node); - int (*cb)(unsigned int cpu); - int ret, cnt; - - if (!step->multi_instance) { - cb = bringup ? step->startup.single : step->teardown.single; - if (!cb) - return 0; - trace_cpuhp_enter(cpu, st->target, state, cb); - ret = cb(cpu); - trace_cpuhp_exit(cpu, st->state, state, ret); - return ret; - } - cbm = bringup ? step->startup.multi : step->teardown.multi; - if (!cbm) - return 0; - - /* Single invocation for instance add/remove */ - if (node) { - trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node); - ret = cbm(cpu, node); - trace_cpuhp_exit(cpu, st->state, state, ret); - return ret; - } - - /* State transition. Invoke on all instances */ - cnt = 0; - hlist_for_each(node, &step->list) { - trace_cpuhp_multi_enter(cpu, st->target, state, cbm, node); - ret = cbm(cpu, node); - trace_cpuhp_exit(cpu, st->state, state, ret); - if (ret) - goto err; - cnt++; - } - return 0; -err: - /* Rollback the instances if one failed */ - cbm = !bringup ? step->startup.multi : step->teardown.multi; - if (!cbm) - return ret; - - hlist_for_each(node, &step->list) { - if (!cnt--) - break; - cbm(cpu, node); - } - return ret; -} - -#ifdef CONFIG_SMP -/* Serializes the updates to cpu_online_mask, cpu_present_mask */ -static DEFINE_MUTEX(cpu_add_remove_lock); -bool cpuhp_tasks_frozen; -EXPORT_SYMBOL_GPL(cpuhp_tasks_frozen); - -/* - * The following two APIs (cpu_maps_update_begin/done) must be used when - * attempting to serialize the updates to cpu_online_mask & cpu_present_mask. - * The APIs cpu_notifier_register_begin/done() must be used to protect CPU - * hotplug callback (un)registration performed using __register_cpu_notifier() - * or __unregister_cpu_notifier(). - */ -void cpu_maps_update_begin(void) -{ - mutex_lock(&cpu_add_remove_lock); -} -EXPORT_SYMBOL(cpu_notifier_register_begin); - -void cpu_maps_update_done(void) -{ - mutex_unlock(&cpu_add_remove_lock); -} -EXPORT_SYMBOL(cpu_notifier_register_done); - -static RAW_NOTIFIER_HEAD(cpu_chain); - -/* If set, cpu_up and cpu_down will return -EBUSY and do nothing. - * Should always be manipulated under cpu_add_remove_lock - */ -static int cpu_hotplug_disabled; - -#ifdef CONFIG_HOTPLUG_CPU - -static struct { - struct task_struct *active_writer; - /* wait queue to wake up the active_writer */ - wait_queue_head_t wq; - /* verifies that no writer will get active while readers are active */ - struct mutex lock; - /* - * Also blocks the new readers during - * an ongoing cpu hotplug operation. - */ - atomic_t refcount; - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map dep_map; -#endif -} cpu_hotplug = { - .active_writer = NULL, - .wq = __WAIT_QUEUE_HEAD_INITIALIZER(cpu_hotplug.wq), - .lock = __MUTEX_INITIALIZER(cpu_hotplug.lock), -#ifdef CONFIG_DEBUG_LOCK_ALLOC - .dep_map = STATIC_LOCKDEP_MAP_INIT("cpu_hotplug.dep_map", &cpu_hotplug.dep_map), -#endif -}; - -/* Lockdep annotations for get/put_online_cpus() and cpu_hotplug_begin/end() */ -#define cpuhp_lock_acquire_read() lock_map_acquire_read(&cpu_hotplug.dep_map) -#define cpuhp_lock_acquire_tryread() \ - lock_map_acquire_tryread(&cpu_hotplug.dep_map) -#define cpuhp_lock_acquire() lock_map_acquire(&cpu_hotplug.dep_map) -#define cpuhp_lock_release() lock_map_release(&cpu_hotplug.dep_map) - - -void get_online_cpus(void) -{ - might_sleep(); - if (cpu_hotplug.active_writer == current) - return; - cpuhp_lock_acquire_read(); - mutex_lock(&cpu_hotplug.lock); - atomic_inc(&cpu_hotplug.refcount); - mutex_unlock(&cpu_hotplug.lock); -} -EXPORT_SYMBOL_GPL(get_online_cpus); - -void put_online_cpus(void) -{ - int refcount; - - if (cpu_hotplug.active_writer == current) - return; - - refcount = atomic_dec_return(&cpu_hotplug.refcount); - if (WARN_ON(refcount < 0)) /* try to fix things up */ - atomic_inc(&cpu_hotplug.refcount); - - if (refcount <= 0 && waitqueue_active(&cpu_hotplug.wq)) - wake_up(&cpu_hotplug.wq); - - cpuhp_lock_release(); - -} -EXPORT_SYMBOL_GPL(put_online_cpus); - -/* - * This ensures that the hotplug operation can begin only when the - * refcount goes to zero. - * - * Note that during a cpu-hotplug operation, the new readers, if any, - * will be blocked by the cpu_hotplug.lock - * - * Since cpu_hotplug_begin() is always called after invoking - * cpu_maps_update_begin(), we can be sure that only one writer is active. - * - * Note that theoretically, there is a possibility of a livelock: - * - Refcount goes to zero, last reader wakes up the sleeping - * writer. - * - Last reader unlocks the cpu_hotplug.lock. - * - A new reader arrives at this moment, bumps up the refcount. - * - The writer acquires the cpu_hotplug.lock finds the refcount - * non zero and goes to sleep again. - * - * However, this is very difficult to achieve in practice since - * get_online_cpus() not an api which is called all that often. - * - */ -void cpu_hotplug_begin(void) -{ - DEFINE_WAIT(wait); - - cpu_hotplug.active_writer = current; - cpuhp_lock_acquire(); - - for (;;) { - mutex_lock(&cpu_hotplug.lock); - prepare_to_wait(&cpu_hotplug.wq, &wait, TASK_UNINTERRUPTIBLE); - if (likely(!atomic_read(&cpu_hotplug.refcount))) - break; - mutex_unlock(&cpu_hotplug.lock); - schedule(); - } - finish_wait(&cpu_hotplug.wq, &wait); -} - -void cpu_hotplug_done(void) -{ - cpu_hotplug.active_writer = NULL; - mutex_unlock(&cpu_hotplug.lock); - cpuhp_lock_release(); -} - -/* - * Wait for currently running CPU hotplug operations to complete (if any) and - * disable future CPU hotplug (from sysfs). The 'cpu_add_remove_lock' protects - * the 'cpu_hotplug_disabled' flag. The same lock is also acquired by the - * hotplug path before performing hotplug operations. So acquiring that lock - * guarantees mutual exclusion from any currently running hotplug operations. - */ -void cpu_hotplug_disable(void) -{ - cpu_maps_update_begin(); - cpu_hotplug_disabled++; - cpu_maps_update_done(); -} -EXPORT_SYMBOL_GPL(cpu_hotplug_disable); - -static void __cpu_hotplug_enable(void) -{ - if (WARN_ONCE(!cpu_hotplug_disabled, "Unbalanced cpu hotplug enable\n")) - return; - cpu_hotplug_disabled--; -} - -void cpu_hotplug_enable(void) -{ - cpu_maps_update_begin(); - __cpu_hotplug_enable(); - cpu_maps_update_done(); -} -EXPORT_SYMBOL_GPL(cpu_hotplug_enable); -#endif /* CONFIG_HOTPLUG_CPU */ - -/* Need to know about CPUs going up/down? */ -int register_cpu_notifier(struct notifier_block *nb) -{ - int ret; - cpu_maps_update_begin(); - ret = raw_notifier_chain_register(&cpu_chain, nb); - cpu_maps_update_done(); - return ret; -} - -int __register_cpu_notifier(struct notifier_block *nb) -{ - return raw_notifier_chain_register(&cpu_chain, nb); -} - -static int __cpu_notify(unsigned long val, unsigned int cpu, int nr_to_call, - int *nr_calls) -{ - unsigned long mod = cpuhp_tasks_frozen ? CPU_TASKS_FROZEN : 0; - void *hcpu = (void *)(long)cpu; - - int ret; - - ret = __raw_notifier_call_chain(&cpu_chain, val | mod, hcpu, nr_to_call, - nr_calls); - - return notifier_to_errno(ret); -} - -static int cpu_notify(unsigned long val, unsigned int cpu) -{ - return __cpu_notify(val, cpu, -1, NULL); -} - -static void cpu_notify_nofail(unsigned long val, unsigned int cpu) -{ - BUG_ON(cpu_notify(val, cpu)); -} - -/* Notifier wrappers for transitioning to state machine */ -static int notify_prepare(unsigned int cpu) -{ - int nr_calls = 0; - int ret; - - ret = __cpu_notify(CPU_UP_PREPARE, cpu, -1, &nr_calls); - if (ret) { - nr_calls--; - printk(KERN_WARNING "%s: attempt to bring up CPU %u failed\n", - __func__, cpu); - __cpu_notify(CPU_UP_CANCELED, cpu, nr_calls, NULL); - } - return ret; -} - -static int notify_online(unsigned int cpu) -{ - cpu_notify(CPU_ONLINE, cpu); - return 0; -} - -static int bringup_wait_for_ap(unsigned int cpu) -{ - struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); - - wait_for_completion(&st->done); - return st->result; -} - -static int bringup_cpu(unsigned int cpu) -{ - struct task_struct *idle = idle_thread_get(cpu); - int ret; - - /* - * Some architectures have to walk the irq descriptors to - * setup the vector space for the cpu which comes online. - * Prevent irq alloc/free across the bringup. - */ - irq_lock_sparse(); - - /* Arch-specific enabling code. */ - ret = __cpu_up(cpu, idle); - irq_unlock_sparse(); - if (ret) { - cpu_notify(CPU_UP_CANCELED, cpu); - return ret; - } - ret = bringup_wait_for_ap(cpu); - BUG_ON(!cpu_online(cpu)); - return ret; -} - -/* - * Hotplug state machine related functions - */ -static void undo_cpu_down(unsigned int cpu, struct cpuhp_cpu_state *st) -{ - for (st->state++; st->state < st->target; st->state++) { - struct cpuhp_step *step = cpuhp_get_step(st->state); - - if (!step->skip_onerr) - cpuhp_invoke_callback(cpu, st->state, true, NULL); - } -} - -static int cpuhp_down_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st, - enum cpuhp_state target) -{ - enum cpuhp_state prev_state = st->state; - int ret = 0; - - for (; st->state > target; st->state--) { - ret = cpuhp_invoke_callback(cpu, st->state, false, NULL); - if (ret) { - st->target = prev_state; - undo_cpu_down(cpu, st); - break; - } - } - return ret; -} - -static void undo_cpu_up(unsigned int cpu, struct cpuhp_cpu_state *st) -{ - for (st->state--; st->state > st->target; st->state--) { - struct cpuhp_step *step = cpuhp_get_step(st->state); - - if (!step->skip_onerr) - cpuhp_invoke_callback(cpu, st->state, false, NULL); - } -} - -static int cpuhp_up_callbacks(unsigned int cpu, struct cpuhp_cpu_state *st, - enum cpuhp_state target) -{ - enum cpuhp_state prev_state = st->state; - int ret = 0; - - while (st->state < target) { - st->state++; - ret = cpuhp_invoke_callback(cpu, st->state, true, NULL); - if (ret) { - st->target = prev_state; - undo_cpu_up(cpu, st); - break; - } - } - return ret; -} - -/* - * The cpu hotplug threads manage the bringup and teardown of the cpus - */ -static void cpuhp_create(unsigned int cpu) -{ - struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); - - init_completion(&st->done); -} - -static int cpuhp_should_run(unsigned int cpu) -{ - struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); - - return st->should_run; -} - -/* Execute the teardown callbacks. Used to be CPU_DOWN_PREPARE */ -static int cpuhp_ap_offline(unsigned int cpu, struct cpuhp_cpu_state *st) -{ - enum cpuhp_state target = max((int)st->target, CPUHP_TEARDOWN_CPU); - - return cpuhp_down_callbacks(cpu, st, target); -} - -/* Execute the online startup callbacks. Used to be CPU_ONLINE */ -static int cpuhp_ap_online(unsigned int cpu, struct cpuhp_cpu_state *st) -{ - return cpuhp_up_callbacks(cpu, st, st->target); -} - -/* - * Execute teardown/startup callbacks on the plugged cpu. Also used to invoke - * callbacks when a state gets [un]installed at runtime. - */ -static void cpuhp_thread_fun(unsigned int cpu) -{ - struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); - int ret = 0; - - /* - * Paired with the mb() in cpuhp_kick_ap_work and - * cpuhp_invoke_ap_callback, so the work set is consistent visible. - */ - smp_mb(); - if (!st->should_run) - return; - - st->should_run = false; - - /* Single callback invocation for [un]install ? */ - if (st->single) { - if (st->cb_state < CPUHP_AP_ONLINE) { - local_irq_disable(); - ret = cpuhp_invoke_callback(cpu, st->cb_state, - st->bringup, st->node); - local_irq_enable(); - } else { - ret = cpuhp_invoke_callback(cpu, st->cb_state, - st->bringup, st->node); - } - } else if (st->rollback) { - BUG_ON(st->state < CPUHP_AP_ONLINE_IDLE); - - undo_cpu_down(cpu, st); - /* - * This is a momentary workaround to keep the notifier users - * happy. Will go away once we got rid of the notifiers. - */ - cpu_notify_nofail(CPU_DOWN_FAILED, cpu); - st->rollback = false; - } else { - /* Cannot happen .... */ - BUG_ON(st->state < CPUHP_AP_ONLINE_IDLE); - - /* Regular hotplug work */ - if (st->state < st->target) - ret = cpuhp_ap_online(cpu, st); - else if (st->state > st->target) - ret = cpuhp_ap_offline(cpu, st); - } - st->result = ret; - complete(&st->done); -} - -/* Invoke a single callback on a remote cpu */ -static int -cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state, bool bringup, - struct hlist_node *node) -{ - struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); - - if (!cpu_online(cpu)) - return 0; - - /* - * If we are up and running, use the hotplug thread. For early calls - * we invoke the thread function directly. - */ - if (!st->thread) - return cpuhp_invoke_callback(cpu, state, bringup, node); - - st->cb_state = state; - st->single = true; - st->bringup = bringup; - st->node = node; - - /* - * Make sure the above stores are visible before should_run becomes - * true. Paired with the mb() above in cpuhp_thread_fun() - */ - smp_mb(); - st->should_run = true; - wake_up_process(st->thread); - wait_for_completion(&st->done); - return st->result; -} - -/* Regular hotplug invocation of the AP hotplug thread */ -static void __cpuhp_kick_ap_work(struct cpuhp_cpu_state *st) -{ - st->result = 0; - st->single = false; - /* - * Make sure the above stores are visible before should_run becomes - * true. Paired with the mb() above in cpuhp_thread_fun() - */ - smp_mb(); - st->should_run = true; - wake_up_process(st->thread); -} - -static int cpuhp_kick_ap_work(unsigned int cpu) -{ - struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); - enum cpuhp_state state = st->state; - - trace_cpuhp_enter(cpu, st->target, state, cpuhp_kick_ap_work); - __cpuhp_kick_ap_work(st); - wait_for_completion(&st->done); - trace_cpuhp_exit(cpu, st->state, state, st->result); - return st->result; -} - -static struct smp_hotplug_thread cpuhp_threads = { - .store = &cpuhp_state.thread, - .create = &cpuhp_create, - .thread_should_run = cpuhp_should_run, - .thread_fn = cpuhp_thread_fun, - .thread_comm = "cpuhp/%u", - .selfparking = true, -}; - -void __init cpuhp_threads_init(void) -{ - BUG_ON(smpboot_register_percpu_thread(&cpuhp_threads)); - kthread_unpark(this_cpu_read(cpuhp_state.thread)); -} - -#ifdef CONFIG_HOTPLUG_CPU -EXPORT_SYMBOL(register_cpu_notifier); -EXPORT_SYMBOL(__register_cpu_notifier); -void unregister_cpu_notifier(struct notifier_block *nb) -{ - cpu_maps_update_begin(); - raw_notifier_chain_unregister(&cpu_chain, nb); - cpu_maps_update_done(); -} -EXPORT_SYMBOL(unregister_cpu_notifier); - -void __unregister_cpu_notifier(struct notifier_block *nb) -{ - raw_notifier_chain_unregister(&cpu_chain, nb); -} -EXPORT_SYMBOL(__unregister_cpu_notifier); - -/** - * clear_tasks_mm_cpumask - Safely clear tasks' mm_cpumask for a CPU - * @cpu: a CPU id - * - * This function walks all processes, finds a valid mm struct for each one and - * then clears a corresponding bit in mm's cpumask. While this all sounds - * trivial, there are various non-obvious corner cases, which this function - * tries to solve in a safe manner. - * - * Also note that the function uses a somewhat relaxed locking scheme, so it may - * be called only for an already offlined CPU. - */ -void clear_tasks_mm_cpumask(int cpu) -{ - struct task_struct *p; - - /* - * This function is called after the cpu is taken down and marked - * offline, so its not like new tasks will ever get this cpu set in - * their mm mask. -- Peter Zijlstra - * Thus, we may use rcu_read_lock() here, instead of grabbing - * full-fledged tasklist_lock. - */ - WARN_ON(cpu_online(cpu)); - rcu_read_lock(); - for_each_process(p) { - struct task_struct *t; - - /* - * Main thread might exit, but other threads may still have - * a valid mm. Find one. - */ - t = find_lock_task_mm(p); - if (!t) - continue; - cpumask_clear_cpu(cpu, mm_cpumask(t->mm)); - task_unlock(t); - } - rcu_read_unlock(); -} - -static inline void check_for_tasks(int dead_cpu) -{ - struct task_struct *g, *p; - - read_lock(&tasklist_lock); - for_each_process_thread(g, p) { - if (!p->on_rq) - continue; - /* - * We do the check with unlocked task_rq(p)->lock. - * Order the reading to do not warn about a task, - * which was running on this cpu in the past, and - * it's just been woken on another cpu. - */ - rmb(); - if (task_cpu(p) != dead_cpu) - continue; - - pr_warn("Task %s (pid=%d) is on cpu %d (state=%ld, flags=%x)\n", - p->comm, task_pid_nr(p), dead_cpu, p->state, p->flags); - } - read_unlock(&tasklist_lock); -} - -static int notify_down_prepare(unsigned int cpu) -{ - int err, nr_calls = 0; - - err = __cpu_notify(CPU_DOWN_PREPARE, cpu, -1, &nr_calls); - if (err) { - nr_calls--; - __cpu_notify(CPU_DOWN_FAILED, cpu, nr_calls, NULL); - pr_warn("%s: attempt to take down CPU %u failed\n", - __func__, cpu); - } - return err; -} - -/* Take this CPU down. */ -static int take_cpu_down(void *_param) -{ - struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); - enum cpuhp_state target = max((int)st->target, CPUHP_AP_OFFLINE); - int err, cpu = smp_processor_id(); - - /* Ensure this CPU doesn't handle any more interrupts. */ - err = __cpu_disable(); - if (err < 0) - return err; - - /* - * We get here while we are in CPUHP_TEARDOWN_CPU state and we must not - * do this step again. - */ - WARN_ON(st->state != CPUHP_TEARDOWN_CPU); - st->state--; - /* Invoke the former CPU_DYING callbacks */ - for (; st->state > target; st->state--) - cpuhp_invoke_callback(cpu, st->state, false, NULL); - - /* Give up timekeeping duties */ - tick_handover_do_timer(); - /* Park the stopper thread */ - stop_machine_park(cpu); - return 0; -} - -static int takedown_cpu(unsigned int cpu) -{ - struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); - int err; - - /* Park the smpboot threads */ - kthread_park(per_cpu_ptr(&cpuhp_state, cpu)->thread); - smpboot_park_threads(cpu); - - /* - * Prevent irq alloc/free while the dying cpu reorganizes the - * interrupt affinities. - */ - irq_lock_sparse(); - - /* - * So now all preempt/rcu users must observe !cpu_active(). - */ - err = stop_machine(take_cpu_down, NULL, cpumask_of(cpu)); - if (err) { - /* CPU refused to die */ - irq_unlock_sparse(); - /* Unpark the hotplug thread so we can rollback there */ - kthread_unpark(per_cpu_ptr(&cpuhp_state, cpu)->thread); - return err; - } - BUG_ON(cpu_online(cpu)); - - /* - * The CPUHP_AP_SCHED_MIGRATE_DYING callback will have removed all - * runnable tasks from the cpu, there's only the idle task left now - * that the migration thread is done doing the stop_machine thing. - * - * Wait for the stop thread to go away. - */ - wait_for_completion(&st->done); - BUG_ON(st->state != CPUHP_AP_IDLE_DEAD); - - /* Interrupts are moved away from the dying cpu, reenable alloc/free */ - irq_unlock_sparse(); - - hotplug_cpu__broadcast_tick_pull(cpu); - /* This actually kills the CPU. */ - __cpu_die(cpu); - - tick_cleanup_dead_cpu(cpu); - return 0; -} - -static int notify_dead(unsigned int cpu) -{ - cpu_notify_nofail(CPU_DEAD, cpu); - check_for_tasks(cpu); - return 0; -} - -static void cpuhp_complete_idle_dead(void *arg) -{ - struct cpuhp_cpu_state *st = arg; - - complete(&st->done); -} - -void cpuhp_report_idle_dead(void) -{ - struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); - - BUG_ON(st->state != CPUHP_AP_OFFLINE); - rcu_report_dead(smp_processor_id()); - st->state = CPUHP_AP_IDLE_DEAD; - /* - * We cannot call complete after rcu_report_dead() so we delegate it - * to an online cpu. - */ - smp_call_function_single(cpumask_first(cpu_online_mask), - cpuhp_complete_idle_dead, st, 0); -} - -#else -#define notify_down_prepare NULL -#define takedown_cpu NULL -#define notify_dead NULL -#endif - -#ifdef CONFIG_HOTPLUG_CPU - -/* Requires cpu_add_remove_lock to be held */ -static int __ref _cpu_down(unsigned int cpu, int tasks_frozen, - enum cpuhp_state target) -{ - struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); - int prev_state, ret = 0; - bool hasdied = false; - - if (num_online_cpus() == 1) - return -EBUSY; - - if (!cpu_present(cpu)) - return -EINVAL; - - cpu_hotplug_begin(); - - cpuhp_tasks_frozen = tasks_frozen; - - prev_state = st->state; - st->target = target; - /* - * If the current CPU state is in the range of the AP hotplug thread, - * then we need to kick the thread. - */ - if (st->state > CPUHP_TEARDOWN_CPU) { - ret = cpuhp_kick_ap_work(cpu); - /* - * The AP side has done the error rollback already. Just - * return the error code.. - */ - if (ret) - goto out; - - /* - * We might have stopped still in the range of the AP hotplug - * thread. Nothing to do anymore. - */ - if (st->state > CPUHP_TEARDOWN_CPU) - goto out; - } - /* - * The AP brought itself down to CPUHP_TEARDOWN_CPU. So we need - * to do the further cleanups. - */ - ret = cpuhp_down_callbacks(cpu, st, target); - if (ret && st->state > CPUHP_TEARDOWN_CPU && st->state < prev_state) { - st->target = prev_state; - st->rollback = true; - cpuhp_kick_ap_work(cpu); - } - - hasdied = prev_state != st->state && st->state == CPUHP_OFFLINE; -out: - cpu_hotplug_done(); - /* This post dead nonsense must die */ - if (!ret && hasdied) - cpu_notify_nofail(CPU_POST_DEAD, cpu); - return ret; -} - -static int do_cpu_down(unsigned int cpu, enum cpuhp_state target) -{ - int err; - - cpu_maps_update_begin(); - - if (cpu_hotplug_disabled) { - err = -EBUSY; - goto out; - } - - err = _cpu_down(cpu, 0, target); - -out: - cpu_maps_update_done(); - return err; -} -int cpu_down(unsigned int cpu) -{ - return do_cpu_down(cpu, CPUHP_OFFLINE); -} -EXPORT_SYMBOL(cpu_down); -#endif /*CONFIG_HOTPLUG_CPU*/ - -/** - * notify_cpu_starting(cpu) - Invoke the callbacks on the starting CPU - * @cpu: cpu that just started - * - * It must be called by the arch code on the new cpu, before the new cpu - * enables interrupts and before the "boot" cpu returns from __cpu_up(). - */ -void notify_cpu_starting(unsigned int cpu) -{ - struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); - enum cpuhp_state target = min((int)st->target, CPUHP_AP_ONLINE); - - rcu_cpu_starting(cpu); /* Enables RCU usage on this CPU. */ - while (st->state < target) { - st->state++; - cpuhp_invoke_callback(cpu, st->state, true, NULL); - } -} - -/* - * Called from the idle task. We need to set active here, so we can kick off - * the stopper thread and unpark the smpboot threads. If the target state is - * beyond CPUHP_AP_ONLINE_IDLE we kick cpuhp thread and let it bring up the - * cpu further. - */ -void cpuhp_online_idle(enum cpuhp_state state) -{ - struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); - unsigned int cpu = smp_processor_id(); - - /* Happens for the boot cpu */ - if (state != CPUHP_AP_ONLINE_IDLE) - return; - - st->state = CPUHP_AP_ONLINE_IDLE; - - /* Unpark the stopper thread and the hotplug thread of this cpu */ - stop_machine_unpark(cpu); - kthread_unpark(st->thread); - - /* Should we go further up ? */ - if (st->target > CPUHP_AP_ONLINE_IDLE) - __cpuhp_kick_ap_work(st); - else - complete(&st->done); -} - -/* Requires cpu_add_remove_lock to be held */ -static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target) -{ - struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); - struct task_struct *idle; - int ret = 0; - - cpu_hotplug_begin(); - - if (!cpu_present(cpu)) { - ret = -EINVAL; - goto out; - } - - /* - * The caller of do_cpu_up might have raced with another - * caller. Ignore it for now. - */ - if (st->state >= target) - goto out; - - if (st->state == CPUHP_OFFLINE) { - /* Let it fail before we try to bring the cpu up */ - idle = idle_thread_get(cpu); - if (IS_ERR(idle)) { - ret = PTR_ERR(idle); - goto out; - } - } - - cpuhp_tasks_frozen = tasks_frozen; - - st->target = target; - /* - * If the current CPU state is in the range of the AP hotplug thread, - * then we need to kick the thread once more. - */ - if (st->state > CPUHP_BRINGUP_CPU) { - ret = cpuhp_kick_ap_work(cpu); - /* - * The AP side has done the error rollback already. Just - * return the error code.. - */ - if (ret) - goto out; - } - - /* - * Try to reach the target state. We max out on the BP at - * CPUHP_BRINGUP_CPU. After that the AP hotplug thread is - * responsible for bringing it up to the target state. - */ - target = min((int)target, CPUHP_BRINGUP_CPU); - ret = cpuhp_up_callbacks(cpu, st, target); -out: - cpu_hotplug_done(); - return ret; -} - -static int do_cpu_up(unsigned int cpu, enum cpuhp_state target) -{ - int err = 0; - - if (!cpu_possible(cpu)) { - pr_err("can't online cpu %d because it is not configured as may-hotadd at boot time\n", - cpu); -#if defined(CONFIG_IA64) - pr_err("please check additional_cpus= boot parameter\n"); -#endif - return -EINVAL; - } - - err = try_online_node(cpu_to_node(cpu)); - if (err) - return err; - - cpu_maps_update_begin(); - - if (cpu_hotplug_disabled) { - err = -EBUSY; - goto out; - } - - err = _cpu_up(cpu, 0, target); -out: - cpu_maps_update_done(); - return err; -} - -int cpu_up(unsigned int cpu) -{ - return do_cpu_up(cpu, CPUHP_ONLINE); -} -EXPORT_SYMBOL_GPL(cpu_up); - -#ifdef CONFIG_PM_SLEEP_SMP -static cpumask_var_t frozen_cpus; - -int freeze_secondary_cpus(int primary) -{ - int cpu, error = 0; - - cpu_maps_update_begin(); - if (!cpu_online(primary)) - primary = cpumask_first(cpu_online_mask); - /* - * We take down all of the non-boot CPUs in one shot to avoid races - * with the userspace trying to use the CPU hotplug at the same time - */ - cpumask_clear(frozen_cpus); - - pr_info("Disabling non-boot CPUs ...\n"); - for_each_online_cpu(cpu) { - if (cpu == primary) - continue; - trace_suspend_resume(TPS("CPU_OFF"), cpu, true); - error = _cpu_down(cpu, 1, CPUHP_OFFLINE); - trace_suspend_resume(TPS("CPU_OFF"), cpu, false); - if (!error) - cpumask_set_cpu(cpu, frozen_cpus); - else { - pr_err("Error taking CPU%d down: %d\n", cpu, error); - break; - } - } - - if (!error) - BUG_ON(num_online_cpus() > 1); - else - pr_err("Non-boot CPUs are not disabled\n"); - - /* - * Make sure the CPUs won't be enabled by someone else. We need to do - * this even in case of failure as all disable_nonboot_cpus() users are - * supposed to do enable_nonboot_cpus() on the failure path. - */ - cpu_hotplug_disabled++; - - cpu_maps_update_done(); - return error; -} - -void __weak arch_enable_nonboot_cpus_begin(void) -{ -} - -void __weak arch_enable_nonboot_cpus_end(void) -{ -} - -void enable_nonboot_cpus(void) -{ - int cpu, error; - - /* Allow everyone to use the CPU hotplug again */ - cpu_maps_update_begin(); - __cpu_hotplug_enable(); - if (cpumask_empty(frozen_cpus)) - goto out; - - pr_info("Enabling non-boot CPUs ...\n"); - - arch_enable_nonboot_cpus_begin(); - - for_each_cpu(cpu, frozen_cpus) { - trace_suspend_resume(TPS("CPU_ON"), cpu, true); - error = _cpu_up(cpu, 1, CPUHP_ONLINE); - trace_suspend_resume(TPS("CPU_ON"), cpu, false); - if (!error) { - pr_info("CPU%d is up\n", cpu); - continue; - } - pr_warn("Error taking CPU%d up: %d\n", cpu, error); - } - - arch_enable_nonboot_cpus_end(); - - cpumask_clear(frozen_cpus); -out: - cpu_maps_update_done(); -} - -static int __init alloc_frozen_cpus(void) -{ - if (!alloc_cpumask_var(&frozen_cpus, GFP_KERNEL|__GFP_ZERO)) - return -ENOMEM; - return 0; -} -core_initcall(alloc_frozen_cpus); - -/* - * When callbacks for CPU hotplug notifications are being executed, we must - * ensure that the state of the system with respect to the tasks being frozen - * or not, as reported by the notification, remains unchanged *throughout the - * duration* of the execution of the callbacks. - * Hence we need to prevent the freezer from racing with regular CPU hotplug. - * - * This synchronization is implemented by mutually excluding regular CPU - * hotplug and Suspend/Hibernate call paths by hooking onto the Suspend/ - * Hibernate notifications. - */ -static int -cpu_hotplug_pm_callback(struct notifier_block *nb, - unsigned long action, void *ptr) -{ - switch (action) { - - case PM_SUSPEND_PREPARE: - case PM_HIBERNATION_PREPARE: - cpu_hotplug_disable(); - break; - - case PM_POST_SUSPEND: - case PM_POST_HIBERNATION: - cpu_hotplug_enable(); - break; - - default: - return NOTIFY_DONE; - } - - return NOTIFY_OK; -} - - -static int __init cpu_hotplug_pm_sync_init(void) -{ - /* - * cpu_hotplug_pm_callback has higher priority than x86 - * bsp_pm_callback which depends on cpu_hotplug_pm_callback - * to disable cpu hotplug to avoid cpu hotplug race. - */ - pm_notifier(cpu_hotplug_pm_callback, 0); - return 0; -} -core_initcall(cpu_hotplug_pm_sync_init); - -#endif /* CONFIG_PM_SLEEP_SMP */ - -#endif /* CONFIG_SMP */ - -/* Boot processor state steps */ -static struct cpuhp_step cpuhp_bp_states[] = { - [CPUHP_OFFLINE] = { - .name = "offline", - .startup.single = NULL, - .teardown.single = NULL, - }, -#ifdef CONFIG_SMP - [CPUHP_CREATE_THREADS]= { - .name = "threads:prepare", - .startup.single = smpboot_create_threads, - .teardown.single = NULL, - .cant_stop = true, - }, - [CPUHP_PERF_PREPARE] = { - .name = "perf:prepare", - .startup.single = perf_event_init_cpu, - .teardown.single = perf_event_exit_cpu, - }, - [CPUHP_WORKQUEUE_PREP] = { - .name = "workqueue:prepare", - .startup.single = workqueue_prepare_cpu, - .teardown.single = NULL, - }, - [CPUHP_HRTIMERS_PREPARE] = { - .name = "hrtimers:prepare", - .startup.single = hrtimers_prepare_cpu, - .teardown.single = hrtimers_dead_cpu, - }, - [CPUHP_SMPCFD_PREPARE] = { - .name = "smpcfd:prepare", - .startup.single = smpcfd_prepare_cpu, - .teardown.single = smpcfd_dead_cpu, - }, - [CPUHP_RELAY_PREPARE] = { - .name = "relay:prepare", - .startup.single = relay_prepare_cpu, - .teardown.single = NULL, - }, - [CPUHP_SLAB_PREPARE] = { - .name = "slab:prepare", - .startup.single = slab_prepare_cpu, - .teardown.single = slab_dead_cpu, - }, - [CPUHP_RCUTREE_PREP] = { - .name = "RCU/tree:prepare", - .startup.single = rcutree_prepare_cpu, - .teardown.single = rcutree_dead_cpu, - }, - /* - * Preparatory and dead notifiers. Will be replaced once the notifiers - * are converted to states. - */ - [CPUHP_NOTIFY_PREPARE] = { - .name = "notify:prepare", - .startup.single = notify_prepare, - .teardown.single = notify_dead, - .skip_onerr = true, - .cant_stop = true, - }, - /* - * On the tear-down path, timers_dead_cpu() must be invoked - * before blk_mq_queue_reinit_notify() from notify_dead(), - * otherwise a RCU stall occurs. - */ - [CPUHP_TIMERS_DEAD] = { - .name = "timers:dead", - .startup.single = NULL, - .teardown.single = timers_dead_cpu, - }, - /* Kicks the plugged cpu into life */ - [CPUHP_BRINGUP_CPU] = { - .name = "cpu:bringup", - .startup.single = bringup_cpu, - .teardown.single = NULL, - .cant_stop = true, - }, - [CPUHP_AP_SMPCFD_DYING] = { - .name = "smpcfd:dying", - .startup.single = NULL, - .teardown.single = smpcfd_dying_cpu, - }, - /* - * Handled on controll processor until the plugged processor manages - * this itself. - */ - [CPUHP_TEARDOWN_CPU] = { - .name = "cpu:teardown", - .startup.single = NULL, - .teardown.single = takedown_cpu, - .cant_stop = true, - }, -#else - [CPUHP_BRINGUP_CPU] = { }, -#endif -}; - -/* Application processor state steps */ -static struct cpuhp_step cpuhp_ap_states[] = { -#ifdef CONFIG_SMP - /* Final state before CPU kills itself */ - [CPUHP_AP_IDLE_DEAD] = { - .name = "idle:dead", - }, - /* - * Last state before CPU enters the idle loop to die. Transient state - * for synchronization. - */ - [CPUHP_AP_OFFLINE] = { - .name = "ap:offline", - .cant_stop = true, - }, - /* First state is scheduler control. Interrupts are disabled */ - [CPUHP_AP_SCHED_STARTING] = { - .name = "sched:starting", - .startup.single = sched_cpu_starting, - .teardown.single = sched_cpu_dying, - }, - [CPUHP_AP_RCUTREE_DYING] = { - .name = "RCU/tree:dying", - .startup.single = NULL, - .teardown.single = rcutree_dying_cpu, - }, - /* Entry state on starting. Interrupts enabled from here on. Transient - * state for synchronsization */ - [CPUHP_AP_ONLINE] = { - .name = "ap:online", - }, - /* Handle smpboot threads park/unpark */ - [CPUHP_AP_SMPBOOT_THREADS] = { - .name = "smpboot/threads:online", - .startup.single = smpboot_unpark_threads, - .teardown.single = NULL, - }, - [CPUHP_AP_PERF_ONLINE] = { - .name = "perf:online", - .startup.single = perf_event_init_cpu, - .teardown.single = perf_event_exit_cpu, - }, - [CPUHP_AP_WORKQUEUE_ONLINE] = { - .name = "workqueue:online", - .startup.single = workqueue_online_cpu, - .teardown.single = workqueue_offline_cpu, - }, - [CPUHP_AP_RCUTREE_ONLINE] = { - .name = "RCU/tree:online", - .startup.single = rcutree_online_cpu, - .teardown.single = rcutree_offline_cpu, - }, - - /* - * Online/down_prepare notifiers. Will be removed once the notifiers - * are converted to states. - */ - [CPUHP_AP_NOTIFY_ONLINE] = { - .name = "notify:online", - .startup.single = notify_online, - .teardown.single = notify_down_prepare, - .skip_onerr = true, - }, -#endif - /* - * The dynamically registered state space is here - */ - -#ifdef CONFIG_SMP - /* Last state is scheduler control setting the cpu active */ - [CPUHP_AP_ACTIVE] = { - .name = "sched:active", - .startup.single = sched_cpu_activate, - .teardown.single = sched_cpu_deactivate, - }, -#endif - - /* CPU is fully up and running. */ - [CPUHP_ONLINE] = { - .name = "online", - .startup.single = NULL, - .teardown.single = NULL, - }, -}; - -/* Sanity check for callbacks */ -static int cpuhp_cb_check(enum cpuhp_state state) -{ - if (state <= CPUHP_OFFLINE || state >= CPUHP_ONLINE) - return -EINVAL; - return 0; -} - -static void cpuhp_store_callbacks(enum cpuhp_state state, - const char *name, - int (*startup)(unsigned int cpu), - int (*teardown)(unsigned int cpu), - bool multi_instance) -{ - /* (Un)Install the callbacks for further cpu hotplug operations */ - struct cpuhp_step *sp; - - mutex_lock(&cpuhp_state_mutex); - sp = cpuhp_get_step(state); - sp->startup.single = startup; - sp->teardown.single = teardown; - sp->name = name; - sp->multi_instance = multi_instance; - INIT_HLIST_HEAD(&sp->list); - mutex_unlock(&cpuhp_state_mutex); -} - -static void *cpuhp_get_teardown_cb(enum cpuhp_state state) -{ - return cpuhp_get_step(state)->teardown.single; -} - -/* - * Call the startup/teardown function for a step either on the AP or - * on the current CPU. - */ -static int cpuhp_issue_call(int cpu, enum cpuhp_state state, bool bringup, - struct hlist_node *node) -{ - struct cpuhp_step *sp = cpuhp_get_step(state); - int ret; - - if ((bringup && !sp->startup.single) || - (!bringup && !sp->teardown.single)) - return 0; - /* - * The non AP bound callbacks can fail on bringup. On teardown - * e.g. module removal we crash for now. - */ -#ifdef CONFIG_SMP - if (cpuhp_is_ap_state(state)) - ret = cpuhp_invoke_ap_callback(cpu, state, bringup, node); - else - ret = cpuhp_invoke_callback(cpu, state, bringup, node); -#else - ret = cpuhp_invoke_callback(cpu, state, bringup, node); -#endif - BUG_ON(ret && !bringup); - return ret; -} - -/* - * Called from __cpuhp_setup_state on a recoverable failure. - * - * Note: The teardown callbacks for rollback are not allowed to fail! - */ -static void cpuhp_rollback_install(int failedcpu, enum cpuhp_state state, - struct hlist_node *node) -{ - int cpu; - - /* Roll back the already executed steps on the other cpus */ - for_each_present_cpu(cpu) { - struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); - int cpustate = st->state; - - if (cpu >= failedcpu) - break; - - /* Did we invoke the startup call on that cpu ? */ - if (cpustate >= state) - cpuhp_issue_call(cpu, state, false, node); - } -} - -/* - * Returns a free for dynamic slot assignment of the Online state. The states - * are protected by the cpuhp_slot_states mutex and an empty slot is identified - * by having no name assigned. - */ -static int cpuhp_reserve_state(enum cpuhp_state state) -{ - enum cpuhp_state i; - - mutex_lock(&cpuhp_state_mutex); - for (i = CPUHP_AP_ONLINE_DYN; i <= CPUHP_AP_ONLINE_DYN_END; i++) { - if (cpuhp_ap_states[i].name) - continue; - - cpuhp_ap_states[i].name = "Reserved"; - mutex_unlock(&cpuhp_state_mutex); - return i; - } - mutex_unlock(&cpuhp_state_mutex); - WARN(1, "No more dynamic states available for CPU hotplug\n"); - return -ENOSPC; -} - -int __cpuhp_state_add_instance(enum cpuhp_state state, struct hlist_node *node, - bool invoke) -{ - struct cpuhp_step *sp; - int cpu; - int ret; - - sp = cpuhp_get_step(state); - if (sp->multi_instance == false) - return -EINVAL; - - get_online_cpus(); - - if (!invoke || !sp->startup.multi) - goto add_node; - - /* - * Try to call the startup callback for each present cpu - * depending on the hotplug state of the cpu. - */ - for_each_present_cpu(cpu) { - struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); - int cpustate = st->state; - - if (cpustate < state) - continue; - - ret = cpuhp_issue_call(cpu, state, true, node); - if (ret) { - if (sp->teardown.multi) - cpuhp_rollback_install(cpu, state, node); - goto err; - } - } -add_node: - ret = 0; - mutex_lock(&cpuhp_state_mutex); - hlist_add_head(node, &sp->list); - mutex_unlock(&cpuhp_state_mutex); - -err: - put_online_cpus(); - return ret; -} -EXPORT_SYMBOL_GPL(__cpuhp_state_add_instance); - -/** - * __cpuhp_setup_state - Setup the callbacks for an hotplug machine state - * @state: The state to setup - * @invoke: If true, the startup function is invoked for cpus where - * cpu state >= @state - * @startup: startup callback function - * @teardown: teardown callback function - * - * Returns 0 if successful, otherwise a proper error code - */ -int __cpuhp_setup_state(enum cpuhp_state state, - const char *name, bool invoke, - int (*startup)(unsigned int cpu), - int (*teardown)(unsigned int cpu), - bool multi_instance) -{ - int cpu, ret = 0; - int dyn_state = 0; - - if (cpuhp_cb_check(state) || !name) - return -EINVAL; - - get_online_cpus(); - - /* currently assignments for the ONLINE state are possible */ - if (state == CPUHP_AP_ONLINE_DYN) { - dyn_state = 1; - ret = cpuhp_reserve_state(state); - if (ret < 0) - goto out; - state = ret; - } - - cpuhp_store_callbacks(state, name, startup, teardown, multi_instance); - - if (!invoke || !startup) - goto out; - - /* - * Try to call the startup callback for each present cpu - * depending on the hotplug state of the cpu. - */ - for_each_present_cpu(cpu) { - struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); - int cpustate = st->state; - - if (cpustate < state) - continue; - - ret = cpuhp_issue_call(cpu, state, true, NULL); - if (ret) { - if (teardown) - cpuhp_rollback_install(cpu, state, NULL); - cpuhp_store_callbacks(state, NULL, NULL, NULL, false); - goto out; - } - } -out: - put_online_cpus(); - if (!ret && dyn_state) - return state; - return ret; -} -EXPORT_SYMBOL(__cpuhp_setup_state); - -int __cpuhp_state_remove_instance(enum cpuhp_state state, - struct hlist_node *node, bool invoke) -{ - struct cpuhp_step *sp = cpuhp_get_step(state); - int cpu; - - BUG_ON(cpuhp_cb_check(state)); - - if (!sp->multi_instance) - return -EINVAL; - - get_online_cpus(); - if (!invoke || !cpuhp_get_teardown_cb(state)) - goto remove; - /* - * Call the teardown callback for each present cpu depending - * on the hotplug state of the cpu. This function is not - * allowed to fail currently! - */ - for_each_present_cpu(cpu) { - struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); - int cpustate = st->state; - - if (cpustate >= state) - cpuhp_issue_call(cpu, state, false, node); - } - -remove: - mutex_lock(&cpuhp_state_mutex); - hlist_del(node); - mutex_unlock(&cpuhp_state_mutex); - put_online_cpus(); - - return 0; -} -EXPORT_SYMBOL_GPL(__cpuhp_state_remove_instance); -/** - * __cpuhp_remove_state - Remove the callbacks for an hotplug machine state - * @state: The state to remove - * @invoke: If true, the teardown function is invoked for cpus where - * cpu state >= @state - * - * The teardown callback is currently not allowed to fail. Think - * about module removal! - */ -void __cpuhp_remove_state(enum cpuhp_state state, bool invoke) -{ - struct cpuhp_step *sp = cpuhp_get_step(state); - int cpu; - - BUG_ON(cpuhp_cb_check(state)); - - get_online_cpus(); - - if (sp->multi_instance) { - WARN(!hlist_empty(&sp->list), - "Error: Removing state %d which has instances left.\n", - state); - goto remove; - } - - if (!invoke || !cpuhp_get_teardown_cb(state)) - goto remove; - - /* - * Call the teardown callback for each present cpu depending - * on the hotplug state of the cpu. This function is not - * allowed to fail currently! - */ - for_each_present_cpu(cpu) { - struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); - int cpustate = st->state; - - if (cpustate >= state) - cpuhp_issue_call(cpu, state, false, NULL); - } -remove: - cpuhp_store_callbacks(state, NULL, NULL, NULL, false); - put_online_cpus(); -} -EXPORT_SYMBOL(__cpuhp_remove_state); - -#if defined(CONFIG_SYSFS) && defined(CONFIG_HOTPLUG_CPU) -static ssize_t show_cpuhp_state(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id); - - return sprintf(buf, "%d\n", st->state); -} -static DEVICE_ATTR(state, 0444, show_cpuhp_state, NULL); - -static ssize_t write_cpuhp_target(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id); - struct cpuhp_step *sp; - int target, ret; - - ret = kstrtoint(buf, 10, &target); - if (ret) - return ret; - -#ifdef CONFIG_CPU_HOTPLUG_STATE_CONTROL - if (target < CPUHP_OFFLINE || target > CPUHP_ONLINE) - return -EINVAL; -#else - if (target != CPUHP_OFFLINE && target != CPUHP_ONLINE) - return -EINVAL; -#endif - - ret = lock_device_hotplug_sysfs(); - if (ret) - return ret; - - mutex_lock(&cpuhp_state_mutex); - sp = cpuhp_get_step(target); - ret = !sp->name || sp->cant_stop ? -EINVAL : 0; - mutex_unlock(&cpuhp_state_mutex); - if (ret) - return ret; - - if (st->state < target) - ret = do_cpu_up(dev->id, target); - else - ret = do_cpu_down(dev->id, target); - - unlock_device_hotplug(); - return ret ? ret : count; -} - -static ssize_t show_cpuhp_target(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id); - - return sprintf(buf, "%d\n", st->target); -} -static DEVICE_ATTR(target, 0644, show_cpuhp_target, write_cpuhp_target); - -static struct attribute *cpuhp_cpu_attrs[] = { - &dev_attr_state.attr, - &dev_attr_target.attr, - NULL -}; - -static struct attribute_group cpuhp_cpu_attr_group = { - .attrs = cpuhp_cpu_attrs, - .name = "hotplug", - NULL -}; - -static ssize_t show_cpuhp_states(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssize_t cur, res = 0; - int i; - - mutex_lock(&cpuhp_state_mutex); - for (i = CPUHP_OFFLINE; i <= CPUHP_ONLINE; i++) { - struct cpuhp_step *sp = cpuhp_get_step(i); - - if (sp->name) { - cur = sprintf(buf, "%3d: %s\n", i, sp->name); - buf += cur; - res += cur; - } - } - mutex_unlock(&cpuhp_state_mutex); - return res; -} -static DEVICE_ATTR(states, 0444, show_cpuhp_states, NULL); - -static struct attribute *cpuhp_cpu_root_attrs[] = { - &dev_attr_states.attr, - NULL -}; - -static struct attribute_group cpuhp_cpu_root_attr_group = { - .attrs = cpuhp_cpu_root_attrs, - .name = "hotplug", - NULL -}; - -static int __init cpuhp_sysfs_init(void) -{ - int cpu, ret; - - ret = sysfs_create_group(&cpu_subsys.dev_root->kobj, - &cpuhp_cpu_root_attr_group); - if (ret) - return ret; - - for_each_possible_cpu(cpu) { - struct device *dev = get_cpu_device(cpu); - - if (!dev) - continue; - ret = sysfs_create_group(&dev->kobj, &cpuhp_cpu_attr_group); - if (ret) - return ret; - } - return 0; -} -device_initcall(cpuhp_sysfs_init); -#endif - -/* - * cpu_bit_bitmap[] is a special, "compressed" data structure that - * represents all NR_CPUS bits binary values of 1< 32 - MASK_DECLARE_8(32), MASK_DECLARE_8(40), - MASK_DECLARE_8(48), MASK_DECLARE_8(56), -#endif -}; -EXPORT_SYMBOL_GPL(cpu_bit_bitmap); - -const DECLARE_BITMAP(cpu_all_bits, NR_CPUS) = CPU_BITS_ALL; -EXPORT_SYMBOL(cpu_all_bits); - -#ifdef CONFIG_INIT_ALL_POSSIBLE -struct cpumask __cpu_possible_mask __read_mostly - = {CPU_BITS_ALL}; -#else -struct cpumask __cpu_possible_mask __read_mostly; -#endif -EXPORT_SYMBOL(__cpu_possible_mask); - -struct cpumask __cpu_online_mask __read_mostly; -EXPORT_SYMBOL(__cpu_online_mask); - -struct cpumask __cpu_present_mask __read_mostly; -EXPORT_SYMBOL(__cpu_present_mask); - -struct cpumask __cpu_active_mask __read_mostly; -EXPORT_SYMBOL(__cpu_active_mask); - -void init_cpu_present(const struct cpumask *src) -{ - cpumask_copy(&__cpu_present_mask, src); -} - -void init_cpu_possible(const struct cpumask *src) -{ - cpumask_copy(&__cpu_possible_mask, src); -} - -void init_cpu_online(const struct cpumask *src) -{ - cpumask_copy(&__cpu_online_mask, src); -} - -/* - * Activate the first processor. - */ -void __init boot_cpu_init(void) -{ - int cpu = smp_processor_id(); - - /* Mark the boot cpu "present", "online" etc for SMP and UP case */ - set_cpu_online(cpu, true); - set_cpu_active(cpu, true); - set_cpu_present(cpu, true); - set_cpu_possible(cpu, true); -} - -/* - * Must be called _AFTER_ setting up the per_cpu areas - */ -void __init boot_cpu_state_init(void) -{ - per_cpu_ptr(&cpuhp_state, smp_processor_id())->state = CPUHP_ONLINE; -} - -void __weak cpu_yield_to_irqs(void) -{ -} -EXPORT_SYMBOL(cpu_yield_to_irqs); diff --git a/src/linux/kernel/cred.c b/src/linux/kernel/cred.c deleted file mode 100644 index 5f264fb..0000000 --- a/src/linux/kernel/cred.c +++ /dev/null @@ -1,817 +0,0 @@ -/* Task credentials management - see Documentation/security/credentials.txt - * - * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if 0 -#define kdebug(FMT, ...) \ - printk("[%-5.5s%5u] " FMT "\n", \ - current->comm, current->pid, ##__VA_ARGS__) -#else -#define kdebug(FMT, ...) \ -do { \ - if (0) \ - no_printk("[%-5.5s%5u] " FMT "\n", \ - current->comm, current->pid, ##__VA_ARGS__); \ -} while (0) -#endif - -static struct kmem_cache *cred_jar; - -/* init to 2 - one for init_task, one to ensure it is never freed */ -struct group_info init_groups = { .usage = ATOMIC_INIT(2) }; - -/* - * The initial credentials for the initial task - */ -struct cred init_cred = { - .usage = ATOMIC_INIT(4), -#ifdef CONFIG_DEBUG_CREDENTIALS - .subscribers = ATOMIC_INIT(2), - .magic = CRED_MAGIC, -#endif - .uid = GLOBAL_ROOT_UID, - .gid = GLOBAL_ROOT_GID, - .suid = GLOBAL_ROOT_UID, - .sgid = GLOBAL_ROOT_GID, - .euid = GLOBAL_ROOT_UID, - .egid = GLOBAL_ROOT_GID, - .fsuid = GLOBAL_ROOT_UID, - .fsgid = GLOBAL_ROOT_GID, - .securebits = SECUREBITS_DEFAULT, - .cap_inheritable = CAP_EMPTY_SET, - .cap_permitted = CAP_FULL_SET, - .cap_effective = CAP_FULL_SET, - .cap_bset = CAP_FULL_SET, - .user = INIT_USER, - .user_ns = &init_user_ns, - .group_info = &init_groups, -}; - -static inline void set_cred_subscribers(struct cred *cred, int n) -{ -#ifdef CONFIG_DEBUG_CREDENTIALS - atomic_set(&cred->subscribers, n); -#endif -} - -static inline int read_cred_subscribers(const struct cred *cred) -{ -#ifdef CONFIG_DEBUG_CREDENTIALS - return atomic_read(&cred->subscribers); -#else - return 0; -#endif -} - -static inline void alter_cred_subscribers(const struct cred *_cred, int n) -{ -#ifdef CONFIG_DEBUG_CREDENTIALS - struct cred *cred = (struct cred *) _cred; - - atomic_add(n, &cred->subscribers); -#endif -} - -/* - * The RCU callback to actually dispose of a set of credentials - */ -static void put_cred_rcu(struct rcu_head *rcu) -{ - struct cred *cred = container_of(rcu, struct cred, rcu); - - kdebug("put_cred_rcu(%p)", cred); - -#ifdef CONFIG_DEBUG_CREDENTIALS - if (cred->magic != CRED_MAGIC_DEAD || - atomic_read(&cred->usage) != 0 || - read_cred_subscribers(cred) != 0) - panic("CRED: put_cred_rcu() sees %p with" - " mag %x, put %p, usage %d, subscr %d\n", - cred, cred->magic, cred->put_addr, - atomic_read(&cred->usage), - read_cred_subscribers(cred)); -#else - if (atomic_read(&cred->usage) != 0) - panic("CRED: put_cred_rcu() sees %p with usage %d\n", - cred, atomic_read(&cred->usage)); -#endif - - security_cred_free(cred); - key_put(cred->session_keyring); - key_put(cred->process_keyring); - key_put(cred->thread_keyring); - key_put(cred->request_key_auth); - if (cred->group_info) - put_group_info(cred->group_info); - free_uid(cred->user); - put_user_ns(cred->user_ns); - kmem_cache_free(cred_jar, cred); -} - -/** - * __put_cred - Destroy a set of credentials - * @cred: The record to release - * - * Destroy a set of credentials on which no references remain. - */ -void __put_cred(struct cred *cred) -{ - kdebug("__put_cred(%p{%d,%d})", cred, - atomic_read(&cred->usage), - read_cred_subscribers(cred)); - - BUG_ON(atomic_read(&cred->usage) != 0); -#ifdef CONFIG_DEBUG_CREDENTIALS - BUG_ON(read_cred_subscribers(cred) != 0); - cred->magic = CRED_MAGIC_DEAD; - cred->put_addr = __builtin_return_address(0); -#endif - BUG_ON(cred == current->cred); - BUG_ON(cred == current->real_cred); - - call_rcu(&cred->rcu, put_cred_rcu); -} -EXPORT_SYMBOL(__put_cred); - -/* - * Clean up a task's credentials when it exits - */ -void exit_creds(struct task_struct *tsk) -{ - struct cred *cred; - - kdebug("exit_creds(%u,%p,%p,{%d,%d})", tsk->pid, tsk->real_cred, tsk->cred, - atomic_read(&tsk->cred->usage), - read_cred_subscribers(tsk->cred)); - - cred = (struct cred *) tsk->real_cred; - tsk->real_cred = NULL; - validate_creds(cred); - alter_cred_subscribers(cred, -1); - put_cred(cred); - - cred = (struct cred *) tsk->cred; - tsk->cred = NULL; - validate_creds(cred); - alter_cred_subscribers(cred, -1); - put_cred(cred); -} - -/** - * get_task_cred - Get another task's objective credentials - * @task: The task to query - * - * Get the objective credentials of a task, pinning them so that they can't go - * away. Accessing a task's credentials directly is not permitted. - * - * The caller must also make sure task doesn't get deleted, either by holding a - * ref on task or by holding tasklist_lock to prevent it from being unlinked. - */ -const struct cred *get_task_cred(struct task_struct *task) -{ - const struct cred *cred; - - rcu_read_lock(); - - do { - cred = __task_cred((task)); - BUG_ON(!cred); - } while (!atomic_inc_not_zero(&((struct cred *)cred)->usage)); - - rcu_read_unlock(); - return cred; -} - -/* - * Allocate blank credentials, such that the credentials can be filled in at a - * later date without risk of ENOMEM. - */ -struct cred *cred_alloc_blank(void) -{ - struct cred *new; - - new = kmem_cache_zalloc(cred_jar, GFP_KERNEL); - if (!new) - return NULL; - - atomic_set(&new->usage, 1); -#ifdef CONFIG_DEBUG_CREDENTIALS - new->magic = CRED_MAGIC; -#endif - - if (security_cred_alloc_blank(new, GFP_KERNEL) < 0) - goto error; - - return new; - -error: - abort_creds(new); - return NULL; -} - -/** - * prepare_creds - Prepare a new set of credentials for modification - * - * Prepare a new set of task credentials for modification. A task's creds - * shouldn't generally be modified directly, therefore this function is used to - * prepare a new copy, which the caller then modifies and then commits by - * calling commit_creds(). - * - * Preparation involves making a copy of the objective creds for modification. - * - * Returns a pointer to the new creds-to-be if successful, NULL otherwise. - * - * Call commit_creds() or abort_creds() to clean up. - */ -struct cred *prepare_creds(void) -{ - struct task_struct *task = current; - const struct cred *old; - struct cred *new; - - validate_process_creds(); - - new = kmem_cache_alloc(cred_jar, GFP_KERNEL); - if (!new) - return NULL; - - kdebug("prepare_creds() alloc %p", new); - - old = task->cred; - memcpy(new, old, sizeof(struct cred)); - - atomic_set(&new->usage, 1); - set_cred_subscribers(new, 0); - get_group_info(new->group_info); - get_uid(new->user); - get_user_ns(new->user_ns); - -#ifdef CONFIG_KEYS - key_get(new->session_keyring); - key_get(new->process_keyring); - key_get(new->thread_keyring); - key_get(new->request_key_auth); -#endif - -#ifdef CONFIG_SECURITY - new->security = NULL; -#endif - - if (security_prepare_creds(new, old, GFP_KERNEL) < 0) - goto error; - validate_creds(new); - return new; - -error: - abort_creds(new); - return NULL; -} -EXPORT_SYMBOL(prepare_creds); - -/* - * Prepare credentials for current to perform an execve() - * - The caller must hold ->cred_guard_mutex - */ -struct cred *prepare_exec_creds(void) -{ - struct cred *new; - - new = prepare_creds(); - if (!new) - return new; - -#ifdef CONFIG_KEYS - /* newly exec'd tasks don't get a thread keyring */ - key_put(new->thread_keyring); - new->thread_keyring = NULL; - - /* inherit the session keyring; new process keyring */ - key_put(new->process_keyring); - new->process_keyring = NULL; -#endif - - return new; -} - -/* - * Copy credentials for the new process created by fork() - * - * We share if we can, but under some circumstances we have to generate a new - * set. - * - * The new process gets the current process's subjective credentials as its - * objective and subjective credentials - */ -int copy_creds(struct task_struct *p, unsigned long clone_flags) -{ - struct cred *new; - int ret; - - if ( -#ifdef CONFIG_KEYS - !p->cred->thread_keyring && -#endif - clone_flags & CLONE_THREAD - ) { - p->real_cred = get_cred(p->cred); - get_cred(p->cred); - alter_cred_subscribers(p->cred, 2); - kdebug("share_creds(%p{%d,%d})", - p->cred, atomic_read(&p->cred->usage), - read_cred_subscribers(p->cred)); - atomic_inc(&p->cred->user->processes); - return 0; - } - - new = prepare_creds(); - if (!new) - return -ENOMEM; - - if (clone_flags & CLONE_NEWUSER) { - ret = create_user_ns(new); - if (ret < 0) - goto error_put; - } - -#ifdef CONFIG_KEYS - /* new threads get their own thread keyrings if their parent already - * had one */ - if (new->thread_keyring) { - key_put(new->thread_keyring); - new->thread_keyring = NULL; - if (clone_flags & CLONE_THREAD) - install_thread_keyring_to_cred(new); - } - - /* The process keyring is only shared between the threads in a process; - * anything outside of those threads doesn't inherit. - */ - if (!(clone_flags & CLONE_THREAD)) { - key_put(new->process_keyring); - new->process_keyring = NULL; - } -#endif - - atomic_inc(&new->user->processes); - p->cred = p->real_cred = get_cred(new); - alter_cred_subscribers(new, 2); - validate_creds(new); - return 0; - -error_put: - put_cred(new); - return ret; -} - -static bool cred_cap_issubset(const struct cred *set, const struct cred *subset) -{ - const struct user_namespace *set_ns = set->user_ns; - const struct user_namespace *subset_ns = subset->user_ns; - - /* If the two credentials are in the same user namespace see if - * the capabilities of subset are a subset of set. - */ - if (set_ns == subset_ns) - return cap_issubset(subset->cap_permitted, set->cap_permitted); - - /* The credentials are in a different user namespaces - * therefore one is a subset of the other only if a set is an - * ancestor of subset and set->euid is owner of subset or one - * of subsets ancestors. - */ - for (;subset_ns != &init_user_ns; subset_ns = subset_ns->parent) { - if ((set_ns == subset_ns->parent) && - uid_eq(subset_ns->owner, set->euid)) - return true; - } - - return false; -} - -/** - * commit_creds - Install new credentials upon the current task - * @new: The credentials to be assigned - * - * Install a new set of credentials to the current task, using RCU to replace - * the old set. Both the objective and the subjective credentials pointers are - * updated. This function may not be called if the subjective credentials are - * in an overridden state. - * - * This function eats the caller's reference to the new credentials. - * - * Always returns 0 thus allowing this function to be tail-called at the end - * of, say, sys_setgid(). - */ -int commit_creds(struct cred *new) -{ - struct task_struct *task = current; - const struct cred *old = task->real_cred; - - kdebug("commit_creds(%p{%d,%d})", new, - atomic_read(&new->usage), - read_cred_subscribers(new)); - - BUG_ON(task->cred != old); -#ifdef CONFIG_DEBUG_CREDENTIALS - BUG_ON(read_cred_subscribers(old) < 2); - validate_creds(old); - validate_creds(new); -#endif - BUG_ON(atomic_read(&new->usage) < 1); - - get_cred(new); /* we will require a ref for the subj creds too */ - - /* dumpability changes */ - if (!uid_eq(old->euid, new->euid) || - !gid_eq(old->egid, new->egid) || - !uid_eq(old->fsuid, new->fsuid) || - !gid_eq(old->fsgid, new->fsgid) || - !cred_cap_issubset(old, new)) { - if (task->mm) - set_dumpable(task->mm, suid_dumpable); - task->pdeath_signal = 0; - smp_wmb(); - } - - /* alter the thread keyring */ - if (!uid_eq(new->fsuid, old->fsuid)) - key_fsuid_changed(task); - if (!gid_eq(new->fsgid, old->fsgid)) - key_fsgid_changed(task); - - /* do it - * RLIMIT_NPROC limits on user->processes have already been checked - * in set_user(). - */ - alter_cred_subscribers(new, 2); - if (new->user != old->user) - atomic_inc(&new->user->processes); - rcu_assign_pointer(task->real_cred, new); - rcu_assign_pointer(task->cred, new); - if (new->user != old->user) - atomic_dec(&old->user->processes); - alter_cred_subscribers(old, -2); - - /* send notifications */ - if (!uid_eq(new->uid, old->uid) || - !uid_eq(new->euid, old->euid) || - !uid_eq(new->suid, old->suid) || - !uid_eq(new->fsuid, old->fsuid)) - proc_id_connector(task, PROC_EVENT_UID); - - if (!gid_eq(new->gid, old->gid) || - !gid_eq(new->egid, old->egid) || - !gid_eq(new->sgid, old->sgid) || - !gid_eq(new->fsgid, old->fsgid)) - proc_id_connector(task, PROC_EVENT_GID); - - /* release the old obj and subj refs both */ - put_cred(old); - put_cred(old); - return 0; -} -EXPORT_SYMBOL(commit_creds); - -/** - * abort_creds - Discard a set of credentials and unlock the current task - * @new: The credentials that were going to be applied - * - * Discard a set of credentials that were under construction and unlock the - * current task. - */ -void abort_creds(struct cred *new) -{ - kdebug("abort_creds(%p{%d,%d})", new, - atomic_read(&new->usage), - read_cred_subscribers(new)); - -#ifdef CONFIG_DEBUG_CREDENTIALS - BUG_ON(read_cred_subscribers(new) != 0); -#endif - BUG_ON(atomic_read(&new->usage) < 1); - put_cred(new); -} -EXPORT_SYMBOL(abort_creds); - -/** - * override_creds - Override the current process's subjective credentials - * @new: The credentials to be assigned - * - * Install a set of temporary override subjective credentials on the current - * process, returning the old set for later reversion. - */ -const struct cred *override_creds(const struct cred *new) -{ - const struct cred *old = current->cred; - - kdebug("override_creds(%p{%d,%d})", new, - atomic_read(&new->usage), - read_cred_subscribers(new)); - - validate_creds(old); - validate_creds(new); - get_cred(new); - alter_cred_subscribers(new, 1); - rcu_assign_pointer(current->cred, new); - alter_cred_subscribers(old, -1); - - kdebug("override_creds() = %p{%d,%d}", old, - atomic_read(&old->usage), - read_cred_subscribers(old)); - return old; -} -EXPORT_SYMBOL(override_creds); - -/** - * revert_creds - Revert a temporary subjective credentials override - * @old: The credentials to be restored - * - * Revert a temporary set of override subjective credentials to an old set, - * discarding the override set. - */ -void revert_creds(const struct cred *old) -{ - const struct cred *override = current->cred; - - kdebug("revert_creds(%p{%d,%d})", old, - atomic_read(&old->usage), - read_cred_subscribers(old)); - - validate_creds(old); - validate_creds(override); - alter_cred_subscribers(old, 1); - rcu_assign_pointer(current->cred, old); - alter_cred_subscribers(override, -1); - put_cred(override); -} -EXPORT_SYMBOL(revert_creds); - -/* - * initialise the credentials stuff - */ -void __init cred_init(void) -{ - /* allocate a slab in which we can store credentials */ - cred_jar = kmem_cache_create("cred_jar", sizeof(struct cred), 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_ACCOUNT, NULL); -} - -/** - * prepare_kernel_cred - Prepare a set of credentials for a kernel service - * @daemon: A userspace daemon to be used as a reference - * - * Prepare a set of credentials for a kernel service. This can then be used to - * override a task's own credentials so that work can be done on behalf of that - * task that requires a different subjective context. - * - * @daemon is used to provide a base for the security record, but can be NULL. - * If @daemon is supplied, then the security data will be derived from that; - * otherwise they'll be set to 0 and no groups, full capabilities and no keys. - * - * The caller may change these controls afterwards if desired. - * - * Returns the new credentials or NULL if out of memory. - * - * Does not take, and does not return holding current->cred_replace_mutex. - */ -struct cred *prepare_kernel_cred(struct task_struct *daemon) -{ - const struct cred *old; - struct cred *new; - - new = kmem_cache_alloc(cred_jar, GFP_KERNEL); - if (!new) - return NULL; - - kdebug("prepare_kernel_cred() alloc %p", new); - - if (daemon) - old = get_task_cred(daemon); - else - old = get_cred(&init_cred); - - validate_creds(old); - - *new = *old; - atomic_set(&new->usage, 1); - set_cred_subscribers(new, 0); - get_uid(new->user); - get_user_ns(new->user_ns); - get_group_info(new->group_info); - -#ifdef CONFIG_KEYS - new->session_keyring = NULL; - new->process_keyring = NULL; - new->thread_keyring = NULL; - new->request_key_auth = NULL; - new->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING; -#endif - -#ifdef CONFIG_SECURITY - new->security = NULL; -#endif - if (security_prepare_creds(new, old, GFP_KERNEL) < 0) - goto error; - - put_cred(old); - validate_creds(new); - return new; - -error: - put_cred(new); - put_cred(old); - return NULL; -} -EXPORT_SYMBOL(prepare_kernel_cred); - -/** - * set_security_override - Set the security ID in a set of credentials - * @new: The credentials to alter - * @secid: The LSM security ID to set - * - * Set the LSM security ID in a set of credentials so that the subjective - * security is overridden when an alternative set of credentials is used. - */ -int set_security_override(struct cred *new, u32 secid) -{ - return security_kernel_act_as(new, secid); -} -EXPORT_SYMBOL(set_security_override); - -/** - * set_security_override_from_ctx - Set the security ID in a set of credentials - * @new: The credentials to alter - * @secctx: The LSM security context to generate the security ID from. - * - * Set the LSM security ID in a set of credentials so that the subjective - * security is overridden when an alternative set of credentials is used. The - * security ID is specified in string form as a security context to be - * interpreted by the LSM. - */ -int set_security_override_from_ctx(struct cred *new, const char *secctx) -{ - u32 secid; - int ret; - - ret = security_secctx_to_secid(secctx, strlen(secctx), &secid); - if (ret < 0) - return ret; - - return set_security_override(new, secid); -} -EXPORT_SYMBOL(set_security_override_from_ctx); - -/** - * set_create_files_as - Set the LSM file create context in a set of credentials - * @new: The credentials to alter - * @inode: The inode to take the context from - * - * Change the LSM file creation context in a set of credentials to be the same - * as the object context of the specified inode, so that the new inodes have - * the same MAC context as that inode. - */ -int set_create_files_as(struct cred *new, struct inode *inode) -{ - if (!uid_valid(inode->i_uid) || !gid_valid(inode->i_gid)) - return -EINVAL; - new->fsuid = inode->i_uid; - new->fsgid = inode->i_gid; - return security_kernel_create_files_as(new, inode); -} -EXPORT_SYMBOL(set_create_files_as); - -#ifdef CONFIG_DEBUG_CREDENTIALS - -bool creds_are_invalid(const struct cred *cred) -{ - if (cred->magic != CRED_MAGIC) - return true; -#ifdef CONFIG_SECURITY_SELINUX - /* - * cred->security == NULL if security_cred_alloc_blank() or - * security_prepare_creds() returned an error. - */ - if (selinux_is_enabled() && cred->security) { - if ((unsigned long) cred->security < PAGE_SIZE) - return true; - if ((*(u32 *)cred->security & 0xffffff00) == - (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8)) - return true; - } -#endif - return false; -} -EXPORT_SYMBOL(creds_are_invalid); - -/* - * dump invalid credentials - */ -static void dump_invalid_creds(const struct cred *cred, const char *label, - const struct task_struct *tsk) -{ - printk(KERN_ERR "CRED: %s credentials: %p %s%s%s\n", - label, cred, - cred == &init_cred ? "[init]" : "", - cred == tsk->real_cred ? "[real]" : "", - cred == tsk->cred ? "[eff]" : ""); - printk(KERN_ERR "CRED: ->magic=%x, put_addr=%p\n", - cred->magic, cred->put_addr); - printk(KERN_ERR "CRED: ->usage=%d, subscr=%d\n", - atomic_read(&cred->usage), - read_cred_subscribers(cred)); - printk(KERN_ERR "CRED: ->*uid = { %d,%d,%d,%d }\n", - from_kuid_munged(&init_user_ns, cred->uid), - from_kuid_munged(&init_user_ns, cred->euid), - from_kuid_munged(&init_user_ns, cred->suid), - from_kuid_munged(&init_user_ns, cred->fsuid)); - printk(KERN_ERR "CRED: ->*gid = { %d,%d,%d,%d }\n", - from_kgid_munged(&init_user_ns, cred->gid), - from_kgid_munged(&init_user_ns, cred->egid), - from_kgid_munged(&init_user_ns, cred->sgid), - from_kgid_munged(&init_user_ns, cred->fsgid)); -#ifdef CONFIG_SECURITY - printk(KERN_ERR "CRED: ->security is %p\n", cred->security); - if ((unsigned long) cred->security >= PAGE_SIZE && - (((unsigned long) cred->security & 0xffffff00) != - (POISON_FREE << 24 | POISON_FREE << 16 | POISON_FREE << 8))) - printk(KERN_ERR "CRED: ->security {%x, %x}\n", - ((u32*)cred->security)[0], - ((u32*)cred->security)[1]); -#endif -} - -/* - * report use of invalid credentials - */ -void __invalid_creds(const struct cred *cred, const char *file, unsigned line) -{ - printk(KERN_ERR "CRED: Invalid credentials\n"); - printk(KERN_ERR "CRED: At %s:%u\n", file, line); - dump_invalid_creds(cred, "Specified", current); - BUG(); -} -EXPORT_SYMBOL(__invalid_creds); - -/* - * check the credentials on a process - */ -void __validate_process_creds(struct task_struct *tsk, - const char *file, unsigned line) -{ - if (tsk->cred == tsk->real_cred) { - if (unlikely(read_cred_subscribers(tsk->cred) < 2 || - creds_are_invalid(tsk->cred))) - goto invalid_creds; - } else { - if (unlikely(read_cred_subscribers(tsk->real_cred) < 1 || - read_cred_subscribers(tsk->cred) < 1 || - creds_are_invalid(tsk->real_cred) || - creds_are_invalid(tsk->cred))) - goto invalid_creds; - } - return; - -invalid_creds: - printk(KERN_ERR "CRED: Invalid process credentials\n"); - printk(KERN_ERR "CRED: At %s:%u\n", file, line); - - dump_invalid_creds(tsk->real_cred, "Real", tsk); - if (tsk->cred != tsk->real_cred) - dump_invalid_creds(tsk->cred, "Effective", tsk); - else - printk(KERN_ERR "CRED: Effective creds == Real creds\n"); - BUG(); -} -EXPORT_SYMBOL(__validate_process_creds); - -/* - * check creds for do_exit() - */ -void validate_creds_for_do_exit(struct task_struct *tsk) -{ - kdebug("validate_creds_for_do_exit(%p,%p{%d,%d})", - tsk->real_cred, tsk->cred, - atomic_read(&tsk->cred->usage), - read_cred_subscribers(tsk->cred)); - - __validate_process_creds(tsk, __FILE__, __LINE__); -} - -#endif /* CONFIG_DEBUG_CREDENTIALS */ diff --git a/src/linux/kernel/debug/kdb/.gitignore b/src/linux/kernel/debug/kdb/.gitignore deleted file mode 100644 index 396d12e..0000000 --- a/src/linux/kernel/debug/kdb/.gitignore +++ /dev/null @@ -1 +0,0 @@ -gen-kdb_cmds.c diff --git a/src/linux/kernel/exec_domain.c b/src/linux/kernel/exec_domain.c deleted file mode 100644 index 6873bb3..0000000 --- a/src/linux/kernel/exec_domain.c +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Handling of different ABIs (personalities). - * - * We group personalities into execution domains which have their - * own handlers for kernel entry points, signal mapping, etc... - * - * 2001-05-06 Complete rewrite, Christoph Hellwig (hch@infradead.org) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_PROC_FS -static int execdomains_proc_show(struct seq_file *m, void *v) -{ - seq_puts(m, "0-0\tLinux \t[kernel]\n"); - return 0; -} - -static int execdomains_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, execdomains_proc_show, NULL); -} - -static const struct file_operations execdomains_proc_fops = { - .open = execdomains_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static int __init proc_execdomains_init(void) -{ - proc_create("execdomains", 0, NULL, &execdomains_proc_fops); - return 0; -} -module_init(proc_execdomains_init); -#endif - -SYSCALL_DEFINE1(personality, unsigned int, personality) -{ - unsigned int old = current->personality; - - if (personality != 0xffffffff) - set_personality(personality); - - return old; -} diff --git a/src/linux/kernel/exit.c b/src/linux/kernel/exit.c deleted file mode 100644 index 3076f30..0000000 --- a/src/linux/kernel/exit.c +++ /dev/null @@ -1,1701 +0,0 @@ -/* - * linux/kernel/exit.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for audit_free() */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -static void __unhash_process(struct task_struct *p, bool group_dead) -{ - nr_threads--; - detach_pid(p, PIDTYPE_PID); - if (group_dead) { - detach_pid(p, PIDTYPE_PGID); - detach_pid(p, PIDTYPE_SID); - - list_del_rcu(&p->tasks); - list_del_init(&p->sibling); - __this_cpu_dec(process_counts); - } - list_del_rcu(&p->thread_group); - list_del_rcu(&p->thread_node); -} - -/* - * This function expects the tasklist_lock write-locked. - */ -static void __exit_signal(struct task_struct *tsk) -{ - struct signal_struct *sig = tsk->signal; - bool group_dead = thread_group_leader(tsk); - struct sighand_struct *sighand; - struct tty_struct *uninitialized_var(tty); - cputime_t utime, stime; - - sighand = rcu_dereference_check(tsk->sighand, - lockdep_tasklist_lock_is_held()); - spin_lock(&sighand->siglock); - - posix_cpu_timers_exit(tsk); - if (group_dead) { - posix_cpu_timers_exit_group(tsk); - tty = sig->tty; - sig->tty = NULL; - } else { - /* - * This can only happen if the caller is de_thread(). - * FIXME: this is the temporary hack, we should teach - * posix-cpu-timers to handle this case correctly. - */ - if (unlikely(has_group_leader_pid(tsk))) - posix_cpu_timers_exit_group(tsk); - - /* - * If there is any task waiting for the group exit - * then notify it: - */ - if (sig->notify_count > 0 && !--sig->notify_count) - wake_up_process(sig->group_exit_task); - - if (tsk == sig->curr_target) - sig->curr_target = next_thread(tsk); - } - - /* - * Accumulate here the counters for all threads as they die. We could - * skip the group leader because it is the last user of signal_struct, - * but we want to avoid the race with thread_group_cputime() which can - * see the empty ->thread_head list. - */ - task_cputime(tsk, &utime, &stime); - write_seqlock(&sig->stats_lock); - sig->utime += utime; - sig->stime += stime; - sig->gtime += task_gtime(tsk); - sig->min_flt += tsk->min_flt; - sig->maj_flt += tsk->maj_flt; - sig->nvcsw += tsk->nvcsw; - sig->nivcsw += tsk->nivcsw; - sig->inblock += task_io_get_inblock(tsk); - sig->oublock += task_io_get_oublock(tsk); - task_io_accounting_add(&sig->ioac, &tsk->ioac); - sig->sum_sched_runtime += tsk->se.sum_exec_runtime; - sig->nr_threads--; - __unhash_process(tsk, group_dead); - write_sequnlock(&sig->stats_lock); - - /* - * Do this under ->siglock, we can race with another thread - * doing sigqueue_free() if we have SIGQUEUE_PREALLOC signals. - */ - flush_sigqueue(&tsk->pending); - tsk->sighand = NULL; - spin_unlock(&sighand->siglock); - - __cleanup_sighand(sighand); - clear_tsk_thread_flag(tsk, TIF_SIGPENDING); - if (group_dead) { - flush_sigqueue(&sig->shared_pending); - tty_kref_put(tty); - } -} - -static void delayed_put_task_struct(struct rcu_head *rhp) -{ - struct task_struct *tsk = container_of(rhp, struct task_struct, rcu); - - perf_event_delayed_put(tsk); - trace_sched_process_free(tsk); - put_task_struct(tsk); -} - - -void release_task(struct task_struct *p) -{ - struct task_struct *leader; - int zap_leader; -repeat: - /* don't need to get the RCU readlock here - the process is dead and - * can't be modifying its own credentials. But shut RCU-lockdep up */ - rcu_read_lock(); - atomic_dec(&__task_cred(p)->user->processes); - rcu_read_unlock(); - - proc_flush_task(p); - - write_lock_irq(&tasklist_lock); - ptrace_release_task(p); - __exit_signal(p); - - /* - * If we are the last non-leader member of the thread - * group, and the leader is zombie, then notify the - * group leader's parent process. (if it wants notification.) - */ - zap_leader = 0; - leader = p->group_leader; - if (leader != p && thread_group_empty(leader) - && leader->exit_state == EXIT_ZOMBIE) { - /* - * If we were the last child thread and the leader has - * exited already, and the leader's parent ignores SIGCHLD, - * then we are the one who should release the leader. - */ - zap_leader = do_notify_parent(leader, leader->exit_signal); - if (zap_leader) - leader->exit_state = EXIT_DEAD; - } - - write_unlock_irq(&tasklist_lock); - release_thread(p); - call_rcu(&p->rcu, delayed_put_task_struct); - - p = leader; - if (unlikely(zap_leader)) - goto repeat; -} - -/* - * Note that if this function returns a valid task_struct pointer (!NULL) - * task->usage must remain >0 for the duration of the RCU critical section. - */ -struct task_struct *task_rcu_dereference(struct task_struct **ptask) -{ - struct sighand_struct *sighand; - struct task_struct *task; - - /* - * We need to verify that release_task() was not called and thus - * delayed_put_task_struct() can't run and drop the last reference - * before rcu_read_unlock(). We check task->sighand != NULL, - * but we can read the already freed and reused memory. - */ -retry: - task = rcu_dereference(*ptask); - if (!task) - return NULL; - - probe_kernel_address(&task->sighand, sighand); - - /* - * Pairs with atomic_dec_and_test() in put_task_struct(). If this task - * was already freed we can not miss the preceding update of this - * pointer. - */ - smp_rmb(); - if (unlikely(task != READ_ONCE(*ptask))) - goto retry; - - /* - * We've re-checked that "task == *ptask", now we have two different - * cases: - * - * 1. This is actually the same task/task_struct. In this case - * sighand != NULL tells us it is still alive. - * - * 2. This is another task which got the same memory for task_struct. - * We can't know this of course, and we can not trust - * sighand != NULL. - * - * In this case we actually return a random value, but this is - * correct. - * - * If we return NULL - we can pretend that we actually noticed that - * *ptask was updated when the previous task has exited. Or pretend - * that probe_slab_address(&sighand) reads NULL. - * - * If we return the new task (because sighand is not NULL for any - * reason) - this is fine too. This (new) task can't go away before - * another gp pass. - * - * And note: We could even eliminate the false positive if re-read - * task->sighand once again to avoid the falsely NULL. But this case - * is very unlikely so we don't care. - */ - if (!sighand) - return NULL; - - return task; -} - -struct task_struct *try_get_task_struct(struct task_struct **ptask) -{ - struct task_struct *task; - - rcu_read_lock(); - task = task_rcu_dereference(ptask); - if (task) - get_task_struct(task); - rcu_read_unlock(); - - return task; -} - -/* - * Determine if a process group is "orphaned", according to the POSIX - * definition in 2.2.2.52. Orphaned process groups are not to be affected - * by terminal-generated stop signals. Newly orphaned process groups are - * to receive a SIGHUP and a SIGCONT. - * - * "I ask you, have you ever known what it is to be an orphan?" - */ -static int will_become_orphaned_pgrp(struct pid *pgrp, - struct task_struct *ignored_task) -{ - struct task_struct *p; - - do_each_pid_task(pgrp, PIDTYPE_PGID, p) { - if ((p == ignored_task) || - (p->exit_state && thread_group_empty(p)) || - is_global_init(p->real_parent)) - continue; - - if (task_pgrp(p->real_parent) != pgrp && - task_session(p->real_parent) == task_session(p)) - return 0; - } while_each_pid_task(pgrp, PIDTYPE_PGID, p); - - return 1; -} - -int is_current_pgrp_orphaned(void) -{ - int retval; - - read_lock(&tasklist_lock); - retval = will_become_orphaned_pgrp(task_pgrp(current), NULL); - read_unlock(&tasklist_lock); - - return retval; -} - -static bool has_stopped_jobs(struct pid *pgrp) -{ - struct task_struct *p; - - do_each_pid_task(pgrp, PIDTYPE_PGID, p) { - if (p->signal->flags & SIGNAL_STOP_STOPPED) - return true; - } while_each_pid_task(pgrp, PIDTYPE_PGID, p); - - return false; -} - -/* - * Check to see if any process groups have become orphaned as - * a result of our exiting, and if they have any stopped jobs, - * send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) - */ -static void -kill_orphaned_pgrp(struct task_struct *tsk, struct task_struct *parent) -{ - struct pid *pgrp = task_pgrp(tsk); - struct task_struct *ignored_task = tsk; - - if (!parent) - /* exit: our father is in a different pgrp than - * we are and we were the only connection outside. - */ - parent = tsk->real_parent; - else - /* reparent: our child is in a different pgrp than - * we are, and it was the only connection outside. - */ - ignored_task = NULL; - - if (task_pgrp(parent) != pgrp && - task_session(parent) == task_session(tsk) && - will_become_orphaned_pgrp(pgrp, ignored_task) && - has_stopped_jobs(pgrp)) { - __kill_pgrp_info(SIGHUP, SEND_SIG_PRIV, pgrp); - __kill_pgrp_info(SIGCONT, SEND_SIG_PRIV, pgrp); - } -} - -#ifdef CONFIG_MEMCG -/* - * A task is exiting. If it owned this mm, find a new owner for the mm. - */ -void mm_update_next_owner(struct mm_struct *mm) -{ - struct task_struct *c, *g, *p = current; - -retry: - /* - * If the exiting or execing task is not the owner, it's - * someone else's problem. - */ - if (mm->owner != p) - return; - /* - * The current owner is exiting/execing and there are no other - * candidates. Do not leave the mm pointing to a possibly - * freed task structure. - */ - if (atomic_read(&mm->mm_users) <= 1) { - mm->owner = NULL; - return; - } - - read_lock(&tasklist_lock); - /* - * Search in the children - */ - list_for_each_entry(c, &p->children, sibling) { - if (c->mm == mm) - goto assign_new_owner; - } - - /* - * Search in the siblings - */ - list_for_each_entry(c, &p->real_parent->children, sibling) { - if (c->mm == mm) - goto assign_new_owner; - } - - /* - * Search through everything else, we should not get here often. - */ - for_each_process(g) { - if (g->flags & PF_KTHREAD) - continue; - for_each_thread(g, c) { - if (c->mm == mm) - goto assign_new_owner; - if (c->mm) - break; - } - } - read_unlock(&tasklist_lock); - /* - * We found no owner yet mm_users > 1: this implies that we are - * most likely racing with swapoff (try_to_unuse()) or /proc or - * ptrace or page migration (get_task_mm()). Mark owner as NULL. - */ - mm->owner = NULL; - return; - -assign_new_owner: - BUG_ON(c == p); - get_task_struct(c); - /* - * The task_lock protects c->mm from changing. - * We always want mm->owner->mm == mm - */ - task_lock(c); - /* - * Delay read_unlock() till we have the task_lock() - * to ensure that c does not slip away underneath us - */ - read_unlock(&tasklist_lock); - if (c->mm != mm) { - task_unlock(c); - put_task_struct(c); - goto retry; - } - mm->owner = c; - task_unlock(c); - put_task_struct(c); -} -#endif /* CONFIG_MEMCG */ - -/* - * Turn us into a lazy TLB process if we - * aren't already.. - */ -static void exit_mm(struct task_struct *tsk) -{ - struct mm_struct *mm = tsk->mm; - struct core_state *core_state; - - mm_release(tsk, mm); - if (!mm) - return; - sync_mm_rss(mm); - /* - * Serialize with any possible pending coredump. - * We must hold mmap_sem around checking core_state - * and clearing tsk->mm. The core-inducing thread - * will increment ->nr_threads for each thread in the - * group with ->mm != NULL. - */ - down_read(&mm->mmap_sem); - core_state = mm->core_state; - if (core_state) { - struct core_thread self; - - up_read(&mm->mmap_sem); - - self.task = tsk; - self.next = xchg(&core_state->dumper.next, &self); - /* - * Implies mb(), the result of xchg() must be visible - * to core_state->dumper. - */ - if (atomic_dec_and_test(&core_state->nr_threads)) - complete(&core_state->startup); - - for (;;) { - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (!self.task) /* see coredump_finish() */ - break; - freezable_schedule(); - } - __set_task_state(tsk, TASK_RUNNING); - down_read(&mm->mmap_sem); - } - atomic_inc(&mm->mm_count); - BUG_ON(mm != tsk->active_mm); - /* more a memory barrier than a real lock */ - task_lock(tsk); - tsk->mm = NULL; - up_read(&mm->mmap_sem); - enter_lazy_tlb(mm, current); - task_unlock(tsk); - mm_update_next_owner(mm); - mmput(mm); - if (test_thread_flag(TIF_MEMDIE)) - exit_oom_victim(); -} - -static struct task_struct *find_alive_thread(struct task_struct *p) -{ - struct task_struct *t; - - for_each_thread(p, t) { - if (!(t->flags & PF_EXITING)) - return t; - } - return NULL; -} - -static struct task_struct *find_child_reaper(struct task_struct *father) - __releases(&tasklist_lock) - __acquires(&tasklist_lock) -{ - struct pid_namespace *pid_ns = task_active_pid_ns(father); - struct task_struct *reaper = pid_ns->child_reaper; - - if (likely(reaper != father)) - return reaper; - - reaper = find_alive_thread(father); - if (reaper) { - pid_ns->child_reaper = reaper; - return reaper; - } - - write_unlock_irq(&tasklist_lock); - if (unlikely(pid_ns == &init_pid_ns)) { - panic("Attempted to kill init! exitcode=0x%08x\n", - father->signal->group_exit_code ?: father->exit_code); - } - zap_pid_ns_processes(pid_ns); - write_lock_irq(&tasklist_lock); - - return father; -} - -/* - * When we die, we re-parent all our children, and try to: - * 1. give them to another thread in our thread group, if such a member exists - * 2. give it to the first ancestor process which prctl'd itself as a - * child_subreaper for its children (like a service manager) - * 3. give it to the init process (PID 1) in our pid namespace - */ -static struct task_struct *find_new_reaper(struct task_struct *father, - struct task_struct *child_reaper) -{ - struct task_struct *thread, *reaper; - - thread = find_alive_thread(father); - if (thread) - return thread; - - if (father->signal->has_child_subreaper) { - /* - * Find the first ->is_child_subreaper ancestor in our pid_ns. - * We start from father to ensure we can not look into another - * namespace, this is safe because all its threads are dead. - */ - for (reaper = father; - !same_thread_group(reaper, child_reaper); - reaper = reaper->real_parent) { - /* call_usermodehelper() descendants need this check */ - if (reaper == &init_task) - break; - if (!reaper->signal->is_child_subreaper) - continue; - thread = find_alive_thread(reaper); - if (thread) - return thread; - } - } - - return child_reaper; -} - -/* -* Any that need to be release_task'd are put on the @dead list. - */ -static void reparent_leader(struct task_struct *father, struct task_struct *p, - struct list_head *dead) -{ - if (unlikely(p->exit_state == EXIT_DEAD)) - return; - - /* We don't want people slaying init. */ - p->exit_signal = SIGCHLD; - - /* If it has exited notify the new parent about this child's death. */ - if (!p->ptrace && - p->exit_state == EXIT_ZOMBIE && thread_group_empty(p)) { - if (do_notify_parent(p, p->exit_signal)) { - p->exit_state = EXIT_DEAD; - list_add(&p->ptrace_entry, dead); - } - } - - kill_orphaned_pgrp(p, father); -} - -/* - * This does two things: - * - * A. Make init inherit all the child processes - * B. Check to see if any process groups have become orphaned - * as a result of our exiting, and if they have any stopped - * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) - */ -static void forget_original_parent(struct task_struct *father, - struct list_head *dead) -{ - struct task_struct *p, *t, *reaper; - - if (unlikely(!list_empty(&father->ptraced))) - exit_ptrace(father, dead); - - /* Can drop and reacquire tasklist_lock */ - reaper = find_child_reaper(father); - if (list_empty(&father->children)) - return; - - reaper = find_new_reaper(father, reaper); - list_for_each_entry(p, &father->children, sibling) { - for_each_thread(p, t) { - t->real_parent = reaper; - BUG_ON((!t->ptrace) != (t->parent == father)); - if (likely(!t->ptrace)) - t->parent = t->real_parent; - if (t->pdeath_signal) - group_send_sig_info(t->pdeath_signal, - SEND_SIG_NOINFO, t); - } - /* - * If this is a threaded reparent there is no need to - * notify anyone anything has happened. - */ - if (!same_thread_group(reaper, father)) - reparent_leader(father, p, dead); - } - list_splice_tail_init(&father->children, &reaper->children); -} - -/* - * Send signals to all our closest relatives so that they know - * to properly mourn us.. - */ -static void exit_notify(struct task_struct *tsk, int group_dead) -{ - bool autoreap; - struct task_struct *p, *n; - LIST_HEAD(dead); - - write_lock_irq(&tasklist_lock); - forget_original_parent(tsk, &dead); - - if (group_dead) - kill_orphaned_pgrp(tsk->group_leader, NULL); - - if (unlikely(tsk->ptrace)) { - int sig = thread_group_leader(tsk) && - thread_group_empty(tsk) && - !ptrace_reparented(tsk) ? - tsk->exit_signal : SIGCHLD; - autoreap = do_notify_parent(tsk, sig); - } else if (thread_group_leader(tsk)) { - autoreap = thread_group_empty(tsk) && - do_notify_parent(tsk, tsk->exit_signal); - } else { - autoreap = true; - } - - tsk->exit_state = autoreap ? EXIT_DEAD : EXIT_ZOMBIE; - if (tsk->exit_state == EXIT_DEAD) - list_add(&tsk->ptrace_entry, &dead); - - /* mt-exec, de_thread() is waiting for group leader */ - if (unlikely(tsk->signal->notify_count < 0)) - wake_up_process(tsk->signal->group_exit_task); - write_unlock_irq(&tasklist_lock); - - list_for_each_entry_safe(p, n, &dead, ptrace_entry) { - list_del_init(&p->ptrace_entry); - release_task(p); - } -} - -#ifdef CONFIG_DEBUG_STACK_USAGE -static void check_stack_usage(void) -{ - static DEFINE_SPINLOCK(low_water_lock); - static int lowest_to_date = THREAD_SIZE; - unsigned long free; - - free = stack_not_used(current); - - if (free >= lowest_to_date) - return; - - spin_lock(&low_water_lock); - if (free < lowest_to_date) { - pr_info("%s (%d) used greatest stack depth: %lu bytes left\n", - current->comm, task_pid_nr(current), free); - lowest_to_date = free; - } - spin_unlock(&low_water_lock); -} -#else -static inline void check_stack_usage(void) {} -#endif - -void __noreturn do_exit(long code) -{ - struct task_struct *tsk = current; - int group_dead; - TASKS_RCU(int tasks_rcu_i); - - profile_task_exit(tsk); - kcov_task_exit(tsk); - - WARN_ON(blk_needs_flush_plug(tsk)); - - if (unlikely(in_interrupt())) - panic("Aiee, killing interrupt handler!"); - if (unlikely(!tsk->pid)) - panic("Attempted to kill the idle task!"); - - /* - * If do_exit is called because this processes oopsed, it's possible - * that get_fs() was left as KERNEL_DS, so reset it to USER_DS before - * continuing. Amongst other possible reasons, this is to prevent - * mm_release()->clear_child_tid() from writing to a user-controlled - * kernel address. - */ - set_fs(USER_DS); - - ptrace_event(PTRACE_EVENT_EXIT, code); - - validate_creds_for_do_exit(tsk); - - /* - * We're taking recursive faults here in do_exit. Safest is to just - * leave this task alone and wait for reboot. - */ - if (unlikely(tsk->flags & PF_EXITING)) { - pr_alert("Fixing recursive fault but reboot is needed!\n"); - /* - * We can do this unlocked here. The futex code uses - * this flag just to verify whether the pi state - * cleanup has been done or not. In the worst case it - * loops once more. We pretend that the cleanup was - * done as there is no way to return. Either the - * OWNER_DIED bit is set by now or we push the blocked - * task into the wait for ever nirwana as well. - */ - tsk->flags |= PF_EXITPIDONE; - set_current_state(TASK_UNINTERRUPTIBLE); - schedule(); - } - - exit_signals(tsk); /* sets PF_EXITING */ - /* - * Ensure that all new tsk->pi_lock acquisitions must observe - * PF_EXITING. Serializes against futex.c:attach_to_pi_owner(). - */ - smp_mb(); - /* - * Ensure that we must observe the pi_state in exit_mm() -> - * mm_release() -> exit_pi_state_list(). - */ - raw_spin_unlock_wait(&tsk->pi_lock); - - if (unlikely(in_atomic())) { - pr_info("note: %s[%d] exited with preempt_count %d\n", - current->comm, task_pid_nr(current), - preempt_count()); - preempt_count_set(PREEMPT_ENABLED); - } - - /* sync mm's RSS info before statistics gathering */ - if (tsk->mm) - sync_mm_rss(tsk->mm); - acct_update_integrals(tsk); - group_dead = atomic_dec_and_test(&tsk->signal->live); - if (group_dead) { - hrtimer_cancel(&tsk->signal->real_timer); - exit_itimers(tsk->signal); - if (tsk->mm) - setmax_mm_hiwater_rss(&tsk->signal->maxrss, tsk->mm); - } - acct_collect(code, group_dead); - if (group_dead) - tty_audit_exit(); - audit_free(tsk); - - tsk->exit_code = code; - taskstats_exit(tsk, group_dead); - - exit_mm(tsk); - - if (group_dead) - acct_process(); - trace_sched_process_exit(tsk); - - exit_sem(tsk); - exit_shm(tsk); - exit_files(tsk); - exit_fs(tsk); - if (group_dead) - disassociate_ctty(1); - exit_task_namespaces(tsk); - exit_task_work(tsk); - exit_thread(tsk); - - /* - * Flush inherited counters to the parent - before the parent - * gets woken up by child-exit notifications. - * - * because of cgroup mode, must be called before cgroup_exit() - */ - perf_event_exit_task(tsk); - - sched_autogroup_exit_task(tsk); - cgroup_exit(tsk); - - /* - * FIXME: do that only when needed, using sched_exit tracepoint - */ - flush_ptrace_hw_breakpoint(tsk); - - TASKS_RCU(preempt_disable()); - TASKS_RCU(tasks_rcu_i = __srcu_read_lock(&tasks_rcu_exit_srcu)); - TASKS_RCU(preempt_enable()); - exit_notify(tsk, group_dead); - proc_exit_connector(tsk); - mpol_put_task_policy(tsk); -#ifdef CONFIG_FUTEX - if (unlikely(current->pi_state_cache)) - kfree(current->pi_state_cache); -#endif - /* - * Make sure we are holding no locks: - */ - debug_check_no_locks_held(); - /* - * We can do this unlocked here. The futex code uses this flag - * just to verify whether the pi state cleanup has been done - * or not. In the worst case it loops once more. - */ - tsk->flags |= PF_EXITPIDONE; - - if (tsk->io_context) - exit_io_context(tsk); - - if (tsk->splice_pipe) - free_pipe_info(tsk->splice_pipe); - - if (tsk->task_frag.page) - put_page(tsk->task_frag.page); - - validate_creds_for_do_exit(tsk); - - check_stack_usage(); - preempt_disable(); - if (tsk->nr_dirtied) - __this_cpu_add(dirty_throttle_leaks, tsk->nr_dirtied); - exit_rcu(); - TASKS_RCU(__srcu_read_unlock(&tasks_rcu_exit_srcu, tasks_rcu_i)); - - do_task_dead(); -} -EXPORT_SYMBOL_GPL(do_exit); - -void complete_and_exit(struct completion *comp, long code) -{ - if (comp) - complete(comp); - - do_exit(code); -} -EXPORT_SYMBOL(complete_and_exit); - -SYSCALL_DEFINE1(exit, int, error_code) -{ - do_exit((error_code&0xff)<<8); -} - -/* - * Take down every thread in the group. This is called by fatal signals - * as well as by sys_exit_group (below). - */ -void -do_group_exit(int exit_code) -{ - struct signal_struct *sig = current->signal; - - BUG_ON(exit_code & 0x80); /* core dumps don't get here */ - - if (signal_group_exit(sig)) - exit_code = sig->group_exit_code; - else if (!thread_group_empty(current)) { - struct sighand_struct *const sighand = current->sighand; - - spin_lock_irq(&sighand->siglock); - if (signal_group_exit(sig)) - /* Another thread got here before we took the lock. */ - exit_code = sig->group_exit_code; - else { - sig->group_exit_code = exit_code; - sig->flags = SIGNAL_GROUP_EXIT; - zap_other_threads(current); - } - spin_unlock_irq(&sighand->siglock); - } - - do_exit(exit_code); - /* NOTREACHED */ -} - -/* - * this kills every thread in the thread group. Note that any externally - * wait4()-ing process will get the correct exit code - even if this - * thread is not the thread group leader. - */ -SYSCALL_DEFINE1(exit_group, int, error_code) -{ - do_group_exit((error_code & 0xff) << 8); - /* NOTREACHED */ - return 0; -} - -struct wait_opts { - enum pid_type wo_type; - int wo_flags; - struct pid *wo_pid; - - struct siginfo __user *wo_info; - int __user *wo_stat; - struct rusage __user *wo_rusage; - - wait_queue_t child_wait; - int notask_error; -}; - -static inline -struct pid *task_pid_type(struct task_struct *task, enum pid_type type) -{ - if (type != PIDTYPE_PID) - task = task->group_leader; - return task->pids[type].pid; -} - -static int eligible_pid(struct wait_opts *wo, struct task_struct *p) -{ - return wo->wo_type == PIDTYPE_MAX || - task_pid_type(p, wo->wo_type) == wo->wo_pid; -} - -static int -eligible_child(struct wait_opts *wo, bool ptrace, struct task_struct *p) -{ - if (!eligible_pid(wo, p)) - return 0; - - /* - * Wait for all children (clone and not) if __WALL is set or - * if it is traced by us. - */ - if (ptrace || (wo->wo_flags & __WALL)) - return 1; - - /* - * Otherwise, wait for clone children *only* if __WCLONE is set; - * otherwise, wait for non-clone children *only*. - * - * Note: a "clone" child here is one that reports to its parent - * using a signal other than SIGCHLD, or a non-leader thread which - * we can only see if it is traced by us. - */ - if ((p->exit_signal != SIGCHLD) ^ !!(wo->wo_flags & __WCLONE)) - return 0; - - return 1; -} - -static int wait_noreap_copyout(struct wait_opts *wo, struct task_struct *p, - pid_t pid, uid_t uid, int why, int status) -{ - struct siginfo __user *infop; - int retval = wo->wo_rusage - ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0; - - put_task_struct(p); - infop = wo->wo_info; - if (infop) { - if (!retval) - retval = put_user(SIGCHLD, &infop->si_signo); - if (!retval) - retval = put_user(0, &infop->si_errno); - if (!retval) - retval = put_user((short)why, &infop->si_code); - if (!retval) - retval = put_user(pid, &infop->si_pid); - if (!retval) - retval = put_user(uid, &infop->si_uid); - if (!retval) - retval = put_user(status, &infop->si_status); - } - if (!retval) - retval = pid; - return retval; -} - -/* - * Handle sys_wait4 work for one task in state EXIT_ZOMBIE. We hold - * read_lock(&tasklist_lock) on entry. If we return zero, we still hold - * the lock and this task is uninteresting. If we return nonzero, we have - * released the lock and the system call should return. - */ -static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p) -{ - int state, retval, status; - pid_t pid = task_pid_vnr(p); - uid_t uid = from_kuid_munged(current_user_ns(), task_uid(p)); - struct siginfo __user *infop; - - if (!likely(wo->wo_flags & WEXITED)) - return 0; - - if (unlikely(wo->wo_flags & WNOWAIT)) { - int exit_code = p->exit_code; - int why; - - get_task_struct(p); - read_unlock(&tasklist_lock); - sched_annotate_sleep(); - - if ((exit_code & 0x7f) == 0) { - why = CLD_EXITED; - status = exit_code >> 8; - } else { - why = (exit_code & 0x80) ? CLD_DUMPED : CLD_KILLED; - status = exit_code & 0x7f; - } - return wait_noreap_copyout(wo, p, pid, uid, why, status); - } - /* - * Move the task's state to DEAD/TRACE, only one thread can do this. - */ - state = (ptrace_reparented(p) && thread_group_leader(p)) ? - EXIT_TRACE : EXIT_DEAD; - if (cmpxchg(&p->exit_state, EXIT_ZOMBIE, state) != EXIT_ZOMBIE) - return 0; - /* - * We own this thread, nobody else can reap it. - */ - read_unlock(&tasklist_lock); - sched_annotate_sleep(); - - /* - * Check thread_group_leader() to exclude the traced sub-threads. - */ - if (state == EXIT_DEAD && thread_group_leader(p)) { - struct signal_struct *sig = p->signal; - struct signal_struct *psig = current->signal; - unsigned long maxrss; - cputime_t tgutime, tgstime; - - /* - * The resource counters for the group leader are in its - * own task_struct. Those for dead threads in the group - * are in its signal_struct, as are those for the child - * processes it has previously reaped. All these - * accumulate in the parent's signal_struct c* fields. - * - * We don't bother to take a lock here to protect these - * p->signal fields because the whole thread group is dead - * and nobody can change them. - * - * psig->stats_lock also protects us from our sub-theads - * which can reap other children at the same time. Until - * we change k_getrusage()-like users to rely on this lock - * we have to take ->siglock as well. - * - * We use thread_group_cputime_adjusted() to get times for - * the thread group, which consolidates times for all threads - * in the group including the group leader. - */ - thread_group_cputime_adjusted(p, &tgutime, &tgstime); - spin_lock_irq(¤t->sighand->siglock); - write_seqlock(&psig->stats_lock); - psig->cutime += tgutime + sig->cutime; - psig->cstime += tgstime + sig->cstime; - psig->cgtime += task_gtime(p) + sig->gtime + sig->cgtime; - psig->cmin_flt += - p->min_flt + sig->min_flt + sig->cmin_flt; - psig->cmaj_flt += - p->maj_flt + sig->maj_flt + sig->cmaj_flt; - psig->cnvcsw += - p->nvcsw + sig->nvcsw + sig->cnvcsw; - psig->cnivcsw += - p->nivcsw + sig->nivcsw + sig->cnivcsw; - psig->cinblock += - task_io_get_inblock(p) + - sig->inblock + sig->cinblock; - psig->coublock += - task_io_get_oublock(p) + - sig->oublock + sig->coublock; - maxrss = max(sig->maxrss, sig->cmaxrss); - if (psig->cmaxrss < maxrss) - psig->cmaxrss = maxrss; - task_io_accounting_add(&psig->ioac, &p->ioac); - task_io_accounting_add(&psig->ioac, &sig->ioac); - write_sequnlock(&psig->stats_lock); - spin_unlock_irq(¤t->sighand->siglock); - } - - retval = wo->wo_rusage - ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0; - status = (p->signal->flags & SIGNAL_GROUP_EXIT) - ? p->signal->group_exit_code : p->exit_code; - if (!retval && wo->wo_stat) - retval = put_user(status, wo->wo_stat); - - infop = wo->wo_info; - if (!retval && infop) - retval = put_user(SIGCHLD, &infop->si_signo); - if (!retval && infop) - retval = put_user(0, &infop->si_errno); - if (!retval && infop) { - int why; - - if ((status & 0x7f) == 0) { - why = CLD_EXITED; - status >>= 8; - } else { - why = (status & 0x80) ? CLD_DUMPED : CLD_KILLED; - status &= 0x7f; - } - retval = put_user((short)why, &infop->si_code); - if (!retval) - retval = put_user(status, &infop->si_status); - } - if (!retval && infop) - retval = put_user(pid, &infop->si_pid); - if (!retval && infop) - retval = put_user(uid, &infop->si_uid); - if (!retval) - retval = pid; - - if (state == EXIT_TRACE) { - write_lock_irq(&tasklist_lock); - /* We dropped tasklist, ptracer could die and untrace */ - ptrace_unlink(p); - - /* If parent wants a zombie, don't release it now */ - state = EXIT_ZOMBIE; - if (do_notify_parent(p, p->exit_signal)) - state = EXIT_DEAD; - p->exit_state = state; - write_unlock_irq(&tasklist_lock); - } - if (state == EXIT_DEAD) - release_task(p); - - return retval; -} - -static int *task_stopped_code(struct task_struct *p, bool ptrace) -{ - if (ptrace) { - if (task_is_traced(p) && !(p->jobctl & JOBCTL_LISTENING)) - return &p->exit_code; - } else { - if (p->signal->flags & SIGNAL_STOP_STOPPED) - return &p->signal->group_exit_code; - } - return NULL; -} - -/** - * wait_task_stopped - Wait for %TASK_STOPPED or %TASK_TRACED - * @wo: wait options - * @ptrace: is the wait for ptrace - * @p: task to wait for - * - * Handle sys_wait4() work for %p in state %TASK_STOPPED or %TASK_TRACED. - * - * CONTEXT: - * read_lock(&tasklist_lock), which is released if return value is - * non-zero. Also, grabs and releases @p->sighand->siglock. - * - * RETURNS: - * 0 if wait condition didn't exist and search for other wait conditions - * should continue. Non-zero return, -errno on failure and @p's pid on - * success, implies that tasklist_lock is released and wait condition - * search should terminate. - */ -static int wait_task_stopped(struct wait_opts *wo, - int ptrace, struct task_struct *p) -{ - struct siginfo __user *infop; - int retval, exit_code, *p_code, why; - uid_t uid = 0; /* unneeded, required by compiler */ - pid_t pid; - - /* - * Traditionally we see ptrace'd stopped tasks regardless of options. - */ - if (!ptrace && !(wo->wo_flags & WUNTRACED)) - return 0; - - if (!task_stopped_code(p, ptrace)) - return 0; - - exit_code = 0; - spin_lock_irq(&p->sighand->siglock); - - p_code = task_stopped_code(p, ptrace); - if (unlikely(!p_code)) - goto unlock_sig; - - exit_code = *p_code; - if (!exit_code) - goto unlock_sig; - - if (!unlikely(wo->wo_flags & WNOWAIT)) - *p_code = 0; - - uid = from_kuid_munged(current_user_ns(), task_uid(p)); -unlock_sig: - spin_unlock_irq(&p->sighand->siglock); - if (!exit_code) - return 0; - - /* - * Now we are pretty sure this task is interesting. - * Make sure it doesn't get reaped out from under us while we - * give up the lock and then examine it below. We don't want to - * keep holding onto the tasklist_lock while we call getrusage and - * possibly take page faults for user memory. - */ - get_task_struct(p); - pid = task_pid_vnr(p); - why = ptrace ? CLD_TRAPPED : CLD_STOPPED; - read_unlock(&tasklist_lock); - sched_annotate_sleep(); - - if (unlikely(wo->wo_flags & WNOWAIT)) - return wait_noreap_copyout(wo, p, pid, uid, why, exit_code); - - retval = wo->wo_rusage - ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0; - if (!retval && wo->wo_stat) - retval = put_user((exit_code << 8) | 0x7f, wo->wo_stat); - - infop = wo->wo_info; - if (!retval && infop) - retval = put_user(SIGCHLD, &infop->si_signo); - if (!retval && infop) - retval = put_user(0, &infop->si_errno); - if (!retval && infop) - retval = put_user((short)why, &infop->si_code); - if (!retval && infop) - retval = put_user(exit_code, &infop->si_status); - if (!retval && infop) - retval = put_user(pid, &infop->si_pid); - if (!retval && infop) - retval = put_user(uid, &infop->si_uid); - if (!retval) - retval = pid; - put_task_struct(p); - - BUG_ON(!retval); - return retval; -} - -/* - * Handle do_wait work for one task in a live, non-stopped state. - * read_lock(&tasklist_lock) on entry. If we return zero, we still hold - * the lock and this task is uninteresting. If we return nonzero, we have - * released the lock and the system call should return. - */ -static int wait_task_continued(struct wait_opts *wo, struct task_struct *p) -{ - int retval; - pid_t pid; - uid_t uid; - - if (!unlikely(wo->wo_flags & WCONTINUED)) - return 0; - - if (!(p->signal->flags & SIGNAL_STOP_CONTINUED)) - return 0; - - spin_lock_irq(&p->sighand->siglock); - /* Re-check with the lock held. */ - if (!(p->signal->flags & SIGNAL_STOP_CONTINUED)) { - spin_unlock_irq(&p->sighand->siglock); - return 0; - } - if (!unlikely(wo->wo_flags & WNOWAIT)) - p->signal->flags &= ~SIGNAL_STOP_CONTINUED; - uid = from_kuid_munged(current_user_ns(), task_uid(p)); - spin_unlock_irq(&p->sighand->siglock); - - pid = task_pid_vnr(p); - get_task_struct(p); - read_unlock(&tasklist_lock); - sched_annotate_sleep(); - - if (!wo->wo_info) { - retval = wo->wo_rusage - ? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0; - put_task_struct(p); - if (!retval && wo->wo_stat) - retval = put_user(0xffff, wo->wo_stat); - if (!retval) - retval = pid; - } else { - retval = wait_noreap_copyout(wo, p, pid, uid, - CLD_CONTINUED, SIGCONT); - BUG_ON(retval == 0); - } - - return retval; -} - -/* - * Consider @p for a wait by @parent. - * - * -ECHILD should be in ->notask_error before the first call. - * Returns nonzero for a final return, when we have unlocked tasklist_lock. - * Returns zero if the search for a child should continue; - * then ->notask_error is 0 if @p is an eligible child, - * or another error from security_task_wait(), or still -ECHILD. - */ -static int wait_consider_task(struct wait_opts *wo, int ptrace, - struct task_struct *p) -{ - /* - * We can race with wait_task_zombie() from another thread. - * Ensure that EXIT_ZOMBIE -> EXIT_DEAD/EXIT_TRACE transition - * can't confuse the checks below. - */ - int exit_state = ACCESS_ONCE(p->exit_state); - int ret; - - if (unlikely(exit_state == EXIT_DEAD)) - return 0; - - ret = eligible_child(wo, ptrace, p); - if (!ret) - return ret; - - ret = security_task_wait(p); - if (unlikely(ret < 0)) { - /* - * If we have not yet seen any eligible child, - * then let this error code replace -ECHILD. - * A permission error will give the user a clue - * to look for security policy problems, rather - * than for mysterious wait bugs. - */ - if (wo->notask_error) - wo->notask_error = ret; - return 0; - } - - if (unlikely(exit_state == EXIT_TRACE)) { - /* - * ptrace == 0 means we are the natural parent. In this case - * we should clear notask_error, debugger will notify us. - */ - if (likely(!ptrace)) - wo->notask_error = 0; - return 0; - } - - if (likely(!ptrace) && unlikely(p->ptrace)) { - /* - * If it is traced by its real parent's group, just pretend - * the caller is ptrace_do_wait() and reap this child if it - * is zombie. - * - * This also hides group stop state from real parent; otherwise - * a single stop can be reported twice as group and ptrace stop. - * If a ptracer wants to distinguish these two events for its - * own children it should create a separate process which takes - * the role of real parent. - */ - if (!ptrace_reparented(p)) - ptrace = 1; - } - - /* slay zombie? */ - if (exit_state == EXIT_ZOMBIE) { - /* we don't reap group leaders with subthreads */ - if (!delay_group_leader(p)) { - /* - * A zombie ptracee is only visible to its ptracer. - * Notification and reaping will be cascaded to the - * real parent when the ptracer detaches. - */ - if (unlikely(ptrace) || likely(!p->ptrace)) - return wait_task_zombie(wo, p); - } - - /* - * Allow access to stopped/continued state via zombie by - * falling through. Clearing of notask_error is complex. - * - * When !@ptrace: - * - * If WEXITED is set, notask_error should naturally be - * cleared. If not, subset of WSTOPPED|WCONTINUED is set, - * so, if there are live subthreads, there are events to - * wait for. If all subthreads are dead, it's still safe - * to clear - this function will be called again in finite - * amount time once all the subthreads are released and - * will then return without clearing. - * - * When @ptrace: - * - * Stopped state is per-task and thus can't change once the - * target task dies. Only continued and exited can happen. - * Clear notask_error if WCONTINUED | WEXITED. - */ - if (likely(!ptrace) || (wo->wo_flags & (WCONTINUED | WEXITED))) - wo->notask_error = 0; - } else { - /* - * @p is alive and it's gonna stop, continue or exit, so - * there always is something to wait for. - */ - wo->notask_error = 0; - } - - /* - * Wait for stopped. Depending on @ptrace, different stopped state - * is used and the two don't interact with each other. - */ - ret = wait_task_stopped(wo, ptrace, p); - if (ret) - return ret; - - /* - * Wait for continued. There's only one continued state and the - * ptracer can consume it which can confuse the real parent. Don't - * use WCONTINUED from ptracer. You don't need or want it. - */ - return wait_task_continued(wo, p); -} - -/* - * Do the work of do_wait() for one thread in the group, @tsk. - * - * -ECHILD should be in ->notask_error before the first call. - * Returns nonzero for a final return, when we have unlocked tasklist_lock. - * Returns zero if the search for a child should continue; then - * ->notask_error is 0 if there were any eligible children, - * or another error from security_task_wait(), or still -ECHILD. - */ -static int do_wait_thread(struct wait_opts *wo, struct task_struct *tsk) -{ - struct task_struct *p; - - list_for_each_entry(p, &tsk->children, sibling) { - int ret = wait_consider_task(wo, 0, p); - - if (ret) - return ret; - } - - return 0; -} - -static int ptrace_do_wait(struct wait_opts *wo, struct task_struct *tsk) -{ - struct task_struct *p; - - list_for_each_entry(p, &tsk->ptraced, ptrace_entry) { - int ret = wait_consider_task(wo, 1, p); - - if (ret) - return ret; - } - - return 0; -} - -static int child_wait_callback(wait_queue_t *wait, unsigned mode, - int sync, void *key) -{ - struct wait_opts *wo = container_of(wait, struct wait_opts, - child_wait); - struct task_struct *p = key; - - if (!eligible_pid(wo, p)) - return 0; - - if ((wo->wo_flags & __WNOTHREAD) && wait->private != p->parent) - return 0; - - return default_wake_function(wait, mode, sync, key); -} - -void __wake_up_parent(struct task_struct *p, struct task_struct *parent) -{ - __wake_up_sync_key(&parent->signal->wait_chldexit, - TASK_INTERRUPTIBLE, 1, p); -} - -static long do_wait(struct wait_opts *wo) -{ - struct task_struct *tsk; - int retval; - - trace_sched_process_wait(wo->wo_pid); - - init_waitqueue_func_entry(&wo->child_wait, child_wait_callback); - wo->child_wait.private = current; - add_wait_queue(¤t->signal->wait_chldexit, &wo->child_wait); -repeat: - /* - * If there is nothing that can match our criteria, just get out. - * We will clear ->notask_error to zero if we see any child that - * might later match our criteria, even if we are not able to reap - * it yet. - */ - wo->notask_error = -ECHILD; - if ((wo->wo_type < PIDTYPE_MAX) && - (!wo->wo_pid || hlist_empty(&wo->wo_pid->tasks[wo->wo_type]))) - goto notask; - - set_current_state(TASK_INTERRUPTIBLE); - read_lock(&tasklist_lock); - tsk = current; - do { - retval = do_wait_thread(wo, tsk); - if (retval) - goto end; - - retval = ptrace_do_wait(wo, tsk); - if (retval) - goto end; - - if (wo->wo_flags & __WNOTHREAD) - break; - } while_each_thread(current, tsk); - read_unlock(&tasklist_lock); - -notask: - retval = wo->notask_error; - if (!retval && !(wo->wo_flags & WNOHANG)) { - retval = -ERESTARTSYS; - if (!signal_pending(current)) { - schedule(); - goto repeat; - } - } -end: - __set_current_state(TASK_RUNNING); - remove_wait_queue(¤t->signal->wait_chldexit, &wo->child_wait); - return retval; -} - -SYSCALL_DEFINE5(waitid, int, which, pid_t, upid, struct siginfo __user *, - infop, int, options, struct rusage __user *, ru) -{ - struct wait_opts wo; - struct pid *pid = NULL; - enum pid_type type; - long ret; - - if (options & ~(WNOHANG|WNOWAIT|WEXITED|WSTOPPED|WCONTINUED| - __WNOTHREAD|__WCLONE|__WALL)) - return -EINVAL; - if (!(options & (WEXITED|WSTOPPED|WCONTINUED))) - return -EINVAL; - - switch (which) { - case P_ALL: - type = PIDTYPE_MAX; - break; - case P_PID: - type = PIDTYPE_PID; - if (upid <= 0) - return -EINVAL; - break; - case P_PGID: - type = PIDTYPE_PGID; - if (upid <= 0) - return -EINVAL; - break; - default: - return -EINVAL; - } - - if (type < PIDTYPE_MAX) - pid = find_get_pid(upid); - - wo.wo_type = type; - wo.wo_pid = pid; - wo.wo_flags = options; - wo.wo_info = infop; - wo.wo_stat = NULL; - wo.wo_rusage = ru; - ret = do_wait(&wo); - - if (ret > 0) { - ret = 0; - } else if (infop) { - /* - * For a WNOHANG return, clear out all the fields - * we would set so the user can easily tell the - * difference. - */ - if (!ret) - ret = put_user(0, &infop->si_signo); - if (!ret) - ret = put_user(0, &infop->si_errno); - if (!ret) - ret = put_user(0, &infop->si_code); - if (!ret) - ret = put_user(0, &infop->si_pid); - if (!ret) - ret = put_user(0, &infop->si_uid); - if (!ret) - ret = put_user(0, &infop->si_status); - } - - put_pid(pid); - return ret; -} - -SYSCALL_DEFINE4(wait4, pid_t, upid, int __user *, stat_addr, - int, options, struct rusage __user *, ru) -{ - struct wait_opts wo; - struct pid *pid = NULL; - enum pid_type type; - long ret; - - if (options & ~(WNOHANG|WUNTRACED|WCONTINUED| - __WNOTHREAD|__WCLONE|__WALL)) - return -EINVAL; - - if (upid == -1) - type = PIDTYPE_MAX; - else if (upid < 0) { - type = PIDTYPE_PGID; - pid = find_get_pid(-upid); - } else if (upid == 0) { - type = PIDTYPE_PGID; - pid = get_task_pid(current, PIDTYPE_PGID); - } else /* upid > 0 */ { - type = PIDTYPE_PID; - pid = find_get_pid(upid); - } - - wo.wo_type = type; - wo.wo_pid = pid; - wo.wo_flags = options | WEXITED; - wo.wo_info = NULL; - wo.wo_stat = stat_addr; - wo.wo_rusage = ru; - ret = do_wait(&wo); - put_pid(pid); - - return ret; -} - -#ifdef __ARCH_WANT_SYS_WAITPID - -/* - * sys_waitpid() remains for compatibility. waitpid() should be - * implemented by calling sys_wait4() from libc.a. - */ -SYSCALL_DEFINE3(waitpid, pid_t, pid, int __user *, stat_addr, int, options) -{ - return sys_wait4(pid, stat_addr, options, NULL); -} - -#endif diff --git a/src/linux/kernel/extable.c b/src/linux/kernel/extable.c deleted file mode 100644 index e820cce..0000000 --- a/src/linux/kernel/extable.c +++ /dev/null @@ -1,143 +0,0 @@ -/* Rewritten by Rusty Russell, on the backs of many others... - Copyright (C) 2001 Rusty Russell, 2002 Rusty Russell IBM. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#include -#include -#include -#include -#include - -#include -#include - -/* - * mutex protecting text section modification (dynamic code patching). - * some users need to sleep (allocating memory...) while they hold this lock. - * - * NOT exported to modules - patching kernel text is a really delicate matter. - */ -DEFINE_MUTEX(text_mutex); - -extern struct exception_table_entry __start___ex_table[]; -extern struct exception_table_entry __stop___ex_table[]; - -/* Cleared by build time tools if the table is already sorted. */ -u32 __initdata __visible main_extable_sort_needed = 1; - -/* Sort the kernel's built-in exception table */ -void __init sort_main_extable(void) -{ - if (main_extable_sort_needed && __stop___ex_table > __start___ex_table) { - pr_notice("Sorting __ex_table...\n"); - sort_extable(__start___ex_table, __stop___ex_table); - } -} - -/* Given an address, look for it in the exception tables. */ -const struct exception_table_entry *search_exception_tables(unsigned long addr) -{ - const struct exception_table_entry *e; - - e = search_extable(__start___ex_table, __stop___ex_table-1, addr); - if (!e) - e = search_module_extables(addr); - return e; -} - -static inline int init_kernel_text(unsigned long addr) -{ - if (addr >= (unsigned long)_sinittext && - addr < (unsigned long)_einittext) - return 1; - return 0; -} - -int core_kernel_text(unsigned long addr) -{ - if (addr >= (unsigned long)_stext && - addr < (unsigned long)_etext) - return 1; - - if (system_state == SYSTEM_BOOTING && - init_kernel_text(addr)) - return 1; - return 0; -} - -/** - * core_kernel_data - tell if addr points to kernel data - * @addr: address to test - * - * Returns true if @addr passed in is from the core kernel data - * section. - * - * Note: On some archs it may return true for core RODATA, and false - * for others. But will always be true for core RW data. - */ -int core_kernel_data(unsigned long addr) -{ - if (addr >= (unsigned long)_sdata && - addr < (unsigned long)_edata) - return 1; - return 0; -} - -int __kernel_text_address(unsigned long addr) -{ - if (core_kernel_text(addr)) - return 1; - if (is_module_text_address(addr)) - return 1; - if (is_ftrace_trampoline(addr)) - return 1; - /* - * There might be init symbols in saved stacktraces. - * Give those symbols a chance to be printed in - * backtraces (such as lockdep traces). - * - * Since we are after the module-symbols check, there's - * no danger of address overlap: - */ - if (init_kernel_text(addr)) - return 1; - return 0; -} - -int kernel_text_address(unsigned long addr) -{ - if (core_kernel_text(addr)) - return 1; - if (is_module_text_address(addr)) - return 1; - return is_ftrace_trampoline(addr); -} - -/* - * On some architectures (PPC64, IA64) function pointers - * are actually only tokens to some data that then holds the - * real function address. As a result, to find if a function - * pointer is part of the kernel text, we need to do some - * special dereferencing first. - */ -int func_ptr_is_kernel_text(void *ptr) -{ - unsigned long addr; - addr = (unsigned long) dereference_function_descriptor(ptr); - if (core_kernel_text(addr)) - return 1; - return is_module_text_address(addr); -} diff --git a/src/linux/kernel/fork.c b/src/linux/kernel/fork.c deleted file mode 100644 index 997ac1d..0000000 --- a/src/linux/kernel/fork.c +++ /dev/null @@ -1,2331 +0,0 @@ -/* - * linux/kernel/fork.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -/* - * 'fork.c' contains the help-routines for the 'fork' system call - * (see also entry.S and others). - * Fork is rather simple, once you get the hang of it, but the memory - * management can be a bitch. See 'mm/memory.c': 'copy_page_range()' - */ - -#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 -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#define CREATE_TRACE_POINTS -#include - -/* - * Minimum number of threads to boot the kernel - */ -#define MIN_THREADS 20 - -/* - * Maximum number of threads - */ -#define MAX_THREADS FUTEX_TID_MASK - -/* - * Protected counters by write_lock_irq(&tasklist_lock) - */ -unsigned long total_forks; /* Handle normal Linux uptimes. */ -int nr_threads; /* The idle threads do not count.. */ - -int max_threads; /* tunable limit on nr_threads */ - -DEFINE_PER_CPU(unsigned long, process_counts) = 0; - -__cacheline_aligned DEFINE_RWLOCK(tasklist_lock); /* outer */ - -#ifdef CONFIG_PROVE_RCU -int lockdep_tasklist_lock_is_held(void) -{ - return lockdep_is_held(&tasklist_lock); -} -EXPORT_SYMBOL_GPL(lockdep_tasklist_lock_is_held); -#endif /* #ifdef CONFIG_PROVE_RCU */ - -int nr_processes(void) -{ - int cpu; - int total = 0; - - for_each_possible_cpu(cpu) - total += per_cpu(process_counts, cpu); - - return total; -} - -void __weak arch_release_task_struct(struct task_struct *tsk) -{ -} - -#ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR -static struct kmem_cache *task_struct_cachep; - -static inline struct task_struct *alloc_task_struct_node(int node) -{ - return kmem_cache_alloc_node(task_struct_cachep, GFP_KERNEL, node); -} - -static inline void free_task_struct(struct task_struct *tsk) -{ - kmem_cache_free(task_struct_cachep, tsk); -} -#endif - -void __weak arch_release_thread_stack(unsigned long *stack) -{ -} - -#ifndef CONFIG_ARCH_THREAD_STACK_ALLOCATOR - -/* - * Allocate pages if THREAD_SIZE is >= PAGE_SIZE, otherwise use a - * kmemcache based allocator. - */ -# if THREAD_SIZE >= PAGE_SIZE || defined(CONFIG_VMAP_STACK) - -#ifdef CONFIG_VMAP_STACK -/* - * vmalloc() is a bit slow, and calling vfree() enough times will force a TLB - * flush. Try to minimize the number of calls by caching stacks. - */ -#define NR_CACHED_STACKS 2 -static DEFINE_PER_CPU(struct vm_struct *, cached_stacks[NR_CACHED_STACKS]); -#endif - -static unsigned long *alloc_thread_stack_node(struct task_struct *tsk, int node) -{ -#ifdef CONFIG_VMAP_STACK - void *stack; - int i; - - local_irq_disable(); - for (i = 0; i < NR_CACHED_STACKS; i++) { - struct vm_struct *s = this_cpu_read(cached_stacks[i]); - - if (!s) - continue; - this_cpu_write(cached_stacks[i], NULL); - - tsk->stack_vm_area = s; - local_irq_enable(); - return s->addr; - } - local_irq_enable(); - - stack = __vmalloc_node_range(THREAD_SIZE, THREAD_SIZE, - VMALLOC_START, VMALLOC_END, - THREADINFO_GFP | __GFP_HIGHMEM, - PAGE_KERNEL, - 0, node, __builtin_return_address(0)); - - /* - * We can't call find_vm_area() in interrupt context, and - * free_thread_stack() can be called in interrupt context, - * so cache the vm_struct. - */ - if (stack) - tsk->stack_vm_area = find_vm_area(stack); - return stack; -#else - struct page *page = alloc_pages_node(node, THREADINFO_GFP, - THREAD_SIZE_ORDER); - - return page ? page_address(page) : NULL; -#endif -} - -static inline void free_thread_stack(struct task_struct *tsk) -{ -#ifdef CONFIG_VMAP_STACK - if (task_stack_vm_area(tsk)) { - unsigned long flags; - int i; - - local_irq_save(flags); - for (i = 0; i < NR_CACHED_STACKS; i++) { - if (this_cpu_read(cached_stacks[i])) - continue; - - this_cpu_write(cached_stacks[i], tsk->stack_vm_area); - local_irq_restore(flags); - return; - } - local_irq_restore(flags); - - vfree(tsk->stack); - return; - } -#endif - - __free_pages(virt_to_page(tsk->stack), THREAD_SIZE_ORDER); -} -# else -static struct kmem_cache *thread_stack_cache; - -static unsigned long *alloc_thread_stack_node(struct task_struct *tsk, - int node) -{ - return kmem_cache_alloc_node(thread_stack_cache, THREADINFO_GFP, node); -} - -static void free_thread_stack(struct task_struct *tsk) -{ - kmem_cache_free(thread_stack_cache, tsk->stack); -} - -void thread_stack_cache_init(void) -{ - thread_stack_cache = kmem_cache_create("thread_stack", THREAD_SIZE, - THREAD_SIZE, 0, NULL); - BUG_ON(thread_stack_cache == NULL); -} -# endif -#endif - -/* SLAB cache for signal_struct structures (tsk->signal) */ -static struct kmem_cache *signal_cachep; - -/* SLAB cache for sighand_struct structures (tsk->sighand) */ -struct kmem_cache *sighand_cachep; - -/* SLAB cache for files_struct structures (tsk->files) */ -struct kmem_cache *files_cachep; - -/* SLAB cache for fs_struct structures (tsk->fs) */ -struct kmem_cache *fs_cachep; - -/* SLAB cache for vm_area_struct structures */ -struct kmem_cache *vm_area_cachep; - -/* SLAB cache for mm_struct structures (tsk->mm) */ -static struct kmem_cache *mm_cachep; - -static void account_kernel_stack(struct task_struct *tsk, int account) -{ - void *stack = task_stack_page(tsk); - struct vm_struct *vm = task_stack_vm_area(tsk); - - BUILD_BUG_ON(IS_ENABLED(CONFIG_VMAP_STACK) && PAGE_SIZE % 1024 != 0); - - if (vm) { - int i; - - BUG_ON(vm->nr_pages != THREAD_SIZE / PAGE_SIZE); - - for (i = 0; i < THREAD_SIZE / PAGE_SIZE; i++) { - mod_zone_page_state(page_zone(vm->pages[i]), - NR_KERNEL_STACK_KB, - PAGE_SIZE / 1024 * account); - } - - /* All stack pages belong to the same memcg. */ - memcg_kmem_update_page_stat(vm->pages[0], MEMCG_KERNEL_STACK_KB, - account * (THREAD_SIZE / 1024)); - } else { - /* - * All stack pages are in the same zone and belong to the - * same memcg. - */ - struct page *first_page = virt_to_page(stack); - - mod_zone_page_state(page_zone(first_page), NR_KERNEL_STACK_KB, - THREAD_SIZE / 1024 * account); - - memcg_kmem_update_page_stat(first_page, MEMCG_KERNEL_STACK_KB, - account * (THREAD_SIZE / 1024)); - } -} - -static void release_task_stack(struct task_struct *tsk) -{ - if (WARN_ON(tsk->state != TASK_DEAD)) - return; /* Better to leak the stack than to free prematurely */ - - account_kernel_stack(tsk, -1); - arch_release_thread_stack(tsk->stack); - free_thread_stack(tsk); - tsk->stack = NULL; -#ifdef CONFIG_VMAP_STACK - tsk->stack_vm_area = NULL; -#endif -} - -#ifdef CONFIG_THREAD_INFO_IN_TASK -void put_task_stack(struct task_struct *tsk) -{ - if (atomic_dec_and_test(&tsk->stack_refcount)) - release_task_stack(tsk); -} -#endif - -void free_task(struct task_struct *tsk) -{ -#ifndef CONFIG_THREAD_INFO_IN_TASK - /* - * The task is finally done with both the stack and thread_info, - * so free both. - */ - release_task_stack(tsk); -#else - /* - * If the task had a separate stack allocation, it should be gone - * by now. - */ - WARN_ON_ONCE(atomic_read(&tsk->stack_refcount) != 0); -#endif - rt_mutex_debug_task_free(tsk); - ftrace_graph_exit_task(tsk); - put_seccomp_filter(tsk); - arch_release_task_struct(tsk); - free_task_struct(tsk); -} -EXPORT_SYMBOL(free_task); - -static inline void free_signal_struct(struct signal_struct *sig) -{ - taskstats_tgid_free(sig); - sched_autogroup_exit(sig); - /* - * __mmdrop is not safe to call from softirq context on x86 due to - * pgd_dtor so postpone it to the async context - */ - if (sig->oom_mm) - mmdrop_async(sig->oom_mm); - kmem_cache_free(signal_cachep, sig); -} - -static inline void put_signal_struct(struct signal_struct *sig) -{ - if (atomic_dec_and_test(&sig->sigcnt)) - free_signal_struct(sig); -} - -void __put_task_struct(struct task_struct *tsk) -{ - WARN_ON(!tsk->exit_state); - WARN_ON(atomic_read(&tsk->usage)); - WARN_ON(tsk == current); - - cgroup_free(tsk); - task_numa_free(tsk); - security_task_free(tsk); - exit_creds(tsk); - delayacct_tsk_free(tsk); - put_signal_struct(tsk->signal); - - if (!profile_handoff_task(tsk)) - free_task(tsk); -} -EXPORT_SYMBOL_GPL(__put_task_struct); - -void __init __weak arch_task_cache_init(void) { } - -/* - * set_max_threads - */ -static void set_max_threads(unsigned int max_threads_suggested) -{ - u64 threads; - - /* - * The number of threads shall be limited such that the thread - * structures may only consume a small part of the available memory. - */ - if (fls64(totalram_pages) + fls64(PAGE_SIZE) > 64) - threads = MAX_THREADS; - else - threads = div64_u64((u64) totalram_pages * (u64) PAGE_SIZE, - (u64) THREAD_SIZE * 8UL); - - if (threads > max_threads_suggested) - threads = max_threads_suggested; - - max_threads = clamp_t(u64, threads, MIN_THREADS, MAX_THREADS); -} - -#ifdef CONFIG_ARCH_WANTS_DYNAMIC_TASK_STRUCT -/* Initialized by the architecture: */ -int arch_task_struct_size __read_mostly; -#endif - -void __init fork_init(void) -{ - int i; -#ifndef CONFIG_ARCH_TASK_STRUCT_ALLOCATOR -#ifndef ARCH_MIN_TASKALIGN -#define ARCH_MIN_TASKALIGN L1_CACHE_BYTES -#endif - /* create a slab on which task_structs can be allocated */ - task_struct_cachep = kmem_cache_create("task_struct", - arch_task_struct_size, ARCH_MIN_TASKALIGN, - SLAB_PANIC|SLAB_NOTRACK|SLAB_ACCOUNT, NULL); -#endif - - /* do the arch specific task caches init */ - arch_task_cache_init(); - - set_max_threads(MAX_THREADS); - - init_task.signal->rlim[RLIMIT_NPROC].rlim_cur = max_threads/2; - init_task.signal->rlim[RLIMIT_NPROC].rlim_max = max_threads/2; - init_task.signal->rlim[RLIMIT_SIGPENDING] = - init_task.signal->rlim[RLIMIT_NPROC]; - - for (i = 0; i < UCOUNT_COUNTS; i++) { - init_user_ns.ucount_max[i] = max_threads/2; - } -} - -int __weak arch_dup_task_struct(struct task_struct *dst, - struct task_struct *src) -{ - *dst = *src; - return 0; -} - -void set_task_stack_end_magic(struct task_struct *tsk) -{ - unsigned long *stackend; - - stackend = end_of_stack(tsk); - *stackend = STACK_END_MAGIC; /* for overflow detection */ -} - -static struct task_struct *dup_task_struct(struct task_struct *orig, int node) -{ - struct task_struct *tsk; - unsigned long *stack; - struct vm_struct *stack_vm_area; - int err; - - if (node == NUMA_NO_NODE) - node = tsk_fork_get_node(orig); - tsk = alloc_task_struct_node(node); - if (!tsk) - return NULL; - - stack = alloc_thread_stack_node(tsk, node); - if (!stack) - goto free_tsk; - - stack_vm_area = task_stack_vm_area(tsk); - - err = arch_dup_task_struct(tsk, orig); - - /* - * arch_dup_task_struct() clobbers the stack-related fields. Make - * sure they're properly initialized before using any stack-related - * functions again. - */ - tsk->stack = stack; -#ifdef CONFIG_VMAP_STACK - tsk->stack_vm_area = stack_vm_area; -#endif -#ifdef CONFIG_THREAD_INFO_IN_TASK - atomic_set(&tsk->stack_refcount, 1); -#endif - - if (err) - goto free_stack; - -#ifdef CONFIG_SECCOMP - /* - * We must handle setting up seccomp filters once we're under - * the sighand lock in case orig has changed between now and - * then. Until then, filter must be NULL to avoid messing up - * the usage counts on the error path calling free_task. - */ - tsk->seccomp.filter = NULL; -#endif - - setup_thread_stack(tsk, orig); - clear_user_return_notifier(tsk); - clear_tsk_need_resched(tsk); - set_task_stack_end_magic(tsk); - -#ifdef CONFIG_CC_STACKPROTECTOR - tsk->stack_canary = get_random_int(); -#endif - - /* - * One for us, one for whoever does the "release_task()" (usually - * parent) - */ - atomic_set(&tsk->usage, 2); -#ifdef CONFIG_BLK_DEV_IO_TRACE - tsk->btrace_seq = 0; -#endif - tsk->splice_pipe = NULL; - tsk->task_frag.page = NULL; - tsk->wake_q.next = NULL; - - account_kernel_stack(tsk, 1); - - kcov_task_init(tsk); - - return tsk; - -free_stack: - free_thread_stack(tsk); -free_tsk: - free_task_struct(tsk); - return NULL; -} - -#ifdef CONFIG_MMU -static __latent_entropy int dup_mmap(struct mm_struct *mm, - struct mm_struct *oldmm) -{ - struct vm_area_struct *mpnt, *tmp, *prev, **pprev; - struct rb_node **rb_link, *rb_parent; - int retval; - unsigned long charge; - - uprobe_start_dup_mmap(); - if (down_write_killable(&oldmm->mmap_sem)) { - retval = -EINTR; - goto fail_uprobe_end; - } - flush_cache_dup_mm(oldmm); - uprobe_dup_mmap(oldmm, mm); - /* - * Not linked in yet - no deadlock potential: - */ - down_write_nested(&mm->mmap_sem, SINGLE_DEPTH_NESTING); - - /* No ordering required: file already has been exposed. */ - RCU_INIT_POINTER(mm->exe_file, get_mm_exe_file(oldmm)); - - mm->total_vm = oldmm->total_vm; - mm->data_vm = oldmm->data_vm; - mm->exec_vm = oldmm->exec_vm; - mm->stack_vm = oldmm->stack_vm; - - rb_link = &mm->mm_rb.rb_node; - rb_parent = NULL; - pprev = &mm->mmap; - retval = ksm_fork(mm, oldmm); - if (retval) - goto out; - retval = khugepaged_fork(mm, oldmm); - if (retval) - goto out; - - prev = NULL; - for (mpnt = oldmm->mmap; mpnt; mpnt = mpnt->vm_next) { - struct file *file; - - if (mpnt->vm_flags & VM_DONTCOPY) { - vm_stat_account(mm, mpnt->vm_flags, -vma_pages(mpnt)); - continue; - } - charge = 0; - if (mpnt->vm_flags & VM_ACCOUNT) { - unsigned long len = vma_pages(mpnt); - - if (security_vm_enough_memory_mm(oldmm, len)) /* sic */ - goto fail_nomem; - charge = len; - } - tmp = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); - if (!tmp) - goto fail_nomem; - *tmp = *mpnt; - INIT_LIST_HEAD(&tmp->anon_vma_chain); - retval = vma_dup_policy(mpnt, tmp); - if (retval) - goto fail_nomem_policy; - tmp->vm_mm = mm; - if (anon_vma_fork(tmp, mpnt)) - goto fail_nomem_anon_vma_fork; - tmp->vm_flags &= - ~(VM_LOCKED|VM_LOCKONFAULT|VM_UFFD_MISSING|VM_UFFD_WP); - tmp->vm_next = tmp->vm_prev = NULL; - tmp->vm_userfaultfd_ctx = NULL_VM_UFFD_CTX; - file = tmp->vm_file; - if (file) { - struct inode *inode = file_inode(file); - struct address_space *mapping = file->f_mapping; - - get_file(file); - if (tmp->vm_flags & VM_DENYWRITE) - atomic_dec(&inode->i_writecount); - i_mmap_lock_write(mapping); - if (tmp->vm_flags & VM_SHARED) - atomic_inc(&mapping->i_mmap_writable); - flush_dcache_mmap_lock(mapping); - /* insert tmp into the share list, just after mpnt */ - vma_interval_tree_insert_after(tmp, mpnt, - &mapping->i_mmap); - flush_dcache_mmap_unlock(mapping); - i_mmap_unlock_write(mapping); - } - - /* - * Clear hugetlb-related page reserves for children. This only - * affects MAP_PRIVATE mappings. Faults generated by the child - * are not guaranteed to succeed, even if read-only - */ - if (is_vm_hugetlb_page(tmp)) - reset_vma_resv_huge_pages(tmp); - - /* - * Link in the new vma and copy the page table entries. - */ - *pprev = tmp; - pprev = &tmp->vm_next; - tmp->vm_prev = prev; - prev = tmp; - - __vma_link_rb(mm, tmp, rb_link, rb_parent); - rb_link = &tmp->vm_rb.rb_right; - rb_parent = &tmp->vm_rb; - - mm->map_count++; - retval = copy_page_range(mm, oldmm, mpnt); - - if (tmp->vm_ops && tmp->vm_ops->open) - tmp->vm_ops->open(tmp); - - if (retval) - goto out; - } - /* a new mm has just been created */ - arch_dup_mmap(oldmm, mm); - retval = 0; -out: - up_write(&mm->mmap_sem); - flush_tlb_mm(oldmm); - up_write(&oldmm->mmap_sem); -fail_uprobe_end: - uprobe_end_dup_mmap(); - return retval; -fail_nomem_anon_vma_fork: - mpol_put(vma_policy(tmp)); -fail_nomem_policy: - kmem_cache_free(vm_area_cachep, tmp); -fail_nomem: - retval = -ENOMEM; - vm_unacct_memory(charge); - goto out; -} - -static inline int mm_alloc_pgd(struct mm_struct *mm) -{ - mm->pgd = pgd_alloc(mm); - if (unlikely(!mm->pgd)) - return -ENOMEM; - return 0; -} - -static inline void mm_free_pgd(struct mm_struct *mm) -{ - pgd_free(mm, mm->pgd); -} -#else -static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) -{ - down_write(&oldmm->mmap_sem); - RCU_INIT_POINTER(mm->exe_file, get_mm_exe_file(oldmm)); - up_write(&oldmm->mmap_sem); - return 0; -} -#define mm_alloc_pgd(mm) (0) -#define mm_free_pgd(mm) -#endif /* CONFIG_MMU */ - -__cacheline_aligned_in_smp DEFINE_SPINLOCK(mmlist_lock); - -#define allocate_mm() (kmem_cache_alloc(mm_cachep, GFP_KERNEL)) -#define free_mm(mm) (kmem_cache_free(mm_cachep, (mm))) - -static unsigned long default_dump_filter = MMF_DUMP_FILTER_DEFAULT; - -static int __init coredump_filter_setup(char *s) -{ - default_dump_filter = - (simple_strtoul(s, NULL, 0) << MMF_DUMP_FILTER_SHIFT) & - MMF_DUMP_FILTER_MASK; - return 1; -} - -__setup("coredump_filter=", coredump_filter_setup); - -#include - -static void mm_init_aio(struct mm_struct *mm) -{ -#ifdef CONFIG_AIO - spin_lock_init(&mm->ioctx_lock); - mm->ioctx_table = NULL; -#endif -} - -static void mm_init_owner(struct mm_struct *mm, struct task_struct *p) -{ -#ifdef CONFIG_MEMCG - mm->owner = p; -#endif -} - -static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p) -{ - mm->mmap = NULL; - mm->mm_rb = RB_ROOT; - mm->vmacache_seqnum = 0; - atomic_set(&mm->mm_users, 1); - atomic_set(&mm->mm_count, 1); - init_rwsem(&mm->mmap_sem); - INIT_LIST_HEAD(&mm->mmlist); - mm->core_state = NULL; - atomic_long_set(&mm->nr_ptes, 0); - mm_nr_pmds_init(mm); - mm->map_count = 0; - mm->locked_vm = 0; - mm->pinned_vm = 0; - memset(&mm->rss_stat, 0, sizeof(mm->rss_stat)); - spin_lock_init(&mm->page_table_lock); - mm_init_cpumask(mm); - mm_init_aio(mm); - mm_init_owner(mm, p); - mmu_notifier_mm_init(mm); - clear_tlb_flush_pending(mm); -#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && !USE_SPLIT_PMD_PTLOCKS - mm->pmd_huge_pte = NULL; -#endif - - if (current->mm) { - mm->flags = current->mm->flags & MMF_INIT_MASK; - mm->def_flags = current->mm->def_flags & VM_INIT_DEF_MASK; - } else { - mm->flags = default_dump_filter; - mm->def_flags = 0; - } - - if (mm_alloc_pgd(mm)) - goto fail_nopgd; - - if (init_new_context(p, mm)) - goto fail_nocontext; - - return mm; - -fail_nocontext: - mm_free_pgd(mm); -fail_nopgd: - free_mm(mm); - return NULL; -} - -static void check_mm(struct mm_struct *mm) -{ - int i; - - for (i = 0; i < NR_MM_COUNTERS; i++) { - long x = atomic_long_read(&mm->rss_stat.count[i]); - - if (unlikely(x)) - printk(KERN_ALERT "BUG: Bad rss-counter state " - "mm:%p idx:%d val:%ld\n", mm, i, x); - } - - if (atomic_long_read(&mm->nr_ptes)) - pr_alert("BUG: non-zero nr_ptes on freeing mm: %ld\n", - atomic_long_read(&mm->nr_ptes)); - if (mm_nr_pmds(mm)) - pr_alert("BUG: non-zero nr_pmds on freeing mm: %ld\n", - mm_nr_pmds(mm)); - -#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && !USE_SPLIT_PMD_PTLOCKS - VM_BUG_ON_MM(mm->pmd_huge_pte, mm); -#endif -} - -/* - * Allocate and initialize an mm_struct. - */ -struct mm_struct *mm_alloc(void) -{ - struct mm_struct *mm; - - mm = allocate_mm(); - if (!mm) - return NULL; - - memset(mm, 0, sizeof(*mm)); - return mm_init(mm, current); -} - -/* - * Called when the last reference to the mm - * is dropped: either by a lazy thread or by - * mmput. Free the page directory and the mm. - */ -void __mmdrop(struct mm_struct *mm) -{ - BUG_ON(mm == &init_mm); - mm_free_pgd(mm); - destroy_context(mm); - mmu_notifier_mm_destroy(mm); - check_mm(mm); - free_mm(mm); -} -EXPORT_SYMBOL_GPL(__mmdrop); - -static inline void __mmput(struct mm_struct *mm) -{ - VM_BUG_ON(atomic_read(&mm->mm_users)); - - uprobe_clear_state(mm); - exit_aio(mm); - ksm_exit(mm); - khugepaged_exit(mm); /* must run before exit_mmap */ - exit_mmap(mm); - mm_put_huge_zero_page(mm); - set_mm_exe_file(mm, NULL); - if (!list_empty(&mm->mmlist)) { - spin_lock(&mmlist_lock); - list_del(&mm->mmlist); - spin_unlock(&mmlist_lock); - } - if (mm->binfmt) - module_put(mm->binfmt->module); - set_bit(MMF_OOM_SKIP, &mm->flags); - mmdrop(mm); -} - -/* - * Decrement the use count and release all resources for an mm. - */ -void mmput(struct mm_struct *mm) -{ - might_sleep(); - - if (atomic_dec_and_test(&mm->mm_users)) - __mmput(mm); -} -EXPORT_SYMBOL_GPL(mmput); - -#ifdef CONFIG_MMU -static void mmput_async_fn(struct work_struct *work) -{ - struct mm_struct *mm = container_of(work, struct mm_struct, async_put_work); - __mmput(mm); -} - -void mmput_async(struct mm_struct *mm) -{ - if (atomic_dec_and_test(&mm->mm_users)) { - INIT_WORK(&mm->async_put_work, mmput_async_fn); - schedule_work(&mm->async_put_work); - } -} -#endif - -/** - * set_mm_exe_file - change a reference to the mm's executable file - * - * This changes mm's executable file (shown as symlink /proc/[pid]/exe). - * - * Main users are mmput() and sys_execve(). Callers prevent concurrent - * invocations: in mmput() nobody alive left, in execve task is single - * threaded. sys_prctl(PR_SET_MM_MAP/EXE_FILE) also needs to set the - * mm->exe_file, but does so without using set_mm_exe_file() in order - * to do avoid the need for any locks. - */ -void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file) -{ - struct file *old_exe_file; - - /* - * It is safe to dereference the exe_file without RCU as - * this function is only called if nobody else can access - * this mm -- see comment above for justification. - */ - old_exe_file = rcu_dereference_raw(mm->exe_file); - - if (new_exe_file) - get_file(new_exe_file); - rcu_assign_pointer(mm->exe_file, new_exe_file); - if (old_exe_file) - fput(old_exe_file); -} - -/** - * get_mm_exe_file - acquire a reference to the mm's executable file - * - * Returns %NULL if mm has no associated executable file. - * User must release file via fput(). - */ -struct file *get_mm_exe_file(struct mm_struct *mm) -{ - struct file *exe_file; - - rcu_read_lock(); - exe_file = rcu_dereference(mm->exe_file); - if (exe_file && !get_file_rcu(exe_file)) - exe_file = NULL; - rcu_read_unlock(); - return exe_file; -} -EXPORT_SYMBOL(get_mm_exe_file); - -/** - * get_task_exe_file - acquire a reference to the task's executable file - * - * Returns %NULL if task's mm (if any) has no associated executable file or - * this is a kernel thread with borrowed mm (see the comment above get_task_mm). - * User must release file via fput(). - */ -struct file *get_task_exe_file(struct task_struct *task) -{ - struct file *exe_file = NULL; - struct mm_struct *mm; - - task_lock(task); - mm = task->mm; - if (mm) { - if (!(task->flags & PF_KTHREAD)) - exe_file = get_mm_exe_file(mm); - } - task_unlock(task); - return exe_file; -} -EXPORT_SYMBOL(get_task_exe_file); - -/** - * get_task_mm - acquire a reference to the task's mm - * - * Returns %NULL if the task has no mm. Checks PF_KTHREAD (meaning - * this kernel workthread has transiently adopted a user mm with use_mm, - * to do its AIO) is not set and if so returns a reference to it, after - * bumping up the use count. User must release the mm via mmput() - * after use. Typically used by /proc and ptrace. - */ -struct mm_struct *get_task_mm(struct task_struct *task) -{ - struct mm_struct *mm; - - task_lock(task); - mm = task->mm; - if (mm) { - if (task->flags & PF_KTHREAD) - mm = NULL; - else - atomic_inc(&mm->mm_users); - } - task_unlock(task); - return mm; -} -EXPORT_SYMBOL_GPL(get_task_mm); - -struct mm_struct *mm_access(struct task_struct *task, unsigned int mode) -{ - struct mm_struct *mm; - int err; - - err = mutex_lock_killable(&task->signal->cred_guard_mutex); - if (err) - return ERR_PTR(err); - - mm = get_task_mm(task); - if (mm && mm != current->mm && - !ptrace_may_access(task, mode)) { - mmput(mm); - mm = ERR_PTR(-EACCES); - } - mutex_unlock(&task->signal->cred_guard_mutex); - - return mm; -} - -static void complete_vfork_done(struct task_struct *tsk) -{ - struct completion *vfork; - - task_lock(tsk); - vfork = tsk->vfork_done; - if (likely(vfork)) { - tsk->vfork_done = NULL; - complete(vfork); - } - task_unlock(tsk); -} - -static int wait_for_vfork_done(struct task_struct *child, - struct completion *vfork) -{ - int killed; - - freezer_do_not_count(); - killed = wait_for_completion_killable(vfork); - freezer_count(); - - if (killed) { - task_lock(child); - child->vfork_done = NULL; - task_unlock(child); - } - - put_task_struct(child); - return killed; -} - -/* Please note the differences between mmput and mm_release. - * mmput is called whenever we stop holding onto a mm_struct, - * error success whatever. - * - * mm_release is called after a mm_struct has been removed - * from the current process. - * - * This difference is important for error handling, when we - * only half set up a mm_struct for a new process and need to restore - * the old one. Because we mmput the new mm_struct before - * restoring the old one. . . - * Eric Biederman 10 January 1998 - */ -void mm_release(struct task_struct *tsk, struct mm_struct *mm) -{ - /* Get rid of any futexes when releasing the mm */ -#ifdef CONFIG_FUTEX - if (unlikely(tsk->robust_list)) { - exit_robust_list(tsk); - tsk->robust_list = NULL; - } -#ifdef CONFIG_COMPAT - if (unlikely(tsk->compat_robust_list)) { - compat_exit_robust_list(tsk); - tsk->compat_robust_list = NULL; - } -#endif - if (unlikely(!list_empty(&tsk->pi_state_list))) - exit_pi_state_list(tsk); -#endif - - uprobe_free_utask(tsk); - - /* Get rid of any cached register state */ - deactivate_mm(tsk, mm); - - /* - * Signal userspace if we're not exiting with a core dump - * because we want to leave the value intact for debugging - * purposes. - */ - if (tsk->clear_child_tid) { - if (!(tsk->signal->flags & SIGNAL_GROUP_COREDUMP) && - atomic_read(&mm->mm_users) > 1) { - /* - * We don't check the error code - if userspace has - * not set up a proper pointer then tough luck. - */ - put_user(0, tsk->clear_child_tid); - sys_futex(tsk->clear_child_tid, FUTEX_WAKE, - 1, NULL, NULL, 0); - } - tsk->clear_child_tid = NULL; - } - - /* - * All done, finally we can wake up parent and return this mm to him. - * Also kthread_stop() uses this completion for synchronization. - */ - if (tsk->vfork_done) - complete_vfork_done(tsk); -} - -/* - * Allocate a new mm structure and copy contents from the - * mm structure of the passed in task structure. - */ -static struct mm_struct *dup_mm(struct task_struct *tsk) -{ - struct mm_struct *mm, *oldmm = current->mm; - int err; - - mm = allocate_mm(); - if (!mm) - goto fail_nomem; - - memcpy(mm, oldmm, sizeof(*mm)); - - if (!mm_init(mm, tsk)) - goto fail_nomem; - - err = dup_mmap(mm, oldmm); - if (err) - goto free_pt; - - mm->hiwater_rss = get_mm_rss(mm); - mm->hiwater_vm = mm->total_vm; - - if (mm->binfmt && !try_module_get(mm->binfmt->module)) - goto free_pt; - - return mm; - -free_pt: - /* don't put binfmt in mmput, we haven't got module yet */ - mm->binfmt = NULL; - mmput(mm); - -fail_nomem: - return NULL; -} - -static int copy_mm(unsigned long clone_flags, struct task_struct *tsk) -{ - struct mm_struct *mm, *oldmm; - int retval; - - tsk->min_flt = tsk->maj_flt = 0; - tsk->nvcsw = tsk->nivcsw = 0; -#ifdef CONFIG_DETECT_HUNG_TASK - tsk->last_switch_count = tsk->nvcsw + tsk->nivcsw; -#endif - - tsk->mm = NULL; - tsk->active_mm = NULL; - - /* - * Are we cloning a kernel thread? - * - * We need to steal a active VM for that.. - */ - oldmm = current->mm; - if (!oldmm) - return 0; - - /* initialize the new vmacache entries */ - vmacache_flush(tsk); - - if (clone_flags & CLONE_VM) { - atomic_inc(&oldmm->mm_users); - mm = oldmm; - goto good_mm; - } - - retval = -ENOMEM; - mm = dup_mm(tsk); - if (!mm) - goto fail_nomem; - -good_mm: - tsk->mm = mm; - tsk->active_mm = mm; - return 0; - -fail_nomem: - return retval; -} - -static int copy_fs(unsigned long clone_flags, struct task_struct *tsk) -{ - struct fs_struct *fs = current->fs; - if (clone_flags & CLONE_FS) { - /* tsk->fs is already what we want */ - spin_lock(&fs->lock); - if (fs->in_exec) { - spin_unlock(&fs->lock); - return -EAGAIN; - } - fs->users++; - spin_unlock(&fs->lock); - return 0; - } - tsk->fs = copy_fs_struct(fs); - if (!tsk->fs) - return -ENOMEM; - return 0; -} - -static int copy_files(unsigned long clone_flags, struct task_struct *tsk) -{ - struct files_struct *oldf, *newf; - int error = 0; - - /* - * A background process may not have any files ... - */ - oldf = current->files; - if (!oldf) - goto out; - - if (clone_flags & CLONE_FILES) { - atomic_inc(&oldf->count); - goto out; - } - - newf = dup_fd(oldf, &error); - if (!newf) - goto out; - - tsk->files = newf; - error = 0; -out: - return error; -} - -static int copy_io(unsigned long clone_flags, struct task_struct *tsk) -{ -#ifdef CONFIG_BLOCK - struct io_context *ioc = current->io_context; - struct io_context *new_ioc; - - if (!ioc) - return 0; - /* - * Share io context with parent, if CLONE_IO is set - */ - if (clone_flags & CLONE_IO) { - ioc_task_link(ioc); - tsk->io_context = ioc; - } else if (ioprio_valid(ioc->ioprio)) { - new_ioc = get_task_io_context(tsk, GFP_KERNEL, NUMA_NO_NODE); - if (unlikely(!new_ioc)) - return -ENOMEM; - - new_ioc->ioprio = ioc->ioprio; - put_io_context(new_ioc); - } -#endif - return 0; -} - -static int copy_sighand(unsigned long clone_flags, struct task_struct *tsk) -{ - struct sighand_struct *sig; - - if (clone_flags & CLONE_SIGHAND) { - atomic_inc(¤t->sighand->count); - return 0; - } - sig = kmem_cache_alloc(sighand_cachep, GFP_KERNEL); - rcu_assign_pointer(tsk->sighand, sig); - if (!sig) - return -ENOMEM; - - atomic_set(&sig->count, 1); - memcpy(sig->action, current->sighand->action, sizeof(sig->action)); - return 0; -} - -void __cleanup_sighand(struct sighand_struct *sighand) -{ - if (atomic_dec_and_test(&sighand->count)) { - signalfd_cleanup(sighand); - /* - * sighand_cachep is SLAB_DESTROY_BY_RCU so we can free it - * without an RCU grace period, see __lock_task_sighand(). - */ - kmem_cache_free(sighand_cachep, sighand); - } -} - -/* - * Initialize POSIX timer handling for a thread group. - */ -static void posix_cpu_timers_init_group(struct signal_struct *sig) -{ - unsigned long cpu_limit; - - cpu_limit = READ_ONCE(sig->rlim[RLIMIT_CPU].rlim_cur); - if (cpu_limit != RLIM_INFINITY) { - sig->cputime_expires.prof_exp = secs_to_cputime(cpu_limit); - sig->cputimer.running = true; - } - - /* The timer lists. */ - INIT_LIST_HEAD(&sig->cpu_timers[0]); - INIT_LIST_HEAD(&sig->cpu_timers[1]); - INIT_LIST_HEAD(&sig->cpu_timers[2]); -} - -static int copy_signal(unsigned long clone_flags, struct task_struct *tsk) -{ - struct signal_struct *sig; - - if (clone_flags & CLONE_THREAD) - return 0; - - sig = kmem_cache_zalloc(signal_cachep, GFP_KERNEL); - tsk->signal = sig; - if (!sig) - return -ENOMEM; - - sig->nr_threads = 1; - atomic_set(&sig->live, 1); - atomic_set(&sig->sigcnt, 1); - - /* list_add(thread_node, thread_head) without INIT_LIST_HEAD() */ - sig->thread_head = (struct list_head)LIST_HEAD_INIT(tsk->thread_node); - tsk->thread_node = (struct list_head)LIST_HEAD_INIT(sig->thread_head); - - init_waitqueue_head(&sig->wait_chldexit); - sig->curr_target = tsk; - init_sigpending(&sig->shared_pending); - INIT_LIST_HEAD(&sig->posix_timers); - seqlock_init(&sig->stats_lock); - prev_cputime_init(&sig->prev_cputime); - - hrtimer_init(&sig->real_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - sig->real_timer.function = it_real_fn; - - task_lock(current->group_leader); - memcpy(sig->rlim, current->signal->rlim, sizeof sig->rlim); - task_unlock(current->group_leader); - - posix_cpu_timers_init_group(sig); - - tty_audit_fork(sig); - sched_autogroup_fork(sig); - - sig->oom_score_adj = current->signal->oom_score_adj; - sig->oom_score_adj_min = current->signal->oom_score_adj_min; - - sig->has_child_subreaper = current->signal->has_child_subreaper || - current->signal->is_child_subreaper; - - mutex_init(&sig->cred_guard_mutex); - - return 0; -} - -static void copy_seccomp(struct task_struct *p) -{ -#ifdef CONFIG_SECCOMP - /* - * Must be called with sighand->lock held, which is common to - * all threads in the group. Holding cred_guard_mutex is not - * needed because this new task is not yet running and cannot - * be racing exec. - */ - assert_spin_locked(¤t->sighand->siglock); - - /* Ref-count the new filter user, and assign it. */ - get_seccomp_filter(current); - p->seccomp = current->seccomp; - - /* - * Explicitly enable no_new_privs here in case it got set - * between the task_struct being duplicated and holding the - * sighand lock. The seccomp state and nnp must be in sync. - */ - if (task_no_new_privs(current)) - task_set_no_new_privs(p); - - /* - * If the parent gained a seccomp mode after copying thread - * flags and between before we held the sighand lock, we have - * to manually enable the seccomp thread flag here. - */ - if (p->seccomp.mode != SECCOMP_MODE_DISABLED) - set_tsk_thread_flag(p, TIF_SECCOMP); -#endif -} - -SYSCALL_DEFINE1(set_tid_address, int __user *, tidptr) -{ - current->clear_child_tid = tidptr; - - return task_pid_vnr(current); -} - -static void rt_mutex_init_task(struct task_struct *p) -{ - raw_spin_lock_init(&p->pi_lock); -#ifdef CONFIG_RT_MUTEXES - p->pi_waiters = RB_ROOT; - p->pi_waiters_leftmost = NULL; - p->pi_blocked_on = NULL; -#endif -} - -/* - * Initialize POSIX timer handling for a single task. - */ -static void posix_cpu_timers_init(struct task_struct *tsk) -{ - tsk->cputime_expires.prof_exp = 0; - tsk->cputime_expires.virt_exp = 0; - tsk->cputime_expires.sched_exp = 0; - INIT_LIST_HEAD(&tsk->cpu_timers[0]); - INIT_LIST_HEAD(&tsk->cpu_timers[1]); - INIT_LIST_HEAD(&tsk->cpu_timers[2]); -} - -static inline void -init_task_pid(struct task_struct *task, enum pid_type type, struct pid *pid) -{ - task->pids[type].pid = pid; -} - -/* - * This creates a new process as a copy of the old one, - * but does not actually start it yet. - * - * It copies the registers, and all the appropriate - * parts of the process environment (as per the clone - * flags). The actual kick-off is left to the caller. - */ -static __latent_entropy struct task_struct *copy_process( - unsigned long clone_flags, - unsigned long stack_start, - unsigned long stack_size, - int __user *child_tidptr, - struct pid *pid, - int trace, - unsigned long tls, - int node) -{ - int retval; - struct task_struct *p; - - if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) - return ERR_PTR(-EINVAL); - - if ((clone_flags & (CLONE_NEWUSER|CLONE_FS)) == (CLONE_NEWUSER|CLONE_FS)) - return ERR_PTR(-EINVAL); - - /* - * Thread groups must share signals as well, and detached threads - * can only be started up within the thread group. - */ - if ((clone_flags & CLONE_THREAD) && !(clone_flags & CLONE_SIGHAND)) - return ERR_PTR(-EINVAL); - - /* - * Shared signal handlers imply shared VM. By way of the above, - * thread groups also imply shared VM. Blocking this case allows - * for various simplifications in other code. - */ - if ((clone_flags & CLONE_SIGHAND) && !(clone_flags & CLONE_VM)) - return ERR_PTR(-EINVAL); - - /* - * Siblings of global init remain as zombies on exit since they are - * not reaped by their parent (swapper). To solve this and to avoid - * multi-rooted process trees, prevent global and container-inits - * from creating siblings. - */ - if ((clone_flags & CLONE_PARENT) && - current->signal->flags & SIGNAL_UNKILLABLE) - return ERR_PTR(-EINVAL); - - /* - * If the new process will be in a different pid or user namespace - * do not allow it to share a thread group with the forking task. - */ - if (clone_flags & CLONE_THREAD) { - if ((clone_flags & (CLONE_NEWUSER | CLONE_NEWPID)) || - (task_active_pid_ns(current) != - current->nsproxy->pid_ns_for_children)) - return ERR_PTR(-EINVAL); - } - - retval = security_task_create(clone_flags); - if (retval) - goto fork_out; - - retval = -ENOMEM; - p = dup_task_struct(current, node); - if (!p) - goto fork_out; - - ftrace_graph_init_task(p); - - rt_mutex_init_task(p); - -#ifdef CONFIG_PROVE_LOCKING - DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled); - DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled); -#endif - retval = -EAGAIN; - if (atomic_read(&p->real_cred->user->processes) >= - task_rlimit(p, RLIMIT_NPROC)) { - if (p->real_cred->user != INIT_USER && - !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) - goto bad_fork_free; - } - current->flags &= ~PF_NPROC_EXCEEDED; - - retval = copy_creds(p, clone_flags); - if (retval < 0) - goto bad_fork_free; - - /* - * If multiple threads are within copy_process(), then this check - * triggers too late. This doesn't hurt, the check is only there - * to stop root fork bombs. - */ - retval = -EAGAIN; - if (nr_threads >= max_threads) - goto bad_fork_cleanup_count; - - delayacct_tsk_init(p); /* Must remain after dup_task_struct() */ - p->flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER); - p->flags |= PF_FORKNOEXEC; - INIT_LIST_HEAD(&p->children); - INIT_LIST_HEAD(&p->sibling); - rcu_copy_process(p); - p->vfork_done = NULL; - spin_lock_init(&p->alloc_lock); - - init_sigpending(&p->pending); - - p->utime = p->stime = p->gtime = 0; - p->utimescaled = p->stimescaled = 0; - prev_cputime_init(&p->prev_cputime); - -#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN - seqcount_init(&p->vtime_seqcount); - p->vtime_snap = 0; - p->vtime_snap_whence = VTIME_INACTIVE; -#endif - -#if defined(SPLIT_RSS_COUNTING) - memset(&p->rss_stat, 0, sizeof(p->rss_stat)); -#endif - - p->default_timer_slack_ns = current->timer_slack_ns; - - task_io_accounting_init(&p->ioac); - acct_clear_integrals(p); - - posix_cpu_timers_init(p); - - p->start_time = ktime_get_ns(); - p->real_start_time = ktime_get_boot_ns(); - p->io_context = NULL; - p->audit_context = NULL; - cgroup_fork(p); -#ifdef CONFIG_NUMA - p->mempolicy = mpol_dup(p->mempolicy); - if (IS_ERR(p->mempolicy)) { - retval = PTR_ERR(p->mempolicy); - p->mempolicy = NULL; - goto bad_fork_cleanup_threadgroup_lock; - } -#endif -#ifdef CONFIG_CPUSETS - p->cpuset_mem_spread_rotor = NUMA_NO_NODE; - p->cpuset_slab_spread_rotor = NUMA_NO_NODE; - seqcount_init(&p->mems_allowed_seq); -#endif -#ifdef CONFIG_TRACE_IRQFLAGS - p->irq_events = 0; - p->hardirqs_enabled = 0; - p->hardirq_enable_ip = 0; - p->hardirq_enable_event = 0; - p->hardirq_disable_ip = _THIS_IP_; - p->hardirq_disable_event = 0; - p->softirqs_enabled = 1; - p->softirq_enable_ip = _THIS_IP_; - p->softirq_enable_event = 0; - p->softirq_disable_ip = 0; - p->softirq_disable_event = 0; - p->hardirq_context = 0; - p->softirq_context = 0; -#endif - - p->pagefault_disabled = 0; - -#ifdef CONFIG_LOCKDEP - p->lockdep_depth = 0; /* no locks held yet */ - p->curr_chain_key = 0; - p->lockdep_recursion = 0; -#endif - -#ifdef CONFIG_DEBUG_MUTEXES - p->blocked_on = NULL; /* not blocked yet */ -#endif -#ifdef CONFIG_BCACHE - p->sequential_io = 0; - p->sequential_io_avg = 0; -#endif - - /* Perform scheduler related setup. Assign this task to a CPU. */ - retval = sched_fork(clone_flags, p); - if (retval) - goto bad_fork_cleanup_policy; - - retval = perf_event_init_task(p); - if (retval) - goto bad_fork_cleanup_policy; - retval = audit_alloc(p); - if (retval) - goto bad_fork_cleanup_perf; - /* copy all the process information */ - shm_init_task(p); - retval = copy_semundo(clone_flags, p); - if (retval) - goto bad_fork_cleanup_audit; - retval = copy_files(clone_flags, p); - if (retval) - goto bad_fork_cleanup_semundo; - retval = copy_fs(clone_flags, p); - if (retval) - goto bad_fork_cleanup_files; - retval = copy_sighand(clone_flags, p); - if (retval) - goto bad_fork_cleanup_fs; - retval = copy_signal(clone_flags, p); - if (retval) - goto bad_fork_cleanup_sighand; - retval = copy_mm(clone_flags, p); - if (retval) - goto bad_fork_cleanup_signal; - retval = copy_namespaces(clone_flags, p); - if (retval) - goto bad_fork_cleanup_mm; - retval = copy_io(clone_flags, p); - if (retval) - goto bad_fork_cleanup_namespaces; - retval = copy_thread_tls(clone_flags, stack_start, stack_size, p, tls); - if (retval) - goto bad_fork_cleanup_io; - - if (pid != &init_struct_pid) { - pid = alloc_pid(p->nsproxy->pid_ns_for_children); - if (IS_ERR(pid)) { - retval = PTR_ERR(pid); - goto bad_fork_cleanup_thread; - } - } - - p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; - /* - * Clear TID on mm_release()? - */ - p->clear_child_tid = (clone_flags & CLONE_CHILD_CLEARTID) ? child_tidptr : NULL; -#ifdef CONFIG_BLOCK - p->plug = NULL; -#endif -#ifdef CONFIG_FUTEX - p->robust_list = NULL; -#ifdef CONFIG_COMPAT - p->compat_robust_list = NULL; -#endif - INIT_LIST_HEAD(&p->pi_state_list); - p->pi_state_cache = NULL; -#endif - /* - * sigaltstack should be cleared when sharing the same VM - */ - if ((clone_flags & (CLONE_VM|CLONE_VFORK)) == CLONE_VM) - sas_ss_reset(p); - - /* - * Syscall tracing and stepping should be turned off in the - * child regardless of CLONE_PTRACE. - */ - user_disable_single_step(p); - clear_tsk_thread_flag(p, TIF_SYSCALL_TRACE); -#ifdef TIF_SYSCALL_EMU - clear_tsk_thread_flag(p, TIF_SYSCALL_EMU); -#endif - clear_all_latency_tracing(p); - - /* ok, now we should be set up.. */ - p->pid = pid_nr(pid); - if (clone_flags & CLONE_THREAD) { - p->exit_signal = -1; - p->group_leader = current->group_leader; - p->tgid = current->tgid; - } else { - if (clone_flags & CLONE_PARENT) - p->exit_signal = current->group_leader->exit_signal; - else - p->exit_signal = (clone_flags & CSIGNAL); - p->group_leader = p; - p->tgid = p->pid; - } - - p->nr_dirtied = 0; - p->nr_dirtied_pause = 128 >> (PAGE_SHIFT - 10); - p->dirty_paused_when = 0; - - p->pdeath_signal = 0; - INIT_LIST_HEAD(&p->thread_group); - p->task_works = NULL; - - threadgroup_change_begin(current); - /* - * Ensure that the cgroup subsystem policies allow the new process to be - * forked. It should be noted the the new process's css_set can be changed - * between here and cgroup_post_fork() if an organisation operation is in - * progress. - */ - retval = cgroup_can_fork(p); - if (retval) - goto bad_fork_free_pid; - - /* - * Make it visible to the rest of the system, but dont wake it up yet. - * Need tasklist lock for parent etc handling! - */ - write_lock_irq(&tasklist_lock); - - /* CLONE_PARENT re-uses the old parent */ - if (clone_flags & (CLONE_PARENT|CLONE_THREAD)) { - p->real_parent = current->real_parent; - p->parent_exec_id = current->parent_exec_id; - } else { - p->real_parent = current; - p->parent_exec_id = current->self_exec_id; - } - - spin_lock(¤t->sighand->siglock); - - /* - * Copy seccomp details explicitly here, in case they were changed - * before holding sighand lock. - */ - copy_seccomp(p); - - /* - * Process group and session signals need to be delivered to just the - * parent before the fork or both the parent and the child after the - * fork. Restart if a signal comes in before we add the new process to - * it's process group. - * A fatal signal pending means that current will exit, so the new - * thread can't slip out of an OOM kill (or normal SIGKILL). - */ - recalc_sigpending(); - if (signal_pending(current)) { - spin_unlock(¤t->sighand->siglock); - write_unlock_irq(&tasklist_lock); - retval = -ERESTARTNOINTR; - goto bad_fork_cancel_cgroup; - } - - if (likely(p->pid)) { - ptrace_init_task(p, (clone_flags & CLONE_PTRACE) || trace); - - init_task_pid(p, PIDTYPE_PID, pid); - if (thread_group_leader(p)) { - init_task_pid(p, PIDTYPE_PGID, task_pgrp(current)); - init_task_pid(p, PIDTYPE_SID, task_session(current)); - - if (is_child_reaper(pid)) { - ns_of_pid(pid)->child_reaper = p; - p->signal->flags |= SIGNAL_UNKILLABLE; - } - - p->signal->leader_pid = pid; - p->signal->tty = tty_kref_get(current->signal->tty); - list_add_tail(&p->sibling, &p->real_parent->children); - list_add_tail_rcu(&p->tasks, &init_task.tasks); - attach_pid(p, PIDTYPE_PGID); - attach_pid(p, PIDTYPE_SID); - __this_cpu_inc(process_counts); - } else { - current->signal->nr_threads++; - atomic_inc(¤t->signal->live); - atomic_inc(¤t->signal->sigcnt); - list_add_tail_rcu(&p->thread_group, - &p->group_leader->thread_group); - list_add_tail_rcu(&p->thread_node, - &p->signal->thread_head); - } - attach_pid(p, PIDTYPE_PID); - nr_threads++; - } - - total_forks++; - spin_unlock(¤t->sighand->siglock); - syscall_tracepoint_update(p); - write_unlock_irq(&tasklist_lock); - - proc_fork_connector(p); - cgroup_post_fork(p); - threadgroup_change_end(current); - perf_event_fork(p); - - trace_task_newtask(p, clone_flags); - uprobe_copy_process(p, clone_flags); - - return p; - -bad_fork_cancel_cgroup: - cgroup_cancel_fork(p); -bad_fork_free_pid: - threadgroup_change_end(current); - if (pid != &init_struct_pid) - free_pid(pid); -bad_fork_cleanup_thread: - exit_thread(p); -bad_fork_cleanup_io: - if (p->io_context) - exit_io_context(p); -bad_fork_cleanup_namespaces: - exit_task_namespaces(p); -bad_fork_cleanup_mm: - if (p->mm) - mmput(p->mm); -bad_fork_cleanup_signal: - if (!(clone_flags & CLONE_THREAD)) - free_signal_struct(p->signal); -bad_fork_cleanup_sighand: - __cleanup_sighand(p->sighand); -bad_fork_cleanup_fs: - exit_fs(p); /* blocking */ -bad_fork_cleanup_files: - exit_files(p); /* blocking */ -bad_fork_cleanup_semundo: - exit_sem(p); -bad_fork_cleanup_audit: - audit_free(p); -bad_fork_cleanup_perf: - perf_event_free_task(p); -bad_fork_cleanup_policy: -#ifdef CONFIG_NUMA - mpol_put(p->mempolicy); -bad_fork_cleanup_threadgroup_lock: -#endif - delayacct_tsk_free(p); -bad_fork_cleanup_count: - atomic_dec(&p->cred->user->processes); - exit_creds(p); -bad_fork_free: - p->state = TASK_DEAD; - put_task_stack(p); - free_task(p); -fork_out: - return ERR_PTR(retval); -} - -static inline void init_idle_pids(struct pid_link *links) -{ - enum pid_type type; - - for (type = PIDTYPE_PID; type < PIDTYPE_MAX; ++type) { - INIT_HLIST_NODE(&links[type].node); /* not really needed */ - links[type].pid = &init_struct_pid; - } -} - -struct task_struct *fork_idle(int cpu) -{ - struct task_struct *task; - task = copy_process(CLONE_VM, 0, 0, NULL, &init_struct_pid, 0, 0, - cpu_to_node(cpu)); - if (!IS_ERR(task)) { - init_idle_pids(task->pids); - init_idle(task, cpu); - } - - return task; -} - -/* - * Ok, this is the main fork-routine. - * - * It copies the process, and if successful kick-starts - * it and waits for it to finish using the VM if required. - */ -long _do_fork(unsigned long clone_flags, - unsigned long stack_start, - unsigned long stack_size, - int __user *parent_tidptr, - int __user *child_tidptr, - unsigned long tls) -{ - struct task_struct *p; - int trace = 0; - long nr; - - /* - * Determine whether and which event to report to ptracer. When - * called from kernel_thread or CLONE_UNTRACED is explicitly - * requested, no event is reported; otherwise, report if the event - * for the type of forking is enabled. - */ - if (!(clone_flags & CLONE_UNTRACED)) { - if (clone_flags & CLONE_VFORK) - trace = PTRACE_EVENT_VFORK; - else if ((clone_flags & CSIGNAL) != SIGCHLD) - trace = PTRACE_EVENT_CLONE; - else - trace = PTRACE_EVENT_FORK; - - if (likely(!ptrace_event_enabled(current, trace))) - trace = 0; - } - - p = copy_process(clone_flags, stack_start, stack_size, - child_tidptr, NULL, trace, tls, NUMA_NO_NODE); - add_latent_entropy(); - /* - * Do this prior waking up the new thread - the thread pointer - * might get invalid after that point, if the thread exits quickly. - */ - if (!IS_ERR(p)) { - struct completion vfork; - struct pid *pid; - - trace_sched_process_fork(current, p); - - pid = get_task_pid(p, PIDTYPE_PID); - nr = pid_vnr(pid); - - if (clone_flags & CLONE_PARENT_SETTID) - put_user(nr, parent_tidptr); - - if (clone_flags & CLONE_VFORK) { - p->vfork_done = &vfork; - init_completion(&vfork); - get_task_struct(p); - } - - wake_up_new_task(p); - - /* forking complete and child started to run, tell ptracer */ - if (unlikely(trace)) - ptrace_event_pid(trace, pid); - - if (clone_flags & CLONE_VFORK) { - if (!wait_for_vfork_done(p, &vfork)) - ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid); - } - - put_pid(pid); - } else { - nr = PTR_ERR(p); - } - return nr; -} - -#ifndef CONFIG_HAVE_COPY_THREAD_TLS -/* For compatibility with architectures that call do_fork directly rather than - * using the syscall entry points below. */ -long do_fork(unsigned long clone_flags, - unsigned long stack_start, - unsigned long stack_size, - int __user *parent_tidptr, - int __user *child_tidptr) -{ - return _do_fork(clone_flags, stack_start, stack_size, - parent_tidptr, child_tidptr, 0); -} -#endif - -/* - * Create a kernel thread. - */ -pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) -{ - return _do_fork(flags|CLONE_VM|CLONE_UNTRACED, (unsigned long)fn, - (unsigned long)arg, NULL, NULL, 0); -} - -#ifdef __ARCH_WANT_SYS_FORK -SYSCALL_DEFINE0(fork) -{ -#ifdef CONFIG_MMU - return _do_fork(SIGCHLD, 0, 0, NULL, NULL, 0); -#else - /* can not support in nommu mode */ - return -EINVAL; -#endif -} -#endif - -#ifdef __ARCH_WANT_SYS_VFORK -SYSCALL_DEFINE0(vfork) -{ - return _do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, - 0, NULL, NULL, 0); -} -#endif - -#ifdef __ARCH_WANT_SYS_CLONE -#ifdef CONFIG_CLONE_BACKWARDS -SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp, - int __user *, parent_tidptr, - unsigned long, tls, - int __user *, child_tidptr) -#elif defined(CONFIG_CLONE_BACKWARDS2) -SYSCALL_DEFINE5(clone, unsigned long, newsp, unsigned long, clone_flags, - int __user *, parent_tidptr, - int __user *, child_tidptr, - unsigned long, tls) -#elif defined(CONFIG_CLONE_BACKWARDS3) -SYSCALL_DEFINE6(clone, unsigned long, clone_flags, unsigned long, newsp, - int, stack_size, - int __user *, parent_tidptr, - int __user *, child_tidptr, - unsigned long, tls) -#else -SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp, - int __user *, parent_tidptr, - int __user *, child_tidptr, - unsigned long, tls) -#endif -{ - return _do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr, tls); -} -#endif - -#ifndef ARCH_MIN_MMSTRUCT_ALIGN -#define ARCH_MIN_MMSTRUCT_ALIGN 0 -#endif - -static void sighand_ctor(void *data) -{ - struct sighand_struct *sighand = data; - - spin_lock_init(&sighand->siglock); - init_waitqueue_head(&sighand->signalfd_wqh); -} - -void __init proc_caches_init(void) -{ - sighand_cachep = kmem_cache_create("sighand_cache", - sizeof(struct sighand_struct), 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_DESTROY_BY_RCU| - SLAB_NOTRACK|SLAB_ACCOUNT, sighand_ctor); - signal_cachep = kmem_cache_create("signal_cache", - sizeof(struct signal_struct), 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK|SLAB_ACCOUNT, - NULL); - files_cachep = kmem_cache_create("files_cache", - sizeof(struct files_struct), 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK|SLAB_ACCOUNT, - NULL); - fs_cachep = kmem_cache_create("fs_cache", - sizeof(struct fs_struct), 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK|SLAB_ACCOUNT, - NULL); - /* - * FIXME! The "sizeof(struct mm_struct)" currently includes the - * whole struct cpumask for the OFFSTACK case. We could change - * this to *only* allocate as much of it as required by the - * maximum number of CPU's we can ever have. The cpumask_allocation - * is at the end of the structure, exactly for that reason. - */ - mm_cachep = kmem_cache_create("mm_struct", - sizeof(struct mm_struct), ARCH_MIN_MMSTRUCT_ALIGN, - SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_NOTRACK|SLAB_ACCOUNT, - NULL); - vm_area_cachep = KMEM_CACHE(vm_area_struct, SLAB_PANIC|SLAB_ACCOUNT); - mmap_init(); - nsproxy_cache_init(); -} - -/* - * Check constraints on flags passed to the unshare system call. - */ -static int check_unshare_flags(unsigned long unshare_flags) -{ - if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND| - CLONE_VM|CLONE_FILES|CLONE_SYSVSEM| - CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET| - CLONE_NEWUSER|CLONE_NEWPID|CLONE_NEWCGROUP)) - return -EINVAL; - /* - * Not implemented, but pretend it works if there is nothing - * to unshare. Note that unsharing the address space or the - * signal handlers also need to unshare the signal queues (aka - * CLONE_THREAD). - */ - if (unshare_flags & (CLONE_THREAD | CLONE_SIGHAND | CLONE_VM)) { - if (!thread_group_empty(current)) - return -EINVAL; - } - if (unshare_flags & (CLONE_SIGHAND | CLONE_VM)) { - if (atomic_read(¤t->sighand->count) > 1) - return -EINVAL; - } - if (unshare_flags & CLONE_VM) { - if (!current_is_single_threaded()) - return -EINVAL; - } - - return 0; -} - -/* - * Unshare the filesystem structure if it is being shared - */ -static int unshare_fs(unsigned long unshare_flags, struct fs_struct **new_fsp) -{ - struct fs_struct *fs = current->fs; - - if (!(unshare_flags & CLONE_FS) || !fs) - return 0; - - /* don't need lock here; in the worst case we'll do useless copy */ - if (fs->users == 1) - return 0; - - *new_fsp = copy_fs_struct(fs); - if (!*new_fsp) - return -ENOMEM; - - return 0; -} - -/* - * Unshare file descriptor table if it is being shared - */ -static int unshare_fd(unsigned long unshare_flags, struct files_struct **new_fdp) -{ - struct files_struct *fd = current->files; - int error = 0; - - if ((unshare_flags & CLONE_FILES) && - (fd && atomic_read(&fd->count) > 1)) { - *new_fdp = dup_fd(fd, &error); - if (!*new_fdp) - return error; - } - - return 0; -} - -/* - * unshare allows a process to 'unshare' part of the process - * context which was originally shared using clone. copy_* - * functions used by do_fork() cannot be used here directly - * because they modify an inactive task_struct that is being - * constructed. Here we are modifying the current, active, - * task_struct. - */ -SYSCALL_DEFINE1(unshare, unsigned long, unshare_flags) -{ - struct fs_struct *fs, *new_fs = NULL; - struct files_struct *fd, *new_fd = NULL; - struct cred *new_cred = NULL; - struct nsproxy *new_nsproxy = NULL; - int do_sysvsem = 0; - int err; - - /* - * If unsharing a user namespace must also unshare the thread group - * and unshare the filesystem root and working directories. - */ - if (unshare_flags & CLONE_NEWUSER) - unshare_flags |= CLONE_THREAD | CLONE_FS; - /* - * If unsharing vm, must also unshare signal handlers. - */ - if (unshare_flags & CLONE_VM) - unshare_flags |= CLONE_SIGHAND; - /* - * If unsharing a signal handlers, must also unshare the signal queues. - */ - if (unshare_flags & CLONE_SIGHAND) - unshare_flags |= CLONE_THREAD; - /* - * If unsharing namespace, must also unshare filesystem information. - */ - if (unshare_flags & CLONE_NEWNS) - unshare_flags |= CLONE_FS; - - err = check_unshare_flags(unshare_flags); - if (err) - goto bad_unshare_out; - /* - * CLONE_NEWIPC must also detach from the undolist: after switching - * to a new ipc namespace, the semaphore arrays from the old - * namespace are unreachable. - */ - if (unshare_flags & (CLONE_NEWIPC|CLONE_SYSVSEM)) - do_sysvsem = 1; - err = unshare_fs(unshare_flags, &new_fs); - if (err) - goto bad_unshare_out; - err = unshare_fd(unshare_flags, &new_fd); - if (err) - goto bad_unshare_cleanup_fs; - err = unshare_userns(unshare_flags, &new_cred); - if (err) - goto bad_unshare_cleanup_fd; - err = unshare_nsproxy_namespaces(unshare_flags, &new_nsproxy, - new_cred, new_fs); - if (err) - goto bad_unshare_cleanup_cred; - - if (new_fs || new_fd || do_sysvsem || new_cred || new_nsproxy) { - if (do_sysvsem) { - /* - * CLONE_SYSVSEM is equivalent to sys_exit(). - */ - exit_sem(current); - } - if (unshare_flags & CLONE_NEWIPC) { - /* Orphan segments in old ns (see sem above). */ - exit_shm(current); - shm_init_task(current); - } - - if (new_nsproxy) - switch_task_namespaces(current, new_nsproxy); - - task_lock(current); - - if (new_fs) { - fs = current->fs; - spin_lock(&fs->lock); - current->fs = new_fs; - if (--fs->users) - new_fs = NULL; - else - new_fs = fs; - spin_unlock(&fs->lock); - } - - if (new_fd) { - fd = current->files; - current->files = new_fd; - new_fd = fd; - } - - task_unlock(current); - - if (new_cred) { - /* Install the new user namespace */ - commit_creds(new_cred); - new_cred = NULL; - } - } - -bad_unshare_cleanup_cred: - if (new_cred) - put_cred(new_cred); -bad_unshare_cleanup_fd: - if (new_fd) - put_files_struct(new_fd); - -bad_unshare_cleanup_fs: - if (new_fs) - free_fs_struct(new_fs); - -bad_unshare_out: - return err; -} - -/* - * Helper to unshare the files of the current task. - * We don't want to expose copy_files internals to - * the exec layer of the kernel. - */ - -int unshare_files(struct files_struct **displaced) -{ - struct task_struct *task = current; - struct files_struct *copy = NULL; - int error; - - error = unshare_fd(CLONE_FILES, ©); - if (error || !copy) { - *displaced = NULL; - return error; - } - *displaced = task->files; - task_lock(task); - task->files = copy; - task_unlock(task); - return 0; -} - -int sysctl_max_threads(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - struct ctl_table t; - int ret; - int threads = max_threads; - int min = MIN_THREADS; - int max = MAX_THREADS; - - t = *table; - t.data = &threads; - t.extra1 = &min; - t.extra2 = &max; - - ret = proc_dointvec_minmax(&t, write, buffer, lenp, ppos); - if (ret || !write) - return ret; - - set_max_threads(threads); - - return 0; -} diff --git a/src/linux/kernel/gcov/Kconfig b/src/linux/kernel/gcov/Kconfig deleted file mode 100644 index 1276aab..0000000 --- a/src/linux/kernel/gcov/Kconfig +++ /dev/null @@ -1,83 +0,0 @@ -menu "GCOV-based kernel profiling" - -config GCOV_KERNEL - bool "Enable gcov-based kernel profiling" - depends on DEBUG_FS - select CONSTRUCTORS if !UML - default n - ---help--- - This option enables gcov-based code profiling (e.g. for code coverage - measurements). - - If unsure, say N. - - Additionally specify CONFIG_GCOV_PROFILE_ALL=y to get profiling data - for the entire kernel. To enable profiling for specific files or - directories, add a line similar to the following to the respective - Makefile: - - For a single file (e.g. main.o): - GCOV_PROFILE_main.o := y - - For all files in one directory: - GCOV_PROFILE := y - - To exclude files from being profiled even when CONFIG_GCOV_PROFILE_ALL - is specified, use: - - GCOV_PROFILE_main.o := n - and: - GCOV_PROFILE := n - - Note that the debugfs filesystem has to be mounted to access - profiling data. - -config ARCH_HAS_GCOV_PROFILE_ALL - def_bool n - -config GCOV_PROFILE_ALL - bool "Profile entire Kernel" - depends on !COMPILE_TEST - depends on GCOV_KERNEL - depends on ARCH_HAS_GCOV_PROFILE_ALL - default n - ---help--- - This options activates profiling for the entire kernel. - - If unsure, say N. - - Note that a kernel compiled with profiling flags will be significantly - larger and run slower. Also be sure to exclude files from profiling - which are not linked to the kernel image to prevent linker errors. - -choice - prompt "Specify GCOV format" - depends on GCOV_KERNEL - default GCOV_FORMAT_AUTODETECT - ---help--- - The gcov format is usually determined by the GCC version, but there are - exceptions where format changes are integrated in lower-version GCCs. - In such a case use this option to adjust the format used in the kernel - accordingly. - - If unsure, choose "Autodetect". - -config GCOV_FORMAT_AUTODETECT - bool "Autodetect" - ---help--- - Select this option to use the format that corresponds to your GCC - version. - -config GCOV_FORMAT_3_4 - bool "GCC 3.4 format" - ---help--- - Select this option to use the format defined by GCC 3.4. - -config GCOV_FORMAT_4_7 - bool "GCC 4.7 format" - ---help--- - Select this option to use the format defined by GCC 4.7. - -endchoice - -endmenu diff --git a/src/linux/kernel/groups.c b/src/linux/kernel/groups.c deleted file mode 100644 index 2fcadd6..0000000 --- a/src/linux/kernel/groups.c +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Supplementary group IDs - */ -#include -#include -#include -#include -#include -#include -#include -#include - -struct group_info *groups_alloc(int gidsetsize) -{ - struct group_info *gi; - unsigned int len; - - len = sizeof(struct group_info) + sizeof(kgid_t) * gidsetsize; - gi = kmalloc(len, GFP_KERNEL_ACCOUNT|__GFP_NOWARN|__GFP_NORETRY); - if (!gi) - gi = __vmalloc(len, GFP_KERNEL_ACCOUNT|__GFP_HIGHMEM, PAGE_KERNEL); - if (!gi) - return NULL; - - atomic_set(&gi->usage, 1); - gi->ngroups = gidsetsize; - return gi; -} - -EXPORT_SYMBOL(groups_alloc); - -void groups_free(struct group_info *group_info) -{ - kvfree(group_info); -} - -EXPORT_SYMBOL(groups_free); - -/* export the group_info to a user-space array */ -static int groups_to_user(gid_t __user *grouplist, - const struct group_info *group_info) -{ - struct user_namespace *user_ns = current_user_ns(); - int i; - unsigned int count = group_info->ngroups; - - for (i = 0; i < count; i++) { - gid_t gid; - gid = from_kgid_munged(user_ns, group_info->gid[i]); - if (put_user(gid, grouplist+i)) - return -EFAULT; - } - return 0; -} - -/* fill a group_info from a user-space array - it must be allocated already */ -static int groups_from_user(struct group_info *group_info, - gid_t __user *grouplist) -{ - struct user_namespace *user_ns = current_user_ns(); - int i; - unsigned int count = group_info->ngroups; - - for (i = 0; i < count; i++) { - gid_t gid; - kgid_t kgid; - if (get_user(gid, grouplist+i)) - return -EFAULT; - - kgid = make_kgid(user_ns, gid); - if (!gid_valid(kgid)) - return -EINVAL; - - group_info->gid[i] = kgid; - } - return 0; -} - -/* a simple Shell sort */ -static void groups_sort(struct group_info *group_info) -{ - int base, max, stride; - int gidsetsize = group_info->ngroups; - - for (stride = 1; stride < gidsetsize; stride = 3 * stride + 1) - ; /* nothing */ - stride /= 3; - - while (stride) { - max = gidsetsize - stride; - for (base = 0; base < max; base++) { - int left = base; - int right = left + stride; - kgid_t tmp = group_info->gid[right]; - - while (left >= 0 && gid_gt(group_info->gid[left], tmp)) { - group_info->gid[right] = group_info->gid[left]; - right = left; - left -= stride; - } - group_info->gid[right] = tmp; - } - stride /= 3; - } -} - -/* a simple bsearch */ -int groups_search(const struct group_info *group_info, kgid_t grp) -{ - unsigned int left, right; - - if (!group_info) - return 0; - - left = 0; - right = group_info->ngroups; - while (left < right) { - unsigned int mid = (left+right)/2; - if (gid_gt(grp, group_info->gid[mid])) - left = mid + 1; - else if (gid_lt(grp, group_info->gid[mid])) - right = mid; - else - return 1; - } - return 0; -} - -/** - * set_groups - Change a group subscription in a set of credentials - * @new: The newly prepared set of credentials to alter - * @group_info: The group list to install - */ -void set_groups(struct cred *new, struct group_info *group_info) -{ - put_group_info(new->group_info); - groups_sort(group_info); - get_group_info(group_info); - new->group_info = group_info; -} - -EXPORT_SYMBOL(set_groups); - -/** - * set_current_groups - Change current's group subscription - * @group_info: The group list to impose - * - * Validate a group subscription and, if valid, impose it upon current's task - * security record. - */ -int set_current_groups(struct group_info *group_info) -{ - struct cred *new; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - - set_groups(new, group_info); - return commit_creds(new); -} - -EXPORT_SYMBOL(set_current_groups); - -SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t __user *, grouplist) -{ - const struct cred *cred = current_cred(); - int i; - - if (gidsetsize < 0) - return -EINVAL; - - /* no need to grab task_lock here; it cannot change */ - i = cred->group_info->ngroups; - if (gidsetsize) { - if (i > gidsetsize) { - i = -EINVAL; - goto out; - } - if (groups_to_user(grouplist, cred->group_info)) { - i = -EFAULT; - goto out; - } - } -out: - return i; -} - -bool may_setgroups(void) -{ - struct user_namespace *user_ns = current_user_ns(); - - return ns_capable(user_ns, CAP_SETGID) && - userns_may_setgroups(user_ns); -} - -/* - * SMP: Our groups are copy-on-write. We can set them safely - * without another task interfering. - */ - -SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist) -{ - struct group_info *group_info; - int retval; - - if (!may_setgroups()) - return -EPERM; - if ((unsigned)gidsetsize > NGROUPS_MAX) - return -EINVAL; - - group_info = groups_alloc(gidsetsize); - if (!group_info) - return -ENOMEM; - retval = groups_from_user(group_info, grouplist); - if (retval) { - put_group_info(group_info); - return retval; - } - - retval = set_current_groups(group_info); - put_group_info(group_info); - - return retval; -} - -/* - * Check whether we're fsgid/egid or in the supplemental group.. - */ -int in_group_p(kgid_t grp) -{ - const struct cred *cred = current_cred(); - int retval = 1; - - if (!gid_eq(grp, cred->fsgid)) - retval = groups_search(cred->group_info, grp); - return retval; -} - -EXPORT_SYMBOL(in_group_p); - -int in_egroup_p(kgid_t grp) -{ - const struct cred *cred = current_cred(); - int retval = 1; - - if (!gid_eq(grp, cred->egid)) - retval = groups_search(cred->group_info, grp); - return retval; -} - -EXPORT_SYMBOL(in_egroup_p); diff --git a/src/linux/kernel/irq/Kconfig b/src/linux/kernel/irq/Kconfig deleted file mode 100644 index 3bbfd6a..0000000 --- a/src/linux/kernel/irq/Kconfig +++ /dev/null @@ -1,111 +0,0 @@ -menu "IRQ subsystem" -# Options selectable by the architecture code - -# Make sparse irq Kconfig switch below available -config MAY_HAVE_SPARSE_IRQ - bool - -# Legacy support, required for itanic -config GENERIC_IRQ_LEGACY - bool - -# Enable the generic irq autoprobe mechanism -config GENERIC_IRQ_PROBE - bool - -# Use the generic /proc/interrupts implementation -config GENERIC_IRQ_SHOW - bool - -# Print level/edge extra information -config GENERIC_IRQ_SHOW_LEVEL - bool - -# Facility to allocate a hardware interrupt. This is legacy support -# and should not be used in new code. Use irq domains instead. -config GENERIC_IRQ_LEGACY_ALLOC_HWIRQ - bool - -# Support for delayed migration from interrupt context -config GENERIC_PENDING_IRQ - bool - -# Support for generic irq migrating off cpu before the cpu is offline. -config GENERIC_IRQ_MIGRATION - bool - -# Alpha specific irq affinity mechanism -config AUTO_IRQ_AFFINITY - bool - -# Tasklet based software resend for pending interrupts on enable_irq() -config HARDIRQS_SW_RESEND - bool - -# Preflow handler support for fasteoi (sparc64) -config IRQ_PREFLOW_FASTEOI - bool - -# Edge style eoi based handler (cell) -config IRQ_EDGE_EOI_HANDLER - bool - -# Generic configurable interrupt chip implementation -config GENERIC_IRQ_CHIP - bool - select IRQ_DOMAIN - -# Generic irq_domain hw <--> linux irq number translation -config IRQ_DOMAIN - bool - -# Support for hierarchical irq domains -config IRQ_DOMAIN_HIERARCHY - bool - select IRQ_DOMAIN - -# Generic IRQ IPI support -config GENERIC_IRQ_IPI - bool - -# Generic MSI interrupt support -config GENERIC_MSI_IRQ - bool - -# Generic MSI hierarchical interrupt domain support -config GENERIC_MSI_IRQ_DOMAIN - bool - select IRQ_DOMAIN_HIERARCHY - select GENERIC_MSI_IRQ - -config HANDLE_DOMAIN_IRQ - bool - -config IRQ_DOMAIN_DEBUG - bool "Expose hardware/virtual IRQ mapping via debugfs" - depends on IRQ_DOMAIN && DEBUG_FS - help - This option will show the mapping relationship between hardware irq - numbers and Linux irq numbers. The mapping is exposed via debugfs - in the file "irq_domain_mapping". - - If you don't know what this means you don't need it. - -# Support forced irq threading -config IRQ_FORCED_THREADING - bool - -config SPARSE_IRQ - bool "Support sparse irq numbering" if MAY_HAVE_SPARSE_IRQ - ---help--- - - Sparse irq numbering is useful for distro kernels that want - to define a high CONFIG_NR_CPUS value but still want to have - low kernel memory footprint on smaller machines. - - ( Sparse irqs can also be beneficial on NUMA boxes, as they spread - out the interrupt descriptors in a more NUMA-friendly way. ) - - If you don't know what to do here, say N. - -endmenu diff --git a/src/linux/kernel/irq/Makefile b/src/linux/kernel/irq/Makefile deleted file mode 100644 index 1d3ee31..0000000 --- a/src/linux/kernel/irq/Makefile +++ /dev/null @@ -1,12 +0,0 @@ - -obj-y := irqdesc.o handle.o manage.o spurious.o resend.o chip.o dummychip.o devres.o -obj-$(CONFIG_GENERIC_IRQ_CHIP) += generic-chip.o -obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o -obj-$(CONFIG_IRQ_DOMAIN) += irqdomain.o -obj-$(CONFIG_PROC_FS) += proc.o -obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o -obj-$(CONFIG_GENERIC_IRQ_MIGRATION) += cpuhotplug.o -obj-$(CONFIG_PM_SLEEP) += pm.o -obj-$(CONFIG_GENERIC_MSI_IRQ) += msi.o -obj-$(CONFIG_GENERIC_IRQ_IPI) += ipi.o -obj-$(CONFIG_SMP) += affinity.o diff --git a/src/linux/kernel/irq/chip.c b/src/linux/kernel/irq/chip.c deleted file mode 100644 index be3c34e..0000000 --- a/src/linux/kernel/irq/chip.c +++ /dev/null @@ -1,1202 +0,0 @@ -/* - * linux/kernel/irq/chip.c - * - * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar - * Copyright (C) 2005-2006, Thomas Gleixner, Russell King - * - * This file contains the core interrupt handling code, for irq-chip - * based architectures. - * - * Detailed information is available in Documentation/DocBook/genericirq - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "internals.h" - -static irqreturn_t bad_chained_irq(int irq, void *dev_id) -{ - WARN_ONCE(1, "Chained irq %d should not call an action\n", irq); - return IRQ_NONE; -} - -/* - * Chained handlers should never call action on their IRQ. This default - * action will emit warning if such thing happens. - */ -struct irqaction chained_action = { - .handler = bad_chained_irq, -}; - -/** - * irq_set_chip - set the irq chip for an irq - * @irq: irq number - * @chip: pointer to irq chip description structure - */ -int irq_set_chip(unsigned int irq, struct irq_chip *chip) -{ - unsigned long flags; - struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); - - if (!desc) - return -EINVAL; - - if (!chip) - chip = &no_irq_chip; - - desc->irq_data.chip = chip; - irq_put_desc_unlock(desc, flags); - /* - * For !CONFIG_SPARSE_IRQ make the irq show up in - * allocated_irqs. - */ - irq_mark_irq(irq); - return 0; -} -EXPORT_SYMBOL(irq_set_chip); - -/** - * irq_set_type - set the irq trigger type for an irq - * @irq: irq number - * @type: IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h - */ -int irq_set_irq_type(unsigned int irq, unsigned int type) -{ - unsigned long flags; - struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL); - int ret = 0; - - if (!desc) - return -EINVAL; - - ret = __irq_set_trigger(desc, type); - irq_put_desc_busunlock(desc, flags); - return ret; -} -EXPORT_SYMBOL(irq_set_irq_type); - -/** - * irq_set_handler_data - set irq handler data for an irq - * @irq: Interrupt number - * @data: Pointer to interrupt specific data - * - * Set the hardware irq controller data for an irq - */ -int irq_set_handler_data(unsigned int irq, void *data) -{ - unsigned long flags; - struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); - - if (!desc) - return -EINVAL; - desc->irq_common_data.handler_data = data; - irq_put_desc_unlock(desc, flags); - return 0; -} -EXPORT_SYMBOL(irq_set_handler_data); - -/** - * irq_set_msi_desc_off - set MSI descriptor data for an irq at offset - * @irq_base: Interrupt number base - * @irq_offset: Interrupt number offset - * @entry: Pointer to MSI descriptor data - * - * Set the MSI descriptor entry for an irq at offset - */ -int irq_set_msi_desc_off(unsigned int irq_base, unsigned int irq_offset, - struct msi_desc *entry) -{ - unsigned long flags; - struct irq_desc *desc = irq_get_desc_lock(irq_base + irq_offset, &flags, IRQ_GET_DESC_CHECK_GLOBAL); - - if (!desc) - return -EINVAL; - desc->irq_common_data.msi_desc = entry; - if (entry && !irq_offset) - entry->irq = irq_base; - irq_put_desc_unlock(desc, flags); - return 0; -} - -/** - * irq_set_msi_desc - set MSI descriptor data for an irq - * @irq: Interrupt number - * @entry: Pointer to MSI descriptor data - * - * Set the MSI descriptor entry for an irq - */ -int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry) -{ - return irq_set_msi_desc_off(irq, 0, entry); -} - -/** - * irq_set_chip_data - set irq chip data for an irq - * @irq: Interrupt number - * @data: Pointer to chip specific data - * - * Set the hardware irq chip data for an irq - */ -int irq_set_chip_data(unsigned int irq, void *data) -{ - unsigned long flags; - struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); - - if (!desc) - return -EINVAL; - desc->irq_data.chip_data = data; - irq_put_desc_unlock(desc, flags); - return 0; -} -EXPORT_SYMBOL(irq_set_chip_data); - -struct irq_data *irq_get_irq_data(unsigned int irq) -{ - struct irq_desc *desc = irq_to_desc(irq); - - return desc ? &desc->irq_data : NULL; -} -EXPORT_SYMBOL_GPL(irq_get_irq_data); - -static void irq_state_clr_disabled(struct irq_desc *desc) -{ - irqd_clear(&desc->irq_data, IRQD_IRQ_DISABLED); -} - -static void irq_state_set_disabled(struct irq_desc *desc) -{ - irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED); -} - -static void irq_state_clr_masked(struct irq_desc *desc) -{ - irqd_clear(&desc->irq_data, IRQD_IRQ_MASKED); -} - -static void irq_state_set_masked(struct irq_desc *desc) -{ - irqd_set(&desc->irq_data, IRQD_IRQ_MASKED); -} - -int irq_startup(struct irq_desc *desc, bool resend) -{ - int ret = 0; - - irq_state_clr_disabled(desc); - desc->depth = 0; - - irq_domain_activate_irq(&desc->irq_data); - if (desc->irq_data.chip->irq_startup) { - ret = desc->irq_data.chip->irq_startup(&desc->irq_data); - irq_state_clr_masked(desc); - } else { - irq_enable(desc); - } - if (resend) - check_irq_resend(desc); - return ret; -} - -void irq_shutdown(struct irq_desc *desc) -{ - irq_state_set_disabled(desc); - desc->depth = 1; - if (desc->irq_data.chip->irq_shutdown) - desc->irq_data.chip->irq_shutdown(&desc->irq_data); - else if (desc->irq_data.chip->irq_disable) - desc->irq_data.chip->irq_disable(&desc->irq_data); - else - desc->irq_data.chip->irq_mask(&desc->irq_data); - irq_domain_deactivate_irq(&desc->irq_data); - irq_state_set_masked(desc); -} - -void irq_enable(struct irq_desc *desc) -{ - irq_state_clr_disabled(desc); - if (desc->irq_data.chip->irq_enable) - desc->irq_data.chip->irq_enable(&desc->irq_data); - else - desc->irq_data.chip->irq_unmask(&desc->irq_data); - irq_state_clr_masked(desc); -} - -/** - * irq_disable - Mark interrupt disabled - * @desc: irq descriptor which should be disabled - * - * If the chip does not implement the irq_disable callback, we - * use a lazy disable approach. That means we mark the interrupt - * disabled, but leave the hardware unmasked. That's an - * optimization because we avoid the hardware access for the - * common case where no interrupt happens after we marked it - * disabled. If an interrupt happens, then the interrupt flow - * handler masks the line at the hardware level and marks it - * pending. - * - * If the interrupt chip does not implement the irq_disable callback, - * a driver can disable the lazy approach for a particular irq line by - * calling 'irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY)'. This can - * be used for devices which cannot disable the interrupt at the - * device level under certain circumstances and have to use - * disable_irq[_nosync] instead. - */ -void irq_disable(struct irq_desc *desc) -{ - irq_state_set_disabled(desc); - if (desc->irq_data.chip->irq_disable) { - desc->irq_data.chip->irq_disable(&desc->irq_data); - irq_state_set_masked(desc); - } else if (irq_settings_disable_unlazy(desc)) { - mask_irq(desc); - } -} - -void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu) -{ - if (desc->irq_data.chip->irq_enable) - desc->irq_data.chip->irq_enable(&desc->irq_data); - else - desc->irq_data.chip->irq_unmask(&desc->irq_data); - cpumask_set_cpu(cpu, desc->percpu_enabled); -} - -void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu) -{ - if (desc->irq_data.chip->irq_disable) - desc->irq_data.chip->irq_disable(&desc->irq_data); - else - desc->irq_data.chip->irq_mask(&desc->irq_data); - cpumask_clear_cpu(cpu, desc->percpu_enabled); -} - -static inline void mask_ack_irq(struct irq_desc *desc) -{ - if (desc->irq_data.chip->irq_mask_ack) - desc->irq_data.chip->irq_mask_ack(&desc->irq_data); - else { - desc->irq_data.chip->irq_mask(&desc->irq_data); - if (desc->irq_data.chip->irq_ack) - desc->irq_data.chip->irq_ack(&desc->irq_data); - } - irq_state_set_masked(desc); -} - -void mask_irq(struct irq_desc *desc) -{ - if (desc->irq_data.chip->irq_mask) { - desc->irq_data.chip->irq_mask(&desc->irq_data); - irq_state_set_masked(desc); - } -} - -void unmask_irq(struct irq_desc *desc) -{ - if (desc->irq_data.chip->irq_unmask) { - desc->irq_data.chip->irq_unmask(&desc->irq_data); - irq_state_clr_masked(desc); - } -} - -void unmask_threaded_irq(struct irq_desc *desc) -{ - struct irq_chip *chip = desc->irq_data.chip; - - if (chip->flags & IRQCHIP_EOI_THREADED) - chip->irq_eoi(&desc->irq_data); - - if (chip->irq_unmask) { - chip->irq_unmask(&desc->irq_data); - irq_state_clr_masked(desc); - } -} - -/* - * handle_nested_irq - Handle a nested irq from a irq thread - * @irq: the interrupt number - * - * Handle interrupts which are nested into a threaded interrupt - * handler. The handler function is called inside the calling - * threads context. - */ -void handle_nested_irq(unsigned int irq) -{ - struct irq_desc *desc = irq_to_desc(irq); - struct irqaction *action; - irqreturn_t action_ret; - - might_sleep(); - - raw_spin_lock_irq(&desc->lock); - - desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); - - action = desc->action; - if (unlikely(!action || irqd_irq_disabled(&desc->irq_data))) { - desc->istate |= IRQS_PENDING; - goto out_unlock; - } - - kstat_incr_irqs_this_cpu(desc); - irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS); - raw_spin_unlock_irq(&desc->lock); - - action_ret = action->thread_fn(action->irq, action->dev_id); - if (!noirqdebug) - note_interrupt(desc, action_ret); - - raw_spin_lock_irq(&desc->lock); - irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS); - -out_unlock: - raw_spin_unlock_irq(&desc->lock); -} -EXPORT_SYMBOL_GPL(handle_nested_irq); - -static bool irq_check_poll(struct irq_desc *desc) -{ - if (!(desc->istate & IRQS_POLL_INPROGRESS)) - return false; - return irq_wait_for_poll(desc); -} - -static bool irq_may_run(struct irq_desc *desc) -{ - unsigned int mask = IRQD_IRQ_INPROGRESS | IRQD_WAKEUP_ARMED; - - /* - * If the interrupt is not in progress and is not an armed - * wakeup interrupt, proceed. - */ - if (!irqd_has_set(&desc->irq_data, mask)) - return true; - - /* - * If the interrupt is an armed wakeup source, mark it pending - * and suspended, disable it and notify the pm core about the - * event. - */ - if (irq_pm_check_wakeup(desc)) - return false; - - /* - * Handle a potential concurrent poll on a different core. - */ - return irq_check_poll(desc); -} - -/** - * handle_simple_irq - Simple and software-decoded IRQs. - * @desc: the interrupt description structure for this irq - * - * Simple interrupts are either sent from a demultiplexing interrupt - * handler or come from hardware, where no interrupt hardware control - * is necessary. - * - * Note: The caller is expected to handle the ack, clear, mask and - * unmask issues if necessary. - */ -void handle_simple_irq(struct irq_desc *desc) -{ - raw_spin_lock(&desc->lock); - - if (!irq_may_run(desc)) - goto out_unlock; - - desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); - - if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) { - desc->istate |= IRQS_PENDING; - goto out_unlock; - } - - kstat_incr_irqs_this_cpu(desc); - handle_irq_event(desc); - -out_unlock: - raw_spin_unlock(&desc->lock); -} -EXPORT_SYMBOL_GPL(handle_simple_irq); - -/** - * handle_untracked_irq - Simple and software-decoded IRQs. - * @desc: the interrupt description structure for this irq - * - * Untracked interrupts are sent from a demultiplexing interrupt - * handler when the demultiplexer does not know which device it its - * multiplexed irq domain generated the interrupt. IRQ's handled - * through here are not subjected to stats tracking, randomness, or - * spurious interrupt detection. - * - * Note: Like handle_simple_irq, the caller is expected to handle - * the ack, clear, mask and unmask issues if necessary. - */ -void handle_untracked_irq(struct irq_desc *desc) -{ - unsigned int flags = 0; - - raw_spin_lock(&desc->lock); - - if (!irq_may_run(desc)) - goto out_unlock; - - desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); - - if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) { - desc->istate |= IRQS_PENDING; - goto out_unlock; - } - - desc->istate &= ~IRQS_PENDING; - irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS); - raw_spin_unlock(&desc->lock); - - __handle_irq_event_percpu(desc, &flags); - - raw_spin_lock(&desc->lock); - irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS); - -out_unlock: - raw_spin_unlock(&desc->lock); -} -EXPORT_SYMBOL_GPL(handle_untracked_irq); - -/* - * Called unconditionally from handle_level_irq() and only for oneshot - * interrupts from handle_fasteoi_irq() - */ -static void cond_unmask_irq(struct irq_desc *desc) -{ - /* - * We need to unmask in the following cases: - * - Standard level irq (IRQF_ONESHOT is not set) - * - Oneshot irq which did not wake the thread (caused by a - * spurious interrupt or a primary handler handling it - * completely). - */ - if (!irqd_irq_disabled(&desc->irq_data) && - irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) - unmask_irq(desc); -} - -/** - * handle_level_irq - Level type irq handler - * @desc: the interrupt description structure for this irq - * - * Level type interrupts are active as long as the hardware line has - * the active level. This may require to mask the interrupt and unmask - * it after the associated handler has acknowledged the device, so the - * interrupt line is back to inactive. - */ -void handle_level_irq(struct irq_desc *desc) -{ - raw_spin_lock(&desc->lock); - mask_ack_irq(desc); - - if (!irq_may_run(desc)) - goto out_unlock; - - desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); - - /* - * If its disabled or no action available - * keep it masked and get out of here - */ - if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) { - desc->istate |= IRQS_PENDING; - goto out_unlock; - } - - kstat_incr_irqs_this_cpu(desc); - handle_irq_event(desc); - - cond_unmask_irq(desc); - -out_unlock: - raw_spin_unlock(&desc->lock); -} -EXPORT_SYMBOL_GPL(handle_level_irq); - -#ifdef CONFIG_IRQ_PREFLOW_FASTEOI -static inline void preflow_handler(struct irq_desc *desc) -{ - if (desc->preflow_handler) - desc->preflow_handler(&desc->irq_data); -} -#else -static inline void preflow_handler(struct irq_desc *desc) { } -#endif - -static void cond_unmask_eoi_irq(struct irq_desc *desc, struct irq_chip *chip) -{ - if (!(desc->istate & IRQS_ONESHOT)) { - chip->irq_eoi(&desc->irq_data); - return; - } - /* - * We need to unmask in the following cases: - * - Oneshot irq which did not wake the thread (caused by a - * spurious interrupt or a primary handler handling it - * completely). - */ - if (!irqd_irq_disabled(&desc->irq_data) && - irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot) { - chip->irq_eoi(&desc->irq_data); - unmask_irq(desc); - } else if (!(chip->flags & IRQCHIP_EOI_THREADED)) { - chip->irq_eoi(&desc->irq_data); - } -} - -/** - * handle_fasteoi_irq - irq handler for transparent controllers - * @desc: the interrupt description structure for this irq - * - * Only a single callback will be issued to the chip: an ->eoi() - * call when the interrupt has been serviced. This enables support - * for modern forms of interrupt handlers, which handle the flow - * details in hardware, transparently. - */ -void handle_fasteoi_irq(struct irq_desc *desc) -{ - struct irq_chip *chip = desc->irq_data.chip; - - raw_spin_lock(&desc->lock); - - if (!irq_may_run(desc)) - goto out; - - desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); - - /* - * If its disabled or no action available - * then mask it and get out of here: - */ - if (unlikely(!desc->action || irqd_irq_disabled(&desc->irq_data))) { - desc->istate |= IRQS_PENDING; - mask_irq(desc); - goto out; - } - - kstat_incr_irqs_this_cpu(desc); - if (desc->istate & IRQS_ONESHOT) - mask_irq(desc); - - preflow_handler(desc); - handle_irq_event(desc); - - cond_unmask_eoi_irq(desc, chip); - - raw_spin_unlock(&desc->lock); - return; -out: - if (!(chip->flags & IRQCHIP_EOI_IF_HANDLED)) - chip->irq_eoi(&desc->irq_data); - raw_spin_unlock(&desc->lock); -} -EXPORT_SYMBOL_GPL(handle_fasteoi_irq); - -/** - * handle_edge_irq - edge type IRQ handler - * @desc: the interrupt description structure for this irq - * - * Interrupt occures on the falling and/or rising edge of a hardware - * signal. The occurrence is latched into the irq controller hardware - * and must be acked in order to be reenabled. After the ack another - * interrupt can happen on the same source even before the first one - * is handled by the associated event handler. If this happens it - * might be necessary to disable (mask) the interrupt depending on the - * controller hardware. This requires to reenable the interrupt inside - * of the loop which handles the interrupts which have arrived while - * the handler was running. If all pending interrupts are handled, the - * loop is left. - */ -void handle_edge_irq(struct irq_desc *desc) -{ - raw_spin_lock(&desc->lock); - - desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); - - if (!irq_may_run(desc)) { - desc->istate |= IRQS_PENDING; - mask_ack_irq(desc); - goto out_unlock; - } - - /* - * If its disabled or no action available then mask it and get - * out of here. - */ - if (irqd_irq_disabled(&desc->irq_data) || !desc->action) { - desc->istate |= IRQS_PENDING; - mask_ack_irq(desc); - goto out_unlock; - } - - kstat_incr_irqs_this_cpu(desc); - - /* Start handling the irq */ - desc->irq_data.chip->irq_ack(&desc->irq_data); - - do { - if (unlikely(!desc->action)) { - mask_irq(desc); - goto out_unlock; - } - - /* - * When another irq arrived while we were handling - * one, we could have masked the irq. - * Renable it, if it was not disabled in meantime. - */ - if (unlikely(desc->istate & IRQS_PENDING)) { - if (!irqd_irq_disabled(&desc->irq_data) && - irqd_irq_masked(&desc->irq_data)) - unmask_irq(desc); - } - - handle_irq_event(desc); - - } while ((desc->istate & IRQS_PENDING) && - !irqd_irq_disabled(&desc->irq_data)); - -out_unlock: - raw_spin_unlock(&desc->lock); -} -EXPORT_SYMBOL(handle_edge_irq); - -#ifdef CONFIG_IRQ_EDGE_EOI_HANDLER -/** - * handle_edge_eoi_irq - edge eoi type IRQ handler - * @desc: the interrupt description structure for this irq - * - * Similar as the above handle_edge_irq, but using eoi and w/o the - * mask/unmask logic. - */ -void handle_edge_eoi_irq(struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - - raw_spin_lock(&desc->lock); - - desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING); - - if (!irq_may_run(desc)) { - desc->istate |= IRQS_PENDING; - goto out_eoi; - } - - /* - * If its disabled or no action available then mask it and get - * out of here. - */ - if (irqd_irq_disabled(&desc->irq_data) || !desc->action) { - desc->istate |= IRQS_PENDING; - goto out_eoi; - } - - kstat_incr_irqs_this_cpu(desc); - - do { - if (unlikely(!desc->action)) - goto out_eoi; - - handle_irq_event(desc); - - } while ((desc->istate & IRQS_PENDING) && - !irqd_irq_disabled(&desc->irq_data)); - -out_eoi: - chip->irq_eoi(&desc->irq_data); - raw_spin_unlock(&desc->lock); -} -#endif - -/** - * handle_percpu_irq - Per CPU local irq handler - * @desc: the interrupt description structure for this irq - * - * Per CPU interrupts on SMP machines without locking requirements - */ -void handle_percpu_irq(struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - - kstat_incr_irqs_this_cpu(desc); - - if (chip->irq_ack) - chip->irq_ack(&desc->irq_data); - - handle_irq_event_percpu(desc); - - if (chip->irq_eoi) - chip->irq_eoi(&desc->irq_data); -} - -/** - * handle_percpu_devid_irq - Per CPU local irq handler with per cpu dev ids - * @desc: the interrupt description structure for this irq - * - * Per CPU interrupts on SMP machines without locking requirements. Same as - * handle_percpu_irq() above but with the following extras: - * - * action->percpu_dev_id is a pointer to percpu variables which - * contain the real device id for the cpu on which this handler is - * called - */ -void handle_percpu_devid_irq(struct irq_desc *desc) -{ - struct irq_chip *chip = irq_desc_get_chip(desc); - struct irqaction *action = desc->action; - unsigned int irq = irq_desc_get_irq(desc); - irqreturn_t res; - - kstat_incr_irqs_this_cpu(desc); - - if (chip->irq_ack) - chip->irq_ack(&desc->irq_data); - - if (likely(action)) { - trace_irq_handler_entry(irq, action); - res = action->handler(irq, raw_cpu_ptr(action->percpu_dev_id)); - trace_irq_handler_exit(irq, action, res); - } else { - unsigned int cpu = smp_processor_id(); - bool enabled = cpumask_test_cpu(cpu, desc->percpu_enabled); - - if (enabled) - irq_percpu_disable(desc, cpu); - - pr_err_once("Spurious%s percpu IRQ%u on CPU%u\n", - enabled ? " and unmasked" : "", irq, cpu); - } - - if (chip->irq_eoi) - chip->irq_eoi(&desc->irq_data); -} - -static void -__irq_do_set_handler(struct irq_desc *desc, irq_flow_handler_t handle, - int is_chained, const char *name) -{ - if (!handle) { - handle = handle_bad_irq; - } else { - struct irq_data *irq_data = &desc->irq_data; -#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY - /* - * With hierarchical domains we might run into a - * situation where the outermost chip is not yet set - * up, but the inner chips are there. Instead of - * bailing we install the handler, but obviously we - * cannot enable/startup the interrupt at this point. - */ - while (irq_data) { - if (irq_data->chip != &no_irq_chip) - break; - /* - * Bail out if the outer chip is not set up - * and the interrrupt supposed to be started - * right away. - */ - if (WARN_ON(is_chained)) - return; - /* Try the parent */ - irq_data = irq_data->parent_data; - } -#endif - if (WARN_ON(!irq_data || irq_data->chip == &no_irq_chip)) - return; - } - - /* Uninstall? */ - if (handle == handle_bad_irq) { - if (desc->irq_data.chip != &no_irq_chip) - mask_ack_irq(desc); - irq_state_set_disabled(desc); - if (is_chained) - desc->action = NULL; - desc->depth = 1; - } - desc->handle_irq = handle; - desc->name = name; - - if (handle != handle_bad_irq && is_chained) { - unsigned int type = irqd_get_trigger_type(&desc->irq_data); - - /* - * We're about to start this interrupt immediately, - * hence the need to set the trigger configuration. - * But the .set_type callback may have overridden the - * flow handler, ignoring that we're dealing with a - * chained interrupt. Reset it immediately because we - * do know better. - */ - if (type != IRQ_TYPE_NONE) { - __irq_set_trigger(desc, type); - desc->handle_irq = handle; - } - - irq_settings_set_noprobe(desc); - irq_settings_set_norequest(desc); - irq_settings_set_nothread(desc); - desc->action = &chained_action; - irq_startup(desc, true); - } -} - -void -__irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained, - const char *name) -{ - unsigned long flags; - struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0); - - if (!desc) - return; - - __irq_do_set_handler(desc, handle, is_chained, name); - irq_put_desc_busunlock(desc, flags); -} -EXPORT_SYMBOL_GPL(__irq_set_handler); - -void -irq_set_chained_handler_and_data(unsigned int irq, irq_flow_handler_t handle, - void *data) -{ - unsigned long flags; - struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, 0); - - if (!desc) - return; - - __irq_do_set_handler(desc, handle, 1, NULL); - desc->irq_common_data.handler_data = data; - - irq_put_desc_busunlock(desc, flags); -} -EXPORT_SYMBOL_GPL(irq_set_chained_handler_and_data); - -void -irq_set_chip_and_handler_name(unsigned int irq, struct irq_chip *chip, - irq_flow_handler_t handle, const char *name) -{ - irq_set_chip(irq, chip); - __irq_set_handler(irq, handle, 0, name); -} -EXPORT_SYMBOL_GPL(irq_set_chip_and_handler_name); - -void irq_modify_status(unsigned int irq, unsigned long clr, unsigned long set) -{ - unsigned long flags; - struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); - - if (!desc) - return; - irq_settings_clr_and_set(desc, clr, set); - - irqd_clear(&desc->irq_data, IRQD_NO_BALANCING | IRQD_PER_CPU | - IRQD_TRIGGER_MASK | IRQD_LEVEL | IRQD_MOVE_PCNTXT); - if (irq_settings_has_no_balance_set(desc)) - irqd_set(&desc->irq_data, IRQD_NO_BALANCING); - if (irq_settings_is_per_cpu(desc)) - irqd_set(&desc->irq_data, IRQD_PER_CPU); - if (irq_settings_can_move_pcntxt(desc)) - irqd_set(&desc->irq_data, IRQD_MOVE_PCNTXT); - if (irq_settings_is_level(desc)) - irqd_set(&desc->irq_data, IRQD_LEVEL); - - irqd_set(&desc->irq_data, irq_settings_get_trigger_mask(desc)); - - irq_put_desc_unlock(desc, flags); -} -EXPORT_SYMBOL_GPL(irq_modify_status); - -/** - * irq_cpu_online - Invoke all irq_cpu_online functions. - * - * Iterate through all irqs and invoke the chip.irq_cpu_online() - * for each. - */ -void irq_cpu_online(void) -{ - struct irq_desc *desc; - struct irq_chip *chip; - unsigned long flags; - unsigned int irq; - - for_each_active_irq(irq) { - desc = irq_to_desc(irq); - if (!desc) - continue; - - raw_spin_lock_irqsave(&desc->lock, flags); - - chip = irq_data_get_irq_chip(&desc->irq_data); - if (chip && chip->irq_cpu_online && - (!(chip->flags & IRQCHIP_ONOFFLINE_ENABLED) || - !irqd_irq_disabled(&desc->irq_data))) - chip->irq_cpu_online(&desc->irq_data); - - raw_spin_unlock_irqrestore(&desc->lock, flags); - } -} - -/** - * irq_cpu_offline - Invoke all irq_cpu_offline functions. - * - * Iterate through all irqs and invoke the chip.irq_cpu_offline() - * for each. - */ -void irq_cpu_offline(void) -{ - struct irq_desc *desc; - struct irq_chip *chip; - unsigned long flags; - unsigned int irq; - - for_each_active_irq(irq) { - desc = irq_to_desc(irq); - if (!desc) - continue; - - raw_spin_lock_irqsave(&desc->lock, flags); - - chip = irq_data_get_irq_chip(&desc->irq_data); - if (chip && chip->irq_cpu_offline && - (!(chip->flags & IRQCHIP_ONOFFLINE_ENABLED) || - !irqd_irq_disabled(&desc->irq_data))) - chip->irq_cpu_offline(&desc->irq_data); - - raw_spin_unlock_irqrestore(&desc->lock, flags); - } -} - -#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY -/** - * irq_chip_enable_parent - Enable the parent interrupt (defaults to unmask if - * NULL) - * @data: Pointer to interrupt specific data - */ -void irq_chip_enable_parent(struct irq_data *data) -{ - data = data->parent_data; - if (data->chip->irq_enable) - data->chip->irq_enable(data); - else - data->chip->irq_unmask(data); -} - -/** - * irq_chip_disable_parent - Disable the parent interrupt (defaults to mask if - * NULL) - * @data: Pointer to interrupt specific data - */ -void irq_chip_disable_parent(struct irq_data *data) -{ - data = data->parent_data; - if (data->chip->irq_disable) - data->chip->irq_disable(data); - else - data->chip->irq_mask(data); -} - -/** - * irq_chip_ack_parent - Acknowledge the parent interrupt - * @data: Pointer to interrupt specific data - */ -void irq_chip_ack_parent(struct irq_data *data) -{ - data = data->parent_data; - data->chip->irq_ack(data); -} -EXPORT_SYMBOL_GPL(irq_chip_ack_parent); - -/** - * irq_chip_mask_parent - Mask the parent interrupt - * @data: Pointer to interrupt specific data - */ -void irq_chip_mask_parent(struct irq_data *data) -{ - data = data->parent_data; - data->chip->irq_mask(data); -} -EXPORT_SYMBOL_GPL(irq_chip_mask_parent); - -/** - * irq_chip_unmask_parent - Unmask the parent interrupt - * @data: Pointer to interrupt specific data - */ -void irq_chip_unmask_parent(struct irq_data *data) -{ - data = data->parent_data; - data->chip->irq_unmask(data); -} -EXPORT_SYMBOL_GPL(irq_chip_unmask_parent); - -/** - * irq_chip_eoi_parent - Invoke EOI on the parent interrupt - * @data: Pointer to interrupt specific data - */ -void irq_chip_eoi_parent(struct irq_data *data) -{ - data = data->parent_data; - data->chip->irq_eoi(data); -} -EXPORT_SYMBOL_GPL(irq_chip_eoi_parent); - -/** - * irq_chip_set_affinity_parent - Set affinity on the parent interrupt - * @data: Pointer to interrupt specific data - * @dest: The affinity mask to set - * @force: Flag to enforce setting (disable online checks) - * - * Conditinal, as the underlying parent chip might not implement it. - */ -int irq_chip_set_affinity_parent(struct irq_data *data, - const struct cpumask *dest, bool force) -{ - data = data->parent_data; - if (data->chip->irq_set_affinity) - return data->chip->irq_set_affinity(data, dest, force); - - return -ENOSYS; -} - -/** - * irq_chip_set_type_parent - Set IRQ type on the parent interrupt - * @data: Pointer to interrupt specific data - * @type: IRQ_TYPE_{LEVEL,EDGE}_* value - see include/linux/irq.h - * - * Conditional, as the underlying parent chip might not implement it. - */ -int irq_chip_set_type_parent(struct irq_data *data, unsigned int type) -{ - data = data->parent_data; - - if (data->chip->irq_set_type) - return data->chip->irq_set_type(data, type); - - return -ENOSYS; -} -EXPORT_SYMBOL_GPL(irq_chip_set_type_parent); - -/** - * irq_chip_retrigger_hierarchy - Retrigger an interrupt in hardware - * @data: Pointer to interrupt specific data - * - * Iterate through the domain hierarchy of the interrupt and check - * whether a hw retrigger function exists. If yes, invoke it. - */ -int irq_chip_retrigger_hierarchy(struct irq_data *data) -{ - for (data = data->parent_data; data; data = data->parent_data) - if (data->chip && data->chip->irq_retrigger) - return data->chip->irq_retrigger(data); - - return 0; -} - -/** - * irq_chip_set_vcpu_affinity_parent - Set vcpu affinity on the parent interrupt - * @data: Pointer to interrupt specific data - * @vcpu_info: The vcpu affinity information - */ -int irq_chip_set_vcpu_affinity_parent(struct irq_data *data, void *vcpu_info) -{ - data = data->parent_data; - if (data->chip->irq_set_vcpu_affinity) - return data->chip->irq_set_vcpu_affinity(data, vcpu_info); - - return -ENOSYS; -} - -/** - * irq_chip_set_wake_parent - Set/reset wake-up on the parent interrupt - * @data: Pointer to interrupt specific data - * @on: Whether to set or reset the wake-up capability of this irq - * - * Conditional, as the underlying parent chip might not implement it. - */ -int irq_chip_set_wake_parent(struct irq_data *data, unsigned int on) -{ - data = data->parent_data; - if (data->chip->irq_set_wake) - return data->chip->irq_set_wake(data, on); - - return -ENOSYS; -} -#endif - -/** - * irq_chip_compose_msi_msg - Componse msi message for a irq chip - * @data: Pointer to interrupt specific data - * @msg: Pointer to the MSI message - * - * For hierarchical domains we find the first chip in the hierarchy - * which implements the irq_compose_msi_msg callback. For non - * hierarchical we use the top level chip. - */ -int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg) -{ - struct irq_data *pos = NULL; - -#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY - for (; data; data = data->parent_data) -#endif - if (data->chip && data->chip->irq_compose_msi_msg) - pos = data; - if (!pos) - return -ENOSYS; - - pos->chip->irq_compose_msi_msg(pos, msg); - - return 0; -} - -/** - * irq_chip_pm_get - Enable power for an IRQ chip - * @data: Pointer to interrupt specific data - * - * Enable the power to the IRQ chip referenced by the interrupt data - * structure. - */ -int irq_chip_pm_get(struct irq_data *data) -{ - int retval; - - if (IS_ENABLED(CONFIG_PM) && data->chip->parent_device) { - retval = pm_runtime_get_sync(data->chip->parent_device); - if (retval < 0) { - pm_runtime_put_noidle(data->chip->parent_device); - return retval; - } - } - - return 0; -} - -/** - * irq_chip_pm_put - Disable power for an IRQ chip - * @data: Pointer to interrupt specific data - * - * Disable the power to the IRQ chip referenced by the interrupt data - * structure, belongs. Note that power will only be disabled, once this - * function has been called for all IRQs that have called irq_chip_pm_get(). - */ -int irq_chip_pm_put(struct irq_data *data) -{ - int retval = 0; - - if (IS_ENABLED(CONFIG_PM) && data->chip->parent_device) - retval = pm_runtime_put(data->chip->parent_device); - - return (retval < 0) ? retval : 0; -} diff --git a/src/linux/kernel/irq/debug.h b/src/linux/kernel/irq/debug.h deleted file mode 100644 index e75e29e..0000000 --- a/src/linux/kernel/irq/debug.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Debugging printout: - */ - -#include - -#define ___P(f) if (desc->status_use_accessors & f) printk("%14s set\n", #f) -#define ___PS(f) if (desc->istate & f) printk("%14s set\n", #f) -/* FIXME */ -#define ___PD(f) do { } while (0) - -static inline void print_irq_desc(unsigned int irq, struct irq_desc *desc) -{ - printk("irq %d, desc: %p, depth: %d, count: %d, unhandled: %d\n", - irq, desc, desc->depth, desc->irq_count, desc->irqs_unhandled); - printk("->handle_irq(): %p, ", desc->handle_irq); - print_symbol("%s\n", (unsigned long)desc->handle_irq); - printk("->irq_data.chip(): %p, ", desc->irq_data.chip); - print_symbol("%s\n", (unsigned long)desc->irq_data.chip); - printk("->action(): %p\n", desc->action); - if (desc->action) { - printk("->action->handler(): %p, ", desc->action->handler); - print_symbol("%s\n", (unsigned long)desc->action->handler); - } - - ___P(IRQ_LEVEL); - ___P(IRQ_PER_CPU); - ___P(IRQ_NOPROBE); - ___P(IRQ_NOREQUEST); - ___P(IRQ_NOTHREAD); - ___P(IRQ_NOAUTOEN); - - ___PS(IRQS_AUTODETECT); - ___PS(IRQS_REPLAY); - ___PS(IRQS_WAITING); - ___PS(IRQS_PENDING); - - ___PD(IRQS_INPROGRESS); - ___PD(IRQS_DISABLED); - ___PD(IRQS_MASKED); -} - -#undef ___P -#undef ___PS -#undef ___PD diff --git a/src/linux/kernel/irq/devres.c b/src/linux/kernel/irq/devres.c deleted file mode 100644 index 74d90a7..0000000 --- a/src/linux/kernel/irq/devres.c +++ /dev/null @@ -1,139 +0,0 @@ -#include -#include -#include -#include - -/* - * Device resource management aware IRQ request/free implementation. - */ -struct irq_devres { - unsigned int irq; - void *dev_id; -}; - -static void devm_irq_release(struct device *dev, void *res) -{ - struct irq_devres *this = res; - - free_irq(this->irq, this->dev_id); -} - -static int devm_irq_match(struct device *dev, void *res, void *data) -{ - struct irq_devres *this = res, *match = data; - - return this->irq == match->irq && this->dev_id == match->dev_id; -} - -/** - * devm_request_threaded_irq - allocate an interrupt line for a managed device - * @dev: device to request interrupt for - * @irq: Interrupt line to allocate - * @handler: Function to be called when the IRQ occurs - * @thread_fn: function to be called in a threaded interrupt context. NULL - * for devices which handle everything in @handler - * @irqflags: Interrupt type flags - * @devname: An ascii name for the claiming device - * @dev_id: A cookie passed back to the handler function - * - * Except for the extra @dev argument, this function takes the - * same arguments and performs the same function as - * request_threaded_irq(). IRQs requested with this function will be - * automatically freed on driver detach. - * - * If an IRQ allocated with this function needs to be freed - * separately, devm_free_irq() must be used. - */ -int devm_request_threaded_irq(struct device *dev, unsigned int irq, - irq_handler_t handler, irq_handler_t thread_fn, - unsigned long irqflags, const char *devname, - void *dev_id) -{ - struct irq_devres *dr; - int rc; - - dr = devres_alloc(devm_irq_release, sizeof(struct irq_devres), - GFP_KERNEL); - if (!dr) - return -ENOMEM; - - rc = request_threaded_irq(irq, handler, thread_fn, irqflags, devname, - dev_id); - if (rc) { - devres_free(dr); - return rc; - } - - dr->irq = irq; - dr->dev_id = dev_id; - devres_add(dev, dr); - - return 0; -} -EXPORT_SYMBOL(devm_request_threaded_irq); - -/** - * devm_request_any_context_irq - allocate an interrupt line for a managed device - * @dev: device to request interrupt for - * @irq: Interrupt line to allocate - * @handler: Function to be called when the IRQ occurs - * @thread_fn: function to be called in a threaded interrupt context. NULL - * for devices which handle everything in @handler - * @irqflags: Interrupt type flags - * @devname: An ascii name for the claiming device - * @dev_id: A cookie passed back to the handler function - * - * Except for the extra @dev argument, this function takes the - * same arguments and performs the same function as - * request_any_context_irq(). IRQs requested with this function will be - * automatically freed on driver detach. - * - * If an IRQ allocated with this function needs to be freed - * separately, devm_free_irq() must be used. - */ -int devm_request_any_context_irq(struct device *dev, unsigned int irq, - irq_handler_t handler, unsigned long irqflags, - const char *devname, void *dev_id) -{ - struct irq_devres *dr; - int rc; - - dr = devres_alloc(devm_irq_release, sizeof(struct irq_devres), - GFP_KERNEL); - if (!dr) - return -ENOMEM; - - rc = request_any_context_irq(irq, handler, irqflags, devname, dev_id); - if (rc < 0) { - devres_free(dr); - return rc; - } - - dr->irq = irq; - dr->dev_id = dev_id; - devres_add(dev, dr); - - return rc; -} -EXPORT_SYMBOL(devm_request_any_context_irq); - -/** - * devm_free_irq - free an interrupt - * @dev: device to free interrupt for - * @irq: Interrupt line to free - * @dev_id: Device identity to free - * - * Except for the extra @dev argument, this function takes the - * same arguments and performs the same function as free_irq(). - * This function instead of free_irq() should be used to manually - * free IRQs allocated with devm_request_irq(). - */ -void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id) -{ - struct irq_devres match_data = { irq, dev_id }; - - WARN_ON(devres_destroy(dev, devm_irq_release, devm_irq_match, - &match_data)); - free_irq(irq, dev_id); -} -EXPORT_SYMBOL(devm_free_irq); diff --git a/src/linux/kernel/irq/dummychip.c b/src/linux/kernel/irq/dummychip.c deleted file mode 100644 index 326a67f..0000000 --- a/src/linux/kernel/irq/dummychip.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar - * Copyright (C) 2005-2006, Thomas Gleixner, Russell King - * - * This file contains the dummy interrupt chip implementation - */ -#include -#include -#include - -#include "internals.h" - -/* - * What should we do if we get a hw irq event on an illegal vector? - * Each architecture has to answer this themself. - */ -static void ack_bad(struct irq_data *data) -{ - struct irq_desc *desc = irq_data_to_desc(data); - - print_irq_desc(data->irq, desc); - ack_bad_irq(data->irq); -} - -/* - * NOP functions - */ -static void noop(struct irq_data *data) { } - -static unsigned int noop_ret(struct irq_data *data) -{ - return 0; -} - -/* - * Generic no controller implementation - */ -struct irq_chip no_irq_chip = { - .name = "none", - .irq_startup = noop_ret, - .irq_shutdown = noop, - .irq_enable = noop, - .irq_disable = noop, - .irq_ack = ack_bad, - .flags = IRQCHIP_SKIP_SET_WAKE, -}; - -/* - * Generic dummy implementation which can be used for - * real dumb interrupt sources - */ -struct irq_chip dummy_irq_chip = { - .name = "dummy", - .irq_startup = noop_ret, - .irq_shutdown = noop, - .irq_enable = noop, - .irq_disable = noop, - .irq_ack = noop, - .irq_mask = noop, - .irq_unmask = noop, - .flags = IRQCHIP_SKIP_SET_WAKE, -}; -EXPORT_SYMBOL_GPL(dummy_irq_chip); diff --git a/src/linux/kernel/irq/handle.c b/src/linux/kernel/irq/handle.c deleted file mode 100644 index d3f2490..0000000 --- a/src/linux/kernel/irq/handle.c +++ /dev/null @@ -1,207 +0,0 @@ -/* - * linux/kernel/irq/handle.c - * - * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar - * Copyright (C) 2005-2006, Thomas Gleixner, Russell King - * - * This file contains the core interrupt handling code. - * - * Detailed information is available in Documentation/DocBook/genericirq - * - */ - -#include -#include -#include -#include -#include - -#include - -#include "internals.h" - -/** - * handle_bad_irq - handle spurious and unhandled irqs - * @desc: description of the interrupt - * - * Handles spurious and unhandled IRQ's. It also prints a debugmessage. - */ -void handle_bad_irq(struct irq_desc *desc) -{ - unsigned int irq = irq_desc_get_irq(desc); - - print_irq_desc(irq, desc); - kstat_incr_irqs_this_cpu(desc); - ack_bad_irq(irq); -} -EXPORT_SYMBOL_GPL(handle_bad_irq); - -/* - * Special, empty irq handler: - */ -irqreturn_t no_action(int cpl, void *dev_id) -{ - return IRQ_NONE; -} -EXPORT_SYMBOL_GPL(no_action); - -static void warn_no_thread(unsigned int irq, struct irqaction *action) -{ - if (test_and_set_bit(IRQTF_WARNED, &action->thread_flags)) - return; - - printk(KERN_WARNING "IRQ %d device %s returned IRQ_WAKE_THREAD " - "but no thread function available.", irq, action->name); -} - -void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action) -{ - /* - * In case the thread crashed and was killed we just pretend that - * we handled the interrupt. The hardirq handler has disabled the - * device interrupt, so no irq storm is lurking. - */ - if (action->thread->flags & PF_EXITING) - return; - - /* - * Wake up the handler thread for this action. If the - * RUNTHREAD bit is already set, nothing to do. - */ - if (test_and_set_bit(IRQTF_RUNTHREAD, &action->thread_flags)) - return; - - /* - * It's safe to OR the mask lockless here. We have only two - * places which write to threads_oneshot: This code and the - * irq thread. - * - * This code is the hard irq context and can never run on two - * cpus in parallel. If it ever does we have more serious - * problems than this bitmask. - * - * The irq threads of this irq which clear their "running" bit - * in threads_oneshot are serialized via desc->lock against - * each other and they are serialized against this code by - * IRQS_INPROGRESS. - * - * Hard irq handler: - * - * spin_lock(desc->lock); - * desc->state |= IRQS_INPROGRESS; - * spin_unlock(desc->lock); - * set_bit(IRQTF_RUNTHREAD, &action->thread_flags); - * desc->threads_oneshot |= mask; - * spin_lock(desc->lock); - * desc->state &= ~IRQS_INPROGRESS; - * spin_unlock(desc->lock); - * - * irq thread: - * - * again: - * spin_lock(desc->lock); - * if (desc->state & IRQS_INPROGRESS) { - * spin_unlock(desc->lock); - * while(desc->state & IRQS_INPROGRESS) - * cpu_relax(); - * goto again; - * } - * if (!test_bit(IRQTF_RUNTHREAD, &action->thread_flags)) - * desc->threads_oneshot &= ~mask; - * spin_unlock(desc->lock); - * - * So either the thread waits for us to clear IRQS_INPROGRESS - * or we are waiting in the flow handler for desc->lock to be - * released before we reach this point. The thread also checks - * IRQTF_RUNTHREAD under desc->lock. If set it leaves - * threads_oneshot untouched and runs the thread another time. - */ - desc->threads_oneshot |= action->thread_mask; - - /* - * We increment the threads_active counter in case we wake up - * the irq thread. The irq thread decrements the counter when - * it returns from the handler or in the exit path and wakes - * up waiters which are stuck in synchronize_irq() when the - * active count becomes zero. synchronize_irq() is serialized - * against this code (hard irq handler) via IRQS_INPROGRESS - * like the finalize_oneshot() code. See comment above. - */ - atomic_inc(&desc->threads_active); - - wake_up_process(action->thread); -} - -irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags) -{ - irqreturn_t retval = IRQ_NONE; - unsigned int irq = desc->irq_data.irq; - struct irqaction *action; - - for_each_action_of_desc(desc, action) { - irqreturn_t res; - - trace_irq_handler_entry(irq, action); - res = action->handler(irq, action->dev_id); - trace_irq_handler_exit(irq, action, res); - - if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pF enabled interrupts\n", - irq, action->handler)) - local_irq_disable(); - - switch (res) { - case IRQ_WAKE_THREAD: - /* - * Catch drivers which return WAKE_THREAD but - * did not set up a thread function - */ - if (unlikely(!action->thread_fn)) { - warn_no_thread(irq, action); - break; - } - - __irq_wake_thread(desc, action); - - /* Fall through to add to randomness */ - case IRQ_HANDLED: - *flags |= action->flags; - break; - - default: - break; - } - - retval |= res; - } - - return retval; -} - -irqreturn_t handle_irq_event_percpu(struct irq_desc *desc) -{ - irqreturn_t retval; - unsigned int flags = 0; - - retval = __handle_irq_event_percpu(desc, &flags); - - add_interrupt_randomness(desc->irq_data.irq, flags); - - if (!noirqdebug) - note_interrupt(desc, retval); - return retval; -} - -irqreturn_t handle_irq_event(struct irq_desc *desc) -{ - irqreturn_t ret; - - desc->istate &= ~IRQS_PENDING; - irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS); - raw_spin_unlock(&desc->lock); - - ret = handle_irq_event_percpu(desc); - - raw_spin_lock(&desc->lock); - irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS); - return ret; -} diff --git a/src/linux/kernel/irq/internals.h b/src/linux/kernel/irq/internals.h deleted file mode 100644 index bc226e7..0000000 --- a/src/linux/kernel/irq/internals.h +++ /dev/null @@ -1,228 +0,0 @@ -/* - * IRQ subsystem internal functions and variables: - * - * Do not ever include this file from anything else than - * kernel/irq/. Do not even think about using any information outside - * of this file for your non core code. - */ -#include -#include -#include - -#ifdef CONFIG_SPARSE_IRQ -# define IRQ_BITMAP_BITS (NR_IRQS + 8196) -#else -# define IRQ_BITMAP_BITS NR_IRQS -#endif - -#define istate core_internal_state__do_not_mess_with_it - -extern bool noirqdebug; - -extern struct irqaction chained_action; - -/* - * Bits used by threaded handlers: - * IRQTF_RUNTHREAD - signals that the interrupt handler thread should run - * IRQTF_WARNED - warning "IRQ_WAKE_THREAD w/o thread_fn" has been printed - * IRQTF_AFFINITY - irq thread is requested to adjust affinity - * IRQTF_FORCED_THREAD - irq action is force threaded - */ -enum { - IRQTF_RUNTHREAD, - IRQTF_WARNED, - IRQTF_AFFINITY, - IRQTF_FORCED_THREAD, -}; - -/* - * Bit masks for desc->core_internal_state__do_not_mess_with_it - * - * IRQS_AUTODETECT - autodetection in progress - * IRQS_SPURIOUS_DISABLED - was disabled due to spurious interrupt - * detection - * IRQS_POLL_INPROGRESS - polling in progress - * IRQS_ONESHOT - irq is not unmasked in primary handler - * IRQS_REPLAY - irq is replayed - * IRQS_WAITING - irq is waiting - * IRQS_PENDING - irq is pending and replayed later - * IRQS_SUSPENDED - irq is suspended - */ -enum { - IRQS_AUTODETECT = 0x00000001, - IRQS_SPURIOUS_DISABLED = 0x00000002, - IRQS_POLL_INPROGRESS = 0x00000008, - IRQS_ONESHOT = 0x00000020, - IRQS_REPLAY = 0x00000040, - IRQS_WAITING = 0x00000080, - IRQS_PENDING = 0x00000200, - IRQS_SUSPENDED = 0x00000800, -}; - -#include "debug.h" -#include "settings.h" - -extern int __irq_set_trigger(struct irq_desc *desc, unsigned long flags); -extern void __disable_irq(struct irq_desc *desc); -extern void __enable_irq(struct irq_desc *desc); - -extern int irq_startup(struct irq_desc *desc, bool resend); -extern void irq_shutdown(struct irq_desc *desc); -extern void irq_enable(struct irq_desc *desc); -extern void irq_disable(struct irq_desc *desc); -extern void irq_percpu_enable(struct irq_desc *desc, unsigned int cpu); -extern void irq_percpu_disable(struct irq_desc *desc, unsigned int cpu); -extern void mask_irq(struct irq_desc *desc); -extern void unmask_irq(struct irq_desc *desc); -extern void unmask_threaded_irq(struct irq_desc *desc); - -#ifdef CONFIG_SPARSE_IRQ -static inline void irq_mark_irq(unsigned int irq) { } -#else -extern void irq_mark_irq(unsigned int irq); -#endif - -extern void init_kstat_irqs(struct irq_desc *desc, int node, int nr); - -irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags); -irqreturn_t handle_irq_event_percpu(struct irq_desc *desc); -irqreturn_t handle_irq_event(struct irq_desc *desc); - -/* Resending of interrupts :*/ -void check_irq_resend(struct irq_desc *desc); -bool irq_wait_for_poll(struct irq_desc *desc); -void __irq_wake_thread(struct irq_desc *desc, struct irqaction *action); - -#ifdef CONFIG_PROC_FS -extern void register_irq_proc(unsigned int irq, struct irq_desc *desc); -extern void unregister_irq_proc(unsigned int irq, struct irq_desc *desc); -extern void register_handler_proc(unsigned int irq, struct irqaction *action); -extern void unregister_handler_proc(unsigned int irq, struct irqaction *action); -#else -static inline void register_irq_proc(unsigned int irq, struct irq_desc *desc) { } -static inline void unregister_irq_proc(unsigned int irq, struct irq_desc *desc) { } -static inline void register_handler_proc(unsigned int irq, - struct irqaction *action) { } -static inline void unregister_handler_proc(unsigned int irq, - struct irqaction *action) { } -#endif - -extern bool irq_can_set_affinity_usr(unsigned int irq); - -extern int irq_select_affinity_usr(unsigned int irq, struct cpumask *mask); - -extern void irq_set_thread_affinity(struct irq_desc *desc); - -extern int irq_do_set_affinity(struct irq_data *data, - const struct cpumask *dest, bool force); - -/* Inline functions for support of irq chips on slow busses */ -static inline void chip_bus_lock(struct irq_desc *desc) -{ - if (unlikely(desc->irq_data.chip->irq_bus_lock)) - desc->irq_data.chip->irq_bus_lock(&desc->irq_data); -} - -static inline void chip_bus_sync_unlock(struct irq_desc *desc) -{ - if (unlikely(desc->irq_data.chip->irq_bus_sync_unlock)) - desc->irq_data.chip->irq_bus_sync_unlock(&desc->irq_data); -} - -#define _IRQ_DESC_CHECK (1 << 0) -#define _IRQ_DESC_PERCPU (1 << 1) - -#define IRQ_GET_DESC_CHECK_GLOBAL (_IRQ_DESC_CHECK) -#define IRQ_GET_DESC_CHECK_PERCPU (_IRQ_DESC_CHECK | _IRQ_DESC_PERCPU) - -#define for_each_action_of_desc(desc, act) \ - for (act = desc->act; act; act = act->next) - -struct irq_desc * -__irq_get_desc_lock(unsigned int irq, unsigned long *flags, bool bus, - unsigned int check); -void __irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags, bool bus); - -static inline struct irq_desc * -irq_get_desc_buslock(unsigned int irq, unsigned long *flags, unsigned int check) -{ - return __irq_get_desc_lock(irq, flags, true, check); -} - -static inline void -irq_put_desc_busunlock(struct irq_desc *desc, unsigned long flags) -{ - __irq_put_desc_unlock(desc, flags, true); -} - -static inline struct irq_desc * -irq_get_desc_lock(unsigned int irq, unsigned long *flags, unsigned int check) -{ - return __irq_get_desc_lock(irq, flags, false, check); -} - -static inline void -irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags) -{ - __irq_put_desc_unlock(desc, flags, false); -} - -#define __irqd_to_state(d) ACCESS_PRIVATE((d)->common, state_use_accessors) - -/* - * Manipulation functions for irq_data.state - */ -static inline void irqd_set_move_pending(struct irq_data *d) -{ - __irqd_to_state(d) |= IRQD_SETAFFINITY_PENDING; -} - -static inline void irqd_clr_move_pending(struct irq_data *d) -{ - __irqd_to_state(d) &= ~IRQD_SETAFFINITY_PENDING; -} - -static inline void irqd_clear(struct irq_data *d, unsigned int mask) -{ - __irqd_to_state(d) &= ~mask; -} - -static inline void irqd_set(struct irq_data *d, unsigned int mask) -{ - __irqd_to_state(d) |= mask; -} - -static inline bool irqd_has_set(struct irq_data *d, unsigned int mask) -{ - return __irqd_to_state(d) & mask; -} - -#undef __irqd_to_state - -static inline void kstat_incr_irqs_this_cpu(struct irq_desc *desc) -{ - __this_cpu_inc(*desc->kstat_irqs); - __this_cpu_inc(kstat.irqs_sum); -} - -static inline int irq_desc_get_node(struct irq_desc *desc) -{ - return irq_common_data_get_node(&desc->irq_common_data); -} - -static inline int irq_desc_is_chained(struct irq_desc *desc) -{ - return (desc->action && desc->action == &chained_action); -} - -#ifdef CONFIG_PM_SLEEP -bool irq_pm_check_wakeup(struct irq_desc *desc); -void irq_pm_install_action(struct irq_desc *desc, struct irqaction *action); -void irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action); -#else -static inline bool irq_pm_check_wakeup(struct irq_desc *desc) { return false; } -static inline void -irq_pm_install_action(struct irq_desc *desc, struct irqaction *action) { } -static inline void -irq_pm_remove_action(struct irq_desc *desc, struct irqaction *action) { } -#endif diff --git a/src/linux/kernel/irq/irqdesc.c b/src/linux/kernel/irq/irqdesc.c deleted file mode 100644 index 00bb0ae..0000000 --- a/src/linux/kernel/irq/irqdesc.c +++ /dev/null @@ -1,920 +0,0 @@ -/* - * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar - * Copyright (C) 2005-2006, Thomas Gleixner, Russell King - * - * This file contains the interrupt descriptor management code - * - * Detailed information is available in Documentation/DocBook/genericirq - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internals.h" - -/* - * lockdep: we want to handle all irq_desc locks as a single lock-class: - */ -static struct lock_class_key irq_desc_lock_class; - -#if defined(CONFIG_SMP) -static int __init irq_affinity_setup(char *str) -{ - zalloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT); - cpulist_parse(str, irq_default_affinity); - /* - * Set at least the boot cpu. We don't want to end up with - * bugreports caused by random comandline masks - */ - cpumask_set_cpu(smp_processor_id(), irq_default_affinity); - return 1; -} -__setup("irqaffinity=", irq_affinity_setup); - -static void __init init_irq_default_affinity(void) -{ -#ifdef CONFIG_CPUMASK_OFFSTACK - if (!irq_default_affinity) - zalloc_cpumask_var(&irq_default_affinity, GFP_NOWAIT); -#endif - if (cpumask_empty(irq_default_affinity)) - cpumask_setall(irq_default_affinity); -} -#else -static void __init init_irq_default_affinity(void) -{ -} -#endif - -#ifdef CONFIG_SMP -static int alloc_masks(struct irq_desc *desc, gfp_t gfp, int node) -{ - if (!zalloc_cpumask_var_node(&desc->irq_common_data.affinity, - gfp, node)) - return -ENOMEM; - -#ifdef CONFIG_GENERIC_PENDING_IRQ - if (!zalloc_cpumask_var_node(&desc->pending_mask, gfp, node)) { - free_cpumask_var(desc->irq_common_data.affinity); - return -ENOMEM; - } -#endif - return 0; -} - -static void desc_smp_init(struct irq_desc *desc, int node, - const struct cpumask *affinity) -{ - if (!affinity) - affinity = irq_default_affinity; - cpumask_copy(desc->irq_common_data.affinity, affinity); - -#ifdef CONFIG_GENERIC_PENDING_IRQ - cpumask_clear(desc->pending_mask); -#endif -#ifdef CONFIG_NUMA - desc->irq_common_data.node = node; -#endif -} - -#else -static inline int -alloc_masks(struct irq_desc *desc, gfp_t gfp, int node) { return 0; } -static inline void -desc_smp_init(struct irq_desc *desc, int node, const struct cpumask *affinity) { } -#endif - -static void desc_set_defaults(unsigned int irq, struct irq_desc *desc, int node, - const struct cpumask *affinity, struct module *owner) -{ - int cpu; - - desc->irq_common_data.handler_data = NULL; - desc->irq_common_data.msi_desc = NULL; - - desc->irq_data.common = &desc->irq_common_data; - desc->irq_data.irq = irq; - desc->irq_data.chip = &no_irq_chip; - desc->irq_data.chip_data = NULL; - irq_settings_clr_and_set(desc, ~0, _IRQ_DEFAULT_INIT_FLAGS); - irqd_set(&desc->irq_data, IRQD_IRQ_DISABLED); - desc->handle_irq = handle_bad_irq; - desc->depth = 1; - desc->irq_count = 0; - desc->irqs_unhandled = 0; - desc->name = NULL; - desc->owner = owner; - for_each_possible_cpu(cpu) - *per_cpu_ptr(desc->kstat_irqs, cpu) = 0; - desc_smp_init(desc, node, affinity); -} - -int nr_irqs = NR_IRQS; -EXPORT_SYMBOL_GPL(nr_irqs); - -static DEFINE_MUTEX(sparse_irq_lock); -static DECLARE_BITMAP(allocated_irqs, IRQ_BITMAP_BITS); - -#ifdef CONFIG_SPARSE_IRQ - -static void irq_kobj_release(struct kobject *kobj); - -#ifdef CONFIG_SYSFS -static struct kobject *irq_kobj_base; - -#define IRQ_ATTR_RO(_name) \ -static struct kobj_attribute _name##_attr = __ATTR_RO(_name) - -static ssize_t per_cpu_count_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - struct irq_desc *desc = container_of(kobj, struct irq_desc, kobj); - int cpu, irq = desc->irq_data.irq; - ssize_t ret = 0; - char *p = ""; - - for_each_possible_cpu(cpu) { - unsigned int c = kstat_irqs_cpu(irq, cpu); - - ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s%u", p, c); - p = ","; - } - - ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n"); - return ret; -} -IRQ_ATTR_RO(per_cpu_count); - -static ssize_t chip_name_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - struct irq_desc *desc = container_of(kobj, struct irq_desc, kobj); - ssize_t ret = 0; - - raw_spin_lock_irq(&desc->lock); - if (desc->irq_data.chip && desc->irq_data.chip->name) { - ret = scnprintf(buf, PAGE_SIZE, "%s\n", - desc->irq_data.chip->name); - } - raw_spin_unlock_irq(&desc->lock); - - return ret; -} -IRQ_ATTR_RO(chip_name); - -static ssize_t hwirq_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - struct irq_desc *desc = container_of(kobj, struct irq_desc, kobj); - ssize_t ret = 0; - - raw_spin_lock_irq(&desc->lock); - if (desc->irq_data.domain) - ret = sprintf(buf, "%d\n", (int)desc->irq_data.hwirq); - raw_spin_unlock_irq(&desc->lock); - - return ret; -} -IRQ_ATTR_RO(hwirq); - -static ssize_t type_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - struct irq_desc *desc = container_of(kobj, struct irq_desc, kobj); - ssize_t ret = 0; - - raw_spin_lock_irq(&desc->lock); - ret = sprintf(buf, "%s\n", - irqd_is_level_type(&desc->irq_data) ? "level" : "edge"); - raw_spin_unlock_irq(&desc->lock); - - return ret; - -} -IRQ_ATTR_RO(type); - -static ssize_t name_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - struct irq_desc *desc = container_of(kobj, struct irq_desc, kobj); - ssize_t ret = 0; - - raw_spin_lock_irq(&desc->lock); - if (desc->name) - ret = scnprintf(buf, PAGE_SIZE, "%s\n", desc->name); - raw_spin_unlock_irq(&desc->lock); - - return ret; -} -IRQ_ATTR_RO(name); - -static ssize_t actions_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - struct irq_desc *desc = container_of(kobj, struct irq_desc, kobj); - struct irqaction *action; - ssize_t ret = 0; - char *p = ""; - - raw_spin_lock_irq(&desc->lock); - for (action = desc->action; action != NULL; action = action->next) { - ret += scnprintf(buf + ret, PAGE_SIZE - ret, "%s%s", - p, action->name); - p = ","; - } - raw_spin_unlock_irq(&desc->lock); - - if (ret) - ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n"); - - return ret; -} -IRQ_ATTR_RO(actions); - -static struct attribute *irq_attrs[] = { - &per_cpu_count_attr.attr, - &chip_name_attr.attr, - &hwirq_attr.attr, - &type_attr.attr, - &name_attr.attr, - &actions_attr.attr, - NULL -}; - -static struct kobj_type irq_kobj_type = { - .release = irq_kobj_release, - .sysfs_ops = &kobj_sysfs_ops, - .default_attrs = irq_attrs, -}; - -static void irq_sysfs_add(int irq, struct irq_desc *desc) -{ - if (irq_kobj_base) { - /* - * Continue even in case of failure as this is nothing - * crucial. - */ - if (kobject_add(&desc->kobj, irq_kobj_base, "%d", irq)) - pr_warn("Failed to add kobject for irq %d\n", irq); - } -} - -static int __init irq_sysfs_init(void) -{ - struct irq_desc *desc; - int irq; - - /* Prevent concurrent irq alloc/free */ - irq_lock_sparse(); - - irq_kobj_base = kobject_create_and_add("irq", kernel_kobj); - if (!irq_kobj_base) { - irq_unlock_sparse(); - return -ENOMEM; - } - - /* Add the already allocated interrupts */ - for_each_irq_desc(irq, desc) - irq_sysfs_add(irq, desc); - irq_unlock_sparse(); - - return 0; -} -postcore_initcall(irq_sysfs_init); - -#else /* !CONFIG_SYSFS */ - -static struct kobj_type irq_kobj_type = { - .release = irq_kobj_release, -}; - -static void irq_sysfs_add(int irq, struct irq_desc *desc) {} - -#endif /* CONFIG_SYSFS */ - -static RADIX_TREE(irq_desc_tree, GFP_KERNEL); - -static void irq_insert_desc(unsigned int irq, struct irq_desc *desc) -{ - radix_tree_insert(&irq_desc_tree, irq, desc); -} - -struct irq_desc *irq_to_desc(unsigned int irq) -{ - return radix_tree_lookup(&irq_desc_tree, irq); -} -EXPORT_SYMBOL(irq_to_desc); - -static void delete_irq_desc(unsigned int irq) -{ - radix_tree_delete(&irq_desc_tree, irq); -} - -#ifdef CONFIG_SMP -static void free_masks(struct irq_desc *desc) -{ -#ifdef CONFIG_GENERIC_PENDING_IRQ - free_cpumask_var(desc->pending_mask); -#endif - free_cpumask_var(desc->irq_common_data.affinity); -} -#else -static inline void free_masks(struct irq_desc *desc) { } -#endif - -void irq_lock_sparse(void) -{ - mutex_lock(&sparse_irq_lock); -} - -void irq_unlock_sparse(void) -{ - mutex_unlock(&sparse_irq_lock); -} - -static struct irq_desc *alloc_desc(int irq, int node, unsigned int flags, - const struct cpumask *affinity, - struct module *owner) -{ - struct irq_desc *desc; - gfp_t gfp = GFP_KERNEL; - - desc = kzalloc_node(sizeof(*desc), gfp, node); - if (!desc) - return NULL; - /* allocate based on nr_cpu_ids */ - desc->kstat_irqs = alloc_percpu(unsigned int); - if (!desc->kstat_irqs) - goto err_desc; - - if (alloc_masks(desc, gfp, node)) - goto err_kstat; - - raw_spin_lock_init(&desc->lock); - lockdep_set_class(&desc->lock, &irq_desc_lock_class); - init_rcu_head(&desc->rcu); - - desc_set_defaults(irq, desc, node, affinity, owner); - irqd_set(&desc->irq_data, flags); - kobject_init(&desc->kobj, &irq_kobj_type); - - return desc; - -err_kstat: - free_percpu(desc->kstat_irqs); -err_desc: - kfree(desc); - return NULL; -} - -static void irq_kobj_release(struct kobject *kobj) -{ - struct irq_desc *desc = container_of(kobj, struct irq_desc, kobj); - - free_masks(desc); - free_percpu(desc->kstat_irqs); - kfree(desc); -} - -static void delayed_free_desc(struct rcu_head *rhp) -{ - struct irq_desc *desc = container_of(rhp, struct irq_desc, rcu); - - kobject_put(&desc->kobj); -} - -static void free_desc(unsigned int irq) -{ - struct irq_desc *desc = irq_to_desc(irq); - - unregister_irq_proc(irq, desc); - - /* - * sparse_irq_lock protects also show_interrupts() and - * kstat_irq_usr(). Once we deleted the descriptor from the - * sparse tree we can free it. Access in proc will fail to - * lookup the descriptor. - * - * The sysfs entry must be serialized against a concurrent - * irq_sysfs_init() as well. - */ - mutex_lock(&sparse_irq_lock); - kobject_del(&desc->kobj); - delete_irq_desc(irq); - mutex_unlock(&sparse_irq_lock); - - /* - * We free the descriptor, masks and stat fields via RCU. That - * allows demultiplex interrupts to do rcu based management of - * the child interrupts. - */ - call_rcu(&desc->rcu, delayed_free_desc); -} - -static int alloc_descs(unsigned int start, unsigned int cnt, int node, - const struct cpumask *affinity, struct module *owner) -{ - const struct cpumask *mask = NULL; - struct irq_desc *desc; - unsigned int flags; - int i; - - /* Validate affinity mask(s) */ - if (affinity) { - for (i = 0, mask = affinity; i < cnt; i++, mask++) { - if (cpumask_empty(mask)) - return -EINVAL; - } - } - - flags = affinity ? IRQD_AFFINITY_MANAGED : 0; - mask = NULL; - - for (i = 0; i < cnt; i++) { - if (affinity) { - node = cpu_to_node(cpumask_first(affinity)); - mask = affinity; - affinity++; - } - desc = alloc_desc(start + i, node, flags, mask, owner); - if (!desc) - goto err; - mutex_lock(&sparse_irq_lock); - irq_insert_desc(start + i, desc); - irq_sysfs_add(start + i, desc); - mutex_unlock(&sparse_irq_lock); - } - return start; - -err: - for (i--; i >= 0; i--) - free_desc(start + i); - - mutex_lock(&sparse_irq_lock); - bitmap_clear(allocated_irqs, start, cnt); - mutex_unlock(&sparse_irq_lock); - return -ENOMEM; -} - -static int irq_expand_nr_irqs(unsigned int nr) -{ - if (nr > IRQ_BITMAP_BITS) - return -ENOMEM; - nr_irqs = nr; - return 0; -} - -int __init early_irq_init(void) -{ - int i, initcnt, node = first_online_node; - struct irq_desc *desc; - - init_irq_default_affinity(); - - /* Let arch update nr_irqs and return the nr of preallocated irqs */ - initcnt = arch_probe_nr_irqs(); - printk(KERN_INFO "NR_IRQS:%d nr_irqs:%d %d\n", NR_IRQS, nr_irqs, initcnt); - - if (WARN_ON(nr_irqs > IRQ_BITMAP_BITS)) - nr_irqs = IRQ_BITMAP_BITS; - - if (WARN_ON(initcnt > IRQ_BITMAP_BITS)) - initcnt = IRQ_BITMAP_BITS; - - if (initcnt > nr_irqs) - nr_irqs = initcnt; - - for (i = 0; i < initcnt; i++) { - desc = alloc_desc(i, node, 0, NULL, NULL); - set_bit(i, allocated_irqs); - irq_insert_desc(i, desc); - } - return arch_early_irq_init(); -} - -#else /* !CONFIG_SPARSE_IRQ */ - -struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = { - [0 ... NR_IRQS-1] = { - .handle_irq = handle_bad_irq, - .depth = 1, - .lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock), - } -}; - -int __init early_irq_init(void) -{ - int count, i, node = first_online_node; - struct irq_desc *desc; - - init_irq_default_affinity(); - - printk(KERN_INFO "NR_IRQS:%d\n", NR_IRQS); - - desc = irq_desc; - count = ARRAY_SIZE(irq_desc); - - for (i = 0; i < count; i++) { - desc[i].kstat_irqs = alloc_percpu(unsigned int); - alloc_masks(&desc[i], GFP_KERNEL, node); - raw_spin_lock_init(&desc[i].lock); - lockdep_set_class(&desc[i].lock, &irq_desc_lock_class); - desc_set_defaults(i, &desc[i], node, NULL, NULL); - } - return arch_early_irq_init(); -} - -struct irq_desc *irq_to_desc(unsigned int irq) -{ - return (irq < NR_IRQS) ? irq_desc + irq : NULL; -} -EXPORT_SYMBOL(irq_to_desc); - -static void free_desc(unsigned int irq) -{ - struct irq_desc *desc = irq_to_desc(irq); - unsigned long flags; - - raw_spin_lock_irqsave(&desc->lock, flags); - desc_set_defaults(irq, desc, irq_desc_get_node(desc), NULL, NULL); - raw_spin_unlock_irqrestore(&desc->lock, flags); -} - -static inline int alloc_descs(unsigned int start, unsigned int cnt, int node, - const struct cpumask *affinity, - struct module *owner) -{ - u32 i; - - for (i = 0; i < cnt; i++) { - struct irq_desc *desc = irq_to_desc(start + i); - - desc->owner = owner; - } - return start; -} - -static int irq_expand_nr_irqs(unsigned int nr) -{ - return -ENOMEM; -} - -void irq_mark_irq(unsigned int irq) -{ - mutex_lock(&sparse_irq_lock); - bitmap_set(allocated_irqs, irq, 1); - mutex_unlock(&sparse_irq_lock); -} - -#ifdef CONFIG_GENERIC_IRQ_LEGACY -void irq_init_desc(unsigned int irq) -{ - free_desc(irq); -} -#endif - -#endif /* !CONFIG_SPARSE_IRQ */ - -/** - * generic_handle_irq - Invoke the handler for a particular irq - * @irq: The irq number to handle - * - */ -int generic_handle_irq(unsigned int irq) -{ - struct irq_desc *desc = irq_to_desc(irq); - - if (!desc) - return -EINVAL; - generic_handle_irq_desc(desc); - return 0; -} -EXPORT_SYMBOL_GPL(generic_handle_irq); - -#ifdef CONFIG_HANDLE_DOMAIN_IRQ -/** - * __handle_domain_irq - Invoke the handler for a HW irq belonging to a domain - * @domain: The domain where to perform the lookup - * @hwirq: The HW irq number to convert to a logical one - * @lookup: Whether to perform the domain lookup or not - * @regs: Register file coming from the low-level handling code - * - * Returns: 0 on success, or -EINVAL if conversion has failed - */ -int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq, - bool lookup, struct pt_regs *regs) -{ - struct pt_regs *old_regs = set_irq_regs(regs); - unsigned int irq = hwirq; - int ret = 0; - - irq_enter(); - -#ifdef CONFIG_IRQ_DOMAIN - if (lookup) - irq = irq_find_mapping(domain, hwirq); -#endif - - /* - * Some hardware gives randomly wrong interrupts. Rather - * than crashing, do something sensible. - */ - if (unlikely(!irq || irq >= nr_irqs)) { - ack_bad_irq(irq); - ret = -EINVAL; - } else { - generic_handle_irq(irq); - } - - irq_exit(); - set_irq_regs(old_regs); - return ret; -} -#endif - -/* Dynamic interrupt handling */ - -/** - * irq_free_descs - free irq descriptors - * @from: Start of descriptor range - * @cnt: Number of consecutive irqs to free - */ -void irq_free_descs(unsigned int from, unsigned int cnt) -{ - int i; - - if (from >= nr_irqs || (from + cnt) > nr_irqs) - return; - - for (i = 0; i < cnt; i++) - free_desc(from + i); - - mutex_lock(&sparse_irq_lock); - bitmap_clear(allocated_irqs, from, cnt); - mutex_unlock(&sparse_irq_lock); -} -EXPORT_SYMBOL_GPL(irq_free_descs); - -/** - * irq_alloc_descs - allocate and initialize a range of irq descriptors - * @irq: Allocate for specific irq number if irq >= 0 - * @from: Start the search from this irq number - * @cnt: Number of consecutive irqs to allocate. - * @node: Preferred node on which the irq descriptor should be allocated - * @owner: Owning module (can be NULL) - * @affinity: Optional pointer to an affinity mask array of size @cnt which - * hints where the irq descriptors should be allocated and which - * default affinities to use - * - * Returns the first irq number or error code - */ -int __ref -__irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, - struct module *owner, const struct cpumask *affinity) -{ - int start, ret; - - if (!cnt) - return -EINVAL; - - if (irq >= 0) { - if (from > irq) - return -EINVAL; - from = irq; - } else { - /* - * For interrupts which are freely allocated the - * architecture can force a lower bound to the @from - * argument. x86 uses this to exclude the GSI space. - */ - from = arch_dynirq_lower_bound(from); - } - - mutex_lock(&sparse_irq_lock); - - start = bitmap_find_next_zero_area(allocated_irqs, IRQ_BITMAP_BITS, - from, cnt, 0); - ret = -EEXIST; - if (irq >=0 && start != irq) - goto err; - - if (start + cnt > nr_irqs) { - ret = irq_expand_nr_irqs(start + cnt); - if (ret) - goto err; - } - - bitmap_set(allocated_irqs, start, cnt); - mutex_unlock(&sparse_irq_lock); - return alloc_descs(start, cnt, node, affinity, owner); - -err: - mutex_unlock(&sparse_irq_lock); - return ret; -} -EXPORT_SYMBOL_GPL(__irq_alloc_descs); - -#ifdef CONFIG_GENERIC_IRQ_LEGACY_ALLOC_HWIRQ -/** - * irq_alloc_hwirqs - Allocate an irq descriptor and initialize the hardware - * @cnt: number of interrupts to allocate - * @node: node on which to allocate - * - * Returns an interrupt number > 0 or 0, if the allocation fails. - */ -unsigned int irq_alloc_hwirqs(int cnt, int node) -{ - int i, irq = __irq_alloc_descs(-1, 0, cnt, node, NULL, NULL); - - if (irq < 0) - return 0; - - for (i = irq; cnt > 0; i++, cnt--) { - if (arch_setup_hwirq(i, node)) - goto err; - irq_clear_status_flags(i, _IRQ_NOREQUEST); - } - return irq; - -err: - for (i--; i >= irq; i--) { - irq_set_status_flags(i, _IRQ_NOREQUEST | _IRQ_NOPROBE); - arch_teardown_hwirq(i); - } - irq_free_descs(irq, cnt); - return 0; -} -EXPORT_SYMBOL_GPL(irq_alloc_hwirqs); - -/** - * irq_free_hwirqs - Free irq descriptor and cleanup the hardware - * @from: Free from irq number - * @cnt: number of interrupts to free - * - */ -void irq_free_hwirqs(unsigned int from, int cnt) -{ - int i, j; - - for (i = from, j = cnt; j > 0; i++, j--) { - irq_set_status_flags(i, _IRQ_NOREQUEST | _IRQ_NOPROBE); - arch_teardown_hwirq(i); - } - irq_free_descs(from, cnt); -} -EXPORT_SYMBOL_GPL(irq_free_hwirqs); -#endif - -/** - * irq_get_next_irq - get next allocated irq number - * @offset: where to start the search - * - * Returns next irq number after offset or nr_irqs if none is found. - */ -unsigned int irq_get_next_irq(unsigned int offset) -{ - return find_next_bit(allocated_irqs, nr_irqs, offset); -} - -struct irq_desc * -__irq_get_desc_lock(unsigned int irq, unsigned long *flags, bool bus, - unsigned int check) -{ - struct irq_desc *desc = irq_to_desc(irq); - - if (desc) { - if (check & _IRQ_DESC_CHECK) { - if ((check & _IRQ_DESC_PERCPU) && - !irq_settings_is_per_cpu_devid(desc)) - return NULL; - - if (!(check & _IRQ_DESC_PERCPU) && - irq_settings_is_per_cpu_devid(desc)) - return NULL; - } - - if (bus) - chip_bus_lock(desc); - raw_spin_lock_irqsave(&desc->lock, *flags); - } - return desc; -} - -void __irq_put_desc_unlock(struct irq_desc *desc, unsigned long flags, bool bus) -{ - raw_spin_unlock_irqrestore(&desc->lock, flags); - if (bus) - chip_bus_sync_unlock(desc); -} - -int irq_set_percpu_devid_partition(unsigned int irq, - const struct cpumask *affinity) -{ - struct irq_desc *desc = irq_to_desc(irq); - - if (!desc) - return -EINVAL; - - if (desc->percpu_enabled) - return -EINVAL; - - desc->percpu_enabled = kzalloc(sizeof(*desc->percpu_enabled), GFP_KERNEL); - - if (!desc->percpu_enabled) - return -ENOMEM; - - if (affinity) - desc->percpu_affinity = affinity; - else - desc->percpu_affinity = cpu_possible_mask; - - irq_set_percpu_devid_flags(irq); - return 0; -} - -int irq_set_percpu_devid(unsigned int irq) -{ - return irq_set_percpu_devid_partition(irq, NULL); -} - -int irq_get_percpu_devid_partition(unsigned int irq, struct cpumask *affinity) -{ - struct irq_desc *desc = irq_to_desc(irq); - - if (!desc || !desc->percpu_enabled) - return -EINVAL; - - if (affinity) - cpumask_copy(affinity, desc->percpu_affinity); - - return 0; -} - -void kstat_incr_irq_this_cpu(unsigned int irq) -{ - kstat_incr_irqs_this_cpu(irq_to_desc(irq)); -} - -/** - * kstat_irqs_cpu - Get the statistics for an interrupt on a cpu - * @irq: The interrupt number - * @cpu: The cpu number - * - * Returns the sum of interrupt counts on @cpu since boot for - * @irq. The caller must ensure that the interrupt is not removed - * concurrently. - */ -unsigned int kstat_irqs_cpu(unsigned int irq, int cpu) -{ - struct irq_desc *desc = irq_to_desc(irq); - - return desc && desc->kstat_irqs ? - *per_cpu_ptr(desc->kstat_irqs, cpu) : 0; -} - -/** - * kstat_irqs - Get the statistics for an interrupt - * @irq: The interrupt number - * - * Returns the sum of interrupt counts on all cpus since boot for - * @irq. The caller must ensure that the interrupt is not removed - * concurrently. - */ -unsigned int kstat_irqs(unsigned int irq) -{ - struct irq_desc *desc = irq_to_desc(irq); - int cpu; - unsigned int sum = 0; - - if (!desc || !desc->kstat_irqs) - return 0; - for_each_possible_cpu(cpu) - sum += *per_cpu_ptr(desc->kstat_irqs, cpu); - return sum; -} - -/** - * kstat_irqs_usr - Get the statistics for an interrupt - * @irq: The interrupt number - * - * Returns the sum of interrupt counts on all cpus since boot for - * @irq. Contrary to kstat_irqs() this can be called from any - * preemptible context. It's protected against concurrent removal of - * an interrupt descriptor when sparse irqs are enabled. - */ -unsigned int kstat_irqs_usr(unsigned int irq) -{ - unsigned int sum; - - irq_lock_sparse(); - sum = kstat_irqs(irq); - irq_unlock_sparse(); - return sum; -} diff --git a/src/linux/kernel/irq/manage.c b/src/linux/kernel/irq/manage.c deleted file mode 100644 index 6b66959..0000000 --- a/src/linux/kernel/irq/manage.c +++ /dev/null @@ -1,2099 +0,0 @@ -/* - * linux/kernel/irq/manage.c - * - * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar - * Copyright (C) 2005-2006 Thomas Gleixner - * - * This file contains driver APIs to the irq subsystem. - */ - -#define pr_fmt(fmt) "genirq: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internals.h" - -#ifdef CONFIG_IRQ_FORCED_THREADING -__read_mostly bool force_irqthreads; - -static int __init setup_forced_irqthreads(char *arg) -{ - force_irqthreads = true; - return 0; -} -early_param("threadirqs", setup_forced_irqthreads); -#endif - -static void __synchronize_hardirq(struct irq_desc *desc) -{ - bool inprogress; - - do { - unsigned long flags; - - /* - * Wait until we're out of the critical section. This might - * give the wrong answer due to the lack of memory barriers. - */ - while (irqd_irq_inprogress(&desc->irq_data)) - cpu_relax(); - - /* Ok, that indicated we're done: double-check carefully. */ - raw_spin_lock_irqsave(&desc->lock, flags); - inprogress = irqd_irq_inprogress(&desc->irq_data); - raw_spin_unlock_irqrestore(&desc->lock, flags); - - /* Oops, that failed? */ - } while (inprogress); -} - -/** - * synchronize_hardirq - wait for pending hard IRQ handlers (on other CPUs) - * @irq: interrupt number to wait for - * - * This function waits for any pending hard IRQ handlers for this - * interrupt to complete before returning. If you use this - * function while holding a resource the IRQ handler may need you - * will deadlock. It does not take associated threaded handlers - * into account. - * - * Do not use this for shutdown scenarios where you must be sure - * that all parts (hardirq and threaded handler) have completed. - * - * Returns: false if a threaded handler is active. - * - * This function may be called - with care - from IRQ context. - */ -bool synchronize_hardirq(unsigned int irq) -{ - struct irq_desc *desc = irq_to_desc(irq); - - if (desc) { - __synchronize_hardirq(desc); - return !atomic_read(&desc->threads_active); - } - - return true; -} -EXPORT_SYMBOL(synchronize_hardirq); - -/** - * synchronize_irq - wait for pending IRQ handlers (on other CPUs) - * @irq: interrupt number to wait for - * - * This function waits for any pending IRQ handlers for this interrupt - * to complete before returning. If you use this function while - * holding a resource the IRQ handler may need you will deadlock. - * - * This function may be called - with care - from IRQ context. - */ -void synchronize_irq(unsigned int irq) -{ - struct irq_desc *desc = irq_to_desc(irq); - - if (desc) { - __synchronize_hardirq(desc); - /* - * We made sure that no hardirq handler is - * running. Now verify that no threaded handlers are - * active. - */ - wait_event(desc->wait_for_threads, - !atomic_read(&desc->threads_active)); - } -} -EXPORT_SYMBOL(synchronize_irq); - -#ifdef CONFIG_SMP -cpumask_var_t irq_default_affinity; - -static bool __irq_can_set_affinity(struct irq_desc *desc) -{ - if (!desc || !irqd_can_balance(&desc->irq_data) || - !desc->irq_data.chip || !desc->irq_data.chip->irq_set_affinity) - return false; - return true; -} - -/** - * irq_can_set_affinity - Check if the affinity of a given irq can be set - * @irq: Interrupt to check - * - */ -int irq_can_set_affinity(unsigned int irq) -{ - return __irq_can_set_affinity(irq_to_desc(irq)); -} - -/** - * irq_can_set_affinity_usr - Check if affinity of a irq can be set from user space - * @irq: Interrupt to check - * - * Like irq_can_set_affinity() above, but additionally checks for the - * AFFINITY_MANAGED flag. - */ -bool irq_can_set_affinity_usr(unsigned int irq) -{ - struct irq_desc *desc = irq_to_desc(irq); - - return __irq_can_set_affinity(desc) && - !irqd_affinity_is_managed(&desc->irq_data); -} - -/** - * irq_set_thread_affinity - Notify irq threads to adjust affinity - * @desc: irq descriptor which has affitnity changed - * - * We just set IRQTF_AFFINITY and delegate the affinity setting - * to the interrupt thread itself. We can not call - * set_cpus_allowed_ptr() here as we hold desc->lock and this - * code can be called from hard interrupt context. - */ -void irq_set_thread_affinity(struct irq_desc *desc) -{ - struct irqaction *action; - - for_each_action_of_desc(desc, action) - if (action->thread) - set_bit(IRQTF_AFFINITY, &action->thread_flags); -} - -#ifdef CONFIG_GENERIC_PENDING_IRQ -static inline bool irq_can_move_pcntxt(struct irq_data *data) -{ - return irqd_can_move_in_process_context(data); -} -static inline bool irq_move_pending(struct irq_data *data) -{ - return irqd_is_setaffinity_pending(data); -} -static inline void -irq_copy_pending(struct irq_desc *desc, const struct cpumask *mask) -{ - cpumask_copy(desc->pending_mask, mask); -} -static inline void -irq_get_pending(struct cpumask *mask, struct irq_desc *desc) -{ - cpumask_copy(mask, desc->pending_mask); -} -#else -static inline bool irq_can_move_pcntxt(struct irq_data *data) { return true; } -static inline bool irq_move_pending(struct irq_data *data) { return false; } -static inline void -irq_copy_pending(struct irq_desc *desc, const struct cpumask *mask) { } -static inline void -irq_get_pending(struct cpumask *mask, struct irq_desc *desc) { } -#endif - -int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask, - bool force) -{ - struct irq_desc *desc = irq_data_to_desc(data); - struct irq_chip *chip = irq_data_get_irq_chip(data); - int ret; - - ret = chip->irq_set_affinity(data, mask, force); - switch (ret) { - case IRQ_SET_MASK_OK: - case IRQ_SET_MASK_OK_DONE: - cpumask_copy(desc->irq_common_data.affinity, mask); - case IRQ_SET_MASK_OK_NOCOPY: - irq_set_thread_affinity(desc); - ret = 0; - } - - return ret; -} - -int irq_set_affinity_locked(struct irq_data *data, const struct cpumask *mask, - bool force) -{ - struct irq_chip *chip = irq_data_get_irq_chip(data); - struct irq_desc *desc = irq_data_to_desc(data); - int ret = 0; - - if (!chip || !chip->irq_set_affinity) - return -EINVAL; - - if (irq_can_move_pcntxt(data)) { - ret = irq_do_set_affinity(data, mask, force); - } else { - irqd_set_move_pending(data); - irq_copy_pending(desc, mask); - } - - if (desc->affinity_notify) { - kref_get(&desc->affinity_notify->kref); - schedule_work(&desc->affinity_notify->work); - } - irqd_set(data, IRQD_AFFINITY_SET); - - return ret; -} - -int __irq_set_affinity(unsigned int irq, const struct cpumask *mask, bool force) -{ - struct irq_desc *desc = irq_to_desc(irq); - unsigned long flags; - int ret; - - if (!desc) - return -EINVAL; - - raw_spin_lock_irqsave(&desc->lock, flags); - ret = irq_set_affinity_locked(irq_desc_get_irq_data(desc), mask, force); - raw_spin_unlock_irqrestore(&desc->lock, flags); - return ret; -} - -int irq_set_affinity_hint(unsigned int irq, const struct cpumask *m) -{ - unsigned long flags; - struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL); - - if (!desc) - return -EINVAL; - desc->affinity_hint = m; - irq_put_desc_unlock(desc, flags); - /* set the initial affinity to prevent every interrupt being on CPU0 */ - if (m) - __irq_set_affinity(irq, m, false); - return 0; -} -EXPORT_SYMBOL_GPL(irq_set_affinity_hint); - -static void irq_affinity_notify(struct work_struct *work) -{ - struct irq_affinity_notify *notify = - container_of(work, struct irq_affinity_notify, work); - struct irq_desc *desc = irq_to_desc(notify->irq); - cpumask_var_t cpumask; - unsigned long flags; - - if (!desc || !alloc_cpumask_var(&cpumask, GFP_KERNEL)) - goto out; - - raw_spin_lock_irqsave(&desc->lock, flags); - if (irq_move_pending(&desc->irq_data)) - irq_get_pending(cpumask, desc); - else - cpumask_copy(cpumask, desc->irq_common_data.affinity); - raw_spin_unlock_irqrestore(&desc->lock, flags); - - notify->notify(notify, cpumask); - - free_cpumask_var(cpumask); -out: - kref_put(¬ify->kref, notify->release); -} - -/** - * irq_set_affinity_notifier - control notification of IRQ affinity changes - * @irq: Interrupt for which to enable/disable notification - * @notify: Context for notification, or %NULL to disable - * notification. Function pointers must be initialised; - * the other fields will be initialised by this function. - * - * Must be called in process context. Notification may only be enabled - * after the IRQ is allocated and must be disabled before the IRQ is - * freed using free_irq(). - */ -int -irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify) -{ - struct irq_desc *desc = irq_to_desc(irq); - struct irq_affinity_notify *old_notify; - unsigned long flags; - - /* The release function is promised process context */ - might_sleep(); - - if (!desc) - return -EINVAL; - - /* Complete initialisation of *notify */ - if (notify) { - notify->irq = irq; - kref_init(¬ify->kref); - INIT_WORK(¬ify->work, irq_affinity_notify); - } - - raw_spin_lock_irqsave(&desc->lock, flags); - old_notify = desc->affinity_notify; - desc->affinity_notify = notify; - raw_spin_unlock_irqrestore(&desc->lock, flags); - - if (old_notify) - kref_put(&old_notify->kref, old_notify->release); - - return 0; -} -EXPORT_SYMBOL_GPL(irq_set_affinity_notifier); - -#ifndef CONFIG_AUTO_IRQ_AFFINITY -/* - * Generic version of the affinity autoselector. - */ -static int setup_affinity(struct irq_desc *desc, struct cpumask *mask) -{ - struct cpumask *set = irq_default_affinity; - int node = irq_desc_get_node(desc); - - /* Excludes PER_CPU and NO_BALANCE interrupts */ - if (!__irq_can_set_affinity(desc)) - return 0; - - /* - * Preserve the managed affinity setting and an userspace affinity - * setup, but make sure that one of the targets is online. - */ - if (irqd_affinity_is_managed(&desc->irq_data) || - irqd_has_set(&desc->irq_data, IRQD_AFFINITY_SET)) { - if (cpumask_intersects(desc->irq_common_data.affinity, - cpu_online_mask)) - set = desc->irq_common_data.affinity; - else - irqd_clear(&desc->irq_data, IRQD_AFFINITY_SET); - } - - cpumask_and(mask, cpu_online_mask, set); - if (node != NUMA_NO_NODE) { - const struct cpumask *nodemask = cpumask_of_node(node); - - /* make sure at least one of the cpus in nodemask is online */ - if (cpumask_intersects(mask, nodemask)) - cpumask_and(mask, mask, nodemask); - } - irq_do_set_affinity(&desc->irq_data, mask, false); - return 0; -} -#else -/* Wrapper for ALPHA specific affinity selector magic */ -static inline int setup_affinity(struct irq_desc *d, struct cpumask *mask) -{ - return irq_select_affinity(irq_desc_get_irq(d)); -} -#endif - -/* - * Called when affinity is set via /proc/irq - */ -int irq_select_affinity_usr(unsigned int irq, struct cpumask *mask) -{ - struct irq_desc *desc = irq_to_desc(irq); - unsigned long flags; - int ret; - - raw_spin_lock_irqsave(&desc->lock, flags); - ret = setup_affinity(desc, mask); - raw_spin_unlock_irqrestore(&desc->lock, flags); - return ret; -} - -#else -static inline int -setup_affinity(struct irq_desc *desc, struct cpumask *mask) -{ - return 0; -} -#endif - -/** - * irq_set_vcpu_affinity - Set vcpu affinity for the interrupt - * @irq: interrupt number to set affinity - * @vcpu_info: vCPU specific data - * - * This function uses the vCPU specific data to set the vCPU - * affinity for an irq. The vCPU specific data is passed from - * outside, such as KVM. One example code path is as below: - * KVM -> IOMMU -> irq_set_vcpu_affinity(). - */ -int irq_set_vcpu_affinity(unsigned int irq, void *vcpu_info) -{ - unsigned long flags; - struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); - struct irq_data *data; - struct irq_chip *chip; - int ret = -ENOSYS; - - if (!desc) - return -EINVAL; - - data = irq_desc_get_irq_data(desc); - chip = irq_data_get_irq_chip(data); - if (chip && chip->irq_set_vcpu_affinity) - ret = chip->irq_set_vcpu_affinity(data, vcpu_info); - irq_put_desc_unlock(desc, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(irq_set_vcpu_affinity); - -void __disable_irq(struct irq_desc *desc) -{ - if (!desc->depth++) - irq_disable(desc); -} - -static int __disable_irq_nosync(unsigned int irq) -{ - unsigned long flags; - struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL); - - if (!desc) - return -EINVAL; - __disable_irq(desc); - irq_put_desc_busunlock(desc, flags); - return 0; -} - -/** - * disable_irq_nosync - disable an irq without waiting - * @irq: Interrupt to disable - * - * Disable the selected interrupt line. Disables and Enables are - * nested. - * Unlike disable_irq(), this function does not ensure existing - * instances of the IRQ handler have completed before returning. - * - * This function may be called from IRQ context. - */ -void disable_irq_nosync(unsigned int irq) -{ - __disable_irq_nosync(irq); -} -EXPORT_SYMBOL(disable_irq_nosync); - -/** - * disable_irq - disable an irq and wait for completion - * @irq: Interrupt to disable - * - * Disable the selected interrupt line. Enables and Disables are - * nested. - * This function waits for any pending IRQ handlers for this interrupt - * to complete before returning. If you use this function while - * holding a resource the IRQ handler may need you will deadlock. - * - * This function may be called - with care - from IRQ context. - */ -void disable_irq(unsigned int irq) -{ - if (!__disable_irq_nosync(irq)) - synchronize_irq(irq); -} -EXPORT_SYMBOL(disable_irq); - -/** - * disable_hardirq - disables an irq and waits for hardirq completion - * @irq: Interrupt to disable - * - * Disable the selected interrupt line. Enables and Disables are - * nested. - * This function waits for any pending hard IRQ handlers for this - * interrupt to complete before returning. If you use this function while - * holding a resource the hard IRQ handler may need you will deadlock. - * - * When used to optimistically disable an interrupt from atomic context - * the return value must be checked. - * - * Returns: false if a threaded handler is active. - * - * This function may be called - with care - from IRQ context. - */ -bool disable_hardirq(unsigned int irq) -{ - if (!__disable_irq_nosync(irq)) - return synchronize_hardirq(irq); - - return false; -} -EXPORT_SYMBOL_GPL(disable_hardirq); - -void __enable_irq(struct irq_desc *desc) -{ - switch (desc->depth) { - case 0: - err_out: - WARN(1, KERN_WARNING "Unbalanced enable for IRQ %d\n", - irq_desc_get_irq(desc)); - break; - case 1: { - if (desc->istate & IRQS_SUSPENDED) - goto err_out; - /* Prevent probing on this irq: */ - irq_settings_set_noprobe(desc); - irq_enable(desc); - check_irq_resend(desc); - /* fall-through */ - } - default: - desc->depth--; - } -} - -/** - * enable_irq - enable handling of an irq - * @irq: Interrupt to enable - * - * Undoes the effect of one call to disable_irq(). If this - * matches the last disable, processing of interrupts on this - * IRQ line is re-enabled. - * - * This function may be called from IRQ context only when - * desc->irq_data.chip->bus_lock and desc->chip->bus_sync_unlock are NULL ! - */ -void enable_irq(unsigned int irq) -{ - unsigned long flags; - struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL); - - if (!desc) - return; - if (WARN(!desc->irq_data.chip, - KERN_ERR "enable_irq before setup/request_irq: irq %u\n", irq)) - goto out; - - __enable_irq(desc); -out: - irq_put_desc_busunlock(desc, flags); -} -EXPORT_SYMBOL(enable_irq); - -static int set_irq_wake_real(unsigned int irq, unsigned int on) -{ - struct irq_desc *desc = irq_to_desc(irq); - int ret = -ENXIO; - - if (irq_desc_get_chip(desc)->flags & IRQCHIP_SKIP_SET_WAKE) - return 0; - - if (desc->irq_data.chip->irq_set_wake) - ret = desc->irq_data.chip->irq_set_wake(&desc->irq_data, on); - - return ret; -} - -/** - * irq_set_irq_wake - control irq power management wakeup - * @irq: interrupt to control - * @on: enable/disable power management wakeup - * - * Enable/disable power management wakeup mode, which is - * disabled by default. Enables and disables must match, - * just as they match for non-wakeup mode support. - * - * Wakeup mode lets this IRQ wake the system from sleep - * states like "suspend to RAM". - */ -int irq_set_irq_wake(unsigned int irq, unsigned int on) -{ - unsigned long flags; - struct irq_desc *desc = irq_get_desc_buslock(irq, &flags, IRQ_GET_DESC_CHECK_GLOBAL); - int ret = 0; - - if (!desc) - return -EINVAL; - - /* wakeup-capable irqs can be shared between drivers that - * don't need to have the same sleep mode behaviors. - */ - if (on) { - if (desc->wake_depth++ == 0) { - ret = set_irq_wake_real(irq, on); - if (ret) - desc->wake_depth = 0; - else - irqd_set(&desc->irq_data, IRQD_WAKEUP_STATE); - } - } else { - if (desc->wake_depth == 0) { - WARN(1, "Unbalanced IRQ %d wake disable\n", irq); - } else if (--desc->wake_depth == 0) { - ret = set_irq_wake_real(irq, on); - if (ret) - desc->wake_depth = 1; - else - irqd_clear(&desc->irq_data, IRQD_WAKEUP_STATE); - } - } - irq_put_desc_busunlock(desc, flags); - return ret; -} -EXPORT_SYMBOL(irq_set_irq_wake); - -/* - * Internal function that tells the architecture code whether a - * particular irq has been exclusively allocated or is available - * for driver use. - */ -int can_request_irq(unsigned int irq, unsigned long irqflags) -{ - unsigned long flags; - struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); - int canrequest = 0; - - if (!desc) - return 0; - - if (irq_settings_can_request(desc)) { - if (!desc->action || - irqflags & desc->action->flags & IRQF_SHARED) - canrequest = 1; - } - irq_put_desc_unlock(desc, flags); - return canrequest; -} - -int __irq_set_trigger(struct irq_desc *desc, unsigned long flags) -{ - struct irq_chip *chip = desc->irq_data.chip; - int ret, unmask = 0; - - if (!chip || !chip->irq_set_type) { - /* - * IRQF_TRIGGER_* but the PIC does not support multiple - * flow-types? - */ - pr_debug("No set_type function for IRQ %d (%s)\n", - irq_desc_get_irq(desc), - chip ? (chip->name ? : "unknown") : "unknown"); - return 0; - } - - if (chip->flags & IRQCHIP_SET_TYPE_MASKED) { - if (!irqd_irq_masked(&desc->irq_data)) - mask_irq(desc); - if (!irqd_irq_disabled(&desc->irq_data)) - unmask = 1; - } - - /* Mask all flags except trigger mode */ - flags &= IRQ_TYPE_SENSE_MASK; - ret = chip->irq_set_type(&desc->irq_data, flags); - - switch (ret) { - case IRQ_SET_MASK_OK: - case IRQ_SET_MASK_OK_DONE: - irqd_clear(&desc->irq_data, IRQD_TRIGGER_MASK); - irqd_set(&desc->irq_data, flags); - - case IRQ_SET_MASK_OK_NOCOPY: - flags = irqd_get_trigger_type(&desc->irq_data); - irq_settings_set_trigger_mask(desc, flags); - irqd_clear(&desc->irq_data, IRQD_LEVEL); - irq_settings_clr_level(desc); - if (flags & IRQ_TYPE_LEVEL_MASK) { - irq_settings_set_level(desc); - irqd_set(&desc->irq_data, IRQD_LEVEL); - } - - ret = 0; - break; - default: - pr_err("Setting trigger mode %lu for irq %u failed (%pF)\n", - flags, irq_desc_get_irq(desc), chip->irq_set_type); - } - if (unmask) - unmask_irq(desc); - return ret; -} - -#ifdef CONFIG_HARDIRQS_SW_RESEND -int irq_set_parent(int irq, int parent_irq) -{ - unsigned long flags; - struct irq_desc *desc = irq_get_desc_lock(irq, &flags, 0); - - if (!desc) - return -EINVAL; - - desc->parent_irq = parent_irq; - - irq_put_desc_unlock(desc, flags); - return 0; -} -EXPORT_SYMBOL_GPL(irq_set_parent); -#endif - -/* - * Default primary interrupt handler for threaded interrupts. Is - * assigned as primary handler when request_threaded_irq is called - * with handler == NULL. Useful for oneshot interrupts. - */ -static irqreturn_t irq_default_primary_handler(int irq, void *dev_id) -{ - return IRQ_WAKE_THREAD; -} - -/* - * Primary handler for nested threaded interrupts. Should never be - * called. - */ -static irqreturn_t irq_nested_primary_handler(int irq, void *dev_id) -{ - WARN(1, "Primary handler called for nested irq %d\n", irq); - return IRQ_NONE; -} - -static irqreturn_t irq_forced_secondary_handler(int irq, void *dev_id) -{ - WARN(1, "Secondary action handler called for irq %d\n", irq); - return IRQ_NONE; -} - -static int irq_wait_for_interrupt(struct irqaction *action) -{ - set_current_state(TASK_INTERRUPTIBLE); - - while (!kthread_should_stop()) { - - if (test_and_clear_bit(IRQTF_RUNTHREAD, - &action->thread_flags)) { - __set_current_state(TASK_RUNNING); - return 0; - } - schedule(); - set_current_state(TASK_INTERRUPTIBLE); - } - __set_current_state(TASK_RUNNING); - return -1; -} - -/* - * Oneshot interrupts keep the irq line masked until the threaded - * handler finished. unmask if the interrupt has not been disabled and - * is marked MASKED. - */ -static void irq_finalize_oneshot(struct irq_desc *desc, - struct irqaction *action) -{ - if (!(desc->istate & IRQS_ONESHOT) || - action->handler == irq_forced_secondary_handler) - return; -again: - chip_bus_lock(desc); - raw_spin_lock_irq(&desc->lock); - - /* - * Implausible though it may be we need to protect us against - * the following scenario: - * - * The thread is faster done than the hard interrupt handler - * on the other CPU. If we unmask the irq line then the - * interrupt can come in again and masks the line, leaves due - * to IRQS_INPROGRESS and the irq line is masked forever. - * - * This also serializes the state of shared oneshot handlers - * versus "desc->threads_onehsot |= action->thread_mask;" in - * irq_wake_thread(). See the comment there which explains the - * serialization. - */ - if (unlikely(irqd_irq_inprogress(&desc->irq_data))) { - raw_spin_unlock_irq(&desc->lock); - chip_bus_sync_unlock(desc); - cpu_relax(); - goto again; - } - - /* - * Now check again, whether the thread should run. Otherwise - * we would clear the threads_oneshot bit of this thread which - * was just set. - */ - if (test_bit(IRQTF_RUNTHREAD, &action->thread_flags)) - goto out_unlock; - - desc->threads_oneshot &= ~action->thread_mask; - - if (!desc->threads_oneshot && !irqd_irq_disabled(&desc->irq_data) && - irqd_irq_masked(&desc->irq_data)) - unmask_threaded_irq(desc); - -out_unlock: - raw_spin_unlock_irq(&desc->lock); - chip_bus_sync_unlock(desc); -} - -#ifdef CONFIG_SMP -/* - * Check whether we need to change the affinity of the interrupt thread. - */ -static void -irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action) -{ - cpumask_var_t mask; - bool valid = true; - - if (!test_and_clear_bit(IRQTF_AFFINITY, &action->thread_flags)) - return; - - /* - * In case we are out of memory we set IRQTF_AFFINITY again and - * try again next time - */ - if (!alloc_cpumask_var(&mask, GFP_KERNEL)) { - set_bit(IRQTF_AFFINITY, &action->thread_flags); - return; - } - - raw_spin_lock_irq(&desc->lock); - /* - * This code is triggered unconditionally. Check the affinity - * mask pointer. For CPU_MASK_OFFSTACK=n this is optimized out. - */ - if (desc->irq_common_data.affinity) - cpumask_copy(mask, desc->irq_common_data.affinity); - else - valid = false; - raw_spin_unlock_irq(&desc->lock); - - if (valid) - set_cpus_allowed_ptr(current, mask); - free_cpumask_var(mask); -} -#else -static inline void -irq_thread_check_affinity(struct irq_desc *desc, struct irqaction *action) { } -#endif - -/* - * Interrupts which are not explicitely requested as threaded - * interrupts rely on the implicit bh/preempt disable of the hard irq - * context. So we need to disable bh here to avoid deadlocks and other - * side effects. - */ -static irqreturn_t -irq_forced_thread_fn(struct irq_desc *desc, struct irqaction *action) -{ - irqreturn_t ret; - - local_bh_disable(); - ret = action->thread_fn(action->irq, action->dev_id); - irq_finalize_oneshot(desc, action); - local_bh_enable(); - return ret; -} - -/* - * Interrupts explicitly requested as threaded interrupts want to be - * preemtible - many of them need to sleep and wait for slow busses to - * complete. - */ -static irqreturn_t irq_thread_fn(struct irq_desc *desc, - struct irqaction *action) -{ - irqreturn_t ret; - - ret = action->thread_fn(action->irq, action->dev_id); - irq_finalize_oneshot(desc, action); - return ret; -} - -static void wake_threads_waitq(struct irq_desc *desc) -{ - if (atomic_dec_and_test(&desc->threads_active)) - wake_up(&desc->wait_for_threads); -} - -static void irq_thread_dtor(struct callback_head *unused) -{ - struct task_struct *tsk = current; - struct irq_desc *desc; - struct irqaction *action; - - if (WARN_ON_ONCE(!(current->flags & PF_EXITING))) - return; - - action = kthread_data(tsk); - - pr_err("exiting task \"%s\" (%d) is an active IRQ thread (irq %d)\n", - tsk->comm, tsk->pid, action->irq); - - - desc = irq_to_desc(action->irq); - /* - * If IRQTF_RUNTHREAD is set, we need to decrement - * desc->threads_active and wake possible waiters. - */ - if (test_and_clear_bit(IRQTF_RUNTHREAD, &action->thread_flags)) - wake_threads_waitq(desc); - - /* Prevent a stale desc->threads_oneshot */ - irq_finalize_oneshot(desc, action); -} - -static void irq_wake_secondary(struct irq_desc *desc, struct irqaction *action) -{ - struct irqaction *secondary = action->secondary; - - if (WARN_ON_ONCE(!secondary)) - return; - - raw_spin_lock_irq(&desc->lock); - __irq_wake_thread(desc, secondary); - raw_spin_unlock_irq(&desc->lock); -} - -/* - * Interrupt handler thread - */ -static int irq_thread(void *data) -{ - struct callback_head on_exit_work; - struct irqaction *action = data; - struct irq_desc *desc = irq_to_desc(action->irq); - irqreturn_t (*handler_fn)(struct irq_desc *desc, - struct irqaction *action); - - if (force_irqthreads && test_bit(IRQTF_FORCED_THREAD, - &action->thread_flags)) - handler_fn = irq_forced_thread_fn; - else - handler_fn = irq_thread_fn; - - init_task_work(&on_exit_work, irq_thread_dtor); - task_work_add(current, &on_exit_work, false); - - irq_thread_check_affinity(desc, action); - - while (!irq_wait_for_interrupt(action)) { - irqreturn_t action_ret; - - irq_thread_check_affinity(desc, action); - - action_ret = handler_fn(desc, action); - if (action_ret == IRQ_HANDLED) - atomic_inc(&desc->threads_handled); - if (action_ret == IRQ_WAKE_THREAD) - irq_wake_secondary(desc, action); - - wake_threads_waitq(desc); - } - - /* - * This is the regular exit path. __free_irq() is stopping the - * thread via kthread_stop() after calling - * synchronize_irq(). So neither IRQTF_RUNTHREAD nor the - * oneshot mask bit can be set. We cannot verify that as we - * cannot touch the oneshot mask at this point anymore as - * __setup_irq() might have given out currents thread_mask - * again. - */ - task_work_cancel(current, irq_thread_dtor); - return 0; -} - -/** - * irq_wake_thread - wake the irq thread for the action identified by dev_id - * @irq: Interrupt line - * @dev_id: Device identity for which the thread should be woken - * - */ -void irq_wake_thread(unsigned int irq, void *dev_id) -{ - struct irq_desc *desc = irq_to_desc(irq); - struct irqaction *action; - unsigned long flags; - - if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc))) - return; - - raw_spin_lock_irqsave(&desc->lock, flags); - for_each_action_of_desc(desc, action) { - if (action->dev_id == dev_id) { - if (action->thread) - __irq_wake_thread(desc, action); - break; - } - } - raw_spin_unlock_irqrestore(&desc->lock, flags); -} -EXPORT_SYMBOL_GPL(irq_wake_thread); - -static int irq_setup_forced_threading(struct irqaction *new) -{ - if (!force_irqthreads) - return 0; - if (new->flags & (IRQF_NO_THREAD | IRQF_PERCPU | IRQF_ONESHOT)) - return 0; - - new->flags |= IRQF_ONESHOT; - - /* - * Handle the case where we have a real primary handler and a - * thread handler. We force thread them as well by creating a - * secondary action. - */ - if (new->handler != irq_default_primary_handler && new->thread_fn) { - /* Allocate the secondary action */ - new->secondary = kzalloc(sizeof(struct irqaction), GFP_KERNEL); - if (!new->secondary) - return -ENOMEM; - new->secondary->handler = irq_forced_secondary_handler; - new->secondary->thread_fn = new->thread_fn; - new->secondary->dev_id = new->dev_id; - new->secondary->irq = new->irq; - new->secondary->name = new->name; - } - /* Deal with the primary handler */ - set_bit(IRQTF_FORCED_THREAD, &new->thread_flags); - new->thread_fn = new->handler; - new->handler = irq_default_primary_handler; - return 0; -} - -static int irq_request_resources(struct irq_desc *desc) -{ - struct irq_data *d = &desc->irq_data; - struct irq_chip *c = d->chip; - - return c->irq_request_resources ? c->irq_request_resources(d) : 0; -} - -static void irq_release_resources(struct irq_desc *desc) -{ - struct irq_data *d = &desc->irq_data; - struct irq_chip *c = d->chip; - - if (c->irq_release_resources) - c->irq_release_resources(d); -} - -static int -setup_irq_thread(struct irqaction *new, unsigned int irq, bool secondary) -{ - struct task_struct *t; - struct sched_param param = { - .sched_priority = MAX_USER_RT_PRIO/2, - }; - - if (!secondary) { - t = kthread_create(irq_thread, new, "irq/%d-%s", irq, - new->name); - } else { - t = kthread_create(irq_thread, new, "irq/%d-s-%s", irq, - new->name); - param.sched_priority -= 1; - } - - if (IS_ERR(t)) - return PTR_ERR(t); - - sched_setscheduler_nocheck(t, SCHED_FIFO, ¶m); - - /* - * We keep the reference to the task struct even if - * the thread dies to avoid that the interrupt code - * references an already freed task_struct. - */ - get_task_struct(t); - new->thread = t; - /* - * Tell the thread to set its affinity. This is - * important for shared interrupt handlers as we do - * not invoke setup_affinity() for the secondary - * handlers as everything is already set up. Even for - * interrupts marked with IRQF_NO_BALANCE this is - * correct as we want the thread to move to the cpu(s) - * on which the requesting code placed the interrupt. - */ - set_bit(IRQTF_AFFINITY, &new->thread_flags); - return 0; -} - -/* - * Internal function to register an irqaction - typically used to - * allocate special interrupts that are part of the architecture. - */ -static int -__setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) -{ - struct irqaction *old, **old_ptr; - unsigned long flags, thread_mask = 0; - int ret, nested, shared = 0; - cpumask_var_t mask; - - if (!desc) - return -EINVAL; - - if (desc->irq_data.chip == &no_irq_chip) - return -ENOSYS; - if (!try_module_get(desc->owner)) - return -ENODEV; - - new->irq = irq; - - /* - * If the trigger type is not specified by the caller, - * then use the default for this interrupt. - */ - if (!(new->flags & IRQF_TRIGGER_MASK)) - new->flags |= irqd_get_trigger_type(&desc->irq_data); - - /* - * Check whether the interrupt nests into another interrupt - * thread. - */ - nested = irq_settings_is_nested_thread(desc); - if (nested) { - if (!new->thread_fn) { - ret = -EINVAL; - goto out_mput; - } - /* - * Replace the primary handler which was provided from - * the driver for non nested interrupt handling by the - * dummy function which warns when called. - */ - new->handler = irq_nested_primary_handler; - } else { - if (irq_settings_can_thread(desc)) { - ret = irq_setup_forced_threading(new); - if (ret) - goto out_mput; - } - } - - /* - * Create a handler thread when a thread function is supplied - * and the interrupt does not nest into another interrupt - * thread. - */ - if (new->thread_fn && !nested) { - ret = setup_irq_thread(new, irq, false); - if (ret) - goto out_mput; - if (new->secondary) { - ret = setup_irq_thread(new->secondary, irq, true); - if (ret) - goto out_thread; - } - } - - if (!alloc_cpumask_var(&mask, GFP_KERNEL)) { - ret = -ENOMEM; - goto out_thread; - } - - /* - * Drivers are often written to work w/o knowledge about the - * underlying irq chip implementation, so a request for a - * threaded irq without a primary hard irq context handler - * requires the ONESHOT flag to be set. Some irq chips like - * MSI based interrupts are per se one shot safe. Check the - * chip flags, so we can avoid the unmask dance at the end of - * the threaded handler for those. - */ - if (desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE) - new->flags &= ~IRQF_ONESHOT; - - /* - * The following block of code has to be executed atomically - */ - raw_spin_lock_irqsave(&desc->lock, flags); - old_ptr = &desc->action; - old = *old_ptr; - if (old) { - /* - * Can't share interrupts unless both agree to and are - * the same type (level, edge, polarity). So both flag - * fields must have IRQF_SHARED set and the bits which - * set the trigger type must match. Also all must - * agree on ONESHOT. - */ - if (!((old->flags & new->flags) & IRQF_SHARED) || - ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK) || - ((old->flags ^ new->flags) & IRQF_ONESHOT)) - goto mismatch; - - /* All handlers must agree on per-cpuness */ - if ((old->flags & IRQF_PERCPU) != - (new->flags & IRQF_PERCPU)) - goto mismatch; - - /* add new interrupt at end of irq queue */ - do { - /* - * Or all existing action->thread_mask bits, - * so we can find the next zero bit for this - * new action. - */ - thread_mask |= old->thread_mask; - old_ptr = &old->next; - old = *old_ptr; - } while (old); - shared = 1; - } - - /* - * Setup the thread mask for this irqaction for ONESHOT. For - * !ONESHOT irqs the thread mask is 0 so we can avoid a - * conditional in irq_wake_thread(). - */ - if (new->flags & IRQF_ONESHOT) { - /* - * Unlikely to have 32 resp 64 irqs sharing one line, - * but who knows. - */ - if (thread_mask == ~0UL) { - ret = -EBUSY; - goto out_mask; - } - /* - * The thread_mask for the action is or'ed to - * desc->thread_active to indicate that the - * IRQF_ONESHOT thread handler has been woken, but not - * yet finished. The bit is cleared when a thread - * completes. When all threads of a shared interrupt - * line have completed desc->threads_active becomes - * zero and the interrupt line is unmasked. See - * handle.c:irq_wake_thread() for further information. - * - * If no thread is woken by primary (hard irq context) - * interrupt handlers, then desc->threads_active is - * also checked for zero to unmask the irq line in the - * affected hard irq flow handlers - * (handle_[fasteoi|level]_irq). - * - * The new action gets the first zero bit of - * thread_mask assigned. See the loop above which or's - * all existing action->thread_mask bits. - */ - new->thread_mask = 1 << ffz(thread_mask); - - } else if (new->handler == irq_default_primary_handler && - !(desc->irq_data.chip->flags & IRQCHIP_ONESHOT_SAFE)) { - /* - * The interrupt was requested with handler = NULL, so - * we use the default primary handler for it. But it - * does not have the oneshot flag set. In combination - * with level interrupts this is deadly, because the - * default primary handler just wakes the thread, then - * the irq lines is reenabled, but the device still - * has the level irq asserted. Rinse and repeat.... - * - * While this works for edge type interrupts, we play - * it safe and reject unconditionally because we can't - * say for sure which type this interrupt really - * has. The type flags are unreliable as the - * underlying chip implementation can override them. - */ - pr_err("Threaded irq requested with handler=NULL and !ONESHOT for irq %d\n", - irq); - ret = -EINVAL; - goto out_mask; - } - - if (!shared) { - ret = irq_request_resources(desc); - if (ret) { - pr_err("Failed to request resources for %s (irq %d) on irqchip %s\n", - new->name, irq, desc->irq_data.chip->name); - goto out_mask; - } - - init_waitqueue_head(&desc->wait_for_threads); - - /* Setup the type (level, edge polarity) if configured: */ - if (new->flags & IRQF_TRIGGER_MASK) { - ret = __irq_set_trigger(desc, - new->flags & IRQF_TRIGGER_MASK); - - if (ret) - goto out_mask; - } - - desc->istate &= ~(IRQS_AUTODETECT | IRQS_SPURIOUS_DISABLED | \ - IRQS_ONESHOT | IRQS_WAITING); - irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS); - - if (new->flags & IRQF_PERCPU) { - irqd_set(&desc->irq_data, IRQD_PER_CPU); - irq_settings_set_per_cpu(desc); - } - - if (new->flags & IRQF_ONESHOT) - desc->istate |= IRQS_ONESHOT; - - if (irq_settings_can_autoenable(desc)) - irq_startup(desc, true); - else - /* Undo nested disables: */ - desc->depth = 1; - - /* Exclude IRQ from balancing if requested */ - if (new->flags & IRQF_NOBALANCING) { - irq_settings_set_no_balancing(desc); - irqd_set(&desc->irq_data, IRQD_NO_BALANCING); - } - - /* Set default affinity mask once everything is setup */ - setup_affinity(desc, mask); - - } else if (new->flags & IRQF_TRIGGER_MASK) { - unsigned int nmsk = new->flags & IRQF_TRIGGER_MASK; - unsigned int omsk = irqd_get_trigger_type(&desc->irq_data); - - if (nmsk != omsk) - /* hope the handler works with current trigger mode */ - pr_warn("irq %d uses trigger mode %u; requested %u\n", - irq, omsk, nmsk); - } - - *old_ptr = new; - - irq_pm_install_action(desc, new); - - /* Reset broken irq detection when installing new handler */ - desc->irq_count = 0; - desc->irqs_unhandled = 0; - - /* - * Check whether we disabled the irq via the spurious handler - * before. Reenable it and give it another chance. - */ - if (shared && (desc->istate & IRQS_SPURIOUS_DISABLED)) { - desc->istate &= ~IRQS_SPURIOUS_DISABLED; - __enable_irq(desc); - } - - raw_spin_unlock_irqrestore(&desc->lock, flags); - - /* - * Strictly no need to wake it up, but hung_task complains - * when no hard interrupt wakes the thread up. - */ - if (new->thread) - wake_up_process(new->thread); - if (new->secondary) - wake_up_process(new->secondary->thread); - - register_irq_proc(irq, desc); - new->dir = NULL; - register_handler_proc(irq, new); - free_cpumask_var(mask); - - return 0; - -mismatch: - if (!(new->flags & IRQF_PROBE_SHARED)) { - pr_err("Flags mismatch irq %d. %08x (%s) vs. %08x (%s)\n", - irq, new->flags, new->name, old->flags, old->name); -#ifdef CONFIG_DEBUG_SHIRQ - dump_stack(); -#endif - } - ret = -EBUSY; - -out_mask: - raw_spin_unlock_irqrestore(&desc->lock, flags); - free_cpumask_var(mask); - -out_thread: - if (new->thread) { - struct task_struct *t = new->thread; - - new->thread = NULL; - kthread_stop(t); - put_task_struct(t); - } - if (new->secondary && new->secondary->thread) { - struct task_struct *t = new->secondary->thread; - - new->secondary->thread = NULL; - kthread_stop(t); - put_task_struct(t); - } -out_mput: - module_put(desc->owner); - return ret; -} - -/** - * setup_irq - setup an interrupt - * @irq: Interrupt line to setup - * @act: irqaction for the interrupt - * - * Used to statically setup interrupts in the early boot process. - */ -int setup_irq(unsigned int irq, struct irqaction *act) -{ - int retval; - struct irq_desc *desc = irq_to_desc(irq); - - if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc))) - return -EINVAL; - - retval = irq_chip_pm_get(&desc->irq_data); - if (retval < 0) - return retval; - - chip_bus_lock(desc); - retval = __setup_irq(irq, desc, act); - chip_bus_sync_unlock(desc); - - if (retval) - irq_chip_pm_put(&desc->irq_data); - - return retval; -} -EXPORT_SYMBOL_GPL(setup_irq); - -/* - * Internal function to unregister an irqaction - used to free - * regular and special interrupts that are part of the architecture. - */ -static struct irqaction *__free_irq(unsigned int irq, void *dev_id) -{ - struct irq_desc *desc = irq_to_desc(irq); - struct irqaction *action, **action_ptr; - unsigned long flags; - - WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq); - - if (!desc) - return NULL; - - chip_bus_lock(desc); - raw_spin_lock_irqsave(&desc->lock, flags); - - /* - * There can be multiple actions per IRQ descriptor, find the right - * one based on the dev_id: - */ - action_ptr = &desc->action; - for (;;) { - action = *action_ptr; - - if (!action) { - WARN(1, "Trying to free already-free IRQ %d\n", irq); - raw_spin_unlock_irqrestore(&desc->lock, flags); - chip_bus_sync_unlock(desc); - return NULL; - } - - if (action->dev_id == dev_id) - break; - action_ptr = &action->next; - } - - /* Found it - now remove it from the list of entries: */ - *action_ptr = action->next; - - irq_pm_remove_action(desc, action); - - /* If this was the last handler, shut down the IRQ line: */ - if (!desc->action) { - irq_settings_clr_disable_unlazy(desc); - irq_shutdown(desc); - irq_release_resources(desc); - } - -#ifdef CONFIG_SMP - /* make sure affinity_hint is cleaned up */ - if (WARN_ON_ONCE(desc->affinity_hint)) - desc->affinity_hint = NULL; -#endif - - raw_spin_unlock_irqrestore(&desc->lock, flags); - chip_bus_sync_unlock(desc); - - unregister_handler_proc(irq, action); - - /* Make sure it's not being used on another CPU: */ - synchronize_irq(irq); - -#ifdef CONFIG_DEBUG_SHIRQ - /* - * It's a shared IRQ -- the driver ought to be prepared for an IRQ - * event to happen even now it's being freed, so let's make sure that - * is so by doing an extra call to the handler .... - * - * ( We do this after actually deregistering it, to make sure that a - * 'real' IRQ doesn't run in * parallel with our fake. ) - */ - if (action->flags & IRQF_SHARED) { - local_irq_save(flags); - action->handler(irq, dev_id); - local_irq_restore(flags); - } -#endif - - if (action->thread) { - kthread_stop(action->thread); - put_task_struct(action->thread); - if (action->secondary && action->secondary->thread) { - kthread_stop(action->secondary->thread); - put_task_struct(action->secondary->thread); - } - } - - irq_chip_pm_put(&desc->irq_data); - module_put(desc->owner); - kfree(action->secondary); - return action; -} - -/** - * remove_irq - free an interrupt - * @irq: Interrupt line to free - * @act: irqaction for the interrupt - * - * Used to remove interrupts statically setup by the early boot process. - */ -void remove_irq(unsigned int irq, struct irqaction *act) -{ - struct irq_desc *desc = irq_to_desc(irq); - - if (desc && !WARN_ON(irq_settings_is_per_cpu_devid(desc))) - __free_irq(irq, act->dev_id); -} -EXPORT_SYMBOL_GPL(remove_irq); - -/** - * free_irq - free an interrupt allocated with request_irq - * @irq: Interrupt line to free - * @dev_id: Device identity to free - * - * Remove an interrupt handler. The handler is removed and if the - * interrupt line is no longer in use by any driver it is disabled. - * On a shared IRQ the caller must ensure the interrupt is disabled - * on the card it drives before calling this function. The function - * does not return until any executing interrupts for this IRQ - * have completed. - * - * This function must not be called from interrupt context. - */ -void free_irq(unsigned int irq, void *dev_id) -{ - struct irq_desc *desc = irq_to_desc(irq); - - if (!desc || WARN_ON(irq_settings_is_per_cpu_devid(desc))) - return; - -#ifdef CONFIG_SMP - if (WARN_ON(desc->affinity_notify)) - desc->affinity_notify = NULL; -#endif - - kfree(__free_irq(irq, dev_id)); -} -EXPORT_SYMBOL(free_irq); - -/** - * request_threaded_irq - allocate an interrupt line - * @irq: Interrupt line to allocate - * @handler: Function to be called when the IRQ occurs. - * Primary handler for threaded interrupts - * If NULL and thread_fn != NULL the default - * primary handler is installed - * @thread_fn: Function called from the irq handler thread - * If NULL, no irq thread is created - * @irqflags: Interrupt type flags - * @devname: An ascii name for the claiming device - * @dev_id: A cookie passed back to the handler function - * - * This call allocates interrupt resources and enables the - * interrupt line and IRQ handling. From the point this - * call is made your handler function may be invoked. Since - * your handler function must clear any interrupt the board - * raises, you must take care both to initialise your hardware - * and to set up the interrupt handler in the right order. - * - * If you want to set up a threaded irq handler for your device - * then you need to supply @handler and @thread_fn. @handler is - * still called in hard interrupt context and has to check - * whether the interrupt originates from the device. If yes it - * needs to disable the interrupt on the device and return - * IRQ_WAKE_THREAD which will wake up the handler thread and run - * @thread_fn. This split handler design is necessary to support - * shared interrupts. - * - * Dev_id must be globally unique. Normally the address of the - * device data structure is used as the cookie. Since the handler - * receives this value it makes sense to use it. - * - * If your interrupt is shared you must pass a non NULL dev_id - * as this is required when freeing the interrupt. - * - * Flags: - * - * IRQF_SHARED Interrupt is shared - * IRQF_TRIGGER_* Specify active edge(s) or level - * - */ -int request_threaded_irq(unsigned int irq, irq_handler_t handler, - irq_handler_t thread_fn, unsigned long irqflags, - const char *devname, void *dev_id) -{ - struct irqaction *action; - struct irq_desc *desc; - int retval; - - if (irq == IRQ_NOTCONNECTED) - return -ENOTCONN; - - /* - * Sanity-check: shared interrupts must pass in a real dev-ID, - * otherwise we'll have trouble later trying to figure out - * which interrupt is which (messes up the interrupt freeing - * logic etc). - * - * Also IRQF_COND_SUSPEND only makes sense for shared interrupts and - * it cannot be set along with IRQF_NO_SUSPEND. - */ - if (((irqflags & IRQF_SHARED) && !dev_id) || - (!(irqflags & IRQF_SHARED) && (irqflags & IRQF_COND_SUSPEND)) || - ((irqflags & IRQF_NO_SUSPEND) && (irqflags & IRQF_COND_SUSPEND))) - return -EINVAL; - - desc = irq_to_desc(irq); - if (!desc) - return -EINVAL; - - if (!irq_settings_can_request(desc) || - WARN_ON(irq_settings_is_per_cpu_devid(desc))) - return -EINVAL; - - if (!handler) { - if (!thread_fn) - return -EINVAL; - handler = irq_default_primary_handler; - } - - action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); - if (!action) - return -ENOMEM; - - action->handler = handler; - action->thread_fn = thread_fn; - action->flags = irqflags; - action->name = devname; - action->dev_id = dev_id; - - retval = irq_chip_pm_get(&desc->irq_data); - if (retval < 0) { - kfree(action); - return retval; - } - - chip_bus_lock(desc); - retval = __setup_irq(irq, desc, action); - chip_bus_sync_unlock(desc); - - if (retval) { - irq_chip_pm_put(&desc->irq_data); - kfree(action->secondary); - kfree(action); - } - -#ifdef CONFIG_DEBUG_SHIRQ_FIXME - if (!retval && (irqflags & IRQF_SHARED)) { - /* - * It's a shared IRQ -- the driver ought to be prepared for it - * to happen immediately, so let's make sure.... - * We disable the irq to make sure that a 'real' IRQ doesn't - * run in parallel with our fake. - */ - unsigned long flags; - - disable_irq(irq); - local_irq_save(flags); - - handler(irq, dev_id); - - local_irq_restore(flags); - enable_irq(irq); - } -#endif - return retval; -} -EXPORT_SYMBOL(request_threaded_irq); - -/** - * request_any_context_irq - allocate an interrupt line - * @irq: Interrupt line to allocate - * @handler: Function to be called when the IRQ occurs. - * Threaded handler for threaded interrupts. - * @flags: Interrupt type flags - * @name: An ascii name for the claiming device - * @dev_id: A cookie passed back to the handler function - * - * This call allocates interrupt resources and enables the - * interrupt line and IRQ handling. It selects either a - * hardirq or threaded handling method depending on the - * context. - * - * On failure, it returns a negative value. On success, - * it returns either IRQC_IS_HARDIRQ or IRQC_IS_NESTED. - */ -int request_any_context_irq(unsigned int irq, irq_handler_t handler, - unsigned long flags, const char *name, void *dev_id) -{ - struct irq_desc *desc; - int ret; - - if (irq == IRQ_NOTCONNECTED) - return -ENOTCONN; - - desc = irq_to_desc(irq); - if (!desc) - return -EINVAL; - - if (irq_settings_is_nested_thread(desc)) { - ret = request_threaded_irq(irq, NULL, handler, - flags, name, dev_id); - return !ret ? IRQC_IS_NESTED : ret; - } - - ret = request_irq(irq, handler, flags, name, dev_id); - return !ret ? IRQC_IS_HARDIRQ : ret; -} -EXPORT_SYMBOL_GPL(request_any_context_irq); - -void enable_percpu_irq(unsigned int irq, unsigned int type) -{ - unsigned int cpu = smp_processor_id(); - unsigned long flags; - struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_PERCPU); - - if (!desc) - return; - - /* - * If the trigger type is not specified by the caller, then - * use the default for this interrupt. - */ - type &= IRQ_TYPE_SENSE_MASK; - if (type == IRQ_TYPE_NONE) - type = irqd_get_trigger_type(&desc->irq_data); - - if (type != IRQ_TYPE_NONE) { - int ret; - - ret = __irq_set_trigger(desc, type); - - if (ret) { - WARN(1, "failed to set type for IRQ%d\n", irq); - goto out; - } - } - - irq_percpu_enable(desc, cpu); -out: - irq_put_desc_unlock(desc, flags); -} -EXPORT_SYMBOL_GPL(enable_percpu_irq); - -/** - * irq_percpu_is_enabled - Check whether the per cpu irq is enabled - * @irq: Linux irq number to check for - * - * Must be called from a non migratable context. Returns the enable - * state of a per cpu interrupt on the current cpu. - */ -bool irq_percpu_is_enabled(unsigned int irq) -{ - unsigned int cpu = smp_processor_id(); - struct irq_desc *desc; - unsigned long flags; - bool is_enabled; - - desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_PERCPU); - if (!desc) - return false; - - is_enabled = cpumask_test_cpu(cpu, desc->percpu_enabled); - irq_put_desc_unlock(desc, flags); - - return is_enabled; -} -EXPORT_SYMBOL_GPL(irq_percpu_is_enabled); - -void disable_percpu_irq(unsigned int irq) -{ - unsigned int cpu = smp_processor_id(); - unsigned long flags; - struct irq_desc *desc = irq_get_desc_lock(irq, &flags, IRQ_GET_DESC_CHECK_PERCPU); - - if (!desc) - return; - - irq_percpu_disable(desc, cpu); - irq_put_desc_unlock(desc, flags); -} -EXPORT_SYMBOL_GPL(disable_percpu_irq); - -/* - * Internal function to unregister a percpu irqaction. - */ -static struct irqaction *__free_percpu_irq(unsigned int irq, void __percpu *dev_id) -{ - struct irq_desc *desc = irq_to_desc(irq); - struct irqaction *action; - unsigned long flags; - - WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq); - - if (!desc) - return NULL; - - raw_spin_lock_irqsave(&desc->lock, flags); - - action = desc->action; - if (!action || action->percpu_dev_id != dev_id) { - WARN(1, "Trying to free already-free IRQ %d\n", irq); - goto bad; - } - - if (!cpumask_empty(desc->percpu_enabled)) { - WARN(1, "percpu IRQ %d still enabled on CPU%d!\n", - irq, cpumask_first(desc->percpu_enabled)); - goto bad; - } - - /* Found it - now remove it from the list of entries: */ - desc->action = NULL; - - raw_spin_unlock_irqrestore(&desc->lock, flags); - - unregister_handler_proc(irq, action); - - irq_chip_pm_put(&desc->irq_data); - module_put(desc->owner); - return action; - -bad: - raw_spin_unlock_irqrestore(&desc->lock, flags); - return NULL; -} - -/** - * remove_percpu_irq - free a per-cpu interrupt - * @irq: Interrupt line to free - * @act: irqaction for the interrupt - * - * Used to remove interrupts statically setup by the early boot process. - */ -void remove_percpu_irq(unsigned int irq, struct irqaction *act) -{ - struct irq_desc *desc = irq_to_desc(irq); - - if (desc && irq_settings_is_per_cpu_devid(desc)) - __free_percpu_irq(irq, act->percpu_dev_id); -} - -/** - * free_percpu_irq - free an interrupt allocated with request_percpu_irq - * @irq: Interrupt line to free - * @dev_id: Device identity to free - * - * Remove a percpu interrupt handler. The handler is removed, but - * the interrupt line is not disabled. This must be done on each - * CPU before calling this function. The function does not return - * until any executing interrupts for this IRQ have completed. - * - * This function must not be called from interrupt context. - */ -void free_percpu_irq(unsigned int irq, void __percpu *dev_id) -{ - struct irq_desc *desc = irq_to_desc(irq); - - if (!desc || !irq_settings_is_per_cpu_devid(desc)) - return; - - chip_bus_lock(desc); - kfree(__free_percpu_irq(irq, dev_id)); - chip_bus_sync_unlock(desc); -} -EXPORT_SYMBOL_GPL(free_percpu_irq); - -/** - * setup_percpu_irq - setup a per-cpu interrupt - * @irq: Interrupt line to setup - * @act: irqaction for the interrupt - * - * Used to statically setup per-cpu interrupts in the early boot process. - */ -int setup_percpu_irq(unsigned int irq, struct irqaction *act) -{ - struct irq_desc *desc = irq_to_desc(irq); - int retval; - - if (!desc || !irq_settings_is_per_cpu_devid(desc)) - return -EINVAL; - - retval = irq_chip_pm_get(&desc->irq_data); - if (retval < 0) - return retval; - - chip_bus_lock(desc); - retval = __setup_irq(irq, desc, act); - chip_bus_sync_unlock(desc); - - if (retval) - irq_chip_pm_put(&desc->irq_data); - - return retval; -} - -/** - * request_percpu_irq - allocate a percpu interrupt line - * @irq: Interrupt line to allocate - * @handler: Function to be called when the IRQ occurs. - * @devname: An ascii name for the claiming device - * @dev_id: A percpu cookie passed back to the handler function - * - * This call allocates interrupt resources and enables the - * interrupt on the local CPU. If the interrupt is supposed to be - * enabled on other CPUs, it has to be done on each CPU using - * enable_percpu_irq(). - * - * Dev_id must be globally unique. It is a per-cpu variable, and - * the handler gets called with the interrupted CPU's instance of - * that variable. - */ -int request_percpu_irq(unsigned int irq, irq_handler_t handler, - const char *devname, void __percpu *dev_id) -{ - struct irqaction *action; - struct irq_desc *desc; - int retval; - - if (!dev_id) - return -EINVAL; - - desc = irq_to_desc(irq); - if (!desc || !irq_settings_can_request(desc) || - !irq_settings_is_per_cpu_devid(desc)) - return -EINVAL; - - action = kzalloc(sizeof(struct irqaction), GFP_KERNEL); - if (!action) - return -ENOMEM; - - action->handler = handler; - action->flags = IRQF_PERCPU | IRQF_NO_SUSPEND; - action->name = devname; - action->percpu_dev_id = dev_id; - - retval = irq_chip_pm_get(&desc->irq_data); - if (retval < 0) { - kfree(action); - return retval; - } - - chip_bus_lock(desc); - retval = __setup_irq(irq, desc, action); - chip_bus_sync_unlock(desc); - - if (retval) { - irq_chip_pm_put(&desc->irq_data); - kfree(action); - } - - return retval; -} -EXPORT_SYMBOL_GPL(request_percpu_irq); - -/** - * irq_get_irqchip_state - returns the irqchip state of a interrupt. - * @irq: Interrupt line that is forwarded to a VM - * @which: One of IRQCHIP_STATE_* the caller wants to know about - * @state: a pointer to a boolean where the state is to be storeed - * - * This call snapshots the internal irqchip state of an - * interrupt, returning into @state the bit corresponding to - * stage @which - * - * This function should be called with preemption disabled if the - * interrupt controller has per-cpu registers. - */ -int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which, - bool *state) -{ - struct irq_desc *desc; - struct irq_data *data; - struct irq_chip *chip; - unsigned long flags; - int err = -EINVAL; - - desc = irq_get_desc_buslock(irq, &flags, 0); - if (!desc) - return err; - - data = irq_desc_get_irq_data(desc); - - do { - chip = irq_data_get_irq_chip(data); - if (chip->irq_get_irqchip_state) - break; -#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY - data = data->parent_data; -#else - data = NULL; -#endif - } while (data); - - if (data) - err = chip->irq_get_irqchip_state(data, which, state); - - irq_put_desc_busunlock(desc, flags); - return err; -} -EXPORT_SYMBOL_GPL(irq_get_irqchip_state); - -/** - * irq_set_irqchip_state - set the state of a forwarded interrupt. - * @irq: Interrupt line that is forwarded to a VM - * @which: State to be restored (one of IRQCHIP_STATE_*) - * @val: Value corresponding to @which - * - * This call sets the internal irqchip state of an interrupt, - * depending on the value of @which. - * - * This function should be called with preemption disabled if the - * interrupt controller has per-cpu registers. - */ -int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which, - bool val) -{ - struct irq_desc *desc; - struct irq_data *data; - struct irq_chip *chip; - unsigned long flags; - int err = -EINVAL; - - desc = irq_get_desc_buslock(irq, &flags, 0); - if (!desc) - return err; - - data = irq_desc_get_irq_data(desc); - - do { - chip = irq_data_get_irq_chip(data); - if (chip->irq_set_irqchip_state) - break; -#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY - data = data->parent_data; -#else - data = NULL; -#endif - } while (data); - - if (data) - err = chip->irq_set_irqchip_state(data, which, val); - - irq_put_desc_busunlock(desc, flags); - return err; -} -EXPORT_SYMBOL_GPL(irq_set_irqchip_state); diff --git a/src/linux/kernel/irq/proc.c b/src/linux/kernel/irq/proc.c deleted file mode 100644 index feaa813..0000000 --- a/src/linux/kernel/irq/proc.c +++ /dev/null @@ -1,509 +0,0 @@ -/* - * linux/kernel/irq/proc.c - * - * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar - * - * This file contains the /proc/irq/ handling code. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "internals.h" - -/* - * Access rules: - * - * procfs protects read/write of /proc/irq/N/ files against a - * concurrent free of the interrupt descriptor. remove_proc_entry() - * immediately prevents new read/writes to happen and waits for - * already running read/write functions to complete. - * - * We remove the proc entries first and then delete the interrupt - * descriptor from the radix tree and free it. So it is guaranteed - * that irq_to_desc(N) is valid as long as the read/writes are - * permitted by procfs. - * - * The read from /proc/interrupts is a different problem because there - * is no protection. So the lookup and the access to irqdesc - * information must be protected by sparse_irq_lock. - */ -static struct proc_dir_entry *root_irq_dir; - -#ifdef CONFIG_SMP - -static int show_irq_affinity(int type, struct seq_file *m, void *v) -{ - struct irq_desc *desc = irq_to_desc((long)m->private); - const struct cpumask *mask = desc->irq_common_data.affinity; - -#ifdef CONFIG_GENERIC_PENDING_IRQ - if (irqd_is_setaffinity_pending(&desc->irq_data)) - mask = desc->pending_mask; -#endif - if (type) - seq_printf(m, "%*pbl\n", cpumask_pr_args(mask)); - else - seq_printf(m, "%*pb\n", cpumask_pr_args(mask)); - return 0; -} - -static int irq_affinity_hint_proc_show(struct seq_file *m, void *v) -{ - struct irq_desc *desc = irq_to_desc((long)m->private); - unsigned long flags; - cpumask_var_t mask; - - if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) - return -ENOMEM; - - raw_spin_lock_irqsave(&desc->lock, flags); - if (desc->affinity_hint) - cpumask_copy(mask, desc->affinity_hint); - raw_spin_unlock_irqrestore(&desc->lock, flags); - - seq_printf(m, "%*pb\n", cpumask_pr_args(mask)); - free_cpumask_var(mask); - - return 0; -} - -#ifndef is_affinity_mask_valid -#define is_affinity_mask_valid(val) 1 -#endif - -int no_irq_affinity; -static int irq_affinity_proc_show(struct seq_file *m, void *v) -{ - return show_irq_affinity(0, m, v); -} - -static int irq_affinity_list_proc_show(struct seq_file *m, void *v) -{ - return show_irq_affinity(1, m, v); -} - - -static ssize_t write_irq_affinity(int type, struct file *file, - const char __user *buffer, size_t count, loff_t *pos) -{ - unsigned int irq = (int)(long)PDE_DATA(file_inode(file)); - cpumask_var_t new_value; - int err; - - if (!irq_can_set_affinity_usr(irq) || no_irq_affinity) - return -EIO; - - if (!alloc_cpumask_var(&new_value, GFP_KERNEL)) - return -ENOMEM; - - if (type) - err = cpumask_parselist_user(buffer, count, new_value); - else - err = cpumask_parse_user(buffer, count, new_value); - if (err) - goto free_cpumask; - - if (!is_affinity_mask_valid(new_value)) { - err = -EINVAL; - goto free_cpumask; - } - - /* - * Do not allow disabling IRQs completely - it's a too easy - * way to make the system unusable accidentally :-) At least - * one online CPU still has to be targeted. - */ - if (!cpumask_intersects(new_value, cpu_online_mask)) { - /* Special case for empty set - allow the architecture - code to set default SMP affinity. */ - err = irq_select_affinity_usr(irq, new_value) ? -EINVAL : count; - } else { - irq_set_affinity(irq, new_value); - err = count; - } - -free_cpumask: - free_cpumask_var(new_value); - return err; -} - -static ssize_t irq_affinity_proc_write(struct file *file, - const char __user *buffer, size_t count, loff_t *pos) -{ - return write_irq_affinity(0, file, buffer, count, pos); -} - -static ssize_t irq_affinity_list_proc_write(struct file *file, - const char __user *buffer, size_t count, loff_t *pos) -{ - return write_irq_affinity(1, file, buffer, count, pos); -} - -static int irq_affinity_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, irq_affinity_proc_show, PDE_DATA(inode)); -} - -static int irq_affinity_list_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, irq_affinity_list_proc_show, PDE_DATA(inode)); -} - -static int irq_affinity_hint_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, irq_affinity_hint_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations irq_affinity_proc_fops = { - .open = irq_affinity_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = irq_affinity_proc_write, -}; - -static const struct file_operations irq_affinity_hint_proc_fops = { - .open = irq_affinity_hint_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static const struct file_operations irq_affinity_list_proc_fops = { - .open = irq_affinity_list_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = irq_affinity_list_proc_write, -}; - -static int default_affinity_show(struct seq_file *m, void *v) -{ - seq_printf(m, "%*pb\n", cpumask_pr_args(irq_default_affinity)); - return 0; -} - -static ssize_t default_affinity_write(struct file *file, - const char __user *buffer, size_t count, loff_t *ppos) -{ - cpumask_var_t new_value; - int err; - - if (!alloc_cpumask_var(&new_value, GFP_KERNEL)) - return -ENOMEM; - - err = cpumask_parse_user(buffer, count, new_value); - if (err) - goto out; - - if (!is_affinity_mask_valid(new_value)) { - err = -EINVAL; - goto out; - } - - /* - * Do not allow disabling IRQs completely - it's a too easy - * way to make the system unusable accidentally :-) At least - * one online CPU still has to be targeted. - */ - if (!cpumask_intersects(new_value, cpu_online_mask)) { - err = -EINVAL; - goto out; - } - - cpumask_copy(irq_default_affinity, new_value); - err = count; - -out: - free_cpumask_var(new_value); - return err; -} - -static int default_affinity_open(struct inode *inode, struct file *file) -{ - return single_open(file, default_affinity_show, PDE_DATA(inode)); -} - -static const struct file_operations default_affinity_proc_fops = { - .open = default_affinity_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, - .write = default_affinity_write, -}; - -static int irq_node_proc_show(struct seq_file *m, void *v) -{ - struct irq_desc *desc = irq_to_desc((long) m->private); - - seq_printf(m, "%d\n", irq_desc_get_node(desc)); - return 0; -} - -static int irq_node_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, irq_node_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations irq_node_proc_fops = { - .open = irq_node_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -#endif - -static int irq_spurious_proc_show(struct seq_file *m, void *v) -{ - struct irq_desc *desc = irq_to_desc((long) m->private); - - seq_printf(m, "count %u\n" "unhandled %u\n" "last_unhandled %u ms\n", - desc->irq_count, desc->irqs_unhandled, - jiffies_to_msecs(desc->last_unhandled)); - return 0; -} - -static int irq_spurious_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, irq_spurious_proc_show, PDE_DATA(inode)); -} - -static const struct file_operations irq_spurious_proc_fops = { - .open = irq_spurious_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -#define MAX_NAMELEN 128 - -static int name_unique(unsigned int irq, struct irqaction *new_action) -{ - struct irq_desc *desc = irq_to_desc(irq); - struct irqaction *action; - unsigned long flags; - int ret = 1; - - raw_spin_lock_irqsave(&desc->lock, flags); - for_each_action_of_desc(desc, action) { - if ((action != new_action) && action->name && - !strcmp(new_action->name, action->name)) { - ret = 0; - break; - } - } - raw_spin_unlock_irqrestore(&desc->lock, flags); - return ret; -} - -void register_handler_proc(unsigned int irq, struct irqaction *action) -{ - char name [MAX_NAMELEN]; - struct irq_desc *desc = irq_to_desc(irq); - - if (!desc->dir || action->dir || !action->name || - !name_unique(irq, action)) - return; - - snprintf(name, MAX_NAMELEN, "%s", action->name); - - /* create /proc/irq/1234/handler/ */ - action->dir = proc_mkdir(name, desc->dir); -} - -#undef MAX_NAMELEN - -#define MAX_NAMELEN 10 - -void register_irq_proc(unsigned int irq, struct irq_desc *desc) -{ - static DEFINE_MUTEX(register_lock); - char name [MAX_NAMELEN]; - - if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip)) - return; - - /* - * irq directories are registered only when a handler is - * added, not when the descriptor is created, so multiple - * tasks might try to register at the same time. - */ - mutex_lock(®ister_lock); - - if (desc->dir) - goto out_unlock; - - sprintf(name, "%d", irq); - - /* create /proc/irq/1234 */ - desc->dir = proc_mkdir(name, root_irq_dir); - if (!desc->dir) - goto out_unlock; - -#ifdef CONFIG_SMP - /* create /proc/irq//smp_affinity */ - proc_create_data("smp_affinity", 0644, desc->dir, - &irq_affinity_proc_fops, (void *)(long)irq); - - /* create /proc/irq//affinity_hint */ - proc_create_data("affinity_hint", 0444, desc->dir, - &irq_affinity_hint_proc_fops, (void *)(long)irq); - - /* create /proc/irq//smp_affinity_list */ - proc_create_data("smp_affinity_list", 0644, desc->dir, - &irq_affinity_list_proc_fops, (void *)(long)irq); - - proc_create_data("node", 0444, desc->dir, - &irq_node_proc_fops, (void *)(long)irq); -#endif - - proc_create_data("spurious", 0444, desc->dir, - &irq_spurious_proc_fops, (void *)(long)irq); - -out_unlock: - mutex_unlock(®ister_lock); -} - -void unregister_irq_proc(unsigned int irq, struct irq_desc *desc) -{ - char name [MAX_NAMELEN]; - - if (!root_irq_dir || !desc->dir) - return; -#ifdef CONFIG_SMP - remove_proc_entry("smp_affinity", desc->dir); - remove_proc_entry("affinity_hint", desc->dir); - remove_proc_entry("smp_affinity_list", desc->dir); - remove_proc_entry("node", desc->dir); -#endif - remove_proc_entry("spurious", desc->dir); - - sprintf(name, "%u", irq); - remove_proc_entry(name, root_irq_dir); -} - -#undef MAX_NAMELEN - -void unregister_handler_proc(unsigned int irq, struct irqaction *action) -{ - proc_remove(action->dir); -} - -static void register_default_affinity_proc(void) -{ -#ifdef CONFIG_SMP - proc_create("irq/default_smp_affinity", 0644, NULL, - &default_affinity_proc_fops); -#endif -} - -void init_irq_proc(void) -{ - unsigned int irq; - struct irq_desc *desc; - - /* create /proc/irq */ - root_irq_dir = proc_mkdir("irq", NULL); - if (!root_irq_dir) - return; - - register_default_affinity_proc(); - - /* - * Create entries for all existing IRQs. - */ - for_each_irq_desc(irq, desc) - register_irq_proc(irq, desc); -} - -#ifdef CONFIG_GENERIC_IRQ_SHOW - -int __weak arch_show_interrupts(struct seq_file *p, int prec) -{ - return 0; -} - -#ifndef ACTUAL_NR_IRQS -# define ACTUAL_NR_IRQS nr_irqs -#endif - -int show_interrupts(struct seq_file *p, void *v) -{ - static int prec; - - unsigned long flags, any_count = 0; - int i = *(loff_t *) v, j; - struct irqaction *action; - struct irq_desc *desc; - - if (i > ACTUAL_NR_IRQS) - return 0; - - if (i == ACTUAL_NR_IRQS) - return arch_show_interrupts(p, prec); - - /* print header and calculate the width of the first column */ - if (i == 0) { - for (prec = 3, j = 1000; prec < 10 && j <= nr_irqs; ++prec) - j *= 10; - - seq_printf(p, "%*s", prec + 8, ""); - for_each_online_cpu(j) - seq_printf(p, "CPU%-8d", j); - seq_putc(p, '\n'); - } - - irq_lock_sparse(); - desc = irq_to_desc(i); - if (!desc) - goto outsparse; - - raw_spin_lock_irqsave(&desc->lock, flags); - for_each_online_cpu(j) - any_count |= kstat_irqs_cpu(i, j); - action = desc->action; - if ((!action || irq_desc_is_chained(desc)) && !any_count) - goto out; - - seq_printf(p, "%*d: ", prec, i); - for_each_online_cpu(j) - seq_printf(p, "%10u ", kstat_irqs_cpu(i, j)); - - if (desc->irq_data.chip) { - if (desc->irq_data.chip->irq_print_chip) - desc->irq_data.chip->irq_print_chip(&desc->irq_data, p); - else if (desc->irq_data.chip->name) - seq_printf(p, " %8s", desc->irq_data.chip->name); - else - seq_printf(p, " %8s", "-"); - } else { - seq_printf(p, " %8s", "None"); - } - if (desc->irq_data.domain) - seq_printf(p, " %*d", prec, (int) desc->irq_data.hwirq); -#ifdef CONFIG_GENERIC_IRQ_SHOW_LEVEL - seq_printf(p, " %-8s", irqd_is_level_type(&desc->irq_data) ? "Level" : "Edge"); -#endif - if (desc->name) - seq_printf(p, "-%-8s", desc->name); - - if (action) { - seq_printf(p, " %s", action->name); - while ((action = action->next) != NULL) - seq_printf(p, ", %s", action->name); - } - - seq_putc(p, '\n'); -out: - raw_spin_unlock_irqrestore(&desc->lock, flags); -outsparse: - irq_unlock_sparse(); - return 0; -} -#endif diff --git a/src/linux/kernel/irq/resend.c b/src/linux/kernel/irq/resend.c deleted file mode 100644 index b86886b..0000000 --- a/src/linux/kernel/irq/resend.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * linux/kernel/irq/resend.c - * - * Copyright (C) 1992, 1998-2006 Linus Torvalds, Ingo Molnar - * Copyright (C) 2005-2006, Thomas Gleixner - * - * This file contains the IRQ-resend code - * - * If the interrupt is waiting to be processed, we try to re-run it. - * We can't directly run it from here since the caller might be in an - * interrupt-protected region. Not all irq controller chips can - * retrigger interrupts at the hardware level, so in those cases - * we allow the resending of IRQs via a tasklet. - */ - -#include -#include -#include -#include - -#include "internals.h" - -#ifdef CONFIG_HARDIRQS_SW_RESEND - -/* Bitmap to handle software resend of interrupts: */ -static DECLARE_BITMAP(irqs_resend, IRQ_BITMAP_BITS); - -/* - * Run software resends of IRQ's - */ -static void resend_irqs(unsigned long arg) -{ - struct irq_desc *desc; - int irq; - - while (!bitmap_empty(irqs_resend, nr_irqs)) { - irq = find_first_bit(irqs_resend, nr_irqs); - clear_bit(irq, irqs_resend); - desc = irq_to_desc(irq); - local_irq_disable(); - desc->handle_irq(desc); - local_irq_enable(); - } -} - -/* Tasklet to handle resend: */ -static DECLARE_TASKLET(resend_tasklet, resend_irqs, 0); - -#endif - -/* - * IRQ resend - * - * Is called with interrupts disabled and desc->lock held. - */ -void check_irq_resend(struct irq_desc *desc) -{ - /* - * We do not resend level type interrupts. Level type - * interrupts are resent by hardware when they are still - * active. Clear the pending bit so suspend/resume does not - * get confused. - */ - if (irq_settings_is_level(desc)) { - desc->istate &= ~IRQS_PENDING; - return; - } - if (desc->istate & IRQS_REPLAY) - return; - if (desc->istate & IRQS_PENDING) { - desc->istate &= ~IRQS_PENDING; - desc->istate |= IRQS_REPLAY; - - if (!desc->irq_data.chip->irq_retrigger || - !desc->irq_data.chip->irq_retrigger(&desc->irq_data)) { -#ifdef CONFIG_HARDIRQS_SW_RESEND - unsigned int irq = irq_desc_get_irq(desc); - - /* - * If the interrupt is running in the thread - * context of the parent irq we need to be - * careful, because we cannot trigger it - * directly. - */ - if (irq_settings_is_nested_thread(desc)) { - /* - * If the parent_irq is valid, we - * retrigger the parent, otherwise we - * do nothing. - */ - if (!desc->parent_irq) - return; - irq = desc->parent_irq; - } - /* Set it pending and activate the softirq: */ - set_bit(irq, irqs_resend); - tasklet_schedule(&resend_tasklet); -#endif - } - } -} diff --git a/src/linux/kernel/irq/settings.h b/src/linux/kernel/irq/settings.h deleted file mode 100644 index 320579d..0000000 --- a/src/linux/kernel/irq/settings.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Internal header to deal with irq_desc->status which will be renamed - * to irq_desc->settings. - */ -enum { - _IRQ_DEFAULT_INIT_FLAGS = IRQ_DEFAULT_INIT_FLAGS, - _IRQ_PER_CPU = IRQ_PER_CPU, - _IRQ_LEVEL = IRQ_LEVEL, - _IRQ_NOPROBE = IRQ_NOPROBE, - _IRQ_NOREQUEST = IRQ_NOREQUEST, - _IRQ_NOTHREAD = IRQ_NOTHREAD, - _IRQ_NOAUTOEN = IRQ_NOAUTOEN, - _IRQ_MOVE_PCNTXT = IRQ_MOVE_PCNTXT, - _IRQ_NO_BALANCING = IRQ_NO_BALANCING, - _IRQ_NESTED_THREAD = IRQ_NESTED_THREAD, - _IRQ_PER_CPU_DEVID = IRQ_PER_CPU_DEVID, - _IRQ_IS_POLLED = IRQ_IS_POLLED, - _IRQ_DISABLE_UNLAZY = IRQ_DISABLE_UNLAZY, - _IRQF_MODIFY_MASK = IRQF_MODIFY_MASK, -}; - -#define IRQ_PER_CPU GOT_YOU_MORON -#define IRQ_NO_BALANCING GOT_YOU_MORON -#define IRQ_LEVEL GOT_YOU_MORON -#define IRQ_NOPROBE GOT_YOU_MORON -#define IRQ_NOREQUEST GOT_YOU_MORON -#define IRQ_NOTHREAD GOT_YOU_MORON -#define IRQ_NOAUTOEN GOT_YOU_MORON -#define IRQ_NESTED_THREAD GOT_YOU_MORON -#define IRQ_PER_CPU_DEVID GOT_YOU_MORON -#define IRQ_IS_POLLED GOT_YOU_MORON -#define IRQ_DISABLE_UNLAZY GOT_YOU_MORON -#undef IRQF_MODIFY_MASK -#define IRQF_MODIFY_MASK GOT_YOU_MORON - -static inline void -irq_settings_clr_and_set(struct irq_desc *desc, u32 clr, u32 set) -{ - desc->status_use_accessors &= ~(clr & _IRQF_MODIFY_MASK); - desc->status_use_accessors |= (set & _IRQF_MODIFY_MASK); -} - -static inline bool irq_settings_is_per_cpu(struct irq_desc *desc) -{ - return desc->status_use_accessors & _IRQ_PER_CPU; -} - -static inline bool irq_settings_is_per_cpu_devid(struct irq_desc *desc) -{ - return desc->status_use_accessors & _IRQ_PER_CPU_DEVID; -} - -static inline void irq_settings_set_per_cpu(struct irq_desc *desc) -{ - desc->status_use_accessors |= _IRQ_PER_CPU; -} - -static inline void irq_settings_set_no_balancing(struct irq_desc *desc) -{ - desc->status_use_accessors |= _IRQ_NO_BALANCING; -} - -static inline bool irq_settings_has_no_balance_set(struct irq_desc *desc) -{ - return desc->status_use_accessors & _IRQ_NO_BALANCING; -} - -static inline u32 irq_settings_get_trigger_mask(struct irq_desc *desc) -{ - return desc->status_use_accessors & IRQ_TYPE_SENSE_MASK; -} - -static inline void -irq_settings_set_trigger_mask(struct irq_desc *desc, u32 mask) -{ - desc->status_use_accessors &= ~IRQ_TYPE_SENSE_MASK; - desc->status_use_accessors |= mask & IRQ_TYPE_SENSE_MASK; -} - -static inline bool irq_settings_is_level(struct irq_desc *desc) -{ - return desc->status_use_accessors & _IRQ_LEVEL; -} - -static inline void irq_settings_clr_level(struct irq_desc *desc) -{ - desc->status_use_accessors &= ~_IRQ_LEVEL; -} - -static inline void irq_settings_set_level(struct irq_desc *desc) -{ - desc->status_use_accessors |= _IRQ_LEVEL; -} - -static inline bool irq_settings_can_request(struct irq_desc *desc) -{ - return !(desc->status_use_accessors & _IRQ_NOREQUEST); -} - -static inline void irq_settings_clr_norequest(struct irq_desc *desc) -{ - desc->status_use_accessors &= ~_IRQ_NOREQUEST; -} - -static inline void irq_settings_set_norequest(struct irq_desc *desc) -{ - desc->status_use_accessors |= _IRQ_NOREQUEST; -} - -static inline bool irq_settings_can_thread(struct irq_desc *desc) -{ - return !(desc->status_use_accessors & _IRQ_NOTHREAD); -} - -static inline void irq_settings_clr_nothread(struct irq_desc *desc) -{ - desc->status_use_accessors &= ~_IRQ_NOTHREAD; -} - -static inline void irq_settings_set_nothread(struct irq_desc *desc) -{ - desc->status_use_accessors |= _IRQ_NOTHREAD; -} - -static inline bool irq_settings_can_probe(struct irq_desc *desc) -{ - return !(desc->status_use_accessors & _IRQ_NOPROBE); -} - -static inline void irq_settings_clr_noprobe(struct irq_desc *desc) -{ - desc->status_use_accessors &= ~_IRQ_NOPROBE; -} - -static inline void irq_settings_set_noprobe(struct irq_desc *desc) -{ - desc->status_use_accessors |= _IRQ_NOPROBE; -} - -static inline bool irq_settings_can_move_pcntxt(struct irq_desc *desc) -{ - return desc->status_use_accessors & _IRQ_MOVE_PCNTXT; -} - -static inline bool irq_settings_can_autoenable(struct irq_desc *desc) -{ - return !(desc->status_use_accessors & _IRQ_NOAUTOEN); -} - -static inline bool irq_settings_is_nested_thread(struct irq_desc *desc) -{ - return desc->status_use_accessors & _IRQ_NESTED_THREAD; -} - -static inline bool irq_settings_is_polled(struct irq_desc *desc) -{ - return desc->status_use_accessors & _IRQ_IS_POLLED; -} - -static inline bool irq_settings_disable_unlazy(struct irq_desc *desc) -{ - return desc->status_use_accessors & _IRQ_DISABLE_UNLAZY; -} - -static inline void irq_settings_clr_disable_unlazy(struct irq_desc *desc) -{ - desc->status_use_accessors &= ~_IRQ_DISABLE_UNLAZY; -} diff --git a/src/linux/kernel/irq/spurious.c b/src/linux/kernel/irq/spurious.c deleted file mode 100644 index 5707f97..0000000 --- a/src/linux/kernel/irq/spurious.c +++ /dev/null @@ -1,465 +0,0 @@ -/* - * linux/kernel/irq/spurious.c - * - * Copyright (C) 1992, 1998-2004 Linus Torvalds, Ingo Molnar - * - * This file contains spurious interrupt handling. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "internals.h" - -static int irqfixup __read_mostly; - -#define POLL_SPURIOUS_IRQ_INTERVAL (HZ/10) -static void poll_spurious_irqs(unsigned long dummy); -static DEFINE_TIMER(poll_spurious_irq_timer, poll_spurious_irqs, 0, 0); -static int irq_poll_cpu; -static atomic_t irq_poll_active; - -/* - * We wait here for a poller to finish. - * - * If the poll runs on this CPU, then we yell loudly and return - * false. That will leave the interrupt line disabled in the worst - * case, but it should never happen. - * - * We wait until the poller is done and then recheck disabled and - * action (about to be disabled). Only if it's still active, we return - * true and let the handler run. - */ -bool irq_wait_for_poll(struct irq_desc *desc) -{ - if (WARN_ONCE(irq_poll_cpu == smp_processor_id(), - "irq poll in progress on cpu %d for irq %d\n", - smp_processor_id(), desc->irq_data.irq)) - return false; - -#ifdef CONFIG_SMP - do { - raw_spin_unlock(&desc->lock); - while (irqd_irq_inprogress(&desc->irq_data)) - cpu_relax(); - raw_spin_lock(&desc->lock); - } while (irqd_irq_inprogress(&desc->irq_data)); - /* Might have been disabled in meantime */ - return !irqd_irq_disabled(&desc->irq_data) && desc->action; -#else - return false; -#endif -} - - -/* - * Recovery handler for misrouted interrupts. - */ -static int try_one_irq(struct irq_desc *desc, bool force) -{ - irqreturn_t ret = IRQ_NONE; - struct irqaction *action; - - raw_spin_lock(&desc->lock); - - /* - * PER_CPU, nested thread interrupts and interrupts explicitely - * marked polled are excluded from polling. - */ - if (irq_settings_is_per_cpu(desc) || - irq_settings_is_nested_thread(desc) || - irq_settings_is_polled(desc)) - goto out; - - /* - * Do not poll disabled interrupts unless the spurious - * disabled poller asks explicitely. - */ - if (irqd_irq_disabled(&desc->irq_data) && !force) - goto out; - - /* - * All handlers must agree on IRQF_SHARED, so we test just the - * first. - */ - action = desc->action; - if (!action || !(action->flags & IRQF_SHARED) || - (action->flags & __IRQF_TIMER)) - goto out; - - /* Already running on another processor */ - if (irqd_irq_inprogress(&desc->irq_data)) { - /* - * Already running: If it is shared get the other - * CPU to go looking for our mystery interrupt too - */ - desc->istate |= IRQS_PENDING; - goto out; - } - - /* Mark it poll in progress */ - desc->istate |= IRQS_POLL_INPROGRESS; - do { - if (handle_irq_event(desc) == IRQ_HANDLED) - ret = IRQ_HANDLED; - /* Make sure that there is still a valid action */ - action = desc->action; - } while ((desc->istate & IRQS_PENDING) && action); - desc->istate &= ~IRQS_POLL_INPROGRESS; -out: - raw_spin_unlock(&desc->lock); - return ret == IRQ_HANDLED; -} - -static int misrouted_irq(int irq) -{ - struct irq_desc *desc; - int i, ok = 0; - - if (atomic_inc_return(&irq_poll_active) != 1) - goto out; - - irq_poll_cpu = smp_processor_id(); - - for_each_irq_desc(i, desc) { - if (!i) - continue; - - if (i == irq) /* Already tried */ - continue; - - if (try_one_irq(desc, false)) - ok = 1; - } -out: - atomic_dec(&irq_poll_active); - /* So the caller can adjust the irq error counts */ - return ok; -} - -static void poll_spurious_irqs(unsigned long dummy) -{ - struct irq_desc *desc; - int i; - - if (atomic_inc_return(&irq_poll_active) != 1) - goto out; - irq_poll_cpu = smp_processor_id(); - - for_each_irq_desc(i, desc) { - unsigned int state; - - if (!i) - continue; - - /* Racy but it doesn't matter */ - state = desc->istate; - barrier(); - if (!(state & IRQS_SPURIOUS_DISABLED)) - continue; - - local_irq_disable(); - try_one_irq(desc, true); - local_irq_enable(); - } -out: - atomic_dec(&irq_poll_active); - mod_timer(&poll_spurious_irq_timer, - jiffies + POLL_SPURIOUS_IRQ_INTERVAL); -} - -static inline int bad_action_ret(irqreturn_t action_ret) -{ - if (likely(action_ret <= (IRQ_HANDLED | IRQ_WAKE_THREAD))) - return 0; - return 1; -} - -/* - * If 99,900 of the previous 100,000 interrupts have not been handled - * then assume that the IRQ is stuck in some manner. Drop a diagnostic - * and try to turn the IRQ off. - * - * (The other 100-of-100,000 interrupts may have been a correctly - * functioning device sharing an IRQ with the failing one) - */ -static void __report_bad_irq(struct irq_desc *desc, irqreturn_t action_ret) -{ - unsigned int irq = irq_desc_get_irq(desc); - struct irqaction *action; - unsigned long flags; - - if (bad_action_ret(action_ret)) { - printk(KERN_ERR "irq event %d: bogus return value %x\n", - irq, action_ret); - } else { - printk(KERN_ERR "irq %d: nobody cared (try booting with " - "the \"irqpoll\" option)\n", irq); - } - dump_stack(); - printk(KERN_ERR "handlers:\n"); - - /* - * We need to take desc->lock here. note_interrupt() is called - * w/o desc->lock held, but IRQ_PROGRESS set. We might race - * with something else removing an action. It's ok to take - * desc->lock here. See synchronize_irq(). - */ - raw_spin_lock_irqsave(&desc->lock, flags); - for_each_action_of_desc(desc, action) { - printk(KERN_ERR "[<%p>] %pf", action->handler, action->handler); - if (action->thread_fn) - printk(KERN_CONT " threaded [<%p>] %pf", - action->thread_fn, action->thread_fn); - printk(KERN_CONT "\n"); - } - raw_spin_unlock_irqrestore(&desc->lock, flags); -} - -static void report_bad_irq(struct irq_desc *desc, irqreturn_t action_ret) -{ - static int count = 100; - - if (count > 0) { - count--; - __report_bad_irq(desc, action_ret); - } -} - -static inline int -try_misrouted_irq(unsigned int irq, struct irq_desc *desc, - irqreturn_t action_ret) -{ - struct irqaction *action; - - if (!irqfixup) - return 0; - - /* We didn't actually handle the IRQ - see if it was misrouted? */ - if (action_ret == IRQ_NONE) - return 1; - - /* - * But for 'irqfixup == 2' we also do it for handled interrupts if - * they are marked as IRQF_IRQPOLL (or for irq zero, which is the - * traditional PC timer interrupt.. Legacy) - */ - if (irqfixup < 2) - return 0; - - if (!irq) - return 1; - - /* - * Since we don't get the descriptor lock, "action" can - * change under us. We don't really care, but we don't - * want to follow a NULL pointer. So tell the compiler to - * just load it once by using a barrier. - */ - action = desc->action; - barrier(); - return action && (action->flags & IRQF_IRQPOLL); -} - -#define SPURIOUS_DEFERRED 0x80000000 - -void note_interrupt(struct irq_desc *desc, irqreturn_t action_ret) -{ - unsigned int irq; - - if (desc->istate & IRQS_POLL_INPROGRESS || - irq_settings_is_polled(desc)) - return; - - if (bad_action_ret(action_ret)) { - report_bad_irq(desc, action_ret); - return; - } - - /* - * We cannot call note_interrupt from the threaded handler - * because we need to look at the compound of all handlers - * (primary and threaded). Aside of that in the threaded - * shared case we have no serialization against an incoming - * hardware interrupt while we are dealing with a threaded - * result. - * - * So in case a thread is woken, we just note the fact and - * defer the analysis to the next hardware interrupt. - * - * The threaded handlers store whether they sucessfully - * handled an interrupt and we check whether that number - * changed versus the last invocation. - * - * We could handle all interrupts with the delayed by one - * mechanism, but for the non forced threaded case we'd just - * add pointless overhead to the straight hardirq interrupts - * for the sake of a few lines less code. - */ - if (action_ret & IRQ_WAKE_THREAD) { - /* - * There is a thread woken. Check whether one of the - * shared primary handlers returned IRQ_HANDLED. If - * not we defer the spurious detection to the next - * interrupt. - */ - if (action_ret == IRQ_WAKE_THREAD) { - int handled; - /* - * We use bit 31 of thread_handled_last to - * denote the deferred spurious detection - * active. No locking necessary as - * thread_handled_last is only accessed here - * and we have the guarantee that hard - * interrupts are not reentrant. - */ - if (!(desc->threads_handled_last & SPURIOUS_DEFERRED)) { - desc->threads_handled_last |= SPURIOUS_DEFERRED; - return; - } - /* - * Check whether one of the threaded handlers - * returned IRQ_HANDLED since the last - * interrupt happened. - * - * For simplicity we just set bit 31, as it is - * set in threads_handled_last as well. So we - * avoid extra masking. And we really do not - * care about the high bits of the handled - * count. We just care about the count being - * different than the one we saw before. - */ - handled = atomic_read(&desc->threads_handled); - handled |= SPURIOUS_DEFERRED; - if (handled != desc->threads_handled_last) { - action_ret = IRQ_HANDLED; - /* - * Note: We keep the SPURIOUS_DEFERRED - * bit set. We are handling the - * previous invocation right now. - * Keep it for the current one, so the - * next hardware interrupt will - * account for it. - */ - desc->threads_handled_last = handled; - } else { - /* - * None of the threaded handlers felt - * responsible for the last interrupt - * - * We keep the SPURIOUS_DEFERRED bit - * set in threads_handled_last as we - * need to account for the current - * interrupt as well. - */ - action_ret = IRQ_NONE; - } - } else { - /* - * One of the primary handlers returned - * IRQ_HANDLED. So we don't care about the - * threaded handlers on the same line. Clear - * the deferred detection bit. - * - * In theory we could/should check whether the - * deferred bit is set and take the result of - * the previous run into account here as - * well. But it's really not worth the - * trouble. If every other interrupt is - * handled we never trigger the spurious - * detector. And if this is just the one out - * of 100k unhandled ones which is handled - * then we merily delay the spurious detection - * by one hard interrupt. Not a real problem. - */ - desc->threads_handled_last &= ~SPURIOUS_DEFERRED; - } - } - - if (unlikely(action_ret == IRQ_NONE)) { - /* - * If we are seeing only the odd spurious IRQ caused by - * bus asynchronicity then don't eventually trigger an error, - * otherwise the counter becomes a doomsday timer for otherwise - * working systems - */ - if (time_after(jiffies, desc->last_unhandled + HZ/10)) - desc->irqs_unhandled = 1; - else - desc->irqs_unhandled++; - desc->last_unhandled = jiffies; - } - - irq = irq_desc_get_irq(desc); - if (unlikely(try_misrouted_irq(irq, desc, action_ret))) { - int ok = misrouted_irq(irq); - if (action_ret == IRQ_NONE) - desc->irqs_unhandled -= ok; - } - - desc->irq_count++; - if (likely(desc->irq_count < 100000)) - return; - - desc->irq_count = 0; - if (unlikely(desc->irqs_unhandled > 99900)) { - /* - * The interrupt is stuck - */ - __report_bad_irq(desc, action_ret); - /* - * Now kill the IRQ - */ - printk(KERN_EMERG "Disabling IRQ #%d\n", irq); - desc->istate |= IRQS_SPURIOUS_DISABLED; - desc->depth++; - irq_disable(desc); - - mod_timer(&poll_spurious_irq_timer, - jiffies + POLL_SPURIOUS_IRQ_INTERVAL); - } - desc->irqs_unhandled = 0; -} - -bool noirqdebug __read_mostly; - -int noirqdebug_setup(char *str) -{ - noirqdebug = 1; - printk(KERN_INFO "IRQ lockup detection disabled\n"); - - return 1; -} - -__setup("noirqdebug", noirqdebug_setup); -module_param(noirqdebug, bool, 0644); -MODULE_PARM_DESC(noirqdebug, "Disable irq lockup detection when true"); - -static int __init irqfixup_setup(char *str) -{ - irqfixup = 1; - printk(KERN_WARNING "Misrouted IRQ fixup support enabled.\n"); - printk(KERN_WARNING "This may impact system performance.\n"); - - return 1; -} - -__setup("irqfixup", irqfixup_setup); -module_param(irqfixup, int, 0644); - -static int __init irqpoll_setup(char *str) -{ - irqfixup = 2; - printk(KERN_WARNING "Misrouted IRQ fixup and polling support " - "enabled\n"); - printk(KERN_WARNING "This may significantly impact system " - "performance\n"); - return 1; -} - -__setup("irqpoll", irqpoll_setup); diff --git a/src/linux/kernel/irq_work.c b/src/linux/kernel/irq_work.c deleted file mode 100644 index bcf107c..0000000 --- a/src/linux/kernel/irq_work.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright (C) 2010 Red Hat, Inc., Peter Zijlstra - * - * Provides a framework for enqueueing and running callbacks from hardirq - * context. The enqueueing is NMI-safe. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -static DEFINE_PER_CPU(struct llist_head, raised_list); -static DEFINE_PER_CPU(struct llist_head, lazy_list); - -/* - * Claim the entry so that no one else will poke at it. - */ -static bool irq_work_claim(struct irq_work *work) -{ - unsigned long flags, oflags, nflags; - - /* - * Start with our best wish as a premise but only trust any - * flag value after cmpxchg() result. - */ - flags = work->flags & ~IRQ_WORK_PENDING; - for (;;) { - nflags = flags | IRQ_WORK_FLAGS; - oflags = cmpxchg(&work->flags, flags, nflags); - if (oflags == flags) - break; - if (oflags & IRQ_WORK_PENDING) - return false; - flags = oflags; - cpu_relax(); - } - - return true; -} - -void __weak arch_irq_work_raise(void) -{ - /* - * Lame architectures will get the timer tick callback - */ -} - -#ifdef CONFIG_SMP -/* - * Enqueue the irq_work @work on @cpu unless it's already pending - * somewhere. - * - * Can be re-enqueued while the callback is still in progress. - */ -bool irq_work_queue_on(struct irq_work *work, int cpu) -{ - /* All work should have been flushed before going offline */ - WARN_ON_ONCE(cpu_is_offline(cpu)); - - /* Arch remote IPI send/receive backend aren't NMI safe */ - WARN_ON_ONCE(in_nmi()); - - /* Only queue if not already pending */ - if (!irq_work_claim(work)) - return false; - - if (llist_add(&work->llnode, &per_cpu(raised_list, cpu))) - arch_send_call_function_single_ipi(cpu); - - return true; -} -EXPORT_SYMBOL_GPL(irq_work_queue_on); -#endif - -/* Enqueue the irq work @work on the current CPU */ -bool irq_work_queue(struct irq_work *work) -{ - /* Only queue if not already pending */ - if (!irq_work_claim(work)) - return false; - - /* Queue the entry and raise the IPI if needed. */ - preempt_disable(); - - /* If the work is "lazy", handle it from next tick if any */ - if (work->flags & IRQ_WORK_LAZY) { - if (llist_add(&work->llnode, this_cpu_ptr(&lazy_list)) && - tick_nohz_tick_stopped()) - arch_irq_work_raise(); - } else { - if (llist_add(&work->llnode, this_cpu_ptr(&raised_list))) - arch_irq_work_raise(); - } - - preempt_enable(); - - return true; -} -EXPORT_SYMBOL_GPL(irq_work_queue); - -bool irq_work_needs_cpu(void) -{ - struct llist_head *raised, *lazy; - - raised = this_cpu_ptr(&raised_list); - lazy = this_cpu_ptr(&lazy_list); - - if (llist_empty(raised) || arch_irq_work_has_interrupt()) - if (llist_empty(lazy)) - return false; - - /* All work should have been flushed before going offline */ - WARN_ON_ONCE(cpu_is_offline(smp_processor_id())); - - return true; -} - -static void irq_work_run_list(struct llist_head *list) -{ - unsigned long flags; - struct irq_work *work; - struct llist_node *llnode; - - BUG_ON(!irqs_disabled()); - - if (llist_empty(list)) - return; - - llnode = llist_del_all(list); - while (llnode != NULL) { - work = llist_entry(llnode, struct irq_work, llnode); - - llnode = llist_next(llnode); - - /* - * Clear the PENDING bit, after this point the @work - * can be re-used. - * Make it immediately visible so that other CPUs trying - * to claim that work don't rely on us to handle their data - * while we are in the middle of the func. - */ - flags = work->flags & ~IRQ_WORK_PENDING; - xchg(&work->flags, flags); - - work->func(work); - /* - * Clear the BUSY bit and return to the free state if - * no-one else claimed it meanwhile. - */ - (void)cmpxchg(&work->flags, flags, flags & ~IRQ_WORK_BUSY); - } -} - -/* - * hotplug calls this through: - * hotplug_cfd() -> flush_smp_call_function_queue() - */ -void irq_work_run(void) -{ - irq_work_run_list(this_cpu_ptr(&raised_list)); - irq_work_run_list(this_cpu_ptr(&lazy_list)); -} -EXPORT_SYMBOL_GPL(irq_work_run); - -void irq_work_tick(void) -{ - struct llist_head *raised = this_cpu_ptr(&raised_list); - - if (!llist_empty(raised) && !arch_irq_work_has_interrupt()) - irq_work_run_list(raised); - irq_work_run_list(this_cpu_ptr(&lazy_list)); -} - -/* - * Synchronize against the irq_work @entry, ensures the entry is not - * currently in use. - */ -void irq_work_sync(struct irq_work *work) -{ - WARN_ON_ONCE(irqs_disabled()); - - while (work->flags & IRQ_WORK_BUSY) - cpu_relax(); -} -EXPORT_SYMBOL_GPL(irq_work_sync); diff --git a/src/linux/kernel/kallsyms.c b/src/linux/kernel/kallsyms.c deleted file mode 100644 index fafd1a3..0000000 --- a/src/linux/kernel/kallsyms.c +++ /dev/null @@ -1,632 +0,0 @@ -/* - * kallsyms.c: in-kernel printing of symbolic oopses and stack traces. - * - * Rewritten and vastly simplified by Rusty Russell for in-kernel - * module loader: - * Copyright 2002 Rusty Russell IBM Corporation - * - * ChangeLog: - * - * (25/Aug/2004) Paulo Marques - * Changed the compression method from stem compression to "table lookup" - * compression (see scripts/kallsyms.c for a more complete description) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for cond_resched */ -#include -#include -#include -#include - -#include - -#ifdef CONFIG_KALLSYMS_ALL -#define all_var 1 -#else -#define all_var 0 -#endif - -/* - * These will be re-linked against their real values - * during the second link stage. - */ -extern const unsigned long kallsyms_addresses[] __weak; -extern const int kallsyms_offsets[] __weak; -extern const u8 kallsyms_names[] __weak; - -/* - * Tell the compiler that the count isn't in the small data section if the arch - * has one (eg: FRV). - */ -extern const unsigned long kallsyms_num_syms -__attribute__((weak, section(".rodata"))); - -extern const unsigned long kallsyms_relative_base -__attribute__((weak, section(".rodata"))); - -extern const u8 kallsyms_token_table[] __weak; -extern const u16 kallsyms_token_index[] __weak; - -extern const unsigned long kallsyms_markers[] __weak; - -static inline int is_kernel_inittext(unsigned long addr) -{ - if (addr >= (unsigned long)_sinittext - && addr <= (unsigned long)_einittext) - return 1; - return 0; -} - -static inline int is_kernel_text(unsigned long addr) -{ - if ((addr >= (unsigned long)_stext && addr <= (unsigned long)_etext) || - arch_is_kernel_text(addr)) - return 1; - return in_gate_area_no_mm(addr); -} - -static inline int is_kernel(unsigned long addr) -{ - if (addr >= (unsigned long)_stext && addr <= (unsigned long)_end) - return 1; - return in_gate_area_no_mm(addr); -} - -static int is_ksym_addr(unsigned long addr) -{ - if (all_var) - return is_kernel(addr); - - return is_kernel_text(addr) || is_kernel_inittext(addr); -} - -/* - * Expand a compressed symbol data into the resulting uncompressed string, - * if uncompressed string is too long (>= maxlen), it will be truncated, - * given the offset to where the symbol is in the compressed stream. - */ -static unsigned int kallsyms_expand_symbol(unsigned int off, - char *result, size_t maxlen) -{ - int len, skipped_first = 0; - const u8 *tptr, *data; - - /* Get the compressed symbol length from the first symbol byte. */ - data = &kallsyms_names[off]; - len = *data; - data++; - - /* - * Update the offset to return the offset for the next symbol on - * the compressed stream. - */ - off += len + 1; - - /* - * For every byte on the compressed symbol data, copy the table - * entry for that byte. - */ - while (len) { - tptr = &kallsyms_token_table[kallsyms_token_index[*data]]; - data++; - len--; - - while (*tptr) { - if (skipped_first) { - if (maxlen <= 1) - goto tail; - *result = *tptr; - result++; - maxlen--; - } else - skipped_first = 1; - tptr++; - } - } - -tail: - if (maxlen) - *result = '\0'; - - /* Return to offset to the next symbol. */ - return off; -} - -/* - * Get symbol type information. This is encoded as a single char at the - * beginning of the symbol name. - */ -static char kallsyms_get_symbol_type(unsigned int off) -{ - /* - * Get just the first code, look it up in the token table, - * and return the first char from this token. - */ - return kallsyms_token_table[kallsyms_token_index[kallsyms_names[off + 1]]]; -} - - -/* - * Find the offset on the compressed stream given and index in the - * kallsyms array. - */ -static unsigned int get_symbol_offset(unsigned long pos) -{ - const u8 *name; - int i; - - /* - * Use the closest marker we have. We have markers every 256 positions, - * so that should be close enough. - */ - name = &kallsyms_names[kallsyms_markers[pos >> 8]]; - - /* - * Sequentially scan all the symbols up to the point we're searching - * for. Every symbol is stored in a [][ bytes of data] format, - * so we just need to add the len to the current pointer for every - * symbol we wish to skip. - */ - for (i = 0; i < (pos & 0xFF); i++) - name = name + (*name) + 1; - - return name - kallsyms_names; -} - -static unsigned long kallsyms_sym_address(int idx) -{ - if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE)) - return kallsyms_addresses[idx]; - - /* values are unsigned offsets if --absolute-percpu is not in effect */ - if (!IS_ENABLED(CONFIG_KALLSYMS_ABSOLUTE_PERCPU)) - return kallsyms_relative_base + (u32)kallsyms_offsets[idx]; - - /* ...otherwise, positive offsets are absolute values */ - if (kallsyms_offsets[idx] >= 0) - return kallsyms_offsets[idx]; - - /* ...and negative offsets are relative to kallsyms_relative_base - 1 */ - return kallsyms_relative_base - 1 - kallsyms_offsets[idx]; -} - -/* Lookup the address for this symbol. Returns 0 if not found. */ -unsigned long kallsyms_lookup_name(const char *name) -{ - char namebuf[KSYM_NAME_LEN]; - unsigned long i; - unsigned int off; - - for (i = 0, off = 0; i < kallsyms_num_syms; i++) { - off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf)); - - if (strcmp(namebuf, name) == 0) - return kallsyms_sym_address(i); - } - return module_kallsyms_lookup_name(name); -} -EXPORT_SYMBOL_GPL(kallsyms_lookup_name); - -int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, - unsigned long), - void *data) -{ - char namebuf[KSYM_NAME_LEN]; - unsigned long i; - unsigned int off; - int ret; - - for (i = 0, off = 0; i < kallsyms_num_syms; i++) { - off = kallsyms_expand_symbol(off, namebuf, ARRAY_SIZE(namebuf)); - ret = fn(data, namebuf, NULL, kallsyms_sym_address(i)); - if (ret != 0) - return ret; - } - return module_kallsyms_on_each_symbol(fn, data); -} -EXPORT_SYMBOL_GPL(kallsyms_on_each_symbol); - -static unsigned long get_symbol_pos(unsigned long addr, - unsigned long *symbolsize, - unsigned long *offset) -{ - unsigned long symbol_start = 0, symbol_end = 0; - unsigned long i, low, high, mid; - - /* This kernel should never had been booted. */ - if (!IS_ENABLED(CONFIG_KALLSYMS_BASE_RELATIVE)) - BUG_ON(!kallsyms_addresses); - else - BUG_ON(!kallsyms_offsets); - - /* Do a binary search on the sorted kallsyms_addresses array. */ - low = 0; - high = kallsyms_num_syms; - - while (high - low > 1) { - mid = low + (high - low) / 2; - if (kallsyms_sym_address(mid) <= addr) - low = mid; - else - high = mid; - } - - /* - * Search for the first aliased symbol. Aliased - * symbols are symbols with the same address. - */ - while (low && kallsyms_sym_address(low-1) == kallsyms_sym_address(low)) - --low; - - symbol_start = kallsyms_sym_address(low); - - /* Search for next non-aliased symbol. */ - for (i = low + 1; i < kallsyms_num_syms; i++) { - if (kallsyms_sym_address(i) > symbol_start) { - symbol_end = kallsyms_sym_address(i); - break; - } - } - - /* If we found no next symbol, we use the end of the section. */ - if (!symbol_end) { - if (is_kernel_inittext(addr)) - symbol_end = (unsigned long)_einittext; - else if (all_var) - symbol_end = (unsigned long)_end; - else - symbol_end = (unsigned long)_etext; - } - - if (symbolsize) - *symbolsize = symbol_end - symbol_start; - if (offset) - *offset = addr - symbol_start; - - return low; -} - -/* - * Lookup an address but don't bother to find any names. - */ -int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize, - unsigned long *offset) -{ - char namebuf[KSYM_NAME_LEN]; - if (is_ksym_addr(addr)) - return !!get_symbol_pos(addr, symbolsize, offset); - - return !!module_address_lookup(addr, symbolsize, offset, NULL, namebuf); -} - -/* - * Lookup an address - * - modname is set to NULL if it's in the kernel. - * - We guarantee that the returned name is valid until we reschedule even if. - * It resides in a module. - * - We also guarantee that modname will be valid until rescheduled. - */ -const char *kallsyms_lookup(unsigned long addr, - unsigned long *symbolsize, - unsigned long *offset, - char **modname, char *namebuf) -{ - namebuf[KSYM_NAME_LEN - 1] = 0; - namebuf[0] = 0; - - if (is_ksym_addr(addr)) { - unsigned long pos; - - pos = get_symbol_pos(addr, symbolsize, offset); - /* Grab name */ - kallsyms_expand_symbol(get_symbol_offset(pos), - namebuf, KSYM_NAME_LEN); - if (modname) - *modname = NULL; - return namebuf; - } - - /* See if it's in a module. */ - return module_address_lookup(addr, symbolsize, offset, modname, - namebuf); -} - -int lookup_symbol_name(unsigned long addr, char *symname) -{ - symname[0] = '\0'; - symname[KSYM_NAME_LEN - 1] = '\0'; - - if (is_ksym_addr(addr)) { - unsigned long pos; - - pos = get_symbol_pos(addr, NULL, NULL); - /* Grab name */ - kallsyms_expand_symbol(get_symbol_offset(pos), - symname, KSYM_NAME_LEN); - return 0; - } - /* See if it's in a module. */ - return lookup_module_symbol_name(addr, symname); -} - -int lookup_symbol_attrs(unsigned long addr, unsigned long *size, - unsigned long *offset, char *modname, char *name) -{ - name[0] = '\0'; - name[KSYM_NAME_LEN - 1] = '\0'; - - if (is_ksym_addr(addr)) { - unsigned long pos; - - pos = get_symbol_pos(addr, size, offset); - /* Grab name */ - kallsyms_expand_symbol(get_symbol_offset(pos), - name, KSYM_NAME_LEN); - modname[0] = '\0'; - return 0; - } - /* See if it's in a module. */ - return lookup_module_symbol_attrs(addr, size, offset, modname, name); -} - -/* Look up a kernel symbol and return it in a text buffer. */ -static int __sprint_symbol(char *buffer, unsigned long address, - int symbol_offset, int add_offset) -{ - char *modname; - const char *name; - unsigned long offset, size; - int len; - - address += symbol_offset; - name = kallsyms_lookup(address, &size, &offset, &modname, buffer); - if (!name) - return sprintf(buffer, "0x%lx", address - symbol_offset); - - if (name != buffer) - strcpy(buffer, name); - len = strlen(buffer); - offset -= symbol_offset; - - if (add_offset) - len += sprintf(buffer + len, "+%#lx/%#lx", offset, size); - - if (modname) - len += sprintf(buffer + len, " [%s]", modname); - - return len; -} - -/** - * sprint_symbol - Look up a kernel symbol and return it in a text buffer - * @buffer: buffer to be stored - * @address: address to lookup - * - * This function looks up a kernel symbol with @address and stores its name, - * offset, size and module name to @buffer if possible. If no symbol was found, - * just saves its @address as is. - * - * This function returns the number of bytes stored in @buffer. - */ -int sprint_symbol(char *buffer, unsigned long address) -{ - return __sprint_symbol(buffer, address, 0, 1); -} -EXPORT_SYMBOL_GPL(sprint_symbol); - -/** - * sprint_symbol_no_offset - Look up a kernel symbol and return it in a text buffer - * @buffer: buffer to be stored - * @address: address to lookup - * - * This function looks up a kernel symbol with @address and stores its name - * and module name to @buffer if possible. If no symbol was found, just saves - * its @address as is. - * - * This function returns the number of bytes stored in @buffer. - */ -int sprint_symbol_no_offset(char *buffer, unsigned long address) -{ - return __sprint_symbol(buffer, address, 0, 0); -} -EXPORT_SYMBOL_GPL(sprint_symbol_no_offset); - -/** - * sprint_backtrace - Look up a backtrace symbol and return it in a text buffer - * @buffer: buffer to be stored - * @address: address to lookup - * - * This function is for stack backtrace and does the same thing as - * sprint_symbol() but with modified/decreased @address. If there is a - * tail-call to the function marked "noreturn", gcc optimized out code after - * the call so that the stack-saved return address could point outside of the - * caller. This function ensures that kallsyms will find the original caller - * by decreasing @address. - * - * This function returns the number of bytes stored in @buffer. - */ -int sprint_backtrace(char *buffer, unsigned long address) -{ - return __sprint_symbol(buffer, address, -1, 1); -} - -/* Look up a kernel symbol and print it to the kernel messages. */ -void __print_symbol(const char *fmt, unsigned long address) -{ - char buffer[KSYM_SYMBOL_LEN]; - - sprint_symbol(buffer, address); - - printk(fmt, buffer); -} -EXPORT_SYMBOL(__print_symbol); - -/* To avoid using get_symbol_offset for every symbol, we carry prefix along. */ -struct kallsym_iter { - loff_t pos; - unsigned long value; - unsigned int nameoff; /* If iterating in core kernel symbols. */ - char type; - char name[KSYM_NAME_LEN]; - char module_name[MODULE_NAME_LEN]; - int exported; -}; - -static int get_ksymbol_mod(struct kallsym_iter *iter) -{ - if (module_get_kallsym(iter->pos - kallsyms_num_syms, &iter->value, - &iter->type, iter->name, iter->module_name, - &iter->exported) < 0) - return 0; - return 1; -} - -/* Returns space to next name. */ -static unsigned long get_ksymbol_core(struct kallsym_iter *iter) -{ - unsigned off = iter->nameoff; - - iter->module_name[0] = '\0'; - iter->value = kallsyms_sym_address(iter->pos); - - iter->type = kallsyms_get_symbol_type(off); - - off = kallsyms_expand_symbol(off, iter->name, ARRAY_SIZE(iter->name)); - - return off - iter->nameoff; -} - -static void reset_iter(struct kallsym_iter *iter, loff_t new_pos) -{ - iter->name[0] = '\0'; - iter->nameoff = get_symbol_offset(new_pos); - iter->pos = new_pos; -} - -/* Returns false if pos at or past end of file. */ -static int update_iter(struct kallsym_iter *iter, loff_t pos) -{ - /* Module symbols can be accessed randomly. */ - if (pos >= kallsyms_num_syms) { - iter->pos = pos; - return get_ksymbol_mod(iter); - } - - /* If we're not on the desired position, reset to new position. */ - if (pos != iter->pos) - reset_iter(iter, pos); - - iter->nameoff += get_ksymbol_core(iter); - iter->pos++; - - return 1; -} - -static void *s_next(struct seq_file *m, void *p, loff_t *pos) -{ - (*pos)++; - - if (!update_iter(m->private, *pos)) - return NULL; - return p; -} - -static void *s_start(struct seq_file *m, loff_t *pos) -{ - if (!update_iter(m->private, *pos)) - return NULL; - return m->private; -} - -static void s_stop(struct seq_file *m, void *p) -{ -} - -static int s_show(struct seq_file *m, void *p) -{ - struct kallsym_iter *iter = m->private; - - /* Some debugging symbols have no name. Ignore them. */ - if (!iter->name[0]) - return 0; - - if (iter->module_name[0]) { - char type; - - /* - * Label it "global" if it is exported, - * "local" if not exported. - */ - type = iter->exported ? toupper(iter->type) : - tolower(iter->type); - seq_printf(m, "%pK %c %s\t[%s]\n", (void *)iter->value, - type, iter->name, iter->module_name); - } else - seq_printf(m, "%pK %c %s\n", (void *)iter->value, - iter->type, iter->name); - return 0; -} - -static const struct seq_operations kallsyms_op = { - .start = s_start, - .next = s_next, - .stop = s_stop, - .show = s_show -}; - -static int kallsyms_open(struct inode *inode, struct file *file) -{ - /* - * We keep iterator in m->private, since normal case is to - * s_start from where we left off, so we avoid doing - * using get_symbol_offset for every symbol. - */ - struct kallsym_iter *iter; - iter = __seq_open_private(file, &kallsyms_op, sizeof(*iter)); - if (!iter) - return -ENOMEM; - reset_iter(iter, 0); - - return 0; -} - -#ifdef CONFIG_KGDB_KDB -const char *kdb_walk_kallsyms(loff_t *pos) -{ - static struct kallsym_iter kdb_walk_kallsyms_iter; - if (*pos == 0) { - memset(&kdb_walk_kallsyms_iter, 0, - sizeof(kdb_walk_kallsyms_iter)); - reset_iter(&kdb_walk_kallsyms_iter, 0); - } - while (1) { - if (!update_iter(&kdb_walk_kallsyms_iter, *pos)) - return NULL; - ++*pos; - /* Some debugging symbols have no name. Ignore them. */ - if (kdb_walk_kallsyms_iter.name[0]) - return kdb_walk_kallsyms_iter.name; - } -} -#endif /* CONFIG_KGDB_KDB */ - -static const struct file_operations kallsyms_operations = { - .open = kallsyms_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_private, -}; - -static int __init kallsyms_init(void) -{ - proc_create("kallsyms", 0444, NULL, &kallsyms_operations); - return 0; -} -device_initcall(kallsyms_init); diff --git a/src/linux/kernel/kmod.c b/src/linux/kernel/kmod.c deleted file mode 100644 index 0277d12..0000000 --- a/src/linux/kernel/kmod.c +++ /dev/null @@ -1,706 +0,0 @@ -/* - kmod, the new module loader (replaces kerneld) - Kirk Petersen - - Reorganized not to be a daemon by Adam Richter, with guidance - from Greg Zornetzer. - - Modified to avoid chroot and file sharing problems. - Mikael Pettersson - - Limit the concurrent number of kmod modprobes to catch loops from - "modprobe needs a service that is in a module". - Keith Owens December 1999 - - Unblock all signals when we exec a usermode process. - Shuu Yamaguchi December 2000 - - call_usermodehelper wait flag, and remove exec_usermodehelper. - Rusty Russell Jan 2003 -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -extern int max_threads; - -#define CAP_BSET (void *)1 -#define CAP_PI (void *)2 - -static kernel_cap_t usermodehelper_bset = CAP_FULL_SET; -static kernel_cap_t usermodehelper_inheritable = CAP_FULL_SET; -static DEFINE_SPINLOCK(umh_sysctl_lock); -static DECLARE_RWSEM(umhelper_sem); - -#ifdef CONFIG_MODULES - -/* - modprobe_path is set via /proc/sys. -*/ -char modprobe_path[KMOD_PATH_LEN] = "/sbin/modprobe"; - -static void free_modprobe_argv(struct subprocess_info *info) -{ - kfree(info->argv[3]); /* check call_modprobe() */ - kfree(info->argv); -} - -static int call_modprobe(char *module_name, int wait) -{ - struct subprocess_info *info; - static char *envp[] = { - "HOME=/", - "TERM=linux", - "PATH=/sbin:/usr/sbin:/bin:/usr/bin", - NULL - }; - - char **argv = kmalloc(sizeof(char *[5]), GFP_KERNEL); - if (!argv) - goto out; - - module_name = kstrdup(module_name, GFP_KERNEL); - if (!module_name) - goto free_argv; - - argv[0] = modprobe_path; - argv[1] = "-q"; - argv[2] = "--"; - argv[3] = module_name; /* check free_modprobe_argv() */ - argv[4] = NULL; - - info = call_usermodehelper_setup(modprobe_path, argv, envp, GFP_KERNEL, - NULL, free_modprobe_argv, NULL); - if (!info) - goto free_module_name; - - return call_usermodehelper_exec(info, wait | UMH_KILLABLE); - -free_module_name: - kfree(module_name); -free_argv: - kfree(argv); -out: - return -ENOMEM; -} - -/** - * __request_module - try to load a kernel module - * @wait: wait (or not) for the operation to complete - * @fmt: printf style format string for the name of the module - * @...: arguments as specified in the format string - * - * Load a module using the user mode module loader. The function returns - * zero on success or a negative errno code or positive exit code from - * "modprobe" on failure. Note that a successful module load does not mean - * the module did not then unload and exit on an error of its own. Callers - * must check that the service they requested is now available not blindly - * invoke it. - * - * If module auto-loading support is disabled then this function - * becomes a no-operation. - */ -int __request_module(bool wait, const char *fmt, ...) -{ - va_list args; - char module_name[MODULE_NAME_LEN]; - unsigned int max_modprobes; - int ret; - static atomic_t kmod_concurrent = ATOMIC_INIT(0); -#define MAX_KMOD_CONCURRENT 50 /* Completely arbitrary value - KAO */ - static int kmod_loop_msg; - - /* - * We don't allow synchronous module loading from async. Module - * init may invoke async_synchronize_full() which will end up - * waiting for this task which already is waiting for the module - * loading to complete, leading to a deadlock. - */ - WARN_ON_ONCE(wait && current_is_async()); - - if (!modprobe_path[0]) - return 0; - - va_start(args, fmt); - ret = vsnprintf(module_name, MODULE_NAME_LEN, fmt, args); - va_end(args); - if (ret >= MODULE_NAME_LEN) - return -ENAMETOOLONG; - - ret = security_kernel_module_request(module_name); - if (ret) - return ret; - - /* If modprobe needs a service that is in a module, we get a recursive - * loop. Limit the number of running kmod threads to max_threads/2 or - * MAX_KMOD_CONCURRENT, whichever is the smaller. A cleaner method - * would be to run the parents of this process, counting how many times - * kmod was invoked. That would mean accessing the internals of the - * process tables to get the command line, proc_pid_cmdline is static - * and it is not worth changing the proc code just to handle this case. - * KAO. - * - * "trace the ppid" is simple, but will fail if someone's - * parent exits. I think this is as good as it gets. --RR - */ - max_modprobes = min(max_threads/2, MAX_KMOD_CONCURRENT); - atomic_inc(&kmod_concurrent); - if (atomic_read(&kmod_concurrent) > max_modprobes) { - /* We may be blaming an innocent here, but unlikely */ - if (kmod_loop_msg < 5) { - printk(KERN_ERR - "request_module: runaway loop modprobe %s\n", - module_name); - kmod_loop_msg++; - } - atomic_dec(&kmod_concurrent); - return -ENOMEM; - } - - trace_module_request(module_name, wait, _RET_IP_); - - ret = call_modprobe(module_name, wait ? UMH_WAIT_PROC : UMH_WAIT_EXEC); - - atomic_dec(&kmod_concurrent); - return ret; -} -EXPORT_SYMBOL(__request_module); -#endif /* CONFIG_MODULES */ - -static void call_usermodehelper_freeinfo(struct subprocess_info *info) -{ - if (info->cleanup) - (*info->cleanup)(info); - kfree(info); -} - -static void umh_complete(struct subprocess_info *sub_info) -{ - struct completion *comp = xchg(&sub_info->complete, NULL); - /* - * See call_usermodehelper_exec(). If xchg() returns NULL - * we own sub_info, the UMH_KILLABLE caller has gone away - * or the caller used UMH_NO_WAIT. - */ - if (comp) - complete(comp); - else - call_usermodehelper_freeinfo(sub_info); -} - -/* - * This is the task which runs the usermode application - */ -static int call_usermodehelper_exec_async(void *data) -{ - struct subprocess_info *sub_info = data; - struct cred *new; - int retval; - - spin_lock_irq(¤t->sighand->siglock); - flush_signal_handlers(current, 1); - spin_unlock_irq(¤t->sighand->siglock); - - /* - * Our parent (unbound workqueue) runs with elevated scheduling - * priority. Avoid propagating that into the userspace child. - */ - set_user_nice(current, 0); - - retval = -ENOMEM; - new = prepare_kernel_cred(current); - if (!new) - goto out; - - spin_lock(&umh_sysctl_lock); - new->cap_bset = cap_intersect(usermodehelper_bset, new->cap_bset); - new->cap_inheritable = cap_intersect(usermodehelper_inheritable, - new->cap_inheritable); - spin_unlock(&umh_sysctl_lock); - - if (sub_info->init) { - retval = sub_info->init(sub_info, new); - if (retval) { - abort_creds(new); - goto out; - } - } - - commit_creds(new); - - retval = do_execve(getname_kernel(sub_info->path), - (const char __user *const __user *)sub_info->argv, - (const char __user *const __user *)sub_info->envp); -out: - sub_info->retval = retval; - /* - * call_usermodehelper_exec_sync() will call umh_complete - * if UHM_WAIT_PROC. - */ - if (!(sub_info->wait & UMH_WAIT_PROC)) - umh_complete(sub_info); - if (!retval) - return 0; - do_exit(0); -} - -/* Handles UMH_WAIT_PROC. */ -static void call_usermodehelper_exec_sync(struct subprocess_info *sub_info) -{ - pid_t pid; - - /* If SIGCLD is ignored sys_wait4 won't populate the status. */ - kernel_sigaction(SIGCHLD, SIG_DFL); - pid = kernel_thread(call_usermodehelper_exec_async, sub_info, SIGCHLD); - if (pid < 0) { - sub_info->retval = pid; - } else { - int ret = -ECHILD; - /* - * Normally it is bogus to call wait4() from in-kernel because - * wait4() wants to write the exit code to a userspace address. - * But call_usermodehelper_exec_sync() always runs as kernel - * thread (workqueue) and put_user() to a kernel address works - * OK for kernel threads, due to their having an mm_segment_t - * which spans the entire address space. - * - * Thus the __user pointer cast is valid here. - */ - sys_wait4(pid, (int __user *)&ret, 0, NULL); - - /* - * If ret is 0, either call_usermodehelper_exec_async failed and - * the real error code is already in sub_info->retval or - * sub_info->retval is 0 anyway, so don't mess with it then. - */ - if (ret) - sub_info->retval = ret; - } - - /* Restore default kernel sig handler */ - kernel_sigaction(SIGCHLD, SIG_IGN); - - umh_complete(sub_info); -} - -/* - * We need to create the usermodehelper kernel thread from a task that is affine - * to an optimized set of CPUs (or nohz housekeeping ones) such that they - * inherit a widest affinity irrespective of call_usermodehelper() callers with - * possibly reduced affinity (eg: per-cpu workqueues). We don't want - * usermodehelper targets to contend a busy CPU. - * - * Unbound workqueues provide such wide affinity and allow to block on - * UMH_WAIT_PROC requests without blocking pending request (up to some limit). - * - * Besides, workqueues provide the privilege level that caller might not have - * to perform the usermodehelper request. - * - */ -static void call_usermodehelper_exec_work(struct work_struct *work) -{ - struct subprocess_info *sub_info = - container_of(work, struct subprocess_info, work); - - if (sub_info->wait & UMH_WAIT_PROC) { - call_usermodehelper_exec_sync(sub_info); - } else { - pid_t pid; - /* - * Use CLONE_PARENT to reparent it to kthreadd; we do not - * want to pollute current->children, and we need a parent - * that always ignores SIGCHLD to ensure auto-reaping. - */ - pid = kernel_thread(call_usermodehelper_exec_async, sub_info, - CLONE_PARENT | SIGCHLD); - if (pid < 0) { - sub_info->retval = pid; - umh_complete(sub_info); - } - } -} - -/* - * If set, call_usermodehelper_exec() will exit immediately returning -EBUSY - * (used for preventing user land processes from being created after the user - * land has been frozen during a system-wide hibernation or suspend operation). - * Should always be manipulated under umhelper_sem acquired for write. - */ -static enum umh_disable_depth usermodehelper_disabled = UMH_DISABLED; - -/* Number of helpers running */ -static atomic_t running_helpers = ATOMIC_INIT(0); - -/* - * Wait queue head used by usermodehelper_disable() to wait for all running - * helpers to finish. - */ -static DECLARE_WAIT_QUEUE_HEAD(running_helpers_waitq); - -/* - * Used by usermodehelper_read_lock_wait() to wait for usermodehelper_disabled - * to become 'false'. - */ -static DECLARE_WAIT_QUEUE_HEAD(usermodehelper_disabled_waitq); - -/* - * Time to wait for running_helpers to become zero before the setting of - * usermodehelper_disabled in usermodehelper_disable() fails - */ -#define RUNNING_HELPERS_TIMEOUT (5 * HZ) - -int usermodehelper_read_trylock(void) -{ - DEFINE_WAIT(wait); - int ret = 0; - - down_read(&umhelper_sem); - for (;;) { - prepare_to_wait(&usermodehelper_disabled_waitq, &wait, - TASK_INTERRUPTIBLE); - if (!usermodehelper_disabled) - break; - - if (usermodehelper_disabled == UMH_DISABLED) - ret = -EAGAIN; - - up_read(&umhelper_sem); - - if (ret) - break; - - schedule(); - try_to_freeze(); - - down_read(&umhelper_sem); - } - finish_wait(&usermodehelper_disabled_waitq, &wait); - return ret; -} -EXPORT_SYMBOL_GPL(usermodehelper_read_trylock); - -long usermodehelper_read_lock_wait(long timeout) -{ - DEFINE_WAIT(wait); - - if (timeout < 0) - return -EINVAL; - - down_read(&umhelper_sem); - for (;;) { - prepare_to_wait(&usermodehelper_disabled_waitq, &wait, - TASK_UNINTERRUPTIBLE); - if (!usermodehelper_disabled) - break; - - up_read(&umhelper_sem); - - timeout = schedule_timeout(timeout); - if (!timeout) - break; - - down_read(&umhelper_sem); - } - finish_wait(&usermodehelper_disabled_waitq, &wait); - return timeout; -} -EXPORT_SYMBOL_GPL(usermodehelper_read_lock_wait); - -void usermodehelper_read_unlock(void) -{ - up_read(&umhelper_sem); -} -EXPORT_SYMBOL_GPL(usermodehelper_read_unlock); - -/** - * __usermodehelper_set_disable_depth - Modify usermodehelper_disabled. - * @depth: New value to assign to usermodehelper_disabled. - * - * Change the value of usermodehelper_disabled (under umhelper_sem locked for - * writing) and wakeup tasks waiting for it to change. - */ -void __usermodehelper_set_disable_depth(enum umh_disable_depth depth) -{ - down_write(&umhelper_sem); - usermodehelper_disabled = depth; - wake_up(&usermodehelper_disabled_waitq); - up_write(&umhelper_sem); -} - -/** - * __usermodehelper_disable - Prevent new helpers from being started. - * @depth: New value to assign to usermodehelper_disabled. - * - * Set usermodehelper_disabled to @depth and wait for running helpers to exit. - */ -int __usermodehelper_disable(enum umh_disable_depth depth) -{ - long retval; - - if (!depth) - return -EINVAL; - - down_write(&umhelper_sem); - usermodehelper_disabled = depth; - up_write(&umhelper_sem); - - /* - * From now on call_usermodehelper_exec() won't start any new - * helpers, so it is sufficient if running_helpers turns out to - * be zero at one point (it may be increased later, but that - * doesn't matter). - */ - retval = wait_event_timeout(running_helpers_waitq, - atomic_read(&running_helpers) == 0, - RUNNING_HELPERS_TIMEOUT); - if (retval) - return 0; - - __usermodehelper_set_disable_depth(UMH_ENABLED); - return -EAGAIN; -} - -static void helper_lock(void) -{ - atomic_inc(&running_helpers); - smp_mb__after_atomic(); -} - -static void helper_unlock(void) -{ - if (atomic_dec_and_test(&running_helpers)) - wake_up(&running_helpers_waitq); -} - -/** - * call_usermodehelper_setup - prepare to call a usermode helper - * @path: path to usermode executable - * @argv: arg vector for process - * @envp: environment for process - * @gfp_mask: gfp mask for memory allocation - * @cleanup: a cleanup function - * @init: an init function - * @data: arbitrary context sensitive data - * - * Returns either %NULL on allocation failure, or a subprocess_info - * structure. This should be passed to call_usermodehelper_exec to - * exec the process and free the structure. - * - * The init function is used to customize the helper process prior to - * exec. A non-zero return code causes the process to error out, exit, - * and return the failure to the calling process - * - * The cleanup function is just before ethe subprocess_info is about to - * be freed. This can be used for freeing the argv and envp. The - * Function must be runnable in either a process context or the - * context in which call_usermodehelper_exec is called. - */ -struct subprocess_info *call_usermodehelper_setup(char *path, char **argv, - char **envp, gfp_t gfp_mask, - int (*init)(struct subprocess_info *info, struct cred *new), - void (*cleanup)(struct subprocess_info *info), - void *data) -{ - struct subprocess_info *sub_info; - sub_info = kzalloc(sizeof(struct subprocess_info), gfp_mask); - if (!sub_info) - goto out; - - INIT_WORK(&sub_info->work, call_usermodehelper_exec_work); - sub_info->path = path; - sub_info->argv = argv; - sub_info->envp = envp; - - sub_info->cleanup = cleanup; - sub_info->init = init; - sub_info->data = data; - out: - return sub_info; -} -EXPORT_SYMBOL(call_usermodehelper_setup); - -/** - * call_usermodehelper_exec - start a usermode application - * @sub_info: information about the subprocessa - * @wait: wait for the application to finish and return status. - * when UMH_NO_WAIT don't wait at all, but you get no useful error back - * when the program couldn't be exec'ed. This makes it safe to call - * from interrupt context. - * - * Runs a user-space application. The application is started - * asynchronously if wait is not set, and runs as a child of system workqueues. - * (ie. it runs with full root capabilities and optimized affinity). - */ -int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait) -{ - DECLARE_COMPLETION_ONSTACK(done); - int retval = 0; - - if (!sub_info->path) { - call_usermodehelper_freeinfo(sub_info); - return -EINVAL; - } - helper_lock(); - if (usermodehelper_disabled) { - retval = -EBUSY; - goto out; - } - /* - * Set the completion pointer only if there is a waiter. - * This makes it possible to use umh_complete to free - * the data structure in case of UMH_NO_WAIT. - */ - sub_info->complete = (wait == UMH_NO_WAIT) ? NULL : &done; - sub_info->wait = wait; - - queue_work(system_unbound_wq, &sub_info->work); - if (wait == UMH_NO_WAIT) /* task has freed sub_info */ - goto unlock; - - if (wait & UMH_KILLABLE) { - retval = wait_for_completion_killable(&done); - if (!retval) - goto wait_done; - - /* umh_complete() will see NULL and free sub_info */ - if (xchg(&sub_info->complete, NULL)) - goto unlock; - /* fallthrough, umh_complete() was already called */ - } - - wait_for_completion(&done); -wait_done: - retval = sub_info->retval; -out: - call_usermodehelper_freeinfo(sub_info); -unlock: - helper_unlock(); - return retval; -} -EXPORT_SYMBOL(call_usermodehelper_exec); - -/** - * call_usermodehelper() - prepare and start a usermode application - * @path: path to usermode executable - * @argv: arg vector for process - * @envp: environment for process - * @wait: wait for the application to finish and return status. - * when UMH_NO_WAIT don't wait at all, but you get no useful error back - * when the program couldn't be exec'ed. This makes it safe to call - * from interrupt context. - * - * This function is the equivalent to use call_usermodehelper_setup() and - * call_usermodehelper_exec(). - */ -int call_usermodehelper(char *path, char **argv, char **envp, int wait) -{ - struct subprocess_info *info; - gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL; - - info = call_usermodehelper_setup(path, argv, envp, gfp_mask, - NULL, NULL, NULL); - if (info == NULL) - return -ENOMEM; - - return call_usermodehelper_exec(info, wait); -} -EXPORT_SYMBOL(call_usermodehelper); - -static int proc_cap_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - struct ctl_table t; - unsigned long cap_array[_KERNEL_CAPABILITY_U32S]; - kernel_cap_t new_cap; - int err, i; - - if (write && (!capable(CAP_SETPCAP) || - !capable(CAP_SYS_MODULE))) - return -EPERM; - - /* - * convert from the global kernel_cap_t to the ulong array to print to - * userspace if this is a read. - */ - spin_lock(&umh_sysctl_lock); - for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++) { - if (table->data == CAP_BSET) - cap_array[i] = usermodehelper_bset.cap[i]; - else if (table->data == CAP_PI) - cap_array[i] = usermodehelper_inheritable.cap[i]; - else - BUG(); - } - spin_unlock(&umh_sysctl_lock); - - t = *table; - t.data = &cap_array; - - /* - * actually read or write and array of ulongs from userspace. Remember - * these are least significant 32 bits first - */ - err = proc_doulongvec_minmax(&t, write, buffer, lenp, ppos); - if (err < 0) - return err; - - /* - * convert from the sysctl array of ulongs to the kernel_cap_t - * internal representation - */ - for (i = 0; i < _KERNEL_CAPABILITY_U32S; i++) - new_cap.cap[i] = cap_array[i]; - - /* - * Drop everything not in the new_cap (but don't add things) - */ - spin_lock(&umh_sysctl_lock); - if (write) { - if (table->data == CAP_BSET) - usermodehelper_bset = cap_intersect(usermodehelper_bset, new_cap); - if (table->data == CAP_PI) - usermodehelper_inheritable = cap_intersect(usermodehelper_inheritable, new_cap); - } - spin_unlock(&umh_sysctl_lock); - - return 0; -} - -struct ctl_table usermodehelper_table[] = { - { - .procname = "bset", - .data = CAP_BSET, - .maxlen = _KERNEL_CAPABILITY_U32S * sizeof(unsigned long), - .mode = 0600, - .proc_handler = proc_cap_handler, - }, - { - .procname = "inheritable", - .data = CAP_PI, - .maxlen = _KERNEL_CAPABILITY_U32S * sizeof(unsigned long), - .mode = 0600, - .proc_handler = proc_cap_handler, - }, - { } -}; diff --git a/src/linux/kernel/ksysfs.c b/src/linux/kernel/ksysfs.c deleted file mode 100644 index ee1bc1b..0000000 --- a/src/linux/kernel/ksysfs.c +++ /dev/null @@ -1,265 +0,0 @@ -/* - * kernel/ksysfs.c - sysfs attributes in /sys/kernel, which - * are not related to any other subsystem - * - * Copyright (C) 2004 Kay Sievers - * - * This file is release under the GPLv2 - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include /* rcu_expedited and rcu_normal */ - -#define KERNEL_ATTR_RO(_name) \ -static struct kobj_attribute _name##_attr = __ATTR_RO(_name) - -#define KERNEL_ATTR_RW(_name) \ -static struct kobj_attribute _name##_attr = \ - __ATTR(_name, 0644, _name##_show, _name##_store) - -/* current uevent sequence number */ -static ssize_t uevent_seqnum_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - return sprintf(buf, "%llu\n", (unsigned long long)uevent_seqnum); -} -KERNEL_ATTR_RO(uevent_seqnum); - -#ifdef CONFIG_UEVENT_HELPER -/* uevent helper program, used during early boot */ -static ssize_t uevent_helper_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - return sprintf(buf, "%s\n", uevent_helper); -} -static ssize_t uevent_helper_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - if (count+1 > UEVENT_HELPER_PATH_LEN) - return -ENOENT; - memcpy(uevent_helper, buf, count); - uevent_helper[count] = '\0'; - if (count && uevent_helper[count-1] == '\n') - uevent_helper[count-1] = '\0'; - return count; -} -KERNEL_ATTR_RW(uevent_helper); -#endif - -#ifdef CONFIG_PROFILING -static ssize_t profiling_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", prof_on); -} -static ssize_t profiling_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - int ret; - - if (prof_on) - return -EEXIST; - /* - * This eventually calls into get_option() which - * has a ton of callers and is not const. It is - * easiest to cast it away here. - */ - profile_setup((char *)buf); - ret = profile_init(); - if (ret) - return ret; - ret = create_proc_profile(); - if (ret) - return ret; - return count; -} -KERNEL_ATTR_RW(profiling); -#endif - -#ifdef CONFIG_KEXEC_CORE -static ssize_t kexec_loaded_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", !!kexec_image); -} -KERNEL_ATTR_RO(kexec_loaded); - -static ssize_t kexec_crash_loaded_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", kexec_crash_loaded()); -} -KERNEL_ATTR_RO(kexec_crash_loaded); - -static ssize_t kexec_crash_size_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - return sprintf(buf, "%zu\n", crash_get_memory_size()); -} -static ssize_t kexec_crash_size_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - unsigned long cnt; - int ret; - - if (kstrtoul(buf, 0, &cnt)) - return -EINVAL; - - ret = crash_shrink_memory(cnt); - return ret < 0 ? ret : count; -} -KERNEL_ATTR_RW(kexec_crash_size); - -static ssize_t vmcoreinfo_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - phys_addr_t vmcore_base = paddr_vmcoreinfo_note(); - return sprintf(buf, "%pa %x\n", &vmcore_base, - (unsigned int)sizeof(vmcoreinfo_note)); -} -KERNEL_ATTR_RO(vmcoreinfo); - -#endif /* CONFIG_KEXEC_CORE */ - -/* whether file capabilities are enabled */ -static ssize_t fscaps_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", file_caps_enabled); -} -KERNEL_ATTR_RO(fscaps); - -#ifndef CONFIG_TINY_RCU -int rcu_expedited; -static ssize_t rcu_expedited_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", READ_ONCE(rcu_expedited)); -} -static ssize_t rcu_expedited_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - if (kstrtoint(buf, 0, &rcu_expedited)) - return -EINVAL; - - return count; -} -KERNEL_ATTR_RW(rcu_expedited); - -int rcu_normal; -static ssize_t rcu_normal_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", READ_ONCE(rcu_normal)); -} -static ssize_t rcu_normal_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - if (kstrtoint(buf, 0, &rcu_normal)) - return -EINVAL; - - return count; -} -KERNEL_ATTR_RW(rcu_normal); -#endif /* #ifndef CONFIG_TINY_RCU */ - -/* - * Make /sys/kernel/notes give the raw contents of our kernel .notes section. - */ -extern const void __start_notes __weak; -extern const void __stop_notes __weak; -#define notes_size (&__stop_notes - &__start_notes) - -static ssize_t notes_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) -{ - memcpy(buf, &__start_notes + off, count); - return count; -} - -static struct bin_attribute notes_attr = { - .attr = { - .name = "notes", - .mode = S_IRUGO, - }, - .read = ¬es_read, -}; - -struct kobject *kernel_kobj; -EXPORT_SYMBOL_GPL(kernel_kobj); - -static struct attribute * kernel_attrs[] = { - &fscaps_attr.attr, - &uevent_seqnum_attr.attr, -#ifdef CONFIG_UEVENT_HELPER - &uevent_helper_attr.attr, -#endif -#ifdef CONFIG_PROFILING - &profiling_attr.attr, -#endif -#ifdef CONFIG_KEXEC_CORE - &kexec_loaded_attr.attr, - &kexec_crash_loaded_attr.attr, - &kexec_crash_size_attr.attr, - &vmcoreinfo_attr.attr, -#endif -#ifndef CONFIG_TINY_RCU - &rcu_expedited_attr.attr, - &rcu_normal_attr.attr, -#endif - NULL -}; - -static struct attribute_group kernel_attr_group = { - .attrs = kernel_attrs, -}; - -static int __init ksysfs_init(void) -{ - int error; - - kernel_kobj = kobject_create_and_add("kernel", NULL); - if (!kernel_kobj) { - error = -ENOMEM; - goto exit; - } - error = sysfs_create_group(kernel_kobj, &kernel_attr_group); - if (error) - goto kset_exit; - - if (notes_size > 0) { - notes_attr.size = notes_size; - error = sysfs_create_bin_file(kernel_kobj, ¬es_attr); - if (error) - goto group_exit; - } - - return 0; - -group_exit: - sysfs_remove_group(kernel_kobj, &kernel_attr_group); -kset_exit: - kobject_put(kernel_kobj); -exit: - return error; -} - -core_initcall(ksysfs_init); diff --git a/src/linux/kernel/kthread.c b/src/linux/kernel/kthread.c deleted file mode 100644 index be2cc1f..0000000 --- a/src/linux/kernel/kthread.c +++ /dev/null @@ -1,1152 +0,0 @@ -/* Kernel thread helper functions. - * Copyright (C) 2004 IBM Corporation, Rusty Russell. - * - * Creation is done via kthreadd, so that we get a clean environment - * even if we're invoked from userspace (think modprobe, hotplug cpu, - * etc.). - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static DEFINE_SPINLOCK(kthread_create_lock); -static LIST_HEAD(kthread_create_list); -struct task_struct *kthreadd_task; - -struct kthread_create_info -{ - /* Information passed to kthread() from kthreadd. */ - int (*threadfn)(void *data); - void *data; - int node; - - /* Result passed back to kthread_create() from kthreadd. */ - struct task_struct *result; - struct completion *done; - - struct list_head list; -}; - -struct kthread { - unsigned long flags; - unsigned int cpu; - void *data; - struct completion parked; - struct completion exited; -}; - -enum KTHREAD_BITS { - KTHREAD_IS_PER_CPU = 0, - KTHREAD_SHOULD_STOP, - KTHREAD_SHOULD_PARK, - KTHREAD_IS_PARKED, -}; - -#define __to_kthread(vfork) \ - container_of(vfork, struct kthread, exited) - -static inline struct kthread *to_kthread(struct task_struct *k) -{ - return __to_kthread(k->vfork_done); -} - -static struct kthread *to_live_kthread(struct task_struct *k) -{ - struct completion *vfork = ACCESS_ONCE(k->vfork_done); - if (likely(vfork) && try_get_task_stack(k)) - return __to_kthread(vfork); - return NULL; -} - -/** - * kthread_should_stop - should this kthread return now? - * - * When someone calls kthread_stop() on your kthread, it will be woken - * and this will return true. You should then return, and your return - * value will be passed through to kthread_stop(). - */ -bool kthread_should_stop(void) -{ - return test_bit(KTHREAD_SHOULD_STOP, &to_kthread(current)->flags); -} -EXPORT_SYMBOL(kthread_should_stop); - -/** - * kthread_should_park - should this kthread park now? - * - * When someone calls kthread_park() on your kthread, it will be woken - * and this will return true. You should then do the necessary - * cleanup and call kthread_parkme() - * - * Similar to kthread_should_stop(), but this keeps the thread alive - * and in a park position. kthread_unpark() "restarts" the thread and - * calls the thread function again. - */ -bool kthread_should_park(void) -{ - return test_bit(KTHREAD_SHOULD_PARK, &to_kthread(current)->flags); -} -EXPORT_SYMBOL_GPL(kthread_should_park); - -/** - * kthread_freezable_should_stop - should this freezable kthread return now? - * @was_frozen: optional out parameter, indicates whether %current was frozen - * - * kthread_should_stop() for freezable kthreads, which will enter - * refrigerator if necessary. This function is safe from kthread_stop() / - * freezer deadlock and freezable kthreads should use this function instead - * of calling try_to_freeze() directly. - */ -bool kthread_freezable_should_stop(bool *was_frozen) -{ - bool frozen = false; - - might_sleep(); - - if (unlikely(freezing(current))) - frozen = __refrigerator(true); - - if (was_frozen) - *was_frozen = frozen; - - return kthread_should_stop(); -} -EXPORT_SYMBOL_GPL(kthread_freezable_should_stop); - -/** - * kthread_data - return data value specified on kthread creation - * @task: kthread task in question - * - * Return the data value specified when kthread @task was created. - * The caller is responsible for ensuring the validity of @task when - * calling this function. - */ -void *kthread_data(struct task_struct *task) -{ - return to_kthread(task)->data; -} - -/** - * kthread_probe_data - speculative version of kthread_data() - * @task: possible kthread task in question - * - * @task could be a kthread task. Return the data value specified when it - * was created if accessible. If @task isn't a kthread task or its data is - * inaccessible for any reason, %NULL is returned. This function requires - * that @task itself is safe to dereference. - */ -void *kthread_probe_data(struct task_struct *task) -{ - struct kthread *kthread = to_kthread(task); - void *data = NULL; - - probe_kernel_read(&data, &kthread->data, sizeof(data)); - return data; -} - -static void __kthread_parkme(struct kthread *self) -{ - __set_current_state(TASK_PARKED); - while (test_bit(KTHREAD_SHOULD_PARK, &self->flags)) { - if (!test_and_set_bit(KTHREAD_IS_PARKED, &self->flags)) - complete(&self->parked); - schedule(); - __set_current_state(TASK_PARKED); - } - clear_bit(KTHREAD_IS_PARKED, &self->flags); - __set_current_state(TASK_RUNNING); -} - -void kthread_parkme(void) -{ - __kthread_parkme(to_kthread(current)); -} -EXPORT_SYMBOL_GPL(kthread_parkme); - -static int kthread(void *_create) -{ - /* Copy data: it's on kthread's stack */ - struct kthread_create_info *create = _create; - int (*threadfn)(void *data) = create->threadfn; - void *data = create->data; - struct completion *done; - struct kthread self; - int ret; - - self.flags = 0; - self.data = data; - init_completion(&self.exited); - init_completion(&self.parked); - current->vfork_done = &self.exited; - - /* If user was SIGKILLed, I release the structure. */ - done = xchg(&create->done, NULL); - if (!done) { - kfree(create); - do_exit(-EINTR); - } - /* OK, tell user we're spawned, wait for stop or wakeup */ - __set_current_state(TASK_UNINTERRUPTIBLE); - create->result = current; - complete(done); - schedule(); - - ret = -EINTR; - - if (!test_bit(KTHREAD_SHOULD_STOP, &self.flags)) { - __kthread_parkme(&self); - ret = threadfn(data); - } - /* we can't just return, we must preserve "self" on stack */ - do_exit(ret); -} - -/* called from do_fork() to get node information for about to be created task */ -int tsk_fork_get_node(struct task_struct *tsk) -{ -#ifdef CONFIG_NUMA - if (tsk == kthreadd_task) - return tsk->pref_node_fork; -#endif - return NUMA_NO_NODE; -} - -static void create_kthread(struct kthread_create_info *create) -{ - int pid; - -#ifdef CONFIG_NUMA - current->pref_node_fork = create->node; -#endif - /* We want our own signal handler (we take no signals by default). */ - pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD); - if (pid < 0) { - /* If user was SIGKILLed, I release the structure. */ - struct completion *done = xchg(&create->done, NULL); - - if (!done) { - kfree(create); - return; - } - create->result = ERR_PTR(pid); - complete(done); - } -} - -static struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data), - void *data, int node, - const char namefmt[], - va_list args) -{ - DECLARE_COMPLETION_ONSTACK(done); - struct task_struct *task; - struct kthread_create_info *create = kmalloc(sizeof(*create), - GFP_KERNEL); - - if (!create) - return ERR_PTR(-ENOMEM); - create->threadfn = threadfn; - create->data = data; - create->node = node; - create->done = &done; - - spin_lock(&kthread_create_lock); - list_add_tail(&create->list, &kthread_create_list); - spin_unlock(&kthread_create_lock); - - wake_up_process(kthreadd_task); - /* - * Wait for completion in killable state, for I might be chosen by - * the OOM killer while kthreadd is trying to allocate memory for - * new kernel thread. - */ - if (unlikely(wait_for_completion_killable(&done))) { - /* - * If I was SIGKILLed before kthreadd (or new kernel thread) - * calls complete(), leave the cleanup of this structure to - * that thread. - */ - if (xchg(&create->done, NULL)) - return ERR_PTR(-EINTR); - /* - * kthreadd (or new kernel thread) will call complete() - * shortly. - */ - wait_for_completion(&done); - } - task = create->result; - if (!IS_ERR(task)) { - static const struct sched_param param = { .sched_priority = 0 }; - - vsnprintf(task->comm, sizeof(task->comm), namefmt, args); - /* - * root may have changed our (kthreadd's) priority or CPU mask. - * The kernel thread should not inherit these properties. - */ - sched_setscheduler_nocheck(task, SCHED_NORMAL, ¶m); - set_cpus_allowed_ptr(task, cpu_all_mask); - } - kfree(create); - return task; -} - -/** - * kthread_create_on_node - create a kthread. - * @threadfn: the function to run until signal_pending(current). - * @data: data ptr for @threadfn. - * @node: task and thread structures for the thread are allocated on this node - * @namefmt: printf-style name for the thread. - * - * Description: This helper function creates and names a kernel - * thread. The thread will be stopped: use wake_up_process() to start - * it. See also kthread_run(). The new thread has SCHED_NORMAL policy and - * is affine to all CPUs. - * - * If thread is going to be bound on a particular cpu, give its node - * in @node, to get NUMA affinity for kthread stack, or else give NUMA_NO_NODE. - * When woken, the thread will run @threadfn() with @data as its - * argument. @threadfn() can either call do_exit() directly if it is a - * standalone thread for which no one will call kthread_stop(), or - * return when 'kthread_should_stop()' is true (which means - * kthread_stop() has been called). The return value should be zero - * or a negative error number; it will be passed to kthread_stop(). - * - * Returns a task_struct or ERR_PTR(-ENOMEM) or ERR_PTR(-EINTR). - */ -struct task_struct *kthread_create_on_node(int (*threadfn)(void *data), - void *data, int node, - const char namefmt[], - ...) -{ - struct task_struct *task; - va_list args; - - va_start(args, namefmt); - task = __kthread_create_on_node(threadfn, data, node, namefmt, args); - va_end(args); - - return task; -} -EXPORT_SYMBOL(kthread_create_on_node); - -static void __kthread_bind_mask(struct task_struct *p, const struct cpumask *mask, long state) -{ - unsigned long flags; - - if (!wait_task_inactive(p, state)) { - WARN_ON(1); - return; - } - - /* It's safe because the task is inactive. */ - raw_spin_lock_irqsave(&p->pi_lock, flags); - do_set_cpus_allowed(p, mask); - p->flags |= PF_NO_SETAFFINITY; - raw_spin_unlock_irqrestore(&p->pi_lock, flags); -} - -static void __kthread_bind(struct task_struct *p, unsigned int cpu, long state) -{ - __kthread_bind_mask(p, cpumask_of(cpu), state); -} - -void kthread_bind_mask(struct task_struct *p, const struct cpumask *mask) -{ - __kthread_bind_mask(p, mask, TASK_UNINTERRUPTIBLE); -} - -/** - * kthread_bind - bind a just-created kthread to a cpu. - * @p: thread created by kthread_create(). - * @cpu: cpu (might not be online, must be possible) for @k to run on. - * - * Description: This function is equivalent to set_cpus_allowed(), - * except that @cpu doesn't need to be online, and the thread must be - * stopped (i.e., just returned from kthread_create()). - */ -void kthread_bind(struct task_struct *p, unsigned int cpu) -{ - __kthread_bind(p, cpu, TASK_UNINTERRUPTIBLE); -} -EXPORT_SYMBOL(kthread_bind); - -/** - * kthread_create_on_cpu - Create a cpu bound kthread - * @threadfn: the function to run until signal_pending(current). - * @data: data ptr for @threadfn. - * @cpu: The cpu on which the thread should be bound, - * @namefmt: printf-style name for the thread. Format is restricted - * to "name.*%u". Code fills in cpu number. - * - * Description: This helper function creates and names a kernel thread - * The thread will be woken and put into park mode. - */ -struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data), - void *data, unsigned int cpu, - const char *namefmt) -{ - struct task_struct *p; - - p = kthread_create_on_node(threadfn, data, cpu_to_node(cpu), namefmt, - cpu); - if (IS_ERR(p)) - return p; - kthread_bind(p, cpu); - /* CPU hotplug need to bind once again when unparking the thread. */ - set_bit(KTHREAD_IS_PER_CPU, &to_kthread(p)->flags); - to_kthread(p)->cpu = cpu; - return p; -} - -static void __kthread_unpark(struct task_struct *k, struct kthread *kthread) -{ - clear_bit(KTHREAD_SHOULD_PARK, &kthread->flags); - /* - * We clear the IS_PARKED bit here as we don't wait - * until the task has left the park code. So if we'd - * park before that happens we'd see the IS_PARKED bit - * which might be about to be cleared. - */ - if (test_and_clear_bit(KTHREAD_IS_PARKED, &kthread->flags)) { - /* - * Newly created kthread was parked when the CPU was offline. - * The binding was lost and we need to set it again. - */ - if (test_bit(KTHREAD_IS_PER_CPU, &kthread->flags)) - __kthread_bind(k, kthread->cpu, TASK_PARKED); - wake_up_state(k, TASK_PARKED); - } -} - -/** - * kthread_unpark - unpark a thread created by kthread_create(). - * @k: thread created by kthread_create(). - * - * Sets kthread_should_park() for @k to return false, wakes it, and - * waits for it to return. If the thread is marked percpu then its - * bound to the cpu again. - */ -void kthread_unpark(struct task_struct *k) -{ - struct kthread *kthread = to_live_kthread(k); - - if (kthread) { - __kthread_unpark(k, kthread); - put_task_stack(k); - } -} -EXPORT_SYMBOL_GPL(kthread_unpark); - -/** - * kthread_park - park a thread created by kthread_create(). - * @k: thread created by kthread_create(). - * - * Sets kthread_should_park() for @k to return true, wakes it, and - * waits for it to return. This can also be called after kthread_create() - * instead of calling wake_up_process(): the thread will park without - * calling threadfn(). - * - * Returns 0 if the thread is parked, -ENOSYS if the thread exited. - * If called by the kthread itself just the park bit is set. - */ -int kthread_park(struct task_struct *k) -{ - struct kthread *kthread = to_live_kthread(k); - int ret = -ENOSYS; - - if (kthread) { - if (!test_bit(KTHREAD_IS_PARKED, &kthread->flags)) { - set_bit(KTHREAD_SHOULD_PARK, &kthread->flags); - if (k != current) { - wake_up_process(k); - wait_for_completion(&kthread->parked); - } - } - put_task_stack(k); - ret = 0; - } - return ret; -} -EXPORT_SYMBOL_GPL(kthread_park); - -/** - * kthread_stop - stop a thread created by kthread_create(). - * @k: thread created by kthread_create(). - * - * Sets kthread_should_stop() for @k to return true, wakes it, and - * waits for it to exit. This can also be called after kthread_create() - * instead of calling wake_up_process(): the thread will exit without - * calling threadfn(). - * - * If threadfn() may call do_exit() itself, the caller must ensure - * task_struct can't go away. - * - * Returns the result of threadfn(), or %-EINTR if wake_up_process() - * was never called. - */ -int kthread_stop(struct task_struct *k) -{ - struct kthread *kthread; - int ret; - - trace_sched_kthread_stop(k); - - get_task_struct(k); - kthread = to_live_kthread(k); - if (kthread) { - set_bit(KTHREAD_SHOULD_STOP, &kthread->flags); - __kthread_unpark(k, kthread); - wake_up_process(k); - wait_for_completion(&kthread->exited); - put_task_stack(k); - } - ret = k->exit_code; - put_task_struct(k); - - trace_sched_kthread_stop_ret(ret); - return ret; -} -EXPORT_SYMBOL(kthread_stop); - -int kthreadd(void *unused) -{ - struct task_struct *tsk = current; - - /* Setup a clean context for our children to inherit. */ - set_task_comm(tsk, "kthreadd"); - ignore_signals(tsk); - set_cpus_allowed_ptr(tsk, cpu_all_mask); - set_mems_allowed(node_states[N_MEMORY]); - - current->flags |= PF_NOFREEZE; - - for (;;) { - set_current_state(TASK_INTERRUPTIBLE); - if (list_empty(&kthread_create_list)) - schedule(); - __set_current_state(TASK_RUNNING); - - spin_lock(&kthread_create_lock); - while (!list_empty(&kthread_create_list)) { - struct kthread_create_info *create; - - create = list_entry(kthread_create_list.next, - struct kthread_create_info, list); - list_del_init(&create->list); - spin_unlock(&kthread_create_lock); - - create_kthread(create); - - spin_lock(&kthread_create_lock); - } - spin_unlock(&kthread_create_lock); - } - - return 0; -} - -void __kthread_init_worker(struct kthread_worker *worker, - const char *name, - struct lock_class_key *key) -{ - memset(worker, 0, sizeof(struct kthread_worker)); - spin_lock_init(&worker->lock); - lockdep_set_class_and_name(&worker->lock, key, name); - INIT_LIST_HEAD(&worker->work_list); - INIT_LIST_HEAD(&worker->delayed_work_list); -} -EXPORT_SYMBOL_GPL(__kthread_init_worker); - -/** - * kthread_worker_fn - kthread function to process kthread_worker - * @worker_ptr: pointer to initialized kthread_worker - * - * This function implements the main cycle of kthread worker. It processes - * work_list until it is stopped with kthread_stop(). It sleeps when the queue - * is empty. - * - * The works are not allowed to keep any locks, disable preemption or interrupts - * when they finish. There is defined a safe point for freezing when one work - * finishes and before a new one is started. - * - * Also the works must not be handled by more than one worker at the same time, - * see also kthread_queue_work(). - */ -int kthread_worker_fn(void *worker_ptr) -{ - struct kthread_worker *worker = worker_ptr; - struct kthread_work *work; - - /* - * FIXME: Update the check and remove the assignment when all kthread - * worker users are created using kthread_create_worker*() functions. - */ - WARN_ON(worker->task && worker->task != current); - worker->task = current; - - if (worker->flags & KTW_FREEZABLE) - set_freezable(); - -repeat: - set_current_state(TASK_INTERRUPTIBLE); /* mb paired w/ kthread_stop */ - - if (kthread_should_stop()) { - __set_current_state(TASK_RUNNING); - spin_lock_irq(&worker->lock); - worker->task = NULL; - spin_unlock_irq(&worker->lock); - return 0; - } - - work = NULL; - spin_lock_irq(&worker->lock); - if (!list_empty(&worker->work_list)) { - work = list_first_entry(&worker->work_list, - struct kthread_work, node); - list_del_init(&work->node); - } - worker->current_work = work; - spin_unlock_irq(&worker->lock); - - if (work) { - __set_current_state(TASK_RUNNING); - work->func(work); - } else if (!freezing(current)) - schedule(); - - try_to_freeze(); - goto repeat; -} -EXPORT_SYMBOL_GPL(kthread_worker_fn); - -static struct kthread_worker * -__kthread_create_worker(int cpu, unsigned int flags, - const char namefmt[], va_list args) -{ - struct kthread_worker *worker; - struct task_struct *task; - - worker = kzalloc(sizeof(*worker), GFP_KERNEL); - if (!worker) - return ERR_PTR(-ENOMEM); - - kthread_init_worker(worker); - - if (cpu >= 0) { - char name[TASK_COMM_LEN]; - - /* - * kthread_create_worker_on_cpu() allows to pass a generic - * namefmt in compare with kthread_create_on_cpu. We need - * to format it here. - */ - vsnprintf(name, sizeof(name), namefmt, args); - task = kthread_create_on_cpu(kthread_worker_fn, worker, - cpu, name); - } else { - task = __kthread_create_on_node(kthread_worker_fn, worker, - -1, namefmt, args); - } - - if (IS_ERR(task)) - goto fail_task; - - worker->flags = flags; - worker->task = task; - wake_up_process(task); - return worker; - -fail_task: - kfree(worker); - return ERR_CAST(task); -} - -/** - * kthread_create_worker - create a kthread worker - * @flags: flags modifying the default behavior of the worker - * @namefmt: printf-style name for the kthread worker (task). - * - * Returns a pointer to the allocated worker on success, ERR_PTR(-ENOMEM) - * when the needed structures could not get allocated, and ERR_PTR(-EINTR) - * when the worker was SIGKILLed. - */ -struct kthread_worker * -kthread_create_worker(unsigned int flags, const char namefmt[], ...) -{ - struct kthread_worker *worker; - va_list args; - - va_start(args, namefmt); - worker = __kthread_create_worker(-1, flags, namefmt, args); - va_end(args); - - return worker; -} -EXPORT_SYMBOL(kthread_create_worker); - -/** - * kthread_create_worker_on_cpu - create a kthread worker and bind it - * it to a given CPU and the associated NUMA node. - * @cpu: CPU number - * @flags: flags modifying the default behavior of the worker - * @namefmt: printf-style name for the kthread worker (task). - * - * Use a valid CPU number if you want to bind the kthread worker - * to the given CPU and the associated NUMA node. - * - * A good practice is to add the cpu number also into the worker name. - * For example, use kthread_create_worker_on_cpu(cpu, "helper/%d", cpu). - * - * Returns a pointer to the allocated worker on success, ERR_PTR(-ENOMEM) - * when the needed structures could not get allocated, and ERR_PTR(-EINTR) - * when the worker was SIGKILLed. - */ -struct kthread_worker * -kthread_create_worker_on_cpu(int cpu, unsigned int flags, - const char namefmt[], ...) -{ - struct kthread_worker *worker; - va_list args; - - va_start(args, namefmt); - worker = __kthread_create_worker(cpu, flags, namefmt, args); - va_end(args); - - return worker; -} -EXPORT_SYMBOL(kthread_create_worker_on_cpu); - -/* - * Returns true when the work could not be queued at the moment. - * It happens when it is already pending in a worker list - * or when it is being cancelled. - */ -static inline bool queuing_blocked(struct kthread_worker *worker, - struct kthread_work *work) -{ - lockdep_assert_held(&worker->lock); - - return !list_empty(&work->node) || work->canceling; -} - -static void kthread_insert_work_sanity_check(struct kthread_worker *worker, - struct kthread_work *work) -{ - lockdep_assert_held(&worker->lock); - WARN_ON_ONCE(!list_empty(&work->node)); - /* Do not use a work with >1 worker, see kthread_queue_work() */ - WARN_ON_ONCE(work->worker && work->worker != worker); -} - -/* insert @work before @pos in @worker */ -static void kthread_insert_work(struct kthread_worker *worker, - struct kthread_work *work, - struct list_head *pos) -{ - kthread_insert_work_sanity_check(worker, work); - - list_add_tail(&work->node, pos); - work->worker = worker; - if (!worker->current_work && likely(worker->task)) - wake_up_process(worker->task); -} - -/** - * kthread_queue_work - queue a kthread_work - * @worker: target kthread_worker - * @work: kthread_work to queue - * - * Queue @work to work processor @task for async execution. @task - * must have been created with kthread_worker_create(). Returns %true - * if @work was successfully queued, %false if it was already pending. - * - * Reinitialize the work if it needs to be used by another worker. - * For example, when the worker was stopped and started again. - */ -bool kthread_queue_work(struct kthread_worker *worker, - struct kthread_work *work) -{ - bool ret = false; - unsigned long flags; - - spin_lock_irqsave(&worker->lock, flags); - if (!queuing_blocked(worker, work)) { - kthread_insert_work(worker, work, &worker->work_list); - ret = true; - } - spin_unlock_irqrestore(&worker->lock, flags); - return ret; -} -EXPORT_SYMBOL_GPL(kthread_queue_work); - -/** - * kthread_delayed_work_timer_fn - callback that queues the associated kthread - * delayed work when the timer expires. - * @__data: pointer to the data associated with the timer - * - * The format of the function is defined by struct timer_list. - * It should have been called from irqsafe timer with irq already off. - */ -void kthread_delayed_work_timer_fn(unsigned long __data) -{ - struct kthread_delayed_work *dwork = - (struct kthread_delayed_work *)__data; - struct kthread_work *work = &dwork->work; - struct kthread_worker *worker = work->worker; - - /* - * This might happen when a pending work is reinitialized. - * It means that it is used a wrong way. - */ - if (WARN_ON_ONCE(!worker)) - return; - - spin_lock(&worker->lock); - /* Work must not be used with >1 worker, see kthread_queue_work(). */ - WARN_ON_ONCE(work->worker != worker); - - /* Move the work from worker->delayed_work_list. */ - WARN_ON_ONCE(list_empty(&work->node)); - list_del_init(&work->node); - kthread_insert_work(worker, work, &worker->work_list); - - spin_unlock(&worker->lock); -} -EXPORT_SYMBOL(kthread_delayed_work_timer_fn); - -void __kthread_queue_delayed_work(struct kthread_worker *worker, - struct kthread_delayed_work *dwork, - unsigned long delay) -{ - struct timer_list *timer = &dwork->timer; - struct kthread_work *work = &dwork->work; - - WARN_ON_ONCE(timer->function != kthread_delayed_work_timer_fn || - timer->data != (unsigned long)dwork); - - /* - * If @delay is 0, queue @dwork->work immediately. This is for - * both optimization and correctness. The earliest @timer can - * expire is on the closest next tick and delayed_work users depend - * on that there's no such delay when @delay is 0. - */ - if (!delay) { - kthread_insert_work(worker, work, &worker->work_list); - return; - } - - /* Be paranoid and try to detect possible races already now. */ - kthread_insert_work_sanity_check(worker, work); - - list_add(&work->node, &worker->delayed_work_list); - work->worker = worker; - timer_stats_timer_set_start_info(&dwork->timer); - timer->expires = jiffies + delay; - add_timer(timer); -} - -/** - * kthread_queue_delayed_work - queue the associated kthread work - * after a delay. - * @worker: target kthread_worker - * @dwork: kthread_delayed_work to queue - * @delay: number of jiffies to wait before queuing - * - * If the work has not been pending it starts a timer that will queue - * the work after the given @delay. If @delay is zero, it queues the - * work immediately. - * - * Return: %false if the @work has already been pending. It means that - * either the timer was running or the work was queued. It returns %true - * otherwise. - */ -bool kthread_queue_delayed_work(struct kthread_worker *worker, - struct kthread_delayed_work *dwork, - unsigned long delay) -{ - struct kthread_work *work = &dwork->work; - unsigned long flags; - bool ret = false; - - spin_lock_irqsave(&worker->lock, flags); - - if (!queuing_blocked(worker, work)) { - __kthread_queue_delayed_work(worker, dwork, delay); - ret = true; - } - - spin_unlock_irqrestore(&worker->lock, flags); - return ret; -} -EXPORT_SYMBOL_GPL(kthread_queue_delayed_work); - -struct kthread_flush_work { - struct kthread_work work; - struct completion done; -}; - -static void kthread_flush_work_fn(struct kthread_work *work) -{ - struct kthread_flush_work *fwork = - container_of(work, struct kthread_flush_work, work); - complete(&fwork->done); -} - -/** - * kthread_flush_work - flush a kthread_work - * @work: work to flush - * - * If @work is queued or executing, wait for it to finish execution. - */ -void kthread_flush_work(struct kthread_work *work) -{ - struct kthread_flush_work fwork = { - KTHREAD_WORK_INIT(fwork.work, kthread_flush_work_fn), - COMPLETION_INITIALIZER_ONSTACK(fwork.done), - }; - struct kthread_worker *worker; - bool noop = false; - - worker = work->worker; - if (!worker) - return; - - spin_lock_irq(&worker->lock); - /* Work must not be used with >1 worker, see kthread_queue_work(). */ - WARN_ON_ONCE(work->worker != worker); - - if (!list_empty(&work->node)) - kthread_insert_work(worker, &fwork.work, work->node.next); - else if (worker->current_work == work) - kthread_insert_work(worker, &fwork.work, - worker->work_list.next); - else - noop = true; - - spin_unlock_irq(&worker->lock); - - if (!noop) - wait_for_completion(&fwork.done); -} -EXPORT_SYMBOL_GPL(kthread_flush_work); - -/* - * This function removes the work from the worker queue. Also it makes sure - * that it won't get queued later via the delayed work's timer. - * - * The work might still be in use when this function finishes. See the - * current_work proceed by the worker. - * - * Return: %true if @work was pending and successfully canceled, - * %false if @work was not pending - */ -static bool __kthread_cancel_work(struct kthread_work *work, bool is_dwork, - unsigned long *flags) -{ - /* Try to cancel the timer if exists. */ - if (is_dwork) { - struct kthread_delayed_work *dwork = - container_of(work, struct kthread_delayed_work, work); - struct kthread_worker *worker = work->worker; - - /* - * del_timer_sync() must be called to make sure that the timer - * callback is not running. The lock must be temporary released - * to avoid a deadlock with the callback. In the meantime, - * any queuing is blocked by setting the canceling counter. - */ - work->canceling++; - spin_unlock_irqrestore(&worker->lock, *flags); - del_timer_sync(&dwork->timer); - spin_lock_irqsave(&worker->lock, *flags); - work->canceling--; - } - - /* - * Try to remove the work from a worker list. It might either - * be from worker->work_list or from worker->delayed_work_list. - */ - if (!list_empty(&work->node)) { - list_del_init(&work->node); - return true; - } - - return false; -} - -/** - * kthread_mod_delayed_work - modify delay of or queue a kthread delayed work - * @worker: kthread worker to use - * @dwork: kthread delayed work to queue - * @delay: number of jiffies to wait before queuing - * - * If @dwork is idle, equivalent to kthread_queue_delayed_work(). Otherwise, - * modify @dwork's timer so that it expires after @delay. If @delay is zero, - * @work is guaranteed to be queued immediately. - * - * Return: %true if @dwork was pending and its timer was modified, - * %false otherwise. - * - * A special case is when the work is being canceled in parallel. - * It might be caused either by the real kthread_cancel_delayed_work_sync() - * or yet another kthread_mod_delayed_work() call. We let the other command - * win and return %false here. The caller is supposed to synchronize these - * operations a reasonable way. - * - * This function is safe to call from any context including IRQ handler. - * See __kthread_cancel_work() and kthread_delayed_work_timer_fn() - * for details. - */ -bool kthread_mod_delayed_work(struct kthread_worker *worker, - struct kthread_delayed_work *dwork, - unsigned long delay) -{ - struct kthread_work *work = &dwork->work; - unsigned long flags; - int ret = false; - - spin_lock_irqsave(&worker->lock, flags); - - /* Do not bother with canceling when never queued. */ - if (!work->worker) - goto fast_queue; - - /* Work must not be used with >1 worker, see kthread_queue_work() */ - WARN_ON_ONCE(work->worker != worker); - - /* Do not fight with another command that is canceling this work. */ - if (work->canceling) - goto out; - - ret = __kthread_cancel_work(work, true, &flags); -fast_queue: - __kthread_queue_delayed_work(worker, dwork, delay); -out: - spin_unlock_irqrestore(&worker->lock, flags); - return ret; -} -EXPORT_SYMBOL_GPL(kthread_mod_delayed_work); - -static bool __kthread_cancel_work_sync(struct kthread_work *work, bool is_dwork) -{ - struct kthread_worker *worker = work->worker; - unsigned long flags; - int ret = false; - - if (!worker) - goto out; - - spin_lock_irqsave(&worker->lock, flags); - /* Work must not be used with >1 worker, see kthread_queue_work(). */ - WARN_ON_ONCE(work->worker != worker); - - ret = __kthread_cancel_work(work, is_dwork, &flags); - - if (worker->current_work != work) - goto out_fast; - - /* - * The work is in progress and we need to wait with the lock released. - * In the meantime, block any queuing by setting the canceling counter. - */ - work->canceling++; - spin_unlock_irqrestore(&worker->lock, flags); - kthread_flush_work(work); - spin_lock_irqsave(&worker->lock, flags); - work->canceling--; - -out_fast: - spin_unlock_irqrestore(&worker->lock, flags); -out: - return ret; -} - -/** - * kthread_cancel_work_sync - cancel a kthread work and wait for it to finish - * @work: the kthread work to cancel - * - * Cancel @work and wait for its execution to finish. This function - * can be used even if the work re-queues itself. On return from this - * function, @work is guaranteed to be not pending or executing on any CPU. - * - * kthread_cancel_work_sync(&delayed_work->work) must not be used for - * delayed_work's. Use kthread_cancel_delayed_work_sync() instead. - * - * The caller must ensure that the worker on which @work was last - * queued can't be destroyed before this function returns. - * - * Return: %true if @work was pending, %false otherwise. - */ -bool kthread_cancel_work_sync(struct kthread_work *work) -{ - return __kthread_cancel_work_sync(work, false); -} -EXPORT_SYMBOL_GPL(kthread_cancel_work_sync); - -/** - * kthread_cancel_delayed_work_sync - cancel a kthread delayed work and - * wait for it to finish. - * @dwork: the kthread delayed work to cancel - * - * This is kthread_cancel_work_sync() for delayed works. - * - * Return: %true if @dwork was pending, %false otherwise. - */ -bool kthread_cancel_delayed_work_sync(struct kthread_delayed_work *dwork) -{ - return __kthread_cancel_work_sync(&dwork->work, true); -} -EXPORT_SYMBOL_GPL(kthread_cancel_delayed_work_sync); - -/** - * kthread_flush_worker - flush all current works on a kthread_worker - * @worker: worker to flush - * - * Wait until all currently executing or pending works on @worker are - * finished. - */ -void kthread_flush_worker(struct kthread_worker *worker) -{ - struct kthread_flush_work fwork = { - KTHREAD_WORK_INIT(fwork.work, kthread_flush_work_fn), - COMPLETION_INITIALIZER_ONSTACK(fwork.done), - }; - - kthread_queue_work(worker, &fwork.work); - wait_for_completion(&fwork.done); -} -EXPORT_SYMBOL_GPL(kthread_flush_worker); - -/** - * kthread_destroy_worker - destroy a kthread worker - * @worker: worker to be destroyed - * - * Flush and destroy @worker. The simple flush is enough because the kthread - * worker API is used only in trivial scenarios. There are no multi-step state - * machines needed. - */ -void kthread_destroy_worker(struct kthread_worker *worker) -{ - struct task_struct *task; - - task = worker->task; - if (WARN_ON(!task)) - return; - - kthread_flush_worker(worker); - kthread_stop(task); - WARN_ON(!list_empty(&worker->work_list)); - kfree(worker); -} -EXPORT_SYMBOL(kthread_destroy_worker); diff --git a/src/linux/kernel/livepatch/Makefile b/src/linux/kernel/livepatch/Makefile deleted file mode 100644 index e8780c0..0000000 --- a/src/linux/kernel/livepatch/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_LIVEPATCH) += livepatch.o - -livepatch-objs := core.o diff --git a/src/linux/kernel/locking/Makefile b/src/linux/kernel/locking/Makefile deleted file mode 100644 index 6f88e35..0000000 --- a/src/linux/kernel/locking/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -# Any varying coverage in these files is non-deterministic -# and is generally not a function of system call inputs. -KCOV_INSTRUMENT := n - -obj-y += mutex.o semaphore.o rwsem.o percpu-rwsem.o - -ifdef CONFIG_FUNCTION_TRACER -CFLAGS_REMOVE_lockdep.o = $(CC_FLAGS_FTRACE) -CFLAGS_REMOVE_lockdep_proc.o = $(CC_FLAGS_FTRACE) -CFLAGS_REMOVE_mutex-debug.o = $(CC_FLAGS_FTRACE) -CFLAGS_REMOVE_rtmutex-debug.o = $(CC_FLAGS_FTRACE) -endif - -obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o -obj-$(CONFIG_LOCKDEP) += lockdep.o -ifeq ($(CONFIG_PROC_FS),y) -obj-$(CONFIG_LOCKDEP) += lockdep_proc.o -endif -obj-$(CONFIG_SMP) += spinlock.o -obj-$(CONFIG_LOCK_SPIN_ON_OWNER) += osq_lock.o -obj-$(CONFIG_PROVE_LOCKING) += spinlock.o -obj-$(CONFIG_QUEUED_SPINLOCKS) += qspinlock.o -obj-$(CONFIG_RT_MUTEXES) += rtmutex.o -obj-$(CONFIG_DEBUG_RT_MUTEXES) += rtmutex-debug.o -obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock.o -obj-$(CONFIG_DEBUG_SPINLOCK) += spinlock_debug.o -obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o -obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem-xadd.o -obj-$(CONFIG_QUEUED_RWLOCKS) += qrwlock.o -obj-$(CONFIG_LOCK_TORTURE_TEST) += locktorture.o diff --git a/src/linux/kernel/locking/mutex.c b/src/linux/kernel/locking/mutex.c deleted file mode 100644 index a70b90d..0000000 --- a/src/linux/kernel/locking/mutex.c +++ /dev/null @@ -1,977 +0,0 @@ -/* - * kernel/locking/mutex.c - * - * Mutexes: blocking mutual exclusion locks - * - * Started by Ingo Molnar: - * - * Copyright (C) 2004, 2005, 2006 Red Hat, Inc., Ingo Molnar - * - * Many thanks to Arjan van de Ven, Thomas Gleixner, Steven Rostedt and - * David Howells for suggestions and improvements. - * - * - Adaptive spinning for mutexes by Peter Zijlstra. (Ported to mainline - * from the -rt tree, where it was originally implemented for rtmutexes - * by Steven Rostedt, based on work by Gregory Haskins, Peter Morreale - * and Sven Dietrich. - * - * Also see Documentation/locking/mutex-design.txt. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * In the DEBUG case we are using the "NULL fastpath" for mutexes, - * which forces all calls into the slowpath: - */ -#ifdef CONFIG_DEBUG_MUTEXES -# include "mutex-debug.h" -# include -/* - * Must be 0 for the debug case so we do not do the unlock outside of the - * wait_lock region. debug_mutex_unlock() will do the actual unlock in this - * case. - */ -# undef __mutex_slowpath_needs_to_unlock -# define __mutex_slowpath_needs_to_unlock() 0 -#else -# include "mutex.h" -# include -#endif - -void -__mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key) -{ - atomic_set(&lock->count, 1); - spin_lock_init(&lock->wait_lock); - INIT_LIST_HEAD(&lock->wait_list); - mutex_clear_owner(lock); -#ifdef CONFIG_MUTEX_SPIN_ON_OWNER - osq_lock_init(&lock->osq); -#endif - - debug_mutex_init(lock, name, key); -} - -EXPORT_SYMBOL(__mutex_init); - -#ifndef CONFIG_DEBUG_LOCK_ALLOC -/* - * We split the mutex lock/unlock logic into separate fastpath and - * slowpath functions, to reduce the register pressure on the fastpath. - * We also put the fastpath first in the kernel image, to make sure the - * branch is predicted by the CPU as default-untaken. - */ -__visible void __sched __mutex_lock_slowpath(atomic_t *lock_count); - -/** - * mutex_lock - acquire the mutex - * @lock: the mutex to be acquired - * - * Lock the mutex exclusively for this task. If the mutex is not - * available right now, it will sleep until it can get it. - * - * The mutex must later on be released by the same task that - * acquired it. Recursive locking is not allowed. The task - * may not exit without first unlocking the mutex. Also, kernel - * memory where the mutex resides must not be freed with - * the mutex still locked. The mutex must first be initialized - * (or statically defined) before it can be locked. memset()-ing - * the mutex to 0 is not allowed. - * - * ( The CONFIG_DEBUG_MUTEXES .config option turns on debugging - * checks that will enforce the restrictions and will also do - * deadlock debugging. ) - * - * This function is similar to (but not equivalent to) down(). - */ -void __sched mutex_lock(struct mutex *lock) -{ - might_sleep(); - /* - * The locking fastpath is the 1->0 transition from - * 'unlocked' into 'locked' state. - */ - __mutex_fastpath_lock(&lock->count, __mutex_lock_slowpath); - mutex_set_owner(lock); -} - -EXPORT_SYMBOL(mutex_lock); -#endif - -static __always_inline void ww_mutex_lock_acquired(struct ww_mutex *ww, - struct ww_acquire_ctx *ww_ctx) -{ -#ifdef CONFIG_DEBUG_MUTEXES - /* - * If this WARN_ON triggers, you used ww_mutex_lock to acquire, - * but released with a normal mutex_unlock in this call. - * - * This should never happen, always use ww_mutex_unlock. - */ - DEBUG_LOCKS_WARN_ON(ww->ctx); - - /* - * Not quite done after calling ww_acquire_done() ? - */ - DEBUG_LOCKS_WARN_ON(ww_ctx->done_acquire); - - if (ww_ctx->contending_lock) { - /* - * After -EDEADLK you tried to - * acquire a different ww_mutex? Bad! - */ - DEBUG_LOCKS_WARN_ON(ww_ctx->contending_lock != ww); - - /* - * You called ww_mutex_lock after receiving -EDEADLK, - * but 'forgot' to unlock everything else first? - */ - DEBUG_LOCKS_WARN_ON(ww_ctx->acquired > 0); - ww_ctx->contending_lock = NULL; - } - - /* - * Naughty, using a different class will lead to undefined behavior! - */ - DEBUG_LOCKS_WARN_ON(ww_ctx->ww_class != ww->ww_class); -#endif - ww_ctx->acquired++; -} - -/* - * After acquiring lock with fastpath or when we lost out in contested - * slowpath, set ctx and wake up any waiters so they can recheck. - * - * This function is never called when CONFIG_DEBUG_LOCK_ALLOC is set, - * as the fastpath and opportunistic spinning are disabled in that case. - */ -static __always_inline void -ww_mutex_set_context_fastpath(struct ww_mutex *lock, - struct ww_acquire_ctx *ctx) -{ - unsigned long flags; - struct mutex_waiter *cur; - - ww_mutex_lock_acquired(lock, ctx); - - lock->ctx = ctx; - - /* - * The lock->ctx update should be visible on all cores before - * the atomic read is done, otherwise contended waiters might be - * missed. The contended waiters will either see ww_ctx == NULL - * and keep spinning, or it will acquire wait_lock, add itself - * to waiter list and sleep. - */ - smp_mb(); /* ^^^ */ - - /* - * Check if lock is contended, if not there is nobody to wake up - */ - if (likely(atomic_read(&lock->base.count) == 0)) - return; - - /* - * Uh oh, we raced in fastpath, wake up everyone in this case, - * so they can see the new lock->ctx. - */ - spin_lock_mutex(&lock->base.wait_lock, flags); - list_for_each_entry(cur, &lock->base.wait_list, list) { - debug_mutex_wake_waiter(&lock->base, cur); - wake_up_process(cur->task); - } - spin_unlock_mutex(&lock->base.wait_lock, flags); -} - -/* - * After acquiring lock in the slowpath set ctx and wake up any - * waiters so they can recheck. - * - * Callers must hold the mutex wait_lock. - */ -static __always_inline void -ww_mutex_set_context_slowpath(struct ww_mutex *lock, - struct ww_acquire_ctx *ctx) -{ - struct mutex_waiter *cur; - - ww_mutex_lock_acquired(lock, ctx); - lock->ctx = ctx; - - /* - * Give any possible sleeping processes the chance to wake up, - * so they can recheck if they have to back off. - */ - list_for_each_entry(cur, &lock->base.wait_list, list) { - debug_mutex_wake_waiter(&lock->base, cur); - wake_up_process(cur->task); - } -} - -#ifdef CONFIG_MUTEX_SPIN_ON_OWNER -/* - * Look out! "owner" is an entirely speculative pointer - * access and not reliable. - */ -static noinline -bool mutex_spin_on_owner(struct mutex *lock, struct task_struct *owner) -{ - bool ret = true; - - rcu_read_lock(); - while (lock->owner == owner) { - /* - * Ensure we emit the owner->on_cpu, dereference _after_ - * checking lock->owner still matches owner. If that fails, - * owner might point to freed memory. If it still matches, - * the rcu_read_lock() ensures the memory stays valid. - */ - barrier(); - - if (!owner->on_cpu || need_resched()) { - ret = false; - break; - } - - cpu_relax_lowlatency(); - } - rcu_read_unlock(); - - return ret; -} - -/* - * Initial check for entering the mutex spinning loop - */ -static inline int mutex_can_spin_on_owner(struct mutex *lock) -{ - struct task_struct *owner; - int retval = 1; - - if (need_resched()) - return 0; - - rcu_read_lock(); - owner = READ_ONCE(lock->owner); - if (owner) - retval = owner->on_cpu; - rcu_read_unlock(); - /* - * if lock->owner is not set, the mutex owner may have just acquired - * it and not set the owner yet or the mutex has been released. - */ - return retval; -} - -/* - * Atomically try to take the lock when it is available - */ -static inline bool mutex_try_to_acquire(struct mutex *lock) -{ - return !mutex_is_locked(lock) && - (atomic_cmpxchg_acquire(&lock->count, 1, 0) == 1); -} - -/* - * Optimistic spinning. - * - * We try to spin for acquisition when we find that the lock owner - * is currently running on a (different) CPU and while we don't - * need to reschedule. The rationale is that if the lock owner is - * running, it is likely to release the lock soon. - * - * Since this needs the lock owner, and this mutex implementation - * doesn't track the owner atomically in the lock field, we need to - * track it non-atomically. - * - * We can't do this for DEBUG_MUTEXES because that relies on wait_lock - * to serialize everything. - * - * The mutex spinners are queued up using MCS lock so that only one - * spinner can compete for the mutex. However, if mutex spinning isn't - * going to happen, there is no point in going through the lock/unlock - * overhead. - * - * Returns true when the lock was taken, otherwise false, indicating - * that we need to jump to the slowpath and sleep. - */ -static bool mutex_optimistic_spin(struct mutex *lock, - struct ww_acquire_ctx *ww_ctx, const bool use_ww_ctx) -{ - struct task_struct *task = current; - - if (!mutex_can_spin_on_owner(lock)) - goto done; - - /* - * In order to avoid a stampede of mutex spinners trying to - * acquire the mutex all at once, the spinners need to take a - * MCS (queued) lock first before spinning on the owner field. - */ - if (!osq_lock(&lock->osq)) - goto done; - - while (true) { - struct task_struct *owner; - - if (use_ww_ctx && ww_ctx->acquired > 0) { - struct ww_mutex *ww; - - ww = container_of(lock, struct ww_mutex, base); - /* - * If ww->ctx is set the contents are undefined, only - * by acquiring wait_lock there is a guarantee that - * they are not invalid when reading. - * - * As such, when deadlock detection needs to be - * performed the optimistic spinning cannot be done. - */ - if (READ_ONCE(ww->ctx)) - break; - } - - /* - * If there's an owner, wait for it to either - * release the lock or go to sleep. - */ - owner = READ_ONCE(lock->owner); - if (owner && !mutex_spin_on_owner(lock, owner)) - break; - - /* Try to acquire the mutex if it is unlocked. */ - if (mutex_try_to_acquire(lock)) { - lock_acquired(&lock->dep_map, ip); - - if (use_ww_ctx) { - struct ww_mutex *ww; - ww = container_of(lock, struct ww_mutex, base); - - ww_mutex_set_context_fastpath(ww, ww_ctx); - } - - mutex_set_owner(lock); - osq_unlock(&lock->osq); - return true; - } - - /* - * When there's no owner, we might have preempted between the - * owner acquiring the lock and setting the owner field. If - * we're an RT task that will live-lock because we won't let - * the owner complete. - */ - if (!owner && (need_resched() || rt_task(task))) - break; - - /* - * The cpu_relax() call is a compiler barrier which forces - * everything in this loop to be re-loaded. We don't need - * memory barriers as we'll eventually observe the right - * values at the cost of a few extra spins. - */ - cpu_relax_lowlatency(); - } - - osq_unlock(&lock->osq); -done: - /* - * If we fell out of the spin path because of need_resched(), - * reschedule now, before we try-lock the mutex. This avoids getting - * scheduled out right after we obtained the mutex. - */ - if (need_resched()) { - /* - * We _should_ have TASK_RUNNING here, but just in case - * we do not, make it so, otherwise we might get stuck. - */ - __set_current_state(TASK_RUNNING); - schedule_preempt_disabled(); - } - - return false; -} -#else -static bool mutex_optimistic_spin(struct mutex *lock, - struct ww_acquire_ctx *ww_ctx, const bool use_ww_ctx) -{ - return false; -} -#endif - -__visible __used noinline -void __sched __mutex_unlock_slowpath(atomic_t *lock_count); - -/** - * mutex_unlock - release the mutex - * @lock: the mutex to be released - * - * Unlock a mutex that has been locked by this task previously. - * - * This function must not be used in interrupt context. Unlocking - * of a not locked mutex is not allowed. - * - * This function is similar to (but not equivalent to) up(). - */ -void __sched mutex_unlock(struct mutex *lock) -{ - /* - * The unlocking fastpath is the 0->1 transition from 'locked' - * into 'unlocked' state: - */ -#ifndef CONFIG_DEBUG_MUTEXES - /* - * When debugging is enabled we must not clear the owner before time, - * the slow path will always be taken, and that clears the owner field - * after verifying that it was indeed current. - */ - mutex_clear_owner(lock); -#endif - __mutex_fastpath_unlock(&lock->count, __mutex_unlock_slowpath); -} - -EXPORT_SYMBOL(mutex_unlock); - -/** - * ww_mutex_unlock - release the w/w mutex - * @lock: the mutex to be released - * - * Unlock a mutex that has been locked by this task previously with any of the - * ww_mutex_lock* functions (with or without an acquire context). It is - * forbidden to release the locks after releasing the acquire context. - * - * This function must not be used in interrupt context. Unlocking - * of a unlocked mutex is not allowed. - */ -void __sched ww_mutex_unlock(struct ww_mutex *lock) -{ - /* - * The unlocking fastpath is the 0->1 transition from 'locked' - * into 'unlocked' state: - */ - if (lock->ctx) { -#ifdef CONFIG_DEBUG_MUTEXES - DEBUG_LOCKS_WARN_ON(!lock->ctx->acquired); -#endif - if (lock->ctx->acquired > 0) - lock->ctx->acquired--; - lock->ctx = NULL; - } - -#ifndef CONFIG_DEBUG_MUTEXES - /* - * When debugging is enabled we must not clear the owner before time, - * the slow path will always be taken, and that clears the owner field - * after verifying that it was indeed current. - */ - mutex_clear_owner(&lock->base); -#endif - __mutex_fastpath_unlock(&lock->base.count, __mutex_unlock_slowpath); -} -EXPORT_SYMBOL(ww_mutex_unlock); - -static inline int __sched -__ww_mutex_lock_check_stamp(struct mutex *lock, struct ww_acquire_ctx *ctx) -{ - struct ww_mutex *ww = container_of(lock, struct ww_mutex, base); - struct ww_acquire_ctx *hold_ctx = READ_ONCE(ww->ctx); - - if (!hold_ctx) - return 0; - - if (ctx->stamp - hold_ctx->stamp <= LONG_MAX && - (ctx->stamp != hold_ctx->stamp || ctx > hold_ctx)) { -#ifdef CONFIG_DEBUG_MUTEXES - DEBUG_LOCKS_WARN_ON(ctx->contending_lock); - ctx->contending_lock = ww; -#endif - return -EDEADLK; - } - - return 0; -} - -/* - * Lock a mutex (possibly interruptible), slowpath: - */ -static __always_inline int __sched -__mutex_lock_common(struct mutex *lock, long state, unsigned int subclass, - struct lockdep_map *nest_lock, unsigned long ip, - struct ww_acquire_ctx *ww_ctx, const bool use_ww_ctx) -{ - struct task_struct *task = current; - struct mutex_waiter waiter; - unsigned long flags; - int ret; - - if (use_ww_ctx) { - struct ww_mutex *ww = container_of(lock, struct ww_mutex, base); - if (unlikely(ww_ctx == READ_ONCE(ww->ctx))) - return -EALREADY; - } - - preempt_disable(); - mutex_acquire_nest(&lock->dep_map, subclass, 0, nest_lock, ip); - - if (mutex_optimistic_spin(lock, ww_ctx, use_ww_ctx)) { - /* got the lock, yay! */ - preempt_enable(); - return 0; - } - - spin_lock_mutex(&lock->wait_lock, flags); - - /* - * Once more, try to acquire the lock. Only try-lock the mutex if - * it is unlocked to reduce unnecessary xchg() operations. - */ - if (!mutex_is_locked(lock) && - (atomic_xchg_acquire(&lock->count, 0) == 1)) - goto skip_wait; - - debug_mutex_lock_common(lock, &waiter); - debug_mutex_add_waiter(lock, &waiter, task); - - /* add waiting tasks to the end of the waitqueue (FIFO): */ - list_add_tail(&waiter.list, &lock->wait_list); - waiter.task = task; - - lock_contended(&lock->dep_map, ip); - - for (;;) { - /* - * Lets try to take the lock again - this is needed even if - * we get here for the first time (shortly after failing to - * acquire the lock), to make sure that we get a wakeup once - * it's unlocked. Later on, if we sleep, this is the - * operation that gives us the lock. We xchg it to -1, so - * that when we release the lock, we properly wake up the - * other waiters. We only attempt the xchg if the count is - * non-negative in order to avoid unnecessary xchg operations: - */ - if (atomic_read(&lock->count) >= 0 && - (atomic_xchg_acquire(&lock->count, -1) == 1)) - break; - - /* - * got a signal? (This code gets eliminated in the - * TASK_UNINTERRUPTIBLE case.) - */ - if (unlikely(signal_pending_state(state, task))) { - ret = -EINTR; - goto err; - } - - if (use_ww_ctx && ww_ctx->acquired > 0) { - ret = __ww_mutex_lock_check_stamp(lock, ww_ctx); - if (ret) - goto err; - } - - __set_task_state(task, state); - - /* didn't get the lock, go to sleep: */ - spin_unlock_mutex(&lock->wait_lock, flags); - schedule_preempt_disabled(); - spin_lock_mutex(&lock->wait_lock, flags); - } - __set_task_state(task, TASK_RUNNING); - - mutex_remove_waiter(lock, &waiter, task); - /* set it to 0 if there are no waiters left: */ - if (likely(list_empty(&lock->wait_list))) - atomic_set(&lock->count, 0); - debug_mutex_free_waiter(&waiter); - -skip_wait: - /* got the lock - cleanup and rejoice! */ - lock_acquired(&lock->dep_map, ip); - mutex_set_owner(lock); - - if (use_ww_ctx) { - struct ww_mutex *ww = container_of(lock, struct ww_mutex, base); - ww_mutex_set_context_slowpath(ww, ww_ctx); - } - - spin_unlock_mutex(&lock->wait_lock, flags); - preempt_enable(); - return 0; - -err: - mutex_remove_waiter(lock, &waiter, task); - spin_unlock_mutex(&lock->wait_lock, flags); - debug_mutex_free_waiter(&waiter); - mutex_release(&lock->dep_map, 1, ip); - preempt_enable(); - return ret; -} - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -void __sched -mutex_lock_nested(struct mutex *lock, unsigned int subclass) -{ - might_sleep(); - __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, - subclass, NULL, _RET_IP_, NULL, 0); -} - -EXPORT_SYMBOL_GPL(mutex_lock_nested); - -void __sched -_mutex_lock_nest_lock(struct mutex *lock, struct lockdep_map *nest) -{ - might_sleep(); - __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, - 0, nest, _RET_IP_, NULL, 0); -} - -EXPORT_SYMBOL_GPL(_mutex_lock_nest_lock); - -int __sched -mutex_lock_killable_nested(struct mutex *lock, unsigned int subclass) -{ - might_sleep(); - return __mutex_lock_common(lock, TASK_KILLABLE, - subclass, NULL, _RET_IP_, NULL, 0); -} -EXPORT_SYMBOL_GPL(mutex_lock_killable_nested); - -int __sched -mutex_lock_interruptible_nested(struct mutex *lock, unsigned int subclass) -{ - might_sleep(); - return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, - subclass, NULL, _RET_IP_, NULL, 0); -} - -EXPORT_SYMBOL_GPL(mutex_lock_interruptible_nested); - -static inline int -ww_mutex_deadlock_injection(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) -{ -#ifdef CONFIG_DEBUG_WW_MUTEX_SLOWPATH - unsigned tmp; - - if (ctx->deadlock_inject_countdown-- == 0) { - tmp = ctx->deadlock_inject_interval; - if (tmp > UINT_MAX/4) - tmp = UINT_MAX; - else - tmp = tmp*2 + tmp + tmp/2; - - ctx->deadlock_inject_interval = tmp; - ctx->deadlock_inject_countdown = tmp; - ctx->contending_lock = lock; - - ww_mutex_unlock(lock); - - return -EDEADLK; - } -#endif - - return 0; -} - -int __sched -__ww_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) -{ - int ret; - - might_sleep(); - ret = __mutex_lock_common(&lock->base, TASK_UNINTERRUPTIBLE, - 0, &ctx->dep_map, _RET_IP_, ctx, 1); - if (!ret && ctx->acquired > 1) - return ww_mutex_deadlock_injection(lock, ctx); - - return ret; -} -EXPORT_SYMBOL_GPL(__ww_mutex_lock); - -int __sched -__ww_mutex_lock_interruptible(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) -{ - int ret; - - might_sleep(); - ret = __mutex_lock_common(&lock->base, TASK_INTERRUPTIBLE, - 0, &ctx->dep_map, _RET_IP_, ctx, 1); - - if (!ret && ctx->acquired > 1) - return ww_mutex_deadlock_injection(lock, ctx); - - return ret; -} -EXPORT_SYMBOL_GPL(__ww_mutex_lock_interruptible); - -#endif - -/* - * Release the lock, slowpath: - */ -static inline void -__mutex_unlock_common_slowpath(struct mutex *lock, int nested) -{ - unsigned long flags; - WAKE_Q(wake_q); - - /* - * As a performance measurement, release the lock before doing other - * wakeup related duties to follow. This allows other tasks to acquire - * the lock sooner, while still handling cleanups in past unlock calls. - * This can be done as we do not enforce strict equivalence between the - * mutex counter and wait_list. - * - * - * Some architectures leave the lock unlocked in the fastpath failure - * case, others need to leave it locked. In the later case we have to - * unlock it here - as the lock counter is currently 0 or negative. - */ - if (__mutex_slowpath_needs_to_unlock()) - atomic_set(&lock->count, 1); - - spin_lock_mutex(&lock->wait_lock, flags); - mutex_release(&lock->dep_map, nested, _RET_IP_); - debug_mutex_unlock(lock); - - if (!list_empty(&lock->wait_list)) { - /* get the first entry from the wait-list: */ - struct mutex_waiter *waiter = - list_entry(lock->wait_list.next, - struct mutex_waiter, list); - - debug_mutex_wake_waiter(lock, waiter); - wake_q_add(&wake_q, waiter->task); - } - - spin_unlock_mutex(&lock->wait_lock, flags); - wake_up_q(&wake_q); -} - -/* - * Release the lock, slowpath: - */ -__visible void -__mutex_unlock_slowpath(atomic_t *lock_count) -{ - struct mutex *lock = container_of(lock_count, struct mutex, count); - - __mutex_unlock_common_slowpath(lock, 1); -} - -#ifndef CONFIG_DEBUG_LOCK_ALLOC -/* - * Here come the less common (and hence less performance-critical) APIs: - * mutex_lock_interruptible() and mutex_trylock(). - */ -static noinline int __sched -__mutex_lock_killable_slowpath(struct mutex *lock); - -static noinline int __sched -__mutex_lock_interruptible_slowpath(struct mutex *lock); - -/** - * mutex_lock_interruptible - acquire the mutex, interruptible - * @lock: the mutex to be acquired - * - * Lock the mutex like mutex_lock(), and return 0 if the mutex has - * been acquired or sleep until the mutex becomes available. If a - * signal arrives while waiting for the lock then this function - * returns -EINTR. - * - * This function is similar to (but not equivalent to) down_interruptible(). - */ -int __sched mutex_lock_interruptible(struct mutex *lock) -{ - int ret; - - might_sleep(); - ret = __mutex_fastpath_lock_retval(&lock->count); - if (likely(!ret)) { - mutex_set_owner(lock); - return 0; - } else - return __mutex_lock_interruptible_slowpath(lock); -} - -EXPORT_SYMBOL(mutex_lock_interruptible); - -int __sched mutex_lock_killable(struct mutex *lock) -{ - int ret; - - might_sleep(); - ret = __mutex_fastpath_lock_retval(&lock->count); - if (likely(!ret)) { - mutex_set_owner(lock); - return 0; - } else - return __mutex_lock_killable_slowpath(lock); -} -EXPORT_SYMBOL(mutex_lock_killable); - -__visible void __sched -__mutex_lock_slowpath(atomic_t *lock_count) -{ - struct mutex *lock = container_of(lock_count, struct mutex, count); - - __mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, - NULL, _RET_IP_, NULL, 0); -} - -static noinline int __sched -__mutex_lock_killable_slowpath(struct mutex *lock) -{ - return __mutex_lock_common(lock, TASK_KILLABLE, 0, - NULL, _RET_IP_, NULL, 0); -} - -static noinline int __sched -__mutex_lock_interruptible_slowpath(struct mutex *lock) -{ - return __mutex_lock_common(lock, TASK_INTERRUPTIBLE, 0, - NULL, _RET_IP_, NULL, 0); -} - -static noinline int __sched -__ww_mutex_lock_slowpath(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) -{ - return __mutex_lock_common(&lock->base, TASK_UNINTERRUPTIBLE, 0, - NULL, _RET_IP_, ctx, 1); -} - -static noinline int __sched -__ww_mutex_lock_interruptible_slowpath(struct ww_mutex *lock, - struct ww_acquire_ctx *ctx) -{ - return __mutex_lock_common(&lock->base, TASK_INTERRUPTIBLE, 0, - NULL, _RET_IP_, ctx, 1); -} - -#endif - -/* - * Spinlock based trylock, we take the spinlock and check whether we - * can get the lock: - */ -static inline int __mutex_trylock_slowpath(atomic_t *lock_count) -{ - struct mutex *lock = container_of(lock_count, struct mutex, count); - unsigned long flags; - int prev; - - /* No need to trylock if the mutex is locked. */ - if (mutex_is_locked(lock)) - return 0; - - spin_lock_mutex(&lock->wait_lock, flags); - - prev = atomic_xchg_acquire(&lock->count, -1); - if (likely(prev == 1)) { - mutex_set_owner(lock); - mutex_acquire(&lock->dep_map, 0, 1, _RET_IP_); - } - - /* Set it back to 0 if there are no waiters: */ - if (likely(list_empty(&lock->wait_list))) - atomic_set(&lock->count, 0); - - spin_unlock_mutex(&lock->wait_lock, flags); - - return prev == 1; -} - -/** - * mutex_trylock - try to acquire the mutex, without waiting - * @lock: the mutex to be acquired - * - * Try to acquire the mutex atomically. Returns 1 if the mutex - * has been acquired successfully, and 0 on contention. - * - * NOTE: this function follows the spin_trylock() convention, so - * it is negated from the down_trylock() return values! Be careful - * about this when converting semaphore users to mutexes. - * - * This function must not be used in interrupt context. The - * mutex must be released by the same task that acquired it. - */ -int __sched mutex_trylock(struct mutex *lock) -{ - int ret; - - ret = __mutex_fastpath_trylock(&lock->count, __mutex_trylock_slowpath); - if (ret) - mutex_set_owner(lock); - - return ret; -} -EXPORT_SYMBOL(mutex_trylock); - -#ifndef CONFIG_DEBUG_LOCK_ALLOC -int __sched -__ww_mutex_lock(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) -{ - int ret; - - might_sleep(); - - ret = __mutex_fastpath_lock_retval(&lock->base.count); - - if (likely(!ret)) { - ww_mutex_set_context_fastpath(lock, ctx); - mutex_set_owner(&lock->base); - } else - ret = __ww_mutex_lock_slowpath(lock, ctx); - return ret; -} -EXPORT_SYMBOL(__ww_mutex_lock); - -int __sched -__ww_mutex_lock_interruptible(struct ww_mutex *lock, struct ww_acquire_ctx *ctx) -{ - int ret; - - might_sleep(); - - ret = __mutex_fastpath_lock_retval(&lock->base.count); - - if (likely(!ret)) { - ww_mutex_set_context_fastpath(lock, ctx); - mutex_set_owner(&lock->base); - } else - ret = __ww_mutex_lock_interruptible_slowpath(lock, ctx); - return ret; -} -EXPORT_SYMBOL(__ww_mutex_lock_interruptible); - -#endif - -/** - * atomic_dec_and_mutex_lock - return holding mutex if we dec to 0 - * @cnt: the atomic which we are to dec - * @lock: the mutex to return holding if we dec to 0 - * - * return true and hold lock if we dec to 0, return false otherwise - */ -int atomic_dec_and_mutex_lock(atomic_t *cnt, struct mutex *lock) -{ - /* dec if we can't possibly hit 0 */ - if (atomic_add_unless(cnt, -1, 1)) - return 0; - /* we might hit 0, so take the lock */ - mutex_lock(lock); - if (!atomic_dec_and_test(cnt)) { - /* when we actually did the dec, we didn't hit 0 */ - mutex_unlock(lock); - return 0; - } - /* we hit 0, and we hold the lock */ - return 1; -} -EXPORT_SYMBOL(atomic_dec_and_mutex_lock); diff --git a/src/linux/kernel/locking/mutex.h b/src/linux/kernel/locking/mutex.h deleted file mode 100644 index 6cd6b8e..0000000 --- a/src/linux/kernel/locking/mutex.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Mutexes: blocking mutual exclusion locks - * - * started by Ingo Molnar: - * - * Copyright (C) 2004, 2005, 2006 Red Hat, Inc., Ingo Molnar - * - * This file contains mutex debugging related internal prototypes, for the - * !CONFIG_DEBUG_MUTEXES case. Most of them are NOPs: - */ - -#define spin_lock_mutex(lock, flags) \ - do { spin_lock(lock); (void)(flags); } while (0) -#define spin_unlock_mutex(lock, flags) \ - do { spin_unlock(lock); (void)(flags); } while (0) -#define mutex_remove_waiter(lock, waiter, task) \ - __list_del((waiter)->list.prev, (waiter)->list.next) - -#ifdef CONFIG_MUTEX_SPIN_ON_OWNER -/* - * The mutex owner can get read and written to locklessly. - * We should use WRITE_ONCE when writing the owner value to - * avoid store tearing, otherwise, a thread could potentially - * read a partially written and incomplete owner value. - */ -static inline void mutex_set_owner(struct mutex *lock) -{ - WRITE_ONCE(lock->owner, current); -} - -static inline void mutex_clear_owner(struct mutex *lock) -{ - WRITE_ONCE(lock->owner, NULL); -} -#else -static inline void mutex_set_owner(struct mutex *lock) -{ -} - -static inline void mutex_clear_owner(struct mutex *lock) -{ -} -#endif - -#define debug_mutex_wake_waiter(lock, waiter) do { } while (0) -#define debug_mutex_free_waiter(waiter) do { } while (0) -#define debug_mutex_add_waiter(lock, waiter, ti) do { } while (0) -#define debug_mutex_unlock(lock) do { } while (0) -#define debug_mutex_init(lock, name, key) do { } while (0) - -static inline void -debug_mutex_lock_common(struct mutex *lock, struct mutex_waiter *waiter) -{ -} diff --git a/src/linux/kernel/locking/percpu-rwsem.c b/src/linux/kernel/locking/percpu-rwsem.c deleted file mode 100644 index ce18259..0000000 --- a/src/linux/kernel/locking/percpu-rwsem.c +++ /dev/null @@ -1,193 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int __percpu_init_rwsem(struct percpu_rw_semaphore *sem, - const char *name, struct lock_class_key *rwsem_key) -{ - sem->read_count = alloc_percpu(int); - if (unlikely(!sem->read_count)) - return -ENOMEM; - - /* ->rw_sem represents the whole percpu_rw_semaphore for lockdep */ - rcu_sync_init(&sem->rss, RCU_SCHED_SYNC); - __init_rwsem(&sem->rw_sem, name, rwsem_key); - init_waitqueue_head(&sem->writer); - sem->readers_block = 0; - return 0; -} -EXPORT_SYMBOL_GPL(__percpu_init_rwsem); - -void percpu_free_rwsem(struct percpu_rw_semaphore *sem) -{ - /* - * XXX: temporary kludge. The error path in alloc_super() - * assumes that percpu_free_rwsem() is safe after kzalloc(). - */ - if (!sem->read_count) - return; - - rcu_sync_dtor(&sem->rss); - free_percpu(sem->read_count); - sem->read_count = NULL; /* catch use after free bugs */ -} -EXPORT_SYMBOL_GPL(percpu_free_rwsem); - -int __percpu_down_read(struct percpu_rw_semaphore *sem, int try) -{ - /* - * Due to having preemption disabled the decrement happens on - * the same CPU as the increment, avoiding the - * increment-on-one-CPU-and-decrement-on-another problem. - * - * If the reader misses the writer's assignment of readers_block, then - * the writer is guaranteed to see the reader's increment. - * - * Conversely, any readers that increment their sem->read_count after - * the writer looks are guaranteed to see the readers_block value, - * which in turn means that they are guaranteed to immediately - * decrement their sem->read_count, so that it doesn't matter that the - * writer missed them. - */ - - smp_mb(); /* A matches D */ - - /* - * If !readers_block the critical section starts here, matched by the - * release in percpu_up_write(). - */ - if (likely(!smp_load_acquire(&sem->readers_block))) - return 1; - - /* - * Per the above comment; we still have preemption disabled and - * will thus decrement on the same CPU as we incremented. - */ - __percpu_up_read(sem); - - if (try) - return 0; - - /* - * We either call schedule() in the wait, or we'll fall through - * and reschedule on the preempt_enable() in percpu_down_read(). - */ - preempt_enable_no_resched(); - - /* - * Avoid lockdep for the down/up_read() we already have them. - */ - __down_read(&sem->rw_sem); - this_cpu_inc(*sem->read_count); - __up_read(&sem->rw_sem); - - preempt_disable(); - return 1; -} -EXPORT_SYMBOL_GPL(__percpu_down_read); - -void __percpu_up_read(struct percpu_rw_semaphore *sem) -{ - smp_mb(); /* B matches C */ - /* - * In other words, if they see our decrement (presumably to aggregate - * zero, as that is the only time it matters) they will also see our - * critical section. - */ - __this_cpu_dec(*sem->read_count); - - /* Prod writer to recheck readers_active */ - wake_up(&sem->writer); -} -EXPORT_SYMBOL_GPL(__percpu_up_read); - -#define per_cpu_sum(var) \ -({ \ - typeof(var) __sum = 0; \ - int cpu; \ - compiletime_assert_atomic_type(__sum); \ - for_each_possible_cpu(cpu) \ - __sum += per_cpu(var, cpu); \ - __sum; \ -}) - -/* - * Return true if the modular sum of the sem->read_count per-CPU variable is - * zero. If this sum is zero, then it is stable due to the fact that if any - * newly arriving readers increment a given counter, they will immediately - * decrement that same counter. - */ -static bool readers_active_check(struct percpu_rw_semaphore *sem) -{ - if (per_cpu_sum(*sem->read_count) != 0) - return false; - - /* - * If we observed the decrement; ensure we see the entire critical - * section. - */ - - smp_mb(); /* C matches B */ - - return true; -} - -void percpu_down_write(struct percpu_rw_semaphore *sem) -{ - /* Notify readers to take the slow path. */ - rcu_sync_enter(&sem->rss); - - down_write(&sem->rw_sem); - - /* - * Notify new readers to block; up until now, and thus throughout the - * longish rcu_sync_enter() above, new readers could still come in. - */ - WRITE_ONCE(sem->readers_block, 1); - - smp_mb(); /* D matches A */ - - /* - * If they don't see our writer of readers_block, then we are - * guaranteed to see their sem->read_count increment, and therefore - * will wait for them. - */ - - /* Wait for all now active readers to complete. */ - wait_event(sem->writer, readers_active_check(sem)); -} -EXPORT_SYMBOL_GPL(percpu_down_write); - -void percpu_up_write(struct percpu_rw_semaphore *sem) -{ - /* - * Signal the writer is done, no fast path yet. - * - * One reason that we cannot just immediately flip to readers_fast is - * that new readers might fail to see the results of this writer's - * critical section. - * - * Therefore we force it through the slow path which guarantees an - * acquire and thereby guarantees the critical section's consistency. - */ - smp_store_release(&sem->readers_block, 0); - - /* - * Release the write lock, this will allow readers back in the game. - */ - up_write(&sem->rw_sem); - - /* - * Once this completes (at least one RCU-sched grace period hence) the - * reader fast path will be available again. Safe to use outside the - * exclusive write lock because its counting. - */ - rcu_sync_exit(&sem->rss); -} -EXPORT_SYMBOL_GPL(percpu_up_write); diff --git a/src/linux/kernel/locking/rwsem-spinlock.c b/src/linux/kernel/locking/rwsem-spinlock.c deleted file mode 100644 index 1591f6b..0000000 --- a/src/linux/kernel/locking/rwsem-spinlock.c +++ /dev/null @@ -1,316 +0,0 @@ -/* rwsem-spinlock.c: R/W semaphores: contention handling functions for - * generic spinlock implementation - * - * Copyright (c) 2001 David Howells (dhowells@redhat.com). - * - Derived partially from idea by Andrea Arcangeli - * - Derived also from comments by Linus - */ -#include -#include -#include - -enum rwsem_waiter_type { - RWSEM_WAITING_FOR_WRITE, - RWSEM_WAITING_FOR_READ -}; - -struct rwsem_waiter { - struct list_head list; - struct task_struct *task; - enum rwsem_waiter_type type; -}; - -int rwsem_is_locked(struct rw_semaphore *sem) -{ - int ret = 1; - unsigned long flags; - - if (raw_spin_trylock_irqsave(&sem->wait_lock, flags)) { - ret = (sem->count != 0); - raw_spin_unlock_irqrestore(&sem->wait_lock, flags); - } - return ret; -} -EXPORT_SYMBOL(rwsem_is_locked); - -/* - * initialise the semaphore - */ -void __init_rwsem(struct rw_semaphore *sem, const char *name, - struct lock_class_key *key) -{ -#ifdef CONFIG_DEBUG_LOCK_ALLOC - /* - * Make sure we are not reinitializing a held semaphore: - */ - debug_check_no_locks_freed((void *)sem, sizeof(*sem)); - lockdep_init_map(&sem->dep_map, name, key, 0); -#endif - sem->count = 0; - raw_spin_lock_init(&sem->wait_lock); - INIT_LIST_HEAD(&sem->wait_list); -} -EXPORT_SYMBOL(__init_rwsem); - -/* - * handle the lock release when processes blocked on it that can now run - * - if we come here, then: - * - the 'active count' _reached_ zero - * - the 'waiting count' is non-zero - * - the spinlock must be held by the caller - * - woken process blocks are discarded from the list after having task zeroed - * - writers are only woken if wakewrite is non-zero - */ -static inline struct rw_semaphore * -__rwsem_do_wake(struct rw_semaphore *sem, int wakewrite) -{ - struct rwsem_waiter *waiter; - struct task_struct *tsk; - int woken; - - waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); - - if (waiter->type == RWSEM_WAITING_FOR_WRITE) { - if (wakewrite) - /* Wake up a writer. Note that we do not grant it the - * lock - it will have to acquire it when it runs. */ - wake_up_process(waiter->task); - goto out; - } - - /* grant an infinite number of read locks to the front of the queue */ - woken = 0; - do { - struct list_head *next = waiter->list.next; - - list_del(&waiter->list); - tsk = waiter->task; - /* - * Make sure we do not wakeup the next reader before - * setting the nil condition to grant the next reader; - * otherwise we could miss the wakeup on the other - * side and end up sleeping again. See the pairing - * in rwsem_down_read_failed(). - */ - smp_mb(); - waiter->task = NULL; - wake_up_process(tsk); - put_task_struct(tsk); - woken++; - if (next == &sem->wait_list) - break; - waiter = list_entry(next, struct rwsem_waiter, list); - } while (waiter->type != RWSEM_WAITING_FOR_WRITE); - - sem->count += woken; - - out: - return sem; -} - -/* - * wake a single writer - */ -static inline struct rw_semaphore * -__rwsem_wake_one_writer(struct rw_semaphore *sem) -{ - struct rwsem_waiter *waiter; - - waiter = list_entry(sem->wait_list.next, struct rwsem_waiter, list); - wake_up_process(waiter->task); - - return sem; -} - -/* - * get a read lock on the semaphore - */ -void __sched __down_read(struct rw_semaphore *sem) -{ - struct rwsem_waiter waiter; - struct task_struct *tsk; - unsigned long flags; - - raw_spin_lock_irqsave(&sem->wait_lock, flags); - - if (sem->count >= 0 && list_empty(&sem->wait_list)) { - /* granted */ - sem->count++; - raw_spin_unlock_irqrestore(&sem->wait_lock, flags); - goto out; - } - - tsk = current; - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - - /* set up my own style of waitqueue */ - waiter.task = tsk; - waiter.type = RWSEM_WAITING_FOR_READ; - get_task_struct(tsk); - - list_add_tail(&waiter.list, &sem->wait_list); - - /* we don't need to touch the semaphore struct anymore */ - raw_spin_unlock_irqrestore(&sem->wait_lock, flags); - - /* wait to be given the lock */ - for (;;) { - if (!waiter.task) - break; - schedule(); - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - } - - __set_task_state(tsk, TASK_RUNNING); - out: - ; -} - -/* - * trylock for reading -- returns 1 if successful, 0 if contention - */ -int __down_read_trylock(struct rw_semaphore *sem) -{ - unsigned long flags; - int ret = 0; - - - raw_spin_lock_irqsave(&sem->wait_lock, flags); - - if (sem->count >= 0 && list_empty(&sem->wait_list)) { - /* granted */ - sem->count++; - ret = 1; - } - - raw_spin_unlock_irqrestore(&sem->wait_lock, flags); - - return ret; -} - -/* - * get a write lock on the semaphore - */ -int __sched __down_write_common(struct rw_semaphore *sem, int state) -{ - struct rwsem_waiter waiter; - struct task_struct *tsk; - unsigned long flags; - int ret = 0; - - raw_spin_lock_irqsave(&sem->wait_lock, flags); - - /* set up my own style of waitqueue */ - tsk = current; - waiter.task = tsk; - waiter.type = RWSEM_WAITING_FOR_WRITE; - list_add_tail(&waiter.list, &sem->wait_list); - - /* wait for someone to release the lock */ - for (;;) { - /* - * That is the key to support write lock stealing: allows the - * task already on CPU to get the lock soon rather than put - * itself into sleep and waiting for system woke it or someone - * else in the head of the wait list up. - */ - if (sem->count == 0) - break; - if (signal_pending_state(state, current)) { - ret = -EINTR; - goto out; - } - set_task_state(tsk, state); - raw_spin_unlock_irqrestore(&sem->wait_lock, flags); - schedule(); - raw_spin_lock_irqsave(&sem->wait_lock, flags); - } - /* got the lock */ - sem->count = -1; -out: - list_del(&waiter.list); - - raw_spin_unlock_irqrestore(&sem->wait_lock, flags); - - return ret; -} - -void __sched __down_write(struct rw_semaphore *sem) -{ - __down_write_common(sem, TASK_UNINTERRUPTIBLE); -} - -int __sched __down_write_killable(struct rw_semaphore *sem) -{ - return __down_write_common(sem, TASK_KILLABLE); -} - -/* - * trylock for writing -- returns 1 if successful, 0 if contention - */ -int __down_write_trylock(struct rw_semaphore *sem) -{ - unsigned long flags; - int ret = 0; - - raw_spin_lock_irqsave(&sem->wait_lock, flags); - - if (sem->count == 0) { - /* got the lock */ - sem->count = -1; - ret = 1; - } - - raw_spin_unlock_irqrestore(&sem->wait_lock, flags); - - return ret; -} - -/* - * release a read lock on the semaphore - */ -void __up_read(struct rw_semaphore *sem) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&sem->wait_lock, flags); - - if (--sem->count == 0 && !list_empty(&sem->wait_list)) - sem = __rwsem_wake_one_writer(sem); - - raw_spin_unlock_irqrestore(&sem->wait_lock, flags); -} - -/* - * release a write lock on the semaphore - */ -void __up_write(struct rw_semaphore *sem) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&sem->wait_lock, flags); - - sem->count = 0; - if (!list_empty(&sem->wait_list)) - sem = __rwsem_do_wake(sem, 1); - - raw_spin_unlock_irqrestore(&sem->wait_lock, flags); -} - -/* - * downgrade a write lock into a read lock - * - just wake up any readers at the front of the queue - */ -void __downgrade_write(struct rw_semaphore *sem) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&sem->wait_lock, flags); - - sem->count = 1; - if (!list_empty(&sem->wait_list)) - sem = __rwsem_do_wake(sem, 0); - - raw_spin_unlock_irqrestore(&sem->wait_lock, flags); -} - diff --git a/src/linux/kernel/locking/rwsem.c b/src/linux/kernel/locking/rwsem.c deleted file mode 100644 index 45ba475..0000000 --- a/src/linux/kernel/locking/rwsem.c +++ /dev/null @@ -1,205 +0,0 @@ -/* kernel/rwsem.c: R/W semaphores, public implementation - * - * Written by David Howells (dhowells@redhat.com). - * Derived from asm-i386/semaphore.h - */ - -#include -#include -#include -#include -#include -#include - -#include "rwsem.h" - -/* - * lock for reading - */ -void __sched down_read(struct rw_semaphore *sem) -{ - might_sleep(); - rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_); - - LOCK_CONTENDED(sem, __down_read_trylock, __down_read); - rwsem_set_reader_owned(sem); -} - -EXPORT_SYMBOL(down_read); - -/* - * trylock for reading -- returns 1 if successful, 0 if contention - */ -int down_read_trylock(struct rw_semaphore *sem) -{ - int ret = __down_read_trylock(sem); - - if (ret == 1) { - rwsem_acquire_read(&sem->dep_map, 0, 1, _RET_IP_); - rwsem_set_reader_owned(sem); - } - return ret; -} - -EXPORT_SYMBOL(down_read_trylock); - -/* - * lock for writing - */ -void __sched down_write(struct rw_semaphore *sem) -{ - might_sleep(); - rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_); - - LOCK_CONTENDED(sem, __down_write_trylock, __down_write); - rwsem_set_owner(sem); -} - -EXPORT_SYMBOL(down_write); - -/* - * lock for writing - */ -int __sched down_write_killable(struct rw_semaphore *sem) -{ - might_sleep(); - rwsem_acquire(&sem->dep_map, 0, 0, _RET_IP_); - - if (LOCK_CONTENDED_RETURN(sem, __down_write_trylock, __down_write_killable)) { - rwsem_release(&sem->dep_map, 1, _RET_IP_); - return -EINTR; - } - - rwsem_set_owner(sem); - return 0; -} - -EXPORT_SYMBOL(down_write_killable); - -/* - * trylock for writing -- returns 1 if successful, 0 if contention - */ -int down_write_trylock(struct rw_semaphore *sem) -{ - int ret = __down_write_trylock(sem); - - if (ret == 1) { - rwsem_acquire(&sem->dep_map, 0, 1, _RET_IP_); - rwsem_set_owner(sem); - } - - return ret; -} - -EXPORT_SYMBOL(down_write_trylock); - -/* - * release a read lock - */ -void up_read(struct rw_semaphore *sem) -{ - rwsem_release(&sem->dep_map, 1, _RET_IP_); - - __up_read(sem); -} - -EXPORT_SYMBOL(up_read); - -/* - * release a write lock - */ -void up_write(struct rw_semaphore *sem) -{ - rwsem_release(&sem->dep_map, 1, _RET_IP_); - - rwsem_clear_owner(sem); - __up_write(sem); -} - -EXPORT_SYMBOL(up_write); - -/* - * downgrade write lock to read lock - */ -void downgrade_write(struct rw_semaphore *sem) -{ - /* - * lockdep: a downgraded write will live on as a write - * dependency. - */ - rwsem_set_reader_owned(sem); - __downgrade_write(sem); -} - -EXPORT_SYMBOL(downgrade_write); - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - -void down_read_nested(struct rw_semaphore *sem, int subclass) -{ - might_sleep(); - rwsem_acquire_read(&sem->dep_map, subclass, 0, _RET_IP_); - - LOCK_CONTENDED(sem, __down_read_trylock, __down_read); - rwsem_set_reader_owned(sem); -} - -EXPORT_SYMBOL(down_read_nested); - -void _down_write_nest_lock(struct rw_semaphore *sem, struct lockdep_map *nest) -{ - might_sleep(); - rwsem_acquire_nest(&sem->dep_map, 0, 0, nest, _RET_IP_); - - LOCK_CONTENDED(sem, __down_write_trylock, __down_write); - rwsem_set_owner(sem); -} - -EXPORT_SYMBOL(_down_write_nest_lock); - -void down_read_non_owner(struct rw_semaphore *sem) -{ - might_sleep(); - - __down_read(sem); -} - -EXPORT_SYMBOL(down_read_non_owner); - -void down_write_nested(struct rw_semaphore *sem, int subclass) -{ - might_sleep(); - rwsem_acquire(&sem->dep_map, subclass, 0, _RET_IP_); - - LOCK_CONTENDED(sem, __down_write_trylock, __down_write); - rwsem_set_owner(sem); -} - -EXPORT_SYMBOL(down_write_nested); - -int __sched down_write_killable_nested(struct rw_semaphore *sem, int subclass) -{ - might_sleep(); - rwsem_acquire(&sem->dep_map, subclass, 0, _RET_IP_); - - if (LOCK_CONTENDED_RETURN(sem, __down_write_trylock, __down_write_killable)) { - rwsem_release(&sem->dep_map, 1, _RET_IP_); - return -EINTR; - } - - rwsem_set_owner(sem); - return 0; -} - -EXPORT_SYMBOL(down_write_killable_nested); - -void up_read_non_owner(struct rw_semaphore *sem) -{ - __up_read(sem); -} - -EXPORT_SYMBOL(up_read_non_owner); - -#endif - - diff --git a/src/linux/kernel/locking/rwsem.h b/src/linux/kernel/locking/rwsem.h deleted file mode 100644 index a699f40..0000000 --- a/src/linux/kernel/locking/rwsem.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * The owner field of the rw_semaphore structure will be set to - * RWSEM_READ_OWNED when a reader grabs the lock. A writer will clear - * the owner field when it unlocks. A reader, on the other hand, will - * not touch the owner field when it unlocks. - * - * In essence, the owner field now has the following 3 states: - * 1) 0 - * - lock is free or the owner hasn't set the field yet - * 2) RWSEM_READER_OWNED - * - lock is currently or previously owned by readers (lock is free - * or not set by owner yet) - * 3) Other non-zero value - * - a writer owns the lock - */ -#define RWSEM_READER_OWNED ((struct task_struct *)1UL) - -#ifdef CONFIG_RWSEM_SPIN_ON_OWNER -/* - * All writes to owner are protected by WRITE_ONCE() to make sure that - * store tearing can't happen as optimistic spinners may read and use - * the owner value concurrently without lock. Read from owner, however, - * may not need READ_ONCE() as long as the pointer value is only used - * for comparison and isn't being dereferenced. - */ -static inline void rwsem_set_owner(struct rw_semaphore *sem) -{ - WRITE_ONCE(sem->owner, current); -} - -static inline void rwsem_clear_owner(struct rw_semaphore *sem) -{ - WRITE_ONCE(sem->owner, NULL); -} - -static inline void rwsem_set_reader_owned(struct rw_semaphore *sem) -{ - /* - * We check the owner value first to make sure that we will only - * do a write to the rwsem cacheline when it is really necessary - * to minimize cacheline contention. - */ - if (sem->owner != RWSEM_READER_OWNED) - WRITE_ONCE(sem->owner, RWSEM_READER_OWNED); -} - -static inline bool rwsem_owner_is_writer(struct task_struct *owner) -{ - return owner && owner != RWSEM_READER_OWNED; -} - -static inline bool rwsem_owner_is_reader(struct task_struct *owner) -{ - return owner == RWSEM_READER_OWNED; -} -#else -static inline void rwsem_set_owner(struct rw_semaphore *sem) -{ -} - -static inline void rwsem_clear_owner(struct rw_semaphore *sem) -{ -} - -static inline void rwsem_set_reader_owned(struct rw_semaphore *sem) -{ -} -#endif diff --git a/src/linux/kernel/locking/semaphore.c b/src/linux/kernel/locking/semaphore.c deleted file mode 100644 index b8120ab..0000000 --- a/src/linux/kernel/locking/semaphore.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2008 Intel Corporation - * Author: Matthew Wilcox - * - * Distributed under the terms of the GNU GPL, version 2 - * - * This file implements counting semaphores. - * A counting semaphore may be acquired 'n' times before sleeping. - * See mutex.c for single-acquisition sleeping locks which enforce - * rules which allow code to be debugged more easily. - */ - -/* - * Some notes on the implementation: - * - * The spinlock controls access to the other members of the semaphore. - * down_trylock() and up() can be called from interrupt context, so we - * have to disable interrupts when taking the lock. It turns out various - * parts of the kernel expect to be able to use down() on a semaphore in - * interrupt context when they know it will succeed, so we have to use - * irqsave variants for down(), down_interruptible() and down_killable() - * too. - * - * The ->count variable represents how many more tasks can acquire this - * semaphore. If it's zero, there may be tasks waiting on the wait_list. - */ - -#include -#include -#include -#include -#include -#include -#include - -static noinline void __down(struct semaphore *sem); -static noinline int __down_interruptible(struct semaphore *sem); -static noinline int __down_killable(struct semaphore *sem); -static noinline int __down_timeout(struct semaphore *sem, long timeout); -static noinline void __up(struct semaphore *sem); - -/** - * down - acquire the semaphore - * @sem: the semaphore to be acquired - * - * Acquires the semaphore. If no more tasks are allowed to acquire the - * semaphore, calling this function will put the task to sleep until the - * semaphore is released. - * - * Use of this function is deprecated, please use down_interruptible() or - * down_killable() instead. - */ -void down(struct semaphore *sem) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&sem->lock, flags); - if (likely(sem->count > 0)) - sem->count--; - else - __down(sem); - raw_spin_unlock_irqrestore(&sem->lock, flags); -} -EXPORT_SYMBOL(down); - -/** - * down_interruptible - acquire the semaphore unless interrupted - * @sem: the semaphore to be acquired - * - * Attempts to acquire the semaphore. If no more tasks are allowed to - * acquire the semaphore, calling this function will put the task to sleep. - * If the sleep is interrupted by a signal, this function will return -EINTR. - * If the semaphore is successfully acquired, this function returns 0. - */ -int down_interruptible(struct semaphore *sem) -{ - unsigned long flags; - int result = 0; - - raw_spin_lock_irqsave(&sem->lock, flags); - if (likely(sem->count > 0)) - sem->count--; - else - result = __down_interruptible(sem); - raw_spin_unlock_irqrestore(&sem->lock, flags); - - return result; -} -EXPORT_SYMBOL(down_interruptible); - -/** - * down_killable - acquire the semaphore unless killed - * @sem: the semaphore to be acquired - * - * Attempts to acquire the semaphore. If no more tasks are allowed to - * acquire the semaphore, calling this function will put the task to sleep. - * If the sleep is interrupted by a fatal signal, this function will return - * -EINTR. If the semaphore is successfully acquired, this function returns - * 0. - */ -int down_killable(struct semaphore *sem) -{ - unsigned long flags; - int result = 0; - - raw_spin_lock_irqsave(&sem->lock, flags); - if (likely(sem->count > 0)) - sem->count--; - else - result = __down_killable(sem); - raw_spin_unlock_irqrestore(&sem->lock, flags); - - return result; -} -EXPORT_SYMBOL(down_killable); - -/** - * down_trylock - try to acquire the semaphore, without waiting - * @sem: the semaphore to be acquired - * - * Try to acquire the semaphore atomically. Returns 0 if the semaphore has - * been acquired successfully or 1 if it it cannot be acquired. - * - * NOTE: This return value is inverted from both spin_trylock and - * mutex_trylock! Be careful about this when converting code. - * - * Unlike mutex_trylock, this function can be used from interrupt context, - * and the semaphore can be released by any task or interrupt. - */ -int down_trylock(struct semaphore *sem) -{ - unsigned long flags; - int count; - - raw_spin_lock_irqsave(&sem->lock, flags); - count = sem->count - 1; - if (likely(count >= 0)) - sem->count = count; - raw_spin_unlock_irqrestore(&sem->lock, flags); - - return (count < 0); -} -EXPORT_SYMBOL(down_trylock); - -/** - * down_timeout - acquire the semaphore within a specified time - * @sem: the semaphore to be acquired - * @timeout: how long to wait before failing - * - * Attempts to acquire the semaphore. If no more tasks are allowed to - * acquire the semaphore, calling this function will put the task to sleep. - * If the semaphore is not released within the specified number of jiffies, - * this function returns -ETIME. It returns 0 if the semaphore was acquired. - */ -int down_timeout(struct semaphore *sem, long timeout) -{ - unsigned long flags; - int result = 0; - - raw_spin_lock_irqsave(&sem->lock, flags); - if (likely(sem->count > 0)) - sem->count--; - else - result = __down_timeout(sem, timeout); - raw_spin_unlock_irqrestore(&sem->lock, flags); - - return result; -} -EXPORT_SYMBOL(down_timeout); - -/** - * up - release the semaphore - * @sem: the semaphore to release - * - * Release the semaphore. Unlike mutexes, up() may be called from any - * context and even by tasks which have never called down(). - */ -void up(struct semaphore *sem) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&sem->lock, flags); - if (likely(list_empty(&sem->wait_list))) - sem->count++; - else - __up(sem); - raw_spin_unlock_irqrestore(&sem->lock, flags); -} -EXPORT_SYMBOL(up); - -/* Functions for the contended case */ - -struct semaphore_waiter { - struct list_head list; - struct task_struct *task; - bool up; -}; - -/* - * Because this function is inlined, the 'state' parameter will be - * constant, and thus optimised away by the compiler. Likewise the - * 'timeout' parameter for the cases without timeouts. - */ -static inline int __sched __down_common(struct semaphore *sem, long state, - long timeout) -{ - struct task_struct *task = current; - struct semaphore_waiter waiter; - - list_add_tail(&waiter.list, &sem->wait_list); - waiter.task = task; - waiter.up = false; - - for (;;) { - if (signal_pending_state(state, task)) - goto interrupted; - if (unlikely(timeout <= 0)) - goto timed_out; - __set_task_state(task, state); - raw_spin_unlock_irq(&sem->lock); - timeout = schedule_timeout(timeout); - raw_spin_lock_irq(&sem->lock); - if (waiter.up) - return 0; - } - - timed_out: - list_del(&waiter.list); - return -ETIME; - - interrupted: - list_del(&waiter.list); - return -EINTR; -} - -static noinline void __sched __down(struct semaphore *sem) -{ - __down_common(sem, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); -} - -static noinline int __sched __down_interruptible(struct semaphore *sem) -{ - return __down_common(sem, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); -} - -static noinline int __sched __down_killable(struct semaphore *sem) -{ - return __down_common(sem, TASK_KILLABLE, MAX_SCHEDULE_TIMEOUT); -} - -static noinline int __sched __down_timeout(struct semaphore *sem, long timeout) -{ - return __down_common(sem, TASK_UNINTERRUPTIBLE, timeout); -} - -static noinline void __sched __up(struct semaphore *sem) -{ - struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list, - struct semaphore_waiter, list); - list_del(&waiter->list); - waiter->up = true; - wake_up_process(waiter->task); -} diff --git a/src/linux/kernel/membarrier.c b/src/linux/kernel/membarrier.c deleted file mode 100644 index 536c727..0000000 --- a/src/linux/kernel/membarrier.c +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2010, 2015 Mathieu Desnoyers - * - * membarrier system call - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include - -/* - * Bitmask made from a "or" of all commands within enum membarrier_cmd, - * except MEMBARRIER_CMD_QUERY. - */ -#define MEMBARRIER_CMD_BITMASK (MEMBARRIER_CMD_SHARED) - -/** - * sys_membarrier - issue memory barriers on a set of threads - * @cmd: Takes command values defined in enum membarrier_cmd. - * @flags: Currently needs to be 0. For future extensions. - * - * If this system call is not implemented, -ENOSYS is returned. If the - * command specified does not exist, or if the command argument is invalid, - * this system call returns -EINVAL. For a given command, with flags argument - * set to 0, this system call is guaranteed to always return the same value - * until reboot. - * - * All memory accesses performed in program order from each targeted thread - * is guaranteed to be ordered with respect to sys_membarrier(). If we use - * the semantic "barrier()" to represent a compiler barrier forcing memory - * accesses to be performed in program order across the barrier, and - * smp_mb() to represent explicit memory barriers forcing full memory - * ordering across the barrier, we have the following ordering table for - * each pair of barrier(), sys_membarrier() and smp_mb(): - * - * The pair ordering is detailed as (O: ordered, X: not ordered): - * - * barrier() smp_mb() sys_membarrier() - * barrier() X X O - * smp_mb() X O O - * sys_membarrier() O O O - */ -SYSCALL_DEFINE2(membarrier, int, cmd, int, flags) -{ - if (unlikely(flags)) - return -EINVAL; - switch (cmd) { - case MEMBARRIER_CMD_QUERY: - return MEMBARRIER_CMD_BITMASK; - case MEMBARRIER_CMD_SHARED: - if (num_online_cpus() > 1) - synchronize_sched(); - return 0; - default: - return -EINVAL; - } -} diff --git a/src/linux/kernel/memremap.c b/src/linux/kernel/memremap.c deleted file mode 100644 index b501e39..0000000 --- a/src/linux/kernel/memremap.c +++ /dev/null @@ -1,426 +0,0 @@ -/* - * Copyright(c) 2015 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef ioremap_cache -/* temporary while we convert existing ioremap_cache users to memremap */ -__weak void __iomem *ioremap_cache(resource_size_t offset, unsigned long size) -{ - return ioremap(offset, size); -} -#endif - -#ifndef arch_memremap_wb -static void *arch_memremap_wb(resource_size_t offset, unsigned long size) -{ - return (__force void *)ioremap_cache(offset, size); -} -#endif - -static void *try_ram_remap(resource_size_t offset, size_t size) -{ - unsigned long pfn = PHYS_PFN(offset); - - /* In the simple case just return the existing linear address */ - if (pfn_valid(pfn) && !PageHighMem(pfn_to_page(pfn))) - return __va(offset); - return NULL; /* fallback to arch_memremap_wb */ -} - -/** - * memremap() - remap an iomem_resource as cacheable memory - * @offset: iomem resource start address - * @size: size of remap - * @flags: any of MEMREMAP_WB, MEMREMAP_WT and MEMREMAP_WC - * - * memremap() is "ioremap" for cases where it is known that the resource - * being mapped does not have i/o side effects and the __iomem - * annotation is not applicable. In the case of multiple flags, the different - * mapping types will be attempted in the order listed below until one of - * them succeeds. - * - * MEMREMAP_WB - matches the default mapping for System RAM on - * the architecture. This is usually a read-allocate write-back cache. - * Morever, if MEMREMAP_WB is specified and the requested remap region is RAM - * memremap() will bypass establishing a new mapping and instead return - * a pointer into the direct map. - * - * MEMREMAP_WT - establish a mapping whereby writes either bypass the - * cache or are written through to memory and never exist in a - * cache-dirty state with respect to program visibility. Attempts to - * map System RAM with this mapping type will fail. - * - * MEMREMAP_WC - establish a writecombine mapping, whereby writes may - * be coalesced together (e.g. in the CPU's write buffers), but is otherwise - * uncached. Attempts to map System RAM with this mapping type will fail. - */ -void *memremap(resource_size_t offset, size_t size, unsigned long flags) -{ - int is_ram = region_intersects(offset, size, - IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE); - void *addr = NULL; - - if (!flags) - return NULL; - - if (is_ram == REGION_MIXED) { - WARN_ONCE(1, "memremap attempted on mixed range %pa size: %#lx\n", - &offset, (unsigned long) size); - return NULL; - } - - /* Try all mapping types requested until one returns non-NULL */ - if (flags & MEMREMAP_WB) { - /* - * MEMREMAP_WB is special in that it can be satisifed - * from the direct map. Some archs depend on the - * capability of memremap() to autodetect cases where - * the requested range is potentially in System RAM. - */ - if (is_ram == REGION_INTERSECTS) - addr = try_ram_remap(offset, size); - if (!addr) - addr = arch_memremap_wb(offset, size); - } - - /* - * If we don't have a mapping yet and other request flags are - * present then we will be attempting to establish a new virtual - * address mapping. Enforce that this mapping is not aliasing - * System RAM. - */ - if (!addr && is_ram == REGION_INTERSECTS && flags != MEMREMAP_WB) { - WARN_ONCE(1, "memremap attempted on ram %pa size: %#lx\n", - &offset, (unsigned long) size); - return NULL; - } - - if (!addr && (flags & MEMREMAP_WT)) - addr = ioremap_wt(offset, size); - - if (!addr && (flags & MEMREMAP_WC)) - addr = ioremap_wc(offset, size); - - return addr; -} -EXPORT_SYMBOL(memremap); - -void memunmap(void *addr) -{ - if (is_vmalloc_addr(addr)) - iounmap((void __iomem *) addr); -} -EXPORT_SYMBOL(memunmap); - -static void devm_memremap_release(struct device *dev, void *res) -{ - memunmap(*(void **)res); -} - -static int devm_memremap_match(struct device *dev, void *res, void *match_data) -{ - return *(void **)res == match_data; -} - -void *devm_memremap(struct device *dev, resource_size_t offset, - size_t size, unsigned long flags) -{ - void **ptr, *addr; - - ptr = devres_alloc_node(devm_memremap_release, sizeof(*ptr), GFP_KERNEL, - dev_to_node(dev)); - if (!ptr) - return ERR_PTR(-ENOMEM); - - addr = memremap(offset, size, flags); - if (addr) { - *ptr = addr; - devres_add(dev, ptr); - } else { - devres_free(ptr); - return ERR_PTR(-ENXIO); - } - - return addr; -} -EXPORT_SYMBOL(devm_memremap); - -void devm_memunmap(struct device *dev, void *addr) -{ - WARN_ON(devres_release(dev, devm_memremap_release, - devm_memremap_match, addr)); -} -EXPORT_SYMBOL(devm_memunmap); - -#ifdef CONFIG_ZONE_DEVICE -static DEFINE_MUTEX(pgmap_lock); -static RADIX_TREE(pgmap_radix, GFP_KERNEL); -#define SECTION_MASK ~((1UL << PA_SECTION_SHIFT) - 1) -#define SECTION_SIZE (1UL << PA_SECTION_SHIFT) - -struct page_map { - struct resource res; - struct percpu_ref *ref; - struct dev_pagemap pgmap; - struct vmem_altmap altmap; -}; - -void get_zone_device_page(struct page *page) -{ - percpu_ref_get(page->pgmap->ref); -} -EXPORT_SYMBOL(get_zone_device_page); - -void put_zone_device_page(struct page *page) -{ - put_dev_pagemap(page->pgmap); -} -EXPORT_SYMBOL(put_zone_device_page); - -static void pgmap_radix_release(struct resource *res) -{ - resource_size_t key, align_start, align_size, align_end; - - align_start = res->start & ~(SECTION_SIZE - 1); - align_size = ALIGN(resource_size(res), SECTION_SIZE); - align_end = align_start + align_size - 1; - - mutex_lock(&pgmap_lock); - for (key = res->start; key <= res->end; key += SECTION_SIZE) - radix_tree_delete(&pgmap_radix, key >> PA_SECTION_SHIFT); - mutex_unlock(&pgmap_lock); -} - -static unsigned long pfn_first(struct page_map *page_map) -{ - struct dev_pagemap *pgmap = &page_map->pgmap; - const struct resource *res = &page_map->res; - struct vmem_altmap *altmap = pgmap->altmap; - unsigned long pfn; - - pfn = res->start >> PAGE_SHIFT; - if (altmap) - pfn += vmem_altmap_offset(altmap); - return pfn; -} - -static unsigned long pfn_end(struct page_map *page_map) -{ - const struct resource *res = &page_map->res; - - return (res->start + resource_size(res)) >> PAGE_SHIFT; -} - -#define for_each_device_pfn(pfn, map) \ - for (pfn = pfn_first(map); pfn < pfn_end(map); pfn++) - -static void devm_memremap_pages_release(struct device *dev, void *data) -{ - struct page_map *page_map = data; - struct resource *res = &page_map->res; - resource_size_t align_start, align_size; - struct dev_pagemap *pgmap = &page_map->pgmap; - - if (percpu_ref_tryget_live(pgmap->ref)) { - dev_WARN(dev, "%s: page mapping is still live!\n", __func__); - percpu_ref_put(pgmap->ref); - } - - /* pages are dead and unused, undo the arch mapping */ - align_start = res->start & ~(SECTION_SIZE - 1); - align_size = ALIGN(resource_size(res), SECTION_SIZE); - arch_remove_memory(align_start, align_size); - untrack_pfn(NULL, PHYS_PFN(align_start), align_size); - pgmap_radix_release(res); - dev_WARN_ONCE(dev, pgmap->altmap && pgmap->altmap->alloc, - "%s: failed to free all reserved pages\n", __func__); -} - -/* assumes rcu_read_lock() held at entry */ -struct dev_pagemap *find_dev_pagemap(resource_size_t phys) -{ - struct page_map *page_map; - - WARN_ON_ONCE(!rcu_read_lock_held()); - - page_map = radix_tree_lookup(&pgmap_radix, phys >> PA_SECTION_SHIFT); - return page_map ? &page_map->pgmap : NULL; -} - -/** - * devm_memremap_pages - remap and provide memmap backing for the given resource - * @dev: hosting device for @res - * @res: "host memory" address range - * @ref: a live per-cpu reference count - * @altmap: optional descriptor for allocating the memmap from @res - * - * Notes: - * 1/ @ref must be 'live' on entry and 'dead' before devm_memunmap_pages() time - * (or devm release event). - * - * 2/ @res is expected to be a host memory range that could feasibly be - * treated as a "System RAM" range, i.e. not a device mmio range, but - * this is not enforced. - */ -void *devm_memremap_pages(struct device *dev, struct resource *res, - struct percpu_ref *ref, struct vmem_altmap *altmap) -{ - resource_size_t key, align_start, align_size, align_end; - pgprot_t pgprot = PAGE_KERNEL; - struct dev_pagemap *pgmap; - struct page_map *page_map; - int error, nid, is_ram; - unsigned long pfn; - - align_start = res->start & ~(SECTION_SIZE - 1); - align_size = ALIGN(res->start + resource_size(res), SECTION_SIZE) - - align_start; - is_ram = region_intersects(align_start, align_size, - IORESOURCE_SYSTEM_RAM, IORES_DESC_NONE); - - if (is_ram == REGION_MIXED) { - WARN_ONCE(1, "%s attempted on mixed region %pr\n", - __func__, res); - return ERR_PTR(-ENXIO); - } - - if (is_ram == REGION_INTERSECTS) - return __va(res->start); - - if (!ref) - return ERR_PTR(-EINVAL); - - page_map = devres_alloc_node(devm_memremap_pages_release, - sizeof(*page_map), GFP_KERNEL, dev_to_node(dev)); - if (!page_map) - return ERR_PTR(-ENOMEM); - pgmap = &page_map->pgmap; - - memcpy(&page_map->res, res, sizeof(*res)); - - pgmap->dev = dev; - if (altmap) { - memcpy(&page_map->altmap, altmap, sizeof(*altmap)); - pgmap->altmap = &page_map->altmap; - } - pgmap->ref = ref; - pgmap->res = &page_map->res; - - mutex_lock(&pgmap_lock); - error = 0; - align_end = align_start + align_size - 1; - for (key = align_start; key <= align_end; key += SECTION_SIZE) { - struct dev_pagemap *dup; - - rcu_read_lock(); - dup = find_dev_pagemap(key); - rcu_read_unlock(); - if (dup) { - dev_err(dev, "%s: %pr collides with mapping for %s\n", - __func__, res, dev_name(dup->dev)); - error = -EBUSY; - break; - } - error = radix_tree_insert(&pgmap_radix, key >> PA_SECTION_SHIFT, - page_map); - if (error) { - dev_err(dev, "%s: failed: %d\n", __func__, error); - break; - } - } - mutex_unlock(&pgmap_lock); - if (error) - goto err_radix; - - nid = dev_to_node(dev); - if (nid < 0) - nid = numa_mem_id(); - - error = track_pfn_remap(NULL, &pgprot, PHYS_PFN(align_start), 0, - align_size); - if (error) - goto err_pfn_remap; - - error = arch_add_memory(nid, align_start, align_size, true); - if (error) - goto err_add_memory; - - for_each_device_pfn(pfn, page_map) { - struct page *page = pfn_to_page(pfn); - - /* - * ZONE_DEVICE pages union ->lru with a ->pgmap back - * pointer. It is a bug if a ZONE_DEVICE page is ever - * freed or placed on a driver-private list. Seed the - * storage with LIST_POISON* values. - */ - list_del(&page->lru); - page->pgmap = pgmap; - } - devres_add(dev, page_map); - return __va(res->start); - - err_add_memory: - untrack_pfn(NULL, PHYS_PFN(align_start), align_size); - err_pfn_remap: - err_radix: - pgmap_radix_release(res); - devres_free(page_map); - return ERR_PTR(error); -} -EXPORT_SYMBOL(devm_memremap_pages); - -unsigned long vmem_altmap_offset(struct vmem_altmap *altmap) -{ - /* number of pfns from base where pfn_to_page() is valid */ - return altmap->reserve + altmap->free; -} - -void vmem_altmap_free(struct vmem_altmap *altmap, unsigned long nr_pfns) -{ - altmap->alloc -= nr_pfns; -} - -struct vmem_altmap *to_vmem_altmap(unsigned long memmap_start) -{ - /* - * 'memmap_start' is the virtual address for the first "struct - * page" in this range of the vmemmap array. In the case of - * CONFIG_SPARSEMEM_VMEMMAP a page_to_pfn conversion is simple - * pointer arithmetic, so we can perform this to_vmem_altmap() - * conversion without concern for the initialization state of - * the struct page fields. - */ - struct page *page = (struct page *) memmap_start; - struct dev_pagemap *pgmap; - - /* - * Unconditionally retrieve a dev_pagemap associated with the - * given physical address, this is only for use in the - * arch_{add|remove}_memory() for setting up and tearing down - * the memmap. - */ - rcu_read_lock(); - pgmap = find_dev_pagemap(__pfn_to_phys(page_to_pfn(page))); - rcu_read_unlock(); - - return pgmap ? pgmap->altmap : NULL; -} -#endif /* CONFIG_ZONE_DEVICE */ diff --git a/src/linux/kernel/notifier.c b/src/linux/kernel/notifier.c deleted file mode 100644 index fd2c9ac..0000000 --- a/src/linux/kernel/notifier.c +++ /dev/null @@ -1,564 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -/* - * Notifier list for kernel code which wants to be called - * at shutdown. This is used to stop any idling DMA operations - * and the like. - */ -BLOCKING_NOTIFIER_HEAD(reboot_notifier_list); - -/* - * Notifier chain core routines. The exported routines below - * are layered on top of these, with appropriate locking added. - */ - -static int notifier_chain_register(struct notifier_block **nl, - struct notifier_block *n) -{ - while ((*nl) != NULL) { - if (n->priority > (*nl)->priority) - break; - nl = &((*nl)->next); - } - n->next = *nl; - rcu_assign_pointer(*nl, n); - return 0; -} - -static int notifier_chain_cond_register(struct notifier_block **nl, - struct notifier_block *n) -{ - while ((*nl) != NULL) { - if ((*nl) == n) - return 0; - if (n->priority > (*nl)->priority) - break; - nl = &((*nl)->next); - } - n->next = *nl; - rcu_assign_pointer(*nl, n); - return 0; -} - -static int notifier_chain_unregister(struct notifier_block **nl, - struct notifier_block *n) -{ - while ((*nl) != NULL) { - if ((*nl) == n) { - rcu_assign_pointer(*nl, n->next); - return 0; - } - nl = &((*nl)->next); - } - return -ENOENT; -} - -/** - * notifier_call_chain - Informs the registered notifiers about an event. - * @nl: Pointer to head of the blocking notifier chain - * @val: Value passed unmodified to notifier function - * @v: Pointer passed unmodified to notifier function - * @nr_to_call: Number of notifier functions to be called. Don't care - * value of this parameter is -1. - * @nr_calls: Records the number of notifications sent. Don't care - * value of this field is NULL. - * @returns: notifier_call_chain returns the value returned by the - * last notifier function called. - */ -static int notifier_call_chain(struct notifier_block **nl, - unsigned long val, void *v, - int nr_to_call, int *nr_calls) -{ - int ret = NOTIFY_DONE; - struct notifier_block *nb, *next_nb; - - nb = rcu_dereference_raw(*nl); - - while (nb && nr_to_call) { - next_nb = rcu_dereference_raw(nb->next); - -#ifdef CONFIG_DEBUG_NOTIFIERS - if (unlikely(!func_ptr_is_kernel_text(nb->notifier_call))) { - WARN(1, "Invalid notifier called!"); - nb = next_nb; - continue; - } -#endif - ret = nb->notifier_call(nb, val, v); - - if (nr_calls) - (*nr_calls)++; - - if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK) - break; - nb = next_nb; - nr_to_call--; - } - return ret; -} -NOKPROBE_SYMBOL(notifier_call_chain); - -/* - * Atomic notifier chain routines. Registration and unregistration - * use a spinlock, and call_chain is synchronized by RCU (no locks). - */ - -/** - * atomic_notifier_chain_register - Add notifier to an atomic notifier chain - * @nh: Pointer to head of the atomic notifier chain - * @n: New entry in notifier chain - * - * Adds a notifier to an atomic notifier chain. - * - * Currently always returns zero. - */ -int atomic_notifier_chain_register(struct atomic_notifier_head *nh, - struct notifier_block *n) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&nh->lock, flags); - ret = notifier_chain_register(&nh->head, n); - spin_unlock_irqrestore(&nh->lock, flags); - return ret; -} -EXPORT_SYMBOL_GPL(atomic_notifier_chain_register); - -/** - * atomic_notifier_chain_unregister - Remove notifier from an atomic notifier chain - * @nh: Pointer to head of the atomic notifier chain - * @n: Entry to remove from notifier chain - * - * Removes a notifier from an atomic notifier chain. - * - * Returns zero on success or %-ENOENT on failure. - */ -int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh, - struct notifier_block *n) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&nh->lock, flags); - ret = notifier_chain_unregister(&nh->head, n); - spin_unlock_irqrestore(&nh->lock, flags); - synchronize_rcu(); - return ret; -} -EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister); - -/** - * __atomic_notifier_call_chain - Call functions in an atomic notifier chain - * @nh: Pointer to head of the atomic notifier chain - * @val: Value passed unmodified to notifier function - * @v: Pointer passed unmodified to notifier function - * @nr_to_call: See the comment for notifier_call_chain. - * @nr_calls: See the comment for notifier_call_chain. - * - * Calls each function in a notifier chain in turn. The functions - * run in an atomic context, so they must not block. - * This routine uses RCU to synchronize with changes to the chain. - * - * If the return value of the notifier can be and'ed - * with %NOTIFY_STOP_MASK then atomic_notifier_call_chain() - * will return immediately, with the return value of - * the notifier function which halted execution. - * Otherwise the return value is the return value - * of the last notifier function called. - */ -int __atomic_notifier_call_chain(struct atomic_notifier_head *nh, - unsigned long val, void *v, - int nr_to_call, int *nr_calls) -{ - int ret; - - rcu_read_lock(); - ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls); - rcu_read_unlock(); - return ret; -} -EXPORT_SYMBOL_GPL(__atomic_notifier_call_chain); -NOKPROBE_SYMBOL(__atomic_notifier_call_chain); - -int atomic_notifier_call_chain(struct atomic_notifier_head *nh, - unsigned long val, void *v) -{ - return __atomic_notifier_call_chain(nh, val, v, -1, NULL); -} -EXPORT_SYMBOL_GPL(atomic_notifier_call_chain); -NOKPROBE_SYMBOL(atomic_notifier_call_chain); - -/* - * Blocking notifier chain routines. All access to the chain is - * synchronized by an rwsem. - */ - -/** - * blocking_notifier_chain_register - Add notifier to a blocking notifier chain - * @nh: Pointer to head of the blocking notifier chain - * @n: New entry in notifier chain - * - * Adds a notifier to a blocking notifier chain. - * Must be called in process context. - * - * Currently always returns zero. - */ -int blocking_notifier_chain_register(struct blocking_notifier_head *nh, - struct notifier_block *n) -{ - int ret; - - /* - * This code gets used during boot-up, when task switching is - * not yet working and interrupts must remain disabled. At - * such times we must not call down_write(). - */ - if (unlikely(system_state == SYSTEM_BOOTING)) - return notifier_chain_register(&nh->head, n); - - down_write(&nh->rwsem); - ret = notifier_chain_register(&nh->head, n); - up_write(&nh->rwsem); - return ret; -} -EXPORT_SYMBOL_GPL(blocking_notifier_chain_register); - -/** - * blocking_notifier_chain_cond_register - Cond add notifier to a blocking notifier chain - * @nh: Pointer to head of the blocking notifier chain - * @n: New entry in notifier chain - * - * Adds a notifier to a blocking notifier chain, only if not already - * present in the chain. - * Must be called in process context. - * - * Currently always returns zero. - */ -int blocking_notifier_chain_cond_register(struct blocking_notifier_head *nh, - struct notifier_block *n) -{ - int ret; - - down_write(&nh->rwsem); - ret = notifier_chain_cond_register(&nh->head, n); - up_write(&nh->rwsem); - return ret; -} -EXPORT_SYMBOL_GPL(blocking_notifier_chain_cond_register); - -/** - * blocking_notifier_chain_unregister - Remove notifier from a blocking notifier chain - * @nh: Pointer to head of the blocking notifier chain - * @n: Entry to remove from notifier chain - * - * Removes a notifier from a blocking notifier chain. - * Must be called from process context. - * - * Returns zero on success or %-ENOENT on failure. - */ -int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh, - struct notifier_block *n) -{ - int ret; - - /* - * This code gets used during boot-up, when task switching is - * not yet working and interrupts must remain disabled. At - * such times we must not call down_write(). - */ - if (unlikely(system_state == SYSTEM_BOOTING)) - return notifier_chain_unregister(&nh->head, n); - - down_write(&nh->rwsem); - ret = notifier_chain_unregister(&nh->head, n); - up_write(&nh->rwsem); - return ret; -} -EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister); - -/** - * __blocking_notifier_call_chain - Call functions in a blocking notifier chain - * @nh: Pointer to head of the blocking notifier chain - * @val: Value passed unmodified to notifier function - * @v: Pointer passed unmodified to notifier function - * @nr_to_call: See comment for notifier_call_chain. - * @nr_calls: See comment for notifier_call_chain. - * - * Calls each function in a notifier chain in turn. The functions - * run in a process context, so they are allowed to block. - * - * If the return value of the notifier can be and'ed - * with %NOTIFY_STOP_MASK then blocking_notifier_call_chain() - * will return immediately, with the return value of - * the notifier function which halted execution. - * Otherwise the return value is the return value - * of the last notifier function called. - */ -int __blocking_notifier_call_chain(struct blocking_notifier_head *nh, - unsigned long val, void *v, - int nr_to_call, int *nr_calls) -{ - int ret = NOTIFY_DONE; - - /* - * We check the head outside the lock, but if this access is - * racy then it does not matter what the result of the test - * is, we re-check the list after having taken the lock anyway: - */ - if (rcu_access_pointer(nh->head)) { - down_read(&nh->rwsem); - ret = notifier_call_chain(&nh->head, val, v, nr_to_call, - nr_calls); - up_read(&nh->rwsem); - } - return ret; -} -EXPORT_SYMBOL_GPL(__blocking_notifier_call_chain); - -int blocking_notifier_call_chain(struct blocking_notifier_head *nh, - unsigned long val, void *v) -{ - return __blocking_notifier_call_chain(nh, val, v, -1, NULL); -} -EXPORT_SYMBOL_GPL(blocking_notifier_call_chain); - -/* - * Raw notifier chain routines. There is no protection; - * the caller must provide it. Use at your own risk! - */ - -/** - * raw_notifier_chain_register - Add notifier to a raw notifier chain - * @nh: Pointer to head of the raw notifier chain - * @n: New entry in notifier chain - * - * Adds a notifier to a raw notifier chain. - * All locking must be provided by the caller. - * - * Currently always returns zero. - */ -int raw_notifier_chain_register(struct raw_notifier_head *nh, - struct notifier_block *n) -{ - return notifier_chain_register(&nh->head, n); -} -EXPORT_SYMBOL_GPL(raw_notifier_chain_register); - -/** - * raw_notifier_chain_unregister - Remove notifier from a raw notifier chain - * @nh: Pointer to head of the raw notifier chain - * @n: Entry to remove from notifier chain - * - * Removes a notifier from a raw notifier chain. - * All locking must be provided by the caller. - * - * Returns zero on success or %-ENOENT on failure. - */ -int raw_notifier_chain_unregister(struct raw_notifier_head *nh, - struct notifier_block *n) -{ - return notifier_chain_unregister(&nh->head, n); -} -EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister); - -/** - * __raw_notifier_call_chain - Call functions in a raw notifier chain - * @nh: Pointer to head of the raw notifier chain - * @val: Value passed unmodified to notifier function - * @v: Pointer passed unmodified to notifier function - * @nr_to_call: See comment for notifier_call_chain. - * @nr_calls: See comment for notifier_call_chain - * - * Calls each function in a notifier chain in turn. The functions - * run in an undefined context. - * All locking must be provided by the caller. - * - * If the return value of the notifier can be and'ed - * with %NOTIFY_STOP_MASK then raw_notifier_call_chain() - * will return immediately, with the return value of - * the notifier function which halted execution. - * Otherwise the return value is the return value - * of the last notifier function called. - */ -int __raw_notifier_call_chain(struct raw_notifier_head *nh, - unsigned long val, void *v, - int nr_to_call, int *nr_calls) -{ - return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls); -} -EXPORT_SYMBOL_GPL(__raw_notifier_call_chain); - -int raw_notifier_call_chain(struct raw_notifier_head *nh, - unsigned long val, void *v) -{ - return __raw_notifier_call_chain(nh, val, v, -1, NULL); -} -EXPORT_SYMBOL_GPL(raw_notifier_call_chain); - -#ifdef CONFIG_SRCU -/* - * SRCU notifier chain routines. Registration and unregistration - * use a mutex, and call_chain is synchronized by SRCU (no locks). - */ - -/** - * srcu_notifier_chain_register - Add notifier to an SRCU notifier chain - * @nh: Pointer to head of the SRCU notifier chain - * @n: New entry in notifier chain - * - * Adds a notifier to an SRCU notifier chain. - * Must be called in process context. - * - * Currently always returns zero. - */ -int srcu_notifier_chain_register(struct srcu_notifier_head *nh, - struct notifier_block *n) -{ - int ret; - - /* - * This code gets used during boot-up, when task switching is - * not yet working and interrupts must remain disabled. At - * such times we must not call mutex_lock(). - */ - if (unlikely(system_state == SYSTEM_BOOTING)) - return notifier_chain_register(&nh->head, n); - - mutex_lock(&nh->mutex); - ret = notifier_chain_register(&nh->head, n); - mutex_unlock(&nh->mutex); - return ret; -} -EXPORT_SYMBOL_GPL(srcu_notifier_chain_register); - -/** - * srcu_notifier_chain_unregister - Remove notifier from an SRCU notifier chain - * @nh: Pointer to head of the SRCU notifier chain - * @n: Entry to remove from notifier chain - * - * Removes a notifier from an SRCU notifier chain. - * Must be called from process context. - * - * Returns zero on success or %-ENOENT on failure. - */ -int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh, - struct notifier_block *n) -{ - int ret; - - /* - * This code gets used during boot-up, when task switching is - * not yet working and interrupts must remain disabled. At - * such times we must not call mutex_lock(). - */ - if (unlikely(system_state == SYSTEM_BOOTING)) - return notifier_chain_unregister(&nh->head, n); - - mutex_lock(&nh->mutex); - ret = notifier_chain_unregister(&nh->head, n); - mutex_unlock(&nh->mutex); - synchronize_srcu(&nh->srcu); - return ret; -} -EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister); - -/** - * __srcu_notifier_call_chain - Call functions in an SRCU notifier chain - * @nh: Pointer to head of the SRCU notifier chain - * @val: Value passed unmodified to notifier function - * @v: Pointer passed unmodified to notifier function - * @nr_to_call: See comment for notifier_call_chain. - * @nr_calls: See comment for notifier_call_chain - * - * Calls each function in a notifier chain in turn. The functions - * run in a process context, so they are allowed to block. - * - * If the return value of the notifier can be and'ed - * with %NOTIFY_STOP_MASK then srcu_notifier_call_chain() - * will return immediately, with the return value of - * the notifier function which halted execution. - * Otherwise the return value is the return value - * of the last notifier function called. - */ -int __srcu_notifier_call_chain(struct srcu_notifier_head *nh, - unsigned long val, void *v, - int nr_to_call, int *nr_calls) -{ - int ret; - int idx; - - idx = srcu_read_lock(&nh->srcu); - ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls); - srcu_read_unlock(&nh->srcu, idx); - return ret; -} -EXPORT_SYMBOL_GPL(__srcu_notifier_call_chain); - -int srcu_notifier_call_chain(struct srcu_notifier_head *nh, - unsigned long val, void *v) -{ - return __srcu_notifier_call_chain(nh, val, v, -1, NULL); -} -EXPORT_SYMBOL_GPL(srcu_notifier_call_chain); - -/** - * srcu_init_notifier_head - Initialize an SRCU notifier head - * @nh: Pointer to head of the srcu notifier chain - * - * Unlike other sorts of notifier heads, SRCU notifier heads require - * dynamic initialization. Be sure to call this routine before - * calling any of the other SRCU notifier routines for this head. - * - * If an SRCU notifier head is deallocated, it must first be cleaned - * up by calling srcu_cleanup_notifier_head(). Otherwise the head's - * per-cpu data (used by the SRCU mechanism) will leak. - */ -void srcu_init_notifier_head(struct srcu_notifier_head *nh) -{ - mutex_init(&nh->mutex); - if (init_srcu_struct(&nh->srcu) < 0) - BUG(); - nh->head = NULL; -} -EXPORT_SYMBOL_GPL(srcu_init_notifier_head); - -#endif /* CONFIG_SRCU */ - -static ATOMIC_NOTIFIER_HEAD(die_chain); - -int notrace notify_die(enum die_val val, const char *str, - struct pt_regs *regs, long err, int trap, int sig) -{ - struct die_args args = { - .regs = regs, - .str = str, - .err = err, - .trapnr = trap, - .signr = sig, - - }; - RCU_LOCKDEP_WARN(!rcu_is_watching(), - "notify_die called but RCU thinks we're quiescent"); - return atomic_notifier_call_chain(&die_chain, val, &args); -} -NOKPROBE_SYMBOL(notify_die); - -int register_die_notifier(struct notifier_block *nb) -{ - vmalloc_sync_all(); - return atomic_notifier_chain_register(&die_chain, nb); -} -EXPORT_SYMBOL_GPL(register_die_notifier); - -int unregister_die_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&die_chain, nb); -} -EXPORT_SYMBOL_GPL(unregister_die_notifier); diff --git a/src/linux/kernel/nsproxy.c b/src/linux/kernel/nsproxy.c deleted file mode 100644 index 782102e..0000000 --- a/src/linux/kernel/nsproxy.c +++ /dev/null @@ -1,274 +0,0 @@ -/* - * Copyright (C) 2006 IBM Corporation - * - * Author: Serge Hallyn - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - * - * Jun 2006 - namespaces support - * OpenVZ, SWsoft Inc. - * Pavel Emelianov - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct kmem_cache *nsproxy_cachep; - -struct nsproxy init_nsproxy = { - .count = ATOMIC_INIT(1), - .uts_ns = &init_uts_ns, -#if defined(CONFIG_POSIX_MQUEUE) || defined(CONFIG_SYSVIPC) - .ipc_ns = &init_ipc_ns, -#endif - .mnt_ns = NULL, - .pid_ns_for_children = &init_pid_ns, -#ifdef CONFIG_NET - .net_ns = &init_net, -#endif -#ifdef CONFIG_CGROUPS - .cgroup_ns = &init_cgroup_ns, -#endif -}; - -static inline struct nsproxy *create_nsproxy(void) -{ - struct nsproxy *nsproxy; - - nsproxy = kmem_cache_alloc(nsproxy_cachep, GFP_KERNEL); - if (nsproxy) - atomic_set(&nsproxy->count, 1); - return nsproxy; -} - -/* - * Create new nsproxy and all of its the associated namespaces. - * Return the newly created nsproxy. Do not attach this to the task, - * leave it to the caller to do proper locking and attach it to task. - */ -static struct nsproxy *create_new_namespaces(unsigned long flags, - struct task_struct *tsk, struct user_namespace *user_ns, - struct fs_struct *new_fs) -{ - struct nsproxy *new_nsp; - int err; - - new_nsp = create_nsproxy(); - if (!new_nsp) - return ERR_PTR(-ENOMEM); - - new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, user_ns, new_fs); - if (IS_ERR(new_nsp->mnt_ns)) { - err = PTR_ERR(new_nsp->mnt_ns); - goto out_ns; - } - - new_nsp->uts_ns = copy_utsname(flags, user_ns, tsk->nsproxy->uts_ns); - if (IS_ERR(new_nsp->uts_ns)) { - err = PTR_ERR(new_nsp->uts_ns); - goto out_uts; - } - - new_nsp->ipc_ns = copy_ipcs(flags, user_ns, tsk->nsproxy->ipc_ns); - if (IS_ERR(new_nsp->ipc_ns)) { - err = PTR_ERR(new_nsp->ipc_ns); - goto out_ipc; - } - - new_nsp->pid_ns_for_children = - copy_pid_ns(flags, user_ns, tsk->nsproxy->pid_ns_for_children); - if (IS_ERR(new_nsp->pid_ns_for_children)) { - err = PTR_ERR(new_nsp->pid_ns_for_children); - goto out_pid; - } - - new_nsp->cgroup_ns = copy_cgroup_ns(flags, user_ns, - tsk->nsproxy->cgroup_ns); - if (IS_ERR(new_nsp->cgroup_ns)) { - err = PTR_ERR(new_nsp->cgroup_ns); - goto out_cgroup; - } - - new_nsp->net_ns = copy_net_ns(flags, user_ns, tsk->nsproxy->net_ns); - if (IS_ERR(new_nsp->net_ns)) { - err = PTR_ERR(new_nsp->net_ns); - goto out_net; - } - - return new_nsp; - -out_net: - put_cgroup_ns(new_nsp->cgroup_ns); -out_cgroup: - if (new_nsp->pid_ns_for_children) - put_pid_ns(new_nsp->pid_ns_for_children); -out_pid: - if (new_nsp->ipc_ns) - put_ipc_ns(new_nsp->ipc_ns); -out_ipc: - if (new_nsp->uts_ns) - put_uts_ns(new_nsp->uts_ns); -out_uts: - if (new_nsp->mnt_ns) - put_mnt_ns(new_nsp->mnt_ns); -out_ns: - kmem_cache_free(nsproxy_cachep, new_nsp); - return ERR_PTR(err); -} - -/* - * called from clone. This now handles copy for nsproxy and all - * namespaces therein. - */ -int copy_namespaces(unsigned long flags, struct task_struct *tsk) -{ - struct nsproxy *old_ns = tsk->nsproxy; - struct user_namespace *user_ns = task_cred_xxx(tsk, user_ns); - struct nsproxy *new_ns; - - if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | - CLONE_NEWPID | CLONE_NEWNET | - CLONE_NEWCGROUP)))) { - get_nsproxy(old_ns); - return 0; - } - - if (!ns_capable(user_ns, CAP_SYS_ADMIN)) - return -EPERM; - - /* - * CLONE_NEWIPC must detach from the undolist: after switching - * to a new ipc namespace, the semaphore arrays from the old - * namespace are unreachable. In clone parlance, CLONE_SYSVSEM - * means share undolist with parent, so we must forbid using - * it along with CLONE_NEWIPC. - */ - if ((flags & (CLONE_NEWIPC | CLONE_SYSVSEM)) == - (CLONE_NEWIPC | CLONE_SYSVSEM)) - return -EINVAL; - - new_ns = create_new_namespaces(flags, tsk, user_ns, tsk->fs); - if (IS_ERR(new_ns)) - return PTR_ERR(new_ns); - - tsk->nsproxy = new_ns; - return 0; -} - -void free_nsproxy(struct nsproxy *ns) -{ - if (ns->mnt_ns) - put_mnt_ns(ns->mnt_ns); - if (ns->uts_ns) - put_uts_ns(ns->uts_ns); - if (ns->ipc_ns) - put_ipc_ns(ns->ipc_ns); - if (ns->pid_ns_for_children) - put_pid_ns(ns->pid_ns_for_children); - put_cgroup_ns(ns->cgroup_ns); - put_net(ns->net_ns); - kmem_cache_free(nsproxy_cachep, ns); -} - -/* - * Called from unshare. Unshare all the namespaces part of nsproxy. - * On success, returns the new nsproxy. - */ -int unshare_nsproxy_namespaces(unsigned long unshare_flags, - struct nsproxy **new_nsp, struct cred *new_cred, struct fs_struct *new_fs) -{ - struct user_namespace *user_ns; - int err = 0; - - if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | - CLONE_NEWNET | CLONE_NEWPID | CLONE_NEWCGROUP))) - return 0; - - user_ns = new_cred ? new_cred->user_ns : current_user_ns(); - if (!ns_capable(user_ns, CAP_SYS_ADMIN)) - return -EPERM; - - *new_nsp = create_new_namespaces(unshare_flags, current, user_ns, - new_fs ? new_fs : current->fs); - if (IS_ERR(*new_nsp)) { - err = PTR_ERR(*new_nsp); - goto out; - } - -out: - return err; -} - -void switch_task_namespaces(struct task_struct *p, struct nsproxy *new) -{ - struct nsproxy *ns; - - might_sleep(); - - task_lock(p); - ns = p->nsproxy; - p->nsproxy = new; - task_unlock(p); - - if (ns && atomic_dec_and_test(&ns->count)) - free_nsproxy(ns); -} - -void exit_task_namespaces(struct task_struct *p) -{ - switch_task_namespaces(p, NULL); -} - -SYSCALL_DEFINE2(setns, int, fd, int, nstype) -{ - struct task_struct *tsk = current; - struct nsproxy *new_nsproxy; - struct file *file; - struct ns_common *ns; - int err; - - file = proc_ns_fget(fd); - if (IS_ERR(file)) - return PTR_ERR(file); - - err = -EINVAL; - ns = get_proc_ns(file_inode(file)); - if (nstype && (ns->ops->type != nstype)) - goto out; - - new_nsproxy = create_new_namespaces(0, tsk, current_user_ns(), tsk->fs); - if (IS_ERR(new_nsproxy)) { - err = PTR_ERR(new_nsproxy); - goto out; - } - - err = ns->ops->install(new_nsproxy, ns); - if (err) { - free_nsproxy(new_nsproxy); - goto out; - } - switch_task_namespaces(tsk, new_nsproxy); -out: - fput(file); - return err; -} - -int __init nsproxy_cache_init(void) -{ - nsproxy_cachep = KMEM_CACHE(nsproxy, SLAB_PANIC); - return 0; -} diff --git a/src/linux/kernel/panic.c b/src/linux/kernel/panic.c deleted file mode 100644 index e6480e2..0000000 --- a/src/linux/kernel/panic.c +++ /dev/null @@ -1,618 +0,0 @@ -/* - * linux/kernel/panic.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -/* - * This function is used through-out the kernel (including mm and fs) - * to indicate a major problem. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define PANIC_TIMER_STEP 100 -#define PANIC_BLINK_SPD 18 - -int panic_on_oops = CONFIG_PANIC_ON_OOPS_VALUE; -static unsigned long tainted_mask; -static int pause_on_oops; -static int pause_on_oops_flag; -static DEFINE_SPINLOCK(pause_on_oops_lock); -bool crash_kexec_post_notifiers; -int panic_on_warn __read_mostly; - -int panic_timeout = CONFIG_PANIC_TIMEOUT; -EXPORT_SYMBOL_GPL(panic_timeout); - -ATOMIC_NOTIFIER_HEAD(panic_notifier_list); - -EXPORT_SYMBOL(panic_notifier_list); - -static long no_blink(int state) -{ - return 0; -} - -/* Returns how long it waited in ms */ -long (*panic_blink)(int state); -EXPORT_SYMBOL(panic_blink); - -/* - * Stop ourself in panic -- architecture code may override this - */ -void __weak panic_smp_self_stop(void) -{ - while (1) - cpu_relax(); -} - -/* - * Stop ourselves in NMI context if another CPU has already panicked. Arch code - * may override this to prepare for crash dumping, e.g. save regs info. - */ -void __weak nmi_panic_self_stop(struct pt_regs *regs) -{ - panic_smp_self_stop(); -} - -/* - * Stop other CPUs in panic. Architecture dependent code may override this - * with more suitable version. For example, if the architecture supports - * crash dump, it should save registers of each stopped CPU and disable - * per-CPU features such as virtualization extensions. - */ -void __weak crash_smp_send_stop(void) -{ - static int cpus_stopped; - - /* - * This function can be called twice in panic path, but obviously - * we execute this only once. - */ - if (cpus_stopped) - return; - - /* - * Note smp_send_stop is the usual smp shutdown function, which - * unfortunately means it may not be hardened to work in a panic - * situation. - */ - smp_send_stop(); - cpus_stopped = 1; -} - -atomic_t panic_cpu = ATOMIC_INIT(PANIC_CPU_INVALID); - -/* - * A variant of panic() called from NMI context. We return if we've already - * panicked on this CPU. If another CPU already panicked, loop in - * nmi_panic_self_stop() which can provide architecture dependent code such - * as saving register state for crash dump. - */ -void nmi_panic(struct pt_regs *regs, const char *msg) -{ - int old_cpu, cpu; - - cpu = raw_smp_processor_id(); - old_cpu = atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, cpu); - - if (old_cpu == PANIC_CPU_INVALID) - panic("%s", msg); - else if (old_cpu != cpu) - nmi_panic_self_stop(regs); -} -EXPORT_SYMBOL(nmi_panic); - -/** - * panic - halt the system - * @fmt: The text string to print - * - * Display a message, then perform cleanups. - * - * This function never returns. - */ -void panic(const char *fmt, ...) -{ - static char buf[1024]; - va_list args; - long i, i_next = 0; - int state = 0; - int old_cpu, this_cpu; - bool _crash_kexec_post_notifiers = crash_kexec_post_notifiers; - - /* - * Disable local interrupts. This will prevent panic_smp_self_stop - * from deadlocking the first cpu that invokes the panic, since - * there is nothing to prevent an interrupt handler (that runs - * after setting panic_cpu) from invoking panic() again. - */ - local_irq_disable(); - - /* - * It's possible to come here directly from a panic-assertion and - * not have preempt disabled. Some functions called from here want - * preempt to be disabled. No point enabling it later though... - * - * Only one CPU is allowed to execute the panic code from here. For - * multiple parallel invocations of panic, all other CPUs either - * stop themself or will wait until they are stopped by the 1st CPU - * with smp_send_stop(). - * - * `old_cpu == PANIC_CPU_INVALID' means this is the 1st CPU which - * comes here, so go ahead. - * `old_cpu == this_cpu' means we came from nmi_panic() which sets - * panic_cpu to this CPU. In this case, this is also the 1st CPU. - */ - this_cpu = raw_smp_processor_id(); - old_cpu = atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, this_cpu); - - if (old_cpu != PANIC_CPU_INVALID && old_cpu != this_cpu) - panic_smp_self_stop(); - - console_verbose(); - bust_spinlocks(1); - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - pr_emerg("Kernel panic - not syncing: %s\n", buf); -#ifdef CONFIG_DEBUG_BUGVERBOSE - /* - * Avoid nested stack-dumping if a panic occurs during oops processing - */ - if (!test_taint(TAINT_DIE) && oops_in_progress <= 1) - dump_stack(); -#endif - - /* - * If we have crashed and we have a crash kernel loaded let it handle - * everything else. - * If we want to run this after calling panic_notifiers, pass - * the "crash_kexec_post_notifiers" option to the kernel. - * - * Bypass the panic_cpu check and call __crash_kexec directly. - */ - if (!_crash_kexec_post_notifiers) { - printk_nmi_flush_on_panic(); - __crash_kexec(NULL); - - /* - * Note smp_send_stop is the usual smp shutdown function, which - * unfortunately means it may not be hardened to work in a - * panic situation. - */ - smp_send_stop(); - } else { - /* - * If we want to do crash dump after notifier calls and - * kmsg_dump, we will need architecture dependent extra - * works in addition to stopping other CPUs. - */ - crash_smp_send_stop(); - } - - /* - * Run any panic handlers, including those that might need to - * add information to the kmsg dump output. - */ - atomic_notifier_call_chain(&panic_notifier_list, 0, buf); - - /* Call flush even twice. It tries harder with a single online CPU */ - printk_nmi_flush_on_panic(); - kmsg_dump(KMSG_DUMP_PANIC); - - /* - * If you doubt kdump always works fine in any situation, - * "crash_kexec_post_notifiers" offers you a chance to run - * panic_notifiers and dumping kmsg before kdump. - * Note: since some panic_notifiers can make crashed kernel - * more unstable, it can increase risks of the kdump failure too. - * - * Bypass the panic_cpu check and call __crash_kexec directly. - */ - if (_crash_kexec_post_notifiers) - __crash_kexec(NULL); - - bust_spinlocks(0); - - /* - * We may have ended up stopping the CPU holding the lock (in - * smp_send_stop()) while still having some valuable data in the console - * buffer. Try to acquire the lock then release it regardless of the - * result. The release will also print the buffers out. Locks debug - * should be disabled to avoid reporting bad unlock balance when - * panic() is not being callled from OOPS. - */ - debug_locks_off(); - console_flush_on_panic(); - - if (!panic_blink) - panic_blink = no_blink; - - if (panic_timeout > 0) { - /* - * Delay timeout seconds before rebooting the machine. - * We can't use the "normal" timers since we just panicked. - */ - pr_emerg("Rebooting in %d seconds..", panic_timeout); - - for (i = 0; i < panic_timeout * 1000; i += PANIC_TIMER_STEP) { - touch_nmi_watchdog(); - if (i >= i_next) { - i += panic_blink(state ^= 1); - i_next = i + 3600 / PANIC_BLINK_SPD; - } - mdelay(PANIC_TIMER_STEP); - } - } - if (panic_timeout != 0) { - /* - * This will not be a clean reboot, with everything - * shutting down. But if there is a chance of - * rebooting the system it will be rebooted. - */ - emergency_restart(); - } -#ifdef __sparc__ - { - extern int stop_a_enabled; - /* Make sure the user can actually press Stop-A (L1-A) */ - stop_a_enabled = 1; - pr_emerg("Press Stop-A (L1-A) to return to the boot prom\n"); - } -#endif -#if defined(CONFIG_S390) - { - unsigned long caller; - - caller = (unsigned long)__builtin_return_address(0); - disabled_wait(caller); - } -#endif - pr_emerg("---[ end Kernel panic - not syncing: %s\n", buf); - local_irq_enable(); - for (i = 0; ; i += PANIC_TIMER_STEP) { - touch_softlockup_watchdog(); - if (i >= i_next) { - i += panic_blink(state ^= 1); - i_next = i + 3600 / PANIC_BLINK_SPD; - } - mdelay(PANIC_TIMER_STEP); - } -} - -EXPORT_SYMBOL(panic); - - -struct tnt { - u8 bit; - char true; - char false; -}; - -static const struct tnt tnts[] = { - { TAINT_PROPRIETARY_MODULE, 'P', 'G' }, - { TAINT_FORCED_MODULE, 'F', ' ' }, - { TAINT_CPU_OUT_OF_SPEC, 'S', ' ' }, - { TAINT_FORCED_RMMOD, 'R', ' ' }, - { TAINT_MACHINE_CHECK, 'M', ' ' }, - { TAINT_BAD_PAGE, 'B', ' ' }, - { TAINT_USER, 'U', ' ' }, - { TAINT_DIE, 'D', ' ' }, - { TAINT_OVERRIDDEN_ACPI_TABLE, 'A', ' ' }, - { TAINT_WARN, 'W', ' ' }, - { TAINT_CRAP, 'C', ' ' }, - { TAINT_FIRMWARE_WORKAROUND, 'I', ' ' }, - { TAINT_OOT_MODULE, 'O', ' ' }, - { TAINT_UNSIGNED_MODULE, 'E', ' ' }, - { TAINT_SOFTLOCKUP, 'L', ' ' }, - { TAINT_LIVEPATCH, 'K', ' ' }, -}; - -/** - * print_tainted - return a string to represent the kernel taint state. - * - * 'P' - Proprietary module has been loaded. - * 'F' - Module has been forcibly loaded. - * 'S' - SMP with CPUs not designed for SMP. - * 'R' - User forced a module unload. - * 'M' - System experienced a machine check exception. - * 'B' - System has hit bad_page. - * 'U' - Userspace-defined naughtiness. - * 'D' - Kernel has oopsed before - * 'A' - ACPI table overridden. - * 'W' - Taint on warning. - * 'C' - modules from drivers/staging are loaded. - * 'I' - Working around severe firmware bug. - * 'O' - Out-of-tree module has been loaded. - * 'E' - Unsigned module has been loaded. - * 'L' - A soft lockup has previously occurred. - * 'K' - Kernel has been live patched. - * - * The string is overwritten by the next call to print_tainted(). - */ -const char *print_tainted(void) -{ - static char buf[ARRAY_SIZE(tnts) + sizeof("Tainted: ")]; - - if (tainted_mask) { - char *s; - int i; - - s = buf + sprintf(buf, "Tainted: "); - for (i = 0; i < ARRAY_SIZE(tnts); i++) { - const struct tnt *t = &tnts[i]; - *s++ = test_bit(t->bit, &tainted_mask) ? - t->true : t->false; - } - *s = 0; - } else - snprintf(buf, sizeof(buf), "Not tainted"); - - return buf; -} - -int test_taint(unsigned flag) -{ - return test_bit(flag, &tainted_mask); -} -EXPORT_SYMBOL(test_taint); - -unsigned long get_taint(void) -{ - return tainted_mask; -} - -/** - * add_taint: add a taint flag if not already set. - * @flag: one of the TAINT_* constants. - * @lockdep_ok: whether lock debugging is still OK. - * - * If something bad has gone wrong, you'll want @lockdebug_ok = false, but for - * some notewortht-but-not-corrupting cases, it can be set to true. - */ -void add_taint(unsigned flag, enum lockdep_ok lockdep_ok) -{ - if (lockdep_ok == LOCKDEP_NOW_UNRELIABLE && __debug_locks_off()) - pr_warn("Disabling lock debugging due to kernel taint\n"); - - set_bit(flag, &tainted_mask); -} -EXPORT_SYMBOL(add_taint); - -static void spin_msec(int msecs) -{ - int i; - - for (i = 0; i < msecs; i++) { - touch_nmi_watchdog(); - mdelay(1); - } -} - -/* - * It just happens that oops_enter() and oops_exit() are identically - * implemented... - */ -static void do_oops_enter_exit(void) -{ - unsigned long flags; - static int spin_counter; - - if (!pause_on_oops) - return; - - spin_lock_irqsave(&pause_on_oops_lock, flags); - if (pause_on_oops_flag == 0) { - /* This CPU may now print the oops message */ - pause_on_oops_flag = 1; - } else { - /* We need to stall this CPU */ - if (!spin_counter) { - /* This CPU gets to do the counting */ - spin_counter = pause_on_oops; - do { - spin_unlock(&pause_on_oops_lock); - spin_msec(MSEC_PER_SEC); - spin_lock(&pause_on_oops_lock); - } while (--spin_counter); - pause_on_oops_flag = 0; - } else { - /* This CPU waits for a different one */ - while (spin_counter) { - spin_unlock(&pause_on_oops_lock); - spin_msec(1); - spin_lock(&pause_on_oops_lock); - } - } - } - spin_unlock_irqrestore(&pause_on_oops_lock, flags); -} - -/* - * Return true if the calling CPU is allowed to print oops-related info. - * This is a bit racy.. - */ -int oops_may_print(void) -{ - return pause_on_oops_flag == 0; -} - -/* - * Called when the architecture enters its oops handler, before it prints - * anything. If this is the first CPU to oops, and it's oopsing the first - * time then let it proceed. - * - * This is all enabled by the pause_on_oops kernel boot option. We do all - * this to ensure that oopses don't scroll off the screen. It has the - * side-effect of preventing later-oopsing CPUs from mucking up the display, - * too. - * - * It turns out that the CPU which is allowed to print ends up pausing for - * the right duration, whereas all the other CPUs pause for twice as long: - * once in oops_enter(), once in oops_exit(). - */ -void oops_enter(void) -{ - tracing_off(); - /* can't trust the integrity of the kernel anymore: */ - debug_locks_off(); - do_oops_enter_exit(); -} - -/* - * 64-bit random ID for oopses: - */ -static u64 oops_id; - -static int init_oops_id(void) -{ - if (!oops_id) - get_random_bytes(&oops_id, sizeof(oops_id)); - else - oops_id++; - - return 0; -} -late_initcall(init_oops_id); - -void print_oops_end_marker(void) -{ - init_oops_id(); - pr_warn("---[ end trace %016llx ]---\n", (unsigned long long)oops_id); -} - -/* - * Called when the architecture exits its oops handler, after printing - * everything. - */ -void oops_exit(void) -{ - do_oops_enter_exit(); - print_oops_end_marker(); - kmsg_dump(KMSG_DUMP_OOPS); -} - -struct warn_args { - const char *fmt; - va_list args; -}; - -void __warn(const char *file, int line, void *caller, unsigned taint, - struct pt_regs *regs, struct warn_args *args) -{ - disable_trace_on_warning(); - - pr_warn("------------[ cut here ]------------\n"); - - if (file) - pr_warn("WARNING: CPU: %d PID: %d at %s:%d %pS\n", - raw_smp_processor_id(), current->pid, file, line, - caller); - else - pr_warn("WARNING: CPU: %d PID: %d at %pS\n", - raw_smp_processor_id(), current->pid, caller); - - if (args) - vprintk(args->fmt, args->args); - - if (panic_on_warn) { - /* - * This thread may hit another WARN() in the panic path. - * Resetting this prevents additional WARN() from panicking the - * system on this thread. Other threads are blocked by the - * panic_mutex in panic(). - */ - panic_on_warn = 0; - panic("panic_on_warn set ...\n"); - } - - print_modules(); - - if (regs) - show_regs(regs); - else - dump_stack(); - - print_oops_end_marker(); - - /* Just a warning, don't kill lockdep. */ - add_taint(taint, LOCKDEP_STILL_OK); -} - -#ifdef WANT_WARN_ON_SLOWPATH -void warn_slowpath_fmt(const char *file, int line, const char *fmt, ...) -{ - struct warn_args args; - - args.fmt = fmt; - va_start(args.args, fmt); - __warn(file, line, __builtin_return_address(0), TAINT_WARN, NULL, - &args); - va_end(args.args); -} -EXPORT_SYMBOL(warn_slowpath_fmt); - -void warn_slowpath_fmt_taint(const char *file, int line, - unsigned taint, const char *fmt, ...) -{ - struct warn_args args; - - args.fmt = fmt; - va_start(args.args, fmt); - __warn(file, line, __builtin_return_address(0), taint, NULL, &args); - va_end(args.args); -} -EXPORT_SYMBOL(warn_slowpath_fmt_taint); - -void warn_slowpath_null(const char *file, int line) -{ - __warn(file, line, __builtin_return_address(0), TAINT_WARN, NULL, NULL); -} -EXPORT_SYMBOL(warn_slowpath_null); -#endif - -#ifdef CONFIG_CC_STACKPROTECTOR - -/* - * Called when gcc's -fstack-protector feature is used, and - * gcc detects corruption of the on-stack canary value - */ -__visible void __stack_chk_fail(void) -{ - panic("stack-protector: Kernel stack is corrupted in: %p\n", - __builtin_return_address(0)); -} -EXPORT_SYMBOL(__stack_chk_fail); - -#endif - -core_param(panic, panic_timeout, int, 0644); -core_param(pause_on_oops, pause_on_oops, int, 0644); -core_param(panic_on_warn, panic_on_warn, int, 0644); -core_param(crash_kexec_post_notifiers, crash_kexec_post_notifiers, bool, 0644); - -static int __init oops_setup(char *s) -{ - if (!s) - return -EINVAL; - if (!strcmp(s, "panic")) - panic_on_oops = 1; - return 0; -} -early_param("oops", oops_setup); diff --git a/src/linux/kernel/params.c b/src/linux/kernel/params.c deleted file mode 100644 index a6d6149..0000000 --- a/src/linux/kernel/params.c +++ /dev/null @@ -1,1015 +0,0 @@ -/* Helpers for initial module or kernel cmdline parsing - Copyright (C) 2001 Rusty Russell. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_SYSFS -/* Protects all built-in parameters, modules use their own param_lock */ -static DEFINE_MUTEX(param_lock); - -/* Use the module's mutex, or if built-in use the built-in mutex */ -#ifdef CONFIG_MODULES -#define KPARAM_MUTEX(mod) ((mod) ? &(mod)->param_lock : ¶m_lock) -#else -#define KPARAM_MUTEX(mod) (¶m_lock) -#endif - -static inline void check_kparam_locked(struct module *mod) -{ - BUG_ON(!mutex_is_locked(KPARAM_MUTEX(mod))); -} -#else -static inline void check_kparam_locked(struct module *mod) -{ -} -#endif /* !CONFIG_SYSFS */ - -/* This just allows us to keep track of which parameters are kmalloced. */ -struct kmalloced_param { - struct list_head list; - char val[]; -}; -static LIST_HEAD(kmalloced_params); -static DEFINE_SPINLOCK(kmalloced_params_lock); - -static void *kmalloc_parameter(unsigned int size) -{ - struct kmalloced_param *p; - - p = kmalloc(sizeof(*p) + size, GFP_KERNEL); - if (!p) - return NULL; - - spin_lock(&kmalloced_params_lock); - list_add(&p->list, &kmalloced_params); - spin_unlock(&kmalloced_params_lock); - - return p->val; -} - -/* Does nothing if parameter wasn't kmalloced above. */ -static void maybe_kfree_parameter(void *param) -{ - struct kmalloced_param *p; - - spin_lock(&kmalloced_params_lock); - list_for_each_entry(p, &kmalloced_params, list) { - if (p->val == param) { - list_del(&p->list); - kfree(p); - break; - } - } - spin_unlock(&kmalloced_params_lock); -} - -static char dash2underscore(char c) -{ - if (c == '-') - return '_'; - return c; -} - -bool parameqn(const char *a, const char *b, size_t n) -{ - size_t i; - - for (i = 0; i < n; i++) { - if (dash2underscore(a[i]) != dash2underscore(b[i])) - return false; - } - return true; -} - -bool parameq(const char *a, const char *b) -{ - return parameqn(a, b, strlen(a)+1); -} - -static void param_check_unsafe(const struct kernel_param *kp) -{ - if (kp->flags & KERNEL_PARAM_FL_UNSAFE) { - pr_warn("Setting dangerous option %s - tainting kernel\n", - kp->name); - add_taint(TAINT_USER, LOCKDEP_STILL_OK); - } -} - -static int parse_one(char *param, - char *val, - const char *doing, - const struct kernel_param *params, - unsigned num_params, - s16 min_level, - s16 max_level, - void *arg, - int (*handle_unknown)(char *param, char *val, - const char *doing, void *arg)) -{ - unsigned int i; - int err; - - /* Find parameter */ - for (i = 0; i < num_params; i++) { - if (parameq(param, params[i].name)) { - if (params[i].level < min_level - || params[i].level > max_level) - return 0; - /* No one handled NULL, so do it here. */ - if (!val && - !(params[i].ops->flags & KERNEL_PARAM_OPS_FL_NOARG)) - return -EINVAL; - pr_debug("handling %s with %p\n", param, - params[i].ops->set); - kernel_param_lock(params[i].mod); - param_check_unsafe(¶ms[i]); - err = params[i].ops->set(val, ¶ms[i]); - kernel_param_unlock(params[i].mod); - return err; - } - } - - if (handle_unknown) { - pr_debug("doing %s: %s='%s'\n", doing, param, val); - return handle_unknown(param, val, doing, arg); - } - - pr_debug("Unknown argument '%s'\n", param); - return -ENOENT; -} - -/* You can use " around spaces, but can't escape ". */ -/* Hyphens and underscores equivalent in parameter names. */ -static char *next_arg(char *args, char **param, char **val) -{ - unsigned int i, equals = 0; - int in_quote = 0, quoted = 0; - char *next; - - if (*args == '"') { - args++; - in_quote = 1; - quoted = 1; - } - - for (i = 0; args[i]; i++) { - if (isspace(args[i]) && !in_quote) - break; - if (equals == 0) { - if (args[i] == '=') - equals = i; - } - if (args[i] == '"') - in_quote = !in_quote; - } - - *param = args; - if (!equals) - *val = NULL; - else { - args[equals] = '\0'; - *val = args + equals + 1; - - /* Don't include quotes in value. */ - if (**val == '"') { - (*val)++; - if (args[i-1] == '"') - args[i-1] = '\0'; - } - } - if (quoted && args[i-1] == '"') - args[i-1] = '\0'; - - if (args[i]) { - args[i] = '\0'; - next = args + i + 1; - } else - next = args + i; - - /* Chew up trailing spaces. */ - return skip_spaces(next); -} - -/* Args looks like "foo=bar,bar2 baz=fuz wiz". */ -char *parse_args(const char *doing, - char *args, - const struct kernel_param *params, - unsigned num, - s16 min_level, - s16 max_level, - void *arg, - int (*unknown)(char *param, char *val, - const char *doing, void *arg)) -{ - char *param, *val, *err = NULL; - - /* Chew leading spaces */ - args = skip_spaces(args); - - if (*args) - pr_debug("doing %s, parsing ARGS: '%s'\n", doing, args); - - while (*args) { - int ret; - int irq_was_disabled; - - args = next_arg(args, ¶m, &val); - /* Stop at -- */ - if (!val && strcmp(param, "--") == 0) - return err ?: args; - irq_was_disabled = irqs_disabled(); - ret = parse_one(param, val, doing, params, num, - min_level, max_level, arg, unknown); - if (irq_was_disabled && !irqs_disabled()) - pr_warn("%s: option '%s' enabled irq's!\n", - doing, param); - - switch (ret) { - case 0: - continue; - case -ENOENT: - pr_err("%s: Unknown parameter `%s'\n", doing, param); - break; - case -ENOSPC: - pr_err("%s: `%s' too large for parameter `%s'\n", - doing, val ?: "", param); - break; - default: - pr_err("%s: `%s' invalid for parameter `%s'\n", - doing, val ?: "", param); - break; - } - - err = ERR_PTR(ret); - } - - return err; -} - -/* Lazy bastard, eh? */ -#define STANDARD_PARAM_DEF(name, type, format, strtolfn) \ - int param_set_##name(const char *val, const struct kernel_param *kp) \ - { \ - return strtolfn(val, 0, (type *)kp->arg); \ - } \ - int param_get_##name(char *buffer, const struct kernel_param *kp) \ - { \ - return scnprintf(buffer, PAGE_SIZE, format, \ - *((type *)kp->arg)); \ - } \ - const struct kernel_param_ops param_ops_##name = { \ - .set = param_set_##name, \ - .get = param_get_##name, \ - }; \ - EXPORT_SYMBOL(param_set_##name); \ - EXPORT_SYMBOL(param_get_##name); \ - EXPORT_SYMBOL(param_ops_##name) - - -STANDARD_PARAM_DEF(byte, unsigned char, "%hhu", kstrtou8); -STANDARD_PARAM_DEF(short, short, "%hi", kstrtos16); -STANDARD_PARAM_DEF(ushort, unsigned short, "%hu", kstrtou16); -STANDARD_PARAM_DEF(int, int, "%i", kstrtoint); -STANDARD_PARAM_DEF(uint, unsigned int, "%u", kstrtouint); -STANDARD_PARAM_DEF(long, long, "%li", kstrtol); -STANDARD_PARAM_DEF(ulong, unsigned long, "%lu", kstrtoul); -STANDARD_PARAM_DEF(ullong, unsigned long long, "%llu", kstrtoull); - -int param_set_charp(const char *val, const struct kernel_param *kp) -{ - if (strlen(val) > 1024) { - pr_err("%s: string parameter too long\n", kp->name); - return -ENOSPC; - } - - maybe_kfree_parameter(*(char **)kp->arg); - - /* This is a hack. We can't kmalloc in early boot, and we - * don't need to; this mangled commandline is preserved. */ - if (slab_is_available()) { - *(char **)kp->arg = kmalloc_parameter(strlen(val)+1); - if (!*(char **)kp->arg) - return -ENOMEM; - strcpy(*(char **)kp->arg, val); - } else - *(const char **)kp->arg = val; - - return 0; -} -EXPORT_SYMBOL(param_set_charp); - -int param_get_charp(char *buffer, const struct kernel_param *kp) -{ - return scnprintf(buffer, PAGE_SIZE, "%s", *((char **)kp->arg)); -} -EXPORT_SYMBOL(param_get_charp); - -void param_free_charp(void *arg) -{ - maybe_kfree_parameter(*((char **)arg)); -} -EXPORT_SYMBOL(param_free_charp); - -const struct kernel_param_ops param_ops_charp = { - .set = param_set_charp, - .get = param_get_charp, - .free = param_free_charp, -}; -EXPORT_SYMBOL(param_ops_charp); - -/* Actually could be a bool or an int, for historical reasons. */ -int param_set_bool(const char *val, const struct kernel_param *kp) -{ - /* No equals means "set"... */ - if (!val) val = "1"; - - /* One of =[yYnN01] */ - return strtobool(val, kp->arg); -} -EXPORT_SYMBOL(param_set_bool); - -int param_get_bool(char *buffer, const struct kernel_param *kp) -{ - /* Y and N chosen as being relatively non-coder friendly */ - return sprintf(buffer, "%c", *(bool *)kp->arg ? 'Y' : 'N'); -} -EXPORT_SYMBOL(param_get_bool); - -const struct kernel_param_ops param_ops_bool = { - .flags = KERNEL_PARAM_OPS_FL_NOARG, - .set = param_set_bool, - .get = param_get_bool, -}; -EXPORT_SYMBOL(param_ops_bool); - -int param_set_bool_enable_only(const char *val, const struct kernel_param *kp) -{ - int err = 0; - bool new_value; - bool orig_value = *(bool *)kp->arg; - struct kernel_param dummy_kp = *kp; - - dummy_kp.arg = &new_value; - - err = param_set_bool(val, &dummy_kp); - if (err) - return err; - - /* Don't let them unset it once it's set! */ - if (!new_value && orig_value) - return -EROFS; - - if (new_value) - err = param_set_bool(val, kp); - - return err; -} -EXPORT_SYMBOL_GPL(param_set_bool_enable_only); - -const struct kernel_param_ops param_ops_bool_enable_only = { - .flags = KERNEL_PARAM_OPS_FL_NOARG, - .set = param_set_bool_enable_only, - .get = param_get_bool, -}; -EXPORT_SYMBOL_GPL(param_ops_bool_enable_only); - -/* This one must be bool. */ -int param_set_invbool(const char *val, const struct kernel_param *kp) -{ - int ret; - bool boolval; - struct kernel_param dummy; - - dummy.arg = &boolval; - ret = param_set_bool(val, &dummy); - if (ret == 0) - *(bool *)kp->arg = !boolval; - return ret; -} -EXPORT_SYMBOL(param_set_invbool); - -int param_get_invbool(char *buffer, const struct kernel_param *kp) -{ - return sprintf(buffer, "%c", (*(bool *)kp->arg) ? 'N' : 'Y'); -} -EXPORT_SYMBOL(param_get_invbool); - -const struct kernel_param_ops param_ops_invbool = { - .set = param_set_invbool, - .get = param_get_invbool, -}; -EXPORT_SYMBOL(param_ops_invbool); - -int param_set_bint(const char *val, const struct kernel_param *kp) -{ - /* Match bool exactly, by re-using it. */ - struct kernel_param boolkp = *kp; - bool v; - int ret; - - boolkp.arg = &v; - - ret = param_set_bool(val, &boolkp); - if (ret == 0) - *(int *)kp->arg = v; - return ret; -} -EXPORT_SYMBOL(param_set_bint); - -const struct kernel_param_ops param_ops_bint = { - .flags = KERNEL_PARAM_OPS_FL_NOARG, - .set = param_set_bint, - .get = param_get_int, -}; -EXPORT_SYMBOL(param_ops_bint); - -/* We break the rule and mangle the string. */ -static int param_array(struct module *mod, - const char *name, - const char *val, - unsigned int min, unsigned int max, - void *elem, int elemsize, - int (*set)(const char *, const struct kernel_param *kp), - s16 level, - unsigned int *num) -{ - int ret; - struct kernel_param kp; - char save; - - /* Get the name right for errors. */ - kp.name = name; - kp.arg = elem; - kp.level = level; - - *num = 0; - /* We expect a comma-separated list of values. */ - do { - int len; - - if (*num == max) { - pr_err("%s: can only take %i arguments\n", name, max); - return -EINVAL; - } - len = strcspn(val, ","); - - /* nul-terminate and parse */ - save = val[len]; - ((char *)val)[len] = '\0'; - check_kparam_locked(mod); - ret = set(val, &kp); - - if (ret != 0) - return ret; - kp.arg += elemsize; - val += len+1; - (*num)++; - } while (save == ','); - - if (*num < min) { - pr_err("%s: needs at least %i arguments\n", name, min); - return -EINVAL; - } - return 0; -} - -static int param_array_set(const char *val, const struct kernel_param *kp) -{ - const struct kparam_array *arr = kp->arr; - unsigned int temp_num; - - return param_array(kp->mod, kp->name, val, 1, arr->max, arr->elem, - arr->elemsize, arr->ops->set, kp->level, - arr->num ?: &temp_num); -} - -static int param_array_get(char *buffer, const struct kernel_param *kp) -{ - int i, off, ret; - const struct kparam_array *arr = kp->arr; - struct kernel_param p = *kp; - - for (i = off = 0; i < (arr->num ? *arr->num : arr->max); i++) { - if (i) - buffer[off++] = ','; - p.arg = arr->elem + arr->elemsize * i; - check_kparam_locked(p.mod); - ret = arr->ops->get(buffer + off, &p); - if (ret < 0) - return ret; - off += ret; - } - buffer[off] = '\0'; - return off; -} - -static void param_array_free(void *arg) -{ - unsigned int i; - const struct kparam_array *arr = arg; - - if (arr->ops->free) - for (i = 0; i < (arr->num ? *arr->num : arr->max); i++) - arr->ops->free(arr->elem + arr->elemsize * i); -} - -const struct kernel_param_ops param_array_ops = { - .set = param_array_set, - .get = param_array_get, - .free = param_array_free, -}; -EXPORT_SYMBOL(param_array_ops); - -int param_set_copystring(const char *val, const struct kernel_param *kp) -{ - const struct kparam_string *kps = kp->str; - - if (strlen(val)+1 > kps->maxlen) { - pr_err("%s: string doesn't fit in %u chars.\n", - kp->name, kps->maxlen-1); - return -ENOSPC; - } - strcpy(kps->string, val); - return 0; -} -EXPORT_SYMBOL(param_set_copystring); - -int param_get_string(char *buffer, const struct kernel_param *kp) -{ - const struct kparam_string *kps = kp->str; - return strlcpy(buffer, kps->string, kps->maxlen); -} -EXPORT_SYMBOL(param_get_string); - -const struct kernel_param_ops param_ops_string = { - .set = param_set_copystring, - .get = param_get_string, -}; -EXPORT_SYMBOL(param_ops_string); - -/* sysfs output in /sys/modules/XYZ/parameters/ */ -#define to_module_attr(n) container_of(n, struct module_attribute, attr) -#define to_module_kobject(n) container_of(n, struct module_kobject, kobj) - -struct param_attribute -{ - struct module_attribute mattr; - const struct kernel_param *param; -}; - -struct module_param_attrs -{ - unsigned int num; - struct attribute_group grp; - struct param_attribute attrs[0]; -}; - -#ifdef CONFIG_SYSFS -#define to_param_attr(n) container_of(n, struct param_attribute, mattr) - -static ssize_t param_attr_show(struct module_attribute *mattr, - struct module_kobject *mk, char *buf) -{ - int count; - struct param_attribute *attribute = to_param_attr(mattr); - - if (!attribute->param->ops->get) - return -EPERM; - - kernel_param_lock(mk->mod); - count = attribute->param->ops->get(buf, attribute->param); - kernel_param_unlock(mk->mod); - if (count > 0) { - strcat(buf, "\n"); - ++count; - } - return count; -} - -/* sysfs always hands a nul-terminated string in buf. We rely on that. */ -static ssize_t param_attr_store(struct module_attribute *mattr, - struct module_kobject *mk, - const char *buf, size_t len) -{ - int err; - struct param_attribute *attribute = to_param_attr(mattr); - - if (!attribute->param->ops->set) - return -EPERM; - - kernel_param_lock(mk->mod); - param_check_unsafe(attribute->param); - err = attribute->param->ops->set(buf, attribute->param); - kernel_param_unlock(mk->mod); - if (!err) - return len; - return err; -} -#endif - -#ifdef CONFIG_MODULES -#define __modinit -#else -#define __modinit __init -#endif - -#ifdef CONFIG_SYSFS -void kernel_param_lock(struct module *mod) -{ - mutex_lock(KPARAM_MUTEX(mod)); -} - -void kernel_param_unlock(struct module *mod) -{ - mutex_unlock(KPARAM_MUTEX(mod)); -} - -EXPORT_SYMBOL(kernel_param_lock); -EXPORT_SYMBOL(kernel_param_unlock); - -/* - * add_sysfs_param - add a parameter to sysfs - * @mk: struct module_kobject - * @kparam: the actual parameter definition to add to sysfs - * @name: name of parameter - * - * Create a kobject if for a (per-module) parameter if mp NULL, and - * create file in sysfs. Returns an error on out of memory. Always cleans up - * if there's an error. - */ -static __modinit int add_sysfs_param(struct module_kobject *mk, - const struct kernel_param *kp, - const char *name) -{ - struct module_param_attrs *new_mp; - struct attribute **new_attrs; - unsigned int i; - - /* We don't bother calling this with invisible parameters. */ - BUG_ON(!kp->perm); - - if (!mk->mp) { - /* First allocation. */ - mk->mp = kzalloc(sizeof(*mk->mp), GFP_KERNEL); - if (!mk->mp) - return -ENOMEM; - mk->mp->grp.name = "parameters"; - /* NULL-terminated attribute array. */ - mk->mp->grp.attrs = kzalloc(sizeof(mk->mp->grp.attrs[0]), - GFP_KERNEL); - /* Caller will cleanup via free_module_param_attrs */ - if (!mk->mp->grp.attrs) - return -ENOMEM; - } - - /* Enlarge allocations. */ - new_mp = krealloc(mk->mp, - sizeof(*mk->mp) + - sizeof(mk->mp->attrs[0]) * (mk->mp->num + 1), - GFP_KERNEL); - if (!new_mp) - return -ENOMEM; - mk->mp = new_mp; - - /* Extra pointer for NULL terminator */ - new_attrs = krealloc(mk->mp->grp.attrs, - sizeof(mk->mp->grp.attrs[0]) * (mk->mp->num + 2), - GFP_KERNEL); - if (!new_attrs) - return -ENOMEM; - mk->mp->grp.attrs = new_attrs; - - /* Tack new one on the end. */ - memset(&mk->mp->attrs[mk->mp->num], 0, sizeof(mk->mp->attrs[0])); - sysfs_attr_init(&mk->mp->attrs[mk->mp->num].mattr.attr); - mk->mp->attrs[mk->mp->num].param = kp; - mk->mp->attrs[mk->mp->num].mattr.show = param_attr_show; - /* Do not allow runtime DAC changes to make param writable. */ - if ((kp->perm & (S_IWUSR | S_IWGRP | S_IWOTH)) != 0) - mk->mp->attrs[mk->mp->num].mattr.store = param_attr_store; - else - mk->mp->attrs[mk->mp->num].mattr.store = NULL; - mk->mp->attrs[mk->mp->num].mattr.attr.name = (char *)name; - mk->mp->attrs[mk->mp->num].mattr.attr.mode = kp->perm; - mk->mp->num++; - - /* Fix up all the pointers, since krealloc can move us */ - for (i = 0; i < mk->mp->num; i++) - mk->mp->grp.attrs[i] = &mk->mp->attrs[i].mattr.attr; - mk->mp->grp.attrs[mk->mp->num] = NULL; - return 0; -} - -#ifdef CONFIG_MODULES -static void free_module_param_attrs(struct module_kobject *mk) -{ - if (mk->mp) - kfree(mk->mp->grp.attrs); - kfree(mk->mp); - mk->mp = NULL; -} - -/* - * module_param_sysfs_setup - setup sysfs support for one module - * @mod: module - * @kparam: module parameters (array) - * @num_params: number of module parameters - * - * Adds sysfs entries for module parameters under - * /sys/module/[mod->name]/parameters/ - */ -int module_param_sysfs_setup(struct module *mod, - const struct kernel_param *kparam, - unsigned int num_params) -{ - int i, err; - bool params = false; - - for (i = 0; i < num_params; i++) { - if (kparam[i].perm == 0) - continue; - err = add_sysfs_param(&mod->mkobj, &kparam[i], kparam[i].name); - if (err) { - free_module_param_attrs(&mod->mkobj); - return err; - } - params = true; - } - - if (!params) - return 0; - - /* Create the param group. */ - err = sysfs_create_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp); - if (err) - free_module_param_attrs(&mod->mkobj); - return err; -} - -/* - * module_param_sysfs_remove - remove sysfs support for one module - * @mod: module - * - * Remove sysfs entries for module parameters and the corresponding - * kobject. - */ -void module_param_sysfs_remove(struct module *mod) -{ - if (mod->mkobj.mp) { - sysfs_remove_group(&mod->mkobj.kobj, &mod->mkobj.mp->grp); - /* We are positive that no one is using any param - * attrs at this point. Deallocate immediately. */ - free_module_param_attrs(&mod->mkobj); - } -} -#endif - -void destroy_params(const struct kernel_param *params, unsigned num) -{ - unsigned int i; - - for (i = 0; i < num; i++) - if (params[i].ops->free) - params[i].ops->free(params[i].arg); -} - -static struct module_kobject * __init locate_module_kobject(const char *name) -{ - struct module_kobject *mk; - struct kobject *kobj; - int err; - - kobj = kset_find_obj(module_kset, name); - if (kobj) { - mk = to_module_kobject(kobj); - } else { - mk = kzalloc(sizeof(struct module_kobject), GFP_KERNEL); - BUG_ON(!mk); - - mk->mod = THIS_MODULE; - mk->kobj.kset = module_kset; - err = kobject_init_and_add(&mk->kobj, &module_ktype, NULL, - "%s", name); -#ifdef CONFIG_MODULES - if (!err) - err = sysfs_create_file(&mk->kobj, &module_uevent.attr); -#endif - if (err) { - kobject_put(&mk->kobj); - pr_crit("Adding module '%s' to sysfs failed (%d), the system may be unstable.\n", - name, err); - return NULL; - } - - /* So that we hold reference in both cases. */ - kobject_get(&mk->kobj); - } - - return mk; -} - -static void __init kernel_add_sysfs_param(const char *name, - const struct kernel_param *kparam, - unsigned int name_skip) -{ - struct module_kobject *mk; - int err; - - mk = locate_module_kobject(name); - if (!mk) - return; - - /* We need to remove old parameters before adding more. */ - if (mk->mp) - sysfs_remove_group(&mk->kobj, &mk->mp->grp); - - /* These should not fail at boot. */ - err = add_sysfs_param(mk, kparam, kparam->name + name_skip); - BUG_ON(err); - err = sysfs_create_group(&mk->kobj, &mk->mp->grp); - BUG_ON(err); - kobject_uevent(&mk->kobj, KOBJ_ADD); - kobject_put(&mk->kobj); -} - -/* - * param_sysfs_builtin - add sysfs parameters for built-in modules - * - * Add module_parameters to sysfs for "modules" built into the kernel. - * - * The "module" name (KBUILD_MODNAME) is stored before a dot, the - * "parameter" name is stored behind a dot in kernel_param->name. So, - * extract the "module" name for all built-in kernel_param-eters, - * and for all who have the same, call kernel_add_sysfs_param. - */ -static void __init param_sysfs_builtin(void) -{ - const struct kernel_param *kp; - unsigned int name_len; - char modname[MODULE_NAME_LEN]; - - for (kp = __start___param; kp < __stop___param; kp++) { - char *dot; - - if (kp->perm == 0) - continue; - - dot = strchr(kp->name, '.'); - if (!dot) { - /* This happens for core_param() */ - strcpy(modname, "kernel"); - name_len = 0; - } else { - name_len = dot - kp->name + 1; - strlcpy(modname, kp->name, name_len); - } - kernel_add_sysfs_param(modname, kp, name_len); - } -} - -ssize_t __modver_version_show(struct module_attribute *mattr, - struct module_kobject *mk, char *buf) -{ - struct module_version_attribute *vattr = - container_of(mattr, struct module_version_attribute, mattr); - - return scnprintf(buf, PAGE_SIZE, "%s\n", vattr->version); -} - -extern const struct module_version_attribute *__start___modver[]; -extern const struct module_version_attribute *__stop___modver[]; - -static void __init version_sysfs_builtin(void) -{ - const struct module_version_attribute **p; - struct module_kobject *mk; - int err; - - for (p = __start___modver; p < __stop___modver; p++) { - const struct module_version_attribute *vattr = *p; - - mk = locate_module_kobject(vattr->module_name); - if (mk) { - err = sysfs_create_file(&mk->kobj, &vattr->mattr.attr); - WARN_ON_ONCE(err); - kobject_uevent(&mk->kobj, KOBJ_ADD); - kobject_put(&mk->kobj); - } - } -} - -/* module-related sysfs stuff */ - -static ssize_t module_attr_show(struct kobject *kobj, - struct attribute *attr, - char *buf) -{ - struct module_attribute *attribute; - struct module_kobject *mk; - int ret; - - attribute = to_module_attr(attr); - mk = to_module_kobject(kobj); - - if (!attribute->show) - return -EIO; - - ret = attribute->show(attribute, mk, buf); - - return ret; -} - -static ssize_t module_attr_store(struct kobject *kobj, - struct attribute *attr, - const char *buf, size_t len) -{ - struct module_attribute *attribute; - struct module_kobject *mk; - int ret; - - attribute = to_module_attr(attr); - mk = to_module_kobject(kobj); - - if (!attribute->store) - return -EIO; - - ret = attribute->store(attribute, mk, buf, len); - - return ret; -} - -static const struct sysfs_ops module_sysfs_ops = { - .show = module_attr_show, - .store = module_attr_store, -}; - -static int uevent_filter(struct kset *kset, struct kobject *kobj) -{ - struct kobj_type *ktype = get_ktype(kobj); - - if (ktype == &module_ktype) - return 1; - return 0; -} - -static const struct kset_uevent_ops module_uevent_ops = { - .filter = uevent_filter, -}; - -struct kset *module_kset; -int module_sysfs_initialized; - -static void module_kobj_release(struct kobject *kobj) -{ - struct module_kobject *mk = to_module_kobject(kobj); - complete(mk->kobj_completion); -} - -struct kobj_type module_ktype = { - .release = module_kobj_release, - .sysfs_ops = &module_sysfs_ops, -}; - -/* - * param_sysfs_init - wrapper for built-in params support - */ -static int __init param_sysfs_init(void) -{ - module_kset = kset_create_and_add("module", &module_uevent_ops, NULL); - if (!module_kset) { - printk(KERN_WARNING "%s (%d): error creating kset\n", - __FILE__, __LINE__); - return -ENOMEM; - } - module_sysfs_initialized = 1; - - version_sysfs_builtin(); - param_sysfs_builtin(); - - return 0; -} -subsys_initcall(param_sysfs_init); - -#endif /* CONFIG_SYSFS */ diff --git a/src/linux/kernel/pid.c b/src/linux/kernel/pid.c deleted file mode 100644 index f66162f..0000000 --- a/src/linux/kernel/pid.c +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Generic pidhash and scalable, time-bounded PID allocator - * - * (C) 2002-2003 Nadia Yvette Chambers, IBM - * (C) 2004 Nadia Yvette Chambers, Oracle - * (C) 2002-2004 Ingo Molnar, Red Hat - * - * pid-structures are backing objects for tasks sharing a given ID to chain - * against. There is very little to them aside from hashing them and - * parking tasks using given ID's on a list. - * - * The hash is always changed with the tasklist_lock write-acquired, - * and the hash is only accessed with the tasklist_lock at least - * read-acquired, so there's no additional SMP locking needed here. - * - * We have a list of bitmap pages, which bitmaps represent the PID space. - * Allocating and freeing PIDs is completely lockless. The worst-case - * allocation scenario when all but one out of 1 million PIDs possible are - * allocated already: the scanning of 32 list entries and at most PAGE_SIZE - * bytes. The typical fastpath is a single successful setbit. Freeing is O(1). - * - * Pid namespaces: - * (C) 2007 Pavel Emelyanov , OpenVZ, SWsoft Inc. - * (C) 2007 Sukadev Bhattiprolu , IBM - * Many thanks to Oleg Nesterov for comments and help - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define pid_hashfn(nr, ns) \ - hash_long((unsigned long)nr + (unsigned long)ns, pidhash_shift) -static struct hlist_head *pid_hash; -static unsigned int pidhash_shift = 4; -struct pid init_struct_pid = INIT_STRUCT_PID; - -int pid_max = PID_MAX_DEFAULT; - -#define RESERVED_PIDS 300 - -int pid_max_min = RESERVED_PIDS + 1; -int pid_max_max = PID_MAX_LIMIT; - -static inline int mk_pid(struct pid_namespace *pid_ns, - struct pidmap *map, int off) -{ - return (map - pid_ns->pidmap)*BITS_PER_PAGE + off; -} - -#define find_next_offset(map, off) \ - find_next_zero_bit((map)->page, BITS_PER_PAGE, off) - -/* - * PID-map pages start out as NULL, they get allocated upon - * first use and are never deallocated. This way a low pid_max - * value does not cause lots of bitmaps to be allocated, but - * the scheme scales to up to 4 million PIDs, runtime. - */ -struct pid_namespace init_pid_ns = { - .kref = { - .refcount = ATOMIC_INIT(2), - }, - .pidmap = { - [ 0 ... PIDMAP_ENTRIES-1] = { ATOMIC_INIT(BITS_PER_PAGE), NULL } - }, - .last_pid = 0, - .nr_hashed = PIDNS_HASH_ADDING, - .level = 0, - .child_reaper = &init_task, - .user_ns = &init_user_ns, - .ns.inum = PROC_PID_INIT_INO, -#ifdef CONFIG_PID_NS - .ns.ops = &pidns_operations, -#endif -}; -EXPORT_SYMBOL_GPL(init_pid_ns); - -/* - * Note: disable interrupts while the pidmap_lock is held as an - * interrupt might come in and do read_lock(&tasklist_lock). - * - * If we don't disable interrupts there is a nasty deadlock between - * detach_pid()->free_pid() and another cpu that does - * spin_lock(&pidmap_lock) followed by an interrupt routine that does - * read_lock(&tasklist_lock); - * - * After we clean up the tasklist_lock and know there are no - * irq handlers that take it we can leave the interrupts enabled. - * For now it is easier to be safe than to prove it can't happen. - */ - -static __cacheline_aligned_in_smp DEFINE_SPINLOCK(pidmap_lock); - -static void free_pidmap(struct upid *upid) -{ - int nr = upid->nr; - struct pidmap *map = upid->ns->pidmap + nr / BITS_PER_PAGE; - int offset = nr & BITS_PER_PAGE_MASK; - - clear_bit(offset, map->page); - atomic_inc(&map->nr_free); -} - -/* - * If we started walking pids at 'base', is 'a' seen before 'b'? - */ -static int pid_before(int base, int a, int b) -{ - /* - * This is the same as saying - * - * (a - base + MAXUINT) % MAXUINT < (b - base + MAXUINT) % MAXUINT - * and that mapping orders 'a' and 'b' with respect to 'base'. - */ - return (unsigned)(a - base) < (unsigned)(b - base); -} - -/* - * We might be racing with someone else trying to set pid_ns->last_pid - * at the pid allocation time (there's also a sysctl for this, but racing - * with this one is OK, see comment in kernel/pid_namespace.c about it). - * We want the winner to have the "later" value, because if the - * "earlier" value prevails, then a pid may get reused immediately. - * - * Since pids rollover, it is not sufficient to just pick the bigger - * value. We have to consider where we started counting from. - * - * 'base' is the value of pid_ns->last_pid that we observed when - * we started looking for a pid. - * - * 'pid' is the pid that we eventually found. - */ -static void set_last_pid(struct pid_namespace *pid_ns, int base, int pid) -{ - int prev; - int last_write = base; - do { - prev = last_write; - last_write = cmpxchg(&pid_ns->last_pid, prev, pid); - } while ((prev != last_write) && (pid_before(base, last_write, pid))); -} - -static int alloc_pidmap(struct pid_namespace *pid_ns) -{ - int i, offset, max_scan, pid, last = pid_ns->last_pid; - struct pidmap *map; - - pid = last + 1; - if (pid >= pid_max) - pid = RESERVED_PIDS; - offset = pid & BITS_PER_PAGE_MASK; - map = &pid_ns->pidmap[pid/BITS_PER_PAGE]; - /* - * If last_pid points into the middle of the map->page we - * want to scan this bitmap block twice, the second time - * we start with offset == 0 (or RESERVED_PIDS). - */ - max_scan = DIV_ROUND_UP(pid_max, BITS_PER_PAGE) - !offset; - for (i = 0; i <= max_scan; ++i) { - if (unlikely(!map->page)) { - void *page = kzalloc(PAGE_SIZE, GFP_KERNEL); - /* - * Free the page if someone raced with us - * installing it: - */ - spin_lock_irq(&pidmap_lock); - if (!map->page) { - map->page = page; - page = NULL; - } - spin_unlock_irq(&pidmap_lock); - kfree(page); - if (unlikely(!map->page)) - return -ENOMEM; - } - if (likely(atomic_read(&map->nr_free))) { - for ( ; ; ) { - if (!test_and_set_bit(offset, map->page)) { - atomic_dec(&map->nr_free); - set_last_pid(pid_ns, last, pid); - return pid; - } - offset = find_next_offset(map, offset); - if (offset >= BITS_PER_PAGE) - break; - pid = mk_pid(pid_ns, map, offset); - if (pid >= pid_max) - break; - } - } - if (map < &pid_ns->pidmap[(pid_max-1)/BITS_PER_PAGE]) { - ++map; - offset = 0; - } else { - map = &pid_ns->pidmap[0]; - offset = RESERVED_PIDS; - if (unlikely(last == offset)) - break; - } - pid = mk_pid(pid_ns, map, offset); - } - return -EAGAIN; -} - -int next_pidmap(struct pid_namespace *pid_ns, unsigned int last) -{ - int offset; - struct pidmap *map, *end; - - if (last >= PID_MAX_LIMIT) - return -1; - - offset = (last + 1) & BITS_PER_PAGE_MASK; - map = &pid_ns->pidmap[(last + 1)/BITS_PER_PAGE]; - end = &pid_ns->pidmap[PIDMAP_ENTRIES]; - for (; map < end; map++, offset = 0) { - if (unlikely(!map->page)) - continue; - offset = find_next_bit((map)->page, BITS_PER_PAGE, offset); - if (offset < BITS_PER_PAGE) - return mk_pid(pid_ns, map, offset); - } - return -1; -} - -void put_pid(struct pid *pid) -{ - struct pid_namespace *ns; - - if (!pid) - return; - - ns = pid->numbers[pid->level].ns; - if ((atomic_read(&pid->count) == 1) || - atomic_dec_and_test(&pid->count)) { - kmem_cache_free(ns->pid_cachep, pid); - put_pid_ns(ns); - } -} -EXPORT_SYMBOL_GPL(put_pid); - -static void delayed_put_pid(struct rcu_head *rhp) -{ - struct pid *pid = container_of(rhp, struct pid, rcu); - put_pid(pid); -} - -void free_pid(struct pid *pid) -{ - /* We can be called with write_lock_irq(&tasklist_lock) held */ - int i; - unsigned long flags; - - spin_lock_irqsave(&pidmap_lock, flags); - for (i = 0; i <= pid->level; i++) { - struct upid *upid = pid->numbers + i; - struct pid_namespace *ns = upid->ns; - hlist_del_rcu(&upid->pid_chain); - switch(--ns->nr_hashed) { - case 2: - case 1: - /* When all that is left in the pid namespace - * is the reaper wake up the reaper. The reaper - * may be sleeping in zap_pid_ns_processes(). - */ - wake_up_process(ns->child_reaper); - break; - case PIDNS_HASH_ADDING: - /* Handle a fork failure of the first process */ - WARN_ON(ns->child_reaper); - ns->nr_hashed = 0; - /* fall through */ - case 0: - schedule_work(&ns->proc_work); - break; - } - } - spin_unlock_irqrestore(&pidmap_lock, flags); - - for (i = 0; i <= pid->level; i++) - free_pidmap(pid->numbers + i); - - call_rcu(&pid->rcu, delayed_put_pid); -} - -struct pid *alloc_pid(struct pid_namespace *ns) -{ - struct pid *pid; - enum pid_type type; - int i, nr; - struct pid_namespace *tmp; - struct upid *upid; - int retval = -ENOMEM; - - pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL); - if (!pid) - return ERR_PTR(retval); - - tmp = ns; - pid->level = ns->level; - for (i = ns->level; i >= 0; i--) { - nr = alloc_pidmap(tmp); - if (nr < 0) { - retval = nr; - goto out_free; - } - - pid->numbers[i].nr = nr; - pid->numbers[i].ns = tmp; - tmp = tmp->parent; - } - - if (unlikely(is_child_reaper(pid))) { - if (pid_ns_prepare_proc(ns)) - goto out_free; - } - - get_pid_ns(ns); - atomic_set(&pid->count, 1); - for (type = 0; type < PIDTYPE_MAX; ++type) - INIT_HLIST_HEAD(&pid->tasks[type]); - - upid = pid->numbers + ns->level; - spin_lock_irq(&pidmap_lock); - if (!(ns->nr_hashed & PIDNS_HASH_ADDING)) - goto out_unlock; - for ( ; upid >= pid->numbers; --upid) { - hlist_add_head_rcu(&upid->pid_chain, - &pid_hash[pid_hashfn(upid->nr, upid->ns)]); - upid->ns->nr_hashed++; - } - spin_unlock_irq(&pidmap_lock); - - return pid; - -out_unlock: - spin_unlock_irq(&pidmap_lock); - put_pid_ns(ns); - -out_free: - while (++i <= ns->level) - free_pidmap(pid->numbers + i); - - kmem_cache_free(ns->pid_cachep, pid); - return ERR_PTR(retval); -} - -void disable_pid_allocation(struct pid_namespace *ns) -{ - spin_lock_irq(&pidmap_lock); - ns->nr_hashed &= ~PIDNS_HASH_ADDING; - spin_unlock_irq(&pidmap_lock); -} - -struct pid *find_pid_ns(int nr, struct pid_namespace *ns) -{ - struct upid *pnr; - - hlist_for_each_entry_rcu(pnr, - &pid_hash[pid_hashfn(nr, ns)], pid_chain) - if (pnr->nr == nr && pnr->ns == ns) - return container_of(pnr, struct pid, - numbers[ns->level]); - - return NULL; -} -EXPORT_SYMBOL_GPL(find_pid_ns); - -struct pid *find_vpid(int nr) -{ - return find_pid_ns(nr, task_active_pid_ns(current)); -} -EXPORT_SYMBOL_GPL(find_vpid); - -/* - * attach_pid() must be called with the tasklist_lock write-held. - */ -void attach_pid(struct task_struct *task, enum pid_type type) -{ - struct pid_link *link = &task->pids[type]; - hlist_add_head_rcu(&link->node, &link->pid->tasks[type]); -} - -static void __change_pid(struct task_struct *task, enum pid_type type, - struct pid *new) -{ - struct pid_link *link; - struct pid *pid; - int tmp; - - link = &task->pids[type]; - pid = link->pid; - - hlist_del_rcu(&link->node); - link->pid = new; - - for (tmp = PIDTYPE_MAX; --tmp >= 0; ) - if (!hlist_empty(&pid->tasks[tmp])) - return; - - free_pid(pid); -} - -void detach_pid(struct task_struct *task, enum pid_type type) -{ - __change_pid(task, type, NULL); -} - -void change_pid(struct task_struct *task, enum pid_type type, - struct pid *pid) -{ - __change_pid(task, type, pid); - attach_pid(task, type); -} - -/* transfer_pid is an optimization of attach_pid(new), detach_pid(old) */ -void transfer_pid(struct task_struct *old, struct task_struct *new, - enum pid_type type) -{ - new->pids[type].pid = old->pids[type].pid; - hlist_replace_rcu(&old->pids[type].node, &new->pids[type].node); -} - -struct task_struct *pid_task(struct pid *pid, enum pid_type type) -{ - struct task_struct *result = NULL; - if (pid) { - struct hlist_node *first; - first = rcu_dereference_check(hlist_first_rcu(&pid->tasks[type]), - lockdep_tasklist_lock_is_held()); - if (first) - result = hlist_entry(first, struct task_struct, pids[(type)].node); - } - return result; -} -EXPORT_SYMBOL(pid_task); - -/* - * Must be called under rcu_read_lock(). - */ -struct task_struct *find_task_by_pid_ns(pid_t nr, struct pid_namespace *ns) -{ - RCU_LOCKDEP_WARN(!rcu_read_lock_held(), - "find_task_by_pid_ns() needs rcu_read_lock() protection"); - return pid_task(find_pid_ns(nr, ns), PIDTYPE_PID); -} - -struct task_struct *find_task_by_vpid(pid_t vnr) -{ - return find_task_by_pid_ns(vnr, task_active_pid_ns(current)); -} - -struct pid *get_task_pid(struct task_struct *task, enum pid_type type) -{ - struct pid *pid; - rcu_read_lock(); - if (type != PIDTYPE_PID) - task = task->group_leader; - pid = get_pid(rcu_dereference(task->pids[type].pid)); - rcu_read_unlock(); - return pid; -} -EXPORT_SYMBOL_GPL(get_task_pid); - -struct task_struct *get_pid_task(struct pid *pid, enum pid_type type) -{ - struct task_struct *result; - rcu_read_lock(); - result = pid_task(pid, type); - if (result) - get_task_struct(result); - rcu_read_unlock(); - return result; -} -EXPORT_SYMBOL_GPL(get_pid_task); - -struct pid *find_get_pid(pid_t nr) -{ - struct pid *pid; - - rcu_read_lock(); - pid = get_pid(find_vpid(nr)); - rcu_read_unlock(); - - return pid; -} -EXPORT_SYMBOL_GPL(find_get_pid); - -pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns) -{ - struct upid *upid; - pid_t nr = 0; - - if (pid && ns->level <= pid->level) { - upid = &pid->numbers[ns->level]; - if (upid->ns == ns) - nr = upid->nr; - } - return nr; -} -EXPORT_SYMBOL_GPL(pid_nr_ns); - -pid_t pid_vnr(struct pid *pid) -{ - return pid_nr_ns(pid, task_active_pid_ns(current)); -} -EXPORT_SYMBOL_GPL(pid_vnr); - -pid_t __task_pid_nr_ns(struct task_struct *task, enum pid_type type, - struct pid_namespace *ns) -{ - pid_t nr = 0; - - rcu_read_lock(); - if (!ns) - ns = task_active_pid_ns(current); - if (likely(pid_alive(task))) { - if (type != PIDTYPE_PID) - task = task->group_leader; - nr = pid_nr_ns(rcu_dereference(task->pids[type].pid), ns); - } - rcu_read_unlock(); - - return nr; -} -EXPORT_SYMBOL(__task_pid_nr_ns); - -pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns) -{ - return pid_nr_ns(task_tgid(tsk), ns); -} -EXPORT_SYMBOL(task_tgid_nr_ns); - -struct pid_namespace *task_active_pid_ns(struct task_struct *tsk) -{ - return ns_of_pid(task_pid(tsk)); -} -EXPORT_SYMBOL_GPL(task_active_pid_ns); - -/* - * Used by proc to find the first pid that is greater than or equal to nr. - * - * If there is a pid at nr this function is exactly the same as find_pid_ns. - */ -struct pid *find_ge_pid(int nr, struct pid_namespace *ns) -{ - struct pid *pid; - - do { - pid = find_pid_ns(nr, ns); - if (pid) - break; - nr = next_pidmap(ns, nr); - } while (nr > 0); - - return pid; -} - -/* - * The pid hash table is scaled according to the amount of memory in the - * machine. From a minimum of 16 slots up to 4096 slots at one gigabyte or - * more. - */ -void __init pidhash_init(void) -{ - unsigned int i, pidhash_size; - - pid_hash = alloc_large_system_hash("PID", sizeof(*pid_hash), 0, 18, - HASH_EARLY | HASH_SMALL, - &pidhash_shift, NULL, - 0, 4096); - pidhash_size = 1U << pidhash_shift; - - for (i = 0; i < pidhash_size; i++) - INIT_HLIST_HEAD(&pid_hash[i]); -} - -void __init pidmap_init(void) -{ - /* Verify no one has done anything silly: */ - BUILD_BUG_ON(PID_MAX_LIMIT >= PIDNS_HASH_ADDING); - - /* bump default and minimum pid_max based on number of cpus */ - pid_max = min(pid_max_max, max_t(int, pid_max, - PIDS_PER_CPU_DEFAULT * num_possible_cpus())); - pid_max_min = max_t(int, pid_max_min, - PIDS_PER_CPU_MIN * num_possible_cpus()); - pr_info("pid_max: default: %u minimum: %u\n", pid_max, pid_max_min); - - init_pid_ns.pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL); - /* Reserve PID 0. We never call free_pidmap(0) */ - set_bit(0, init_pid_ns.pidmap[0].page); - atomic_dec(&init_pid_ns.pidmap[0].nr_free); - - init_pid_ns.pid_cachep = KMEM_CACHE(pid, - SLAB_HWCACHE_ALIGN | SLAB_PANIC | SLAB_ACCOUNT); -} diff --git a/src/linux/kernel/power/Makefile b/src/linux/kernel/power/Makefile deleted file mode 100644 index eb4f717..0000000 --- a/src/linux/kernel/power/Makefile +++ /dev/null @@ -1,16 +0,0 @@ - -ccflags-$(CONFIG_PM_DEBUG) := -DDEBUG - -KASAN_SANITIZE_snapshot.o := n - -obj-y += qos.o -obj-$(CONFIG_PM) += main.o -obj-$(CONFIG_VT_CONSOLE_SLEEP) += console.o -obj-$(CONFIG_FREEZER) += process.o -obj-$(CONFIG_SUSPEND) += suspend.o -obj-$(CONFIG_PM_TEST_SUSPEND) += suspend_test.o -obj-$(CONFIG_HIBERNATION) += hibernate.o snapshot.o swap.o user.o -obj-$(CONFIG_PM_AUTOSLEEP) += autosleep.o -obj-$(CONFIG_PM_WAKELOCKS) += wakelock.o - -obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o diff --git a/src/linux/kernel/power/qos.c b/src/linux/kernel/power/qos.c deleted file mode 100644 index 168ff44..0000000 --- a/src/linux/kernel/power/qos.c +++ /dev/null @@ -1,722 +0,0 @@ -/* - * This module exposes the interface to kernel space for specifying - * QoS dependencies. It provides infrastructure for registration of: - * - * Dependents on a QoS value : register requests - * Watchers of QoS value : get notified when target QoS value changes - * - * This QoS design is best effort based. Dependents register their QoS needs. - * Watchers register to keep track of the current QoS needs of the system. - * - * There are 3 basic classes of QoS parameter: latency, timeout, throughput - * each have defined units: - * latency: usec - * timeout: usec <-- currently not used. - * throughput: kbs (kilo byte / sec) - * - * There are lists of pm_qos_objects each one wrapping requests, notifiers - * - * User mode requests on a QOS parameter register themselves to the - * subsystem by opening the device node /dev/... and writing there request to - * the node. As long as the process holds a file handle open to the node the - * client continues to be accounted for. Upon file release the usermode - * request is removed and a new qos target is computed. This way when the - * request that the application has is cleaned up when closes the file - * pointer or exits the pm_qos_object will get an opportunity to clean up. - * - * Mark Gross - */ - -/*#define DEBUG*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -/* - * locking rule: all changes to constraints or notifiers lists - * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock - * held, taken with _irqsave. One lock to rule them all - */ -struct pm_qos_object { - struct pm_qos_constraints *constraints; - struct miscdevice pm_qos_power_miscdev; - char *name; -}; - -static DEFINE_SPINLOCK(pm_qos_lock); - -static struct pm_qos_object null_pm_qos; - -static BLOCKING_NOTIFIER_HEAD(cpu_dma_lat_notifier); -static struct pm_qos_constraints cpu_dma_constraints = { - .list = PLIST_HEAD_INIT(cpu_dma_constraints.list), - .target_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE, - .default_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE, - .no_constraint_value = PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE, - .type = PM_QOS_MIN, - .notifiers = &cpu_dma_lat_notifier, -}; -static struct pm_qos_object cpu_dma_pm_qos = { - .constraints = &cpu_dma_constraints, - .name = "cpu_dma_latency", -}; - -static BLOCKING_NOTIFIER_HEAD(network_lat_notifier); -static struct pm_qos_constraints network_lat_constraints = { - .list = PLIST_HEAD_INIT(network_lat_constraints.list), - .target_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE, - .default_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE, - .no_constraint_value = PM_QOS_NETWORK_LAT_DEFAULT_VALUE, - .type = PM_QOS_MIN, - .notifiers = &network_lat_notifier, -}; -static struct pm_qos_object network_lat_pm_qos = { - .constraints = &network_lat_constraints, - .name = "network_latency", -}; - - -static BLOCKING_NOTIFIER_HEAD(network_throughput_notifier); -static struct pm_qos_constraints network_tput_constraints = { - .list = PLIST_HEAD_INIT(network_tput_constraints.list), - .target_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE, - .default_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE, - .no_constraint_value = PM_QOS_NETWORK_THROUGHPUT_DEFAULT_VALUE, - .type = PM_QOS_MAX, - .notifiers = &network_throughput_notifier, -}; -static struct pm_qos_object network_throughput_pm_qos = { - .constraints = &network_tput_constraints, - .name = "network_throughput", -}; - - -static BLOCKING_NOTIFIER_HEAD(memory_bandwidth_notifier); -static struct pm_qos_constraints memory_bw_constraints = { - .list = PLIST_HEAD_INIT(memory_bw_constraints.list), - .target_value = PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE, - .default_value = PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE, - .no_constraint_value = PM_QOS_MEMORY_BANDWIDTH_DEFAULT_VALUE, - .type = PM_QOS_SUM, - .notifiers = &memory_bandwidth_notifier, -}; -static struct pm_qos_object memory_bandwidth_pm_qos = { - .constraints = &memory_bw_constraints, - .name = "memory_bandwidth", -}; - - -static struct pm_qos_object *pm_qos_array[] = { - &null_pm_qos, - &cpu_dma_pm_qos, - &network_lat_pm_qos, - &network_throughput_pm_qos, - &memory_bandwidth_pm_qos, -}; - -static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, - size_t count, loff_t *f_pos); -static ssize_t pm_qos_power_read(struct file *filp, char __user *buf, - size_t count, loff_t *f_pos); -static int pm_qos_power_open(struct inode *inode, struct file *filp); -static int pm_qos_power_release(struct inode *inode, struct file *filp); - -static const struct file_operations pm_qos_power_fops = { - .write = pm_qos_power_write, - .read = pm_qos_power_read, - .open = pm_qos_power_open, - .release = pm_qos_power_release, - .llseek = noop_llseek, -}; - -/* unlocked internal variant */ -static inline int pm_qos_get_value(struct pm_qos_constraints *c) -{ - struct plist_node *node; - int total_value = 0; - - if (plist_head_empty(&c->list)) - return c->no_constraint_value; - - switch (c->type) { - case PM_QOS_MIN: - return plist_first(&c->list)->prio; - - case PM_QOS_MAX: - return plist_last(&c->list)->prio; - - case PM_QOS_SUM: - plist_for_each(node, &c->list) - total_value += node->prio; - - return total_value; - - default: - /* runtime check for not using enum */ - BUG(); - return PM_QOS_DEFAULT_VALUE; - } -} - -s32 pm_qos_read_value(struct pm_qos_constraints *c) -{ - return c->target_value; -} - -static inline void pm_qos_set_value(struct pm_qos_constraints *c, s32 value) -{ - c->target_value = value; -} - -static inline int pm_qos_get_value(struct pm_qos_constraints *c); -static int pm_qos_dbg_show_requests(struct seq_file *s, void *unused) -{ - struct pm_qos_object *qos = (struct pm_qos_object *)s->private; - struct pm_qos_constraints *c; - struct pm_qos_request *req; - char *type; - unsigned long flags; - int tot_reqs = 0; - int active_reqs = 0; - - if (IS_ERR_OR_NULL(qos)) { - pr_err("%s: bad qos param!\n", __func__); - return -EINVAL; - } - c = qos->constraints; - if (IS_ERR_OR_NULL(c)) { - pr_err("%s: Bad constraints on qos?\n", __func__); - return -EINVAL; - } - - /* Lock to ensure we have a snapshot */ - spin_lock_irqsave(&pm_qos_lock, flags); - if (plist_head_empty(&c->list)) { - seq_puts(s, "Empty!\n"); - goto out; - } - - switch (c->type) { - case PM_QOS_MIN: - type = "Minimum"; - break; - case PM_QOS_MAX: - type = "Maximum"; - break; - case PM_QOS_SUM: - type = "Sum"; - break; - default: - type = "Unknown"; - } - - plist_for_each_entry(req, &c->list, node) { - char *state = "Default"; - - if ((req->node).prio != c->default_value) { - active_reqs++; - state = "Active"; - } - tot_reqs++; - seq_printf(s, "%d: %d: %s\n", tot_reqs, - (req->node).prio, state); - } - - seq_printf(s, "Type=%s, Value=%d, Requests: active=%d / total=%d\n", - type, pm_qos_get_value(c), active_reqs, tot_reqs); - -out: - spin_unlock_irqrestore(&pm_qos_lock, flags); - return 0; -} - -static int pm_qos_dbg_open(struct inode *inode, struct file *file) -{ - return single_open(file, pm_qos_dbg_show_requests, - inode->i_private); -} - -static const struct file_operations pm_qos_debug_fops = { - .open = pm_qos_dbg_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -/** - * pm_qos_update_target - manages the constraints list and calls the notifiers - * if needed - * @c: constraints data struct - * @node: request to add to the list, to update or to remove - * @action: action to take on the constraints list - * @value: value of the request to add or update - * - * This function returns 1 if the aggregated constraint value has changed, 0 - * otherwise. - */ -int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node, - enum pm_qos_req_action action, int value) -{ - unsigned long flags; - int prev_value, curr_value, new_value; - int ret; - - spin_lock_irqsave(&pm_qos_lock, flags); - prev_value = pm_qos_get_value(c); - if (value == PM_QOS_DEFAULT_VALUE) - new_value = c->default_value; - else - new_value = value; - - switch (action) { - case PM_QOS_REMOVE_REQ: - plist_del(node, &c->list); - break; - case PM_QOS_UPDATE_REQ: - /* - * to change the list, we atomically remove, reinit - * with new value and add, then see if the extremal - * changed - */ - plist_del(node, &c->list); - case PM_QOS_ADD_REQ: - plist_node_init(node, new_value); - plist_add(node, &c->list); - break; - default: - /* no action */ - ; - } - - curr_value = pm_qos_get_value(c); - pm_qos_set_value(c, curr_value); - - spin_unlock_irqrestore(&pm_qos_lock, flags); - - trace_pm_qos_update_target(action, prev_value, curr_value); - if (prev_value != curr_value) { - ret = 1; - if (c->notifiers) - blocking_notifier_call_chain(c->notifiers, - (unsigned long)curr_value, - NULL); - } else { - ret = 0; - } - return ret; -} - -/** - * pm_qos_flags_remove_req - Remove device PM QoS flags request. - * @pqf: Device PM QoS flags set to remove the request from. - * @req: Request to remove from the set. - */ -static void pm_qos_flags_remove_req(struct pm_qos_flags *pqf, - struct pm_qos_flags_request *req) -{ - s32 val = 0; - - list_del(&req->node); - list_for_each_entry(req, &pqf->list, node) - val |= req->flags; - - pqf->effective_flags = val; -} - -/** - * pm_qos_update_flags - Update a set of PM QoS flags. - * @pqf: Set of flags to update. - * @req: Request to add to the set, to modify, or to remove from the set. - * @action: Action to take on the set. - * @val: Value of the request to add or modify. - * - * Update the given set of PM QoS flags and call notifiers if the aggregate - * value has changed. Returns 1 if the aggregate constraint value has changed, - * 0 otherwise. - */ -bool pm_qos_update_flags(struct pm_qos_flags *pqf, - struct pm_qos_flags_request *req, - enum pm_qos_req_action action, s32 val) -{ - unsigned long irqflags; - s32 prev_value, curr_value; - - spin_lock_irqsave(&pm_qos_lock, irqflags); - - prev_value = list_empty(&pqf->list) ? 0 : pqf->effective_flags; - - switch (action) { - case PM_QOS_REMOVE_REQ: - pm_qos_flags_remove_req(pqf, req); - break; - case PM_QOS_UPDATE_REQ: - pm_qos_flags_remove_req(pqf, req); - case PM_QOS_ADD_REQ: - req->flags = val; - INIT_LIST_HEAD(&req->node); - list_add_tail(&req->node, &pqf->list); - pqf->effective_flags |= val; - break; - default: - /* no action */ - ; - } - - curr_value = list_empty(&pqf->list) ? 0 : pqf->effective_flags; - - spin_unlock_irqrestore(&pm_qos_lock, irqflags); - - trace_pm_qos_update_flags(action, prev_value, curr_value); - return prev_value != curr_value; -} - -/** - * pm_qos_request - returns current system wide qos expectation - * @pm_qos_class: identification of which qos value is requested - * - * This function returns the current target value. - */ -int pm_qos_request(int pm_qos_class) -{ - return pm_qos_read_value(pm_qos_array[pm_qos_class]->constraints); -} -EXPORT_SYMBOL_GPL(pm_qos_request); - -int pm_qos_request_active(struct pm_qos_request *req) -{ - return req->pm_qos_class != 0; -} -EXPORT_SYMBOL_GPL(pm_qos_request_active); - -static void __pm_qos_update_request(struct pm_qos_request *req, - s32 new_value) -{ - trace_pm_qos_update_request(req->pm_qos_class, new_value); - - if (new_value != req->node.prio) - pm_qos_update_target( - pm_qos_array[req->pm_qos_class]->constraints, - &req->node, PM_QOS_UPDATE_REQ, new_value); -} - -/** - * pm_qos_work_fn - the timeout handler of pm_qos_update_request_timeout - * @work: work struct for the delayed work (timeout) - * - * This cancels the timeout request by falling back to the default at timeout. - */ -static void pm_qos_work_fn(struct work_struct *work) -{ - struct pm_qos_request *req = container_of(to_delayed_work(work), - struct pm_qos_request, - work); - - __pm_qos_update_request(req, PM_QOS_DEFAULT_VALUE); -} - -/** - * pm_qos_add_request - inserts new qos request into the list - * @req: pointer to a preallocated handle - * @pm_qos_class: identifies which list of qos request to use - * @value: defines the qos request - * - * This function inserts a new entry in the pm_qos_class list of requested qos - * performance characteristics. It recomputes the aggregate QoS expectations - * for the pm_qos_class of parameters and initializes the pm_qos_request - * handle. Caller needs to save this handle for later use in updates and - * removal. - */ - -void pm_qos_add_request(struct pm_qos_request *req, - int pm_qos_class, s32 value) -{ - if (!req) /*guard against callers passing in null */ - return; - - if (pm_qos_request_active(req)) { - WARN(1, KERN_ERR "pm_qos_add_request() called for already added request\n"); - return; - } - req->pm_qos_class = pm_qos_class; - INIT_DELAYED_WORK(&req->work, pm_qos_work_fn); - trace_pm_qos_add_request(pm_qos_class, value); - pm_qos_update_target(pm_qos_array[pm_qos_class]->constraints, - &req->node, PM_QOS_ADD_REQ, value); -} -EXPORT_SYMBOL_GPL(pm_qos_add_request); - -/** - * pm_qos_update_request - modifies an existing qos request - * @req : handle to list element holding a pm_qos request to use - * @value: defines the qos request - * - * Updates an existing qos request for the pm_qos_class of parameters along - * with updating the target pm_qos_class value. - * - * Attempts are made to make this code callable on hot code paths. - */ -void pm_qos_update_request(struct pm_qos_request *req, - s32 new_value) -{ - if (!req) /*guard against callers passing in null */ - return; - - if (!pm_qos_request_active(req)) { - WARN(1, KERN_ERR "pm_qos_update_request() called for unknown object\n"); - return; - } - - /* - * This function may be called very early during boot, for example, - * from of_clk_init(), where irq needs to stay disabled. - * cancel_delayed_work_sync() assumes that irq is enabled on - * invocation and re-enables it on return. Avoid calling it until - * workqueue is initialized. - */ - if (keventd_up()) - cancel_delayed_work_sync(&req->work); - - __pm_qos_update_request(req, new_value); -} -EXPORT_SYMBOL_GPL(pm_qos_update_request); - -/** - * pm_qos_update_request_timeout - modifies an existing qos request temporarily. - * @req : handle to list element holding a pm_qos request to use - * @new_value: defines the temporal qos request - * @timeout_us: the effective duration of this qos request in usecs. - * - * After timeout_us, this qos request is cancelled automatically. - */ -void pm_qos_update_request_timeout(struct pm_qos_request *req, s32 new_value, - unsigned long timeout_us) -{ - if (!req) - return; - if (WARN(!pm_qos_request_active(req), - "%s called for unknown object.", __func__)) - return; - - cancel_delayed_work_sync(&req->work); - - trace_pm_qos_update_request_timeout(req->pm_qos_class, - new_value, timeout_us); - if (new_value != req->node.prio) - pm_qos_update_target( - pm_qos_array[req->pm_qos_class]->constraints, - &req->node, PM_QOS_UPDATE_REQ, new_value); - - schedule_delayed_work(&req->work, usecs_to_jiffies(timeout_us)); -} - -/** - * pm_qos_remove_request - modifies an existing qos request - * @req: handle to request list element - * - * Will remove pm qos request from the list of constraints and - * recompute the current target value for the pm_qos_class. Call this - * on slow code paths. - */ -void pm_qos_remove_request(struct pm_qos_request *req) -{ - if (!req) /*guard against callers passing in null */ - return; - /* silent return to keep pcm code cleaner */ - - if (!pm_qos_request_active(req)) { - WARN(1, KERN_ERR "pm_qos_remove_request() called for unknown object\n"); - return; - } - - cancel_delayed_work_sync(&req->work); - - trace_pm_qos_remove_request(req->pm_qos_class, PM_QOS_DEFAULT_VALUE); - pm_qos_update_target(pm_qos_array[req->pm_qos_class]->constraints, - &req->node, PM_QOS_REMOVE_REQ, - PM_QOS_DEFAULT_VALUE); - memset(req, 0, sizeof(*req)); -} -EXPORT_SYMBOL_GPL(pm_qos_remove_request); - -/** - * pm_qos_add_notifier - sets notification entry for changes to target value - * @pm_qos_class: identifies which qos target changes should be notified. - * @notifier: notifier block managed by caller. - * - * will register the notifier into a notification chain that gets called - * upon changes to the pm_qos_class target value. - */ -int pm_qos_add_notifier(int pm_qos_class, struct notifier_block *notifier) -{ - int retval; - - retval = blocking_notifier_chain_register( - pm_qos_array[pm_qos_class]->constraints->notifiers, - notifier); - - return retval; -} -EXPORT_SYMBOL_GPL(pm_qos_add_notifier); - -/** - * pm_qos_remove_notifier - deletes notification entry from chain. - * @pm_qos_class: identifies which qos target changes are notified. - * @notifier: notifier block to be removed. - * - * will remove the notifier from the notification chain that gets called - * upon changes to the pm_qos_class target value. - */ -int pm_qos_remove_notifier(int pm_qos_class, struct notifier_block *notifier) -{ - int retval; - - retval = blocking_notifier_chain_unregister( - pm_qos_array[pm_qos_class]->constraints->notifiers, - notifier); - - return retval; -} -EXPORT_SYMBOL_GPL(pm_qos_remove_notifier); - -/* User space interface to PM QoS classes via misc devices */ -static int register_pm_qos_misc(struct pm_qos_object *qos, struct dentry *d) -{ - qos->pm_qos_power_miscdev.minor = MISC_DYNAMIC_MINOR; - qos->pm_qos_power_miscdev.name = qos->name; - qos->pm_qos_power_miscdev.fops = &pm_qos_power_fops; - - if (d) { - (void)debugfs_create_file(qos->name, S_IRUGO, d, - (void *)qos, &pm_qos_debug_fops); - } - - return misc_register(&qos->pm_qos_power_miscdev); -} - -static int find_pm_qos_object_by_minor(int minor) -{ - int pm_qos_class; - - for (pm_qos_class = PM_QOS_CPU_DMA_LATENCY; - pm_qos_class < PM_QOS_NUM_CLASSES; pm_qos_class++) { - if (minor == - pm_qos_array[pm_qos_class]->pm_qos_power_miscdev.minor) - return pm_qos_class; - } - return -1; -} - -static int pm_qos_power_open(struct inode *inode, struct file *filp) -{ - long pm_qos_class; - - pm_qos_class = find_pm_qos_object_by_minor(iminor(inode)); - if (pm_qos_class >= PM_QOS_CPU_DMA_LATENCY) { - struct pm_qos_request *req = kzalloc(sizeof(*req), GFP_KERNEL); - if (!req) - return -ENOMEM; - - pm_qos_add_request(req, pm_qos_class, PM_QOS_DEFAULT_VALUE); - filp->private_data = req; - - return 0; - } - return -EPERM; -} - -static int pm_qos_power_release(struct inode *inode, struct file *filp) -{ - struct pm_qos_request *req; - - req = filp->private_data; - pm_qos_remove_request(req); - kfree(req); - - return 0; -} - - -static ssize_t pm_qos_power_read(struct file *filp, char __user *buf, - size_t count, loff_t *f_pos) -{ - s32 value; - unsigned long flags; - struct pm_qos_request *req = filp->private_data; - - if (!req) - return -EINVAL; - if (!pm_qos_request_active(req)) - return -EINVAL; - - spin_lock_irqsave(&pm_qos_lock, flags); - value = pm_qos_get_value(pm_qos_array[req->pm_qos_class]->constraints); - spin_unlock_irqrestore(&pm_qos_lock, flags); - - return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32)); -} - -static ssize_t pm_qos_power_write(struct file *filp, const char __user *buf, - size_t count, loff_t *f_pos) -{ - s32 value; - struct pm_qos_request *req; - - if (count == sizeof(s32)) { - if (copy_from_user(&value, buf, sizeof(s32))) - return -EFAULT; - } else { - int ret; - - ret = kstrtos32_from_user(buf, count, 16, &value); - if (ret) - return ret; - } - - req = filp->private_data; - pm_qos_update_request(req, value); - - return count; -} - - -static int __init pm_qos_power_init(void) -{ - int ret = 0; - int i; - struct dentry *d; - - BUILD_BUG_ON(ARRAY_SIZE(pm_qos_array) != PM_QOS_NUM_CLASSES); - - d = debugfs_create_dir("pm_qos", NULL); - if (IS_ERR_OR_NULL(d)) - d = NULL; - - for (i = PM_QOS_CPU_DMA_LATENCY; i < PM_QOS_NUM_CLASSES; i++) { - ret = register_pm_qos_misc(pm_qos_array[i], d); - if (ret < 0) { - printk(KERN_ERR "pm_qos_param: %s setup failed\n", - pm_qos_array[i]->name); - return ret; - } - } - - return ret; -} - -late_initcall(pm_qos_power_init); diff --git a/src/linux/kernel/printk/Makefile b/src/linux/kernel/printk/Makefile deleted file mode 100644 index abb0042..0000000 --- a/src/linux/kernel/printk/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-y = printk.o -obj-$(CONFIG_PRINTK_NMI) += nmi.o -obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o diff --git a/src/linux/kernel/printk/braille.h b/src/linux/kernel/printk/braille.h deleted file mode 100644 index 769d771..0000000 --- a/src/linux/kernel/printk/braille.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef _PRINTK_BRAILLE_H -#define _PRINTK_BRAILLE_H - -#ifdef CONFIG_A11Y_BRAILLE_CONSOLE - -static inline void -braille_set_options(struct console_cmdline *c, char *brl_options) -{ - c->brl_options = brl_options; -} - -char * -_braille_console_setup(char **str, char **brl_options); - -int -_braille_register_console(struct console *console, struct console_cmdline *c); - -int -_braille_unregister_console(struct console *console); - -#else - -static inline void -braille_set_options(struct console_cmdline *c, char *brl_options) -{ -} - -static inline char * -_braille_console_setup(char **str, char **brl_options) -{ - return NULL; -} - -static inline int -_braille_register_console(struct console *console, struct console_cmdline *c) -{ - return 0; -} - -static inline int -_braille_unregister_console(struct console *console) -{ - return 0; -} - -#endif - -#endif diff --git a/src/linux/kernel/printk/console_cmdline.h b/src/linux/kernel/printk/console_cmdline.h deleted file mode 100644 index 2ca4a8b..0000000 --- a/src/linux/kernel/printk/console_cmdline.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _CONSOLE_CMDLINE_H -#define _CONSOLE_CMDLINE_H - -struct console_cmdline -{ - char name[16]; /* Name of the driver */ - int index; /* Minor dev. to use */ - char *options; /* Options for the driver */ -#ifdef CONFIG_A11Y_BRAILLE_CONSOLE - char *brl_options; /* Options for braille driver */ -#endif -}; - -#endif diff --git a/src/linux/kernel/printk/internal.h b/src/linux/kernel/printk/internal.h deleted file mode 100644 index 7fd2838..0000000 --- a/src/linux/kernel/printk/internal.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * internal.h - printk internal definitions - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - */ -#include - -typedef __printf(1, 0) int (*printk_func_t)(const char *fmt, va_list args); - -int __printf(1, 0) vprintk_default(const char *fmt, va_list args); - -#ifdef CONFIG_PRINTK_NMI - -extern raw_spinlock_t logbuf_lock; - -/* - * printk() could not take logbuf_lock in NMI context. Instead, - * it temporary stores the strings into a per-CPU buffer. - * The alternative implementation is chosen transparently - * via per-CPU variable. - */ -DECLARE_PER_CPU(printk_func_t, printk_func); -static inline __printf(1, 0) int vprintk_func(const char *fmt, va_list args) -{ - return this_cpu_read(printk_func)(fmt, args); -} - -extern atomic_t nmi_message_lost; -static inline int get_nmi_message_lost(void) -{ - return atomic_xchg(&nmi_message_lost, 0); -} - -#else /* CONFIG_PRINTK_NMI */ - -static inline __printf(1, 0) int vprintk_func(const char *fmt, va_list args) -{ - return vprintk_default(fmt, args); -} - -static inline int get_nmi_message_lost(void) -{ - return 0; -} - -#endif /* CONFIG_PRINTK_NMI */ diff --git a/src/linux/kernel/printk/printk.c b/src/linux/kernel/printk/printk.c deleted file mode 100644 index f7a55e9..0000000 --- a/src/linux/kernel/printk/printk.c +++ /dev/null @@ -1,3313 +0,0 @@ -/* - * linux/kernel/printk.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * Modified to make sys_syslog() more flexible: added commands to - * return the last 4k of kernel messages, regardless of whether - * they've been read or not. Added option to suppress kernel printk's - * to the console. Added hook for sending the console messages - * elsewhere, in preparation for a serial line console (someday). - * Ted Ts'o, 2/11/93. - * Modified for sysctl support, 1/8/97, Chris Horn. - * Fixed SMP synchronization, 08/08/99, Manfred Spraul - * manfred@colorfullife.com - * Rewrote bits to get rid of console_lock - * 01Mar01 Andrew Morton - */ - -#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 -#include - -#include -#include - -#define CREATE_TRACE_POINTS -#include - -#include "console_cmdline.h" -#include "braille.h" -#include "internal.h" - -int console_printk[4] = { - CONSOLE_LOGLEVEL_DEFAULT, /* console_loglevel */ - MESSAGE_LOGLEVEL_DEFAULT, /* default_message_loglevel */ - CONSOLE_LOGLEVEL_MIN, /* minimum_console_loglevel */ - CONSOLE_LOGLEVEL_DEFAULT, /* default_console_loglevel */ -}; - -/* - * Low level drivers may need that to know if they can schedule in - * their unblank() callback or not. So let's export it. - */ -int oops_in_progress; -EXPORT_SYMBOL(oops_in_progress); - -/* - * console_sem protects the console_drivers list, and also - * provides serialisation for access to the entire console - * driver system. - */ -static DEFINE_SEMAPHORE(console_sem); -struct console *console_drivers; -EXPORT_SYMBOL_GPL(console_drivers); - -#ifdef CONFIG_LOCKDEP -static struct lockdep_map console_lock_dep_map = { - .name = "console_lock" -}; -#endif - -enum devkmsg_log_bits { - __DEVKMSG_LOG_BIT_ON = 0, - __DEVKMSG_LOG_BIT_OFF, - __DEVKMSG_LOG_BIT_LOCK, -}; - -enum devkmsg_log_masks { - DEVKMSG_LOG_MASK_ON = BIT(__DEVKMSG_LOG_BIT_ON), - DEVKMSG_LOG_MASK_OFF = BIT(__DEVKMSG_LOG_BIT_OFF), - DEVKMSG_LOG_MASK_LOCK = BIT(__DEVKMSG_LOG_BIT_LOCK), -}; - -/* Keep both the 'on' and 'off' bits clear, i.e. ratelimit by default: */ -#define DEVKMSG_LOG_MASK_DEFAULT 0 - -static unsigned int __read_mostly devkmsg_log = DEVKMSG_LOG_MASK_DEFAULT; - -static int __control_devkmsg(char *str) -{ - if (!str) - return -EINVAL; - - if (!strncmp(str, "on", 2)) { - devkmsg_log = DEVKMSG_LOG_MASK_ON; - return 2; - } else if (!strncmp(str, "off", 3)) { - devkmsg_log = DEVKMSG_LOG_MASK_OFF; - return 3; - } else if (!strncmp(str, "ratelimit", 9)) { - devkmsg_log = DEVKMSG_LOG_MASK_DEFAULT; - return 9; - } - return -EINVAL; -} - -static int __init control_devkmsg(char *str) -{ - if (__control_devkmsg(str) < 0) - return 1; - - /* - * Set sysctl string accordingly: - */ - if (devkmsg_log == DEVKMSG_LOG_MASK_ON) { - memset(devkmsg_log_str, 0, DEVKMSG_STR_MAX_SIZE); - strncpy(devkmsg_log_str, "on", 2); - } else if (devkmsg_log == DEVKMSG_LOG_MASK_OFF) { - memset(devkmsg_log_str, 0, DEVKMSG_STR_MAX_SIZE); - strncpy(devkmsg_log_str, "off", 3); - } - /* else "ratelimit" which is set by default. */ - - /* - * Sysctl cannot change it anymore. The kernel command line setting of - * this parameter is to force the setting to be permanent throughout the - * runtime of the system. This is a precation measure against userspace - * trying to be a smarta** and attempting to change it up on us. - */ - devkmsg_log |= DEVKMSG_LOG_MASK_LOCK; - - return 0; -} -__setup("printk.devkmsg=", control_devkmsg); - -char devkmsg_log_str[DEVKMSG_STR_MAX_SIZE] = "ratelimit"; - -int devkmsg_sysctl_set_loglvl(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - char old_str[DEVKMSG_STR_MAX_SIZE]; - unsigned int old; - int err; - - if (write) { - if (devkmsg_log & DEVKMSG_LOG_MASK_LOCK) - return -EINVAL; - - old = devkmsg_log; - strncpy(old_str, devkmsg_log_str, DEVKMSG_STR_MAX_SIZE); - } - - err = proc_dostring(table, write, buffer, lenp, ppos); - if (err) - return err; - - if (write) { - err = __control_devkmsg(devkmsg_log_str); - - /* - * Do not accept an unknown string OR a known string with - * trailing crap... - */ - if (err < 0 || (err + 1 != *lenp)) { - - /* ... and restore old setting. */ - devkmsg_log = old; - strncpy(devkmsg_log_str, old_str, DEVKMSG_STR_MAX_SIZE); - - return -EINVAL; - } - } - - return 0; -} - -/* - * Number of registered extended console drivers. - * - * If extended consoles are present, in-kernel cont reassembly is disabled - * and each fragment is stored as a separate log entry with proper - * continuation flag so that every emitted message has full metadata. This - * doesn't change the result for regular consoles or /proc/kmsg. For - * /dev/kmsg, as long as the reader concatenates messages according to - * consecutive continuation flags, the end result should be the same too. - */ -static int nr_ext_console_drivers; - -/* - * Helper macros to handle lockdep when locking/unlocking console_sem. We use - * macros instead of functions so that _RET_IP_ contains useful information. - */ -#define down_console_sem() do { \ - down(&console_sem);\ - mutex_acquire(&console_lock_dep_map, 0, 0, _RET_IP_);\ -} while (0) - -static int __down_trylock_console_sem(unsigned long ip) -{ - if (down_trylock(&console_sem)) - return 1; - mutex_acquire(&console_lock_dep_map, 0, 1, ip); - return 0; -} -#define down_trylock_console_sem() __down_trylock_console_sem(_RET_IP_) - -#define up_console_sem() do { \ - mutex_release(&console_lock_dep_map, 1, _RET_IP_);\ - up(&console_sem);\ -} while (0) - -/* - * This is used for debugging the mess that is the VT code by - * keeping track if we have the console semaphore held. It's - * definitely not the perfect debug tool (we don't know if _WE_ - * hold it and are racing, but it helps tracking those weird code - * paths in the console code where we end up in places I want - * locked without the console sempahore held). - */ -static int console_locked, console_suspended; - -/* - * If exclusive_console is non-NULL then only this console is to be printed to. - */ -static struct console *exclusive_console; - -/* - * Array of consoles built from command line options (console=) - */ - -#define MAX_CMDLINECONSOLES 8 - -static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES]; - -static int selected_console = -1; -static int preferred_console = -1; -int console_set_on_cmdline; -EXPORT_SYMBOL(console_set_on_cmdline); - -/* Flag: console code may call schedule() */ -static int console_may_schedule; - -/* - * The printk log buffer consists of a chain of concatenated variable - * length records. Every record starts with a record header, containing - * the overall length of the record. - * - * The heads to the first and last entry in the buffer, as well as the - * sequence numbers of these entries are maintained when messages are - * stored. - * - * If the heads indicate available messages, the length in the header - * tells the start next message. A length == 0 for the next message - * indicates a wrap-around to the beginning of the buffer. - * - * Every record carries the monotonic timestamp in microseconds, as well as - * the standard userspace syslog level and syslog facility. The usual - * kernel messages use LOG_KERN; userspace-injected messages always carry - * a matching syslog facility, by default LOG_USER. The origin of every - * message can be reliably determined that way. - * - * The human readable log message directly follows the message header. The - * length of the message text is stored in the header, the stored message - * is not terminated. - * - * Optionally, a message can carry a dictionary of properties (key/value pairs), - * to provide userspace with a machine-readable message context. - * - * Examples for well-defined, commonly used property names are: - * DEVICE=b12:8 device identifier - * b12:8 block dev_t - * c127:3 char dev_t - * n8 netdev ifindex - * +sound:card0 subsystem:devname - * SUBSYSTEM=pci driver-core subsystem name - * - * Valid characters in property names are [a-zA-Z0-9.-_]. The plain text value - * follows directly after a '=' character. Every property is terminated by - * a '\0' character. The last property is not terminated. - * - * Example of a message structure: - * 0000 ff 8f 00 00 00 00 00 00 monotonic time in nsec - * 0008 34 00 record is 52 bytes long - * 000a 0b 00 text is 11 bytes long - * 000c 1f 00 dictionary is 23 bytes long - * 000e 03 00 LOG_KERN (facility) LOG_ERR (level) - * 0010 69 74 27 73 20 61 20 6c "it's a l" - * 69 6e 65 "ine" - * 001b 44 45 56 49 43 "DEVIC" - * 45 3d 62 38 3a 32 00 44 "E=b8:2\0D" - * 52 49 56 45 52 3d 62 75 "RIVER=bu" - * 67 "g" - * 0032 00 00 00 padding to next message header - * - * The 'struct printk_log' buffer header must never be directly exported to - * userspace, it is a kernel-private implementation detail that might - * need to be changed in the future, when the requirements change. - * - * /dev/kmsg exports the structured data in the following line format: - * ",,,[,additional_values, ... ];\n" - * - * Users of the export format should ignore possible additional values - * separated by ',', and find the message after the ';' character. - * - * The optional key/value pairs are attached as continuation lines starting - * with a space character and terminated by a newline. All possible - * non-prinatable characters are escaped in the "\xff" notation. - */ - -enum log_flags { - LOG_NOCONS = 1, /* already flushed, do not print to console */ - LOG_NEWLINE = 2, /* text ended with a newline */ - LOG_PREFIX = 4, /* text started with a prefix */ - LOG_CONT = 8, /* text is a fragment of a continuation line */ -}; - -struct printk_log { - u64 ts_nsec; /* timestamp in nanoseconds */ - u16 len; /* length of entire record */ - u16 text_len; /* length of text buffer */ - u16 dict_len; /* length of dictionary buffer */ - u8 facility; /* syslog facility */ - u8 flags:5; /* internal record flags */ - u8 level:3; /* syslog level */ -} -#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS -__packed __aligned(4) -#endif -; - -/* - * The logbuf_lock protects kmsg buffer, indices, counters. This can be taken - * within the scheduler's rq lock. It must be released before calling - * console_unlock() or anything else that might wake up a process. - */ -DEFINE_RAW_SPINLOCK(logbuf_lock); - -#ifdef CONFIG_PRINTK -DECLARE_WAIT_QUEUE_HEAD(log_wait); -/* the next printk record to read by syslog(READ) or /proc/kmsg */ -static u64 syslog_seq; -static u32 syslog_idx; -static enum log_flags syslog_prev; -static size_t syslog_partial; - -/* index and sequence number of the first record stored in the buffer */ -static u64 log_first_seq; -static u32 log_first_idx; - -/* index and sequence number of the next record to store in the buffer */ -static u64 log_next_seq; -static u32 log_next_idx; - -/* the next printk record to write to the console */ -static u64 console_seq; -static u32 console_idx; -static enum log_flags console_prev; - -/* the next printk record to read after the last 'clear' command */ -static u64 clear_seq; -static u32 clear_idx; - -#define PREFIX_MAX 32 -#define LOG_LINE_MAX (1024 - PREFIX_MAX) - -#define LOG_LEVEL(v) ((v) & 0x07) -#define LOG_FACILITY(v) ((v) >> 3 & 0xff) - -/* record buffer */ -#define LOG_ALIGN __alignof__(struct printk_log) -#define __LOG_BUF_LEN (1 << CONFIG_LOG_BUF_SHIFT) -static char __log_buf[__LOG_BUF_LEN] __aligned(LOG_ALIGN); -static char *log_buf = __log_buf; -static u32 log_buf_len = __LOG_BUF_LEN; - -/* Return log buffer address */ -char *log_buf_addr_get(void) -{ - return log_buf; -} - -/* Return log buffer size */ -u32 log_buf_len_get(void) -{ - return log_buf_len; -} - -/* human readable text of the record */ -static char *log_text(const struct printk_log *msg) -{ - return (char *)msg + sizeof(struct printk_log); -} - -/* optional key/value pair dictionary attached to the record */ -static char *log_dict(const struct printk_log *msg) -{ - return (char *)msg + sizeof(struct printk_log) + msg->text_len; -} - -/* get record by index; idx must point to valid msg */ -static struct printk_log *log_from_idx(u32 idx) -{ - struct printk_log *msg = (struct printk_log *)(log_buf + idx); - - /* - * A length == 0 record is the end of buffer marker. Wrap around and - * read the message at the start of the buffer. - */ - if (!msg->len) - return (struct printk_log *)log_buf; - return msg; -} - -/* get next record; idx must point to valid msg */ -static u32 log_next(u32 idx) -{ - struct printk_log *msg = (struct printk_log *)(log_buf + idx); - - /* length == 0 indicates the end of the buffer; wrap */ - /* - * A length == 0 record is the end of buffer marker. Wrap around and - * read the message at the start of the buffer as *this* one, and - * return the one after that. - */ - if (!msg->len) { - msg = (struct printk_log *)log_buf; - return msg->len; - } - return idx + msg->len; -} - -/* - * Check whether there is enough free space for the given message. - * - * The same values of first_idx and next_idx mean that the buffer - * is either empty or full. - * - * If the buffer is empty, we must respect the position of the indexes. - * They cannot be reset to the beginning of the buffer. - */ -static int logbuf_has_space(u32 msg_size, bool empty) -{ - u32 free; - - if (log_next_idx > log_first_idx || empty) - free = max(log_buf_len - log_next_idx, log_first_idx); - else - free = log_first_idx - log_next_idx; - - /* - * We need space also for an empty header that signalizes wrapping - * of the buffer. - */ - return free >= msg_size + sizeof(struct printk_log); -} - -static int log_make_free_space(u32 msg_size) -{ - while (log_first_seq < log_next_seq && - !logbuf_has_space(msg_size, false)) { - /* drop old messages until we have enough contiguous space */ - log_first_idx = log_next(log_first_idx); - log_first_seq++; - } - - if (clear_seq < log_first_seq) { - clear_seq = log_first_seq; - clear_idx = log_first_idx; - } - - /* sequence numbers are equal, so the log buffer is empty */ - if (logbuf_has_space(msg_size, log_first_seq == log_next_seq)) - return 0; - - return -ENOMEM; -} - -/* compute the message size including the padding bytes */ -static u32 msg_used_size(u16 text_len, u16 dict_len, u32 *pad_len) -{ - u32 size; - - size = sizeof(struct printk_log) + text_len + dict_len; - *pad_len = (-size) & (LOG_ALIGN - 1); - size += *pad_len; - - return size; -} - -/* - * Define how much of the log buffer we could take at maximum. The value - * must be greater than two. Note that only half of the buffer is available - * when the index points to the middle. - */ -#define MAX_LOG_TAKE_PART 4 -static const char trunc_msg[] = ""; - -static u32 truncate_msg(u16 *text_len, u16 *trunc_msg_len, - u16 *dict_len, u32 *pad_len) -{ - /* - * The message should not take the whole buffer. Otherwise, it might - * get removed too soon. - */ - u32 max_text_len = log_buf_len / MAX_LOG_TAKE_PART; - if (*text_len > max_text_len) - *text_len = max_text_len; - /* enable the warning message */ - *trunc_msg_len = strlen(trunc_msg); - /* disable the "dict" completely */ - *dict_len = 0; - /* compute the size again, count also the warning message */ - return msg_used_size(*text_len + *trunc_msg_len, 0, pad_len); -} - -/* insert record into the buffer, discard old ones, update heads */ -static int log_store(int facility, int level, - enum log_flags flags, u64 ts_nsec, - const char *dict, u16 dict_len, - const char *text, u16 text_len) -{ - struct printk_log *msg; - u32 size, pad_len; - u16 trunc_msg_len = 0; - - /* number of '\0' padding bytes to next message */ - size = msg_used_size(text_len, dict_len, &pad_len); - - if (log_make_free_space(size)) { - /* truncate the message if it is too long for empty buffer */ - size = truncate_msg(&text_len, &trunc_msg_len, - &dict_len, &pad_len); - /* survive when the log buffer is too small for trunc_msg */ - if (log_make_free_space(size)) - return 0; - } - - if (log_next_idx + size + sizeof(struct printk_log) > log_buf_len) { - /* - * This message + an additional empty header does not fit - * at the end of the buffer. Add an empty header with len == 0 - * to signify a wrap around. - */ - memset(log_buf + log_next_idx, 0, sizeof(struct printk_log)); - log_next_idx = 0; - } - - /* fill message */ - msg = (struct printk_log *)(log_buf + log_next_idx); - memcpy(log_text(msg), text, text_len); - msg->text_len = text_len; - if (trunc_msg_len) { - memcpy(log_text(msg) + text_len, trunc_msg, trunc_msg_len); - msg->text_len += trunc_msg_len; - } - memcpy(log_dict(msg), dict, dict_len); - msg->dict_len = dict_len; - msg->facility = facility; - msg->level = level & 7; - msg->flags = flags & 0x1f; - if (ts_nsec > 0) - msg->ts_nsec = ts_nsec; - else - msg->ts_nsec = local_clock(); - memset(log_dict(msg) + dict_len, 0, pad_len); - msg->len = size; - - /* insert message */ - log_next_idx += msg->len; - log_next_seq++; - - return msg->text_len; -} - -int dmesg_restrict = IS_ENABLED(CONFIG_SECURITY_DMESG_RESTRICT); - -static int syslog_action_restricted(int type) -{ - if (dmesg_restrict) - return 1; - /* - * Unless restricted, we allow "read all" and "get buffer size" - * for everybody. - */ - return type != SYSLOG_ACTION_READ_ALL && - type != SYSLOG_ACTION_SIZE_BUFFER; -} - -int check_syslog_permissions(int type, int source) -{ - /* - * If this is from /proc/kmsg and we've already opened it, then we've - * already done the capabilities checks at open time. - */ - if (source == SYSLOG_FROM_PROC && type != SYSLOG_ACTION_OPEN) - goto ok; - - if (syslog_action_restricted(type)) { - if (capable(CAP_SYSLOG)) - goto ok; - /* - * For historical reasons, accept CAP_SYS_ADMIN too, with - * a warning. - */ - if (capable(CAP_SYS_ADMIN)) { - pr_warn_once("%s (%d): Attempt to access syslog with " - "CAP_SYS_ADMIN but no CAP_SYSLOG " - "(deprecated).\n", - current->comm, task_pid_nr(current)); - goto ok; - } - return -EPERM; - } -ok: - return security_syslog(type); -} -EXPORT_SYMBOL_GPL(check_syslog_permissions); - -static void append_char(char **pp, char *e, char c) -{ - if (*pp < e) - *(*pp)++ = c; -} - -static ssize_t msg_print_ext_header(char *buf, size_t size, - struct printk_log *msg, u64 seq, - enum log_flags prev_flags) -{ - u64 ts_usec = msg->ts_nsec; - char cont = '-'; - - do_div(ts_usec, 1000); - - /* - * If we couldn't merge continuation line fragments during the print, - * export the stored flags to allow an optional external merge of the - * records. Merging the records isn't always neccessarily correct, like - * when we hit a race during printing. In most cases though, it produces - * better readable output. 'c' in the record flags mark the first - * fragment of a line, '+' the following. - */ - if (msg->flags & LOG_CONT) - cont = (prev_flags & LOG_CONT) ? '+' : 'c'; - - return scnprintf(buf, size, "%u,%llu,%llu,%c;", - (msg->facility << 3) | msg->level, seq, ts_usec, cont); -} - -static ssize_t msg_print_ext_body(char *buf, size_t size, - char *dict, size_t dict_len, - char *text, size_t text_len) -{ - char *p = buf, *e = buf + size; - size_t i; - - /* escape non-printable characters */ - for (i = 0; i < text_len; i++) { - unsigned char c = text[i]; - - if (c < ' ' || c >= 127 || c == '\\') - p += scnprintf(p, e - p, "\\x%02x", c); - else - append_char(&p, e, c); - } - append_char(&p, e, '\n'); - - if (dict_len) { - bool line = true; - - for (i = 0; i < dict_len; i++) { - unsigned char c = dict[i]; - - if (line) { - append_char(&p, e, ' '); - line = false; - } - - if (c == '\0') { - append_char(&p, e, '\n'); - line = true; - continue; - } - - if (c < ' ' || c >= 127 || c == '\\') { - p += scnprintf(p, e - p, "\\x%02x", c); - continue; - } - - append_char(&p, e, c); - } - append_char(&p, e, '\n'); - } - - return p - buf; -} - -/* /dev/kmsg - userspace message inject/listen interface */ -struct devkmsg_user { - u64 seq; - u32 idx; - enum log_flags prev; - struct ratelimit_state rs; - struct mutex lock; - char buf[CONSOLE_EXT_LOG_MAX]; -}; - -static ssize_t devkmsg_write(struct kiocb *iocb, struct iov_iter *from) -{ - char *buf, *line; - int level = default_message_loglevel; - int facility = 1; /* LOG_USER */ - struct file *file = iocb->ki_filp; - struct devkmsg_user *user = file->private_data; - size_t len = iov_iter_count(from); - ssize_t ret = len; - - if (!user || len > LOG_LINE_MAX) - return -EINVAL; - - /* Ignore when user logging is disabled. */ - if (devkmsg_log & DEVKMSG_LOG_MASK_OFF) - return len; - - /* Ratelimit when not explicitly enabled. */ - if (!(devkmsg_log & DEVKMSG_LOG_MASK_ON)) { - if (!___ratelimit(&user->rs, current->comm)) - return ret; - } - - buf = kmalloc(len+1, GFP_KERNEL); - if (buf == NULL) - return -ENOMEM; - - buf[len] = '\0'; - if (copy_from_iter(buf, len, from) != len) { - kfree(buf); - return -EFAULT; - } - - /* - * Extract and skip the syslog prefix <[0-9]*>. Coming from userspace - * the decimal value represents 32bit, the lower 3 bit are the log - * level, the rest are the log facility. - * - * If no prefix or no userspace facility is specified, we - * enforce LOG_USER, to be able to reliably distinguish - * kernel-generated messages from userspace-injected ones. - */ - line = buf; - if (line[0] == '<') { - char *endp = NULL; - unsigned int u; - - u = simple_strtoul(line + 1, &endp, 10); - if (endp && endp[0] == '>') { - level = LOG_LEVEL(u); - if (LOG_FACILITY(u) != 0) - facility = LOG_FACILITY(u); - endp++; - len -= endp - line; - line = endp; - } - } - - printk_emit(facility, level, NULL, 0, "%s", line); - kfree(buf); - return ret; -} - -static ssize_t devkmsg_read(struct file *file, char __user *buf, - size_t count, loff_t *ppos) -{ - struct devkmsg_user *user = file->private_data; - struct printk_log *msg; - size_t len; - ssize_t ret; - - if (!user) - return -EBADF; - - ret = mutex_lock_interruptible(&user->lock); - if (ret) - return ret; - raw_spin_lock_irq(&logbuf_lock); - while (user->seq == log_next_seq) { - if (file->f_flags & O_NONBLOCK) { - ret = -EAGAIN; - raw_spin_unlock_irq(&logbuf_lock); - goto out; - } - - raw_spin_unlock_irq(&logbuf_lock); - ret = wait_event_interruptible(log_wait, - user->seq != log_next_seq); - if (ret) - goto out; - raw_spin_lock_irq(&logbuf_lock); - } - - if (user->seq < log_first_seq) { - /* our last seen message is gone, return error and reset */ - user->idx = log_first_idx; - user->seq = log_first_seq; - ret = -EPIPE; - raw_spin_unlock_irq(&logbuf_lock); - goto out; - } - - msg = log_from_idx(user->idx); - len = msg_print_ext_header(user->buf, sizeof(user->buf), - msg, user->seq, user->prev); - len += msg_print_ext_body(user->buf + len, sizeof(user->buf) - len, - log_dict(msg), msg->dict_len, - log_text(msg), msg->text_len); - - user->prev = msg->flags; - user->idx = log_next(user->idx); - user->seq++; - raw_spin_unlock_irq(&logbuf_lock); - - if (len > count) { - ret = -EINVAL; - goto out; - } - - if (copy_to_user(buf, user->buf, len)) { - ret = -EFAULT; - goto out; - } - ret = len; -out: - mutex_unlock(&user->lock); - return ret; -} - -static loff_t devkmsg_llseek(struct file *file, loff_t offset, int whence) -{ - struct devkmsg_user *user = file->private_data; - loff_t ret = 0; - - if (!user) - return -EBADF; - if (offset) - return -ESPIPE; - - raw_spin_lock_irq(&logbuf_lock); - switch (whence) { - case SEEK_SET: - /* the first record */ - user->idx = log_first_idx; - user->seq = log_first_seq; - break; - case SEEK_DATA: - /* - * The first record after the last SYSLOG_ACTION_CLEAR, - * like issued by 'dmesg -c'. Reading /dev/kmsg itself - * changes no global state, and does not clear anything. - */ - user->idx = clear_idx; - user->seq = clear_seq; - break; - case SEEK_END: - /* after the last record */ - user->idx = log_next_idx; - user->seq = log_next_seq; - break; - default: - ret = -EINVAL; - } - raw_spin_unlock_irq(&logbuf_lock); - return ret; -} - -static unsigned int devkmsg_poll(struct file *file, poll_table *wait) -{ - struct devkmsg_user *user = file->private_data; - int ret = 0; - - if (!user) - return POLLERR|POLLNVAL; - - poll_wait(file, &log_wait, wait); - - raw_spin_lock_irq(&logbuf_lock); - if (user->seq < log_next_seq) { - /* return error when data has vanished underneath us */ - if (user->seq < log_first_seq) - ret = POLLIN|POLLRDNORM|POLLERR|POLLPRI; - else - ret = POLLIN|POLLRDNORM; - } - raw_spin_unlock_irq(&logbuf_lock); - - return ret; -} - -static int devkmsg_open(struct inode *inode, struct file *file) -{ - struct devkmsg_user *user; - int err; - - if (devkmsg_log & DEVKMSG_LOG_MASK_OFF) - return -EPERM; - - /* write-only does not need any file context */ - if ((file->f_flags & O_ACCMODE) != O_WRONLY) { - err = check_syslog_permissions(SYSLOG_ACTION_READ_ALL, - SYSLOG_FROM_READER); - if (err) - return err; - } - - user = kmalloc(sizeof(struct devkmsg_user), GFP_KERNEL); - if (!user) - return -ENOMEM; - - ratelimit_default_init(&user->rs); - ratelimit_set_flags(&user->rs, RATELIMIT_MSG_ON_RELEASE); - - mutex_init(&user->lock); - - raw_spin_lock_irq(&logbuf_lock); - user->idx = log_first_idx; - user->seq = log_first_seq; - raw_spin_unlock_irq(&logbuf_lock); - - file->private_data = user; - return 0; -} - -static int devkmsg_release(struct inode *inode, struct file *file) -{ - struct devkmsg_user *user = file->private_data; - - if (!user) - return 0; - - ratelimit_state_exit(&user->rs); - - mutex_destroy(&user->lock); - kfree(user); - return 0; -} - -const struct file_operations kmsg_fops = { - .open = devkmsg_open, - .read = devkmsg_read, - .write_iter = devkmsg_write, - .llseek = devkmsg_llseek, - .poll = devkmsg_poll, - .release = devkmsg_release, -}; - -#ifdef CONFIG_KEXEC_CORE -/* - * This appends the listed symbols to /proc/vmcore - * - * /proc/vmcore is used by various utilities, like crash and makedumpfile to - * obtain access to symbols that are otherwise very difficult to locate. These - * symbols are specifically used so that utilities can access and extract the - * dmesg log from a vmcore file after a crash. - */ -void log_buf_kexec_setup(void) -{ - VMCOREINFO_SYMBOL(log_buf); - VMCOREINFO_SYMBOL(log_buf_len); - VMCOREINFO_SYMBOL(log_first_idx); - VMCOREINFO_SYMBOL(clear_idx); - VMCOREINFO_SYMBOL(log_next_idx); - /* - * Export struct printk_log size and field offsets. User space tools can - * parse it and detect any changes to structure down the line. - */ - VMCOREINFO_STRUCT_SIZE(printk_log); - VMCOREINFO_OFFSET(printk_log, ts_nsec); - VMCOREINFO_OFFSET(printk_log, len); - VMCOREINFO_OFFSET(printk_log, text_len); - VMCOREINFO_OFFSET(printk_log, dict_len); -} -#endif - -/* requested log_buf_len from kernel cmdline */ -static unsigned long __initdata new_log_buf_len; - -/* we practice scaling the ring buffer by powers of 2 */ -static void __init log_buf_len_update(unsigned size) -{ - if (size) - size = roundup_pow_of_two(size); - if (size > log_buf_len) - new_log_buf_len = size; -} - -/* save requested log_buf_len since it's too early to process it */ -static int __init log_buf_len_setup(char *str) -{ - unsigned size = memparse(str, &str); - - log_buf_len_update(size); - - return 0; -} -early_param("log_buf_len", log_buf_len_setup); - -#ifdef CONFIG_SMP -#define __LOG_CPU_MAX_BUF_LEN (1 << CONFIG_LOG_CPU_MAX_BUF_SHIFT) - -static void __init log_buf_add_cpu(void) -{ - unsigned int cpu_extra; - - /* - * archs should set up cpu_possible_bits properly with - * set_cpu_possible() after setup_arch() but just in - * case lets ensure this is valid. - */ - if (num_possible_cpus() == 1) - return; - - cpu_extra = (num_possible_cpus() - 1) * __LOG_CPU_MAX_BUF_LEN; - - /* by default this will only continue through for large > 64 CPUs */ - if (cpu_extra <= __LOG_BUF_LEN / 2) - return; - - pr_info("log_buf_len individual max cpu contribution: %d bytes\n", - __LOG_CPU_MAX_BUF_LEN); - pr_info("log_buf_len total cpu_extra contributions: %d bytes\n", - cpu_extra); - pr_info("log_buf_len min size: %d bytes\n", __LOG_BUF_LEN); - - log_buf_len_update(cpu_extra + __LOG_BUF_LEN); -} -#else /* !CONFIG_SMP */ -static inline void log_buf_add_cpu(void) {} -#endif /* CONFIG_SMP */ - -void __init setup_log_buf(int early) -{ - unsigned long flags; - char *new_log_buf; - int free; - - if (log_buf != __log_buf) - return; - - if (!early && !new_log_buf_len) - log_buf_add_cpu(); - - if (!new_log_buf_len) - return; - - if (early) { - new_log_buf = - memblock_virt_alloc(new_log_buf_len, LOG_ALIGN); - } else { - new_log_buf = memblock_virt_alloc_nopanic(new_log_buf_len, - LOG_ALIGN); - } - - if (unlikely(!new_log_buf)) { - pr_err("log_buf_len: %ld bytes not available\n", - new_log_buf_len); - return; - } - - raw_spin_lock_irqsave(&logbuf_lock, flags); - log_buf_len = new_log_buf_len; - log_buf = new_log_buf; - new_log_buf_len = 0; - free = __LOG_BUF_LEN - log_next_idx; - memcpy(log_buf, __log_buf, __LOG_BUF_LEN); - raw_spin_unlock_irqrestore(&logbuf_lock, flags); - - pr_info("log_buf_len: %d bytes\n", log_buf_len); - pr_info("early log buf free: %d(%d%%)\n", - free, (free * 100) / __LOG_BUF_LEN); -} - -static bool __read_mostly ignore_loglevel; - -static int __init ignore_loglevel_setup(char *str) -{ - ignore_loglevel = true; - pr_info("debug: ignoring loglevel setting.\n"); - - return 0; -} - -early_param("ignore_loglevel", ignore_loglevel_setup); -module_param(ignore_loglevel, bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(ignore_loglevel, - "ignore loglevel setting (prints all kernel messages to the console)"); - -static bool suppress_message_printing(int level) -{ - return (level >= console_loglevel && !ignore_loglevel); -} - -#ifdef CONFIG_BOOT_PRINTK_DELAY - -static int boot_delay; /* msecs delay after each printk during bootup */ -static unsigned long long loops_per_msec; /* based on boot_delay */ - -static int __init boot_delay_setup(char *str) -{ - unsigned long lpj; - - lpj = preset_lpj ? preset_lpj : 1000000; /* some guess */ - loops_per_msec = (unsigned long long)lpj / 1000 * HZ; - - get_option(&str, &boot_delay); - if (boot_delay > 10 * 1000) - boot_delay = 0; - - pr_debug("boot_delay: %u, preset_lpj: %ld, lpj: %lu, " - "HZ: %d, loops_per_msec: %llu\n", - boot_delay, preset_lpj, lpj, HZ, loops_per_msec); - return 0; -} -early_param("boot_delay", boot_delay_setup); - -static void boot_delay_msec(int level) -{ - unsigned long long k; - unsigned long timeout; - - if ((boot_delay == 0 || system_state != SYSTEM_BOOTING) - || suppress_message_printing(level)) { - return; - } - - k = (unsigned long long)loops_per_msec * boot_delay; - - timeout = jiffies + msecs_to_jiffies(boot_delay); - while (k) { - k--; - cpu_relax(); - /* - * use (volatile) jiffies to prevent - * compiler reduction; loop termination via jiffies - * is secondary and may or may not happen. - */ - if (time_after(jiffies, timeout)) - break; - touch_nmi_watchdog(); - } -} -#else -static inline void boot_delay_msec(int level) -{ -} -#endif - -static bool printk_time = IS_ENABLED(CONFIG_PRINTK_TIME); -module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR); - -static size_t print_time(u64 ts, char *buf) -{ - unsigned long rem_nsec; - - if (!printk_time) - return 0; - - rem_nsec = do_div(ts, 1000000000); - - if (!buf) - return snprintf(NULL, 0, "[%5lu.000000] ", (unsigned long)ts); - - return sprintf(buf, "[%5lu.%06lu] ", - (unsigned long)ts, rem_nsec / 1000); -} - -static size_t print_prefix(const struct printk_log *msg, bool syslog, char *buf) -{ - size_t len = 0; - unsigned int prefix = (msg->facility << 3) | msg->level; - - if (syslog) { - if (buf) { - len += sprintf(buf, "<%u>", prefix); - } else { - len += 3; - if (prefix > 999) - len += 3; - else if (prefix > 99) - len += 2; - else if (prefix > 9) - len++; - } - } - - len += print_time(msg->ts_nsec, buf ? buf + len : NULL); - return len; -} - -static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev, - bool syslog, char *buf, size_t size) -{ - const char *text = log_text(msg); - size_t text_size = msg->text_len; - bool prefix = true; - bool newline = true; - size_t len = 0; - - if ((prev & LOG_CONT) && !(msg->flags & LOG_PREFIX)) - prefix = false; - - if (msg->flags & LOG_CONT) { - if ((prev & LOG_CONT) && !(prev & LOG_NEWLINE)) - prefix = false; - - if (!(msg->flags & LOG_NEWLINE)) - newline = false; - } - - do { - const char *next = memchr(text, '\n', text_size); - size_t text_len; - - if (next) { - text_len = next - text; - next++; - text_size -= next - text; - } else { - text_len = text_size; - } - - if (buf) { - if (print_prefix(msg, syslog, NULL) + - text_len + 1 >= size - len) - break; - - if (prefix) - len += print_prefix(msg, syslog, buf + len); - memcpy(buf + len, text, text_len); - len += text_len; - if (next || newline) - buf[len++] = '\n'; - } else { - /* SYSLOG_ACTION_* buffer size only calculation */ - if (prefix) - len += print_prefix(msg, syslog, NULL); - len += text_len; - if (next || newline) - len++; - } - - prefix = true; - text = next; - } while (text); - - return len; -} - -static int syslog_print(char __user *buf, int size) -{ - char *text; - struct printk_log *msg; - int len = 0; - - text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL); - if (!text) - return -ENOMEM; - - while (size > 0) { - size_t n; - size_t skip; - - raw_spin_lock_irq(&logbuf_lock); - if (syslog_seq < log_first_seq) { - /* messages are gone, move to first one */ - syslog_seq = log_first_seq; - syslog_idx = log_first_idx; - syslog_prev = 0; - syslog_partial = 0; - } - if (syslog_seq == log_next_seq) { - raw_spin_unlock_irq(&logbuf_lock); - break; - } - - skip = syslog_partial; - msg = log_from_idx(syslog_idx); - n = msg_print_text(msg, syslog_prev, true, text, - LOG_LINE_MAX + PREFIX_MAX); - if (n - syslog_partial <= size) { - /* message fits into buffer, move forward */ - syslog_idx = log_next(syslog_idx); - syslog_seq++; - syslog_prev = msg->flags; - n -= syslog_partial; - syslog_partial = 0; - } else if (!len){ - /* partial read(), remember position */ - n = size; - syslog_partial += n; - } else - n = 0; - raw_spin_unlock_irq(&logbuf_lock); - - if (!n) - break; - - if (copy_to_user(buf, text + skip, n)) { - if (!len) - len = -EFAULT; - break; - } - - len += n; - size -= n; - buf += n; - } - - kfree(text); - return len; -} - -static int syslog_print_all(char __user *buf, int size, bool clear) -{ - char *text; - int len = 0; - - text = kmalloc(LOG_LINE_MAX + PREFIX_MAX, GFP_KERNEL); - if (!text) - return -ENOMEM; - - raw_spin_lock_irq(&logbuf_lock); - if (buf) { - u64 next_seq; - u64 seq; - u32 idx; - enum log_flags prev; - - /* - * Find first record that fits, including all following records, - * into the user-provided buffer for this dump. - */ - seq = clear_seq; - idx = clear_idx; - prev = 0; - while (seq < log_next_seq) { - struct printk_log *msg = log_from_idx(idx); - - len += msg_print_text(msg, prev, true, NULL, 0); - prev = msg->flags; - idx = log_next(idx); - seq++; - } - - /* move first record forward until length fits into the buffer */ - seq = clear_seq; - idx = clear_idx; - prev = 0; - while (len > size && seq < log_next_seq) { - struct printk_log *msg = log_from_idx(idx); - - len -= msg_print_text(msg, prev, true, NULL, 0); - prev = msg->flags; - idx = log_next(idx); - seq++; - } - - /* last message fitting into this dump */ - next_seq = log_next_seq; - - len = 0; - while (len >= 0 && seq < next_seq) { - struct printk_log *msg = log_from_idx(idx); - int textlen; - - textlen = msg_print_text(msg, prev, true, text, - LOG_LINE_MAX + PREFIX_MAX); - if (textlen < 0) { - len = textlen; - break; - } - idx = log_next(idx); - seq++; - prev = msg->flags; - - raw_spin_unlock_irq(&logbuf_lock); - if (copy_to_user(buf + len, text, textlen)) - len = -EFAULT; - else - len += textlen; - raw_spin_lock_irq(&logbuf_lock); - - if (seq < log_first_seq) { - /* messages are gone, move to next one */ - seq = log_first_seq; - idx = log_first_idx; - prev = 0; - } - } - } - - if (clear) { - clear_seq = log_next_seq; - clear_idx = log_next_idx; - } - raw_spin_unlock_irq(&logbuf_lock); - - kfree(text); - return len; -} - -int do_syslog(int type, char __user *buf, int len, int source) -{ - bool clear = false; - static int saved_console_loglevel = LOGLEVEL_DEFAULT; - int error; - - error = check_syslog_permissions(type, source); - if (error) - goto out; - - switch (type) { - case SYSLOG_ACTION_CLOSE: /* Close log */ - break; - case SYSLOG_ACTION_OPEN: /* Open log */ - break; - case SYSLOG_ACTION_READ: /* Read from log */ - error = -EINVAL; - if (!buf || len < 0) - goto out; - error = 0; - if (!len) - goto out; - if (!access_ok(VERIFY_WRITE, buf, len)) { - error = -EFAULT; - goto out; - } - error = wait_event_interruptible(log_wait, - syslog_seq != log_next_seq); - if (error) - goto out; - error = syslog_print(buf, len); - break; - /* Read/clear last kernel messages */ - case SYSLOG_ACTION_READ_CLEAR: - clear = true; - /* FALL THRU */ - /* Read last kernel messages */ - case SYSLOG_ACTION_READ_ALL: - error = -EINVAL; - if (!buf || len < 0) - goto out; - error = 0; - if (!len) - goto out; - if (!access_ok(VERIFY_WRITE, buf, len)) { - error = -EFAULT; - goto out; - } - error = syslog_print_all(buf, len, clear); - break; - /* Clear ring buffer */ - case SYSLOG_ACTION_CLEAR: - syslog_print_all(NULL, 0, true); - break; - /* Disable logging to console */ - case SYSLOG_ACTION_CONSOLE_OFF: - if (saved_console_loglevel == LOGLEVEL_DEFAULT) - saved_console_loglevel = console_loglevel; - console_loglevel = minimum_console_loglevel; - break; - /* Enable logging to console */ - case SYSLOG_ACTION_CONSOLE_ON: - if (saved_console_loglevel != LOGLEVEL_DEFAULT) { - console_loglevel = saved_console_loglevel; - saved_console_loglevel = LOGLEVEL_DEFAULT; - } - break; - /* Set level of messages printed to console */ - case SYSLOG_ACTION_CONSOLE_LEVEL: - error = -EINVAL; - if (len < 1 || len > 8) - goto out; - if (len < minimum_console_loglevel) - len = minimum_console_loglevel; - console_loglevel = len; - /* Implicitly re-enable logging to console */ - saved_console_loglevel = LOGLEVEL_DEFAULT; - error = 0; - break; - /* Number of chars in the log buffer */ - case SYSLOG_ACTION_SIZE_UNREAD: - raw_spin_lock_irq(&logbuf_lock); - if (syslog_seq < log_first_seq) { - /* messages are gone, move to first one */ - syslog_seq = log_first_seq; - syslog_idx = log_first_idx; - syslog_prev = 0; - syslog_partial = 0; - } - if (source == SYSLOG_FROM_PROC) { - /* - * Short-cut for poll(/"proc/kmsg") which simply checks - * for pending data, not the size; return the count of - * records, not the length. - */ - error = log_next_seq - syslog_seq; - } else { - u64 seq = syslog_seq; - u32 idx = syslog_idx; - enum log_flags prev = syslog_prev; - - error = 0; - while (seq < log_next_seq) { - struct printk_log *msg = log_from_idx(idx); - - error += msg_print_text(msg, prev, true, NULL, 0); - idx = log_next(idx); - seq++; - prev = msg->flags; - } - error -= syslog_partial; - } - raw_spin_unlock_irq(&logbuf_lock); - break; - /* Size of the log buffer */ - case SYSLOG_ACTION_SIZE_BUFFER: - error = log_buf_len; - break; - default: - error = -EINVAL; - break; - } -out: - return error; -} - -SYSCALL_DEFINE3(syslog, int, type, char __user *, buf, int, len) -{ - return do_syslog(type, buf, len, SYSLOG_FROM_READER); -} - -/* - * Call the console drivers, asking them to write out - * log_buf[start] to log_buf[end - 1]. - * The console_lock must be held. - */ -static void call_console_drivers(int level, - const char *ext_text, size_t ext_len, - const char *text, size_t len) -{ - struct console *con; - - trace_console(text, len); - - if (!console_drivers) - return; - - for_each_console(con) { - if (exclusive_console && con != exclusive_console) - continue; - if (!(con->flags & CON_ENABLED)) - continue; - if (!con->write) - continue; - if (!cpu_online(smp_processor_id()) && - !(con->flags & CON_ANYTIME)) - continue; - if (con->flags & CON_EXTENDED) - con->write(con, ext_text, ext_len); - else - con->write(con, text, len); - } -} - -/* - * Zap console related locks when oopsing. - * To leave time for slow consoles to print a full oops, - * only zap at most once every 30 seconds. - */ -static void zap_locks(void) -{ - static unsigned long oops_timestamp; - - if (time_after_eq(jiffies, oops_timestamp) && - !time_after(jiffies, oops_timestamp + 30 * HZ)) - return; - - oops_timestamp = jiffies; - - debug_locks_off(); - /* If a crash is occurring, make sure we can't deadlock */ - raw_spin_lock_init(&logbuf_lock); - /* And make sure that we print immediately */ - sema_init(&console_sem, 1); -} - -int printk_delay_msec __read_mostly; - -static inline void printk_delay(void) -{ - if (unlikely(printk_delay_msec)) { - int m = printk_delay_msec; - - while (m--) { - mdelay(1); - touch_nmi_watchdog(); - } - } -} - -/* - * Continuation lines are buffered, and not committed to the record buffer - * until the line is complete, or a race forces it. The line fragments - * though, are printed immediately to the consoles to ensure everything has - * reached the console in case of a kernel crash. - */ -static struct cont { - char buf[LOG_LINE_MAX]; - size_t len; /* length == 0 means unused buffer */ - size_t cons; /* bytes written to console */ - struct task_struct *owner; /* task of first print*/ - u64 ts_nsec; /* time of first print */ - u8 level; /* log level of first message */ - u8 facility; /* log facility of first message */ - enum log_flags flags; /* prefix, newline flags */ - bool flushed:1; /* buffer sealed and committed */ -} cont; - -static void cont_flush(void) -{ - if (cont.flushed) - return; - if (cont.len == 0) - return; - if (cont.cons) { - /* - * If a fragment of this line was directly flushed to the - * console; wait for the console to pick up the rest of the - * line. LOG_NOCONS suppresses a duplicated output. - */ - log_store(cont.facility, cont.level, cont.flags | LOG_NOCONS, - cont.ts_nsec, NULL, 0, cont.buf, cont.len); - cont.flushed = true; - } else { - /* - * If no fragment of this line ever reached the console, - * just submit it to the store and free the buffer. - */ - log_store(cont.facility, cont.level, cont.flags, 0, - NULL, 0, cont.buf, cont.len); - cont.len = 0; - } -} - -static bool cont_add(int facility, int level, enum log_flags flags, const char *text, size_t len) -{ - if (cont.len && cont.flushed) - return false; - - /* - * If ext consoles are present, flush and skip in-kernel - * continuation. See nr_ext_console_drivers definition. Also, if - * the line gets too long, split it up in separate records. - */ - if (nr_ext_console_drivers || cont.len + len > sizeof(cont.buf)) { - cont_flush(); - return false; - } - - if (!cont.len) { - cont.facility = facility; - cont.level = level; - cont.owner = current; - cont.ts_nsec = local_clock(); - cont.flags = flags; - cont.cons = 0; - cont.flushed = false; - } - - memcpy(cont.buf + cont.len, text, len); - cont.len += len; - - // The original flags come from the first line, - // but later continuations can add a newline. - if (flags & LOG_NEWLINE) { - cont.flags |= LOG_NEWLINE; - cont_flush(); - } - - if (cont.len > (sizeof(cont.buf) * 80) / 100) - cont_flush(); - - return true; -} - -static size_t cont_print_text(char *text, size_t size) -{ - size_t textlen = 0; - size_t len; - - if (cont.cons == 0 && (console_prev & LOG_NEWLINE)) { - textlen += print_time(cont.ts_nsec, text); - size -= textlen; - } - - len = cont.len - cont.cons; - if (len > 0) { - if (len+1 > size) - len = size-1; - memcpy(text + textlen, cont.buf + cont.cons, len); - textlen += len; - cont.cons = cont.len; - } - - if (cont.flushed) { - if (cont.flags & LOG_NEWLINE) - text[textlen++] = '\n'; - /* got everything, release buffer */ - cont.len = 0; - } - return textlen; -} - -static size_t log_output(int facility, int level, enum log_flags lflags, const char *dict, size_t dictlen, char *text, size_t text_len) -{ - /* - * If an earlier line was buffered, and we're a continuation - * write from the same process, try to add it to the buffer. - */ - if (cont.len) { - if (cont.owner == current && (lflags & LOG_CONT)) { - if (cont_add(facility, level, lflags, text, text_len)) - return text_len; - } - /* Otherwise, make sure it's flushed */ - cont_flush(); - } - - /* Skip empty continuation lines that couldn't be added - they just flush */ - if (!text_len && (lflags & LOG_CONT)) - return 0; - - /* If it doesn't end in a newline, try to buffer the current line */ - if (!(lflags & LOG_NEWLINE)) { - if (cont_add(facility, level, lflags, text, text_len)) - return text_len; - } - - /* Store it in the record log */ - return log_store(facility, level, lflags, 0, dict, dictlen, text, text_len); -} - -asmlinkage int vprintk_emit(int facility, int level, - const char *dict, size_t dictlen, - const char *fmt, va_list args) -{ - static bool recursion_bug; - static char textbuf[LOG_LINE_MAX]; - char *text = textbuf; - size_t text_len = 0; - enum log_flags lflags = 0; - unsigned long flags; - int this_cpu; - int printed_len = 0; - int nmi_message_lost; - bool in_sched = false; - /* cpu currently holding logbuf_lock in this function */ - static unsigned int logbuf_cpu = UINT_MAX; - - if (level == LOGLEVEL_SCHED) { - level = LOGLEVEL_DEFAULT; - in_sched = true; - } - - boot_delay_msec(level); - printk_delay(); - - local_irq_save(flags); - this_cpu = smp_processor_id(); - - /* - * Ouch, printk recursed into itself! - */ - if (unlikely(logbuf_cpu == this_cpu)) { - /* - * If a crash is occurring during printk() on this CPU, - * then try to get the crash message out but make sure - * we can't deadlock. Otherwise just return to avoid the - * recursion and return - but flag the recursion so that - * it can be printed at the next appropriate moment: - */ - if (!oops_in_progress && !lockdep_recursing(current)) { - recursion_bug = true; - local_irq_restore(flags); - return 0; - } - zap_locks(); - } - - lockdep_off(); - /* This stops the holder of console_sem just where we want him */ - raw_spin_lock(&logbuf_lock); - logbuf_cpu = this_cpu; - - if (unlikely(recursion_bug)) { - static const char recursion_msg[] = - "BUG: recent printk recursion!"; - - recursion_bug = false; - /* emit KERN_CRIT message */ - printed_len += log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0, - NULL, 0, recursion_msg, - strlen(recursion_msg)); - } - - nmi_message_lost = get_nmi_message_lost(); - if (unlikely(nmi_message_lost)) { - text_len = scnprintf(textbuf, sizeof(textbuf), - "BAD LUCK: lost %d message(s) from NMI context!", - nmi_message_lost); - printed_len += log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0, - NULL, 0, textbuf, text_len); - } - - /* - * The printf needs to come first; we need the syslog - * prefix which might be passed-in as a parameter. - */ - text_len = vscnprintf(text, sizeof(textbuf), fmt, args); - - /* mark and strip a trailing newline */ - if (text_len && text[text_len-1] == '\n') { - text_len--; - lflags |= LOG_NEWLINE; - } - - /* strip kernel syslog prefix and extract log level or control flags */ - if (facility == 0) { - int kern_level; - - while ((kern_level = printk_get_level(text)) != 0) { - switch (kern_level) { - case '0' ... '7': - if (level == LOGLEVEL_DEFAULT) - level = kern_level - '0'; - /* fallthrough */ - case 'd': /* KERN_DEFAULT */ - lflags |= LOG_PREFIX; - break; - case 'c': /* KERN_CONT */ - lflags |= LOG_CONT; - } - - text_len -= 2; - text += 2; - } - } - - if (level == LOGLEVEL_DEFAULT) - level = default_message_loglevel; - - if (dict) - lflags |= LOG_PREFIX|LOG_NEWLINE; - - printed_len += log_output(facility, level, lflags, dict, dictlen, text, text_len); - - logbuf_cpu = UINT_MAX; - raw_spin_unlock(&logbuf_lock); - lockdep_on(); - local_irq_restore(flags); - - /* If called from the scheduler, we can not call up(). */ - if (!in_sched) { - lockdep_off(); - /* - * Try to acquire and then immediately release the console - * semaphore. The release will print out buffers and wake up - * /dev/kmsg and syslog() users. - */ - if (console_trylock()) - console_unlock(); - lockdep_on(); - } - - return printed_len; -} -EXPORT_SYMBOL(vprintk_emit); - -asmlinkage int vprintk(const char *fmt, va_list args) -{ - return vprintk_emit(0, LOGLEVEL_DEFAULT, NULL, 0, fmt, args); -} -EXPORT_SYMBOL(vprintk); - -asmlinkage int printk_emit(int facility, int level, - const char *dict, size_t dictlen, - const char *fmt, ...) -{ - va_list args; - int r; - - va_start(args, fmt); - r = vprintk_emit(facility, level, dict, dictlen, fmt, args); - va_end(args); - - return r; -} -EXPORT_SYMBOL(printk_emit); - -int vprintk_default(const char *fmt, va_list args) -{ - int r; - -#ifdef CONFIG_KGDB_KDB - if (unlikely(kdb_trap_printk)) { - r = vkdb_printf(KDB_MSGSRC_PRINTK, fmt, args); - return r; - } -#endif - r = vprintk_emit(0, LOGLEVEL_DEFAULT, NULL, 0, fmt, args); - - return r; -} -EXPORT_SYMBOL_GPL(vprintk_default); - -/** - * printk - print a kernel message - * @fmt: format string - * - * This is printk(). It can be called from any context. We want it to work. - * - * We try to grab the console_lock. If we succeed, it's easy - we log the - * output and call the console drivers. If we fail to get the semaphore, we - * place the output into the log buffer and return. The current holder of - * the console_sem will notice the new output in console_unlock(); and will - * send it to the consoles before releasing the lock. - * - * One effect of this deferred printing is that code which calls printk() and - * then changes console_loglevel may break. This is because console_loglevel - * is inspected when the actual printing occurs. - * - * See also: - * printf(3) - * - * See the vsnprintf() documentation for format string extensions over C99. - */ -asmlinkage __visible int printk(const char *fmt, ...) -{ - va_list args; - int r; - - va_start(args, fmt); - r = vprintk_func(fmt, args); - va_end(args); - - return r; -} -EXPORT_SYMBOL(printk); - -#else /* CONFIG_PRINTK */ - -#define LOG_LINE_MAX 0 -#define PREFIX_MAX 0 - -static u64 syslog_seq; -static u32 syslog_idx; -static u64 console_seq; -static u32 console_idx; -static enum log_flags syslog_prev; -static u64 log_first_seq; -static u32 log_first_idx; -static u64 log_next_seq; -static enum log_flags console_prev; -static struct cont { - size_t len; - size_t cons; - u8 level; - bool flushed:1; -} cont; -static char *log_text(const struct printk_log *msg) { return NULL; } -static char *log_dict(const struct printk_log *msg) { return NULL; } -static struct printk_log *log_from_idx(u32 idx) { return NULL; } -static u32 log_next(u32 idx) { return 0; } -static ssize_t msg_print_ext_header(char *buf, size_t size, - struct printk_log *msg, u64 seq, - enum log_flags prev_flags) { return 0; } -static ssize_t msg_print_ext_body(char *buf, size_t size, - char *dict, size_t dict_len, - char *text, size_t text_len) { return 0; } -static void call_console_drivers(int level, - const char *ext_text, size_t ext_len, - const char *text, size_t len) {} -static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev, - bool syslog, char *buf, size_t size) { return 0; } -static size_t cont_print_text(char *text, size_t size) { return 0; } -static bool suppress_message_printing(int level) { return false; } - -/* Still needs to be defined for users */ -DEFINE_PER_CPU(printk_func_t, printk_func); - -#endif /* CONFIG_PRINTK */ - -#ifdef CONFIG_EARLY_PRINTK -struct console *early_console; - -asmlinkage __visible void early_printk(const char *fmt, ...) -{ - va_list ap; - char buf[512]; - int n; - - if (!early_console) - return; - - va_start(ap, fmt); - n = vscnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - - early_console->write(early_console, buf, n); -} -#endif - -static int __add_preferred_console(char *name, int idx, char *options, - char *brl_options) -{ - struct console_cmdline *c; - int i; - - /* - * See if this tty is not yet registered, and - * if we have a slot free. - */ - for (i = 0, c = console_cmdline; - i < MAX_CMDLINECONSOLES && c->name[0]; - i++, c++) { - if (strcmp(c->name, name) == 0 && c->index == idx) { - if (!brl_options) - selected_console = i; - return 0; - } - } - if (i == MAX_CMDLINECONSOLES) - return -E2BIG; - if (!brl_options) - selected_console = i; - strlcpy(c->name, name, sizeof(c->name)); - c->options = options; - braille_set_options(c, brl_options); - - c->index = idx; - return 0; -} -/* - * Set up a console. Called via do_early_param() in init/main.c - * for each "console=" parameter in the boot command line. - */ -static int __init console_setup(char *str) -{ - char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for "ttyS" */ - char *s, *options, *brl_options = NULL; - int idx; - - if (_braille_console_setup(&str, &brl_options)) - return 1; - - /* - * Decode str into name, index, options. - */ - if (str[0] >= '0' && str[0] <= '9') { - strcpy(buf, "ttyS"); - strncpy(buf + 4, str, sizeof(buf) - 5); - } else { - strncpy(buf, str, sizeof(buf) - 1); - } - buf[sizeof(buf) - 1] = 0; - options = strchr(str, ','); - if (options) - *(options++) = 0; -#ifdef __sparc__ - if (!strcmp(str, "ttya")) - strcpy(buf, "ttyS0"); - if (!strcmp(str, "ttyb")) - strcpy(buf, "ttyS1"); -#endif - for (s = buf; *s; s++) - if (isdigit(*s) || *s == ',') - break; - idx = simple_strtoul(s, NULL, 10); - *s = 0; - - __add_preferred_console(buf, idx, options, brl_options); - console_set_on_cmdline = 1; - return 1; -} -__setup("console=", console_setup); - -/** - * add_preferred_console - add a device to the list of preferred consoles. - * @name: device name - * @idx: device index - * @options: options for this console - * - * The last preferred console added will be used for kernel messages - * and stdin/out/err for init. Normally this is used by console_setup - * above to handle user-supplied console arguments; however it can also - * be used by arch-specific code either to override the user or more - * commonly to provide a default console (ie from PROM variables) when - * the user has not supplied one. - */ -int add_preferred_console(char *name, int idx, char *options) -{ - return __add_preferred_console(name, idx, options, NULL); -} - -bool console_suspend_enabled = true; -EXPORT_SYMBOL(console_suspend_enabled); - -static int __init console_suspend_disable(char *str) -{ - console_suspend_enabled = false; - return 1; -} -__setup("no_console_suspend", console_suspend_disable); -module_param_named(console_suspend, console_suspend_enabled, - bool, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(console_suspend, "suspend console during suspend" - " and hibernate operations"); - -/** - * suspend_console - suspend the console subsystem - * - * This disables printk() while we go into suspend states - */ -void suspend_console(void) -{ - if (!console_suspend_enabled) - return; - printk("Suspending console(s) (use no_console_suspend to debug)\n"); - console_lock(); - console_suspended = 1; - up_console_sem(); -} - -void resume_console(void) -{ - if (!console_suspend_enabled) - return; - down_console_sem(); - console_suspended = 0; - console_unlock(); -} - -/** - * console_cpu_notify - print deferred console messages after CPU hotplug - * @self: notifier struct - * @action: CPU hotplug event - * @hcpu: unused - * - * If printk() is called from a CPU that is not online yet, the messages - * will be spooled but will not show up on the console. This function is - * called when a new CPU comes online (or fails to come up), and ensures - * that any such output gets printed. - */ -static int console_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) -{ - switch (action) { - case CPU_ONLINE: - case CPU_DEAD: - case CPU_DOWN_FAILED: - case CPU_UP_CANCELED: - console_lock(); - console_unlock(); - } - return NOTIFY_OK; -} - -/** - * console_lock - lock the console system for exclusive use. - * - * Acquires a lock which guarantees that the caller has - * exclusive access to the console system and the console_drivers list. - * - * Can sleep, returns nothing. - */ -void console_lock(void) -{ - might_sleep(); - - down_console_sem(); - if (console_suspended) - return; - console_locked = 1; - console_may_schedule = 1; -} -EXPORT_SYMBOL(console_lock); - -/** - * console_trylock - try to lock the console system for exclusive use. - * - * Try to acquire a lock which guarantees that the caller has exclusive - * access to the console system and the console_drivers list. - * - * returns 1 on success, and 0 on failure to acquire the lock. - */ -int console_trylock(void) -{ - if (down_trylock_console_sem()) - return 0; - if (console_suspended) { - up_console_sem(); - return 0; - } - console_locked = 1; - /* - * When PREEMPT_COUNT disabled we can't reliably detect if it's - * safe to schedule (e.g. calling printk while holding a spin_lock), - * because preempt_disable()/preempt_enable() are just barriers there - * and preempt_count() is always 0. - * - * RCU read sections have a separate preemption counter when - * PREEMPT_RCU enabled thus we must take extra care and check - * rcu_preempt_depth(), otherwise RCU read sections modify - * preempt_count(). - */ - console_may_schedule = !oops_in_progress && - preemptible() && - !rcu_preempt_depth(); - return 1; -} -EXPORT_SYMBOL(console_trylock); - -int is_console_locked(void) -{ - return console_locked; -} - -/* - * Check if we have any console that is capable of printing while cpu is - * booting or shutting down. Requires console_sem. - */ -static int have_callable_console(void) -{ - struct console *con; - - for_each_console(con) - if ((con->flags & CON_ENABLED) && - (con->flags & CON_ANYTIME)) - return 1; - - return 0; -} - -/* - * Can we actually use the console at this time on this cpu? - * - * Console drivers may assume that per-cpu resources have been allocated. So - * unless they're explicitly marked as being able to cope (CON_ANYTIME) don't - * call them until this CPU is officially up. - */ -static inline int can_use_console(void) -{ - return cpu_online(raw_smp_processor_id()) || have_callable_console(); -} - -static void console_cont_flush(char *text, size_t size) -{ - unsigned long flags; - size_t len; - - raw_spin_lock_irqsave(&logbuf_lock, flags); - - if (!cont.len) - goto out; - - if (suppress_message_printing(cont.level)) { - cont.cons = cont.len; - if (cont.flushed) - cont.len = 0; - goto out; - } - - /* - * We still queue earlier records, likely because the console was - * busy. The earlier ones need to be printed before this one, we - * did not flush any fragment so far, so just let it queue up. - */ - if (console_seq < log_next_seq && !cont.cons) - goto out; - - len = cont_print_text(text, size); - raw_spin_unlock(&logbuf_lock); - stop_critical_timings(); - call_console_drivers(cont.level, NULL, 0, text, len); - start_critical_timings(); - local_irq_restore(flags); - return; -out: - raw_spin_unlock_irqrestore(&logbuf_lock, flags); -} - -/** - * console_unlock - unlock the console system - * - * Releases the console_lock which the caller holds on the console system - * and the console driver list. - * - * While the console_lock was held, console output may have been buffered - * by printk(). If this is the case, console_unlock(); emits - * the output prior to releasing the lock. - * - * If there is output waiting, we wake /dev/kmsg and syslog() users. - * - * console_unlock(); may be called from any context. - */ -void console_unlock(void) -{ - static char ext_text[CONSOLE_EXT_LOG_MAX]; - static char text[LOG_LINE_MAX + PREFIX_MAX]; - static u64 seen_seq; - unsigned long flags; - bool wake_klogd = false; - bool do_cond_resched, retry; - - if (console_suspended) { - up_console_sem(); - return; - } - - /* - * Console drivers are called under logbuf_lock, so - * @console_may_schedule should be cleared before; however, we may - * end up dumping a lot of lines, for example, if called from - * console registration path, and should invoke cond_resched() - * between lines if allowable. Not doing so can cause a very long - * scheduling stall on a slow console leading to RCU stall and - * softlockup warnings which exacerbate the issue with more - * messages practically incapacitating the system. - */ - do_cond_resched = console_may_schedule; - console_may_schedule = 0; - -again: - /* - * We released the console_sem lock, so we need to recheck if - * cpu is online and (if not) is there at least one CON_ANYTIME - * console. - */ - if (!can_use_console()) { - console_locked = 0; - up_console_sem(); - return; - } - - /* flush buffered message fragment immediately to console */ - console_cont_flush(text, sizeof(text)); - - for (;;) { - struct printk_log *msg; - size_t ext_len = 0; - size_t len; - int level; - - raw_spin_lock_irqsave(&logbuf_lock, flags); - if (seen_seq != log_next_seq) { - wake_klogd = true; - seen_seq = log_next_seq; - } - - if (console_seq < log_first_seq) { - len = sprintf(text, "** %u printk messages dropped ** ", - (unsigned)(log_first_seq - console_seq)); - - /* messages are gone, move to first one */ - console_seq = log_first_seq; - console_idx = log_first_idx; - console_prev = 0; - } else { - len = 0; - } -skip: - if (console_seq == log_next_seq) - break; - - msg = log_from_idx(console_idx); - level = msg->level; - if ((msg->flags & LOG_NOCONS) || - suppress_message_printing(level)) { - /* - * Skip record we have buffered and already printed - * directly to the console when we received it, and - * record that has level above the console loglevel. - */ - console_idx = log_next(console_idx); - console_seq++; - /* - * We will get here again when we register a new - * CON_PRINTBUFFER console. Clear the flag so we - * will properly dump everything later. - */ - msg->flags &= ~LOG_NOCONS; - console_prev = msg->flags; - goto skip; - } - - len += msg_print_text(msg, console_prev, false, - text + len, sizeof(text) - len); - if (nr_ext_console_drivers) { - ext_len = msg_print_ext_header(ext_text, - sizeof(ext_text), - msg, console_seq, console_prev); - ext_len += msg_print_ext_body(ext_text + ext_len, - sizeof(ext_text) - ext_len, - log_dict(msg), msg->dict_len, - log_text(msg), msg->text_len); - } - console_idx = log_next(console_idx); - console_seq++; - console_prev = msg->flags; - raw_spin_unlock(&logbuf_lock); - - stop_critical_timings(); /* don't trace print latency */ - call_console_drivers(level, ext_text, ext_len, text, len); - start_critical_timings(); - local_irq_restore(flags); - - if (do_cond_resched) - cond_resched(); - } - console_locked = 0; - - /* Release the exclusive_console once it is used */ - if (unlikely(exclusive_console)) - exclusive_console = NULL; - - raw_spin_unlock(&logbuf_lock); - - up_console_sem(); - - /* - * Someone could have filled up the buffer again, so re-check if there's - * something to flush. In case we cannot trylock the console_sem again, - * there's a new owner and the console_unlock() from them will do the - * flush, no worries. - */ - raw_spin_lock(&logbuf_lock); - retry = console_seq != log_next_seq; - raw_spin_unlock_irqrestore(&logbuf_lock, flags); - - if (retry && console_trylock()) - goto again; - - if (wake_klogd) - wake_up_klogd(); -} -EXPORT_SYMBOL(console_unlock); - -/** - * console_conditional_schedule - yield the CPU if required - * - * If the console code is currently allowed to sleep, and - * if this CPU should yield the CPU to another task, do - * so here. - * - * Must be called within console_lock();. - */ -void __sched console_conditional_schedule(void) -{ - if (console_may_schedule) - cond_resched(); -} -EXPORT_SYMBOL(console_conditional_schedule); - -void console_unblank(void) -{ - struct console *c; - - /* - * console_unblank can no longer be called in interrupt context unless - * oops_in_progress is set to 1.. - */ - if (oops_in_progress) { - if (down_trylock_console_sem() != 0) - return; - } else - console_lock(); - - console_locked = 1; - console_may_schedule = 0; - for_each_console(c) - if ((c->flags & CON_ENABLED) && c->unblank) - c->unblank(); - console_unlock(); -} - -/** - * console_flush_on_panic - flush console content on panic - * - * Immediately output all pending messages no matter what. - */ -void console_flush_on_panic(void) -{ - /* - * If someone else is holding the console lock, trylock will fail - * and may_schedule may be set. Ignore and proceed to unlock so - * that messages are flushed out. As this can be called from any - * context and we don't want to get preempted while flushing, - * ensure may_schedule is cleared. - */ - console_trylock(); - console_may_schedule = 0; - console_unlock(); -} - -/* - * Return the console tty driver structure and its associated index - */ -struct tty_driver *console_device(int *index) -{ - struct console *c; - struct tty_driver *driver = NULL; - - console_lock(); - for_each_console(c) { - if (!c->device) - continue; - driver = c->device(c, index); - if (driver) - break; - } - console_unlock(); - return driver; -} - -/* - * Prevent further output on the passed console device so that (for example) - * serial drivers can disable console output before suspending a port, and can - * re-enable output afterwards. - */ -void console_stop(struct console *console) -{ - console_lock(); - console->flags &= ~CON_ENABLED; - console_unlock(); -} -EXPORT_SYMBOL(console_stop); - -void console_start(struct console *console) -{ - console_lock(); - console->flags |= CON_ENABLED; - console_unlock(); -} -EXPORT_SYMBOL(console_start); - -static int __read_mostly keep_bootcon; - -static int __init keep_bootcon_setup(char *str) -{ - keep_bootcon = 1; - pr_info("debug: skip boot console de-registration.\n"); - - return 0; -} - -early_param("keep_bootcon", keep_bootcon_setup); - -/* - * The console driver calls this routine during kernel initialization - * to register the console printing procedure with printk() and to - * print any messages that were printed by the kernel before the - * console driver was initialized. - * - * This can happen pretty early during the boot process (because of - * early_printk) - sometimes before setup_arch() completes - be careful - * of what kernel features are used - they may not be initialised yet. - * - * There are two types of consoles - bootconsoles (early_printk) and - * "real" consoles (everything which is not a bootconsole) which are - * handled differently. - * - Any number of bootconsoles can be registered at any time. - * - As soon as a "real" console is registered, all bootconsoles - * will be unregistered automatically. - * - Once a "real" console is registered, any attempt to register a - * bootconsoles will be rejected - */ -void register_console(struct console *newcon) -{ - int i; - unsigned long flags; - struct console *bcon = NULL; - struct console_cmdline *c; - - if (console_drivers) - for_each_console(bcon) - if (WARN(bcon == newcon, - "console '%s%d' already registered\n", - bcon->name, bcon->index)) - return; - - /* - * before we register a new CON_BOOT console, make sure we don't - * already have a valid console - */ - if (console_drivers && newcon->flags & CON_BOOT) { - /* find the last or real console */ - for_each_console(bcon) { - if (!(bcon->flags & CON_BOOT)) { - pr_info("Too late to register bootconsole %s%d\n", - newcon->name, newcon->index); - return; - } - } - } - - if (console_drivers && console_drivers->flags & CON_BOOT) - bcon = console_drivers; - - if (preferred_console < 0 || bcon || !console_drivers) - preferred_console = selected_console; - - /* - * See if we want to use this console driver. If we - * didn't select a console we take the first one - * that registers here. - */ - if (preferred_console < 0) { - if (newcon->index < 0) - newcon->index = 0; - if (newcon->setup == NULL || - newcon->setup(newcon, NULL) == 0) { - newcon->flags |= CON_ENABLED; - if (newcon->device) { - newcon->flags |= CON_CONSDEV; - preferred_console = 0; - } - } - } - - /* - * See if this console matches one we selected on - * the command line. - */ - for (i = 0, c = console_cmdline; - i < MAX_CMDLINECONSOLES && c->name[0]; - i++, c++) { - if (!newcon->match || - newcon->match(newcon, c->name, c->index, c->options) != 0) { - /* default matching */ - BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name)); - if (strcmp(c->name, newcon->name) != 0) - continue; - if (newcon->index >= 0 && - newcon->index != c->index) - continue; - if (newcon->index < 0) - newcon->index = c->index; - - if (_braille_register_console(newcon, c)) - return; - - if (newcon->setup && - newcon->setup(newcon, c->options) != 0) - break; - } - - newcon->flags |= CON_ENABLED; - if (i == selected_console) { - newcon->flags |= CON_CONSDEV; - preferred_console = selected_console; - } - break; - } - - if (!(newcon->flags & CON_ENABLED)) - return; - - /* - * If we have a bootconsole, and are switching to a real console, - * don't print everything out again, since when the boot console, and - * the real console are the same physical device, it's annoying to - * see the beginning boot messages twice - */ - if (bcon && ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV)) - newcon->flags &= ~CON_PRINTBUFFER; - - /* - * Put this console in the list - keep the - * preferred driver at the head of the list. - */ - console_lock(); - if ((newcon->flags & CON_CONSDEV) || console_drivers == NULL) { - newcon->next = console_drivers; - console_drivers = newcon; - if (newcon->next) - newcon->next->flags &= ~CON_CONSDEV; - } else { - newcon->next = console_drivers->next; - console_drivers->next = newcon; - } - - if (newcon->flags & CON_EXTENDED) - if (!nr_ext_console_drivers++) - pr_info("printk: continuation disabled due to ext consoles, expect more fragments in /dev/kmsg\n"); - - if (newcon->flags & CON_PRINTBUFFER) { - /* - * console_unlock(); will print out the buffered messages - * for us. - */ - raw_spin_lock_irqsave(&logbuf_lock, flags); - console_seq = syslog_seq; - console_idx = syslog_idx; - console_prev = syslog_prev; - raw_spin_unlock_irqrestore(&logbuf_lock, flags); - /* - * We're about to replay the log buffer. Only do this to the - * just-registered console to avoid excessive message spam to - * the already-registered consoles. - */ - exclusive_console = newcon; - } - console_unlock(); - console_sysfs_notify(); - - /* - * By unregistering the bootconsoles after we enable the real console - * we get the "console xxx enabled" message on all the consoles - - * boot consoles, real consoles, etc - this is to ensure that end - * users know there might be something in the kernel's log buffer that - * went to the bootconsole (that they do not see on the real console) - */ - pr_info("%sconsole [%s%d] enabled\n", - (newcon->flags & CON_BOOT) ? "boot" : "" , - newcon->name, newcon->index); - if (bcon && - ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV) && - !keep_bootcon) { - /* We need to iterate through all boot consoles, to make - * sure we print everything out, before we unregister them. - */ - for_each_console(bcon) - if (bcon->flags & CON_BOOT) - unregister_console(bcon); - } -} -EXPORT_SYMBOL(register_console); - -int unregister_console(struct console *console) -{ - struct console *a, *b; - int res; - - pr_info("%sconsole [%s%d] disabled\n", - (console->flags & CON_BOOT) ? "boot" : "" , - console->name, console->index); - - res = _braille_unregister_console(console); - if (res) - return res; - - res = 1; - console_lock(); - if (console_drivers == console) { - console_drivers=console->next; - res = 0; - } else if (console_drivers) { - for (a=console_drivers->next, b=console_drivers ; - a; b=a, a=b->next) { - if (a == console) { - b->next = a->next; - res = 0; - break; - } - } - } - - if (!res && (console->flags & CON_EXTENDED)) - nr_ext_console_drivers--; - - /* - * If this isn't the last console and it has CON_CONSDEV set, we - * need to set it on the next preferred console. - */ - if (console_drivers != NULL && console->flags & CON_CONSDEV) - console_drivers->flags |= CON_CONSDEV; - - console->flags &= ~CON_ENABLED; - console_unlock(); - console_sysfs_notify(); - return res; -} -EXPORT_SYMBOL(unregister_console); - -/* - * Some boot consoles access data that is in the init section and which will - * be discarded after the initcalls have been run. To make sure that no code - * will access this data, unregister the boot consoles in a late initcall. - * - * If for some reason, such as deferred probe or the driver being a loadable - * module, the real console hasn't registered yet at this point, there will - * be a brief interval in which no messages are logged to the console, which - * makes it difficult to diagnose problems that occur during this time. - * - * To mitigate this problem somewhat, only unregister consoles whose memory - * intersects with the init section. Note that code exists elsewhere to get - * rid of the boot console as soon as the proper console shows up, so there - * won't be side-effects from postponing the removal. - */ -static int __init printk_late_init(void) -{ - struct console *con; - - for_each_console(con) { - if (!keep_bootcon && con->flags & CON_BOOT) { - /* - * Make sure to unregister boot consoles whose data - * resides in the init section before the init section - * is discarded. Boot consoles whose data will stick - * around will automatically be unregistered when the - * proper console replaces them. - */ - if (init_section_intersects(con, sizeof(*con))) - unregister_console(con); - } - } - hotcpu_notifier(console_cpu_notify, 0); - return 0; -} -late_initcall(printk_late_init); - -#if defined CONFIG_PRINTK -/* - * Delayed printk version, for scheduler-internal messages: - */ -#define PRINTK_PENDING_WAKEUP 0x01 -#define PRINTK_PENDING_OUTPUT 0x02 - -static DEFINE_PER_CPU(int, printk_pending); - -static void wake_up_klogd_work_func(struct irq_work *irq_work) -{ - int pending = __this_cpu_xchg(printk_pending, 0); - - if (pending & PRINTK_PENDING_OUTPUT) { - /* If trylock fails, someone else is doing the printing */ - if (console_trylock()) - console_unlock(); - } - - if (pending & PRINTK_PENDING_WAKEUP) - wake_up_interruptible(&log_wait); -} - -static DEFINE_PER_CPU(struct irq_work, wake_up_klogd_work) = { - .func = wake_up_klogd_work_func, - .flags = IRQ_WORK_LAZY, -}; - -void wake_up_klogd(void) -{ - preempt_disable(); - if (waitqueue_active(&log_wait)) { - this_cpu_or(printk_pending, PRINTK_PENDING_WAKEUP); - irq_work_queue(this_cpu_ptr(&wake_up_klogd_work)); - } - preempt_enable(); -} - -int printk_deferred(const char *fmt, ...) -{ - va_list args; - int r; - - preempt_disable(); - va_start(args, fmt); - r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, 0, fmt, args); - va_end(args); - - __this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT); - irq_work_queue(this_cpu_ptr(&wake_up_klogd_work)); - preempt_enable(); - - return r; -} - -/* - * printk rate limiting, lifted from the networking subsystem. - * - * This enforces a rate limit: not more than 10 kernel messages - * every 5s to make a denial-of-service attack impossible. - */ -DEFINE_RATELIMIT_STATE(printk_ratelimit_state, 5 * HZ, 10); - -int __printk_ratelimit(const char *func) -{ - return ___ratelimit(&printk_ratelimit_state, func); -} -EXPORT_SYMBOL(__printk_ratelimit); - -/** - * printk_timed_ratelimit - caller-controlled printk ratelimiting - * @caller_jiffies: pointer to caller's state - * @interval_msecs: minimum interval between prints - * - * printk_timed_ratelimit() returns true if more than @interval_msecs - * milliseconds have elapsed since the last time printk_timed_ratelimit() - * returned true. - */ -bool printk_timed_ratelimit(unsigned long *caller_jiffies, - unsigned int interval_msecs) -{ - unsigned long elapsed = jiffies - *caller_jiffies; - - if (*caller_jiffies && elapsed <= msecs_to_jiffies(interval_msecs)) - return false; - - *caller_jiffies = jiffies; - return true; -} -EXPORT_SYMBOL(printk_timed_ratelimit); - -static DEFINE_SPINLOCK(dump_list_lock); -static LIST_HEAD(dump_list); - -/** - * kmsg_dump_register - register a kernel log dumper. - * @dumper: pointer to the kmsg_dumper structure - * - * Adds a kernel log dumper to the system. The dump callback in the - * structure will be called when the kernel oopses or panics and must be - * set. Returns zero on success and %-EINVAL or %-EBUSY otherwise. - */ -int kmsg_dump_register(struct kmsg_dumper *dumper) -{ - unsigned long flags; - int err = -EBUSY; - - /* The dump callback needs to be set */ - if (!dumper->dump) - return -EINVAL; - - spin_lock_irqsave(&dump_list_lock, flags); - /* Don't allow registering multiple times */ - if (!dumper->registered) { - dumper->registered = 1; - list_add_tail_rcu(&dumper->list, &dump_list); - err = 0; - } - spin_unlock_irqrestore(&dump_list_lock, flags); - - return err; -} -EXPORT_SYMBOL_GPL(kmsg_dump_register); - -/** - * kmsg_dump_unregister - unregister a kmsg dumper. - * @dumper: pointer to the kmsg_dumper structure - * - * Removes a dump device from the system. Returns zero on success and - * %-EINVAL otherwise. - */ -int kmsg_dump_unregister(struct kmsg_dumper *dumper) -{ - unsigned long flags; - int err = -EINVAL; - - spin_lock_irqsave(&dump_list_lock, flags); - if (dumper->registered) { - dumper->registered = 0; - list_del_rcu(&dumper->list); - err = 0; - } - spin_unlock_irqrestore(&dump_list_lock, flags); - synchronize_rcu(); - - return err; -} -EXPORT_SYMBOL_GPL(kmsg_dump_unregister); - -static bool always_kmsg_dump; -module_param_named(always_kmsg_dump, always_kmsg_dump, bool, S_IRUGO | S_IWUSR); - -/** - * kmsg_dump - dump kernel log to kernel message dumpers. - * @reason: the reason (oops, panic etc) for dumping - * - * Call each of the registered dumper's dump() callback, which can - * retrieve the kmsg records with kmsg_dump_get_line() or - * kmsg_dump_get_buffer(). - */ -void kmsg_dump(enum kmsg_dump_reason reason) -{ - struct kmsg_dumper *dumper; - unsigned long flags; - - if ((reason > KMSG_DUMP_OOPS) && !always_kmsg_dump) - return; - - rcu_read_lock(); - list_for_each_entry_rcu(dumper, &dump_list, list) { - if (dumper->max_reason && reason > dumper->max_reason) - continue; - - /* initialize iterator with data about the stored records */ - dumper->active = true; - - raw_spin_lock_irqsave(&logbuf_lock, flags); - dumper->cur_seq = clear_seq; - dumper->cur_idx = clear_idx; - dumper->next_seq = log_next_seq; - dumper->next_idx = log_next_idx; - raw_spin_unlock_irqrestore(&logbuf_lock, flags); - - /* invoke dumper which will iterate over records */ - dumper->dump(dumper, reason); - - /* reset iterator */ - dumper->active = false; - } - rcu_read_unlock(); -} - -/** - * kmsg_dump_get_line_nolock - retrieve one kmsg log line (unlocked version) - * @dumper: registered kmsg dumper - * @syslog: include the "<4>" prefixes - * @line: buffer to copy the line to - * @size: maximum size of the buffer - * @len: length of line placed into buffer - * - * Start at the beginning of the kmsg buffer, with the oldest kmsg - * record, and copy one record into the provided buffer. - * - * Consecutive calls will return the next available record moving - * towards the end of the buffer with the youngest messages. - * - * A return value of FALSE indicates that there are no more records to - * read. - * - * The function is similar to kmsg_dump_get_line(), but grabs no locks. - */ -bool kmsg_dump_get_line_nolock(struct kmsg_dumper *dumper, bool syslog, - char *line, size_t size, size_t *len) -{ - struct printk_log *msg; - size_t l = 0; - bool ret = false; - - if (!dumper->active) - goto out; - - if (dumper->cur_seq < log_first_seq) { - /* messages are gone, move to first available one */ - dumper->cur_seq = log_first_seq; - dumper->cur_idx = log_first_idx; - } - - /* last entry */ - if (dumper->cur_seq >= log_next_seq) - goto out; - - msg = log_from_idx(dumper->cur_idx); - l = msg_print_text(msg, 0, syslog, line, size); - - dumper->cur_idx = log_next(dumper->cur_idx); - dumper->cur_seq++; - ret = true; -out: - if (len) - *len = l; - return ret; -} - -/** - * kmsg_dump_get_line - retrieve one kmsg log line - * @dumper: registered kmsg dumper - * @syslog: include the "<4>" prefixes - * @line: buffer to copy the line to - * @size: maximum size of the buffer - * @len: length of line placed into buffer - * - * Start at the beginning of the kmsg buffer, with the oldest kmsg - * record, and copy one record into the provided buffer. - * - * Consecutive calls will return the next available record moving - * towards the end of the buffer with the youngest messages. - * - * A return value of FALSE indicates that there are no more records to - * read. - */ -bool kmsg_dump_get_line(struct kmsg_dumper *dumper, bool syslog, - char *line, size_t size, size_t *len) -{ - unsigned long flags; - bool ret; - - raw_spin_lock_irqsave(&logbuf_lock, flags); - ret = kmsg_dump_get_line_nolock(dumper, syslog, line, size, len); - raw_spin_unlock_irqrestore(&logbuf_lock, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(kmsg_dump_get_line); - -/** - * kmsg_dump_get_buffer - copy kmsg log lines - * @dumper: registered kmsg dumper - * @syslog: include the "<4>" prefixes - * @buf: buffer to copy the line to - * @size: maximum size of the buffer - * @len: length of line placed into buffer - * - * Start at the end of the kmsg buffer and fill the provided buffer - * with as many of the the *youngest* kmsg records that fit into it. - * If the buffer is large enough, all available kmsg records will be - * copied with a single call. - * - * Consecutive calls will fill the buffer with the next block of - * available older records, not including the earlier retrieved ones. - * - * A return value of FALSE indicates that there are no more records to - * read. - */ -bool kmsg_dump_get_buffer(struct kmsg_dumper *dumper, bool syslog, - char *buf, size_t size, size_t *len) -{ - unsigned long flags; - u64 seq; - u32 idx; - u64 next_seq; - u32 next_idx; - enum log_flags prev; - size_t l = 0; - bool ret = false; - - if (!dumper->active) - goto out; - - raw_spin_lock_irqsave(&logbuf_lock, flags); - if (dumper->cur_seq < log_first_seq) { - /* messages are gone, move to first available one */ - dumper->cur_seq = log_first_seq; - dumper->cur_idx = log_first_idx; - } - - /* last entry */ - if (dumper->cur_seq >= dumper->next_seq) { - raw_spin_unlock_irqrestore(&logbuf_lock, flags); - goto out; - } - - /* calculate length of entire buffer */ - seq = dumper->cur_seq; - idx = dumper->cur_idx; - prev = 0; - while (seq < dumper->next_seq) { - struct printk_log *msg = log_from_idx(idx); - - l += msg_print_text(msg, prev, true, NULL, 0); - idx = log_next(idx); - seq++; - prev = msg->flags; - } - - /* move first record forward until length fits into the buffer */ - seq = dumper->cur_seq; - idx = dumper->cur_idx; - prev = 0; - while (l > size && seq < dumper->next_seq) { - struct printk_log *msg = log_from_idx(idx); - - l -= msg_print_text(msg, prev, true, NULL, 0); - idx = log_next(idx); - seq++; - prev = msg->flags; - } - - /* last message in next interation */ - next_seq = seq; - next_idx = idx; - - l = 0; - while (seq < dumper->next_seq) { - struct printk_log *msg = log_from_idx(idx); - - l += msg_print_text(msg, prev, syslog, buf + l, size - l); - idx = log_next(idx); - seq++; - prev = msg->flags; - } - - dumper->next_seq = next_seq; - dumper->next_idx = next_idx; - ret = true; - raw_spin_unlock_irqrestore(&logbuf_lock, flags); -out: - if (len) - *len = l; - return ret; -} -EXPORT_SYMBOL_GPL(kmsg_dump_get_buffer); - -/** - * kmsg_dump_rewind_nolock - reset the interator (unlocked version) - * @dumper: registered kmsg dumper - * - * Reset the dumper's iterator so that kmsg_dump_get_line() and - * kmsg_dump_get_buffer() can be called again and used multiple - * times within the same dumper.dump() callback. - * - * The function is similar to kmsg_dump_rewind(), but grabs no locks. - */ -void kmsg_dump_rewind_nolock(struct kmsg_dumper *dumper) -{ - dumper->cur_seq = clear_seq; - dumper->cur_idx = clear_idx; - dumper->next_seq = log_next_seq; - dumper->next_idx = log_next_idx; -} - -/** - * kmsg_dump_rewind - reset the interator - * @dumper: registered kmsg dumper - * - * Reset the dumper's iterator so that kmsg_dump_get_line() and - * kmsg_dump_get_buffer() can be called again and used multiple - * times within the same dumper.dump() callback. - */ -void kmsg_dump_rewind(struct kmsg_dumper *dumper) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&logbuf_lock, flags); - kmsg_dump_rewind_nolock(dumper); - raw_spin_unlock_irqrestore(&logbuf_lock, flags); -} -EXPORT_SYMBOL_GPL(kmsg_dump_rewind); - -static char dump_stack_arch_desc_str[128]; - -/** - * dump_stack_set_arch_desc - set arch-specific str to show with task dumps - * @fmt: printf-style format string - * @...: arguments for the format string - * - * The configured string will be printed right after utsname during task - * dumps. Usually used to add arch-specific system identifiers. If an - * arch wants to make use of such an ID string, it should initialize this - * as soon as possible during boot. - */ -void __init dump_stack_set_arch_desc(const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - vsnprintf(dump_stack_arch_desc_str, sizeof(dump_stack_arch_desc_str), - fmt, args); - va_end(args); -} - -/** - * dump_stack_print_info - print generic debug info for dump_stack() - * @log_lvl: log level - * - * Arch-specific dump_stack() implementations can use this function to - * print out the same debug information as the generic dump_stack(). - */ -void dump_stack_print_info(const char *log_lvl) -{ - printk("%sCPU: %d PID: %d Comm: %.20s %s %s %.*s\n", - log_lvl, raw_smp_processor_id(), current->pid, current->comm, - print_tainted(), init_utsname()->release, - (int)strcspn(init_utsname()->version, " "), - init_utsname()->version); - - if (dump_stack_arch_desc_str[0] != '\0') - printk("%sHardware name: %s\n", - log_lvl, dump_stack_arch_desc_str); - - print_worker_info(log_lvl, current); -} - -/** - * show_regs_print_info - print generic debug info for show_regs() - * @log_lvl: log level - * - * show_regs() implementations can use this function to print out generic - * debug information. - */ -void show_regs_print_info(const char *log_lvl) -{ - dump_stack_print_info(log_lvl); - - printk("%stask: %p task.stack: %p\n", - log_lvl, current, task_stack_page(current)); -} - -#endif diff --git a/src/linux/kernel/ptrace.c b/src/linux/kernel/ptrace.c deleted file mode 100644 index e6474f7..0000000 --- a/src/linux/kernel/ptrace.c +++ /dev/null @@ -1,1270 +0,0 @@ -/* - * linux/kernel/ptrace.c - * - * (C) Copyright 1999 Linus Torvalds - * - * Common interfaces for "ptrace()" which we do not want - * to continually duplicate across every architecture. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -/* - * ptrace a task: make the debugger its new parent and - * move it to the ptrace list. - * - * Must be called with the tasklist lock write-held. - */ -void __ptrace_link(struct task_struct *child, struct task_struct *new_parent) -{ - BUG_ON(!list_empty(&child->ptrace_entry)); - list_add(&child->ptrace_entry, &new_parent->ptraced); - child->parent = new_parent; -} - -/** - * __ptrace_unlink - unlink ptracee and restore its execution state - * @child: ptracee to be unlinked - * - * Remove @child from the ptrace list, move it back to the original parent, - * and restore the execution state so that it conforms to the group stop - * state. - * - * Unlinking can happen via two paths - explicit PTRACE_DETACH or ptracer - * exiting. For PTRACE_DETACH, unless the ptracee has been killed between - * ptrace_check_attach() and here, it's guaranteed to be in TASK_TRACED. - * If the ptracer is exiting, the ptracee can be in any state. - * - * After detach, the ptracee should be in a state which conforms to the - * group stop. If the group is stopped or in the process of stopping, the - * ptracee should be put into TASK_STOPPED; otherwise, it should be woken - * up from TASK_TRACED. - * - * If the ptracee is in TASK_TRACED and needs to be moved to TASK_STOPPED, - * it goes through TRACED -> RUNNING -> STOPPED transition which is similar - * to but in the opposite direction of what happens while attaching to a - * stopped task. However, in this direction, the intermediate RUNNING - * state is not hidden even from the current ptracer and if it immediately - * re-attaches and performs a WNOHANG wait(2), it may fail. - * - * CONTEXT: - * write_lock_irq(tasklist_lock) - */ -void __ptrace_unlink(struct task_struct *child) -{ - BUG_ON(!child->ptrace); - - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - - child->parent = child->real_parent; - list_del_init(&child->ptrace_entry); - - spin_lock(&child->sighand->siglock); - child->ptrace = 0; - /* - * Clear all pending traps and TRAPPING. TRAPPING should be - * cleared regardless of JOBCTL_STOP_PENDING. Do it explicitly. - */ - task_clear_jobctl_pending(child, JOBCTL_TRAP_MASK); - task_clear_jobctl_trapping(child); - - /* - * Reinstate JOBCTL_STOP_PENDING if group stop is in effect and - * @child isn't dead. - */ - if (!(child->flags & PF_EXITING) && - (child->signal->flags & SIGNAL_STOP_STOPPED || - child->signal->group_stop_count)) { - child->jobctl |= JOBCTL_STOP_PENDING; - - /* - * This is only possible if this thread was cloned by the - * traced task running in the stopped group, set the signal - * for the future reports. - * FIXME: we should change ptrace_init_task() to handle this - * case. - */ - if (!(child->jobctl & JOBCTL_STOP_SIGMASK)) - child->jobctl |= SIGSTOP; - } - - /* - * If transition to TASK_STOPPED is pending or in TASK_TRACED, kick - * @child in the butt. Note that @resume should be used iff @child - * is in TASK_TRACED; otherwise, we might unduly disrupt - * TASK_KILLABLE sleeps. - */ - if (child->jobctl & JOBCTL_STOP_PENDING || task_is_traced(child)) - ptrace_signal_wake_up(child, true); - - spin_unlock(&child->sighand->siglock); -} - -/* Ensure that nothing can wake it up, even SIGKILL */ -static bool ptrace_freeze_traced(struct task_struct *task) -{ - bool ret = false; - - /* Lockless, nobody but us can set this flag */ - if (task->jobctl & JOBCTL_LISTENING) - return ret; - - spin_lock_irq(&task->sighand->siglock); - if (task_is_traced(task) && !__fatal_signal_pending(task)) { - task->state = __TASK_TRACED; - ret = true; - } - spin_unlock_irq(&task->sighand->siglock); - - return ret; -} - -static void ptrace_unfreeze_traced(struct task_struct *task) -{ - if (task->state != __TASK_TRACED) - return; - - WARN_ON(!task->ptrace || task->parent != current); - - spin_lock_irq(&task->sighand->siglock); - if (__fatal_signal_pending(task)) - wake_up_state(task, __TASK_TRACED); - else - task->state = TASK_TRACED; - spin_unlock_irq(&task->sighand->siglock); -} - -/** - * ptrace_check_attach - check whether ptracee is ready for ptrace operation - * @child: ptracee to check for - * @ignore_state: don't check whether @child is currently %TASK_TRACED - * - * Check whether @child is being ptraced by %current and ready for further - * ptrace operations. If @ignore_state is %false, @child also should be in - * %TASK_TRACED state and on return the child is guaranteed to be traced - * and not executing. If @ignore_state is %true, @child can be in any - * state. - * - * CONTEXT: - * Grabs and releases tasklist_lock and @child->sighand->siglock. - * - * RETURNS: - * 0 on success, -ESRCH if %child is not ready. - */ -static int ptrace_check_attach(struct task_struct *child, bool ignore_state) -{ - int ret = -ESRCH; - - /* - * We take the read lock around doing both checks to close a - * possible race where someone else was tracing our child and - * detached between these two checks. After this locked check, - * we are sure that this is our traced child and that can only - * be changed by us so it's not changing right after this. - */ - read_lock(&tasklist_lock); - if (child->ptrace && child->parent == current) { - WARN_ON(child->state == __TASK_TRACED); - /* - * child->sighand can't be NULL, release_task() - * does ptrace_unlink() before __exit_signal(). - */ - if (ignore_state || ptrace_freeze_traced(child)) - ret = 0; - } - read_unlock(&tasklist_lock); - - if (!ret && !ignore_state) { - if (!wait_task_inactive(child, __TASK_TRACED)) { - /* - * This can only happen if may_ptrace_stop() fails and - * ptrace_stop() changes ->state back to TASK_RUNNING, - * so we should not worry about leaking __TASK_TRACED. - */ - WARN_ON(child->state == __TASK_TRACED); - ret = -ESRCH; - } - } - - return ret; -} - -static int ptrace_has_cap(struct user_namespace *ns, unsigned int mode) -{ - if (mode & PTRACE_MODE_NOAUDIT) - return has_ns_capability_noaudit(current, ns, CAP_SYS_PTRACE); - else - return has_ns_capability(current, ns, CAP_SYS_PTRACE); -} - -/* Returns 0 on success, -errno on denial. */ -static int __ptrace_may_access(struct task_struct *task, unsigned int mode) -{ - const struct cred *cred = current_cred(), *tcred; - int dumpable = 0; - kuid_t caller_uid; - kgid_t caller_gid; - - if (!(mode & PTRACE_MODE_FSCREDS) == !(mode & PTRACE_MODE_REALCREDS)) { - WARN(1, "denying ptrace access check without PTRACE_MODE_*CREDS\n"); - return -EPERM; - } - - /* May we inspect the given task? - * This check is used both for attaching with ptrace - * and for allowing access to sensitive information in /proc. - * - * ptrace_attach denies several cases that /proc allows - * because setting up the necessary parent/child relationship - * or halting the specified task is impossible. - */ - - /* Don't let security modules deny introspection */ - if (same_thread_group(task, current)) - return 0; - rcu_read_lock(); - if (mode & PTRACE_MODE_FSCREDS) { - caller_uid = cred->fsuid; - caller_gid = cred->fsgid; - } else { - /* - * Using the euid would make more sense here, but something - * in userland might rely on the old behavior, and this - * shouldn't be a security problem since - * PTRACE_MODE_REALCREDS implies that the caller explicitly - * used a syscall that requests access to another process - * (and not a filesystem syscall to procfs). - */ - caller_uid = cred->uid; - caller_gid = cred->gid; - } - tcred = __task_cred(task); - if (uid_eq(caller_uid, tcred->euid) && - uid_eq(caller_uid, tcred->suid) && - uid_eq(caller_uid, tcred->uid) && - gid_eq(caller_gid, tcred->egid) && - gid_eq(caller_gid, tcred->sgid) && - gid_eq(caller_gid, tcred->gid)) - goto ok; - if (ptrace_has_cap(tcred->user_ns, mode)) - goto ok; - rcu_read_unlock(); - return -EPERM; -ok: - rcu_read_unlock(); - smp_rmb(); - if (task->mm) - dumpable = get_dumpable(task->mm); - rcu_read_lock(); - if (dumpable != SUID_DUMP_USER && - !ptrace_has_cap(__task_cred(task)->user_ns, mode)) { - rcu_read_unlock(); - return -EPERM; - } - rcu_read_unlock(); - - return security_ptrace_access_check(task, mode); -} - -bool ptrace_may_access(struct task_struct *task, unsigned int mode) -{ - int err; - task_lock(task); - err = __ptrace_may_access(task, mode); - task_unlock(task); - return !err; -} - -static int ptrace_attach(struct task_struct *task, long request, - unsigned long addr, - unsigned long flags) -{ - bool seize = (request == PTRACE_SEIZE); - int retval; - - retval = -EIO; - if (seize) { - if (addr != 0) - goto out; - if (flags & ~(unsigned long)PTRACE_O_MASK) - goto out; - flags = PT_PTRACED | PT_SEIZED | (flags << PT_OPT_FLAG_SHIFT); - } else { - flags = PT_PTRACED; - } - - audit_ptrace(task); - - retval = -EPERM; - if (unlikely(task->flags & PF_KTHREAD)) - goto out; - if (same_thread_group(task, current)) - goto out; - - /* - * Protect exec's credential calculations against our interference; - * SUID, SGID and LSM creds get determined differently - * under ptrace. - */ - retval = -ERESTARTNOINTR; - if (mutex_lock_interruptible(&task->signal->cred_guard_mutex)) - goto out; - - task_lock(task); - retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH_REALCREDS); - task_unlock(task); - if (retval) - goto unlock_creds; - - write_lock_irq(&tasklist_lock); - retval = -EPERM; - if (unlikely(task->exit_state)) - goto unlock_tasklist; - if (task->ptrace) - goto unlock_tasklist; - - if (seize) - flags |= PT_SEIZED; - rcu_read_lock(); - if (ns_capable(__task_cred(task)->user_ns, CAP_SYS_PTRACE)) - flags |= PT_PTRACE_CAP; - rcu_read_unlock(); - task->ptrace = flags; - - __ptrace_link(task, current); - - /* SEIZE doesn't trap tracee on attach */ - if (!seize) - send_sig_info(SIGSTOP, SEND_SIG_FORCED, task); - - spin_lock(&task->sighand->siglock); - - /* - * If the task is already STOPPED, set JOBCTL_TRAP_STOP and - * TRAPPING, and kick it so that it transits to TRACED. TRAPPING - * will be cleared if the child completes the transition or any - * event which clears the group stop states happens. We'll wait - * for the transition to complete before returning from this - * function. - * - * This hides STOPPED -> RUNNING -> TRACED transition from the - * attaching thread but a different thread in the same group can - * still observe the transient RUNNING state. IOW, if another - * thread's WNOHANG wait(2) on the stopped tracee races against - * ATTACH, the wait(2) may fail due to the transient RUNNING. - * - * The following task_is_stopped() test is safe as both transitions - * in and out of STOPPED are protected by siglock. - */ - if (task_is_stopped(task) && - task_set_jobctl_pending(task, JOBCTL_TRAP_STOP | JOBCTL_TRAPPING)) - signal_wake_up_state(task, __TASK_STOPPED); - - spin_unlock(&task->sighand->siglock); - - retval = 0; -unlock_tasklist: - write_unlock_irq(&tasklist_lock); -unlock_creds: - mutex_unlock(&task->signal->cred_guard_mutex); -out: - if (!retval) { - /* - * We do not bother to change retval or clear JOBCTL_TRAPPING - * if wait_on_bit() was interrupted by SIGKILL. The tracer will - * not return to user-mode, it will exit and clear this bit in - * __ptrace_unlink() if it wasn't already cleared by the tracee; - * and until then nobody can ptrace this task. - */ - wait_on_bit(&task->jobctl, JOBCTL_TRAPPING_BIT, TASK_KILLABLE); - proc_ptrace_connector(task, PTRACE_ATTACH); - } - - return retval; -} - -/** - * ptrace_traceme -- helper for PTRACE_TRACEME - * - * Performs checks and sets PT_PTRACED. - * Should be used by all ptrace implementations for PTRACE_TRACEME. - */ -static int ptrace_traceme(void) -{ - int ret = -EPERM; - - write_lock_irq(&tasklist_lock); - /* Are we already being traced? */ - if (!current->ptrace) { - ret = security_ptrace_traceme(current->parent); - /* - * Check PF_EXITING to ensure ->real_parent has not passed - * exit_ptrace(). Otherwise we don't report the error but - * pretend ->real_parent untraces us right after return. - */ - if (!ret && !(current->real_parent->flags & PF_EXITING)) { - current->ptrace = PT_PTRACED; - __ptrace_link(current, current->real_parent); - } - } - write_unlock_irq(&tasklist_lock); - - return ret; -} - -/* - * Called with irqs disabled, returns true if childs should reap themselves. - */ -static int ignoring_children(struct sighand_struct *sigh) -{ - int ret; - spin_lock(&sigh->siglock); - ret = (sigh->action[SIGCHLD-1].sa.sa_handler == SIG_IGN) || - (sigh->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT); - spin_unlock(&sigh->siglock); - return ret; -} - -/* - * Called with tasklist_lock held for writing. - * Unlink a traced task, and clean it up if it was a traced zombie. - * Return true if it needs to be reaped with release_task(). - * (We can't call release_task() here because we already hold tasklist_lock.) - * - * If it's a zombie, our attachedness prevented normal parent notification - * or self-reaping. Do notification now if it would have happened earlier. - * If it should reap itself, return true. - * - * If it's our own child, there is no notification to do. But if our normal - * children self-reap, then this child was prevented by ptrace and we must - * reap it now, in that case we must also wake up sub-threads sleeping in - * do_wait(). - */ -static bool __ptrace_detach(struct task_struct *tracer, struct task_struct *p) -{ - bool dead; - - __ptrace_unlink(p); - - if (p->exit_state != EXIT_ZOMBIE) - return false; - - dead = !thread_group_leader(p); - - if (!dead && thread_group_empty(p)) { - if (!same_thread_group(p->real_parent, tracer)) - dead = do_notify_parent(p, p->exit_signal); - else if (ignoring_children(tracer->sighand)) { - __wake_up_parent(p, tracer); - dead = true; - } - } - /* Mark it as in the process of being reaped. */ - if (dead) - p->exit_state = EXIT_DEAD; - return dead; -} - -static int ptrace_detach(struct task_struct *child, unsigned int data) -{ - if (!valid_signal(data)) - return -EIO; - - /* Architecture-specific hardware disable .. */ - ptrace_disable(child); - - write_lock_irq(&tasklist_lock); - /* - * We rely on ptrace_freeze_traced(). It can't be killed and - * untraced by another thread, it can't be a zombie. - */ - WARN_ON(!child->ptrace || child->exit_state); - /* - * tasklist_lock avoids the race with wait_task_stopped(), see - * the comment in ptrace_resume(). - */ - child->exit_code = data; - __ptrace_detach(current, child); - write_unlock_irq(&tasklist_lock); - - proc_ptrace_connector(child, PTRACE_DETACH); - - return 0; -} - -/* - * Detach all tasks we were using ptrace on. Called with tasklist held - * for writing. - */ -void exit_ptrace(struct task_struct *tracer, struct list_head *dead) -{ - struct task_struct *p, *n; - - list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) { - if (unlikely(p->ptrace & PT_EXITKILL)) - send_sig_info(SIGKILL, SEND_SIG_FORCED, p); - - if (__ptrace_detach(tracer, p)) - list_add(&p->ptrace_entry, dead); - } -} - -int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len) -{ - int copied = 0; - - while (len > 0) { - char buf[128]; - int this_len, retval; - - this_len = (len > sizeof(buf)) ? sizeof(buf) : len; - retval = access_process_vm(tsk, src, buf, this_len, FOLL_FORCE); - if (!retval) { - if (copied) - break; - return -EIO; - } - if (copy_to_user(dst, buf, retval)) - return -EFAULT; - copied += retval; - src += retval; - dst += retval; - len -= retval; - } - return copied; -} - -int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len) -{ - int copied = 0; - - while (len > 0) { - char buf[128]; - int this_len, retval; - - this_len = (len > sizeof(buf)) ? sizeof(buf) : len; - if (copy_from_user(buf, src, this_len)) - return -EFAULT; - retval = access_process_vm(tsk, dst, buf, this_len, - FOLL_FORCE | FOLL_WRITE); - if (!retval) { - if (copied) - break; - return -EIO; - } - copied += retval; - src += retval; - dst += retval; - len -= retval; - } - return copied; -} - -static int ptrace_setoptions(struct task_struct *child, unsigned long data) -{ - unsigned flags; - - if (data & ~(unsigned long)PTRACE_O_MASK) - return -EINVAL; - - if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) { - if (!IS_ENABLED(CONFIG_CHECKPOINT_RESTORE) || - !IS_ENABLED(CONFIG_SECCOMP)) - return -EINVAL; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - if (seccomp_mode(¤t->seccomp) != SECCOMP_MODE_DISABLED || - current->ptrace & PT_SUSPEND_SECCOMP) - return -EPERM; - } - - /* Avoid intermediate state when all opts are cleared */ - flags = child->ptrace; - flags &= ~(PTRACE_O_MASK << PT_OPT_FLAG_SHIFT); - flags |= (data << PT_OPT_FLAG_SHIFT); - child->ptrace = flags; - - return 0; -} - -static int ptrace_getsiginfo(struct task_struct *child, siginfo_t *info) -{ - unsigned long flags; - int error = -ESRCH; - - if (lock_task_sighand(child, &flags)) { - error = -EINVAL; - if (likely(child->last_siginfo != NULL)) { - *info = *child->last_siginfo; - error = 0; - } - unlock_task_sighand(child, &flags); - } - return error; -} - -static int ptrace_setsiginfo(struct task_struct *child, const siginfo_t *info) -{ - unsigned long flags; - int error = -ESRCH; - - if (lock_task_sighand(child, &flags)) { - error = -EINVAL; - if (likely(child->last_siginfo != NULL)) { - *child->last_siginfo = *info; - error = 0; - } - unlock_task_sighand(child, &flags); - } - return error; -} - -static int ptrace_peek_siginfo(struct task_struct *child, - unsigned long addr, - unsigned long data) -{ - struct ptrace_peeksiginfo_args arg; - struct sigpending *pending; - struct sigqueue *q; - int ret, i; - - ret = copy_from_user(&arg, (void __user *) addr, - sizeof(struct ptrace_peeksiginfo_args)); - if (ret) - return -EFAULT; - - if (arg.flags & ~PTRACE_PEEKSIGINFO_SHARED) - return -EINVAL; /* unknown flags */ - - if (arg.nr < 0) - return -EINVAL; - - if (arg.flags & PTRACE_PEEKSIGINFO_SHARED) - pending = &child->signal->shared_pending; - else - pending = &child->pending; - - for (i = 0; i < arg.nr; ) { - siginfo_t info; - s32 off = arg.off + i; - - spin_lock_irq(&child->sighand->siglock); - list_for_each_entry(q, &pending->list, list) { - if (!off--) { - copy_siginfo(&info, &q->info); - break; - } - } - spin_unlock_irq(&child->sighand->siglock); - - if (off >= 0) /* beyond the end of the list */ - break; - -#ifdef CONFIG_COMPAT - if (unlikely(in_compat_syscall())) { - compat_siginfo_t __user *uinfo = compat_ptr(data); - - if (copy_siginfo_to_user32(uinfo, &info) || - __put_user(info.si_code, &uinfo->si_code)) { - ret = -EFAULT; - break; - } - - } else -#endif - { - siginfo_t __user *uinfo = (siginfo_t __user *) data; - - if (copy_siginfo_to_user(uinfo, &info) || - __put_user(info.si_code, &uinfo->si_code)) { - ret = -EFAULT; - break; - } - } - - data += sizeof(siginfo_t); - i++; - - if (signal_pending(current)) - break; - - cond_resched(); - } - - if (i > 0) - return i; - - return ret; -} - -#ifdef PTRACE_SINGLESTEP -#define is_singlestep(request) ((request) == PTRACE_SINGLESTEP) -#else -#define is_singlestep(request) 0 -#endif - -#ifdef PTRACE_SINGLEBLOCK -#define is_singleblock(request) ((request) == PTRACE_SINGLEBLOCK) -#else -#define is_singleblock(request) 0 -#endif - -#ifdef PTRACE_SYSEMU -#define is_sysemu_singlestep(request) ((request) == PTRACE_SYSEMU_SINGLESTEP) -#else -#define is_sysemu_singlestep(request) 0 -#endif - -static int ptrace_resume(struct task_struct *child, long request, - unsigned long data) -{ - bool need_siglock; - - if (!valid_signal(data)) - return -EIO; - - if (request == PTRACE_SYSCALL) - set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - else - clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); - -#ifdef TIF_SYSCALL_EMU - if (request == PTRACE_SYSEMU || request == PTRACE_SYSEMU_SINGLESTEP) - set_tsk_thread_flag(child, TIF_SYSCALL_EMU); - else - clear_tsk_thread_flag(child, TIF_SYSCALL_EMU); -#endif - - if (is_singleblock(request)) { - if (unlikely(!arch_has_block_step())) - return -EIO; - user_enable_block_step(child); - } else if (is_singlestep(request) || is_sysemu_singlestep(request)) { - if (unlikely(!arch_has_single_step())) - return -EIO; - user_enable_single_step(child); - } else { - user_disable_single_step(child); - } - - /* - * Change ->exit_code and ->state under siglock to avoid the race - * with wait_task_stopped() in between; a non-zero ->exit_code will - * wrongly look like another report from tracee. - * - * Note that we need siglock even if ->exit_code == data and/or this - * status was not reported yet, the new status must not be cleared by - * wait_task_stopped() after resume. - * - * If data == 0 we do not care if wait_task_stopped() reports the old - * status and clears the code too; this can't race with the tracee, it - * takes siglock after resume. - */ - need_siglock = data && !thread_group_empty(current); - if (need_siglock) - spin_lock_irq(&child->sighand->siglock); - child->exit_code = data; - wake_up_state(child, __TASK_TRACED); - if (need_siglock) - spin_unlock_irq(&child->sighand->siglock); - - return 0; -} - -#ifdef CONFIG_HAVE_ARCH_TRACEHOOK - -static const struct user_regset * -find_regset(const struct user_regset_view *view, unsigned int type) -{ - const struct user_regset *regset; - int n; - - for (n = 0; n < view->n; ++n) { - regset = view->regsets + n; - if (regset->core_note_type == type) - return regset; - } - - return NULL; -} - -static int ptrace_regset(struct task_struct *task, int req, unsigned int type, - struct iovec *kiov) -{ - const struct user_regset_view *view = task_user_regset_view(task); - const struct user_regset *regset = find_regset(view, type); - int regset_no; - - if (!regset || (kiov->iov_len % regset->size) != 0) - return -EINVAL; - - regset_no = regset - view->regsets; - kiov->iov_len = min(kiov->iov_len, - (__kernel_size_t) (regset->n * regset->size)); - - if (req == PTRACE_GETREGSET) - return copy_regset_to_user(task, view, regset_no, 0, - kiov->iov_len, kiov->iov_base); - else - return copy_regset_from_user(task, view, regset_no, 0, - kiov->iov_len, kiov->iov_base); -} - -/* - * This is declared in linux/regset.h and defined in machine-dependent - * code. We put the export here, near the primary machine-neutral use, - * to ensure no machine forgets it. - */ -EXPORT_SYMBOL_GPL(task_user_regset_view); -#endif - -int ptrace_request(struct task_struct *child, long request, - unsigned long addr, unsigned long data) -{ - bool seized = child->ptrace & PT_SEIZED; - int ret = -EIO; - siginfo_t siginfo, *si; - void __user *datavp = (void __user *) data; - unsigned long __user *datalp = datavp; - unsigned long flags; - - switch (request) { - case PTRACE_PEEKTEXT: - case PTRACE_PEEKDATA: - return generic_ptrace_peekdata(child, addr, data); - case PTRACE_POKETEXT: - case PTRACE_POKEDATA: - return generic_ptrace_pokedata(child, addr, data); - -#ifdef PTRACE_OLDSETOPTIONS - case PTRACE_OLDSETOPTIONS: -#endif - case PTRACE_SETOPTIONS: - ret = ptrace_setoptions(child, data); - break; - case PTRACE_GETEVENTMSG: - ret = put_user(child->ptrace_message, datalp); - break; - - case PTRACE_PEEKSIGINFO: - ret = ptrace_peek_siginfo(child, addr, data); - break; - - case PTRACE_GETSIGINFO: - ret = ptrace_getsiginfo(child, &siginfo); - if (!ret) - ret = copy_siginfo_to_user(datavp, &siginfo); - break; - - case PTRACE_SETSIGINFO: - if (copy_from_user(&siginfo, datavp, sizeof siginfo)) - ret = -EFAULT; - else - ret = ptrace_setsiginfo(child, &siginfo); - break; - - case PTRACE_GETSIGMASK: - if (addr != sizeof(sigset_t)) { - ret = -EINVAL; - break; - } - - if (copy_to_user(datavp, &child->blocked, sizeof(sigset_t))) - ret = -EFAULT; - else - ret = 0; - - break; - - case PTRACE_SETSIGMASK: { - sigset_t new_set; - - if (addr != sizeof(sigset_t)) { - ret = -EINVAL; - break; - } - - if (copy_from_user(&new_set, datavp, sizeof(sigset_t))) { - ret = -EFAULT; - break; - } - - sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); - - /* - * Every thread does recalc_sigpending() after resume, so - * retarget_shared_pending() and recalc_sigpending() are not - * called here. - */ - spin_lock_irq(&child->sighand->siglock); - child->blocked = new_set; - spin_unlock_irq(&child->sighand->siglock); - - ret = 0; - break; - } - - case PTRACE_INTERRUPT: - /* - * Stop tracee without any side-effect on signal or job - * control. At least one trap is guaranteed to happen - * after this request. If @child is already trapped, the - * current trap is not disturbed and another trap will - * happen after the current trap is ended with PTRACE_CONT. - * - * The actual trap might not be PTRACE_EVENT_STOP trap but - * the pending condition is cleared regardless. - */ - if (unlikely(!seized || !lock_task_sighand(child, &flags))) - break; - - /* - * INTERRUPT doesn't disturb existing trap sans one - * exception. If ptracer issued LISTEN for the current - * STOP, this INTERRUPT should clear LISTEN and re-trap - * tracee into STOP. - */ - if (likely(task_set_jobctl_pending(child, JOBCTL_TRAP_STOP))) - ptrace_signal_wake_up(child, child->jobctl & JOBCTL_LISTENING); - - unlock_task_sighand(child, &flags); - ret = 0; - break; - - case PTRACE_LISTEN: - /* - * Listen for events. Tracee must be in STOP. It's not - * resumed per-se but is not considered to be in TRACED by - * wait(2) or ptrace(2). If an async event (e.g. group - * stop state change) happens, tracee will enter STOP trap - * again. Alternatively, ptracer can issue INTERRUPT to - * finish listening and re-trap tracee into STOP. - */ - if (unlikely(!seized || !lock_task_sighand(child, &flags))) - break; - - si = child->last_siginfo; - if (likely(si && (si->si_code >> 8) == PTRACE_EVENT_STOP)) { - child->jobctl |= JOBCTL_LISTENING; - /* - * If NOTIFY is set, it means event happened between - * start of this trap and now. Trigger re-trap. - */ - if (child->jobctl & JOBCTL_TRAP_NOTIFY) - ptrace_signal_wake_up(child, true); - ret = 0; - } - unlock_task_sighand(child, &flags); - break; - - case PTRACE_DETACH: /* detach a process that was attached. */ - ret = ptrace_detach(child, data); - break; - -#ifdef CONFIG_BINFMT_ELF_FDPIC - case PTRACE_GETFDPIC: { - struct mm_struct *mm = get_task_mm(child); - unsigned long tmp = 0; - - ret = -ESRCH; - if (!mm) - break; - - switch (addr) { - case PTRACE_GETFDPIC_EXEC: - tmp = mm->context.exec_fdpic_loadmap; - break; - case PTRACE_GETFDPIC_INTERP: - tmp = mm->context.interp_fdpic_loadmap; - break; - default: - break; - } - mmput(mm); - - ret = put_user(tmp, datalp); - break; - } -#endif - -#ifdef PTRACE_SINGLESTEP - case PTRACE_SINGLESTEP: -#endif -#ifdef PTRACE_SINGLEBLOCK - case PTRACE_SINGLEBLOCK: -#endif -#ifdef PTRACE_SYSEMU - case PTRACE_SYSEMU: - case PTRACE_SYSEMU_SINGLESTEP: -#endif - case PTRACE_SYSCALL: - case PTRACE_CONT: - return ptrace_resume(child, request, data); - - case PTRACE_KILL: - if (child->exit_state) /* already dead */ - return 0; - return ptrace_resume(child, request, SIGKILL); - -#ifdef CONFIG_HAVE_ARCH_TRACEHOOK - case PTRACE_GETREGSET: - case PTRACE_SETREGSET: { - struct iovec kiov; - struct iovec __user *uiov = datavp; - - if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov))) - return -EFAULT; - - if (__get_user(kiov.iov_base, &uiov->iov_base) || - __get_user(kiov.iov_len, &uiov->iov_len)) - return -EFAULT; - - ret = ptrace_regset(child, request, addr, &kiov); - if (!ret) - ret = __put_user(kiov.iov_len, &uiov->iov_len); - break; - } -#endif - - case PTRACE_SECCOMP_GET_FILTER: - ret = seccomp_get_filter(child, addr, datavp); - break; - - default: - break; - } - - return ret; -} - -static struct task_struct *ptrace_get_task_struct(pid_t pid) -{ - struct task_struct *child; - - rcu_read_lock(); - child = find_task_by_vpid(pid); - if (child) - get_task_struct(child); - rcu_read_unlock(); - - if (!child) - return ERR_PTR(-ESRCH); - return child; -} - -#ifndef arch_ptrace_attach -#define arch_ptrace_attach(child) do { } while (0) -#endif - -SYSCALL_DEFINE4(ptrace, long, request, long, pid, unsigned long, addr, - unsigned long, data) -{ - struct task_struct *child; - long ret; - - if (request == PTRACE_TRACEME) { - ret = ptrace_traceme(); - if (!ret) - arch_ptrace_attach(current); - goto out; - } - - child = ptrace_get_task_struct(pid); - if (IS_ERR(child)) { - ret = PTR_ERR(child); - goto out; - } - - if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) { - ret = ptrace_attach(child, request, addr, data); - /* - * Some architectures need to do book-keeping after - * a ptrace attach. - */ - if (!ret) - arch_ptrace_attach(child); - goto out_put_task_struct; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL || - request == PTRACE_INTERRUPT); - if (ret < 0) - goto out_put_task_struct; - - ret = arch_ptrace(child, request, addr, data); - if (ret || request != PTRACE_DETACH) - ptrace_unfreeze_traced(child); - - out_put_task_struct: - put_task_struct(child); - out: - return ret; -} - -int generic_ptrace_peekdata(struct task_struct *tsk, unsigned long addr, - unsigned long data) -{ - unsigned long tmp; - int copied; - - copied = access_process_vm(tsk, addr, &tmp, sizeof(tmp), FOLL_FORCE); - if (copied != sizeof(tmp)) - return -EIO; - return put_user(tmp, (unsigned long __user *)data); -} - -int generic_ptrace_pokedata(struct task_struct *tsk, unsigned long addr, - unsigned long data) -{ - int copied; - - copied = access_process_vm(tsk, addr, &data, sizeof(data), - FOLL_FORCE | FOLL_WRITE); - return (copied == sizeof(data)) ? 0 : -EIO; -} - -#if defined CONFIG_COMPAT - -int compat_ptrace_request(struct task_struct *child, compat_long_t request, - compat_ulong_t addr, compat_ulong_t data) -{ - compat_ulong_t __user *datap = compat_ptr(data); - compat_ulong_t word; - siginfo_t siginfo; - int ret; - - switch (request) { - case PTRACE_PEEKTEXT: - case PTRACE_PEEKDATA: - ret = access_process_vm(child, addr, &word, sizeof(word), - FOLL_FORCE); - if (ret != sizeof(word)) - ret = -EIO; - else - ret = put_user(word, datap); - break; - - case PTRACE_POKETEXT: - case PTRACE_POKEDATA: - ret = access_process_vm(child, addr, &data, sizeof(data), - FOLL_FORCE | FOLL_WRITE); - ret = (ret != sizeof(data) ? -EIO : 0); - break; - - case PTRACE_GETEVENTMSG: - ret = put_user((compat_ulong_t) child->ptrace_message, datap); - break; - - case PTRACE_GETSIGINFO: - ret = ptrace_getsiginfo(child, &siginfo); - if (!ret) - ret = copy_siginfo_to_user32( - (struct compat_siginfo __user *) datap, - &siginfo); - break; - - case PTRACE_SETSIGINFO: - memset(&siginfo, 0, sizeof siginfo); - if (copy_siginfo_from_user32( - &siginfo, (struct compat_siginfo __user *) datap)) - ret = -EFAULT; - else - ret = ptrace_setsiginfo(child, &siginfo); - break; -#ifdef CONFIG_HAVE_ARCH_TRACEHOOK - case PTRACE_GETREGSET: - case PTRACE_SETREGSET: - { - struct iovec kiov; - struct compat_iovec __user *uiov = - (struct compat_iovec __user *) datap; - compat_uptr_t ptr; - compat_size_t len; - - if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov))) - return -EFAULT; - - if (__get_user(ptr, &uiov->iov_base) || - __get_user(len, &uiov->iov_len)) - return -EFAULT; - - kiov.iov_base = compat_ptr(ptr); - kiov.iov_len = len; - - ret = ptrace_regset(child, request, addr, &kiov); - if (!ret) - ret = __put_user(kiov.iov_len, &uiov->iov_len); - break; - } -#endif - - default: - ret = ptrace_request(child, request, addr, data); - } - - return ret; -} - -COMPAT_SYSCALL_DEFINE4(ptrace, compat_long_t, request, compat_long_t, pid, - compat_long_t, addr, compat_long_t, data) -{ - struct task_struct *child; - long ret; - - if (request == PTRACE_TRACEME) { - ret = ptrace_traceme(); - goto out; - } - - child = ptrace_get_task_struct(pid); - if (IS_ERR(child)) { - ret = PTR_ERR(child); - goto out; - } - - if (request == PTRACE_ATTACH || request == PTRACE_SEIZE) { - ret = ptrace_attach(child, request, addr, data); - /* - * Some architectures need to do book-keeping after - * a ptrace attach. - */ - if (!ret) - arch_ptrace_attach(child); - goto out_put_task_struct; - } - - ret = ptrace_check_attach(child, request == PTRACE_KILL || - request == PTRACE_INTERRUPT); - if (!ret) { - ret = compat_arch_ptrace(child, request, addr, data); - if (ret || request != PTRACE_DETACH) - ptrace_unfreeze_traced(child); - } - - out_put_task_struct: - put_task_struct(child); - out: - return ret; -} -#endif /* CONFIG_COMPAT */ diff --git a/src/linux/kernel/range.c b/src/linux/kernel/range.c deleted file mode 100644 index 82cfc28..0000000 --- a/src/linux/kernel/range.c +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Range add and subtract - */ -#include -#include -#include -#include -#include - -int add_range(struct range *range, int az, int nr_range, u64 start, u64 end) -{ - if (start >= end) - return nr_range; - - /* Out of slots: */ - if (nr_range >= az) - return nr_range; - - range[nr_range].start = start; - range[nr_range].end = end; - - nr_range++; - - return nr_range; -} - -int add_range_with_merge(struct range *range, int az, int nr_range, - u64 start, u64 end) -{ - int i; - - if (start >= end) - return nr_range; - - /* get new start/end: */ - for (i = 0; i < nr_range; i++) { - u64 common_start, common_end; - - if (!range[i].end) - continue; - - common_start = max(range[i].start, start); - common_end = min(range[i].end, end); - if (common_start > common_end) - continue; - - /* new start/end, will add it back at last */ - start = min(range[i].start, start); - end = max(range[i].end, end); - - memmove(&range[i], &range[i + 1], - (nr_range - (i + 1)) * sizeof(range[i])); - range[nr_range - 1].start = 0; - range[nr_range - 1].end = 0; - nr_range--; - i--; - } - - /* Need to add it: */ - return add_range(range, az, nr_range, start, end); -} - -void subtract_range(struct range *range, int az, u64 start, u64 end) -{ - int i, j; - - if (start >= end) - return; - - for (j = 0; j < az; j++) { - if (!range[j].end) - continue; - - if (start <= range[j].start && end >= range[j].end) { - range[j].start = 0; - range[j].end = 0; - continue; - } - - if (start <= range[j].start && end < range[j].end && - range[j].start < end) { - range[j].start = end; - continue; - } - - - if (start > range[j].start && end >= range[j].end && - range[j].end > start) { - range[j].end = start; - continue; - } - - if (start > range[j].start && end < range[j].end) { - /* Find the new spare: */ - for (i = 0; i < az; i++) { - if (range[i].end == 0) - break; - } - if (i < az) { - range[i].end = range[j].end; - range[i].start = end; - } else { - pr_err("%s: run out of slot in ranges\n", - __func__); - } - range[j].end = start; - continue; - } - } -} - -static int cmp_range(const void *x1, const void *x2) -{ - const struct range *r1 = x1; - const struct range *r2 = x2; - - if (r1->start < r2->start) - return -1; - if (r1->start > r2->start) - return 1; - return 0; -} - -int clean_sort_range(struct range *range, int az) -{ - int i, j, k = az - 1, nr_range = az; - - for (i = 0; i < k; i++) { - if (range[i].end) - continue; - for (j = k; j > i; j--) { - if (range[j].end) { - k = j; - break; - } - } - if (j == i) - break; - range[i].start = range[k].start; - range[i].end = range[k].end; - range[k].start = 0; - range[k].end = 0; - k--; - } - /* count it */ - for (i = 0; i < az; i++) { - if (!range[i].end) { - nr_range = i; - break; - } - } - - /* sort them */ - sort(range, nr_range, sizeof(struct range), cmp_range, NULL); - - return nr_range; -} - -void sort_range(struct range *range, int nr_range) -{ - /* sort them */ - sort(range, nr_range, sizeof(struct range), cmp_range, NULL); -} diff --git a/src/linux/kernel/rcu/Makefile b/src/linux/kernel/rcu/Makefile deleted file mode 100644 index 18dfc48..0000000 --- a/src/linux/kernel/rcu/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# Any varying coverage in these files is non-deterministic -# and is generally not a function of system call inputs. -KCOV_INSTRUMENT := n - -obj-y += update.o sync.o -obj-$(CONFIG_SRCU) += srcu.o -obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o -obj-$(CONFIG_RCU_PERF_TEST) += rcuperf.o -obj-$(CONFIG_TREE_RCU) += tree.o -obj-$(CONFIG_PREEMPT_RCU) += tree.o -obj-$(CONFIG_TREE_RCU_TRACE) += tree_trace.o -obj-$(CONFIG_TINY_RCU) += tiny.o diff --git a/src/linux/kernel/rcu/rcu.h b/src/linux/kernel/rcu/rcu.h deleted file mode 100644 index 80adef7..0000000 --- a/src/linux/kernel/rcu/rcu.h +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Read-Copy Update definitions shared among RCU implementations. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you can access it online at - * http://www.gnu.org/licenses/gpl-2.0.html. - * - * Copyright IBM Corporation, 2011 - * - * Author: Paul E. McKenney - */ - -#ifndef __LINUX_RCU_H -#define __LINUX_RCU_H - -#include -#ifdef CONFIG_RCU_TRACE -#define RCU_TRACE(stmt) stmt -#else /* #ifdef CONFIG_RCU_TRACE */ -#define RCU_TRACE(stmt) -#endif /* #else #ifdef CONFIG_RCU_TRACE */ - -/* - * Process-level increment to ->dynticks_nesting field. This allows for - * architectures that use half-interrupts and half-exceptions from - * process context. - * - * DYNTICK_TASK_NEST_MASK defines a field of width DYNTICK_TASK_NEST_WIDTH - * that counts the number of process-based reasons why RCU cannot - * consider the corresponding CPU to be idle, and DYNTICK_TASK_NEST_VALUE - * is the value used to increment or decrement this field. - * - * The rest of the bits could in principle be used to count interrupts, - * but this would mean that a negative-one value in the interrupt - * field could incorrectly zero out the DYNTICK_TASK_NEST_MASK field. - * We therefore provide a two-bit guard field defined by DYNTICK_TASK_MASK - * that is set to DYNTICK_TASK_FLAG upon initial exit from idle. - * The DYNTICK_TASK_EXIT_IDLE value is thus the combined value used upon - * initial exit from idle. - */ -#define DYNTICK_TASK_NEST_WIDTH 7 -#define DYNTICK_TASK_NEST_VALUE ((LLONG_MAX >> DYNTICK_TASK_NEST_WIDTH) + 1) -#define DYNTICK_TASK_NEST_MASK (LLONG_MAX - DYNTICK_TASK_NEST_VALUE + 1) -#define DYNTICK_TASK_FLAG ((DYNTICK_TASK_NEST_VALUE / 8) * 2) -#define DYNTICK_TASK_MASK ((DYNTICK_TASK_NEST_VALUE / 8) * 3) -#define DYNTICK_TASK_EXIT_IDLE (DYNTICK_TASK_NEST_VALUE + \ - DYNTICK_TASK_FLAG) - -/* - * debug_rcu_head_queue()/debug_rcu_head_unqueue() are used internally - * by call_rcu() and rcu callback execution, and are therefore not part of the - * RCU API. Leaving in rcupdate.h because they are used by all RCU flavors. - */ - -#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD -# define STATE_RCU_HEAD_READY 0 -# define STATE_RCU_HEAD_QUEUED 1 - -extern struct debug_obj_descr rcuhead_debug_descr; - -static inline int debug_rcu_head_queue(struct rcu_head *head) -{ - int r1; - - r1 = debug_object_activate(head, &rcuhead_debug_descr); - debug_object_active_state(head, &rcuhead_debug_descr, - STATE_RCU_HEAD_READY, - STATE_RCU_HEAD_QUEUED); - return r1; -} - -static inline void debug_rcu_head_unqueue(struct rcu_head *head) -{ - debug_object_active_state(head, &rcuhead_debug_descr, - STATE_RCU_HEAD_QUEUED, - STATE_RCU_HEAD_READY); - debug_object_deactivate(head, &rcuhead_debug_descr); -} -#else /* !CONFIG_DEBUG_OBJECTS_RCU_HEAD */ -static inline int debug_rcu_head_queue(struct rcu_head *head) -{ - return 0; -} - -static inline void debug_rcu_head_unqueue(struct rcu_head *head) -{ -} -#endif /* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */ - -void kfree(const void *); - -/* - * Reclaim the specified callback, either by invoking it (non-lazy case) - * or freeing it directly (lazy case). Return true if lazy, false otherwise. - */ -static inline bool __rcu_reclaim(const char *rn, struct rcu_head *head) -{ - unsigned long offset = (unsigned long)head->func; - - rcu_lock_acquire(&rcu_callback_map); - if (__is_kfree_rcu_offset(offset)) { - RCU_TRACE(trace_rcu_invoke_kfree_callback(rn, head, offset)); - kfree((void *)head - offset); - rcu_lock_release(&rcu_callback_map); - return true; - } else { - RCU_TRACE(trace_rcu_invoke_callback(rn, head)); - head->func(head); - rcu_lock_release(&rcu_callback_map); - return false; - } -} - -#ifdef CONFIG_RCU_STALL_COMMON - -extern int rcu_cpu_stall_suppress; -int rcu_jiffies_till_stall_check(void); - -#endif /* #ifdef CONFIG_RCU_STALL_COMMON */ - -/* - * Strings used in tracepoints need to be exported via the - * tracing system such that tools like perf and trace-cmd can - * translate the string address pointers to actual text. - */ -#define TPS(x) tracepoint_string(x) - -void rcu_early_boot_tests(void); - -/* - * This function really isn't for public consumption, but RCU is special in - * that context switches can allow the state machine to make progress. - */ -extern void resched_cpu(int cpu); - -#endif /* __LINUX_RCU_H */ diff --git a/src/linux/kernel/rcu/srcu.c b/src/linux/kernel/rcu/srcu.c deleted file mode 100644 index 9b9cdd5..0000000 --- a/src/linux/kernel/rcu/srcu.c +++ /dev/null @@ -1,675 +0,0 @@ -/* - * Sleepable Read-Copy Update mechanism for mutual exclusion. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you can access it online at - * http://www.gnu.org/licenses/gpl-2.0.html. - * - * Copyright (C) IBM Corporation, 2006 - * Copyright (C) Fujitsu, 2012 - * - * Author: Paul McKenney - * Lai Jiangshan - * - * For detailed explanation of Read-Copy Update mechanism see - - * Documentation/RCU/ *.txt - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rcu.h" - -/* - * Initialize an rcu_batch structure to empty. - */ -static inline void rcu_batch_init(struct rcu_batch *b) -{ - b->head = NULL; - b->tail = &b->head; -} - -/* - * Enqueue a callback onto the tail of the specified rcu_batch structure. - */ -static inline void rcu_batch_queue(struct rcu_batch *b, struct rcu_head *head) -{ - *b->tail = head; - b->tail = &head->next; -} - -/* - * Is the specified rcu_batch structure empty? - */ -static inline bool rcu_batch_empty(struct rcu_batch *b) -{ - return b->tail == &b->head; -} - -/* - * Remove the callback at the head of the specified rcu_batch structure - * and return a pointer to it, or return NULL if the structure is empty. - */ -static inline struct rcu_head *rcu_batch_dequeue(struct rcu_batch *b) -{ - struct rcu_head *head; - - if (rcu_batch_empty(b)) - return NULL; - - head = b->head; - b->head = head->next; - if (b->tail == &head->next) - rcu_batch_init(b); - - return head; -} - -/* - * Move all callbacks from the rcu_batch structure specified by "from" to - * the structure specified by "to". - */ -static inline void rcu_batch_move(struct rcu_batch *to, struct rcu_batch *from) -{ - if (!rcu_batch_empty(from)) { - *to->tail = from->head; - to->tail = from->tail; - rcu_batch_init(from); - } -} - -static int init_srcu_struct_fields(struct srcu_struct *sp) -{ - sp->completed = 0; - spin_lock_init(&sp->queue_lock); - sp->running = false; - rcu_batch_init(&sp->batch_queue); - rcu_batch_init(&sp->batch_check0); - rcu_batch_init(&sp->batch_check1); - rcu_batch_init(&sp->batch_done); - INIT_DELAYED_WORK(&sp->work, process_srcu); - sp->per_cpu_ref = alloc_percpu(struct srcu_struct_array); - return sp->per_cpu_ref ? 0 : -ENOMEM; -} - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - -int __init_srcu_struct(struct srcu_struct *sp, const char *name, - struct lock_class_key *key) -{ - /* Don't re-initialize a lock while it is held. */ - debug_check_no_locks_freed((void *)sp, sizeof(*sp)); - lockdep_init_map(&sp->dep_map, name, key, 0); - return init_srcu_struct_fields(sp); -} -EXPORT_SYMBOL_GPL(__init_srcu_struct); - -#else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ - -/** - * init_srcu_struct - initialize a sleep-RCU structure - * @sp: structure to initialize. - * - * Must invoke this on a given srcu_struct before passing that srcu_struct - * to any other function. Each srcu_struct represents a separate domain - * of SRCU protection. - */ -int init_srcu_struct(struct srcu_struct *sp) -{ - return init_srcu_struct_fields(sp); -} -EXPORT_SYMBOL_GPL(init_srcu_struct); - -#endif /* #else #ifdef CONFIG_DEBUG_LOCK_ALLOC */ - -/* - * Returns approximate total of the readers' ->seq[] values for the - * rank of per-CPU counters specified by idx. - */ -static unsigned long srcu_readers_seq_idx(struct srcu_struct *sp, int idx) -{ - int cpu; - unsigned long sum = 0; - unsigned long t; - - for_each_possible_cpu(cpu) { - t = READ_ONCE(per_cpu_ptr(sp->per_cpu_ref, cpu)->seq[idx]); - sum += t; - } - return sum; -} - -/* - * Returns approximate number of readers active on the specified rank - * of the per-CPU ->c[] counters. - */ -static unsigned long srcu_readers_active_idx(struct srcu_struct *sp, int idx) -{ - int cpu; - unsigned long sum = 0; - unsigned long t; - - for_each_possible_cpu(cpu) { - t = READ_ONCE(per_cpu_ptr(sp->per_cpu_ref, cpu)->c[idx]); - sum += t; - } - return sum; -} - -/* - * Return true if the number of pre-existing readers is determined to - * be stably zero. An example unstable zero can occur if the call - * to srcu_readers_active_idx() misses an __srcu_read_lock() increment, - * but due to task migration, sees the corresponding __srcu_read_unlock() - * decrement. This can happen because srcu_readers_active_idx() takes - * time to sum the array, and might in fact be interrupted or preempted - * partway through the summation. - */ -static bool srcu_readers_active_idx_check(struct srcu_struct *sp, int idx) -{ - unsigned long seq; - - seq = srcu_readers_seq_idx(sp, idx); - - /* - * The following smp_mb() A pairs with the smp_mb() B located in - * __srcu_read_lock(). This pairing ensures that if an - * __srcu_read_lock() increments its counter after the summation - * in srcu_readers_active_idx(), then the corresponding SRCU read-side - * critical section will see any changes made prior to the start - * of the current SRCU grace period. - * - * Also, if the above call to srcu_readers_seq_idx() saw the - * increment of ->seq[], then the call to srcu_readers_active_idx() - * must see the increment of ->c[]. - */ - smp_mb(); /* A */ - - /* - * Note that srcu_readers_active_idx() can incorrectly return - * zero even though there is a pre-existing reader throughout. - * To see this, suppose that task A is in a very long SRCU - * read-side critical section that started on CPU 0, and that - * no other reader exists, so that the sum of the counters - * is equal to one. Then suppose that task B starts executing - * srcu_readers_active_idx(), summing up to CPU 1, and then that - * task C starts reading on CPU 0, so that its increment is not - * summed, but finishes reading on CPU 2, so that its decrement - * -is- summed. Then when task B completes its sum, it will - * incorrectly get zero, despite the fact that task A has been - * in its SRCU read-side critical section the whole time. - * - * We therefore do a validation step should srcu_readers_active_idx() - * return zero. - */ - if (srcu_readers_active_idx(sp, idx) != 0) - return false; - - /* - * The remainder of this function is the validation step. - * The following smp_mb() D pairs with the smp_mb() C in - * __srcu_read_unlock(). If the __srcu_read_unlock() was seen - * by srcu_readers_active_idx() above, then any destructive - * operation performed after the grace period will happen after - * the corresponding SRCU read-side critical section. - * - * Note that there can be at most NR_CPUS worth of readers using - * the old index, which is not enough to overflow even a 32-bit - * integer. (Yes, this does mean that systems having more than - * a billion or so CPUs need to be 64-bit systems.) Therefore, - * the sum of the ->seq[] counters cannot possibly overflow. - * Therefore, the only way that the return values of the two - * calls to srcu_readers_seq_idx() can be equal is if there were - * no increments of the corresponding rank of ->seq[] counts - * in the interim. But the missed-increment scenario laid out - * above includes an increment of the ->seq[] counter by - * the corresponding __srcu_read_lock(). Therefore, if this - * scenario occurs, the return values from the two calls to - * srcu_readers_seq_idx() will differ, and thus the validation - * step below suffices. - */ - smp_mb(); /* D */ - - return srcu_readers_seq_idx(sp, idx) == seq; -} - -/** - * srcu_readers_active - returns true if there are readers. and false - * otherwise - * @sp: which srcu_struct to count active readers (holding srcu_read_lock). - * - * Note that this is not an atomic primitive, and can therefore suffer - * severe errors when invoked on an active srcu_struct. That said, it - * can be useful as an error check at cleanup time. - */ -static bool srcu_readers_active(struct srcu_struct *sp) -{ - int cpu; - unsigned long sum = 0; - - for_each_possible_cpu(cpu) { - sum += READ_ONCE(per_cpu_ptr(sp->per_cpu_ref, cpu)->c[0]); - sum += READ_ONCE(per_cpu_ptr(sp->per_cpu_ref, cpu)->c[1]); - } - return sum; -} - -/** - * cleanup_srcu_struct - deconstruct a sleep-RCU structure - * @sp: structure to clean up. - * - * Must invoke this after you are finished using a given srcu_struct that - * was initialized via init_srcu_struct(), else you leak memory. - */ -void cleanup_srcu_struct(struct srcu_struct *sp) -{ - if (WARN_ON(srcu_readers_active(sp))) - return; /* Leakage unless caller handles error. */ - free_percpu(sp->per_cpu_ref); - sp->per_cpu_ref = NULL; -} -EXPORT_SYMBOL_GPL(cleanup_srcu_struct); - -/* - * Counts the new reader in the appropriate per-CPU element of the - * srcu_struct. Must be called from process context. - * Returns an index that must be passed to the matching srcu_read_unlock(). - */ -int __srcu_read_lock(struct srcu_struct *sp) -{ - int idx; - - idx = READ_ONCE(sp->completed) & 0x1; - __this_cpu_inc(sp->per_cpu_ref->c[idx]); - smp_mb(); /* B */ /* Avoid leaking the critical section. */ - __this_cpu_inc(sp->per_cpu_ref->seq[idx]); - return idx; -} -EXPORT_SYMBOL_GPL(__srcu_read_lock); - -/* - * Removes the count for the old reader from the appropriate per-CPU - * element of the srcu_struct. Note that this may well be a different - * CPU than that which was incremented by the corresponding srcu_read_lock(). - * Must be called from process context. - */ -void __srcu_read_unlock(struct srcu_struct *sp, int idx) -{ - smp_mb(); /* C */ /* Avoid leaking the critical section. */ - this_cpu_dec(sp->per_cpu_ref->c[idx]); -} -EXPORT_SYMBOL_GPL(__srcu_read_unlock); - -/* - * We use an adaptive strategy for synchronize_srcu() and especially for - * synchronize_srcu_expedited(). We spin for a fixed time period - * (defined below) to allow SRCU readers to exit their read-side critical - * sections. If there are still some readers after 10 microseconds, - * we repeatedly block for 1-millisecond time periods. This approach - * has done well in testing, so there is no need for a config parameter. - */ -#define SRCU_RETRY_CHECK_DELAY 5 -#define SYNCHRONIZE_SRCU_TRYCOUNT 2 -#define SYNCHRONIZE_SRCU_EXP_TRYCOUNT 12 - -/* - * @@@ Wait until all pre-existing readers complete. Such readers - * will have used the index specified by "idx". - * the caller should ensures the ->completed is not changed while checking - * and idx = (->completed & 1) ^ 1 - */ -static bool try_check_zero(struct srcu_struct *sp, int idx, int trycount) -{ - for (;;) { - if (srcu_readers_active_idx_check(sp, idx)) - return true; - if (--trycount <= 0) - return false; - udelay(SRCU_RETRY_CHECK_DELAY); - } -} - -/* - * Increment the ->completed counter so that future SRCU readers will - * use the other rank of the ->c[] and ->seq[] arrays. This allows - * us to wait for pre-existing readers in a starvation-free manner. - */ -static void srcu_flip(struct srcu_struct *sp) -{ - sp->completed++; -} - -/* - * Enqueue an SRCU callback on the specified srcu_struct structure, - * initiating grace-period processing if it is not already running. - * - * Note that all CPUs must agree that the grace period extended beyond - * all pre-existing SRCU read-side critical section. On systems with - * more than one CPU, this means that when "func()" is invoked, each CPU - * is guaranteed to have executed a full memory barrier since the end of - * its last corresponding SRCU read-side critical section whose beginning - * preceded the call to call_rcu(). It also means that each CPU executing - * an SRCU read-side critical section that continues beyond the start of - * "func()" must have executed a memory barrier after the call_rcu() - * but before the beginning of that SRCU read-side critical section. - * Note that these guarantees include CPUs that are offline, idle, or - * executing in user mode, as well as CPUs that are executing in the kernel. - * - * Furthermore, if CPU A invoked call_rcu() and CPU B invoked the - * resulting SRCU callback function "func()", then both CPU A and CPU - * B are guaranteed to execute a full memory barrier during the time - * interval between the call to call_rcu() and the invocation of "func()". - * This guarantee applies even if CPU A and CPU B are the same CPU (but - * again only if the system has more than one CPU). - * - * Of course, these guarantees apply only for invocations of call_srcu(), - * srcu_read_lock(), and srcu_read_unlock() that are all passed the same - * srcu_struct structure. - */ -void call_srcu(struct srcu_struct *sp, struct rcu_head *head, - rcu_callback_t func) -{ - unsigned long flags; - - head->next = NULL; - head->func = func; - spin_lock_irqsave(&sp->queue_lock, flags); - rcu_batch_queue(&sp->batch_queue, head); - if (!sp->running) { - sp->running = true; - queue_delayed_work(system_power_efficient_wq, &sp->work, 0); - } - spin_unlock_irqrestore(&sp->queue_lock, flags); -} -EXPORT_SYMBOL_GPL(call_srcu); - -static void srcu_advance_batches(struct srcu_struct *sp, int trycount); -static void srcu_reschedule(struct srcu_struct *sp); - -/* - * Helper function for synchronize_srcu() and synchronize_srcu_expedited(). - */ -static void __synchronize_srcu(struct srcu_struct *sp, int trycount) -{ - struct rcu_synchronize rcu; - struct rcu_head *head = &rcu.head; - bool done = false; - - RCU_LOCKDEP_WARN(lock_is_held(&sp->dep_map) || - lock_is_held(&rcu_bh_lock_map) || - lock_is_held(&rcu_lock_map) || - lock_is_held(&rcu_sched_lock_map), - "Illegal synchronize_srcu() in same-type SRCU (or in RCU) read-side critical section"); - - might_sleep(); - init_completion(&rcu.completion); - - head->next = NULL; - head->func = wakeme_after_rcu; - spin_lock_irq(&sp->queue_lock); - if (!sp->running) { - /* steal the processing owner */ - sp->running = true; - rcu_batch_queue(&sp->batch_check0, head); - spin_unlock_irq(&sp->queue_lock); - - srcu_advance_batches(sp, trycount); - if (!rcu_batch_empty(&sp->batch_done)) { - BUG_ON(sp->batch_done.head != head); - rcu_batch_dequeue(&sp->batch_done); - done = true; - } - /* give the processing owner to work_struct */ - srcu_reschedule(sp); - } else { - rcu_batch_queue(&sp->batch_queue, head); - spin_unlock_irq(&sp->queue_lock); - } - - if (!done) - wait_for_completion(&rcu.completion); -} - -/** - * synchronize_srcu - wait for prior SRCU read-side critical-section completion - * @sp: srcu_struct with which to synchronize. - * - * Wait for the count to drain to zero of both indexes. To avoid the - * possible starvation of synchronize_srcu(), it waits for the count of - * the index=((->completed & 1) ^ 1) to drain to zero at first, - * and then flip the completed and wait for the count of the other index. - * - * Can block; must be called from process context. - * - * Note that it is illegal to call synchronize_srcu() from the corresponding - * SRCU read-side critical section; doing so will result in deadlock. - * However, it is perfectly legal to call synchronize_srcu() on one - * srcu_struct from some other srcu_struct's read-side critical section, - * as long as the resulting graph of srcu_structs is acyclic. - * - * There are memory-ordering constraints implied by synchronize_srcu(). - * On systems with more than one CPU, when synchronize_srcu() returns, - * each CPU is guaranteed to have executed a full memory barrier since - * the end of its last corresponding SRCU-sched read-side critical section - * whose beginning preceded the call to synchronize_srcu(). In addition, - * each CPU having an SRCU read-side critical section that extends beyond - * the return from synchronize_srcu() is guaranteed to have executed a - * full memory barrier after the beginning of synchronize_srcu() and before - * the beginning of that SRCU read-side critical section. Note that these - * guarantees include CPUs that are offline, idle, or executing in user mode, - * as well as CPUs that are executing in the kernel. - * - * Furthermore, if CPU A invoked synchronize_srcu(), which returned - * to its caller on CPU B, then both CPU A and CPU B are guaranteed - * to have executed a full memory barrier during the execution of - * synchronize_srcu(). This guarantee applies even if CPU A and CPU B - * are the same CPU, but again only if the system has more than one CPU. - * - * Of course, these memory-ordering guarantees apply only when - * synchronize_srcu(), srcu_read_lock(), and srcu_read_unlock() are - * passed the same srcu_struct structure. - */ -void synchronize_srcu(struct srcu_struct *sp) -{ - __synchronize_srcu(sp, (rcu_gp_is_expedited() && !rcu_gp_is_normal()) - ? SYNCHRONIZE_SRCU_EXP_TRYCOUNT - : SYNCHRONIZE_SRCU_TRYCOUNT); -} -EXPORT_SYMBOL_GPL(synchronize_srcu); - -/** - * synchronize_srcu_expedited - Brute-force SRCU grace period - * @sp: srcu_struct with which to synchronize. - * - * Wait for an SRCU grace period to elapse, but be more aggressive about - * spinning rather than blocking when waiting. - * - * Note that synchronize_srcu_expedited() has the same deadlock and - * memory-ordering properties as does synchronize_srcu(). - */ -void synchronize_srcu_expedited(struct srcu_struct *sp) -{ - __synchronize_srcu(sp, SYNCHRONIZE_SRCU_EXP_TRYCOUNT); -} -EXPORT_SYMBOL_GPL(synchronize_srcu_expedited); - -/** - * srcu_barrier - Wait until all in-flight call_srcu() callbacks complete. - * @sp: srcu_struct on which to wait for in-flight callbacks. - */ -void srcu_barrier(struct srcu_struct *sp) -{ - synchronize_srcu(sp); -} -EXPORT_SYMBOL_GPL(srcu_barrier); - -/** - * srcu_batches_completed - return batches completed. - * @sp: srcu_struct on which to report batch completion. - * - * Report the number of batches, correlated with, but not necessarily - * precisely the same as, the number of grace periods that have elapsed. - */ -unsigned long srcu_batches_completed(struct srcu_struct *sp) -{ - return sp->completed; -} -EXPORT_SYMBOL_GPL(srcu_batches_completed); - -#define SRCU_CALLBACK_BATCH 10 -#define SRCU_INTERVAL 1 - -/* - * Move any new SRCU callbacks to the first stage of the SRCU grace - * period pipeline. - */ -static void srcu_collect_new(struct srcu_struct *sp) -{ - if (!rcu_batch_empty(&sp->batch_queue)) { - spin_lock_irq(&sp->queue_lock); - rcu_batch_move(&sp->batch_check0, &sp->batch_queue); - spin_unlock_irq(&sp->queue_lock); - } -} - -/* - * Core SRCU state machine. Advance callbacks from ->batch_check0 to - * ->batch_check1 and then to ->batch_done as readers drain. - */ -static void srcu_advance_batches(struct srcu_struct *sp, int trycount) -{ - int idx = 1 ^ (sp->completed & 1); - - /* - * Because readers might be delayed for an extended period after - * fetching ->completed for their index, at any point in time there - * might well be readers using both idx=0 and idx=1. We therefore - * need to wait for readers to clear from both index values before - * invoking a callback. - */ - - if (rcu_batch_empty(&sp->batch_check0) && - rcu_batch_empty(&sp->batch_check1)) - return; /* no callbacks need to be advanced */ - - if (!try_check_zero(sp, idx, trycount)) - return; /* failed to advance, will try after SRCU_INTERVAL */ - - /* - * The callbacks in ->batch_check1 have already done with their - * first zero check and flip back when they were enqueued on - * ->batch_check0 in a previous invocation of srcu_advance_batches(). - * (Presumably try_check_zero() returned false during that - * invocation, leaving the callbacks stranded on ->batch_check1.) - * They are therefore ready to invoke, so move them to ->batch_done. - */ - rcu_batch_move(&sp->batch_done, &sp->batch_check1); - - if (rcu_batch_empty(&sp->batch_check0)) - return; /* no callbacks need to be advanced */ - srcu_flip(sp); - - /* - * The callbacks in ->batch_check0 just finished their - * first check zero and flip, so move them to ->batch_check1 - * for future checking on the other idx. - */ - rcu_batch_move(&sp->batch_check1, &sp->batch_check0); - - /* - * SRCU read-side critical sections are normally short, so check - * at least twice in quick succession after a flip. - */ - trycount = trycount < 2 ? 2 : trycount; - if (!try_check_zero(sp, idx^1, trycount)) - return; /* failed to advance, will try after SRCU_INTERVAL */ - - /* - * The callbacks in ->batch_check1 have now waited for all - * pre-existing readers using both idx values. They are therefore - * ready to invoke, so move them to ->batch_done. - */ - rcu_batch_move(&sp->batch_done, &sp->batch_check1); -} - -/* - * Invoke a limited number of SRCU callbacks that have passed through - * their grace period. If there are more to do, SRCU will reschedule - * the workqueue. - */ -static void srcu_invoke_callbacks(struct srcu_struct *sp) -{ - int i; - struct rcu_head *head; - - for (i = 0; i < SRCU_CALLBACK_BATCH; i++) { - head = rcu_batch_dequeue(&sp->batch_done); - if (!head) - break; - local_bh_disable(); - head->func(head); - local_bh_enable(); - } -} - -/* - * Finished one round of SRCU grace period. Start another if there are - * more SRCU callbacks queued, otherwise put SRCU into not-running state. - */ -static void srcu_reschedule(struct srcu_struct *sp) -{ - bool pending = true; - - if (rcu_batch_empty(&sp->batch_done) && - rcu_batch_empty(&sp->batch_check1) && - rcu_batch_empty(&sp->batch_check0) && - rcu_batch_empty(&sp->batch_queue)) { - spin_lock_irq(&sp->queue_lock); - if (rcu_batch_empty(&sp->batch_done) && - rcu_batch_empty(&sp->batch_check1) && - rcu_batch_empty(&sp->batch_check0) && - rcu_batch_empty(&sp->batch_queue)) { - sp->running = false; - pending = false; - } - spin_unlock_irq(&sp->queue_lock); - } - - if (pending) - queue_delayed_work(system_power_efficient_wq, - &sp->work, SRCU_INTERVAL); -} - -/* - * This is the work-queue function that handles SRCU grace periods. - */ -void process_srcu(struct work_struct *work) -{ - struct srcu_struct *sp; - - sp = container_of(work, struct srcu_struct, work.work); - - srcu_collect_new(sp); - srcu_advance_batches(sp, 1); - srcu_invoke_callbacks(sp); - srcu_reschedule(sp); -} -EXPORT_SYMBOL_GPL(process_srcu); diff --git a/src/linux/kernel/rcu/sync.c b/src/linux/kernel/rcu/sync.c deleted file mode 100644 index 50d1861..0000000 --- a/src/linux/kernel/rcu/sync.c +++ /dev/null @@ -1,237 +0,0 @@ -/* - * RCU-based infrastructure for lightweight reader-writer locking - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you can access it online at - * http://www.gnu.org/licenses/gpl-2.0.html. - * - * Copyright (c) 2015, Red Hat, Inc. - * - * Author: Oleg Nesterov - */ - -#include -#include - -#ifdef CONFIG_PROVE_RCU -#define __INIT_HELD(func) .held = func, -#else -#define __INIT_HELD(func) -#endif - -static const struct { - void (*sync)(void); - void (*call)(struct rcu_head *, void (*)(struct rcu_head *)); - void (*wait)(void); -#ifdef CONFIG_PROVE_RCU - int (*held)(void); -#endif -} gp_ops[] = { - [RCU_SYNC] = { - .sync = synchronize_rcu, - .call = call_rcu, - .wait = rcu_barrier, - __INIT_HELD(rcu_read_lock_held) - }, - [RCU_SCHED_SYNC] = { - .sync = synchronize_sched, - .call = call_rcu_sched, - .wait = rcu_barrier_sched, - __INIT_HELD(rcu_read_lock_sched_held) - }, - [RCU_BH_SYNC] = { - .sync = synchronize_rcu_bh, - .call = call_rcu_bh, - .wait = rcu_barrier_bh, - __INIT_HELD(rcu_read_lock_bh_held) - }, -}; - -enum { GP_IDLE = 0, GP_PENDING, GP_PASSED }; -enum { CB_IDLE = 0, CB_PENDING, CB_REPLAY }; - -#define rss_lock gp_wait.lock - -#ifdef CONFIG_PROVE_RCU -void rcu_sync_lockdep_assert(struct rcu_sync *rsp) -{ - RCU_LOCKDEP_WARN(!gp_ops[rsp->gp_type].held(), - "suspicious rcu_sync_is_idle() usage"); -} - -EXPORT_SYMBOL_GPL(rcu_sync_lockdep_assert); -#endif - -/** - * rcu_sync_init() - Initialize an rcu_sync structure - * @rsp: Pointer to rcu_sync structure to be initialized - * @type: Flavor of RCU with which to synchronize rcu_sync structure - */ -void rcu_sync_init(struct rcu_sync *rsp, enum rcu_sync_type type) -{ - memset(rsp, 0, sizeof(*rsp)); - init_waitqueue_head(&rsp->gp_wait); - rsp->gp_type = type; -} - -/** - * Must be called after rcu_sync_init() and before first use. - * - * Ensures rcu_sync_is_idle() returns false and rcu_sync_{enter,exit}() - * pairs turn into NO-OPs. - */ -void rcu_sync_enter_start(struct rcu_sync *rsp) -{ - rsp->gp_count++; - rsp->gp_state = GP_PASSED; -} - -/** - * rcu_sync_enter() - Force readers onto slowpath - * @rsp: Pointer to rcu_sync structure to use for synchronization - * - * This function is used by updaters who need readers to make use of - * a slowpath during the update. After this function returns, all - * subsequent calls to rcu_sync_is_idle() will return false, which - * tells readers to stay off their fastpaths. A later call to - * rcu_sync_exit() re-enables reader slowpaths. - * - * When called in isolation, rcu_sync_enter() must wait for a grace - * period, however, closely spaced calls to rcu_sync_enter() can - * optimize away the grace-period wait via a state machine implemented - * by rcu_sync_enter(), rcu_sync_exit(), and rcu_sync_func(). - */ -void rcu_sync_enter(struct rcu_sync *rsp) -{ - bool need_wait, need_sync; - - spin_lock_irq(&rsp->rss_lock); - need_wait = rsp->gp_count++; - need_sync = rsp->gp_state == GP_IDLE; - if (need_sync) - rsp->gp_state = GP_PENDING; - spin_unlock_irq(&rsp->rss_lock); - - BUG_ON(need_wait && need_sync); - - if (need_sync) { - gp_ops[rsp->gp_type].sync(); - rsp->gp_state = GP_PASSED; - wake_up_all(&rsp->gp_wait); - } else if (need_wait) { - wait_event(rsp->gp_wait, rsp->gp_state == GP_PASSED); - } else { - /* - * Possible when there's a pending CB from a rcu_sync_exit(). - * Nobody has yet been allowed the 'fast' path and thus we can - * avoid doing any sync(). The callback will get 'dropped'. - */ - BUG_ON(rsp->gp_state != GP_PASSED); - } -} - -/** - * rcu_sync_func() - Callback function managing reader access to fastpath - * @rsp: Pointer to rcu_sync structure to use for synchronization - * - * This function is passed to one of the call_rcu() functions by - * rcu_sync_exit(), so that it is invoked after a grace period following the - * that invocation of rcu_sync_exit(). It takes action based on events that - * have taken place in the meantime, so that closely spaced rcu_sync_enter() - * and rcu_sync_exit() pairs need not wait for a grace period. - * - * If another rcu_sync_enter() is invoked before the grace period - * ended, reset state to allow the next rcu_sync_exit() to let the - * readers back onto their fastpaths (after a grace period). If both - * another rcu_sync_enter() and its matching rcu_sync_exit() are invoked - * before the grace period ended, re-invoke call_rcu() on behalf of that - * rcu_sync_exit(). Otherwise, set all state back to idle so that readers - * can again use their fastpaths. - */ -static void rcu_sync_func(struct rcu_head *rcu) -{ - struct rcu_sync *rsp = container_of(rcu, struct rcu_sync, cb_head); - unsigned long flags; - - BUG_ON(rsp->gp_state != GP_PASSED); - BUG_ON(rsp->cb_state == CB_IDLE); - - spin_lock_irqsave(&rsp->rss_lock, flags); - if (rsp->gp_count) { - /* - * A new rcu_sync_begin() has happened; drop the callback. - */ - rsp->cb_state = CB_IDLE; - } else if (rsp->cb_state == CB_REPLAY) { - /* - * A new rcu_sync_exit() has happened; requeue the callback - * to catch a later GP. - */ - rsp->cb_state = CB_PENDING; - gp_ops[rsp->gp_type].call(&rsp->cb_head, rcu_sync_func); - } else { - /* - * We're at least a GP after rcu_sync_exit(); eveybody will now - * have observed the write side critical section. Let 'em rip!. - */ - rsp->cb_state = CB_IDLE; - rsp->gp_state = GP_IDLE; - } - spin_unlock_irqrestore(&rsp->rss_lock, flags); -} - -/** - * rcu_sync_exit() - Allow readers back onto fast patch after grace period - * @rsp: Pointer to rcu_sync structure to use for synchronization - * - * This function is used by updaters who have completed, and can therefore - * now allow readers to make use of their fastpaths after a grace period - * has elapsed. After this grace period has completed, all subsequent - * calls to rcu_sync_is_idle() will return true, which tells readers that - * they can once again use their fastpaths. - */ -void rcu_sync_exit(struct rcu_sync *rsp) -{ - spin_lock_irq(&rsp->rss_lock); - if (!--rsp->gp_count) { - if (rsp->cb_state == CB_IDLE) { - rsp->cb_state = CB_PENDING; - gp_ops[rsp->gp_type].call(&rsp->cb_head, rcu_sync_func); - } else if (rsp->cb_state == CB_PENDING) { - rsp->cb_state = CB_REPLAY; - } - } - spin_unlock_irq(&rsp->rss_lock); -} - -/** - * rcu_sync_dtor() - Clean up an rcu_sync structure - * @rsp: Pointer to rcu_sync structure to be cleaned up - */ -void rcu_sync_dtor(struct rcu_sync *rsp) -{ - int cb_state; - - BUG_ON(rsp->gp_count); - - spin_lock_irq(&rsp->rss_lock); - if (rsp->cb_state == CB_REPLAY) - rsp->cb_state = CB_PENDING; - cb_state = rsp->cb_state; - spin_unlock_irq(&rsp->rss_lock); - - if (cb_state != CB_IDLE) { - gp_ops[rsp->gp_type].wait(); - BUG_ON(rsp->cb_state != CB_IDLE); - } -} diff --git a/src/linux/kernel/rcu/tiny.c b/src/linux/kernel/rcu/tiny.c deleted file mode 100644 index 1898559..0000000 --- a/src/linux/kernel/rcu/tiny.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Read-Copy Update mechanism for mutual exclusion, the Bloatwatch edition. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you can access it online at - * http://www.gnu.org/licenses/gpl-2.0.html. - * - * Copyright IBM Corporation, 2008 - * - * Author: Paul E. McKenney - * - * For detailed explanation of Read-Copy Update mechanism see - - * Documentation/RCU - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "rcu.h" - -/* Forward declarations for tiny_plugin.h. */ -struct rcu_ctrlblk; -static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp); -static void rcu_process_callbacks(struct softirq_action *unused); -static void __call_rcu(struct rcu_head *head, - rcu_callback_t func, - struct rcu_ctrlblk *rcp); - -#include "tiny_plugin.h" - -#if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) - -/* - * Test whether RCU thinks that the current CPU is idle. - */ -bool notrace __rcu_is_watching(void) -{ - return true; -} -EXPORT_SYMBOL(__rcu_is_watching); - -#endif /* defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) */ - -/* - * Helper function for rcu_sched_qs() and rcu_bh_qs(). - * Also irqs are disabled to avoid confusion due to interrupt handlers - * invoking call_rcu(). - */ -static int rcu_qsctr_help(struct rcu_ctrlblk *rcp) -{ - RCU_TRACE(reset_cpu_stall_ticks(rcp)); - if (rcp->donetail != rcp->curtail) { - rcp->donetail = rcp->curtail; - return 1; - } - - return 0; -} - -/* - * Record an rcu quiescent state. And an rcu_bh quiescent state while we - * are at it, given that any rcu quiescent state is also an rcu_bh - * quiescent state. Use "+" instead of "||" to defeat short circuiting. - */ -void rcu_sched_qs(void) -{ - unsigned long flags; - - local_irq_save(flags); - if (rcu_qsctr_help(&rcu_sched_ctrlblk) + - rcu_qsctr_help(&rcu_bh_ctrlblk)) - raise_softirq(RCU_SOFTIRQ); - local_irq_restore(flags); -} - -/* - * Record an rcu_bh quiescent state. - */ -void rcu_bh_qs(void) -{ - unsigned long flags; - - local_irq_save(flags); - if (rcu_qsctr_help(&rcu_bh_ctrlblk)) - raise_softirq(RCU_SOFTIRQ); - local_irq_restore(flags); -} - -/* - * Check to see if the scheduling-clock interrupt came from an extended - * quiescent state, and, if so, tell RCU about it. This function must - * be called from hardirq context. It is normally called from the - * scheduling-clock interrupt. - */ -void rcu_check_callbacks(int user) -{ - RCU_TRACE(check_cpu_stalls()); - if (user) - rcu_sched_qs(); - else if (!in_softirq()) - rcu_bh_qs(); - if (user) - rcu_note_voluntary_context_switch(current); -} - -/* - * Invoke the RCU callbacks on the specified rcu_ctrlkblk structure - * whose grace period has elapsed. - */ -static void __rcu_process_callbacks(struct rcu_ctrlblk *rcp) -{ - const char *rn = NULL; - struct rcu_head *next, *list; - unsigned long flags; - RCU_TRACE(int cb_count = 0); - - /* Move the ready-to-invoke callbacks to a local list. */ - local_irq_save(flags); - if (rcp->donetail == &rcp->rcucblist) { - /* No callbacks ready, so just leave. */ - local_irq_restore(flags); - return; - } - RCU_TRACE(trace_rcu_batch_start(rcp->name, 0, rcp->qlen, -1)); - list = rcp->rcucblist; - rcp->rcucblist = *rcp->donetail; - *rcp->donetail = NULL; - if (rcp->curtail == rcp->donetail) - rcp->curtail = &rcp->rcucblist; - rcp->donetail = &rcp->rcucblist; - local_irq_restore(flags); - - /* Invoke the callbacks on the local list. */ - RCU_TRACE(rn = rcp->name); - while (list) { - next = list->next; - prefetch(next); - debug_rcu_head_unqueue(list); - local_bh_disable(); - __rcu_reclaim(rn, list); - local_bh_enable(); - list = next; - RCU_TRACE(cb_count++); - } - RCU_TRACE(rcu_trace_sub_qlen(rcp, cb_count)); - RCU_TRACE(trace_rcu_batch_end(rcp->name, - cb_count, 0, need_resched(), - is_idle_task(current), - false)); -} - -static __latent_entropy void rcu_process_callbacks(struct softirq_action *unused) -{ - __rcu_process_callbacks(&rcu_sched_ctrlblk); - __rcu_process_callbacks(&rcu_bh_ctrlblk); -} - -/* - * Wait for a grace period to elapse. But it is illegal to invoke - * synchronize_sched() from within an RCU read-side critical section. - * Therefore, any legal call to synchronize_sched() is a quiescent - * state, and so on a UP system, synchronize_sched() need do nothing. - * Ditto for synchronize_rcu_bh(). (But Lai Jiangshan points out the - * benefits of doing might_sleep() to reduce latency.) - * - * Cool, huh? (Due to Josh Triplett.) - * - * But we want to make this a static inline later. The cond_resched() - * currently makes this problematic. - */ -void synchronize_sched(void) -{ - RCU_LOCKDEP_WARN(lock_is_held(&rcu_bh_lock_map) || - lock_is_held(&rcu_lock_map) || - lock_is_held(&rcu_sched_lock_map), - "Illegal synchronize_sched() in RCU read-side critical section"); - cond_resched(); -} -EXPORT_SYMBOL_GPL(synchronize_sched); - -/* - * Helper function for call_rcu() and call_rcu_bh(). - */ -static void __call_rcu(struct rcu_head *head, - rcu_callback_t func, - struct rcu_ctrlblk *rcp) -{ - unsigned long flags; - - debug_rcu_head_queue(head); - head->func = func; - head->next = NULL; - - local_irq_save(flags); - *rcp->curtail = head; - rcp->curtail = &head->next; - RCU_TRACE(rcp->qlen++); - local_irq_restore(flags); - - if (unlikely(is_idle_task(current))) { - /* force scheduling for rcu_sched_qs() */ - resched_cpu(0); - } -} - -/* - * Post an RCU callback to be invoked after the end of an RCU-sched grace - * period. But since we have but one CPU, that would be after any - * quiescent state. - */ -void call_rcu_sched(struct rcu_head *head, rcu_callback_t func) -{ - __call_rcu(head, func, &rcu_sched_ctrlblk); -} -EXPORT_SYMBOL_GPL(call_rcu_sched); - -/* - * Post an RCU bottom-half callback to be invoked after any subsequent - * quiescent state. - */ -void call_rcu_bh(struct rcu_head *head, rcu_callback_t func) -{ - __call_rcu(head, func, &rcu_bh_ctrlblk); -} -EXPORT_SYMBOL_GPL(call_rcu_bh); - -void __init rcu_init(void) -{ - open_softirq(RCU_SOFTIRQ, rcu_process_callbacks); - RCU_TRACE(reset_cpu_stall_ticks(&rcu_sched_ctrlblk)); - RCU_TRACE(reset_cpu_stall_ticks(&rcu_bh_ctrlblk)); - - rcu_early_boot_tests(); -} diff --git a/src/linux/kernel/rcu/tiny_plugin.h b/src/linux/kernel/rcu/tiny_plugin.h deleted file mode 100644 index 196f030..0000000 --- a/src/linux/kernel/rcu/tiny_plugin.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Read-Copy Update mechanism for mutual exclusion, the Bloatwatch edition - * Internal non-public definitions that provide either classic - * or preemptible semantics. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you can access it online at - * http://www.gnu.org/licenses/gpl-2.0.html. - * - * Copyright (c) 2010 Linaro - * - * Author: Paul E. McKenney - */ - -#include -#include -#include -#include - -/* Global control variables for rcupdate callback mechanism. */ -struct rcu_ctrlblk { - struct rcu_head *rcucblist; /* List of pending callbacks (CBs). */ - struct rcu_head **donetail; /* ->next pointer of last "done" CB. */ - struct rcu_head **curtail; /* ->next pointer of last CB. */ - RCU_TRACE(long qlen); /* Number of pending CBs. */ - RCU_TRACE(unsigned long gp_start); /* Start time for stalls. */ - RCU_TRACE(unsigned long ticks_this_gp); /* Statistic for stalls. */ - RCU_TRACE(unsigned long jiffies_stall); /* Jiffies at next stall. */ - RCU_TRACE(const char *name); /* Name of RCU type. */ -}; - -/* Definition for rcupdate control block. */ -static struct rcu_ctrlblk rcu_sched_ctrlblk = { - .donetail = &rcu_sched_ctrlblk.rcucblist, - .curtail = &rcu_sched_ctrlblk.rcucblist, - RCU_TRACE(.name = "rcu_sched") -}; - -static struct rcu_ctrlblk rcu_bh_ctrlblk = { - .donetail = &rcu_bh_ctrlblk.rcucblist, - .curtail = &rcu_bh_ctrlblk.rcucblist, - RCU_TRACE(.name = "rcu_bh") -}; - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -#include - -int rcu_scheduler_active __read_mostly; -EXPORT_SYMBOL_GPL(rcu_scheduler_active); - -/* - * During boot, we forgive RCU lockdep issues. After this function is - * invoked, we start taking RCU lockdep issues seriously. - */ -void __init rcu_scheduler_starting(void) -{ - WARN_ON(nr_context_switches() > 0); - rcu_scheduler_active = 1; -} - -#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ - -#ifdef CONFIG_RCU_TRACE - -static void rcu_trace_sub_qlen(struct rcu_ctrlblk *rcp, int n) -{ - unsigned long flags; - - local_irq_save(flags); - rcp->qlen -= n; - local_irq_restore(flags); -} - -/* - * Dump statistics for TINY_RCU, such as they are. - */ -static int show_tiny_stats(struct seq_file *m, void *unused) -{ - seq_printf(m, "rcu_sched: qlen: %ld\n", rcu_sched_ctrlblk.qlen); - seq_printf(m, "rcu_bh: qlen: %ld\n", rcu_bh_ctrlblk.qlen); - return 0; -} - -static int show_tiny_stats_open(struct inode *inode, struct file *file) -{ - return single_open(file, show_tiny_stats, NULL); -} - -static const struct file_operations show_tiny_stats_fops = { - .owner = THIS_MODULE, - .open = show_tiny_stats_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static struct dentry *rcudir; - -static int __init rcutiny_trace_init(void) -{ - struct dentry *retval; - - rcudir = debugfs_create_dir("rcu", NULL); - if (!rcudir) - goto free_out; - retval = debugfs_create_file("rcudata", 0444, rcudir, - NULL, &show_tiny_stats_fops); - if (!retval) - goto free_out; - return 0; -free_out: - debugfs_remove_recursive(rcudir); - return 1; -} -device_initcall(rcutiny_trace_init); - -static void check_cpu_stall(struct rcu_ctrlblk *rcp) -{ - unsigned long j; - unsigned long js; - - if (rcu_cpu_stall_suppress) - return; - rcp->ticks_this_gp++; - j = jiffies; - js = READ_ONCE(rcp->jiffies_stall); - if (rcp->rcucblist && ULONG_CMP_GE(j, js)) { - pr_err("INFO: %s stall on CPU (%lu ticks this GP) idle=%llx (t=%lu jiffies q=%ld)\n", - rcp->name, rcp->ticks_this_gp, DYNTICK_TASK_EXIT_IDLE, - jiffies - rcp->gp_start, rcp->qlen); - dump_stack(); - WRITE_ONCE(rcp->jiffies_stall, - jiffies + 3 * rcu_jiffies_till_stall_check() + 3); - } else if (ULONG_CMP_GE(j, js)) { - WRITE_ONCE(rcp->jiffies_stall, - jiffies + rcu_jiffies_till_stall_check()); - } -} - -static void reset_cpu_stall_ticks(struct rcu_ctrlblk *rcp) -{ - rcp->ticks_this_gp = 0; - rcp->gp_start = jiffies; - WRITE_ONCE(rcp->jiffies_stall, - jiffies + rcu_jiffies_till_stall_check()); -} - -static void check_cpu_stalls(void) -{ - RCU_TRACE(check_cpu_stall(&rcu_bh_ctrlblk)); - RCU_TRACE(check_cpu_stall(&rcu_sched_ctrlblk)); -} - -#endif /* #ifdef CONFIG_RCU_TRACE */ diff --git a/src/linux/kernel/rcu/update.c b/src/linux/kernel/rcu/update.c deleted file mode 100644 index f19271d..0000000 --- a/src/linux/kernel/rcu/update.c +++ /dev/null @@ -1,898 +0,0 @@ -/* - * Read-Copy Update mechanism for mutual exclusion - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, you can access it online at - * http://www.gnu.org/licenses/gpl-2.0.html. - * - * Copyright IBM Corporation, 2001 - * - * Authors: Dipankar Sarma - * Manfred Spraul - * - * Based on the original work by Paul McKenney - * and inputs from Rusty Russell, Andrea Arcangeli and Andi Kleen. - * Papers: - * http://www.rdrop.com/users/paulmck/paper/rclockpdcsproof.pdf - * http://lse.sourceforge.net/locking/rclock_OLS.2001.05.01c.sc.pdf (OLS2001) - * - * For detailed explanation of Read-Copy Update mechanism see - - * http://lse.sourceforge.net/locking/rcupdate.html - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CREATE_TRACE_POINTS - -#include "rcu.h" - -#ifdef MODULE_PARAM_PREFIX -#undef MODULE_PARAM_PREFIX -#endif -#define MODULE_PARAM_PREFIX "rcupdate." - -#ifndef CONFIG_TINY_RCU -module_param(rcu_expedited, int, 0); -module_param(rcu_normal, int, 0); -static int rcu_normal_after_boot; -module_param(rcu_normal_after_boot, int, 0); -#endif /* #ifndef CONFIG_TINY_RCU */ - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -/** - * rcu_read_lock_sched_held() - might we be in RCU-sched read-side critical section? - * - * If CONFIG_DEBUG_LOCK_ALLOC is selected, returns nonzero iff in an - * RCU-sched read-side critical section. In absence of - * CONFIG_DEBUG_LOCK_ALLOC, this assumes we are in an RCU-sched read-side - * critical section unless it can prove otherwise. Note that disabling - * of preemption (including disabling irqs) counts as an RCU-sched - * read-side critical section. This is useful for debug checks in functions - * that required that they be called within an RCU-sched read-side - * critical section. - * - * Check debug_lockdep_rcu_enabled() to prevent false positives during boot - * and while lockdep is disabled. - * - * Note that if the CPU is in the idle loop from an RCU point of - * view (ie: that we are in the section between rcu_idle_enter() and - * rcu_idle_exit()) then rcu_read_lock_held() returns false even if the CPU - * did an rcu_read_lock(). The reason for this is that RCU ignores CPUs - * that are in such a section, considering these as in extended quiescent - * state, so such a CPU is effectively never in an RCU read-side critical - * section regardless of what RCU primitives it invokes. This state of - * affairs is required --- we need to keep an RCU-free window in idle - * where the CPU may possibly enter into low power mode. This way we can - * notice an extended quiescent state to other CPUs that started a grace - * period. Otherwise we would delay any grace period as long as we run in - * the idle task. - * - * Similarly, we avoid claiming an SRCU read lock held if the current - * CPU is offline. - */ -int rcu_read_lock_sched_held(void) -{ - int lockdep_opinion = 0; - - if (!debug_lockdep_rcu_enabled()) - return 1; - if (!rcu_is_watching()) - return 0; - if (!rcu_lockdep_current_cpu_online()) - return 0; - if (debug_locks) - lockdep_opinion = lock_is_held(&rcu_sched_lock_map); - return lockdep_opinion || !preemptible(); -} -EXPORT_SYMBOL(rcu_read_lock_sched_held); -#endif - -#ifndef CONFIG_TINY_RCU - -/* - * Should expedited grace-period primitives always fall back to their - * non-expedited counterparts? Intended for use within RCU. Note - * that if the user specifies both rcu_expedited and rcu_normal, then - * rcu_normal wins. - */ -bool rcu_gp_is_normal(void) -{ - return READ_ONCE(rcu_normal); -} -EXPORT_SYMBOL_GPL(rcu_gp_is_normal); - -static atomic_t rcu_expedited_nesting = - ATOMIC_INIT(IS_ENABLED(CONFIG_RCU_EXPEDITE_BOOT) ? 1 : 0); - -/* - * Should normal grace-period primitives be expedited? Intended for - * use within RCU. Note that this function takes the rcu_expedited - * sysfs/boot variable into account as well as the rcu_expedite_gp() - * nesting. So looping on rcu_unexpedite_gp() until rcu_gp_is_expedited() - * returns false is a -really- bad idea. - */ -bool rcu_gp_is_expedited(void) -{ - return rcu_expedited || atomic_read(&rcu_expedited_nesting); -} -EXPORT_SYMBOL_GPL(rcu_gp_is_expedited); - -/** - * rcu_expedite_gp - Expedite future RCU grace periods - * - * After a call to this function, future calls to synchronize_rcu() and - * friends act as the corresponding synchronize_rcu_expedited() function - * had instead been called. - */ -void rcu_expedite_gp(void) -{ - atomic_inc(&rcu_expedited_nesting); -} -EXPORT_SYMBOL_GPL(rcu_expedite_gp); - -/** - * rcu_unexpedite_gp - Cancel prior rcu_expedite_gp() invocation - * - * Undo a prior call to rcu_expedite_gp(). If all prior calls to - * rcu_expedite_gp() are undone by a subsequent call to rcu_unexpedite_gp(), - * and if the rcu_expedited sysfs/boot parameter is not set, then all - * subsequent calls to synchronize_rcu() and friends will return to - * their normal non-expedited behavior. - */ -void rcu_unexpedite_gp(void) -{ - atomic_dec(&rcu_expedited_nesting); -} -EXPORT_SYMBOL_GPL(rcu_unexpedite_gp); - -/* - * Inform RCU of the end of the in-kernel boot sequence. - */ -void rcu_end_inkernel_boot(void) -{ - if (IS_ENABLED(CONFIG_RCU_EXPEDITE_BOOT)) - rcu_unexpedite_gp(); - if (rcu_normal_after_boot) - WRITE_ONCE(rcu_normal, 1); -} - -#endif /* #ifndef CONFIG_TINY_RCU */ - -#ifdef CONFIG_PREEMPT_RCU - -/* - * Preemptible RCU implementation for rcu_read_lock(). - * Just increment ->rcu_read_lock_nesting, shared state will be updated - * if we block. - */ -void __rcu_read_lock(void) -{ - current->rcu_read_lock_nesting++; - barrier(); /* critical section after entry code. */ -} -EXPORT_SYMBOL_GPL(__rcu_read_lock); - -/* - * Preemptible RCU implementation for rcu_read_unlock(). - * Decrement ->rcu_read_lock_nesting. If the result is zero (outermost - * rcu_read_unlock()) and ->rcu_read_unlock_special is non-zero, then - * invoke rcu_read_unlock_special() to clean up after a context switch - * in an RCU read-side critical section and other special cases. - */ -void __rcu_read_unlock(void) -{ - struct task_struct *t = current; - - if (t->rcu_read_lock_nesting != 1) { - --t->rcu_read_lock_nesting; - } else { - barrier(); /* critical section before exit code. */ - t->rcu_read_lock_nesting = INT_MIN; - barrier(); /* assign before ->rcu_read_unlock_special load */ - if (unlikely(READ_ONCE(t->rcu_read_unlock_special.s))) - rcu_read_unlock_special(t); - barrier(); /* ->rcu_read_unlock_special load before assign */ - t->rcu_read_lock_nesting = 0; - } -#ifdef CONFIG_PROVE_LOCKING - { - int rrln = READ_ONCE(t->rcu_read_lock_nesting); - - WARN_ON_ONCE(rrln < 0 && rrln > INT_MIN / 2); - } -#endif /* #ifdef CONFIG_PROVE_LOCKING */ -} -EXPORT_SYMBOL_GPL(__rcu_read_unlock); - -#endif /* #ifdef CONFIG_PREEMPT_RCU */ - -#ifdef CONFIG_DEBUG_LOCK_ALLOC -static struct lock_class_key rcu_lock_key; -struct lockdep_map rcu_lock_map = - STATIC_LOCKDEP_MAP_INIT("rcu_read_lock", &rcu_lock_key); -EXPORT_SYMBOL_GPL(rcu_lock_map); - -static struct lock_class_key rcu_bh_lock_key; -struct lockdep_map rcu_bh_lock_map = - STATIC_LOCKDEP_MAP_INIT("rcu_read_lock_bh", &rcu_bh_lock_key); -EXPORT_SYMBOL_GPL(rcu_bh_lock_map); - -static struct lock_class_key rcu_sched_lock_key; -struct lockdep_map rcu_sched_lock_map = - STATIC_LOCKDEP_MAP_INIT("rcu_read_lock_sched", &rcu_sched_lock_key); -EXPORT_SYMBOL_GPL(rcu_sched_lock_map); - -static struct lock_class_key rcu_callback_key; -struct lockdep_map rcu_callback_map = - STATIC_LOCKDEP_MAP_INIT("rcu_callback", &rcu_callback_key); -EXPORT_SYMBOL_GPL(rcu_callback_map); - -int notrace debug_lockdep_rcu_enabled(void) -{ - return rcu_scheduler_active && debug_locks && - current->lockdep_recursion == 0; -} -EXPORT_SYMBOL_GPL(debug_lockdep_rcu_enabled); - -/** - * rcu_read_lock_held() - might we be in RCU read-side critical section? - * - * If CONFIG_DEBUG_LOCK_ALLOC is selected, returns nonzero iff in an RCU - * read-side critical section. In absence of CONFIG_DEBUG_LOCK_ALLOC, - * this assumes we are in an RCU read-side critical section unless it can - * prove otherwise. This is useful for debug checks in functions that - * require that they be called within an RCU read-side critical section. - * - * Checks debug_lockdep_rcu_enabled() to prevent false positives during boot - * and while lockdep is disabled. - * - * Note that rcu_read_lock() and the matching rcu_read_unlock() must - * occur in the same context, for example, it is illegal to invoke - * rcu_read_unlock() in process context if the matching rcu_read_lock() - * was invoked from within an irq handler. - * - * Note that rcu_read_lock() is disallowed if the CPU is either idle or - * offline from an RCU perspective, so check for those as well. - */ -int rcu_read_lock_held(void) -{ - if (!debug_lockdep_rcu_enabled()) - return 1; - if (!rcu_is_watching()) - return 0; - if (!rcu_lockdep_current_cpu_online()) - return 0; - return lock_is_held(&rcu_lock_map); -} -EXPORT_SYMBOL_GPL(rcu_read_lock_held); - -/** - * rcu_read_lock_bh_held() - might we be in RCU-bh read-side critical section? - * - * Check for bottom half being disabled, which covers both the - * CONFIG_PROVE_RCU and not cases. Note that if someone uses - * rcu_read_lock_bh(), but then later enables BH, lockdep (if enabled) - * will show the situation. This is useful for debug checks in functions - * that require that they be called within an RCU read-side critical - * section. - * - * Check debug_lockdep_rcu_enabled() to prevent false positives during boot. - * - * Note that rcu_read_lock() is disallowed if the CPU is either idle or - * offline from an RCU perspective, so check for those as well. - */ -int rcu_read_lock_bh_held(void) -{ - if (!debug_lockdep_rcu_enabled()) - return 1; - if (!rcu_is_watching()) - return 0; - if (!rcu_lockdep_current_cpu_online()) - return 0; - return in_softirq() || irqs_disabled(); -} -EXPORT_SYMBOL_GPL(rcu_read_lock_bh_held); - -#endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ - -/** - * wakeme_after_rcu() - Callback function to awaken a task after grace period - * @head: Pointer to rcu_head member within rcu_synchronize structure - * - * Awaken the corresponding task now that a grace period has elapsed. - */ -void wakeme_after_rcu(struct rcu_head *head) -{ - struct rcu_synchronize *rcu; - - rcu = container_of(head, struct rcu_synchronize, head); - complete(&rcu->completion); -} -EXPORT_SYMBOL_GPL(wakeme_after_rcu); - -void __wait_rcu_gp(bool checktiny, int n, call_rcu_func_t *crcu_array, - struct rcu_synchronize *rs_array) -{ - int i; - - /* Initialize and register callbacks for each flavor specified. */ - for (i = 0; i < n; i++) { - if (checktiny && - (crcu_array[i] == call_rcu || - crcu_array[i] == call_rcu_bh)) { - might_sleep(); - continue; - } - init_rcu_head_on_stack(&rs_array[i].head); - init_completion(&rs_array[i].completion); - (crcu_array[i])(&rs_array[i].head, wakeme_after_rcu); - } - - /* Wait for all callbacks to be invoked. */ - for (i = 0; i < n; i++) { - if (checktiny && - (crcu_array[i] == call_rcu || - crcu_array[i] == call_rcu_bh)) - continue; - wait_for_completion(&rs_array[i].completion); - destroy_rcu_head_on_stack(&rs_array[i].head); - } -} -EXPORT_SYMBOL_GPL(__wait_rcu_gp); - -#ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD -void init_rcu_head(struct rcu_head *head) -{ - debug_object_init(head, &rcuhead_debug_descr); -} - -void destroy_rcu_head(struct rcu_head *head) -{ - debug_object_free(head, &rcuhead_debug_descr); -} - -static bool rcuhead_is_static_object(void *addr) -{ - return true; -} - -/** - * init_rcu_head_on_stack() - initialize on-stack rcu_head for debugobjects - * @head: pointer to rcu_head structure to be initialized - * - * This function informs debugobjects of a new rcu_head structure that - * has been allocated as an auto variable on the stack. This function - * is not required for rcu_head structures that are statically defined or - * that are dynamically allocated on the heap. This function has no - * effect for !CONFIG_DEBUG_OBJECTS_RCU_HEAD kernel builds. - */ -void init_rcu_head_on_stack(struct rcu_head *head) -{ - debug_object_init_on_stack(head, &rcuhead_debug_descr); -} -EXPORT_SYMBOL_GPL(init_rcu_head_on_stack); - -/** - * destroy_rcu_head_on_stack() - destroy on-stack rcu_head for debugobjects - * @head: pointer to rcu_head structure to be initialized - * - * This function informs debugobjects that an on-stack rcu_head structure - * is about to go out of scope. As with init_rcu_head_on_stack(), this - * function is not required for rcu_head structures that are statically - * defined or that are dynamically allocated on the heap. Also as with - * init_rcu_head_on_stack(), this function has no effect for - * !CONFIG_DEBUG_OBJECTS_RCU_HEAD kernel builds. - */ -void destroy_rcu_head_on_stack(struct rcu_head *head) -{ - debug_object_free(head, &rcuhead_debug_descr); -} -EXPORT_SYMBOL_GPL(destroy_rcu_head_on_stack); - -struct debug_obj_descr rcuhead_debug_descr = { - .name = "rcu_head", - .is_static_object = rcuhead_is_static_object, -}; -EXPORT_SYMBOL_GPL(rcuhead_debug_descr); -#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ - -#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU) || defined(CONFIG_RCU_TRACE) -void do_trace_rcu_torture_read(const char *rcutorturename, struct rcu_head *rhp, - unsigned long secs, - unsigned long c_old, unsigned long c) -{ - trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c); -} -EXPORT_SYMBOL_GPL(do_trace_rcu_torture_read); -#else -#define do_trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \ - do { } while (0) -#endif - -#ifdef CONFIG_RCU_STALL_COMMON - -#ifdef CONFIG_PROVE_RCU -#define RCU_STALL_DELAY_DELTA (5 * HZ) -#else -#define RCU_STALL_DELAY_DELTA 0 -#endif - -int rcu_cpu_stall_suppress __read_mostly; /* 1 = suppress stall warnings. */ -static int rcu_cpu_stall_timeout __read_mostly = CONFIG_RCU_CPU_STALL_TIMEOUT; - -module_param(rcu_cpu_stall_suppress, int, 0644); -module_param(rcu_cpu_stall_timeout, int, 0644); - -int rcu_jiffies_till_stall_check(void) -{ - int till_stall_check = READ_ONCE(rcu_cpu_stall_timeout); - - /* - * Limit check must be consistent with the Kconfig limits - * for CONFIG_RCU_CPU_STALL_TIMEOUT. - */ - if (till_stall_check < 3) { - WRITE_ONCE(rcu_cpu_stall_timeout, 3); - till_stall_check = 3; - } else if (till_stall_check > 300) { - WRITE_ONCE(rcu_cpu_stall_timeout, 300); - till_stall_check = 300; - } - return till_stall_check * HZ + RCU_STALL_DELAY_DELTA; -} - -void rcu_sysrq_start(void) -{ - if (!rcu_cpu_stall_suppress) - rcu_cpu_stall_suppress = 2; -} - -void rcu_sysrq_end(void) -{ - if (rcu_cpu_stall_suppress == 2) - rcu_cpu_stall_suppress = 0; -} - -static int rcu_panic(struct notifier_block *this, unsigned long ev, void *ptr) -{ - rcu_cpu_stall_suppress = 1; - return NOTIFY_DONE; -} - -static struct notifier_block rcu_panic_block = { - .notifier_call = rcu_panic, -}; - -static int __init check_cpu_stall_init(void) -{ - atomic_notifier_chain_register(&panic_notifier_list, &rcu_panic_block); - return 0; -} -early_initcall(check_cpu_stall_init); - -#endif /* #ifdef CONFIG_RCU_STALL_COMMON */ - -#ifdef CONFIG_TASKS_RCU - -/* - * Simple variant of RCU whose quiescent states are voluntary context switch, - * user-space execution, and idle. As such, grace periods can take one good - * long time. There are no read-side primitives similar to rcu_read_lock() - * and rcu_read_unlock() because this implementation is intended to get - * the system into a safe state for some of the manipulations involved in - * tracing and the like. Finally, this implementation does not support - * high call_rcu_tasks() rates from multiple CPUs. If this is required, - * per-CPU callback lists will be needed. - */ - -/* Global list of callbacks and associated lock. */ -static struct rcu_head *rcu_tasks_cbs_head; -static struct rcu_head **rcu_tasks_cbs_tail = &rcu_tasks_cbs_head; -static DECLARE_WAIT_QUEUE_HEAD(rcu_tasks_cbs_wq); -static DEFINE_RAW_SPINLOCK(rcu_tasks_cbs_lock); - -/* Track exiting tasks in order to allow them to be waited for. */ -DEFINE_SRCU(tasks_rcu_exit_srcu); - -/* Control stall timeouts. Disable with <= 0, otherwise jiffies till stall. */ -static int rcu_task_stall_timeout __read_mostly = HZ * 60 * 10; -module_param(rcu_task_stall_timeout, int, 0644); - -static void rcu_spawn_tasks_kthread(void); -static struct task_struct *rcu_tasks_kthread_ptr; - -/* - * Post an RCU-tasks callback. First call must be from process context - * after the scheduler if fully operational. - */ -void call_rcu_tasks(struct rcu_head *rhp, rcu_callback_t func) -{ - unsigned long flags; - bool needwake; - bool havetask = READ_ONCE(rcu_tasks_kthread_ptr); - - rhp->next = NULL; - rhp->func = func; - raw_spin_lock_irqsave(&rcu_tasks_cbs_lock, flags); - needwake = !rcu_tasks_cbs_head; - *rcu_tasks_cbs_tail = rhp; - rcu_tasks_cbs_tail = &rhp->next; - raw_spin_unlock_irqrestore(&rcu_tasks_cbs_lock, flags); - /* We can't create the thread unless interrupts are enabled. */ - if ((needwake && havetask) || - (!havetask && !irqs_disabled_flags(flags))) { - rcu_spawn_tasks_kthread(); - wake_up(&rcu_tasks_cbs_wq); - } -} -EXPORT_SYMBOL_GPL(call_rcu_tasks); - -/** - * synchronize_rcu_tasks - wait until an rcu-tasks grace period has elapsed. - * - * Control will return to the caller some time after a full rcu-tasks - * grace period has elapsed, in other words after all currently - * executing rcu-tasks read-side critical sections have elapsed. These - * read-side critical sections are delimited by calls to schedule(), - * cond_resched_rcu_qs(), idle execution, userspace execution, calls - * to synchronize_rcu_tasks(), and (in theory, anyway) cond_resched(). - * - * This is a very specialized primitive, intended only for a few uses in - * tracing and other situations requiring manipulation of function - * preambles and profiling hooks. The synchronize_rcu_tasks() function - * is not (yet) intended for heavy use from multiple CPUs. - * - * Note that this guarantee implies further memory-ordering guarantees. - * On systems with more than one CPU, when synchronize_rcu_tasks() returns, - * each CPU is guaranteed to have executed a full memory barrier since the - * end of its last RCU-tasks read-side critical section whose beginning - * preceded the call to synchronize_rcu_tasks(). In addition, each CPU - * having an RCU-tasks read-side critical section that extends beyond - * the return from synchronize_rcu_tasks() is guaranteed to have executed - * a full memory barrier after the beginning of synchronize_rcu_tasks() - * and before the beginning of that RCU-tasks read-side critical section. - * Note that these guarantees include CPUs that are offline, idle, or - * executing in user mode, as well as CPUs that are executing in the kernel. - * - * Furthermore, if CPU A invoked synchronize_rcu_tasks(), which returned - * to its caller on CPU B, then both CPU A and CPU B are guaranteed - * to have executed a full memory barrier during the execution of - * synchronize_rcu_tasks() -- even if CPU A and CPU B are the same CPU - * (but again only if the system has more than one CPU). - */ -void synchronize_rcu_tasks(void) -{ - /* Complain if the scheduler has not started. */ - RCU_LOCKDEP_WARN(!rcu_scheduler_active, - "synchronize_rcu_tasks called too soon"); - - /* Wait for the grace period. */ - wait_rcu_gp(call_rcu_tasks); -} -EXPORT_SYMBOL_GPL(synchronize_rcu_tasks); - -/** - * rcu_barrier_tasks - Wait for in-flight call_rcu_tasks() callbacks. - * - * Although the current implementation is guaranteed to wait, it is not - * obligated to, for example, if there are no pending callbacks. - */ -void rcu_barrier_tasks(void) -{ - /* There is only one callback queue, so this is easy. ;-) */ - synchronize_rcu_tasks(); -} -EXPORT_SYMBOL_GPL(rcu_barrier_tasks); - -/* See if tasks are still holding out, complain if so. */ -static void check_holdout_task(struct task_struct *t, - bool needreport, bool *firstreport) -{ - int cpu; - - if (!READ_ONCE(t->rcu_tasks_holdout) || - t->rcu_tasks_nvcsw != READ_ONCE(t->nvcsw) || - !READ_ONCE(t->on_rq) || - (IS_ENABLED(CONFIG_NO_HZ_FULL) && - !is_idle_task(t) && t->rcu_tasks_idle_cpu >= 0)) { - WRITE_ONCE(t->rcu_tasks_holdout, false); - list_del_init(&t->rcu_tasks_holdout_list); - put_task_struct(t); - return; - } - if (!needreport) - return; - if (*firstreport) { - pr_err("INFO: rcu_tasks detected stalls on tasks:\n"); - *firstreport = false; - } - cpu = task_cpu(t); - pr_alert("%p: %c%c nvcsw: %lu/%lu holdout: %d idle_cpu: %d/%d\n", - t, ".I"[is_idle_task(t)], - "N."[cpu < 0 || !tick_nohz_full_cpu(cpu)], - t->rcu_tasks_nvcsw, t->nvcsw, t->rcu_tasks_holdout, - t->rcu_tasks_idle_cpu, cpu); - sched_show_task(t); -} - -/* RCU-tasks kthread that detects grace periods and invokes callbacks. */ -static int __noreturn rcu_tasks_kthread(void *arg) -{ - unsigned long flags; - struct task_struct *g, *t; - unsigned long lastreport; - struct rcu_head *list; - struct rcu_head *next; - LIST_HEAD(rcu_tasks_holdouts); - - /* Run on housekeeping CPUs by default. Sysadm can move if desired. */ - housekeeping_affine(current); - - /* - * Each pass through the following loop makes one check for - * newly arrived callbacks, and, if there are some, waits for - * one RCU-tasks grace period and then invokes the callbacks. - * This loop is terminated by the system going down. ;-) - */ - for (;;) { - - /* Pick up any new callbacks. */ - raw_spin_lock_irqsave(&rcu_tasks_cbs_lock, flags); - list = rcu_tasks_cbs_head; - rcu_tasks_cbs_head = NULL; - rcu_tasks_cbs_tail = &rcu_tasks_cbs_head; - raw_spin_unlock_irqrestore(&rcu_tasks_cbs_lock, flags); - - /* If there were none, wait a bit and start over. */ - if (!list) { - wait_event_interruptible(rcu_tasks_cbs_wq, - rcu_tasks_cbs_head); - if (!rcu_tasks_cbs_head) { - WARN_ON(signal_pending(current)); - schedule_timeout_interruptible(HZ/10); - } - continue; - } - - /* - * Wait for all pre-existing t->on_rq and t->nvcsw - * transitions to complete. Invoking synchronize_sched() - * suffices because all these transitions occur with - * interrupts disabled. Without this synchronize_sched(), - * a read-side critical section that started before the - * grace period might be incorrectly seen as having started - * after the grace period. - * - * This synchronize_sched() also dispenses with the - * need for a memory barrier on the first store to - * ->rcu_tasks_holdout, as it forces the store to happen - * after the beginning of the grace period. - */ - synchronize_sched(); - - /* - * There were callbacks, so we need to wait for an - * RCU-tasks grace period. Start off by scanning - * the task list for tasks that are not already - * voluntarily blocked. Mark these tasks and make - * a list of them in rcu_tasks_holdouts. - */ - rcu_read_lock(); - for_each_process_thread(g, t) { - if (t != current && READ_ONCE(t->on_rq) && - !is_idle_task(t)) { - get_task_struct(t); - t->rcu_tasks_nvcsw = READ_ONCE(t->nvcsw); - WRITE_ONCE(t->rcu_tasks_holdout, true); - list_add(&t->rcu_tasks_holdout_list, - &rcu_tasks_holdouts); - } - } - rcu_read_unlock(); - - /* - * Wait for tasks that are in the process of exiting. - * This does only part of the job, ensuring that all - * tasks that were previously exiting reach the point - * where they have disabled preemption, allowing the - * later synchronize_sched() to finish the job. - */ - synchronize_srcu(&tasks_rcu_exit_srcu); - - /* - * Each pass through the following loop scans the list - * of holdout tasks, removing any that are no longer - * holdouts. When the list is empty, we are done. - */ - lastreport = jiffies; - while (!list_empty(&rcu_tasks_holdouts)) { - bool firstreport; - bool needreport; - int rtst; - struct task_struct *t1; - - schedule_timeout_interruptible(HZ); - rtst = READ_ONCE(rcu_task_stall_timeout); - needreport = rtst > 0 && - time_after(jiffies, lastreport + rtst); - if (needreport) - lastreport = jiffies; - firstreport = true; - WARN_ON(signal_pending(current)); - list_for_each_entry_safe(t, t1, &rcu_tasks_holdouts, - rcu_tasks_holdout_list) { - check_holdout_task(t, needreport, &firstreport); - cond_resched(); - } - } - - /* - * Because ->on_rq and ->nvcsw are not guaranteed - * to have a full memory barriers prior to them in the - * schedule() path, memory reordering on other CPUs could - * cause their RCU-tasks read-side critical sections to - * extend past the end of the grace period. However, - * because these ->nvcsw updates are carried out with - * interrupts disabled, we can use synchronize_sched() - * to force the needed ordering on all such CPUs. - * - * This synchronize_sched() also confines all - * ->rcu_tasks_holdout accesses to be within the grace - * period, avoiding the need for memory barriers for - * ->rcu_tasks_holdout accesses. - * - * In addition, this synchronize_sched() waits for exiting - * tasks to complete their final preempt_disable() region - * of execution, cleaning up after the synchronize_srcu() - * above. - */ - synchronize_sched(); - - /* Invoke the callbacks. */ - while (list) { - next = list->next; - local_bh_disable(); - list->func(list); - local_bh_enable(); - list = next; - cond_resched(); - } - schedule_timeout_uninterruptible(HZ/10); - } -} - -/* Spawn rcu_tasks_kthread() at first call to call_rcu_tasks(). */ -static void rcu_spawn_tasks_kthread(void) -{ - static DEFINE_MUTEX(rcu_tasks_kthread_mutex); - struct task_struct *t; - - if (READ_ONCE(rcu_tasks_kthread_ptr)) { - smp_mb(); /* Ensure caller sees full kthread. */ - return; - } - mutex_lock(&rcu_tasks_kthread_mutex); - if (rcu_tasks_kthread_ptr) { - mutex_unlock(&rcu_tasks_kthread_mutex); - return; - } - t = kthread_run(rcu_tasks_kthread, NULL, "rcu_tasks_kthread"); - BUG_ON(IS_ERR(t)); - smp_mb(); /* Ensure others see full kthread. */ - WRITE_ONCE(rcu_tasks_kthread_ptr, t); - mutex_unlock(&rcu_tasks_kthread_mutex); -} - -#endif /* #ifdef CONFIG_TASKS_RCU */ - -#ifdef CONFIG_PROVE_RCU - -/* - * Early boot self test parameters, one for each flavor - */ -static bool rcu_self_test; -static bool rcu_self_test_bh; -static bool rcu_self_test_sched; - -module_param(rcu_self_test, bool, 0444); -module_param(rcu_self_test_bh, bool, 0444); -module_param(rcu_self_test_sched, bool, 0444); - -static int rcu_self_test_counter; - -static void test_callback(struct rcu_head *r) -{ - rcu_self_test_counter++; - pr_info("RCU test callback executed %d\n", rcu_self_test_counter); -} - -static void early_boot_test_call_rcu(void) -{ - static struct rcu_head head; - - call_rcu(&head, test_callback); -} - -static void early_boot_test_call_rcu_bh(void) -{ - static struct rcu_head head; - - call_rcu_bh(&head, test_callback); -} - -static void early_boot_test_call_rcu_sched(void) -{ - static struct rcu_head head; - - call_rcu_sched(&head, test_callback); -} - -void rcu_early_boot_tests(void) -{ - pr_info("Running RCU self tests\n"); - - if (rcu_self_test) - early_boot_test_call_rcu(); - if (rcu_self_test_bh) - early_boot_test_call_rcu_bh(); - if (rcu_self_test_sched) - early_boot_test_call_rcu_sched(); -} - -static int rcu_verify_early_boot_tests(void) -{ - int ret = 0; - int early_boot_test_counter = 0; - - if (rcu_self_test) { - early_boot_test_counter++; - rcu_barrier(); - } - if (rcu_self_test_bh) { - early_boot_test_counter++; - rcu_barrier_bh(); - } - if (rcu_self_test_sched) { - early_boot_test_counter++; - rcu_barrier_sched(); - } - - if (rcu_self_test_counter != early_boot_test_counter) { - WARN_ON(1); - ret = -1; - } - - return ret; -} -late_initcall(rcu_verify_early_boot_tests); -#else -void rcu_early_boot_tests(void) {} -#endif /* CONFIG_PROVE_RCU */ diff --git a/src/linux/kernel/reboot.c b/src/linux/kernel/reboot.c deleted file mode 100644 index bd30a97..0000000 --- a/src/linux/kernel/reboot.c +++ /dev/null @@ -1,557 +0,0 @@ -/* - * linux/kernel/reboot.c - * - * Copyright (C) 2013 Linus Torvalds - */ - -#define pr_fmt(fmt) "reboot: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * this indicates whether you can reboot with ctrl-alt-del: the default is yes - */ - -int C_A_D = 1; -struct pid *cad_pid; -EXPORT_SYMBOL(cad_pid); - -#if defined(CONFIG_ARM) || defined(CONFIG_UNICORE32) -#define DEFAULT_REBOOT_MODE = REBOOT_HARD -#else -#define DEFAULT_REBOOT_MODE -#endif -enum reboot_mode reboot_mode DEFAULT_REBOOT_MODE; - -/* - * This variable is used privately to keep track of whether or not - * reboot_type is still set to its default value (i.e., reboot= hasn't - * been set on the command line). This is needed so that we can - * suppress DMI scanning for reboot quirks. Without it, it's - * impossible to override a faulty reboot quirk without recompiling. - */ -int reboot_default = 1; -int reboot_cpu; -enum reboot_type reboot_type = BOOT_ACPI; -int reboot_force; - -/* - * If set, this is used for preparing the system to power off. - */ - -void (*pm_power_off_prepare)(void); - -/** - * emergency_restart - reboot the system - * - * Without shutting down any hardware or taking any locks - * reboot the system. This is called when we know we are in - * trouble so this is our best effort to reboot. This is - * safe to call in interrupt context. - */ -void emergency_restart(void) -{ - kmsg_dump(KMSG_DUMP_EMERG); - machine_emergency_restart(); -} -EXPORT_SYMBOL_GPL(emergency_restart); - -void kernel_restart_prepare(char *cmd) -{ - blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); - system_state = SYSTEM_RESTART; - usermodehelper_disable(); - device_shutdown(); -} - -/** - * register_reboot_notifier - Register function to be called at reboot time - * @nb: Info about notifier function to be called - * - * Registers a function with the list of functions - * to be called at reboot time. - * - * Currently always returns zero, as blocking_notifier_chain_register() - * always returns zero. - */ -int register_reboot_notifier(struct notifier_block *nb) -{ - return blocking_notifier_chain_register(&reboot_notifier_list, nb); -} -EXPORT_SYMBOL(register_reboot_notifier); - -/** - * unregister_reboot_notifier - Unregister previously registered reboot notifier - * @nb: Hook to be unregistered - * - * Unregisters a previously registered reboot - * notifier function. - * - * Returns zero on success, or %-ENOENT on failure. - */ -int unregister_reboot_notifier(struct notifier_block *nb) -{ - return blocking_notifier_chain_unregister(&reboot_notifier_list, nb); -} -EXPORT_SYMBOL(unregister_reboot_notifier); - -/* - * Notifier list for kernel code which wants to be called - * to restart the system. - */ -static ATOMIC_NOTIFIER_HEAD(restart_handler_list); - -/** - * register_restart_handler - Register function to be called to reset - * the system - * @nb: Info about handler function to be called - * @nb->priority: Handler priority. Handlers should follow the - * following guidelines for setting priorities. - * 0: Restart handler of last resort, - * with limited restart capabilities - * 128: Default restart handler; use if no other - * restart handler is expected to be available, - * and/or if restart functionality is - * sufficient to restart the entire system - * 255: Highest priority restart handler, will - * preempt all other restart handlers - * - * Registers a function with code to be called to restart the - * system. - * - * Registered functions will be called from machine_restart as last - * step of the restart sequence (if the architecture specific - * machine_restart function calls do_kernel_restart - see below - * for details). - * Registered functions are expected to restart the system immediately. - * If more than one function is registered, the restart handler priority - * selects which function will be called first. - * - * Restart handlers are expected to be registered from non-architecture - * code, typically from drivers. A typical use case would be a system - * where restart functionality is provided through a watchdog. Multiple - * restart handlers may exist; for example, one restart handler might - * restart the entire system, while another only restarts the CPU. - * In such cases, the restart handler which only restarts part of the - * hardware is expected to register with low priority to ensure that - * it only runs if no other means to restart the system is available. - * - * Currently always returns zero, as atomic_notifier_chain_register() - * always returns zero. - */ -int register_restart_handler(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&restart_handler_list, nb); -} -EXPORT_SYMBOL(register_restart_handler); - -/** - * unregister_restart_handler - Unregister previously registered - * restart handler - * @nb: Hook to be unregistered - * - * Unregisters a previously registered restart handler function. - * - * Returns zero on success, or %-ENOENT on failure. - */ -int unregister_restart_handler(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&restart_handler_list, nb); -} -EXPORT_SYMBOL(unregister_restart_handler); - -/** - * do_kernel_restart - Execute kernel restart handler call chain - * - * Calls functions registered with register_restart_handler. - * - * Expected to be called from machine_restart as last step of the restart - * sequence. - * - * Restarts the system immediately if a restart handler function has been - * registered. Otherwise does nothing. - */ -void do_kernel_restart(char *cmd) -{ - atomic_notifier_call_chain(&restart_handler_list, reboot_mode, cmd); -} - -void migrate_to_reboot_cpu(void) -{ - /* The boot cpu is always logical cpu 0 */ - int cpu = reboot_cpu; - - cpu_hotplug_disable(); - - /* Make certain the cpu I'm about to reboot on is online */ - if (!cpu_online(cpu)) - cpu = cpumask_first(cpu_online_mask); - - /* Prevent races with other tasks migrating this task */ - current->flags |= PF_NO_SETAFFINITY; - - /* Make certain I only run on the appropriate processor */ - set_cpus_allowed_ptr(current, cpumask_of(cpu)); -} - -/** - * kernel_restart - reboot the system - * @cmd: pointer to buffer containing command to execute for restart - * or %NULL - * - * Shutdown everything and perform a clean reboot. - * This is not safe to call in interrupt context. - */ -void kernel_restart(char *cmd) -{ - kernel_restart_prepare(cmd); - migrate_to_reboot_cpu(); - syscore_shutdown(); - if (!cmd) - pr_emerg("Restarting system\n"); - else - pr_emerg("Restarting system with command '%s'\n", cmd); - kmsg_dump(KMSG_DUMP_RESTART); - machine_restart(cmd); -} -EXPORT_SYMBOL_GPL(kernel_restart); - -static void kernel_shutdown_prepare(enum system_states state) -{ - blocking_notifier_call_chain(&reboot_notifier_list, - (state == SYSTEM_HALT) ? SYS_HALT : SYS_POWER_OFF, NULL); - system_state = state; - usermodehelper_disable(); - device_shutdown(); -} -/** - * kernel_halt - halt the system - * - * Shutdown everything and perform a clean system halt. - */ -void kernel_halt(void) -{ - kernel_shutdown_prepare(SYSTEM_HALT); - migrate_to_reboot_cpu(); - syscore_shutdown(); - pr_emerg("System halted\n"); - kmsg_dump(KMSG_DUMP_HALT); - machine_halt(); -} -EXPORT_SYMBOL_GPL(kernel_halt); - -/** - * kernel_power_off - power_off the system - * - * Shutdown everything and perform a clean system power_off. - */ -void kernel_power_off(void) -{ - kernel_shutdown_prepare(SYSTEM_POWER_OFF); - if (pm_power_off_prepare) - pm_power_off_prepare(); - migrate_to_reboot_cpu(); - syscore_shutdown(); - pr_emerg("Power down\n"); - kmsg_dump(KMSG_DUMP_POWEROFF); - machine_power_off(); -} -EXPORT_SYMBOL_GPL(kernel_power_off); - -static DEFINE_MUTEX(reboot_mutex); - -/* - * Reboot system call: for obvious reasons only root may call it, - * and even root needs to set up some magic numbers in the registers - * so that some mistake won't make this reboot the whole machine. - * You can also set the meaning of the ctrl-alt-del-key here. - * - * reboot doesn't sync: do that yourself before calling this. - */ -SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd, - void __user *, arg) -{ - struct pid_namespace *pid_ns = task_active_pid_ns(current); - char buffer[256]; - int ret = 0; - - /* We only trust the superuser with rebooting the system. */ - if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT)) - return -EPERM; - - /* For safety, we require "magic" arguments. */ - if (magic1 != LINUX_REBOOT_MAGIC1 || - (magic2 != LINUX_REBOOT_MAGIC2 && - magic2 != LINUX_REBOOT_MAGIC2A && - magic2 != LINUX_REBOOT_MAGIC2B && - magic2 != LINUX_REBOOT_MAGIC2C)) - return -EINVAL; - - /* - * If pid namespaces are enabled and the current task is in a child - * pid_namespace, the command is handled by reboot_pid_ns() which will - * call do_exit(). - */ - ret = reboot_pid_ns(pid_ns, cmd); - if (ret) - return ret; - - /* Instead of trying to make the power_off code look like - * halt when pm_power_off is not set do it the easy way. - */ - if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off) - cmd = LINUX_REBOOT_CMD_HALT; - - mutex_lock(&reboot_mutex); - switch (cmd) { - case LINUX_REBOOT_CMD_RESTART: - kernel_restart(NULL); - break; - - case LINUX_REBOOT_CMD_CAD_ON: - C_A_D = 1; - break; - - case LINUX_REBOOT_CMD_CAD_OFF: - C_A_D = 0; - break; - - case LINUX_REBOOT_CMD_HALT: - kernel_halt(); - do_exit(0); - panic("cannot halt"); - - case LINUX_REBOOT_CMD_POWER_OFF: - kernel_power_off(); - do_exit(0); - break; - - case LINUX_REBOOT_CMD_RESTART2: - ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1); - if (ret < 0) { - ret = -EFAULT; - break; - } - buffer[sizeof(buffer) - 1] = '\0'; - - kernel_restart(buffer); - break; - -#ifdef CONFIG_KEXEC_CORE - case LINUX_REBOOT_CMD_KEXEC: - ret = kernel_kexec(); - break; -#endif - -#ifdef CONFIG_HIBERNATION - case LINUX_REBOOT_CMD_SW_SUSPEND: - ret = hibernate(); - break; -#endif - - default: - ret = -EINVAL; - break; - } - mutex_unlock(&reboot_mutex); - return ret; -} - -static void deferred_cad(struct work_struct *dummy) -{ - kernel_restart(NULL); -} - -/* - * This function gets called by ctrl-alt-del - ie the keyboard interrupt. - * As it's called within an interrupt, it may NOT sync: the only choice - * is whether to reboot at once, or just ignore the ctrl-alt-del. - */ -void ctrl_alt_del(void) -{ - static DECLARE_WORK(cad_work, deferred_cad); - - if (C_A_D) - schedule_work(&cad_work); - else - kill_cad_pid(SIGINT, 1); -} - -char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff"; -static const char reboot_cmd[] = "/sbin/reboot"; - -static int run_cmd(const char *cmd) -{ - char **argv; - static char *envp[] = { - "HOME=/", - "PATH=/sbin:/bin:/usr/sbin:/usr/bin", - NULL - }; - int ret; - argv = argv_split(GFP_KERNEL, cmd, NULL); - if (argv) { - ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); - argv_free(argv); - } else { - ret = -ENOMEM; - } - - return ret; -} - -static int __orderly_reboot(void) -{ - int ret; - - ret = run_cmd(reboot_cmd); - - if (ret) { - pr_warn("Failed to start orderly reboot: forcing the issue\n"); - emergency_sync(); - kernel_restart(NULL); - } - - return ret; -} - -static int __orderly_poweroff(bool force) -{ - int ret; - - ret = run_cmd(poweroff_cmd); - - if (ret && force) { - pr_warn("Failed to start orderly shutdown: forcing the issue\n"); - - /* - * I guess this should try to kick off some daemon to sync and - * poweroff asap. Or not even bother syncing if we're doing an - * emergency shutdown? - */ - emergency_sync(); - kernel_power_off(); - } - - return ret; -} - -static bool poweroff_force; - -static void poweroff_work_func(struct work_struct *work) -{ - __orderly_poweroff(poweroff_force); -} - -static DECLARE_WORK(poweroff_work, poweroff_work_func); - -/** - * orderly_poweroff - Trigger an orderly system poweroff - * @force: force poweroff if command execution fails - * - * This may be called from any context to trigger a system shutdown. - * If the orderly shutdown fails, it will force an immediate shutdown. - */ -void orderly_poweroff(bool force) -{ - if (force) /* do not override the pending "true" */ - poweroff_force = true; - schedule_work(&poweroff_work); -} -EXPORT_SYMBOL_GPL(orderly_poweroff); - -static void reboot_work_func(struct work_struct *work) -{ - __orderly_reboot(); -} - -static DECLARE_WORK(reboot_work, reboot_work_func); - -/** - * orderly_reboot - Trigger an orderly system reboot - * - * This may be called from any context to trigger a system reboot. - * If the orderly reboot fails, it will force an immediate reboot. - */ -void orderly_reboot(void) -{ - schedule_work(&reboot_work); -} -EXPORT_SYMBOL_GPL(orderly_reboot); - -static int __init reboot_setup(char *str) -{ - for (;;) { - /* - * Having anything passed on the command line via - * reboot= will cause us to disable DMI checking - * below. - */ - reboot_default = 0; - - switch (*str) { - case 'w': - reboot_mode = REBOOT_WARM; - break; - - case 'c': - reboot_mode = REBOOT_COLD; - break; - - case 'h': - reboot_mode = REBOOT_HARD; - break; - - case 's': - { - int rc; - - if (isdigit(*(str+1))) { - rc = kstrtoint(str+1, 0, &reboot_cpu); - if (rc) - return rc; - } else if (str[1] == 'm' && str[2] == 'p' && - isdigit(*(str+3))) { - rc = kstrtoint(str+3, 0, &reboot_cpu); - if (rc) - return rc; - } else - reboot_mode = REBOOT_SOFT; - break; - } - case 'g': - reboot_mode = REBOOT_GPIO; - break; - - case 'b': - case 'a': - case 'k': - case 't': - case 'e': - case 'p': - reboot_type = *str; - break; - - case 'f': - reboot_force = 1; - break; - } - - str = strchr(str, ','); - if (str) - str++; - else - break; - } - return 1; -} -__setup("reboot=", reboot_setup); diff --git a/src/linux/kernel/resource.c b/src/linux/kernel/resource.c deleted file mode 100644 index 9b5f044..0000000 --- a/src/linux/kernel/resource.c +++ /dev/null @@ -1,1623 +0,0 @@ -/* - * linux/kernel/resource.c - * - * Copyright (C) 1999 Linus Torvalds - * Copyright (C) 1999 Martin Mares - * - * Arbitrary resource management. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -struct resource ioport_resource = { - .name = "PCI IO", - .start = 0, - .end = IO_SPACE_LIMIT, - .flags = IORESOURCE_IO, -}; -EXPORT_SYMBOL(ioport_resource); - -struct resource iomem_resource = { - .name = "PCI mem", - .start = 0, - .end = -1, - .flags = IORESOURCE_MEM, -}; -EXPORT_SYMBOL(iomem_resource); - -/* constraints to be met while allocating resources */ -struct resource_constraint { - resource_size_t min, max, align; - resource_size_t (*alignf)(void *, const struct resource *, - resource_size_t, resource_size_t); - void *alignf_data; -}; - -static DEFINE_RWLOCK(resource_lock); - -/* - * For memory hotplug, there is no way to free resource entries allocated - * by boot mem after the system is up. So for reusing the resource entry - * we need to remember the resource. - */ -static struct resource *bootmem_resource_free; -static DEFINE_SPINLOCK(bootmem_resource_lock); - -static struct resource *next_resource(struct resource *p, bool sibling_only) -{ - /* Caller wants to traverse through siblings only */ - if (sibling_only) - return p->sibling; - - if (p->child) - return p->child; - while (!p->sibling && p->parent) - p = p->parent; - return p->sibling; -} - -static void *r_next(struct seq_file *m, void *v, loff_t *pos) -{ - struct resource *p = v; - (*pos)++; - return (void *)next_resource(p, false); -} - -#ifdef CONFIG_PROC_FS - -enum { MAX_IORES_LEVEL = 5 }; - -static void *r_start(struct seq_file *m, loff_t *pos) - __acquires(resource_lock) -{ - struct resource *p = m->private; - loff_t l = 0; - read_lock(&resource_lock); - for (p = p->child; p && l < *pos; p = r_next(m, p, &l)) - ; - return p; -} - -static void r_stop(struct seq_file *m, void *v) - __releases(resource_lock) -{ - read_unlock(&resource_lock); -} - -static int r_show(struct seq_file *m, void *v) -{ - struct resource *root = m->private; - struct resource *r = v, *p; - unsigned long long start, end; - int width = root->end < 0x10000 ? 4 : 8; - int depth; - - for (depth = 0, p = r; depth < MAX_IORES_LEVEL; depth++, p = p->parent) - if (p->parent == root) - break; - - if (file_ns_capable(m->file, &init_user_ns, CAP_SYS_ADMIN)) { - start = r->start; - end = r->end; - } else { - start = end = 0; - } - - seq_printf(m, "%*s%0*llx-%0*llx : %s\n", - depth * 2, "", - width, start, - width, end, - r->name ? r->name : ""); - return 0; -} - -static const struct seq_operations resource_op = { - .start = r_start, - .next = r_next, - .stop = r_stop, - .show = r_show, -}; - -static int ioports_open(struct inode *inode, struct file *file) -{ - int res = seq_open(file, &resource_op); - if (!res) { - struct seq_file *m = file->private_data; - m->private = &ioport_resource; - } - return res; -} - -static int iomem_open(struct inode *inode, struct file *file) -{ - int res = seq_open(file, &resource_op); - if (!res) { - struct seq_file *m = file->private_data; - m->private = &iomem_resource; - } - return res; -} - -static const struct file_operations proc_ioports_operations = { - .open = ioports_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static const struct file_operations proc_iomem_operations = { - .open = iomem_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int __init ioresources_init(void) -{ - proc_create("ioports", 0, NULL, &proc_ioports_operations); - proc_create("iomem", 0, NULL, &proc_iomem_operations); - return 0; -} -__initcall(ioresources_init); - -#endif /* CONFIG_PROC_FS */ - -static void free_resource(struct resource *res) -{ - if (!res) - return; - - if (!PageSlab(virt_to_head_page(res))) { - spin_lock(&bootmem_resource_lock); - res->sibling = bootmem_resource_free; - bootmem_resource_free = res; - spin_unlock(&bootmem_resource_lock); - } else { - kfree(res); - } -} - -static struct resource *alloc_resource(gfp_t flags) -{ - struct resource *res = NULL; - - spin_lock(&bootmem_resource_lock); - if (bootmem_resource_free) { - res = bootmem_resource_free; - bootmem_resource_free = res->sibling; - } - spin_unlock(&bootmem_resource_lock); - - if (res) - memset(res, 0, sizeof(struct resource)); - else - res = kzalloc(sizeof(struct resource), flags); - - return res; -} - -/* Return the conflict entry if you can't request it */ -static struct resource * __request_resource(struct resource *root, struct resource *new) -{ - resource_size_t start = new->start; - resource_size_t end = new->end; - struct resource *tmp, **p; - - if (end < start) - return root; - if (start < root->start) - return root; - if (end > root->end) - return root; - p = &root->child; - for (;;) { - tmp = *p; - if (!tmp || tmp->start > end) { - new->sibling = tmp; - *p = new; - new->parent = root; - return NULL; - } - p = &tmp->sibling; - if (tmp->end < start) - continue; - return tmp; - } -} - -static int __release_resource(struct resource *old, bool release_child) -{ - struct resource *tmp, **p, *chd; - - p = &old->parent->child; - for (;;) { - tmp = *p; - if (!tmp) - break; - if (tmp == old) { - if (release_child || !(tmp->child)) { - *p = tmp->sibling; - } else { - for (chd = tmp->child;; chd = chd->sibling) { - chd->parent = tmp->parent; - if (!(chd->sibling)) - break; - } - *p = tmp->child; - chd->sibling = tmp->sibling; - } - old->parent = NULL; - return 0; - } - p = &tmp->sibling; - } - return -EINVAL; -} - -static void __release_child_resources(struct resource *r) -{ - struct resource *tmp, *p; - resource_size_t size; - - p = r->child; - r->child = NULL; - while (p) { - tmp = p; - p = p->sibling; - - tmp->parent = NULL; - tmp->sibling = NULL; - __release_child_resources(tmp); - - printk(KERN_DEBUG "release child resource %pR\n", tmp); - /* need to restore size, and keep flags */ - size = resource_size(tmp); - tmp->start = 0; - tmp->end = size - 1; - } -} - -void release_child_resources(struct resource *r) -{ - write_lock(&resource_lock); - __release_child_resources(r); - write_unlock(&resource_lock); -} - -/** - * request_resource_conflict - request and reserve an I/O or memory resource - * @root: root resource descriptor - * @new: resource descriptor desired by caller - * - * Returns 0 for success, conflict resource on error. - */ -struct resource *request_resource_conflict(struct resource *root, struct resource *new) -{ - struct resource *conflict; - - write_lock(&resource_lock); - conflict = __request_resource(root, new); - write_unlock(&resource_lock); - return conflict; -} - -/** - * request_resource - request and reserve an I/O or memory resource - * @root: root resource descriptor - * @new: resource descriptor desired by caller - * - * Returns 0 for success, negative error code on error. - */ -int request_resource(struct resource *root, struct resource *new) -{ - struct resource *conflict; - - conflict = request_resource_conflict(root, new); - return conflict ? -EBUSY : 0; -} - -EXPORT_SYMBOL(request_resource); - -/** - * release_resource - release a previously reserved resource - * @old: resource pointer - */ -int release_resource(struct resource *old) -{ - int retval; - - write_lock(&resource_lock); - retval = __release_resource(old, true); - write_unlock(&resource_lock); - return retval; -} - -EXPORT_SYMBOL(release_resource); - -/* - * Finds the lowest iomem resource existing within [res->start.res->end). - * The caller must specify res->start, res->end, res->flags, and optionally - * desc. If found, returns 0, res is overwritten, if not found, returns -1. - * This function walks the whole tree and not just first level children until - * and unless first_level_children_only is true. - */ -static int find_next_iomem_res(struct resource *res, unsigned long desc, - bool first_level_children_only) -{ - resource_size_t start, end; - struct resource *p; - bool sibling_only = false; - - BUG_ON(!res); - - start = res->start; - end = res->end; - BUG_ON(start >= end); - - if (first_level_children_only) - sibling_only = true; - - read_lock(&resource_lock); - - for (p = iomem_resource.child; p; p = next_resource(p, sibling_only)) { - if ((p->flags & res->flags) != res->flags) - continue; - if ((desc != IORES_DESC_NONE) && (desc != p->desc)) - continue; - if (p->start > end) { - p = NULL; - break; - } - if ((p->end >= start) && (p->start < end)) - break; - } - - read_unlock(&resource_lock); - if (!p) - return -1; - /* copy data */ - if (res->start < p->start) - res->start = p->start; - if (res->end > p->end) - res->end = p->end; - return 0; -} - -/* - * Walks through iomem resources and calls func() with matching resource - * ranges. This walks through whole tree and not just first level children. - * All the memory ranges which overlap start,end and also match flags and - * desc are valid candidates. - * - * @desc: I/O resource descriptor. Use IORES_DESC_NONE to skip @desc check. - * @flags: I/O resource flags - * @start: start addr - * @end: end addr - * - * NOTE: For a new descriptor search, define a new IORES_DESC in - * and set it in 'desc' of a target resource entry. - */ -int walk_iomem_res_desc(unsigned long desc, unsigned long flags, u64 start, - u64 end, void *arg, int (*func)(u64, u64, void *)) -{ - struct resource res; - u64 orig_end; - int ret = -1; - - res.start = start; - res.end = end; - res.flags = flags; - orig_end = res.end; - - while ((res.start < res.end) && - (!find_next_iomem_res(&res, desc, false))) { - - ret = (*func)(res.start, res.end, arg); - if (ret) - break; - - res.start = res.end + 1; - res.end = orig_end; - } - - return ret; -} - -/* - * This function calls the @func callback against all memory ranges of type - * System RAM which are marked as IORESOURCE_SYSTEM_RAM and IORESOUCE_BUSY. - * Now, this function is only for System RAM, it deals with full ranges and - * not PFNs. If resources are not PFN-aligned, dealing with PFNs can truncate - * ranges. - */ -int walk_system_ram_res(u64 start, u64 end, void *arg, - int (*func)(u64, u64, void *)) -{ - struct resource res; - u64 orig_end; - int ret = -1; - - res.start = start; - res.end = end; - res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; - orig_end = res.end; - while ((res.start < res.end) && - (!find_next_iomem_res(&res, IORES_DESC_NONE, true))) { - ret = (*func)(res.start, res.end, arg); - if (ret) - break; - res.start = res.end + 1; - res.end = orig_end; - } - return ret; -} - -#if !defined(CONFIG_ARCH_HAS_WALK_MEMORY) - -/* - * This function calls the @func callback against all memory ranges of type - * System RAM which are marked as IORESOURCE_SYSTEM_RAM and IORESOUCE_BUSY. - * It is to be used only for System RAM. - */ -int walk_system_ram_range(unsigned long start_pfn, unsigned long nr_pages, - void *arg, int (*func)(unsigned long, unsigned long, void *)) -{ - struct resource res; - unsigned long pfn, end_pfn; - u64 orig_end; - int ret = -1; - - res.start = (u64) start_pfn << PAGE_SHIFT; - res.end = ((u64)(start_pfn + nr_pages) << PAGE_SHIFT) - 1; - res.flags = IORESOURCE_SYSTEM_RAM | IORESOURCE_BUSY; - orig_end = res.end; - while ((res.start < res.end) && - (find_next_iomem_res(&res, IORES_DESC_NONE, true) >= 0)) { - pfn = (res.start + PAGE_SIZE - 1) >> PAGE_SHIFT; - end_pfn = (res.end + 1) >> PAGE_SHIFT; - if (end_pfn > pfn) - ret = (*func)(pfn, end_pfn - pfn, arg); - if (ret) - break; - res.start = res.end + 1; - res.end = orig_end; - } - return ret; -} - -#endif - -static int __is_ram(unsigned long pfn, unsigned long nr_pages, void *arg) -{ - return 1; -} -/* - * This generic page_is_ram() returns true if specified address is - * registered as System RAM in iomem_resource list. - */ -int __weak page_is_ram(unsigned long pfn) -{ - return walk_system_ram_range(pfn, 1, NULL, __is_ram) == 1; -} -EXPORT_SYMBOL_GPL(page_is_ram); - -/** - * region_intersects() - determine intersection of region with known resources - * @start: region start address - * @size: size of region - * @flags: flags of resource (in iomem_resource) - * @desc: descriptor of resource (in iomem_resource) or IORES_DESC_NONE - * - * Check if the specified region partially overlaps or fully eclipses a - * resource identified by @flags and @desc (optional with IORES_DESC_NONE). - * Return REGION_DISJOINT if the region does not overlap @flags/@desc, - * return REGION_MIXED if the region overlaps @flags/@desc and another - * resource, and return REGION_INTERSECTS if the region overlaps @flags/@desc - * and no other defined resource. Note that REGION_INTERSECTS is also - * returned in the case when the specified region overlaps RAM and undefined - * memory holes. - * - * region_intersect() is used by memory remapping functions to ensure - * the user is not remapping RAM and is a vast speed up over walking - * through the resource table page by page. - */ -int region_intersects(resource_size_t start, size_t size, unsigned long flags, - unsigned long desc) -{ - resource_size_t end = start + size - 1; - int type = 0; int other = 0; - struct resource *p; - - read_lock(&resource_lock); - for (p = iomem_resource.child; p ; p = p->sibling) { - bool is_type = (((p->flags & flags) == flags) && - ((desc == IORES_DESC_NONE) || - (desc == p->desc))); - - if (start >= p->start && start <= p->end) - is_type ? type++ : other++; - if (end >= p->start && end <= p->end) - is_type ? type++ : other++; - if (p->start >= start && p->end <= end) - is_type ? type++ : other++; - } - read_unlock(&resource_lock); - - if (other == 0) - return type ? REGION_INTERSECTS : REGION_DISJOINT; - - if (type) - return REGION_MIXED; - - return REGION_DISJOINT; -} -EXPORT_SYMBOL_GPL(region_intersects); - -void __weak arch_remove_reservations(struct resource *avail) -{ -} - -static resource_size_t simple_align_resource(void *data, - const struct resource *avail, - resource_size_t size, - resource_size_t align) -{ - return avail->start; -} - -static void resource_clip(struct resource *res, resource_size_t min, - resource_size_t max) -{ - if (res->start < min) - res->start = min; - if (res->end > max) - res->end = max; -} - -/* - * Find empty slot in the resource tree with the given range and - * alignment constraints - */ -static int __find_resource(struct resource *root, struct resource *old, - struct resource *new, - resource_size_t size, - struct resource_constraint *constraint) -{ - struct resource *this = root->child; - struct resource tmp = *new, avail, alloc; - - tmp.start = root->start; - /* - * Skip past an allocated resource that starts at 0, since the assignment - * of this->start - 1 to tmp->end below would cause an underflow. - */ - if (this && this->start == root->start) { - tmp.start = (this == old) ? old->start : this->end + 1; - this = this->sibling; - } - for(;;) { - if (this) - tmp.end = (this == old) ? this->end : this->start - 1; - else - tmp.end = root->end; - - if (tmp.end < tmp.start) - goto next; - - resource_clip(&tmp, constraint->min, constraint->max); - arch_remove_reservations(&tmp); - - /* Check for overflow after ALIGN() */ - avail.start = ALIGN(tmp.start, constraint->align); - avail.end = tmp.end; - avail.flags = new->flags & ~IORESOURCE_UNSET; - if (avail.start >= tmp.start) { - alloc.flags = avail.flags; - alloc.start = constraint->alignf(constraint->alignf_data, &avail, - size, constraint->align); - alloc.end = alloc.start + size - 1; - if (resource_contains(&avail, &alloc)) { - new->start = alloc.start; - new->end = alloc.end; - return 0; - } - } - -next: if (!this || this->end == root->end) - break; - - if (this != old) - tmp.start = this->end + 1; - this = this->sibling; - } - return -EBUSY; -} - -/* - * Find empty slot in the resource tree given range and alignment. - */ -static int find_resource(struct resource *root, struct resource *new, - resource_size_t size, - struct resource_constraint *constraint) -{ - return __find_resource(root, NULL, new, size, constraint); -} - -/** - * reallocate_resource - allocate a slot in the resource tree given range & alignment. - * The resource will be relocated if the new size cannot be reallocated in the - * current location. - * - * @root: root resource descriptor - * @old: resource descriptor desired by caller - * @newsize: new size of the resource descriptor - * @constraint: the size and alignment constraints to be met. - */ -static int reallocate_resource(struct resource *root, struct resource *old, - resource_size_t newsize, - struct resource_constraint *constraint) -{ - int err=0; - struct resource new = *old; - struct resource *conflict; - - write_lock(&resource_lock); - - if ((err = __find_resource(root, old, &new, newsize, constraint))) - goto out; - - if (resource_contains(&new, old)) { - old->start = new.start; - old->end = new.end; - goto out; - } - - if (old->child) { - err = -EBUSY; - goto out; - } - - if (resource_contains(old, &new)) { - old->start = new.start; - old->end = new.end; - } else { - __release_resource(old, true); - *old = new; - conflict = __request_resource(root, old); - BUG_ON(conflict); - } -out: - write_unlock(&resource_lock); - return err; -} - - -/** - * allocate_resource - allocate empty slot in the resource tree given range & alignment. - * The resource will be reallocated with a new size if it was already allocated - * @root: root resource descriptor - * @new: resource descriptor desired by caller - * @size: requested resource region size - * @min: minimum boundary to allocate - * @max: maximum boundary to allocate - * @align: alignment requested, in bytes - * @alignf: alignment function, optional, called if not NULL - * @alignf_data: arbitrary data to pass to the @alignf function - */ -int allocate_resource(struct resource *root, struct resource *new, - resource_size_t size, resource_size_t min, - resource_size_t max, resource_size_t align, - resource_size_t (*alignf)(void *, - const struct resource *, - resource_size_t, - resource_size_t), - void *alignf_data) -{ - int err; - struct resource_constraint constraint; - - if (!alignf) - alignf = simple_align_resource; - - constraint.min = min; - constraint.max = max; - constraint.align = align; - constraint.alignf = alignf; - constraint.alignf_data = alignf_data; - - if ( new->parent ) { - /* resource is already allocated, try reallocating with - the new constraints */ - return reallocate_resource(root, new, size, &constraint); - } - - write_lock(&resource_lock); - err = find_resource(root, new, size, &constraint); - if (err >= 0 && __request_resource(root, new)) - err = -EBUSY; - write_unlock(&resource_lock); - return err; -} - -EXPORT_SYMBOL(allocate_resource); - -/** - * lookup_resource - find an existing resource by a resource start address - * @root: root resource descriptor - * @start: resource start address - * - * Returns a pointer to the resource if found, NULL otherwise - */ -struct resource *lookup_resource(struct resource *root, resource_size_t start) -{ - struct resource *res; - - read_lock(&resource_lock); - for (res = root->child; res; res = res->sibling) { - if (res->start == start) - break; - } - read_unlock(&resource_lock); - - return res; -} - -/* - * Insert a resource into the resource tree. If successful, return NULL, - * otherwise return the conflicting resource (compare to __request_resource()) - */ -static struct resource * __insert_resource(struct resource *parent, struct resource *new) -{ - struct resource *first, *next; - - for (;; parent = first) { - first = __request_resource(parent, new); - if (!first) - return first; - - if (first == parent) - return first; - if (WARN_ON(first == new)) /* duplicated insertion */ - return first; - - if ((first->start > new->start) || (first->end < new->end)) - break; - if ((first->start == new->start) && (first->end == new->end)) - break; - } - - for (next = first; ; next = next->sibling) { - /* Partial overlap? Bad, and unfixable */ - if (next->start < new->start || next->end > new->end) - return next; - if (!next->sibling) - break; - if (next->sibling->start > new->end) - break; - } - - new->parent = parent; - new->sibling = next->sibling; - new->child = first; - - next->sibling = NULL; - for (next = first; next; next = next->sibling) - next->parent = new; - - if (parent->child == first) { - parent->child = new; - } else { - next = parent->child; - while (next->sibling != first) - next = next->sibling; - next->sibling = new; - } - return NULL; -} - -/** - * insert_resource_conflict - Inserts resource in the resource tree - * @parent: parent of the new resource - * @new: new resource to insert - * - * Returns 0 on success, conflict resource if the resource can't be inserted. - * - * This function is equivalent to request_resource_conflict when no conflict - * happens. If a conflict happens, and the conflicting resources - * entirely fit within the range of the new resource, then the new - * resource is inserted and the conflicting resources become children of - * the new resource. - * - * This function is intended for producers of resources, such as FW modules - * and bus drivers. - */ -struct resource *insert_resource_conflict(struct resource *parent, struct resource *new) -{ - struct resource *conflict; - - write_lock(&resource_lock); - conflict = __insert_resource(parent, new); - write_unlock(&resource_lock); - return conflict; -} - -/** - * insert_resource - Inserts a resource in the resource tree - * @parent: parent of the new resource - * @new: new resource to insert - * - * Returns 0 on success, -EBUSY if the resource can't be inserted. - * - * This function is intended for producers of resources, such as FW modules - * and bus drivers. - */ -int insert_resource(struct resource *parent, struct resource *new) -{ - struct resource *conflict; - - conflict = insert_resource_conflict(parent, new); - return conflict ? -EBUSY : 0; -} -EXPORT_SYMBOL_GPL(insert_resource); - -/** - * insert_resource_expand_to_fit - Insert a resource into the resource tree - * @root: root resource descriptor - * @new: new resource to insert - * - * Insert a resource into the resource tree, possibly expanding it in order - * to make it encompass any conflicting resources. - */ -void insert_resource_expand_to_fit(struct resource *root, struct resource *new) -{ - if (new->parent) - return; - - write_lock(&resource_lock); - for (;;) { - struct resource *conflict; - - conflict = __insert_resource(root, new); - if (!conflict) - break; - if (conflict == root) - break; - - /* Ok, expand resource to cover the conflict, then try again .. */ - if (conflict->start < new->start) - new->start = conflict->start; - if (conflict->end > new->end) - new->end = conflict->end; - - printk("Expanded resource %s due to conflict with %s\n", new->name, conflict->name); - } - write_unlock(&resource_lock); -} - -/** - * remove_resource - Remove a resource in the resource tree - * @old: resource to remove - * - * Returns 0 on success, -EINVAL if the resource is not valid. - * - * This function removes a resource previously inserted by insert_resource() - * or insert_resource_conflict(), and moves the children (if any) up to - * where they were before. insert_resource() and insert_resource_conflict() - * insert a new resource, and move any conflicting resources down to the - * children of the new resource. - * - * insert_resource(), insert_resource_conflict() and remove_resource() are - * intended for producers of resources, such as FW modules and bus drivers. - */ -int remove_resource(struct resource *old) -{ - int retval; - - write_lock(&resource_lock); - retval = __release_resource(old, false); - write_unlock(&resource_lock); - return retval; -} -EXPORT_SYMBOL_GPL(remove_resource); - -static int __adjust_resource(struct resource *res, resource_size_t start, - resource_size_t size) -{ - struct resource *tmp, *parent = res->parent; - resource_size_t end = start + size - 1; - int result = -EBUSY; - - if (!parent) - goto skip; - - if ((start < parent->start) || (end > parent->end)) - goto out; - - if (res->sibling && (res->sibling->start <= end)) - goto out; - - tmp = parent->child; - if (tmp != res) { - while (tmp->sibling != res) - tmp = tmp->sibling; - if (start <= tmp->end) - goto out; - } - -skip: - for (tmp = res->child; tmp; tmp = tmp->sibling) - if ((tmp->start < start) || (tmp->end > end)) - goto out; - - res->start = start; - res->end = end; - result = 0; - - out: - return result; -} - -/** - * adjust_resource - modify a resource's start and size - * @res: resource to modify - * @start: new start value - * @size: new size - * - * Given an existing resource, change its start and size to match the - * arguments. Returns 0 on success, -EBUSY if it can't fit. - * Existing children of the resource are assumed to be immutable. - */ -int adjust_resource(struct resource *res, resource_size_t start, - resource_size_t size) -{ - int result; - - write_lock(&resource_lock); - result = __adjust_resource(res, start, size); - write_unlock(&resource_lock); - return result; -} -EXPORT_SYMBOL(adjust_resource); - -static void __init __reserve_region_with_split(struct resource *root, - resource_size_t start, resource_size_t end, - const char *name) -{ - struct resource *parent = root; - struct resource *conflict; - struct resource *res = alloc_resource(GFP_ATOMIC); - struct resource *next_res = NULL; - - if (!res) - return; - - res->name = name; - res->start = start; - res->end = end; - res->flags = IORESOURCE_BUSY; - res->desc = IORES_DESC_NONE; - - while (1) { - - conflict = __request_resource(parent, res); - if (!conflict) { - if (!next_res) - break; - res = next_res; - next_res = NULL; - continue; - } - - /* conflict covered whole area */ - if (conflict->start <= res->start && - conflict->end >= res->end) { - free_resource(res); - WARN_ON(next_res); - break; - } - - /* failed, split and try again */ - if (conflict->start > res->start) { - end = res->end; - res->end = conflict->start - 1; - if (conflict->end < end) { - next_res = alloc_resource(GFP_ATOMIC); - if (!next_res) { - free_resource(res); - break; - } - next_res->name = name; - next_res->start = conflict->end + 1; - next_res->end = end; - next_res->flags = IORESOURCE_BUSY; - next_res->desc = IORES_DESC_NONE; - } - } else { - res->start = conflict->end + 1; - } - } - -} - -void __init reserve_region_with_split(struct resource *root, - resource_size_t start, resource_size_t end, - const char *name) -{ - int abort = 0; - - write_lock(&resource_lock); - if (root->start > start || root->end < end) { - pr_err("requested range [0x%llx-0x%llx] not in root %pr\n", - (unsigned long long)start, (unsigned long long)end, - root); - if (start > root->end || end < root->start) - abort = 1; - else { - if (end > root->end) - end = root->end; - if (start < root->start) - start = root->start; - pr_err("fixing request to [0x%llx-0x%llx]\n", - (unsigned long long)start, - (unsigned long long)end); - } - dump_stack(); - } - if (!abort) - __reserve_region_with_split(root, start, end, name); - write_unlock(&resource_lock); -} - -/** - * resource_alignment - calculate resource's alignment - * @res: resource pointer - * - * Returns alignment on success, 0 (invalid alignment) on failure. - */ -resource_size_t resource_alignment(struct resource *res) -{ - switch (res->flags & (IORESOURCE_SIZEALIGN | IORESOURCE_STARTALIGN)) { - case IORESOURCE_SIZEALIGN: - return resource_size(res); - case IORESOURCE_STARTALIGN: - return res->start; - default: - return 0; - } -} - -/* - * This is compatibility stuff for IO resources. - * - * Note how this, unlike the above, knows about - * the IO flag meanings (busy etc). - * - * request_region creates a new busy region. - * - * release_region releases a matching busy region. - */ - -static DECLARE_WAIT_QUEUE_HEAD(muxed_resource_wait); - -/** - * __request_region - create a new busy resource region - * @parent: parent resource descriptor - * @start: resource start address - * @n: resource region size - * @name: reserving caller's ID string - * @flags: IO resource flags - */ -struct resource * __request_region(struct resource *parent, - resource_size_t start, resource_size_t n, - const char *name, int flags) -{ - DECLARE_WAITQUEUE(wait, current); - struct resource *res = alloc_resource(GFP_KERNEL); - - if (!res) - return NULL; - - res->name = name; - res->start = start; - res->end = start + n - 1; - - write_lock(&resource_lock); - - for (;;) { - struct resource *conflict; - - res->flags = resource_type(parent) | resource_ext_type(parent); - res->flags |= IORESOURCE_BUSY | flags; - res->desc = parent->desc; - - conflict = __request_resource(parent, res); - if (!conflict) - break; - if (conflict != parent) { - if (!(conflict->flags & IORESOURCE_BUSY)) { - parent = conflict; - continue; - } - } - if (conflict->flags & flags & IORESOURCE_MUXED) { - add_wait_queue(&muxed_resource_wait, &wait); - write_unlock(&resource_lock); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule(); - remove_wait_queue(&muxed_resource_wait, &wait); - write_lock(&resource_lock); - continue; - } - /* Uhhuh, that didn't work out.. */ - free_resource(res); - res = NULL; - break; - } - write_unlock(&resource_lock); - return res; -} -EXPORT_SYMBOL(__request_region); - -/** - * __release_region - release a previously reserved resource region - * @parent: parent resource descriptor - * @start: resource start address - * @n: resource region size - * - * The described resource region must match a currently busy region. - */ -void __release_region(struct resource *parent, resource_size_t start, - resource_size_t n) -{ - struct resource **p; - resource_size_t end; - - p = &parent->child; - end = start + n - 1; - - write_lock(&resource_lock); - - for (;;) { - struct resource *res = *p; - - if (!res) - break; - if (res->start <= start && res->end >= end) { - if (!(res->flags & IORESOURCE_BUSY)) { - p = &res->child; - continue; - } - if (res->start != start || res->end != end) - break; - *p = res->sibling; - write_unlock(&resource_lock); - if (res->flags & IORESOURCE_MUXED) - wake_up(&muxed_resource_wait); - free_resource(res); - return; - } - p = &res->sibling; - } - - write_unlock(&resource_lock); - - printk(KERN_WARNING "Trying to free nonexistent resource " - "<%016llx-%016llx>\n", (unsigned long long)start, - (unsigned long long)end); -} -EXPORT_SYMBOL(__release_region); - -#ifdef CONFIG_MEMORY_HOTREMOVE -/** - * release_mem_region_adjustable - release a previously reserved memory region - * @parent: parent resource descriptor - * @start: resource start address - * @size: resource region size - * - * This interface is intended for memory hot-delete. The requested region - * is released from a currently busy memory resource. The requested region - * must either match exactly or fit into a single busy resource entry. In - * the latter case, the remaining resource is adjusted accordingly. - * Existing children of the busy memory resource must be immutable in the - * request. - * - * Note: - * - Additional release conditions, such as overlapping region, can be - * supported after they are confirmed as valid cases. - * - When a busy memory resource gets split into two entries, the code - * assumes that all children remain in the lower address entry for - * simplicity. Enhance this logic when necessary. - */ -int release_mem_region_adjustable(struct resource *parent, - resource_size_t start, resource_size_t size) -{ - struct resource **p; - struct resource *res; - struct resource *new_res; - resource_size_t end; - int ret = -EINVAL; - - end = start + size - 1; - if ((start < parent->start) || (end > parent->end)) - return ret; - - /* The alloc_resource() result gets checked later */ - new_res = alloc_resource(GFP_KERNEL); - - p = &parent->child; - write_lock(&resource_lock); - - while ((res = *p)) { - if (res->start >= end) - break; - - /* look for the next resource if it does not fit into */ - if (res->start > start || res->end < end) { - p = &res->sibling; - continue; - } - - if (!(res->flags & IORESOURCE_MEM)) - break; - - if (!(res->flags & IORESOURCE_BUSY)) { - p = &res->child; - continue; - } - - /* found the target resource; let's adjust accordingly */ - if (res->start == start && res->end == end) { - /* free the whole entry */ - *p = res->sibling; - free_resource(res); - ret = 0; - } else if (res->start == start && res->end != end) { - /* adjust the start */ - ret = __adjust_resource(res, end + 1, - res->end - end); - } else if (res->start != start && res->end == end) { - /* adjust the end */ - ret = __adjust_resource(res, res->start, - start - res->start); - } else { - /* split into two entries */ - if (!new_res) { - ret = -ENOMEM; - break; - } - new_res->name = res->name; - new_res->start = end + 1; - new_res->end = res->end; - new_res->flags = res->flags; - new_res->desc = res->desc; - new_res->parent = res->parent; - new_res->sibling = res->sibling; - new_res->child = NULL; - - ret = __adjust_resource(res, res->start, - start - res->start); - if (ret) - break; - res->sibling = new_res; - new_res = NULL; - } - - break; - } - - write_unlock(&resource_lock); - free_resource(new_res); - return ret; -} -#endif /* CONFIG_MEMORY_HOTREMOVE */ - -/* - * Managed region resource - */ -static void devm_resource_release(struct device *dev, void *ptr) -{ - struct resource **r = ptr; - - release_resource(*r); -} - -/** - * devm_request_resource() - request and reserve an I/O or memory resource - * @dev: device for which to request the resource - * @root: root of the resource tree from which to request the resource - * @new: descriptor of the resource to request - * - * This is a device-managed version of request_resource(). There is usually - * no need to release resources requested by this function explicitly since - * that will be taken care of when the device is unbound from its driver. - * If for some reason the resource needs to be released explicitly, because - * of ordering issues for example, drivers must call devm_release_resource() - * rather than the regular release_resource(). - * - * When a conflict is detected between any existing resources and the newly - * requested resource, an error message will be printed. - * - * Returns 0 on success or a negative error code on failure. - */ -int devm_request_resource(struct device *dev, struct resource *root, - struct resource *new) -{ - struct resource *conflict, **ptr; - - ptr = devres_alloc(devm_resource_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return -ENOMEM; - - *ptr = new; - - conflict = request_resource_conflict(root, new); - if (conflict) { - dev_err(dev, "resource collision: %pR conflicts with %s %pR\n", - new, conflict->name, conflict); - devres_free(ptr); - return -EBUSY; - } - - devres_add(dev, ptr); - return 0; -} -EXPORT_SYMBOL(devm_request_resource); - -static int devm_resource_match(struct device *dev, void *res, void *data) -{ - struct resource **ptr = res; - - return *ptr == data; -} - -/** - * devm_release_resource() - release a previously requested resource - * @dev: device for which to release the resource - * @new: descriptor of the resource to release - * - * Releases a resource previously requested using devm_request_resource(). - */ -void devm_release_resource(struct device *dev, struct resource *new) -{ - WARN_ON(devres_release(dev, devm_resource_release, devm_resource_match, - new)); -} -EXPORT_SYMBOL(devm_release_resource); - -struct region_devres { - struct resource *parent; - resource_size_t start; - resource_size_t n; -}; - -static void devm_region_release(struct device *dev, void *res) -{ - struct region_devres *this = res; - - __release_region(this->parent, this->start, this->n); -} - -static int devm_region_match(struct device *dev, void *res, void *match_data) -{ - struct region_devres *this = res, *match = match_data; - - return this->parent == match->parent && - this->start == match->start && this->n == match->n; -} - -struct resource * __devm_request_region(struct device *dev, - struct resource *parent, resource_size_t start, - resource_size_t n, const char *name) -{ - struct region_devres *dr = NULL; - struct resource *res; - - dr = devres_alloc(devm_region_release, sizeof(struct region_devres), - GFP_KERNEL); - if (!dr) - return NULL; - - dr->parent = parent; - dr->start = start; - dr->n = n; - - res = __request_region(parent, start, n, name, 0); - if (res) - devres_add(dev, dr); - else - devres_free(dr); - - return res; -} -EXPORT_SYMBOL(__devm_request_region); - -void __devm_release_region(struct device *dev, struct resource *parent, - resource_size_t start, resource_size_t n) -{ - struct region_devres match_data = { parent, start, n }; - - __release_region(parent, start, n); - WARN_ON(devres_destroy(dev, devm_region_release, devm_region_match, - &match_data)); -} -EXPORT_SYMBOL(__devm_release_region); - -/* - * Called from init/main.c to reserve IO ports. - */ -#define MAXRESERVE 4 -static int __init reserve_setup(char *str) -{ - static int reserved; - static struct resource reserve[MAXRESERVE]; - - for (;;) { - unsigned int io_start, io_num; - int x = reserved; - - if (get_option (&str, &io_start) != 2) - break; - if (get_option (&str, &io_num) == 0) - break; - if (x < MAXRESERVE) { - struct resource *res = reserve + x; - res->name = "reserved"; - res->start = io_start; - res->end = io_start + io_num - 1; - res->flags = IORESOURCE_BUSY; - res->desc = IORES_DESC_NONE; - res->child = NULL; - if (request_resource(res->start >= 0x10000 ? &iomem_resource : &ioport_resource, res) == 0) - reserved = x+1; - } - } - return 1; -} - -__setup("reserve=", reserve_setup); - -/* - * Check if the requested addr and size spans more than any slot in the - * iomem resource tree. - */ -int iomem_map_sanity_check(resource_size_t addr, unsigned long size) -{ - struct resource *p = &iomem_resource; - int err = 0; - loff_t l; - - read_lock(&resource_lock); - for (p = p->child; p ; p = r_next(NULL, p, &l)) { - /* - * We can probably skip the resources without - * IORESOURCE_IO attribute? - */ - if (p->start >= addr + size) - continue; - if (p->end < addr) - continue; - if (PFN_DOWN(p->start) <= PFN_DOWN(addr) && - PFN_DOWN(p->end) >= PFN_DOWN(addr + size - 1)) - continue; - /* - * if a resource is "BUSY", it's not a hardware resource - * but a driver mapping of such a resource; we don't want - * to warn for those; some drivers legitimately map only - * partial hardware resources. (example: vesafb) - */ - if (p->flags & IORESOURCE_BUSY) - continue; - - printk(KERN_WARNING "resource sanity check: requesting [mem %#010llx-%#010llx], which spans more than %s %pR\n", - (unsigned long long)addr, - (unsigned long long)(addr + size - 1), - p->name, p); - err = -1; - break; - } - read_unlock(&resource_lock); - - return err; -} - -#ifdef CONFIG_STRICT_DEVMEM -static int strict_iomem_checks = 1; -#else -static int strict_iomem_checks; -#endif - -/* - * check if an address is reserved in the iomem resource tree - * returns 1 if reserved, 0 if not reserved. - */ -int iomem_is_exclusive(u64 addr) -{ - struct resource *p = &iomem_resource; - int err = 0; - loff_t l; - int size = PAGE_SIZE; - - if (!strict_iomem_checks) - return 0; - - addr = addr & PAGE_MASK; - - read_lock(&resource_lock); - for (p = p->child; p ; p = r_next(NULL, p, &l)) { - /* - * We can probably skip the resources without - * IORESOURCE_IO attribute? - */ - if (p->start >= addr + size) - break; - if (p->end < addr) - continue; - /* - * A resource is exclusive if IORESOURCE_EXCLUSIVE is set - * or CONFIG_IO_STRICT_DEVMEM is enabled and the - * resource is busy. - */ - if ((p->flags & IORESOURCE_BUSY) == 0) - continue; - if (IS_ENABLED(CONFIG_IO_STRICT_DEVMEM) - || p->flags & IORESOURCE_EXCLUSIVE) { - err = 1; - break; - } - } - read_unlock(&resource_lock); - - return err; -} - -struct resource_entry *resource_list_create_entry(struct resource *res, - size_t extra_size) -{ - struct resource_entry *entry; - - entry = kzalloc(sizeof(*entry) + extra_size, GFP_KERNEL); - if (entry) { - INIT_LIST_HEAD(&entry->node); - entry->res = res ? res : &entry->__res; - } - - return entry; -} -EXPORT_SYMBOL(resource_list_create_entry); - -void resource_list_free(struct list_head *head) -{ - struct resource_entry *entry, *tmp; - - list_for_each_entry_safe(entry, tmp, head, node) - resource_list_destroy_entry(entry); -} -EXPORT_SYMBOL(resource_list_free); - -static int __init strict_iomem(char *str) -{ - if (strstr(str, "relaxed")) - strict_iomem_checks = 0; - if (strstr(str, "strict")) - strict_iomem_checks = 1; - return 1; -} - -__setup("iomem=", strict_iomem); diff --git a/src/linux/kernel/sched/Makefile b/src/linux/kernel/sched/Makefile deleted file mode 100644 index 5e59b83..0000000 --- a/src/linux/kernel/sched/Makefile +++ /dev/null @@ -1,27 +0,0 @@ -ifdef CONFIG_FUNCTION_TRACER -CFLAGS_REMOVE_clock.o = $(CC_FLAGS_FTRACE) -endif - -# These files are disabled because they produce non-interesting flaky coverage -# that is not a function of syscall inputs. E.g. involuntary context switches. -KCOV_INSTRUMENT := n - -ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y) -# According to Alan Modra , the -fno-omit-frame-pointer is -# needed for x86 only. Why this used to be enabled for all architectures is beyond -# me. I suspect most platforms don't need this, but until we know that for sure -# I turn this off for IA-64 only. Andreas Schwab says it's also needed on m68k -# to get a correct value for the wait-channel (WCHAN in ps). --davidm -CFLAGS_core.o := $(PROFILING) -fno-omit-frame-pointer -endif - -obj-y += core.o loadavg.o clock.o cputime.o -obj-y += idle_task.o fair.o rt.o deadline.o stop_task.o -obj-y += wait.o swait.o completion.o idle.o -obj-$(CONFIG_SMP) += cpupri.o cpudeadline.o -obj-$(CONFIG_SCHED_AUTOGROUP) += auto_group.o -obj-$(CONFIG_SCHEDSTATS) += stats.o -obj-$(CONFIG_SCHED_DEBUG) += debug.o -obj-$(CONFIG_CGROUP_CPUACCT) += cpuacct.o -obj-$(CONFIG_CPU_FREQ) += cpufreq.o -obj-$(CONFIG_CPU_FREQ_GOV_SCHEDUTIL) += cpufreq_schedutil.o diff --git a/src/linux/kernel/sched/auto_group.h b/src/linux/kernel/sched/auto_group.h deleted file mode 100644 index 890c95f..0000000 --- a/src/linux/kernel/sched/auto_group.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifdef CONFIG_SCHED_AUTOGROUP - -#include -#include - -struct autogroup { - /* - * reference doesn't mean how many thread attach to this - * autogroup now. It just stands for the number of task - * could use this autogroup. - */ - struct kref kref; - struct task_group *tg; - struct rw_semaphore lock; - unsigned long id; - int nice; -}; - -extern void autogroup_init(struct task_struct *init_task); -extern void autogroup_free(struct task_group *tg); - -static inline bool task_group_is_autogroup(struct task_group *tg) -{ - return !!tg->autogroup; -} - -extern bool task_wants_autogroup(struct task_struct *p, struct task_group *tg); - -static inline struct task_group * -autogroup_task_group(struct task_struct *p, struct task_group *tg) -{ - int enabled = READ_ONCE(sysctl_sched_autogroup_enabled); - - if (enabled && task_wants_autogroup(p, tg)) - return p->signal->autogroup->tg; - - return tg; -} - -extern int autogroup_path(struct task_group *tg, char *buf, int buflen); - -#else /* !CONFIG_SCHED_AUTOGROUP */ - -static inline void autogroup_init(struct task_struct *init_task) { } -static inline void autogroup_free(struct task_group *tg) { } -static inline bool task_group_is_autogroup(struct task_group *tg) -{ - return 0; -} - -static inline struct task_group * -autogroup_task_group(struct task_struct *p, struct task_group *tg) -{ - return tg; -} - -#ifdef CONFIG_SCHED_DEBUG -static inline int autogroup_path(struct task_group *tg, char *buf, int buflen) -{ - return 0; -} -#endif - -#endif /* CONFIG_SCHED_AUTOGROUP */ diff --git a/src/linux/kernel/sched/clock.c b/src/linux/kernel/sched/clock.c deleted file mode 100644 index e85a725..0000000 --- a/src/linux/kernel/sched/clock.c +++ /dev/null @@ -1,394 +0,0 @@ -/* - * sched_clock for unstable cpu clocks - * - * Copyright (C) 2008 Red Hat, Inc., Peter Zijlstra - * - * Updates and enhancements: - * Copyright (C) 2008 Red Hat, Inc. Steven Rostedt - * - * Based on code by: - * Ingo Molnar - * Guillaume Chazarain - * - * - * What: - * - * cpu_clock(i) provides a fast (execution time) high resolution - * clock with bounded drift between CPUs. The value of cpu_clock(i) - * is monotonic for constant i. The timestamp returned is in nanoseconds. - * - * ######################### BIG FAT WARNING ########################## - * # when comparing cpu_clock(i) to cpu_clock(j) for i != j, time can # - * # go backwards !! # - * #################################################################### - * - * There is no strict promise about the base, although it tends to start - * at 0 on boot (but people really shouldn't rely on that). - * - * cpu_clock(i) -- can be used from any context, including NMI. - * local_clock() -- is cpu_clock() on the current cpu. - * - * sched_clock_cpu(i) - * - * How: - * - * The implementation either uses sched_clock() when - * !CONFIG_HAVE_UNSTABLE_SCHED_CLOCK, which means in that case the - * sched_clock() is assumed to provide these properties (mostly it means - * the architecture provides a globally synchronized highres time source). - * - * Otherwise it tries to create a semi stable clock from a mixture of other - * clocks, including: - * - * - GTOD (clock monotomic) - * - sched_clock() - * - explicit idle events - * - * We use GTOD as base and use sched_clock() deltas to improve resolution. The - * deltas are filtered to provide monotonicity and keeping it within an - * expected window. - * - * Furthermore, explicit sleep and wakeup hooks allow us to account for time - * that is otherwise invisible (TSC gets stopped). - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Scheduler clock - returns current time in nanosec units. - * This is default implementation. - * Architectures and sub-architectures can override this. - */ -unsigned long long __weak sched_clock(void) -{ - return (unsigned long long)(jiffies - INITIAL_JIFFIES) - * (NSEC_PER_SEC / HZ); -} -EXPORT_SYMBOL_GPL(sched_clock); - -__read_mostly int sched_clock_running; - -#ifdef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK -static struct static_key __sched_clock_stable = STATIC_KEY_INIT; -static int __sched_clock_stable_early; - -int sched_clock_stable(void) -{ - return static_key_false(&__sched_clock_stable); -} - -static void __set_sched_clock_stable(void) -{ - if (!sched_clock_stable()) - static_key_slow_inc(&__sched_clock_stable); - - tick_dep_clear(TICK_DEP_BIT_CLOCK_UNSTABLE); -} - -void set_sched_clock_stable(void) -{ - __sched_clock_stable_early = 1; - - smp_mb(); /* matches sched_clock_init() */ - - if (!sched_clock_running) - return; - - __set_sched_clock_stable(); -} - -static void __clear_sched_clock_stable(struct work_struct *work) -{ - /* XXX worry about clock continuity */ - if (sched_clock_stable()) - static_key_slow_dec(&__sched_clock_stable); - - tick_dep_set(TICK_DEP_BIT_CLOCK_UNSTABLE); -} - -static DECLARE_WORK(sched_clock_work, __clear_sched_clock_stable); - -void clear_sched_clock_stable(void) -{ - __sched_clock_stable_early = 0; - - smp_mb(); /* matches sched_clock_init() */ - - if (!sched_clock_running) - return; - - schedule_work(&sched_clock_work); -} - -struct sched_clock_data { - u64 tick_raw; - u64 tick_gtod; - u64 clock; -}; - -static DEFINE_PER_CPU_SHARED_ALIGNED(struct sched_clock_data, sched_clock_data); - -static inline struct sched_clock_data *this_scd(void) -{ - return this_cpu_ptr(&sched_clock_data); -} - -static inline struct sched_clock_data *cpu_sdc(int cpu) -{ - return &per_cpu(sched_clock_data, cpu); -} - -void sched_clock_init(void) -{ - u64 ktime_now = ktime_to_ns(ktime_get()); - int cpu; - - for_each_possible_cpu(cpu) { - struct sched_clock_data *scd = cpu_sdc(cpu); - - scd->tick_raw = 0; - scd->tick_gtod = ktime_now; - scd->clock = ktime_now; - } - - sched_clock_running = 1; - - /* - * Ensure that it is impossible to not do a static_key update. - * - * Either {set,clear}_sched_clock_stable() must see sched_clock_running - * and do the update, or we must see their __sched_clock_stable_early - * and do the update, or both. - */ - smp_mb(); /* matches {set,clear}_sched_clock_stable() */ - - if (__sched_clock_stable_early) - __set_sched_clock_stable(); - else - __clear_sched_clock_stable(NULL); -} - -/* - * min, max except they take wrapping into account - */ - -static inline u64 wrap_min(u64 x, u64 y) -{ - return (s64)(x - y) < 0 ? x : y; -} - -static inline u64 wrap_max(u64 x, u64 y) -{ - return (s64)(x - y) > 0 ? x : y; -} - -/* - * update the percpu scd from the raw @now value - * - * - filter out backward motion - * - use the GTOD tick value to create a window to filter crazy TSC values - */ -static u64 sched_clock_local(struct sched_clock_data *scd) -{ - u64 now, clock, old_clock, min_clock, max_clock; - s64 delta; - -again: - now = sched_clock(); - delta = now - scd->tick_raw; - if (unlikely(delta < 0)) - delta = 0; - - old_clock = scd->clock; - - /* - * scd->clock = clamp(scd->tick_gtod + delta, - * max(scd->tick_gtod, scd->clock), - * scd->tick_gtod + TICK_NSEC); - */ - - clock = scd->tick_gtod + delta; - min_clock = wrap_max(scd->tick_gtod, old_clock); - max_clock = wrap_max(old_clock, scd->tick_gtod + TICK_NSEC); - - clock = wrap_max(clock, min_clock); - clock = wrap_min(clock, max_clock); - - if (cmpxchg64(&scd->clock, old_clock, clock) != old_clock) - goto again; - - return clock; -} - -static u64 sched_clock_remote(struct sched_clock_data *scd) -{ - struct sched_clock_data *my_scd = this_scd(); - u64 this_clock, remote_clock; - u64 *ptr, old_val, val; - -#if BITS_PER_LONG != 64 -again: - /* - * Careful here: The local and the remote clock values need to - * be read out atomic as we need to compare the values and - * then update either the local or the remote side. So the - * cmpxchg64 below only protects one readout. - * - * We must reread via sched_clock_local() in the retry case on - * 32bit as an NMI could use sched_clock_local() via the - * tracer and hit between the readout of - * the low32bit and the high 32bit portion. - */ - this_clock = sched_clock_local(my_scd); - /* - * We must enforce atomic readout on 32bit, otherwise the - * update on the remote cpu can hit inbetween the readout of - * the low32bit and the high 32bit portion. - */ - remote_clock = cmpxchg64(&scd->clock, 0, 0); -#else - /* - * On 64bit the read of [my]scd->clock is atomic versus the - * update, so we can avoid the above 32bit dance. - */ - sched_clock_local(my_scd); -again: - this_clock = my_scd->clock; - remote_clock = scd->clock; -#endif - - /* - * Use the opportunity that we have both locks - * taken to couple the two clocks: we take the - * larger time as the latest time for both - * runqueues. (this creates monotonic movement) - */ - if (likely((s64)(remote_clock - this_clock) < 0)) { - ptr = &scd->clock; - old_val = remote_clock; - val = this_clock; - } else { - /* - * Should be rare, but possible: - */ - ptr = &my_scd->clock; - old_val = this_clock; - val = remote_clock; - } - - if (cmpxchg64(ptr, old_val, val) != old_val) - goto again; - - return val; -} - -/* - * Similar to cpu_clock(), but requires local IRQs to be disabled. - * - * See cpu_clock(). - */ -u64 sched_clock_cpu(int cpu) -{ - struct sched_clock_data *scd; - u64 clock; - - if (sched_clock_stable()) - return sched_clock(); - - if (unlikely(!sched_clock_running)) - return 0ull; - - preempt_disable_notrace(); - scd = cpu_sdc(cpu); - - if (cpu != smp_processor_id()) - clock = sched_clock_remote(scd); - else - clock = sched_clock_local(scd); - preempt_enable_notrace(); - - return clock; -} -EXPORT_SYMBOL_GPL(sched_clock_cpu); - -void sched_clock_tick(void) -{ - struct sched_clock_data *scd; - u64 now, now_gtod; - - if (sched_clock_stable()) - return; - - if (unlikely(!sched_clock_running)) - return; - - WARN_ON_ONCE(!irqs_disabled()); - - scd = this_scd(); - now_gtod = ktime_to_ns(ktime_get()); - now = sched_clock(); - - scd->tick_raw = now; - scd->tick_gtod = now_gtod; - sched_clock_local(scd); -} - -/* - * We are going deep-idle (irqs are disabled): - */ -void sched_clock_idle_sleep_event(void) -{ - sched_clock_cpu(smp_processor_id()); -} -EXPORT_SYMBOL_GPL(sched_clock_idle_sleep_event); - -/* - * We just idled delta nanoseconds (called with irqs disabled): - */ -void sched_clock_idle_wakeup_event(u64 delta_ns) -{ - if (timekeeping_suspended) - return; - - sched_clock_tick(); - touch_softlockup_watchdog_sched(); -} -EXPORT_SYMBOL_GPL(sched_clock_idle_wakeup_event); - -#else /* CONFIG_HAVE_UNSTABLE_SCHED_CLOCK */ - -void sched_clock_init(void) -{ - sched_clock_running = 1; -} - -u64 sched_clock_cpu(int cpu) -{ - if (unlikely(!sched_clock_running)) - return 0; - - return sched_clock(); -} -#endif /* CONFIG_HAVE_UNSTABLE_SCHED_CLOCK */ - -/* - * Running clock - returns the time that has elapsed while a guest has been - * running. - * On a guest this value should be local_clock minus the time the guest was - * suspended by the hypervisor (for any reason). - * On bare metal this function should return the same as local_clock. - * Architectures and sub-architectures can override this. - */ -u64 __weak running_clock(void) -{ - return local_clock(); -} diff --git a/src/linux/kernel/sched/completion.c b/src/linux/kernel/sched/completion.c deleted file mode 100644 index 8d0f35d..0000000 --- a/src/linux/kernel/sched/completion.c +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Generic wait-for-completion handler; - * - * It differs from semaphores in that their default case is the opposite, - * wait_for_completion default blocks whereas semaphore default non-block. The - * interface also makes it easy to 'complete' multiple waiting threads, - * something which isn't entirely natural for semaphores. - * - * But more importantly, the primitive documents the usage. Semaphores would - * typically be used for exclusion which gives rise to priority inversion. - * Waiting for completion is a typically sync point, but not an exclusion point. - */ - -#include -#include - -/** - * complete: - signals a single thread waiting on this completion - * @x: holds the state of this particular completion - * - * This will wake up a single thread waiting on this completion. Threads will be - * awakened in the same order in which they were queued. - * - * See also complete_all(), wait_for_completion() and related routines. - * - * It may be assumed that this function implies a write memory barrier before - * changing the task state if and only if any tasks are woken up. - */ -void complete(struct completion *x) -{ - unsigned long flags; - - spin_lock_irqsave(&x->wait.lock, flags); - x->done++; - __wake_up_locked(&x->wait, TASK_NORMAL, 1); - spin_unlock_irqrestore(&x->wait.lock, flags); -} -EXPORT_SYMBOL(complete); - -/** - * complete_all: - signals all threads waiting on this completion - * @x: holds the state of this particular completion - * - * This will wake up all threads waiting on this particular completion event. - * - * It may be assumed that this function implies a write memory barrier before - * changing the task state if and only if any tasks are woken up. - */ -void complete_all(struct completion *x) -{ - unsigned long flags; - - spin_lock_irqsave(&x->wait.lock, flags); - x->done += UINT_MAX/2; - __wake_up_locked(&x->wait, TASK_NORMAL, 0); - spin_unlock_irqrestore(&x->wait.lock, flags); -} -EXPORT_SYMBOL(complete_all); - -static inline long __sched -do_wait_for_common(struct completion *x, - long (*action)(long), long timeout, int state) -{ - if (!x->done) { - DECLARE_WAITQUEUE(wait, current); - - __add_wait_queue_tail_exclusive(&x->wait, &wait); - do { - if (signal_pending_state(state, current)) { - timeout = -ERESTARTSYS; - break; - } - __set_current_state(state); - spin_unlock_irq(&x->wait.lock); - timeout = action(timeout); - spin_lock_irq(&x->wait.lock); - } while (!x->done && timeout); - __remove_wait_queue(&x->wait, &wait); - if (!x->done) - return timeout; - } - x->done--; - return timeout ?: 1; -} - -static inline long __sched -__wait_for_common(struct completion *x, - long (*action)(long), long timeout, int state) -{ - might_sleep(); - - spin_lock_irq(&x->wait.lock); - timeout = do_wait_for_common(x, action, timeout, state); - spin_unlock_irq(&x->wait.lock); - return timeout; -} - -static long __sched -wait_for_common(struct completion *x, long timeout, int state) -{ - return __wait_for_common(x, schedule_timeout, timeout, state); -} - -static long __sched -wait_for_common_io(struct completion *x, long timeout, int state) -{ - return __wait_for_common(x, io_schedule_timeout, timeout, state); -} - -/** - * wait_for_completion: - waits for completion of a task - * @x: holds the state of this particular completion - * - * This waits to be signaled for completion of a specific task. It is NOT - * interruptible and there is no timeout. - * - * See also similar routines (i.e. wait_for_completion_timeout()) with timeout - * and interrupt capability. Also see complete(). - */ -void __sched wait_for_completion(struct completion *x) -{ - wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE); -} -EXPORT_SYMBOL(wait_for_completion); - -/** - * wait_for_completion_timeout: - waits for completion of a task (w/timeout) - * @x: holds the state of this particular completion - * @timeout: timeout value in jiffies - * - * This waits for either a completion of a specific task to be signaled or for a - * specified timeout to expire. The timeout is in jiffies. It is not - * interruptible. - * - * Return: 0 if timed out, and positive (at least 1, or number of jiffies left - * till timeout) if completed. - */ -unsigned long __sched -wait_for_completion_timeout(struct completion *x, unsigned long timeout) -{ - return wait_for_common(x, timeout, TASK_UNINTERRUPTIBLE); -} -EXPORT_SYMBOL(wait_for_completion_timeout); - -/** - * wait_for_completion_io: - waits for completion of a task - * @x: holds the state of this particular completion - * - * This waits to be signaled for completion of a specific task. It is NOT - * interruptible and there is no timeout. The caller is accounted as waiting - * for IO (which traditionally means blkio only). - */ -void __sched wait_for_completion_io(struct completion *x) -{ - wait_for_common_io(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE); -} -EXPORT_SYMBOL(wait_for_completion_io); - -/** - * wait_for_completion_io_timeout: - waits for completion of a task (w/timeout) - * @x: holds the state of this particular completion - * @timeout: timeout value in jiffies - * - * This waits for either a completion of a specific task to be signaled or for a - * specified timeout to expire. The timeout is in jiffies. It is not - * interruptible. The caller is accounted as waiting for IO (which traditionally - * means blkio only). - * - * Return: 0 if timed out, and positive (at least 1, or number of jiffies left - * till timeout) if completed. - */ -unsigned long __sched -wait_for_completion_io_timeout(struct completion *x, unsigned long timeout) -{ - return wait_for_common_io(x, timeout, TASK_UNINTERRUPTIBLE); -} -EXPORT_SYMBOL(wait_for_completion_io_timeout); - -/** - * wait_for_completion_interruptible: - waits for completion of a task (w/intr) - * @x: holds the state of this particular completion - * - * This waits for completion of a specific task to be signaled. It is - * interruptible. - * - * Return: -ERESTARTSYS if interrupted, 0 if completed. - */ -int __sched wait_for_completion_interruptible(struct completion *x) -{ - long t = wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_INTERRUPTIBLE); - if (t == -ERESTARTSYS) - return t; - return 0; -} -EXPORT_SYMBOL(wait_for_completion_interruptible); - -/** - * wait_for_completion_interruptible_timeout: - waits for completion (w/(to,intr)) - * @x: holds the state of this particular completion - * @timeout: timeout value in jiffies - * - * This waits for either a completion of a specific task to be signaled or for a - * specified timeout to expire. It is interruptible. The timeout is in jiffies. - * - * Return: -ERESTARTSYS if interrupted, 0 if timed out, positive (at least 1, - * or number of jiffies left till timeout) if completed. - */ -long __sched -wait_for_completion_interruptible_timeout(struct completion *x, - unsigned long timeout) -{ - return wait_for_common(x, timeout, TASK_INTERRUPTIBLE); -} -EXPORT_SYMBOL(wait_for_completion_interruptible_timeout); - -/** - * wait_for_completion_killable: - waits for completion of a task (killable) - * @x: holds the state of this particular completion - * - * This waits to be signaled for completion of a specific task. It can be - * interrupted by a kill signal. - * - * Return: -ERESTARTSYS if interrupted, 0 if completed. - */ -int __sched wait_for_completion_killable(struct completion *x) -{ - long t = wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_KILLABLE); - if (t == -ERESTARTSYS) - return t; - return 0; -} -EXPORT_SYMBOL(wait_for_completion_killable); - -/** - * wait_for_completion_killable_timeout: - waits for completion of a task (w/(to,killable)) - * @x: holds the state of this particular completion - * @timeout: timeout value in jiffies - * - * This waits for either a completion of a specific task to be - * signaled or for a specified timeout to expire. It can be - * interrupted by a kill signal. The timeout is in jiffies. - * - * Return: -ERESTARTSYS if interrupted, 0 if timed out, positive (at least 1, - * or number of jiffies left till timeout) if completed. - */ -long __sched -wait_for_completion_killable_timeout(struct completion *x, - unsigned long timeout) -{ - return wait_for_common(x, timeout, TASK_KILLABLE); -} -EXPORT_SYMBOL(wait_for_completion_killable_timeout); - -/** - * try_wait_for_completion - try to decrement a completion without blocking - * @x: completion structure - * - * Return: 0 if a decrement cannot be done without blocking - * 1 if a decrement succeeded. - * - * If a completion is being used as a counting completion, - * attempt to decrement the counter without blocking. This - * enables us to avoid waiting if the resource the completion - * is protecting is not available. - */ -bool try_wait_for_completion(struct completion *x) -{ - unsigned long flags; - int ret = 1; - - /* - * Since x->done will need to be locked only - * in the non-blocking case, we check x->done - * first without taking the lock so we can - * return early in the blocking case. - */ - if (!READ_ONCE(x->done)) - return 0; - - spin_lock_irqsave(&x->wait.lock, flags); - if (!x->done) - ret = 0; - else - x->done--; - spin_unlock_irqrestore(&x->wait.lock, flags); - return ret; -} -EXPORT_SYMBOL(try_wait_for_completion); - -/** - * completion_done - Test to see if a completion has any waiters - * @x: completion structure - * - * Return: 0 if there are waiters (wait_for_completion() in progress) - * 1 if there are no waiters. - * - */ -bool completion_done(struct completion *x) -{ - if (!READ_ONCE(x->done)) - return false; - - /* - * If ->done, we need to wait for complete() to release ->wait.lock - * otherwise we can end up freeing the completion before complete() - * is done referencing it. - * - * The RMB pairs with complete()'s RELEASE of ->wait.lock and orders - * the loads of ->done and ->wait.lock such that we cannot observe - * the lock before complete() acquires it while observing the ->done - * after it's acquired the lock. - */ - smp_rmb(); - spin_unlock_wait(&x->wait.lock); - return true; -} -EXPORT_SYMBOL(completion_done); diff --git a/src/linux/kernel/sched/core.c b/src/linux/kernel/sched/core.c deleted file mode 100644 index 154fd68..0000000 --- a/src/linux/kernel/sched/core.c +++ /dev/null @@ -1,8845 +0,0 @@ -/* - * kernel/sched/core.c - * - * Kernel scheduler and related syscalls - * - * Copyright (C) 1991-2002 Linus Torvalds - * - * 1996-12-23 Modified by Dave Grothe to fix bugs in semaphores and - * make semaphores SMP safe - * 1998-11-19 Implemented schedule_timeout() and related stuff - * by Andrea Arcangeli - * 2002-01-04 New ultra-scalable O(1) scheduler by Ingo Molnar: - * hybrid priority-list and round-robin design with - * an array-switch method of distributing timeslices - * and per-CPU runqueues. Cleanups and useful suggestions - * by Davide Libenzi, preemptible kernel bits by Robert Love. - * 2003-09-03 Interactivity tuning by Con Kolivas. - * 2004-04-02 Scheduler domains code by Nick Piggin - * 2007-04-15 Work begun on replacing all interactivity tuning with a - * fair scheduling design by Con Kolivas. - * 2007-05-05 Load balancing (smp-nice) and other improvements - * by Peter Williams - * 2007-05-06 Interactivity improvements to CFS by Mike Galbraith - * 2007-07-01 Group scheduling enhancements by Srivatsa Vaddagiri - * 2007-11-29 RT balancing improvements by Steven Rostedt, Gregory Haskins, - * Thomas Gleixner, Mike Kravetz - */ - -#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 -#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 -#ifdef CONFIG_PARAVIRT -#include -#endif - -#include "sched.h" -#include "../workqueue_internal.h" -#include "../smpboot.h" - -#define CREATE_TRACE_POINTS -#include - -DEFINE_MUTEX(sched_domains_mutex); -DEFINE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues); - -static void update_rq_clock_task(struct rq *rq, s64 delta); - -void update_rq_clock(struct rq *rq) -{ - s64 delta; - - lockdep_assert_held(&rq->lock); - - if (rq->clock_skip_update & RQCF_ACT_SKIP) - return; - - delta = sched_clock_cpu(cpu_of(rq)) - rq->clock; - if (delta < 0) - return; - rq->clock += delta; - update_rq_clock_task(rq, delta); -} - -/* - * Debugging: various feature bits - */ - -#define SCHED_FEAT(name, enabled) \ - (1UL << __SCHED_FEAT_##name) * enabled | - -const_debug unsigned int sysctl_sched_features = -#include "features.h" - 0; - -#undef SCHED_FEAT - -/* - * Number of tasks to iterate in a single balance run. - * Limited because this is done with IRQs disabled. - */ -const_debug unsigned int sysctl_sched_nr_migrate = 32; - -/* - * period over which we average the RT time consumption, measured - * in ms. - * - * default: 1s - */ -const_debug unsigned int sysctl_sched_time_avg = MSEC_PER_SEC; - -/* - * period over which we measure -rt task cpu usage in us. - * default: 1s - */ -unsigned int sysctl_sched_rt_period = 1000000; - -__read_mostly int scheduler_running; - -/* - * part of the period that we allow rt tasks to run in us. - * default: 0.95s - */ -int sysctl_sched_rt_runtime = 950000; - -/* cpus with isolated domains */ -cpumask_var_t cpu_isolated_map; - -/* - * this_rq_lock - lock this runqueue and disable interrupts. - */ -static struct rq *this_rq_lock(void) - __acquires(rq->lock) -{ - struct rq *rq; - - local_irq_disable(); - rq = this_rq(); - raw_spin_lock(&rq->lock); - - return rq; -} - -/* - * __task_rq_lock - lock the rq @p resides on. - */ -struct rq *__task_rq_lock(struct task_struct *p, struct rq_flags *rf) - __acquires(rq->lock) -{ - struct rq *rq; - - lockdep_assert_held(&p->pi_lock); - - for (;;) { - rq = task_rq(p); - raw_spin_lock(&rq->lock); - if (likely(rq == task_rq(p) && !task_on_rq_migrating(p))) { - rf->cookie = lockdep_pin_lock(&rq->lock); - return rq; - } - raw_spin_unlock(&rq->lock); - - while (unlikely(task_on_rq_migrating(p))) - cpu_relax(); - } -} - -/* - * task_rq_lock - lock p->pi_lock and lock the rq @p resides on. - */ -struct rq *task_rq_lock(struct task_struct *p, struct rq_flags *rf) - __acquires(p->pi_lock) - __acquires(rq->lock) -{ - struct rq *rq; - - for (;;) { - raw_spin_lock_irqsave(&p->pi_lock, rf->flags); - rq = task_rq(p); - raw_spin_lock(&rq->lock); - /* - * move_queued_task() task_rq_lock() - * - * ACQUIRE (rq->lock) - * [S] ->on_rq = MIGRATING [L] rq = task_rq() - * WMB (__set_task_cpu()) ACQUIRE (rq->lock); - * [S] ->cpu = new_cpu [L] task_rq() - * [L] ->on_rq - * RELEASE (rq->lock) - * - * If we observe the old cpu in task_rq_lock, the acquire of - * the old rq->lock will fully serialize against the stores. - * - * If we observe the new cpu in task_rq_lock, the acquire will - * pair with the WMB to ensure we must then also see migrating. - */ - if (likely(rq == task_rq(p) && !task_on_rq_migrating(p))) { - rf->cookie = lockdep_pin_lock(&rq->lock); - return rq; - } - raw_spin_unlock(&rq->lock); - raw_spin_unlock_irqrestore(&p->pi_lock, rf->flags); - - while (unlikely(task_on_rq_migrating(p))) - cpu_relax(); - } -} - -#ifdef CONFIG_SCHED_HRTICK -/* - * Use HR-timers to deliver accurate preemption points. - */ - -static void hrtick_clear(struct rq *rq) -{ - if (hrtimer_active(&rq->hrtick_timer)) - hrtimer_cancel(&rq->hrtick_timer); -} - -/* - * High-resolution timer tick. - * Runs from hardirq context with interrupts disabled. - */ -static enum hrtimer_restart hrtick(struct hrtimer *timer) -{ - struct rq *rq = container_of(timer, struct rq, hrtick_timer); - - WARN_ON_ONCE(cpu_of(rq) != smp_processor_id()); - - raw_spin_lock(&rq->lock); - update_rq_clock(rq); - rq->curr->sched_class->task_tick(rq, rq->curr, 1); - raw_spin_unlock(&rq->lock); - - return HRTIMER_NORESTART; -} - -#ifdef CONFIG_SMP - -static void __hrtick_restart(struct rq *rq) -{ - struct hrtimer *timer = &rq->hrtick_timer; - - hrtimer_start_expires(timer, HRTIMER_MODE_ABS_PINNED); -} - -/* - * called from hardirq (IPI) context - */ -static void __hrtick_start(void *arg) -{ - struct rq *rq = arg; - - raw_spin_lock(&rq->lock); - __hrtick_restart(rq); - rq->hrtick_csd_pending = 0; - raw_spin_unlock(&rq->lock); -} - -/* - * Called to set the hrtick timer state. - * - * called with rq->lock held and irqs disabled - */ -void hrtick_start(struct rq *rq, u64 delay) -{ - struct hrtimer *timer = &rq->hrtick_timer; - ktime_t time; - s64 delta; - - /* - * Don't schedule slices shorter than 10000ns, that just - * doesn't make sense and can cause timer DoS. - */ - delta = max_t(s64, delay, 10000LL); - time = ktime_add_ns(timer->base->get_time(), delta); - - hrtimer_set_expires(timer, time); - - if (rq == this_rq()) { - __hrtick_restart(rq); - } else if (!rq->hrtick_csd_pending) { - smp_call_function_single_async(cpu_of(rq), &rq->hrtick_csd); - rq->hrtick_csd_pending = 1; - } -} - -#else -/* - * Called to set the hrtick timer state. - * - * called with rq->lock held and irqs disabled - */ -void hrtick_start(struct rq *rq, u64 delay) -{ - /* - * Don't schedule slices shorter than 10000ns, that just - * doesn't make sense. Rely on vruntime for fairness. - */ - delay = max_t(u64, delay, 10000LL); - hrtimer_start(&rq->hrtick_timer, ns_to_ktime(delay), - HRTIMER_MODE_REL_PINNED); -} -#endif /* CONFIG_SMP */ - -static void init_rq_hrtick(struct rq *rq) -{ -#ifdef CONFIG_SMP - rq->hrtick_csd_pending = 0; - - rq->hrtick_csd.flags = 0; - rq->hrtick_csd.func = __hrtick_start; - rq->hrtick_csd.info = rq; -#endif - - hrtimer_init(&rq->hrtick_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - rq->hrtick_timer.function = hrtick; -} -#else /* CONFIG_SCHED_HRTICK */ -static inline void hrtick_clear(struct rq *rq) -{ -} - -static inline void init_rq_hrtick(struct rq *rq) -{ -} -#endif /* CONFIG_SCHED_HRTICK */ - -/* - * cmpxchg based fetch_or, macro so it works for different integer types - */ -#define fetch_or(ptr, mask) \ - ({ \ - typeof(ptr) _ptr = (ptr); \ - typeof(mask) _mask = (mask); \ - typeof(*_ptr) _old, _val = *_ptr; \ - \ - for (;;) { \ - _old = cmpxchg(_ptr, _val, _val | _mask); \ - if (_old == _val) \ - break; \ - _val = _old; \ - } \ - _old; \ -}) - -#if defined(CONFIG_SMP) && defined(TIF_POLLING_NRFLAG) -/* - * Atomically set TIF_NEED_RESCHED and test for TIF_POLLING_NRFLAG, - * this avoids any races wrt polling state changes and thereby avoids - * spurious IPIs. - */ -static bool set_nr_and_not_polling(struct task_struct *p) -{ - struct thread_info *ti = task_thread_info(p); - return !(fetch_or(&ti->flags, _TIF_NEED_RESCHED) & _TIF_POLLING_NRFLAG); -} - -/* - * Atomically set TIF_NEED_RESCHED if TIF_POLLING_NRFLAG is set. - * - * If this returns true, then the idle task promises to call - * sched_ttwu_pending() and reschedule soon. - */ -static bool set_nr_if_polling(struct task_struct *p) -{ - struct thread_info *ti = task_thread_info(p); - typeof(ti->flags) old, val = READ_ONCE(ti->flags); - - for (;;) { - if (!(val & _TIF_POLLING_NRFLAG)) - return false; - if (val & _TIF_NEED_RESCHED) - return true; - old = cmpxchg(&ti->flags, val, val | _TIF_NEED_RESCHED); - if (old == val) - break; - val = old; - } - return true; -} - -#else -static bool set_nr_and_not_polling(struct task_struct *p) -{ - set_tsk_need_resched(p); - return true; -} - -#ifdef CONFIG_SMP -static bool set_nr_if_polling(struct task_struct *p) -{ - return false; -} -#endif -#endif - -void wake_q_add(struct wake_q_head *head, struct task_struct *task) -{ - struct wake_q_node *node = &task->wake_q; - - /* - * Atomically grab the task, if ->wake_q is !nil already it means - * its already queued (either by us or someone else) and will get the - * wakeup due to that. - * - * This cmpxchg() implies a full barrier, which pairs with the write - * barrier implied by the wakeup in wake_up_q(). - */ - if (cmpxchg(&node->next, NULL, WAKE_Q_TAIL)) - return; - - get_task_struct(task); - - /* - * The head is context local, there can be no concurrency. - */ - *head->lastp = node; - head->lastp = &node->next; -} - -void wake_up_q(struct wake_q_head *head) -{ - struct wake_q_node *node = head->first; - - while (node != WAKE_Q_TAIL) { - struct task_struct *task; - - task = container_of(node, struct task_struct, wake_q); - BUG_ON(!task); - /* task can safely be re-inserted now */ - node = node->next; - task->wake_q.next = NULL; - - /* - * wake_up_process() implies a wmb() to pair with the queueing - * in wake_q_add() so as not to miss wakeups. - */ - wake_up_process(task); - put_task_struct(task); - } -} - -/* - * resched_curr - mark rq's current task 'to be rescheduled now'. - * - * On UP this means the setting of the need_resched flag, on SMP it - * might also involve a cross-CPU call to trigger the scheduler on - * the target CPU. - */ -void resched_curr(struct rq *rq) -{ - struct task_struct *curr = rq->curr; - int cpu; - - lockdep_assert_held(&rq->lock); - - if (test_tsk_need_resched(curr)) - return; - - cpu = cpu_of(rq); - - if (cpu == smp_processor_id()) { - set_tsk_need_resched(curr); - set_preempt_need_resched(); - return; - } - - if (set_nr_and_not_polling(curr)) - smp_send_reschedule(cpu); - else - trace_sched_wake_idle_without_ipi(cpu); -} - -void resched_cpu(int cpu) -{ - struct rq *rq = cpu_rq(cpu); - unsigned long flags; - - if (!raw_spin_trylock_irqsave(&rq->lock, flags)) - return; - resched_curr(rq); - raw_spin_unlock_irqrestore(&rq->lock, flags); -} - -#ifdef CONFIG_SMP -#ifdef CONFIG_NO_HZ_COMMON -/* - * In the semi idle case, use the nearest busy cpu for migrating timers - * from an idle cpu. This is good for power-savings. - * - * We don't do similar optimization for completely idle system, as - * selecting an idle cpu will add more delays to the timers than intended - * (as that cpu's timer base may not be uptodate wrt jiffies etc). - */ -int get_nohz_timer_target(void) -{ - int i, cpu = smp_processor_id(); - struct sched_domain *sd; - - if (!idle_cpu(cpu) && is_housekeeping_cpu(cpu)) - return cpu; - - rcu_read_lock(); - for_each_domain(cpu, sd) { - for_each_cpu(i, sched_domain_span(sd)) { - if (cpu == i) - continue; - - if (!idle_cpu(i) && is_housekeeping_cpu(i)) { - cpu = i; - goto unlock; - } - } - } - - if (!is_housekeeping_cpu(cpu)) - cpu = housekeeping_any_cpu(); -unlock: - rcu_read_unlock(); - return cpu; -} -/* - * When add_timer_on() enqueues a timer into the timer wheel of an - * idle CPU then this timer might expire before the next timer event - * which is scheduled to wake up that CPU. In case of a completely - * idle system the next event might even be infinite time into the - * future. wake_up_idle_cpu() ensures that the CPU is woken up and - * leaves the inner idle loop so the newly added timer is taken into - * account when the CPU goes back to idle and evaluates the timer - * wheel for the next timer event. - */ -static void wake_up_idle_cpu(int cpu) -{ - struct rq *rq = cpu_rq(cpu); - - if (cpu == smp_processor_id()) - return; - - if (set_nr_and_not_polling(rq->idle)) - smp_send_reschedule(cpu); - else - trace_sched_wake_idle_without_ipi(cpu); -} - -static bool wake_up_full_nohz_cpu(int cpu) -{ - /* - * We just need the target to call irq_exit() and re-evaluate - * the next tick. The nohz full kick at least implies that. - * If needed we can still optimize that later with an - * empty IRQ. - */ - if (cpu_is_offline(cpu)) - return true; /* Don't try to wake offline CPUs. */ - if (tick_nohz_full_cpu(cpu)) { - if (cpu != smp_processor_id() || - tick_nohz_tick_stopped()) - tick_nohz_full_kick_cpu(cpu); - return true; - } - - return false; -} - -/* - * Wake up the specified CPU. If the CPU is going offline, it is the - * caller's responsibility to deal with the lost wakeup, for example, - * by hooking into the CPU_DEAD notifier like timers and hrtimers do. - */ -void wake_up_nohz_cpu(int cpu) -{ - if (!wake_up_full_nohz_cpu(cpu)) - wake_up_idle_cpu(cpu); -} - -static inline bool got_nohz_idle_kick(void) -{ - int cpu = smp_processor_id(); - - if (!test_bit(NOHZ_BALANCE_KICK, nohz_flags(cpu))) - return false; - - if (idle_cpu(cpu) && !need_resched()) - return true; - - /* - * We can't run Idle Load Balance on this CPU for this time so we - * cancel it and clear NOHZ_BALANCE_KICK - */ - clear_bit(NOHZ_BALANCE_KICK, nohz_flags(cpu)); - return false; -} - -#else /* CONFIG_NO_HZ_COMMON */ - -static inline bool got_nohz_idle_kick(void) -{ - return false; -} - -#endif /* CONFIG_NO_HZ_COMMON */ - -#ifdef CONFIG_NO_HZ_FULL -bool sched_can_stop_tick(struct rq *rq) -{ - int fifo_nr_running; - - /* Deadline tasks, even if single, need the tick */ - if (rq->dl.dl_nr_running) - return false; - - /* - * If there are more than one RR tasks, we need the tick to effect the - * actual RR behaviour. - */ - if (rq->rt.rr_nr_running) { - if (rq->rt.rr_nr_running == 1) - return true; - else - return false; - } - - /* - * If there's no RR tasks, but FIFO tasks, we can skip the tick, no - * forced preemption between FIFO tasks. - */ - fifo_nr_running = rq->rt.rt_nr_running - rq->rt.rr_nr_running; - if (fifo_nr_running) - return true; - - /* - * If there are no DL,RR/FIFO tasks, there must only be CFS tasks left; - * if there's more than one we need the tick for involuntary - * preemption. - */ - if (rq->nr_running > 1) - return false; - - return true; -} -#endif /* CONFIG_NO_HZ_FULL */ - -void sched_avg_update(struct rq *rq) -{ - s64 period = sched_avg_period(); - - while ((s64)(rq_clock(rq) - rq->age_stamp) > period) { - /* - * Inline assembly required to prevent the compiler - * optimising this loop into a divmod call. - * See __iter_div_u64_rem() for another example of this. - */ - asm("" : "+rm" (rq->age_stamp)); - rq->age_stamp += period; - rq->rt_avg /= 2; - } -} - -#endif /* CONFIG_SMP */ - -#if defined(CONFIG_RT_GROUP_SCHED) || (defined(CONFIG_FAIR_GROUP_SCHED) && \ - (defined(CONFIG_SMP) || defined(CONFIG_CFS_BANDWIDTH))) -/* - * Iterate task_group tree rooted at *from, calling @down when first entering a - * node and @up when leaving it for the final time. - * - * Caller must hold rcu_lock or sufficient equivalent. - */ -int walk_tg_tree_from(struct task_group *from, - tg_visitor down, tg_visitor up, void *data) -{ - struct task_group *parent, *child; - int ret; - - parent = from; - -down: - ret = (*down)(parent, data); - if (ret) - goto out; - list_for_each_entry_rcu(child, &parent->children, siblings) { - parent = child; - goto down; - -up: - continue; - } - ret = (*up)(parent, data); - if (ret || parent == from) - goto out; - - child = parent; - parent = parent->parent; - if (parent) - goto up; -out: - return ret; -} - -int tg_nop(struct task_group *tg, void *data) -{ - return 0; -} -#endif - -static void set_load_weight(struct task_struct *p) -{ - int prio = p->static_prio - MAX_RT_PRIO; - struct load_weight *load = &p->se.load; - - /* - * SCHED_IDLE tasks get minimal weight: - */ - if (idle_policy(p->policy)) { - load->weight = scale_load(WEIGHT_IDLEPRIO); - load->inv_weight = WMULT_IDLEPRIO; - return; - } - - load->weight = scale_load(sched_prio_to_weight[prio]); - load->inv_weight = sched_prio_to_wmult[prio]; -} - -static inline void enqueue_task(struct rq *rq, struct task_struct *p, int flags) -{ - update_rq_clock(rq); - if (!(flags & ENQUEUE_RESTORE)) - sched_info_queued(rq, p); - p->sched_class->enqueue_task(rq, p, flags); -} - -static inline void dequeue_task(struct rq *rq, struct task_struct *p, int flags) -{ - update_rq_clock(rq); - if (!(flags & DEQUEUE_SAVE)) - sched_info_dequeued(rq, p); - p->sched_class->dequeue_task(rq, p, flags); -} - -void activate_task(struct rq *rq, struct task_struct *p, int flags) -{ - if (task_contributes_to_load(p)) - rq->nr_uninterruptible--; - - enqueue_task(rq, p, flags); -} - -void deactivate_task(struct rq *rq, struct task_struct *p, int flags) -{ - if (task_contributes_to_load(p)) - rq->nr_uninterruptible++; - - dequeue_task(rq, p, flags); -} - -static void update_rq_clock_task(struct rq *rq, s64 delta) -{ -/* - * In theory, the compile should just see 0 here, and optimize out the call - * to sched_rt_avg_update. But I don't trust it... - */ -#if defined(CONFIG_IRQ_TIME_ACCOUNTING) || defined(CONFIG_PARAVIRT_TIME_ACCOUNTING) - s64 steal = 0, irq_delta = 0; -#endif -#ifdef CONFIG_IRQ_TIME_ACCOUNTING - irq_delta = irq_time_read(cpu_of(rq)) - rq->prev_irq_time; - - /* - * Since irq_time is only updated on {soft,}irq_exit, we might run into - * this case when a previous update_rq_clock() happened inside a - * {soft,}irq region. - * - * When this happens, we stop ->clock_task and only update the - * prev_irq_time stamp to account for the part that fit, so that a next - * update will consume the rest. This ensures ->clock_task is - * monotonic. - * - * It does however cause some slight miss-attribution of {soft,}irq - * time, a more accurate solution would be to update the irq_time using - * the current rq->clock timestamp, except that would require using - * atomic ops. - */ - if (irq_delta > delta) - irq_delta = delta; - - rq->prev_irq_time += irq_delta; - delta -= irq_delta; -#endif -#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING - if (static_key_false((¶virt_steal_rq_enabled))) { - steal = paravirt_steal_clock(cpu_of(rq)); - steal -= rq->prev_steal_time_rq; - - if (unlikely(steal > delta)) - steal = delta; - - rq->prev_steal_time_rq += steal; - delta -= steal; - } -#endif - - rq->clock_task += delta; - -#if defined(CONFIG_IRQ_TIME_ACCOUNTING) || defined(CONFIG_PARAVIRT_TIME_ACCOUNTING) - if ((irq_delta + steal) && sched_feat(NONTASK_CAPACITY)) - sched_rt_avg_update(rq, irq_delta + steal); -#endif -} - -void sched_set_stop_task(int cpu, struct task_struct *stop) -{ - struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; - struct task_struct *old_stop = cpu_rq(cpu)->stop; - - if (stop) { - /* - * Make it appear like a SCHED_FIFO task, its something - * userspace knows about and won't get confused about. - * - * Also, it will make PI more or less work without too - * much confusion -- but then, stop work should not - * rely on PI working anyway. - */ - sched_setscheduler_nocheck(stop, SCHED_FIFO, ¶m); - - stop->sched_class = &stop_sched_class; - } - - cpu_rq(cpu)->stop = stop; - - if (old_stop) { - /* - * Reset it back to a normal scheduling class so that - * it can die in pieces. - */ - old_stop->sched_class = &rt_sched_class; - } -} - -/* - * __normal_prio - return the priority that is based on the static prio - */ -static inline int __normal_prio(struct task_struct *p) -{ - return p->static_prio; -} - -/* - * Calculate the expected normal priority: i.e. priority - * without taking RT-inheritance into account. Might be - * boosted by interactivity modifiers. Changes upon fork, - * setprio syscalls, and whenever the interactivity - * estimator recalculates. - */ -static inline int normal_prio(struct task_struct *p) -{ - int prio; - - if (task_has_dl_policy(p)) - prio = MAX_DL_PRIO-1; - else if (task_has_rt_policy(p)) - prio = MAX_RT_PRIO-1 - p->rt_priority; - else - prio = __normal_prio(p); - return prio; -} - -/* - * Calculate the current priority, i.e. the priority - * taken into account by the scheduler. This value might - * be boosted by RT tasks, or might be boosted by - * interactivity modifiers. Will be RT if the task got - * RT-boosted. If not then it returns p->normal_prio. - */ -static int effective_prio(struct task_struct *p) -{ - p->normal_prio = normal_prio(p); - /* - * If we are RT tasks or we were boosted to RT priority, - * keep the priority unchanged. Otherwise, update priority - * to the normal priority: - */ - if (!rt_prio(p->prio)) - return p->normal_prio; - return p->prio; -} - -/** - * task_curr - is this task currently executing on a CPU? - * @p: the task in question. - * - * Return: 1 if the task is currently executing. 0 otherwise. - */ -inline int task_curr(const struct task_struct *p) -{ - return cpu_curr(task_cpu(p)) == p; -} - -/* - * switched_from, switched_to and prio_changed must _NOT_ drop rq->lock, - * use the balance_callback list if you want balancing. - * - * this means any call to check_class_changed() must be followed by a call to - * balance_callback(). - */ -static inline void check_class_changed(struct rq *rq, struct task_struct *p, - const struct sched_class *prev_class, - int oldprio) -{ - if (prev_class != p->sched_class) { - if (prev_class->switched_from) - prev_class->switched_from(rq, p); - - p->sched_class->switched_to(rq, p); - } else if (oldprio != p->prio || dl_task(p)) - p->sched_class->prio_changed(rq, p, oldprio); -} - -void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags) -{ - const struct sched_class *class; - - if (p->sched_class == rq->curr->sched_class) { - rq->curr->sched_class->check_preempt_curr(rq, p, flags); - } else { - for_each_class(class) { - if (class == rq->curr->sched_class) - break; - if (class == p->sched_class) { - resched_curr(rq); - break; - } - } - } - - /* - * A queue event has occurred, and we're going to schedule. In - * this case, we can save a useless back to back clock update. - */ - if (task_on_rq_queued(rq->curr) && test_tsk_need_resched(rq->curr)) - rq_clock_skip_update(rq, true); -} - -#ifdef CONFIG_SMP -/* - * This is how migration works: - * - * 1) we invoke migration_cpu_stop() on the target CPU using - * stop_one_cpu(). - * 2) stopper starts to run (implicitly forcing the migrated thread - * off the CPU) - * 3) it checks whether the migrated task is still in the wrong runqueue. - * 4) if it's in the wrong runqueue then the migration thread removes - * it and puts it into the right queue. - * 5) stopper completes and stop_one_cpu() returns and the migration - * is done. - */ - -/* - * move_queued_task - move a queued task to new rq. - * - * Returns (locked) new rq. Old rq's lock is released. - */ -static struct rq *move_queued_task(struct rq *rq, struct task_struct *p, int new_cpu) -{ - lockdep_assert_held(&rq->lock); - - p->on_rq = TASK_ON_RQ_MIGRATING; - dequeue_task(rq, p, 0); - set_task_cpu(p, new_cpu); - raw_spin_unlock(&rq->lock); - - rq = cpu_rq(new_cpu); - - raw_spin_lock(&rq->lock); - BUG_ON(task_cpu(p) != new_cpu); - enqueue_task(rq, p, 0); - p->on_rq = TASK_ON_RQ_QUEUED; - check_preempt_curr(rq, p, 0); - - return rq; -} - -struct migration_arg { - struct task_struct *task; - int dest_cpu; -}; - -/* - * Move (not current) task off this cpu, onto dest cpu. We're doing - * this because either it can't run here any more (set_cpus_allowed() - * away from this CPU, or CPU going down), or because we're - * attempting to rebalance this task on exec (sched_exec). - * - * So we race with normal scheduler movements, but that's OK, as long - * as the task is no longer on this CPU. - */ -static struct rq *__migrate_task(struct rq *rq, struct task_struct *p, int dest_cpu) -{ - if (unlikely(!cpu_active(dest_cpu))) - return rq; - - /* Affinity changed (again). */ - if (!cpumask_test_cpu(dest_cpu, tsk_cpus_allowed(p))) - return rq; - - rq = move_queued_task(rq, p, dest_cpu); - - return rq; -} - -/* - * migration_cpu_stop - this will be executed by a highprio stopper thread - * and performs thread migration by bumping thread off CPU then - * 'pushing' onto another runqueue. - */ -static int migration_cpu_stop(void *data) -{ - struct migration_arg *arg = data; - struct task_struct *p = arg->task; - struct rq *rq = this_rq(); - - /* - * The original target cpu might have gone down and we might - * be on another cpu but it doesn't matter. - */ - local_irq_disable(); - /* - * We need to explicitly wake pending tasks before running - * __migrate_task() such that we will not miss enforcing cpus_allowed - * during wakeups, see set_cpus_allowed_ptr()'s TASK_WAKING test. - */ - sched_ttwu_pending(); - - raw_spin_lock(&p->pi_lock); - raw_spin_lock(&rq->lock); - /* - * If task_rq(p) != rq, it cannot be migrated here, because we're - * holding rq->lock, if p->on_rq == 0 it cannot get enqueued because - * we're holding p->pi_lock. - */ - if (task_rq(p) == rq) { - if (task_on_rq_queued(p)) - rq = __migrate_task(rq, p, arg->dest_cpu); - else - p->wake_cpu = arg->dest_cpu; - } - raw_spin_unlock(&rq->lock); - raw_spin_unlock(&p->pi_lock); - - local_irq_enable(); - return 0; -} - -/* - * sched_class::set_cpus_allowed must do the below, but is not required to - * actually call this function. - */ -void set_cpus_allowed_common(struct task_struct *p, const struct cpumask *new_mask) -{ - cpumask_copy(&p->cpus_allowed, new_mask); - p->nr_cpus_allowed = cpumask_weight(new_mask); -} - -void do_set_cpus_allowed(struct task_struct *p, const struct cpumask *new_mask) -{ - struct rq *rq = task_rq(p); - bool queued, running; - - lockdep_assert_held(&p->pi_lock); - - queued = task_on_rq_queued(p); - running = task_current(rq, p); - - if (queued) { - /* - * Because __kthread_bind() calls this on blocked tasks without - * holding rq->lock. - */ - lockdep_assert_held(&rq->lock); - dequeue_task(rq, p, DEQUEUE_SAVE); - } - if (running) - put_prev_task(rq, p); - - p->sched_class->set_cpus_allowed(p, new_mask); - - if (queued) - enqueue_task(rq, p, ENQUEUE_RESTORE); - if (running) - set_curr_task(rq, p); -} - -/* - * Change a given task's CPU affinity. Migrate the thread to a - * proper CPU and schedule it away if the CPU it's executing on - * is removed from the allowed bitmask. - * - * NOTE: the caller must have a valid reference to the task, the - * task must not exit() & deallocate itself prematurely. The - * call is not atomic; no spinlocks may be held. - */ -static int __set_cpus_allowed_ptr(struct task_struct *p, - const struct cpumask *new_mask, bool check) -{ - const struct cpumask *cpu_valid_mask = cpu_active_mask; - unsigned int dest_cpu; - struct rq_flags rf; - struct rq *rq; - int ret = 0; - - rq = task_rq_lock(p, &rf); - - if (p->flags & PF_KTHREAD) { - /* - * Kernel threads are allowed on online && !active CPUs - */ - cpu_valid_mask = cpu_online_mask; - } - - /* - * Must re-check here, to close a race against __kthread_bind(), - * sched_setaffinity() is not guaranteed to observe the flag. - */ - if (check && (p->flags & PF_NO_SETAFFINITY)) { - ret = -EINVAL; - goto out; - } - - if (cpumask_equal(&p->cpus_allowed, new_mask)) - goto out; - - if (!cpumask_intersects(new_mask, cpu_valid_mask)) { - ret = -EINVAL; - goto out; - } - - do_set_cpus_allowed(p, new_mask); - - if (p->flags & PF_KTHREAD) { - /* - * For kernel threads that do indeed end up on online && - * !active we want to ensure they are strict per-cpu threads. - */ - WARN_ON(cpumask_intersects(new_mask, cpu_online_mask) && - !cpumask_intersects(new_mask, cpu_active_mask) && - p->nr_cpus_allowed != 1); - } - - /* Can the task run on the task's current CPU? If so, we're done */ - if (cpumask_test_cpu(task_cpu(p), new_mask)) - goto out; - - dest_cpu = cpumask_any_and(cpu_valid_mask, new_mask); - if (task_running(rq, p) || p->state == TASK_WAKING) { - struct migration_arg arg = { p, dest_cpu }; - /* Need help from migration thread: drop lock and wait. */ - task_rq_unlock(rq, p, &rf); - stop_one_cpu(cpu_of(rq), migration_cpu_stop, &arg); - tlb_migrate_finish(p->mm); - return 0; - } else if (task_on_rq_queued(p)) { - /* - * OK, since we're going to drop the lock immediately - * afterwards anyway. - */ - lockdep_unpin_lock(&rq->lock, rf.cookie); - rq = move_queued_task(rq, p, dest_cpu); - lockdep_repin_lock(&rq->lock, rf.cookie); - } -out: - task_rq_unlock(rq, p, &rf); - - return ret; -} - -int set_cpus_allowed_ptr(struct task_struct *p, const struct cpumask *new_mask) -{ - return __set_cpus_allowed_ptr(p, new_mask, false); -} -EXPORT_SYMBOL_GPL(set_cpus_allowed_ptr); - -void set_task_cpu(struct task_struct *p, unsigned int new_cpu) -{ -#ifdef CONFIG_SCHED_DEBUG - /* - * We should never call set_task_cpu() on a blocked task, - * ttwu() will sort out the placement. - */ - WARN_ON_ONCE(p->state != TASK_RUNNING && p->state != TASK_WAKING && - !p->on_rq); - - /* - * Migrating fair class task must have p->on_rq = TASK_ON_RQ_MIGRATING, - * because schedstat_wait_{start,end} rebase migrating task's wait_start - * time relying on p->on_rq. - */ - WARN_ON_ONCE(p->state == TASK_RUNNING && - p->sched_class == &fair_sched_class && - (p->on_rq && !task_on_rq_migrating(p))); - -#ifdef CONFIG_LOCKDEP - /* - * The caller should hold either p->pi_lock or rq->lock, when changing - * a task's CPU. ->pi_lock for waking tasks, rq->lock for runnable tasks. - * - * sched_move_task() holds both and thus holding either pins the cgroup, - * see task_group(). - * - * Furthermore, all task_rq users should acquire both locks, see - * task_rq_lock(). - */ - WARN_ON_ONCE(debug_locks && !(lockdep_is_held(&p->pi_lock) || - lockdep_is_held(&task_rq(p)->lock))); -#endif -#endif - - trace_sched_migrate_task(p, new_cpu); - - if (task_cpu(p) != new_cpu) { - if (p->sched_class->migrate_task_rq) - p->sched_class->migrate_task_rq(p); - p->se.nr_migrations++; - perf_event_task_migrate(p); - } - - __set_task_cpu(p, new_cpu); -} - -static void __migrate_swap_task(struct task_struct *p, int cpu) -{ - if (task_on_rq_queued(p)) { - struct rq *src_rq, *dst_rq; - - src_rq = task_rq(p); - dst_rq = cpu_rq(cpu); - - p->on_rq = TASK_ON_RQ_MIGRATING; - deactivate_task(src_rq, p, 0); - set_task_cpu(p, cpu); - activate_task(dst_rq, p, 0); - p->on_rq = TASK_ON_RQ_QUEUED; - check_preempt_curr(dst_rq, p, 0); - } else { - /* - * Task isn't running anymore; make it appear like we migrated - * it before it went to sleep. This means on wakeup we make the - * previous cpu our target instead of where it really is. - */ - p->wake_cpu = cpu; - } -} - -struct migration_swap_arg { - struct task_struct *src_task, *dst_task; - int src_cpu, dst_cpu; -}; - -static int migrate_swap_stop(void *data) -{ - struct migration_swap_arg *arg = data; - struct rq *src_rq, *dst_rq; - int ret = -EAGAIN; - - if (!cpu_active(arg->src_cpu) || !cpu_active(arg->dst_cpu)) - return -EAGAIN; - - src_rq = cpu_rq(arg->src_cpu); - dst_rq = cpu_rq(arg->dst_cpu); - - double_raw_lock(&arg->src_task->pi_lock, - &arg->dst_task->pi_lock); - double_rq_lock(src_rq, dst_rq); - - if (task_cpu(arg->dst_task) != arg->dst_cpu) - goto unlock; - - if (task_cpu(arg->src_task) != arg->src_cpu) - goto unlock; - - if (!cpumask_test_cpu(arg->dst_cpu, tsk_cpus_allowed(arg->src_task))) - goto unlock; - - if (!cpumask_test_cpu(arg->src_cpu, tsk_cpus_allowed(arg->dst_task))) - goto unlock; - - __migrate_swap_task(arg->src_task, arg->dst_cpu); - __migrate_swap_task(arg->dst_task, arg->src_cpu); - - ret = 0; - -unlock: - double_rq_unlock(src_rq, dst_rq); - raw_spin_unlock(&arg->dst_task->pi_lock); - raw_spin_unlock(&arg->src_task->pi_lock); - - return ret; -} - -/* - * Cross migrate two tasks - */ -int migrate_swap(struct task_struct *cur, struct task_struct *p) -{ - struct migration_swap_arg arg; - int ret = -EINVAL; - - arg = (struct migration_swap_arg){ - .src_task = cur, - .src_cpu = task_cpu(cur), - .dst_task = p, - .dst_cpu = task_cpu(p), - }; - - if (arg.src_cpu == arg.dst_cpu) - goto out; - - /* - * These three tests are all lockless; this is OK since all of them - * will be re-checked with proper locks held further down the line. - */ - if (!cpu_active(arg.src_cpu) || !cpu_active(arg.dst_cpu)) - goto out; - - if (!cpumask_test_cpu(arg.dst_cpu, tsk_cpus_allowed(arg.src_task))) - goto out; - - if (!cpumask_test_cpu(arg.src_cpu, tsk_cpus_allowed(arg.dst_task))) - goto out; - - trace_sched_swap_numa(cur, arg.src_cpu, p, arg.dst_cpu); - ret = stop_two_cpus(arg.dst_cpu, arg.src_cpu, migrate_swap_stop, &arg); - -out: - return ret; -} - -/* - * wait_task_inactive - wait for a thread to unschedule. - * - * If @match_state is nonzero, it's the @p->state value just checked and - * not expected to change. If it changes, i.e. @p might have woken up, - * then return zero. When we succeed in waiting for @p to be off its CPU, - * we return a positive number (its total switch count). If a second call - * a short while later returns the same number, the caller can be sure that - * @p has remained unscheduled the whole time. - * - * The caller must ensure that the task *will* unschedule sometime soon, - * else this function might spin for a *long* time. This function can't - * be called with interrupts off, or it may introduce deadlock with - * smp_call_function() if an IPI is sent by the same process we are - * waiting to become inactive. - */ -unsigned long wait_task_inactive(struct task_struct *p, long match_state) -{ - int running, queued; - struct rq_flags rf; - unsigned long ncsw; - struct rq *rq; - - for (;;) { - /* - * We do the initial early heuristics without holding - * any task-queue locks at all. We'll only try to get - * the runqueue lock when things look like they will - * work out! - */ - rq = task_rq(p); - - /* - * If the task is actively running on another CPU - * still, just relax and busy-wait without holding - * any locks. - * - * NOTE! Since we don't hold any locks, it's not - * even sure that "rq" stays as the right runqueue! - * But we don't care, since "task_running()" will - * return false if the runqueue has changed and p - * is actually now running somewhere else! - */ - while (task_running(rq, p)) { - if (match_state && unlikely(p->state != match_state)) - return 0; - cpu_relax(); - } - - /* - * Ok, time to look more closely! We need the rq - * lock now, to be *sure*. If we're wrong, we'll - * just go back and repeat. - */ - rq = task_rq_lock(p, &rf); - trace_sched_wait_task(p); - running = task_running(rq, p); - queued = task_on_rq_queued(p); - ncsw = 0; - if (!match_state || p->state == match_state) - ncsw = p->nvcsw | LONG_MIN; /* sets MSB */ - task_rq_unlock(rq, p, &rf); - - /* - * If it changed from the expected state, bail out now. - */ - if (unlikely(!ncsw)) - break; - - /* - * Was it really running after all now that we - * checked with the proper locks actually held? - * - * Oops. Go back and try again.. - */ - if (unlikely(running)) { - cpu_relax(); - continue; - } - - /* - * It's not enough that it's not actively running, - * it must be off the runqueue _entirely_, and not - * preempted! - * - * So if it was still runnable (but just not actively - * running right now), it's preempted, and we should - * yield - it could be a while. - */ - if (unlikely(queued)) { - ktime_t to = ktime_set(0, NSEC_PER_SEC/HZ); - - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_hrtimeout(&to, HRTIMER_MODE_REL); - continue; - } - - /* - * Ahh, all good. It wasn't running, and it wasn't - * runnable, which means that it will never become - * running in the future either. We're all done! - */ - break; - } - - return ncsw; -} - -/*** - * kick_process - kick a running thread to enter/exit the kernel - * @p: the to-be-kicked thread - * - * Cause a process which is running on another CPU to enter - * kernel-mode, without any delay. (to get signals handled.) - * - * NOTE: this function doesn't have to take the runqueue lock, - * because all it wants to ensure is that the remote task enters - * the kernel. If the IPI races and the task has been migrated - * to another CPU then no harm is done and the purpose has been - * achieved as well. - */ -void kick_process(struct task_struct *p) -{ - int cpu; - - preempt_disable(); - cpu = task_cpu(p); - if ((cpu != smp_processor_id()) && task_curr(p)) - smp_send_reschedule(cpu); - preempt_enable(); -} -EXPORT_SYMBOL_GPL(kick_process); - -/* - * ->cpus_allowed is protected by both rq->lock and p->pi_lock - * - * A few notes on cpu_active vs cpu_online: - * - * - cpu_active must be a subset of cpu_online - * - * - on cpu-up we allow per-cpu kthreads on the online && !active cpu, - * see __set_cpus_allowed_ptr(). At this point the newly online - * cpu isn't yet part of the sched domains, and balancing will not - * see it. - * - * - on cpu-down we clear cpu_active() to mask the sched domains and - * avoid the load balancer to place new tasks on the to be removed - * cpu. Existing tasks will remain running there and will be taken - * off. - * - * This means that fallback selection must not select !active CPUs. - * And can assume that any active CPU must be online. Conversely - * select_task_rq() below may allow selection of !active CPUs in order - * to satisfy the above rules. - */ -static int select_fallback_rq(int cpu, struct task_struct *p) -{ - int nid = cpu_to_node(cpu); - const struct cpumask *nodemask = NULL; - enum { cpuset, possible, fail } state = cpuset; - int dest_cpu; - - /* - * If the node that the cpu is on has been offlined, cpu_to_node() - * will return -1. There is no cpu on the node, and we should - * select the cpu on the other node. - */ - if (nid != -1) { - nodemask = cpumask_of_node(nid); - - /* Look for allowed, online CPU in same node. */ - for_each_cpu(dest_cpu, nodemask) { - if (!cpu_active(dest_cpu)) - continue; - if (cpumask_test_cpu(dest_cpu, tsk_cpus_allowed(p))) - return dest_cpu; - } - } - - for (;;) { - /* Any allowed, online CPU? */ - for_each_cpu(dest_cpu, tsk_cpus_allowed(p)) { - if (!(p->flags & PF_KTHREAD) && !cpu_active(dest_cpu)) - continue; - if (!cpu_online(dest_cpu)) - continue; - goto out; - } - - /* No more Mr. Nice Guy. */ - switch (state) { - case cpuset: - if (IS_ENABLED(CONFIG_CPUSETS)) { - cpuset_cpus_allowed_fallback(p); - state = possible; - break; - } - /* fall-through */ - case possible: - do_set_cpus_allowed(p, cpu_possible_mask); - state = fail; - break; - - case fail: - BUG(); - break; - } - } - -out: - if (state != cpuset) { - /* - * Don't tell them about moving exiting tasks or - * kernel threads (both mm NULL), since they never - * leave kernel. - */ - if (p->mm && printk_ratelimit()) { - printk_deferred("process %d (%s) no longer affine to cpu%d\n", - task_pid_nr(p), p->comm, cpu); - } - } - - return dest_cpu; -} - -/* - * The caller (fork, wakeup) owns p->pi_lock, ->cpus_allowed is stable. - */ -static inline -int select_task_rq(struct task_struct *p, int cpu, int sd_flags, int wake_flags) -{ - lockdep_assert_held(&p->pi_lock); - - if (tsk_nr_cpus_allowed(p) > 1) - cpu = p->sched_class->select_task_rq(p, cpu, sd_flags, wake_flags); - else - cpu = cpumask_any(tsk_cpus_allowed(p)); - - /* - * In order not to call set_task_cpu() on a blocking task we need - * to rely on ttwu() to place the task on a valid ->cpus_allowed - * cpu. - * - * Since this is common to all placement strategies, this lives here. - * - * [ this allows ->select_task() to simply return task_cpu(p) and - * not worry about this generic constraint ] - */ - if (unlikely(!cpumask_test_cpu(cpu, tsk_cpus_allowed(p)) || - !cpu_online(cpu))) - cpu = select_fallback_rq(task_cpu(p), p); - - return cpu; -} - -static void update_avg(u64 *avg, u64 sample) -{ - s64 diff = sample - *avg; - *avg += diff >> 3; -} - -#else - -static inline int __set_cpus_allowed_ptr(struct task_struct *p, - const struct cpumask *new_mask, bool check) -{ - return set_cpus_allowed_ptr(p, new_mask); -} - -#endif /* CONFIG_SMP */ - -static void -ttwu_stat(struct task_struct *p, int cpu, int wake_flags) -{ - struct rq *rq; - - if (!schedstat_enabled()) - return; - - rq = this_rq(); - -#ifdef CONFIG_SMP - if (cpu == rq->cpu) { - schedstat_inc(rq->ttwu_local); - schedstat_inc(p->se.statistics.nr_wakeups_local); - } else { - struct sched_domain *sd; - - schedstat_inc(p->se.statistics.nr_wakeups_remote); - rcu_read_lock(); - for_each_domain(rq->cpu, sd) { - if (cpumask_test_cpu(cpu, sched_domain_span(sd))) { - schedstat_inc(sd->ttwu_wake_remote); - break; - } - } - rcu_read_unlock(); - } - - if (wake_flags & WF_MIGRATED) - schedstat_inc(p->se.statistics.nr_wakeups_migrate); -#endif /* CONFIG_SMP */ - - schedstat_inc(rq->ttwu_count); - schedstat_inc(p->se.statistics.nr_wakeups); - - if (wake_flags & WF_SYNC) - schedstat_inc(p->se.statistics.nr_wakeups_sync); -} - -static inline void ttwu_activate(struct rq *rq, struct task_struct *p, int en_flags) -{ - activate_task(rq, p, en_flags); - p->on_rq = TASK_ON_RQ_QUEUED; - - /* if a worker is waking up, notify workqueue */ - if (p->flags & PF_WQ_WORKER) - wq_worker_waking_up(p, cpu_of(rq)); -} - -/* - * Mark the task runnable and perform wakeup-preemption. - */ -static void ttwu_do_wakeup(struct rq *rq, struct task_struct *p, int wake_flags, - struct pin_cookie cookie) -{ - check_preempt_curr(rq, p, wake_flags); - p->state = TASK_RUNNING; - trace_sched_wakeup(p); - -#ifdef CONFIG_SMP - if (p->sched_class->task_woken) { - /* - * Our task @p is fully woken up and running; so its safe to - * drop the rq->lock, hereafter rq is only used for statistics. - */ - lockdep_unpin_lock(&rq->lock, cookie); - p->sched_class->task_woken(rq, p); - lockdep_repin_lock(&rq->lock, cookie); - } - - if (rq->idle_stamp) { - u64 delta = rq_clock(rq) - rq->idle_stamp; - u64 max = 2*rq->max_idle_balance_cost; - - update_avg(&rq->avg_idle, delta); - - if (rq->avg_idle > max) - rq->avg_idle = max; - - rq->idle_stamp = 0; - } -#endif -} - -static void -ttwu_do_activate(struct rq *rq, struct task_struct *p, int wake_flags, - struct pin_cookie cookie) -{ - int en_flags = ENQUEUE_WAKEUP; - - lockdep_assert_held(&rq->lock); - -#ifdef CONFIG_SMP - if (p->sched_contributes_to_load) - rq->nr_uninterruptible--; - - if (wake_flags & WF_MIGRATED) - en_flags |= ENQUEUE_MIGRATED; -#endif - - ttwu_activate(rq, p, en_flags); - ttwu_do_wakeup(rq, p, wake_flags, cookie); -} - -/* - * Called in case the task @p isn't fully descheduled from its runqueue, - * in this case we must do a remote wakeup. Its a 'light' wakeup though, - * since all we need to do is flip p->state to TASK_RUNNING, since - * the task is still ->on_rq. - */ -static int ttwu_remote(struct task_struct *p, int wake_flags) -{ - struct rq_flags rf; - struct rq *rq; - int ret = 0; - - rq = __task_rq_lock(p, &rf); - if (task_on_rq_queued(p)) { - /* check_preempt_curr() may use rq clock */ - update_rq_clock(rq); - ttwu_do_wakeup(rq, p, wake_flags, rf.cookie); - ret = 1; - } - __task_rq_unlock(rq, &rf); - - return ret; -} - -#ifdef CONFIG_SMP -void sched_ttwu_pending(void) -{ - struct rq *rq = this_rq(); - struct llist_node *llist = llist_del_all(&rq->wake_list); - struct pin_cookie cookie; - struct task_struct *p; - unsigned long flags; - - if (!llist) - return; - - raw_spin_lock_irqsave(&rq->lock, flags); - cookie = lockdep_pin_lock(&rq->lock); - - while (llist) { - int wake_flags = 0; - - p = llist_entry(llist, struct task_struct, wake_entry); - llist = llist_next(llist); - - if (p->sched_remote_wakeup) - wake_flags = WF_MIGRATED; - - ttwu_do_activate(rq, p, wake_flags, cookie); - } - - lockdep_unpin_lock(&rq->lock, cookie); - raw_spin_unlock_irqrestore(&rq->lock, flags); -} - -void scheduler_ipi(void) -{ - /* - * Fold TIF_NEED_RESCHED into the preempt_count; anybody setting - * TIF_NEED_RESCHED remotely (for the first time) will also send - * this IPI. - */ - preempt_fold_need_resched(); - - if (llist_empty(&this_rq()->wake_list) && !got_nohz_idle_kick()) - return; - - /* - * Not all reschedule IPI handlers call irq_enter/irq_exit, since - * traditionally all their work was done from the interrupt return - * path. Now that we actually do some work, we need to make sure - * we do call them. - * - * Some archs already do call them, luckily irq_enter/exit nest - * properly. - * - * Arguably we should visit all archs and update all handlers, - * however a fair share of IPIs are still resched only so this would - * somewhat pessimize the simple resched case. - */ - irq_enter(); - sched_ttwu_pending(); - - /* - * Check if someone kicked us for doing the nohz idle load balance. - */ - if (unlikely(got_nohz_idle_kick())) { - this_rq()->idle_balance = 1; - raise_softirq_irqoff(SCHED_SOFTIRQ); - } - irq_exit(); -} - -static void ttwu_queue_remote(struct task_struct *p, int cpu, int wake_flags) -{ - struct rq *rq = cpu_rq(cpu); - - p->sched_remote_wakeup = !!(wake_flags & WF_MIGRATED); - - if (llist_add(&p->wake_entry, &cpu_rq(cpu)->wake_list)) { - if (!set_nr_if_polling(rq->idle)) - smp_send_reschedule(cpu); - else - trace_sched_wake_idle_without_ipi(cpu); - } -} - -void wake_up_if_idle(int cpu) -{ - struct rq *rq = cpu_rq(cpu); - unsigned long flags; - - rcu_read_lock(); - - if (!is_idle_task(rcu_dereference(rq->curr))) - goto out; - - if (set_nr_if_polling(rq->idle)) { - trace_sched_wake_idle_without_ipi(cpu); - } else { - raw_spin_lock_irqsave(&rq->lock, flags); - if (is_idle_task(rq->curr)) - smp_send_reschedule(cpu); - /* Else cpu is not in idle, do nothing here */ - raw_spin_unlock_irqrestore(&rq->lock, flags); - } - -out: - rcu_read_unlock(); -} - -bool cpus_share_cache(int this_cpu, int that_cpu) -{ - return per_cpu(sd_llc_id, this_cpu) == per_cpu(sd_llc_id, that_cpu); -} -#endif /* CONFIG_SMP */ - -static void ttwu_queue(struct task_struct *p, int cpu, int wake_flags) -{ - struct rq *rq = cpu_rq(cpu); - struct pin_cookie cookie; - -#if defined(CONFIG_SMP) - if (sched_feat(TTWU_QUEUE) && !cpus_share_cache(smp_processor_id(), cpu)) { - sched_clock_cpu(cpu); /* sync clocks x-cpu */ - ttwu_queue_remote(p, cpu, wake_flags); - return; - } -#endif - - raw_spin_lock(&rq->lock); - cookie = lockdep_pin_lock(&rq->lock); - ttwu_do_activate(rq, p, wake_flags, cookie); - lockdep_unpin_lock(&rq->lock, cookie); - raw_spin_unlock(&rq->lock); -} - -/* - * Notes on Program-Order guarantees on SMP systems. - * - * MIGRATION - * - * The basic program-order guarantee on SMP systems is that when a task [t] - * migrates, all its activity on its old cpu [c0] happens-before any subsequent - * execution on its new cpu [c1]. - * - * For migration (of runnable tasks) this is provided by the following means: - * - * A) UNLOCK of the rq(c0)->lock scheduling out task t - * B) migration for t is required to synchronize *both* rq(c0)->lock and - * rq(c1)->lock (if not at the same time, then in that order). - * C) LOCK of the rq(c1)->lock scheduling in task - * - * Transitivity guarantees that B happens after A and C after B. - * Note: we only require RCpc transitivity. - * Note: the cpu doing B need not be c0 or c1 - * - * Example: - * - * CPU0 CPU1 CPU2 - * - * LOCK rq(0)->lock - * sched-out X - * sched-in Y - * UNLOCK rq(0)->lock - * - * LOCK rq(0)->lock // orders against CPU0 - * dequeue X - * UNLOCK rq(0)->lock - * - * LOCK rq(1)->lock - * enqueue X - * UNLOCK rq(1)->lock - * - * LOCK rq(1)->lock // orders against CPU2 - * sched-out Z - * sched-in X - * UNLOCK rq(1)->lock - * - * - * BLOCKING -- aka. SLEEP + WAKEUP - * - * For blocking we (obviously) need to provide the same guarantee as for - * migration. However the means are completely different as there is no lock - * chain to provide order. Instead we do: - * - * 1) smp_store_release(X->on_cpu, 0) - * 2) smp_cond_load_acquire(!X->on_cpu) - * - * Example: - * - * CPU0 (schedule) CPU1 (try_to_wake_up) CPU2 (schedule) - * - * LOCK rq(0)->lock LOCK X->pi_lock - * dequeue X - * sched-out X - * smp_store_release(X->on_cpu, 0); - * - * smp_cond_load_acquire(&X->on_cpu, !VAL); - * X->state = WAKING - * set_task_cpu(X,2) - * - * LOCK rq(2)->lock - * enqueue X - * X->state = RUNNING - * UNLOCK rq(2)->lock - * - * LOCK rq(2)->lock // orders against CPU1 - * sched-out Z - * sched-in X - * UNLOCK rq(2)->lock - * - * UNLOCK X->pi_lock - * UNLOCK rq(0)->lock - * - * - * However; for wakeups there is a second guarantee we must provide, namely we - * must observe the state that lead to our wakeup. That is, not only must our - * task observe its own prior state, it must also observe the stores prior to - * its wakeup. - * - * This means that any means of doing remote wakeups must order the CPU doing - * the wakeup against the CPU the task is going to end up running on. This, - * however, is already required for the regular Program-Order guarantee above, - * since the waking CPU is the one issueing the ACQUIRE (smp_cond_load_acquire). - * - */ - -/** - * try_to_wake_up - wake up a thread - * @p: the thread to be awakened - * @state: the mask of task states that can be woken - * @wake_flags: wake modifier flags (WF_*) - * - * Put it on the run-queue if it's not already there. The "current" - * thread is always on the run-queue (except when the actual - * re-schedule is in progress), and as such you're allowed to do - * the simpler "current->state = TASK_RUNNING" to mark yourself - * runnable without the overhead of this. - * - * Return: %true if @p was woken up, %false if it was already running. - * or @state didn't match @p's state. - */ -static int -try_to_wake_up(struct task_struct *p, unsigned int state, int wake_flags) -{ - unsigned long flags; - int cpu, success = 0; - - /* - * If we are going to wake up a thread waiting for CONDITION we - * need to ensure that CONDITION=1 done by the caller can not be - * reordered with p->state check below. This pairs with mb() in - * set_current_state() the waiting thread does. - */ - smp_mb__before_spinlock(); - raw_spin_lock_irqsave(&p->pi_lock, flags); - if (!(p->state & state)) - goto out; - - trace_sched_waking(p); - - success = 1; /* we're going to change ->state */ - cpu = task_cpu(p); - - /* - * Ensure we load p->on_rq _after_ p->state, otherwise it would - * be possible to, falsely, observe p->on_rq == 0 and get stuck - * in smp_cond_load_acquire() below. - * - * sched_ttwu_pending() try_to_wake_up() - * [S] p->on_rq = 1; [L] P->state - * UNLOCK rq->lock -----. - * \ - * +--- RMB - * schedule() / - * LOCK rq->lock -----' - * UNLOCK rq->lock - * - * [task p] - * [S] p->state = UNINTERRUPTIBLE [L] p->on_rq - * - * Pairs with the UNLOCK+LOCK on rq->lock from the - * last wakeup of our task and the schedule that got our task - * current. - */ - smp_rmb(); - if (p->on_rq && ttwu_remote(p, wake_flags)) - goto stat; - -#ifdef CONFIG_SMP - /* - * Ensure we load p->on_cpu _after_ p->on_rq, otherwise it would be - * possible to, falsely, observe p->on_cpu == 0. - * - * One must be running (->on_cpu == 1) in order to remove oneself - * from the runqueue. - * - * [S] ->on_cpu = 1; [L] ->on_rq - * UNLOCK rq->lock - * RMB - * LOCK rq->lock - * [S] ->on_rq = 0; [L] ->on_cpu - * - * Pairs with the full barrier implied in the UNLOCK+LOCK on rq->lock - * from the consecutive calls to schedule(); the first switching to our - * task, the second putting it to sleep. - */ - smp_rmb(); - - /* - * If the owning (remote) cpu is still in the middle of schedule() with - * this task as prev, wait until its done referencing the task. - * - * Pairs with the smp_store_release() in finish_lock_switch(). - * - * This ensures that tasks getting woken will be fully ordered against - * their previous state and preserve Program Order. - */ - smp_cond_load_acquire(&p->on_cpu, !VAL); - - p->sched_contributes_to_load = !!task_contributes_to_load(p); - p->state = TASK_WAKING; - - cpu = select_task_rq(p, p->wake_cpu, SD_BALANCE_WAKE, wake_flags); - if (task_cpu(p) != cpu) { - wake_flags |= WF_MIGRATED; - set_task_cpu(p, cpu); - } -#endif /* CONFIG_SMP */ - - ttwu_queue(p, cpu, wake_flags); -stat: - ttwu_stat(p, cpu, wake_flags); -out: - raw_spin_unlock_irqrestore(&p->pi_lock, flags); - - return success; -} - -/** - * try_to_wake_up_local - try to wake up a local task with rq lock held - * @p: the thread to be awakened - * @cookie: context's cookie for pinning - * - * Put @p on the run-queue if it's not already there. The caller must - * ensure that this_rq() is locked, @p is bound to this_rq() and not - * the current task. - */ -static void try_to_wake_up_local(struct task_struct *p, struct pin_cookie cookie) -{ - struct rq *rq = task_rq(p); - - if (WARN_ON_ONCE(rq != this_rq()) || - WARN_ON_ONCE(p == current)) - return; - - lockdep_assert_held(&rq->lock); - - if (!raw_spin_trylock(&p->pi_lock)) { - /* - * This is OK, because current is on_cpu, which avoids it being - * picked for load-balance and preemption/IRQs are still - * disabled avoiding further scheduler activity on it and we've - * not yet picked a replacement task. - */ - lockdep_unpin_lock(&rq->lock, cookie); - raw_spin_unlock(&rq->lock); - raw_spin_lock(&p->pi_lock); - raw_spin_lock(&rq->lock); - lockdep_repin_lock(&rq->lock, cookie); - } - - if (!(p->state & TASK_NORMAL)) - goto out; - - trace_sched_waking(p); - - if (!task_on_rq_queued(p)) - ttwu_activate(rq, p, ENQUEUE_WAKEUP); - - ttwu_do_wakeup(rq, p, 0, cookie); - ttwu_stat(p, smp_processor_id(), 0); -out: - raw_spin_unlock(&p->pi_lock); -} - -/** - * wake_up_process - Wake up a specific process - * @p: The process to be woken up. - * - * Attempt to wake up the nominated process and move it to the set of runnable - * processes. - * - * Return: 1 if the process was woken up, 0 if it was already running. - * - * It may be assumed that this function implies a write memory barrier before - * changing the task state if and only if any tasks are woken up. - */ -int wake_up_process(struct task_struct *p) -{ - return try_to_wake_up(p, TASK_NORMAL, 0); -} -EXPORT_SYMBOL(wake_up_process); - -int wake_up_state(struct task_struct *p, unsigned int state) -{ - return try_to_wake_up(p, state, 0); -} - -/* - * This function clears the sched_dl_entity static params. - */ -void __dl_clear_params(struct task_struct *p) -{ - struct sched_dl_entity *dl_se = &p->dl; - - dl_se->dl_runtime = 0; - dl_se->dl_deadline = 0; - dl_se->dl_period = 0; - dl_se->flags = 0; - dl_se->dl_bw = 0; - - dl_se->dl_throttled = 0; - dl_se->dl_yielded = 0; -} - -/* - * Perform scheduler related setup for a newly forked process p. - * p is forked by current. - * - * __sched_fork() is basic setup used by init_idle() too: - */ -static void __sched_fork(unsigned long clone_flags, struct task_struct *p) -{ - p->on_rq = 0; - - p->se.on_rq = 0; - p->se.exec_start = 0; - p->se.sum_exec_runtime = 0; - p->se.prev_sum_exec_runtime = 0; - p->se.nr_migrations = 0; - p->se.vruntime = 0; - INIT_LIST_HEAD(&p->se.group_node); - -#ifdef CONFIG_FAIR_GROUP_SCHED - p->se.cfs_rq = NULL; -#endif - -#ifdef CONFIG_SCHEDSTATS - /* Even if schedstat is disabled, there should not be garbage */ - memset(&p->se.statistics, 0, sizeof(p->se.statistics)); -#endif - - RB_CLEAR_NODE(&p->dl.rb_node); - init_dl_task_timer(&p->dl); - __dl_clear_params(p); - - INIT_LIST_HEAD(&p->rt.run_list); - p->rt.timeout = 0; - p->rt.time_slice = sched_rr_timeslice; - p->rt.on_rq = 0; - p->rt.on_list = 0; - -#ifdef CONFIG_PREEMPT_NOTIFIERS - INIT_HLIST_HEAD(&p->preempt_notifiers); -#endif - -#ifdef CONFIG_NUMA_BALANCING - if (p->mm && atomic_read(&p->mm->mm_users) == 1) { - p->mm->numa_next_scan = jiffies + msecs_to_jiffies(sysctl_numa_balancing_scan_delay); - p->mm->numa_scan_seq = 0; - } - - if (clone_flags & CLONE_VM) - p->numa_preferred_nid = current->numa_preferred_nid; - else - p->numa_preferred_nid = -1; - - p->node_stamp = 0ULL; - p->numa_scan_seq = p->mm ? p->mm->numa_scan_seq : 0; - p->numa_scan_period = sysctl_numa_balancing_scan_delay; - p->numa_work.next = &p->numa_work; - p->numa_faults = NULL; - p->last_task_numa_placement = 0; - p->last_sum_exec_runtime = 0; - - p->numa_group = NULL; -#endif /* CONFIG_NUMA_BALANCING */ -} - -DEFINE_STATIC_KEY_FALSE(sched_numa_balancing); - -#ifdef CONFIG_NUMA_BALANCING - -void set_numabalancing_state(bool enabled) -{ - if (enabled) - static_branch_enable(&sched_numa_balancing); - else - static_branch_disable(&sched_numa_balancing); -} - -#ifdef CONFIG_PROC_SYSCTL -int sysctl_numa_balancing(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - struct ctl_table t; - int err; - int state = static_branch_likely(&sched_numa_balancing); - - if (write && !capable(CAP_SYS_ADMIN)) - return -EPERM; - - t = *table; - t.data = &state; - err = proc_dointvec_minmax(&t, write, buffer, lenp, ppos); - if (err < 0) - return err; - if (write) - set_numabalancing_state(state); - return err; -} -#endif -#endif - -#ifdef CONFIG_SCHEDSTATS - -DEFINE_STATIC_KEY_FALSE(sched_schedstats); -static bool __initdata __sched_schedstats = false; - -static void set_schedstats(bool enabled) -{ - if (enabled) - static_branch_enable(&sched_schedstats); - else - static_branch_disable(&sched_schedstats); -} - -void force_schedstat_enabled(void) -{ - if (!schedstat_enabled()) { - pr_info("kernel profiling enabled schedstats, disable via kernel.sched_schedstats.\n"); - static_branch_enable(&sched_schedstats); - } -} - -static int __init setup_schedstats(char *str) -{ - int ret = 0; - if (!str) - goto out; - - /* - * This code is called before jump labels have been set up, so we can't - * change the static branch directly just yet. Instead set a temporary - * variable so init_schedstats() can do it later. - */ - if (!strcmp(str, "enable")) { - __sched_schedstats = true; - ret = 1; - } else if (!strcmp(str, "disable")) { - __sched_schedstats = false; - ret = 1; - } -out: - if (!ret) - pr_warn("Unable to parse schedstats=\n"); - - return ret; -} -__setup("schedstats=", setup_schedstats); - -static void __init init_schedstats(void) -{ - set_schedstats(__sched_schedstats); -} - -#ifdef CONFIG_PROC_SYSCTL -int sysctl_schedstats(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - struct ctl_table t; - int err; - int state = static_branch_likely(&sched_schedstats); - - if (write && !capable(CAP_SYS_ADMIN)) - return -EPERM; - - t = *table; - t.data = &state; - err = proc_dointvec_minmax(&t, write, buffer, lenp, ppos); - if (err < 0) - return err; - if (write) - set_schedstats(state); - return err; -} -#endif /* CONFIG_PROC_SYSCTL */ -#else /* !CONFIG_SCHEDSTATS */ -static inline void init_schedstats(void) {} -#endif /* CONFIG_SCHEDSTATS */ - -/* - * fork()/clone()-time setup: - */ -int sched_fork(unsigned long clone_flags, struct task_struct *p) -{ - unsigned long flags; - int cpu = get_cpu(); - - __sched_fork(clone_flags, p); - /* - * We mark the process as NEW here. This guarantees that - * nobody will actually run it, and a signal or other external - * event cannot wake it up and insert it on the runqueue either. - */ - p->state = TASK_NEW; - - /* - * Make sure we do not leak PI boosting priority to the child. - */ - p->prio = current->normal_prio; - - /* - * Revert to default priority/policy on fork if requested. - */ - if (unlikely(p->sched_reset_on_fork)) { - if (task_has_dl_policy(p) || task_has_rt_policy(p)) { - p->policy = SCHED_NORMAL; - p->static_prio = NICE_TO_PRIO(0); - p->rt_priority = 0; - } else if (PRIO_TO_NICE(p->static_prio) < 0) - p->static_prio = NICE_TO_PRIO(0); - - p->prio = p->normal_prio = __normal_prio(p); - set_load_weight(p); - - /* - * We don't need the reset flag anymore after the fork. It has - * fulfilled its duty: - */ - p->sched_reset_on_fork = 0; - } - - if (dl_prio(p->prio)) { - put_cpu(); - return -EAGAIN; - } else if (rt_prio(p->prio)) { - p->sched_class = &rt_sched_class; - } else { - p->sched_class = &fair_sched_class; - } - - init_entity_runnable_average(&p->se); - - /* - * The child is not yet in the pid-hash so no cgroup attach races, - * and the cgroup is pinned to this child due to cgroup_fork() - * is ran before sched_fork(). - * - * Silence PROVE_RCU. - */ - raw_spin_lock_irqsave(&p->pi_lock, flags); - /* - * We're setting the cpu for the first time, we don't migrate, - * so use __set_task_cpu(). - */ - __set_task_cpu(p, cpu); - if (p->sched_class->task_fork) - p->sched_class->task_fork(p); - raw_spin_unlock_irqrestore(&p->pi_lock, flags); - -#ifdef CONFIG_SCHED_INFO - if (likely(sched_info_on())) - memset(&p->sched_info, 0, sizeof(p->sched_info)); -#endif -#if defined(CONFIG_SMP) - p->on_cpu = 0; -#endif - init_task_preempt_count(p); -#ifdef CONFIG_SMP - plist_node_init(&p->pushable_tasks, MAX_PRIO); - RB_CLEAR_NODE(&p->pushable_dl_tasks); -#endif - - put_cpu(); - return 0; -} - -unsigned long to_ratio(u64 period, u64 runtime) -{ - if (runtime == RUNTIME_INF) - return 1ULL << 20; - - /* - * Doing this here saves a lot of checks in all - * the calling paths, and returning zero seems - * safe for them anyway. - */ - if (period == 0) - return 0; - - return div64_u64(runtime << 20, period); -} - -#ifdef CONFIG_SMP -inline struct dl_bw *dl_bw_of(int i) -{ - RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held(), - "sched RCU must be held"); - return &cpu_rq(i)->rd->dl_bw; -} - -static inline int dl_bw_cpus(int i) -{ - struct root_domain *rd = cpu_rq(i)->rd; - int cpus = 0; - - RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held(), - "sched RCU must be held"); - for_each_cpu_and(i, rd->span, cpu_active_mask) - cpus++; - - return cpus; -} -#else -inline struct dl_bw *dl_bw_of(int i) -{ - return &cpu_rq(i)->dl.dl_bw; -} - -static inline int dl_bw_cpus(int i) -{ - return 1; -} -#endif - -/* - * We must be sure that accepting a new task (or allowing changing the - * parameters of an existing one) is consistent with the bandwidth - * constraints. If yes, this function also accordingly updates the currently - * allocated bandwidth to reflect the new situation. - * - * This function is called while holding p's rq->lock. - * - * XXX we should delay bw change until the task's 0-lag point, see - * __setparam_dl(). - */ -static int dl_overflow(struct task_struct *p, int policy, - const struct sched_attr *attr) -{ - - struct dl_bw *dl_b = dl_bw_of(task_cpu(p)); - u64 period = attr->sched_period ?: attr->sched_deadline; - u64 runtime = attr->sched_runtime; - u64 new_bw = dl_policy(policy) ? to_ratio(period, runtime) : 0; - int cpus, err = -1; - - /* !deadline task may carry old deadline bandwidth */ - if (new_bw == p->dl.dl_bw && task_has_dl_policy(p)) - return 0; - - /* - * Either if a task, enters, leave, or stays -deadline but changes - * its parameters, we may need to update accordingly the total - * allocated bandwidth of the container. - */ - raw_spin_lock(&dl_b->lock); - cpus = dl_bw_cpus(task_cpu(p)); - if (dl_policy(policy) && !task_has_dl_policy(p) && - !__dl_overflow(dl_b, cpus, 0, new_bw)) { - __dl_add(dl_b, new_bw); - err = 0; - } else if (dl_policy(policy) && task_has_dl_policy(p) && - !__dl_overflow(dl_b, cpus, p->dl.dl_bw, new_bw)) { - __dl_clear(dl_b, p->dl.dl_bw); - __dl_add(dl_b, new_bw); - err = 0; - } else if (!dl_policy(policy) && task_has_dl_policy(p)) { - __dl_clear(dl_b, p->dl.dl_bw); - err = 0; - } - raw_spin_unlock(&dl_b->lock); - - return err; -} - -extern void init_dl_bw(struct dl_bw *dl_b); - -/* - * wake_up_new_task - wake up a newly created task for the first time. - * - * This function will do some initial scheduler statistics housekeeping - * that must be done for every newly created context, then puts the task - * on the runqueue and wakes it. - */ -void wake_up_new_task(struct task_struct *p) -{ - struct rq_flags rf; - struct rq *rq; - - raw_spin_lock_irqsave(&p->pi_lock, rf.flags); - p->state = TASK_RUNNING; -#ifdef CONFIG_SMP - /* - * Fork balancing, do it here and not earlier because: - * - cpus_allowed can change in the fork path - * - any previously selected cpu might disappear through hotplug - * - * Use __set_task_cpu() to avoid calling sched_class::migrate_task_rq, - * as we're not fully set-up yet. - */ - __set_task_cpu(p, select_task_rq(p, task_cpu(p), SD_BALANCE_FORK, 0)); -#endif - rq = __task_rq_lock(p, &rf); - post_init_entity_util_avg(&p->se); - - activate_task(rq, p, 0); - p->on_rq = TASK_ON_RQ_QUEUED; - trace_sched_wakeup_new(p); - check_preempt_curr(rq, p, WF_FORK); -#ifdef CONFIG_SMP - if (p->sched_class->task_woken) { - /* - * Nothing relies on rq->lock after this, so its fine to - * drop it. - */ - lockdep_unpin_lock(&rq->lock, rf.cookie); - p->sched_class->task_woken(rq, p); - lockdep_repin_lock(&rq->lock, rf.cookie); - } -#endif - task_rq_unlock(rq, p, &rf); -} - -#ifdef CONFIG_PREEMPT_NOTIFIERS - -static struct static_key preempt_notifier_key = STATIC_KEY_INIT_FALSE; - -void preempt_notifier_inc(void) -{ - static_key_slow_inc(&preempt_notifier_key); -} -EXPORT_SYMBOL_GPL(preempt_notifier_inc); - -void preempt_notifier_dec(void) -{ - static_key_slow_dec(&preempt_notifier_key); -} -EXPORT_SYMBOL_GPL(preempt_notifier_dec); - -/** - * preempt_notifier_register - tell me when current is being preempted & rescheduled - * @notifier: notifier struct to register - */ -void preempt_notifier_register(struct preempt_notifier *notifier) -{ - if (!static_key_false(&preempt_notifier_key)) - WARN(1, "registering preempt_notifier while notifiers disabled\n"); - - hlist_add_head(¬ifier->link, ¤t->preempt_notifiers); -} -EXPORT_SYMBOL_GPL(preempt_notifier_register); - -/** - * preempt_notifier_unregister - no longer interested in preemption notifications - * @notifier: notifier struct to unregister - * - * This is *not* safe to call from within a preemption notifier. - */ -void preempt_notifier_unregister(struct preempt_notifier *notifier) -{ - hlist_del(¬ifier->link); -} -EXPORT_SYMBOL_GPL(preempt_notifier_unregister); - -static void __fire_sched_in_preempt_notifiers(struct task_struct *curr) -{ - struct preempt_notifier *notifier; - - hlist_for_each_entry(notifier, &curr->preempt_notifiers, link) - notifier->ops->sched_in(notifier, raw_smp_processor_id()); -} - -static __always_inline void fire_sched_in_preempt_notifiers(struct task_struct *curr) -{ - if (static_key_false(&preempt_notifier_key)) - __fire_sched_in_preempt_notifiers(curr); -} - -static void -__fire_sched_out_preempt_notifiers(struct task_struct *curr, - struct task_struct *next) -{ - struct preempt_notifier *notifier; - - hlist_for_each_entry(notifier, &curr->preempt_notifiers, link) - notifier->ops->sched_out(notifier, next); -} - -static __always_inline void -fire_sched_out_preempt_notifiers(struct task_struct *curr, - struct task_struct *next) -{ - if (static_key_false(&preempt_notifier_key)) - __fire_sched_out_preempt_notifiers(curr, next); -} - -#else /* !CONFIG_PREEMPT_NOTIFIERS */ - -static inline void fire_sched_in_preempt_notifiers(struct task_struct *curr) -{ -} - -static inline void -fire_sched_out_preempt_notifiers(struct task_struct *curr, - struct task_struct *next) -{ -} - -#endif /* CONFIG_PREEMPT_NOTIFIERS */ - -/** - * prepare_task_switch - prepare to switch tasks - * @rq: the runqueue preparing to switch - * @prev: the current task that is being switched out - * @next: the task we are going to switch to. - * - * This is called with the rq lock held and interrupts off. It must - * be paired with a subsequent finish_task_switch after the context - * switch. - * - * prepare_task_switch sets up locking and calls architecture specific - * hooks. - */ -static inline void -prepare_task_switch(struct rq *rq, struct task_struct *prev, - struct task_struct *next) -{ - sched_info_switch(rq, prev, next); - perf_event_task_sched_out(prev, next); - fire_sched_out_preempt_notifiers(prev, next); - prepare_lock_switch(rq, next); - prepare_arch_switch(next); -} - -/** - * finish_task_switch - clean up after a task-switch - * @prev: the thread we just switched away from. - * - * finish_task_switch must be called after the context switch, paired - * with a prepare_task_switch call before the context switch. - * finish_task_switch will reconcile locking set up by prepare_task_switch, - * and do any other architecture-specific cleanup actions. - * - * Note that we may have delayed dropping an mm in context_switch(). If - * so, we finish that here outside of the runqueue lock. (Doing it - * with the lock held can cause deadlocks; see schedule() for - * details.) - * - * The context switch have flipped the stack from under us and restored the - * local variables which were saved when this task called schedule() in the - * past. prev == current is still correct but we need to recalculate this_rq - * because prev may have moved to another CPU. - */ -static struct rq *finish_task_switch(struct task_struct *prev) - __releases(rq->lock) -{ - struct rq *rq = this_rq(); - struct mm_struct *mm = rq->prev_mm; - long prev_state; - - /* - * The previous task will have left us with a preempt_count of 2 - * because it left us after: - * - * schedule() - * preempt_disable(); // 1 - * __schedule() - * raw_spin_lock_irq(&rq->lock) // 2 - * - * Also, see FORK_PREEMPT_COUNT. - */ - if (WARN_ONCE(preempt_count() != 2*PREEMPT_DISABLE_OFFSET, - "corrupted preempt_count: %s/%d/0x%x\n", - current->comm, current->pid, preempt_count())) - preempt_count_set(FORK_PREEMPT_COUNT); - - rq->prev_mm = NULL; - - /* - * A task struct has one reference for the use as "current". - * If a task dies, then it sets TASK_DEAD in tsk->state and calls - * schedule one last time. The schedule call will never return, and - * the scheduled task must drop that reference. - * - * We must observe prev->state before clearing prev->on_cpu (in - * finish_lock_switch), otherwise a concurrent wakeup can get prev - * running on another CPU and we could rave with its RUNNING -> DEAD - * transition, resulting in a double drop. - */ - prev_state = prev->state; - vtime_task_switch(prev); - perf_event_task_sched_in(prev, current); - finish_lock_switch(rq, prev); - finish_arch_post_lock_switch(); - - fire_sched_in_preempt_notifiers(current); - if (mm) - mmdrop(mm); - if (unlikely(prev_state == TASK_DEAD)) { - if (prev->sched_class->task_dead) - prev->sched_class->task_dead(prev); - - /* - * Remove function-return probe instances associated with this - * task and put them back on the free list. - */ - kprobe_flush_task(prev); - - /* Task is done with its stack. */ - put_task_stack(prev); - - put_task_struct(prev); - } - - tick_nohz_task_switch(); - return rq; -} - -#ifdef CONFIG_SMP - -/* rq->lock is NOT held, but preemption is disabled */ -static void __balance_callback(struct rq *rq) -{ - struct callback_head *head, *next; - void (*func)(struct rq *rq); - unsigned long flags; - - raw_spin_lock_irqsave(&rq->lock, flags); - head = rq->balance_callback; - rq->balance_callback = NULL; - while (head) { - func = (void (*)(struct rq *))head->func; - next = head->next; - head->next = NULL; - head = next; - - func(rq); - } - raw_spin_unlock_irqrestore(&rq->lock, flags); -} - -static inline void balance_callback(struct rq *rq) -{ - if (unlikely(rq->balance_callback)) - __balance_callback(rq); -} - -#else - -static inline void balance_callback(struct rq *rq) -{ -} - -#endif - -/** - * schedule_tail - first thing a freshly forked thread must call. - * @prev: the thread we just switched away from. - */ -asmlinkage __visible void schedule_tail(struct task_struct *prev) - __releases(rq->lock) -{ - struct rq *rq; - - /* - * New tasks start with FORK_PREEMPT_COUNT, see there and - * finish_task_switch() for details. - * - * finish_task_switch() will drop rq->lock() and lower preempt_count - * and the preempt_enable() will end up enabling preemption (on - * PREEMPT_COUNT kernels). - */ - - rq = finish_task_switch(prev); - balance_callback(rq); - preempt_enable(); - - if (current->set_child_tid) - put_user(task_pid_vnr(current), current->set_child_tid); -} - -/* - * context_switch - switch to the new MM and the new thread's register state. - */ -static __always_inline struct rq * -context_switch(struct rq *rq, struct task_struct *prev, - struct task_struct *next, struct pin_cookie cookie) -{ - struct mm_struct *mm, *oldmm; - - prepare_task_switch(rq, prev, next); - - mm = next->mm; - oldmm = prev->active_mm; - /* - * For paravirt, this is coupled with an exit in switch_to to - * combine the page table reload and the switch backend into - * one hypercall. - */ - arch_start_context_switch(prev); - - if (!mm) { - next->active_mm = oldmm; - atomic_inc(&oldmm->mm_count); - enter_lazy_tlb(oldmm, next); - } else - switch_mm_irqs_off(oldmm, mm, next); - - if (!prev->mm) { - prev->active_mm = NULL; - rq->prev_mm = oldmm; - } - /* - * Since the runqueue lock will be released by the next - * task (which is an invalid locking op but in the case - * of the scheduler it's an obvious special-case), so we - * do an early lockdep release here: - */ - lockdep_unpin_lock(&rq->lock, cookie); - spin_release(&rq->lock.dep_map, 1, _THIS_IP_); - - /* Here we just switch the register state and the stack. */ - switch_to(prev, next, prev); - barrier(); - - return finish_task_switch(prev); -} - -/* - * nr_running and nr_context_switches: - * - * externally visible scheduler statistics: current number of runnable - * threads, total number of context switches performed since bootup. - */ -unsigned long nr_running(void) -{ - unsigned long i, sum = 0; - - for_each_online_cpu(i) - sum += cpu_rq(i)->nr_running; - - return sum; -} - -/* - * Check if only the current task is running on the cpu. - * - * Caution: this function does not check that the caller has disabled - * preemption, thus the result might have a time-of-check-to-time-of-use - * race. The caller is responsible to use it correctly, for example: - * - * - from a non-preemptable section (of course) - * - * - from a thread that is bound to a single CPU - * - * - in a loop with very short iterations (e.g. a polling loop) - */ -bool single_task_running(void) -{ - return raw_rq()->nr_running == 1; -} -EXPORT_SYMBOL(single_task_running); - -unsigned long long nr_context_switches(void) -{ - int i; - unsigned long long sum = 0; - - for_each_possible_cpu(i) - sum += cpu_rq(i)->nr_switches; - - return sum; -} - -unsigned long nr_iowait(void) -{ - unsigned long i, sum = 0; - - for_each_possible_cpu(i) - sum += atomic_read(&cpu_rq(i)->nr_iowait); - - return sum; -} - -unsigned long nr_iowait_cpu(int cpu) -{ - struct rq *this = cpu_rq(cpu); - return atomic_read(&this->nr_iowait); -} - -void get_iowait_load(unsigned long *nr_waiters, unsigned long *load) -{ - struct rq *rq = this_rq(); - *nr_waiters = atomic_read(&rq->nr_iowait); - *load = rq->load.weight; -} - -#ifdef CONFIG_SMP - -/* - * sched_exec - execve() is a valuable balancing opportunity, because at - * this point the task has the smallest effective memory and cache footprint. - */ -void sched_exec(void) -{ - struct task_struct *p = current; - unsigned long flags; - int dest_cpu; - - raw_spin_lock_irqsave(&p->pi_lock, flags); - dest_cpu = p->sched_class->select_task_rq(p, task_cpu(p), SD_BALANCE_EXEC, 0); - if (dest_cpu == smp_processor_id()) - goto unlock; - - if (likely(cpu_active(dest_cpu))) { - struct migration_arg arg = { p, dest_cpu }; - - raw_spin_unlock_irqrestore(&p->pi_lock, flags); - stop_one_cpu(task_cpu(p), migration_cpu_stop, &arg); - return; - } -unlock: - raw_spin_unlock_irqrestore(&p->pi_lock, flags); -} - -#endif - -DEFINE_PER_CPU(struct kernel_stat, kstat); -DEFINE_PER_CPU(struct kernel_cpustat, kernel_cpustat); - -EXPORT_PER_CPU_SYMBOL(kstat); -EXPORT_PER_CPU_SYMBOL(kernel_cpustat); - -/* - * The function fair_sched_class.update_curr accesses the struct curr - * and its field curr->exec_start; when called from task_sched_runtime(), - * we observe a high rate of cache misses in practice. - * Prefetching this data results in improved performance. - */ -static inline void prefetch_curr_exec_start(struct task_struct *p) -{ -#ifdef CONFIG_FAIR_GROUP_SCHED - struct sched_entity *curr = (&p->se)->cfs_rq->curr; -#else - struct sched_entity *curr = (&task_rq(p)->cfs)->curr; -#endif - prefetch(curr); - prefetch(&curr->exec_start); -} - -/* - * Return accounted runtime for the task. - * In case the task is currently running, return the runtime plus current's - * pending runtime that have not been accounted yet. - */ -unsigned long long task_sched_runtime(struct task_struct *p) -{ - struct rq_flags rf; - struct rq *rq; - u64 ns; - -#if defined(CONFIG_64BIT) && defined(CONFIG_SMP) - /* - * 64-bit doesn't need locks to atomically read a 64bit value. - * So we have a optimization chance when the task's delta_exec is 0. - * Reading ->on_cpu is racy, but this is ok. - * - * If we race with it leaving cpu, we'll take a lock. So we're correct. - * If we race with it entering cpu, unaccounted time is 0. This is - * indistinguishable from the read occurring a few cycles earlier. - * If we see ->on_cpu without ->on_rq, the task is leaving, and has - * been accounted, so we're correct here as well. - */ - if (!p->on_cpu || !task_on_rq_queued(p)) - return p->se.sum_exec_runtime; -#endif - - rq = task_rq_lock(p, &rf); - /* - * Must be ->curr _and_ ->on_rq. If dequeued, we would - * project cycles that may never be accounted to this - * thread, breaking clock_gettime(). - */ - if (task_current(rq, p) && task_on_rq_queued(p)) { - prefetch_curr_exec_start(p); - update_rq_clock(rq); - p->sched_class->update_curr(rq); - } - ns = p->se.sum_exec_runtime; - task_rq_unlock(rq, p, &rf); - - return ns; -} - -/* - * This function gets called by the timer code, with HZ frequency. - * We call it with interrupts disabled. - */ -void scheduler_tick(void) -{ - int cpu = smp_processor_id(); - struct rq *rq = cpu_rq(cpu); - struct task_struct *curr = rq->curr; - - sched_clock_tick(); - - raw_spin_lock(&rq->lock); - update_rq_clock(rq); - curr->sched_class->task_tick(rq, curr, 0); - cpu_load_update_active(rq); - calc_global_load_tick(rq); - raw_spin_unlock(&rq->lock); - - perf_event_task_tick(); - -#ifdef CONFIG_SMP - rq->idle_balance = idle_cpu(cpu); - trigger_load_balance(rq); -#endif - rq_last_tick_reset(rq); -} - -#ifdef CONFIG_NO_HZ_FULL -/** - * scheduler_tick_max_deferment - * - * Keep at least one tick per second when a single - * active task is running because the scheduler doesn't - * yet completely support full dynticks environment. - * - * This makes sure that uptime, CFS vruntime, load - * balancing, etc... continue to move forward, even - * with a very low granularity. - * - * Return: Maximum deferment in nanoseconds. - */ -u64 scheduler_tick_max_deferment(void) -{ - struct rq *rq = this_rq(); - unsigned long next, now = READ_ONCE(jiffies); - - next = rq->last_sched_tick + HZ; - - if (time_before_eq(next, now)) - return 0; - - return jiffies_to_nsecs(next - now); -} -#endif - -#if defined(CONFIG_PREEMPT) && (defined(CONFIG_DEBUG_PREEMPT) || \ - defined(CONFIG_PREEMPT_TRACER)) -/* - * If the value passed in is equal to the current preempt count - * then we just disabled preemption. Start timing the latency. - */ -static inline void preempt_latency_start(int val) -{ - if (preempt_count() == val) { - unsigned long ip = get_lock_parent_ip(); -#ifdef CONFIG_DEBUG_PREEMPT - current->preempt_disable_ip = ip; -#endif - trace_preempt_off(CALLER_ADDR0, ip); - } -} - -void preempt_count_add(int val) -{ -#ifdef CONFIG_DEBUG_PREEMPT - /* - * Underflow? - */ - if (DEBUG_LOCKS_WARN_ON((preempt_count() < 0))) - return; -#endif - __preempt_count_add(val); -#ifdef CONFIG_DEBUG_PREEMPT - /* - * Spinlock count overflowing soon? - */ - DEBUG_LOCKS_WARN_ON((preempt_count() & PREEMPT_MASK) >= - PREEMPT_MASK - 10); -#endif - preempt_latency_start(val); -} -EXPORT_SYMBOL(preempt_count_add); -NOKPROBE_SYMBOL(preempt_count_add); - -/* - * If the value passed in equals to the current preempt count - * then we just enabled preemption. Stop timing the latency. - */ -static inline void preempt_latency_stop(int val) -{ - if (preempt_count() == val) - trace_preempt_on(CALLER_ADDR0, get_lock_parent_ip()); -} - -void preempt_count_sub(int val) -{ -#ifdef CONFIG_DEBUG_PREEMPT - /* - * Underflow? - */ - if (DEBUG_LOCKS_WARN_ON(val > preempt_count())) - return; - /* - * Is the spinlock portion underflowing? - */ - if (DEBUG_LOCKS_WARN_ON((val < PREEMPT_MASK) && - !(preempt_count() & PREEMPT_MASK))) - return; -#endif - - preempt_latency_stop(val); - __preempt_count_sub(val); -} -EXPORT_SYMBOL(preempt_count_sub); -NOKPROBE_SYMBOL(preempt_count_sub); - -#else -static inline void preempt_latency_start(int val) { } -static inline void preempt_latency_stop(int val) { } -#endif - -/* - * Print scheduling while atomic bug: - */ -static noinline void __schedule_bug(struct task_struct *prev) -{ - /* Save this before calling printk(), since that will clobber it */ - unsigned long preempt_disable_ip = get_preempt_disable_ip(current); - - if (oops_in_progress) - return; - - printk(KERN_ERR "BUG: scheduling while atomic: %s/%d/0x%08x\n", - prev->comm, prev->pid, preempt_count()); - - debug_show_held_locks(prev); - print_modules(); - if (irqs_disabled()) - print_irqtrace_events(prev); - if (IS_ENABLED(CONFIG_DEBUG_PREEMPT) - && in_atomic_preempt_off()) { - pr_err("Preemption disabled at:"); - print_ip_sym(preempt_disable_ip); - pr_cont("\n"); - } - if (panic_on_warn) - panic("scheduling while atomic\n"); - - dump_stack(); - add_taint(TAINT_WARN, LOCKDEP_STILL_OK); -} - -/* - * Various schedule()-time debugging checks and statistics: - */ -static inline void schedule_debug(struct task_struct *prev) -{ -#ifdef CONFIG_SCHED_STACK_END_CHECK - if (task_stack_end_corrupted(prev)) - panic("corrupted stack end detected inside scheduler\n"); -#endif - - if (unlikely(in_atomic_preempt_off())) { - __schedule_bug(prev); - preempt_count_set(PREEMPT_DISABLED); - } - rcu_sleep_check(); - - profile_hit(SCHED_PROFILING, __builtin_return_address(0)); - - schedstat_inc(this_rq()->sched_count); -} - -/* - * Pick up the highest-prio task: - */ -static inline struct task_struct * -pick_next_task(struct rq *rq, struct task_struct *prev, struct pin_cookie cookie) -{ - const struct sched_class *class = &fair_sched_class; - struct task_struct *p; - - /* - * Optimization: we know that if all tasks are in - * the fair class we can call that function directly: - */ - if (likely(prev->sched_class == class && - rq->nr_running == rq->cfs.h_nr_running)) { - p = fair_sched_class.pick_next_task(rq, prev, cookie); - if (unlikely(p == RETRY_TASK)) - goto again; - - /* assumes fair_sched_class->next == idle_sched_class */ - if (unlikely(!p)) - p = idle_sched_class.pick_next_task(rq, prev, cookie); - - return p; - } - -again: - for_each_class(class) { - p = class->pick_next_task(rq, prev, cookie); - if (p) { - if (unlikely(p == RETRY_TASK)) - goto again; - return p; - } - } - - BUG(); /* the idle class will always have a runnable task */ -} - -/* - * __schedule() is the main scheduler function. - * - * The main means of driving the scheduler and thus entering this function are: - * - * 1. Explicit blocking: mutex, semaphore, waitqueue, etc. - * - * 2. TIF_NEED_RESCHED flag is checked on interrupt and userspace return - * paths. For example, see arch/x86/entry_64.S. - * - * To drive preemption between tasks, the scheduler sets the flag in timer - * interrupt handler scheduler_tick(). - * - * 3. Wakeups don't really cause entry into schedule(). They add a - * task to the run-queue and that's it. - * - * Now, if the new task added to the run-queue preempts the current - * task, then the wakeup sets TIF_NEED_RESCHED and schedule() gets - * called on the nearest possible occasion: - * - * - If the kernel is preemptible (CONFIG_PREEMPT=y): - * - * - in syscall or exception context, at the next outmost - * preempt_enable(). (this might be as soon as the wake_up()'s - * spin_unlock()!) - * - * - in IRQ context, return from interrupt-handler to - * preemptible context - * - * - If the kernel is not preemptible (CONFIG_PREEMPT is not set) - * then at the next: - * - * - cond_resched() call - * - explicit schedule() call - * - return from syscall or exception to user-space - * - return from interrupt-handler to user-space - * - * WARNING: must be called with preemption disabled! - */ -static void __sched notrace __schedule(bool preempt) -{ - struct task_struct *prev, *next; - unsigned long *switch_count; - struct pin_cookie cookie; - struct rq *rq; - int cpu; - - cpu = smp_processor_id(); - rq = cpu_rq(cpu); - prev = rq->curr; - - schedule_debug(prev); - - if (sched_feat(HRTICK)) - hrtick_clear(rq); - - local_irq_disable(); - rcu_note_context_switch(); - - /* - * Make sure that signal_pending_state()->signal_pending() below - * can't be reordered with __set_current_state(TASK_INTERRUPTIBLE) - * done by the caller to avoid the race with signal_wake_up(). - */ - smp_mb__before_spinlock(); - raw_spin_lock(&rq->lock); - cookie = lockdep_pin_lock(&rq->lock); - - rq->clock_skip_update <<= 1; /* promote REQ to ACT */ - - switch_count = &prev->nivcsw; - if (!preempt && prev->state) { - if (unlikely(signal_pending_state(prev->state, prev))) { - prev->state = TASK_RUNNING; - } else { - deactivate_task(rq, prev, DEQUEUE_SLEEP); - prev->on_rq = 0; - - /* - * If a worker went to sleep, notify and ask workqueue - * whether it wants to wake up a task to maintain - * concurrency. - */ - if (prev->flags & PF_WQ_WORKER) { - struct task_struct *to_wakeup; - - to_wakeup = wq_worker_sleeping(prev); - if (to_wakeup) - try_to_wake_up_local(to_wakeup, cookie); - } - } - switch_count = &prev->nvcsw; - } - - if (task_on_rq_queued(prev)) - update_rq_clock(rq); - - next = pick_next_task(rq, prev, cookie); - clear_tsk_need_resched(prev); - clear_preempt_need_resched(); - rq->clock_skip_update = 0; - - if (likely(prev != next)) { - rq->nr_switches++; - rq->curr = next; - ++*switch_count; - - trace_sched_switch(preempt, prev, next); - rq = context_switch(rq, prev, next, cookie); /* unlocks the rq */ - } else { - lockdep_unpin_lock(&rq->lock, cookie); - raw_spin_unlock_irq(&rq->lock); - } - - balance_callback(rq); -} - -void __noreturn do_task_dead(void) -{ - /* - * The setting of TASK_RUNNING by try_to_wake_up() may be delayed - * when the following two conditions become true. - * - There is race condition of mmap_sem (It is acquired by - * exit_mm()), and - * - SMI occurs before setting TASK_RUNINNG. - * (or hypervisor of virtual machine switches to other guest) - * As a result, we may become TASK_RUNNING after becoming TASK_DEAD - * - * To avoid it, we have to wait for releasing tsk->pi_lock which - * is held by try_to_wake_up() - */ - smp_mb(); - raw_spin_unlock_wait(¤t->pi_lock); - - /* causes final put_task_struct in finish_task_switch(). */ - __set_current_state(TASK_DEAD); - current->flags |= PF_NOFREEZE; /* tell freezer to ignore us */ - __schedule(false); - BUG(); - /* Avoid "noreturn function does return". */ - for (;;) - cpu_relax(); /* For when BUG is null */ -} - -static inline void sched_submit_work(struct task_struct *tsk) -{ - if (!tsk->state || tsk_is_pi_blocked(tsk)) - return; - /* - * If we are going to sleep and we have plugged IO queued, - * make sure to submit it to avoid deadlocks. - */ - if (blk_needs_flush_plug(tsk)) - blk_schedule_flush_plug(tsk); -} - -asmlinkage __visible void __sched schedule(void) -{ - struct task_struct *tsk = current; - - sched_submit_work(tsk); - do { - preempt_disable(); - __schedule(false); - sched_preempt_enable_no_resched(); - } while (need_resched()); -} -EXPORT_SYMBOL(schedule); - -#ifdef CONFIG_CONTEXT_TRACKING -asmlinkage __visible void __sched schedule_user(void) -{ - /* - * If we come here after a random call to set_need_resched(), - * or we have been woken up remotely but the IPI has not yet arrived, - * we haven't yet exited the RCU idle mode. Do it here manually until - * we find a better solution. - * - * NB: There are buggy callers of this function. Ideally we - * should warn if prev_state != CONTEXT_USER, but that will trigger - * too frequently to make sense yet. - */ - enum ctx_state prev_state = exception_enter(); - schedule(); - exception_exit(prev_state); -} -#endif - -/** - * schedule_preempt_disabled - called with preemption disabled - * - * Returns with preemption disabled. Note: preempt_count must be 1 - */ -void __sched schedule_preempt_disabled(void) -{ - sched_preempt_enable_no_resched(); - schedule(); - preempt_disable(); -} - -static void __sched notrace preempt_schedule_common(void) -{ - do { - /* - * Because the function tracer can trace preempt_count_sub() - * and it also uses preempt_enable/disable_notrace(), if - * NEED_RESCHED is set, the preempt_enable_notrace() called - * by the function tracer will call this function again and - * cause infinite recursion. - * - * Preemption must be disabled here before the function - * tracer can trace. Break up preempt_disable() into two - * calls. One to disable preemption without fear of being - * traced. The other to still record the preemption latency, - * which can also be traced by the function tracer. - */ - preempt_disable_notrace(); - preempt_latency_start(1); - __schedule(true); - preempt_latency_stop(1); - preempt_enable_no_resched_notrace(); - - /* - * Check again in case we missed a preemption opportunity - * between schedule and now. - */ - } while (need_resched()); -} - -#ifdef CONFIG_PREEMPT -/* - * this is the entry point to schedule() from in-kernel preemption - * off of preempt_enable. Kernel preemptions off return from interrupt - * occur there and call schedule directly. - */ -asmlinkage __visible void __sched notrace preempt_schedule(void) -{ - /* - * If there is a non-zero preempt_count or interrupts are disabled, - * we do not want to preempt the current task. Just return.. - */ - if (likely(!preemptible())) - return; - - preempt_schedule_common(); -} -NOKPROBE_SYMBOL(preempt_schedule); -EXPORT_SYMBOL(preempt_schedule); - -/** - * preempt_schedule_notrace - preempt_schedule called by tracing - * - * The tracing infrastructure uses preempt_enable_notrace to prevent - * recursion and tracing preempt enabling caused by the tracing - * infrastructure itself. But as tracing can happen in areas coming - * from userspace or just about to enter userspace, a preempt enable - * can occur before user_exit() is called. This will cause the scheduler - * to be called when the system is still in usermode. - * - * To prevent this, the preempt_enable_notrace will use this function - * instead of preempt_schedule() to exit user context if needed before - * calling the scheduler. - */ -asmlinkage __visible void __sched notrace preempt_schedule_notrace(void) -{ - enum ctx_state prev_ctx; - - if (likely(!preemptible())) - return; - - do { - /* - * Because the function tracer can trace preempt_count_sub() - * and it also uses preempt_enable/disable_notrace(), if - * NEED_RESCHED is set, the preempt_enable_notrace() called - * by the function tracer will call this function again and - * cause infinite recursion. - * - * Preemption must be disabled here before the function - * tracer can trace. Break up preempt_disable() into two - * calls. One to disable preemption without fear of being - * traced. The other to still record the preemption latency, - * which can also be traced by the function tracer. - */ - preempt_disable_notrace(); - preempt_latency_start(1); - /* - * Needs preempt disabled in case user_exit() is traced - * and the tracer calls preempt_enable_notrace() causing - * an infinite recursion. - */ - prev_ctx = exception_enter(); - __schedule(true); - exception_exit(prev_ctx); - - preempt_latency_stop(1); - preempt_enable_no_resched_notrace(); - } while (need_resched()); -} -EXPORT_SYMBOL_GPL(preempt_schedule_notrace); - -#endif /* CONFIG_PREEMPT */ - -/* - * this is the entry point to schedule() from kernel preemption - * off of irq context. - * Note, that this is called and return with irqs disabled. This will - * protect us against recursive calling from irq. - */ -asmlinkage __visible void __sched preempt_schedule_irq(void) -{ - enum ctx_state prev_state; - - /* Catch callers which need to be fixed */ - BUG_ON(preempt_count() || !irqs_disabled()); - - prev_state = exception_enter(); - - do { - preempt_disable(); - local_irq_enable(); - __schedule(true); - local_irq_disable(); - sched_preempt_enable_no_resched(); - } while (need_resched()); - - exception_exit(prev_state); -} - -int default_wake_function(wait_queue_t *curr, unsigned mode, int wake_flags, - void *key) -{ - return try_to_wake_up(curr->private, mode, wake_flags); -} -EXPORT_SYMBOL(default_wake_function); - -#ifdef CONFIG_RT_MUTEXES - -/* - * rt_mutex_setprio - set the current priority of a task - * @p: task - * @prio: prio value (kernel-internal form) - * - * This function changes the 'effective' priority of a task. It does - * not touch ->normal_prio like __setscheduler(). - * - * Used by the rt_mutex code to implement priority inheritance - * logic. Call site only calls if the priority of the task changed. - */ -void rt_mutex_setprio(struct task_struct *p, int prio) -{ - int oldprio, queued, running, queue_flag = DEQUEUE_SAVE | DEQUEUE_MOVE; - const struct sched_class *prev_class; - struct rq_flags rf; - struct rq *rq; - - BUG_ON(prio > MAX_PRIO); - - rq = __task_rq_lock(p, &rf); - - /* - * Idle task boosting is a nono in general. There is one - * exception, when PREEMPT_RT and NOHZ is active: - * - * The idle task calls get_next_timer_interrupt() and holds - * the timer wheel base->lock on the CPU and another CPU wants - * to access the timer (probably to cancel it). We can safely - * ignore the boosting request, as the idle CPU runs this code - * with interrupts disabled and will complete the lock - * protected section without being interrupted. So there is no - * real need to boost. - */ - if (unlikely(p == rq->idle)) { - WARN_ON(p != rq->curr); - WARN_ON(p->pi_blocked_on); - goto out_unlock; - } - - trace_sched_pi_setprio(p, prio); - oldprio = p->prio; - - if (oldprio == prio) - queue_flag &= ~DEQUEUE_MOVE; - - prev_class = p->sched_class; - queued = task_on_rq_queued(p); - running = task_current(rq, p); - if (queued) - dequeue_task(rq, p, queue_flag); - if (running) - put_prev_task(rq, p); - - /* - * Boosting condition are: - * 1. -rt task is running and holds mutex A - * --> -dl task blocks on mutex A - * - * 2. -dl task is running and holds mutex A - * --> -dl task blocks on mutex A and could preempt the - * running task - */ - if (dl_prio(prio)) { - struct task_struct *pi_task = rt_mutex_get_top_task(p); - if (!dl_prio(p->normal_prio) || - (pi_task && dl_entity_preempt(&pi_task->dl, &p->dl))) { - p->dl.dl_boosted = 1; - queue_flag |= ENQUEUE_REPLENISH; - } else - p->dl.dl_boosted = 0; - p->sched_class = &dl_sched_class; - } else if (rt_prio(prio)) { - if (dl_prio(oldprio)) - p->dl.dl_boosted = 0; - if (oldprio < prio) - queue_flag |= ENQUEUE_HEAD; - p->sched_class = &rt_sched_class; - } else { - if (dl_prio(oldprio)) - p->dl.dl_boosted = 0; - if (rt_prio(oldprio)) - p->rt.timeout = 0; - p->sched_class = &fair_sched_class; - } - - p->prio = prio; - - if (queued) - enqueue_task(rq, p, queue_flag); - if (running) - set_curr_task(rq, p); - - check_class_changed(rq, p, prev_class, oldprio); -out_unlock: - preempt_disable(); /* avoid rq from going away on us */ - __task_rq_unlock(rq, &rf); - - balance_callback(rq); - preempt_enable(); -} -#endif - -void set_user_nice(struct task_struct *p, long nice) -{ - bool queued, running; - int old_prio, delta; - struct rq_flags rf; - struct rq *rq; - - if (task_nice(p) == nice || nice < MIN_NICE || nice > MAX_NICE) - return; - /* - * We have to be careful, if called from sys_setpriority(), - * the task might be in the middle of scheduling on another CPU. - */ - rq = task_rq_lock(p, &rf); - /* - * The RT priorities are set via sched_setscheduler(), but we still - * allow the 'normal' nice value to be set - but as expected - * it wont have any effect on scheduling until the task is - * SCHED_DEADLINE, SCHED_FIFO or SCHED_RR: - */ - if (task_has_dl_policy(p) || task_has_rt_policy(p)) { - p->static_prio = NICE_TO_PRIO(nice); - goto out_unlock; - } - queued = task_on_rq_queued(p); - running = task_current(rq, p); - if (queued) - dequeue_task(rq, p, DEQUEUE_SAVE); - if (running) - put_prev_task(rq, p); - - p->static_prio = NICE_TO_PRIO(nice); - set_load_weight(p); - old_prio = p->prio; - p->prio = effective_prio(p); - delta = p->prio - old_prio; - - if (queued) { - enqueue_task(rq, p, ENQUEUE_RESTORE); - /* - * If the task increased its priority or is running and - * lowered its priority, then reschedule its CPU: - */ - if (delta < 0 || (delta > 0 && task_running(rq, p))) - resched_curr(rq); - } - if (running) - set_curr_task(rq, p); -out_unlock: - task_rq_unlock(rq, p, &rf); -} -EXPORT_SYMBOL(set_user_nice); - -/* - * can_nice - check if a task can reduce its nice value - * @p: task - * @nice: nice value - */ -int can_nice(const struct task_struct *p, const int nice) -{ - /* convert nice value [19,-20] to rlimit style value [1,40] */ - int nice_rlim = nice_to_rlimit(nice); - - return (nice_rlim <= task_rlimit(p, RLIMIT_NICE) || - capable(CAP_SYS_NICE)); -} - -#ifdef __ARCH_WANT_SYS_NICE - -/* - * sys_nice - change the priority of the current process. - * @increment: priority increment - * - * sys_setpriority is a more generic, but much slower function that - * does similar things. - */ -SYSCALL_DEFINE1(nice, int, increment) -{ - long nice, retval; - - /* - * Setpriority might change our priority at the same moment. - * We don't have to worry. Conceptually one call occurs first - * and we have a single winner. - */ - increment = clamp(increment, -NICE_WIDTH, NICE_WIDTH); - nice = task_nice(current) + increment; - - nice = clamp_val(nice, MIN_NICE, MAX_NICE); - if (increment < 0 && !can_nice(current, nice)) - return -EPERM; - - retval = security_task_setnice(current, nice); - if (retval) - return retval; - - set_user_nice(current, nice); - return 0; -} - -#endif - -/** - * task_prio - return the priority value of a given task. - * @p: the task in question. - * - * Return: The priority value as seen by users in /proc. - * RT tasks are offset by -200. Normal tasks are centered - * around 0, value goes from -16 to +15. - */ -int task_prio(const struct task_struct *p) -{ - return p->prio - MAX_RT_PRIO; -} - -/** - * idle_cpu - is a given cpu idle currently? - * @cpu: the processor in question. - * - * Return: 1 if the CPU is currently idle. 0 otherwise. - */ -int idle_cpu(int cpu) -{ - struct rq *rq = cpu_rq(cpu); - - if (rq->curr != rq->idle) - return 0; - - if (rq->nr_running) - return 0; - -#ifdef CONFIG_SMP - if (!llist_empty(&rq->wake_list)) - return 0; -#endif - - return 1; -} - -/** - * idle_task - return the idle task for a given cpu. - * @cpu: the processor in question. - * - * Return: The idle task for the cpu @cpu. - */ -struct task_struct *idle_task(int cpu) -{ - return cpu_rq(cpu)->idle; -} - -/** - * find_process_by_pid - find a process with a matching PID value. - * @pid: the pid in question. - * - * The task of @pid, if found. %NULL otherwise. - */ -static struct task_struct *find_process_by_pid(pid_t pid) -{ - return pid ? find_task_by_vpid(pid) : current; -} - -/* - * This function initializes the sched_dl_entity of a newly becoming - * SCHED_DEADLINE task. - * - * Only the static values are considered here, the actual runtime and the - * absolute deadline will be properly calculated when the task is enqueued - * for the first time with its new policy. - */ -static void -__setparam_dl(struct task_struct *p, const struct sched_attr *attr) -{ - struct sched_dl_entity *dl_se = &p->dl; - - dl_se->dl_runtime = attr->sched_runtime; - dl_se->dl_deadline = attr->sched_deadline; - dl_se->dl_period = attr->sched_period ?: dl_se->dl_deadline; - dl_se->flags = attr->sched_flags; - dl_se->dl_bw = to_ratio(dl_se->dl_period, dl_se->dl_runtime); - - /* - * Changing the parameters of a task is 'tricky' and we're not doing - * the correct thing -- also see task_dead_dl() and switched_from_dl(). - * - * What we SHOULD do is delay the bandwidth release until the 0-lag - * point. This would include retaining the task_struct until that time - * and change dl_overflow() to not immediately decrement the current - * amount. - * - * Instead we retain the current runtime/deadline and let the new - * parameters take effect after the current reservation period lapses. - * This is safe (albeit pessimistic) because the 0-lag point is always - * before the current scheduling deadline. - * - * We can still have temporary overloads because we do not delay the - * change in bandwidth until that time; so admission control is - * not on the safe side. It does however guarantee tasks will never - * consume more than promised. - */ -} - -/* - * sched_setparam() passes in -1 for its policy, to let the functions - * it calls know not to change it. - */ -#define SETPARAM_POLICY -1 - -static void __setscheduler_params(struct task_struct *p, - const struct sched_attr *attr) -{ - int policy = attr->sched_policy; - - if (policy == SETPARAM_POLICY) - policy = p->policy; - - p->policy = policy; - - if (dl_policy(policy)) - __setparam_dl(p, attr); - else if (fair_policy(policy)) - p->static_prio = NICE_TO_PRIO(attr->sched_nice); - - /* - * __sched_setscheduler() ensures attr->sched_priority == 0 when - * !rt_policy. Always setting this ensures that things like - * getparam()/getattr() don't report silly values for !rt tasks. - */ - p->rt_priority = attr->sched_priority; - p->normal_prio = normal_prio(p); - set_load_weight(p); -} - -/* Actually do priority change: must hold pi & rq lock. */ -static void __setscheduler(struct rq *rq, struct task_struct *p, - const struct sched_attr *attr, bool keep_boost) -{ - __setscheduler_params(p, attr); - - /* - * Keep a potential priority boosting if called from - * sched_setscheduler(). - */ - if (keep_boost) - p->prio = rt_mutex_get_effective_prio(p, normal_prio(p)); - else - p->prio = normal_prio(p); - - if (dl_prio(p->prio)) - p->sched_class = &dl_sched_class; - else if (rt_prio(p->prio)) - p->sched_class = &rt_sched_class; - else - p->sched_class = &fair_sched_class; -} - -static void -__getparam_dl(struct task_struct *p, struct sched_attr *attr) -{ - struct sched_dl_entity *dl_se = &p->dl; - - attr->sched_priority = p->rt_priority; - attr->sched_runtime = dl_se->dl_runtime; - attr->sched_deadline = dl_se->dl_deadline; - attr->sched_period = dl_se->dl_period; - attr->sched_flags = dl_se->flags; -} - -/* - * This function validates the new parameters of a -deadline task. - * We ask for the deadline not being zero, and greater or equal - * than the runtime, as well as the period of being zero or - * greater than deadline. Furthermore, we have to be sure that - * user parameters are above the internal resolution of 1us (we - * check sched_runtime only since it is always the smaller one) and - * below 2^63 ns (we have to check both sched_deadline and - * sched_period, as the latter can be zero). - */ -static bool -__checkparam_dl(const struct sched_attr *attr) -{ - /* deadline != 0 */ - if (attr->sched_deadline == 0) - return false; - - /* - * Since we truncate DL_SCALE bits, make sure we're at least - * that big. - */ - if (attr->sched_runtime < (1ULL << DL_SCALE)) - return false; - - /* - * Since we use the MSB for wrap-around and sign issues, make - * sure it's not set (mind that period can be equal to zero). - */ - if (attr->sched_deadline & (1ULL << 63) || - attr->sched_period & (1ULL << 63)) - return false; - - /* runtime <= deadline <= period (if period != 0) */ - if ((attr->sched_period != 0 && - attr->sched_period < attr->sched_deadline) || - attr->sched_deadline < attr->sched_runtime) - return false; - - return true; -} - -/* - * check the target process has a UID that matches the current process's - */ -static bool check_same_owner(struct task_struct *p) -{ - const struct cred *cred = current_cred(), *pcred; - bool match; - - rcu_read_lock(); - pcred = __task_cred(p); - match = (uid_eq(cred->euid, pcred->euid) || - uid_eq(cred->euid, pcred->uid)); - rcu_read_unlock(); - return match; -} - -static bool dl_param_changed(struct task_struct *p, - const struct sched_attr *attr) -{ - struct sched_dl_entity *dl_se = &p->dl; - - if (dl_se->dl_runtime != attr->sched_runtime || - dl_se->dl_deadline != attr->sched_deadline || - dl_se->dl_period != attr->sched_period || - dl_se->flags != attr->sched_flags) - return true; - - return false; -} - -static int __sched_setscheduler(struct task_struct *p, - const struct sched_attr *attr, - bool user, bool pi) -{ - int newprio = dl_policy(attr->sched_policy) ? MAX_DL_PRIO - 1 : - MAX_RT_PRIO - 1 - attr->sched_priority; - int retval, oldprio, oldpolicy = -1, queued, running; - int new_effective_prio, policy = attr->sched_policy; - const struct sched_class *prev_class; - struct rq_flags rf; - int reset_on_fork; - int queue_flags = DEQUEUE_SAVE | DEQUEUE_MOVE; - struct rq *rq; - - /* may grab non-irq protected spin_locks */ - BUG_ON(in_interrupt()); -recheck: - /* double check policy once rq lock held */ - if (policy < 0) { - reset_on_fork = p->sched_reset_on_fork; - policy = oldpolicy = p->policy; - } else { - reset_on_fork = !!(attr->sched_flags & SCHED_FLAG_RESET_ON_FORK); - - if (!valid_policy(policy)) - return -EINVAL; - } - - if (attr->sched_flags & ~(SCHED_FLAG_RESET_ON_FORK)) - return -EINVAL; - - /* - * Valid priorities for SCHED_FIFO and SCHED_RR are - * 1..MAX_USER_RT_PRIO-1, valid priority for SCHED_NORMAL, - * SCHED_BATCH and SCHED_IDLE is 0. - */ - if ((p->mm && attr->sched_priority > MAX_USER_RT_PRIO-1) || - (!p->mm && attr->sched_priority > MAX_RT_PRIO-1)) - return -EINVAL; - if ((dl_policy(policy) && !__checkparam_dl(attr)) || - (rt_policy(policy) != (attr->sched_priority != 0))) - return -EINVAL; - - /* - * Allow unprivileged RT tasks to decrease priority: - */ - if (user && !capable(CAP_SYS_NICE)) { - if (fair_policy(policy)) { - if (attr->sched_nice < task_nice(p) && - !can_nice(p, attr->sched_nice)) - return -EPERM; - } - - if (rt_policy(policy)) { - unsigned long rlim_rtprio = - task_rlimit(p, RLIMIT_RTPRIO); - - /* can't set/change the rt policy */ - if (policy != p->policy && !rlim_rtprio) - return -EPERM; - - /* can't increase priority */ - if (attr->sched_priority > p->rt_priority && - attr->sched_priority > rlim_rtprio) - return -EPERM; - } - - /* - * Can't set/change SCHED_DEADLINE policy at all for now - * (safest behavior); in the future we would like to allow - * unprivileged DL tasks to increase their relative deadline - * or reduce their runtime (both ways reducing utilization) - */ - if (dl_policy(policy)) - return -EPERM; - - /* - * Treat SCHED_IDLE as nice 20. Only allow a switch to - * SCHED_NORMAL if the RLIMIT_NICE would normally permit it. - */ - if (idle_policy(p->policy) && !idle_policy(policy)) { - if (!can_nice(p, task_nice(p))) - return -EPERM; - } - - /* can't change other user's priorities */ - if (!check_same_owner(p)) - return -EPERM; - - /* Normal users shall not reset the sched_reset_on_fork flag */ - if (p->sched_reset_on_fork && !reset_on_fork) - return -EPERM; - } - - if (user) { - retval = security_task_setscheduler(p); - if (retval) - return retval; - } - - /* - * make sure no PI-waiters arrive (or leave) while we are - * changing the priority of the task: - * - * To be able to change p->policy safely, the appropriate - * runqueue lock must be held. - */ - rq = task_rq_lock(p, &rf); - - /* - * Changing the policy of the stop threads its a very bad idea - */ - if (p == rq->stop) { - task_rq_unlock(rq, p, &rf); - return -EINVAL; - } - - /* - * If not changing anything there's no need to proceed further, - * but store a possible modification of reset_on_fork. - */ - if (unlikely(policy == p->policy)) { - if (fair_policy(policy) && attr->sched_nice != task_nice(p)) - goto change; - if (rt_policy(policy) && attr->sched_priority != p->rt_priority) - goto change; - if (dl_policy(policy) && dl_param_changed(p, attr)) - goto change; - - p->sched_reset_on_fork = reset_on_fork; - task_rq_unlock(rq, p, &rf); - return 0; - } -change: - - if (user) { -#ifdef CONFIG_RT_GROUP_SCHED - /* - * Do not allow realtime tasks into groups that have no runtime - * assigned. - */ - if (rt_bandwidth_enabled() && rt_policy(policy) && - task_group(p)->rt_bandwidth.rt_runtime == 0 && - !task_group_is_autogroup(task_group(p))) { - task_rq_unlock(rq, p, &rf); - return -EPERM; - } -#endif -#ifdef CONFIG_SMP - if (dl_bandwidth_enabled() && dl_policy(policy)) { - cpumask_t *span = rq->rd->span; - - /* - * Don't allow tasks with an affinity mask smaller than - * the entire root_domain to become SCHED_DEADLINE. We - * will also fail if there's no bandwidth available. - */ - if (!cpumask_subset(span, &p->cpus_allowed) || - rq->rd->dl_bw.bw == 0) { - task_rq_unlock(rq, p, &rf); - return -EPERM; - } - } -#endif - } - - /* recheck policy now with rq lock held */ - if (unlikely(oldpolicy != -1 && oldpolicy != p->policy)) { - policy = oldpolicy = -1; - task_rq_unlock(rq, p, &rf); - goto recheck; - } - - /* - * If setscheduling to SCHED_DEADLINE (or changing the parameters - * of a SCHED_DEADLINE task) we need to check if enough bandwidth - * is available. - */ - if ((dl_policy(policy) || dl_task(p)) && dl_overflow(p, policy, attr)) { - task_rq_unlock(rq, p, &rf); - return -EBUSY; - } - - p->sched_reset_on_fork = reset_on_fork; - oldprio = p->prio; - - if (pi) { - /* - * Take priority boosted tasks into account. If the new - * effective priority is unchanged, we just store the new - * normal parameters and do not touch the scheduler class and - * the runqueue. This will be done when the task deboost - * itself. - */ - new_effective_prio = rt_mutex_get_effective_prio(p, newprio); - if (new_effective_prio == oldprio) - queue_flags &= ~DEQUEUE_MOVE; - } - - queued = task_on_rq_queued(p); - running = task_current(rq, p); - if (queued) - dequeue_task(rq, p, queue_flags); - if (running) - put_prev_task(rq, p); - - prev_class = p->sched_class; - __setscheduler(rq, p, attr, pi); - - if (queued) { - /* - * We enqueue to tail when the priority of a task is - * increased (user space view). - */ - if (oldprio < p->prio) - queue_flags |= ENQUEUE_HEAD; - - enqueue_task(rq, p, queue_flags); - } - if (running) - set_curr_task(rq, p); - - check_class_changed(rq, p, prev_class, oldprio); - preempt_disable(); /* avoid rq from going away on us */ - task_rq_unlock(rq, p, &rf); - - if (pi) - rt_mutex_adjust_pi(p); - - /* - * Run balance callbacks after we've adjusted the PI chain. - */ - balance_callback(rq); - preempt_enable(); - - return 0; -} - -static int _sched_setscheduler(struct task_struct *p, int policy, - const struct sched_param *param, bool check) -{ - struct sched_attr attr = { - .sched_policy = policy, - .sched_priority = param->sched_priority, - .sched_nice = PRIO_TO_NICE(p->static_prio), - }; - - /* Fixup the legacy SCHED_RESET_ON_FORK hack. */ - if ((policy != SETPARAM_POLICY) && (policy & SCHED_RESET_ON_FORK)) { - attr.sched_flags |= SCHED_FLAG_RESET_ON_FORK; - policy &= ~SCHED_RESET_ON_FORK; - attr.sched_policy = policy; - } - - return __sched_setscheduler(p, &attr, check, true); -} -/** - * sched_setscheduler - change the scheduling policy and/or RT priority of a thread. - * @p: the task in question. - * @policy: new policy. - * @param: structure containing the new RT priority. - * - * Return: 0 on success. An error code otherwise. - * - * NOTE that the task may be already dead. - */ -int sched_setscheduler(struct task_struct *p, int policy, - const struct sched_param *param) -{ - return _sched_setscheduler(p, policy, param, true); -} -EXPORT_SYMBOL_GPL(sched_setscheduler); - -int sched_setattr(struct task_struct *p, const struct sched_attr *attr) -{ - return __sched_setscheduler(p, attr, true, true); -} -EXPORT_SYMBOL_GPL(sched_setattr); - -/** - * sched_setscheduler_nocheck - change the scheduling policy and/or RT priority of a thread from kernelspace. - * @p: the task in question. - * @policy: new policy. - * @param: structure containing the new RT priority. - * - * Just like sched_setscheduler, only don't bother checking if the - * current context has permission. For example, this is needed in - * stop_machine(): we create temporary high priority worker threads, - * but our caller might not have that capability. - * - * Return: 0 on success. An error code otherwise. - */ -int sched_setscheduler_nocheck(struct task_struct *p, int policy, - const struct sched_param *param) -{ - return _sched_setscheduler(p, policy, param, false); -} -EXPORT_SYMBOL_GPL(sched_setscheduler_nocheck); - -static int -do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param) -{ - struct sched_param lparam; - struct task_struct *p; - int retval; - - if (!param || pid < 0) - return -EINVAL; - if (copy_from_user(&lparam, param, sizeof(struct sched_param))) - return -EFAULT; - - rcu_read_lock(); - retval = -ESRCH; - p = find_process_by_pid(pid); - if (p != NULL) - retval = sched_setscheduler(p, policy, &lparam); - rcu_read_unlock(); - - return retval; -} - -/* - * Mimics kernel/events/core.c perf_copy_attr(). - */ -static int sched_copy_attr(struct sched_attr __user *uattr, - struct sched_attr *attr) -{ - u32 size; - int ret; - - if (!access_ok(VERIFY_WRITE, uattr, SCHED_ATTR_SIZE_VER0)) - return -EFAULT; - - /* - * zero the full structure, so that a short copy will be nice. - */ - memset(attr, 0, sizeof(*attr)); - - ret = get_user(size, &uattr->size); - if (ret) - return ret; - - if (size > PAGE_SIZE) /* silly large */ - goto err_size; - - if (!size) /* abi compat */ - size = SCHED_ATTR_SIZE_VER0; - - if (size < SCHED_ATTR_SIZE_VER0) - goto err_size; - - /* - * If we're handed a bigger struct than we know of, - * ensure all the unknown bits are 0 - i.e. new - * user-space does not rely on any kernel feature - * extensions we dont know about yet. - */ - if (size > sizeof(*attr)) { - unsigned char __user *addr; - unsigned char __user *end; - unsigned char val; - - addr = (void __user *)uattr + sizeof(*attr); - end = (void __user *)uattr + size; - - for (; addr < end; addr++) { - ret = get_user(val, addr); - if (ret) - return ret; - if (val) - goto err_size; - } - size = sizeof(*attr); - } - - ret = copy_from_user(attr, uattr, size); - if (ret) - return -EFAULT; - - /* - * XXX: do we want to be lenient like existing syscalls; or do we want - * to be strict and return an error on out-of-bounds values? - */ - attr->sched_nice = clamp(attr->sched_nice, MIN_NICE, MAX_NICE); - - return 0; - -err_size: - put_user(sizeof(*attr), &uattr->size); - return -E2BIG; -} - -/** - * sys_sched_setscheduler - set/change the scheduler policy and RT priority - * @pid: the pid in question. - * @policy: new policy. - * @param: structure containing the new RT priority. - * - * Return: 0 on success. An error code otherwise. - */ -SYSCALL_DEFINE3(sched_setscheduler, pid_t, pid, int, policy, - struct sched_param __user *, param) -{ - /* negative values for policy are not valid */ - if (policy < 0) - return -EINVAL; - - return do_sched_setscheduler(pid, policy, param); -} - -/** - * sys_sched_setparam - set/change the RT priority of a thread - * @pid: the pid in question. - * @param: structure containing the new RT priority. - * - * Return: 0 on success. An error code otherwise. - */ -SYSCALL_DEFINE2(sched_setparam, pid_t, pid, struct sched_param __user *, param) -{ - return do_sched_setscheduler(pid, SETPARAM_POLICY, param); -} - -/** - * sys_sched_setattr - same as above, but with extended sched_attr - * @pid: the pid in question. - * @uattr: structure containing the extended parameters. - * @flags: for future extension. - */ -SYSCALL_DEFINE3(sched_setattr, pid_t, pid, struct sched_attr __user *, uattr, - unsigned int, flags) -{ - struct sched_attr attr; - struct task_struct *p; - int retval; - - if (!uattr || pid < 0 || flags) - return -EINVAL; - - retval = sched_copy_attr(uattr, &attr); - if (retval) - return retval; - - if ((int)attr.sched_policy < 0) - return -EINVAL; - - rcu_read_lock(); - retval = -ESRCH; - p = find_process_by_pid(pid); - if (p != NULL) - retval = sched_setattr(p, &attr); - rcu_read_unlock(); - - return retval; -} - -/** - * sys_sched_getscheduler - get the policy (scheduling class) of a thread - * @pid: the pid in question. - * - * Return: On success, the policy of the thread. Otherwise, a negative error - * code. - */ -SYSCALL_DEFINE1(sched_getscheduler, pid_t, pid) -{ - struct task_struct *p; - int retval; - - if (pid < 0) - return -EINVAL; - - retval = -ESRCH; - rcu_read_lock(); - p = find_process_by_pid(pid); - if (p) { - retval = security_task_getscheduler(p); - if (!retval) - retval = p->policy - | (p->sched_reset_on_fork ? SCHED_RESET_ON_FORK : 0); - } - rcu_read_unlock(); - return retval; -} - -/** - * sys_sched_getparam - get the RT priority of a thread - * @pid: the pid in question. - * @param: structure containing the RT priority. - * - * Return: On success, 0 and the RT priority is in @param. Otherwise, an error - * code. - */ -SYSCALL_DEFINE2(sched_getparam, pid_t, pid, struct sched_param __user *, param) -{ - struct sched_param lp = { .sched_priority = 0 }; - struct task_struct *p; - int retval; - - if (!param || pid < 0) - return -EINVAL; - - rcu_read_lock(); - p = find_process_by_pid(pid); - retval = -ESRCH; - if (!p) - goto out_unlock; - - retval = security_task_getscheduler(p); - if (retval) - goto out_unlock; - - if (task_has_rt_policy(p)) - lp.sched_priority = p->rt_priority; - rcu_read_unlock(); - - /* - * This one might sleep, we cannot do it with a spinlock held ... - */ - retval = copy_to_user(param, &lp, sizeof(*param)) ? -EFAULT : 0; - - return retval; - -out_unlock: - rcu_read_unlock(); - return retval; -} - -static int sched_read_attr(struct sched_attr __user *uattr, - struct sched_attr *attr, - unsigned int usize) -{ - int ret; - - if (!access_ok(VERIFY_WRITE, uattr, usize)) - return -EFAULT; - - /* - * If we're handed a smaller struct than we know of, - * ensure all the unknown bits are 0 - i.e. old - * user-space does not get uncomplete information. - */ - if (usize < sizeof(*attr)) { - unsigned char *addr; - unsigned char *end; - - addr = (void *)attr + usize; - end = (void *)attr + sizeof(*attr); - - for (; addr < end; addr++) { - if (*addr) - return -EFBIG; - } - - attr->size = usize; - } - - ret = copy_to_user(uattr, attr, attr->size); - if (ret) - return -EFAULT; - - return 0; -} - -/** - * sys_sched_getattr - similar to sched_getparam, but with sched_attr - * @pid: the pid in question. - * @uattr: structure containing the extended parameters. - * @size: sizeof(attr) for fwd/bwd comp. - * @flags: for future extension. - */ -SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr, - unsigned int, size, unsigned int, flags) -{ - struct sched_attr attr = { - .size = sizeof(struct sched_attr), - }; - struct task_struct *p; - int retval; - - if (!uattr || pid < 0 || size > PAGE_SIZE || - size < SCHED_ATTR_SIZE_VER0 || flags) - return -EINVAL; - - rcu_read_lock(); - p = find_process_by_pid(pid); - retval = -ESRCH; - if (!p) - goto out_unlock; - - retval = security_task_getscheduler(p); - if (retval) - goto out_unlock; - - attr.sched_policy = p->policy; - if (p->sched_reset_on_fork) - attr.sched_flags |= SCHED_FLAG_RESET_ON_FORK; - if (task_has_dl_policy(p)) - __getparam_dl(p, &attr); - else if (task_has_rt_policy(p)) - attr.sched_priority = p->rt_priority; - else - attr.sched_nice = task_nice(p); - - rcu_read_unlock(); - - retval = sched_read_attr(uattr, &attr, size); - return retval; - -out_unlock: - rcu_read_unlock(); - return retval; -} - -long sched_setaffinity(pid_t pid, const struct cpumask *in_mask) -{ - cpumask_var_t cpus_allowed, new_mask; - struct task_struct *p; - int retval; - - rcu_read_lock(); - - p = find_process_by_pid(pid); - if (!p) { - rcu_read_unlock(); - return -ESRCH; - } - - /* Prevent p going away */ - get_task_struct(p); - rcu_read_unlock(); - - if (p->flags & PF_NO_SETAFFINITY) { - retval = -EINVAL; - goto out_put_task; - } - if (!alloc_cpumask_var(&cpus_allowed, GFP_KERNEL)) { - retval = -ENOMEM; - goto out_put_task; - } - if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) { - retval = -ENOMEM; - goto out_free_cpus_allowed; - } - retval = -EPERM; - if (!check_same_owner(p)) { - rcu_read_lock(); - if (!ns_capable(__task_cred(p)->user_ns, CAP_SYS_NICE)) { - rcu_read_unlock(); - goto out_free_new_mask; - } - rcu_read_unlock(); - } - - retval = security_task_setscheduler(p); - if (retval) - goto out_free_new_mask; - - - cpuset_cpus_allowed(p, cpus_allowed); - cpumask_and(new_mask, in_mask, cpus_allowed); - - /* - * Since bandwidth control happens on root_domain basis, - * if admission test is enabled, we only admit -deadline - * tasks allowed to run on all the CPUs in the task's - * root_domain. - */ -#ifdef CONFIG_SMP - if (task_has_dl_policy(p) && dl_bandwidth_enabled()) { - rcu_read_lock(); - if (!cpumask_subset(task_rq(p)->rd->span, new_mask)) { - retval = -EBUSY; - rcu_read_unlock(); - goto out_free_new_mask; - } - rcu_read_unlock(); - } -#endif -again: - retval = __set_cpus_allowed_ptr(p, new_mask, true); - - if (!retval) { - cpuset_cpus_allowed(p, cpus_allowed); - if (!cpumask_subset(new_mask, cpus_allowed)) { - /* - * We must have raced with a concurrent cpuset - * update. Just reset the cpus_allowed to the - * cpuset's cpus_allowed - */ - cpumask_copy(new_mask, cpus_allowed); - goto again; - } - } -out_free_new_mask: - free_cpumask_var(new_mask); -out_free_cpus_allowed: - free_cpumask_var(cpus_allowed); -out_put_task: - put_task_struct(p); - return retval; -} - -static int get_user_cpu_mask(unsigned long __user *user_mask_ptr, unsigned len, - struct cpumask *new_mask) -{ - if (len < cpumask_size()) - cpumask_clear(new_mask); - else if (len > cpumask_size()) - len = cpumask_size(); - - return copy_from_user(new_mask, user_mask_ptr, len) ? -EFAULT : 0; -} - -/** - * sys_sched_setaffinity - set the cpu affinity of a process - * @pid: pid of the process - * @len: length in bytes of the bitmask pointed to by user_mask_ptr - * @user_mask_ptr: user-space pointer to the new cpu mask - * - * Return: 0 on success. An error code otherwise. - */ -SYSCALL_DEFINE3(sched_setaffinity, pid_t, pid, unsigned int, len, - unsigned long __user *, user_mask_ptr) -{ - cpumask_var_t new_mask; - int retval; - - if (!alloc_cpumask_var(&new_mask, GFP_KERNEL)) - return -ENOMEM; - - retval = get_user_cpu_mask(user_mask_ptr, len, new_mask); - if (retval == 0) - retval = sched_setaffinity(pid, new_mask); - free_cpumask_var(new_mask); - return retval; -} - -long sched_getaffinity(pid_t pid, struct cpumask *mask) -{ - struct task_struct *p; - unsigned long flags; - int retval; - - rcu_read_lock(); - - retval = -ESRCH; - p = find_process_by_pid(pid); - if (!p) - goto out_unlock; - - retval = security_task_getscheduler(p); - if (retval) - goto out_unlock; - - raw_spin_lock_irqsave(&p->pi_lock, flags); - cpumask_and(mask, &p->cpus_allowed, cpu_active_mask); - raw_spin_unlock_irqrestore(&p->pi_lock, flags); - -out_unlock: - rcu_read_unlock(); - - return retval; -} - -/** - * sys_sched_getaffinity - get the cpu affinity of a process - * @pid: pid of the process - * @len: length in bytes of the bitmask pointed to by user_mask_ptr - * @user_mask_ptr: user-space pointer to hold the current cpu mask - * - * Return: size of CPU mask copied to user_mask_ptr on success. An - * error code otherwise. - */ -SYSCALL_DEFINE3(sched_getaffinity, pid_t, pid, unsigned int, len, - unsigned long __user *, user_mask_ptr) -{ - int ret; - cpumask_var_t mask; - - if ((len * BITS_PER_BYTE) < nr_cpu_ids) - return -EINVAL; - if (len & (sizeof(unsigned long)-1)) - return -EINVAL; - - if (!alloc_cpumask_var(&mask, GFP_KERNEL)) - return -ENOMEM; - - ret = sched_getaffinity(pid, mask); - if (ret == 0) { - size_t retlen = min_t(size_t, len, cpumask_size()); - - if (copy_to_user(user_mask_ptr, mask, retlen)) - ret = -EFAULT; - else - ret = retlen; - } - free_cpumask_var(mask); - - return ret; -} - -/** - * sys_sched_yield - yield the current processor to other threads. - * - * This function yields the current CPU to other tasks. If there are no - * other threads running on this CPU then this function will return. - * - * Return: 0. - */ -SYSCALL_DEFINE0(sched_yield) -{ - struct rq *rq = this_rq_lock(); - - schedstat_inc(rq->yld_count); - current->sched_class->yield_task(rq); - - /* - * Since we are going to call schedule() anyway, there's - * no need to preempt or enable interrupts: - */ - __release(rq->lock); - spin_release(&rq->lock.dep_map, 1, _THIS_IP_); - do_raw_spin_unlock(&rq->lock); - sched_preempt_enable_no_resched(); - - schedule(); - - return 0; -} - -#ifndef CONFIG_PREEMPT -int __sched _cond_resched(void) -{ - if (should_resched(0)) { - preempt_schedule_common(); - return 1; - } - return 0; -} -EXPORT_SYMBOL(_cond_resched); -#endif - -/* - * __cond_resched_lock() - if a reschedule is pending, drop the given lock, - * call schedule, and on return reacquire the lock. - * - * This works OK both with and without CONFIG_PREEMPT. We do strange low-level - * operations here to prevent schedule() from being called twice (once via - * spin_unlock(), once by hand). - */ -int __cond_resched_lock(spinlock_t *lock) -{ - int resched = should_resched(PREEMPT_LOCK_OFFSET); - int ret = 0; - - lockdep_assert_held(lock); - - if (spin_needbreak(lock) || resched) { - spin_unlock(lock); - if (resched) - preempt_schedule_common(); - else - cpu_relax(); - ret = 1; - spin_lock(lock); - } - return ret; -} -EXPORT_SYMBOL(__cond_resched_lock); - -int __sched __cond_resched_softirq(void) -{ - BUG_ON(!in_softirq()); - - if (should_resched(SOFTIRQ_DISABLE_OFFSET)) { - local_bh_enable(); - preempt_schedule_common(); - local_bh_disable(); - return 1; - } - return 0; -} -EXPORT_SYMBOL(__cond_resched_softirq); - -/** - * yield - yield the current processor to other threads. - * - * Do not ever use this function, there's a 99% chance you're doing it wrong. - * - * The scheduler is at all times free to pick the calling task as the most - * eligible task to run, if removing the yield() call from your code breaks - * it, its already broken. - * - * Typical broken usage is: - * - * while (!event) - * yield(); - * - * where one assumes that yield() will let 'the other' process run that will - * make event true. If the current task is a SCHED_FIFO task that will never - * happen. Never use yield() as a progress guarantee!! - * - * If you want to use yield() to wait for something, use wait_event(). - * If you want to use yield() to be 'nice' for others, use cond_resched(). - * If you still want to use yield(), do not! - */ -void __sched yield(void) -{ - set_current_state(TASK_RUNNING); - sys_sched_yield(); -} -EXPORT_SYMBOL(yield); - -/** - * yield_to - yield the current processor to another thread in - * your thread group, or accelerate that thread toward the - * processor it's on. - * @p: target task - * @preempt: whether task preemption is allowed or not - * - * It's the caller's job to ensure that the target task struct - * can't go away on us before we can do any checks. - * - * Return: - * true (>0) if we indeed boosted the target task. - * false (0) if we failed to boost the target. - * -ESRCH if there's no task to yield to. - */ -int __sched yield_to(struct task_struct *p, bool preempt) -{ - struct task_struct *curr = current; - struct rq *rq, *p_rq; - unsigned long flags; - int yielded = 0; - - local_irq_save(flags); - rq = this_rq(); - -again: - p_rq = task_rq(p); - /* - * If we're the only runnable task on the rq and target rq also - * has only one task, there's absolutely no point in yielding. - */ - if (rq->nr_running == 1 && p_rq->nr_running == 1) { - yielded = -ESRCH; - goto out_irq; - } - - double_rq_lock(rq, p_rq); - if (task_rq(p) != p_rq) { - double_rq_unlock(rq, p_rq); - goto again; - } - - if (!curr->sched_class->yield_to_task) - goto out_unlock; - - if (curr->sched_class != p->sched_class) - goto out_unlock; - - if (task_running(p_rq, p) || p->state) - goto out_unlock; - - yielded = curr->sched_class->yield_to_task(rq, p, preempt); - if (yielded) { - schedstat_inc(rq->yld_count); - /* - * Make p's CPU reschedule; pick_next_entity takes care of - * fairness. - */ - if (preempt && rq != p_rq) - resched_curr(p_rq); - } - -out_unlock: - double_rq_unlock(rq, p_rq); -out_irq: - local_irq_restore(flags); - - if (yielded > 0) - schedule(); - - return yielded; -} -EXPORT_SYMBOL_GPL(yield_to); - -/* - * This task is about to go to sleep on IO. Increment rq->nr_iowait so - * that process accounting knows that this is a task in IO wait state. - */ -long __sched io_schedule_timeout(long timeout) -{ - int old_iowait = current->in_iowait; - struct rq *rq; - long ret; - - current->in_iowait = 1; - blk_schedule_flush_plug(current); - - delayacct_blkio_start(); - rq = raw_rq(); - atomic_inc(&rq->nr_iowait); - ret = schedule_timeout(timeout); - current->in_iowait = old_iowait; - atomic_dec(&rq->nr_iowait); - delayacct_blkio_end(); - - return ret; -} -EXPORT_SYMBOL(io_schedule_timeout); - -/** - * sys_sched_get_priority_max - return maximum RT priority. - * @policy: scheduling class. - * - * Return: On success, this syscall returns the maximum - * rt_priority that can be used by a given scheduling class. - * On failure, a negative error code is returned. - */ -SYSCALL_DEFINE1(sched_get_priority_max, int, policy) -{ - int ret = -EINVAL; - - switch (policy) { - case SCHED_FIFO: - case SCHED_RR: - ret = MAX_USER_RT_PRIO-1; - break; - case SCHED_DEADLINE: - case SCHED_NORMAL: - case SCHED_BATCH: - case SCHED_IDLE: - ret = 0; - break; - } - return ret; -} - -/** - * sys_sched_get_priority_min - return minimum RT priority. - * @policy: scheduling class. - * - * Return: On success, this syscall returns the minimum - * rt_priority that can be used by a given scheduling class. - * On failure, a negative error code is returned. - */ -SYSCALL_DEFINE1(sched_get_priority_min, int, policy) -{ - int ret = -EINVAL; - - switch (policy) { - case SCHED_FIFO: - case SCHED_RR: - ret = 1; - break; - case SCHED_DEADLINE: - case SCHED_NORMAL: - case SCHED_BATCH: - case SCHED_IDLE: - ret = 0; - } - return ret; -} - -/** - * sys_sched_rr_get_interval - return the default timeslice of a process. - * @pid: pid of the process. - * @interval: userspace pointer to the timeslice value. - * - * this syscall writes the default timeslice value of a given process - * into the user-space timespec buffer. A value of '0' means infinity. - * - * Return: On success, 0 and the timeslice is in @interval. Otherwise, - * an error code. - */ -SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid, - struct timespec __user *, interval) -{ - struct task_struct *p; - unsigned int time_slice; - struct rq_flags rf; - struct timespec t; - struct rq *rq; - int retval; - - if (pid < 0) - return -EINVAL; - - retval = -ESRCH; - rcu_read_lock(); - p = find_process_by_pid(pid); - if (!p) - goto out_unlock; - - retval = security_task_getscheduler(p); - if (retval) - goto out_unlock; - - rq = task_rq_lock(p, &rf); - time_slice = 0; - if (p->sched_class->get_rr_interval) - time_slice = p->sched_class->get_rr_interval(rq, p); - task_rq_unlock(rq, p, &rf); - - rcu_read_unlock(); - jiffies_to_timespec(time_slice, &t); - retval = copy_to_user(interval, &t, sizeof(t)) ? -EFAULT : 0; - return retval; - -out_unlock: - rcu_read_unlock(); - return retval; -} - -static const char stat_nam[] = TASK_STATE_TO_CHAR_STR; - -void sched_show_task(struct task_struct *p) -{ - unsigned long free = 0; - int ppid; - unsigned long state = p->state; - - if (!try_get_task_stack(p)) - return; - if (state) - state = __ffs(state) + 1; - printk(KERN_INFO "%-15.15s %c", p->comm, - state < sizeof(stat_nam) - 1 ? stat_nam[state] : '?'); - if (state == TASK_RUNNING) - printk(KERN_CONT " running task "); -#ifdef CONFIG_DEBUG_STACK_USAGE - free = stack_not_used(p); -#endif - ppid = 0; - rcu_read_lock(); - if (pid_alive(p)) - ppid = task_pid_nr(rcu_dereference(p->real_parent)); - rcu_read_unlock(); - printk(KERN_CONT "%5lu %5d %6d 0x%08lx\n", free, - task_pid_nr(p), ppid, - (unsigned long)task_thread_info(p)->flags); - - print_worker_info(KERN_INFO, p); - show_stack(p, NULL); - put_task_stack(p); -} - -void show_state_filter(unsigned long state_filter) -{ - struct task_struct *g, *p; - -#if BITS_PER_LONG == 32 - printk(KERN_INFO - " task PC stack pid father\n"); -#else - printk(KERN_INFO - " task PC stack pid father\n"); -#endif - rcu_read_lock(); - for_each_process_thread(g, p) { - /* - * reset the NMI-timeout, listing all files on a slow - * console might take a lot of time: - * Also, reset softlockup watchdogs on all CPUs, because - * another CPU might be blocked waiting for us to process - * an IPI. - */ - touch_nmi_watchdog(); - touch_all_softlockup_watchdogs(); - if (!state_filter || (p->state & state_filter)) - sched_show_task(p); - } - -#ifdef CONFIG_SCHED_DEBUG - if (!state_filter) - sysrq_sched_debug_show(); -#endif - rcu_read_unlock(); - /* - * Only show locks if all tasks are dumped: - */ - if (!state_filter) - debug_show_all_locks(); -} - -void init_idle_bootup_task(struct task_struct *idle) -{ - idle->sched_class = &idle_sched_class; -} - -/** - * init_idle - set up an idle thread for a given CPU - * @idle: task in question - * @cpu: cpu the idle task belongs to - * - * NOTE: this function does not set the idle thread's NEED_RESCHED - * flag, to make booting more robust. - */ -void init_idle(struct task_struct *idle, int cpu) -{ - struct rq *rq = cpu_rq(cpu); - unsigned long flags; - - raw_spin_lock_irqsave(&idle->pi_lock, flags); - raw_spin_lock(&rq->lock); - - __sched_fork(0, idle); - idle->state = TASK_RUNNING; - idle->se.exec_start = sched_clock(); - - kasan_unpoison_task_stack(idle); - -#ifdef CONFIG_SMP - /* - * Its possible that init_idle() gets called multiple times on a task, - * in that case do_set_cpus_allowed() will not do the right thing. - * - * And since this is boot we can forgo the serialization. - */ - set_cpus_allowed_common(idle, cpumask_of(cpu)); -#endif - /* - * We're having a chicken and egg problem, even though we are - * holding rq->lock, the cpu isn't yet set to this cpu so the - * lockdep check in task_group() will fail. - * - * Similar case to sched_fork(). / Alternatively we could - * use task_rq_lock() here and obtain the other rq->lock. - * - * Silence PROVE_RCU - */ - rcu_read_lock(); - __set_task_cpu(idle, cpu); - rcu_read_unlock(); - - rq->curr = rq->idle = idle; - idle->on_rq = TASK_ON_RQ_QUEUED; -#ifdef CONFIG_SMP - idle->on_cpu = 1; -#endif - raw_spin_unlock(&rq->lock); - raw_spin_unlock_irqrestore(&idle->pi_lock, flags); - - /* Set the preempt count _outside_ the spinlocks! */ - init_idle_preempt_count(idle, cpu); - - /* - * The idle tasks have their own, simple scheduling class: - */ - idle->sched_class = &idle_sched_class; - ftrace_graph_init_idle_task(idle, cpu); - vtime_init_idle(idle, cpu); -#ifdef CONFIG_SMP - sprintf(idle->comm, "%s/%d", INIT_TASK_COMM, cpu); -#endif -} - -int cpuset_cpumask_can_shrink(const struct cpumask *cur, - const struct cpumask *trial) -{ - int ret = 1, trial_cpus; - struct dl_bw *cur_dl_b; - unsigned long flags; - - if (!cpumask_weight(cur)) - return ret; - - rcu_read_lock_sched(); - cur_dl_b = dl_bw_of(cpumask_any(cur)); - trial_cpus = cpumask_weight(trial); - - raw_spin_lock_irqsave(&cur_dl_b->lock, flags); - if (cur_dl_b->bw != -1 && - cur_dl_b->bw * trial_cpus < cur_dl_b->total_bw) - ret = 0; - raw_spin_unlock_irqrestore(&cur_dl_b->lock, flags); - rcu_read_unlock_sched(); - - return ret; -} - -int task_can_attach(struct task_struct *p, - const struct cpumask *cs_cpus_allowed) -{ - int ret = 0; - - /* - * Kthreads which disallow setaffinity shouldn't be moved - * to a new cpuset; we don't want to change their cpu - * affinity and isolating such threads by their set of - * allowed nodes is unnecessary. Thus, cpusets are not - * applicable for such threads. This prevents checking for - * success of set_cpus_allowed_ptr() on all attached tasks - * before cpus_allowed may be changed. - */ - if (p->flags & PF_NO_SETAFFINITY) { - ret = -EINVAL; - goto out; - } - -#ifdef CONFIG_SMP - if (dl_task(p) && !cpumask_intersects(task_rq(p)->rd->span, - cs_cpus_allowed)) { - unsigned int dest_cpu = cpumask_any_and(cpu_active_mask, - cs_cpus_allowed); - struct dl_bw *dl_b; - bool overflow; - int cpus; - unsigned long flags; - - rcu_read_lock_sched(); - dl_b = dl_bw_of(dest_cpu); - raw_spin_lock_irqsave(&dl_b->lock, flags); - cpus = dl_bw_cpus(dest_cpu); - overflow = __dl_overflow(dl_b, cpus, 0, p->dl.dl_bw); - if (overflow) - ret = -EBUSY; - else { - /* - * We reserve space for this task in the destination - * root_domain, as we can't fail after this point. - * We will free resources in the source root_domain - * later on (see set_cpus_allowed_dl()). - */ - __dl_add(dl_b, p->dl.dl_bw); - } - raw_spin_unlock_irqrestore(&dl_b->lock, flags); - rcu_read_unlock_sched(); - - } -#endif -out: - return ret; -} - -#ifdef CONFIG_SMP - -static bool sched_smp_initialized __read_mostly; - -#ifdef CONFIG_NUMA_BALANCING -/* Migrate current task p to target_cpu */ -int migrate_task_to(struct task_struct *p, int target_cpu) -{ - struct migration_arg arg = { p, target_cpu }; - int curr_cpu = task_cpu(p); - - if (curr_cpu == target_cpu) - return 0; - - if (!cpumask_test_cpu(target_cpu, tsk_cpus_allowed(p))) - return -EINVAL; - - /* TODO: This is not properly updating schedstats */ - - trace_sched_move_numa(p, curr_cpu, target_cpu); - return stop_one_cpu(curr_cpu, migration_cpu_stop, &arg); -} - -/* - * Requeue a task on a given node and accurately track the number of NUMA - * tasks on the runqueues - */ -void sched_setnuma(struct task_struct *p, int nid) -{ - bool queued, running; - struct rq_flags rf; - struct rq *rq; - - rq = task_rq_lock(p, &rf); - queued = task_on_rq_queued(p); - running = task_current(rq, p); - - if (queued) - dequeue_task(rq, p, DEQUEUE_SAVE); - if (running) - put_prev_task(rq, p); - - p->numa_preferred_nid = nid; - - if (queued) - enqueue_task(rq, p, ENQUEUE_RESTORE); - if (running) - set_curr_task(rq, p); - task_rq_unlock(rq, p, &rf); -} -#endif /* CONFIG_NUMA_BALANCING */ - -#ifdef CONFIG_HOTPLUG_CPU -/* - * Ensures that the idle task is using init_mm right before its cpu goes - * offline. - */ -void idle_task_exit(void) -{ - struct mm_struct *mm = current->active_mm; - - BUG_ON(cpu_online(smp_processor_id())); - - if (mm != &init_mm) { - switch_mm_irqs_off(mm, &init_mm, current); - finish_arch_post_lock_switch(); - } - mmdrop(mm); -} - -/* - * Since this CPU is going 'away' for a while, fold any nr_active delta - * we might have. Assumes we're called after migrate_tasks() so that the - * nr_active count is stable. We need to take the teardown thread which - * is calling this into account, so we hand in adjust = 1 to the load - * calculation. - * - * Also see the comment "Global load-average calculations". - */ -static void calc_load_migrate(struct rq *rq) -{ - long delta = calc_load_fold_active(rq, 1); - if (delta) - atomic_long_add(delta, &calc_load_tasks); -} - -static void put_prev_task_fake(struct rq *rq, struct task_struct *prev) -{ -} - -static const struct sched_class fake_sched_class = { - .put_prev_task = put_prev_task_fake, -}; - -static struct task_struct fake_task = { - /* - * Avoid pull_{rt,dl}_task() - */ - .prio = MAX_PRIO + 1, - .sched_class = &fake_sched_class, -}; - -/* - * Migrate all tasks from the rq, sleeping tasks will be migrated by - * try_to_wake_up()->select_task_rq(). - * - * Called with rq->lock held even though we'er in stop_machine() and - * there's no concurrency possible, we hold the required locks anyway - * because of lock validation efforts. - */ -static void migrate_tasks(struct rq *dead_rq) -{ - struct rq *rq = dead_rq; - struct task_struct *next, *stop = rq->stop; - struct pin_cookie cookie; - int dest_cpu; - - /* - * Fudge the rq selection such that the below task selection loop - * doesn't get stuck on the currently eligible stop task. - * - * We're currently inside stop_machine() and the rq is either stuck - * in the stop_machine_cpu_stop() loop, or we're executing this code, - * either way we should never end up calling schedule() until we're - * done here. - */ - rq->stop = NULL; - - /* - * put_prev_task() and pick_next_task() sched - * class method both need to have an up-to-date - * value of rq->clock[_task] - */ - update_rq_clock(rq); - - for (;;) { - /* - * There's this thread running, bail when that's the only - * remaining thread. - */ - if (rq->nr_running == 1) - break; - - /* - * pick_next_task assumes pinned rq->lock. - */ - cookie = lockdep_pin_lock(&rq->lock); - next = pick_next_task(rq, &fake_task, cookie); - BUG_ON(!next); - next->sched_class->put_prev_task(rq, next); - - /* - * Rules for changing task_struct::cpus_allowed are holding - * both pi_lock and rq->lock, such that holding either - * stabilizes the mask. - * - * Drop rq->lock is not quite as disastrous as it usually is - * because !cpu_active at this point, which means load-balance - * will not interfere. Also, stop-machine. - */ - lockdep_unpin_lock(&rq->lock, cookie); - raw_spin_unlock(&rq->lock); - raw_spin_lock(&next->pi_lock); - raw_spin_lock(&rq->lock); - - /* - * Since we're inside stop-machine, _nothing_ should have - * changed the task, WARN if weird stuff happened, because in - * that case the above rq->lock drop is a fail too. - */ - if (WARN_ON(task_rq(next) != rq || !task_on_rq_queued(next))) { - raw_spin_unlock(&next->pi_lock); - continue; - } - - /* Find suitable destination for @next, with force if needed. */ - dest_cpu = select_fallback_rq(dead_rq->cpu, next); - - rq = __migrate_task(rq, next, dest_cpu); - if (rq != dead_rq) { - raw_spin_unlock(&rq->lock); - rq = dead_rq; - raw_spin_lock(&rq->lock); - } - raw_spin_unlock(&next->pi_lock); - } - - rq->stop = stop; -} -#endif /* CONFIG_HOTPLUG_CPU */ - -static void set_rq_online(struct rq *rq) -{ - if (!rq->online) { - const struct sched_class *class; - - cpumask_set_cpu(rq->cpu, rq->rd->online); - rq->online = 1; - - for_each_class(class) { - if (class->rq_online) - class->rq_online(rq); - } - } -} - -static void set_rq_offline(struct rq *rq) -{ - if (rq->online) { - const struct sched_class *class; - - for_each_class(class) { - if (class->rq_offline) - class->rq_offline(rq); - } - - cpumask_clear_cpu(rq->cpu, rq->rd->online); - rq->online = 0; - } -} - -static void set_cpu_rq_start_time(unsigned int cpu) -{ - struct rq *rq = cpu_rq(cpu); - - rq->age_stamp = sched_clock_cpu(cpu); -} - -static cpumask_var_t sched_domains_tmpmask; /* sched_domains_mutex */ - -#ifdef CONFIG_SCHED_DEBUG - -static __read_mostly int sched_debug_enabled; - -static int __init sched_debug_setup(char *str) -{ - sched_debug_enabled = 1; - - return 0; -} -early_param("sched_debug", sched_debug_setup); - -static inline bool sched_debug(void) -{ - return sched_debug_enabled; -} - -static int sched_domain_debug_one(struct sched_domain *sd, int cpu, int level, - struct cpumask *groupmask) -{ - struct sched_group *group = sd->groups; - - cpumask_clear(groupmask); - - printk(KERN_DEBUG "%*s domain %d: ", level, "", level); - - if (!(sd->flags & SD_LOAD_BALANCE)) { - printk("does not load-balance\n"); - if (sd->parent) - printk(KERN_ERR "ERROR: !SD_LOAD_BALANCE domain" - " has parent"); - return -1; - } - - printk(KERN_CONT "span %*pbl level %s\n", - cpumask_pr_args(sched_domain_span(sd)), sd->name); - - if (!cpumask_test_cpu(cpu, sched_domain_span(sd))) { - printk(KERN_ERR "ERROR: domain->span does not contain " - "CPU%d\n", cpu); - } - if (!cpumask_test_cpu(cpu, sched_group_cpus(group))) { - printk(KERN_ERR "ERROR: domain->groups does not contain" - " CPU%d\n", cpu); - } - - printk(KERN_DEBUG "%*s groups:", level + 1, ""); - do { - if (!group) { - printk("\n"); - printk(KERN_ERR "ERROR: group is NULL\n"); - break; - } - - if (!cpumask_weight(sched_group_cpus(group))) { - printk(KERN_CONT "\n"); - printk(KERN_ERR "ERROR: empty group\n"); - break; - } - - if (!(sd->flags & SD_OVERLAP) && - cpumask_intersects(groupmask, sched_group_cpus(group))) { - printk(KERN_CONT "\n"); - printk(KERN_ERR "ERROR: repeated CPUs\n"); - break; - } - - cpumask_or(groupmask, groupmask, sched_group_cpus(group)); - - printk(KERN_CONT " %*pbl", - cpumask_pr_args(sched_group_cpus(group))); - if (group->sgc->capacity != SCHED_CAPACITY_SCALE) { - printk(KERN_CONT " (cpu_capacity = %d)", - group->sgc->capacity); - } - - group = group->next; - } while (group != sd->groups); - printk(KERN_CONT "\n"); - - if (!cpumask_equal(sched_domain_span(sd), groupmask)) - printk(KERN_ERR "ERROR: groups don't span domain->span\n"); - - if (sd->parent && - !cpumask_subset(groupmask, sched_domain_span(sd->parent))) - printk(KERN_ERR "ERROR: parent span is not a superset " - "of domain->span\n"); - return 0; -} - -static void sched_domain_debug(struct sched_domain *sd, int cpu) -{ - int level = 0; - - if (!sched_debug_enabled) - return; - - if (!sd) { - printk(KERN_DEBUG "CPU%d attaching NULL sched-domain.\n", cpu); - return; - } - - printk(KERN_DEBUG "CPU%d attaching sched-domain:\n", cpu); - - for (;;) { - if (sched_domain_debug_one(sd, cpu, level, sched_domains_tmpmask)) - break; - level++; - sd = sd->parent; - if (!sd) - break; - } -} -#else /* !CONFIG_SCHED_DEBUG */ - -# define sched_debug_enabled 0 -# define sched_domain_debug(sd, cpu) do { } while (0) -static inline bool sched_debug(void) -{ - return false; -} -#endif /* CONFIG_SCHED_DEBUG */ - -static int sd_degenerate(struct sched_domain *sd) -{ - if (cpumask_weight(sched_domain_span(sd)) == 1) - return 1; - - /* Following flags need at least 2 groups */ - if (sd->flags & (SD_LOAD_BALANCE | - SD_BALANCE_NEWIDLE | - SD_BALANCE_FORK | - SD_BALANCE_EXEC | - SD_SHARE_CPUCAPACITY | - SD_ASYM_CPUCAPACITY | - SD_SHARE_PKG_RESOURCES | - SD_SHARE_POWERDOMAIN)) { - if (sd->groups != sd->groups->next) - return 0; - } - - /* Following flags don't use groups */ - if (sd->flags & (SD_WAKE_AFFINE)) - return 0; - - return 1; -} - -static int -sd_parent_degenerate(struct sched_domain *sd, struct sched_domain *parent) -{ - unsigned long cflags = sd->flags, pflags = parent->flags; - - if (sd_degenerate(parent)) - return 1; - - if (!cpumask_equal(sched_domain_span(sd), sched_domain_span(parent))) - return 0; - - /* Flags needing groups don't count if only 1 group in parent */ - if (parent->groups == parent->groups->next) { - pflags &= ~(SD_LOAD_BALANCE | - SD_BALANCE_NEWIDLE | - SD_BALANCE_FORK | - SD_BALANCE_EXEC | - SD_ASYM_CPUCAPACITY | - SD_SHARE_CPUCAPACITY | - SD_SHARE_PKG_RESOURCES | - SD_PREFER_SIBLING | - SD_SHARE_POWERDOMAIN); - if (nr_node_ids == 1) - pflags &= ~SD_SERIALIZE; - } - if (~cflags & pflags) - return 0; - - return 1; -} - -static void free_rootdomain(struct rcu_head *rcu) -{ - struct root_domain *rd = container_of(rcu, struct root_domain, rcu); - - cpupri_cleanup(&rd->cpupri); - cpudl_cleanup(&rd->cpudl); - free_cpumask_var(rd->dlo_mask); - free_cpumask_var(rd->rto_mask); - free_cpumask_var(rd->online); - free_cpumask_var(rd->span); - kfree(rd); -} - -static void rq_attach_root(struct rq *rq, struct root_domain *rd) -{ - struct root_domain *old_rd = NULL; - unsigned long flags; - - raw_spin_lock_irqsave(&rq->lock, flags); - - if (rq->rd) { - old_rd = rq->rd; - - if (cpumask_test_cpu(rq->cpu, old_rd->online)) - set_rq_offline(rq); - - cpumask_clear_cpu(rq->cpu, old_rd->span); - - /* - * If we dont want to free the old_rd yet then - * set old_rd to NULL to skip the freeing later - * in this function: - */ - if (!atomic_dec_and_test(&old_rd->refcount)) - old_rd = NULL; - } - - atomic_inc(&rd->refcount); - rq->rd = rd; - - cpumask_set_cpu(rq->cpu, rd->span); - if (cpumask_test_cpu(rq->cpu, cpu_active_mask)) - set_rq_online(rq); - - raw_spin_unlock_irqrestore(&rq->lock, flags); - - if (old_rd) - call_rcu_sched(&old_rd->rcu, free_rootdomain); -} - -static int init_rootdomain(struct root_domain *rd) -{ - memset(rd, 0, sizeof(*rd)); - - if (!zalloc_cpumask_var(&rd->span, GFP_KERNEL)) - goto out; - if (!zalloc_cpumask_var(&rd->online, GFP_KERNEL)) - goto free_span; - if (!zalloc_cpumask_var(&rd->dlo_mask, GFP_KERNEL)) - goto free_online; - if (!zalloc_cpumask_var(&rd->rto_mask, GFP_KERNEL)) - goto free_dlo_mask; - - init_dl_bw(&rd->dl_bw); - if (cpudl_init(&rd->cpudl) != 0) - goto free_dlo_mask; - - if (cpupri_init(&rd->cpupri) != 0) - goto free_rto_mask; - return 0; - -free_rto_mask: - free_cpumask_var(rd->rto_mask); -free_dlo_mask: - free_cpumask_var(rd->dlo_mask); -free_online: - free_cpumask_var(rd->online); -free_span: - free_cpumask_var(rd->span); -out: - return -ENOMEM; -} - -/* - * By default the system creates a single root-domain with all cpus as - * members (mimicking the global state we have today). - */ -struct root_domain def_root_domain; - -static void init_defrootdomain(void) -{ - init_rootdomain(&def_root_domain); - - atomic_set(&def_root_domain.refcount, 1); -} - -static struct root_domain *alloc_rootdomain(void) -{ - struct root_domain *rd; - - rd = kmalloc(sizeof(*rd), GFP_KERNEL); - if (!rd) - return NULL; - - if (init_rootdomain(rd) != 0) { - kfree(rd); - return NULL; - } - - return rd; -} - -static void free_sched_groups(struct sched_group *sg, int free_sgc) -{ - struct sched_group *tmp, *first; - - if (!sg) - return; - - first = sg; - do { - tmp = sg->next; - - if (free_sgc && atomic_dec_and_test(&sg->sgc->ref)) - kfree(sg->sgc); - - kfree(sg); - sg = tmp; - } while (sg != first); -} - -static void destroy_sched_domain(struct sched_domain *sd) -{ - /* - * If its an overlapping domain it has private groups, iterate and - * nuke them all. - */ - if (sd->flags & SD_OVERLAP) { - free_sched_groups(sd->groups, 1); - } else if (atomic_dec_and_test(&sd->groups->ref)) { - kfree(sd->groups->sgc); - kfree(sd->groups); - } - if (sd->shared && atomic_dec_and_test(&sd->shared->ref)) - kfree(sd->shared); - kfree(sd); -} - -static void destroy_sched_domains_rcu(struct rcu_head *rcu) -{ - struct sched_domain *sd = container_of(rcu, struct sched_domain, rcu); - - while (sd) { - struct sched_domain *parent = sd->parent; - destroy_sched_domain(sd); - sd = parent; - } -} - -static void destroy_sched_domains(struct sched_domain *sd) -{ - if (sd) - call_rcu(&sd->rcu, destroy_sched_domains_rcu); -} - -/* - * Keep a special pointer to the highest sched_domain that has - * SD_SHARE_PKG_RESOURCE set (Last Level Cache Domain) for this - * allows us to avoid some pointer chasing select_idle_sibling(). - * - * Also keep a unique ID per domain (we use the first cpu number in - * the cpumask of the domain), this allows us to quickly tell if - * two cpus are in the same cache domain, see cpus_share_cache(). - */ -DEFINE_PER_CPU(struct sched_domain *, sd_llc); -DEFINE_PER_CPU(int, sd_llc_size); -DEFINE_PER_CPU(int, sd_llc_id); -DEFINE_PER_CPU(struct sched_domain_shared *, sd_llc_shared); -DEFINE_PER_CPU(struct sched_domain *, sd_numa); -DEFINE_PER_CPU(struct sched_domain *, sd_asym); - -static void update_top_cache_domain(int cpu) -{ - struct sched_domain_shared *sds = NULL; - struct sched_domain *sd; - int id = cpu; - int size = 1; - - sd = highest_flag_domain(cpu, SD_SHARE_PKG_RESOURCES); - if (sd) { - id = cpumask_first(sched_domain_span(sd)); - size = cpumask_weight(sched_domain_span(sd)); - sds = sd->shared; - } - - rcu_assign_pointer(per_cpu(sd_llc, cpu), sd); - per_cpu(sd_llc_size, cpu) = size; - per_cpu(sd_llc_id, cpu) = id; - rcu_assign_pointer(per_cpu(sd_llc_shared, cpu), sds); - - sd = lowest_flag_domain(cpu, SD_NUMA); - rcu_assign_pointer(per_cpu(sd_numa, cpu), sd); - - sd = highest_flag_domain(cpu, SD_ASYM_PACKING); - rcu_assign_pointer(per_cpu(sd_asym, cpu), sd); -} - -/* - * Attach the domain 'sd' to 'cpu' as its base domain. Callers must - * hold the hotplug lock. - */ -static void -cpu_attach_domain(struct sched_domain *sd, struct root_domain *rd, int cpu) -{ - struct rq *rq = cpu_rq(cpu); - struct sched_domain *tmp; - - /* Remove the sched domains which do not contribute to scheduling. */ - for (tmp = sd; tmp; ) { - struct sched_domain *parent = tmp->parent; - if (!parent) - break; - - if (sd_parent_degenerate(tmp, parent)) { - tmp->parent = parent->parent; - if (parent->parent) - parent->parent->child = tmp; - /* - * Transfer SD_PREFER_SIBLING down in case of a - * degenerate parent; the spans match for this - * so the property transfers. - */ - if (parent->flags & SD_PREFER_SIBLING) - tmp->flags |= SD_PREFER_SIBLING; - destroy_sched_domain(parent); - } else - tmp = tmp->parent; - } - - if (sd && sd_degenerate(sd)) { - tmp = sd; - sd = sd->parent; - destroy_sched_domain(tmp); - if (sd) - sd->child = NULL; - } - - sched_domain_debug(sd, cpu); - - rq_attach_root(rq, rd); - tmp = rq->sd; - rcu_assign_pointer(rq->sd, sd); - destroy_sched_domains(tmp); - - update_top_cache_domain(cpu); -} - -/* Setup the mask of cpus configured for isolated domains */ -static int __init isolated_cpu_setup(char *str) -{ - int ret; - - alloc_bootmem_cpumask_var(&cpu_isolated_map); - ret = cpulist_parse(str, cpu_isolated_map); - if (ret) { - pr_err("sched: Error, all isolcpus= values must be between 0 and %d\n", nr_cpu_ids); - return 0; - } - return 1; -} -__setup("isolcpus=", isolated_cpu_setup); - -struct s_data { - struct sched_domain ** __percpu sd; - struct root_domain *rd; -}; - -enum s_alloc { - sa_rootdomain, - sa_sd, - sa_sd_storage, - sa_none, -}; - -/* - * Build an iteration mask that can exclude certain CPUs from the upwards - * domain traversal. - * - * Asymmetric node setups can result in situations where the domain tree is of - * unequal depth, make sure to skip domains that already cover the entire - * range. - * - * In that case build_sched_domains() will have terminated the iteration early - * and our sibling sd spans will be empty. Domains should always include the - * cpu they're built on, so check that. - * - */ -static void build_group_mask(struct sched_domain *sd, struct sched_group *sg) -{ - const struct cpumask *span = sched_domain_span(sd); - struct sd_data *sdd = sd->private; - struct sched_domain *sibling; - int i; - - for_each_cpu(i, span) { - sibling = *per_cpu_ptr(sdd->sd, i); - if (!cpumask_test_cpu(i, sched_domain_span(sibling))) - continue; - - cpumask_set_cpu(i, sched_group_mask(sg)); - } -} - -/* - * Return the canonical balance cpu for this group, this is the first cpu - * of this group that's also in the iteration mask. - */ -int group_balance_cpu(struct sched_group *sg) -{ - return cpumask_first_and(sched_group_cpus(sg), sched_group_mask(sg)); -} - -static int -build_overlap_sched_groups(struct sched_domain *sd, int cpu) -{ - struct sched_group *first = NULL, *last = NULL, *groups = NULL, *sg; - const struct cpumask *span = sched_domain_span(sd); - struct cpumask *covered = sched_domains_tmpmask; - struct sd_data *sdd = sd->private; - struct sched_domain *sibling; - int i; - - cpumask_clear(covered); - - for_each_cpu(i, span) { - struct cpumask *sg_span; - - if (cpumask_test_cpu(i, covered)) - continue; - - sibling = *per_cpu_ptr(sdd->sd, i); - - /* See the comment near build_group_mask(). */ - if (!cpumask_test_cpu(i, sched_domain_span(sibling))) - continue; - - sg = kzalloc_node(sizeof(struct sched_group) + cpumask_size(), - GFP_KERNEL, cpu_to_node(cpu)); - - if (!sg) - goto fail; - - sg_span = sched_group_cpus(sg); - if (sibling->child) - cpumask_copy(sg_span, sched_domain_span(sibling->child)); - else - cpumask_set_cpu(i, sg_span); - - cpumask_or(covered, covered, sg_span); - - sg->sgc = *per_cpu_ptr(sdd->sgc, i); - if (atomic_inc_return(&sg->sgc->ref) == 1) - build_group_mask(sd, sg); - - /* - * Initialize sgc->capacity such that even if we mess up the - * domains and no possible iteration will get us here, we won't - * die on a /0 trap. - */ - sg->sgc->capacity = SCHED_CAPACITY_SCALE * cpumask_weight(sg_span); - - /* - * Make sure the first group of this domain contains the - * canonical balance cpu. Otherwise the sched_domain iteration - * breaks. See update_sg_lb_stats(). - */ - if ((!groups && cpumask_test_cpu(cpu, sg_span)) || - group_balance_cpu(sg) == cpu) - groups = sg; - - if (!first) - first = sg; - if (last) - last->next = sg; - last = sg; - last->next = first; - } - sd->groups = groups; - - return 0; - -fail: - free_sched_groups(first, 0); - - return -ENOMEM; -} - -static int get_group(int cpu, struct sd_data *sdd, struct sched_group **sg) -{ - struct sched_domain *sd = *per_cpu_ptr(sdd->sd, cpu); - struct sched_domain *child = sd->child; - - if (child) - cpu = cpumask_first(sched_domain_span(child)); - - if (sg) { - *sg = *per_cpu_ptr(sdd->sg, cpu); - (*sg)->sgc = *per_cpu_ptr(sdd->sgc, cpu); - atomic_set(&(*sg)->sgc->ref, 1); /* for claim_allocations */ - } - - return cpu; -} - -/* - * build_sched_groups will build a circular linked list of the groups - * covered by the given span, and will set each group's ->cpumask correctly, - * and ->cpu_capacity to 0. - * - * Assumes the sched_domain tree is fully constructed - */ -static int -build_sched_groups(struct sched_domain *sd, int cpu) -{ - struct sched_group *first = NULL, *last = NULL; - struct sd_data *sdd = sd->private; - const struct cpumask *span = sched_domain_span(sd); - struct cpumask *covered; - int i; - - get_group(cpu, sdd, &sd->groups); - atomic_inc(&sd->groups->ref); - - if (cpu != cpumask_first(span)) - return 0; - - lockdep_assert_held(&sched_domains_mutex); - covered = sched_domains_tmpmask; - - cpumask_clear(covered); - - for_each_cpu(i, span) { - struct sched_group *sg; - int group, j; - - if (cpumask_test_cpu(i, covered)) - continue; - - group = get_group(i, sdd, &sg); - cpumask_setall(sched_group_mask(sg)); - - for_each_cpu(j, span) { - if (get_group(j, sdd, NULL) != group) - continue; - - cpumask_set_cpu(j, covered); - cpumask_set_cpu(j, sched_group_cpus(sg)); - } - - if (!first) - first = sg; - if (last) - last->next = sg; - last = sg; - } - last->next = first; - - return 0; -} - -/* - * Initialize sched groups cpu_capacity. - * - * cpu_capacity indicates the capacity of sched group, which is used while - * distributing the load between different sched groups in a sched domain. - * Typically cpu_capacity for all the groups in a sched domain will be same - * unless there are asymmetries in the topology. If there are asymmetries, - * group having more cpu_capacity will pickup more load compared to the - * group having less cpu_capacity. - */ -static void init_sched_groups_capacity(int cpu, struct sched_domain *sd) -{ - struct sched_group *sg = sd->groups; - - WARN_ON(!sg); - - do { - sg->group_weight = cpumask_weight(sched_group_cpus(sg)); - sg = sg->next; - } while (sg != sd->groups); - - if (cpu != group_balance_cpu(sg)) - return; - - update_group_capacity(sd, cpu); -} - -/* - * Initializers for schedule domains - * Non-inlined to reduce accumulated stack pressure in build_sched_domains() - */ - -static int default_relax_domain_level = -1; -int sched_domain_level_max; - -static int __init setup_relax_domain_level(char *str) -{ - if (kstrtoint(str, 0, &default_relax_domain_level)) - pr_warn("Unable to set relax_domain_level\n"); - - return 1; -} -__setup("relax_domain_level=", setup_relax_domain_level); - -static void set_domain_attribute(struct sched_domain *sd, - struct sched_domain_attr *attr) -{ - int request; - - if (!attr || attr->relax_domain_level < 0) { - if (default_relax_domain_level < 0) - return; - else - request = default_relax_domain_level; - } else - request = attr->relax_domain_level; - if (request < sd->level) { - /* turn off idle balance on this domain */ - sd->flags &= ~(SD_BALANCE_WAKE|SD_BALANCE_NEWIDLE); - } else { - /* turn on idle balance on this domain */ - sd->flags |= (SD_BALANCE_WAKE|SD_BALANCE_NEWIDLE); - } -} - -static void __sdt_free(const struct cpumask *cpu_map); -static int __sdt_alloc(const struct cpumask *cpu_map); - -static void __free_domain_allocs(struct s_data *d, enum s_alloc what, - const struct cpumask *cpu_map) -{ - switch (what) { - case sa_rootdomain: - if (!atomic_read(&d->rd->refcount)) - free_rootdomain(&d->rd->rcu); /* fall through */ - case sa_sd: - free_percpu(d->sd); /* fall through */ - case sa_sd_storage: - __sdt_free(cpu_map); /* fall through */ - case sa_none: - break; - } -} - -static enum s_alloc __visit_domain_allocation_hell(struct s_data *d, - const struct cpumask *cpu_map) -{ - memset(d, 0, sizeof(*d)); - - if (__sdt_alloc(cpu_map)) - return sa_sd_storage; - d->sd = alloc_percpu(struct sched_domain *); - if (!d->sd) - return sa_sd_storage; - d->rd = alloc_rootdomain(); - if (!d->rd) - return sa_sd; - return sa_rootdomain; -} - -/* - * NULL the sd_data elements we've used to build the sched_domain and - * sched_group structure so that the subsequent __free_domain_allocs() - * will not free the data we're using. - */ -static void claim_allocations(int cpu, struct sched_domain *sd) -{ - struct sd_data *sdd = sd->private; - - WARN_ON_ONCE(*per_cpu_ptr(sdd->sd, cpu) != sd); - *per_cpu_ptr(sdd->sd, cpu) = NULL; - - if (atomic_read(&(*per_cpu_ptr(sdd->sds, cpu))->ref)) - *per_cpu_ptr(sdd->sds, cpu) = NULL; - - if (atomic_read(&(*per_cpu_ptr(sdd->sg, cpu))->ref)) - *per_cpu_ptr(sdd->sg, cpu) = NULL; - - if (atomic_read(&(*per_cpu_ptr(sdd->sgc, cpu))->ref)) - *per_cpu_ptr(sdd->sgc, cpu) = NULL; -} - -#ifdef CONFIG_NUMA -static int sched_domains_numa_levels; -enum numa_topology_type sched_numa_topology_type; -static int *sched_domains_numa_distance; -int sched_max_numa_distance; -static struct cpumask ***sched_domains_numa_masks; -static int sched_domains_curr_level; -#endif - -/* - * SD_flags allowed in topology descriptions. - * - * These flags are purely descriptive of the topology and do not prescribe - * behaviour. Behaviour is artificial and mapped in the below sd_init() - * function: - * - * SD_SHARE_CPUCAPACITY - describes SMT topologies - * SD_SHARE_PKG_RESOURCES - describes shared caches - * SD_NUMA - describes NUMA topologies - * SD_SHARE_POWERDOMAIN - describes shared power domain - * SD_ASYM_CPUCAPACITY - describes mixed capacity topologies - * - * Odd one out, which beside describing the topology has a quirk also - * prescribes the desired behaviour that goes along with it: - * - * SD_ASYM_PACKING - describes SMT quirks - */ -#define TOPOLOGY_SD_FLAGS \ - (SD_SHARE_CPUCAPACITY | \ - SD_SHARE_PKG_RESOURCES | \ - SD_NUMA | \ - SD_ASYM_PACKING | \ - SD_ASYM_CPUCAPACITY | \ - SD_SHARE_POWERDOMAIN) - -static struct sched_domain * -sd_init(struct sched_domain_topology_level *tl, - const struct cpumask *cpu_map, - struct sched_domain *child, int cpu) -{ - struct sd_data *sdd = &tl->data; - struct sched_domain *sd = *per_cpu_ptr(sdd->sd, cpu); - int sd_id, sd_weight, sd_flags = 0; - -#ifdef CONFIG_NUMA - /* - * Ugly hack to pass state to sd_numa_mask()... - */ - sched_domains_curr_level = tl->numa_level; -#endif - - sd_weight = cpumask_weight(tl->mask(cpu)); - - if (tl->sd_flags) - sd_flags = (*tl->sd_flags)(); - if (WARN_ONCE(sd_flags & ~TOPOLOGY_SD_FLAGS, - "wrong sd_flags in topology description\n")) - sd_flags &= ~TOPOLOGY_SD_FLAGS; - - *sd = (struct sched_domain){ - .min_interval = sd_weight, - .max_interval = 2*sd_weight, - .busy_factor = 32, - .imbalance_pct = 125, - - .cache_nice_tries = 0, - .busy_idx = 0, - .idle_idx = 0, - .newidle_idx = 0, - .wake_idx = 0, - .forkexec_idx = 0, - - .flags = 1*SD_LOAD_BALANCE - | 1*SD_BALANCE_NEWIDLE - | 1*SD_BALANCE_EXEC - | 1*SD_BALANCE_FORK - | 0*SD_BALANCE_WAKE - | 1*SD_WAKE_AFFINE - | 0*SD_SHARE_CPUCAPACITY - | 0*SD_SHARE_PKG_RESOURCES - | 0*SD_SERIALIZE - | 0*SD_PREFER_SIBLING - | 0*SD_NUMA - | sd_flags - , - - .last_balance = jiffies, - .balance_interval = sd_weight, - .smt_gain = 0, - .max_newidle_lb_cost = 0, - .next_decay_max_lb_cost = jiffies, - .child = child, -#ifdef CONFIG_SCHED_DEBUG - .name = tl->name, -#endif - }; - - cpumask_and(sched_domain_span(sd), cpu_map, tl->mask(cpu)); - sd_id = cpumask_first(sched_domain_span(sd)); - - /* - * Convert topological properties into behaviour. - */ - - if (sd->flags & SD_ASYM_CPUCAPACITY) { - struct sched_domain *t = sd; - - for_each_lower_domain(t) - t->flags |= SD_BALANCE_WAKE; - } - - if (sd->flags & SD_SHARE_CPUCAPACITY) { - sd->flags |= SD_PREFER_SIBLING; - sd->imbalance_pct = 110; - sd->smt_gain = 1178; /* ~15% */ - - } else if (sd->flags & SD_SHARE_PKG_RESOURCES) { - sd->imbalance_pct = 117; - sd->cache_nice_tries = 1; - sd->busy_idx = 2; - -#ifdef CONFIG_NUMA - } else if (sd->flags & SD_NUMA) { - sd->cache_nice_tries = 2; - sd->busy_idx = 3; - sd->idle_idx = 2; - - sd->flags |= SD_SERIALIZE; - if (sched_domains_numa_distance[tl->numa_level] > RECLAIM_DISTANCE) { - sd->flags &= ~(SD_BALANCE_EXEC | - SD_BALANCE_FORK | - SD_WAKE_AFFINE); - } - -#endif - } else { - sd->flags |= SD_PREFER_SIBLING; - sd->cache_nice_tries = 1; - sd->busy_idx = 2; - sd->idle_idx = 1; - } - - /* - * For all levels sharing cache; connect a sched_domain_shared - * instance. - */ - if (sd->flags & SD_SHARE_PKG_RESOURCES) { - sd->shared = *per_cpu_ptr(sdd->sds, sd_id); - atomic_inc(&sd->shared->ref); - atomic_set(&sd->shared->nr_busy_cpus, sd_weight); - } - - sd->private = sdd; - - return sd; -} - -/* - * Topology list, bottom-up. - */ -static struct sched_domain_topology_level default_topology[] = { -#ifdef CONFIG_SCHED_SMT - { cpu_smt_mask, cpu_smt_flags, SD_INIT_NAME(SMT) }, -#endif -#ifdef CONFIG_SCHED_MC - { cpu_coregroup_mask, cpu_core_flags, SD_INIT_NAME(MC) }, -#endif - { cpu_cpu_mask, SD_INIT_NAME(DIE) }, - { NULL, }, -}; - -static struct sched_domain_topology_level *sched_domain_topology = - default_topology; - -#define for_each_sd_topology(tl) \ - for (tl = sched_domain_topology; tl->mask; tl++) - -void set_sched_topology(struct sched_domain_topology_level *tl) -{ - if (WARN_ON_ONCE(sched_smp_initialized)) - return; - - sched_domain_topology = tl; -} - -#ifdef CONFIG_NUMA - -static const struct cpumask *sd_numa_mask(int cpu) -{ - return sched_domains_numa_masks[sched_domains_curr_level][cpu_to_node(cpu)]; -} - -static void sched_numa_warn(const char *str) -{ - static int done = false; - int i,j; - - if (done) - return; - - done = true; - - printk(KERN_WARNING "ERROR: %s\n\n", str); - - for (i = 0; i < nr_node_ids; i++) { - printk(KERN_WARNING " "); - for (j = 0; j < nr_node_ids; j++) - printk(KERN_CONT "%02d ", node_distance(i,j)); - printk(KERN_CONT "\n"); - } - printk(KERN_WARNING "\n"); -} - -bool find_numa_distance(int distance) -{ - int i; - - if (distance == node_distance(0, 0)) - return true; - - for (i = 0; i < sched_domains_numa_levels; i++) { - if (sched_domains_numa_distance[i] == distance) - return true; - } - - return false; -} - -/* - * A system can have three types of NUMA topology: - * NUMA_DIRECT: all nodes are directly connected, or not a NUMA system - * NUMA_GLUELESS_MESH: some nodes reachable through intermediary nodes - * NUMA_BACKPLANE: nodes can reach other nodes through a backplane - * - * The difference between a glueless mesh topology and a backplane - * topology lies in whether communication between not directly - * connected nodes goes through intermediary nodes (where programs - * could run), or through backplane controllers. This affects - * placement of programs. - * - * The type of topology can be discerned with the following tests: - * - If the maximum distance between any nodes is 1 hop, the system - * is directly connected. - * - If for two nodes A and B, located N > 1 hops away from each other, - * there is an intermediary node C, which is < N hops away from both - * nodes A and B, the system is a glueless mesh. - */ -static void init_numa_topology_type(void) -{ - int a, b, c, n; - - n = sched_max_numa_distance; - - if (sched_domains_numa_levels <= 1) { - sched_numa_topology_type = NUMA_DIRECT; - return; - } - - for_each_online_node(a) { - for_each_online_node(b) { - /* Find two nodes furthest removed from each other. */ - if (node_distance(a, b) < n) - continue; - - /* Is there an intermediary node between a and b? */ - for_each_online_node(c) { - if (node_distance(a, c) < n && - node_distance(b, c) < n) { - sched_numa_topology_type = - NUMA_GLUELESS_MESH; - return; - } - } - - sched_numa_topology_type = NUMA_BACKPLANE; - return; - } - } -} - -static void sched_init_numa(void) -{ - int next_distance, curr_distance = node_distance(0, 0); - struct sched_domain_topology_level *tl; - int level = 0; - int i, j, k; - - sched_domains_numa_distance = kzalloc(sizeof(int) * nr_node_ids, GFP_KERNEL); - if (!sched_domains_numa_distance) - return; - - /* - * O(nr_nodes^2) deduplicating selection sort -- in order to find the - * unique distances in the node_distance() table. - * - * Assumes node_distance(0,j) includes all distances in - * node_distance(i,j) in order to avoid cubic time. - */ - next_distance = curr_distance; - for (i = 0; i < nr_node_ids; i++) { - for (j = 0; j < nr_node_ids; j++) { - for (k = 0; k < nr_node_ids; k++) { - int distance = node_distance(i, k); - - if (distance > curr_distance && - (distance < next_distance || - next_distance == curr_distance)) - next_distance = distance; - - /* - * While not a strong assumption it would be nice to know - * about cases where if node A is connected to B, B is not - * equally connected to A. - */ - if (sched_debug() && node_distance(k, i) != distance) - sched_numa_warn("Node-distance not symmetric"); - - if (sched_debug() && i && !find_numa_distance(distance)) - sched_numa_warn("Node-0 not representative"); - } - if (next_distance != curr_distance) { - sched_domains_numa_distance[level++] = next_distance; - sched_domains_numa_levels = level; - curr_distance = next_distance; - } else break; - } - - /* - * In case of sched_debug() we verify the above assumption. - */ - if (!sched_debug()) - break; - } - - if (!level) - return; - - /* - * 'level' contains the number of unique distances, excluding the - * identity distance node_distance(i,i). - * - * The sched_domains_numa_distance[] array includes the actual distance - * numbers. - */ - - /* - * Here, we should temporarily reset sched_domains_numa_levels to 0. - * If it fails to allocate memory for array sched_domains_numa_masks[][], - * the array will contain less then 'level' members. This could be - * dangerous when we use it to iterate array sched_domains_numa_masks[][] - * in other functions. - * - * We reset it to 'level' at the end of this function. - */ - sched_domains_numa_levels = 0; - - sched_domains_numa_masks = kzalloc(sizeof(void *) * level, GFP_KERNEL); - if (!sched_domains_numa_masks) - return; - - /* - * Now for each level, construct a mask per node which contains all - * cpus of nodes that are that many hops away from us. - */ - for (i = 0; i < level; i++) { - sched_domains_numa_masks[i] = - kzalloc(nr_node_ids * sizeof(void *), GFP_KERNEL); - if (!sched_domains_numa_masks[i]) - return; - - for (j = 0; j < nr_node_ids; j++) { - struct cpumask *mask = kzalloc(cpumask_size(), GFP_KERNEL); - if (!mask) - return; - - sched_domains_numa_masks[i][j] = mask; - - for_each_node(k) { - if (node_distance(j, k) > sched_domains_numa_distance[i]) - continue; - - cpumask_or(mask, mask, cpumask_of_node(k)); - } - } - } - - /* Compute default topology size */ - for (i = 0; sched_domain_topology[i].mask; i++); - - tl = kzalloc((i + level + 1) * - sizeof(struct sched_domain_topology_level), GFP_KERNEL); - if (!tl) - return; - - /* - * Copy the default topology bits.. - */ - for (i = 0; sched_domain_topology[i].mask; i++) - tl[i] = sched_domain_topology[i]; - - /* - * .. and append 'j' levels of NUMA goodness. - */ - for (j = 0; j < level; i++, j++) { - tl[i] = (struct sched_domain_topology_level){ - .mask = sd_numa_mask, - .sd_flags = cpu_numa_flags, - .flags = SDTL_OVERLAP, - .numa_level = j, - SD_INIT_NAME(NUMA) - }; - } - - sched_domain_topology = tl; - - sched_domains_numa_levels = level; - sched_max_numa_distance = sched_domains_numa_distance[level - 1]; - - init_numa_topology_type(); -} - -static void sched_domains_numa_masks_set(unsigned int cpu) -{ - int node = cpu_to_node(cpu); - int i, j; - - for (i = 0; i < sched_domains_numa_levels; i++) { - for (j = 0; j < nr_node_ids; j++) { - if (node_distance(j, node) <= sched_domains_numa_distance[i]) - cpumask_set_cpu(cpu, sched_domains_numa_masks[i][j]); - } - } -} - -static void sched_domains_numa_masks_clear(unsigned int cpu) -{ - int i, j; - - for (i = 0; i < sched_domains_numa_levels; i++) { - for (j = 0; j < nr_node_ids; j++) - cpumask_clear_cpu(cpu, sched_domains_numa_masks[i][j]); - } -} - -#else -static inline void sched_init_numa(void) { } -static void sched_domains_numa_masks_set(unsigned int cpu) { } -static void sched_domains_numa_masks_clear(unsigned int cpu) { } -#endif /* CONFIG_NUMA */ - -static int __sdt_alloc(const struct cpumask *cpu_map) -{ - struct sched_domain_topology_level *tl; - int j; - - for_each_sd_topology(tl) { - struct sd_data *sdd = &tl->data; - - sdd->sd = alloc_percpu(struct sched_domain *); - if (!sdd->sd) - return -ENOMEM; - - sdd->sds = alloc_percpu(struct sched_domain_shared *); - if (!sdd->sds) - return -ENOMEM; - - sdd->sg = alloc_percpu(struct sched_group *); - if (!sdd->sg) - return -ENOMEM; - - sdd->sgc = alloc_percpu(struct sched_group_capacity *); - if (!sdd->sgc) - return -ENOMEM; - - for_each_cpu(j, cpu_map) { - struct sched_domain *sd; - struct sched_domain_shared *sds; - struct sched_group *sg; - struct sched_group_capacity *sgc; - - sd = kzalloc_node(sizeof(struct sched_domain) + cpumask_size(), - GFP_KERNEL, cpu_to_node(j)); - if (!sd) - return -ENOMEM; - - *per_cpu_ptr(sdd->sd, j) = sd; - - sds = kzalloc_node(sizeof(struct sched_domain_shared), - GFP_KERNEL, cpu_to_node(j)); - if (!sds) - return -ENOMEM; - - *per_cpu_ptr(sdd->sds, j) = sds; - - sg = kzalloc_node(sizeof(struct sched_group) + cpumask_size(), - GFP_KERNEL, cpu_to_node(j)); - if (!sg) - return -ENOMEM; - - sg->next = sg; - - *per_cpu_ptr(sdd->sg, j) = sg; - - sgc = kzalloc_node(sizeof(struct sched_group_capacity) + cpumask_size(), - GFP_KERNEL, cpu_to_node(j)); - if (!sgc) - return -ENOMEM; - - *per_cpu_ptr(sdd->sgc, j) = sgc; - } - } - - return 0; -} - -static void __sdt_free(const struct cpumask *cpu_map) -{ - struct sched_domain_topology_level *tl; - int j; - - for_each_sd_topology(tl) { - struct sd_data *sdd = &tl->data; - - for_each_cpu(j, cpu_map) { - struct sched_domain *sd; - - if (sdd->sd) { - sd = *per_cpu_ptr(sdd->sd, j); - if (sd && (sd->flags & SD_OVERLAP)) - free_sched_groups(sd->groups, 0); - kfree(*per_cpu_ptr(sdd->sd, j)); - } - - if (sdd->sds) - kfree(*per_cpu_ptr(sdd->sds, j)); - if (sdd->sg) - kfree(*per_cpu_ptr(sdd->sg, j)); - if (sdd->sgc) - kfree(*per_cpu_ptr(sdd->sgc, j)); - } - free_percpu(sdd->sd); - sdd->sd = NULL; - free_percpu(sdd->sds); - sdd->sds = NULL; - free_percpu(sdd->sg); - sdd->sg = NULL; - free_percpu(sdd->sgc); - sdd->sgc = NULL; - } -} - -struct sched_domain *build_sched_domain(struct sched_domain_topology_level *tl, - const struct cpumask *cpu_map, struct sched_domain_attr *attr, - struct sched_domain *child, int cpu) -{ - struct sched_domain *sd = sd_init(tl, cpu_map, child, cpu); - - if (child) { - sd->level = child->level + 1; - sched_domain_level_max = max(sched_domain_level_max, sd->level); - child->parent = sd; - - if (!cpumask_subset(sched_domain_span(child), - sched_domain_span(sd))) { - pr_err("BUG: arch topology borken\n"); -#ifdef CONFIG_SCHED_DEBUG - pr_err(" the %s domain not a subset of the %s domain\n", - child->name, sd->name); -#endif - /* Fixup, ensure @sd has at least @child cpus. */ - cpumask_or(sched_domain_span(sd), - sched_domain_span(sd), - sched_domain_span(child)); - } - - } - set_domain_attribute(sd, attr); - - return sd; -} - -/* - * Build sched domains for a given set of cpus and attach the sched domains - * to the individual cpus - */ -static int build_sched_domains(const struct cpumask *cpu_map, - struct sched_domain_attr *attr) -{ - enum s_alloc alloc_state; - struct sched_domain *sd; - struct s_data d; - struct rq *rq = NULL; - int i, ret = -ENOMEM; - - alloc_state = __visit_domain_allocation_hell(&d, cpu_map); - if (alloc_state != sa_rootdomain) - goto error; - - /* Set up domains for cpus specified by the cpu_map. */ - for_each_cpu(i, cpu_map) { - struct sched_domain_topology_level *tl; - - sd = NULL; - for_each_sd_topology(tl) { - sd = build_sched_domain(tl, cpu_map, attr, sd, i); - if (tl == sched_domain_topology) - *per_cpu_ptr(d.sd, i) = sd; - if (tl->flags & SDTL_OVERLAP || sched_feat(FORCE_SD_OVERLAP)) - sd->flags |= SD_OVERLAP; - if (cpumask_equal(cpu_map, sched_domain_span(sd))) - break; - } - } - - /* Build the groups for the domains */ - for_each_cpu(i, cpu_map) { - for (sd = *per_cpu_ptr(d.sd, i); sd; sd = sd->parent) { - sd->span_weight = cpumask_weight(sched_domain_span(sd)); - if (sd->flags & SD_OVERLAP) { - if (build_overlap_sched_groups(sd, i)) - goto error; - } else { - if (build_sched_groups(sd, i)) - goto error; - } - } - } - - /* Calculate CPU capacity for physical packages and nodes */ - for (i = nr_cpumask_bits-1; i >= 0; i--) { - if (!cpumask_test_cpu(i, cpu_map)) - continue; - - for (sd = *per_cpu_ptr(d.sd, i); sd; sd = sd->parent) { - claim_allocations(i, sd); - init_sched_groups_capacity(i, sd); - } - } - - /* Attach the domains */ - rcu_read_lock(); - for_each_cpu(i, cpu_map) { - rq = cpu_rq(i); - sd = *per_cpu_ptr(d.sd, i); - - /* Use READ_ONCE()/WRITE_ONCE() to avoid load/store tearing: */ - if (rq->cpu_capacity_orig > READ_ONCE(d.rd->max_cpu_capacity)) - WRITE_ONCE(d.rd->max_cpu_capacity, rq->cpu_capacity_orig); - - cpu_attach_domain(sd, d.rd, i); - } - rcu_read_unlock(); - - if (rq && sched_debug_enabled) { - pr_info("span: %*pbl (max cpu_capacity = %lu)\n", - cpumask_pr_args(cpu_map), rq->rd->max_cpu_capacity); - } - - ret = 0; -error: - __free_domain_allocs(&d, alloc_state, cpu_map); - return ret; -} - -static cpumask_var_t *doms_cur; /* current sched domains */ -static int ndoms_cur; /* number of sched domains in 'doms_cur' */ -static struct sched_domain_attr *dattr_cur; - /* attribues of custom domains in 'doms_cur' */ - -/* - * Special case: If a kmalloc of a doms_cur partition (array of - * cpumask) fails, then fallback to a single sched domain, - * as determined by the single cpumask fallback_doms. - */ -static cpumask_var_t fallback_doms; - -/* - * arch_update_cpu_topology lets virtualized architectures update the - * cpu core maps. It is supposed to return 1 if the topology changed - * or 0 if it stayed the same. - */ -int __weak arch_update_cpu_topology(void) -{ - return 0; -} - -cpumask_var_t *alloc_sched_domains(unsigned int ndoms) -{ - int i; - cpumask_var_t *doms; - - doms = kmalloc(sizeof(*doms) * ndoms, GFP_KERNEL); - if (!doms) - return NULL; - for (i = 0; i < ndoms; i++) { - if (!alloc_cpumask_var(&doms[i], GFP_KERNEL)) { - free_sched_domains(doms, i); - return NULL; - } - } - return doms; -} - -void free_sched_domains(cpumask_var_t doms[], unsigned int ndoms) -{ - unsigned int i; - for (i = 0; i < ndoms; i++) - free_cpumask_var(doms[i]); - kfree(doms); -} - -/* - * Set up scheduler domains and groups. Callers must hold the hotplug lock. - * For now this just excludes isolated cpus, but could be used to - * exclude other special cases in the future. - */ -static int init_sched_domains(const struct cpumask *cpu_map) -{ - int err; - - arch_update_cpu_topology(); - ndoms_cur = 1; - doms_cur = alloc_sched_domains(ndoms_cur); - if (!doms_cur) - doms_cur = &fallback_doms; - cpumask_andnot(doms_cur[0], cpu_map, cpu_isolated_map); - err = build_sched_domains(doms_cur[0], NULL); - register_sched_domain_sysctl(); - - return err; -} - -/* - * Detach sched domains from a group of cpus specified in cpu_map - * These cpus will now be attached to the NULL domain - */ -static void detach_destroy_domains(const struct cpumask *cpu_map) -{ - int i; - - rcu_read_lock(); - for_each_cpu(i, cpu_map) - cpu_attach_domain(NULL, &def_root_domain, i); - rcu_read_unlock(); -} - -/* handle null as "default" */ -static int dattrs_equal(struct sched_domain_attr *cur, int idx_cur, - struct sched_domain_attr *new, int idx_new) -{ - struct sched_domain_attr tmp; - - /* fast path */ - if (!new && !cur) - return 1; - - tmp = SD_ATTR_INIT; - return !memcmp(cur ? (cur + idx_cur) : &tmp, - new ? (new + idx_new) : &tmp, - sizeof(struct sched_domain_attr)); -} - -/* - * Partition sched domains as specified by the 'ndoms_new' - * cpumasks in the array doms_new[] of cpumasks. This compares - * doms_new[] to the current sched domain partitioning, doms_cur[]. - * It destroys each deleted domain and builds each new domain. - * - * 'doms_new' is an array of cpumask_var_t's of length 'ndoms_new'. - * The masks don't intersect (don't overlap.) We should setup one - * sched domain for each mask. CPUs not in any of the cpumasks will - * not be load balanced. If the same cpumask appears both in the - * current 'doms_cur' domains and in the new 'doms_new', we can leave - * it as it is. - * - * The passed in 'doms_new' should be allocated using - * alloc_sched_domains. This routine takes ownership of it and will - * free_sched_domains it when done with it. If the caller failed the - * alloc call, then it can pass in doms_new == NULL && ndoms_new == 1, - * and partition_sched_domains() will fallback to the single partition - * 'fallback_doms', it also forces the domains to be rebuilt. - * - * If doms_new == NULL it will be replaced with cpu_online_mask. - * ndoms_new == 0 is a special case for destroying existing domains, - * and it will not create the default domain. - * - * Call with hotplug lock held - */ -void partition_sched_domains(int ndoms_new, cpumask_var_t doms_new[], - struct sched_domain_attr *dattr_new) -{ - int i, j, n; - int new_topology; - - mutex_lock(&sched_domains_mutex); - - /* always unregister in case we don't destroy any domains */ - unregister_sched_domain_sysctl(); - - /* Let architecture update cpu core mappings. */ - new_topology = arch_update_cpu_topology(); - - n = doms_new ? ndoms_new : 0; - - /* Destroy deleted domains */ - for (i = 0; i < ndoms_cur; i++) { - for (j = 0; j < n && !new_topology; j++) { - if (cpumask_equal(doms_cur[i], doms_new[j]) - && dattrs_equal(dattr_cur, i, dattr_new, j)) - goto match1; - } - /* no match - a current sched domain not in new doms_new[] */ - detach_destroy_domains(doms_cur[i]); -match1: - ; - } - - n = ndoms_cur; - if (doms_new == NULL) { - n = 0; - doms_new = &fallback_doms; - cpumask_andnot(doms_new[0], cpu_active_mask, cpu_isolated_map); - WARN_ON_ONCE(dattr_new); - } - - /* Build new domains */ - for (i = 0; i < ndoms_new; i++) { - for (j = 0; j < n && !new_topology; j++) { - if (cpumask_equal(doms_new[i], doms_cur[j]) - && dattrs_equal(dattr_new, i, dattr_cur, j)) - goto match2; - } - /* no match - add a new doms_new */ - build_sched_domains(doms_new[i], dattr_new ? dattr_new + i : NULL); -match2: - ; - } - - /* Remember the new sched domains */ - if (doms_cur != &fallback_doms) - free_sched_domains(doms_cur, ndoms_cur); - kfree(dattr_cur); /* kfree(NULL) is safe */ - doms_cur = doms_new; - dattr_cur = dattr_new; - ndoms_cur = ndoms_new; - - register_sched_domain_sysctl(); - - mutex_unlock(&sched_domains_mutex); -} - -static int num_cpus_frozen; /* used to mark begin/end of suspend/resume */ - -/* - * Update cpusets according to cpu_active mask. If cpusets are - * disabled, cpuset_update_active_cpus() becomes a simple wrapper - * around partition_sched_domains(). - * - * If we come here as part of a suspend/resume, don't touch cpusets because we - * want to restore it back to its original state upon resume anyway. - */ -static void cpuset_cpu_active(void) -{ - if (cpuhp_tasks_frozen) { - /* - * num_cpus_frozen tracks how many CPUs are involved in suspend - * resume sequence. As long as this is not the last online - * operation in the resume sequence, just build a single sched - * domain, ignoring cpusets. - */ - num_cpus_frozen--; - if (likely(num_cpus_frozen)) { - partition_sched_domains(1, NULL, NULL); - return; - } - /* - * This is the last CPU online operation. So fall through and - * restore the original sched domains by considering the - * cpuset configurations. - */ - } - cpuset_update_active_cpus(true); -} - -static int cpuset_cpu_inactive(unsigned int cpu) -{ - unsigned long flags; - struct dl_bw *dl_b; - bool overflow; - int cpus; - - if (!cpuhp_tasks_frozen) { - rcu_read_lock_sched(); - dl_b = dl_bw_of(cpu); - - raw_spin_lock_irqsave(&dl_b->lock, flags); - cpus = dl_bw_cpus(cpu); - overflow = __dl_overflow(dl_b, cpus, 0, 0); - raw_spin_unlock_irqrestore(&dl_b->lock, flags); - - rcu_read_unlock_sched(); - - if (overflow) - return -EBUSY; - cpuset_update_active_cpus(false); - } else { - num_cpus_frozen++; - partition_sched_domains(1, NULL, NULL); - } - return 0; -} - -int sched_cpu_activate(unsigned int cpu) -{ - struct rq *rq = cpu_rq(cpu); - unsigned long flags; - - set_cpu_active(cpu, true); - - if (sched_smp_initialized) { - sched_domains_numa_masks_set(cpu); - cpuset_cpu_active(); - } - - /* - * Put the rq online, if not already. This happens: - * - * 1) In the early boot process, because we build the real domains - * after all cpus have been brought up. - * - * 2) At runtime, if cpuset_cpu_active() fails to rebuild the - * domains. - */ - raw_spin_lock_irqsave(&rq->lock, flags); - if (rq->rd) { - BUG_ON(!cpumask_test_cpu(cpu, rq->rd->span)); - set_rq_online(rq); - } - raw_spin_unlock_irqrestore(&rq->lock, flags); - - update_max_interval(); - - return 0; -} - -int sched_cpu_deactivate(unsigned int cpu) -{ - int ret; - - set_cpu_active(cpu, false); - /* - * We've cleared cpu_active_mask, wait for all preempt-disabled and RCU - * users of this state to go away such that all new such users will - * observe it. - * - * For CONFIG_PREEMPT we have preemptible RCU and its sync_rcu() might - * not imply sync_sched(), so wait for both. - * - * Do sync before park smpboot threads to take care the rcu boost case. - */ - if (IS_ENABLED(CONFIG_PREEMPT)) - synchronize_rcu_mult(call_rcu, call_rcu_sched); - else - synchronize_rcu(); - - if (!sched_smp_initialized) - return 0; - - ret = cpuset_cpu_inactive(cpu); - if (ret) { - set_cpu_active(cpu, true); - return ret; - } - sched_domains_numa_masks_clear(cpu); - return 0; -} - -static void sched_rq_cpu_starting(unsigned int cpu) -{ - struct rq *rq = cpu_rq(cpu); - - rq->calc_load_update = calc_load_update; - update_max_interval(); -} - -int sched_cpu_starting(unsigned int cpu) -{ - set_cpu_rq_start_time(cpu); - sched_rq_cpu_starting(cpu); - return 0; -} - -#ifdef CONFIG_HOTPLUG_CPU -int sched_cpu_dying(unsigned int cpu) -{ - struct rq *rq = cpu_rq(cpu); - unsigned long flags; - - /* Handle pending wakeups and then migrate everything off */ - sched_ttwu_pending(); - raw_spin_lock_irqsave(&rq->lock, flags); - if (rq->rd) { - BUG_ON(!cpumask_test_cpu(cpu, rq->rd->span)); - set_rq_offline(rq); - } - migrate_tasks(rq); - BUG_ON(rq->nr_running != 1); - raw_spin_unlock_irqrestore(&rq->lock, flags); - calc_load_migrate(rq); - update_max_interval(); - nohz_balance_exit_idle(cpu); - hrtick_clear(rq); - return 0; -} -#endif - -#ifdef CONFIG_SCHED_SMT -DEFINE_STATIC_KEY_FALSE(sched_smt_present); - -static void sched_init_smt(void) -{ - /* - * We've enumerated all CPUs and will assume that if any CPU - * has SMT siblings, CPU0 will too. - */ - if (cpumask_weight(cpu_smt_mask(0)) > 1) - static_branch_enable(&sched_smt_present); -} -#else -static inline void sched_init_smt(void) { } -#endif - -void __init sched_init_smp(void) -{ - cpumask_var_t non_isolated_cpus; - - alloc_cpumask_var(&non_isolated_cpus, GFP_KERNEL); - alloc_cpumask_var(&fallback_doms, GFP_KERNEL); - - sched_init_numa(); - - /* - * There's no userspace yet to cause hotplug operations; hence all the - * cpu masks are stable and all blatant races in the below code cannot - * happen. - */ - mutex_lock(&sched_domains_mutex); - init_sched_domains(cpu_active_mask); - cpumask_andnot(non_isolated_cpus, cpu_possible_mask, cpu_isolated_map); - if (cpumask_empty(non_isolated_cpus)) - cpumask_set_cpu(smp_processor_id(), non_isolated_cpus); - mutex_unlock(&sched_domains_mutex); - - /* Move init over to a non-isolated CPU */ - if (set_cpus_allowed_ptr(current, non_isolated_cpus) < 0) - BUG(); - sched_init_granularity(); - free_cpumask_var(non_isolated_cpus); - - init_sched_rt_class(); - init_sched_dl_class(); - - sched_init_smt(); - - sched_smp_initialized = true; -} - -static int __init migration_init(void) -{ - sched_rq_cpu_starting(smp_processor_id()); - return 0; -} -early_initcall(migration_init); - -#else -void __init sched_init_smp(void) -{ - sched_init_granularity(); -} -#endif /* CONFIG_SMP */ - -int in_sched_functions(unsigned long addr) -{ - return in_lock_functions(addr) || - (addr >= (unsigned long)__sched_text_start - && addr < (unsigned long)__sched_text_end); -} - -#ifdef CONFIG_CGROUP_SCHED -/* - * Default task group. - * Every task in system belongs to this group at bootup. - */ -struct task_group root_task_group; -LIST_HEAD(task_groups); - -/* Cacheline aligned slab cache for task_group */ -static struct kmem_cache *task_group_cache __read_mostly; -#endif - -DECLARE_PER_CPU(cpumask_var_t, load_balance_mask); -DECLARE_PER_CPU(cpumask_var_t, select_idle_mask); - -#define WAIT_TABLE_BITS 8 -#define WAIT_TABLE_SIZE (1 << WAIT_TABLE_BITS) -static wait_queue_head_t bit_wait_table[WAIT_TABLE_SIZE] __cacheline_aligned; - -wait_queue_head_t *bit_waitqueue(void *word, int bit) -{ - const int shift = BITS_PER_LONG == 32 ? 5 : 6; - unsigned long val = (unsigned long)word << shift | bit; - - return bit_wait_table + hash_long(val, WAIT_TABLE_BITS); -} -EXPORT_SYMBOL(bit_waitqueue); - -void __init sched_init(void) -{ - int i, j; - unsigned long alloc_size = 0, ptr; - - for (i = 0; i < WAIT_TABLE_SIZE; i++) - init_waitqueue_head(bit_wait_table + i); - -#ifdef CONFIG_FAIR_GROUP_SCHED - alloc_size += 2 * nr_cpu_ids * sizeof(void **); -#endif -#ifdef CONFIG_RT_GROUP_SCHED - alloc_size += 2 * nr_cpu_ids * sizeof(void **); -#endif - if (alloc_size) { - ptr = (unsigned long)kzalloc(alloc_size, GFP_NOWAIT); - -#ifdef CONFIG_FAIR_GROUP_SCHED - root_task_group.se = (struct sched_entity **)ptr; - ptr += nr_cpu_ids * sizeof(void **); - - root_task_group.cfs_rq = (struct cfs_rq **)ptr; - ptr += nr_cpu_ids * sizeof(void **); - -#endif /* CONFIG_FAIR_GROUP_SCHED */ -#ifdef CONFIG_RT_GROUP_SCHED - root_task_group.rt_se = (struct sched_rt_entity **)ptr; - ptr += nr_cpu_ids * sizeof(void **); - - root_task_group.rt_rq = (struct rt_rq **)ptr; - ptr += nr_cpu_ids * sizeof(void **); - -#endif /* CONFIG_RT_GROUP_SCHED */ - } -#ifdef CONFIG_CPUMASK_OFFSTACK - for_each_possible_cpu(i) { - per_cpu(load_balance_mask, i) = (cpumask_var_t)kzalloc_node( - cpumask_size(), GFP_KERNEL, cpu_to_node(i)); - per_cpu(select_idle_mask, i) = (cpumask_var_t)kzalloc_node( - cpumask_size(), GFP_KERNEL, cpu_to_node(i)); - } -#endif /* CONFIG_CPUMASK_OFFSTACK */ - - init_rt_bandwidth(&def_rt_bandwidth, - global_rt_period(), global_rt_runtime()); - init_dl_bandwidth(&def_dl_bandwidth, - global_rt_period(), global_rt_runtime()); - -#ifdef CONFIG_SMP - init_defrootdomain(); -#endif - -#ifdef CONFIG_RT_GROUP_SCHED - init_rt_bandwidth(&root_task_group.rt_bandwidth, - global_rt_period(), global_rt_runtime()); -#endif /* CONFIG_RT_GROUP_SCHED */ - -#ifdef CONFIG_CGROUP_SCHED - task_group_cache = KMEM_CACHE(task_group, 0); - - list_add(&root_task_group.list, &task_groups); - INIT_LIST_HEAD(&root_task_group.children); - INIT_LIST_HEAD(&root_task_group.siblings); - autogroup_init(&init_task); -#endif /* CONFIG_CGROUP_SCHED */ - - for_each_possible_cpu(i) { - struct rq *rq; - - rq = cpu_rq(i); - raw_spin_lock_init(&rq->lock); - rq->nr_running = 0; - rq->calc_load_active = 0; - rq->calc_load_update = jiffies + LOAD_FREQ; - init_cfs_rq(&rq->cfs); - init_rt_rq(&rq->rt); - init_dl_rq(&rq->dl); -#ifdef CONFIG_FAIR_GROUP_SCHED - root_task_group.shares = ROOT_TASK_GROUP_LOAD; - INIT_LIST_HEAD(&rq->leaf_cfs_rq_list); - /* - * How much cpu bandwidth does root_task_group get? - * - * In case of task-groups formed thr' the cgroup filesystem, it - * gets 100% of the cpu resources in the system. This overall - * system cpu resource is divided among the tasks of - * root_task_group and its child task-groups in a fair manner, - * based on each entity's (task or task-group's) weight - * (se->load.weight). - * - * In other words, if root_task_group has 10 tasks of weight - * 1024) and two child groups A0 and A1 (of weight 1024 each), - * then A0's share of the cpu resource is: - * - * A0's bandwidth = 1024 / (10*1024 + 1024 + 1024) = 8.33% - * - * We achieve this by letting root_task_group's tasks sit - * directly in rq->cfs (i.e root_task_group->se[] = NULL). - */ - init_cfs_bandwidth(&root_task_group.cfs_bandwidth); - init_tg_cfs_entry(&root_task_group, &rq->cfs, NULL, i, NULL); -#endif /* CONFIG_FAIR_GROUP_SCHED */ - - rq->rt.rt_runtime = def_rt_bandwidth.rt_runtime; -#ifdef CONFIG_RT_GROUP_SCHED - init_tg_rt_entry(&root_task_group, &rq->rt, NULL, i, NULL); -#endif - - for (j = 0; j < CPU_LOAD_IDX_MAX; j++) - rq->cpu_load[j] = 0; - -#ifdef CONFIG_SMP - rq->sd = NULL; - rq->rd = NULL; - rq->cpu_capacity = rq->cpu_capacity_orig = SCHED_CAPACITY_SCALE; - rq->balance_callback = NULL; - rq->active_balance = 0; - rq->next_balance = jiffies; - rq->push_cpu = 0; - rq->cpu = i; - rq->online = 0; - rq->idle_stamp = 0; - rq->avg_idle = 2*sysctl_sched_migration_cost; - rq->max_idle_balance_cost = sysctl_sched_migration_cost; - - INIT_LIST_HEAD(&rq->cfs_tasks); - - rq_attach_root(rq, &def_root_domain); -#ifdef CONFIG_NO_HZ_COMMON - rq->last_load_update_tick = jiffies; - rq->nohz_flags = 0; -#endif -#ifdef CONFIG_NO_HZ_FULL - rq->last_sched_tick = 0; -#endif -#endif /* CONFIG_SMP */ - init_rq_hrtick(rq); - atomic_set(&rq->nr_iowait, 0); - } - - set_load_weight(&init_task); - - /* - * The boot idle thread does lazy MMU switching as well: - */ - atomic_inc(&init_mm.mm_count); - enter_lazy_tlb(&init_mm, current); - - /* - * Make us the idle thread. Technically, schedule() should not be - * called from this thread, however somewhere below it might be, - * but because we are the idle thread, we just pick up running again - * when this runqueue becomes "idle". - */ - init_idle(current, smp_processor_id()); - - calc_load_update = jiffies + LOAD_FREQ; - -#ifdef CONFIG_SMP - zalloc_cpumask_var(&sched_domains_tmpmask, GFP_NOWAIT); - /* May be allocated at isolcpus cmdline parse time */ - if (cpu_isolated_map == NULL) - zalloc_cpumask_var(&cpu_isolated_map, GFP_NOWAIT); - idle_thread_set_boot_cpu(); - set_cpu_rq_start_time(smp_processor_id()); -#endif - init_sched_fair_class(); - - init_schedstats(); - - scheduler_running = 1; -} - -#ifdef CONFIG_DEBUG_ATOMIC_SLEEP -static inline int preempt_count_equals(int preempt_offset) -{ - int nested = preempt_count() + rcu_preempt_depth(); - - return (nested == preempt_offset); -} - -void __might_sleep(const char *file, int line, int preempt_offset) -{ - /* - * Blocking primitives will set (and therefore destroy) current->state, - * since we will exit with TASK_RUNNING make sure we enter with it, - * otherwise we will destroy state. - */ - WARN_ONCE(current->state != TASK_RUNNING && current->task_state_change, - "do not call blocking ops when !TASK_RUNNING; " - "state=%lx set at [<%p>] %pS\n", - current->state, - (void *)current->task_state_change, - (void *)current->task_state_change); - - ___might_sleep(file, line, preempt_offset); -} -EXPORT_SYMBOL(__might_sleep); - -void ___might_sleep(const char *file, int line, int preempt_offset) -{ - static unsigned long prev_jiffy; /* ratelimiting */ - unsigned long preempt_disable_ip; - - rcu_sleep_check(); /* WARN_ON_ONCE() by default, no rate limit reqd. */ - if ((preempt_count_equals(preempt_offset) && !irqs_disabled() && - !is_idle_task(current)) || - system_state != SYSTEM_RUNNING || oops_in_progress) - return; - if (time_before(jiffies, prev_jiffy + HZ) && prev_jiffy) - return; - prev_jiffy = jiffies; - - /* Save this before calling printk(), since that will clobber it */ - preempt_disable_ip = get_preempt_disable_ip(current); - - printk(KERN_ERR - "BUG: sleeping function called from invalid context at %s:%d\n", - file, line); - printk(KERN_ERR - "in_atomic(): %d, irqs_disabled(): %d, pid: %d, name: %s\n", - in_atomic(), irqs_disabled(), - current->pid, current->comm); - - if (task_stack_end_corrupted(current)) - printk(KERN_EMERG "Thread overran stack, or stack corrupted\n"); - - debug_show_held_locks(current); - if (irqs_disabled()) - print_irqtrace_events(current); - if (IS_ENABLED(CONFIG_DEBUG_PREEMPT) - && !preempt_count_equals(preempt_offset)) { - pr_err("Preemption disabled at:"); - print_ip_sym(preempt_disable_ip); - pr_cont("\n"); - } - dump_stack(); - add_taint(TAINT_WARN, LOCKDEP_STILL_OK); -} -EXPORT_SYMBOL(___might_sleep); -#endif - -#ifdef CONFIG_MAGIC_SYSRQ -void normalize_rt_tasks(void) -{ - struct task_struct *g, *p; - struct sched_attr attr = { - .sched_policy = SCHED_NORMAL, - }; - - read_lock(&tasklist_lock); - for_each_process_thread(g, p) { - /* - * Only normalize user tasks: - */ - if (p->flags & PF_KTHREAD) - continue; - - p->se.exec_start = 0; - schedstat_set(p->se.statistics.wait_start, 0); - schedstat_set(p->se.statistics.sleep_start, 0); - schedstat_set(p->se.statistics.block_start, 0); - - if (!dl_task(p) && !rt_task(p)) { - /* - * Renice negative nice level userspace - * tasks back to 0: - */ - if (task_nice(p) < 0) - set_user_nice(p, 0); - continue; - } - - __sched_setscheduler(p, &attr, false, false); - } - read_unlock(&tasklist_lock); -} - -#endif /* CONFIG_MAGIC_SYSRQ */ - -#if defined(CONFIG_IA64) || defined(CONFIG_KGDB_KDB) -/* - * These functions are only useful for the IA64 MCA handling, or kdb. - * - * They can only be called when the whole system has been - * stopped - every CPU needs to be quiescent, and no scheduling - * activity can take place. Using them for anything else would - * be a serious bug, and as a result, they aren't even visible - * under any other configuration. - */ - -/** - * curr_task - return the current task for a given cpu. - * @cpu: the processor in question. - * - * ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED! - * - * Return: The current task for @cpu. - */ -struct task_struct *curr_task(int cpu) -{ - return cpu_curr(cpu); -} - -#endif /* defined(CONFIG_IA64) || defined(CONFIG_KGDB_KDB) */ - -#ifdef CONFIG_IA64 -/** - * set_curr_task - set the current task for a given cpu. - * @cpu: the processor in question. - * @p: the task pointer to set. - * - * Description: This function must only be used when non-maskable interrupts - * are serviced on a separate stack. It allows the architecture to switch the - * notion of the current task on a cpu in a non-blocking manner. This function - * must be called with all CPU's synchronized, and interrupts disabled, the - * and caller must save the original value of the current task (see - * curr_task() above) and restore that value before reenabling interrupts and - * re-starting the system. - * - * ONLY VALID WHEN THE WHOLE SYSTEM IS STOPPED! - */ -void ia64_set_curr_task(int cpu, struct task_struct *p) -{ - cpu_curr(cpu) = p; -} - -#endif - -#ifdef CONFIG_CGROUP_SCHED -/* task_group_lock serializes the addition/removal of task groups */ -static DEFINE_SPINLOCK(task_group_lock); - -static void sched_free_group(struct task_group *tg) -{ - free_fair_sched_group(tg); - free_rt_sched_group(tg); - autogroup_free(tg); - kmem_cache_free(task_group_cache, tg); -} - -/* allocate runqueue etc for a new task group */ -struct task_group *sched_create_group(struct task_group *parent) -{ - struct task_group *tg; - - tg = kmem_cache_alloc(task_group_cache, GFP_KERNEL | __GFP_ZERO); - if (!tg) - return ERR_PTR(-ENOMEM); - - if (!alloc_fair_sched_group(tg, parent)) - goto err; - - if (!alloc_rt_sched_group(tg, parent)) - goto err; - - return tg; - -err: - sched_free_group(tg); - return ERR_PTR(-ENOMEM); -} - -void sched_online_group(struct task_group *tg, struct task_group *parent) -{ - unsigned long flags; - - spin_lock_irqsave(&task_group_lock, flags); - list_add_rcu(&tg->list, &task_groups); - - WARN_ON(!parent); /* root should already exist */ - - tg->parent = parent; - INIT_LIST_HEAD(&tg->children); - list_add_rcu(&tg->siblings, &parent->children); - spin_unlock_irqrestore(&task_group_lock, flags); - - online_fair_sched_group(tg); -} - -/* rcu callback to free various structures associated with a task group */ -static void sched_free_group_rcu(struct rcu_head *rhp) -{ - /* now it should be safe to free those cfs_rqs */ - sched_free_group(container_of(rhp, struct task_group, rcu)); -} - -void sched_destroy_group(struct task_group *tg) -{ - /* wait for possible concurrent references to cfs_rqs complete */ - call_rcu(&tg->rcu, sched_free_group_rcu); -} - -void sched_offline_group(struct task_group *tg) -{ - unsigned long flags; - - /* end participation in shares distribution */ - unregister_fair_sched_group(tg); - - spin_lock_irqsave(&task_group_lock, flags); - list_del_rcu(&tg->list); - list_del_rcu(&tg->siblings); - spin_unlock_irqrestore(&task_group_lock, flags); -} - -static void sched_change_group(struct task_struct *tsk, int type) -{ - struct task_group *tg; - - /* - * All callers are synchronized by task_rq_lock(); we do not use RCU - * which is pointless here. Thus, we pass "true" to task_css_check() - * to prevent lockdep warnings. - */ - tg = container_of(task_css_check(tsk, cpu_cgrp_id, true), - struct task_group, css); - tg = autogroup_task_group(tsk, tg); - tsk->sched_task_group = tg; - -#ifdef CONFIG_FAIR_GROUP_SCHED - if (tsk->sched_class->task_change_group) - tsk->sched_class->task_change_group(tsk, type); - else -#endif - set_task_rq(tsk, task_cpu(tsk)); -} - -/* - * Change task's runqueue when it moves between groups. - * - * The caller of this function should have put the task in its new group by - * now. This function just updates tsk->se.cfs_rq and tsk->se.parent to reflect - * its new group. - */ -void sched_move_task(struct task_struct *tsk) -{ - int queued, running; - struct rq_flags rf; - struct rq *rq; - - rq = task_rq_lock(tsk, &rf); - - running = task_current(rq, tsk); - queued = task_on_rq_queued(tsk); - - if (queued) - dequeue_task(rq, tsk, DEQUEUE_SAVE | DEQUEUE_MOVE); - if (unlikely(running)) - put_prev_task(rq, tsk); - - sched_change_group(tsk, TASK_MOVE_GROUP); - - if (queued) - enqueue_task(rq, tsk, ENQUEUE_RESTORE | ENQUEUE_MOVE); - if (unlikely(running)) - set_curr_task(rq, tsk); - - task_rq_unlock(rq, tsk, &rf); -} -#endif /* CONFIG_CGROUP_SCHED */ - -#ifdef CONFIG_RT_GROUP_SCHED -/* - * Ensure that the real time constraints are schedulable. - */ -static DEFINE_MUTEX(rt_constraints_mutex); - -/* Must be called with tasklist_lock held */ -static inline int tg_has_rt_tasks(struct task_group *tg) -{ - struct task_struct *g, *p; - - /* - * Autogroups do not have RT tasks; see autogroup_create(). - */ - if (task_group_is_autogroup(tg)) - return 0; - - for_each_process_thread(g, p) { - if (rt_task(p) && task_group(p) == tg) - return 1; - } - - return 0; -} - -struct rt_schedulable_data { - struct task_group *tg; - u64 rt_period; - u64 rt_runtime; -}; - -static int tg_rt_schedulable(struct task_group *tg, void *data) -{ - struct rt_schedulable_data *d = data; - struct task_group *child; - unsigned long total, sum = 0; - u64 period, runtime; - - period = ktime_to_ns(tg->rt_bandwidth.rt_period); - runtime = tg->rt_bandwidth.rt_runtime; - - if (tg == d->tg) { - period = d->rt_period; - runtime = d->rt_runtime; - } - - /* - * Cannot have more runtime than the period. - */ - if (runtime > period && runtime != RUNTIME_INF) - return -EINVAL; - - /* - * Ensure we don't starve existing RT tasks. - */ - if (rt_bandwidth_enabled() && !runtime && tg_has_rt_tasks(tg)) - return -EBUSY; - - total = to_ratio(period, runtime); - - /* - * Nobody can have more than the global setting allows. - */ - if (total > to_ratio(global_rt_period(), global_rt_runtime())) - return -EINVAL; - - /* - * The sum of our children's runtime should not exceed our own. - */ - list_for_each_entry_rcu(child, &tg->children, siblings) { - period = ktime_to_ns(child->rt_bandwidth.rt_period); - runtime = child->rt_bandwidth.rt_runtime; - - if (child == d->tg) { - period = d->rt_period; - runtime = d->rt_runtime; - } - - sum += to_ratio(period, runtime); - } - - if (sum > total) - return -EINVAL; - - return 0; -} - -static int __rt_schedulable(struct task_group *tg, u64 period, u64 runtime) -{ - int ret; - - struct rt_schedulable_data data = { - .tg = tg, - .rt_period = period, - .rt_runtime = runtime, - }; - - rcu_read_lock(); - ret = walk_tg_tree(tg_rt_schedulable, tg_nop, &data); - rcu_read_unlock(); - - return ret; -} - -static int tg_set_rt_bandwidth(struct task_group *tg, - u64 rt_period, u64 rt_runtime) -{ - int i, err = 0; - - /* - * Disallowing the root group RT runtime is BAD, it would disallow the - * kernel creating (and or operating) RT threads. - */ - if (tg == &root_task_group && rt_runtime == 0) - return -EINVAL; - - /* No period doesn't make any sense. */ - if (rt_period == 0) - return -EINVAL; - - mutex_lock(&rt_constraints_mutex); - read_lock(&tasklist_lock); - err = __rt_schedulable(tg, rt_period, rt_runtime); - if (err) - goto unlock; - - raw_spin_lock_irq(&tg->rt_bandwidth.rt_runtime_lock); - tg->rt_bandwidth.rt_period = ns_to_ktime(rt_period); - tg->rt_bandwidth.rt_runtime = rt_runtime; - - for_each_possible_cpu(i) { - struct rt_rq *rt_rq = tg->rt_rq[i]; - - raw_spin_lock(&rt_rq->rt_runtime_lock); - rt_rq->rt_runtime = rt_runtime; - raw_spin_unlock(&rt_rq->rt_runtime_lock); - } - raw_spin_unlock_irq(&tg->rt_bandwidth.rt_runtime_lock); -unlock: - read_unlock(&tasklist_lock); - mutex_unlock(&rt_constraints_mutex); - - return err; -} - -static int sched_group_set_rt_runtime(struct task_group *tg, long rt_runtime_us) -{ - u64 rt_runtime, rt_period; - - rt_period = ktime_to_ns(tg->rt_bandwidth.rt_period); - rt_runtime = (u64)rt_runtime_us * NSEC_PER_USEC; - if (rt_runtime_us < 0) - rt_runtime = RUNTIME_INF; - - return tg_set_rt_bandwidth(tg, rt_period, rt_runtime); -} - -static long sched_group_rt_runtime(struct task_group *tg) -{ - u64 rt_runtime_us; - - if (tg->rt_bandwidth.rt_runtime == RUNTIME_INF) - return -1; - - rt_runtime_us = tg->rt_bandwidth.rt_runtime; - do_div(rt_runtime_us, NSEC_PER_USEC); - return rt_runtime_us; -} - -static int sched_group_set_rt_period(struct task_group *tg, u64 rt_period_us) -{ - u64 rt_runtime, rt_period; - - rt_period = rt_period_us * NSEC_PER_USEC; - rt_runtime = tg->rt_bandwidth.rt_runtime; - - return tg_set_rt_bandwidth(tg, rt_period, rt_runtime); -} - -static long sched_group_rt_period(struct task_group *tg) -{ - u64 rt_period_us; - - rt_period_us = ktime_to_ns(tg->rt_bandwidth.rt_period); - do_div(rt_period_us, NSEC_PER_USEC); - return rt_period_us; -} -#endif /* CONFIG_RT_GROUP_SCHED */ - -#ifdef CONFIG_RT_GROUP_SCHED -static int sched_rt_global_constraints(void) -{ - int ret = 0; - - mutex_lock(&rt_constraints_mutex); - read_lock(&tasklist_lock); - ret = __rt_schedulable(NULL, 0, 0); - read_unlock(&tasklist_lock); - mutex_unlock(&rt_constraints_mutex); - - return ret; -} - -static int sched_rt_can_attach(struct task_group *tg, struct task_struct *tsk) -{ - /* Don't accept realtime tasks when there is no way for them to run */ - if (rt_task(tsk) && tg->rt_bandwidth.rt_runtime == 0) - return 0; - - return 1; -} - -#else /* !CONFIG_RT_GROUP_SCHED */ -static int sched_rt_global_constraints(void) -{ - unsigned long flags; - int i; - - raw_spin_lock_irqsave(&def_rt_bandwidth.rt_runtime_lock, flags); - for_each_possible_cpu(i) { - struct rt_rq *rt_rq = &cpu_rq(i)->rt; - - raw_spin_lock(&rt_rq->rt_runtime_lock); - rt_rq->rt_runtime = global_rt_runtime(); - raw_spin_unlock(&rt_rq->rt_runtime_lock); - } - raw_spin_unlock_irqrestore(&def_rt_bandwidth.rt_runtime_lock, flags); - - return 0; -} -#endif /* CONFIG_RT_GROUP_SCHED */ - -static int sched_dl_global_validate(void) -{ - u64 runtime = global_rt_runtime(); - u64 period = global_rt_period(); - u64 new_bw = to_ratio(period, runtime); - struct dl_bw *dl_b; - int cpu, ret = 0; - unsigned long flags; - - /* - * Here we want to check the bandwidth not being set to some - * value smaller than the currently allocated bandwidth in - * any of the root_domains. - * - * FIXME: Cycling on all the CPUs is overdoing, but simpler than - * cycling on root_domains... Discussion on different/better - * solutions is welcome! - */ - for_each_possible_cpu(cpu) { - rcu_read_lock_sched(); - dl_b = dl_bw_of(cpu); - - raw_spin_lock_irqsave(&dl_b->lock, flags); - if (new_bw < dl_b->total_bw) - ret = -EBUSY; - raw_spin_unlock_irqrestore(&dl_b->lock, flags); - - rcu_read_unlock_sched(); - - if (ret) - break; - } - - return ret; -} - -static void sched_dl_do_global(void) -{ - u64 new_bw = -1; - struct dl_bw *dl_b; - int cpu; - unsigned long flags; - - def_dl_bandwidth.dl_period = global_rt_period(); - def_dl_bandwidth.dl_runtime = global_rt_runtime(); - - if (global_rt_runtime() != RUNTIME_INF) - new_bw = to_ratio(global_rt_period(), global_rt_runtime()); - - /* - * FIXME: As above... - */ - for_each_possible_cpu(cpu) { - rcu_read_lock_sched(); - dl_b = dl_bw_of(cpu); - - raw_spin_lock_irqsave(&dl_b->lock, flags); - dl_b->bw = new_bw; - raw_spin_unlock_irqrestore(&dl_b->lock, flags); - - rcu_read_unlock_sched(); - } -} - -static int sched_rt_global_validate(void) -{ - if (sysctl_sched_rt_period <= 0) - return -EINVAL; - - if ((sysctl_sched_rt_runtime != RUNTIME_INF) && - (sysctl_sched_rt_runtime > sysctl_sched_rt_period)) - return -EINVAL; - - return 0; -} - -static void sched_rt_do_global(void) -{ - def_rt_bandwidth.rt_runtime = global_rt_runtime(); - def_rt_bandwidth.rt_period = ns_to_ktime(global_rt_period()); -} - -int sched_rt_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - int old_period, old_runtime; - static DEFINE_MUTEX(mutex); - int ret; - - mutex_lock(&mutex); - old_period = sysctl_sched_rt_period; - old_runtime = sysctl_sched_rt_runtime; - - ret = proc_dointvec(table, write, buffer, lenp, ppos); - - if (!ret && write) { - ret = sched_rt_global_validate(); - if (ret) - goto undo; - - ret = sched_dl_global_validate(); - if (ret) - goto undo; - - ret = sched_rt_global_constraints(); - if (ret) - goto undo; - - sched_rt_do_global(); - sched_dl_do_global(); - } - if (0) { -undo: - sysctl_sched_rt_period = old_period; - sysctl_sched_rt_runtime = old_runtime; - } - mutex_unlock(&mutex); - - return ret; -} - -int sched_rr_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - int ret; - static DEFINE_MUTEX(mutex); - - mutex_lock(&mutex); - ret = proc_dointvec(table, write, buffer, lenp, ppos); - /* make sure that internally we keep jiffies */ - /* also, writing zero resets timeslice to default */ - if (!ret && write) { - sched_rr_timeslice = sched_rr_timeslice <= 0 ? - RR_TIMESLICE : msecs_to_jiffies(sched_rr_timeslice); - } - mutex_unlock(&mutex); - return ret; -} - -#ifdef CONFIG_CGROUP_SCHED - -static inline struct task_group *css_tg(struct cgroup_subsys_state *css) -{ - return css ? container_of(css, struct task_group, css) : NULL; -} - -static struct cgroup_subsys_state * -cpu_cgroup_css_alloc(struct cgroup_subsys_state *parent_css) -{ - struct task_group *parent = css_tg(parent_css); - struct task_group *tg; - - if (!parent) { - /* This is early initialization for the top cgroup */ - return &root_task_group.css; - } - - tg = sched_create_group(parent); - if (IS_ERR(tg)) - return ERR_PTR(-ENOMEM); - - sched_online_group(tg, parent); - - return &tg->css; -} - -static void cpu_cgroup_css_released(struct cgroup_subsys_state *css) -{ - struct task_group *tg = css_tg(css); - - sched_offline_group(tg); -} - -static void cpu_cgroup_css_free(struct cgroup_subsys_state *css) -{ - struct task_group *tg = css_tg(css); - - /* - * Relies on the RCU grace period between css_released() and this. - */ - sched_free_group(tg); -} - -/* - * This is called before wake_up_new_task(), therefore we really only - * have to set its group bits, all the other stuff does not apply. - */ -static void cpu_cgroup_fork(struct task_struct *task) -{ - struct rq_flags rf; - struct rq *rq; - - rq = task_rq_lock(task, &rf); - - sched_change_group(task, TASK_SET_GROUP); - - task_rq_unlock(rq, task, &rf); -} - -static int cpu_cgroup_can_attach(struct cgroup_taskset *tset) -{ - struct task_struct *task; - struct cgroup_subsys_state *css; - int ret = 0; - - cgroup_taskset_for_each(task, css, tset) { -#ifdef CONFIG_RT_GROUP_SCHED - if (!sched_rt_can_attach(css_tg(css), task)) - return -EINVAL; -#else - /* We don't support RT-tasks being in separate groups */ - if (task->sched_class != &fair_sched_class) - return -EINVAL; -#endif - /* - * Serialize against wake_up_new_task() such that if its - * running, we're sure to observe its full state. - */ - raw_spin_lock_irq(&task->pi_lock); - /* - * Avoid calling sched_move_task() before wake_up_new_task() - * has happened. This would lead to problems with PELT, due to - * move wanting to detach+attach while we're not attached yet. - */ - if (task->state == TASK_NEW) - ret = -EINVAL; - raw_spin_unlock_irq(&task->pi_lock); - - if (ret) - break; - } - return ret; -} - -static void cpu_cgroup_attach(struct cgroup_taskset *tset) -{ - struct task_struct *task; - struct cgroup_subsys_state *css; - - cgroup_taskset_for_each(task, css, tset) - sched_move_task(task); -} - -#ifdef CONFIG_FAIR_GROUP_SCHED -static int cpu_shares_write_u64(struct cgroup_subsys_state *css, - struct cftype *cftype, u64 shareval) -{ - return sched_group_set_shares(css_tg(css), scale_load(shareval)); -} - -static u64 cpu_shares_read_u64(struct cgroup_subsys_state *css, - struct cftype *cft) -{ - struct task_group *tg = css_tg(css); - - return (u64) scale_load_down(tg->shares); -} - -#ifdef CONFIG_CFS_BANDWIDTH -static DEFINE_MUTEX(cfs_constraints_mutex); - -const u64 max_cfs_quota_period = 1 * NSEC_PER_SEC; /* 1s */ -const u64 min_cfs_quota_period = 1 * NSEC_PER_MSEC; /* 1ms */ - -static int __cfs_schedulable(struct task_group *tg, u64 period, u64 runtime); - -static int tg_set_cfs_bandwidth(struct task_group *tg, u64 period, u64 quota) -{ - int i, ret = 0, runtime_enabled, runtime_was_enabled; - struct cfs_bandwidth *cfs_b = &tg->cfs_bandwidth; - - if (tg == &root_task_group) - return -EINVAL; - - /* - * Ensure we have at some amount of bandwidth every period. This is - * to prevent reaching a state of large arrears when throttled via - * entity_tick() resulting in prolonged exit starvation. - */ - if (quota < min_cfs_quota_period || period < min_cfs_quota_period) - return -EINVAL; - - /* - * Likewise, bound things on the otherside by preventing insane quota - * periods. This also allows us to normalize in computing quota - * feasibility. - */ - if (period > max_cfs_quota_period) - return -EINVAL; - - /* - * Prevent race between setting of cfs_rq->runtime_enabled and - * unthrottle_offline_cfs_rqs(). - */ - get_online_cpus(); - mutex_lock(&cfs_constraints_mutex); - ret = __cfs_schedulable(tg, period, quota); - if (ret) - goto out_unlock; - - runtime_enabled = quota != RUNTIME_INF; - runtime_was_enabled = cfs_b->quota != RUNTIME_INF; - /* - * If we need to toggle cfs_bandwidth_used, off->on must occur - * before making related changes, and on->off must occur afterwards - */ - if (runtime_enabled && !runtime_was_enabled) - cfs_bandwidth_usage_inc(); - raw_spin_lock_irq(&cfs_b->lock); - cfs_b->period = ns_to_ktime(period); - cfs_b->quota = quota; - - __refill_cfs_bandwidth_runtime(cfs_b); - /* restart the period timer (if active) to handle new period expiry */ - if (runtime_enabled) - start_cfs_bandwidth(cfs_b); - raw_spin_unlock_irq(&cfs_b->lock); - - for_each_online_cpu(i) { - struct cfs_rq *cfs_rq = tg->cfs_rq[i]; - struct rq *rq = cfs_rq->rq; - - raw_spin_lock_irq(&rq->lock); - cfs_rq->runtime_enabled = runtime_enabled; - cfs_rq->runtime_remaining = 0; - - if (cfs_rq->throttled) - unthrottle_cfs_rq(cfs_rq); - raw_spin_unlock_irq(&rq->lock); - } - if (runtime_was_enabled && !runtime_enabled) - cfs_bandwidth_usage_dec(); -out_unlock: - mutex_unlock(&cfs_constraints_mutex); - put_online_cpus(); - - return ret; -} - -int tg_set_cfs_quota(struct task_group *tg, long cfs_quota_us) -{ - u64 quota, period; - - period = ktime_to_ns(tg->cfs_bandwidth.period); - if (cfs_quota_us < 0) - quota = RUNTIME_INF; - else - quota = (u64)cfs_quota_us * NSEC_PER_USEC; - - return tg_set_cfs_bandwidth(tg, period, quota); -} - -long tg_get_cfs_quota(struct task_group *tg) -{ - u64 quota_us; - - if (tg->cfs_bandwidth.quota == RUNTIME_INF) - return -1; - - quota_us = tg->cfs_bandwidth.quota; - do_div(quota_us, NSEC_PER_USEC); - - return quota_us; -} - -int tg_set_cfs_period(struct task_group *tg, long cfs_period_us) -{ - u64 quota, period; - - period = (u64)cfs_period_us * NSEC_PER_USEC; - quota = tg->cfs_bandwidth.quota; - - return tg_set_cfs_bandwidth(tg, period, quota); -} - -long tg_get_cfs_period(struct task_group *tg) -{ - u64 cfs_period_us; - - cfs_period_us = ktime_to_ns(tg->cfs_bandwidth.period); - do_div(cfs_period_us, NSEC_PER_USEC); - - return cfs_period_us; -} - -static s64 cpu_cfs_quota_read_s64(struct cgroup_subsys_state *css, - struct cftype *cft) -{ - return tg_get_cfs_quota(css_tg(css)); -} - -static int cpu_cfs_quota_write_s64(struct cgroup_subsys_state *css, - struct cftype *cftype, s64 cfs_quota_us) -{ - return tg_set_cfs_quota(css_tg(css), cfs_quota_us); -} - -static u64 cpu_cfs_period_read_u64(struct cgroup_subsys_state *css, - struct cftype *cft) -{ - return tg_get_cfs_period(css_tg(css)); -} - -static int cpu_cfs_period_write_u64(struct cgroup_subsys_state *css, - struct cftype *cftype, u64 cfs_period_us) -{ - return tg_set_cfs_period(css_tg(css), cfs_period_us); -} - -struct cfs_schedulable_data { - struct task_group *tg; - u64 period, quota; -}; - -/* - * normalize group quota/period to be quota/max_period - * note: units are usecs - */ -static u64 normalize_cfs_quota(struct task_group *tg, - struct cfs_schedulable_data *d) -{ - u64 quota, period; - - if (tg == d->tg) { - period = d->period; - quota = d->quota; - } else { - period = tg_get_cfs_period(tg); - quota = tg_get_cfs_quota(tg); - } - - /* note: these should typically be equivalent */ - if (quota == RUNTIME_INF || quota == -1) - return RUNTIME_INF; - - return to_ratio(period, quota); -} - -static int tg_cfs_schedulable_down(struct task_group *tg, void *data) -{ - struct cfs_schedulable_data *d = data; - struct cfs_bandwidth *cfs_b = &tg->cfs_bandwidth; - s64 quota = 0, parent_quota = -1; - - if (!tg->parent) { - quota = RUNTIME_INF; - } else { - struct cfs_bandwidth *parent_b = &tg->parent->cfs_bandwidth; - - quota = normalize_cfs_quota(tg, d); - parent_quota = parent_b->hierarchical_quota; - - /* - * ensure max(child_quota) <= parent_quota, inherit when no - * limit is set - */ - if (quota == RUNTIME_INF) - quota = parent_quota; - else if (parent_quota != RUNTIME_INF && quota > parent_quota) - return -EINVAL; - } - cfs_b->hierarchical_quota = quota; - - return 0; -} - -static int __cfs_schedulable(struct task_group *tg, u64 period, u64 quota) -{ - int ret; - struct cfs_schedulable_data data = { - .tg = tg, - .period = period, - .quota = quota, - }; - - if (quota != RUNTIME_INF) { - do_div(data.period, NSEC_PER_USEC); - do_div(data.quota, NSEC_PER_USEC); - } - - rcu_read_lock(); - ret = walk_tg_tree(tg_cfs_schedulable_down, tg_nop, &data); - rcu_read_unlock(); - - return ret; -} - -static int cpu_stats_show(struct seq_file *sf, void *v) -{ - struct task_group *tg = css_tg(seq_css(sf)); - struct cfs_bandwidth *cfs_b = &tg->cfs_bandwidth; - - seq_printf(sf, "nr_periods %d\n", cfs_b->nr_periods); - seq_printf(sf, "nr_throttled %d\n", cfs_b->nr_throttled); - seq_printf(sf, "throttled_time %llu\n", cfs_b->throttled_time); - - return 0; -} -#endif /* CONFIG_CFS_BANDWIDTH */ -#endif /* CONFIG_FAIR_GROUP_SCHED */ - -#ifdef CONFIG_RT_GROUP_SCHED -static int cpu_rt_runtime_write(struct cgroup_subsys_state *css, - struct cftype *cft, s64 val) -{ - return sched_group_set_rt_runtime(css_tg(css), val); -} - -static s64 cpu_rt_runtime_read(struct cgroup_subsys_state *css, - struct cftype *cft) -{ - return sched_group_rt_runtime(css_tg(css)); -} - -static int cpu_rt_period_write_uint(struct cgroup_subsys_state *css, - struct cftype *cftype, u64 rt_period_us) -{ - return sched_group_set_rt_period(css_tg(css), rt_period_us); -} - -static u64 cpu_rt_period_read_uint(struct cgroup_subsys_state *css, - struct cftype *cft) -{ - return sched_group_rt_period(css_tg(css)); -} -#endif /* CONFIG_RT_GROUP_SCHED */ - -static struct cftype cpu_files[] = { -#ifdef CONFIG_FAIR_GROUP_SCHED - { - .name = "shares", - .read_u64 = cpu_shares_read_u64, - .write_u64 = cpu_shares_write_u64, - }, -#endif -#ifdef CONFIG_CFS_BANDWIDTH - { - .name = "cfs_quota_us", - .read_s64 = cpu_cfs_quota_read_s64, - .write_s64 = cpu_cfs_quota_write_s64, - }, - { - .name = "cfs_period_us", - .read_u64 = cpu_cfs_period_read_u64, - .write_u64 = cpu_cfs_period_write_u64, - }, - { - .name = "stat", - .seq_show = cpu_stats_show, - }, -#endif -#ifdef CONFIG_RT_GROUP_SCHED - { - .name = "rt_runtime_us", - .read_s64 = cpu_rt_runtime_read, - .write_s64 = cpu_rt_runtime_write, - }, - { - .name = "rt_period_us", - .read_u64 = cpu_rt_period_read_uint, - .write_u64 = cpu_rt_period_write_uint, - }, -#endif - { } /* terminate */ -}; - -struct cgroup_subsys cpu_cgrp_subsys = { - .css_alloc = cpu_cgroup_css_alloc, - .css_released = cpu_cgroup_css_released, - .css_free = cpu_cgroup_css_free, - .fork = cpu_cgroup_fork, - .can_attach = cpu_cgroup_can_attach, - .attach = cpu_cgroup_attach, - .legacy_cftypes = cpu_files, - .early_init = true, -}; - -#endif /* CONFIG_CGROUP_SCHED */ - -void dump_cpu_task(int cpu) -{ - pr_info("Task dump for CPU %d:\n", cpu); - sched_show_task(cpu_curr(cpu)); -} - -/* - * Nice levels are multiplicative, with a gentle 10% change for every - * nice level changed. I.e. when a CPU-bound task goes from nice 0 to - * nice 1, it will get ~10% less CPU time than another CPU-bound task - * that remained on nice 0. - * - * The "10% effect" is relative and cumulative: from _any_ nice level, - * if you go up 1 level, it's -10% CPU usage, if you go down 1 level - * it's +10% CPU usage. (to achieve that we use a multiplier of 1.25. - * If a task goes up by ~10% and another task goes down by ~10% then - * the relative distance between them is ~25%.) - */ -const int sched_prio_to_weight[40] = { - /* -20 */ 88761, 71755, 56483, 46273, 36291, - /* -15 */ 29154, 23254, 18705, 14949, 11916, - /* -10 */ 9548, 7620, 6100, 4904, 3906, - /* -5 */ 3121, 2501, 1991, 1586, 1277, - /* 0 */ 1024, 820, 655, 526, 423, - /* 5 */ 335, 272, 215, 172, 137, - /* 10 */ 110, 87, 70, 56, 45, - /* 15 */ 36, 29, 23, 18, 15, -}; - -/* - * Inverse (2^32/x) values of the sched_prio_to_weight[] array, precalculated. - * - * In cases where the weight does not change often, we can use the - * precalculated inverse to speed up arithmetics by turning divisions - * into multiplications: - */ -const u32 sched_prio_to_wmult[40] = { - /* -20 */ 48388, 59856, 76040, 92818, 118348, - /* -15 */ 147320, 184698, 229616, 287308, 360437, - /* -10 */ 449829, 563644, 704093, 875809, 1099582, - /* -5 */ 1376151, 1717300, 2157191, 2708050, 3363326, - /* 0 */ 4194304, 5237765, 6557202, 8165337, 10153587, - /* 5 */ 12820798, 15790321, 19976592, 24970740, 31350126, - /* 10 */ 39045157, 49367440, 61356676, 76695844, 95443717, - /* 15 */ 119304647, 148102320, 186737708, 238609294, 286331153, -}; diff --git a/src/linux/kernel/sched/cpuacct.h b/src/linux/kernel/sched/cpuacct.h deleted file mode 100644 index ba72807..0000000 --- a/src/linux/kernel/sched/cpuacct.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifdef CONFIG_CGROUP_CPUACCT - -extern void cpuacct_charge(struct task_struct *tsk, u64 cputime); -extern void cpuacct_account_field(struct task_struct *tsk, int index, u64 val); - -#else - -static inline void cpuacct_charge(struct task_struct *tsk, u64 cputime) -{ -} - -static inline void -cpuacct_account_field(struct task_struct *tsk, int index, u64 val) -{ -} - -#endif diff --git a/src/linux/kernel/sched/cpudeadline.h b/src/linux/kernel/sched/cpudeadline.h deleted file mode 100644 index f7da8c5..0000000 --- a/src/linux/kernel/sched/cpudeadline.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _LINUX_CPUDL_H -#define _LINUX_CPUDL_H - -#include -#include - -#define IDX_INVALID -1 - -struct cpudl_item { - u64 dl; - int cpu; - int idx; -}; - -struct cpudl { - raw_spinlock_t lock; - int size; - cpumask_var_t free_cpus; - struct cpudl_item *elements; -}; - - -#ifdef CONFIG_SMP -int cpudl_find(struct cpudl *cp, struct task_struct *p, - struct cpumask *later_mask); -void cpudl_set(struct cpudl *cp, int cpu, u64 dl); -void cpudl_clear(struct cpudl *cp, int cpu); -int cpudl_init(struct cpudl *cp); -void cpudl_set_freecpu(struct cpudl *cp, int cpu); -void cpudl_clear_freecpu(struct cpudl *cp, int cpu); -void cpudl_cleanup(struct cpudl *cp); -#endif /* CONFIG_SMP */ - -#endif /* _LINUX_CPUDL_H */ diff --git a/src/linux/kernel/sched/cpupri.h b/src/linux/kernel/sched/cpupri.h deleted file mode 100644 index 63cbb9c..0000000 --- a/src/linux/kernel/sched/cpupri.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _LINUX_CPUPRI_H -#define _LINUX_CPUPRI_H - -#include - -#define CPUPRI_NR_PRIORITIES (MAX_RT_PRIO + 2) - -#define CPUPRI_INVALID -1 -#define CPUPRI_IDLE 0 -#define CPUPRI_NORMAL 1 -/* values 2-101 are RT priorities 0-99 */ - -struct cpupri_vec { - atomic_t count; - cpumask_var_t mask; -}; - -struct cpupri { - struct cpupri_vec pri_to_cpu[CPUPRI_NR_PRIORITIES]; - int *cpu_to_pri; -}; - -#ifdef CONFIG_SMP -int cpupri_find(struct cpupri *cp, - struct task_struct *p, struct cpumask *lowest_mask); -void cpupri_set(struct cpupri *cp, int cpu, int pri); -int cpupri_init(struct cpupri *cp); -void cpupri_cleanup(struct cpupri *cp); -#endif - -#endif /* _LINUX_CPUPRI_H */ diff --git a/src/linux/kernel/sched/cputime.c b/src/linux/kernel/sched/cputime.c deleted file mode 100644 index 5ebee31..0000000 --- a/src/linux/kernel/sched/cputime.c +++ /dev/null @@ -1,947 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "sched.h" -#ifdef CONFIG_PARAVIRT -#include -#endif - - -#ifdef CONFIG_IRQ_TIME_ACCOUNTING - -/* - * There are no locks covering percpu hardirq/softirq time. - * They are only modified in vtime_account, on corresponding CPU - * with interrupts disabled. So, writes are safe. - * They are read and saved off onto struct rq in update_rq_clock(). - * This may result in other CPU reading this CPU's irq time and can - * race with irq/vtime_account on this CPU. We would either get old - * or new value with a side effect of accounting a slice of irq time to wrong - * task when irq is in progress while we read rq->clock. That is a worthy - * compromise in place of having locks on each irq in account_system_time. - */ -DEFINE_PER_CPU(struct irqtime, cpu_irqtime); - -static int sched_clock_irqtime; - -void enable_sched_clock_irqtime(void) -{ - sched_clock_irqtime = 1; -} - -void disable_sched_clock_irqtime(void) -{ - sched_clock_irqtime = 0; -} - -/* - * Called before incrementing preempt_count on {soft,}irq_enter - * and before decrementing preempt_count on {soft,}irq_exit. - */ -void irqtime_account_irq(struct task_struct *curr) -{ - struct irqtime *irqtime = this_cpu_ptr(&cpu_irqtime); - s64 delta; - int cpu; - - if (!sched_clock_irqtime) - return; - - cpu = smp_processor_id(); - delta = sched_clock_cpu(cpu) - irqtime->irq_start_time; - irqtime->irq_start_time += delta; - - u64_stats_update_begin(&irqtime->sync); - /* - * We do not account for softirq time from ksoftirqd here. - * We want to continue accounting softirq time to ksoftirqd thread - * in that case, so as not to confuse scheduler with a special task - * that do not consume any time, but still wants to run. - */ - if (hardirq_count()) - irqtime->hardirq_time += delta; - else if (in_serving_softirq() && curr != this_cpu_ksoftirqd()) - irqtime->softirq_time += delta; - - u64_stats_update_end(&irqtime->sync); -} -EXPORT_SYMBOL_GPL(irqtime_account_irq); - -static cputime_t irqtime_account_update(u64 irqtime, int idx, cputime_t maxtime) -{ - u64 *cpustat = kcpustat_this_cpu->cpustat; - cputime_t irq_cputime; - - irq_cputime = nsecs_to_cputime64(irqtime) - cpustat[idx]; - irq_cputime = min(irq_cputime, maxtime); - cpustat[idx] += irq_cputime; - - return irq_cputime; -} - -static cputime_t irqtime_account_hi_update(cputime_t maxtime) -{ - return irqtime_account_update(__this_cpu_read(cpu_irqtime.hardirq_time), - CPUTIME_IRQ, maxtime); -} - -static cputime_t irqtime_account_si_update(cputime_t maxtime) -{ - return irqtime_account_update(__this_cpu_read(cpu_irqtime.softirq_time), - CPUTIME_SOFTIRQ, maxtime); -} - -#else /* CONFIG_IRQ_TIME_ACCOUNTING */ - -#define sched_clock_irqtime (0) - -static cputime_t irqtime_account_hi_update(cputime_t dummy) -{ - return 0; -} - -static cputime_t irqtime_account_si_update(cputime_t dummy) -{ - return 0; -} - -#endif /* !CONFIG_IRQ_TIME_ACCOUNTING */ - -static inline void task_group_account_field(struct task_struct *p, int index, - u64 tmp) -{ - /* - * Since all updates are sure to touch the root cgroup, we - * get ourselves ahead and touch it first. If the root cgroup - * is the only cgroup, then nothing else should be necessary. - * - */ - __this_cpu_add(kernel_cpustat.cpustat[index], tmp); - - cpuacct_account_field(p, index, tmp); -} - -/* - * Account user cpu time to a process. - * @p: the process that the cpu time gets accounted to - * @cputime: the cpu time spent in user space since the last update - * @cputime_scaled: cputime scaled by cpu frequency - */ -void account_user_time(struct task_struct *p, cputime_t cputime, - cputime_t cputime_scaled) -{ - int index; - - /* Add user time to process. */ - p->utime += cputime; - p->utimescaled += cputime_scaled; - account_group_user_time(p, cputime); - - index = (task_nice(p) > 0) ? CPUTIME_NICE : CPUTIME_USER; - - /* Add user time to cpustat. */ - task_group_account_field(p, index, (__force u64) cputime); - - /* Account for user time used */ - acct_account_cputime(p); -} - -/* - * Account guest cpu time to a process. - * @p: the process that the cpu time gets accounted to - * @cputime: the cpu time spent in virtual machine since the last update - * @cputime_scaled: cputime scaled by cpu frequency - */ -static void account_guest_time(struct task_struct *p, cputime_t cputime, - cputime_t cputime_scaled) -{ - u64 *cpustat = kcpustat_this_cpu->cpustat; - - /* Add guest time to process. */ - p->utime += cputime; - p->utimescaled += cputime_scaled; - account_group_user_time(p, cputime); - p->gtime += cputime; - - /* Add guest time to cpustat. */ - if (task_nice(p) > 0) { - cpustat[CPUTIME_NICE] += (__force u64) cputime; - cpustat[CPUTIME_GUEST_NICE] += (__force u64) cputime; - } else { - cpustat[CPUTIME_USER] += (__force u64) cputime; - cpustat[CPUTIME_GUEST] += (__force u64) cputime; - } -} - -/* - * Account system cpu time to a process and desired cpustat field - * @p: the process that the cpu time gets accounted to - * @cputime: the cpu time spent in kernel space since the last update - * @cputime_scaled: cputime scaled by cpu frequency - * @target_cputime64: pointer to cpustat field that has to be updated - */ -static inline -void __account_system_time(struct task_struct *p, cputime_t cputime, - cputime_t cputime_scaled, int index) -{ - /* Add system time to process. */ - p->stime += cputime; - p->stimescaled += cputime_scaled; - account_group_system_time(p, cputime); - - /* Add system time to cpustat. */ - task_group_account_field(p, index, (__force u64) cputime); - - /* Account for system time used */ - acct_account_cputime(p); -} - -/* - * Account system cpu time to a process. - * @p: the process that the cpu time gets accounted to - * @hardirq_offset: the offset to subtract from hardirq_count() - * @cputime: the cpu time spent in kernel space since the last update - * @cputime_scaled: cputime scaled by cpu frequency - */ -void account_system_time(struct task_struct *p, int hardirq_offset, - cputime_t cputime, cputime_t cputime_scaled) -{ - int index; - - if ((p->flags & PF_VCPU) && (irq_count() - hardirq_offset == 0)) { - account_guest_time(p, cputime, cputime_scaled); - return; - } - - if (hardirq_count() - hardirq_offset) - index = CPUTIME_IRQ; - else if (in_serving_softirq()) - index = CPUTIME_SOFTIRQ; - else - index = CPUTIME_SYSTEM; - - __account_system_time(p, cputime, cputime_scaled, index); -} - -/* - * Account for involuntary wait time. - * @cputime: the cpu time spent in involuntary wait - */ -void account_steal_time(cputime_t cputime) -{ - u64 *cpustat = kcpustat_this_cpu->cpustat; - - cpustat[CPUTIME_STEAL] += (__force u64) cputime; -} - -/* - * Account for idle time. - * @cputime: the cpu time spent in idle wait - */ -void account_idle_time(cputime_t cputime) -{ - u64 *cpustat = kcpustat_this_cpu->cpustat; - struct rq *rq = this_rq(); - - if (atomic_read(&rq->nr_iowait) > 0) - cpustat[CPUTIME_IOWAIT] += (__force u64) cputime; - else - cpustat[CPUTIME_IDLE] += (__force u64) cputime; -} - -/* - * When a guest is interrupted for a longer amount of time, missed clock - * ticks are not redelivered later. Due to that, this function may on - * occasion account more time than the calling functions think elapsed. - */ -static __always_inline cputime_t steal_account_process_time(cputime_t maxtime) -{ -#ifdef CONFIG_PARAVIRT - if (static_key_false(¶virt_steal_enabled)) { - cputime_t steal_cputime; - u64 steal; - - steal = paravirt_steal_clock(smp_processor_id()); - steal -= this_rq()->prev_steal_time; - - steal_cputime = min(nsecs_to_cputime(steal), maxtime); - account_steal_time(steal_cputime); - this_rq()->prev_steal_time += cputime_to_nsecs(steal_cputime); - - return steal_cputime; - } -#endif - return 0; -} - -/* - * Account how much elapsed time was spent in steal, irq, or softirq time. - */ -static inline cputime_t account_other_time(cputime_t max) -{ - cputime_t accounted; - - /* Shall be converted to a lockdep-enabled lightweight check */ - WARN_ON_ONCE(!irqs_disabled()); - - accounted = steal_account_process_time(max); - - if (accounted < max) - accounted += irqtime_account_hi_update(max - accounted); - - if (accounted < max) - accounted += irqtime_account_si_update(max - accounted); - - return accounted; -} - -#ifdef CONFIG_64BIT -static inline u64 read_sum_exec_runtime(struct task_struct *t) -{ - return t->se.sum_exec_runtime; -} -#else -static u64 read_sum_exec_runtime(struct task_struct *t) -{ - u64 ns; - struct rq_flags rf; - struct rq *rq; - - rq = task_rq_lock(t, &rf); - ns = t->se.sum_exec_runtime; - task_rq_unlock(rq, t, &rf); - - return ns; -} -#endif - -/* - * Accumulate raw cputime values of dead tasks (sig->[us]time) and live - * tasks (sum on group iteration) belonging to @tsk's group. - */ -void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times) -{ - struct signal_struct *sig = tsk->signal; - cputime_t utime, stime; - struct task_struct *t; - unsigned int seq, nextseq; - unsigned long flags; - - /* - * Update current task runtime to account pending time since last - * scheduler action or thread_group_cputime() call. This thread group - * might have other running tasks on different CPUs, but updating - * their runtime can affect syscall performance, so we skip account - * those pending times and rely only on values updated on tick or - * other scheduler action. - */ - if (same_thread_group(current, tsk)) - (void) task_sched_runtime(current); - - rcu_read_lock(); - /* Attempt a lockless read on the first round. */ - nextseq = 0; - do { - seq = nextseq; - flags = read_seqbegin_or_lock_irqsave(&sig->stats_lock, &seq); - times->utime = sig->utime; - times->stime = sig->stime; - times->sum_exec_runtime = sig->sum_sched_runtime; - - for_each_thread(tsk, t) { - task_cputime(t, &utime, &stime); - times->utime += utime; - times->stime += stime; - times->sum_exec_runtime += read_sum_exec_runtime(t); - } - /* If lockless access failed, take the lock. */ - nextseq = 1; - } while (need_seqretry(&sig->stats_lock, seq)); - done_seqretry_irqrestore(&sig->stats_lock, seq, flags); - rcu_read_unlock(); -} - -#ifdef CONFIG_IRQ_TIME_ACCOUNTING -/* - * Account a tick to a process and cpustat - * @p: the process that the cpu time gets accounted to - * @user_tick: is the tick from userspace - * @rq: the pointer to rq - * - * Tick demultiplexing follows the order - * - pending hardirq update - * - pending softirq update - * - user_time - * - idle_time - * - system time - * - check for guest_time - * - else account as system_time - * - * Check for hardirq is done both for system and user time as there is - * no timer going off while we are on hardirq and hence we may never get an - * opportunity to update it solely in system time. - * p->stime and friends are only updated on system time and not on irq - * softirq as those do not count in task exec_runtime any more. - */ -static void irqtime_account_process_tick(struct task_struct *p, int user_tick, - struct rq *rq, int ticks) -{ - u64 cputime = (__force u64) cputime_one_jiffy * ticks; - cputime_t scaled, other; - - /* - * When returning from idle, many ticks can get accounted at - * once, including some ticks of steal, irq, and softirq time. - * Subtract those ticks from the amount of time accounted to - * idle, or potentially user or system time. Due to rounding, - * other time can exceed ticks occasionally. - */ - other = account_other_time(ULONG_MAX); - if (other >= cputime) - return; - cputime -= other; - scaled = cputime_to_scaled(cputime); - - if (this_cpu_ksoftirqd() == p) { - /* - * ksoftirqd time do not get accounted in cpu_softirq_time. - * So, we have to handle it separately here. - * Also, p->stime needs to be updated for ksoftirqd. - */ - __account_system_time(p, cputime, scaled, CPUTIME_SOFTIRQ); - } else if (user_tick) { - account_user_time(p, cputime, scaled); - } else if (p == rq->idle) { - account_idle_time(cputime); - } else if (p->flags & PF_VCPU) { /* System time or guest time */ - account_guest_time(p, cputime, scaled); - } else { - __account_system_time(p, cputime, scaled, CPUTIME_SYSTEM); - } -} - -static void irqtime_account_idle_ticks(int ticks) -{ - struct rq *rq = this_rq(); - - irqtime_account_process_tick(current, 0, rq, ticks); -} -#else /* CONFIG_IRQ_TIME_ACCOUNTING */ -static inline void irqtime_account_idle_ticks(int ticks) {} -static inline void irqtime_account_process_tick(struct task_struct *p, int user_tick, - struct rq *rq, int nr_ticks) {} -#endif /* CONFIG_IRQ_TIME_ACCOUNTING */ - -/* - * Use precise platform statistics if available: - */ -#ifdef CONFIG_VIRT_CPU_ACCOUNTING - -#ifndef __ARCH_HAS_VTIME_TASK_SWITCH -void vtime_common_task_switch(struct task_struct *prev) -{ - if (is_idle_task(prev)) - vtime_account_idle(prev); - else - vtime_account_system(prev); - -#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE - vtime_account_user(prev); -#endif - arch_vtime_task_switch(prev); -} -#endif - -#endif /* CONFIG_VIRT_CPU_ACCOUNTING */ - - -#ifdef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE -/* - * Archs that account the whole time spent in the idle task - * (outside irq) as idle time can rely on this and just implement - * vtime_account_system() and vtime_account_idle(). Archs that - * have other meaning of the idle time (s390 only includes the - * time spent by the CPU when it's in low power mode) must override - * vtime_account(). - */ -#ifndef __ARCH_HAS_VTIME_ACCOUNT -void vtime_account_irq_enter(struct task_struct *tsk) -{ - if (!in_interrupt() && is_idle_task(tsk)) - vtime_account_idle(tsk); - else - vtime_account_system(tsk); -} -EXPORT_SYMBOL_GPL(vtime_account_irq_enter); -#endif /* __ARCH_HAS_VTIME_ACCOUNT */ - -void task_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st) -{ - *ut = p->utime; - *st = p->stime; -} -EXPORT_SYMBOL_GPL(task_cputime_adjusted); - -void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st) -{ - struct task_cputime cputime; - - thread_group_cputime(p, &cputime); - - *ut = cputime.utime; - *st = cputime.stime; -} -#else /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ -/* - * Account a single tick of cpu time. - * @p: the process that the cpu time gets accounted to - * @user_tick: indicates if the tick is a user or a system tick - */ -void account_process_tick(struct task_struct *p, int user_tick) -{ - cputime_t cputime, scaled, steal; - struct rq *rq = this_rq(); - - if (vtime_accounting_cpu_enabled()) - return; - - if (sched_clock_irqtime) { - irqtime_account_process_tick(p, user_tick, rq, 1); - return; - } - - cputime = cputime_one_jiffy; - steal = steal_account_process_time(ULONG_MAX); - - if (steal >= cputime) - return; - - cputime -= steal; - scaled = cputime_to_scaled(cputime); - - if (user_tick) - account_user_time(p, cputime, scaled); - else if ((p != rq->idle) || (irq_count() != HARDIRQ_OFFSET)) - account_system_time(p, HARDIRQ_OFFSET, cputime, scaled); - else - account_idle_time(cputime); -} - -/* - * Account multiple ticks of idle time. - * @ticks: number of stolen ticks - */ -void account_idle_ticks(unsigned long ticks) -{ - cputime_t cputime, steal; - - if (sched_clock_irqtime) { - irqtime_account_idle_ticks(ticks); - return; - } - - cputime = jiffies_to_cputime(ticks); - steal = steal_account_process_time(ULONG_MAX); - - if (steal >= cputime) - return; - - cputime -= steal; - account_idle_time(cputime); -} - -/* - * Perform (stime * rtime) / total, but avoid multiplication overflow by - * loosing precision when the numbers are big. - */ -static cputime_t scale_stime(u64 stime, u64 rtime, u64 total) -{ - u64 scaled; - - for (;;) { - /* Make sure "rtime" is the bigger of stime/rtime */ - if (stime > rtime) - swap(rtime, stime); - - /* Make sure 'total' fits in 32 bits */ - if (total >> 32) - goto drop_precision; - - /* Does rtime (and thus stime) fit in 32 bits? */ - if (!(rtime >> 32)) - break; - - /* Can we just balance rtime/stime rather than dropping bits? */ - if (stime >> 31) - goto drop_precision; - - /* We can grow stime and shrink rtime and try to make them both fit */ - stime <<= 1; - rtime >>= 1; - continue; - -drop_precision: - /* We drop from rtime, it has more bits than stime */ - rtime >>= 1; - total >>= 1; - } - - /* - * Make sure gcc understands that this is a 32x32->64 multiply, - * followed by a 64/32->64 divide. - */ - scaled = div_u64((u64) (u32) stime * (u64) (u32) rtime, (u32)total); - return (__force cputime_t) scaled; -} - -/* - * Adjust tick based cputime random precision against scheduler runtime - * accounting. - * - * Tick based cputime accounting depend on random scheduling timeslices of a - * task to be interrupted or not by the timer. Depending on these - * circumstances, the number of these interrupts may be over or - * under-optimistic, matching the real user and system cputime with a variable - * precision. - * - * Fix this by scaling these tick based values against the total runtime - * accounted by the CFS scheduler. - * - * This code provides the following guarantees: - * - * stime + utime == rtime - * stime_i+1 >= stime_i, utime_i+1 >= utime_i - * - * Assuming that rtime_i+1 >= rtime_i. - */ -static void cputime_adjust(struct task_cputime *curr, - struct prev_cputime *prev, - cputime_t *ut, cputime_t *st) -{ - cputime_t rtime, stime, utime; - unsigned long flags; - - /* Serialize concurrent callers such that we can honour our guarantees */ - raw_spin_lock_irqsave(&prev->lock, flags); - rtime = nsecs_to_cputime(curr->sum_exec_runtime); - - /* - * This is possible under two circumstances: - * - rtime isn't monotonic after all (a bug); - * - we got reordered by the lock. - * - * In both cases this acts as a filter such that the rest of the code - * can assume it is monotonic regardless of anything else. - */ - if (prev->stime + prev->utime >= rtime) - goto out; - - stime = curr->stime; - utime = curr->utime; - - /* - * If either stime or both stime and utime are 0, assume all runtime is - * userspace. Once a task gets some ticks, the monotonicy code at - * 'update' will ensure things converge to the observed ratio. - */ - if (stime == 0) { - utime = rtime; - goto update; - } - - if (utime == 0) { - stime = rtime; - goto update; - } - - stime = scale_stime((__force u64)stime, (__force u64)rtime, - (__force u64)(stime + utime)); - -update: - /* - * Make sure stime doesn't go backwards; this preserves monotonicity - * for utime because rtime is monotonic. - * - * utime_i+1 = rtime_i+1 - stime_i - * = rtime_i+1 - (rtime_i - utime_i) - * = (rtime_i+1 - rtime_i) + utime_i - * >= utime_i - */ - if (stime < prev->stime) - stime = prev->stime; - utime = rtime - stime; - - /* - * Make sure utime doesn't go backwards; this still preserves - * monotonicity for stime, analogous argument to above. - */ - if (utime < prev->utime) { - utime = prev->utime; - stime = rtime - utime; - } - - prev->stime = stime; - prev->utime = utime; -out: - *ut = prev->utime; - *st = prev->stime; - raw_spin_unlock_irqrestore(&prev->lock, flags); -} - -void task_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st) -{ - struct task_cputime cputime = { - .sum_exec_runtime = p->se.sum_exec_runtime, - }; - - task_cputime(p, &cputime.utime, &cputime.stime); - cputime_adjust(&cputime, &p->prev_cputime, ut, st); -} -EXPORT_SYMBOL_GPL(task_cputime_adjusted); - -void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st) -{ - struct task_cputime cputime; - - thread_group_cputime(p, &cputime); - cputime_adjust(&cputime, &p->signal->prev_cputime, ut, st); -} -#endif /* !CONFIG_VIRT_CPU_ACCOUNTING_NATIVE */ - -#ifdef CONFIG_VIRT_CPU_ACCOUNTING_GEN -static cputime_t vtime_delta(struct task_struct *tsk) -{ - unsigned long now = READ_ONCE(jiffies); - - if (time_before(now, (unsigned long)tsk->vtime_snap)) - return 0; - - return jiffies_to_cputime(now - tsk->vtime_snap); -} - -static cputime_t get_vtime_delta(struct task_struct *tsk) -{ - unsigned long now = READ_ONCE(jiffies); - cputime_t delta, other; - - /* - * Unlike tick based timing, vtime based timing never has lost - * ticks, and no need for steal time accounting to make up for - * lost ticks. Vtime accounts a rounded version of actual - * elapsed time. Limit account_other_time to prevent rounding - * errors from causing elapsed vtime to go negative. - */ - delta = jiffies_to_cputime(now - tsk->vtime_snap); - other = account_other_time(delta); - WARN_ON_ONCE(tsk->vtime_snap_whence == VTIME_INACTIVE); - tsk->vtime_snap = now; - - return delta - other; -} - -static void __vtime_account_system(struct task_struct *tsk) -{ - cputime_t delta_cpu = get_vtime_delta(tsk); - - account_system_time(tsk, irq_count(), delta_cpu, cputime_to_scaled(delta_cpu)); -} - -void vtime_account_system(struct task_struct *tsk) -{ - if (!vtime_delta(tsk)) - return; - - write_seqcount_begin(&tsk->vtime_seqcount); - __vtime_account_system(tsk); - write_seqcount_end(&tsk->vtime_seqcount); -} - -void vtime_account_user(struct task_struct *tsk) -{ - cputime_t delta_cpu; - - write_seqcount_begin(&tsk->vtime_seqcount); - tsk->vtime_snap_whence = VTIME_SYS; - if (vtime_delta(tsk)) { - delta_cpu = get_vtime_delta(tsk); - account_user_time(tsk, delta_cpu, cputime_to_scaled(delta_cpu)); - } - write_seqcount_end(&tsk->vtime_seqcount); -} - -void vtime_user_enter(struct task_struct *tsk) -{ - write_seqcount_begin(&tsk->vtime_seqcount); - if (vtime_delta(tsk)) - __vtime_account_system(tsk); - tsk->vtime_snap_whence = VTIME_USER; - write_seqcount_end(&tsk->vtime_seqcount); -} - -void vtime_guest_enter(struct task_struct *tsk) -{ - /* - * The flags must be updated under the lock with - * the vtime_snap flush and update. - * That enforces a right ordering and update sequence - * synchronization against the reader (task_gtime()) - * that can thus safely catch up with a tickless delta. - */ - write_seqcount_begin(&tsk->vtime_seqcount); - if (vtime_delta(tsk)) - __vtime_account_system(tsk); - current->flags |= PF_VCPU; - write_seqcount_end(&tsk->vtime_seqcount); -} -EXPORT_SYMBOL_GPL(vtime_guest_enter); - -void vtime_guest_exit(struct task_struct *tsk) -{ - write_seqcount_begin(&tsk->vtime_seqcount); - __vtime_account_system(tsk); - current->flags &= ~PF_VCPU; - write_seqcount_end(&tsk->vtime_seqcount); -} -EXPORT_SYMBOL_GPL(vtime_guest_exit); - -void vtime_account_idle(struct task_struct *tsk) -{ - cputime_t delta_cpu = get_vtime_delta(tsk); - - account_idle_time(delta_cpu); -} - -void arch_vtime_task_switch(struct task_struct *prev) -{ - write_seqcount_begin(&prev->vtime_seqcount); - prev->vtime_snap_whence = VTIME_INACTIVE; - write_seqcount_end(&prev->vtime_seqcount); - - write_seqcount_begin(¤t->vtime_seqcount); - current->vtime_snap_whence = VTIME_SYS; - current->vtime_snap = jiffies; - write_seqcount_end(¤t->vtime_seqcount); -} - -void vtime_init_idle(struct task_struct *t, int cpu) -{ - unsigned long flags; - - local_irq_save(flags); - write_seqcount_begin(&t->vtime_seqcount); - t->vtime_snap_whence = VTIME_SYS; - t->vtime_snap = jiffies; - write_seqcount_end(&t->vtime_seqcount); - local_irq_restore(flags); -} - -cputime_t task_gtime(struct task_struct *t) -{ - unsigned int seq; - cputime_t gtime; - - if (!vtime_accounting_enabled()) - return t->gtime; - - do { - seq = read_seqcount_begin(&t->vtime_seqcount); - - gtime = t->gtime; - if (t->vtime_snap_whence == VTIME_SYS && t->flags & PF_VCPU) - gtime += vtime_delta(t); - - } while (read_seqcount_retry(&t->vtime_seqcount, seq)); - - return gtime; -} - -/* - * Fetch cputime raw values from fields of task_struct and - * add up the pending nohz execution time since the last - * cputime snapshot. - */ -static void -fetch_task_cputime(struct task_struct *t, - cputime_t *u_dst, cputime_t *s_dst, - cputime_t *u_src, cputime_t *s_src, - cputime_t *udelta, cputime_t *sdelta) -{ - unsigned int seq; - unsigned long long delta; - - do { - *udelta = 0; - *sdelta = 0; - - seq = read_seqcount_begin(&t->vtime_seqcount); - - if (u_dst) - *u_dst = *u_src; - if (s_dst) - *s_dst = *s_src; - - /* Task is sleeping, nothing to add */ - if (t->vtime_snap_whence == VTIME_INACTIVE || - is_idle_task(t)) - continue; - - delta = vtime_delta(t); - - /* - * Task runs either in user or kernel space, add pending nohz time to - * the right place. - */ - if (t->vtime_snap_whence == VTIME_USER || t->flags & PF_VCPU) { - *udelta = delta; - } else { - if (t->vtime_snap_whence == VTIME_SYS) - *sdelta = delta; - } - } while (read_seqcount_retry(&t->vtime_seqcount, seq)); -} - - -void task_cputime(struct task_struct *t, cputime_t *utime, cputime_t *stime) -{ - cputime_t udelta, sdelta; - - if (!vtime_accounting_enabled()) { - if (utime) - *utime = t->utime; - if (stime) - *stime = t->stime; - return; - } - - fetch_task_cputime(t, utime, stime, &t->utime, - &t->stime, &udelta, &sdelta); - if (utime) - *utime += udelta; - if (stime) - *stime += sdelta; -} - -void task_cputime_scaled(struct task_struct *t, - cputime_t *utimescaled, cputime_t *stimescaled) -{ - cputime_t udelta, sdelta; - - if (!vtime_accounting_enabled()) { - if (utimescaled) - *utimescaled = t->utimescaled; - if (stimescaled) - *stimescaled = t->stimescaled; - return; - } - - fetch_task_cputime(t, utimescaled, stimescaled, - &t->utimescaled, &t->stimescaled, &udelta, &sdelta); - if (utimescaled) - *utimescaled += cputime_to_scaled(udelta); - if (stimescaled) - *stimescaled += cputime_to_scaled(sdelta); -} -#endif /* CONFIG_VIRT_CPU_ACCOUNTING_GEN */ diff --git a/src/linux/kernel/sched/deadline.c b/src/linux/kernel/sched/deadline.c deleted file mode 100644 index 37e2449..0000000 --- a/src/linux/kernel/sched/deadline.c +++ /dev/null @@ -1,1815 +0,0 @@ -/* - * Deadline Scheduling Class (SCHED_DEADLINE) - * - * Earliest Deadline First (EDF) + Constant Bandwidth Server (CBS). - * - * Tasks that periodically executes their instances for less than their - * runtime won't miss any of their deadlines. - * Tasks that are not periodic or sporadic or that tries to execute more - * than their reserved bandwidth will be slowed down (and may potentially - * miss some of their deadlines), and won't affect any other task. - * - * Copyright (C) 2012 Dario Faggioli , - * Juri Lelli , - * Michael Trimarchi , - * Fabio Checconi - */ -#include "sched.h" - -#include - -struct dl_bandwidth def_dl_bandwidth; - -static inline struct task_struct *dl_task_of(struct sched_dl_entity *dl_se) -{ - return container_of(dl_se, struct task_struct, dl); -} - -static inline struct rq *rq_of_dl_rq(struct dl_rq *dl_rq) -{ - return container_of(dl_rq, struct rq, dl); -} - -static inline struct dl_rq *dl_rq_of_se(struct sched_dl_entity *dl_se) -{ - struct task_struct *p = dl_task_of(dl_se); - struct rq *rq = task_rq(p); - - return &rq->dl; -} - -static inline int on_dl_rq(struct sched_dl_entity *dl_se) -{ - return !RB_EMPTY_NODE(&dl_se->rb_node); -} - -static inline int is_leftmost(struct task_struct *p, struct dl_rq *dl_rq) -{ - struct sched_dl_entity *dl_se = &p->dl; - - return dl_rq->rb_leftmost == &dl_se->rb_node; -} - -void init_dl_bandwidth(struct dl_bandwidth *dl_b, u64 period, u64 runtime) -{ - raw_spin_lock_init(&dl_b->dl_runtime_lock); - dl_b->dl_period = period; - dl_b->dl_runtime = runtime; -} - -void init_dl_bw(struct dl_bw *dl_b) -{ - raw_spin_lock_init(&dl_b->lock); - raw_spin_lock(&def_dl_bandwidth.dl_runtime_lock); - if (global_rt_runtime() == RUNTIME_INF) - dl_b->bw = -1; - else - dl_b->bw = to_ratio(global_rt_period(), global_rt_runtime()); - raw_spin_unlock(&def_dl_bandwidth.dl_runtime_lock); - dl_b->total_bw = 0; -} - -void init_dl_rq(struct dl_rq *dl_rq) -{ - dl_rq->rb_root = RB_ROOT; - -#ifdef CONFIG_SMP - /* zero means no -deadline tasks */ - dl_rq->earliest_dl.curr = dl_rq->earliest_dl.next = 0; - - dl_rq->dl_nr_migratory = 0; - dl_rq->overloaded = 0; - dl_rq->pushable_dl_tasks_root = RB_ROOT; -#else - init_dl_bw(&dl_rq->dl_bw); -#endif -} - -#ifdef CONFIG_SMP - -static inline int dl_overloaded(struct rq *rq) -{ - return atomic_read(&rq->rd->dlo_count); -} - -static inline void dl_set_overload(struct rq *rq) -{ - if (!rq->online) - return; - - cpumask_set_cpu(rq->cpu, rq->rd->dlo_mask); - /* - * Must be visible before the overload count is - * set (as in sched_rt.c). - * - * Matched by the barrier in pull_dl_task(). - */ - smp_wmb(); - atomic_inc(&rq->rd->dlo_count); -} - -static inline void dl_clear_overload(struct rq *rq) -{ - if (!rq->online) - return; - - atomic_dec(&rq->rd->dlo_count); - cpumask_clear_cpu(rq->cpu, rq->rd->dlo_mask); -} - -static void update_dl_migration(struct dl_rq *dl_rq) -{ - if (dl_rq->dl_nr_migratory && dl_rq->dl_nr_running > 1) { - if (!dl_rq->overloaded) { - dl_set_overload(rq_of_dl_rq(dl_rq)); - dl_rq->overloaded = 1; - } - } else if (dl_rq->overloaded) { - dl_clear_overload(rq_of_dl_rq(dl_rq)); - dl_rq->overloaded = 0; - } -} - -static void inc_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq) -{ - struct task_struct *p = dl_task_of(dl_se); - - if (tsk_nr_cpus_allowed(p) > 1) - dl_rq->dl_nr_migratory++; - - update_dl_migration(dl_rq); -} - -static void dec_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq) -{ - struct task_struct *p = dl_task_of(dl_se); - - if (tsk_nr_cpus_allowed(p) > 1) - dl_rq->dl_nr_migratory--; - - update_dl_migration(dl_rq); -} - -/* - * The list of pushable -deadline task is not a plist, like in - * sched_rt.c, it is an rb-tree with tasks ordered by deadline. - */ -static void enqueue_pushable_dl_task(struct rq *rq, struct task_struct *p) -{ - struct dl_rq *dl_rq = &rq->dl; - struct rb_node **link = &dl_rq->pushable_dl_tasks_root.rb_node; - struct rb_node *parent = NULL; - struct task_struct *entry; - int leftmost = 1; - - BUG_ON(!RB_EMPTY_NODE(&p->pushable_dl_tasks)); - - while (*link) { - parent = *link; - entry = rb_entry(parent, struct task_struct, - pushable_dl_tasks); - if (dl_entity_preempt(&p->dl, &entry->dl)) - link = &parent->rb_left; - else { - link = &parent->rb_right; - leftmost = 0; - } - } - - if (leftmost) { - dl_rq->pushable_dl_tasks_leftmost = &p->pushable_dl_tasks; - dl_rq->earliest_dl.next = p->dl.deadline; - } - - rb_link_node(&p->pushable_dl_tasks, parent, link); - rb_insert_color(&p->pushable_dl_tasks, &dl_rq->pushable_dl_tasks_root); -} - -static void dequeue_pushable_dl_task(struct rq *rq, struct task_struct *p) -{ - struct dl_rq *dl_rq = &rq->dl; - - if (RB_EMPTY_NODE(&p->pushable_dl_tasks)) - return; - - if (dl_rq->pushable_dl_tasks_leftmost == &p->pushable_dl_tasks) { - struct rb_node *next_node; - - next_node = rb_next(&p->pushable_dl_tasks); - dl_rq->pushable_dl_tasks_leftmost = next_node; - if (next_node) { - dl_rq->earliest_dl.next = rb_entry(next_node, - struct task_struct, pushable_dl_tasks)->dl.deadline; - } - } - - rb_erase(&p->pushable_dl_tasks, &dl_rq->pushable_dl_tasks_root); - RB_CLEAR_NODE(&p->pushable_dl_tasks); -} - -static inline int has_pushable_dl_tasks(struct rq *rq) -{ - return !RB_EMPTY_ROOT(&rq->dl.pushable_dl_tasks_root); -} - -static int push_dl_task(struct rq *rq); - -static inline bool need_pull_dl_task(struct rq *rq, struct task_struct *prev) -{ - return dl_task(prev); -} - -static DEFINE_PER_CPU(struct callback_head, dl_push_head); -static DEFINE_PER_CPU(struct callback_head, dl_pull_head); - -static void push_dl_tasks(struct rq *); -static void pull_dl_task(struct rq *); - -static inline void queue_push_tasks(struct rq *rq) -{ - if (!has_pushable_dl_tasks(rq)) - return; - - queue_balance_callback(rq, &per_cpu(dl_push_head, rq->cpu), push_dl_tasks); -} - -static inline void queue_pull_task(struct rq *rq) -{ - queue_balance_callback(rq, &per_cpu(dl_pull_head, rq->cpu), pull_dl_task); -} - -static struct rq *find_lock_later_rq(struct task_struct *task, struct rq *rq); - -static struct rq *dl_task_offline_migration(struct rq *rq, struct task_struct *p) -{ - struct rq *later_rq = NULL; - - later_rq = find_lock_later_rq(p, rq); - if (!later_rq) { - int cpu; - - /* - * If we cannot preempt any rq, fall back to pick any - * online cpu. - */ - cpu = cpumask_any_and(cpu_active_mask, tsk_cpus_allowed(p)); - if (cpu >= nr_cpu_ids) { - /* - * Fail to find any suitable cpu. - * The task will never come back! - */ - BUG_ON(dl_bandwidth_enabled()); - - /* - * If admission control is disabled we - * try a little harder to let the task - * run. - */ - cpu = cpumask_any(cpu_active_mask); - } - later_rq = cpu_rq(cpu); - double_lock_balance(rq, later_rq); - } - - set_task_cpu(p, later_rq->cpu); - double_unlock_balance(later_rq, rq); - - return later_rq; -} - -#else - -static inline -void enqueue_pushable_dl_task(struct rq *rq, struct task_struct *p) -{ -} - -static inline -void dequeue_pushable_dl_task(struct rq *rq, struct task_struct *p) -{ -} - -static inline -void inc_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq) -{ -} - -static inline -void dec_dl_migration(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq) -{ -} - -static inline bool need_pull_dl_task(struct rq *rq, struct task_struct *prev) -{ - return false; -} - -static inline void pull_dl_task(struct rq *rq) -{ -} - -static inline void queue_push_tasks(struct rq *rq) -{ -} - -static inline void queue_pull_task(struct rq *rq) -{ -} -#endif /* CONFIG_SMP */ - -static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags); -static void __dequeue_task_dl(struct rq *rq, struct task_struct *p, int flags); -static void check_preempt_curr_dl(struct rq *rq, struct task_struct *p, - int flags); - -/* - * We are being explicitly informed that a new instance is starting, - * and this means that: - * - the absolute deadline of the entity has to be placed at - * current time + relative deadline; - * - the runtime of the entity has to be set to the maximum value. - * - * The capability of specifying such event is useful whenever a -deadline - * entity wants to (try to!) synchronize its behaviour with the scheduler's - * one, and to (try to!) reconcile itself with its own scheduling - * parameters. - */ -static inline void setup_new_dl_entity(struct sched_dl_entity *dl_se) -{ - struct dl_rq *dl_rq = dl_rq_of_se(dl_se); - struct rq *rq = rq_of_dl_rq(dl_rq); - - WARN_ON(dl_se->dl_boosted); - WARN_ON(dl_time_before(rq_clock(rq), dl_se->deadline)); - - /* - * We are racing with the deadline timer. So, do nothing because - * the deadline timer handler will take care of properly recharging - * the runtime and postponing the deadline - */ - if (dl_se->dl_throttled) - return; - - /* - * We use the regular wall clock time to set deadlines in the - * future; in fact, we must consider execution overheads (time - * spent on hardirq context, etc.). - */ - dl_se->deadline = rq_clock(rq) + dl_se->dl_deadline; - dl_se->runtime = dl_se->dl_runtime; -} - -/* - * Pure Earliest Deadline First (EDF) scheduling does not deal with the - * possibility of a entity lasting more than what it declared, and thus - * exhausting its runtime. - * - * Here we are interested in making runtime overrun possible, but we do - * not want a entity which is misbehaving to affect the scheduling of all - * other entities. - * Therefore, a budgeting strategy called Constant Bandwidth Server (CBS) - * is used, in order to confine each entity within its own bandwidth. - * - * This function deals exactly with that, and ensures that when the runtime - * of a entity is replenished, its deadline is also postponed. That ensures - * the overrunning entity can't interfere with other entity in the system and - * can't make them miss their deadlines. Reasons why this kind of overruns - * could happen are, typically, a entity voluntarily trying to overcome its - * runtime, or it just underestimated it during sched_setattr(). - */ -static void replenish_dl_entity(struct sched_dl_entity *dl_se, - struct sched_dl_entity *pi_se) -{ - struct dl_rq *dl_rq = dl_rq_of_se(dl_se); - struct rq *rq = rq_of_dl_rq(dl_rq); - - BUG_ON(pi_se->dl_runtime <= 0); - - /* - * This could be the case for a !-dl task that is boosted. - * Just go with full inherited parameters. - */ - if (dl_se->dl_deadline == 0) { - dl_se->deadline = rq_clock(rq) + pi_se->dl_deadline; - dl_se->runtime = pi_se->dl_runtime; - } - - if (dl_se->dl_yielded && dl_se->runtime > 0) - dl_se->runtime = 0; - - /* - * We keep moving the deadline away until we get some - * available runtime for the entity. This ensures correct - * handling of situations where the runtime overrun is - * arbitrary large. - */ - while (dl_se->runtime <= 0) { - dl_se->deadline += pi_se->dl_period; - dl_se->runtime += pi_se->dl_runtime; - } - - /* - * At this point, the deadline really should be "in - * the future" with respect to rq->clock. If it's - * not, we are, for some reason, lagging too much! - * Anyway, after having warn userspace abut that, - * we still try to keep the things running by - * resetting the deadline and the budget of the - * entity. - */ - if (dl_time_before(dl_se->deadline, rq_clock(rq))) { - printk_deferred_once("sched: DL replenish lagged too much\n"); - dl_se->deadline = rq_clock(rq) + pi_se->dl_deadline; - dl_se->runtime = pi_se->dl_runtime; - } - - if (dl_se->dl_yielded) - dl_se->dl_yielded = 0; - if (dl_se->dl_throttled) - dl_se->dl_throttled = 0; -} - -/* - * Here we check if --at time t-- an entity (which is probably being - * [re]activated or, in general, enqueued) can use its remaining runtime - * and its current deadline _without_ exceeding the bandwidth it is - * assigned (function returns true if it can't). We are in fact applying - * one of the CBS rules: when a task wakes up, if the residual runtime - * over residual deadline fits within the allocated bandwidth, then we - * can keep the current (absolute) deadline and residual budget without - * disrupting the schedulability of the system. Otherwise, we should - * refill the runtime and set the deadline a period in the future, - * because keeping the current (absolute) deadline of the task would - * result in breaking guarantees promised to other tasks (refer to - * Documentation/scheduler/sched-deadline.txt for more informations). - * - * This function returns true if: - * - * runtime / (deadline - t) > dl_runtime / dl_period , - * - * IOW we can't recycle current parameters. - * - * Notice that the bandwidth check is done against the period. For - * task with deadline equal to period this is the same of using - * dl_deadline instead of dl_period in the equation above. - */ -static bool dl_entity_overflow(struct sched_dl_entity *dl_se, - struct sched_dl_entity *pi_se, u64 t) -{ - u64 left, right; - - /* - * left and right are the two sides of the equation above, - * after a bit of shuffling to use multiplications instead - * of divisions. - * - * Note that none of the time values involved in the two - * multiplications are absolute: dl_deadline and dl_runtime - * are the relative deadline and the maximum runtime of each - * instance, runtime is the runtime left for the last instance - * and (deadline - t), since t is rq->clock, is the time left - * to the (absolute) deadline. Even if overflowing the u64 type - * is very unlikely to occur in both cases, here we scale down - * as we want to avoid that risk at all. Scaling down by 10 - * means that we reduce granularity to 1us. We are fine with it, - * since this is only a true/false check and, anyway, thinking - * of anything below microseconds resolution is actually fiction - * (but still we want to give the user that illusion >;). - */ - left = (pi_se->dl_period >> DL_SCALE) * (dl_se->runtime >> DL_SCALE); - right = ((dl_se->deadline - t) >> DL_SCALE) * - (pi_se->dl_runtime >> DL_SCALE); - - return dl_time_before(right, left); -} - -/* - * When a -deadline entity is queued back on the runqueue, its runtime and - * deadline might need updating. - * - * The policy here is that we update the deadline of the entity only if: - * - the current deadline is in the past, - * - using the remaining runtime with the current deadline would make - * the entity exceed its bandwidth. - */ -static void update_dl_entity(struct sched_dl_entity *dl_se, - struct sched_dl_entity *pi_se) -{ - struct dl_rq *dl_rq = dl_rq_of_se(dl_se); - struct rq *rq = rq_of_dl_rq(dl_rq); - - if (dl_time_before(dl_se->deadline, rq_clock(rq)) || - dl_entity_overflow(dl_se, pi_se, rq_clock(rq))) { - dl_se->deadline = rq_clock(rq) + pi_se->dl_deadline; - dl_se->runtime = pi_se->dl_runtime; - } -} - -/* - * If the entity depleted all its runtime, and if we want it to sleep - * while waiting for some new execution time to become available, we - * set the bandwidth enforcement timer to the replenishment instant - * and try to activate it. - * - * Notice that it is important for the caller to know if the timer - * actually started or not (i.e., the replenishment instant is in - * the future or in the past). - */ -static int start_dl_timer(struct task_struct *p) -{ - struct sched_dl_entity *dl_se = &p->dl; - struct hrtimer *timer = &dl_se->dl_timer; - struct rq *rq = task_rq(p); - ktime_t now, act; - s64 delta; - - lockdep_assert_held(&rq->lock); - - /* - * We want the timer to fire at the deadline, but considering - * that it is actually coming from rq->clock and not from - * hrtimer's time base reading. - */ - act = ns_to_ktime(dl_se->deadline); - now = hrtimer_cb_get_time(timer); - delta = ktime_to_ns(now) - rq_clock(rq); - act = ktime_add_ns(act, delta); - - /* - * If the expiry time already passed, e.g., because the value - * chosen as the deadline is too small, don't even try to - * start the timer in the past! - */ - if (ktime_us_delta(act, now) < 0) - return 0; - - /* - * !enqueued will guarantee another callback; even if one is already in - * progress. This ensures a balanced {get,put}_task_struct(). - * - * The race against __run_timer() clearing the enqueued state is - * harmless because we're holding task_rq()->lock, therefore the timer - * expiring after we've done the check will wait on its task_rq_lock() - * and observe our state. - */ - if (!hrtimer_is_queued(timer)) { - get_task_struct(p); - hrtimer_start(timer, act, HRTIMER_MODE_ABS); - } - - return 1; -} - -/* - * This is the bandwidth enforcement timer callback. If here, we know - * a task is not on its dl_rq, since the fact that the timer was running - * means the task is throttled and needs a runtime replenishment. - * - * However, what we actually do depends on the fact the task is active, - * (it is on its rq) or has been removed from there by a call to - * dequeue_task_dl(). In the former case we must issue the runtime - * replenishment and add the task back to the dl_rq; in the latter, we just - * do nothing but clearing dl_throttled, so that runtime and deadline - * updating (and the queueing back to dl_rq) will be done by the - * next call to enqueue_task_dl(). - */ -static enum hrtimer_restart dl_task_timer(struct hrtimer *timer) -{ - struct sched_dl_entity *dl_se = container_of(timer, - struct sched_dl_entity, - dl_timer); - struct task_struct *p = dl_task_of(dl_se); - struct rq_flags rf; - struct rq *rq; - - rq = task_rq_lock(p, &rf); - - /* - * The task might have changed its scheduling policy to something - * different than SCHED_DEADLINE (through switched_fromd_dl()). - */ - if (!dl_task(p)) { - __dl_clear_params(p); - goto unlock; - } - - /* - * The task might have been boosted by someone else and might be in the - * boosting/deboosting path, its not throttled. - */ - if (dl_se->dl_boosted) - goto unlock; - - /* - * Spurious timer due to start_dl_timer() race; or we already received - * a replenishment from rt_mutex_setprio(). - */ - if (!dl_se->dl_throttled) - goto unlock; - - sched_clock_tick(); - update_rq_clock(rq); - - /* - * If the throttle happened during sched-out; like: - * - * schedule() - * deactivate_task() - * dequeue_task_dl() - * update_curr_dl() - * start_dl_timer() - * __dequeue_task_dl() - * prev->on_rq = 0; - * - * We can be both throttled and !queued. Replenish the counter - * but do not enqueue -- wait for our wakeup to do that. - */ - if (!task_on_rq_queued(p)) { - replenish_dl_entity(dl_se, dl_se); - goto unlock; - } - -#ifdef CONFIG_SMP - if (unlikely(!rq->online)) { - /* - * If the runqueue is no longer available, migrate the - * task elsewhere. This necessarily changes rq. - */ - lockdep_unpin_lock(&rq->lock, rf.cookie); - rq = dl_task_offline_migration(rq, p); - rf.cookie = lockdep_pin_lock(&rq->lock); - - /* - * Now that the task has been migrated to the new RQ and we - * have that locked, proceed as normal and enqueue the task - * there. - */ - } -#endif - - enqueue_task_dl(rq, p, ENQUEUE_REPLENISH); - if (dl_task(rq->curr)) - check_preempt_curr_dl(rq, p, 0); - else - resched_curr(rq); - -#ifdef CONFIG_SMP - /* - * Queueing this task back might have overloaded rq, check if we need - * to kick someone away. - */ - if (has_pushable_dl_tasks(rq)) { - /* - * Nothing relies on rq->lock after this, so its safe to drop - * rq->lock. - */ - lockdep_unpin_lock(&rq->lock, rf.cookie); - push_dl_task(rq); - lockdep_repin_lock(&rq->lock, rf.cookie); - } -#endif - -unlock: - task_rq_unlock(rq, p, &rf); - - /* - * This can free the task_struct, including this hrtimer, do not touch - * anything related to that after this. - */ - put_task_struct(p); - - return HRTIMER_NORESTART; -} - -void init_dl_task_timer(struct sched_dl_entity *dl_se) -{ - struct hrtimer *timer = &dl_se->dl_timer; - - hrtimer_init(timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - timer->function = dl_task_timer; -} - -static -int dl_runtime_exceeded(struct sched_dl_entity *dl_se) -{ - return (dl_se->runtime <= 0); -} - -extern bool sched_rt_bandwidth_account(struct rt_rq *rt_rq); - -/* - * Update the current task's runtime statistics (provided it is still - * a -deadline task and has not been removed from the dl_rq). - */ -static void update_curr_dl(struct rq *rq) -{ - struct task_struct *curr = rq->curr; - struct sched_dl_entity *dl_se = &curr->dl; - u64 delta_exec; - - if (!dl_task(curr) || !on_dl_rq(dl_se)) - return; - - /* - * Consumed budget is computed considering the time as - * observed by schedulable tasks (excluding time spent - * in hardirq context, etc.). Deadlines are instead - * computed using hard walltime. This seems to be the more - * natural solution, but the full ramifications of this - * approach need further study. - */ - delta_exec = rq_clock_task(rq) - curr->se.exec_start; - if (unlikely((s64)delta_exec <= 0)) { - if (unlikely(dl_se->dl_yielded)) - goto throttle; - return; - } - - /* kick cpufreq (see the comment in kernel/sched/sched.h). */ - cpufreq_update_this_cpu(rq, SCHED_CPUFREQ_DL); - - schedstat_set(curr->se.statistics.exec_max, - max(curr->se.statistics.exec_max, delta_exec)); - - curr->se.sum_exec_runtime += delta_exec; - account_group_exec_runtime(curr, delta_exec); - - curr->se.exec_start = rq_clock_task(rq); - cpuacct_charge(curr, delta_exec); - - sched_rt_avg_update(rq, delta_exec); - - dl_se->runtime -= delta_exec; - -throttle: - if (dl_runtime_exceeded(dl_se) || dl_se->dl_yielded) { - dl_se->dl_throttled = 1; - __dequeue_task_dl(rq, curr, 0); - if (unlikely(dl_se->dl_boosted || !start_dl_timer(curr))) - enqueue_task_dl(rq, curr, ENQUEUE_REPLENISH); - - if (!is_leftmost(curr, &rq->dl)) - resched_curr(rq); - } - - /* - * Because -- for now -- we share the rt bandwidth, we need to - * account our runtime there too, otherwise actual rt tasks - * would be able to exceed the shared quota. - * - * Account to the root rt group for now. - * - * The solution we're working towards is having the RT groups scheduled - * using deadline servers -- however there's a few nasties to figure - * out before that can happen. - */ - if (rt_bandwidth_enabled()) { - struct rt_rq *rt_rq = &rq->rt; - - raw_spin_lock(&rt_rq->rt_runtime_lock); - /* - * We'll let actual RT tasks worry about the overflow here, we - * have our own CBS to keep us inline; only account when RT - * bandwidth is relevant. - */ - if (sched_rt_bandwidth_account(rt_rq)) - rt_rq->rt_time += delta_exec; - raw_spin_unlock(&rt_rq->rt_runtime_lock); - } -} - -#ifdef CONFIG_SMP - -static void inc_dl_deadline(struct dl_rq *dl_rq, u64 deadline) -{ - struct rq *rq = rq_of_dl_rq(dl_rq); - - if (dl_rq->earliest_dl.curr == 0 || - dl_time_before(deadline, dl_rq->earliest_dl.curr)) { - dl_rq->earliest_dl.curr = deadline; - cpudl_set(&rq->rd->cpudl, rq->cpu, deadline); - } -} - -static void dec_dl_deadline(struct dl_rq *dl_rq, u64 deadline) -{ - struct rq *rq = rq_of_dl_rq(dl_rq); - - /* - * Since we may have removed our earliest (and/or next earliest) - * task we must recompute them. - */ - if (!dl_rq->dl_nr_running) { - dl_rq->earliest_dl.curr = 0; - dl_rq->earliest_dl.next = 0; - cpudl_clear(&rq->rd->cpudl, rq->cpu); - } else { - struct rb_node *leftmost = dl_rq->rb_leftmost; - struct sched_dl_entity *entry; - - entry = rb_entry(leftmost, struct sched_dl_entity, rb_node); - dl_rq->earliest_dl.curr = entry->deadline; - cpudl_set(&rq->rd->cpudl, rq->cpu, entry->deadline); - } -} - -#else - -static inline void inc_dl_deadline(struct dl_rq *dl_rq, u64 deadline) {} -static inline void dec_dl_deadline(struct dl_rq *dl_rq, u64 deadline) {} - -#endif /* CONFIG_SMP */ - -static inline -void inc_dl_tasks(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq) -{ - int prio = dl_task_of(dl_se)->prio; - u64 deadline = dl_se->deadline; - - WARN_ON(!dl_prio(prio)); - dl_rq->dl_nr_running++; - add_nr_running(rq_of_dl_rq(dl_rq), 1); - - inc_dl_deadline(dl_rq, deadline); - inc_dl_migration(dl_se, dl_rq); -} - -static inline -void dec_dl_tasks(struct sched_dl_entity *dl_se, struct dl_rq *dl_rq) -{ - int prio = dl_task_of(dl_se)->prio; - - WARN_ON(!dl_prio(prio)); - WARN_ON(!dl_rq->dl_nr_running); - dl_rq->dl_nr_running--; - sub_nr_running(rq_of_dl_rq(dl_rq), 1); - - dec_dl_deadline(dl_rq, dl_se->deadline); - dec_dl_migration(dl_se, dl_rq); -} - -static void __enqueue_dl_entity(struct sched_dl_entity *dl_se) -{ - struct dl_rq *dl_rq = dl_rq_of_se(dl_se); - struct rb_node **link = &dl_rq->rb_root.rb_node; - struct rb_node *parent = NULL; - struct sched_dl_entity *entry; - int leftmost = 1; - - BUG_ON(!RB_EMPTY_NODE(&dl_se->rb_node)); - - while (*link) { - parent = *link; - entry = rb_entry(parent, struct sched_dl_entity, rb_node); - if (dl_time_before(dl_se->deadline, entry->deadline)) - link = &parent->rb_left; - else { - link = &parent->rb_right; - leftmost = 0; - } - } - - if (leftmost) - dl_rq->rb_leftmost = &dl_se->rb_node; - - rb_link_node(&dl_se->rb_node, parent, link); - rb_insert_color(&dl_se->rb_node, &dl_rq->rb_root); - - inc_dl_tasks(dl_se, dl_rq); -} - -static void __dequeue_dl_entity(struct sched_dl_entity *dl_se) -{ - struct dl_rq *dl_rq = dl_rq_of_se(dl_se); - - if (RB_EMPTY_NODE(&dl_se->rb_node)) - return; - - if (dl_rq->rb_leftmost == &dl_se->rb_node) { - struct rb_node *next_node; - - next_node = rb_next(&dl_se->rb_node); - dl_rq->rb_leftmost = next_node; - } - - rb_erase(&dl_se->rb_node, &dl_rq->rb_root); - RB_CLEAR_NODE(&dl_se->rb_node); - - dec_dl_tasks(dl_se, dl_rq); -} - -static void -enqueue_dl_entity(struct sched_dl_entity *dl_se, - struct sched_dl_entity *pi_se, int flags) -{ - BUG_ON(on_dl_rq(dl_se)); - - /* - * If this is a wakeup or a new instance, the scheduling - * parameters of the task might need updating. Otherwise, - * we want a replenishment of its runtime. - */ - if (flags & ENQUEUE_WAKEUP) - update_dl_entity(dl_se, pi_se); - else if (flags & ENQUEUE_REPLENISH) - replenish_dl_entity(dl_se, pi_se); - - __enqueue_dl_entity(dl_se); -} - -static void dequeue_dl_entity(struct sched_dl_entity *dl_se) -{ - __dequeue_dl_entity(dl_se); -} - -static void enqueue_task_dl(struct rq *rq, struct task_struct *p, int flags) -{ - struct task_struct *pi_task = rt_mutex_get_top_task(p); - struct sched_dl_entity *pi_se = &p->dl; - - /* - * Use the scheduling parameters of the top pi-waiter - * task if we have one and its (absolute) deadline is - * smaller than our one... OTW we keep our runtime and - * deadline. - */ - if (pi_task && p->dl.dl_boosted && dl_prio(pi_task->normal_prio)) { - pi_se = &pi_task->dl; - } else if (!dl_prio(p->normal_prio)) { - /* - * Special case in which we have a !SCHED_DEADLINE task - * that is going to be deboosted, but exceedes its - * runtime while doing so. No point in replenishing - * it, as it's going to return back to its original - * scheduling class after this. - */ - BUG_ON(!p->dl.dl_boosted || flags != ENQUEUE_REPLENISH); - return; - } - - /* - * If p is throttled, we do nothing. In fact, if it exhausted - * its budget it needs a replenishment and, since it now is on - * its rq, the bandwidth timer callback (which clearly has not - * run yet) will take care of this. - */ - if (p->dl.dl_throttled && !(flags & ENQUEUE_REPLENISH)) - return; - - enqueue_dl_entity(&p->dl, pi_se, flags); - - if (!task_current(rq, p) && tsk_nr_cpus_allowed(p) > 1) - enqueue_pushable_dl_task(rq, p); -} - -static void __dequeue_task_dl(struct rq *rq, struct task_struct *p, int flags) -{ - dequeue_dl_entity(&p->dl); - dequeue_pushable_dl_task(rq, p); -} - -static void dequeue_task_dl(struct rq *rq, struct task_struct *p, int flags) -{ - update_curr_dl(rq); - __dequeue_task_dl(rq, p, flags); -} - -/* - * Yield task semantic for -deadline tasks is: - * - * get off from the CPU until our next instance, with - * a new runtime. This is of little use now, since we - * don't have a bandwidth reclaiming mechanism. Anyway, - * bandwidth reclaiming is planned for the future, and - * yield_task_dl will indicate that some spare budget - * is available for other task instances to use it. - */ -static void yield_task_dl(struct rq *rq) -{ - /* - * We make the task go to sleep until its current deadline by - * forcing its runtime to zero. This way, update_curr_dl() stops - * it and the bandwidth timer will wake it up and will give it - * new scheduling parameters (thanks to dl_yielded=1). - */ - rq->curr->dl.dl_yielded = 1; - - update_rq_clock(rq); - update_curr_dl(rq); - /* - * Tell update_rq_clock() that we've just updated, - * so we don't do microscopic update in schedule() - * and double the fastpath cost. - */ - rq_clock_skip_update(rq, true); -} - -#ifdef CONFIG_SMP - -static int find_later_rq(struct task_struct *task); - -static int -select_task_rq_dl(struct task_struct *p, int cpu, int sd_flag, int flags) -{ - struct task_struct *curr; - struct rq *rq; - - if (sd_flag != SD_BALANCE_WAKE) - goto out; - - rq = cpu_rq(cpu); - - rcu_read_lock(); - curr = READ_ONCE(rq->curr); /* unlocked access */ - - /* - * If we are dealing with a -deadline task, we must - * decide where to wake it up. - * If it has a later deadline and the current task - * on this rq can't move (provided the waking task - * can!) we prefer to send it somewhere else. On the - * other hand, if it has a shorter deadline, we - * try to make it stay here, it might be important. - */ - if (unlikely(dl_task(curr)) && - (tsk_nr_cpus_allowed(curr) < 2 || - !dl_entity_preempt(&p->dl, &curr->dl)) && - (tsk_nr_cpus_allowed(p) > 1)) { - int target = find_later_rq(p); - - if (target != -1 && - (dl_time_before(p->dl.deadline, - cpu_rq(target)->dl.earliest_dl.curr) || - (cpu_rq(target)->dl.dl_nr_running == 0))) - cpu = target; - } - rcu_read_unlock(); - -out: - return cpu; -} - -static void check_preempt_equal_dl(struct rq *rq, struct task_struct *p) -{ - /* - * Current can't be migrated, useless to reschedule, - * let's hope p can move out. - */ - if (tsk_nr_cpus_allowed(rq->curr) == 1 || - cpudl_find(&rq->rd->cpudl, rq->curr, NULL) == -1) - return; - - /* - * p is migratable, so let's not schedule it and - * see if it is pushed or pulled somewhere else. - */ - if (tsk_nr_cpus_allowed(p) != 1 && - cpudl_find(&rq->rd->cpudl, p, NULL) != -1) - return; - - resched_curr(rq); -} - -#endif /* CONFIG_SMP */ - -/* - * Only called when both the current and waking task are -deadline - * tasks. - */ -static void check_preempt_curr_dl(struct rq *rq, struct task_struct *p, - int flags) -{ - if (dl_entity_preempt(&p->dl, &rq->curr->dl)) { - resched_curr(rq); - return; - } - -#ifdef CONFIG_SMP - /* - * In the unlikely case current and p have the same deadline - * let us try to decide what's the best thing to do... - */ - if ((p->dl.deadline == rq->curr->dl.deadline) && - !test_tsk_need_resched(rq->curr)) - check_preempt_equal_dl(rq, p); -#endif /* CONFIG_SMP */ -} - -#ifdef CONFIG_SCHED_HRTICK -static void start_hrtick_dl(struct rq *rq, struct task_struct *p) -{ - hrtick_start(rq, p->dl.runtime); -} -#else /* !CONFIG_SCHED_HRTICK */ -static void start_hrtick_dl(struct rq *rq, struct task_struct *p) -{ -} -#endif - -static struct sched_dl_entity *pick_next_dl_entity(struct rq *rq, - struct dl_rq *dl_rq) -{ - struct rb_node *left = dl_rq->rb_leftmost; - - if (!left) - return NULL; - - return rb_entry(left, struct sched_dl_entity, rb_node); -} - -struct task_struct * -pick_next_task_dl(struct rq *rq, struct task_struct *prev, struct pin_cookie cookie) -{ - struct sched_dl_entity *dl_se; - struct task_struct *p; - struct dl_rq *dl_rq; - - dl_rq = &rq->dl; - - if (need_pull_dl_task(rq, prev)) { - /* - * This is OK, because current is on_cpu, which avoids it being - * picked for load-balance and preemption/IRQs are still - * disabled avoiding further scheduler activity on it and we're - * being very careful to re-start the picking loop. - */ - lockdep_unpin_lock(&rq->lock, cookie); - pull_dl_task(rq); - lockdep_repin_lock(&rq->lock, cookie); - /* - * pull_rt_task() can drop (and re-acquire) rq->lock; this - * means a stop task can slip in, in which case we need to - * re-start task selection. - */ - if (rq->stop && task_on_rq_queued(rq->stop)) - return RETRY_TASK; - } - - /* - * When prev is DL, we may throttle it in put_prev_task(). - * So, we update time before we check for dl_nr_running. - */ - if (prev->sched_class == &dl_sched_class) - update_curr_dl(rq); - - if (unlikely(!dl_rq->dl_nr_running)) - return NULL; - - put_prev_task(rq, prev); - - dl_se = pick_next_dl_entity(rq, dl_rq); - BUG_ON(!dl_se); - - p = dl_task_of(dl_se); - p->se.exec_start = rq_clock_task(rq); - - /* Running task will never be pushed. */ - dequeue_pushable_dl_task(rq, p); - - if (hrtick_enabled(rq)) - start_hrtick_dl(rq, p); - - queue_push_tasks(rq); - - return p; -} - -static void put_prev_task_dl(struct rq *rq, struct task_struct *p) -{ - update_curr_dl(rq); - - if (on_dl_rq(&p->dl) && tsk_nr_cpus_allowed(p) > 1) - enqueue_pushable_dl_task(rq, p); -} - -static void task_tick_dl(struct rq *rq, struct task_struct *p, int queued) -{ - update_curr_dl(rq); - - /* - * Even when we have runtime, update_curr_dl() might have resulted in us - * not being the leftmost task anymore. In that case NEED_RESCHED will - * be set and schedule() will start a new hrtick for the next task. - */ - if (hrtick_enabled(rq) && queued && p->dl.runtime > 0 && - is_leftmost(p, &rq->dl)) - start_hrtick_dl(rq, p); -} - -static void task_fork_dl(struct task_struct *p) -{ - /* - * SCHED_DEADLINE tasks cannot fork and this is achieved through - * sched_fork() - */ -} - -static void task_dead_dl(struct task_struct *p) -{ - struct dl_bw *dl_b = dl_bw_of(task_cpu(p)); - - /* - * Since we are TASK_DEAD we won't slip out of the domain! - */ - raw_spin_lock_irq(&dl_b->lock); - /* XXX we should retain the bw until 0-lag */ - dl_b->total_bw -= p->dl.dl_bw; - raw_spin_unlock_irq(&dl_b->lock); -} - -static void set_curr_task_dl(struct rq *rq) -{ - struct task_struct *p = rq->curr; - - p->se.exec_start = rq_clock_task(rq); - - /* You can't push away the running task */ - dequeue_pushable_dl_task(rq, p); -} - -#ifdef CONFIG_SMP - -/* Only try algorithms three times */ -#define DL_MAX_TRIES 3 - -static int pick_dl_task(struct rq *rq, struct task_struct *p, int cpu) -{ - if (!task_running(rq, p) && - cpumask_test_cpu(cpu, tsk_cpus_allowed(p))) - return 1; - return 0; -} - -/* - * Return the earliest pushable rq's task, which is suitable to be executed - * on the CPU, NULL otherwise: - */ -static struct task_struct *pick_earliest_pushable_dl_task(struct rq *rq, int cpu) -{ - struct rb_node *next_node = rq->dl.pushable_dl_tasks_leftmost; - struct task_struct *p = NULL; - - if (!has_pushable_dl_tasks(rq)) - return NULL; - -next_node: - if (next_node) { - p = rb_entry(next_node, struct task_struct, pushable_dl_tasks); - - if (pick_dl_task(rq, p, cpu)) - return p; - - next_node = rb_next(next_node); - goto next_node; - } - - return NULL; -} - -static DEFINE_PER_CPU(cpumask_var_t, local_cpu_mask_dl); - -static int find_later_rq(struct task_struct *task) -{ - struct sched_domain *sd; - struct cpumask *later_mask = this_cpu_cpumask_var_ptr(local_cpu_mask_dl); - int this_cpu = smp_processor_id(); - int best_cpu, cpu = task_cpu(task); - - /* Make sure the mask is initialized first */ - if (unlikely(!later_mask)) - return -1; - - if (tsk_nr_cpus_allowed(task) == 1) - return -1; - - /* - * We have to consider system topology and task affinity - * first, then we can look for a suitable cpu. - */ - best_cpu = cpudl_find(&task_rq(task)->rd->cpudl, - task, later_mask); - if (best_cpu == -1) - return -1; - - /* - * If we are here, some target has been found, - * the most suitable of which is cached in best_cpu. - * This is, among the runqueues where the current tasks - * have later deadlines than the task's one, the rq - * with the latest possible one. - * - * Now we check how well this matches with task's - * affinity and system topology. - * - * The last cpu where the task run is our first - * guess, since it is most likely cache-hot there. - */ - if (cpumask_test_cpu(cpu, later_mask)) - return cpu; - /* - * Check if this_cpu is to be skipped (i.e., it is - * not in the mask) or not. - */ - if (!cpumask_test_cpu(this_cpu, later_mask)) - this_cpu = -1; - - rcu_read_lock(); - for_each_domain(cpu, sd) { - if (sd->flags & SD_WAKE_AFFINE) { - - /* - * If possible, preempting this_cpu is - * cheaper than migrating. - */ - if (this_cpu != -1 && - cpumask_test_cpu(this_cpu, sched_domain_span(sd))) { - rcu_read_unlock(); - return this_cpu; - } - - /* - * Last chance: if best_cpu is valid and is - * in the mask, that becomes our choice. - */ - if (best_cpu < nr_cpu_ids && - cpumask_test_cpu(best_cpu, sched_domain_span(sd))) { - rcu_read_unlock(); - return best_cpu; - } - } - } - rcu_read_unlock(); - - /* - * At this point, all our guesses failed, we just return - * 'something', and let the caller sort the things out. - */ - if (this_cpu != -1) - return this_cpu; - - cpu = cpumask_any(later_mask); - if (cpu < nr_cpu_ids) - return cpu; - - return -1; -} - -/* Locks the rq it finds */ -static struct rq *find_lock_later_rq(struct task_struct *task, struct rq *rq) -{ - struct rq *later_rq = NULL; - int tries; - int cpu; - - for (tries = 0; tries < DL_MAX_TRIES; tries++) { - cpu = find_later_rq(task); - - if ((cpu == -1) || (cpu == rq->cpu)) - break; - - later_rq = cpu_rq(cpu); - - if (later_rq->dl.dl_nr_running && - !dl_time_before(task->dl.deadline, - later_rq->dl.earliest_dl.curr)) { - /* - * Target rq has tasks of equal or earlier deadline, - * retrying does not release any lock and is unlikely - * to yield a different result. - */ - later_rq = NULL; - break; - } - - /* Retry if something changed. */ - if (double_lock_balance(rq, later_rq)) { - if (unlikely(task_rq(task) != rq || - !cpumask_test_cpu(later_rq->cpu, - tsk_cpus_allowed(task)) || - task_running(rq, task) || - !dl_task(task) || - !task_on_rq_queued(task))) { - double_unlock_balance(rq, later_rq); - later_rq = NULL; - break; - } - } - - /* - * If the rq we found has no -deadline task, or - * its earliest one has a later deadline than our - * task, the rq is a good one. - */ - if (!later_rq->dl.dl_nr_running || - dl_time_before(task->dl.deadline, - later_rq->dl.earliest_dl.curr)) - break; - - /* Otherwise we try again. */ - double_unlock_balance(rq, later_rq); - later_rq = NULL; - } - - return later_rq; -} - -static struct task_struct *pick_next_pushable_dl_task(struct rq *rq) -{ - struct task_struct *p; - - if (!has_pushable_dl_tasks(rq)) - return NULL; - - p = rb_entry(rq->dl.pushable_dl_tasks_leftmost, - struct task_struct, pushable_dl_tasks); - - BUG_ON(rq->cpu != task_cpu(p)); - BUG_ON(task_current(rq, p)); - BUG_ON(tsk_nr_cpus_allowed(p) <= 1); - - BUG_ON(!task_on_rq_queued(p)); - BUG_ON(!dl_task(p)); - - return p; -} - -/* - * See if the non running -deadline tasks on this rq - * can be sent to some other CPU where they can preempt - * and start executing. - */ -static int push_dl_task(struct rq *rq) -{ - struct task_struct *next_task; - struct rq *later_rq; - int ret = 0; - - if (!rq->dl.overloaded) - return 0; - - next_task = pick_next_pushable_dl_task(rq); - if (!next_task) - return 0; - -retry: - if (unlikely(next_task == rq->curr)) { - WARN_ON(1); - return 0; - } - - /* - * If next_task preempts rq->curr, and rq->curr - * can move away, it makes sense to just reschedule - * without going further in pushing next_task. - */ - if (dl_task(rq->curr) && - dl_time_before(next_task->dl.deadline, rq->curr->dl.deadline) && - tsk_nr_cpus_allowed(rq->curr) > 1) { - resched_curr(rq); - return 0; - } - - /* We might release rq lock */ - get_task_struct(next_task); - - /* Will lock the rq it'll find */ - later_rq = find_lock_later_rq(next_task, rq); - if (!later_rq) { - struct task_struct *task; - - /* - * We must check all this again, since - * find_lock_later_rq releases rq->lock and it is - * then possible that next_task has migrated. - */ - task = pick_next_pushable_dl_task(rq); - if (task_cpu(next_task) == rq->cpu && task == next_task) { - /* - * The task is still there. We don't try - * again, some other cpu will pull it when ready. - */ - goto out; - } - - if (!task) - /* No more tasks */ - goto out; - - put_task_struct(next_task); - next_task = task; - goto retry; - } - - deactivate_task(rq, next_task, 0); - set_task_cpu(next_task, later_rq->cpu); - activate_task(later_rq, next_task, 0); - ret = 1; - - resched_curr(later_rq); - - double_unlock_balance(rq, later_rq); - -out: - put_task_struct(next_task); - - return ret; -} - -static void push_dl_tasks(struct rq *rq) -{ - /* push_dl_task() will return true if it moved a -deadline task */ - while (push_dl_task(rq)) - ; -} - -static void pull_dl_task(struct rq *this_rq) -{ - int this_cpu = this_rq->cpu, cpu; - struct task_struct *p; - bool resched = false; - struct rq *src_rq; - u64 dmin = LONG_MAX; - - if (likely(!dl_overloaded(this_rq))) - return; - - /* - * Match the barrier from dl_set_overloaded; this guarantees that if we - * see overloaded we must also see the dlo_mask bit. - */ - smp_rmb(); - - for_each_cpu(cpu, this_rq->rd->dlo_mask) { - if (this_cpu == cpu) - continue; - - src_rq = cpu_rq(cpu); - - /* - * It looks racy, abd it is! However, as in sched_rt.c, - * we are fine with this. - */ - if (this_rq->dl.dl_nr_running && - dl_time_before(this_rq->dl.earliest_dl.curr, - src_rq->dl.earliest_dl.next)) - continue; - - /* Might drop this_rq->lock */ - double_lock_balance(this_rq, src_rq); - - /* - * If there are no more pullable tasks on the - * rq, we're done with it. - */ - if (src_rq->dl.dl_nr_running <= 1) - goto skip; - - p = pick_earliest_pushable_dl_task(src_rq, this_cpu); - - /* - * We found a task to be pulled if: - * - it preempts our current (if there's one), - * - it will preempt the last one we pulled (if any). - */ - if (p && dl_time_before(p->dl.deadline, dmin) && - (!this_rq->dl.dl_nr_running || - dl_time_before(p->dl.deadline, - this_rq->dl.earliest_dl.curr))) { - WARN_ON(p == src_rq->curr); - WARN_ON(!task_on_rq_queued(p)); - - /* - * Then we pull iff p has actually an earlier - * deadline than the current task of its runqueue. - */ - if (dl_time_before(p->dl.deadline, - src_rq->curr->dl.deadline)) - goto skip; - - resched = true; - - deactivate_task(src_rq, p, 0); - set_task_cpu(p, this_cpu); - activate_task(this_rq, p, 0); - dmin = p->dl.deadline; - - /* Is there any other task even earlier? */ - } -skip: - double_unlock_balance(this_rq, src_rq); - } - - if (resched) - resched_curr(this_rq); -} - -/* - * Since the task is not running and a reschedule is not going to happen - * anytime soon on its runqueue, we try pushing it away now. - */ -static void task_woken_dl(struct rq *rq, struct task_struct *p) -{ - if (!task_running(rq, p) && - !test_tsk_need_resched(rq->curr) && - tsk_nr_cpus_allowed(p) > 1 && - dl_task(rq->curr) && - (tsk_nr_cpus_allowed(rq->curr) < 2 || - !dl_entity_preempt(&p->dl, &rq->curr->dl))) { - push_dl_tasks(rq); - } -} - -static void set_cpus_allowed_dl(struct task_struct *p, - const struct cpumask *new_mask) -{ - struct root_domain *src_rd; - struct rq *rq; - - BUG_ON(!dl_task(p)); - - rq = task_rq(p); - src_rd = rq->rd; - /* - * Migrating a SCHED_DEADLINE task between exclusive - * cpusets (different root_domains) entails a bandwidth - * update. We already made space for us in the destination - * domain (see cpuset_can_attach()). - */ - if (!cpumask_intersects(src_rd->span, new_mask)) { - struct dl_bw *src_dl_b; - - src_dl_b = dl_bw_of(cpu_of(rq)); - /* - * We now free resources of the root_domain we are migrating - * off. In the worst case, sched_setattr() may temporary fail - * until we complete the update. - */ - raw_spin_lock(&src_dl_b->lock); - __dl_clear(src_dl_b, p->dl.dl_bw); - raw_spin_unlock(&src_dl_b->lock); - } - - set_cpus_allowed_common(p, new_mask); -} - -/* Assumes rq->lock is held */ -static void rq_online_dl(struct rq *rq) -{ - if (rq->dl.overloaded) - dl_set_overload(rq); - - cpudl_set_freecpu(&rq->rd->cpudl, rq->cpu); - if (rq->dl.dl_nr_running > 0) - cpudl_set(&rq->rd->cpudl, rq->cpu, rq->dl.earliest_dl.curr); -} - -/* Assumes rq->lock is held */ -static void rq_offline_dl(struct rq *rq) -{ - if (rq->dl.overloaded) - dl_clear_overload(rq); - - cpudl_clear(&rq->rd->cpudl, rq->cpu); - cpudl_clear_freecpu(&rq->rd->cpudl, rq->cpu); -} - -void __init init_sched_dl_class(void) -{ - unsigned int i; - - for_each_possible_cpu(i) - zalloc_cpumask_var_node(&per_cpu(local_cpu_mask_dl, i), - GFP_KERNEL, cpu_to_node(i)); -} - -#endif /* CONFIG_SMP */ - -static void switched_from_dl(struct rq *rq, struct task_struct *p) -{ - /* - * Start the deadline timer; if we switch back to dl before this we'll - * continue consuming our current CBS slice. If we stay outside of - * SCHED_DEADLINE until the deadline passes, the timer will reset the - * task. - */ - if (!start_dl_timer(p)) - __dl_clear_params(p); - - /* - * Since this might be the only -deadline task on the rq, - * this is the right place to try to pull some other one - * from an overloaded cpu, if any. - */ - if (!task_on_rq_queued(p) || rq->dl.dl_nr_running) - return; - - queue_pull_task(rq); -} - -/* - * When switching to -deadline, we may overload the rq, then - * we try to push someone off, if possible. - */ -static void switched_to_dl(struct rq *rq, struct task_struct *p) -{ - - /* If p is not queued we will update its parameters at next wakeup. */ - if (!task_on_rq_queued(p)) - return; - - /* - * If p is boosted we already updated its params in - * rt_mutex_setprio()->enqueue_task(..., ENQUEUE_REPLENISH), - * p's deadline being now already after rq_clock(rq). - */ - if (dl_time_before(p->dl.deadline, rq_clock(rq))) - setup_new_dl_entity(&p->dl); - - if (rq->curr != p) { -#ifdef CONFIG_SMP - if (tsk_nr_cpus_allowed(p) > 1 && rq->dl.overloaded) - queue_push_tasks(rq); -#else - if (dl_task(rq->curr)) - check_preempt_curr_dl(rq, p, 0); - else - resched_curr(rq); -#endif - } -} - -/* - * If the scheduling parameters of a -deadline task changed, - * a push or pull operation might be needed. - */ -static void prio_changed_dl(struct rq *rq, struct task_struct *p, - int oldprio) -{ - if (task_on_rq_queued(p) || rq->curr == p) { -#ifdef CONFIG_SMP - /* - * This might be too much, but unfortunately - * we don't have the old deadline value, and - * we can't argue if the task is increasing - * or lowering its prio, so... - */ - if (!rq->dl.overloaded) - queue_pull_task(rq); - - /* - * If we now have a earlier deadline task than p, - * then reschedule, provided p is still on this - * runqueue. - */ - if (dl_time_before(rq->dl.earliest_dl.curr, p->dl.deadline)) - resched_curr(rq); -#else - /* - * Again, we don't know if p has a earlier - * or later deadline, so let's blindly set a - * (maybe not needed) rescheduling point. - */ - resched_curr(rq); -#endif /* CONFIG_SMP */ - } -} - -const struct sched_class dl_sched_class = { - .next = &rt_sched_class, - .enqueue_task = enqueue_task_dl, - .dequeue_task = dequeue_task_dl, - .yield_task = yield_task_dl, - - .check_preempt_curr = check_preempt_curr_dl, - - .pick_next_task = pick_next_task_dl, - .put_prev_task = put_prev_task_dl, - -#ifdef CONFIG_SMP - .select_task_rq = select_task_rq_dl, - .set_cpus_allowed = set_cpus_allowed_dl, - .rq_online = rq_online_dl, - .rq_offline = rq_offline_dl, - .task_woken = task_woken_dl, -#endif - - .set_curr_task = set_curr_task_dl, - .task_tick = task_tick_dl, - .task_fork = task_fork_dl, - .task_dead = task_dead_dl, - - .prio_changed = prio_changed_dl, - .switched_from = switched_from_dl, - .switched_to = switched_to_dl, - - .update_curr = update_curr_dl, -}; - -#ifdef CONFIG_SCHED_DEBUG -extern void print_dl_rq(struct seq_file *m, int cpu, struct dl_rq *dl_rq); - -void print_dl_stats(struct seq_file *m, int cpu) -{ - print_dl_rq(m, cpu, &cpu_rq(cpu)->dl); -} -#endif /* CONFIG_SCHED_DEBUG */ diff --git a/src/linux/kernel/sched/debug.c b/src/linux/kernel/sched/debug.c deleted file mode 100644 index fa178b6..0000000 --- a/src/linux/kernel/sched/debug.c +++ /dev/null @@ -1,981 +0,0 @@ -/* - * kernel/sched/debug.c - * - * Print the CFS rbtree - * - * Copyright(C) 2007, Red Hat, Inc., Ingo Molnar - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "sched.h" - -static DEFINE_SPINLOCK(sched_debug_lock); - -/* - * This allows printing both to /proc/sched_debug and - * to the console - */ -#define SEQ_printf(m, x...) \ - do { \ - if (m) \ - seq_printf(m, x); \ - else \ - printk(x); \ - } while (0) - -/* - * Ease the printing of nsec fields: - */ -static long long nsec_high(unsigned long long nsec) -{ - if ((long long)nsec < 0) { - nsec = -nsec; - do_div(nsec, 1000000); - return -nsec; - } - do_div(nsec, 1000000); - - return nsec; -} - -static unsigned long nsec_low(unsigned long long nsec) -{ - if ((long long)nsec < 0) - nsec = -nsec; - - return do_div(nsec, 1000000); -} - -#define SPLIT_NS(x) nsec_high(x), nsec_low(x) - -#define SCHED_FEAT(name, enabled) \ - #name , - -static const char * const sched_feat_names[] = { -#include "features.h" -}; - -#undef SCHED_FEAT - -static int sched_feat_show(struct seq_file *m, void *v) -{ - int i; - - for (i = 0; i < __SCHED_FEAT_NR; i++) { - if (!(sysctl_sched_features & (1UL << i))) - seq_puts(m, "NO_"); - seq_printf(m, "%s ", sched_feat_names[i]); - } - seq_puts(m, "\n"); - - return 0; -} - -#ifdef HAVE_JUMP_LABEL - -#define jump_label_key__true STATIC_KEY_INIT_TRUE -#define jump_label_key__false STATIC_KEY_INIT_FALSE - -#define SCHED_FEAT(name, enabled) \ - jump_label_key__##enabled , - -struct static_key sched_feat_keys[__SCHED_FEAT_NR] = { -#include "features.h" -}; - -#undef SCHED_FEAT - -static void sched_feat_disable(int i) -{ - static_key_disable(&sched_feat_keys[i]); -} - -static void sched_feat_enable(int i) -{ - static_key_enable(&sched_feat_keys[i]); -} -#else -static void sched_feat_disable(int i) { }; -static void sched_feat_enable(int i) { }; -#endif /* HAVE_JUMP_LABEL */ - -static int sched_feat_set(char *cmp) -{ - int i; - int neg = 0; - - if (strncmp(cmp, "NO_", 3) == 0) { - neg = 1; - cmp += 3; - } - - for (i = 0; i < __SCHED_FEAT_NR; i++) { - if (strcmp(cmp, sched_feat_names[i]) == 0) { - if (neg) { - sysctl_sched_features &= ~(1UL << i); - sched_feat_disable(i); - } else { - sysctl_sched_features |= (1UL << i); - sched_feat_enable(i); - } - break; - } - } - - return i; -} - -static ssize_t -sched_feat_write(struct file *filp, const char __user *ubuf, - size_t cnt, loff_t *ppos) -{ - char buf[64]; - char *cmp; - int i; - struct inode *inode; - - if (cnt > 63) - cnt = 63; - - if (copy_from_user(&buf, ubuf, cnt)) - return -EFAULT; - - buf[cnt] = 0; - cmp = strstrip(buf); - - /* Ensure the static_key remains in a consistent state */ - inode = file_inode(filp); - inode_lock(inode); - i = sched_feat_set(cmp); - inode_unlock(inode); - if (i == __SCHED_FEAT_NR) - return -EINVAL; - - *ppos += cnt; - - return cnt; -} - -static int sched_feat_open(struct inode *inode, struct file *filp) -{ - return single_open(filp, sched_feat_show, NULL); -} - -static const struct file_operations sched_feat_fops = { - .open = sched_feat_open, - .write = sched_feat_write, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static __init int sched_init_debug(void) -{ - debugfs_create_file("sched_features", 0644, NULL, NULL, - &sched_feat_fops); - - return 0; -} -late_initcall(sched_init_debug); - -#ifdef CONFIG_SMP - -#ifdef CONFIG_SYSCTL - -static struct ctl_table sd_ctl_dir[] = { - { - .procname = "sched_domain", - .mode = 0555, - }, - {} -}; - -static struct ctl_table sd_ctl_root[] = { - { - .procname = "kernel", - .mode = 0555, - .child = sd_ctl_dir, - }, - {} -}; - -static struct ctl_table *sd_alloc_ctl_entry(int n) -{ - struct ctl_table *entry = - kcalloc(n, sizeof(struct ctl_table), GFP_KERNEL); - - return entry; -} - -static void sd_free_ctl_entry(struct ctl_table **tablep) -{ - struct ctl_table *entry; - - /* - * In the intermediate directories, both the child directory and - * procname are dynamically allocated and could fail but the mode - * will always be set. In the lowest directory the names are - * static strings and all have proc handlers. - */ - for (entry = *tablep; entry->mode; entry++) { - if (entry->child) - sd_free_ctl_entry(&entry->child); - if (entry->proc_handler == NULL) - kfree(entry->procname); - } - - kfree(*tablep); - *tablep = NULL; -} - -static int min_load_idx = 0; -static int max_load_idx = CPU_LOAD_IDX_MAX-1; - -static void -set_table_entry(struct ctl_table *entry, - const char *procname, void *data, int maxlen, - umode_t mode, proc_handler *proc_handler, - bool load_idx) -{ - entry->procname = procname; - entry->data = data; - entry->maxlen = maxlen; - entry->mode = mode; - entry->proc_handler = proc_handler; - - if (load_idx) { - entry->extra1 = &min_load_idx; - entry->extra2 = &max_load_idx; - } -} - -static struct ctl_table * -sd_alloc_ctl_domain_table(struct sched_domain *sd) -{ - struct ctl_table *table = sd_alloc_ctl_entry(14); - - if (table == NULL) - return NULL; - - set_table_entry(&table[0], "min_interval", &sd->min_interval, - sizeof(long), 0644, proc_doulongvec_minmax, false); - set_table_entry(&table[1], "max_interval", &sd->max_interval, - sizeof(long), 0644, proc_doulongvec_minmax, false); - set_table_entry(&table[2], "busy_idx", &sd->busy_idx, - sizeof(int), 0644, proc_dointvec_minmax, true); - set_table_entry(&table[3], "idle_idx", &sd->idle_idx, - sizeof(int), 0644, proc_dointvec_minmax, true); - set_table_entry(&table[4], "newidle_idx", &sd->newidle_idx, - sizeof(int), 0644, proc_dointvec_minmax, true); - set_table_entry(&table[5], "wake_idx", &sd->wake_idx, - sizeof(int), 0644, proc_dointvec_minmax, true); - set_table_entry(&table[6], "forkexec_idx", &sd->forkexec_idx, - sizeof(int), 0644, proc_dointvec_minmax, true); - set_table_entry(&table[7], "busy_factor", &sd->busy_factor, - sizeof(int), 0644, proc_dointvec_minmax, false); - set_table_entry(&table[8], "imbalance_pct", &sd->imbalance_pct, - sizeof(int), 0644, proc_dointvec_minmax, false); - set_table_entry(&table[9], "cache_nice_tries", - &sd->cache_nice_tries, - sizeof(int), 0644, proc_dointvec_minmax, false); - set_table_entry(&table[10], "flags", &sd->flags, - sizeof(int), 0644, proc_dointvec_minmax, false); - set_table_entry(&table[11], "max_newidle_lb_cost", - &sd->max_newidle_lb_cost, - sizeof(long), 0644, proc_doulongvec_minmax, false); - set_table_entry(&table[12], "name", sd->name, - CORENAME_MAX_SIZE, 0444, proc_dostring, false); - /* &table[13] is terminator */ - - return table; -} - -static struct ctl_table *sd_alloc_ctl_cpu_table(int cpu) -{ - struct ctl_table *entry, *table; - struct sched_domain *sd; - int domain_num = 0, i; - char buf[32]; - - for_each_domain(cpu, sd) - domain_num++; - entry = table = sd_alloc_ctl_entry(domain_num + 1); - if (table == NULL) - return NULL; - - i = 0; - for_each_domain(cpu, sd) { - snprintf(buf, 32, "domain%d", i); - entry->procname = kstrdup(buf, GFP_KERNEL); - entry->mode = 0555; - entry->child = sd_alloc_ctl_domain_table(sd); - entry++; - i++; - } - return table; -} - -static struct ctl_table_header *sd_sysctl_header; -void register_sched_domain_sysctl(void) -{ - int i, cpu_num = num_possible_cpus(); - struct ctl_table *entry = sd_alloc_ctl_entry(cpu_num + 1); - char buf[32]; - - WARN_ON(sd_ctl_dir[0].child); - sd_ctl_dir[0].child = entry; - - if (entry == NULL) - return; - - for_each_possible_cpu(i) { - snprintf(buf, 32, "cpu%d", i); - entry->procname = kstrdup(buf, GFP_KERNEL); - entry->mode = 0555; - entry->child = sd_alloc_ctl_cpu_table(i); - entry++; - } - - WARN_ON(sd_sysctl_header); - sd_sysctl_header = register_sysctl_table(sd_ctl_root); -} - -/* may be called multiple times per register */ -void unregister_sched_domain_sysctl(void) -{ - unregister_sysctl_table(sd_sysctl_header); - sd_sysctl_header = NULL; - if (sd_ctl_dir[0].child) - sd_free_ctl_entry(&sd_ctl_dir[0].child); -} -#endif /* CONFIG_SYSCTL */ -#endif /* CONFIG_SMP */ - -#ifdef CONFIG_FAIR_GROUP_SCHED -static void print_cfs_group_stats(struct seq_file *m, int cpu, struct task_group *tg) -{ - struct sched_entity *se = tg->se[cpu]; - -#define P(F) \ - SEQ_printf(m, " .%-30s: %lld\n", #F, (long long)F) -#define P_SCHEDSTAT(F) \ - SEQ_printf(m, " .%-30s: %lld\n", #F, (long long)schedstat_val(F)) -#define PN(F) \ - SEQ_printf(m, " .%-30s: %lld.%06ld\n", #F, SPLIT_NS((long long)F)) -#define PN_SCHEDSTAT(F) \ - SEQ_printf(m, " .%-30s: %lld.%06ld\n", #F, SPLIT_NS((long long)schedstat_val(F))) - - if (!se) - return; - - PN(se->exec_start); - PN(se->vruntime); - PN(se->sum_exec_runtime); - if (schedstat_enabled()) { - PN_SCHEDSTAT(se->statistics.wait_start); - PN_SCHEDSTAT(se->statistics.sleep_start); - PN_SCHEDSTAT(se->statistics.block_start); - PN_SCHEDSTAT(se->statistics.sleep_max); - PN_SCHEDSTAT(se->statistics.block_max); - PN_SCHEDSTAT(se->statistics.exec_max); - PN_SCHEDSTAT(se->statistics.slice_max); - PN_SCHEDSTAT(se->statistics.wait_max); - PN_SCHEDSTAT(se->statistics.wait_sum); - P_SCHEDSTAT(se->statistics.wait_count); - } - P(se->load.weight); -#ifdef CONFIG_SMP - P(se->avg.load_avg); - P(se->avg.util_avg); -#endif - -#undef PN_SCHEDSTAT -#undef PN -#undef P_SCHEDSTAT -#undef P -} -#endif - -#ifdef CONFIG_CGROUP_SCHED -static char group_path[PATH_MAX]; - -static char *task_group_path(struct task_group *tg) -{ - if (autogroup_path(tg, group_path, PATH_MAX)) - return group_path; - - cgroup_path(tg->css.cgroup, group_path, PATH_MAX); - return group_path; -} -#endif - -static void -print_task(struct seq_file *m, struct rq *rq, struct task_struct *p) -{ - if (rq->curr == p) - SEQ_printf(m, "R"); - else - SEQ_printf(m, " "); - - SEQ_printf(m, "%15s %5d %9Ld.%06ld %9Ld %5d ", - p->comm, task_pid_nr(p), - SPLIT_NS(p->se.vruntime), - (long long)(p->nvcsw + p->nivcsw), - p->prio); - - SEQ_printf(m, "%9Ld.%06ld %9Ld.%06ld %9Ld.%06ld", - SPLIT_NS(schedstat_val_or_zero(p->se.statistics.wait_sum)), - SPLIT_NS(p->se.sum_exec_runtime), - SPLIT_NS(schedstat_val_or_zero(p->se.statistics.sum_sleep_runtime))); - -#ifdef CONFIG_NUMA_BALANCING - SEQ_printf(m, " %d %d", task_node(p), task_numa_group_id(p)); -#endif -#ifdef CONFIG_CGROUP_SCHED - SEQ_printf(m, " %s", task_group_path(task_group(p))); -#endif - - SEQ_printf(m, "\n"); -} - -static void print_rq(struct seq_file *m, struct rq *rq, int rq_cpu) -{ - struct task_struct *g, *p; - - SEQ_printf(m, - "\nrunnable tasks:\n" - " task PID tree-key switches prio" - " wait-time sum-exec sum-sleep\n" - "------------------------------------------------------" - "----------------------------------------------------\n"); - - rcu_read_lock(); - for_each_process_thread(g, p) { - if (task_cpu(p) != rq_cpu) - continue; - - print_task(m, rq, p); - } - rcu_read_unlock(); -} - -void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq) -{ - s64 MIN_vruntime = -1, min_vruntime, max_vruntime = -1, - spread, rq0_min_vruntime, spread0; - struct rq *rq = cpu_rq(cpu); - struct sched_entity *last; - unsigned long flags; - -#ifdef CONFIG_FAIR_GROUP_SCHED - SEQ_printf(m, "\ncfs_rq[%d]:%s\n", cpu, task_group_path(cfs_rq->tg)); -#else - SEQ_printf(m, "\ncfs_rq[%d]:\n", cpu); -#endif - SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "exec_clock", - SPLIT_NS(cfs_rq->exec_clock)); - - raw_spin_lock_irqsave(&rq->lock, flags); - if (cfs_rq->rb_leftmost) - MIN_vruntime = (__pick_first_entity(cfs_rq))->vruntime; - last = __pick_last_entity(cfs_rq); - if (last) - max_vruntime = last->vruntime; - min_vruntime = cfs_rq->min_vruntime; - rq0_min_vruntime = cpu_rq(0)->cfs.min_vruntime; - raw_spin_unlock_irqrestore(&rq->lock, flags); - SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "MIN_vruntime", - SPLIT_NS(MIN_vruntime)); - SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "min_vruntime", - SPLIT_NS(min_vruntime)); - SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "max_vruntime", - SPLIT_NS(max_vruntime)); - spread = max_vruntime - MIN_vruntime; - SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "spread", - SPLIT_NS(spread)); - spread0 = min_vruntime - rq0_min_vruntime; - SEQ_printf(m, " .%-30s: %Ld.%06ld\n", "spread0", - SPLIT_NS(spread0)); - SEQ_printf(m, " .%-30s: %d\n", "nr_spread_over", - cfs_rq->nr_spread_over); - SEQ_printf(m, " .%-30s: %d\n", "nr_running", cfs_rq->nr_running); - SEQ_printf(m, " .%-30s: %ld\n", "load", cfs_rq->load.weight); -#ifdef CONFIG_SMP - SEQ_printf(m, " .%-30s: %lu\n", "load_avg", - cfs_rq->avg.load_avg); - SEQ_printf(m, " .%-30s: %lu\n", "runnable_load_avg", - cfs_rq->runnable_load_avg); - SEQ_printf(m, " .%-30s: %lu\n", "util_avg", - cfs_rq->avg.util_avg); - SEQ_printf(m, " .%-30s: %ld\n", "removed_load_avg", - atomic_long_read(&cfs_rq->removed_load_avg)); - SEQ_printf(m, " .%-30s: %ld\n", "removed_util_avg", - atomic_long_read(&cfs_rq->removed_util_avg)); -#ifdef CONFIG_FAIR_GROUP_SCHED - SEQ_printf(m, " .%-30s: %lu\n", "tg_load_avg_contrib", - cfs_rq->tg_load_avg_contrib); - SEQ_printf(m, " .%-30s: %ld\n", "tg_load_avg", - atomic_long_read(&cfs_rq->tg->load_avg)); -#endif -#endif -#ifdef CONFIG_CFS_BANDWIDTH - SEQ_printf(m, " .%-30s: %d\n", "throttled", - cfs_rq->throttled); - SEQ_printf(m, " .%-30s: %d\n", "throttle_count", - cfs_rq->throttle_count); -#endif - -#ifdef CONFIG_FAIR_GROUP_SCHED - print_cfs_group_stats(m, cpu, cfs_rq->tg); -#endif -} - -void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq) -{ -#ifdef CONFIG_RT_GROUP_SCHED - SEQ_printf(m, "\nrt_rq[%d]:%s\n", cpu, task_group_path(rt_rq->tg)); -#else - SEQ_printf(m, "\nrt_rq[%d]:\n", cpu); -#endif - -#define P(x) \ - SEQ_printf(m, " .%-30s: %Ld\n", #x, (long long)(rt_rq->x)) -#define PN(x) \ - SEQ_printf(m, " .%-30s: %Ld.%06ld\n", #x, SPLIT_NS(rt_rq->x)) - - P(rt_nr_running); - P(rt_throttled); - PN(rt_time); - PN(rt_runtime); - -#undef PN -#undef P -} - -void print_dl_rq(struct seq_file *m, int cpu, struct dl_rq *dl_rq) -{ - struct dl_bw *dl_bw; - - SEQ_printf(m, "\ndl_rq[%d]:\n", cpu); - SEQ_printf(m, " .%-30s: %ld\n", "dl_nr_running", dl_rq->dl_nr_running); -#ifdef CONFIG_SMP - dl_bw = &cpu_rq(cpu)->rd->dl_bw; -#else - dl_bw = &dl_rq->dl_bw; -#endif - SEQ_printf(m, " .%-30s: %lld\n", "dl_bw->bw", dl_bw->bw); - SEQ_printf(m, " .%-30s: %lld\n", "dl_bw->total_bw", dl_bw->total_bw); -} - -extern __read_mostly int sched_clock_running; - -static void print_cpu(struct seq_file *m, int cpu) -{ - struct rq *rq = cpu_rq(cpu); - unsigned long flags; - -#ifdef CONFIG_X86 - { - unsigned int freq = cpu_khz ? : 1; - - SEQ_printf(m, "cpu#%d, %u.%03u MHz\n", - cpu, freq / 1000, (freq % 1000)); - } -#else - SEQ_printf(m, "cpu#%d\n", cpu); -#endif - -#define P(x) \ -do { \ - if (sizeof(rq->x) == 4) \ - SEQ_printf(m, " .%-30s: %ld\n", #x, (long)(rq->x)); \ - else \ - SEQ_printf(m, " .%-30s: %Ld\n", #x, (long long)(rq->x));\ -} while (0) - -#define PN(x) \ - SEQ_printf(m, " .%-30s: %Ld.%06ld\n", #x, SPLIT_NS(rq->x)) - - P(nr_running); - SEQ_printf(m, " .%-30s: %lu\n", "load", - rq->load.weight); - P(nr_switches); - P(nr_load_updates); - P(nr_uninterruptible); - PN(next_balance); - SEQ_printf(m, " .%-30s: %ld\n", "curr->pid", (long)(task_pid_nr(rq->curr))); - PN(clock); - PN(clock_task); - P(cpu_load[0]); - P(cpu_load[1]); - P(cpu_load[2]); - P(cpu_load[3]); - P(cpu_load[4]); -#undef P -#undef PN - -#ifdef CONFIG_SMP -#define P64(n) SEQ_printf(m, " .%-30s: %Ld\n", #n, rq->n); - P64(avg_idle); - P64(max_idle_balance_cost); -#undef P64 -#endif - -#define P(n) SEQ_printf(m, " .%-30s: %d\n", #n, schedstat_val(rq->n)); - if (schedstat_enabled()) { - P(yld_count); - P(sched_count); - P(sched_goidle); - P(ttwu_count); - P(ttwu_local); - } -#undef P - - spin_lock_irqsave(&sched_debug_lock, flags); - print_cfs_stats(m, cpu); - print_rt_stats(m, cpu); - print_dl_stats(m, cpu); - - print_rq(m, rq, cpu); - spin_unlock_irqrestore(&sched_debug_lock, flags); - SEQ_printf(m, "\n"); -} - -static const char *sched_tunable_scaling_names[] = { - "none", - "logaritmic", - "linear" -}; - -static void sched_debug_header(struct seq_file *m) -{ - u64 ktime, sched_clk, cpu_clk; - unsigned long flags; - - local_irq_save(flags); - ktime = ktime_to_ns(ktime_get()); - sched_clk = sched_clock(); - cpu_clk = local_clock(); - local_irq_restore(flags); - - SEQ_printf(m, "Sched Debug Version: v0.11, %s %.*s\n", - init_utsname()->release, - (int)strcspn(init_utsname()->version, " "), - init_utsname()->version); - -#define P(x) \ - SEQ_printf(m, "%-40s: %Ld\n", #x, (long long)(x)) -#define PN(x) \ - SEQ_printf(m, "%-40s: %Ld.%06ld\n", #x, SPLIT_NS(x)) - PN(ktime); - PN(sched_clk); - PN(cpu_clk); - P(jiffies); -#ifdef CONFIG_HAVE_UNSTABLE_SCHED_CLOCK - P(sched_clock_stable()); -#endif -#undef PN -#undef P - - SEQ_printf(m, "\n"); - SEQ_printf(m, "sysctl_sched\n"); - -#define P(x) \ - SEQ_printf(m, " .%-40s: %Ld\n", #x, (long long)(x)) -#define PN(x) \ - SEQ_printf(m, " .%-40s: %Ld.%06ld\n", #x, SPLIT_NS(x)) - PN(sysctl_sched_latency); - PN(sysctl_sched_min_granularity); - PN(sysctl_sched_wakeup_granularity); - P(sysctl_sched_child_runs_first); - P(sysctl_sched_features); -#undef PN -#undef P - - SEQ_printf(m, " .%-40s: %d (%s)\n", - "sysctl_sched_tunable_scaling", - sysctl_sched_tunable_scaling, - sched_tunable_scaling_names[sysctl_sched_tunable_scaling]); - SEQ_printf(m, "\n"); -} - -static int sched_debug_show(struct seq_file *m, void *v) -{ - int cpu = (unsigned long)(v - 2); - - if (cpu != -1) - print_cpu(m, cpu); - else - sched_debug_header(m); - - return 0; -} - -void sysrq_sched_debug_show(void) -{ - int cpu; - - sched_debug_header(NULL); - for_each_online_cpu(cpu) - print_cpu(NULL, cpu); - -} - -/* - * This itererator needs some explanation. - * It returns 1 for the header position. - * This means 2 is cpu 0. - * In a hotplugged system some cpus, including cpu 0, may be missing so we have - * to use cpumask_* to iterate over the cpus. - */ -static void *sched_debug_start(struct seq_file *file, loff_t *offset) -{ - unsigned long n = *offset; - - if (n == 0) - return (void *) 1; - - n--; - - if (n > 0) - n = cpumask_next(n - 1, cpu_online_mask); - else - n = cpumask_first(cpu_online_mask); - - *offset = n + 1; - - if (n < nr_cpu_ids) - return (void *)(unsigned long)(n + 2); - return NULL; -} - -static void *sched_debug_next(struct seq_file *file, void *data, loff_t *offset) -{ - (*offset)++; - return sched_debug_start(file, offset); -} - -static void sched_debug_stop(struct seq_file *file, void *data) -{ -} - -static const struct seq_operations sched_debug_sops = { - .start = sched_debug_start, - .next = sched_debug_next, - .stop = sched_debug_stop, - .show = sched_debug_show, -}; - -static int sched_debug_release(struct inode *inode, struct file *file) -{ - seq_release(inode, file); - - return 0; -} - -static int sched_debug_open(struct inode *inode, struct file *filp) -{ - int ret = 0; - - ret = seq_open(filp, &sched_debug_sops); - - return ret; -} - -static const struct file_operations sched_debug_fops = { - .open = sched_debug_open, - .read = seq_read, - .llseek = seq_lseek, - .release = sched_debug_release, -}; - -static int __init init_sched_debug_procfs(void) -{ - struct proc_dir_entry *pe; - - pe = proc_create("sched_debug", 0444, NULL, &sched_debug_fops); - if (!pe) - return -ENOMEM; - return 0; -} - -__initcall(init_sched_debug_procfs); - -#define __P(F) \ - SEQ_printf(m, "%-45s:%21Ld\n", #F, (long long)F) -#define P(F) \ - SEQ_printf(m, "%-45s:%21Ld\n", #F, (long long)p->F) -#define __PN(F) \ - SEQ_printf(m, "%-45s:%14Ld.%06ld\n", #F, SPLIT_NS((long long)F)) -#define PN(F) \ - SEQ_printf(m, "%-45s:%14Ld.%06ld\n", #F, SPLIT_NS((long long)p->F)) - - -#ifdef CONFIG_NUMA_BALANCING -void print_numa_stats(struct seq_file *m, int node, unsigned long tsf, - unsigned long tpf, unsigned long gsf, unsigned long gpf) -{ - SEQ_printf(m, "numa_faults node=%d ", node); - SEQ_printf(m, "task_private=%lu task_shared=%lu ", tsf, tpf); - SEQ_printf(m, "group_private=%lu group_shared=%lu\n", gsf, gpf); -} -#endif - - -static void sched_show_numa(struct task_struct *p, struct seq_file *m) -{ -#ifdef CONFIG_NUMA_BALANCING - struct mempolicy *pol; - - if (p->mm) - P(mm->numa_scan_seq); - - task_lock(p); - pol = p->mempolicy; - if (pol && !(pol->flags & MPOL_F_MORON)) - pol = NULL; - mpol_get(pol); - task_unlock(p); - - P(numa_pages_migrated); - P(numa_preferred_nid); - P(total_numa_faults); - SEQ_printf(m, "current_node=%d, numa_group_id=%d\n", - task_node(p), task_numa_group_id(p)); - show_numa_stats(p, m); - mpol_put(pol); -#endif -} - -void proc_sched_show_task(struct task_struct *p, struct seq_file *m) -{ - unsigned long nr_switches; - - SEQ_printf(m, "%s (%d, #threads: %d)\n", p->comm, task_pid_nr(p), - get_nr_threads(p)); - SEQ_printf(m, - "---------------------------------------------------------" - "----------\n"); -#define __P(F) \ - SEQ_printf(m, "%-45s:%21Ld\n", #F, (long long)F) -#define P(F) \ - SEQ_printf(m, "%-45s:%21Ld\n", #F, (long long)p->F) -#define P_SCHEDSTAT(F) \ - SEQ_printf(m, "%-45s:%21Ld\n", #F, (long long)schedstat_val(p->F)) -#define __PN(F) \ - SEQ_printf(m, "%-45s:%14Ld.%06ld\n", #F, SPLIT_NS((long long)F)) -#define PN(F) \ - SEQ_printf(m, "%-45s:%14Ld.%06ld\n", #F, SPLIT_NS((long long)p->F)) -#define PN_SCHEDSTAT(F) \ - SEQ_printf(m, "%-45s:%14Ld.%06ld\n", #F, SPLIT_NS((long long)schedstat_val(p->F))) - - PN(se.exec_start); - PN(se.vruntime); - PN(se.sum_exec_runtime); - - nr_switches = p->nvcsw + p->nivcsw; - - P(se.nr_migrations); - - if (schedstat_enabled()) { - u64 avg_atom, avg_per_cpu; - - PN_SCHEDSTAT(se.statistics.sum_sleep_runtime); - PN_SCHEDSTAT(se.statistics.wait_start); - PN_SCHEDSTAT(se.statistics.sleep_start); - PN_SCHEDSTAT(se.statistics.block_start); - PN_SCHEDSTAT(se.statistics.sleep_max); - PN_SCHEDSTAT(se.statistics.block_max); - PN_SCHEDSTAT(se.statistics.exec_max); - PN_SCHEDSTAT(se.statistics.slice_max); - PN_SCHEDSTAT(se.statistics.wait_max); - PN_SCHEDSTAT(se.statistics.wait_sum); - P_SCHEDSTAT(se.statistics.wait_count); - PN_SCHEDSTAT(se.statistics.iowait_sum); - P_SCHEDSTAT(se.statistics.iowait_count); - P_SCHEDSTAT(se.statistics.nr_migrations_cold); - P_SCHEDSTAT(se.statistics.nr_failed_migrations_affine); - P_SCHEDSTAT(se.statistics.nr_failed_migrations_running); - P_SCHEDSTAT(se.statistics.nr_failed_migrations_hot); - P_SCHEDSTAT(se.statistics.nr_forced_migrations); - P_SCHEDSTAT(se.statistics.nr_wakeups); - P_SCHEDSTAT(se.statistics.nr_wakeups_sync); - P_SCHEDSTAT(se.statistics.nr_wakeups_migrate); - P_SCHEDSTAT(se.statistics.nr_wakeups_local); - P_SCHEDSTAT(se.statistics.nr_wakeups_remote); - P_SCHEDSTAT(se.statistics.nr_wakeups_affine); - P_SCHEDSTAT(se.statistics.nr_wakeups_affine_attempts); - P_SCHEDSTAT(se.statistics.nr_wakeups_passive); - P_SCHEDSTAT(se.statistics.nr_wakeups_idle); - - avg_atom = p->se.sum_exec_runtime; - if (nr_switches) - avg_atom = div64_ul(avg_atom, nr_switches); - else - avg_atom = -1LL; - - avg_per_cpu = p->se.sum_exec_runtime; - if (p->se.nr_migrations) { - avg_per_cpu = div64_u64(avg_per_cpu, - p->se.nr_migrations); - } else { - avg_per_cpu = -1LL; - } - - __PN(avg_atom); - __PN(avg_per_cpu); - } - - __P(nr_switches); - SEQ_printf(m, "%-45s:%21Ld\n", - "nr_voluntary_switches", (long long)p->nvcsw); - SEQ_printf(m, "%-45s:%21Ld\n", - "nr_involuntary_switches", (long long)p->nivcsw); - - P(se.load.weight); -#ifdef CONFIG_SMP - P(se.avg.load_sum); - P(se.avg.util_sum); - P(se.avg.load_avg); - P(se.avg.util_avg); - P(se.avg.last_update_time); -#endif - P(policy); - P(prio); -#undef PN_SCHEDSTAT -#undef PN -#undef __PN -#undef P_SCHEDSTAT -#undef P -#undef __P - - { - unsigned int this_cpu = raw_smp_processor_id(); - u64 t0, t1; - - t0 = cpu_clock(this_cpu); - t1 = cpu_clock(this_cpu); - SEQ_printf(m, "%-45s:%21Ld\n", - "clock-delta", (long long)(t1-t0)); - } - - sched_show_numa(p, m); -} - -void proc_sched_set_task(struct task_struct *p) -{ -#ifdef CONFIG_SCHEDSTATS - memset(&p->se.statistics, 0, sizeof(p->se.statistics)); -#endif -} diff --git a/src/linux/kernel/sched/fair.c b/src/linux/kernel/sched/fair.c deleted file mode 100644 index c242944..0000000 --- a/src/linux/kernel/sched/fair.c +++ /dev/null @@ -1,9108 +0,0 @@ -/* - * Completely Fair Scheduling (CFS) Class (SCHED_NORMAL/SCHED_BATCH) - * - * Copyright (C) 2007 Red Hat, Inc., Ingo Molnar - * - * Interactivity improvements by Mike Galbraith - * (C) 2007 Mike Galbraith - * - * Various enhancements by Dmitry Adamushko. - * (C) 2007 Dmitry Adamushko - * - * Group scheduling enhancements by Srivatsa Vaddagiri - * Copyright IBM Corporation, 2007 - * Author: Srivatsa Vaddagiri - * - * Scaled math optimizations by Thomas Gleixner - * Copyright (C) 2007, Thomas Gleixner - * - * Adaptive scheduling granularity, math enhancements by Peter Zijlstra - * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "sched.h" - -/* - * Targeted preemption latency for CPU-bound tasks: - * (default: 6ms * (1 + ilog(ncpus)), units: nanoseconds) - * - * NOTE: this latency value is not the same as the concept of - * 'timeslice length' - timeslices in CFS are of variable length - * and have no persistent notion like in traditional, time-slice - * based scheduling concepts. - * - * (to see the precise effective timeslice length of your workload, - * run vmstat and monitor the context-switches (cs) field) - */ -unsigned int sysctl_sched_latency = 6000000ULL; -unsigned int normalized_sysctl_sched_latency = 6000000ULL; - -/* - * The initial- and re-scaling of tunables is configurable - * (default SCHED_TUNABLESCALING_LOG = *(1+ilog(ncpus)) - * - * Options are: - * SCHED_TUNABLESCALING_NONE - unscaled, always *1 - * SCHED_TUNABLESCALING_LOG - scaled logarithmical, *1+ilog(ncpus) - * SCHED_TUNABLESCALING_LINEAR - scaled linear, *ncpus - */ -enum sched_tunable_scaling sysctl_sched_tunable_scaling - = SCHED_TUNABLESCALING_LOG; - -/* - * Minimal preemption granularity for CPU-bound tasks: - * (default: 0.75 msec * (1 + ilog(ncpus)), units: nanoseconds) - */ -unsigned int sysctl_sched_min_granularity = 750000ULL; -unsigned int normalized_sysctl_sched_min_granularity = 750000ULL; - -/* - * is kept at sysctl_sched_latency / sysctl_sched_min_granularity - */ -static unsigned int sched_nr_latency = 8; - -/* - * After fork, child runs first. If set to 0 (default) then - * parent will (try to) run first. - */ -unsigned int sysctl_sched_child_runs_first __read_mostly; - -/* - * SCHED_OTHER wake-up granularity. - * (default: 1 msec * (1 + ilog(ncpus)), units: nanoseconds) - * - * This option delays the preemption effects of decoupled workloads - * and reduces their over-scheduling. Synchronous workloads will still - * have immediate wakeup/sleep latencies. - */ -unsigned int sysctl_sched_wakeup_granularity = 1000000UL; -unsigned int normalized_sysctl_sched_wakeup_granularity = 1000000UL; - -const_debug unsigned int sysctl_sched_migration_cost = 500000UL; - -/* - * The exponential sliding window over which load is averaged for shares - * distribution. - * (default: 10msec) - */ -unsigned int __read_mostly sysctl_sched_shares_window = 10000000UL; - -#ifdef CONFIG_CFS_BANDWIDTH -/* - * Amount of runtime to allocate from global (tg) to local (per-cfs_rq) pool - * each time a cfs_rq requests quota. - * - * Note: in the case that the slice exceeds the runtime remaining (either due - * to consumption or the quota being specified to be smaller than the slice) - * we will always only issue the remaining available time. - * - * default: 5 msec, units: microseconds - */ -unsigned int sysctl_sched_cfs_bandwidth_slice = 5000UL; -#endif - -/* - * The margin used when comparing utilization with CPU capacity: - * util * 1024 < capacity * margin - */ -unsigned int capacity_margin = 1280; /* ~20% */ - -static inline void update_load_add(struct load_weight *lw, unsigned long inc) -{ - lw->weight += inc; - lw->inv_weight = 0; -} - -static inline void update_load_sub(struct load_weight *lw, unsigned long dec) -{ - lw->weight -= dec; - lw->inv_weight = 0; -} - -static inline void update_load_set(struct load_weight *lw, unsigned long w) -{ - lw->weight = w; - lw->inv_weight = 0; -} - -/* - * Increase the granularity value when there are more CPUs, - * because with more CPUs the 'effective latency' as visible - * to users decreases. But the relationship is not linear, - * so pick a second-best guess by going with the log2 of the - * number of CPUs. - * - * This idea comes from the SD scheduler of Con Kolivas: - */ -static unsigned int get_update_sysctl_factor(void) -{ - unsigned int cpus = min_t(unsigned int, num_online_cpus(), 8); - unsigned int factor; - - switch (sysctl_sched_tunable_scaling) { - case SCHED_TUNABLESCALING_NONE: - factor = 1; - break; - case SCHED_TUNABLESCALING_LINEAR: - factor = cpus; - break; - case SCHED_TUNABLESCALING_LOG: - default: - factor = 1 + ilog2(cpus); - break; - } - - return factor; -} - -static void update_sysctl(void) -{ - unsigned int factor = get_update_sysctl_factor(); - -#define SET_SYSCTL(name) \ - (sysctl_##name = (factor) * normalized_sysctl_##name) - SET_SYSCTL(sched_min_granularity); - SET_SYSCTL(sched_latency); - SET_SYSCTL(sched_wakeup_granularity); -#undef SET_SYSCTL -} - -void sched_init_granularity(void) -{ - update_sysctl(); -} - -#define WMULT_CONST (~0U) -#define WMULT_SHIFT 32 - -static void __update_inv_weight(struct load_weight *lw) -{ - unsigned long w; - - if (likely(lw->inv_weight)) - return; - - w = scale_load_down(lw->weight); - - if (BITS_PER_LONG > 32 && unlikely(w >= WMULT_CONST)) - lw->inv_weight = 1; - else if (unlikely(!w)) - lw->inv_weight = WMULT_CONST; - else - lw->inv_weight = WMULT_CONST / w; -} - -/* - * delta_exec * weight / lw.weight - * OR - * (delta_exec * (weight * lw->inv_weight)) >> WMULT_SHIFT - * - * Either weight := NICE_0_LOAD and lw \e sched_prio_to_wmult[], in which case - * we're guaranteed shift stays positive because inv_weight is guaranteed to - * fit 32 bits, and NICE_0_LOAD gives another 10 bits; therefore shift >= 22. - * - * Or, weight =< lw.weight (because lw.weight is the runqueue weight), thus - * weight/lw.weight <= 1, and therefore our shift will also be positive. - */ -static u64 __calc_delta(u64 delta_exec, unsigned long weight, struct load_weight *lw) -{ - u64 fact = scale_load_down(weight); - int shift = WMULT_SHIFT; - - __update_inv_weight(lw); - - if (unlikely(fact >> 32)) { - while (fact >> 32) { - fact >>= 1; - shift--; - } - } - - /* hint to use a 32x32->64 mul */ - fact = (u64)(u32)fact * lw->inv_weight; - - while (fact >> 32) { - fact >>= 1; - shift--; - } - - return mul_u64_u32_shr(delta_exec, fact, shift); -} - - -const struct sched_class fair_sched_class; - -/************************************************************** - * CFS operations on generic schedulable entities: - */ - -#ifdef CONFIG_FAIR_GROUP_SCHED - -/* cpu runqueue to which this cfs_rq is attached */ -static inline struct rq *rq_of(struct cfs_rq *cfs_rq) -{ - return cfs_rq->rq; -} - -/* An entity is a task if it doesn't "own" a runqueue */ -#define entity_is_task(se) (!se->my_q) - -static inline struct task_struct *task_of(struct sched_entity *se) -{ - SCHED_WARN_ON(!entity_is_task(se)); - return container_of(se, struct task_struct, se); -} - -/* Walk up scheduling entities hierarchy */ -#define for_each_sched_entity(se) \ - for (; se; se = se->parent) - -static inline struct cfs_rq *task_cfs_rq(struct task_struct *p) -{ - return p->se.cfs_rq; -} - -/* runqueue on which this entity is (to be) queued */ -static inline struct cfs_rq *cfs_rq_of(struct sched_entity *se) -{ - return se->cfs_rq; -} - -/* runqueue "owned" by this group */ -static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp) -{ - return grp->my_q; -} - -static inline void list_add_leaf_cfs_rq(struct cfs_rq *cfs_rq) -{ - if (!cfs_rq->on_list) { - /* - * Ensure we either appear before our parent (if already - * enqueued) or force our parent to appear after us when it is - * enqueued. The fact that we always enqueue bottom-up - * reduces this to two cases. - */ - if (cfs_rq->tg->parent && - cfs_rq->tg->parent->cfs_rq[cpu_of(rq_of(cfs_rq))]->on_list) { - list_add_rcu(&cfs_rq->leaf_cfs_rq_list, - &rq_of(cfs_rq)->leaf_cfs_rq_list); - } else { - list_add_tail_rcu(&cfs_rq->leaf_cfs_rq_list, - &rq_of(cfs_rq)->leaf_cfs_rq_list); - } - - cfs_rq->on_list = 1; - } -} - -static inline void list_del_leaf_cfs_rq(struct cfs_rq *cfs_rq) -{ - if (cfs_rq->on_list) { - list_del_rcu(&cfs_rq->leaf_cfs_rq_list); - cfs_rq->on_list = 0; - } -} - -/* Iterate thr' all leaf cfs_rq's on a runqueue */ -#define for_each_leaf_cfs_rq(rq, cfs_rq) \ - list_for_each_entry_rcu(cfs_rq, &rq->leaf_cfs_rq_list, leaf_cfs_rq_list) - -/* Do the two (enqueued) entities belong to the same group ? */ -static inline struct cfs_rq * -is_same_group(struct sched_entity *se, struct sched_entity *pse) -{ - if (se->cfs_rq == pse->cfs_rq) - return se->cfs_rq; - - return NULL; -} - -static inline struct sched_entity *parent_entity(struct sched_entity *se) -{ - return se->parent; -} - -static void -find_matching_se(struct sched_entity **se, struct sched_entity **pse) -{ - int se_depth, pse_depth; - - /* - * preemption test can be made between sibling entities who are in the - * same cfs_rq i.e who have a common parent. Walk up the hierarchy of - * both tasks until we find their ancestors who are siblings of common - * parent. - */ - - /* First walk up until both entities are at same depth */ - se_depth = (*se)->depth; - pse_depth = (*pse)->depth; - - while (se_depth > pse_depth) { - se_depth--; - *se = parent_entity(*se); - } - - while (pse_depth > se_depth) { - pse_depth--; - *pse = parent_entity(*pse); - } - - while (!is_same_group(*se, *pse)) { - *se = parent_entity(*se); - *pse = parent_entity(*pse); - } -} - -#else /* !CONFIG_FAIR_GROUP_SCHED */ - -static inline struct task_struct *task_of(struct sched_entity *se) -{ - return container_of(se, struct task_struct, se); -} - -static inline struct rq *rq_of(struct cfs_rq *cfs_rq) -{ - return container_of(cfs_rq, struct rq, cfs); -} - -#define entity_is_task(se) 1 - -#define for_each_sched_entity(se) \ - for (; se; se = NULL) - -static inline struct cfs_rq *task_cfs_rq(struct task_struct *p) -{ - return &task_rq(p)->cfs; -} - -static inline struct cfs_rq *cfs_rq_of(struct sched_entity *se) -{ - struct task_struct *p = task_of(se); - struct rq *rq = task_rq(p); - - return &rq->cfs; -} - -/* runqueue "owned" by this group */ -static inline struct cfs_rq *group_cfs_rq(struct sched_entity *grp) -{ - return NULL; -} - -static inline void list_add_leaf_cfs_rq(struct cfs_rq *cfs_rq) -{ -} - -static inline void list_del_leaf_cfs_rq(struct cfs_rq *cfs_rq) -{ -} - -#define for_each_leaf_cfs_rq(rq, cfs_rq) \ - for (cfs_rq = &rq->cfs; cfs_rq; cfs_rq = NULL) - -static inline struct sched_entity *parent_entity(struct sched_entity *se) -{ - return NULL; -} - -static inline void -find_matching_se(struct sched_entity **se, struct sched_entity **pse) -{ -} - -#endif /* CONFIG_FAIR_GROUP_SCHED */ - -static __always_inline -void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec); - -/************************************************************** - * Scheduling class tree data structure manipulation methods: - */ - -static inline u64 max_vruntime(u64 max_vruntime, u64 vruntime) -{ - s64 delta = (s64)(vruntime - max_vruntime); - if (delta > 0) - max_vruntime = vruntime; - - return max_vruntime; -} - -static inline u64 min_vruntime(u64 min_vruntime, u64 vruntime) -{ - s64 delta = (s64)(vruntime - min_vruntime); - if (delta < 0) - min_vruntime = vruntime; - - return min_vruntime; -} - -static inline int entity_before(struct sched_entity *a, - struct sched_entity *b) -{ - return (s64)(a->vruntime - b->vruntime) < 0; -} - -static void update_min_vruntime(struct cfs_rq *cfs_rq) -{ - struct sched_entity *curr = cfs_rq->curr; - - u64 vruntime = cfs_rq->min_vruntime; - - if (curr) { - if (curr->on_rq) - vruntime = curr->vruntime; - else - curr = NULL; - } - - if (cfs_rq->rb_leftmost) { - struct sched_entity *se = rb_entry(cfs_rq->rb_leftmost, - struct sched_entity, - run_node); - - if (!curr) - vruntime = se->vruntime; - else - vruntime = min_vruntime(vruntime, se->vruntime); - } - - /* ensure we never gain time by being placed backwards. */ - cfs_rq->min_vruntime = max_vruntime(cfs_rq->min_vruntime, vruntime); -#ifndef CONFIG_64BIT - smp_wmb(); - cfs_rq->min_vruntime_copy = cfs_rq->min_vruntime; -#endif -} - -/* - * Enqueue an entity into the rb-tree: - */ -static void __enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se) -{ - struct rb_node **link = &cfs_rq->tasks_timeline.rb_node; - struct rb_node *parent = NULL; - struct sched_entity *entry; - int leftmost = 1; - - /* - * Find the right place in the rbtree: - */ - while (*link) { - parent = *link; - entry = rb_entry(parent, struct sched_entity, run_node); - /* - * We dont care about collisions. Nodes with - * the same key stay together. - */ - if (entity_before(se, entry)) { - link = &parent->rb_left; - } else { - link = &parent->rb_right; - leftmost = 0; - } - } - - /* - * Maintain a cache of leftmost tree entries (it is frequently - * used): - */ - if (leftmost) - cfs_rq->rb_leftmost = &se->run_node; - - rb_link_node(&se->run_node, parent, link); - rb_insert_color(&se->run_node, &cfs_rq->tasks_timeline); -} - -static void __dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se) -{ - if (cfs_rq->rb_leftmost == &se->run_node) { - struct rb_node *next_node; - - next_node = rb_next(&se->run_node); - cfs_rq->rb_leftmost = next_node; - } - - rb_erase(&se->run_node, &cfs_rq->tasks_timeline); -} - -struct sched_entity *__pick_first_entity(struct cfs_rq *cfs_rq) -{ - struct rb_node *left = cfs_rq->rb_leftmost; - - if (!left) - return NULL; - - return rb_entry(left, struct sched_entity, run_node); -} - -static struct sched_entity *__pick_next_entity(struct sched_entity *se) -{ - struct rb_node *next = rb_next(&se->run_node); - - if (!next) - return NULL; - - return rb_entry(next, struct sched_entity, run_node); -} - -#ifdef CONFIG_SCHED_DEBUG -struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq) -{ - struct rb_node *last = rb_last(&cfs_rq->tasks_timeline); - - if (!last) - return NULL; - - return rb_entry(last, struct sched_entity, run_node); -} - -/************************************************************** - * Scheduling class statistics methods: - */ - -int sched_proc_update_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - int ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); - unsigned int factor = get_update_sysctl_factor(); - - if (ret || !write) - return ret; - - sched_nr_latency = DIV_ROUND_UP(sysctl_sched_latency, - sysctl_sched_min_granularity); - -#define WRT_SYSCTL(name) \ - (normalized_sysctl_##name = sysctl_##name / (factor)) - WRT_SYSCTL(sched_min_granularity); - WRT_SYSCTL(sched_latency); - WRT_SYSCTL(sched_wakeup_granularity); -#undef WRT_SYSCTL - - return 0; -} -#endif - -/* - * delta /= w - */ -static inline u64 calc_delta_fair(u64 delta, struct sched_entity *se) -{ - if (unlikely(se->load.weight != NICE_0_LOAD)) - delta = __calc_delta(delta, NICE_0_LOAD, &se->load); - - return delta; -} - -/* - * The idea is to set a period in which each task runs once. - * - * When there are too many tasks (sched_nr_latency) we have to stretch - * this period because otherwise the slices get too small. - * - * p = (nr <= nl) ? l : l*nr/nl - */ -static u64 __sched_period(unsigned long nr_running) -{ - if (unlikely(nr_running > sched_nr_latency)) - return nr_running * sysctl_sched_min_granularity; - else - return sysctl_sched_latency; -} - -/* - * We calculate the wall-time slice from the period by taking a part - * proportional to the weight. - * - * s = p*P[w/rw] - */ -static u64 sched_slice(struct cfs_rq *cfs_rq, struct sched_entity *se) -{ - u64 slice = __sched_period(cfs_rq->nr_running + !se->on_rq); - - for_each_sched_entity(se) { - struct load_weight *load; - struct load_weight lw; - - cfs_rq = cfs_rq_of(se); - load = &cfs_rq->load; - - if (unlikely(!se->on_rq)) { - lw = cfs_rq->load; - - update_load_add(&lw, se->load.weight); - load = &lw; - } - slice = __calc_delta(slice, se->load.weight, load); - } - return slice; -} - -/* - * We calculate the vruntime slice of a to-be-inserted task. - * - * vs = s/w - */ -static u64 sched_vslice(struct cfs_rq *cfs_rq, struct sched_entity *se) -{ - return calc_delta_fair(sched_slice(cfs_rq, se), se); -} - -#ifdef CONFIG_SMP -static int select_idle_sibling(struct task_struct *p, int prev_cpu, int cpu); -static unsigned long task_h_load(struct task_struct *p); - -/* - * We choose a half-life close to 1 scheduling period. - * Note: The tables runnable_avg_yN_inv and runnable_avg_yN_sum are - * dependent on this value. - */ -#define LOAD_AVG_PERIOD 32 -#define LOAD_AVG_MAX 47742 /* maximum possible load avg */ -#define LOAD_AVG_MAX_N 345 /* number of full periods to produce LOAD_AVG_MAX */ - -/* Give new sched_entity start runnable values to heavy its load in infant time */ -void init_entity_runnable_average(struct sched_entity *se) -{ - struct sched_avg *sa = &se->avg; - - sa->last_update_time = 0; - /* - * sched_avg's period_contrib should be strictly less then 1024, so - * we give it 1023 to make sure it is almost a period (1024us), and - * will definitely be update (after enqueue). - */ - sa->period_contrib = 1023; - /* - * Tasks are intialized with full load to be seen as heavy tasks until - * they get a chance to stabilize to their real load level. - * Group entities are intialized with zero load to reflect the fact that - * nothing has been attached to the task group yet. - */ - if (entity_is_task(se)) - sa->load_avg = scale_load_down(se->load.weight); - sa->load_sum = sa->load_avg * LOAD_AVG_MAX; - /* - * At this point, util_avg won't be used in select_task_rq_fair anyway - */ - sa->util_avg = 0; - sa->util_sum = 0; - /* when this task enqueue'ed, it will contribute to its cfs_rq's load_avg */ -} - -static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq); -static int update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq, bool update_freq); -static void update_tg_load_avg(struct cfs_rq *cfs_rq, int force); -static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se); - -/* - * With new tasks being created, their initial util_avgs are extrapolated - * based on the cfs_rq's current util_avg: - * - * util_avg = cfs_rq->util_avg / (cfs_rq->load_avg + 1) * se.load.weight - * - * However, in many cases, the above util_avg does not give a desired - * value. Moreover, the sum of the util_avgs may be divergent, such - * as when the series is a harmonic series. - * - * To solve this problem, we also cap the util_avg of successive tasks to - * only 1/2 of the left utilization budget: - * - * util_avg_cap = (1024 - cfs_rq->avg.util_avg) / 2^n - * - * where n denotes the nth task. - * - * For example, a simplest series from the beginning would be like: - * - * task util_avg: 512, 256, 128, 64, 32, 16, 8, ... - * cfs_rq util_avg: 512, 768, 896, 960, 992, 1008, 1016, ... - * - * Finally, that extrapolated util_avg is clamped to the cap (util_avg_cap) - * if util_avg > util_avg_cap. - */ -void post_init_entity_util_avg(struct sched_entity *se) -{ - struct cfs_rq *cfs_rq = cfs_rq_of(se); - struct sched_avg *sa = &se->avg; - long cap = (long)(SCHED_CAPACITY_SCALE - cfs_rq->avg.util_avg) / 2; - u64 now = cfs_rq_clock_task(cfs_rq); - - if (cap > 0) { - if (cfs_rq->avg.util_avg != 0) { - sa->util_avg = cfs_rq->avg.util_avg * se->load.weight; - sa->util_avg /= (cfs_rq->avg.load_avg + 1); - - if (sa->util_avg > cap) - sa->util_avg = cap; - } else { - sa->util_avg = cap; - } - sa->util_sum = sa->util_avg * LOAD_AVG_MAX; - } - - if (entity_is_task(se)) { - struct task_struct *p = task_of(se); - if (p->sched_class != &fair_sched_class) { - /* - * For !fair tasks do: - * - update_cfs_rq_load_avg(now, cfs_rq, false); - attach_entity_load_avg(cfs_rq, se); - switched_from_fair(rq, p); - * - * such that the next switched_to_fair() has the - * expected state. - */ - se->avg.last_update_time = now; - return; - } - } - - update_cfs_rq_load_avg(now, cfs_rq, false); - attach_entity_load_avg(cfs_rq, se); - update_tg_load_avg(cfs_rq, false); -} - -#else /* !CONFIG_SMP */ -void init_entity_runnable_average(struct sched_entity *se) -{ -} -void post_init_entity_util_avg(struct sched_entity *se) -{ -} -static void update_tg_load_avg(struct cfs_rq *cfs_rq, int force) -{ -} -#endif /* CONFIG_SMP */ - -/* - * Update the current task's runtime statistics. - */ -static void update_curr(struct cfs_rq *cfs_rq) -{ - struct sched_entity *curr = cfs_rq->curr; - u64 now = rq_clock_task(rq_of(cfs_rq)); - u64 delta_exec; - - if (unlikely(!curr)) - return; - - delta_exec = now - curr->exec_start; - if (unlikely((s64)delta_exec <= 0)) - return; - - curr->exec_start = now; - - schedstat_set(curr->statistics.exec_max, - max(delta_exec, curr->statistics.exec_max)); - - curr->sum_exec_runtime += delta_exec; - schedstat_add(cfs_rq->exec_clock, delta_exec); - - curr->vruntime += calc_delta_fair(delta_exec, curr); - update_min_vruntime(cfs_rq); - - if (entity_is_task(curr)) { - struct task_struct *curtask = task_of(curr); - - trace_sched_stat_runtime(curtask, delta_exec, curr->vruntime); - cpuacct_charge(curtask, delta_exec); - account_group_exec_runtime(curtask, delta_exec); - } - - account_cfs_rq_runtime(cfs_rq, delta_exec); -} - -static void update_curr_fair(struct rq *rq) -{ - update_curr(cfs_rq_of(&rq->curr->se)); -} - -static inline void -update_stats_wait_start(struct cfs_rq *cfs_rq, struct sched_entity *se) -{ - u64 wait_start, prev_wait_start; - - if (!schedstat_enabled()) - return; - - wait_start = rq_clock(rq_of(cfs_rq)); - prev_wait_start = schedstat_val(se->statistics.wait_start); - - if (entity_is_task(se) && task_on_rq_migrating(task_of(se)) && - likely(wait_start > prev_wait_start)) - wait_start -= prev_wait_start; - - schedstat_set(se->statistics.wait_start, wait_start); -} - -static inline void -update_stats_wait_end(struct cfs_rq *cfs_rq, struct sched_entity *se) -{ - struct task_struct *p; - u64 delta; - - if (!schedstat_enabled()) - return; - - delta = rq_clock(rq_of(cfs_rq)) - schedstat_val(se->statistics.wait_start); - - if (entity_is_task(se)) { - p = task_of(se); - if (task_on_rq_migrating(p)) { - /* - * Preserve migrating task's wait time so wait_start - * time stamp can be adjusted to accumulate wait time - * prior to migration. - */ - schedstat_set(se->statistics.wait_start, delta); - return; - } - trace_sched_stat_wait(p, delta); - } - - schedstat_set(se->statistics.wait_max, - max(schedstat_val(se->statistics.wait_max), delta)); - schedstat_inc(se->statistics.wait_count); - schedstat_add(se->statistics.wait_sum, delta); - schedstat_set(se->statistics.wait_start, 0); -} - -static inline void -update_stats_enqueue_sleeper(struct cfs_rq *cfs_rq, struct sched_entity *se) -{ - struct task_struct *tsk = NULL; - u64 sleep_start, block_start; - - if (!schedstat_enabled()) - return; - - sleep_start = schedstat_val(se->statistics.sleep_start); - block_start = schedstat_val(se->statistics.block_start); - - if (entity_is_task(se)) - tsk = task_of(se); - - if (sleep_start) { - u64 delta = rq_clock(rq_of(cfs_rq)) - sleep_start; - - if ((s64)delta < 0) - delta = 0; - - if (unlikely(delta > schedstat_val(se->statistics.sleep_max))) - schedstat_set(se->statistics.sleep_max, delta); - - schedstat_set(se->statistics.sleep_start, 0); - schedstat_add(se->statistics.sum_sleep_runtime, delta); - - if (tsk) { - account_scheduler_latency(tsk, delta >> 10, 1); - trace_sched_stat_sleep(tsk, delta); - } - } - if (block_start) { - u64 delta = rq_clock(rq_of(cfs_rq)) - block_start; - - if ((s64)delta < 0) - delta = 0; - - if (unlikely(delta > schedstat_val(se->statistics.block_max))) - schedstat_set(se->statistics.block_max, delta); - - schedstat_set(se->statistics.block_start, 0); - schedstat_add(se->statistics.sum_sleep_runtime, delta); - - if (tsk) { - if (tsk->in_iowait) { - schedstat_add(se->statistics.iowait_sum, delta); - schedstat_inc(se->statistics.iowait_count); - trace_sched_stat_iowait(tsk, delta); - } - - trace_sched_stat_blocked(tsk, delta); - - /* - * Blocking time is in units of nanosecs, so shift by - * 20 to get a milliseconds-range estimation of the - * amount of time that the task spent sleeping: - */ - if (unlikely(prof_on == SLEEP_PROFILING)) { - profile_hits(SLEEP_PROFILING, - (void *)get_wchan(tsk), - delta >> 20); - } - account_scheduler_latency(tsk, delta >> 10, 0); - } - } -} - -/* - * Task is being enqueued - update stats: - */ -static inline void -update_stats_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) -{ - if (!schedstat_enabled()) - return; - - /* - * Are we enqueueing a waiting task? (for current tasks - * a dequeue/enqueue event is a NOP) - */ - if (se != cfs_rq->curr) - update_stats_wait_start(cfs_rq, se); - - if (flags & ENQUEUE_WAKEUP) - update_stats_enqueue_sleeper(cfs_rq, se); -} - -static inline void -update_stats_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) -{ - - if (!schedstat_enabled()) - return; - - /* - * Mark the end of the wait period if dequeueing a - * waiting task: - */ - if (se != cfs_rq->curr) - update_stats_wait_end(cfs_rq, se); - - if ((flags & DEQUEUE_SLEEP) && entity_is_task(se)) { - struct task_struct *tsk = task_of(se); - - if (tsk->state & TASK_INTERRUPTIBLE) - schedstat_set(se->statistics.sleep_start, - rq_clock(rq_of(cfs_rq))); - if (tsk->state & TASK_UNINTERRUPTIBLE) - schedstat_set(se->statistics.block_start, - rq_clock(rq_of(cfs_rq))); - } -} - -/* - * We are picking a new current task - update its stats: - */ -static inline void -update_stats_curr_start(struct cfs_rq *cfs_rq, struct sched_entity *se) -{ - /* - * We are starting a new run period: - */ - se->exec_start = rq_clock_task(rq_of(cfs_rq)); -} - -/************************************************** - * Scheduling class queueing methods: - */ - -#ifdef CONFIG_NUMA_BALANCING -/* - * Approximate time to scan a full NUMA task in ms. The task scan period is - * calculated based on the tasks virtual memory size and - * numa_balancing_scan_size. - */ -unsigned int sysctl_numa_balancing_scan_period_min = 1000; -unsigned int sysctl_numa_balancing_scan_period_max = 60000; - -/* Portion of address space to scan in MB */ -unsigned int sysctl_numa_balancing_scan_size = 256; - -/* Scan @scan_size MB every @scan_period after an initial @scan_delay in ms */ -unsigned int sysctl_numa_balancing_scan_delay = 1000; - -static unsigned int task_nr_scan_windows(struct task_struct *p) -{ - unsigned long rss = 0; - unsigned long nr_scan_pages; - - /* - * Calculations based on RSS as non-present and empty pages are skipped - * by the PTE scanner and NUMA hinting faults should be trapped based - * on resident pages - */ - nr_scan_pages = sysctl_numa_balancing_scan_size << (20 - PAGE_SHIFT); - rss = get_mm_rss(p->mm); - if (!rss) - rss = nr_scan_pages; - - rss = round_up(rss, nr_scan_pages); - return rss / nr_scan_pages; -} - -/* For sanitys sake, never scan more PTEs than MAX_SCAN_WINDOW MB/sec. */ -#define MAX_SCAN_WINDOW 2560 - -static unsigned int task_scan_min(struct task_struct *p) -{ - unsigned int scan_size = READ_ONCE(sysctl_numa_balancing_scan_size); - unsigned int scan, floor; - unsigned int windows = 1; - - if (scan_size < MAX_SCAN_WINDOW) - windows = MAX_SCAN_WINDOW / scan_size; - floor = 1000 / windows; - - scan = sysctl_numa_balancing_scan_period_min / task_nr_scan_windows(p); - return max_t(unsigned int, floor, scan); -} - -static unsigned int task_scan_max(struct task_struct *p) -{ - unsigned int smin = task_scan_min(p); - unsigned int smax; - - /* Watch for min being lower than max due to floor calculations */ - smax = sysctl_numa_balancing_scan_period_max / task_nr_scan_windows(p); - return max(smin, smax); -} - -static void account_numa_enqueue(struct rq *rq, struct task_struct *p) -{ - rq->nr_numa_running += (p->numa_preferred_nid != -1); - rq->nr_preferred_running += (p->numa_preferred_nid == task_node(p)); -} - -static void account_numa_dequeue(struct rq *rq, struct task_struct *p) -{ - rq->nr_numa_running -= (p->numa_preferred_nid != -1); - rq->nr_preferred_running -= (p->numa_preferred_nid == task_node(p)); -} - -struct numa_group { - atomic_t refcount; - - spinlock_t lock; /* nr_tasks, tasks */ - int nr_tasks; - pid_t gid; - int active_nodes; - - struct rcu_head rcu; - unsigned long total_faults; - unsigned long max_faults_cpu; - /* - * Faults_cpu is used to decide whether memory should move - * towards the CPU. As a consequence, these stats are weighted - * more by CPU use than by memory faults. - */ - unsigned long *faults_cpu; - unsigned long faults[0]; -}; - -/* Shared or private faults. */ -#define NR_NUMA_HINT_FAULT_TYPES 2 - -/* Memory and CPU locality */ -#define NR_NUMA_HINT_FAULT_STATS (NR_NUMA_HINT_FAULT_TYPES * 2) - -/* Averaged statistics, and temporary buffers. */ -#define NR_NUMA_HINT_FAULT_BUCKETS (NR_NUMA_HINT_FAULT_STATS * 2) - -pid_t task_numa_group_id(struct task_struct *p) -{ - return p->numa_group ? p->numa_group->gid : 0; -} - -/* - * The averaged statistics, shared & private, memory & cpu, - * occupy the first half of the array. The second half of the - * array is for current counters, which are averaged into the - * first set by task_numa_placement. - */ -static inline int task_faults_idx(enum numa_faults_stats s, int nid, int priv) -{ - return NR_NUMA_HINT_FAULT_TYPES * (s * nr_node_ids + nid) + priv; -} - -static inline unsigned long task_faults(struct task_struct *p, int nid) -{ - if (!p->numa_faults) - return 0; - - return p->numa_faults[task_faults_idx(NUMA_MEM, nid, 0)] + - p->numa_faults[task_faults_idx(NUMA_MEM, nid, 1)]; -} - -static inline unsigned long group_faults(struct task_struct *p, int nid) -{ - if (!p->numa_group) - return 0; - - return p->numa_group->faults[task_faults_idx(NUMA_MEM, nid, 0)] + - p->numa_group->faults[task_faults_idx(NUMA_MEM, nid, 1)]; -} - -static inline unsigned long group_faults_cpu(struct numa_group *group, int nid) -{ - return group->faults_cpu[task_faults_idx(NUMA_MEM, nid, 0)] + - group->faults_cpu[task_faults_idx(NUMA_MEM, nid, 1)]; -} - -/* - * A node triggering more than 1/3 as many NUMA faults as the maximum is - * considered part of a numa group's pseudo-interleaving set. Migrations - * between these nodes are slowed down, to allow things to settle down. - */ -#define ACTIVE_NODE_FRACTION 3 - -static bool numa_is_active_node(int nid, struct numa_group *ng) -{ - return group_faults_cpu(ng, nid) * ACTIVE_NODE_FRACTION > ng->max_faults_cpu; -} - -/* Handle placement on systems where not all nodes are directly connected. */ -static unsigned long score_nearby_nodes(struct task_struct *p, int nid, - int maxdist, bool task) -{ - unsigned long score = 0; - int node; - - /* - * All nodes are directly connected, and the same distance - * from each other. No need for fancy placement algorithms. - */ - if (sched_numa_topology_type == NUMA_DIRECT) - return 0; - - /* - * This code is called for each node, introducing N^2 complexity, - * which should be ok given the number of nodes rarely exceeds 8. - */ - for_each_online_node(node) { - unsigned long faults; - int dist = node_distance(nid, node); - - /* - * The furthest away nodes in the system are not interesting - * for placement; nid was already counted. - */ - if (dist == sched_max_numa_distance || node == nid) - continue; - - /* - * On systems with a backplane NUMA topology, compare groups - * of nodes, and move tasks towards the group with the most - * memory accesses. When comparing two nodes at distance - * "hoplimit", only nodes closer by than "hoplimit" are part - * of each group. Skip other nodes. - */ - if (sched_numa_topology_type == NUMA_BACKPLANE && - dist > maxdist) - continue; - - /* Add up the faults from nearby nodes. */ - if (task) - faults = task_faults(p, node); - else - faults = group_faults(p, node); - - /* - * On systems with a glueless mesh NUMA topology, there are - * no fixed "groups of nodes". Instead, nodes that are not - * directly connected bounce traffic through intermediate - * nodes; a numa_group can occupy any set of nodes. - * The further away a node is, the less the faults count. - * This seems to result in good task placement. - */ - if (sched_numa_topology_type == NUMA_GLUELESS_MESH) { - faults *= (sched_max_numa_distance - dist); - faults /= (sched_max_numa_distance - LOCAL_DISTANCE); - } - - score += faults; - } - - return score; -} - -/* - * These return the fraction of accesses done by a particular task, or - * task group, on a particular numa node. The group weight is given a - * larger multiplier, in order to group tasks together that are almost - * evenly spread out between numa nodes. - */ -static inline unsigned long task_weight(struct task_struct *p, int nid, - int dist) -{ - unsigned long faults, total_faults; - - if (!p->numa_faults) - return 0; - - total_faults = p->total_numa_faults; - - if (!total_faults) - return 0; - - faults = task_faults(p, nid); - faults += score_nearby_nodes(p, nid, dist, true); - - return 1000 * faults / total_faults; -} - -static inline unsigned long group_weight(struct task_struct *p, int nid, - int dist) -{ - unsigned long faults, total_faults; - - if (!p->numa_group) - return 0; - - total_faults = p->numa_group->total_faults; - - if (!total_faults) - return 0; - - faults = group_faults(p, nid); - faults += score_nearby_nodes(p, nid, dist, false); - - return 1000 * faults / total_faults; -} - -bool should_numa_migrate_memory(struct task_struct *p, struct page * page, - int src_nid, int dst_cpu) -{ - struct numa_group *ng = p->numa_group; - int dst_nid = cpu_to_node(dst_cpu); - int last_cpupid, this_cpupid; - - this_cpupid = cpu_pid_to_cpupid(dst_cpu, current->pid); - - /* - * Multi-stage node selection is used in conjunction with a periodic - * migration fault to build a temporal task<->page relation. By using - * a two-stage filter we remove short/unlikely relations. - * - * Using P(p) ~ n_p / n_t as per frequentist probability, we can equate - * a task's usage of a particular page (n_p) per total usage of this - * page (n_t) (in a given time-span) to a probability. - * - * Our periodic faults will sample this probability and getting the - * same result twice in a row, given these samples are fully - * independent, is then given by P(n)^2, provided our sample period - * is sufficiently short compared to the usage pattern. - * - * This quadric squishes small probabilities, making it less likely we - * act on an unlikely task<->page relation. - */ - last_cpupid = page_cpupid_xchg_last(page, this_cpupid); - if (!cpupid_pid_unset(last_cpupid) && - cpupid_to_nid(last_cpupid) != dst_nid) - return false; - - /* Always allow migrate on private faults */ - if (cpupid_match_pid(p, last_cpupid)) - return true; - - /* A shared fault, but p->numa_group has not been set up yet. */ - if (!ng) - return true; - - /* - * Destination node is much more heavily used than the source - * node? Allow migration. - */ - if (group_faults_cpu(ng, dst_nid) > group_faults_cpu(ng, src_nid) * - ACTIVE_NODE_FRACTION) - return true; - - /* - * Distribute memory according to CPU & memory use on each node, - * with 3/4 hysteresis to avoid unnecessary memory migrations: - * - * faults_cpu(dst) 3 faults_cpu(src) - * --------------- * - > --------------- - * faults_mem(dst) 4 faults_mem(src) - */ - return group_faults_cpu(ng, dst_nid) * group_faults(p, src_nid) * 3 > - group_faults_cpu(ng, src_nid) * group_faults(p, dst_nid) * 4; -} - -static unsigned long weighted_cpuload(const int cpu); -static unsigned long source_load(int cpu, int type); -static unsigned long target_load(int cpu, int type); -static unsigned long capacity_of(int cpu); -static long effective_load(struct task_group *tg, int cpu, long wl, long wg); - -/* Cached statistics for all CPUs within a node */ -struct numa_stats { - unsigned long nr_running; - unsigned long load; - - /* Total compute capacity of CPUs on a node */ - unsigned long compute_capacity; - - /* Approximate capacity in terms of runnable tasks on a node */ - unsigned long task_capacity; - int has_free_capacity; -}; - -/* - * XXX borrowed from update_sg_lb_stats - */ -static void update_numa_stats(struct numa_stats *ns, int nid) -{ - int smt, cpu, cpus = 0; - unsigned long capacity; - - memset(ns, 0, sizeof(*ns)); - for_each_cpu(cpu, cpumask_of_node(nid)) { - struct rq *rq = cpu_rq(cpu); - - ns->nr_running += rq->nr_running; - ns->load += weighted_cpuload(cpu); - ns->compute_capacity += capacity_of(cpu); - - cpus++; - } - - /* - * If we raced with hotplug and there are no CPUs left in our mask - * the @ns structure is NULL'ed and task_numa_compare() will - * not find this node attractive. - * - * We'll either bail at !has_free_capacity, or we'll detect a huge - * imbalance and bail there. - */ - if (!cpus) - return; - - /* smt := ceil(cpus / capacity), assumes: 1 < smt_power < 2 */ - smt = DIV_ROUND_UP(SCHED_CAPACITY_SCALE * cpus, ns->compute_capacity); - capacity = cpus / smt; /* cores */ - - ns->task_capacity = min_t(unsigned, capacity, - DIV_ROUND_CLOSEST(ns->compute_capacity, SCHED_CAPACITY_SCALE)); - ns->has_free_capacity = (ns->nr_running < ns->task_capacity); -} - -struct task_numa_env { - struct task_struct *p; - - int src_cpu, src_nid; - int dst_cpu, dst_nid; - - struct numa_stats src_stats, dst_stats; - - int imbalance_pct; - int dist; - - struct task_struct *best_task; - long best_imp; - int best_cpu; -}; - -static void task_numa_assign(struct task_numa_env *env, - struct task_struct *p, long imp) -{ - if (env->best_task) - put_task_struct(env->best_task); - if (p) - get_task_struct(p); - - env->best_task = p; - env->best_imp = imp; - env->best_cpu = env->dst_cpu; -} - -static bool load_too_imbalanced(long src_load, long dst_load, - struct task_numa_env *env) -{ - long imb, old_imb; - long orig_src_load, orig_dst_load; - long src_capacity, dst_capacity; - - /* - * The load is corrected for the CPU capacity available on each node. - * - * src_load dst_load - * ------------ vs --------- - * src_capacity dst_capacity - */ - src_capacity = env->src_stats.compute_capacity; - dst_capacity = env->dst_stats.compute_capacity; - - /* We care about the slope of the imbalance, not the direction. */ - if (dst_load < src_load) - swap(dst_load, src_load); - - /* Is the difference below the threshold? */ - imb = dst_load * src_capacity * 100 - - src_load * dst_capacity * env->imbalance_pct; - if (imb <= 0) - return false; - - /* - * The imbalance is above the allowed threshold. - * Compare it with the old imbalance. - */ - orig_src_load = env->src_stats.load; - orig_dst_load = env->dst_stats.load; - - if (orig_dst_load < orig_src_load) - swap(orig_dst_load, orig_src_load); - - old_imb = orig_dst_load * src_capacity * 100 - - orig_src_load * dst_capacity * env->imbalance_pct; - - /* Would this change make things worse? */ - return (imb > old_imb); -} - -/* - * This checks if the overall compute and NUMA accesses of the system would - * be improved if the source tasks was migrated to the target dst_cpu taking - * into account that it might be best if task running on the dst_cpu should - * be exchanged with the source task - */ -static void task_numa_compare(struct task_numa_env *env, - long taskimp, long groupimp) -{ - struct rq *src_rq = cpu_rq(env->src_cpu); - struct rq *dst_rq = cpu_rq(env->dst_cpu); - struct task_struct *cur; - long src_load, dst_load; - long load; - long imp = env->p->numa_group ? groupimp : taskimp; - long moveimp = imp; - int dist = env->dist; - - rcu_read_lock(); - cur = task_rcu_dereference(&dst_rq->curr); - if (cur && ((cur->flags & PF_EXITING) || is_idle_task(cur))) - cur = NULL; - - /* - * Because we have preemption enabled we can get migrated around and - * end try selecting ourselves (current == env->p) as a swap candidate. - */ - if (cur == env->p) - goto unlock; - - /* - * "imp" is the fault differential for the source task between the - * source and destination node. Calculate the total differential for - * the source task and potential destination task. The more negative - * the value is, the more rmeote accesses that would be expected to - * be incurred if the tasks were swapped. - */ - if (cur) { - /* Skip this swap candidate if cannot move to the source cpu */ - if (!cpumask_test_cpu(env->src_cpu, tsk_cpus_allowed(cur))) - goto unlock; - - /* - * If dst and source tasks are in the same NUMA group, or not - * in any group then look only at task weights. - */ - if (cur->numa_group == env->p->numa_group) { - imp = taskimp + task_weight(cur, env->src_nid, dist) - - task_weight(cur, env->dst_nid, dist); - /* - * Add some hysteresis to prevent swapping the - * tasks within a group over tiny differences. - */ - if (cur->numa_group) - imp -= imp/16; - } else { - /* - * Compare the group weights. If a task is all by - * itself (not part of a group), use the task weight - * instead. - */ - if (cur->numa_group) - imp += group_weight(cur, env->src_nid, dist) - - group_weight(cur, env->dst_nid, dist); - else - imp += task_weight(cur, env->src_nid, dist) - - task_weight(cur, env->dst_nid, dist); - } - } - - if (imp <= env->best_imp && moveimp <= env->best_imp) - goto unlock; - - if (!cur) { - /* Is there capacity at our destination? */ - if (env->src_stats.nr_running <= env->src_stats.task_capacity && - !env->dst_stats.has_free_capacity) - goto unlock; - - goto balance; - } - - /* Balance doesn't matter much if we're running a task per cpu */ - if (imp > env->best_imp && src_rq->nr_running == 1 && - dst_rq->nr_running == 1) - goto assign; - - /* - * In the overloaded case, try and keep the load balanced. - */ -balance: - load = task_h_load(env->p); - dst_load = env->dst_stats.load + load; - src_load = env->src_stats.load - load; - - if (moveimp > imp && moveimp > env->best_imp) { - /* - * If the improvement from just moving env->p direction is - * better than swapping tasks around, check if a move is - * possible. Store a slightly smaller score than moveimp, - * so an actually idle CPU will win. - */ - if (!load_too_imbalanced(src_load, dst_load, env)) { - imp = moveimp - 1; - cur = NULL; - goto assign; - } - } - - if (imp <= env->best_imp) - goto unlock; - - if (cur) { - load = task_h_load(cur); - dst_load -= load; - src_load += load; - } - - if (load_too_imbalanced(src_load, dst_load, env)) - goto unlock; - - /* - * One idle CPU per node is evaluated for a task numa move. - * Call select_idle_sibling to maybe find a better one. - */ - if (!cur) { - /* - * select_idle_siblings() uses an per-cpu cpumask that - * can be used from IRQ context. - */ - local_irq_disable(); - env->dst_cpu = select_idle_sibling(env->p, env->src_cpu, - env->dst_cpu); - local_irq_enable(); - } - -assign: - task_numa_assign(env, cur, imp); -unlock: - rcu_read_unlock(); -} - -static void task_numa_find_cpu(struct task_numa_env *env, - long taskimp, long groupimp) -{ - int cpu; - - for_each_cpu(cpu, cpumask_of_node(env->dst_nid)) { - /* Skip this CPU if the source task cannot migrate */ - if (!cpumask_test_cpu(cpu, tsk_cpus_allowed(env->p))) - continue; - - env->dst_cpu = cpu; - task_numa_compare(env, taskimp, groupimp); - } -} - -/* Only move tasks to a NUMA node less busy than the current node. */ -static bool numa_has_capacity(struct task_numa_env *env) -{ - struct numa_stats *src = &env->src_stats; - struct numa_stats *dst = &env->dst_stats; - - if (src->has_free_capacity && !dst->has_free_capacity) - return false; - - /* - * Only consider a task move if the source has a higher load - * than the destination, corrected for CPU capacity on each node. - * - * src->load dst->load - * --------------------- vs --------------------- - * src->compute_capacity dst->compute_capacity - */ - if (src->load * dst->compute_capacity * env->imbalance_pct > - - dst->load * src->compute_capacity * 100) - return true; - - return false; -} - -static int task_numa_migrate(struct task_struct *p) -{ - struct task_numa_env env = { - .p = p, - - .src_cpu = task_cpu(p), - .src_nid = task_node(p), - - .imbalance_pct = 112, - - .best_task = NULL, - .best_imp = 0, - .best_cpu = -1, - }; - struct sched_domain *sd; - unsigned long taskweight, groupweight; - int nid, ret, dist; - long taskimp, groupimp; - - /* - * Pick the lowest SD_NUMA domain, as that would have the smallest - * imbalance and would be the first to start moving tasks about. - * - * And we want to avoid any moving of tasks about, as that would create - * random movement of tasks -- counter the numa conditions we're trying - * to satisfy here. - */ - rcu_read_lock(); - sd = rcu_dereference(per_cpu(sd_numa, env.src_cpu)); - if (sd) - env.imbalance_pct = 100 + (sd->imbalance_pct - 100) / 2; - rcu_read_unlock(); - - /* - * Cpusets can break the scheduler domain tree into smaller - * balance domains, some of which do not cross NUMA boundaries. - * Tasks that are "trapped" in such domains cannot be migrated - * elsewhere, so there is no point in (re)trying. - */ - if (unlikely(!sd)) { - p->numa_preferred_nid = task_node(p); - return -EINVAL; - } - - env.dst_nid = p->numa_preferred_nid; - dist = env.dist = node_distance(env.src_nid, env.dst_nid); - taskweight = task_weight(p, env.src_nid, dist); - groupweight = group_weight(p, env.src_nid, dist); - update_numa_stats(&env.src_stats, env.src_nid); - taskimp = task_weight(p, env.dst_nid, dist) - taskweight; - groupimp = group_weight(p, env.dst_nid, dist) - groupweight; - update_numa_stats(&env.dst_stats, env.dst_nid); - - /* Try to find a spot on the preferred nid. */ - if (numa_has_capacity(&env)) - task_numa_find_cpu(&env, taskimp, groupimp); - - /* - * Look at other nodes in these cases: - * - there is no space available on the preferred_nid - * - the task is part of a numa_group that is interleaved across - * multiple NUMA nodes; in order to better consolidate the group, - * we need to check other locations. - */ - if (env.best_cpu == -1 || (p->numa_group && p->numa_group->active_nodes > 1)) { - for_each_online_node(nid) { - if (nid == env.src_nid || nid == p->numa_preferred_nid) - continue; - - dist = node_distance(env.src_nid, env.dst_nid); - if (sched_numa_topology_type == NUMA_BACKPLANE && - dist != env.dist) { - taskweight = task_weight(p, env.src_nid, dist); - groupweight = group_weight(p, env.src_nid, dist); - } - - /* Only consider nodes where both task and groups benefit */ - taskimp = task_weight(p, nid, dist) - taskweight; - groupimp = group_weight(p, nid, dist) - groupweight; - if (taskimp < 0 && groupimp < 0) - continue; - - env.dist = dist; - env.dst_nid = nid; - update_numa_stats(&env.dst_stats, env.dst_nid); - if (numa_has_capacity(&env)) - task_numa_find_cpu(&env, taskimp, groupimp); - } - } - - /* - * If the task is part of a workload that spans multiple NUMA nodes, - * and is migrating into one of the workload's active nodes, remember - * this node as the task's preferred numa node, so the workload can - * settle down. - * A task that migrated to a second choice node will be better off - * trying for a better one later. Do not set the preferred node here. - */ - if (p->numa_group) { - struct numa_group *ng = p->numa_group; - - if (env.best_cpu == -1) - nid = env.src_nid; - else - nid = env.dst_nid; - - if (ng->active_nodes > 1 && numa_is_active_node(env.dst_nid, ng)) - sched_setnuma(p, env.dst_nid); - } - - /* No better CPU than the current one was found. */ - if (env.best_cpu == -1) - return -EAGAIN; - - /* - * Reset the scan period if the task is being rescheduled on an - * alternative node to recheck if the tasks is now properly placed. - */ - p->numa_scan_period = task_scan_min(p); - - if (env.best_task == NULL) { - ret = migrate_task_to(p, env.best_cpu); - if (ret != 0) - trace_sched_stick_numa(p, env.src_cpu, env.best_cpu); - return ret; - } - - ret = migrate_swap(p, env.best_task); - if (ret != 0) - trace_sched_stick_numa(p, env.src_cpu, task_cpu(env.best_task)); - put_task_struct(env.best_task); - return ret; -} - -/* Attempt to migrate a task to a CPU on the preferred node. */ -static void numa_migrate_preferred(struct task_struct *p) -{ - unsigned long interval = HZ; - - /* This task has no NUMA fault statistics yet */ - if (unlikely(p->numa_preferred_nid == -1 || !p->numa_faults)) - return; - - /* Periodically retry migrating the task to the preferred node */ - interval = min(interval, msecs_to_jiffies(p->numa_scan_period) / 16); - p->numa_migrate_retry = jiffies + interval; - - /* Success if task is already running on preferred CPU */ - if (task_node(p) == p->numa_preferred_nid) - return; - - /* Otherwise, try migrate to a CPU on the preferred node */ - task_numa_migrate(p); -} - -/* - * Find out how many nodes on the workload is actively running on. Do this by - * tracking the nodes from which NUMA hinting faults are triggered. This can - * be different from the set of nodes where the workload's memory is currently - * located. - */ -static void numa_group_count_active_nodes(struct numa_group *numa_group) -{ - unsigned long faults, max_faults = 0; - int nid, active_nodes = 0; - - for_each_online_node(nid) { - faults = group_faults_cpu(numa_group, nid); - if (faults > max_faults) - max_faults = faults; - } - - for_each_online_node(nid) { - faults = group_faults_cpu(numa_group, nid); - if (faults * ACTIVE_NODE_FRACTION > max_faults) - active_nodes++; - } - - numa_group->max_faults_cpu = max_faults; - numa_group->active_nodes = active_nodes; -} - -/* - * When adapting the scan rate, the period is divided into NUMA_PERIOD_SLOTS - * increments. The more local the fault statistics are, the higher the scan - * period will be for the next scan window. If local/(local+remote) ratio is - * below NUMA_PERIOD_THRESHOLD (where range of ratio is 1..NUMA_PERIOD_SLOTS) - * the scan period will decrease. Aim for 70% local accesses. - */ -#define NUMA_PERIOD_SLOTS 10 -#define NUMA_PERIOD_THRESHOLD 7 - -/* - * Increase the scan period (slow down scanning) if the majority of - * our memory is already on our local node, or if the majority of - * the page accesses are shared with other processes. - * Otherwise, decrease the scan period. - */ -static void update_task_scan_period(struct task_struct *p, - unsigned long shared, unsigned long private) -{ - unsigned int period_slot; - int ratio; - int diff; - - unsigned long remote = p->numa_faults_locality[0]; - unsigned long local = p->numa_faults_locality[1]; - - /* - * If there were no record hinting faults then either the task is - * completely idle or all activity is areas that are not of interest - * to automatic numa balancing. Related to that, if there were failed - * migration then it implies we are migrating too quickly or the local - * node is overloaded. In either case, scan slower - */ - if (local + shared == 0 || p->numa_faults_locality[2]) { - p->numa_scan_period = min(p->numa_scan_period_max, - p->numa_scan_period << 1); - - p->mm->numa_next_scan = jiffies + - msecs_to_jiffies(p->numa_scan_period); - - return; - } - - /* - * Prepare to scale scan period relative to the current period. - * == NUMA_PERIOD_THRESHOLD scan period stays the same - * < NUMA_PERIOD_THRESHOLD scan period decreases (scan faster) - * >= NUMA_PERIOD_THRESHOLD scan period increases (scan slower) - */ - period_slot = DIV_ROUND_UP(p->numa_scan_period, NUMA_PERIOD_SLOTS); - ratio = (local * NUMA_PERIOD_SLOTS) / (local + remote); - if (ratio >= NUMA_PERIOD_THRESHOLD) { - int slot = ratio - NUMA_PERIOD_THRESHOLD; - if (!slot) - slot = 1; - diff = slot * period_slot; - } else { - diff = -(NUMA_PERIOD_THRESHOLD - ratio) * period_slot; - - /* - * Scale scan rate increases based on sharing. There is an - * inverse relationship between the degree of sharing and - * the adjustment made to the scanning period. Broadly - * speaking the intent is that there is little point - * scanning faster if shared accesses dominate as it may - * simply bounce migrations uselessly - */ - ratio = DIV_ROUND_UP(private * NUMA_PERIOD_SLOTS, (private + shared + 1)); - diff = (diff * ratio) / NUMA_PERIOD_SLOTS; - } - - p->numa_scan_period = clamp(p->numa_scan_period + diff, - task_scan_min(p), task_scan_max(p)); - memset(p->numa_faults_locality, 0, sizeof(p->numa_faults_locality)); -} - -/* - * Get the fraction of time the task has been running since the last - * NUMA placement cycle. The scheduler keeps similar statistics, but - * decays those on a 32ms period, which is orders of magnitude off - * from the dozens-of-seconds NUMA balancing period. Use the scheduler - * stats only if the task is so new there are no NUMA statistics yet. - */ -static u64 numa_get_avg_runtime(struct task_struct *p, u64 *period) -{ - u64 runtime, delta, now; - /* Use the start of this time slice to avoid calculations. */ - now = p->se.exec_start; - runtime = p->se.sum_exec_runtime; - - if (p->last_task_numa_placement) { - delta = runtime - p->last_sum_exec_runtime; - *period = now - p->last_task_numa_placement; - } else { - delta = p->se.avg.load_sum / p->se.load.weight; - *period = LOAD_AVG_MAX; - } - - p->last_sum_exec_runtime = runtime; - p->last_task_numa_placement = now; - - return delta; -} - -/* - * Determine the preferred nid for a task in a numa_group. This needs to - * be done in a way that produces consistent results with group_weight, - * otherwise workloads might not converge. - */ -static int preferred_group_nid(struct task_struct *p, int nid) -{ - nodemask_t nodes; - int dist; - - /* Direct connections between all NUMA nodes. */ - if (sched_numa_topology_type == NUMA_DIRECT) - return nid; - - /* - * On a system with glueless mesh NUMA topology, group_weight - * scores nodes according to the number of NUMA hinting faults on - * both the node itself, and on nearby nodes. - */ - if (sched_numa_topology_type == NUMA_GLUELESS_MESH) { - unsigned long score, max_score = 0; - int node, max_node = nid; - - dist = sched_max_numa_distance; - - for_each_online_node(node) { - score = group_weight(p, node, dist); - if (score > max_score) { - max_score = score; - max_node = node; - } - } - return max_node; - } - - /* - * Finding the preferred nid in a system with NUMA backplane - * interconnect topology is more involved. The goal is to locate - * tasks from numa_groups near each other in the system, and - * untangle workloads from different sides of the system. This requires - * searching down the hierarchy of node groups, recursively searching - * inside the highest scoring group of nodes. The nodemask tricks - * keep the complexity of the search down. - */ - nodes = node_online_map; - for (dist = sched_max_numa_distance; dist > LOCAL_DISTANCE; dist--) { - unsigned long max_faults = 0; - nodemask_t max_group = NODE_MASK_NONE; - int a, b; - - /* Are there nodes at this distance from each other? */ - if (!find_numa_distance(dist)) - continue; - - for_each_node_mask(a, nodes) { - unsigned long faults = 0; - nodemask_t this_group; - nodes_clear(this_group); - - /* Sum group's NUMA faults; includes a==b case. */ - for_each_node_mask(b, nodes) { - if (node_distance(a, b) < dist) { - faults += group_faults(p, b); - node_set(b, this_group); - node_clear(b, nodes); - } - } - - /* Remember the top group. */ - if (faults > max_faults) { - max_faults = faults; - max_group = this_group; - /* - * subtle: at the smallest distance there is - * just one node left in each "group", the - * winner is the preferred nid. - */ - nid = a; - } - } - /* Next round, evaluate the nodes within max_group. */ - if (!max_faults) - break; - nodes = max_group; - } - return nid; -} - -static void task_numa_placement(struct task_struct *p) -{ - int seq, nid, max_nid = -1, max_group_nid = -1; - unsigned long max_faults = 0, max_group_faults = 0; - unsigned long fault_types[2] = { 0, 0 }; - unsigned long total_faults; - u64 runtime, period; - spinlock_t *group_lock = NULL; - - /* - * The p->mm->numa_scan_seq field gets updated without - * exclusive access. Use READ_ONCE() here to ensure - * that the field is read in a single access: - */ - seq = READ_ONCE(p->mm->numa_scan_seq); - if (p->numa_scan_seq == seq) - return; - p->numa_scan_seq = seq; - p->numa_scan_period_max = task_scan_max(p); - - total_faults = p->numa_faults_locality[0] + - p->numa_faults_locality[1]; - runtime = numa_get_avg_runtime(p, &period); - - /* If the task is part of a group prevent parallel updates to group stats */ - if (p->numa_group) { - group_lock = &p->numa_group->lock; - spin_lock_irq(group_lock); - } - - /* Find the node with the highest number of faults */ - for_each_online_node(nid) { - /* Keep track of the offsets in numa_faults array */ - int mem_idx, membuf_idx, cpu_idx, cpubuf_idx; - unsigned long faults = 0, group_faults = 0; - int priv; - - for (priv = 0; priv < NR_NUMA_HINT_FAULT_TYPES; priv++) { - long diff, f_diff, f_weight; - - mem_idx = task_faults_idx(NUMA_MEM, nid, priv); - membuf_idx = task_faults_idx(NUMA_MEMBUF, nid, priv); - cpu_idx = task_faults_idx(NUMA_CPU, nid, priv); - cpubuf_idx = task_faults_idx(NUMA_CPUBUF, nid, priv); - - /* Decay existing window, copy faults since last scan */ - diff = p->numa_faults[membuf_idx] - p->numa_faults[mem_idx] / 2; - fault_types[priv] += p->numa_faults[membuf_idx]; - p->numa_faults[membuf_idx] = 0; - - /* - * Normalize the faults_from, so all tasks in a group - * count according to CPU use, instead of by the raw - * number of faults. Tasks with little runtime have - * little over-all impact on throughput, and thus their - * faults are less important. - */ - f_weight = div64_u64(runtime << 16, period + 1); - f_weight = (f_weight * p->numa_faults[cpubuf_idx]) / - (total_faults + 1); - f_diff = f_weight - p->numa_faults[cpu_idx] / 2; - p->numa_faults[cpubuf_idx] = 0; - - p->numa_faults[mem_idx] += diff; - p->numa_faults[cpu_idx] += f_diff; - faults += p->numa_faults[mem_idx]; - p->total_numa_faults += diff; - if (p->numa_group) { - /* - * safe because we can only change our own group - * - * mem_idx represents the offset for a given - * nid and priv in a specific region because it - * is at the beginning of the numa_faults array. - */ - p->numa_group->faults[mem_idx] += diff; - p->numa_group->faults_cpu[mem_idx] += f_diff; - p->numa_group->total_faults += diff; - group_faults += p->numa_group->faults[mem_idx]; - } - } - - if (faults > max_faults) { - max_faults = faults; - max_nid = nid; - } - - if (group_faults > max_group_faults) { - max_group_faults = group_faults; - max_group_nid = nid; - } - } - - update_task_scan_period(p, fault_types[0], fault_types[1]); - - if (p->numa_group) { - numa_group_count_active_nodes(p->numa_group); - spin_unlock_irq(group_lock); - max_nid = preferred_group_nid(p, max_group_nid); - } - - if (max_faults) { - /* Set the new preferred node */ - if (max_nid != p->numa_preferred_nid) - sched_setnuma(p, max_nid); - - if (task_node(p) != p->numa_preferred_nid) - numa_migrate_preferred(p); - } -} - -static inline int get_numa_group(struct numa_group *grp) -{ - return atomic_inc_not_zero(&grp->refcount); -} - -static inline void put_numa_group(struct numa_group *grp) -{ - if (atomic_dec_and_test(&grp->refcount)) - kfree_rcu(grp, rcu); -} - -static void task_numa_group(struct task_struct *p, int cpupid, int flags, - int *priv) -{ - struct numa_group *grp, *my_grp; - struct task_struct *tsk; - bool join = false; - int cpu = cpupid_to_cpu(cpupid); - int i; - - if (unlikely(!p->numa_group)) { - unsigned int size = sizeof(struct numa_group) + - 4*nr_node_ids*sizeof(unsigned long); - - grp = kzalloc(size, GFP_KERNEL | __GFP_NOWARN); - if (!grp) - return; - - atomic_set(&grp->refcount, 1); - grp->active_nodes = 1; - grp->max_faults_cpu = 0; - spin_lock_init(&grp->lock); - grp->gid = p->pid; - /* Second half of the array tracks nids where faults happen */ - grp->faults_cpu = grp->faults + NR_NUMA_HINT_FAULT_TYPES * - nr_node_ids; - - for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++) - grp->faults[i] = p->numa_faults[i]; - - grp->total_faults = p->total_numa_faults; - - grp->nr_tasks++; - rcu_assign_pointer(p->numa_group, grp); - } - - rcu_read_lock(); - tsk = READ_ONCE(cpu_rq(cpu)->curr); - - if (!cpupid_match_pid(tsk, cpupid)) - goto no_join; - - grp = rcu_dereference(tsk->numa_group); - if (!grp) - goto no_join; - - my_grp = p->numa_group; - if (grp == my_grp) - goto no_join; - - /* - * Only join the other group if its bigger; if we're the bigger group, - * the other task will join us. - */ - if (my_grp->nr_tasks > grp->nr_tasks) - goto no_join; - - /* - * Tie-break on the grp address. - */ - if (my_grp->nr_tasks == grp->nr_tasks && my_grp > grp) - goto no_join; - - /* Always join threads in the same process. */ - if (tsk->mm == current->mm) - join = true; - - /* Simple filter to avoid false positives due to PID collisions */ - if (flags & TNF_SHARED) - join = true; - - /* Update priv based on whether false sharing was detected */ - *priv = !join; - - if (join && !get_numa_group(grp)) - goto no_join; - - rcu_read_unlock(); - - if (!join) - return; - - BUG_ON(irqs_disabled()); - double_lock_irq(&my_grp->lock, &grp->lock); - - for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++) { - my_grp->faults[i] -= p->numa_faults[i]; - grp->faults[i] += p->numa_faults[i]; - } - my_grp->total_faults -= p->total_numa_faults; - grp->total_faults += p->total_numa_faults; - - my_grp->nr_tasks--; - grp->nr_tasks++; - - spin_unlock(&my_grp->lock); - spin_unlock_irq(&grp->lock); - - rcu_assign_pointer(p->numa_group, grp); - - put_numa_group(my_grp); - return; - -no_join: - rcu_read_unlock(); - return; -} - -void task_numa_free(struct task_struct *p) -{ - struct numa_group *grp = p->numa_group; - void *numa_faults = p->numa_faults; - unsigned long flags; - int i; - - if (grp) { - spin_lock_irqsave(&grp->lock, flags); - for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++) - grp->faults[i] -= p->numa_faults[i]; - grp->total_faults -= p->total_numa_faults; - - grp->nr_tasks--; - spin_unlock_irqrestore(&grp->lock, flags); - RCU_INIT_POINTER(p->numa_group, NULL); - put_numa_group(grp); - } - - p->numa_faults = NULL; - kfree(numa_faults); -} - -/* - * Got a PROT_NONE fault for a page on @node. - */ -void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags) -{ - struct task_struct *p = current; - bool migrated = flags & TNF_MIGRATED; - int cpu_node = task_node(current); - int local = !!(flags & TNF_FAULT_LOCAL); - struct numa_group *ng; - int priv; - - if (!static_branch_likely(&sched_numa_balancing)) - return; - - /* for example, ksmd faulting in a user's mm */ - if (!p->mm) - return; - - /* Allocate buffer to track faults on a per-node basis */ - if (unlikely(!p->numa_faults)) { - int size = sizeof(*p->numa_faults) * - NR_NUMA_HINT_FAULT_BUCKETS * nr_node_ids; - - p->numa_faults = kzalloc(size, GFP_KERNEL|__GFP_NOWARN); - if (!p->numa_faults) - return; - - p->total_numa_faults = 0; - memset(p->numa_faults_locality, 0, sizeof(p->numa_faults_locality)); - } - - /* - * First accesses are treated as private, otherwise consider accesses - * to be private if the accessing pid has not changed - */ - if (unlikely(last_cpupid == (-1 & LAST_CPUPID_MASK))) { - priv = 1; - } else { - priv = cpupid_match_pid(p, last_cpupid); - if (!priv && !(flags & TNF_NO_GROUP)) - task_numa_group(p, last_cpupid, flags, &priv); - } - - /* - * If a workload spans multiple NUMA nodes, a shared fault that - * occurs wholly within the set of nodes that the workload is - * actively using should be counted as local. This allows the - * scan rate to slow down when a workload has settled down. - */ - ng = p->numa_group; - if (!priv && !local && ng && ng->active_nodes > 1 && - numa_is_active_node(cpu_node, ng) && - numa_is_active_node(mem_node, ng)) - local = 1; - - task_numa_placement(p); - - /* - * Retry task to preferred node migration periodically, in case it - * case it previously failed, or the scheduler moved us. - */ - if (time_after(jiffies, p->numa_migrate_retry)) - numa_migrate_preferred(p); - - if (migrated) - p->numa_pages_migrated += pages; - if (flags & TNF_MIGRATE_FAIL) - p->numa_faults_locality[2] += pages; - - p->numa_faults[task_faults_idx(NUMA_MEMBUF, mem_node, priv)] += pages; - p->numa_faults[task_faults_idx(NUMA_CPUBUF, cpu_node, priv)] += pages; - p->numa_faults_locality[local] += pages; -} - -static void reset_ptenuma_scan(struct task_struct *p) -{ - /* - * We only did a read acquisition of the mmap sem, so - * p->mm->numa_scan_seq is written to without exclusive access - * and the update is not guaranteed to be atomic. That's not - * much of an issue though, since this is just used for - * statistical sampling. Use READ_ONCE/WRITE_ONCE, which are not - * expensive, to avoid any form of compiler optimizations: - */ - WRITE_ONCE(p->mm->numa_scan_seq, READ_ONCE(p->mm->numa_scan_seq) + 1); - p->mm->numa_scan_offset = 0; -} - -/* - * The expensive part of numa migration is done from task_work context. - * Triggered from task_tick_numa(). - */ -void task_numa_work(struct callback_head *work) -{ - unsigned long migrate, next_scan, now = jiffies; - struct task_struct *p = current; - struct mm_struct *mm = p->mm; - u64 runtime = p->se.sum_exec_runtime; - struct vm_area_struct *vma; - unsigned long start, end; - unsigned long nr_pte_updates = 0; - long pages, virtpages; - - SCHED_WARN_ON(p != container_of(work, struct task_struct, numa_work)); - - work->next = work; /* protect against double add */ - /* - * Who cares about NUMA placement when they're dying. - * - * NOTE: make sure not to dereference p->mm before this check, - * exit_task_work() happens _after_ exit_mm() so we could be called - * without p->mm even though we still had it when we enqueued this - * work. - */ - if (p->flags & PF_EXITING) - return; - - if (!mm->numa_next_scan) { - mm->numa_next_scan = now + - msecs_to_jiffies(sysctl_numa_balancing_scan_delay); - } - - /* - * Enforce maximal scan/migration frequency.. - */ - migrate = mm->numa_next_scan; - if (time_before(now, migrate)) - return; - - if (p->numa_scan_period == 0) { - p->numa_scan_period_max = task_scan_max(p); - p->numa_scan_period = task_scan_min(p); - } - - next_scan = now + msecs_to_jiffies(p->numa_scan_period); - if (cmpxchg(&mm->numa_next_scan, migrate, next_scan) != migrate) - return; - - /* - * Delay this task enough that another task of this mm will likely win - * the next time around. - */ - p->node_stamp += 2 * TICK_NSEC; - - start = mm->numa_scan_offset; - pages = sysctl_numa_balancing_scan_size; - pages <<= 20 - PAGE_SHIFT; /* MB in pages */ - virtpages = pages * 8; /* Scan up to this much virtual space */ - if (!pages) - return; - - - down_read(&mm->mmap_sem); - vma = find_vma(mm, start); - if (!vma) { - reset_ptenuma_scan(p); - start = 0; - vma = mm->mmap; - } - for (; vma; vma = vma->vm_next) { - if (!vma_migratable(vma) || !vma_policy_mof(vma) || - is_vm_hugetlb_page(vma) || (vma->vm_flags & VM_MIXEDMAP)) { - continue; - } - - /* - * Shared library pages mapped by multiple processes are not - * migrated as it is expected they are cache replicated. Avoid - * hinting faults in read-only file-backed mappings or the vdso - * as migrating the pages will be of marginal benefit. - */ - if (!vma->vm_mm || - (vma->vm_file && (vma->vm_flags & (VM_READ|VM_WRITE)) == (VM_READ))) - continue; - - /* - * Skip inaccessible VMAs to avoid any confusion between - * PROT_NONE and NUMA hinting ptes - */ - if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) - continue; - - do { - start = max(start, vma->vm_start); - end = ALIGN(start + (pages << PAGE_SHIFT), HPAGE_SIZE); - end = min(end, vma->vm_end); - nr_pte_updates = change_prot_numa(vma, start, end); - - /* - * Try to scan sysctl_numa_balancing_size worth of - * hpages that have at least one present PTE that - * is not already pte-numa. If the VMA contains - * areas that are unused or already full of prot_numa - * PTEs, scan up to virtpages, to skip through those - * areas faster. - */ - if (nr_pte_updates) - pages -= (end - start) >> PAGE_SHIFT; - virtpages -= (end - start) >> PAGE_SHIFT; - - start = end; - if (pages <= 0 || virtpages <= 0) - goto out; - - cond_resched(); - } while (end != vma->vm_end); - } - -out: - /* - * It is possible to reach the end of the VMA list but the last few - * VMAs are not guaranteed to the vma_migratable. If they are not, we - * would find the !migratable VMA on the next scan but not reset the - * scanner to the start so check it now. - */ - if (vma) - mm->numa_scan_offset = start; - else - reset_ptenuma_scan(p); - up_read(&mm->mmap_sem); - - /* - * Make sure tasks use at least 32x as much time to run other code - * than they used here, to limit NUMA PTE scanning overhead to 3% max. - * Usually update_task_scan_period slows down scanning enough; on an - * overloaded system we need to limit overhead on a per task basis. - */ - if (unlikely(p->se.sum_exec_runtime != runtime)) { - u64 diff = p->se.sum_exec_runtime - runtime; - p->node_stamp += 32 * diff; - } -} - -/* - * Drive the periodic memory faults.. - */ -void task_tick_numa(struct rq *rq, struct task_struct *curr) -{ - struct callback_head *work = &curr->numa_work; - u64 period, now; - - /* - * We don't care about NUMA placement if we don't have memory. - */ - if (!curr->mm || (curr->flags & PF_EXITING) || work->next != work) - return; - - /* - * Using runtime rather than walltime has the dual advantage that - * we (mostly) drive the selection from busy threads and that the - * task needs to have done some actual work before we bother with - * NUMA placement. - */ - now = curr->se.sum_exec_runtime; - period = (u64)curr->numa_scan_period * NSEC_PER_MSEC; - - if (now > curr->node_stamp + period) { - if (!curr->node_stamp) - curr->numa_scan_period = task_scan_min(curr); - curr->node_stamp += period; - - if (!time_before(jiffies, curr->mm->numa_next_scan)) { - init_task_work(work, task_numa_work); /* TODO: move this into sched_fork() */ - task_work_add(curr, work, true); - } - } -} -#else -static void task_tick_numa(struct rq *rq, struct task_struct *curr) -{ -} - -static inline void account_numa_enqueue(struct rq *rq, struct task_struct *p) -{ -} - -static inline void account_numa_dequeue(struct rq *rq, struct task_struct *p) -{ -} -#endif /* CONFIG_NUMA_BALANCING */ - -static void -account_entity_enqueue(struct cfs_rq *cfs_rq, struct sched_entity *se) -{ - update_load_add(&cfs_rq->load, se->load.weight); - if (!parent_entity(se)) - update_load_add(&rq_of(cfs_rq)->load, se->load.weight); -#ifdef CONFIG_SMP - if (entity_is_task(se)) { - struct rq *rq = rq_of(cfs_rq); - - account_numa_enqueue(rq, task_of(se)); - list_add(&se->group_node, &rq->cfs_tasks); - } -#endif - cfs_rq->nr_running++; -} - -static void -account_entity_dequeue(struct cfs_rq *cfs_rq, struct sched_entity *se) -{ - update_load_sub(&cfs_rq->load, se->load.weight); - if (!parent_entity(se)) - update_load_sub(&rq_of(cfs_rq)->load, se->load.weight); -#ifdef CONFIG_SMP - if (entity_is_task(se)) { - account_numa_dequeue(rq_of(cfs_rq), task_of(se)); - list_del_init(&se->group_node); - } -#endif - cfs_rq->nr_running--; -} - -#ifdef CONFIG_FAIR_GROUP_SCHED -# ifdef CONFIG_SMP -static long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg) -{ - long tg_weight, load, shares; - - /* - * This really should be: cfs_rq->avg.load_avg, but instead we use - * cfs_rq->load.weight, which is its upper bound. This helps ramp up - * the shares for small weight interactive tasks. - */ - load = scale_load_down(cfs_rq->load.weight); - - tg_weight = atomic_long_read(&tg->load_avg); - - /* Ensure tg_weight >= load */ - tg_weight -= cfs_rq->tg_load_avg_contrib; - tg_weight += load; - - shares = (tg->shares * load); - if (tg_weight) - shares /= tg_weight; - - if (shares < MIN_SHARES) - shares = MIN_SHARES; - if (shares > tg->shares) - shares = tg->shares; - - return shares; -} -# else /* CONFIG_SMP */ -static inline long calc_cfs_shares(struct cfs_rq *cfs_rq, struct task_group *tg) -{ - return tg->shares; -} -# endif /* CONFIG_SMP */ - -static void reweight_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, - unsigned long weight) -{ - if (se->on_rq) { - /* commit outstanding execution time */ - if (cfs_rq->curr == se) - update_curr(cfs_rq); - account_entity_dequeue(cfs_rq, se); - } - - update_load_set(&se->load, weight); - - if (se->on_rq) - account_entity_enqueue(cfs_rq, se); -} - -static inline int throttled_hierarchy(struct cfs_rq *cfs_rq); - -static void update_cfs_shares(struct cfs_rq *cfs_rq) -{ - struct task_group *tg; - struct sched_entity *se; - long shares; - - tg = cfs_rq->tg; - se = tg->se[cpu_of(rq_of(cfs_rq))]; - if (!se || throttled_hierarchy(cfs_rq)) - return; -#ifndef CONFIG_SMP - if (likely(se->load.weight == tg->shares)) - return; -#endif - shares = calc_cfs_shares(cfs_rq, tg); - - reweight_entity(cfs_rq_of(se), se, shares); -} -#else /* CONFIG_FAIR_GROUP_SCHED */ -static inline void update_cfs_shares(struct cfs_rq *cfs_rq) -{ -} -#endif /* CONFIG_FAIR_GROUP_SCHED */ - -#ifdef CONFIG_SMP -/* Precomputed fixed inverse multiplies for multiplication by y^n */ -static const u32 runnable_avg_yN_inv[] = { - 0xffffffff, 0xfa83b2da, 0xf5257d14, 0xefe4b99a, 0xeac0c6e6, 0xe5b906e6, - 0xe0ccdeeb, 0xdbfbb796, 0xd744fcc9, 0xd2a81d91, 0xce248c14, 0xc9b9bd85, - 0xc5672a10, 0xc12c4cc9, 0xbd08a39e, 0xb8fbaf46, 0xb504f333, 0xb123f581, - 0xad583ee9, 0xa9a15ab4, 0xa5fed6a9, 0xa2704302, 0x9ef5325f, 0x9b8d39b9, - 0x9837f050, 0x94f4efa8, 0x91c3d373, 0x8ea4398a, 0x8b95c1e3, 0x88980e80, - 0x85aac367, 0x82cd8698, -}; - -/* - * Precomputed \Sum y^k { 1<=k<=n }. These are floor(true_value) to prevent - * over-estimates when re-combining. - */ -static const u32 runnable_avg_yN_sum[] = { - 0, 1002, 1982, 2941, 3880, 4798, 5697, 6576, 7437, 8279, 9103, - 9909,10698,11470,12226,12966,13690,14398,15091,15769,16433,17082, - 17718,18340,18949,19545,20128,20698,21256,21802,22336,22859,23371, -}; - -/* - * Precomputed \Sum y^k { 1<=k<=n, where n%32=0). Values are rolled down to - * lower integers. See Documentation/scheduler/sched-avg.txt how these - * were generated: - */ -static const u32 __accumulated_sum_N32[] = { - 0, 23371, 35056, 40899, 43820, 45281, - 46011, 46376, 46559, 46650, 46696, 46719, -}; - -/* - * Approximate: - * val * y^n, where y^32 ~= 0.5 (~1 scheduling period) - */ -static __always_inline u64 decay_load(u64 val, u64 n) -{ - unsigned int local_n; - - if (!n) - return val; - else if (unlikely(n > LOAD_AVG_PERIOD * 63)) - return 0; - - /* after bounds checking we can collapse to 32-bit */ - local_n = n; - - /* - * As y^PERIOD = 1/2, we can combine - * y^n = 1/2^(n/PERIOD) * y^(n%PERIOD) - * With a look-up table which covers y^n (n= LOAD_AVG_PERIOD)) { - val >>= local_n / LOAD_AVG_PERIOD; - local_n %= LOAD_AVG_PERIOD; - } - - val = mul_u64_u32_shr(val, runnable_avg_yN_inv[local_n], 32); - return val; -} - -/* - * For updates fully spanning n periods, the contribution to runnable - * average will be: \Sum 1024*y^n - * - * We can compute this reasonably efficiently by combining: - * y^PERIOD = 1/2 with precomputed \Sum 1024*y^n {for n = LOAD_AVG_MAX_N)) - return LOAD_AVG_MAX; - - /* Since n < LOAD_AVG_MAX_N, n/LOAD_AVG_PERIOD < 11 */ - contrib = __accumulated_sum_N32[n/LOAD_AVG_PERIOD]; - n %= LOAD_AVG_PERIOD; - contrib = decay_load(contrib, n); - return contrib + runnable_avg_yN_sum[n]; -} - -#define cap_scale(v, s) ((v)*(s) >> SCHED_CAPACITY_SHIFT) - -/* - * We can represent the historical contribution to runnable average as the - * coefficients of a geometric series. To do this we sub-divide our runnable - * history into segments of approximately 1ms (1024us); label the segment that - * occurred N-ms ago p_N, with p_0 corresponding to the current period, e.g. - * - * [<- 1024us ->|<- 1024us ->|<- 1024us ->| ... - * p0 p1 p2 - * (now) (~1ms ago) (~2ms ago) - * - * Let u_i denote the fraction of p_i that the entity was runnable. - * - * We then designate the fractions u_i as our co-efficients, yielding the - * following representation of historical load: - * u_0 + u_1*y + u_2*y^2 + u_3*y^3 + ... - * - * We choose y based on the with of a reasonably scheduling period, fixing: - * y^32 = 0.5 - * - * This means that the contribution to load ~32ms ago (u_32) will be weighted - * approximately half as much as the contribution to load within the last ms - * (u_0). - * - * When a period "rolls over" and we have new u_0`, multiplying the previous - * sum again by y is sufficient to update: - * load_avg = u_0` + y*(u_0 + u_1*y + u_2*y^2 + ... ) - * = u_0 + u_1*y + u_2*y^2 + ... [re-labeling u_i --> u_{i+1}] - */ -static __always_inline int -__update_load_avg(u64 now, int cpu, struct sched_avg *sa, - unsigned long weight, int running, struct cfs_rq *cfs_rq) -{ - u64 delta, scaled_delta, periods; - u32 contrib; - unsigned int delta_w, scaled_delta_w, decayed = 0; - unsigned long scale_freq, scale_cpu; - - delta = now - sa->last_update_time; - /* - * This should only happen when time goes backwards, which it - * unfortunately does during sched clock init when we swap over to TSC. - */ - if ((s64)delta < 0) { - sa->last_update_time = now; - return 0; - } - - /* - * Use 1024ns as the unit of measurement since it's a reasonable - * approximation of 1us and fast to compute. - */ - delta >>= 10; - if (!delta) - return 0; - sa->last_update_time = now; - - scale_freq = arch_scale_freq_capacity(NULL, cpu); - scale_cpu = arch_scale_cpu_capacity(NULL, cpu); - - /* delta_w is the amount already accumulated against our next period */ - delta_w = sa->period_contrib; - if (delta + delta_w >= 1024) { - decayed = 1; - - /* how much left for next period will start over, we don't know yet */ - sa->period_contrib = 0; - - /* - * Now that we know we're crossing a period boundary, figure - * out how much from delta we need to complete the current - * period and accrue it. - */ - delta_w = 1024 - delta_w; - scaled_delta_w = cap_scale(delta_w, scale_freq); - if (weight) { - sa->load_sum += weight * scaled_delta_w; - if (cfs_rq) { - cfs_rq->runnable_load_sum += - weight * scaled_delta_w; - } - } - if (running) - sa->util_sum += scaled_delta_w * scale_cpu; - - delta -= delta_w; - - /* Figure out how many additional periods this update spans */ - periods = delta / 1024; - delta %= 1024; - - sa->load_sum = decay_load(sa->load_sum, periods + 1); - if (cfs_rq) { - cfs_rq->runnable_load_sum = - decay_load(cfs_rq->runnable_load_sum, periods + 1); - } - sa->util_sum = decay_load((u64)(sa->util_sum), periods + 1); - - /* Efficiently calculate \sum (1..n_period) 1024*y^i */ - contrib = __compute_runnable_contrib(periods); - contrib = cap_scale(contrib, scale_freq); - if (weight) { - sa->load_sum += weight * contrib; - if (cfs_rq) - cfs_rq->runnable_load_sum += weight * contrib; - } - if (running) - sa->util_sum += contrib * scale_cpu; - } - - /* Remainder of delta accrued against u_0` */ - scaled_delta = cap_scale(delta, scale_freq); - if (weight) { - sa->load_sum += weight * scaled_delta; - if (cfs_rq) - cfs_rq->runnable_load_sum += weight * scaled_delta; - } - if (running) - sa->util_sum += scaled_delta * scale_cpu; - - sa->period_contrib += delta; - - if (decayed) { - sa->load_avg = div_u64(sa->load_sum, LOAD_AVG_MAX); - if (cfs_rq) { - cfs_rq->runnable_load_avg = - div_u64(cfs_rq->runnable_load_sum, LOAD_AVG_MAX); - } - sa->util_avg = sa->util_sum / LOAD_AVG_MAX; - } - - return decayed; -} - -#ifdef CONFIG_FAIR_GROUP_SCHED -/** - * update_tg_load_avg - update the tg's load avg - * @cfs_rq: the cfs_rq whose avg changed - * @force: update regardless of how small the difference - * - * This function 'ensures': tg->load_avg := \Sum tg->cfs_rq[]->avg.load. - * However, because tg->load_avg is a global value there are performance - * considerations. - * - * In order to avoid having to look at the other cfs_rq's, we use a - * differential update where we store the last value we propagated. This in - * turn allows skipping updates if the differential is 'small'. - * - * Updating tg's load_avg is necessary before update_cfs_share() (which is - * done) and effective_load() (which is not done because it is too costly). - */ -static inline void update_tg_load_avg(struct cfs_rq *cfs_rq, int force) -{ - long delta = cfs_rq->avg.load_avg - cfs_rq->tg_load_avg_contrib; - - /* - * No need to update load_avg for root_task_group as it is not used. - */ - if (cfs_rq->tg == &root_task_group) - return; - - if (force || abs(delta) > cfs_rq->tg_load_avg_contrib / 64) { - atomic_long_add(delta, &cfs_rq->tg->load_avg); - cfs_rq->tg_load_avg_contrib = cfs_rq->avg.load_avg; - } -} - -/* - * Called within set_task_rq() right before setting a task's cpu. The - * caller only guarantees p->pi_lock is held; no other assumptions, - * including the state of rq->lock, should be made. - */ -void set_task_rq_fair(struct sched_entity *se, - struct cfs_rq *prev, struct cfs_rq *next) -{ - if (!sched_feat(ATTACH_AGE_LOAD)) - return; - - /* - * We are supposed to update the task to "current" time, then its up to - * date and ready to go to new CPU/cfs_rq. But we have difficulty in - * getting what current time is, so simply throw away the out-of-date - * time. This will result in the wakee task is less decayed, but giving - * the wakee more load sounds not bad. - */ - if (se->avg.last_update_time && prev) { - u64 p_last_update_time; - u64 n_last_update_time; - -#ifndef CONFIG_64BIT - u64 p_last_update_time_copy; - u64 n_last_update_time_copy; - - do { - p_last_update_time_copy = prev->load_last_update_time_copy; - n_last_update_time_copy = next->load_last_update_time_copy; - - smp_rmb(); - - p_last_update_time = prev->avg.last_update_time; - n_last_update_time = next->avg.last_update_time; - - } while (p_last_update_time != p_last_update_time_copy || - n_last_update_time != n_last_update_time_copy); -#else - p_last_update_time = prev->avg.last_update_time; - n_last_update_time = next->avg.last_update_time; -#endif - __update_load_avg(p_last_update_time, cpu_of(rq_of(prev)), - &se->avg, 0, 0, NULL); - se->avg.last_update_time = n_last_update_time; - } -} -#else /* CONFIG_FAIR_GROUP_SCHED */ -static inline void update_tg_load_avg(struct cfs_rq *cfs_rq, int force) {} -#endif /* CONFIG_FAIR_GROUP_SCHED */ - -static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq) -{ - if (&this_rq()->cfs == cfs_rq) { - /* - * There are a few boundary cases this might miss but it should - * get called often enough that that should (hopefully) not be - * a real problem -- added to that it only calls on the local - * CPU, so if we enqueue remotely we'll miss an update, but - * the next tick/schedule should update. - * - * It will not get called when we go idle, because the idle - * thread is a different class (!fair), nor will the utilization - * number include things like RT tasks. - * - * As is, the util number is not freq-invariant (we'd have to - * implement arch_scale_freq_capacity() for that). - * - * See cpu_util(). - */ - cpufreq_update_util(rq_of(cfs_rq), 0); - } -} - -/* - * Unsigned subtract and clamp on underflow. - * - * Explicitly do a load-store to ensure the intermediate value never hits - * memory. This allows lockless observations without ever seeing the negative - * values. - */ -#define sub_positive(_ptr, _val) do { \ - typeof(_ptr) ptr = (_ptr); \ - typeof(*ptr) val = (_val); \ - typeof(*ptr) res, var = READ_ONCE(*ptr); \ - res = var - val; \ - if (res > var) \ - res = 0; \ - WRITE_ONCE(*ptr, res); \ -} while (0) - -/** - * update_cfs_rq_load_avg - update the cfs_rq's load/util averages - * @now: current time, as per cfs_rq_clock_task() - * @cfs_rq: cfs_rq to update - * @update_freq: should we call cfs_rq_util_change() or will the call do so - * - * The cfs_rq avg is the direct sum of all its entities (blocked and runnable) - * avg. The immediate corollary is that all (fair) tasks must be attached, see - * post_init_entity_util_avg(). - * - * cfs_rq->avg is used for task_h_load() and update_cfs_share() for example. - * - * Returns true if the load decayed or we removed load. - * - * Since both these conditions indicate a changed cfs_rq->avg.load we should - * call update_tg_load_avg() when this function returns true. - */ -static inline int -update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq, bool update_freq) -{ - struct sched_avg *sa = &cfs_rq->avg; - int decayed, removed_load = 0, removed_util = 0; - - if (atomic_long_read(&cfs_rq->removed_load_avg)) { - s64 r = atomic_long_xchg(&cfs_rq->removed_load_avg, 0); - sub_positive(&sa->load_avg, r); - sub_positive(&sa->load_sum, r * LOAD_AVG_MAX); - removed_load = 1; - } - - if (atomic_long_read(&cfs_rq->removed_util_avg)) { - long r = atomic_long_xchg(&cfs_rq->removed_util_avg, 0); - sub_positive(&sa->util_avg, r); - sub_positive(&sa->util_sum, r * LOAD_AVG_MAX); - removed_util = 1; - } - - decayed = __update_load_avg(now, cpu_of(rq_of(cfs_rq)), sa, - scale_load_down(cfs_rq->load.weight), cfs_rq->curr != NULL, cfs_rq); - -#ifndef CONFIG_64BIT - smp_wmb(); - cfs_rq->load_last_update_time_copy = sa->last_update_time; -#endif - - if (update_freq && (decayed || removed_util)) - cfs_rq_util_change(cfs_rq); - - return decayed || removed_load; -} - -/* Update task and its cfs_rq load average */ -static inline void update_load_avg(struct sched_entity *se, int update_tg) -{ - struct cfs_rq *cfs_rq = cfs_rq_of(se); - u64 now = cfs_rq_clock_task(cfs_rq); - struct rq *rq = rq_of(cfs_rq); - int cpu = cpu_of(rq); - - /* - * Track task load average for carrying it to new CPU after migrated, and - * track group sched_entity load average for task_h_load calc in migration - */ - __update_load_avg(now, cpu, &se->avg, - se->on_rq * scale_load_down(se->load.weight), - cfs_rq->curr == se, NULL); - - if (update_cfs_rq_load_avg(now, cfs_rq, true) && update_tg) - update_tg_load_avg(cfs_rq, 0); -} - -/** - * attach_entity_load_avg - attach this entity to its cfs_rq load avg - * @cfs_rq: cfs_rq to attach to - * @se: sched_entity to attach - * - * Must call update_cfs_rq_load_avg() before this, since we rely on - * cfs_rq->avg.last_update_time being current. - */ -static void attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) -{ - if (!sched_feat(ATTACH_AGE_LOAD)) - goto skip_aging; - - /* - * If we got migrated (either between CPUs or between cgroups) we'll - * have aged the average right before clearing @last_update_time. - * - * Or we're fresh through post_init_entity_util_avg(). - */ - if (se->avg.last_update_time) { - __update_load_avg(cfs_rq->avg.last_update_time, cpu_of(rq_of(cfs_rq)), - &se->avg, 0, 0, NULL); - - /* - * XXX: we could have just aged the entire load away if we've been - * absent from the fair class for too long. - */ - } - -skip_aging: - se->avg.last_update_time = cfs_rq->avg.last_update_time; - cfs_rq->avg.load_avg += se->avg.load_avg; - cfs_rq->avg.load_sum += se->avg.load_sum; - cfs_rq->avg.util_avg += se->avg.util_avg; - cfs_rq->avg.util_sum += se->avg.util_sum; - - cfs_rq_util_change(cfs_rq); -} - -/** - * detach_entity_load_avg - detach this entity from its cfs_rq load avg - * @cfs_rq: cfs_rq to detach from - * @se: sched_entity to detach - * - * Must call update_cfs_rq_load_avg() before this, since we rely on - * cfs_rq->avg.last_update_time being current. - */ -static void detach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) -{ - __update_load_avg(cfs_rq->avg.last_update_time, cpu_of(rq_of(cfs_rq)), - &se->avg, se->on_rq * scale_load_down(se->load.weight), - cfs_rq->curr == se, NULL); - - sub_positive(&cfs_rq->avg.load_avg, se->avg.load_avg); - sub_positive(&cfs_rq->avg.load_sum, se->avg.load_sum); - sub_positive(&cfs_rq->avg.util_avg, se->avg.util_avg); - sub_positive(&cfs_rq->avg.util_sum, se->avg.util_sum); - - cfs_rq_util_change(cfs_rq); -} - -/* Add the load generated by se into cfs_rq's load average */ -static inline void -enqueue_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) -{ - struct sched_avg *sa = &se->avg; - u64 now = cfs_rq_clock_task(cfs_rq); - int migrated, decayed; - - migrated = !sa->last_update_time; - if (!migrated) { - __update_load_avg(now, cpu_of(rq_of(cfs_rq)), sa, - se->on_rq * scale_load_down(se->load.weight), - cfs_rq->curr == se, NULL); - } - - decayed = update_cfs_rq_load_avg(now, cfs_rq, !migrated); - - cfs_rq->runnable_load_avg += sa->load_avg; - cfs_rq->runnable_load_sum += sa->load_sum; - - if (migrated) - attach_entity_load_avg(cfs_rq, se); - - if (decayed || migrated) - update_tg_load_avg(cfs_rq, 0); -} - -/* Remove the runnable load generated by se from cfs_rq's runnable load average */ -static inline void -dequeue_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) -{ - update_load_avg(se, 1); - - cfs_rq->runnable_load_avg = - max_t(long, cfs_rq->runnable_load_avg - se->avg.load_avg, 0); - cfs_rq->runnable_load_sum = - max_t(s64, cfs_rq->runnable_load_sum - se->avg.load_sum, 0); -} - -#ifndef CONFIG_64BIT -static inline u64 cfs_rq_last_update_time(struct cfs_rq *cfs_rq) -{ - u64 last_update_time_copy; - u64 last_update_time; - - do { - last_update_time_copy = cfs_rq->load_last_update_time_copy; - smp_rmb(); - last_update_time = cfs_rq->avg.last_update_time; - } while (last_update_time != last_update_time_copy); - - return last_update_time; -} -#else -static inline u64 cfs_rq_last_update_time(struct cfs_rq *cfs_rq) -{ - return cfs_rq->avg.last_update_time; -} -#endif - -/* - * Task first catches up with cfs_rq, and then subtract - * itself from the cfs_rq (task must be off the queue now). - */ -void remove_entity_load_avg(struct sched_entity *se) -{ - struct cfs_rq *cfs_rq = cfs_rq_of(se); - u64 last_update_time; - - /* - * tasks cannot exit without having gone through wake_up_new_task() -> - * post_init_entity_util_avg() which will have added things to the - * cfs_rq, so we can remove unconditionally. - * - * Similarly for groups, they will have passed through - * post_init_entity_util_avg() before unregister_sched_fair_group() - * calls this. - */ - - last_update_time = cfs_rq_last_update_time(cfs_rq); - - __update_load_avg(last_update_time, cpu_of(rq_of(cfs_rq)), &se->avg, 0, 0, NULL); - atomic_long_add(se->avg.load_avg, &cfs_rq->removed_load_avg); - atomic_long_add(se->avg.util_avg, &cfs_rq->removed_util_avg); -} - -static inline unsigned long cfs_rq_runnable_load_avg(struct cfs_rq *cfs_rq) -{ - return cfs_rq->runnable_load_avg; -} - -static inline unsigned long cfs_rq_load_avg(struct cfs_rq *cfs_rq) -{ - return cfs_rq->avg.load_avg; -} - -static int idle_balance(struct rq *this_rq); - -#else /* CONFIG_SMP */ - -static inline int -update_cfs_rq_load_avg(u64 now, struct cfs_rq *cfs_rq, bool update_freq) -{ - return 0; -} - -static inline void update_load_avg(struct sched_entity *se, int not_used) -{ - cpufreq_update_util(rq_of(cfs_rq_of(se)), 0); -} - -static inline void -enqueue_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) {} -static inline void -dequeue_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) {} -static inline void remove_entity_load_avg(struct sched_entity *se) {} - -static inline void -attach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) {} -static inline void -detach_entity_load_avg(struct cfs_rq *cfs_rq, struct sched_entity *se) {} - -static inline int idle_balance(struct rq *rq) -{ - return 0; -} - -#endif /* CONFIG_SMP */ - -static void check_spread(struct cfs_rq *cfs_rq, struct sched_entity *se) -{ -#ifdef CONFIG_SCHED_DEBUG - s64 d = se->vruntime - cfs_rq->min_vruntime; - - if (d < 0) - d = -d; - - if (d > 3*sysctl_sched_latency) - schedstat_inc(cfs_rq->nr_spread_over); -#endif -} - -static void -place_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int initial) -{ - u64 vruntime = cfs_rq->min_vruntime; - - /* - * The 'current' period is already promised to the current tasks, - * however the extra weight of the new task will slow them down a - * little, place the new task so that it fits in the slot that - * stays open at the end. - */ - if (initial && sched_feat(START_DEBIT)) - vruntime += sched_vslice(cfs_rq, se); - - /* sleeps up to a single latency don't count. */ - if (!initial) { - unsigned long thresh = sysctl_sched_latency; - - /* - * Halve their sleep time's effect, to allow - * for a gentler effect of sleepers: - */ - if (sched_feat(GENTLE_FAIR_SLEEPERS)) - thresh >>= 1; - - vruntime -= thresh; - } - - /* ensure we never gain time by being placed backwards. */ - se->vruntime = max_vruntime(se->vruntime, vruntime); -} - -static void check_enqueue_throttle(struct cfs_rq *cfs_rq); - -static inline void check_schedstat_required(void) -{ -#ifdef CONFIG_SCHEDSTATS - if (schedstat_enabled()) - return; - - /* Force schedstat enabled if a dependent tracepoint is active */ - if (trace_sched_stat_wait_enabled() || - trace_sched_stat_sleep_enabled() || - trace_sched_stat_iowait_enabled() || - trace_sched_stat_blocked_enabled() || - trace_sched_stat_runtime_enabled()) { - printk_deferred_once("Scheduler tracepoints stat_sleep, stat_iowait, " - "stat_blocked and stat_runtime require the " - "kernel parameter schedstats=enabled or " - "kernel.sched_schedstats=1\n"); - } -#endif -} - - -/* - * MIGRATION - * - * dequeue - * update_curr() - * update_min_vruntime() - * vruntime -= min_vruntime - * - * enqueue - * update_curr() - * update_min_vruntime() - * vruntime += min_vruntime - * - * this way the vruntime transition between RQs is done when both - * min_vruntime are up-to-date. - * - * WAKEUP (remote) - * - * ->migrate_task_rq_fair() (p->state == TASK_WAKING) - * vruntime -= min_vruntime - * - * enqueue - * update_curr() - * update_min_vruntime() - * vruntime += min_vruntime - * - * this way we don't have the most up-to-date min_vruntime on the originating - * CPU and an up-to-date min_vruntime on the destination CPU. - */ - -static void -enqueue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) -{ - bool renorm = !(flags & ENQUEUE_WAKEUP) || (flags & ENQUEUE_MIGRATED); - bool curr = cfs_rq->curr == se; - - /* - * If we're the current task, we must renormalise before calling - * update_curr(). - */ - if (renorm && curr) - se->vruntime += cfs_rq->min_vruntime; - - update_curr(cfs_rq); - - /* - * Otherwise, renormalise after, such that we're placed at the current - * moment in time, instead of some random moment in the past. Being - * placed in the past could significantly boost this task to the - * fairness detriment of existing tasks. - */ - if (renorm && !curr) - se->vruntime += cfs_rq->min_vruntime; - - enqueue_entity_load_avg(cfs_rq, se); - account_entity_enqueue(cfs_rq, se); - update_cfs_shares(cfs_rq); - - if (flags & ENQUEUE_WAKEUP) - place_entity(cfs_rq, se, 0); - - check_schedstat_required(); - update_stats_enqueue(cfs_rq, se, flags); - check_spread(cfs_rq, se); - if (!curr) - __enqueue_entity(cfs_rq, se); - se->on_rq = 1; - - if (cfs_rq->nr_running == 1) { - list_add_leaf_cfs_rq(cfs_rq); - check_enqueue_throttle(cfs_rq); - } -} - -static void __clear_buddies_last(struct sched_entity *se) -{ - for_each_sched_entity(se) { - struct cfs_rq *cfs_rq = cfs_rq_of(se); - if (cfs_rq->last != se) - break; - - cfs_rq->last = NULL; - } -} - -static void __clear_buddies_next(struct sched_entity *se) -{ - for_each_sched_entity(se) { - struct cfs_rq *cfs_rq = cfs_rq_of(se); - if (cfs_rq->next != se) - break; - - cfs_rq->next = NULL; - } -} - -static void __clear_buddies_skip(struct sched_entity *se) -{ - for_each_sched_entity(se) { - struct cfs_rq *cfs_rq = cfs_rq_of(se); - if (cfs_rq->skip != se) - break; - - cfs_rq->skip = NULL; - } -} - -static void clear_buddies(struct cfs_rq *cfs_rq, struct sched_entity *se) -{ - if (cfs_rq->last == se) - __clear_buddies_last(se); - - if (cfs_rq->next == se) - __clear_buddies_next(se); - - if (cfs_rq->skip == se) - __clear_buddies_skip(se); -} - -static __always_inline void return_cfs_rq_runtime(struct cfs_rq *cfs_rq); - -static void -dequeue_entity(struct cfs_rq *cfs_rq, struct sched_entity *se, int flags) -{ - /* - * Update run-time statistics of the 'current'. - */ - update_curr(cfs_rq); - dequeue_entity_load_avg(cfs_rq, se); - - update_stats_dequeue(cfs_rq, se, flags); - - clear_buddies(cfs_rq, se); - - if (se != cfs_rq->curr) - __dequeue_entity(cfs_rq, se); - se->on_rq = 0; - account_entity_dequeue(cfs_rq, se); - - /* - * Normalize after update_curr(); which will also have moved - * min_vruntime if @se is the one holding it back. But before doing - * update_min_vruntime() again, which will discount @se's position and - * can move min_vruntime forward still more. - */ - if (!(flags & DEQUEUE_SLEEP)) - se->vruntime -= cfs_rq->min_vruntime; - - /* return excess runtime on last dequeue */ - return_cfs_rq_runtime(cfs_rq); - - update_cfs_shares(cfs_rq); - - /* - * Now advance min_vruntime if @se was the entity holding it back, - * except when: DEQUEUE_SAVE && !DEQUEUE_MOVE, in this case we'll be - * put back on, and if we advance min_vruntime, we'll be placed back - * further than we started -- ie. we'll be penalized. - */ - if ((flags & (DEQUEUE_SAVE | DEQUEUE_MOVE)) == DEQUEUE_SAVE) - update_min_vruntime(cfs_rq); -} - -/* - * Preempt the current task with a newly woken task if needed: - */ -static void -check_preempt_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr) -{ - unsigned long ideal_runtime, delta_exec; - struct sched_entity *se; - s64 delta; - - ideal_runtime = sched_slice(cfs_rq, curr); - delta_exec = curr->sum_exec_runtime - curr->prev_sum_exec_runtime; - if (delta_exec > ideal_runtime) { - resched_curr(rq_of(cfs_rq)); - /* - * The current task ran long enough, ensure it doesn't get - * re-elected due to buddy favours. - */ - clear_buddies(cfs_rq, curr); - return; - } - - /* - * Ensure that a task that missed wakeup preemption by a - * narrow margin doesn't have to wait for a full slice. - * This also mitigates buddy induced latencies under load. - */ - if (delta_exec < sysctl_sched_min_granularity) - return; - - se = __pick_first_entity(cfs_rq); - delta = curr->vruntime - se->vruntime; - - if (delta < 0) - return; - - if (delta > ideal_runtime) - resched_curr(rq_of(cfs_rq)); -} - -static void -set_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *se) -{ - /* 'current' is not kept within the tree. */ - if (se->on_rq) { - /* - * Any task has to be enqueued before it get to execute on - * a CPU. So account for the time it spent waiting on the - * runqueue. - */ - update_stats_wait_end(cfs_rq, se); - __dequeue_entity(cfs_rq, se); - update_load_avg(se, 1); - } - - update_stats_curr_start(cfs_rq, se); - cfs_rq->curr = se; - - /* - * Track our maximum slice length, if the CPU's load is at - * least twice that of our own weight (i.e. dont track it - * when there are only lesser-weight tasks around): - */ - if (schedstat_enabled() && rq_of(cfs_rq)->load.weight >= 2*se->load.weight) { - schedstat_set(se->statistics.slice_max, - max((u64)schedstat_val(se->statistics.slice_max), - se->sum_exec_runtime - se->prev_sum_exec_runtime)); - } - - se->prev_sum_exec_runtime = se->sum_exec_runtime; -} - -static int -wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se); - -/* - * Pick the next process, keeping these things in mind, in this order: - * 1) keep things fair between processes/task groups - * 2) pick the "next" process, since someone really wants that to run - * 3) pick the "last" process, for cache locality - * 4) do not run the "skip" process, if something else is available - */ -static struct sched_entity * -pick_next_entity(struct cfs_rq *cfs_rq, struct sched_entity *curr) -{ - struct sched_entity *left = __pick_first_entity(cfs_rq); - struct sched_entity *se; - - /* - * If curr is set we have to see if its left of the leftmost entity - * still in the tree, provided there was anything in the tree at all. - */ - if (!left || (curr && entity_before(curr, left))) - left = curr; - - se = left; /* ideally we run the leftmost entity */ - - /* - * Avoid running the skip buddy, if running something else can - * be done without getting too unfair. - */ - if (cfs_rq->skip == se) { - struct sched_entity *second; - - if (se == curr) { - second = __pick_first_entity(cfs_rq); - } else { - second = __pick_next_entity(se); - if (!second || (curr && entity_before(curr, second))) - second = curr; - } - - if (second && wakeup_preempt_entity(second, left) < 1) - se = second; - } - - /* - * Prefer last buddy, try to return the CPU to a preempted task. - */ - if (cfs_rq->last && wakeup_preempt_entity(cfs_rq->last, left) < 1) - se = cfs_rq->last; - - /* - * Someone really wants this to run. If it's not unfair, run it. - */ - if (cfs_rq->next && wakeup_preempt_entity(cfs_rq->next, left) < 1) - se = cfs_rq->next; - - clear_buddies(cfs_rq, se); - - return se; -} - -static bool check_cfs_rq_runtime(struct cfs_rq *cfs_rq); - -static void put_prev_entity(struct cfs_rq *cfs_rq, struct sched_entity *prev) -{ - /* - * If still on the runqueue then deactivate_task() - * was not called and update_curr() has to be done: - */ - if (prev->on_rq) - update_curr(cfs_rq); - - /* throttle cfs_rqs exceeding runtime */ - check_cfs_rq_runtime(cfs_rq); - - check_spread(cfs_rq, prev); - - if (prev->on_rq) { - update_stats_wait_start(cfs_rq, prev); - /* Put 'current' back into the tree. */ - __enqueue_entity(cfs_rq, prev); - /* in !on_rq case, update occurred at dequeue */ - update_load_avg(prev, 0); - } - cfs_rq->curr = NULL; -} - -static void -entity_tick(struct cfs_rq *cfs_rq, struct sched_entity *curr, int queued) -{ - /* - * Update run-time statistics of the 'current'. - */ - update_curr(cfs_rq); - - /* - * Ensure that runnable average is periodically updated. - */ - update_load_avg(curr, 1); - update_cfs_shares(cfs_rq); - -#ifdef CONFIG_SCHED_HRTICK - /* - * queued ticks are scheduled to match the slice, so don't bother - * validating it and just reschedule. - */ - if (queued) { - resched_curr(rq_of(cfs_rq)); - return; - } - /* - * don't let the period tick interfere with the hrtick preemption - */ - if (!sched_feat(DOUBLE_TICK) && - hrtimer_active(&rq_of(cfs_rq)->hrtick_timer)) - return; -#endif - - if (cfs_rq->nr_running > 1) - check_preempt_tick(cfs_rq, curr); -} - - -/************************************************** - * CFS bandwidth control machinery - */ - -#ifdef CONFIG_CFS_BANDWIDTH - -#ifdef HAVE_JUMP_LABEL -static struct static_key __cfs_bandwidth_used; - -static inline bool cfs_bandwidth_used(void) -{ - return static_key_false(&__cfs_bandwidth_used); -} - -void cfs_bandwidth_usage_inc(void) -{ - static_key_slow_inc(&__cfs_bandwidth_used); -} - -void cfs_bandwidth_usage_dec(void) -{ - static_key_slow_dec(&__cfs_bandwidth_used); -} -#else /* HAVE_JUMP_LABEL */ -static bool cfs_bandwidth_used(void) -{ - return true; -} - -void cfs_bandwidth_usage_inc(void) {} -void cfs_bandwidth_usage_dec(void) {} -#endif /* HAVE_JUMP_LABEL */ - -/* - * default period for cfs group bandwidth. - * default: 0.1s, units: nanoseconds - */ -static inline u64 default_cfs_period(void) -{ - return 100000000ULL; -} - -static inline u64 sched_cfs_bandwidth_slice(void) -{ - return (u64)sysctl_sched_cfs_bandwidth_slice * NSEC_PER_USEC; -} - -/* - * Replenish runtime according to assigned quota and update expiration time. - * We use sched_clock_cpu directly instead of rq->clock to avoid adding - * additional synchronization around rq->lock. - * - * requires cfs_b->lock - */ -void __refill_cfs_bandwidth_runtime(struct cfs_bandwidth *cfs_b) -{ - u64 now; - - if (cfs_b->quota == RUNTIME_INF) - return; - - now = sched_clock_cpu(smp_processor_id()); - cfs_b->runtime = cfs_b->quota; - cfs_b->runtime_expires = now + ktime_to_ns(cfs_b->period); -} - -static inline struct cfs_bandwidth *tg_cfs_bandwidth(struct task_group *tg) -{ - return &tg->cfs_bandwidth; -} - -/* rq->task_clock normalized against any time this cfs_rq has spent throttled */ -static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq) -{ - if (unlikely(cfs_rq->throttle_count)) - return cfs_rq->throttled_clock_task - cfs_rq->throttled_clock_task_time; - - return rq_clock_task(rq_of(cfs_rq)) - cfs_rq->throttled_clock_task_time; -} - -/* returns 0 on failure to allocate runtime */ -static int assign_cfs_rq_runtime(struct cfs_rq *cfs_rq) -{ - struct task_group *tg = cfs_rq->tg; - struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(tg); - u64 amount = 0, min_amount, expires; - - /* note: this is a positive sum as runtime_remaining <= 0 */ - min_amount = sched_cfs_bandwidth_slice() - cfs_rq->runtime_remaining; - - raw_spin_lock(&cfs_b->lock); - if (cfs_b->quota == RUNTIME_INF) - amount = min_amount; - else { - start_cfs_bandwidth(cfs_b); - - if (cfs_b->runtime > 0) { - amount = min(cfs_b->runtime, min_amount); - cfs_b->runtime -= amount; - cfs_b->idle = 0; - } - } - expires = cfs_b->runtime_expires; - raw_spin_unlock(&cfs_b->lock); - - cfs_rq->runtime_remaining += amount; - /* - * we may have advanced our local expiration to account for allowed - * spread between our sched_clock and the one on which runtime was - * issued. - */ - if ((s64)(expires - cfs_rq->runtime_expires) > 0) - cfs_rq->runtime_expires = expires; - - return cfs_rq->runtime_remaining > 0; -} - -/* - * Note: This depends on the synchronization provided by sched_clock and the - * fact that rq->clock snapshots this value. - */ -static void expire_cfs_rq_runtime(struct cfs_rq *cfs_rq) -{ - struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(cfs_rq->tg); - - /* if the deadline is ahead of our clock, nothing to do */ - if (likely((s64)(rq_clock(rq_of(cfs_rq)) - cfs_rq->runtime_expires) < 0)) - return; - - if (cfs_rq->runtime_remaining < 0) - return; - - /* - * If the local deadline has passed we have to consider the - * possibility that our sched_clock is 'fast' and the global deadline - * has not truly expired. - * - * Fortunately we can check determine whether this the case by checking - * whether the global deadline has advanced. It is valid to compare - * cfs_b->runtime_expires without any locks since we only care about - * exact equality, so a partial write will still work. - */ - - if (cfs_rq->runtime_expires != cfs_b->runtime_expires) { - /* extend local deadline, drift is bounded above by 2 ticks */ - cfs_rq->runtime_expires += TICK_NSEC; - } else { - /* global deadline is ahead, expiration has passed */ - cfs_rq->runtime_remaining = 0; - } -} - -static void __account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec) -{ - /* dock delta_exec before expiring quota (as it could span periods) */ - cfs_rq->runtime_remaining -= delta_exec; - expire_cfs_rq_runtime(cfs_rq); - - if (likely(cfs_rq->runtime_remaining > 0)) - return; - - /* - * if we're unable to extend our runtime we resched so that the active - * hierarchy can be throttled - */ - if (!assign_cfs_rq_runtime(cfs_rq) && likely(cfs_rq->curr)) - resched_curr(rq_of(cfs_rq)); -} - -static __always_inline -void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec) -{ - if (!cfs_bandwidth_used() || !cfs_rq->runtime_enabled) - return; - - __account_cfs_rq_runtime(cfs_rq, delta_exec); -} - -static inline int cfs_rq_throttled(struct cfs_rq *cfs_rq) -{ - return cfs_bandwidth_used() && cfs_rq->throttled; -} - -/* check whether cfs_rq, or any parent, is throttled */ -static inline int throttled_hierarchy(struct cfs_rq *cfs_rq) -{ - return cfs_bandwidth_used() && cfs_rq->throttle_count; -} - -/* - * Ensure that neither of the group entities corresponding to src_cpu or - * dest_cpu are members of a throttled hierarchy when performing group - * load-balance operations. - */ -static inline int throttled_lb_pair(struct task_group *tg, - int src_cpu, int dest_cpu) -{ - struct cfs_rq *src_cfs_rq, *dest_cfs_rq; - - src_cfs_rq = tg->cfs_rq[src_cpu]; - dest_cfs_rq = tg->cfs_rq[dest_cpu]; - - return throttled_hierarchy(src_cfs_rq) || - throttled_hierarchy(dest_cfs_rq); -} - -/* updated child weight may affect parent so we have to do this bottom up */ -static int tg_unthrottle_up(struct task_group *tg, void *data) -{ - struct rq *rq = data; - struct cfs_rq *cfs_rq = tg->cfs_rq[cpu_of(rq)]; - - cfs_rq->throttle_count--; - if (!cfs_rq->throttle_count) { - /* adjust cfs_rq_clock_task() */ - cfs_rq->throttled_clock_task_time += rq_clock_task(rq) - - cfs_rq->throttled_clock_task; - } - - return 0; -} - -static int tg_throttle_down(struct task_group *tg, void *data) -{ - struct rq *rq = data; - struct cfs_rq *cfs_rq = tg->cfs_rq[cpu_of(rq)]; - - /* group is entering throttled state, stop time */ - if (!cfs_rq->throttle_count) - cfs_rq->throttled_clock_task = rq_clock_task(rq); - cfs_rq->throttle_count++; - - return 0; -} - -static void throttle_cfs_rq(struct cfs_rq *cfs_rq) -{ - struct rq *rq = rq_of(cfs_rq); - struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(cfs_rq->tg); - struct sched_entity *se; - long task_delta, dequeue = 1; - bool empty; - - se = cfs_rq->tg->se[cpu_of(rq_of(cfs_rq))]; - - /* freeze hierarchy runnable averages while throttled */ - rcu_read_lock(); - walk_tg_tree_from(cfs_rq->tg, tg_throttle_down, tg_nop, (void *)rq); - rcu_read_unlock(); - - task_delta = cfs_rq->h_nr_running; - for_each_sched_entity(se) { - struct cfs_rq *qcfs_rq = cfs_rq_of(se); - /* throttled entity or throttle-on-deactivate */ - if (!se->on_rq) - break; - - if (dequeue) - dequeue_entity(qcfs_rq, se, DEQUEUE_SLEEP); - qcfs_rq->h_nr_running -= task_delta; - - if (qcfs_rq->load.weight) - dequeue = 0; - } - - if (!se) - sub_nr_running(rq, task_delta); - - cfs_rq->throttled = 1; - cfs_rq->throttled_clock = rq_clock(rq); - raw_spin_lock(&cfs_b->lock); - empty = list_empty(&cfs_b->throttled_cfs_rq); - - /* - * Add to the _head_ of the list, so that an already-started - * distribute_cfs_runtime will not see us - */ - list_add_rcu(&cfs_rq->throttled_list, &cfs_b->throttled_cfs_rq); - - /* - * If we're the first throttled task, make sure the bandwidth - * timer is running. - */ - if (empty) - start_cfs_bandwidth(cfs_b); - - raw_spin_unlock(&cfs_b->lock); -} - -void unthrottle_cfs_rq(struct cfs_rq *cfs_rq) -{ - struct rq *rq = rq_of(cfs_rq); - struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(cfs_rq->tg); - struct sched_entity *se; - int enqueue = 1; - long task_delta; - - se = cfs_rq->tg->se[cpu_of(rq)]; - - cfs_rq->throttled = 0; - - update_rq_clock(rq); - - raw_spin_lock(&cfs_b->lock); - cfs_b->throttled_time += rq_clock(rq) - cfs_rq->throttled_clock; - list_del_rcu(&cfs_rq->throttled_list); - raw_spin_unlock(&cfs_b->lock); - - /* update hierarchical throttle state */ - walk_tg_tree_from(cfs_rq->tg, tg_nop, tg_unthrottle_up, (void *)rq); - - if (!cfs_rq->load.weight) - return; - - task_delta = cfs_rq->h_nr_running; - for_each_sched_entity(se) { - if (se->on_rq) - enqueue = 0; - - cfs_rq = cfs_rq_of(se); - if (enqueue) - enqueue_entity(cfs_rq, se, ENQUEUE_WAKEUP); - cfs_rq->h_nr_running += task_delta; - - if (cfs_rq_throttled(cfs_rq)) - break; - } - - if (!se) - add_nr_running(rq, task_delta); - - /* determine whether we need to wake up potentially idle cpu */ - if (rq->curr == rq->idle && rq->cfs.nr_running) - resched_curr(rq); -} - -static u64 distribute_cfs_runtime(struct cfs_bandwidth *cfs_b, - u64 remaining, u64 expires) -{ - struct cfs_rq *cfs_rq; - u64 runtime; - u64 starting_runtime = remaining; - - rcu_read_lock(); - list_for_each_entry_rcu(cfs_rq, &cfs_b->throttled_cfs_rq, - throttled_list) { - struct rq *rq = rq_of(cfs_rq); - - raw_spin_lock(&rq->lock); - if (!cfs_rq_throttled(cfs_rq)) - goto next; - - runtime = -cfs_rq->runtime_remaining + 1; - if (runtime > remaining) - runtime = remaining; - remaining -= runtime; - - cfs_rq->runtime_remaining += runtime; - cfs_rq->runtime_expires = expires; - - /* we check whether we're throttled above */ - if (cfs_rq->runtime_remaining > 0) - unthrottle_cfs_rq(cfs_rq); - -next: - raw_spin_unlock(&rq->lock); - - if (!remaining) - break; - } - rcu_read_unlock(); - - return starting_runtime - remaining; -} - -/* - * Responsible for refilling a task_group's bandwidth and unthrottling its - * cfs_rqs as appropriate. If there has been no activity within the last - * period the timer is deactivated until scheduling resumes; cfs_b->idle is - * used to track this state. - */ -static int do_sched_cfs_period_timer(struct cfs_bandwidth *cfs_b, int overrun) -{ - u64 runtime, runtime_expires; - int throttled; - - /* no need to continue the timer with no bandwidth constraint */ - if (cfs_b->quota == RUNTIME_INF) - goto out_deactivate; - - throttled = !list_empty(&cfs_b->throttled_cfs_rq); - cfs_b->nr_periods += overrun; - - /* - * idle depends on !throttled (for the case of a large deficit), and if - * we're going inactive then everything else can be deferred - */ - if (cfs_b->idle && !throttled) - goto out_deactivate; - - __refill_cfs_bandwidth_runtime(cfs_b); - - if (!throttled) { - /* mark as potentially idle for the upcoming period */ - cfs_b->idle = 1; - return 0; - } - - /* account preceding periods in which throttling occurred */ - cfs_b->nr_throttled += overrun; - - runtime_expires = cfs_b->runtime_expires; - - /* - * This check is repeated as we are holding onto the new bandwidth while - * we unthrottle. This can potentially race with an unthrottled group - * trying to acquire new bandwidth from the global pool. This can result - * in us over-using our runtime if it is all used during this loop, but - * only by limited amounts in that extreme case. - */ - while (throttled && cfs_b->runtime > 0) { - runtime = cfs_b->runtime; - raw_spin_unlock(&cfs_b->lock); - /* we can't nest cfs_b->lock while distributing bandwidth */ - runtime = distribute_cfs_runtime(cfs_b, runtime, - runtime_expires); - raw_spin_lock(&cfs_b->lock); - - throttled = !list_empty(&cfs_b->throttled_cfs_rq); - - cfs_b->runtime -= min(runtime, cfs_b->runtime); - } - - /* - * While we are ensured activity in the period following an - * unthrottle, this also covers the case in which the new bandwidth is - * insufficient to cover the existing bandwidth deficit. (Forcing the - * timer to remain active while there are any throttled entities.) - */ - cfs_b->idle = 0; - - return 0; - -out_deactivate: - return 1; -} - -/* a cfs_rq won't donate quota below this amount */ -static const u64 min_cfs_rq_runtime = 1 * NSEC_PER_MSEC; -/* minimum remaining period time to redistribute slack quota */ -static const u64 min_bandwidth_expiration = 2 * NSEC_PER_MSEC; -/* how long we wait to gather additional slack before distributing */ -static const u64 cfs_bandwidth_slack_period = 5 * NSEC_PER_MSEC; - -/* - * Are we near the end of the current quota period? - * - * Requires cfs_b->lock for hrtimer_expires_remaining to be safe against the - * hrtimer base being cleared by hrtimer_start. In the case of - * migrate_hrtimers, base is never cleared, so we are fine. - */ -static int runtime_refresh_within(struct cfs_bandwidth *cfs_b, u64 min_expire) -{ - struct hrtimer *refresh_timer = &cfs_b->period_timer; - u64 remaining; - - /* if the call-back is running a quota refresh is already occurring */ - if (hrtimer_callback_running(refresh_timer)) - return 1; - - /* is a quota refresh about to occur? */ - remaining = ktime_to_ns(hrtimer_expires_remaining(refresh_timer)); - if (remaining < min_expire) - return 1; - - return 0; -} - -static void start_cfs_slack_bandwidth(struct cfs_bandwidth *cfs_b) -{ - u64 min_left = cfs_bandwidth_slack_period + min_bandwidth_expiration; - - /* if there's a quota refresh soon don't bother with slack */ - if (runtime_refresh_within(cfs_b, min_left)) - return; - - hrtimer_start(&cfs_b->slack_timer, - ns_to_ktime(cfs_bandwidth_slack_period), - HRTIMER_MODE_REL); -} - -/* we know any runtime found here is valid as update_curr() precedes return */ -static void __return_cfs_rq_runtime(struct cfs_rq *cfs_rq) -{ - struct cfs_bandwidth *cfs_b = tg_cfs_bandwidth(cfs_rq->tg); - s64 slack_runtime = cfs_rq->runtime_remaining - min_cfs_rq_runtime; - - if (slack_runtime <= 0) - return; - - raw_spin_lock(&cfs_b->lock); - if (cfs_b->quota != RUNTIME_INF && - cfs_rq->runtime_expires == cfs_b->runtime_expires) { - cfs_b->runtime += slack_runtime; - - /* we are under rq->lock, defer unthrottling using a timer */ - if (cfs_b->runtime > sched_cfs_bandwidth_slice() && - !list_empty(&cfs_b->throttled_cfs_rq)) - start_cfs_slack_bandwidth(cfs_b); - } - raw_spin_unlock(&cfs_b->lock); - - /* even if it's not valid for return we don't want to try again */ - cfs_rq->runtime_remaining -= slack_runtime; -} - -static __always_inline void return_cfs_rq_runtime(struct cfs_rq *cfs_rq) -{ - if (!cfs_bandwidth_used()) - return; - - if (!cfs_rq->runtime_enabled || cfs_rq->nr_running) - return; - - __return_cfs_rq_runtime(cfs_rq); -} - -/* - * This is done with a timer (instead of inline with bandwidth return) since - * it's necessary to juggle rq->locks to unthrottle their respective cfs_rqs. - */ -static void do_sched_cfs_slack_timer(struct cfs_bandwidth *cfs_b) -{ - u64 runtime = 0, slice = sched_cfs_bandwidth_slice(); - u64 expires; - - /* confirm we're still not at a refresh boundary */ - raw_spin_lock(&cfs_b->lock); - if (runtime_refresh_within(cfs_b, min_bandwidth_expiration)) { - raw_spin_unlock(&cfs_b->lock); - return; - } - - if (cfs_b->quota != RUNTIME_INF && cfs_b->runtime > slice) - runtime = cfs_b->runtime; - - expires = cfs_b->runtime_expires; - raw_spin_unlock(&cfs_b->lock); - - if (!runtime) - return; - - runtime = distribute_cfs_runtime(cfs_b, runtime, expires); - - raw_spin_lock(&cfs_b->lock); - if (expires == cfs_b->runtime_expires) - cfs_b->runtime -= min(runtime, cfs_b->runtime); - raw_spin_unlock(&cfs_b->lock); -} - -/* - * When a group wakes up we want to make sure that its quota is not already - * expired/exceeded, otherwise it may be allowed to steal additional ticks of - * runtime as update_curr() throttling can not not trigger until it's on-rq. - */ -static void check_enqueue_throttle(struct cfs_rq *cfs_rq) -{ - if (!cfs_bandwidth_used()) - return; - - /* an active group must be handled by the update_curr()->put() path */ - if (!cfs_rq->runtime_enabled || cfs_rq->curr) - return; - - /* ensure the group is not already throttled */ - if (cfs_rq_throttled(cfs_rq)) - return; - - /* update runtime allocation */ - account_cfs_rq_runtime(cfs_rq, 0); - if (cfs_rq->runtime_remaining <= 0) - throttle_cfs_rq(cfs_rq); -} - -static void sync_throttle(struct task_group *tg, int cpu) -{ - struct cfs_rq *pcfs_rq, *cfs_rq; - - if (!cfs_bandwidth_used()) - return; - - if (!tg->parent) - return; - - cfs_rq = tg->cfs_rq[cpu]; - pcfs_rq = tg->parent->cfs_rq[cpu]; - - cfs_rq->throttle_count = pcfs_rq->throttle_count; - cfs_rq->throttled_clock_task = rq_clock_task(cpu_rq(cpu)); -} - -/* conditionally throttle active cfs_rq's from put_prev_entity() */ -static bool check_cfs_rq_runtime(struct cfs_rq *cfs_rq) -{ - if (!cfs_bandwidth_used()) - return false; - - if (likely(!cfs_rq->runtime_enabled || cfs_rq->runtime_remaining > 0)) - return false; - - /* - * it's possible for a throttled entity to be forced into a running - * state (e.g. set_curr_task), in this case we're finished. - */ - if (cfs_rq_throttled(cfs_rq)) - return true; - - throttle_cfs_rq(cfs_rq); - return true; -} - -static enum hrtimer_restart sched_cfs_slack_timer(struct hrtimer *timer) -{ - struct cfs_bandwidth *cfs_b = - container_of(timer, struct cfs_bandwidth, slack_timer); - - do_sched_cfs_slack_timer(cfs_b); - - return HRTIMER_NORESTART; -} - -static enum hrtimer_restart sched_cfs_period_timer(struct hrtimer *timer) -{ - struct cfs_bandwidth *cfs_b = - container_of(timer, struct cfs_bandwidth, period_timer); - int overrun; - int idle = 0; - - raw_spin_lock(&cfs_b->lock); - for (;;) { - overrun = hrtimer_forward_now(timer, cfs_b->period); - if (!overrun) - break; - - idle = do_sched_cfs_period_timer(cfs_b, overrun); - } - if (idle) - cfs_b->period_active = 0; - raw_spin_unlock(&cfs_b->lock); - - return idle ? HRTIMER_NORESTART : HRTIMER_RESTART; -} - -void init_cfs_bandwidth(struct cfs_bandwidth *cfs_b) -{ - raw_spin_lock_init(&cfs_b->lock); - cfs_b->runtime = 0; - cfs_b->quota = RUNTIME_INF; - cfs_b->period = ns_to_ktime(default_cfs_period()); - - INIT_LIST_HEAD(&cfs_b->throttled_cfs_rq); - hrtimer_init(&cfs_b->period_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS_PINNED); - cfs_b->period_timer.function = sched_cfs_period_timer; - hrtimer_init(&cfs_b->slack_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - cfs_b->slack_timer.function = sched_cfs_slack_timer; -} - -static void init_cfs_rq_runtime(struct cfs_rq *cfs_rq) -{ - cfs_rq->runtime_enabled = 0; - INIT_LIST_HEAD(&cfs_rq->throttled_list); -} - -void start_cfs_bandwidth(struct cfs_bandwidth *cfs_b) -{ - lockdep_assert_held(&cfs_b->lock); - - if (!cfs_b->period_active) { - cfs_b->period_active = 1; - hrtimer_forward_now(&cfs_b->period_timer, cfs_b->period); - hrtimer_start_expires(&cfs_b->period_timer, HRTIMER_MODE_ABS_PINNED); - } -} - -static void destroy_cfs_bandwidth(struct cfs_bandwidth *cfs_b) -{ - /* init_cfs_bandwidth() was not called */ - if (!cfs_b->throttled_cfs_rq.next) - return; - - hrtimer_cancel(&cfs_b->period_timer); - hrtimer_cancel(&cfs_b->slack_timer); -} - -static void __maybe_unused update_runtime_enabled(struct rq *rq) -{ - struct cfs_rq *cfs_rq; - - for_each_leaf_cfs_rq(rq, cfs_rq) { - struct cfs_bandwidth *cfs_b = &cfs_rq->tg->cfs_bandwidth; - - raw_spin_lock(&cfs_b->lock); - cfs_rq->runtime_enabled = cfs_b->quota != RUNTIME_INF; - raw_spin_unlock(&cfs_b->lock); - } -} - -static void __maybe_unused unthrottle_offline_cfs_rqs(struct rq *rq) -{ - struct cfs_rq *cfs_rq; - - for_each_leaf_cfs_rq(rq, cfs_rq) { - if (!cfs_rq->runtime_enabled) - continue; - - /* - * clock_task is not advancing so we just need to make sure - * there's some valid quota amount - */ - cfs_rq->runtime_remaining = 1; - /* - * Offline rq is schedulable till cpu is completely disabled - * in take_cpu_down(), so we prevent new cfs throttling here. - */ - cfs_rq->runtime_enabled = 0; - - if (cfs_rq_throttled(cfs_rq)) - unthrottle_cfs_rq(cfs_rq); - } -} - -#else /* CONFIG_CFS_BANDWIDTH */ -static inline u64 cfs_rq_clock_task(struct cfs_rq *cfs_rq) -{ - return rq_clock_task(rq_of(cfs_rq)); -} - -static void account_cfs_rq_runtime(struct cfs_rq *cfs_rq, u64 delta_exec) {} -static bool check_cfs_rq_runtime(struct cfs_rq *cfs_rq) { return false; } -static void check_enqueue_throttle(struct cfs_rq *cfs_rq) {} -static inline void sync_throttle(struct task_group *tg, int cpu) {} -static __always_inline void return_cfs_rq_runtime(struct cfs_rq *cfs_rq) {} - -static inline int cfs_rq_throttled(struct cfs_rq *cfs_rq) -{ - return 0; -} - -static inline int throttled_hierarchy(struct cfs_rq *cfs_rq) -{ - return 0; -} - -static inline int throttled_lb_pair(struct task_group *tg, - int src_cpu, int dest_cpu) -{ - return 0; -} - -void init_cfs_bandwidth(struct cfs_bandwidth *cfs_b) {} - -#ifdef CONFIG_FAIR_GROUP_SCHED -static void init_cfs_rq_runtime(struct cfs_rq *cfs_rq) {} -#endif - -static inline struct cfs_bandwidth *tg_cfs_bandwidth(struct task_group *tg) -{ - return NULL; -} -static inline void destroy_cfs_bandwidth(struct cfs_bandwidth *cfs_b) {} -static inline void update_runtime_enabled(struct rq *rq) {} -static inline void unthrottle_offline_cfs_rqs(struct rq *rq) {} - -#endif /* CONFIG_CFS_BANDWIDTH */ - -/************************************************** - * CFS operations on tasks: - */ - -#ifdef CONFIG_SCHED_HRTICK -static void hrtick_start_fair(struct rq *rq, struct task_struct *p) -{ - struct sched_entity *se = &p->se; - struct cfs_rq *cfs_rq = cfs_rq_of(se); - - SCHED_WARN_ON(task_rq(p) != rq); - - if (rq->cfs.h_nr_running > 1) { - u64 slice = sched_slice(cfs_rq, se); - u64 ran = se->sum_exec_runtime - se->prev_sum_exec_runtime; - s64 delta = slice - ran; - - if (delta < 0) { - if (rq->curr == p) - resched_curr(rq); - return; - } - hrtick_start(rq, delta); - } -} - -/* - * called from enqueue/dequeue and updates the hrtick when the - * current task is from our class and nr_running is low enough - * to matter. - */ -static void hrtick_update(struct rq *rq) -{ - struct task_struct *curr = rq->curr; - - if (!hrtick_enabled(rq) || curr->sched_class != &fair_sched_class) - return; - - if (cfs_rq_of(&curr->se)->nr_running < sched_nr_latency) - hrtick_start_fair(rq, curr); -} -#else /* !CONFIG_SCHED_HRTICK */ -static inline void -hrtick_start_fair(struct rq *rq, struct task_struct *p) -{ -} - -static inline void hrtick_update(struct rq *rq) -{ -} -#endif - -/* - * The enqueue_task method is called before nr_running is - * increased. Here we update the fair scheduling stats and - * then put the task into the rbtree: - */ -static void -enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags) -{ - struct cfs_rq *cfs_rq; - struct sched_entity *se = &p->se; - - /* - * If in_iowait is set, the code below may not trigger any cpufreq - * utilization updates, so do it here explicitly with the IOWAIT flag - * passed. - */ - if (p->in_iowait) - cpufreq_update_this_cpu(rq, SCHED_CPUFREQ_IOWAIT); - - for_each_sched_entity(se) { - if (se->on_rq) - break; - cfs_rq = cfs_rq_of(se); - enqueue_entity(cfs_rq, se, flags); - - /* - * end evaluation on encountering a throttled cfs_rq - * - * note: in the case of encountering a throttled cfs_rq we will - * post the final h_nr_running increment below. - */ - if (cfs_rq_throttled(cfs_rq)) - break; - cfs_rq->h_nr_running++; - - flags = ENQUEUE_WAKEUP; - } - - for_each_sched_entity(se) { - cfs_rq = cfs_rq_of(se); - cfs_rq->h_nr_running++; - - if (cfs_rq_throttled(cfs_rq)) - break; - - update_load_avg(se, 1); - update_cfs_shares(cfs_rq); - } - - if (!se) - add_nr_running(rq, 1); - - hrtick_update(rq); -} - -static void set_next_buddy(struct sched_entity *se); - -/* - * The dequeue_task method is called before nr_running is - * decreased. We remove the task from the rbtree and - * update the fair scheduling stats: - */ -static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int flags) -{ - struct cfs_rq *cfs_rq; - struct sched_entity *se = &p->se; - int task_sleep = flags & DEQUEUE_SLEEP; - - for_each_sched_entity(se) { - cfs_rq = cfs_rq_of(se); - dequeue_entity(cfs_rq, se, flags); - - /* - * end evaluation on encountering a throttled cfs_rq - * - * note: in the case of encountering a throttled cfs_rq we will - * post the final h_nr_running decrement below. - */ - if (cfs_rq_throttled(cfs_rq)) - break; - cfs_rq->h_nr_running--; - - /* Don't dequeue parent if it has other entities besides us */ - if (cfs_rq->load.weight) { - /* Avoid re-evaluating load for this entity: */ - se = parent_entity(se); - /* - * Bias pick_next to pick a task from this cfs_rq, as - * p is sleeping when it is within its sched_slice. - */ - if (task_sleep && se && !throttled_hierarchy(cfs_rq)) - set_next_buddy(se); - break; - } - flags |= DEQUEUE_SLEEP; - } - - for_each_sched_entity(se) { - cfs_rq = cfs_rq_of(se); - cfs_rq->h_nr_running--; - - if (cfs_rq_throttled(cfs_rq)) - break; - - update_load_avg(se, 1); - update_cfs_shares(cfs_rq); - } - - if (!se) - sub_nr_running(rq, 1); - - hrtick_update(rq); -} - -#ifdef CONFIG_SMP - -/* Working cpumask for: load_balance, load_balance_newidle. */ -DEFINE_PER_CPU(cpumask_var_t, load_balance_mask); -DEFINE_PER_CPU(cpumask_var_t, select_idle_mask); - -#ifdef CONFIG_NO_HZ_COMMON -/* - * per rq 'load' arrray crap; XXX kill this. - */ - -/* - * The exact cpuload calculated at every tick would be: - * - * load' = (1 - 1/2^i) * load + (1/2^i) * cur_load - * - * If a cpu misses updates for n ticks (as it was idle) and update gets - * called on the n+1-th tick when cpu may be busy, then we have: - * - * load_n = (1 - 1/2^i)^n * load_0 - * load_n+1 = (1 - 1/2^i) * load_n + (1/2^i) * cur_load - * - * decay_load_missed() below does efficient calculation of - * - * load' = (1 - 1/2^i)^n * load - * - * Because x^(n+m) := x^n * x^m we can decompose any x^n in power-of-2 factors. - * This allows us to precompute the above in said factors, thereby allowing the - * reduction of an arbitrary n in O(log_2 n) steps. (See also - * fixed_power_int()) - * - * The calculation is approximated on a 128 point scale. - */ -#define DEGRADE_SHIFT 7 - -static const u8 degrade_zero_ticks[CPU_LOAD_IDX_MAX] = {0, 8, 32, 64, 128}; -static const u8 degrade_factor[CPU_LOAD_IDX_MAX][DEGRADE_SHIFT + 1] = { - { 0, 0, 0, 0, 0, 0, 0, 0 }, - { 64, 32, 8, 0, 0, 0, 0, 0 }, - { 96, 72, 40, 12, 1, 0, 0, 0 }, - { 112, 98, 75, 43, 15, 1, 0, 0 }, - { 120, 112, 98, 76, 45, 16, 2, 0 } -}; - -/* - * Update cpu_load for any missed ticks, due to tickless idle. The backlog - * would be when CPU is idle and so we just decay the old load without - * adding any new load. - */ -static unsigned long -decay_load_missed(unsigned long load, unsigned long missed_updates, int idx) -{ - int j = 0; - - if (!missed_updates) - return load; - - if (missed_updates >= degrade_zero_ticks[idx]) - return 0; - - if (idx == 1) - return load >> missed_updates; - - while (missed_updates) { - if (missed_updates % 2) - load = (load * degrade_factor[idx][j]) >> DEGRADE_SHIFT; - - missed_updates >>= 1; - j++; - } - return load; -} -#endif /* CONFIG_NO_HZ_COMMON */ - -/** - * __cpu_load_update - update the rq->cpu_load[] statistics - * @this_rq: The rq to update statistics for - * @this_load: The current load - * @pending_updates: The number of missed updates - * - * Update rq->cpu_load[] statistics. This function is usually called every - * scheduler tick (TICK_NSEC). - * - * This function computes a decaying average: - * - * load[i]' = (1 - 1/2^i) * load[i] + (1/2^i) * load - * - * Because of NOHZ it might not get called on every tick which gives need for - * the @pending_updates argument. - * - * load[i]_n = (1 - 1/2^i) * load[i]_n-1 + (1/2^i) * load_n-1 - * = A * load[i]_n-1 + B ; A := (1 - 1/2^i), B := (1/2^i) * load - * = A * (A * load[i]_n-2 + B) + B - * = A * (A * (A * load[i]_n-3 + B) + B) + B - * = A^3 * load[i]_n-3 + (A^2 + A + 1) * B - * = A^n * load[i]_0 + (A^(n-1) + A^(n-2) + ... + 1) * B - * = A^n * load[i]_0 + ((1 - A^n) / (1 - A)) * B - * = (1 - 1/2^i)^n * (load[i]_0 - load) + load - * - * In the above we've assumed load_n := load, which is true for NOHZ_FULL as - * any change in load would have resulted in the tick being turned back on. - * - * For regular NOHZ, this reduces to: - * - * load[i]_n = (1 - 1/2^i)^n * load[i]_0 - * - * see decay_load_misses(). For NOHZ_FULL we get to subtract and add the extra - * term. - */ -static void cpu_load_update(struct rq *this_rq, unsigned long this_load, - unsigned long pending_updates) -{ - unsigned long __maybe_unused tickless_load = this_rq->cpu_load[0]; - int i, scale; - - this_rq->nr_load_updates++; - - /* Update our load: */ - this_rq->cpu_load[0] = this_load; /* Fasttrack for idx 0 */ - for (i = 1, scale = 2; i < CPU_LOAD_IDX_MAX; i++, scale += scale) { - unsigned long old_load, new_load; - - /* scale is effectively 1 << i now, and >> i divides by scale */ - - old_load = this_rq->cpu_load[i]; -#ifdef CONFIG_NO_HZ_COMMON - old_load = decay_load_missed(old_load, pending_updates - 1, i); - if (tickless_load) { - old_load -= decay_load_missed(tickless_load, pending_updates - 1, i); - /* - * old_load can never be a negative value because a - * decayed tickless_load cannot be greater than the - * original tickless_load. - */ - old_load += tickless_load; - } -#endif - new_load = this_load; - /* - * Round up the averaging division if load is increasing. This - * prevents us from getting stuck on 9 if the load is 10, for - * example. - */ - if (new_load > old_load) - new_load += scale - 1; - - this_rq->cpu_load[i] = (old_load * (scale - 1) + new_load) >> i; - } - - sched_avg_update(this_rq); -} - -/* Used instead of source_load when we know the type == 0 */ -static unsigned long weighted_cpuload(const int cpu) -{ - return cfs_rq_runnable_load_avg(&cpu_rq(cpu)->cfs); -} - -#ifdef CONFIG_NO_HZ_COMMON -/* - * There is no sane way to deal with nohz on smp when using jiffies because the - * cpu doing the jiffies update might drift wrt the cpu doing the jiffy reading - * causing off-by-one errors in observed deltas; {0,2} instead of {1,1}. - * - * Therefore we need to avoid the delta approach from the regular tick when - * possible since that would seriously skew the load calculation. This is why we - * use cpu_load_update_periodic() for CPUs out of nohz. However we'll rely on - * jiffies deltas for updates happening while in nohz mode (idle ticks, idle - * loop exit, nohz_idle_balance, nohz full exit...) - * - * This means we might still be one tick off for nohz periods. - */ - -static void cpu_load_update_nohz(struct rq *this_rq, - unsigned long curr_jiffies, - unsigned long load) -{ - unsigned long pending_updates; - - pending_updates = curr_jiffies - this_rq->last_load_update_tick; - if (pending_updates) { - this_rq->last_load_update_tick = curr_jiffies; - /* - * In the regular NOHZ case, we were idle, this means load 0. - * In the NOHZ_FULL case, we were non-idle, we should consider - * its weighted load. - */ - cpu_load_update(this_rq, load, pending_updates); - } -} - -/* - * Called from nohz_idle_balance() to update the load ratings before doing the - * idle balance. - */ -static void cpu_load_update_idle(struct rq *this_rq) -{ - /* - * bail if there's load or we're actually up-to-date. - */ - if (weighted_cpuload(cpu_of(this_rq))) - return; - - cpu_load_update_nohz(this_rq, READ_ONCE(jiffies), 0); -} - -/* - * Record CPU load on nohz entry so we know the tickless load to account - * on nohz exit. cpu_load[0] happens then to be updated more frequently - * than other cpu_load[idx] but it should be fine as cpu_load readers - * shouldn't rely into synchronized cpu_load[*] updates. - */ -void cpu_load_update_nohz_start(void) -{ - struct rq *this_rq = this_rq(); - - /* - * This is all lockless but should be fine. If weighted_cpuload changes - * concurrently we'll exit nohz. And cpu_load write can race with - * cpu_load_update_idle() but both updater would be writing the same. - */ - this_rq->cpu_load[0] = weighted_cpuload(cpu_of(this_rq)); -} - -/* - * Account the tickless load in the end of a nohz frame. - */ -void cpu_load_update_nohz_stop(void) -{ - unsigned long curr_jiffies = READ_ONCE(jiffies); - struct rq *this_rq = this_rq(); - unsigned long load; - - if (curr_jiffies == this_rq->last_load_update_tick) - return; - - load = weighted_cpuload(cpu_of(this_rq)); - raw_spin_lock(&this_rq->lock); - update_rq_clock(this_rq); - cpu_load_update_nohz(this_rq, curr_jiffies, load); - raw_spin_unlock(&this_rq->lock); -} -#else /* !CONFIG_NO_HZ_COMMON */ -static inline void cpu_load_update_nohz(struct rq *this_rq, - unsigned long curr_jiffies, - unsigned long load) { } -#endif /* CONFIG_NO_HZ_COMMON */ - -static void cpu_load_update_periodic(struct rq *this_rq, unsigned long load) -{ -#ifdef CONFIG_NO_HZ_COMMON - /* See the mess around cpu_load_update_nohz(). */ - this_rq->last_load_update_tick = READ_ONCE(jiffies); -#endif - cpu_load_update(this_rq, load, 1); -} - -/* - * Called from scheduler_tick() - */ -void cpu_load_update_active(struct rq *this_rq) -{ - unsigned long load = weighted_cpuload(cpu_of(this_rq)); - - if (tick_nohz_tick_stopped()) - cpu_load_update_nohz(this_rq, READ_ONCE(jiffies), load); - else - cpu_load_update_periodic(this_rq, load); -} - -/* - * Return a low guess at the load of a migration-source cpu weighted - * according to the scheduling class and "nice" value. - * - * We want to under-estimate the load of migration sources, to - * balance conservatively. - */ -static unsigned long source_load(int cpu, int type) -{ - struct rq *rq = cpu_rq(cpu); - unsigned long total = weighted_cpuload(cpu); - - if (type == 0 || !sched_feat(LB_BIAS)) - return total; - - return min(rq->cpu_load[type-1], total); -} - -/* - * Return a high guess at the load of a migration-target cpu weighted - * according to the scheduling class and "nice" value. - */ -static unsigned long target_load(int cpu, int type) -{ - struct rq *rq = cpu_rq(cpu); - unsigned long total = weighted_cpuload(cpu); - - if (type == 0 || !sched_feat(LB_BIAS)) - return total; - - return max(rq->cpu_load[type-1], total); -} - -static unsigned long capacity_of(int cpu) -{ - return cpu_rq(cpu)->cpu_capacity; -} - -static unsigned long capacity_orig_of(int cpu) -{ - return cpu_rq(cpu)->cpu_capacity_orig; -} - -static unsigned long cpu_avg_load_per_task(int cpu) -{ - struct rq *rq = cpu_rq(cpu); - unsigned long nr_running = READ_ONCE(rq->cfs.h_nr_running); - unsigned long load_avg = weighted_cpuload(cpu); - - if (nr_running) - return load_avg / nr_running; - - return 0; -} - -#ifdef CONFIG_FAIR_GROUP_SCHED -/* - * effective_load() calculates the load change as seen from the root_task_group - * - * Adding load to a group doesn't make a group heavier, but can cause movement - * of group shares between cpus. Assuming the shares were perfectly aligned one - * can calculate the shift in shares. - * - * Calculate the effective load difference if @wl is added (subtracted) to @tg - * on this @cpu and results in a total addition (subtraction) of @wg to the - * total group weight. - * - * Given a runqueue weight distribution (rw_i) we can compute a shares - * distribution (s_i) using: - * - * s_i = rw_i / \Sum rw_j (1) - * - * Suppose we have 4 CPUs and our @tg is a direct child of the root group and - * has 7 equal weight tasks, distributed as below (rw_i), with the resulting - * shares distribution (s_i): - * - * rw_i = { 2, 4, 1, 0 } - * s_i = { 2/7, 4/7, 1/7, 0 } - * - * As per wake_affine() we're interested in the load of two CPUs (the CPU the - * task used to run on and the CPU the waker is running on), we need to - * compute the effect of waking a task on either CPU and, in case of a sync - * wakeup, compute the effect of the current task going to sleep. - * - * So for a change of @wl to the local @cpu with an overall group weight change - * of @wl we can compute the new shares distribution (s'_i) using: - * - * s'_i = (rw_i + @wl) / (@wg + \Sum rw_j) (2) - * - * Suppose we're interested in CPUs 0 and 1, and want to compute the load - * differences in waking a task to CPU 0. The additional task changes the - * weight and shares distributions like: - * - * rw'_i = { 3, 4, 1, 0 } - * s'_i = { 3/8, 4/8, 1/8, 0 } - * - * We can then compute the difference in effective weight by using: - * - * dw_i = S * (s'_i - s_i) (3) - * - * Where 'S' is the group weight as seen by its parent. - * - * Therefore the effective change in loads on CPU 0 would be 5/56 (3/8 - 2/7) - * times the weight of the group. The effect on CPU 1 would be -4/56 (4/8 - - * 4/7) times the weight of the group. - */ -static long effective_load(struct task_group *tg, int cpu, long wl, long wg) -{ - struct sched_entity *se = tg->se[cpu]; - - if (!tg->parent) /* the trivial, non-cgroup case */ - return wl; - - for_each_sched_entity(se) { - struct cfs_rq *cfs_rq = se->my_q; - long W, w = cfs_rq_load_avg(cfs_rq); - - tg = cfs_rq->tg; - - /* - * W = @wg + \Sum rw_j - */ - W = wg + atomic_long_read(&tg->load_avg); - - /* Ensure \Sum rw_j >= rw_i */ - W -= cfs_rq->tg_load_avg_contrib; - W += w; - - /* - * w = rw_i + @wl - */ - w += wl; - - /* - * wl = S * s'_i; see (2) - */ - if (W > 0 && w < W) - wl = (w * (long)scale_load_down(tg->shares)) / W; - else - wl = scale_load_down(tg->shares); - - /* - * Per the above, wl is the new se->load.weight value; since - * those are clipped to [MIN_SHARES, ...) do so now. See - * calc_cfs_shares(). - */ - if (wl < MIN_SHARES) - wl = MIN_SHARES; - - /* - * wl = dw_i = S * (s'_i - s_i); see (3) - */ - wl -= se->avg.load_avg; - - /* - * Recursively apply this logic to all parent groups to compute - * the final effective load change on the root group. Since - * only the @tg group gets extra weight, all parent groups can - * only redistribute existing shares. @wl is the shift in shares - * resulting from this level per the above. - */ - wg = 0; - } - - return wl; -} -#else - -static long effective_load(struct task_group *tg, int cpu, long wl, long wg) -{ - return wl; -} - -#endif - -static void record_wakee(struct task_struct *p) -{ - /* - * Only decay a single time; tasks that have less then 1 wakeup per - * jiffy will not have built up many flips. - */ - if (time_after(jiffies, current->wakee_flip_decay_ts + HZ)) { - current->wakee_flips >>= 1; - current->wakee_flip_decay_ts = jiffies; - } - - if (current->last_wakee != p) { - current->last_wakee = p; - current->wakee_flips++; - } -} - -/* - * Detect M:N waker/wakee relationships via a switching-frequency heuristic. - * - * A waker of many should wake a different task than the one last awakened - * at a frequency roughly N times higher than one of its wakees. - * - * In order to determine whether we should let the load spread vs consolidating - * to shared cache, we look for a minimum 'flip' frequency of llc_size in one - * partner, and a factor of lls_size higher frequency in the other. - * - * With both conditions met, we can be relatively sure that the relationship is - * non-monogamous, with partner count exceeding socket size. - * - * Waker/wakee being client/server, worker/dispatcher, interrupt source or - * whatever is irrelevant, spread criteria is apparent partner count exceeds - * socket size. - */ -static int wake_wide(struct task_struct *p) -{ - unsigned int master = current->wakee_flips; - unsigned int slave = p->wakee_flips; - int factor = this_cpu_read(sd_llc_size); - - if (master < slave) - swap(master, slave); - if (slave < factor || master < slave * factor) - return 0; - return 1; -} - -static int wake_affine(struct sched_domain *sd, struct task_struct *p, - int prev_cpu, int sync) -{ - s64 this_load, load; - s64 this_eff_load, prev_eff_load; - int idx, this_cpu; - struct task_group *tg; - unsigned long weight; - int balanced; - - idx = sd->wake_idx; - this_cpu = smp_processor_id(); - load = source_load(prev_cpu, idx); - this_load = target_load(this_cpu, idx); - - /* - * If sync wakeup then subtract the (maximum possible) - * effect of the currently running task from the load - * of the current CPU: - */ - if (sync) { - tg = task_group(current); - weight = current->se.avg.load_avg; - - this_load += effective_load(tg, this_cpu, -weight, -weight); - load += effective_load(tg, prev_cpu, 0, -weight); - } - - tg = task_group(p); - weight = p->se.avg.load_avg; - - /* - * In low-load situations, where prev_cpu is idle and this_cpu is idle - * due to the sync cause above having dropped this_load to 0, we'll - * always have an imbalance, but there's really nothing you can do - * about that, so that's good too. - * - * Otherwise check if either cpus are near enough in load to allow this - * task to be woken on this_cpu. - */ - this_eff_load = 100; - this_eff_load *= capacity_of(prev_cpu); - - prev_eff_load = 100 + (sd->imbalance_pct - 100) / 2; - prev_eff_load *= capacity_of(this_cpu); - - if (this_load > 0) { - this_eff_load *= this_load + - effective_load(tg, this_cpu, weight, weight); - - prev_eff_load *= load + effective_load(tg, prev_cpu, 0, weight); - } - - balanced = this_eff_load <= prev_eff_load; - - schedstat_inc(p->se.statistics.nr_wakeups_affine_attempts); - - if (!balanced) - return 0; - - schedstat_inc(sd->ttwu_move_affine); - schedstat_inc(p->se.statistics.nr_wakeups_affine); - - return 1; -} - -/* - * find_idlest_group finds and returns the least busy CPU group within the - * domain. - */ -static struct sched_group * -find_idlest_group(struct sched_domain *sd, struct task_struct *p, - int this_cpu, int sd_flag) -{ - struct sched_group *idlest = NULL, *group = sd->groups; - unsigned long min_load = ULONG_MAX, this_load = 0; - int load_idx = sd->forkexec_idx; - int imbalance = 100 + (sd->imbalance_pct-100)/2; - - if (sd_flag & SD_BALANCE_WAKE) - load_idx = sd->wake_idx; - - do { - unsigned long load, avg_load; - int local_group; - int i; - - /* Skip over this group if it has no CPUs allowed */ - if (!cpumask_intersects(sched_group_cpus(group), - tsk_cpus_allowed(p))) - continue; - - local_group = cpumask_test_cpu(this_cpu, - sched_group_cpus(group)); - - /* Tally up the load of all CPUs in the group */ - avg_load = 0; - - for_each_cpu(i, sched_group_cpus(group)) { - /* Bias balancing toward cpus of our domain */ - if (local_group) - load = source_load(i, load_idx); - else - load = target_load(i, load_idx); - - avg_load += load; - } - - /* Adjust by relative CPU capacity of the group */ - avg_load = (avg_load * SCHED_CAPACITY_SCALE) / group->sgc->capacity; - - if (local_group) { - this_load = avg_load; - } else if (avg_load < min_load) { - min_load = avg_load; - idlest = group; - } - } while (group = group->next, group != sd->groups); - - if (!idlest || 100*this_load < imbalance*min_load) - return NULL; - return idlest; -} - -/* - * find_idlest_cpu - find the idlest cpu among the cpus in group. - */ -static int -find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu) -{ - unsigned long load, min_load = ULONG_MAX; - unsigned int min_exit_latency = UINT_MAX; - u64 latest_idle_timestamp = 0; - int least_loaded_cpu = this_cpu; - int shallowest_idle_cpu = -1; - int i; - - /* Check if we have any choice: */ - if (group->group_weight == 1) - return cpumask_first(sched_group_cpus(group)); - - /* Traverse only the allowed CPUs */ - for_each_cpu_and(i, sched_group_cpus(group), tsk_cpus_allowed(p)) { - if (idle_cpu(i)) { - struct rq *rq = cpu_rq(i); - struct cpuidle_state *idle = idle_get_state(rq); - if (idle && idle->exit_latency < min_exit_latency) { - /* - * We give priority to a CPU whose idle state - * has the smallest exit latency irrespective - * of any idle timestamp. - */ - min_exit_latency = idle->exit_latency; - latest_idle_timestamp = rq->idle_stamp; - shallowest_idle_cpu = i; - } else if ((!idle || idle->exit_latency == min_exit_latency) && - rq->idle_stamp > latest_idle_timestamp) { - /* - * If equal or no active idle state, then - * the most recently idled CPU might have - * a warmer cache. - */ - latest_idle_timestamp = rq->idle_stamp; - shallowest_idle_cpu = i; - } - } else if (shallowest_idle_cpu == -1) { - load = weighted_cpuload(i); - if (load < min_load || (load == min_load && i == this_cpu)) { - min_load = load; - least_loaded_cpu = i; - } - } - } - - return shallowest_idle_cpu != -1 ? shallowest_idle_cpu : least_loaded_cpu; -} - -/* - * Implement a for_each_cpu() variant that starts the scan at a given cpu - * (@start), and wraps around. - * - * This is used to scan for idle CPUs; such that not all CPUs looking for an - * idle CPU find the same CPU. The down-side is that tasks tend to cycle - * through the LLC domain. - * - * Especially tbench is found sensitive to this. - */ - -static int cpumask_next_wrap(int n, const struct cpumask *mask, int start, int *wrapped) -{ - int next; - -again: - next = find_next_bit(cpumask_bits(mask), nr_cpumask_bits, n+1); - - if (*wrapped) { - if (next >= start) - return nr_cpumask_bits; - } else { - if (next >= nr_cpumask_bits) { - *wrapped = 1; - n = -1; - goto again; - } - } - - return next; -} - -#define for_each_cpu_wrap(cpu, mask, start, wrap) \ - for ((wrap) = 0, (cpu) = (start)-1; \ - (cpu) = cpumask_next_wrap((cpu), (mask), (start), &(wrap)), \ - (cpu) < nr_cpumask_bits; ) - -#ifdef CONFIG_SCHED_SMT - -static inline void set_idle_cores(int cpu, int val) -{ - struct sched_domain_shared *sds; - - sds = rcu_dereference(per_cpu(sd_llc_shared, cpu)); - if (sds) - WRITE_ONCE(sds->has_idle_cores, val); -} - -static inline bool test_idle_cores(int cpu, bool def) -{ - struct sched_domain_shared *sds; - - sds = rcu_dereference(per_cpu(sd_llc_shared, cpu)); - if (sds) - return READ_ONCE(sds->has_idle_cores); - - return def; -} - -/* - * Scans the local SMT mask to see if the entire core is idle, and records this - * information in sd_llc_shared->has_idle_cores. - * - * Since SMT siblings share all cache levels, inspecting this limited remote - * state should be fairly cheap. - */ -void __update_idle_core(struct rq *rq) -{ - int core = cpu_of(rq); - int cpu; - - rcu_read_lock(); - if (test_idle_cores(core, true)) - goto unlock; - - for_each_cpu(cpu, cpu_smt_mask(core)) { - if (cpu == core) - continue; - - if (!idle_cpu(cpu)) - goto unlock; - } - - set_idle_cores(core, 1); -unlock: - rcu_read_unlock(); -} - -/* - * Scan the entire LLC domain for idle cores; this dynamically switches off if - * there are no idle cores left in the system; tracked through - * sd_llc->shared->has_idle_cores and enabled through update_idle_core() above. - */ -static int select_idle_core(struct task_struct *p, struct sched_domain *sd, int target) -{ - struct cpumask *cpus = this_cpu_cpumask_var_ptr(select_idle_mask); - int core, cpu, wrap; - - if (!static_branch_likely(&sched_smt_present)) - return -1; - - if (!test_idle_cores(target, false)) - return -1; - - cpumask_and(cpus, sched_domain_span(sd), tsk_cpus_allowed(p)); - - for_each_cpu_wrap(core, cpus, target, wrap) { - bool idle = true; - - for_each_cpu(cpu, cpu_smt_mask(core)) { - cpumask_clear_cpu(cpu, cpus); - if (!idle_cpu(cpu)) - idle = false; - } - - if (idle) - return core; - } - - /* - * Failed to find an idle core; stop looking for one. - */ - set_idle_cores(target, 0); - - return -1; -} - -/* - * Scan the local SMT mask for idle CPUs. - */ -static int select_idle_smt(struct task_struct *p, struct sched_domain *sd, int target) -{ - int cpu; - - if (!static_branch_likely(&sched_smt_present)) - return -1; - - for_each_cpu(cpu, cpu_smt_mask(target)) { - if (!cpumask_test_cpu(cpu, tsk_cpus_allowed(p))) - continue; - if (idle_cpu(cpu)) - return cpu; - } - - return -1; -} - -#else /* CONFIG_SCHED_SMT */ - -static inline int select_idle_core(struct task_struct *p, struct sched_domain *sd, int target) -{ - return -1; -} - -static inline int select_idle_smt(struct task_struct *p, struct sched_domain *sd, int target) -{ - return -1; -} - -#endif /* CONFIG_SCHED_SMT */ - -/* - * Scan the LLC domain for idle CPUs; this is dynamically regulated by - * comparing the average scan cost (tracked in sd->avg_scan_cost) against the - * average idle time for this rq (as found in rq->avg_idle). - */ -static int select_idle_cpu(struct task_struct *p, struct sched_domain *sd, int target) -{ - struct sched_domain *this_sd; - u64 avg_cost, avg_idle = this_rq()->avg_idle; - u64 time, cost; - s64 delta; - int cpu, wrap; - - this_sd = rcu_dereference(*this_cpu_ptr(&sd_llc)); - if (!this_sd) - return -1; - - avg_cost = this_sd->avg_scan_cost; - - /* - * Due to large variance we need a large fuzz factor; hackbench in - * particularly is sensitive here. - */ - if ((avg_idle / 512) < avg_cost) - return -1; - - time = local_clock(); - - for_each_cpu_wrap(cpu, sched_domain_span(sd), target, wrap) { - if (!cpumask_test_cpu(cpu, tsk_cpus_allowed(p))) - continue; - if (idle_cpu(cpu)) - break; - } - - time = local_clock() - time; - cost = this_sd->avg_scan_cost; - delta = (s64)(time - cost) / 8; - this_sd->avg_scan_cost += delta; - - return cpu; -} - -/* - * Try and locate an idle core/thread in the LLC cache domain. - */ -static int select_idle_sibling(struct task_struct *p, int prev, int target) -{ - struct sched_domain *sd; - int i; - - if (idle_cpu(target)) - return target; - - /* - * If the previous cpu is cache affine and idle, don't be stupid. - */ - if (prev != target && cpus_share_cache(prev, target) && idle_cpu(prev)) - return prev; - - sd = rcu_dereference(per_cpu(sd_llc, target)); - if (!sd) - return target; - - i = select_idle_core(p, sd, target); - if ((unsigned)i < nr_cpumask_bits) - return i; - - i = select_idle_cpu(p, sd, target); - if ((unsigned)i < nr_cpumask_bits) - return i; - - i = select_idle_smt(p, sd, target); - if ((unsigned)i < nr_cpumask_bits) - return i; - - return target; -} - -/* - * cpu_util returns the amount of capacity of a CPU that is used by CFS - * tasks. The unit of the return value must be the one of capacity so we can - * compare the utilization with the capacity of the CPU that is available for - * CFS task (ie cpu_capacity). - * - * cfs_rq.avg.util_avg is the sum of running time of runnable tasks plus the - * recent utilization of currently non-runnable tasks on a CPU. It represents - * the amount of utilization of a CPU in the range [0..capacity_orig] where - * capacity_orig is the cpu_capacity available at the highest frequency - * (arch_scale_freq_capacity()). - * The utilization of a CPU converges towards a sum equal to or less than the - * current capacity (capacity_curr <= capacity_orig) of the CPU because it is - * the running time on this CPU scaled by capacity_curr. - * - * Nevertheless, cfs_rq.avg.util_avg can be higher than capacity_curr or even - * higher than capacity_orig because of unfortunate rounding in - * cfs.avg.util_avg or just after migrating tasks and new task wakeups until - * the average stabilizes with the new running time. We need to check that the - * utilization stays within the range of [0..capacity_orig] and cap it if - * necessary. Without utilization capping, a group could be seen as overloaded - * (CPU0 utilization at 121% + CPU1 utilization at 80%) whereas CPU1 has 20% of - * available capacity. We allow utilization to overshoot capacity_curr (but not - * capacity_orig) as it useful for predicting the capacity required after task - * migrations (scheduler-driven DVFS). - */ -static int cpu_util(int cpu) -{ - unsigned long util = cpu_rq(cpu)->cfs.avg.util_avg; - unsigned long capacity = capacity_orig_of(cpu); - - return (util >= capacity) ? capacity : util; -} - -static inline int task_util(struct task_struct *p) -{ - return p->se.avg.util_avg; -} - -/* - * Disable WAKE_AFFINE in the case where task @p doesn't fit in the - * capacity of either the waking CPU @cpu or the previous CPU @prev_cpu. - * - * In that case WAKE_AFFINE doesn't make sense and we'll let - * BALANCE_WAKE sort things out. - */ -static int wake_cap(struct task_struct *p, int cpu, int prev_cpu) -{ - long min_cap, max_cap; - - min_cap = min(capacity_orig_of(prev_cpu), capacity_orig_of(cpu)); - max_cap = cpu_rq(cpu)->rd->max_cpu_capacity; - - /* Minimum capacity is close to max, no need to abort wake_affine */ - if (max_cap - min_cap < max_cap >> 3) - return 0; - - return min_cap * 1024 < task_util(p) * capacity_margin; -} - -/* - * select_task_rq_fair: Select target runqueue for the waking task in domains - * that have the 'sd_flag' flag set. In practice, this is SD_BALANCE_WAKE, - * SD_BALANCE_FORK, or SD_BALANCE_EXEC. - * - * Balances load by selecting the idlest cpu in the idlest group, or under - * certain conditions an idle sibling cpu if the domain has SD_WAKE_AFFINE set. - * - * Returns the target cpu number. - * - * preempt must be disabled. - */ -static int -select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_flags) -{ - struct sched_domain *tmp, *affine_sd = NULL, *sd = NULL; - int cpu = smp_processor_id(); - int new_cpu = prev_cpu; - int want_affine = 0; - int sync = wake_flags & WF_SYNC; - - if (sd_flag & SD_BALANCE_WAKE) { - record_wakee(p); - want_affine = !wake_wide(p) && !wake_cap(p, cpu, prev_cpu) - && cpumask_test_cpu(cpu, tsk_cpus_allowed(p)); - } - - rcu_read_lock(); - for_each_domain(cpu, tmp) { - if (!(tmp->flags & SD_LOAD_BALANCE)) - break; - - /* - * If both cpu and prev_cpu are part of this domain, - * cpu is a valid SD_WAKE_AFFINE target. - */ - if (want_affine && (tmp->flags & SD_WAKE_AFFINE) && - cpumask_test_cpu(prev_cpu, sched_domain_span(tmp))) { - affine_sd = tmp; - break; - } - - if (tmp->flags & sd_flag) - sd = tmp; - else if (!want_affine) - break; - } - - if (affine_sd) { - sd = NULL; /* Prefer wake_affine over balance flags */ - if (cpu != prev_cpu && wake_affine(affine_sd, p, prev_cpu, sync)) - new_cpu = cpu; - } - - if (!sd) { - if (sd_flag & SD_BALANCE_WAKE) /* XXX always ? */ - new_cpu = select_idle_sibling(p, prev_cpu, new_cpu); - - } else while (sd) { - struct sched_group *group; - int weight; - - if (!(sd->flags & sd_flag)) { - sd = sd->child; - continue; - } - - group = find_idlest_group(sd, p, cpu, sd_flag); - if (!group) { - sd = sd->child; - continue; - } - - new_cpu = find_idlest_cpu(group, p, cpu); - if (new_cpu == -1 || new_cpu == cpu) { - /* Now try balancing at a lower domain level of cpu */ - sd = sd->child; - continue; - } - - /* Now try balancing at a lower domain level of new_cpu */ - cpu = new_cpu; - weight = sd->span_weight; - sd = NULL; - for_each_domain(cpu, tmp) { - if (weight <= tmp->span_weight) - break; - if (tmp->flags & sd_flag) - sd = tmp; - } - /* while loop will break here if sd == NULL */ - } - rcu_read_unlock(); - - return new_cpu; -} - -/* - * Called immediately before a task is migrated to a new cpu; task_cpu(p) and - * cfs_rq_of(p) references at time of call are still valid and identify the - * previous cpu. The caller guarantees p->pi_lock or task_rq(p)->lock is held. - */ -static void migrate_task_rq_fair(struct task_struct *p) -{ - /* - * As blocked tasks retain absolute vruntime the migration needs to - * deal with this by subtracting the old and adding the new - * min_vruntime -- the latter is done by enqueue_entity() when placing - * the task on the new runqueue. - */ - if (p->state == TASK_WAKING) { - struct sched_entity *se = &p->se; - struct cfs_rq *cfs_rq = cfs_rq_of(se); - u64 min_vruntime; - -#ifndef CONFIG_64BIT - u64 min_vruntime_copy; - - do { - min_vruntime_copy = cfs_rq->min_vruntime_copy; - smp_rmb(); - min_vruntime = cfs_rq->min_vruntime; - } while (min_vruntime != min_vruntime_copy); -#else - min_vruntime = cfs_rq->min_vruntime; -#endif - - se->vruntime -= min_vruntime; - } - - /* - * We are supposed to update the task to "current" time, then its up to date - * and ready to go to new CPU/cfs_rq. But we have difficulty in getting - * what current time is, so simply throw away the out-of-date time. This - * will result in the wakee task is less decayed, but giving the wakee more - * load sounds not bad. - */ - remove_entity_load_avg(&p->se); - - /* Tell new CPU we are migrated */ - p->se.avg.last_update_time = 0; - - /* We have migrated, no longer consider this task hot */ - p->se.exec_start = 0; -} - -static void task_dead_fair(struct task_struct *p) -{ - remove_entity_load_avg(&p->se); -} -#endif /* CONFIG_SMP */ - -static unsigned long -wakeup_gran(struct sched_entity *curr, struct sched_entity *se) -{ - unsigned long gran = sysctl_sched_wakeup_granularity; - - /* - * Since its curr running now, convert the gran from real-time - * to virtual-time in his units. - * - * By using 'se' instead of 'curr' we penalize light tasks, so - * they get preempted easier. That is, if 'se' < 'curr' then - * the resulting gran will be larger, therefore penalizing the - * lighter, if otoh 'se' > 'curr' then the resulting gran will - * be smaller, again penalizing the lighter task. - * - * This is especially important for buddies when the leftmost - * task is higher priority than the buddy. - */ - return calc_delta_fair(gran, se); -} - -/* - * Should 'se' preempt 'curr'. - * - * |s1 - * |s2 - * |s3 - * g - * |<--->|c - * - * w(c, s1) = -1 - * w(c, s2) = 0 - * w(c, s3) = 1 - * - */ -static int -wakeup_preempt_entity(struct sched_entity *curr, struct sched_entity *se) -{ - s64 gran, vdiff = curr->vruntime - se->vruntime; - - if (vdiff <= 0) - return -1; - - gran = wakeup_gran(curr, se); - if (vdiff > gran) - return 1; - - return 0; -} - -static void set_last_buddy(struct sched_entity *se) -{ - if (entity_is_task(se) && unlikely(task_of(se)->policy == SCHED_IDLE)) - return; - - for_each_sched_entity(se) - cfs_rq_of(se)->last = se; -} - -static void set_next_buddy(struct sched_entity *se) -{ - if (entity_is_task(se) && unlikely(task_of(se)->policy == SCHED_IDLE)) - return; - - for_each_sched_entity(se) - cfs_rq_of(se)->next = se; -} - -static void set_skip_buddy(struct sched_entity *se) -{ - for_each_sched_entity(se) - cfs_rq_of(se)->skip = se; -} - -/* - * Preempt the current task with a newly woken task if needed: - */ -static void check_preempt_wakeup(struct rq *rq, struct task_struct *p, int wake_flags) -{ - struct task_struct *curr = rq->curr; - struct sched_entity *se = &curr->se, *pse = &p->se; - struct cfs_rq *cfs_rq = task_cfs_rq(curr); - int scale = cfs_rq->nr_running >= sched_nr_latency; - int next_buddy_marked = 0; - - if (unlikely(se == pse)) - return; - - /* - * This is possible from callers such as attach_tasks(), in which we - * unconditionally check_prempt_curr() after an enqueue (which may have - * lead to a throttle). This both saves work and prevents false - * next-buddy nomination below. - */ - if (unlikely(throttled_hierarchy(cfs_rq_of(pse)))) - return; - - if (sched_feat(NEXT_BUDDY) && scale && !(wake_flags & WF_FORK)) { - set_next_buddy(pse); - next_buddy_marked = 1; - } - - /* - * We can come here with TIF_NEED_RESCHED already set from new task - * wake up path. - * - * Note: this also catches the edge-case of curr being in a throttled - * group (e.g. via set_curr_task), since update_curr() (in the - * enqueue of curr) will have resulted in resched being set. This - * prevents us from potentially nominating it as a false LAST_BUDDY - * below. - */ - if (test_tsk_need_resched(curr)) - return; - - /* Idle tasks are by definition preempted by non-idle tasks. */ - if (unlikely(curr->policy == SCHED_IDLE) && - likely(p->policy != SCHED_IDLE)) - goto preempt; - - /* - * Batch and idle tasks do not preempt non-idle tasks (their preemption - * is driven by the tick): - */ - if (unlikely(p->policy != SCHED_NORMAL) || !sched_feat(WAKEUP_PREEMPTION)) - return; - - find_matching_se(&se, &pse); - update_curr(cfs_rq_of(se)); - BUG_ON(!pse); - if (wakeup_preempt_entity(se, pse) == 1) { - /* - * Bias pick_next to pick the sched entity that is - * triggering this preemption. - */ - if (!next_buddy_marked) - set_next_buddy(pse); - goto preempt; - } - - return; - -preempt: - resched_curr(rq); - /* - * Only set the backward buddy when the current task is still - * on the rq. This can happen when a wakeup gets interleaved - * with schedule on the ->pre_schedule() or idle_balance() - * point, either of which can * drop the rq lock. - * - * Also, during early boot the idle thread is in the fair class, - * for obvious reasons its a bad idea to schedule back to it. - */ - if (unlikely(!se->on_rq || curr == rq->idle)) - return; - - if (sched_feat(LAST_BUDDY) && scale && entity_is_task(se)) - set_last_buddy(se); -} - -static struct task_struct * -pick_next_task_fair(struct rq *rq, struct task_struct *prev, struct pin_cookie cookie) -{ - struct cfs_rq *cfs_rq = &rq->cfs; - struct sched_entity *se; - struct task_struct *p; - int new_tasks; - -again: -#ifdef CONFIG_FAIR_GROUP_SCHED - if (!cfs_rq->nr_running) - goto idle; - - if (prev->sched_class != &fair_sched_class) - goto simple; - - /* - * Because of the set_next_buddy() in dequeue_task_fair() it is rather - * likely that a next task is from the same cgroup as the current. - * - * Therefore attempt to avoid putting and setting the entire cgroup - * hierarchy, only change the part that actually changes. - */ - - do { - struct sched_entity *curr = cfs_rq->curr; - - /* - * Since we got here without doing put_prev_entity() we also - * have to consider cfs_rq->curr. If it is still a runnable - * entity, update_curr() will update its vruntime, otherwise - * forget we've ever seen it. - */ - if (curr) { - if (curr->on_rq) - update_curr(cfs_rq); - else - curr = NULL; - - /* - * This call to check_cfs_rq_runtime() will do the - * throttle and dequeue its entity in the parent(s). - * Therefore the 'simple' nr_running test will indeed - * be correct. - */ - if (unlikely(check_cfs_rq_runtime(cfs_rq))) - goto simple; - } - - se = pick_next_entity(cfs_rq, curr); - cfs_rq = group_cfs_rq(se); - } while (cfs_rq); - - p = task_of(se); - - /* - * Since we haven't yet done put_prev_entity and if the selected task - * is a different task than we started out with, try and touch the - * least amount of cfs_rqs. - */ - if (prev != p) { - struct sched_entity *pse = &prev->se; - - while (!(cfs_rq = is_same_group(se, pse))) { - int se_depth = se->depth; - int pse_depth = pse->depth; - - if (se_depth <= pse_depth) { - put_prev_entity(cfs_rq_of(pse), pse); - pse = parent_entity(pse); - } - if (se_depth >= pse_depth) { - set_next_entity(cfs_rq_of(se), se); - se = parent_entity(se); - } - } - - put_prev_entity(cfs_rq, pse); - set_next_entity(cfs_rq, se); - } - - if (hrtick_enabled(rq)) - hrtick_start_fair(rq, p); - - return p; -simple: - cfs_rq = &rq->cfs; -#endif - - if (!cfs_rq->nr_running) - goto idle; - - put_prev_task(rq, prev); - - do { - se = pick_next_entity(cfs_rq, NULL); - set_next_entity(cfs_rq, se); - cfs_rq = group_cfs_rq(se); - } while (cfs_rq); - - p = task_of(se); - - if (hrtick_enabled(rq)) - hrtick_start_fair(rq, p); - - return p; - -idle: - /* - * This is OK, because current is on_cpu, which avoids it being picked - * for load-balance and preemption/IRQs are still disabled avoiding - * further scheduler activity on it and we're being very careful to - * re-start the picking loop. - */ - lockdep_unpin_lock(&rq->lock, cookie); - new_tasks = idle_balance(rq); - lockdep_repin_lock(&rq->lock, cookie); - /* - * Because idle_balance() releases (and re-acquires) rq->lock, it is - * possible for any higher priority task to appear. In that case we - * must re-start the pick_next_entity() loop. - */ - if (new_tasks < 0) - return RETRY_TASK; - - if (new_tasks > 0) - goto again; - - return NULL; -} - -/* - * Account for a descheduled task: - */ -static void put_prev_task_fair(struct rq *rq, struct task_struct *prev) -{ - struct sched_entity *se = &prev->se; - struct cfs_rq *cfs_rq; - - for_each_sched_entity(se) { - cfs_rq = cfs_rq_of(se); - put_prev_entity(cfs_rq, se); - } -} - -/* - * sched_yield() is very simple - * - * The magic of dealing with the ->skip buddy is in pick_next_entity. - */ -static void yield_task_fair(struct rq *rq) -{ - struct task_struct *curr = rq->curr; - struct cfs_rq *cfs_rq = task_cfs_rq(curr); - struct sched_entity *se = &curr->se; - - /* - * Are we the only task in the tree? - */ - if (unlikely(rq->nr_running == 1)) - return; - - clear_buddies(cfs_rq, se); - - if (curr->policy != SCHED_BATCH) { - update_rq_clock(rq); - /* - * Update run-time statistics of the 'current'. - */ - update_curr(cfs_rq); - /* - * Tell update_rq_clock() that we've just updated, - * so we don't do microscopic update in schedule() - * and double the fastpath cost. - */ - rq_clock_skip_update(rq, true); - } - - set_skip_buddy(se); -} - -static bool yield_to_task_fair(struct rq *rq, struct task_struct *p, bool preempt) -{ - struct sched_entity *se = &p->se; - - /* throttled hierarchies are not runnable */ - if (!se->on_rq || throttled_hierarchy(cfs_rq_of(se))) - return false; - - /* Tell the scheduler that we'd really like pse to run next. */ - set_next_buddy(se); - - yield_task_fair(rq); - - return true; -} - -#ifdef CONFIG_SMP -/************************************************** - * Fair scheduling class load-balancing methods. - * - * BASICS - * - * The purpose of load-balancing is to achieve the same basic fairness the - * per-cpu scheduler provides, namely provide a proportional amount of compute - * time to each task. This is expressed in the following equation: - * - * W_i,n/P_i == W_j,n/P_j for all i,j (1) - * - * Where W_i,n is the n-th weight average for cpu i. The instantaneous weight - * W_i,0 is defined as: - * - * W_i,0 = \Sum_j w_i,j (2) - * - * Where w_i,j is the weight of the j-th runnable task on cpu i. This weight - * is derived from the nice value as per sched_prio_to_weight[]. - * - * The weight average is an exponential decay average of the instantaneous - * weight: - * - * W'_i,n = (2^n - 1) / 2^n * W_i,n + 1 / 2^n * W_i,0 (3) - * - * C_i is the compute capacity of cpu i, typically it is the - * fraction of 'recent' time available for SCHED_OTHER task execution. But it - * can also include other factors [XXX]. - * - * To achieve this balance we define a measure of imbalance which follows - * directly from (1): - * - * imb_i,j = max{ avg(W/C), W_i/C_i } - min{ avg(W/C), W_j/C_j } (4) - * - * We them move tasks around to minimize the imbalance. In the continuous - * function space it is obvious this converges, in the discrete case we get - * a few fun cases generally called infeasible weight scenarios. - * - * [XXX expand on: - * - infeasible weights; - * - local vs global optima in the discrete case. ] - * - * - * SCHED DOMAINS - * - * In order to solve the imbalance equation (4), and avoid the obvious O(n^2) - * for all i,j solution, we create a tree of cpus that follows the hardware - * topology where each level pairs two lower groups (or better). This results - * in O(log n) layers. Furthermore we reduce the number of cpus going up the - * tree to only the first of the previous level and we decrease the frequency - * of load-balance at each level inv. proportional to the number of cpus in - * the groups. - * - * This yields: - * - * log_2 n 1 n - * \Sum { --- * --- * 2^i } = O(n) (5) - * i = 0 2^i 2^i - * `- size of each group - * | | `- number of cpus doing load-balance - * | `- freq - * `- sum over all levels - * - * Coupled with a limit on how many tasks we can migrate every balance pass, - * this makes (5) the runtime complexity of the balancer. - * - * An important property here is that each CPU is still (indirectly) connected - * to every other cpu in at most O(log n) steps: - * - * The adjacency matrix of the resulting graph is given by: - * - * log_2 n - * A_i,j = \Union (i % 2^k == 0) && i / 2^(k+1) == j / 2^(k+1) (6) - * k = 0 - * - * And you'll find that: - * - * A^(log_2 n)_i,j != 0 for all i,j (7) - * - * Showing there's indeed a path between every cpu in at most O(log n) steps. - * The task movement gives a factor of O(m), giving a convergence complexity - * of: - * - * O(nm log n), n := nr_cpus, m := nr_tasks (8) - * - * - * WORK CONSERVING - * - * In order to avoid CPUs going idle while there's still work to do, new idle - * balancing is more aggressive and has the newly idle cpu iterate up the domain - * tree itself instead of relying on other CPUs to bring it work. - * - * This adds some complexity to both (5) and (8) but it reduces the total idle - * time. - * - * [XXX more?] - * - * - * CGROUPS - * - * Cgroups make a horror show out of (2), instead of a simple sum we get: - * - * s_k,i - * W_i,0 = \Sum_j \Prod_k w_k * ----- (9) - * S_k - * - * Where - * - * s_k,i = \Sum_j w_i,j,k and S_k = \Sum_i s_k,i (10) - * - * w_i,j,k is the weight of the j-th runnable task in the k-th cgroup on cpu i. - * - * The big problem is S_k, its a global sum needed to compute a local (W_i) - * property. - * - * [XXX write more on how we solve this.. _after_ merging pjt's patches that - * rewrite all of this once again.] - */ - -static unsigned long __read_mostly max_load_balance_interval = HZ/10; - -enum fbq_type { regular, remote, all }; - -#define LBF_ALL_PINNED 0x01 -#define LBF_NEED_BREAK 0x02 -#define LBF_DST_PINNED 0x04 -#define LBF_SOME_PINNED 0x08 - -struct lb_env { - struct sched_domain *sd; - - struct rq *src_rq; - int src_cpu; - - int dst_cpu; - struct rq *dst_rq; - - struct cpumask *dst_grpmask; - int new_dst_cpu; - enum cpu_idle_type idle; - long imbalance; - /* The set of CPUs under consideration for load-balancing */ - struct cpumask *cpus; - - unsigned int flags; - - unsigned int loop; - unsigned int loop_break; - unsigned int loop_max; - - enum fbq_type fbq_type; - struct list_head tasks; -}; - -/* - * Is this task likely cache-hot: - */ -static int task_hot(struct task_struct *p, struct lb_env *env) -{ - s64 delta; - - lockdep_assert_held(&env->src_rq->lock); - - if (p->sched_class != &fair_sched_class) - return 0; - - if (unlikely(p->policy == SCHED_IDLE)) - return 0; - - /* - * Buddy candidates are cache hot: - */ - if (sched_feat(CACHE_HOT_BUDDY) && env->dst_rq->nr_running && - (&p->se == cfs_rq_of(&p->se)->next || - &p->se == cfs_rq_of(&p->se)->last)) - return 1; - - if (sysctl_sched_migration_cost == -1) - return 1; - if (sysctl_sched_migration_cost == 0) - return 0; - - delta = rq_clock_task(env->src_rq) - p->se.exec_start; - - return delta < (s64)sysctl_sched_migration_cost; -} - -#ifdef CONFIG_NUMA_BALANCING -/* - * Returns 1, if task migration degrades locality - * Returns 0, if task migration improves locality i.e migration preferred. - * Returns -1, if task migration is not affected by locality. - */ -static int migrate_degrades_locality(struct task_struct *p, struct lb_env *env) -{ - struct numa_group *numa_group = rcu_dereference(p->numa_group); - unsigned long src_faults, dst_faults; - int src_nid, dst_nid; - - if (!static_branch_likely(&sched_numa_balancing)) - return -1; - - if (!p->numa_faults || !(env->sd->flags & SD_NUMA)) - return -1; - - src_nid = cpu_to_node(env->src_cpu); - dst_nid = cpu_to_node(env->dst_cpu); - - if (src_nid == dst_nid) - return -1; - - /* Migrating away from the preferred node is always bad. */ - if (src_nid == p->numa_preferred_nid) { - if (env->src_rq->nr_running > env->src_rq->nr_preferred_running) - return 1; - else - return -1; - } - - /* Encourage migration to the preferred node. */ - if (dst_nid == p->numa_preferred_nid) - return 0; - - if (numa_group) { - src_faults = group_faults(p, src_nid); - dst_faults = group_faults(p, dst_nid); - } else { - src_faults = task_faults(p, src_nid); - dst_faults = task_faults(p, dst_nid); - } - - return dst_faults < src_faults; -} - -#else -static inline int migrate_degrades_locality(struct task_struct *p, - struct lb_env *env) -{ - return -1; -} -#endif - -/* - * can_migrate_task - may task p from runqueue rq be migrated to this_cpu? - */ -static -int can_migrate_task(struct task_struct *p, struct lb_env *env) -{ - int tsk_cache_hot; - - lockdep_assert_held(&env->src_rq->lock); - - /* - * We do not migrate tasks that are: - * 1) throttled_lb_pair, or - * 2) cannot be migrated to this CPU due to cpus_allowed, or - * 3) running (obviously), or - * 4) are cache-hot on their current CPU. - */ - if (throttled_lb_pair(task_group(p), env->src_cpu, env->dst_cpu)) - return 0; - - if (!cpumask_test_cpu(env->dst_cpu, tsk_cpus_allowed(p))) { - int cpu; - - schedstat_inc(p->se.statistics.nr_failed_migrations_affine); - - env->flags |= LBF_SOME_PINNED; - - /* - * Remember if this task can be migrated to any other cpu in - * our sched_group. We may want to revisit it if we couldn't - * meet load balance goals by pulling other tasks on src_cpu. - * - * Also avoid computing new_dst_cpu if we have already computed - * one in current iteration. - */ - if (!env->dst_grpmask || (env->flags & LBF_DST_PINNED)) - return 0; - - /* Prevent to re-select dst_cpu via env's cpus */ - for_each_cpu_and(cpu, env->dst_grpmask, env->cpus) { - if (cpumask_test_cpu(cpu, tsk_cpus_allowed(p))) { - env->flags |= LBF_DST_PINNED; - env->new_dst_cpu = cpu; - break; - } - } - - return 0; - } - - /* Record that we found atleast one task that could run on dst_cpu */ - env->flags &= ~LBF_ALL_PINNED; - - if (task_running(env->src_rq, p)) { - schedstat_inc(p->se.statistics.nr_failed_migrations_running); - return 0; - } - - /* - * Aggressive migration if: - * 1) destination numa is preferred - * 2) task is cache cold, or - * 3) too many balance attempts have failed. - */ - tsk_cache_hot = migrate_degrades_locality(p, env); - if (tsk_cache_hot == -1) - tsk_cache_hot = task_hot(p, env); - - if (tsk_cache_hot <= 0 || - env->sd->nr_balance_failed > env->sd->cache_nice_tries) { - if (tsk_cache_hot == 1) { - schedstat_inc(env->sd->lb_hot_gained[env->idle]); - schedstat_inc(p->se.statistics.nr_forced_migrations); - } - return 1; - } - - schedstat_inc(p->se.statistics.nr_failed_migrations_hot); - return 0; -} - -/* - * detach_task() -- detach the task for the migration specified in env - */ -static void detach_task(struct task_struct *p, struct lb_env *env) -{ - lockdep_assert_held(&env->src_rq->lock); - - p->on_rq = TASK_ON_RQ_MIGRATING; - deactivate_task(env->src_rq, p, 0); - set_task_cpu(p, env->dst_cpu); -} - -/* - * detach_one_task() -- tries to dequeue exactly one task from env->src_rq, as - * part of active balancing operations within "domain". - * - * Returns a task if successful and NULL otherwise. - */ -static struct task_struct *detach_one_task(struct lb_env *env) -{ - struct task_struct *p, *n; - - lockdep_assert_held(&env->src_rq->lock); - - list_for_each_entry_safe(p, n, &env->src_rq->cfs_tasks, se.group_node) { - if (!can_migrate_task(p, env)) - continue; - - detach_task(p, env); - - /* - * Right now, this is only the second place where - * lb_gained[env->idle] is updated (other is detach_tasks) - * so we can safely collect stats here rather than - * inside detach_tasks(). - */ - schedstat_inc(env->sd->lb_gained[env->idle]); - return p; - } - return NULL; -} - -static const unsigned int sched_nr_migrate_break = 32; - -/* - * detach_tasks() -- tries to detach up to imbalance weighted load from - * busiest_rq, as part of a balancing operation within domain "sd". - * - * Returns number of detached tasks if successful and 0 otherwise. - */ -static int detach_tasks(struct lb_env *env) -{ - struct list_head *tasks = &env->src_rq->cfs_tasks; - struct task_struct *p; - unsigned long load; - int detached = 0; - - lockdep_assert_held(&env->src_rq->lock); - - if (env->imbalance <= 0) - return 0; - - while (!list_empty(tasks)) { - /* - * We don't want to steal all, otherwise we may be treated likewise, - * which could at worst lead to a livelock crash. - */ - if (env->idle != CPU_NOT_IDLE && env->src_rq->nr_running <= 1) - break; - - p = list_first_entry(tasks, struct task_struct, se.group_node); - - env->loop++; - /* We've more or less seen every task there is, call it quits */ - if (env->loop > env->loop_max) - break; - - /* take a breather every nr_migrate tasks */ - if (env->loop > env->loop_break) { - env->loop_break += sched_nr_migrate_break; - env->flags |= LBF_NEED_BREAK; - break; - } - - if (!can_migrate_task(p, env)) - goto next; - - load = task_h_load(p); - - if (sched_feat(LB_MIN) && load < 16 && !env->sd->nr_balance_failed) - goto next; - - if ((load / 2) > env->imbalance) - goto next; - - detach_task(p, env); - list_add(&p->se.group_node, &env->tasks); - - detached++; - env->imbalance -= load; - -#ifdef CONFIG_PREEMPT - /* - * NEWIDLE balancing is a source of latency, so preemptible - * kernels will stop after the first task is detached to minimize - * the critical section. - */ - if (env->idle == CPU_NEWLY_IDLE) - break; -#endif - - /* - * We only want to steal up to the prescribed amount of - * weighted load. - */ - if (env->imbalance <= 0) - break; - - continue; -next: - list_move_tail(&p->se.group_node, tasks); - } - - /* - * Right now, this is one of only two places we collect this stat - * so we can safely collect detach_one_task() stats here rather - * than inside detach_one_task(). - */ - schedstat_add(env->sd->lb_gained[env->idle], detached); - - return detached; -} - -/* - * attach_task() -- attach the task detached by detach_task() to its new rq. - */ -static void attach_task(struct rq *rq, struct task_struct *p) -{ - lockdep_assert_held(&rq->lock); - - BUG_ON(task_rq(p) != rq); - activate_task(rq, p, 0); - p->on_rq = TASK_ON_RQ_QUEUED; - check_preempt_curr(rq, p, 0); -} - -/* - * attach_one_task() -- attaches the task returned from detach_one_task() to - * its new rq. - */ -static void attach_one_task(struct rq *rq, struct task_struct *p) -{ - raw_spin_lock(&rq->lock); - attach_task(rq, p); - raw_spin_unlock(&rq->lock); -} - -/* - * attach_tasks() -- attaches all tasks detached by detach_tasks() to their - * new rq. - */ -static void attach_tasks(struct lb_env *env) -{ - struct list_head *tasks = &env->tasks; - struct task_struct *p; - - raw_spin_lock(&env->dst_rq->lock); - - while (!list_empty(tasks)) { - p = list_first_entry(tasks, struct task_struct, se.group_node); - list_del_init(&p->se.group_node); - - attach_task(env->dst_rq, p); - } - - raw_spin_unlock(&env->dst_rq->lock); -} - -#ifdef CONFIG_FAIR_GROUP_SCHED -static void update_blocked_averages(int cpu) -{ - struct rq *rq = cpu_rq(cpu); - struct cfs_rq *cfs_rq; - unsigned long flags; - - raw_spin_lock_irqsave(&rq->lock, flags); - update_rq_clock(rq); - - /* - * Iterates the task_group tree in a bottom up fashion, see - * list_add_leaf_cfs_rq() for details. - */ - for_each_leaf_cfs_rq(rq, cfs_rq) { - /* throttled entities do not contribute to load */ - if (throttled_hierarchy(cfs_rq)) - continue; - - if (update_cfs_rq_load_avg(cfs_rq_clock_task(cfs_rq), cfs_rq, true)) - update_tg_load_avg(cfs_rq, 0); - } - raw_spin_unlock_irqrestore(&rq->lock, flags); -} - -/* - * Compute the hierarchical load factor for cfs_rq and all its ascendants. - * This needs to be done in a top-down fashion because the load of a child - * group is a fraction of its parents load. - */ -static void update_cfs_rq_h_load(struct cfs_rq *cfs_rq) -{ - struct rq *rq = rq_of(cfs_rq); - struct sched_entity *se = cfs_rq->tg->se[cpu_of(rq)]; - unsigned long now = jiffies; - unsigned long load; - - if (cfs_rq->last_h_load_update == now) - return; - - cfs_rq->h_load_next = NULL; - for_each_sched_entity(se) { - cfs_rq = cfs_rq_of(se); - cfs_rq->h_load_next = se; - if (cfs_rq->last_h_load_update == now) - break; - } - - if (!se) { - cfs_rq->h_load = cfs_rq_load_avg(cfs_rq); - cfs_rq->last_h_load_update = now; - } - - while ((se = cfs_rq->h_load_next) != NULL) { - load = cfs_rq->h_load; - load = div64_ul(load * se->avg.load_avg, - cfs_rq_load_avg(cfs_rq) + 1); - cfs_rq = group_cfs_rq(se); - cfs_rq->h_load = load; - cfs_rq->last_h_load_update = now; - } -} - -static unsigned long task_h_load(struct task_struct *p) -{ - struct cfs_rq *cfs_rq = task_cfs_rq(p); - - update_cfs_rq_h_load(cfs_rq); - return div64_ul(p->se.avg.load_avg * cfs_rq->h_load, - cfs_rq_load_avg(cfs_rq) + 1); -} -#else -static inline void update_blocked_averages(int cpu) -{ - struct rq *rq = cpu_rq(cpu); - struct cfs_rq *cfs_rq = &rq->cfs; - unsigned long flags; - - raw_spin_lock_irqsave(&rq->lock, flags); - update_rq_clock(rq); - update_cfs_rq_load_avg(cfs_rq_clock_task(cfs_rq), cfs_rq, true); - raw_spin_unlock_irqrestore(&rq->lock, flags); -} - -static unsigned long task_h_load(struct task_struct *p) -{ - return p->se.avg.load_avg; -} -#endif - -/********** Helpers for find_busiest_group ************************/ - -enum group_type { - group_other = 0, - group_imbalanced, - group_overloaded, -}; - -/* - * sg_lb_stats - stats of a sched_group required for load_balancing - */ -struct sg_lb_stats { - unsigned long avg_load; /*Avg load across the CPUs of the group */ - unsigned long group_load; /* Total load over the CPUs of the group */ - unsigned long sum_weighted_load; /* Weighted load of group's tasks */ - unsigned long load_per_task; - unsigned long group_capacity; - unsigned long group_util; /* Total utilization of the group */ - unsigned int sum_nr_running; /* Nr tasks running in the group */ - unsigned int idle_cpus; - unsigned int group_weight; - enum group_type group_type; - int group_no_capacity; -#ifdef CONFIG_NUMA_BALANCING - unsigned int nr_numa_running; - unsigned int nr_preferred_running; -#endif -}; - -/* - * sd_lb_stats - Structure to store the statistics of a sched_domain - * during load balancing. - */ -struct sd_lb_stats { - struct sched_group *busiest; /* Busiest group in this sd */ - struct sched_group *local; /* Local group in this sd */ - unsigned long total_load; /* Total load of all groups in sd */ - unsigned long total_capacity; /* Total capacity of all groups in sd */ - unsigned long avg_load; /* Average load across all groups in sd */ - - struct sg_lb_stats busiest_stat;/* Statistics of the busiest group */ - struct sg_lb_stats local_stat; /* Statistics of the local group */ -}; - -static inline void init_sd_lb_stats(struct sd_lb_stats *sds) -{ - /* - * Skimp on the clearing to avoid duplicate work. We can avoid clearing - * local_stat because update_sg_lb_stats() does a full clear/assignment. - * We must however clear busiest_stat::avg_load because - * update_sd_pick_busiest() reads this before assignment. - */ - *sds = (struct sd_lb_stats){ - .busiest = NULL, - .local = NULL, - .total_load = 0UL, - .total_capacity = 0UL, - .busiest_stat = { - .avg_load = 0UL, - .sum_nr_running = 0, - .group_type = group_other, - }, - }; -} - -/** - * get_sd_load_idx - Obtain the load index for a given sched domain. - * @sd: The sched_domain whose load_idx is to be obtained. - * @idle: The idle status of the CPU for whose sd load_idx is obtained. - * - * Return: The load index. - */ -static inline int get_sd_load_idx(struct sched_domain *sd, - enum cpu_idle_type idle) -{ - int load_idx; - - switch (idle) { - case CPU_NOT_IDLE: - load_idx = sd->busy_idx; - break; - - case CPU_NEWLY_IDLE: - load_idx = sd->newidle_idx; - break; - default: - load_idx = sd->idle_idx; - break; - } - - return load_idx; -} - -static unsigned long scale_rt_capacity(int cpu) -{ - struct rq *rq = cpu_rq(cpu); - u64 total, used, age_stamp, avg; - s64 delta; - - /* - * Since we're reading these variables without serialization make sure - * we read them once before doing sanity checks on them. - */ - age_stamp = READ_ONCE(rq->age_stamp); - avg = READ_ONCE(rq->rt_avg); - delta = __rq_clock_broken(rq) - age_stamp; - - if (unlikely(delta < 0)) - delta = 0; - - total = sched_avg_period() + delta; - - used = div_u64(avg, total); - - if (likely(used < SCHED_CAPACITY_SCALE)) - return SCHED_CAPACITY_SCALE - used; - - return 1; -} - -static void update_cpu_capacity(struct sched_domain *sd, int cpu) -{ - unsigned long capacity = arch_scale_cpu_capacity(sd, cpu); - struct sched_group *sdg = sd->groups; - - cpu_rq(cpu)->cpu_capacity_orig = capacity; - - capacity *= scale_rt_capacity(cpu); - capacity >>= SCHED_CAPACITY_SHIFT; - - if (!capacity) - capacity = 1; - - cpu_rq(cpu)->cpu_capacity = capacity; - sdg->sgc->capacity = capacity; -} - -void update_group_capacity(struct sched_domain *sd, int cpu) -{ - struct sched_domain *child = sd->child; - struct sched_group *group, *sdg = sd->groups; - unsigned long capacity; - unsigned long interval; - - interval = msecs_to_jiffies(sd->balance_interval); - interval = clamp(interval, 1UL, max_load_balance_interval); - sdg->sgc->next_update = jiffies + interval; - - if (!child) { - update_cpu_capacity(sd, cpu); - return; - } - - capacity = 0; - - if (child->flags & SD_OVERLAP) { - /* - * SD_OVERLAP domains cannot assume that child groups - * span the current group. - */ - - for_each_cpu(cpu, sched_group_cpus(sdg)) { - struct sched_group_capacity *sgc; - struct rq *rq = cpu_rq(cpu); - - /* - * build_sched_domains() -> init_sched_groups_capacity() - * gets here before we've attached the domains to the - * runqueues. - * - * Use capacity_of(), which is set irrespective of domains - * in update_cpu_capacity(). - * - * This avoids capacity from being 0 and - * causing divide-by-zero issues on boot. - */ - if (unlikely(!rq->sd)) { - capacity += capacity_of(cpu); - continue; - } - - sgc = rq->sd->groups->sgc; - capacity += sgc->capacity; - } - } else { - /* - * !SD_OVERLAP domains can assume that child groups - * span the current group. - */ - - group = child->groups; - do { - capacity += group->sgc->capacity; - group = group->next; - } while (group != child->groups); - } - - sdg->sgc->capacity = capacity; -} - -/* - * Check whether the capacity of the rq has been noticeably reduced by side - * activity. The imbalance_pct is used for the threshold. - * Return true is the capacity is reduced - */ -static inline int -check_cpu_capacity(struct rq *rq, struct sched_domain *sd) -{ - return ((rq->cpu_capacity * sd->imbalance_pct) < - (rq->cpu_capacity_orig * 100)); -} - -/* - * Group imbalance indicates (and tries to solve) the problem where balancing - * groups is inadequate due to tsk_cpus_allowed() constraints. - * - * Imagine a situation of two groups of 4 cpus each and 4 tasks each with a - * cpumask covering 1 cpu of the first group and 3 cpus of the second group. - * Something like: - * - * { 0 1 2 3 } { 4 5 6 7 } - * * * * * - * - * If we were to balance group-wise we'd place two tasks in the first group and - * two tasks in the second group. Clearly this is undesired as it will overload - * cpu 3 and leave one of the cpus in the second group unused. - * - * The current solution to this issue is detecting the skew in the first group - * by noticing the lower domain failed to reach balance and had difficulty - * moving tasks due to affinity constraints. - * - * When this is so detected; this group becomes a candidate for busiest; see - * update_sd_pick_busiest(). And calculate_imbalance() and - * find_busiest_group() avoid some of the usual balance conditions to allow it - * to create an effective group imbalance. - * - * This is a somewhat tricky proposition since the next run might not find the - * group imbalance and decide the groups need to be balanced again. A most - * subtle and fragile situation. - */ - -static inline int sg_imbalanced(struct sched_group *group) -{ - return group->sgc->imbalance; -} - -/* - * group_has_capacity returns true if the group has spare capacity that could - * be used by some tasks. - * We consider that a group has spare capacity if the * number of task is - * smaller than the number of CPUs or if the utilization is lower than the - * available capacity for CFS tasks. - * For the latter, we use a threshold to stabilize the state, to take into - * account the variance of the tasks' load and to return true if the available - * capacity in meaningful for the load balancer. - * As an example, an available capacity of 1% can appear but it doesn't make - * any benefit for the load balance. - */ -static inline bool -group_has_capacity(struct lb_env *env, struct sg_lb_stats *sgs) -{ - if (sgs->sum_nr_running < sgs->group_weight) - return true; - - if ((sgs->group_capacity * 100) > - (sgs->group_util * env->sd->imbalance_pct)) - return true; - - return false; -} - -/* - * group_is_overloaded returns true if the group has more tasks than it can - * handle. - * group_is_overloaded is not equals to !group_has_capacity because a group - * with the exact right number of tasks, has no more spare capacity but is not - * overloaded so both group_has_capacity and group_is_overloaded return - * false. - */ -static inline bool -group_is_overloaded(struct lb_env *env, struct sg_lb_stats *sgs) -{ - if (sgs->sum_nr_running <= sgs->group_weight) - return false; - - if ((sgs->group_capacity * 100) < - (sgs->group_util * env->sd->imbalance_pct)) - return true; - - return false; -} - -static inline enum -group_type group_classify(struct sched_group *group, - struct sg_lb_stats *sgs) -{ - if (sgs->group_no_capacity) - return group_overloaded; - - if (sg_imbalanced(group)) - return group_imbalanced; - - return group_other; -} - -/** - * update_sg_lb_stats - Update sched_group's statistics for load balancing. - * @env: The load balancing environment. - * @group: sched_group whose statistics are to be updated. - * @load_idx: Load index of sched_domain of this_cpu for load calc. - * @local_group: Does group contain this_cpu. - * @sgs: variable to hold the statistics for this group. - * @overload: Indicate more than one runnable task for any CPU. - */ -static inline void update_sg_lb_stats(struct lb_env *env, - struct sched_group *group, int load_idx, - int local_group, struct sg_lb_stats *sgs, - bool *overload) -{ - unsigned long load; - int i, nr_running; - - memset(sgs, 0, sizeof(*sgs)); - - for_each_cpu_and(i, sched_group_cpus(group), env->cpus) { - struct rq *rq = cpu_rq(i); - - /* Bias balancing toward cpus of our domain */ - if (local_group) - load = target_load(i, load_idx); - else - load = source_load(i, load_idx); - - sgs->group_load += load; - sgs->group_util += cpu_util(i); - sgs->sum_nr_running += rq->cfs.h_nr_running; - - nr_running = rq->nr_running; - if (nr_running > 1) - *overload = true; - -#ifdef CONFIG_NUMA_BALANCING - sgs->nr_numa_running += rq->nr_numa_running; - sgs->nr_preferred_running += rq->nr_preferred_running; -#endif - sgs->sum_weighted_load += weighted_cpuload(i); - /* - * No need to call idle_cpu() if nr_running is not 0 - */ - if (!nr_running && idle_cpu(i)) - sgs->idle_cpus++; - } - - /* Adjust by relative CPU capacity of the group */ - sgs->group_capacity = group->sgc->capacity; - sgs->avg_load = (sgs->group_load*SCHED_CAPACITY_SCALE) / sgs->group_capacity; - - if (sgs->sum_nr_running) - sgs->load_per_task = sgs->sum_weighted_load / sgs->sum_nr_running; - - sgs->group_weight = group->group_weight; - - sgs->group_no_capacity = group_is_overloaded(env, sgs); - sgs->group_type = group_classify(group, sgs); -} - -/** - * update_sd_pick_busiest - return 1 on busiest group - * @env: The load balancing environment. - * @sds: sched_domain statistics - * @sg: sched_group candidate to be checked for being the busiest - * @sgs: sched_group statistics - * - * Determine if @sg is a busier group than the previously selected - * busiest group. - * - * Return: %true if @sg is a busier group than the previously selected - * busiest group. %false otherwise. - */ -static bool update_sd_pick_busiest(struct lb_env *env, - struct sd_lb_stats *sds, - struct sched_group *sg, - struct sg_lb_stats *sgs) -{ - struct sg_lb_stats *busiest = &sds->busiest_stat; - - if (sgs->group_type > busiest->group_type) - return true; - - if (sgs->group_type < busiest->group_type) - return false; - - if (sgs->avg_load <= busiest->avg_load) - return false; - - /* This is the busiest node in its class. */ - if (!(env->sd->flags & SD_ASYM_PACKING)) - return true; - - /* No ASYM_PACKING if target cpu is already busy */ - if (env->idle == CPU_NOT_IDLE) - return true; - /* - * ASYM_PACKING needs to move all the work to the lowest - * numbered CPUs in the group, therefore mark all groups - * higher than ourself as busy. - */ - if (sgs->sum_nr_running && env->dst_cpu < group_first_cpu(sg)) { - if (!sds->busiest) - return true; - - /* Prefer to move from highest possible cpu's work */ - if (group_first_cpu(sds->busiest) < group_first_cpu(sg)) - return true; - } - - return false; -} - -#ifdef CONFIG_NUMA_BALANCING -static inline enum fbq_type fbq_classify_group(struct sg_lb_stats *sgs) -{ - if (sgs->sum_nr_running > sgs->nr_numa_running) - return regular; - if (sgs->sum_nr_running > sgs->nr_preferred_running) - return remote; - return all; -} - -static inline enum fbq_type fbq_classify_rq(struct rq *rq) -{ - if (rq->nr_running > rq->nr_numa_running) - return regular; - if (rq->nr_running > rq->nr_preferred_running) - return remote; - return all; -} -#else -static inline enum fbq_type fbq_classify_group(struct sg_lb_stats *sgs) -{ - return all; -} - -static inline enum fbq_type fbq_classify_rq(struct rq *rq) -{ - return regular; -} -#endif /* CONFIG_NUMA_BALANCING */ - -/** - * update_sd_lb_stats - Update sched_domain's statistics for load balancing. - * @env: The load balancing environment. - * @sds: variable to hold the statistics for this sched_domain. - */ -static inline void update_sd_lb_stats(struct lb_env *env, struct sd_lb_stats *sds) -{ - struct sched_domain *child = env->sd->child; - struct sched_group *sg = env->sd->groups; - struct sg_lb_stats tmp_sgs; - int load_idx, prefer_sibling = 0; - bool overload = false; - - if (child && child->flags & SD_PREFER_SIBLING) - prefer_sibling = 1; - - load_idx = get_sd_load_idx(env->sd, env->idle); - - do { - struct sg_lb_stats *sgs = &tmp_sgs; - int local_group; - - local_group = cpumask_test_cpu(env->dst_cpu, sched_group_cpus(sg)); - if (local_group) { - sds->local = sg; - sgs = &sds->local_stat; - - if (env->idle != CPU_NEWLY_IDLE || - time_after_eq(jiffies, sg->sgc->next_update)) - update_group_capacity(env->sd, env->dst_cpu); - } - - update_sg_lb_stats(env, sg, load_idx, local_group, sgs, - &overload); - - if (local_group) - goto next_group; - - /* - * In case the child domain prefers tasks go to siblings - * first, lower the sg capacity so that we'll try - * and move all the excess tasks away. We lower the capacity - * of a group only if the local group has the capacity to fit - * these excess tasks. The extra check prevents the case where - * you always pull from the heaviest group when it is already - * under-utilized (possible with a large weight task outweighs - * the tasks on the system). - */ - if (prefer_sibling && sds->local && - group_has_capacity(env, &sds->local_stat) && - (sgs->sum_nr_running > 1)) { - sgs->group_no_capacity = 1; - sgs->group_type = group_classify(sg, sgs); - } - - if (update_sd_pick_busiest(env, sds, sg, sgs)) { - sds->busiest = sg; - sds->busiest_stat = *sgs; - } - -next_group: - /* Now, start updating sd_lb_stats */ - sds->total_load += sgs->group_load; - sds->total_capacity += sgs->group_capacity; - - sg = sg->next; - } while (sg != env->sd->groups); - - if (env->sd->flags & SD_NUMA) - env->fbq_type = fbq_classify_group(&sds->busiest_stat); - - if (!env->sd->parent) { - /* update overload indicator if we are at root domain */ - if (env->dst_rq->rd->overload != overload) - env->dst_rq->rd->overload = overload; - } - -} - -/** - * check_asym_packing - Check to see if the group is packed into the - * sched doman. - * - * This is primarily intended to used at the sibling level. Some - * cores like POWER7 prefer to use lower numbered SMT threads. In the - * case of POWER7, it can move to lower SMT modes only when higher - * threads are idle. When in lower SMT modes, the threads will - * perform better since they share less core resources. Hence when we - * have idle threads, we want them to be the higher ones. - * - * This packing function is run on idle threads. It checks to see if - * the busiest CPU in this domain (core in the P7 case) has a higher - * CPU number than the packing function is being run on. Here we are - * assuming lower CPU number will be equivalent to lower a SMT thread - * number. - * - * Return: 1 when packing is required and a task should be moved to - * this CPU. The amount of the imbalance is returned in *imbalance. - * - * @env: The load balancing environment. - * @sds: Statistics of the sched_domain which is to be packed - */ -static int check_asym_packing(struct lb_env *env, struct sd_lb_stats *sds) -{ - int busiest_cpu; - - if (!(env->sd->flags & SD_ASYM_PACKING)) - return 0; - - if (env->idle == CPU_NOT_IDLE) - return 0; - - if (!sds->busiest) - return 0; - - busiest_cpu = group_first_cpu(sds->busiest); - if (env->dst_cpu > busiest_cpu) - return 0; - - env->imbalance = DIV_ROUND_CLOSEST( - sds->busiest_stat.avg_load * sds->busiest_stat.group_capacity, - SCHED_CAPACITY_SCALE); - - return 1; -} - -/** - * fix_small_imbalance - Calculate the minor imbalance that exists - * amongst the groups of a sched_domain, during - * load balancing. - * @env: The load balancing environment. - * @sds: Statistics of the sched_domain whose imbalance is to be calculated. - */ -static inline -void fix_small_imbalance(struct lb_env *env, struct sd_lb_stats *sds) -{ - unsigned long tmp, capa_now = 0, capa_move = 0; - unsigned int imbn = 2; - unsigned long scaled_busy_load_per_task; - struct sg_lb_stats *local, *busiest; - - local = &sds->local_stat; - busiest = &sds->busiest_stat; - - if (!local->sum_nr_running) - local->load_per_task = cpu_avg_load_per_task(env->dst_cpu); - else if (busiest->load_per_task > local->load_per_task) - imbn = 1; - - scaled_busy_load_per_task = - (busiest->load_per_task * SCHED_CAPACITY_SCALE) / - busiest->group_capacity; - - if (busiest->avg_load + scaled_busy_load_per_task >= - local->avg_load + (scaled_busy_load_per_task * imbn)) { - env->imbalance = busiest->load_per_task; - return; - } - - /* - * OK, we don't have enough imbalance to justify moving tasks, - * however we may be able to increase total CPU capacity used by - * moving them. - */ - - capa_now += busiest->group_capacity * - min(busiest->load_per_task, busiest->avg_load); - capa_now += local->group_capacity * - min(local->load_per_task, local->avg_load); - capa_now /= SCHED_CAPACITY_SCALE; - - /* Amount of load we'd subtract */ - if (busiest->avg_load > scaled_busy_load_per_task) { - capa_move += busiest->group_capacity * - min(busiest->load_per_task, - busiest->avg_load - scaled_busy_load_per_task); - } - - /* Amount of load we'd add */ - if (busiest->avg_load * busiest->group_capacity < - busiest->load_per_task * SCHED_CAPACITY_SCALE) { - tmp = (busiest->avg_load * busiest->group_capacity) / - local->group_capacity; - } else { - tmp = (busiest->load_per_task * SCHED_CAPACITY_SCALE) / - local->group_capacity; - } - capa_move += local->group_capacity * - min(local->load_per_task, local->avg_load + tmp); - capa_move /= SCHED_CAPACITY_SCALE; - - /* Move if we gain throughput */ - if (capa_move > capa_now) - env->imbalance = busiest->load_per_task; -} - -/** - * calculate_imbalance - Calculate the amount of imbalance present within the - * groups of a given sched_domain during load balance. - * @env: load balance environment - * @sds: statistics of the sched_domain whose imbalance is to be calculated. - */ -static inline void calculate_imbalance(struct lb_env *env, struct sd_lb_stats *sds) -{ - unsigned long max_pull, load_above_capacity = ~0UL; - struct sg_lb_stats *local, *busiest; - - local = &sds->local_stat; - busiest = &sds->busiest_stat; - - if (busiest->group_type == group_imbalanced) { - /* - * In the group_imb case we cannot rely on group-wide averages - * to ensure cpu-load equilibrium, look at wider averages. XXX - */ - busiest->load_per_task = - min(busiest->load_per_task, sds->avg_load); - } - - /* - * Avg load of busiest sg can be less and avg load of local sg can - * be greater than avg load across all sgs of sd because avg load - * factors in sg capacity and sgs with smaller group_type are - * skipped when updating the busiest sg: - */ - if (busiest->avg_load <= sds->avg_load || - local->avg_load >= sds->avg_load) { - env->imbalance = 0; - return fix_small_imbalance(env, sds); - } - - /* - * If there aren't any idle cpus, avoid creating some. - */ - if (busiest->group_type == group_overloaded && - local->group_type == group_overloaded) { - load_above_capacity = busiest->sum_nr_running * SCHED_CAPACITY_SCALE; - if (load_above_capacity > busiest->group_capacity) { - load_above_capacity -= busiest->group_capacity; - load_above_capacity *= scale_load_down(NICE_0_LOAD); - load_above_capacity /= busiest->group_capacity; - } else - load_above_capacity = ~0UL; - } - - /* - * We're trying to get all the cpus to the average_load, so we don't - * want to push ourselves above the average load, nor do we wish to - * reduce the max loaded cpu below the average load. At the same time, - * we also don't want to reduce the group load below the group - * capacity. Thus we look for the minimum possible imbalance. - */ - max_pull = min(busiest->avg_load - sds->avg_load, load_above_capacity); - - /* How much load to actually move to equalise the imbalance */ - env->imbalance = min( - max_pull * busiest->group_capacity, - (sds->avg_load - local->avg_load) * local->group_capacity - ) / SCHED_CAPACITY_SCALE; - - /* - * if *imbalance is less than the average load per runnable task - * there is no guarantee that any tasks will be moved so we'll have - * a think about bumping its value to force at least one task to be - * moved - */ - if (env->imbalance < busiest->load_per_task) - return fix_small_imbalance(env, sds); -} - -/******* find_busiest_group() helpers end here *********************/ - -/** - * find_busiest_group - Returns the busiest group within the sched_domain - * if there is an imbalance. - * - * Also calculates the amount of weighted load which should be moved - * to restore balance. - * - * @env: The load balancing environment. - * - * Return: - The busiest group if imbalance exists. - */ -static struct sched_group *find_busiest_group(struct lb_env *env) -{ - struct sg_lb_stats *local, *busiest; - struct sd_lb_stats sds; - - init_sd_lb_stats(&sds); - - /* - * Compute the various statistics relavent for load balancing at - * this level. - */ - update_sd_lb_stats(env, &sds); - local = &sds.local_stat; - busiest = &sds.busiest_stat; - - /* ASYM feature bypasses nice load balance check */ - if (check_asym_packing(env, &sds)) - return sds.busiest; - - /* There is no busy sibling group to pull tasks from */ - if (!sds.busiest || busiest->sum_nr_running == 0) - goto out_balanced; - - sds.avg_load = (SCHED_CAPACITY_SCALE * sds.total_load) - / sds.total_capacity; - - /* - * If the busiest group is imbalanced the below checks don't - * work because they assume all things are equal, which typically - * isn't true due to cpus_allowed constraints and the like. - */ - if (busiest->group_type == group_imbalanced) - goto force_balance; - - /* SD_BALANCE_NEWIDLE trumps SMP nice when underutilized */ - if (env->idle == CPU_NEWLY_IDLE && group_has_capacity(env, local) && - busiest->group_no_capacity) - goto force_balance; - - /* - * If the local group is busier than the selected busiest group - * don't try and pull any tasks. - */ - if (local->avg_load >= busiest->avg_load) - goto out_balanced; - - /* - * Don't pull any tasks if this group is already above the domain - * average load. - */ - if (local->avg_load >= sds.avg_load) - goto out_balanced; - - if (env->idle == CPU_IDLE) { - /* - * This cpu is idle. If the busiest group is not overloaded - * and there is no imbalance between this and busiest group - * wrt idle cpus, it is balanced. The imbalance becomes - * significant if the diff is greater than 1 otherwise we - * might end up to just move the imbalance on another group - */ - if ((busiest->group_type != group_overloaded) && - (local->idle_cpus <= (busiest->idle_cpus + 1))) - goto out_balanced; - } else { - /* - * In the CPU_NEWLY_IDLE, CPU_NOT_IDLE cases, use - * imbalance_pct to be conservative. - */ - if (100 * busiest->avg_load <= - env->sd->imbalance_pct * local->avg_load) - goto out_balanced; - } - -force_balance: - /* Looks like there is an imbalance. Compute it */ - calculate_imbalance(env, &sds); - return sds.busiest; - -out_balanced: - env->imbalance = 0; - return NULL; -} - -/* - * find_busiest_queue - find the busiest runqueue among the cpus in group. - */ -static struct rq *find_busiest_queue(struct lb_env *env, - struct sched_group *group) -{ - struct rq *busiest = NULL, *rq; - unsigned long busiest_load = 0, busiest_capacity = 1; - int i; - - for_each_cpu_and(i, sched_group_cpus(group), env->cpus) { - unsigned long capacity, wl; - enum fbq_type rt; - - rq = cpu_rq(i); - rt = fbq_classify_rq(rq); - - /* - * We classify groups/runqueues into three groups: - * - regular: there are !numa tasks - * - remote: there are numa tasks that run on the 'wrong' node - * - all: there is no distinction - * - * In order to avoid migrating ideally placed numa tasks, - * ignore those when there's better options. - * - * If we ignore the actual busiest queue to migrate another - * task, the next balance pass can still reduce the busiest - * queue by moving tasks around inside the node. - * - * If we cannot move enough load due to this classification - * the next pass will adjust the group classification and - * allow migration of more tasks. - * - * Both cases only affect the total convergence complexity. - */ - if (rt > env->fbq_type) - continue; - - capacity = capacity_of(i); - - wl = weighted_cpuload(i); - - /* - * When comparing with imbalance, use weighted_cpuload() - * which is not scaled with the cpu capacity. - */ - - if (rq->nr_running == 1 && wl > env->imbalance && - !check_cpu_capacity(rq, env->sd)) - continue; - - /* - * For the load comparisons with the other cpu's, consider - * the weighted_cpuload() scaled with the cpu capacity, so - * that the load can be moved away from the cpu that is - * potentially running at a lower capacity. - * - * Thus we're looking for max(wl_i / capacity_i), crosswise - * multiplication to rid ourselves of the division works out - * to: wl_i * capacity_j > wl_j * capacity_i; where j is - * our previous maximum. - */ - if (wl * busiest_capacity > busiest_load * capacity) { - busiest_load = wl; - busiest_capacity = capacity; - busiest = rq; - } - } - - return busiest; -} - -/* - * Max backoff if we encounter pinned tasks. Pretty arbitrary value, but - * so long as it is large enough. - */ -#define MAX_PINNED_INTERVAL 512 - -static int need_active_balance(struct lb_env *env) -{ - struct sched_domain *sd = env->sd; - - if (env->idle == CPU_NEWLY_IDLE) { - - /* - * ASYM_PACKING needs to force migrate tasks from busy but - * higher numbered CPUs in order to pack all tasks in the - * lowest numbered CPUs. - */ - if ((sd->flags & SD_ASYM_PACKING) && env->src_cpu > env->dst_cpu) - return 1; - } - - /* - * The dst_cpu is idle and the src_cpu CPU has only 1 CFS task. - * It's worth migrating the task if the src_cpu's capacity is reduced - * because of other sched_class or IRQs if more capacity stays - * available on dst_cpu. - */ - if ((env->idle != CPU_NOT_IDLE) && - (env->src_rq->cfs.h_nr_running == 1)) { - if ((check_cpu_capacity(env->src_rq, sd)) && - (capacity_of(env->src_cpu)*sd->imbalance_pct < capacity_of(env->dst_cpu)*100)) - return 1; - } - - return unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2); -} - -static int active_load_balance_cpu_stop(void *data); - -static int should_we_balance(struct lb_env *env) -{ - struct sched_group *sg = env->sd->groups; - struct cpumask *sg_cpus, *sg_mask; - int cpu, balance_cpu = -1; - - /* - * In the newly idle case, we will allow all the cpu's - * to do the newly idle load balance. - */ - if (env->idle == CPU_NEWLY_IDLE) - return 1; - - sg_cpus = sched_group_cpus(sg); - sg_mask = sched_group_mask(sg); - /* Try to find first idle cpu */ - for_each_cpu_and(cpu, sg_cpus, env->cpus) { - if (!cpumask_test_cpu(cpu, sg_mask) || !idle_cpu(cpu)) - continue; - - balance_cpu = cpu; - break; - } - - if (balance_cpu == -1) - balance_cpu = group_balance_cpu(sg); - - /* - * First idle cpu or the first cpu(busiest) in this sched group - * is eligible for doing load balancing at this and above domains. - */ - return balance_cpu == env->dst_cpu; -} - -/* - * Check this_cpu to ensure it is balanced within domain. Attempt to move - * tasks if there is an imbalance. - */ -static int load_balance(int this_cpu, struct rq *this_rq, - struct sched_domain *sd, enum cpu_idle_type idle, - int *continue_balancing) -{ - int ld_moved, cur_ld_moved, active_balance = 0; - struct sched_domain *sd_parent = sd->parent; - struct sched_group *group; - struct rq *busiest; - unsigned long flags; - struct cpumask *cpus = this_cpu_cpumask_var_ptr(load_balance_mask); - - struct lb_env env = { - .sd = sd, - .dst_cpu = this_cpu, - .dst_rq = this_rq, - .dst_grpmask = sched_group_cpus(sd->groups), - .idle = idle, - .loop_break = sched_nr_migrate_break, - .cpus = cpus, - .fbq_type = all, - .tasks = LIST_HEAD_INIT(env.tasks), - }; - - /* - * For NEWLY_IDLE load_balancing, we don't need to consider - * other cpus in our group - */ - if (idle == CPU_NEWLY_IDLE) - env.dst_grpmask = NULL; - - cpumask_copy(cpus, cpu_active_mask); - - schedstat_inc(sd->lb_count[idle]); - -redo: - if (!should_we_balance(&env)) { - *continue_balancing = 0; - goto out_balanced; - } - - group = find_busiest_group(&env); - if (!group) { - schedstat_inc(sd->lb_nobusyg[idle]); - goto out_balanced; - } - - busiest = find_busiest_queue(&env, group); - if (!busiest) { - schedstat_inc(sd->lb_nobusyq[idle]); - goto out_balanced; - } - - BUG_ON(busiest == env.dst_rq); - - schedstat_add(sd->lb_imbalance[idle], env.imbalance); - - env.src_cpu = busiest->cpu; - env.src_rq = busiest; - - ld_moved = 0; - if (busiest->nr_running > 1) { - /* - * Attempt to move tasks. If find_busiest_group has found - * an imbalance but busiest->nr_running <= 1, the group is - * still unbalanced. ld_moved simply stays zero, so it is - * correctly treated as an imbalance. - */ - env.flags |= LBF_ALL_PINNED; - env.loop_max = min(sysctl_sched_nr_migrate, busiest->nr_running); - -more_balance: - raw_spin_lock_irqsave(&busiest->lock, flags); - - /* - * cur_ld_moved - load moved in current iteration - * ld_moved - cumulative load moved across iterations - */ - cur_ld_moved = detach_tasks(&env); - - /* - * We've detached some tasks from busiest_rq. Every - * task is masked "TASK_ON_RQ_MIGRATING", so we can safely - * unlock busiest->lock, and we are able to be sure - * that nobody can manipulate the tasks in parallel. - * See task_rq_lock() family for the details. - */ - - raw_spin_unlock(&busiest->lock); - - if (cur_ld_moved) { - attach_tasks(&env); - ld_moved += cur_ld_moved; - } - - local_irq_restore(flags); - - if (env.flags & LBF_NEED_BREAK) { - env.flags &= ~LBF_NEED_BREAK; - goto more_balance; - } - - /* - * Revisit (affine) tasks on src_cpu that couldn't be moved to - * us and move them to an alternate dst_cpu in our sched_group - * where they can run. The upper limit on how many times we - * iterate on same src_cpu is dependent on number of cpus in our - * sched_group. - * - * This changes load balance semantics a bit on who can move - * load to a given_cpu. In addition to the given_cpu itself - * (or a ilb_cpu acting on its behalf where given_cpu is - * nohz-idle), we now have balance_cpu in a position to move - * load to given_cpu. In rare situations, this may cause - * conflicts (balance_cpu and given_cpu/ilb_cpu deciding - * _independently_ and at _same_ time to move some load to - * given_cpu) causing exceess load to be moved to given_cpu. - * This however should not happen so much in practice and - * moreover subsequent load balance cycles should correct the - * excess load moved. - */ - if ((env.flags & LBF_DST_PINNED) && env.imbalance > 0) { - - /* Prevent to re-select dst_cpu via env's cpus */ - cpumask_clear_cpu(env.dst_cpu, env.cpus); - - env.dst_rq = cpu_rq(env.new_dst_cpu); - env.dst_cpu = env.new_dst_cpu; - env.flags &= ~LBF_DST_PINNED; - env.loop = 0; - env.loop_break = sched_nr_migrate_break; - - /* - * Go back to "more_balance" rather than "redo" since we - * need to continue with same src_cpu. - */ - goto more_balance; - } - - /* - * We failed to reach balance because of affinity. - */ - if (sd_parent) { - int *group_imbalance = &sd_parent->groups->sgc->imbalance; - - if ((env.flags & LBF_SOME_PINNED) && env.imbalance > 0) - *group_imbalance = 1; - } - - /* All tasks on this runqueue were pinned by CPU affinity */ - if (unlikely(env.flags & LBF_ALL_PINNED)) { - cpumask_clear_cpu(cpu_of(busiest), cpus); - if (!cpumask_empty(cpus)) { - env.loop = 0; - env.loop_break = sched_nr_migrate_break; - goto redo; - } - goto out_all_pinned; - } - } - - if (!ld_moved) { - schedstat_inc(sd->lb_failed[idle]); - /* - * Increment the failure counter only on periodic balance. - * We do not want newidle balance, which can be very - * frequent, pollute the failure counter causing - * excessive cache_hot migrations and active balances. - */ - if (idle != CPU_NEWLY_IDLE) - sd->nr_balance_failed++; - - if (need_active_balance(&env)) { - raw_spin_lock_irqsave(&busiest->lock, flags); - - /* don't kick the active_load_balance_cpu_stop, - * if the curr task on busiest cpu can't be - * moved to this_cpu - */ - if (!cpumask_test_cpu(this_cpu, - tsk_cpus_allowed(busiest->curr))) { - raw_spin_unlock_irqrestore(&busiest->lock, - flags); - env.flags |= LBF_ALL_PINNED; - goto out_one_pinned; - } - - /* - * ->active_balance synchronizes accesses to - * ->active_balance_work. Once set, it's cleared - * only after active load balance is finished. - */ - if (!busiest->active_balance) { - busiest->active_balance = 1; - busiest->push_cpu = this_cpu; - active_balance = 1; - } - raw_spin_unlock_irqrestore(&busiest->lock, flags); - - if (active_balance) { - stop_one_cpu_nowait(cpu_of(busiest), - active_load_balance_cpu_stop, busiest, - &busiest->active_balance_work); - } - - /* We've kicked active balancing, force task migration. */ - sd->nr_balance_failed = sd->cache_nice_tries+1; - } - } else - sd->nr_balance_failed = 0; - - if (likely(!active_balance)) { - /* We were unbalanced, so reset the balancing interval */ - sd->balance_interval = sd->min_interval; - } else { - /* - * If we've begun active balancing, start to back off. This - * case may not be covered by the all_pinned logic if there - * is only 1 task on the busy runqueue (because we don't call - * detach_tasks). - */ - if (sd->balance_interval < sd->max_interval) - sd->balance_interval *= 2; - } - - goto out; - -out_balanced: - /* - * We reach balance although we may have faced some affinity - * constraints. Clear the imbalance flag if it was set. - */ - if (sd_parent) { - int *group_imbalance = &sd_parent->groups->sgc->imbalance; - - if (*group_imbalance) - *group_imbalance = 0; - } - -out_all_pinned: - /* - * We reach balance because all tasks are pinned at this level so - * we can't migrate them. Let the imbalance flag set so parent level - * can try to migrate them. - */ - schedstat_inc(sd->lb_balanced[idle]); - - sd->nr_balance_failed = 0; - -out_one_pinned: - /* tune up the balancing interval */ - if (((env.flags & LBF_ALL_PINNED) && - sd->balance_interval < MAX_PINNED_INTERVAL) || - (sd->balance_interval < sd->max_interval)) - sd->balance_interval *= 2; - - ld_moved = 0; -out: - return ld_moved; -} - -static inline unsigned long -get_sd_balance_interval(struct sched_domain *sd, int cpu_busy) -{ - unsigned long interval = sd->balance_interval; - - if (cpu_busy) - interval *= sd->busy_factor; - - /* scale ms to jiffies */ - interval = msecs_to_jiffies(interval); - interval = clamp(interval, 1UL, max_load_balance_interval); - - return interval; -} - -static inline void -update_next_balance(struct sched_domain *sd, unsigned long *next_balance) -{ - unsigned long interval, next; - - /* used by idle balance, so cpu_busy = 0 */ - interval = get_sd_balance_interval(sd, 0); - next = sd->last_balance + interval; - - if (time_after(*next_balance, next)) - *next_balance = next; -} - -/* - * idle_balance is called by schedule() if this_cpu is about to become - * idle. Attempts to pull tasks from other CPUs. - */ -static int idle_balance(struct rq *this_rq) -{ - unsigned long next_balance = jiffies + HZ; - int this_cpu = this_rq->cpu; - struct sched_domain *sd; - int pulled_task = 0; - u64 curr_cost = 0; - - /* - * We must set idle_stamp _before_ calling idle_balance(), such that we - * measure the duration of idle_balance() as idle time. - */ - this_rq->idle_stamp = rq_clock(this_rq); - - if (this_rq->avg_idle < sysctl_sched_migration_cost || - !this_rq->rd->overload) { - rcu_read_lock(); - sd = rcu_dereference_check_sched_domain(this_rq->sd); - if (sd) - update_next_balance(sd, &next_balance); - rcu_read_unlock(); - - goto out; - } - - raw_spin_unlock(&this_rq->lock); - - update_blocked_averages(this_cpu); - rcu_read_lock(); - for_each_domain(this_cpu, sd) { - int continue_balancing = 1; - u64 t0, domain_cost; - - if (!(sd->flags & SD_LOAD_BALANCE)) - continue; - - if (this_rq->avg_idle < curr_cost + sd->max_newidle_lb_cost) { - update_next_balance(sd, &next_balance); - break; - } - - if (sd->flags & SD_BALANCE_NEWIDLE) { - t0 = sched_clock_cpu(this_cpu); - - pulled_task = load_balance(this_cpu, this_rq, - sd, CPU_NEWLY_IDLE, - &continue_balancing); - - domain_cost = sched_clock_cpu(this_cpu) - t0; - if (domain_cost > sd->max_newidle_lb_cost) - sd->max_newidle_lb_cost = domain_cost; - - curr_cost += domain_cost; - } - - update_next_balance(sd, &next_balance); - - /* - * Stop searching for tasks to pull if there are - * now runnable tasks on this rq. - */ - if (pulled_task || this_rq->nr_running > 0) - break; - } - rcu_read_unlock(); - - raw_spin_lock(&this_rq->lock); - - if (curr_cost > this_rq->max_idle_balance_cost) - this_rq->max_idle_balance_cost = curr_cost; - - /* - * While browsing the domains, we released the rq lock, a task could - * have been enqueued in the meantime. Since we're not going idle, - * pretend we pulled a task. - */ - if (this_rq->cfs.h_nr_running && !pulled_task) - pulled_task = 1; - -out: - /* Move the next balance forward */ - if (time_after(this_rq->next_balance, next_balance)) - this_rq->next_balance = next_balance; - - /* Is there a task of a high priority class? */ - if (this_rq->nr_running != this_rq->cfs.h_nr_running) - pulled_task = -1; - - if (pulled_task) - this_rq->idle_stamp = 0; - - return pulled_task; -} - -/* - * active_load_balance_cpu_stop is run by cpu stopper. It pushes - * running tasks off the busiest CPU onto idle CPUs. It requires at - * least 1 task to be running on each physical CPU where possible, and - * avoids physical / logical imbalances. - */ -static int active_load_balance_cpu_stop(void *data) -{ - struct rq *busiest_rq = data; - int busiest_cpu = cpu_of(busiest_rq); - int target_cpu = busiest_rq->push_cpu; - struct rq *target_rq = cpu_rq(target_cpu); - struct sched_domain *sd; - struct task_struct *p = NULL; - - raw_spin_lock_irq(&busiest_rq->lock); - - /* make sure the requested cpu hasn't gone down in the meantime */ - if (unlikely(busiest_cpu != smp_processor_id() || - !busiest_rq->active_balance)) - goto out_unlock; - - /* Is there any task to move? */ - if (busiest_rq->nr_running <= 1) - goto out_unlock; - - /* - * This condition is "impossible", if it occurs - * we need to fix it. Originally reported by - * Bjorn Helgaas on a 128-cpu setup. - */ - BUG_ON(busiest_rq == target_rq); - - /* Search for an sd spanning us and the target CPU. */ - rcu_read_lock(); - for_each_domain(target_cpu, sd) { - if ((sd->flags & SD_LOAD_BALANCE) && - cpumask_test_cpu(busiest_cpu, sched_domain_span(sd))) - break; - } - - if (likely(sd)) { - struct lb_env env = { - .sd = sd, - .dst_cpu = target_cpu, - .dst_rq = target_rq, - .src_cpu = busiest_rq->cpu, - .src_rq = busiest_rq, - .idle = CPU_IDLE, - }; - - schedstat_inc(sd->alb_count); - - p = detach_one_task(&env); - if (p) { - schedstat_inc(sd->alb_pushed); - /* Active balancing done, reset the failure counter. */ - sd->nr_balance_failed = 0; - } else { - schedstat_inc(sd->alb_failed); - } - } - rcu_read_unlock(); -out_unlock: - busiest_rq->active_balance = 0; - raw_spin_unlock(&busiest_rq->lock); - - if (p) - attach_one_task(target_rq, p); - - local_irq_enable(); - - return 0; -} - -static inline int on_null_domain(struct rq *rq) -{ - return unlikely(!rcu_dereference_sched(rq->sd)); -} - -#ifdef CONFIG_NO_HZ_COMMON -/* - * idle load balancing details - * - When one of the busy CPUs notice that there may be an idle rebalancing - * needed, they will kick the idle load balancer, which then does idle - * load balancing for all the idle CPUs. - */ -static struct { - cpumask_var_t idle_cpus_mask; - atomic_t nr_cpus; - unsigned long next_balance; /* in jiffy units */ -} nohz ____cacheline_aligned; - -static inline int find_new_ilb(void) -{ - int ilb = cpumask_first(nohz.idle_cpus_mask); - - if (ilb < nr_cpu_ids && idle_cpu(ilb)) - return ilb; - - return nr_cpu_ids; -} - -/* - * Kick a CPU to do the nohz balancing, if it is time for it. We pick the - * nohz_load_balancer CPU (if there is one) otherwise fallback to any idle - * CPU (if there is one). - */ -static void nohz_balancer_kick(void) -{ - int ilb_cpu; - - nohz.next_balance++; - - ilb_cpu = find_new_ilb(); - - if (ilb_cpu >= nr_cpu_ids) - return; - - if (test_and_set_bit(NOHZ_BALANCE_KICK, nohz_flags(ilb_cpu))) - return; - /* - * Use smp_send_reschedule() instead of resched_cpu(). - * This way we generate a sched IPI on the target cpu which - * is idle. And the softirq performing nohz idle load balance - * will be run before returning from the IPI. - */ - smp_send_reschedule(ilb_cpu); - return; -} - -void nohz_balance_exit_idle(unsigned int cpu) -{ - if (unlikely(test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)))) { - /* - * Completely isolated CPUs don't ever set, so we must test. - */ - if (likely(cpumask_test_cpu(cpu, nohz.idle_cpus_mask))) { - cpumask_clear_cpu(cpu, nohz.idle_cpus_mask); - atomic_dec(&nohz.nr_cpus); - } - clear_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)); - } -} - -static inline void set_cpu_sd_state_busy(void) -{ - struct sched_domain *sd; - int cpu = smp_processor_id(); - - rcu_read_lock(); - sd = rcu_dereference(per_cpu(sd_llc, cpu)); - - if (!sd || !sd->nohz_idle) - goto unlock; - sd->nohz_idle = 0; - - atomic_inc(&sd->shared->nr_busy_cpus); -unlock: - rcu_read_unlock(); -} - -void set_cpu_sd_state_idle(void) -{ - struct sched_domain *sd; - int cpu = smp_processor_id(); - - rcu_read_lock(); - sd = rcu_dereference(per_cpu(sd_llc, cpu)); - - if (!sd || sd->nohz_idle) - goto unlock; - sd->nohz_idle = 1; - - atomic_dec(&sd->shared->nr_busy_cpus); -unlock: - rcu_read_unlock(); -} - -/* - * This routine will record that the cpu is going idle with tick stopped. - * This info will be used in performing idle load balancing in the future. - */ -void nohz_balance_enter_idle(int cpu) -{ - /* - * If this cpu is going down, then nothing needs to be done. - */ - if (!cpu_active(cpu)) - return; - - if (test_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu))) - return; - - /* - * If we're a completely isolated CPU, we don't play. - */ - if (on_null_domain(cpu_rq(cpu))) - return; - - cpumask_set_cpu(cpu, nohz.idle_cpus_mask); - atomic_inc(&nohz.nr_cpus); - set_bit(NOHZ_TICK_STOPPED, nohz_flags(cpu)); -} -#endif - -static DEFINE_SPINLOCK(balancing); - -/* - * Scale the max load_balance interval with the number of CPUs in the system. - * This trades load-balance latency on larger machines for less cross talk. - */ -void update_max_interval(void) -{ - max_load_balance_interval = HZ*num_online_cpus()/10; -} - -/* - * It checks each scheduling domain to see if it is due to be balanced, - * and initiates a balancing operation if so. - * - * Balancing parameters are set up in init_sched_domains. - */ -static void rebalance_domains(struct rq *rq, enum cpu_idle_type idle) -{ - int continue_balancing = 1; - int cpu = rq->cpu; - unsigned long interval; - struct sched_domain *sd; - /* Earliest time when we have to do rebalance again */ - unsigned long next_balance = jiffies + 60*HZ; - int update_next_balance = 0; - int need_serialize, need_decay = 0; - u64 max_cost = 0; - - update_blocked_averages(cpu); - - rcu_read_lock(); - for_each_domain(cpu, sd) { - /* - * Decay the newidle max times here because this is a regular - * visit to all the domains. Decay ~1% per second. - */ - if (time_after(jiffies, sd->next_decay_max_lb_cost)) { - sd->max_newidle_lb_cost = - (sd->max_newidle_lb_cost * 253) / 256; - sd->next_decay_max_lb_cost = jiffies + HZ; - need_decay = 1; - } - max_cost += sd->max_newidle_lb_cost; - - if (!(sd->flags & SD_LOAD_BALANCE)) - continue; - - /* - * Stop the load balance at this level. There is another - * CPU in our sched group which is doing load balancing more - * actively. - */ - if (!continue_balancing) { - if (need_decay) - continue; - break; - } - - interval = get_sd_balance_interval(sd, idle != CPU_IDLE); - - need_serialize = sd->flags & SD_SERIALIZE; - if (need_serialize) { - if (!spin_trylock(&balancing)) - goto out; - } - - if (time_after_eq(jiffies, sd->last_balance + interval)) { - if (load_balance(cpu, rq, sd, idle, &continue_balancing)) { - /* - * The LBF_DST_PINNED logic could have changed - * env->dst_cpu, so we can't know our idle - * state even if we migrated tasks. Update it. - */ - idle = idle_cpu(cpu) ? CPU_IDLE : CPU_NOT_IDLE; - } - sd->last_balance = jiffies; - interval = get_sd_balance_interval(sd, idle != CPU_IDLE); - } - if (need_serialize) - spin_unlock(&balancing); -out: - if (time_after(next_balance, sd->last_balance + interval)) { - next_balance = sd->last_balance + interval; - update_next_balance = 1; - } - } - if (need_decay) { - /* - * Ensure the rq-wide value also decays but keep it at a - * reasonable floor to avoid funnies with rq->avg_idle. - */ - rq->max_idle_balance_cost = - max((u64)sysctl_sched_migration_cost, max_cost); - } - rcu_read_unlock(); - - /* - * next_balance will be updated only when there is a need. - * When the cpu is attached to null domain for ex, it will not be - * updated. - */ - if (likely(update_next_balance)) { - rq->next_balance = next_balance; - -#ifdef CONFIG_NO_HZ_COMMON - /* - * If this CPU has been elected to perform the nohz idle - * balance. Other idle CPUs have already rebalanced with - * nohz_idle_balance() and nohz.next_balance has been - * updated accordingly. This CPU is now running the idle load - * balance for itself and we need to update the - * nohz.next_balance accordingly. - */ - if ((idle == CPU_IDLE) && time_after(nohz.next_balance, rq->next_balance)) - nohz.next_balance = rq->next_balance; -#endif - } -} - -#ifdef CONFIG_NO_HZ_COMMON -/* - * In CONFIG_NO_HZ_COMMON case, the idle balance kickee will do the - * rebalancing for all the cpus for whom scheduler ticks are stopped. - */ -static void nohz_idle_balance(struct rq *this_rq, enum cpu_idle_type idle) -{ - int this_cpu = this_rq->cpu; - struct rq *rq; - int balance_cpu; - /* Earliest time when we have to do rebalance again */ - unsigned long next_balance = jiffies + 60*HZ; - int update_next_balance = 0; - - if (idle != CPU_IDLE || - !test_bit(NOHZ_BALANCE_KICK, nohz_flags(this_cpu))) - goto end; - - for_each_cpu(balance_cpu, nohz.idle_cpus_mask) { - if (balance_cpu == this_cpu || !idle_cpu(balance_cpu)) - continue; - - /* - * If this cpu gets work to do, stop the load balancing - * work being done for other cpus. Next load - * balancing owner will pick it up. - */ - if (need_resched()) - break; - - rq = cpu_rq(balance_cpu); - - /* - * If time for next balance is due, - * do the balance. - */ - if (time_after_eq(jiffies, rq->next_balance)) { - raw_spin_lock_irq(&rq->lock); - update_rq_clock(rq); - cpu_load_update_idle(rq); - raw_spin_unlock_irq(&rq->lock); - rebalance_domains(rq, CPU_IDLE); - } - - if (time_after(next_balance, rq->next_balance)) { - next_balance = rq->next_balance; - update_next_balance = 1; - } - } - - /* - * next_balance will be updated only when there is a need. - * When the CPU is attached to null domain for ex, it will not be - * updated. - */ - if (likely(update_next_balance)) - nohz.next_balance = next_balance; -end: - clear_bit(NOHZ_BALANCE_KICK, nohz_flags(this_cpu)); -} - -/* - * Current heuristic for kicking the idle load balancer in the presence - * of an idle cpu in the system. - * - This rq has more than one task. - * - This rq has at least one CFS task and the capacity of the CPU is - * significantly reduced because of RT tasks or IRQs. - * - At parent of LLC scheduler domain level, this cpu's scheduler group has - * multiple busy cpu. - * - For SD_ASYM_PACKING, if the lower numbered cpu's in the scheduler - * domain span are idle. - */ -static inline bool nohz_kick_needed(struct rq *rq) -{ - unsigned long now = jiffies; - struct sched_domain_shared *sds; - struct sched_domain *sd; - int nr_busy, cpu = rq->cpu; - bool kick = false; - - if (unlikely(rq->idle_balance)) - return false; - - /* - * We may be recently in ticked or tickless idle mode. At the first - * busy tick after returning from idle, we will update the busy stats. - */ - set_cpu_sd_state_busy(); - nohz_balance_exit_idle(cpu); - - /* - * None are in tickless mode and hence no need for NOHZ idle load - * balancing. - */ - if (likely(!atomic_read(&nohz.nr_cpus))) - return false; - - if (time_before(now, nohz.next_balance)) - return false; - - if (rq->nr_running >= 2) - return true; - - rcu_read_lock(); - sds = rcu_dereference(per_cpu(sd_llc_shared, cpu)); - if (sds) { - /* - * XXX: write a coherent comment on why we do this. - * See also: http://lkml.kernel.org/r/20111202010832.602203411@sbsiddha-desk.sc.intel.com - */ - nr_busy = atomic_read(&sds->nr_busy_cpus); - if (nr_busy > 1) { - kick = true; - goto unlock; - } - - } - - sd = rcu_dereference(rq->sd); - if (sd) { - if ((rq->cfs.h_nr_running >= 1) && - check_cpu_capacity(rq, sd)) { - kick = true; - goto unlock; - } - } - - sd = rcu_dereference(per_cpu(sd_asym, cpu)); - if (sd && (cpumask_first_and(nohz.idle_cpus_mask, - sched_domain_span(sd)) < cpu)) { - kick = true; - goto unlock; - } - -unlock: - rcu_read_unlock(); - return kick; -} -#else -static void nohz_idle_balance(struct rq *this_rq, enum cpu_idle_type idle) { } -#endif - -/* - * run_rebalance_domains is triggered when needed from the scheduler tick. - * Also triggered for nohz idle balancing (with nohz_balancing_kick set). - */ -static __latent_entropy void run_rebalance_domains(struct softirq_action *h) -{ - struct rq *this_rq = this_rq(); - enum cpu_idle_type idle = this_rq->idle_balance ? - CPU_IDLE : CPU_NOT_IDLE; - - /* - * If this cpu has a pending nohz_balance_kick, then do the - * balancing on behalf of the other idle cpus whose ticks are - * stopped. Do nohz_idle_balance *before* rebalance_domains to - * give the idle cpus a chance to load balance. Else we may - * load balance only within the local sched_domain hierarchy - * and abort nohz_idle_balance altogether if we pull some load. - */ - nohz_idle_balance(this_rq, idle); - rebalance_domains(this_rq, idle); -} - -/* - * Trigger the SCHED_SOFTIRQ if it is time to do periodic load balancing. - */ -void trigger_load_balance(struct rq *rq) -{ - /* Don't need to rebalance while attached to NULL domain */ - if (unlikely(on_null_domain(rq))) - return; - - if (time_after_eq(jiffies, rq->next_balance)) - raise_softirq(SCHED_SOFTIRQ); -#ifdef CONFIG_NO_HZ_COMMON - if (nohz_kick_needed(rq)) - nohz_balancer_kick(); -#endif -} - -static void rq_online_fair(struct rq *rq) -{ - update_sysctl(); - - update_runtime_enabled(rq); -} - -static void rq_offline_fair(struct rq *rq) -{ - update_sysctl(); - - /* Ensure any throttled groups are reachable by pick_next_task */ - unthrottle_offline_cfs_rqs(rq); -} - -#endif /* CONFIG_SMP */ - -/* - * scheduler tick hitting a task of our scheduling class: - */ -static void task_tick_fair(struct rq *rq, struct task_struct *curr, int queued) -{ - struct cfs_rq *cfs_rq; - struct sched_entity *se = &curr->se; - - for_each_sched_entity(se) { - cfs_rq = cfs_rq_of(se); - entity_tick(cfs_rq, se, queued); - } - - if (static_branch_unlikely(&sched_numa_balancing)) - task_tick_numa(rq, curr); -} - -/* - * called on fork with the child task as argument from the parent's context - * - child not yet on the tasklist - * - preemption disabled - */ -static void task_fork_fair(struct task_struct *p) -{ - struct cfs_rq *cfs_rq; - struct sched_entity *se = &p->se, *curr; - struct rq *rq = this_rq(); - - raw_spin_lock(&rq->lock); - update_rq_clock(rq); - - cfs_rq = task_cfs_rq(current); - curr = cfs_rq->curr; - if (curr) { - update_curr(cfs_rq); - se->vruntime = curr->vruntime; - } - place_entity(cfs_rq, se, 1); - - if (sysctl_sched_child_runs_first && curr && entity_before(curr, se)) { - /* - * Upon rescheduling, sched_class::put_prev_task() will place - * 'current' within the tree based on its new key value. - */ - swap(curr->vruntime, se->vruntime); - resched_curr(rq); - } - - se->vruntime -= cfs_rq->min_vruntime; - raw_spin_unlock(&rq->lock); -} - -/* - * Priority of the task has changed. Check to see if we preempt - * the current task. - */ -static void -prio_changed_fair(struct rq *rq, struct task_struct *p, int oldprio) -{ - if (!task_on_rq_queued(p)) - return; - - /* - * Reschedule if we are currently running on this runqueue and - * our priority decreased, or if we are not currently running on - * this runqueue and our priority is higher than the current's - */ - if (rq->curr == p) { - if (p->prio > oldprio) - resched_curr(rq); - } else - check_preempt_curr(rq, p, 0); -} - -static inline bool vruntime_normalized(struct task_struct *p) -{ - struct sched_entity *se = &p->se; - - /* - * In both the TASK_ON_RQ_QUEUED and TASK_ON_RQ_MIGRATING cases, - * the dequeue_entity(.flags=0) will already have normalized the - * vruntime. - */ - if (p->on_rq) - return true; - - /* - * When !on_rq, vruntime of the task has usually NOT been normalized. - * But there are some cases where it has already been normalized: - * - * - A forked child which is waiting for being woken up by - * wake_up_new_task(). - * - A task which has been woken up by try_to_wake_up() and - * waiting for actually being woken up by sched_ttwu_pending(). - */ - if (!se->sum_exec_runtime || p->state == TASK_WAKING) - return true; - - return false; -} - -static void detach_task_cfs_rq(struct task_struct *p) -{ - struct sched_entity *se = &p->se; - struct cfs_rq *cfs_rq = cfs_rq_of(se); - u64 now = cfs_rq_clock_task(cfs_rq); - - if (!vruntime_normalized(p)) { - /* - * Fix up our vruntime so that the current sleep doesn't - * cause 'unlimited' sleep bonus. - */ - place_entity(cfs_rq, se, 0); - se->vruntime -= cfs_rq->min_vruntime; - } - - /* Catch up with the cfs_rq and remove our load when we leave */ - update_cfs_rq_load_avg(now, cfs_rq, false); - detach_entity_load_avg(cfs_rq, se); - update_tg_load_avg(cfs_rq, false); -} - -static void attach_task_cfs_rq(struct task_struct *p) -{ - struct sched_entity *se = &p->se; - struct cfs_rq *cfs_rq = cfs_rq_of(se); - u64 now = cfs_rq_clock_task(cfs_rq); - -#ifdef CONFIG_FAIR_GROUP_SCHED - /* - * Since the real-depth could have been changed (only FAIR - * class maintain depth value), reset depth properly. - */ - se->depth = se->parent ? se->parent->depth + 1 : 0; -#endif - - /* Synchronize task with its cfs_rq */ - update_cfs_rq_load_avg(now, cfs_rq, false); - attach_entity_load_avg(cfs_rq, se); - update_tg_load_avg(cfs_rq, false); - - if (!vruntime_normalized(p)) - se->vruntime += cfs_rq->min_vruntime; -} - -static void switched_from_fair(struct rq *rq, struct task_struct *p) -{ - detach_task_cfs_rq(p); -} - -static void switched_to_fair(struct rq *rq, struct task_struct *p) -{ - attach_task_cfs_rq(p); - - if (task_on_rq_queued(p)) { - /* - * We were most likely switched from sched_rt, so - * kick off the schedule if running, otherwise just see - * if we can still preempt the current task. - */ - if (rq->curr == p) - resched_curr(rq); - else - check_preempt_curr(rq, p, 0); - } -} - -/* Account for a task changing its policy or group. - * - * This routine is mostly called to set cfs_rq->curr field when a task - * migrates between groups/classes. - */ -static void set_curr_task_fair(struct rq *rq) -{ - struct sched_entity *se = &rq->curr->se; - - for_each_sched_entity(se) { - struct cfs_rq *cfs_rq = cfs_rq_of(se); - - set_next_entity(cfs_rq, se); - /* ensure bandwidth has been allocated on our new cfs_rq */ - account_cfs_rq_runtime(cfs_rq, 0); - } -} - -void init_cfs_rq(struct cfs_rq *cfs_rq) -{ - cfs_rq->tasks_timeline = RB_ROOT; - cfs_rq->min_vruntime = (u64)(-(1LL << 20)); -#ifndef CONFIG_64BIT - cfs_rq->min_vruntime_copy = cfs_rq->min_vruntime; -#endif -#ifdef CONFIG_SMP - atomic_long_set(&cfs_rq->removed_load_avg, 0); - atomic_long_set(&cfs_rq->removed_util_avg, 0); -#endif -} - -#ifdef CONFIG_FAIR_GROUP_SCHED -static void task_set_group_fair(struct task_struct *p) -{ - struct sched_entity *se = &p->se; - - set_task_rq(p, task_cpu(p)); - se->depth = se->parent ? se->parent->depth + 1 : 0; -} - -static void task_move_group_fair(struct task_struct *p) -{ - detach_task_cfs_rq(p); - set_task_rq(p, task_cpu(p)); - -#ifdef CONFIG_SMP - /* Tell se's cfs_rq has been changed -- migrated */ - p->se.avg.last_update_time = 0; -#endif - attach_task_cfs_rq(p); -} - -static void task_change_group_fair(struct task_struct *p, int type) -{ - switch (type) { - case TASK_SET_GROUP: - task_set_group_fair(p); - break; - - case TASK_MOVE_GROUP: - task_move_group_fair(p); - break; - } -} - -void free_fair_sched_group(struct task_group *tg) -{ - int i; - - destroy_cfs_bandwidth(tg_cfs_bandwidth(tg)); - - for_each_possible_cpu(i) { - if (tg->cfs_rq) - kfree(tg->cfs_rq[i]); - if (tg->se) - kfree(tg->se[i]); - } - - kfree(tg->cfs_rq); - kfree(tg->se); -} - -int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent) -{ - struct sched_entity *se; - struct cfs_rq *cfs_rq; - int i; - - tg->cfs_rq = kzalloc(sizeof(cfs_rq) * nr_cpu_ids, GFP_KERNEL); - if (!tg->cfs_rq) - goto err; - tg->se = kzalloc(sizeof(se) * nr_cpu_ids, GFP_KERNEL); - if (!tg->se) - goto err; - - tg->shares = NICE_0_LOAD; - - init_cfs_bandwidth(tg_cfs_bandwidth(tg)); - - for_each_possible_cpu(i) { - cfs_rq = kzalloc_node(sizeof(struct cfs_rq), - GFP_KERNEL, cpu_to_node(i)); - if (!cfs_rq) - goto err; - - se = kzalloc_node(sizeof(struct sched_entity), - GFP_KERNEL, cpu_to_node(i)); - if (!se) - goto err_free_rq; - - init_cfs_rq(cfs_rq); - init_tg_cfs_entry(tg, cfs_rq, se, i, parent->se[i]); - init_entity_runnable_average(se); - } - - return 1; - -err_free_rq: - kfree(cfs_rq); -err: - return 0; -} - -void online_fair_sched_group(struct task_group *tg) -{ - struct sched_entity *se; - struct rq *rq; - int i; - - for_each_possible_cpu(i) { - rq = cpu_rq(i); - se = tg->se[i]; - - raw_spin_lock_irq(&rq->lock); - post_init_entity_util_avg(se); - sync_throttle(tg, i); - raw_spin_unlock_irq(&rq->lock); - } -} - -void unregister_fair_sched_group(struct task_group *tg) -{ - unsigned long flags; - struct rq *rq; - int cpu; - - for_each_possible_cpu(cpu) { - if (tg->se[cpu]) - remove_entity_load_avg(tg->se[cpu]); - - /* - * Only empty task groups can be destroyed; so we can speculatively - * check on_list without danger of it being re-added. - */ - if (!tg->cfs_rq[cpu]->on_list) - continue; - - rq = cpu_rq(cpu); - - raw_spin_lock_irqsave(&rq->lock, flags); - list_del_leaf_cfs_rq(tg->cfs_rq[cpu]); - raw_spin_unlock_irqrestore(&rq->lock, flags); - } -} - -void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq, - struct sched_entity *se, int cpu, - struct sched_entity *parent) -{ - struct rq *rq = cpu_rq(cpu); - - cfs_rq->tg = tg; - cfs_rq->rq = rq; - init_cfs_rq_runtime(cfs_rq); - - tg->cfs_rq[cpu] = cfs_rq; - tg->se[cpu] = se; - - /* se could be NULL for root_task_group */ - if (!se) - return; - - if (!parent) { - se->cfs_rq = &rq->cfs; - se->depth = 0; - } else { - se->cfs_rq = parent->my_q; - se->depth = parent->depth + 1; - } - - se->my_q = cfs_rq; - /* guarantee group entities always have weight */ - update_load_set(&se->load, NICE_0_LOAD); - se->parent = parent; -} - -static DEFINE_MUTEX(shares_mutex); - -int sched_group_set_shares(struct task_group *tg, unsigned long shares) -{ - int i; - unsigned long flags; - - /* - * We can't change the weight of the root cgroup. - */ - if (!tg->se[0]) - return -EINVAL; - - shares = clamp(shares, scale_load(MIN_SHARES), scale_load(MAX_SHARES)); - - mutex_lock(&shares_mutex); - if (tg->shares == shares) - goto done; - - tg->shares = shares; - for_each_possible_cpu(i) { - struct rq *rq = cpu_rq(i); - struct sched_entity *se; - - se = tg->se[i]; - /* Propagate contribution to hierarchy */ - raw_spin_lock_irqsave(&rq->lock, flags); - - /* Possible calls to update_curr() need rq clock */ - update_rq_clock(rq); - for_each_sched_entity(se) - update_cfs_shares(group_cfs_rq(se)); - raw_spin_unlock_irqrestore(&rq->lock, flags); - } - -done: - mutex_unlock(&shares_mutex); - return 0; -} -#else /* CONFIG_FAIR_GROUP_SCHED */ - -void free_fair_sched_group(struct task_group *tg) { } - -int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent) -{ - return 1; -} - -void online_fair_sched_group(struct task_group *tg) { } - -void unregister_fair_sched_group(struct task_group *tg) { } - -#endif /* CONFIG_FAIR_GROUP_SCHED */ - - -static unsigned int get_rr_interval_fair(struct rq *rq, struct task_struct *task) -{ - struct sched_entity *se = &task->se; - unsigned int rr_interval = 0; - - /* - * Time slice is 0 for SCHED_OTHER tasks that are on an otherwise - * idle runqueue: - */ - if (rq->cfs.load.weight) - rr_interval = NS_TO_JIFFIES(sched_slice(cfs_rq_of(se), se)); - - return rr_interval; -} - -/* - * All the scheduling class methods: - */ -const struct sched_class fair_sched_class = { - .next = &idle_sched_class, - .enqueue_task = enqueue_task_fair, - .dequeue_task = dequeue_task_fair, - .yield_task = yield_task_fair, - .yield_to_task = yield_to_task_fair, - - .check_preempt_curr = check_preempt_wakeup, - - .pick_next_task = pick_next_task_fair, - .put_prev_task = put_prev_task_fair, - -#ifdef CONFIG_SMP - .select_task_rq = select_task_rq_fair, - .migrate_task_rq = migrate_task_rq_fair, - - .rq_online = rq_online_fair, - .rq_offline = rq_offline_fair, - - .task_dead = task_dead_fair, - .set_cpus_allowed = set_cpus_allowed_common, -#endif - - .set_curr_task = set_curr_task_fair, - .task_tick = task_tick_fair, - .task_fork = task_fork_fair, - - .prio_changed = prio_changed_fair, - .switched_from = switched_from_fair, - .switched_to = switched_to_fair, - - .get_rr_interval = get_rr_interval_fair, - - .update_curr = update_curr_fair, - -#ifdef CONFIG_FAIR_GROUP_SCHED - .task_change_group = task_change_group_fair, -#endif -}; - -#ifdef CONFIG_SCHED_DEBUG -void print_cfs_stats(struct seq_file *m, int cpu) -{ - struct cfs_rq *cfs_rq; - - rcu_read_lock(); - for_each_leaf_cfs_rq(cpu_rq(cpu), cfs_rq) - print_cfs_rq(m, cpu, cfs_rq); - rcu_read_unlock(); -} - -#ifdef CONFIG_NUMA_BALANCING -void show_numa_stats(struct task_struct *p, struct seq_file *m) -{ - int node; - unsigned long tsf = 0, tpf = 0, gsf = 0, gpf = 0; - - for_each_online_node(node) { - if (p->numa_faults) { - tsf = p->numa_faults[task_faults_idx(NUMA_MEM, node, 0)]; - tpf = p->numa_faults[task_faults_idx(NUMA_MEM, node, 1)]; - } - if (p->numa_group) { - gsf = p->numa_group->faults[task_faults_idx(NUMA_MEM, node, 0)], - gpf = p->numa_group->faults[task_faults_idx(NUMA_MEM, node, 1)]; - } - print_numa_stats(m, node, tsf, tpf, gsf, gpf); - } -} -#endif /* CONFIG_NUMA_BALANCING */ -#endif /* CONFIG_SCHED_DEBUG */ - -__init void init_sched_fair_class(void) -{ -#ifdef CONFIG_SMP - open_softirq(SCHED_SOFTIRQ, run_rebalance_domains); - -#ifdef CONFIG_NO_HZ_COMMON - nohz.next_balance = jiffies; - zalloc_cpumask_var(&nohz.idle_cpus_mask, GFP_NOWAIT); -#endif -#endif /* SMP */ - -} diff --git a/src/linux/kernel/sched/features.h b/src/linux/kernel/sched/features.h deleted file mode 100644 index 69631fa..0000000 --- a/src/linux/kernel/sched/features.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Only give sleepers 50% of their service deficit. This allows - * them to run sooner, but does not allow tons of sleepers to - * rip the spread apart. - */ -SCHED_FEAT(GENTLE_FAIR_SLEEPERS, true) - -/* - * Place new tasks ahead so that they do not starve already running - * tasks - */ -SCHED_FEAT(START_DEBIT, true) - -/* - * Prefer to schedule the task we woke last (assuming it failed - * wakeup-preemption), since its likely going to consume data we - * touched, increases cache locality. - */ -SCHED_FEAT(NEXT_BUDDY, false) - -/* - * Prefer to schedule the task that ran last (when we did - * wake-preempt) as that likely will touch the same data, increases - * cache locality. - */ -SCHED_FEAT(LAST_BUDDY, true) - -/* - * Consider buddies to be cache hot, decreases the likelyness of a - * cache buddy being migrated away, increases cache locality. - */ -SCHED_FEAT(CACHE_HOT_BUDDY, true) - -/* - * Allow wakeup-time preemption of the current task: - */ -SCHED_FEAT(WAKEUP_PREEMPTION, true) - -SCHED_FEAT(HRTICK, false) -SCHED_FEAT(DOUBLE_TICK, false) -SCHED_FEAT(LB_BIAS, true) - -/* - * Decrement CPU capacity based on time not spent running tasks - */ -SCHED_FEAT(NONTASK_CAPACITY, true) - -/* - * Queue remote wakeups on the target CPU and process them - * using the scheduler IPI. Reduces rq->lock contention/bounces. - */ -SCHED_FEAT(TTWU_QUEUE, true) - -#ifdef HAVE_RT_PUSH_IPI -/* - * In order to avoid a thundering herd attack of CPUs that are - * lowering their priorities at the same time, and there being - * a single CPU that has an RT task that can migrate and is waiting - * to run, where the other CPUs will try to take that CPUs - * rq lock and possibly create a large contention, sending an - * IPI to that CPU and let that CPU push the RT task to where - * it should go may be a better scenario. - */ -SCHED_FEAT(RT_PUSH_IPI, true) -#endif - -SCHED_FEAT(FORCE_SD_OVERLAP, false) -SCHED_FEAT(RT_RUNTIME_SHARE, true) -SCHED_FEAT(LB_MIN, false) -SCHED_FEAT(ATTACH_AGE_LOAD, true) - diff --git a/src/linux/kernel/sched/idle.c b/src/linux/kernel/sched/idle.c deleted file mode 100644 index 8f96581..0000000 --- a/src/linux/kernel/sched/idle.c +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Generic entry point for the idle threads - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include "sched.h" - -/* Linker adds these: start and end of __cpuidle functions */ -extern char __cpuidle_text_start[], __cpuidle_text_end[]; - -/** - * sched_idle_set_state - Record idle state for the current CPU. - * @idle_state: State to record. - */ -void sched_idle_set_state(struct cpuidle_state *idle_state) -{ - idle_set_state(this_rq(), idle_state); -} - -static int __read_mostly cpu_idle_force_poll; - -void cpu_idle_poll_ctrl(bool enable) -{ - if (enable) { - cpu_idle_force_poll++; - } else { - cpu_idle_force_poll--; - WARN_ON_ONCE(cpu_idle_force_poll < 0); - } -} - -#ifdef CONFIG_GENERIC_IDLE_POLL_SETUP -static int __init cpu_idle_poll_setup(char *__unused) -{ - cpu_idle_force_poll = 1; - return 1; -} -__setup("nohlt", cpu_idle_poll_setup); - -static int __init cpu_idle_nopoll_setup(char *__unused) -{ - cpu_idle_force_poll = 0; - return 1; -} -__setup("hlt", cpu_idle_nopoll_setup); -#endif - -static noinline int __cpuidle cpu_idle_poll(void) -{ - rcu_idle_enter(); - trace_cpu_idle_rcuidle(0, smp_processor_id()); - local_irq_enable(); - stop_critical_timings(); - while (!tif_need_resched() && - (cpu_idle_force_poll || tick_check_broadcast_expired())) - cpu_relax(); - start_critical_timings(); - trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id()); - rcu_idle_exit(); - return 1; -} - -/* Weak implementations for optional arch specific functions */ -void __weak arch_cpu_idle_prepare(void) { } -void __weak arch_cpu_idle_enter(void) { } -void __weak arch_cpu_idle_exit(void) { } -void __weak arch_cpu_idle_dead(void) { } -void __weak arch_cpu_idle(void) -{ - cpu_idle_force_poll = 1; - local_irq_enable(); -} - -/** - * default_idle_call - Default CPU idle routine. - * - * To use when the cpuidle framework cannot be used. - */ -void __cpuidle default_idle_call(void) -{ - if (current_clr_polling_and_test()) { - local_irq_enable(); - } else { - stop_critical_timings(); - arch_cpu_idle(); - start_critical_timings(); - } -} - -static int call_cpuidle(struct cpuidle_driver *drv, struct cpuidle_device *dev, - int next_state) -{ - /* - * The idle task must be scheduled, it is pointless to go to idle, just - * update no idle residency and return. - */ - if (current_clr_polling_and_test()) { - dev->last_residency = 0; - local_irq_enable(); - return -EBUSY; - } - - /* - * Enter the idle state previously returned by the governor decision. - * This function will block until an interrupt occurs and will take - * care of re-enabling the local interrupts - */ - return cpuidle_enter(drv, dev, next_state); -} - -/** - * cpuidle_idle_call - the main idle function - * - * NOTE: no locks or semaphores should be used here - * - * On archs that support TIF_POLLING_NRFLAG, is called with polling - * set, and it returns with polling set. If it ever stops polling, it - * must clear the polling bit. - */ -static void cpuidle_idle_call(void) -{ - struct cpuidle_device *dev = cpuidle_get_device(); - struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev); - int next_state, entered_state; - - /* - * Check if the idle task must be rescheduled. If it is the - * case, exit the function after re-enabling the local irq. - */ - if (need_resched()) { - local_irq_enable(); - return; - } - - /* - * Tell the RCU framework we are entering an idle section, - * so no more rcu read side critical sections and one more - * step to the grace period - */ - rcu_idle_enter(); - - if (cpuidle_not_available(drv, dev)) { - default_idle_call(); - goto exit_idle; - } - - /* - * Suspend-to-idle ("freeze") is a system state in which all user space - * has been frozen, all I/O devices have been suspended and the only - * activity happens here and in iterrupts (if any). In that case bypass - * the cpuidle governor and go stratight for the deepest idle state - * available. Possibly also suspend the local tick and the entire - * timekeeping to prevent timer interrupts from kicking us out of idle - * until a proper wakeup interrupt happens. - */ - if (idle_should_freeze()) { - entered_state = cpuidle_enter_freeze(drv, dev); - if (entered_state > 0) { - local_irq_enable(); - goto exit_idle; - } - - next_state = cpuidle_find_deepest_state(drv, dev); - call_cpuidle(drv, dev, next_state); - } else { - /* - * Ask the cpuidle framework to choose a convenient idle state. - */ - next_state = cpuidle_select(drv, dev); - entered_state = call_cpuidle(drv, dev, next_state); - /* - * Give the governor an opportunity to reflect on the outcome - */ - cpuidle_reflect(dev, entered_state); - } - -exit_idle: - __current_set_polling(); - - /* - * It is up to the idle functions to reenable local interrupts - */ - if (WARN_ON_ONCE(irqs_disabled())) - local_irq_enable(); - - rcu_idle_exit(); -} - -/* - * Generic idle loop implementation - * - * Called with polling cleared. - */ -void cpu_idle_loop(void) -{ - int cpu = smp_processor_id(); - - while (1) { - /* - * If the arch has a polling bit, we maintain an invariant: - * - * Our polling bit is clear if we're not scheduled (i.e. if - * rq->curr != rq->idle). This means that, if rq->idle has - * the polling bit set, then setting need_resched is - * guaranteed to cause the cpu to reschedule. - */ - - __current_set_polling(); - quiet_vmstat(); - tick_nohz_idle_enter(); - - while (!need_resched()) { - check_pgt_cache(); - rmb(); - - if (cpu_is_offline(cpu)) { - cpuhp_report_idle_dead(); - arch_cpu_idle_dead(); - } - - local_irq_disable(); - arch_cpu_idle_enter(); - - /* - * In poll mode we reenable interrupts and spin. - * - * Also if we detected in the wakeup from idle - * path that the tick broadcast device expired - * for us, we don't want to go deep idle as we - * know that the IPI is going to arrive right - * away - */ - if (cpu_idle_force_poll || tick_check_broadcast_expired()) - cpu_idle_poll(); - else - cpuidle_idle_call(); - - arch_cpu_idle_exit(); - } - - /* - * Since we fell out of the loop above, we know - * TIF_NEED_RESCHED must be set, propagate it into - * PREEMPT_NEED_RESCHED. - * - * This is required because for polling idle loops we will - * not have had an IPI to fold the state for us. - */ - preempt_set_need_resched(); - tick_nohz_idle_exit(); - __current_clr_polling(); - - /* - * We promise to call sched_ttwu_pending and reschedule - * if need_resched is set while polling is set. That - * means that clearing polling needs to be visible - * before doing these things. - */ - smp_mb__after_atomic(); - - sched_ttwu_pending(); - schedule_preempt_disabled(); - } -} -EXPORT_SYMBOL(cpu_idle_loop); - -bool cpu_in_idle(unsigned long pc) -{ - return pc >= (unsigned long)__cpuidle_text_start && - pc < (unsigned long)__cpuidle_text_end; -} - -void cpu_startup_entry(enum cpuhp_state state) -{ - /* - * This #ifdef needs to die, but it's too late in the cycle to - * make this generic (arm and sh have never invoked the canary - * init for the non boot cpus!). Will be fixed in 3.11 - */ -#ifdef CONFIG_X86 - /* - * If we're the non-boot CPU, nothing set the stack canary up - * for us. The boot CPU already has it initialized but no harm - * in doing it again. This is a good place for updating it, as - * we wont ever return from this function (so the invalid - * canaries already on the stack wont ever trigger). - */ - boot_init_stack_canary(); -#endif - arch_cpu_idle_prepare(); - cpuhp_online_idle(state); - cpu_idle_loop(); -} diff --git a/src/linux/kernel/sched/idle_task.c b/src/linux/kernel/sched/idle_task.c deleted file mode 100644 index 5405d3f..0000000 --- a/src/linux/kernel/sched/idle_task.c +++ /dev/null @@ -1,109 +0,0 @@ -#include "sched.h" - -/* - * idle-task scheduling class. - * - * (NOTE: these are not related to SCHED_IDLE tasks which are - * handled in sched/fair.c) - */ - -#ifdef CONFIG_SMP -static int -select_task_rq_idle(struct task_struct *p, int cpu, int sd_flag, int flags) -{ - return task_cpu(p); /* IDLE tasks as never migrated */ -} -#endif /* CONFIG_SMP */ - -/* - * Idle tasks are unconditionally rescheduled: - */ -static void check_preempt_curr_idle(struct rq *rq, struct task_struct *p, int flags) -{ - resched_curr(rq); -} - -static struct task_struct * -pick_next_task_idle(struct rq *rq, struct task_struct *prev, struct pin_cookie cookie) -{ - put_prev_task(rq, prev); - update_idle_core(rq); - schedstat_inc(rq->sched_goidle); - return rq->idle; -} - -/* - * It is not legal to sleep in the idle task - print a warning - * message if some code attempts to do it: - */ -static void -dequeue_task_idle(struct rq *rq, struct task_struct *p, int flags) -{ - raw_spin_unlock_irq(&rq->lock); - printk(KERN_ERR "bad: scheduling from the idle thread!\n"); - dump_stack(); - raw_spin_lock_irq(&rq->lock); -} - -static void put_prev_task_idle(struct rq *rq, struct task_struct *prev) -{ - rq_last_tick_reset(rq); -} - -static void task_tick_idle(struct rq *rq, struct task_struct *curr, int queued) -{ -} - -static void set_curr_task_idle(struct rq *rq) -{ -} - -static void switched_to_idle(struct rq *rq, struct task_struct *p) -{ - BUG(); -} - -static void -prio_changed_idle(struct rq *rq, struct task_struct *p, int oldprio) -{ - BUG(); -} - -static unsigned int get_rr_interval_idle(struct rq *rq, struct task_struct *task) -{ - return 0; -} - -static void update_curr_idle(struct rq *rq) -{ -} - -/* - * Simple, special scheduling class for the per-CPU idle tasks: - */ -const struct sched_class idle_sched_class = { - /* .next is NULL */ - /* no enqueue/yield_task for idle tasks */ - - /* dequeue is not valid, we print a debug message there: */ - .dequeue_task = dequeue_task_idle, - - .check_preempt_curr = check_preempt_curr_idle, - - .pick_next_task = pick_next_task_idle, - .put_prev_task = put_prev_task_idle, - -#ifdef CONFIG_SMP - .select_task_rq = select_task_rq_idle, - .set_cpus_allowed = set_cpus_allowed_common, -#endif - - .set_curr_task = set_curr_task_idle, - .task_tick = task_tick_idle, - - .get_rr_interval = get_rr_interval_idle, - - .prio_changed = prio_changed_idle, - .switched_to = switched_to_idle, - .update_curr = update_curr_idle, -}; diff --git a/src/linux/kernel/sched/loadavg.c b/src/linux/kernel/sched/loadavg.c deleted file mode 100644 index a2d6eb7..0000000 --- a/src/linux/kernel/sched/loadavg.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - * kernel/sched/loadavg.c - * - * This file contains the magic bits required to compute the global loadavg - * figure. Its a silly number but people think its important. We go through - * great pains to make it work on big machines and tickless kernels. - */ - -#include - -#include "sched.h" - -/* - * Global load-average calculations - * - * We take a distributed and async approach to calculating the global load-avg - * in order to minimize overhead. - * - * The global load average is an exponentially decaying average of nr_running + - * nr_uninterruptible. - * - * Once every LOAD_FREQ: - * - * nr_active = 0; - * for_each_possible_cpu(cpu) - * nr_active += cpu_of(cpu)->nr_running + cpu_of(cpu)->nr_uninterruptible; - * - * avenrun[n] = avenrun[0] * exp_n + nr_active * (1 - exp_n) - * - * Due to a number of reasons the above turns in the mess below: - * - * - for_each_possible_cpu() is prohibitively expensive on machines with - * serious number of cpus, therefore we need to take a distributed approach - * to calculating nr_active. - * - * \Sum_i x_i(t) = \Sum_i x_i(t) - x_i(t_0) | x_i(t_0) := 0 - * = \Sum_i { \Sum_j=1 x_i(t_j) - x_i(t_j-1) } - * - * So assuming nr_active := 0 when we start out -- true per definition, we - * can simply take per-cpu deltas and fold those into a global accumulate - * to obtain the same result. See calc_load_fold_active(). - * - * Furthermore, in order to avoid synchronizing all per-cpu delta folding - * across the machine, we assume 10 ticks is sufficient time for every - * cpu to have completed this task. - * - * This places an upper-bound on the IRQ-off latency of the machine. Then - * again, being late doesn't loose the delta, just wrecks the sample. - * - * - cpu_rq()->nr_uninterruptible isn't accurately tracked per-cpu because - * this would add another cross-cpu cacheline miss and atomic operation - * to the wakeup path. Instead we increment on whatever cpu the task ran - * when it went into uninterruptible state and decrement on whatever cpu - * did the wakeup. This means that only the sum of nr_uninterruptible over - * all cpus yields the correct result. - * - * This covers the NO_HZ=n code, for extra head-aches, see the comment below. - */ - -/* Variables and functions for calc_load */ -atomic_long_t calc_load_tasks; -unsigned long calc_load_update; -unsigned long avenrun[3]; -EXPORT_SYMBOL(avenrun); /* should be removed */ - -/** - * get_avenrun - get the load average array - * @loads: pointer to dest load array - * @offset: offset to add - * @shift: shift count to shift the result left - * - * These values are estimates at best, so no need for locking. - */ -void get_avenrun(unsigned long *loads, unsigned long offset, int shift) -{ - loads[0] = (avenrun[0] + offset) << shift; - loads[1] = (avenrun[1] + offset) << shift; - loads[2] = (avenrun[2] + offset) << shift; -} - -long calc_load_fold_active(struct rq *this_rq, long adjust) -{ - long nr_active, delta = 0; - - nr_active = this_rq->nr_running - adjust; - nr_active += (long)this_rq->nr_uninterruptible; - - if (nr_active != this_rq->calc_load_active) { - delta = nr_active - this_rq->calc_load_active; - this_rq->calc_load_active = nr_active; - } - - return delta; -} - -/* - * a1 = a0 * e + a * (1 - e) - */ -static unsigned long -calc_load(unsigned long load, unsigned long exp, unsigned long active) -{ - unsigned long newload; - - newload = load * exp + active * (FIXED_1 - exp); - if (active >= load) - newload += FIXED_1-1; - - return newload / FIXED_1; -} - -#ifdef CONFIG_NO_HZ_COMMON -/* - * Handle NO_HZ for the global load-average. - * - * Since the above described distributed algorithm to compute the global - * load-average relies on per-cpu sampling from the tick, it is affected by - * NO_HZ. - * - * The basic idea is to fold the nr_active delta into a global idle-delta upon - * entering NO_HZ state such that we can include this as an 'extra' cpu delta - * when we read the global state. - * - * Obviously reality has to ruin such a delightfully simple scheme: - * - * - When we go NO_HZ idle during the window, we can negate our sample - * contribution, causing under-accounting. - * - * We avoid this by keeping two idle-delta counters and flipping them - * when the window starts, thus separating old and new NO_HZ load. - * - * The only trick is the slight shift in index flip for read vs write. - * - * 0s 5s 10s 15s - * +10 +10 +10 +10 - * |-|-----------|-|-----------|-|-----------|-| - * r:0 0 1 1 0 0 1 1 0 - * w:0 1 1 0 0 1 1 0 0 - * - * This ensures we'll fold the old idle contribution in this window while - * accumlating the new one. - * - * - When we wake up from NO_HZ idle during the window, we push up our - * contribution, since we effectively move our sample point to a known - * busy state. - * - * This is solved by pushing the window forward, and thus skipping the - * sample, for this cpu (effectively using the idle-delta for this cpu which - * was in effect at the time the window opened). This also solves the issue - * of having to deal with a cpu having been in NOHZ idle for multiple - * LOAD_FREQ intervals. - * - * When making the ILB scale, we should try to pull this in as well. - */ -static atomic_long_t calc_load_idle[2]; -static int calc_load_idx; - -static inline int calc_load_write_idx(void) -{ - int idx = calc_load_idx; - - /* - * See calc_global_nohz(), if we observe the new index, we also - * need to observe the new update time. - */ - smp_rmb(); - - /* - * If the folding window started, make sure we start writing in the - * next idle-delta. - */ - if (!time_before(jiffies, calc_load_update)) - idx++; - - return idx & 1; -} - -static inline int calc_load_read_idx(void) -{ - return calc_load_idx & 1; -} - -void calc_load_enter_idle(void) -{ - struct rq *this_rq = this_rq(); - long delta; - - /* - * We're going into NOHZ mode, if there's any pending delta, fold it - * into the pending idle delta. - */ - delta = calc_load_fold_active(this_rq, 0); - if (delta) { - int idx = calc_load_write_idx(); - - atomic_long_add(delta, &calc_load_idle[idx]); - } -} - -void calc_load_exit_idle(void) -{ - struct rq *this_rq = this_rq(); - - /* - * If we're still before the sample window, we're done. - */ - if (time_before(jiffies, this_rq->calc_load_update)) - return; - - /* - * We woke inside or after the sample window, this means we're already - * accounted through the nohz accounting, so skip the entire deal and - * sync up for the next window. - */ - this_rq->calc_load_update = calc_load_update; - if (time_before(jiffies, this_rq->calc_load_update + 10)) - this_rq->calc_load_update += LOAD_FREQ; -} - -static long calc_load_fold_idle(void) -{ - int idx = calc_load_read_idx(); - long delta = 0; - - if (atomic_long_read(&calc_load_idle[idx])) - delta = atomic_long_xchg(&calc_load_idle[idx], 0); - - return delta; -} - -/** - * fixed_power_int - compute: x^n, in O(log n) time - * - * @x: base of the power - * @frac_bits: fractional bits of @x - * @n: power to raise @x to. - * - * By exploiting the relation between the definition of the natural power - * function: x^n := x*x*...*x (x multiplied by itself for n times), and - * the binary encoding of numbers used by computers: n := \Sum n_i * 2^i, - * (where: n_i \elem {0, 1}, the binary vector representing n), - * we find: x^n := x^(\Sum n_i * 2^i) := \Prod x^(n_i * 2^i), which is - * of course trivially computable in O(log_2 n), the length of our binary - * vector. - */ -static unsigned long -fixed_power_int(unsigned long x, unsigned int frac_bits, unsigned int n) -{ - unsigned long result = 1UL << frac_bits; - - if (n) { - for (;;) { - if (n & 1) { - result *= x; - result += 1UL << (frac_bits - 1); - result >>= frac_bits; - } - n >>= 1; - if (!n) - break; - x *= x; - x += 1UL << (frac_bits - 1); - x >>= frac_bits; - } - } - - return result; -} - -/* - * a1 = a0 * e + a * (1 - e) - * - * a2 = a1 * e + a * (1 - e) - * = (a0 * e + a * (1 - e)) * e + a * (1 - e) - * = a0 * e^2 + a * (1 - e) * (1 + e) - * - * a3 = a2 * e + a * (1 - e) - * = (a0 * e^2 + a * (1 - e) * (1 + e)) * e + a * (1 - e) - * = a0 * e^3 + a * (1 - e) * (1 + e + e^2) - * - * ... - * - * an = a0 * e^n + a * (1 - e) * (1 + e + ... + e^n-1) [1] - * = a0 * e^n + a * (1 - e) * (1 - e^n)/(1 - e) - * = a0 * e^n + a * (1 - e^n) - * - * [1] application of the geometric series: - * - * n 1 - x^(n+1) - * S_n := \Sum x^i = ------------- - * i=0 1 - x - */ -static unsigned long -calc_load_n(unsigned long load, unsigned long exp, - unsigned long active, unsigned int n) -{ - return calc_load(load, fixed_power_int(exp, FSHIFT, n), active); -} - -/* - * NO_HZ can leave us missing all per-cpu ticks calling - * calc_load_account_active(), but since an idle CPU folds its delta into - * calc_load_tasks_idle per calc_load_account_idle(), all we need to do is fold - * in the pending idle delta if our idle period crossed a load cycle boundary. - * - * Once we've updated the global active value, we need to apply the exponential - * weights adjusted to the number of cycles missed. - */ -static void calc_global_nohz(void) -{ - long delta, active, n; - - if (!time_before(jiffies, calc_load_update + 10)) { - /* - * Catch-up, fold however many we are behind still - */ - delta = jiffies - calc_load_update - 10; - n = 1 + (delta / LOAD_FREQ); - - active = atomic_long_read(&calc_load_tasks); - active = active > 0 ? active * FIXED_1 : 0; - - avenrun[0] = calc_load_n(avenrun[0], EXP_1, active, n); - avenrun[1] = calc_load_n(avenrun[1], EXP_5, active, n); - avenrun[2] = calc_load_n(avenrun[2], EXP_15, active, n); - - calc_load_update += n * LOAD_FREQ; - } - - /* - * Flip the idle index... - * - * Make sure we first write the new time then flip the index, so that - * calc_load_write_idx() will see the new time when it reads the new - * index, this avoids a double flip messing things up. - */ - smp_wmb(); - calc_load_idx++; -} -#else /* !CONFIG_NO_HZ_COMMON */ - -static inline long calc_load_fold_idle(void) { return 0; } -static inline void calc_global_nohz(void) { } - -#endif /* CONFIG_NO_HZ_COMMON */ - -/* - * calc_load - update the avenrun load estimates 10 ticks after the - * CPUs have updated calc_load_tasks. - * - * Called from the global timer code. - */ -void calc_global_load(unsigned long ticks) -{ - long active, delta; - - if (time_before(jiffies, calc_load_update + 10)) - return; - - /* - * Fold the 'old' idle-delta to include all NO_HZ cpus. - */ - delta = calc_load_fold_idle(); - if (delta) - atomic_long_add(delta, &calc_load_tasks); - - active = atomic_long_read(&calc_load_tasks); - active = active > 0 ? active * FIXED_1 : 0; - - avenrun[0] = calc_load(avenrun[0], EXP_1, active); - avenrun[1] = calc_load(avenrun[1], EXP_5, active); - avenrun[2] = calc_load(avenrun[2], EXP_15, active); - - calc_load_update += LOAD_FREQ; - - /* - * In case we idled for multiple LOAD_FREQ intervals, catch up in bulk. - */ - calc_global_nohz(); -} - -/* - * Called from scheduler_tick() to periodically update this CPU's - * active count. - */ -void calc_global_load_tick(struct rq *this_rq) -{ - long delta; - - if (time_before(jiffies, this_rq->calc_load_update)) - return; - - delta = calc_load_fold_active(this_rq, 0); - if (delta) - atomic_long_add(delta, &calc_load_tasks); - - this_rq->calc_load_update += LOAD_FREQ; -} diff --git a/src/linux/kernel/sched/rt.c b/src/linux/kernel/sched/rt.c deleted file mode 100644 index 2516b8d..0000000 --- a/src/linux/kernel/sched/rt.c +++ /dev/null @@ -1,2370 +0,0 @@ -/* - * Real-Time Scheduling Class (mapped to the SCHED_FIFO and SCHED_RR - * policies) - */ - -#include "sched.h" - -#include -#include - -int sched_rr_timeslice = RR_TIMESLICE; - -static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun); - -struct rt_bandwidth def_rt_bandwidth; - -static enum hrtimer_restart sched_rt_period_timer(struct hrtimer *timer) -{ - struct rt_bandwidth *rt_b = - container_of(timer, struct rt_bandwidth, rt_period_timer); - int idle = 0; - int overrun; - - raw_spin_lock(&rt_b->rt_runtime_lock); - for (;;) { - overrun = hrtimer_forward_now(timer, rt_b->rt_period); - if (!overrun) - break; - - raw_spin_unlock(&rt_b->rt_runtime_lock); - idle = do_sched_rt_period_timer(rt_b, overrun); - raw_spin_lock(&rt_b->rt_runtime_lock); - } - if (idle) - rt_b->rt_period_active = 0; - raw_spin_unlock(&rt_b->rt_runtime_lock); - - return idle ? HRTIMER_NORESTART : HRTIMER_RESTART; -} - -void init_rt_bandwidth(struct rt_bandwidth *rt_b, u64 period, u64 runtime) -{ - rt_b->rt_period = ns_to_ktime(period); - rt_b->rt_runtime = runtime; - - raw_spin_lock_init(&rt_b->rt_runtime_lock); - - hrtimer_init(&rt_b->rt_period_timer, - CLOCK_MONOTONIC, HRTIMER_MODE_REL); - rt_b->rt_period_timer.function = sched_rt_period_timer; -} - -static void start_rt_bandwidth(struct rt_bandwidth *rt_b) -{ - if (!rt_bandwidth_enabled() || rt_b->rt_runtime == RUNTIME_INF) - return; - - raw_spin_lock(&rt_b->rt_runtime_lock); - if (!rt_b->rt_period_active) { - rt_b->rt_period_active = 1; - /* - * SCHED_DEADLINE updates the bandwidth, as a run away - * RT task with a DL task could hog a CPU. But DL does - * not reset the period. If a deadline task was running - * without an RT task running, it can cause RT tasks to - * throttle when they start up. Kick the timer right away - * to update the period. - */ - hrtimer_forward_now(&rt_b->rt_period_timer, ns_to_ktime(0)); - hrtimer_start_expires(&rt_b->rt_period_timer, HRTIMER_MODE_ABS_PINNED); - } - raw_spin_unlock(&rt_b->rt_runtime_lock); -} - -#if defined(CONFIG_SMP) && defined(HAVE_RT_PUSH_IPI) -static void push_irq_work_func(struct irq_work *work); -#endif - -void init_rt_rq(struct rt_rq *rt_rq) -{ - struct rt_prio_array *array; - int i; - - array = &rt_rq->active; - for (i = 0; i < MAX_RT_PRIO; i++) { - INIT_LIST_HEAD(array->queue + i); - __clear_bit(i, array->bitmap); - } - /* delimiter for bitsearch: */ - __set_bit(MAX_RT_PRIO, array->bitmap); - -#if defined CONFIG_SMP - rt_rq->highest_prio.curr = MAX_RT_PRIO; - rt_rq->highest_prio.next = MAX_RT_PRIO; - rt_rq->rt_nr_migratory = 0; - rt_rq->overloaded = 0; - plist_head_init(&rt_rq->pushable_tasks); - -#ifdef HAVE_RT_PUSH_IPI - rt_rq->push_flags = 0; - rt_rq->push_cpu = nr_cpu_ids; - raw_spin_lock_init(&rt_rq->push_lock); - init_irq_work(&rt_rq->push_work, push_irq_work_func); -#endif -#endif /* CONFIG_SMP */ - /* We start is dequeued state, because no RT tasks are queued */ - rt_rq->rt_queued = 0; - - rt_rq->rt_time = 0; - rt_rq->rt_throttled = 0; - rt_rq->rt_runtime = 0; - raw_spin_lock_init(&rt_rq->rt_runtime_lock); -} - -#ifdef CONFIG_RT_GROUP_SCHED -static void destroy_rt_bandwidth(struct rt_bandwidth *rt_b) -{ - hrtimer_cancel(&rt_b->rt_period_timer); -} - -#define rt_entity_is_task(rt_se) (!(rt_se)->my_q) - -static inline struct task_struct *rt_task_of(struct sched_rt_entity *rt_se) -{ -#ifdef CONFIG_SCHED_DEBUG - WARN_ON_ONCE(!rt_entity_is_task(rt_se)); -#endif - return container_of(rt_se, struct task_struct, rt); -} - -static inline struct rq *rq_of_rt_rq(struct rt_rq *rt_rq) -{ - return rt_rq->rq; -} - -static inline struct rt_rq *rt_rq_of_se(struct sched_rt_entity *rt_se) -{ - return rt_se->rt_rq; -} - -static inline struct rq *rq_of_rt_se(struct sched_rt_entity *rt_se) -{ - struct rt_rq *rt_rq = rt_se->rt_rq; - - return rt_rq->rq; -} - -void free_rt_sched_group(struct task_group *tg) -{ - int i; - - if (tg->rt_se) - destroy_rt_bandwidth(&tg->rt_bandwidth); - - for_each_possible_cpu(i) { - if (tg->rt_rq) - kfree(tg->rt_rq[i]); - if (tg->rt_se) - kfree(tg->rt_se[i]); - } - - kfree(tg->rt_rq); - kfree(tg->rt_se); -} - -void init_tg_rt_entry(struct task_group *tg, struct rt_rq *rt_rq, - struct sched_rt_entity *rt_se, int cpu, - struct sched_rt_entity *parent) -{ - struct rq *rq = cpu_rq(cpu); - - rt_rq->highest_prio.curr = MAX_RT_PRIO; - rt_rq->rt_nr_boosted = 0; - rt_rq->rq = rq; - rt_rq->tg = tg; - - tg->rt_rq[cpu] = rt_rq; - tg->rt_se[cpu] = rt_se; - - if (!rt_se) - return; - - if (!parent) - rt_se->rt_rq = &rq->rt; - else - rt_se->rt_rq = parent->my_q; - - rt_se->my_q = rt_rq; - rt_se->parent = parent; - INIT_LIST_HEAD(&rt_se->run_list); -} - -int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent) -{ - struct rt_rq *rt_rq; - struct sched_rt_entity *rt_se; - int i; - - tg->rt_rq = kzalloc(sizeof(rt_rq) * nr_cpu_ids, GFP_KERNEL); - if (!tg->rt_rq) - goto err; - tg->rt_se = kzalloc(sizeof(rt_se) * nr_cpu_ids, GFP_KERNEL); - if (!tg->rt_se) - goto err; - - init_rt_bandwidth(&tg->rt_bandwidth, - ktime_to_ns(def_rt_bandwidth.rt_period), 0); - - for_each_possible_cpu(i) { - rt_rq = kzalloc_node(sizeof(struct rt_rq), - GFP_KERNEL, cpu_to_node(i)); - if (!rt_rq) - goto err; - - rt_se = kzalloc_node(sizeof(struct sched_rt_entity), - GFP_KERNEL, cpu_to_node(i)); - if (!rt_se) - goto err_free_rq; - - init_rt_rq(rt_rq); - rt_rq->rt_runtime = tg->rt_bandwidth.rt_runtime; - init_tg_rt_entry(tg, rt_rq, rt_se, i, parent->rt_se[i]); - } - - return 1; - -err_free_rq: - kfree(rt_rq); -err: - return 0; -} - -#else /* CONFIG_RT_GROUP_SCHED */ - -#define rt_entity_is_task(rt_se) (1) - -static inline struct task_struct *rt_task_of(struct sched_rt_entity *rt_se) -{ - return container_of(rt_se, struct task_struct, rt); -} - -static inline struct rq *rq_of_rt_rq(struct rt_rq *rt_rq) -{ - return container_of(rt_rq, struct rq, rt); -} - -static inline struct rq *rq_of_rt_se(struct sched_rt_entity *rt_se) -{ - struct task_struct *p = rt_task_of(rt_se); - - return task_rq(p); -} - -static inline struct rt_rq *rt_rq_of_se(struct sched_rt_entity *rt_se) -{ - struct rq *rq = rq_of_rt_se(rt_se); - - return &rq->rt; -} - -void free_rt_sched_group(struct task_group *tg) { } - -int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent) -{ - return 1; -} -#endif /* CONFIG_RT_GROUP_SCHED */ - -#ifdef CONFIG_SMP - -static void pull_rt_task(struct rq *this_rq); - -static inline bool need_pull_rt_task(struct rq *rq, struct task_struct *prev) -{ - /* Try to pull RT tasks here if we lower this rq's prio */ - return rq->rt.highest_prio.curr > prev->prio; -} - -static inline int rt_overloaded(struct rq *rq) -{ - return atomic_read(&rq->rd->rto_count); -} - -static inline void rt_set_overload(struct rq *rq) -{ - if (!rq->online) - return; - - cpumask_set_cpu(rq->cpu, rq->rd->rto_mask); - /* - * Make sure the mask is visible before we set - * the overload count. That is checked to determine - * if we should look at the mask. It would be a shame - * if we looked at the mask, but the mask was not - * updated yet. - * - * Matched by the barrier in pull_rt_task(). - */ - smp_wmb(); - atomic_inc(&rq->rd->rto_count); -} - -static inline void rt_clear_overload(struct rq *rq) -{ - if (!rq->online) - return; - - /* the order here really doesn't matter */ - atomic_dec(&rq->rd->rto_count); - cpumask_clear_cpu(rq->cpu, rq->rd->rto_mask); -} - -static void update_rt_migration(struct rt_rq *rt_rq) -{ - if (rt_rq->rt_nr_migratory && rt_rq->rt_nr_total > 1) { - if (!rt_rq->overloaded) { - rt_set_overload(rq_of_rt_rq(rt_rq)); - rt_rq->overloaded = 1; - } - } else if (rt_rq->overloaded) { - rt_clear_overload(rq_of_rt_rq(rt_rq)); - rt_rq->overloaded = 0; - } -} - -static void inc_rt_migration(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) -{ - struct task_struct *p; - - if (!rt_entity_is_task(rt_se)) - return; - - p = rt_task_of(rt_se); - rt_rq = &rq_of_rt_rq(rt_rq)->rt; - - rt_rq->rt_nr_total++; - if (tsk_nr_cpus_allowed(p) > 1) - rt_rq->rt_nr_migratory++; - - update_rt_migration(rt_rq); -} - -static void dec_rt_migration(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) -{ - struct task_struct *p; - - if (!rt_entity_is_task(rt_se)) - return; - - p = rt_task_of(rt_se); - rt_rq = &rq_of_rt_rq(rt_rq)->rt; - - rt_rq->rt_nr_total--; - if (tsk_nr_cpus_allowed(p) > 1) - rt_rq->rt_nr_migratory--; - - update_rt_migration(rt_rq); -} - -static inline int has_pushable_tasks(struct rq *rq) -{ - return !plist_head_empty(&rq->rt.pushable_tasks); -} - -static DEFINE_PER_CPU(struct callback_head, rt_push_head); -static DEFINE_PER_CPU(struct callback_head, rt_pull_head); - -static void push_rt_tasks(struct rq *); -static void pull_rt_task(struct rq *); - -static inline void queue_push_tasks(struct rq *rq) -{ - if (!has_pushable_tasks(rq)) - return; - - queue_balance_callback(rq, &per_cpu(rt_push_head, rq->cpu), push_rt_tasks); -} - -static inline void queue_pull_task(struct rq *rq) -{ - queue_balance_callback(rq, &per_cpu(rt_pull_head, rq->cpu), pull_rt_task); -} - -static void enqueue_pushable_task(struct rq *rq, struct task_struct *p) -{ - plist_del(&p->pushable_tasks, &rq->rt.pushable_tasks); - plist_node_init(&p->pushable_tasks, p->prio); - plist_add(&p->pushable_tasks, &rq->rt.pushable_tasks); - - /* Update the highest prio pushable task */ - if (p->prio < rq->rt.highest_prio.next) - rq->rt.highest_prio.next = p->prio; -} - -static void dequeue_pushable_task(struct rq *rq, struct task_struct *p) -{ - plist_del(&p->pushable_tasks, &rq->rt.pushable_tasks); - - /* Update the new highest prio pushable task */ - if (has_pushable_tasks(rq)) { - p = plist_first_entry(&rq->rt.pushable_tasks, - struct task_struct, pushable_tasks); - rq->rt.highest_prio.next = p->prio; - } else - rq->rt.highest_prio.next = MAX_RT_PRIO; -} - -#else - -static inline void enqueue_pushable_task(struct rq *rq, struct task_struct *p) -{ -} - -static inline void dequeue_pushable_task(struct rq *rq, struct task_struct *p) -{ -} - -static inline -void inc_rt_migration(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) -{ -} - -static inline -void dec_rt_migration(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) -{ -} - -static inline bool need_pull_rt_task(struct rq *rq, struct task_struct *prev) -{ - return false; -} - -static inline void pull_rt_task(struct rq *this_rq) -{ -} - -static inline void queue_push_tasks(struct rq *rq) -{ -} -#endif /* CONFIG_SMP */ - -static void enqueue_top_rt_rq(struct rt_rq *rt_rq); -static void dequeue_top_rt_rq(struct rt_rq *rt_rq); - -static inline int on_rt_rq(struct sched_rt_entity *rt_se) -{ - return rt_se->on_rq; -} - -#ifdef CONFIG_RT_GROUP_SCHED - -static inline u64 sched_rt_runtime(struct rt_rq *rt_rq) -{ - if (!rt_rq->tg) - return RUNTIME_INF; - - return rt_rq->rt_runtime; -} - -static inline u64 sched_rt_period(struct rt_rq *rt_rq) -{ - return ktime_to_ns(rt_rq->tg->rt_bandwidth.rt_period); -} - -typedef struct task_group *rt_rq_iter_t; - -static inline struct task_group *next_task_group(struct task_group *tg) -{ - do { - tg = list_entry_rcu(tg->list.next, - typeof(struct task_group), list); - } while (&tg->list != &task_groups && task_group_is_autogroup(tg)); - - if (&tg->list == &task_groups) - tg = NULL; - - return tg; -} - -#define for_each_rt_rq(rt_rq, iter, rq) \ - for (iter = container_of(&task_groups, typeof(*iter), list); \ - (iter = next_task_group(iter)) && \ - (rt_rq = iter->rt_rq[cpu_of(rq)]);) - -#define for_each_sched_rt_entity(rt_se) \ - for (; rt_se; rt_se = rt_se->parent) - -static inline struct rt_rq *group_rt_rq(struct sched_rt_entity *rt_se) -{ - return rt_se->my_q; -} - -static void enqueue_rt_entity(struct sched_rt_entity *rt_se, unsigned int flags); -static void dequeue_rt_entity(struct sched_rt_entity *rt_se, unsigned int flags); - -static void sched_rt_rq_enqueue(struct rt_rq *rt_rq) -{ - struct task_struct *curr = rq_of_rt_rq(rt_rq)->curr; - struct rq *rq = rq_of_rt_rq(rt_rq); - struct sched_rt_entity *rt_se; - - int cpu = cpu_of(rq); - - rt_se = rt_rq->tg->rt_se[cpu]; - - if (rt_rq->rt_nr_running) { - if (!rt_se) - enqueue_top_rt_rq(rt_rq); - else if (!on_rt_rq(rt_se)) - enqueue_rt_entity(rt_se, 0); - - if (rt_rq->highest_prio.curr < curr->prio) - resched_curr(rq); - } -} - -static void sched_rt_rq_dequeue(struct rt_rq *rt_rq) -{ - struct sched_rt_entity *rt_se; - int cpu = cpu_of(rq_of_rt_rq(rt_rq)); - - rt_se = rt_rq->tg->rt_se[cpu]; - - if (!rt_se) - dequeue_top_rt_rq(rt_rq); - else if (on_rt_rq(rt_se)) - dequeue_rt_entity(rt_se, 0); -} - -static inline int rt_rq_throttled(struct rt_rq *rt_rq) -{ - return rt_rq->rt_throttled && !rt_rq->rt_nr_boosted; -} - -static int rt_se_boosted(struct sched_rt_entity *rt_se) -{ - struct rt_rq *rt_rq = group_rt_rq(rt_se); - struct task_struct *p; - - if (rt_rq) - return !!rt_rq->rt_nr_boosted; - - p = rt_task_of(rt_se); - return p->prio != p->normal_prio; -} - -#ifdef CONFIG_SMP -static inline const struct cpumask *sched_rt_period_mask(void) -{ - return this_rq()->rd->span; -} -#else -static inline const struct cpumask *sched_rt_period_mask(void) -{ - return cpu_online_mask; -} -#endif - -static inline -struct rt_rq *sched_rt_period_rt_rq(struct rt_bandwidth *rt_b, int cpu) -{ - return container_of(rt_b, struct task_group, rt_bandwidth)->rt_rq[cpu]; -} - -static inline struct rt_bandwidth *sched_rt_bandwidth(struct rt_rq *rt_rq) -{ - return &rt_rq->tg->rt_bandwidth; -} - -#else /* !CONFIG_RT_GROUP_SCHED */ - -static inline u64 sched_rt_runtime(struct rt_rq *rt_rq) -{ - return rt_rq->rt_runtime; -} - -static inline u64 sched_rt_period(struct rt_rq *rt_rq) -{ - return ktime_to_ns(def_rt_bandwidth.rt_period); -} - -typedef struct rt_rq *rt_rq_iter_t; - -#define for_each_rt_rq(rt_rq, iter, rq) \ - for ((void) iter, rt_rq = &rq->rt; rt_rq; rt_rq = NULL) - -#define for_each_sched_rt_entity(rt_se) \ - for (; rt_se; rt_se = NULL) - -static inline struct rt_rq *group_rt_rq(struct sched_rt_entity *rt_se) -{ - return NULL; -} - -static inline void sched_rt_rq_enqueue(struct rt_rq *rt_rq) -{ - struct rq *rq = rq_of_rt_rq(rt_rq); - - if (!rt_rq->rt_nr_running) - return; - - enqueue_top_rt_rq(rt_rq); - resched_curr(rq); -} - -static inline void sched_rt_rq_dequeue(struct rt_rq *rt_rq) -{ - dequeue_top_rt_rq(rt_rq); -} - -static inline int rt_rq_throttled(struct rt_rq *rt_rq) -{ - return rt_rq->rt_throttled; -} - -static inline const struct cpumask *sched_rt_period_mask(void) -{ - return cpu_online_mask; -} - -static inline -struct rt_rq *sched_rt_period_rt_rq(struct rt_bandwidth *rt_b, int cpu) -{ - return &cpu_rq(cpu)->rt; -} - -static inline struct rt_bandwidth *sched_rt_bandwidth(struct rt_rq *rt_rq) -{ - return &def_rt_bandwidth; -} - -#endif /* CONFIG_RT_GROUP_SCHED */ - -bool sched_rt_bandwidth_account(struct rt_rq *rt_rq) -{ - struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq); - - return (hrtimer_active(&rt_b->rt_period_timer) || - rt_rq->rt_time < rt_b->rt_runtime); -} - -#ifdef CONFIG_SMP -/* - * We ran out of runtime, see if we can borrow some from our neighbours. - */ -static void do_balance_runtime(struct rt_rq *rt_rq) -{ - struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq); - struct root_domain *rd = rq_of_rt_rq(rt_rq)->rd; - int i, weight; - u64 rt_period; - - weight = cpumask_weight(rd->span); - - raw_spin_lock(&rt_b->rt_runtime_lock); - rt_period = ktime_to_ns(rt_b->rt_period); - for_each_cpu(i, rd->span) { - struct rt_rq *iter = sched_rt_period_rt_rq(rt_b, i); - s64 diff; - - if (iter == rt_rq) - continue; - - raw_spin_lock(&iter->rt_runtime_lock); - /* - * Either all rqs have inf runtime and there's nothing to steal - * or __disable_runtime() below sets a specific rq to inf to - * indicate its been disabled and disalow stealing. - */ - if (iter->rt_runtime == RUNTIME_INF) - goto next; - - /* - * From runqueues with spare time, take 1/n part of their - * spare time, but no more than our period. - */ - diff = iter->rt_runtime - iter->rt_time; - if (diff > 0) { - diff = div_u64((u64)diff, weight); - if (rt_rq->rt_runtime + diff > rt_period) - diff = rt_period - rt_rq->rt_runtime; - iter->rt_runtime -= diff; - rt_rq->rt_runtime += diff; - if (rt_rq->rt_runtime == rt_period) { - raw_spin_unlock(&iter->rt_runtime_lock); - break; - } - } -next: - raw_spin_unlock(&iter->rt_runtime_lock); - } - raw_spin_unlock(&rt_b->rt_runtime_lock); -} - -/* - * Ensure this RQ takes back all the runtime it lend to its neighbours. - */ -static void __disable_runtime(struct rq *rq) -{ - struct root_domain *rd = rq->rd; - rt_rq_iter_t iter; - struct rt_rq *rt_rq; - - if (unlikely(!scheduler_running)) - return; - - for_each_rt_rq(rt_rq, iter, rq) { - struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq); - s64 want; - int i; - - raw_spin_lock(&rt_b->rt_runtime_lock); - raw_spin_lock(&rt_rq->rt_runtime_lock); - /* - * Either we're all inf and nobody needs to borrow, or we're - * already disabled and thus have nothing to do, or we have - * exactly the right amount of runtime to take out. - */ - if (rt_rq->rt_runtime == RUNTIME_INF || - rt_rq->rt_runtime == rt_b->rt_runtime) - goto balanced; - raw_spin_unlock(&rt_rq->rt_runtime_lock); - - /* - * Calculate the difference between what we started out with - * and what we current have, that's the amount of runtime - * we lend and now have to reclaim. - */ - want = rt_b->rt_runtime - rt_rq->rt_runtime; - - /* - * Greedy reclaim, take back as much as we can. - */ - for_each_cpu(i, rd->span) { - struct rt_rq *iter = sched_rt_period_rt_rq(rt_b, i); - s64 diff; - - /* - * Can't reclaim from ourselves or disabled runqueues. - */ - if (iter == rt_rq || iter->rt_runtime == RUNTIME_INF) - continue; - - raw_spin_lock(&iter->rt_runtime_lock); - if (want > 0) { - diff = min_t(s64, iter->rt_runtime, want); - iter->rt_runtime -= diff; - want -= diff; - } else { - iter->rt_runtime -= want; - want -= want; - } - raw_spin_unlock(&iter->rt_runtime_lock); - - if (!want) - break; - } - - raw_spin_lock(&rt_rq->rt_runtime_lock); - /* - * We cannot be left wanting - that would mean some runtime - * leaked out of the system. - */ - BUG_ON(want); -balanced: - /* - * Disable all the borrow logic by pretending we have inf - * runtime - in which case borrowing doesn't make sense. - */ - rt_rq->rt_runtime = RUNTIME_INF; - rt_rq->rt_throttled = 0; - raw_spin_unlock(&rt_rq->rt_runtime_lock); - raw_spin_unlock(&rt_b->rt_runtime_lock); - - /* Make rt_rq available for pick_next_task() */ - sched_rt_rq_enqueue(rt_rq); - } -} - -static void __enable_runtime(struct rq *rq) -{ - rt_rq_iter_t iter; - struct rt_rq *rt_rq; - - if (unlikely(!scheduler_running)) - return; - - /* - * Reset each runqueue's bandwidth settings - */ - for_each_rt_rq(rt_rq, iter, rq) { - struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq); - - raw_spin_lock(&rt_b->rt_runtime_lock); - raw_spin_lock(&rt_rq->rt_runtime_lock); - rt_rq->rt_runtime = rt_b->rt_runtime; - rt_rq->rt_time = 0; - rt_rq->rt_throttled = 0; - raw_spin_unlock(&rt_rq->rt_runtime_lock); - raw_spin_unlock(&rt_b->rt_runtime_lock); - } -} - -static void balance_runtime(struct rt_rq *rt_rq) -{ - if (!sched_feat(RT_RUNTIME_SHARE)) - return; - - if (rt_rq->rt_time > rt_rq->rt_runtime) { - raw_spin_unlock(&rt_rq->rt_runtime_lock); - do_balance_runtime(rt_rq); - raw_spin_lock(&rt_rq->rt_runtime_lock); - } -} -#else /* !CONFIG_SMP */ -static inline void balance_runtime(struct rt_rq *rt_rq) {} -#endif /* CONFIG_SMP */ - -static int do_sched_rt_period_timer(struct rt_bandwidth *rt_b, int overrun) -{ - int i, idle = 1, throttled = 0; - const struct cpumask *span; - - span = sched_rt_period_mask(); -#ifdef CONFIG_RT_GROUP_SCHED - /* - * FIXME: isolated CPUs should really leave the root task group, - * whether they are isolcpus or were isolated via cpusets, lest - * the timer run on a CPU which does not service all runqueues, - * potentially leaving other CPUs indefinitely throttled. If - * isolation is really required, the user will turn the throttle - * off to kill the perturbations it causes anyway. Meanwhile, - * this maintains functionality for boot and/or troubleshooting. - */ - if (rt_b == &root_task_group.rt_bandwidth) - span = cpu_online_mask; -#endif - for_each_cpu(i, span) { - int enqueue = 0; - struct rt_rq *rt_rq = sched_rt_period_rt_rq(rt_b, i); - struct rq *rq = rq_of_rt_rq(rt_rq); - - raw_spin_lock(&rq->lock); - if (rt_rq->rt_time) { - u64 runtime; - - raw_spin_lock(&rt_rq->rt_runtime_lock); - if (rt_rq->rt_throttled) - balance_runtime(rt_rq); - runtime = rt_rq->rt_runtime; - rt_rq->rt_time -= min(rt_rq->rt_time, overrun*runtime); - if (rt_rq->rt_throttled && rt_rq->rt_time < runtime) { - rt_rq->rt_throttled = 0; - enqueue = 1; - - /* - * When we're idle and a woken (rt) task is - * throttled check_preempt_curr() will set - * skip_update and the time between the wakeup - * and this unthrottle will get accounted as - * 'runtime'. - */ - if (rt_rq->rt_nr_running && rq->curr == rq->idle) - rq_clock_skip_update(rq, false); - } - if (rt_rq->rt_time || rt_rq->rt_nr_running) - idle = 0; - raw_spin_unlock(&rt_rq->rt_runtime_lock); - } else if (rt_rq->rt_nr_running) { - idle = 0; - if (!rt_rq_throttled(rt_rq)) - enqueue = 1; - } - if (rt_rq->rt_throttled) - throttled = 1; - - if (enqueue) - sched_rt_rq_enqueue(rt_rq); - raw_spin_unlock(&rq->lock); - } - - if (!throttled && (!rt_bandwidth_enabled() || rt_b->rt_runtime == RUNTIME_INF)) - return 1; - - return idle; -} - -static inline int rt_se_prio(struct sched_rt_entity *rt_se) -{ -#ifdef CONFIG_RT_GROUP_SCHED - struct rt_rq *rt_rq = group_rt_rq(rt_se); - - if (rt_rq) - return rt_rq->highest_prio.curr; -#endif - - return rt_task_of(rt_se)->prio; -} - -static int sched_rt_runtime_exceeded(struct rt_rq *rt_rq) -{ - u64 runtime = sched_rt_runtime(rt_rq); - - if (rt_rq->rt_throttled) - return rt_rq_throttled(rt_rq); - - if (runtime >= sched_rt_period(rt_rq)) - return 0; - - balance_runtime(rt_rq); - runtime = sched_rt_runtime(rt_rq); - if (runtime == RUNTIME_INF) - return 0; - - if (rt_rq->rt_time > runtime) { - struct rt_bandwidth *rt_b = sched_rt_bandwidth(rt_rq); - - /* - * Don't actually throttle groups that have no runtime assigned - * but accrue some time due to boosting. - */ - if (likely(rt_b->rt_runtime)) { - rt_rq->rt_throttled = 1; - printk_deferred_once("sched: RT throttling activated\n"); - } else { - /* - * In case we did anyway, make it go away, - * replenishment is a joke, since it will replenish us - * with exactly 0 ns. - */ - rt_rq->rt_time = 0; - } - - if (rt_rq_throttled(rt_rq)) { - sched_rt_rq_dequeue(rt_rq); - return 1; - } - } - - return 0; -} - -/* - * Update the current task's runtime statistics. Skip current tasks that - * are not in our scheduling class. - */ -static void update_curr_rt(struct rq *rq) -{ - struct task_struct *curr = rq->curr; - struct sched_rt_entity *rt_se = &curr->rt; - u64 delta_exec; - - if (curr->sched_class != &rt_sched_class) - return; - - delta_exec = rq_clock_task(rq) - curr->se.exec_start; - if (unlikely((s64)delta_exec <= 0)) - return; - - /* Kick cpufreq (see the comment in kernel/sched/sched.h). */ - cpufreq_update_this_cpu(rq, SCHED_CPUFREQ_RT); - - schedstat_set(curr->se.statistics.exec_max, - max(curr->se.statistics.exec_max, delta_exec)); - - curr->se.sum_exec_runtime += delta_exec; - account_group_exec_runtime(curr, delta_exec); - - curr->se.exec_start = rq_clock_task(rq); - cpuacct_charge(curr, delta_exec); - - sched_rt_avg_update(rq, delta_exec); - - if (!rt_bandwidth_enabled()) - return; - - for_each_sched_rt_entity(rt_se) { - struct rt_rq *rt_rq = rt_rq_of_se(rt_se); - - if (sched_rt_runtime(rt_rq) != RUNTIME_INF) { - raw_spin_lock(&rt_rq->rt_runtime_lock); - rt_rq->rt_time += delta_exec; - if (sched_rt_runtime_exceeded(rt_rq)) - resched_curr(rq); - raw_spin_unlock(&rt_rq->rt_runtime_lock); - } - } -} - -static void -dequeue_top_rt_rq(struct rt_rq *rt_rq) -{ - struct rq *rq = rq_of_rt_rq(rt_rq); - - BUG_ON(&rq->rt != rt_rq); - - if (!rt_rq->rt_queued) - return; - - BUG_ON(!rq->nr_running); - - sub_nr_running(rq, rt_rq->rt_nr_running); - rt_rq->rt_queued = 0; -} - -static void -enqueue_top_rt_rq(struct rt_rq *rt_rq) -{ - struct rq *rq = rq_of_rt_rq(rt_rq); - - BUG_ON(&rq->rt != rt_rq); - - if (rt_rq->rt_queued) - return; - if (rt_rq_throttled(rt_rq) || !rt_rq->rt_nr_running) - return; - - add_nr_running(rq, rt_rq->rt_nr_running); - rt_rq->rt_queued = 1; -} - -#if defined CONFIG_SMP - -static void -inc_rt_prio_smp(struct rt_rq *rt_rq, int prio, int prev_prio) -{ - struct rq *rq = rq_of_rt_rq(rt_rq); - -#ifdef CONFIG_RT_GROUP_SCHED - /* - * Change rq's cpupri only if rt_rq is the top queue. - */ - if (&rq->rt != rt_rq) - return; -#endif - if (rq->online && prio < prev_prio) - cpupri_set(&rq->rd->cpupri, rq->cpu, prio); -} - -static void -dec_rt_prio_smp(struct rt_rq *rt_rq, int prio, int prev_prio) -{ - struct rq *rq = rq_of_rt_rq(rt_rq); - -#ifdef CONFIG_RT_GROUP_SCHED - /* - * Change rq's cpupri only if rt_rq is the top queue. - */ - if (&rq->rt != rt_rq) - return; -#endif - if (rq->online && rt_rq->highest_prio.curr != prev_prio) - cpupri_set(&rq->rd->cpupri, rq->cpu, rt_rq->highest_prio.curr); -} - -#else /* CONFIG_SMP */ - -static inline -void inc_rt_prio_smp(struct rt_rq *rt_rq, int prio, int prev_prio) {} -static inline -void dec_rt_prio_smp(struct rt_rq *rt_rq, int prio, int prev_prio) {} - -#endif /* CONFIG_SMP */ - -#if defined CONFIG_SMP || defined CONFIG_RT_GROUP_SCHED -static void -inc_rt_prio(struct rt_rq *rt_rq, int prio) -{ - int prev_prio = rt_rq->highest_prio.curr; - - if (prio < prev_prio) - rt_rq->highest_prio.curr = prio; - - inc_rt_prio_smp(rt_rq, prio, prev_prio); -} - -static void -dec_rt_prio(struct rt_rq *rt_rq, int prio) -{ - int prev_prio = rt_rq->highest_prio.curr; - - if (rt_rq->rt_nr_running) { - - WARN_ON(prio < prev_prio); - - /* - * This may have been our highest task, and therefore - * we may have some recomputation to do - */ - if (prio == prev_prio) { - struct rt_prio_array *array = &rt_rq->active; - - rt_rq->highest_prio.curr = - sched_find_first_bit(array->bitmap); - } - - } else - rt_rq->highest_prio.curr = MAX_RT_PRIO; - - dec_rt_prio_smp(rt_rq, prio, prev_prio); -} - -#else - -static inline void inc_rt_prio(struct rt_rq *rt_rq, int prio) {} -static inline void dec_rt_prio(struct rt_rq *rt_rq, int prio) {} - -#endif /* CONFIG_SMP || CONFIG_RT_GROUP_SCHED */ - -#ifdef CONFIG_RT_GROUP_SCHED - -static void -inc_rt_group(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) -{ - if (rt_se_boosted(rt_se)) - rt_rq->rt_nr_boosted++; - - if (rt_rq->tg) - start_rt_bandwidth(&rt_rq->tg->rt_bandwidth); -} - -static void -dec_rt_group(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) -{ - if (rt_se_boosted(rt_se)) - rt_rq->rt_nr_boosted--; - - WARN_ON(!rt_rq->rt_nr_running && rt_rq->rt_nr_boosted); -} - -#else /* CONFIG_RT_GROUP_SCHED */ - -static void -inc_rt_group(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) -{ - start_rt_bandwidth(&def_rt_bandwidth); -} - -static inline -void dec_rt_group(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) {} - -#endif /* CONFIG_RT_GROUP_SCHED */ - -static inline -unsigned int rt_se_nr_running(struct sched_rt_entity *rt_se) -{ - struct rt_rq *group_rq = group_rt_rq(rt_se); - - if (group_rq) - return group_rq->rt_nr_running; - else - return 1; -} - -static inline -unsigned int rt_se_rr_nr_running(struct sched_rt_entity *rt_se) -{ - struct rt_rq *group_rq = group_rt_rq(rt_se); - struct task_struct *tsk; - - if (group_rq) - return group_rq->rr_nr_running; - - tsk = rt_task_of(rt_se); - - return (tsk->policy == SCHED_RR) ? 1 : 0; -} - -static inline -void inc_rt_tasks(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) -{ - int prio = rt_se_prio(rt_se); - - WARN_ON(!rt_prio(prio)); - rt_rq->rt_nr_running += rt_se_nr_running(rt_se); - rt_rq->rr_nr_running += rt_se_rr_nr_running(rt_se); - - inc_rt_prio(rt_rq, prio); - inc_rt_migration(rt_se, rt_rq); - inc_rt_group(rt_se, rt_rq); -} - -static inline -void dec_rt_tasks(struct sched_rt_entity *rt_se, struct rt_rq *rt_rq) -{ - WARN_ON(!rt_prio(rt_se_prio(rt_se))); - WARN_ON(!rt_rq->rt_nr_running); - rt_rq->rt_nr_running -= rt_se_nr_running(rt_se); - rt_rq->rr_nr_running -= rt_se_rr_nr_running(rt_se); - - dec_rt_prio(rt_rq, rt_se_prio(rt_se)); - dec_rt_migration(rt_se, rt_rq); - dec_rt_group(rt_se, rt_rq); -} - -/* - * Change rt_se->run_list location unless SAVE && !MOVE - * - * assumes ENQUEUE/DEQUEUE flags match - */ -static inline bool move_entity(unsigned int flags) -{ - if ((flags & (DEQUEUE_SAVE | DEQUEUE_MOVE)) == DEQUEUE_SAVE) - return false; - - return true; -} - -static void __delist_rt_entity(struct sched_rt_entity *rt_se, struct rt_prio_array *array) -{ - list_del_init(&rt_se->run_list); - - if (list_empty(array->queue + rt_se_prio(rt_se))) - __clear_bit(rt_se_prio(rt_se), array->bitmap); - - rt_se->on_list = 0; -} - -static void __enqueue_rt_entity(struct sched_rt_entity *rt_se, unsigned int flags) -{ - struct rt_rq *rt_rq = rt_rq_of_se(rt_se); - struct rt_prio_array *array = &rt_rq->active; - struct rt_rq *group_rq = group_rt_rq(rt_se); - struct list_head *queue = array->queue + rt_se_prio(rt_se); - - /* - * Don't enqueue the group if its throttled, or when empty. - * The latter is a consequence of the former when a child group - * get throttled and the current group doesn't have any other - * active members. - */ - if (group_rq && (rt_rq_throttled(group_rq) || !group_rq->rt_nr_running)) { - if (rt_se->on_list) - __delist_rt_entity(rt_se, array); - return; - } - - if (move_entity(flags)) { - WARN_ON_ONCE(rt_se->on_list); - if (flags & ENQUEUE_HEAD) - list_add(&rt_se->run_list, queue); - else - list_add_tail(&rt_se->run_list, queue); - - __set_bit(rt_se_prio(rt_se), array->bitmap); - rt_se->on_list = 1; - } - rt_se->on_rq = 1; - - inc_rt_tasks(rt_se, rt_rq); -} - -static void __dequeue_rt_entity(struct sched_rt_entity *rt_se, unsigned int flags) -{ - struct rt_rq *rt_rq = rt_rq_of_se(rt_se); - struct rt_prio_array *array = &rt_rq->active; - - if (move_entity(flags)) { - WARN_ON_ONCE(!rt_se->on_list); - __delist_rt_entity(rt_se, array); - } - rt_se->on_rq = 0; - - dec_rt_tasks(rt_se, rt_rq); -} - -/* - * Because the prio of an upper entry depends on the lower - * entries, we must remove entries top - down. - */ -static void dequeue_rt_stack(struct sched_rt_entity *rt_se, unsigned int flags) -{ - struct sched_rt_entity *back = NULL; - - for_each_sched_rt_entity(rt_se) { - rt_se->back = back; - back = rt_se; - } - - dequeue_top_rt_rq(rt_rq_of_se(back)); - - for (rt_se = back; rt_se; rt_se = rt_se->back) { - if (on_rt_rq(rt_se)) - __dequeue_rt_entity(rt_se, flags); - } -} - -static void enqueue_rt_entity(struct sched_rt_entity *rt_se, unsigned int flags) -{ - struct rq *rq = rq_of_rt_se(rt_se); - - dequeue_rt_stack(rt_se, flags); - for_each_sched_rt_entity(rt_se) - __enqueue_rt_entity(rt_se, flags); - enqueue_top_rt_rq(&rq->rt); -} - -static void dequeue_rt_entity(struct sched_rt_entity *rt_se, unsigned int flags) -{ - struct rq *rq = rq_of_rt_se(rt_se); - - dequeue_rt_stack(rt_se, flags); - - for_each_sched_rt_entity(rt_se) { - struct rt_rq *rt_rq = group_rt_rq(rt_se); - - if (rt_rq && rt_rq->rt_nr_running) - __enqueue_rt_entity(rt_se, flags); - } - enqueue_top_rt_rq(&rq->rt); -} - -/* - * Adding/removing a task to/from a priority array: - */ -static void -enqueue_task_rt(struct rq *rq, struct task_struct *p, int flags) -{ - struct sched_rt_entity *rt_se = &p->rt; - - if (flags & ENQUEUE_WAKEUP) - rt_se->timeout = 0; - - enqueue_rt_entity(rt_se, flags); - - if (!task_current(rq, p) && tsk_nr_cpus_allowed(p) > 1) - enqueue_pushable_task(rq, p); -} - -static void dequeue_task_rt(struct rq *rq, struct task_struct *p, int flags) -{ - struct sched_rt_entity *rt_se = &p->rt; - - update_curr_rt(rq); - dequeue_rt_entity(rt_se, flags); - - dequeue_pushable_task(rq, p); -} - -/* - * Put task to the head or the end of the run list without the overhead of - * dequeue followed by enqueue. - */ -static void -requeue_rt_entity(struct rt_rq *rt_rq, struct sched_rt_entity *rt_se, int head) -{ - if (on_rt_rq(rt_se)) { - struct rt_prio_array *array = &rt_rq->active; - struct list_head *queue = array->queue + rt_se_prio(rt_se); - - if (head) - list_move(&rt_se->run_list, queue); - else - list_move_tail(&rt_se->run_list, queue); - } -} - -static void requeue_task_rt(struct rq *rq, struct task_struct *p, int head) -{ - struct sched_rt_entity *rt_se = &p->rt; - struct rt_rq *rt_rq; - - for_each_sched_rt_entity(rt_se) { - rt_rq = rt_rq_of_se(rt_se); - requeue_rt_entity(rt_rq, rt_se, head); - } -} - -static void yield_task_rt(struct rq *rq) -{ - requeue_task_rt(rq, rq->curr, 0); -} - -#ifdef CONFIG_SMP -static int find_lowest_rq(struct task_struct *task); - -static int -select_task_rq_rt(struct task_struct *p, int cpu, int sd_flag, int flags) -{ - struct task_struct *curr; - struct rq *rq; - - /* For anything but wake ups, just return the task_cpu */ - if (sd_flag != SD_BALANCE_WAKE && sd_flag != SD_BALANCE_FORK) - goto out; - - rq = cpu_rq(cpu); - - rcu_read_lock(); - curr = READ_ONCE(rq->curr); /* unlocked access */ - - /* - * If the current task on @p's runqueue is an RT task, then - * try to see if we can wake this RT task up on another - * runqueue. Otherwise simply start this RT task - * on its current runqueue. - * - * We want to avoid overloading runqueues. If the woken - * task is a higher priority, then it will stay on this CPU - * and the lower prio task should be moved to another CPU. - * Even though this will probably make the lower prio task - * lose its cache, we do not want to bounce a higher task - * around just because it gave up its CPU, perhaps for a - * lock? - * - * For equal prio tasks, we just let the scheduler sort it out. - * - * Otherwise, just let it ride on the affined RQ and the - * post-schedule router will push the preempted task away - * - * This test is optimistic, if we get it wrong the load-balancer - * will have to sort it out. - */ - if (curr && unlikely(rt_task(curr)) && - (tsk_nr_cpus_allowed(curr) < 2 || - curr->prio <= p->prio)) { - int target = find_lowest_rq(p); - - /* - * Don't bother moving it if the destination CPU is - * not running a lower priority task. - */ - if (target != -1 && - p->prio < cpu_rq(target)->rt.highest_prio.curr) - cpu = target; - } - rcu_read_unlock(); - -out: - return cpu; -} - -static void check_preempt_equal_prio(struct rq *rq, struct task_struct *p) -{ - /* - * Current can't be migrated, useless to reschedule, - * let's hope p can move out. - */ - if (tsk_nr_cpus_allowed(rq->curr) == 1 || - !cpupri_find(&rq->rd->cpupri, rq->curr, NULL)) - return; - - /* - * p is migratable, so let's not schedule it and - * see if it is pushed or pulled somewhere else. - */ - if (tsk_nr_cpus_allowed(p) != 1 - && cpupri_find(&rq->rd->cpupri, p, NULL)) - return; - - /* - * There appears to be other cpus that can accept - * current and none to run 'p', so lets reschedule - * to try and push current away: - */ - requeue_task_rt(rq, p, 1); - resched_curr(rq); -} - -#endif /* CONFIG_SMP */ - -/* - * Preempt the current task with a newly woken task if needed: - */ -static void check_preempt_curr_rt(struct rq *rq, struct task_struct *p, int flags) -{ - if (p->prio < rq->curr->prio) { - resched_curr(rq); - return; - } - -#ifdef CONFIG_SMP - /* - * If: - * - * - the newly woken task is of equal priority to the current task - * - the newly woken task is non-migratable while current is migratable - * - current will be preempted on the next reschedule - * - * we should check to see if current can readily move to a different - * cpu. If so, we will reschedule to allow the push logic to try - * to move current somewhere else, making room for our non-migratable - * task. - */ - if (p->prio == rq->curr->prio && !test_tsk_need_resched(rq->curr)) - check_preempt_equal_prio(rq, p); -#endif -} - -static struct sched_rt_entity *pick_next_rt_entity(struct rq *rq, - struct rt_rq *rt_rq) -{ - struct rt_prio_array *array = &rt_rq->active; - struct sched_rt_entity *next = NULL; - struct list_head *queue; - int idx; - - idx = sched_find_first_bit(array->bitmap); - BUG_ON(idx >= MAX_RT_PRIO); - - queue = array->queue + idx; - next = list_entry(queue->next, struct sched_rt_entity, run_list); - - return next; -} - -static struct task_struct *_pick_next_task_rt(struct rq *rq) -{ - struct sched_rt_entity *rt_se; - struct task_struct *p; - struct rt_rq *rt_rq = &rq->rt; - - do { - rt_se = pick_next_rt_entity(rq, rt_rq); - BUG_ON(!rt_se); - rt_rq = group_rt_rq(rt_se); - } while (rt_rq); - - p = rt_task_of(rt_se); - p->se.exec_start = rq_clock_task(rq); - - return p; -} - -static struct task_struct * -pick_next_task_rt(struct rq *rq, struct task_struct *prev, struct pin_cookie cookie) -{ - struct task_struct *p; - struct rt_rq *rt_rq = &rq->rt; - - if (need_pull_rt_task(rq, prev)) { - /* - * This is OK, because current is on_cpu, which avoids it being - * picked for load-balance and preemption/IRQs are still - * disabled avoiding further scheduler activity on it and we're - * being very careful to re-start the picking loop. - */ - lockdep_unpin_lock(&rq->lock, cookie); - pull_rt_task(rq); - lockdep_repin_lock(&rq->lock, cookie); - /* - * pull_rt_task() can drop (and re-acquire) rq->lock; this - * means a dl or stop task can slip in, in which case we need - * to re-start task selection. - */ - if (unlikely((rq->stop && task_on_rq_queued(rq->stop)) || - rq->dl.dl_nr_running)) - return RETRY_TASK; - } - - /* - * We may dequeue prev's rt_rq in put_prev_task(). - * So, we update time before rt_nr_running check. - */ - if (prev->sched_class == &rt_sched_class) - update_curr_rt(rq); - - if (!rt_rq->rt_queued) - return NULL; - - put_prev_task(rq, prev); - - p = _pick_next_task_rt(rq); - - /* The running task is never eligible for pushing */ - dequeue_pushable_task(rq, p); - - queue_push_tasks(rq); - - return p; -} - -static void put_prev_task_rt(struct rq *rq, struct task_struct *p) -{ - update_curr_rt(rq); - - /* - * The previous task needs to be made eligible for pushing - * if it is still active - */ - if (on_rt_rq(&p->rt) && tsk_nr_cpus_allowed(p) > 1) - enqueue_pushable_task(rq, p); -} - -#ifdef CONFIG_SMP - -/* Only try algorithms three times */ -#define RT_MAX_TRIES 3 - -static int pick_rt_task(struct rq *rq, struct task_struct *p, int cpu) -{ - if (!task_running(rq, p) && - cpumask_test_cpu(cpu, tsk_cpus_allowed(p))) - return 1; - return 0; -} - -/* - * Return the highest pushable rq's task, which is suitable to be executed - * on the cpu, NULL otherwise - */ -static struct task_struct *pick_highest_pushable_task(struct rq *rq, int cpu) -{ - struct plist_head *head = &rq->rt.pushable_tasks; - struct task_struct *p; - - if (!has_pushable_tasks(rq)) - return NULL; - - plist_for_each_entry(p, head, pushable_tasks) { - if (pick_rt_task(rq, p, cpu)) - return p; - } - - return NULL; -} - -static DEFINE_PER_CPU(cpumask_var_t, local_cpu_mask); - -static int find_lowest_rq(struct task_struct *task) -{ - struct sched_domain *sd; - struct cpumask *lowest_mask = this_cpu_cpumask_var_ptr(local_cpu_mask); - int this_cpu = smp_processor_id(); - int cpu = task_cpu(task); - - /* Make sure the mask is initialized first */ - if (unlikely(!lowest_mask)) - return -1; - - if (tsk_nr_cpus_allowed(task) == 1) - return -1; /* No other targets possible */ - - if (!cpupri_find(&task_rq(task)->rd->cpupri, task, lowest_mask)) - return -1; /* No targets found */ - - /* - * At this point we have built a mask of cpus representing the - * lowest priority tasks in the system. Now we want to elect - * the best one based on our affinity and topology. - * - * We prioritize the last cpu that the task executed on since - * it is most likely cache-hot in that location. - */ - if (cpumask_test_cpu(cpu, lowest_mask)) - return cpu; - - /* - * Otherwise, we consult the sched_domains span maps to figure - * out which cpu is logically closest to our hot cache data. - */ - if (!cpumask_test_cpu(this_cpu, lowest_mask)) - this_cpu = -1; /* Skip this_cpu opt if not among lowest */ - - rcu_read_lock(); - for_each_domain(cpu, sd) { - if (sd->flags & SD_WAKE_AFFINE) { - int best_cpu; - - /* - * "this_cpu" is cheaper to preempt than a - * remote processor. - */ - if (this_cpu != -1 && - cpumask_test_cpu(this_cpu, sched_domain_span(sd))) { - rcu_read_unlock(); - return this_cpu; - } - - best_cpu = cpumask_first_and(lowest_mask, - sched_domain_span(sd)); - if (best_cpu < nr_cpu_ids) { - rcu_read_unlock(); - return best_cpu; - } - } - } - rcu_read_unlock(); - - /* - * And finally, if there were no matches within the domains - * just give the caller *something* to work with from the compatible - * locations. - */ - if (this_cpu != -1) - return this_cpu; - - cpu = cpumask_any(lowest_mask); - if (cpu < nr_cpu_ids) - return cpu; - return -1; -} - -/* Will lock the rq it finds */ -static struct rq *find_lock_lowest_rq(struct task_struct *task, struct rq *rq) -{ - struct rq *lowest_rq = NULL; - int tries; - int cpu; - - for (tries = 0; tries < RT_MAX_TRIES; tries++) { - cpu = find_lowest_rq(task); - - if ((cpu == -1) || (cpu == rq->cpu)) - break; - - lowest_rq = cpu_rq(cpu); - - if (lowest_rq->rt.highest_prio.curr <= task->prio) { - /* - * Target rq has tasks of equal or higher priority, - * retrying does not release any lock and is unlikely - * to yield a different result. - */ - lowest_rq = NULL; - break; - } - - /* if the prio of this runqueue changed, try again */ - if (double_lock_balance(rq, lowest_rq)) { - /* - * We had to unlock the run queue. In - * the mean time, task could have - * migrated already or had its affinity changed. - * Also make sure that it wasn't scheduled on its rq. - */ - if (unlikely(task_rq(task) != rq || - !cpumask_test_cpu(lowest_rq->cpu, - tsk_cpus_allowed(task)) || - task_running(rq, task) || - !rt_task(task) || - !task_on_rq_queued(task))) { - - double_unlock_balance(rq, lowest_rq); - lowest_rq = NULL; - break; - } - } - - /* If this rq is still suitable use it. */ - if (lowest_rq->rt.highest_prio.curr > task->prio) - break; - - /* try again */ - double_unlock_balance(rq, lowest_rq); - lowest_rq = NULL; - } - - return lowest_rq; -} - -static struct task_struct *pick_next_pushable_task(struct rq *rq) -{ - struct task_struct *p; - - if (!has_pushable_tasks(rq)) - return NULL; - - p = plist_first_entry(&rq->rt.pushable_tasks, - struct task_struct, pushable_tasks); - - BUG_ON(rq->cpu != task_cpu(p)); - BUG_ON(task_current(rq, p)); - BUG_ON(tsk_nr_cpus_allowed(p) <= 1); - - BUG_ON(!task_on_rq_queued(p)); - BUG_ON(!rt_task(p)); - - return p; -} - -/* - * If the current CPU has more than one RT task, see if the non - * running task can migrate over to a CPU that is running a task - * of lesser priority. - */ -static int push_rt_task(struct rq *rq) -{ - struct task_struct *next_task; - struct rq *lowest_rq; - int ret = 0; - - if (!rq->rt.overloaded) - return 0; - - next_task = pick_next_pushable_task(rq); - if (!next_task) - return 0; - -retry: - if (unlikely(next_task == rq->curr)) { - WARN_ON(1); - return 0; - } - - /* - * It's possible that the next_task slipped in of - * higher priority than current. If that's the case - * just reschedule current. - */ - if (unlikely(next_task->prio < rq->curr->prio)) { - resched_curr(rq); - return 0; - } - - /* We might release rq lock */ - get_task_struct(next_task); - - /* find_lock_lowest_rq locks the rq if found */ - lowest_rq = find_lock_lowest_rq(next_task, rq); - if (!lowest_rq) { - struct task_struct *task; - /* - * find_lock_lowest_rq releases rq->lock - * so it is possible that next_task has migrated. - * - * We need to make sure that the task is still on the same - * run-queue and is also still the next task eligible for - * pushing. - */ - task = pick_next_pushable_task(rq); - if (task_cpu(next_task) == rq->cpu && task == next_task) { - /* - * The task hasn't migrated, and is still the next - * eligible task, but we failed to find a run-queue - * to push it to. Do not retry in this case, since - * other cpus will pull from us when ready. - */ - goto out; - } - - if (!task) - /* No more tasks, just exit */ - goto out; - - /* - * Something has shifted, try again. - */ - put_task_struct(next_task); - next_task = task; - goto retry; - } - - deactivate_task(rq, next_task, 0); - set_task_cpu(next_task, lowest_rq->cpu); - activate_task(lowest_rq, next_task, 0); - ret = 1; - - resched_curr(lowest_rq); - - double_unlock_balance(rq, lowest_rq); - -out: - put_task_struct(next_task); - - return ret; -} - -static void push_rt_tasks(struct rq *rq) -{ - /* push_rt_task will return true if it moved an RT */ - while (push_rt_task(rq)) - ; -} - -#ifdef HAVE_RT_PUSH_IPI -/* - * The search for the next cpu always starts at rq->cpu and ends - * when we reach rq->cpu again. It will never return rq->cpu. - * This returns the next cpu to check, or nr_cpu_ids if the loop - * is complete. - * - * rq->rt.push_cpu holds the last cpu returned by this function, - * or if this is the first instance, it must hold rq->cpu. - */ -static int rto_next_cpu(struct rq *rq) -{ - int prev_cpu = rq->rt.push_cpu; - int cpu; - - cpu = cpumask_next(prev_cpu, rq->rd->rto_mask); - - /* - * If the previous cpu is less than the rq's CPU, then it already - * passed the end of the mask, and has started from the beginning. - * We end if the next CPU is greater or equal to rq's CPU. - */ - if (prev_cpu < rq->cpu) { - if (cpu >= rq->cpu) - return nr_cpu_ids; - - } else if (cpu >= nr_cpu_ids) { - /* - * We passed the end of the mask, start at the beginning. - * If the result is greater or equal to the rq's CPU, then - * the loop is finished. - */ - cpu = cpumask_first(rq->rd->rto_mask); - if (cpu >= rq->cpu) - return nr_cpu_ids; - } - rq->rt.push_cpu = cpu; - - /* Return cpu to let the caller know if the loop is finished or not */ - return cpu; -} - -static int find_next_push_cpu(struct rq *rq) -{ - struct rq *next_rq; - int cpu; - - while (1) { - cpu = rto_next_cpu(rq); - if (cpu >= nr_cpu_ids) - break; - next_rq = cpu_rq(cpu); - - /* Make sure the next rq can push to this rq */ - if (next_rq->rt.highest_prio.next < rq->rt.highest_prio.curr) - break; - } - - return cpu; -} - -#define RT_PUSH_IPI_EXECUTING 1 -#define RT_PUSH_IPI_RESTART 2 - -static void tell_cpu_to_push(struct rq *rq) -{ - int cpu; - - if (rq->rt.push_flags & RT_PUSH_IPI_EXECUTING) { - raw_spin_lock(&rq->rt.push_lock); - /* Make sure it's still executing */ - if (rq->rt.push_flags & RT_PUSH_IPI_EXECUTING) { - /* - * Tell the IPI to restart the loop as things have - * changed since it started. - */ - rq->rt.push_flags |= RT_PUSH_IPI_RESTART; - raw_spin_unlock(&rq->rt.push_lock); - return; - } - raw_spin_unlock(&rq->rt.push_lock); - } - - /* When here, there's no IPI going around */ - - rq->rt.push_cpu = rq->cpu; - cpu = find_next_push_cpu(rq); - if (cpu >= nr_cpu_ids) - return; - - rq->rt.push_flags = RT_PUSH_IPI_EXECUTING; - - irq_work_queue_on(&rq->rt.push_work, cpu); -} - -/* Called from hardirq context */ -static void try_to_push_tasks(void *arg) -{ - struct rt_rq *rt_rq = arg; - struct rq *rq, *src_rq; - int this_cpu; - int cpu; - - this_cpu = rt_rq->push_cpu; - - /* Paranoid check */ - BUG_ON(this_cpu != smp_processor_id()); - - rq = cpu_rq(this_cpu); - src_rq = rq_of_rt_rq(rt_rq); - -again: - if (has_pushable_tasks(rq)) { - raw_spin_lock(&rq->lock); - push_rt_task(rq); - raw_spin_unlock(&rq->lock); - } - - /* Pass the IPI to the next rt overloaded queue */ - raw_spin_lock(&rt_rq->push_lock); - /* - * If the source queue changed since the IPI went out, - * we need to restart the search from that CPU again. - */ - if (rt_rq->push_flags & RT_PUSH_IPI_RESTART) { - rt_rq->push_flags &= ~RT_PUSH_IPI_RESTART; - rt_rq->push_cpu = src_rq->cpu; - } - - cpu = find_next_push_cpu(src_rq); - - if (cpu >= nr_cpu_ids) - rt_rq->push_flags &= ~RT_PUSH_IPI_EXECUTING; - raw_spin_unlock(&rt_rq->push_lock); - - if (cpu >= nr_cpu_ids) - return; - - /* - * It is possible that a restart caused this CPU to be - * chosen again. Don't bother with an IPI, just see if we - * have more to push. - */ - if (unlikely(cpu == rq->cpu)) - goto again; - - /* Try the next RT overloaded CPU */ - irq_work_queue_on(&rt_rq->push_work, cpu); -} - -static void push_irq_work_func(struct irq_work *work) -{ - struct rt_rq *rt_rq = container_of(work, struct rt_rq, push_work); - - try_to_push_tasks(rt_rq); -} -#endif /* HAVE_RT_PUSH_IPI */ - -static void pull_rt_task(struct rq *this_rq) -{ - int this_cpu = this_rq->cpu, cpu; - bool resched = false; - struct task_struct *p; - struct rq *src_rq; - - if (likely(!rt_overloaded(this_rq))) - return; - - /* - * Match the barrier from rt_set_overloaded; this guarantees that if we - * see overloaded we must also see the rto_mask bit. - */ - smp_rmb(); - -#ifdef HAVE_RT_PUSH_IPI - if (sched_feat(RT_PUSH_IPI)) { - tell_cpu_to_push(this_rq); - return; - } -#endif - - for_each_cpu(cpu, this_rq->rd->rto_mask) { - if (this_cpu == cpu) - continue; - - src_rq = cpu_rq(cpu); - - /* - * Don't bother taking the src_rq->lock if the next highest - * task is known to be lower-priority than our current task. - * This may look racy, but if this value is about to go - * logically higher, the src_rq will push this task away. - * And if its going logically lower, we do not care - */ - if (src_rq->rt.highest_prio.next >= - this_rq->rt.highest_prio.curr) - continue; - - /* - * We can potentially drop this_rq's lock in - * double_lock_balance, and another CPU could - * alter this_rq - */ - double_lock_balance(this_rq, src_rq); - - /* - * We can pull only a task, which is pushable - * on its rq, and no others. - */ - p = pick_highest_pushable_task(src_rq, this_cpu); - - /* - * Do we have an RT task that preempts - * the to-be-scheduled task? - */ - if (p && (p->prio < this_rq->rt.highest_prio.curr)) { - WARN_ON(p == src_rq->curr); - WARN_ON(!task_on_rq_queued(p)); - - /* - * There's a chance that p is higher in priority - * than what's currently running on its cpu. - * This is just that p is wakeing up and hasn't - * had a chance to schedule. We only pull - * p if it is lower in priority than the - * current task on the run queue - */ - if (p->prio < src_rq->curr->prio) - goto skip; - - resched = true; - - deactivate_task(src_rq, p, 0); - set_task_cpu(p, this_cpu); - activate_task(this_rq, p, 0); - /* - * We continue with the search, just in - * case there's an even higher prio task - * in another runqueue. (low likelihood - * but possible) - */ - } -skip: - double_unlock_balance(this_rq, src_rq); - } - - if (resched) - resched_curr(this_rq); -} - -/* - * If we are not running and we are not going to reschedule soon, we should - * try to push tasks away now - */ -static void task_woken_rt(struct rq *rq, struct task_struct *p) -{ - if (!task_running(rq, p) && - !test_tsk_need_resched(rq->curr) && - tsk_nr_cpus_allowed(p) > 1 && - (dl_task(rq->curr) || rt_task(rq->curr)) && - (tsk_nr_cpus_allowed(rq->curr) < 2 || - rq->curr->prio <= p->prio)) - push_rt_tasks(rq); -} - -/* Assumes rq->lock is held */ -static void rq_online_rt(struct rq *rq) -{ - if (rq->rt.overloaded) - rt_set_overload(rq); - - __enable_runtime(rq); - - cpupri_set(&rq->rd->cpupri, rq->cpu, rq->rt.highest_prio.curr); -} - -/* Assumes rq->lock is held */ -static void rq_offline_rt(struct rq *rq) -{ - if (rq->rt.overloaded) - rt_clear_overload(rq); - - __disable_runtime(rq); - - cpupri_set(&rq->rd->cpupri, rq->cpu, CPUPRI_INVALID); -} - -/* - * When switch from the rt queue, we bring ourselves to a position - * that we might want to pull RT tasks from other runqueues. - */ -static void switched_from_rt(struct rq *rq, struct task_struct *p) -{ - /* - * If there are other RT tasks then we will reschedule - * and the scheduling of the other RT tasks will handle - * the balancing. But if we are the last RT task - * we may need to handle the pulling of RT tasks - * now. - */ - if (!task_on_rq_queued(p) || rq->rt.rt_nr_running) - return; - - queue_pull_task(rq); -} - -void __init init_sched_rt_class(void) -{ - unsigned int i; - - for_each_possible_cpu(i) { - zalloc_cpumask_var_node(&per_cpu(local_cpu_mask, i), - GFP_KERNEL, cpu_to_node(i)); - } -} -#endif /* CONFIG_SMP */ - -/* - * When switching a task to RT, we may overload the runqueue - * with RT tasks. In this case we try to push them off to - * other runqueues. - */ -static void switched_to_rt(struct rq *rq, struct task_struct *p) -{ - /* - * If we are already running, then there's nothing - * that needs to be done. But if we are not running - * we may need to preempt the current running task. - * If that current running task is also an RT task - * then see if we can move to another run queue. - */ - if (task_on_rq_queued(p) && rq->curr != p) { -#ifdef CONFIG_SMP - if (tsk_nr_cpus_allowed(p) > 1 && rq->rt.overloaded) - queue_push_tasks(rq); -#else - if (p->prio < rq->curr->prio) - resched_curr(rq); -#endif /* CONFIG_SMP */ - } -} - -/* - * Priority of the task has changed. This may cause - * us to initiate a push or pull. - */ -static void -prio_changed_rt(struct rq *rq, struct task_struct *p, int oldprio) -{ - if (!task_on_rq_queued(p)) - return; - - if (rq->curr == p) { -#ifdef CONFIG_SMP - /* - * If our priority decreases while running, we - * may need to pull tasks to this runqueue. - */ - if (oldprio < p->prio) - queue_pull_task(rq); - - /* - * If there's a higher priority task waiting to run - * then reschedule. - */ - if (p->prio > rq->rt.highest_prio.curr) - resched_curr(rq); -#else - /* For UP simply resched on drop of prio */ - if (oldprio < p->prio) - resched_curr(rq); -#endif /* CONFIG_SMP */ - } else { - /* - * This task is not running, but if it is - * greater than the current running task - * then reschedule. - */ - if (p->prio < rq->curr->prio) - resched_curr(rq); - } -} - -static void watchdog(struct rq *rq, struct task_struct *p) -{ - unsigned long soft, hard; - - /* max may change after cur was read, this will be fixed next tick */ - soft = task_rlimit(p, RLIMIT_RTTIME); - hard = task_rlimit_max(p, RLIMIT_RTTIME); - - if (soft != RLIM_INFINITY) { - unsigned long next; - - if (p->rt.watchdog_stamp != jiffies) { - p->rt.timeout++; - p->rt.watchdog_stamp = jiffies; - } - - next = DIV_ROUND_UP(min(soft, hard), USEC_PER_SEC/HZ); - if (p->rt.timeout > next) - p->cputime_expires.sched_exp = p->se.sum_exec_runtime; - } -} - -static void task_tick_rt(struct rq *rq, struct task_struct *p, int queued) -{ - struct sched_rt_entity *rt_se = &p->rt; - - update_curr_rt(rq); - - watchdog(rq, p); - - /* - * RR tasks need a special form of timeslice management. - * FIFO tasks have no timeslices. - */ - if (p->policy != SCHED_RR) - return; - - if (--p->rt.time_slice) - return; - - p->rt.time_slice = sched_rr_timeslice; - - /* - * Requeue to the end of queue if we (and all of our ancestors) are not - * the only element on the queue - */ - for_each_sched_rt_entity(rt_se) { - if (rt_se->run_list.prev != rt_se->run_list.next) { - requeue_task_rt(rq, p, 0); - resched_curr(rq); - return; - } - } -} - -static void set_curr_task_rt(struct rq *rq) -{ - struct task_struct *p = rq->curr; - - p->se.exec_start = rq_clock_task(rq); - - /* The running task is never eligible for pushing */ - dequeue_pushable_task(rq, p); -} - -static unsigned int get_rr_interval_rt(struct rq *rq, struct task_struct *task) -{ - /* - * Time slice is 0 for SCHED_FIFO tasks - */ - if (task->policy == SCHED_RR) - return sched_rr_timeslice; - else - return 0; -} - -const struct sched_class rt_sched_class = { - .next = &fair_sched_class, - .enqueue_task = enqueue_task_rt, - .dequeue_task = dequeue_task_rt, - .yield_task = yield_task_rt, - - .check_preempt_curr = check_preempt_curr_rt, - - .pick_next_task = pick_next_task_rt, - .put_prev_task = put_prev_task_rt, - -#ifdef CONFIG_SMP - .select_task_rq = select_task_rq_rt, - - .set_cpus_allowed = set_cpus_allowed_common, - .rq_online = rq_online_rt, - .rq_offline = rq_offline_rt, - .task_woken = task_woken_rt, - .switched_from = switched_from_rt, -#endif - - .set_curr_task = set_curr_task_rt, - .task_tick = task_tick_rt, - - .get_rr_interval = get_rr_interval_rt, - - .prio_changed = prio_changed_rt, - .switched_to = switched_to_rt, - - .update_curr = update_curr_rt, -}; - -#ifdef CONFIG_SCHED_DEBUG -extern void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq); - -void print_rt_stats(struct seq_file *m, int cpu) -{ - rt_rq_iter_t iter; - struct rt_rq *rt_rq; - - rcu_read_lock(); - for_each_rt_rq(rt_rq, iter, cpu_rq(cpu)) - print_rt_rq(m, cpu, rt_rq); - rcu_read_unlock(); -} -#endif /* CONFIG_SCHED_DEBUG */ diff --git a/src/linux/kernel/sched/sched.h b/src/linux/kernel/sched/sched.h deleted file mode 100644 index 055f935..0000000 --- a/src/linux/kernel/sched/sched.h +++ /dev/null @@ -1,1817 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "cpupri.h" -#include "cpudeadline.h" -#include "cpuacct.h" - -#ifdef CONFIG_SCHED_DEBUG -#define SCHED_WARN_ON(x) WARN_ONCE(x, #x) -#else -#define SCHED_WARN_ON(x) ((void)(x)) -#endif - -struct rq; -struct cpuidle_state; - -/* task_struct::on_rq states: */ -#define TASK_ON_RQ_QUEUED 1 -#define TASK_ON_RQ_MIGRATING 2 - -extern __read_mostly int scheduler_running; - -extern unsigned long calc_load_update; -extern atomic_long_t calc_load_tasks; - -extern void calc_global_load_tick(struct rq *this_rq); -extern long calc_load_fold_active(struct rq *this_rq, long adjust); - -#ifdef CONFIG_SMP -extern void cpu_load_update_active(struct rq *this_rq); -#else -static inline void cpu_load_update_active(struct rq *this_rq) { } -#endif - -/* - * Helpers for converting nanosecond timing to jiffy resolution - */ -#define NS_TO_JIFFIES(TIME) ((unsigned long)(TIME) / (NSEC_PER_SEC / HZ)) - -/* - * Increase resolution of nice-level calculations for 64-bit architectures. - * The extra resolution improves shares distribution and load balancing of - * low-weight task groups (eg. nice +19 on an autogroup), deeper taskgroup - * hierarchies, especially on larger systems. This is not a user-visible change - * and does not change the user-interface for setting shares/weights. - * - * We increase resolution only if we have enough bits to allow this increased - * resolution (i.e. 64bit). The costs for increasing resolution when 32bit are - * pretty high and the returns do not justify the increased costs. - * - * Really only required when CONFIG_FAIR_GROUP_SCHED is also set, but to - * increase coverage and consistency always enable it on 64bit platforms. - */ -#ifdef CONFIG_64BIT -# define NICE_0_LOAD_SHIFT (SCHED_FIXEDPOINT_SHIFT + SCHED_FIXEDPOINT_SHIFT) -# define scale_load(w) ((w) << SCHED_FIXEDPOINT_SHIFT) -# define scale_load_down(w) ((w) >> SCHED_FIXEDPOINT_SHIFT) -#else -# define NICE_0_LOAD_SHIFT (SCHED_FIXEDPOINT_SHIFT) -# define scale_load(w) (w) -# define scale_load_down(w) (w) -#endif - -/* - * Task weight (visible to users) and its load (invisible to users) have - * independent resolution, but they should be well calibrated. We use - * scale_load() and scale_load_down(w) to convert between them. The - * following must be true: - * - * scale_load(sched_prio_to_weight[USER_PRIO(NICE_TO_PRIO(0))]) == NICE_0_LOAD - * - */ -#define NICE_0_LOAD (1L << NICE_0_LOAD_SHIFT) - -/* - * Single value that decides SCHED_DEADLINE internal math precision. - * 10 -> just above 1us - * 9 -> just above 0.5us - */ -#define DL_SCALE (10) - -/* - * These are the 'tuning knobs' of the scheduler: - */ - -/* - * single value that denotes runtime == period, ie unlimited time. - */ -#define RUNTIME_INF ((u64)~0ULL) - -static inline int idle_policy(int policy) -{ - return policy == SCHED_IDLE; -} -static inline int fair_policy(int policy) -{ - return policy == SCHED_NORMAL || policy == SCHED_BATCH; -} - -static inline int rt_policy(int policy) -{ - return policy == SCHED_FIFO || policy == SCHED_RR; -} - -static inline int dl_policy(int policy) -{ - return policy == SCHED_DEADLINE; -} -static inline bool valid_policy(int policy) -{ - return idle_policy(policy) || fair_policy(policy) || - rt_policy(policy) || dl_policy(policy); -} - -static inline int task_has_rt_policy(struct task_struct *p) -{ - return rt_policy(p->policy); -} - -static inline int task_has_dl_policy(struct task_struct *p) -{ - return dl_policy(p->policy); -} - -/* - * Tells if entity @a should preempt entity @b. - */ -static inline bool -dl_entity_preempt(struct sched_dl_entity *a, struct sched_dl_entity *b) -{ - return dl_time_before(a->deadline, b->deadline); -} - -/* - * This is the priority-queue data structure of the RT scheduling class: - */ -struct rt_prio_array { - DECLARE_BITMAP(bitmap, MAX_RT_PRIO+1); /* include 1 bit for delimiter */ - struct list_head queue[MAX_RT_PRIO]; -}; - -struct rt_bandwidth { - /* nests inside the rq lock: */ - raw_spinlock_t rt_runtime_lock; - ktime_t rt_period; - u64 rt_runtime; - struct hrtimer rt_period_timer; - unsigned int rt_period_active; -}; - -void __dl_clear_params(struct task_struct *p); - -/* - * To keep the bandwidth of -deadline tasks and groups under control - * we need some place where: - * - store the maximum -deadline bandwidth of the system (the group); - * - cache the fraction of that bandwidth that is currently allocated. - * - * This is all done in the data structure below. It is similar to the - * one used for RT-throttling (rt_bandwidth), with the main difference - * that, since here we are only interested in admission control, we - * do not decrease any runtime while the group "executes", neither we - * need a timer to replenish it. - * - * With respect to SMP, the bandwidth is given on a per-CPU basis, - * meaning that: - * - dl_bw (< 100%) is the bandwidth of the system (group) on each CPU; - * - dl_total_bw array contains, in the i-eth element, the currently - * allocated bandwidth on the i-eth CPU. - * Moreover, groups consume bandwidth on each CPU, while tasks only - * consume bandwidth on the CPU they're running on. - * Finally, dl_total_bw_cpu is used to cache the index of dl_total_bw - * that will be shown the next time the proc or cgroup controls will - * be red. It on its turn can be changed by writing on its own - * control. - */ -struct dl_bandwidth { - raw_spinlock_t dl_runtime_lock; - u64 dl_runtime; - u64 dl_period; -}; - -static inline int dl_bandwidth_enabled(void) -{ - return sysctl_sched_rt_runtime >= 0; -} - -extern struct dl_bw *dl_bw_of(int i); - -struct dl_bw { - raw_spinlock_t lock; - u64 bw, total_bw; -}; - -static inline -void __dl_clear(struct dl_bw *dl_b, u64 tsk_bw) -{ - dl_b->total_bw -= tsk_bw; -} - -static inline -void __dl_add(struct dl_bw *dl_b, u64 tsk_bw) -{ - dl_b->total_bw += tsk_bw; -} - -static inline -bool __dl_overflow(struct dl_bw *dl_b, int cpus, u64 old_bw, u64 new_bw) -{ - return dl_b->bw != -1 && - dl_b->bw * cpus < dl_b->total_bw - old_bw + new_bw; -} - -extern struct mutex sched_domains_mutex; - -#ifdef CONFIG_CGROUP_SCHED - -#include - -struct cfs_rq; -struct rt_rq; - -extern struct list_head task_groups; - -struct cfs_bandwidth { -#ifdef CONFIG_CFS_BANDWIDTH - raw_spinlock_t lock; - ktime_t period; - u64 quota, runtime; - s64 hierarchical_quota; - u64 runtime_expires; - - int idle, period_active; - struct hrtimer period_timer, slack_timer; - struct list_head throttled_cfs_rq; - - /* statistics */ - int nr_periods, nr_throttled; - u64 throttled_time; -#endif -}; - -/* task group related information */ -struct task_group { - struct cgroup_subsys_state css; - -#ifdef CONFIG_FAIR_GROUP_SCHED - /* schedulable entities of this group on each cpu */ - struct sched_entity **se; - /* runqueue "owned" by this group on each cpu */ - struct cfs_rq **cfs_rq; - unsigned long shares; - -#ifdef CONFIG_SMP - /* - * load_avg can be heavily contended at clock tick time, so put - * it in its own cacheline separated from the fields above which - * will also be accessed at each tick. - */ - atomic_long_t load_avg ____cacheline_aligned; -#endif -#endif - -#ifdef CONFIG_RT_GROUP_SCHED - struct sched_rt_entity **rt_se; - struct rt_rq **rt_rq; - - struct rt_bandwidth rt_bandwidth; -#endif - - struct rcu_head rcu; - struct list_head list; - - struct task_group *parent; - struct list_head siblings; - struct list_head children; - -#ifdef CONFIG_SCHED_AUTOGROUP - struct autogroup *autogroup; -#endif - - struct cfs_bandwidth cfs_bandwidth; -}; - -#ifdef CONFIG_FAIR_GROUP_SCHED -#define ROOT_TASK_GROUP_LOAD NICE_0_LOAD - -/* - * A weight of 0 or 1 can cause arithmetics problems. - * A weight of a cfs_rq is the sum of weights of which entities - * are queued on this cfs_rq, so a weight of a entity should not be - * too large, so as the shares value of a task group. - * (The default weight is 1024 - so there's no practical - * limitation from this.) - */ -#define MIN_SHARES (1UL << 1) -#define MAX_SHARES (1UL << 18) -#endif - -typedef int (*tg_visitor)(struct task_group *, void *); - -extern int walk_tg_tree_from(struct task_group *from, - tg_visitor down, tg_visitor up, void *data); - -/* - * Iterate the full tree, calling @down when first entering a node and @up when - * leaving it for the final time. - * - * Caller must hold rcu_lock or sufficient equivalent. - */ -static inline int walk_tg_tree(tg_visitor down, tg_visitor up, void *data) -{ - return walk_tg_tree_from(&root_task_group, down, up, data); -} - -extern int tg_nop(struct task_group *tg, void *data); - -extern void free_fair_sched_group(struct task_group *tg); -extern int alloc_fair_sched_group(struct task_group *tg, struct task_group *parent); -extern void online_fair_sched_group(struct task_group *tg); -extern void unregister_fair_sched_group(struct task_group *tg); -extern void init_tg_cfs_entry(struct task_group *tg, struct cfs_rq *cfs_rq, - struct sched_entity *se, int cpu, - struct sched_entity *parent); -extern void init_cfs_bandwidth(struct cfs_bandwidth *cfs_b); - -extern void __refill_cfs_bandwidth_runtime(struct cfs_bandwidth *cfs_b); -extern void start_cfs_bandwidth(struct cfs_bandwidth *cfs_b); -extern void unthrottle_cfs_rq(struct cfs_rq *cfs_rq); - -extern void free_rt_sched_group(struct task_group *tg); -extern int alloc_rt_sched_group(struct task_group *tg, struct task_group *parent); -extern void init_tg_rt_entry(struct task_group *tg, struct rt_rq *rt_rq, - struct sched_rt_entity *rt_se, int cpu, - struct sched_rt_entity *parent); - -extern struct task_group *sched_create_group(struct task_group *parent); -extern void sched_online_group(struct task_group *tg, - struct task_group *parent); -extern void sched_destroy_group(struct task_group *tg); -extern void sched_offline_group(struct task_group *tg); - -extern void sched_move_task(struct task_struct *tsk); - -#ifdef CONFIG_FAIR_GROUP_SCHED -extern int sched_group_set_shares(struct task_group *tg, unsigned long shares); - -#ifdef CONFIG_SMP -extern void set_task_rq_fair(struct sched_entity *se, - struct cfs_rq *prev, struct cfs_rq *next); -#else /* !CONFIG_SMP */ -static inline void set_task_rq_fair(struct sched_entity *se, - struct cfs_rq *prev, struct cfs_rq *next) { } -#endif /* CONFIG_SMP */ -#endif /* CONFIG_FAIR_GROUP_SCHED */ - -#else /* CONFIG_CGROUP_SCHED */ - -struct cfs_bandwidth { }; - -#endif /* CONFIG_CGROUP_SCHED */ - -/* CFS-related fields in a runqueue */ -struct cfs_rq { - struct load_weight load; - unsigned int nr_running, h_nr_running; - - u64 exec_clock; - u64 min_vruntime; -#ifndef CONFIG_64BIT - u64 min_vruntime_copy; -#endif - - struct rb_root tasks_timeline; - struct rb_node *rb_leftmost; - - /* - * 'curr' points to currently running entity on this cfs_rq. - * It is set to NULL otherwise (i.e when none are currently running). - */ - struct sched_entity *curr, *next, *last, *skip; - -#ifdef CONFIG_SCHED_DEBUG - unsigned int nr_spread_over; -#endif - -#ifdef CONFIG_SMP - /* - * CFS load tracking - */ - struct sched_avg avg; - u64 runnable_load_sum; - unsigned long runnable_load_avg; -#ifdef CONFIG_FAIR_GROUP_SCHED - unsigned long tg_load_avg_contrib; -#endif - atomic_long_t removed_load_avg, removed_util_avg; -#ifndef CONFIG_64BIT - u64 load_last_update_time_copy; -#endif - -#ifdef CONFIG_FAIR_GROUP_SCHED - /* - * h_load = weight * f(tg) - * - * Where f(tg) is the recursive weight fraction assigned to - * this group. - */ - unsigned long h_load; - u64 last_h_load_update; - struct sched_entity *h_load_next; -#endif /* CONFIG_FAIR_GROUP_SCHED */ -#endif /* CONFIG_SMP */ - -#ifdef CONFIG_FAIR_GROUP_SCHED - struct rq *rq; /* cpu runqueue to which this cfs_rq is attached */ - - /* - * leaf cfs_rqs are those that hold tasks (lowest schedulable entity in - * a hierarchy). Non-leaf lrqs hold other higher schedulable entities - * (like users, containers etc.) - * - * leaf_cfs_rq_list ties together list of leaf cfs_rq's in a cpu. This - * list is used during load balance. - */ - int on_list; - struct list_head leaf_cfs_rq_list; - struct task_group *tg; /* group that "owns" this runqueue */ - -#ifdef CONFIG_CFS_BANDWIDTH - int runtime_enabled; - u64 runtime_expires; - s64 runtime_remaining; - - u64 throttled_clock, throttled_clock_task; - u64 throttled_clock_task_time; - int throttled, throttle_count; - struct list_head throttled_list; -#endif /* CONFIG_CFS_BANDWIDTH */ -#endif /* CONFIG_FAIR_GROUP_SCHED */ -}; - -static inline int rt_bandwidth_enabled(void) -{ - return sysctl_sched_rt_runtime >= 0; -} - -/* RT IPI pull logic requires IRQ_WORK */ -#ifdef CONFIG_IRQ_WORK -# define HAVE_RT_PUSH_IPI -#endif - -/* Real-Time classes' related field in a runqueue: */ -struct rt_rq { - struct rt_prio_array active; - unsigned int rt_nr_running; - unsigned int rr_nr_running; -#if defined CONFIG_SMP || defined CONFIG_RT_GROUP_SCHED - struct { - int curr; /* highest queued rt task prio */ -#ifdef CONFIG_SMP - int next; /* next highest */ -#endif - } highest_prio; -#endif -#ifdef CONFIG_SMP - unsigned long rt_nr_migratory; - unsigned long rt_nr_total; - int overloaded; - struct plist_head pushable_tasks; -#ifdef HAVE_RT_PUSH_IPI - int push_flags; - int push_cpu; - struct irq_work push_work; - raw_spinlock_t push_lock; -#endif -#endif /* CONFIG_SMP */ - int rt_queued; - - int rt_throttled; - u64 rt_time; - u64 rt_runtime; - /* Nests inside the rq lock: */ - raw_spinlock_t rt_runtime_lock; - -#ifdef CONFIG_RT_GROUP_SCHED - unsigned long rt_nr_boosted; - - struct rq *rq; - struct task_group *tg; -#endif -}; - -/* Deadline class' related fields in a runqueue */ -struct dl_rq { - /* runqueue is an rbtree, ordered by deadline */ - struct rb_root rb_root; - struct rb_node *rb_leftmost; - - unsigned long dl_nr_running; - -#ifdef CONFIG_SMP - /* - * Deadline values of the currently executing and the - * earliest ready task on this rq. Caching these facilitates - * the decision wether or not a ready but not running task - * should migrate somewhere else. - */ - struct { - u64 curr; - u64 next; - } earliest_dl; - - unsigned long dl_nr_migratory; - int overloaded; - - /* - * Tasks on this rq that can be pushed away. They are kept in - * an rb-tree, ordered by tasks' deadlines, with caching - * of the leftmost (earliest deadline) element. - */ - struct rb_root pushable_dl_tasks_root; - struct rb_node *pushable_dl_tasks_leftmost; -#else - struct dl_bw dl_bw; -#endif -}; - -#ifdef CONFIG_SMP - -/* - * We add the notion of a root-domain which will be used to define per-domain - * variables. Each exclusive cpuset essentially defines an island domain by - * fully partitioning the member cpus from any other cpuset. Whenever a new - * exclusive cpuset is created, we also create and attach a new root-domain - * object. - * - */ -struct root_domain { - atomic_t refcount; - atomic_t rto_count; - struct rcu_head rcu; - cpumask_var_t span; - cpumask_var_t online; - - /* Indicate more than one runnable task for any CPU */ - bool overload; - - /* - * The bit corresponding to a CPU gets set here if such CPU has more - * than one runnable -deadline task (as it is below for RT tasks). - */ - cpumask_var_t dlo_mask; - atomic_t dlo_count; - struct dl_bw dl_bw; - struct cpudl cpudl; - - /* - * The "RT overload" flag: it gets set if a CPU has more than - * one runnable RT task. - */ - cpumask_var_t rto_mask; - struct cpupri cpupri; - - unsigned long max_cpu_capacity; -}; - -extern struct root_domain def_root_domain; - -#endif /* CONFIG_SMP */ - -/* - * This is the main, per-CPU runqueue data structure. - * - * Locking rule: those places that want to lock multiple runqueues - * (such as the load balancing or the thread migration code), lock - * acquire operations must be ordered by ascending &runqueue. - */ -struct rq { - /* runqueue lock: */ - raw_spinlock_t lock; - - /* - * nr_running and cpu_load should be in the same cacheline because - * remote CPUs use both these fields when doing load calculation. - */ - unsigned int nr_running; -#ifdef CONFIG_NUMA_BALANCING - unsigned int nr_numa_running; - unsigned int nr_preferred_running; -#endif - #define CPU_LOAD_IDX_MAX 5 - unsigned long cpu_load[CPU_LOAD_IDX_MAX]; -#ifdef CONFIG_NO_HZ_COMMON -#ifdef CONFIG_SMP - unsigned long last_load_update_tick; -#endif /* CONFIG_SMP */ - unsigned long nohz_flags; -#endif /* CONFIG_NO_HZ_COMMON */ -#ifdef CONFIG_NO_HZ_FULL - unsigned long last_sched_tick; -#endif - /* capture load from *all* tasks on this cpu: */ - struct load_weight load; - unsigned long nr_load_updates; - u64 nr_switches; - - struct cfs_rq cfs; - struct rt_rq rt; - struct dl_rq dl; - -#ifdef CONFIG_FAIR_GROUP_SCHED - /* list of leaf cfs_rq on this cpu: */ - struct list_head leaf_cfs_rq_list; -#endif /* CONFIG_FAIR_GROUP_SCHED */ - - /* - * This is part of a global counter where only the total sum - * over all CPUs matters. A task can increase this counter on - * one CPU and if it got migrated afterwards it may decrease - * it on another CPU. Always updated under the runqueue lock: - */ - unsigned long nr_uninterruptible; - - struct task_struct *curr, *idle, *stop; - unsigned long next_balance; - struct mm_struct *prev_mm; - - unsigned int clock_skip_update; - u64 clock; - u64 clock_task; - - atomic_t nr_iowait; - -#ifdef CONFIG_SMP - struct root_domain *rd; - struct sched_domain *sd; - - unsigned long cpu_capacity; - unsigned long cpu_capacity_orig; - - struct callback_head *balance_callback; - - unsigned char idle_balance; - /* For active balancing */ - int active_balance; - int push_cpu; - struct cpu_stop_work active_balance_work; - /* cpu of this runqueue: */ - int cpu; - int online; - - struct list_head cfs_tasks; - - u64 rt_avg; - u64 age_stamp; - u64 idle_stamp; - u64 avg_idle; - - /* This is used to determine avg_idle's max value */ - u64 max_idle_balance_cost; -#endif - -#ifdef CONFIG_IRQ_TIME_ACCOUNTING - u64 prev_irq_time; -#endif -#ifdef CONFIG_PARAVIRT - u64 prev_steal_time; -#endif -#ifdef CONFIG_PARAVIRT_TIME_ACCOUNTING - u64 prev_steal_time_rq; -#endif - - /* calc_load related fields */ - unsigned long calc_load_update; - long calc_load_active; - -#ifdef CONFIG_SCHED_HRTICK -#ifdef CONFIG_SMP - int hrtick_csd_pending; - struct call_single_data hrtick_csd; -#endif - struct hrtimer hrtick_timer; -#endif - -#ifdef CONFIG_SCHEDSTATS - /* latency stats */ - struct sched_info rq_sched_info; - unsigned long long rq_cpu_time; - /* could above be rq->cfs_rq.exec_clock + rq->rt_rq.rt_runtime ? */ - - /* sys_sched_yield() stats */ - unsigned int yld_count; - - /* schedule() stats */ - unsigned int sched_count; - unsigned int sched_goidle; - - /* try_to_wake_up() stats */ - unsigned int ttwu_count; - unsigned int ttwu_local; -#endif - -#ifdef CONFIG_SMP - struct llist_head wake_list; -#endif - -#ifdef CONFIG_CPU_IDLE - /* Must be inspected within a rcu lock section */ - struct cpuidle_state *idle_state; -#endif -}; - -static inline int cpu_of(struct rq *rq) -{ -#ifdef CONFIG_SMP - return rq->cpu; -#else - return 0; -#endif -} - - -#ifdef CONFIG_SCHED_SMT - -extern struct static_key_false sched_smt_present; - -extern void __update_idle_core(struct rq *rq); - -static inline void update_idle_core(struct rq *rq) -{ - if (static_branch_unlikely(&sched_smt_present)) - __update_idle_core(rq); -} - -#else -static inline void update_idle_core(struct rq *rq) { } -#endif - -DECLARE_PER_CPU_SHARED_ALIGNED(struct rq, runqueues); - -#define cpu_rq(cpu) (&per_cpu(runqueues, (cpu))) -#define this_rq() this_cpu_ptr(&runqueues) -#define task_rq(p) cpu_rq(task_cpu(p)) -#define cpu_curr(cpu) (cpu_rq(cpu)->curr) -#define raw_rq() raw_cpu_ptr(&runqueues) - -static inline u64 __rq_clock_broken(struct rq *rq) -{ - return READ_ONCE(rq->clock); -} - -static inline u64 rq_clock(struct rq *rq) -{ - lockdep_assert_held(&rq->lock); - return rq->clock; -} - -static inline u64 rq_clock_task(struct rq *rq) -{ - lockdep_assert_held(&rq->lock); - return rq->clock_task; -} - -#define RQCF_REQ_SKIP 0x01 -#define RQCF_ACT_SKIP 0x02 - -static inline void rq_clock_skip_update(struct rq *rq, bool skip) -{ - lockdep_assert_held(&rq->lock); - if (skip) - rq->clock_skip_update |= RQCF_REQ_SKIP; - else - rq->clock_skip_update &= ~RQCF_REQ_SKIP; -} - -#ifdef CONFIG_NUMA -enum numa_topology_type { - NUMA_DIRECT, - NUMA_GLUELESS_MESH, - NUMA_BACKPLANE, -}; -extern enum numa_topology_type sched_numa_topology_type; -extern int sched_max_numa_distance; -extern bool find_numa_distance(int distance); -#endif - -#ifdef CONFIG_NUMA_BALANCING -/* The regions in numa_faults array from task_struct */ -enum numa_faults_stats { - NUMA_MEM = 0, - NUMA_CPU, - NUMA_MEMBUF, - NUMA_CPUBUF -}; -extern void sched_setnuma(struct task_struct *p, int node); -extern int migrate_task_to(struct task_struct *p, int cpu); -extern int migrate_swap(struct task_struct *, struct task_struct *); -#endif /* CONFIG_NUMA_BALANCING */ - -#ifdef CONFIG_SMP - -static inline void -queue_balance_callback(struct rq *rq, - struct callback_head *head, - void (*func)(struct rq *rq)) -{ - lockdep_assert_held(&rq->lock); - - if (unlikely(head->next)) - return; - - head->func = (void (*)(struct callback_head *))func; - head->next = rq->balance_callback; - rq->balance_callback = head; -} - -extern void sched_ttwu_pending(void); - -#define rcu_dereference_check_sched_domain(p) \ - rcu_dereference_check((p), \ - lockdep_is_held(&sched_domains_mutex)) - -/* - * The domain tree (rq->sd) is protected by RCU's quiescent state transition. - * See detach_destroy_domains: synchronize_sched for details. - * - * The domain tree of any CPU may only be accessed from within - * preempt-disabled sections. - */ -#define for_each_domain(cpu, __sd) \ - for (__sd = rcu_dereference_check_sched_domain(cpu_rq(cpu)->sd); \ - __sd; __sd = __sd->parent) - -#define for_each_lower_domain(sd) for (; sd; sd = sd->child) - -/** - * highest_flag_domain - Return highest sched_domain containing flag. - * @cpu: The cpu whose highest level of sched domain is to - * be returned. - * @flag: The flag to check for the highest sched_domain - * for the given cpu. - * - * Returns the highest sched_domain of a cpu which contains the given flag. - */ -static inline struct sched_domain *highest_flag_domain(int cpu, int flag) -{ - struct sched_domain *sd, *hsd = NULL; - - for_each_domain(cpu, sd) { - if (!(sd->flags & flag)) - break; - hsd = sd; - } - - return hsd; -} - -static inline struct sched_domain *lowest_flag_domain(int cpu, int flag) -{ - struct sched_domain *sd; - - for_each_domain(cpu, sd) { - if (sd->flags & flag) - break; - } - - return sd; -} - -DECLARE_PER_CPU(struct sched_domain *, sd_llc); -DECLARE_PER_CPU(int, sd_llc_size); -DECLARE_PER_CPU(int, sd_llc_id); -DECLARE_PER_CPU(struct sched_domain_shared *, sd_llc_shared); -DECLARE_PER_CPU(struct sched_domain *, sd_numa); -DECLARE_PER_CPU(struct sched_domain *, sd_asym); - -struct sched_group_capacity { - atomic_t ref; - /* - * CPU capacity of this group, SCHED_CAPACITY_SCALE being max capacity - * for a single CPU. - */ - unsigned int capacity; - unsigned long next_update; - int imbalance; /* XXX unrelated to capacity but shared group state */ - - unsigned long cpumask[0]; /* iteration mask */ -}; - -struct sched_group { - struct sched_group *next; /* Must be a circular list */ - atomic_t ref; - - unsigned int group_weight; - struct sched_group_capacity *sgc; - - /* - * The CPUs this group covers. - * - * NOTE: this field is variable length. (Allocated dynamically - * by attaching extra space to the end of the structure, - * depending on how many CPUs the kernel has booted up with) - */ - unsigned long cpumask[0]; -}; - -static inline struct cpumask *sched_group_cpus(struct sched_group *sg) -{ - return to_cpumask(sg->cpumask); -} - -/* - * cpumask masking which cpus in the group are allowed to iterate up the domain - * tree. - */ -static inline struct cpumask *sched_group_mask(struct sched_group *sg) -{ - return to_cpumask(sg->sgc->cpumask); -} - -/** - * group_first_cpu - Returns the first cpu in the cpumask of a sched_group. - * @group: The group whose first cpu is to be returned. - */ -static inline unsigned int group_first_cpu(struct sched_group *group) -{ - return cpumask_first(sched_group_cpus(group)); -} - -extern int group_balance_cpu(struct sched_group *sg); - -#if defined(CONFIG_SCHED_DEBUG) && defined(CONFIG_SYSCTL) -void register_sched_domain_sysctl(void); -void unregister_sched_domain_sysctl(void); -#else -static inline void register_sched_domain_sysctl(void) -{ -} -static inline void unregister_sched_domain_sysctl(void) -{ -} -#endif - -#else - -static inline void sched_ttwu_pending(void) { } - -#endif /* CONFIG_SMP */ - -#include "stats.h" -#include "auto_group.h" - -#ifdef CONFIG_CGROUP_SCHED - -/* - * Return the group to which this tasks belongs. - * - * We cannot use task_css() and friends because the cgroup subsystem - * changes that value before the cgroup_subsys::attach() method is called, - * therefore we cannot pin it and might observe the wrong value. - * - * The same is true for autogroup's p->signal->autogroup->tg, the autogroup - * core changes this before calling sched_move_task(). - * - * Instead we use a 'copy' which is updated from sched_move_task() while - * holding both task_struct::pi_lock and rq::lock. - */ -static inline struct task_group *task_group(struct task_struct *p) -{ - return p->sched_task_group; -} - -/* Change a task's cfs_rq and parent entity if it moves across CPUs/groups */ -static inline void set_task_rq(struct task_struct *p, unsigned int cpu) -{ -#if defined(CONFIG_FAIR_GROUP_SCHED) || defined(CONFIG_RT_GROUP_SCHED) - struct task_group *tg = task_group(p); -#endif - -#ifdef CONFIG_FAIR_GROUP_SCHED - set_task_rq_fair(&p->se, p->se.cfs_rq, tg->cfs_rq[cpu]); - p->se.cfs_rq = tg->cfs_rq[cpu]; - p->se.parent = tg->se[cpu]; -#endif - -#ifdef CONFIG_RT_GROUP_SCHED - p->rt.rt_rq = tg->rt_rq[cpu]; - p->rt.parent = tg->rt_se[cpu]; -#endif -} - -#else /* CONFIG_CGROUP_SCHED */ - -static inline void set_task_rq(struct task_struct *p, unsigned int cpu) { } -static inline struct task_group *task_group(struct task_struct *p) -{ - return NULL; -} - -#endif /* CONFIG_CGROUP_SCHED */ - -static inline void __set_task_cpu(struct task_struct *p, unsigned int cpu) -{ - set_task_rq(p, cpu); -#ifdef CONFIG_SMP - /* - * After ->cpu is set up to a new value, task_rq_lock(p, ...) can be - * successfuly executed on another CPU. We must ensure that updates of - * per-task data have been completed by this moment. - */ - smp_wmb(); -#ifdef CONFIG_THREAD_INFO_IN_TASK - p->cpu = cpu; -#else - task_thread_info(p)->cpu = cpu; -#endif - p->wake_cpu = cpu; -#endif -} - -/* - * Tunables that become constants when CONFIG_SCHED_DEBUG is off: - */ -#ifdef CONFIG_SCHED_DEBUG -# include -# define const_debug __read_mostly -#else -# define const_debug const -#endif - -extern const_debug unsigned int sysctl_sched_features; - -#define SCHED_FEAT(name, enabled) \ - __SCHED_FEAT_##name , - -enum { -#include "features.h" - __SCHED_FEAT_NR, -}; - -#undef SCHED_FEAT - -#if defined(CONFIG_SCHED_DEBUG) && defined(HAVE_JUMP_LABEL) -#define SCHED_FEAT(name, enabled) \ -static __always_inline bool static_branch_##name(struct static_key *key) \ -{ \ - return static_key_##enabled(key); \ -} - -#include "features.h" - -#undef SCHED_FEAT - -extern struct static_key sched_feat_keys[__SCHED_FEAT_NR]; -#define sched_feat(x) (static_branch_##x(&sched_feat_keys[__SCHED_FEAT_##x])) -#else /* !(SCHED_DEBUG && HAVE_JUMP_LABEL) */ -#define sched_feat(x) (sysctl_sched_features & (1UL << __SCHED_FEAT_##x)) -#endif /* SCHED_DEBUG && HAVE_JUMP_LABEL */ - -extern struct static_key_false sched_numa_balancing; -extern struct static_key_false sched_schedstats; - -static inline u64 global_rt_period(void) -{ - return (u64)sysctl_sched_rt_period * NSEC_PER_USEC; -} - -static inline u64 global_rt_runtime(void) -{ - if (sysctl_sched_rt_runtime < 0) - return RUNTIME_INF; - - return (u64)sysctl_sched_rt_runtime * NSEC_PER_USEC; -} - -static inline int task_current(struct rq *rq, struct task_struct *p) -{ - return rq->curr == p; -} - -static inline int task_running(struct rq *rq, struct task_struct *p) -{ -#ifdef CONFIG_SMP - return p->on_cpu; -#else - return task_current(rq, p); -#endif -} - -static inline int task_on_rq_queued(struct task_struct *p) -{ - return p->on_rq == TASK_ON_RQ_QUEUED; -} - -static inline int task_on_rq_migrating(struct task_struct *p) -{ - return p->on_rq == TASK_ON_RQ_MIGRATING; -} - -#ifndef prepare_arch_switch -# define prepare_arch_switch(next) do { } while (0) -#endif -#ifndef finish_arch_post_lock_switch -# define finish_arch_post_lock_switch() do { } while (0) -#endif - -static inline void prepare_lock_switch(struct rq *rq, struct task_struct *next) -{ -#ifdef CONFIG_SMP - /* - * We can optimise this out completely for !SMP, because the - * SMP rebalancing from interrupt is the only thing that cares - * here. - */ - next->on_cpu = 1; -#endif -} - -static inline void finish_lock_switch(struct rq *rq, struct task_struct *prev) -{ -#ifdef CONFIG_SMP - /* - * After ->on_cpu is cleared, the task can be moved to a different CPU. - * We must ensure this doesn't happen until the switch is completely - * finished. - * - * In particular, the load of prev->state in finish_task_switch() must - * happen before this. - * - * Pairs with the smp_cond_load_acquire() in try_to_wake_up(). - */ - smp_store_release(&prev->on_cpu, 0); -#endif -#ifdef CONFIG_DEBUG_SPINLOCK - /* this is a valid case when another task releases the spinlock */ - rq->lock.owner = current; -#endif - /* - * If we are tracking spinlock dependencies then we have to - * fix up the runqueue lock - which gets 'carried over' from - * prev into current: - */ - spin_acquire(&rq->lock.dep_map, 0, 0, _THIS_IP_); - - raw_spin_unlock_irq(&rq->lock); -} - -/* - * wake flags - */ -#define WF_SYNC 0x01 /* waker goes to sleep after wakeup */ -#define WF_FORK 0x02 /* child wakeup after fork */ -#define WF_MIGRATED 0x4 /* internal use, task got migrated */ - -/* - * To aid in avoiding the subversion of "niceness" due to uneven distribution - * of tasks with abnormal "nice" values across CPUs the contribution that - * each task makes to its run queue's load is weighted according to its - * scheduling class and "nice" value. For SCHED_NORMAL tasks this is just a - * scaled version of the new time slice allocation that they receive on time - * slice expiry etc. - */ - -#define WEIGHT_IDLEPRIO 3 -#define WMULT_IDLEPRIO 1431655765 - -extern const int sched_prio_to_weight[40]; -extern const u32 sched_prio_to_wmult[40]; - -/* - * {de,en}queue flags: - * - * DEQUEUE_SLEEP - task is no longer runnable - * ENQUEUE_WAKEUP - task just became runnable - * - * SAVE/RESTORE - an otherwise spurious dequeue/enqueue, done to ensure tasks - * are in a known state which allows modification. Such pairs - * should preserve as much state as possible. - * - * MOVE - paired with SAVE/RESTORE, explicitly does not preserve the location - * in the runqueue. - * - * ENQUEUE_HEAD - place at front of runqueue (tail if not specified) - * ENQUEUE_REPLENISH - CBS (replenish runtime and postpone deadline) - * ENQUEUE_MIGRATED - the task was migrated during wakeup - * - */ - -#define DEQUEUE_SLEEP 0x01 -#define DEQUEUE_SAVE 0x02 /* matches ENQUEUE_RESTORE */ -#define DEQUEUE_MOVE 0x04 /* matches ENQUEUE_MOVE */ - -#define ENQUEUE_WAKEUP 0x01 -#define ENQUEUE_RESTORE 0x02 -#define ENQUEUE_MOVE 0x04 - -#define ENQUEUE_HEAD 0x08 -#define ENQUEUE_REPLENISH 0x10 -#ifdef CONFIG_SMP -#define ENQUEUE_MIGRATED 0x20 -#else -#define ENQUEUE_MIGRATED 0x00 -#endif - -#define RETRY_TASK ((void *)-1UL) - -struct sched_class { - const struct sched_class *next; - - void (*enqueue_task) (struct rq *rq, struct task_struct *p, int flags); - void (*dequeue_task) (struct rq *rq, struct task_struct *p, int flags); - void (*yield_task) (struct rq *rq); - bool (*yield_to_task) (struct rq *rq, struct task_struct *p, bool preempt); - - void (*check_preempt_curr) (struct rq *rq, struct task_struct *p, int flags); - - /* - * It is the responsibility of the pick_next_task() method that will - * return the next task to call put_prev_task() on the @prev task or - * something equivalent. - * - * May return RETRY_TASK when it finds a higher prio class has runnable - * tasks. - */ - struct task_struct * (*pick_next_task) (struct rq *rq, - struct task_struct *prev, - struct pin_cookie cookie); - void (*put_prev_task) (struct rq *rq, struct task_struct *p); - -#ifdef CONFIG_SMP - int (*select_task_rq)(struct task_struct *p, int task_cpu, int sd_flag, int flags); - void (*migrate_task_rq)(struct task_struct *p); - - void (*task_woken) (struct rq *this_rq, struct task_struct *task); - - void (*set_cpus_allowed)(struct task_struct *p, - const struct cpumask *newmask); - - void (*rq_online)(struct rq *rq); - void (*rq_offline)(struct rq *rq); -#endif - - void (*set_curr_task) (struct rq *rq); - void (*task_tick) (struct rq *rq, struct task_struct *p, int queued); - void (*task_fork) (struct task_struct *p); - void (*task_dead) (struct task_struct *p); - - /* - * The switched_from() call is allowed to drop rq->lock, therefore we - * cannot assume the switched_from/switched_to pair is serliazed by - * rq->lock. They are however serialized by p->pi_lock. - */ - void (*switched_from) (struct rq *this_rq, struct task_struct *task); - void (*switched_to) (struct rq *this_rq, struct task_struct *task); - void (*prio_changed) (struct rq *this_rq, struct task_struct *task, - int oldprio); - - unsigned int (*get_rr_interval) (struct rq *rq, - struct task_struct *task); - - void (*update_curr) (struct rq *rq); - -#define TASK_SET_GROUP 0 -#define TASK_MOVE_GROUP 1 - -#ifdef CONFIG_FAIR_GROUP_SCHED - void (*task_change_group) (struct task_struct *p, int type); -#endif -}; - -static inline void put_prev_task(struct rq *rq, struct task_struct *prev) -{ - prev->sched_class->put_prev_task(rq, prev); -} - -static inline void set_curr_task(struct rq *rq, struct task_struct *curr) -{ - curr->sched_class->set_curr_task(rq); -} - -#define sched_class_highest (&stop_sched_class) -#define for_each_class(class) \ - for (class = sched_class_highest; class; class = class->next) - -extern const struct sched_class stop_sched_class; -extern const struct sched_class dl_sched_class; -extern const struct sched_class rt_sched_class; -extern const struct sched_class fair_sched_class; -extern const struct sched_class idle_sched_class; - - -#ifdef CONFIG_SMP - -extern void update_group_capacity(struct sched_domain *sd, int cpu); - -extern void trigger_load_balance(struct rq *rq); - -extern void set_cpus_allowed_common(struct task_struct *p, const struct cpumask *new_mask); - -#endif - -#ifdef CONFIG_CPU_IDLE -static inline void idle_set_state(struct rq *rq, - struct cpuidle_state *idle_state) -{ - rq->idle_state = idle_state; -} - -static inline struct cpuidle_state *idle_get_state(struct rq *rq) -{ - SCHED_WARN_ON(!rcu_read_lock_held()); - return rq->idle_state; -} -#else -static inline void idle_set_state(struct rq *rq, - struct cpuidle_state *idle_state) -{ -} - -static inline struct cpuidle_state *idle_get_state(struct rq *rq) -{ - return NULL; -} -#endif - -extern void sysrq_sched_debug_show(void); -extern void sched_init_granularity(void); -extern void update_max_interval(void); - -extern void init_sched_dl_class(void); -extern void init_sched_rt_class(void); -extern void init_sched_fair_class(void); - -extern void resched_curr(struct rq *rq); -extern void resched_cpu(int cpu); - -extern struct rt_bandwidth def_rt_bandwidth; -extern void init_rt_bandwidth(struct rt_bandwidth *rt_b, u64 period, u64 runtime); - -extern struct dl_bandwidth def_dl_bandwidth; -extern void init_dl_bandwidth(struct dl_bandwidth *dl_b, u64 period, u64 runtime); -extern void init_dl_task_timer(struct sched_dl_entity *dl_se); - -unsigned long to_ratio(u64 period, u64 runtime); - -extern void init_entity_runnable_average(struct sched_entity *se); -extern void post_init_entity_util_avg(struct sched_entity *se); - -#ifdef CONFIG_NO_HZ_FULL -extern bool sched_can_stop_tick(struct rq *rq); - -/* - * Tick may be needed by tasks in the runqueue depending on their policy and - * requirements. If tick is needed, lets send the target an IPI to kick it out of - * nohz mode if necessary. - */ -static inline void sched_update_tick_dependency(struct rq *rq) -{ - int cpu; - - if (!tick_nohz_full_enabled()) - return; - - cpu = cpu_of(rq); - - if (!tick_nohz_full_cpu(cpu)) - return; - - if (sched_can_stop_tick(rq)) - tick_nohz_dep_clear_cpu(cpu, TICK_DEP_BIT_SCHED); - else - tick_nohz_dep_set_cpu(cpu, TICK_DEP_BIT_SCHED); -} -#else -static inline void sched_update_tick_dependency(struct rq *rq) { } -#endif - -static inline void add_nr_running(struct rq *rq, unsigned count) -{ - unsigned prev_nr = rq->nr_running; - - rq->nr_running = prev_nr + count; - - if (prev_nr < 2 && rq->nr_running >= 2) { -#ifdef CONFIG_SMP - if (!rq->rd->overload) - rq->rd->overload = true; -#endif - } - - sched_update_tick_dependency(rq); -} - -static inline void sub_nr_running(struct rq *rq, unsigned count) -{ - rq->nr_running -= count; - /* Check if we still need preemption */ - sched_update_tick_dependency(rq); -} - -static inline void rq_last_tick_reset(struct rq *rq) -{ -#ifdef CONFIG_NO_HZ_FULL - rq->last_sched_tick = jiffies; -#endif -} - -extern void update_rq_clock(struct rq *rq); - -extern void activate_task(struct rq *rq, struct task_struct *p, int flags); -extern void deactivate_task(struct rq *rq, struct task_struct *p, int flags); - -extern void check_preempt_curr(struct rq *rq, struct task_struct *p, int flags); - -extern const_debug unsigned int sysctl_sched_time_avg; -extern const_debug unsigned int sysctl_sched_nr_migrate; -extern const_debug unsigned int sysctl_sched_migration_cost; - -static inline u64 sched_avg_period(void) -{ - return (u64)sysctl_sched_time_avg * NSEC_PER_MSEC / 2; -} - -#ifdef CONFIG_SCHED_HRTICK - -/* - * Use hrtick when: - * - enabled by features - * - hrtimer is actually high res - */ -static inline int hrtick_enabled(struct rq *rq) -{ - if (!sched_feat(HRTICK)) - return 0; - if (!cpu_active(cpu_of(rq))) - return 0; - return hrtimer_is_hres_active(&rq->hrtick_timer); -} - -void hrtick_start(struct rq *rq, u64 delay); - -#else - -static inline int hrtick_enabled(struct rq *rq) -{ - return 0; -} - -#endif /* CONFIG_SCHED_HRTICK */ - -#ifdef CONFIG_SMP -extern void sched_avg_update(struct rq *rq); - -#ifndef arch_scale_freq_capacity -static __always_inline -unsigned long arch_scale_freq_capacity(struct sched_domain *sd, int cpu) -{ - return SCHED_CAPACITY_SCALE; -} -#endif - -#ifndef arch_scale_cpu_capacity -static __always_inline -unsigned long arch_scale_cpu_capacity(struct sched_domain *sd, int cpu) -{ - if (sd && (sd->flags & SD_SHARE_CPUCAPACITY) && (sd->span_weight > 1)) - return sd->smt_gain / sd->span_weight; - - return SCHED_CAPACITY_SCALE; -} -#endif - -static inline void sched_rt_avg_update(struct rq *rq, u64 rt_delta) -{ - rq->rt_avg += rt_delta * arch_scale_freq_capacity(NULL, cpu_of(rq)); - sched_avg_update(rq); -} -#else -static inline void sched_rt_avg_update(struct rq *rq, u64 rt_delta) { } -static inline void sched_avg_update(struct rq *rq) { } -#endif - -struct rq_flags { - unsigned long flags; - struct pin_cookie cookie; -}; - -struct rq *__task_rq_lock(struct task_struct *p, struct rq_flags *rf) - __acquires(rq->lock); -struct rq *task_rq_lock(struct task_struct *p, struct rq_flags *rf) - __acquires(p->pi_lock) - __acquires(rq->lock); - -static inline void __task_rq_unlock(struct rq *rq, struct rq_flags *rf) - __releases(rq->lock) -{ - lockdep_unpin_lock(&rq->lock, rf->cookie); - raw_spin_unlock(&rq->lock); -} - -static inline void -task_rq_unlock(struct rq *rq, struct task_struct *p, struct rq_flags *rf) - __releases(rq->lock) - __releases(p->pi_lock) -{ - lockdep_unpin_lock(&rq->lock, rf->cookie); - raw_spin_unlock(&rq->lock); - raw_spin_unlock_irqrestore(&p->pi_lock, rf->flags); -} - -#ifdef CONFIG_SMP -#ifdef CONFIG_PREEMPT - -static inline void double_rq_lock(struct rq *rq1, struct rq *rq2); - -/* - * fair double_lock_balance: Safely acquires both rq->locks in a fair - * way at the expense of forcing extra atomic operations in all - * invocations. This assures that the double_lock is acquired using the - * same underlying policy as the spinlock_t on this architecture, which - * reduces latency compared to the unfair variant below. However, it - * also adds more overhead and therefore may reduce throughput. - */ -static inline int _double_lock_balance(struct rq *this_rq, struct rq *busiest) - __releases(this_rq->lock) - __acquires(busiest->lock) - __acquires(this_rq->lock) -{ - raw_spin_unlock(&this_rq->lock); - double_rq_lock(this_rq, busiest); - - return 1; -} - -#else -/* - * Unfair double_lock_balance: Optimizes throughput at the expense of - * latency by eliminating extra atomic operations when the locks are - * already in proper order on entry. This favors lower cpu-ids and will - * grant the double lock to lower cpus over higher ids under contention, - * regardless of entry order into the function. - */ -static inline int _double_lock_balance(struct rq *this_rq, struct rq *busiest) - __releases(this_rq->lock) - __acquires(busiest->lock) - __acquires(this_rq->lock) -{ - int ret = 0; - - if (unlikely(!raw_spin_trylock(&busiest->lock))) { - if (busiest < this_rq) { - raw_spin_unlock(&this_rq->lock); - raw_spin_lock(&busiest->lock); - raw_spin_lock_nested(&this_rq->lock, - SINGLE_DEPTH_NESTING); - ret = 1; - } else - raw_spin_lock_nested(&busiest->lock, - SINGLE_DEPTH_NESTING); - } - return ret; -} - -#endif /* CONFIG_PREEMPT */ - -/* - * double_lock_balance - lock the busiest runqueue, this_rq is locked already. - */ -static inline int double_lock_balance(struct rq *this_rq, struct rq *busiest) -{ - if (unlikely(!irqs_disabled())) { - /* printk() doesn't work good under rq->lock */ - raw_spin_unlock(&this_rq->lock); - BUG_ON(1); - } - - return _double_lock_balance(this_rq, busiest); -} - -static inline void double_unlock_balance(struct rq *this_rq, struct rq *busiest) - __releases(busiest->lock) -{ - raw_spin_unlock(&busiest->lock); - lock_set_subclass(&this_rq->lock.dep_map, 0, _RET_IP_); -} - -static inline void double_lock(spinlock_t *l1, spinlock_t *l2) -{ - if (l1 > l2) - swap(l1, l2); - - spin_lock(l1); - spin_lock_nested(l2, SINGLE_DEPTH_NESTING); -} - -static inline void double_lock_irq(spinlock_t *l1, spinlock_t *l2) -{ - if (l1 > l2) - swap(l1, l2); - - spin_lock_irq(l1); - spin_lock_nested(l2, SINGLE_DEPTH_NESTING); -} - -static inline void double_raw_lock(raw_spinlock_t *l1, raw_spinlock_t *l2) -{ - if (l1 > l2) - swap(l1, l2); - - raw_spin_lock(l1); - raw_spin_lock_nested(l2, SINGLE_DEPTH_NESTING); -} - -/* - * double_rq_lock - safely lock two runqueues - * - * Note this does not disable interrupts like task_rq_lock, - * you need to do so manually before calling. - */ -static inline void double_rq_lock(struct rq *rq1, struct rq *rq2) - __acquires(rq1->lock) - __acquires(rq2->lock) -{ - BUG_ON(!irqs_disabled()); - if (rq1 == rq2) { - raw_spin_lock(&rq1->lock); - __acquire(rq2->lock); /* Fake it out ;) */ - } else { - if (rq1 < rq2) { - raw_spin_lock(&rq1->lock); - raw_spin_lock_nested(&rq2->lock, SINGLE_DEPTH_NESTING); - } else { - raw_spin_lock(&rq2->lock); - raw_spin_lock_nested(&rq1->lock, SINGLE_DEPTH_NESTING); - } - } -} - -/* - * double_rq_unlock - safely unlock two runqueues - * - * Note this does not restore interrupts like task_rq_unlock, - * you need to do so manually after calling. - */ -static inline void double_rq_unlock(struct rq *rq1, struct rq *rq2) - __releases(rq1->lock) - __releases(rq2->lock) -{ - raw_spin_unlock(&rq1->lock); - if (rq1 != rq2) - raw_spin_unlock(&rq2->lock); - else - __release(rq2->lock); -} - -#else /* CONFIG_SMP */ - -/* - * double_rq_lock - safely lock two runqueues - * - * Note this does not disable interrupts like task_rq_lock, - * you need to do so manually before calling. - */ -static inline void double_rq_lock(struct rq *rq1, struct rq *rq2) - __acquires(rq1->lock) - __acquires(rq2->lock) -{ - BUG_ON(!irqs_disabled()); - BUG_ON(rq1 != rq2); - raw_spin_lock(&rq1->lock); - __acquire(rq2->lock); /* Fake it out ;) */ -} - -/* - * double_rq_unlock - safely unlock two runqueues - * - * Note this does not restore interrupts like task_rq_unlock, - * you need to do so manually after calling. - */ -static inline void double_rq_unlock(struct rq *rq1, struct rq *rq2) - __releases(rq1->lock) - __releases(rq2->lock) -{ - BUG_ON(rq1 != rq2); - raw_spin_unlock(&rq1->lock); - __release(rq2->lock); -} - -#endif - -extern struct sched_entity *__pick_first_entity(struct cfs_rq *cfs_rq); -extern struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq); - -#ifdef CONFIG_SCHED_DEBUG -extern void print_cfs_stats(struct seq_file *m, int cpu); -extern void print_rt_stats(struct seq_file *m, int cpu); -extern void print_dl_stats(struct seq_file *m, int cpu); -extern void -print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq); - -#ifdef CONFIG_NUMA_BALANCING -extern void -show_numa_stats(struct task_struct *p, struct seq_file *m); -extern void -print_numa_stats(struct seq_file *m, int node, unsigned long tsf, - unsigned long tpf, unsigned long gsf, unsigned long gpf); -#endif /* CONFIG_NUMA_BALANCING */ -#endif /* CONFIG_SCHED_DEBUG */ - -extern void init_cfs_rq(struct cfs_rq *cfs_rq); -extern void init_rt_rq(struct rt_rq *rt_rq); -extern void init_dl_rq(struct dl_rq *dl_rq); - -extern void cfs_bandwidth_usage_inc(void); -extern void cfs_bandwidth_usage_dec(void); - -#ifdef CONFIG_NO_HZ_COMMON -enum rq_nohz_flag_bits { - NOHZ_TICK_STOPPED, - NOHZ_BALANCE_KICK, -}; - -#define nohz_flags(cpu) (&cpu_rq(cpu)->nohz_flags) - -extern void nohz_balance_exit_idle(unsigned int cpu); -#else -static inline void nohz_balance_exit_idle(unsigned int cpu) { } -#endif - -#ifdef CONFIG_IRQ_TIME_ACCOUNTING -struct irqtime { - u64 hardirq_time; - u64 softirq_time; - u64 irq_start_time; - struct u64_stats_sync sync; -}; - -DECLARE_PER_CPU(struct irqtime, cpu_irqtime); - -static inline u64 irq_time_read(int cpu) -{ - struct irqtime *irqtime = &per_cpu(cpu_irqtime, cpu); - unsigned int seq; - u64 total; - - do { - seq = __u64_stats_fetch_begin(&irqtime->sync); - total = irqtime->softirq_time + irqtime->hardirq_time; - } while (__u64_stats_fetch_retry(&irqtime->sync, seq)); - - return total; -} -#endif /* CONFIG_IRQ_TIME_ACCOUNTING */ - -#ifdef CONFIG_CPU_FREQ -DECLARE_PER_CPU(struct update_util_data *, cpufreq_update_util_data); - -/** - * cpufreq_update_util - Take a note about CPU utilization changes. - * @rq: Runqueue to carry out the update for. - * @flags: Update reason flags. - * - * This function is called by the scheduler on the CPU whose utilization is - * being updated. - * - * It can only be called from RCU-sched read-side critical sections. - * - * The way cpufreq is currently arranged requires it to evaluate the CPU - * performance state (frequency/voltage) on a regular basis to prevent it from - * being stuck in a completely inadequate performance level for too long. - * That is not guaranteed to happen if the updates are only triggered from CFS, - * though, because they may not be coming in if RT or deadline tasks are active - * all the time (or there are RT and DL tasks only). - * - * As a workaround for that issue, this function is called by the RT and DL - * sched classes to trigger extra cpufreq updates to prevent it from stalling, - * but that really is a band-aid. Going forward it should be replaced with - * solutions targeted more specifically at RT and DL tasks. - */ -static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) -{ - struct update_util_data *data; - - data = rcu_dereference_sched(*this_cpu_ptr(&cpufreq_update_util_data)); - if (data) - data->func(data, rq_clock(rq), flags); -} - -static inline void cpufreq_update_this_cpu(struct rq *rq, unsigned int flags) -{ - if (cpu_of(rq) == smp_processor_id()) - cpufreq_update_util(rq, flags); -} -#else -static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) {} -static inline void cpufreq_update_this_cpu(struct rq *rq, unsigned int flags) {} -#endif /* CONFIG_CPU_FREQ */ - -#ifdef arch_scale_freq_capacity -#ifndef arch_scale_freq_invariant -#define arch_scale_freq_invariant() (true) -#endif -#else /* arch_scale_freq_capacity */ -#define arch_scale_freq_invariant() (false) -#endif diff --git a/src/linux/kernel/sched/stats.h b/src/linux/kernel/sched/stats.h deleted file mode 100644 index 34659a8..0000000 --- a/src/linux/kernel/sched/stats.h +++ /dev/null @@ -1,269 +0,0 @@ - -#ifdef CONFIG_SCHEDSTATS - -/* - * Expects runqueue lock to be held for atomicity of update - */ -static inline void -rq_sched_info_arrive(struct rq *rq, unsigned long long delta) -{ - if (rq) { - rq->rq_sched_info.run_delay += delta; - rq->rq_sched_info.pcount++; - } -} - -/* - * Expects runqueue lock to be held for atomicity of update - */ -static inline void -rq_sched_info_depart(struct rq *rq, unsigned long long delta) -{ - if (rq) - rq->rq_cpu_time += delta; -} - -static inline void -rq_sched_info_dequeued(struct rq *rq, unsigned long long delta) -{ - if (rq) - rq->rq_sched_info.run_delay += delta; -} -#define schedstat_enabled() static_branch_unlikely(&sched_schedstats) -#define schedstat_inc(var) do { if (schedstat_enabled()) { var++; } } while (0) -#define schedstat_add(var, amt) do { if (schedstat_enabled()) { var += (amt); } } while (0) -#define schedstat_set(var, val) do { if (schedstat_enabled()) { var = (val); } } while (0) -#define schedstat_val(var) (var) -#define schedstat_val_or_zero(var) ((schedstat_enabled()) ? (var) : 0) - -#else /* !CONFIG_SCHEDSTATS */ -static inline void -rq_sched_info_arrive(struct rq *rq, unsigned long long delta) -{} -static inline void -rq_sched_info_dequeued(struct rq *rq, unsigned long long delta) -{} -static inline void -rq_sched_info_depart(struct rq *rq, unsigned long long delta) -{} -#define schedstat_enabled() 0 -#define schedstat_inc(var) do { } while (0) -#define schedstat_add(var, amt) do { } while (0) -#define schedstat_set(var, val) do { } while (0) -#define schedstat_val(var) 0 -#define schedstat_val_or_zero(var) 0 -#endif /* CONFIG_SCHEDSTATS */ - -#ifdef CONFIG_SCHED_INFO -static inline void sched_info_reset_dequeued(struct task_struct *t) -{ - t->sched_info.last_queued = 0; -} - -/* - * We are interested in knowing how long it was from the *first* time a - * task was queued to the time that it finally hit a cpu, we call this routine - * from dequeue_task() to account for possible rq->clock skew across cpus. The - * delta taken on each cpu would annul the skew. - */ -static inline void sched_info_dequeued(struct rq *rq, struct task_struct *t) -{ - unsigned long long now = rq_clock(rq), delta = 0; - - if (unlikely(sched_info_on())) - if (t->sched_info.last_queued) - delta = now - t->sched_info.last_queued; - sched_info_reset_dequeued(t); - t->sched_info.run_delay += delta; - - rq_sched_info_dequeued(rq, delta); -} - -/* - * Called when a task finally hits the cpu. We can now calculate how - * long it was waiting to run. We also note when it began so that we - * can keep stats on how long its timeslice is. - */ -static void sched_info_arrive(struct rq *rq, struct task_struct *t) -{ - unsigned long long now = rq_clock(rq), delta = 0; - - if (t->sched_info.last_queued) - delta = now - t->sched_info.last_queued; - sched_info_reset_dequeued(t); - t->sched_info.run_delay += delta; - t->sched_info.last_arrival = now; - t->sched_info.pcount++; - - rq_sched_info_arrive(rq, delta); -} - -/* - * This function is only called from enqueue_task(), but also only updates - * the timestamp if it is already not set. It's assumed that - * sched_info_dequeued() will clear that stamp when appropriate. - */ -static inline void sched_info_queued(struct rq *rq, struct task_struct *t) -{ - if (unlikely(sched_info_on())) - if (!t->sched_info.last_queued) - t->sched_info.last_queued = rq_clock(rq); -} - -/* - * Called when a process ceases being the active-running process involuntarily - * due, typically, to expiring its time slice (this may also be called when - * switching to the idle task). Now we can calculate how long we ran. - * Also, if the process is still in the TASK_RUNNING state, call - * sched_info_queued() to mark that it has now again started waiting on - * the runqueue. - */ -static inline void sched_info_depart(struct rq *rq, struct task_struct *t) -{ - unsigned long long delta = rq_clock(rq) - - t->sched_info.last_arrival; - - rq_sched_info_depart(rq, delta); - - if (t->state == TASK_RUNNING) - sched_info_queued(rq, t); -} - -/* - * Called when tasks are switched involuntarily due, typically, to expiring - * their time slice. (This may also be called when switching to or from - * the idle task.) We are only called when prev != next. - */ -static inline void -__sched_info_switch(struct rq *rq, - struct task_struct *prev, struct task_struct *next) -{ - /* - * prev now departs the cpu. It's not interesting to record - * stats about how efficient we were at scheduling the idle - * process, however. - */ - if (prev != rq->idle) - sched_info_depart(rq, prev); - - if (next != rq->idle) - sched_info_arrive(rq, next); -} -static inline void -sched_info_switch(struct rq *rq, - struct task_struct *prev, struct task_struct *next) -{ - if (unlikely(sched_info_on())) - __sched_info_switch(rq, prev, next); -} -#else -#define sched_info_queued(rq, t) do { } while (0) -#define sched_info_reset_dequeued(t) do { } while (0) -#define sched_info_dequeued(rq, t) do { } while (0) -#define sched_info_depart(rq, t) do { } while (0) -#define sched_info_arrive(rq, next) do { } while (0) -#define sched_info_switch(rq, t, next) do { } while (0) -#endif /* CONFIG_SCHED_INFO */ - -/* - * The following are functions that support scheduler-internal time accounting. - * These functions are generally called at the timer tick. None of this depends - * on CONFIG_SCHEDSTATS. - */ - -/** - * cputimer_running - return true if cputimer is running - * - * @tsk: Pointer to target task. - */ -static inline bool cputimer_running(struct task_struct *tsk) - -{ - struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; - - /* Check if cputimer isn't running. This is accessed without locking. */ - if (!READ_ONCE(cputimer->running)) - return false; - - /* - * After we flush the task's sum_exec_runtime to sig->sum_sched_runtime - * in __exit_signal(), we won't account to the signal struct further - * cputime consumed by that task, even though the task can still be - * ticking after __exit_signal(). - * - * In order to keep a consistent behaviour between thread group cputime - * and thread group cputimer accounting, lets also ignore the cputime - * elapsing after __exit_signal() in any thread group timer running. - * - * This makes sure that POSIX CPU clocks and timers are synchronized, so - * that a POSIX CPU timer won't expire while the corresponding POSIX CPU - * clock delta is behind the expiring timer value. - */ - if (unlikely(!tsk->sighand)) - return false; - - return true; -} - -/** - * account_group_user_time - Maintain utime for a thread group. - * - * @tsk: Pointer to task structure. - * @cputime: Time value by which to increment the utime field of the - * thread_group_cputime structure. - * - * If thread group time is being maintained, get the structure for the - * running CPU and update the utime field there. - */ -static inline void account_group_user_time(struct task_struct *tsk, - cputime_t cputime) -{ - struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; - - if (!cputimer_running(tsk)) - return; - - atomic64_add(cputime, &cputimer->cputime_atomic.utime); -} - -/** - * account_group_system_time - Maintain stime for a thread group. - * - * @tsk: Pointer to task structure. - * @cputime: Time value by which to increment the stime field of the - * thread_group_cputime structure. - * - * If thread group time is being maintained, get the structure for the - * running CPU and update the stime field there. - */ -static inline void account_group_system_time(struct task_struct *tsk, - cputime_t cputime) -{ - struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; - - if (!cputimer_running(tsk)) - return; - - atomic64_add(cputime, &cputimer->cputime_atomic.stime); -} - -/** - * account_group_exec_runtime - Maintain exec runtime for a thread group. - * - * @tsk: Pointer to task structure. - * @ns: Time value by which to increment the sum_exec_runtime field - * of the thread_group_cputime structure. - * - * If thread group time is being maintained, get the structure for the - * running CPU and update the sum_exec_runtime field there. - */ -static inline void account_group_exec_runtime(struct task_struct *tsk, - unsigned long long ns) -{ - struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; - - if (!cputimer_running(tsk)) - return; - - atomic64_add(ns, &cputimer->cputime_atomic.sum_exec_runtime); -} diff --git a/src/linux/kernel/sched/stop_task.c b/src/linux/kernel/sched/stop_task.c deleted file mode 100644 index 604297a..0000000 --- a/src/linux/kernel/sched/stop_task.c +++ /dev/null @@ -1,137 +0,0 @@ -#include "sched.h" - -/* - * stop-task scheduling class. - * - * The stop task is the highest priority task in the system, it preempts - * everything and will be preempted by nothing. - * - * See kernel/stop_machine.c - */ - -#ifdef CONFIG_SMP -static int -select_task_rq_stop(struct task_struct *p, int cpu, int sd_flag, int flags) -{ - return task_cpu(p); /* stop tasks as never migrate */ -} -#endif /* CONFIG_SMP */ - -static void -check_preempt_curr_stop(struct rq *rq, struct task_struct *p, int flags) -{ - /* we're never preempted */ -} - -static struct task_struct * -pick_next_task_stop(struct rq *rq, struct task_struct *prev, struct pin_cookie cookie) -{ - struct task_struct *stop = rq->stop; - - if (!stop || !task_on_rq_queued(stop)) - return NULL; - - put_prev_task(rq, prev); - - stop->se.exec_start = rq_clock_task(rq); - - return stop; -} - -static void -enqueue_task_stop(struct rq *rq, struct task_struct *p, int flags) -{ - add_nr_running(rq, 1); -} - -static void -dequeue_task_stop(struct rq *rq, struct task_struct *p, int flags) -{ - sub_nr_running(rq, 1); -} - -static void yield_task_stop(struct rq *rq) -{ - BUG(); /* the stop task should never yield, its pointless. */ -} - -static void put_prev_task_stop(struct rq *rq, struct task_struct *prev) -{ - struct task_struct *curr = rq->curr; - u64 delta_exec; - - delta_exec = rq_clock_task(rq) - curr->se.exec_start; - if (unlikely((s64)delta_exec < 0)) - delta_exec = 0; - - schedstat_set(curr->se.statistics.exec_max, - max(curr->se.statistics.exec_max, delta_exec)); - - curr->se.sum_exec_runtime += delta_exec; - account_group_exec_runtime(curr, delta_exec); - - curr->se.exec_start = rq_clock_task(rq); - cpuacct_charge(curr, delta_exec); -} - -static void task_tick_stop(struct rq *rq, struct task_struct *curr, int queued) -{ -} - -static void set_curr_task_stop(struct rq *rq) -{ - struct task_struct *stop = rq->stop; - - stop->se.exec_start = rq_clock_task(rq); -} - -static void switched_to_stop(struct rq *rq, struct task_struct *p) -{ - BUG(); /* its impossible to change to this class */ -} - -static void -prio_changed_stop(struct rq *rq, struct task_struct *p, int oldprio) -{ - BUG(); /* how!?, what priority? */ -} - -static unsigned int -get_rr_interval_stop(struct rq *rq, struct task_struct *task) -{ - return 0; -} - -static void update_curr_stop(struct rq *rq) -{ -} - -/* - * Simple, special scheduling class for the per-CPU stop tasks: - */ -const struct sched_class stop_sched_class = { - .next = &dl_sched_class, - - .enqueue_task = enqueue_task_stop, - .dequeue_task = dequeue_task_stop, - .yield_task = yield_task_stop, - - .check_preempt_curr = check_preempt_curr_stop, - - .pick_next_task = pick_next_task_stop, - .put_prev_task = put_prev_task_stop, - -#ifdef CONFIG_SMP - .select_task_rq = select_task_rq_stop, - .set_cpus_allowed = set_cpus_allowed_common, -#endif - - .set_curr_task = set_curr_task_stop, - .task_tick = task_tick_stop, - - .get_rr_interval = get_rr_interval_stop, - - .prio_changed = prio_changed_stop, - .switched_to = switched_to_stop, - .update_curr = update_curr_stop, -}; diff --git a/src/linux/kernel/sched/swait.c b/src/linux/kernel/sched/swait.c deleted file mode 100644 index 82f0dff..0000000 --- a/src/linux/kernel/sched/swait.c +++ /dev/null @@ -1,123 +0,0 @@ -#include -#include - -void __init_swait_queue_head(struct swait_queue_head *q, const char *name, - struct lock_class_key *key) -{ - raw_spin_lock_init(&q->lock); - lockdep_set_class_and_name(&q->lock, key, name); - INIT_LIST_HEAD(&q->task_list); -} -EXPORT_SYMBOL(__init_swait_queue_head); - -/* - * The thing about the wake_up_state() return value; I think we can ignore it. - * - * If for some reason it would return 0, that means the previously waiting - * task is already running, so it will observe condition true (or has already). - */ -void swake_up_locked(struct swait_queue_head *q) -{ - struct swait_queue *curr; - - if (list_empty(&q->task_list)) - return; - - curr = list_first_entry(&q->task_list, typeof(*curr), task_list); - wake_up_process(curr->task); - list_del_init(&curr->task_list); -} -EXPORT_SYMBOL(swake_up_locked); - -void swake_up(struct swait_queue_head *q) -{ - unsigned long flags; - - if (!swait_active(q)) - return; - - raw_spin_lock_irqsave(&q->lock, flags); - swake_up_locked(q); - raw_spin_unlock_irqrestore(&q->lock, flags); -} -EXPORT_SYMBOL(swake_up); - -/* - * Does not allow usage from IRQ disabled, since we must be able to - * release IRQs to guarantee bounded hold time. - */ -void swake_up_all(struct swait_queue_head *q) -{ - struct swait_queue *curr; - LIST_HEAD(tmp); - - if (!swait_active(q)) - return; - - raw_spin_lock_irq(&q->lock); - list_splice_init(&q->task_list, &tmp); - while (!list_empty(&tmp)) { - curr = list_first_entry(&tmp, typeof(*curr), task_list); - - wake_up_state(curr->task, TASK_NORMAL); - list_del_init(&curr->task_list); - - if (list_empty(&tmp)) - break; - - raw_spin_unlock_irq(&q->lock); - raw_spin_lock_irq(&q->lock); - } - raw_spin_unlock_irq(&q->lock); -} -EXPORT_SYMBOL(swake_up_all); - -void __prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait) -{ - wait->task = current; - if (list_empty(&wait->task_list)) - list_add(&wait->task_list, &q->task_list); -} - -void prepare_to_swait(struct swait_queue_head *q, struct swait_queue *wait, int state) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&q->lock, flags); - __prepare_to_swait(q, wait); - set_current_state(state); - raw_spin_unlock_irqrestore(&q->lock, flags); -} -EXPORT_SYMBOL(prepare_to_swait); - -long prepare_to_swait_event(struct swait_queue_head *q, struct swait_queue *wait, int state) -{ - if (signal_pending_state(state, current)) - return -ERESTARTSYS; - - prepare_to_swait(q, wait, state); - - return 0; -} -EXPORT_SYMBOL(prepare_to_swait_event); - -void __finish_swait(struct swait_queue_head *q, struct swait_queue *wait) -{ - __set_current_state(TASK_RUNNING); - if (!list_empty(&wait->task_list)) - list_del_init(&wait->task_list); -} - -void finish_swait(struct swait_queue_head *q, struct swait_queue *wait) -{ - unsigned long flags; - - __set_current_state(TASK_RUNNING); - - if (!list_empty_careful(&wait->task_list)) { - raw_spin_lock_irqsave(&q->lock, flags); - list_del_init(&wait->task_list); - raw_spin_unlock_irqrestore(&q->lock, flags); - } -} -EXPORT_SYMBOL(finish_swait); diff --git a/src/linux/kernel/sched/wait.c b/src/linux/kernel/sched/wait.c deleted file mode 100644 index 9453efe..0000000 --- a/src/linux/kernel/sched/wait.c +++ /dev/null @@ -1,611 +0,0 @@ -/* - * Generic waiting primitives. - * - * (C) 2004 Nadia Yvette Chambers, Oracle - */ -#include -#include -#include -#include -#include -#include -#include - -void __init_waitqueue_head(wait_queue_head_t *q, const char *name, struct lock_class_key *key) -{ - spin_lock_init(&q->lock); - lockdep_set_class_and_name(&q->lock, key, name); - INIT_LIST_HEAD(&q->task_list); -} - -EXPORT_SYMBOL(__init_waitqueue_head); - -void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait) -{ - unsigned long flags; - - wait->flags &= ~WQ_FLAG_EXCLUSIVE; - spin_lock_irqsave(&q->lock, flags); - __add_wait_queue(q, wait); - spin_unlock_irqrestore(&q->lock, flags); -} -EXPORT_SYMBOL(add_wait_queue); - -void add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t *wait) -{ - unsigned long flags; - - wait->flags |= WQ_FLAG_EXCLUSIVE; - spin_lock_irqsave(&q->lock, flags); - __add_wait_queue_tail(q, wait); - spin_unlock_irqrestore(&q->lock, flags); -} -EXPORT_SYMBOL(add_wait_queue_exclusive); - -void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait) -{ - unsigned long flags; - - spin_lock_irqsave(&q->lock, flags); - __remove_wait_queue(q, wait); - spin_unlock_irqrestore(&q->lock, flags); -} -EXPORT_SYMBOL(remove_wait_queue); - - -/* - * The core wakeup function. Non-exclusive wakeups (nr_exclusive == 0) just - * wake everything up. If it's an exclusive wakeup (nr_exclusive == small +ve - * number) then we wake all the non-exclusive tasks and one exclusive task. - * - * There are circumstances in which we can try to wake a task which has already - * started to run but is not in state TASK_RUNNING. try_to_wake_up() returns - * zero in this (rare) case, and we handle it by continuing to scan the queue. - */ -static void __wake_up_common(wait_queue_head_t *q, unsigned int mode, - int nr_exclusive, int wake_flags, void *key) -{ - wait_queue_t *curr, *next; - - list_for_each_entry_safe(curr, next, &q->task_list, task_list) { - unsigned flags = curr->flags; - - if (curr->func(curr, mode, wake_flags, key) && - (flags & WQ_FLAG_EXCLUSIVE) && !--nr_exclusive) - break; - } -} - -/** - * __wake_up - wake up threads blocked on a waitqueue. - * @q: the waitqueue - * @mode: which threads - * @nr_exclusive: how many wake-one or wake-many threads to wake up - * @key: is directly passed to the wakeup function - * - * It may be assumed that this function implies a write memory barrier before - * changing the task state if and only if any tasks are woken up. - */ -void __wake_up(wait_queue_head_t *q, unsigned int mode, - int nr_exclusive, void *key) -{ - unsigned long flags; - - spin_lock_irqsave(&q->lock, flags); - __wake_up_common(q, mode, nr_exclusive, 0, key); - spin_unlock_irqrestore(&q->lock, flags); -} -EXPORT_SYMBOL(__wake_up); - -/* - * Same as __wake_up but called with the spinlock in wait_queue_head_t held. - */ -void __wake_up_locked(wait_queue_head_t *q, unsigned int mode, int nr) -{ - __wake_up_common(q, mode, nr, 0, NULL); -} -EXPORT_SYMBOL_GPL(__wake_up_locked); - -void __wake_up_locked_key(wait_queue_head_t *q, unsigned int mode, void *key) -{ - __wake_up_common(q, mode, 1, 0, key); -} -EXPORT_SYMBOL_GPL(__wake_up_locked_key); - -/** - * __wake_up_sync_key - wake up threads blocked on a waitqueue. - * @q: the waitqueue - * @mode: which threads - * @nr_exclusive: how many wake-one or wake-many threads to wake up - * @key: opaque value to be passed to wakeup targets - * - * The sync wakeup differs that the waker knows that it will schedule - * away soon, so while the target thread will be woken up, it will not - * be migrated to another CPU - ie. the two threads are 'synchronized' - * with each other. This can prevent needless bouncing between CPUs. - * - * On UP it can prevent extra preemption. - * - * It may be assumed that this function implies a write memory barrier before - * changing the task state if and only if any tasks are woken up. - */ -void __wake_up_sync_key(wait_queue_head_t *q, unsigned int mode, - int nr_exclusive, void *key) -{ - unsigned long flags; - int wake_flags = 1; /* XXX WF_SYNC */ - - if (unlikely(!q)) - return; - - if (unlikely(nr_exclusive != 1)) - wake_flags = 0; - - spin_lock_irqsave(&q->lock, flags); - __wake_up_common(q, mode, nr_exclusive, wake_flags, key); - spin_unlock_irqrestore(&q->lock, flags); -} -EXPORT_SYMBOL_GPL(__wake_up_sync_key); - -/* - * __wake_up_sync - see __wake_up_sync_key() - */ -void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive) -{ - __wake_up_sync_key(q, mode, nr_exclusive, NULL); -} -EXPORT_SYMBOL_GPL(__wake_up_sync); /* For internal use only */ - -/* - * Note: we use "set_current_state()" _after_ the wait-queue add, - * because we need a memory barrier there on SMP, so that any - * wake-function that tests for the wait-queue being active - * will be guaranteed to see waitqueue addition _or_ subsequent - * tests in this thread will see the wakeup having taken place. - * - * The spin_unlock() itself is semi-permeable and only protects - * one way (it only protects stuff inside the critical region and - * stops them from bleeding out - it would still allow subsequent - * loads to move into the critical region). - */ -void -prepare_to_wait(wait_queue_head_t *q, wait_queue_t *wait, int state) -{ - unsigned long flags; - - wait->flags &= ~WQ_FLAG_EXCLUSIVE; - spin_lock_irqsave(&q->lock, flags); - if (list_empty(&wait->task_list)) - __add_wait_queue(q, wait); - set_current_state(state); - spin_unlock_irqrestore(&q->lock, flags); -} -EXPORT_SYMBOL(prepare_to_wait); - -void -prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int state) -{ - unsigned long flags; - - wait->flags |= WQ_FLAG_EXCLUSIVE; - spin_lock_irqsave(&q->lock, flags); - if (list_empty(&wait->task_list)) - __add_wait_queue_tail(q, wait); - set_current_state(state); - spin_unlock_irqrestore(&q->lock, flags); -} -EXPORT_SYMBOL(prepare_to_wait_exclusive); - -void init_wait_entry(wait_queue_t *wait, int flags) -{ - wait->flags = flags; - wait->private = current; - wait->func = autoremove_wake_function; - INIT_LIST_HEAD(&wait->task_list); -} -EXPORT_SYMBOL(init_wait_entry); - -long prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state) -{ - unsigned long flags; - long ret = 0; - - spin_lock_irqsave(&q->lock, flags); - if (unlikely(signal_pending_state(state, current))) { - /* - * Exclusive waiter must not fail if it was selected by wakeup, - * it should "consume" the condition we were waiting for. - * - * The caller will recheck the condition and return success if - * we were already woken up, we can not miss the event because - * wakeup locks/unlocks the same q->lock. - * - * But we need to ensure that set-condition + wakeup after that - * can't see us, it should wake up another exclusive waiter if - * we fail. - */ - list_del_init(&wait->task_list); - ret = -ERESTARTSYS; - } else { - if (list_empty(&wait->task_list)) { - if (wait->flags & WQ_FLAG_EXCLUSIVE) - __add_wait_queue_tail(q, wait); - else - __add_wait_queue(q, wait); - } - set_current_state(state); - } - spin_unlock_irqrestore(&q->lock, flags); - - return ret; -} -EXPORT_SYMBOL(prepare_to_wait_event); - -/** - * finish_wait - clean up after waiting in a queue - * @q: waitqueue waited on - * @wait: wait descriptor - * - * Sets current thread back to running state and removes - * the wait descriptor from the given waitqueue if still - * queued. - */ -void finish_wait(wait_queue_head_t *q, wait_queue_t *wait) -{ - unsigned long flags; - - __set_current_state(TASK_RUNNING); - /* - * We can check for list emptiness outside the lock - * IFF: - * - we use the "careful" check that verifies both - * the next and prev pointers, so that there cannot - * be any half-pending updates in progress on other - * CPU's that we haven't seen yet (and that might - * still change the stack area. - * and - * - all other users take the lock (ie we can only - * have _one_ other CPU that looks at or modifies - * the list). - */ - if (!list_empty_careful(&wait->task_list)) { - spin_lock_irqsave(&q->lock, flags); - list_del_init(&wait->task_list); - spin_unlock_irqrestore(&q->lock, flags); - } -} -EXPORT_SYMBOL(finish_wait); - -int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key) -{ - int ret = default_wake_function(wait, mode, sync, key); - - if (ret) - list_del_init(&wait->task_list); - return ret; -} -EXPORT_SYMBOL(autoremove_wake_function); - -static inline bool is_kthread_should_stop(void) -{ - return (current->flags & PF_KTHREAD) && kthread_should_stop(); -} - -/* - * DEFINE_WAIT_FUNC(wait, woken_wake_func); - * - * add_wait_queue(&wq, &wait); - * for (;;) { - * if (condition) - * break; - * - * p->state = mode; condition = true; - * smp_mb(); // A smp_wmb(); // C - * if (!wait->flags & WQ_FLAG_WOKEN) wait->flags |= WQ_FLAG_WOKEN; - * schedule() try_to_wake_up(); - * p->state = TASK_RUNNING; ~~~~~~~~~~~~~~~~~~ - * wait->flags &= ~WQ_FLAG_WOKEN; condition = true; - * smp_mb() // B smp_wmb(); // C - * wait->flags |= WQ_FLAG_WOKEN; - * } - * remove_wait_queue(&wq, &wait); - * - */ -long wait_woken(wait_queue_t *wait, unsigned mode, long timeout) -{ - set_current_state(mode); /* A */ - /* - * The above implies an smp_mb(), which matches with the smp_wmb() from - * woken_wake_function() such that if we observe WQ_FLAG_WOKEN we must - * also observe all state before the wakeup. - */ - if (!(wait->flags & WQ_FLAG_WOKEN) && !is_kthread_should_stop()) - timeout = schedule_timeout(timeout); - __set_current_state(TASK_RUNNING); - - /* - * The below implies an smp_mb(), it too pairs with the smp_wmb() from - * woken_wake_function() such that we must either observe the wait - * condition being true _OR_ WQ_FLAG_WOKEN such that we will not miss - * an event. - */ - smp_store_mb(wait->flags, wait->flags & ~WQ_FLAG_WOKEN); /* B */ - - return timeout; -} -EXPORT_SYMBOL(wait_woken); - -int woken_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key) -{ - /* - * Although this function is called under waitqueue lock, LOCK - * doesn't imply write barrier and the users expects write - * barrier semantics on wakeup functions. The following - * smp_wmb() is equivalent to smp_wmb() in try_to_wake_up() - * and is paired with smp_store_mb() in wait_woken(). - */ - smp_wmb(); /* C */ - wait->flags |= WQ_FLAG_WOKEN; - - return default_wake_function(wait, mode, sync, key); -} -EXPORT_SYMBOL(woken_wake_function); - -int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *arg) -{ - struct wait_bit_key *key = arg; - struct wait_bit_queue *wait_bit - = container_of(wait, struct wait_bit_queue, wait); - - if (wait_bit->key.flags != key->flags || - wait_bit->key.bit_nr != key->bit_nr || - test_bit(key->bit_nr, key->flags)) - return 0; - else - return autoremove_wake_function(wait, mode, sync, key); -} -EXPORT_SYMBOL(wake_bit_function); - -/* - * To allow interruptible waiting and asynchronous (i.e. nonblocking) - * waiting, the actions of __wait_on_bit() and __wait_on_bit_lock() are - * permitted return codes. Nonzero return codes halt waiting and return. - */ -int __sched -__wait_on_bit(wait_queue_head_t *wq, struct wait_bit_queue *q, - wait_bit_action_f *action, unsigned mode) -{ - int ret = 0; - - do { - prepare_to_wait(wq, &q->wait, mode); - if (test_bit(q->key.bit_nr, q->key.flags)) - ret = (*action)(&q->key, mode); - } while (test_bit(q->key.bit_nr, q->key.flags) && !ret); - finish_wait(wq, &q->wait); - return ret; -} -EXPORT_SYMBOL(__wait_on_bit); - -int __sched out_of_line_wait_on_bit(void *word, int bit, - wait_bit_action_f *action, unsigned mode) -{ - wait_queue_head_t *wq = bit_waitqueue(word, bit); - DEFINE_WAIT_BIT(wait, word, bit); - - return __wait_on_bit(wq, &wait, action, mode); -} -EXPORT_SYMBOL(out_of_line_wait_on_bit); - -int __sched out_of_line_wait_on_bit_timeout( - void *word, int bit, wait_bit_action_f *action, - unsigned mode, unsigned long timeout) -{ - wait_queue_head_t *wq = bit_waitqueue(word, bit); - DEFINE_WAIT_BIT(wait, word, bit); - - wait.key.timeout = jiffies + timeout; - return __wait_on_bit(wq, &wait, action, mode); -} -EXPORT_SYMBOL_GPL(out_of_line_wait_on_bit_timeout); - -int __sched -__wait_on_bit_lock(wait_queue_head_t *wq, struct wait_bit_queue *q, - wait_bit_action_f *action, unsigned mode) -{ - int ret = 0; - - for (;;) { - prepare_to_wait_exclusive(wq, &q->wait, mode); - if (test_bit(q->key.bit_nr, q->key.flags)) { - ret = action(&q->key, mode); - /* - * See the comment in prepare_to_wait_event(). - * finish_wait() does not necessarily takes wq->lock, - * but test_and_set_bit() implies mb() which pairs with - * smp_mb__after_atomic() before wake_up_page(). - */ - if (ret) - finish_wait(wq, &q->wait); - } - if (!test_and_set_bit(q->key.bit_nr, q->key.flags)) { - if (!ret) - finish_wait(wq, &q->wait); - return 0; - } else if (ret) { - return ret; - } - } -} -EXPORT_SYMBOL(__wait_on_bit_lock); - -int __sched out_of_line_wait_on_bit_lock(void *word, int bit, - wait_bit_action_f *action, unsigned mode) -{ - wait_queue_head_t *wq = bit_waitqueue(word, bit); - DEFINE_WAIT_BIT(wait, word, bit); - - return __wait_on_bit_lock(wq, &wait, action, mode); -} -EXPORT_SYMBOL(out_of_line_wait_on_bit_lock); - -void __wake_up_bit(wait_queue_head_t *wq, void *word, int bit) -{ - struct wait_bit_key key = __WAIT_BIT_KEY_INITIALIZER(word, bit); - if (waitqueue_active(wq)) - __wake_up(wq, TASK_NORMAL, 1, &key); -} -EXPORT_SYMBOL(__wake_up_bit); - -/** - * wake_up_bit - wake up a waiter on a bit - * @word: the word being waited on, a kernel virtual address - * @bit: the bit of the word being waited on - * - * There is a standard hashed waitqueue table for generic use. This - * is the part of the hashtable's accessor API that wakes up waiters - * on a bit. For instance, if one were to have waiters on a bitflag, - * one would call wake_up_bit() after clearing the bit. - * - * In order for this to function properly, as it uses waitqueue_active() - * internally, some kind of memory barrier must be done prior to calling - * this. Typically, this will be smp_mb__after_atomic(), but in some - * cases where bitflags are manipulated non-atomically under a lock, one - * may need to use a less regular barrier, such fs/inode.c's smp_mb(), - * because spin_unlock() does not guarantee a memory barrier. - */ -void wake_up_bit(void *word, int bit) -{ - __wake_up_bit(bit_waitqueue(word, bit), word, bit); -} -EXPORT_SYMBOL(wake_up_bit); - -/* - * Manipulate the atomic_t address to produce a better bit waitqueue table hash - * index (we're keying off bit -1, but that would produce a horrible hash - * value). - */ -static inline wait_queue_head_t *atomic_t_waitqueue(atomic_t *p) -{ - if (BITS_PER_LONG == 64) { - unsigned long q = (unsigned long)p; - return bit_waitqueue((void *)(q & ~1), q & 1); - } - return bit_waitqueue(p, 0); -} - -static int wake_atomic_t_function(wait_queue_t *wait, unsigned mode, int sync, - void *arg) -{ - struct wait_bit_key *key = arg; - struct wait_bit_queue *wait_bit - = container_of(wait, struct wait_bit_queue, wait); - atomic_t *val = key->flags; - - if (wait_bit->key.flags != key->flags || - wait_bit->key.bit_nr != key->bit_nr || - atomic_read(val) != 0) - return 0; - return autoremove_wake_function(wait, mode, sync, key); -} - -/* - * To allow interruptible waiting and asynchronous (i.e. nonblocking) waiting, - * the actions of __wait_on_atomic_t() are permitted return codes. Nonzero - * return codes halt waiting and return. - */ -static __sched -int __wait_on_atomic_t(wait_queue_head_t *wq, struct wait_bit_queue *q, - int (*action)(atomic_t *), unsigned mode) -{ - atomic_t *val; - int ret = 0; - - do { - prepare_to_wait(wq, &q->wait, mode); - val = q->key.flags; - if (atomic_read(val) == 0) - break; - ret = (*action)(val); - } while (!ret && atomic_read(val) != 0); - finish_wait(wq, &q->wait); - return ret; -} - -#define DEFINE_WAIT_ATOMIC_T(name, p) \ - struct wait_bit_queue name = { \ - .key = __WAIT_ATOMIC_T_KEY_INITIALIZER(p), \ - .wait = { \ - .private = current, \ - .func = wake_atomic_t_function, \ - .task_list = \ - LIST_HEAD_INIT((name).wait.task_list), \ - }, \ - } - -__sched int out_of_line_wait_on_atomic_t(atomic_t *p, int (*action)(atomic_t *), - unsigned mode) -{ - wait_queue_head_t *wq = atomic_t_waitqueue(p); - DEFINE_WAIT_ATOMIC_T(wait, p); - - return __wait_on_atomic_t(wq, &wait, action, mode); -} -EXPORT_SYMBOL(out_of_line_wait_on_atomic_t); - -/** - * wake_up_atomic_t - Wake up a waiter on a atomic_t - * @p: The atomic_t being waited on, a kernel virtual address - * - * Wake up anyone waiting for the atomic_t to go to zero. - * - * Abuse the bit-waker function and its waitqueue hash table set (the atomic_t - * check is done by the waiter's wake function, not the by the waker itself). - */ -void wake_up_atomic_t(atomic_t *p) -{ - __wake_up_bit(atomic_t_waitqueue(p), p, WAIT_ATOMIC_T_BIT_NR); -} -EXPORT_SYMBOL(wake_up_atomic_t); - -__sched int bit_wait(struct wait_bit_key *word, int mode) -{ - schedule(); - if (signal_pending_state(mode, current)) - return -EINTR; - return 0; -} -EXPORT_SYMBOL(bit_wait); - -__sched int bit_wait_io(struct wait_bit_key *word, int mode) -{ - io_schedule(); - if (signal_pending_state(mode, current)) - return -EINTR; - return 0; -} -EXPORT_SYMBOL(bit_wait_io); - -__sched int bit_wait_timeout(struct wait_bit_key *word, int mode) -{ - unsigned long now = READ_ONCE(jiffies); - if (time_after_eq(now, word->timeout)) - return -EAGAIN; - schedule_timeout(word->timeout - now); - if (signal_pending_state(mode, current)) - return -EINTR; - return 0; -} -EXPORT_SYMBOL_GPL(bit_wait_timeout); - -__sched int bit_wait_io_timeout(struct wait_bit_key *word, int mode) -{ - unsigned long now = READ_ONCE(jiffies); - if (time_after_eq(now, word->timeout)) - return -EAGAIN; - io_schedule_timeout(word->timeout - now); - if (signal_pending_state(mode, current)) - return -EINTR; - return 0; -} -EXPORT_SYMBOL_GPL(bit_wait_io_timeout); diff --git a/src/linux/kernel/signal.c b/src/linux/kernel/signal.c deleted file mode 100644 index 644c6d5..0000000 --- a/src/linux/kernel/signal.c +++ /dev/null @@ -1,3639 +0,0 @@ -/* - * linux/kernel/signal.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * 1997-11-02 Modified for POSIX.1b signals by Richard Henderson - * - * 2003-06-02 Jim Houston - Concurrent Computer Corp. - * Changes to use preallocated sigqueue structures - * to allow signals to be sent reliably. - */ - -#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 CREATE_TRACE_POINTS -#include - -#include -#include -#include -#include -#include -#include "audit.h" /* audit_signal_info() */ - -/* - * SLAB caches for signal bits. - */ - -static struct kmem_cache *sigqueue_cachep; - -int print_fatal_signals __read_mostly; - -static void __user *sig_handler(struct task_struct *t, int sig) -{ - return t->sighand->action[sig - 1].sa.sa_handler; -} - -static int sig_handler_ignored(void __user *handler, int sig) -{ - /* Is it explicitly or implicitly ignored? */ - return handler == SIG_IGN || - (handler == SIG_DFL && sig_kernel_ignore(sig)); -} - -static int sig_task_ignored(struct task_struct *t, int sig, bool force) -{ - void __user *handler; - - handler = sig_handler(t, sig); - - if (unlikely(t->signal->flags & SIGNAL_UNKILLABLE) && - handler == SIG_DFL && !force) - return 1; - - return sig_handler_ignored(handler, sig); -} - -static int sig_ignored(struct task_struct *t, int sig, bool force) -{ - /* - * Blocked signals are never ignored, since the - * signal handler may change by the time it is - * unblocked. - */ - if (sigismember(&t->blocked, sig) || sigismember(&t->real_blocked, sig)) - return 0; - - if (!sig_task_ignored(t, sig, force)) - return 0; - - /* - * Tracers may want to know about even ignored signals. - */ - return !t->ptrace; -} - -/* - * Re-calculate pending state from the set of locally pending - * signals, globally pending signals, and blocked signals. - */ -static inline int has_pending_signals(sigset_t *signal, sigset_t *blocked) -{ - unsigned long ready; - long i; - - switch (_NSIG_WORDS) { - default: - for (i = _NSIG_WORDS, ready = 0; --i >= 0 ;) - ready |= signal->sig[i] &~ blocked->sig[i]; - break; - - case 4: ready = signal->sig[3] &~ blocked->sig[3]; - ready |= signal->sig[2] &~ blocked->sig[2]; - ready |= signal->sig[1] &~ blocked->sig[1]; - ready |= signal->sig[0] &~ blocked->sig[0]; - break; - - case 2: ready = signal->sig[1] &~ blocked->sig[1]; - ready |= signal->sig[0] &~ blocked->sig[0]; - break; - - case 1: ready = signal->sig[0] &~ blocked->sig[0]; - } - return ready != 0; -} - -#define PENDING(p,b) has_pending_signals(&(p)->signal, (b)) - -static int recalc_sigpending_tsk(struct task_struct *t) -{ - if ((t->jobctl & JOBCTL_PENDING_MASK) || - PENDING(&t->pending, &t->blocked) || - PENDING(&t->signal->shared_pending, &t->blocked)) { - set_tsk_thread_flag(t, TIF_SIGPENDING); - return 1; - } - /* - * We must never clear the flag in another thread, or in current - * when it's possible the current syscall is returning -ERESTART*. - * So we don't clear it here, and only callers who know they should do. - */ - return 0; -} - -/* - * After recalculating TIF_SIGPENDING, we need to make sure the task wakes up. - * This is superfluous when called on current, the wakeup is a harmless no-op. - */ -void recalc_sigpending_and_wake(struct task_struct *t) -{ - if (recalc_sigpending_tsk(t)) - signal_wake_up(t, 0); -} - -void recalc_sigpending(void) -{ - if (!recalc_sigpending_tsk(current) && !freezing(current)) - clear_thread_flag(TIF_SIGPENDING); - -} - -/* Given the mask, find the first available signal that should be serviced. */ - -#define SYNCHRONOUS_MASK \ - (sigmask(SIGSEGV) | sigmask(SIGBUS) | sigmask(SIGILL) | \ - sigmask(SIGTRAP) | sigmask(SIGFPE) | sigmask(SIGSYS)) - -int next_signal(struct sigpending *pending, sigset_t *mask) -{ - unsigned long i, *s, *m, x; - int sig = 0; - - s = pending->signal.sig; - m = mask->sig; - - /* - * Handle the first word specially: it contains the - * synchronous signals that need to be dequeued first. - */ - x = *s &~ *m; - if (x) { - if (x & SYNCHRONOUS_MASK) - x &= SYNCHRONOUS_MASK; - sig = ffz(~x) + 1; - return sig; - } - - switch (_NSIG_WORDS) { - default: - for (i = 1; i < _NSIG_WORDS; ++i) { - x = *++s &~ *++m; - if (!x) - continue; - sig = ffz(~x) + i*_NSIG_BPW + 1; - break; - } - break; - - case 2: - x = s[1] &~ m[1]; - if (!x) - break; - sig = ffz(~x) + _NSIG_BPW + 1; - break; - - case 1: - /* Nothing to do */ - break; - } - - return sig; -} - -static inline void print_dropped_signal(int sig) -{ - static DEFINE_RATELIMIT_STATE(ratelimit_state, 5 * HZ, 10); - - if (!print_fatal_signals) - return; - - if (!__ratelimit(&ratelimit_state)) - return; - - pr_info("%s/%d: reached RLIMIT_SIGPENDING, dropped signal %d\n", - current->comm, current->pid, sig); -} - -/** - * task_set_jobctl_pending - set jobctl pending bits - * @task: target task - * @mask: pending bits to set - * - * Clear @mask from @task->jobctl. @mask must be subset of - * %JOBCTL_PENDING_MASK | %JOBCTL_STOP_CONSUME | %JOBCTL_STOP_SIGMASK | - * %JOBCTL_TRAPPING. If stop signo is being set, the existing signo is - * cleared. If @task is already being killed or exiting, this function - * becomes noop. - * - * CONTEXT: - * Must be called with @task->sighand->siglock held. - * - * RETURNS: - * %true if @mask is set, %false if made noop because @task was dying. - */ -bool task_set_jobctl_pending(struct task_struct *task, unsigned long mask) -{ - BUG_ON(mask & ~(JOBCTL_PENDING_MASK | JOBCTL_STOP_CONSUME | - JOBCTL_STOP_SIGMASK | JOBCTL_TRAPPING)); - BUG_ON((mask & JOBCTL_TRAPPING) && !(mask & JOBCTL_PENDING_MASK)); - - if (unlikely(fatal_signal_pending(task) || (task->flags & PF_EXITING))) - return false; - - if (mask & JOBCTL_STOP_SIGMASK) - task->jobctl &= ~JOBCTL_STOP_SIGMASK; - - task->jobctl |= mask; - return true; -} - -/** - * task_clear_jobctl_trapping - clear jobctl trapping bit - * @task: target task - * - * If JOBCTL_TRAPPING is set, a ptracer is waiting for us to enter TRACED. - * Clear it and wake up the ptracer. Note that we don't need any further - * locking. @task->siglock guarantees that @task->parent points to the - * ptracer. - * - * CONTEXT: - * Must be called with @task->sighand->siglock held. - */ -void task_clear_jobctl_trapping(struct task_struct *task) -{ - if (unlikely(task->jobctl & JOBCTL_TRAPPING)) { - task->jobctl &= ~JOBCTL_TRAPPING; - smp_mb(); /* advised by wake_up_bit() */ - wake_up_bit(&task->jobctl, JOBCTL_TRAPPING_BIT); - } -} - -/** - * task_clear_jobctl_pending - clear jobctl pending bits - * @task: target task - * @mask: pending bits to clear - * - * Clear @mask from @task->jobctl. @mask must be subset of - * %JOBCTL_PENDING_MASK. If %JOBCTL_STOP_PENDING is being cleared, other - * STOP bits are cleared together. - * - * If clearing of @mask leaves no stop or trap pending, this function calls - * task_clear_jobctl_trapping(). - * - * CONTEXT: - * Must be called with @task->sighand->siglock held. - */ -void task_clear_jobctl_pending(struct task_struct *task, unsigned long mask) -{ - BUG_ON(mask & ~JOBCTL_PENDING_MASK); - - if (mask & JOBCTL_STOP_PENDING) - mask |= JOBCTL_STOP_CONSUME | JOBCTL_STOP_DEQUEUED; - - task->jobctl &= ~mask; - - if (!(task->jobctl & JOBCTL_PENDING_MASK)) - task_clear_jobctl_trapping(task); -} - -/** - * task_participate_group_stop - participate in a group stop - * @task: task participating in a group stop - * - * @task has %JOBCTL_STOP_PENDING set and is participating in a group stop. - * Group stop states are cleared and the group stop count is consumed if - * %JOBCTL_STOP_CONSUME was set. If the consumption completes the group - * stop, the appropriate %SIGNAL_* flags are set. - * - * CONTEXT: - * Must be called with @task->sighand->siglock held. - * - * RETURNS: - * %true if group stop completion should be notified to the parent, %false - * otherwise. - */ -static bool task_participate_group_stop(struct task_struct *task) -{ - struct signal_struct *sig = task->signal; - bool consume = task->jobctl & JOBCTL_STOP_CONSUME; - - WARN_ON_ONCE(!(task->jobctl & JOBCTL_STOP_PENDING)); - - task_clear_jobctl_pending(task, JOBCTL_STOP_PENDING); - - if (!consume) - return false; - - if (!WARN_ON_ONCE(sig->group_stop_count == 0)) - sig->group_stop_count--; - - /* - * Tell the caller to notify completion iff we are entering into a - * fresh group stop. Read comment in do_signal_stop() for details. - */ - if (!sig->group_stop_count && !(sig->flags & SIGNAL_STOP_STOPPED)) { - sig->flags = SIGNAL_STOP_STOPPED; - return true; - } - return false; -} - -/* - * allocate a new signal queue record - * - this may be called without locks if and only if t == current, otherwise an - * appropriate lock must be held to stop the target task from exiting - */ -static struct sigqueue * -__sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimit) -{ - struct sigqueue *q = NULL; - struct user_struct *user; - - /* - * Protect access to @t credentials. This can go away when all - * callers hold rcu read lock. - */ - rcu_read_lock(); - user = get_uid(__task_cred(t)->user); - atomic_inc(&user->sigpending); - rcu_read_unlock(); - - if (override_rlimit || - atomic_read(&user->sigpending) <= - task_rlimit(t, RLIMIT_SIGPENDING)) { - q = kmem_cache_alloc(sigqueue_cachep, flags); - } else { - print_dropped_signal(sig); - } - - if (unlikely(q == NULL)) { - atomic_dec(&user->sigpending); - free_uid(user); - } else { - INIT_LIST_HEAD(&q->list); - q->flags = 0; - q->user = user; - } - - return q; -} - -static void __sigqueue_free(struct sigqueue *q) -{ - if (q->flags & SIGQUEUE_PREALLOC) - return; - atomic_dec(&q->user->sigpending); - free_uid(q->user); - kmem_cache_free(sigqueue_cachep, q); -} - -void flush_sigqueue(struct sigpending *queue) -{ - struct sigqueue *q; - - sigemptyset(&queue->signal); - while (!list_empty(&queue->list)) { - q = list_entry(queue->list.next, struct sigqueue , list); - list_del_init(&q->list); - __sigqueue_free(q); - } -} - -/* - * Flush all pending signals for this kthread. - */ -void flush_signals(struct task_struct *t) -{ - unsigned long flags; - - spin_lock_irqsave(&t->sighand->siglock, flags); - clear_tsk_thread_flag(t, TIF_SIGPENDING); - flush_sigqueue(&t->pending); - flush_sigqueue(&t->signal->shared_pending); - spin_unlock_irqrestore(&t->sighand->siglock, flags); -} - -static void __flush_itimer_signals(struct sigpending *pending) -{ - sigset_t signal, retain; - struct sigqueue *q, *n; - - signal = pending->signal; - sigemptyset(&retain); - - list_for_each_entry_safe(q, n, &pending->list, list) { - int sig = q->info.si_signo; - - if (likely(q->info.si_code != SI_TIMER)) { - sigaddset(&retain, sig); - } else { - sigdelset(&signal, sig); - list_del_init(&q->list); - __sigqueue_free(q); - } - } - - sigorsets(&pending->signal, &signal, &retain); -} - -void flush_itimer_signals(void) -{ - struct task_struct *tsk = current; - unsigned long flags; - - spin_lock_irqsave(&tsk->sighand->siglock, flags); - __flush_itimer_signals(&tsk->pending); - __flush_itimer_signals(&tsk->signal->shared_pending); - spin_unlock_irqrestore(&tsk->sighand->siglock, flags); -} - -void ignore_signals(struct task_struct *t) -{ - int i; - - for (i = 0; i < _NSIG; ++i) - t->sighand->action[i].sa.sa_handler = SIG_IGN; - - flush_signals(t); -} - -/* - * Flush all handlers for a task. - */ - -void -flush_signal_handlers(struct task_struct *t, int force_default) -{ - int i; - struct k_sigaction *ka = &t->sighand->action[0]; - for (i = _NSIG ; i != 0 ; i--) { - if (force_default || ka->sa.sa_handler != SIG_IGN) - ka->sa.sa_handler = SIG_DFL; - ka->sa.sa_flags = 0; -#ifdef __ARCH_HAS_SA_RESTORER - ka->sa.sa_restorer = NULL; -#endif - sigemptyset(&ka->sa.sa_mask); - ka++; - } -} - -int unhandled_signal(struct task_struct *tsk, int sig) -{ - void __user *handler = tsk->sighand->action[sig-1].sa.sa_handler; - if (is_global_init(tsk)) - return 1; - if (handler != SIG_IGN && handler != SIG_DFL) - return 0; - /* if ptraced, let the tracer determine */ - return !tsk->ptrace; -} - -static void collect_signal(int sig, struct sigpending *list, siginfo_t *info) -{ - struct sigqueue *q, *first = NULL; - - /* - * Collect the siginfo appropriate to this signal. Check if - * there is another siginfo for the same signal. - */ - list_for_each_entry(q, &list->list, list) { - if (q->info.si_signo == sig) { - if (first) - goto still_pending; - first = q; - } - } - - sigdelset(&list->signal, sig); - - if (first) { -still_pending: - list_del_init(&first->list); - copy_siginfo(info, &first->info); - __sigqueue_free(first); - } else { - /* - * Ok, it wasn't in the queue. This must be - * a fast-pathed signal or we must have been - * out of queue space. So zero out the info. - */ - info->si_signo = sig; - info->si_errno = 0; - info->si_code = SI_USER; - info->si_pid = 0; - info->si_uid = 0; - } -} - -static int __dequeue_signal(struct sigpending *pending, sigset_t *mask, - siginfo_t *info) -{ - int sig = next_signal(pending, mask); - - if (sig) - collect_signal(sig, pending, info); - return sig; -} - -/* - * Dequeue a signal and return the element to the caller, which is - * expected to free it. - * - * All callers have to hold the siglock. - */ -int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) -{ - int signr; - - /* We only dequeue private signals from ourselves, we don't let - * signalfd steal them - */ - signr = __dequeue_signal(&tsk->pending, mask, info); - if (!signr) { - signr = __dequeue_signal(&tsk->signal->shared_pending, - mask, info); - /* - * itimer signal ? - * - * itimers are process shared and we restart periodic - * itimers in the signal delivery path to prevent DoS - * attacks in the high resolution timer case. This is - * compliant with the old way of self-restarting - * itimers, as the SIGALRM is a legacy signal and only - * queued once. Changing the restart behaviour to - * restart the timer in the signal dequeue path is - * reducing the timer noise on heavy loaded !highres - * systems too. - */ - if (unlikely(signr == SIGALRM)) { - struct hrtimer *tmr = &tsk->signal->real_timer; - - if (!hrtimer_is_queued(tmr) && - tsk->signal->it_real_incr.tv64 != 0) { - hrtimer_forward(tmr, tmr->base->get_time(), - tsk->signal->it_real_incr); - hrtimer_restart(tmr); - } - } - } - - recalc_sigpending(); - if (!signr) - return 0; - - if (unlikely(sig_kernel_stop(signr))) { - /* - * Set a marker that we have dequeued a stop signal. Our - * caller might release the siglock and then the pending - * stop signal it is about to process is no longer in the - * pending bitmasks, but must still be cleared by a SIGCONT - * (and overruled by a SIGKILL). So those cases clear this - * shared flag after we've set it. Note that this flag may - * remain set after the signal we return is ignored or - * handled. That doesn't matter because its only purpose - * is to alert stop-signal processing code when another - * processor has come along and cleared the flag. - */ - current->jobctl |= JOBCTL_STOP_DEQUEUED; - } - if ((info->si_code & __SI_MASK) == __SI_TIMER && info->si_sys_private) { - /* - * Release the siglock to ensure proper locking order - * of timer locks outside of siglocks. Note, we leave - * irqs disabled here, since the posix-timers code is - * about to disable them again anyway. - */ - spin_unlock(&tsk->sighand->siglock); - do_schedule_next_timer(info); - spin_lock(&tsk->sighand->siglock); - } - return signr; -} - -/* - * Tell a process that it has a new active signal.. - * - * NOTE! we rely on the previous spin_lock to - * lock interrupts for us! We can only be called with - * "siglock" held, and the local interrupt must - * have been disabled when that got acquired! - * - * No need to set need_resched since signal event passing - * goes through ->blocked - */ -void signal_wake_up_state(struct task_struct *t, unsigned int state) -{ - set_tsk_thread_flag(t, TIF_SIGPENDING); - /* - * TASK_WAKEKILL also means wake it up in the stopped/traced/killable - * case. We don't check t->state here because there is a race with it - * executing another processor and just now entering stopped state. - * By using wake_up_state, we ensure the process will wake up and - * handle its death signal. - */ - if (!wake_up_state(t, state | TASK_INTERRUPTIBLE)) - kick_process(t); -} - -/* - * Remove signals in mask from the pending set and queue. - * Returns 1 if any signals were found. - * - * All callers must be holding the siglock. - */ -static int flush_sigqueue_mask(sigset_t *mask, struct sigpending *s) -{ - struct sigqueue *q, *n; - sigset_t m; - - sigandsets(&m, mask, &s->signal); - if (sigisemptyset(&m)) - return 0; - - sigandnsets(&s->signal, &s->signal, mask); - list_for_each_entry_safe(q, n, &s->list, list) { - if (sigismember(mask, q->info.si_signo)) { - list_del_init(&q->list); - __sigqueue_free(q); - } - } - return 1; -} - -static inline int is_si_special(const struct siginfo *info) -{ - return info <= SEND_SIG_FORCED; -} - -static inline bool si_fromuser(const struct siginfo *info) -{ - return info == SEND_SIG_NOINFO || - (!is_si_special(info) && SI_FROMUSER(info)); -} - -/* - * called with RCU read lock from check_kill_permission() - */ -static int kill_ok_by_cred(struct task_struct *t) -{ - const struct cred *cred = current_cred(); - const struct cred *tcred = __task_cred(t); - - if (uid_eq(cred->euid, tcred->suid) || - uid_eq(cred->euid, tcred->uid) || - uid_eq(cred->uid, tcred->suid) || - uid_eq(cred->uid, tcred->uid)) - return 1; - - if (ns_capable(tcred->user_ns, CAP_KILL)) - return 1; - - return 0; -} - -/* - * Bad permissions for sending the signal - * - the caller must hold the RCU read lock - */ -static int check_kill_permission(int sig, struct siginfo *info, - struct task_struct *t) -{ - struct pid *sid; - int error; - - if (!valid_signal(sig)) - return -EINVAL; - - if (!si_fromuser(info)) - return 0; - - error = audit_signal_info(sig, t); /* Let audit system see the signal */ - if (error) - return error; - - if (!same_thread_group(current, t) && - !kill_ok_by_cred(t)) { - switch (sig) { - case SIGCONT: - sid = task_session(t); - /* - * We don't return the error if sid == NULL. The - * task was unhashed, the caller must notice this. - */ - if (!sid || sid == task_session(current)) - break; - default: - return -EPERM; - } - } - - return security_task_kill(t, info, sig, 0); -} - -/** - * ptrace_trap_notify - schedule trap to notify ptracer - * @t: tracee wanting to notify tracer - * - * This function schedules sticky ptrace trap which is cleared on the next - * TRAP_STOP to notify ptracer of an event. @t must have been seized by - * ptracer. - * - * If @t is running, STOP trap will be taken. If trapped for STOP and - * ptracer is listening for events, tracee is woken up so that it can - * re-trap for the new event. If trapped otherwise, STOP trap will be - * eventually taken without returning to userland after the existing traps - * are finished by PTRACE_CONT. - * - * CONTEXT: - * Must be called with @task->sighand->siglock held. - */ -static void ptrace_trap_notify(struct task_struct *t) -{ - WARN_ON_ONCE(!(t->ptrace & PT_SEIZED)); - assert_spin_locked(&t->sighand->siglock); - - task_set_jobctl_pending(t, JOBCTL_TRAP_NOTIFY); - ptrace_signal_wake_up(t, t->jobctl & JOBCTL_LISTENING); -} - -/* - * Handle magic process-wide effects of stop/continue signals. Unlike - * the signal actions, these happen immediately at signal-generation - * time regardless of blocking, ignoring, or handling. This does the - * actual continuing for SIGCONT, but not the actual stopping for stop - * signals. The process stop is done as a signal action for SIG_DFL. - * - * Returns true if the signal should be actually delivered, otherwise - * it should be dropped. - */ -static bool prepare_signal(int sig, struct task_struct *p, bool force) -{ - struct signal_struct *signal = p->signal; - struct task_struct *t; - sigset_t flush; - - if (signal->flags & (SIGNAL_GROUP_EXIT | SIGNAL_GROUP_COREDUMP)) { - if (!(signal->flags & SIGNAL_GROUP_EXIT)) - return sig == SIGKILL; - /* - * The process is in the middle of dying, nothing to do. - */ - } else if (sig_kernel_stop(sig)) { - /* - * This is a stop signal. Remove SIGCONT from all queues. - */ - siginitset(&flush, sigmask(SIGCONT)); - flush_sigqueue_mask(&flush, &signal->shared_pending); - for_each_thread(p, t) - flush_sigqueue_mask(&flush, &t->pending); - } else if (sig == SIGCONT) { - unsigned int why; - /* - * Remove all stop signals from all queues, wake all threads. - */ - siginitset(&flush, SIG_KERNEL_STOP_MASK); - flush_sigqueue_mask(&flush, &signal->shared_pending); - for_each_thread(p, t) { - flush_sigqueue_mask(&flush, &t->pending); - task_clear_jobctl_pending(t, JOBCTL_STOP_PENDING); - if (likely(!(t->ptrace & PT_SEIZED))) - wake_up_state(t, __TASK_STOPPED); - else - ptrace_trap_notify(t); - } - - /* - * Notify the parent with CLD_CONTINUED if we were stopped. - * - * If we were in the middle of a group stop, we pretend it - * was already finished, and then continued. Since SIGCHLD - * doesn't queue we report only CLD_STOPPED, as if the next - * CLD_CONTINUED was dropped. - */ - why = 0; - if (signal->flags & SIGNAL_STOP_STOPPED) - why |= SIGNAL_CLD_CONTINUED; - else if (signal->group_stop_count) - why |= SIGNAL_CLD_STOPPED; - - if (why) { - /* - * The first thread which returns from do_signal_stop() - * will take ->siglock, notice SIGNAL_CLD_MASK, and - * notify its parent. See get_signal_to_deliver(). - */ - signal->flags = why | SIGNAL_STOP_CONTINUED; - signal->group_stop_count = 0; - signal->group_exit_code = 0; - } - } - - return !sig_ignored(p, sig, force); -} - -/* - * Test if P wants to take SIG. After we've checked all threads with this, - * it's equivalent to finding no threads not blocking SIG. Any threads not - * blocking SIG were ruled out because they are not running and already - * have pending signals. Such threads will dequeue from the shared queue - * as soon as they're available, so putting the signal on the shared queue - * will be equivalent to sending it to one such thread. - */ -static inline int wants_signal(int sig, struct task_struct *p) -{ - if (sigismember(&p->blocked, sig)) - return 0; - if (p->flags & PF_EXITING) - return 0; - if (sig == SIGKILL) - return 1; - if (task_is_stopped_or_traced(p)) - return 0; - return task_curr(p) || !signal_pending(p); -} - -static void complete_signal(int sig, struct task_struct *p, int group) -{ - struct signal_struct *signal = p->signal; - struct task_struct *t; - - /* - * Now find a thread we can wake up to take the signal off the queue. - * - * If the main thread wants the signal, it gets first crack. - * Probably the least surprising to the average bear. - */ - if (wants_signal(sig, p)) - t = p; - else if (!group || thread_group_empty(p)) - /* - * There is just one thread and it does not need to be woken. - * It will dequeue unblocked signals before it runs again. - */ - return; - else { - /* - * Otherwise try to find a suitable thread. - */ - t = signal->curr_target; - while (!wants_signal(sig, t)) { - t = next_thread(t); - if (t == signal->curr_target) - /* - * No thread needs to be woken. - * Any eligible threads will see - * the signal in the queue soon. - */ - return; - } - signal->curr_target = t; - } - - /* - * Found a killable thread. If the signal will be fatal, - * then start taking the whole group down immediately. - */ - if (sig_fatal(p, sig) && - !(signal->flags & (SIGNAL_UNKILLABLE | SIGNAL_GROUP_EXIT)) && - !sigismember(&t->real_blocked, sig) && - (sig == SIGKILL || !t->ptrace)) { - /* - * This signal will be fatal to the whole group. - */ - if (!sig_kernel_coredump(sig)) { - /* - * Start a group exit and wake everybody up. - * This way we don't have other threads - * running and doing things after a slower - * thread has the fatal signal pending. - */ - signal->flags = SIGNAL_GROUP_EXIT; - signal->group_exit_code = sig; - signal->group_stop_count = 0; - t = p; - do { - task_clear_jobctl_pending(t, JOBCTL_PENDING_MASK); - sigaddset(&t->pending.signal, SIGKILL); - signal_wake_up(t, 1); - } while_each_thread(p, t); - return; - } - } - - /* - * The signal is already in the shared-pending queue. - * Tell the chosen thread to wake up and dequeue it. - */ - signal_wake_up(t, sig == SIGKILL); - return; -} - -static inline int legacy_queue(struct sigpending *signals, int sig) -{ - return (sig < SIGRTMIN) && sigismember(&signals->signal, sig); -} - -#ifdef CONFIG_USER_NS -static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t) -{ - if (current_user_ns() == task_cred_xxx(t, user_ns)) - return; - - if (SI_FROMKERNEL(info)) - return; - - rcu_read_lock(); - info->si_uid = from_kuid_munged(task_cred_xxx(t, user_ns), - make_kuid(current_user_ns(), info->si_uid)); - rcu_read_unlock(); -} -#else -static inline void userns_fixup_signal_uid(struct siginfo *info, struct task_struct *t) -{ - return; -} -#endif - -static int __send_signal(int sig, struct siginfo *info, struct task_struct *t, - int group, int from_ancestor_ns) -{ - struct sigpending *pending; - struct sigqueue *q; - int override_rlimit; - int ret = 0, result; - - assert_spin_locked(&t->sighand->siglock); - - result = TRACE_SIGNAL_IGNORED; - if (!prepare_signal(sig, t, - from_ancestor_ns || (info == SEND_SIG_FORCED))) - goto ret; - - pending = group ? &t->signal->shared_pending : &t->pending; - /* - * Short-circuit ignored signals and support queuing - * exactly one non-rt signal, so that we can get more - * detailed information about the cause of the signal. - */ - result = TRACE_SIGNAL_ALREADY_PENDING; - if (legacy_queue(pending, sig)) - goto ret; - - result = TRACE_SIGNAL_DELIVERED; - /* - * fast-pathed signals for kernel-internal things like SIGSTOP - * or SIGKILL. - */ - if (info == SEND_SIG_FORCED) - goto out_set; - - /* - * Real-time signals must be queued if sent by sigqueue, or - * some other real-time mechanism. It is implementation - * defined whether kill() does so. We attempt to do so, on - * the principle of least surprise, but since kill is not - * allowed to fail with EAGAIN when low on memory we just - * make sure at least one signal gets delivered and don't - * pass on the info struct. - */ - if (sig < SIGRTMIN) - override_rlimit = (is_si_special(info) || info->si_code >= 0); - else - override_rlimit = 0; - - q = __sigqueue_alloc(sig, t, GFP_ATOMIC | __GFP_NOTRACK_FALSE_POSITIVE, - override_rlimit); - if (q) { - list_add_tail(&q->list, &pending->list); - switch ((unsigned long) info) { - case (unsigned long) SEND_SIG_NOINFO: - q->info.si_signo = sig; - q->info.si_errno = 0; - q->info.si_code = SI_USER; - q->info.si_pid = task_tgid_nr_ns(current, - task_active_pid_ns(t)); - q->info.si_uid = from_kuid_munged(current_user_ns(), current_uid()); - break; - case (unsigned long) SEND_SIG_PRIV: - q->info.si_signo = sig; - q->info.si_errno = 0; - q->info.si_code = SI_KERNEL; - q->info.si_pid = 0; - q->info.si_uid = 0; - break; - default: - copy_siginfo(&q->info, info); - if (from_ancestor_ns) - q->info.si_pid = 0; - break; - } - - userns_fixup_signal_uid(&q->info, t); - - } else if (!is_si_special(info)) { - if (sig >= SIGRTMIN && info->si_code != SI_USER) { - /* - * Queue overflow, abort. We may abort if the - * signal was rt and sent by user using something - * other than kill(). - */ - result = TRACE_SIGNAL_OVERFLOW_FAIL; - ret = -EAGAIN; - goto ret; - } else { - /* - * This is a silent loss of information. We still - * send the signal, but the *info bits are lost. - */ - result = TRACE_SIGNAL_LOSE_INFO; - } - } - -out_set: - signalfd_notify(t, sig); - sigaddset(&pending->signal, sig); - complete_signal(sig, t, group); -ret: - trace_signal_generate(sig, info, t, group, result); - return ret; -} - -static int send_signal(int sig, struct siginfo *info, struct task_struct *t, - int group) -{ - int from_ancestor_ns = 0; - -#ifdef CONFIG_PID_NS - from_ancestor_ns = si_fromuser(info) && - !task_pid_nr_ns(current, task_active_pid_ns(t)); -#endif - - return __send_signal(sig, info, t, group, from_ancestor_ns); -} - -static void print_fatal_signal(int signr) -{ - struct pt_regs *regs = signal_pt_regs(); - pr_info("potentially unexpected fatal signal %d.\n", signr); - -#ifdef CONFIG_X86_32 - pr_info("code at %08lx: ", regs->ip); - { - int i; - for (i = 0; i < 16; i++) { - unsigned char insn; - - if (get_user(insn, (unsigned char *)(regs->ip + i))) - break; - pr_cont("%02x ", insn); - } - } - pr_cont("\n"); -#endif - preempt_disable(); - show_regs(regs); - preempt_enable(); -} - -static int __init setup_print_fatal_signals(char *str) -{ - get_option (&str, &print_fatal_signals); - - return 1; -} - -__setup("print-fatal-signals=", setup_print_fatal_signals); - -int -__group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) -{ - return send_signal(sig, info, p, 1); -} - -static int -specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t) -{ - return send_signal(sig, info, t, 0); -} - -int do_send_sig_info(int sig, struct siginfo *info, struct task_struct *p, - bool group) -{ - unsigned long flags; - int ret = -ESRCH; - - if (lock_task_sighand(p, &flags)) { - ret = send_signal(sig, info, p, group); - unlock_task_sighand(p, &flags); - } - - return ret; -} - -/* - * Force a signal that the process can't ignore: if necessary - * we unblock the signal and change any SIG_IGN to SIG_DFL. - * - * Note: If we unblock the signal, we always reset it to SIG_DFL, - * since we do not want to have a signal handler that was blocked - * be invoked when user space had explicitly blocked it. - * - * We don't want to have recursive SIGSEGV's etc, for example, - * that is why we also clear SIGNAL_UNKILLABLE. - */ -int -force_sig_info(int sig, struct siginfo *info, struct task_struct *t) -{ - unsigned long int flags; - int ret, blocked, ignored; - struct k_sigaction *action; - - spin_lock_irqsave(&t->sighand->siglock, flags); - action = &t->sighand->action[sig-1]; - ignored = action->sa.sa_handler == SIG_IGN; - blocked = sigismember(&t->blocked, sig); - if (blocked || ignored) { - action->sa.sa_handler = SIG_DFL; - if (blocked) { - sigdelset(&t->blocked, sig); - recalc_sigpending_and_wake(t); - } - } - if (action->sa.sa_handler == SIG_DFL) - t->signal->flags &= ~SIGNAL_UNKILLABLE; - ret = specific_send_sig_info(sig, info, t); - spin_unlock_irqrestore(&t->sighand->siglock, flags); - - return ret; -} - -/* - * Nuke all other threads in the group. - */ -int zap_other_threads(struct task_struct *p) -{ - struct task_struct *t = p; - int count = 0; - - p->signal->group_stop_count = 0; - - while_each_thread(p, t) { - task_clear_jobctl_pending(t, JOBCTL_PENDING_MASK); - count++; - - /* Don't bother with already dead threads */ - if (t->exit_state) - continue; - sigaddset(&t->pending.signal, SIGKILL); - signal_wake_up(t, 1); - } - - return count; -} - -struct sighand_struct *__lock_task_sighand(struct task_struct *tsk, - unsigned long *flags) -{ - struct sighand_struct *sighand; - - for (;;) { - /* - * Disable interrupts early to avoid deadlocks. - * See rcu_read_unlock() comment header for details. - */ - local_irq_save(*flags); - rcu_read_lock(); - sighand = rcu_dereference(tsk->sighand); - if (unlikely(sighand == NULL)) { - rcu_read_unlock(); - local_irq_restore(*flags); - break; - } - /* - * This sighand can be already freed and even reused, but - * we rely on SLAB_DESTROY_BY_RCU and sighand_ctor() which - * initializes ->siglock: this slab can't go away, it has - * the same object type, ->siglock can't be reinitialized. - * - * We need to ensure that tsk->sighand is still the same - * after we take the lock, we can race with de_thread() or - * __exit_signal(). In the latter case the next iteration - * must see ->sighand == NULL. - */ - spin_lock(&sighand->siglock); - if (likely(sighand == tsk->sighand)) { - rcu_read_unlock(); - break; - } - spin_unlock(&sighand->siglock); - rcu_read_unlock(); - local_irq_restore(*flags); - } - - return sighand; -} - -/* - * send signal info to all the members of a group - */ -int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) -{ - int ret; - - rcu_read_lock(); - ret = check_kill_permission(sig, info, p); - rcu_read_unlock(); - - if (!ret && sig) - ret = do_send_sig_info(sig, info, p, true); - - return ret; -} - -/* - * __kill_pgrp_info() sends a signal to a process group: this is what the tty - * control characters do (^C, ^Z etc) - * - the caller must hold at least a readlock on tasklist_lock - */ -int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp) -{ - struct task_struct *p = NULL; - int retval, success; - - success = 0; - retval = -ESRCH; - do_each_pid_task(pgrp, PIDTYPE_PGID, p) { - int err = group_send_sig_info(sig, info, p); - success |= !err; - retval = err; - } while_each_pid_task(pgrp, PIDTYPE_PGID, p); - return success ? 0 : retval; -} - -int kill_pid_info(int sig, struct siginfo *info, struct pid *pid) -{ - int error = -ESRCH; - struct task_struct *p; - - for (;;) { - rcu_read_lock(); - p = pid_task(pid, PIDTYPE_PID); - if (p) - error = group_send_sig_info(sig, info, p); - rcu_read_unlock(); - if (likely(!p || error != -ESRCH)) - return error; - - /* - * The task was unhashed in between, try again. If it - * is dead, pid_task() will return NULL, if we race with - * de_thread() it will find the new leader. - */ - } -} - -int kill_proc_info(int sig, struct siginfo *info, pid_t pid) -{ - int error; - rcu_read_lock(); - error = kill_pid_info(sig, info, find_vpid(pid)); - rcu_read_unlock(); - return error; -} - -static int kill_as_cred_perm(const struct cred *cred, - struct task_struct *target) -{ - const struct cred *pcred = __task_cred(target); - if (!uid_eq(cred->euid, pcred->suid) && !uid_eq(cred->euid, pcred->uid) && - !uid_eq(cred->uid, pcred->suid) && !uid_eq(cred->uid, pcred->uid)) - return 0; - return 1; -} - -/* like kill_pid_info(), but doesn't use uid/euid of "current" */ -int kill_pid_info_as_cred(int sig, struct siginfo *info, struct pid *pid, - const struct cred *cred, u32 secid) -{ - int ret = -EINVAL; - struct task_struct *p; - unsigned long flags; - - if (!valid_signal(sig)) - return ret; - - rcu_read_lock(); - p = pid_task(pid, PIDTYPE_PID); - if (!p) { - ret = -ESRCH; - goto out_unlock; - } - if (si_fromuser(info) && !kill_as_cred_perm(cred, p)) { - ret = -EPERM; - goto out_unlock; - } - ret = security_task_kill(p, info, sig, secid); - if (ret) - goto out_unlock; - - if (sig) { - if (lock_task_sighand(p, &flags)) { - ret = __send_signal(sig, info, p, 1, 0); - unlock_task_sighand(p, &flags); - } else - ret = -ESRCH; - } -out_unlock: - rcu_read_unlock(); - return ret; -} -EXPORT_SYMBOL_GPL(kill_pid_info_as_cred); - -/* - * kill_something_info() interprets pid in interesting ways just like kill(2). - * - * POSIX specifies that kill(-1,sig) is unspecified, but what we have - * is probably wrong. Should make it like BSD or SYSV. - */ - -static int kill_something_info(int sig, struct siginfo *info, pid_t pid) -{ - int ret; - - if (pid > 0) { - rcu_read_lock(); - ret = kill_pid_info(sig, info, find_vpid(pid)); - rcu_read_unlock(); - return ret; - } - - read_lock(&tasklist_lock); - if (pid != -1) { - ret = __kill_pgrp_info(sig, info, - pid ? find_vpid(-pid) : task_pgrp(current)); - } else { - int retval = 0, count = 0; - struct task_struct * p; - - for_each_process(p) { - if (task_pid_vnr(p) > 1 && - !same_thread_group(p, current)) { - int err = group_send_sig_info(sig, info, p); - ++count; - if (err != -EPERM) - retval = err; - } - } - ret = count ? retval : -ESRCH; - } - read_unlock(&tasklist_lock); - - return ret; -} - -/* - * These are for backward compatibility with the rest of the kernel source. - */ - -int send_sig_info(int sig, struct siginfo *info, struct task_struct *p) -{ - /* - * Make sure legacy kernel users don't send in bad values - * (normal paths check this in check_kill_permission). - */ - if (!valid_signal(sig)) - return -EINVAL; - - return do_send_sig_info(sig, info, p, false); -} - -#define __si_special(priv) \ - ((priv) ? SEND_SIG_PRIV : SEND_SIG_NOINFO) - -int -send_sig(int sig, struct task_struct *p, int priv) -{ - return send_sig_info(sig, __si_special(priv), p); -} - -void -force_sig(int sig, struct task_struct *p) -{ - force_sig_info(sig, SEND_SIG_PRIV, p); -} - -/* - * When things go south during signal handling, we - * will force a SIGSEGV. And if the signal that caused - * the problem was already a SIGSEGV, we'll want to - * make sure we don't even try to deliver the signal.. - */ -int -force_sigsegv(int sig, struct task_struct *p) -{ - if (sig == SIGSEGV) { - unsigned long flags; - spin_lock_irqsave(&p->sighand->siglock, flags); - p->sighand->action[sig - 1].sa.sa_handler = SIG_DFL; - spin_unlock_irqrestore(&p->sighand->siglock, flags); - } - force_sig(SIGSEGV, p); - return 0; -} - -int kill_pgrp(struct pid *pid, int sig, int priv) -{ - int ret; - - read_lock(&tasklist_lock); - ret = __kill_pgrp_info(sig, __si_special(priv), pid); - read_unlock(&tasklist_lock); - - return ret; -} -EXPORT_SYMBOL(kill_pgrp); - -int kill_pid(struct pid *pid, int sig, int priv) -{ - return kill_pid_info(sig, __si_special(priv), pid); -} -EXPORT_SYMBOL(kill_pid); - -/* - * These functions support sending signals using preallocated sigqueue - * structures. This is needed "because realtime applications cannot - * afford to lose notifications of asynchronous events, like timer - * expirations or I/O completions". In the case of POSIX Timers - * we allocate the sigqueue structure from the timer_create. If this - * allocation fails we are able to report the failure to the application - * with an EAGAIN error. - */ -struct sigqueue *sigqueue_alloc(void) -{ - struct sigqueue *q = __sigqueue_alloc(-1, current, GFP_KERNEL, 0); - - if (q) - q->flags |= SIGQUEUE_PREALLOC; - - return q; -} - -void sigqueue_free(struct sigqueue *q) -{ - unsigned long flags; - spinlock_t *lock = ¤t->sighand->siglock; - - BUG_ON(!(q->flags & SIGQUEUE_PREALLOC)); - /* - * We must hold ->siglock while testing q->list - * to serialize with collect_signal() or with - * __exit_signal()->flush_sigqueue(). - */ - spin_lock_irqsave(lock, flags); - q->flags &= ~SIGQUEUE_PREALLOC; - /* - * If it is queued it will be freed when dequeued, - * like the "regular" sigqueue. - */ - if (!list_empty(&q->list)) - q = NULL; - spin_unlock_irqrestore(lock, flags); - - if (q) - __sigqueue_free(q); -} - -int send_sigqueue(struct sigqueue *q, struct task_struct *t, int group) -{ - int sig = q->info.si_signo; - struct sigpending *pending; - unsigned long flags; - int ret, result; - - BUG_ON(!(q->flags & SIGQUEUE_PREALLOC)); - - ret = -1; - if (!likely(lock_task_sighand(t, &flags))) - goto ret; - - ret = 1; /* the signal is ignored */ - result = TRACE_SIGNAL_IGNORED; - if (!prepare_signal(sig, t, false)) - goto out; - - ret = 0; - if (unlikely(!list_empty(&q->list))) { - /* - * If an SI_TIMER entry is already queue just increment - * the overrun count. - */ - BUG_ON(q->info.si_code != SI_TIMER); - q->info.si_overrun++; - result = TRACE_SIGNAL_ALREADY_PENDING; - goto out; - } - q->info.si_overrun = 0; - - signalfd_notify(t, sig); - pending = group ? &t->signal->shared_pending : &t->pending; - list_add_tail(&q->list, &pending->list); - sigaddset(&pending->signal, sig); - complete_signal(sig, t, group); - result = TRACE_SIGNAL_DELIVERED; -out: - trace_signal_generate(sig, &q->info, t, group, result); - unlock_task_sighand(t, &flags); -ret: - return ret; -} - -/* - * Let a parent know about the death of a child. - * For a stopped/continued status change, use do_notify_parent_cldstop instead. - * - * Returns true if our parent ignored us and so we've switched to - * self-reaping. - */ -bool do_notify_parent(struct task_struct *tsk, int sig) -{ - struct siginfo info; - unsigned long flags; - struct sighand_struct *psig; - bool autoreap = false; - cputime_t utime, stime; - - BUG_ON(sig == -1); - - /* do_notify_parent_cldstop should have been called instead. */ - BUG_ON(task_is_stopped_or_traced(tsk)); - - BUG_ON(!tsk->ptrace && - (tsk->group_leader != tsk || !thread_group_empty(tsk))); - - if (sig != SIGCHLD) { - /* - * This is only possible if parent == real_parent. - * Check if it has changed security domain. - */ - if (tsk->parent_exec_id != tsk->parent->self_exec_id) - sig = SIGCHLD; - } - - info.si_signo = sig; - info.si_errno = 0; - /* - * We are under tasklist_lock here so our parent is tied to - * us and cannot change. - * - * task_active_pid_ns will always return the same pid namespace - * until a task passes through release_task. - * - * write_lock() currently calls preempt_disable() which is the - * same as rcu_read_lock(), but according to Oleg, this is not - * correct to rely on this - */ - rcu_read_lock(); - info.si_pid = task_pid_nr_ns(tsk, task_active_pid_ns(tsk->parent)); - info.si_uid = from_kuid_munged(task_cred_xxx(tsk->parent, user_ns), - task_uid(tsk)); - rcu_read_unlock(); - - task_cputime(tsk, &utime, &stime); - info.si_utime = cputime_to_clock_t(utime + tsk->signal->utime); - info.si_stime = cputime_to_clock_t(stime + tsk->signal->stime); - - info.si_status = tsk->exit_code & 0x7f; - if (tsk->exit_code & 0x80) - info.si_code = CLD_DUMPED; - else if (tsk->exit_code & 0x7f) - info.si_code = CLD_KILLED; - else { - info.si_code = CLD_EXITED; - info.si_status = tsk->exit_code >> 8; - } - - psig = tsk->parent->sighand; - spin_lock_irqsave(&psig->siglock, flags); - if (!tsk->ptrace && sig == SIGCHLD && - (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN || - (psig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDWAIT))) { - /* - * We are exiting and our parent doesn't care. POSIX.1 - * defines special semantics for setting SIGCHLD to SIG_IGN - * or setting the SA_NOCLDWAIT flag: we should be reaped - * automatically and not left for our parent's wait4 call. - * Rather than having the parent do it as a magic kind of - * signal handler, we just set this to tell do_exit that we - * can be cleaned up without becoming a zombie. Note that - * we still call __wake_up_parent in this case, because a - * blocked sys_wait4 might now return -ECHILD. - * - * Whether we send SIGCHLD or not for SA_NOCLDWAIT - * is implementation-defined: we do (if you don't want - * it, just use SIG_IGN instead). - */ - autoreap = true; - if (psig->action[SIGCHLD-1].sa.sa_handler == SIG_IGN) - sig = 0; - } - if (valid_signal(sig) && sig) - __group_send_sig_info(sig, &info, tsk->parent); - __wake_up_parent(tsk, tsk->parent); - spin_unlock_irqrestore(&psig->siglock, flags); - - return autoreap; -} - -/** - * do_notify_parent_cldstop - notify parent of stopped/continued state change - * @tsk: task reporting the state change - * @for_ptracer: the notification is for ptracer - * @why: CLD_{CONTINUED|STOPPED|TRAPPED} to report - * - * Notify @tsk's parent that the stopped/continued state has changed. If - * @for_ptracer is %false, @tsk's group leader notifies to its real parent. - * If %true, @tsk reports to @tsk->parent which should be the ptracer. - * - * CONTEXT: - * Must be called with tasklist_lock at least read locked. - */ -static void do_notify_parent_cldstop(struct task_struct *tsk, - bool for_ptracer, int why) -{ - struct siginfo info; - unsigned long flags; - struct task_struct *parent; - struct sighand_struct *sighand; - cputime_t utime, stime; - - if (for_ptracer) { - parent = tsk->parent; - } else { - tsk = tsk->group_leader; - parent = tsk->real_parent; - } - - info.si_signo = SIGCHLD; - info.si_errno = 0; - /* - * see comment in do_notify_parent() about the following 4 lines - */ - rcu_read_lock(); - info.si_pid = task_pid_nr_ns(tsk, task_active_pid_ns(parent)); - info.si_uid = from_kuid_munged(task_cred_xxx(parent, user_ns), task_uid(tsk)); - rcu_read_unlock(); - - task_cputime(tsk, &utime, &stime); - info.si_utime = cputime_to_clock_t(utime); - info.si_stime = cputime_to_clock_t(stime); - - info.si_code = why; - switch (why) { - case CLD_CONTINUED: - info.si_status = SIGCONT; - break; - case CLD_STOPPED: - info.si_status = tsk->signal->group_exit_code & 0x7f; - break; - case CLD_TRAPPED: - info.si_status = tsk->exit_code & 0x7f; - break; - default: - BUG(); - } - - sighand = parent->sighand; - spin_lock_irqsave(&sighand->siglock, flags); - if (sighand->action[SIGCHLD-1].sa.sa_handler != SIG_IGN && - !(sighand->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) - __group_send_sig_info(SIGCHLD, &info, parent); - /* - * Even if SIGCHLD is not generated, we must wake up wait4 calls. - */ - __wake_up_parent(tsk, parent); - spin_unlock_irqrestore(&sighand->siglock, flags); -} - -static inline int may_ptrace_stop(void) -{ - if (!likely(current->ptrace)) - return 0; - /* - * Are we in the middle of do_coredump? - * If so and our tracer is also part of the coredump stopping - * is a deadlock situation, and pointless because our tracer - * is dead so don't allow us to stop. - * If SIGKILL was already sent before the caller unlocked - * ->siglock we must see ->core_state != NULL. Otherwise it - * is safe to enter schedule(). - * - * This is almost outdated, a task with the pending SIGKILL can't - * block in TASK_TRACED. But PTRACE_EVENT_EXIT can be reported - * after SIGKILL was already dequeued. - */ - if (unlikely(current->mm->core_state) && - unlikely(current->mm == current->parent->mm)) - return 0; - - return 1; -} - -/* - * Return non-zero if there is a SIGKILL that should be waking us up. - * Called with the siglock held. - */ -static int sigkill_pending(struct task_struct *tsk) -{ - return sigismember(&tsk->pending.signal, SIGKILL) || - sigismember(&tsk->signal->shared_pending.signal, SIGKILL); -} - -/* - * This must be called with current->sighand->siglock held. - * - * This should be the path for all ptrace stops. - * We always set current->last_siginfo while stopped here. - * That makes it a way to test a stopped process for - * being ptrace-stopped vs being job-control-stopped. - * - * If we actually decide not to stop at all because the tracer - * is gone, we keep current->exit_code unless clear_code. - */ -static void ptrace_stop(int exit_code, int why, int clear_code, siginfo_t *info) - __releases(¤t->sighand->siglock) - __acquires(¤t->sighand->siglock) -{ - bool gstop_done = false; - - if (arch_ptrace_stop_needed(exit_code, info)) { - /* - * The arch code has something special to do before a - * ptrace stop. This is allowed to block, e.g. for faults - * on user stack pages. We can't keep the siglock while - * calling arch_ptrace_stop, so we must release it now. - * To preserve proper semantics, we must do this before - * any signal bookkeeping like checking group_stop_count. - * Meanwhile, a SIGKILL could come in before we retake the - * siglock. That must prevent us from sleeping in TASK_TRACED. - * So after regaining the lock, we must check for SIGKILL. - */ - spin_unlock_irq(¤t->sighand->siglock); - arch_ptrace_stop(exit_code, info); - spin_lock_irq(¤t->sighand->siglock); - if (sigkill_pending(current)) - return; - } - - /* - * We're committing to trapping. TRACED should be visible before - * TRAPPING is cleared; otherwise, the tracer might fail do_wait(). - * Also, transition to TRACED and updates to ->jobctl should be - * atomic with respect to siglock and should be done after the arch - * hook as siglock is released and regrabbed across it. - */ - set_current_state(TASK_TRACED); - - current->last_siginfo = info; - current->exit_code = exit_code; - - /* - * If @why is CLD_STOPPED, we're trapping to participate in a group - * stop. Do the bookkeeping. Note that if SIGCONT was delievered - * across siglock relocks since INTERRUPT was scheduled, PENDING - * could be clear now. We act as if SIGCONT is received after - * TASK_TRACED is entered - ignore it. - */ - if (why == CLD_STOPPED && (current->jobctl & JOBCTL_STOP_PENDING)) - gstop_done = task_participate_group_stop(current); - - /* any trap clears pending STOP trap, STOP trap clears NOTIFY */ - task_clear_jobctl_pending(current, JOBCTL_TRAP_STOP); - if (info && info->si_code >> 8 == PTRACE_EVENT_STOP) - task_clear_jobctl_pending(current, JOBCTL_TRAP_NOTIFY); - - /* entering a trap, clear TRAPPING */ - task_clear_jobctl_trapping(current); - - spin_unlock_irq(¤t->sighand->siglock); - read_lock(&tasklist_lock); - if (may_ptrace_stop()) { - /* - * Notify parents of the stop. - * - * While ptraced, there are two parents - the ptracer and - * the real_parent of the group_leader. The ptracer should - * know about every stop while the real parent is only - * interested in the completion of group stop. The states - * for the two don't interact with each other. Notify - * separately unless they're gonna be duplicates. - */ - do_notify_parent_cldstop(current, true, why); - if (gstop_done && ptrace_reparented(current)) - do_notify_parent_cldstop(current, false, why); - - /* - * Don't want to allow preemption here, because - * sys_ptrace() needs this task to be inactive. - * - * XXX: implement read_unlock_no_resched(). - */ - preempt_disable(); - read_unlock(&tasklist_lock); - preempt_enable_no_resched(); - freezable_schedule(); - } else { - /* - * By the time we got the lock, our tracer went away. - * Don't drop the lock yet, another tracer may come. - * - * If @gstop_done, the ptracer went away between group stop - * completion and here. During detach, it would have set - * JOBCTL_STOP_PENDING on us and we'll re-enter - * TASK_STOPPED in do_signal_stop() on return, so notifying - * the real parent of the group stop completion is enough. - */ - if (gstop_done) - do_notify_parent_cldstop(current, false, why); - - /* tasklist protects us from ptrace_freeze_traced() */ - __set_current_state(TASK_RUNNING); - if (clear_code) - current->exit_code = 0; - read_unlock(&tasklist_lock); - } - - /* - * We are back. Now reacquire the siglock before touching - * last_siginfo, so that we are sure to have synchronized with - * any signal-sending on another CPU that wants to examine it. - */ - spin_lock_irq(¤t->sighand->siglock); - current->last_siginfo = NULL; - - /* LISTENING can be set only during STOP traps, clear it */ - current->jobctl &= ~JOBCTL_LISTENING; - - /* - * Queued signals ignored us while we were stopped for tracing. - * So check for any that we should take before resuming user mode. - * This sets TIF_SIGPENDING, but never clears it. - */ - recalc_sigpending_tsk(current); -} - -static void ptrace_do_notify(int signr, int exit_code, int why) -{ - siginfo_t info; - - memset(&info, 0, sizeof info); - info.si_signo = signr; - info.si_code = exit_code; - info.si_pid = task_pid_vnr(current); - info.si_uid = from_kuid_munged(current_user_ns(), current_uid()); - - /* Let the debugger run. */ - ptrace_stop(exit_code, why, 1, &info); -} - -void ptrace_notify(int exit_code) -{ - BUG_ON((exit_code & (0x7f | ~0xffff)) != SIGTRAP); - if (unlikely(current->task_works)) - task_work_run(); - - spin_lock_irq(¤t->sighand->siglock); - ptrace_do_notify(SIGTRAP, exit_code, CLD_TRAPPED); - spin_unlock_irq(¤t->sighand->siglock); -} - -/** - * do_signal_stop - handle group stop for SIGSTOP and other stop signals - * @signr: signr causing group stop if initiating - * - * If %JOBCTL_STOP_PENDING is not set yet, initiate group stop with @signr - * and participate in it. If already set, participate in the existing - * group stop. If participated in a group stop (and thus slept), %true is - * returned with siglock released. - * - * If ptraced, this function doesn't handle stop itself. Instead, - * %JOBCTL_TRAP_STOP is scheduled and %false is returned with siglock - * untouched. The caller must ensure that INTERRUPT trap handling takes - * places afterwards. - * - * CONTEXT: - * Must be called with @current->sighand->siglock held, which is released - * on %true return. - * - * RETURNS: - * %false if group stop is already cancelled or ptrace trap is scheduled. - * %true if participated in group stop. - */ -static bool do_signal_stop(int signr) - __releases(¤t->sighand->siglock) -{ - struct signal_struct *sig = current->signal; - - if (!(current->jobctl & JOBCTL_STOP_PENDING)) { - unsigned long gstop = JOBCTL_STOP_PENDING | JOBCTL_STOP_CONSUME; - struct task_struct *t; - - /* signr will be recorded in task->jobctl for retries */ - WARN_ON_ONCE(signr & ~JOBCTL_STOP_SIGMASK); - - if (!likely(current->jobctl & JOBCTL_STOP_DEQUEUED) || - unlikely(signal_group_exit(sig))) - return false; - /* - * There is no group stop already in progress. We must - * initiate one now. - * - * While ptraced, a task may be resumed while group stop is - * still in effect and then receive a stop signal and - * initiate another group stop. This deviates from the - * usual behavior as two consecutive stop signals can't - * cause two group stops when !ptraced. That is why we - * also check !task_is_stopped(t) below. - * - * The condition can be distinguished by testing whether - * SIGNAL_STOP_STOPPED is already set. Don't generate - * group_exit_code in such case. - * - * This is not necessary for SIGNAL_STOP_CONTINUED because - * an intervening stop signal is required to cause two - * continued events regardless of ptrace. - */ - if (!(sig->flags & SIGNAL_STOP_STOPPED)) - sig->group_exit_code = signr; - - sig->group_stop_count = 0; - - if (task_set_jobctl_pending(current, signr | gstop)) - sig->group_stop_count++; - - t = current; - while_each_thread(current, t) { - /* - * Setting state to TASK_STOPPED for a group - * stop is always done with the siglock held, - * so this check has no races. - */ - if (!task_is_stopped(t) && - task_set_jobctl_pending(t, signr | gstop)) { - sig->group_stop_count++; - if (likely(!(t->ptrace & PT_SEIZED))) - signal_wake_up(t, 0); - else - ptrace_trap_notify(t); - } - } - } - - if (likely(!current->ptrace)) { - int notify = 0; - - /* - * If there are no other threads in the group, or if there - * is a group stop in progress and we are the last to stop, - * report to the parent. - */ - if (task_participate_group_stop(current)) - notify = CLD_STOPPED; - - __set_current_state(TASK_STOPPED); - spin_unlock_irq(¤t->sighand->siglock); - - /* - * Notify the parent of the group stop completion. Because - * we're not holding either the siglock or tasklist_lock - * here, ptracer may attach inbetween; however, this is for - * group stop and should always be delivered to the real - * parent of the group leader. The new ptracer will get - * its notification when this task transitions into - * TASK_TRACED. - */ - if (notify) { - read_lock(&tasklist_lock); - do_notify_parent_cldstop(current, false, notify); - read_unlock(&tasklist_lock); - } - - /* Now we don't run again until woken by SIGCONT or SIGKILL */ - freezable_schedule(); - return true; - } else { - /* - * While ptraced, group stop is handled by STOP trap. - * Schedule it and let the caller deal with it. - */ - task_set_jobctl_pending(current, JOBCTL_TRAP_STOP); - return false; - } -} - -/** - * do_jobctl_trap - take care of ptrace jobctl traps - * - * When PT_SEIZED, it's used for both group stop and explicit - * SEIZE/INTERRUPT traps. Both generate PTRACE_EVENT_STOP trap with - * accompanying siginfo. If stopped, lower eight bits of exit_code contain - * the stop signal; otherwise, %SIGTRAP. - * - * When !PT_SEIZED, it's used only for group stop trap with stop signal - * number as exit_code and no siginfo. - * - * CONTEXT: - * Must be called with @current->sighand->siglock held, which may be - * released and re-acquired before returning with intervening sleep. - */ -static void do_jobctl_trap(void) -{ - struct signal_struct *signal = current->signal; - int signr = current->jobctl & JOBCTL_STOP_SIGMASK; - - if (current->ptrace & PT_SEIZED) { - if (!signal->group_stop_count && - !(signal->flags & SIGNAL_STOP_STOPPED)) - signr = SIGTRAP; - WARN_ON_ONCE(!signr); - ptrace_do_notify(signr, signr | (PTRACE_EVENT_STOP << 8), - CLD_STOPPED); - } else { - WARN_ON_ONCE(!signr); - ptrace_stop(signr, CLD_STOPPED, 0, NULL); - current->exit_code = 0; - } -} - -static int ptrace_signal(int signr, siginfo_t *info) -{ - ptrace_signal_deliver(); - /* - * We do not check sig_kernel_stop(signr) but set this marker - * unconditionally because we do not know whether debugger will - * change signr. This flag has no meaning unless we are going - * to stop after return from ptrace_stop(). In this case it will - * be checked in do_signal_stop(), we should only stop if it was - * not cleared by SIGCONT while we were sleeping. See also the - * comment in dequeue_signal(). - */ - current->jobctl |= JOBCTL_STOP_DEQUEUED; - ptrace_stop(signr, CLD_TRAPPED, 0, info); - - /* We're back. Did the debugger cancel the sig? */ - signr = current->exit_code; - if (signr == 0) - return signr; - - current->exit_code = 0; - - /* - * Update the siginfo structure if the signal has - * changed. If the debugger wanted something - * specific in the siginfo structure then it should - * have updated *info via PTRACE_SETSIGINFO. - */ - if (signr != info->si_signo) { - info->si_signo = signr; - info->si_errno = 0; - info->si_code = SI_USER; - rcu_read_lock(); - info->si_pid = task_pid_vnr(current->parent); - info->si_uid = from_kuid_munged(current_user_ns(), - task_uid(current->parent)); - rcu_read_unlock(); - } - - /* If the (new) signal is now blocked, requeue it. */ - if (sigismember(¤t->blocked, signr)) { - specific_send_sig_info(signr, info, current); - signr = 0; - } - - return signr; -} - -int get_signal(struct ksignal *ksig) -{ - struct sighand_struct *sighand = current->sighand; - struct signal_struct *signal = current->signal; - int signr; - - if (unlikely(current->task_works)) - task_work_run(); - - if (unlikely(uprobe_deny_signal())) - return 0; - - /* - * Do this once, we can't return to user-mode if freezing() == T. - * do_signal_stop() and ptrace_stop() do freezable_schedule() and - * thus do not need another check after return. - */ - try_to_freeze(); - -relock: - spin_lock_irq(&sighand->siglock); - /* - * Every stopped thread goes here after wakeup. Check to see if - * we should notify the parent, prepare_signal(SIGCONT) encodes - * the CLD_ si_code into SIGNAL_CLD_MASK bits. - */ - if (unlikely(signal->flags & SIGNAL_CLD_MASK)) { - int why; - - if (signal->flags & SIGNAL_CLD_CONTINUED) - why = CLD_CONTINUED; - else - why = CLD_STOPPED; - - signal->flags &= ~SIGNAL_CLD_MASK; - - spin_unlock_irq(&sighand->siglock); - - /* - * Notify the parent that we're continuing. This event is - * always per-process and doesn't make whole lot of sense - * for ptracers, who shouldn't consume the state via - * wait(2) either, but, for backward compatibility, notify - * the ptracer of the group leader too unless it's gonna be - * a duplicate. - */ - read_lock(&tasklist_lock); - do_notify_parent_cldstop(current, false, why); - - if (ptrace_reparented(current->group_leader)) - do_notify_parent_cldstop(current->group_leader, - true, why); - read_unlock(&tasklist_lock); - - goto relock; - } - - for (;;) { - struct k_sigaction *ka; - - if (unlikely(current->jobctl & JOBCTL_STOP_PENDING) && - do_signal_stop(0)) - goto relock; - - if (unlikely(current->jobctl & JOBCTL_TRAP_MASK)) { - do_jobctl_trap(); - spin_unlock_irq(&sighand->siglock); - goto relock; - } - - signr = dequeue_signal(current, ¤t->blocked, &ksig->info); - - if (!signr) - break; /* will return 0 */ - - if (unlikely(current->ptrace) && signr != SIGKILL) { - signr = ptrace_signal(signr, &ksig->info); - if (!signr) - continue; - } - - ka = &sighand->action[signr-1]; - - /* Trace actually delivered signals. */ - trace_signal_deliver(signr, &ksig->info, ka); - - if (ka->sa.sa_handler == SIG_IGN) /* Do nothing. */ - continue; - if (ka->sa.sa_handler != SIG_DFL) { - /* Run the handler. */ - ksig->ka = *ka; - - if (ka->sa.sa_flags & SA_ONESHOT) - ka->sa.sa_handler = SIG_DFL; - - break; /* will return non-zero "signr" value */ - } - - /* - * Now we are doing the default action for this signal. - */ - if (sig_kernel_ignore(signr)) /* Default is nothing. */ - continue; - - /* - * Global init gets no signals it doesn't want. - * Container-init gets no signals it doesn't want from same - * container. - * - * Note that if global/container-init sees a sig_kernel_only() - * signal here, the signal must have been generated internally - * or must have come from an ancestor namespace. In either - * case, the signal cannot be dropped. - */ - if (unlikely(signal->flags & SIGNAL_UNKILLABLE) && - !sig_kernel_only(signr)) - continue; - - if (sig_kernel_stop(signr)) { - /* - * The default action is to stop all threads in - * the thread group. The job control signals - * do nothing in an orphaned pgrp, but SIGSTOP - * always works. Note that siglock needs to be - * dropped during the call to is_orphaned_pgrp() - * because of lock ordering with tasklist_lock. - * This allows an intervening SIGCONT to be posted. - * We need to check for that and bail out if necessary. - */ - if (signr != SIGSTOP) { - spin_unlock_irq(&sighand->siglock); - - /* signals can be posted during this window */ - - if (is_current_pgrp_orphaned()) - goto relock; - - spin_lock_irq(&sighand->siglock); - } - - if (likely(do_signal_stop(ksig->info.si_signo))) { - /* It released the siglock. */ - goto relock; - } - - /* - * We didn't actually stop, due to a race - * with SIGCONT or something like that. - */ - continue; - } - - spin_unlock_irq(&sighand->siglock); - - /* - * Anything else is fatal, maybe with a core dump. - */ - current->flags |= PF_SIGNALED; - - if (sig_kernel_coredump(signr)) { - if (print_fatal_signals) - print_fatal_signal(ksig->info.si_signo); - proc_coredump_connector(current); - /* - * If it was able to dump core, this kills all - * other threads in the group and synchronizes with - * their demise. If we lost the race with another - * thread getting here, it set group_exit_code - * first and our do_group_exit call below will use - * that value and ignore the one we pass it. - */ - do_coredump(&ksig->info); - } - - /* - * Death signals, no core dump. - */ - do_group_exit(ksig->info.si_signo); - /* NOTREACHED */ - } - spin_unlock_irq(&sighand->siglock); - - ksig->sig = signr; - return ksig->sig > 0; -} - -/** - * signal_delivered - - * @ksig: kernel signal struct - * @stepping: nonzero if debugger single-step or block-step in use - * - * This function should be called when a signal has successfully been - * delivered. It updates the blocked signals accordingly (@ksig->ka.sa.sa_mask - * is always blocked, and the signal itself is blocked unless %SA_NODEFER - * is set in @ksig->ka.sa.sa_flags. Tracing is notified. - */ -static void signal_delivered(struct ksignal *ksig, int stepping) -{ - sigset_t blocked; - - /* A signal was successfully delivered, and the - saved sigmask was stored on the signal frame, - and will be restored by sigreturn. So we can - simply clear the restore sigmask flag. */ - clear_restore_sigmask(); - - sigorsets(&blocked, ¤t->blocked, &ksig->ka.sa.sa_mask); - if (!(ksig->ka.sa.sa_flags & SA_NODEFER)) - sigaddset(&blocked, ksig->sig); - set_current_blocked(&blocked); - tracehook_signal_handler(stepping); -} - -void signal_setup_done(int failed, struct ksignal *ksig, int stepping) -{ - if (failed) - force_sigsegv(ksig->sig, current); - else - signal_delivered(ksig, stepping); -} - -/* - * It could be that complete_signal() picked us to notify about the - * group-wide signal. Other threads should be notified now to take - * the shared signals in @which since we will not. - */ -static void retarget_shared_pending(struct task_struct *tsk, sigset_t *which) -{ - sigset_t retarget; - struct task_struct *t; - - sigandsets(&retarget, &tsk->signal->shared_pending.signal, which); - if (sigisemptyset(&retarget)) - return; - - t = tsk; - while_each_thread(tsk, t) { - if (t->flags & PF_EXITING) - continue; - - if (!has_pending_signals(&retarget, &t->blocked)) - continue; - /* Remove the signals this thread can handle. */ - sigandsets(&retarget, &retarget, &t->blocked); - - if (!signal_pending(t)) - signal_wake_up(t, 0); - - if (sigisemptyset(&retarget)) - break; - } -} - -void exit_signals(struct task_struct *tsk) -{ - int group_stop = 0; - sigset_t unblocked; - - /* - * @tsk is about to have PF_EXITING set - lock out users which - * expect stable threadgroup. - */ - threadgroup_change_begin(tsk); - - if (thread_group_empty(tsk) || signal_group_exit(tsk->signal)) { - tsk->flags |= PF_EXITING; - threadgroup_change_end(tsk); - return; - } - - spin_lock_irq(&tsk->sighand->siglock); - /* - * From now this task is not visible for group-wide signals, - * see wants_signal(), do_signal_stop(). - */ - tsk->flags |= PF_EXITING; - - threadgroup_change_end(tsk); - - if (!signal_pending(tsk)) - goto out; - - unblocked = tsk->blocked; - signotset(&unblocked); - retarget_shared_pending(tsk, &unblocked); - - if (unlikely(tsk->jobctl & JOBCTL_STOP_PENDING) && - task_participate_group_stop(tsk)) - group_stop = CLD_STOPPED; -out: - spin_unlock_irq(&tsk->sighand->siglock); - - /* - * If group stop has completed, deliver the notification. This - * should always go to the real parent of the group leader. - */ - if (unlikely(group_stop)) { - read_lock(&tasklist_lock); - do_notify_parent_cldstop(tsk, false, group_stop); - read_unlock(&tasklist_lock); - } -} - -EXPORT_SYMBOL(recalc_sigpending); -EXPORT_SYMBOL_GPL(dequeue_signal); -EXPORT_SYMBOL(flush_signals); -EXPORT_SYMBOL(force_sig); -EXPORT_SYMBOL(send_sig); -EXPORT_SYMBOL(send_sig_info); -EXPORT_SYMBOL(sigprocmask); - -/* - * System call entry points. - */ - -/** - * sys_restart_syscall - restart a system call - */ -SYSCALL_DEFINE0(restart_syscall) -{ - struct restart_block *restart = ¤t->restart_block; - return restart->fn(restart); -} - -long do_no_restart_syscall(struct restart_block *param) -{ - return -EINTR; -} - -static void __set_task_blocked(struct task_struct *tsk, const sigset_t *newset) -{ - if (signal_pending(tsk) && !thread_group_empty(tsk)) { - sigset_t newblocked; - /* A set of now blocked but previously unblocked signals. */ - sigandnsets(&newblocked, newset, ¤t->blocked); - retarget_shared_pending(tsk, &newblocked); - } - tsk->blocked = *newset; - recalc_sigpending(); -} - -/** - * set_current_blocked - change current->blocked mask - * @newset: new mask - * - * It is wrong to change ->blocked directly, this helper should be used - * to ensure the process can't miss a shared signal we are going to block. - */ -void set_current_blocked(sigset_t *newset) -{ - sigdelsetmask(newset, sigmask(SIGKILL) | sigmask(SIGSTOP)); - __set_current_blocked(newset); -} - -void __set_current_blocked(const sigset_t *newset) -{ - struct task_struct *tsk = current; - - spin_lock_irq(&tsk->sighand->siglock); - __set_task_blocked(tsk, newset); - spin_unlock_irq(&tsk->sighand->siglock); -} - -/* - * This is also useful for kernel threads that want to temporarily - * (or permanently) block certain signals. - * - * NOTE! Unlike the user-mode sys_sigprocmask(), the kernel - * interface happily blocks "unblockable" signals like SIGKILL - * and friends. - */ -int sigprocmask(int how, sigset_t *set, sigset_t *oldset) -{ - struct task_struct *tsk = current; - sigset_t newset; - - /* Lockless, only current can change ->blocked, never from irq */ - if (oldset) - *oldset = tsk->blocked; - - switch (how) { - case SIG_BLOCK: - sigorsets(&newset, &tsk->blocked, set); - break; - case SIG_UNBLOCK: - sigandnsets(&newset, &tsk->blocked, set); - break; - case SIG_SETMASK: - newset = *set; - break; - default: - return -EINVAL; - } - - __set_current_blocked(&newset); - return 0; -} - -/** - * sys_rt_sigprocmask - change the list of currently blocked signals - * @how: whether to add, remove, or set signals - * @nset: stores pending signals - * @oset: previous value of signal mask if non-null - * @sigsetsize: size of sigset_t type - */ -SYSCALL_DEFINE4(rt_sigprocmask, int, how, sigset_t __user *, nset, - sigset_t __user *, oset, size_t, sigsetsize) -{ - sigset_t old_set, new_set; - int error; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - - old_set = current->blocked; - - if (nset) { - if (copy_from_user(&new_set, nset, sizeof(sigset_t))) - return -EFAULT; - sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); - - error = sigprocmask(how, &new_set, NULL); - if (error) - return error; - } - - if (oset) { - if (copy_to_user(oset, &old_set, sizeof(sigset_t))) - return -EFAULT; - } - - return 0; -} - -#ifdef CONFIG_COMPAT -COMPAT_SYSCALL_DEFINE4(rt_sigprocmask, int, how, compat_sigset_t __user *, nset, - compat_sigset_t __user *, oset, compat_size_t, sigsetsize) -{ -#ifdef __BIG_ENDIAN - sigset_t old_set = current->blocked; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - - if (nset) { - compat_sigset_t new32; - sigset_t new_set; - int error; - if (copy_from_user(&new32, nset, sizeof(compat_sigset_t))) - return -EFAULT; - - sigset_from_compat(&new_set, &new32); - sigdelsetmask(&new_set, sigmask(SIGKILL)|sigmask(SIGSTOP)); - - error = sigprocmask(how, &new_set, NULL); - if (error) - return error; - } - if (oset) { - compat_sigset_t old32; - sigset_to_compat(&old32, &old_set); - if (copy_to_user(oset, &old32, sizeof(compat_sigset_t))) - return -EFAULT; - } - return 0; -#else - return sys_rt_sigprocmask(how, (sigset_t __user *)nset, - (sigset_t __user *)oset, sigsetsize); -#endif -} -#endif - -static int do_sigpending(void *set, unsigned long sigsetsize) -{ - if (sigsetsize > sizeof(sigset_t)) - return -EINVAL; - - spin_lock_irq(¤t->sighand->siglock); - sigorsets(set, ¤t->pending.signal, - ¤t->signal->shared_pending.signal); - spin_unlock_irq(¤t->sighand->siglock); - - /* Outside the lock because only this thread touches it. */ - sigandsets(set, ¤t->blocked, set); - return 0; -} - -/** - * sys_rt_sigpending - examine a pending signal that has been raised - * while blocked - * @uset: stores pending signals - * @sigsetsize: size of sigset_t type or larger - */ -SYSCALL_DEFINE2(rt_sigpending, sigset_t __user *, uset, size_t, sigsetsize) -{ - sigset_t set; - int err = do_sigpending(&set, sigsetsize); - if (!err && copy_to_user(uset, &set, sigsetsize)) - err = -EFAULT; - return err; -} - -#ifdef CONFIG_COMPAT -COMPAT_SYSCALL_DEFINE2(rt_sigpending, compat_sigset_t __user *, uset, - compat_size_t, sigsetsize) -{ -#ifdef __BIG_ENDIAN - sigset_t set; - int err = do_sigpending(&set, sigsetsize); - if (!err) { - compat_sigset_t set32; - sigset_to_compat(&set32, &set); - /* we can get here only if sigsetsize <= sizeof(set) */ - if (copy_to_user(uset, &set32, sigsetsize)) - err = -EFAULT; - } - return err; -#else - return sys_rt_sigpending((sigset_t __user *)uset, sigsetsize); -#endif -} -#endif - -#ifndef HAVE_ARCH_COPY_SIGINFO_TO_USER - -int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from) -{ - int err; - - if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) - return -EFAULT; - if (from->si_code < 0) - return __copy_to_user(to, from, sizeof(siginfo_t)) - ? -EFAULT : 0; - /* - * If you change siginfo_t structure, please be sure - * this code is fixed accordingly. - * Please remember to update the signalfd_copyinfo() function - * inside fs/signalfd.c too, in case siginfo_t changes. - * It should never copy any pad contained in the structure - * to avoid security leaks, but must copy the generic - * 3 ints plus the relevant union member. - */ - err = __put_user(from->si_signo, &to->si_signo); - err |= __put_user(from->si_errno, &to->si_errno); - err |= __put_user((short)from->si_code, &to->si_code); - switch (from->si_code & __SI_MASK) { - case __SI_KILL: - err |= __put_user(from->si_pid, &to->si_pid); - err |= __put_user(from->si_uid, &to->si_uid); - break; - case __SI_TIMER: - err |= __put_user(from->si_tid, &to->si_tid); - err |= __put_user(from->si_overrun, &to->si_overrun); - err |= __put_user(from->si_ptr, &to->si_ptr); - break; - case __SI_POLL: - err |= __put_user(from->si_band, &to->si_band); - err |= __put_user(from->si_fd, &to->si_fd); - break; - case __SI_FAULT: - err |= __put_user(from->si_addr, &to->si_addr); -#ifdef __ARCH_SI_TRAPNO - err |= __put_user(from->si_trapno, &to->si_trapno); -#endif -#ifdef BUS_MCEERR_AO - /* - * Other callers might not initialize the si_lsb field, - * so check explicitly for the right codes here. - */ - if (from->si_signo == SIGBUS && - (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)) - err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb); -#endif -#ifdef SEGV_BNDERR - if (from->si_signo == SIGSEGV && from->si_code == SEGV_BNDERR) { - err |= __put_user(from->si_lower, &to->si_lower); - err |= __put_user(from->si_upper, &to->si_upper); - } -#endif -#ifdef SEGV_PKUERR - if (from->si_signo == SIGSEGV && from->si_code == SEGV_PKUERR) - err |= __put_user(from->si_pkey, &to->si_pkey); -#endif - break; - case __SI_CHLD: - err |= __put_user(from->si_pid, &to->si_pid); - err |= __put_user(from->si_uid, &to->si_uid); - err |= __put_user(from->si_status, &to->si_status); - err |= __put_user(from->si_utime, &to->si_utime); - err |= __put_user(from->si_stime, &to->si_stime); - break; - case __SI_RT: /* This is not generated by the kernel as of now. */ - case __SI_MESGQ: /* But this is */ - err |= __put_user(from->si_pid, &to->si_pid); - err |= __put_user(from->si_uid, &to->si_uid); - err |= __put_user(from->si_ptr, &to->si_ptr); - break; -#ifdef __ARCH_SIGSYS - case __SI_SYS: - err |= __put_user(from->si_call_addr, &to->si_call_addr); - err |= __put_user(from->si_syscall, &to->si_syscall); - err |= __put_user(from->si_arch, &to->si_arch); - break; -#endif - default: /* this is just in case for now ... */ - err |= __put_user(from->si_pid, &to->si_pid); - err |= __put_user(from->si_uid, &to->si_uid); - break; - } - return err; -} - -#endif - -/** - * do_sigtimedwait - wait for queued signals specified in @which - * @which: queued signals to wait for - * @info: if non-null, the signal's siginfo is returned here - * @ts: upper bound on process time suspension - */ -int do_sigtimedwait(const sigset_t *which, siginfo_t *info, - const struct timespec *ts) -{ - ktime_t *to = NULL, timeout = { .tv64 = KTIME_MAX }; - struct task_struct *tsk = current; - sigset_t mask = *which; - int sig, ret = 0; - - if (ts) { - if (!timespec_valid(ts)) - return -EINVAL; - timeout = timespec_to_ktime(*ts); - to = &timeout; - } - - /* - * Invert the set of allowed signals to get those we want to block. - */ - sigdelsetmask(&mask, sigmask(SIGKILL) | sigmask(SIGSTOP)); - signotset(&mask); - - spin_lock_irq(&tsk->sighand->siglock); - sig = dequeue_signal(tsk, &mask, info); - if (!sig && timeout.tv64) { - /* - * None ready, temporarily unblock those we're interested - * while we are sleeping in so that we'll be awakened when - * they arrive. Unblocking is always fine, we can avoid - * set_current_blocked(). - */ - tsk->real_blocked = tsk->blocked; - sigandsets(&tsk->blocked, &tsk->blocked, &mask); - recalc_sigpending(); - spin_unlock_irq(&tsk->sighand->siglock); - - __set_current_state(TASK_INTERRUPTIBLE); - ret = freezable_schedule_hrtimeout_range(to, tsk->timer_slack_ns, - HRTIMER_MODE_REL); - spin_lock_irq(&tsk->sighand->siglock); - __set_task_blocked(tsk, &tsk->real_blocked); - sigemptyset(&tsk->real_blocked); - sig = dequeue_signal(tsk, &mask, info); - } - spin_unlock_irq(&tsk->sighand->siglock); - - if (sig) - return sig; - return ret ? -EINTR : -EAGAIN; -} - -/** - * sys_rt_sigtimedwait - synchronously wait for queued signals specified - * in @uthese - * @uthese: queued signals to wait for - * @uinfo: if non-null, the signal's siginfo is returned here - * @uts: upper bound on process time suspension - * @sigsetsize: size of sigset_t type - */ -SYSCALL_DEFINE4(rt_sigtimedwait, const sigset_t __user *, uthese, - siginfo_t __user *, uinfo, const struct timespec __user *, uts, - size_t, sigsetsize) -{ - sigset_t these; - struct timespec ts; - siginfo_t info; - int ret; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user(&these, uthese, sizeof(these))) - return -EFAULT; - - if (uts) { - if (copy_from_user(&ts, uts, sizeof(ts))) - return -EFAULT; - } - - ret = do_sigtimedwait(&these, &info, uts ? &ts : NULL); - - if (ret > 0 && uinfo) { - if (copy_siginfo_to_user(uinfo, &info)) - ret = -EFAULT; - } - - return ret; -} - -/** - * sys_kill - send a signal to a process - * @pid: the PID of the process - * @sig: signal to be sent - */ -SYSCALL_DEFINE2(kill, pid_t, pid, int, sig) -{ - struct siginfo info; - - info.si_signo = sig; - info.si_errno = 0; - info.si_code = SI_USER; - info.si_pid = task_tgid_vnr(current); - info.si_uid = from_kuid_munged(current_user_ns(), current_uid()); - - return kill_something_info(sig, &info, pid); -} - -static int -do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info) -{ - struct task_struct *p; - int error = -ESRCH; - - rcu_read_lock(); - p = find_task_by_vpid(pid); - if (p && (tgid <= 0 || task_tgid_vnr(p) == tgid)) { - error = check_kill_permission(sig, info, p); - /* - * The null signal is a permissions and process existence - * probe. No signal is actually delivered. - */ - if (!error && sig) { - error = do_send_sig_info(sig, info, p, false); - /* - * If lock_task_sighand() failed we pretend the task - * dies after receiving the signal. The window is tiny, - * and the signal is private anyway. - */ - if (unlikely(error == -ESRCH)) - error = 0; - } - } - rcu_read_unlock(); - - return error; -} - -static int do_tkill(pid_t tgid, pid_t pid, int sig) -{ - struct siginfo info = {}; - - info.si_signo = sig; - info.si_errno = 0; - info.si_code = SI_TKILL; - info.si_pid = task_tgid_vnr(current); - info.si_uid = from_kuid_munged(current_user_ns(), current_uid()); - - return do_send_specific(tgid, pid, sig, &info); -} - -/** - * sys_tgkill - send signal to one specific thread - * @tgid: the thread group ID of the thread - * @pid: the PID of the thread - * @sig: signal to be sent - * - * This syscall also checks the @tgid and returns -ESRCH even if the PID - * exists but it's not belonging to the target process anymore. This - * method solves the problem of threads exiting and PIDs getting reused. - */ -SYSCALL_DEFINE3(tgkill, pid_t, tgid, pid_t, pid, int, sig) -{ - /* This is only valid for single tasks */ - if (pid <= 0 || tgid <= 0) - return -EINVAL; - - return do_tkill(tgid, pid, sig); -} - -/** - * sys_tkill - send signal to one specific task - * @pid: the PID of the task - * @sig: signal to be sent - * - * Send a signal to only one task, even if it's a CLONE_THREAD task. - */ -SYSCALL_DEFINE2(tkill, pid_t, pid, int, sig) -{ - /* This is only valid for single tasks */ - if (pid <= 0) - return -EINVAL; - - return do_tkill(0, pid, sig); -} - -static int do_rt_sigqueueinfo(pid_t pid, int sig, siginfo_t *info) -{ - /* Not even root can pretend to send signals from the kernel. - * Nor can they impersonate a kill()/tgkill(), which adds source info. - */ - if ((info->si_code >= 0 || info->si_code == SI_TKILL) && - (task_pid_vnr(current) != pid)) - return -EPERM; - - info->si_signo = sig; - - /* POSIX.1b doesn't mention process groups. */ - return kill_proc_info(sig, info, pid); -} - -/** - * sys_rt_sigqueueinfo - send signal information to a signal - * @pid: the PID of the thread - * @sig: signal to be sent - * @uinfo: signal info to be sent - */ -SYSCALL_DEFINE3(rt_sigqueueinfo, pid_t, pid, int, sig, - siginfo_t __user *, uinfo) -{ - siginfo_t info; - if (copy_from_user(&info, uinfo, sizeof(siginfo_t))) - return -EFAULT; - return do_rt_sigqueueinfo(pid, sig, &info); -} - -#ifdef CONFIG_COMPAT -COMPAT_SYSCALL_DEFINE3(rt_sigqueueinfo, - compat_pid_t, pid, - int, sig, - struct compat_siginfo __user *, uinfo) -{ - siginfo_t info = {}; - int ret = copy_siginfo_from_user32(&info, uinfo); - if (unlikely(ret)) - return ret; - return do_rt_sigqueueinfo(pid, sig, &info); -} -#endif - -static int do_rt_tgsigqueueinfo(pid_t tgid, pid_t pid, int sig, siginfo_t *info) -{ - /* This is only valid for single tasks */ - if (pid <= 0 || tgid <= 0) - return -EINVAL; - - /* Not even root can pretend to send signals from the kernel. - * Nor can they impersonate a kill()/tgkill(), which adds source info. - */ - if ((info->si_code >= 0 || info->si_code == SI_TKILL) && - (task_pid_vnr(current) != pid)) - return -EPERM; - - info->si_signo = sig; - - return do_send_specific(tgid, pid, sig, info); -} - -SYSCALL_DEFINE4(rt_tgsigqueueinfo, pid_t, tgid, pid_t, pid, int, sig, - siginfo_t __user *, uinfo) -{ - siginfo_t info; - - if (copy_from_user(&info, uinfo, sizeof(siginfo_t))) - return -EFAULT; - - return do_rt_tgsigqueueinfo(tgid, pid, sig, &info); -} - -#ifdef CONFIG_COMPAT -COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo, - compat_pid_t, tgid, - compat_pid_t, pid, - int, sig, - struct compat_siginfo __user *, uinfo) -{ - siginfo_t info = {}; - - if (copy_siginfo_from_user32(&info, uinfo)) - return -EFAULT; - return do_rt_tgsigqueueinfo(tgid, pid, sig, &info); -} -#endif - -/* - * For kthreads only, must not be used if cloned with CLONE_SIGHAND - */ -void kernel_sigaction(int sig, __sighandler_t action) -{ - spin_lock_irq(¤t->sighand->siglock); - current->sighand->action[sig - 1].sa.sa_handler = action; - if (action == SIG_IGN) { - sigset_t mask; - - sigemptyset(&mask); - sigaddset(&mask, sig); - - flush_sigqueue_mask(&mask, ¤t->signal->shared_pending); - flush_sigqueue_mask(&mask, ¤t->pending); - recalc_sigpending(); - } - spin_unlock_irq(¤t->sighand->siglock); -} -EXPORT_SYMBOL(kernel_sigaction); - -void __weak sigaction_compat_abi(struct k_sigaction *act, - struct k_sigaction *oact) -{ -} - -int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact) -{ - struct task_struct *p = current, *t; - struct k_sigaction *k; - sigset_t mask; - - if (!valid_signal(sig) || sig < 1 || (act && sig_kernel_only(sig))) - return -EINVAL; - - k = &p->sighand->action[sig-1]; - - spin_lock_irq(&p->sighand->siglock); - if (oact) - *oact = *k; - - sigaction_compat_abi(act, oact); - - if (act) { - sigdelsetmask(&act->sa.sa_mask, - sigmask(SIGKILL) | sigmask(SIGSTOP)); - *k = *act; - /* - * POSIX 3.3.1.3: - * "Setting a signal action to SIG_IGN for a signal that is - * pending shall cause the pending signal to be discarded, - * whether or not it is blocked." - * - * "Setting a signal action to SIG_DFL for a signal that is - * pending and whose default action is to ignore the signal - * (for example, SIGCHLD), shall cause the pending signal to - * be discarded, whether or not it is blocked" - */ - if (sig_handler_ignored(sig_handler(p, sig), sig)) { - sigemptyset(&mask); - sigaddset(&mask, sig); - flush_sigqueue_mask(&mask, &p->signal->shared_pending); - for_each_thread(p, t) - flush_sigqueue_mask(&mask, &t->pending); - } - } - - spin_unlock_irq(&p->sighand->siglock); - return 0; -} - -static int -do_sigaltstack (const stack_t __user *uss, stack_t __user *uoss, unsigned long sp) -{ - stack_t oss; - int error; - - oss.ss_sp = (void __user *) current->sas_ss_sp; - oss.ss_size = current->sas_ss_size; - oss.ss_flags = sas_ss_flags(sp) | - (current->sas_ss_flags & SS_FLAG_BITS); - - if (uss) { - void __user *ss_sp; - size_t ss_size; - unsigned ss_flags; - int ss_mode; - - error = -EFAULT; - if (!access_ok(VERIFY_READ, uss, sizeof(*uss))) - goto out; - error = __get_user(ss_sp, &uss->ss_sp) | - __get_user(ss_flags, &uss->ss_flags) | - __get_user(ss_size, &uss->ss_size); - if (error) - goto out; - - error = -EPERM; - if (on_sig_stack(sp)) - goto out; - - ss_mode = ss_flags & ~SS_FLAG_BITS; - error = -EINVAL; - if (ss_mode != SS_DISABLE && ss_mode != SS_ONSTACK && - ss_mode != 0) - goto out; - - if (ss_mode == SS_DISABLE) { - ss_size = 0; - ss_sp = NULL; - } else { - error = -ENOMEM; - if (ss_size < MINSIGSTKSZ) - goto out; - } - - current->sas_ss_sp = (unsigned long) ss_sp; - current->sas_ss_size = ss_size; - current->sas_ss_flags = ss_flags; - } - - error = 0; - if (uoss) { - error = -EFAULT; - if (!access_ok(VERIFY_WRITE, uoss, sizeof(*uoss))) - goto out; - error = __put_user(oss.ss_sp, &uoss->ss_sp) | - __put_user(oss.ss_size, &uoss->ss_size) | - __put_user(oss.ss_flags, &uoss->ss_flags); - } - -out: - return error; -} -SYSCALL_DEFINE2(sigaltstack,const stack_t __user *,uss, stack_t __user *,uoss) -{ - return do_sigaltstack(uss, uoss, current_user_stack_pointer()); -} - -int restore_altstack(const stack_t __user *uss) -{ - int err = do_sigaltstack(uss, NULL, current_user_stack_pointer()); - /* squash all but EFAULT for now */ - return err == -EFAULT ? err : 0; -} - -int __save_altstack(stack_t __user *uss, unsigned long sp) -{ - struct task_struct *t = current; - int err = __put_user((void __user *)t->sas_ss_sp, &uss->ss_sp) | - __put_user(t->sas_ss_flags, &uss->ss_flags) | - __put_user(t->sas_ss_size, &uss->ss_size); - if (err) - return err; - if (t->sas_ss_flags & SS_AUTODISARM) - sas_ss_reset(t); - return 0; -} - -#ifdef CONFIG_COMPAT -COMPAT_SYSCALL_DEFINE2(sigaltstack, - const compat_stack_t __user *, uss_ptr, - compat_stack_t __user *, uoss_ptr) -{ - stack_t uss, uoss; - int ret; - mm_segment_t seg; - - if (uss_ptr) { - compat_stack_t uss32; - - memset(&uss, 0, sizeof(stack_t)); - if (copy_from_user(&uss32, uss_ptr, sizeof(compat_stack_t))) - return -EFAULT; - uss.ss_sp = compat_ptr(uss32.ss_sp); - uss.ss_flags = uss32.ss_flags; - uss.ss_size = uss32.ss_size; - } - seg = get_fs(); - set_fs(KERNEL_DS); - ret = do_sigaltstack((stack_t __force __user *) (uss_ptr ? &uss : NULL), - (stack_t __force __user *) &uoss, - compat_user_stack_pointer()); - set_fs(seg); - if (ret >= 0 && uoss_ptr) { - if (!access_ok(VERIFY_WRITE, uoss_ptr, sizeof(compat_stack_t)) || - __put_user(ptr_to_compat(uoss.ss_sp), &uoss_ptr->ss_sp) || - __put_user(uoss.ss_flags, &uoss_ptr->ss_flags) || - __put_user(uoss.ss_size, &uoss_ptr->ss_size)) - ret = -EFAULT; - } - return ret; -} - -int compat_restore_altstack(const compat_stack_t __user *uss) -{ - int err = compat_sys_sigaltstack(uss, NULL); - /* squash all but -EFAULT for now */ - return err == -EFAULT ? err : 0; -} - -int __compat_save_altstack(compat_stack_t __user *uss, unsigned long sp) -{ - struct task_struct *t = current; - return __put_user(ptr_to_compat((void __user *)t->sas_ss_sp), &uss->ss_sp) | - __put_user(sas_ss_flags(sp), &uss->ss_flags) | - __put_user(t->sas_ss_size, &uss->ss_size); -} -#endif - -#ifdef __ARCH_WANT_SYS_SIGPENDING - -/** - * sys_sigpending - examine pending signals - * @set: where mask of pending signal is returned - */ -SYSCALL_DEFINE1(sigpending, old_sigset_t __user *, set) -{ - return sys_rt_sigpending((sigset_t __user *)set, sizeof(old_sigset_t)); -} - -#endif - -#ifdef __ARCH_WANT_SYS_SIGPROCMASK -/** - * sys_sigprocmask - examine and change blocked signals - * @how: whether to add, remove, or set signals - * @nset: signals to add or remove (if non-null) - * @oset: previous value of signal mask if non-null - * - * Some platforms have their own version with special arguments; - * others support only sys_rt_sigprocmask. - */ - -SYSCALL_DEFINE3(sigprocmask, int, how, old_sigset_t __user *, nset, - old_sigset_t __user *, oset) -{ - old_sigset_t old_set, new_set; - sigset_t new_blocked; - - old_set = current->blocked.sig[0]; - - if (nset) { - if (copy_from_user(&new_set, nset, sizeof(*nset))) - return -EFAULT; - - new_blocked = current->blocked; - - switch (how) { - case SIG_BLOCK: - sigaddsetmask(&new_blocked, new_set); - break; - case SIG_UNBLOCK: - sigdelsetmask(&new_blocked, new_set); - break; - case SIG_SETMASK: - new_blocked.sig[0] = new_set; - break; - default: - return -EINVAL; - } - - set_current_blocked(&new_blocked); - } - - if (oset) { - if (copy_to_user(oset, &old_set, sizeof(*oset))) - return -EFAULT; - } - - return 0; -} -#endif /* __ARCH_WANT_SYS_SIGPROCMASK */ - -#ifndef CONFIG_ODD_RT_SIGACTION -/** - * sys_rt_sigaction - alter an action taken by a process - * @sig: signal to be sent - * @act: new sigaction - * @oact: used to save the previous sigaction - * @sigsetsize: size of sigset_t type - */ -SYSCALL_DEFINE4(rt_sigaction, int, sig, - const struct sigaction __user *, act, - struct sigaction __user *, oact, - size_t, sigsetsize) -{ - struct k_sigaction new_sa, old_sa; - int ret = -EINVAL; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - goto out; - - if (act) { - if (copy_from_user(&new_sa.sa, act, sizeof(new_sa.sa))) - return -EFAULT; - } - - ret = do_sigaction(sig, act ? &new_sa : NULL, oact ? &old_sa : NULL); - - if (!ret && oact) { - if (copy_to_user(oact, &old_sa.sa, sizeof(old_sa.sa))) - return -EFAULT; - } -out: - return ret; -} -#ifdef CONFIG_COMPAT -COMPAT_SYSCALL_DEFINE4(rt_sigaction, int, sig, - const struct compat_sigaction __user *, act, - struct compat_sigaction __user *, oact, - compat_size_t, sigsetsize) -{ - struct k_sigaction new_ka, old_ka; - compat_sigset_t mask; -#ifdef __ARCH_HAS_SA_RESTORER - compat_uptr_t restorer; -#endif - int ret; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(compat_sigset_t)) - return -EINVAL; - - if (act) { - compat_uptr_t handler; - ret = get_user(handler, &act->sa_handler); - new_ka.sa.sa_handler = compat_ptr(handler); -#ifdef __ARCH_HAS_SA_RESTORER - ret |= get_user(restorer, &act->sa_restorer); - new_ka.sa.sa_restorer = compat_ptr(restorer); -#endif - ret |= copy_from_user(&mask, &act->sa_mask, sizeof(mask)); - ret |= get_user(new_ka.sa.sa_flags, &act->sa_flags); - if (ret) - return -EFAULT; - sigset_from_compat(&new_ka.sa.sa_mask, &mask); - } - - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - if (!ret && oact) { - sigset_to_compat(&mask, &old_ka.sa.sa_mask); - ret = put_user(ptr_to_compat(old_ka.sa.sa_handler), - &oact->sa_handler); - ret |= copy_to_user(&oact->sa_mask, &mask, sizeof(mask)); - ret |= put_user(old_ka.sa.sa_flags, &oact->sa_flags); -#ifdef __ARCH_HAS_SA_RESTORER - ret |= put_user(ptr_to_compat(old_ka.sa.sa_restorer), - &oact->sa_restorer); -#endif - } - return ret; -} -#endif -#endif /* !CONFIG_ODD_RT_SIGACTION */ - -#ifdef CONFIG_OLD_SIGACTION -SYSCALL_DEFINE3(sigaction, int, sig, - const struct old_sigaction __user *, act, - struct old_sigaction __user *, oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; - - if (act) { - old_sigset_t mask; - if (!access_ok(VERIFY_READ, act, sizeof(*act)) || - __get_user(new_ka.sa.sa_handler, &act->sa_handler) || - __get_user(new_ka.sa.sa_restorer, &act->sa_restorer) || - __get_user(new_ka.sa.sa_flags, &act->sa_flags) || - __get_user(mask, &act->sa_mask)) - return -EFAULT; -#ifdef __ARCH_HAS_KA_RESTORER - new_ka.ka_restorer = NULL; -#endif - siginitset(&new_ka.sa.sa_mask, mask); - } - - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - - if (!ret && oact) { - if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || - __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || - __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer) || - __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) - return -EFAULT; - } - - return ret; -} -#endif -#ifdef CONFIG_COMPAT_OLD_SIGACTION -COMPAT_SYSCALL_DEFINE3(sigaction, int, sig, - const struct compat_old_sigaction __user *, act, - struct compat_old_sigaction __user *, oact) -{ - struct k_sigaction new_ka, old_ka; - int ret; - compat_old_sigset_t mask; - compat_uptr_t handler, restorer; - - if (act) { - if (!access_ok(VERIFY_READ, act, sizeof(*act)) || - __get_user(handler, &act->sa_handler) || - __get_user(restorer, &act->sa_restorer) || - __get_user(new_ka.sa.sa_flags, &act->sa_flags) || - __get_user(mask, &act->sa_mask)) - return -EFAULT; - -#ifdef __ARCH_HAS_KA_RESTORER - new_ka.ka_restorer = NULL; -#endif - new_ka.sa.sa_handler = compat_ptr(handler); - new_ka.sa.sa_restorer = compat_ptr(restorer); - siginitset(&new_ka.sa.sa_mask, mask); - } - - ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); - - if (!ret && oact) { - if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)) || - __put_user(ptr_to_compat(old_ka.sa.sa_handler), - &oact->sa_handler) || - __put_user(ptr_to_compat(old_ka.sa.sa_restorer), - &oact->sa_restorer) || - __put_user(old_ka.sa.sa_flags, &oact->sa_flags) || - __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask)) - return -EFAULT; - } - return ret; -} -#endif - -#ifdef CONFIG_SGETMASK_SYSCALL - -/* - * For backwards compatibility. Functionality superseded by sigprocmask. - */ -SYSCALL_DEFINE0(sgetmask) -{ - /* SMP safe */ - return current->blocked.sig[0]; -} - -SYSCALL_DEFINE1(ssetmask, int, newmask) -{ - int old = current->blocked.sig[0]; - sigset_t newset; - - siginitset(&newset, newmask); - set_current_blocked(&newset); - - return old; -} -#endif /* CONFIG_SGETMASK_SYSCALL */ - -#ifdef __ARCH_WANT_SYS_SIGNAL -/* - * For backwards compatibility. Functionality superseded by sigaction. - */ -SYSCALL_DEFINE2(signal, int, sig, __sighandler_t, handler) -{ - struct k_sigaction new_sa, old_sa; - int ret; - - new_sa.sa.sa_handler = handler; - new_sa.sa.sa_flags = SA_ONESHOT | SA_NOMASK; - sigemptyset(&new_sa.sa.sa_mask); - - ret = do_sigaction(sig, &new_sa, &old_sa); - - return ret ? ret : (unsigned long)old_sa.sa.sa_handler; -} -#endif /* __ARCH_WANT_SYS_SIGNAL */ - -#ifdef __ARCH_WANT_SYS_PAUSE - -SYSCALL_DEFINE0(pause) -{ - while (!signal_pending(current)) { - __set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } - return -ERESTARTNOHAND; -} - -#endif - -static int sigsuspend(sigset_t *set) -{ - current->saved_sigmask = current->blocked; - set_current_blocked(set); - - while (!signal_pending(current)) { - __set_current_state(TASK_INTERRUPTIBLE); - schedule(); - } - set_restore_sigmask(); - return -ERESTARTNOHAND; -} - -/** - * sys_rt_sigsuspend - replace the signal mask for a value with the - * @unewset value until a signal is received - * @unewset: new signal mask value - * @sigsetsize: size of sigset_t type - */ -SYSCALL_DEFINE2(rt_sigsuspend, sigset_t __user *, unewset, size_t, sigsetsize) -{ - sigset_t newset; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user(&newset, unewset, sizeof(newset))) - return -EFAULT; - return sigsuspend(&newset); -} - -#ifdef CONFIG_COMPAT -COMPAT_SYSCALL_DEFINE2(rt_sigsuspend, compat_sigset_t __user *, unewset, compat_size_t, sigsetsize) -{ -#ifdef __BIG_ENDIAN - sigset_t newset; - compat_sigset_t newset32; - - /* XXX: Don't preclude handling different sized sigset_t's. */ - if (sigsetsize != sizeof(sigset_t)) - return -EINVAL; - - if (copy_from_user(&newset32, unewset, sizeof(compat_sigset_t))) - return -EFAULT; - sigset_from_compat(&newset, &newset32); - return sigsuspend(&newset); -#else - /* on little-endian bitmaps don't care about granularity */ - return sys_rt_sigsuspend((sigset_t __user *)unewset, sigsetsize); -#endif -} -#endif - -#ifdef CONFIG_OLD_SIGSUSPEND -SYSCALL_DEFINE1(sigsuspend, old_sigset_t, mask) -{ - sigset_t blocked; - siginitset(&blocked, mask); - return sigsuspend(&blocked); -} -#endif -#ifdef CONFIG_OLD_SIGSUSPEND3 -SYSCALL_DEFINE3(sigsuspend, int, unused1, int, unused2, old_sigset_t, mask) -{ - sigset_t blocked; - siginitset(&blocked, mask); - return sigsuspend(&blocked); -} -#endif - -__weak const char *arch_vma_name(struct vm_area_struct *vma) -{ - return NULL; -} - -void __init signals_init(void) -{ - /* If this check fails, the __ARCH_SI_PREAMBLE_SIZE value is wrong! */ - BUILD_BUG_ON(__ARCH_SI_PREAMBLE_SIZE - != offsetof(struct siginfo, _sifields._pad)); - - sigqueue_cachep = KMEM_CACHE(sigqueue, SLAB_PANIC); -} - -#ifdef CONFIG_KGDB_KDB -#include -/* - * kdb_send_sig_info - Allows kdb to send signals without exposing - * signal internals. This function checks if the required locks are - * available before calling the main signal code, to avoid kdb - * deadlocks. - */ -void -kdb_send_sig_info(struct task_struct *t, struct siginfo *info) -{ - static struct task_struct *kdb_prev_t; - int sig, new_t; - if (!spin_trylock(&t->sighand->siglock)) { - kdb_printf("Can't do kill command now.\n" - "The sigmask lock is held somewhere else in " - "kernel, try again later\n"); - return; - } - spin_unlock(&t->sighand->siglock); - new_t = kdb_prev_t != t; - kdb_prev_t = t; - if (t->state != TASK_RUNNING && new_t) { - kdb_printf("Process is not RUNNING, sending a signal from " - "kdb risks deadlock\n" - "on the run queue locks. " - "The signal has _not_ been sent.\n" - "Reissue the kill command if you want to risk " - "the deadlock.\n"); - return; - } - sig = info->si_signo; - if (send_sig_info(sig, info, t)) - kdb_printf("Fail to deliver Signal %d to process %d.\n", - sig, t->pid); - else - kdb_printf("Signal %d is sent to process %d.\n", sig, t->pid); -} -#endif /* CONFIG_KGDB_KDB */ diff --git a/src/linux/kernel/smpboot.c b/src/linux/kernel/smpboot.c deleted file mode 100644 index 4a5c6e7..0000000 --- a/src/linux/kernel/smpboot.c +++ /dev/null @@ -1,533 +0,0 @@ -/* - * Common SMP CPU bringup/teardown functions - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "smpboot.h" - -#ifdef CONFIG_SMP - -#ifdef CONFIG_GENERIC_SMP_IDLE_THREAD -/* - * For the hotplug case we keep the task structs around and reuse - * them. - */ -static DEFINE_PER_CPU(struct task_struct *, idle_threads); - -struct task_struct *idle_thread_get(unsigned int cpu) -{ - struct task_struct *tsk = per_cpu(idle_threads, cpu); - - if (!tsk) - return ERR_PTR(-ENOMEM); - init_idle(tsk, cpu); - return tsk; -} - -void __init idle_thread_set_boot_cpu(void) -{ - per_cpu(idle_threads, smp_processor_id()) = current; -} - -/** - * idle_init - Initialize the idle thread for a cpu - * @cpu: The cpu for which the idle thread should be initialized - * - * Creates the thread if it does not exist. - */ -static inline void idle_init(unsigned int cpu) -{ - struct task_struct *tsk = per_cpu(idle_threads, cpu); - - if (!tsk) { - tsk = fork_idle(cpu); - if (IS_ERR(tsk)) - pr_err("SMP: fork_idle() failed for CPU %u\n", cpu); - else - per_cpu(idle_threads, cpu) = tsk; - } -} - -/** - * idle_threads_init - Initialize idle threads for all cpus - */ -void __init idle_threads_init(void) -{ - unsigned int cpu, boot_cpu; - - boot_cpu = smp_processor_id(); - - for_each_possible_cpu(cpu) { - if (cpu != boot_cpu) - idle_init(cpu); - } -} -#endif - -#endif /* #ifdef CONFIG_SMP */ - -static LIST_HEAD(hotplug_threads); -static DEFINE_MUTEX(smpboot_threads_lock); - -struct smpboot_thread_data { - unsigned int cpu; - unsigned int status; - struct smp_hotplug_thread *ht; -}; - -enum { - HP_THREAD_NONE = 0, - HP_THREAD_ACTIVE, - HP_THREAD_PARKED, -}; - -/** - * smpboot_thread_fn - percpu hotplug thread loop function - * @data: thread data pointer - * - * Checks for thread stop and park conditions. Calls the necessary - * setup, cleanup, park and unpark functions for the registered - * thread. - * - * Returns 1 when the thread should exit, 0 otherwise. - */ -static int smpboot_thread_fn(void *data) -{ - struct smpboot_thread_data *td = data; - struct smp_hotplug_thread *ht = td->ht; - - while (1) { - set_current_state(TASK_INTERRUPTIBLE); - preempt_disable(); - if (kthread_should_stop()) { - __set_current_state(TASK_RUNNING); - preempt_enable(); - /* cleanup must mirror setup */ - if (ht->cleanup && td->status != HP_THREAD_NONE) - ht->cleanup(td->cpu, cpu_online(td->cpu)); - kfree(td); - return 0; - } - - if (kthread_should_park()) { - __set_current_state(TASK_RUNNING); - preempt_enable(); - if (ht->park && td->status == HP_THREAD_ACTIVE) { - BUG_ON(td->cpu != smp_processor_id()); - ht->park(td->cpu); - td->status = HP_THREAD_PARKED; - } - kthread_parkme(); - /* We might have been woken for stop */ - continue; - } - - BUG_ON(td->cpu != smp_processor_id()); - - /* Check for state change setup */ - switch (td->status) { - case HP_THREAD_NONE: - __set_current_state(TASK_RUNNING); - preempt_enable(); - if (ht->setup) - ht->setup(td->cpu); - td->status = HP_THREAD_ACTIVE; - continue; - - case HP_THREAD_PARKED: - __set_current_state(TASK_RUNNING); - preempt_enable(); - if (ht->unpark) - ht->unpark(td->cpu); - td->status = HP_THREAD_ACTIVE; - continue; - } - - if (!ht->thread_should_run(td->cpu)) { - preempt_enable_no_resched(); - schedule(); - } else { - __set_current_state(TASK_RUNNING); - preempt_enable(); - ht->thread_fn(td->cpu); - } - } -} - -static int -__smpboot_create_thread(struct smp_hotplug_thread *ht, unsigned int cpu) -{ - struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu); - struct smpboot_thread_data *td; - - if (tsk) - return 0; - - td = kzalloc_node(sizeof(*td), GFP_KERNEL, cpu_to_node(cpu)); - if (!td) - return -ENOMEM; - td->cpu = cpu; - td->ht = ht; - - tsk = kthread_create_on_cpu(smpboot_thread_fn, td, cpu, - ht->thread_comm); - if (IS_ERR(tsk)) { - kfree(td); - return PTR_ERR(tsk); - } - /* - * Park the thread so that it could start right on the CPU - * when it is available. - */ - kthread_park(tsk); - get_task_struct(tsk); - *per_cpu_ptr(ht->store, cpu) = tsk; - if (ht->create) { - /* - * Make sure that the task has actually scheduled out - * into park position, before calling the create - * callback. At least the migration thread callback - * requires that the task is off the runqueue. - */ - if (!wait_task_inactive(tsk, TASK_PARKED)) - WARN_ON(1); - else - ht->create(cpu); - } - return 0; -} - -int smpboot_create_threads(unsigned int cpu) -{ - struct smp_hotplug_thread *cur; - int ret = 0; - - mutex_lock(&smpboot_threads_lock); - list_for_each_entry(cur, &hotplug_threads, list) { - ret = __smpboot_create_thread(cur, cpu); - if (ret) - break; - } - mutex_unlock(&smpboot_threads_lock); - return ret; -} - -static void smpboot_unpark_thread(struct smp_hotplug_thread *ht, unsigned int cpu) -{ - struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu); - - if (!ht->selfparking) - kthread_unpark(tsk); -} - -int smpboot_unpark_threads(unsigned int cpu) -{ - struct smp_hotplug_thread *cur; - - mutex_lock(&smpboot_threads_lock); - list_for_each_entry(cur, &hotplug_threads, list) - if (cpumask_test_cpu(cpu, cur->cpumask)) - smpboot_unpark_thread(cur, cpu); - mutex_unlock(&smpboot_threads_lock); - return 0; -} - -static void smpboot_park_thread(struct smp_hotplug_thread *ht, unsigned int cpu) -{ - struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu); - - if (tsk && !ht->selfparking) - kthread_park(tsk); -} - -int smpboot_park_threads(unsigned int cpu) -{ - struct smp_hotplug_thread *cur; - - mutex_lock(&smpboot_threads_lock); - list_for_each_entry_reverse(cur, &hotplug_threads, list) - smpboot_park_thread(cur, cpu); - mutex_unlock(&smpboot_threads_lock); - return 0; -} - -static void smpboot_destroy_threads(struct smp_hotplug_thread *ht) -{ - unsigned int cpu; - - /* We need to destroy also the parked threads of offline cpus */ - for_each_possible_cpu(cpu) { - struct task_struct *tsk = *per_cpu_ptr(ht->store, cpu); - - if (tsk) { - kthread_stop(tsk); - put_task_struct(tsk); - *per_cpu_ptr(ht->store, cpu) = NULL; - } - } -} - -/** - * smpboot_register_percpu_thread_cpumask - Register a per_cpu thread related - * to hotplug - * @plug_thread: Hotplug thread descriptor - * @cpumask: The cpumask where threads run - * - * Creates and starts the threads on all online cpus. - */ -int smpboot_register_percpu_thread_cpumask(struct smp_hotplug_thread *plug_thread, - const struct cpumask *cpumask) -{ - unsigned int cpu; - int ret = 0; - - if (!alloc_cpumask_var(&plug_thread->cpumask, GFP_KERNEL)) - return -ENOMEM; - cpumask_copy(plug_thread->cpumask, cpumask); - - get_online_cpus(); - mutex_lock(&smpboot_threads_lock); - for_each_online_cpu(cpu) { - ret = __smpboot_create_thread(plug_thread, cpu); - if (ret) { - smpboot_destroy_threads(plug_thread); - free_cpumask_var(plug_thread->cpumask); - goto out; - } - if (cpumask_test_cpu(cpu, cpumask)) - smpboot_unpark_thread(plug_thread, cpu); - } - list_add(&plug_thread->list, &hotplug_threads); -out: - mutex_unlock(&smpboot_threads_lock); - put_online_cpus(); - return ret; -} -EXPORT_SYMBOL_GPL(smpboot_register_percpu_thread_cpumask); - -/** - * smpboot_unregister_percpu_thread - Unregister a per_cpu thread related to hotplug - * @plug_thread: Hotplug thread descriptor - * - * Stops all threads on all possible cpus. - */ -void smpboot_unregister_percpu_thread(struct smp_hotplug_thread *plug_thread) -{ - get_online_cpus(); - mutex_lock(&smpboot_threads_lock); - list_del(&plug_thread->list); - smpboot_destroy_threads(plug_thread); - mutex_unlock(&smpboot_threads_lock); - put_online_cpus(); - free_cpumask_var(plug_thread->cpumask); -} -EXPORT_SYMBOL_GPL(smpboot_unregister_percpu_thread); - -/** - * smpboot_update_cpumask_percpu_thread - Adjust which per_cpu hotplug threads stay parked - * @plug_thread: Hotplug thread descriptor - * @new: Revised mask to use - * - * The cpumask field in the smp_hotplug_thread must not be updated directly - * by the client, but only by calling this function. - * This function can only be called on a registered smp_hotplug_thread. - */ -int smpboot_update_cpumask_percpu_thread(struct smp_hotplug_thread *plug_thread, - const struct cpumask *new) -{ - struct cpumask *old = plug_thread->cpumask; - cpumask_var_t tmp; - unsigned int cpu; - - if (!alloc_cpumask_var(&tmp, GFP_KERNEL)) - return -ENOMEM; - - get_online_cpus(); - mutex_lock(&smpboot_threads_lock); - - /* Park threads that were exclusively enabled on the old mask. */ - cpumask_andnot(tmp, old, new); - for_each_cpu_and(cpu, tmp, cpu_online_mask) - smpboot_park_thread(plug_thread, cpu); - - /* Unpark threads that are exclusively enabled on the new mask. */ - cpumask_andnot(tmp, new, old); - for_each_cpu_and(cpu, tmp, cpu_online_mask) - smpboot_unpark_thread(plug_thread, cpu); - - cpumask_copy(old, new); - - mutex_unlock(&smpboot_threads_lock); - put_online_cpus(); - - free_cpumask_var(tmp); - - return 0; -} -EXPORT_SYMBOL_GPL(smpboot_update_cpumask_percpu_thread); - -static DEFINE_PER_CPU(atomic_t, cpu_hotplug_state) = ATOMIC_INIT(CPU_POST_DEAD); - -/* - * Called to poll specified CPU's state, for example, when waiting for - * a CPU to come online. - */ -int cpu_report_state(int cpu) -{ - return atomic_read(&per_cpu(cpu_hotplug_state, cpu)); -} - -/* - * If CPU has died properly, set its state to CPU_UP_PREPARE and - * return success. Otherwise, return -EBUSY if the CPU died after - * cpu_wait_death() timed out. And yet otherwise again, return -EAGAIN - * if cpu_wait_death() timed out and the CPU still hasn't gotten around - * to dying. In the latter two cases, the CPU might not be set up - * properly, but it is up to the arch-specific code to decide. - * Finally, -EIO indicates an unanticipated problem. - * - * Note that it is permissible to omit this call entirely, as is - * done in architectures that do no CPU-hotplug error checking. - */ -int cpu_check_up_prepare(int cpu) -{ - if (!IS_ENABLED(CONFIG_HOTPLUG_CPU)) { - atomic_set(&per_cpu(cpu_hotplug_state, cpu), CPU_UP_PREPARE); - return 0; - } - - switch (atomic_read(&per_cpu(cpu_hotplug_state, cpu))) { - - case CPU_POST_DEAD: - - /* The CPU died properly, so just start it up again. */ - atomic_set(&per_cpu(cpu_hotplug_state, cpu), CPU_UP_PREPARE); - return 0; - - case CPU_DEAD_FROZEN: - - /* - * Timeout during CPU death, so let caller know. - * The outgoing CPU completed its processing, but after - * cpu_wait_death() timed out and reported the error. The - * caller is free to proceed, in which case the state - * will be reset properly by cpu_set_state_online(). - * Proceeding despite this -EBUSY return makes sense - * for systems where the outgoing CPUs take themselves - * offline, with no post-death manipulation required from - * a surviving CPU. - */ - return -EBUSY; - - case CPU_BROKEN: - - /* - * The most likely reason we got here is that there was - * a timeout during CPU death, and the outgoing CPU never - * did complete its processing. This could happen on - * a virtualized system if the outgoing VCPU gets preempted - * for more than five seconds, and the user attempts to - * immediately online that same CPU. Trying again later - * might return -EBUSY above, hence -EAGAIN. - */ - return -EAGAIN; - - default: - - /* Should not happen. Famous last words. */ - return -EIO; - } -} - -/* - * Mark the specified CPU online. - * - * Note that it is permissible to omit this call entirely, as is - * done in architectures that do no CPU-hotplug error checking. - */ -void cpu_set_state_online(int cpu) -{ - (void)atomic_xchg(&per_cpu(cpu_hotplug_state, cpu), CPU_ONLINE); -} - -#ifdef CONFIG_HOTPLUG_CPU - -/* - * Wait for the specified CPU to exit the idle loop and die. - */ -bool cpu_wait_death(unsigned int cpu, int seconds) -{ - int jf_left = seconds * HZ; - int oldstate; - bool ret = true; - int sleep_jf = 1; - - might_sleep(); - - /* The outgoing CPU will normally get done quite quickly. */ - if (atomic_read(&per_cpu(cpu_hotplug_state, cpu)) == CPU_DEAD) - goto update_state; - udelay(5); - - /* But if the outgoing CPU dawdles, wait increasingly long times. */ - while (atomic_read(&per_cpu(cpu_hotplug_state, cpu)) != CPU_DEAD) { - schedule_timeout_uninterruptible(sleep_jf); - jf_left -= sleep_jf; - if (jf_left <= 0) - break; - sleep_jf = DIV_ROUND_UP(sleep_jf * 11, 10); - } -update_state: - oldstate = atomic_read(&per_cpu(cpu_hotplug_state, cpu)); - if (oldstate == CPU_DEAD) { - /* Outgoing CPU died normally, update state. */ - smp_mb(); /* atomic_read() before update. */ - atomic_set(&per_cpu(cpu_hotplug_state, cpu), CPU_POST_DEAD); - } else { - /* Outgoing CPU still hasn't died, set state accordingly. */ - if (atomic_cmpxchg(&per_cpu(cpu_hotplug_state, cpu), - oldstate, CPU_BROKEN) != oldstate) - goto update_state; - ret = false; - } - return ret; -} - -/* - * Called by the outgoing CPU to report its successful death. Return - * false if this report follows the surviving CPU's timing out. - * - * A separate "CPU_DEAD_FROZEN" is used when the surviving CPU - * timed out. This approach allows architectures to omit calls to - * cpu_check_up_prepare() and cpu_set_state_online() without defeating - * the next cpu_wait_death()'s polling loop. - */ -bool cpu_report_death(void) -{ - int oldstate; - int newstate; - int cpu = smp_processor_id(); - - do { - oldstate = atomic_read(&per_cpu(cpu_hotplug_state, cpu)); - if (oldstate != CPU_BROKEN) - newstate = CPU_DEAD; - else - newstate = CPU_DEAD_FROZEN; - } while (atomic_cmpxchg(&per_cpu(cpu_hotplug_state, cpu), - oldstate, newstate) != oldstate); - return newstate == CPU_DEAD; -} - -#endif /* #ifdef CONFIG_HOTPLUG_CPU */ diff --git a/src/linux/kernel/smpboot.h b/src/linux/kernel/smpboot.h deleted file mode 100644 index 485b81c..0000000 --- a/src/linux/kernel/smpboot.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef SMPBOOT_H -#define SMPBOOT_H - -struct task_struct; - -#ifdef CONFIG_GENERIC_SMP_IDLE_THREAD -struct task_struct *idle_thread_get(unsigned int cpu); -void idle_thread_set_boot_cpu(void); -void idle_threads_init(void); -#else -static inline struct task_struct *idle_thread_get(unsigned int cpu) { return NULL; } -static inline void idle_thread_set_boot_cpu(void) { } -static inline void idle_threads_init(void) { } -#endif - -int smpboot_create_threads(unsigned int cpu); -int smpboot_park_threads(unsigned int cpu); -int smpboot_unpark_threads(unsigned int cpu); - -void __init cpuhp_threads_init(void); - -#endif diff --git a/src/linux/kernel/softirq.c b/src/linux/kernel/softirq.c deleted file mode 100644 index 744fa61..0000000 --- a/src/linux/kernel/softirq.c +++ /dev/null @@ -1,786 +0,0 @@ -/* - * linux/kernel/softirq.c - * - * Copyright (C) 1992 Linus Torvalds - * - * Distribute under GPLv2. - * - * Rewritten. Old one was good in 2.2, but in 2.3 it was immoral. --ANK (990903) - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CREATE_TRACE_POINTS -#include - -/* - - No shared variables, all the data are CPU local. - - If a softirq needs serialization, let it serialize itself - by its own spinlocks. - - Even if softirq is serialized, only local cpu is marked for - execution. Hence, we get something sort of weak cpu binding. - Though it is still not clear, will it result in better locality - or will not. - - Examples: - - NET RX softirq. It is multithreaded and does not require - any global serialization. - - NET TX softirq. It kicks software netdevice queues, hence - it is logically serialized per device, but this serialization - is invisible to common code. - - Tasklets: serialized wrt itself. - */ - -#ifndef __ARCH_IRQ_STAT -irq_cpustat_t irq_stat[NR_CPUS] ____cacheline_aligned; -EXPORT_SYMBOL(irq_stat); -#endif - -static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp; - -DEFINE_PER_CPU(struct task_struct *, ksoftirqd); - -const char * const softirq_to_name[NR_SOFTIRQS] = { - "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "IRQ_POLL", - "TASKLET", "SCHED", "HRTIMER", "RCU" -}; - -/* - * we cannot loop indefinitely here to avoid userspace starvation, - * but we also don't want to introduce a worst case 1/HZ latency - * to the pending events, so lets the scheduler to balance - * the softirq load for us. - */ -static void wakeup_softirqd(void) -{ - /* Interrupts are disabled: no need to stop preemption */ - struct task_struct *tsk = __this_cpu_read(ksoftirqd); - - if (tsk && tsk->state != TASK_RUNNING) - wake_up_process(tsk); -} - -/* - * If ksoftirqd is scheduled, we do not want to process pending softirqs - * right now. Let ksoftirqd handle this at its own rate, to get fairness. - */ -static bool ksoftirqd_running(void) -{ - struct task_struct *tsk = __this_cpu_read(ksoftirqd); - - return tsk && (tsk->state == TASK_RUNNING); -} - -/* - * preempt_count and SOFTIRQ_OFFSET usage: - * - preempt_count is changed by SOFTIRQ_OFFSET on entering or leaving - * softirq processing. - * - preempt_count is changed by SOFTIRQ_DISABLE_OFFSET (= 2 * SOFTIRQ_OFFSET) - * on local_bh_disable or local_bh_enable. - * This lets us distinguish between whether we are currently processing - * softirq and whether we just have bh disabled. - */ - -/* - * This one is for softirq.c-internal use, - * where hardirqs are disabled legitimately: - */ -#ifdef CONFIG_TRACE_IRQFLAGS -void __local_bh_disable_ip(unsigned long ip, unsigned int cnt) -{ - unsigned long flags; - - WARN_ON_ONCE(in_irq()); - - raw_local_irq_save(flags); - /* - * The preempt tracer hooks into preempt_count_add and will break - * lockdep because it calls back into lockdep after SOFTIRQ_OFFSET - * is set and before current->softirq_enabled is cleared. - * We must manually increment preempt_count here and manually - * call the trace_preempt_off later. - */ - __preempt_count_add(cnt); - /* - * Were softirqs turned off above: - */ - if (softirq_count() == (cnt & SOFTIRQ_MASK)) - trace_softirqs_off(ip); - raw_local_irq_restore(flags); - - if (preempt_count() == cnt) { -#ifdef CONFIG_DEBUG_PREEMPT - current->preempt_disable_ip = get_lock_parent_ip(); -#endif - trace_preempt_off(CALLER_ADDR0, get_lock_parent_ip()); - } -} -EXPORT_SYMBOL(__local_bh_disable_ip); -#endif /* CONFIG_TRACE_IRQFLAGS */ - -static void __local_bh_enable(unsigned int cnt) -{ - WARN_ON_ONCE(!irqs_disabled()); - - if (softirq_count() == (cnt & SOFTIRQ_MASK)) - trace_softirqs_on(_RET_IP_); - preempt_count_sub(cnt); -} - -/* - * Special-case - softirqs can safely be enabled in - * cond_resched_softirq(), or by __do_softirq(), - * without processing still-pending softirqs: - */ -void _local_bh_enable(void) -{ - WARN_ON_ONCE(in_irq()); - __local_bh_enable(SOFTIRQ_DISABLE_OFFSET); -} -EXPORT_SYMBOL(_local_bh_enable); - -void __local_bh_enable_ip(unsigned long ip, unsigned int cnt) -{ - WARN_ON_ONCE(in_irq() || irqs_disabled()); -#ifdef CONFIG_TRACE_IRQFLAGS - local_irq_disable(); -#endif - /* - * Are softirqs going to be turned on now: - */ - if (softirq_count() == SOFTIRQ_DISABLE_OFFSET) - trace_softirqs_on(ip); - /* - * Keep preemption disabled until we are done with - * softirq processing: - */ - preempt_count_sub(cnt - 1); - - if (unlikely(!in_interrupt() && local_softirq_pending())) { - /* - * Run softirq if any pending. And do it in its own stack - * as we may be calling this deep in a task call stack already. - */ - do_softirq(); - } - - preempt_count_dec(); -#ifdef CONFIG_TRACE_IRQFLAGS - local_irq_enable(); -#endif - preempt_check_resched(); -} -EXPORT_SYMBOL(__local_bh_enable_ip); - -/* - * We restart softirq processing for at most MAX_SOFTIRQ_RESTART times, - * but break the loop if need_resched() is set or after 2 ms. - * The MAX_SOFTIRQ_TIME provides a nice upper bound in most cases, but in - * certain cases, such as stop_machine(), jiffies may cease to - * increment and so we need the MAX_SOFTIRQ_RESTART limit as - * well to make sure we eventually return from this method. - * - * These limits have been established via experimentation. - * The two things to balance is latency against fairness - - * we want to handle softirqs as soon as possible, but they - * should not be able to lock up the box. - */ -#define MAX_SOFTIRQ_TIME msecs_to_jiffies(2) -#define MAX_SOFTIRQ_RESTART 10 - -#ifdef CONFIG_TRACE_IRQFLAGS -/* - * When we run softirqs from irq_exit() and thus on the hardirq stack we need - * to keep the lockdep irq context tracking as tight as possible in order to - * not miss-qualify lock contexts and miss possible deadlocks. - */ - -static inline bool lockdep_softirq_start(void) -{ - bool in_hardirq = false; - - if (trace_hardirq_context(current)) { - in_hardirq = true; - trace_hardirq_exit(); - } - - lockdep_softirq_enter(); - - return in_hardirq; -} - -static inline void lockdep_softirq_end(bool in_hardirq) -{ - lockdep_softirq_exit(); - - if (in_hardirq) - trace_hardirq_enter(); -} -#else -static inline bool lockdep_softirq_start(void) { return false; } -static inline void lockdep_softirq_end(bool in_hardirq) { } -#endif - -asmlinkage __visible void __softirq_entry __do_softirq(void) -{ - unsigned long end = jiffies + MAX_SOFTIRQ_TIME; - unsigned long old_flags = current->flags; - int max_restart = MAX_SOFTIRQ_RESTART; - struct softirq_action *h; - bool in_hardirq; - __u32 pending; - int softirq_bit; - - /* - * Mask out PF_MEMALLOC s current task context is borrowed for the - * softirq. A softirq handled such as network RX might set PF_MEMALLOC - * again if the socket is related to swap - */ - current->flags &= ~PF_MEMALLOC; - - pending = local_softirq_pending(); - account_irq_enter_time(current); - - __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET); - in_hardirq = lockdep_softirq_start(); - -restart: - /* Reset the pending bitmask before enabling irqs */ - set_softirq_pending(0); - - local_irq_enable(); - - h = softirq_vec; - - while ((softirq_bit = ffs(pending))) { - unsigned int vec_nr; - int prev_count; - - h += softirq_bit - 1; - - vec_nr = h - softirq_vec; - prev_count = preempt_count(); - - kstat_incr_softirqs_this_cpu(vec_nr); - - trace_softirq_entry(vec_nr); - h->action(h); - trace_softirq_exit(vec_nr); - if (unlikely(prev_count != preempt_count())) { - pr_err("huh, entered softirq %u %s %p with preempt_count %08x, exited with %08x?\n", - vec_nr, softirq_to_name[vec_nr], h->action, - prev_count, preempt_count()); - preempt_count_set(prev_count); - } - h++; - pending >>= softirq_bit; - } - - rcu_bh_qs(); - local_irq_disable(); - - pending = local_softirq_pending(); - if (pending) { - if (time_before(jiffies, end) && !need_resched() && - --max_restart) - goto restart; - - wakeup_softirqd(); - } - - lockdep_softirq_end(in_hardirq); - account_irq_exit_time(current); - __local_bh_enable(SOFTIRQ_OFFSET); - WARN_ON_ONCE(in_interrupt()); - tsk_restore_flags(current, old_flags, PF_MEMALLOC); -} - -asmlinkage __visible void do_softirq(void) -{ - __u32 pending; - unsigned long flags; - - if (in_interrupt()) - return; - - local_irq_save(flags); - - pending = local_softirq_pending(); - - if (pending && !ksoftirqd_running()) - do_softirq_own_stack(); - - local_irq_restore(flags); -} - -/* - * Enter an interrupt context. - */ -void irq_enter(void) -{ - rcu_irq_enter(); - if (is_idle_task(current) && !in_interrupt()) { - /* - * Prevent raise_softirq from needlessly waking up ksoftirqd - * here, as softirq will be serviced on return from interrupt. - */ - local_bh_disable(); - tick_irq_enter(); - _local_bh_enable(); - } - - __irq_enter(); -} - -static inline void invoke_softirq(void) -{ - if (ksoftirqd_running()) - return; - - if (!force_irqthreads) { -#ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK - /* - * We can safely execute softirq on the current stack if - * it is the irq stack, because it should be near empty - * at this stage. - */ - __do_softirq(); -#else - /* - * Otherwise, irq_exit() is called on the task stack that can - * be potentially deep already. So call softirq in its own stack - * to prevent from any overrun. - */ - do_softirq_own_stack(); -#endif - } else { - wakeup_softirqd(); - } -} - -static inline void tick_irq_exit(void) -{ -#ifdef CONFIG_NO_HZ_COMMON - int cpu = smp_processor_id(); - - /* Make sure that timer wheel updates are propagated */ - if ((idle_cpu(cpu) && !need_resched()) || tick_nohz_full_cpu(cpu)) { - if (!in_interrupt()) - tick_nohz_irq_exit(); - } -#endif -} - -/* - * Exit an interrupt context. Process softirqs if needed and possible: - */ -void irq_exit(void) -{ -#ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED - local_irq_disable(); -#else - WARN_ON_ONCE(!irqs_disabled()); -#endif - - account_irq_exit_time(current); - preempt_count_sub(HARDIRQ_OFFSET); - if (!in_interrupt() && local_softirq_pending()) - invoke_softirq(); - - tick_irq_exit(); - rcu_irq_exit(); - trace_hardirq_exit(); /* must be last! */ -} - -/* - * This function must run with irqs disabled! - */ -inline void raise_softirq_irqoff(unsigned int nr) -{ - __raise_softirq_irqoff(nr); - - /* - * If we're in an interrupt or softirq, we're done - * (this also catches softirq-disabled code). We will - * actually run the softirq once we return from - * the irq or softirq. - * - * Otherwise we wake up ksoftirqd to make sure we - * schedule the softirq soon. - */ - if (!in_interrupt()) - wakeup_softirqd(); -} - -void raise_softirq(unsigned int nr) -{ - unsigned long flags; - - local_irq_save(flags); - raise_softirq_irqoff(nr); - local_irq_restore(flags); -} - -void __raise_softirq_irqoff(unsigned int nr) -{ - trace_softirq_raise(nr); - or_softirq_pending(1UL << nr); -} - -void open_softirq(int nr, void (*action)(struct softirq_action *)) -{ - softirq_vec[nr].action = action; -} - -/* - * Tasklets - */ -struct tasklet_head { - struct tasklet_struct *head; - struct tasklet_struct **tail; -}; - -static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec); -static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec); - -void __tasklet_schedule(struct tasklet_struct *t) -{ - unsigned long flags; - - local_irq_save(flags); - t->next = NULL; - *__this_cpu_read(tasklet_vec.tail) = t; - __this_cpu_write(tasklet_vec.tail, &(t->next)); - raise_softirq_irqoff(TASKLET_SOFTIRQ); - local_irq_restore(flags); -} -EXPORT_SYMBOL(__tasklet_schedule); - -void __tasklet_hi_schedule(struct tasklet_struct *t) -{ - unsigned long flags; - - local_irq_save(flags); - t->next = NULL; - *__this_cpu_read(tasklet_hi_vec.tail) = t; - __this_cpu_write(tasklet_hi_vec.tail, &(t->next)); - raise_softirq_irqoff(HI_SOFTIRQ); - local_irq_restore(flags); -} -EXPORT_SYMBOL(__tasklet_hi_schedule); - -void __tasklet_hi_schedule_first(struct tasklet_struct *t) -{ - BUG_ON(!irqs_disabled()); - - t->next = __this_cpu_read(tasklet_hi_vec.head); - __this_cpu_write(tasklet_hi_vec.head, t); - __raise_softirq_irqoff(HI_SOFTIRQ); -} -EXPORT_SYMBOL(__tasklet_hi_schedule_first); - -static __latent_entropy void tasklet_action(struct softirq_action *a) -{ - struct tasklet_struct *list; - - local_irq_disable(); - list = __this_cpu_read(tasklet_vec.head); - __this_cpu_write(tasklet_vec.head, NULL); - __this_cpu_write(tasklet_vec.tail, this_cpu_ptr(&tasklet_vec.head)); - local_irq_enable(); - - while (list) { - struct tasklet_struct *t = list; - - list = list->next; - - if (tasklet_trylock(t)) { - if (!atomic_read(&t->count)) { - if (!test_and_clear_bit(TASKLET_STATE_SCHED, - &t->state)) - BUG(); - t->func(t->data); - tasklet_unlock(t); - continue; - } - tasklet_unlock(t); - } - - local_irq_disable(); - t->next = NULL; - *__this_cpu_read(tasklet_vec.tail) = t; - __this_cpu_write(tasklet_vec.tail, &(t->next)); - __raise_softirq_irqoff(TASKLET_SOFTIRQ); - local_irq_enable(); - } -} - -static __latent_entropy void tasklet_hi_action(struct softirq_action *a) -{ - struct tasklet_struct *list; - - local_irq_disable(); - list = __this_cpu_read(tasklet_hi_vec.head); - __this_cpu_write(tasklet_hi_vec.head, NULL); - __this_cpu_write(tasklet_hi_vec.tail, this_cpu_ptr(&tasklet_hi_vec.head)); - local_irq_enable(); - - while (list) { - struct tasklet_struct *t = list; - - list = list->next; - - if (tasklet_trylock(t)) { - if (!atomic_read(&t->count)) { - if (!test_and_clear_bit(TASKLET_STATE_SCHED, - &t->state)) - BUG(); - t->func(t->data); - tasklet_unlock(t); - continue; - } - tasklet_unlock(t); - } - - local_irq_disable(); - t->next = NULL; - *__this_cpu_read(tasklet_hi_vec.tail) = t; - __this_cpu_write(tasklet_hi_vec.tail, &(t->next)); - __raise_softirq_irqoff(HI_SOFTIRQ); - local_irq_enable(); - } -} - -void tasklet_init(struct tasklet_struct *t, - void (*func)(unsigned long), unsigned long data) -{ - t->next = NULL; - t->state = 0; - atomic_set(&t->count, 0); - t->func = func; - t->data = data; -} -EXPORT_SYMBOL(tasklet_init); - -void tasklet_kill(struct tasklet_struct *t) -{ - if (in_interrupt()) - pr_notice("Attempt to kill tasklet from interrupt\n"); - - while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) { - do { - yield(); - } while (test_bit(TASKLET_STATE_SCHED, &t->state)); - } - tasklet_unlock_wait(t); - clear_bit(TASKLET_STATE_SCHED, &t->state); -} -EXPORT_SYMBOL(tasklet_kill); - -/* - * tasklet_hrtimer - */ - -/* - * The trampoline is called when the hrtimer expires. It schedules a tasklet - * to run __tasklet_hrtimer_trampoline() which in turn will call the intended - * hrtimer callback, but from softirq context. - */ -static enum hrtimer_restart __hrtimer_tasklet_trampoline(struct hrtimer *timer) -{ - struct tasklet_hrtimer *ttimer = - container_of(timer, struct tasklet_hrtimer, timer); - - tasklet_hi_schedule(&ttimer->tasklet); - return HRTIMER_NORESTART; -} - -/* - * Helper function which calls the hrtimer callback from - * tasklet/softirq context - */ -static void __tasklet_hrtimer_trampoline(unsigned long data) -{ - struct tasklet_hrtimer *ttimer = (void *)data; - enum hrtimer_restart restart; - - restart = ttimer->function(&ttimer->timer); - if (restart != HRTIMER_NORESTART) - hrtimer_restart(&ttimer->timer); -} - -/** - * tasklet_hrtimer_init - Init a tasklet/hrtimer combo for softirq callbacks - * @ttimer: tasklet_hrtimer which is initialized - * @function: hrtimer callback function which gets called from softirq context - * @which_clock: clock id (CLOCK_MONOTONIC/CLOCK_REALTIME) - * @mode: hrtimer mode (HRTIMER_MODE_ABS/HRTIMER_MODE_REL) - */ -void tasklet_hrtimer_init(struct tasklet_hrtimer *ttimer, - enum hrtimer_restart (*function)(struct hrtimer *), - clockid_t which_clock, enum hrtimer_mode mode) -{ - hrtimer_init(&ttimer->timer, which_clock, mode); - ttimer->timer.function = __hrtimer_tasklet_trampoline; - tasklet_init(&ttimer->tasklet, __tasklet_hrtimer_trampoline, - (unsigned long)ttimer); - ttimer->function = function; -} -EXPORT_SYMBOL_GPL(tasklet_hrtimer_init); - -void __init softirq_init(void) -{ - int cpu; - - for_each_possible_cpu(cpu) { - per_cpu(tasklet_vec, cpu).tail = - &per_cpu(tasklet_vec, cpu).head; - per_cpu(tasklet_hi_vec, cpu).tail = - &per_cpu(tasklet_hi_vec, cpu).head; - } - - open_softirq(TASKLET_SOFTIRQ, tasklet_action); - open_softirq(HI_SOFTIRQ, tasklet_hi_action); -} - -static int ksoftirqd_should_run(unsigned int cpu) -{ - return local_softirq_pending(); -} - -static void run_ksoftirqd(unsigned int cpu) -{ - local_irq_disable(); - if (local_softirq_pending()) { - /* - * We can safely run softirq on inline stack, as we are not deep - * in the task stack here. - */ - __do_softirq(); - local_irq_enable(); - cond_resched_rcu_qs(); - return; - } - local_irq_enable(); -} - -#ifdef CONFIG_HOTPLUG_CPU -/* - * tasklet_kill_immediate is called to remove a tasklet which can already be - * scheduled for execution on @cpu. - * - * Unlike tasklet_kill, this function removes the tasklet - * _immediately_, even if the tasklet is in TASKLET_STATE_SCHED state. - * - * When this function is called, @cpu must be in the CPU_DEAD state. - */ -void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu) -{ - struct tasklet_struct **i; - - BUG_ON(cpu_online(cpu)); - BUG_ON(test_bit(TASKLET_STATE_RUN, &t->state)); - - if (!test_bit(TASKLET_STATE_SCHED, &t->state)) - return; - - /* CPU is dead, so no lock needed. */ - for (i = &per_cpu(tasklet_vec, cpu).head; *i; i = &(*i)->next) { - if (*i == t) { - *i = t->next; - /* If this was the tail element, move the tail ptr */ - if (*i == NULL) - per_cpu(tasklet_vec, cpu).tail = i; - return; - } - } - BUG(); -} - -static int takeover_tasklets(unsigned int cpu) -{ - /* CPU is dead, so no lock needed. */ - local_irq_disable(); - - /* Find end, append list for that CPU. */ - if (&per_cpu(tasklet_vec, cpu).head != per_cpu(tasklet_vec, cpu).tail) { - *__this_cpu_read(tasklet_vec.tail) = per_cpu(tasklet_vec, cpu).head; - this_cpu_write(tasklet_vec.tail, per_cpu(tasklet_vec, cpu).tail); - per_cpu(tasklet_vec, cpu).head = NULL; - per_cpu(tasklet_vec, cpu).tail = &per_cpu(tasklet_vec, cpu).head; - } - raise_softirq_irqoff(TASKLET_SOFTIRQ); - - if (&per_cpu(tasklet_hi_vec, cpu).head != per_cpu(tasklet_hi_vec, cpu).tail) { - *__this_cpu_read(tasklet_hi_vec.tail) = per_cpu(tasklet_hi_vec, cpu).head; - __this_cpu_write(tasklet_hi_vec.tail, per_cpu(tasklet_hi_vec, cpu).tail); - per_cpu(tasklet_hi_vec, cpu).head = NULL; - per_cpu(tasklet_hi_vec, cpu).tail = &per_cpu(tasklet_hi_vec, cpu).head; - } - raise_softirq_irqoff(HI_SOFTIRQ); - - local_irq_enable(); - return 0; -} -#else -#define takeover_tasklets NULL -#endif /* CONFIG_HOTPLUG_CPU */ - -static struct smp_hotplug_thread softirq_threads = { - .store = &ksoftirqd, - .thread_should_run = ksoftirqd_should_run, - .thread_fn = run_ksoftirqd, - .thread_comm = "ksoftirqd/%u", -}; - -static __init int spawn_ksoftirqd(void) -{ - cpuhp_setup_state_nocalls(CPUHP_SOFTIRQ_DEAD, "softirq:dead", NULL, - takeover_tasklets); - BUG_ON(smpboot_register_percpu_thread(&softirq_threads)); - - return 0; -} -early_initcall(spawn_ksoftirqd); - -/* - * [ These __weak aliases are kept in a separate compilation unit, so that - * GCC does not inline them incorrectly. ] - */ - -int __init __weak early_irq_init(void) -{ - return 0; -} - -int __init __weak arch_probe_nr_irqs(void) -{ - return NR_IRQS_LEGACY; -} - -int __init __weak arch_early_irq_init(void) -{ - return 0; -} - -unsigned int __weak arch_dynirq_lower_bound(unsigned int from) -{ - return from; -} diff --git a/src/linux/kernel/sys.c b/src/linux/kernel/sys.c deleted file mode 100644 index 89d5be4..0000000 --- a/src/linux/kernel/sys.c +++ /dev/null @@ -1,2435 +0,0 @@ -/* - * linux/kernel/sys.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -/* Move somewhere else to avoid recompiling? */ -#include - -#include -#include -#include - -#ifndef SET_UNALIGN_CTL -# define SET_UNALIGN_CTL(a, b) (-EINVAL) -#endif -#ifndef GET_UNALIGN_CTL -# define GET_UNALIGN_CTL(a, b) (-EINVAL) -#endif -#ifndef SET_FPEMU_CTL -# define SET_FPEMU_CTL(a, b) (-EINVAL) -#endif -#ifndef GET_FPEMU_CTL -# define GET_FPEMU_CTL(a, b) (-EINVAL) -#endif -#ifndef SET_FPEXC_CTL -# define SET_FPEXC_CTL(a, b) (-EINVAL) -#endif -#ifndef GET_FPEXC_CTL -# define GET_FPEXC_CTL(a, b) (-EINVAL) -#endif -#ifndef GET_ENDIAN -# define GET_ENDIAN(a, b) (-EINVAL) -#endif -#ifndef SET_ENDIAN -# define SET_ENDIAN(a, b) (-EINVAL) -#endif -#ifndef GET_TSC_CTL -# define GET_TSC_CTL(a) (-EINVAL) -#endif -#ifndef SET_TSC_CTL -# define SET_TSC_CTL(a) (-EINVAL) -#endif -#ifndef MPX_ENABLE_MANAGEMENT -# define MPX_ENABLE_MANAGEMENT() (-EINVAL) -#endif -#ifndef MPX_DISABLE_MANAGEMENT -# define MPX_DISABLE_MANAGEMENT() (-EINVAL) -#endif -#ifndef GET_FP_MODE -# define GET_FP_MODE(a) (-EINVAL) -#endif -#ifndef SET_FP_MODE -# define SET_FP_MODE(a,b) (-EINVAL) -#endif - -/* - * this is where the system-wide overflow UID and GID are defined, for - * architectures that now have 32-bit UID/GID but didn't in the past - */ - -int overflowuid = DEFAULT_OVERFLOWUID; -int overflowgid = DEFAULT_OVERFLOWGID; - -EXPORT_SYMBOL(overflowuid); -EXPORT_SYMBOL(overflowgid); - -/* - * the same as above, but for filesystems which can only store a 16-bit - * UID and GID. as such, this is needed on all architectures - */ - -int fs_overflowuid = DEFAULT_FS_OVERFLOWUID; -int fs_overflowgid = DEFAULT_FS_OVERFLOWUID; - -EXPORT_SYMBOL(fs_overflowuid); -EXPORT_SYMBOL(fs_overflowgid); - -/* - * Returns true if current's euid is same as p's uid or euid, - * or has CAP_SYS_NICE to p's user_ns. - * - * Called with rcu_read_lock, creds are safe - */ -static bool set_one_prio_perm(struct task_struct *p) -{ - const struct cred *cred = current_cred(), *pcred = __task_cred(p); - - if (uid_eq(pcred->uid, cred->euid) || - uid_eq(pcred->euid, cred->euid)) - return true; - if (ns_capable(pcred->user_ns, CAP_SYS_NICE)) - return true; - return false; -} - -/* - * set the priority of a task - * - the caller must hold the RCU read lock - */ -static int set_one_prio(struct task_struct *p, int niceval, int error) -{ - int no_nice; - - if (!set_one_prio_perm(p)) { - error = -EPERM; - goto out; - } - if (niceval < task_nice(p) && !can_nice(p, niceval)) { - error = -EACCES; - goto out; - } - no_nice = security_task_setnice(p, niceval); - if (no_nice) { - error = no_nice; - goto out; - } - if (error == -ESRCH) - error = 0; - set_user_nice(p, niceval); -out: - return error; -} - -SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval) -{ - struct task_struct *g, *p; - struct user_struct *user; - const struct cred *cred = current_cred(); - int error = -EINVAL; - struct pid *pgrp; - kuid_t uid; - - if (which > PRIO_USER || which < PRIO_PROCESS) - goto out; - - /* normalize: avoid signed division (rounding problems) */ - error = -ESRCH; - if (niceval < MIN_NICE) - niceval = MIN_NICE; - if (niceval > MAX_NICE) - niceval = MAX_NICE; - - rcu_read_lock(); - read_lock(&tasklist_lock); - switch (which) { - case PRIO_PROCESS: - if (who) - p = find_task_by_vpid(who); - else - p = current; - if (p) - error = set_one_prio(p, niceval, error); - break; - case PRIO_PGRP: - if (who) - pgrp = find_vpid(who); - else - pgrp = task_pgrp(current); - do_each_pid_thread(pgrp, PIDTYPE_PGID, p) { - error = set_one_prio(p, niceval, error); - } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); - break; - case PRIO_USER: - uid = make_kuid(cred->user_ns, who); - user = cred->user; - if (!who) - uid = cred->uid; - else if (!uid_eq(uid, cred->uid)) { - user = find_user(uid); - if (!user) - goto out_unlock; /* No processes for this user */ - } - do_each_thread(g, p) { - if (uid_eq(task_uid(p), uid) && task_pid_vnr(p)) - error = set_one_prio(p, niceval, error); - } while_each_thread(g, p); - if (!uid_eq(uid, cred->uid)) - free_uid(user); /* For find_user() */ - break; - } -out_unlock: - read_unlock(&tasklist_lock); - rcu_read_unlock(); -out: - return error; -} - -/* - * Ugh. To avoid negative return values, "getpriority()" will - * not return the normal nice-value, but a negated value that - * has been offset by 20 (ie it returns 40..1 instead of -20..19) - * to stay compatible. - */ -SYSCALL_DEFINE2(getpriority, int, which, int, who) -{ - struct task_struct *g, *p; - struct user_struct *user; - const struct cred *cred = current_cred(); - long niceval, retval = -ESRCH; - struct pid *pgrp; - kuid_t uid; - - if (which > PRIO_USER || which < PRIO_PROCESS) - return -EINVAL; - - rcu_read_lock(); - read_lock(&tasklist_lock); - switch (which) { - case PRIO_PROCESS: - if (who) - p = find_task_by_vpid(who); - else - p = current; - if (p) { - niceval = nice_to_rlimit(task_nice(p)); - if (niceval > retval) - retval = niceval; - } - break; - case PRIO_PGRP: - if (who) - pgrp = find_vpid(who); - else - pgrp = task_pgrp(current); - do_each_pid_thread(pgrp, PIDTYPE_PGID, p) { - niceval = nice_to_rlimit(task_nice(p)); - if (niceval > retval) - retval = niceval; - } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); - break; - case PRIO_USER: - uid = make_kuid(cred->user_ns, who); - user = cred->user; - if (!who) - uid = cred->uid; - else if (!uid_eq(uid, cred->uid)) { - user = find_user(uid); - if (!user) - goto out_unlock; /* No processes for this user */ - } - do_each_thread(g, p) { - if (uid_eq(task_uid(p), uid) && task_pid_vnr(p)) { - niceval = nice_to_rlimit(task_nice(p)); - if (niceval > retval) - retval = niceval; - } - } while_each_thread(g, p); - if (!uid_eq(uid, cred->uid)) - free_uid(user); /* for find_user() */ - break; - } -out_unlock: - read_unlock(&tasklist_lock); - rcu_read_unlock(); - - return retval; -} - -/* - * Unprivileged users may change the real gid to the effective gid - * or vice versa. (BSD-style) - * - * If you set the real gid at all, or set the effective gid to a value not - * equal to the real gid, then the saved gid is set to the new effective gid. - * - * This makes it possible for a setgid program to completely drop its - * privileges, which is often a useful assertion to make when you are doing - * a security audit over a program. - * - * The general idea is that a program which uses just setregid() will be - * 100% compatible with BSD. A program which uses just setgid() will be - * 100% compatible with POSIX with saved IDs. - * - * SMP: There are not races, the GIDs are checked only by filesystem - * operations (as far as semantic preservation is concerned). - */ -#ifdef CONFIG_MULTIUSER -SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid) -{ - struct user_namespace *ns = current_user_ns(); - const struct cred *old; - struct cred *new; - int retval; - kgid_t krgid, kegid; - - krgid = make_kgid(ns, rgid); - kegid = make_kgid(ns, egid); - - if ((rgid != (gid_t) -1) && !gid_valid(krgid)) - return -EINVAL; - if ((egid != (gid_t) -1) && !gid_valid(kegid)) - return -EINVAL; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - old = current_cred(); - - retval = -EPERM; - if (rgid != (gid_t) -1) { - if (gid_eq(old->gid, krgid) || - gid_eq(old->egid, krgid) || - ns_capable(old->user_ns, CAP_SETGID)) - new->gid = krgid; - else - goto error; - } - if (egid != (gid_t) -1) { - if (gid_eq(old->gid, kegid) || - gid_eq(old->egid, kegid) || - gid_eq(old->sgid, kegid) || - ns_capable(old->user_ns, CAP_SETGID)) - new->egid = kegid; - else - goto error; - } - - if (rgid != (gid_t) -1 || - (egid != (gid_t) -1 && !gid_eq(kegid, old->gid))) - new->sgid = new->egid; - new->fsgid = new->egid; - - return commit_creds(new); - -error: - abort_creds(new); - return retval; -} - -/* - * setgid() is implemented like SysV w/ SAVED_IDS - * - * SMP: Same implicit races as above. - */ -SYSCALL_DEFINE1(setgid, gid_t, gid) -{ - struct user_namespace *ns = current_user_ns(); - const struct cred *old; - struct cred *new; - int retval; - kgid_t kgid; - - kgid = make_kgid(ns, gid); - if (!gid_valid(kgid)) - return -EINVAL; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - old = current_cred(); - - retval = -EPERM; - if (ns_capable(old->user_ns, CAP_SETGID)) - new->gid = new->egid = new->sgid = new->fsgid = kgid; - else if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->sgid)) - new->egid = new->fsgid = kgid; - else - goto error; - - return commit_creds(new); - -error: - abort_creds(new); - return retval; -} - -/* - * change the user struct in a credentials set to match the new UID - */ -static int set_user(struct cred *new) -{ - struct user_struct *new_user; - - new_user = alloc_uid(new->uid); - if (!new_user) - return -EAGAIN; - - /* - * We don't fail in case of NPROC limit excess here because too many - * poorly written programs don't check set*uid() return code, assuming - * it never fails if called by root. We may still enforce NPROC limit - * for programs doing set*uid()+execve() by harmlessly deferring the - * failure to the execve() stage. - */ - if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) && - new_user != INIT_USER) - current->flags |= PF_NPROC_EXCEEDED; - else - current->flags &= ~PF_NPROC_EXCEEDED; - - free_uid(new->user); - new->user = new_user; - return 0; -} - -/* - * Unprivileged users may change the real uid to the effective uid - * or vice versa. (BSD-style) - * - * If you set the real uid at all, or set the effective uid to a value not - * equal to the real uid, then the saved uid is set to the new effective uid. - * - * This makes it possible for a setuid program to completely drop its - * privileges, which is often a useful assertion to make when you are doing - * a security audit over a program. - * - * The general idea is that a program which uses just setreuid() will be - * 100% compatible with BSD. A program which uses just setuid() will be - * 100% compatible with POSIX with saved IDs. - */ -SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid) -{ - struct user_namespace *ns = current_user_ns(); - const struct cred *old; - struct cred *new; - int retval; - kuid_t kruid, keuid; - - kruid = make_kuid(ns, ruid); - keuid = make_kuid(ns, euid); - - if ((ruid != (uid_t) -1) && !uid_valid(kruid)) - return -EINVAL; - if ((euid != (uid_t) -1) && !uid_valid(keuid)) - return -EINVAL; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - old = current_cred(); - - retval = -EPERM; - if (ruid != (uid_t) -1) { - new->uid = kruid; - if (!uid_eq(old->uid, kruid) && - !uid_eq(old->euid, kruid) && - !ns_capable(old->user_ns, CAP_SETUID)) - goto error; - } - - if (euid != (uid_t) -1) { - new->euid = keuid; - if (!uid_eq(old->uid, keuid) && - !uid_eq(old->euid, keuid) && - !uid_eq(old->suid, keuid) && - !ns_capable(old->user_ns, CAP_SETUID)) - goto error; - } - - if (!uid_eq(new->uid, old->uid)) { - retval = set_user(new); - if (retval < 0) - goto error; - } - if (ruid != (uid_t) -1 || - (euid != (uid_t) -1 && !uid_eq(keuid, old->uid))) - new->suid = new->euid; - new->fsuid = new->euid; - - retval = security_task_fix_setuid(new, old, LSM_SETID_RE); - if (retval < 0) - goto error; - - return commit_creds(new); - -error: - abort_creds(new); - return retval; -} - -/* - * setuid() is implemented like SysV with SAVED_IDS - * - * Note that SAVED_ID's is deficient in that a setuid root program - * like sendmail, for example, cannot set its uid to be a normal - * user and then switch back, because if you're root, setuid() sets - * the saved uid too. If you don't like this, blame the bright people - * in the POSIX committee and/or USG. Note that the BSD-style setreuid() - * will allow a root program to temporarily drop privileges and be able to - * regain them by swapping the real and effective uid. - */ -SYSCALL_DEFINE1(setuid, uid_t, uid) -{ - struct user_namespace *ns = current_user_ns(); - const struct cred *old; - struct cred *new; - int retval; - kuid_t kuid; - - kuid = make_kuid(ns, uid); - if (!uid_valid(kuid)) - return -EINVAL; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - old = current_cred(); - - retval = -EPERM; - if (ns_capable(old->user_ns, CAP_SETUID)) { - new->suid = new->uid = kuid; - if (!uid_eq(kuid, old->uid)) { - retval = set_user(new); - if (retval < 0) - goto error; - } - } else if (!uid_eq(kuid, old->uid) && !uid_eq(kuid, new->suid)) { - goto error; - } - - new->fsuid = new->euid = kuid; - - retval = security_task_fix_setuid(new, old, LSM_SETID_ID); - if (retval < 0) - goto error; - - return commit_creds(new); - -error: - abort_creds(new); - return retval; -} - - -/* - * This function implements a generic ability to update ruid, euid, - * and suid. This allows you to implement the 4.4 compatible seteuid(). - */ -SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid) -{ - struct user_namespace *ns = current_user_ns(); - const struct cred *old; - struct cred *new; - int retval; - kuid_t kruid, keuid, ksuid; - - kruid = make_kuid(ns, ruid); - keuid = make_kuid(ns, euid); - ksuid = make_kuid(ns, suid); - - if ((ruid != (uid_t) -1) && !uid_valid(kruid)) - return -EINVAL; - - if ((euid != (uid_t) -1) && !uid_valid(keuid)) - return -EINVAL; - - if ((suid != (uid_t) -1) && !uid_valid(ksuid)) - return -EINVAL; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - - old = current_cred(); - - retval = -EPERM; - if (!ns_capable(old->user_ns, CAP_SETUID)) { - if (ruid != (uid_t) -1 && !uid_eq(kruid, old->uid) && - !uid_eq(kruid, old->euid) && !uid_eq(kruid, old->suid)) - goto error; - if (euid != (uid_t) -1 && !uid_eq(keuid, old->uid) && - !uid_eq(keuid, old->euid) && !uid_eq(keuid, old->suid)) - goto error; - if (suid != (uid_t) -1 && !uid_eq(ksuid, old->uid) && - !uid_eq(ksuid, old->euid) && !uid_eq(ksuid, old->suid)) - goto error; - } - - if (ruid != (uid_t) -1) { - new->uid = kruid; - if (!uid_eq(kruid, old->uid)) { - retval = set_user(new); - if (retval < 0) - goto error; - } - } - if (euid != (uid_t) -1) - new->euid = keuid; - if (suid != (uid_t) -1) - new->suid = ksuid; - new->fsuid = new->euid; - - retval = security_task_fix_setuid(new, old, LSM_SETID_RES); - if (retval < 0) - goto error; - - return commit_creds(new); - -error: - abort_creds(new); - return retval; -} - -SYSCALL_DEFINE3(getresuid, uid_t __user *, ruidp, uid_t __user *, euidp, uid_t __user *, suidp) -{ - const struct cred *cred = current_cred(); - int retval; - uid_t ruid, euid, suid; - - ruid = from_kuid_munged(cred->user_ns, cred->uid); - euid = from_kuid_munged(cred->user_ns, cred->euid); - suid = from_kuid_munged(cred->user_ns, cred->suid); - - retval = put_user(ruid, ruidp); - if (!retval) { - retval = put_user(euid, euidp); - if (!retval) - return put_user(suid, suidp); - } - return retval; -} - -/* - * Same as above, but for rgid, egid, sgid. - */ -SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid) -{ - struct user_namespace *ns = current_user_ns(); - const struct cred *old; - struct cred *new; - int retval; - kgid_t krgid, kegid, ksgid; - - krgid = make_kgid(ns, rgid); - kegid = make_kgid(ns, egid); - ksgid = make_kgid(ns, sgid); - - if ((rgid != (gid_t) -1) && !gid_valid(krgid)) - return -EINVAL; - if ((egid != (gid_t) -1) && !gid_valid(kegid)) - return -EINVAL; - if ((sgid != (gid_t) -1) && !gid_valid(ksgid)) - return -EINVAL; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - old = current_cred(); - - retval = -EPERM; - if (!ns_capable(old->user_ns, CAP_SETGID)) { - if (rgid != (gid_t) -1 && !gid_eq(krgid, old->gid) && - !gid_eq(krgid, old->egid) && !gid_eq(krgid, old->sgid)) - goto error; - if (egid != (gid_t) -1 && !gid_eq(kegid, old->gid) && - !gid_eq(kegid, old->egid) && !gid_eq(kegid, old->sgid)) - goto error; - if (sgid != (gid_t) -1 && !gid_eq(ksgid, old->gid) && - !gid_eq(ksgid, old->egid) && !gid_eq(ksgid, old->sgid)) - goto error; - } - - if (rgid != (gid_t) -1) - new->gid = krgid; - if (egid != (gid_t) -1) - new->egid = kegid; - if (sgid != (gid_t) -1) - new->sgid = ksgid; - new->fsgid = new->egid; - - return commit_creds(new); - -error: - abort_creds(new); - return retval; -} - -SYSCALL_DEFINE3(getresgid, gid_t __user *, rgidp, gid_t __user *, egidp, gid_t __user *, sgidp) -{ - const struct cred *cred = current_cred(); - int retval; - gid_t rgid, egid, sgid; - - rgid = from_kgid_munged(cred->user_ns, cred->gid); - egid = from_kgid_munged(cred->user_ns, cred->egid); - sgid = from_kgid_munged(cred->user_ns, cred->sgid); - - retval = put_user(rgid, rgidp); - if (!retval) { - retval = put_user(egid, egidp); - if (!retval) - retval = put_user(sgid, sgidp); - } - - return retval; -} - - -/* - * "setfsuid()" sets the fsuid - the uid used for filesystem checks. This - * is used for "access()" and for the NFS daemon (letting nfsd stay at - * whatever uid it wants to). It normally shadows "euid", except when - * explicitly set by setfsuid() or for access.. - */ -SYSCALL_DEFINE1(setfsuid, uid_t, uid) -{ - const struct cred *old; - struct cred *new; - uid_t old_fsuid; - kuid_t kuid; - - old = current_cred(); - old_fsuid = from_kuid_munged(old->user_ns, old->fsuid); - - kuid = make_kuid(old->user_ns, uid); - if (!uid_valid(kuid)) - return old_fsuid; - - new = prepare_creds(); - if (!new) - return old_fsuid; - - if (uid_eq(kuid, old->uid) || uid_eq(kuid, old->euid) || - uid_eq(kuid, old->suid) || uid_eq(kuid, old->fsuid) || - ns_capable(old->user_ns, CAP_SETUID)) { - if (!uid_eq(kuid, old->fsuid)) { - new->fsuid = kuid; - if (security_task_fix_setuid(new, old, LSM_SETID_FS) == 0) - goto change_okay; - } - } - - abort_creds(new); - return old_fsuid; - -change_okay: - commit_creds(new); - return old_fsuid; -} - -/* - * Samma pÃ¥ svenska.. - */ -SYSCALL_DEFINE1(setfsgid, gid_t, gid) -{ - const struct cred *old; - struct cred *new; - gid_t old_fsgid; - kgid_t kgid; - - old = current_cred(); - old_fsgid = from_kgid_munged(old->user_ns, old->fsgid); - - kgid = make_kgid(old->user_ns, gid); - if (!gid_valid(kgid)) - return old_fsgid; - - new = prepare_creds(); - if (!new) - return old_fsgid; - - if (gid_eq(kgid, old->gid) || gid_eq(kgid, old->egid) || - gid_eq(kgid, old->sgid) || gid_eq(kgid, old->fsgid) || - ns_capable(old->user_ns, CAP_SETGID)) { - if (!gid_eq(kgid, old->fsgid)) { - new->fsgid = kgid; - goto change_okay; - } - } - - abort_creds(new); - return old_fsgid; - -change_okay: - commit_creds(new); - return old_fsgid; -} -#endif /* CONFIG_MULTIUSER */ - -/** - * sys_getpid - return the thread group id of the current process - * - * Note, despite the name, this returns the tgid not the pid. The tgid and - * the pid are identical unless CLONE_THREAD was specified on clone() in - * which case the tgid is the same in all threads of the same group. - * - * This is SMP safe as current->tgid does not change. - */ -SYSCALL_DEFINE0(getpid) -{ - return task_tgid_vnr(current); -} - -/* Thread ID - the internal kernel "pid" */ -SYSCALL_DEFINE0(gettid) -{ - return task_pid_vnr(current); -} - -/* - * Accessing ->real_parent is not SMP-safe, it could - * change from under us. However, we can use a stale - * value of ->real_parent under rcu_read_lock(), see - * release_task()->call_rcu(delayed_put_task_struct). - */ -SYSCALL_DEFINE0(getppid) -{ - int pid; - - rcu_read_lock(); - pid = task_tgid_vnr(rcu_dereference(current->real_parent)); - rcu_read_unlock(); - - return pid; -} - -SYSCALL_DEFINE0(getuid) -{ - /* Only we change this so SMP safe */ - return from_kuid_munged(current_user_ns(), current_uid()); -} - -SYSCALL_DEFINE0(geteuid) -{ - /* Only we change this so SMP safe */ - return from_kuid_munged(current_user_ns(), current_euid()); -} - -SYSCALL_DEFINE0(getgid) -{ - /* Only we change this so SMP safe */ - return from_kgid_munged(current_user_ns(), current_gid()); -} - -SYSCALL_DEFINE0(getegid) -{ - /* Only we change this so SMP safe */ - return from_kgid_munged(current_user_ns(), current_egid()); -} - -void do_sys_times(struct tms *tms) -{ - cputime_t tgutime, tgstime, cutime, cstime; - - thread_group_cputime_adjusted(current, &tgutime, &tgstime); - cutime = current->signal->cutime; - cstime = current->signal->cstime; - tms->tms_utime = cputime_to_clock_t(tgutime); - tms->tms_stime = cputime_to_clock_t(tgstime); - tms->tms_cutime = cputime_to_clock_t(cutime); - tms->tms_cstime = cputime_to_clock_t(cstime); -} - -SYSCALL_DEFINE1(times, struct tms __user *, tbuf) -{ - if (tbuf) { - struct tms tmp; - - do_sys_times(&tmp); - if (copy_to_user(tbuf, &tmp, sizeof(struct tms))) - return -EFAULT; - } - force_successful_syscall_return(); - return (long) jiffies_64_to_clock_t(get_jiffies_64()); -} - -/* - * This needs some heavy checking ... - * I just haven't the stomach for it. I also don't fully - * understand sessions/pgrp etc. Let somebody who does explain it. - * - * OK, I think I have the protection semantics right.... this is really - * only important on a multi-user system anyway, to make sure one user - * can't send a signal to a process owned by another. -TYT, 12/12/91 - * - * !PF_FORKNOEXEC check to conform completely to POSIX. - */ -SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid) -{ - struct task_struct *p; - struct task_struct *group_leader = current->group_leader; - struct pid *pgrp; - int err; - - if (!pid) - pid = task_pid_vnr(group_leader); - if (!pgid) - pgid = pid; - if (pgid < 0) - return -EINVAL; - rcu_read_lock(); - - /* From this point forward we keep holding onto the tasklist lock - * so that our parent does not change from under us. -DaveM - */ - write_lock_irq(&tasklist_lock); - - err = -ESRCH; - p = find_task_by_vpid(pid); - if (!p) - goto out; - - err = -EINVAL; - if (!thread_group_leader(p)) - goto out; - - if (same_thread_group(p->real_parent, group_leader)) { - err = -EPERM; - if (task_session(p) != task_session(group_leader)) - goto out; - err = -EACCES; - if (!(p->flags & PF_FORKNOEXEC)) - goto out; - } else { - err = -ESRCH; - if (p != group_leader) - goto out; - } - - err = -EPERM; - if (p->signal->leader) - goto out; - - pgrp = task_pid(p); - if (pgid != pid) { - struct task_struct *g; - - pgrp = find_vpid(pgid); - g = pid_task(pgrp, PIDTYPE_PGID); - if (!g || task_session(g) != task_session(group_leader)) - goto out; - } - - err = security_task_setpgid(p, pgid); - if (err) - goto out; - - if (task_pgrp(p) != pgrp) - change_pid(p, PIDTYPE_PGID, pgrp); - - err = 0; -out: - /* All paths lead to here, thus we are safe. -DaveM */ - write_unlock_irq(&tasklist_lock); - rcu_read_unlock(); - return err; -} - -SYSCALL_DEFINE1(getpgid, pid_t, pid) -{ - struct task_struct *p; - struct pid *grp; - int retval; - - rcu_read_lock(); - if (!pid) - grp = task_pgrp(current); - else { - retval = -ESRCH; - p = find_task_by_vpid(pid); - if (!p) - goto out; - grp = task_pgrp(p); - if (!grp) - goto out; - - retval = security_task_getpgid(p); - if (retval) - goto out; - } - retval = pid_vnr(grp); -out: - rcu_read_unlock(); - return retval; -} - -#ifdef __ARCH_WANT_SYS_GETPGRP - -SYSCALL_DEFINE0(getpgrp) -{ - return sys_getpgid(0); -} - -#endif - -SYSCALL_DEFINE1(getsid, pid_t, pid) -{ - struct task_struct *p; - struct pid *sid; - int retval; - - rcu_read_lock(); - if (!pid) - sid = task_session(current); - else { - retval = -ESRCH; - p = find_task_by_vpid(pid); - if (!p) - goto out; - sid = task_session(p); - if (!sid) - goto out; - - retval = security_task_getsid(p); - if (retval) - goto out; - } - retval = pid_vnr(sid); -out: - rcu_read_unlock(); - return retval; -} - -static void set_special_pids(struct pid *pid) -{ - struct task_struct *curr = current->group_leader; - - if (task_session(curr) != pid) - change_pid(curr, PIDTYPE_SID, pid); - - if (task_pgrp(curr) != pid) - change_pid(curr, PIDTYPE_PGID, pid); -} - -SYSCALL_DEFINE0(setsid) -{ - struct task_struct *group_leader = current->group_leader; - struct pid *sid = task_pid(group_leader); - pid_t session = pid_vnr(sid); - int err = -EPERM; - - write_lock_irq(&tasklist_lock); - /* Fail if I am already a session leader */ - if (group_leader->signal->leader) - goto out; - - /* Fail if a process group id already exists that equals the - * proposed session id. - */ - if (pid_task(sid, PIDTYPE_PGID)) - goto out; - - group_leader->signal->leader = 1; - set_special_pids(sid); - - proc_clear_tty(group_leader); - - err = session; -out: - write_unlock_irq(&tasklist_lock); - if (err > 0) { - proc_sid_connector(group_leader); - sched_autogroup_create_attach(group_leader); - } - return err; -} - -DECLARE_RWSEM(uts_sem); - -#ifdef COMPAT_UTS_MACHINE -#define override_architecture(name) \ - (personality(current->personality) == PER_LINUX32 && \ - copy_to_user(name->machine, COMPAT_UTS_MACHINE, \ - sizeof(COMPAT_UTS_MACHINE))) -#else -#define override_architecture(name) 0 -#endif - -/* - * Work around broken programs that cannot handle "Linux 3.0". - * Instead we map 3.x to 2.6.40+x, so e.g. 3.0 would be 2.6.40 - * And we map 4.x to 2.6.60+x, so 4.0 would be 2.6.60. - */ -static int override_release(char __user *release, size_t len) -{ - int ret = 0; - - if (current->personality & UNAME26) { - const char *rest = UTS_RELEASE; - char buf[65] = { 0 }; - int ndots = 0; - unsigned v; - size_t copy; - - while (*rest) { - if (*rest == '.' && ++ndots >= 3) - break; - if (!isdigit(*rest) && *rest != '.') - break; - rest++; - } - v = ((LINUX_VERSION_CODE >> 8) & 0xff) + 60; - copy = clamp_t(size_t, len, 1, sizeof(buf)); - copy = scnprintf(buf, copy, "2.6.%u%s", v, rest); - ret = copy_to_user(release, buf, copy + 1); - } - return ret; -} - -SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name) -{ - int errno = 0; - - down_read(&uts_sem); - if (copy_to_user(name, utsname(), sizeof *name)) - errno = -EFAULT; - up_read(&uts_sem); - - if (!errno && override_release(name->release, sizeof(name->release))) - errno = -EFAULT; - if (!errno && override_architecture(name)) - errno = -EFAULT; - return errno; -} - -#ifdef __ARCH_WANT_SYS_OLD_UNAME -/* - * Old cruft - */ -SYSCALL_DEFINE1(uname, struct old_utsname __user *, name) -{ - int error = 0; - - if (!name) - return -EFAULT; - - down_read(&uts_sem); - if (copy_to_user(name, utsname(), sizeof(*name))) - error = -EFAULT; - up_read(&uts_sem); - - if (!error && override_release(name->release, sizeof(name->release))) - error = -EFAULT; - if (!error && override_architecture(name)) - error = -EFAULT; - return error; -} - -SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name) -{ - int error; - - if (!name) - return -EFAULT; - if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname))) - return -EFAULT; - - down_read(&uts_sem); - error = __copy_to_user(&name->sysname, &utsname()->sysname, - __OLD_UTS_LEN); - error |= __put_user(0, name->sysname + __OLD_UTS_LEN); - error |= __copy_to_user(&name->nodename, &utsname()->nodename, - __OLD_UTS_LEN); - error |= __put_user(0, name->nodename + __OLD_UTS_LEN); - error |= __copy_to_user(&name->release, &utsname()->release, - __OLD_UTS_LEN); - error |= __put_user(0, name->release + __OLD_UTS_LEN); - error |= __copy_to_user(&name->version, &utsname()->version, - __OLD_UTS_LEN); - error |= __put_user(0, name->version + __OLD_UTS_LEN); - error |= __copy_to_user(&name->machine, &utsname()->machine, - __OLD_UTS_LEN); - error |= __put_user(0, name->machine + __OLD_UTS_LEN); - up_read(&uts_sem); - - if (!error && override_architecture(name)) - error = -EFAULT; - if (!error && override_release(name->release, sizeof(name->release))) - error = -EFAULT; - return error ? -EFAULT : 0; -} -#endif - -SYSCALL_DEFINE2(sethostname, char __user *, name, int, len) -{ - int errno; - char tmp[__NEW_UTS_LEN]; - - if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN)) - return -EPERM; - - if (len < 0 || len > __NEW_UTS_LEN) - return -EINVAL; - down_write(&uts_sem); - errno = -EFAULT; - if (!copy_from_user(tmp, name, len)) { - struct new_utsname *u = utsname(); - - memcpy(u->nodename, tmp, len); - memset(u->nodename + len, 0, sizeof(u->nodename) - len); - errno = 0; - uts_proc_notify(UTS_PROC_HOSTNAME); - } - up_write(&uts_sem); - return errno; -} - -#ifdef __ARCH_WANT_SYS_GETHOSTNAME - -SYSCALL_DEFINE2(gethostname, char __user *, name, int, len) -{ - int i, errno; - struct new_utsname *u; - - if (len < 0) - return -EINVAL; - down_read(&uts_sem); - u = utsname(); - i = 1 + strlen(u->nodename); - if (i > len) - i = len; - errno = 0; - if (copy_to_user(name, u->nodename, i)) - errno = -EFAULT; - up_read(&uts_sem); - return errno; -} - -#endif - -/* - * Only setdomainname; getdomainname can be implemented by calling - * uname() - */ -SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len) -{ - int errno; - char tmp[__NEW_UTS_LEN]; - - if (!ns_capable(current->nsproxy->uts_ns->user_ns, CAP_SYS_ADMIN)) - return -EPERM; - if (len < 0 || len > __NEW_UTS_LEN) - return -EINVAL; - - down_write(&uts_sem); - errno = -EFAULT; - if (!copy_from_user(tmp, name, len)) { - struct new_utsname *u = utsname(); - - memcpy(u->domainname, tmp, len); - memset(u->domainname + len, 0, sizeof(u->domainname) - len); - errno = 0; - uts_proc_notify(UTS_PROC_DOMAINNAME); - } - up_write(&uts_sem); - return errno; -} - -SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim) -{ - struct rlimit value; - int ret; - - ret = do_prlimit(current, resource, NULL, &value); - if (!ret) - ret = copy_to_user(rlim, &value, sizeof(*rlim)) ? -EFAULT : 0; - - return ret; -} - -#ifdef __ARCH_WANT_SYS_OLD_GETRLIMIT - -/* - * Back compatibility for getrlimit. Needed for some apps. - */ -SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource, - struct rlimit __user *, rlim) -{ - struct rlimit x; - if (resource >= RLIM_NLIMITS) - return -EINVAL; - - task_lock(current->group_leader); - x = current->signal->rlim[resource]; - task_unlock(current->group_leader); - if (x.rlim_cur > 0x7FFFFFFF) - x.rlim_cur = 0x7FFFFFFF; - if (x.rlim_max > 0x7FFFFFFF) - x.rlim_max = 0x7FFFFFFF; - return copy_to_user(rlim, &x, sizeof(x)) ? -EFAULT : 0; -} - -#endif - -static inline bool rlim64_is_infinity(__u64 rlim64) -{ -#if BITS_PER_LONG < 64 - return rlim64 >= ULONG_MAX; -#else - return rlim64 == RLIM64_INFINITY; -#endif -} - -static void rlim_to_rlim64(const struct rlimit *rlim, struct rlimit64 *rlim64) -{ - if (rlim->rlim_cur == RLIM_INFINITY) - rlim64->rlim_cur = RLIM64_INFINITY; - else - rlim64->rlim_cur = rlim->rlim_cur; - if (rlim->rlim_max == RLIM_INFINITY) - rlim64->rlim_max = RLIM64_INFINITY; - else - rlim64->rlim_max = rlim->rlim_max; -} - -static void rlim64_to_rlim(const struct rlimit64 *rlim64, struct rlimit *rlim) -{ - if (rlim64_is_infinity(rlim64->rlim_cur)) - rlim->rlim_cur = RLIM_INFINITY; - else - rlim->rlim_cur = (unsigned long)rlim64->rlim_cur; - if (rlim64_is_infinity(rlim64->rlim_max)) - rlim->rlim_max = RLIM_INFINITY; - else - rlim->rlim_max = (unsigned long)rlim64->rlim_max; -} - -/* make sure you are allowed to change @tsk limits before calling this */ -int do_prlimit(struct task_struct *tsk, unsigned int resource, - struct rlimit *new_rlim, struct rlimit *old_rlim) -{ - struct rlimit *rlim; - int retval = 0; - - if (resource >= RLIM_NLIMITS) - return -EINVAL; - if (new_rlim) { - if (new_rlim->rlim_cur > new_rlim->rlim_max) - return -EINVAL; - if (resource == RLIMIT_NOFILE && - new_rlim->rlim_max > sysctl_nr_open) - return -EPERM; - } - - /* protect tsk->signal and tsk->sighand from disappearing */ - read_lock(&tasklist_lock); - if (!tsk->sighand) { - retval = -ESRCH; - goto out; - } - - rlim = tsk->signal->rlim + resource; - task_lock(tsk->group_leader); - if (new_rlim) { - /* Keep the capable check against init_user_ns until - cgroups can contain all limits */ - if (new_rlim->rlim_max > rlim->rlim_max && - !capable(CAP_SYS_RESOURCE)) - retval = -EPERM; - if (!retval) - retval = security_task_setrlimit(tsk->group_leader, - resource, new_rlim); - if (resource == RLIMIT_CPU && new_rlim->rlim_cur == 0) { - /* - * The caller is asking for an immediate RLIMIT_CPU - * expiry. But we use the zero value to mean "it was - * never set". So let's cheat and make it one second - * instead - */ - new_rlim->rlim_cur = 1; - } - } - if (!retval) { - if (old_rlim) - *old_rlim = *rlim; - if (new_rlim) - *rlim = *new_rlim; - } - task_unlock(tsk->group_leader); - - /* - * RLIMIT_CPU handling. Note that the kernel fails to return an error - * code if it rejected the user's attempt to set RLIMIT_CPU. This is a - * very long-standing error, and fixing it now risks breakage of - * applications, so we live with it - */ - if (!retval && new_rlim && resource == RLIMIT_CPU && - new_rlim->rlim_cur != RLIM_INFINITY) - update_rlimit_cpu(tsk, new_rlim->rlim_cur); -out: - read_unlock(&tasklist_lock); - return retval; -} - -/* rcu lock must be held */ -static int check_prlimit_permission(struct task_struct *task) -{ - const struct cred *cred = current_cred(), *tcred; - - if (current == task) - return 0; - - tcred = __task_cred(task); - if (uid_eq(cred->uid, tcred->euid) && - uid_eq(cred->uid, tcred->suid) && - uid_eq(cred->uid, tcred->uid) && - gid_eq(cred->gid, tcred->egid) && - gid_eq(cred->gid, tcred->sgid) && - gid_eq(cred->gid, tcred->gid)) - return 0; - if (ns_capable(tcred->user_ns, CAP_SYS_RESOURCE)) - return 0; - - return -EPERM; -} - -SYSCALL_DEFINE4(prlimit64, pid_t, pid, unsigned int, resource, - const struct rlimit64 __user *, new_rlim, - struct rlimit64 __user *, old_rlim) -{ - struct rlimit64 old64, new64; - struct rlimit old, new; - struct task_struct *tsk; - int ret; - - if (new_rlim) { - if (copy_from_user(&new64, new_rlim, sizeof(new64))) - return -EFAULT; - rlim64_to_rlim(&new64, &new); - } - - rcu_read_lock(); - tsk = pid ? find_task_by_vpid(pid) : current; - if (!tsk) { - rcu_read_unlock(); - return -ESRCH; - } - ret = check_prlimit_permission(tsk); - if (ret) { - rcu_read_unlock(); - return ret; - } - get_task_struct(tsk); - rcu_read_unlock(); - - ret = do_prlimit(tsk, resource, new_rlim ? &new : NULL, - old_rlim ? &old : NULL); - - if (!ret && old_rlim) { - rlim_to_rlim64(&old, &old64); - if (copy_to_user(old_rlim, &old64, sizeof(old64))) - ret = -EFAULT; - } - - put_task_struct(tsk); - return ret; -} - -SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim) -{ - struct rlimit new_rlim; - - if (copy_from_user(&new_rlim, rlim, sizeof(*rlim))) - return -EFAULT; - return do_prlimit(current, resource, &new_rlim, NULL); -} - -/* - * It would make sense to put struct rusage in the task_struct, - * except that would make the task_struct be *really big*. After - * task_struct gets moved into malloc'ed memory, it would - * make sense to do this. It will make moving the rest of the information - * a lot simpler! (Which we're not doing right now because we're not - * measuring them yet). - * - * When sampling multiple threads for RUSAGE_SELF, under SMP we might have - * races with threads incrementing their own counters. But since word - * reads are atomic, we either get new values or old values and we don't - * care which for the sums. We always take the siglock to protect reading - * the c* fields from p->signal from races with exit.c updating those - * fields when reaping, so a sample either gets all the additions of a - * given child after it's reaped, or none so this sample is before reaping. - * - * Locking: - * We need to take the siglock for CHILDEREN, SELF and BOTH - * for the cases current multithreaded, non-current single threaded - * non-current multithreaded. Thread traversal is now safe with - * the siglock held. - * Strictly speaking, we donot need to take the siglock if we are current and - * single threaded, as no one else can take our signal_struct away, no one - * else can reap the children to update signal->c* counters, and no one else - * can race with the signal-> fields. If we do not take any lock, the - * signal-> fields could be read out of order while another thread was just - * exiting. So we should place a read memory barrier when we avoid the lock. - * On the writer side, write memory barrier is implied in __exit_signal - * as __exit_signal releases the siglock spinlock after updating the signal-> - * fields. But we don't do this yet to keep things simple. - * - */ - -static void accumulate_thread_rusage(struct task_struct *t, struct rusage *r) -{ - r->ru_nvcsw += t->nvcsw; - r->ru_nivcsw += t->nivcsw; - r->ru_minflt += t->min_flt; - r->ru_majflt += t->maj_flt; - r->ru_inblock += task_io_get_inblock(t); - r->ru_oublock += task_io_get_oublock(t); -} - -static void k_getrusage(struct task_struct *p, int who, struct rusage *r) -{ - struct task_struct *t; - unsigned long flags; - cputime_t tgutime, tgstime, utime, stime; - unsigned long maxrss = 0; - - memset((char *)r, 0, sizeof (*r)); - utime = stime = 0; - - if (who == RUSAGE_THREAD) { - task_cputime_adjusted(current, &utime, &stime); - accumulate_thread_rusage(p, r); - maxrss = p->signal->maxrss; - goto out; - } - - if (!lock_task_sighand(p, &flags)) - return; - - switch (who) { - case RUSAGE_BOTH: - case RUSAGE_CHILDREN: - utime = p->signal->cutime; - stime = p->signal->cstime; - r->ru_nvcsw = p->signal->cnvcsw; - r->ru_nivcsw = p->signal->cnivcsw; - r->ru_minflt = p->signal->cmin_flt; - r->ru_majflt = p->signal->cmaj_flt; - r->ru_inblock = p->signal->cinblock; - r->ru_oublock = p->signal->coublock; - maxrss = p->signal->cmaxrss; - - if (who == RUSAGE_CHILDREN) - break; - - case RUSAGE_SELF: - thread_group_cputime_adjusted(p, &tgutime, &tgstime); - utime += tgutime; - stime += tgstime; - r->ru_nvcsw += p->signal->nvcsw; - r->ru_nivcsw += p->signal->nivcsw; - r->ru_minflt += p->signal->min_flt; - r->ru_majflt += p->signal->maj_flt; - r->ru_inblock += p->signal->inblock; - r->ru_oublock += p->signal->oublock; - if (maxrss < p->signal->maxrss) - maxrss = p->signal->maxrss; - t = p; - do { - accumulate_thread_rusage(t, r); - } while_each_thread(p, t); - break; - - default: - BUG(); - } - unlock_task_sighand(p, &flags); - -out: - cputime_to_timeval(utime, &r->ru_utime); - cputime_to_timeval(stime, &r->ru_stime); - - if (who != RUSAGE_CHILDREN) { - struct mm_struct *mm = get_task_mm(p); - - if (mm) { - setmax_mm_hiwater_rss(&maxrss, mm); - mmput(mm); - } - } - r->ru_maxrss = maxrss * (PAGE_SIZE / 1024); /* convert pages to KBs */ -} - -int getrusage(struct task_struct *p, int who, struct rusage __user *ru) -{ - struct rusage r; - - k_getrusage(p, who, &r); - return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0; -} - -SYSCALL_DEFINE2(getrusage, int, who, struct rusage __user *, ru) -{ - if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN && - who != RUSAGE_THREAD) - return -EINVAL; - return getrusage(current, who, ru); -} - -#ifdef CONFIG_COMPAT -COMPAT_SYSCALL_DEFINE2(getrusage, int, who, struct compat_rusage __user *, ru) -{ - struct rusage r; - - if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN && - who != RUSAGE_THREAD) - return -EINVAL; - - k_getrusage(current, who, &r); - return put_compat_rusage(&r, ru); -} -#endif - -SYSCALL_DEFINE1(umask, int, mask) -{ - mask = xchg(¤t->fs->umask, mask & S_IRWXUGO); - return mask; -} - -static int prctl_set_mm_exe_file(struct mm_struct *mm, unsigned int fd) -{ - struct fd exe; - struct file *old_exe, *exe_file; - struct inode *inode; - int err; - - exe = fdget(fd); - if (!exe.file) - return -EBADF; - - inode = file_inode(exe.file); - - /* - * Because the original mm->exe_file points to executable file, make - * sure that this one is executable as well, to avoid breaking an - * overall picture. - */ - err = -EACCES; - if (!S_ISREG(inode->i_mode) || path_noexec(&exe.file->f_path)) - goto exit; - - err = inode_permission(inode, MAY_EXEC); - if (err) - goto exit; - - /* - * Forbid mm->exe_file change if old file still mapped. - */ - exe_file = get_mm_exe_file(mm); - err = -EBUSY; - if (exe_file) { - struct vm_area_struct *vma; - - down_read(&mm->mmap_sem); - for (vma = mm->mmap; vma; vma = vma->vm_next) { - if (!vma->vm_file) - continue; - if (path_equal(&vma->vm_file->f_path, - &exe_file->f_path)) - goto exit_err; - } - - up_read(&mm->mmap_sem); - fput(exe_file); - } - - /* - * The symlink can be changed only once, just to disallow arbitrary - * transitions malicious software might bring in. This means one - * could make a snapshot over all processes running and monitor - * /proc/pid/exe changes to notice unusual activity if needed. - */ - err = -EPERM; - if (test_and_set_bit(MMF_EXE_FILE_CHANGED, &mm->flags)) - goto exit; - - err = 0; - /* set the new file, lockless */ - get_file(exe.file); - old_exe = xchg(&mm->exe_file, exe.file); - if (old_exe) - fput(old_exe); -exit: - fdput(exe); - return err; -exit_err: - up_read(&mm->mmap_sem); - fput(exe_file); - goto exit; -} - -/* - * WARNING: we don't require any capability here so be very careful - * in what is allowed for modification from userspace. - */ -static int validate_prctl_map(struct prctl_mm_map *prctl_map) -{ - unsigned long mmap_max_addr = TASK_SIZE; - struct mm_struct *mm = current->mm; - int error = -EINVAL, i; - - static const unsigned char offsets[] = { - offsetof(struct prctl_mm_map, start_code), - offsetof(struct prctl_mm_map, end_code), - offsetof(struct prctl_mm_map, start_data), - offsetof(struct prctl_mm_map, end_data), - offsetof(struct prctl_mm_map, start_brk), - offsetof(struct prctl_mm_map, brk), - offsetof(struct prctl_mm_map, start_stack), - offsetof(struct prctl_mm_map, arg_start), - offsetof(struct prctl_mm_map, arg_end), - offsetof(struct prctl_mm_map, env_start), - offsetof(struct prctl_mm_map, env_end), - }; - - /* - * Make sure the members are not somewhere outside - * of allowed address space. - */ - for (i = 0; i < ARRAY_SIZE(offsets); i++) { - u64 val = *(u64 *)((char *)prctl_map + offsets[i]); - - if ((unsigned long)val >= mmap_max_addr || - (unsigned long)val < mmap_min_addr) - goto out; - } - - /* - * Make sure the pairs are ordered. - */ -#define __prctl_check_order(__m1, __op, __m2) \ - ((unsigned long)prctl_map->__m1 __op \ - (unsigned long)prctl_map->__m2) ? 0 : -EINVAL - error = __prctl_check_order(start_code, <, end_code); - error |= __prctl_check_order(start_data, <, end_data); - error |= __prctl_check_order(start_brk, <=, brk); - error |= __prctl_check_order(arg_start, <=, arg_end); - error |= __prctl_check_order(env_start, <=, env_end); - if (error) - goto out; -#undef __prctl_check_order - - error = -EINVAL; - - /* - * @brk should be after @end_data in traditional maps. - */ - if (prctl_map->start_brk <= prctl_map->end_data || - prctl_map->brk <= prctl_map->end_data) - goto out; - - /* - * Neither we should allow to override limits if they set. - */ - if (check_data_rlimit(rlimit(RLIMIT_DATA), prctl_map->brk, - prctl_map->start_brk, prctl_map->end_data, - prctl_map->start_data)) - goto out; - - /* - * Someone is trying to cheat the auxv vector. - */ - if (prctl_map->auxv_size) { - if (!prctl_map->auxv || prctl_map->auxv_size > sizeof(mm->saved_auxv)) - goto out; - } - - /* - * Finally, make sure the caller has the rights to - * change /proc/pid/exe link: only local root should - * be allowed to. - */ - if (prctl_map->exe_fd != (u32)-1) { - struct user_namespace *ns = current_user_ns(); - const struct cred *cred = current_cred(); - - if (!uid_eq(cred->uid, make_kuid(ns, 0)) || - !gid_eq(cred->gid, make_kgid(ns, 0))) - goto out; - } - - error = 0; -out: - return error; -} - -#ifdef CONFIG_CHECKPOINT_RESTORE -static int prctl_set_mm_map(int opt, const void __user *addr, unsigned long data_size) -{ - struct prctl_mm_map prctl_map = { .exe_fd = (u32)-1, }; - unsigned long user_auxv[AT_VECTOR_SIZE]; - struct mm_struct *mm = current->mm; - int error; - - BUILD_BUG_ON(sizeof(user_auxv) != sizeof(mm->saved_auxv)); - BUILD_BUG_ON(sizeof(struct prctl_mm_map) > 256); - - if (opt == PR_SET_MM_MAP_SIZE) - return put_user((unsigned int)sizeof(prctl_map), - (unsigned int __user *)addr); - - if (data_size != sizeof(prctl_map)) - return -EINVAL; - - if (copy_from_user(&prctl_map, addr, sizeof(prctl_map))) - return -EFAULT; - - error = validate_prctl_map(&prctl_map); - if (error) - return error; - - if (prctl_map.auxv_size) { - memset(user_auxv, 0, sizeof(user_auxv)); - if (copy_from_user(user_auxv, - (const void __user *)prctl_map.auxv, - prctl_map.auxv_size)) - return -EFAULT; - - /* Last entry must be AT_NULL as specification requires */ - user_auxv[AT_VECTOR_SIZE - 2] = AT_NULL; - user_auxv[AT_VECTOR_SIZE - 1] = AT_NULL; - } - - if (prctl_map.exe_fd != (u32)-1) { - error = prctl_set_mm_exe_file(mm, prctl_map.exe_fd); - if (error) - return error; - } - - down_write(&mm->mmap_sem); - - /* - * We don't validate if these members are pointing to - * real present VMAs because application may have correspond - * VMAs already unmapped and kernel uses these members for statistics - * output in procfs mostly, except - * - * - @start_brk/@brk which are used in do_brk but kernel lookups - * for VMAs when updating these memvers so anything wrong written - * here cause kernel to swear at userspace program but won't lead - * to any problem in kernel itself - */ - - mm->start_code = prctl_map.start_code; - mm->end_code = prctl_map.end_code; - mm->start_data = prctl_map.start_data; - mm->end_data = prctl_map.end_data; - mm->start_brk = prctl_map.start_brk; - mm->brk = prctl_map.brk; - mm->start_stack = prctl_map.start_stack; - mm->arg_start = prctl_map.arg_start; - mm->arg_end = prctl_map.arg_end; - mm->env_start = prctl_map.env_start; - mm->env_end = prctl_map.env_end; - - /* - * Note this update of @saved_auxv is lockless thus - * if someone reads this member in procfs while we're - * updating -- it may get partly updated results. It's - * known and acceptable trade off: we leave it as is to - * not introduce additional locks here making the kernel - * more complex. - */ - if (prctl_map.auxv_size) - memcpy(mm->saved_auxv, user_auxv, sizeof(user_auxv)); - - up_write(&mm->mmap_sem); - return 0; -} -#endif /* CONFIG_CHECKPOINT_RESTORE */ - -static int prctl_set_auxv(struct mm_struct *mm, unsigned long addr, - unsigned long len) -{ - /* - * This doesn't move the auxiliary vector itself since it's pinned to - * mm_struct, but it permits filling the vector with new values. It's - * up to the caller to provide sane values here, otherwise userspace - * tools which use this vector might be unhappy. - */ - unsigned long user_auxv[AT_VECTOR_SIZE]; - - if (len > sizeof(user_auxv)) - return -EINVAL; - - if (copy_from_user(user_auxv, (const void __user *)addr, len)) - return -EFAULT; - - /* Make sure the last entry is always AT_NULL */ - user_auxv[AT_VECTOR_SIZE - 2] = 0; - user_auxv[AT_VECTOR_SIZE - 1] = 0; - - BUILD_BUG_ON(sizeof(user_auxv) != sizeof(mm->saved_auxv)); - - task_lock(current); - memcpy(mm->saved_auxv, user_auxv, len); - task_unlock(current); - - return 0; -} - -static int prctl_set_mm(int opt, unsigned long addr, - unsigned long arg4, unsigned long arg5) -{ - struct mm_struct *mm = current->mm; - struct prctl_mm_map prctl_map; - struct vm_area_struct *vma; - int error; - - if (arg5 || (arg4 && (opt != PR_SET_MM_AUXV && - opt != PR_SET_MM_MAP && - opt != PR_SET_MM_MAP_SIZE))) - return -EINVAL; - -#ifdef CONFIG_CHECKPOINT_RESTORE - if (opt == PR_SET_MM_MAP || opt == PR_SET_MM_MAP_SIZE) - return prctl_set_mm_map(opt, (const void __user *)addr, arg4); -#endif - - if (!capable(CAP_SYS_RESOURCE)) - return -EPERM; - - if (opt == PR_SET_MM_EXE_FILE) - return prctl_set_mm_exe_file(mm, (unsigned int)addr); - - if (opt == PR_SET_MM_AUXV) - return prctl_set_auxv(mm, addr, arg4); - - if (addr >= TASK_SIZE || addr < mmap_min_addr) - return -EINVAL; - - error = -EINVAL; - - down_write(&mm->mmap_sem); - vma = find_vma(mm, addr); - - prctl_map.start_code = mm->start_code; - prctl_map.end_code = mm->end_code; - prctl_map.start_data = mm->start_data; - prctl_map.end_data = mm->end_data; - prctl_map.start_brk = mm->start_brk; - prctl_map.brk = mm->brk; - prctl_map.start_stack = mm->start_stack; - prctl_map.arg_start = mm->arg_start; - prctl_map.arg_end = mm->arg_end; - prctl_map.env_start = mm->env_start; - prctl_map.env_end = mm->env_end; - prctl_map.auxv = NULL; - prctl_map.auxv_size = 0; - prctl_map.exe_fd = -1; - - switch (opt) { - case PR_SET_MM_START_CODE: - prctl_map.start_code = addr; - break; - case PR_SET_MM_END_CODE: - prctl_map.end_code = addr; - break; - case PR_SET_MM_START_DATA: - prctl_map.start_data = addr; - break; - case PR_SET_MM_END_DATA: - prctl_map.end_data = addr; - break; - case PR_SET_MM_START_STACK: - prctl_map.start_stack = addr; - break; - case PR_SET_MM_START_BRK: - prctl_map.start_brk = addr; - break; - case PR_SET_MM_BRK: - prctl_map.brk = addr; - break; - case PR_SET_MM_ARG_START: - prctl_map.arg_start = addr; - break; - case PR_SET_MM_ARG_END: - prctl_map.arg_end = addr; - break; - case PR_SET_MM_ENV_START: - prctl_map.env_start = addr; - break; - case PR_SET_MM_ENV_END: - prctl_map.env_end = addr; - break; - default: - goto out; - } - - error = validate_prctl_map(&prctl_map); - if (error) - goto out; - - switch (opt) { - /* - * If command line arguments and environment - * are placed somewhere else on stack, we can - * set them up here, ARG_START/END to setup - * command line argumets and ENV_START/END - * for environment. - */ - case PR_SET_MM_START_STACK: - case PR_SET_MM_ARG_START: - case PR_SET_MM_ARG_END: - case PR_SET_MM_ENV_START: - case PR_SET_MM_ENV_END: - if (!vma) { - error = -EFAULT; - goto out; - } - } - - mm->start_code = prctl_map.start_code; - mm->end_code = prctl_map.end_code; - mm->start_data = prctl_map.start_data; - mm->end_data = prctl_map.end_data; - mm->start_brk = prctl_map.start_brk; - mm->brk = prctl_map.brk; - mm->start_stack = prctl_map.start_stack; - mm->arg_start = prctl_map.arg_start; - mm->arg_end = prctl_map.arg_end; - mm->env_start = prctl_map.env_start; - mm->env_end = prctl_map.env_end; - - error = 0; -out: - up_write(&mm->mmap_sem); - return error; -} - -#ifdef CONFIG_CHECKPOINT_RESTORE -static int prctl_get_tid_address(struct task_struct *me, int __user **tid_addr) -{ - return put_user(me->clear_child_tid, tid_addr); -} -#else -static int prctl_get_tid_address(struct task_struct *me, int __user **tid_addr) -{ - return -EINVAL; -} -#endif - -SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, - unsigned long, arg4, unsigned long, arg5) -{ - struct task_struct *me = current; - unsigned char comm[sizeof(me->comm)]; - long error; - - error = security_task_prctl(option, arg2, arg3, arg4, arg5); - if (error != -ENOSYS) - return error; - - error = 0; - switch (option) { - case PR_SET_PDEATHSIG: - if (!valid_signal(arg2)) { - error = -EINVAL; - break; - } - me->pdeath_signal = arg2; - break; - case PR_GET_PDEATHSIG: - error = put_user(me->pdeath_signal, (int __user *)arg2); - break; - case PR_GET_DUMPABLE: - error = get_dumpable(me->mm); - break; - case PR_SET_DUMPABLE: - if (arg2 != SUID_DUMP_DISABLE && arg2 != SUID_DUMP_USER) { - error = -EINVAL; - break; - } - set_dumpable(me->mm, arg2); - break; - - case PR_SET_UNALIGN: - error = SET_UNALIGN_CTL(me, arg2); - break; - case PR_GET_UNALIGN: - error = GET_UNALIGN_CTL(me, arg2); - break; - case PR_SET_FPEMU: - error = SET_FPEMU_CTL(me, arg2); - break; - case PR_GET_FPEMU: - error = GET_FPEMU_CTL(me, arg2); - break; - case PR_SET_FPEXC: - error = SET_FPEXC_CTL(me, arg2); - break; - case PR_GET_FPEXC: - error = GET_FPEXC_CTL(me, arg2); - break; - case PR_GET_TIMING: - error = PR_TIMING_STATISTICAL; - break; - case PR_SET_TIMING: - if (arg2 != PR_TIMING_STATISTICAL) - error = -EINVAL; - break; - case PR_SET_NAME: - comm[sizeof(me->comm) - 1] = 0; - if (strncpy_from_user(comm, (char __user *)arg2, - sizeof(me->comm) - 1) < 0) - return -EFAULT; - set_task_comm(me, comm); - proc_comm_connector(me); - break; - case PR_GET_NAME: - get_task_comm(comm, me); - if (copy_to_user((char __user *)arg2, comm, sizeof(comm))) - return -EFAULT; - break; - case PR_GET_ENDIAN: - error = GET_ENDIAN(me, arg2); - break; - case PR_SET_ENDIAN: - error = SET_ENDIAN(me, arg2); - break; - case PR_GET_SECCOMP: - error = prctl_get_seccomp(); - break; - case PR_SET_SECCOMP: - error = prctl_set_seccomp(arg2, (char __user *)arg3); - break; - case PR_GET_TSC: - error = GET_TSC_CTL(arg2); - break; - case PR_SET_TSC: - error = SET_TSC_CTL(arg2); - break; - case PR_TASK_PERF_EVENTS_DISABLE: - error = perf_event_task_disable(); - break; - case PR_TASK_PERF_EVENTS_ENABLE: - error = perf_event_task_enable(); - break; - case PR_GET_TIMERSLACK: - if (current->timer_slack_ns > ULONG_MAX) - error = ULONG_MAX; - else - error = current->timer_slack_ns; - break; - case PR_SET_TIMERSLACK: - if (arg2 <= 0) - current->timer_slack_ns = - current->default_timer_slack_ns; - else - current->timer_slack_ns = arg2; - break; - case PR_MCE_KILL: - if (arg4 | arg5) - return -EINVAL; - switch (arg2) { - case PR_MCE_KILL_CLEAR: - if (arg3 != 0) - return -EINVAL; - current->flags &= ~PF_MCE_PROCESS; - break; - case PR_MCE_KILL_SET: - current->flags |= PF_MCE_PROCESS; - if (arg3 == PR_MCE_KILL_EARLY) - current->flags |= PF_MCE_EARLY; - else if (arg3 == PR_MCE_KILL_LATE) - current->flags &= ~PF_MCE_EARLY; - else if (arg3 == PR_MCE_KILL_DEFAULT) - current->flags &= - ~(PF_MCE_EARLY|PF_MCE_PROCESS); - else - return -EINVAL; - break; - default: - return -EINVAL; - } - break; - case PR_MCE_KILL_GET: - if (arg2 | arg3 | arg4 | arg5) - return -EINVAL; - if (current->flags & PF_MCE_PROCESS) - error = (current->flags & PF_MCE_EARLY) ? - PR_MCE_KILL_EARLY : PR_MCE_KILL_LATE; - else - error = PR_MCE_KILL_DEFAULT; - break; - case PR_SET_MM: - error = prctl_set_mm(arg2, arg3, arg4, arg5); - break; - case PR_GET_TID_ADDRESS: - error = prctl_get_tid_address(me, (int __user **)arg2); - break; - case PR_SET_CHILD_SUBREAPER: - me->signal->is_child_subreaper = !!arg2; - break; - case PR_GET_CHILD_SUBREAPER: - error = put_user(me->signal->is_child_subreaper, - (int __user *)arg2); - break; - case PR_SET_NO_NEW_PRIVS: - if (arg2 != 1 || arg3 || arg4 || arg5) - return -EINVAL; - - task_set_no_new_privs(current); - break; - case PR_GET_NO_NEW_PRIVS: - if (arg2 || arg3 || arg4 || arg5) - return -EINVAL; - return task_no_new_privs(current) ? 1 : 0; - case PR_GET_THP_DISABLE: - if (arg2 || arg3 || arg4 || arg5) - return -EINVAL; - error = !!(me->mm->def_flags & VM_NOHUGEPAGE); - break; - case PR_SET_THP_DISABLE: - if (arg3 || arg4 || arg5) - return -EINVAL; - if (down_write_killable(&me->mm->mmap_sem)) - return -EINTR; - if (arg2) - me->mm->def_flags |= VM_NOHUGEPAGE; - else - me->mm->def_flags &= ~VM_NOHUGEPAGE; - up_write(&me->mm->mmap_sem); - break; - case PR_MPX_ENABLE_MANAGEMENT: - if (arg2 || arg3 || arg4 || arg5) - return -EINVAL; - error = MPX_ENABLE_MANAGEMENT(); - break; - case PR_MPX_DISABLE_MANAGEMENT: - if (arg2 || arg3 || arg4 || arg5) - return -EINVAL; - error = MPX_DISABLE_MANAGEMENT(); - break; - case PR_SET_FP_MODE: - error = SET_FP_MODE(me, arg2); - break; - case PR_GET_FP_MODE: - error = GET_FP_MODE(me); - break; - default: - error = -EINVAL; - break; - } - return error; -} - -SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep, - struct getcpu_cache __user *, unused) -{ - int err = 0; - int cpu = raw_smp_processor_id(); - - if (cpup) - err |= put_user(cpu, cpup); - if (nodep) - err |= put_user(cpu_to_node(cpu), nodep); - return err ? -EFAULT : 0; -} - -/** - * do_sysinfo - fill in sysinfo struct - * @info: pointer to buffer to fill - */ -static int do_sysinfo(struct sysinfo *info) -{ - unsigned long mem_total, sav_total; - unsigned int mem_unit, bitcount; - struct timespec tp; - - memset(info, 0, sizeof(struct sysinfo)); - - get_monotonic_boottime(&tp); - info->uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0); - - get_avenrun(info->loads, 0, SI_LOAD_SHIFT - FSHIFT); - - info->procs = nr_threads; - - si_meminfo(info); - si_swapinfo(info); - - /* - * If the sum of all the available memory (i.e. ram + swap) - * is less than can be stored in a 32 bit unsigned long then - * we can be binary compatible with 2.2.x kernels. If not, - * well, in that case 2.2.x was broken anyways... - * - * -Erik Andersen - */ - - mem_total = info->totalram + info->totalswap; - if (mem_total < info->totalram || mem_total < info->totalswap) - goto out; - bitcount = 0; - mem_unit = info->mem_unit; - while (mem_unit > 1) { - bitcount++; - mem_unit >>= 1; - sav_total = mem_total; - mem_total <<= 1; - if (mem_total < sav_total) - goto out; - } - - /* - * If mem_total did not overflow, multiply all memory values by - * info->mem_unit and set it to 1. This leaves things compatible - * with 2.2.x, and also retains compatibility with earlier 2.4.x - * kernels... - */ - - info->mem_unit = 1; - info->totalram <<= bitcount; - info->freeram <<= bitcount; - info->sharedram <<= bitcount; - info->bufferram <<= bitcount; - info->totalswap <<= bitcount; - info->freeswap <<= bitcount; - info->totalhigh <<= bitcount; - info->freehigh <<= bitcount; - -out: - return 0; -} - -SYSCALL_DEFINE1(sysinfo, struct sysinfo __user *, info) -{ - struct sysinfo val; - - do_sysinfo(&val); - - if (copy_to_user(info, &val, sizeof(struct sysinfo))) - return -EFAULT; - - return 0; -} - -#ifdef CONFIG_COMPAT -struct compat_sysinfo { - s32 uptime; - u32 loads[3]; - u32 totalram; - u32 freeram; - u32 sharedram; - u32 bufferram; - u32 totalswap; - u32 freeswap; - u16 procs; - u16 pad; - u32 totalhigh; - u32 freehigh; - u32 mem_unit; - char _f[20-2*sizeof(u32)-sizeof(int)]; -}; - -COMPAT_SYSCALL_DEFINE1(sysinfo, struct compat_sysinfo __user *, info) -{ - struct sysinfo s; - - do_sysinfo(&s); - - /* Check to see if any memory value is too large for 32-bit and scale - * down if needed - */ - if (upper_32_bits(s.totalram) || upper_32_bits(s.totalswap)) { - int bitcount = 0; - - while (s.mem_unit < PAGE_SIZE) { - s.mem_unit <<= 1; - bitcount++; - } - - s.totalram >>= bitcount; - s.freeram >>= bitcount; - s.sharedram >>= bitcount; - s.bufferram >>= bitcount; - s.totalswap >>= bitcount; - s.freeswap >>= bitcount; - s.totalhigh >>= bitcount; - s.freehigh >>= bitcount; - } - - if (!access_ok(VERIFY_WRITE, info, sizeof(struct compat_sysinfo)) || - __put_user(s.uptime, &info->uptime) || - __put_user(s.loads[0], &info->loads[0]) || - __put_user(s.loads[1], &info->loads[1]) || - __put_user(s.loads[2], &info->loads[2]) || - __put_user(s.totalram, &info->totalram) || - __put_user(s.freeram, &info->freeram) || - __put_user(s.sharedram, &info->sharedram) || - __put_user(s.bufferram, &info->bufferram) || - __put_user(s.totalswap, &info->totalswap) || - __put_user(s.freeswap, &info->freeswap) || - __put_user(s.procs, &info->procs) || - __put_user(s.totalhigh, &info->totalhigh) || - __put_user(s.freehigh, &info->freehigh) || - __put_user(s.mem_unit, &info->mem_unit)) - return -EFAULT; - - return 0; -} -#endif /* CONFIG_COMPAT */ diff --git a/src/linux/kernel/sys_ni.c b/src/linux/kernel/sys_ni.c deleted file mode 100644 index 635482e..0000000 --- a/src/linux/kernel/sys_ni.c +++ /dev/null @@ -1,257 +0,0 @@ - -#include -#include - -#include - -/* we can't #include here, - but tell gcc to not warn with -Wmissing-prototypes */ -asmlinkage long sys_ni_syscall(void); - -/* - * Non-implemented system calls get redirected here. - */ -asmlinkage long sys_ni_syscall(void) -{ - return -ENOSYS; -} - -cond_syscall(sys_quotactl); -cond_syscall(sys32_quotactl); -cond_syscall(sys_acct); -cond_syscall(sys_lookup_dcookie); -cond_syscall(compat_sys_lookup_dcookie); -cond_syscall(sys_swapon); -cond_syscall(sys_swapoff); -cond_syscall(sys_kexec_load); -cond_syscall(compat_sys_kexec_load); -cond_syscall(sys_kexec_file_load); -cond_syscall(sys_init_module); -cond_syscall(sys_finit_module); -cond_syscall(sys_delete_module); -cond_syscall(sys_socketpair); -cond_syscall(sys_bind); -cond_syscall(sys_listen); -cond_syscall(sys_accept); -cond_syscall(sys_accept4); -cond_syscall(sys_connect); -cond_syscall(sys_getsockname); -cond_syscall(sys_getpeername); -cond_syscall(sys_sendto); -cond_syscall(sys_send); -cond_syscall(sys_recvfrom); -cond_syscall(sys_recv); -cond_syscall(sys_socket); -cond_syscall(sys_setsockopt); -cond_syscall(compat_sys_setsockopt); -cond_syscall(sys_getsockopt); -cond_syscall(compat_sys_getsockopt); -cond_syscall(sys_shutdown); -cond_syscall(sys_sendmsg); -cond_syscall(sys_sendmmsg); -cond_syscall(compat_sys_sendmsg); -cond_syscall(compat_sys_sendmmsg); -cond_syscall(sys_recvmsg); -cond_syscall(sys_recvmmsg); -cond_syscall(compat_sys_recvmsg); -cond_syscall(compat_sys_recv); -cond_syscall(compat_sys_recvfrom); -cond_syscall(compat_sys_recvmmsg); -cond_syscall(sys_socketcall); -cond_syscall(sys_futex); -cond_syscall(compat_sys_futex); -cond_syscall(sys_set_robust_list); -cond_syscall(compat_sys_set_robust_list); -cond_syscall(sys_get_robust_list); -cond_syscall(compat_sys_get_robust_list); -cond_syscall(sys_epoll_create); -cond_syscall(sys_epoll_create1); -cond_syscall(sys_epoll_ctl); -cond_syscall(sys_epoll_wait); -cond_syscall(sys_epoll_pwait); -cond_syscall(compat_sys_epoll_pwait); -cond_syscall(sys_semget); -cond_syscall(sys_semop); -cond_syscall(sys_semtimedop); -cond_syscall(compat_sys_semtimedop); -cond_syscall(sys_semctl); -cond_syscall(compat_sys_semctl); -cond_syscall(sys_msgget); -cond_syscall(sys_msgsnd); -cond_syscall(compat_sys_msgsnd); -cond_syscall(sys_msgrcv); -cond_syscall(compat_sys_msgrcv); -cond_syscall(sys_msgctl); -cond_syscall(compat_sys_msgctl); -cond_syscall(sys_shmget); -cond_syscall(sys_shmat); -cond_syscall(compat_sys_shmat); -cond_syscall(sys_shmdt); -cond_syscall(sys_shmctl); -cond_syscall(compat_sys_shmctl); -cond_syscall(sys_mq_open); -cond_syscall(sys_mq_unlink); -cond_syscall(sys_mq_timedsend); -cond_syscall(sys_mq_timedreceive); -cond_syscall(sys_mq_notify); -cond_syscall(sys_mq_getsetattr); -cond_syscall(compat_sys_mq_open); -cond_syscall(compat_sys_mq_timedsend); -cond_syscall(compat_sys_mq_timedreceive); -cond_syscall(compat_sys_mq_notify); -cond_syscall(compat_sys_mq_getsetattr); -cond_syscall(sys_mbind); -cond_syscall(sys_get_mempolicy); -cond_syscall(sys_set_mempolicy); -cond_syscall(compat_sys_mbind); -cond_syscall(compat_sys_get_mempolicy); -cond_syscall(compat_sys_set_mempolicy); -cond_syscall(sys_add_key); -cond_syscall(sys_request_key); -cond_syscall(sys_keyctl); -cond_syscall(compat_sys_keyctl); -cond_syscall(compat_sys_socketcall); -cond_syscall(sys_inotify_init); -cond_syscall(sys_inotify_init1); -cond_syscall(sys_inotify_add_watch); -cond_syscall(sys_inotify_rm_watch); -cond_syscall(sys_migrate_pages); -cond_syscall(sys_move_pages); -cond_syscall(sys_chown16); -cond_syscall(sys_fchown16); -cond_syscall(sys_getegid16); -cond_syscall(sys_geteuid16); -cond_syscall(sys_getgid16); -cond_syscall(sys_getgroups16); -cond_syscall(sys_getresgid16); -cond_syscall(sys_getresuid16); -cond_syscall(sys_getuid16); -cond_syscall(sys_lchown16); -cond_syscall(sys_setfsgid16); -cond_syscall(sys_setfsuid16); -cond_syscall(sys_setgid16); -cond_syscall(sys_setgroups16); -cond_syscall(sys_setregid16); -cond_syscall(sys_setresgid16); -cond_syscall(sys_setresuid16); -cond_syscall(sys_setreuid16); -cond_syscall(sys_setuid16); -cond_syscall(sys_sgetmask); -cond_syscall(sys_ssetmask); -cond_syscall(sys_vm86old); -cond_syscall(sys_vm86); -cond_syscall(sys_modify_ldt); -cond_syscall(sys_ipc); -cond_syscall(compat_sys_ipc); -cond_syscall(compat_sys_sysctl); -cond_syscall(sys_flock); -cond_syscall(sys_io_setup); -cond_syscall(sys_io_destroy); -cond_syscall(sys_io_submit); -cond_syscall(sys_io_cancel); -cond_syscall(sys_io_getevents); -cond_syscall(sys_sysfs); -cond_syscall(sys_syslog); -cond_syscall(sys_process_vm_readv); -cond_syscall(sys_process_vm_writev); -cond_syscall(compat_sys_process_vm_readv); -cond_syscall(compat_sys_process_vm_writev); -cond_syscall(sys_uselib); -cond_syscall(sys_fadvise64); -cond_syscall(sys_fadvise64_64); -cond_syscall(sys_madvise); -cond_syscall(sys_setuid); -cond_syscall(sys_setregid); -cond_syscall(sys_setgid); -cond_syscall(sys_setreuid); -cond_syscall(sys_setresuid); -cond_syscall(sys_getresuid); -cond_syscall(sys_setresgid); -cond_syscall(sys_getresgid); -cond_syscall(sys_setgroups); -cond_syscall(sys_getgroups); -cond_syscall(sys_setfsuid); -cond_syscall(sys_setfsgid); -cond_syscall(sys_capget); -cond_syscall(sys_capset); -cond_syscall(sys_copy_file_range); - -/* arch-specific weak syscall entries */ -cond_syscall(sys_pciconfig_read); -cond_syscall(sys_pciconfig_write); -cond_syscall(sys_pciconfig_iobase); -cond_syscall(compat_sys_s390_ipc); -cond_syscall(ppc_rtas); -cond_syscall(sys_spu_run); -cond_syscall(sys_spu_create); -cond_syscall(sys_subpage_prot); -cond_syscall(sys_s390_pci_mmio_read); -cond_syscall(sys_s390_pci_mmio_write); - -/* mmu depending weak syscall entries */ -cond_syscall(sys_mprotect); -cond_syscall(sys_msync); -cond_syscall(sys_mlock); -cond_syscall(sys_munlock); -cond_syscall(sys_mlockall); -cond_syscall(sys_munlockall); -cond_syscall(sys_mlock2); -cond_syscall(sys_mincore); -cond_syscall(sys_madvise); -cond_syscall(sys_mremap); -cond_syscall(sys_remap_file_pages); -cond_syscall(compat_sys_move_pages); -cond_syscall(compat_sys_migrate_pages); - -/* block-layer dependent */ -cond_syscall(sys_bdflush); -cond_syscall(sys_ioprio_set); -cond_syscall(sys_ioprio_get); - -/* New file descriptors */ -cond_syscall(sys_signalfd); -cond_syscall(sys_signalfd4); -cond_syscall(compat_sys_signalfd); -cond_syscall(compat_sys_signalfd4); -cond_syscall(sys_timerfd_create); -cond_syscall(sys_timerfd_settime); -cond_syscall(sys_timerfd_gettime); -cond_syscall(compat_sys_timerfd_settime); -cond_syscall(compat_sys_timerfd_gettime); -cond_syscall(sys_eventfd); -cond_syscall(sys_eventfd2); -cond_syscall(sys_memfd_create); -cond_syscall(sys_userfaultfd); - -/* performance counters: */ -cond_syscall(sys_perf_event_open); - -/* fanotify! */ -cond_syscall(sys_fanotify_init); -cond_syscall(sys_fanotify_mark); -cond_syscall(compat_sys_fanotify_mark); - -/* open by handle */ -cond_syscall(sys_name_to_handle_at); -cond_syscall(sys_open_by_handle_at); -cond_syscall(compat_sys_open_by_handle_at); - -/* compare kernel pointers */ -cond_syscall(sys_kcmp); - -/* operate on Secure Computing state */ -cond_syscall(sys_seccomp); - -/* access BPF programs and maps */ -cond_syscall(sys_bpf); - -/* execveat */ -cond_syscall(sys_execveat); - -/* membarrier */ -cond_syscall(sys_membarrier); - -/* memory protection keys */ -cond_syscall(sys_pkey_mprotect); -cond_syscall(sys_pkey_alloc); -cond_syscall(sys_pkey_free); diff --git a/src/linux/kernel/sysctl.c b/src/linux/kernel/sysctl.c deleted file mode 100644 index 706309f..0000000 --- a/src/linux/kernel/sysctl.c +++ /dev/null @@ -1,2952 +0,0 @@ -/* - * sysctl.c: General linux system control interface - * - * Begun 24 March 1995, Stephen Tweedie - * Added /proc support, Dec 1995 - * Added bdflush entry and intvec min/max checking, 2/23/96, Tom Dyas. - * Added hooks for /proc/sys/net (minor, minor patch), 96/4/1, Mike Shaver. - * Added kernel/java-{interpreter,appletviewer}, 96/5/10, Mike Shaver. - * Dynamic registration fixes, Stephen Tweedie. - * Added kswapd-interval, ctrl-alt-del, printk stuff, 1/8/97, Chris Horn. - * Made sysctl support optional via CONFIG_SYSCTL, 1/10/97, Chris - * Horn. - * Added proc_doulongvec_ms_jiffies_minmax, 09/08/99, Carlos H. Bauer. - * Added proc_doulongvec_minmax, 09/08/99, Carlos H. Bauer. - * Changed linked lists to use list.h instead of lists.h, 02/24/00, Bill - * Wendling. - * The list_for_each() macro wasn't appropriate for the sysctl loop. - * Removed it and replaced it with older style, 03/23/00, Bill Wendling - */ - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef CONFIG_X86 -#include -#include -#include -#endif -#ifdef CONFIG_SPARC -#include -#endif -#ifdef CONFIG_BSD_PROCESS_ACCT -#include -#endif -#ifdef CONFIG_RT_MUTEXES -#include -#endif -#if defined(CONFIG_PROVE_LOCKING) || defined(CONFIG_LOCK_STAT) -#include -#endif -#ifdef CONFIG_CHR_DEV_SG -#include -#endif - -#ifdef CONFIG_LOCKUP_DETECTOR -#include -#endif - -#if defined(CONFIG_SYSCTL) - -/* External variables not in a header file. */ -extern int suid_dumpable; -#ifdef CONFIG_COREDUMP -extern int core_uses_pid; -extern char core_pattern[]; -extern unsigned int core_pipe_limit; -#endif -extern int pid_max; -extern int pid_max_min, pid_max_max; -extern int percpu_pagelist_fraction; -extern int latencytop_enabled; -extern unsigned int sysctl_nr_open_min, sysctl_nr_open_max; -#ifndef CONFIG_MMU -extern int sysctl_nr_trim_pages; -#endif - -/* Constants used for minimum and maximum */ -#ifdef CONFIG_LOCKUP_DETECTOR -static int sixty = 60; -#endif - -static int __maybe_unused neg_one = -1; - -static int zero; -static int __maybe_unused one = 1; -static int __maybe_unused two = 2; -static int __maybe_unused four = 4; -static unsigned long one_ul = 1; -static int one_hundred = 100; -static int one_thousand = 1000; -#ifdef CONFIG_PRINTK -static int ten_thousand = 10000; -#endif -#ifdef CONFIG_PERF_EVENTS -static int six_hundred_forty_kb = 640 * 1024; -#endif - -/* this is needed for the proc_doulongvec_minmax of vm_dirty_bytes */ -static unsigned long dirty_bytes_min = 2 * PAGE_SIZE; - -/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ -static int maxolduid = 65535; -static int minolduid; - -static int ngroups_max = NGROUPS_MAX; -static const int cap_last_cap = CAP_LAST_CAP; - -/*this is needed for proc_doulongvec_minmax of sysctl_hung_task_timeout_secs */ -#ifdef CONFIG_DETECT_HUNG_TASK -static unsigned long hung_task_timeout_max = (LONG_MAX/HZ); -#endif - -#ifdef CONFIG_INOTIFY_USER -#include -#endif -#ifdef CONFIG_SPARC -#endif - -#ifdef __hppa__ -extern int pwrsw_enabled; -#endif - -#ifdef CONFIG_SYSCTL_ARCH_UNALIGN_ALLOW -extern int unaligned_enabled; -#endif - -#ifdef CONFIG_IA64 -extern int unaligned_dump_stack; -#endif - -#ifdef CONFIG_SYSCTL_ARCH_UNALIGN_NO_WARN -extern int no_unaligned_warning; -#endif - -#ifdef CONFIG_PROC_SYSCTL - -#define SYSCTL_WRITES_LEGACY -1 -#define SYSCTL_WRITES_WARN 0 -#define SYSCTL_WRITES_STRICT 1 - -static int sysctl_writes_strict = SYSCTL_WRITES_STRICT; - -static int proc_do_cad_pid(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); -static int proc_taint(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); -#endif - -#ifdef CONFIG_PRINTK -static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); -#endif - -static int proc_dointvec_minmax_coredump(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); -#ifdef CONFIG_COREDUMP -static int proc_dostring_coredump(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos); -#endif - -#ifdef CONFIG_MAGIC_SYSRQ -/* Note: sysrq code uses it's own private copy */ -static int __sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE; - -static int sysrq_sysctl_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - int error; - - error = proc_dointvec(table, write, buffer, lenp, ppos); - if (error) - return error; - - if (write) - sysrq_toggle_support(__sysrq_enabled); - - return 0; -} - -#endif - -static struct ctl_table kern_table[]; -static struct ctl_table vm_table[]; -static struct ctl_table fs_table[]; -static struct ctl_table debug_table[]; -static struct ctl_table dev_table[]; -extern struct ctl_table random_table[]; -#ifdef CONFIG_EPOLL -extern struct ctl_table epoll_table[]; -#endif - -#ifdef HAVE_ARCH_PICK_MMAP_LAYOUT -int sysctl_legacy_va_layout; -#endif - -/* The default sysctl tables: */ - -static struct ctl_table sysctl_base_table[] = { - { - .procname = "kernel", - .mode = 0555, - .child = kern_table, - }, - { - .procname = "vm", - .mode = 0555, - .child = vm_table, - }, - { - .procname = "fs", - .mode = 0555, - .child = fs_table, - }, - { - .procname = "debug", - .mode = 0555, - .child = debug_table, - }, - { - .procname = "dev", - .mode = 0555, - .child = dev_table, - }, - { } -}; - -#ifdef CONFIG_SCHED_DEBUG -static int min_sched_granularity_ns = 100000; /* 100 usecs */ -static int max_sched_granularity_ns = NSEC_PER_SEC; /* 1 second */ -static int min_wakeup_granularity_ns; /* 0 usecs */ -static int max_wakeup_granularity_ns = NSEC_PER_SEC; /* 1 second */ -#ifdef CONFIG_SMP -static int min_sched_tunable_scaling = SCHED_TUNABLESCALING_NONE; -static int max_sched_tunable_scaling = SCHED_TUNABLESCALING_END-1; -#endif /* CONFIG_SMP */ -#endif /* CONFIG_SCHED_DEBUG */ - -#ifdef CONFIG_COMPACTION -static int min_extfrag_threshold; -static int max_extfrag_threshold = 1000; -#endif - -static struct ctl_table kern_table[] = { - { - .procname = "sched_child_runs_first", - .data = &sysctl_sched_child_runs_first, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#ifdef CONFIG_SCHED_DEBUG - { - .procname = "sched_min_granularity_ns", - .data = &sysctl_sched_min_granularity, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = sched_proc_update_handler, - .extra1 = &min_sched_granularity_ns, - .extra2 = &max_sched_granularity_ns, - }, - { - .procname = "sched_latency_ns", - .data = &sysctl_sched_latency, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = sched_proc_update_handler, - .extra1 = &min_sched_granularity_ns, - .extra2 = &max_sched_granularity_ns, - }, - { - .procname = "sched_wakeup_granularity_ns", - .data = &sysctl_sched_wakeup_granularity, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = sched_proc_update_handler, - .extra1 = &min_wakeup_granularity_ns, - .extra2 = &max_wakeup_granularity_ns, - }, -#ifdef CONFIG_SMP - { - .procname = "sched_tunable_scaling", - .data = &sysctl_sched_tunable_scaling, - .maxlen = sizeof(enum sched_tunable_scaling), - .mode = 0644, - .proc_handler = sched_proc_update_handler, - .extra1 = &min_sched_tunable_scaling, - .extra2 = &max_sched_tunable_scaling, - }, - { - .procname = "sched_migration_cost_ns", - .data = &sysctl_sched_migration_cost, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "sched_nr_migrate", - .data = &sysctl_sched_nr_migrate, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "sched_time_avg_ms", - .data = &sysctl_sched_time_avg, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "sched_shares_window_ns", - .data = &sysctl_sched_shares_window, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#ifdef CONFIG_SCHEDSTATS - { - .procname = "sched_schedstats", - .data = NULL, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = sysctl_schedstats, - .extra1 = &zero, - .extra2 = &one, - }, -#endif /* CONFIG_SCHEDSTATS */ -#endif /* CONFIG_SMP */ -#ifdef CONFIG_NUMA_BALANCING - { - .procname = "numa_balancing_scan_delay_ms", - .data = &sysctl_numa_balancing_scan_delay, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "numa_balancing_scan_period_min_ms", - .data = &sysctl_numa_balancing_scan_period_min, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "numa_balancing_scan_period_max_ms", - .data = &sysctl_numa_balancing_scan_period_max, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "numa_balancing_scan_size_mb", - .data = &sysctl_numa_balancing_scan_size, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &one, - }, - { - .procname = "numa_balancing", - .data = NULL, /* filled in by handler */ - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = sysctl_numa_balancing, - .extra1 = &zero, - .extra2 = &one, - }, -#endif /* CONFIG_NUMA_BALANCING */ -#endif /* CONFIG_SCHED_DEBUG */ - { - .procname = "sched_rt_period_us", - .data = &sysctl_sched_rt_period, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = sched_rt_handler, - }, - { - .procname = "sched_rt_runtime_us", - .data = &sysctl_sched_rt_runtime, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = sched_rt_handler, - }, - { - .procname = "sched_rr_timeslice_ms", - .data = &sched_rr_timeslice, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = sched_rr_handler, - }, -#ifdef CONFIG_SCHED_AUTOGROUP - { - .procname = "sched_autogroup_enabled", - .data = &sysctl_sched_autogroup_enabled, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, -#endif -#ifdef CONFIG_CFS_BANDWIDTH - { - .procname = "sched_cfs_bandwidth_slice_us", - .data = &sysctl_sched_cfs_bandwidth_slice, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &one, - }, -#endif -#ifdef CONFIG_PROVE_LOCKING - { - .procname = "prove_locking", - .data = &prove_locking, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif -#ifdef CONFIG_LOCK_STAT - { - .procname = "lock_stat", - .data = &lock_stat, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif - { - .procname = "panic", - .data = &panic_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#ifdef CONFIG_COREDUMP - { - .procname = "core_uses_pid", - .data = &core_uses_pid, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "core_pattern", - .data = core_pattern, - .maxlen = CORENAME_MAX_SIZE, - .mode = 0644, - .proc_handler = proc_dostring_coredump, - }, - { - .procname = "core_pipe_limit", - .data = &core_pipe_limit, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif -#ifdef CONFIG_PROC_SYSCTL - { - .procname = "tainted", - .maxlen = sizeof(long), - .mode = 0644, - .proc_handler = proc_taint, - }, - { - .procname = "sysctl_writes_strict", - .data = &sysctl_writes_strict, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &neg_one, - .extra2 = &one, - }, -#endif -#ifdef CONFIG_LATENCYTOP - { - .procname = "latencytop", - .data = &latencytop_enabled, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = sysctl_latencytop, - }, -#endif -#ifdef CONFIG_BLK_DEV_INITRD - { - .procname = "real-root-dev", - .data = &real_root_dev, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif - { - .procname = "print-fatal-signals", - .data = &print_fatal_signals, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#ifdef CONFIG_SPARC - { - .procname = "reboot-cmd", - .data = reboot_command, - .maxlen = 256, - .mode = 0644, - .proc_handler = proc_dostring, - }, - { - .procname = "stop-a", - .data = &stop_a_enabled, - .maxlen = sizeof (int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "scons-poweroff", - .data = &scons_pwroff, - .maxlen = sizeof (int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif -#ifdef CONFIG_SPARC64 - { - .procname = "tsb-ratio", - .data = &sysctl_tsb_ratio, - .maxlen = sizeof (int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif -#ifdef __hppa__ - { - .procname = "soft-power", - .data = &pwrsw_enabled, - .maxlen = sizeof (int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif -#ifdef CONFIG_SYSCTL_ARCH_UNALIGN_ALLOW - { - .procname = "unaligned-trap", - .data = &unaligned_enabled, - .maxlen = sizeof (int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif - { - .procname = "ctrl-alt-del", - .data = &C_A_D, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#ifdef CONFIG_FUNCTION_TRACER - { - .procname = "ftrace_enabled", - .data = &ftrace_enabled, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = ftrace_enable_sysctl, - }, -#endif -#ifdef CONFIG_STACK_TRACER - { - .procname = "stack_tracer_enabled", - .data = &stack_tracer_enabled, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = stack_trace_sysctl, - }, -#endif -#ifdef CONFIG_TRACING - { - .procname = "ftrace_dump_on_oops", - .data = &ftrace_dump_on_oops, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "traceoff_on_warning", - .data = &__disable_trace_on_warning, - .maxlen = sizeof(__disable_trace_on_warning), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "tracepoint_printk", - .data = &tracepoint_printk, - .maxlen = sizeof(tracepoint_printk), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif -#ifdef CONFIG_KEXEC_CORE - { - .procname = "kexec_load_disabled", - .data = &kexec_load_disabled, - .maxlen = sizeof(int), - .mode = 0644, - /* only handle a transition from default "0" to "1" */ - .proc_handler = proc_dointvec_minmax, - .extra1 = &one, - .extra2 = &one, - }, -#endif -#ifdef CONFIG_MODULES - { - .procname = "modprobe", - .data = &modprobe_path, - .maxlen = KMOD_PATH_LEN, - .mode = 0644, - .proc_handler = proc_dostring, - }, - { - .procname = "modules_disabled", - .data = &modules_disabled, - .maxlen = sizeof(int), - .mode = 0644, - /* only handle a transition from default "0" to "1" */ - .proc_handler = proc_dointvec_minmax, - .extra1 = &one, - .extra2 = &one, - }, -#endif -#ifdef CONFIG_UEVENT_HELPER - { - .procname = "hotplug", - .data = &uevent_helper, - .maxlen = UEVENT_HELPER_PATH_LEN, - .mode = 0644, - .proc_handler = proc_dostring, - }, -#endif -#ifdef CONFIG_CHR_DEV_SG - { - .procname = "sg-big-buff", - .data = &sg_big_buff, - .maxlen = sizeof (int), - .mode = 0444, - .proc_handler = proc_dointvec, - }, -#endif -#ifdef CONFIG_BSD_PROCESS_ACCT - { - .procname = "acct", - .data = &acct_parm, - .maxlen = 3*sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif -#ifdef CONFIG_MAGIC_SYSRQ - { - .procname = "sysrq", - .data = &__sysrq_enabled, - .maxlen = sizeof (int), - .mode = 0644, - .proc_handler = sysrq_sysctl_handler, - }, -#endif -#ifdef CONFIG_PROC_SYSCTL - { - .procname = "cad_pid", - .data = NULL, - .maxlen = sizeof (int), - .mode = 0600, - .proc_handler = proc_do_cad_pid, - }, -#endif - { - .procname = "threads-max", - .data = NULL, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = sysctl_max_threads, - }, - { - .procname = "random", - .mode = 0555, - .child = random_table, - }, - { - .procname = "usermodehelper", - .mode = 0555, - .child = usermodehelper_table, - }, - { - .procname = "overflowuid", - .data = &overflowuid, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &minolduid, - .extra2 = &maxolduid, - }, - { - .procname = "overflowgid", - .data = &overflowgid, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &minolduid, - .extra2 = &maxolduid, - }, -#ifdef CONFIG_S390 -#ifdef CONFIG_MATHEMU - { - .procname = "ieee_emulation_warnings", - .data = &sysctl_ieee_emulation_warnings, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif - { - .procname = "userprocess_debug", - .data = &show_unhandled_signals, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif - { - .procname = "pid_max", - .data = &pid_max, - .maxlen = sizeof (int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &pid_max_min, - .extra2 = &pid_max_max, - }, - { - .procname = "panic_on_oops", - .data = &panic_on_oops, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#if defined CONFIG_PRINTK - { - .procname = "printk", - .data = &console_loglevel, - .maxlen = 4*sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "printk_ratelimit", - .data = &printk_ratelimit_state.interval, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "printk_ratelimit_burst", - .data = &printk_ratelimit_state.burst, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "printk_delay", - .data = &printk_delay_msec, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &ten_thousand, - }, - { - .procname = "printk_devkmsg", - .data = devkmsg_log_str, - .maxlen = DEVKMSG_STR_MAX_SIZE, - .mode = 0644, - .proc_handler = devkmsg_sysctl_set_loglvl, - }, - { - .procname = "dmesg_restrict", - .data = &dmesg_restrict, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax_sysadmin, - .extra1 = &zero, - .extra2 = &one, - }, - { - .procname = "kptr_restrict", - .data = &kptr_restrict, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax_sysadmin, - .extra1 = &zero, - .extra2 = &two, - }, -#endif - { - .procname = "ngroups_max", - .data = &ngroups_max, - .maxlen = sizeof (int), - .mode = 0444, - .proc_handler = proc_dointvec, - }, - { - .procname = "cap_last_cap", - .data = (void *)&cap_last_cap, - .maxlen = sizeof(int), - .mode = 0444, - .proc_handler = proc_dointvec, - }, -#if defined(CONFIG_LOCKUP_DETECTOR) - { - .procname = "watchdog", - .data = &watchdog_user_enabled, - .maxlen = sizeof (int), - .mode = 0644, - .proc_handler = proc_watchdog, - .extra1 = &zero, - .extra2 = &one, - }, - { - .procname = "watchdog_thresh", - .data = &watchdog_thresh, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_watchdog_thresh, - .extra1 = &zero, - .extra2 = &sixty, - }, - { - .procname = "nmi_watchdog", - .data = &nmi_watchdog_enabled, - .maxlen = sizeof (int), - .mode = 0644, - .proc_handler = proc_nmi_watchdog, - .extra1 = &zero, -#if defined(CONFIG_HAVE_NMI_WATCHDOG) || defined(CONFIG_HARDLOCKUP_DETECTOR) - .extra2 = &one, -#else - .extra2 = &zero, -#endif - }, - { - .procname = "soft_watchdog", - .data = &soft_watchdog_enabled, - .maxlen = sizeof (int), - .mode = 0644, - .proc_handler = proc_soft_watchdog, - .extra1 = &zero, - .extra2 = &one, - }, - { - .procname = "watchdog_cpumask", - .data = &watchdog_cpumask_bits, - .maxlen = NR_CPUS, - .mode = 0644, - .proc_handler = proc_watchdog_cpumask, - }, - { - .procname = "softlockup_panic", - .data = &softlockup_panic, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, -#ifdef CONFIG_HARDLOCKUP_DETECTOR - { - .procname = "hardlockup_panic", - .data = &hardlockup_panic, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, -#endif -#ifdef CONFIG_SMP - { - .procname = "softlockup_all_cpu_backtrace", - .data = &sysctl_softlockup_all_cpu_backtrace, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, - { - .procname = "hardlockup_all_cpu_backtrace", - .data = &sysctl_hardlockup_all_cpu_backtrace, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, -#endif /* CONFIG_SMP */ -#endif -#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86) - { - .procname = "unknown_nmi_panic", - .data = &unknown_nmi_panic, - .maxlen = sizeof (int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif -#if defined(CONFIG_X86) - { - .procname = "panic_on_unrecovered_nmi", - .data = &panic_on_unrecovered_nmi, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "panic_on_io_nmi", - .data = &panic_on_io_nmi, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#ifdef CONFIG_DEBUG_STACKOVERFLOW - { - .procname = "panic_on_stackoverflow", - .data = &sysctl_panic_on_stackoverflow, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif - { - .procname = "bootloader_type", - .data = &bootloader_type, - .maxlen = sizeof (int), - .mode = 0444, - .proc_handler = proc_dointvec, - }, - { - .procname = "bootloader_version", - .data = &bootloader_version, - .maxlen = sizeof (int), - .mode = 0444, - .proc_handler = proc_dointvec, - }, - { - .procname = "kstack_depth_to_print", - .data = &kstack_depth_to_print, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "io_delay_type", - .data = &io_delay_type, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif -#if defined(CONFIG_MMU) - { - .procname = "randomize_va_space", - .data = &randomize_va_space, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif -#if defined(CONFIG_S390) && defined(CONFIG_SMP) - { - .procname = "spin_retry", - .data = &spin_retry, - .maxlen = sizeof (int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif -#if defined(CONFIG_ACPI_SLEEP) && defined(CONFIG_X86) - { - .procname = "acpi_video_flags", - .data = &acpi_realmode_flags, - .maxlen = sizeof (unsigned long), - .mode = 0644, - .proc_handler = proc_doulongvec_minmax, - }, -#endif -#ifdef CONFIG_SYSCTL_ARCH_UNALIGN_NO_WARN - { - .procname = "ignore-unaligned-usertrap", - .data = &no_unaligned_warning, - .maxlen = sizeof (int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif -#ifdef CONFIG_IA64 - { - .procname = "unaligned-dump-stack", - .data = &unaligned_dump_stack, - .maxlen = sizeof (int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif -#ifdef CONFIG_DETECT_HUNG_TASK - { - .procname = "hung_task_panic", - .data = &sysctl_hung_task_panic, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, - { - .procname = "hung_task_check_count", - .data = &sysctl_hung_task_check_count, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - }, - { - .procname = "hung_task_timeout_secs", - .data = &sysctl_hung_task_timeout_secs, - .maxlen = sizeof(unsigned long), - .mode = 0644, - .proc_handler = proc_dohung_task_timeout_secs, - .extra2 = &hung_task_timeout_max, - }, - { - .procname = "hung_task_warnings", - .data = &sysctl_hung_task_warnings, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &neg_one, - }, -#endif -#ifdef CONFIG_RT_MUTEXES - { - .procname = "max_lock_depth", - .data = &max_lock_depth, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif - { - .procname = "poweroff_cmd", - .data = &poweroff_cmd, - .maxlen = POWEROFF_CMD_PATH_LEN, - .mode = 0644, - .proc_handler = proc_dostring, - }, -#ifdef CONFIG_KEYS - { - .procname = "keys", - .mode = 0555, - .child = key_sysctls, - }, -#endif -#ifdef CONFIG_PERF_EVENTS - /* - * User-space scripts rely on the existence of this file - * as a feature check for perf_events being enabled. - * - * So it's an ABI, do not remove! - */ - { - .procname = "perf_event_paranoid", - .data = &sysctl_perf_event_paranoid, - .maxlen = sizeof(sysctl_perf_event_paranoid), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "perf_event_mlock_kb", - .data = &sysctl_perf_event_mlock, - .maxlen = sizeof(sysctl_perf_event_mlock), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "perf_event_max_sample_rate", - .data = &sysctl_perf_event_sample_rate, - .maxlen = sizeof(sysctl_perf_event_sample_rate), - .mode = 0644, - .proc_handler = perf_proc_update_handler, - .extra1 = &one, - }, - { - .procname = "perf_cpu_time_max_percent", - .data = &sysctl_perf_cpu_time_max_percent, - .maxlen = sizeof(sysctl_perf_cpu_time_max_percent), - .mode = 0644, - .proc_handler = perf_cpu_time_max_percent_handler, - .extra1 = &zero, - .extra2 = &one_hundred, - }, - { - .procname = "perf_event_max_stack", - .data = &sysctl_perf_event_max_stack, - .maxlen = sizeof(sysctl_perf_event_max_stack), - .mode = 0644, - .proc_handler = perf_event_max_stack_handler, - .extra1 = &zero, - .extra2 = &six_hundred_forty_kb, - }, - { - .procname = "perf_event_max_contexts_per_stack", - .data = &sysctl_perf_event_max_contexts_per_stack, - .maxlen = sizeof(sysctl_perf_event_max_contexts_per_stack), - .mode = 0644, - .proc_handler = perf_event_max_stack_handler, - .extra1 = &zero, - .extra2 = &one_thousand, - }, -#endif -#ifdef CONFIG_KMEMCHECK - { - .procname = "kmemcheck", - .data = &kmemcheck_enabled, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif - { - .procname = "panic_on_warn", - .data = &panic_on_warn, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, -#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON) - { - .procname = "timer_migration", - .data = &sysctl_timer_migration, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = timer_migration_handler, - }, -#endif -#ifdef CONFIG_BPF_SYSCALL - { - .procname = "unprivileged_bpf_disabled", - .data = &sysctl_unprivileged_bpf_disabled, - .maxlen = sizeof(sysctl_unprivileged_bpf_disabled), - .mode = 0644, - /* only handle a transition from default "0" to "1" */ - .proc_handler = proc_dointvec_minmax, - .extra1 = &one, - .extra2 = &one, - }, -#endif -#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU) - { - .procname = "panic_on_rcu_stall", - .data = &sysctl_panic_on_rcu_stall, - .maxlen = sizeof(sysctl_panic_on_rcu_stall), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, -#endif - { } -}; - -static struct ctl_table vm_table[] = { - { - .procname = "overcommit_memory", - .data = &sysctl_overcommit_memory, - .maxlen = sizeof(sysctl_overcommit_memory), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &two, - }, - { - .procname = "panic_on_oom", - .data = &sysctl_panic_on_oom, - .maxlen = sizeof(sysctl_panic_on_oom), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &two, - }, - { - .procname = "oom_kill_allocating_task", - .data = &sysctl_oom_kill_allocating_task, - .maxlen = sizeof(sysctl_oom_kill_allocating_task), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "oom_dump_tasks", - .data = &sysctl_oom_dump_tasks, - .maxlen = sizeof(sysctl_oom_dump_tasks), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "overcommit_ratio", - .data = &sysctl_overcommit_ratio, - .maxlen = sizeof(sysctl_overcommit_ratio), - .mode = 0644, - .proc_handler = overcommit_ratio_handler, - }, - { - .procname = "overcommit_kbytes", - .data = &sysctl_overcommit_kbytes, - .maxlen = sizeof(sysctl_overcommit_kbytes), - .mode = 0644, - .proc_handler = overcommit_kbytes_handler, - }, - { - .procname = "page-cluster", - .data = &page_cluster, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - }, - { - .procname = "dirty_background_ratio", - .data = &dirty_background_ratio, - .maxlen = sizeof(dirty_background_ratio), - .mode = 0644, - .proc_handler = dirty_background_ratio_handler, - .extra1 = &zero, - .extra2 = &one_hundred, - }, - { - .procname = "dirty_background_bytes", - .data = &dirty_background_bytes, - .maxlen = sizeof(dirty_background_bytes), - .mode = 0644, - .proc_handler = dirty_background_bytes_handler, - .extra1 = &one_ul, - }, - { - .procname = "dirty_ratio", - .data = &vm_dirty_ratio, - .maxlen = sizeof(vm_dirty_ratio), - .mode = 0644, - .proc_handler = dirty_ratio_handler, - .extra1 = &zero, - .extra2 = &one_hundred, - }, - { - .procname = "dirty_bytes", - .data = &vm_dirty_bytes, - .maxlen = sizeof(vm_dirty_bytes), - .mode = 0644, - .proc_handler = dirty_bytes_handler, - .extra1 = &dirty_bytes_min, - }, - { - .procname = "dirty_writeback_centisecs", - .data = &dirty_writeback_interval, - .maxlen = sizeof(dirty_writeback_interval), - .mode = 0644, - .proc_handler = dirty_writeback_centisecs_handler, - }, - { - .procname = "dirty_expire_centisecs", - .data = &dirty_expire_interval, - .maxlen = sizeof(dirty_expire_interval), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - }, - { - .procname = "dirtytime_expire_seconds", - .data = &dirtytime_expire_interval, - .maxlen = sizeof(dirty_expire_interval), - .mode = 0644, - .proc_handler = dirtytime_interval_handler, - .extra1 = &zero, - }, - { - .procname = "nr_pdflush_threads", - .mode = 0444 /* read-only */, - .proc_handler = pdflush_proc_obsolete, - }, - { - .procname = "swappiness", - .data = &vm_swappiness, - .maxlen = sizeof(vm_swappiness), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one_hundred, - }, -#ifdef CONFIG_HUGETLB_PAGE - { - .procname = "nr_hugepages", - .data = NULL, - .maxlen = sizeof(unsigned long), - .mode = 0644, - .proc_handler = hugetlb_sysctl_handler, - }, -#ifdef CONFIG_NUMA - { - .procname = "nr_hugepages_mempolicy", - .data = NULL, - .maxlen = sizeof(unsigned long), - .mode = 0644, - .proc_handler = &hugetlb_mempolicy_sysctl_handler, - }, -#endif - { - .procname = "hugetlb_shm_group", - .data = &sysctl_hugetlb_shm_group, - .maxlen = sizeof(gid_t), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "hugepages_treat_as_movable", - .data = &hugepages_treat_as_movable, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "nr_overcommit_hugepages", - .data = NULL, - .maxlen = sizeof(unsigned long), - .mode = 0644, - .proc_handler = hugetlb_overcommit_handler, - }, -#endif - { - .procname = "lowmem_reserve_ratio", - .data = &sysctl_lowmem_reserve_ratio, - .maxlen = sizeof(sysctl_lowmem_reserve_ratio), - .mode = 0644, - .proc_handler = lowmem_reserve_ratio_sysctl_handler, - }, - { - .procname = "drop_caches", - .data = &sysctl_drop_caches, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = drop_caches_sysctl_handler, - .extra1 = &one, - .extra2 = &four, - }, -#ifdef CONFIG_COMPACTION - { - .procname = "compact_memory", - .data = &sysctl_compact_memory, - .maxlen = sizeof(int), - .mode = 0200, - .proc_handler = sysctl_compaction_handler, - }, - { - .procname = "extfrag_threshold", - .data = &sysctl_extfrag_threshold, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = sysctl_extfrag_handler, - .extra1 = &min_extfrag_threshold, - .extra2 = &max_extfrag_threshold, - }, - { - .procname = "compact_unevictable_allowed", - .data = &sysctl_compact_unevictable_allowed, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - .extra1 = &zero, - .extra2 = &one, - }, - -#endif /* CONFIG_COMPACTION */ - { - .procname = "min_free_kbytes", - .data = &min_free_kbytes, - .maxlen = sizeof(min_free_kbytes), - .mode = 0644, - .proc_handler = min_free_kbytes_sysctl_handler, - .extra1 = &zero, - }, - { - .procname = "watermark_scale_factor", - .data = &watermark_scale_factor, - .maxlen = sizeof(watermark_scale_factor), - .mode = 0644, - .proc_handler = watermark_scale_factor_sysctl_handler, - .extra1 = &one, - .extra2 = &one_thousand, - }, - { - .procname = "percpu_pagelist_fraction", - .data = &percpu_pagelist_fraction, - .maxlen = sizeof(percpu_pagelist_fraction), - .mode = 0644, - .proc_handler = percpu_pagelist_fraction_sysctl_handler, - .extra1 = &zero, - }, -#ifdef CONFIG_MMU - { - .procname = "max_map_count", - .data = &sysctl_max_map_count, - .maxlen = sizeof(sysctl_max_map_count), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - }, -#else - { - .procname = "nr_trim_pages", - .data = &sysctl_nr_trim_pages, - .maxlen = sizeof(sysctl_nr_trim_pages), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - }, -#endif - { - .procname = "laptop_mode", - .data = &laptop_mode, - .maxlen = sizeof(laptop_mode), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "block_dump", - .data = &block_dump, - .maxlen = sizeof(block_dump), - .mode = 0644, - .proc_handler = proc_dointvec, - .extra1 = &zero, - }, - { - .procname = "vfs_cache_pressure", - .data = &sysctl_vfs_cache_pressure, - .maxlen = sizeof(sysctl_vfs_cache_pressure), - .mode = 0644, - .proc_handler = proc_dointvec, - .extra1 = &zero, - }, -#ifdef HAVE_ARCH_PICK_MMAP_LAYOUT - { - .procname = "legacy_va_layout", - .data = &sysctl_legacy_va_layout, - .maxlen = sizeof(sysctl_legacy_va_layout), - .mode = 0644, - .proc_handler = proc_dointvec, - .extra1 = &zero, - }, -#endif -#ifdef CONFIG_NUMA - { - .procname = "zone_reclaim_mode", - .data = &node_reclaim_mode, - .maxlen = sizeof(node_reclaim_mode), - .mode = 0644, - .proc_handler = proc_dointvec, - .extra1 = &zero, - }, - { - .procname = "min_unmapped_ratio", - .data = &sysctl_min_unmapped_ratio, - .maxlen = sizeof(sysctl_min_unmapped_ratio), - .mode = 0644, - .proc_handler = sysctl_min_unmapped_ratio_sysctl_handler, - .extra1 = &zero, - .extra2 = &one_hundred, - }, - { - .procname = "min_slab_ratio", - .data = &sysctl_min_slab_ratio, - .maxlen = sizeof(sysctl_min_slab_ratio), - .mode = 0644, - .proc_handler = sysctl_min_slab_ratio_sysctl_handler, - .extra1 = &zero, - .extra2 = &one_hundred, - }, -#endif -#ifdef CONFIG_SMP - { - .procname = "stat_interval", - .data = &sysctl_stat_interval, - .maxlen = sizeof(sysctl_stat_interval), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "stat_refresh", - .data = NULL, - .maxlen = 0, - .mode = 0600, - .proc_handler = vmstat_refresh, - }, -#endif -#ifdef CONFIG_MMU - { - .procname = "mmap_min_addr", - .data = &dac_mmap_min_addr, - .maxlen = sizeof(unsigned long), - .mode = 0644, - .proc_handler = mmap_min_addr_handler, - }, -#endif -#ifdef CONFIG_NUMA - { - .procname = "numa_zonelist_order", - .data = &numa_zonelist_order, - .maxlen = NUMA_ZONELIST_ORDER_LEN, - .mode = 0644, - .proc_handler = numa_zonelist_order_handler, - }, -#endif -#if (defined(CONFIG_X86_32) && !defined(CONFIG_UML))|| \ - (defined(CONFIG_SUPERH) && defined(CONFIG_VSYSCALL)) - { - .procname = "vdso_enabled", -#ifdef CONFIG_X86_32 - .data = &vdso32_enabled, - .maxlen = sizeof(vdso32_enabled), -#else - .data = &vdso_enabled, - .maxlen = sizeof(vdso_enabled), -#endif - .mode = 0644, - .proc_handler = proc_dointvec, - .extra1 = &zero, - }, -#endif -#ifdef CONFIG_HIGHMEM - { - .procname = "highmem_is_dirtyable", - .data = &vm_highmem_is_dirtyable, - .maxlen = sizeof(vm_highmem_is_dirtyable), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, -#endif -#ifdef CONFIG_MEMORY_FAILURE - { - .procname = "memory_failure_early_kill", - .data = &sysctl_memory_failure_early_kill, - .maxlen = sizeof(sysctl_memory_failure_early_kill), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, - { - .procname = "memory_failure_recovery", - .data = &sysctl_memory_failure_recovery, - .maxlen = sizeof(sysctl_memory_failure_recovery), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, -#endif - { - .procname = "user_reserve_kbytes", - .data = &sysctl_user_reserve_kbytes, - .maxlen = sizeof(sysctl_user_reserve_kbytes), - .mode = 0644, - .proc_handler = proc_doulongvec_minmax, - }, - { - .procname = "admin_reserve_kbytes", - .data = &sysctl_admin_reserve_kbytes, - .maxlen = sizeof(sysctl_admin_reserve_kbytes), - .mode = 0644, - .proc_handler = proc_doulongvec_minmax, - }, -#ifdef CONFIG_HAVE_ARCH_MMAP_RND_BITS - { - .procname = "mmap_rnd_bits", - .data = &mmap_rnd_bits, - .maxlen = sizeof(mmap_rnd_bits), - .mode = 0600, - .proc_handler = proc_dointvec_minmax, - .extra1 = (void *)&mmap_rnd_bits_min, - .extra2 = (void *)&mmap_rnd_bits_max, - }, -#endif -#ifdef CONFIG_HAVE_ARCH_MMAP_RND_COMPAT_BITS - { - .procname = "mmap_rnd_compat_bits", - .data = &mmap_rnd_compat_bits, - .maxlen = sizeof(mmap_rnd_compat_bits), - .mode = 0600, - .proc_handler = proc_dointvec_minmax, - .extra1 = (void *)&mmap_rnd_compat_bits_min, - .extra2 = (void *)&mmap_rnd_compat_bits_max, - }, -#endif - { } -}; - -static struct ctl_table fs_table[] = { - { - .procname = "inode-nr", - .data = &inodes_stat, - .maxlen = 2*sizeof(long), - .mode = 0444, - .proc_handler = proc_nr_inodes, - }, - { - .procname = "inode-state", - .data = &inodes_stat, - .maxlen = 7*sizeof(long), - .mode = 0444, - .proc_handler = proc_nr_inodes, - }, - { - .procname = "file-nr", - .data = &files_stat, - .maxlen = sizeof(files_stat), - .mode = 0444, - .proc_handler = proc_nr_files, - }, - { - .procname = "file-max", - .data = &files_stat.max_files, - .maxlen = sizeof(files_stat.max_files), - .mode = 0644, - .proc_handler = proc_doulongvec_minmax, - }, - { - .procname = "nr_open", - .data = &sysctl_nr_open, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &sysctl_nr_open_min, - .extra2 = &sysctl_nr_open_max, - }, - { - .procname = "dentry-state", - .data = &dentry_stat, - .maxlen = 6*sizeof(long), - .mode = 0444, - .proc_handler = proc_nr_dentry, - }, - { - .procname = "overflowuid", - .data = &fs_overflowuid, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &minolduid, - .extra2 = &maxolduid, - }, - { - .procname = "overflowgid", - .data = &fs_overflowgid, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &minolduid, - .extra2 = &maxolduid, - }, -#ifdef CONFIG_FILE_LOCKING - { - .procname = "leases-enable", - .data = &leases_enable, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif -#ifdef CONFIG_DNOTIFY - { - .procname = "dir-notify-enable", - .data = &dir_notify_enable, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif -#ifdef CONFIG_MMU -#ifdef CONFIG_FILE_LOCKING - { - .procname = "lease-break-time", - .data = &lease_break_time, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif -#ifdef CONFIG_AIO - { - .procname = "aio-nr", - .data = &aio_nr, - .maxlen = sizeof(aio_nr), - .mode = 0444, - .proc_handler = proc_doulongvec_minmax, - }, - { - .procname = "aio-max-nr", - .data = &aio_max_nr, - .maxlen = sizeof(aio_max_nr), - .mode = 0644, - .proc_handler = proc_doulongvec_minmax, - }, -#endif /* CONFIG_AIO */ -#ifdef CONFIG_INOTIFY_USER - { - .procname = "inotify", - .mode = 0555, - .child = inotify_table, - }, -#endif -#ifdef CONFIG_EPOLL - { - .procname = "epoll", - .mode = 0555, - .child = epoll_table, - }, -#endif -#endif - { - .procname = "protected_symlinks", - .data = &sysctl_protected_symlinks, - .maxlen = sizeof(int), - .mode = 0600, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, - { - .procname = "protected_hardlinks", - .data = &sysctl_protected_hardlinks, - .maxlen = sizeof(int), - .mode = 0600, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, - { - .procname = "suid_dumpable", - .data = &suid_dumpable, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax_coredump, - .extra1 = &zero, - .extra2 = &two, - }, -#if defined(CONFIG_BINFMT_MISC) || defined(CONFIG_BINFMT_MISC_MODULE) - { - .procname = "binfmt_misc", - .mode = 0555, - .child = sysctl_mount_point, - }, -#endif - { - .procname = "pipe-max-size", - .data = &pipe_max_size, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &pipe_proc_fn, - .extra1 = &pipe_min_size, - }, - { - .procname = "pipe-user-pages-hard", - .data = &pipe_user_pages_hard, - .maxlen = sizeof(pipe_user_pages_hard), - .mode = 0644, - .proc_handler = proc_doulongvec_minmax, - }, - { - .procname = "pipe-user-pages-soft", - .data = &pipe_user_pages_soft, - .maxlen = sizeof(pipe_user_pages_soft), - .mode = 0644, - .proc_handler = proc_doulongvec_minmax, - }, - { - .procname = "mount-max", - .data = &sysctl_mount_max, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &one, - }, - { } -}; - -static struct ctl_table debug_table[] = { -#ifdef CONFIG_SYSCTL_EXCEPTION_TRACE - { - .procname = "exception-trace", - .data = &show_unhandled_signals, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, -#endif -#if defined(CONFIG_OPTPROBES) - { - .procname = "kprobes-optimization", - .data = &sysctl_kprobes_optimization, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_kprobes_optimization_handler, - .extra1 = &zero, - .extra2 = &one, - }, -#endif - { } -}; - -static struct ctl_table dev_table[] = { - { } -}; - -int __init sysctl_init(void) -{ - struct ctl_table_header *hdr; - - hdr = register_sysctl_table(sysctl_base_table); - kmemleak_not_leak(hdr); - return 0; -} - -#endif /* CONFIG_SYSCTL */ - -/* - * /proc/sys support - */ - -#ifdef CONFIG_PROC_SYSCTL - -static int _proc_do_string(char *data, int maxlen, int write, - char __user *buffer, - size_t *lenp, loff_t *ppos) -{ - size_t len; - char __user *p; - char c; - - if (!data || !maxlen || !*lenp) { - *lenp = 0; - return 0; - } - - if (write) { - if (sysctl_writes_strict == SYSCTL_WRITES_STRICT) { - /* Only continue writes not past the end of buffer. */ - len = strlen(data); - if (len > maxlen - 1) - len = maxlen - 1; - - if (*ppos > len) - return 0; - len = *ppos; - } else { - /* Start writing from beginning of buffer. */ - len = 0; - } - - *ppos += *lenp; - p = buffer; - while ((p - buffer) < *lenp && len < maxlen - 1) { - if (get_user(c, p++)) - return -EFAULT; - if (c == 0 || c == '\n') - break; - data[len++] = c; - } - data[len] = 0; - } else { - len = strlen(data); - if (len > maxlen) - len = maxlen; - - if (*ppos > len) { - *lenp = 0; - return 0; - } - - data += *ppos; - len -= *ppos; - - if (len > *lenp) - len = *lenp; - if (len) - if (copy_to_user(buffer, data, len)) - return -EFAULT; - if (len < *lenp) { - if (put_user('\n', buffer + len)) - return -EFAULT; - len++; - } - *lenp = len; - *ppos += len; - } - return 0; -} - -static void warn_sysctl_write(struct ctl_table *table) -{ - pr_warn_once("%s wrote to %s when file position was not 0!\n" - "This will not be supported in the future. To silence this\n" - "warning, set kernel.sysctl_writes_strict = -1\n", - current->comm, table->procname); -} - -/** - * proc_dostring - read a string sysctl - * @table: the sysctl table - * @write: %TRUE if this is a write to the sysctl file - * @buffer: the user buffer - * @lenp: the size of the user buffer - * @ppos: file position - * - * Reads/writes a string from/to the user buffer. If the kernel - * buffer provided is not large enough to hold the string, the - * string is truncated. The copied string is %NULL-terminated. - * If the string is being read by the user process, it is copied - * and a newline '\n' is added. It is truncated if the buffer is - * not large enough. - * - * Returns 0 on success. - */ -int proc_dostring(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - if (write && *ppos && sysctl_writes_strict == SYSCTL_WRITES_WARN) - warn_sysctl_write(table); - - return _proc_do_string((char *)(table->data), table->maxlen, write, - (char __user *)buffer, lenp, ppos); -} - -static size_t proc_skip_spaces(char **buf) -{ - size_t ret; - char *tmp = skip_spaces(*buf); - ret = tmp - *buf; - *buf = tmp; - return ret; -} - -static void proc_skip_char(char **buf, size_t *size, const char v) -{ - while (*size) { - if (**buf != v) - break; - (*size)--; - (*buf)++; - } -} - -#define TMPBUFLEN 22 -/** - * proc_get_long - reads an ASCII formatted integer from a user buffer - * - * @buf: a kernel buffer - * @size: size of the kernel buffer - * @val: this is where the number will be stored - * @neg: set to %TRUE if number is negative - * @perm_tr: a vector which contains the allowed trailers - * @perm_tr_len: size of the perm_tr vector - * @tr: pointer to store the trailer character - * - * In case of success %0 is returned and @buf and @size are updated with - * the amount of bytes read. If @tr is non-NULL and a trailing - * character exists (size is non-zero after returning from this - * function), @tr is updated with the trailing character. - */ -static int proc_get_long(char **buf, size_t *size, - unsigned long *val, bool *neg, - const char *perm_tr, unsigned perm_tr_len, char *tr) -{ - int len; - char *p, tmp[TMPBUFLEN]; - - if (!*size) - return -EINVAL; - - len = *size; - if (len > TMPBUFLEN - 1) - len = TMPBUFLEN - 1; - - memcpy(tmp, *buf, len); - - tmp[len] = 0; - p = tmp; - if (*p == '-' && *size > 1) { - *neg = true; - p++; - } else - *neg = false; - if (!isdigit(*p)) - return -EINVAL; - - *val = simple_strtoul(p, &p, 0); - - len = p - tmp; - - /* We don't know if the next char is whitespace thus we may accept - * invalid integers (e.g. 1234...a) or two integers instead of one - * (e.g. 123...1). So lets not allow such large numbers. */ - if (len == TMPBUFLEN - 1) - return -EINVAL; - - if (len < *size && perm_tr_len && !memchr(perm_tr, *p, perm_tr_len)) - return -EINVAL; - - if (tr && (len < *size)) - *tr = *p; - - *buf += len; - *size -= len; - - return 0; -} - -/** - * proc_put_long - converts an integer to a decimal ASCII formatted string - * - * @buf: the user buffer - * @size: the size of the user buffer - * @val: the integer to be converted - * @neg: sign of the number, %TRUE for negative - * - * In case of success %0 is returned and @buf and @size are updated with - * the amount of bytes written. - */ -static int proc_put_long(void __user **buf, size_t *size, unsigned long val, - bool neg) -{ - int len; - char tmp[TMPBUFLEN], *p = tmp; - - sprintf(p, "%s%lu", neg ? "-" : "", val); - len = strlen(tmp); - if (len > *size) - len = *size; - if (copy_to_user(*buf, tmp, len)) - return -EFAULT; - *size -= len; - *buf += len; - return 0; -} -#undef TMPBUFLEN - -static int proc_put_char(void __user **buf, size_t *size, char c) -{ - if (*size) { - char __user **buffer = (char __user **)buf; - if (put_user(c, *buffer)) - return -EFAULT; - (*size)--, (*buffer)++; - *buf = *buffer; - } - return 0; -} - -static int do_proc_dointvec_conv(bool *negp, unsigned long *lvalp, - int *valp, - int write, void *data) -{ - if (write) { - if (*negp) { - if (*lvalp > (unsigned long) INT_MAX + 1) - return -EINVAL; - *valp = -*lvalp; - } else { - if (*lvalp > (unsigned long) INT_MAX) - return -EINVAL; - *valp = *lvalp; - } - } else { - int val = *valp; - if (val < 0) { - *negp = true; - *lvalp = -(unsigned long)val; - } else { - *negp = false; - *lvalp = (unsigned long)val; - } - } - return 0; -} - -static int do_proc_douintvec_conv(bool *negp, unsigned long *lvalp, - int *valp, - int write, void *data) -{ - if (write) { - if (*negp) - return -EINVAL; - *valp = *lvalp; - } else { - unsigned int val = *valp; - *lvalp = (unsigned long)val; - } - return 0; -} - -static const char proc_wspace_sep[] = { ' ', '\t', '\n' }; - -static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table, - int write, void __user *buffer, - size_t *lenp, loff_t *ppos, - int (*conv)(bool *negp, unsigned long *lvalp, int *valp, - int write, void *data), - void *data) -{ - int *i, vleft, first = 1, err = 0; - size_t left; - char *kbuf = NULL, *p; - - if (!tbl_data || !table->maxlen || !*lenp || (*ppos && !write)) { - *lenp = 0; - return 0; - } - - i = (int *) tbl_data; - vleft = table->maxlen / sizeof(*i); - left = *lenp; - - if (!conv) - conv = do_proc_dointvec_conv; - - if (write) { - if (*ppos) { - switch (sysctl_writes_strict) { - case SYSCTL_WRITES_STRICT: - goto out; - case SYSCTL_WRITES_WARN: - warn_sysctl_write(table); - break; - default: - break; - } - } - - if (left > PAGE_SIZE - 1) - left = PAGE_SIZE - 1; - p = kbuf = memdup_user_nul(buffer, left); - if (IS_ERR(kbuf)) - return PTR_ERR(kbuf); - } - - for (; left && vleft--; i++, first=0) { - unsigned long lval; - bool neg; - - if (write) { - left -= proc_skip_spaces(&p); - - if (!left) - break; - err = proc_get_long(&p, &left, &lval, &neg, - proc_wspace_sep, - sizeof(proc_wspace_sep), NULL); - if (err) - break; - if (conv(&neg, &lval, i, 1, data)) { - err = -EINVAL; - break; - } - } else { - if (conv(&neg, &lval, i, 0, data)) { - err = -EINVAL; - break; - } - if (!first) - err = proc_put_char(&buffer, &left, '\t'); - if (err) - break; - err = proc_put_long(&buffer, &left, lval, neg); - if (err) - break; - } - } - - if (!write && !first && left && !err) - err = proc_put_char(&buffer, &left, '\n'); - if (write && !err && left) - left -= proc_skip_spaces(&p); - if (write) { - kfree(kbuf); - if (first) - return err ? : -EINVAL; - } - *lenp -= left; -out: - *ppos += *lenp; - return err; -} - -static int do_proc_dointvec(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos, - int (*conv)(bool *negp, unsigned long *lvalp, int *valp, - int write, void *data), - void *data) -{ - return __do_proc_dointvec(table->data, table, write, - buffer, lenp, ppos, conv, data); -} - -/** - * proc_dointvec - read a vector of integers - * @table: the sysctl table - * @write: %TRUE if this is a write to the sysctl file - * @buffer: the user buffer - * @lenp: the size of the user buffer - * @ppos: file position - * - * Reads/writes up to table->maxlen/sizeof(unsigned int) integer - * values from/to the user buffer, treated as an ASCII string. - * - * Returns 0 on success. - */ -int proc_dointvec(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return do_proc_dointvec(table, write, buffer, lenp, ppos, NULL, NULL); -} - -/** - * proc_douintvec - read a vector of unsigned integers - * @table: the sysctl table - * @write: %TRUE if this is a write to the sysctl file - * @buffer: the user buffer - * @lenp: the size of the user buffer - * @ppos: file position - * - * Reads/writes up to table->maxlen/sizeof(unsigned int) unsigned integer - * values from/to the user buffer, treated as an ASCII string. - * - * Returns 0 on success. - */ -int proc_douintvec(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return do_proc_dointvec(table, write, buffer, lenp, ppos, - do_proc_douintvec_conv, NULL); -} - -/* - * Taint values can only be increased - * This means we can safely use a temporary. - */ -static int proc_taint(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - struct ctl_table t; - unsigned long tmptaint = get_taint(); - int err; - - if (write && !capable(CAP_SYS_ADMIN)) - return -EPERM; - - t = *table; - t.data = &tmptaint; - err = proc_doulongvec_minmax(&t, write, buffer, lenp, ppos); - if (err < 0) - return err; - - if (write) { - /* - * Poor man's atomic or. Not worth adding a primitive - * to everyone's atomic.h for this - */ - int i; - for (i = 0; i < BITS_PER_LONG && tmptaint >> i; i++) { - if ((tmptaint >> i) & 1) - add_taint(i, LOCKDEP_STILL_OK); - } - } - - return err; -} - -#ifdef CONFIG_PRINTK -static int proc_dointvec_minmax_sysadmin(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - if (write && !capable(CAP_SYS_ADMIN)) - return -EPERM; - - return proc_dointvec_minmax(table, write, buffer, lenp, ppos); -} -#endif - -struct do_proc_dointvec_minmax_conv_param { - int *min; - int *max; -}; - -static int do_proc_dointvec_minmax_conv(bool *negp, unsigned long *lvalp, - int *valp, - int write, void *data) -{ - struct do_proc_dointvec_minmax_conv_param *param = data; - if (write) { - int val = *negp ? -*lvalp : *lvalp; - if ((param->min && *param->min > val) || - (param->max && *param->max < val)) - return -EINVAL; - *valp = val; - } else { - int val = *valp; - if (val < 0) { - *negp = true; - *lvalp = -(unsigned long)val; - } else { - *negp = false; - *lvalp = (unsigned long)val; - } - } - return 0; -} - -/** - * proc_dointvec_minmax - read a vector of integers with min/max values - * @table: the sysctl table - * @write: %TRUE if this is a write to the sysctl file - * @buffer: the user buffer - * @lenp: the size of the user buffer - * @ppos: file position - * - * Reads/writes up to table->maxlen/sizeof(unsigned int) integer - * values from/to the user buffer, treated as an ASCII string. - * - * This routine will ensure the values are within the range specified by - * table->extra1 (min) and table->extra2 (max). - * - * Returns 0 on success. - */ -int proc_dointvec_minmax(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - struct do_proc_dointvec_minmax_conv_param param = { - .min = (int *) table->extra1, - .max = (int *) table->extra2, - }; - return do_proc_dointvec(table, write, buffer, lenp, ppos, - do_proc_dointvec_minmax_conv, ¶m); -} - -static void validate_coredump_safety(void) -{ -#ifdef CONFIG_COREDUMP - if (suid_dumpable == SUID_DUMP_ROOT && - core_pattern[0] != '/' && core_pattern[0] != '|') { - printk(KERN_WARNING "Unsafe core_pattern used with "\ - "suid_dumpable=2. Pipe handler or fully qualified "\ - "core dump path required.\n"); - } -#endif -} - -static int proc_dointvec_minmax_coredump(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - int error = proc_dointvec_minmax(table, write, buffer, lenp, ppos); - if (!error) - validate_coredump_safety(); - return error; -} - -#ifdef CONFIG_COREDUMP -static int proc_dostring_coredump(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - int error = proc_dostring(table, write, buffer, lenp, ppos); - if (!error) - validate_coredump_safety(); - return error; -} -#endif - -static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos, - unsigned long convmul, - unsigned long convdiv) -{ - unsigned long *i, *min, *max; - int vleft, first = 1, err = 0; - size_t left; - char *kbuf = NULL, *p; - - if (!data || !table->maxlen || !*lenp || (*ppos && !write)) { - *lenp = 0; - return 0; - } - - i = (unsigned long *) data; - min = (unsigned long *) table->extra1; - max = (unsigned long *) table->extra2; - vleft = table->maxlen / sizeof(unsigned long); - left = *lenp; - - if (write) { - if (*ppos) { - switch (sysctl_writes_strict) { - case SYSCTL_WRITES_STRICT: - goto out; - case SYSCTL_WRITES_WARN: - warn_sysctl_write(table); - break; - default: - break; - } - } - - if (left > PAGE_SIZE - 1) - left = PAGE_SIZE - 1; - p = kbuf = memdup_user_nul(buffer, left); - if (IS_ERR(kbuf)) - return PTR_ERR(kbuf); - } - - for (; left && vleft--; i++, first = 0) { - unsigned long val; - - if (write) { - bool neg; - - left -= proc_skip_spaces(&p); - - err = proc_get_long(&p, &left, &val, &neg, - proc_wspace_sep, - sizeof(proc_wspace_sep), NULL); - if (err) - break; - if (neg) - continue; - if ((min && val < *min) || (max && val > *max)) - continue; - *i = val; - } else { - val = convdiv * (*i) / convmul; - if (!first) { - err = proc_put_char(&buffer, &left, '\t'); - if (err) - break; - } - err = proc_put_long(&buffer, &left, val, false); - if (err) - break; - } - } - - if (!write && !first && left && !err) - err = proc_put_char(&buffer, &left, '\n'); - if (write && !err) - left -= proc_skip_spaces(&p); - if (write) { - kfree(kbuf); - if (first) - return err ? : -EINVAL; - } - *lenp -= left; -out: - *ppos += *lenp; - return err; -} - -static int do_proc_doulongvec_minmax(struct ctl_table *table, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos, - unsigned long convmul, - unsigned long convdiv) -{ - return __do_proc_doulongvec_minmax(table->data, table, write, - buffer, lenp, ppos, convmul, convdiv); -} - -/** - * proc_doulongvec_minmax - read a vector of long integers with min/max values - * @table: the sysctl table - * @write: %TRUE if this is a write to the sysctl file - * @buffer: the user buffer - * @lenp: the size of the user buffer - * @ppos: file position - * - * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long - * values from/to the user buffer, treated as an ASCII string. - * - * This routine will ensure the values are within the range specified by - * table->extra1 (min) and table->extra2 (max). - * - * Returns 0 on success. - */ -int proc_doulongvec_minmax(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return do_proc_doulongvec_minmax(table, write, buffer, lenp, ppos, 1l, 1l); -} - -/** - * proc_doulongvec_ms_jiffies_minmax - read a vector of millisecond values with min/max values - * @table: the sysctl table - * @write: %TRUE if this is a write to the sysctl file - * @buffer: the user buffer - * @lenp: the size of the user buffer - * @ppos: file position - * - * Reads/writes up to table->maxlen/sizeof(unsigned long) unsigned long - * values from/to the user buffer, treated as an ASCII string. The values - * are treated as milliseconds, and converted to jiffies when they are stored. - * - * This routine will ensure the values are within the range specified by - * table->extra1 (min) and table->extra2 (max). - * - * Returns 0 on success. - */ -int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - return do_proc_doulongvec_minmax(table, write, buffer, - lenp, ppos, HZ, 1000l); -} - - -static int do_proc_dointvec_jiffies_conv(bool *negp, unsigned long *lvalp, - int *valp, - int write, void *data) -{ - if (write) { - if (*lvalp > LONG_MAX / HZ) - return 1; - *valp = *negp ? -(*lvalp*HZ) : (*lvalp*HZ); - } else { - int val = *valp; - unsigned long lval; - if (val < 0) { - *negp = true; - lval = -(unsigned long)val; - } else { - *negp = false; - lval = (unsigned long)val; - } - *lvalp = lval / HZ; - } - return 0; -} - -static int do_proc_dointvec_userhz_jiffies_conv(bool *negp, unsigned long *lvalp, - int *valp, - int write, void *data) -{ - if (write) { - if (USER_HZ < HZ && *lvalp > (LONG_MAX / HZ) * USER_HZ) - return 1; - *valp = clock_t_to_jiffies(*negp ? -*lvalp : *lvalp); - } else { - int val = *valp; - unsigned long lval; - if (val < 0) { - *negp = true; - lval = -(unsigned long)val; - } else { - *negp = false; - lval = (unsigned long)val; - } - *lvalp = jiffies_to_clock_t(lval); - } - return 0; -} - -static int do_proc_dointvec_ms_jiffies_conv(bool *negp, unsigned long *lvalp, - int *valp, - int write, void *data) -{ - if (write) { - unsigned long jif = msecs_to_jiffies(*negp ? -*lvalp : *lvalp); - - if (jif > INT_MAX) - return 1; - *valp = (int)jif; - } else { - int val = *valp; - unsigned long lval; - if (val < 0) { - *negp = true; - lval = -(unsigned long)val; - } else { - *negp = false; - lval = (unsigned long)val; - } - *lvalp = jiffies_to_msecs(lval); - } - return 0; -} - -/** - * proc_dointvec_jiffies - read a vector of integers as seconds - * @table: the sysctl table - * @write: %TRUE if this is a write to the sysctl file - * @buffer: the user buffer - * @lenp: the size of the user buffer - * @ppos: file position - * - * Reads/writes up to table->maxlen/sizeof(unsigned int) integer - * values from/to the user buffer, treated as an ASCII string. - * The values read are assumed to be in seconds, and are converted into - * jiffies. - * - * Returns 0 on success. - */ -int proc_dointvec_jiffies(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return do_proc_dointvec(table,write,buffer,lenp,ppos, - do_proc_dointvec_jiffies_conv,NULL); -} - -/** - * proc_dointvec_userhz_jiffies - read a vector of integers as 1/USER_HZ seconds - * @table: the sysctl table - * @write: %TRUE if this is a write to the sysctl file - * @buffer: the user buffer - * @lenp: the size of the user buffer - * @ppos: pointer to the file position - * - * Reads/writes up to table->maxlen/sizeof(unsigned int) integer - * values from/to the user buffer, treated as an ASCII string. - * The values read are assumed to be in 1/USER_HZ seconds, and - * are converted into jiffies. - * - * Returns 0 on success. - */ -int proc_dointvec_userhz_jiffies(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return do_proc_dointvec(table,write,buffer,lenp,ppos, - do_proc_dointvec_userhz_jiffies_conv,NULL); -} - -/** - * proc_dointvec_ms_jiffies - read a vector of integers as 1 milliseconds - * @table: the sysctl table - * @write: %TRUE if this is a write to the sysctl file - * @buffer: the user buffer - * @lenp: the size of the user buffer - * @ppos: file position - * @ppos: the current position in the file - * - * Reads/writes up to table->maxlen/sizeof(unsigned int) integer - * values from/to the user buffer, treated as an ASCII string. - * The values read are assumed to be in 1/1000 seconds, and - * are converted into jiffies. - * - * Returns 0 on success. - */ -int proc_dointvec_ms_jiffies(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return do_proc_dointvec(table, write, buffer, lenp, ppos, - do_proc_dointvec_ms_jiffies_conv, NULL); -} - -static int proc_do_cad_pid(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - struct pid *new_pid; - pid_t tmp; - int r; - - tmp = pid_vnr(cad_pid); - - r = __do_proc_dointvec(&tmp, table, write, buffer, - lenp, ppos, NULL, NULL); - if (r || !write) - return r; - - new_pid = find_get_pid(tmp); - if (!new_pid) - return -ESRCH; - - put_pid(xchg(&cad_pid, new_pid)); - return 0; -} - -/** - * proc_do_large_bitmap - read/write from/to a large bitmap - * @table: the sysctl table - * @write: %TRUE if this is a write to the sysctl file - * @buffer: the user buffer - * @lenp: the size of the user buffer - * @ppos: file position - * - * The bitmap is stored at table->data and the bitmap length (in bits) - * in table->maxlen. - * - * We use a range comma separated format (e.g. 1,3-4,10-10) so that - * large bitmaps may be represented in a compact manner. Writing into - * the file will clear the bitmap then update it with the given input. - * - * Returns 0 on success. - */ -int proc_do_large_bitmap(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - int err = 0; - bool first = 1; - size_t left = *lenp; - unsigned long bitmap_len = table->maxlen; - unsigned long *bitmap = *(unsigned long **) table->data; - unsigned long *tmp_bitmap = NULL; - char tr_a[] = { '-', ',', '\n' }, tr_b[] = { ',', '\n', 0 }, c; - - if (!bitmap || !bitmap_len || !left || (*ppos && !write)) { - *lenp = 0; - return 0; - } - - if (write) { - char *kbuf, *p; - - if (left > PAGE_SIZE - 1) - left = PAGE_SIZE - 1; - - p = kbuf = memdup_user_nul(buffer, left); - if (IS_ERR(kbuf)) - return PTR_ERR(kbuf); - - tmp_bitmap = kzalloc(BITS_TO_LONGS(bitmap_len) * sizeof(unsigned long), - GFP_KERNEL); - if (!tmp_bitmap) { - kfree(kbuf); - return -ENOMEM; - } - proc_skip_char(&p, &left, '\n'); - while (!err && left) { - unsigned long val_a, val_b; - bool neg; - - err = proc_get_long(&p, &left, &val_a, &neg, tr_a, - sizeof(tr_a), &c); - if (err) - break; - if (val_a >= bitmap_len || neg) { - err = -EINVAL; - break; - } - - val_b = val_a; - if (left) { - p++; - left--; - } - - if (c == '-') { - err = proc_get_long(&p, &left, &val_b, - &neg, tr_b, sizeof(tr_b), - &c); - if (err) - break; - if (val_b >= bitmap_len || neg || - val_a > val_b) { - err = -EINVAL; - break; - } - if (left) { - p++; - left--; - } - } - - bitmap_set(tmp_bitmap, val_a, val_b - val_a + 1); - first = 0; - proc_skip_char(&p, &left, '\n'); - } - kfree(kbuf); - } else { - unsigned long bit_a, bit_b = 0; - - while (left) { - bit_a = find_next_bit(bitmap, bitmap_len, bit_b); - if (bit_a >= bitmap_len) - break; - bit_b = find_next_zero_bit(bitmap, bitmap_len, - bit_a + 1) - 1; - - if (!first) { - err = proc_put_char(&buffer, &left, ','); - if (err) - break; - } - err = proc_put_long(&buffer, &left, bit_a, false); - if (err) - break; - if (bit_a != bit_b) { - err = proc_put_char(&buffer, &left, '-'); - if (err) - break; - err = proc_put_long(&buffer, &left, bit_b, false); - if (err) - break; - } - - first = 0; bit_b++; - } - if (!err) - err = proc_put_char(&buffer, &left, '\n'); - } - - if (!err) { - if (write) { - if (*ppos) - bitmap_or(bitmap, bitmap, tmp_bitmap, bitmap_len); - else - bitmap_copy(bitmap, tmp_bitmap, bitmap_len); - } - kfree(tmp_bitmap); - *lenp -= left; - *ppos += *lenp; - return 0; - } else { - kfree(tmp_bitmap); - return err; - } -} - -#else /* CONFIG_PROC_SYSCTL */ - -int proc_dostring(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return -ENOSYS; -} - -int proc_dointvec(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return -ENOSYS; -} - -int proc_douintvec(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return -ENOSYS; -} - -int proc_dointvec_minmax(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return -ENOSYS; -} - -int proc_dointvec_jiffies(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return -ENOSYS; -} - -int proc_dointvec_userhz_jiffies(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return -ENOSYS; -} - -int proc_dointvec_ms_jiffies(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return -ENOSYS; -} - -int proc_doulongvec_minmax(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - return -ENOSYS; -} - -int proc_doulongvec_ms_jiffies_minmax(struct ctl_table *table, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - return -ENOSYS; -} - - -#endif /* CONFIG_PROC_SYSCTL */ - -/* - * No sense putting this after each symbol definition, twice, - * exception granted :-) - */ -EXPORT_SYMBOL(proc_dointvec); -EXPORT_SYMBOL(proc_douintvec); -EXPORT_SYMBOL(proc_dointvec_jiffies); -EXPORT_SYMBOL(proc_dointvec_minmax); -EXPORT_SYMBOL(proc_dointvec_userhz_jiffies); -EXPORT_SYMBOL(proc_dointvec_ms_jiffies); -EXPORT_SYMBOL(proc_dostring); -EXPORT_SYMBOL(proc_doulongvec_minmax); -EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax); diff --git a/src/linux/kernel/sysctl_binary.c b/src/linux/kernel/sysctl_binary.c deleted file mode 100644 index 6eb99c1..0000000 --- a/src/linux/kernel/sysctl_binary.c +++ /dev/null @@ -1,1485 +0,0 @@ -#include -#include -#include "../fs/xfs/xfs_sysctl.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_SYSCTL_SYSCALL - -struct bin_table; -typedef ssize_t bin_convert_t(struct file *file, - void __user *oldval, size_t oldlen, void __user *newval, size_t newlen); - -static bin_convert_t bin_dir; -static bin_convert_t bin_string; -static bin_convert_t bin_intvec; -static bin_convert_t bin_ulongvec; -static bin_convert_t bin_uuid; -static bin_convert_t bin_dn_node_address; - -#define CTL_DIR bin_dir -#define CTL_STR bin_string -#define CTL_INT bin_intvec -#define CTL_ULONG bin_ulongvec -#define CTL_UUID bin_uuid -#define CTL_DNADR bin_dn_node_address - -#define BUFSZ 256 - -struct bin_table { - bin_convert_t *convert; - int ctl_name; - const char *procname; - const struct bin_table *child; -}; - -static const struct bin_table bin_random_table[] = { - { CTL_INT, RANDOM_POOLSIZE, "poolsize" }, - { CTL_INT, RANDOM_ENTROPY_COUNT, "entropy_avail" }, - { CTL_INT, RANDOM_READ_THRESH, "read_wakeup_threshold" }, - { CTL_INT, RANDOM_WRITE_THRESH, "write_wakeup_threshold" }, - { CTL_UUID, RANDOM_BOOT_ID, "boot_id" }, - { CTL_UUID, RANDOM_UUID, "uuid" }, - {} -}; - -static const struct bin_table bin_pty_table[] = { - { CTL_INT, PTY_MAX, "max" }, - { CTL_INT, PTY_NR, "nr" }, - {} -}; - -static const struct bin_table bin_kern_table[] = { - { CTL_STR, KERN_OSTYPE, "ostype" }, - { CTL_STR, KERN_OSRELEASE, "osrelease" }, - /* KERN_OSREV not used */ - { CTL_STR, KERN_VERSION, "version" }, - /* KERN_SECUREMASK not used */ - /* KERN_PROF not used */ - { CTL_STR, KERN_NODENAME, "hostname" }, - { CTL_STR, KERN_DOMAINNAME, "domainname" }, - - { CTL_INT, KERN_PANIC, "panic" }, - { CTL_INT, KERN_REALROOTDEV, "real-root-dev" }, - - { CTL_STR, KERN_SPARC_REBOOT, "reboot-cmd" }, - { CTL_INT, KERN_CTLALTDEL, "ctrl-alt-del" }, - { CTL_INT, KERN_PRINTK, "printk" }, - - /* KERN_NAMETRANS not used */ - /* KERN_PPC_HTABRECLAIM not used */ - /* KERN_PPC_ZEROPAGED not used */ - { CTL_INT, KERN_PPC_POWERSAVE_NAP, "powersave-nap" }, - - { CTL_STR, KERN_MODPROBE, "modprobe" }, - { CTL_INT, KERN_SG_BIG_BUFF, "sg-big-buff" }, - { CTL_INT, KERN_ACCT, "acct" }, - /* KERN_PPC_L2CR "l2cr" no longer used */ - - /* KERN_RTSIGNR not used */ - /* KERN_RTSIGMAX not used */ - - { CTL_ULONG, KERN_SHMMAX, "shmmax" }, - { CTL_INT, KERN_MSGMAX, "msgmax" }, - { CTL_INT, KERN_MSGMNB, "msgmnb" }, - /* KERN_MSGPOOL not used*/ - { CTL_INT, KERN_SYSRQ, "sysrq" }, - { CTL_INT, KERN_MAX_THREADS, "threads-max" }, - { CTL_DIR, KERN_RANDOM, "random", bin_random_table }, - { CTL_ULONG, KERN_SHMALL, "shmall" }, - { CTL_INT, KERN_MSGMNI, "msgmni" }, - { CTL_INT, KERN_SEM, "sem" }, - { CTL_INT, KERN_SPARC_STOP_A, "stop-a" }, - { CTL_INT, KERN_SHMMNI, "shmmni" }, - - { CTL_INT, KERN_OVERFLOWUID, "overflowuid" }, - { CTL_INT, KERN_OVERFLOWGID, "overflowgid" }, - - { CTL_STR, KERN_HOTPLUG, "hotplug", }, - { CTL_INT, KERN_IEEE_EMULATION_WARNINGS, "ieee_emulation_warnings" }, - - { CTL_INT, KERN_S390_USER_DEBUG_LOGGING, "userprocess_debug" }, - { CTL_INT, KERN_CORE_USES_PID, "core_uses_pid" }, - /* KERN_TAINTED "tainted" no longer used */ - { CTL_INT, KERN_CADPID, "cad_pid" }, - { CTL_INT, KERN_PIDMAX, "pid_max" }, - { CTL_STR, KERN_CORE_PATTERN, "core_pattern" }, - { CTL_INT, KERN_PANIC_ON_OOPS, "panic_on_oops" }, - { CTL_INT, KERN_HPPA_PWRSW, "soft-power" }, - { CTL_INT, KERN_HPPA_UNALIGNED, "unaligned-trap" }, - - { CTL_INT, KERN_PRINTK_RATELIMIT, "printk_ratelimit" }, - { CTL_INT, KERN_PRINTK_RATELIMIT_BURST, "printk_ratelimit_burst" }, - - { CTL_DIR, KERN_PTY, "pty", bin_pty_table }, - { CTL_INT, KERN_NGROUPS_MAX, "ngroups_max" }, - { CTL_INT, KERN_SPARC_SCONS_PWROFF, "scons-poweroff" }, - /* KERN_HZ_TIMER "hz_timer" no longer used */ - { CTL_INT, KERN_UNKNOWN_NMI_PANIC, "unknown_nmi_panic" }, - { CTL_INT, KERN_BOOTLOADER_TYPE, "bootloader_type" }, - { CTL_INT, KERN_RANDOMIZE, "randomize_va_space" }, - - { CTL_INT, KERN_SPIN_RETRY, "spin_retry" }, - /* KERN_ACPI_VIDEO_FLAGS "acpi_video_flags" no longer used */ - { CTL_INT, KERN_IA64_UNALIGNED, "ignore-unaligned-usertrap" }, - { CTL_INT, KERN_COMPAT_LOG, "compat-log" }, - { CTL_INT, KERN_MAX_LOCK_DEPTH, "max_lock_depth" }, - { CTL_INT, KERN_PANIC_ON_NMI, "panic_on_unrecovered_nmi" }, - { CTL_INT, KERN_PANIC_ON_WARN, "panic_on_warn" }, - {} -}; - -static const struct bin_table bin_vm_table[] = { - { CTL_INT, VM_OVERCOMMIT_MEMORY, "overcommit_memory" }, - { CTL_INT, VM_PAGE_CLUSTER, "page-cluster" }, - { CTL_INT, VM_DIRTY_BACKGROUND, "dirty_background_ratio" }, - { CTL_INT, VM_DIRTY_RATIO, "dirty_ratio" }, - /* VM_DIRTY_WB_CS "dirty_writeback_centisecs" no longer used */ - /* VM_DIRTY_EXPIRE_CS "dirty_expire_centisecs" no longer used */ - /* VM_NR_PDFLUSH_THREADS "nr_pdflush_threads" no longer used */ - { CTL_INT, VM_OVERCOMMIT_RATIO, "overcommit_ratio" }, - /* VM_PAGEBUF unused */ - /* VM_HUGETLB_PAGES "nr_hugepages" no longer used */ - { CTL_INT, VM_SWAPPINESS, "swappiness" }, - { CTL_INT, VM_LOWMEM_RESERVE_RATIO, "lowmem_reserve_ratio" }, - { CTL_INT, VM_MIN_FREE_KBYTES, "min_free_kbytes" }, - { CTL_INT, VM_MAX_MAP_COUNT, "max_map_count" }, - { CTL_INT, VM_LAPTOP_MODE, "laptop_mode" }, - { CTL_INT, VM_BLOCK_DUMP, "block_dump" }, - { CTL_INT, VM_HUGETLB_GROUP, "hugetlb_shm_group" }, - { CTL_INT, VM_VFS_CACHE_PRESSURE, "vfs_cache_pressure" }, - { CTL_INT, VM_LEGACY_VA_LAYOUT, "legacy_va_layout" }, - /* VM_SWAP_TOKEN_TIMEOUT unused */ - { CTL_INT, VM_DROP_PAGECACHE, "drop_caches" }, - { CTL_INT, VM_PERCPU_PAGELIST_FRACTION, "percpu_pagelist_fraction" }, - { CTL_INT, VM_ZONE_RECLAIM_MODE, "zone_reclaim_mode" }, - { CTL_INT, VM_MIN_UNMAPPED, "min_unmapped_ratio" }, - { CTL_INT, VM_PANIC_ON_OOM, "panic_on_oom" }, - { CTL_INT, VM_VDSO_ENABLED, "vdso_enabled" }, - { CTL_INT, VM_MIN_SLAB, "min_slab_ratio" }, - - {} -}; - -static const struct bin_table bin_net_core_table[] = { - { CTL_INT, NET_CORE_WMEM_MAX, "wmem_max" }, - { CTL_INT, NET_CORE_RMEM_MAX, "rmem_max" }, - { CTL_INT, NET_CORE_WMEM_DEFAULT, "wmem_default" }, - { CTL_INT, NET_CORE_RMEM_DEFAULT, "rmem_default" }, - /* NET_CORE_DESTROY_DELAY unused */ - { CTL_INT, NET_CORE_MAX_BACKLOG, "netdev_max_backlog" }, - /* NET_CORE_FASTROUTE unused */ - { CTL_INT, NET_CORE_MSG_COST, "message_cost" }, - { CTL_INT, NET_CORE_MSG_BURST, "message_burst" }, - { CTL_INT, NET_CORE_OPTMEM_MAX, "optmem_max" }, - /* NET_CORE_HOT_LIST_LENGTH unused */ - /* NET_CORE_DIVERT_VERSION unused */ - /* NET_CORE_NO_CONG_THRESH unused */ - /* NET_CORE_NO_CONG unused */ - /* NET_CORE_LO_CONG unused */ - /* NET_CORE_MOD_CONG unused */ - { CTL_INT, NET_CORE_DEV_WEIGHT, "dev_weight" }, - { CTL_INT, NET_CORE_SOMAXCONN, "somaxconn" }, - { CTL_INT, NET_CORE_BUDGET, "netdev_budget" }, - { CTL_INT, NET_CORE_AEVENT_ETIME, "xfrm_aevent_etime" }, - { CTL_INT, NET_CORE_AEVENT_RSEQTH, "xfrm_aevent_rseqth" }, - { CTL_INT, NET_CORE_WARNINGS, "warnings" }, - {}, -}; - -static const struct bin_table bin_net_unix_table[] = { - /* NET_UNIX_DESTROY_DELAY unused */ - /* NET_UNIX_DELETE_DELAY unused */ - { CTL_INT, NET_UNIX_MAX_DGRAM_QLEN, "max_dgram_qlen" }, - {} -}; - -static const struct bin_table bin_net_ipv4_route_table[] = { - { CTL_INT, NET_IPV4_ROUTE_FLUSH, "flush" }, - /* NET_IPV4_ROUTE_MIN_DELAY "min_delay" no longer used */ - /* NET_IPV4_ROUTE_MAX_DELAY "max_delay" no longer used */ - { CTL_INT, NET_IPV4_ROUTE_GC_THRESH, "gc_thresh" }, - { CTL_INT, NET_IPV4_ROUTE_MAX_SIZE, "max_size" }, - { CTL_INT, NET_IPV4_ROUTE_GC_MIN_INTERVAL, "gc_min_interval" }, - { CTL_INT, NET_IPV4_ROUTE_GC_MIN_INTERVAL_MS, "gc_min_interval_ms" }, - { CTL_INT, NET_IPV4_ROUTE_GC_TIMEOUT, "gc_timeout" }, - /* NET_IPV4_ROUTE_GC_INTERVAL "gc_interval" no longer used */ - { CTL_INT, NET_IPV4_ROUTE_REDIRECT_LOAD, "redirect_load" }, - { CTL_INT, NET_IPV4_ROUTE_REDIRECT_NUMBER, "redirect_number" }, - { CTL_INT, NET_IPV4_ROUTE_REDIRECT_SILENCE, "redirect_silence" }, - { CTL_INT, NET_IPV4_ROUTE_ERROR_COST, "error_cost" }, - { CTL_INT, NET_IPV4_ROUTE_ERROR_BURST, "error_burst" }, - { CTL_INT, NET_IPV4_ROUTE_GC_ELASTICITY, "gc_elasticity" }, - { CTL_INT, NET_IPV4_ROUTE_MTU_EXPIRES, "mtu_expires" }, - { CTL_INT, NET_IPV4_ROUTE_MIN_PMTU, "min_pmtu" }, - { CTL_INT, NET_IPV4_ROUTE_MIN_ADVMSS, "min_adv_mss" }, - {} -}; - -static const struct bin_table bin_net_ipv4_conf_vars_table[] = { - { CTL_INT, NET_IPV4_CONF_FORWARDING, "forwarding" }, - { CTL_INT, NET_IPV4_CONF_MC_FORWARDING, "mc_forwarding" }, - - { CTL_INT, NET_IPV4_CONF_ACCEPT_REDIRECTS, "accept_redirects" }, - { CTL_INT, NET_IPV4_CONF_SECURE_REDIRECTS, "secure_redirects" }, - { CTL_INT, NET_IPV4_CONF_SEND_REDIRECTS, "send_redirects" }, - { CTL_INT, NET_IPV4_CONF_SHARED_MEDIA, "shared_media" }, - { CTL_INT, NET_IPV4_CONF_RP_FILTER, "rp_filter" }, - { CTL_INT, NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE, "accept_source_route" }, - { CTL_INT, NET_IPV4_CONF_PROXY_ARP, "proxy_arp" }, - { CTL_INT, NET_IPV4_CONF_MEDIUM_ID, "medium_id" }, - { CTL_INT, NET_IPV4_CONF_BOOTP_RELAY, "bootp_relay" }, - { CTL_INT, NET_IPV4_CONF_LOG_MARTIANS, "log_martians" }, - { CTL_INT, NET_IPV4_CONF_TAG, "tag" }, - { CTL_INT, NET_IPV4_CONF_ARPFILTER, "arp_filter" }, - { CTL_INT, NET_IPV4_CONF_ARP_ANNOUNCE, "arp_announce" }, - { CTL_INT, NET_IPV4_CONF_ARP_IGNORE, "arp_ignore" }, - { CTL_INT, NET_IPV4_CONF_ARP_ACCEPT, "arp_accept" }, - { CTL_INT, NET_IPV4_CONF_ARP_NOTIFY, "arp_notify" }, - - { CTL_INT, NET_IPV4_CONF_NOXFRM, "disable_xfrm" }, - { CTL_INT, NET_IPV4_CONF_NOPOLICY, "disable_policy" }, - { CTL_INT, NET_IPV4_CONF_FORCE_IGMP_VERSION, "force_igmp_version" }, - { CTL_INT, NET_IPV4_CONF_PROMOTE_SECONDARIES, "promote_secondaries" }, - {} -}; - -static const struct bin_table bin_net_ipv4_conf_table[] = { - { CTL_DIR, NET_PROTO_CONF_ALL, "all", bin_net_ipv4_conf_vars_table }, - { CTL_DIR, NET_PROTO_CONF_DEFAULT, "default", bin_net_ipv4_conf_vars_table }, - { CTL_DIR, 0, NULL, bin_net_ipv4_conf_vars_table }, - {} -}; - -static const struct bin_table bin_net_neigh_vars_table[] = { - { CTL_INT, NET_NEIGH_MCAST_SOLICIT, "mcast_solicit" }, - { CTL_INT, NET_NEIGH_UCAST_SOLICIT, "ucast_solicit" }, - { CTL_INT, NET_NEIGH_APP_SOLICIT, "app_solicit" }, - /* NET_NEIGH_RETRANS_TIME "retrans_time" no longer used */ - { CTL_INT, NET_NEIGH_REACHABLE_TIME, "base_reachable_time" }, - { CTL_INT, NET_NEIGH_DELAY_PROBE_TIME, "delay_first_probe_time" }, - { CTL_INT, NET_NEIGH_GC_STALE_TIME, "gc_stale_time" }, - { CTL_INT, NET_NEIGH_UNRES_QLEN, "unres_qlen" }, - { CTL_INT, NET_NEIGH_PROXY_QLEN, "proxy_qlen" }, - /* NET_NEIGH_ANYCAST_DELAY "anycast_delay" no longer used */ - /* NET_NEIGH_PROXY_DELAY "proxy_delay" no longer used */ - /* NET_NEIGH_LOCKTIME "locktime" no longer used */ - { CTL_INT, NET_NEIGH_GC_INTERVAL, "gc_interval" }, - { CTL_INT, NET_NEIGH_GC_THRESH1, "gc_thresh1" }, - { CTL_INT, NET_NEIGH_GC_THRESH2, "gc_thresh2" }, - { CTL_INT, NET_NEIGH_GC_THRESH3, "gc_thresh3" }, - { CTL_INT, NET_NEIGH_RETRANS_TIME_MS, "retrans_time_ms" }, - { CTL_INT, NET_NEIGH_REACHABLE_TIME_MS, "base_reachable_time_ms" }, - {} -}; - -static const struct bin_table bin_net_neigh_table[] = { - { CTL_DIR, NET_PROTO_CONF_DEFAULT, "default", bin_net_neigh_vars_table }, - { CTL_DIR, 0, NULL, bin_net_neigh_vars_table }, - {} -}; - -static const struct bin_table bin_net_ipv4_netfilter_table[] = { - { CTL_INT, NET_IPV4_NF_CONNTRACK_MAX, "ip_conntrack_max" }, - - /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT "ip_conntrack_tcp_timeout_syn_sent" no longer used */ - /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV "ip_conntrack_tcp_timeout_syn_recv" no longer used */ - /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED "ip_conntrack_tcp_timeout_established" no longer used */ - /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT "ip_conntrack_tcp_timeout_fin_wait" no longer used */ - /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT "ip_conntrack_tcp_timeout_close_wait" no longer used */ - /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK "ip_conntrack_tcp_timeout_last_ack" no longer used */ - /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT "ip_conntrack_tcp_timeout_time_wait" no longer used */ - /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_CLOSE "ip_conntrack_tcp_timeout_close" no longer used */ - - /* NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT "ip_conntrack_udp_timeout" no longer used */ - /* NET_IPV4_NF_CONNTRACK_UDP_TIMEOUT_STREAM "ip_conntrack_udp_timeout_stream" no longer used */ - /* NET_IPV4_NF_CONNTRACK_ICMP_TIMEOUT "ip_conntrack_icmp_timeout" no longer used */ - /* NET_IPV4_NF_CONNTRACK_GENERIC_TIMEOUT "ip_conntrack_generic_timeout" no longer used */ - - { CTL_INT, NET_IPV4_NF_CONNTRACK_BUCKETS, "ip_conntrack_buckets" }, - { CTL_INT, NET_IPV4_NF_CONNTRACK_LOG_INVALID, "ip_conntrack_log_invalid" }, - /* NET_IPV4_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS "ip_conntrack_tcp_timeout_max_retrans" no longer used */ - { CTL_INT, NET_IPV4_NF_CONNTRACK_TCP_LOOSE, "ip_conntrack_tcp_loose" }, - { CTL_INT, NET_IPV4_NF_CONNTRACK_TCP_BE_LIBERAL, "ip_conntrack_tcp_be_liberal" }, - { CTL_INT, NET_IPV4_NF_CONNTRACK_TCP_MAX_RETRANS, "ip_conntrack_tcp_max_retrans" }, - - /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED "ip_conntrack_sctp_timeout_closed" no longer used */ - /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT "ip_conntrack_sctp_timeout_cookie_wait" no longer used */ - /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED "ip_conntrack_sctp_timeout_cookie_echoed" no longer used */ - /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED "ip_conntrack_sctp_timeout_established" no longer used */ - /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT "ip_conntrack_sctp_timeout_shutdown_sent" no longer used */ - /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD "ip_conntrack_sctp_timeout_shutdown_recd" no longer used */ - /* NET_IPV4_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT "ip_conntrack_sctp_timeout_shutdown_ack_sent" no longer used */ - - { CTL_INT, NET_IPV4_NF_CONNTRACK_COUNT, "ip_conntrack_count" }, - { CTL_INT, NET_IPV4_NF_CONNTRACK_CHECKSUM, "ip_conntrack_checksum" }, - {} -}; - -static const struct bin_table bin_net_ipv4_table[] = { - {CTL_INT, NET_IPV4_FORWARD, "ip_forward" }, - - { CTL_DIR, NET_IPV4_CONF, "conf", bin_net_ipv4_conf_table }, - { CTL_DIR, NET_IPV4_NEIGH, "neigh", bin_net_neigh_table }, - { CTL_DIR, NET_IPV4_ROUTE, "route", bin_net_ipv4_route_table }, - /* NET_IPV4_FIB_HASH unused */ - { CTL_DIR, NET_IPV4_NETFILTER, "netfilter", bin_net_ipv4_netfilter_table }, - - { CTL_INT, NET_IPV4_TCP_TIMESTAMPS, "tcp_timestamps" }, - { CTL_INT, NET_IPV4_TCP_WINDOW_SCALING, "tcp_window_scaling" }, - { CTL_INT, NET_IPV4_TCP_SACK, "tcp_sack" }, - { CTL_INT, NET_IPV4_TCP_RETRANS_COLLAPSE, "tcp_retrans_collapse" }, - { CTL_INT, NET_IPV4_DEFAULT_TTL, "ip_default_ttl" }, - /* NET_IPV4_AUTOCONFIG unused */ - { CTL_INT, NET_IPV4_NO_PMTU_DISC, "ip_no_pmtu_disc" }, - { CTL_INT, NET_IPV4_NONLOCAL_BIND, "ip_nonlocal_bind" }, - { CTL_INT, NET_IPV4_TCP_SYN_RETRIES, "tcp_syn_retries" }, - { CTL_INT, NET_TCP_SYNACK_RETRIES, "tcp_synack_retries" }, - { CTL_INT, NET_TCP_MAX_ORPHANS, "tcp_max_orphans" }, - { CTL_INT, NET_TCP_MAX_TW_BUCKETS, "tcp_max_tw_buckets" }, - { CTL_INT, NET_IPV4_DYNADDR, "ip_dynaddr" }, - { CTL_INT, NET_IPV4_TCP_KEEPALIVE_TIME, "tcp_keepalive_time" }, - { CTL_INT, NET_IPV4_TCP_KEEPALIVE_PROBES, "tcp_keepalive_probes" }, - { CTL_INT, NET_IPV4_TCP_KEEPALIVE_INTVL, "tcp_keepalive_intvl" }, - { CTL_INT, NET_IPV4_TCP_RETRIES1, "tcp_retries1" }, - { CTL_INT, NET_IPV4_TCP_RETRIES2, "tcp_retries2" }, - { CTL_INT, NET_IPV4_TCP_FIN_TIMEOUT, "tcp_fin_timeout" }, - { CTL_INT, NET_TCP_SYNCOOKIES, "tcp_syncookies" }, - { CTL_INT, NET_TCP_TW_RECYCLE, "tcp_tw_recycle" }, - { CTL_INT, NET_TCP_ABORT_ON_OVERFLOW, "tcp_abort_on_overflow" }, - { CTL_INT, NET_TCP_STDURG, "tcp_stdurg" }, - { CTL_INT, NET_TCP_RFC1337, "tcp_rfc1337" }, - { CTL_INT, NET_TCP_MAX_SYN_BACKLOG, "tcp_max_syn_backlog" }, - { CTL_INT, NET_IPV4_LOCAL_PORT_RANGE, "ip_local_port_range" }, - { CTL_INT, NET_IPV4_IGMP_MAX_MEMBERSHIPS, "igmp_max_memberships" }, - { CTL_INT, NET_IPV4_IGMP_MAX_MSF, "igmp_max_msf" }, - { CTL_INT, NET_IPV4_INET_PEER_THRESHOLD, "inet_peer_threshold" }, - { CTL_INT, NET_IPV4_INET_PEER_MINTTL, "inet_peer_minttl" }, - { CTL_INT, NET_IPV4_INET_PEER_MAXTTL, "inet_peer_maxttl" }, - { CTL_INT, NET_IPV4_INET_PEER_GC_MINTIME, "inet_peer_gc_mintime" }, - { CTL_INT, NET_IPV4_INET_PEER_GC_MAXTIME, "inet_peer_gc_maxtime" }, - { CTL_INT, NET_TCP_ORPHAN_RETRIES, "tcp_orphan_retries" }, - { CTL_INT, NET_TCP_FACK, "tcp_fack" }, - { CTL_INT, NET_TCP_REORDERING, "tcp_reordering" }, - { CTL_INT, NET_TCP_ECN, "tcp_ecn" }, - { CTL_INT, NET_TCP_DSACK, "tcp_dsack" }, - { CTL_INT, NET_TCP_MEM, "tcp_mem" }, - { CTL_INT, NET_TCP_WMEM, "tcp_wmem" }, - { CTL_INT, NET_TCP_RMEM, "tcp_rmem" }, - { CTL_INT, NET_TCP_APP_WIN, "tcp_app_win" }, - { CTL_INT, NET_TCP_ADV_WIN_SCALE, "tcp_adv_win_scale" }, - { CTL_INT, NET_TCP_TW_REUSE, "tcp_tw_reuse" }, - { CTL_INT, NET_TCP_FRTO, "tcp_frto" }, - { CTL_INT, NET_TCP_FRTO_RESPONSE, "tcp_frto_response" }, - { CTL_INT, NET_TCP_LOW_LATENCY, "tcp_low_latency" }, - { CTL_INT, NET_TCP_NO_METRICS_SAVE, "tcp_no_metrics_save" }, - { CTL_INT, NET_TCP_MODERATE_RCVBUF, "tcp_moderate_rcvbuf" }, - { CTL_INT, NET_TCP_TSO_WIN_DIVISOR, "tcp_tso_win_divisor" }, - { CTL_STR, NET_TCP_CONG_CONTROL, "tcp_congestion_control" }, - { CTL_INT, NET_TCP_MTU_PROBING, "tcp_mtu_probing" }, - { CTL_INT, NET_TCP_BASE_MSS, "tcp_base_mss" }, - { CTL_INT, NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS, "tcp_workaround_signed_windows" }, - { CTL_INT, NET_TCP_SLOW_START_AFTER_IDLE, "tcp_slow_start_after_idle" }, - { CTL_INT, NET_CIPSOV4_CACHE_ENABLE, "cipso_cache_enable" }, - { CTL_INT, NET_CIPSOV4_CACHE_BUCKET_SIZE, "cipso_cache_bucket_size" }, - { CTL_INT, NET_CIPSOV4_RBM_OPTFMT, "cipso_rbm_optfmt" }, - { CTL_INT, NET_CIPSOV4_RBM_STRICTVALID, "cipso_rbm_strictvalid" }, - /* NET_TCP_AVAIL_CONG_CONTROL "tcp_available_congestion_control" no longer used */ - { CTL_STR, NET_TCP_ALLOWED_CONG_CONTROL, "tcp_allowed_congestion_control" }, - { CTL_INT, NET_TCP_MAX_SSTHRESH, "tcp_max_ssthresh" }, - - { CTL_INT, NET_IPV4_ICMP_ECHO_IGNORE_ALL, "icmp_echo_ignore_all" }, - { CTL_INT, NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS, "icmp_echo_ignore_broadcasts" }, - { CTL_INT, NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES, "icmp_ignore_bogus_error_responses" }, - { CTL_INT, NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR, "icmp_errors_use_inbound_ifaddr" }, - { CTL_INT, NET_IPV4_ICMP_RATELIMIT, "icmp_ratelimit" }, - { CTL_INT, NET_IPV4_ICMP_RATEMASK, "icmp_ratemask" }, - - { CTL_INT, NET_IPV4_IPFRAG_HIGH_THRESH, "ipfrag_high_thresh" }, - { CTL_INT, NET_IPV4_IPFRAG_LOW_THRESH, "ipfrag_low_thresh" }, - { CTL_INT, NET_IPV4_IPFRAG_TIME, "ipfrag_time" }, - - { CTL_INT, NET_IPV4_IPFRAG_SECRET_INTERVAL, "ipfrag_secret_interval" }, - /* NET_IPV4_IPFRAG_MAX_DIST "ipfrag_max_dist" no longer used */ - - { CTL_INT, 2088 /* NET_IPQ_QMAX */, "ip_queue_maxlen" }, - - /* NET_TCP_DEFAULT_WIN_SCALE unused */ - /* NET_TCP_BIC_BETA unused */ - /* NET_IPV4_TCP_MAX_KA_PROBES unused */ - /* NET_IPV4_IP_MASQ_DEBUG unused */ - /* NET_TCP_SYN_TAILDROP unused */ - /* NET_IPV4_ICMP_SOURCEQUENCH_RATE unused */ - /* NET_IPV4_ICMP_DESTUNREACH_RATE unused */ - /* NET_IPV4_ICMP_TIMEEXCEED_RATE unused */ - /* NET_IPV4_ICMP_PARAMPROB_RATE unused */ - /* NET_IPV4_ICMP_ECHOREPLY_RATE unused */ - /* NET_IPV4_ALWAYS_DEFRAG unused */ - {} -}; - -static const struct bin_table bin_net_ipx_table[] = { - { CTL_INT, NET_IPX_PPROP_BROADCASTING, "ipx_pprop_broadcasting" }, - /* NET_IPX_FORWARDING unused */ - {} -}; - -static const struct bin_table bin_net_atalk_table[] = { - { CTL_INT, NET_ATALK_AARP_EXPIRY_TIME, "aarp-expiry-time" }, - { CTL_INT, NET_ATALK_AARP_TICK_TIME, "aarp-tick-time" }, - { CTL_INT, NET_ATALK_AARP_RETRANSMIT_LIMIT, "aarp-retransmit-limit" }, - { CTL_INT, NET_ATALK_AARP_RESOLVE_TIME, "aarp-resolve-time" }, - {}, -}; - -static const struct bin_table bin_net_netrom_table[] = { - { CTL_INT, NET_NETROM_DEFAULT_PATH_QUALITY, "default_path_quality" }, - { CTL_INT, NET_NETROM_OBSOLESCENCE_COUNT_INITIALISER, "obsolescence_count_initialiser" }, - { CTL_INT, NET_NETROM_NETWORK_TTL_INITIALISER, "network_ttl_initialiser" }, - { CTL_INT, NET_NETROM_TRANSPORT_TIMEOUT, "transport_timeout" }, - { CTL_INT, NET_NETROM_TRANSPORT_MAXIMUM_TRIES, "transport_maximum_tries" }, - { CTL_INT, NET_NETROM_TRANSPORT_ACKNOWLEDGE_DELAY, "transport_acknowledge_delay" }, - { CTL_INT, NET_NETROM_TRANSPORT_BUSY_DELAY, "transport_busy_delay" }, - { CTL_INT, NET_NETROM_TRANSPORT_REQUESTED_WINDOW_SIZE, "transport_requested_window_size" }, - { CTL_INT, NET_NETROM_TRANSPORT_NO_ACTIVITY_TIMEOUT, "transport_no_activity_timeout" }, - { CTL_INT, NET_NETROM_ROUTING_CONTROL, "routing_control" }, - { CTL_INT, NET_NETROM_LINK_FAILS_COUNT, "link_fails_count" }, - { CTL_INT, NET_NETROM_RESET, "reset" }, - {} -}; - -static const struct bin_table bin_net_ax25_param_table[] = { - { CTL_INT, NET_AX25_IP_DEFAULT_MODE, "ip_default_mode" }, - { CTL_INT, NET_AX25_DEFAULT_MODE, "ax25_default_mode" }, - { CTL_INT, NET_AX25_BACKOFF_TYPE, "backoff_type" }, - { CTL_INT, NET_AX25_CONNECT_MODE, "connect_mode" }, - { CTL_INT, NET_AX25_STANDARD_WINDOW, "standard_window_size" }, - { CTL_INT, NET_AX25_EXTENDED_WINDOW, "extended_window_size" }, - { CTL_INT, NET_AX25_T1_TIMEOUT, "t1_timeout" }, - { CTL_INT, NET_AX25_T2_TIMEOUT, "t2_timeout" }, - { CTL_INT, NET_AX25_T3_TIMEOUT, "t3_timeout" }, - { CTL_INT, NET_AX25_IDLE_TIMEOUT, "idle_timeout" }, - { CTL_INT, NET_AX25_N2, "maximum_retry_count" }, - { CTL_INT, NET_AX25_PACLEN, "maximum_packet_length" }, - { CTL_INT, NET_AX25_PROTOCOL, "protocol" }, - { CTL_INT, NET_AX25_DAMA_SLAVE_TIMEOUT, "dama_slave_timeout" }, - {} -}; - -static const struct bin_table bin_net_ax25_table[] = { - { CTL_DIR, 0, NULL, bin_net_ax25_param_table }, - {} -}; - -static const struct bin_table bin_net_rose_table[] = { - { CTL_INT, NET_ROSE_RESTART_REQUEST_TIMEOUT, "restart_request_timeout" }, - { CTL_INT, NET_ROSE_CALL_REQUEST_TIMEOUT, "call_request_timeout" }, - { CTL_INT, NET_ROSE_RESET_REQUEST_TIMEOUT, "reset_request_timeout" }, - { CTL_INT, NET_ROSE_CLEAR_REQUEST_TIMEOUT, "clear_request_timeout" }, - { CTL_INT, NET_ROSE_ACK_HOLD_BACK_TIMEOUT, "acknowledge_hold_back_timeout" }, - { CTL_INT, NET_ROSE_ROUTING_CONTROL, "routing_control" }, - { CTL_INT, NET_ROSE_LINK_FAIL_TIMEOUT, "link_fail_timeout" }, - { CTL_INT, NET_ROSE_MAX_VCS, "maximum_virtual_circuits" }, - { CTL_INT, NET_ROSE_WINDOW_SIZE, "window_size" }, - { CTL_INT, NET_ROSE_NO_ACTIVITY_TIMEOUT, "no_activity_timeout" }, - {} -}; - -static const struct bin_table bin_net_ipv6_conf_var_table[] = { - { CTL_INT, NET_IPV6_FORWARDING, "forwarding" }, - { CTL_INT, NET_IPV6_HOP_LIMIT, "hop_limit" }, - { CTL_INT, NET_IPV6_MTU, "mtu" }, - { CTL_INT, NET_IPV6_ACCEPT_RA, "accept_ra" }, - { CTL_INT, NET_IPV6_ACCEPT_REDIRECTS, "accept_redirects" }, - { CTL_INT, NET_IPV6_AUTOCONF, "autoconf" }, - { CTL_INT, NET_IPV6_DAD_TRANSMITS, "dad_transmits" }, - { CTL_INT, NET_IPV6_RTR_SOLICITS, "router_solicitations" }, - { CTL_INT, NET_IPV6_RTR_SOLICIT_INTERVAL, "router_solicitation_interval" }, - { CTL_INT, NET_IPV6_RTR_SOLICIT_DELAY, "router_solicitation_delay" }, - { CTL_INT, NET_IPV6_USE_TEMPADDR, "use_tempaddr" }, - { CTL_INT, NET_IPV6_TEMP_VALID_LFT, "temp_valid_lft" }, - { CTL_INT, NET_IPV6_TEMP_PREFERED_LFT, "temp_prefered_lft" }, - { CTL_INT, NET_IPV6_REGEN_MAX_RETRY, "regen_max_retry" }, - { CTL_INT, NET_IPV6_MAX_DESYNC_FACTOR, "max_desync_factor" }, - { CTL_INT, NET_IPV6_MAX_ADDRESSES, "max_addresses" }, - { CTL_INT, NET_IPV6_FORCE_MLD_VERSION, "force_mld_version" }, - { CTL_INT, NET_IPV6_ACCEPT_RA_DEFRTR, "accept_ra_defrtr" }, - { CTL_INT, NET_IPV6_ACCEPT_RA_PINFO, "accept_ra_pinfo" }, - { CTL_INT, NET_IPV6_ACCEPT_RA_RTR_PREF, "accept_ra_rtr_pref" }, - { CTL_INT, NET_IPV6_RTR_PROBE_INTERVAL, "router_probe_interval" }, - { CTL_INT, NET_IPV6_ACCEPT_RA_RT_INFO_MAX_PLEN, "accept_ra_rt_info_max_plen" }, - { CTL_INT, NET_IPV6_PROXY_NDP, "proxy_ndp" }, - { CTL_INT, NET_IPV6_ACCEPT_SOURCE_ROUTE, "accept_source_route" }, - { CTL_INT, NET_IPV6_ACCEPT_RA_FROM_LOCAL, "accept_ra_from_local" }, - {} -}; - -static const struct bin_table bin_net_ipv6_conf_table[] = { - { CTL_DIR, NET_PROTO_CONF_ALL, "all", bin_net_ipv6_conf_var_table }, - { CTL_DIR, NET_PROTO_CONF_DEFAULT, "default", bin_net_ipv6_conf_var_table }, - { CTL_DIR, 0, NULL, bin_net_ipv6_conf_var_table }, - {} -}; - -static const struct bin_table bin_net_ipv6_route_table[] = { - /* NET_IPV6_ROUTE_FLUSH "flush" no longer used */ - { CTL_INT, NET_IPV6_ROUTE_GC_THRESH, "gc_thresh" }, - { CTL_INT, NET_IPV6_ROUTE_MAX_SIZE, "max_size" }, - { CTL_INT, NET_IPV6_ROUTE_GC_MIN_INTERVAL, "gc_min_interval" }, - { CTL_INT, NET_IPV6_ROUTE_GC_TIMEOUT, "gc_timeout" }, - { CTL_INT, NET_IPV6_ROUTE_GC_INTERVAL, "gc_interval" }, - { CTL_INT, NET_IPV6_ROUTE_GC_ELASTICITY, "gc_elasticity" }, - { CTL_INT, NET_IPV6_ROUTE_MTU_EXPIRES, "mtu_expires" }, - { CTL_INT, NET_IPV6_ROUTE_MIN_ADVMSS, "min_adv_mss" }, - { CTL_INT, NET_IPV6_ROUTE_GC_MIN_INTERVAL_MS, "gc_min_interval_ms" }, - {} -}; - -static const struct bin_table bin_net_ipv6_icmp_table[] = { - { CTL_INT, NET_IPV6_ICMP_RATELIMIT, "ratelimit" }, - {} -}; - -static const struct bin_table bin_net_ipv6_table[] = { - { CTL_DIR, NET_IPV6_CONF, "conf", bin_net_ipv6_conf_table }, - { CTL_DIR, NET_IPV6_NEIGH, "neigh", bin_net_neigh_table }, - { CTL_DIR, NET_IPV6_ROUTE, "route", bin_net_ipv6_route_table }, - { CTL_DIR, NET_IPV6_ICMP, "icmp", bin_net_ipv6_icmp_table }, - { CTL_INT, NET_IPV6_BINDV6ONLY, "bindv6only" }, - { CTL_INT, NET_IPV6_IP6FRAG_HIGH_THRESH, "ip6frag_high_thresh" }, - { CTL_INT, NET_IPV6_IP6FRAG_LOW_THRESH, "ip6frag_low_thresh" }, - { CTL_INT, NET_IPV6_IP6FRAG_TIME, "ip6frag_time" }, - { CTL_INT, NET_IPV6_IP6FRAG_SECRET_INTERVAL, "ip6frag_secret_interval" }, - { CTL_INT, NET_IPV6_MLD_MAX_MSF, "mld_max_msf" }, - { CTL_INT, 2088 /* IPQ_QMAX */, "ip6_queue_maxlen" }, - {} -}; - -static const struct bin_table bin_net_x25_table[] = { - { CTL_INT, NET_X25_RESTART_REQUEST_TIMEOUT, "restart_request_timeout" }, - { CTL_INT, NET_X25_CALL_REQUEST_TIMEOUT, "call_request_timeout" }, - { CTL_INT, NET_X25_RESET_REQUEST_TIMEOUT, "reset_request_timeout" }, - { CTL_INT, NET_X25_CLEAR_REQUEST_TIMEOUT, "clear_request_timeout" }, - { CTL_INT, NET_X25_ACK_HOLD_BACK_TIMEOUT, "acknowledgement_hold_back_timeout" }, - { CTL_INT, NET_X25_FORWARD, "x25_forward" }, - {} -}; - -static const struct bin_table bin_net_tr_table[] = { - { CTL_INT, NET_TR_RIF_TIMEOUT, "rif_timeout" }, - {} -}; - - -static const struct bin_table bin_net_decnet_conf_vars[] = { - { CTL_INT, NET_DECNET_CONF_DEV_FORWARDING, "forwarding" }, - { CTL_INT, NET_DECNET_CONF_DEV_PRIORITY, "priority" }, - { CTL_INT, NET_DECNET_CONF_DEV_T2, "t2" }, - { CTL_INT, NET_DECNET_CONF_DEV_T3, "t3" }, - {} -}; - -static const struct bin_table bin_net_decnet_conf[] = { - { CTL_DIR, NET_DECNET_CONF_ETHER, "ethernet", bin_net_decnet_conf_vars }, - { CTL_DIR, NET_DECNET_CONF_GRE, "ipgre", bin_net_decnet_conf_vars }, - { CTL_DIR, NET_DECNET_CONF_X25, "x25", bin_net_decnet_conf_vars }, - { CTL_DIR, NET_DECNET_CONF_PPP, "ppp", bin_net_decnet_conf_vars }, - { CTL_DIR, NET_DECNET_CONF_DDCMP, "ddcmp", bin_net_decnet_conf_vars }, - { CTL_DIR, NET_DECNET_CONF_LOOPBACK, "loopback", bin_net_decnet_conf_vars }, - { CTL_DIR, 0, NULL, bin_net_decnet_conf_vars }, - {} -}; - -static const struct bin_table bin_net_decnet_table[] = { - { CTL_DIR, NET_DECNET_CONF, "conf", bin_net_decnet_conf }, - { CTL_DNADR, NET_DECNET_NODE_ADDRESS, "node_address" }, - { CTL_STR, NET_DECNET_NODE_NAME, "node_name" }, - { CTL_STR, NET_DECNET_DEFAULT_DEVICE, "default_device" }, - { CTL_INT, NET_DECNET_TIME_WAIT, "time_wait" }, - { CTL_INT, NET_DECNET_DN_COUNT, "dn_count" }, - { CTL_INT, NET_DECNET_DI_COUNT, "di_count" }, - { CTL_INT, NET_DECNET_DR_COUNT, "dr_count" }, - { CTL_INT, NET_DECNET_DST_GC_INTERVAL, "dst_gc_interval" }, - { CTL_INT, NET_DECNET_NO_FC_MAX_CWND, "no_fc_max_cwnd" }, - { CTL_INT, NET_DECNET_MEM, "decnet_mem" }, - { CTL_INT, NET_DECNET_RMEM, "decnet_rmem" }, - { CTL_INT, NET_DECNET_WMEM, "decnet_wmem" }, - { CTL_INT, NET_DECNET_DEBUG_LEVEL, "debug" }, - {} -}; - -static const struct bin_table bin_net_sctp_table[] = { - { CTL_INT, NET_SCTP_RTO_INITIAL, "rto_initial" }, - { CTL_INT, NET_SCTP_RTO_MIN, "rto_min" }, - { CTL_INT, NET_SCTP_RTO_MAX, "rto_max" }, - { CTL_INT, NET_SCTP_RTO_ALPHA, "rto_alpha_exp_divisor" }, - { CTL_INT, NET_SCTP_RTO_BETA, "rto_beta_exp_divisor" }, - { CTL_INT, NET_SCTP_VALID_COOKIE_LIFE, "valid_cookie_life" }, - { CTL_INT, NET_SCTP_ASSOCIATION_MAX_RETRANS, "association_max_retrans" }, - { CTL_INT, NET_SCTP_PATH_MAX_RETRANS, "path_max_retrans" }, - { CTL_INT, NET_SCTP_MAX_INIT_RETRANSMITS, "max_init_retransmits" }, - { CTL_INT, NET_SCTP_HB_INTERVAL, "hb_interval" }, - { CTL_INT, NET_SCTP_PRESERVE_ENABLE, "cookie_preserve_enable" }, - { CTL_INT, NET_SCTP_MAX_BURST, "max_burst" }, - { CTL_INT, NET_SCTP_ADDIP_ENABLE, "addip_enable" }, - { CTL_INT, NET_SCTP_PRSCTP_ENABLE, "prsctp_enable" }, - { CTL_INT, NET_SCTP_SNDBUF_POLICY, "sndbuf_policy" }, - { CTL_INT, NET_SCTP_SACK_TIMEOUT, "sack_timeout" }, - { CTL_INT, NET_SCTP_RCVBUF_POLICY, "rcvbuf_policy" }, - {} -}; - -static const struct bin_table bin_net_llc_llc2_timeout_table[] = { - { CTL_INT, NET_LLC2_ACK_TIMEOUT, "ack" }, - { CTL_INT, NET_LLC2_P_TIMEOUT, "p" }, - { CTL_INT, NET_LLC2_REJ_TIMEOUT, "rej" }, - { CTL_INT, NET_LLC2_BUSY_TIMEOUT, "busy" }, - {} -}; - -static const struct bin_table bin_net_llc_station_table[] = { - { CTL_INT, NET_LLC_STATION_ACK_TIMEOUT, "ack_timeout" }, - {} -}; - -static const struct bin_table bin_net_llc_llc2_table[] = { - { CTL_DIR, NET_LLC2, "timeout", bin_net_llc_llc2_timeout_table }, - {} -}; - -static const struct bin_table bin_net_llc_table[] = { - { CTL_DIR, NET_LLC2, "llc2", bin_net_llc_llc2_table }, - { CTL_DIR, NET_LLC_STATION, "station", bin_net_llc_station_table }, - {} -}; - -static const struct bin_table bin_net_netfilter_table[] = { - { CTL_INT, NET_NF_CONNTRACK_MAX, "nf_conntrack_max" }, - /* NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_SENT "nf_conntrack_tcp_timeout_syn_sent" no longer used */ - /* NET_NF_CONNTRACK_TCP_TIMEOUT_SYN_RECV "nf_conntrack_tcp_timeout_syn_recv" no longer used */ - /* NET_NF_CONNTRACK_TCP_TIMEOUT_ESTABLISHED "nf_conntrack_tcp_timeout_established" no longer used */ - /* NET_NF_CONNTRACK_TCP_TIMEOUT_FIN_WAIT "nf_conntrack_tcp_timeout_fin_wait" no longer used */ - /* NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE_WAIT "nf_conntrack_tcp_timeout_close_wait" no longer used */ - /* NET_NF_CONNTRACK_TCP_TIMEOUT_LAST_ACK "nf_conntrack_tcp_timeout_last_ack" no longer used */ - /* NET_NF_CONNTRACK_TCP_TIMEOUT_TIME_WAIT "nf_conntrack_tcp_timeout_time_wait" no longer used */ - /* NET_NF_CONNTRACK_TCP_TIMEOUT_CLOSE "nf_conntrack_tcp_timeout_close" no longer used */ - /* NET_NF_CONNTRACK_UDP_TIMEOUT "nf_conntrack_udp_timeout" no longer used */ - /* NET_NF_CONNTRACK_UDP_TIMEOUT_STREAM "nf_conntrack_udp_timeout_stream" no longer used */ - /* NET_NF_CONNTRACK_ICMP_TIMEOUT "nf_conntrack_icmp_timeout" no longer used */ - /* NET_NF_CONNTRACK_GENERIC_TIMEOUT "nf_conntrack_generic_timeout" no longer used */ - { CTL_INT, NET_NF_CONNTRACK_BUCKETS, "nf_conntrack_buckets" }, - { CTL_INT, NET_NF_CONNTRACK_LOG_INVALID, "nf_conntrack_log_invalid" }, - /* NET_NF_CONNTRACK_TCP_TIMEOUT_MAX_RETRANS "nf_conntrack_tcp_timeout_max_retrans" no longer used */ - { CTL_INT, NET_NF_CONNTRACK_TCP_LOOSE, "nf_conntrack_tcp_loose" }, - { CTL_INT, NET_NF_CONNTRACK_TCP_BE_LIBERAL, "nf_conntrack_tcp_be_liberal" }, - { CTL_INT, NET_NF_CONNTRACK_TCP_MAX_RETRANS, "nf_conntrack_tcp_max_retrans" }, - /* NET_NF_CONNTRACK_SCTP_TIMEOUT_CLOSED "nf_conntrack_sctp_timeout_closed" no longer used */ - /* NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_WAIT "nf_conntrack_sctp_timeout_cookie_wait" no longer used */ - /* NET_NF_CONNTRACK_SCTP_TIMEOUT_COOKIE_ECHOED "nf_conntrack_sctp_timeout_cookie_echoed" no longer used */ - /* NET_NF_CONNTRACK_SCTP_TIMEOUT_ESTABLISHED "nf_conntrack_sctp_timeout_established" no longer used */ - /* NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_SENT "nf_conntrack_sctp_timeout_shutdown_sent" no longer used */ - /* NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_RECD "nf_conntrack_sctp_timeout_shutdown_recd" no longer used */ - /* NET_NF_CONNTRACK_SCTP_TIMEOUT_SHUTDOWN_ACK_SENT "nf_conntrack_sctp_timeout_shutdown_ack_sent" no longer used */ - { CTL_INT, NET_NF_CONNTRACK_COUNT, "nf_conntrack_count" }, - /* NET_NF_CONNTRACK_ICMPV6_TIMEOUT "nf_conntrack_icmpv6_timeout" no longer used */ - /* NET_NF_CONNTRACK_FRAG6_TIMEOUT "nf_conntrack_frag6_timeout" no longer used */ - { CTL_INT, NET_NF_CONNTRACK_FRAG6_LOW_THRESH, "nf_conntrack_frag6_low_thresh" }, - { CTL_INT, NET_NF_CONNTRACK_FRAG6_HIGH_THRESH, "nf_conntrack_frag6_high_thresh" }, - { CTL_INT, NET_NF_CONNTRACK_CHECKSUM, "nf_conntrack_checksum" }, - - {} -}; - -static const struct bin_table bin_net_irda_table[] = { - { CTL_INT, NET_IRDA_DISCOVERY, "discovery" }, - { CTL_STR, NET_IRDA_DEVNAME, "devname" }, - { CTL_INT, NET_IRDA_DEBUG, "debug" }, - { CTL_INT, NET_IRDA_FAST_POLL, "fast_poll_increase" }, - { CTL_INT, NET_IRDA_DISCOVERY_SLOTS, "discovery_slots" }, - { CTL_INT, NET_IRDA_DISCOVERY_TIMEOUT, "discovery_timeout" }, - { CTL_INT, NET_IRDA_SLOT_TIMEOUT, "slot_timeout" }, - { CTL_INT, NET_IRDA_MAX_BAUD_RATE, "max_baud_rate" }, - { CTL_INT, NET_IRDA_MIN_TX_TURN_TIME, "min_tx_turn_time" }, - { CTL_INT, NET_IRDA_MAX_TX_DATA_SIZE, "max_tx_data_size" }, - { CTL_INT, NET_IRDA_MAX_TX_WINDOW, "max_tx_window" }, - { CTL_INT, NET_IRDA_MAX_NOREPLY_TIME, "max_noreply_time" }, - { CTL_INT, NET_IRDA_WARN_NOREPLY_TIME, "warn_noreply_time" }, - { CTL_INT, NET_IRDA_LAP_KEEPALIVE_TIME, "lap_keepalive_time" }, - {} -}; - -static const struct bin_table bin_net_table[] = { - { CTL_DIR, NET_CORE, "core", bin_net_core_table }, - /* NET_ETHER not used */ - /* NET_802 not used */ - { CTL_DIR, NET_UNIX, "unix", bin_net_unix_table }, - { CTL_DIR, NET_IPV4, "ipv4", bin_net_ipv4_table }, - { CTL_DIR, NET_IPX, "ipx", bin_net_ipx_table }, - { CTL_DIR, NET_ATALK, "appletalk", bin_net_atalk_table }, - { CTL_DIR, NET_NETROM, "netrom", bin_net_netrom_table }, - { CTL_DIR, NET_AX25, "ax25", bin_net_ax25_table }, - /* NET_BRIDGE "bridge" no longer used */ - { CTL_DIR, NET_ROSE, "rose", bin_net_rose_table }, - { CTL_DIR, NET_IPV6, "ipv6", bin_net_ipv6_table }, - { CTL_DIR, NET_X25, "x25", bin_net_x25_table }, - { CTL_DIR, NET_TR, "token-ring", bin_net_tr_table }, - { CTL_DIR, NET_DECNET, "decnet", bin_net_decnet_table }, - /* NET_ECONET not used */ - { CTL_DIR, NET_SCTP, "sctp", bin_net_sctp_table }, - { CTL_DIR, NET_LLC, "llc", bin_net_llc_table }, - { CTL_DIR, NET_NETFILTER, "netfilter", bin_net_netfilter_table }, - /* NET_DCCP "dccp" no longer used */ - { CTL_DIR, NET_IRDA, "irda", bin_net_irda_table }, - { CTL_INT, 2089, "nf_conntrack_max" }, - {} -}; - -static const struct bin_table bin_fs_quota_table[] = { - { CTL_INT, FS_DQ_LOOKUPS, "lookups" }, - { CTL_INT, FS_DQ_DROPS, "drops" }, - { CTL_INT, FS_DQ_READS, "reads" }, - { CTL_INT, FS_DQ_WRITES, "writes" }, - { CTL_INT, FS_DQ_CACHE_HITS, "cache_hits" }, - { CTL_INT, FS_DQ_ALLOCATED, "allocated_dquots" }, - { CTL_INT, FS_DQ_FREE, "free_dquots" }, - { CTL_INT, FS_DQ_SYNCS, "syncs" }, - { CTL_INT, FS_DQ_WARNINGS, "warnings" }, - {} -}; - -static const struct bin_table bin_fs_xfs_table[] = { - { CTL_INT, XFS_SGID_INHERIT, "irix_sgid_inherit" }, - { CTL_INT, XFS_SYMLINK_MODE, "irix_symlink_mode" }, - { CTL_INT, XFS_PANIC_MASK, "panic_mask" }, - - { CTL_INT, XFS_ERRLEVEL, "error_level" }, - { CTL_INT, XFS_SYNCD_TIMER, "xfssyncd_centisecs" }, - { CTL_INT, XFS_INHERIT_SYNC, "inherit_sync" }, - { CTL_INT, XFS_INHERIT_NODUMP, "inherit_nodump" }, - { CTL_INT, XFS_INHERIT_NOATIME, "inherit_noatime" }, - { CTL_INT, XFS_BUF_TIMER, "xfsbufd_centisecs" }, - { CTL_INT, XFS_BUF_AGE, "age_buffer_centisecs" }, - { CTL_INT, XFS_INHERIT_NOSYM, "inherit_nosymlinks" }, - { CTL_INT, XFS_ROTORSTEP, "rotorstep" }, - { CTL_INT, XFS_INHERIT_NODFRG, "inherit_nodefrag" }, - { CTL_INT, XFS_FILESTREAM_TIMER, "filestream_centisecs" }, - { CTL_INT, XFS_STATS_CLEAR, "stats_clear" }, - {} -}; - -static const struct bin_table bin_fs_ocfs2_nm_table[] = { - { CTL_STR, 1, "hb_ctl_path" }, - {} -}; - -static const struct bin_table bin_fs_ocfs2_table[] = { - { CTL_DIR, 1, "nm", bin_fs_ocfs2_nm_table }, - {} -}; - -static const struct bin_table bin_inotify_table[] = { - { CTL_INT, INOTIFY_MAX_USER_INSTANCES, "max_user_instances" }, - { CTL_INT, INOTIFY_MAX_USER_WATCHES, "max_user_watches" }, - { CTL_INT, INOTIFY_MAX_QUEUED_EVENTS, "max_queued_events" }, - {} -}; - -static const struct bin_table bin_fs_table[] = { - { CTL_INT, FS_NRINODE, "inode-nr" }, - { CTL_INT, FS_STATINODE, "inode-state" }, - /* FS_MAXINODE unused */ - /* FS_NRDQUOT unused */ - /* FS_MAXDQUOT unused */ - /* FS_NRFILE "file-nr" no longer used */ - { CTL_INT, FS_MAXFILE, "file-max" }, - { CTL_INT, FS_DENTRY, "dentry-state" }, - /* FS_NRSUPER unused */ - /* FS_MAXUPSER unused */ - { CTL_INT, FS_OVERFLOWUID, "overflowuid" }, - { CTL_INT, FS_OVERFLOWGID, "overflowgid" }, - { CTL_INT, FS_LEASES, "leases-enable" }, - { CTL_INT, FS_DIR_NOTIFY, "dir-notify-enable" }, - { CTL_INT, FS_LEASE_TIME, "lease-break-time" }, - { CTL_DIR, FS_DQSTATS, "quota", bin_fs_quota_table }, - { CTL_DIR, FS_XFS, "xfs", bin_fs_xfs_table }, - { CTL_ULONG, FS_AIO_NR, "aio-nr" }, - { CTL_ULONG, FS_AIO_MAX_NR, "aio-max-nr" }, - { CTL_DIR, FS_INOTIFY, "inotify", bin_inotify_table }, - { CTL_DIR, FS_OCFS2, "ocfs2", bin_fs_ocfs2_table }, - { CTL_INT, KERN_SETUID_DUMPABLE, "suid_dumpable" }, - {} -}; - -static const struct bin_table bin_ipmi_table[] = { - { CTL_INT, DEV_IPMI_POWEROFF_POWERCYCLE, "poweroff_powercycle" }, - {} -}; - -static const struct bin_table bin_mac_hid_files[] = { - /* DEV_MAC_HID_KEYBOARD_SENDS_LINUX_KEYCODES unused */ - /* DEV_MAC_HID_KEYBOARD_LOCK_KEYCODES unused */ - { CTL_INT, DEV_MAC_HID_MOUSE_BUTTON_EMULATION, "mouse_button_emulation" }, - { CTL_INT, DEV_MAC_HID_MOUSE_BUTTON2_KEYCODE, "mouse_button2_keycode" }, - { CTL_INT, DEV_MAC_HID_MOUSE_BUTTON3_KEYCODE, "mouse_button3_keycode" }, - /* DEV_MAC_HID_ADB_MOUSE_SENDS_KEYCODES unused */ - {} -}; - -static const struct bin_table bin_raid_table[] = { - { CTL_INT, DEV_RAID_SPEED_LIMIT_MIN, "speed_limit_min" }, - { CTL_INT, DEV_RAID_SPEED_LIMIT_MAX, "speed_limit_max" }, - {} -}; - -static const struct bin_table bin_scsi_table[] = { - { CTL_INT, DEV_SCSI_LOGGING_LEVEL, "logging_level" }, - {} -}; - -static const struct bin_table bin_dev_table[] = { - /* DEV_CDROM "cdrom" no longer used */ - /* DEV_HWMON unused */ - /* DEV_PARPORT "parport" no longer used */ - { CTL_DIR, DEV_RAID, "raid", bin_raid_table }, - { CTL_DIR, DEV_MAC_HID, "mac_hid", bin_mac_hid_files }, - { CTL_DIR, DEV_SCSI, "scsi", bin_scsi_table }, - { CTL_DIR, DEV_IPMI, "ipmi", bin_ipmi_table }, - {} -}; - -static const struct bin_table bin_bus_isa_table[] = { - { CTL_INT, BUS_ISA_MEM_BASE, "membase" }, - { CTL_INT, BUS_ISA_PORT_BASE, "portbase" }, - { CTL_INT, BUS_ISA_PORT_SHIFT, "portshift" }, - {} -}; - -static const struct bin_table bin_bus_table[] = { - { CTL_DIR, CTL_BUS_ISA, "isa", bin_bus_isa_table }, - {} -}; - - -static const struct bin_table bin_s390dbf_table[] = { - { CTL_INT, 5678 /* CTL_S390DBF_STOPPABLE */, "debug_stoppable" }, - { CTL_INT, 5679 /* CTL_S390DBF_ACTIVE */, "debug_active" }, - {} -}; - -static const struct bin_table bin_sunrpc_table[] = { - /* CTL_RPCDEBUG "rpc_debug" no longer used */ - /* CTL_NFSDEBUG "nfs_debug" no longer used */ - /* CTL_NFSDDEBUG "nfsd_debug" no longer used */ - /* CTL_NLMDEBUG "nlm_debug" no longer used */ - - { CTL_INT, CTL_SLOTTABLE_UDP, "udp_slot_table_entries" }, - { CTL_INT, CTL_SLOTTABLE_TCP, "tcp_slot_table_entries" }, - { CTL_INT, CTL_MIN_RESVPORT, "min_resvport" }, - { CTL_INT, CTL_MAX_RESVPORT, "max_resvport" }, - {} -}; - -static const struct bin_table bin_pm_table[] = { - /* frv specific */ - /* 1 == CTL_PM_SUSPEND "suspend" no longer used" */ - { CTL_INT, 2 /* CTL_PM_CMODE */, "cmode" }, - { CTL_INT, 3 /* CTL_PM_P0 */, "p0" }, - { CTL_INT, 4 /* CTL_PM_CM */, "cm" }, - {} -}; - -static const struct bin_table bin_root_table[] = { - { CTL_DIR, CTL_KERN, "kernel", bin_kern_table }, - { CTL_DIR, CTL_VM, "vm", bin_vm_table }, - { CTL_DIR, CTL_NET, "net", bin_net_table }, - /* CTL_PROC not used */ - { CTL_DIR, CTL_FS, "fs", bin_fs_table }, - /* CTL_DEBUG "debug" no longer used */ - { CTL_DIR, CTL_DEV, "dev", bin_dev_table }, - { CTL_DIR, CTL_BUS, "bus", bin_bus_table }, - { CTL_DIR, CTL_ABI, "abi" }, - /* CTL_CPU not used */ - /* CTL_ARLAN "arlan" no longer used */ - { CTL_DIR, CTL_S390DBF, "s390dbf", bin_s390dbf_table }, - { CTL_DIR, CTL_SUNRPC, "sunrpc", bin_sunrpc_table }, - { CTL_DIR, CTL_PM, "pm", bin_pm_table }, - {} -}; - -static ssize_t bin_dir(struct file *file, - void __user *oldval, size_t oldlen, void __user *newval, size_t newlen) -{ - return -ENOTDIR; -} - - -static ssize_t bin_string(struct file *file, - void __user *oldval, size_t oldlen, void __user *newval, size_t newlen) -{ - ssize_t result, copied = 0; - - if (oldval && oldlen) { - char __user *lastp; - loff_t pos = 0; - int ch; - - result = vfs_read(file, oldval, oldlen, &pos); - if (result < 0) - goto out; - - copied = result; - lastp = oldval + copied - 1; - - result = -EFAULT; - if (get_user(ch, lastp)) - goto out; - - /* Trim off the trailing newline */ - if (ch == '\n') { - result = -EFAULT; - if (put_user('\0', lastp)) - goto out; - copied -= 1; - } - } - - if (newval && newlen) { - loff_t pos = 0; - - result = vfs_write(file, newval, newlen, &pos); - if (result < 0) - goto out; - } - - result = copied; -out: - return result; -} - -static ssize_t bin_intvec(struct file *file, - void __user *oldval, size_t oldlen, void __user *newval, size_t newlen) -{ - ssize_t copied = 0; - char *buffer; - ssize_t result; - - result = -ENOMEM; - buffer = kmalloc(BUFSZ, GFP_KERNEL); - if (!buffer) - goto out; - - if (oldval && oldlen) { - unsigned __user *vec = oldval; - size_t length = oldlen / sizeof(*vec); - char *str, *end; - int i; - - result = kernel_read(file, 0, buffer, BUFSZ - 1); - if (result < 0) - goto out_kfree; - - str = buffer; - end = str + result; - *end++ = '\0'; - for (i = 0; i < length; i++) { - unsigned long value; - - value = simple_strtoul(str, &str, 10); - while (isspace(*str)) - str++; - - result = -EFAULT; - if (put_user(value, vec + i)) - goto out_kfree; - - copied += sizeof(*vec); - if (!isdigit(*str)) - break; - } - } - - if (newval && newlen) { - unsigned __user *vec = newval; - size_t length = newlen / sizeof(*vec); - char *str, *end; - int i; - - str = buffer; - end = str + BUFSZ; - for (i = 0; i < length; i++) { - unsigned long value; - - result = -EFAULT; - if (get_user(value, vec + i)) - goto out_kfree; - - str += scnprintf(str, end - str, "%lu\t", value); - } - - result = kernel_write(file, buffer, str - buffer, 0); - if (result < 0) - goto out_kfree; - } - result = copied; -out_kfree: - kfree(buffer); -out: - return result; -} - -static ssize_t bin_ulongvec(struct file *file, - void __user *oldval, size_t oldlen, void __user *newval, size_t newlen) -{ - ssize_t copied = 0; - char *buffer; - ssize_t result; - - result = -ENOMEM; - buffer = kmalloc(BUFSZ, GFP_KERNEL); - if (!buffer) - goto out; - - if (oldval && oldlen) { - unsigned long __user *vec = oldval; - size_t length = oldlen / sizeof(*vec); - char *str, *end; - int i; - - result = kernel_read(file, 0, buffer, BUFSZ - 1); - if (result < 0) - goto out_kfree; - - str = buffer; - end = str + result; - *end++ = '\0'; - for (i = 0; i < length; i++) { - unsigned long value; - - value = simple_strtoul(str, &str, 10); - while (isspace(*str)) - str++; - - result = -EFAULT; - if (put_user(value, vec + i)) - goto out_kfree; - - copied += sizeof(*vec); - if (!isdigit(*str)) - break; - } - } - - if (newval && newlen) { - unsigned long __user *vec = newval; - size_t length = newlen / sizeof(*vec); - char *str, *end; - int i; - - str = buffer; - end = str + BUFSZ; - for (i = 0; i < length; i++) { - unsigned long value; - - result = -EFAULT; - if (get_user(value, vec + i)) - goto out_kfree; - - str += scnprintf(str, end - str, "%lu\t", value); - } - - result = kernel_write(file, buffer, str - buffer, 0); - if (result < 0) - goto out_kfree; - } - result = copied; -out_kfree: - kfree(buffer); -out: - return result; -} - -static ssize_t bin_uuid(struct file *file, - void __user *oldval, size_t oldlen, void __user *newval, size_t newlen) -{ - ssize_t result, copied = 0; - - /* Only supports reads */ - if (oldval && oldlen) { - char buf[UUID_STRING_LEN + 1]; - uuid_be uuid; - - result = kernel_read(file, 0, buf, sizeof(buf) - 1); - if (result < 0) - goto out; - - buf[result] = '\0'; - - result = -EIO; - if (uuid_be_to_bin(buf, &uuid)) - goto out; - - if (oldlen > 16) - oldlen = 16; - - result = -EFAULT; - if (copy_to_user(oldval, &uuid, oldlen)) - goto out; - - copied = oldlen; - } - result = copied; -out: - return result; -} - -static ssize_t bin_dn_node_address(struct file *file, - void __user *oldval, size_t oldlen, void __user *newval, size_t newlen) -{ - ssize_t result, copied = 0; - - if (oldval && oldlen) { - char buf[15], *nodep; - unsigned long area, node; - __le16 dnaddr; - - result = kernel_read(file, 0, buf, sizeof(buf) - 1); - if (result < 0) - goto out; - - buf[result] = '\0'; - - /* Convert the decnet address to binary */ - result = -EIO; - nodep = strchr(buf, '.'); - if (!nodep) - goto out; - ++nodep; - - area = simple_strtoul(buf, NULL, 10); - node = simple_strtoul(nodep, NULL, 10); - - result = -EIO; - if ((area > 63)||(node > 1023)) - goto out; - - dnaddr = cpu_to_le16((area << 10) | node); - - result = -EFAULT; - if (put_user(dnaddr, (__le16 __user *)oldval)) - goto out; - - copied = sizeof(dnaddr); - } - - if (newval && newlen) { - __le16 dnaddr; - char buf[15]; - int len; - - result = -EINVAL; - if (newlen != sizeof(dnaddr)) - goto out; - - result = -EFAULT; - if (get_user(dnaddr, (__le16 __user *)newval)) - goto out; - - len = scnprintf(buf, sizeof(buf), "%hu.%hu", - le16_to_cpu(dnaddr) >> 10, - le16_to_cpu(dnaddr) & 0x3ff); - - result = kernel_write(file, buf, len, 0); - if (result < 0) - goto out; - } - - result = copied; -out: - return result; -} - -static const struct bin_table *get_sysctl(const int *name, int nlen, char *path) -{ - const struct bin_table *table = &bin_root_table[0]; - int ctl_name; - - /* The binary sysctl tables have a small maximum depth so - * there is no danger of overflowing our path as it PATH_MAX - * bytes long. - */ - memcpy(path, "sys/", 4); - path += 4; - -repeat: - if (!nlen) - return ERR_PTR(-ENOTDIR); - ctl_name = *name; - name++; - nlen--; - for ( ; table->convert; table++) { - int len = 0; - - /* - * For a wild card entry map from ifindex to network - * device name. - */ - if (!table->ctl_name) { -#ifdef CONFIG_NET - struct net *net = current->nsproxy->net_ns; - struct net_device *dev; - dev = dev_get_by_index(net, ctl_name); - if (dev) { - len = strlen(dev->name); - memcpy(path, dev->name, len); - dev_put(dev); - } -#endif - /* Use the well known sysctl number to proc name mapping */ - } else if (ctl_name == table->ctl_name) { - len = strlen(table->procname); - memcpy(path, table->procname, len); - } - if (len) { - path += len; - if (table->child) { - *path++ = '/'; - table = table->child; - goto repeat; - } - *path = '\0'; - return table; - } - } - return ERR_PTR(-ENOTDIR); -} - -static char *sysctl_getname(const int *name, int nlen, const struct bin_table **tablep) -{ - char *tmp, *result; - - result = ERR_PTR(-ENOMEM); - tmp = __getname(); - if (tmp) { - const struct bin_table *table = get_sysctl(name, nlen, tmp); - result = tmp; - *tablep = table; - if (IS_ERR(table)) { - __putname(tmp); - result = ERR_CAST(table); - } - } - return result; -} - -static ssize_t binary_sysctl(const int *name, int nlen, - void __user *oldval, size_t oldlen, void __user *newval, size_t newlen) -{ - const struct bin_table *table = NULL; - struct vfsmount *mnt; - struct file *file; - ssize_t result; - char *pathname; - int flags; - - pathname = sysctl_getname(name, nlen, &table); - result = PTR_ERR(pathname); - if (IS_ERR(pathname)) - goto out; - - /* How should the sysctl be accessed? */ - if (oldval && oldlen && newval && newlen) { - flags = O_RDWR; - } else if (newval && newlen) { - flags = O_WRONLY; - } else if (oldval && oldlen) { - flags = O_RDONLY; - } else { - result = 0; - goto out_putname; - } - - mnt = task_active_pid_ns(current)->proc_mnt; - file = file_open_root(mnt->mnt_root, mnt, pathname, flags, 0); - result = PTR_ERR(file); - if (IS_ERR(file)) - goto out_putname; - - result = table->convert(file, oldval, oldlen, newval, newlen); - - fput(file); -out_putname: - __putname(pathname); -out: - return result; -} - - -#else /* CONFIG_SYSCTL_SYSCALL */ - -static ssize_t binary_sysctl(const int *name, int nlen, - void __user *oldval, size_t oldlen, void __user *newval, size_t newlen) -{ - return -ENOSYS; -} - -#endif /* CONFIG_SYSCTL_SYSCALL */ - - -static void deprecated_sysctl_warning(const int *name, int nlen) -{ - int i; - - /* - * CTL_KERN/KERN_VERSION is used by older glibc and cannot - * ever go away. - */ - if (name[0] == CTL_KERN && name[1] == KERN_VERSION) - return; - - if (printk_ratelimit()) { - printk(KERN_INFO - "warning: process `%s' used the deprecated sysctl " - "system call with ", current->comm); - for (i = 0; i < nlen; i++) - printk("%d.", name[i]); - printk("\n"); - } - return; -} - -#define WARN_ONCE_HASH_BITS 8 -#define WARN_ONCE_HASH_SIZE (1<nlen. */ - if (nlen < 0 || nlen > CTL_MAXNAME) - return -ENOTDIR; - /* Read in the sysctl name for simplicity */ - for (i = 0; i < nlen; i++) - if (get_user(name[i], args_name + i)) - return -EFAULT; - - warn_on_bintable(name, nlen); - - return binary_sysctl(name, nlen, oldval, oldlen, newval, newlen); -} - -SYSCALL_DEFINE1(sysctl, struct __sysctl_args __user *, args) -{ - struct __sysctl_args tmp; - size_t oldlen = 0; - ssize_t result; - - if (copy_from_user(&tmp, args, sizeof(tmp))) - return -EFAULT; - - if (tmp.oldval && !tmp.oldlenp) - return -EFAULT; - - if (tmp.oldlenp && get_user(oldlen, tmp.oldlenp)) - return -EFAULT; - - result = do_sysctl(tmp.name, tmp.nlen, tmp.oldval, oldlen, - tmp.newval, tmp.newlen); - - if (result >= 0) { - oldlen = result; - result = 0; - } - - if (tmp.oldlenp && put_user(oldlen, tmp.oldlenp)) - return -EFAULT; - - return result; -} - - -#ifdef CONFIG_COMPAT - -struct compat_sysctl_args { - compat_uptr_t name; - int nlen; - compat_uptr_t oldval; - compat_uptr_t oldlenp; - compat_uptr_t newval; - compat_size_t newlen; - compat_ulong_t __unused[4]; -}; - -COMPAT_SYSCALL_DEFINE1(sysctl, struct compat_sysctl_args __user *, args) -{ - struct compat_sysctl_args tmp; - compat_size_t __user *compat_oldlenp; - size_t oldlen = 0; - ssize_t result; - - if (copy_from_user(&tmp, args, sizeof(tmp))) - return -EFAULT; - - if (tmp.oldval && !tmp.oldlenp) - return -EFAULT; - - compat_oldlenp = compat_ptr(tmp.oldlenp); - if (compat_oldlenp && get_user(oldlen, compat_oldlenp)) - return -EFAULT; - - result = do_sysctl(compat_ptr(tmp.name), tmp.nlen, - compat_ptr(tmp.oldval), oldlen, - compat_ptr(tmp.newval), tmp.newlen); - - if (result >= 0) { - oldlen = result; - result = 0; - } - - if (compat_oldlenp && put_user(oldlen, compat_oldlenp)) - return -EFAULT; - - return result; -} - -#endif /* CONFIG_COMPAT */ diff --git a/src/linux/kernel/task_work.c b/src/linux/kernel/task_work.c deleted file mode 100644 index d513051..0000000 --- a/src/linux/kernel/task_work.c +++ /dev/null @@ -1,121 +0,0 @@ -#include -#include -#include - -static struct callback_head work_exited; /* all we need is ->next == NULL */ - -/** - * task_work_add - ask the @task to execute @work->func() - * @task: the task which should run the callback - * @work: the callback to run - * @notify: send the notification if true - * - * Queue @work for task_work_run() below and notify the @task if @notify. - * Fails if the @task is exiting/exited and thus it can't process this @work. - * Otherwise @work->func() will be called when the @task returns from kernel - * mode or exits. - * - * This is like the signal handler which runs in kernel mode, but it doesn't - * try to wake up the @task. - * - * Note: there is no ordering guarantee on works queued here. - * - * RETURNS: - * 0 if succeeds or -ESRCH. - */ -int -task_work_add(struct task_struct *task, struct callback_head *work, bool notify) -{ - struct callback_head *head; - - do { - head = READ_ONCE(task->task_works); - if (unlikely(head == &work_exited)) - return -ESRCH; - work->next = head; - } while (cmpxchg(&task->task_works, head, work) != head); - - if (notify) - set_notify_resume(task); - return 0; -} - -/** - * task_work_cancel - cancel a pending work added by task_work_add() - * @task: the task which should execute the work - * @func: identifies the work to remove - * - * Find the last queued pending work with ->func == @func and remove - * it from queue. - * - * RETURNS: - * The found work or NULL if not found. - */ -struct callback_head * -task_work_cancel(struct task_struct *task, task_work_func_t func) -{ - struct callback_head **pprev = &task->task_works; - struct callback_head *work; - unsigned long flags; - - if (likely(!task->task_works)) - return NULL; - /* - * If cmpxchg() fails we continue without updating pprev. - * Either we raced with task_work_add() which added the - * new entry before this work, we will find it again. Or - * we raced with task_work_run(), *pprev == NULL/exited. - */ - raw_spin_lock_irqsave(&task->pi_lock, flags); - while ((work = lockless_dereference(*pprev))) { - if (work->func != func) - pprev = &work->next; - else if (cmpxchg(pprev, work, work->next) == work) - break; - } - raw_spin_unlock_irqrestore(&task->pi_lock, flags); - - return work; -} - -/** - * task_work_run - execute the works added by task_work_add() - * - * Flush the pending works. Should be used by the core kernel code. - * Called before the task returns to the user-mode or stops, or when - * it exits. In the latter case task_work_add() can no longer add the - * new work after task_work_run() returns. - */ -void task_work_run(void) -{ - struct task_struct *task = current; - struct callback_head *work, *head, *next; - - for (;;) { - /* - * work->func() can do task_work_add(), do not set - * work_exited unless the list is empty. - */ - do { - work = READ_ONCE(task->task_works); - head = !work && (task->flags & PF_EXITING) ? - &work_exited : NULL; - } while (cmpxchg(&task->task_works, work, head) != work); - - if (!work) - break; - /* - * Synchronize with task_work_cancel(). It can't remove - * the first entry == work, cmpxchg(task_works) should - * fail, but it can play with *work and other entries. - */ - raw_spin_unlock_wait(&task->pi_lock); - - do { - next = work->next; - work->func(work); - work = next; - cond_resched(); - } while (work); - } -} diff --git a/src/linux/kernel/time/Kconfig b/src/linux/kernel/time/Kconfig deleted file mode 100644 index 4008d9f..0000000 --- a/src/linux/kernel/time/Kconfig +++ /dev/null @@ -1,197 +0,0 @@ -# -# Timer subsystem related configuration options -# - -# Options selectable by arch Kconfig - -# Watchdog function for clocksources to detect instabilities -config CLOCKSOURCE_WATCHDOG - bool - -# Architecture has extra clocksource data -config ARCH_CLOCKSOURCE_DATA - bool - -# Clocksources require validation of the clocksource against the last -# cycle update - x86/TSC misfeature -config CLOCKSOURCE_VALIDATE_LAST_CYCLE - bool - -# Timekeeping vsyscall support -config GENERIC_TIME_VSYSCALL - bool - -# Timekeeping vsyscall support -config GENERIC_TIME_VSYSCALL_OLD - bool - -# Old style timekeeping -config ARCH_USES_GETTIMEOFFSET - bool - -# The generic clock events infrastructure -config GENERIC_CLOCKEVENTS - bool - -# Architecture can handle broadcast in a driver-agnostic way -config ARCH_HAS_TICK_BROADCAST - bool - -# Clockevents broadcasting infrastructure -config GENERIC_CLOCKEVENTS_BROADCAST - bool - depends on GENERIC_CLOCKEVENTS - -# Automatically adjust the min. reprogramming time for -# clock event device -config GENERIC_CLOCKEVENTS_MIN_ADJUST - bool - -# Generic update of CMOS clock -config GENERIC_CMOS_UPDATE - bool - -if GENERIC_CLOCKEVENTS -menu "Timers subsystem" - -# Core internal switch. Selected by NO_HZ_COMMON / HIGH_RES_TIMERS. This is -# only related to the tick functionality. Oneshot clockevent devices -# are supported independ of this. -config TICK_ONESHOT - bool - -config NO_HZ_COMMON - bool - depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS - select TICK_ONESHOT - -choice - prompt "Timer tick handling" - default NO_HZ_IDLE if NO_HZ - -config HZ_PERIODIC - bool "Periodic timer ticks (constant rate, no dynticks)" - help - This option keeps the tick running periodically at a constant - rate, even when the CPU doesn't need it. - -config NO_HZ_IDLE - bool "Idle dynticks system (tickless idle)" - depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS - select NO_HZ_COMMON - help - This option enables a tickless idle system: timer interrupts - will only trigger on an as-needed basis when the system is idle. - This is usually interesting for energy saving. - - Most of the time you want to say Y here. - -config NO_HZ_FULL - bool "Full dynticks system (tickless)" - # NO_HZ_COMMON dependency - depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS - # We need at least one periodic CPU for timekeeping - depends on SMP - depends on HAVE_CONTEXT_TRACKING - # VIRT_CPU_ACCOUNTING_GEN dependency - depends on HAVE_VIRT_CPU_ACCOUNTING_GEN - select NO_HZ_COMMON - select RCU_NOCB_CPU - select VIRT_CPU_ACCOUNTING_GEN - select IRQ_WORK - help - Adaptively try to shutdown the tick whenever possible, even when - the CPU is running tasks. Typically this requires running a single - task on the CPU. Chances for running tickless are maximized when - the task mostly runs in userspace and has few kernel activity. - - You need to fill up the nohz_full boot parameter with the - desired range of dynticks CPUs. - - This is implemented at the expense of some overhead in user <-> kernel - transitions: syscalls, exceptions and interrupts. Even when it's - dynamically off. - - Say N. - -endchoice - -config NO_HZ_FULL_ALL - bool "Full dynticks system on all CPUs by default (except CPU 0)" - depends on NO_HZ_FULL - help - If the user doesn't pass the nohz_full boot option to - define the range of full dynticks CPUs, consider that all - CPUs in the system are full dynticks by default. - Note the boot CPU will still be kept outside the range to - handle the timekeeping duty. - -config NO_HZ_FULL_SYSIDLE - bool "Detect full-system idle state for full dynticks system" - depends on NO_HZ_FULL - default n - help - At least one CPU must keep the scheduling-clock tick running for - timekeeping purposes whenever there is a non-idle CPU, where - "non-idle" also includes dynticks CPUs as long as they are - running non-idle tasks. Because the underlying adaptive-tick - support cannot distinguish between all CPUs being idle and - all CPUs each running a single task in dynticks mode, the - underlying support simply ensures that there is always a CPU - handling the scheduling-clock tick, whether or not all CPUs - are idle. This Kconfig option enables scalable detection of - the all-CPUs-idle state, thus allowing the scheduling-clock - tick to be disabled when all CPUs are idle. Note that scalable - detection of the all-CPUs-idle state means that larger systems - will be slower to declare the all-CPUs-idle state. - - Say Y if you would like to help debug all-CPUs-idle detection. - - Say N if you are unsure. - -config NO_HZ_FULL_SYSIDLE_SMALL - int "Number of CPUs above which large-system approach is used" - depends on NO_HZ_FULL_SYSIDLE - range 1 NR_CPUS - default 8 - help - The full-system idle detection mechanism takes a lazy approach - on large systems, as is required to attain decent scalability. - However, on smaller systems, scalability is not anywhere near as - large a concern as is energy efficiency. The sysidle subsystem - therefore uses a fast but non-scalable algorithm for small - systems and a lazier but scalable algorithm for large systems. - This Kconfig parameter defines the number of CPUs in the largest - system that will be considered to be "small". - - The default value will be fine in most cases. Battery-powered - systems that (1) enable NO_HZ_FULL_SYSIDLE, (2) have larger - numbers of CPUs, and (3) are suffering from battery-lifetime - problems due to long sysidle latencies might wish to experiment - with larger values for this Kconfig parameter. On the other - hand, they might be even better served by disabling NO_HZ_FULL - entirely, given that NO_HZ_FULL is intended for HPC and - real-time workloads that at present do not tend to be run on - battery-powered systems. - - Take the default if you are unsure. - -config NO_HZ - bool "Old Idle dynticks config" - depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS - help - This is the old config entry that enables dynticks idle. - We keep it around for a little while to enforce backward - compatibility with older config files. - -config HIGH_RES_TIMERS - bool "High Resolution Timer Support" - depends on !ARCH_USES_GETTIMEOFFSET && GENERIC_CLOCKEVENTS - select TICK_ONESHOT - help - This option enables high resolution timer support. If your - hardware is not capable then this option only increases - the size of the kernel image. - -endmenu -endif diff --git a/src/linux/kernel/time/Makefile b/src/linux/kernel/time/Makefile deleted file mode 100644 index 49eca0b..0000000 --- a/src/linux/kernel/time/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -obj-y += time.o timer.o hrtimer.o itimer.o posix-timers.o posix-cpu-timers.o -obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o -obj-y += timeconv.o timecounter.o posix-clock.o alarmtimer.o - -obj-$(CONFIG_GENERIC_CLOCKEVENTS) += clockevents.o tick-common.o -ifeq ($(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST),y) - obj-y += tick-broadcast.o - obj-$(CONFIG_TICK_ONESHOT) += tick-broadcast-hrtimer.o -endif -obj-$(CONFIG_GENERIC_SCHED_CLOCK) += sched_clock.o -obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o tick-sched.o -obj-$(CONFIG_TIMER_STATS) += timer_stats.o -obj-$(CONFIG_DEBUG_FS) += timekeeping_debug.o -obj-$(CONFIG_TEST_UDELAY) += test_udelay.o diff --git a/src/linux/kernel/time/alarmtimer.c b/src/linux/kernel/time/alarmtimer.c deleted file mode 100644 index 12dd190..0000000 --- a/src/linux/kernel/time/alarmtimer.c +++ /dev/null @@ -1,884 +0,0 @@ -/* - * Alarmtimer interface - * - * This interface provides a timer which is similarto hrtimers, - * but triggers a RTC alarm if the box is suspend. - * - * This interface is influenced by the Android RTC Alarm timer - * interface. - * - * Copyright (C) 2010 IBM Corperation - * - * Author: John Stultz - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * struct alarm_base - Alarm timer bases - * @lock: Lock for syncrhonized access to the base - * @timerqueue: Timerqueue head managing the list of events - * @gettime: Function to read the time correlating to the base - * @base_clockid: clockid for the base - */ -static struct alarm_base { - spinlock_t lock; - struct timerqueue_head timerqueue; - ktime_t (*gettime)(void); - clockid_t base_clockid; -} alarm_bases[ALARM_NUMTYPE]; - -/* freezer delta & lock used to handle clock_nanosleep triggered wakeups */ -static ktime_t freezer_delta; -static DEFINE_SPINLOCK(freezer_delta_lock); - -static struct wakeup_source *ws; - -#ifdef CONFIG_RTC_CLASS -/* rtc timer and device for setting alarm wakeups at suspend */ -static struct rtc_timer rtctimer; -static struct rtc_device *rtcdev; -static DEFINE_SPINLOCK(rtcdev_lock); - -/** - * alarmtimer_get_rtcdev - Return selected rtcdevice - * - * This function returns the rtc device to use for wakealarms. - * If one has not already been chosen, it checks to see if a - * functional rtc device is available. - */ -struct rtc_device *alarmtimer_get_rtcdev(void) -{ - unsigned long flags; - struct rtc_device *ret; - - spin_lock_irqsave(&rtcdev_lock, flags); - ret = rtcdev; - spin_unlock_irqrestore(&rtcdev_lock, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(alarmtimer_get_rtcdev); - -static int alarmtimer_rtc_add_device(struct device *dev, - struct class_interface *class_intf) -{ - unsigned long flags; - struct rtc_device *rtc = to_rtc_device(dev); - - if (rtcdev) - return -EBUSY; - - if (!rtc->ops->set_alarm) - return -1; - if (!device_may_wakeup(rtc->dev.parent)) - return -1; - - spin_lock_irqsave(&rtcdev_lock, flags); - if (!rtcdev) { - rtcdev = rtc; - /* hold a reference so it doesn't go away */ - get_device(dev); - } - spin_unlock_irqrestore(&rtcdev_lock, flags); - return 0; -} - -static inline void alarmtimer_rtc_timer_init(void) -{ - rtc_timer_init(&rtctimer, NULL, NULL); -} - -static struct class_interface alarmtimer_rtc_interface = { - .add_dev = &alarmtimer_rtc_add_device, -}; - -static int alarmtimer_rtc_interface_setup(void) -{ - alarmtimer_rtc_interface.class = rtc_class; - return class_interface_register(&alarmtimer_rtc_interface); -} -static void alarmtimer_rtc_interface_remove(void) -{ - class_interface_unregister(&alarmtimer_rtc_interface); -} -#else -struct rtc_device *alarmtimer_get_rtcdev(void) -{ - return NULL; -} -#define rtcdev (NULL) -static inline int alarmtimer_rtc_interface_setup(void) { return 0; } -static inline void alarmtimer_rtc_interface_remove(void) { } -static inline void alarmtimer_rtc_timer_init(void) { } -#endif - -/** - * alarmtimer_enqueue - Adds an alarm timer to an alarm_base timerqueue - * @base: pointer to the base where the timer is being run - * @alarm: pointer to alarm being enqueued. - * - * Adds alarm to a alarm_base timerqueue - * - * Must hold base->lock when calling. - */ -static void alarmtimer_enqueue(struct alarm_base *base, struct alarm *alarm) -{ - if (alarm->state & ALARMTIMER_STATE_ENQUEUED) - timerqueue_del(&base->timerqueue, &alarm->node); - - timerqueue_add(&base->timerqueue, &alarm->node); - alarm->state |= ALARMTIMER_STATE_ENQUEUED; -} - -/** - * alarmtimer_dequeue - Removes an alarm timer from an alarm_base timerqueue - * @base: pointer to the base where the timer is running - * @alarm: pointer to alarm being removed - * - * Removes alarm to a alarm_base timerqueue - * - * Must hold base->lock when calling. - */ -static void alarmtimer_dequeue(struct alarm_base *base, struct alarm *alarm) -{ - if (!(alarm->state & ALARMTIMER_STATE_ENQUEUED)) - return; - - timerqueue_del(&base->timerqueue, &alarm->node); - alarm->state &= ~ALARMTIMER_STATE_ENQUEUED; -} - - -/** - * alarmtimer_fired - Handles alarm hrtimer being fired. - * @timer: pointer to hrtimer being run - * - * When a alarm timer fires, this runs through the timerqueue to - * see which alarms expired, and runs those. If there are more alarm - * timers queued for the future, we set the hrtimer to fire when - * when the next future alarm timer expires. - */ -static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer) -{ - struct alarm *alarm = container_of(timer, struct alarm, timer); - struct alarm_base *base = &alarm_bases[alarm->type]; - unsigned long flags; - int ret = HRTIMER_NORESTART; - int restart = ALARMTIMER_NORESTART; - - spin_lock_irqsave(&base->lock, flags); - alarmtimer_dequeue(base, alarm); - spin_unlock_irqrestore(&base->lock, flags); - - if (alarm->function) - restart = alarm->function(alarm, base->gettime()); - - spin_lock_irqsave(&base->lock, flags); - if (restart != ALARMTIMER_NORESTART) { - hrtimer_set_expires(&alarm->timer, alarm->node.expires); - alarmtimer_enqueue(base, alarm); - ret = HRTIMER_RESTART; - } - spin_unlock_irqrestore(&base->lock, flags); - - return ret; - -} - -ktime_t alarm_expires_remaining(const struct alarm *alarm) -{ - struct alarm_base *base = &alarm_bases[alarm->type]; - return ktime_sub(alarm->node.expires, base->gettime()); -} -EXPORT_SYMBOL_GPL(alarm_expires_remaining); - -#ifdef CONFIG_RTC_CLASS -/** - * alarmtimer_suspend - Suspend time callback - * @dev: unused - * @state: unused - * - * When we are going into suspend, we look through the bases - * to see which is the soonest timer to expire. We then - * set an rtc timer to fire that far into the future, which - * will wake us from suspend. - */ -static int alarmtimer_suspend(struct device *dev) -{ - struct rtc_time tm; - ktime_t min, now; - unsigned long flags; - struct rtc_device *rtc; - int i; - int ret; - - spin_lock_irqsave(&freezer_delta_lock, flags); - min = freezer_delta; - freezer_delta = ktime_set(0, 0); - spin_unlock_irqrestore(&freezer_delta_lock, flags); - - rtc = alarmtimer_get_rtcdev(); - /* If we have no rtcdev, just return */ - if (!rtc) - return 0; - - /* Find the soonest timer to expire*/ - for (i = 0; i < ALARM_NUMTYPE; i++) { - struct alarm_base *base = &alarm_bases[i]; - struct timerqueue_node *next; - ktime_t delta; - - spin_lock_irqsave(&base->lock, flags); - next = timerqueue_getnext(&base->timerqueue); - spin_unlock_irqrestore(&base->lock, flags); - if (!next) - continue; - delta = ktime_sub(next->expires, base->gettime()); - if (!min.tv64 || (delta.tv64 < min.tv64)) - min = delta; - } - if (min.tv64 == 0) - return 0; - - if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) { - __pm_wakeup_event(ws, 2 * MSEC_PER_SEC); - return -EBUSY; - } - - /* Setup an rtc timer to fire that far in the future */ - rtc_timer_cancel(rtc, &rtctimer); - rtc_read_time(rtc, &tm); - now = rtc_tm_to_ktime(tm); - now = ktime_add(now, min); - - /* Set alarm, if in the past reject suspend briefly to handle */ - ret = rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0)); - if (ret < 0) - __pm_wakeup_event(ws, MSEC_PER_SEC); - return ret; -} - -static int alarmtimer_resume(struct device *dev) -{ - struct rtc_device *rtc; - - rtc = alarmtimer_get_rtcdev(); - if (rtc) - rtc_timer_cancel(rtc, &rtctimer); - return 0; -} - -#else -static int alarmtimer_suspend(struct device *dev) -{ - return 0; -} - -static int alarmtimer_resume(struct device *dev) -{ - return 0; -} -#endif - -static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type) -{ - ktime_t delta; - unsigned long flags; - struct alarm_base *base = &alarm_bases[type]; - - delta = ktime_sub(absexp, base->gettime()); - - spin_lock_irqsave(&freezer_delta_lock, flags); - if (!freezer_delta.tv64 || (delta.tv64 < freezer_delta.tv64)) - freezer_delta = delta; - spin_unlock_irqrestore(&freezer_delta_lock, flags); -} - - -/** - * alarm_init - Initialize an alarm structure - * @alarm: ptr to alarm to be initialized - * @type: the type of the alarm - * @function: callback that is run when the alarm fires - */ -void alarm_init(struct alarm *alarm, enum alarmtimer_type type, - enum alarmtimer_restart (*function)(struct alarm *, ktime_t)) -{ - timerqueue_init(&alarm->node); - hrtimer_init(&alarm->timer, alarm_bases[type].base_clockid, - HRTIMER_MODE_ABS); - alarm->timer.function = alarmtimer_fired; - alarm->function = function; - alarm->type = type; - alarm->state = ALARMTIMER_STATE_INACTIVE; -} -EXPORT_SYMBOL_GPL(alarm_init); - -/** - * alarm_start - Sets an absolute alarm to fire - * @alarm: ptr to alarm to set - * @start: time to run the alarm - */ -void alarm_start(struct alarm *alarm, ktime_t start) -{ - struct alarm_base *base = &alarm_bases[alarm->type]; - unsigned long flags; - - spin_lock_irqsave(&base->lock, flags); - alarm->node.expires = start; - alarmtimer_enqueue(base, alarm); - hrtimer_start(&alarm->timer, alarm->node.expires, HRTIMER_MODE_ABS); - spin_unlock_irqrestore(&base->lock, flags); -} -EXPORT_SYMBOL_GPL(alarm_start); - -/** - * alarm_start_relative - Sets a relative alarm to fire - * @alarm: ptr to alarm to set - * @start: time relative to now to run the alarm - */ -void alarm_start_relative(struct alarm *alarm, ktime_t start) -{ - struct alarm_base *base = &alarm_bases[alarm->type]; - - start = ktime_add(start, base->gettime()); - alarm_start(alarm, start); -} -EXPORT_SYMBOL_GPL(alarm_start_relative); - -void alarm_restart(struct alarm *alarm) -{ - struct alarm_base *base = &alarm_bases[alarm->type]; - unsigned long flags; - - spin_lock_irqsave(&base->lock, flags); - hrtimer_set_expires(&alarm->timer, alarm->node.expires); - hrtimer_restart(&alarm->timer); - alarmtimer_enqueue(base, alarm); - spin_unlock_irqrestore(&base->lock, flags); -} -EXPORT_SYMBOL_GPL(alarm_restart); - -/** - * alarm_try_to_cancel - Tries to cancel an alarm timer - * @alarm: ptr to alarm to be canceled - * - * Returns 1 if the timer was canceled, 0 if it was not running, - * and -1 if the callback was running - */ -int alarm_try_to_cancel(struct alarm *alarm) -{ - struct alarm_base *base = &alarm_bases[alarm->type]; - unsigned long flags; - int ret; - - spin_lock_irqsave(&base->lock, flags); - ret = hrtimer_try_to_cancel(&alarm->timer); - if (ret >= 0) - alarmtimer_dequeue(base, alarm); - spin_unlock_irqrestore(&base->lock, flags); - return ret; -} -EXPORT_SYMBOL_GPL(alarm_try_to_cancel); - - -/** - * alarm_cancel - Spins trying to cancel an alarm timer until it is done - * @alarm: ptr to alarm to be canceled - * - * Returns 1 if the timer was canceled, 0 if it was not active. - */ -int alarm_cancel(struct alarm *alarm) -{ - for (;;) { - int ret = alarm_try_to_cancel(alarm); - if (ret >= 0) - return ret; - cpu_relax(); - } -} -EXPORT_SYMBOL_GPL(alarm_cancel); - - -u64 alarm_forward(struct alarm *alarm, ktime_t now, ktime_t interval) -{ - u64 overrun = 1; - ktime_t delta; - - delta = ktime_sub(now, alarm->node.expires); - - if (delta.tv64 < 0) - return 0; - - if (unlikely(delta.tv64 >= interval.tv64)) { - s64 incr = ktime_to_ns(interval); - - overrun = ktime_divns(delta, incr); - - alarm->node.expires = ktime_add_ns(alarm->node.expires, - incr*overrun); - - if (alarm->node.expires.tv64 > now.tv64) - return overrun; - /* - * This (and the ktime_add() below) is the - * correction for exact: - */ - overrun++; - } - - alarm->node.expires = ktime_add(alarm->node.expires, interval); - return overrun; -} -EXPORT_SYMBOL_GPL(alarm_forward); - -u64 alarm_forward_now(struct alarm *alarm, ktime_t interval) -{ - struct alarm_base *base = &alarm_bases[alarm->type]; - - return alarm_forward(alarm, base->gettime(), interval); -} -EXPORT_SYMBOL_GPL(alarm_forward_now); - - -/** - * clock2alarm - helper that converts from clockid to alarmtypes - * @clockid: clockid. - */ -static enum alarmtimer_type clock2alarm(clockid_t clockid) -{ - if (clockid == CLOCK_REALTIME_ALARM) - return ALARM_REALTIME; - if (clockid == CLOCK_BOOTTIME_ALARM) - return ALARM_BOOTTIME; - return -1; -} - -/** - * alarm_handle_timer - Callback for posix timers - * @alarm: alarm that fired - * - * Posix timer callback for expired alarm timers. - */ -static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm, - ktime_t now) -{ - unsigned long flags; - struct k_itimer *ptr = container_of(alarm, struct k_itimer, - it.alarm.alarmtimer); - enum alarmtimer_restart result = ALARMTIMER_NORESTART; - - spin_lock_irqsave(&ptr->it_lock, flags); - if ((ptr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) { - if (posix_timer_event(ptr, 0) != 0) - ptr->it_overrun++; - } - - /* Re-add periodic timers */ - if (ptr->it.alarm.interval.tv64) { - ptr->it_overrun += alarm_forward(alarm, now, - ptr->it.alarm.interval); - result = ALARMTIMER_RESTART; - } - spin_unlock_irqrestore(&ptr->it_lock, flags); - - return result; -} - -/** - * alarm_clock_getres - posix getres interface - * @which_clock: clockid - * @tp: timespec to fill - * - * Returns the granularity of underlying alarm base clock - */ -static int alarm_clock_getres(const clockid_t which_clock, struct timespec *tp) -{ - if (!alarmtimer_get_rtcdev()) - return -EINVAL; - - tp->tv_sec = 0; - tp->tv_nsec = hrtimer_resolution; - return 0; -} - -/** - * alarm_clock_get - posix clock_get interface - * @which_clock: clockid - * @tp: timespec to fill. - * - * Provides the underlying alarm base time. - */ -static int alarm_clock_get(clockid_t which_clock, struct timespec *tp) -{ - struct alarm_base *base = &alarm_bases[clock2alarm(which_clock)]; - - if (!alarmtimer_get_rtcdev()) - return -EINVAL; - - *tp = ktime_to_timespec(base->gettime()); - return 0; -} - -/** - * alarm_timer_create - posix timer_create interface - * @new_timer: k_itimer pointer to manage - * - * Initializes the k_itimer structure. - */ -static int alarm_timer_create(struct k_itimer *new_timer) -{ - enum alarmtimer_type type; - - if (!alarmtimer_get_rtcdev()) - return -ENOTSUPP; - - if (!capable(CAP_WAKE_ALARM)) - return -EPERM; - - type = clock2alarm(new_timer->it_clock); - alarm_init(&new_timer->it.alarm.alarmtimer, type, alarm_handle_timer); - return 0; -} - -/** - * alarm_timer_get - posix timer_get interface - * @new_timer: k_itimer pointer - * @cur_setting: itimerspec data to fill - * - * Copies out the current itimerspec data - */ -static void alarm_timer_get(struct k_itimer *timr, - struct itimerspec *cur_setting) -{ - ktime_t relative_expiry_time = - alarm_expires_remaining(&(timr->it.alarm.alarmtimer)); - - if (ktime_to_ns(relative_expiry_time) > 0) { - cur_setting->it_value = ktime_to_timespec(relative_expiry_time); - } else { - cur_setting->it_value.tv_sec = 0; - cur_setting->it_value.tv_nsec = 0; - } - - cur_setting->it_interval = ktime_to_timespec(timr->it.alarm.interval); -} - -/** - * alarm_timer_del - posix timer_del interface - * @timr: k_itimer pointer to be deleted - * - * Cancels any programmed alarms for the given timer. - */ -static int alarm_timer_del(struct k_itimer *timr) -{ - if (!rtcdev) - return -ENOTSUPP; - - if (alarm_try_to_cancel(&timr->it.alarm.alarmtimer) < 0) - return TIMER_RETRY; - - return 0; -} - -/** - * alarm_timer_set - posix timer_set interface - * @timr: k_itimer pointer to be deleted - * @flags: timer flags - * @new_setting: itimerspec to be used - * @old_setting: itimerspec being replaced - * - * Sets the timer to new_setting, and starts the timer. - */ -static int alarm_timer_set(struct k_itimer *timr, int flags, - struct itimerspec *new_setting, - struct itimerspec *old_setting) -{ - ktime_t exp; - - if (!rtcdev) - return -ENOTSUPP; - - if (flags & ~TIMER_ABSTIME) - return -EINVAL; - - if (old_setting) - alarm_timer_get(timr, old_setting); - - /* If the timer was already set, cancel it */ - if (alarm_try_to_cancel(&timr->it.alarm.alarmtimer) < 0) - return TIMER_RETRY; - - /* start the timer */ - timr->it.alarm.interval = timespec_to_ktime(new_setting->it_interval); - exp = timespec_to_ktime(new_setting->it_value); - /* Convert (if necessary) to absolute time */ - if (flags != TIMER_ABSTIME) { - ktime_t now; - - now = alarm_bases[timr->it.alarm.alarmtimer.type].gettime(); - exp = ktime_add(now, exp); - } - - alarm_start(&timr->it.alarm.alarmtimer, exp); - return 0; -} - -/** - * alarmtimer_nsleep_wakeup - Wakeup function for alarm_timer_nsleep - * @alarm: ptr to alarm that fired - * - * Wakes up the task that set the alarmtimer - */ -static enum alarmtimer_restart alarmtimer_nsleep_wakeup(struct alarm *alarm, - ktime_t now) -{ - struct task_struct *task = (struct task_struct *)alarm->data; - - alarm->data = NULL; - if (task) - wake_up_process(task); - return ALARMTIMER_NORESTART; -} - -/** - * alarmtimer_do_nsleep - Internal alarmtimer nsleep implementation - * @alarm: ptr to alarmtimer - * @absexp: absolute expiration time - * - * Sets the alarm timer and sleeps until it is fired or interrupted. - */ -static int alarmtimer_do_nsleep(struct alarm *alarm, ktime_t absexp) -{ - alarm->data = (void *)current; - do { - set_current_state(TASK_INTERRUPTIBLE); - alarm_start(alarm, absexp); - if (likely(alarm->data)) - schedule(); - - alarm_cancel(alarm); - } while (alarm->data && !signal_pending(current)); - - __set_current_state(TASK_RUNNING); - - return (alarm->data == NULL); -} - - -/** - * update_rmtp - Update remaining timespec value - * @exp: expiration time - * @type: timer type - * @rmtp: user pointer to remaining timepsec value - * - * Helper function that fills in rmtp value with time between - * now and the exp value - */ -static int update_rmtp(ktime_t exp, enum alarmtimer_type type, - struct timespec __user *rmtp) -{ - struct timespec rmt; - ktime_t rem; - - rem = ktime_sub(exp, alarm_bases[type].gettime()); - - if (rem.tv64 <= 0) - return 0; - rmt = ktime_to_timespec(rem); - - if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) - return -EFAULT; - - return 1; - -} - -/** - * alarm_timer_nsleep_restart - restartblock alarmtimer nsleep - * @restart: ptr to restart block - * - * Handles restarted clock_nanosleep calls - */ -static long __sched alarm_timer_nsleep_restart(struct restart_block *restart) -{ - enum alarmtimer_type type = restart->nanosleep.clockid; - ktime_t exp; - struct timespec __user *rmtp; - struct alarm alarm; - int ret = 0; - - exp.tv64 = restart->nanosleep.expires; - alarm_init(&alarm, type, alarmtimer_nsleep_wakeup); - - if (alarmtimer_do_nsleep(&alarm, exp)) - goto out; - - if (freezing(current)) - alarmtimer_freezerset(exp, type); - - rmtp = restart->nanosleep.rmtp; - if (rmtp) { - ret = update_rmtp(exp, type, rmtp); - if (ret <= 0) - goto out; - } - - - /* The other values in restart are already filled in */ - ret = -ERESTART_RESTARTBLOCK; -out: - return ret; -} - -/** - * alarm_timer_nsleep - alarmtimer nanosleep - * @which_clock: clockid - * @flags: determins abstime or relative - * @tsreq: requested sleep time (abs or rel) - * @rmtp: remaining sleep time saved - * - * Handles clock_nanosleep calls against _ALARM clockids - */ -static int alarm_timer_nsleep(const clockid_t which_clock, int flags, - struct timespec *tsreq, struct timespec __user *rmtp) -{ - enum alarmtimer_type type = clock2alarm(which_clock); - struct alarm alarm; - ktime_t exp; - int ret = 0; - struct restart_block *restart; - - if (!alarmtimer_get_rtcdev()) - return -ENOTSUPP; - - if (flags & ~TIMER_ABSTIME) - return -EINVAL; - - if (!capable(CAP_WAKE_ALARM)) - return -EPERM; - - alarm_init(&alarm, type, alarmtimer_nsleep_wakeup); - - exp = timespec_to_ktime(*tsreq); - /* Convert (if necessary) to absolute time */ - if (flags != TIMER_ABSTIME) { - ktime_t now = alarm_bases[type].gettime(); - exp = ktime_add(now, exp); - } - - if (alarmtimer_do_nsleep(&alarm, exp)) - goto out; - - if (freezing(current)) - alarmtimer_freezerset(exp, type); - - /* abs timers don't set remaining time or restart */ - if (flags == TIMER_ABSTIME) { - ret = -ERESTARTNOHAND; - goto out; - } - - if (rmtp) { - ret = update_rmtp(exp, type, rmtp); - if (ret <= 0) - goto out; - } - - restart = ¤t->restart_block; - restart->fn = alarm_timer_nsleep_restart; - restart->nanosleep.clockid = type; - restart->nanosleep.expires = exp.tv64; - restart->nanosleep.rmtp = rmtp; - ret = -ERESTART_RESTARTBLOCK; - -out: - return ret; -} - - -/* Suspend hook structures */ -static const struct dev_pm_ops alarmtimer_pm_ops = { - .suspend = alarmtimer_suspend, - .resume = alarmtimer_resume, -}; - -static struct platform_driver alarmtimer_driver = { - .driver = { - .name = "alarmtimer", - .pm = &alarmtimer_pm_ops, - } -}; - -/** - * alarmtimer_init - Initialize alarm timer code - * - * This function initializes the alarm bases and registers - * the posix clock ids. - */ -static int __init alarmtimer_init(void) -{ - struct platform_device *pdev; - int error = 0; - int i; - struct k_clock alarm_clock = { - .clock_getres = alarm_clock_getres, - .clock_get = alarm_clock_get, - .timer_create = alarm_timer_create, - .timer_set = alarm_timer_set, - .timer_del = alarm_timer_del, - .timer_get = alarm_timer_get, - .nsleep = alarm_timer_nsleep, - }; - - alarmtimer_rtc_timer_init(); - - posix_timers_register_clock(CLOCK_REALTIME_ALARM, &alarm_clock); - posix_timers_register_clock(CLOCK_BOOTTIME_ALARM, &alarm_clock); - - /* Initialize alarm bases */ - alarm_bases[ALARM_REALTIME].base_clockid = CLOCK_REALTIME; - alarm_bases[ALARM_REALTIME].gettime = &ktime_get_real; - alarm_bases[ALARM_BOOTTIME].base_clockid = CLOCK_BOOTTIME; - alarm_bases[ALARM_BOOTTIME].gettime = &ktime_get_boottime; - for (i = 0; i < ALARM_NUMTYPE; i++) { - timerqueue_init_head(&alarm_bases[i].timerqueue); - spin_lock_init(&alarm_bases[i].lock); - } - - error = alarmtimer_rtc_interface_setup(); - if (error) - return error; - - error = platform_driver_register(&alarmtimer_driver); - if (error) - goto out_if; - - pdev = platform_device_register_simple("alarmtimer", -1, NULL, 0); - if (IS_ERR(pdev)) { - error = PTR_ERR(pdev); - goto out_drv; - } - ws = wakeup_source_register("alarmtimer"); - return 0; - -out_drv: - platform_driver_unregister(&alarmtimer_driver); -out_if: - alarmtimer_rtc_interface_remove(); - return error; -} -device_initcall(alarmtimer_init); diff --git a/src/linux/kernel/time/clockevents.c b/src/linux/kernel/time/clockevents.c deleted file mode 100644 index 2c5bc77..0000000 --- a/src/linux/kernel/time/clockevents.c +++ /dev/null @@ -1,763 +0,0 @@ -/* - * linux/kernel/time/clockevents.c - * - * This file contains functions which manage clock event devices. - * - * Copyright(C) 2005-2006, Thomas Gleixner - * Copyright(C) 2005-2007, Red Hat, Inc., Ingo Molnar - * Copyright(C) 2006-2007, Timesys Corp., Thomas Gleixner - * - * This code is licenced under the GPL version 2. For details see - * kernel-base/COPYING. - */ - -#include -#include -#include -#include -#include -#include - -#include "tick-internal.h" - -/* The registered clock event devices */ -static LIST_HEAD(clockevent_devices); -static LIST_HEAD(clockevents_released); -/* Protection for the above */ -static DEFINE_RAW_SPINLOCK(clockevents_lock); -/* Protection for unbind operations */ -static DEFINE_MUTEX(clockevents_mutex); - -struct ce_unbind { - struct clock_event_device *ce; - int res; -}; - -static u64 cev_delta2ns(unsigned long latch, struct clock_event_device *evt, - bool ismax) -{ - u64 clc = (u64) latch << evt->shift; - u64 rnd; - - if (unlikely(!evt->mult)) { - evt->mult = 1; - WARN_ON(1); - } - rnd = (u64) evt->mult - 1; - - /* - * Upper bound sanity check. If the backwards conversion is - * not equal latch, we know that the above shift overflowed. - */ - if ((clc >> evt->shift) != (u64)latch) - clc = ~0ULL; - - /* - * Scaled math oddities: - * - * For mult <= (1 << shift) we can safely add mult - 1 to - * prevent integer rounding loss. So the backwards conversion - * from nsec to device ticks will be correct. - * - * For mult > (1 << shift), i.e. device frequency is > 1GHz we - * need to be careful. Adding mult - 1 will result in a value - * which when converted back to device ticks can be larger - * than latch by up to (mult - 1) >> shift. For the min_delta - * calculation we still want to apply this in order to stay - * above the minimum device ticks limit. For the upper limit - * we would end up with a latch value larger than the upper - * limit of the device, so we omit the add to stay below the - * device upper boundary. - * - * Also omit the add if it would overflow the u64 boundary. - */ - if ((~0ULL - clc > rnd) && - (!ismax || evt->mult <= (1ULL << evt->shift))) - clc += rnd; - - do_div(clc, evt->mult); - - /* Deltas less than 1usec are pointless noise */ - return clc > 1000 ? clc : 1000; -} - -/** - * clockevents_delta2ns - Convert a latch value (device ticks) to nanoseconds - * @latch: value to convert - * @evt: pointer to clock event device descriptor - * - * Math helper, returns latch value converted to nanoseconds (bound checked) - */ -u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt) -{ - return cev_delta2ns(latch, evt, false); -} -EXPORT_SYMBOL_GPL(clockevent_delta2ns); - -static int __clockevents_switch_state(struct clock_event_device *dev, - enum clock_event_state state) -{ - if (dev->features & CLOCK_EVT_FEAT_DUMMY) - return 0; - - /* Transition with new state-specific callbacks */ - switch (state) { - case CLOCK_EVT_STATE_DETACHED: - /* The clockevent device is getting replaced. Shut it down. */ - - case CLOCK_EVT_STATE_SHUTDOWN: - if (dev->set_state_shutdown) - return dev->set_state_shutdown(dev); - return 0; - - case CLOCK_EVT_STATE_PERIODIC: - /* Core internal bug */ - if (!(dev->features & CLOCK_EVT_FEAT_PERIODIC)) - return -ENOSYS; - if (dev->set_state_periodic) - return dev->set_state_periodic(dev); - return 0; - - case CLOCK_EVT_STATE_ONESHOT: - /* Core internal bug */ - if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT)) - return -ENOSYS; - if (dev->set_state_oneshot) - return dev->set_state_oneshot(dev); - return 0; - - case CLOCK_EVT_STATE_ONESHOT_STOPPED: - /* Core internal bug */ - if (WARN_ONCE(!clockevent_state_oneshot(dev), - "Current state: %d\n", - clockevent_get_state(dev))) - return -EINVAL; - - if (dev->set_state_oneshot_stopped) - return dev->set_state_oneshot_stopped(dev); - else - return -ENOSYS; - - default: - return -ENOSYS; - } -} - -/** - * clockevents_switch_state - set the operating state of a clock event device - * @dev: device to modify - * @state: new state - * - * Must be called with interrupts disabled ! - */ -void clockevents_switch_state(struct clock_event_device *dev, - enum clock_event_state state) -{ - if (clockevent_get_state(dev) != state) { - if (__clockevents_switch_state(dev, state)) - return; - - clockevent_set_state(dev, state); - - /* - * A nsec2cyc multiplicator of 0 is invalid and we'd crash - * on it, so fix it up and emit a warning: - */ - if (clockevent_state_oneshot(dev)) { - if (unlikely(!dev->mult)) { - dev->mult = 1; - WARN_ON(1); - } - } - } -} - -/** - * clockevents_shutdown - shutdown the device and clear next_event - * @dev: device to shutdown - */ -void clockevents_shutdown(struct clock_event_device *dev) -{ - clockevents_switch_state(dev, CLOCK_EVT_STATE_SHUTDOWN); - dev->next_event.tv64 = KTIME_MAX; -} - -/** - * clockevents_tick_resume - Resume the tick device before using it again - * @dev: device to resume - */ -int clockevents_tick_resume(struct clock_event_device *dev) -{ - int ret = 0; - - if (dev->tick_resume) - ret = dev->tick_resume(dev); - - return ret; -} - -#ifdef CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST - -/* Limit min_delta to a jiffie */ -#define MIN_DELTA_LIMIT (NSEC_PER_SEC / HZ) - -/** - * clockevents_increase_min_delta - raise minimum delta of a clock event device - * @dev: device to increase the minimum delta - * - * Returns 0 on success, -ETIME when the minimum delta reached the limit. - */ -static int clockevents_increase_min_delta(struct clock_event_device *dev) -{ - /* Nothing to do if we already reached the limit */ - if (dev->min_delta_ns >= MIN_DELTA_LIMIT) { - printk_deferred(KERN_WARNING - "CE: Reprogramming failure. Giving up\n"); - dev->next_event.tv64 = KTIME_MAX; - return -ETIME; - } - - if (dev->min_delta_ns < 5000) - dev->min_delta_ns = 5000; - else - dev->min_delta_ns += dev->min_delta_ns >> 1; - - if (dev->min_delta_ns > MIN_DELTA_LIMIT) - dev->min_delta_ns = MIN_DELTA_LIMIT; - - printk_deferred(KERN_WARNING - "CE: %s increased min_delta_ns to %llu nsec\n", - dev->name ? dev->name : "?", - (unsigned long long) dev->min_delta_ns); - return 0; -} - -/** - * clockevents_program_min_delta - Set clock event device to the minimum delay. - * @dev: device to program - * - * Returns 0 on success, -ETIME when the retry loop failed. - */ -static int clockevents_program_min_delta(struct clock_event_device *dev) -{ - unsigned long long clc; - int64_t delta; - int i; - - for (i = 0;;) { - delta = dev->min_delta_ns; - dev->next_event = ktime_add_ns(ktime_get(), delta); - - if (clockevent_state_shutdown(dev)) - return 0; - - dev->retries++; - clc = ((unsigned long long) delta * dev->mult) >> dev->shift; - if (dev->set_next_event((unsigned long) clc, dev) == 0) - return 0; - - if (++i > 2) { - /* - * We tried 3 times to program the device with the - * given min_delta_ns. Try to increase the minimum - * delta, if that fails as well get out of here. - */ - if (clockevents_increase_min_delta(dev)) - return -ETIME; - i = 0; - } - } -} - -#else /* CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST */ - -/** - * clockevents_program_min_delta - Set clock event device to the minimum delay. - * @dev: device to program - * - * Returns 0 on success, -ETIME when the retry loop failed. - */ -static int clockevents_program_min_delta(struct clock_event_device *dev) -{ - unsigned long long clc; - int64_t delta; - - delta = dev->min_delta_ns; - dev->next_event = ktime_add_ns(ktime_get(), delta); - - if (clockevent_state_shutdown(dev)) - return 0; - - dev->retries++; - clc = ((unsigned long long) delta * dev->mult) >> dev->shift; - return dev->set_next_event((unsigned long) clc, dev); -} - -#endif /* CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST */ - -/** - * clockevents_program_event - Reprogram the clock event device. - * @dev: device to program - * @expires: absolute expiry time (monotonic clock) - * @force: program minimum delay if expires can not be set - * - * Returns 0 on success, -ETIME when the event is in the past. - */ -int clockevents_program_event(struct clock_event_device *dev, ktime_t expires, - bool force) -{ - unsigned long long clc; - int64_t delta; - int rc; - - if (unlikely(expires.tv64 < 0)) { - WARN_ON_ONCE(1); - return -ETIME; - } - - dev->next_event = expires; - - if (clockevent_state_shutdown(dev)) - return 0; - - /* We must be in ONESHOT state here */ - WARN_ONCE(!clockevent_state_oneshot(dev), "Current state: %d\n", - clockevent_get_state(dev)); - - /* Shortcut for clockevent devices that can deal with ktime. */ - if (dev->features & CLOCK_EVT_FEAT_KTIME) - return dev->set_next_ktime(expires, dev); - - delta = ktime_to_ns(ktime_sub(expires, ktime_get())); - if (delta <= 0) - return force ? clockevents_program_min_delta(dev) : -ETIME; - - delta = min(delta, (int64_t) dev->max_delta_ns); - delta = max(delta, (int64_t) dev->min_delta_ns); - - clc = ((unsigned long long) delta * dev->mult) >> dev->shift; - rc = dev->set_next_event((unsigned long) clc, dev); - - return (rc && force) ? clockevents_program_min_delta(dev) : rc; -} - -/* - * Called after a notify add to make devices available which were - * released from the notifier call. - */ -static void clockevents_notify_released(void) -{ - struct clock_event_device *dev; - - while (!list_empty(&clockevents_released)) { - dev = list_entry(clockevents_released.next, - struct clock_event_device, list); - list_del(&dev->list); - list_add(&dev->list, &clockevent_devices); - tick_check_new_device(dev); - } -} - -/* - * Try to install a replacement clock event device - */ -static int clockevents_replace(struct clock_event_device *ced) -{ - struct clock_event_device *dev, *newdev = NULL; - - list_for_each_entry(dev, &clockevent_devices, list) { - if (dev == ced || !clockevent_state_detached(dev)) - continue; - - if (!tick_check_replacement(newdev, dev)) - continue; - - if (!try_module_get(dev->owner)) - continue; - - if (newdev) - module_put(newdev->owner); - newdev = dev; - } - if (newdev) { - tick_install_replacement(newdev); - list_del_init(&ced->list); - } - return newdev ? 0 : -EBUSY; -} - -/* - * Called with clockevents_mutex and clockevents_lock held - */ -static int __clockevents_try_unbind(struct clock_event_device *ced, int cpu) -{ - /* Fast track. Device is unused */ - if (clockevent_state_detached(ced)) { - list_del_init(&ced->list); - return 0; - } - - return ced == per_cpu(tick_cpu_device, cpu).evtdev ? -EAGAIN : -EBUSY; -} - -/* - * SMP function call to unbind a device - */ -static void __clockevents_unbind(void *arg) -{ - struct ce_unbind *cu = arg; - int res; - - raw_spin_lock(&clockevents_lock); - res = __clockevents_try_unbind(cu->ce, smp_processor_id()); - if (res == -EAGAIN) - res = clockevents_replace(cu->ce); - cu->res = res; - raw_spin_unlock(&clockevents_lock); -} - -/* - * Issues smp function call to unbind a per cpu device. Called with - * clockevents_mutex held. - */ -static int clockevents_unbind(struct clock_event_device *ced, int cpu) -{ - struct ce_unbind cu = { .ce = ced, .res = -ENODEV }; - - smp_call_function_single(cpu, __clockevents_unbind, &cu, 1); - return cu.res; -} - -/* - * Unbind a clockevents device. - */ -int clockevents_unbind_device(struct clock_event_device *ced, int cpu) -{ - int ret; - - mutex_lock(&clockevents_mutex); - ret = clockevents_unbind(ced, cpu); - mutex_unlock(&clockevents_mutex); - return ret; -} -EXPORT_SYMBOL_GPL(clockevents_unbind_device); - -/** - * clockevents_register_device - register a clock event device - * @dev: device to register - */ -void clockevents_register_device(struct clock_event_device *dev) -{ - unsigned long flags; - - /* Initialize state to DETACHED */ - clockevent_set_state(dev, CLOCK_EVT_STATE_DETACHED); - - if (!dev->cpumask) { - WARN_ON(num_possible_cpus() > 1); - dev->cpumask = cpumask_of(smp_processor_id()); - } - - raw_spin_lock_irqsave(&clockevents_lock, flags); - - list_add(&dev->list, &clockevent_devices); - tick_check_new_device(dev); - clockevents_notify_released(); - - raw_spin_unlock_irqrestore(&clockevents_lock, flags); -} -EXPORT_SYMBOL_GPL(clockevents_register_device); - -void clockevents_config(struct clock_event_device *dev, u32 freq) -{ - u64 sec; - - if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT)) - return; - - /* - * Calculate the maximum number of seconds we can sleep. Limit - * to 10 minutes for hardware which can program more than - * 32bit ticks so we still get reasonable conversion values. - */ - sec = dev->max_delta_ticks; - do_div(sec, freq); - if (!sec) - sec = 1; - else if (sec > 600 && dev->max_delta_ticks > UINT_MAX) - sec = 600; - - clockevents_calc_mult_shift(dev, freq, sec); - dev->min_delta_ns = cev_delta2ns(dev->min_delta_ticks, dev, false); - dev->max_delta_ns = cev_delta2ns(dev->max_delta_ticks, dev, true); -} - -/** - * clockevents_config_and_register - Configure and register a clock event device - * @dev: device to register - * @freq: The clock frequency - * @min_delta: The minimum clock ticks to program in oneshot mode - * @max_delta: The maximum clock ticks to program in oneshot mode - * - * min/max_delta can be 0 for devices which do not support oneshot mode. - */ -void clockevents_config_and_register(struct clock_event_device *dev, - u32 freq, unsigned long min_delta, - unsigned long max_delta) -{ - dev->min_delta_ticks = min_delta; - dev->max_delta_ticks = max_delta; - clockevents_config(dev, freq); - clockevents_register_device(dev); -} -EXPORT_SYMBOL_GPL(clockevents_config_and_register); - -int __clockevents_update_freq(struct clock_event_device *dev, u32 freq) -{ - clockevents_config(dev, freq); - - if (clockevent_state_oneshot(dev)) - return clockevents_program_event(dev, dev->next_event, false); - - if (clockevent_state_periodic(dev)) - return __clockevents_switch_state(dev, CLOCK_EVT_STATE_PERIODIC); - - return 0; -} - -/** - * clockevents_update_freq - Update frequency and reprogram a clock event device. - * @dev: device to modify - * @freq: new device frequency - * - * Reconfigure and reprogram a clock event device in oneshot - * mode. Must be called on the cpu for which the device delivers per - * cpu timer events. If called for the broadcast device the core takes - * care of serialization. - * - * Returns 0 on success, -ETIME when the event is in the past. - */ -int clockevents_update_freq(struct clock_event_device *dev, u32 freq) -{ - unsigned long flags; - int ret; - - local_irq_save(flags); - ret = tick_broadcast_update_freq(dev, freq); - if (ret == -ENODEV) - ret = __clockevents_update_freq(dev, freq); - local_irq_restore(flags); - return ret; -} - -/* - * Noop handler when we shut down an event device - */ -void clockevents_handle_noop(struct clock_event_device *dev) -{ -} - -/** - * clockevents_exchange_device - release and request clock devices - * @old: device to release (can be NULL) - * @new: device to request (can be NULL) - * - * Called from various tick functions with clockevents_lock held and - * interrupts disabled. - */ -void clockevents_exchange_device(struct clock_event_device *old, - struct clock_event_device *new) -{ - /* - * Caller releases a clock event device. We queue it into the - * released list and do a notify add later. - */ - if (old) { - module_put(old->owner); - clockevents_switch_state(old, CLOCK_EVT_STATE_DETACHED); - list_del(&old->list); - list_add(&old->list, &clockevents_released); - } - - if (new) { - BUG_ON(!clockevent_state_detached(new)); - clockevents_shutdown(new); - } -} - -/** - * clockevents_suspend - suspend clock devices - */ -void clockevents_suspend(void) -{ - struct clock_event_device *dev; - - list_for_each_entry_reverse(dev, &clockevent_devices, list) - if (dev->suspend && !clockevent_state_detached(dev)) - dev->suspend(dev); -} - -/** - * clockevents_resume - resume clock devices - */ -void clockevents_resume(void) -{ - struct clock_event_device *dev; - - list_for_each_entry(dev, &clockevent_devices, list) - if (dev->resume && !clockevent_state_detached(dev)) - dev->resume(dev); -} - -#ifdef CONFIG_HOTPLUG_CPU -/** - * tick_cleanup_dead_cpu - Cleanup the tick and clockevents of a dead cpu - */ -void tick_cleanup_dead_cpu(int cpu) -{ - struct clock_event_device *dev, *tmp; - unsigned long flags; - - raw_spin_lock_irqsave(&clockevents_lock, flags); - - tick_shutdown_broadcast_oneshot(cpu); - tick_shutdown_broadcast(cpu); - tick_shutdown(cpu); - /* - * Unregister the clock event devices which were - * released from the users in the notify chain. - */ - list_for_each_entry_safe(dev, tmp, &clockevents_released, list) - list_del(&dev->list); - /* - * Now check whether the CPU has left unused per cpu devices - */ - list_for_each_entry_safe(dev, tmp, &clockevent_devices, list) { - if (cpumask_test_cpu(cpu, dev->cpumask) && - cpumask_weight(dev->cpumask) == 1 && - !tick_is_broadcast_device(dev)) { - BUG_ON(!clockevent_state_detached(dev)); - list_del(&dev->list); - } - } - raw_spin_unlock_irqrestore(&clockevents_lock, flags); -} -#endif - -#ifdef CONFIG_SYSFS -static struct bus_type clockevents_subsys = { - .name = "clockevents", - .dev_name = "clockevent", -}; - -static DEFINE_PER_CPU(struct device, tick_percpu_dev); -static struct tick_device *tick_get_tick_dev(struct device *dev); - -static ssize_t sysfs_show_current_tick_dev(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct tick_device *td; - ssize_t count = 0; - - raw_spin_lock_irq(&clockevents_lock); - td = tick_get_tick_dev(dev); - if (td && td->evtdev) - count = snprintf(buf, PAGE_SIZE, "%s\n", td->evtdev->name); - raw_spin_unlock_irq(&clockevents_lock); - return count; -} -static DEVICE_ATTR(current_device, 0444, sysfs_show_current_tick_dev, NULL); - -/* We don't support the abomination of removable broadcast devices */ -static ssize_t sysfs_unbind_tick_dev(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - char name[CS_NAME_LEN]; - ssize_t ret = sysfs_get_uname(buf, name, count); - struct clock_event_device *ce; - - if (ret < 0) - return ret; - - ret = -ENODEV; - mutex_lock(&clockevents_mutex); - raw_spin_lock_irq(&clockevents_lock); - list_for_each_entry(ce, &clockevent_devices, list) { - if (!strcmp(ce->name, name)) { - ret = __clockevents_try_unbind(ce, dev->id); - break; - } - } - raw_spin_unlock_irq(&clockevents_lock); - /* - * We hold clockevents_mutex, so ce can't go away - */ - if (ret == -EAGAIN) - ret = clockevents_unbind(ce, dev->id); - mutex_unlock(&clockevents_mutex); - return ret ? ret : count; -} -static DEVICE_ATTR(unbind_device, 0200, NULL, sysfs_unbind_tick_dev); - -#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST -static struct device tick_bc_dev = { - .init_name = "broadcast", - .id = 0, - .bus = &clockevents_subsys, -}; - -static struct tick_device *tick_get_tick_dev(struct device *dev) -{ - return dev == &tick_bc_dev ? tick_get_broadcast_device() : - &per_cpu(tick_cpu_device, dev->id); -} - -static __init int tick_broadcast_init_sysfs(void) -{ - int err = device_register(&tick_bc_dev); - - if (!err) - err = device_create_file(&tick_bc_dev, &dev_attr_current_device); - return err; -} -#else -static struct tick_device *tick_get_tick_dev(struct device *dev) -{ - return &per_cpu(tick_cpu_device, dev->id); -} -static inline int tick_broadcast_init_sysfs(void) { return 0; } -#endif - -static int __init tick_init_sysfs(void) -{ - int cpu; - - for_each_possible_cpu(cpu) { - struct device *dev = &per_cpu(tick_percpu_dev, cpu); - int err; - - dev->id = cpu; - dev->bus = &clockevents_subsys; - err = device_register(dev); - if (!err) - err = device_create_file(dev, &dev_attr_current_device); - if (!err) - err = device_create_file(dev, &dev_attr_unbind_device); - if (err) - return err; - } - return tick_broadcast_init_sysfs(); -} - -static int __init clockevents_init_sysfs(void) -{ - int err = subsys_system_register(&clockevents_subsys, NULL); - - if (!err) - err = tick_init_sysfs(); - return err; -} -device_initcall(clockevents_init_sysfs); -#endif /* SYSFS */ diff --git a/src/linux/kernel/time/clocksource.c b/src/linux/kernel/time/clocksource.c deleted file mode 100644 index 7e4fad7..0000000 --- a/src/linux/kernel/time/clocksource.c +++ /dev/null @@ -1,1062 +0,0 @@ -/* - * linux/kernel/time/clocksource.c - * - * This file contains the functions which manage clocksource drivers. - * - * Copyright (C) 2004, 2005 IBM, John Stultz (johnstul@us.ibm.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * TODO WishList: - * o Allow clocksource drivers to be unregistered - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include /* for spin_unlock_irq() using preempt_count() m68k */ -#include -#include - -#include "tick-internal.h" -#include "timekeeping_internal.h" - -/** - * clocks_calc_mult_shift - calculate mult/shift factors for scaled math of clocks - * @mult: pointer to mult variable - * @shift: pointer to shift variable - * @from: frequency to convert from - * @to: frequency to convert to - * @maxsec: guaranteed runtime conversion range in seconds - * - * The function evaluates the shift/mult pair for the scaled math - * operations of clocksources and clockevents. - * - * @to and @from are frequency values in HZ. For clock sources @to is - * NSEC_PER_SEC == 1GHz and @from is the counter frequency. For clock - * event @to is the counter frequency and @from is NSEC_PER_SEC. - * - * The @maxsec conversion range argument controls the time frame in - * seconds which must be covered by the runtime conversion with the - * calculated mult and shift factors. This guarantees that no 64bit - * overflow happens when the input value of the conversion is - * multiplied with the calculated mult factor. Larger ranges may - * reduce the conversion accuracy by chosing smaller mult and shift - * factors. - */ -void -clocks_calc_mult_shift(u32 *mult, u32 *shift, u32 from, u32 to, u32 maxsec) -{ - u64 tmp; - u32 sft, sftacc= 32; - - /* - * Calculate the shift factor which is limiting the conversion - * range: - */ - tmp = ((u64)maxsec * from) >> 32; - while (tmp) { - tmp >>=1; - sftacc--; - } - - /* - * Find the conversion shift/mult pair which has the best - * accuracy and fits the maxsec conversion range: - */ - for (sft = 32; sft > 0; sft--) { - tmp = (u64) to << sft; - tmp += from / 2; - do_div(tmp, from); - if ((tmp >> sftacc) == 0) - break; - } - *mult = tmp; - *shift = sft; -} - -/*[Clocksource internal variables]--------- - * curr_clocksource: - * currently selected clocksource. - * clocksource_list: - * linked list with the registered clocksources - * clocksource_mutex: - * protects manipulations to curr_clocksource and the clocksource_list - * override_name: - * Name of the user-specified clocksource. - */ -static struct clocksource *curr_clocksource; -static LIST_HEAD(clocksource_list); -static DEFINE_MUTEX(clocksource_mutex); -static char override_name[CS_NAME_LEN]; -static int finished_booting; - -#ifdef CONFIG_CLOCKSOURCE_WATCHDOG -static void clocksource_watchdog_work(struct work_struct *work); -static void clocksource_select(void); - -static LIST_HEAD(watchdog_list); -static struct clocksource *watchdog; -static struct timer_list watchdog_timer; -static DECLARE_WORK(watchdog_work, clocksource_watchdog_work); -static DEFINE_SPINLOCK(watchdog_lock); -static int watchdog_running; -static atomic_t watchdog_reset_pending; - -static int clocksource_watchdog_kthread(void *data); -static void __clocksource_change_rating(struct clocksource *cs, int rating); - -/* - * Interval: 0.5sec Threshold: 0.0625s - */ -#define WATCHDOG_INTERVAL (HZ >> 1) -#define WATCHDOG_THRESHOLD (NSEC_PER_SEC >> 4) - -static void clocksource_watchdog_work(struct work_struct *work) -{ - /* - * If kthread_run fails the next watchdog scan over the - * watchdog_list will find the unstable clock again. - */ - kthread_run(clocksource_watchdog_kthread, NULL, "kwatchdog"); -} - -static void __clocksource_unstable(struct clocksource *cs) -{ - cs->flags &= ~(CLOCK_SOURCE_VALID_FOR_HRES | CLOCK_SOURCE_WATCHDOG); - cs->flags |= CLOCK_SOURCE_UNSTABLE; - if (finished_booting) - schedule_work(&watchdog_work); -} - -/** - * clocksource_mark_unstable - mark clocksource unstable via watchdog - * @cs: clocksource to be marked unstable - * - * This function is called instead of clocksource_change_rating from - * cpu hotplug code to avoid a deadlock between the clocksource mutex - * and the cpu hotplug mutex. It defers the update of the clocksource - * to the watchdog thread. - */ -void clocksource_mark_unstable(struct clocksource *cs) -{ - unsigned long flags; - - spin_lock_irqsave(&watchdog_lock, flags); - if (!(cs->flags & CLOCK_SOURCE_UNSTABLE)) { - if (list_empty(&cs->wd_list)) - list_add(&cs->wd_list, &watchdog_list); - __clocksource_unstable(cs); - } - spin_unlock_irqrestore(&watchdog_lock, flags); -} - -static void clocksource_watchdog(unsigned long data) -{ - struct clocksource *cs; - cycle_t csnow, wdnow, cslast, wdlast, delta; - int64_t wd_nsec, cs_nsec; - int next_cpu, reset_pending; - - spin_lock(&watchdog_lock); - if (!watchdog_running) - goto out; - - reset_pending = atomic_read(&watchdog_reset_pending); - - list_for_each_entry(cs, &watchdog_list, wd_list) { - - /* Clocksource already marked unstable? */ - if (cs->flags & CLOCK_SOURCE_UNSTABLE) { - if (finished_booting) - schedule_work(&watchdog_work); - continue; - } - - local_irq_disable(); - csnow = cs->read(cs); - wdnow = watchdog->read(watchdog); - local_irq_enable(); - - /* Clocksource initialized ? */ - if (!(cs->flags & CLOCK_SOURCE_WATCHDOG) || - atomic_read(&watchdog_reset_pending)) { - cs->flags |= CLOCK_SOURCE_WATCHDOG; - cs->wd_last = wdnow; - cs->cs_last = csnow; - continue; - } - - delta = clocksource_delta(wdnow, cs->wd_last, watchdog->mask); - wd_nsec = clocksource_cyc2ns(delta, watchdog->mult, - watchdog->shift); - - delta = clocksource_delta(csnow, cs->cs_last, cs->mask); - cs_nsec = clocksource_cyc2ns(delta, cs->mult, cs->shift); - wdlast = cs->wd_last; /* save these in case we print them */ - cslast = cs->cs_last; - cs->cs_last = csnow; - cs->wd_last = wdnow; - - if (atomic_read(&watchdog_reset_pending)) - continue; - - /* Check the deviation from the watchdog clocksource. */ - if (abs(cs_nsec - wd_nsec) > WATCHDOG_THRESHOLD) { - pr_warn("timekeeping watchdog on CPU%d: Marking clocksource '%s' as unstable because the skew is too large:\n", - smp_processor_id(), cs->name); - pr_warn(" '%s' wd_now: %llx wd_last: %llx mask: %llx\n", - watchdog->name, wdnow, wdlast, watchdog->mask); - pr_warn(" '%s' cs_now: %llx cs_last: %llx mask: %llx\n", - cs->name, csnow, cslast, cs->mask); - __clocksource_unstable(cs); - continue; - } - - if (!(cs->flags & CLOCK_SOURCE_VALID_FOR_HRES) && - (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) && - (watchdog->flags & CLOCK_SOURCE_IS_CONTINUOUS)) { - /* Mark it valid for high-res. */ - cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES; - - /* - * clocksource_done_booting() will sort it if - * finished_booting is not set yet. - */ - if (!finished_booting) - continue; - - /* - * If this is not the current clocksource let - * the watchdog thread reselect it. Due to the - * change to high res this clocksource might - * be preferred now. If it is the current - * clocksource let the tick code know about - * that change. - */ - if (cs != curr_clocksource) { - cs->flags |= CLOCK_SOURCE_RESELECT; - schedule_work(&watchdog_work); - } else { - tick_clock_notify(); - } - } - } - - /* - * We only clear the watchdog_reset_pending, when we did a - * full cycle through all clocksources. - */ - if (reset_pending) - atomic_dec(&watchdog_reset_pending); - - /* - * Cycle through CPUs to check if the CPUs stay synchronized - * to each other. - */ - next_cpu = cpumask_next(raw_smp_processor_id(), cpu_online_mask); - if (next_cpu >= nr_cpu_ids) - next_cpu = cpumask_first(cpu_online_mask); - watchdog_timer.expires += WATCHDOG_INTERVAL; - add_timer_on(&watchdog_timer, next_cpu); -out: - spin_unlock(&watchdog_lock); -} - -static inline void clocksource_start_watchdog(void) -{ - if (watchdog_running || !watchdog || list_empty(&watchdog_list)) - return; - init_timer(&watchdog_timer); - watchdog_timer.function = clocksource_watchdog; - watchdog_timer.expires = jiffies + WATCHDOG_INTERVAL; - add_timer_on(&watchdog_timer, cpumask_first(cpu_online_mask)); - watchdog_running = 1; -} - -static inline void clocksource_stop_watchdog(void) -{ - if (!watchdog_running || (watchdog && !list_empty(&watchdog_list))) - return; - del_timer(&watchdog_timer); - watchdog_running = 0; -} - -static inline void clocksource_reset_watchdog(void) -{ - struct clocksource *cs; - - list_for_each_entry(cs, &watchdog_list, wd_list) - cs->flags &= ~CLOCK_SOURCE_WATCHDOG; -} - -static void clocksource_resume_watchdog(void) -{ - atomic_inc(&watchdog_reset_pending); -} - -static void clocksource_enqueue_watchdog(struct clocksource *cs) -{ - unsigned long flags; - - spin_lock_irqsave(&watchdog_lock, flags); - if (cs->flags & CLOCK_SOURCE_MUST_VERIFY) { - /* cs is a clocksource to be watched. */ - list_add(&cs->wd_list, &watchdog_list); - cs->flags &= ~CLOCK_SOURCE_WATCHDOG; - } else { - /* cs is a watchdog. */ - if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) - cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES; - } - spin_unlock_irqrestore(&watchdog_lock, flags); -} - -static void clocksource_select_watchdog(bool fallback) -{ - struct clocksource *cs, *old_wd; - unsigned long flags; - - spin_lock_irqsave(&watchdog_lock, flags); - /* save current watchdog */ - old_wd = watchdog; - if (fallback) - watchdog = NULL; - - list_for_each_entry(cs, &clocksource_list, list) { - /* cs is a clocksource to be watched. */ - if (cs->flags & CLOCK_SOURCE_MUST_VERIFY) - continue; - - /* Skip current if we were requested for a fallback. */ - if (fallback && cs == old_wd) - continue; - - /* Pick the best watchdog. */ - if (!watchdog || cs->rating > watchdog->rating) - watchdog = cs; - } - /* If we failed to find a fallback restore the old one. */ - if (!watchdog) - watchdog = old_wd; - - /* If we changed the watchdog we need to reset cycles. */ - if (watchdog != old_wd) - clocksource_reset_watchdog(); - - /* Check if the watchdog timer needs to be started. */ - clocksource_start_watchdog(); - spin_unlock_irqrestore(&watchdog_lock, flags); -} - -static void clocksource_dequeue_watchdog(struct clocksource *cs) -{ - unsigned long flags; - - spin_lock_irqsave(&watchdog_lock, flags); - if (cs != watchdog) { - if (cs->flags & CLOCK_SOURCE_MUST_VERIFY) { - /* cs is a watched clocksource. */ - list_del_init(&cs->wd_list); - /* Check if the watchdog timer needs to be stopped. */ - clocksource_stop_watchdog(); - } - } - spin_unlock_irqrestore(&watchdog_lock, flags); -} - -static int __clocksource_watchdog_kthread(void) -{ - struct clocksource *cs, *tmp; - unsigned long flags; - LIST_HEAD(unstable); - int select = 0; - - spin_lock_irqsave(&watchdog_lock, flags); - list_for_each_entry_safe(cs, tmp, &watchdog_list, wd_list) { - if (cs->flags & CLOCK_SOURCE_UNSTABLE) { - list_del_init(&cs->wd_list); - list_add(&cs->wd_list, &unstable); - select = 1; - } - if (cs->flags & CLOCK_SOURCE_RESELECT) { - cs->flags &= ~CLOCK_SOURCE_RESELECT; - select = 1; - } - } - /* Check if the watchdog timer needs to be stopped. */ - clocksource_stop_watchdog(); - spin_unlock_irqrestore(&watchdog_lock, flags); - - /* Needs to be done outside of watchdog lock */ - list_for_each_entry_safe(cs, tmp, &unstable, wd_list) { - list_del_init(&cs->wd_list); - __clocksource_change_rating(cs, 0); - } - return select; -} - -static int clocksource_watchdog_kthread(void *data) -{ - mutex_lock(&clocksource_mutex); - if (__clocksource_watchdog_kthread()) - clocksource_select(); - mutex_unlock(&clocksource_mutex); - return 0; -} - -static bool clocksource_is_watchdog(struct clocksource *cs) -{ - return cs == watchdog; -} - -#else /* CONFIG_CLOCKSOURCE_WATCHDOG */ - -static void clocksource_enqueue_watchdog(struct clocksource *cs) -{ - if (cs->flags & CLOCK_SOURCE_IS_CONTINUOUS) - cs->flags |= CLOCK_SOURCE_VALID_FOR_HRES; -} - -static void clocksource_select_watchdog(bool fallback) { } -static inline void clocksource_dequeue_watchdog(struct clocksource *cs) { } -static inline void clocksource_resume_watchdog(void) { } -static inline int __clocksource_watchdog_kthread(void) { return 0; } -static bool clocksource_is_watchdog(struct clocksource *cs) { return false; } -void clocksource_mark_unstable(struct clocksource *cs) { } - -#endif /* CONFIG_CLOCKSOURCE_WATCHDOG */ - -/** - * clocksource_suspend - suspend the clocksource(s) - */ -void clocksource_suspend(void) -{ - struct clocksource *cs; - - list_for_each_entry_reverse(cs, &clocksource_list, list) - if (cs->suspend) - cs->suspend(cs); -} - -/** - * clocksource_resume - resume the clocksource(s) - */ -void clocksource_resume(void) -{ - struct clocksource *cs; - - list_for_each_entry(cs, &clocksource_list, list) - if (cs->resume) - cs->resume(cs); - - clocksource_resume_watchdog(); -} - -/** - * clocksource_touch_watchdog - Update watchdog - * - * Update the watchdog after exception contexts such as kgdb so as not - * to incorrectly trip the watchdog. This might fail when the kernel - * was stopped in code which holds watchdog_lock. - */ -void clocksource_touch_watchdog(void) -{ - clocksource_resume_watchdog(); -} - -/** - * clocksource_max_adjustment- Returns max adjustment amount - * @cs: Pointer to clocksource - * - */ -static u32 clocksource_max_adjustment(struct clocksource *cs) -{ - u64 ret; - /* - * We won't try to correct for more than 11% adjustments (110,000 ppm), - */ - ret = (u64)cs->mult * 11; - do_div(ret,100); - return (u32)ret; -} - -/** - * clocks_calc_max_nsecs - Returns maximum nanoseconds that can be converted - * @mult: cycle to nanosecond multiplier - * @shift: cycle to nanosecond divisor (power of two) - * @maxadj: maximum adjustment value to mult (~11%) - * @mask: bitmask for two's complement subtraction of non 64 bit counters - * @max_cyc: maximum cycle value before potential overflow (does not include - * any safety margin) - * - * NOTE: This function includes a safety margin of 50%, in other words, we - * return half the number of nanoseconds the hardware counter can technically - * cover. This is done so that we can potentially detect problems caused by - * delayed timers or bad hardware, which might result in time intervals that - * are larger than what the math used can handle without overflows. - */ -u64 clocks_calc_max_nsecs(u32 mult, u32 shift, u32 maxadj, u64 mask, u64 *max_cyc) -{ - u64 max_nsecs, max_cycles; - - /* - * Calculate the maximum number of cycles that we can pass to the - * cyc2ns() function without overflowing a 64-bit result. - */ - max_cycles = ULLONG_MAX; - do_div(max_cycles, mult+maxadj); - - /* - * The actual maximum number of cycles we can defer the clocksource is - * determined by the minimum of max_cycles and mask. - * Note: Here we subtract the maxadj to make sure we don't sleep for - * too long if there's a large negative adjustment. - */ - max_cycles = min(max_cycles, mask); - max_nsecs = clocksource_cyc2ns(max_cycles, mult - maxadj, shift); - - /* return the max_cycles value as well if requested */ - if (max_cyc) - *max_cyc = max_cycles; - - /* Return 50% of the actual maximum, so we can detect bad values */ - max_nsecs >>= 1; - - return max_nsecs; -} - -/** - * clocksource_update_max_deferment - Updates the clocksource max_idle_ns & max_cycles - * @cs: Pointer to clocksource to be updated - * - */ -static inline void clocksource_update_max_deferment(struct clocksource *cs) -{ - cs->max_idle_ns = clocks_calc_max_nsecs(cs->mult, cs->shift, - cs->maxadj, cs->mask, - &cs->max_cycles); -} - -#ifndef CONFIG_ARCH_USES_GETTIMEOFFSET - -static struct clocksource *clocksource_find_best(bool oneshot, bool skipcur) -{ - struct clocksource *cs; - - if (!finished_booting || list_empty(&clocksource_list)) - return NULL; - - /* - * We pick the clocksource with the highest rating. If oneshot - * mode is active, we pick the highres valid clocksource with - * the best rating. - */ - list_for_each_entry(cs, &clocksource_list, list) { - if (skipcur && cs == curr_clocksource) - continue; - if (oneshot && !(cs->flags & CLOCK_SOURCE_VALID_FOR_HRES)) - continue; - return cs; - } - return NULL; -} - -static void __clocksource_select(bool skipcur) -{ - bool oneshot = tick_oneshot_mode_active(); - struct clocksource *best, *cs; - - /* Find the best suitable clocksource */ - best = clocksource_find_best(oneshot, skipcur); - if (!best) - return; - - /* Check for the override clocksource. */ - list_for_each_entry(cs, &clocksource_list, list) { - if (skipcur && cs == curr_clocksource) - continue; - if (strcmp(cs->name, override_name) != 0) - continue; - /* - * Check to make sure we don't switch to a non-highres - * capable clocksource if the tick code is in oneshot - * mode (highres or nohz) - */ - if (!(cs->flags & CLOCK_SOURCE_VALID_FOR_HRES) && oneshot) { - /* Override clocksource cannot be used. */ - if (cs->flags & CLOCK_SOURCE_UNSTABLE) { - pr_warn("Override clocksource %s is unstable and not HRT compatible - cannot switch while in HRT/NOHZ mode\n", - cs->name); - override_name[0] = 0; - } else { - /* - * The override cannot be currently verified. - * Deferring to let the watchdog check. - */ - pr_info("Override clocksource %s is not currently HRT compatible - deferring\n", - cs->name); - } - } else - /* Override clocksource can be used. */ - best = cs; - break; - } - - if (curr_clocksource != best && !timekeeping_notify(best)) { - pr_info("Switched to clocksource %s\n", best->name); - curr_clocksource = best; - } -} - -/** - * clocksource_select - Select the best clocksource available - * - * Private function. Must hold clocksource_mutex when called. - * - * Select the clocksource with the best rating, or the clocksource, - * which is selected by userspace override. - */ -static void clocksource_select(void) -{ - __clocksource_select(false); -} - -static void clocksource_select_fallback(void) -{ - __clocksource_select(true); -} - -#else /* !CONFIG_ARCH_USES_GETTIMEOFFSET */ -static inline void clocksource_select(void) { } -static inline void clocksource_select_fallback(void) { } - -#endif - -/* - * clocksource_done_booting - Called near the end of core bootup - * - * Hack to avoid lots of clocksource churn at boot time. - * We use fs_initcall because we want this to start before - * device_initcall but after subsys_initcall. - */ -static int __init clocksource_done_booting(void) -{ - mutex_lock(&clocksource_mutex); - curr_clocksource = clocksource_default_clock(); - finished_booting = 1; - /* - * Run the watchdog first to eliminate unstable clock sources - */ - __clocksource_watchdog_kthread(); - clocksource_select(); - mutex_unlock(&clocksource_mutex); - return 0; -} -fs_initcall(clocksource_done_booting); - -/* - * Enqueue the clocksource sorted by rating - */ -static void clocksource_enqueue(struct clocksource *cs) -{ - struct list_head *entry = &clocksource_list; - struct clocksource *tmp; - - list_for_each_entry(tmp, &clocksource_list, list) { - /* Keep track of the place, where to insert */ - if (tmp->rating < cs->rating) - break; - entry = &tmp->list; - } - list_add(&cs->list, entry); -} - -/** - * __clocksource_update_freq_scale - Used update clocksource with new freq - * @cs: clocksource to be registered - * @scale: Scale factor multiplied against freq to get clocksource hz - * @freq: clocksource frequency (cycles per second) divided by scale - * - * This should only be called from the clocksource->enable() method. - * - * This *SHOULD NOT* be called directly! Please use the - * __clocksource_update_freq_hz() or __clocksource_update_freq_khz() helper - * functions. - */ -void __clocksource_update_freq_scale(struct clocksource *cs, u32 scale, u32 freq) -{ - u64 sec; - - /* - * Default clocksources are *special* and self-define their mult/shift. - * But, you're not special, so you should specify a freq value. - */ - if (freq) { - /* - * Calc the maximum number of seconds which we can run before - * wrapping around. For clocksources which have a mask > 32-bit - * we need to limit the max sleep time to have a good - * conversion precision. 10 minutes is still a reasonable - * amount. That results in a shift value of 24 for a - * clocksource with mask >= 40-bit and f >= 4GHz. That maps to - * ~ 0.06ppm granularity for NTP. - */ - sec = cs->mask; - do_div(sec, freq); - do_div(sec, scale); - if (!sec) - sec = 1; - else if (sec > 600 && cs->mask > UINT_MAX) - sec = 600; - - clocks_calc_mult_shift(&cs->mult, &cs->shift, freq, - NSEC_PER_SEC / scale, sec * scale); - } - /* - * Ensure clocksources that have large 'mult' values don't overflow - * when adjusted. - */ - cs->maxadj = clocksource_max_adjustment(cs); - while (freq && ((cs->mult + cs->maxadj < cs->mult) - || (cs->mult - cs->maxadj > cs->mult))) { - cs->mult >>= 1; - cs->shift--; - cs->maxadj = clocksource_max_adjustment(cs); - } - - /* - * Only warn for *special* clocksources that self-define - * their mult/shift values and don't specify a freq. - */ - WARN_ONCE(cs->mult + cs->maxadj < cs->mult, - "timekeeping: Clocksource %s might overflow on 11%% adjustment\n", - cs->name); - - clocksource_update_max_deferment(cs); - - pr_info("%s: mask: 0x%llx max_cycles: 0x%llx, max_idle_ns: %lld ns\n", - cs->name, cs->mask, cs->max_cycles, cs->max_idle_ns); -} -EXPORT_SYMBOL_GPL(__clocksource_update_freq_scale); - -/** - * __clocksource_register_scale - Used to install new clocksources - * @cs: clocksource to be registered - * @scale: Scale factor multiplied against freq to get clocksource hz - * @freq: clocksource frequency (cycles per second) divided by scale - * - * Returns -EBUSY if registration fails, zero otherwise. - * - * This *SHOULD NOT* be called directly! Please use the - * clocksource_register_hz() or clocksource_register_khz helper functions. - */ -int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq) -{ - - /* Initialize mult/shift and max_idle_ns */ - __clocksource_update_freq_scale(cs, scale, freq); - - /* Add clocksource to the clocksource list */ - mutex_lock(&clocksource_mutex); - clocksource_enqueue(cs); - clocksource_enqueue_watchdog(cs); - clocksource_select(); - clocksource_select_watchdog(false); - mutex_unlock(&clocksource_mutex); - return 0; -} -EXPORT_SYMBOL_GPL(__clocksource_register_scale); - -static void __clocksource_change_rating(struct clocksource *cs, int rating) -{ - list_del(&cs->list); - cs->rating = rating; - clocksource_enqueue(cs); -} - -/** - * clocksource_change_rating - Change the rating of a registered clocksource - * @cs: clocksource to be changed - * @rating: new rating - */ -void clocksource_change_rating(struct clocksource *cs, int rating) -{ - mutex_lock(&clocksource_mutex); - __clocksource_change_rating(cs, rating); - clocksource_select(); - clocksource_select_watchdog(false); - mutex_unlock(&clocksource_mutex); -} -EXPORT_SYMBOL(clocksource_change_rating); - -/* - * Unbind clocksource @cs. Called with clocksource_mutex held - */ -static int clocksource_unbind(struct clocksource *cs) -{ - if (clocksource_is_watchdog(cs)) { - /* Select and try to install a replacement watchdog. */ - clocksource_select_watchdog(true); - if (clocksource_is_watchdog(cs)) - return -EBUSY; - } - - if (cs == curr_clocksource) { - /* Select and try to install a replacement clock source */ - clocksource_select_fallback(); - if (curr_clocksource == cs) - return -EBUSY; - } - clocksource_dequeue_watchdog(cs); - list_del_init(&cs->list); - return 0; -} - -/** - * clocksource_unregister - remove a registered clocksource - * @cs: clocksource to be unregistered - */ -int clocksource_unregister(struct clocksource *cs) -{ - int ret = 0; - - mutex_lock(&clocksource_mutex); - if (!list_empty(&cs->list)) - ret = clocksource_unbind(cs); - mutex_unlock(&clocksource_mutex); - return ret; -} -EXPORT_SYMBOL(clocksource_unregister); - -#ifdef CONFIG_SYSFS -/** - * sysfs_show_current_clocksources - sysfs interface for current clocksource - * @dev: unused - * @attr: unused - * @buf: char buffer to be filled with clocksource list - * - * Provides sysfs interface for listing current clocksource. - */ -static ssize_t -sysfs_show_current_clocksources(struct device *dev, - struct device_attribute *attr, char *buf) -{ - ssize_t count = 0; - - mutex_lock(&clocksource_mutex); - count = snprintf(buf, PAGE_SIZE, "%s\n", curr_clocksource->name); - mutex_unlock(&clocksource_mutex); - - return count; -} - -ssize_t sysfs_get_uname(const char *buf, char *dst, size_t cnt) -{ - size_t ret = cnt; - - /* strings from sysfs write are not 0 terminated! */ - if (!cnt || cnt >= CS_NAME_LEN) - return -EINVAL; - - /* strip of \n: */ - if (buf[cnt-1] == '\n') - cnt--; - if (cnt > 0) - memcpy(dst, buf, cnt); - dst[cnt] = 0; - return ret; -} - -/** - * sysfs_override_clocksource - interface for manually overriding clocksource - * @dev: unused - * @attr: unused - * @buf: name of override clocksource - * @count: length of buffer - * - * Takes input from sysfs interface for manually overriding the default - * clocksource selection. - */ -static ssize_t sysfs_override_clocksource(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - ssize_t ret; - - mutex_lock(&clocksource_mutex); - - ret = sysfs_get_uname(buf, override_name, count); - if (ret >= 0) - clocksource_select(); - - mutex_unlock(&clocksource_mutex); - - return ret; -} - -/** - * sysfs_unbind_current_clocksource - interface for manually unbinding clocksource - * @dev: unused - * @attr: unused - * @buf: unused - * @count: length of buffer - * - * Takes input from sysfs interface for manually unbinding a clocksource. - */ -static ssize_t sysfs_unbind_clocksource(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct clocksource *cs; - char name[CS_NAME_LEN]; - ssize_t ret; - - ret = sysfs_get_uname(buf, name, count); - if (ret < 0) - return ret; - - ret = -ENODEV; - mutex_lock(&clocksource_mutex); - list_for_each_entry(cs, &clocksource_list, list) { - if (strcmp(cs->name, name)) - continue; - ret = clocksource_unbind(cs); - break; - } - mutex_unlock(&clocksource_mutex); - - return ret ? ret : count; -} - -/** - * sysfs_show_available_clocksources - sysfs interface for listing clocksource - * @dev: unused - * @attr: unused - * @buf: char buffer to be filled with clocksource list - * - * Provides sysfs interface for listing registered clocksources - */ -static ssize_t -sysfs_show_available_clocksources(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct clocksource *src; - ssize_t count = 0; - - mutex_lock(&clocksource_mutex); - list_for_each_entry(src, &clocksource_list, list) { - /* - * Don't show non-HRES clocksource if the tick code is - * in one shot mode (highres=on or nohz=on) - */ - if (!tick_oneshot_mode_active() || - (src->flags & CLOCK_SOURCE_VALID_FOR_HRES)) - count += snprintf(buf + count, - max((ssize_t)PAGE_SIZE - count, (ssize_t)0), - "%s ", src->name); - } - mutex_unlock(&clocksource_mutex); - - count += snprintf(buf + count, - max((ssize_t)PAGE_SIZE - count, (ssize_t)0), "\n"); - - return count; -} - -/* - * Sysfs setup bits: - */ -static DEVICE_ATTR(current_clocksource, 0644, sysfs_show_current_clocksources, - sysfs_override_clocksource); - -static DEVICE_ATTR(unbind_clocksource, 0200, NULL, sysfs_unbind_clocksource); - -static DEVICE_ATTR(available_clocksource, 0444, - sysfs_show_available_clocksources, NULL); - -static struct bus_type clocksource_subsys = { - .name = "clocksource", - .dev_name = "clocksource", -}; - -static struct device device_clocksource = { - .id = 0, - .bus = &clocksource_subsys, -}; - -static int __init init_clocksource_sysfs(void) -{ - int error = subsys_system_register(&clocksource_subsys, NULL); - - if (!error) - error = device_register(&device_clocksource); - if (!error) - error = device_create_file( - &device_clocksource, - &dev_attr_current_clocksource); - if (!error) - error = device_create_file(&device_clocksource, - &dev_attr_unbind_clocksource); - if (!error) - error = device_create_file( - &device_clocksource, - &dev_attr_available_clocksource); - return error; -} - -device_initcall(init_clocksource_sysfs); -#endif /* CONFIG_SYSFS */ - -/** - * boot_override_clocksource - boot clock override - * @str: override name - * - * Takes a clocksource= boot argument and uses it - * as the clocksource override name. - */ -static int __init boot_override_clocksource(char* str) -{ - mutex_lock(&clocksource_mutex); - if (str) - strlcpy(override_name, str, sizeof(override_name)); - mutex_unlock(&clocksource_mutex); - return 1; -} - -__setup("clocksource=", boot_override_clocksource); - -/** - * boot_override_clock - Compatibility layer for deprecated boot option - * @str: override name - * - * DEPRECATED! Takes a clock= boot argument and uses it - * as the clocksource override name - */ -static int __init boot_override_clock(char* str) -{ - if (!strcmp(str, "pmtmr")) { - pr_warn("clock=pmtmr is deprecated - use clocksource=acpi_pm\n"); - return boot_override_clocksource("acpi_pm"); - } - pr_warn("clock= boot option is deprecated - use clocksource=xyz\n"); - return boot_override_clocksource(str); -} - -__setup("clock=", boot_override_clock); diff --git a/src/linux/kernel/time/hrtimer.c b/src/linux/kernel/time/hrtimer.c deleted file mode 100644 index bb5ec42..0000000 --- a/src/linux/kernel/time/hrtimer.c +++ /dev/null @@ -1,1790 +0,0 @@ -/* - * linux/kernel/hrtimer.c - * - * Copyright(C) 2005-2006, Thomas Gleixner - * Copyright(C) 2005-2007, Red Hat, Inc., Ingo Molnar - * Copyright(C) 2006-2007 Timesys Corp., Thomas Gleixner - * - * High-resolution kernel timers - * - * In contrast to the low-resolution timeout API implemented in - * kernel/timer.c, hrtimers provide finer resolution and accuracy - * depending on system configuration and capabilities. - * - * These timers are currently used for: - * - itimers - * - POSIX timers - * - nanosleep - * - precise in-kernel timing - * - * Started by: Thomas Gleixner and Ingo Molnar - * - * Credits: - * based on kernel/timer.c - * - * Help, testing, suggestions, bugfixes, improvements were - * provided by: - * - * George Anzinger, Andrew Morton, Steven Rostedt, Roman Zippel - * et. al. - * - * For licencing details see kernel-base/COPYING - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include "tick-internal.h" - -/* - * The timer bases: - * - * There are more clockids than hrtimer bases. Thus, we index - * into the timer bases by the hrtimer_base_type enum. When trying - * to reach a base using a clockid, hrtimer_clockid_to_base() - * is used to convert from clockid to the proper hrtimer_base_type. - */ -DEFINE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases) = -{ - .lock = __RAW_SPIN_LOCK_UNLOCKED(hrtimer_bases.lock), - .seq = SEQCNT_ZERO(hrtimer_bases.seq), - .clock_base = - { - { - .index = HRTIMER_BASE_MONOTONIC, - .clockid = CLOCK_MONOTONIC, - .get_time = &ktime_get, - }, - { - .index = HRTIMER_BASE_REALTIME, - .clockid = CLOCK_REALTIME, - .get_time = &ktime_get_real, - }, - { - .index = HRTIMER_BASE_BOOTTIME, - .clockid = CLOCK_BOOTTIME, - .get_time = &ktime_get_boottime, - }, - { - .index = HRTIMER_BASE_TAI, - .clockid = CLOCK_TAI, - .get_time = &ktime_get_clocktai, - }, - } -}; - -static const int hrtimer_clock_to_base_table[MAX_CLOCKS] = { - [CLOCK_REALTIME] = HRTIMER_BASE_REALTIME, - [CLOCK_MONOTONIC] = HRTIMER_BASE_MONOTONIC, - [CLOCK_BOOTTIME] = HRTIMER_BASE_BOOTTIME, - [CLOCK_TAI] = HRTIMER_BASE_TAI, -}; - -static inline int hrtimer_clockid_to_base(clockid_t clock_id) -{ - return hrtimer_clock_to_base_table[clock_id]; -} - -/* - * Functions and macros which are different for UP/SMP systems are kept in a - * single place - */ -#ifdef CONFIG_SMP - -/* - * We require the migration_base for lock_hrtimer_base()/switch_hrtimer_base() - * such that hrtimer_callback_running() can unconditionally dereference - * timer->base->cpu_base - */ -static struct hrtimer_cpu_base migration_cpu_base = { - .seq = SEQCNT_ZERO(migration_cpu_base), - .clock_base = { { .cpu_base = &migration_cpu_base, }, }, -}; - -#define migration_base migration_cpu_base.clock_base[0] - -/* - * We are using hashed locking: holding per_cpu(hrtimer_bases)[n].lock - * means that all timers which are tied to this base via timer->base are - * locked, and the base itself is locked too. - * - * So __run_timers/migrate_timers can safely modify all timers which could - * be found on the lists/queues. - * - * When the timer's base is locked, and the timer removed from list, it is - * possible to set timer->base = &migration_base and drop the lock: the timer - * remains locked. - */ -static -struct hrtimer_clock_base *lock_hrtimer_base(const struct hrtimer *timer, - unsigned long *flags) -{ - struct hrtimer_clock_base *base; - - for (;;) { - base = timer->base; - if (likely(base != &migration_base)) { - raw_spin_lock_irqsave(&base->cpu_base->lock, *flags); - if (likely(base == timer->base)) - return base; - /* The timer has migrated to another CPU: */ - raw_spin_unlock_irqrestore(&base->cpu_base->lock, *flags); - } - cpu_relax(); - } -} - -/* - * With HIGHRES=y we do not migrate the timer when it is expiring - * before the next event on the target cpu because we cannot reprogram - * the target cpu hardware and we would cause it to fire late. - * - * Called with cpu_base->lock of target cpu held. - */ -static int -hrtimer_check_target(struct hrtimer *timer, struct hrtimer_clock_base *new_base) -{ -#ifdef CONFIG_HIGH_RES_TIMERS - ktime_t expires; - - if (!new_base->cpu_base->hres_active) - return 0; - - expires = ktime_sub(hrtimer_get_expires(timer), new_base->offset); - return expires.tv64 <= new_base->cpu_base->expires_next.tv64; -#else - return 0; -#endif -} - -#ifdef CONFIG_NO_HZ_COMMON -static inline -struct hrtimer_cpu_base *get_target_base(struct hrtimer_cpu_base *base, - int pinned) -{ - if (pinned || !base->migration_enabled) - return base; - return &per_cpu(hrtimer_bases, get_nohz_timer_target()); -} -#else -static inline -struct hrtimer_cpu_base *get_target_base(struct hrtimer_cpu_base *base, - int pinned) -{ - return base; -} -#endif - -/* - * We switch the timer base to a power-optimized selected CPU target, - * if: - * - NO_HZ_COMMON is enabled - * - timer migration is enabled - * - the timer callback is not running - * - the timer is not the first expiring timer on the new target - * - * If one of the above requirements is not fulfilled we move the timer - * to the current CPU or leave it on the previously assigned CPU if - * the timer callback is currently running. - */ -static inline struct hrtimer_clock_base * -switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base, - int pinned) -{ - struct hrtimer_cpu_base *new_cpu_base, *this_cpu_base; - struct hrtimer_clock_base *new_base; - int basenum = base->index; - - this_cpu_base = this_cpu_ptr(&hrtimer_bases); - new_cpu_base = get_target_base(this_cpu_base, pinned); -again: - new_base = &new_cpu_base->clock_base[basenum]; - - if (base != new_base) { - /* - * We are trying to move timer to new_base. - * However we can't change timer's base while it is running, - * so we keep it on the same CPU. No hassle vs. reprogramming - * the event source in the high resolution case. The softirq - * code will take care of this when the timer function has - * completed. There is no conflict as we hold the lock until - * the timer is enqueued. - */ - if (unlikely(hrtimer_callback_running(timer))) - return base; - - /* See the comment in lock_hrtimer_base() */ - timer->base = &migration_base; - raw_spin_unlock(&base->cpu_base->lock); - raw_spin_lock(&new_base->cpu_base->lock); - - if (new_cpu_base != this_cpu_base && - hrtimer_check_target(timer, new_base)) { - raw_spin_unlock(&new_base->cpu_base->lock); - raw_spin_lock(&base->cpu_base->lock); - new_cpu_base = this_cpu_base; - timer->base = base; - goto again; - } - timer->base = new_base; - } else { - if (new_cpu_base != this_cpu_base && - hrtimer_check_target(timer, new_base)) { - new_cpu_base = this_cpu_base; - goto again; - } - } - return new_base; -} - -#else /* CONFIG_SMP */ - -static inline struct hrtimer_clock_base * -lock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags) -{ - struct hrtimer_clock_base *base = timer->base; - - raw_spin_lock_irqsave(&base->cpu_base->lock, *flags); - - return base; -} - -# define switch_hrtimer_base(t, b, p) (b) - -#endif /* !CONFIG_SMP */ - -/* - * Functions for the union type storage format of ktime_t which are - * too large for inlining: - */ -#if BITS_PER_LONG < 64 -/* - * Divide a ktime value by a nanosecond value - */ -s64 __ktime_divns(const ktime_t kt, s64 div) -{ - int sft = 0; - s64 dclc; - u64 tmp; - - dclc = ktime_to_ns(kt); - tmp = dclc < 0 ? -dclc : dclc; - - /* Make sure the divisor is less than 2^32: */ - while (div >> 32) { - sft++; - div >>= 1; - } - tmp >>= sft; - do_div(tmp, (unsigned long) div); - return dclc < 0 ? -tmp : tmp; -} -EXPORT_SYMBOL_GPL(__ktime_divns); -#endif /* BITS_PER_LONG >= 64 */ - -/* - * Add two ktime values and do a safety check for overflow: - */ -ktime_t ktime_add_safe(const ktime_t lhs, const ktime_t rhs) -{ - ktime_t res = ktime_add_unsafe(lhs, rhs); - - /* - * We use KTIME_SEC_MAX here, the maximum timeout which we can - * return to user space in a timespec: - */ - if (res.tv64 < 0 || res.tv64 < lhs.tv64 || res.tv64 < rhs.tv64) - res = ktime_set(KTIME_SEC_MAX, 0); - - return res; -} - -EXPORT_SYMBOL_GPL(ktime_add_safe); - -#ifdef CONFIG_DEBUG_OBJECTS_TIMERS - -static struct debug_obj_descr hrtimer_debug_descr; - -static void *hrtimer_debug_hint(void *addr) -{ - return ((struct hrtimer *) addr)->function; -} - -/* - * fixup_init is called when: - * - an active object is initialized - */ -static bool hrtimer_fixup_init(void *addr, enum debug_obj_state state) -{ - struct hrtimer *timer = addr; - - switch (state) { - case ODEBUG_STATE_ACTIVE: - hrtimer_cancel(timer); - debug_object_init(timer, &hrtimer_debug_descr); - return true; - default: - return false; - } -} - -/* - * fixup_activate is called when: - * - an active object is activated - * - an unknown non-static object is activated - */ -static bool hrtimer_fixup_activate(void *addr, enum debug_obj_state state) -{ - switch (state) { - case ODEBUG_STATE_ACTIVE: - WARN_ON(1); - - default: - return false; - } -} - -/* - * fixup_free is called when: - * - an active object is freed - */ -static bool hrtimer_fixup_free(void *addr, enum debug_obj_state state) -{ - struct hrtimer *timer = addr; - - switch (state) { - case ODEBUG_STATE_ACTIVE: - hrtimer_cancel(timer); - debug_object_free(timer, &hrtimer_debug_descr); - return true; - default: - return false; - } -} - -static struct debug_obj_descr hrtimer_debug_descr = { - .name = "hrtimer", - .debug_hint = hrtimer_debug_hint, - .fixup_init = hrtimer_fixup_init, - .fixup_activate = hrtimer_fixup_activate, - .fixup_free = hrtimer_fixup_free, -}; - -static inline void debug_hrtimer_init(struct hrtimer *timer) -{ - debug_object_init(timer, &hrtimer_debug_descr); -} - -static inline void debug_hrtimer_activate(struct hrtimer *timer) -{ - debug_object_activate(timer, &hrtimer_debug_descr); -} - -static inline void debug_hrtimer_deactivate(struct hrtimer *timer) -{ - debug_object_deactivate(timer, &hrtimer_debug_descr); -} - -static inline void debug_hrtimer_free(struct hrtimer *timer) -{ - debug_object_free(timer, &hrtimer_debug_descr); -} - -static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id, - enum hrtimer_mode mode); - -void hrtimer_init_on_stack(struct hrtimer *timer, clockid_t clock_id, - enum hrtimer_mode mode) -{ - debug_object_init_on_stack(timer, &hrtimer_debug_descr); - __hrtimer_init(timer, clock_id, mode); -} -EXPORT_SYMBOL_GPL(hrtimer_init_on_stack); - -void destroy_hrtimer_on_stack(struct hrtimer *timer) -{ - debug_object_free(timer, &hrtimer_debug_descr); -} -EXPORT_SYMBOL_GPL(destroy_hrtimer_on_stack); - -#else -static inline void debug_hrtimer_init(struct hrtimer *timer) { } -static inline void debug_hrtimer_activate(struct hrtimer *timer) { } -static inline void debug_hrtimer_deactivate(struct hrtimer *timer) { } -#endif - -static inline void -debug_init(struct hrtimer *timer, clockid_t clockid, - enum hrtimer_mode mode) -{ - debug_hrtimer_init(timer); - trace_hrtimer_init(timer, clockid, mode); -} - -static inline void debug_activate(struct hrtimer *timer) -{ - debug_hrtimer_activate(timer); - trace_hrtimer_start(timer); -} - -static inline void debug_deactivate(struct hrtimer *timer) -{ - debug_hrtimer_deactivate(timer); - trace_hrtimer_cancel(timer); -} - -#if defined(CONFIG_NO_HZ_COMMON) || defined(CONFIG_HIGH_RES_TIMERS) -static inline void hrtimer_update_next_timer(struct hrtimer_cpu_base *cpu_base, - struct hrtimer *timer) -{ -#ifdef CONFIG_HIGH_RES_TIMERS - cpu_base->next_timer = timer; -#endif -} - -static ktime_t __hrtimer_get_next_event(struct hrtimer_cpu_base *cpu_base) -{ - struct hrtimer_clock_base *base = cpu_base->clock_base; - ktime_t expires, expires_next = { .tv64 = KTIME_MAX }; - unsigned int active = cpu_base->active_bases; - - hrtimer_update_next_timer(cpu_base, NULL); - for (; active; base++, active >>= 1) { - struct timerqueue_node *next; - struct hrtimer *timer; - - if (!(active & 0x01)) - continue; - - next = timerqueue_getnext(&base->active); - timer = container_of(next, struct hrtimer, node); - expires = ktime_sub(hrtimer_get_expires(timer), base->offset); - if (expires.tv64 < expires_next.tv64) { - expires_next = expires; - hrtimer_update_next_timer(cpu_base, timer); - } - } - /* - * clock_was_set() might have changed base->offset of any of - * the clock bases so the result might be negative. Fix it up - * to prevent a false positive in clockevents_program_event(). - */ - if (expires_next.tv64 < 0) - expires_next.tv64 = 0; - return expires_next; -} -#endif - -static inline ktime_t hrtimer_update_base(struct hrtimer_cpu_base *base) -{ - ktime_t *offs_real = &base->clock_base[HRTIMER_BASE_REALTIME].offset; - ktime_t *offs_boot = &base->clock_base[HRTIMER_BASE_BOOTTIME].offset; - ktime_t *offs_tai = &base->clock_base[HRTIMER_BASE_TAI].offset; - - return ktime_get_update_offsets_now(&base->clock_was_set_seq, - offs_real, offs_boot, offs_tai); -} - -/* High resolution timer related functions */ -#ifdef CONFIG_HIGH_RES_TIMERS - -/* - * High resolution timer enabled ? - */ -static bool hrtimer_hres_enabled __read_mostly = true; -unsigned int hrtimer_resolution __read_mostly = LOW_RES_NSEC; -EXPORT_SYMBOL_GPL(hrtimer_resolution); - -/* - * Enable / Disable high resolution mode - */ -static int __init setup_hrtimer_hres(char *str) -{ - return (kstrtobool(str, &hrtimer_hres_enabled) == 0); -} - -__setup("highres=", setup_hrtimer_hres); - -/* - * hrtimer_high_res_enabled - query, if the highres mode is enabled - */ -static inline int hrtimer_is_hres_enabled(void) -{ - return hrtimer_hres_enabled; -} - -/* - * Is the high resolution mode active ? - */ -static inline int __hrtimer_hres_active(struct hrtimer_cpu_base *cpu_base) -{ - return cpu_base->hres_active; -} - -static inline int hrtimer_hres_active(void) -{ - return __hrtimer_hres_active(this_cpu_ptr(&hrtimer_bases)); -} - -/* - * Reprogram the event source with checking both queues for the - * next event - * Called with interrupts disabled and base->lock held - */ -static void -hrtimer_force_reprogram(struct hrtimer_cpu_base *cpu_base, int skip_equal) -{ - ktime_t expires_next; - - if (!cpu_base->hres_active) - return; - - expires_next = __hrtimer_get_next_event(cpu_base); - - if (skip_equal && expires_next.tv64 == cpu_base->expires_next.tv64) - return; - - cpu_base->expires_next.tv64 = expires_next.tv64; - - /* - * If a hang was detected in the last timer interrupt then we - * leave the hang delay active in the hardware. We want the - * system to make progress. That also prevents the following - * scenario: - * T1 expires 50ms from now - * T2 expires 5s from now - * - * T1 is removed, so this code is called and would reprogram - * the hardware to 5s from now. Any hrtimer_start after that - * will not reprogram the hardware due to hang_detected being - * set. So we'd effectivly block all timers until the T2 event - * fires. - */ - if (cpu_base->hang_detected) - return; - - tick_program_event(cpu_base->expires_next, 1); -} - -/* - * When a timer is enqueued and expires earlier than the already enqueued - * timers, we have to check, whether it expires earlier than the timer for - * which the clock event device was armed. - * - * Called with interrupts disabled and base->cpu_base.lock held - */ -static void hrtimer_reprogram(struct hrtimer *timer, - struct hrtimer_clock_base *base) -{ - struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); - ktime_t expires = ktime_sub(hrtimer_get_expires(timer), base->offset); - - WARN_ON_ONCE(hrtimer_get_expires_tv64(timer) < 0); - - /* - * If the timer is not on the current cpu, we cannot reprogram - * the other cpus clock event device. - */ - if (base->cpu_base != cpu_base) - return; - - /* - * If the hrtimer interrupt is running, then it will - * reevaluate the clock bases and reprogram the clock event - * device. The callbacks are always executed in hard interrupt - * context so we don't need an extra check for a running - * callback. - */ - if (cpu_base->in_hrtirq) - return; - - /* - * CLOCK_REALTIME timer might be requested with an absolute - * expiry time which is less than base->offset. Set it to 0. - */ - if (expires.tv64 < 0) - expires.tv64 = 0; - - if (expires.tv64 >= cpu_base->expires_next.tv64) - return; - - /* Update the pointer to the next expiring timer */ - cpu_base->next_timer = timer; - - /* - * If a hang was detected in the last timer interrupt then we - * do not schedule a timer which is earlier than the expiry - * which we enforced in the hang detection. We want the system - * to make progress. - */ - if (cpu_base->hang_detected) - return; - - /* - * Program the timer hardware. We enforce the expiry for - * events which are already in the past. - */ - cpu_base->expires_next = expires; - tick_program_event(expires, 1); -} - -/* - * Initialize the high resolution related parts of cpu_base - */ -static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) -{ - base->expires_next.tv64 = KTIME_MAX; - base->hres_active = 0; -} - -/* - * Retrigger next event is called after clock was set - * - * Called with interrupts disabled via on_each_cpu() - */ -static void retrigger_next_event(void *arg) -{ - struct hrtimer_cpu_base *base = this_cpu_ptr(&hrtimer_bases); - - if (!base->hres_active) - return; - - raw_spin_lock(&base->lock); - hrtimer_update_base(base); - hrtimer_force_reprogram(base, 0); - raw_spin_unlock(&base->lock); -} - -/* - * Switch to high resolution mode - */ -static void hrtimer_switch_to_hres(void) -{ - struct hrtimer_cpu_base *base = this_cpu_ptr(&hrtimer_bases); - - if (tick_init_highres()) { - printk(KERN_WARNING "Could not switch to high resolution " - "mode on CPU %d\n", base->cpu); - return; - } - base->hres_active = 1; - hrtimer_resolution = HIGH_RES_NSEC; - - tick_setup_sched_timer(); - /* "Retrigger" the interrupt to get things going */ - retrigger_next_event(NULL); -} - -static void clock_was_set_work(struct work_struct *work) -{ - clock_was_set(); -} - -static DECLARE_WORK(hrtimer_work, clock_was_set_work); - -/* - * Called from timekeeping and resume code to reprogram the hrtimer - * interrupt device on all cpus. - */ -void clock_was_set_delayed(void) -{ - schedule_work(&hrtimer_work); -} - -#else - -static inline int __hrtimer_hres_active(struct hrtimer_cpu_base *b) { return 0; } -static inline int hrtimer_hres_active(void) { return 0; } -static inline int hrtimer_is_hres_enabled(void) { return 0; } -static inline void hrtimer_switch_to_hres(void) { } -static inline void -hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { } -static inline int hrtimer_reprogram(struct hrtimer *timer, - struct hrtimer_clock_base *base) -{ - return 0; -} -static inline void hrtimer_init_hres(struct hrtimer_cpu_base *base) { } -static inline void retrigger_next_event(void *arg) { } - -#endif /* CONFIG_HIGH_RES_TIMERS */ - -/* - * Clock realtime was set - * - * Change the offset of the realtime clock vs. the monotonic - * clock. - * - * We might have to reprogram the high resolution timer interrupt. On - * SMP we call the architecture specific code to retrigger _all_ high - * resolution timer interrupts. On UP we just disable interrupts and - * call the high resolution interrupt code. - */ -void clock_was_set(void) -{ -#ifdef CONFIG_HIGH_RES_TIMERS - /* Retrigger the CPU local events everywhere */ - on_each_cpu(retrigger_next_event, NULL, 1); -#endif - timerfd_clock_was_set(); -} - -/* - * During resume we might have to reprogram the high resolution timer - * interrupt on all online CPUs. However, all other CPUs will be - * stopped with IRQs interrupts disabled so the clock_was_set() call - * must be deferred. - */ -void hrtimers_resume(void) -{ - WARN_ONCE(!irqs_disabled(), - KERN_INFO "hrtimers_resume() called with IRQs enabled!"); - - /* Retrigger on the local CPU */ - retrigger_next_event(NULL); - /* And schedule a retrigger for all others */ - clock_was_set_delayed(); -} - -static inline void timer_stats_hrtimer_set_start_info(struct hrtimer *timer) -{ -#ifdef CONFIG_TIMER_STATS - if (timer->start_site) - return; - timer->start_site = __builtin_return_address(0); - memcpy(timer->start_comm, current->comm, TASK_COMM_LEN); - timer->start_pid = current->pid; -#endif -} - -static inline void timer_stats_hrtimer_clear_start_info(struct hrtimer *timer) -{ -#ifdef CONFIG_TIMER_STATS - timer->start_site = NULL; -#endif -} - -static inline void timer_stats_account_hrtimer(struct hrtimer *timer) -{ -#ifdef CONFIG_TIMER_STATS - if (likely(!timer_stats_active)) - return; - timer_stats_update_stats(timer, timer->start_pid, timer->start_site, - timer->function, timer->start_comm, 0); -#endif -} - -/* - * Counterpart to lock_hrtimer_base above: - */ -static inline -void unlock_hrtimer_base(const struct hrtimer *timer, unsigned long *flags) -{ - raw_spin_unlock_irqrestore(&timer->base->cpu_base->lock, *flags); -} - -/** - * hrtimer_forward - forward the timer expiry - * @timer: hrtimer to forward - * @now: forward past this time - * @interval: the interval to forward - * - * Forward the timer expiry so it will expire in the future. - * Returns the number of overruns. - * - * Can be safely called from the callback function of @timer. If - * called from other contexts @timer must neither be enqueued nor - * running the callback and the caller needs to take care of - * serialization. - * - * Note: This only updates the timer expiry value and does not requeue - * the timer. - */ -u64 hrtimer_forward(struct hrtimer *timer, ktime_t now, ktime_t interval) -{ - u64 orun = 1; - ktime_t delta; - - delta = ktime_sub(now, hrtimer_get_expires(timer)); - - if (delta.tv64 < 0) - return 0; - - if (WARN_ON(timer->state & HRTIMER_STATE_ENQUEUED)) - return 0; - - if (interval.tv64 < hrtimer_resolution) - interval.tv64 = hrtimer_resolution; - - if (unlikely(delta.tv64 >= interval.tv64)) { - s64 incr = ktime_to_ns(interval); - - orun = ktime_divns(delta, incr); - hrtimer_add_expires_ns(timer, incr * orun); - if (hrtimer_get_expires_tv64(timer) > now.tv64) - return orun; - /* - * This (and the ktime_add() below) is the - * correction for exact: - */ - orun++; - } - hrtimer_add_expires(timer, interval); - - return orun; -} -EXPORT_SYMBOL_GPL(hrtimer_forward); - -/* - * enqueue_hrtimer - internal function to (re)start a timer - * - * The timer is inserted in expiry order. Insertion into the - * red black tree is O(log(n)). Must hold the base lock. - * - * Returns 1 when the new timer is the leftmost timer in the tree. - */ -static int enqueue_hrtimer(struct hrtimer *timer, - struct hrtimer_clock_base *base) -{ - debug_activate(timer); - - base->cpu_base->active_bases |= 1 << base->index; - - timer->state = HRTIMER_STATE_ENQUEUED; - - return timerqueue_add(&base->active, &timer->node); -} - -/* - * __remove_hrtimer - internal function to remove a timer - * - * Caller must hold the base lock. - * - * High resolution timer mode reprograms the clock event device when the - * timer is the one which expires next. The caller can disable this by setting - * reprogram to zero. This is useful, when the context does a reprogramming - * anyway (e.g. timer interrupt) - */ -static void __remove_hrtimer(struct hrtimer *timer, - struct hrtimer_clock_base *base, - u8 newstate, int reprogram) -{ - struct hrtimer_cpu_base *cpu_base = base->cpu_base; - u8 state = timer->state; - - timer->state = newstate; - if (!(state & HRTIMER_STATE_ENQUEUED)) - return; - - if (!timerqueue_del(&base->active, &timer->node)) - cpu_base->active_bases &= ~(1 << base->index); - -#ifdef CONFIG_HIGH_RES_TIMERS - /* - * Note: If reprogram is false we do not update - * cpu_base->next_timer. This happens when we remove the first - * timer on a remote cpu. No harm as we never dereference - * cpu_base->next_timer. So the worst thing what can happen is - * an superflous call to hrtimer_force_reprogram() on the - * remote cpu later on if the same timer gets enqueued again. - */ - if (reprogram && timer == cpu_base->next_timer) - hrtimer_force_reprogram(cpu_base, 1); -#endif -} - -/* - * remove hrtimer, called with base lock held - */ -static inline int -remove_hrtimer(struct hrtimer *timer, struct hrtimer_clock_base *base, bool restart) -{ - if (hrtimer_is_queued(timer)) { - u8 state = timer->state; - int reprogram; - - /* - * Remove the timer and force reprogramming when high - * resolution mode is active and the timer is on the current - * CPU. If we remove a timer on another CPU, reprogramming is - * skipped. The interrupt event on this CPU is fired and - * reprogramming happens in the interrupt handler. This is a - * rare case and less expensive than a smp call. - */ - debug_deactivate(timer); - timer_stats_hrtimer_clear_start_info(timer); - reprogram = base->cpu_base == this_cpu_ptr(&hrtimer_bases); - - if (!restart) - state = HRTIMER_STATE_INACTIVE; - - __remove_hrtimer(timer, base, state, reprogram); - return 1; - } - return 0; -} - -static inline ktime_t hrtimer_update_lowres(struct hrtimer *timer, ktime_t tim, - const enum hrtimer_mode mode) -{ -#ifdef CONFIG_TIME_LOW_RES - /* - * CONFIG_TIME_LOW_RES indicates that the system has no way to return - * granular time values. For relative timers we add hrtimer_resolution - * (i.e. one jiffie) to prevent short timeouts. - */ - timer->is_rel = mode & HRTIMER_MODE_REL; - if (timer->is_rel) - tim = ktime_add_safe(tim, ktime_set(0, hrtimer_resolution)); -#endif - return tim; -} - -/** - * hrtimer_start_range_ns - (re)start an hrtimer on the current CPU - * @timer: the timer to be added - * @tim: expiry time - * @delta_ns: "slack" range for the timer - * @mode: expiry mode: absolute (HRTIMER_MODE_ABS) or - * relative (HRTIMER_MODE_REL) - */ -void hrtimer_start_range_ns(struct hrtimer *timer, ktime_t tim, - u64 delta_ns, const enum hrtimer_mode mode) -{ - struct hrtimer_clock_base *base, *new_base; - unsigned long flags; - int leftmost; - - base = lock_hrtimer_base(timer, &flags); - - /* Remove an active timer from the queue: */ - remove_hrtimer(timer, base, true); - - if (mode & HRTIMER_MODE_REL) - tim = ktime_add_safe(tim, base->get_time()); - - tim = hrtimer_update_lowres(timer, tim, mode); - - hrtimer_set_expires_range_ns(timer, tim, delta_ns); - - /* Switch the timer base, if necessary: */ - new_base = switch_hrtimer_base(timer, base, mode & HRTIMER_MODE_PINNED); - - timer_stats_hrtimer_set_start_info(timer); - - leftmost = enqueue_hrtimer(timer, new_base); - if (!leftmost) - goto unlock; - - if (!hrtimer_is_hres_active(timer)) { - /* - * Kick to reschedule the next tick to handle the new timer - * on dynticks target. - */ - if (new_base->cpu_base->nohz_active) - wake_up_nohz_cpu(new_base->cpu_base->cpu); - } else { - hrtimer_reprogram(timer, new_base); - } -unlock: - unlock_hrtimer_base(timer, &flags); -} -EXPORT_SYMBOL_GPL(hrtimer_start_range_ns); - -/** - * hrtimer_try_to_cancel - try to deactivate a timer - * @timer: hrtimer to stop - * - * Returns: - * 0 when the timer was not active - * 1 when the timer was active - * -1 when the timer is currently excuting the callback function and - * cannot be stopped - */ -int hrtimer_try_to_cancel(struct hrtimer *timer) -{ - struct hrtimer_clock_base *base; - unsigned long flags; - int ret = -1; - - /* - * Check lockless first. If the timer is not active (neither - * enqueued nor running the callback, nothing to do here. The - * base lock does not serialize against a concurrent enqueue, - * so we can avoid taking it. - */ - if (!hrtimer_active(timer)) - return 0; - - base = lock_hrtimer_base(timer, &flags); - - if (!hrtimer_callback_running(timer)) - ret = remove_hrtimer(timer, base, false); - - unlock_hrtimer_base(timer, &flags); - - return ret; - -} -EXPORT_SYMBOL_GPL(hrtimer_try_to_cancel); - -/** - * hrtimer_cancel - cancel a timer and wait for the handler to finish. - * @timer: the timer to be cancelled - * - * Returns: - * 0 when the timer was not active - * 1 when the timer was active - */ -int hrtimer_cancel(struct hrtimer *timer) -{ - for (;;) { - int ret = hrtimer_try_to_cancel(timer); - - if (ret >= 0) - return ret; - cpu_relax(); - } -} -EXPORT_SYMBOL_GPL(hrtimer_cancel); - -/** - * hrtimer_get_remaining - get remaining time for the timer - * @timer: the timer to read - * @adjust: adjust relative timers when CONFIG_TIME_LOW_RES=y - */ -ktime_t __hrtimer_get_remaining(const struct hrtimer *timer, bool adjust) -{ - unsigned long flags; - ktime_t rem; - - lock_hrtimer_base(timer, &flags); - if (IS_ENABLED(CONFIG_TIME_LOW_RES) && adjust) - rem = hrtimer_expires_remaining_adjusted(timer); - else - rem = hrtimer_expires_remaining(timer); - unlock_hrtimer_base(timer, &flags); - - return rem; -} -EXPORT_SYMBOL_GPL(__hrtimer_get_remaining); - -#ifdef CONFIG_NO_HZ_COMMON -/** - * hrtimer_get_next_event - get the time until next expiry event - * - * Returns the next expiry time or KTIME_MAX if no timer is pending. - */ -u64 hrtimer_get_next_event(void) -{ - struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); - u64 expires = KTIME_MAX; - unsigned long flags; - - raw_spin_lock_irqsave(&cpu_base->lock, flags); - - if (!__hrtimer_hres_active(cpu_base)) - expires = __hrtimer_get_next_event(cpu_base).tv64; - - raw_spin_unlock_irqrestore(&cpu_base->lock, flags); - - return expires; -} -#endif - -static void __hrtimer_init(struct hrtimer *timer, clockid_t clock_id, - enum hrtimer_mode mode) -{ - struct hrtimer_cpu_base *cpu_base; - int base; - - memset(timer, 0, sizeof(struct hrtimer)); - - cpu_base = raw_cpu_ptr(&hrtimer_bases); - - if (clock_id == CLOCK_REALTIME && mode != HRTIMER_MODE_ABS) - clock_id = CLOCK_MONOTONIC; - - base = hrtimer_clockid_to_base(clock_id); - timer->base = &cpu_base->clock_base[base]; - timerqueue_init(&timer->node); - -#ifdef CONFIG_TIMER_STATS - timer->start_site = NULL; - timer->start_pid = -1; - memset(timer->start_comm, 0, TASK_COMM_LEN); -#endif -} - -/** - * hrtimer_init - initialize a timer to the given clock - * @timer: the timer to be initialized - * @clock_id: the clock to be used - * @mode: timer mode abs/rel - */ -void hrtimer_init(struct hrtimer *timer, clockid_t clock_id, - enum hrtimer_mode mode) -{ - debug_init(timer, clock_id, mode); - __hrtimer_init(timer, clock_id, mode); -} -EXPORT_SYMBOL_GPL(hrtimer_init); - -/* - * A timer is active, when it is enqueued into the rbtree or the - * callback function is running or it's in the state of being migrated - * to another cpu. - * - * It is important for this function to not return a false negative. - */ -bool hrtimer_active(const struct hrtimer *timer) -{ - struct hrtimer_cpu_base *cpu_base; - unsigned int seq; - - do { - cpu_base = READ_ONCE(timer->base->cpu_base); - seq = raw_read_seqcount_begin(&cpu_base->seq); - - if (timer->state != HRTIMER_STATE_INACTIVE || - cpu_base->running == timer) - return true; - - } while (read_seqcount_retry(&cpu_base->seq, seq) || - cpu_base != READ_ONCE(timer->base->cpu_base)); - - return false; -} -EXPORT_SYMBOL_GPL(hrtimer_active); - -/* - * The write_seqcount_barrier()s in __run_hrtimer() split the thing into 3 - * distinct sections: - * - * - queued: the timer is queued - * - callback: the timer is being ran - * - post: the timer is inactive or (re)queued - * - * On the read side we ensure we observe timer->state and cpu_base->running - * from the same section, if anything changed while we looked at it, we retry. - * This includes timer->base changing because sequence numbers alone are - * insufficient for that. - * - * The sequence numbers are required because otherwise we could still observe - * a false negative if the read side got smeared over multiple consequtive - * __run_hrtimer() invocations. - */ - -static void __run_hrtimer(struct hrtimer_cpu_base *cpu_base, - struct hrtimer_clock_base *base, - struct hrtimer *timer, ktime_t *now) -{ - enum hrtimer_restart (*fn)(struct hrtimer *); - int restart; - - lockdep_assert_held(&cpu_base->lock); - - debug_deactivate(timer); - cpu_base->running = timer; - - /* - * Separate the ->running assignment from the ->state assignment. - * - * As with a regular write barrier, this ensures the read side in - * hrtimer_active() cannot observe cpu_base->running == NULL && - * timer->state == INACTIVE. - */ - raw_write_seqcount_barrier(&cpu_base->seq); - - __remove_hrtimer(timer, base, HRTIMER_STATE_INACTIVE, 0); - timer_stats_account_hrtimer(timer); - fn = timer->function; - - /* - * Clear the 'is relative' flag for the TIME_LOW_RES case. If the - * timer is restarted with a period then it becomes an absolute - * timer. If its not restarted it does not matter. - */ - if (IS_ENABLED(CONFIG_TIME_LOW_RES)) - timer->is_rel = false; - - /* - * Because we run timers from hardirq context, there is no chance - * they get migrated to another cpu, therefore its safe to unlock - * the timer base. - */ - raw_spin_unlock(&cpu_base->lock); - trace_hrtimer_expire_entry(timer, now); - restart = fn(timer); - trace_hrtimer_expire_exit(timer); - raw_spin_lock(&cpu_base->lock); - - /* - * Note: We clear the running state after enqueue_hrtimer and - * we do not reprogram the event hardware. Happens either in - * hrtimer_start_range_ns() or in hrtimer_interrupt() - * - * Note: Because we dropped the cpu_base->lock above, - * hrtimer_start_range_ns() can have popped in and enqueued the timer - * for us already. - */ - if (restart != HRTIMER_NORESTART && - !(timer->state & HRTIMER_STATE_ENQUEUED)) - enqueue_hrtimer(timer, base); - - /* - * Separate the ->running assignment from the ->state assignment. - * - * As with a regular write barrier, this ensures the read side in - * hrtimer_active() cannot observe cpu_base->running == NULL && - * timer->state == INACTIVE. - */ - raw_write_seqcount_barrier(&cpu_base->seq); - - WARN_ON_ONCE(cpu_base->running != timer); - cpu_base->running = NULL; -} - -static void __hrtimer_run_queues(struct hrtimer_cpu_base *cpu_base, ktime_t now) -{ - struct hrtimer_clock_base *base = cpu_base->clock_base; - unsigned int active = cpu_base->active_bases; - - for (; active; base++, active >>= 1) { - struct timerqueue_node *node; - ktime_t basenow; - - if (!(active & 0x01)) - continue; - - basenow = ktime_add(now, base->offset); - - while ((node = timerqueue_getnext(&base->active))) { - struct hrtimer *timer; - - timer = container_of(node, struct hrtimer, node); - - /* - * The immediate goal for using the softexpires is - * minimizing wakeups, not running timers at the - * earliest interrupt after their soft expiration. - * This allows us to avoid using a Priority Search - * Tree, which can answer a stabbing querry for - * overlapping intervals and instead use the simple - * BST we already have. - * We don't add extra wakeups by delaying timers that - * are right-of a not yet expired timer, because that - * timer will have to trigger a wakeup anyway. - */ - if (basenow.tv64 < hrtimer_get_softexpires_tv64(timer)) - break; - - __run_hrtimer(cpu_base, base, timer, &basenow); - } - } -} - -#ifdef CONFIG_HIGH_RES_TIMERS - -/* - * High resolution timer interrupt - * Called with interrupts disabled - */ -void hrtimer_interrupt(struct clock_event_device *dev) -{ - struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); - ktime_t expires_next, now, entry_time, delta; - int retries = 0; - - BUG_ON(!cpu_base->hres_active); - cpu_base->nr_events++; - dev->next_event.tv64 = KTIME_MAX; - - raw_spin_lock(&cpu_base->lock); - entry_time = now = hrtimer_update_base(cpu_base); -retry: - cpu_base->in_hrtirq = 1; - /* - * We set expires_next to KTIME_MAX here with cpu_base->lock - * held to prevent that a timer is enqueued in our queue via - * the migration code. This does not affect enqueueing of - * timers which run their callback and need to be requeued on - * this CPU. - */ - cpu_base->expires_next.tv64 = KTIME_MAX; - - __hrtimer_run_queues(cpu_base, now); - - /* Reevaluate the clock bases for the next expiry */ - expires_next = __hrtimer_get_next_event(cpu_base); - /* - * Store the new expiry value so the migration code can verify - * against it. - */ - cpu_base->expires_next = expires_next; - cpu_base->in_hrtirq = 0; - raw_spin_unlock(&cpu_base->lock); - - /* Reprogramming necessary ? */ - if (!tick_program_event(expires_next, 0)) { - cpu_base->hang_detected = 0; - return; - } - - /* - * The next timer was already expired due to: - * - tracing - * - long lasting callbacks - * - being scheduled away when running in a VM - * - * We need to prevent that we loop forever in the hrtimer - * interrupt routine. We give it 3 attempts to avoid - * overreacting on some spurious event. - * - * Acquire base lock for updating the offsets and retrieving - * the current time. - */ - raw_spin_lock(&cpu_base->lock); - now = hrtimer_update_base(cpu_base); - cpu_base->nr_retries++; - if (++retries < 3) - goto retry; - /* - * Give the system a chance to do something else than looping - * here. We stored the entry time, so we know exactly how long - * we spent here. We schedule the next event this amount of - * time away. - */ - cpu_base->nr_hangs++; - cpu_base->hang_detected = 1; - raw_spin_unlock(&cpu_base->lock); - delta = ktime_sub(now, entry_time); - if ((unsigned int)delta.tv64 > cpu_base->max_hang_time) - cpu_base->max_hang_time = (unsigned int) delta.tv64; - /* - * Limit it to a sensible value as we enforce a longer - * delay. Give the CPU at least 100ms to catch up. - */ - if (delta.tv64 > 100 * NSEC_PER_MSEC) - expires_next = ktime_add_ns(now, 100 * NSEC_PER_MSEC); - else - expires_next = ktime_add(now, delta); - tick_program_event(expires_next, 1); - printk_once(KERN_WARNING "hrtimer: interrupt took %llu ns\n", - ktime_to_ns(delta)); -} - -/* - * local version of hrtimer_peek_ahead_timers() called with interrupts - * disabled. - */ -static inline void __hrtimer_peek_ahead_timers(void) -{ - struct tick_device *td; - - if (!hrtimer_hres_active()) - return; - - td = this_cpu_ptr(&tick_cpu_device); - if (td && td->evtdev) - hrtimer_interrupt(td->evtdev); -} - -#else /* CONFIG_HIGH_RES_TIMERS */ - -static inline void __hrtimer_peek_ahead_timers(void) { } - -#endif /* !CONFIG_HIGH_RES_TIMERS */ - -/* - * Called from run_local_timers in hardirq context every jiffy - */ -void hrtimer_run_queues(void) -{ - struct hrtimer_cpu_base *cpu_base = this_cpu_ptr(&hrtimer_bases); - ktime_t now; - - if (__hrtimer_hres_active(cpu_base)) - return; - - /* - * This _is_ ugly: We have to check periodically, whether we - * can switch to highres and / or nohz mode. The clocksource - * switch happens with xtime_lock held. Notification from - * there only sets the check bit in the tick_oneshot code, - * otherwise we might deadlock vs. xtime_lock. - */ - if (tick_check_oneshot_change(!hrtimer_is_hres_enabled())) { - hrtimer_switch_to_hres(); - return; - } - - raw_spin_lock(&cpu_base->lock); - now = hrtimer_update_base(cpu_base); - __hrtimer_run_queues(cpu_base, now); - raw_spin_unlock(&cpu_base->lock); -} - -/* - * Sleep related functions: - */ -static enum hrtimer_restart hrtimer_wakeup(struct hrtimer *timer) -{ - struct hrtimer_sleeper *t = - container_of(timer, struct hrtimer_sleeper, timer); - struct task_struct *task = t->task; - - t->task = NULL; - if (task) - wake_up_process(task); - - return HRTIMER_NORESTART; -} - -void hrtimer_init_sleeper(struct hrtimer_sleeper *sl, struct task_struct *task) -{ - sl->timer.function = hrtimer_wakeup; - sl->task = task; -} -EXPORT_SYMBOL_GPL(hrtimer_init_sleeper); - -static int __sched do_nanosleep(struct hrtimer_sleeper *t, enum hrtimer_mode mode) -{ - hrtimer_init_sleeper(t, current); - - do { - set_current_state(TASK_INTERRUPTIBLE); - hrtimer_start_expires(&t->timer, mode); - - if (likely(t->task)) - freezable_schedule(); - - hrtimer_cancel(&t->timer); - mode = HRTIMER_MODE_ABS; - - } while (t->task && !signal_pending(current)); - - __set_current_state(TASK_RUNNING); - - return t->task == NULL; -} - -static int update_rmtp(struct hrtimer *timer, struct timespec __user *rmtp) -{ - struct timespec rmt; - ktime_t rem; - - rem = hrtimer_expires_remaining(timer); - if (rem.tv64 <= 0) - return 0; - rmt = ktime_to_timespec(rem); - - if (copy_to_user(rmtp, &rmt, sizeof(*rmtp))) - return -EFAULT; - - return 1; -} - -long __sched hrtimer_nanosleep_restart(struct restart_block *restart) -{ - struct hrtimer_sleeper t; - struct timespec __user *rmtp; - int ret = 0; - - hrtimer_init_on_stack(&t.timer, restart->nanosleep.clockid, - HRTIMER_MODE_ABS); - hrtimer_set_expires_tv64(&t.timer, restart->nanosleep.expires); - - if (do_nanosleep(&t, HRTIMER_MODE_ABS)) - goto out; - - rmtp = restart->nanosleep.rmtp; - if (rmtp) { - ret = update_rmtp(&t.timer, rmtp); - if (ret <= 0) - goto out; - } - - /* The other values in restart are already filled in */ - ret = -ERESTART_RESTARTBLOCK; -out: - destroy_hrtimer_on_stack(&t.timer); - return ret; -} - -long hrtimer_nanosleep(struct timespec *rqtp, struct timespec __user *rmtp, - const enum hrtimer_mode mode, const clockid_t clockid) -{ - struct restart_block *restart; - struct hrtimer_sleeper t; - int ret = 0; - u64 slack; - - slack = current->timer_slack_ns; - if (dl_task(current) || rt_task(current)) - slack = 0; - - hrtimer_init_on_stack(&t.timer, clockid, mode); - hrtimer_set_expires_range_ns(&t.timer, timespec_to_ktime(*rqtp), slack); - if (do_nanosleep(&t, mode)) - goto out; - - /* Absolute timers do not update the rmtp value and restart: */ - if (mode == HRTIMER_MODE_ABS) { - ret = -ERESTARTNOHAND; - goto out; - } - - if (rmtp) { - ret = update_rmtp(&t.timer, rmtp); - if (ret <= 0) - goto out; - } - - restart = ¤t->restart_block; - restart->fn = hrtimer_nanosleep_restart; - restart->nanosleep.clockid = t.timer.base->clockid; - restart->nanosleep.rmtp = rmtp; - restart->nanosleep.expires = hrtimer_get_expires_tv64(&t.timer); - - ret = -ERESTART_RESTARTBLOCK; -out: - destroy_hrtimer_on_stack(&t.timer); - return ret; -} - -SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp, - struct timespec __user *, rmtp) -{ - struct timespec tu; - - if (copy_from_user(&tu, rqtp, sizeof(tu))) - return -EFAULT; - - if (!timespec_valid(&tu)) - return -EINVAL; - - return hrtimer_nanosleep(&tu, rmtp, HRTIMER_MODE_REL, CLOCK_MONOTONIC); -} - -/* - * Functions related to boot-time initialization: - */ -int hrtimers_prepare_cpu(unsigned int cpu) -{ - struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu); - int i; - - for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { - cpu_base->clock_base[i].cpu_base = cpu_base; - timerqueue_init_head(&cpu_base->clock_base[i].active); - } - - cpu_base->cpu = cpu; - hrtimer_init_hres(cpu_base); - return 0; -} - -#ifdef CONFIG_HOTPLUG_CPU - -static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base, - struct hrtimer_clock_base *new_base) -{ - struct hrtimer *timer; - struct timerqueue_node *node; - - while ((node = timerqueue_getnext(&old_base->active))) { - timer = container_of(node, struct hrtimer, node); - BUG_ON(hrtimer_callback_running(timer)); - debug_deactivate(timer); - - /* - * Mark it as ENQUEUED not INACTIVE otherwise the - * timer could be seen as !active and just vanish away - * under us on another CPU - */ - __remove_hrtimer(timer, old_base, HRTIMER_STATE_ENQUEUED, 0); - timer->base = new_base; - /* - * Enqueue the timers on the new cpu. This does not - * reprogram the event device in case the timer - * expires before the earliest on this CPU, but we run - * hrtimer_interrupt after we migrated everything to - * sort out already expired timers and reprogram the - * event device. - */ - enqueue_hrtimer(timer, new_base); - } -} - -int hrtimers_dead_cpu(unsigned int scpu) -{ - struct hrtimer_cpu_base *old_base, *new_base; - int i; - - BUG_ON(cpu_online(scpu)); - tick_cancel_sched_timer(scpu); - - local_irq_disable(); - old_base = &per_cpu(hrtimer_bases, scpu); - new_base = this_cpu_ptr(&hrtimer_bases); - /* - * The caller is globally serialized and nobody else - * takes two locks at once, deadlock is not possible. - */ - raw_spin_lock(&new_base->lock); - raw_spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING); - - for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { - migrate_hrtimer_list(&old_base->clock_base[i], - &new_base->clock_base[i]); - } - - raw_spin_unlock(&old_base->lock); - raw_spin_unlock(&new_base->lock); - - /* Check, if we got expired work to do */ - __hrtimer_peek_ahead_timers(); - local_irq_enable(); - return 0; -} - -#endif /* CONFIG_HOTPLUG_CPU */ - -void __init hrtimers_init(void) -{ - hrtimers_prepare_cpu(smp_processor_id()); -} - -/** - * schedule_hrtimeout_range_clock - sleep until timeout - * @expires: timeout value (ktime_t) - * @delta: slack in expires timeout (ktime_t) - * @mode: timer mode, HRTIMER_MODE_ABS or HRTIMER_MODE_REL - * @clock: timer clock, CLOCK_MONOTONIC or CLOCK_REALTIME - */ -int __sched -schedule_hrtimeout_range_clock(ktime_t *expires, u64 delta, - const enum hrtimer_mode mode, int clock) -{ - struct hrtimer_sleeper t; - - /* - * Optimize when a zero timeout value is given. It does not - * matter whether this is an absolute or a relative time. - */ - if (expires && !expires->tv64) { - __set_current_state(TASK_RUNNING); - return 0; - } - - /* - * A NULL parameter means "infinite" - */ - if (!expires) { - schedule(); - return -EINTR; - } - - hrtimer_init_on_stack(&t.timer, clock, mode); - hrtimer_set_expires_range_ns(&t.timer, *expires, delta); - - hrtimer_init_sleeper(&t, current); - - hrtimer_start_expires(&t.timer, mode); - - if (likely(t.task)) - schedule(); - - hrtimer_cancel(&t.timer); - destroy_hrtimer_on_stack(&t.timer); - - __set_current_state(TASK_RUNNING); - - return !t.task ? 0 : -EINTR; -} - -/** - * schedule_hrtimeout_range - sleep until timeout - * @expires: timeout value (ktime_t) - * @delta: slack in expires timeout (ktime_t) - * @mode: timer mode, HRTIMER_MODE_ABS or HRTIMER_MODE_REL - * - * Make the current task sleep until the given expiry time has - * elapsed. The routine will return immediately unless - * the current task state has been set (see set_current_state()). - * - * The @delta argument gives the kernel the freedom to schedule the - * actual wakeup to a time that is both power and performance friendly. - * The kernel give the normal best effort behavior for "@expires+@delta", - * but may decide to fire the timer earlier, but no earlier than @expires. - * - * You can set the task state as follows - - * - * %TASK_UNINTERRUPTIBLE - at least @timeout time is guaranteed to - * pass before the routine returns. - * - * %TASK_INTERRUPTIBLE - the routine may return early if a signal is - * delivered to the current task. - * - * The current task state is guaranteed to be TASK_RUNNING when this - * routine returns. - * - * Returns 0 when the timer has expired otherwise -EINTR - */ -int __sched schedule_hrtimeout_range(ktime_t *expires, u64 delta, - const enum hrtimer_mode mode) -{ - return schedule_hrtimeout_range_clock(expires, delta, mode, - CLOCK_MONOTONIC); -} -EXPORT_SYMBOL_GPL(schedule_hrtimeout_range); - -/** - * schedule_hrtimeout - sleep until timeout - * @expires: timeout value (ktime_t) - * @mode: timer mode, HRTIMER_MODE_ABS or HRTIMER_MODE_REL - * - * Make the current task sleep until the given expiry time has - * elapsed. The routine will return immediately unless - * the current task state has been set (see set_current_state()). - * - * You can set the task state as follows - - * - * %TASK_UNINTERRUPTIBLE - at least @timeout time is guaranteed to - * pass before the routine returns. - * - * %TASK_INTERRUPTIBLE - the routine may return early if a signal is - * delivered to the current task. - * - * The current task state is guaranteed to be TASK_RUNNING when this - * routine returns. - * - * Returns 0 when the timer has expired otherwise -EINTR - */ -int __sched schedule_hrtimeout(ktime_t *expires, - const enum hrtimer_mode mode) -{ - return schedule_hrtimeout_range(expires, 0, mode); -} -EXPORT_SYMBOL_GPL(schedule_hrtimeout); diff --git a/src/linux/kernel/time/itimer.c b/src/linux/kernel/time/itimer.c deleted file mode 100644 index 1d5c720..0000000 --- a/src/linux/kernel/time/itimer.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * linux/kernel/itimer.c - * - * Copyright (C) 1992 Darren Senn - */ - -/* These are all the functions necessary to implement itimers */ - -#include -#include -#include -#include -#include -#include -#include - -#include - -/** - * itimer_get_remtime - get remaining time for the timer - * - * @timer: the timer to read - * - * Returns the delta between the expiry time and now, which can be - * less than zero or 1usec for an pending expired timer - */ -static struct timeval itimer_get_remtime(struct hrtimer *timer) -{ - ktime_t rem = __hrtimer_get_remaining(timer, true); - - /* - * Racy but safe: if the itimer expires after the above - * hrtimer_get_remtime() call but before this condition - * then we return 0 - which is correct. - */ - if (hrtimer_active(timer)) { - if (rem.tv64 <= 0) - rem.tv64 = NSEC_PER_USEC; - } else - rem.tv64 = 0; - - return ktime_to_timeval(rem); -} - -static void get_cpu_itimer(struct task_struct *tsk, unsigned int clock_id, - struct itimerval *const value) -{ - cputime_t cval, cinterval; - struct cpu_itimer *it = &tsk->signal->it[clock_id]; - - spin_lock_irq(&tsk->sighand->siglock); - - cval = it->expires; - cinterval = it->incr; - if (cval) { - struct task_cputime cputime; - cputime_t t; - - thread_group_cputimer(tsk, &cputime); - if (clock_id == CPUCLOCK_PROF) - t = cputime.utime + cputime.stime; - else - /* CPUCLOCK_VIRT */ - t = cputime.utime; - - if (cval < t) - /* about to fire */ - cval = cputime_one_jiffy; - else - cval = cval - t; - } - - spin_unlock_irq(&tsk->sighand->siglock); - - cputime_to_timeval(cval, &value->it_value); - cputime_to_timeval(cinterval, &value->it_interval); -} - -int do_getitimer(int which, struct itimerval *value) -{ - struct task_struct *tsk = current; - - switch (which) { - case ITIMER_REAL: - spin_lock_irq(&tsk->sighand->siglock); - value->it_value = itimer_get_remtime(&tsk->signal->real_timer); - value->it_interval = - ktime_to_timeval(tsk->signal->it_real_incr); - spin_unlock_irq(&tsk->sighand->siglock); - break; - case ITIMER_VIRTUAL: - get_cpu_itimer(tsk, CPUCLOCK_VIRT, value); - break; - case ITIMER_PROF: - get_cpu_itimer(tsk, CPUCLOCK_PROF, value); - break; - default: - return(-EINVAL); - } - return 0; -} - -SYSCALL_DEFINE2(getitimer, int, which, struct itimerval __user *, value) -{ - int error = -EFAULT; - struct itimerval get_buffer; - - if (value) { - error = do_getitimer(which, &get_buffer); - if (!error && - copy_to_user(value, &get_buffer, sizeof(get_buffer))) - error = -EFAULT; - } - return error; -} - - -/* - * The timer is automagically restarted, when interval != 0 - */ -enum hrtimer_restart it_real_fn(struct hrtimer *timer) -{ - struct signal_struct *sig = - container_of(timer, struct signal_struct, real_timer); - - trace_itimer_expire(ITIMER_REAL, sig->leader_pid, 0); - kill_pid_info(SIGALRM, SEND_SIG_PRIV, sig->leader_pid); - - return HRTIMER_NORESTART; -} - -static inline u32 cputime_sub_ns(cputime_t ct, s64 real_ns) -{ - struct timespec ts; - s64 cpu_ns; - - cputime_to_timespec(ct, &ts); - cpu_ns = timespec_to_ns(&ts); - - return (cpu_ns <= real_ns) ? 0 : cpu_ns - real_ns; -} - -static void set_cpu_itimer(struct task_struct *tsk, unsigned int clock_id, - const struct itimerval *const value, - struct itimerval *const ovalue) -{ - cputime_t cval, nval, cinterval, ninterval; - s64 ns_ninterval, ns_nval; - u32 error, incr_error; - struct cpu_itimer *it = &tsk->signal->it[clock_id]; - - nval = timeval_to_cputime(&value->it_value); - ns_nval = timeval_to_ns(&value->it_value); - ninterval = timeval_to_cputime(&value->it_interval); - ns_ninterval = timeval_to_ns(&value->it_interval); - - error = cputime_sub_ns(nval, ns_nval); - incr_error = cputime_sub_ns(ninterval, ns_ninterval); - - spin_lock_irq(&tsk->sighand->siglock); - - cval = it->expires; - cinterval = it->incr; - if (cval || nval) { - if (nval > 0) - nval += cputime_one_jiffy; - set_process_cpu_timer(tsk, clock_id, &nval, &cval); - } - it->expires = nval; - it->incr = ninterval; - it->error = error; - it->incr_error = incr_error; - trace_itimer_state(clock_id == CPUCLOCK_VIRT ? - ITIMER_VIRTUAL : ITIMER_PROF, value, nval); - - spin_unlock_irq(&tsk->sighand->siglock); - - if (ovalue) { - cputime_to_timeval(cval, &ovalue->it_value); - cputime_to_timeval(cinterval, &ovalue->it_interval); - } -} - -/* - * Returns true if the timeval is in canonical form - */ -#define timeval_valid(t) \ - (((t)->tv_sec >= 0) && (((unsigned long) (t)->tv_usec) < USEC_PER_SEC)) - -int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) -{ - struct task_struct *tsk = current; - struct hrtimer *timer; - ktime_t expires; - - /* - * Validate the timevals in value. - */ - if (!timeval_valid(&value->it_value) || - !timeval_valid(&value->it_interval)) - return -EINVAL; - - switch (which) { - case ITIMER_REAL: -again: - spin_lock_irq(&tsk->sighand->siglock); - timer = &tsk->signal->real_timer; - if (ovalue) { - ovalue->it_value = itimer_get_remtime(timer); - ovalue->it_interval - = ktime_to_timeval(tsk->signal->it_real_incr); - } - /* We are sharing ->siglock with it_real_fn() */ - if (hrtimer_try_to_cancel(timer) < 0) { - spin_unlock_irq(&tsk->sighand->siglock); - goto again; - } - expires = timeval_to_ktime(value->it_value); - if (expires.tv64 != 0) { - tsk->signal->it_real_incr = - timeval_to_ktime(value->it_interval); - hrtimer_start(timer, expires, HRTIMER_MODE_REL); - } else - tsk->signal->it_real_incr.tv64 = 0; - - trace_itimer_state(ITIMER_REAL, value, 0); - spin_unlock_irq(&tsk->sighand->siglock); - break; - case ITIMER_VIRTUAL: - set_cpu_itimer(tsk, CPUCLOCK_VIRT, value, ovalue); - break; - case ITIMER_PROF: - set_cpu_itimer(tsk, CPUCLOCK_PROF, value, ovalue); - break; - default: - return -EINVAL; - } - return 0; -} - -/** - * alarm_setitimer - set alarm in seconds - * - * @seconds: number of seconds until alarm - * 0 disables the alarm - * - * Returns the remaining time in seconds of a pending timer or 0 when - * the timer is not active. - * - * On 32 bit machines the seconds value is limited to (INT_MAX/2) to avoid - * negative timeval settings which would cause immediate expiry. - */ -unsigned int alarm_setitimer(unsigned int seconds) -{ - struct itimerval it_new, it_old; - -#if BITS_PER_LONG < 64 - if (seconds > INT_MAX) - seconds = INT_MAX; -#endif - it_new.it_value.tv_sec = seconds; - it_new.it_value.tv_usec = 0; - it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0; - - do_setitimer(ITIMER_REAL, &it_new, &it_old); - - /* - * We can't return 0 if we have an alarm pending ... And we'd - * better return too much than too little anyway - */ - if ((!it_old.it_value.tv_sec && it_old.it_value.tv_usec) || - it_old.it_value.tv_usec >= 500000) - it_old.it_value.tv_sec++; - - return it_old.it_value.tv_sec; -} - -SYSCALL_DEFINE3(setitimer, int, which, struct itimerval __user *, value, - struct itimerval __user *, ovalue) -{ - struct itimerval set_buffer, get_buffer; - int error; - - if (value) { - if(copy_from_user(&set_buffer, value, sizeof(set_buffer))) - return -EFAULT; - } else { - memset(&set_buffer, 0, sizeof(set_buffer)); - printk_once(KERN_WARNING "%s calls setitimer() with new_value NULL pointer." - " Misfeature support will be removed\n", - current->comm); - } - - error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : NULL); - if (error || !ovalue) - return error; - - if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer))) - return -EFAULT; - return 0; -} diff --git a/src/linux/kernel/time/jiffies.c b/src/linux/kernel/time/jiffies.c deleted file mode 100644 index 555e21f..0000000 --- a/src/linux/kernel/time/jiffies.c +++ /dev/null @@ -1,136 +0,0 @@ -/*********************************************************************** -* linux/kernel/time/jiffies.c -* -* This file contains the jiffies based clocksource. -* -* Copyright (C) 2004, 2005 IBM, John Stultz (johnstul@us.ibm.com) -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -* -************************************************************************/ -#include -#include -#include -#include - -#include "timekeeping.h" - -/* The Jiffies based clocksource is the lowest common - * denominator clock source which should function on - * all systems. It has the same coarse resolution as - * the timer interrupt frequency HZ and it suffers - * inaccuracies caused by missed or lost timer - * interrupts and the inability for the timer - * interrupt hardware to accuratly tick at the - * requested HZ value. It is also not recommended - * for "tick-less" systems. - */ -#define NSEC_PER_JIFFY ((NSEC_PER_SEC+HZ/2)/HZ) - -/* Since jiffies uses a simple NSEC_PER_JIFFY multiplier - * conversion, the .shift value could be zero. However - * this would make NTP adjustments impossible as they are - * in units of 1/2^.shift. Thus we use JIFFIES_SHIFT to - * shift both the nominator and denominator the same - * amount, and give ntp adjustments in units of 1/2^8 - * - * The value 8 is somewhat carefully chosen, as anything - * larger can result in overflows. NSEC_PER_JIFFY grows as - * HZ shrinks, so values greater than 8 overflow 32bits when - * HZ=100. - */ -#if HZ < 34 -#define JIFFIES_SHIFT 6 -#elif HZ < 67 -#define JIFFIES_SHIFT 7 -#else -#define JIFFIES_SHIFT 8 -#endif - -static cycle_t jiffies_read(struct clocksource *cs) -{ - return (cycle_t) jiffies; -} - -static struct clocksource clocksource_jiffies = { - .name = "jiffies", - .rating = 1, /* lowest valid rating*/ - .read = jiffies_read, - .mask = CLOCKSOURCE_MASK(32), - .mult = NSEC_PER_JIFFY << JIFFIES_SHIFT, /* details above */ - .shift = JIFFIES_SHIFT, - .max_cycles = 10, -}; - -__cacheline_aligned_in_smp DEFINE_SEQLOCK(jiffies_lock); - -#if (BITS_PER_LONG < 64) -u64 get_jiffies_64(void) -{ - unsigned long seq; - u64 ret; - - do { - seq = read_seqbegin(&jiffies_lock); - ret = jiffies_64; - } while (read_seqretry(&jiffies_lock, seq)); - return ret; -} -EXPORT_SYMBOL(get_jiffies_64); -#endif - -EXPORT_SYMBOL(jiffies); - -static int __init init_jiffies_clocksource(void) -{ - return __clocksource_register(&clocksource_jiffies); -} - -core_initcall(init_jiffies_clocksource); - -struct clocksource * __init __weak clocksource_default_clock(void) -{ - return &clocksource_jiffies; -} - -struct clocksource refined_jiffies; - -int register_refined_jiffies(long cycles_per_second) -{ - u64 nsec_per_tick, shift_hz; - long cycles_per_tick; - - - - refined_jiffies = clocksource_jiffies; - refined_jiffies.name = "refined-jiffies"; - refined_jiffies.rating++; - - /* Calc cycles per tick */ - cycles_per_tick = (cycles_per_second + HZ/2)/HZ; - /* shift_hz stores hz<<8 for extra accuracy */ - shift_hz = (u64)cycles_per_second << 8; - shift_hz += cycles_per_tick/2; - do_div(shift_hz, cycles_per_tick); - /* Calculate nsec_per_tick using shift_hz */ - nsec_per_tick = (u64)NSEC_PER_SEC << 8; - nsec_per_tick += (u32)shift_hz/2; - do_div(nsec_per_tick, (u32)shift_hz); - - refined_jiffies.mult = ((u32)nsec_per_tick) << JIFFIES_SHIFT; - - __clocksource_register(&refined_jiffies); - return 0; -} diff --git a/src/linux/kernel/time/ntp.c b/src/linux/kernel/time/ntp.c deleted file mode 100644 index 6df8927..0000000 --- a/src/linux/kernel/time/ntp.c +++ /dev/null @@ -1,1039 +0,0 @@ -/* - * NTP state machine interfaces and logic. - * - * This code was mainly moved from kernel/timer.c and kernel/time.c - * Please see those files for relevant copyright info and historical - * changelogs. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ntp_internal.h" -#include "timekeeping_internal.h" - - -/* - * NTP timekeeping variables: - * - * Note: All of the NTP state is protected by the timekeeping locks. - */ - - -/* USER_HZ period (usecs): */ -unsigned long tick_usec = TICK_USEC; - -/* SHIFTED_HZ period (nsecs): */ -unsigned long tick_nsec; - -static u64 tick_length; -static u64 tick_length_base; - -#define SECS_PER_DAY 86400 -#define MAX_TICKADJ 500LL /* usecs */ -#define MAX_TICKADJ_SCALED \ - (((MAX_TICKADJ * NSEC_PER_USEC) << NTP_SCALE_SHIFT) / NTP_INTERVAL_FREQ) - -/* - * phase-lock loop variables - */ - -/* - * clock synchronization status - * - * (TIME_ERROR prevents overwriting the CMOS clock) - */ -static int time_state = TIME_OK; - -/* clock status bits: */ -static int time_status = STA_UNSYNC; - -/* time adjustment (nsecs): */ -static s64 time_offset; - -/* pll time constant: */ -static long time_constant = 2; - -/* maximum error (usecs): */ -static long time_maxerror = NTP_PHASE_LIMIT; - -/* estimated error (usecs): */ -static long time_esterror = NTP_PHASE_LIMIT; - -/* frequency offset (scaled nsecs/secs): */ -static s64 time_freq; - -/* time at last adjustment (secs): */ -static time64_t time_reftime; - -static long time_adjust; - -/* constant (boot-param configurable) NTP tick adjustment (upscaled) */ -static s64 ntp_tick_adj; - -/* second value of the next pending leapsecond, or TIME64_MAX if no leap */ -static time64_t ntp_next_leap_sec = TIME64_MAX; - -#ifdef CONFIG_NTP_PPS - -/* - * The following variables are used when a pulse-per-second (PPS) signal - * is available. They establish the engineering parameters of the clock - * discipline loop when controlled by the PPS signal. - */ -#define PPS_VALID 10 /* PPS signal watchdog max (s) */ -#define PPS_POPCORN 4 /* popcorn spike threshold (shift) */ -#define PPS_INTMIN 2 /* min freq interval (s) (shift) */ -#define PPS_INTMAX 8 /* max freq interval (s) (shift) */ -#define PPS_INTCOUNT 4 /* number of consecutive good intervals to - increase pps_shift or consecutive bad - intervals to decrease it */ -#define PPS_MAXWANDER 100000 /* max PPS freq wander (ns/s) */ - -static int pps_valid; /* signal watchdog counter */ -static long pps_tf[3]; /* phase median filter */ -static long pps_jitter; /* current jitter (ns) */ -static struct timespec64 pps_fbase; /* beginning of the last freq interval */ -static int pps_shift; /* current interval duration (s) (shift) */ -static int pps_intcnt; /* interval counter */ -static s64 pps_freq; /* frequency offset (scaled ns/s) */ -static long pps_stabil; /* current stability (scaled ns/s) */ - -/* - * PPS signal quality monitors - */ -static long pps_calcnt; /* calibration intervals */ -static long pps_jitcnt; /* jitter limit exceeded */ -static long pps_stbcnt; /* stability limit exceeded */ -static long pps_errcnt; /* calibration errors */ - - -/* PPS kernel consumer compensates the whole phase error immediately. - * Otherwise, reduce the offset by a fixed factor times the time constant. - */ -static inline s64 ntp_offset_chunk(s64 offset) -{ - if (time_status & STA_PPSTIME && time_status & STA_PPSSIGNAL) - return offset; - else - return shift_right(offset, SHIFT_PLL + time_constant); -} - -static inline void pps_reset_freq_interval(void) -{ - /* the PPS calibration interval may end - surprisingly early */ - pps_shift = PPS_INTMIN; - pps_intcnt = 0; -} - -/** - * pps_clear - Clears the PPS state variables - */ -static inline void pps_clear(void) -{ - pps_reset_freq_interval(); - pps_tf[0] = 0; - pps_tf[1] = 0; - pps_tf[2] = 0; - pps_fbase.tv_sec = pps_fbase.tv_nsec = 0; - pps_freq = 0; -} - -/* Decrease pps_valid to indicate that another second has passed since - * the last PPS signal. When it reaches 0, indicate that PPS signal is - * missing. - */ -static inline void pps_dec_valid(void) -{ - if (pps_valid > 0) - pps_valid--; - else { - time_status &= ~(STA_PPSSIGNAL | STA_PPSJITTER | - STA_PPSWANDER | STA_PPSERROR); - pps_clear(); - } -} - -static inline void pps_set_freq(s64 freq) -{ - pps_freq = freq; -} - -static inline int is_error_status(int status) -{ - return (status & (STA_UNSYNC|STA_CLOCKERR)) - /* PPS signal lost when either PPS time or - * PPS frequency synchronization requested - */ - || ((status & (STA_PPSFREQ|STA_PPSTIME)) - && !(status & STA_PPSSIGNAL)) - /* PPS jitter exceeded when - * PPS time synchronization requested */ - || ((status & (STA_PPSTIME|STA_PPSJITTER)) - == (STA_PPSTIME|STA_PPSJITTER)) - /* PPS wander exceeded or calibration error when - * PPS frequency synchronization requested - */ - || ((status & STA_PPSFREQ) - && (status & (STA_PPSWANDER|STA_PPSERROR))); -} - -static inline void pps_fill_timex(struct timex *txc) -{ - txc->ppsfreq = shift_right((pps_freq >> PPM_SCALE_INV_SHIFT) * - PPM_SCALE_INV, NTP_SCALE_SHIFT); - txc->jitter = pps_jitter; - if (!(time_status & STA_NANO)) - txc->jitter /= NSEC_PER_USEC; - txc->shift = pps_shift; - txc->stabil = pps_stabil; - txc->jitcnt = pps_jitcnt; - txc->calcnt = pps_calcnt; - txc->errcnt = pps_errcnt; - txc->stbcnt = pps_stbcnt; -} - -#else /* !CONFIG_NTP_PPS */ - -static inline s64 ntp_offset_chunk(s64 offset) -{ - return shift_right(offset, SHIFT_PLL + time_constant); -} - -static inline void pps_reset_freq_interval(void) {} -static inline void pps_clear(void) {} -static inline void pps_dec_valid(void) {} -static inline void pps_set_freq(s64 freq) {} - -static inline int is_error_status(int status) -{ - return status & (STA_UNSYNC|STA_CLOCKERR); -} - -static inline void pps_fill_timex(struct timex *txc) -{ - /* PPS is not implemented, so these are zero */ - txc->ppsfreq = 0; - txc->jitter = 0; - txc->shift = 0; - txc->stabil = 0; - txc->jitcnt = 0; - txc->calcnt = 0; - txc->errcnt = 0; - txc->stbcnt = 0; -} - -#endif /* CONFIG_NTP_PPS */ - - -/** - * ntp_synced - Returns 1 if the NTP status is not UNSYNC - * - */ -static inline int ntp_synced(void) -{ - return !(time_status & STA_UNSYNC); -} - - -/* - * NTP methods: - */ - -/* - * Update (tick_length, tick_length_base, tick_nsec), based - * on (tick_usec, ntp_tick_adj, time_freq): - */ -static void ntp_update_frequency(void) -{ - u64 second_length; - u64 new_base; - - second_length = (u64)(tick_usec * NSEC_PER_USEC * USER_HZ) - << NTP_SCALE_SHIFT; - - second_length += ntp_tick_adj; - second_length += time_freq; - - tick_nsec = div_u64(second_length, HZ) >> NTP_SCALE_SHIFT; - new_base = div_u64(second_length, NTP_INTERVAL_FREQ); - - /* - * Don't wait for the next second_overflow, apply - * the change to the tick length immediately: - */ - tick_length += new_base - tick_length_base; - tick_length_base = new_base; -} - -static inline s64 ntp_update_offset_fll(s64 offset64, long secs) -{ - time_status &= ~STA_MODE; - - if (secs < MINSEC) - return 0; - - if (!(time_status & STA_FLL) && (secs <= MAXSEC)) - return 0; - - time_status |= STA_MODE; - - return div64_long(offset64 << (NTP_SCALE_SHIFT - SHIFT_FLL), secs); -} - -static void ntp_update_offset(long offset) -{ - s64 freq_adj; - s64 offset64; - long secs; - - if (!(time_status & STA_PLL)) - return; - - if (!(time_status & STA_NANO)) { - /* Make sure the multiplication below won't overflow */ - offset = clamp(offset, -USEC_PER_SEC, USEC_PER_SEC); - offset *= NSEC_PER_USEC; - } - - /* - * Scale the phase adjustment and - * clamp to the operating range. - */ - offset = clamp(offset, -MAXPHASE, MAXPHASE); - - /* - * Select how the frequency is to be controlled - * and in which mode (PLL or FLL). - */ - secs = (long)(__ktime_get_real_seconds() - time_reftime); - if (unlikely(time_status & STA_FREQHOLD)) - secs = 0; - - time_reftime = __ktime_get_real_seconds(); - - offset64 = offset; - freq_adj = ntp_update_offset_fll(offset64, secs); - - /* - * Clamp update interval to reduce PLL gain with low - * sampling rate (e.g. intermittent network connection) - * to avoid instability. - */ - if (unlikely(secs > 1 << (SHIFT_PLL + 1 + time_constant))) - secs = 1 << (SHIFT_PLL + 1 + time_constant); - - freq_adj += (offset64 * secs) << - (NTP_SCALE_SHIFT - 2 * (SHIFT_PLL + 2 + time_constant)); - - freq_adj = min(freq_adj + time_freq, MAXFREQ_SCALED); - - time_freq = max(freq_adj, -MAXFREQ_SCALED); - - time_offset = div_s64(offset64 << NTP_SCALE_SHIFT, NTP_INTERVAL_FREQ); -} - -/** - * ntp_clear - Clears the NTP state variables - */ -void ntp_clear(void) -{ - time_adjust = 0; /* stop active adjtime() */ - time_status |= STA_UNSYNC; - time_maxerror = NTP_PHASE_LIMIT; - time_esterror = NTP_PHASE_LIMIT; - - ntp_update_frequency(); - - tick_length = tick_length_base; - time_offset = 0; - - ntp_next_leap_sec = TIME64_MAX; - /* Clear PPS state variables */ - pps_clear(); -} - - -u64 ntp_tick_length(void) -{ - return tick_length; -} - -/** - * ntp_get_next_leap - Returns the next leapsecond in CLOCK_REALTIME ktime_t - * - * Provides the time of the next leapsecond against CLOCK_REALTIME in - * a ktime_t format. Returns KTIME_MAX if no leapsecond is pending. - */ -ktime_t ntp_get_next_leap(void) -{ - ktime_t ret; - - if ((time_state == TIME_INS) && (time_status & STA_INS)) - return ktime_set(ntp_next_leap_sec, 0); - ret.tv64 = KTIME_MAX; - return ret; -} - -/* - * this routine handles the overflow of the microsecond field - * - * The tricky bits of code to handle the accurate clock support - * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame. - * They were originally developed for SUN and DEC kernels. - * All the kudos should go to Dave for this stuff. - * - * Also handles leap second processing, and returns leap offset - */ -int second_overflow(time64_t secs) -{ - s64 delta; - int leap = 0; - s32 rem; - - /* - * Leap second processing. If in leap-insert state at the end of the - * day, the system clock is set back one second; if in leap-delete - * state, the system clock is set ahead one second. - */ - switch (time_state) { - case TIME_OK: - if (time_status & STA_INS) { - time_state = TIME_INS; - div_s64_rem(secs, SECS_PER_DAY, &rem); - ntp_next_leap_sec = secs + SECS_PER_DAY - rem; - } else if (time_status & STA_DEL) { - time_state = TIME_DEL; - div_s64_rem(secs + 1, SECS_PER_DAY, &rem); - ntp_next_leap_sec = secs + SECS_PER_DAY - rem; - } - break; - case TIME_INS: - if (!(time_status & STA_INS)) { - ntp_next_leap_sec = TIME64_MAX; - time_state = TIME_OK; - } else if (secs == ntp_next_leap_sec) { - leap = -1; - time_state = TIME_OOP; - printk(KERN_NOTICE - "Clock: inserting leap second 23:59:60 UTC\n"); - } - break; - case TIME_DEL: - if (!(time_status & STA_DEL)) { - ntp_next_leap_sec = TIME64_MAX; - time_state = TIME_OK; - } else if (secs == ntp_next_leap_sec) { - leap = 1; - ntp_next_leap_sec = TIME64_MAX; - time_state = TIME_WAIT; - printk(KERN_NOTICE - "Clock: deleting leap second 23:59:59 UTC\n"); - } - break; - case TIME_OOP: - ntp_next_leap_sec = TIME64_MAX; - time_state = TIME_WAIT; - break; - case TIME_WAIT: - if (!(time_status & (STA_INS | STA_DEL))) - time_state = TIME_OK; - break; - } - - - /* Bump the maxerror field */ - time_maxerror += MAXFREQ / NSEC_PER_USEC; - if (time_maxerror > NTP_PHASE_LIMIT) { - time_maxerror = NTP_PHASE_LIMIT; - time_status |= STA_UNSYNC; - } - - /* Compute the phase adjustment for the next second */ - tick_length = tick_length_base; - - delta = ntp_offset_chunk(time_offset); - time_offset -= delta; - tick_length += delta; - - /* Check PPS signal */ - pps_dec_valid(); - - if (!time_adjust) - goto out; - - if (time_adjust > MAX_TICKADJ) { - time_adjust -= MAX_TICKADJ; - tick_length += MAX_TICKADJ_SCALED; - goto out; - } - - if (time_adjust < -MAX_TICKADJ) { - time_adjust += MAX_TICKADJ; - tick_length -= MAX_TICKADJ_SCALED; - goto out; - } - - tick_length += (s64)(time_adjust * NSEC_PER_USEC / NTP_INTERVAL_FREQ) - << NTP_SCALE_SHIFT; - time_adjust = 0; - -out: - return leap; -} - -#ifdef CONFIG_GENERIC_CMOS_UPDATE -int __weak update_persistent_clock(struct timespec now) -{ - return -ENODEV; -} - -int __weak update_persistent_clock64(struct timespec64 now64) -{ - struct timespec now; - - now = timespec64_to_timespec(now64); - return update_persistent_clock(now); -} -#endif - -#if defined(CONFIG_GENERIC_CMOS_UPDATE) || defined(CONFIG_RTC_SYSTOHC) -static void sync_cmos_clock(struct work_struct *work); - -static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock); - -static void sync_cmos_clock(struct work_struct *work) -{ - struct timespec64 now; - struct timespec64 next; - int fail = 1; - - /* - * If we have an externally synchronized Linux clock, then update - * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be - * called as close as possible to 500 ms before the new second starts. - * This code is run on a timer. If the clock is set, that timer - * may not expire at the correct time. Thus, we adjust... - * We want the clock to be within a couple of ticks from the target. - */ - if (!ntp_synced()) { - /* - * Not synced, exit, do not restart a timer (if one is - * running, let it run out). - */ - return; - } - - getnstimeofday64(&now); - if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec * 5) { - struct timespec64 adjust = now; - - fail = -ENODEV; - if (persistent_clock_is_local) - adjust.tv_sec -= (sys_tz.tz_minuteswest * 60); -#ifdef CONFIG_GENERIC_CMOS_UPDATE - fail = update_persistent_clock64(adjust); -#endif - -#ifdef CONFIG_RTC_SYSTOHC - if (fail == -ENODEV) - fail = rtc_set_ntp_time(adjust); -#endif - } - - next.tv_nsec = (NSEC_PER_SEC / 2) - now.tv_nsec - (TICK_NSEC / 2); - if (next.tv_nsec <= 0) - next.tv_nsec += NSEC_PER_SEC; - - if (!fail || fail == -ENODEV) - next.tv_sec = 659; - else - next.tv_sec = 0; - - if (next.tv_nsec >= NSEC_PER_SEC) { - next.tv_sec++; - next.tv_nsec -= NSEC_PER_SEC; - } - queue_delayed_work(system_power_efficient_wq, - &sync_cmos_work, timespec64_to_jiffies(&next)); -} - -void ntp_notify_cmos_timer(void) -{ - queue_delayed_work(system_power_efficient_wq, &sync_cmos_work, 0); -} - -#else -void ntp_notify_cmos_timer(void) { } -#endif - - -/* - * Propagate a new txc->status value into the NTP state: - */ -static inline void process_adj_status(struct timex *txc, struct timespec64 *ts) -{ - if ((time_status & STA_PLL) && !(txc->status & STA_PLL)) { - time_state = TIME_OK; - time_status = STA_UNSYNC; - ntp_next_leap_sec = TIME64_MAX; - /* restart PPS frequency calibration */ - pps_reset_freq_interval(); - } - - /* - * If we turn on PLL adjustments then reset the - * reference time to current time. - */ - if (!(time_status & STA_PLL) && (txc->status & STA_PLL)) - time_reftime = __ktime_get_real_seconds(); - - /* only set allowed bits */ - time_status &= STA_RONLY; - time_status |= txc->status & ~STA_RONLY; -} - - -static inline void process_adjtimex_modes(struct timex *txc, - struct timespec64 *ts, - s32 *time_tai) -{ - if (txc->modes & ADJ_STATUS) - process_adj_status(txc, ts); - - if (txc->modes & ADJ_NANO) - time_status |= STA_NANO; - - if (txc->modes & ADJ_MICRO) - time_status &= ~STA_NANO; - - if (txc->modes & ADJ_FREQUENCY) { - time_freq = txc->freq * PPM_SCALE; - time_freq = min(time_freq, MAXFREQ_SCALED); - time_freq = max(time_freq, -MAXFREQ_SCALED); - /* update pps_freq */ - pps_set_freq(time_freq); - } - - if (txc->modes & ADJ_MAXERROR) - time_maxerror = txc->maxerror; - - if (txc->modes & ADJ_ESTERROR) - time_esterror = txc->esterror; - - if (txc->modes & ADJ_TIMECONST) { - time_constant = txc->constant; - if (!(time_status & STA_NANO)) - time_constant += 4; - time_constant = min(time_constant, (long)MAXTC); - time_constant = max(time_constant, 0l); - } - - if (txc->modes & ADJ_TAI && txc->constant > 0) - *time_tai = txc->constant; - - if (txc->modes & ADJ_OFFSET) - ntp_update_offset(txc->offset); - - if (txc->modes & ADJ_TICK) - tick_usec = txc->tick; - - if (txc->modes & (ADJ_TICK|ADJ_FREQUENCY|ADJ_OFFSET)) - ntp_update_frequency(); -} - - - -/** - * ntp_validate_timex - Ensures the timex is ok for use in do_adjtimex - */ -int ntp_validate_timex(struct timex *txc) -{ - if (txc->modes & ADJ_ADJTIME) { - /* singleshot must not be used with any other mode bits */ - if (!(txc->modes & ADJ_OFFSET_SINGLESHOT)) - return -EINVAL; - if (!(txc->modes & ADJ_OFFSET_READONLY) && - !capable(CAP_SYS_TIME)) - return -EPERM; - } else { - /* In order to modify anything, you gotta be super-user! */ - if (txc->modes && !capable(CAP_SYS_TIME)) - return -EPERM; - /* - * if the quartz is off by more than 10% then - * something is VERY wrong! - */ - if (txc->modes & ADJ_TICK && - (txc->tick < 900000/USER_HZ || - txc->tick > 1100000/USER_HZ)) - return -EINVAL; - } - - if (txc->modes & ADJ_SETOFFSET) { - /* In order to inject time, you gotta be super-user! */ - if (!capable(CAP_SYS_TIME)) - return -EPERM; - - if (txc->modes & ADJ_NANO) { - struct timespec ts; - - ts.tv_sec = txc->time.tv_sec; - ts.tv_nsec = txc->time.tv_usec; - if (!timespec_inject_offset_valid(&ts)) - return -EINVAL; - - } else { - if (!timeval_inject_offset_valid(&txc->time)) - return -EINVAL; - } - } - - /* - * Check for potential multiplication overflows that can - * only happen on 64-bit systems: - */ - if ((txc->modes & ADJ_FREQUENCY) && (BITS_PER_LONG == 64)) { - if (LLONG_MIN / PPM_SCALE > txc->freq) - return -EINVAL; - if (LLONG_MAX / PPM_SCALE < txc->freq) - return -EINVAL; - } - - return 0; -} - - -/* - * adjtimex mainly allows reading (and writing, if superuser) of - * kernel time-keeping variables. used by xntpd. - */ -int __do_adjtimex(struct timex *txc, struct timespec64 *ts, s32 *time_tai) -{ - int result; - - if (txc->modes & ADJ_ADJTIME) { - long save_adjust = time_adjust; - - if (!(txc->modes & ADJ_OFFSET_READONLY)) { - /* adjtime() is independent from ntp_adjtime() */ - time_adjust = txc->offset; - ntp_update_frequency(); - } - txc->offset = save_adjust; - } else { - - /* If there are input parameters, then process them: */ - if (txc->modes) - process_adjtimex_modes(txc, ts, time_tai); - - txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ, - NTP_SCALE_SHIFT); - if (!(time_status & STA_NANO)) - txc->offset /= NSEC_PER_USEC; - } - - result = time_state; /* mostly `TIME_OK' */ - /* check for errors */ - if (is_error_status(time_status)) - result = TIME_ERROR; - - txc->freq = shift_right((time_freq >> PPM_SCALE_INV_SHIFT) * - PPM_SCALE_INV, NTP_SCALE_SHIFT); - txc->maxerror = time_maxerror; - txc->esterror = time_esterror; - txc->status = time_status; - txc->constant = time_constant; - txc->precision = 1; - txc->tolerance = MAXFREQ_SCALED / PPM_SCALE; - txc->tick = tick_usec; - txc->tai = *time_tai; - - /* fill PPS status fields */ - pps_fill_timex(txc); - - txc->time.tv_sec = (time_t)ts->tv_sec; - txc->time.tv_usec = ts->tv_nsec; - if (!(time_status & STA_NANO)) - txc->time.tv_usec /= NSEC_PER_USEC; - - /* Handle leapsec adjustments */ - if (unlikely(ts->tv_sec >= ntp_next_leap_sec)) { - if ((time_state == TIME_INS) && (time_status & STA_INS)) { - result = TIME_OOP; - txc->tai++; - txc->time.tv_sec--; - } - if ((time_state == TIME_DEL) && (time_status & STA_DEL)) { - result = TIME_WAIT; - txc->tai--; - txc->time.tv_sec++; - } - if ((time_state == TIME_OOP) && - (ts->tv_sec == ntp_next_leap_sec)) { - result = TIME_WAIT; - } - } - - return result; -} - -#ifdef CONFIG_NTP_PPS - -/* actually struct pps_normtime is good old struct timespec, but it is - * semantically different (and it is the reason why it was invented): - * pps_normtime.nsec has a range of ( -NSEC_PER_SEC / 2, NSEC_PER_SEC / 2 ] - * while timespec.tv_nsec has a range of [0, NSEC_PER_SEC) */ -struct pps_normtime { - s64 sec; /* seconds */ - long nsec; /* nanoseconds */ -}; - -/* normalize the timestamp so that nsec is in the - ( -NSEC_PER_SEC / 2, NSEC_PER_SEC / 2 ] interval */ -static inline struct pps_normtime pps_normalize_ts(struct timespec64 ts) -{ - struct pps_normtime norm = { - .sec = ts.tv_sec, - .nsec = ts.tv_nsec - }; - - if (norm.nsec > (NSEC_PER_SEC >> 1)) { - norm.nsec -= NSEC_PER_SEC; - norm.sec++; - } - - return norm; -} - -/* get current phase correction and jitter */ -static inline long pps_phase_filter_get(long *jitter) -{ - *jitter = pps_tf[0] - pps_tf[1]; - if (*jitter < 0) - *jitter = -*jitter; - - /* TODO: test various filters */ - return pps_tf[0]; -} - -/* add the sample to the phase filter */ -static inline void pps_phase_filter_add(long err) -{ - pps_tf[2] = pps_tf[1]; - pps_tf[1] = pps_tf[0]; - pps_tf[0] = err; -} - -/* decrease frequency calibration interval length. - * It is halved after four consecutive unstable intervals. - */ -static inline void pps_dec_freq_interval(void) -{ - if (--pps_intcnt <= -PPS_INTCOUNT) { - pps_intcnt = -PPS_INTCOUNT; - if (pps_shift > PPS_INTMIN) { - pps_shift--; - pps_intcnt = 0; - } - } -} - -/* increase frequency calibration interval length. - * It is doubled after four consecutive stable intervals. - */ -static inline void pps_inc_freq_interval(void) -{ - if (++pps_intcnt >= PPS_INTCOUNT) { - pps_intcnt = PPS_INTCOUNT; - if (pps_shift < PPS_INTMAX) { - pps_shift++; - pps_intcnt = 0; - } - } -} - -/* update clock frequency based on MONOTONIC_RAW clock PPS signal - * timestamps - * - * At the end of the calibration interval the difference between the - * first and last MONOTONIC_RAW clock timestamps divided by the length - * of the interval becomes the frequency update. If the interval was - * too long, the data are discarded. - * Returns the difference between old and new frequency values. - */ -static long hardpps_update_freq(struct pps_normtime freq_norm) -{ - long delta, delta_mod; - s64 ftemp; - - /* check if the frequency interval was too long */ - if (freq_norm.sec > (2 << pps_shift)) { - time_status |= STA_PPSERROR; - pps_errcnt++; - pps_dec_freq_interval(); - printk_deferred(KERN_ERR - "hardpps: PPSERROR: interval too long - %lld s\n", - freq_norm.sec); - return 0; - } - - /* here the raw frequency offset and wander (stability) is - * calculated. If the wander is less than the wander threshold - * the interval is increased; otherwise it is decreased. - */ - ftemp = div_s64(((s64)(-freq_norm.nsec)) << NTP_SCALE_SHIFT, - freq_norm.sec); - delta = shift_right(ftemp - pps_freq, NTP_SCALE_SHIFT); - pps_freq = ftemp; - if (delta > PPS_MAXWANDER || delta < -PPS_MAXWANDER) { - printk_deferred(KERN_WARNING - "hardpps: PPSWANDER: change=%ld\n", delta); - time_status |= STA_PPSWANDER; - pps_stbcnt++; - pps_dec_freq_interval(); - } else { /* good sample */ - pps_inc_freq_interval(); - } - - /* the stability metric is calculated as the average of recent - * frequency changes, but is used only for performance - * monitoring - */ - delta_mod = delta; - if (delta_mod < 0) - delta_mod = -delta_mod; - pps_stabil += (div_s64(((s64)delta_mod) << - (NTP_SCALE_SHIFT - SHIFT_USEC), - NSEC_PER_USEC) - pps_stabil) >> PPS_INTMIN; - - /* if enabled, the system clock frequency is updated */ - if ((time_status & STA_PPSFREQ) != 0 && - (time_status & STA_FREQHOLD) == 0) { - time_freq = pps_freq; - ntp_update_frequency(); - } - - return delta; -} - -/* correct REALTIME clock phase error against PPS signal */ -static void hardpps_update_phase(long error) -{ - long correction = -error; - long jitter; - - /* add the sample to the median filter */ - pps_phase_filter_add(correction); - correction = pps_phase_filter_get(&jitter); - - /* Nominal jitter is due to PPS signal noise. If it exceeds the - * threshold, the sample is discarded; otherwise, if so enabled, - * the time offset is updated. - */ - if (jitter > (pps_jitter << PPS_POPCORN)) { - printk_deferred(KERN_WARNING - "hardpps: PPSJITTER: jitter=%ld, limit=%ld\n", - jitter, (pps_jitter << PPS_POPCORN)); - time_status |= STA_PPSJITTER; - pps_jitcnt++; - } else if (time_status & STA_PPSTIME) { - /* correct the time using the phase offset */ - time_offset = div_s64(((s64)correction) << NTP_SCALE_SHIFT, - NTP_INTERVAL_FREQ); - /* cancel running adjtime() */ - time_adjust = 0; - } - /* update jitter */ - pps_jitter += (jitter - pps_jitter) >> PPS_INTMIN; -} - -/* - * __hardpps() - discipline CPU clock oscillator to external PPS signal - * - * This routine is called at each PPS signal arrival in order to - * discipline the CPU clock oscillator to the PPS signal. It takes two - * parameters: REALTIME and MONOTONIC_RAW clock timestamps. The former - * is used to correct clock phase error and the latter is used to - * correct the frequency. - * - * This code is based on David Mills's reference nanokernel - * implementation. It was mostly rewritten but keeps the same idea. - */ -void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_ts) -{ - struct pps_normtime pts_norm, freq_norm; - - pts_norm = pps_normalize_ts(*phase_ts); - - /* clear the error bits, they will be set again if needed */ - time_status &= ~(STA_PPSJITTER | STA_PPSWANDER | STA_PPSERROR); - - /* indicate signal presence */ - time_status |= STA_PPSSIGNAL; - pps_valid = PPS_VALID; - - /* when called for the first time, - * just start the frequency interval */ - if (unlikely(pps_fbase.tv_sec == 0)) { - pps_fbase = *raw_ts; - return; - } - - /* ok, now we have a base for frequency calculation */ - freq_norm = pps_normalize_ts(timespec64_sub(*raw_ts, pps_fbase)); - - /* check that the signal is in the range - * [1s - MAXFREQ us, 1s + MAXFREQ us], otherwise reject it */ - if ((freq_norm.sec == 0) || - (freq_norm.nsec > MAXFREQ * freq_norm.sec) || - (freq_norm.nsec < -MAXFREQ * freq_norm.sec)) { - time_status |= STA_PPSJITTER; - /* restart the frequency calibration interval */ - pps_fbase = *raw_ts; - printk_deferred(KERN_ERR "hardpps: PPSJITTER: bad pulse\n"); - return; - } - - /* signal is ok */ - - /* check if the current frequency interval is finished */ - if (freq_norm.sec >= (1 << pps_shift)) { - pps_calcnt++; - /* restart the frequency calibration interval */ - pps_fbase = *raw_ts; - hardpps_update_freq(freq_norm); - } - - hardpps_update_phase(pts_norm.nsec); - -} -#endif /* CONFIG_NTP_PPS */ - -static int __init ntp_tick_adj_setup(char *str) -{ - int rc = kstrtol(str, 0, (long *)&ntp_tick_adj); - - if (rc) - return rc; - ntp_tick_adj <<= NTP_SCALE_SHIFT; - - return 1; -} - -__setup("ntp_tick_adj=", ntp_tick_adj_setup); - -void __init ntp_init(void) -{ - ntp_clear(); -} diff --git a/src/linux/kernel/time/ntp_internal.h b/src/linux/kernel/time/ntp_internal.h deleted file mode 100644 index d8a7c11..0000000 --- a/src/linux/kernel/time/ntp_internal.h +++ /dev/null @@ -1,13 +0,0 @@ -#ifndef _LINUX_NTP_INTERNAL_H -#define _LINUX_NTP_INTERNAL_H - -extern void ntp_init(void); -extern void ntp_clear(void); -/* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */ -extern u64 ntp_tick_length(void); -extern ktime_t ntp_get_next_leap(void); -extern int second_overflow(time64_t secs); -extern int ntp_validate_timex(struct timex *); -extern int __do_adjtimex(struct timex *, struct timespec64 *, s32 *); -extern void __hardpps(const struct timespec64 *, const struct timespec64 *); -#endif /* _LINUX_NTP_INTERNAL_H */ diff --git a/src/linux/kernel/time/posix-clock.c b/src/linux/kernel/time/posix-clock.c deleted file mode 100644 index 9cff0ab..0000000 --- a/src/linux/kernel/time/posix-clock.c +++ /dev/null @@ -1,446 +0,0 @@ -/* - * posix-clock.c - support for dynamic clock devices - * - * Copyright (C) 2010 OMICRON electronics GmbH - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ -#include -#include -#include -#include -#include -#include -#include - -static void delete_clock(struct kref *kref); - -/* - * Returns NULL if the posix_clock instance attached to 'fp' is old and stale. - */ -static struct posix_clock *get_posix_clock(struct file *fp) -{ - struct posix_clock *clk = fp->private_data; - - down_read(&clk->rwsem); - - if (!clk->zombie) - return clk; - - up_read(&clk->rwsem); - - return NULL; -} - -static void put_posix_clock(struct posix_clock *clk) -{ - up_read(&clk->rwsem); -} - -static ssize_t posix_clock_read(struct file *fp, char __user *buf, - size_t count, loff_t *ppos) -{ - struct posix_clock *clk = get_posix_clock(fp); - int err = -EINVAL; - - if (!clk) - return -ENODEV; - - if (clk->ops.read) - err = clk->ops.read(clk, fp->f_flags, buf, count); - - put_posix_clock(clk); - - return err; -} - -static unsigned int posix_clock_poll(struct file *fp, poll_table *wait) -{ - struct posix_clock *clk = get_posix_clock(fp); - unsigned int result = 0; - - if (!clk) - return POLLERR; - - if (clk->ops.poll) - result = clk->ops.poll(clk, fp, wait); - - put_posix_clock(clk); - - return result; -} - -static int posix_clock_fasync(int fd, struct file *fp, int on) -{ - struct posix_clock *clk = get_posix_clock(fp); - int err = 0; - - if (!clk) - return -ENODEV; - - if (clk->ops.fasync) - err = clk->ops.fasync(clk, fd, fp, on); - - put_posix_clock(clk); - - return err; -} - -static int posix_clock_mmap(struct file *fp, struct vm_area_struct *vma) -{ - struct posix_clock *clk = get_posix_clock(fp); - int err = -ENODEV; - - if (!clk) - return -ENODEV; - - if (clk->ops.mmap) - err = clk->ops.mmap(clk, vma); - - put_posix_clock(clk); - - return err; -} - -static long posix_clock_ioctl(struct file *fp, - unsigned int cmd, unsigned long arg) -{ - struct posix_clock *clk = get_posix_clock(fp); - int err = -ENOTTY; - - if (!clk) - return -ENODEV; - - if (clk->ops.ioctl) - err = clk->ops.ioctl(clk, cmd, arg); - - put_posix_clock(clk); - - return err; -} - -#ifdef CONFIG_COMPAT -static long posix_clock_compat_ioctl(struct file *fp, - unsigned int cmd, unsigned long arg) -{ - struct posix_clock *clk = get_posix_clock(fp); - int err = -ENOTTY; - - if (!clk) - return -ENODEV; - - if (clk->ops.ioctl) - err = clk->ops.ioctl(clk, cmd, arg); - - put_posix_clock(clk); - - return err; -} -#endif - -static int posix_clock_open(struct inode *inode, struct file *fp) -{ - int err; - struct posix_clock *clk = - container_of(inode->i_cdev, struct posix_clock, cdev); - - down_read(&clk->rwsem); - - if (clk->zombie) { - err = -ENODEV; - goto out; - } - if (clk->ops.open) - err = clk->ops.open(clk, fp->f_mode); - else - err = 0; - - if (!err) { - kref_get(&clk->kref); - fp->private_data = clk; - } -out: - up_read(&clk->rwsem); - return err; -} - -static int posix_clock_release(struct inode *inode, struct file *fp) -{ - struct posix_clock *clk = fp->private_data; - int err = 0; - - if (clk->ops.release) - err = clk->ops.release(clk); - - kref_put(&clk->kref, delete_clock); - - fp->private_data = NULL; - - return err; -} - -static const struct file_operations posix_clock_file_operations = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read = posix_clock_read, - .poll = posix_clock_poll, - .unlocked_ioctl = posix_clock_ioctl, - .open = posix_clock_open, - .release = posix_clock_release, - .fasync = posix_clock_fasync, - .mmap = posix_clock_mmap, -#ifdef CONFIG_COMPAT - .compat_ioctl = posix_clock_compat_ioctl, -#endif -}; - -int posix_clock_register(struct posix_clock *clk, dev_t devid) -{ - int err; - - kref_init(&clk->kref); - init_rwsem(&clk->rwsem); - - cdev_init(&clk->cdev, &posix_clock_file_operations); - clk->cdev.owner = clk->ops.owner; - err = cdev_add(&clk->cdev, devid, 1); - - return err; -} -EXPORT_SYMBOL_GPL(posix_clock_register); - -static void delete_clock(struct kref *kref) -{ - struct posix_clock *clk = container_of(kref, struct posix_clock, kref); - - if (clk->release) - clk->release(clk); -} - -void posix_clock_unregister(struct posix_clock *clk) -{ - cdev_del(&clk->cdev); - - down_write(&clk->rwsem); - clk->zombie = true; - up_write(&clk->rwsem); - - kref_put(&clk->kref, delete_clock); -} -EXPORT_SYMBOL_GPL(posix_clock_unregister); - -struct posix_clock_desc { - struct file *fp; - struct posix_clock *clk; -}; - -static int get_clock_desc(const clockid_t id, struct posix_clock_desc *cd) -{ - struct file *fp = fget(CLOCKID_TO_FD(id)); - int err = -EINVAL; - - if (!fp) - return err; - - if (fp->f_op->open != posix_clock_open || !fp->private_data) - goto out; - - cd->fp = fp; - cd->clk = get_posix_clock(fp); - - err = cd->clk ? 0 : -ENODEV; -out: - if (err) - fput(fp); - return err; -} - -static void put_clock_desc(struct posix_clock_desc *cd) -{ - put_posix_clock(cd->clk); - fput(cd->fp); -} - -static int pc_clock_adjtime(clockid_t id, struct timex *tx) -{ - struct posix_clock_desc cd; - int err; - - err = get_clock_desc(id, &cd); - if (err) - return err; - - if ((cd.fp->f_mode & FMODE_WRITE) == 0) { - err = -EACCES; - goto out; - } - - if (cd.clk->ops.clock_adjtime) - err = cd.clk->ops.clock_adjtime(cd.clk, tx); - else - err = -EOPNOTSUPP; -out: - put_clock_desc(&cd); - - return err; -} - -static int pc_clock_gettime(clockid_t id, struct timespec *ts) -{ - struct posix_clock_desc cd; - int err; - - err = get_clock_desc(id, &cd); - if (err) - return err; - - if (cd.clk->ops.clock_gettime) - err = cd.clk->ops.clock_gettime(cd.clk, ts); - else - err = -EOPNOTSUPP; - - put_clock_desc(&cd); - - return err; -} - -static int pc_clock_getres(clockid_t id, struct timespec *ts) -{ - struct posix_clock_desc cd; - int err; - - err = get_clock_desc(id, &cd); - if (err) - return err; - - if (cd.clk->ops.clock_getres) - err = cd.clk->ops.clock_getres(cd.clk, ts); - else - err = -EOPNOTSUPP; - - put_clock_desc(&cd); - - return err; -} - -static int pc_clock_settime(clockid_t id, const struct timespec *ts) -{ - struct posix_clock_desc cd; - int err; - - err = get_clock_desc(id, &cd); - if (err) - return err; - - if ((cd.fp->f_mode & FMODE_WRITE) == 0) { - err = -EACCES; - goto out; - } - - if (cd.clk->ops.clock_settime) - err = cd.clk->ops.clock_settime(cd.clk, ts); - else - err = -EOPNOTSUPP; -out: - put_clock_desc(&cd); - - return err; -} - -static int pc_timer_create(struct k_itimer *kit) -{ - clockid_t id = kit->it_clock; - struct posix_clock_desc cd; - int err; - - err = get_clock_desc(id, &cd); - if (err) - return err; - - if (cd.clk->ops.timer_create) - err = cd.clk->ops.timer_create(cd.clk, kit); - else - err = -EOPNOTSUPP; - - put_clock_desc(&cd); - - return err; -} - -static int pc_timer_delete(struct k_itimer *kit) -{ - clockid_t id = kit->it_clock; - struct posix_clock_desc cd; - int err; - - err = get_clock_desc(id, &cd); - if (err) - return err; - - if (cd.clk->ops.timer_delete) - err = cd.clk->ops.timer_delete(cd.clk, kit); - else - err = -EOPNOTSUPP; - - put_clock_desc(&cd); - - return err; -} - -static void pc_timer_gettime(struct k_itimer *kit, struct itimerspec *ts) -{ - clockid_t id = kit->it_clock; - struct posix_clock_desc cd; - - if (get_clock_desc(id, &cd)) - return; - - if (cd.clk->ops.timer_gettime) - cd.clk->ops.timer_gettime(cd.clk, kit, ts); - - put_clock_desc(&cd); -} - -static int pc_timer_settime(struct k_itimer *kit, int flags, - struct itimerspec *ts, struct itimerspec *old) -{ - clockid_t id = kit->it_clock; - struct posix_clock_desc cd; - int err; - - err = get_clock_desc(id, &cd); - if (err) - return err; - - if (cd.clk->ops.timer_settime) - err = cd.clk->ops.timer_settime(cd.clk, kit, flags, ts, old); - else - err = -EOPNOTSUPP; - - put_clock_desc(&cd); - - return err; -} - -struct k_clock clock_posix_dynamic = { - .clock_getres = pc_clock_getres, - .clock_set = pc_clock_settime, - .clock_get = pc_clock_gettime, - .clock_adj = pc_clock_adjtime, - .timer_create = pc_timer_create, - .timer_set = pc_timer_settime, - .timer_del = pc_timer_delete, - .timer_get = pc_timer_gettime, -}; diff --git a/src/linux/kernel/time/posix-cpu-timers.c b/src/linux/kernel/time/posix-cpu-timers.c deleted file mode 100644 index 39008d7..0000000 --- a/src/linux/kernel/time/posix-cpu-timers.c +++ /dev/null @@ -1,1494 +0,0 @@ -/* - * Implement CPU time clocks for the POSIX clock interface. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Called after updating RLIMIT_CPU to run cpu timer and update - * tsk->signal->cputime_expires expiration cache if necessary. Needs - * siglock protection since other code may update expiration cache as - * well. - */ -void update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new) -{ - cputime_t cputime = secs_to_cputime(rlim_new); - - spin_lock_irq(&task->sighand->siglock); - set_process_cpu_timer(task, CPUCLOCK_PROF, &cputime, NULL); - spin_unlock_irq(&task->sighand->siglock); -} - -static int check_clock(const clockid_t which_clock) -{ - int error = 0; - struct task_struct *p; - const pid_t pid = CPUCLOCK_PID(which_clock); - - if (CPUCLOCK_WHICH(which_clock) >= CPUCLOCK_MAX) - return -EINVAL; - - if (pid == 0) - return 0; - - rcu_read_lock(); - p = find_task_by_vpid(pid); - if (!p || !(CPUCLOCK_PERTHREAD(which_clock) ? - same_thread_group(p, current) : has_group_leader_pid(p))) { - error = -EINVAL; - } - rcu_read_unlock(); - - return error; -} - -static inline unsigned long long -timespec_to_sample(const clockid_t which_clock, const struct timespec *tp) -{ - unsigned long long ret; - - ret = 0; /* high half always zero when .cpu used */ - if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) { - ret = (unsigned long long)tp->tv_sec * NSEC_PER_SEC + tp->tv_nsec; - } else { - ret = cputime_to_expires(timespec_to_cputime(tp)); - } - return ret; -} - -static void sample_to_timespec(const clockid_t which_clock, - unsigned long long expires, - struct timespec *tp) -{ - if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) - *tp = ns_to_timespec(expires); - else - cputime_to_timespec((__force cputime_t)expires, tp); -} - -/* - * Update expiry time from increment, and increase overrun count, - * given the current clock sample. - */ -static void bump_cpu_timer(struct k_itimer *timer, - unsigned long long now) -{ - int i; - unsigned long long delta, incr; - - if (timer->it.cpu.incr == 0) - return; - - if (now < timer->it.cpu.expires) - return; - - incr = timer->it.cpu.incr; - delta = now + incr - timer->it.cpu.expires; - - /* Don't use (incr*2 < delta), incr*2 might overflow. */ - for (i = 0; incr < delta - incr; i++) - incr = incr << 1; - - for (; i >= 0; incr >>= 1, i--) { - if (delta < incr) - continue; - - timer->it.cpu.expires += incr; - timer->it_overrun += 1 << i; - delta -= incr; - } -} - -/** - * task_cputime_zero - Check a task_cputime struct for all zero fields. - * - * @cputime: The struct to compare. - * - * Checks @cputime to see if all fields are zero. Returns true if all fields - * are zero, false if any field is nonzero. - */ -static inline int task_cputime_zero(const struct task_cputime *cputime) -{ - if (!cputime->utime && !cputime->stime && !cputime->sum_exec_runtime) - return 1; - return 0; -} - -static inline unsigned long long prof_ticks(struct task_struct *p) -{ - cputime_t utime, stime; - - task_cputime(p, &utime, &stime); - - return cputime_to_expires(utime + stime); -} -static inline unsigned long long virt_ticks(struct task_struct *p) -{ - cputime_t utime; - - task_cputime(p, &utime, NULL); - - return cputime_to_expires(utime); -} - -static int -posix_cpu_clock_getres(const clockid_t which_clock, struct timespec *tp) -{ - int error = check_clock(which_clock); - if (!error) { - tp->tv_sec = 0; - tp->tv_nsec = ((NSEC_PER_SEC + HZ - 1) / HZ); - if (CPUCLOCK_WHICH(which_clock) == CPUCLOCK_SCHED) { - /* - * If sched_clock is using a cycle counter, we - * don't have any idea of its true resolution - * exported, but it is much more than 1s/HZ. - */ - tp->tv_nsec = 1; - } - } - return error; -} - -static int -posix_cpu_clock_set(const clockid_t which_clock, const struct timespec *tp) -{ - /* - * You can never reset a CPU clock, but we check for other errors - * in the call before failing with EPERM. - */ - int error = check_clock(which_clock); - if (error == 0) { - error = -EPERM; - } - return error; -} - - -/* - * Sample a per-thread clock for the given task. - */ -static int cpu_clock_sample(const clockid_t which_clock, struct task_struct *p, - unsigned long long *sample) -{ - switch (CPUCLOCK_WHICH(which_clock)) { - default: - return -EINVAL; - case CPUCLOCK_PROF: - *sample = prof_ticks(p); - break; - case CPUCLOCK_VIRT: - *sample = virt_ticks(p); - break; - case CPUCLOCK_SCHED: - *sample = task_sched_runtime(p); - break; - } - return 0; -} - -/* - * Set cputime to sum_cputime if sum_cputime > cputime. Use cmpxchg - * to avoid race conditions with concurrent updates to cputime. - */ -static inline void __update_gt_cputime(atomic64_t *cputime, u64 sum_cputime) -{ - u64 curr_cputime; -retry: - curr_cputime = atomic64_read(cputime); - if (sum_cputime > curr_cputime) { - if (atomic64_cmpxchg(cputime, curr_cputime, sum_cputime) != curr_cputime) - goto retry; - } -} - -static void update_gt_cputime(struct task_cputime_atomic *cputime_atomic, struct task_cputime *sum) -{ - __update_gt_cputime(&cputime_atomic->utime, sum->utime); - __update_gt_cputime(&cputime_atomic->stime, sum->stime); - __update_gt_cputime(&cputime_atomic->sum_exec_runtime, sum->sum_exec_runtime); -} - -/* Sample task_cputime_atomic values in "atomic_timers", store results in "times". */ -static inline void sample_cputime_atomic(struct task_cputime *times, - struct task_cputime_atomic *atomic_times) -{ - times->utime = atomic64_read(&atomic_times->utime); - times->stime = atomic64_read(&atomic_times->stime); - times->sum_exec_runtime = atomic64_read(&atomic_times->sum_exec_runtime); -} - -void thread_group_cputimer(struct task_struct *tsk, struct task_cputime *times) -{ - struct thread_group_cputimer *cputimer = &tsk->signal->cputimer; - struct task_cputime sum; - - /* Check if cputimer isn't running. This is accessed without locking. */ - if (!READ_ONCE(cputimer->running)) { - /* - * The POSIX timer interface allows for absolute time expiry - * values through the TIMER_ABSTIME flag, therefore we have - * to synchronize the timer to the clock every time we start it. - */ - thread_group_cputime(tsk, &sum); - update_gt_cputime(&cputimer->cputime_atomic, &sum); - - /* - * We're setting cputimer->running without a lock. Ensure - * this only gets written to in one operation. We set - * running after update_gt_cputime() as a small optimization, - * but barriers are not required because update_gt_cputime() - * can handle concurrent updates. - */ - WRITE_ONCE(cputimer->running, true); - } - sample_cputime_atomic(times, &cputimer->cputime_atomic); -} - -/* - * Sample a process (thread group) clock for the given group_leader task. - * Must be called with task sighand lock held for safe while_each_thread() - * traversal. - */ -static int cpu_clock_sample_group(const clockid_t which_clock, - struct task_struct *p, - unsigned long long *sample) -{ - struct task_cputime cputime; - - switch (CPUCLOCK_WHICH(which_clock)) { - default: - return -EINVAL; - case CPUCLOCK_PROF: - thread_group_cputime(p, &cputime); - *sample = cputime_to_expires(cputime.utime + cputime.stime); - break; - case CPUCLOCK_VIRT: - thread_group_cputime(p, &cputime); - *sample = cputime_to_expires(cputime.utime); - break; - case CPUCLOCK_SCHED: - thread_group_cputime(p, &cputime); - *sample = cputime.sum_exec_runtime; - break; - } - return 0; -} - -static int posix_cpu_clock_get_task(struct task_struct *tsk, - const clockid_t which_clock, - struct timespec *tp) -{ - int err = -EINVAL; - unsigned long long rtn; - - if (CPUCLOCK_PERTHREAD(which_clock)) { - if (same_thread_group(tsk, current)) - err = cpu_clock_sample(which_clock, tsk, &rtn); - } else { - if (tsk == current || thread_group_leader(tsk)) - err = cpu_clock_sample_group(which_clock, tsk, &rtn); - } - - if (!err) - sample_to_timespec(which_clock, rtn, tp); - - return err; -} - - -static int posix_cpu_clock_get(const clockid_t which_clock, struct timespec *tp) -{ - const pid_t pid = CPUCLOCK_PID(which_clock); - int err = -EINVAL; - - if (pid == 0) { - /* - * Special case constant value for our own clocks. - * We don't have to do any lookup to find ourselves. - */ - err = posix_cpu_clock_get_task(current, which_clock, tp); - } else { - /* - * Find the given PID, and validate that the caller - * should be able to see it. - */ - struct task_struct *p; - rcu_read_lock(); - p = find_task_by_vpid(pid); - if (p) - err = posix_cpu_clock_get_task(p, which_clock, tp); - rcu_read_unlock(); - } - - return err; -} - -/* - * Validate the clockid_t for a new CPU-clock timer, and initialize the timer. - * This is called from sys_timer_create() and do_cpu_nanosleep() with the - * new timer already all-zeros initialized. - */ -static int posix_cpu_timer_create(struct k_itimer *new_timer) -{ - int ret = 0; - const pid_t pid = CPUCLOCK_PID(new_timer->it_clock); - struct task_struct *p; - - if (CPUCLOCK_WHICH(new_timer->it_clock) >= CPUCLOCK_MAX) - return -EINVAL; - - INIT_LIST_HEAD(&new_timer->it.cpu.entry); - - rcu_read_lock(); - if (CPUCLOCK_PERTHREAD(new_timer->it_clock)) { - if (pid == 0) { - p = current; - } else { - p = find_task_by_vpid(pid); - if (p && !same_thread_group(p, current)) - p = NULL; - } - } else { - if (pid == 0) { - p = current->group_leader; - } else { - p = find_task_by_vpid(pid); - if (p && !has_group_leader_pid(p)) - p = NULL; - } - } - new_timer->it.cpu.task = p; - if (p) { - get_task_struct(p); - } else { - ret = -EINVAL; - } - rcu_read_unlock(); - - return ret; -} - -/* - * Clean up a CPU-clock timer that is about to be destroyed. - * This is called from timer deletion with the timer already locked. - * If we return TIMER_RETRY, it's necessary to release the timer's lock - * and try again. (This happens when the timer is in the middle of firing.) - */ -static int posix_cpu_timer_del(struct k_itimer *timer) -{ - int ret = 0; - unsigned long flags; - struct sighand_struct *sighand; - struct task_struct *p = timer->it.cpu.task; - - WARN_ON_ONCE(p == NULL); - - /* - * Protect against sighand release/switch in exit/exec and process/ - * thread timer list entry concurrent read/writes. - */ - sighand = lock_task_sighand(p, &flags); - if (unlikely(sighand == NULL)) { - /* - * We raced with the reaping of the task. - * The deletion should have cleared us off the list. - */ - WARN_ON_ONCE(!list_empty(&timer->it.cpu.entry)); - } else { - if (timer->it.cpu.firing) - ret = TIMER_RETRY; - else - list_del(&timer->it.cpu.entry); - - unlock_task_sighand(p, &flags); - } - - if (!ret) - put_task_struct(p); - - return ret; -} - -static void cleanup_timers_list(struct list_head *head) -{ - struct cpu_timer_list *timer, *next; - - list_for_each_entry_safe(timer, next, head, entry) - list_del_init(&timer->entry); -} - -/* - * Clean out CPU timers still ticking when a thread exited. The task - * pointer is cleared, and the expiry time is replaced with the residual - * time for later timer_gettime calls to return. - * This must be called with the siglock held. - */ -static void cleanup_timers(struct list_head *head) -{ - cleanup_timers_list(head); - cleanup_timers_list(++head); - cleanup_timers_list(++head); -} - -/* - * These are both called with the siglock held, when the current thread - * is being reaped. When the final (leader) thread in the group is reaped, - * posix_cpu_timers_exit_group will be called after posix_cpu_timers_exit. - */ -void posix_cpu_timers_exit(struct task_struct *tsk) -{ - add_device_randomness((const void*) &tsk->se.sum_exec_runtime, - sizeof(unsigned long long)); - cleanup_timers(tsk->cpu_timers); - -} -void posix_cpu_timers_exit_group(struct task_struct *tsk) -{ - cleanup_timers(tsk->signal->cpu_timers); -} - -static inline int expires_gt(cputime_t expires, cputime_t new_exp) -{ - return expires == 0 || expires > new_exp; -} - -/* - * Insert the timer on the appropriate list before any timers that - * expire later. This must be called with the sighand lock held. - */ -static void arm_timer(struct k_itimer *timer) -{ - struct task_struct *p = timer->it.cpu.task; - struct list_head *head, *listpos; - struct task_cputime *cputime_expires; - struct cpu_timer_list *const nt = &timer->it.cpu; - struct cpu_timer_list *next; - - if (CPUCLOCK_PERTHREAD(timer->it_clock)) { - head = p->cpu_timers; - cputime_expires = &p->cputime_expires; - } else { - head = p->signal->cpu_timers; - cputime_expires = &p->signal->cputime_expires; - } - head += CPUCLOCK_WHICH(timer->it_clock); - - listpos = head; - list_for_each_entry(next, head, entry) { - if (nt->expires < next->expires) - break; - listpos = &next->entry; - } - list_add(&nt->entry, listpos); - - if (listpos == head) { - unsigned long long exp = nt->expires; - - /* - * We are the new earliest-expiring POSIX 1.b timer, hence - * need to update expiration cache. Take into account that - * for process timers we share expiration cache with itimers - * and RLIMIT_CPU and for thread timers with RLIMIT_RTTIME. - */ - - switch (CPUCLOCK_WHICH(timer->it_clock)) { - case CPUCLOCK_PROF: - if (expires_gt(cputime_expires->prof_exp, expires_to_cputime(exp))) - cputime_expires->prof_exp = expires_to_cputime(exp); - break; - case CPUCLOCK_VIRT: - if (expires_gt(cputime_expires->virt_exp, expires_to_cputime(exp))) - cputime_expires->virt_exp = expires_to_cputime(exp); - break; - case CPUCLOCK_SCHED: - if (cputime_expires->sched_exp == 0 || - cputime_expires->sched_exp > exp) - cputime_expires->sched_exp = exp; - break; - } - if (CPUCLOCK_PERTHREAD(timer->it_clock)) - tick_dep_set_task(p, TICK_DEP_BIT_POSIX_TIMER); - else - tick_dep_set_signal(p->signal, TICK_DEP_BIT_POSIX_TIMER); - } -} - -/* - * The timer is locked, fire it and arrange for its reload. - */ -static void cpu_timer_fire(struct k_itimer *timer) -{ - if ((timer->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE) { - /* - * User don't want any signal. - */ - timer->it.cpu.expires = 0; - } else if (unlikely(timer->sigq == NULL)) { - /* - * This a special case for clock_nanosleep, - * not a normal timer from sys_timer_create. - */ - wake_up_process(timer->it_process); - timer->it.cpu.expires = 0; - } else if (timer->it.cpu.incr == 0) { - /* - * One-shot timer. Clear it as soon as it's fired. - */ - posix_timer_event(timer, 0); - timer->it.cpu.expires = 0; - } else if (posix_timer_event(timer, ++timer->it_requeue_pending)) { - /* - * The signal did not get queued because the signal - * was ignored, so we won't get any callback to - * reload the timer. But we need to keep it - * ticking in case the signal is deliverable next time. - */ - posix_cpu_timer_schedule(timer); - } -} - -/* - * Sample a process (thread group) timer for the given group_leader task. - * Must be called with task sighand lock held for safe while_each_thread() - * traversal. - */ -static int cpu_timer_sample_group(const clockid_t which_clock, - struct task_struct *p, - unsigned long long *sample) -{ - struct task_cputime cputime; - - thread_group_cputimer(p, &cputime); - switch (CPUCLOCK_WHICH(which_clock)) { - default: - return -EINVAL; - case CPUCLOCK_PROF: - *sample = cputime_to_expires(cputime.utime + cputime.stime); - break; - case CPUCLOCK_VIRT: - *sample = cputime_to_expires(cputime.utime); - break; - case CPUCLOCK_SCHED: - *sample = cputime.sum_exec_runtime; - break; - } - return 0; -} - -/* - * Guts of sys_timer_settime for CPU timers. - * This is called with the timer locked and interrupts disabled. - * If we return TIMER_RETRY, it's necessary to release the timer's lock - * and try again. (This happens when the timer is in the middle of firing.) - */ -static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags, - struct itimerspec *new, struct itimerspec *old) -{ - unsigned long flags; - struct sighand_struct *sighand; - struct task_struct *p = timer->it.cpu.task; - unsigned long long old_expires, new_expires, old_incr, val; - int ret; - - WARN_ON_ONCE(p == NULL); - - new_expires = timespec_to_sample(timer->it_clock, &new->it_value); - - /* - * Protect against sighand release/switch in exit/exec and p->cpu_timers - * and p->signal->cpu_timers read/write in arm_timer() - */ - sighand = lock_task_sighand(p, &flags); - /* - * If p has just been reaped, we can no - * longer get any information about it at all. - */ - if (unlikely(sighand == NULL)) { - return -ESRCH; - } - - /* - * Disarm any old timer after extracting its expiry time. - */ - WARN_ON_ONCE(!irqs_disabled()); - - ret = 0; - old_incr = timer->it.cpu.incr; - old_expires = timer->it.cpu.expires; - if (unlikely(timer->it.cpu.firing)) { - timer->it.cpu.firing = -1; - ret = TIMER_RETRY; - } else - list_del_init(&timer->it.cpu.entry); - - /* - * We need to sample the current value to convert the new - * value from to relative and absolute, and to convert the - * old value from absolute to relative. To set a process - * timer, we need a sample to balance the thread expiry - * times (in arm_timer). With an absolute time, we must - * check if it's already passed. In short, we need a sample. - */ - if (CPUCLOCK_PERTHREAD(timer->it_clock)) { - cpu_clock_sample(timer->it_clock, p, &val); - } else { - cpu_timer_sample_group(timer->it_clock, p, &val); - } - - if (old) { - if (old_expires == 0) { - old->it_value.tv_sec = 0; - old->it_value.tv_nsec = 0; - } else { - /* - * Update the timer in case it has - * overrun already. If it has, - * we'll report it as having overrun - * and with the next reloaded timer - * already ticking, though we are - * swallowing that pending - * notification here to install the - * new setting. - */ - bump_cpu_timer(timer, val); - if (val < timer->it.cpu.expires) { - old_expires = timer->it.cpu.expires - val; - sample_to_timespec(timer->it_clock, - old_expires, - &old->it_value); - } else { - old->it_value.tv_nsec = 1; - old->it_value.tv_sec = 0; - } - } - } - - if (unlikely(ret)) { - /* - * We are colliding with the timer actually firing. - * Punt after filling in the timer's old value, and - * disable this firing since we are already reporting - * it as an overrun (thanks to bump_cpu_timer above). - */ - unlock_task_sighand(p, &flags); - goto out; - } - - if (new_expires != 0 && !(timer_flags & TIMER_ABSTIME)) { - new_expires += val; - } - - /* - * Install the new expiry time (or zero). - * For a timer with no notification action, we don't actually - * arm the timer (we'll just fake it for timer_gettime). - */ - timer->it.cpu.expires = new_expires; - if (new_expires != 0 && val < new_expires) { - arm_timer(timer); - } - - unlock_task_sighand(p, &flags); - /* - * Install the new reload setting, and - * set up the signal and overrun bookkeeping. - */ - timer->it.cpu.incr = timespec_to_sample(timer->it_clock, - &new->it_interval); - - /* - * This acts as a modification timestamp for the timer, - * so any automatic reload attempt will punt on seeing - * that we have reset the timer manually. - */ - timer->it_requeue_pending = (timer->it_requeue_pending + 2) & - ~REQUEUE_PENDING; - timer->it_overrun_last = 0; - timer->it_overrun = -1; - - if (new_expires != 0 && !(val < new_expires)) { - /* - * The designated time already passed, so we notify - * immediately, even if the thread never runs to - * accumulate more time on this clock. - */ - cpu_timer_fire(timer); - } - - ret = 0; - out: - if (old) { - sample_to_timespec(timer->it_clock, - old_incr, &old->it_interval); - } - - return ret; -} - -static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp) -{ - unsigned long long now; - struct task_struct *p = timer->it.cpu.task; - - WARN_ON_ONCE(p == NULL); - - /* - * Easy part: convert the reload time. - */ - sample_to_timespec(timer->it_clock, - timer->it.cpu.incr, &itp->it_interval); - - if (timer->it.cpu.expires == 0) { /* Timer not armed at all. */ - itp->it_value.tv_sec = itp->it_value.tv_nsec = 0; - return; - } - - /* - * Sample the clock to take the difference with the expiry time. - */ - if (CPUCLOCK_PERTHREAD(timer->it_clock)) { - cpu_clock_sample(timer->it_clock, p, &now); - } else { - struct sighand_struct *sighand; - unsigned long flags; - - /* - * Protect against sighand release/switch in exit/exec and - * also make timer sampling safe if it ends up calling - * thread_group_cputime(). - */ - sighand = lock_task_sighand(p, &flags); - if (unlikely(sighand == NULL)) { - /* - * The process has been reaped. - * We can't even collect a sample any more. - * Call the timer disarmed, nothing else to do. - */ - timer->it.cpu.expires = 0; - sample_to_timespec(timer->it_clock, timer->it.cpu.expires, - &itp->it_value); - return; - } else { - cpu_timer_sample_group(timer->it_clock, p, &now); - unlock_task_sighand(p, &flags); - } - } - - if (now < timer->it.cpu.expires) { - sample_to_timespec(timer->it_clock, - timer->it.cpu.expires - now, - &itp->it_value); - } else { - /* - * The timer should have expired already, but the firing - * hasn't taken place yet. Say it's just about to expire. - */ - itp->it_value.tv_nsec = 1; - itp->it_value.tv_sec = 0; - } -} - -static unsigned long long -check_timers_list(struct list_head *timers, - struct list_head *firing, - unsigned long long curr) -{ - int maxfire = 20; - - while (!list_empty(timers)) { - struct cpu_timer_list *t; - - t = list_first_entry(timers, struct cpu_timer_list, entry); - - if (!--maxfire || curr < t->expires) - return t->expires; - - t->firing = 1; - list_move_tail(&t->entry, firing); - } - - return 0; -} - -/* - * Check for any per-thread CPU timers that have fired and move them off - * the tsk->cpu_timers[N] list onto the firing list. Here we update the - * tsk->it_*_expires values to reflect the remaining thread CPU timers. - */ -static void check_thread_timers(struct task_struct *tsk, - struct list_head *firing) -{ - struct list_head *timers = tsk->cpu_timers; - struct signal_struct *const sig = tsk->signal; - struct task_cputime *tsk_expires = &tsk->cputime_expires; - unsigned long long expires; - unsigned long soft; - - /* - * If cputime_expires is zero, then there are no active - * per thread CPU timers. - */ - if (task_cputime_zero(&tsk->cputime_expires)) - return; - - expires = check_timers_list(timers, firing, prof_ticks(tsk)); - tsk_expires->prof_exp = expires_to_cputime(expires); - - expires = check_timers_list(++timers, firing, virt_ticks(tsk)); - tsk_expires->virt_exp = expires_to_cputime(expires); - - tsk_expires->sched_exp = check_timers_list(++timers, firing, - tsk->se.sum_exec_runtime); - - /* - * Check for the special case thread timers. - */ - soft = READ_ONCE(sig->rlim[RLIMIT_RTTIME].rlim_cur); - if (soft != RLIM_INFINITY) { - unsigned long hard = - READ_ONCE(sig->rlim[RLIMIT_RTTIME].rlim_max); - - if (hard != RLIM_INFINITY && - tsk->rt.timeout > DIV_ROUND_UP(hard, USEC_PER_SEC/HZ)) { - /* - * At the hard limit, we just die. - * No need to calculate anything else now. - */ - __group_send_sig_info(SIGKILL, SEND_SIG_PRIV, tsk); - return; - } - if (tsk->rt.timeout > DIV_ROUND_UP(soft, USEC_PER_SEC/HZ)) { - /* - * At the soft limit, send a SIGXCPU every second. - */ - if (soft < hard) { - soft += USEC_PER_SEC; - sig->rlim[RLIMIT_RTTIME].rlim_cur = soft; - } - printk(KERN_INFO - "RT Watchdog Timeout: %s[%d]\n", - tsk->comm, task_pid_nr(tsk)); - __group_send_sig_info(SIGXCPU, SEND_SIG_PRIV, tsk); - } - } - if (task_cputime_zero(tsk_expires)) - tick_dep_clear_task(tsk, TICK_DEP_BIT_POSIX_TIMER); -} - -static inline void stop_process_timers(struct signal_struct *sig) -{ - struct thread_group_cputimer *cputimer = &sig->cputimer; - - /* Turn off cputimer->running. This is done without locking. */ - WRITE_ONCE(cputimer->running, false); - tick_dep_clear_signal(sig, TICK_DEP_BIT_POSIX_TIMER); -} - -static u32 onecputick; - -static void check_cpu_itimer(struct task_struct *tsk, struct cpu_itimer *it, - unsigned long long *expires, - unsigned long long cur_time, int signo) -{ - if (!it->expires) - return; - - if (cur_time >= it->expires) { - if (it->incr) { - it->expires += it->incr; - it->error += it->incr_error; - if (it->error >= onecputick) { - it->expires -= cputime_one_jiffy; - it->error -= onecputick; - } - } else { - it->expires = 0; - } - - trace_itimer_expire(signo == SIGPROF ? - ITIMER_PROF : ITIMER_VIRTUAL, - tsk->signal->leader_pid, cur_time); - __group_send_sig_info(signo, SEND_SIG_PRIV, tsk); - } - - if (it->expires && (!*expires || it->expires < *expires)) { - *expires = it->expires; - } -} - -/* - * Check for any per-thread CPU timers that have fired and move them - * off the tsk->*_timers list onto the firing list. Per-thread timers - * have already been taken off. - */ -static void check_process_timers(struct task_struct *tsk, - struct list_head *firing) -{ - struct signal_struct *const sig = tsk->signal; - unsigned long long utime, ptime, virt_expires, prof_expires; - unsigned long long sum_sched_runtime, sched_expires; - struct list_head *timers = sig->cpu_timers; - struct task_cputime cputime; - unsigned long soft; - - /* - * If cputimer is not running, then there are no active - * process wide timers (POSIX 1.b, itimers, RLIMIT_CPU). - */ - if (!READ_ONCE(tsk->signal->cputimer.running)) - return; - - /* - * Signify that a thread is checking for process timers. - * Write access to this field is protected by the sighand lock. - */ - sig->cputimer.checking_timer = true; - - /* - * Collect the current process totals. - */ - thread_group_cputimer(tsk, &cputime); - utime = cputime_to_expires(cputime.utime); - ptime = utime + cputime_to_expires(cputime.stime); - sum_sched_runtime = cputime.sum_exec_runtime; - - prof_expires = check_timers_list(timers, firing, ptime); - virt_expires = check_timers_list(++timers, firing, utime); - sched_expires = check_timers_list(++timers, firing, sum_sched_runtime); - - /* - * Check for the special case process timers. - */ - check_cpu_itimer(tsk, &sig->it[CPUCLOCK_PROF], &prof_expires, ptime, - SIGPROF); - check_cpu_itimer(tsk, &sig->it[CPUCLOCK_VIRT], &virt_expires, utime, - SIGVTALRM); - soft = READ_ONCE(sig->rlim[RLIMIT_CPU].rlim_cur); - if (soft != RLIM_INFINITY) { - unsigned long psecs = cputime_to_secs(ptime); - unsigned long hard = - READ_ONCE(sig->rlim[RLIMIT_CPU].rlim_max); - cputime_t x; - if (psecs >= hard) { - /* - * At the hard limit, we just die. - * No need to calculate anything else now. - */ - __group_send_sig_info(SIGKILL, SEND_SIG_PRIV, tsk); - return; - } - if (psecs >= soft) { - /* - * At the soft limit, send a SIGXCPU every second. - */ - __group_send_sig_info(SIGXCPU, SEND_SIG_PRIV, tsk); - if (soft < hard) { - soft++; - sig->rlim[RLIMIT_CPU].rlim_cur = soft; - } - } - x = secs_to_cputime(soft); - if (!prof_expires || x < prof_expires) { - prof_expires = x; - } - } - - sig->cputime_expires.prof_exp = expires_to_cputime(prof_expires); - sig->cputime_expires.virt_exp = expires_to_cputime(virt_expires); - sig->cputime_expires.sched_exp = sched_expires; - if (task_cputime_zero(&sig->cputime_expires)) - stop_process_timers(sig); - - sig->cputimer.checking_timer = false; -} - -/* - * This is called from the signal code (via do_schedule_next_timer) - * when the last timer signal was delivered and we have to reload the timer. - */ -void posix_cpu_timer_schedule(struct k_itimer *timer) -{ - struct sighand_struct *sighand; - unsigned long flags; - struct task_struct *p = timer->it.cpu.task; - unsigned long long now; - - WARN_ON_ONCE(p == NULL); - - /* - * Fetch the current sample and update the timer's expiry time. - */ - if (CPUCLOCK_PERTHREAD(timer->it_clock)) { - cpu_clock_sample(timer->it_clock, p, &now); - bump_cpu_timer(timer, now); - if (unlikely(p->exit_state)) - goto out; - - /* Protect timer list r/w in arm_timer() */ - sighand = lock_task_sighand(p, &flags); - if (!sighand) - goto out; - } else { - /* - * Protect arm_timer() and timer sampling in case of call to - * thread_group_cputime(). - */ - sighand = lock_task_sighand(p, &flags); - if (unlikely(sighand == NULL)) { - /* - * The process has been reaped. - * We can't even collect a sample any more. - */ - timer->it.cpu.expires = 0; - goto out; - } else if (unlikely(p->exit_state) && thread_group_empty(p)) { - unlock_task_sighand(p, &flags); - /* Optimizations: if the process is dying, no need to rearm */ - goto out; - } - cpu_timer_sample_group(timer->it_clock, p, &now); - bump_cpu_timer(timer, now); - /* Leave the sighand locked for the call below. */ - } - - /* - * Now re-arm for the new expiry time. - */ - WARN_ON_ONCE(!irqs_disabled()); - arm_timer(timer); - unlock_task_sighand(p, &flags); - -out: - timer->it_overrun_last = timer->it_overrun; - timer->it_overrun = -1; - ++timer->it_requeue_pending; -} - -/** - * task_cputime_expired - Compare two task_cputime entities. - * - * @sample: The task_cputime structure to be checked for expiration. - * @expires: Expiration times, against which @sample will be checked. - * - * Checks @sample against @expires to see if any field of @sample has expired. - * Returns true if any field of the former is greater than the corresponding - * field of the latter if the latter field is set. Otherwise returns false. - */ -static inline int task_cputime_expired(const struct task_cputime *sample, - const struct task_cputime *expires) -{ - if (expires->utime && sample->utime >= expires->utime) - return 1; - if (expires->stime && sample->utime + sample->stime >= expires->stime) - return 1; - if (expires->sum_exec_runtime != 0 && - sample->sum_exec_runtime >= expires->sum_exec_runtime) - return 1; - return 0; -} - -/** - * fastpath_timer_check - POSIX CPU timers fast path. - * - * @tsk: The task (thread) being checked. - * - * Check the task and thread group timers. If both are zero (there are no - * timers set) return false. Otherwise snapshot the task and thread group - * timers and compare them with the corresponding expiration times. Return - * true if a timer has expired, else return false. - */ -static inline int fastpath_timer_check(struct task_struct *tsk) -{ - struct signal_struct *sig; - - if (!task_cputime_zero(&tsk->cputime_expires)) { - struct task_cputime task_sample; - - task_cputime(tsk, &task_sample.utime, &task_sample.stime); - task_sample.sum_exec_runtime = tsk->se.sum_exec_runtime; - if (task_cputime_expired(&task_sample, &tsk->cputime_expires)) - return 1; - } - - sig = tsk->signal; - /* - * Check if thread group timers expired when the cputimer is - * running and no other thread in the group is already checking - * for thread group cputimers. These fields are read without the - * sighand lock. However, this is fine because this is meant to - * be a fastpath heuristic to determine whether we should try to - * acquire the sighand lock to check/handle timers. - * - * In the worst case scenario, if 'running' or 'checking_timer' gets - * set but the current thread doesn't see the change yet, we'll wait - * until the next thread in the group gets a scheduler interrupt to - * handle the timer. This isn't an issue in practice because these - * types of delays with signals actually getting sent are expected. - */ - if (READ_ONCE(sig->cputimer.running) && - !READ_ONCE(sig->cputimer.checking_timer)) { - struct task_cputime group_sample; - - sample_cputime_atomic(&group_sample, &sig->cputimer.cputime_atomic); - - if (task_cputime_expired(&group_sample, &sig->cputime_expires)) - return 1; - } - - return 0; -} - -/* - * This is called from the timer interrupt handler. The irq handler has - * already updated our counts. We need to check if any timers fire now. - * Interrupts are disabled. - */ -void run_posix_cpu_timers(struct task_struct *tsk) -{ - LIST_HEAD(firing); - struct k_itimer *timer, *next; - unsigned long flags; - - WARN_ON_ONCE(!irqs_disabled()); - - /* - * The fast path checks that there are no expired thread or thread - * group timers. If that's so, just return. - */ - if (!fastpath_timer_check(tsk)) - return; - - if (!lock_task_sighand(tsk, &flags)) - return; - /* - * Here we take off tsk->signal->cpu_timers[N] and - * tsk->cpu_timers[N] all the timers that are firing, and - * put them on the firing list. - */ - check_thread_timers(tsk, &firing); - - check_process_timers(tsk, &firing); - - /* - * We must release these locks before taking any timer's lock. - * There is a potential race with timer deletion here, as the - * siglock now protects our private firing list. We have set - * the firing flag in each timer, so that a deletion attempt - * that gets the timer lock before we do will give it up and - * spin until we've taken care of that timer below. - */ - unlock_task_sighand(tsk, &flags); - - /* - * Now that all the timers on our list have the firing flag, - * no one will touch their list entries but us. We'll take - * each timer's lock before clearing its firing flag, so no - * timer call will interfere. - */ - list_for_each_entry_safe(timer, next, &firing, it.cpu.entry) { - int cpu_firing; - - spin_lock(&timer->it_lock); - list_del_init(&timer->it.cpu.entry); - cpu_firing = timer->it.cpu.firing; - timer->it.cpu.firing = 0; - /* - * The firing flag is -1 if we collided with a reset - * of the timer, which already reported this - * almost-firing as an overrun. So don't generate an event. - */ - if (likely(cpu_firing >= 0)) - cpu_timer_fire(timer); - spin_unlock(&timer->it_lock); - } -} - -/* - * Set one of the process-wide special case CPU timers or RLIMIT_CPU. - * The tsk->sighand->siglock must be held by the caller. - */ -void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx, - cputime_t *newval, cputime_t *oldval) -{ - unsigned long long now; - - WARN_ON_ONCE(clock_idx == CPUCLOCK_SCHED); - cpu_timer_sample_group(clock_idx, tsk, &now); - - if (oldval) { - /* - * We are setting itimer. The *oldval is absolute and we update - * it to be relative, *newval argument is relative and we update - * it to be absolute. - */ - if (*oldval) { - if (*oldval <= now) { - /* Just about to fire. */ - *oldval = cputime_one_jiffy; - } else { - *oldval -= now; - } - } - - if (!*newval) - return; - *newval += now; - } - - /* - * Update expiration cache if we are the earliest timer, or eventually - * RLIMIT_CPU limit is earlier than prof_exp cpu timer expire. - */ - switch (clock_idx) { - case CPUCLOCK_PROF: - if (expires_gt(tsk->signal->cputime_expires.prof_exp, *newval)) - tsk->signal->cputime_expires.prof_exp = *newval; - break; - case CPUCLOCK_VIRT: - if (expires_gt(tsk->signal->cputime_expires.virt_exp, *newval)) - tsk->signal->cputime_expires.virt_exp = *newval; - break; - } - - tick_dep_set_signal(tsk->signal, TICK_DEP_BIT_POSIX_TIMER); -} - -static int do_cpu_nanosleep(const clockid_t which_clock, int flags, - struct timespec *rqtp, struct itimerspec *it) -{ - struct k_itimer timer; - int error; - - /* - * Set up a temporary timer and then wait for it to go off. - */ - memset(&timer, 0, sizeof timer); - spin_lock_init(&timer.it_lock); - timer.it_clock = which_clock; - timer.it_overrun = -1; - error = posix_cpu_timer_create(&timer); - timer.it_process = current; - if (!error) { - static struct itimerspec zero_it; - - memset(it, 0, sizeof *it); - it->it_value = *rqtp; - - spin_lock_irq(&timer.it_lock); - error = posix_cpu_timer_set(&timer, flags, it, NULL); - if (error) { - spin_unlock_irq(&timer.it_lock); - return error; - } - - while (!signal_pending(current)) { - if (timer.it.cpu.expires == 0) { - /* - * Our timer fired and was reset, below - * deletion can not fail. - */ - posix_cpu_timer_del(&timer); - spin_unlock_irq(&timer.it_lock); - return 0; - } - - /* - * Block until cpu_timer_fire (or a signal) wakes us. - */ - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&timer.it_lock); - schedule(); - spin_lock_irq(&timer.it_lock); - } - - /* - * We were interrupted by a signal. - */ - sample_to_timespec(which_clock, timer.it.cpu.expires, rqtp); - error = posix_cpu_timer_set(&timer, 0, &zero_it, it); - if (!error) { - /* - * Timer is now unarmed, deletion can not fail. - */ - posix_cpu_timer_del(&timer); - } - spin_unlock_irq(&timer.it_lock); - - while (error == TIMER_RETRY) { - /* - * We need to handle case when timer was or is in the - * middle of firing. In other cases we already freed - * resources. - */ - spin_lock_irq(&timer.it_lock); - error = posix_cpu_timer_del(&timer); - spin_unlock_irq(&timer.it_lock); - } - - if ((it->it_value.tv_sec | it->it_value.tv_nsec) == 0) { - /* - * It actually did fire already. - */ - return 0; - } - - error = -ERESTART_RESTARTBLOCK; - } - - return error; -} - -static long posix_cpu_nsleep_restart(struct restart_block *restart_block); - -static int posix_cpu_nsleep(const clockid_t which_clock, int flags, - struct timespec *rqtp, struct timespec __user *rmtp) -{ - struct restart_block *restart_block = ¤t->restart_block; - struct itimerspec it; - int error; - - /* - * Diagnose required errors first. - */ - if (CPUCLOCK_PERTHREAD(which_clock) && - (CPUCLOCK_PID(which_clock) == 0 || - CPUCLOCK_PID(which_clock) == current->pid)) - return -EINVAL; - - error = do_cpu_nanosleep(which_clock, flags, rqtp, &it); - - if (error == -ERESTART_RESTARTBLOCK) { - - if (flags & TIMER_ABSTIME) - return -ERESTARTNOHAND; - /* - * Report back to the user the time still remaining. - */ - if (rmtp && copy_to_user(rmtp, &it.it_value, sizeof *rmtp)) - return -EFAULT; - - restart_block->fn = posix_cpu_nsleep_restart; - restart_block->nanosleep.clockid = which_clock; - restart_block->nanosleep.rmtp = rmtp; - restart_block->nanosleep.expires = timespec_to_ns(rqtp); - } - return error; -} - -static long posix_cpu_nsleep_restart(struct restart_block *restart_block) -{ - clockid_t which_clock = restart_block->nanosleep.clockid; - struct timespec t; - struct itimerspec it; - int error; - - t = ns_to_timespec(restart_block->nanosleep.expires); - - error = do_cpu_nanosleep(which_clock, TIMER_ABSTIME, &t, &it); - - if (error == -ERESTART_RESTARTBLOCK) { - struct timespec __user *rmtp = restart_block->nanosleep.rmtp; - /* - * Report back to the user the time still remaining. - */ - if (rmtp && copy_to_user(rmtp, &it.it_value, sizeof *rmtp)) - return -EFAULT; - - restart_block->nanosleep.expires = timespec_to_ns(&t); - } - return error; - -} - -#define PROCESS_CLOCK MAKE_PROCESS_CPUCLOCK(0, CPUCLOCK_SCHED) -#define THREAD_CLOCK MAKE_THREAD_CPUCLOCK(0, CPUCLOCK_SCHED) - -static int process_cpu_clock_getres(const clockid_t which_clock, - struct timespec *tp) -{ - return posix_cpu_clock_getres(PROCESS_CLOCK, tp); -} -static int process_cpu_clock_get(const clockid_t which_clock, - struct timespec *tp) -{ - return posix_cpu_clock_get(PROCESS_CLOCK, tp); -} -static int process_cpu_timer_create(struct k_itimer *timer) -{ - timer->it_clock = PROCESS_CLOCK; - return posix_cpu_timer_create(timer); -} -static int process_cpu_nsleep(const clockid_t which_clock, int flags, - struct timespec *rqtp, - struct timespec __user *rmtp) -{ - return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp, rmtp); -} -static long process_cpu_nsleep_restart(struct restart_block *restart_block) -{ - return -EINVAL; -} -static int thread_cpu_clock_getres(const clockid_t which_clock, - struct timespec *tp) -{ - return posix_cpu_clock_getres(THREAD_CLOCK, tp); -} -static int thread_cpu_clock_get(const clockid_t which_clock, - struct timespec *tp) -{ - return posix_cpu_clock_get(THREAD_CLOCK, tp); -} -static int thread_cpu_timer_create(struct k_itimer *timer) -{ - timer->it_clock = THREAD_CLOCK; - return posix_cpu_timer_create(timer); -} - -struct k_clock clock_posix_cpu = { - .clock_getres = posix_cpu_clock_getres, - .clock_set = posix_cpu_clock_set, - .clock_get = posix_cpu_clock_get, - .timer_create = posix_cpu_timer_create, - .nsleep = posix_cpu_nsleep, - .nsleep_restart = posix_cpu_nsleep_restart, - .timer_set = posix_cpu_timer_set, - .timer_del = posix_cpu_timer_del, - .timer_get = posix_cpu_timer_get, -}; - -static __init int init_posix_cpu_timers(void) -{ - struct k_clock process = { - .clock_getres = process_cpu_clock_getres, - .clock_get = process_cpu_clock_get, - .timer_create = process_cpu_timer_create, - .nsleep = process_cpu_nsleep, - .nsleep_restart = process_cpu_nsleep_restart, - }; - struct k_clock thread = { - .clock_getres = thread_cpu_clock_getres, - .clock_get = thread_cpu_clock_get, - .timer_create = thread_cpu_timer_create, - }; - struct timespec ts; - - posix_timers_register_clock(CLOCK_PROCESS_CPUTIME_ID, &process); - posix_timers_register_clock(CLOCK_THREAD_CPUTIME_ID, &thread); - - cputime_to_timespec(cputime_one_jiffy, &ts); - onecputick = ts.tv_nsec; - WARN_ON(ts.tv_sec != 0); - - return 0; -} -__initcall(init_posix_cpu_timers); diff --git a/src/linux/kernel/time/posix-timers.c b/src/linux/kernel/time/posix-timers.c deleted file mode 100644 index f2826c3..0000000 --- a/src/linux/kernel/time/posix-timers.c +++ /dev/null @@ -1,1131 +0,0 @@ -/* - * linux/kernel/posix-timers.c - * - * - * 2002-10-15 Posix Clocks & timers - * by George Anzinger george@mvista.com - * - * Copyright (C) 2002 2003 by MontaVista Software. - * - * 2004-06-01 Fix CLOCK_REALTIME clock/timer TIMER_ABSTIME bug. - * Copyright (C) 2004 Boris Hu - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - * MontaVista Software | 1237 East Arques Avenue | Sunnyvale | CA 94085 | USA - */ - -/* These are all the functions necessary to implement - * POSIX clocks & timers - */ -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "timekeeping.h" - -/* - * Management arrays for POSIX timers. Timers are now kept in static hash table - * with 512 entries. - * Timer ids are allocated by local routine, which selects proper hash head by - * key, constructed from current->signal address and per signal struct counter. - * This keeps timer ids unique per process, but now they can intersect between - * processes. - */ - -/* - * Lets keep our timers in a slab cache :-) - */ -static struct kmem_cache *posix_timers_cache; - -static DEFINE_HASHTABLE(posix_timers_hashtable, 9); -static DEFINE_SPINLOCK(hash_lock); - -/* - * we assume that the new SIGEV_THREAD_ID shares no bits with the other - * SIGEV values. Here we put out an error if this assumption fails. - */ -#if SIGEV_THREAD_ID != (SIGEV_THREAD_ID & \ - ~(SIGEV_SIGNAL | SIGEV_NONE | SIGEV_THREAD)) -#error "SIGEV_THREAD_ID must not share bit with other SIGEV values!" -#endif - -/* - * parisc wants ENOTSUP instead of EOPNOTSUPP - */ -#ifndef ENOTSUP -# define ENANOSLEEP_NOTSUP EOPNOTSUPP -#else -# define ENANOSLEEP_NOTSUP ENOTSUP -#endif - -/* - * The timer ID is turned into a timer address by idr_find(). - * Verifying a valid ID consists of: - * - * a) checking that idr_find() returns other than -1. - * b) checking that the timer id matches the one in the timer itself. - * c) that the timer owner is in the callers thread group. - */ - -/* - * CLOCKs: The POSIX standard calls for a couple of clocks and allows us - * to implement others. This structure defines the various - * clocks. - * - * RESOLUTION: Clock resolution is used to round up timer and interval - * times, NOT to report clock times, which are reported with as - * much resolution as the system can muster. In some cases this - * resolution may depend on the underlying clock hardware and - * may not be quantifiable until run time, and only then is the - * necessary code is written. The standard says we should say - * something about this issue in the documentation... - * - * FUNCTIONS: The CLOCKs structure defines possible functions to - * handle various clock functions. - * - * The standard POSIX timer management code assumes the - * following: 1.) The k_itimer struct (sched.h) is used for - * the timer. 2.) The list, it_lock, it_clock, it_id and - * it_pid fields are not modified by timer code. - * - * Permissions: It is assumed that the clock_settime() function defined - * for each clock will take care of permission checks. Some - * clocks may be set able by any user (i.e. local process - * clocks) others not. Currently the only set able clock we - * have is CLOCK_REALTIME and its high res counter part, both of - * which we beg off on and pass to do_sys_settimeofday(). - */ - -static struct k_clock posix_clocks[MAX_CLOCKS]; - -/* - * These ones are defined below. - */ -static int common_nsleep(const clockid_t, int flags, struct timespec *t, - struct timespec __user *rmtp); -static int common_timer_create(struct k_itimer *new_timer); -static void common_timer_get(struct k_itimer *, struct itimerspec *); -static int common_timer_set(struct k_itimer *, int, - struct itimerspec *, struct itimerspec *); -static int common_timer_del(struct k_itimer *timer); - -static enum hrtimer_restart posix_timer_fn(struct hrtimer *data); - -static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags); - -#define lock_timer(tid, flags) \ -({ struct k_itimer *__timr; \ - __cond_lock(&__timr->it_lock, __timr = __lock_timer(tid, flags)); \ - __timr; \ -}) - -static int hash(struct signal_struct *sig, unsigned int nr) -{ - return hash_32(hash32_ptr(sig) ^ nr, HASH_BITS(posix_timers_hashtable)); -} - -static struct k_itimer *__posix_timers_find(struct hlist_head *head, - struct signal_struct *sig, - timer_t id) -{ - struct k_itimer *timer; - - hlist_for_each_entry_rcu(timer, head, t_hash) { - if ((timer->it_signal == sig) && (timer->it_id == id)) - return timer; - } - return NULL; -} - -static struct k_itimer *posix_timer_by_id(timer_t id) -{ - struct signal_struct *sig = current->signal; - struct hlist_head *head = &posix_timers_hashtable[hash(sig, id)]; - - return __posix_timers_find(head, sig, id); -} - -static int posix_timer_add(struct k_itimer *timer) -{ - struct signal_struct *sig = current->signal; - int first_free_id = sig->posix_timer_id; - struct hlist_head *head; - int ret = -ENOENT; - - do { - spin_lock(&hash_lock); - head = &posix_timers_hashtable[hash(sig, sig->posix_timer_id)]; - if (!__posix_timers_find(head, sig, sig->posix_timer_id)) { - hlist_add_head_rcu(&timer->t_hash, head); - ret = sig->posix_timer_id; - } - if (++sig->posix_timer_id < 0) - sig->posix_timer_id = 0; - if ((sig->posix_timer_id == first_free_id) && (ret == -ENOENT)) - /* Loop over all possible ids completed */ - ret = -EAGAIN; - spin_unlock(&hash_lock); - } while (ret == -ENOENT); - return ret; -} - -static inline void unlock_timer(struct k_itimer *timr, unsigned long flags) -{ - spin_unlock_irqrestore(&timr->it_lock, flags); -} - -/* Get clock_realtime */ -static int posix_clock_realtime_get(clockid_t which_clock, struct timespec *tp) -{ - ktime_get_real_ts(tp); - return 0; -} - -/* Set clock_realtime */ -static int posix_clock_realtime_set(const clockid_t which_clock, - const struct timespec *tp) -{ - return do_sys_settimeofday(tp, NULL); -} - -static int posix_clock_realtime_adj(const clockid_t which_clock, - struct timex *t) -{ - return do_adjtimex(t); -} - -/* - * Get monotonic time for posix timers - */ -static int posix_ktime_get_ts(clockid_t which_clock, struct timespec *tp) -{ - ktime_get_ts(tp); - return 0; -} - -/* - * Get monotonic-raw time for posix timers - */ -static int posix_get_monotonic_raw(clockid_t which_clock, struct timespec *tp) -{ - getrawmonotonic(tp); - return 0; -} - - -static int posix_get_realtime_coarse(clockid_t which_clock, struct timespec *tp) -{ - *tp = current_kernel_time(); - return 0; -} - -static int posix_get_monotonic_coarse(clockid_t which_clock, - struct timespec *tp) -{ - *tp = get_monotonic_coarse(); - return 0; -} - -static int posix_get_coarse_res(const clockid_t which_clock, struct timespec *tp) -{ - *tp = ktime_to_timespec(KTIME_LOW_RES); - return 0; -} - -static int posix_get_boottime(const clockid_t which_clock, struct timespec *tp) -{ - get_monotonic_boottime(tp); - return 0; -} - -static int posix_get_tai(clockid_t which_clock, struct timespec *tp) -{ - timekeeping_clocktai(tp); - return 0; -} - -static int posix_get_hrtimer_res(clockid_t which_clock, struct timespec *tp) -{ - tp->tv_sec = 0; - tp->tv_nsec = hrtimer_resolution; - return 0; -} - -/* - * Initialize everything, well, just everything in Posix clocks/timers ;) - */ -static __init int init_posix_timers(void) -{ - struct k_clock clock_realtime = { - .clock_getres = posix_get_hrtimer_res, - .clock_get = posix_clock_realtime_get, - .clock_set = posix_clock_realtime_set, - .clock_adj = posix_clock_realtime_adj, - .nsleep = common_nsleep, - .nsleep_restart = hrtimer_nanosleep_restart, - .timer_create = common_timer_create, - .timer_set = common_timer_set, - .timer_get = common_timer_get, - .timer_del = common_timer_del, - }; - struct k_clock clock_monotonic = { - .clock_getres = posix_get_hrtimer_res, - .clock_get = posix_ktime_get_ts, - .nsleep = common_nsleep, - .nsleep_restart = hrtimer_nanosleep_restart, - .timer_create = common_timer_create, - .timer_set = common_timer_set, - .timer_get = common_timer_get, - .timer_del = common_timer_del, - }; - struct k_clock clock_monotonic_raw = { - .clock_getres = posix_get_hrtimer_res, - .clock_get = posix_get_monotonic_raw, - }; - struct k_clock clock_realtime_coarse = { - .clock_getres = posix_get_coarse_res, - .clock_get = posix_get_realtime_coarse, - }; - struct k_clock clock_monotonic_coarse = { - .clock_getres = posix_get_coarse_res, - .clock_get = posix_get_monotonic_coarse, - }; - struct k_clock clock_tai = { - .clock_getres = posix_get_hrtimer_res, - .clock_get = posix_get_tai, - .nsleep = common_nsleep, - .nsleep_restart = hrtimer_nanosleep_restart, - .timer_create = common_timer_create, - .timer_set = common_timer_set, - .timer_get = common_timer_get, - .timer_del = common_timer_del, - }; - struct k_clock clock_boottime = { - .clock_getres = posix_get_hrtimer_res, - .clock_get = posix_get_boottime, - .nsleep = common_nsleep, - .nsleep_restart = hrtimer_nanosleep_restart, - .timer_create = common_timer_create, - .timer_set = common_timer_set, - .timer_get = common_timer_get, - .timer_del = common_timer_del, - }; - - posix_timers_register_clock(CLOCK_REALTIME, &clock_realtime); - posix_timers_register_clock(CLOCK_MONOTONIC, &clock_monotonic); - posix_timers_register_clock(CLOCK_MONOTONIC_RAW, &clock_monotonic_raw); - posix_timers_register_clock(CLOCK_REALTIME_COARSE, &clock_realtime_coarse); - posix_timers_register_clock(CLOCK_MONOTONIC_COARSE, &clock_monotonic_coarse); - posix_timers_register_clock(CLOCK_BOOTTIME, &clock_boottime); - posix_timers_register_clock(CLOCK_TAI, &clock_tai); - - posix_timers_cache = kmem_cache_create("posix_timers_cache", - sizeof (struct k_itimer), 0, SLAB_PANIC, - NULL); - return 0; -} - -__initcall(init_posix_timers); - -static void schedule_next_timer(struct k_itimer *timr) -{ - struct hrtimer *timer = &timr->it.real.timer; - - if (timr->it.real.interval.tv64 == 0) - return; - - timr->it_overrun += (unsigned int) hrtimer_forward(timer, - timer->base->get_time(), - timr->it.real.interval); - - timr->it_overrun_last = timr->it_overrun; - timr->it_overrun = -1; - ++timr->it_requeue_pending; - hrtimer_restart(timer); -} - -/* - * This function is exported for use by the signal deliver code. It is - * called just prior to the info block being released and passes that - * block to us. It's function is to update the overrun entry AND to - * restart the timer. It should only be called if the timer is to be - * restarted (i.e. we have flagged this in the sys_private entry of the - * info block). - * - * To protect against the timer going away while the interrupt is queued, - * we require that the it_requeue_pending flag be set. - */ -void do_schedule_next_timer(struct siginfo *info) -{ - struct k_itimer *timr; - unsigned long flags; - - timr = lock_timer(info->si_tid, &flags); - - if (timr && timr->it_requeue_pending == info->si_sys_private) { - if (timr->it_clock < 0) - posix_cpu_timer_schedule(timr); - else - schedule_next_timer(timr); - - info->si_overrun += timr->it_overrun_last; - } - - if (timr) - unlock_timer(timr, flags); -} - -int posix_timer_event(struct k_itimer *timr, int si_private) -{ - struct task_struct *task; - int shared, ret = -1; - /* - * FIXME: if ->sigq is queued we can race with - * dequeue_signal()->do_schedule_next_timer(). - * - * If dequeue_signal() sees the "right" value of - * si_sys_private it calls do_schedule_next_timer(). - * We re-queue ->sigq and drop ->it_lock(). - * do_schedule_next_timer() locks the timer - * and re-schedules it while ->sigq is pending. - * Not really bad, but not that we want. - */ - timr->sigq->info.si_sys_private = si_private; - - rcu_read_lock(); - task = pid_task(timr->it_pid, PIDTYPE_PID); - if (task) { - shared = !(timr->it_sigev_notify & SIGEV_THREAD_ID); - ret = send_sigqueue(timr->sigq, task, shared); - } - rcu_read_unlock(); - /* If we failed to send the signal the timer stops. */ - return ret > 0; -} -EXPORT_SYMBOL_GPL(posix_timer_event); - -/* - * This function gets called when a POSIX.1b interval timer expires. It - * is used as a callback from the kernel internal timer. The - * run_timer_list code ALWAYS calls with interrupts on. - - * This code is for CLOCK_REALTIME* and CLOCK_MONOTONIC* timers. - */ -static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer) -{ - struct k_itimer *timr; - unsigned long flags; - int si_private = 0; - enum hrtimer_restart ret = HRTIMER_NORESTART; - - timr = container_of(timer, struct k_itimer, it.real.timer); - spin_lock_irqsave(&timr->it_lock, flags); - - if (timr->it.real.interval.tv64 != 0) - si_private = ++timr->it_requeue_pending; - - if (posix_timer_event(timr, si_private)) { - /* - * signal was not sent because of sig_ignor - * we will not get a call back to restart it AND - * it should be restarted. - */ - if (timr->it.real.interval.tv64 != 0) { - ktime_t now = hrtimer_cb_get_time(timer); - - /* - * FIXME: What we really want, is to stop this - * timer completely and restart it in case the - * SIG_IGN is removed. This is a non trivial - * change which involves sighand locking - * (sigh !), which we don't want to do late in - * the release cycle. - * - * For now we just let timers with an interval - * less than a jiffie expire every jiffie to - * avoid softirq starvation in case of SIG_IGN - * and a very small interval, which would put - * the timer right back on the softirq pending - * list. By moving now ahead of time we trick - * hrtimer_forward() to expire the timer - * later, while we still maintain the overrun - * accuracy, but have some inconsistency in - * the timer_gettime() case. This is at least - * better than a starved softirq. A more - * complex fix which solves also another related - * inconsistency is already in the pipeline. - */ -#ifdef CONFIG_HIGH_RES_TIMERS - { - ktime_t kj = ktime_set(0, NSEC_PER_SEC / HZ); - - if (timr->it.real.interval.tv64 < kj.tv64) - now = ktime_add(now, kj); - } -#endif - timr->it_overrun += (unsigned int) - hrtimer_forward(timer, now, - timr->it.real.interval); - ret = HRTIMER_RESTART; - ++timr->it_requeue_pending; - } - } - - unlock_timer(timr, flags); - return ret; -} - -static struct pid *good_sigevent(sigevent_t * event) -{ - struct task_struct *rtn = current->group_leader; - - if ((event->sigev_notify & SIGEV_THREAD_ID ) && - (!(rtn = find_task_by_vpid(event->sigev_notify_thread_id)) || - !same_thread_group(rtn, current) || - (event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_SIGNAL)) - return NULL; - - if (((event->sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) && - ((event->sigev_signo <= 0) || (event->sigev_signo > SIGRTMAX))) - return NULL; - - return task_pid(rtn); -} - -void posix_timers_register_clock(const clockid_t clock_id, - struct k_clock *new_clock) -{ - if ((unsigned) clock_id >= MAX_CLOCKS) { - printk(KERN_WARNING "POSIX clock register failed for clock_id %d\n", - clock_id); - return; - } - - if (!new_clock->clock_get) { - printk(KERN_WARNING "POSIX clock id %d lacks clock_get()\n", - clock_id); - return; - } - if (!new_clock->clock_getres) { - printk(KERN_WARNING "POSIX clock id %d lacks clock_getres()\n", - clock_id); - return; - } - - posix_clocks[clock_id] = *new_clock; -} -EXPORT_SYMBOL_GPL(posix_timers_register_clock); - -static struct k_itimer * alloc_posix_timer(void) -{ - struct k_itimer *tmr; - tmr = kmem_cache_zalloc(posix_timers_cache, GFP_KERNEL); - if (!tmr) - return tmr; - if (unlikely(!(tmr->sigq = sigqueue_alloc()))) { - kmem_cache_free(posix_timers_cache, tmr); - return NULL; - } - memset(&tmr->sigq->info, 0, sizeof(siginfo_t)); - return tmr; -} - -static void k_itimer_rcu_free(struct rcu_head *head) -{ - struct k_itimer *tmr = container_of(head, struct k_itimer, it.rcu); - - kmem_cache_free(posix_timers_cache, tmr); -} - -#define IT_ID_SET 1 -#define IT_ID_NOT_SET 0 -static void release_posix_timer(struct k_itimer *tmr, int it_id_set) -{ - if (it_id_set) { - unsigned long flags; - spin_lock_irqsave(&hash_lock, flags); - hlist_del_rcu(&tmr->t_hash); - spin_unlock_irqrestore(&hash_lock, flags); - } - put_pid(tmr->it_pid); - sigqueue_free(tmr->sigq); - call_rcu(&tmr->it.rcu, k_itimer_rcu_free); -} - -static struct k_clock *clockid_to_kclock(const clockid_t id) -{ - if (id < 0) - return (id & CLOCKFD_MASK) == CLOCKFD ? - &clock_posix_dynamic : &clock_posix_cpu; - - if (id >= MAX_CLOCKS || !posix_clocks[id].clock_getres) - return NULL; - return &posix_clocks[id]; -} - -static int common_timer_create(struct k_itimer *new_timer) -{ - hrtimer_init(&new_timer->it.real.timer, new_timer->it_clock, 0); - return 0; -} - -/* Create a POSIX.1b interval timer. */ - -SYSCALL_DEFINE3(timer_create, const clockid_t, which_clock, - struct sigevent __user *, timer_event_spec, - timer_t __user *, created_timer_id) -{ - struct k_clock *kc = clockid_to_kclock(which_clock); - struct k_itimer *new_timer; - int error, new_timer_id; - sigevent_t event; - int it_id_set = IT_ID_NOT_SET; - - if (!kc) - return -EINVAL; - if (!kc->timer_create) - return -EOPNOTSUPP; - - new_timer = alloc_posix_timer(); - if (unlikely(!new_timer)) - return -EAGAIN; - - spin_lock_init(&new_timer->it_lock); - new_timer_id = posix_timer_add(new_timer); - if (new_timer_id < 0) { - error = new_timer_id; - goto out; - } - - it_id_set = IT_ID_SET; - new_timer->it_id = (timer_t) new_timer_id; - new_timer->it_clock = which_clock; - new_timer->it_overrun = -1; - - if (timer_event_spec) { - if (copy_from_user(&event, timer_event_spec, sizeof (event))) { - error = -EFAULT; - goto out; - } - rcu_read_lock(); - new_timer->it_pid = get_pid(good_sigevent(&event)); - rcu_read_unlock(); - if (!new_timer->it_pid) { - error = -EINVAL; - goto out; - } - } else { - memset(&event.sigev_value, 0, sizeof(event.sigev_value)); - event.sigev_notify = SIGEV_SIGNAL; - event.sigev_signo = SIGALRM; - event.sigev_value.sival_int = new_timer->it_id; - new_timer->it_pid = get_pid(task_tgid(current)); - } - - new_timer->it_sigev_notify = event.sigev_notify; - new_timer->sigq->info.si_signo = event.sigev_signo; - new_timer->sigq->info.si_value = event.sigev_value; - new_timer->sigq->info.si_tid = new_timer->it_id; - new_timer->sigq->info.si_code = SI_TIMER; - - if (copy_to_user(created_timer_id, - &new_timer_id, sizeof (new_timer_id))) { - error = -EFAULT; - goto out; - } - - error = kc->timer_create(new_timer); - if (error) - goto out; - - spin_lock_irq(¤t->sighand->siglock); - new_timer->it_signal = current->signal; - list_add(&new_timer->list, ¤t->signal->posix_timers); - spin_unlock_irq(¤t->sighand->siglock); - - return 0; - /* - * In the case of the timer belonging to another task, after - * the task is unlocked, the timer is owned by the other task - * and may cease to exist at any time. Don't use or modify - * new_timer after the unlock call. - */ -out: - release_posix_timer(new_timer, it_id_set); - return error; -} - -/* - * Locking issues: We need to protect the result of the id look up until - * we get the timer locked down so it is not deleted under us. The - * removal is done under the idr spinlock so we use that here to bridge - * the find to the timer lock. To avoid a dead lock, the timer id MUST - * be release with out holding the timer lock. - */ -static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags) -{ - struct k_itimer *timr; - - /* - * timer_t could be any type >= int and we want to make sure any - * @timer_id outside positive int range fails lookup. - */ - if ((unsigned long long)timer_id > INT_MAX) - return NULL; - - rcu_read_lock(); - timr = posix_timer_by_id(timer_id); - if (timr) { - spin_lock_irqsave(&timr->it_lock, *flags); - if (timr->it_signal == current->signal) { - rcu_read_unlock(); - return timr; - } - spin_unlock_irqrestore(&timr->it_lock, *flags); - } - rcu_read_unlock(); - - return NULL; -} - -/* - * Get the time remaining on a POSIX.1b interval timer. This function - * is ALWAYS called with spin_lock_irq on the timer, thus it must not - * mess with irq. - * - * We have a couple of messes to clean up here. First there is the case - * of a timer that has a requeue pending. These timers should appear to - * be in the timer list with an expiry as if we were to requeue them - * now. - * - * The second issue is the SIGEV_NONE timer which may be active but is - * not really ever put in the timer list (to save system resources). - * This timer may be expired, and if so, we will do it here. Otherwise - * it is the same as a requeue pending timer WRT to what we should - * report. - */ -static void -common_timer_get(struct k_itimer *timr, struct itimerspec *cur_setting) -{ - ktime_t now, remaining, iv; - struct hrtimer *timer = &timr->it.real.timer; - - memset(cur_setting, 0, sizeof(struct itimerspec)); - - iv = timr->it.real.interval; - - /* interval timer ? */ - if (iv.tv64) - cur_setting->it_interval = ktime_to_timespec(iv); - else if (!hrtimer_active(timer) && - (timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) - return; - - now = timer->base->get_time(); - - /* - * When a requeue is pending or this is a SIGEV_NONE - * timer move the expiry time forward by intervals, so - * expiry is > now. - */ - if (iv.tv64 && (timr->it_requeue_pending & REQUEUE_PENDING || - (timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) - timr->it_overrun += (unsigned int) hrtimer_forward(timer, now, iv); - - remaining = __hrtimer_expires_remaining_adjusted(timer, now); - /* Return 0 only, when the timer is expired and not pending */ - if (remaining.tv64 <= 0) { - /* - * A single shot SIGEV_NONE timer must return 0, when - * it is expired ! - */ - if ((timr->it_sigev_notify & ~SIGEV_THREAD_ID) != SIGEV_NONE) - cur_setting->it_value.tv_nsec = 1; - } else - cur_setting->it_value = ktime_to_timespec(remaining); -} - -/* Get the time remaining on a POSIX.1b interval timer. */ -SYSCALL_DEFINE2(timer_gettime, timer_t, timer_id, - struct itimerspec __user *, setting) -{ - struct itimerspec cur_setting; - struct k_itimer *timr; - struct k_clock *kc; - unsigned long flags; - int ret = 0; - - timr = lock_timer(timer_id, &flags); - if (!timr) - return -EINVAL; - - kc = clockid_to_kclock(timr->it_clock); - if (WARN_ON_ONCE(!kc || !kc->timer_get)) - ret = -EINVAL; - else - kc->timer_get(timr, &cur_setting); - - unlock_timer(timr, flags); - - if (!ret && copy_to_user(setting, &cur_setting, sizeof (cur_setting))) - return -EFAULT; - - return ret; -} - -/* - * Get the number of overruns of a POSIX.1b interval timer. This is to - * be the overrun of the timer last delivered. At the same time we are - * accumulating overruns on the next timer. The overrun is frozen when - * the signal is delivered, either at the notify time (if the info block - * is not queued) or at the actual delivery time (as we are informed by - * the call back to do_schedule_next_timer(). So all we need to do is - * to pick up the frozen overrun. - */ -SYSCALL_DEFINE1(timer_getoverrun, timer_t, timer_id) -{ - struct k_itimer *timr; - int overrun; - unsigned long flags; - - timr = lock_timer(timer_id, &flags); - if (!timr) - return -EINVAL; - - overrun = timr->it_overrun_last; - unlock_timer(timr, flags); - - return overrun; -} - -/* Set a POSIX.1b interval timer. */ -/* timr->it_lock is taken. */ -static int -common_timer_set(struct k_itimer *timr, int flags, - struct itimerspec *new_setting, struct itimerspec *old_setting) -{ - struct hrtimer *timer = &timr->it.real.timer; - enum hrtimer_mode mode; - - if (old_setting) - common_timer_get(timr, old_setting); - - /* disable the timer */ - timr->it.real.interval.tv64 = 0; - /* - * careful here. If smp we could be in the "fire" routine which will - * be spinning as we hold the lock. But this is ONLY an SMP issue. - */ - if (hrtimer_try_to_cancel(timer) < 0) - return TIMER_RETRY; - - timr->it_requeue_pending = (timr->it_requeue_pending + 2) & - ~REQUEUE_PENDING; - timr->it_overrun_last = 0; - - /* switch off the timer when it_value is zero */ - if (!new_setting->it_value.tv_sec && !new_setting->it_value.tv_nsec) - return 0; - - mode = flags & TIMER_ABSTIME ? HRTIMER_MODE_ABS : HRTIMER_MODE_REL; - hrtimer_init(&timr->it.real.timer, timr->it_clock, mode); - timr->it.real.timer.function = posix_timer_fn; - - hrtimer_set_expires(timer, timespec_to_ktime(new_setting->it_value)); - - /* Convert interval */ - timr->it.real.interval = timespec_to_ktime(new_setting->it_interval); - - /* SIGEV_NONE timers are not queued ! See common_timer_get */ - if (((timr->it_sigev_notify & ~SIGEV_THREAD_ID) == SIGEV_NONE)) { - /* Setup correct expiry time for relative timers */ - if (mode == HRTIMER_MODE_REL) { - hrtimer_add_expires(timer, timer->base->get_time()); - } - return 0; - } - - hrtimer_start_expires(timer, mode); - return 0; -} - -/* Set a POSIX.1b interval timer */ -SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, - const struct itimerspec __user *, new_setting, - struct itimerspec __user *, old_setting) -{ - struct k_itimer *timr; - struct itimerspec new_spec, old_spec; - int error = 0; - unsigned long flag; - struct itimerspec *rtn = old_setting ? &old_spec : NULL; - struct k_clock *kc; - - if (!new_setting) - return -EINVAL; - - if (copy_from_user(&new_spec, new_setting, sizeof (new_spec))) - return -EFAULT; - - if (!timespec_valid(&new_spec.it_interval) || - !timespec_valid(&new_spec.it_value)) - return -EINVAL; -retry: - timr = lock_timer(timer_id, &flag); - if (!timr) - return -EINVAL; - - kc = clockid_to_kclock(timr->it_clock); - if (WARN_ON_ONCE(!kc || !kc->timer_set)) - error = -EINVAL; - else - error = kc->timer_set(timr, flags, &new_spec, rtn); - - unlock_timer(timr, flag); - if (error == TIMER_RETRY) { - rtn = NULL; // We already got the old time... - goto retry; - } - - if (old_setting && !error && - copy_to_user(old_setting, &old_spec, sizeof (old_spec))) - error = -EFAULT; - - return error; -} - -static int common_timer_del(struct k_itimer *timer) -{ - timer->it.real.interval.tv64 = 0; - - if (hrtimer_try_to_cancel(&timer->it.real.timer) < 0) - return TIMER_RETRY; - return 0; -} - -static inline int timer_delete_hook(struct k_itimer *timer) -{ - struct k_clock *kc = clockid_to_kclock(timer->it_clock); - - if (WARN_ON_ONCE(!kc || !kc->timer_del)) - return -EINVAL; - return kc->timer_del(timer); -} - -/* Delete a POSIX.1b interval timer. */ -SYSCALL_DEFINE1(timer_delete, timer_t, timer_id) -{ - struct k_itimer *timer; - unsigned long flags; - -retry_delete: - timer = lock_timer(timer_id, &flags); - if (!timer) - return -EINVAL; - - if (timer_delete_hook(timer) == TIMER_RETRY) { - unlock_timer(timer, flags); - goto retry_delete; - } - - spin_lock(¤t->sighand->siglock); - list_del(&timer->list); - spin_unlock(¤t->sighand->siglock); - /* - * This keeps any tasks waiting on the spin lock from thinking - * they got something (see the lock code above). - */ - timer->it_signal = NULL; - - unlock_timer(timer, flags); - release_posix_timer(timer, IT_ID_SET); - return 0; -} - -/* - * return timer owned by the process, used by exit_itimers - */ -static void itimer_delete(struct k_itimer *timer) -{ - unsigned long flags; - -retry_delete: - spin_lock_irqsave(&timer->it_lock, flags); - - if (timer_delete_hook(timer) == TIMER_RETRY) { - unlock_timer(timer, flags); - goto retry_delete; - } - list_del(&timer->list); - /* - * This keeps any tasks waiting on the spin lock from thinking - * they got something (see the lock code above). - */ - timer->it_signal = NULL; - - unlock_timer(timer, flags); - release_posix_timer(timer, IT_ID_SET); -} - -/* - * This is called by do_exit or de_thread, only when there are no more - * references to the shared signal_struct. - */ -void exit_itimers(struct signal_struct *sig) -{ - struct k_itimer *tmr; - - while (!list_empty(&sig->posix_timers)) { - tmr = list_entry(sig->posix_timers.next, struct k_itimer, list); - itimer_delete(tmr); - } -} - -SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock, - const struct timespec __user *, tp) -{ - struct k_clock *kc = clockid_to_kclock(which_clock); - struct timespec new_tp; - - if (!kc || !kc->clock_set) - return -EINVAL; - - if (copy_from_user(&new_tp, tp, sizeof (*tp))) - return -EFAULT; - - return kc->clock_set(which_clock, &new_tp); -} - -SYSCALL_DEFINE2(clock_gettime, const clockid_t, which_clock, - struct timespec __user *,tp) -{ - struct k_clock *kc = clockid_to_kclock(which_clock); - struct timespec kernel_tp; - int error; - - if (!kc) - return -EINVAL; - - error = kc->clock_get(which_clock, &kernel_tp); - - if (!error && copy_to_user(tp, &kernel_tp, sizeof (kernel_tp))) - error = -EFAULT; - - return error; -} - -SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock, - struct timex __user *, utx) -{ - struct k_clock *kc = clockid_to_kclock(which_clock); - struct timex ktx; - int err; - - if (!kc) - return -EINVAL; - if (!kc->clock_adj) - return -EOPNOTSUPP; - - if (copy_from_user(&ktx, utx, sizeof(ktx))) - return -EFAULT; - - err = kc->clock_adj(which_clock, &ktx); - - if (err >= 0 && copy_to_user(utx, &ktx, sizeof(ktx))) - return -EFAULT; - - return err; -} - -SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, - struct timespec __user *, tp) -{ - struct k_clock *kc = clockid_to_kclock(which_clock); - struct timespec rtn_tp; - int error; - - if (!kc) - return -EINVAL; - - error = kc->clock_getres(which_clock, &rtn_tp); - - if (!error && tp && copy_to_user(tp, &rtn_tp, sizeof (rtn_tp))) - error = -EFAULT; - - return error; -} - -/* - * nanosleep for monotonic and realtime clocks - */ -static int common_nsleep(const clockid_t which_clock, int flags, - struct timespec *tsave, struct timespec __user *rmtp) -{ - return hrtimer_nanosleep(tsave, rmtp, flags & TIMER_ABSTIME ? - HRTIMER_MODE_ABS : HRTIMER_MODE_REL, - which_clock); -} - -SYSCALL_DEFINE4(clock_nanosleep, const clockid_t, which_clock, int, flags, - const struct timespec __user *, rqtp, - struct timespec __user *, rmtp) -{ - struct k_clock *kc = clockid_to_kclock(which_clock); - struct timespec t; - - if (!kc) - return -EINVAL; - if (!kc->nsleep) - return -ENANOSLEEP_NOTSUP; - - if (copy_from_user(&t, rqtp, sizeof (struct timespec))) - return -EFAULT; - - if (!timespec_valid(&t)) - return -EINVAL; - - return kc->nsleep(which_clock, flags, &t, rmtp); -} - -/* - * This will restart clock_nanosleep. This is required only by - * compat_clock_nanosleep_restart for now. - */ -long clock_nanosleep_restart(struct restart_block *restart_block) -{ - clockid_t which_clock = restart_block->nanosleep.clockid; - struct k_clock *kc = clockid_to_kclock(which_clock); - - if (WARN_ON_ONCE(!kc || !kc->nsleep_restart)) - return -EINVAL; - - return kc->nsleep_restart(restart_block); -} diff --git a/src/linux/kernel/time/tick-common.c b/src/linux/kernel/time/tick-common.c deleted file mode 100644 index 4fcd99e..0000000 --- a/src/linux/kernel/time/tick-common.c +++ /dev/null @@ -1,535 +0,0 @@ -/* - * linux/kernel/time/tick-common.c - * - * This file contains the base functions to manage periodic tick - * related events. - * - * Copyright(C) 2005-2006, Thomas Gleixner - * Copyright(C) 2005-2007, Red Hat, Inc., Ingo Molnar - * Copyright(C) 2006-2007, Timesys Corp., Thomas Gleixner - * - * This code is licenced under the GPL version 2. For details see - * kernel-base/COPYING. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "tick-internal.h" - -/* - * Tick devices - */ -DEFINE_PER_CPU(struct tick_device, tick_cpu_device); -/* - * Tick next event: keeps track of the tick time - */ -ktime_t tick_next_period; -ktime_t tick_period; - -/* - * tick_do_timer_cpu is a timer core internal variable which holds the CPU NR - * which is responsible for calling do_timer(), i.e. the timekeeping stuff. This - * variable has two functions: - * - * 1) Prevent a thundering herd issue of a gazillion of CPUs trying to grab the - * timekeeping lock all at once. Only the CPU which is assigned to do the - * update is handling it. - * - * 2) Hand off the duty in the NOHZ idle case by setting the value to - * TICK_DO_TIMER_NONE, i.e. a non existing CPU. So the next cpu which looks - * at it will take over and keep the time keeping alive. The handover - * procedure also covers cpu hotplug. - */ -int tick_do_timer_cpu __read_mostly = TICK_DO_TIMER_BOOT; - -/* - * Debugging: see timer_list.c - */ -struct tick_device *tick_get_device(int cpu) -{ - return &per_cpu(tick_cpu_device, cpu); -} - -/** - * tick_is_oneshot_available - check for a oneshot capable event device - */ -int tick_is_oneshot_available(void) -{ - struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); - - if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT)) - return 0; - if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) - return 1; - return tick_broadcast_oneshot_available(); -} - -/* - * Periodic tick - */ -static void tick_periodic(int cpu) -{ - if (tick_do_timer_cpu == cpu) { - write_seqlock(&jiffies_lock); - - /* Keep track of the next tick event */ - tick_next_period = ktime_add(tick_next_period, tick_period); - - do_timer(1); - write_sequnlock(&jiffies_lock); - update_wall_time(); - } - - update_process_times(user_mode(get_irq_regs())); - profile_tick(CPU_PROFILING); -} - -/* - * Event handler for periodic ticks - */ -void tick_handle_periodic(struct clock_event_device *dev) -{ - int cpu = smp_processor_id(); - ktime_t next = dev->next_event; - - tick_periodic(cpu); - -#if defined(CONFIG_HIGH_RES_TIMERS) || defined(CONFIG_NO_HZ_COMMON) - /* - * The cpu might have transitioned to HIGHRES or NOHZ mode via - * update_process_times() -> run_local_timers() -> - * hrtimer_run_queues(). - */ - if (dev->event_handler != tick_handle_periodic) - return; -#endif - - if (!clockevent_state_oneshot(dev)) - return; - for (;;) { - /* - * Setup the next period for devices, which do not have - * periodic mode: - */ - next = ktime_add(next, tick_period); - - if (!clockevents_program_event(dev, next, false)) - return; - /* - * Have to be careful here. If we're in oneshot mode, - * before we call tick_periodic() in a loop, we need - * to be sure we're using a real hardware clocksource. - * Otherwise we could get trapped in an infinite - * loop, as the tick_periodic() increments jiffies, - * which then will increment time, possibly causing - * the loop to trigger again and again. - */ - if (timekeeping_valid_for_hres()) - tick_periodic(cpu); - } -} - -/* - * Setup the device for a periodic tick - */ -void tick_setup_periodic(struct clock_event_device *dev, int broadcast) -{ - tick_set_periodic_handler(dev, broadcast); - - /* Broadcast setup ? */ - if (!tick_device_is_functional(dev)) - return; - - if ((dev->features & CLOCK_EVT_FEAT_PERIODIC) && - !tick_broadcast_oneshot_active()) { - clockevents_switch_state(dev, CLOCK_EVT_STATE_PERIODIC); - } else { - unsigned long seq; - ktime_t next; - - do { - seq = read_seqbegin(&jiffies_lock); - next = tick_next_period; - } while (read_seqretry(&jiffies_lock, seq)); - - clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT); - - for (;;) { - if (!clockevents_program_event(dev, next, false)) - return; - next = ktime_add(next, tick_period); - } - } -} - -/* - * Setup the tick device - */ -static void tick_setup_device(struct tick_device *td, - struct clock_event_device *newdev, int cpu, - const struct cpumask *cpumask) -{ - ktime_t next_event; - void (*handler)(struct clock_event_device *) = NULL; - - /* - * First device setup ? - */ - if (!td->evtdev) { - /* - * If no cpu took the do_timer update, assign it to - * this cpu: - */ - if (tick_do_timer_cpu == TICK_DO_TIMER_BOOT) { - if (!tick_nohz_full_cpu(cpu)) - tick_do_timer_cpu = cpu; - else - tick_do_timer_cpu = TICK_DO_TIMER_NONE; - tick_next_period = ktime_get(); - tick_period = ktime_set(0, NSEC_PER_SEC / HZ); - } - - /* - * Startup in periodic mode first. - */ - td->mode = TICKDEV_MODE_PERIODIC; - } else { - handler = td->evtdev->event_handler; - next_event = td->evtdev->next_event; - td->evtdev->event_handler = clockevents_handle_noop; - } - - td->evtdev = newdev; - - /* - * When the device is not per cpu, pin the interrupt to the - * current cpu: - */ - if (!cpumask_equal(newdev->cpumask, cpumask)) - irq_set_affinity(newdev->irq, cpumask); - - /* - * When global broadcasting is active, check if the current - * device is registered as a placeholder for broadcast mode. - * This allows us to handle this x86 misfeature in a generic - * way. This function also returns !=0 when we keep the - * current active broadcast state for this CPU. - */ - if (tick_device_uses_broadcast(newdev, cpu)) - return; - - if (td->mode == TICKDEV_MODE_PERIODIC) - tick_setup_periodic(newdev, 0); - else - tick_setup_oneshot(newdev, handler, next_event); -} - -void tick_install_replacement(struct clock_event_device *newdev) -{ - struct tick_device *td = this_cpu_ptr(&tick_cpu_device); - int cpu = smp_processor_id(); - - clockevents_exchange_device(td->evtdev, newdev); - tick_setup_device(td, newdev, cpu, cpumask_of(cpu)); - if (newdev->features & CLOCK_EVT_FEAT_ONESHOT) - tick_oneshot_notify(); -} - -static bool tick_check_percpu(struct clock_event_device *curdev, - struct clock_event_device *newdev, int cpu) -{ - if (!cpumask_test_cpu(cpu, newdev->cpumask)) - return false; - if (cpumask_equal(newdev->cpumask, cpumask_of(cpu))) - return true; - /* Check if irq affinity can be set */ - if (newdev->irq >= 0 && !irq_can_set_affinity(newdev->irq)) - return false; - /* Prefer an existing cpu local device */ - if (curdev && cpumask_equal(curdev->cpumask, cpumask_of(cpu))) - return false; - return true; -} - -static bool tick_check_preferred(struct clock_event_device *curdev, - struct clock_event_device *newdev) -{ - /* Prefer oneshot capable device */ - if (!(newdev->features & CLOCK_EVT_FEAT_ONESHOT)) { - if (curdev && (curdev->features & CLOCK_EVT_FEAT_ONESHOT)) - return false; - if (tick_oneshot_mode_active()) - return false; - } - - /* - * Use the higher rated one, but prefer a CPU local device with a lower - * rating than a non-CPU local device - */ - return !curdev || - newdev->rating > curdev->rating || - !cpumask_equal(curdev->cpumask, newdev->cpumask); -} - -/* - * Check whether the new device is a better fit than curdev. curdev - * can be NULL ! - */ -bool tick_check_replacement(struct clock_event_device *curdev, - struct clock_event_device *newdev) -{ - if (!tick_check_percpu(curdev, newdev, smp_processor_id())) - return false; - - return tick_check_preferred(curdev, newdev); -} - -/* - * Check, if the new registered device should be used. Called with - * clockevents_lock held and interrupts disabled. - */ -void tick_check_new_device(struct clock_event_device *newdev) -{ - struct clock_event_device *curdev; - struct tick_device *td; - int cpu; - - cpu = smp_processor_id(); - td = &per_cpu(tick_cpu_device, cpu); - curdev = td->evtdev; - - /* cpu local device ? */ - if (!tick_check_percpu(curdev, newdev, cpu)) - goto out_bc; - - /* Preference decision */ - if (!tick_check_preferred(curdev, newdev)) - goto out_bc; - - if (!try_module_get(newdev->owner)) - return; - - /* - * Replace the eventually existing device by the new - * device. If the current device is the broadcast device, do - * not give it back to the clockevents layer ! - */ - if (tick_is_broadcast_device(curdev)) { - clockevents_shutdown(curdev); - curdev = NULL; - } - clockevents_exchange_device(curdev, newdev); - tick_setup_device(td, newdev, cpu, cpumask_of(cpu)); - if (newdev->features & CLOCK_EVT_FEAT_ONESHOT) - tick_oneshot_notify(); - return; - -out_bc: - /* - * Can the new device be used as a broadcast device ? - */ - tick_install_broadcast_device(newdev); -} - -/** - * tick_broadcast_oneshot_control - Enter/exit broadcast oneshot mode - * @state: The target state (enter/exit) - * - * The system enters/leaves a state, where affected devices might stop - * Returns 0 on success, -EBUSY if the cpu is used to broadcast wakeups. - * - * Called with interrupts disabled, so clockevents_lock is not - * required here because the local clock event device cannot go away - * under us. - */ -int tick_broadcast_oneshot_control(enum tick_broadcast_state state) -{ - struct tick_device *td = this_cpu_ptr(&tick_cpu_device); - - if (!(td->evtdev->features & CLOCK_EVT_FEAT_C3STOP)) - return 0; - - return __tick_broadcast_oneshot_control(state); -} -EXPORT_SYMBOL_GPL(tick_broadcast_oneshot_control); - -#ifdef CONFIG_HOTPLUG_CPU -/* - * Transfer the do_timer job away from a dying cpu. - * - * Called with interrupts disabled. Not locking required. If - * tick_do_timer_cpu is owned by this cpu, nothing can change it. - */ -void tick_handover_do_timer(void) -{ - if (tick_do_timer_cpu == smp_processor_id()) { - int cpu = cpumask_first(cpu_online_mask); - - tick_do_timer_cpu = (cpu < nr_cpu_ids) ? cpu : - TICK_DO_TIMER_NONE; - } -} - -/* - * Shutdown an event device on a given cpu: - * - * This is called on a life CPU, when a CPU is dead. So we cannot - * access the hardware device itself. - * We just set the mode and remove it from the lists. - */ -void tick_shutdown(unsigned int cpu) -{ - struct tick_device *td = &per_cpu(tick_cpu_device, cpu); - struct clock_event_device *dev = td->evtdev; - - td->mode = TICKDEV_MODE_PERIODIC; - if (dev) { - /* - * Prevent that the clock events layer tries to call - * the set mode function! - */ - clockevent_set_state(dev, CLOCK_EVT_STATE_DETACHED); - clockevents_exchange_device(dev, NULL); - dev->event_handler = clockevents_handle_noop; - td->evtdev = NULL; - } -} -#endif - -/** - * tick_suspend_local - Suspend the local tick device - * - * Called from the local cpu for freeze with interrupts disabled. - * - * No locks required. Nothing can change the per cpu device. - */ -void tick_suspend_local(void) -{ - struct tick_device *td = this_cpu_ptr(&tick_cpu_device); - - clockevents_shutdown(td->evtdev); -} - -/** - * tick_resume_local - Resume the local tick device - * - * Called from the local CPU for unfreeze or XEN resume magic. - * - * No locks required. Nothing can change the per cpu device. - */ -void tick_resume_local(void) -{ - struct tick_device *td = this_cpu_ptr(&tick_cpu_device); - bool broadcast = tick_resume_check_broadcast(); - - clockevents_tick_resume(td->evtdev); - if (!broadcast) { - if (td->mode == TICKDEV_MODE_PERIODIC) - tick_setup_periodic(td->evtdev, 0); - else - tick_resume_oneshot(); - } -} - -/** - * tick_suspend - Suspend the tick and the broadcast device - * - * Called from syscore_suspend() via timekeeping_suspend with only one - * CPU online and interrupts disabled or from tick_unfreeze() under - * tick_freeze_lock. - * - * No locks required. Nothing can change the per cpu device. - */ -void tick_suspend(void) -{ - tick_suspend_local(); - tick_suspend_broadcast(); -} - -/** - * tick_resume - Resume the tick and the broadcast device - * - * Called from syscore_resume() via timekeeping_resume with only one - * CPU online and interrupts disabled. - * - * No locks required. Nothing can change the per cpu device. - */ -void tick_resume(void) -{ - tick_resume_broadcast(); - tick_resume_local(); -} - -#ifdef CONFIG_SUSPEND -static DEFINE_RAW_SPINLOCK(tick_freeze_lock); -static unsigned int tick_freeze_depth; - -/** - * tick_freeze - Suspend the local tick and (possibly) timekeeping. - * - * Check if this is the last online CPU executing the function and if so, - * suspend timekeeping. Otherwise suspend the local tick. - * - * Call with interrupts disabled. Must be balanced with %tick_unfreeze(). - * Interrupts must not be enabled before the subsequent %tick_unfreeze(). - */ -void tick_freeze(void) -{ - raw_spin_lock(&tick_freeze_lock); - - tick_freeze_depth++; - if (tick_freeze_depth == num_online_cpus()) { - trace_suspend_resume(TPS("timekeeping_freeze"), - smp_processor_id(), true); - timekeeping_suspend(); - } else { - tick_suspend_local(); - } - - raw_spin_unlock(&tick_freeze_lock); -} - -/** - * tick_unfreeze - Resume the local tick and (possibly) timekeeping. - * - * Check if this is the first CPU executing the function and if so, resume - * timekeeping. Otherwise resume the local tick. - * - * Call with interrupts disabled. Must be balanced with %tick_freeze(). - * Interrupts must not be enabled after the preceding %tick_freeze(). - */ -void tick_unfreeze(void) -{ - raw_spin_lock(&tick_freeze_lock); - - if (tick_freeze_depth == num_online_cpus()) { - timekeeping_resume(); - trace_suspend_resume(TPS("timekeeping_freeze"), - smp_processor_id(), false); - } else { - tick_resume_local(); - } - - tick_freeze_depth--; - - raw_spin_unlock(&tick_freeze_lock); -} -#endif /* CONFIG_SUSPEND */ - -/** - * tick_init - initialize the tick control - */ -void __init tick_init(void) -{ - tick_broadcast_init(); - tick_nohz_init(); -} diff --git a/src/linux/kernel/time/tick-internal.h b/src/linux/kernel/time/tick-internal.h deleted file mode 100644 index f738251..0000000 --- a/src/linux/kernel/time/tick-internal.h +++ /dev/null @@ -1,167 +0,0 @@ -/* - * tick internal variable and functions used by low/high res code - */ -#include -#include - -#include "timekeeping.h" -#include "tick-sched.h" - -#ifdef CONFIG_GENERIC_CLOCKEVENTS - -# define TICK_DO_TIMER_NONE -1 -# define TICK_DO_TIMER_BOOT -2 - -DECLARE_PER_CPU(struct tick_device, tick_cpu_device); -extern ktime_t tick_next_period; -extern ktime_t tick_period; -extern int tick_do_timer_cpu __read_mostly; - -extern void tick_setup_periodic(struct clock_event_device *dev, int broadcast); -extern void tick_handle_periodic(struct clock_event_device *dev); -extern void tick_check_new_device(struct clock_event_device *dev); -extern void tick_shutdown(unsigned int cpu); -extern void tick_suspend(void); -extern void tick_resume(void); -extern bool tick_check_replacement(struct clock_event_device *curdev, - struct clock_event_device *newdev); -extern void tick_install_replacement(struct clock_event_device *dev); -extern int tick_is_oneshot_available(void); -extern struct tick_device *tick_get_device(int cpu); - -extern int clockevents_tick_resume(struct clock_event_device *dev); -/* Check, if the device is functional or a dummy for broadcast */ -static inline int tick_device_is_functional(struct clock_event_device *dev) -{ - return !(dev->features & CLOCK_EVT_FEAT_DUMMY); -} - -static inline enum clock_event_state clockevent_get_state(struct clock_event_device *dev) -{ - return dev->state_use_accessors; -} - -static inline void clockevent_set_state(struct clock_event_device *dev, - enum clock_event_state state) -{ - dev->state_use_accessors = state; -} - -extern void clockevents_shutdown(struct clock_event_device *dev); -extern void clockevents_exchange_device(struct clock_event_device *old, - struct clock_event_device *new); -extern void clockevents_switch_state(struct clock_event_device *dev, - enum clock_event_state state); -extern int clockevents_program_event(struct clock_event_device *dev, - ktime_t expires, bool force); -extern void clockevents_handle_noop(struct clock_event_device *dev); -extern int __clockevents_update_freq(struct clock_event_device *dev, u32 freq); -extern ssize_t sysfs_get_uname(const char *buf, char *dst, size_t cnt); - -/* Broadcasting support */ -# ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST -extern int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu); -extern void tick_install_broadcast_device(struct clock_event_device *dev); -extern int tick_is_broadcast_device(struct clock_event_device *dev); -extern void tick_shutdown_broadcast(unsigned int cpu); -extern void tick_suspend_broadcast(void); -extern void tick_resume_broadcast(void); -extern bool tick_resume_check_broadcast(void); -extern void tick_broadcast_init(void); -extern void tick_set_periodic_handler(struct clock_event_device *dev, int broadcast); -extern int tick_broadcast_update_freq(struct clock_event_device *dev, u32 freq); -extern struct tick_device *tick_get_broadcast_device(void); -extern struct cpumask *tick_get_broadcast_mask(void); -# else /* !CONFIG_GENERIC_CLOCKEVENTS_BROADCAST: */ -static inline void tick_install_broadcast_device(struct clock_event_device *dev) { } -static inline int tick_is_broadcast_device(struct clock_event_device *dev) { return 0; } -static inline int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) { return 0; } -static inline void tick_do_periodic_broadcast(struct clock_event_device *d) { } -static inline void tick_shutdown_broadcast(unsigned int cpu) { } -static inline void tick_suspend_broadcast(void) { } -static inline void tick_resume_broadcast(void) { } -static inline bool tick_resume_check_broadcast(void) { return false; } -static inline void tick_broadcast_init(void) { } -static inline int tick_broadcast_update_freq(struct clock_event_device *dev, u32 freq) { return -ENODEV; } - -/* Set the periodic handler in non broadcast mode */ -static inline void tick_set_periodic_handler(struct clock_event_device *dev, int broadcast) -{ - dev->event_handler = tick_handle_periodic; -} -# endif /* !CONFIG_GENERIC_CLOCKEVENTS_BROADCAST */ - -#else /* !GENERIC_CLOCKEVENTS: */ -static inline void tick_suspend(void) { } -static inline void tick_resume(void) { } -#endif /* !GENERIC_CLOCKEVENTS */ - -/* Oneshot related functions */ -#ifdef CONFIG_TICK_ONESHOT -extern void tick_setup_oneshot(struct clock_event_device *newdev, - void (*handler)(struct clock_event_device *), - ktime_t nextevt); -extern int tick_program_event(ktime_t expires, int force); -extern void tick_oneshot_notify(void); -extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)); -extern void tick_resume_oneshot(void); -static inline bool tick_oneshot_possible(void) { return true; } -extern int tick_oneshot_mode_active(void); -extern void tick_clock_notify(void); -extern int tick_check_oneshot_change(int allow_nohz); -extern int tick_init_highres(void); -#else /* !CONFIG_TICK_ONESHOT: */ -static inline -void tick_setup_oneshot(struct clock_event_device *newdev, - void (*handler)(struct clock_event_device *), - ktime_t nextevt) { BUG(); } -static inline void tick_resume_oneshot(void) { BUG(); } -static inline int tick_program_event(ktime_t expires, int force) { return 0; } -static inline void tick_oneshot_notify(void) { } -static inline bool tick_oneshot_possible(void) { return false; } -static inline int tick_oneshot_mode_active(void) { return 0; } -static inline void tick_clock_notify(void) { } -static inline int tick_check_oneshot_change(int allow_nohz) { return 0; } -#endif /* !CONFIG_TICK_ONESHOT */ - -/* Functions related to oneshot broadcasting */ -#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_TICK_ONESHOT) -extern void tick_broadcast_setup_oneshot(struct clock_event_device *bc); -extern void tick_broadcast_switch_to_oneshot(void); -extern void tick_shutdown_broadcast_oneshot(unsigned int cpu); -extern int tick_broadcast_oneshot_active(void); -extern void tick_check_oneshot_broadcast_this_cpu(void); -bool tick_broadcast_oneshot_available(void); -extern struct cpumask *tick_get_broadcast_oneshot_mask(void); -#else /* !(BROADCAST && ONESHOT): */ -static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc) { BUG(); } -static inline void tick_broadcast_switch_to_oneshot(void) { } -static inline void tick_shutdown_broadcast_oneshot(unsigned int cpu) { } -static inline int tick_broadcast_oneshot_active(void) { return 0; } -static inline void tick_check_oneshot_broadcast_this_cpu(void) { } -static inline bool tick_broadcast_oneshot_available(void) { return tick_oneshot_possible(); } -#endif /* !(BROADCAST && ONESHOT) */ - -/* NO_HZ_FULL internal */ -#ifdef CONFIG_NO_HZ_FULL -extern void tick_nohz_init(void); -# else -static inline void tick_nohz_init(void) { } -#endif - -#ifdef CONFIG_NO_HZ_COMMON -extern unsigned long tick_nohz_active; -#else -#define tick_nohz_active (0) -#endif - -#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON) -extern void timers_update_migration(bool update_nohz); -#else -static inline void timers_update_migration(bool update_nohz) { } -#endif - -DECLARE_PER_CPU(struct hrtimer_cpu_base, hrtimer_bases); - -extern u64 get_next_timer_interrupt(unsigned long basej, u64 basem); -void timer_clear_idle(void); diff --git a/src/linux/kernel/time/tick-oneshot.c b/src/linux/kernel/time/tick-oneshot.c deleted file mode 100644 index b513446..0000000 --- a/src/linux/kernel/time/tick-oneshot.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * linux/kernel/time/tick-oneshot.c - * - * This file contains functions which manage high resolution tick - * related events. - * - * Copyright(C) 2005-2006, Thomas Gleixner - * Copyright(C) 2005-2007, Red Hat, Inc., Ingo Molnar - * Copyright(C) 2006-2007, Timesys Corp., Thomas Gleixner - * - * This code is licenced under the GPL version 2. For details see - * kernel-base/COPYING. - */ -#include -#include -#include -#include -#include -#include -#include - -#include "tick-internal.h" - -/** - * tick_program_event - */ -int tick_program_event(ktime_t expires, int force) -{ - struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); - - if (unlikely(expires.tv64 == KTIME_MAX)) { - /* - * We don't need the clock event device any more, stop it. - */ - clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT_STOPPED); - return 0; - } - - if (unlikely(clockevent_state_oneshot_stopped(dev))) { - /* - * We need the clock event again, configure it in ONESHOT mode - * before using it. - */ - clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT); - } - - return clockevents_program_event(dev, expires, force); -} - -/** - * tick_resume_onshot - resume oneshot mode - */ -void tick_resume_oneshot(void) -{ - struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); - - clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT); - clockevents_program_event(dev, ktime_get(), true); -} - -/** - * tick_setup_oneshot - setup the event device for oneshot mode (hres or nohz) - */ -void tick_setup_oneshot(struct clock_event_device *newdev, - void (*handler)(struct clock_event_device *), - ktime_t next_event) -{ - newdev->event_handler = handler; - clockevents_switch_state(newdev, CLOCK_EVT_STATE_ONESHOT); - clockevents_program_event(newdev, next_event, true); -} - -/** - * tick_switch_to_oneshot - switch to oneshot mode - */ -int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *)) -{ - struct tick_device *td = this_cpu_ptr(&tick_cpu_device); - struct clock_event_device *dev = td->evtdev; - - if (!dev || !(dev->features & CLOCK_EVT_FEAT_ONESHOT) || - !tick_device_is_functional(dev)) { - - printk(KERN_INFO "Clockevents: " - "could not switch to one-shot mode:"); - if (!dev) { - printk(" no tick device\n"); - } else { - if (!tick_device_is_functional(dev)) - printk(" %s is not functional.\n", dev->name); - else - printk(" %s does not support one-shot mode.\n", - dev->name); - } - return -EINVAL; - } - - td->mode = TICKDEV_MODE_ONESHOT; - dev->event_handler = handler; - clockevents_switch_state(dev, CLOCK_EVT_STATE_ONESHOT); - tick_broadcast_switch_to_oneshot(); - return 0; -} - -/** - * tick_check_oneshot_mode - check whether the system is in oneshot mode - * - * returns 1 when either nohz or highres are enabled. otherwise 0. - */ -int tick_oneshot_mode_active(void) -{ - unsigned long flags; - int ret; - - local_irq_save(flags); - ret = __this_cpu_read(tick_cpu_device.mode) == TICKDEV_MODE_ONESHOT; - local_irq_restore(flags); - - return ret; -} - -#ifdef CONFIG_HIGH_RES_TIMERS -/** - * tick_init_highres - switch to high resolution mode - * - * Called with interrupts disabled. - */ -int tick_init_highres(void) -{ - return tick_switch_to_oneshot(hrtimer_interrupt); -} -#endif diff --git a/src/linux/kernel/time/tick-sched.c b/src/linux/kernel/time/tick-sched.c deleted file mode 100644 index 3bcb61b..0000000 --- a/src/linux/kernel/time/tick-sched.c +++ /dev/null @@ -1,1276 +0,0 @@ -/* - * linux/kernel/time/tick-sched.c - * - * Copyright(C) 2005-2006, Thomas Gleixner - * Copyright(C) 2005-2007, Red Hat, Inc., Ingo Molnar - * Copyright(C) 2006-2007 Timesys Corp., Thomas Gleixner - * - * No idle tick implementation for low and high resolution timers - * - * Started by: Thomas Gleixner and Ingo Molnar - * - * Distribute under GPLv2. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "tick-internal.h" - -#include - -/* - * Per-CPU nohz control structure - */ -static DEFINE_PER_CPU(struct tick_sched, tick_cpu_sched); - -struct tick_sched *tick_get_tick_sched(int cpu) -{ - return &per_cpu(tick_cpu_sched, cpu); -} - -#if defined(CONFIG_NO_HZ_COMMON) || defined(CONFIG_HIGH_RES_TIMERS) -/* - * The time, when the last jiffy update happened. Protected by jiffies_lock. - */ -static ktime_t last_jiffies_update; - -/* - * Must be called with interrupts disabled ! - */ -static void tick_do_update_jiffies64(ktime_t now) -{ - unsigned long ticks = 0; - ktime_t delta; - - /* - * Do a quick check without holding jiffies_lock: - */ - delta = ktime_sub(now, last_jiffies_update); - if (delta.tv64 < tick_period.tv64) - return; - - /* Reevaluate with jiffies_lock held */ - write_seqlock(&jiffies_lock); - - delta = ktime_sub(now, last_jiffies_update); - if (delta.tv64 >= tick_period.tv64) { - - delta = ktime_sub(delta, tick_period); - last_jiffies_update = ktime_add(last_jiffies_update, - tick_period); - - /* Slow path for long timeouts */ - if (unlikely(delta.tv64 >= tick_period.tv64)) { - s64 incr = ktime_to_ns(tick_period); - - ticks = ktime_divns(delta, incr); - - last_jiffies_update = ktime_add_ns(last_jiffies_update, - incr * ticks); - } - do_timer(++ticks); - - /* Keep the tick_next_period variable up to date */ - tick_next_period = ktime_add(last_jiffies_update, tick_period); - } else { - write_sequnlock(&jiffies_lock); - return; - } - write_sequnlock(&jiffies_lock); - update_wall_time(); -} - -/* - * Initialize and return retrieve the jiffies update. - */ -static ktime_t tick_init_jiffy_update(void) -{ - ktime_t period; - - write_seqlock(&jiffies_lock); - /* Did we start the jiffies update yet ? */ - if (last_jiffies_update.tv64 == 0) - last_jiffies_update = tick_next_period; - period = last_jiffies_update; - write_sequnlock(&jiffies_lock); - return period; -} - - -static void tick_sched_do_timer(ktime_t now) -{ - int cpu = smp_processor_id(); - -#ifdef CONFIG_NO_HZ_COMMON - /* - * Check if the do_timer duty was dropped. We don't care about - * concurrency: This happens only when the CPU in charge went - * into a long sleep. If two CPUs happen to assign themselves to - * this duty, then the jiffies update is still serialized by - * jiffies_lock. - */ - if (unlikely(tick_do_timer_cpu == TICK_DO_TIMER_NONE) - && !tick_nohz_full_cpu(cpu)) - tick_do_timer_cpu = cpu; -#endif - - /* Check, if the jiffies need an update */ - if (tick_do_timer_cpu == cpu) - tick_do_update_jiffies64(now); -} - -static void tick_sched_handle(struct tick_sched *ts, struct pt_regs *regs) -{ -#ifdef CONFIG_NO_HZ_COMMON - /* - * When we are idle and the tick is stopped, we have to touch - * the watchdog as we might not schedule for a really long - * time. This happens on complete idle SMP systems while - * waiting on the login prompt. We also increment the "start of - * idle" jiffy stamp so the idle accounting adjustment we do - * when we go busy again does not account too much ticks. - */ - if (ts->tick_stopped) { - touch_softlockup_watchdog_sched(); - if (is_idle_task(current)) - ts->idle_jiffies++; - } -#endif - update_process_times(user_mode(regs)); - profile_tick(CPU_PROFILING); -} -#endif - -#ifdef CONFIG_NO_HZ_FULL -cpumask_var_t tick_nohz_full_mask; -cpumask_var_t housekeeping_mask; -bool tick_nohz_full_running; -static atomic_t tick_dep_mask; - -static bool check_tick_dependency(atomic_t *dep) -{ - int val = atomic_read(dep); - - if (val & TICK_DEP_MASK_POSIX_TIMER) { - trace_tick_stop(0, TICK_DEP_MASK_POSIX_TIMER); - return true; - } - - if (val & TICK_DEP_MASK_PERF_EVENTS) { - trace_tick_stop(0, TICK_DEP_MASK_PERF_EVENTS); - return true; - } - - if (val & TICK_DEP_MASK_SCHED) { - trace_tick_stop(0, TICK_DEP_MASK_SCHED); - return true; - } - - if (val & TICK_DEP_MASK_CLOCK_UNSTABLE) { - trace_tick_stop(0, TICK_DEP_MASK_CLOCK_UNSTABLE); - return true; - } - - return false; -} - -static bool can_stop_full_tick(int cpu, struct tick_sched *ts) -{ - WARN_ON_ONCE(!irqs_disabled()); - - if (unlikely(!cpu_online(cpu))) - return false; - - if (check_tick_dependency(&tick_dep_mask)) - return false; - - if (check_tick_dependency(&ts->tick_dep_mask)) - return false; - - if (check_tick_dependency(¤t->tick_dep_mask)) - return false; - - if (check_tick_dependency(¤t->signal->tick_dep_mask)) - return false; - - return true; -} - -static void nohz_full_kick_func(struct irq_work *work) -{ - /* Empty, the tick restart happens on tick_nohz_irq_exit() */ -} - -static DEFINE_PER_CPU(struct irq_work, nohz_full_kick_work) = { - .func = nohz_full_kick_func, -}; - -/* - * Kick this CPU if it's full dynticks in order to force it to - * re-evaluate its dependency on the tick and restart it if necessary. - * This kick, unlike tick_nohz_full_kick_cpu() and tick_nohz_full_kick_all(), - * is NMI safe. - */ -static void tick_nohz_full_kick(void) -{ - if (!tick_nohz_full_cpu(smp_processor_id())) - return; - - irq_work_queue(this_cpu_ptr(&nohz_full_kick_work)); -} - -/* - * Kick the CPU if it's full dynticks in order to force it to - * re-evaluate its dependency on the tick and restart it if necessary. - */ -void tick_nohz_full_kick_cpu(int cpu) -{ - if (!tick_nohz_full_cpu(cpu)) - return; - - irq_work_queue_on(&per_cpu(nohz_full_kick_work, cpu), cpu); -} - -/* - * Kick all full dynticks CPUs in order to force these to re-evaluate - * their dependency on the tick and restart it if necessary. - */ -static void tick_nohz_full_kick_all(void) -{ - int cpu; - - if (!tick_nohz_full_running) - return; - - preempt_disable(); - for_each_cpu_and(cpu, tick_nohz_full_mask, cpu_online_mask) - tick_nohz_full_kick_cpu(cpu); - preempt_enable(); -} - -static void tick_nohz_dep_set_all(atomic_t *dep, - enum tick_dep_bits bit) -{ - int prev; - - prev = atomic_fetch_or(BIT(bit), dep); - if (!prev) - tick_nohz_full_kick_all(); -} - -/* - * Set a global tick dependency. Used by perf events that rely on freq and - * by unstable clock. - */ -void tick_nohz_dep_set(enum tick_dep_bits bit) -{ - tick_nohz_dep_set_all(&tick_dep_mask, bit); -} - -void tick_nohz_dep_clear(enum tick_dep_bits bit) -{ - atomic_andnot(BIT(bit), &tick_dep_mask); -} - -/* - * Set per-CPU tick dependency. Used by scheduler and perf events in order to - * manage events throttling. - */ -void tick_nohz_dep_set_cpu(int cpu, enum tick_dep_bits bit) -{ - int prev; - struct tick_sched *ts; - - ts = per_cpu_ptr(&tick_cpu_sched, cpu); - - prev = atomic_fetch_or(BIT(bit), &ts->tick_dep_mask); - if (!prev) { - preempt_disable(); - /* Perf needs local kick that is NMI safe */ - if (cpu == smp_processor_id()) { - tick_nohz_full_kick(); - } else { - /* Remote irq work not NMI-safe */ - if (!WARN_ON_ONCE(in_nmi())) - tick_nohz_full_kick_cpu(cpu); - } - preempt_enable(); - } -} - -void tick_nohz_dep_clear_cpu(int cpu, enum tick_dep_bits bit) -{ - struct tick_sched *ts = per_cpu_ptr(&tick_cpu_sched, cpu); - - atomic_andnot(BIT(bit), &ts->tick_dep_mask); -} - -/* - * Set a per-task tick dependency. Posix CPU timers need this in order to elapse - * per task timers. - */ -void tick_nohz_dep_set_task(struct task_struct *tsk, enum tick_dep_bits bit) -{ - /* - * We could optimize this with just kicking the target running the task - * if that noise matters for nohz full users. - */ - tick_nohz_dep_set_all(&tsk->tick_dep_mask, bit); -} - -void tick_nohz_dep_clear_task(struct task_struct *tsk, enum tick_dep_bits bit) -{ - atomic_andnot(BIT(bit), &tsk->tick_dep_mask); -} - -/* - * Set a per-taskgroup tick dependency. Posix CPU timers need this in order to elapse - * per process timers. - */ -void tick_nohz_dep_set_signal(struct signal_struct *sig, enum tick_dep_bits bit) -{ - tick_nohz_dep_set_all(&sig->tick_dep_mask, bit); -} - -void tick_nohz_dep_clear_signal(struct signal_struct *sig, enum tick_dep_bits bit) -{ - atomic_andnot(BIT(bit), &sig->tick_dep_mask); -} - -/* - * Re-evaluate the need for the tick as we switch the current task. - * It might need the tick due to per task/process properties: - * perf events, posix CPU timers, ... - */ -void __tick_nohz_task_switch(void) -{ - unsigned long flags; - struct tick_sched *ts; - - local_irq_save(flags); - - if (!tick_nohz_full_cpu(smp_processor_id())) - goto out; - - ts = this_cpu_ptr(&tick_cpu_sched); - - if (ts->tick_stopped) { - if (atomic_read(¤t->tick_dep_mask) || - atomic_read(¤t->signal->tick_dep_mask)) - tick_nohz_full_kick(); - } -out: - local_irq_restore(flags); -} - -/* Parse the boot-time nohz CPU list from the kernel parameters. */ -static int __init tick_nohz_full_setup(char *str) -{ - alloc_bootmem_cpumask_var(&tick_nohz_full_mask); - if (cpulist_parse(str, tick_nohz_full_mask) < 0) { - pr_warn("NO_HZ: Incorrect nohz_full cpumask\n"); - free_bootmem_cpumask_var(tick_nohz_full_mask); - return 1; - } - tick_nohz_full_running = true; - - return 1; -} -__setup("nohz_full=", tick_nohz_full_setup); - -static int tick_nohz_cpu_down_callback(struct notifier_block *nfb, - unsigned long action, - void *hcpu) -{ - unsigned int cpu = (unsigned long)hcpu; - - switch (action & ~CPU_TASKS_FROZEN) { - case CPU_DOWN_PREPARE: - /* - * The boot CPU handles housekeeping duty (unbound timers, - * workqueues, timekeeping, ...) on behalf of full dynticks - * CPUs. It must remain online when nohz full is enabled. - */ - if (tick_nohz_full_running && tick_do_timer_cpu == cpu) - return NOTIFY_BAD; - break; - } - return NOTIFY_OK; -} - -static int tick_nohz_init_all(void) -{ - int err = -1; - -#ifdef CONFIG_NO_HZ_FULL_ALL - if (!alloc_cpumask_var(&tick_nohz_full_mask, GFP_KERNEL)) { - WARN(1, "NO_HZ: Can't allocate full dynticks cpumask\n"); - return err; - } - err = 0; - cpumask_setall(tick_nohz_full_mask); - tick_nohz_full_running = true; -#endif - return err; -} - -void __init tick_nohz_init(void) -{ - int cpu; - - if (!tick_nohz_full_running) { - if (tick_nohz_init_all() < 0) - return; - } - - if (!alloc_cpumask_var(&housekeeping_mask, GFP_KERNEL)) { - WARN(1, "NO_HZ: Can't allocate not-full dynticks cpumask\n"); - cpumask_clear(tick_nohz_full_mask); - tick_nohz_full_running = false; - return; - } - - /* - * Full dynticks uses irq work to drive the tick rescheduling on safe - * locking contexts. But then we need irq work to raise its own - * interrupts to avoid circular dependency on the tick - */ - if (!arch_irq_work_has_interrupt()) { - pr_warn("NO_HZ: Can't run full dynticks because arch doesn't support irq work self-IPIs\n"); - cpumask_clear(tick_nohz_full_mask); - cpumask_copy(housekeeping_mask, cpu_possible_mask); - tick_nohz_full_running = false; - return; - } - - cpu = smp_processor_id(); - - if (cpumask_test_cpu(cpu, tick_nohz_full_mask)) { - pr_warn("NO_HZ: Clearing %d from nohz_full range for timekeeping\n", - cpu); - cpumask_clear_cpu(cpu, tick_nohz_full_mask); - } - - cpumask_andnot(housekeeping_mask, - cpu_possible_mask, tick_nohz_full_mask); - - for_each_cpu(cpu, tick_nohz_full_mask) - context_tracking_cpu_set(cpu); - - cpu_notifier(tick_nohz_cpu_down_callback, 0); - pr_info("NO_HZ: Full dynticks CPUs: %*pbl.\n", - cpumask_pr_args(tick_nohz_full_mask)); - - /* - * We need at least one CPU to handle housekeeping work such - * as timekeeping, unbound timers, workqueues, ... - */ - WARN_ON_ONCE(cpumask_empty(housekeeping_mask)); -} -#endif - -/* - * NOHZ - aka dynamic tick functionality - */ -#ifdef CONFIG_NO_HZ_COMMON -/* - * NO HZ enabled ? - */ -bool tick_nohz_enabled __read_mostly = true; -unsigned long tick_nohz_active __read_mostly; -/* - * Enable / Disable tickless mode - */ -static int __init setup_tick_nohz(char *str) -{ - return (kstrtobool(str, &tick_nohz_enabled) == 0); -} - -__setup("nohz=", setup_tick_nohz); - -int tick_nohz_tick_stopped(void) -{ - return __this_cpu_read(tick_cpu_sched.tick_stopped); -} - -/** - * tick_nohz_update_jiffies - update jiffies when idle was interrupted - * - * Called from interrupt entry when the CPU was idle - * - * In case the sched_tick was stopped on this CPU, we have to check if jiffies - * must be updated. Otherwise an interrupt handler could use a stale jiffy - * value. We do this unconditionally on any CPU, as we don't know whether the - * CPU, which has the update task assigned is in a long sleep. - */ -static void tick_nohz_update_jiffies(ktime_t now) -{ - unsigned long flags; - - __this_cpu_write(tick_cpu_sched.idle_waketime, now); - - local_irq_save(flags); - tick_do_update_jiffies64(now); - local_irq_restore(flags); - - touch_softlockup_watchdog_sched(); -} - -/* - * Updates the per-CPU time idle statistics counters - */ -static void -update_ts_time_stats(int cpu, struct tick_sched *ts, ktime_t now, u64 *last_update_time) -{ - ktime_t delta; - - if (ts->idle_active) { - delta = ktime_sub(now, ts->idle_entrytime); - if (nr_iowait_cpu(cpu) > 0) - ts->iowait_sleeptime = ktime_add(ts->iowait_sleeptime, delta); - else - ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta); - ts->idle_entrytime = now; - } - - if (last_update_time) - *last_update_time = ktime_to_us(now); - -} - -static void tick_nohz_stop_idle(struct tick_sched *ts, ktime_t now) -{ - update_ts_time_stats(smp_processor_id(), ts, now, NULL); - ts->idle_active = 0; - - sched_clock_idle_wakeup_event(0); -} - -static ktime_t tick_nohz_start_idle(struct tick_sched *ts) -{ - ktime_t now = ktime_get(); - - ts->idle_entrytime = now; - ts->idle_active = 1; - sched_clock_idle_sleep_event(); - return now; -} - -/** - * get_cpu_idle_time_us - get the total idle time of a CPU - * @cpu: CPU number to query - * @last_update_time: variable to store update time in. Do not update - * counters if NULL. - * - * Return the cumulative idle time (since boot) for a given - * CPU, in microseconds. - * - * This time is measured via accounting rather than sampling, - * and is as accurate as ktime_get() is. - * - * This function returns -1 if NOHZ is not enabled. - */ -u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time) -{ - struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); - ktime_t now, idle; - - if (!tick_nohz_active) - return -1; - - now = ktime_get(); - if (last_update_time) { - update_ts_time_stats(cpu, ts, now, last_update_time); - idle = ts->idle_sleeptime; - } else { - if (ts->idle_active && !nr_iowait_cpu(cpu)) { - ktime_t delta = ktime_sub(now, ts->idle_entrytime); - - idle = ktime_add(ts->idle_sleeptime, delta); - } else { - idle = ts->idle_sleeptime; - } - } - - return ktime_to_us(idle); - -} -EXPORT_SYMBOL_GPL(get_cpu_idle_time_us); - -/** - * get_cpu_iowait_time_us - get the total iowait time of a CPU - * @cpu: CPU number to query - * @last_update_time: variable to store update time in. Do not update - * counters if NULL. - * - * Return the cumulative iowait time (since boot) for a given - * CPU, in microseconds. - * - * This time is measured via accounting rather than sampling, - * and is as accurate as ktime_get() is. - * - * This function returns -1 if NOHZ is not enabled. - */ -u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time) -{ - struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); - ktime_t now, iowait; - - if (!tick_nohz_active) - return -1; - - now = ktime_get(); - if (last_update_time) { - update_ts_time_stats(cpu, ts, now, last_update_time); - iowait = ts->iowait_sleeptime; - } else { - if (ts->idle_active && nr_iowait_cpu(cpu) > 0) { - ktime_t delta = ktime_sub(now, ts->idle_entrytime); - - iowait = ktime_add(ts->iowait_sleeptime, delta); - } else { - iowait = ts->iowait_sleeptime; - } - } - - return ktime_to_us(iowait); -} -EXPORT_SYMBOL_GPL(get_cpu_iowait_time_us); - -static void tick_nohz_restart(struct tick_sched *ts, ktime_t now) -{ - hrtimer_cancel(&ts->sched_timer); - hrtimer_set_expires(&ts->sched_timer, ts->last_tick); - - /* Forward the time to expire in the future */ - hrtimer_forward(&ts->sched_timer, now, tick_period); - - if (ts->nohz_mode == NOHZ_MODE_HIGHRES) - hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS_PINNED); - else - tick_program_event(hrtimer_get_expires(&ts->sched_timer), 1); -} - -static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts, - ktime_t now, int cpu) -{ - struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev); - u64 basemono, next_tick, next_tmr, next_rcu, delta, expires; - unsigned long seq, basejiff; - ktime_t tick; - - /* Read jiffies and the time when jiffies were updated last */ - do { - seq = read_seqbegin(&jiffies_lock); - basemono = last_jiffies_update.tv64; - basejiff = jiffies; - } while (read_seqretry(&jiffies_lock, seq)); - ts->last_jiffies = basejiff; - - if (rcu_needs_cpu(basemono, &next_rcu) || - arch_needs_cpu() || irq_work_needs_cpu()) { - next_tick = basemono + TICK_NSEC; - } else { - /* - * Get the next pending timer. If high resolution - * timers are enabled this only takes the timer wheel - * timers into account. If high resolution timers are - * disabled this also looks at the next expiring - * hrtimer. - */ - next_tmr = get_next_timer_interrupt(basejiff, basemono); - ts->next_timer = next_tmr; - /* Take the next rcu event into account */ - next_tick = next_rcu < next_tmr ? next_rcu : next_tmr; - } - - /* - * If the tick is due in the next period, keep it ticking or - * force prod the timer. - */ - delta = next_tick - basemono; - if (delta <= (u64)TICK_NSEC) { - tick.tv64 = 0; - - /* - * Tell the timer code that the base is not idle, i.e. undo - * the effect of get_next_timer_interrupt(): - */ - timer_clear_idle(); - /* - * We've not stopped the tick yet, and there's a timer in the - * next period, so no point in stopping it either, bail. - */ - if (!ts->tick_stopped) - goto out; - - /* - * If, OTOH, we did stop it, but there's a pending (expired) - * timer reprogram the timer hardware to fire now. - * - * We will not restart the tick proper, just prod the timer - * hardware into firing an interrupt to process the pending - * timers. Just like tick_irq_exit() will not restart the tick - * for 'normal' interrupts. - * - * Only once we exit the idle loop will we re-enable the tick, - * see tick_nohz_idle_exit(). - */ - if (delta == 0) { - tick_nohz_restart(ts, now); - goto out; - } - } - - /* - * If this CPU is the one which updates jiffies, then give up - * the assignment and let it be taken by the CPU which runs - * the tick timer next, which might be this CPU as well. If we - * don't drop this here the jiffies might be stale and - * do_timer() never invoked. Keep track of the fact that it - * was the one which had the do_timer() duty last. If this CPU - * is the one which had the do_timer() duty last, we limit the - * sleep time to the timekeeping max_deferment value. - * Otherwise we can sleep as long as we want. - */ - delta = timekeeping_max_deferment(); - if (cpu == tick_do_timer_cpu) { - tick_do_timer_cpu = TICK_DO_TIMER_NONE; - ts->do_timer_last = 1; - } else if (tick_do_timer_cpu != TICK_DO_TIMER_NONE) { - delta = KTIME_MAX; - ts->do_timer_last = 0; - } else if (!ts->do_timer_last) { - delta = KTIME_MAX; - } - -#ifdef CONFIG_NO_HZ_FULL - /* Limit the tick delta to the maximum scheduler deferment */ - if (!ts->inidle) - delta = min(delta, scheduler_tick_max_deferment()); -#endif - - /* Calculate the next expiry time */ - if (delta < (KTIME_MAX - basemono)) - expires = basemono + delta; - else - expires = KTIME_MAX; - - expires = min_t(u64, expires, next_tick); - tick.tv64 = expires; - - /* Skip reprogram of event if its not changed */ - if (ts->tick_stopped && (expires == dev->next_event.tv64)) - goto out; - - /* - * nohz_stop_sched_tick can be called several times before - * the nohz_restart_sched_tick is called. This happens when - * interrupts arrive which do not cause a reschedule. In the - * first call we save the current tick time, so we can restart - * the scheduler tick in nohz_restart_sched_tick. - */ - if (!ts->tick_stopped) { - nohz_balance_enter_idle(cpu); - calc_load_enter_idle(); - cpu_load_update_nohz_start(); - - ts->last_tick = hrtimer_get_expires(&ts->sched_timer); - ts->tick_stopped = 1; - trace_tick_stop(1, TICK_DEP_MASK_NONE); - } - - /* - * If the expiration time == KTIME_MAX, then we simply stop - * the tick timer. - */ - if (unlikely(expires == KTIME_MAX)) { - if (ts->nohz_mode == NOHZ_MODE_HIGHRES) - hrtimer_cancel(&ts->sched_timer); - goto out; - } - - if (ts->nohz_mode == NOHZ_MODE_HIGHRES) - hrtimer_start(&ts->sched_timer, tick, HRTIMER_MODE_ABS_PINNED); - else - tick_program_event(tick, 1); -out: - /* Update the estimated sleep length */ - ts->sleep_length = ktime_sub(dev->next_event, now); - return tick; -} - -static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now) -{ - /* Update jiffies first */ - tick_do_update_jiffies64(now); - cpu_load_update_nohz_stop(); - - /* - * Clear the timer idle flag, so we avoid IPIs on remote queueing and - * the clock forward checks in the enqueue path: - */ - timer_clear_idle(); - - calc_load_exit_idle(); - touch_softlockup_watchdog_sched(); - /* - * Cancel the scheduled timer and restore the tick - */ - ts->tick_stopped = 0; - ts->idle_exittime = now; - - tick_nohz_restart(ts, now); -} - -static void tick_nohz_full_update_tick(struct tick_sched *ts) -{ -#ifdef CONFIG_NO_HZ_FULL - int cpu = smp_processor_id(); - - if (!tick_nohz_full_cpu(cpu)) - return; - - if (!ts->tick_stopped && ts->nohz_mode == NOHZ_MODE_INACTIVE) - return; - - if (can_stop_full_tick(cpu, ts)) - tick_nohz_stop_sched_tick(ts, ktime_get(), cpu); - else if (ts->tick_stopped) - tick_nohz_restart_sched_tick(ts, ktime_get()); -#endif -} - -static bool can_stop_idle_tick(int cpu, struct tick_sched *ts) -{ - /* - * If this CPU is offline and it is the one which updates - * jiffies, then give up the assignment and let it be taken by - * the CPU which runs the tick timer next. If we don't drop - * this here the jiffies might be stale and do_timer() never - * invoked. - */ - if (unlikely(!cpu_online(cpu))) { - if (cpu == tick_do_timer_cpu) - tick_do_timer_cpu = TICK_DO_TIMER_NONE; - return false; - } - - if (unlikely(ts->nohz_mode == NOHZ_MODE_INACTIVE)) { - ts->sleep_length = (ktime_t) { .tv64 = NSEC_PER_SEC/HZ }; - return false; - } - - if (need_resched()) - return false; - - if (unlikely(local_softirq_pending() && cpu_online(cpu))) { - static int ratelimit; - - if (ratelimit < 10 && - (local_softirq_pending() & SOFTIRQ_STOP_IDLE_MASK)) { - pr_warn("NOHZ: local_softirq_pending %02x\n", - (unsigned int) local_softirq_pending()); - ratelimit++; - } - return false; - } - - if (tick_nohz_full_enabled()) { - /* - * Keep the tick alive to guarantee timekeeping progression - * if there are full dynticks CPUs around - */ - if (tick_do_timer_cpu == cpu) - return false; - /* - * Boot safety: make sure the timekeeping duty has been - * assigned before entering dyntick-idle mode, - */ - if (tick_do_timer_cpu == TICK_DO_TIMER_NONE) - return false; - } - - return true; -} - -static void __tick_nohz_idle_enter(struct tick_sched *ts) -{ - ktime_t now, expires; - int cpu = smp_processor_id(); - - now = tick_nohz_start_idle(ts); - - if (can_stop_idle_tick(cpu, ts)) { - int was_stopped = ts->tick_stopped; - - ts->idle_calls++; - - expires = tick_nohz_stop_sched_tick(ts, now, cpu); - if (expires.tv64 > 0LL) { - ts->idle_sleeps++; - ts->idle_expires = expires; - } - - if (!was_stopped && ts->tick_stopped) - ts->idle_jiffies = ts->last_jiffies; - } -} - -/** - * tick_nohz_idle_enter - stop the idle tick from the idle task - * - * When the next event is more than a tick into the future, stop the idle tick - * Called when we start the idle loop. - * - * The arch is responsible of calling: - * - * - rcu_idle_enter() after its last use of RCU before the CPU is put - * to sleep. - * - rcu_idle_exit() before the first use of RCU after the CPU is woken up. - */ -void tick_nohz_idle_enter(void) -{ - struct tick_sched *ts; - - WARN_ON_ONCE(irqs_disabled()); - - /* - * Update the idle state in the scheduler domain hierarchy - * when tick_nohz_stop_sched_tick() is called from the idle loop. - * State will be updated to busy during the first busy tick after - * exiting idle. - */ - set_cpu_sd_state_idle(); - - local_irq_disable(); - - ts = this_cpu_ptr(&tick_cpu_sched); - ts->inidle = 1; - __tick_nohz_idle_enter(ts); - - local_irq_enable(); -} - -/** - * tick_nohz_irq_exit - update next tick event from interrupt exit - * - * When an interrupt fires while we are idle and it doesn't cause - * a reschedule, it may still add, modify or delete a timer, enqueue - * an RCU callback, etc... - * So we need to re-calculate and reprogram the next tick event. - */ -void tick_nohz_irq_exit(void) -{ - struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); - - if (ts->inidle) - __tick_nohz_idle_enter(ts); - else - tick_nohz_full_update_tick(ts); -} - -/** - * tick_nohz_get_sleep_length - return the length of the current sleep - * - * Called from power state control code with interrupts disabled - */ -ktime_t tick_nohz_get_sleep_length(void) -{ - struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); - - return ts->sleep_length; -} - -static void tick_nohz_account_idle_ticks(struct tick_sched *ts) -{ -#ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE - unsigned long ticks; - - if (vtime_accounting_cpu_enabled()) - return; - /* - * We stopped the tick in idle. Update process times would miss the - * time we slept as update_process_times does only a 1 tick - * accounting. Enforce that this is accounted to idle ! - */ - ticks = jiffies - ts->idle_jiffies; - /* - * We might be one off. Do not randomly account a huge number of ticks! - */ - if (ticks && ticks < LONG_MAX) - account_idle_ticks(ticks); -#endif -} - -/** - * tick_nohz_idle_exit - restart the idle tick from the idle task - * - * Restart the idle tick when the CPU is woken up from idle - * This also exit the RCU extended quiescent state. The CPU - * can use RCU again after this function is called. - */ -void tick_nohz_idle_exit(void) -{ - struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); - ktime_t now; - - local_irq_disable(); - - WARN_ON_ONCE(!ts->inidle); - - ts->inidle = 0; - - if (ts->idle_active || ts->tick_stopped) - now = ktime_get(); - - if (ts->idle_active) - tick_nohz_stop_idle(ts, now); - - if (ts->tick_stopped) { - tick_nohz_restart_sched_tick(ts, now); - tick_nohz_account_idle_ticks(ts); - } - - local_irq_enable(); -} - -/* - * The nohz low res interrupt handler - */ -static void tick_nohz_handler(struct clock_event_device *dev) -{ - struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); - struct pt_regs *regs = get_irq_regs(); - ktime_t now = ktime_get(); - - dev->next_event.tv64 = KTIME_MAX; - - tick_sched_do_timer(now); - tick_sched_handle(ts, regs); - - /* No need to reprogram if we are running tickless */ - if (unlikely(ts->tick_stopped)) - return; - - hrtimer_forward(&ts->sched_timer, now, tick_period); - tick_program_event(hrtimer_get_expires(&ts->sched_timer), 1); -} - -static inline void tick_nohz_activate(struct tick_sched *ts, int mode) -{ - if (!tick_nohz_enabled) - return; - ts->nohz_mode = mode; - /* One update is enough */ - if (!test_and_set_bit(0, &tick_nohz_active)) - timers_update_migration(true); -} - -/** - * tick_nohz_switch_to_nohz - switch to nohz mode - */ -static void tick_nohz_switch_to_nohz(void) -{ - struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); - ktime_t next; - - if (!tick_nohz_enabled) - return; - - if (tick_switch_to_oneshot(tick_nohz_handler)) - return; - - /* - * Recycle the hrtimer in ts, so we can share the - * hrtimer_forward with the highres code. - */ - hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); - /* Get the next period */ - next = tick_init_jiffy_update(); - - hrtimer_set_expires(&ts->sched_timer, next); - hrtimer_forward_now(&ts->sched_timer, tick_period); - tick_program_event(hrtimer_get_expires(&ts->sched_timer), 1); - tick_nohz_activate(ts, NOHZ_MODE_LOWRES); -} - -static inline void tick_nohz_irq_enter(void) -{ - struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); - ktime_t now; - - if (!ts->idle_active && !ts->tick_stopped) - return; - now = ktime_get(); - if (ts->idle_active) - tick_nohz_stop_idle(ts, now); - if (ts->tick_stopped) - tick_nohz_update_jiffies(now); -} - -#else - -static inline void tick_nohz_switch_to_nohz(void) { } -static inline void tick_nohz_irq_enter(void) { } -static inline void tick_nohz_activate(struct tick_sched *ts, int mode) { } - -#endif /* CONFIG_NO_HZ_COMMON */ - -/* - * Called from irq_enter to notify about the possible interruption of idle() - */ -void tick_irq_enter(void) -{ - tick_check_oneshot_broadcast_this_cpu(); - tick_nohz_irq_enter(); -} - -/* - * High resolution timer specific code - */ -#ifdef CONFIG_HIGH_RES_TIMERS -/* - * We rearm the timer until we get disabled by the idle code. - * Called with interrupts disabled. - */ -static enum hrtimer_restart tick_sched_timer(struct hrtimer *timer) -{ - struct tick_sched *ts = - container_of(timer, struct tick_sched, sched_timer); - struct pt_regs *regs = get_irq_regs(); - ktime_t now = ktime_get(); - - tick_sched_do_timer(now); - - /* - * Do not call, when we are not in irq context and have - * no valid regs pointer - */ - if (regs) - tick_sched_handle(ts, regs); - - /* No need to reprogram if we are in idle or full dynticks mode */ - if (unlikely(ts->tick_stopped)) - return HRTIMER_NORESTART; - - hrtimer_forward(timer, now, tick_period); - - return HRTIMER_RESTART; -} - -static int sched_skew_tick; - -static int __init skew_tick(char *str) -{ - get_option(&str, &sched_skew_tick); - - return 0; -} -early_param("skew_tick", skew_tick); - -/** - * tick_setup_sched_timer - setup the tick emulation timer - */ -void tick_setup_sched_timer(void) -{ - struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); - ktime_t now = ktime_get(); - - /* - * Emulate tick processing via per-CPU hrtimers: - */ - hrtimer_init(&ts->sched_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); - ts->sched_timer.function = tick_sched_timer; - - /* Get the next period (per-CPU) */ - hrtimer_set_expires(&ts->sched_timer, tick_init_jiffy_update()); - - /* Offset the tick to avert jiffies_lock contention. */ - if (sched_skew_tick) { - u64 offset = ktime_to_ns(tick_period) >> 1; - do_div(offset, num_possible_cpus()); - offset *= smp_processor_id(); - hrtimer_add_expires_ns(&ts->sched_timer, offset); - } - - hrtimer_forward(&ts->sched_timer, now, tick_period); - hrtimer_start_expires(&ts->sched_timer, HRTIMER_MODE_ABS_PINNED); - tick_nohz_activate(ts, NOHZ_MODE_HIGHRES); -} -#endif /* HIGH_RES_TIMERS */ - -#if defined CONFIG_NO_HZ_COMMON || defined CONFIG_HIGH_RES_TIMERS -void tick_cancel_sched_timer(int cpu) -{ - struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); - -# ifdef CONFIG_HIGH_RES_TIMERS - if (ts->sched_timer.base) - hrtimer_cancel(&ts->sched_timer); -# endif - - memset(ts, 0, sizeof(*ts)); -} -#endif - -/** - * Async notification about clocksource changes - */ -void tick_clock_notify(void) -{ - int cpu; - - for_each_possible_cpu(cpu) - set_bit(0, &per_cpu(tick_cpu_sched, cpu).check_clocks); -} - -/* - * Async notification about clock event changes - */ -void tick_oneshot_notify(void) -{ - struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); - - set_bit(0, &ts->check_clocks); -} - -/** - * Check, if a change happened, which makes oneshot possible. - * - * Called cyclic from the hrtimer softirq (driven by the timer - * softirq) allow_nohz signals, that we can switch into low-res nohz - * mode, because high resolution timers are disabled (either compile - * or runtime). Called with interrupts disabled. - */ -int tick_check_oneshot_change(int allow_nohz) -{ - struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); - - if (!test_and_clear_bit(0, &ts->check_clocks)) - return 0; - - if (ts->nohz_mode != NOHZ_MODE_INACTIVE) - return 0; - - if (!timekeeping_valid_for_hres() || !tick_is_oneshot_available()) - return 0; - - if (!allow_nohz) - return 1; - - tick_nohz_switch_to_nohz(); - return 0; -} diff --git a/src/linux/kernel/time/tick-sched.h b/src/linux/kernel/time/tick-sched.h deleted file mode 100644 index bf38226..0000000 --- a/src/linux/kernel/time/tick-sched.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef _TICK_SCHED_H -#define _TICK_SCHED_H - -#include - -enum tick_device_mode { - TICKDEV_MODE_PERIODIC, - TICKDEV_MODE_ONESHOT, -}; - -struct tick_device { - struct clock_event_device *evtdev; - enum tick_device_mode mode; -}; - -enum tick_nohz_mode { - NOHZ_MODE_INACTIVE, - NOHZ_MODE_LOWRES, - NOHZ_MODE_HIGHRES, -}; - -/** - * struct tick_sched - sched tick emulation and no idle tick control/stats - * @sched_timer: hrtimer to schedule the periodic tick in high - * resolution mode - * @last_tick: Store the last tick expiry time when the tick - * timer is modified for nohz sleeps. This is necessary - * to resume the tick timer operation in the timeline - * when the CPU returns from nohz sleep. - * @tick_stopped: Indicator that the idle tick has been stopped - * @idle_jiffies: jiffies at the entry to idle for idle time accounting - * @idle_calls: Total number of idle calls - * @idle_sleeps: Number of idle calls, where the sched tick was stopped - * @idle_entrytime: Time when the idle call was entered - * @idle_waketime: Time when the idle was interrupted - * @idle_exittime: Time when the idle state was left - * @idle_sleeptime: Sum of the time slept in idle with sched tick stopped - * @iowait_sleeptime: Sum of the time slept in idle with sched tick stopped, with IO outstanding - * @sleep_length: Duration of the current idle sleep - * @do_timer_lst: CPU was the last one doing do_timer before going idle - */ -struct tick_sched { - struct hrtimer sched_timer; - unsigned long check_clocks; - enum tick_nohz_mode nohz_mode; - ktime_t last_tick; - int inidle; - int tick_stopped; - unsigned long idle_jiffies; - unsigned long idle_calls; - unsigned long idle_sleeps; - int idle_active; - ktime_t idle_entrytime; - ktime_t idle_waketime; - ktime_t idle_exittime; - ktime_t idle_sleeptime; - ktime_t iowait_sleeptime; - ktime_t sleep_length; - unsigned long last_jiffies; - u64 next_timer; - ktime_t idle_expires; - int do_timer_last; - atomic_t tick_dep_mask; -}; - -extern struct tick_sched *tick_get_tick_sched(int cpu); - -extern void tick_setup_sched_timer(void); -#if defined CONFIG_NO_HZ_COMMON || defined CONFIG_HIGH_RES_TIMERS -extern void tick_cancel_sched_timer(int cpu); -#else -static inline void tick_cancel_sched_timer(int cpu) { } -#endif - -#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST -extern int __tick_broadcast_oneshot_control(enum tick_broadcast_state state); -#else -static inline int -__tick_broadcast_oneshot_control(enum tick_broadcast_state state) -{ - return -EBUSY; -} -#endif - -#endif diff --git a/src/linux/kernel/time/time.c b/src/linux/kernel/time/time.c deleted file mode 100644 index bd62fb8..0000000 --- a/src/linux/kernel/time/time.c +++ /dev/null @@ -1,792 +0,0 @@ -/* - * linux/kernel/time.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * This file contains the interface functions for the various - * time related system calls: time, stime, gettimeofday, settimeofday, - * adjtime - */ -/* - * Modification history kernel/time.c - * - * 1993-09-02 Philip Gladstone - * Created file with time related functions from sched/core.c and adjtimex() - * 1993-10-08 Torsten Duwe - * adjtime interface update and CMOS clock write code - * 1995-08-13 Torsten Duwe - * kernel PLL updated to 1994-12-13 specs (rfc-1589) - * 1999-01-16 Ulrich Windl - * Introduced error checking for many cases in adjtimex(). - * Updated NTP code according to technical memorandum Jan '96 - * "A Kernel Model for Precision Timekeeping" by Dave Mills - * Allow time_constant larger than MAXTC(6) for NTP v4 (MAXTC == 10) - * (Even though the technical memorandum forbids it) - * 2004-07-14 Christoph Lameter - * Added getnstimeofday to allow the posix timer functions to return - * with nanosecond accuracy - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include "timekeeping.h" - -/* - * The timezone where the local system is located. Used as a default by some - * programs who obtain this value by using gettimeofday. - */ -struct timezone sys_tz; - -EXPORT_SYMBOL(sys_tz); - -#ifdef __ARCH_WANT_SYS_TIME - -/* - * sys_time() can be implemented in user-level using - * sys_gettimeofday(). Is this for backwards compatibility? If so, - * why not move it into the appropriate arch directory (for those - * architectures that need it). - */ -SYSCALL_DEFINE1(time, time_t __user *, tloc) -{ - time_t i = get_seconds(); - - if (tloc) { - if (put_user(i,tloc)) - return -EFAULT; - } - force_successful_syscall_return(); - return i; -} - -/* - * sys_stime() can be implemented in user-level using - * sys_settimeofday(). Is this for backwards compatibility? If so, - * why not move it into the appropriate arch directory (for those - * architectures that need it). - */ - -SYSCALL_DEFINE1(stime, time_t __user *, tptr) -{ - struct timespec tv; - int err; - - if (get_user(tv.tv_sec, tptr)) - return -EFAULT; - - tv.tv_nsec = 0; - - err = security_settime(&tv, NULL); - if (err) - return err; - - do_settimeofday(&tv); - return 0; -} - -#endif /* __ARCH_WANT_SYS_TIME */ - -SYSCALL_DEFINE2(gettimeofday, struct timeval __user *, tv, - struct timezone __user *, tz) -{ - if (likely(tv != NULL)) { - struct timeval ktv; - do_gettimeofday(&ktv); - if (copy_to_user(tv, &ktv, sizeof(ktv))) - return -EFAULT; - } - if (unlikely(tz != NULL)) { - if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) - return -EFAULT; - } - return 0; -} - -/* - * Indicates if there is an offset between the system clock and the hardware - * clock/persistent clock/rtc. - */ -int persistent_clock_is_local; - -/* - * Adjust the time obtained from the CMOS to be UTC time instead of - * local time. - * - * This is ugly, but preferable to the alternatives. Otherwise we - * would either need to write a program to do it in /etc/rc (and risk - * confusion if the program gets run more than once; it would also be - * hard to make the program warp the clock precisely n hours) or - * compile in the timezone information into the kernel. Bad, bad.... - * - * - TYT, 1992-01-01 - * - * The best thing to do is to keep the CMOS clock in universal time (UTC) - * as real UNIX machines always do it. This avoids all headaches about - * daylight saving times and warping kernel clocks. - */ -static inline void warp_clock(void) -{ - if (sys_tz.tz_minuteswest != 0) { - struct timespec adjust; - - persistent_clock_is_local = 1; - adjust.tv_sec = sys_tz.tz_minuteswest * 60; - adjust.tv_nsec = 0; - timekeeping_inject_offset(&adjust); - } -} - -/* - * In case for some reason the CMOS clock has not already been running - * in UTC, but in some local time: The first time we set the timezone, - * we will warp the clock so that it is ticking UTC time instead of - * local time. Presumably, if someone is setting the timezone then we - * are running in an environment where the programs understand about - * timezones. This should be done at boot time in the /etc/rc script, - * as soon as possible, so that the clock can be set right. Otherwise, - * various programs will get confused when the clock gets warped. - */ - -int do_sys_settimeofday64(const struct timespec64 *tv, const struct timezone *tz) -{ - static int firsttime = 1; - int error = 0; - - if (tv && !timespec64_valid(tv)) - return -EINVAL; - - error = security_settime64(tv, tz); - if (error) - return error; - - if (tz) { - /* Verify we're witin the +-15 hrs range */ - if (tz->tz_minuteswest > 15*60 || tz->tz_minuteswest < -15*60) - return -EINVAL; - - sys_tz = *tz; - update_vsyscall_tz(); - if (firsttime) { - firsttime = 0; - if (!tv) - warp_clock(); - } - } - if (tv) - return do_settimeofday64(tv); - return 0; -} - -SYSCALL_DEFINE2(settimeofday, struct timeval __user *, tv, - struct timezone __user *, tz) -{ - struct timeval user_tv; - struct timespec new_ts; - struct timezone new_tz; - - if (tv) { - if (copy_from_user(&user_tv, tv, sizeof(*tv))) - return -EFAULT; - - if (!timeval_valid(&user_tv)) - return -EINVAL; - - new_ts.tv_sec = user_tv.tv_sec; - new_ts.tv_nsec = user_tv.tv_usec * NSEC_PER_USEC; - } - if (tz) { - if (copy_from_user(&new_tz, tz, sizeof(*tz))) - return -EFAULT; - } - - return do_sys_settimeofday(tv ? &new_ts : NULL, tz ? &new_tz : NULL); -} - -SYSCALL_DEFINE1(adjtimex, struct timex __user *, txc_p) -{ - struct timex txc; /* Local copy of parameter */ - int ret; - - /* Copy the user data space into the kernel copy - * structure. But bear in mind that the structures - * may change - */ - if(copy_from_user(&txc, txc_p, sizeof(struct timex))) - return -EFAULT; - ret = do_adjtimex(&txc); - return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : ret; -} - -/** - * current_fs_time - Return FS time - * @sb: Superblock. - * - * Return the current time truncated to the time granularity supported by - * the fs. - */ -struct timespec current_fs_time(struct super_block *sb) -{ - struct timespec now = current_kernel_time(); - return timespec_trunc(now, sb->s_time_gran); -} -EXPORT_SYMBOL(current_fs_time); - -/* - * Convert jiffies to milliseconds and back. - * - * Avoid unnecessary multiplications/divisions in the - * two most common HZ cases: - */ -unsigned int jiffies_to_msecs(const unsigned long j) -{ -#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ) - return (MSEC_PER_SEC / HZ) * j; -#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC) - return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC); -#else -# if BITS_PER_LONG == 32 - return (HZ_TO_MSEC_MUL32 * j) >> HZ_TO_MSEC_SHR32; -# else - return (j * HZ_TO_MSEC_NUM) / HZ_TO_MSEC_DEN; -# endif -#endif -} -EXPORT_SYMBOL(jiffies_to_msecs); - -unsigned int jiffies_to_usecs(const unsigned long j) -{ - /* - * Hz usually doesn't go much further MSEC_PER_SEC. - * jiffies_to_usecs() and usecs_to_jiffies() depend on that. - */ - BUILD_BUG_ON(HZ > USEC_PER_SEC); - -#if !(USEC_PER_SEC % HZ) - return (USEC_PER_SEC / HZ) * j; -#else -# if BITS_PER_LONG == 32 - return (HZ_TO_USEC_MUL32 * j) >> HZ_TO_USEC_SHR32; -# else - return (j * HZ_TO_USEC_NUM) / HZ_TO_USEC_DEN; -# endif -#endif -} -EXPORT_SYMBOL(jiffies_to_usecs); - -/** - * timespec_trunc - Truncate timespec to a granularity - * @t: Timespec - * @gran: Granularity in ns. - * - * Truncate a timespec to a granularity. Always rounds down. gran must - * not be 0 nor greater than a second (NSEC_PER_SEC, or 10^9 ns). - */ -struct timespec timespec_trunc(struct timespec t, unsigned gran) -{ - /* Avoid division in the common cases 1 ns and 1 s. */ - if (gran == 1) { - /* nothing */ - } else if (gran == NSEC_PER_SEC) { - t.tv_nsec = 0; - } else if (gran > 1 && gran < NSEC_PER_SEC) { - t.tv_nsec -= t.tv_nsec % gran; - } else { - WARN(1, "illegal file time granularity: %u", gran); - } - return t; -} -EXPORT_SYMBOL(timespec_trunc); - -/* - * mktime64 - Converts date to seconds. - * Converts Gregorian date to seconds since 1970-01-01 00:00:00. - * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 - * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. - * - * [For the Julian calendar (which was used in Russia before 1917, - * Britain & colonies before 1752, anywhere else before 1582, - * and is still in use by some communities) leave out the - * -year/100+year/400 terms, and add 10.] - * - * This algorithm was first published by Gauss (I think). - * - * A leap second can be indicated by calling this function with sec as - * 60 (allowable under ISO 8601). The leap second is treated the same - * as the following second since they don't exist in UNIX time. - * - * An encoding of midnight at the end of the day as 24:00:00 - ie. midnight - * tomorrow - (allowable under ISO 8601) is supported. - */ -time64_t mktime64(const unsigned int year0, const unsigned int mon0, - const unsigned int day, const unsigned int hour, - const unsigned int min, const unsigned int sec) -{ - unsigned int mon = mon0, year = year0; - - /* 1..12 -> 11,12,1..10 */ - if (0 >= (int) (mon -= 2)) { - mon += 12; /* Puts Feb last since it has leap day */ - year -= 1; - } - - return ((((time64_t) - (year/4 - year/100 + year/400 + 367*mon/12 + day) + - year*365 - 719499 - )*24 + hour /* now have hours - midnight tomorrow handled here */ - )*60 + min /* now have minutes */ - )*60 + sec; /* finally seconds */ -} -EXPORT_SYMBOL(mktime64); - -/** - * set_normalized_timespec - set timespec sec and nsec parts and normalize - * - * @ts: pointer to timespec variable to be set - * @sec: seconds to set - * @nsec: nanoseconds to set - * - * Set seconds and nanoseconds field of a timespec variable and - * normalize to the timespec storage format - * - * Note: The tv_nsec part is always in the range of - * 0 <= tv_nsec < NSEC_PER_SEC - * For negative values only the tv_sec field is negative ! - */ -void set_normalized_timespec(struct timespec *ts, time_t sec, s64 nsec) -{ - while (nsec >= NSEC_PER_SEC) { - /* - * The following asm() prevents the compiler from - * optimising this loop into a modulo operation. See - * also __iter_div_u64_rem() in include/linux/time.h - */ - asm("" : "+rm"(nsec)); - nsec -= NSEC_PER_SEC; - ++sec; - } - while (nsec < 0) { - asm("" : "+rm"(nsec)); - nsec += NSEC_PER_SEC; - --sec; - } - ts->tv_sec = sec; - ts->tv_nsec = nsec; -} -EXPORT_SYMBOL(set_normalized_timespec); - -/** - * ns_to_timespec - Convert nanoseconds to timespec - * @nsec: the nanoseconds value to be converted - * - * Returns the timespec representation of the nsec parameter. - */ -struct timespec ns_to_timespec(const s64 nsec) -{ - struct timespec ts; - s32 rem; - - if (!nsec) - return (struct timespec) {0, 0}; - - ts.tv_sec = div_s64_rem(nsec, NSEC_PER_SEC, &rem); - if (unlikely(rem < 0)) { - ts.tv_sec--; - rem += NSEC_PER_SEC; - } - ts.tv_nsec = rem; - - return ts; -} -EXPORT_SYMBOL(ns_to_timespec); - -/** - * ns_to_timeval - Convert nanoseconds to timeval - * @nsec: the nanoseconds value to be converted - * - * Returns the timeval representation of the nsec parameter. - */ -struct timeval ns_to_timeval(const s64 nsec) -{ - struct timespec ts = ns_to_timespec(nsec); - struct timeval tv; - - tv.tv_sec = ts.tv_sec; - tv.tv_usec = (suseconds_t) ts.tv_nsec / 1000; - - return tv; -} -EXPORT_SYMBOL(ns_to_timeval); - -#if BITS_PER_LONG == 32 -/** - * set_normalized_timespec - set timespec sec and nsec parts and normalize - * - * @ts: pointer to timespec variable to be set - * @sec: seconds to set - * @nsec: nanoseconds to set - * - * Set seconds and nanoseconds field of a timespec variable and - * normalize to the timespec storage format - * - * Note: The tv_nsec part is always in the range of - * 0 <= tv_nsec < NSEC_PER_SEC - * For negative values only the tv_sec field is negative ! - */ -void set_normalized_timespec64(struct timespec64 *ts, time64_t sec, s64 nsec) -{ - while (nsec >= NSEC_PER_SEC) { - /* - * The following asm() prevents the compiler from - * optimising this loop into a modulo operation. See - * also __iter_div_u64_rem() in include/linux/time.h - */ - asm("" : "+rm"(nsec)); - nsec -= NSEC_PER_SEC; - ++sec; - } - while (nsec < 0) { - asm("" : "+rm"(nsec)); - nsec += NSEC_PER_SEC; - --sec; - } - ts->tv_sec = sec; - ts->tv_nsec = nsec; -} -EXPORT_SYMBOL(set_normalized_timespec64); - -/** - * ns_to_timespec64 - Convert nanoseconds to timespec64 - * @nsec: the nanoseconds value to be converted - * - * Returns the timespec64 representation of the nsec parameter. - */ -struct timespec64 ns_to_timespec64(const s64 nsec) -{ - struct timespec64 ts; - s32 rem; - - if (!nsec) - return (struct timespec64) {0, 0}; - - ts.tv_sec = div_s64_rem(nsec, NSEC_PER_SEC, &rem); - if (unlikely(rem < 0)) { - ts.tv_sec--; - rem += NSEC_PER_SEC; - } - ts.tv_nsec = rem; - - return ts; -} -EXPORT_SYMBOL(ns_to_timespec64); -#endif -/** - * msecs_to_jiffies: - convert milliseconds to jiffies - * @m: time in milliseconds - * - * conversion is done as follows: - * - * - negative values mean 'infinite timeout' (MAX_JIFFY_OFFSET) - * - * - 'too large' values [that would result in larger than - * MAX_JIFFY_OFFSET values] mean 'infinite timeout' too. - * - * - all other values are converted to jiffies by either multiplying - * the input value by a factor or dividing it with a factor and - * handling any 32-bit overflows. - * for the details see __msecs_to_jiffies() - * - * msecs_to_jiffies() checks for the passed in value being a constant - * via __builtin_constant_p() allowing gcc to eliminate most of the - * code, __msecs_to_jiffies() is called if the value passed does not - * allow constant folding and the actual conversion must be done at - * runtime. - * the _msecs_to_jiffies helpers are the HZ dependent conversion - * routines found in include/linux/jiffies.h - */ -unsigned long __msecs_to_jiffies(const unsigned int m) -{ - /* - * Negative value, means infinite timeout: - */ - if ((int)m < 0) - return MAX_JIFFY_OFFSET; - return _msecs_to_jiffies(m); -} -EXPORT_SYMBOL(__msecs_to_jiffies); - -unsigned long __usecs_to_jiffies(const unsigned int u) -{ - if (u > jiffies_to_usecs(MAX_JIFFY_OFFSET)) - return MAX_JIFFY_OFFSET; - return _usecs_to_jiffies(u); -} -EXPORT_SYMBOL(__usecs_to_jiffies); - -/* - * The TICK_NSEC - 1 rounds up the value to the next resolution. Note - * that a remainder subtract here would not do the right thing as the - * resolution values don't fall on second boundries. I.e. the line: - * nsec -= nsec % TICK_NSEC; is NOT a correct resolution rounding. - * Note that due to the small error in the multiplier here, this - * rounding is incorrect for sufficiently large values of tv_nsec, but - * well formed timespecs should have tv_nsec < NSEC_PER_SEC, so we're - * OK. - * - * Rather, we just shift the bits off the right. - * - * The >> (NSEC_JIFFIE_SC - SEC_JIFFIE_SC) converts the scaled nsec - * value to a scaled second value. - */ -static unsigned long -__timespec64_to_jiffies(u64 sec, long nsec) -{ - nsec = nsec + TICK_NSEC - 1; - - if (sec >= MAX_SEC_IN_JIFFIES){ - sec = MAX_SEC_IN_JIFFIES; - nsec = 0; - } - return ((sec * SEC_CONVERSION) + - (((u64)nsec * NSEC_CONVERSION) >> - (NSEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC; - -} - -static unsigned long -__timespec_to_jiffies(unsigned long sec, long nsec) -{ - return __timespec64_to_jiffies((u64)sec, nsec); -} - -unsigned long -timespec64_to_jiffies(const struct timespec64 *value) -{ - return __timespec64_to_jiffies(value->tv_sec, value->tv_nsec); -} -EXPORT_SYMBOL(timespec64_to_jiffies); - -void -jiffies_to_timespec64(const unsigned long jiffies, struct timespec64 *value) -{ - /* - * Convert jiffies to nanoseconds and separate with - * one divide. - */ - u32 rem; - value->tv_sec = div_u64_rem((u64)jiffies * TICK_NSEC, - NSEC_PER_SEC, &rem); - value->tv_nsec = rem; -} -EXPORT_SYMBOL(jiffies_to_timespec64); - -/* - * We could use a similar algorithm to timespec_to_jiffies (with a - * different multiplier for usec instead of nsec). But this has a - * problem with rounding: we can't exactly add TICK_NSEC - 1 to the - * usec value, since it's not necessarily integral. - * - * We could instead round in the intermediate scaled representation - * (i.e. in units of 1/2^(large scale) jiffies) but that's also - * perilous: the scaling introduces a small positive error, which - * combined with a division-rounding-upward (i.e. adding 2^(scale) - 1 - * units to the intermediate before shifting) leads to accidental - * overflow and overestimates. - * - * At the cost of one additional multiplication by a constant, just - * use the timespec implementation. - */ -unsigned long -timeval_to_jiffies(const struct timeval *value) -{ - return __timespec_to_jiffies(value->tv_sec, - value->tv_usec * NSEC_PER_USEC); -} -EXPORT_SYMBOL(timeval_to_jiffies); - -void jiffies_to_timeval(const unsigned long jiffies, struct timeval *value) -{ - /* - * Convert jiffies to nanoseconds and separate with - * one divide. - */ - u32 rem; - - value->tv_sec = div_u64_rem((u64)jiffies * TICK_NSEC, - NSEC_PER_SEC, &rem); - value->tv_usec = rem / NSEC_PER_USEC; -} -EXPORT_SYMBOL(jiffies_to_timeval); - -/* - * Convert jiffies/jiffies_64 to clock_t and back. - */ -clock_t jiffies_to_clock_t(unsigned long x) -{ -#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0 -# if HZ < USER_HZ - return x * (USER_HZ / HZ); -# else - return x / (HZ / USER_HZ); -# endif -#else - return div_u64((u64)x * TICK_NSEC, NSEC_PER_SEC / USER_HZ); -#endif -} -EXPORT_SYMBOL(jiffies_to_clock_t); - -unsigned long clock_t_to_jiffies(unsigned long x) -{ -#if (HZ % USER_HZ)==0 - if (x >= ~0UL / (HZ / USER_HZ)) - return ~0UL; - return x * (HZ / USER_HZ); -#else - /* Don't worry about loss of precision here .. */ - if (x >= ~0UL / HZ * USER_HZ) - return ~0UL; - - /* .. but do try to contain it here */ - return div_u64((u64)x * HZ, USER_HZ); -#endif -} -EXPORT_SYMBOL(clock_t_to_jiffies); - -u64 jiffies_64_to_clock_t(u64 x) -{ -#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0 -# if HZ < USER_HZ - x = div_u64(x * USER_HZ, HZ); -# elif HZ > USER_HZ - x = div_u64(x, HZ / USER_HZ); -# else - /* Nothing to do */ -# endif -#else - /* - * There are better ways that don't overflow early, - * but even this doesn't overflow in hundreds of years - * in 64 bits, so.. - */ - x = div_u64(x * TICK_NSEC, (NSEC_PER_SEC / USER_HZ)); -#endif - return x; -} -EXPORT_SYMBOL(jiffies_64_to_clock_t); - -u64 nsec_to_clock_t(u64 x) -{ -#if (NSEC_PER_SEC % USER_HZ) == 0 - return div_u64(x, NSEC_PER_SEC / USER_HZ); -#elif (USER_HZ % 512) == 0 - return div_u64(x * USER_HZ / 512, NSEC_PER_SEC / 512); -#else - /* - * max relative error 5.7e-8 (1.8s per year) for USER_HZ <= 1024, - * overflow after 64.99 years. - * exact for HZ=60, 72, 90, 120, 144, 180, 300, 600, 900, ... - */ - return div_u64(x * 9, (9ull * NSEC_PER_SEC + (USER_HZ / 2)) / USER_HZ); -#endif -} - -/** - * nsecs_to_jiffies64 - Convert nsecs in u64 to jiffies64 - * - * @n: nsecs in u64 - * - * Unlike {m,u}secs_to_jiffies, type of input is not unsigned int but u64. - * And this doesn't return MAX_JIFFY_OFFSET since this function is designed - * for scheduler, not for use in device drivers to calculate timeout value. - * - * note: - * NSEC_PER_SEC = 10^9 = (5^9 * 2^9) = (1953125 * 512) - * ULLONG_MAX ns = 18446744073.709551615 secs = about 584 years - */ -u64 nsecs_to_jiffies64(u64 n) -{ -#if (NSEC_PER_SEC % HZ) == 0 - /* Common case, HZ = 100, 128, 200, 250, 256, 500, 512, 1000 etc. */ - return div_u64(n, NSEC_PER_SEC / HZ); -#elif (HZ % 512) == 0 - /* overflow after 292 years if HZ = 1024 */ - return div_u64(n * HZ / 512, NSEC_PER_SEC / 512); -#else - /* - * Generic case - optimized for cases where HZ is a multiple of 3. - * overflow after 64.99 years, exact for HZ = 60, 72, 90, 120 etc. - */ - return div_u64(n * 9, (9ull * NSEC_PER_SEC + HZ / 2) / HZ); -#endif -} -EXPORT_SYMBOL(nsecs_to_jiffies64); - -/** - * nsecs_to_jiffies - Convert nsecs in u64 to jiffies - * - * @n: nsecs in u64 - * - * Unlike {m,u}secs_to_jiffies, type of input is not unsigned int but u64. - * And this doesn't return MAX_JIFFY_OFFSET since this function is designed - * for scheduler, not for use in device drivers to calculate timeout value. - * - * note: - * NSEC_PER_SEC = 10^9 = (5^9 * 2^9) = (1953125 * 512) - * ULLONG_MAX ns = 18446744073.709551615 secs = about 584 years - */ -unsigned long nsecs_to_jiffies(u64 n) -{ - return (unsigned long)nsecs_to_jiffies64(n); -} -EXPORT_SYMBOL_GPL(nsecs_to_jiffies); - -/* - * Add two timespec values and do a safety check for overflow. - * It's assumed that both values are valid (>= 0) - */ -struct timespec timespec_add_safe(const struct timespec lhs, - const struct timespec rhs) -{ - struct timespec res; - - set_normalized_timespec(&res, lhs.tv_sec + rhs.tv_sec, - lhs.tv_nsec + rhs.tv_nsec); - - if (res.tv_sec < lhs.tv_sec || res.tv_sec < rhs.tv_sec) - res.tv_sec = TIME_T_MAX; - - return res; -} - -/* - * Add two timespec64 values and do a safety check for overflow. - * It's assumed that both values are valid (>= 0). - * And, each timespec64 is in normalized form. - */ -struct timespec64 timespec64_add_safe(const struct timespec64 lhs, - const struct timespec64 rhs) -{ - struct timespec64 res; - - set_normalized_timespec64(&res, (timeu64_t) lhs.tv_sec + rhs.tv_sec, - lhs.tv_nsec + rhs.tv_nsec); - - if (unlikely(res.tv_sec < lhs.tv_sec || res.tv_sec < rhs.tv_sec)) { - res.tv_sec = TIME64_MAX; - res.tv_nsec = 0; - } - - return res; -} diff --git a/src/linux/kernel/time/timeconst.bc b/src/linux/kernel/time/timeconst.bc deleted file mode 100644 index c486889..0000000 --- a/src/linux/kernel/time/timeconst.bc +++ /dev/null @@ -1,109 +0,0 @@ -scale=0 - -define gcd(a,b) { - auto t; - while (b) { - t = b; - b = a % b; - a = t; - } - return a; -} - -/* Division by reciprocal multiplication. */ -define fmul(b,n,d) { - return (2^b*n+d-1)/d; -} - -/* Adjustment factor when a ceiling value is used. Use as: - (imul * n) + (fmulxx * n + fadjxx) >> xx) */ -define fadj(b,n,d) { - auto v; - d = d/gcd(n,d); - v = 2^b*(d-1)/d; - return v; -} - -/* Compute the appropriate mul/adj values as well as a shift count, - which brings the mul value into the range 2^b-1 <= x < 2^b. Such - a shift value will be correct in the signed integer range and off - by at most one in the upper half of the unsigned range. */ -define fmuls(b,n,d) { - auto s, m; - for (s = 0; 1; s++) { - m = fmul(s,n,d); - if (m >= 2^(b-1)) - return s; - } - return 0; -} - -define timeconst(hz) { - print "/* Automatically generated by kernel/time/timeconst.bc */\n" - print "/* Time conversion constants for HZ == ", hz, " */\n" - print "\n" - - print "#ifndef KERNEL_TIMECONST_H\n" - print "#define KERNEL_TIMECONST_H\n\n" - - print "#include \n" - print "#include \n\n" - - print "#if HZ != ", hz, "\n" - print "#error \qinclude/generated/timeconst.h has the wrong HZ value!\q\n" - print "#endif\n\n" - - if (hz < 2) { - print "#error Totally bogus HZ value!\n" - } else { - s=fmuls(32,1000,hz) - obase=16 - print "#define HZ_TO_MSEC_MUL32\tU64_C(0x", fmul(s,1000,hz), ")\n" - print "#define HZ_TO_MSEC_ADJ32\tU64_C(0x", fadj(s,1000,hz), ")\n" - obase=10 - print "#define HZ_TO_MSEC_SHR32\t", s, "\n" - - s=fmuls(32,hz,1000) - obase=16 - print "#define MSEC_TO_HZ_MUL32\tU64_C(0x", fmul(s,hz,1000), ")\n" - print "#define MSEC_TO_HZ_ADJ32\tU64_C(0x", fadj(s,hz,1000), ")\n" - obase=10 - print "#define MSEC_TO_HZ_SHR32\t", s, "\n" - - obase=10 - cd=gcd(hz,1000) - print "#define HZ_TO_MSEC_NUM\t\t", 1000/cd, "\n" - print "#define HZ_TO_MSEC_DEN\t\t", hz/cd, "\n" - print "#define MSEC_TO_HZ_NUM\t\t", hz/cd, "\n" - print "#define MSEC_TO_HZ_DEN\t\t", 1000/cd, "\n" - print "\n" - - s=fmuls(32,1000000,hz) - obase=16 - print "#define HZ_TO_USEC_MUL32\tU64_C(0x", fmul(s,1000000,hz), ")\n" - print "#define HZ_TO_USEC_ADJ32\tU64_C(0x", fadj(s,1000000,hz), ")\n" - obase=10 - print "#define HZ_TO_USEC_SHR32\t", s, "\n" - - s=fmuls(32,hz,1000000) - obase=16 - print "#define USEC_TO_HZ_MUL32\tU64_C(0x", fmul(s,hz,1000000), ")\n" - print "#define USEC_TO_HZ_ADJ32\tU64_C(0x", fadj(s,hz,1000000), ")\n" - obase=10 - print "#define USEC_TO_HZ_SHR32\t", s, "\n" - - obase=10 - cd=gcd(hz,1000000) - print "#define HZ_TO_USEC_NUM\t\t", 1000000/cd, "\n" - print "#define HZ_TO_USEC_DEN\t\t", hz/cd, "\n" - print "#define USEC_TO_HZ_NUM\t\t", hz/cd, "\n" - print "#define USEC_TO_HZ_DEN\t\t", 1000000/cd, "\n" - print "\n" - - print "#endif /* KERNEL_TIMECONST_H */\n" - } - halt -} - -hz = read(); -timeconst(hz) diff --git a/src/linux/kernel/time/timeconv.c b/src/linux/kernel/time/timeconv.c deleted file mode 100644 index 7142580..0000000 --- a/src/linux/kernel/time/timeconv.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc. - * This file is part of the GNU C Library. - * Contributed by Paul Eggert (eggert@twinsun.com). - * - * The GNU C Library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. - * - * The GNU C Library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with the GNU C Library; see the file COPYING.LIB. If not, - * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - -/* - * Converts the calendar time to broken-down time representation - * Based on code from glibc-2.6 - * - * 2009-7-14: - * Moved from glibc-2.6 to kernel by Zhaolei - */ - -#include -#include - -/* - * Nonzero if YEAR is a leap year (every 4 years, - * except every 100th isn't, and every 400th is). - */ -static int __isleap(long year) -{ - return (year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0); -} - -/* do a mathdiv for long type */ -static long math_div(long a, long b) -{ - return a / b - (a % b < 0); -} - -/* How many leap years between y1 and y2, y1 must less or equal to y2 */ -static long leaps_between(long y1, long y2) -{ - long leaps1 = math_div(y1 - 1, 4) - math_div(y1 - 1, 100) - + math_div(y1 - 1, 400); - long leaps2 = math_div(y2 - 1, 4) - math_div(y2 - 1, 100) - + math_div(y2 - 1, 400); - return leaps2 - leaps1; -} - -/* How many days come before each month (0-12). */ -static const unsigned short __mon_yday[2][13] = { - /* Normal years. */ - {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, - /* Leap years. */ - {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} -}; - -#define SECS_PER_HOUR (60 * 60) -#define SECS_PER_DAY (SECS_PER_HOUR * 24) - -/** - * time64_to_tm - converts the calendar time to local broken-down time - * - * @totalsecs the number of seconds elapsed since 00:00:00 on January 1, 1970, - * Coordinated Universal Time (UTC). - * @offset offset seconds adding to totalsecs. - * @result pointer to struct tm variable to receive broken-down time - */ -void time64_to_tm(time64_t totalsecs, int offset, struct tm *result) -{ - long days, rem, y; - int remainder; - const unsigned short *ip; - - days = div_s64_rem(totalsecs, SECS_PER_DAY, &remainder); - rem = remainder; - rem += offset; - while (rem < 0) { - rem += SECS_PER_DAY; - --days; - } - while (rem >= SECS_PER_DAY) { - rem -= SECS_PER_DAY; - ++days; - } - - result->tm_hour = rem / SECS_PER_HOUR; - rem %= SECS_PER_HOUR; - result->tm_min = rem / 60; - result->tm_sec = rem % 60; - - /* January 1, 1970 was a Thursday. */ - result->tm_wday = (4 + days) % 7; - if (result->tm_wday < 0) - result->tm_wday += 7; - - y = 1970; - - while (days < 0 || days >= (__isleap(y) ? 366 : 365)) { - /* Guess a corrected year, assuming 365 days per year. */ - long yg = y + math_div(days, 365); - - /* Adjust DAYS and Y to match the guessed year. */ - days -= (yg - y) * 365 + leaps_between(y, yg); - y = yg; - } - - result->tm_year = y - 1900; - - result->tm_yday = days; - - ip = __mon_yday[__isleap(y)]; - for (y = 11; days < ip[y]; y--) - continue; - days -= ip[y]; - - result->tm_mon = y; - result->tm_mday = days + 1; -} -EXPORT_SYMBOL(time64_to_tm); diff --git a/src/linux/kernel/time/timecounter.c b/src/linux/kernel/time/timecounter.c deleted file mode 100644 index 4687b31..0000000 --- a/src/linux/kernel/time/timecounter.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * linux/kernel/time/timecounter.c - * - * based on code that migrated away from - * linux/kernel/time/clocksource.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include - -void timecounter_init(struct timecounter *tc, - const struct cyclecounter *cc, - u64 start_tstamp) -{ - tc->cc = cc; - tc->cycle_last = cc->read(cc); - tc->nsec = start_tstamp; - tc->mask = (1ULL << cc->shift) - 1; - tc->frac = 0; -} -EXPORT_SYMBOL_GPL(timecounter_init); - -/** - * timecounter_read_delta - get nanoseconds since last call of this function - * @tc: Pointer to time counter - * - * When the underlying cycle counter runs over, this will be handled - * correctly as long as it does not run over more than once between - * calls. - * - * The first call to this function for a new time counter initializes - * the time tracking and returns an undefined result. - */ -static u64 timecounter_read_delta(struct timecounter *tc) -{ - cycle_t cycle_now, cycle_delta; - u64 ns_offset; - - /* read cycle counter: */ - cycle_now = tc->cc->read(tc->cc); - - /* calculate the delta since the last timecounter_read_delta(): */ - cycle_delta = (cycle_now - tc->cycle_last) & tc->cc->mask; - - /* convert to nanoseconds: */ - ns_offset = cyclecounter_cyc2ns(tc->cc, cycle_delta, - tc->mask, &tc->frac); - - /* update time stamp of timecounter_read_delta() call: */ - tc->cycle_last = cycle_now; - - return ns_offset; -} - -u64 timecounter_read(struct timecounter *tc) -{ - u64 nsec; - - /* increment time by nanoseconds since last call */ - nsec = timecounter_read_delta(tc); - nsec += tc->nsec; - tc->nsec = nsec; - - return nsec; -} -EXPORT_SYMBOL_GPL(timecounter_read); - -/* - * This is like cyclecounter_cyc2ns(), but it is used for computing a - * time previous to the time stored in the cycle counter. - */ -static u64 cc_cyc2ns_backwards(const struct cyclecounter *cc, - cycle_t cycles, u64 mask, u64 frac) -{ - u64 ns = (u64) cycles; - - ns = ((ns * cc->mult) - frac) >> cc->shift; - - return ns; -} - -u64 timecounter_cyc2time(struct timecounter *tc, - cycle_t cycle_tstamp) -{ - u64 delta = (cycle_tstamp - tc->cycle_last) & tc->cc->mask; - u64 nsec = tc->nsec, frac = tc->frac; - - /* - * Instead of always treating cycle_tstamp as more recent - * than tc->cycle_last, detect when it is too far in the - * future and treat it as old time stamp instead. - */ - if (delta > tc->cc->mask / 2) { - delta = (tc->cycle_last - cycle_tstamp) & tc->cc->mask; - nsec -= cc_cyc2ns_backwards(tc->cc, delta, tc->mask, frac); - } else { - nsec += cyclecounter_cyc2ns(tc->cc, delta, tc->mask, &frac); - } - - return nsec; -} -EXPORT_SYMBOL_GPL(timecounter_cyc2time); diff --git a/src/linux/kernel/time/timekeeping.c b/src/linux/kernel/time/timekeeping.c deleted file mode 100644 index 37dec7e..0000000 --- a/src/linux/kernel/time/timekeeping.c +++ /dev/null @@ -1,2335 +0,0 @@ -/* - * linux/kernel/time/timekeeping.c - * - * Kernel timekeeping code and accessor functions - * - * This code was moved from linux/kernel/timer.c. - * Please see that file for copyright and history logs. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "tick-internal.h" -#include "ntp_internal.h" -#include "timekeeping_internal.h" - -#define TK_CLEAR_NTP (1 << 0) -#define TK_MIRROR (1 << 1) -#define TK_CLOCK_WAS_SET (1 << 2) - -/* - * The most important data for readout fits into a single 64 byte - * cache line. - */ -static struct { - seqcount_t seq; - struct timekeeper timekeeper; -} tk_core ____cacheline_aligned; - -static DEFINE_RAW_SPINLOCK(timekeeper_lock); -static struct timekeeper shadow_timekeeper; - -/** - * struct tk_fast - NMI safe timekeeper - * @seq: Sequence counter for protecting updates. The lowest bit - * is the index for the tk_read_base array - * @base: tk_read_base array. Access is indexed by the lowest bit of - * @seq. - * - * See @update_fast_timekeeper() below. - */ -struct tk_fast { - seqcount_t seq; - struct tk_read_base base[2]; -}; - -static struct tk_fast tk_fast_mono ____cacheline_aligned; -static struct tk_fast tk_fast_raw ____cacheline_aligned; - -/* flag for if timekeeping is suspended */ -int __read_mostly timekeeping_suspended; - -static inline void tk_normalize_xtime(struct timekeeper *tk) -{ - while (tk->tkr_mono.xtime_nsec >= ((u64)NSEC_PER_SEC << tk->tkr_mono.shift)) { - tk->tkr_mono.xtime_nsec -= (u64)NSEC_PER_SEC << tk->tkr_mono.shift; - tk->xtime_sec++; - } -} - -static inline struct timespec64 tk_xtime(struct timekeeper *tk) -{ - struct timespec64 ts; - - ts.tv_sec = tk->xtime_sec; - ts.tv_nsec = (long)(tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift); - return ts; -} - -static void tk_set_xtime(struct timekeeper *tk, const struct timespec64 *ts) -{ - tk->xtime_sec = ts->tv_sec; - tk->tkr_mono.xtime_nsec = (u64)ts->tv_nsec << tk->tkr_mono.shift; -} - -static void tk_xtime_add(struct timekeeper *tk, const struct timespec64 *ts) -{ - tk->xtime_sec += ts->tv_sec; - tk->tkr_mono.xtime_nsec += (u64)ts->tv_nsec << tk->tkr_mono.shift; - tk_normalize_xtime(tk); -} - -static void tk_set_wall_to_mono(struct timekeeper *tk, struct timespec64 wtm) -{ - struct timespec64 tmp; - - /* - * Verify consistency of: offset_real = -wall_to_monotonic - * before modifying anything - */ - set_normalized_timespec64(&tmp, -tk->wall_to_monotonic.tv_sec, - -tk->wall_to_monotonic.tv_nsec); - WARN_ON_ONCE(tk->offs_real.tv64 != timespec64_to_ktime(tmp).tv64); - tk->wall_to_monotonic = wtm; - set_normalized_timespec64(&tmp, -wtm.tv_sec, -wtm.tv_nsec); - tk->offs_real = timespec64_to_ktime(tmp); - tk->offs_tai = ktime_add(tk->offs_real, ktime_set(tk->tai_offset, 0)); -} - -static inline void tk_update_sleep_time(struct timekeeper *tk, ktime_t delta) -{ - tk->offs_boot = ktime_add(tk->offs_boot, delta); -} - -#ifdef CONFIG_DEBUG_TIMEKEEPING -#define WARNING_FREQ (HZ*300) /* 5 minute rate-limiting */ - -static void timekeeping_check_update(struct timekeeper *tk, cycle_t offset) -{ - - cycle_t max_cycles = tk->tkr_mono.clock->max_cycles; - const char *name = tk->tkr_mono.clock->name; - - if (offset > max_cycles) { - printk_deferred("WARNING: timekeeping: Cycle offset (%lld) is larger than allowed by the '%s' clock's max_cycles value (%lld): time overflow danger\n", - offset, name, max_cycles); - printk_deferred(" timekeeping: Your kernel is sick, but tries to cope by capping time updates\n"); - } else { - if (offset > (max_cycles >> 1)) { - printk_deferred("INFO: timekeeping: Cycle offset (%lld) is larger than the '%s' clock's 50%% safety margin (%lld)\n", - offset, name, max_cycles >> 1); - printk_deferred(" timekeeping: Your kernel is still fine, but is feeling a bit nervous\n"); - } - } - - if (tk->underflow_seen) { - if (jiffies - tk->last_warning > WARNING_FREQ) { - printk_deferred("WARNING: Underflow in clocksource '%s' observed, time update ignored.\n", name); - printk_deferred(" Please report this, consider using a different clocksource, if possible.\n"); - printk_deferred(" Your kernel is probably still fine.\n"); - tk->last_warning = jiffies; - } - tk->underflow_seen = 0; - } - - if (tk->overflow_seen) { - if (jiffies - tk->last_warning > WARNING_FREQ) { - printk_deferred("WARNING: Overflow in clocksource '%s' observed, time update capped.\n", name); - printk_deferred(" Please report this, consider using a different clocksource, if possible.\n"); - printk_deferred(" Your kernel is probably still fine.\n"); - tk->last_warning = jiffies; - } - tk->overflow_seen = 0; - } -} - -static inline cycle_t timekeeping_get_delta(struct tk_read_base *tkr) -{ - struct timekeeper *tk = &tk_core.timekeeper; - cycle_t now, last, mask, max, delta; - unsigned int seq; - - /* - * Since we're called holding a seqlock, the data may shift - * under us while we're doing the calculation. This can cause - * false positives, since we'd note a problem but throw the - * results away. So nest another seqlock here to atomically - * grab the points we are checking with. - */ - do { - seq = read_seqcount_begin(&tk_core.seq); - now = tkr->read(tkr->clock); - last = tkr->cycle_last; - mask = tkr->mask; - max = tkr->clock->max_cycles; - } while (read_seqcount_retry(&tk_core.seq, seq)); - - delta = clocksource_delta(now, last, mask); - - /* - * Try to catch underflows by checking if we are seeing small - * mask-relative negative values. - */ - if (unlikely((~delta & mask) < (mask >> 3))) { - tk->underflow_seen = 1; - delta = 0; - } - - /* Cap delta value to the max_cycles values to avoid mult overflows */ - if (unlikely(delta > max)) { - tk->overflow_seen = 1; - delta = tkr->clock->max_cycles; - } - - return delta; -} -#else -static inline void timekeeping_check_update(struct timekeeper *tk, cycle_t offset) -{ -} -static inline cycle_t timekeeping_get_delta(struct tk_read_base *tkr) -{ - cycle_t cycle_now, delta; - - /* read clocksource */ - cycle_now = tkr->read(tkr->clock); - - /* calculate the delta since the last update_wall_time */ - delta = clocksource_delta(cycle_now, tkr->cycle_last, tkr->mask); - - return delta; -} -#endif - -/** - * tk_setup_internals - Set up internals to use clocksource clock. - * - * @tk: The target timekeeper to setup. - * @clock: Pointer to clocksource. - * - * Calculates a fixed cycle/nsec interval for a given clocksource/adjustment - * pair and interval request. - * - * Unless you're the timekeeping code, you should not be using this! - */ -static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock) -{ - cycle_t interval; - u64 tmp, ntpinterval; - struct clocksource *old_clock; - - ++tk->cs_was_changed_seq; - old_clock = tk->tkr_mono.clock; - tk->tkr_mono.clock = clock; - tk->tkr_mono.read = clock->read; - tk->tkr_mono.mask = clock->mask; - tk->tkr_mono.cycle_last = tk->tkr_mono.read(clock); - - tk->tkr_raw.clock = clock; - tk->tkr_raw.read = clock->read; - tk->tkr_raw.mask = clock->mask; - tk->tkr_raw.cycle_last = tk->tkr_mono.cycle_last; - - /* Do the ns -> cycle conversion first, using original mult */ - tmp = NTP_INTERVAL_LENGTH; - tmp <<= clock->shift; - ntpinterval = tmp; - tmp += clock->mult/2; - do_div(tmp, clock->mult); - if (tmp == 0) - tmp = 1; - - interval = (cycle_t) tmp; - tk->cycle_interval = interval; - - /* Go back from cycles -> shifted ns */ - tk->xtime_interval = (u64) interval * clock->mult; - tk->xtime_remainder = ntpinterval - tk->xtime_interval; - tk->raw_interval = - ((u64) interval * clock->mult) >> clock->shift; - - /* if changing clocks, convert xtime_nsec shift units */ - if (old_clock) { - int shift_change = clock->shift - old_clock->shift; - if (shift_change < 0) - tk->tkr_mono.xtime_nsec >>= -shift_change; - else - tk->tkr_mono.xtime_nsec <<= shift_change; - } - tk->tkr_raw.xtime_nsec = 0; - - tk->tkr_mono.shift = clock->shift; - tk->tkr_raw.shift = clock->shift; - - tk->ntp_error = 0; - tk->ntp_error_shift = NTP_SCALE_SHIFT - clock->shift; - tk->ntp_tick = ntpinterval << tk->ntp_error_shift; - - /* - * The timekeeper keeps its own mult values for the currently - * active clocksource. These value will be adjusted via NTP - * to counteract clock drifting. - */ - tk->tkr_mono.mult = clock->mult; - tk->tkr_raw.mult = clock->mult; - tk->ntp_err_mult = 0; -} - -/* Timekeeper helper functions. */ - -#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET -static u32 default_arch_gettimeoffset(void) { return 0; } -u32 (*arch_gettimeoffset)(void) = default_arch_gettimeoffset; -#else -static inline u32 arch_gettimeoffset(void) { return 0; } -#endif - -static inline s64 timekeeping_delta_to_ns(struct tk_read_base *tkr, - cycle_t delta) -{ - s64 nsec; - - nsec = delta * tkr->mult + tkr->xtime_nsec; - nsec >>= tkr->shift; - - /* If arch requires, add in get_arch_timeoffset() */ - return nsec + arch_gettimeoffset(); -} - -static inline s64 timekeeping_get_ns(struct tk_read_base *tkr) -{ - cycle_t delta; - - delta = timekeeping_get_delta(tkr); - return timekeeping_delta_to_ns(tkr, delta); -} - -static inline s64 timekeeping_cycles_to_ns(struct tk_read_base *tkr, - cycle_t cycles) -{ - cycle_t delta; - - /* calculate the delta since the last update_wall_time */ - delta = clocksource_delta(cycles, tkr->cycle_last, tkr->mask); - return timekeeping_delta_to_ns(tkr, delta); -} - -/** - * update_fast_timekeeper - Update the fast and NMI safe monotonic timekeeper. - * @tkr: Timekeeping readout base from which we take the update - * - * We want to use this from any context including NMI and tracing / - * instrumenting the timekeeping code itself. - * - * Employ the latch technique; see @raw_write_seqcount_latch. - * - * So if a NMI hits the update of base[0] then it will use base[1] - * which is still consistent. In the worst case this can result is a - * slightly wrong timestamp (a few nanoseconds). See - * @ktime_get_mono_fast_ns. - */ -static void update_fast_timekeeper(struct tk_read_base *tkr, struct tk_fast *tkf) -{ - struct tk_read_base *base = tkf->base; - - /* Force readers off to base[1] */ - raw_write_seqcount_latch(&tkf->seq); - - /* Update base[0] */ - memcpy(base, tkr, sizeof(*base)); - - /* Force readers back to base[0] */ - raw_write_seqcount_latch(&tkf->seq); - - /* Update base[1] */ - memcpy(base + 1, base, sizeof(*base)); -} - -/** - * ktime_get_mono_fast_ns - Fast NMI safe access to clock monotonic - * - * This timestamp is not guaranteed to be monotonic across an update. - * The timestamp is calculated by: - * - * now = base_mono + clock_delta * slope - * - * So if the update lowers the slope, readers who are forced to the - * not yet updated second array are still using the old steeper slope. - * - * tmono - * ^ - * | o n - * | o n - * | u - * | o - * |o - * |12345678---> reader order - * - * o = old slope - * u = update - * n = new slope - * - * So reader 6 will observe time going backwards versus reader 5. - * - * While other CPUs are likely to be able observe that, the only way - * for a CPU local observation is when an NMI hits in the middle of - * the update. Timestamps taken from that NMI context might be ahead - * of the following timestamps. Callers need to be aware of that and - * deal with it. - */ -static __always_inline u64 __ktime_get_fast_ns(struct tk_fast *tkf) -{ - struct tk_read_base *tkr; - unsigned int seq; - u64 now; - - do { - seq = raw_read_seqcount_latch(&tkf->seq); - tkr = tkf->base + (seq & 0x01); - now = ktime_to_ns(tkr->base); - - now += timekeeping_delta_to_ns(tkr, - clocksource_delta( - tkr->read(tkr->clock), - tkr->cycle_last, - tkr->mask)); - } while (read_seqcount_retry(&tkf->seq, seq)); - - return now; -} - -u64 ktime_get_mono_fast_ns(void) -{ - return __ktime_get_fast_ns(&tk_fast_mono); -} -EXPORT_SYMBOL_GPL(ktime_get_mono_fast_ns); - -u64 ktime_get_raw_fast_ns(void) -{ - return __ktime_get_fast_ns(&tk_fast_raw); -} -EXPORT_SYMBOL_GPL(ktime_get_raw_fast_ns); - -/* Suspend-time cycles value for halted fast timekeeper. */ -static cycle_t cycles_at_suspend; - -static cycle_t dummy_clock_read(struct clocksource *cs) -{ - return cycles_at_suspend; -} - -/** - * halt_fast_timekeeper - Prevent fast timekeeper from accessing clocksource. - * @tk: Timekeeper to snapshot. - * - * It generally is unsafe to access the clocksource after timekeeping has been - * suspended, so take a snapshot of the readout base of @tk and use it as the - * fast timekeeper's readout base while suspended. It will return the same - * number of cycles every time until timekeeping is resumed at which time the - * proper readout base for the fast timekeeper will be restored automatically. - */ -static void halt_fast_timekeeper(struct timekeeper *tk) -{ - static struct tk_read_base tkr_dummy; - struct tk_read_base *tkr = &tk->tkr_mono; - - memcpy(&tkr_dummy, tkr, sizeof(tkr_dummy)); - cycles_at_suspend = tkr->read(tkr->clock); - tkr_dummy.read = dummy_clock_read; - update_fast_timekeeper(&tkr_dummy, &tk_fast_mono); - - tkr = &tk->tkr_raw; - memcpy(&tkr_dummy, tkr, sizeof(tkr_dummy)); - tkr_dummy.read = dummy_clock_read; - update_fast_timekeeper(&tkr_dummy, &tk_fast_raw); -} - -#ifdef CONFIG_GENERIC_TIME_VSYSCALL_OLD - -static inline void update_vsyscall(struct timekeeper *tk) -{ - struct timespec xt, wm; - - xt = timespec64_to_timespec(tk_xtime(tk)); - wm = timespec64_to_timespec(tk->wall_to_monotonic); - update_vsyscall_old(&xt, &wm, tk->tkr_mono.clock, tk->tkr_mono.mult, - tk->tkr_mono.cycle_last); -} - -static inline void old_vsyscall_fixup(struct timekeeper *tk) -{ - s64 remainder; - - /* - * Store only full nanoseconds into xtime_nsec after rounding - * it up and add the remainder to the error difference. - * XXX - This is necessary to avoid small 1ns inconsistnecies caused - * by truncating the remainder in vsyscalls. However, it causes - * additional work to be done in timekeeping_adjust(). Once - * the vsyscall implementations are converted to use xtime_nsec - * (shifted nanoseconds), and CONFIG_GENERIC_TIME_VSYSCALL_OLD - * users are removed, this can be killed. - */ - remainder = tk->tkr_mono.xtime_nsec & ((1ULL << tk->tkr_mono.shift) - 1); - if (remainder != 0) { - tk->tkr_mono.xtime_nsec -= remainder; - tk->tkr_mono.xtime_nsec += 1ULL << tk->tkr_mono.shift; - tk->ntp_error += remainder << tk->ntp_error_shift; - tk->ntp_error -= (1ULL << tk->tkr_mono.shift) << tk->ntp_error_shift; - } -} -#else -#define old_vsyscall_fixup(tk) -#endif - -static RAW_NOTIFIER_HEAD(pvclock_gtod_chain); - -static void update_pvclock_gtod(struct timekeeper *tk, bool was_set) -{ - raw_notifier_call_chain(&pvclock_gtod_chain, was_set, tk); -} - -/** - * pvclock_gtod_register_notifier - register a pvclock timedata update listener - */ -int pvclock_gtod_register_notifier(struct notifier_block *nb) -{ - struct timekeeper *tk = &tk_core.timekeeper; - unsigned long flags; - int ret; - - raw_spin_lock_irqsave(&timekeeper_lock, flags); - ret = raw_notifier_chain_register(&pvclock_gtod_chain, nb); - update_pvclock_gtod(tk, true); - raw_spin_unlock_irqrestore(&timekeeper_lock, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(pvclock_gtod_register_notifier); - -/** - * pvclock_gtod_unregister_notifier - unregister a pvclock - * timedata update listener - */ -int pvclock_gtod_unregister_notifier(struct notifier_block *nb) -{ - unsigned long flags; - int ret; - - raw_spin_lock_irqsave(&timekeeper_lock, flags); - ret = raw_notifier_chain_unregister(&pvclock_gtod_chain, nb); - raw_spin_unlock_irqrestore(&timekeeper_lock, flags); - - return ret; -} -EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier); - -/* - * tk_update_leap_state - helper to update the next_leap_ktime - */ -static inline void tk_update_leap_state(struct timekeeper *tk) -{ - tk->next_leap_ktime = ntp_get_next_leap(); - if (tk->next_leap_ktime.tv64 != KTIME_MAX) - /* Convert to monotonic time */ - tk->next_leap_ktime = ktime_sub(tk->next_leap_ktime, tk->offs_real); -} - -/* - * Update the ktime_t based scalar nsec members of the timekeeper - */ -static inline void tk_update_ktime_data(struct timekeeper *tk) -{ - u64 seconds; - u32 nsec; - - /* - * The xtime based monotonic readout is: - * nsec = (xtime_sec + wtm_sec) * 1e9 + wtm_nsec + now(); - * The ktime based monotonic readout is: - * nsec = base_mono + now(); - * ==> base_mono = (xtime_sec + wtm_sec) * 1e9 + wtm_nsec - */ - seconds = (u64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec); - nsec = (u32) tk->wall_to_monotonic.tv_nsec; - tk->tkr_mono.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec); - - /* Update the monotonic raw base */ - tk->tkr_raw.base = timespec64_to_ktime(tk->raw_time); - - /* - * The sum of the nanoseconds portions of xtime and - * wall_to_monotonic can be greater/equal one second. Take - * this into account before updating tk->ktime_sec. - */ - nsec += (u32)(tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift); - if (nsec >= NSEC_PER_SEC) - seconds++; - tk->ktime_sec = seconds; -} - -/* must hold timekeeper_lock */ -static void timekeeping_update(struct timekeeper *tk, unsigned int action) -{ - if (action & TK_CLEAR_NTP) { - tk->ntp_error = 0; - ntp_clear(); - } - - tk_update_leap_state(tk); - tk_update_ktime_data(tk); - - update_vsyscall(tk); - update_pvclock_gtod(tk, action & TK_CLOCK_WAS_SET); - - update_fast_timekeeper(&tk->tkr_mono, &tk_fast_mono); - update_fast_timekeeper(&tk->tkr_raw, &tk_fast_raw); - - if (action & TK_CLOCK_WAS_SET) - tk->clock_was_set_seq++; - /* - * The mirroring of the data to the shadow-timekeeper needs - * to happen last here to ensure we don't over-write the - * timekeeper structure on the next update with stale data - */ - if (action & TK_MIRROR) - memcpy(&shadow_timekeeper, &tk_core.timekeeper, - sizeof(tk_core.timekeeper)); -} - -/** - * timekeeping_forward_now - update clock to the current time - * - * Forward the current clock to update its state since the last call to - * update_wall_time(). This is useful before significant clock changes, - * as it avoids having to deal with this time offset explicitly. - */ -static void timekeeping_forward_now(struct timekeeper *tk) -{ - struct clocksource *clock = tk->tkr_mono.clock; - cycle_t cycle_now, delta; - s64 nsec; - - cycle_now = tk->tkr_mono.read(clock); - delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last, tk->tkr_mono.mask); - tk->tkr_mono.cycle_last = cycle_now; - tk->tkr_raw.cycle_last = cycle_now; - - tk->tkr_mono.xtime_nsec += delta * tk->tkr_mono.mult; - - /* If arch requires, add in get_arch_timeoffset() */ - tk->tkr_mono.xtime_nsec += (u64)arch_gettimeoffset() << tk->tkr_mono.shift; - - tk_normalize_xtime(tk); - - nsec = clocksource_cyc2ns(delta, tk->tkr_raw.mult, tk->tkr_raw.shift); - timespec64_add_ns(&tk->raw_time, nsec); -} - -/** - * __getnstimeofday64 - Returns the time of day in a timespec64. - * @ts: pointer to the timespec to be set - * - * Updates the time of day in the timespec. - * Returns 0 on success, or -ve when suspended (timespec will be undefined). - */ -int __getnstimeofday64(struct timespec64 *ts) -{ - struct timekeeper *tk = &tk_core.timekeeper; - unsigned long seq; - s64 nsecs = 0; - - do { - seq = read_seqcount_begin(&tk_core.seq); - - ts->tv_sec = tk->xtime_sec; - nsecs = timekeeping_get_ns(&tk->tkr_mono); - - } while (read_seqcount_retry(&tk_core.seq, seq)); - - ts->tv_nsec = 0; - timespec64_add_ns(ts, nsecs); - - /* - * Do not bail out early, in case there were callers still using - * the value, even in the face of the WARN_ON. - */ - if (unlikely(timekeeping_suspended)) - return -EAGAIN; - return 0; -} -EXPORT_SYMBOL(__getnstimeofday64); - -/** - * getnstimeofday64 - Returns the time of day in a timespec64. - * @ts: pointer to the timespec64 to be set - * - * Returns the time of day in a timespec64 (WARN if suspended). - */ -void getnstimeofday64(struct timespec64 *ts) -{ - WARN_ON(__getnstimeofday64(ts)); -} -EXPORT_SYMBOL(getnstimeofday64); - -ktime_t ktime_get(void) -{ - struct timekeeper *tk = &tk_core.timekeeper; - unsigned int seq; - ktime_t base; - s64 nsecs; - - WARN_ON(timekeeping_suspended); - - do { - seq = read_seqcount_begin(&tk_core.seq); - base = tk->tkr_mono.base; - nsecs = timekeeping_get_ns(&tk->tkr_mono); - - } while (read_seqcount_retry(&tk_core.seq, seq)); - - return ktime_add_ns(base, nsecs); -} -EXPORT_SYMBOL_GPL(ktime_get); - -u32 ktime_get_resolution_ns(void) -{ - struct timekeeper *tk = &tk_core.timekeeper; - unsigned int seq; - u32 nsecs; - - WARN_ON(timekeeping_suspended); - - do { - seq = read_seqcount_begin(&tk_core.seq); - nsecs = tk->tkr_mono.mult >> tk->tkr_mono.shift; - } while (read_seqcount_retry(&tk_core.seq, seq)); - - return nsecs; -} -EXPORT_SYMBOL_GPL(ktime_get_resolution_ns); - -static ktime_t *offsets[TK_OFFS_MAX] = { - [TK_OFFS_REAL] = &tk_core.timekeeper.offs_real, - [TK_OFFS_BOOT] = &tk_core.timekeeper.offs_boot, - [TK_OFFS_TAI] = &tk_core.timekeeper.offs_tai, -}; - -ktime_t ktime_get_with_offset(enum tk_offsets offs) -{ - struct timekeeper *tk = &tk_core.timekeeper; - unsigned int seq; - ktime_t base, *offset = offsets[offs]; - s64 nsecs; - - WARN_ON(timekeeping_suspended); - - do { - seq = read_seqcount_begin(&tk_core.seq); - base = ktime_add(tk->tkr_mono.base, *offset); - nsecs = timekeeping_get_ns(&tk->tkr_mono); - - } while (read_seqcount_retry(&tk_core.seq, seq)); - - return ktime_add_ns(base, nsecs); - -} -EXPORT_SYMBOL_GPL(ktime_get_with_offset); - -/** - * ktime_mono_to_any() - convert mononotic time to any other time - * @tmono: time to convert. - * @offs: which offset to use - */ -ktime_t ktime_mono_to_any(ktime_t tmono, enum tk_offsets offs) -{ - ktime_t *offset = offsets[offs]; - unsigned long seq; - ktime_t tconv; - - do { - seq = read_seqcount_begin(&tk_core.seq); - tconv = ktime_add(tmono, *offset); - } while (read_seqcount_retry(&tk_core.seq, seq)); - - return tconv; -} -EXPORT_SYMBOL_GPL(ktime_mono_to_any); - -/** - * ktime_get_raw - Returns the raw monotonic time in ktime_t format - */ -ktime_t ktime_get_raw(void) -{ - struct timekeeper *tk = &tk_core.timekeeper; - unsigned int seq; - ktime_t base; - s64 nsecs; - - do { - seq = read_seqcount_begin(&tk_core.seq); - base = tk->tkr_raw.base; - nsecs = timekeeping_get_ns(&tk->tkr_raw); - - } while (read_seqcount_retry(&tk_core.seq, seq)); - - return ktime_add_ns(base, nsecs); -} -EXPORT_SYMBOL_GPL(ktime_get_raw); - -/** - * ktime_get_ts64 - get the monotonic clock in timespec64 format - * @ts: pointer to timespec variable - * - * The function calculates the monotonic clock from the realtime - * clock and the wall_to_monotonic offset and stores the result - * in normalized timespec64 format in the variable pointed to by @ts. - */ -void ktime_get_ts64(struct timespec64 *ts) -{ - struct timekeeper *tk = &tk_core.timekeeper; - struct timespec64 tomono; - s64 nsec; - unsigned int seq; - - WARN_ON(timekeeping_suspended); - - do { - seq = read_seqcount_begin(&tk_core.seq); - ts->tv_sec = tk->xtime_sec; - nsec = timekeeping_get_ns(&tk->tkr_mono); - tomono = tk->wall_to_monotonic; - - } while (read_seqcount_retry(&tk_core.seq, seq)); - - ts->tv_sec += tomono.tv_sec; - ts->tv_nsec = 0; - timespec64_add_ns(ts, nsec + tomono.tv_nsec); -} -EXPORT_SYMBOL_GPL(ktime_get_ts64); - -/** - * ktime_get_seconds - Get the seconds portion of CLOCK_MONOTONIC - * - * Returns the seconds portion of CLOCK_MONOTONIC with a single non - * serialized read. tk->ktime_sec is of type 'unsigned long' so this - * works on both 32 and 64 bit systems. On 32 bit systems the readout - * covers ~136 years of uptime which should be enough to prevent - * premature wrap arounds. - */ -time64_t ktime_get_seconds(void) -{ - struct timekeeper *tk = &tk_core.timekeeper; - - WARN_ON(timekeeping_suspended); - return tk->ktime_sec; -} -EXPORT_SYMBOL_GPL(ktime_get_seconds); - -/** - * ktime_get_real_seconds - Get the seconds portion of CLOCK_REALTIME - * - * Returns the wall clock seconds since 1970. This replaces the - * get_seconds() interface which is not y2038 safe on 32bit systems. - * - * For 64bit systems the fast access to tk->xtime_sec is preserved. On - * 32bit systems the access must be protected with the sequence - * counter to provide "atomic" access to the 64bit tk->xtime_sec - * value. - */ -time64_t ktime_get_real_seconds(void) -{ - struct timekeeper *tk = &tk_core.timekeeper; - time64_t seconds; - unsigned int seq; - - if (IS_ENABLED(CONFIG_64BIT)) - return tk->xtime_sec; - - do { - seq = read_seqcount_begin(&tk_core.seq); - seconds = tk->xtime_sec; - - } while (read_seqcount_retry(&tk_core.seq, seq)); - - return seconds; -} -EXPORT_SYMBOL_GPL(ktime_get_real_seconds); - -/** - * __ktime_get_real_seconds - The same as ktime_get_real_seconds - * but without the sequence counter protect. This internal function - * is called just when timekeeping lock is already held. - */ -time64_t __ktime_get_real_seconds(void) -{ - struct timekeeper *tk = &tk_core.timekeeper; - - return tk->xtime_sec; -} - -/** - * ktime_get_snapshot - snapshots the realtime/monotonic raw clocks with counter - * @systime_snapshot: pointer to struct receiving the system time snapshot - */ -void ktime_get_snapshot(struct system_time_snapshot *systime_snapshot) -{ - struct timekeeper *tk = &tk_core.timekeeper; - unsigned long seq; - ktime_t base_raw; - ktime_t base_real; - s64 nsec_raw; - s64 nsec_real; - cycle_t now; - - WARN_ON_ONCE(timekeeping_suspended); - - do { - seq = read_seqcount_begin(&tk_core.seq); - - now = tk->tkr_mono.read(tk->tkr_mono.clock); - systime_snapshot->cs_was_changed_seq = tk->cs_was_changed_seq; - systime_snapshot->clock_was_set_seq = tk->clock_was_set_seq; - base_real = ktime_add(tk->tkr_mono.base, - tk_core.timekeeper.offs_real); - base_raw = tk->tkr_raw.base; - nsec_real = timekeeping_cycles_to_ns(&tk->tkr_mono, now); - nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw, now); - } while (read_seqcount_retry(&tk_core.seq, seq)); - - systime_snapshot->cycles = now; - systime_snapshot->real = ktime_add_ns(base_real, nsec_real); - systime_snapshot->raw = ktime_add_ns(base_raw, nsec_raw); -} -EXPORT_SYMBOL_GPL(ktime_get_snapshot); - -/* Scale base by mult/div checking for overflow */ -static int scale64_check_overflow(u64 mult, u64 div, u64 *base) -{ - u64 tmp, rem; - - tmp = div64_u64_rem(*base, div, &rem); - - if (((int)sizeof(u64)*8 - fls64(mult) < fls64(tmp)) || - ((int)sizeof(u64)*8 - fls64(mult) < fls64(rem))) - return -EOVERFLOW; - tmp *= mult; - rem *= mult; - - do_div(rem, div); - *base = tmp + rem; - return 0; -} - -/** - * adjust_historical_crosststamp - adjust crosstimestamp previous to current interval - * @history: Snapshot representing start of history - * @partial_history_cycles: Cycle offset into history (fractional part) - * @total_history_cycles: Total history length in cycles - * @discontinuity: True indicates clock was set on history period - * @ts: Cross timestamp that should be adjusted using - * partial/total ratio - * - * Helper function used by get_device_system_crosststamp() to correct the - * crosstimestamp corresponding to the start of the current interval to the - * system counter value (timestamp point) provided by the driver. The - * total_history_* quantities are the total history starting at the provided - * reference point and ending at the start of the current interval. The cycle - * count between the driver timestamp point and the start of the current - * interval is partial_history_cycles. - */ -static int adjust_historical_crosststamp(struct system_time_snapshot *history, - cycle_t partial_history_cycles, - cycle_t total_history_cycles, - bool discontinuity, - struct system_device_crosststamp *ts) -{ - struct timekeeper *tk = &tk_core.timekeeper; - u64 corr_raw, corr_real; - bool interp_forward; - int ret; - - if (total_history_cycles == 0 || partial_history_cycles == 0) - return 0; - - /* Interpolate shortest distance from beginning or end of history */ - interp_forward = partial_history_cycles > total_history_cycles/2 ? - true : false; - partial_history_cycles = interp_forward ? - total_history_cycles - partial_history_cycles : - partial_history_cycles; - - /* - * Scale the monotonic raw time delta by: - * partial_history_cycles / total_history_cycles - */ - corr_raw = (u64)ktime_to_ns( - ktime_sub(ts->sys_monoraw, history->raw)); - ret = scale64_check_overflow(partial_history_cycles, - total_history_cycles, &corr_raw); - if (ret) - return ret; - - /* - * If there is a discontinuity in the history, scale monotonic raw - * correction by: - * mult(real)/mult(raw) yielding the realtime correction - * Otherwise, calculate the realtime correction similar to monotonic - * raw calculation - */ - if (discontinuity) { - corr_real = mul_u64_u32_div - (corr_raw, tk->tkr_mono.mult, tk->tkr_raw.mult); - } else { - corr_real = (u64)ktime_to_ns( - ktime_sub(ts->sys_realtime, history->real)); - ret = scale64_check_overflow(partial_history_cycles, - total_history_cycles, &corr_real); - if (ret) - return ret; - } - - /* Fixup monotonic raw and real time time values */ - if (interp_forward) { - ts->sys_monoraw = ktime_add_ns(history->raw, corr_raw); - ts->sys_realtime = ktime_add_ns(history->real, corr_real); - } else { - ts->sys_monoraw = ktime_sub_ns(ts->sys_monoraw, corr_raw); - ts->sys_realtime = ktime_sub_ns(ts->sys_realtime, corr_real); - } - - return 0; -} - -/* - * cycle_between - true if test occurs chronologically between before and after - */ -static bool cycle_between(cycle_t before, cycle_t test, cycle_t after) -{ - if (test > before && test < after) - return true; - if (test < before && before > after) - return true; - return false; -} - -/** - * get_device_system_crosststamp - Synchronously capture system/device timestamp - * @get_time_fn: Callback to get simultaneous device time and - * system counter from the device driver - * @ctx: Context passed to get_time_fn() - * @history_begin: Historical reference point used to interpolate system - * time when counter provided by the driver is before the current interval - * @xtstamp: Receives simultaneously captured system and device time - * - * Reads a timestamp from a device and correlates it to system time - */ -int get_device_system_crosststamp(int (*get_time_fn) - (ktime_t *device_time, - struct system_counterval_t *sys_counterval, - void *ctx), - void *ctx, - struct system_time_snapshot *history_begin, - struct system_device_crosststamp *xtstamp) -{ - struct system_counterval_t system_counterval; - struct timekeeper *tk = &tk_core.timekeeper; - cycle_t cycles, now, interval_start; - unsigned int clock_was_set_seq = 0; - ktime_t base_real, base_raw; - s64 nsec_real, nsec_raw; - u8 cs_was_changed_seq; - unsigned long seq; - bool do_interp; - int ret; - - do { - seq = read_seqcount_begin(&tk_core.seq); - /* - * Try to synchronously capture device time and a system - * counter value calling back into the device driver - */ - ret = get_time_fn(&xtstamp->device, &system_counterval, ctx); - if (ret) - return ret; - - /* - * Verify that the clocksource associated with the captured - * system counter value is the same as the currently installed - * timekeeper clocksource - */ - if (tk->tkr_mono.clock != system_counterval.cs) - return -ENODEV; - cycles = system_counterval.cycles; - - /* - * Check whether the system counter value provided by the - * device driver is on the current timekeeping interval. - */ - now = tk->tkr_mono.read(tk->tkr_mono.clock); - interval_start = tk->tkr_mono.cycle_last; - if (!cycle_between(interval_start, cycles, now)) { - clock_was_set_seq = tk->clock_was_set_seq; - cs_was_changed_seq = tk->cs_was_changed_seq; - cycles = interval_start; - do_interp = true; - } else { - do_interp = false; - } - - base_real = ktime_add(tk->tkr_mono.base, - tk_core.timekeeper.offs_real); - base_raw = tk->tkr_raw.base; - - nsec_real = timekeeping_cycles_to_ns(&tk->tkr_mono, - system_counterval.cycles); - nsec_raw = timekeeping_cycles_to_ns(&tk->tkr_raw, - system_counterval.cycles); - } while (read_seqcount_retry(&tk_core.seq, seq)); - - xtstamp->sys_realtime = ktime_add_ns(base_real, nsec_real); - xtstamp->sys_monoraw = ktime_add_ns(base_raw, nsec_raw); - - /* - * Interpolate if necessary, adjusting back from the start of the - * current interval - */ - if (do_interp) { - cycle_t partial_history_cycles, total_history_cycles; - bool discontinuity; - - /* - * Check that the counter value occurs after the provided - * history reference and that the history doesn't cross a - * clocksource change - */ - if (!history_begin || - !cycle_between(history_begin->cycles, - system_counterval.cycles, cycles) || - history_begin->cs_was_changed_seq != cs_was_changed_seq) - return -EINVAL; - partial_history_cycles = cycles - system_counterval.cycles; - total_history_cycles = cycles - history_begin->cycles; - discontinuity = - history_begin->clock_was_set_seq != clock_was_set_seq; - - ret = adjust_historical_crosststamp(history_begin, - partial_history_cycles, - total_history_cycles, - discontinuity, xtstamp); - if (ret) - return ret; - } - - return 0; -} -EXPORT_SYMBOL_GPL(get_device_system_crosststamp); - -/** - * do_gettimeofday - Returns the time of day in a timeval - * @tv: pointer to the timeval to be set - * - * NOTE: Users should be converted to using getnstimeofday() - */ -void do_gettimeofday(struct timeval *tv) -{ - struct timespec64 now; - - getnstimeofday64(&now); - tv->tv_sec = now.tv_sec; - tv->tv_usec = now.tv_nsec/1000; -} -EXPORT_SYMBOL(do_gettimeofday); - -/** - * do_settimeofday64 - Sets the time of day. - * @ts: pointer to the timespec64 variable containing the new time - * - * Sets the time of day to the new time and update NTP and notify hrtimers - */ -int do_settimeofday64(const struct timespec64 *ts) -{ - struct timekeeper *tk = &tk_core.timekeeper; - struct timespec64 ts_delta, xt; - unsigned long flags; - int ret = 0; - - if (!timespec64_valid_strict(ts)) - return -EINVAL; - - raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&tk_core.seq); - - timekeeping_forward_now(tk); - - xt = tk_xtime(tk); - ts_delta.tv_sec = ts->tv_sec - xt.tv_sec; - ts_delta.tv_nsec = ts->tv_nsec - xt.tv_nsec; - - if (timespec64_compare(&tk->wall_to_monotonic, &ts_delta) > 0) { - ret = -EINVAL; - goto out; - } - - tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, ts_delta)); - - tk_set_xtime(tk, ts); -out: - timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); - - write_seqcount_end(&tk_core.seq); - raw_spin_unlock_irqrestore(&timekeeper_lock, flags); - - /* signal hrtimers about time change */ - clock_was_set(); - - return ret; -} -EXPORT_SYMBOL(do_settimeofday64); - -/** - * timekeeping_inject_offset - Adds or subtracts from the current time. - * @tv: pointer to the timespec variable containing the offset - * - * Adds or subtracts an offset value from the current time. - */ -int timekeeping_inject_offset(struct timespec *ts) -{ - struct timekeeper *tk = &tk_core.timekeeper; - unsigned long flags; - struct timespec64 ts64, tmp; - int ret = 0; - - if (!timespec_inject_offset_valid(ts)) - return -EINVAL; - - ts64 = timespec_to_timespec64(*ts); - - raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&tk_core.seq); - - timekeeping_forward_now(tk); - - /* Make sure the proposed value is valid */ - tmp = timespec64_add(tk_xtime(tk), ts64); - if (timespec64_compare(&tk->wall_to_monotonic, &ts64) > 0 || - !timespec64_valid_strict(&tmp)) { - ret = -EINVAL; - goto error; - } - - tk_xtime_add(tk, &ts64); - tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, ts64)); - -error: /* even if we error out, we forwarded the time, so call update */ - timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); - - write_seqcount_end(&tk_core.seq); - raw_spin_unlock_irqrestore(&timekeeper_lock, flags); - - /* signal hrtimers about time change */ - clock_was_set(); - - return ret; -} -EXPORT_SYMBOL(timekeeping_inject_offset); - - -/** - * timekeeping_get_tai_offset - Returns current TAI offset from UTC - * - */ -s32 timekeeping_get_tai_offset(void) -{ - struct timekeeper *tk = &tk_core.timekeeper; - unsigned int seq; - s32 ret; - - do { - seq = read_seqcount_begin(&tk_core.seq); - ret = tk->tai_offset; - } while (read_seqcount_retry(&tk_core.seq, seq)); - - return ret; -} - -/** - * __timekeeping_set_tai_offset - Lock free worker function - * - */ -static void __timekeeping_set_tai_offset(struct timekeeper *tk, s32 tai_offset) -{ - tk->tai_offset = tai_offset; - tk->offs_tai = ktime_add(tk->offs_real, ktime_set(tai_offset, 0)); -} - -/** - * timekeeping_set_tai_offset - Sets the current TAI offset from UTC - * - */ -void timekeeping_set_tai_offset(s32 tai_offset) -{ - struct timekeeper *tk = &tk_core.timekeeper; - unsigned long flags; - - raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&tk_core.seq); - __timekeeping_set_tai_offset(tk, tai_offset); - timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); - write_seqcount_end(&tk_core.seq); - raw_spin_unlock_irqrestore(&timekeeper_lock, flags); - clock_was_set(); -} - -/** - * change_clocksource - Swaps clocksources if a new one is available - * - * Accumulates current time interval and initializes new clocksource - */ -static int change_clocksource(void *data) -{ - struct timekeeper *tk = &tk_core.timekeeper; - struct clocksource *new, *old; - unsigned long flags; - - new = (struct clocksource *) data; - - raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&tk_core.seq); - - timekeeping_forward_now(tk); - /* - * If the cs is in module, get a module reference. Succeeds - * for built-in code (owner == NULL) as well. - */ - if (try_module_get(new->owner)) { - if (!new->enable || new->enable(new) == 0) { - old = tk->tkr_mono.clock; - tk_setup_internals(tk, new); - if (old->disable) - old->disable(old); - module_put(old->owner); - } else { - module_put(new->owner); - } - } - timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); - - write_seqcount_end(&tk_core.seq); - raw_spin_unlock_irqrestore(&timekeeper_lock, flags); - - return 0; -} - -/** - * timekeeping_notify - Install a new clock source - * @clock: pointer to the clock source - * - * This function is called from clocksource.c after a new, better clock - * source has been registered. The caller holds the clocksource_mutex. - */ -int timekeeping_notify(struct clocksource *clock) -{ - struct timekeeper *tk = &tk_core.timekeeper; - - if (tk->tkr_mono.clock == clock) - return 0; - stop_machine(change_clocksource, clock, NULL); - tick_clock_notify(); - return tk->tkr_mono.clock == clock ? 0 : -1; -} - -/** - * getrawmonotonic64 - Returns the raw monotonic time in a timespec - * @ts: pointer to the timespec64 to be set - * - * Returns the raw monotonic time (completely un-modified by ntp) - */ -void getrawmonotonic64(struct timespec64 *ts) -{ - struct timekeeper *tk = &tk_core.timekeeper; - struct timespec64 ts64; - unsigned long seq; - s64 nsecs; - - do { - seq = read_seqcount_begin(&tk_core.seq); - nsecs = timekeeping_get_ns(&tk->tkr_raw); - ts64 = tk->raw_time; - - } while (read_seqcount_retry(&tk_core.seq, seq)); - - timespec64_add_ns(&ts64, nsecs); - *ts = ts64; -} -EXPORT_SYMBOL(getrawmonotonic64); - - -/** - * timekeeping_valid_for_hres - Check if timekeeping is suitable for hres - */ -int timekeeping_valid_for_hres(void) -{ - struct timekeeper *tk = &tk_core.timekeeper; - unsigned long seq; - int ret; - - do { - seq = read_seqcount_begin(&tk_core.seq); - - ret = tk->tkr_mono.clock->flags & CLOCK_SOURCE_VALID_FOR_HRES; - - } while (read_seqcount_retry(&tk_core.seq, seq)); - - return ret; -} - -/** - * timekeeping_max_deferment - Returns max time the clocksource can be deferred - */ -u64 timekeeping_max_deferment(void) -{ - struct timekeeper *tk = &tk_core.timekeeper; - unsigned long seq; - u64 ret; - - do { - seq = read_seqcount_begin(&tk_core.seq); - - ret = tk->tkr_mono.clock->max_idle_ns; - - } while (read_seqcount_retry(&tk_core.seq, seq)); - - return ret; -} - -/** - * read_persistent_clock - Return time from the persistent clock. - * - * Weak dummy function for arches that do not yet support it. - * Reads the time from the battery backed persistent clock. - * Returns a timespec with tv_sec=0 and tv_nsec=0 if unsupported. - * - * XXX - Do be sure to remove it once all arches implement it. - */ -void __weak read_persistent_clock(struct timespec *ts) -{ - ts->tv_sec = 0; - ts->tv_nsec = 0; -} - -void __weak read_persistent_clock64(struct timespec64 *ts64) -{ - struct timespec ts; - - read_persistent_clock(&ts); - *ts64 = timespec_to_timespec64(ts); -} - -/** - * read_boot_clock64 - Return time of the system start. - * - * Weak dummy function for arches that do not yet support it. - * Function to read the exact time the system has been started. - * Returns a timespec64 with tv_sec=0 and tv_nsec=0 if unsupported. - * - * XXX - Do be sure to remove it once all arches implement it. - */ -void __weak read_boot_clock64(struct timespec64 *ts) -{ - ts->tv_sec = 0; - ts->tv_nsec = 0; -} - -/* Flag for if timekeeping_resume() has injected sleeptime */ -static bool sleeptime_injected; - -/* Flag for if there is a persistent clock on this platform */ -static bool persistent_clock_exists; - -/* - * timekeeping_init - Initializes the clocksource and common timekeeping values - */ -void __init timekeeping_init(void) -{ - struct timekeeper *tk = &tk_core.timekeeper; - struct clocksource *clock; - unsigned long flags; - struct timespec64 now, boot, tmp; - - read_persistent_clock64(&now); - if (!timespec64_valid_strict(&now)) { - pr_warn("WARNING: Persistent clock returned invalid value!\n" - " Check your CMOS/BIOS settings.\n"); - now.tv_sec = 0; - now.tv_nsec = 0; - } else if (now.tv_sec || now.tv_nsec) - persistent_clock_exists = true; - - read_boot_clock64(&boot); - if (!timespec64_valid_strict(&boot)) { - pr_warn("WARNING: Boot clock returned invalid value!\n" - " Check your CMOS/BIOS settings.\n"); - boot.tv_sec = 0; - boot.tv_nsec = 0; - } - - raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&tk_core.seq); - ntp_init(); - - clock = clocksource_default_clock(); - if (clock->enable) - clock->enable(clock); - tk_setup_internals(tk, clock); - - tk_set_xtime(tk, &now); - tk->raw_time.tv_sec = 0; - tk->raw_time.tv_nsec = 0; - if (boot.tv_sec == 0 && boot.tv_nsec == 0) - boot = tk_xtime(tk); - - set_normalized_timespec64(&tmp, -boot.tv_sec, -boot.tv_nsec); - tk_set_wall_to_mono(tk, tmp); - - timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); - - write_seqcount_end(&tk_core.seq); - raw_spin_unlock_irqrestore(&timekeeper_lock, flags); -} - -/* time in seconds when suspend began for persistent clock */ -static struct timespec64 timekeeping_suspend_time; - -/** - * __timekeeping_inject_sleeptime - Internal function to add sleep interval - * @delta: pointer to a timespec delta value - * - * Takes a timespec offset measuring a suspend interval and properly - * adds the sleep offset to the timekeeping variables. - */ -static void __timekeeping_inject_sleeptime(struct timekeeper *tk, - struct timespec64 *delta) -{ - if (!timespec64_valid_strict(delta)) { - printk_deferred(KERN_WARNING - "__timekeeping_inject_sleeptime: Invalid " - "sleep delta value!\n"); - return; - } - tk_xtime_add(tk, delta); - tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, *delta)); - tk_update_sleep_time(tk, timespec64_to_ktime(*delta)); - tk_debug_account_sleep_time(delta); -} - -#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_RTC_HCTOSYS_DEVICE) -/** - * We have three kinds of time sources to use for sleep time - * injection, the preference order is: - * 1) non-stop clocksource - * 2) persistent clock (ie: RTC accessible when irqs are off) - * 3) RTC - * - * 1) and 2) are used by timekeeping, 3) by RTC subsystem. - * If system has neither 1) nor 2), 3) will be used finally. - * - * - * If timekeeping has injected sleeptime via either 1) or 2), - * 3) becomes needless, so in this case we don't need to call - * rtc_resume(), and this is what timekeeping_rtc_skipresume() - * means. - */ -bool timekeeping_rtc_skipresume(void) -{ - return sleeptime_injected; -} - -/** - * 1) can be determined whether to use or not only when doing - * timekeeping_resume() which is invoked after rtc_suspend(), - * so we can't skip rtc_suspend() surely if system has 1). - * - * But if system has 2), 2) will definitely be used, so in this - * case we don't need to call rtc_suspend(), and this is what - * timekeeping_rtc_skipsuspend() means. - */ -bool timekeeping_rtc_skipsuspend(void) -{ - return persistent_clock_exists; -} - -/** - * timekeeping_inject_sleeptime64 - Adds suspend interval to timeekeeping values - * @delta: pointer to a timespec64 delta value - * - * This hook is for architectures that cannot support read_persistent_clock64 - * because their RTC/persistent clock is only accessible when irqs are enabled. - * and also don't have an effective nonstop clocksource. - * - * This function should only be called by rtc_resume(), and allows - * a suspend offset to be injected into the timekeeping values. - */ -void timekeeping_inject_sleeptime64(struct timespec64 *delta) -{ - struct timekeeper *tk = &tk_core.timekeeper; - unsigned long flags; - - raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&tk_core.seq); - - timekeeping_forward_now(tk); - - __timekeeping_inject_sleeptime(tk, delta); - - timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); - - write_seqcount_end(&tk_core.seq); - raw_spin_unlock_irqrestore(&timekeeper_lock, flags); - - /* signal hrtimers about time change */ - clock_was_set(); -} -#endif - -/** - * timekeeping_resume - Resumes the generic timekeeping subsystem. - */ -void timekeeping_resume(void) -{ - struct timekeeper *tk = &tk_core.timekeeper; - struct clocksource *clock = tk->tkr_mono.clock; - unsigned long flags; - struct timespec64 ts_new, ts_delta; - cycle_t cycle_now, cycle_delta; - - sleeptime_injected = false; - read_persistent_clock64(&ts_new); - - clockevents_resume(); - clocksource_resume(); - - raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&tk_core.seq); - - /* - * After system resumes, we need to calculate the suspended time and - * compensate it for the OS time. There are 3 sources that could be - * used: Nonstop clocksource during suspend, persistent clock and rtc - * device. - * - * One specific platform may have 1 or 2 or all of them, and the - * preference will be: - * suspend-nonstop clocksource -> persistent clock -> rtc - * The less preferred source will only be tried if there is no better - * usable source. The rtc part is handled separately in rtc core code. - */ - cycle_now = tk->tkr_mono.read(clock); - if ((clock->flags & CLOCK_SOURCE_SUSPEND_NONSTOP) && - cycle_now > tk->tkr_mono.cycle_last) { - u64 num, max = ULLONG_MAX; - u32 mult = clock->mult; - u32 shift = clock->shift; - s64 nsec = 0; - - cycle_delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last, - tk->tkr_mono.mask); - - /* - * "cycle_delta * mutl" may cause 64 bits overflow, if the - * suspended time is too long. In that case we need do the - * 64 bits math carefully - */ - do_div(max, mult); - if (cycle_delta > max) { - num = div64_u64(cycle_delta, max); - nsec = (((u64) max * mult) >> shift) * num; - cycle_delta -= num * max; - } - nsec += ((u64) cycle_delta * mult) >> shift; - - ts_delta = ns_to_timespec64(nsec); - sleeptime_injected = true; - } else if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) { - ts_delta = timespec64_sub(ts_new, timekeeping_suspend_time); - sleeptime_injected = true; - } - - if (sleeptime_injected) - __timekeeping_inject_sleeptime(tk, &ts_delta); - - /* Re-base the last cycle value */ - tk->tkr_mono.cycle_last = cycle_now; - tk->tkr_raw.cycle_last = cycle_now; - - tk->ntp_error = 0; - timekeeping_suspended = 0; - timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); - write_seqcount_end(&tk_core.seq); - raw_spin_unlock_irqrestore(&timekeeper_lock, flags); - - touch_softlockup_watchdog(); - - tick_resume(); - hrtimers_resume(); -} - -int timekeeping_suspend(void) -{ - struct timekeeper *tk = &tk_core.timekeeper; - unsigned long flags; - struct timespec64 delta, delta_delta; - static struct timespec64 old_delta; - - read_persistent_clock64(&timekeeping_suspend_time); - - /* - * On some systems the persistent_clock can not be detected at - * timekeeping_init by its return value, so if we see a valid - * value returned, update the persistent_clock_exists flag. - */ - if (timekeeping_suspend_time.tv_sec || timekeeping_suspend_time.tv_nsec) - persistent_clock_exists = true; - - raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&tk_core.seq); - timekeeping_forward_now(tk); - timekeeping_suspended = 1; - - if (persistent_clock_exists) { - /* - * To avoid drift caused by repeated suspend/resumes, - * which each can add ~1 second drift error, - * try to compensate so the difference in system time - * and persistent_clock time stays close to constant. - */ - delta = timespec64_sub(tk_xtime(tk), timekeeping_suspend_time); - delta_delta = timespec64_sub(delta, old_delta); - if (abs(delta_delta.tv_sec) >= 2) { - /* - * if delta_delta is too large, assume time correction - * has occurred and set old_delta to the current delta. - */ - old_delta = delta; - } else { - /* Otherwise try to adjust old_system to compensate */ - timekeeping_suspend_time = - timespec64_add(timekeeping_suspend_time, delta_delta); - } - } - - timekeeping_update(tk, TK_MIRROR); - halt_fast_timekeeper(tk); - write_seqcount_end(&tk_core.seq); - raw_spin_unlock_irqrestore(&timekeeper_lock, flags); - - tick_suspend(); - clocksource_suspend(); - clockevents_suspend(); - - return 0; -} - -/* sysfs resume/suspend bits for timekeeping */ -static struct syscore_ops timekeeping_syscore_ops = { - .resume = timekeeping_resume, - .suspend = timekeeping_suspend, -}; - -static int __init timekeeping_init_ops(void) -{ - register_syscore_ops(&timekeeping_syscore_ops); - return 0; -} -device_initcall(timekeeping_init_ops); - -/* - * Apply a multiplier adjustment to the timekeeper - */ -static __always_inline void timekeeping_apply_adjustment(struct timekeeper *tk, - s64 offset, - bool negative, - int adj_scale) -{ - s64 interval = tk->cycle_interval; - s32 mult_adj = 1; - - if (negative) { - mult_adj = -mult_adj; - interval = -interval; - offset = -offset; - } - mult_adj <<= adj_scale; - interval <<= adj_scale; - offset <<= adj_scale; - - /* - * So the following can be confusing. - * - * To keep things simple, lets assume mult_adj == 1 for now. - * - * When mult_adj != 1, remember that the interval and offset values - * have been appropriately scaled so the math is the same. - * - * The basic idea here is that we're increasing the multiplier - * by one, this causes the xtime_interval to be incremented by - * one cycle_interval. This is because: - * xtime_interval = cycle_interval * mult - * So if mult is being incremented by one: - * xtime_interval = cycle_interval * (mult + 1) - * Its the same as: - * xtime_interval = (cycle_interval * mult) + cycle_interval - * Which can be shortened to: - * xtime_interval += cycle_interval - * - * So offset stores the non-accumulated cycles. Thus the current - * time (in shifted nanoseconds) is: - * now = (offset * adj) + xtime_nsec - * Now, even though we're adjusting the clock frequency, we have - * to keep time consistent. In other words, we can't jump back - * in time, and we also want to avoid jumping forward in time. - * - * So given the same offset value, we need the time to be the same - * both before and after the freq adjustment. - * now = (offset * adj_1) + xtime_nsec_1 - * now = (offset * adj_2) + xtime_nsec_2 - * So: - * (offset * adj_1) + xtime_nsec_1 = - * (offset * adj_2) + xtime_nsec_2 - * And we know: - * adj_2 = adj_1 + 1 - * So: - * (offset * adj_1) + xtime_nsec_1 = - * (offset * (adj_1+1)) + xtime_nsec_2 - * (offset * adj_1) + xtime_nsec_1 = - * (offset * adj_1) + offset + xtime_nsec_2 - * Canceling the sides: - * xtime_nsec_1 = offset + xtime_nsec_2 - * Which gives us: - * xtime_nsec_2 = xtime_nsec_1 - offset - * Which simplfies to: - * xtime_nsec -= offset - * - * XXX - TODO: Doc ntp_error calculation. - */ - if ((mult_adj > 0) && (tk->tkr_mono.mult + mult_adj < mult_adj)) { - /* NTP adjustment caused clocksource mult overflow */ - WARN_ON_ONCE(1); - return; - } - - tk->tkr_mono.mult += mult_adj; - tk->xtime_interval += interval; - tk->tkr_mono.xtime_nsec -= offset; - tk->ntp_error -= (interval - offset) << tk->ntp_error_shift; -} - -/* - * Calculate the multiplier adjustment needed to match the frequency - * specified by NTP - */ -static __always_inline void timekeeping_freqadjust(struct timekeeper *tk, - s64 offset) -{ - s64 interval = tk->cycle_interval; - s64 xinterval = tk->xtime_interval; - u32 base = tk->tkr_mono.clock->mult; - u32 max = tk->tkr_mono.clock->maxadj; - u32 cur_adj = tk->tkr_mono.mult; - s64 tick_error; - bool negative; - u32 adj_scale; - - /* Remove any current error adj from freq calculation */ - if (tk->ntp_err_mult) - xinterval -= tk->cycle_interval; - - tk->ntp_tick = ntp_tick_length(); - - /* Calculate current error per tick */ - tick_error = ntp_tick_length() >> tk->ntp_error_shift; - tick_error -= (xinterval + tk->xtime_remainder); - - /* Don't worry about correcting it if its small */ - if (likely((tick_error >= 0) && (tick_error <= interval))) - return; - - /* preserve the direction of correction */ - negative = (tick_error < 0); - - /* If any adjustment would pass the max, just return */ - if (negative && (cur_adj - 1) <= (base - max)) - return; - if (!negative && (cur_adj + 1) >= (base + max)) - return; - /* - * Sort out the magnitude of the correction, but - * avoid making so large a correction that we go - * over the max adjustment. - */ - adj_scale = 0; - tick_error = abs(tick_error); - while (tick_error > interval) { - u32 adj = 1 << (adj_scale + 1); - - /* Check if adjustment gets us within 1 unit from the max */ - if (negative && (cur_adj - adj) <= (base - max)) - break; - if (!negative && (cur_adj + adj) >= (base + max)) - break; - - adj_scale++; - tick_error >>= 1; - } - - /* scale the corrections */ - timekeeping_apply_adjustment(tk, offset, negative, adj_scale); -} - -/* - * Adjust the timekeeper's multiplier to the correct frequency - * and also to reduce the accumulated error value. - */ -static void timekeeping_adjust(struct timekeeper *tk, s64 offset) -{ - /* Correct for the current frequency error */ - timekeeping_freqadjust(tk, offset); - - /* Next make a small adjustment to fix any cumulative error */ - if (!tk->ntp_err_mult && (tk->ntp_error > 0)) { - tk->ntp_err_mult = 1; - timekeeping_apply_adjustment(tk, offset, 0, 0); - } else if (tk->ntp_err_mult && (tk->ntp_error <= 0)) { - /* Undo any existing error adjustment */ - timekeeping_apply_adjustment(tk, offset, 1, 0); - tk->ntp_err_mult = 0; - } - - if (unlikely(tk->tkr_mono.clock->maxadj && - (abs(tk->tkr_mono.mult - tk->tkr_mono.clock->mult) - > tk->tkr_mono.clock->maxadj))) { - printk_once(KERN_WARNING - "Adjusting %s more than 11%% (%ld vs %ld)\n", - tk->tkr_mono.clock->name, (long)tk->tkr_mono.mult, - (long)tk->tkr_mono.clock->mult + tk->tkr_mono.clock->maxadj); - } - - /* - * It may be possible that when we entered this function, xtime_nsec - * was very small. Further, if we're slightly speeding the clocksource - * in the code above, its possible the required corrective factor to - * xtime_nsec could cause it to underflow. - * - * Now, since we already accumulated the second, cannot simply roll - * the accumulated second back, since the NTP subsystem has been - * notified via second_overflow. So instead we push xtime_nsec forward - * by the amount we underflowed, and add that amount into the error. - * - * We'll correct this error next time through this function, when - * xtime_nsec is not as small. - */ - if (unlikely((s64)tk->tkr_mono.xtime_nsec < 0)) { - s64 neg = -(s64)tk->tkr_mono.xtime_nsec; - tk->tkr_mono.xtime_nsec = 0; - tk->ntp_error += neg << tk->ntp_error_shift; - } -} - -/** - * accumulate_nsecs_to_secs - Accumulates nsecs into secs - * - * Helper function that accumulates the nsecs greater than a second - * from the xtime_nsec field to the xtime_secs field. - * It also calls into the NTP code to handle leapsecond processing. - * - */ -static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk) -{ - u64 nsecps = (u64)NSEC_PER_SEC << tk->tkr_mono.shift; - unsigned int clock_set = 0; - - while (tk->tkr_mono.xtime_nsec >= nsecps) { - int leap; - - tk->tkr_mono.xtime_nsec -= nsecps; - tk->xtime_sec++; - - /* Figure out if its a leap sec and apply if needed */ - leap = second_overflow(tk->xtime_sec); - if (unlikely(leap)) { - struct timespec64 ts; - - tk->xtime_sec += leap; - - ts.tv_sec = leap; - ts.tv_nsec = 0; - tk_set_wall_to_mono(tk, - timespec64_sub(tk->wall_to_monotonic, ts)); - - __timekeeping_set_tai_offset(tk, tk->tai_offset - leap); - - clock_set = TK_CLOCK_WAS_SET; - } - } - return clock_set; -} - -/** - * logarithmic_accumulation - shifted accumulation of cycles - * - * This functions accumulates a shifted interval of cycles into - * into a shifted interval nanoseconds. Allows for O(log) accumulation - * loop. - * - * Returns the unconsumed cycles. - */ -static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset, - u32 shift, - unsigned int *clock_set) -{ - cycle_t interval = tk->cycle_interval << shift; - u64 raw_nsecs; - - /* If the offset is smaller than a shifted interval, do nothing */ - if (offset < interval) - return offset; - - /* Accumulate one shifted interval */ - offset -= interval; - tk->tkr_mono.cycle_last += interval; - tk->tkr_raw.cycle_last += interval; - - tk->tkr_mono.xtime_nsec += tk->xtime_interval << shift; - *clock_set |= accumulate_nsecs_to_secs(tk); - - /* Accumulate raw time */ - raw_nsecs = (u64)tk->raw_interval << shift; - raw_nsecs += tk->raw_time.tv_nsec; - if (raw_nsecs >= NSEC_PER_SEC) { - u64 raw_secs = raw_nsecs; - raw_nsecs = do_div(raw_secs, NSEC_PER_SEC); - tk->raw_time.tv_sec += raw_secs; - } - tk->raw_time.tv_nsec = raw_nsecs; - - /* Accumulate error between NTP and clock interval */ - tk->ntp_error += tk->ntp_tick << shift; - tk->ntp_error -= (tk->xtime_interval + tk->xtime_remainder) << - (tk->ntp_error_shift + shift); - - return offset; -} - -/** - * update_wall_time - Uses the current clocksource to increment the wall time - * - */ -void update_wall_time(void) -{ - struct timekeeper *real_tk = &tk_core.timekeeper; - struct timekeeper *tk = &shadow_timekeeper; - cycle_t offset; - int shift = 0, maxshift; - unsigned int clock_set = 0; - unsigned long flags; - - raw_spin_lock_irqsave(&timekeeper_lock, flags); - - /* Make sure we're fully resumed: */ - if (unlikely(timekeeping_suspended)) - goto out; - -#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET - offset = real_tk->cycle_interval; -#else - offset = clocksource_delta(tk->tkr_mono.read(tk->tkr_mono.clock), - tk->tkr_mono.cycle_last, tk->tkr_mono.mask); -#endif - - /* Check if there's really nothing to do */ - if (offset < real_tk->cycle_interval) - goto out; - - /* Do some additional sanity checking */ - timekeeping_check_update(real_tk, offset); - - /* - * With NO_HZ we may have to accumulate many cycle_intervals - * (think "ticks") worth of time at once. To do this efficiently, - * we calculate the largest doubling multiple of cycle_intervals - * that is smaller than the offset. We then accumulate that - * chunk in one go, and then try to consume the next smaller - * doubled multiple. - */ - shift = ilog2(offset) - ilog2(tk->cycle_interval); - shift = max(0, shift); - /* Bound shift to one less than what overflows tick_length */ - maxshift = (64 - (ilog2(ntp_tick_length())+1)) - 1; - shift = min(shift, maxshift); - while (offset >= tk->cycle_interval) { - offset = logarithmic_accumulation(tk, offset, shift, - &clock_set); - if (offset < tk->cycle_interval<offs_real, tk->offs_boot); - - *ts = ktime_to_timespec64(t); -} -EXPORT_SYMBOL_GPL(getboottime64); - -unsigned long get_seconds(void) -{ - struct timekeeper *tk = &tk_core.timekeeper; - - return tk->xtime_sec; -} -EXPORT_SYMBOL(get_seconds); - -struct timespec __current_kernel_time(void) -{ - struct timekeeper *tk = &tk_core.timekeeper; - - return timespec64_to_timespec(tk_xtime(tk)); -} - -struct timespec64 current_kernel_time64(void) -{ - struct timekeeper *tk = &tk_core.timekeeper; - struct timespec64 now; - unsigned long seq; - - do { - seq = read_seqcount_begin(&tk_core.seq); - - now = tk_xtime(tk); - } while (read_seqcount_retry(&tk_core.seq, seq)); - - return now; -} -EXPORT_SYMBOL(current_kernel_time64); - -struct timespec64 get_monotonic_coarse64(void) -{ - struct timekeeper *tk = &tk_core.timekeeper; - struct timespec64 now, mono; - unsigned long seq; - - do { - seq = read_seqcount_begin(&tk_core.seq); - - now = tk_xtime(tk); - mono = tk->wall_to_monotonic; - } while (read_seqcount_retry(&tk_core.seq, seq)); - - set_normalized_timespec64(&now, now.tv_sec + mono.tv_sec, - now.tv_nsec + mono.tv_nsec); - - return now; -} -EXPORT_SYMBOL(get_monotonic_coarse64); - -/* - * Must hold jiffies_lock - */ -void do_timer(unsigned long ticks) -{ - jiffies_64 += ticks; - calc_global_load(ticks); -} - -/** - * ktime_get_update_offsets_now - hrtimer helper - * @cwsseq: pointer to check and store the clock was set sequence number - * @offs_real: pointer to storage for monotonic -> realtime offset - * @offs_boot: pointer to storage for monotonic -> boottime offset - * @offs_tai: pointer to storage for monotonic -> clock tai offset - * - * Returns current monotonic time and updates the offsets if the - * sequence number in @cwsseq and timekeeper.clock_was_set_seq are - * different. - * - * Called from hrtimer_interrupt() or retrigger_next_event() - */ -ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq, ktime_t *offs_real, - ktime_t *offs_boot, ktime_t *offs_tai) -{ - struct timekeeper *tk = &tk_core.timekeeper; - unsigned int seq; - ktime_t base; - u64 nsecs; - - do { - seq = read_seqcount_begin(&tk_core.seq); - - base = tk->tkr_mono.base; - nsecs = timekeeping_get_ns(&tk->tkr_mono); - base = ktime_add_ns(base, nsecs); - - if (*cwsseq != tk->clock_was_set_seq) { - *cwsseq = tk->clock_was_set_seq; - *offs_real = tk->offs_real; - *offs_boot = tk->offs_boot; - *offs_tai = tk->offs_tai; - } - - /* Handle leapsecond insertion adjustments */ - if (unlikely(base.tv64 >= tk->next_leap_ktime.tv64)) - *offs_real = ktime_sub(tk->offs_real, ktime_set(1, 0)); - - } while (read_seqcount_retry(&tk_core.seq, seq)); - - return base; -} - -/** - * do_adjtimex() - Accessor function to NTP __do_adjtimex function - */ -int do_adjtimex(struct timex *txc) -{ - struct timekeeper *tk = &tk_core.timekeeper; - unsigned long flags; - struct timespec64 ts; - s32 orig_tai, tai; - int ret; - - /* Validate the data before disabling interrupts */ - ret = ntp_validate_timex(txc); - if (ret) - return ret; - - if (txc->modes & ADJ_SETOFFSET) { - struct timespec delta; - delta.tv_sec = txc->time.tv_sec; - delta.tv_nsec = txc->time.tv_usec; - if (!(txc->modes & ADJ_NANO)) - delta.tv_nsec *= 1000; - ret = timekeeping_inject_offset(&delta); - if (ret) - return ret; - } - - getnstimeofday64(&ts); - - raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&tk_core.seq); - - orig_tai = tai = tk->tai_offset; - ret = __do_adjtimex(txc, &ts, &tai); - - if (tai != orig_tai) { - __timekeeping_set_tai_offset(tk, tai); - timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); - } - tk_update_leap_state(tk); - - write_seqcount_end(&tk_core.seq); - raw_spin_unlock_irqrestore(&timekeeper_lock, flags); - - if (tai != orig_tai) - clock_was_set(); - - ntp_notify_cmos_timer(); - - return ret; -} - -#ifdef CONFIG_NTP_PPS -/** - * hardpps() - Accessor function to NTP __hardpps function - */ -void hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_ts) -{ - unsigned long flags; - - raw_spin_lock_irqsave(&timekeeper_lock, flags); - write_seqcount_begin(&tk_core.seq); - - __hardpps(phase_ts, raw_ts); - - write_seqcount_end(&tk_core.seq); - raw_spin_unlock_irqrestore(&timekeeper_lock, flags); -} -EXPORT_SYMBOL(hardpps); -#endif - -/** - * xtime_update() - advances the timekeeping infrastructure - * @ticks: number of ticks, that have elapsed since the last call. - * - * Must be called with interrupts disabled. - */ -void xtime_update(unsigned long ticks) -{ - write_seqlock(&jiffies_lock); - do_timer(ticks); - write_sequnlock(&jiffies_lock); - update_wall_time(); -} diff --git a/src/linux/kernel/time/timekeeping.h b/src/linux/kernel/time/timekeeping.h deleted file mode 100644 index 704f595..0000000 --- a/src/linux/kernel/time/timekeeping.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef _KERNEL_TIME_TIMEKEEPING_H -#define _KERNEL_TIME_TIMEKEEPING_H -/* - * Internal interfaces for kernel/time/ - */ -extern ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq, - ktime_t *offs_real, - ktime_t *offs_boot, - ktime_t *offs_tai); - -extern int timekeeping_valid_for_hres(void); -extern u64 timekeeping_max_deferment(void); -extern int timekeeping_inject_offset(struct timespec *ts); -extern s32 timekeeping_get_tai_offset(void); -extern void timekeeping_set_tai_offset(s32 tai_offset); -extern int timekeeping_suspend(void); -extern void timekeeping_resume(void); - -extern void do_timer(unsigned long ticks); -extern void update_wall_time(void); - -extern seqlock_t jiffies_lock; - -#define CS_NAME_LEN 32 - -#endif diff --git a/src/linux/kernel/time/timekeeping_internal.h b/src/linux/kernel/time/timekeeping_internal.h deleted file mode 100644 index 5be7627..0000000 --- a/src/linux/kernel/time/timekeeping_internal.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _TIMEKEEPING_INTERNAL_H -#define _TIMEKEEPING_INTERNAL_H -/* - * timekeeping debug functions - */ -#include -#include - -#ifdef CONFIG_DEBUG_FS -extern void tk_debug_account_sleep_time(struct timespec64 *t); -#else -#define tk_debug_account_sleep_time(x) -#endif - -#ifdef CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE -static inline cycle_t clocksource_delta(cycle_t now, cycle_t last, cycle_t mask) -{ - cycle_t ret = (now - last) & mask; - - /* - * Prevent time going backwards by checking the MSB of mask in - * the result. If set, return 0. - */ - return ret & ~(mask >> 1) ? 0 : ret; -} -#else -static inline cycle_t clocksource_delta(cycle_t now, cycle_t last, cycle_t mask) -{ - return (now - last) & mask; -} -#endif - -extern time64_t __ktime_get_real_seconds(void); - -#endif /* _TIMEKEEPING_INTERNAL_H */ diff --git a/src/linux/kernel/time/timer.c b/src/linux/kernel/time/timer.c deleted file mode 100644 index c611c47..0000000 --- a/src/linux/kernel/time/timer.c +++ /dev/null @@ -1,1939 +0,0 @@ -/* - * linux/kernel/timer.c - * - * Kernel internal timers - * - * Copyright (C) 1991, 1992 Linus Torvalds - * - * 1997-01-28 Modified by Finn Arne Gangstad to make timers scale better. - * - * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 - * "A Kernel Model for Precision Timekeeping" by Dave Mills - * 1998-12-24 Fixed a xtime SMP race (we need the xtime_lock rw spinlock to - * serialize accesses to xtime/lost_ticks). - * Copyright (C) 1998 Andrea Arcangeli - * 1999-03-10 Improved NTP compatibility by Ulrich Windl - * 2002-05-31 Move sys_sysinfo here and make its locking sane, Robert Love - * 2000-10-05 Implemented scalable SMP per-CPU timer handling. - * Copyright (C) 2000, 2001, 2002 Ingo Molnar - * Designed by David S. Miller, Alexey Kuznetsov and Ingo Molnar - */ - -#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 - -#include "tick-internal.h" - -#define CREATE_TRACE_POINTS -#include - -__visible u64 jiffies_64 __cacheline_aligned_in_smp = INITIAL_JIFFIES; - -EXPORT_SYMBOL(jiffies_64); - -/* - * The timer wheel has LVL_DEPTH array levels. Each level provides an array of - * LVL_SIZE buckets. Each level is driven by its own clock and therefor each - * level has a different granularity. - * - * The level granularity is: LVL_CLK_DIV ^ lvl - * The level clock frequency is: HZ / (LVL_CLK_DIV ^ level) - * - * The array level of a newly armed timer depends on the relative expiry - * time. The farther the expiry time is away the higher the array level and - * therefor the granularity becomes. - * - * Contrary to the original timer wheel implementation, which aims for 'exact' - * expiry of the timers, this implementation removes the need for recascading - * the timers into the lower array levels. The previous 'classic' timer wheel - * implementation of the kernel already violated the 'exact' expiry by adding - * slack to the expiry time to provide batched expiration. The granularity - * levels provide implicit batching. - * - * This is an optimization of the original timer wheel implementation for the - * majority of the timer wheel use cases: timeouts. The vast majority of - * timeout timers (networking, disk I/O ...) are canceled before expiry. If - * the timeout expires it indicates that normal operation is disturbed, so it - * does not matter much whether the timeout comes with a slight delay. - * - * The only exception to this are networking timers with a small expiry - * time. They rely on the granularity. Those fit into the first wheel level, - * which has HZ granularity. - * - * We don't have cascading anymore. timers with a expiry time above the - * capacity of the last wheel level are force expired at the maximum timeout - * value of the last wheel level. From data sampling we know that the maximum - * value observed is 5 days (network connection tracking), so this should not - * be an issue. - * - * The currently chosen array constants values are a good compromise between - * array size and granularity. - * - * This results in the following granularity and range levels: - * - * HZ 1000 steps - * Level Offset Granularity Range - * 0 0 1 ms 0 ms - 63 ms - * 1 64 8 ms 64 ms - 511 ms - * 2 128 64 ms 512 ms - 4095 ms (512ms - ~4s) - * 3 192 512 ms 4096 ms - 32767 ms (~4s - ~32s) - * 4 256 4096 ms (~4s) 32768 ms - 262143 ms (~32s - ~4m) - * 5 320 32768 ms (~32s) 262144 ms - 2097151 ms (~4m - ~34m) - * 6 384 262144 ms (~4m) 2097152 ms - 16777215 ms (~34m - ~4h) - * 7 448 2097152 ms (~34m) 16777216 ms - 134217727 ms (~4h - ~1d) - * 8 512 16777216 ms (~4h) 134217728 ms - 1073741822 ms (~1d - ~12d) - * - * HZ 300 - * Level Offset Granularity Range - * 0 0 3 ms 0 ms - 210 ms - * 1 64 26 ms 213 ms - 1703 ms (213ms - ~1s) - * 2 128 213 ms 1706 ms - 13650 ms (~1s - ~13s) - * 3 192 1706 ms (~1s) 13653 ms - 109223 ms (~13s - ~1m) - * 4 256 13653 ms (~13s) 109226 ms - 873810 ms (~1m - ~14m) - * 5 320 109226 ms (~1m) 873813 ms - 6990503 ms (~14m - ~1h) - * 6 384 873813 ms (~14m) 6990506 ms - 55924050 ms (~1h - ~15h) - * 7 448 6990506 ms (~1h) 55924053 ms - 447392423 ms (~15h - ~5d) - * 8 512 55924053 ms (~15h) 447392426 ms - 3579139406 ms (~5d - ~41d) - * - * HZ 250 - * Level Offset Granularity Range - * 0 0 4 ms 0 ms - 255 ms - * 1 64 32 ms 256 ms - 2047 ms (256ms - ~2s) - * 2 128 256 ms 2048 ms - 16383 ms (~2s - ~16s) - * 3 192 2048 ms (~2s) 16384 ms - 131071 ms (~16s - ~2m) - * 4 256 16384 ms (~16s) 131072 ms - 1048575 ms (~2m - ~17m) - * 5 320 131072 ms (~2m) 1048576 ms - 8388607 ms (~17m - ~2h) - * 6 384 1048576 ms (~17m) 8388608 ms - 67108863 ms (~2h - ~18h) - * 7 448 8388608 ms (~2h) 67108864 ms - 536870911 ms (~18h - ~6d) - * 8 512 67108864 ms (~18h) 536870912 ms - 4294967288 ms (~6d - ~49d) - * - * HZ 100 - * Level Offset Granularity Range - * 0 0 10 ms 0 ms - 630 ms - * 1 64 80 ms 640 ms - 5110 ms (640ms - ~5s) - * 2 128 640 ms 5120 ms - 40950 ms (~5s - ~40s) - * 3 192 5120 ms (~5s) 40960 ms - 327670 ms (~40s - ~5m) - * 4 256 40960 ms (~40s) 327680 ms - 2621430 ms (~5m - ~43m) - * 5 320 327680 ms (~5m) 2621440 ms - 20971510 ms (~43m - ~5h) - * 6 384 2621440 ms (~43m) 20971520 ms - 167772150 ms (~5h - ~1d) - * 7 448 20971520 ms (~5h) 167772160 ms - 1342177270 ms (~1d - ~15d) - */ - -/* Clock divisor for the next level */ -#define LVL_CLK_SHIFT 3 -#define LVL_CLK_DIV (1UL << LVL_CLK_SHIFT) -#define LVL_CLK_MASK (LVL_CLK_DIV - 1) -#define LVL_SHIFT(n) ((n) * LVL_CLK_SHIFT) -#define LVL_GRAN(n) (1UL << LVL_SHIFT(n)) - -/* - * The time start value for each level to select the bucket at enqueue - * time. - */ -#define LVL_START(n) ((LVL_SIZE - 1) << (((n) - 1) * LVL_CLK_SHIFT)) - -/* Size of each clock level */ -#define LVL_BITS 6 -#define LVL_SIZE (1UL << LVL_BITS) -#define LVL_MASK (LVL_SIZE - 1) -#define LVL_OFFS(n) ((n) * LVL_SIZE) - -/* Level depth */ -#if HZ > 100 -# define LVL_DEPTH 9 -# else -# define LVL_DEPTH 8 -#endif - -/* The cutoff (max. capacity of the wheel) */ -#define WHEEL_TIMEOUT_CUTOFF (LVL_START(LVL_DEPTH)) -#define WHEEL_TIMEOUT_MAX (WHEEL_TIMEOUT_CUTOFF - LVL_GRAN(LVL_DEPTH - 1)) - -/* - * The resulting wheel size. If NOHZ is configured we allocate two - * wheels so we have a separate storage for the deferrable timers. - */ -#define WHEEL_SIZE (LVL_SIZE * LVL_DEPTH) - -#ifdef CONFIG_NO_HZ_COMMON -# define NR_BASES 2 -# define BASE_STD 0 -# define BASE_DEF 1 -#else -# define NR_BASES 1 -# define BASE_STD 0 -# define BASE_DEF 0 -#endif - -struct timer_base { - spinlock_t lock; - struct timer_list *running_timer; - unsigned long clk; - unsigned long next_expiry; - unsigned int cpu; - bool migration_enabled; - bool nohz_active; - bool is_idle; - DECLARE_BITMAP(pending_map, WHEEL_SIZE); - struct hlist_head vectors[WHEEL_SIZE]; -} ____cacheline_aligned; - -static DEFINE_PER_CPU(struct timer_base, timer_bases[NR_BASES]); - -#if defined(CONFIG_SMP) && defined(CONFIG_NO_HZ_COMMON) -unsigned int sysctl_timer_migration = 1; - -void timers_update_migration(bool update_nohz) -{ - bool on = sysctl_timer_migration && tick_nohz_active; - unsigned int cpu; - - /* Avoid the loop, if nothing to update */ - if (this_cpu_read(timer_bases[BASE_STD].migration_enabled) == on) - return; - - for_each_possible_cpu(cpu) { - per_cpu(timer_bases[BASE_STD].migration_enabled, cpu) = on; - per_cpu(timer_bases[BASE_DEF].migration_enabled, cpu) = on; - per_cpu(hrtimer_bases.migration_enabled, cpu) = on; - if (!update_nohz) - continue; - per_cpu(timer_bases[BASE_STD].nohz_active, cpu) = true; - per_cpu(timer_bases[BASE_DEF].nohz_active, cpu) = true; - per_cpu(hrtimer_bases.nohz_active, cpu) = true; - } -} - -int timer_migration_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - static DEFINE_MUTEX(mutex); - int ret; - - mutex_lock(&mutex); - ret = proc_dointvec(table, write, buffer, lenp, ppos); - if (!ret && write) - timers_update_migration(false); - mutex_unlock(&mutex); - return ret; -} -#endif - -static unsigned long round_jiffies_common(unsigned long j, int cpu, - bool force_up) -{ - int rem; - unsigned long original = j; - - /* - * We don't want all cpus firing their timers at once hitting the - * same lock or cachelines, so we skew each extra cpu with an extra - * 3 jiffies. This 3 jiffies came originally from the mm/ code which - * already did this. - * The skew is done by adding 3*cpunr, then round, then subtract this - * extra offset again. - */ - j += cpu * 3; - - rem = j % HZ; - - /* - * If the target jiffie is just after a whole second (which can happen - * due to delays of the timer irq, long irq off times etc etc) then - * we should round down to the whole second, not up. Use 1/4th second - * as cutoff for this rounding as an extreme upper bound for this. - * But never round down if @force_up is set. - */ - if (rem < HZ/4 && !force_up) /* round down */ - j = j - rem; - else /* round up */ - j = j - rem + HZ; - - /* now that we have rounded, subtract the extra skew again */ - j -= cpu * 3; - - /* - * Make sure j is still in the future. Otherwise return the - * unmodified value. - */ - return time_is_after_jiffies(j) ? j : original; -} - -/** - * __round_jiffies - function to round jiffies to a full second - * @j: the time in (absolute) jiffies that should be rounded - * @cpu: the processor number on which the timeout will happen - * - * __round_jiffies() rounds an absolute time in the future (in jiffies) - * up or down to (approximately) full seconds. This is useful for timers - * for which the exact time they fire does not matter too much, as long as - * they fire approximately every X seconds. - * - * By rounding these timers to whole seconds, all such timers will fire - * at the same time, rather than at various times spread out. The goal - * of this is to have the CPU wake up less, which saves power. - * - * The exact rounding is skewed for each processor to avoid all - * processors firing at the exact same time, which could lead - * to lock contention or spurious cache line bouncing. - * - * The return value is the rounded version of the @j parameter. - */ -unsigned long __round_jiffies(unsigned long j, int cpu) -{ - return round_jiffies_common(j, cpu, false); -} -EXPORT_SYMBOL_GPL(__round_jiffies); - -/** - * __round_jiffies_relative - function to round jiffies to a full second - * @j: the time in (relative) jiffies that should be rounded - * @cpu: the processor number on which the timeout will happen - * - * __round_jiffies_relative() rounds a time delta in the future (in jiffies) - * up or down to (approximately) full seconds. This is useful for timers - * for which the exact time they fire does not matter too much, as long as - * they fire approximately every X seconds. - * - * By rounding these timers to whole seconds, all such timers will fire - * at the same time, rather than at various times spread out. The goal - * of this is to have the CPU wake up less, which saves power. - * - * The exact rounding is skewed for each processor to avoid all - * processors firing at the exact same time, which could lead - * to lock contention or spurious cache line bouncing. - * - * The return value is the rounded version of the @j parameter. - */ -unsigned long __round_jiffies_relative(unsigned long j, int cpu) -{ - unsigned long j0 = jiffies; - - /* Use j0 because jiffies might change while we run */ - return round_jiffies_common(j + j0, cpu, false) - j0; -} -EXPORT_SYMBOL_GPL(__round_jiffies_relative); - -/** - * round_jiffies - function to round jiffies to a full second - * @j: the time in (absolute) jiffies that should be rounded - * - * round_jiffies() rounds an absolute time in the future (in jiffies) - * up or down to (approximately) full seconds. This is useful for timers - * for which the exact time they fire does not matter too much, as long as - * they fire approximately every X seconds. - * - * By rounding these timers to whole seconds, all such timers will fire - * at the same time, rather than at various times spread out. The goal - * of this is to have the CPU wake up less, which saves power. - * - * The return value is the rounded version of the @j parameter. - */ -unsigned long round_jiffies(unsigned long j) -{ - return round_jiffies_common(j, raw_smp_processor_id(), false); -} -EXPORT_SYMBOL_GPL(round_jiffies); - -/** - * round_jiffies_relative - function to round jiffies to a full second - * @j: the time in (relative) jiffies that should be rounded - * - * round_jiffies_relative() rounds a time delta in the future (in jiffies) - * up or down to (approximately) full seconds. This is useful for timers - * for which the exact time they fire does not matter too much, as long as - * they fire approximately every X seconds. - * - * By rounding these timers to whole seconds, all such timers will fire - * at the same time, rather than at various times spread out. The goal - * of this is to have the CPU wake up less, which saves power. - * - * The return value is the rounded version of the @j parameter. - */ -unsigned long round_jiffies_relative(unsigned long j) -{ - return __round_jiffies_relative(j, raw_smp_processor_id()); -} -EXPORT_SYMBOL_GPL(round_jiffies_relative); - -/** - * __round_jiffies_up - function to round jiffies up to a full second - * @j: the time in (absolute) jiffies that should be rounded - * @cpu: the processor number on which the timeout will happen - * - * This is the same as __round_jiffies() except that it will never - * round down. This is useful for timeouts for which the exact time - * of firing does not matter too much, as long as they don't fire too - * early. - */ -unsigned long __round_jiffies_up(unsigned long j, int cpu) -{ - return round_jiffies_common(j, cpu, true); -} -EXPORT_SYMBOL_GPL(__round_jiffies_up); - -/** - * __round_jiffies_up_relative - function to round jiffies up to a full second - * @j: the time in (relative) jiffies that should be rounded - * @cpu: the processor number on which the timeout will happen - * - * This is the same as __round_jiffies_relative() except that it will never - * round down. This is useful for timeouts for which the exact time - * of firing does not matter too much, as long as they don't fire too - * early. - */ -unsigned long __round_jiffies_up_relative(unsigned long j, int cpu) -{ - unsigned long j0 = jiffies; - - /* Use j0 because jiffies might change while we run */ - return round_jiffies_common(j + j0, cpu, true) - j0; -} -EXPORT_SYMBOL_GPL(__round_jiffies_up_relative); - -/** - * round_jiffies_up - function to round jiffies up to a full second - * @j: the time in (absolute) jiffies that should be rounded - * - * This is the same as round_jiffies() except that it will never - * round down. This is useful for timeouts for which the exact time - * of firing does not matter too much, as long as they don't fire too - * early. - */ -unsigned long round_jiffies_up(unsigned long j) -{ - return round_jiffies_common(j, raw_smp_processor_id(), true); -} -EXPORT_SYMBOL_GPL(round_jiffies_up); - -/** - * round_jiffies_up_relative - function to round jiffies up to a full second - * @j: the time in (relative) jiffies that should be rounded - * - * This is the same as round_jiffies_relative() except that it will never - * round down. This is useful for timeouts for which the exact time - * of firing does not matter too much, as long as they don't fire too - * early. - */ -unsigned long round_jiffies_up_relative(unsigned long j) -{ - return __round_jiffies_up_relative(j, raw_smp_processor_id()); -} -EXPORT_SYMBOL_GPL(round_jiffies_up_relative); - - -static inline unsigned int timer_get_idx(struct timer_list *timer) -{ - return (timer->flags & TIMER_ARRAYMASK) >> TIMER_ARRAYSHIFT; -} - -static inline void timer_set_idx(struct timer_list *timer, unsigned int idx) -{ - timer->flags = (timer->flags & ~TIMER_ARRAYMASK) | - idx << TIMER_ARRAYSHIFT; -} - -/* - * Helper function to calculate the array index for a given expiry - * time. - */ -static inline unsigned calc_index(unsigned expires, unsigned lvl) -{ - expires = (expires + LVL_GRAN(lvl)) >> LVL_SHIFT(lvl); - return LVL_OFFS(lvl) + (expires & LVL_MASK); -} - -static int calc_wheel_index(unsigned long expires, unsigned long clk) -{ - unsigned long delta = expires - clk; - unsigned int idx; - - if (delta < LVL_START(1)) { - idx = calc_index(expires, 0); - } else if (delta < LVL_START(2)) { - idx = calc_index(expires, 1); - } else if (delta < LVL_START(3)) { - idx = calc_index(expires, 2); - } else if (delta < LVL_START(4)) { - idx = calc_index(expires, 3); - } else if (delta < LVL_START(5)) { - idx = calc_index(expires, 4); - } else if (delta < LVL_START(6)) { - idx = calc_index(expires, 5); - } else if (delta < LVL_START(7)) { - idx = calc_index(expires, 6); - } else if (LVL_DEPTH > 8 && delta < LVL_START(8)) { - idx = calc_index(expires, 7); - } else if ((long) delta < 0) { - idx = clk & LVL_MASK; - } else { - /* - * Force expire obscene large timeouts to expire at the - * capacity limit of the wheel. - */ - if (expires >= WHEEL_TIMEOUT_CUTOFF) - expires = WHEEL_TIMEOUT_MAX; - - idx = calc_index(expires, LVL_DEPTH - 1); - } - return idx; -} - -/* - * Enqueue the timer into the hash bucket, mark it pending in - * the bitmap and store the index in the timer flags. - */ -static void enqueue_timer(struct timer_base *base, struct timer_list *timer, - unsigned int idx) -{ - hlist_add_head(&timer->entry, base->vectors + idx); - __set_bit(idx, base->pending_map); - timer_set_idx(timer, idx); -} - -static void -__internal_add_timer(struct timer_base *base, struct timer_list *timer) -{ - unsigned int idx; - - idx = calc_wheel_index(timer->expires, base->clk); - enqueue_timer(base, timer, idx); -} - -static void -trigger_dyntick_cpu(struct timer_base *base, struct timer_list *timer) -{ - if (!IS_ENABLED(CONFIG_NO_HZ_COMMON) || !base->nohz_active) - return; - - /* - * TODO: This wants some optimizing similar to the code below, but we - * will do that when we switch from push to pull for deferrable timers. - */ - if (timer->flags & TIMER_DEFERRABLE) { - if (tick_nohz_full_cpu(base->cpu)) - wake_up_nohz_cpu(base->cpu); - return; - } - - /* - * We might have to IPI the remote CPU if the base is idle and the - * timer is not deferrable. If the other CPU is on the way to idle - * then it can't set base->is_idle as we hold the base lock: - */ - if (!base->is_idle) - return; - - /* Check whether this is the new first expiring timer: */ - if (time_after_eq(timer->expires, base->next_expiry)) - return; - - /* - * Set the next expiry time and kick the CPU so it can reevaluate the - * wheel: - */ - base->next_expiry = timer->expires; - wake_up_nohz_cpu(base->cpu); -} - -static void -internal_add_timer(struct timer_base *base, struct timer_list *timer) -{ - __internal_add_timer(base, timer); - trigger_dyntick_cpu(base, timer); -} - -#ifdef CONFIG_TIMER_STATS -void __timer_stats_timer_set_start_info(struct timer_list *timer, void *addr) -{ - if (timer->start_site) - return; - - timer->start_site = addr; - memcpy(timer->start_comm, current->comm, TASK_COMM_LEN); - timer->start_pid = current->pid; -} - -static void timer_stats_account_timer(struct timer_list *timer) -{ - void *site; - - /* - * start_site can be concurrently reset by - * timer_stats_timer_clear_start_info() - */ - site = READ_ONCE(timer->start_site); - if (likely(!site)) - return; - - timer_stats_update_stats(timer, timer->start_pid, site, - timer->function, timer->start_comm, - timer->flags); -} - -#else -static void timer_stats_account_timer(struct timer_list *timer) {} -#endif - -#ifdef CONFIG_DEBUG_OBJECTS_TIMERS - -static struct debug_obj_descr timer_debug_descr; - -static void *timer_debug_hint(void *addr) -{ - return ((struct timer_list *) addr)->function; -} - -static bool timer_is_static_object(void *addr) -{ - struct timer_list *timer = addr; - - return (timer->entry.pprev == NULL && - timer->entry.next == TIMER_ENTRY_STATIC); -} - -/* - * fixup_init is called when: - * - an active object is initialized - */ -static bool timer_fixup_init(void *addr, enum debug_obj_state state) -{ - struct timer_list *timer = addr; - - switch (state) { - case ODEBUG_STATE_ACTIVE: - del_timer_sync(timer); - debug_object_init(timer, &timer_debug_descr); - return true; - default: - return false; - } -} - -/* Stub timer callback for improperly used timers. */ -static void stub_timer(unsigned long data) -{ - WARN_ON(1); -} - -/* - * fixup_activate is called when: - * - an active object is activated - * - an unknown non-static object is activated - */ -static bool timer_fixup_activate(void *addr, enum debug_obj_state state) -{ - struct timer_list *timer = addr; - - switch (state) { - case ODEBUG_STATE_NOTAVAILABLE: - setup_timer(timer, stub_timer, 0); - return true; - - case ODEBUG_STATE_ACTIVE: - WARN_ON(1); - - default: - return false; - } -} - -/* - * fixup_free is called when: - * - an active object is freed - */ -static bool timer_fixup_free(void *addr, enum debug_obj_state state) -{ - struct timer_list *timer = addr; - - switch (state) { - case ODEBUG_STATE_ACTIVE: - del_timer_sync(timer); - debug_object_free(timer, &timer_debug_descr); - return true; - default: - return false; - } -} - -/* - * fixup_assert_init is called when: - * - an untracked/uninit-ed object is found - */ -static bool timer_fixup_assert_init(void *addr, enum debug_obj_state state) -{ - struct timer_list *timer = addr; - - switch (state) { - case ODEBUG_STATE_NOTAVAILABLE: - setup_timer(timer, stub_timer, 0); - return true; - default: - return false; - } -} - -static struct debug_obj_descr timer_debug_descr = { - .name = "timer_list", - .debug_hint = timer_debug_hint, - .is_static_object = timer_is_static_object, - .fixup_init = timer_fixup_init, - .fixup_activate = timer_fixup_activate, - .fixup_free = timer_fixup_free, - .fixup_assert_init = timer_fixup_assert_init, -}; - -static inline void debug_timer_init(struct timer_list *timer) -{ - debug_object_init(timer, &timer_debug_descr); -} - -static inline void debug_timer_activate(struct timer_list *timer) -{ - debug_object_activate(timer, &timer_debug_descr); -} - -static inline void debug_timer_deactivate(struct timer_list *timer) -{ - debug_object_deactivate(timer, &timer_debug_descr); -} - -static inline void debug_timer_free(struct timer_list *timer) -{ - debug_object_free(timer, &timer_debug_descr); -} - -static inline void debug_timer_assert_init(struct timer_list *timer) -{ - debug_object_assert_init(timer, &timer_debug_descr); -} - -static void do_init_timer(struct timer_list *timer, unsigned int flags, - const char *name, struct lock_class_key *key); - -void init_timer_on_stack_key(struct timer_list *timer, unsigned int flags, - const char *name, struct lock_class_key *key) -{ - debug_object_init_on_stack(timer, &timer_debug_descr); - do_init_timer(timer, flags, name, key); -} -EXPORT_SYMBOL_GPL(init_timer_on_stack_key); - -void destroy_timer_on_stack(struct timer_list *timer) -{ - debug_object_free(timer, &timer_debug_descr); -} -EXPORT_SYMBOL_GPL(destroy_timer_on_stack); - -#else -static inline void debug_timer_init(struct timer_list *timer) { } -static inline void debug_timer_activate(struct timer_list *timer) { } -static inline void debug_timer_deactivate(struct timer_list *timer) { } -static inline void debug_timer_assert_init(struct timer_list *timer) { } -#endif - -static inline void debug_init(struct timer_list *timer) -{ - debug_timer_init(timer); - trace_timer_init(timer); -} - -static inline void -debug_activate(struct timer_list *timer, unsigned long expires) -{ - debug_timer_activate(timer); - trace_timer_start(timer, expires, timer->flags); -} - -static inline void debug_deactivate(struct timer_list *timer) -{ - debug_timer_deactivate(timer); - trace_timer_cancel(timer); -} - -static inline void debug_assert_init(struct timer_list *timer) -{ - debug_timer_assert_init(timer); -} - -static void do_init_timer(struct timer_list *timer, unsigned int flags, - const char *name, struct lock_class_key *key) -{ - timer->entry.pprev = NULL; - timer->flags = flags | raw_smp_processor_id(); -#ifdef CONFIG_TIMER_STATS - timer->start_site = NULL; - timer->start_pid = -1; - memset(timer->start_comm, 0, TASK_COMM_LEN); -#endif - lockdep_init_map(&timer->lockdep_map, name, key, 0); -} - -/** - * init_timer_key - initialize a timer - * @timer: the timer to be initialized - * @flags: timer flags - * @name: name of the timer - * @key: lockdep class key of the fake lock used for tracking timer - * sync lock dependencies - * - * init_timer_key() must be done to a timer prior calling *any* of the - * other timer functions. - */ -void init_timer_key(struct timer_list *timer, unsigned int flags, - const char *name, struct lock_class_key *key) -{ - debug_init(timer); - do_init_timer(timer, flags, name, key); -} -EXPORT_SYMBOL(init_timer_key); - -static inline void detach_timer(struct timer_list *timer, bool clear_pending) -{ - struct hlist_node *entry = &timer->entry; - - debug_deactivate(timer); - - __hlist_del(entry); - if (clear_pending) - entry->pprev = NULL; - entry->next = LIST_POISON2; -} - -static int detach_if_pending(struct timer_list *timer, struct timer_base *base, - bool clear_pending) -{ - unsigned idx = timer_get_idx(timer); - - if (!timer_pending(timer)) - return 0; - - if (hlist_is_singular_node(&timer->entry, base->vectors + idx)) - __clear_bit(idx, base->pending_map); - - detach_timer(timer, clear_pending); - return 1; -} - -static inline struct timer_base *get_timer_cpu_base(u32 tflags, u32 cpu) -{ - struct timer_base *base = per_cpu_ptr(&timer_bases[BASE_STD], cpu); - - /* - * If the timer is deferrable and nohz is active then we need to use - * the deferrable base. - */ - if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active && - (tflags & TIMER_DEFERRABLE)) - base = per_cpu_ptr(&timer_bases[BASE_DEF], cpu); - return base; -} - -static inline struct timer_base *get_timer_this_cpu_base(u32 tflags) -{ - struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); - - /* - * If the timer is deferrable and nohz is active then we need to use - * the deferrable base. - */ - if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active && - (tflags & TIMER_DEFERRABLE)) - base = this_cpu_ptr(&timer_bases[BASE_DEF]); - return base; -} - -static inline struct timer_base *get_timer_base(u32 tflags) -{ - return get_timer_cpu_base(tflags, tflags & TIMER_CPUMASK); -} - -#ifdef CONFIG_NO_HZ_COMMON -static inline struct timer_base * -get_target_base(struct timer_base *base, unsigned tflags) -{ -#ifdef CONFIG_SMP - if ((tflags & TIMER_PINNED) || !base->migration_enabled) - return get_timer_this_cpu_base(tflags); - return get_timer_cpu_base(tflags, get_nohz_timer_target()); -#else - return get_timer_this_cpu_base(tflags); -#endif -} - -static inline void forward_timer_base(struct timer_base *base) -{ - unsigned long jnow = READ_ONCE(jiffies); - - /* - * We only forward the base when it's idle and we have a delta between - * base clock and jiffies. - */ - if (!base->is_idle || (long) (jnow - base->clk) < 2) - return; - - /* - * If the next expiry value is > jiffies, then we fast forward to - * jiffies otherwise we forward to the next expiry value. - */ - if (time_after(base->next_expiry, jnow)) - base->clk = jnow; - else - base->clk = base->next_expiry; -} -#else -static inline struct timer_base * -get_target_base(struct timer_base *base, unsigned tflags) -{ - return get_timer_this_cpu_base(tflags); -} - -static inline void forward_timer_base(struct timer_base *base) { } -#endif - - -/* - * We are using hashed locking: Holding per_cpu(timer_bases[x]).lock means - * that all timers which are tied to this base are locked, and the base itself - * is locked too. - * - * So __run_timers/migrate_timers can safely modify all timers which could - * be found in the base->vectors array. - * - * When a timer is migrating then the TIMER_MIGRATING flag is set and we need - * to wait until the migration is done. - */ -static struct timer_base *lock_timer_base(struct timer_list *timer, - unsigned long *flags) - __acquires(timer->base->lock) -{ - for (;;) { - struct timer_base *base; - u32 tf; - - /* - * We need to use READ_ONCE() here, otherwise the compiler - * might re-read @tf between the check for TIMER_MIGRATING - * and spin_lock(). - */ - tf = READ_ONCE(timer->flags); - - if (!(tf & TIMER_MIGRATING)) { - base = get_timer_base(tf); - spin_lock_irqsave(&base->lock, *flags); - if (timer->flags == tf) - return base; - spin_unlock_irqrestore(&base->lock, *flags); - } - cpu_relax(); - } -} - -static inline int -__mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only) -{ - struct timer_base *base, *new_base; - unsigned int idx = UINT_MAX; - unsigned long clk = 0, flags; - int ret = 0; - - BUG_ON(!timer->function); - - /* - * This is a common optimization triggered by the networking code - if - * the timer is re-modified to have the same timeout or ends up in the - * same array bucket then just return: - */ - if (timer_pending(timer)) { - if (timer->expires == expires) - return 1; - - /* - * We lock timer base and calculate the bucket index right - * here. If the timer ends up in the same bucket, then we - * just update the expiry time and avoid the whole - * dequeue/enqueue dance. - */ - base = lock_timer_base(timer, &flags); - - clk = base->clk; - idx = calc_wheel_index(expires, clk); - - /* - * Retrieve and compare the array index of the pending - * timer. If it matches set the expiry to the new value so a - * subsequent call will exit in the expires check above. - */ - if (idx == timer_get_idx(timer)) { - timer->expires = expires; - ret = 1; - goto out_unlock; - } - } else { - base = lock_timer_base(timer, &flags); - } - - timer_stats_timer_set_start_info(timer); - - ret = detach_if_pending(timer, base, false); - if (!ret && pending_only) - goto out_unlock; - - debug_activate(timer, expires); - - new_base = get_target_base(base, timer->flags); - - if (base != new_base) { - /* - * We are trying to schedule the timer on the new base. - * However we can't change timer's base while it is running, - * otherwise del_timer_sync() can't detect that the timer's - * handler yet has not finished. This also guarantees that the - * timer is serialized wrt itself. - */ - if (likely(base->running_timer != timer)) { - /* See the comment in lock_timer_base() */ - timer->flags |= TIMER_MIGRATING; - - spin_unlock(&base->lock); - base = new_base; - spin_lock(&base->lock); - WRITE_ONCE(timer->flags, - (timer->flags & ~TIMER_BASEMASK) | base->cpu); - } - } - - /* Try to forward a stale timer base clock */ - forward_timer_base(base); - - timer->expires = expires; - /* - * If 'idx' was calculated above and the base time did not advance - * between calculating 'idx' and possibly switching the base, only - * enqueue_timer() and trigger_dyntick_cpu() is required. Otherwise - * we need to (re)calculate the wheel index via - * internal_add_timer(). - */ - if (idx != UINT_MAX && clk == base->clk) { - enqueue_timer(base, timer, idx); - trigger_dyntick_cpu(base, timer); - } else { - internal_add_timer(base, timer); - } - -out_unlock: - spin_unlock_irqrestore(&base->lock, flags); - - return ret; -} - -/** - * mod_timer_pending - modify a pending timer's timeout - * @timer: the pending timer to be modified - * @expires: new timeout in jiffies - * - * mod_timer_pending() is the same for pending timers as mod_timer(), - * but will not re-activate and modify already deleted timers. - * - * It is useful for unserialized use of timers. - */ -int mod_timer_pending(struct timer_list *timer, unsigned long expires) -{ - return __mod_timer(timer, expires, true); -} -EXPORT_SYMBOL(mod_timer_pending); - -/** - * mod_timer - modify a timer's timeout - * @timer: the timer to be modified - * @expires: new timeout in jiffies - * - * mod_timer() is a more efficient way to update the expire field of an - * active timer (if the timer is inactive it will be activated) - * - * mod_timer(timer, expires) is equivalent to: - * - * del_timer(timer); timer->expires = expires; add_timer(timer); - * - * Note that if there are multiple unserialized concurrent users of the - * same timer, then mod_timer() is the only safe way to modify the timeout, - * since add_timer() cannot modify an already running timer. - * - * The function returns whether it has modified a pending timer or not. - * (ie. mod_timer() of an inactive timer returns 0, mod_timer() of an - * active timer returns 1.) - */ -int mod_timer(struct timer_list *timer, unsigned long expires) -{ - return __mod_timer(timer, expires, false); -} -EXPORT_SYMBOL(mod_timer); - -/** - * add_timer - start a timer - * @timer: the timer to be added - * - * The kernel will do a ->function(->data) callback from the - * timer interrupt at the ->expires point in the future. The - * current time is 'jiffies'. - * - * The timer's ->expires, ->function (and if the handler uses it, ->data) - * fields must be set prior calling this function. - * - * Timers with an ->expires field in the past will be executed in the next - * timer tick. - */ -void add_timer(struct timer_list *timer) -{ - BUG_ON(timer_pending(timer)); - mod_timer(timer, timer->expires); -} -EXPORT_SYMBOL(add_timer); - -/** - * add_timer_on - start a timer on a particular CPU - * @timer: the timer to be added - * @cpu: the CPU to start it on - * - * This is not very scalable on SMP. Double adds are not possible. - */ -void add_timer_on(struct timer_list *timer, int cpu) -{ - struct timer_base *new_base, *base; - unsigned long flags; - - timer_stats_timer_set_start_info(timer); - BUG_ON(timer_pending(timer) || !timer->function); - - new_base = get_timer_cpu_base(timer->flags, cpu); - - /* - * If @timer was on a different CPU, it should be migrated with the - * old base locked to prevent other operations proceeding with the - * wrong base locked. See lock_timer_base(). - */ - base = lock_timer_base(timer, &flags); - if (base != new_base) { - timer->flags |= TIMER_MIGRATING; - - spin_unlock(&base->lock); - base = new_base; - spin_lock(&base->lock); - WRITE_ONCE(timer->flags, - (timer->flags & ~TIMER_BASEMASK) | cpu); - } - - debug_activate(timer, timer->expires); - internal_add_timer(base, timer); - spin_unlock_irqrestore(&base->lock, flags); -} -EXPORT_SYMBOL_GPL(add_timer_on); - -/** - * del_timer - deactive a timer. - * @timer: the timer to be deactivated - * - * del_timer() deactivates a timer - this works on both active and inactive - * timers. - * - * The function returns whether it has deactivated a pending timer or not. - * (ie. del_timer() of an inactive timer returns 0, del_timer() of an - * active timer returns 1.) - */ -int del_timer(struct timer_list *timer) -{ - struct timer_base *base; - unsigned long flags; - int ret = 0; - - debug_assert_init(timer); - - timer_stats_timer_clear_start_info(timer); - if (timer_pending(timer)) { - base = lock_timer_base(timer, &flags); - ret = detach_if_pending(timer, base, true); - spin_unlock_irqrestore(&base->lock, flags); - } - - return ret; -} -EXPORT_SYMBOL(del_timer); - -/** - * try_to_del_timer_sync - Try to deactivate a timer - * @timer: timer do del - * - * This function tries to deactivate a timer. Upon successful (ret >= 0) - * exit the timer is not queued and the handler is not running on any CPU. - */ -int try_to_del_timer_sync(struct timer_list *timer) -{ - struct timer_base *base; - unsigned long flags; - int ret = -1; - - debug_assert_init(timer); - - base = lock_timer_base(timer, &flags); - - if (base->running_timer != timer) { - timer_stats_timer_clear_start_info(timer); - ret = detach_if_pending(timer, base, true); - } - spin_unlock_irqrestore(&base->lock, flags); - - return ret; -} -EXPORT_SYMBOL(try_to_del_timer_sync); - -#ifdef CONFIG_SMP -/** - * del_timer_sync - deactivate a timer and wait for the handler to finish. - * @timer: the timer to be deactivated - * - * This function only differs from del_timer() on SMP: besides deactivating - * the timer it also makes sure the handler has finished executing on other - * CPUs. - * - * Synchronization rules: Callers must prevent restarting of the timer, - * otherwise this function is meaningless. It must not be called from - * interrupt contexts unless the timer is an irqsafe one. The caller must - * not hold locks which would prevent completion of the timer's - * handler. The timer's handler must not call add_timer_on(). Upon exit the - * timer is not queued and the handler is not running on any CPU. - * - * Note: For !irqsafe timers, you must not hold locks that are held in - * interrupt context while calling this function. Even if the lock has - * nothing to do with the timer in question. Here's why: - * - * CPU0 CPU1 - * ---- ---- - * - * call_timer_fn(); - * base->running_timer = mytimer; - * spin_lock_irq(somelock); - * - * spin_lock(somelock); - * del_timer_sync(mytimer); - * while (base->running_timer == mytimer); - * - * Now del_timer_sync() will never return and never release somelock. - * The interrupt on the other CPU is waiting to grab somelock but - * it has interrupted the softirq that CPU0 is waiting to finish. - * - * The function returns whether it has deactivated a pending timer or not. - */ -int del_timer_sync(struct timer_list *timer) -{ -#ifdef CONFIG_LOCKDEP - unsigned long flags; - - /* - * If lockdep gives a backtrace here, please reference - * the synchronization rules above. - */ - local_irq_save(flags); - lock_map_acquire(&timer->lockdep_map); - lock_map_release(&timer->lockdep_map); - local_irq_restore(flags); -#endif - /* - * don't use it in hardirq context, because it - * could lead to deadlock. - */ - WARN_ON(in_irq() && !(timer->flags & TIMER_IRQSAFE)); - for (;;) { - int ret = try_to_del_timer_sync(timer); - if (ret >= 0) - return ret; - cpu_relax(); - } -} -EXPORT_SYMBOL(del_timer_sync); -#endif - -static void call_timer_fn(struct timer_list *timer, void (*fn)(unsigned long), - unsigned long data) -{ - int count = preempt_count(); - -#ifdef CONFIG_LOCKDEP - /* - * It is permissible to free the timer from inside the - * function that is called from it, this we need to take into - * account for lockdep too. To avoid bogus "held lock freed" - * warnings as well as problems when looking into - * timer->lockdep_map, make a copy and use that here. - */ - struct lockdep_map lockdep_map; - - lockdep_copy_map(&lockdep_map, &timer->lockdep_map); -#endif - /* - * Couple the lock chain with the lock chain at - * del_timer_sync() by acquiring the lock_map around the fn() - * call here and in del_timer_sync(). - */ - lock_map_acquire(&lockdep_map); - - trace_timer_expire_entry(timer); - fn(data); - trace_timer_expire_exit(timer); - - lock_map_release(&lockdep_map); - - if (count != preempt_count()) { - WARN_ONCE(1, "timer: %pF preempt leak: %08x -> %08x\n", - fn, count, preempt_count()); - /* - * Restore the preempt count. That gives us a decent - * chance to survive and extract information. If the - * callback kept a lock held, bad luck, but not worse - * than the BUG() we had. - */ - preempt_count_set(count); - } -} - -static void expire_timers(struct timer_base *base, struct hlist_head *head) -{ - while (!hlist_empty(head)) { - struct timer_list *timer; - void (*fn)(unsigned long); - unsigned long data; - - timer = hlist_entry(head->first, struct timer_list, entry); - timer_stats_account_timer(timer); - - base->running_timer = timer; - detach_timer(timer, true); - - fn = timer->function; - data = timer->data; - - if (timer->flags & TIMER_IRQSAFE) { - spin_unlock(&base->lock); - call_timer_fn(timer, fn, data); - spin_lock(&base->lock); - } else { - spin_unlock_irq(&base->lock); - call_timer_fn(timer, fn, data); - spin_lock_irq(&base->lock); - } - } -} - -static int __collect_expired_timers(struct timer_base *base, - struct hlist_head *heads) -{ - unsigned long clk = base->clk; - struct hlist_head *vec; - int i, levels = 0; - unsigned int idx; - - for (i = 0; i < LVL_DEPTH; i++) { - idx = (clk & LVL_MASK) + i * LVL_SIZE; - - if (__test_and_clear_bit(idx, base->pending_map)) { - vec = base->vectors + idx; - hlist_move_list(vec, heads++); - levels++; - } - /* Is it time to look at the next level? */ - if (clk & LVL_CLK_MASK) - break; - /* Shift clock for the next level granularity */ - clk >>= LVL_CLK_SHIFT; - } - return levels; -} - -#ifdef CONFIG_NO_HZ_COMMON -/* - * Find the next pending bucket of a level. Search from level start (@offset) - * + @clk upwards and if nothing there, search from start of the level - * (@offset) up to @offset + clk. - */ -static int next_pending_bucket(struct timer_base *base, unsigned offset, - unsigned clk) -{ - unsigned pos, start = offset + clk; - unsigned end = offset + LVL_SIZE; - - pos = find_next_bit(base->pending_map, end, start); - if (pos < end) - return pos - start; - - pos = find_next_bit(base->pending_map, start, offset); - return pos < start ? pos + LVL_SIZE - start : -1; -} - -/* - * Search the first expiring timer in the various clock levels. Caller must - * hold base->lock. - */ -static unsigned long __next_timer_interrupt(struct timer_base *base) -{ - unsigned long clk, next, adj; - unsigned lvl, offset = 0; - - next = base->clk + NEXT_TIMER_MAX_DELTA; - clk = base->clk; - for (lvl = 0; lvl < LVL_DEPTH; lvl++, offset += LVL_SIZE) { - int pos = next_pending_bucket(base, offset, clk & LVL_MASK); - - if (pos >= 0) { - unsigned long tmp = clk + (unsigned long) pos; - - tmp <<= LVL_SHIFT(lvl); - if (time_before(tmp, next)) - next = tmp; - } - /* - * Clock for the next level. If the current level clock lower - * bits are zero, we look at the next level as is. If not we - * need to advance it by one because that's going to be the - * next expiring bucket in that level. base->clk is the next - * expiring jiffie. So in case of: - * - * LVL5 LVL4 LVL3 LVL2 LVL1 LVL0 - * 0 0 0 0 0 0 - * - * we have to look at all levels @index 0. With - * - * LVL5 LVL4 LVL3 LVL2 LVL1 LVL0 - * 0 0 0 0 0 2 - * - * LVL0 has the next expiring bucket @index 2. The upper - * levels have the next expiring bucket @index 1. - * - * In case that the propagation wraps the next level the same - * rules apply: - * - * LVL5 LVL4 LVL3 LVL2 LVL1 LVL0 - * 0 0 0 0 F 2 - * - * So after looking at LVL0 we get: - * - * LVL5 LVL4 LVL3 LVL2 LVL1 - * 0 0 0 1 0 - * - * So no propagation from LVL1 to LVL2 because that happened - * with the add already, but then we need to propagate further - * from LVL2 to LVL3. - * - * So the simple check whether the lower bits of the current - * level are 0 or not is sufficient for all cases. - */ - adj = clk & LVL_CLK_MASK ? 1 : 0; - clk >>= LVL_CLK_SHIFT; - clk += adj; - } - return next; -} - -/* - * Check, if the next hrtimer event is before the next timer wheel - * event: - */ -static u64 cmp_next_hrtimer_event(u64 basem, u64 expires) -{ - u64 nextevt = hrtimer_get_next_event(); - - /* - * If high resolution timers are enabled - * hrtimer_get_next_event() returns KTIME_MAX. - */ - if (expires <= nextevt) - return expires; - - /* - * If the next timer is already expired, return the tick base - * time so the tick is fired immediately. - */ - if (nextevt <= basem) - return basem; - - /* - * Round up to the next jiffie. High resolution timers are - * off, so the hrtimers are expired in the tick and we need to - * make sure that this tick really expires the timer to avoid - * a ping pong of the nohz stop code. - * - * Use DIV_ROUND_UP_ULL to prevent gcc calling __divdi3 - */ - return DIV_ROUND_UP_ULL(nextevt, TICK_NSEC) * TICK_NSEC; -} - -/** - * get_next_timer_interrupt - return the time (clock mono) of the next timer - * @basej: base time jiffies - * @basem: base time clock monotonic - * - * Returns the tick aligned clock monotonic time of the next pending - * timer or KTIME_MAX if no timer is pending. - */ -u64 get_next_timer_interrupt(unsigned long basej, u64 basem) -{ - struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); - u64 expires = KTIME_MAX; - unsigned long nextevt; - bool is_max_delta; - - /* - * Pretend that there is no timer pending if the cpu is offline. - * Possible pending timers will be migrated later to an active cpu. - */ - if (cpu_is_offline(smp_processor_id())) - return expires; - - spin_lock(&base->lock); - nextevt = __next_timer_interrupt(base); - is_max_delta = (nextevt == base->clk + NEXT_TIMER_MAX_DELTA); - base->next_expiry = nextevt; - /* - * We have a fresh next event. Check whether we can forward the - * base. We can only do that when @basej is past base->clk - * otherwise we might rewind base->clk. - */ - if (time_after(basej, base->clk)) { - if (time_after(nextevt, basej)) - base->clk = basej; - else if (time_after(nextevt, base->clk)) - base->clk = nextevt; - } - - if (time_before_eq(nextevt, basej)) { - expires = basem; - base->is_idle = false; - } else { - if (!is_max_delta) - expires = basem + (nextevt - basej) * TICK_NSEC; - /* - * If we expect to sleep more than a tick, mark the base idle: - */ - if ((expires - basem) > TICK_NSEC) - base->is_idle = true; - } - spin_unlock(&base->lock); - - return cmp_next_hrtimer_event(basem, expires); -} - -/** - * timer_clear_idle - Clear the idle state of the timer base - * - * Called with interrupts disabled - */ -void timer_clear_idle(void) -{ - struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); - - /* - * We do this unlocked. The worst outcome is a remote enqueue sending - * a pointless IPI, but taking the lock would just make the window for - * sending the IPI a few instructions smaller for the cost of taking - * the lock in the exit from idle path. - */ - base->is_idle = false; -} - -static int collect_expired_timers(struct timer_base *base, - struct hlist_head *heads) -{ - /* - * NOHZ optimization. After a long idle sleep we need to forward the - * base to current jiffies. Avoid a loop by searching the bitfield for - * the next expiring timer. - */ - if ((long)(jiffies - base->clk) > 2) { - unsigned long next = __next_timer_interrupt(base); - - /* - * If the next timer is ahead of time forward to current - * jiffies, otherwise forward to the next expiry time: - */ - if (time_after(next, jiffies)) { - /* The call site will increment clock! */ - base->clk = jiffies - 1; - return 0; - } - base->clk = next; - } - return __collect_expired_timers(base, heads); -} -#else -static inline int collect_expired_timers(struct timer_base *base, - struct hlist_head *heads) -{ - return __collect_expired_timers(base, heads); -} -#endif - -/* - * Called from the timer interrupt handler to charge one tick to the current - * process. user_tick is 1 if the tick is user time, 0 for system. - */ -void update_process_times(int user_tick) -{ - struct task_struct *p = current; - - /* Note: this timer irq context must be accounted for as well. */ - account_process_tick(p, user_tick); - run_local_timers(); - rcu_check_callbacks(user_tick); -#ifdef CONFIG_IRQ_WORK - if (in_irq()) - irq_work_tick(); -#endif - scheduler_tick(); - run_posix_cpu_timers(p); -} - -/** - * __run_timers - run all expired timers (if any) on this CPU. - * @base: the timer vector to be processed. - */ -static inline void __run_timers(struct timer_base *base) -{ - struct hlist_head heads[LVL_DEPTH]; - int levels; - - if (!time_after_eq(jiffies, base->clk)) - return; - - spin_lock_irq(&base->lock); - - while (time_after_eq(jiffies, base->clk)) { - - levels = collect_expired_timers(base, heads); - base->clk++; - - while (levels--) - expire_timers(base, heads + levels); - } - base->running_timer = NULL; - spin_unlock_irq(&base->lock); -} - -/* - * This function runs timers and the timer-tq in bottom half context. - */ -static __latent_entropy void run_timer_softirq(struct softirq_action *h) -{ - struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); - - __run_timers(base); - if (IS_ENABLED(CONFIG_NO_HZ_COMMON) && base->nohz_active) - __run_timers(this_cpu_ptr(&timer_bases[BASE_DEF])); -} - -/* - * Called by the local, per-CPU timer interrupt on SMP. - */ -void run_local_timers(void) -{ - struct timer_base *base = this_cpu_ptr(&timer_bases[BASE_STD]); - - hrtimer_run_queues(); - /* Raise the softirq only if required. */ - if (time_before(jiffies, base->clk)) { - if (!IS_ENABLED(CONFIG_NO_HZ_COMMON) || !base->nohz_active) - return; - /* CPU is awake, so check the deferrable base. */ - base++; - if (time_before(jiffies, base->clk)) - return; - } - raise_softirq(TIMER_SOFTIRQ); -} - -#ifdef __ARCH_WANT_SYS_ALARM - -/* - * For backwards compatibility? This can be done in libc so Alpha - * and all newer ports shouldn't need it. - */ -SYSCALL_DEFINE1(alarm, unsigned int, seconds) -{ - return alarm_setitimer(seconds); -} - -#endif - -static void process_timeout(unsigned long __data) -{ - wake_up_process((struct task_struct *)__data); -} - -/** - * schedule_timeout - sleep until timeout - * @timeout: timeout value in jiffies - * - * Make the current task sleep until @timeout jiffies have - * elapsed. The routine will return immediately unless - * the current task state has been set (see set_current_state()). - * - * You can set the task state as follows - - * - * %TASK_UNINTERRUPTIBLE - at least @timeout jiffies are guaranteed to - * pass before the routine returns. The routine will return 0 - * - * %TASK_INTERRUPTIBLE - the routine may return early if a signal is - * delivered to the current task. In this case the remaining time - * in jiffies will be returned, or 0 if the timer expired in time - * - * The current task state is guaranteed to be TASK_RUNNING when this - * routine returns. - * - * Specifying a @timeout value of %MAX_SCHEDULE_TIMEOUT will schedule - * the CPU away without a bound on the timeout. In this case the return - * value will be %MAX_SCHEDULE_TIMEOUT. - * - * In all cases the return value is guaranteed to be non-negative. - */ -signed long __sched schedule_timeout(signed long timeout) -{ - struct timer_list timer; - unsigned long expire; - - switch (timeout) - { - case MAX_SCHEDULE_TIMEOUT: - /* - * These two special cases are useful to be comfortable - * in the caller. Nothing more. We could take - * MAX_SCHEDULE_TIMEOUT from one of the negative value - * but I' d like to return a valid offset (>=0) to allow - * the caller to do everything it want with the retval. - */ - schedule(); - goto out; - default: - /* - * Another bit of PARANOID. Note that the retval will be - * 0 since no piece of kernel is supposed to do a check - * for a negative retval of schedule_timeout() (since it - * should never happens anyway). You just have the printk() - * that will tell you if something is gone wrong and where. - */ - if (timeout < 0) { - printk(KERN_ERR "schedule_timeout: wrong timeout " - "value %lx\n", timeout); - dump_stack(); - current->state = TASK_RUNNING; - goto out; - } - } - - expire = timeout + jiffies; - - setup_timer_on_stack(&timer, process_timeout, (unsigned long)current); - __mod_timer(&timer, expire, false); - schedule(); - del_singleshot_timer_sync(&timer); - - /* Remove the timer from the object tracker */ - destroy_timer_on_stack(&timer); - - timeout = expire - jiffies; - - out: - return timeout < 0 ? 0 : timeout; -} -EXPORT_SYMBOL(schedule_timeout); - -/* - * We can use __set_current_state() here because schedule_timeout() calls - * schedule() unconditionally. - */ -signed long __sched schedule_timeout_interruptible(signed long timeout) -{ - __set_current_state(TASK_INTERRUPTIBLE); - return schedule_timeout(timeout); -} -EXPORT_SYMBOL(schedule_timeout_interruptible); - -signed long __sched schedule_timeout_killable(signed long timeout) -{ - __set_current_state(TASK_KILLABLE); - return schedule_timeout(timeout); -} -EXPORT_SYMBOL(schedule_timeout_killable); - -signed long __sched schedule_timeout_uninterruptible(signed long timeout) -{ - __set_current_state(TASK_UNINTERRUPTIBLE); - return schedule_timeout(timeout); -} -EXPORT_SYMBOL(schedule_timeout_uninterruptible); - -/* - * Like schedule_timeout_uninterruptible(), except this task will not contribute - * to load average. - */ -signed long __sched schedule_timeout_idle(signed long timeout) -{ - __set_current_state(TASK_IDLE); - return schedule_timeout(timeout); -} -EXPORT_SYMBOL(schedule_timeout_idle); - -#ifdef CONFIG_HOTPLUG_CPU -static void migrate_timer_list(struct timer_base *new_base, struct hlist_head *head) -{ - struct timer_list *timer; - int cpu = new_base->cpu; - - while (!hlist_empty(head)) { - timer = hlist_entry(head->first, struct timer_list, entry); - detach_timer(timer, false); - timer->flags = (timer->flags & ~TIMER_BASEMASK) | cpu; - internal_add_timer(new_base, timer); - } -} - -int timers_dead_cpu(unsigned int cpu) -{ - struct timer_base *old_base; - struct timer_base *new_base; - int b, i; - - BUG_ON(cpu_online(cpu)); - - for (b = 0; b < NR_BASES; b++) { - old_base = per_cpu_ptr(&timer_bases[b], cpu); - new_base = get_cpu_ptr(&timer_bases[b]); - /* - * The caller is globally serialized and nobody else - * takes two locks at once, deadlock is not possible. - */ - spin_lock_irq(&new_base->lock); - spin_lock_nested(&old_base->lock, SINGLE_DEPTH_NESTING); - - BUG_ON(old_base->running_timer); - - for (i = 0; i < WHEEL_SIZE; i++) - migrate_timer_list(new_base, old_base->vectors + i); - - spin_unlock(&old_base->lock); - spin_unlock_irq(&new_base->lock); - put_cpu_ptr(&timer_bases); - } - return 0; -} - -#endif /* CONFIG_HOTPLUG_CPU */ - -static void __init init_timer_cpu(int cpu) -{ - struct timer_base *base; - int i; - - for (i = 0; i < NR_BASES; i++) { - base = per_cpu_ptr(&timer_bases[i], cpu); - base->cpu = cpu; - spin_lock_init(&base->lock); - base->clk = jiffies; - } -} - -static void __init init_timer_cpus(void) -{ - int cpu; - - for_each_possible_cpu(cpu) - init_timer_cpu(cpu); -} - -void __init init_timers(void) -{ - init_timer_cpus(); - init_timer_stats(); - open_softirq(TIMER_SOFTIRQ, run_timer_softirq); -} - -/** - * msleep - sleep safely even with waitqueue interruptions - * @msecs: Time in milliseconds to sleep for - */ -void msleep(unsigned int msecs) -{ - unsigned long timeout = msecs_to_jiffies(msecs) + 1; - - while (timeout) - timeout = schedule_timeout_uninterruptible(timeout); -} - -EXPORT_SYMBOL(msleep); - -/** - * msleep_interruptible - sleep waiting for signals - * @msecs: Time in milliseconds to sleep for - */ -unsigned long msleep_interruptible(unsigned int msecs) -{ - unsigned long timeout = msecs_to_jiffies(msecs) + 1; - - while (timeout && !signal_pending(current)) - timeout = schedule_timeout_interruptible(timeout); - return jiffies_to_msecs(timeout); -} - -EXPORT_SYMBOL(msleep_interruptible); - -static void __sched do_usleep_range(unsigned long min, unsigned long max) -{ - ktime_t kmin; - u64 delta; - - kmin = ktime_set(0, min * NSEC_PER_USEC); - delta = (u64)(max - min) * NSEC_PER_USEC; - schedule_hrtimeout_range(&kmin, delta, HRTIMER_MODE_REL); -} - -/** - * usleep_range - Sleep for an approximate time - * @min: Minimum time in usecs to sleep - * @max: Maximum time in usecs to sleep - * - * In non-atomic context where the exact wakeup time is flexible, use - * usleep_range() instead of udelay(). The sleep improves responsiveness - * by avoiding the CPU-hogging busy-wait of udelay(), and the range reduces - * power usage by allowing hrtimers to take advantage of an already- - * scheduled interrupt instead of scheduling a new one just for this sleep. - */ -void __sched usleep_range(unsigned long min, unsigned long max) -{ - __set_current_state(TASK_UNINTERRUPTIBLE); - do_usleep_range(min, max); -} -EXPORT_SYMBOL(usleep_range); diff --git a/src/linux/kernel/time/timer_list.c b/src/linux/kernel/time/timer_list.c deleted file mode 100644 index ba7d8b2..0000000 --- a/src/linux/kernel/time/timer_list.c +++ /dev/null @@ -1,401 +0,0 @@ -/* - * kernel/time/timer_list.c - * - * List pending timers - * - * Copyright(C) 2006, Red Hat, Inc., Ingo Molnar - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include - -#include - -#include "tick-internal.h" - -struct timer_list_iter { - int cpu; - bool second_pass; - u64 now; -}; - -typedef void (*print_fn_t)(struct seq_file *m, unsigned int *classes); - -/* - * This allows printing both to /proc/timer_list and - * to the console (on SysRq-Q): - */ -__printf(2, 3) -static void SEQ_printf(struct seq_file *m, const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - - if (m) - seq_vprintf(m, fmt, args); - else - vprintk(fmt, args); - - va_end(args); -} - -static void print_name_offset(struct seq_file *m, void *sym) -{ - char symname[KSYM_NAME_LEN]; - - if (lookup_symbol_name((unsigned long)sym, symname) < 0) - SEQ_printf(m, "<%pK>", sym); - else - SEQ_printf(m, "%s", symname); -} - -static void -print_timer(struct seq_file *m, struct hrtimer *taddr, struct hrtimer *timer, - int idx, u64 now) -{ -#ifdef CONFIG_TIMER_STATS - char tmp[TASK_COMM_LEN + 1]; -#endif - SEQ_printf(m, " #%d: ", idx); - print_name_offset(m, taddr); - SEQ_printf(m, ", "); - print_name_offset(m, timer->function); - SEQ_printf(m, ", S:%02x", timer->state); -#ifdef CONFIG_TIMER_STATS - SEQ_printf(m, ", "); - print_name_offset(m, timer->start_site); - memcpy(tmp, timer->start_comm, TASK_COMM_LEN); - tmp[TASK_COMM_LEN] = 0; - SEQ_printf(m, ", %s/%d", tmp, timer->start_pid); -#endif - SEQ_printf(m, "\n"); - SEQ_printf(m, " # expires at %Lu-%Lu nsecs [in %Ld to %Ld nsecs]\n", - (unsigned long long)ktime_to_ns(hrtimer_get_softexpires(timer)), - (unsigned long long)ktime_to_ns(hrtimer_get_expires(timer)), - (long long)(ktime_to_ns(hrtimer_get_softexpires(timer)) - now), - (long long)(ktime_to_ns(hrtimer_get_expires(timer)) - now)); -} - -static void -print_active_timers(struct seq_file *m, struct hrtimer_clock_base *base, - u64 now) -{ - struct hrtimer *timer, tmp; - unsigned long next = 0, i; - struct timerqueue_node *curr; - unsigned long flags; - -next_one: - i = 0; - raw_spin_lock_irqsave(&base->cpu_base->lock, flags); - - curr = timerqueue_getnext(&base->active); - /* - * Crude but we have to do this O(N*N) thing, because - * we have to unlock the base when printing: - */ - while (curr && i < next) { - curr = timerqueue_iterate_next(curr); - i++; - } - - if (curr) { - - timer = container_of(curr, struct hrtimer, node); - tmp = *timer; - raw_spin_unlock_irqrestore(&base->cpu_base->lock, flags); - - print_timer(m, timer, &tmp, i, now); - next++; - goto next_one; - } - raw_spin_unlock_irqrestore(&base->cpu_base->lock, flags); -} - -static void -print_base(struct seq_file *m, struct hrtimer_clock_base *base, u64 now) -{ - SEQ_printf(m, " .base: %pK\n", base); - SEQ_printf(m, " .index: %d\n", base->index); - - SEQ_printf(m, " .resolution: %u nsecs\n", (unsigned) hrtimer_resolution); - - SEQ_printf(m, " .get_time: "); - print_name_offset(m, base->get_time); - SEQ_printf(m, "\n"); -#ifdef CONFIG_HIGH_RES_TIMERS - SEQ_printf(m, " .offset: %Lu nsecs\n", - (unsigned long long) ktime_to_ns(base->offset)); -#endif - SEQ_printf(m, "active timers:\n"); - print_active_timers(m, base, now + ktime_to_ns(base->offset)); -} - -static void print_cpu(struct seq_file *m, int cpu, u64 now) -{ - struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu); - int i; - - SEQ_printf(m, "cpu: %d\n", cpu); - for (i = 0; i < HRTIMER_MAX_CLOCK_BASES; i++) { - SEQ_printf(m, " clock %d:\n", i); - print_base(m, cpu_base->clock_base + i, now); - } -#define P(x) \ - SEQ_printf(m, " .%-15s: %Lu\n", #x, \ - (unsigned long long)(cpu_base->x)) -#define P_ns(x) \ - SEQ_printf(m, " .%-15s: %Lu nsecs\n", #x, \ - (unsigned long long)(ktime_to_ns(cpu_base->x))) - -#ifdef CONFIG_HIGH_RES_TIMERS - P_ns(expires_next); - P(hres_active); - P(nr_events); - P(nr_retries); - P(nr_hangs); - P(max_hang_time); -#endif -#undef P -#undef P_ns - -#ifdef CONFIG_TICK_ONESHOT -# define P(x) \ - SEQ_printf(m, " .%-15s: %Lu\n", #x, \ - (unsigned long long)(ts->x)) -# define P_ns(x) \ - SEQ_printf(m, " .%-15s: %Lu nsecs\n", #x, \ - (unsigned long long)(ktime_to_ns(ts->x))) - { - struct tick_sched *ts = tick_get_tick_sched(cpu); - P(nohz_mode); - P_ns(last_tick); - P(tick_stopped); - P(idle_jiffies); - P(idle_calls); - P(idle_sleeps); - P_ns(idle_entrytime); - P_ns(idle_waketime); - P_ns(idle_exittime); - P_ns(idle_sleeptime); - P_ns(iowait_sleeptime); - P(last_jiffies); - P(next_timer); - P_ns(idle_expires); - SEQ_printf(m, "jiffies: %Lu\n", - (unsigned long long)jiffies); - } -#endif - -#undef P -#undef P_ns - SEQ_printf(m, "\n"); -} - -#ifdef CONFIG_GENERIC_CLOCKEVENTS -static void -print_tickdevice(struct seq_file *m, struct tick_device *td, int cpu) -{ - struct clock_event_device *dev = td->evtdev; - - SEQ_printf(m, "Tick Device: mode: %d\n", td->mode); - if (cpu < 0) - SEQ_printf(m, "Broadcast device\n"); - else - SEQ_printf(m, "Per CPU device: %d\n", cpu); - - SEQ_printf(m, "Clock Event Device: "); - if (!dev) { - SEQ_printf(m, "\n"); - return; - } - SEQ_printf(m, "%s\n", dev->name); - SEQ_printf(m, " max_delta_ns: %llu\n", - (unsigned long long) dev->max_delta_ns); - SEQ_printf(m, " min_delta_ns: %llu\n", - (unsigned long long) dev->min_delta_ns); - SEQ_printf(m, " mult: %u\n", dev->mult); - SEQ_printf(m, " shift: %u\n", dev->shift); - SEQ_printf(m, " mode: %d\n", clockevent_get_state(dev)); - SEQ_printf(m, " next_event: %Ld nsecs\n", - (unsigned long long) ktime_to_ns(dev->next_event)); - - SEQ_printf(m, " set_next_event: "); - print_name_offset(m, dev->set_next_event); - SEQ_printf(m, "\n"); - - if (dev->set_state_shutdown) { - SEQ_printf(m, " shutdown: "); - print_name_offset(m, dev->set_state_shutdown); - SEQ_printf(m, "\n"); - } - - if (dev->set_state_periodic) { - SEQ_printf(m, " periodic: "); - print_name_offset(m, dev->set_state_periodic); - SEQ_printf(m, "\n"); - } - - if (dev->set_state_oneshot) { - SEQ_printf(m, " oneshot: "); - print_name_offset(m, dev->set_state_oneshot); - SEQ_printf(m, "\n"); - } - - if (dev->set_state_oneshot_stopped) { - SEQ_printf(m, " oneshot stopped: "); - print_name_offset(m, dev->set_state_oneshot_stopped); - SEQ_printf(m, "\n"); - } - - if (dev->tick_resume) { - SEQ_printf(m, " resume: "); - print_name_offset(m, dev->tick_resume); - SEQ_printf(m, "\n"); - } - - SEQ_printf(m, " event_handler: "); - print_name_offset(m, dev->event_handler); - SEQ_printf(m, "\n"); - SEQ_printf(m, " retries: %lu\n", dev->retries); - SEQ_printf(m, "\n"); -} - -static void timer_list_show_tickdevices_header(struct seq_file *m) -{ -#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST - print_tickdevice(m, tick_get_broadcast_device(), -1); - SEQ_printf(m, "tick_broadcast_mask: %*pb\n", - cpumask_pr_args(tick_get_broadcast_mask())); -#ifdef CONFIG_TICK_ONESHOT - SEQ_printf(m, "tick_broadcast_oneshot_mask: %*pb\n", - cpumask_pr_args(tick_get_broadcast_oneshot_mask())); -#endif - SEQ_printf(m, "\n"); -#endif -} -#endif - -static inline void timer_list_header(struct seq_file *m, u64 now) -{ - SEQ_printf(m, "Timer List Version: v0.8\n"); - SEQ_printf(m, "HRTIMER_MAX_CLOCK_BASES: %d\n", HRTIMER_MAX_CLOCK_BASES); - SEQ_printf(m, "now at %Ld nsecs\n", (unsigned long long)now); - SEQ_printf(m, "\n"); -} - -static int timer_list_show(struct seq_file *m, void *v) -{ - struct timer_list_iter *iter = v; - - if (iter->cpu == -1 && !iter->second_pass) - timer_list_header(m, iter->now); - else if (!iter->second_pass) - print_cpu(m, iter->cpu, iter->now); -#ifdef CONFIG_GENERIC_CLOCKEVENTS - else if (iter->cpu == -1 && iter->second_pass) - timer_list_show_tickdevices_header(m); - else - print_tickdevice(m, tick_get_device(iter->cpu), iter->cpu); -#endif - return 0; -} - -void sysrq_timer_list_show(void) -{ - u64 now = ktime_to_ns(ktime_get()); - int cpu; - - timer_list_header(NULL, now); - - for_each_online_cpu(cpu) - print_cpu(NULL, cpu, now); - -#ifdef CONFIG_GENERIC_CLOCKEVENTS - timer_list_show_tickdevices_header(NULL); - for_each_online_cpu(cpu) - print_tickdevice(NULL, tick_get_device(cpu), cpu); -#endif - return; -} - -static void *move_iter(struct timer_list_iter *iter, loff_t offset) -{ - for (; offset; offset--) { - iter->cpu = cpumask_next(iter->cpu, cpu_online_mask); - if (iter->cpu >= nr_cpu_ids) { -#ifdef CONFIG_GENERIC_CLOCKEVENTS - if (!iter->second_pass) { - iter->cpu = -1; - iter->second_pass = true; - } else - return NULL; -#else - return NULL; -#endif - } - } - return iter; -} - -static void *timer_list_start(struct seq_file *file, loff_t *offset) -{ - struct timer_list_iter *iter = file->private; - - if (!*offset) - iter->now = ktime_to_ns(ktime_get()); - iter->cpu = -1; - iter->second_pass = false; - return move_iter(iter, *offset); -} - -static void *timer_list_next(struct seq_file *file, void *v, loff_t *offset) -{ - struct timer_list_iter *iter = file->private; - ++*offset; - return move_iter(iter, 1); -} - -static void timer_list_stop(struct seq_file *seq, void *v) -{ -} - -static const struct seq_operations timer_list_sops = { - .start = timer_list_start, - .next = timer_list_next, - .stop = timer_list_stop, - .show = timer_list_show, -}; - -static int timer_list_open(struct inode *inode, struct file *filp) -{ - return seq_open_private(filp, &timer_list_sops, - sizeof(struct timer_list_iter)); -} - -static const struct file_operations timer_list_fops = { - .open = timer_list_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_private, -}; - -static int __init init_timer_list_procfs(void) -{ - struct proc_dir_entry *pe; - - pe = proc_create("timer_list", 0444, NULL, &timer_list_fops); - if (!pe) - return -ENOMEM; - return 0; -} -__initcall(init_timer_list_procfs); diff --git a/src/linux/kernel/trace/Kconfig b/src/linux/kernel/trace/Kconfig deleted file mode 100644 index 2a96b06..0000000 --- a/src/linux/kernel/trace/Kconfig +++ /dev/null @@ -1,705 +0,0 @@ -# -# Architectures that offer an FUNCTION_TRACER implementation should -# select HAVE_FUNCTION_TRACER: -# - -config USER_STACKTRACE_SUPPORT - bool - -config NOP_TRACER - bool - -config HAVE_FTRACE_NMI_ENTER - bool - help - See Documentation/trace/ftrace-design.txt - -config HAVE_FUNCTION_TRACER - bool - help - See Documentation/trace/ftrace-design.txt - -config HAVE_FUNCTION_GRAPH_TRACER - bool - help - See Documentation/trace/ftrace-design.txt - -config HAVE_DYNAMIC_FTRACE - bool - help - See Documentation/trace/ftrace-design.txt - -config HAVE_DYNAMIC_FTRACE_WITH_REGS - bool - -config HAVE_FTRACE_MCOUNT_RECORD - bool - help - See Documentation/trace/ftrace-design.txt - -config HAVE_SYSCALL_TRACEPOINTS - bool - help - See Documentation/trace/ftrace-design.txt - -config HAVE_FENTRY - bool - help - Arch supports the gcc options -pg with -mfentry - -config HAVE_C_RECORDMCOUNT - bool - help - C version of recordmcount available? - -config TRACER_MAX_TRACE - bool - -config TRACE_CLOCK - bool - -config RING_BUFFER - bool - select TRACE_CLOCK - select IRQ_WORK - -config FTRACE_NMI_ENTER - bool - depends on HAVE_FTRACE_NMI_ENTER - default y - -config EVENT_TRACING - select CONTEXT_SWITCH_TRACER - bool - -config CONTEXT_SWITCH_TRACER - bool - -config RING_BUFFER_ALLOW_SWAP - bool - help - Allow the use of ring_buffer_swap_cpu. - Adds a very slight overhead to tracing when enabled. - -# All tracer options should select GENERIC_TRACER. For those options that are -# enabled by all tracers (context switch and event tracer) they select TRACING. -# This allows those options to appear when no other tracer is selected. But the -# options do not appear when something else selects it. We need the two options -# GENERIC_TRACER and TRACING to avoid circular dependencies to accomplish the -# hiding of the automatic options. - -config TRACING - bool - select DEBUG_FS - select RING_BUFFER - select STACKTRACE if STACKTRACE_SUPPORT - select TRACEPOINTS - select NOP_TRACER - select BINARY_PRINTF - select EVENT_TRACING - select TRACE_CLOCK - -config GENERIC_TRACER - bool - select TRACING - -# -# Minimum requirements an architecture has to meet for us to -# be able to offer generic tracing facilities: -# -config TRACING_SUPPORT - bool - # PPC32 has no irqflags tracing support, but it can use most of the - # tracers anyway, they were tested to build and work. Note that new - # exceptions to this list aren't welcomed, better implement the - # irqflags tracing for your architecture. - depends on TRACE_IRQFLAGS_SUPPORT || PPC32 - depends on STACKTRACE_SUPPORT - default y - -if TRACING_SUPPORT - -menuconfig FTRACE - bool "Tracers" - default y if DEBUG_KERNEL - help - Enable the kernel tracing infrastructure. - -if FTRACE - -config FUNCTION_TRACER - bool "Kernel Function Tracer" - depends on HAVE_FUNCTION_TRACER - select KALLSYMS - select GENERIC_TRACER - select CONTEXT_SWITCH_TRACER - help - Enable the kernel to trace every kernel function. This is done - by using a compiler feature to insert a small, 5-byte No-Operation - instruction at the beginning of every kernel function, which NOP - sequence is then dynamically patched into a tracer call when - tracing is enabled by the administrator. If it's runtime disabled - (the bootup default), then the overhead of the instructions is very - small and not measurable even in micro-benchmarks. - -config FUNCTION_GRAPH_TRACER - bool "Kernel Function Graph Tracer" - depends on HAVE_FUNCTION_GRAPH_TRACER - depends on FUNCTION_TRACER - depends on !X86_32 || !CC_OPTIMIZE_FOR_SIZE - default y - help - Enable the kernel to trace a function at both its return - and its entry. - Its first purpose is to trace the duration of functions and - draw a call graph for each thread with some information like - the return value. This is done by setting the current return - address on the current task structure into a stack of calls. - - -config IRQSOFF_TRACER - bool "Interrupts-off Latency Tracer" - default n - depends on TRACE_IRQFLAGS_SUPPORT - depends on !ARCH_USES_GETTIMEOFFSET - select TRACE_IRQFLAGS - select GENERIC_TRACER - select TRACER_MAX_TRACE - select RING_BUFFER_ALLOW_SWAP - select TRACER_SNAPSHOT - select TRACER_SNAPSHOT_PER_CPU_SWAP - help - This option measures the time spent in irqs-off critical - sections, with microsecond accuracy. - - The default measurement method is a maximum search, which is - disabled by default and can be runtime (re-)started - via: - - echo 0 > /sys/kernel/debug/tracing/tracing_max_latency - - (Note that kernel size and overhead increase with this option - enabled. This option and the preempt-off timing option can be - used together or separately.) - -config PREEMPT_TRACER - bool "Preemption-off Latency Tracer" - default n - depends on !ARCH_USES_GETTIMEOFFSET - depends on PREEMPT - select GENERIC_TRACER - select TRACER_MAX_TRACE - select RING_BUFFER_ALLOW_SWAP - select TRACER_SNAPSHOT - select TRACER_SNAPSHOT_PER_CPU_SWAP - help - This option measures the time spent in preemption-off critical - sections, with microsecond accuracy. - - The default measurement method is a maximum search, which is - disabled by default and can be runtime (re-)started - via: - - echo 0 > /sys/kernel/debug/tracing/tracing_max_latency - - (Note that kernel size and overhead increase with this option - enabled. This option and the irqs-off timing option can be - used together or separately.) - -config SCHED_TRACER - bool "Scheduling Latency Tracer" - select GENERIC_TRACER - select CONTEXT_SWITCH_TRACER - select TRACER_MAX_TRACE - select TRACER_SNAPSHOT - help - This tracer tracks the latency of the highest priority task - to be scheduled in, starting from the point it has woken up. - -config HWLAT_TRACER - bool "Tracer to detect hardware latencies (like SMIs)" - select GENERIC_TRACER - help - This tracer, when enabled will create one or more kernel threads, - depening on what the cpumask file is set to, which each thread - spinning in a loop looking for interruptions caused by - something other than the kernel. For example, if a - System Management Interrupt (SMI) takes a noticeable amount of - time, this tracer will detect it. This is useful for testing - if a system is reliable for Real Time tasks. - - Some files are created in the tracing directory when this - is enabled: - - hwlat_detector/width - time in usecs for how long to spin for - hwlat_detector/window - time in usecs between the start of each - iteration - - A kernel thread is created that will spin with interrupts disabled - for "width" microseconds in every "widow" cycle. It will not spin - for "window - width" microseconds, where the system can - continue to operate. - - The output will appear in the trace and trace_pipe files. - - When the tracer is not running, it has no affect on the system, - but when it is running, it can cause the system to be - periodically non responsive. Do not run this tracer on a - production system. - - To enable this tracer, echo in "hwlat" into the current_tracer - file. Every time a latency is greater than tracing_thresh, it will - be recorded into the ring buffer. - -config ENABLE_DEFAULT_TRACERS - bool "Trace process context switches and events" - depends on !GENERIC_TRACER - select TRACING - help - This tracer hooks to various trace points in the kernel, - allowing the user to pick and choose which trace point they - want to trace. It also includes the sched_switch tracer plugin. - -config FTRACE_SYSCALLS - bool "Trace syscalls" - depends on HAVE_SYSCALL_TRACEPOINTS - select GENERIC_TRACER - select KALLSYMS - help - Basic tracer to catch the syscall entry and exit events. - -config TRACER_SNAPSHOT - bool "Create a snapshot trace buffer" - select TRACER_MAX_TRACE - help - Allow tracing users to take snapshot of the current buffer using the - ftrace interface, e.g.: - - echo 1 > /sys/kernel/debug/tracing/snapshot - cat snapshot - -config TRACER_SNAPSHOT_PER_CPU_SWAP - bool "Allow snapshot to swap per CPU" - depends on TRACER_SNAPSHOT - select RING_BUFFER_ALLOW_SWAP - help - Allow doing a snapshot of a single CPU buffer instead of a - full swap (all buffers). If this is set, then the following is - allowed: - - echo 1 > /sys/kernel/debug/tracing/per_cpu/cpu2/snapshot - - After which, only the tracing buffer for CPU 2 was swapped with - the main tracing buffer, and the other CPU buffers remain the same. - - When this is enabled, this adds a little more overhead to the - trace recording, as it needs to add some checks to synchronize - recording with swaps. But this does not affect the performance - of the overall system. This is enabled by default when the preempt - or irq latency tracers are enabled, as those need to swap as well - and already adds the overhead (plus a lot more). - -config TRACE_BRANCH_PROFILING - bool - select GENERIC_TRACER - -choice - prompt "Branch Profiling" - default BRANCH_PROFILE_NONE - help - The branch profiling is a software profiler. It will add hooks - into the C conditionals to test which path a branch takes. - - The likely/unlikely profiler only looks at the conditions that - are annotated with a likely or unlikely macro. - - The "all branch" profiler will profile every if-statement in the - kernel. This profiler will also enable the likely/unlikely - profiler. - - Either of the above profilers adds a bit of overhead to the system. - If unsure, choose "No branch profiling". - -config BRANCH_PROFILE_NONE - bool "No branch profiling" - help - No branch profiling. Branch profiling adds a bit of overhead. - Only enable it if you want to analyse the branching behavior. - Otherwise keep it disabled. - -config PROFILE_ANNOTATED_BRANCHES - bool "Trace likely/unlikely profiler" - select TRACE_BRANCH_PROFILING - help - This tracer profiles all likely and unlikely macros - in the kernel. It will display the results in: - - /sys/kernel/debug/tracing/trace_stat/branch_annotated - - Note: this will add a significant overhead; only turn this - on if you need to profile the system's use of these macros. - -config PROFILE_ALL_BRANCHES - bool "Profile all if conditionals" - select TRACE_BRANCH_PROFILING - help - This tracer profiles all branch conditions. Every if () - taken in the kernel is recorded whether it hit or miss. - The results will be displayed in: - - /sys/kernel/debug/tracing/trace_stat/branch_all - - This option also enables the likely/unlikely profiler. - - This configuration, when enabled, will impose a great overhead - on the system. This should only be enabled when the system - is to be analyzed in much detail. -endchoice - -config TRACING_BRANCHES - bool - help - Selected by tracers that will trace the likely and unlikely - conditions. This prevents the tracers themselves from being - profiled. Profiling the tracing infrastructure can only happen - when the likelys and unlikelys are not being traced. - -config BRANCH_TRACER - bool "Trace likely/unlikely instances" - depends on TRACE_BRANCH_PROFILING - select TRACING_BRANCHES - help - This traces the events of likely and unlikely condition - calls in the kernel. The difference between this and the - "Trace likely/unlikely profiler" is that this is not a - histogram of the callers, but actually places the calling - events into a running trace buffer to see when and where the - events happened, as well as their results. - - Say N if unsure. - -config STACK_TRACER - bool "Trace max stack" - depends on HAVE_FUNCTION_TRACER - select FUNCTION_TRACER - select STACKTRACE - select KALLSYMS - help - This special tracer records the maximum stack footprint of the - kernel and displays it in /sys/kernel/debug/tracing/stack_trace. - - This tracer works by hooking into every function call that the - kernel executes, and keeping a maximum stack depth value and - stack-trace saved. If this is configured with DYNAMIC_FTRACE - then it will not have any overhead while the stack tracer - is disabled. - - To enable the stack tracer on bootup, pass in 'stacktrace' - on the kernel command line. - - The stack tracer can also be enabled or disabled via the - sysctl kernel.stack_tracer_enabled - - Say N if unsure. - -config BLK_DEV_IO_TRACE - bool "Support for tracing block IO actions" - depends on SYSFS - depends on BLOCK - select RELAY - select DEBUG_FS - select TRACEPOINTS - select GENERIC_TRACER - select STACKTRACE - help - Say Y here if you want to be able to trace the block layer actions - on a given queue. Tracing allows you to see any traffic happening - on a block device queue. For more information (and the userspace - support tools needed), fetch the blktrace tools from: - - git://git.kernel.dk/blktrace.git - - Tracing also is possible using the ftrace interface, e.g.: - - echo 1 > /sys/block/sda/sda1/trace/enable - echo blk > /sys/kernel/debug/tracing/current_tracer - cat /sys/kernel/debug/tracing/trace_pipe - - If unsure, say N. - -config KPROBE_EVENT - depends on KPROBES - depends on HAVE_REGS_AND_STACK_ACCESS_API - bool "Enable kprobes-based dynamic events" - select TRACING - select PROBE_EVENTS - default y - help - This allows the user to add tracing events (similar to tracepoints) - on the fly via the ftrace interface. See - Documentation/trace/kprobetrace.txt for more details. - - Those events can be inserted wherever kprobes can probe, and record - various register and memory values. - - This option is also required by perf-probe subcommand of perf tools. - If you want to use perf tools, this option is strongly recommended. - -config UPROBE_EVENT - bool "Enable uprobes-based dynamic events" - depends on ARCH_SUPPORTS_UPROBES - depends on MMU - depends on PERF_EVENTS - select UPROBES - select PROBE_EVENTS - select TRACING - default n - help - This allows the user to add tracing events on top of userspace - dynamic events (similar to tracepoints) on the fly via the trace - events interface. Those events can be inserted wherever uprobes - can probe, and record various registers. - This option is required if you plan to use perf-probe subcommand - of perf tools on user space applications. - -config BPF_EVENTS - depends on BPF_SYSCALL - depends on (KPROBE_EVENT || UPROBE_EVENT) && PERF_EVENTS - bool - default y - help - This allows the user to attach BPF programs to kprobe events. - -config PROBE_EVENTS - def_bool n - -config DYNAMIC_FTRACE - bool "enable/disable function tracing dynamically" - depends on FUNCTION_TRACER - depends on HAVE_DYNAMIC_FTRACE - default y - help - This option will modify all the calls to function tracing - dynamically (will patch them out of the binary image and - replace them with a No-Op instruction) on boot up. During - compile time, a table is made of all the locations that ftrace - can function trace, and this table is linked into the kernel - image. When this is enabled, functions can be individually - enabled, and the functions not enabled will not affect - performance of the system. - - See the files in /sys/kernel/debug/tracing: - available_filter_functions - set_ftrace_filter - set_ftrace_notrace - - This way a CONFIG_FUNCTION_TRACER kernel is slightly larger, but - otherwise has native performance as long as no tracing is active. - -config DYNAMIC_FTRACE_WITH_REGS - def_bool y - depends on DYNAMIC_FTRACE - depends on HAVE_DYNAMIC_FTRACE_WITH_REGS - -config FUNCTION_PROFILER - bool "Kernel function profiler" - depends on FUNCTION_TRACER - default n - help - This option enables the kernel function profiler. A file is created - in debugfs called function_profile_enabled which defaults to zero. - When a 1 is echoed into this file profiling begins, and when a - zero is entered, profiling stops. A "functions" file is created in - the trace_stats directory; this file shows the list of functions that - have been hit and their counters. - - If in doubt, say N. - -config FTRACE_MCOUNT_RECORD - def_bool y - depends on DYNAMIC_FTRACE - depends on HAVE_FTRACE_MCOUNT_RECORD - -config FTRACE_SELFTEST - bool - -config FTRACE_STARTUP_TEST - bool "Perform a startup test on ftrace" - depends on GENERIC_TRACER - select FTRACE_SELFTEST - help - This option performs a series of startup tests on ftrace. On bootup - a series of tests are made to verify that the tracer is - functioning properly. It will do tests on all the configured - tracers of ftrace. - -config EVENT_TRACE_TEST_SYSCALLS - bool "Run selftest on syscall events" - depends on FTRACE_STARTUP_TEST - help - This option will also enable testing every syscall event. - It only enables the event and disables it and runs various loads - with the event enabled. This adds a bit more time for kernel boot - up since it runs this on every system call defined. - - TBD - enable a way to actually call the syscalls as we test their - events - -config MMIOTRACE - bool "Memory mapped IO tracing" - depends on HAVE_MMIOTRACE_SUPPORT && PCI - select GENERIC_TRACER - help - Mmiotrace traces Memory Mapped I/O access and is meant for - debugging and reverse engineering. It is called from the ioremap - implementation and works via page faults. Tracing is disabled by - default and can be enabled at run-time. - - See Documentation/trace/mmiotrace.txt. - If you are not helping to develop drivers, say N. - -config TRACING_MAP - bool - depends on ARCH_HAVE_NMI_SAFE_CMPXCHG - help - tracing_map is a special-purpose lock-free map for tracing, - separated out as a stand-alone facility in order to allow it - to be shared between multiple tracers. It isn't meant to be - generally used outside of that context, and is normally - selected by tracers that use it. - -config HIST_TRIGGERS - bool "Histogram triggers" - depends on ARCH_HAVE_NMI_SAFE_CMPXCHG - select TRACING_MAP - select TRACING - default n - help - Hist triggers allow one or more arbitrary trace event fields - to be aggregated into hash tables and dumped to stdout by - reading a debugfs/tracefs file. They're useful for - gathering quick and dirty (though precise) summaries of - event activity as an initial guide for further investigation - using more advanced tools. - - See Documentation/trace/events.txt. - If in doubt, say N. - -config MMIOTRACE_TEST - tristate "Test module for mmiotrace" - depends on MMIOTRACE && m - help - This is a dumb module for testing mmiotrace. It is very dangerous - as it will write garbage to IO memory starting at a given address. - However, it should be safe to use on e.g. unused portion of VRAM. - - Say N, unless you absolutely know what you are doing. - -config TRACEPOINT_BENCHMARK - bool "Add tracepoint that benchmarks tracepoints" - help - This option creates the tracepoint "benchmark:benchmark_event". - When the tracepoint is enabled, it kicks off a kernel thread that - goes into an infinite loop (calling cond_sched() to let other tasks - run), and calls the tracepoint. Each iteration will record the time - it took to write to the tracepoint and the next iteration that - data will be passed to the tracepoint itself. That is, the tracepoint - will report the time it took to do the previous tracepoint. - The string written to the tracepoint is a static string of 128 bytes - to keep the time the same. The initial string is simply a write of - "START". The second string records the cold cache time of the first - write which is not added to the rest of the calculations. - - As it is a tight loop, it benchmarks as hot cache. That's fine because - we care most about hot paths that are probably in cache already. - - An example of the output: - - START - first=3672 [COLD CACHED] - last=632 first=3672 max=632 min=632 avg=316 std=446 std^2=199712 - last=278 first=3672 max=632 min=278 avg=303 std=316 std^2=100337 - last=277 first=3672 max=632 min=277 avg=296 std=258 std^2=67064 - last=273 first=3672 max=632 min=273 avg=292 std=224 std^2=50411 - last=273 first=3672 max=632 min=273 avg=288 std=200 std^2=40389 - last=281 first=3672 max=632 min=273 avg=287 std=183 std^2=33666 - - -config RING_BUFFER_BENCHMARK - tristate "Ring buffer benchmark stress tester" - depends on RING_BUFFER - help - This option creates a test to stress the ring buffer and benchmark it. - It creates its own ring buffer such that it will not interfere with - any other users of the ring buffer (such as ftrace). It then creates - a producer and consumer that will run for 10 seconds and sleep for - 10 seconds. Each interval it will print out the number of events - it recorded and give a rough estimate of how long each iteration took. - - It does not disable interrupts or raise its priority, so it may be - affected by processes that are running. - - If unsure, say N. - -config RING_BUFFER_STARTUP_TEST - bool "Ring buffer startup self test" - depends on RING_BUFFER - help - Run a simple self test on the ring buffer on boot up. Late in the - kernel boot sequence, the test will start that kicks off - a thread per cpu. Each thread will write various size events - into the ring buffer. Another thread is created to send IPIs - to each of the threads, where the IPI handler will also write - to the ring buffer, to test/stress the nesting ability. - If any anomalies are discovered, a warning will be displayed - and all ring buffers will be disabled. - - The test runs for 10 seconds. This will slow your boot time - by at least 10 more seconds. - - At the end of the test, statics and more checks are done. - It will output the stats of each per cpu buffer. What - was written, the sizes, what was read, what was lost, and - other similar details. - - If unsure, say N - -config TRACE_ENUM_MAP_FILE - bool "Show enum mappings for trace events" - depends on TRACING - help - The "print fmt" of the trace events will show the enum names instead - of their values. This can cause problems for user space tools that - use this string to parse the raw data as user space does not know - how to convert the string to its value. - - To fix this, there's a special macro in the kernel that can be used - to convert the enum into its value. If this macro is used, then the - print fmt strings will have the enums converted to their values. - - If something does not get converted properly, this option can be - used to show what enums the kernel tried to convert. - - This option is for debugging the enum conversions. A file is created - in the tracing directory called "enum_map" that will show the enum - names matched with their values and what trace event system they - belong too. - - Normally, the mapping of the strings to values will be freed after - boot up or module load. With this option, they will not be freed, as - they are needed for the "enum_map" file. Enabling this option will - increase the memory footprint of the running kernel. - - If unsure, say N - -config TRACING_EVENTS_GPIO - bool "Trace gpio events" - depends on GPIOLIB - default y - help - Enable tracing events for gpio subsystem - -endif # FTRACE - -endif # TRACING_SUPPORT - diff --git a/src/linux/kernel/ucount.c b/src/linux/kernel/ucount.c deleted file mode 100644 index 9d20d5d..0000000 --- a/src/linux/kernel/ucount.c +++ /dev/null @@ -1,235 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - */ - -#include -#include -#include -#include -#include - -#define UCOUNTS_HASHTABLE_BITS 10 -static struct hlist_head ucounts_hashtable[(1 << UCOUNTS_HASHTABLE_BITS)]; -static DEFINE_SPINLOCK(ucounts_lock); - -#define ucounts_hashfn(ns, uid) \ - hash_long((unsigned long)__kuid_val(uid) + (unsigned long)(ns), \ - UCOUNTS_HASHTABLE_BITS) -#define ucounts_hashentry(ns, uid) \ - (ucounts_hashtable + ucounts_hashfn(ns, uid)) - - -#ifdef CONFIG_SYSCTL -static struct ctl_table_set * -set_lookup(struct ctl_table_root *root) -{ - return ¤t_user_ns()->set; -} - -static int set_is_seen(struct ctl_table_set *set) -{ - return ¤t_user_ns()->set == set; -} - -static int set_permissions(struct ctl_table_header *head, - struct ctl_table *table) -{ - struct user_namespace *user_ns = - container_of(head->set, struct user_namespace, set); - int mode; - - /* Allow users with CAP_SYS_RESOURCE unrestrained access */ - if (ns_capable(user_ns, CAP_SYS_RESOURCE)) - mode = (table->mode & S_IRWXU) >> 6; - else - /* Allow all others at most read-only access */ - mode = table->mode & S_IROTH; - return (mode << 6) | (mode << 3) | mode; -} - -static struct ctl_table_root set_root = { - .lookup = set_lookup, - .permissions = set_permissions, -}; - -static int zero = 0; -static int int_max = INT_MAX; -#define UCOUNT_ENTRY(name) \ - { \ - .procname = name, \ - .maxlen = sizeof(int), \ - .mode = 0644, \ - .proc_handler = proc_dointvec_minmax, \ - .extra1 = &zero, \ - .extra2 = &int_max, \ - } -static struct ctl_table user_table[] = { - UCOUNT_ENTRY("max_user_namespaces"), - UCOUNT_ENTRY("max_pid_namespaces"), - UCOUNT_ENTRY("max_uts_namespaces"), - UCOUNT_ENTRY("max_ipc_namespaces"), - UCOUNT_ENTRY("max_net_namespaces"), - UCOUNT_ENTRY("max_mnt_namespaces"), - UCOUNT_ENTRY("max_cgroup_namespaces"), - { } -}; -#endif /* CONFIG_SYSCTL */ - -bool setup_userns_sysctls(struct user_namespace *ns) -{ -#ifdef CONFIG_SYSCTL - struct ctl_table *tbl; - setup_sysctl_set(&ns->set, &set_root, set_is_seen); - tbl = kmemdup(user_table, sizeof(user_table), GFP_KERNEL); - if (tbl) { - int i; - for (i = 0; i < UCOUNT_COUNTS; i++) { - tbl[i].data = &ns->ucount_max[i]; - } - ns->sysctls = __register_sysctl_table(&ns->set, "user", tbl); - } - if (!ns->sysctls) { - kfree(tbl); - retire_sysctl_set(&ns->set); - return false; - } -#endif - return true; -} - -void retire_userns_sysctls(struct user_namespace *ns) -{ -#ifdef CONFIG_SYSCTL - struct ctl_table *tbl; - - tbl = ns->sysctls->ctl_table_arg; - unregister_sysctl_table(ns->sysctls); - retire_sysctl_set(&ns->set); - kfree(tbl); -#endif -} - -static struct ucounts *find_ucounts(struct user_namespace *ns, kuid_t uid, struct hlist_head *hashent) -{ - struct ucounts *ucounts; - - hlist_for_each_entry(ucounts, hashent, node) { - if (uid_eq(ucounts->uid, uid) && (ucounts->ns == ns)) - return ucounts; - } - return NULL; -} - -static struct ucounts *get_ucounts(struct user_namespace *ns, kuid_t uid) -{ - struct hlist_head *hashent = ucounts_hashentry(ns, uid); - struct ucounts *ucounts, *new; - - spin_lock(&ucounts_lock); - ucounts = find_ucounts(ns, uid, hashent); - if (!ucounts) { - spin_unlock(&ucounts_lock); - - new = kzalloc(sizeof(*new), GFP_KERNEL); - if (!new) - return NULL; - - new->ns = ns; - new->uid = uid; - atomic_set(&new->count, 0); - - spin_lock(&ucounts_lock); - ucounts = find_ucounts(ns, uid, hashent); - if (ucounts) { - kfree(new); - } else { - hlist_add_head(&new->node, hashent); - ucounts = new; - } - } - if (!atomic_add_unless(&ucounts->count, 1, INT_MAX)) - ucounts = NULL; - spin_unlock(&ucounts_lock); - return ucounts; -} - -static void put_ucounts(struct ucounts *ucounts) -{ - if (atomic_dec_and_test(&ucounts->count)) { - spin_lock(&ucounts_lock); - hlist_del_init(&ucounts->node); - spin_unlock(&ucounts_lock); - - kfree(ucounts); - } -} - -static inline bool atomic_inc_below(atomic_t *v, int u) -{ - int c, old; - c = atomic_read(v); - for (;;) { - if (unlikely(c >= u)) - return false; - old = atomic_cmpxchg(v, c, c+1); - if (likely(old == c)) - return true; - c = old; - } -} - -struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid, - enum ucount_type type) -{ - struct ucounts *ucounts, *iter, *bad; - struct user_namespace *tns; - ucounts = get_ucounts(ns, uid); - for (iter = ucounts; iter; iter = tns->ucounts) { - int max; - tns = iter->ns; - max = READ_ONCE(tns->ucount_max[type]); - if (!atomic_inc_below(&iter->ucount[type], max)) - goto fail; - } - return ucounts; -fail: - bad = iter; - for (iter = ucounts; iter != bad; iter = iter->ns->ucounts) - atomic_dec(&iter->ucount[type]); - - put_ucounts(ucounts); - return NULL; -} - -void dec_ucount(struct ucounts *ucounts, enum ucount_type type) -{ - struct ucounts *iter; - for (iter = ucounts; iter; iter = iter->ns->ucounts) { - int dec = atomic_dec_if_positive(&iter->ucount[type]); - WARN_ON_ONCE(dec < 0); - } - put_ucounts(ucounts); -} - -static __init int user_namespace_sysctl_init(void) -{ -#ifdef CONFIG_SYSCTL - static struct ctl_table_header *user_header; - static struct ctl_table empty[1]; - /* - * It is necessary to register the user directory in the - * default set so that registrations in the child sets work - * properly. - */ - user_header = register_sysctl("user", empty); - BUG_ON(!user_header); - BUG_ON(!setup_userns_sysctls(&init_user_ns)); -#endif - return 0; -} -subsys_initcall(user_namespace_sysctl_init); - - diff --git a/src/linux/kernel/up.c b/src/linux/kernel/up.c deleted file mode 100644 index ee81ac9..0000000 --- a/src/linux/kernel/up.c +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Uniprocessor-only support functions. The counterpart to kernel/smp.c - */ - -#include -#include -#include -#include -#include - -int smp_call_function_single(int cpu, void (*func) (void *info), void *info, - int wait) -{ - unsigned long flags; - - WARN_ON(cpu != 0); - - local_irq_save(flags); - func(info); - local_irq_restore(flags); - - return 0; -} -EXPORT_SYMBOL(smp_call_function_single); - -int smp_call_function_single_async(int cpu, struct call_single_data *csd) -{ - unsigned long flags; - - local_irq_save(flags); - csd->func(csd->info); - local_irq_restore(flags); - return 0; -} -EXPORT_SYMBOL(smp_call_function_single_async); - -int on_each_cpu(smp_call_func_t func, void *info, int wait) -{ - unsigned long flags; - - local_irq_save(flags); - func(info); - local_irq_restore(flags); - return 0; -} -EXPORT_SYMBOL(on_each_cpu); - -/* - * Note we still need to test the mask even for UP - * because we actually can get an empty mask from - * code that on SMP might call us without the local - * CPU in the mask. - */ -void on_each_cpu_mask(const struct cpumask *mask, - smp_call_func_t func, void *info, bool wait) -{ - unsigned long flags; - - if (cpumask_test_cpu(0, mask)) { - local_irq_save(flags); - func(info); - local_irq_restore(flags); - } -} -EXPORT_SYMBOL(on_each_cpu_mask); - -/* - * Preemption is disabled here to make sure the cond_func is called under the - * same condtions in UP and SMP. - */ -void on_each_cpu_cond(bool (*cond_func)(int cpu, void *info), - smp_call_func_t func, void *info, bool wait, - gfp_t gfp_flags) -{ - unsigned long flags; - - preempt_disable(); - if (cond_func(0, info)) { - local_irq_save(flags); - func(info); - local_irq_restore(flags); - } - preempt_enable(); -} -EXPORT_SYMBOL(on_each_cpu_cond); - -int smp_call_on_cpu(unsigned int cpu, int (*func)(void *), void *par, bool phys) -{ - int ret; - - if (cpu != 0) - return -ENXIO; - - if (phys) - hypervisor_pin_vcpu(0); - ret = func(par); - if (phys) - hypervisor_pin_vcpu(-1); - - return ret; -} -EXPORT_SYMBOL_GPL(smp_call_on_cpu); diff --git a/src/linux/kernel/user.c b/src/linux/kernel/user.c deleted file mode 100644 index b069ccb..0000000 --- a/src/linux/kernel/user.c +++ /dev/null @@ -1,228 +0,0 @@ -/* - * The "user cache". - * - * (C) Copyright 1991-2000 Linus Torvalds - * - * We have a per-user structure to keep track of how many - * processes, files etc the user has claimed, in order to be - * able to have per-user limits for system resources. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * userns count is 1 for root user, 1 for init_uts_ns, - * and 1 for... ? - */ -struct user_namespace init_user_ns = { - .uid_map = { - .nr_extents = 1, - .extent[0] = { - .first = 0, - .lower_first = 0, - .count = 4294967295U, - }, - }, - .gid_map = { - .nr_extents = 1, - .extent[0] = { - .first = 0, - .lower_first = 0, - .count = 4294967295U, - }, - }, - .projid_map = { - .nr_extents = 1, - .extent[0] = { - .first = 0, - .lower_first = 0, - .count = 4294967295U, - }, - }, - .count = ATOMIC_INIT(3), - .owner = GLOBAL_ROOT_UID, - .group = GLOBAL_ROOT_GID, - .ns.inum = PROC_USER_INIT_INO, -#ifdef CONFIG_USER_NS - .ns.ops = &userns_operations, -#endif - .flags = USERNS_INIT_FLAGS, -#ifdef CONFIG_PERSISTENT_KEYRINGS - .persistent_keyring_register_sem = - __RWSEM_INITIALIZER(init_user_ns.persistent_keyring_register_sem), -#endif -}; -EXPORT_SYMBOL_GPL(init_user_ns); - -/* - * UID task count cache, to get fast user lookup in "alloc_uid" - * when changing user ID's (ie setuid() and friends). - */ - -#define UIDHASH_BITS (CONFIG_BASE_SMALL ? 3 : 7) -#define UIDHASH_SZ (1 << UIDHASH_BITS) -#define UIDHASH_MASK (UIDHASH_SZ - 1) -#define __uidhashfn(uid) (((uid >> UIDHASH_BITS) + uid) & UIDHASH_MASK) -#define uidhashentry(uid) (uidhash_table + __uidhashfn((__kuid_val(uid)))) - -static struct kmem_cache *uid_cachep; -struct hlist_head uidhash_table[UIDHASH_SZ]; - -/* - * The uidhash_lock is mostly taken from process context, but it is - * occasionally also taken from softirq/tasklet context, when - * task-structs get RCU-freed. Hence all locking must be softirq-safe. - * But free_uid() is also called with local interrupts disabled, and running - * local_bh_enable() with local interrupts disabled is an error - we'll run - * softirq callbacks, and they can unconditionally enable interrupts, and - * the caller of free_uid() didn't expect that.. - */ -static DEFINE_SPINLOCK(uidhash_lock); - -/* root_user.__count is 1, for init task cred */ -struct user_struct root_user = { - .__count = ATOMIC_INIT(1), - .processes = ATOMIC_INIT(1), - .sigpending = ATOMIC_INIT(0), - .locked_shm = 0, - .uid = GLOBAL_ROOT_UID, -}; - -/* - * These routines must be called with the uidhash spinlock held! - */ -static void uid_hash_insert(struct user_struct *up, struct hlist_head *hashent) -{ - hlist_add_head(&up->uidhash_node, hashent); -} - -static void uid_hash_remove(struct user_struct *up) -{ - hlist_del_init(&up->uidhash_node); -} - -static struct user_struct *uid_hash_find(kuid_t uid, struct hlist_head *hashent) -{ - struct user_struct *user; - - hlist_for_each_entry(user, hashent, uidhash_node) { - if (uid_eq(user->uid, uid)) { - atomic_inc(&user->__count); - return user; - } - } - - return NULL; -} - -/* IRQs are disabled and uidhash_lock is held upon function entry. - * IRQ state (as stored in flags) is restored and uidhash_lock released - * upon function exit. - */ -static void free_user(struct user_struct *up, unsigned long flags) - __releases(&uidhash_lock) -{ - uid_hash_remove(up); - spin_unlock_irqrestore(&uidhash_lock, flags); - key_put(up->uid_keyring); - key_put(up->session_keyring); - kmem_cache_free(uid_cachep, up); -} - -/* - * Locate the user_struct for the passed UID. If found, take a ref on it. The - * caller must undo that ref with free_uid(). - * - * If the user_struct could not be found, return NULL. - */ -struct user_struct *find_user(kuid_t uid) -{ - struct user_struct *ret; - unsigned long flags; - - spin_lock_irqsave(&uidhash_lock, flags); - ret = uid_hash_find(uid, uidhashentry(uid)); - spin_unlock_irqrestore(&uidhash_lock, flags); - return ret; -} - -void free_uid(struct user_struct *up) -{ - unsigned long flags; - - if (!up) - return; - - local_irq_save(flags); - if (atomic_dec_and_lock(&up->__count, &uidhash_lock)) - free_user(up, flags); - else - local_irq_restore(flags); -} - -struct user_struct *alloc_uid(kuid_t uid) -{ - struct hlist_head *hashent = uidhashentry(uid); - struct user_struct *up, *new; - - spin_lock_irq(&uidhash_lock); - up = uid_hash_find(uid, hashent); - spin_unlock_irq(&uidhash_lock); - - if (!up) { - new = kmem_cache_zalloc(uid_cachep, GFP_KERNEL); - if (!new) - goto out_unlock; - - new->uid = uid; - atomic_set(&new->__count, 1); - - /* - * Before adding this, check whether we raced - * on adding the same user already.. - */ - spin_lock_irq(&uidhash_lock); - up = uid_hash_find(uid, hashent); - if (up) { - key_put(new->uid_keyring); - key_put(new->session_keyring); - kmem_cache_free(uid_cachep, new); - } else { - uid_hash_insert(new, hashent); - up = new; - } - spin_unlock_irq(&uidhash_lock); - } - - return up; - -out_unlock: - return NULL; -} - -static int __init uid_cache_init(void) -{ - int n; - - uid_cachep = kmem_cache_create("uid_cache", sizeof(struct user_struct), - 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); - - for(n = 0; n < UIDHASH_SZ; ++n) - INIT_HLIST_HEAD(uidhash_table + n); - - /* Insert the root user immediately (init already runs as root) */ - spin_lock_irq(&uidhash_lock); - uid_hash_insert(&root_user, uidhashentry(GLOBAL_ROOT_UID)); - spin_unlock_irq(&uidhash_lock); - - return 0; -} -subsys_initcall(uid_cache_init); diff --git a/src/linux/kernel/utsname_sysctl.c b/src/linux/kernel/utsname_sysctl.c deleted file mode 100644 index c8eac43..0000000 --- a/src/linux/kernel/utsname_sysctl.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2007 - * - * Author: Eric Biederman - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation, version 2 of the - * License. - */ - -#include -#include -#include -#include -#include - -#ifdef CONFIG_PROC_SYSCTL - -static void *get_uts(struct ctl_table *table, int write) -{ - char *which = table->data; - struct uts_namespace *uts_ns; - - uts_ns = current->nsproxy->uts_ns; - which = (which - (char *)&init_uts_ns) + (char *)uts_ns; - - if (!write) - down_read(&uts_sem); - else - down_write(&uts_sem); - return which; -} - -static void put_uts(struct ctl_table *table, int write, void *which) -{ - if (!write) - up_read(&uts_sem); - else - up_write(&uts_sem); -} - -/* - * Special case of dostring for the UTS structure. This has locks - * to observe. Should this be in kernel/sys.c ???? - */ -static int proc_do_uts_string(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - struct ctl_table uts_table; - int r; - memcpy(&uts_table, table, sizeof(uts_table)); - uts_table.data = get_uts(table, write); - r = proc_dostring(&uts_table, write, buffer, lenp, ppos); - put_uts(table, write, uts_table.data); - - if (write) - proc_sys_poll_notify(table->poll); - - return r; -} -#else -#define proc_do_uts_string NULL -#endif - -static DEFINE_CTL_TABLE_POLL(hostname_poll); -static DEFINE_CTL_TABLE_POLL(domainname_poll); - -static struct ctl_table uts_kern_table[] = { - { - .procname = "ostype", - .data = init_uts_ns.name.sysname, - .maxlen = sizeof(init_uts_ns.name.sysname), - .mode = 0444, - .proc_handler = proc_do_uts_string, - }, - { - .procname = "osrelease", - .data = init_uts_ns.name.release, - .maxlen = sizeof(init_uts_ns.name.release), - .mode = 0444, - .proc_handler = proc_do_uts_string, - }, - { - .procname = "version", - .data = init_uts_ns.name.version, - .maxlen = sizeof(init_uts_ns.name.version), - .mode = 0444, - .proc_handler = proc_do_uts_string, - }, - { - .procname = "hostname", - .data = init_uts_ns.name.nodename, - .maxlen = sizeof(init_uts_ns.name.nodename), - .mode = 0644, - .proc_handler = proc_do_uts_string, - .poll = &hostname_poll, - }, - { - .procname = "domainname", - .data = init_uts_ns.name.domainname, - .maxlen = sizeof(init_uts_ns.name.domainname), - .mode = 0644, - .proc_handler = proc_do_uts_string, - .poll = &domainname_poll, - }, - {} -}; - -static struct ctl_table uts_root_table[] = { - { - .procname = "kernel", - .mode = 0555, - .child = uts_kern_table, - }, - {} -}; - -#ifdef CONFIG_PROC_SYSCTL -/* - * Notify userspace about a change in a certain entry of uts_kern_table, - * identified by the parameter proc. - */ -void uts_proc_notify(enum uts_proc proc) -{ - struct ctl_table *table = &uts_kern_table[proc]; - - proc_sys_poll_notify(table->poll); -} -#endif - -static int __init utsname_sysctl_init(void) -{ - register_sysctl_table(uts_root_table); - return 0; -} - -device_initcall(utsname_sysctl_init); diff --git a/src/linux/kernel/workqueue.c b/src/linux/kernel/workqueue.c deleted file mode 100644 index 479d840..0000000 --- a/src/linux/kernel/workqueue.c +++ /dev/null @@ -1,5553 +0,0 @@ -/* - * kernel/workqueue.c - generic async execution with shared worker pool - * - * Copyright (C) 2002 Ingo Molnar - * - * Derived from the taskqueue/keventd code by: - * David Woodhouse - * Andrew Morton - * Kai Petzke - * Theodore Ts'o - * - * Made to use alloc_percpu by Christoph Lameter. - * - * Copyright (C) 2010 SUSE Linux Products GmbH - * Copyright (C) 2010 Tejun Heo - * - * This is the generic async execution mechanism. Work items as are - * executed in process context. The worker pool is shared and - * automatically managed. There are two worker pools for each CPU (one for - * normal work items and the other for high priority ones) and some extra - * pools for workqueues which are not bound to any specific CPU - the - * number of these backing pools is dynamic. - * - * Please read Documentation/workqueue.txt for details. - */ - -#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 "workqueue_internal.h" - -enum { - /* - * worker_pool flags - * - * A bound pool is either associated or disassociated with its CPU. - * While associated (!DISASSOCIATED), all workers are bound to the - * CPU and none has %WORKER_UNBOUND set and concurrency management - * is in effect. - * - * While DISASSOCIATED, the cpu may be offline and all workers have - * %WORKER_UNBOUND set and concurrency management disabled, and may - * be executing on any CPU. The pool behaves as an unbound one. - * - * Note that DISASSOCIATED should be flipped only while holding - * attach_mutex to avoid changing binding state while - * worker_attach_to_pool() is in progress. - */ - POOL_DISASSOCIATED = 1 << 2, /* cpu can't serve workers */ - - /* worker flags */ - WORKER_DIE = 1 << 1, /* die die die */ - WORKER_IDLE = 1 << 2, /* is idle */ - WORKER_PREP = 1 << 3, /* preparing to run works */ - WORKER_CPU_INTENSIVE = 1 << 6, /* cpu intensive */ - WORKER_UNBOUND = 1 << 7, /* worker is unbound */ - WORKER_REBOUND = 1 << 8, /* worker was rebound */ - - WORKER_NOT_RUNNING = WORKER_PREP | WORKER_CPU_INTENSIVE | - WORKER_UNBOUND | WORKER_REBOUND, - - NR_STD_WORKER_POOLS = 2, /* # standard pools per cpu */ - - UNBOUND_POOL_HASH_ORDER = 6, /* hashed by pool->attrs */ - BUSY_WORKER_HASH_ORDER = 6, /* 64 pointers */ - - MAX_IDLE_WORKERS_RATIO = 4, /* 1/4 of busy can be idle */ - IDLE_WORKER_TIMEOUT = 300 * HZ, /* keep idle ones for 5 mins */ - - MAYDAY_INITIAL_TIMEOUT = HZ / 100 >= 2 ? HZ / 100 : 2, - /* call for help after 10ms - (min two ticks) */ - MAYDAY_INTERVAL = HZ / 10, /* and then every 100ms */ - CREATE_COOLDOWN = HZ, /* time to breath after fail */ - - /* - * Rescue workers are used only on emergencies and shared by - * all cpus. Give MIN_NICE. - */ - RESCUER_NICE_LEVEL = MIN_NICE, - HIGHPRI_NICE_LEVEL = MIN_NICE, - - WQ_NAME_LEN = 24, -}; - -/* - * Structure fields follow one of the following exclusion rules. - * - * I: Modifiable by initialization/destruction paths and read-only for - * everyone else. - * - * P: Preemption protected. Disabling preemption is enough and should - * only be modified and accessed from the local cpu. - * - * L: pool->lock protected. Access with pool->lock held. - * - * X: During normal operation, modification requires pool->lock and should - * be done only from local cpu. Either disabling preemption on local - * cpu or grabbing pool->lock is enough for read access. If - * POOL_DISASSOCIATED is set, it's identical to L. - * - * A: pool->attach_mutex protected. - * - * PL: wq_pool_mutex protected. - * - * PR: wq_pool_mutex protected for writes. Sched-RCU protected for reads. - * - * PW: wq_pool_mutex and wq->mutex protected for writes. Either for reads. - * - * PWR: wq_pool_mutex and wq->mutex protected for writes. Either or - * sched-RCU for reads. - * - * WQ: wq->mutex protected. - * - * WR: wq->mutex protected for writes. Sched-RCU protected for reads. - * - * MD: wq_mayday_lock protected. - */ - -/* struct worker is defined in workqueue_internal.h */ - -struct worker_pool { - spinlock_t lock; /* the pool lock */ - int cpu; /* I: the associated cpu */ - int node; /* I: the associated node ID */ - int id; /* I: pool ID */ - unsigned int flags; /* X: flags */ - - unsigned long watchdog_ts; /* L: watchdog timestamp */ - - struct list_head worklist; /* L: list of pending works */ - int nr_workers; /* L: total number of workers */ - - /* nr_idle includes the ones off idle_list for rebinding */ - int nr_idle; /* L: currently idle ones */ - - struct list_head idle_list; /* X: list of idle workers */ - struct timer_list idle_timer; /* L: worker idle timeout */ - struct timer_list mayday_timer; /* L: SOS timer for workers */ - - /* a workers is either on busy_hash or idle_list, or the manager */ - DECLARE_HASHTABLE(busy_hash, BUSY_WORKER_HASH_ORDER); - /* L: hash of busy workers */ - - /* see manage_workers() for details on the two manager mutexes */ - struct mutex manager_arb; /* manager arbitration */ - struct worker *manager; /* L: purely informational */ - struct mutex attach_mutex; /* attach/detach exclusion */ - struct list_head workers; /* A: attached workers */ - struct completion *detach_completion; /* all workers detached */ - - struct ida worker_ida; /* worker IDs for task name */ - - struct workqueue_attrs *attrs; /* I: worker attributes */ - struct hlist_node hash_node; /* PL: unbound_pool_hash node */ - int refcnt; /* PL: refcnt for unbound pools */ - - /* - * The current concurrency level. As it's likely to be accessed - * from other CPUs during try_to_wake_up(), put it in a separate - * cacheline. - */ - atomic_t nr_running ____cacheline_aligned_in_smp; - - /* - * Destruction of pool is sched-RCU protected to allow dereferences - * from get_work_pool(). - */ - struct rcu_head rcu; -} ____cacheline_aligned_in_smp; - -/* - * The per-pool workqueue. While queued, the lower WORK_STRUCT_FLAG_BITS - * of work_struct->data are used for flags and the remaining high bits - * point to the pwq; thus, pwqs need to be aligned at two's power of the - * number of flag bits. - */ -struct pool_workqueue { - struct worker_pool *pool; /* I: the associated pool */ - struct workqueue_struct *wq; /* I: the owning workqueue */ - int work_color; /* L: current color */ - int flush_color; /* L: flushing color */ - int refcnt; /* L: reference count */ - int nr_in_flight[WORK_NR_COLORS]; - /* L: nr of in_flight works */ - int nr_active; /* L: nr of active works */ - int max_active; /* L: max active works */ - struct list_head delayed_works; /* L: delayed works */ - struct list_head pwqs_node; /* WR: node on wq->pwqs */ - struct list_head mayday_node; /* MD: node on wq->maydays */ - - /* - * Release of unbound pwq is punted to system_wq. See put_pwq() - * and pwq_unbound_release_workfn() for details. pool_workqueue - * itself is also sched-RCU protected so that the first pwq can be - * determined without grabbing wq->mutex. - */ - struct work_struct unbound_release_work; - struct rcu_head rcu; -} __aligned(1 << WORK_STRUCT_FLAG_BITS); - -/* - * Structure used to wait for workqueue flush. - */ -struct wq_flusher { - struct list_head list; /* WQ: list of flushers */ - int flush_color; /* WQ: flush color waiting for */ - struct completion done; /* flush completion */ -}; - -struct wq_device; - -/* - * The externally visible workqueue. It relays the issued work items to - * the appropriate worker_pool through its pool_workqueues. - */ -struct workqueue_struct { - struct list_head pwqs; /* WR: all pwqs of this wq */ - struct list_head list; /* PR: list of all workqueues */ - - struct mutex mutex; /* protects this wq */ - int work_color; /* WQ: current work color */ - int flush_color; /* WQ: current flush color */ - atomic_t nr_pwqs_to_flush; /* flush in progress */ - struct wq_flusher *first_flusher; /* WQ: first flusher */ - struct list_head flusher_queue; /* WQ: flush waiters */ - struct list_head flusher_overflow; /* WQ: flush overflow list */ - - struct list_head maydays; /* MD: pwqs requesting rescue */ - struct worker *rescuer; /* I: rescue worker */ - - int nr_drainers; /* WQ: drain in progress */ - int saved_max_active; /* WQ: saved pwq max_active */ - - struct workqueue_attrs *unbound_attrs; /* PW: only for unbound wqs */ - struct pool_workqueue *dfl_pwq; /* PW: only for unbound wqs */ - -#ifdef CONFIG_SYSFS - struct wq_device *wq_dev; /* I: for sysfs interface */ -#endif -#ifdef CONFIG_LOCKDEP - struct lockdep_map lockdep_map; -#endif - char name[WQ_NAME_LEN]; /* I: workqueue name */ - - /* - * Destruction of workqueue_struct is sched-RCU protected to allow - * walking the workqueues list without grabbing wq_pool_mutex. - * This is used to dump all workqueues from sysrq. - */ - struct rcu_head rcu; - - /* hot fields used during command issue, aligned to cacheline */ - unsigned int flags ____cacheline_aligned; /* WQ: WQ_* flags */ - struct pool_workqueue __percpu *cpu_pwqs; /* I: per-cpu pwqs */ - struct pool_workqueue __rcu *numa_pwq_tbl[]; /* PWR: unbound pwqs indexed by node */ -}; - -static struct kmem_cache *pwq_cache; - -static cpumask_var_t *wq_numa_possible_cpumask; - /* possible CPUs of each node */ - -static bool wq_disable_numa; -module_param_named(disable_numa, wq_disable_numa, bool, 0444); - -/* see the comment above the definition of WQ_POWER_EFFICIENT */ -static bool wq_power_efficient = IS_ENABLED(CONFIG_WQ_POWER_EFFICIENT_DEFAULT); -module_param_named(power_efficient, wq_power_efficient, bool, 0444); - -static bool wq_numa_enabled; /* unbound NUMA affinity enabled */ - -/* buf for wq_update_unbound_numa_attrs(), protected by CPU hotplug exclusion */ -static struct workqueue_attrs *wq_update_unbound_numa_attrs_buf; - -static DEFINE_MUTEX(wq_pool_mutex); /* protects pools and workqueues list */ -static DEFINE_SPINLOCK(wq_mayday_lock); /* protects wq->maydays list */ - -static LIST_HEAD(workqueues); /* PR: list of all workqueues */ -static bool workqueue_freezing; /* PL: have wqs started freezing? */ - -/* PL: allowable cpus for unbound wqs and work items */ -static cpumask_var_t wq_unbound_cpumask; - -/* CPU where unbound work was last round robin scheduled from this CPU */ -static DEFINE_PER_CPU(int, wq_rr_cpu_last); - -/* - * Local execution of unbound work items is no longer guaranteed. The - * following always forces round-robin CPU selection on unbound work items - * to uncover usages which depend on it. - */ -#ifdef CONFIG_DEBUG_WQ_FORCE_RR_CPU -static bool wq_debug_force_rr_cpu = true; -#else -static bool wq_debug_force_rr_cpu = false; -#endif -module_param_named(debug_force_rr_cpu, wq_debug_force_rr_cpu, bool, 0644); - -/* the per-cpu worker pools */ -static DEFINE_PER_CPU_SHARED_ALIGNED(struct worker_pool [NR_STD_WORKER_POOLS], cpu_worker_pools); - -static DEFINE_IDR(worker_pool_idr); /* PR: idr of all pools */ - -/* PL: hash of all unbound pools keyed by pool->attrs */ -static DEFINE_HASHTABLE(unbound_pool_hash, UNBOUND_POOL_HASH_ORDER); - -/* I: attributes used when instantiating standard unbound pools on demand */ -static struct workqueue_attrs *unbound_std_wq_attrs[NR_STD_WORKER_POOLS]; - -/* I: attributes used when instantiating ordered pools on demand */ -static struct workqueue_attrs *ordered_wq_attrs[NR_STD_WORKER_POOLS]; - -struct workqueue_struct *system_wq __read_mostly; -EXPORT_SYMBOL(system_wq); -struct workqueue_struct *system_highpri_wq __read_mostly; -EXPORT_SYMBOL_GPL(system_highpri_wq); -struct workqueue_struct *system_long_wq __read_mostly; -EXPORT_SYMBOL_GPL(system_long_wq); -struct workqueue_struct *system_unbound_wq __read_mostly; -EXPORT_SYMBOL_GPL(system_unbound_wq); -struct workqueue_struct *system_freezable_wq __read_mostly; -EXPORT_SYMBOL_GPL(system_freezable_wq); -struct workqueue_struct *system_power_efficient_wq __read_mostly; -EXPORT_SYMBOL_GPL(system_power_efficient_wq); -struct workqueue_struct *system_freezable_power_efficient_wq __read_mostly; -EXPORT_SYMBOL_GPL(system_freezable_power_efficient_wq); - -static int worker_thread(void *__worker); -static void workqueue_sysfs_unregister(struct workqueue_struct *wq); - -#define CREATE_TRACE_POINTS -#include - -#define assert_rcu_or_pool_mutex() \ - RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held() && \ - !lockdep_is_held(&wq_pool_mutex), \ - "sched RCU or wq_pool_mutex should be held") - -#define assert_rcu_or_wq_mutex(wq) \ - RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held() && \ - !lockdep_is_held(&wq->mutex), \ - "sched RCU or wq->mutex should be held") - -#define assert_rcu_or_wq_mutex_or_pool_mutex(wq) \ - RCU_LOCKDEP_WARN(!rcu_read_lock_sched_held() && \ - !lockdep_is_held(&wq->mutex) && \ - !lockdep_is_held(&wq_pool_mutex), \ - "sched RCU, wq->mutex or wq_pool_mutex should be held") - -#define for_each_cpu_worker_pool(pool, cpu) \ - for ((pool) = &per_cpu(cpu_worker_pools, cpu)[0]; \ - (pool) < &per_cpu(cpu_worker_pools, cpu)[NR_STD_WORKER_POOLS]; \ - (pool)++) - -/** - * for_each_pool - iterate through all worker_pools in the system - * @pool: iteration cursor - * @pi: integer used for iteration - * - * This must be called either with wq_pool_mutex held or sched RCU read - * locked. If the pool needs to be used beyond the locking in effect, the - * caller is responsible for guaranteeing that the pool stays online. - * - * The if/else clause exists only for the lockdep assertion and can be - * ignored. - */ -#define for_each_pool(pool, pi) \ - idr_for_each_entry(&worker_pool_idr, pool, pi) \ - if (({ assert_rcu_or_pool_mutex(); false; })) { } \ - else - -/** - * for_each_pool_worker - iterate through all workers of a worker_pool - * @worker: iteration cursor - * @pool: worker_pool to iterate workers of - * - * This must be called with @pool->attach_mutex. - * - * The if/else clause exists only for the lockdep assertion and can be - * ignored. - */ -#define for_each_pool_worker(worker, pool) \ - list_for_each_entry((worker), &(pool)->workers, node) \ - if (({ lockdep_assert_held(&pool->attach_mutex); false; })) { } \ - else - -/** - * for_each_pwq - iterate through all pool_workqueues of the specified workqueue - * @pwq: iteration cursor - * @wq: the target workqueue - * - * This must be called either with wq->mutex held or sched RCU read locked. - * If the pwq needs to be used beyond the locking in effect, the caller is - * responsible for guaranteeing that the pwq stays online. - * - * The if/else clause exists only for the lockdep assertion and can be - * ignored. - */ -#define for_each_pwq(pwq, wq) \ - list_for_each_entry_rcu((pwq), &(wq)->pwqs, pwqs_node) \ - if (({ assert_rcu_or_wq_mutex(wq); false; })) { } \ - else - -#ifdef CONFIG_DEBUG_OBJECTS_WORK - -static struct debug_obj_descr work_debug_descr; - -static void *work_debug_hint(void *addr) -{ - return ((struct work_struct *) addr)->func; -} - -static bool work_is_static_object(void *addr) -{ - struct work_struct *work = addr; - - return test_bit(WORK_STRUCT_STATIC_BIT, work_data_bits(work)); -} - -/* - * fixup_init is called when: - * - an active object is initialized - */ -static bool work_fixup_init(void *addr, enum debug_obj_state state) -{ - struct work_struct *work = addr; - - switch (state) { - case ODEBUG_STATE_ACTIVE: - cancel_work_sync(work); - debug_object_init(work, &work_debug_descr); - return true; - default: - return false; - } -} - -/* - * fixup_free is called when: - * - an active object is freed - */ -static bool work_fixup_free(void *addr, enum debug_obj_state state) -{ - struct work_struct *work = addr; - - switch (state) { - case ODEBUG_STATE_ACTIVE: - cancel_work_sync(work); - debug_object_free(work, &work_debug_descr); - return true; - default: - return false; - } -} - -static struct debug_obj_descr work_debug_descr = { - .name = "work_struct", - .debug_hint = work_debug_hint, - .is_static_object = work_is_static_object, - .fixup_init = work_fixup_init, - .fixup_free = work_fixup_free, -}; - -static inline void debug_work_activate(struct work_struct *work) -{ - debug_object_activate(work, &work_debug_descr); -} - -static inline void debug_work_deactivate(struct work_struct *work) -{ - debug_object_deactivate(work, &work_debug_descr); -} - -void __init_work(struct work_struct *work, int onstack) -{ - if (onstack) - debug_object_init_on_stack(work, &work_debug_descr); - else - debug_object_init(work, &work_debug_descr); -} -EXPORT_SYMBOL_GPL(__init_work); - -void destroy_work_on_stack(struct work_struct *work) -{ - debug_object_free(work, &work_debug_descr); -} -EXPORT_SYMBOL_GPL(destroy_work_on_stack); - -void destroy_delayed_work_on_stack(struct delayed_work *work) -{ - destroy_timer_on_stack(&work->timer); - debug_object_free(&work->work, &work_debug_descr); -} -EXPORT_SYMBOL_GPL(destroy_delayed_work_on_stack); - -#else -static inline void debug_work_activate(struct work_struct *work) { } -static inline void debug_work_deactivate(struct work_struct *work) { } -#endif - -/** - * worker_pool_assign_id - allocate ID and assing it to @pool - * @pool: the pool pointer of interest - * - * Returns 0 if ID in [0, WORK_OFFQ_POOL_NONE) is allocated and assigned - * successfully, -errno on failure. - */ -static int worker_pool_assign_id(struct worker_pool *pool) -{ - int ret; - - lockdep_assert_held(&wq_pool_mutex); - - ret = idr_alloc(&worker_pool_idr, pool, 0, WORK_OFFQ_POOL_NONE, - GFP_KERNEL); - if (ret >= 0) { - pool->id = ret; - return 0; - } - return ret; -} - -/** - * unbound_pwq_by_node - return the unbound pool_workqueue for the given node - * @wq: the target workqueue - * @node: the node ID - * - * This must be called with any of wq_pool_mutex, wq->mutex or sched RCU - * read locked. - * If the pwq needs to be used beyond the locking in effect, the caller is - * responsible for guaranteeing that the pwq stays online. - * - * Return: The unbound pool_workqueue for @node. - */ -static struct pool_workqueue *unbound_pwq_by_node(struct workqueue_struct *wq, - int node) -{ - assert_rcu_or_wq_mutex_or_pool_mutex(wq); - - /* - * XXX: @node can be NUMA_NO_NODE if CPU goes offline while a - * delayed item is pending. The plan is to keep CPU -> NODE - * mapping valid and stable across CPU on/offlines. Once that - * happens, this workaround can be removed. - */ - if (unlikely(node == NUMA_NO_NODE)) - return wq->dfl_pwq; - - return rcu_dereference_raw(wq->numa_pwq_tbl[node]); -} - -static unsigned int work_color_to_flags(int color) -{ - return color << WORK_STRUCT_COLOR_SHIFT; -} - -static int get_work_color(struct work_struct *work) -{ - return (*work_data_bits(work) >> WORK_STRUCT_COLOR_SHIFT) & - ((1 << WORK_STRUCT_COLOR_BITS) - 1); -} - -static int work_next_color(int color) -{ - return (color + 1) % WORK_NR_COLORS; -} - -/* - * While queued, %WORK_STRUCT_PWQ is set and non flag bits of a work's data - * contain the pointer to the queued pwq. Once execution starts, the flag - * is cleared and the high bits contain OFFQ flags and pool ID. - * - * set_work_pwq(), set_work_pool_and_clear_pending(), mark_work_canceling() - * and clear_work_data() can be used to set the pwq, pool or clear - * work->data. These functions should only be called while the work is - * owned - ie. while the PENDING bit is set. - * - * get_work_pool() and get_work_pwq() can be used to obtain the pool or pwq - * corresponding to a work. Pool is available once the work has been - * queued anywhere after initialization until it is sync canceled. pwq is - * available only while the work item is queued. - * - * %WORK_OFFQ_CANCELING is used to mark a work item which is being - * canceled. While being canceled, a work item may have its PENDING set - * but stay off timer and worklist for arbitrarily long and nobody should - * try to steal the PENDING bit. - */ -static inline void set_work_data(struct work_struct *work, unsigned long data, - unsigned long flags) -{ - WARN_ON_ONCE(!work_pending(work)); - atomic_long_set(&work->data, data | flags | work_static(work)); -} - -static void set_work_pwq(struct work_struct *work, struct pool_workqueue *pwq, - unsigned long extra_flags) -{ - set_work_data(work, (unsigned long)pwq, - WORK_STRUCT_PENDING | WORK_STRUCT_PWQ | extra_flags); -} - -static void set_work_pool_and_keep_pending(struct work_struct *work, - int pool_id) -{ - set_work_data(work, (unsigned long)pool_id << WORK_OFFQ_POOL_SHIFT, - WORK_STRUCT_PENDING); -} - -static void set_work_pool_and_clear_pending(struct work_struct *work, - int pool_id) -{ - /* - * The following wmb is paired with the implied mb in - * test_and_set_bit(PENDING) and ensures all updates to @work made - * here are visible to and precede any updates by the next PENDING - * owner. - */ - smp_wmb(); - set_work_data(work, (unsigned long)pool_id << WORK_OFFQ_POOL_SHIFT, 0); - /* - * The following mb guarantees that previous clear of a PENDING bit - * will not be reordered with any speculative LOADS or STORES from - * work->current_func, which is executed afterwards. This possible - * reordering can lead to a missed execution on attempt to qeueue - * the same @work. E.g. consider this case: - * - * CPU#0 CPU#1 - * ---------------------------- -------------------------------- - * - * 1 STORE event_indicated - * 2 queue_work_on() { - * 3 test_and_set_bit(PENDING) - * 4 } set_..._and_clear_pending() { - * 5 set_work_data() # clear bit - * 6 smp_mb() - * 7 work->current_func() { - * 8 LOAD event_indicated - * } - * - * Without an explicit full barrier speculative LOAD on line 8 can - * be executed before CPU#0 does STORE on line 1. If that happens, - * CPU#0 observes the PENDING bit is still set and new execution of - * a @work is not queued in a hope, that CPU#1 will eventually - * finish the queued @work. Meanwhile CPU#1 does not see - * event_indicated is set, because speculative LOAD was executed - * before actual STORE. - */ - smp_mb(); -} - -static void clear_work_data(struct work_struct *work) -{ - smp_wmb(); /* see set_work_pool_and_clear_pending() */ - set_work_data(work, WORK_STRUCT_NO_POOL, 0); -} - -static struct pool_workqueue *get_work_pwq(struct work_struct *work) -{ - unsigned long data = atomic_long_read(&work->data); - - if (data & WORK_STRUCT_PWQ) - return (void *)(data & WORK_STRUCT_WQ_DATA_MASK); - else - return NULL; -} - -/** - * get_work_pool - return the worker_pool a given work was associated with - * @work: the work item of interest - * - * Pools are created and destroyed under wq_pool_mutex, and allows read - * access under sched-RCU read lock. As such, this function should be - * called under wq_pool_mutex or with preemption disabled. - * - * All fields of the returned pool are accessible as long as the above - * mentioned locking is in effect. If the returned pool needs to be used - * beyond the critical section, the caller is responsible for ensuring the - * returned pool is and stays online. - * - * Return: The worker_pool @work was last associated with. %NULL if none. - */ -static struct worker_pool *get_work_pool(struct work_struct *work) -{ - unsigned long data = atomic_long_read(&work->data); - int pool_id; - - assert_rcu_or_pool_mutex(); - - if (data & WORK_STRUCT_PWQ) - return ((struct pool_workqueue *) - (data & WORK_STRUCT_WQ_DATA_MASK))->pool; - - pool_id = data >> WORK_OFFQ_POOL_SHIFT; - if (pool_id == WORK_OFFQ_POOL_NONE) - return NULL; - - return idr_find(&worker_pool_idr, pool_id); -} - -/** - * get_work_pool_id - return the worker pool ID a given work is associated with - * @work: the work item of interest - * - * Return: The worker_pool ID @work was last associated with. - * %WORK_OFFQ_POOL_NONE if none. - */ -static int get_work_pool_id(struct work_struct *work) -{ - unsigned long data = atomic_long_read(&work->data); - - if (data & WORK_STRUCT_PWQ) - return ((struct pool_workqueue *) - (data & WORK_STRUCT_WQ_DATA_MASK))->pool->id; - - return data >> WORK_OFFQ_POOL_SHIFT; -} - -static void mark_work_canceling(struct work_struct *work) -{ - unsigned long pool_id = get_work_pool_id(work); - - pool_id <<= WORK_OFFQ_POOL_SHIFT; - set_work_data(work, pool_id | WORK_OFFQ_CANCELING, WORK_STRUCT_PENDING); -} - -static bool work_is_canceling(struct work_struct *work) -{ - unsigned long data = atomic_long_read(&work->data); - - return !(data & WORK_STRUCT_PWQ) && (data & WORK_OFFQ_CANCELING); -} - -/* - * Policy functions. These define the policies on how the global worker - * pools are managed. Unless noted otherwise, these functions assume that - * they're being called with pool->lock held. - */ - -static bool __need_more_worker(struct worker_pool *pool) -{ - return !atomic_read(&pool->nr_running); -} - -/* - * Need to wake up a worker? Called from anything but currently - * running workers. - * - * Note that, because unbound workers never contribute to nr_running, this - * function will always return %true for unbound pools as long as the - * worklist isn't empty. - */ -static bool need_more_worker(struct worker_pool *pool) -{ - return !list_empty(&pool->worklist) && __need_more_worker(pool); -} - -/* Can I start working? Called from busy but !running workers. */ -static bool may_start_working(struct worker_pool *pool) -{ - return pool->nr_idle; -} - -/* Do I need to keep working? Called from currently running workers. */ -static bool keep_working(struct worker_pool *pool) -{ - return !list_empty(&pool->worklist) && - atomic_read(&pool->nr_running) <= 1; -} - -/* Do we need a new worker? Called from manager. */ -static bool need_to_create_worker(struct worker_pool *pool) -{ - return need_more_worker(pool) && !may_start_working(pool); -} - -/* Do we have too many workers and should some go away? */ -static bool too_many_workers(struct worker_pool *pool) -{ - bool managing = mutex_is_locked(&pool->manager_arb); - int nr_idle = pool->nr_idle + managing; /* manager is considered idle */ - int nr_busy = pool->nr_workers - nr_idle; - - return nr_idle > 2 && (nr_idle - 2) * MAX_IDLE_WORKERS_RATIO >= nr_busy; -} - -/* - * Wake up functions. - */ - -/* Return the first idle worker. Safe with preemption disabled */ -static struct worker *first_idle_worker(struct worker_pool *pool) -{ - if (unlikely(list_empty(&pool->idle_list))) - return NULL; - - return list_first_entry(&pool->idle_list, struct worker, entry); -} - -/** - * wake_up_worker - wake up an idle worker - * @pool: worker pool to wake worker from - * - * Wake up the first idle worker of @pool. - * - * CONTEXT: - * spin_lock_irq(pool->lock). - */ -static void wake_up_worker(struct worker_pool *pool) -{ - struct worker *worker = first_idle_worker(pool); - - if (likely(worker)) - wake_up_process(worker->task); -} - -/** - * wq_worker_waking_up - a worker is waking up - * @task: task waking up - * @cpu: CPU @task is waking up to - * - * This function is called during try_to_wake_up() when a worker is - * being awoken. - * - * CONTEXT: - * spin_lock_irq(rq->lock) - */ -void wq_worker_waking_up(struct task_struct *task, int cpu) -{ - struct worker *worker = kthread_data(task); - - if (!(worker->flags & WORKER_NOT_RUNNING)) { - WARN_ON_ONCE(worker->pool->cpu != cpu); - atomic_inc(&worker->pool->nr_running); - } -} - -/** - * wq_worker_sleeping - a worker is going to sleep - * @task: task going to sleep - * - * This function is called during schedule() when a busy worker is - * going to sleep. Worker on the same cpu can be woken up by - * returning pointer to its task. - * - * CONTEXT: - * spin_lock_irq(rq->lock) - * - * Return: - * Worker task on @cpu to wake up, %NULL if none. - */ -struct task_struct *wq_worker_sleeping(struct task_struct *task) -{ - struct worker *worker = kthread_data(task), *to_wakeup = NULL; - struct worker_pool *pool; - - /* - * Rescuers, which may not have all the fields set up like normal - * workers, also reach here, let's not access anything before - * checking NOT_RUNNING. - */ - if (worker->flags & WORKER_NOT_RUNNING) - return NULL; - - pool = worker->pool; - - /* this can only happen on the local cpu */ - if (WARN_ON_ONCE(pool->cpu != raw_smp_processor_id())) - return NULL; - - /* - * The counterpart of the following dec_and_test, implied mb, - * worklist not empty test sequence is in insert_work(). - * Please read comment there. - * - * NOT_RUNNING is clear. This means that we're bound to and - * running on the local cpu w/ rq lock held and preemption - * disabled, which in turn means that none else could be - * manipulating idle_list, so dereferencing idle_list without pool - * lock is safe. - */ - if (atomic_dec_and_test(&pool->nr_running) && - !list_empty(&pool->worklist)) - to_wakeup = first_idle_worker(pool); - return to_wakeup ? to_wakeup->task : NULL; -} - -/** - * worker_set_flags - set worker flags and adjust nr_running accordingly - * @worker: self - * @flags: flags to set - * - * Set @flags in @worker->flags and adjust nr_running accordingly. - * - * CONTEXT: - * spin_lock_irq(pool->lock) - */ -static inline void worker_set_flags(struct worker *worker, unsigned int flags) -{ - struct worker_pool *pool = worker->pool; - - WARN_ON_ONCE(worker->task != current); - - /* If transitioning into NOT_RUNNING, adjust nr_running. */ - if ((flags & WORKER_NOT_RUNNING) && - !(worker->flags & WORKER_NOT_RUNNING)) { - atomic_dec(&pool->nr_running); - } - - worker->flags |= flags; -} - -/** - * worker_clr_flags - clear worker flags and adjust nr_running accordingly - * @worker: self - * @flags: flags to clear - * - * Clear @flags in @worker->flags and adjust nr_running accordingly. - * - * CONTEXT: - * spin_lock_irq(pool->lock) - */ -static inline void worker_clr_flags(struct worker *worker, unsigned int flags) -{ - struct worker_pool *pool = worker->pool; - unsigned int oflags = worker->flags; - - WARN_ON_ONCE(worker->task != current); - - worker->flags &= ~flags; - - /* - * If transitioning out of NOT_RUNNING, increment nr_running. Note - * that the nested NOT_RUNNING is not a noop. NOT_RUNNING is mask - * of multiple flags, not a single flag. - */ - if ((flags & WORKER_NOT_RUNNING) && (oflags & WORKER_NOT_RUNNING)) - if (!(worker->flags & WORKER_NOT_RUNNING)) - atomic_inc(&pool->nr_running); -} - -/** - * find_worker_executing_work - find worker which is executing a work - * @pool: pool of interest - * @work: work to find worker for - * - * Find a worker which is executing @work on @pool by searching - * @pool->busy_hash which is keyed by the address of @work. For a worker - * to match, its current execution should match the address of @work and - * its work function. This is to avoid unwanted dependency between - * unrelated work executions through a work item being recycled while still - * being executed. - * - * This is a bit tricky. A work item may be freed once its execution - * starts and nothing prevents the freed area from being recycled for - * another work item. If the same work item address ends up being reused - * before the original execution finishes, workqueue will identify the - * recycled work item as currently executing and make it wait until the - * current execution finishes, introducing an unwanted dependency. - * - * This function checks the work item address and work function to avoid - * false positives. Note that this isn't complete as one may construct a - * work function which can introduce dependency onto itself through a - * recycled work item. Well, if somebody wants to shoot oneself in the - * foot that badly, there's only so much we can do, and if such deadlock - * actually occurs, it should be easy to locate the culprit work function. - * - * CONTEXT: - * spin_lock_irq(pool->lock). - * - * Return: - * Pointer to worker which is executing @work if found, %NULL - * otherwise. - */ -static struct worker *find_worker_executing_work(struct worker_pool *pool, - struct work_struct *work) -{ - struct worker *worker; - - hash_for_each_possible(pool->busy_hash, worker, hentry, - (unsigned long)work) - if (worker->current_work == work && - worker->current_func == work->func) - return worker; - - return NULL; -} - -/** - * move_linked_works - move linked works to a list - * @work: start of series of works to be scheduled - * @head: target list to append @work to - * @nextp: out parameter for nested worklist walking - * - * Schedule linked works starting from @work to @head. Work series to - * be scheduled starts at @work and includes any consecutive work with - * WORK_STRUCT_LINKED set in its predecessor. - * - * If @nextp is not NULL, it's updated to point to the next work of - * the last scheduled work. This allows move_linked_works() to be - * nested inside outer list_for_each_entry_safe(). - * - * CONTEXT: - * spin_lock_irq(pool->lock). - */ -static void move_linked_works(struct work_struct *work, struct list_head *head, - struct work_struct **nextp) -{ - struct work_struct *n; - - /* - * Linked worklist will always end before the end of the list, - * use NULL for list head. - */ - list_for_each_entry_safe_from(work, n, NULL, entry) { - list_move_tail(&work->entry, head); - if (!(*work_data_bits(work) & WORK_STRUCT_LINKED)) - break; - } - - /* - * If we're already inside safe list traversal and have moved - * multiple works to the scheduled queue, the next position - * needs to be updated. - */ - if (nextp) - *nextp = n; -} - -/** - * get_pwq - get an extra reference on the specified pool_workqueue - * @pwq: pool_workqueue to get - * - * Obtain an extra reference on @pwq. The caller should guarantee that - * @pwq has positive refcnt and be holding the matching pool->lock. - */ -static void get_pwq(struct pool_workqueue *pwq) -{ - lockdep_assert_held(&pwq->pool->lock); - WARN_ON_ONCE(pwq->refcnt <= 0); - pwq->refcnt++; -} - -/** - * put_pwq - put a pool_workqueue reference - * @pwq: pool_workqueue to put - * - * Drop a reference of @pwq. If its refcnt reaches zero, schedule its - * destruction. The caller should be holding the matching pool->lock. - */ -static void put_pwq(struct pool_workqueue *pwq) -{ - lockdep_assert_held(&pwq->pool->lock); - if (likely(--pwq->refcnt)) - return; - if (WARN_ON_ONCE(!(pwq->wq->flags & WQ_UNBOUND))) - return; - /* - * @pwq can't be released under pool->lock, bounce to - * pwq_unbound_release_workfn(). This never recurses on the same - * pool->lock as this path is taken only for unbound workqueues and - * the release work item is scheduled on a per-cpu workqueue. To - * avoid lockdep warning, unbound pool->locks are given lockdep - * subclass of 1 in get_unbound_pool(). - */ - schedule_work(&pwq->unbound_release_work); -} - -/** - * put_pwq_unlocked - put_pwq() with surrounding pool lock/unlock - * @pwq: pool_workqueue to put (can be %NULL) - * - * put_pwq() with locking. This function also allows %NULL @pwq. - */ -static void put_pwq_unlocked(struct pool_workqueue *pwq) -{ - if (pwq) { - /* - * As both pwqs and pools are sched-RCU protected, the - * following lock operations are safe. - */ - spin_lock_irq(&pwq->pool->lock); - put_pwq(pwq); - spin_unlock_irq(&pwq->pool->lock); - } -} - -static void pwq_activate_delayed_work(struct work_struct *work) -{ - struct pool_workqueue *pwq = get_work_pwq(work); - - trace_workqueue_activate_work(work); - if (list_empty(&pwq->pool->worklist)) - pwq->pool->watchdog_ts = jiffies; - move_linked_works(work, &pwq->pool->worklist, NULL); - __clear_bit(WORK_STRUCT_DELAYED_BIT, work_data_bits(work)); - pwq->nr_active++; -} - -static void pwq_activate_first_delayed(struct pool_workqueue *pwq) -{ - struct work_struct *work = list_first_entry(&pwq->delayed_works, - struct work_struct, entry); - - pwq_activate_delayed_work(work); -} - -/** - * pwq_dec_nr_in_flight - decrement pwq's nr_in_flight - * @pwq: pwq of interest - * @color: color of work which left the queue - * - * A work either has completed or is removed from pending queue, - * decrement nr_in_flight of its pwq and handle workqueue flushing. - * - * CONTEXT: - * spin_lock_irq(pool->lock). - */ -static void pwq_dec_nr_in_flight(struct pool_workqueue *pwq, int color) -{ - /* uncolored work items don't participate in flushing or nr_active */ - if (color == WORK_NO_COLOR) - goto out_put; - - pwq->nr_in_flight[color]--; - - pwq->nr_active--; - if (!list_empty(&pwq->delayed_works)) { - /* one down, submit a delayed one */ - if (pwq->nr_active < pwq->max_active) - pwq_activate_first_delayed(pwq); - } - - /* is flush in progress and are we at the flushing tip? */ - if (likely(pwq->flush_color != color)) - goto out_put; - - /* are there still in-flight works? */ - if (pwq->nr_in_flight[color]) - goto out_put; - - /* this pwq is done, clear flush_color */ - pwq->flush_color = -1; - - /* - * If this was the last pwq, wake up the first flusher. It - * will handle the rest. - */ - if (atomic_dec_and_test(&pwq->wq->nr_pwqs_to_flush)) - complete(&pwq->wq->first_flusher->done); -out_put: - put_pwq(pwq); -} - -/** - * try_to_grab_pending - steal work item from worklist and disable irq - * @work: work item to steal - * @is_dwork: @work is a delayed_work - * @flags: place to store irq state - * - * Try to grab PENDING bit of @work. This function can handle @work in any - * stable state - idle, on timer or on worklist. - * - * Return: - * 1 if @work was pending and we successfully stole PENDING - * 0 if @work was idle and we claimed PENDING - * -EAGAIN if PENDING couldn't be grabbed at the moment, safe to busy-retry - * -ENOENT if someone else is canceling @work, this state may persist - * for arbitrarily long - * - * Note: - * On >= 0 return, the caller owns @work's PENDING bit. To avoid getting - * interrupted while holding PENDING and @work off queue, irq must be - * disabled on entry. This, combined with delayed_work->timer being - * irqsafe, ensures that we return -EAGAIN for finite short period of time. - * - * On successful return, >= 0, irq is disabled and the caller is - * responsible for releasing it using local_irq_restore(*@flags). - * - * This function is safe to call from any context including IRQ handler. - */ -static int try_to_grab_pending(struct work_struct *work, bool is_dwork, - unsigned long *flags) -{ - struct worker_pool *pool; - struct pool_workqueue *pwq; - - local_irq_save(*flags); - - /* try to steal the timer if it exists */ - if (is_dwork) { - struct delayed_work *dwork = to_delayed_work(work); - - /* - * dwork->timer is irqsafe. If del_timer() fails, it's - * guaranteed that the timer is not queued anywhere and not - * running on the local CPU. - */ - if (likely(del_timer(&dwork->timer))) - return 1; - } - - /* try to claim PENDING the normal way */ - if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) - return 0; - - /* - * The queueing is in progress, or it is already queued. Try to - * steal it from ->worklist without clearing WORK_STRUCT_PENDING. - */ - pool = get_work_pool(work); - if (!pool) - goto fail; - - spin_lock(&pool->lock); - /* - * work->data is guaranteed to point to pwq only while the work - * item is queued on pwq->wq, and both updating work->data to point - * to pwq on queueing and to pool on dequeueing are done under - * pwq->pool->lock. This in turn guarantees that, if work->data - * points to pwq which is associated with a locked pool, the work - * item is currently queued on that pool. - */ - pwq = get_work_pwq(work); - if (pwq && pwq->pool == pool) { - debug_work_deactivate(work); - - /* - * A delayed work item cannot be grabbed directly because - * it might have linked NO_COLOR work items which, if left - * on the delayed_list, will confuse pwq->nr_active - * management later on and cause stall. Make sure the work - * item is activated before grabbing. - */ - if (*work_data_bits(work) & WORK_STRUCT_DELAYED) - pwq_activate_delayed_work(work); - - list_del_init(&work->entry); - pwq_dec_nr_in_flight(pwq, get_work_color(work)); - - /* work->data points to pwq iff queued, point to pool */ - set_work_pool_and_keep_pending(work, pool->id); - - spin_unlock(&pool->lock); - return 1; - } - spin_unlock(&pool->lock); -fail: - local_irq_restore(*flags); - if (work_is_canceling(work)) - return -ENOENT; - cpu_relax(); - return -EAGAIN; -} - -/** - * insert_work - insert a work into a pool - * @pwq: pwq @work belongs to - * @work: work to insert - * @head: insertion point - * @extra_flags: extra WORK_STRUCT_* flags to set - * - * Insert @work which belongs to @pwq after @head. @extra_flags is or'd to - * work_struct flags. - * - * CONTEXT: - * spin_lock_irq(pool->lock). - */ -static void insert_work(struct pool_workqueue *pwq, struct work_struct *work, - struct list_head *head, unsigned int extra_flags) -{ - struct worker_pool *pool = pwq->pool; - - /* we own @work, set data and link */ - set_work_pwq(work, pwq, extra_flags); - list_add_tail(&work->entry, head); - get_pwq(pwq); - - /* - * Ensure either wq_worker_sleeping() sees the above - * list_add_tail() or we see zero nr_running to avoid workers lying - * around lazily while there are works to be processed. - */ - smp_mb(); - - if (__need_more_worker(pool)) - wake_up_worker(pool); -} - -/* - * Test whether @work is being queued from another work executing on the - * same workqueue. - */ -static bool is_chained_work(struct workqueue_struct *wq) -{ - struct worker *worker; - - worker = current_wq_worker(); - /* - * Return %true iff I'm a worker execuing a work item on @wq. If - * I'm @worker, it's safe to dereference it without locking. - */ - return worker && worker->current_pwq->wq == wq; -} - -/* - * When queueing an unbound work item to a wq, prefer local CPU if allowed - * by wq_unbound_cpumask. Otherwise, round robin among the allowed ones to - * avoid perturbing sensitive tasks. - */ -static int wq_select_unbound_cpu(int cpu) -{ - static bool printed_dbg_warning; - int new_cpu; - - if (likely(!wq_debug_force_rr_cpu)) { - if (cpumask_test_cpu(cpu, wq_unbound_cpumask)) - return cpu; - } else if (!printed_dbg_warning) { - pr_warn("workqueue: round-robin CPU selection forced, expect performance impact\n"); - printed_dbg_warning = true; - } - - if (cpumask_empty(wq_unbound_cpumask)) - return cpu; - - new_cpu = __this_cpu_read(wq_rr_cpu_last); - new_cpu = cpumask_next_and(new_cpu, wq_unbound_cpumask, cpu_online_mask); - if (unlikely(new_cpu >= nr_cpu_ids)) { - new_cpu = cpumask_first_and(wq_unbound_cpumask, cpu_online_mask); - if (unlikely(new_cpu >= nr_cpu_ids)) - return cpu; - } - __this_cpu_write(wq_rr_cpu_last, new_cpu); - - return new_cpu; -} - -static void __queue_work(int cpu, struct workqueue_struct *wq, - struct work_struct *work) -{ - struct pool_workqueue *pwq; - struct worker_pool *last_pool; - struct list_head *worklist; - unsigned int work_flags; - unsigned int req_cpu = cpu; - - /* - * While a work item is PENDING && off queue, a task trying to - * steal the PENDING will busy-loop waiting for it to either get - * queued or lose PENDING. Grabbing PENDING and queueing should - * happen with IRQ disabled. - */ - WARN_ON_ONCE(!irqs_disabled()); - - debug_work_activate(work); - - /* if draining, only works from the same workqueue are allowed */ - if (unlikely(wq->flags & __WQ_DRAINING) && - WARN_ON_ONCE(!is_chained_work(wq))) - return; -retry: - if (req_cpu == WORK_CPU_UNBOUND) - cpu = wq_select_unbound_cpu(raw_smp_processor_id()); - - /* pwq which will be used unless @work is executing elsewhere */ - if (!(wq->flags & WQ_UNBOUND)) - pwq = per_cpu_ptr(wq->cpu_pwqs, cpu); - else - pwq = unbound_pwq_by_node(wq, cpu_to_node(cpu)); - - /* - * If @work was previously on a different pool, it might still be - * running there, in which case the work needs to be queued on that - * pool to guarantee non-reentrancy. - */ - last_pool = get_work_pool(work); - if (last_pool && last_pool != pwq->pool) { - struct worker *worker; - - spin_lock(&last_pool->lock); - - worker = find_worker_executing_work(last_pool, work); - - if (worker && worker->current_pwq->wq == wq) { - pwq = worker->current_pwq; - } else { - /* meh... not running there, queue here */ - spin_unlock(&last_pool->lock); - spin_lock(&pwq->pool->lock); - } - } else { - spin_lock(&pwq->pool->lock); - } - - /* - * pwq is determined and locked. For unbound pools, we could have - * raced with pwq release and it could already be dead. If its - * refcnt is zero, repeat pwq selection. Note that pwqs never die - * without another pwq replacing it in the numa_pwq_tbl or while - * work items are executing on it, so the retrying is guaranteed to - * make forward-progress. - */ - if (unlikely(!pwq->refcnt)) { - if (wq->flags & WQ_UNBOUND) { - spin_unlock(&pwq->pool->lock); - cpu_relax(); - goto retry; - } - /* oops */ - WARN_ONCE(true, "workqueue: per-cpu pwq for %s on cpu%d has 0 refcnt", - wq->name, cpu); - } - - /* pwq determined, queue */ - trace_workqueue_queue_work(req_cpu, pwq, work); - - if (WARN_ON(!list_empty(&work->entry))) { - spin_unlock(&pwq->pool->lock); - return; - } - - pwq->nr_in_flight[pwq->work_color]++; - work_flags = work_color_to_flags(pwq->work_color); - - if (likely(pwq->nr_active < pwq->max_active)) { - trace_workqueue_activate_work(work); - pwq->nr_active++; - worklist = &pwq->pool->worklist; - if (list_empty(worklist)) - pwq->pool->watchdog_ts = jiffies; - } else { - work_flags |= WORK_STRUCT_DELAYED; - worklist = &pwq->delayed_works; - } - - insert_work(pwq, work, worklist, work_flags); - - spin_unlock(&pwq->pool->lock); -} - -/** - * queue_work_on - queue work on specific cpu - * @cpu: CPU number to execute work on - * @wq: workqueue to use - * @work: work to queue - * - * We queue the work to a specific CPU, the caller must ensure it - * can't go away. - * - * Return: %false if @work was already on a queue, %true otherwise. - */ -bool queue_work_on(int cpu, struct workqueue_struct *wq, - struct work_struct *work) -{ - bool ret = false; - unsigned long flags; - - local_irq_save(flags); - - if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) { - __queue_work(cpu, wq, work); - ret = true; - } - - local_irq_restore(flags); - return ret; -} -EXPORT_SYMBOL(queue_work_on); - -void delayed_work_timer_fn(unsigned long __data) -{ - struct delayed_work *dwork = (struct delayed_work *)__data; - - /* should have been called from irqsafe timer with irq already off */ - __queue_work(dwork->cpu, dwork->wq, &dwork->work); -} -EXPORT_SYMBOL(delayed_work_timer_fn); - -static void __queue_delayed_work(int cpu, struct workqueue_struct *wq, - struct delayed_work *dwork, unsigned long delay) -{ - struct timer_list *timer = &dwork->timer; - struct work_struct *work = &dwork->work; - - WARN_ON_ONCE(timer->function != delayed_work_timer_fn || - timer->data != (unsigned long)dwork); - WARN_ON_ONCE(timer_pending(timer)); - WARN_ON_ONCE(!list_empty(&work->entry)); - - /* - * If @delay is 0, queue @dwork->work immediately. This is for - * both optimization and correctness. The earliest @timer can - * expire is on the closest next tick and delayed_work users depend - * on that there's no such delay when @delay is 0. - */ - if (!delay) { - __queue_work(cpu, wq, &dwork->work); - return; - } - - timer_stats_timer_set_start_info(&dwork->timer); - - dwork->wq = wq; - dwork->cpu = cpu; - timer->expires = jiffies + delay; - - if (unlikely(cpu != WORK_CPU_UNBOUND)) - add_timer_on(timer, cpu); - else - add_timer(timer); -} - -/** - * queue_delayed_work_on - queue work on specific CPU after delay - * @cpu: CPU number to execute work on - * @wq: workqueue to use - * @dwork: work to queue - * @delay: number of jiffies to wait before queueing - * - * Return: %false if @work was already on a queue, %true otherwise. If - * @delay is zero and @dwork is idle, it will be scheduled for immediate - * execution. - */ -bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq, - struct delayed_work *dwork, unsigned long delay) -{ - struct work_struct *work = &dwork->work; - bool ret = false; - unsigned long flags; - - /* read the comment in __queue_work() */ - local_irq_save(flags); - - if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) { - __queue_delayed_work(cpu, wq, dwork, delay); - ret = true; - } - - local_irq_restore(flags); - return ret; -} -EXPORT_SYMBOL(queue_delayed_work_on); - -/** - * mod_delayed_work_on - modify delay of or queue a delayed work on specific CPU - * @cpu: CPU number to execute work on - * @wq: workqueue to use - * @dwork: work to queue - * @delay: number of jiffies to wait before queueing - * - * If @dwork is idle, equivalent to queue_delayed_work_on(); otherwise, - * modify @dwork's timer so that it expires after @delay. If @delay is - * zero, @work is guaranteed to be scheduled immediately regardless of its - * current state. - * - * Return: %false if @dwork was idle and queued, %true if @dwork was - * pending and its timer was modified. - * - * This function is safe to call from any context including IRQ handler. - * See try_to_grab_pending() for details. - */ -bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq, - struct delayed_work *dwork, unsigned long delay) -{ - unsigned long flags; - int ret; - - do { - ret = try_to_grab_pending(&dwork->work, true, &flags); - } while (unlikely(ret == -EAGAIN)); - - if (likely(ret >= 0)) { - __queue_delayed_work(cpu, wq, dwork, delay); - local_irq_restore(flags); - } - - /* -ENOENT from try_to_grab_pending() becomes %true */ - return ret; -} -EXPORT_SYMBOL_GPL(mod_delayed_work_on); - -/** - * worker_enter_idle - enter idle state - * @worker: worker which is entering idle state - * - * @worker is entering idle state. Update stats and idle timer if - * necessary. - * - * LOCKING: - * spin_lock_irq(pool->lock). - */ -static void worker_enter_idle(struct worker *worker) -{ - struct worker_pool *pool = worker->pool; - - if (WARN_ON_ONCE(worker->flags & WORKER_IDLE) || - WARN_ON_ONCE(!list_empty(&worker->entry) && - (worker->hentry.next || worker->hentry.pprev))) - return; - - /* can't use worker_set_flags(), also called from create_worker() */ - worker->flags |= WORKER_IDLE; - pool->nr_idle++; - worker->last_active = jiffies; - - /* idle_list is LIFO */ - list_add(&worker->entry, &pool->idle_list); - - if (too_many_workers(pool) && !timer_pending(&pool->idle_timer)) - mod_timer(&pool->idle_timer, jiffies + IDLE_WORKER_TIMEOUT); - - /* - * Sanity check nr_running. Because wq_unbind_fn() releases - * pool->lock between setting %WORKER_UNBOUND and zapping - * nr_running, the warning may trigger spuriously. Check iff - * unbind is not in progress. - */ - WARN_ON_ONCE(!(pool->flags & POOL_DISASSOCIATED) && - pool->nr_workers == pool->nr_idle && - atomic_read(&pool->nr_running)); -} - -/** - * worker_leave_idle - leave idle state - * @worker: worker which is leaving idle state - * - * @worker is leaving idle state. Update stats. - * - * LOCKING: - * spin_lock_irq(pool->lock). - */ -static void worker_leave_idle(struct worker *worker) -{ - struct worker_pool *pool = worker->pool; - - if (WARN_ON_ONCE(!(worker->flags & WORKER_IDLE))) - return; - worker_clr_flags(worker, WORKER_IDLE); - pool->nr_idle--; - list_del_init(&worker->entry); -} - -static struct worker *alloc_worker(int node) -{ - struct worker *worker; - - worker = kzalloc_node(sizeof(*worker), GFP_KERNEL, node); - if (worker) { - INIT_LIST_HEAD(&worker->entry); - INIT_LIST_HEAD(&worker->scheduled); - INIT_LIST_HEAD(&worker->node); - /* on creation a worker is in !idle && prep state */ - worker->flags = WORKER_PREP; - } - return worker; -} - -/** - * worker_attach_to_pool() - attach a worker to a pool - * @worker: worker to be attached - * @pool: the target pool - * - * Attach @worker to @pool. Once attached, the %WORKER_UNBOUND flag and - * cpu-binding of @worker are kept coordinated with the pool across - * cpu-[un]hotplugs. - */ -static void worker_attach_to_pool(struct worker *worker, - struct worker_pool *pool) -{ - mutex_lock(&pool->attach_mutex); - - /* - * set_cpus_allowed_ptr() will fail if the cpumask doesn't have any - * online CPUs. It'll be re-applied when any of the CPUs come up. - */ - set_cpus_allowed_ptr(worker->task, pool->attrs->cpumask); - - /* - * The pool->attach_mutex ensures %POOL_DISASSOCIATED remains - * stable across this function. See the comments above the - * flag definition for details. - */ - if (pool->flags & POOL_DISASSOCIATED) - worker->flags |= WORKER_UNBOUND; - - list_add_tail(&worker->node, &pool->workers); - - mutex_unlock(&pool->attach_mutex); -} - -/** - * worker_detach_from_pool() - detach a worker from its pool - * @worker: worker which is attached to its pool - * @pool: the pool @worker is attached to - * - * Undo the attaching which had been done in worker_attach_to_pool(). The - * caller worker shouldn't access to the pool after detached except it has - * other reference to the pool. - */ -static void worker_detach_from_pool(struct worker *worker, - struct worker_pool *pool) -{ - struct completion *detach_completion = NULL; - - mutex_lock(&pool->attach_mutex); - list_del(&worker->node); - if (list_empty(&pool->workers)) - detach_completion = pool->detach_completion; - mutex_unlock(&pool->attach_mutex); - - /* clear leftover flags without pool->lock after it is detached */ - worker->flags &= ~(WORKER_UNBOUND | WORKER_REBOUND); - - if (detach_completion) - complete(detach_completion); -} - -/** - * create_worker - create a new workqueue worker - * @pool: pool the new worker will belong to - * - * Create and start a new worker which is attached to @pool. - * - * CONTEXT: - * Might sleep. Does GFP_KERNEL allocations. - * - * Return: - * Pointer to the newly created worker. - */ -static struct worker *create_worker(struct worker_pool *pool) -{ - struct worker *worker = NULL; - int id = -1; - char id_buf[16]; - - /* ID is needed to determine kthread name */ - id = ida_simple_get(&pool->worker_ida, 0, 0, GFP_KERNEL); - if (id < 0) - goto fail; - - worker = alloc_worker(pool->node); - if (!worker) - goto fail; - - worker->pool = pool; - worker->id = id; - - if (pool->cpu >= 0) - snprintf(id_buf, sizeof(id_buf), "%d:%d%s", pool->cpu, id, - pool->attrs->nice < 0 ? "H" : ""); - else - snprintf(id_buf, sizeof(id_buf), "u%d:%d", pool->id, id); - - worker->task = kthread_create_on_node(worker_thread, worker, pool->node, - "kworker/%s", id_buf); - if (IS_ERR(worker->task)) - goto fail; - - set_user_nice(worker->task, pool->attrs->nice); - kthread_bind_mask(worker->task, pool->attrs->cpumask); - - /* successful, attach the worker to the pool */ - worker_attach_to_pool(worker, pool); - - /* start the newly created worker */ - spin_lock_irq(&pool->lock); - worker->pool->nr_workers++; - worker_enter_idle(worker); - wake_up_process(worker->task); - spin_unlock_irq(&pool->lock); - - return worker; - -fail: - if (id >= 0) - ida_simple_remove(&pool->worker_ida, id); - kfree(worker); - return NULL; -} - -/** - * destroy_worker - destroy a workqueue worker - * @worker: worker to be destroyed - * - * Destroy @worker and adjust @pool stats accordingly. The worker should - * be idle. - * - * CONTEXT: - * spin_lock_irq(pool->lock). - */ -static void destroy_worker(struct worker *worker) -{ - struct worker_pool *pool = worker->pool; - - lockdep_assert_held(&pool->lock); - - /* sanity check frenzy */ - if (WARN_ON(worker->current_work) || - WARN_ON(!list_empty(&worker->scheduled)) || - WARN_ON(!(worker->flags & WORKER_IDLE))) - return; - - pool->nr_workers--; - pool->nr_idle--; - - list_del_init(&worker->entry); - worker->flags |= WORKER_DIE; - wake_up_process(worker->task); -} - -static void idle_worker_timeout(unsigned long __pool) -{ - struct worker_pool *pool = (void *)__pool; - - spin_lock_irq(&pool->lock); - - while (too_many_workers(pool)) { - struct worker *worker; - unsigned long expires; - - /* idle_list is kept in LIFO order, check the last one */ - worker = list_entry(pool->idle_list.prev, struct worker, entry); - expires = worker->last_active + IDLE_WORKER_TIMEOUT; - - if (time_before(jiffies, expires)) { - mod_timer(&pool->idle_timer, expires); - break; - } - - destroy_worker(worker); - } - - spin_unlock_irq(&pool->lock); -} - -static void send_mayday(struct work_struct *work) -{ - struct pool_workqueue *pwq = get_work_pwq(work); - struct workqueue_struct *wq = pwq->wq; - - lockdep_assert_held(&wq_mayday_lock); - - if (!wq->rescuer) - return; - - /* mayday mayday mayday */ - if (list_empty(&pwq->mayday_node)) { - /* - * If @pwq is for an unbound wq, its base ref may be put at - * any time due to an attribute change. Pin @pwq until the - * rescuer is done with it. - */ - get_pwq(pwq); - list_add_tail(&pwq->mayday_node, &wq->maydays); - wake_up_process(wq->rescuer->task); - } -} - -static void pool_mayday_timeout(unsigned long __pool) -{ - struct worker_pool *pool = (void *)__pool; - struct work_struct *work; - - spin_lock_irq(&pool->lock); - spin_lock(&wq_mayday_lock); /* for wq->maydays */ - - if (need_to_create_worker(pool)) { - /* - * We've been trying to create a new worker but - * haven't been successful. We might be hitting an - * allocation deadlock. Send distress signals to - * rescuers. - */ - list_for_each_entry(work, &pool->worklist, entry) - send_mayday(work); - } - - spin_unlock(&wq_mayday_lock); - spin_unlock_irq(&pool->lock); - - mod_timer(&pool->mayday_timer, jiffies + MAYDAY_INTERVAL); -} - -/** - * maybe_create_worker - create a new worker if necessary - * @pool: pool to create a new worker for - * - * Create a new worker for @pool if necessary. @pool is guaranteed to - * have at least one idle worker on return from this function. If - * creating a new worker takes longer than MAYDAY_INTERVAL, mayday is - * sent to all rescuers with works scheduled on @pool to resolve - * possible allocation deadlock. - * - * On return, need_to_create_worker() is guaranteed to be %false and - * may_start_working() %true. - * - * LOCKING: - * spin_lock_irq(pool->lock) which may be released and regrabbed - * multiple times. Does GFP_KERNEL allocations. Called only from - * manager. - */ -static void maybe_create_worker(struct worker_pool *pool) -__releases(&pool->lock) -__acquires(&pool->lock) -{ -restart: - spin_unlock_irq(&pool->lock); - - /* if we don't make progress in MAYDAY_INITIAL_TIMEOUT, call for help */ - mod_timer(&pool->mayday_timer, jiffies + MAYDAY_INITIAL_TIMEOUT); - - while (true) { - if (create_worker(pool) || !need_to_create_worker(pool)) - break; - - schedule_timeout_interruptible(CREATE_COOLDOWN); - - if (!need_to_create_worker(pool)) - break; - } - - del_timer_sync(&pool->mayday_timer); - spin_lock_irq(&pool->lock); - /* - * This is necessary even after a new worker was just successfully - * created as @pool->lock was dropped and the new worker might have - * already become busy. - */ - if (need_to_create_worker(pool)) - goto restart; -} - -/** - * manage_workers - manage worker pool - * @worker: self - * - * Assume the manager role and manage the worker pool @worker belongs - * to. At any given time, there can be only zero or one manager per - * pool. The exclusion is handled automatically by this function. - * - * The caller can safely start processing works on false return. On - * true return, it's guaranteed that need_to_create_worker() is false - * and may_start_working() is true. - * - * CONTEXT: - * spin_lock_irq(pool->lock) which may be released and regrabbed - * multiple times. Does GFP_KERNEL allocations. - * - * Return: - * %false if the pool doesn't need management and the caller can safely - * start processing works, %true if management function was performed and - * the conditions that the caller verified before calling the function may - * no longer be true. - */ -static bool manage_workers(struct worker *worker) -{ - struct worker_pool *pool = worker->pool; - - /* - * Anyone who successfully grabs manager_arb wins the arbitration - * and becomes the manager. mutex_trylock() on pool->manager_arb - * failure while holding pool->lock reliably indicates that someone - * else is managing the pool and the worker which failed trylock - * can proceed to executing work items. This means that anyone - * grabbing manager_arb is responsible for actually performing - * manager duties. If manager_arb is grabbed and released without - * actual management, the pool may stall indefinitely. - */ - if (!mutex_trylock(&pool->manager_arb)) - return false; - pool->manager = worker; - - maybe_create_worker(pool); - - pool->manager = NULL; - mutex_unlock(&pool->manager_arb); - return true; -} - -/** - * process_one_work - process single work - * @worker: self - * @work: work to process - * - * Process @work. This function contains all the logics necessary to - * process a single work including synchronization against and - * interaction with other workers on the same cpu, queueing and - * flushing. As long as context requirement is met, any worker can - * call this function to process a work. - * - * CONTEXT: - * spin_lock_irq(pool->lock) which is released and regrabbed. - */ -static void process_one_work(struct worker *worker, struct work_struct *work) -__releases(&pool->lock) -__acquires(&pool->lock) -{ - struct pool_workqueue *pwq = get_work_pwq(work); - struct worker_pool *pool = worker->pool; - bool cpu_intensive = pwq->wq->flags & WQ_CPU_INTENSIVE; - int work_color; - struct worker *collision; -#ifdef CONFIG_LOCKDEP - /* - * It is permissible to free the struct work_struct from - * inside the function that is called from it, this we need to - * take into account for lockdep too. To avoid bogus "held - * lock freed" warnings as well as problems when looking into - * work->lockdep_map, make a copy and use that here. - */ - struct lockdep_map lockdep_map; - - lockdep_copy_map(&lockdep_map, &work->lockdep_map); -#endif - /* ensure we're on the correct CPU */ - WARN_ON_ONCE(!(pool->flags & POOL_DISASSOCIATED) && - raw_smp_processor_id() != pool->cpu); - - /* - * A single work shouldn't be executed concurrently by - * multiple workers on a single cpu. Check whether anyone is - * already processing the work. If so, defer the work to the - * currently executing one. - */ - collision = find_worker_executing_work(pool, work); - if (unlikely(collision)) { - move_linked_works(work, &collision->scheduled, NULL); - return; - } - - /* claim and dequeue */ - debug_work_deactivate(work); - hash_add(pool->busy_hash, &worker->hentry, (unsigned long)work); - worker->current_work = work; - worker->current_func = work->func; - worker->current_pwq = pwq; - work_color = get_work_color(work); - - list_del_init(&work->entry); - - /* - * CPU intensive works don't participate in concurrency management. - * They're the scheduler's responsibility. This takes @worker out - * of concurrency management and the next code block will chain - * execution of the pending work items. - */ - if (unlikely(cpu_intensive)) - worker_set_flags(worker, WORKER_CPU_INTENSIVE); - - /* - * Wake up another worker if necessary. The condition is always - * false for normal per-cpu workers since nr_running would always - * be >= 1 at this point. This is used to chain execution of the - * pending work items for WORKER_NOT_RUNNING workers such as the - * UNBOUND and CPU_INTENSIVE ones. - */ - if (need_more_worker(pool)) - wake_up_worker(pool); - - /* - * Record the last pool and clear PENDING which should be the last - * update to @work. Also, do this inside @pool->lock so that - * PENDING and queued state changes happen together while IRQ is - * disabled. - */ - set_work_pool_and_clear_pending(work, pool->id); - - spin_unlock_irq(&pool->lock); - - lock_map_acquire_read(&pwq->wq->lockdep_map); - lock_map_acquire(&lockdep_map); - trace_workqueue_execute_start(work); - worker->current_func(work); - /* - * While we must be careful to not use "work" after this, the trace - * point will only record its address. - */ - trace_workqueue_execute_end(work); - lock_map_release(&lockdep_map); - lock_map_release(&pwq->wq->lockdep_map); - - if (unlikely(in_atomic() || lockdep_depth(current) > 0)) { - pr_err("BUG: workqueue leaked lock or atomic: %s/0x%08x/%d\n" - " last function: %pf\n", - current->comm, preempt_count(), task_pid_nr(current), - worker->current_func); - debug_show_held_locks(current); - dump_stack(); - } - - /* - * The following prevents a kworker from hogging CPU on !PREEMPT - * kernels, where a requeueing work item waiting for something to - * happen could deadlock with stop_machine as such work item could - * indefinitely requeue itself while all other CPUs are trapped in - * stop_machine. At the same time, report a quiescent RCU state so - * the same condition doesn't freeze RCU. - */ - cond_resched_rcu_qs(); - - spin_lock_irq(&pool->lock); - - /* clear cpu intensive status */ - if (unlikely(cpu_intensive)) - worker_clr_flags(worker, WORKER_CPU_INTENSIVE); - - /* we're done with it, release */ - hash_del(&worker->hentry); - worker->current_work = NULL; - worker->current_func = NULL; - worker->current_pwq = NULL; - worker->desc_valid = false; - pwq_dec_nr_in_flight(pwq, work_color); -} - -/** - * process_scheduled_works - process scheduled works - * @worker: self - * - * Process all scheduled works. Please note that the scheduled list - * may change while processing a work, so this function repeatedly - * fetches a work from the top and executes it. - * - * CONTEXT: - * spin_lock_irq(pool->lock) which may be released and regrabbed - * multiple times. - */ -static void process_scheduled_works(struct worker *worker) -{ - while (!list_empty(&worker->scheduled)) { - struct work_struct *work = list_first_entry(&worker->scheduled, - struct work_struct, entry); - process_one_work(worker, work); - } -} - -/** - * worker_thread - the worker thread function - * @__worker: self - * - * The worker thread function. All workers belong to a worker_pool - - * either a per-cpu one or dynamic unbound one. These workers process all - * work items regardless of their specific target workqueue. The only - * exception is work items which belong to workqueues with a rescuer which - * will be explained in rescuer_thread(). - * - * Return: 0 - */ -static int worker_thread(void *__worker) -{ - struct worker *worker = __worker; - struct worker_pool *pool = worker->pool; - - /* tell the scheduler that this is a workqueue worker */ - worker->task->flags |= PF_WQ_WORKER; -woke_up: - spin_lock_irq(&pool->lock); - - /* am I supposed to die? */ - if (unlikely(worker->flags & WORKER_DIE)) { - spin_unlock_irq(&pool->lock); - WARN_ON_ONCE(!list_empty(&worker->entry)); - worker->task->flags &= ~PF_WQ_WORKER; - - set_task_comm(worker->task, "kworker/dying"); - ida_simple_remove(&pool->worker_ida, worker->id); - worker_detach_from_pool(worker, pool); - kfree(worker); - return 0; - } - - worker_leave_idle(worker); -recheck: - /* no more worker necessary? */ - if (!need_more_worker(pool)) - goto sleep; - - /* do we need to manage? */ - if (unlikely(!may_start_working(pool)) && manage_workers(worker)) - goto recheck; - - /* - * ->scheduled list can only be filled while a worker is - * preparing to process a work or actually processing it. - * Make sure nobody diddled with it while I was sleeping. - */ - WARN_ON_ONCE(!list_empty(&worker->scheduled)); - - /* - * Finish PREP stage. We're guaranteed to have at least one idle - * worker or that someone else has already assumed the manager - * role. This is where @worker starts participating in concurrency - * management if applicable and concurrency management is restored - * after being rebound. See rebind_workers() for details. - */ - worker_clr_flags(worker, WORKER_PREP | WORKER_REBOUND); - - do { - struct work_struct *work = - list_first_entry(&pool->worklist, - struct work_struct, entry); - - pool->watchdog_ts = jiffies; - - if (likely(!(*work_data_bits(work) & WORK_STRUCT_LINKED))) { - /* optimization path, not strictly necessary */ - process_one_work(worker, work); - if (unlikely(!list_empty(&worker->scheduled))) - process_scheduled_works(worker); - } else { - move_linked_works(work, &worker->scheduled, NULL); - process_scheduled_works(worker); - } - } while (keep_working(pool)); - - worker_set_flags(worker, WORKER_PREP); -sleep: - /* - * pool->lock is held and there's no work to process and no need to - * manage, sleep. Workers are woken up only while holding - * pool->lock or from local cpu, so setting the current state - * before releasing pool->lock is enough to prevent losing any - * event. - */ - worker_enter_idle(worker); - __set_current_state(TASK_INTERRUPTIBLE); - spin_unlock_irq(&pool->lock); - schedule(); - goto woke_up; -} - -/** - * rescuer_thread - the rescuer thread function - * @__rescuer: self - * - * Workqueue rescuer thread function. There's one rescuer for each - * workqueue which has WQ_MEM_RECLAIM set. - * - * Regular work processing on a pool may block trying to create a new - * worker which uses GFP_KERNEL allocation which has slight chance of - * developing into deadlock if some works currently on the same queue - * need to be processed to satisfy the GFP_KERNEL allocation. This is - * the problem rescuer solves. - * - * When such condition is possible, the pool summons rescuers of all - * workqueues which have works queued on the pool and let them process - * those works so that forward progress can be guaranteed. - * - * This should happen rarely. - * - * Return: 0 - */ -static int rescuer_thread(void *__rescuer) -{ - struct worker *rescuer = __rescuer; - struct workqueue_struct *wq = rescuer->rescue_wq; - struct list_head *scheduled = &rescuer->scheduled; - bool should_stop; - - set_user_nice(current, RESCUER_NICE_LEVEL); - - /* - * Mark rescuer as worker too. As WORKER_PREP is never cleared, it - * doesn't participate in concurrency management. - */ - rescuer->task->flags |= PF_WQ_WORKER; -repeat: - set_current_state(TASK_INTERRUPTIBLE); - - /* - * By the time the rescuer is requested to stop, the workqueue - * shouldn't have any work pending, but @wq->maydays may still have - * pwq(s) queued. This can happen by non-rescuer workers consuming - * all the work items before the rescuer got to them. Go through - * @wq->maydays processing before acting on should_stop so that the - * list is always empty on exit. - */ - should_stop = kthread_should_stop(); - - /* see whether any pwq is asking for help */ - spin_lock_irq(&wq_mayday_lock); - - while (!list_empty(&wq->maydays)) { - struct pool_workqueue *pwq = list_first_entry(&wq->maydays, - struct pool_workqueue, mayday_node); - struct worker_pool *pool = pwq->pool; - struct work_struct *work, *n; - bool first = true; - - __set_current_state(TASK_RUNNING); - list_del_init(&pwq->mayday_node); - - spin_unlock_irq(&wq_mayday_lock); - - worker_attach_to_pool(rescuer, pool); - - spin_lock_irq(&pool->lock); - rescuer->pool = pool; - - /* - * Slurp in all works issued via this workqueue and - * process'em. - */ - WARN_ON_ONCE(!list_empty(scheduled)); - list_for_each_entry_safe(work, n, &pool->worklist, entry) { - if (get_work_pwq(work) == pwq) { - if (first) - pool->watchdog_ts = jiffies; - move_linked_works(work, scheduled, &n); - } - first = false; - } - - if (!list_empty(scheduled)) { - process_scheduled_works(rescuer); - - /* - * The above execution of rescued work items could - * have created more to rescue through - * pwq_activate_first_delayed() or chained - * queueing. Let's put @pwq back on mayday list so - * that such back-to-back work items, which may be - * being used to relieve memory pressure, don't - * incur MAYDAY_INTERVAL delay inbetween. - */ - if (need_to_create_worker(pool)) { - spin_lock(&wq_mayday_lock); - get_pwq(pwq); - list_move_tail(&pwq->mayday_node, &wq->maydays); - spin_unlock(&wq_mayday_lock); - } - } - - /* - * Put the reference grabbed by send_mayday(). @pool won't - * go away while we're still attached to it. - */ - put_pwq(pwq); - - /* - * Leave this pool. If need_more_worker() is %true, notify a - * regular worker; otherwise, we end up with 0 concurrency - * and stalling the execution. - */ - if (need_more_worker(pool)) - wake_up_worker(pool); - - rescuer->pool = NULL; - spin_unlock_irq(&pool->lock); - - worker_detach_from_pool(rescuer, pool); - - spin_lock_irq(&wq_mayday_lock); - } - - spin_unlock_irq(&wq_mayday_lock); - - if (should_stop) { - __set_current_state(TASK_RUNNING); - rescuer->task->flags &= ~PF_WQ_WORKER; - return 0; - } - - /* rescuers should never participate in concurrency management */ - WARN_ON_ONCE(!(rescuer->flags & WORKER_NOT_RUNNING)); - schedule(); - goto repeat; -} - -/** - * check_flush_dependency - check for flush dependency sanity - * @target_wq: workqueue being flushed - * @target_work: work item being flushed (NULL for workqueue flushes) - * - * %current is trying to flush the whole @target_wq or @target_work on it. - * If @target_wq doesn't have %WQ_MEM_RECLAIM, verify that %current is not - * reclaiming memory or running on a workqueue which doesn't have - * %WQ_MEM_RECLAIM as that can break forward-progress guarantee leading to - * a deadlock. - */ -static void check_flush_dependency(struct workqueue_struct *target_wq, - struct work_struct *target_work) -{ - work_func_t target_func = target_work ? target_work->func : NULL; - struct worker *worker; - - if (target_wq->flags & WQ_MEM_RECLAIM) - return; - - worker = current_wq_worker(); - - WARN_ONCE(current->flags & PF_MEMALLOC, - "workqueue: PF_MEMALLOC task %d(%s) is flushing !WQ_MEM_RECLAIM %s:%pf", - current->pid, current->comm, target_wq->name, target_func); - WARN_ONCE(worker && ((worker->current_pwq->wq->flags & - (WQ_MEM_RECLAIM | __WQ_LEGACY)) == WQ_MEM_RECLAIM), - "workqueue: WQ_MEM_RECLAIM %s:%pf is flushing !WQ_MEM_RECLAIM %s:%pf", - worker->current_pwq->wq->name, worker->current_func, - target_wq->name, target_func); -} - -struct wq_barrier { - struct work_struct work; - struct completion done; - struct task_struct *task; /* purely informational */ -}; - -static void wq_barrier_func(struct work_struct *work) -{ - struct wq_barrier *barr = container_of(work, struct wq_barrier, work); - complete(&barr->done); -} - -/** - * insert_wq_barrier - insert a barrier work - * @pwq: pwq to insert barrier into - * @barr: wq_barrier to insert - * @target: target work to attach @barr to - * @worker: worker currently executing @target, NULL if @target is not executing - * - * @barr is linked to @target such that @barr is completed only after - * @target finishes execution. Please note that the ordering - * guarantee is observed only with respect to @target and on the local - * cpu. - * - * Currently, a queued barrier can't be canceled. This is because - * try_to_grab_pending() can't determine whether the work to be - * grabbed is at the head of the queue and thus can't clear LINKED - * flag of the previous work while there must be a valid next work - * after a work with LINKED flag set. - * - * Note that when @worker is non-NULL, @target may be modified - * underneath us, so we can't reliably determine pwq from @target. - * - * CONTEXT: - * spin_lock_irq(pool->lock). - */ -static void insert_wq_barrier(struct pool_workqueue *pwq, - struct wq_barrier *barr, - struct work_struct *target, struct worker *worker) -{ - struct list_head *head; - unsigned int linked = 0; - - /* - * debugobject calls are safe here even with pool->lock locked - * as we know for sure that this will not trigger any of the - * checks and call back into the fixup functions where we - * might deadlock. - */ - INIT_WORK_ONSTACK(&barr->work, wq_barrier_func); - __set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(&barr->work)); - init_completion(&barr->done); - barr->task = current; - - /* - * If @target is currently being executed, schedule the - * barrier to the worker; otherwise, put it after @target. - */ - if (worker) - head = worker->scheduled.next; - else { - unsigned long *bits = work_data_bits(target); - - head = target->entry.next; - /* there can already be other linked works, inherit and set */ - linked = *bits & WORK_STRUCT_LINKED; - __set_bit(WORK_STRUCT_LINKED_BIT, bits); - } - - debug_work_activate(&barr->work); - insert_work(pwq, &barr->work, head, - work_color_to_flags(WORK_NO_COLOR) | linked); -} - -/** - * flush_workqueue_prep_pwqs - prepare pwqs for workqueue flushing - * @wq: workqueue being flushed - * @flush_color: new flush color, < 0 for no-op - * @work_color: new work color, < 0 for no-op - * - * Prepare pwqs for workqueue flushing. - * - * If @flush_color is non-negative, flush_color on all pwqs should be - * -1. If no pwq has in-flight commands at the specified color, all - * pwq->flush_color's stay at -1 and %false is returned. If any pwq - * has in flight commands, its pwq->flush_color is set to - * @flush_color, @wq->nr_pwqs_to_flush is updated accordingly, pwq - * wakeup logic is armed and %true is returned. - * - * The caller should have initialized @wq->first_flusher prior to - * calling this function with non-negative @flush_color. If - * @flush_color is negative, no flush color update is done and %false - * is returned. - * - * If @work_color is non-negative, all pwqs should have the same - * work_color which is previous to @work_color and all will be - * advanced to @work_color. - * - * CONTEXT: - * mutex_lock(wq->mutex). - * - * Return: - * %true if @flush_color >= 0 and there's something to flush. %false - * otherwise. - */ -static bool flush_workqueue_prep_pwqs(struct workqueue_struct *wq, - int flush_color, int work_color) -{ - bool wait = false; - struct pool_workqueue *pwq; - - if (flush_color >= 0) { - WARN_ON_ONCE(atomic_read(&wq->nr_pwqs_to_flush)); - atomic_set(&wq->nr_pwqs_to_flush, 1); - } - - for_each_pwq(pwq, wq) { - struct worker_pool *pool = pwq->pool; - - spin_lock_irq(&pool->lock); - - if (flush_color >= 0) { - WARN_ON_ONCE(pwq->flush_color != -1); - - if (pwq->nr_in_flight[flush_color]) { - pwq->flush_color = flush_color; - atomic_inc(&wq->nr_pwqs_to_flush); - wait = true; - } - } - - if (work_color >= 0) { - WARN_ON_ONCE(work_color != work_next_color(pwq->work_color)); - pwq->work_color = work_color; - } - - spin_unlock_irq(&pool->lock); - } - - if (flush_color >= 0 && atomic_dec_and_test(&wq->nr_pwqs_to_flush)) - complete(&wq->first_flusher->done); - - return wait; -} - -/** - * flush_workqueue - ensure that any scheduled work has run to completion. - * @wq: workqueue to flush - * - * This function sleeps until all work items which were queued on entry - * have finished execution, but it is not livelocked by new incoming ones. - */ -void flush_workqueue(struct workqueue_struct *wq) -{ - struct wq_flusher this_flusher = { - .list = LIST_HEAD_INIT(this_flusher.list), - .flush_color = -1, - .done = COMPLETION_INITIALIZER_ONSTACK(this_flusher.done), - }; - int next_color; - - lock_map_acquire(&wq->lockdep_map); - lock_map_release(&wq->lockdep_map); - - mutex_lock(&wq->mutex); - - /* - * Start-to-wait phase - */ - next_color = work_next_color(wq->work_color); - - if (next_color != wq->flush_color) { - /* - * Color space is not full. The current work_color - * becomes our flush_color and work_color is advanced - * by one. - */ - WARN_ON_ONCE(!list_empty(&wq->flusher_overflow)); - this_flusher.flush_color = wq->work_color; - wq->work_color = next_color; - - if (!wq->first_flusher) { - /* no flush in progress, become the first flusher */ - WARN_ON_ONCE(wq->flush_color != this_flusher.flush_color); - - wq->first_flusher = &this_flusher; - - if (!flush_workqueue_prep_pwqs(wq, wq->flush_color, - wq->work_color)) { - /* nothing to flush, done */ - wq->flush_color = next_color; - wq->first_flusher = NULL; - goto out_unlock; - } - } else { - /* wait in queue */ - WARN_ON_ONCE(wq->flush_color == this_flusher.flush_color); - list_add_tail(&this_flusher.list, &wq->flusher_queue); - flush_workqueue_prep_pwqs(wq, -1, wq->work_color); - } - } else { - /* - * Oops, color space is full, wait on overflow queue. - * The next flush completion will assign us - * flush_color and transfer to flusher_queue. - */ - list_add_tail(&this_flusher.list, &wq->flusher_overflow); - } - - check_flush_dependency(wq, NULL); - - mutex_unlock(&wq->mutex); - - wait_for_completion(&this_flusher.done); - - /* - * Wake-up-and-cascade phase - * - * First flushers are responsible for cascading flushes and - * handling overflow. Non-first flushers can simply return. - */ - if (wq->first_flusher != &this_flusher) - return; - - mutex_lock(&wq->mutex); - - /* we might have raced, check again with mutex held */ - if (wq->first_flusher != &this_flusher) - goto out_unlock; - - wq->first_flusher = NULL; - - WARN_ON_ONCE(!list_empty(&this_flusher.list)); - WARN_ON_ONCE(wq->flush_color != this_flusher.flush_color); - - while (true) { - struct wq_flusher *next, *tmp; - - /* complete all the flushers sharing the current flush color */ - list_for_each_entry_safe(next, tmp, &wq->flusher_queue, list) { - if (next->flush_color != wq->flush_color) - break; - list_del_init(&next->list); - complete(&next->done); - } - - WARN_ON_ONCE(!list_empty(&wq->flusher_overflow) && - wq->flush_color != work_next_color(wq->work_color)); - - /* this flush_color is finished, advance by one */ - wq->flush_color = work_next_color(wq->flush_color); - - /* one color has been freed, handle overflow queue */ - if (!list_empty(&wq->flusher_overflow)) { - /* - * Assign the same color to all overflowed - * flushers, advance work_color and append to - * flusher_queue. This is the start-to-wait - * phase for these overflowed flushers. - */ - list_for_each_entry(tmp, &wq->flusher_overflow, list) - tmp->flush_color = wq->work_color; - - wq->work_color = work_next_color(wq->work_color); - - list_splice_tail_init(&wq->flusher_overflow, - &wq->flusher_queue); - flush_workqueue_prep_pwqs(wq, -1, wq->work_color); - } - - if (list_empty(&wq->flusher_queue)) { - WARN_ON_ONCE(wq->flush_color != wq->work_color); - break; - } - - /* - * Need to flush more colors. Make the next flusher - * the new first flusher and arm pwqs. - */ - WARN_ON_ONCE(wq->flush_color == wq->work_color); - WARN_ON_ONCE(wq->flush_color != next->flush_color); - - list_del_init(&next->list); - wq->first_flusher = next; - - if (flush_workqueue_prep_pwqs(wq, wq->flush_color, -1)) - break; - - /* - * Meh... this color is already done, clear first - * flusher and repeat cascading. - */ - wq->first_flusher = NULL; - } - -out_unlock: - mutex_unlock(&wq->mutex); -} -EXPORT_SYMBOL(flush_workqueue); - -/** - * drain_workqueue - drain a workqueue - * @wq: workqueue to drain - * - * Wait until the workqueue becomes empty. While draining is in progress, - * only chain queueing is allowed. IOW, only currently pending or running - * work items on @wq can queue further work items on it. @wq is flushed - * repeatedly until it becomes empty. The number of flushing is determined - * by the depth of chaining and should be relatively short. Whine if it - * takes too long. - */ -void drain_workqueue(struct workqueue_struct *wq) -{ - unsigned int flush_cnt = 0; - struct pool_workqueue *pwq; - - /* - * __queue_work() needs to test whether there are drainers, is much - * hotter than drain_workqueue() and already looks at @wq->flags. - * Use __WQ_DRAINING so that queue doesn't have to check nr_drainers. - */ - mutex_lock(&wq->mutex); - if (!wq->nr_drainers++) - wq->flags |= __WQ_DRAINING; - mutex_unlock(&wq->mutex); -reflush: - flush_workqueue(wq); - - mutex_lock(&wq->mutex); - - for_each_pwq(pwq, wq) { - bool drained; - - spin_lock_irq(&pwq->pool->lock); - drained = !pwq->nr_active && list_empty(&pwq->delayed_works); - spin_unlock_irq(&pwq->pool->lock); - - if (drained) - continue; - - if (++flush_cnt == 10 || - (flush_cnt % 100 == 0 && flush_cnt <= 1000)) - pr_warn("workqueue %s: drain_workqueue() isn't complete after %u tries\n", - wq->name, flush_cnt); - - mutex_unlock(&wq->mutex); - goto reflush; - } - - if (!--wq->nr_drainers) - wq->flags &= ~__WQ_DRAINING; - mutex_unlock(&wq->mutex); -} -EXPORT_SYMBOL_GPL(drain_workqueue); - -static bool start_flush_work(struct work_struct *work, struct wq_barrier *barr) -{ - struct worker *worker = NULL; - struct worker_pool *pool; - struct pool_workqueue *pwq; - - might_sleep(); - - local_irq_disable(); - pool = get_work_pool(work); - if (!pool) { - local_irq_enable(); - return false; - } - - spin_lock(&pool->lock); - /* see the comment in try_to_grab_pending() with the same code */ - pwq = get_work_pwq(work); - if (pwq) { - if (unlikely(pwq->pool != pool)) - goto already_gone; - } else { - worker = find_worker_executing_work(pool, work); - if (!worker) - goto already_gone; - pwq = worker->current_pwq; - } - - check_flush_dependency(pwq->wq, work); - - insert_wq_barrier(pwq, barr, work, worker); - spin_unlock_irq(&pool->lock); - - /* - * If @max_active is 1 or rescuer is in use, flushing another work - * item on the same workqueue may lead to deadlock. Make sure the - * flusher is not running on the same workqueue by verifying write - * access. - */ - if (pwq->wq->saved_max_active == 1 || pwq->wq->rescuer) - lock_map_acquire(&pwq->wq->lockdep_map); - else - lock_map_acquire_read(&pwq->wq->lockdep_map); - lock_map_release(&pwq->wq->lockdep_map); - - return true; -already_gone: - spin_unlock_irq(&pool->lock); - return false; -} - -/** - * flush_work - wait for a work to finish executing the last queueing instance - * @work: the work to flush - * - * Wait until @work has finished execution. @work is guaranteed to be idle - * on return if it hasn't been requeued since flush started. - * - * Return: - * %true if flush_work() waited for the work to finish execution, - * %false if it was already idle. - */ -bool flush_work(struct work_struct *work) -{ - struct wq_barrier barr; - - lock_map_acquire(&work->lockdep_map); - lock_map_release(&work->lockdep_map); - - if (start_flush_work(work, &barr)) { - wait_for_completion(&barr.done); - destroy_work_on_stack(&barr.work); - return true; - } else { - return false; - } -} -EXPORT_SYMBOL_GPL(flush_work); - -struct cwt_wait { - wait_queue_t wait; - struct work_struct *work; -}; - -static int cwt_wakefn(wait_queue_t *wait, unsigned mode, int sync, void *key) -{ - struct cwt_wait *cwait = container_of(wait, struct cwt_wait, wait); - - if (cwait->work != key) - return 0; - return autoremove_wake_function(wait, mode, sync, key); -} - -static bool __cancel_work_timer(struct work_struct *work, bool is_dwork) -{ - static DECLARE_WAIT_QUEUE_HEAD(cancel_waitq); - unsigned long flags; - int ret; - - do { - ret = try_to_grab_pending(work, is_dwork, &flags); - /* - * If someone else is already canceling, wait for it to - * finish. flush_work() doesn't work for PREEMPT_NONE - * because we may get scheduled between @work's completion - * and the other canceling task resuming and clearing - * CANCELING - flush_work() will return false immediately - * as @work is no longer busy, try_to_grab_pending() will - * return -ENOENT as @work is still being canceled and the - * other canceling task won't be able to clear CANCELING as - * we're hogging the CPU. - * - * Let's wait for completion using a waitqueue. As this - * may lead to the thundering herd problem, use a custom - * wake function which matches @work along with exclusive - * wait and wakeup. - */ - if (unlikely(ret == -ENOENT)) { - struct cwt_wait cwait; - - init_wait(&cwait.wait); - cwait.wait.func = cwt_wakefn; - cwait.work = work; - - prepare_to_wait_exclusive(&cancel_waitq, &cwait.wait, - TASK_UNINTERRUPTIBLE); - if (work_is_canceling(work)) - schedule(); - finish_wait(&cancel_waitq, &cwait.wait); - } - } while (unlikely(ret < 0)); - - /* tell other tasks trying to grab @work to back off */ - mark_work_canceling(work); - local_irq_restore(flags); - - flush_work(work); - clear_work_data(work); - - /* - * Paired with prepare_to_wait() above so that either - * waitqueue_active() is visible here or !work_is_canceling() is - * visible there. - */ - smp_mb(); - if (waitqueue_active(&cancel_waitq)) - __wake_up(&cancel_waitq, TASK_NORMAL, 1, work); - - return ret; -} - -/** - * cancel_work_sync - cancel a work and wait for it to finish - * @work: the work to cancel - * - * Cancel @work and wait for its execution to finish. This function - * can be used even if the work re-queues itself or migrates to - * another workqueue. On return from this function, @work is - * guaranteed to be not pending or executing on any CPU. - * - * cancel_work_sync(&delayed_work->work) must not be used for - * delayed_work's. Use cancel_delayed_work_sync() instead. - * - * The caller must ensure that the workqueue on which @work was last - * queued can't be destroyed before this function returns. - * - * Return: - * %true if @work was pending, %false otherwise. - */ -bool cancel_work_sync(struct work_struct *work) -{ - return __cancel_work_timer(work, false); -} -EXPORT_SYMBOL_GPL(cancel_work_sync); - -/** - * flush_delayed_work - wait for a dwork to finish executing the last queueing - * @dwork: the delayed work to flush - * - * Delayed timer is cancelled and the pending work is queued for - * immediate execution. Like flush_work(), this function only - * considers the last queueing instance of @dwork. - * - * Return: - * %true if flush_work() waited for the work to finish execution, - * %false if it was already idle. - */ -bool flush_delayed_work(struct delayed_work *dwork) -{ - local_irq_disable(); - if (del_timer_sync(&dwork->timer)) - __queue_work(dwork->cpu, dwork->wq, &dwork->work); - local_irq_enable(); - return flush_work(&dwork->work); -} -EXPORT_SYMBOL(flush_delayed_work); - -static bool __cancel_work(struct work_struct *work, bool is_dwork) -{ - unsigned long flags; - int ret; - - do { - ret = try_to_grab_pending(work, is_dwork, &flags); - } while (unlikely(ret == -EAGAIN)); - - if (unlikely(ret < 0)) - return false; - - set_work_pool_and_clear_pending(work, get_work_pool_id(work)); - local_irq_restore(flags); - return ret; -} - -/* - * See cancel_delayed_work() - */ -bool cancel_work(struct work_struct *work) -{ - return __cancel_work(work, false); -} - -/** - * cancel_delayed_work - cancel a delayed work - * @dwork: delayed_work to cancel - * - * Kill off a pending delayed_work. - * - * Return: %true if @dwork was pending and canceled; %false if it wasn't - * pending. - * - * Note: - * The work callback function may still be running on return, unless - * it returns %true and the work doesn't re-arm itself. Explicitly flush or - * use cancel_delayed_work_sync() to wait on it. - * - * This function is safe to call from any context including IRQ handler. - */ -bool cancel_delayed_work(struct delayed_work *dwork) -{ - return __cancel_work(&dwork->work, true); -} -EXPORT_SYMBOL(cancel_delayed_work); - -/** - * cancel_delayed_work_sync - cancel a delayed work and wait for it to finish - * @dwork: the delayed work cancel - * - * This is cancel_work_sync() for delayed works. - * - * Return: - * %true if @dwork was pending, %false otherwise. - */ -bool cancel_delayed_work_sync(struct delayed_work *dwork) -{ - return __cancel_work_timer(&dwork->work, true); -} -EXPORT_SYMBOL(cancel_delayed_work_sync); - -/** - * schedule_on_each_cpu - execute a function synchronously on each online CPU - * @func: the function to call - * - * schedule_on_each_cpu() executes @func on each online CPU using the - * system workqueue and blocks until all CPUs have completed. - * schedule_on_each_cpu() is very slow. - * - * Return: - * 0 on success, -errno on failure. - */ -int schedule_on_each_cpu(work_func_t func) -{ - int cpu; - struct work_struct __percpu *works; - - works = alloc_percpu(struct work_struct); - if (!works) - return -ENOMEM; - - get_online_cpus(); - - for_each_online_cpu(cpu) { - struct work_struct *work = per_cpu_ptr(works, cpu); - - INIT_WORK(work, func); - schedule_work_on(cpu, work); - } - - for_each_online_cpu(cpu) - flush_work(per_cpu_ptr(works, cpu)); - - put_online_cpus(); - free_percpu(works); - return 0; -} - -/** - * execute_in_process_context - reliably execute the routine with user context - * @fn: the function to execute - * @ew: guaranteed storage for the execute work structure (must - * be available when the work executes) - * - * Executes the function immediately if process context is available, - * otherwise schedules the function for delayed execution. - * - * Return: 0 - function was executed - * 1 - function was scheduled for execution - */ -int execute_in_process_context(work_func_t fn, struct execute_work *ew) -{ - if (!in_interrupt()) { - fn(&ew->work); - return 0; - } - - INIT_WORK(&ew->work, fn); - schedule_work(&ew->work); - - return 1; -} -EXPORT_SYMBOL_GPL(execute_in_process_context); - -/** - * free_workqueue_attrs - free a workqueue_attrs - * @attrs: workqueue_attrs to free - * - * Undo alloc_workqueue_attrs(). - */ -void free_workqueue_attrs(struct workqueue_attrs *attrs) -{ - if (attrs) { - free_cpumask_var(attrs->cpumask); - kfree(attrs); - } -} - -/** - * alloc_workqueue_attrs - allocate a workqueue_attrs - * @gfp_mask: allocation mask to use - * - * Allocate a new workqueue_attrs, initialize with default settings and - * return it. - * - * Return: The allocated new workqueue_attr on success. %NULL on failure. - */ -struct workqueue_attrs *alloc_workqueue_attrs(gfp_t gfp_mask) -{ - struct workqueue_attrs *attrs; - - attrs = kzalloc(sizeof(*attrs), gfp_mask); - if (!attrs) - goto fail; - if (!alloc_cpumask_var(&attrs->cpumask, gfp_mask)) - goto fail; - - cpumask_copy(attrs->cpumask, cpu_possible_mask); - return attrs; -fail: - free_workqueue_attrs(attrs); - return NULL; -} - -static void copy_workqueue_attrs(struct workqueue_attrs *to, - const struct workqueue_attrs *from) -{ - to->nice = from->nice; - cpumask_copy(to->cpumask, from->cpumask); - /* - * Unlike hash and equality test, this function doesn't ignore - * ->no_numa as it is used for both pool and wq attrs. Instead, - * get_unbound_pool() explicitly clears ->no_numa after copying. - */ - to->no_numa = from->no_numa; -} - -/* hash value of the content of @attr */ -static u32 wqattrs_hash(const struct workqueue_attrs *attrs) -{ - u32 hash = 0; - - hash = jhash_1word(attrs->nice, hash); - hash = jhash(cpumask_bits(attrs->cpumask), - BITS_TO_LONGS(nr_cpumask_bits) * sizeof(long), hash); - return hash; -} - -/* content equality test */ -static bool wqattrs_equal(const struct workqueue_attrs *a, - const struct workqueue_attrs *b) -{ - if (a->nice != b->nice) - return false; - if (!cpumask_equal(a->cpumask, b->cpumask)) - return false; - return true; -} - -/** - * init_worker_pool - initialize a newly zalloc'd worker_pool - * @pool: worker_pool to initialize - * - * Initialize a newly zalloc'd @pool. It also allocates @pool->attrs. - * - * Return: 0 on success, -errno on failure. Even on failure, all fields - * inside @pool proper are initialized and put_unbound_pool() can be called - * on @pool safely to release it. - */ -static int init_worker_pool(struct worker_pool *pool) -{ - spin_lock_init(&pool->lock); - pool->id = -1; - pool->cpu = -1; - pool->node = NUMA_NO_NODE; - pool->flags |= POOL_DISASSOCIATED; - pool->watchdog_ts = jiffies; - INIT_LIST_HEAD(&pool->worklist); - INIT_LIST_HEAD(&pool->idle_list); - hash_init(pool->busy_hash); - - init_timer_deferrable(&pool->idle_timer); - pool->idle_timer.function = idle_worker_timeout; - pool->idle_timer.data = (unsigned long)pool; - - setup_timer(&pool->mayday_timer, pool_mayday_timeout, - (unsigned long)pool); - - mutex_init(&pool->manager_arb); - mutex_init(&pool->attach_mutex); - INIT_LIST_HEAD(&pool->workers); - - ida_init(&pool->worker_ida); - INIT_HLIST_NODE(&pool->hash_node); - pool->refcnt = 1; - - /* shouldn't fail above this point */ - pool->attrs = alloc_workqueue_attrs(GFP_KERNEL); - if (!pool->attrs) - return -ENOMEM; - return 0; -} - -static void rcu_free_wq(struct rcu_head *rcu) -{ - struct workqueue_struct *wq = - container_of(rcu, struct workqueue_struct, rcu); - - if (!(wq->flags & WQ_UNBOUND)) - free_percpu(wq->cpu_pwqs); - else - free_workqueue_attrs(wq->unbound_attrs); - - kfree(wq->rescuer); - kfree(wq); -} - -static void rcu_free_pool(struct rcu_head *rcu) -{ - struct worker_pool *pool = container_of(rcu, struct worker_pool, rcu); - - ida_destroy(&pool->worker_ida); - free_workqueue_attrs(pool->attrs); - kfree(pool); -} - -/** - * put_unbound_pool - put a worker_pool - * @pool: worker_pool to put - * - * Put @pool. If its refcnt reaches zero, it gets destroyed in sched-RCU - * safe manner. get_unbound_pool() calls this function on its failure path - * and this function should be able to release pools which went through, - * successfully or not, init_worker_pool(). - * - * Should be called with wq_pool_mutex held. - */ -static void put_unbound_pool(struct worker_pool *pool) -{ - DECLARE_COMPLETION_ONSTACK(detach_completion); - struct worker *worker; - - lockdep_assert_held(&wq_pool_mutex); - - if (--pool->refcnt) - return; - - /* sanity checks */ - if (WARN_ON(!(pool->cpu < 0)) || - WARN_ON(!list_empty(&pool->worklist))) - return; - - /* release id and unhash */ - if (pool->id >= 0) - idr_remove(&worker_pool_idr, pool->id); - hash_del(&pool->hash_node); - - /* - * Become the manager and destroy all workers. Grabbing - * manager_arb prevents @pool's workers from blocking on - * attach_mutex. - */ - mutex_lock(&pool->manager_arb); - - spin_lock_irq(&pool->lock); - while ((worker = first_idle_worker(pool))) - destroy_worker(worker); - WARN_ON(pool->nr_workers || pool->nr_idle); - spin_unlock_irq(&pool->lock); - - mutex_lock(&pool->attach_mutex); - if (!list_empty(&pool->workers)) - pool->detach_completion = &detach_completion; - mutex_unlock(&pool->attach_mutex); - - if (pool->detach_completion) - wait_for_completion(pool->detach_completion); - - mutex_unlock(&pool->manager_arb); - - /* shut down the timers */ - del_timer_sync(&pool->idle_timer); - del_timer_sync(&pool->mayday_timer); - - /* sched-RCU protected to allow dereferences from get_work_pool() */ - call_rcu_sched(&pool->rcu, rcu_free_pool); -} - -/** - * get_unbound_pool - get a worker_pool with the specified attributes - * @attrs: the attributes of the worker_pool to get - * - * Obtain a worker_pool which has the same attributes as @attrs, bump the - * reference count and return it. If there already is a matching - * worker_pool, it will be used; otherwise, this function attempts to - * create a new one. - * - * Should be called with wq_pool_mutex held. - * - * Return: On success, a worker_pool with the same attributes as @attrs. - * On failure, %NULL. - */ -static struct worker_pool *get_unbound_pool(const struct workqueue_attrs *attrs) -{ - u32 hash = wqattrs_hash(attrs); - struct worker_pool *pool; - int node; - int target_node = NUMA_NO_NODE; - - lockdep_assert_held(&wq_pool_mutex); - - /* do we already have a matching pool? */ - hash_for_each_possible(unbound_pool_hash, pool, hash_node, hash) { - if (wqattrs_equal(pool->attrs, attrs)) { - pool->refcnt++; - return pool; - } - } - - /* if cpumask is contained inside a NUMA node, we belong to that node */ - if (wq_numa_enabled) { - for_each_node(node) { - if (cpumask_subset(attrs->cpumask, - wq_numa_possible_cpumask[node])) { - target_node = node; - break; - } - } - } - - /* nope, create a new one */ - pool = kzalloc_node(sizeof(*pool), GFP_KERNEL, target_node); - if (!pool || init_worker_pool(pool) < 0) - goto fail; - - lockdep_set_subclass(&pool->lock, 1); /* see put_pwq() */ - copy_workqueue_attrs(pool->attrs, attrs); - pool->node = target_node; - - /* - * no_numa isn't a worker_pool attribute, always clear it. See - * 'struct workqueue_attrs' comments for detail. - */ - pool->attrs->no_numa = false; - - if (worker_pool_assign_id(pool) < 0) - goto fail; - - /* create and start the initial worker */ - if (!create_worker(pool)) - goto fail; - - /* install */ - hash_add(unbound_pool_hash, &pool->hash_node, hash); - - return pool; -fail: - if (pool) - put_unbound_pool(pool); - return NULL; -} - -static void rcu_free_pwq(struct rcu_head *rcu) -{ - kmem_cache_free(pwq_cache, - container_of(rcu, struct pool_workqueue, rcu)); -} - -/* - * Scheduled on system_wq by put_pwq() when an unbound pwq hits zero refcnt - * and needs to be destroyed. - */ -static void pwq_unbound_release_workfn(struct work_struct *work) -{ - struct pool_workqueue *pwq = container_of(work, struct pool_workqueue, - unbound_release_work); - struct workqueue_struct *wq = pwq->wq; - struct worker_pool *pool = pwq->pool; - bool is_last; - - if (WARN_ON_ONCE(!(wq->flags & WQ_UNBOUND))) - return; - - mutex_lock(&wq->mutex); - list_del_rcu(&pwq->pwqs_node); - is_last = list_empty(&wq->pwqs); - mutex_unlock(&wq->mutex); - - mutex_lock(&wq_pool_mutex); - put_unbound_pool(pool); - mutex_unlock(&wq_pool_mutex); - - call_rcu_sched(&pwq->rcu, rcu_free_pwq); - - /* - * If we're the last pwq going away, @wq is already dead and no one - * is gonna access it anymore. Schedule RCU free. - */ - if (is_last) - call_rcu_sched(&wq->rcu, rcu_free_wq); -} - -/** - * pwq_adjust_max_active - update a pwq's max_active to the current setting - * @pwq: target pool_workqueue - * - * If @pwq isn't freezing, set @pwq->max_active to the associated - * workqueue's saved_max_active and activate delayed work items - * accordingly. If @pwq is freezing, clear @pwq->max_active to zero. - */ -static void pwq_adjust_max_active(struct pool_workqueue *pwq) -{ - struct workqueue_struct *wq = pwq->wq; - bool freezable = wq->flags & WQ_FREEZABLE; - - /* for @wq->saved_max_active */ - lockdep_assert_held(&wq->mutex); - - /* fast exit for non-freezable wqs */ - if (!freezable && pwq->max_active == wq->saved_max_active) - return; - - spin_lock_irq(&pwq->pool->lock); - - /* - * During [un]freezing, the caller is responsible for ensuring that - * this function is called at least once after @workqueue_freezing - * is updated and visible. - */ - if (!freezable || !workqueue_freezing) { - pwq->max_active = wq->saved_max_active; - - while (!list_empty(&pwq->delayed_works) && - pwq->nr_active < pwq->max_active) - pwq_activate_first_delayed(pwq); - - /* - * Need to kick a worker after thawed or an unbound wq's - * max_active is bumped. It's a slow path. Do it always. - */ - wake_up_worker(pwq->pool); - } else { - pwq->max_active = 0; - } - - spin_unlock_irq(&pwq->pool->lock); -} - -/* initialize newly alloced @pwq which is associated with @wq and @pool */ -static void init_pwq(struct pool_workqueue *pwq, struct workqueue_struct *wq, - struct worker_pool *pool) -{ - BUG_ON((unsigned long)pwq & WORK_STRUCT_FLAG_MASK); - - memset(pwq, 0, sizeof(*pwq)); - - pwq->pool = pool; - pwq->wq = wq; - pwq->flush_color = -1; - pwq->refcnt = 1; - INIT_LIST_HEAD(&pwq->delayed_works); - INIT_LIST_HEAD(&pwq->pwqs_node); - INIT_LIST_HEAD(&pwq->mayday_node); - INIT_WORK(&pwq->unbound_release_work, pwq_unbound_release_workfn); -} - -/* sync @pwq with the current state of its associated wq and link it */ -static void link_pwq(struct pool_workqueue *pwq) -{ - struct workqueue_struct *wq = pwq->wq; - - lockdep_assert_held(&wq->mutex); - - /* may be called multiple times, ignore if already linked */ - if (!list_empty(&pwq->pwqs_node)) - return; - - /* set the matching work_color */ - pwq->work_color = wq->work_color; - - /* sync max_active to the current setting */ - pwq_adjust_max_active(pwq); - - /* link in @pwq */ - list_add_rcu(&pwq->pwqs_node, &wq->pwqs); -} - -/* obtain a pool matching @attr and create a pwq associating the pool and @wq */ -static struct pool_workqueue *alloc_unbound_pwq(struct workqueue_struct *wq, - const struct workqueue_attrs *attrs) -{ - struct worker_pool *pool; - struct pool_workqueue *pwq; - - lockdep_assert_held(&wq_pool_mutex); - - pool = get_unbound_pool(attrs); - if (!pool) - return NULL; - - pwq = kmem_cache_alloc_node(pwq_cache, GFP_KERNEL, pool->node); - if (!pwq) { - put_unbound_pool(pool); - return NULL; - } - - init_pwq(pwq, wq, pool); - return pwq; -} - -/** - * wq_calc_node_cpumask - calculate a wq_attrs' cpumask for the specified node - * @attrs: the wq_attrs of the default pwq of the target workqueue - * @node: the target NUMA node - * @cpu_going_down: if >= 0, the CPU to consider as offline - * @cpumask: outarg, the resulting cpumask - * - * Calculate the cpumask a workqueue with @attrs should use on @node. If - * @cpu_going_down is >= 0, that cpu is considered offline during - * calculation. The result is stored in @cpumask. - * - * If NUMA affinity is not enabled, @attrs->cpumask is always used. If - * enabled and @node has online CPUs requested by @attrs, the returned - * cpumask is the intersection of the possible CPUs of @node and - * @attrs->cpumask. - * - * The caller is responsible for ensuring that the cpumask of @node stays - * stable. - * - * Return: %true if the resulting @cpumask is different from @attrs->cpumask, - * %false if equal. - */ -static bool wq_calc_node_cpumask(const struct workqueue_attrs *attrs, int node, - int cpu_going_down, cpumask_t *cpumask) -{ - if (!wq_numa_enabled || attrs->no_numa) - goto use_dfl; - - /* does @node have any online CPUs @attrs wants? */ - cpumask_and(cpumask, cpumask_of_node(node), attrs->cpumask); - if (cpu_going_down >= 0) - cpumask_clear_cpu(cpu_going_down, cpumask); - - if (cpumask_empty(cpumask)) - goto use_dfl; - - /* yeap, return possible CPUs in @node that @attrs wants */ - cpumask_and(cpumask, attrs->cpumask, wq_numa_possible_cpumask[node]); - return !cpumask_equal(cpumask, attrs->cpumask); - -use_dfl: - cpumask_copy(cpumask, attrs->cpumask); - return false; -} - -/* install @pwq into @wq's numa_pwq_tbl[] for @node and return the old pwq */ -static struct pool_workqueue *numa_pwq_tbl_install(struct workqueue_struct *wq, - int node, - struct pool_workqueue *pwq) -{ - struct pool_workqueue *old_pwq; - - lockdep_assert_held(&wq_pool_mutex); - lockdep_assert_held(&wq->mutex); - - /* link_pwq() can handle duplicate calls */ - link_pwq(pwq); - - old_pwq = rcu_access_pointer(wq->numa_pwq_tbl[node]); - rcu_assign_pointer(wq->numa_pwq_tbl[node], pwq); - return old_pwq; -} - -/* context to store the prepared attrs & pwqs before applying */ -struct apply_wqattrs_ctx { - struct workqueue_struct *wq; /* target workqueue */ - struct workqueue_attrs *attrs; /* attrs to apply */ - struct list_head list; /* queued for batching commit */ - struct pool_workqueue *dfl_pwq; - struct pool_workqueue *pwq_tbl[]; -}; - -/* free the resources after success or abort */ -static void apply_wqattrs_cleanup(struct apply_wqattrs_ctx *ctx) -{ - if (ctx) { - int node; - - for_each_node(node) - put_pwq_unlocked(ctx->pwq_tbl[node]); - put_pwq_unlocked(ctx->dfl_pwq); - - free_workqueue_attrs(ctx->attrs); - - kfree(ctx); - } -} - -/* allocate the attrs and pwqs for later installation */ -static struct apply_wqattrs_ctx * -apply_wqattrs_prepare(struct workqueue_struct *wq, - const struct workqueue_attrs *attrs) -{ - struct apply_wqattrs_ctx *ctx; - struct workqueue_attrs *new_attrs, *tmp_attrs; - int node; - - lockdep_assert_held(&wq_pool_mutex); - - ctx = kzalloc(sizeof(*ctx) + nr_node_ids * sizeof(ctx->pwq_tbl[0]), - GFP_KERNEL); - - new_attrs = alloc_workqueue_attrs(GFP_KERNEL); - tmp_attrs = alloc_workqueue_attrs(GFP_KERNEL); - if (!ctx || !new_attrs || !tmp_attrs) - goto out_free; - - /* - * Calculate the attrs of the default pwq. - * If the user configured cpumask doesn't overlap with the - * wq_unbound_cpumask, we fallback to the wq_unbound_cpumask. - */ - copy_workqueue_attrs(new_attrs, attrs); - cpumask_and(new_attrs->cpumask, new_attrs->cpumask, wq_unbound_cpumask); - if (unlikely(cpumask_empty(new_attrs->cpumask))) - cpumask_copy(new_attrs->cpumask, wq_unbound_cpumask); - - /* - * We may create multiple pwqs with differing cpumasks. Make a - * copy of @new_attrs which will be modified and used to obtain - * pools. - */ - copy_workqueue_attrs(tmp_attrs, new_attrs); - - /* - * If something goes wrong during CPU up/down, we'll fall back to - * the default pwq covering whole @attrs->cpumask. Always create - * it even if we don't use it immediately. - */ - ctx->dfl_pwq = alloc_unbound_pwq(wq, new_attrs); - if (!ctx->dfl_pwq) - goto out_free; - - for_each_node(node) { - if (wq_calc_node_cpumask(new_attrs, node, -1, tmp_attrs->cpumask)) { - ctx->pwq_tbl[node] = alloc_unbound_pwq(wq, tmp_attrs); - if (!ctx->pwq_tbl[node]) - goto out_free; - } else { - ctx->dfl_pwq->refcnt++; - ctx->pwq_tbl[node] = ctx->dfl_pwq; - } - } - - /* save the user configured attrs and sanitize it. */ - copy_workqueue_attrs(new_attrs, attrs); - cpumask_and(new_attrs->cpumask, new_attrs->cpumask, cpu_possible_mask); - ctx->attrs = new_attrs; - - ctx->wq = wq; - free_workqueue_attrs(tmp_attrs); - return ctx; - -out_free: - free_workqueue_attrs(tmp_attrs); - free_workqueue_attrs(new_attrs); - apply_wqattrs_cleanup(ctx); - return NULL; -} - -/* set attrs and install prepared pwqs, @ctx points to old pwqs on return */ -static void apply_wqattrs_commit(struct apply_wqattrs_ctx *ctx) -{ - int node; - - /* all pwqs have been created successfully, let's install'em */ - mutex_lock(&ctx->wq->mutex); - - copy_workqueue_attrs(ctx->wq->unbound_attrs, ctx->attrs); - - /* save the previous pwq and install the new one */ - for_each_node(node) - ctx->pwq_tbl[node] = numa_pwq_tbl_install(ctx->wq, node, - ctx->pwq_tbl[node]); - - /* @dfl_pwq might not have been used, ensure it's linked */ - link_pwq(ctx->dfl_pwq); - swap(ctx->wq->dfl_pwq, ctx->dfl_pwq); - - mutex_unlock(&ctx->wq->mutex); -} - -static void apply_wqattrs_lock(void) -{ - /* CPUs should stay stable across pwq creations and installations */ - get_online_cpus(); - mutex_lock(&wq_pool_mutex); -} - -static void apply_wqattrs_unlock(void) -{ - mutex_unlock(&wq_pool_mutex); - put_online_cpus(); -} - -static int apply_workqueue_attrs_locked(struct workqueue_struct *wq, - const struct workqueue_attrs *attrs) -{ - struct apply_wqattrs_ctx *ctx; - - /* only unbound workqueues can change attributes */ - if (WARN_ON(!(wq->flags & WQ_UNBOUND))) - return -EINVAL; - - /* creating multiple pwqs breaks ordering guarantee */ - if (WARN_ON((wq->flags & __WQ_ORDERED) && !list_empty(&wq->pwqs))) - return -EINVAL; - - ctx = apply_wqattrs_prepare(wq, attrs); - if (!ctx) - return -ENOMEM; - - /* the ctx has been prepared successfully, let's commit it */ - apply_wqattrs_commit(ctx); - apply_wqattrs_cleanup(ctx); - - return 0; -} - -/** - * apply_workqueue_attrs - apply new workqueue_attrs to an unbound workqueue - * @wq: the target workqueue - * @attrs: the workqueue_attrs to apply, allocated with alloc_workqueue_attrs() - * - * Apply @attrs to an unbound workqueue @wq. Unless disabled, on NUMA - * machines, this function maps a separate pwq to each NUMA node with - * possibles CPUs in @attrs->cpumask so that work items are affine to the - * NUMA node it was issued on. Older pwqs are released as in-flight work - * items finish. Note that a work item which repeatedly requeues itself - * back-to-back will stay on its current pwq. - * - * Performs GFP_KERNEL allocations. - * - * Return: 0 on success and -errno on failure. - */ -int apply_workqueue_attrs(struct workqueue_struct *wq, - const struct workqueue_attrs *attrs) -{ - int ret; - - apply_wqattrs_lock(); - ret = apply_workqueue_attrs_locked(wq, attrs); - apply_wqattrs_unlock(); - - return ret; -} - -/** - * wq_update_unbound_numa - update NUMA affinity of a wq for CPU hot[un]plug - * @wq: the target workqueue - * @cpu: the CPU coming up or going down - * @online: whether @cpu is coming up or going down - * - * This function is to be called from %CPU_DOWN_PREPARE, %CPU_ONLINE and - * %CPU_DOWN_FAILED. @cpu is being hot[un]plugged, update NUMA affinity of - * @wq accordingly. - * - * If NUMA affinity can't be adjusted due to memory allocation failure, it - * falls back to @wq->dfl_pwq which may not be optimal but is always - * correct. - * - * Note that when the last allowed CPU of a NUMA node goes offline for a - * workqueue with a cpumask spanning multiple nodes, the workers which were - * already executing the work items for the workqueue will lose their CPU - * affinity and may execute on any CPU. This is similar to how per-cpu - * workqueues behave on CPU_DOWN. If a workqueue user wants strict - * affinity, it's the user's responsibility to flush the work item from - * CPU_DOWN_PREPARE. - */ -static void wq_update_unbound_numa(struct workqueue_struct *wq, int cpu, - bool online) -{ - int node = cpu_to_node(cpu); - int cpu_off = online ? -1 : cpu; - struct pool_workqueue *old_pwq = NULL, *pwq; - struct workqueue_attrs *target_attrs; - cpumask_t *cpumask; - - lockdep_assert_held(&wq_pool_mutex); - - if (!wq_numa_enabled || !(wq->flags & WQ_UNBOUND) || - wq->unbound_attrs->no_numa) - return; - - /* - * We don't wanna alloc/free wq_attrs for each wq for each CPU. - * Let's use a preallocated one. The following buf is protected by - * CPU hotplug exclusion. - */ - target_attrs = wq_update_unbound_numa_attrs_buf; - cpumask = target_attrs->cpumask; - - copy_workqueue_attrs(target_attrs, wq->unbound_attrs); - pwq = unbound_pwq_by_node(wq, node); - - /* - * Let's determine what needs to be done. If the target cpumask is - * different from the default pwq's, we need to compare it to @pwq's - * and create a new one if they don't match. If the target cpumask - * equals the default pwq's, the default pwq should be used. - */ - if (wq_calc_node_cpumask(wq->dfl_pwq->pool->attrs, node, cpu_off, cpumask)) { - if (cpumask_equal(cpumask, pwq->pool->attrs->cpumask)) - return; - } else { - goto use_dfl_pwq; - } - - /* create a new pwq */ - pwq = alloc_unbound_pwq(wq, target_attrs); - if (!pwq) { - pr_warn("workqueue: allocation failed while updating NUMA affinity of \"%s\"\n", - wq->name); - goto use_dfl_pwq; - } - - /* Install the new pwq. */ - mutex_lock(&wq->mutex); - old_pwq = numa_pwq_tbl_install(wq, node, pwq); - goto out_unlock; - -use_dfl_pwq: - mutex_lock(&wq->mutex); - spin_lock_irq(&wq->dfl_pwq->pool->lock); - get_pwq(wq->dfl_pwq); - spin_unlock_irq(&wq->dfl_pwq->pool->lock); - old_pwq = numa_pwq_tbl_install(wq, node, wq->dfl_pwq); -out_unlock: - mutex_unlock(&wq->mutex); - put_pwq_unlocked(old_pwq); -} - -static int alloc_and_link_pwqs(struct workqueue_struct *wq) -{ - bool highpri = wq->flags & WQ_HIGHPRI; - int cpu, ret; - - if (!(wq->flags & WQ_UNBOUND)) { - wq->cpu_pwqs = alloc_percpu(struct pool_workqueue); - if (!wq->cpu_pwqs) - return -ENOMEM; - - for_each_possible_cpu(cpu) { - struct pool_workqueue *pwq = - per_cpu_ptr(wq->cpu_pwqs, cpu); - struct worker_pool *cpu_pools = - per_cpu(cpu_worker_pools, cpu); - - init_pwq(pwq, wq, &cpu_pools[highpri]); - - mutex_lock(&wq->mutex); - link_pwq(pwq); - mutex_unlock(&wq->mutex); - } - return 0; - } else if (wq->flags & __WQ_ORDERED) { - ret = apply_workqueue_attrs(wq, ordered_wq_attrs[highpri]); - /* there should only be single pwq for ordering guarantee */ - WARN(!ret && (wq->pwqs.next != &wq->dfl_pwq->pwqs_node || - wq->pwqs.prev != &wq->dfl_pwq->pwqs_node), - "ordering guarantee broken for workqueue %s\n", wq->name); - return ret; - } else { - return apply_workqueue_attrs(wq, unbound_std_wq_attrs[highpri]); - } -} - -static int wq_clamp_max_active(int max_active, unsigned int flags, - const char *name) -{ - int lim = flags & WQ_UNBOUND ? WQ_UNBOUND_MAX_ACTIVE : WQ_MAX_ACTIVE; - - if (max_active < 1 || max_active > lim) - pr_warn("workqueue: max_active %d requested for %s is out of range, clamping between %d and %d\n", - max_active, name, 1, lim); - - return clamp_val(max_active, 1, lim); -} - -struct workqueue_struct *__alloc_workqueue_key(const char *fmt, - unsigned int flags, - int max_active, - struct lock_class_key *key, - const char *lock_name, ...) -{ - size_t tbl_size = 0; - va_list args; - struct workqueue_struct *wq; - struct pool_workqueue *pwq; - - /* see the comment above the definition of WQ_POWER_EFFICIENT */ - if ((flags & WQ_POWER_EFFICIENT) && wq_power_efficient) - flags |= WQ_UNBOUND; - - /* allocate wq and format name */ - if (flags & WQ_UNBOUND) - tbl_size = nr_node_ids * sizeof(wq->numa_pwq_tbl[0]); - - wq = kzalloc(sizeof(*wq) + tbl_size, GFP_KERNEL); - if (!wq) - return NULL; - - if (flags & WQ_UNBOUND) { - wq->unbound_attrs = alloc_workqueue_attrs(GFP_KERNEL); - if (!wq->unbound_attrs) - goto err_free_wq; - } - - va_start(args, lock_name); - vsnprintf(wq->name, sizeof(wq->name), fmt, args); - va_end(args); - - max_active = max_active ?: WQ_DFL_ACTIVE; - max_active = wq_clamp_max_active(max_active, flags, wq->name); - - /* init wq */ - wq->flags = flags; - wq->saved_max_active = max_active; - mutex_init(&wq->mutex); - atomic_set(&wq->nr_pwqs_to_flush, 0); - INIT_LIST_HEAD(&wq->pwqs); - INIT_LIST_HEAD(&wq->flusher_queue); - INIT_LIST_HEAD(&wq->flusher_overflow); - INIT_LIST_HEAD(&wq->maydays); - - lockdep_init_map(&wq->lockdep_map, lock_name, key, 0); - INIT_LIST_HEAD(&wq->list); - - if (alloc_and_link_pwqs(wq) < 0) - goto err_free_wq; - - /* - * Workqueues which may be used during memory reclaim should - * have a rescuer to guarantee forward progress. - */ - if (flags & WQ_MEM_RECLAIM) { - struct worker *rescuer; - - rescuer = alloc_worker(NUMA_NO_NODE); - if (!rescuer) - goto err_destroy; - - rescuer->rescue_wq = wq; - rescuer->task = kthread_create(rescuer_thread, rescuer, "%s", - wq->name); - if (IS_ERR(rescuer->task)) { - kfree(rescuer); - goto err_destroy; - } - - wq->rescuer = rescuer; - kthread_bind_mask(rescuer->task, cpu_possible_mask); - wake_up_process(rescuer->task); - } - - if ((wq->flags & WQ_SYSFS) && workqueue_sysfs_register(wq)) - goto err_destroy; - - /* - * wq_pool_mutex protects global freeze state and workqueues list. - * Grab it, adjust max_active and add the new @wq to workqueues - * list. - */ - mutex_lock(&wq_pool_mutex); - - mutex_lock(&wq->mutex); - for_each_pwq(pwq, wq) - pwq_adjust_max_active(pwq); - mutex_unlock(&wq->mutex); - - list_add_tail_rcu(&wq->list, &workqueues); - - mutex_unlock(&wq_pool_mutex); - - return wq; - -err_free_wq: - free_workqueue_attrs(wq->unbound_attrs); - kfree(wq); - return NULL; -err_destroy: - destroy_workqueue(wq); - return NULL; -} -EXPORT_SYMBOL_GPL(__alloc_workqueue_key); - -/** - * destroy_workqueue - safely terminate a workqueue - * @wq: target workqueue - * - * Safely destroy a workqueue. All work currently pending will be done first. - */ -void destroy_workqueue(struct workqueue_struct *wq) -{ - struct pool_workqueue *pwq; - int node; - - /* drain it before proceeding with destruction */ - drain_workqueue(wq); - - /* sanity checks */ - mutex_lock(&wq->mutex); - for_each_pwq(pwq, wq) { - int i; - - for (i = 0; i < WORK_NR_COLORS; i++) { - if (WARN_ON(pwq->nr_in_flight[i])) { - mutex_unlock(&wq->mutex); - return; - } - } - - if (WARN_ON((pwq != wq->dfl_pwq) && (pwq->refcnt > 1)) || - WARN_ON(pwq->nr_active) || - WARN_ON(!list_empty(&pwq->delayed_works))) { - mutex_unlock(&wq->mutex); - return; - } - } - mutex_unlock(&wq->mutex); - - /* - * wq list is used to freeze wq, remove from list after - * flushing is complete in case freeze races us. - */ - mutex_lock(&wq_pool_mutex); - list_del_rcu(&wq->list); - mutex_unlock(&wq_pool_mutex); - - workqueue_sysfs_unregister(wq); - - if (wq->rescuer) - kthread_stop(wq->rescuer->task); - - if (!(wq->flags & WQ_UNBOUND)) { - /* - * The base ref is never dropped on per-cpu pwqs. Directly - * schedule RCU free. - */ - call_rcu_sched(&wq->rcu, rcu_free_wq); - } else { - /* - * We're the sole accessor of @wq at this point. Directly - * access numa_pwq_tbl[] and dfl_pwq to put the base refs. - * @wq will be freed when the last pwq is released. - */ - for_each_node(node) { - pwq = rcu_access_pointer(wq->numa_pwq_tbl[node]); - RCU_INIT_POINTER(wq->numa_pwq_tbl[node], NULL); - put_pwq_unlocked(pwq); - } - - /* - * Put dfl_pwq. @wq may be freed any time after dfl_pwq is - * put. Don't access it afterwards. - */ - pwq = wq->dfl_pwq; - wq->dfl_pwq = NULL; - put_pwq_unlocked(pwq); - } -} -EXPORT_SYMBOL_GPL(destroy_workqueue); - -/** - * workqueue_set_max_active - adjust max_active of a workqueue - * @wq: target workqueue - * @max_active: new max_active value. - * - * Set max_active of @wq to @max_active. - * - * CONTEXT: - * Don't call from IRQ context. - */ -void workqueue_set_max_active(struct workqueue_struct *wq, int max_active) -{ - struct pool_workqueue *pwq; - - /* disallow meddling with max_active for ordered workqueues */ - if (WARN_ON(wq->flags & __WQ_ORDERED)) - return; - - max_active = wq_clamp_max_active(max_active, wq->flags, wq->name); - - mutex_lock(&wq->mutex); - - wq->saved_max_active = max_active; - - for_each_pwq(pwq, wq) - pwq_adjust_max_active(pwq); - - mutex_unlock(&wq->mutex); -} -EXPORT_SYMBOL_GPL(workqueue_set_max_active); - -/** - * current_is_workqueue_rescuer - is %current workqueue rescuer? - * - * Determine whether %current is a workqueue rescuer. Can be used from - * work functions to determine whether it's being run off the rescuer task. - * - * Return: %true if %current is a workqueue rescuer. %false otherwise. - */ -bool current_is_workqueue_rescuer(void) -{ - struct worker *worker = current_wq_worker(); - - return worker && worker->rescue_wq; -} - -/** - * workqueue_congested - test whether a workqueue is congested - * @cpu: CPU in question - * @wq: target workqueue - * - * Test whether @wq's cpu workqueue for @cpu is congested. There is - * no synchronization around this function and the test result is - * unreliable and only useful as advisory hints or for debugging. - * - * If @cpu is WORK_CPU_UNBOUND, the test is performed on the local CPU. - * Note that both per-cpu and unbound workqueues may be associated with - * multiple pool_workqueues which have separate congested states. A - * workqueue being congested on one CPU doesn't mean the workqueue is also - * contested on other CPUs / NUMA nodes. - * - * Return: - * %true if congested, %false otherwise. - */ -bool workqueue_congested(int cpu, struct workqueue_struct *wq) -{ - struct pool_workqueue *pwq; - bool ret; - - rcu_read_lock_sched(); - - if (cpu == WORK_CPU_UNBOUND) - cpu = smp_processor_id(); - - if (!(wq->flags & WQ_UNBOUND)) - pwq = per_cpu_ptr(wq->cpu_pwqs, cpu); - else - pwq = unbound_pwq_by_node(wq, cpu_to_node(cpu)); - - ret = !list_empty(&pwq->delayed_works); - rcu_read_unlock_sched(); - - return ret; -} -EXPORT_SYMBOL_GPL(workqueue_congested); - -/** - * work_busy - test whether a work is currently pending or running - * @work: the work to be tested - * - * Test whether @work is currently pending or running. There is no - * synchronization around this function and the test result is - * unreliable and only useful as advisory hints or for debugging. - * - * Return: - * OR'd bitmask of WORK_BUSY_* bits. - */ -unsigned int work_busy(struct work_struct *work) -{ - struct worker_pool *pool; - unsigned long flags; - unsigned int ret = 0; - - if (work_pending(work)) - ret |= WORK_BUSY_PENDING; - - local_irq_save(flags); - pool = get_work_pool(work); - if (pool) { - spin_lock(&pool->lock); - if (find_worker_executing_work(pool, work)) - ret |= WORK_BUSY_RUNNING; - spin_unlock(&pool->lock); - } - local_irq_restore(flags); - - return ret; -} -EXPORT_SYMBOL_GPL(work_busy); - -/** - * set_worker_desc - set description for the current work item - * @fmt: printf-style format string - * @...: arguments for the format string - * - * This function can be called by a running work function to describe what - * the work item is about. If the worker task gets dumped, this - * information will be printed out together to help debugging. The - * description can be at most WORKER_DESC_LEN including the trailing '\0'. - */ -void set_worker_desc(const char *fmt, ...) -{ - struct worker *worker = current_wq_worker(); - va_list args; - - if (worker) { - va_start(args, fmt); - vsnprintf(worker->desc, sizeof(worker->desc), fmt, args); - va_end(args); - worker->desc_valid = true; - } -} - -/** - * print_worker_info - print out worker information and description - * @log_lvl: the log level to use when printing - * @task: target task - * - * If @task is a worker and currently executing a work item, print out the - * name of the workqueue being serviced and worker description set with - * set_worker_desc() by the currently executing work item. - * - * This function can be safely called on any task as long as the - * task_struct itself is accessible. While safe, this function isn't - * synchronized and may print out mixups or garbages of limited length. - */ -void print_worker_info(const char *log_lvl, struct task_struct *task) -{ - work_func_t *fn = NULL; - char name[WQ_NAME_LEN] = { }; - char desc[WORKER_DESC_LEN] = { }; - struct pool_workqueue *pwq = NULL; - struct workqueue_struct *wq = NULL; - bool desc_valid = false; - struct worker *worker; - - if (!(task->flags & PF_WQ_WORKER)) - return; - - /* - * This function is called without any synchronization and @task - * could be in any state. Be careful with dereferences. - */ - worker = kthread_probe_data(task); - - /* - * Carefully copy the associated workqueue's workfn and name. Keep - * the original last '\0' in case the original contains garbage. - */ - probe_kernel_read(&fn, &worker->current_func, sizeof(fn)); - probe_kernel_read(&pwq, &worker->current_pwq, sizeof(pwq)); - probe_kernel_read(&wq, &pwq->wq, sizeof(wq)); - probe_kernel_read(name, wq->name, sizeof(name) - 1); - - /* copy worker description */ - probe_kernel_read(&desc_valid, &worker->desc_valid, sizeof(desc_valid)); - if (desc_valid) - probe_kernel_read(desc, worker->desc, sizeof(desc) - 1); - - if (fn || name[0] || desc[0]) { - printk("%sWorkqueue: %s %pf", log_lvl, name, fn); - if (desc[0]) - pr_cont(" (%s)", desc); - pr_cont("\n"); - } -} - -static void pr_cont_pool_info(struct worker_pool *pool) -{ - pr_cont(" cpus=%*pbl", nr_cpumask_bits, pool->attrs->cpumask); - if (pool->node != NUMA_NO_NODE) - pr_cont(" node=%d", pool->node); - pr_cont(" flags=0x%x nice=%d", pool->flags, pool->attrs->nice); -} - -static void pr_cont_work(bool comma, struct work_struct *work) -{ - if (work->func == wq_barrier_func) { - struct wq_barrier *barr; - - barr = container_of(work, struct wq_barrier, work); - - pr_cont("%s BAR(%d)", comma ? "," : "", - task_pid_nr(barr->task)); - } else { - pr_cont("%s %pf", comma ? "," : "", work->func); - } -} - -static void show_pwq(struct pool_workqueue *pwq) -{ - struct worker_pool *pool = pwq->pool; - struct work_struct *work; - struct worker *worker; - bool has_in_flight = false, has_pending = false; - int bkt; - - pr_info(" pwq %d:", pool->id); - pr_cont_pool_info(pool); - - pr_cont(" active=%d/%d%s\n", pwq->nr_active, pwq->max_active, - !list_empty(&pwq->mayday_node) ? " MAYDAY" : ""); - - hash_for_each(pool->busy_hash, bkt, worker, hentry) { - if (worker->current_pwq == pwq) { - has_in_flight = true; - break; - } - } - if (has_in_flight) { - bool comma = false; - - pr_info(" in-flight:"); - hash_for_each(pool->busy_hash, bkt, worker, hentry) { - if (worker->current_pwq != pwq) - continue; - - pr_cont("%s %d%s:%pf", comma ? "," : "", - task_pid_nr(worker->task), - worker == pwq->wq->rescuer ? "(RESCUER)" : "", - worker->current_func); - list_for_each_entry(work, &worker->scheduled, entry) - pr_cont_work(false, work); - comma = true; - } - pr_cont("\n"); - } - - list_for_each_entry(work, &pool->worklist, entry) { - if (get_work_pwq(work) == pwq) { - has_pending = true; - break; - } - } - if (has_pending) { - bool comma = false; - - pr_info(" pending:"); - list_for_each_entry(work, &pool->worklist, entry) { - if (get_work_pwq(work) != pwq) - continue; - - pr_cont_work(comma, work); - comma = !(*work_data_bits(work) & WORK_STRUCT_LINKED); - } - pr_cont("\n"); - } - - if (!list_empty(&pwq->delayed_works)) { - bool comma = false; - - pr_info(" delayed:"); - list_for_each_entry(work, &pwq->delayed_works, entry) { - pr_cont_work(comma, work); - comma = !(*work_data_bits(work) & WORK_STRUCT_LINKED); - } - pr_cont("\n"); - } -} - -/** - * show_workqueue_state - dump workqueue state - * - * Called from a sysrq handler or try_to_freeze_tasks() and prints out - * all busy workqueues and pools. - */ -void show_workqueue_state(void) -{ - struct workqueue_struct *wq; - struct worker_pool *pool; - unsigned long flags; - int pi; - - rcu_read_lock_sched(); - - pr_info("Showing busy workqueues and worker pools:\n"); - - list_for_each_entry_rcu(wq, &workqueues, list) { - struct pool_workqueue *pwq; - bool idle = true; - - for_each_pwq(pwq, wq) { - if (pwq->nr_active || !list_empty(&pwq->delayed_works)) { - idle = false; - break; - } - } - if (idle) - continue; - - pr_info("workqueue %s: flags=0x%x\n", wq->name, wq->flags); - - for_each_pwq(pwq, wq) { - spin_lock_irqsave(&pwq->pool->lock, flags); - if (pwq->nr_active || !list_empty(&pwq->delayed_works)) - show_pwq(pwq); - spin_unlock_irqrestore(&pwq->pool->lock, flags); - } - } - - for_each_pool(pool, pi) { - struct worker *worker; - bool first = true; - - spin_lock_irqsave(&pool->lock, flags); - if (pool->nr_workers == pool->nr_idle) - goto next_pool; - - pr_info("pool %d:", pool->id); - pr_cont_pool_info(pool); - pr_cont(" hung=%us workers=%d", - jiffies_to_msecs(jiffies - pool->watchdog_ts) / 1000, - pool->nr_workers); - if (pool->manager) - pr_cont(" manager: %d", - task_pid_nr(pool->manager->task)); - list_for_each_entry(worker, &pool->idle_list, entry) { - pr_cont(" %s%d", first ? "idle: " : "", - task_pid_nr(worker->task)); - first = false; - } - pr_cont("\n"); - next_pool: - spin_unlock_irqrestore(&pool->lock, flags); - } - - rcu_read_unlock_sched(); -} - -/* - * CPU hotplug. - * - * There are two challenges in supporting CPU hotplug. Firstly, there - * are a lot of assumptions on strong associations among work, pwq and - * pool which make migrating pending and scheduled works very - * difficult to implement without impacting hot paths. Secondly, - * worker pools serve mix of short, long and very long running works making - * blocked draining impractical. - * - * This is solved by allowing the pools to be disassociated from the CPU - * running as an unbound one and allowing it to be reattached later if the - * cpu comes back online. - */ - -static void wq_unbind_fn(struct work_struct *work) -{ - int cpu = smp_processor_id(); - struct worker_pool *pool; - struct worker *worker; - - for_each_cpu_worker_pool(pool, cpu) { - mutex_lock(&pool->attach_mutex); - spin_lock_irq(&pool->lock); - - /* - * We've blocked all attach/detach operations. Make all workers - * unbound and set DISASSOCIATED. Before this, all workers - * except for the ones which are still executing works from - * before the last CPU down must be on the cpu. After - * this, they may become diasporas. - */ - for_each_pool_worker(worker, pool) - worker->flags |= WORKER_UNBOUND; - - pool->flags |= POOL_DISASSOCIATED; - - spin_unlock_irq(&pool->lock); - mutex_unlock(&pool->attach_mutex); - - /* - * Call schedule() so that we cross rq->lock and thus can - * guarantee sched callbacks see the %WORKER_UNBOUND flag. - * This is necessary as scheduler callbacks may be invoked - * from other cpus. - */ - schedule(); - - /* - * Sched callbacks are disabled now. Zap nr_running. - * After this, nr_running stays zero and need_more_worker() - * and keep_working() are always true as long as the - * worklist is not empty. This pool now behaves as an - * unbound (in terms of concurrency management) pool which - * are served by workers tied to the pool. - */ - atomic_set(&pool->nr_running, 0); - - /* - * With concurrency management just turned off, a busy - * worker blocking could lead to lengthy stalls. Kick off - * unbound chain execution of currently pending work items. - */ - spin_lock_irq(&pool->lock); - wake_up_worker(pool); - spin_unlock_irq(&pool->lock); - } -} - -/** - * rebind_workers - rebind all workers of a pool to the associated CPU - * @pool: pool of interest - * - * @pool->cpu is coming online. Rebind all workers to the CPU. - */ -static void rebind_workers(struct worker_pool *pool) -{ - struct worker *worker; - - lockdep_assert_held(&pool->attach_mutex); - - /* - * Restore CPU affinity of all workers. As all idle workers should - * be on the run-queue of the associated CPU before any local - * wake-ups for concurrency management happen, restore CPU affinity - * of all workers first and then clear UNBOUND. As we're called - * from CPU_ONLINE, the following shouldn't fail. - */ - for_each_pool_worker(worker, pool) - WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task, - pool->attrs->cpumask) < 0); - - spin_lock_irq(&pool->lock); - - /* - * XXX: CPU hotplug notifiers are weird and can call DOWN_FAILED - * w/o preceding DOWN_PREPARE. Work around it. CPU hotplug is - * being reworked and this can go away in time. - */ - if (!(pool->flags & POOL_DISASSOCIATED)) { - spin_unlock_irq(&pool->lock); - return; - } - - pool->flags &= ~POOL_DISASSOCIATED; - - for_each_pool_worker(worker, pool) { - unsigned int worker_flags = worker->flags; - - /* - * A bound idle worker should actually be on the runqueue - * of the associated CPU for local wake-ups targeting it to - * work. Kick all idle workers so that they migrate to the - * associated CPU. Doing this in the same loop as - * replacing UNBOUND with REBOUND is safe as no worker will - * be bound before @pool->lock is released. - */ - if (worker_flags & WORKER_IDLE) - wake_up_process(worker->task); - - /* - * We want to clear UNBOUND but can't directly call - * worker_clr_flags() or adjust nr_running. Atomically - * replace UNBOUND with another NOT_RUNNING flag REBOUND. - * @worker will clear REBOUND using worker_clr_flags() when - * it initiates the next execution cycle thus restoring - * concurrency management. Note that when or whether - * @worker clears REBOUND doesn't affect correctness. - * - * ACCESS_ONCE() is necessary because @worker->flags may be - * tested without holding any lock in - * wq_worker_waking_up(). Without it, NOT_RUNNING test may - * fail incorrectly leading to premature concurrency - * management operations. - */ - WARN_ON_ONCE(!(worker_flags & WORKER_UNBOUND)); - worker_flags |= WORKER_REBOUND; - worker_flags &= ~WORKER_UNBOUND; - ACCESS_ONCE(worker->flags) = worker_flags; - } - - spin_unlock_irq(&pool->lock); -} - -/** - * restore_unbound_workers_cpumask - restore cpumask of unbound workers - * @pool: unbound pool of interest - * @cpu: the CPU which is coming up - * - * An unbound pool may end up with a cpumask which doesn't have any online - * CPUs. When a worker of such pool get scheduled, the scheduler resets - * its cpus_allowed. If @cpu is in @pool's cpumask which didn't have any - * online CPU before, cpus_allowed of all its workers should be restored. - */ -static void restore_unbound_workers_cpumask(struct worker_pool *pool, int cpu) -{ - static cpumask_t cpumask; - struct worker *worker; - - lockdep_assert_held(&pool->attach_mutex); - - /* is @cpu allowed for @pool? */ - if (!cpumask_test_cpu(cpu, pool->attrs->cpumask)) - return; - - cpumask_and(&cpumask, pool->attrs->cpumask, cpu_online_mask); - - /* as we're called from CPU_ONLINE, the following shouldn't fail */ - for_each_pool_worker(worker, pool) - WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task, &cpumask) < 0); -} - -int workqueue_prepare_cpu(unsigned int cpu) -{ - struct worker_pool *pool; - - for_each_cpu_worker_pool(pool, cpu) { - if (pool->nr_workers) - continue; - if (!create_worker(pool)) - return -ENOMEM; - } - return 0; -} - -int workqueue_online_cpu(unsigned int cpu) -{ - struct worker_pool *pool; - struct workqueue_struct *wq; - int pi; - - mutex_lock(&wq_pool_mutex); - - for_each_pool(pool, pi) { - mutex_lock(&pool->attach_mutex); - - if (pool->cpu == cpu) - rebind_workers(pool); - else if (pool->cpu < 0) - restore_unbound_workers_cpumask(pool, cpu); - - mutex_unlock(&pool->attach_mutex); - } - - /* update NUMA affinity of unbound workqueues */ - list_for_each_entry(wq, &workqueues, list) - wq_update_unbound_numa(wq, cpu, true); - - mutex_unlock(&wq_pool_mutex); - return 0; -} - -int workqueue_offline_cpu(unsigned int cpu) -{ - struct work_struct unbind_work; - struct workqueue_struct *wq; - - /* unbinding per-cpu workers should happen on the local CPU */ - INIT_WORK_ONSTACK(&unbind_work, wq_unbind_fn); - queue_work_on(cpu, system_highpri_wq, &unbind_work); - - /* update NUMA affinity of unbound workqueues */ - mutex_lock(&wq_pool_mutex); - list_for_each_entry(wq, &workqueues, list) - wq_update_unbound_numa(wq, cpu, false); - mutex_unlock(&wq_pool_mutex); - - /* wait for per-cpu unbinding to finish */ - flush_work(&unbind_work); - destroy_work_on_stack(&unbind_work); - return 0; -} - -#ifdef CONFIG_SMP - -struct work_for_cpu { - struct work_struct work; - long (*fn)(void *); - void *arg; - long ret; -}; - -static void work_for_cpu_fn(struct work_struct *work) -{ - struct work_for_cpu *wfc = container_of(work, struct work_for_cpu, work); - - wfc->ret = wfc->fn(wfc->arg); -} - -/** - * work_on_cpu - run a function in thread context on a particular cpu - * @cpu: the cpu to run on - * @fn: the function to run - * @arg: the function arg - * - * It is up to the caller to ensure that the cpu doesn't go offline. - * The caller must not hold any locks which would prevent @fn from completing. - * - * Return: The value @fn returns. - */ -long work_on_cpu(int cpu, long (*fn)(void *), void *arg) -{ - struct work_for_cpu wfc = { .fn = fn, .arg = arg }; - - INIT_WORK_ONSTACK(&wfc.work, work_for_cpu_fn); - schedule_work_on(cpu, &wfc.work); - flush_work(&wfc.work); - destroy_work_on_stack(&wfc.work); - return wfc.ret; -} -EXPORT_SYMBOL_GPL(work_on_cpu); -#endif /* CONFIG_SMP */ - -#ifdef CONFIG_FREEZER - -/** - * freeze_workqueues_begin - begin freezing workqueues - * - * Start freezing workqueues. After this function returns, all freezable - * workqueues will queue new works to their delayed_works list instead of - * pool->worklist. - * - * CONTEXT: - * Grabs and releases wq_pool_mutex, wq->mutex and pool->lock's. - */ -void freeze_workqueues_begin(void) -{ - struct workqueue_struct *wq; - struct pool_workqueue *pwq; - - mutex_lock(&wq_pool_mutex); - - WARN_ON_ONCE(workqueue_freezing); - workqueue_freezing = true; - - list_for_each_entry(wq, &workqueues, list) { - mutex_lock(&wq->mutex); - for_each_pwq(pwq, wq) - pwq_adjust_max_active(pwq); - mutex_unlock(&wq->mutex); - } - - mutex_unlock(&wq_pool_mutex); -} - -/** - * freeze_workqueues_busy - are freezable workqueues still busy? - * - * Check whether freezing is complete. This function must be called - * between freeze_workqueues_begin() and thaw_workqueues(). - * - * CONTEXT: - * Grabs and releases wq_pool_mutex. - * - * Return: - * %true if some freezable workqueues are still busy. %false if freezing - * is complete. - */ -bool freeze_workqueues_busy(void) -{ - bool busy = false; - struct workqueue_struct *wq; - struct pool_workqueue *pwq; - - mutex_lock(&wq_pool_mutex); - - WARN_ON_ONCE(!workqueue_freezing); - - list_for_each_entry(wq, &workqueues, list) { - if (!(wq->flags & WQ_FREEZABLE)) - continue; - /* - * nr_active is monotonically decreasing. It's safe - * to peek without lock. - */ - rcu_read_lock_sched(); - for_each_pwq(pwq, wq) { - WARN_ON_ONCE(pwq->nr_active < 0); - if (pwq->nr_active) { - busy = true; - rcu_read_unlock_sched(); - goto out_unlock; - } - } - rcu_read_unlock_sched(); - } -out_unlock: - mutex_unlock(&wq_pool_mutex); - return busy; -} - -/** - * thaw_workqueues - thaw workqueues - * - * Thaw workqueues. Normal queueing is restored and all collected - * frozen works are transferred to their respective pool worklists. - * - * CONTEXT: - * Grabs and releases wq_pool_mutex, wq->mutex and pool->lock's. - */ -void thaw_workqueues(void) -{ - struct workqueue_struct *wq; - struct pool_workqueue *pwq; - - mutex_lock(&wq_pool_mutex); - - if (!workqueue_freezing) - goto out_unlock; - - workqueue_freezing = false; - - /* restore max_active and repopulate worklist */ - list_for_each_entry(wq, &workqueues, list) { - mutex_lock(&wq->mutex); - for_each_pwq(pwq, wq) - pwq_adjust_max_active(pwq); - mutex_unlock(&wq->mutex); - } - -out_unlock: - mutex_unlock(&wq_pool_mutex); -} -#endif /* CONFIG_FREEZER */ - -static int workqueue_apply_unbound_cpumask(void) -{ - LIST_HEAD(ctxs); - int ret = 0; - struct workqueue_struct *wq; - struct apply_wqattrs_ctx *ctx, *n; - - lockdep_assert_held(&wq_pool_mutex); - - list_for_each_entry(wq, &workqueues, list) { - if (!(wq->flags & WQ_UNBOUND)) - continue; - /* creating multiple pwqs breaks ordering guarantee */ - if (wq->flags & __WQ_ORDERED) - continue; - - ctx = apply_wqattrs_prepare(wq, wq->unbound_attrs); - if (!ctx) { - ret = -ENOMEM; - break; - } - - list_add_tail(&ctx->list, &ctxs); - } - - list_for_each_entry_safe(ctx, n, &ctxs, list) { - if (!ret) - apply_wqattrs_commit(ctx); - apply_wqattrs_cleanup(ctx); - } - - return ret; -} - -/** - * workqueue_set_unbound_cpumask - Set the low-level unbound cpumask - * @cpumask: the cpumask to set - * - * The low-level workqueues cpumask is a global cpumask that limits - * the affinity of all unbound workqueues. This function check the @cpumask - * and apply it to all unbound workqueues and updates all pwqs of them. - * - * Retun: 0 - Success - * -EINVAL - Invalid @cpumask - * -ENOMEM - Failed to allocate memory for attrs or pwqs. - */ -int workqueue_set_unbound_cpumask(cpumask_var_t cpumask) -{ - int ret = -EINVAL; - cpumask_var_t saved_cpumask; - - if (!zalloc_cpumask_var(&saved_cpumask, GFP_KERNEL)) - return -ENOMEM; - - cpumask_and(cpumask, cpumask, cpu_possible_mask); - if (!cpumask_empty(cpumask)) { - apply_wqattrs_lock(); - - /* save the old wq_unbound_cpumask. */ - cpumask_copy(saved_cpumask, wq_unbound_cpumask); - - /* update wq_unbound_cpumask at first and apply it to wqs. */ - cpumask_copy(wq_unbound_cpumask, cpumask); - ret = workqueue_apply_unbound_cpumask(); - - /* restore the wq_unbound_cpumask when failed. */ - if (ret < 0) - cpumask_copy(wq_unbound_cpumask, saved_cpumask); - - apply_wqattrs_unlock(); - } - - free_cpumask_var(saved_cpumask); - return ret; -} - -#ifdef CONFIG_SYSFS -/* - * Workqueues with WQ_SYSFS flag set is visible to userland via - * /sys/bus/workqueue/devices/WQ_NAME. All visible workqueues have the - * following attributes. - * - * per_cpu RO bool : whether the workqueue is per-cpu or unbound - * max_active RW int : maximum number of in-flight work items - * - * Unbound workqueues have the following extra attributes. - * - * id RO int : the associated pool ID - * nice RW int : nice value of the workers - * cpumask RW mask : bitmask of allowed CPUs for the workers - */ -struct wq_device { - struct workqueue_struct *wq; - struct device dev; -}; - -static struct workqueue_struct *dev_to_wq(struct device *dev) -{ - struct wq_device *wq_dev = container_of(dev, struct wq_device, dev); - - return wq_dev->wq; -} - -static ssize_t per_cpu_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct workqueue_struct *wq = dev_to_wq(dev); - - return scnprintf(buf, PAGE_SIZE, "%d\n", (bool)!(wq->flags & WQ_UNBOUND)); -} -static DEVICE_ATTR_RO(per_cpu); - -static ssize_t max_active_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct workqueue_struct *wq = dev_to_wq(dev); - - return scnprintf(buf, PAGE_SIZE, "%d\n", wq->saved_max_active); -} - -static ssize_t max_active_store(struct device *dev, - struct device_attribute *attr, const char *buf, - size_t count) -{ - struct workqueue_struct *wq = dev_to_wq(dev); - int val; - - if (sscanf(buf, "%d", &val) != 1 || val <= 0) - return -EINVAL; - - workqueue_set_max_active(wq, val); - return count; -} -static DEVICE_ATTR_RW(max_active); - -static struct attribute *wq_sysfs_attrs[] = { - &dev_attr_per_cpu.attr, - &dev_attr_max_active.attr, - NULL, -}; -ATTRIBUTE_GROUPS(wq_sysfs); - -static ssize_t wq_pool_ids_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct workqueue_struct *wq = dev_to_wq(dev); - const char *delim = ""; - int node, written = 0; - - rcu_read_lock_sched(); - for_each_node(node) { - written += scnprintf(buf + written, PAGE_SIZE - written, - "%s%d:%d", delim, node, - unbound_pwq_by_node(wq, node)->pool->id); - delim = " "; - } - written += scnprintf(buf + written, PAGE_SIZE - written, "\n"); - rcu_read_unlock_sched(); - - return written; -} - -static ssize_t wq_nice_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct workqueue_struct *wq = dev_to_wq(dev); - int written; - - mutex_lock(&wq->mutex); - written = scnprintf(buf, PAGE_SIZE, "%d\n", wq->unbound_attrs->nice); - mutex_unlock(&wq->mutex); - - return written; -} - -/* prepare workqueue_attrs for sysfs store operations */ -static struct workqueue_attrs *wq_sysfs_prep_attrs(struct workqueue_struct *wq) -{ - struct workqueue_attrs *attrs; - - lockdep_assert_held(&wq_pool_mutex); - - attrs = alloc_workqueue_attrs(GFP_KERNEL); - if (!attrs) - return NULL; - - copy_workqueue_attrs(attrs, wq->unbound_attrs); - return attrs; -} - -static ssize_t wq_nice_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct workqueue_struct *wq = dev_to_wq(dev); - struct workqueue_attrs *attrs; - int ret = -ENOMEM; - - apply_wqattrs_lock(); - - attrs = wq_sysfs_prep_attrs(wq); - if (!attrs) - goto out_unlock; - - if (sscanf(buf, "%d", &attrs->nice) == 1 && - attrs->nice >= MIN_NICE && attrs->nice <= MAX_NICE) - ret = apply_workqueue_attrs_locked(wq, attrs); - else - ret = -EINVAL; - -out_unlock: - apply_wqattrs_unlock(); - free_workqueue_attrs(attrs); - return ret ?: count; -} - -static ssize_t wq_cpumask_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct workqueue_struct *wq = dev_to_wq(dev); - int written; - - mutex_lock(&wq->mutex); - written = scnprintf(buf, PAGE_SIZE, "%*pb\n", - cpumask_pr_args(wq->unbound_attrs->cpumask)); - mutex_unlock(&wq->mutex); - return written; -} - -static ssize_t wq_cpumask_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct workqueue_struct *wq = dev_to_wq(dev); - struct workqueue_attrs *attrs; - int ret = -ENOMEM; - - apply_wqattrs_lock(); - - attrs = wq_sysfs_prep_attrs(wq); - if (!attrs) - goto out_unlock; - - ret = cpumask_parse(buf, attrs->cpumask); - if (!ret) - ret = apply_workqueue_attrs_locked(wq, attrs); - -out_unlock: - apply_wqattrs_unlock(); - free_workqueue_attrs(attrs); - return ret ?: count; -} - -static ssize_t wq_numa_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct workqueue_struct *wq = dev_to_wq(dev); - int written; - - mutex_lock(&wq->mutex); - written = scnprintf(buf, PAGE_SIZE, "%d\n", - !wq->unbound_attrs->no_numa); - mutex_unlock(&wq->mutex); - - return written; -} - -static ssize_t wq_numa_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct workqueue_struct *wq = dev_to_wq(dev); - struct workqueue_attrs *attrs; - int v, ret = -ENOMEM; - - apply_wqattrs_lock(); - - attrs = wq_sysfs_prep_attrs(wq); - if (!attrs) - goto out_unlock; - - ret = -EINVAL; - if (sscanf(buf, "%d", &v) == 1) { - attrs->no_numa = !v; - ret = apply_workqueue_attrs_locked(wq, attrs); - } - -out_unlock: - apply_wqattrs_unlock(); - free_workqueue_attrs(attrs); - return ret ?: count; -} - -static struct device_attribute wq_sysfs_unbound_attrs[] = { - __ATTR(pool_ids, 0444, wq_pool_ids_show, NULL), - __ATTR(nice, 0644, wq_nice_show, wq_nice_store), - __ATTR(cpumask, 0644, wq_cpumask_show, wq_cpumask_store), - __ATTR(numa, 0644, wq_numa_show, wq_numa_store), - __ATTR_NULL, -}; - -static struct bus_type wq_subsys = { - .name = "workqueue", - .dev_groups = wq_sysfs_groups, -}; - -static ssize_t wq_unbound_cpumask_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - int written; - - mutex_lock(&wq_pool_mutex); - written = scnprintf(buf, PAGE_SIZE, "%*pb\n", - cpumask_pr_args(wq_unbound_cpumask)); - mutex_unlock(&wq_pool_mutex); - - return written; -} - -static ssize_t wq_unbound_cpumask_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - cpumask_var_t cpumask; - int ret; - - if (!zalloc_cpumask_var(&cpumask, GFP_KERNEL)) - return -ENOMEM; - - ret = cpumask_parse(buf, cpumask); - if (!ret) - ret = workqueue_set_unbound_cpumask(cpumask); - - free_cpumask_var(cpumask); - return ret ? ret : count; -} - -static struct device_attribute wq_sysfs_cpumask_attr = - __ATTR(cpumask, 0644, wq_unbound_cpumask_show, - wq_unbound_cpumask_store); - -static int __init wq_sysfs_init(void) -{ - int err; - - err = subsys_virtual_register(&wq_subsys, NULL); - if (err) - return err; - - return device_create_file(wq_subsys.dev_root, &wq_sysfs_cpumask_attr); -} -core_initcall(wq_sysfs_init); - -static void wq_device_release(struct device *dev) -{ - struct wq_device *wq_dev = container_of(dev, struct wq_device, dev); - - kfree(wq_dev); -} - -/** - * workqueue_sysfs_register - make a workqueue visible in sysfs - * @wq: the workqueue to register - * - * Expose @wq in sysfs under /sys/bus/workqueue/devices. - * alloc_workqueue*() automatically calls this function if WQ_SYSFS is set - * which is the preferred method. - * - * Workqueue user should use this function directly iff it wants to apply - * workqueue_attrs before making the workqueue visible in sysfs; otherwise, - * apply_workqueue_attrs() may race against userland updating the - * attributes. - * - * Return: 0 on success, -errno on failure. - */ -int workqueue_sysfs_register(struct workqueue_struct *wq) -{ - struct wq_device *wq_dev; - int ret; - - /* - * Adjusting max_active or creating new pwqs by applying - * attributes breaks ordering guarantee. Disallow exposing ordered - * workqueues. - */ - if (WARN_ON(wq->flags & __WQ_ORDERED)) - return -EINVAL; - - wq->wq_dev = wq_dev = kzalloc(sizeof(*wq_dev), GFP_KERNEL); - if (!wq_dev) - return -ENOMEM; - - wq_dev->wq = wq; - wq_dev->dev.bus = &wq_subsys; - wq_dev->dev.release = wq_device_release; - dev_set_name(&wq_dev->dev, "%s", wq->name); - - /* - * unbound_attrs are created separately. Suppress uevent until - * everything is ready. - */ - dev_set_uevent_suppress(&wq_dev->dev, true); - - ret = device_register(&wq_dev->dev); - if (ret) { - kfree(wq_dev); - wq->wq_dev = NULL; - return ret; - } - - if (wq->flags & WQ_UNBOUND) { - struct device_attribute *attr; - - for (attr = wq_sysfs_unbound_attrs; attr->attr.name; attr++) { - ret = device_create_file(&wq_dev->dev, attr); - if (ret) { - device_unregister(&wq_dev->dev); - wq->wq_dev = NULL; - return ret; - } - } - } - - dev_set_uevent_suppress(&wq_dev->dev, false); - kobject_uevent(&wq_dev->dev.kobj, KOBJ_ADD); - return 0; -} - -/** - * workqueue_sysfs_unregister - undo workqueue_sysfs_register() - * @wq: the workqueue to unregister - * - * If @wq is registered to sysfs by workqueue_sysfs_register(), unregister. - */ -static void workqueue_sysfs_unregister(struct workqueue_struct *wq) -{ - struct wq_device *wq_dev = wq->wq_dev; - - if (!wq->wq_dev) - return; - - wq->wq_dev = NULL; - device_unregister(&wq_dev->dev); -} -#else /* CONFIG_SYSFS */ -static void workqueue_sysfs_unregister(struct workqueue_struct *wq) { } -#endif /* CONFIG_SYSFS */ - -/* - * Workqueue watchdog. - * - * Stall may be caused by various bugs - missing WQ_MEM_RECLAIM, illegal - * flush dependency, a concurrency managed work item which stays RUNNING - * indefinitely. Workqueue stalls can be very difficult to debug as the - * usual warning mechanisms don't trigger and internal workqueue state is - * largely opaque. - * - * Workqueue watchdog monitors all worker pools periodically and dumps - * state if some pools failed to make forward progress for a while where - * forward progress is defined as the first item on ->worklist changing. - * - * This mechanism is controlled through the kernel parameter - * "workqueue.watchdog_thresh" which can be updated at runtime through the - * corresponding sysfs parameter file. - */ -#ifdef CONFIG_WQ_WATCHDOG - -static void wq_watchdog_timer_fn(unsigned long data); - -static unsigned long wq_watchdog_thresh = 30; -static struct timer_list wq_watchdog_timer = - TIMER_DEFERRED_INITIALIZER(wq_watchdog_timer_fn, 0, 0); - -static unsigned long wq_watchdog_touched = INITIAL_JIFFIES; -static DEFINE_PER_CPU(unsigned long, wq_watchdog_touched_cpu) = INITIAL_JIFFIES; - -static void wq_watchdog_reset_touched(void) -{ - int cpu; - - wq_watchdog_touched = jiffies; - for_each_possible_cpu(cpu) - per_cpu(wq_watchdog_touched_cpu, cpu) = jiffies; -} - -static void wq_watchdog_timer_fn(unsigned long data) -{ - unsigned long thresh = READ_ONCE(wq_watchdog_thresh) * HZ; - bool lockup_detected = false; - struct worker_pool *pool; - int pi; - - if (!thresh) - return; - - rcu_read_lock(); - - for_each_pool(pool, pi) { - unsigned long pool_ts, touched, ts; - - if (list_empty(&pool->worklist)) - continue; - - /* get the latest of pool and touched timestamps */ - pool_ts = READ_ONCE(pool->watchdog_ts); - touched = READ_ONCE(wq_watchdog_touched); - - if (time_after(pool_ts, touched)) - ts = pool_ts; - else - ts = touched; - - if (pool->cpu >= 0) { - unsigned long cpu_touched = - READ_ONCE(per_cpu(wq_watchdog_touched_cpu, - pool->cpu)); - if (time_after(cpu_touched, ts)) - ts = cpu_touched; - } - - /* did we stall? */ - if (time_after(jiffies, ts + thresh)) { - lockup_detected = true; - pr_emerg("BUG: workqueue lockup - pool"); - pr_cont_pool_info(pool); - pr_cont(" stuck for %us!\n", - jiffies_to_msecs(jiffies - pool_ts) / 1000); - } - } - - rcu_read_unlock(); - - if (lockup_detected) - show_workqueue_state(); - - wq_watchdog_reset_touched(); - mod_timer(&wq_watchdog_timer, jiffies + thresh); -} - -void wq_watchdog_touch(int cpu) -{ - if (cpu >= 0) - per_cpu(wq_watchdog_touched_cpu, cpu) = jiffies; - else - wq_watchdog_touched = jiffies; -} - -static void wq_watchdog_set_thresh(unsigned long thresh) -{ - wq_watchdog_thresh = 0; - del_timer_sync(&wq_watchdog_timer); - - if (thresh) { - wq_watchdog_thresh = thresh; - wq_watchdog_reset_touched(); - mod_timer(&wq_watchdog_timer, jiffies + thresh * HZ); - } -} - -static int wq_watchdog_param_set_thresh(const char *val, - const struct kernel_param *kp) -{ - unsigned long thresh; - int ret; - - ret = kstrtoul(val, 0, &thresh); - if (ret) - return ret; - - if (system_wq) - wq_watchdog_set_thresh(thresh); - else - wq_watchdog_thresh = thresh; - - return 0; -} - -static const struct kernel_param_ops wq_watchdog_thresh_ops = { - .set = wq_watchdog_param_set_thresh, - .get = param_get_ulong, -}; - -module_param_cb(watchdog_thresh, &wq_watchdog_thresh_ops, &wq_watchdog_thresh, - 0644); - -static void wq_watchdog_init(void) -{ - wq_watchdog_set_thresh(wq_watchdog_thresh); -} - -#else /* CONFIG_WQ_WATCHDOG */ - -static inline void wq_watchdog_init(void) { } - -#endif /* CONFIG_WQ_WATCHDOG */ - -static void __init wq_numa_init(void) -{ - cpumask_var_t *tbl; - int node, cpu; - - if (num_possible_nodes() <= 1) - return; - - if (wq_disable_numa) { - pr_info("workqueue: NUMA affinity support disabled\n"); - return; - } - - wq_update_unbound_numa_attrs_buf = alloc_workqueue_attrs(GFP_KERNEL); - BUG_ON(!wq_update_unbound_numa_attrs_buf); - - /* - * We want masks of possible CPUs of each node which isn't readily - * available. Build one from cpu_to_node() which should have been - * fully initialized by now. - */ - tbl = kzalloc(nr_node_ids * sizeof(tbl[0]), GFP_KERNEL); - BUG_ON(!tbl); - - for_each_node(node) - BUG_ON(!zalloc_cpumask_var_node(&tbl[node], GFP_KERNEL, - node_online(node) ? node : NUMA_NO_NODE)); - - for_each_possible_cpu(cpu) { - node = cpu_to_node(cpu); - if (WARN_ON(node == NUMA_NO_NODE)) { - pr_warn("workqueue: NUMA node mapping not available for cpu%d, disabling NUMA support\n", cpu); - /* happens iff arch is bonkers, let's just proceed */ - return; - } - cpumask_set_cpu(cpu, tbl[node]); - } - - wq_numa_possible_cpumask = tbl; - wq_numa_enabled = true; -} - -static int __init init_workqueues(void) -{ - int std_nice[NR_STD_WORKER_POOLS] = { 0, HIGHPRI_NICE_LEVEL }; - int i, cpu; - - WARN_ON(__alignof__(struct pool_workqueue) < __alignof__(long long)); - - BUG_ON(!alloc_cpumask_var(&wq_unbound_cpumask, GFP_KERNEL)); - cpumask_copy(wq_unbound_cpumask, cpu_possible_mask); - - pwq_cache = KMEM_CACHE(pool_workqueue, SLAB_PANIC); - - wq_numa_init(); - - /* initialize CPU pools */ - for_each_possible_cpu(cpu) { - struct worker_pool *pool; - - i = 0; - for_each_cpu_worker_pool(pool, cpu) { - BUG_ON(init_worker_pool(pool)); - pool->cpu = cpu; - cpumask_copy(pool->attrs->cpumask, cpumask_of(cpu)); - pool->attrs->nice = std_nice[i++]; - pool->node = cpu_to_node(cpu); - - /* alloc pool ID */ - mutex_lock(&wq_pool_mutex); - BUG_ON(worker_pool_assign_id(pool)); - mutex_unlock(&wq_pool_mutex); - } - } - - /* create the initial worker */ - for_each_online_cpu(cpu) { - struct worker_pool *pool; - - for_each_cpu_worker_pool(pool, cpu) { - pool->flags &= ~POOL_DISASSOCIATED; - BUG_ON(!create_worker(pool)); - } - } - - /* create default unbound and ordered wq attrs */ - for (i = 0; i < NR_STD_WORKER_POOLS; i++) { - struct workqueue_attrs *attrs; - - BUG_ON(!(attrs = alloc_workqueue_attrs(GFP_KERNEL))); - attrs->nice = std_nice[i]; - unbound_std_wq_attrs[i] = attrs; - - /* - * An ordered wq should have only one pwq as ordering is - * guaranteed by max_active which is enforced by pwqs. - * Turn off NUMA so that dfl_pwq is used for all nodes. - */ - BUG_ON(!(attrs = alloc_workqueue_attrs(GFP_KERNEL))); - attrs->nice = std_nice[i]; - attrs->no_numa = true; - ordered_wq_attrs[i] = attrs; - } - - system_wq = alloc_workqueue("events", 0, 0); - system_highpri_wq = alloc_workqueue("events_highpri", WQ_HIGHPRI, 0); - system_long_wq = alloc_workqueue("events_long", 0, 0); - system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND, - WQ_UNBOUND_MAX_ACTIVE); - system_freezable_wq = alloc_workqueue("events_freezable", - WQ_FREEZABLE, 0); - system_power_efficient_wq = alloc_workqueue("events_power_efficient", - WQ_POWER_EFFICIENT, 0); - system_freezable_power_efficient_wq = alloc_workqueue("events_freezable_power_efficient", - WQ_FREEZABLE | WQ_POWER_EFFICIENT, - 0); - BUG_ON(!system_wq || !system_highpri_wq || !system_long_wq || - !system_unbound_wq || !system_freezable_wq || - !system_power_efficient_wq || - !system_freezable_power_efficient_wq); - - wq_watchdog_init(); - - return 0; -} -early_initcall(init_workqueues); diff --git a/src/linux/kernel/workqueue_internal.h b/src/linux/kernel/workqueue_internal.h deleted file mode 100644 index 8635417..0000000 --- a/src/linux/kernel/workqueue_internal.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * kernel/workqueue_internal.h - * - * Workqueue internal header file. Only to be included by workqueue and - * core kernel subsystems. - */ -#ifndef _KERNEL_WORKQUEUE_INTERNAL_H -#define _KERNEL_WORKQUEUE_INTERNAL_H - -#include -#include - -struct worker_pool; - -/* - * The poor guys doing the actual heavy lifting. All on-duty workers are - * either serving the manager role, on idle list or on busy hash. For - * details on the locking annotation (L, I, X...), refer to workqueue.c. - * - * Only to be used in workqueue and async. - */ -struct worker { - /* on idle list while idle, on busy hash table while busy */ - union { - struct list_head entry; /* L: while idle */ - struct hlist_node hentry; /* L: while busy */ - }; - - struct work_struct *current_work; /* L: work being processed */ - work_func_t current_func; /* L: current_work's fn */ - struct pool_workqueue *current_pwq; /* L: current_work's pwq */ - bool desc_valid; /* ->desc is valid */ - struct list_head scheduled; /* L: scheduled works */ - - /* 64 bytes boundary on 64bit, 32 on 32bit */ - - struct task_struct *task; /* I: worker task */ - struct worker_pool *pool; /* I: the associated pool */ - /* L: for rescuers */ - struct list_head node; /* A: anchored at pool->workers */ - /* A: runs through worker->node */ - - unsigned long last_active; /* L: last active timestamp */ - unsigned int flags; /* X: flags */ - int id; /* I: worker id */ - - /* - * Opaque string set with work_set_desc(). Printed out with task - * dump for debugging - WARN, BUG, panic or sysrq. - */ - char desc[WORKER_DESC_LEN]; - - /* used only by rescuers to point to the target workqueue */ - struct workqueue_struct *rescue_wq; /* I: the workqueue to rescue */ -}; - -/** - * current_wq_worker - return struct worker if %current is a workqueue worker - */ -static inline struct worker *current_wq_worker(void) -{ - if (current->flags & PF_WQ_WORKER) - return kthread_data(current); - return NULL; -} - -/* - * Scheduler hooks for concurrency managed workqueue. Only to be used from - * sched/core.c and workqueue.c. - */ -void wq_worker_waking_up(struct task_struct *task, int cpu); -struct task_struct *wq_worker_sleeping(struct task_struct *task); - -#endif /* _KERNEL_WORKQUEUE_INTERNAL_H */ diff --git a/src/linux/lib/.gitignore b/src/linux/lib/.gitignore deleted file mode 100644 index a5a50cf..0000000 --- a/src/linux/lib/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# -# Generated files -# -gen_crc32table -gen_crc32table.exe -crc32table.h -oid_registry_data.c diff --git a/src/linux/lib/Kconfig b/src/linux/lib/Kconfig deleted file mode 100644 index 260a80e..0000000 --- a/src/linux/lib/Kconfig +++ /dev/null @@ -1,553 +0,0 @@ -# -# Library configuration -# - -config BINARY_PRINTF - def_bool n - -menu "Library routines" - -config RAID6_PQ - tristate - -config BITREVERSE - tristate - -config HAVE_ARCH_BITREVERSE - bool - default n - depends on BITREVERSE - help - This option enables the use of hardware bit-reversal instructions on - architectures which support such operations. - -config RATIONAL - bool - -config GENERIC_STRNCPY_FROM_USER - bool - -config GENERIC_STRNLEN_USER - bool - -config GENERIC_NET_UTILS - bool - -config GENERIC_FIND_FIRST_BIT - bool - -config NO_GENERIC_PCI_IOPORT_MAP - bool - -config GENERIC_PCI_IOMAP - bool - -config GENERIC_IOMAP - bool - select GENERIC_PCI_IOMAP - -config GENERIC_IO - bool - default n - -config STMP_DEVICE - bool - -config ARCH_USE_CMPXCHG_LOCKREF - bool - -config ARCH_HAS_FAST_MULTIPLIER - bool - -config CRC_CCITT - tristate "CRC-CCITT functions" - help - This option is provided for the case where no in-kernel-tree - modules require CRC-CCITT functions, but a module built outside - the kernel tree does. Such modules that use library CRC-CCITT - functions require M here. - -config CRC16 - tristate "CRC16 functions" - help - This option is provided for the case where no in-kernel-tree - modules require CRC16 functions, but a module built outside - the kernel tree does. Such modules that use library CRC16 - functions require M here. - -config CRC_T10DIF - tristate "CRC calculation for the T10 Data Integrity Field" - select CRYPTO - select CRYPTO_CRCT10DIF - help - This option is only needed if a module that's not in the - kernel tree needs to calculate CRC checks for use with the - SCSI data integrity subsystem. - -config CRC_ITU_T - tristate "CRC ITU-T V.41 functions" - help - This option is provided for the case where no in-kernel-tree - modules require CRC ITU-T V.41 functions, but a module built outside - the kernel tree does. Such modules that use library CRC ITU-T V.41 - functions require M here. - -config CRC32 - tristate "CRC32/CRC32c functions" - default y - select BITREVERSE - help - This option is provided for the case where no in-kernel-tree - modules require CRC32/CRC32c functions, but a module built outside - the kernel tree does. Such modules that use library CRC32/CRC32c - functions require M here. - -config CRC32_SELFTEST - bool "CRC32 perform self test on init" - default n - depends on CRC32 - help - This option enables the CRC32 library functions to perform a - self test on initialization. The self test computes crc32_le - and crc32_be over byte strings with random alignment and length - and computes the total elapsed time and number of bytes processed. - -choice - prompt "CRC32 implementation" - depends on CRC32 - default CRC32_SLICEBY8 - help - This option allows a kernel builder to override the default choice - of CRC32 algorithm. Choose the default ("slice by 8") unless you - know that you need one of the others. - -config CRC32_SLICEBY8 - bool "Slice by 8 bytes" - help - Calculate checksum 8 bytes at a time with a clever slicing algorithm. - This is the fastest algorithm, but comes with a 8KiB lookup table. - Most modern processors have enough cache to hold this table without - thrashing the cache. - - This is the default implementation choice. Choose this one unless - you have a good reason not to. - -config CRC32_SLICEBY4 - bool "Slice by 4 bytes" - help - Calculate checksum 4 bytes at a time with a clever slicing algorithm. - This is a bit slower than slice by 8, but has a smaller 4KiB lookup - table. - - Only choose this option if you know what you are doing. - -config CRC32_SARWATE - bool "Sarwate's Algorithm (one byte at a time)" - help - Calculate checksum a byte at a time using Sarwate's algorithm. This - is not particularly fast, but has a small 256 byte lookup table. - - Only choose this option if you know what you are doing. - -config CRC32_BIT - bool "Classic Algorithm (one bit at a time)" - help - Calculate checksum one bit at a time. This is VERY slow, but has - no lookup table. This is provided as a debugging option. - - Only choose this option if you are debugging crc32. - -endchoice - -config CRC7 - tristate "CRC7 functions" - help - This option is provided for the case where no in-kernel-tree - modules require CRC7 functions, but a module built outside - the kernel tree does. Such modules that use library CRC7 - functions require M here. - -config LIBCRC32C - tristate "CRC32c (Castagnoli, et al) Cyclic Redundancy-Check" - select CRYPTO - select CRYPTO_CRC32C - help - This option is provided for the case where no in-kernel-tree - modules require CRC32c functions, but a module built outside the - kernel tree does. Such modules that use library CRC32c functions - require M here. See Castagnoli93. - Module will be libcrc32c. - -config CRC8 - tristate "CRC8 function" - help - This option provides CRC8 function. Drivers may select this - when they need to do cyclic redundancy check according CRC8 - algorithm. Module will be called crc8. - -config AUDIT_GENERIC - bool - depends on AUDIT && !AUDIT_ARCH - default y - -config AUDIT_ARCH_COMPAT_GENERIC - bool - default n - -config AUDIT_COMPAT_GENERIC - bool - depends on AUDIT_GENERIC && AUDIT_ARCH_COMPAT_GENERIC && COMPAT - default y - -config RANDOM32_SELFTEST - bool "PRNG perform self test on init" - default n - help - This option enables the 32 bit PRNG library functions to perform a - self test on initialization. - -# -# compression support is select'ed if needed -# -config 842_COMPRESS - select CRC32 - tristate - -config 842_DECOMPRESS - select CRC32 - tristate - -config ZLIB_INFLATE - tristate - -config ZLIB_DEFLATE - tristate - select BITREVERSE - -config LZO_COMPRESS - tristate - -config LZO_DECOMPRESS - tristate - -config LZ4_COMPRESS - tristate - -config LZ4HC_COMPRESS - tristate - -config LZ4_DECOMPRESS - tristate - -source "lib/xz/Kconfig" - -# -# These all provide a common interface (hence the apparent duplication with -# ZLIB_INFLATE; DECOMPRESS_GZIP is just a wrapper.) -# -config DECOMPRESS_GZIP - select ZLIB_INFLATE - tristate - -config DECOMPRESS_BZIP2 - tristate - -config DECOMPRESS_LZMA - tristate - -config DECOMPRESS_XZ - select XZ_DEC - tristate - -config DECOMPRESS_LZO - select LZO_DECOMPRESS - tristate - -config DECOMPRESS_LZ4 - select LZ4_DECOMPRESS - tristate - -# -# Generic allocator support is selected if needed -# -config GENERIC_ALLOCATOR - bool - -# -# reed solomon support is select'ed if needed -# -config REED_SOLOMON - tristate - -config REED_SOLOMON_ENC8 - bool - -config REED_SOLOMON_DEC8 - bool - -config REED_SOLOMON_ENC16 - bool - -config REED_SOLOMON_DEC16 - bool - -# -# BCH support is selected if needed -# -config BCH - tristate - -config BCH_CONST_PARAMS - bool - help - Drivers may select this option to force specific constant - values for parameters 'm' (Galois field order) and 't' - (error correction capability). Those specific values must - be set by declaring default values for symbols BCH_CONST_M - and BCH_CONST_T. - Doing so will enable extra compiler optimizations, - improving encoding and decoding performance up to 2x for - usual (m,t) values (typically such that m*t < 200). - When this option is selected, the BCH library supports - only a single (m,t) configuration. This is mainly useful - for NAND flash board drivers requiring known, fixed BCH - parameters. - -config BCH_CONST_M - int - range 5 15 - help - Constant value for Galois field order 'm'. If 'k' is the - number of data bits to protect, 'm' should be chosen such - that (k + m*t) <= 2**m - 1. - Drivers should declare a default value for this symbol if - they select option BCH_CONST_PARAMS. - -config BCH_CONST_T - int - help - Constant value for error correction capability in bits 't'. - Drivers should declare a default value for this symbol if - they select option BCH_CONST_PARAMS. - -# -# Textsearch support is select'ed if needed -# -config TEXTSEARCH - bool - -config TEXTSEARCH_KMP - tristate - -config TEXTSEARCH_BM - tristate - -config TEXTSEARCH_FSM - tristate - -config BTREE - bool - -config INTERVAL_TREE - bool - help - Simple, embeddable, interval-tree. Can find the start of an - overlapping range in log(n) time and then iterate over all - overlapping nodes. The algorithm is implemented as an - augmented rbtree. - - See: - - Documentation/rbtree.txt - - for more information. - -config RADIX_TREE_MULTIORDER - bool - -config ASSOCIATIVE_ARRAY - bool - help - Generic associative array. Can be searched and iterated over whilst - it is being modified. It is also reasonably quick to search and - modify. The algorithms are non-recursive, and the trees are highly - capacious. - - See: - - Documentation/assoc_array.txt - - for more information. - -config HAS_IOMEM - bool - depends on !NO_IOMEM - select GENERIC_IO - default y - -config HAS_IOPORT_MAP - bool - depends on HAS_IOMEM && !NO_IOPORT_MAP - default y - -config HAS_DMA - bool - depends on !NO_DMA - default y - -config CHECK_SIGNATURE - bool - -config CPUMASK_OFFSTACK - bool "Force CPU masks off stack" if DEBUG_PER_CPU_MAPS - help - Use dynamic allocation for cpumask_var_t, instead of putting - them on the stack. This is a bit more expensive, but avoids - stack overflow. - -config CPU_RMAP - bool - depends on SMP - -config DQL - bool - -config GLOB - bool -# This actually supports modular compilation, but the module overhead -# is ridiculous for the amount of code involved. Until an out-of-tree -# driver asks for it, we'll just link it directly it into the kernel -# when required. Since we're ignoring out-of-tree users, there's also -# no need bother prompting for a manual decision: -# prompt "glob_match() function" - help - This option provides a glob_match function for performing - simple text pattern matching. It originated in the ATA code - to blacklist particular drive models, but other device drivers - may need similar functionality. - - All drivers in the Linux kernel tree that require this function - should automatically select this option. Say N unless you - are compiling an out-of tree driver which tells you that it - depends on this. - -config GLOB_SELFTEST - bool "glob self-test on init" - default n - depends on GLOB - help - This option enables a simple self-test of the glob_match - function on startup. It is primarily useful for people - working on the code to ensure they haven't introduced any - regressions. - - It only adds a little bit of code and slows kernel boot (or - module load) by a small amount, so you're welcome to play with - it, but you probably don't need it. - -# -# Netlink attribute parsing support is select'ed if needed -# -config NLATTR - bool - -# -# Generic 64-bit atomic support is selected if needed -# -config GENERIC_ATOMIC64 - bool - -config LRU_CACHE - tristate - -config CLZ_TAB - bool - -config CORDIC - tristate "CORDIC algorithm" - help - This option provides an implementation of the CORDIC algorithm; - calculations are in fixed point. Module will be called cordic. - -config DDR - bool "JEDEC DDR data" - help - Data from JEDEC specs for DDR SDRAM memories, - particularly the AC timing parameters and addressing - information. This data is useful for drivers handling - DDR SDRAM controllers. - -config IRQ_POLL - bool "IRQ polling library" - help - Helper library to poll interrupt mitigation using polling. - -config MPILIB - tristate - select CLZ_TAB - help - Multiprecision maths library from GnuPG. - It is used to implement RSA digital signature verification, - which is used by IMA/EVM digital signature extension. - -config SIGNATURE - tristate - depends on KEYS - select CRYPTO - select CRYPTO_SHA1 - select MPILIB - help - Digital signature verification. Currently only RSA is supported. - Implementation is done using GnuPG MPI library - -# -# libfdt files, only selected if needed. -# -config LIBFDT - bool - -config OID_REGISTRY - tristate - help - Enable fast lookup object identifier registry. - -config UCS2_STRING - tristate - -source "lib/fonts/Kconfig" - -config SG_SPLIT - def_bool n - help - Provides a helper to split scatterlists into chunks, each chunk being - a scatterlist. This should be selected by a driver or an API which - whishes to split a scatterlist amongst multiple DMA channels. - -config SG_POOL - def_bool n - help - Provides a helper to allocate chained scatterlists. This should be - selected by a driver or an API which whishes to allocate chained - scatterlist. - -# -# sg chaining option -# - -config ARCH_HAS_SG_CHAIN - def_bool n - -config ARCH_HAS_PMEM_API - bool - -config ARCH_HAS_MMIO_FLUSH - bool - -config STACKDEPOT - bool - select STACKTRACE - -config SBITMAP - bool - -endmenu diff --git a/src/linux/lib/Kconfig.debug b/src/linux/lib/Kconfig.debug deleted file mode 100644 index a6c8db1..0000000 --- a/src/linux/lib/Kconfig.debug +++ /dev/null @@ -1,2010 +0,0 @@ -menu "printk and dmesg options" - -config PRINTK_TIME - bool "Show timing information on printks" - depends on PRINTK - help - Selecting this option causes time stamps of the printk() - messages to be added to the output of the syslog() system - call and at the console. - - The timestamp is always recorded internally, and exported - to /dev/kmsg. This flag just specifies if the timestamp should - be included, not that the timestamp is recorded. - - The behavior is also controlled by the kernel command line - parameter printk.time=1. See Documentation/kernel-parameters.txt - -config MESSAGE_LOGLEVEL_DEFAULT - int "Default message log level (1-7)" - range 1 7 - default "4" - help - Default log level for printk statements with no specified priority. - - This was hard-coded to KERN_WARNING since at least 2.6.10 but folks - that are auditing their logs closely may want to set it to a lower - priority. - -config BOOT_PRINTK_DELAY - bool "Delay each boot printk message by N milliseconds" - depends on DEBUG_KERNEL && PRINTK && GENERIC_CALIBRATE_DELAY - help - This build option allows you to read kernel boot messages - by inserting a short delay after each one. The delay is - specified in milliseconds on the kernel command line, - using "boot_delay=N". - - It is likely that you would also need to use "lpj=M" to preset - the "loops per jiffie" value. - See a previous boot log for the "lpj" value to use for your - system, and then set "lpj=M" before setting "boot_delay=N". - NOTE: Using this option may adversely affect SMP systems. - I.e., processors other than the first one may not boot up. - BOOT_PRINTK_DELAY also may cause LOCKUP_DETECTOR to detect - what it believes to be lockup conditions. - -config DYNAMIC_DEBUG - bool "Enable dynamic printk() support" - default n - depends on PRINTK - depends on DEBUG_FS - help - - Compiles debug level messages into the kernel, which would not - otherwise be available at runtime. These messages can then be - enabled/disabled based on various levels of scope - per source file, - function, module, format string, and line number. This mechanism - implicitly compiles in all pr_debug() and dev_dbg() calls, which - enlarges the kernel text size by about 2%. - - If a source file is compiled with DEBUG flag set, any - pr_debug() calls in it are enabled by default, but can be - disabled at runtime as below. Note that DEBUG flag is - turned on by many CONFIG_*DEBUG* options. - - Usage: - - Dynamic debugging is controlled via the 'dynamic_debug/control' file, - which is contained in the 'debugfs' filesystem. Thus, the debugfs - filesystem must first be mounted before making use of this feature. - We refer the control file as: /dynamic_debug/control. This - file contains a list of the debug statements that can be enabled. The - format for each line of the file is: - - filename:lineno [module]function flags format - - filename : source file of the debug statement - lineno : line number of the debug statement - module : module that contains the debug statement - function : function that contains the debug statement - flags : '=p' means the line is turned 'on' for printing - format : the format used for the debug statement - - From a live system: - - nullarbor:~ # cat /dynamic_debug/control - # filename:lineno [module]function flags format - fs/aio.c:222 [aio]__put_ioctx =_ "__put_ioctx:\040freeing\040%p\012" - fs/aio.c:248 [aio]ioctx_alloc =_ "ENOMEM:\040nr_events\040too\040high\012" - fs/aio.c:1770 [aio]sys_io_cancel =_ "calling\040cancel\012" - - Example usage: - - // enable the message at line 1603 of file svcsock.c - nullarbor:~ # echo -n 'file svcsock.c line 1603 +p' > - /dynamic_debug/control - - // enable all the messages in file svcsock.c - nullarbor:~ # echo -n 'file svcsock.c +p' > - /dynamic_debug/control - - // enable all the messages in the NFS server module - nullarbor:~ # echo -n 'module nfsd +p' > - /dynamic_debug/control - - // enable all 12 messages in the function svc_process() - nullarbor:~ # echo -n 'func svc_process +p' > - /dynamic_debug/control - - // disable all 12 messages in the function svc_process() - nullarbor:~ # echo -n 'func svc_process -p' > - /dynamic_debug/control - - See Documentation/dynamic-debug-howto.txt for additional information. - -endmenu # "printk and dmesg options" - -menu "Compile-time checks and compiler options" - -config DEBUG_INFO - bool "Compile the kernel with debug info" - depends on DEBUG_KERNEL && !COMPILE_TEST - help - If you say Y here the resulting kernel image will include - debugging info resulting in a larger kernel image. - This adds debug symbols to the kernel and modules (gcc -g), and - is needed if you intend to use kernel crashdump or binary object - tools like crash, kgdb, LKCD, gdb, etc on the kernel. - Say Y here only if you plan to debug the kernel. - - If unsure, say N. - -config DEBUG_INFO_REDUCED - bool "Reduce debugging information" - depends on DEBUG_INFO - help - If you say Y here gcc is instructed to generate less debugging - information for structure types. This means that tools that - need full debugging information (like kgdb or systemtap) won't - be happy. But if you merely need debugging information to - resolve line numbers there is no loss. Advantage is that - build directory object sizes shrink dramatically over a full - DEBUG_INFO build and compile times are reduced too. - Only works with newer gcc versions. - -config DEBUG_INFO_SPLIT - bool "Produce split debuginfo in .dwo files" - depends on DEBUG_INFO - help - Generate debug info into separate .dwo files. This significantly - reduces the build directory size for builds with DEBUG_INFO, - because it stores the information only once on disk in .dwo - files instead of multiple times in object files and executables. - In addition the debug information is also compressed. - - Requires recent gcc (4.7+) and recent gdb/binutils. - Any tool that packages or reads debug information would need - to know about the .dwo files and include them. - Incompatible with older versions of ccache. - -config DEBUG_INFO_DWARF4 - bool "Generate dwarf4 debuginfo" - depends on DEBUG_INFO - help - Generate dwarf4 debug info. This requires recent versions - of gcc and gdb. It makes the debug information larger. - But it significantly improves the success of resolving - variables in gdb on optimized code. - -config GDB_SCRIPTS - bool "Provide GDB scripts for kernel debugging" - depends on DEBUG_INFO - help - This creates the required links to GDB helper scripts in the - build directory. If you load vmlinux into gdb, the helper - scripts will be automatically imported by gdb as well, and - additional functions are available to analyze a Linux kernel - instance. See Documentation/gdb-kernel-debugging.txt for further - details. - -config ENABLE_WARN_DEPRECATED - bool "Enable __deprecated logic" - default y - help - Enable the __deprecated logic in the kernel build. - Disable this to suppress the "warning: 'foo' is deprecated - (declared at kernel/power/somefile.c:1234)" messages. - -config ENABLE_MUST_CHECK - bool "Enable __must_check logic" - default y - help - Enable the __must_check logic in the kernel build. Disable this to - suppress the "warning: ignoring return value of 'foo', declared with - attribute warn_unused_result" messages. - -config FRAME_WARN - int "Warn for stack frames larger than (needs gcc 4.4)" - range 0 8192 - default 0 if KASAN - default 2048 if GCC_PLUGIN_LATENT_ENTROPY - default 1024 if !64BIT - default 2048 if 64BIT - help - Tell gcc to warn at build time for stack frames larger than this. - Setting this too low will cause a lot of warnings. - Setting it to 0 disables the warning. - Requires gcc 4.4 - -config STRIP_ASM_SYMS - bool "Strip assembler-generated symbols during link" - default n - help - Strip internal assembler-generated symbols during a link (symbols - that look like '.Lxxx') so they don't pollute the output of - get_wchan() and suchlike. - -config READABLE_ASM - bool "Generate readable assembler code" - depends on DEBUG_KERNEL - help - Disable some compiler optimizations that tend to generate human unreadable - assembler output. This may make the kernel slightly slower, but it helps - to keep kernel developers who have to stare a lot at assembler listings - sane. - -config UNUSED_SYMBOLS - bool "Enable unused/obsolete exported symbols" - default y if X86 - help - Unused but exported symbols make the kernel needlessly bigger. For - that reason most of these unused exports will soon be removed. This - option is provided temporarily to provide a transition period in case - some external kernel module needs one of these symbols anyway. If you - encounter such a case in your module, consider if you are actually - using the right API. (rationale: since nobody in the kernel is using - this in a module, there is a pretty good chance it's actually the - wrong interface to use). If you really need the symbol, please send a - mail to the linux kernel mailing list mentioning the symbol and why - you really need it, and what the merge plan to the mainline kernel for - your module is. - -config PAGE_OWNER - bool "Track page owner" - depends on DEBUG_KERNEL && STACKTRACE_SUPPORT - select DEBUG_FS - select STACKTRACE - select STACKDEPOT - select PAGE_EXTENSION - help - This keeps track of what call chain is the owner of a page, may - help to find bare alloc_page(s) leaks. Even if you include this - feature on your build, it is disabled in default. You should pass - "page_owner=on" to boot parameter in order to enable it. Eats - a fair amount of memory if enabled. See tools/vm/page_owner_sort.c - for user-space helper. - - If unsure, say N. - -config DEBUG_FS - bool "Debug Filesystem" - select SRCU - help - debugfs is a virtual file system that kernel developers use to put - debugging files into. Enable this option to be able to read and - write to these files. - - For detailed documentation on the debugfs API, see - Documentation/DocBook/filesystems. - - If unsure, say N. - -config HEADERS_CHECK - bool "Run 'make headers_check' when building vmlinux" - depends on !UML - help - This option will extract the user-visible kernel headers whenever - building the kernel, and will run basic sanity checks on them to - ensure that exported files do not attempt to include files which - were not exported, etc. - - If you're making modifications to header files which are - relevant for userspace, say 'Y', and check the headers - exported to $(INSTALL_HDR_PATH) (usually 'usr/include' in - your build tree), to make sure they're suitable. - -config DEBUG_SECTION_MISMATCH - bool "Enable full Section mismatch analysis" - help - The section mismatch analysis checks if there are illegal - references from one section to another section. - During linktime or runtime, some sections are dropped; - any use of code/data previously in these sections would - most likely result in an oops. - In the code, functions and variables are annotated with - __init,, etc. (see the full list in include/linux/init.h), - which results in the code/data being placed in specific sections. - The section mismatch analysis is always performed after a full - kernel build, and enabling this option causes the following - additional steps to occur: - - Add the option -fno-inline-functions-called-once to gcc commands. - When inlining a function annotated with __init in a non-init - function, we would lose the section information and thus - the analysis would not catch the illegal reference. - This option tells gcc to inline less (but it does result in - a larger kernel). - - Run the section mismatch analysis for each module/built-in.o file. - When we run the section mismatch analysis on vmlinux.o, we - lose valuable information about where the mismatch was - introduced. - Running the analysis for each module/built-in.o file - tells where the mismatch happens much closer to the - source. The drawback is that the same mismatch is - reported at least twice. - - Enable verbose reporting from modpost in order to help resolve - the section mismatches that are reported. - -config SECTION_MISMATCH_WARN_ONLY - bool "Make section mismatch errors non-fatal" - default y - help - If you say N here, the build process will fail if there are any - section mismatch, instead of just throwing warnings. - - If unsure, say Y. - -# -# Select this config option from the architecture Kconfig, if it -# is preferred to always offer frame pointers as a config -# option on the architecture (regardless of KERNEL_DEBUG): -# -config ARCH_WANT_FRAME_POINTERS - bool - help - -config FRAME_POINTER - bool "Compile the kernel with frame pointers" - depends on DEBUG_KERNEL && \ - (CRIS || M68K || FRV || UML || \ - AVR32 || SUPERH || BLACKFIN || MN10300 || METAG) || \ - ARCH_WANT_FRAME_POINTERS - default y if (DEBUG_INFO && UML) || ARCH_WANT_FRAME_POINTERS - help - If you say Y here the resulting kernel image will be slightly - larger and slower, but it gives very useful debugging information - in case of kernel bugs. (precise oopses/stacktraces/warnings) - -config STACK_VALIDATION - bool "Compile-time stack metadata validation" - depends on HAVE_STACK_VALIDATION - default n - help - Add compile-time checks to validate stack metadata, including frame - pointers (if CONFIG_FRAME_POINTER is enabled). This helps ensure - that runtime stack traces are more reliable. - - For more information, see - tools/objtool/Documentation/stack-validation.txt. - -config DEBUG_FORCE_WEAK_PER_CPU - bool "Force weak per-cpu definitions" - depends on DEBUG_KERNEL - help - s390 and alpha require percpu variables in modules to be - defined weak to work around addressing range issue which - puts the following two restrictions on percpu variable - definitions. - - 1. percpu symbols must be unique whether static or not - 2. percpu variables can't be defined inside a function - - To ensure that generic code follows the above rules, this - option forces all percpu variables to be defined as weak. - -endmenu # "Compiler options" - -config MAGIC_SYSRQ - bool "Magic SysRq key" - depends on !UML - help - If you say Y here, you will have some control over the system even - if the system crashes for example during kernel debugging (e.g., you - will be able to flush the buffer cache to disk, reboot the system - immediately or dump some status information). This is accomplished - by pressing various keys while holding SysRq (Alt+PrintScreen). It - also works on a serial console (on PC hardware at least), if you - send a BREAK and then within 5 seconds a command keypress. The - keys are documented in . Don't say Y - unless you really know what this hack does. - -config MAGIC_SYSRQ_DEFAULT_ENABLE - hex "Enable magic SysRq key functions by default" - depends on MAGIC_SYSRQ - default 0x1 - help - Specifies which SysRq key functions are enabled by default. - This may be set to 1 or 0 to enable or disable them all, or - to a bitmask as described in Documentation/sysrq.txt. - -config DEBUG_KERNEL - bool "Kernel debugging" - help - Say Y here if you are developing drivers or trying to debug and - identify kernel problems. - -menu "Memory Debugging" - -source mm/Kconfig.debug - -config DEBUG_OBJECTS - bool "Debug object operations" - depends on DEBUG_KERNEL - help - If you say Y here, additional code will be inserted into the - kernel to track the life time of various objects and validate - the operations on those objects. - -config DEBUG_OBJECTS_SELFTEST - bool "Debug objects selftest" - depends on DEBUG_OBJECTS - help - This enables the selftest of the object debug code. - -config DEBUG_OBJECTS_FREE - bool "Debug objects in freed memory" - depends on DEBUG_OBJECTS - help - This enables checks whether a k/v free operation frees an area - which contains an object which has not been deactivated - properly. This can make kmalloc/kfree-intensive workloads - much slower. - -config DEBUG_OBJECTS_TIMERS - bool "Debug timer objects" - depends on DEBUG_OBJECTS - help - If you say Y here, additional code will be inserted into the - timer routines to track the life time of timer objects and - validate the timer operations. - -config DEBUG_OBJECTS_WORK - bool "Debug work objects" - depends on DEBUG_OBJECTS - help - If you say Y here, additional code will be inserted into the - work queue routines to track the life time of work objects and - validate the work operations. - -config DEBUG_OBJECTS_RCU_HEAD - bool "Debug RCU callbacks objects" - depends on DEBUG_OBJECTS - help - Enable this to turn on debugging of RCU list heads (call_rcu() usage). - -config DEBUG_OBJECTS_PERCPU_COUNTER - bool "Debug percpu counter objects" - depends on DEBUG_OBJECTS - help - If you say Y here, additional code will be inserted into the - percpu counter routines to track the life time of percpu counter - objects and validate the percpu counter operations. - -config DEBUG_OBJECTS_ENABLE_DEFAULT - int "debug_objects bootup default value (0-1)" - range 0 1 - default "1" - depends on DEBUG_OBJECTS - help - Debug objects boot parameter default value - -config DEBUG_SLAB - bool "Debug slab memory allocations" - depends on DEBUG_KERNEL && SLAB && !KMEMCHECK - help - Say Y here to have the kernel do limited verification on memory - allocation as well as poisoning memory on free to catch use of freed - memory. This can make kmalloc/kfree-intensive workloads much slower. - -config DEBUG_SLAB_LEAK - bool "Memory leak debugging" - depends on DEBUG_SLAB - -config SLUB_DEBUG_ON - bool "SLUB debugging on by default" - depends on SLUB && SLUB_DEBUG && !KMEMCHECK - default n - help - Boot with debugging on by default. SLUB boots by default with - the runtime debug capabilities switched off. Enabling this is - equivalent to specifying the "slub_debug" parameter on boot. - There is no support for more fine grained debug control like - possible with slub_debug=xxx. SLUB debugging may be switched - off in a kernel built with CONFIG_SLUB_DEBUG_ON by specifying - "slub_debug=-". - -config SLUB_STATS - default n - bool "Enable SLUB performance statistics" - depends on SLUB && SYSFS - help - SLUB statistics are useful to debug SLUBs allocation behavior in - order find ways to optimize the allocator. This should never be - enabled for production use since keeping statistics slows down - the allocator by a few percentage points. The slabinfo command - supports the determination of the most active slabs to figure - out which slabs are relevant to a particular load. - Try running: slabinfo -DA - -config HAVE_DEBUG_KMEMLEAK - bool - -config DEBUG_KMEMLEAK - bool "Kernel memory leak detector" - depends on DEBUG_KERNEL && HAVE_DEBUG_KMEMLEAK - select DEBUG_FS - select STACKTRACE if STACKTRACE_SUPPORT - select KALLSYMS - select CRC32 - help - Say Y here if you want to enable the memory leak - detector. The memory allocation/freeing is traced in a way - similar to the Boehm's conservative garbage collector, the - difference being that the orphan objects are not freed but - only shown in /sys/kernel/debug/kmemleak. Enabling this - feature will introduce an overhead to memory - allocations. See Documentation/kmemleak.txt for more - details. - - Enabling DEBUG_SLAB or SLUB_DEBUG may increase the chances - of finding leaks due to the slab objects poisoning. - - In order to access the kmemleak file, debugfs needs to be - mounted (usually at /sys/kernel/debug). - -config DEBUG_KMEMLEAK_EARLY_LOG_SIZE - int "Maximum kmemleak early log entries" - depends on DEBUG_KMEMLEAK - range 200 40000 - default 400 - help - Kmemleak must track all the memory allocations to avoid - reporting false positives. Since memory may be allocated or - freed before kmemleak is initialised, an early log buffer is - used to store these actions. If kmemleak reports "early log - buffer exceeded", please increase this value. - -config DEBUG_KMEMLEAK_TEST - tristate "Simple test for the kernel memory leak detector" - depends on DEBUG_KMEMLEAK && m - help - This option enables a module that explicitly leaks memory. - - If unsure, say N. - -config DEBUG_KMEMLEAK_DEFAULT_OFF - bool "Default kmemleak to off" - depends on DEBUG_KMEMLEAK - help - Say Y here to disable kmemleak by default. It can then be enabled - on the command line via kmemleak=on. - -config DEBUG_STACK_USAGE - bool "Stack utilization instrumentation" - depends on DEBUG_KERNEL && !IA64 - help - Enables the display of the minimum amount of free stack which each - task has ever had available in the sysrq-T and sysrq-P debug output. - - This option will slow down process creation somewhat. - -config DEBUG_VM - bool "Debug VM" - depends on DEBUG_KERNEL - help - Enable this to turn on extended checks in the virtual-memory system - that may impact performance. - - If unsure, say N. - -config DEBUG_VM_VMACACHE - bool "Debug VMA caching" - depends on DEBUG_VM - help - Enable this to turn on VMA caching debug information. Doing so - can cause significant overhead, so only enable it in non-production - environments. - - If unsure, say N. - -config DEBUG_VM_RB - bool "Debug VM red-black trees" - depends on DEBUG_VM - help - Enable VM red-black tree debugging information and extra validations. - - If unsure, say N. - -config DEBUG_VM_PGFLAGS - bool "Debug page-flags operations" - depends on DEBUG_VM - help - Enables extra validation on page flags operations. - - If unsure, say N. - -config DEBUG_VIRTUAL - bool "Debug VM translations" - depends on DEBUG_KERNEL && X86 - help - Enable some costly sanity checks in virtual to page code. This can - catch mistakes with virt_to_page() and friends. - - If unsure, say N. - -config DEBUG_NOMMU_REGIONS - bool "Debug the global anon/private NOMMU mapping region tree" - depends on DEBUG_KERNEL && !MMU - help - This option causes the global tree of anonymous and private mapping - regions to be regularly checked for invalid topology. - -config DEBUG_MEMORY_INIT - bool "Debug memory initialisation" if EXPERT - default !EXPERT - help - Enable this for additional checks during memory initialisation. - The sanity checks verify aspects of the VM such as the memory model - and other information provided by the architecture. Verbose - information will be printed at KERN_DEBUG loglevel depending - on the mminit_loglevel= command-line option. - - If unsure, say Y - -config MEMORY_NOTIFIER_ERROR_INJECT - tristate "Memory hotplug notifier error injection module" - depends on MEMORY_HOTPLUG_SPARSE && NOTIFIER_ERROR_INJECTION - help - This option provides the ability to inject artificial errors to - memory hotplug notifier chain callbacks. It is controlled through - debugfs interface under /sys/kernel/debug/notifier-error-inject/memory - - If the notifier call chain should be failed with some events - notified, write the error code to "actions//error". - - Example: Inject memory hotplug offline error (-12 == -ENOMEM) - - # cd /sys/kernel/debug/notifier-error-inject/memory - # echo -12 > actions/MEM_GOING_OFFLINE/error - # echo offline > /sys/devices/system/memory/memoryXXX/state - bash: echo: write error: Cannot allocate memory - - To compile this code as a module, choose M here: the module will - be called memory-notifier-error-inject. - - If unsure, say N. - -config DEBUG_PER_CPU_MAPS - bool "Debug access to per_cpu maps" - depends on DEBUG_KERNEL - depends on SMP - help - Say Y to verify that the per_cpu map being accessed has - been set up. This adds a fair amount of code to kernel memory - and decreases performance. - - Say N if unsure. - -config DEBUG_HIGHMEM - bool "Highmem debugging" - depends on DEBUG_KERNEL && HIGHMEM - help - This option enables additional error checking for high memory - systems. Disable for production systems. - -config HAVE_DEBUG_STACKOVERFLOW - bool - -config DEBUG_STACKOVERFLOW - bool "Check for stack overflows" - depends on DEBUG_KERNEL && HAVE_DEBUG_STACKOVERFLOW - ---help--- - Say Y here if you want to check for overflows of kernel, IRQ - and exception stacks (if your architecture uses them). This - option will show detailed messages if free stack space drops - below a certain limit. - - These kinds of bugs usually occur when call-chains in the - kernel get too deep, especially when interrupts are - involved. - - Use this in cases where you see apparently random memory - corruption, especially if it appears in 'struct thread_info' - - If in doubt, say "N". - -source "lib/Kconfig.kmemcheck" - -source "lib/Kconfig.kasan" - -endmenu # "Memory Debugging" - -config ARCH_HAS_KCOV - bool - help - KCOV does not have any arch-specific code, but currently it is enabled - only for x86_64. KCOV requires testing on other archs, and most likely - disabling of instrumentation for some early boot code. - -config KCOV - bool "Code coverage for fuzzing" - depends on ARCH_HAS_KCOV - select DEBUG_FS - select GCC_PLUGINS if !COMPILE_TEST - select GCC_PLUGIN_SANCOV if !COMPILE_TEST - help - KCOV exposes kernel code coverage information in a form suitable - for coverage-guided fuzzing (randomized testing). - - If RANDOMIZE_BASE is enabled, PC values will not be stable across - different machines and across reboots. If you need stable PC values, - disable RANDOMIZE_BASE. - - For more details, see Documentation/kcov.txt. - -config KCOV_INSTRUMENT_ALL - bool "Instrument all code by default" - depends on KCOV - default y if KCOV - help - If you are doing generic system call fuzzing (like e.g. syzkaller), - then you will want to instrument the whole kernel and you should - say y here. If you are doing more targeted fuzzing (like e.g. - filesystem fuzzing with AFL) then you will want to enable coverage - for more specific subsets of files, and should say n here. - -config DEBUG_SHIRQ - bool "Debug shared IRQ handlers" - depends on DEBUG_KERNEL - help - Enable this to generate a spurious interrupt as soon as a shared - interrupt handler is registered, and just before one is deregistered. - Drivers ought to be able to handle interrupts coming in at those - points; some don't and need to be caught. - -menu "Debug Lockups and Hangs" - -config LOCKUP_DETECTOR - bool "Detect Hard and Soft Lockups" - depends on DEBUG_KERNEL && !S390 - help - Say Y here to enable the kernel to act as a watchdog to detect - hard and soft lockups. - - Softlockups are bugs that cause the kernel to loop in kernel - mode for more than 20 seconds, without giving other tasks a - chance to run. The current stack trace is displayed upon - detection and the system will stay locked up. - - Hardlockups are bugs that cause the CPU to loop in kernel mode - for more than 10 seconds, without letting other interrupts have a - chance to run. The current stack trace is displayed upon detection - and the system will stay locked up. - - The overhead should be minimal. A periodic hrtimer runs to - generate interrupts and kick the watchdog task every 4 seconds. - An NMI is generated every 10 seconds or so to check for hardlockups. - - The frequency of hrtimer and NMI events and the soft and hard lockup - thresholds can be controlled through the sysctl watchdog_thresh. - -config HARDLOCKUP_DETECTOR - def_bool y - depends on LOCKUP_DETECTOR && !HAVE_NMI_WATCHDOG - depends on PERF_EVENTS && HAVE_PERF_EVENTS_NMI - -config BOOTPARAM_HARDLOCKUP_PANIC - bool "Panic (Reboot) On Hard Lockups" - depends on HARDLOCKUP_DETECTOR - help - Say Y here to enable the kernel to panic on "hard lockups", - which are bugs that cause the kernel to loop in kernel - mode with interrupts disabled for more than 10 seconds (configurable - using the watchdog_thresh sysctl). - - Say N if unsure. - -config BOOTPARAM_HARDLOCKUP_PANIC_VALUE - int - depends on HARDLOCKUP_DETECTOR - range 0 1 - default 0 if !BOOTPARAM_HARDLOCKUP_PANIC - default 1 if BOOTPARAM_HARDLOCKUP_PANIC - -config BOOTPARAM_SOFTLOCKUP_PANIC - bool "Panic (Reboot) On Soft Lockups" - depends on LOCKUP_DETECTOR - help - Say Y here to enable the kernel to panic on "soft lockups", - which are bugs that cause the kernel to loop in kernel - mode for more than 20 seconds (configurable using the watchdog_thresh - sysctl), without giving other tasks a chance to run. - - The panic can be used in combination with panic_timeout, - to cause the system to reboot automatically after a - lockup has been detected. This feature is useful for - high-availability systems that have uptime guarantees and - where a lockup must be resolved ASAP. - - Say N if unsure. - -config BOOTPARAM_SOFTLOCKUP_PANIC_VALUE - int - depends on LOCKUP_DETECTOR - range 0 1 - default 0 if !BOOTPARAM_SOFTLOCKUP_PANIC - default 1 if BOOTPARAM_SOFTLOCKUP_PANIC - -config DETECT_HUNG_TASK - bool "Detect Hung Tasks" - depends on DEBUG_KERNEL - default LOCKUP_DETECTOR - help - Say Y here to enable the kernel to detect "hung tasks", - which are bugs that cause the task to be stuck in - uninterruptible "D" state indefinitely. - - When a hung task is detected, the kernel will print the - current stack trace (which you should report), but the - task will stay in uninterruptible state. If lockdep is - enabled then all held locks will also be reported. This - feature has negligible overhead. - -config DEFAULT_HUNG_TASK_TIMEOUT - int "Default timeout for hung task detection (in seconds)" - depends on DETECT_HUNG_TASK - default 120 - help - This option controls the default timeout (in seconds) used - to determine when a task has become non-responsive and should - be considered hung. - - It can be adjusted at runtime via the kernel.hung_task_timeout_secs - sysctl or by writing a value to - /proc/sys/kernel/hung_task_timeout_secs. - - A timeout of 0 disables the check. The default is two minutes. - Keeping the default should be fine in most cases. - -config BOOTPARAM_HUNG_TASK_PANIC - bool "Panic (Reboot) On Hung Tasks" - depends on DETECT_HUNG_TASK - help - Say Y here to enable the kernel to panic on "hung tasks", - which are bugs that cause the kernel to leave a task stuck - in uninterruptible "D" state. - - The panic can be used in combination with panic_timeout, - to cause the system to reboot automatically after a - hung task has been detected. This feature is useful for - high-availability systems that have uptime guarantees and - where a hung tasks must be resolved ASAP. - - Say N if unsure. - -config BOOTPARAM_HUNG_TASK_PANIC_VALUE - int - depends on DETECT_HUNG_TASK - range 0 1 - default 0 if !BOOTPARAM_HUNG_TASK_PANIC - default 1 if BOOTPARAM_HUNG_TASK_PANIC - -config WQ_WATCHDOG - bool "Detect Workqueue Stalls" - depends on DEBUG_KERNEL - help - Say Y here to enable stall detection on workqueues. If a - worker pool doesn't make forward progress on a pending work - item for over a given amount of time, 30s by default, a - warning message is printed along with dump of workqueue - state. This can be configured through kernel parameter - "workqueue.watchdog_thresh" and its sysfs counterpart. - -endmenu # "Debug lockups and hangs" - -config PANIC_ON_OOPS - bool "Panic on Oops" - help - Say Y here to enable the kernel to panic when it oopses. This - has the same effect as setting oops=panic on the kernel command - line. - - This feature is useful to ensure that the kernel does not do - anything erroneous after an oops which could result in data - corruption or other issues. - - Say N if unsure. - -config PANIC_ON_OOPS_VALUE - int - range 0 1 - default 0 if !PANIC_ON_OOPS - default 1 if PANIC_ON_OOPS - -config PANIC_TIMEOUT - int "panic timeout" - default 0 - help - Set the timeout value (in seconds) until a reboot occurs when the - the kernel panics. If n = 0, then we wait forever. A timeout - value n > 0 will wait n seconds before rebooting, while a timeout - value n < 0 will reboot immediately. - -config SCHED_DEBUG - bool "Collect scheduler debugging info" - depends on DEBUG_KERNEL && PROC_FS - default y - help - If you say Y here, the /proc/sched_debug file will be provided - that can help debug the scheduler. The runtime overhead of this - option is minimal. - -config SCHED_INFO - bool - default n - -config SCHEDSTATS - bool "Collect scheduler statistics" - depends on DEBUG_KERNEL && PROC_FS - select SCHED_INFO - help - If you say Y here, additional code will be inserted into the - scheduler and related routines to collect statistics about - scheduler behavior and provide them in /proc/schedstat. These - stats may be useful for both tuning and debugging the scheduler - If you aren't debugging the scheduler or trying to tune a specific - application, you can say N to avoid the very slight overhead - this adds. - -config SCHED_STACK_END_CHECK - bool "Detect stack corruption on calls to schedule()" - depends on DEBUG_KERNEL - default n - help - This option checks for a stack overrun on calls to schedule(). - If the stack end location is found to be over written always panic as - the content of the corrupted region can no longer be trusted. - This is to ensure no erroneous behaviour occurs which could result in - data corruption or a sporadic crash at a later stage once the region - is examined. The runtime overhead introduced is minimal. - -config DEBUG_TIMEKEEPING - bool "Enable extra timekeeping sanity checking" - help - This option will enable additional timekeeping sanity checks - which may be helpful when diagnosing issues where timekeeping - problems are suspected. - - This may include checks in the timekeeping hotpaths, so this - option may have a (very small) performance impact to some - workloads. - - If unsure, say N. - -config TIMER_STATS - bool "Collect kernel timers statistics" - depends on DEBUG_KERNEL && PROC_FS - help - If you say Y here, additional code will be inserted into the - timer routines to collect statistics about kernel timers being - reprogrammed. The statistics can be read from /proc/timer_stats. - The statistics collection is started by writing 1 to /proc/timer_stats, - writing 0 stops it. This feature is useful to collect information - about timer usage patterns in kernel and userspace. This feature - is lightweight if enabled in the kernel config but not activated - (it defaults to deactivated on bootup and will only be activated - if some application like powertop activates it explicitly). - -config DEBUG_PREEMPT - bool "Debug preemptible kernel" - depends on DEBUG_KERNEL && PREEMPT && TRACE_IRQFLAGS_SUPPORT - default y - help - If you say Y here then the kernel will use a debug variant of the - commonly used smp_processor_id() function and will print warnings - if kernel code uses it in a preemption-unsafe way. Also, the kernel - will detect preemption count underflows. - -menu "Lock Debugging (spinlocks, mutexes, etc...)" - -config DEBUG_RT_MUTEXES - bool "RT Mutex debugging, deadlock detection" - depends on DEBUG_KERNEL && RT_MUTEXES - help - This allows rt mutex semantics violations and rt mutex related - deadlocks (lockups) to be detected and reported automatically. - -config DEBUG_SPINLOCK - bool "Spinlock and rw-lock debugging: basic checks" - depends on DEBUG_KERNEL - select UNINLINE_SPIN_UNLOCK - help - Say Y here and build SMP to catch missing spinlock initialization - and certain other kinds of spinlock errors commonly made. This is - best used in conjunction with the NMI watchdog so that spinlock - deadlocks are also debuggable. - -config DEBUG_MUTEXES - bool "Mutex debugging: basic checks" - depends on DEBUG_KERNEL - help - This feature allows mutex semantics violations to be detected and - reported. - -config DEBUG_WW_MUTEX_SLOWPATH - bool "Wait/wound mutex debugging: Slowpath testing" - depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT - select DEBUG_LOCK_ALLOC - select DEBUG_SPINLOCK - select DEBUG_MUTEXES - help - This feature enables slowpath testing for w/w mutex users by - injecting additional -EDEADLK wound/backoff cases. Together with - the full mutex checks enabled with (CONFIG_PROVE_LOCKING) this - will test all possible w/w mutex interface abuse with the - exception of simply not acquiring all the required locks. - Note that this feature can introduce significant overhead, so - it really should not be enabled in a production or distro kernel, - even a debug kernel. If you are a driver writer, enable it. If - you are a distro, do not. - -config DEBUG_LOCK_ALLOC - bool "Lock debugging: detect incorrect freeing of live locks" - depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT - select DEBUG_SPINLOCK - select DEBUG_MUTEXES - select LOCKDEP - help - This feature will check whether any held lock (spinlock, rwlock, - mutex or rwsem) is incorrectly freed by the kernel, via any of the - memory-freeing routines (kfree(), kmem_cache_free(), free_pages(), - vfree(), etc.), whether a live lock is incorrectly reinitialized via - spin_lock_init()/mutex_init()/etc., or whether there is any lock - held during task exit. - -config PROVE_LOCKING - bool "Lock debugging: prove locking correctness" - depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT - select LOCKDEP - select DEBUG_SPINLOCK - select DEBUG_MUTEXES - select DEBUG_LOCK_ALLOC - select TRACE_IRQFLAGS - default n - help - This feature enables the kernel to prove that all locking - that occurs in the kernel runtime is mathematically - correct: that under no circumstance could an arbitrary (and - not yet triggered) combination of observed locking - sequences (on an arbitrary number of CPUs, running an - arbitrary number of tasks and interrupt contexts) cause a - deadlock. - - In short, this feature enables the kernel to report locking - related deadlocks before they actually occur. - - The proof does not depend on how hard and complex a - deadlock scenario would be to trigger: how many - participant CPUs, tasks and irq-contexts would be needed - for it to trigger. The proof also does not depend on - timing: if a race and a resulting deadlock is possible - theoretically (no matter how unlikely the race scenario - is), it will be proven so and will immediately be - reported by the kernel (once the event is observed that - makes the deadlock theoretically possible). - - If a deadlock is impossible (i.e. the locking rules, as - observed by the kernel, are mathematically correct), the - kernel reports nothing. - - NOTE: this feature can also be enabled for rwlocks, mutexes - and rwsems - in which case all dependencies between these - different locking variants are observed and mapped too, and - the proof of observed correctness is also maintained for an - arbitrary combination of these separate locking variants. - - For more details, see Documentation/locking/lockdep-design.txt. - -config PROVE_LOCKING_SMALL - bool - -config LOCKDEP - bool - depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT - select STACKTRACE - select FRAME_POINTER if !MIPS && !PPC && !ARM_UNWIND && !S390 && !MICROBLAZE && !ARC && !SCORE - select KALLSYMS - select KALLSYMS_ALL - -config LOCK_STAT - bool "Lock usage statistics" - depends on DEBUG_KERNEL && TRACE_IRQFLAGS_SUPPORT && STACKTRACE_SUPPORT && LOCKDEP_SUPPORT - select LOCKDEP - select DEBUG_SPINLOCK - select DEBUG_MUTEXES - select DEBUG_LOCK_ALLOC - default n - help - This feature enables tracking lock contention points - - For more details, see Documentation/locking/lockstat.txt - - This also enables lock events required by "perf lock", - subcommand of perf. - If you want to use "perf lock", you also need to turn on - CONFIG_EVENT_TRACING. - - CONFIG_LOCK_STAT defines "contended" and "acquired" lock events. - (CONFIG_LOCKDEP defines "acquire" and "release" events.) - -config DEBUG_LOCKDEP - bool "Lock dependency engine debugging" - depends on DEBUG_KERNEL && LOCKDEP - help - If you say Y here, the lock dependency engine will do - additional runtime checks to debug itself, at the price - of more runtime overhead. - -config DEBUG_ATOMIC_SLEEP - bool "Sleep inside atomic section checking" - select PREEMPT_COUNT - depends on DEBUG_KERNEL - help - If you say Y here, various routines which may sleep will become very - noisy if they are called inside atomic sections: when a spinlock is - held, inside an rcu read side critical section, inside preempt disabled - sections, inside an interrupt, etc... - -config DEBUG_LOCKING_API_SELFTESTS - bool "Locking API boot-time self-tests" - depends on DEBUG_KERNEL - help - Say Y here if you want the kernel to run a short self-test during - bootup. The self-test checks whether common types of locking bugs - are detected by debugging mechanisms or not. (if you disable - lock debugging then those bugs wont be detected of course.) - The following locking APIs are covered: spinlocks, rwlocks, - mutexes and rwsems. - -config LOCK_TORTURE_TEST - tristate "torture tests for locking" - depends on DEBUG_KERNEL - select TORTURE_TEST - default n - help - This option provides a kernel module that runs torture tests - on kernel locking primitives. The kernel module may be built - after the fact on the running kernel to be tested, if desired. - - Say Y here if you want kernel locking-primitive torture tests - to be built into the kernel. - Say M if you want these torture tests to build as a module. - Say N if you are unsure. - -endmenu # lock debugging - -config TRACE_IRQFLAGS - bool - help - Enables hooks to interrupt enabling and disabling for - either tracing or lock debugging. - -config STACKTRACE - bool "Stack backtrace support" - depends on STACKTRACE_SUPPORT - help - This option causes the kernel to create a /proc/pid/stack for - every process, showing its current stack trace. - It is also used by various kernel debugging features that require - stack trace generation. - -config DEBUG_KOBJECT - bool "kobject debugging" - depends on DEBUG_KERNEL - help - If you say Y here, some extra kobject debugging messages will be sent - to the syslog. - -config DEBUG_KOBJECT_RELEASE - bool "kobject release debugging" - depends on DEBUG_OBJECTS_TIMERS - help - kobjects are reference counted objects. This means that their - last reference count put is not predictable, and the kobject can - live on past the point at which a driver decides to drop it's - initial reference to the kobject gained on allocation. An - example of this would be a struct device which has just been - unregistered. - - However, some buggy drivers assume that after such an operation, - the memory backing the kobject can be immediately freed. This - goes completely against the principles of a refcounted object. - - If you say Y here, the kernel will delay the release of kobjects - on the last reference count to improve the visibility of this - kind of kobject release bug. - -config HAVE_DEBUG_BUGVERBOSE - bool - -config DEBUG_BUGVERBOSE - bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EXPERT - depends on BUG && (GENERIC_BUG || HAVE_DEBUG_BUGVERBOSE) - default y - help - Say Y here to make BUG() panics output the file name and line number - of the BUG call as well as the EIP and oops trace. This aids - debugging but costs about 70-100K of memory. - -config DEBUG_LIST - bool "Debug linked list manipulation" - depends on DEBUG_KERNEL - help - Enable this to turn on extended checks in the linked-list - walking routines. - - If unsure, say N. - -config DEBUG_PI_LIST - bool "Debug priority linked list manipulation" - depends on DEBUG_KERNEL - help - Enable this to turn on extended checks in the priority-ordered - linked-list (plist) walking routines. This checks the entire - list multiple times during each manipulation. - - If unsure, say N. - -config DEBUG_SG - bool "Debug SG table operations" - depends on DEBUG_KERNEL - help - Enable this to turn on checks on scatter-gather tables. This can - help find problems with drivers that do not properly initialize - their sg tables. - - If unsure, say N. - -config DEBUG_NOTIFIERS - bool "Debug notifier call chains" - depends on DEBUG_KERNEL - help - Enable this to turn on sanity checking for notifier call chains. - This is most useful for kernel developers to make sure that - modules properly unregister themselves from notifier chains. - This is a relatively cheap check but if you care about maximum - performance, say N. - -config DEBUG_CREDENTIALS - bool "Debug credential management" - depends on DEBUG_KERNEL - help - Enable this to turn on some debug checking for credential - management. The additional code keeps track of the number of - pointers from task_structs to any given cred struct, and checks to - see that this number never exceeds the usage count of the cred - struct. - - Furthermore, if SELinux is enabled, this also checks that the - security pointer in the cred struct is never seen to be invalid. - - If unsure, say N. - -menu "RCU Debugging" - -config PROVE_RCU - def_bool PROVE_LOCKING - -config PROVE_RCU_REPEATEDLY - bool "RCU debugging: don't disable PROVE_RCU on first splat" - depends on PROVE_RCU - default n - help - By itself, PROVE_RCU will disable checking upon issuing the - first warning (or "splat"). This feature prevents such - disabling, allowing multiple RCU-lockdep warnings to be printed - on a single reboot. - - Say Y to allow multiple RCU-lockdep warnings per boot. - - Say N if you are unsure. - -config SPARSE_RCU_POINTER - bool "RCU debugging: sparse-based checks for pointer usage" - default n - help - This feature enables the __rcu sparse annotation for - RCU-protected pointers. This annotation will cause sparse - to flag any non-RCU used of annotated pointers. This can be - helpful when debugging RCU usage. Please note that this feature - is not intended to enforce code cleanliness; it is instead merely - a debugging aid. - - Say Y to make sparse flag questionable use of RCU-protected pointers - - Say N if you are unsure. - -config TORTURE_TEST - tristate - default n - -config RCU_PERF_TEST - tristate "performance tests for RCU" - depends on DEBUG_KERNEL - select TORTURE_TEST - select SRCU - select TASKS_RCU - default n - help - This option provides a kernel module that runs performance - tests on the RCU infrastructure. The kernel module may be built - after the fact on the running kernel to be tested, if desired. - - Say Y here if you want RCU performance tests to be built into - the kernel. - Say M if you want the RCU performance tests to build as a module. - Say N if you are unsure. - -config RCU_TORTURE_TEST - tristate "torture tests for RCU" - depends on DEBUG_KERNEL - select TORTURE_TEST - select SRCU - select TASKS_RCU - default n - help - This option provides a kernel module that runs torture tests - on the RCU infrastructure. The kernel module may be built - after the fact on the running kernel to be tested, if desired. - - Say Y here if you want RCU torture tests to be built into - the kernel. - Say M if you want the RCU torture tests to build as a module. - Say N if you are unsure. - -config RCU_TORTURE_TEST_SLOW_PREINIT - bool "Slow down RCU grace-period pre-initialization to expose races" - depends on RCU_TORTURE_TEST - help - This option delays grace-period pre-initialization (the - propagation of CPU-hotplug changes up the rcu_node combining - tree) for a few jiffies between initializing each pair of - consecutive rcu_node structures. This helps to expose races - involving grace-period pre-initialization, in other words, it - makes your kernel less stable. It can also greatly increase - grace-period latency, especially on systems with large numbers - of CPUs. This is useful when torture-testing RCU, but in - almost no other circumstance. - - Say Y here if you want your system to crash and hang more often. - Say N if you want a sane system. - -config RCU_TORTURE_TEST_SLOW_PREINIT_DELAY - int "How much to slow down RCU grace-period pre-initialization" - range 0 5 - default 3 - depends on RCU_TORTURE_TEST_SLOW_PREINIT - help - This option specifies the number of jiffies to wait between - each rcu_node structure pre-initialization step. - -config RCU_TORTURE_TEST_SLOW_INIT - bool "Slow down RCU grace-period initialization to expose races" - depends on RCU_TORTURE_TEST - help - This option delays grace-period initialization for a few - jiffies between initializing each pair of consecutive - rcu_node structures. This helps to expose races involving - grace-period initialization, in other words, it makes your - kernel less stable. It can also greatly increase grace-period - latency, especially on systems with large numbers of CPUs. - This is useful when torture-testing RCU, but in almost no - other circumstance. - - Say Y here if you want your system to crash and hang more often. - Say N if you want a sane system. - -config RCU_TORTURE_TEST_SLOW_INIT_DELAY - int "How much to slow down RCU grace-period initialization" - range 0 5 - default 3 - depends on RCU_TORTURE_TEST_SLOW_INIT - help - This option specifies the number of jiffies to wait between - each rcu_node structure initialization. - -config RCU_TORTURE_TEST_SLOW_CLEANUP - bool "Slow down RCU grace-period cleanup to expose races" - depends on RCU_TORTURE_TEST - help - This option delays grace-period cleanup for a few jiffies - between cleaning up each pair of consecutive rcu_node - structures. This helps to expose races involving grace-period - cleanup, in other words, it makes your kernel less stable. - It can also greatly increase grace-period latency, especially - on systems with large numbers of CPUs. This is useful when - torture-testing RCU, but in almost no other circumstance. - - Say Y here if you want your system to crash and hang more often. - Say N if you want a sane system. - -config RCU_TORTURE_TEST_SLOW_CLEANUP_DELAY - int "How much to slow down RCU grace-period cleanup" - range 0 5 - default 3 - depends on RCU_TORTURE_TEST_SLOW_CLEANUP - help - This option specifies the number of jiffies to wait between - each rcu_node structure cleanup operation. - -config RCU_CPU_STALL_TIMEOUT - int "RCU CPU stall timeout in seconds" - depends on RCU_STALL_COMMON - range 3 300 - default 21 - help - If a given RCU grace period extends more than the specified - number of seconds, a CPU stall warning is printed. If the - RCU grace period persists, additional CPU stall warnings are - printed at more widely spaced intervals. - -config RCU_TRACE - bool "Enable tracing for RCU" - depends on DEBUG_KERNEL - select TRACE_CLOCK - help - This option provides tracing in RCU which presents stats - in debugfs for debugging RCU implementation. - - Say Y here if you want to enable RCU tracing - Say N if you are unsure. - -config RCU_EQS_DEBUG - bool "Provide debugging asserts for adding NO_HZ support to an arch" - depends on DEBUG_KERNEL - help - This option provides consistency checks in RCU's handling of - NO_HZ. These checks have proven quite helpful in detecting - bugs in arch-specific NO_HZ code. - - Say N here if you need ultimate kernel/user switch latencies - Say Y if you are unsure - -endmenu # "RCU Debugging" - -config DEBUG_WQ_FORCE_RR_CPU - bool "Force round-robin CPU selection for unbound work items" - depends on DEBUG_KERNEL - default n - help - Workqueue used to implicitly guarantee that work items queued - without explicit CPU specified are put on the local CPU. This - guarantee is no longer true and while local CPU is still - preferred work items may be put on foreign CPUs. Kernel - parameter "workqueue.debug_force_rr_cpu" is added to force - round-robin CPU selection to flush out usages which depend on the - now broken guarantee. This config option enables the debug - feature by default. When enabled, memory and cache locality will - be impacted. - -config DEBUG_BLOCK_EXT_DEVT - bool "Force extended block device numbers and spread them" - depends on DEBUG_KERNEL - depends on BLOCK - default n - help - BIG FAT WARNING: ENABLING THIS OPTION MIGHT BREAK BOOTING ON - SOME DISTRIBUTIONS. DO NOT ENABLE THIS UNLESS YOU KNOW WHAT - YOU ARE DOING. Distros, please enable this and fix whatever - is broken. - - Conventionally, block device numbers are allocated from - predetermined contiguous area. However, extended block area - may introduce non-contiguous block device numbers. This - option forces most block device numbers to be allocated from - the extended space and spreads them to discover kernel or - userland code paths which assume predetermined contiguous - device number allocation. - - Note that turning on this debug option shuffles all the - device numbers for all IDE and SCSI devices including libata - ones, so root partition specified using device number - directly (via rdev or root=MAJ:MIN) won't work anymore. - Textual device names (root=/dev/sdXn) will continue to work. - - Say N if you are unsure. - -config CPU_HOTPLUG_STATE_CONTROL - bool "Enable CPU hotplug state control" - depends on DEBUG_KERNEL - depends on HOTPLUG_CPU - default n - help - Allows to write steps between "offline" and "online" to the CPUs - sysfs target file so states can be stepped granular. This is a debug - option for now as the hotplug machinery cannot be stopped and - restarted at arbitrary points yet. - - Say N if your are unsure. - -config NOTIFIER_ERROR_INJECTION - tristate "Notifier error injection" - depends on DEBUG_KERNEL - select DEBUG_FS - help - This option provides the ability to inject artificial errors to - specified notifier chain callbacks. It is useful to test the error - handling of notifier call chain failures. - - Say N if unsure. - -config CPU_NOTIFIER_ERROR_INJECT - tristate "CPU notifier error injection module" - depends on HOTPLUG_CPU && NOTIFIER_ERROR_INJECTION - help - This option provides a kernel module that can be used to test - the error handling of the cpu notifiers by injecting artificial - errors to CPU notifier chain callbacks. It is controlled through - debugfs interface under /sys/kernel/debug/notifier-error-inject/cpu - - If the notifier call chain should be failed with some events - notified, write the error code to "actions//error". - - Example: Inject CPU offline error (-1 == -EPERM) - - # cd /sys/kernel/debug/notifier-error-inject/cpu - # echo -1 > actions/CPU_DOWN_PREPARE/error - # echo 0 > /sys/devices/system/cpu/cpu1/online - bash: echo: write error: Operation not permitted - - To compile this code as a module, choose M here: the module will - be called cpu-notifier-error-inject. - - If unsure, say N. - -config PM_NOTIFIER_ERROR_INJECT - tristate "PM notifier error injection module" - depends on PM && NOTIFIER_ERROR_INJECTION - default m if PM_DEBUG - help - This option provides the ability to inject artificial errors to - PM notifier chain callbacks. It is controlled through debugfs - interface /sys/kernel/debug/notifier-error-inject/pm - - If the notifier call chain should be failed with some events - notified, write the error code to "actions//error". - - Example: Inject PM suspend error (-12 = -ENOMEM) - - # cd /sys/kernel/debug/notifier-error-inject/pm/ - # echo -12 > actions/PM_SUSPEND_PREPARE/error - # echo mem > /sys/power/state - bash: echo: write error: Cannot allocate memory - - To compile this code as a module, choose M here: the module will - be called pm-notifier-error-inject. - - If unsure, say N. - -config OF_RECONFIG_NOTIFIER_ERROR_INJECT - tristate "OF reconfig notifier error injection module" - depends on OF_DYNAMIC && NOTIFIER_ERROR_INJECTION - help - This option provides the ability to inject artificial errors to - OF reconfig notifier chain callbacks. It is controlled - through debugfs interface under - /sys/kernel/debug/notifier-error-inject/OF-reconfig/ - - If the notifier call chain should be failed with some events - notified, write the error code to "actions//error". - - To compile this code as a module, choose M here: the module will - be called of-reconfig-notifier-error-inject. - - If unsure, say N. - -config NETDEV_NOTIFIER_ERROR_INJECT - tristate "Netdev notifier error injection module" - depends on NET && NOTIFIER_ERROR_INJECTION - help - This option provides the ability to inject artificial errors to - netdevice notifier chain callbacks. It is controlled through debugfs - interface /sys/kernel/debug/notifier-error-inject/netdev - - If the notifier call chain should be failed with some events - notified, write the error code to "actions//error". - - Example: Inject netdevice mtu change error (-22 = -EINVAL) - - # cd /sys/kernel/debug/notifier-error-inject/netdev - # echo -22 > actions/NETDEV_CHANGEMTU/error - # ip link set eth0 mtu 1024 - RTNETLINK answers: Invalid argument - - To compile this code as a module, choose M here: the module will - be called netdev-notifier-error-inject. - - If unsure, say N. - -config FAULT_INJECTION - bool "Fault-injection framework" - depends on DEBUG_KERNEL - help - Provide fault-injection framework. - For more details, see Documentation/fault-injection/. - -config FAILSLAB - bool "Fault-injection capability for kmalloc" - depends on FAULT_INJECTION - depends on SLAB || SLUB - help - Provide fault-injection capability for kmalloc. - -config FAIL_PAGE_ALLOC - bool "Fault-injection capabilitiy for alloc_pages()" - depends on FAULT_INJECTION - help - Provide fault-injection capability for alloc_pages(). - -config FAIL_MAKE_REQUEST - bool "Fault-injection capability for disk IO" - depends on FAULT_INJECTION && BLOCK - help - Provide fault-injection capability for disk IO. - -config FAIL_IO_TIMEOUT - bool "Fault-injection capability for faking disk interrupts" - depends on FAULT_INJECTION && BLOCK - help - Provide fault-injection capability on end IO handling. This - will make the block layer "forget" an interrupt as configured, - thus exercising the error handling. - - Only works with drivers that use the generic timeout handling, - for others it wont do anything. - -config FAIL_MMC_REQUEST - bool "Fault-injection capability for MMC IO" - depends on FAULT_INJECTION_DEBUG_FS && MMC - help - Provide fault-injection capability for MMC IO. - This will make the mmc core return data errors. This is - useful to test the error handling in the mmc block device - and to test how the mmc host driver handles retries from - the block device. - -config FAIL_FUTEX - bool "Fault-injection capability for futexes" - select DEBUG_FS - depends on FAULT_INJECTION && FUTEX - help - Provide fault-injection capability for futexes. - -config FAULT_INJECTION_DEBUG_FS - bool "Debugfs entries for fault-injection capabilities" - depends on FAULT_INJECTION && SYSFS && DEBUG_FS - help - Enable configuration of fault-injection capabilities via debugfs. - -config FAULT_INJECTION_STACKTRACE_FILTER - bool "stacktrace filter for fault-injection capabilities" - depends on FAULT_INJECTION_DEBUG_FS && STACKTRACE_SUPPORT - depends on !X86_64 - select STACKTRACE - select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND && !ARC && !SCORE - help - Provide stacktrace filter for fault-injection capabilities - -config LATENCYTOP - bool "Latency measuring infrastructure" - depends on DEBUG_KERNEL - depends on STACKTRACE_SUPPORT - depends on PROC_FS - select FRAME_POINTER if !MIPS && !PPC && !S390 && !MICROBLAZE && !ARM_UNWIND && !ARC - select KALLSYMS - select KALLSYMS_ALL - select STACKTRACE - select SCHEDSTATS - select SCHED_DEBUG - help - Enable this option if you want to use the LatencyTOP tool - to find out which userspace is blocking on what kernel operations. - -source kernel/trace/Kconfig - -menu "Runtime Testing" - -config LKDTM - tristate "Linux Kernel Dump Test Tool Module" - depends on DEBUG_FS - depends on BLOCK - default n - help - This module enables testing of the different dumping mechanisms by - inducing system failures at predefined crash points. - If you don't need it: say N - Choose M here to compile this code as a module. The module will be - called lkdtm. - - Documentation on how to use the module can be found in - Documentation/fault-injection/provoke-crashes.txt - -config TEST_LIST_SORT - bool "Linked list sorting test" - depends on DEBUG_KERNEL - help - Enable this to turn on 'list_sort()' function test. This test is - executed only once during system boot, so affects only boot time. - - If unsure, say N. - -config KPROBES_SANITY_TEST - bool "Kprobes sanity tests" - depends on DEBUG_KERNEL - depends on KPROBES - default n - help - This option provides for testing basic kprobes functionality on - boot. A sample kprobe, jprobe and kretprobe are inserted and - verified for functionality. - - Say N if you are unsure. - -config BACKTRACE_SELF_TEST - tristate "Self test for the backtrace code" - depends on DEBUG_KERNEL - default n - help - This option provides a kernel module that can be used to test - the kernel stack backtrace code. This option is not useful - for distributions or general kernels, but only for kernel - developers working on architecture code. - - Note that if you want to also test saved backtraces, you will - have to enable STACKTRACE as well. - - Say N if you are unsure. - -config RBTREE_TEST - tristate "Red-Black tree test" - depends on DEBUG_KERNEL - help - A benchmark measuring the performance of the rbtree library. - Also includes rbtree invariant checks. - -config INTERVAL_TREE_TEST - tristate "Interval tree test" - depends on m && DEBUG_KERNEL - select INTERVAL_TREE - help - A benchmark measuring the performance of the interval tree library - -config PERCPU_TEST - tristate "Per cpu operations test" - depends on m && DEBUG_KERNEL - help - Enable this option to build test module which validates per-cpu - operations. - - If unsure, say N. - -config ATOMIC64_SELFTEST - bool "Perform an atomic64_t self-test at boot" - help - Enable this option to test the atomic64_t functions at boot. - - If unsure, say N. - -config ASYNC_RAID6_TEST - tristate "Self test for hardware accelerated raid6 recovery" - depends on ASYNC_RAID6_RECOV - select ASYNC_MEMCPY - ---help--- - This is a one-shot self test that permutes through the - recovery of all the possible two disk failure scenarios for a - N-disk array. Recovery is performed with the asynchronous - raid6 recovery routines, and will optionally use an offload - engine if one is available. - - If unsure, say N. - -config TEST_HEXDUMP - tristate "Test functions located in the hexdump module at runtime" - -config TEST_STRING_HELPERS - tristate "Test functions located in the string_helpers module at runtime" - -config TEST_KSTRTOX - tristate "Test kstrto*() family of functions at runtime" - -config TEST_PRINTF - tristate "Test printf() family of functions at runtime" - -config TEST_BITMAP - tristate "Test bitmap_*() family of functions at runtime" - default n - help - Enable this option to test the bitmap functions at boot. - - If unsure, say N. - -config TEST_UUID - tristate "Test functions located in the uuid module at runtime" - -config TEST_RHASHTABLE - tristate "Perform selftest on resizable hash table" - default n - help - Enable this option to test the rhashtable functions at boot. - - If unsure, say N. - -config TEST_HASH - tristate "Perform selftest on hash functions" - default n - help - Enable this option to test the kernel's integer () - and string () hash functions on boot - (or module load). - - This is intended to help people writing architecture-specific - optimized versions. If unsure, say N. - -endmenu # runtime tests - -config PROVIDE_OHCI1394_DMA_INIT - bool "Remote debugging over FireWire early on boot" - depends on PCI && X86 - help - If you want to debug problems which hang or crash the kernel early - on boot and the crashing machine has a FireWire port, you can use - this feature to remotely access the memory of the crashed machine - over FireWire. This employs remote DMA as part of the OHCI1394 - specification which is now the standard for FireWire controllers. - - With remote DMA, you can monitor the printk buffer remotely using - firescope and access all memory below 4GB using fireproxy from gdb. - Even controlling a kernel debugger is possible using remote DMA. - - Usage: - - If ohci1394_dma=early is used as boot parameter, it will initialize - all OHCI1394 controllers which are found in the PCI config space. - - As all changes to the FireWire bus such as enabling and disabling - devices cause a bus reset and thereby disable remote DMA for all - devices, be sure to have the cable plugged and FireWire enabled on - the debugging host before booting the debug target for debugging. - - This code (~1k) is freed after boot. By then, the firewire stack - in charge of the OHCI-1394 controllers should be used instead. - - See Documentation/debugging-via-ohci1394.txt for more information. - -config DMA_API_DEBUG - bool "Enable debugging of DMA-API usage" - depends on HAVE_DMA_API_DEBUG - help - Enable this option to debug the use of the DMA API by device drivers. - With this option you will be able to detect common bugs in device - drivers like double-freeing of DMA mappings or freeing mappings that - were never allocated. - - This also attempts to catch cases where a page owned by DMA is - accessed by the cpu in a way that could cause data corruption. For - example, this enables cow_user_page() to check that the source page is - not undergoing DMA. - - This option causes a performance degradation. Use only if you want to - debug device drivers and dma interactions. - - If unsure, say N. - -config TEST_LKM - tristate "Test module loading with 'hello world' module" - default n - depends on m - help - This builds the "test_module" module that emits "Hello, world" - on printk when loaded. It is designed to be used for basic - evaluation of the module loading subsystem (for example when - validating module verification). It lacks any extra dependencies, - and will not normally be loaded by the system unless explicitly - requested by name. - - If unsure, say N. - -config TEST_USER_COPY - tristate "Test user/kernel boundary protections" - default n - depends on m - help - This builds the "test_user_copy" module that runs sanity checks - on the copy_to/from_user infrastructure, making sure basic - user/kernel boundary testing is working. If it fails to load, - a regression has been detected in the user/kernel memory boundary - protections. - - If unsure, say N. - -config TEST_BPF - tristate "Test BPF filter functionality" - default n - depends on m && NET - help - This builds the "test_bpf" module that runs various test vectors - against the BPF interpreter or BPF JIT compiler depending on the - current setting. This is in particular useful for BPF JIT compiler - development, but also to run regression tests against changes in - the interpreter code. It also enables test stubs for eBPF maps and - verifier used by user space verifier testsuite. - - If unsure, say N. - -config TEST_FIRMWARE - tristate "Test firmware loading via userspace interface" - default n - depends on FW_LOADER - help - This builds the "test_firmware" module that creates a userspace - interface for testing firmware loading. This can be used to - control the triggering of firmware loading without needing an - actual firmware-using device. The contents can be rechecked by - userspace. - - If unsure, say N. - -config TEST_UDELAY - tristate "udelay test driver" - default n - help - This builds the "udelay_test" module that helps to make sure - that udelay() is working properly. - - If unsure, say N. - -config MEMTEST - bool "Memtest" - depends on HAVE_MEMBLOCK - ---help--- - This option adds a kernel parameter 'memtest', which allows memtest - to be set. - memtest=0, mean disabled; -- default - memtest=1, mean do 1 test pattern; - ... - memtest=17, mean do 17 test patterns. - If you are unsure how to answer this question, answer N. - -config TEST_STATIC_KEYS - tristate "Test static keys" - default n - depends on m - help - Test the static key interfaces. - - If unsure, say N. - -source "samples/Kconfig" - -source "lib/Kconfig.kgdb" - -source "lib/Kconfig.ubsan" - -config ARCH_HAS_DEVMEM_IS_ALLOWED - bool - -config STRICT_DEVMEM - bool "Filter access to /dev/mem" - depends on MMU - depends on ARCH_HAS_DEVMEM_IS_ALLOWED - default y if TILE || PPC - ---help--- - If this option is disabled, you allow userspace (root) access to all - of memory, including kernel and userspace memory. Accidental - access to this is obviously disastrous, but specific access can - be used by people debugging the kernel. Note that with PAT support - enabled, even in this case there are restrictions on /dev/mem - use due to the cache aliasing requirements. - - If this option is switched on, and IO_STRICT_DEVMEM=n, the /dev/mem - file only allows userspace access to PCI space and the BIOS code and - data regions. This is sufficient for dosemu and X and all common - users of /dev/mem. - - If in doubt, say Y. - -config IO_STRICT_DEVMEM - bool "Filter I/O access to /dev/mem" - depends on STRICT_DEVMEM - ---help--- - If this option is disabled, you allow userspace (root) access to all - io-memory regardless of whether a driver is actively using that - range. Accidental access to this is obviously disastrous, but - specific access can be used by people debugging kernel drivers. - - If this option is switched on, the /dev/mem file only allows - userspace access to *idle* io-memory ranges (see /proc/iomem) This - may break traditional users of /dev/mem (dosemu, legacy X, etc...) - if the driver using a given range cannot be disabled. - - If in doubt, say Y. diff --git a/src/linux/lib/Kconfig.kasan b/src/linux/lib/Kconfig.kasan deleted file mode 100644 index bd38aab..0000000 --- a/src/linux/lib/Kconfig.kasan +++ /dev/null @@ -1,56 +0,0 @@ -config HAVE_ARCH_KASAN - bool - -if HAVE_ARCH_KASAN - -config KASAN - bool "KASan: runtime memory debugger" - depends on SLUB || (SLAB && !DEBUG_SLAB) - select CONSTRUCTORS - select STACKDEPOT - help - Enables kernel address sanitizer - runtime memory debugger, - designed to find out-of-bounds accesses and use-after-free bugs. - This is strictly a debugging feature and it requires a gcc version - of 4.9.2 or later. Detection of out of bounds accesses to stack or - global variables requires gcc 5.0 or later. - This feature consumes about 1/8 of available memory and brings about - ~x3 performance slowdown. - For better error detection enable CONFIG_STACKTRACE. - Currently CONFIG_KASAN doesn't work with CONFIG_DEBUG_SLAB - (the resulting kernel does not boot). - -choice - prompt "Instrumentation type" - depends on KASAN - default KASAN_OUTLINE - -config KASAN_OUTLINE - bool "Outline instrumentation" - help - Before every memory access compiler insert function call - __asan_load*/__asan_store*. These functions performs check - of shadow memory. This is slower than inline instrumentation, - however it doesn't bloat size of kernel's .text section so - much as inline does. - -config KASAN_INLINE - bool "Inline instrumentation" - help - Compiler directly inserts code checking shadow memory before - memory accesses. This is faster than outline (in some workloads - it gives about x2 boost over outline instrumentation), but - make kernel's .text size much bigger. - This requires a gcc version of 5.0 or later. - -endchoice - -config TEST_KASAN - tristate "Module for testing kasan for bug detection" - depends on m && KASAN - help - This is a test module doing various nasty things like - out of bounds accesses, use after free. It is useful for testing - kernel debugging features like kernel address sanitizer. - -endif diff --git a/src/linux/lib/Kconfig.kgdb b/src/linux/lib/Kconfig.kgdb deleted file mode 100644 index 533f912..0000000 --- a/src/linux/lib/Kconfig.kgdb +++ /dev/null @@ -1,126 +0,0 @@ - -config HAVE_ARCH_KGDB - bool - -menuconfig KGDB - bool "KGDB: kernel debugger" - depends on HAVE_ARCH_KGDB - depends on DEBUG_KERNEL - help - If you say Y here, it will be possible to remotely debug the - kernel using gdb. It is recommended but not required, that - you also turn on the kernel config option - CONFIG_FRAME_POINTER to aid in producing more reliable stack - backtraces in the external debugger. Documentation of - kernel debugger is available at http://kgdb.sourceforge.net - as well as in DocBook form in Documentation/DocBook/. If - unsure, say N. - -if KGDB - -config KGDB_SERIAL_CONSOLE - tristate "KGDB: use kgdb over the serial console" - select CONSOLE_POLL - select MAGIC_SYSRQ - depends on TTY && HW_CONSOLE - default y - help - Share a serial console with kgdb. Sysrq-g must be used - to break in initially. - -config KGDB_TESTS - bool "KGDB: internal test suite" - default n - help - This is a kgdb I/O module specifically designed to test - kgdb's internal functions. This kgdb I/O module is - intended to for the development of new kgdb stubs - as well as regression testing the kgdb internals. - See the drivers/misc/kgdbts.c for the details about - the tests. The most basic of this I/O module is to boot - a kernel boot arguments "kgdbwait kgdbts=V1F100" - -config KGDB_TESTS_ON_BOOT - bool "KGDB: Run tests on boot" - depends on KGDB_TESTS - default n - help - Run the kgdb tests on boot up automatically without the need - to pass in a kernel parameter - -config KGDB_TESTS_BOOT_STRING - string "KGDB: which internal kgdb tests to run" - depends on KGDB_TESTS_ON_BOOT - default "V1F100" - help - This is the command string to send the kgdb test suite on - boot. See the drivers/misc/kgdbts.c for detailed - information about other strings you could use beyond the - default of V1F100. - -config KGDB_LOW_LEVEL_TRAP - bool "KGDB: Allow debugging with traps in notifiers" - depends on X86 || MIPS - default n - help - This will add an extra call back to kgdb for the breakpoint - exception handler which will allow kgdb to step through a - notify handler. - -config KGDB_KDB - bool "KGDB_KDB: include kdb frontend for kgdb" - default n - help - KDB frontend for kernel - -config KDB_DEFAULT_ENABLE - hex "KDB: Select kdb command functions to be enabled by default" - depends on KGDB_KDB - default 0x1 - help - Specifiers which kdb commands are enabled by default. This may - be set to 1 or 0 to enable all commands or disable almost all - commands. - - Alternatively the following bitmask applies: - - 0x0002 - allow arbitrary reads from memory and symbol lookup - 0x0004 - allow arbitrary writes to memory - 0x0008 - allow current register state to be inspected - 0x0010 - allow current register state to be modified - 0x0020 - allow passive inspection (backtrace, process list, lsmod) - 0x0040 - allow flow control management (breakpoint, single step) - 0x0080 - enable signalling of processes - 0x0100 - allow machine to be rebooted - - The config option merely sets the default at boot time. Both - issuing 'echo X > /sys/module/kdb/parameters/cmd_enable' or - setting with kdb.cmd_enable=X kernel command line option will - override the default settings. - -config KDB_KEYBOARD - bool "KGDB_KDB: keyboard as input device" - depends on VT && KGDB_KDB - default n - help - KDB can use a PS/2 type keyboard for an input device - -config KDB_CONTINUE_CATASTROPHIC - int "KDB: continue after catastrophic errors" - depends on KGDB_KDB - default "0" - help - This integer controls the behaviour of kdb when the kernel gets a - catastrophic error, i.e. for a panic or oops. - When KDB is active and a catastrophic error occurs, nothing extra - will happen until you type 'go'. - CONFIG_KDB_CONTINUE_CATASTROPHIC == 0 (default). The first time - you type 'go', you will be warned by kdb. The secend time you type - 'go', KDB tries to continue. No guarantees that the - kernel is still usable in this situation. - CONFIG_KDB_CONTINUE_CATASTROPHIC == 1. KDB tries to continue. - No guarantees that the kernel is still usable in this situation. - CONFIG_KDB_CONTINUE_CATASTROPHIC == 2. KDB forces a reboot. - If you are not sure, say 0. - -endif # KGDB diff --git a/src/linux/lib/Kconfig.kmemcheck b/src/linux/lib/Kconfig.kmemcheck deleted file mode 100644 index 846e039..0000000 --- a/src/linux/lib/Kconfig.kmemcheck +++ /dev/null @@ -1,94 +0,0 @@ -config HAVE_ARCH_KMEMCHECK - bool - -if HAVE_ARCH_KMEMCHECK - -menuconfig KMEMCHECK - bool "kmemcheck: trap use of uninitialized memory" - depends on DEBUG_KERNEL - depends on !X86_USE_3DNOW - depends on SLUB || SLAB - depends on !CC_OPTIMIZE_FOR_SIZE - depends on !FUNCTION_TRACER - select FRAME_POINTER - select STACKTRACE - default n - help - This option enables tracing of dynamically allocated kernel memory - to see if memory is used before it has been given an initial value. - Be aware that this requires half of your memory for bookkeeping and - will insert extra code at *every* read and write to tracked memory - thus slow down the kernel code (but user code is unaffected). - - The kernel may be started with kmemcheck=0 or kmemcheck=1 to disable - or enable kmemcheck at boot-time. If the kernel is started with - kmemcheck=0, the large memory and CPU overhead is not incurred. - -choice - prompt "kmemcheck: default mode at boot" - depends on KMEMCHECK - default KMEMCHECK_ONESHOT_BY_DEFAULT - help - This option controls the default behaviour of kmemcheck when the - kernel boots and no kmemcheck= parameter is given. - -config KMEMCHECK_DISABLED_BY_DEFAULT - bool "disabled" - depends on KMEMCHECK - -config KMEMCHECK_ENABLED_BY_DEFAULT - bool "enabled" - depends on KMEMCHECK - -config KMEMCHECK_ONESHOT_BY_DEFAULT - bool "one-shot" - depends on KMEMCHECK - help - In one-shot mode, only the first error detected is reported before - kmemcheck is disabled. - -endchoice - -config KMEMCHECK_QUEUE_SIZE - int "kmemcheck: error queue size" - depends on KMEMCHECK - default 64 - help - Select the maximum number of errors to store in the queue. Since - errors can occur virtually anywhere and in any context, we need a - temporary storage area which is guarantueed not to generate any - other faults. The queue will be emptied as soon as a tasklet may - be scheduled. If the queue is full, new error reports will be - lost. - -config KMEMCHECK_SHADOW_COPY_SHIFT - int "kmemcheck: shadow copy size (5 => 32 bytes, 6 => 64 bytes)" - depends on KMEMCHECK - range 2 8 - default 5 - help - Select the number of shadow bytes to save along with each entry of - the queue. These bytes indicate what parts of an allocation are - initialized, uninitialized, etc. and will be displayed when an - error is detected to help the debugging of a particular problem. - -config KMEMCHECK_PARTIAL_OK - bool "kmemcheck: allow partially uninitialized memory" - depends on KMEMCHECK - default y - help - This option works around certain GCC optimizations that produce - 32-bit reads from 16-bit variables where the upper 16 bits are - thrown away afterwards. This may of course also hide some real - bugs. - -config KMEMCHECK_BITOPS_OK - bool "kmemcheck: allow bit-field manipulation" - depends on KMEMCHECK - default n - help - This option silences warnings that would be generated for bit-field - accesses where not all the bits are initialized at the same time. - This may also hide some real bugs. - -endif diff --git a/src/linux/lib/Kconfig.ubsan b/src/linux/lib/Kconfig.ubsan deleted file mode 100644 index bc6e651..0000000 --- a/src/linux/lib/Kconfig.ubsan +++ /dev/null @@ -1,47 +0,0 @@ -config ARCH_HAS_UBSAN_SANITIZE_ALL - bool - -config ARCH_WANTS_UBSAN_NO_NULL - def_bool n - -config UBSAN - bool "Undefined behaviour sanity checker" - help - This option enables undefined behaviour sanity checker - Compile-time instrumentation is used to detect various undefined - behaviours in runtime. Various types of checks may be enabled - via boot parameter ubsan_handle (see: Documentation/ubsan.txt). - -config UBSAN_SANITIZE_ALL - bool "Enable instrumentation for the entire kernel" - depends on UBSAN - depends on ARCH_HAS_UBSAN_SANITIZE_ALL - - # We build with -Wno-maybe-uninitilzed, but we still want to - # use -Wmaybe-uninitilized in allmodconfig builds. - # So dependsy bellow used to disable this option in allmodconfig - depends on !COMPILE_TEST - default y - help - This option activates instrumentation for the entire kernel. - If you don't enable this option, you have to explicitly specify - UBSAN_SANITIZE := y for the files/directories you want to check for UB. - Enabling this option will get kernel image size increased - significantly. - -config UBSAN_ALIGNMENT - bool "Enable checking of pointers alignment" - depends on UBSAN - default y if !HAVE_EFFICIENT_UNALIGNED_ACCESS - help - This option enables detection of unaligned memory accesses. - Enabling this option on architectures that support unaligned - accesses may produce a lot of false positives. - -config UBSAN_NULL - bool "Enable checking of null pointers" - depends on UBSAN - default y if !ARCH_WANTS_UBSAN_NO_NULL - help - This option enables detection of memory accesses via a - null pointer. diff --git a/src/linux/lib/Makefile b/src/linux/lib/Makefile deleted file mode 100644 index 50144a3..0000000 --- a/src/linux/lib/Makefile +++ /dev/null @@ -1,232 +0,0 @@ -# -# Makefile for some libs needed in the kernel. -# - -ifdef CONFIG_FUNCTION_TRACER -ORIG_CFLAGS := $(KBUILD_CFLAGS) -KBUILD_CFLAGS = $(subst $(CC_FLAGS_FTRACE),,$(ORIG_CFLAGS)) -endif - -# These files are disabled because they produce lots of non-interesting and/or -# flaky coverage that is not a function of syscall inputs. For example, -# rbtree can be global and individual rotations don't correlate with inputs. -KCOV_INSTRUMENT_string.o := n -KCOV_INSTRUMENT_rbtree.o := n -KCOV_INSTRUMENT_list_debug.o := n -KCOV_INSTRUMENT_debugobjects.o := n -KCOV_INSTRUMENT_dynamic_debug.o := n - -lib-y := ctype.o string.o vsprintf.o cmdline.o \ - rbtree.o radix-tree.o dump_stack.o timerqueue.o\ - idr.o int_sqrt.o extable.o \ - sha1.o chacha20.o md5.o irq_regs.o argv_split.o \ - flex_proportions.o ratelimit.o show_mem.o \ - is_single_threaded.o plist.o decompress.o kobject_uevent.o \ - earlycpio.o seq_buf.o nmi_backtrace.o nodemask.o win_minmax.o - -lib-$(CONFIG_MMU) += ioremap.o -lib-$(CONFIG_SMP) += cpumask.o -lib-$(CONFIG_HAS_DMA) += dma-noop.o - -lib-y += kobject.o klist.o -obj-y += lockref.o - -obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ - bust_spinlocks.o kasprintf.o bitmap.o scatterlist.o \ - gcd.o lcm.o list_sort.o uuid.o flex_array.o iov_iter.o clz_ctz.o \ - bsearch.o find_bit.o llist.o memweight.o kfifo.o \ - percpu-refcount.o percpu_ida.o rhashtable.o reciprocal_div.o \ - once.o -obj-y += string_helpers.o -obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o -obj-y += hexdump.o -obj-$(CONFIG_TEST_HEXDUMP) += test_hexdump.o -obj-y += kstrtox.o -obj-$(CONFIG_TEST_BPF) += test_bpf.o -obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o -obj-$(CONFIG_TEST_HASH) += test_hash.o -obj-$(CONFIG_TEST_KASAN) += test_kasan.o -obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o -obj-$(CONFIG_TEST_LKM) += test_module.o -obj-$(CONFIG_TEST_RHASHTABLE) += test_rhashtable.o -obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o -obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o -obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o -obj-$(CONFIG_TEST_PRINTF) += test_printf.o -obj-$(CONFIG_TEST_BITMAP) += test_bitmap.o -obj-$(CONFIG_TEST_UUID) += test_uuid.o - -ifeq ($(CONFIG_DEBUG_KOBJECT),y) -CFLAGS_kobject.o += -DDEBUG -CFLAGS_kobject_uevent.o += -DDEBUG -endif - -obj-$(CONFIG_DEBUG_INFO_REDUCED) += debug_info.o -CFLAGS_debug_info.o += $(call cc-option, -femit-struct-debug-detailed=any) - -obj-$(CONFIG_GENERIC_IOMAP) += iomap.o -obj-$(CONFIG_GENERIC_PCI_IOMAP) += pci_iomap.o -obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o -obj-$(CONFIG_CHECK_SIGNATURE) += check_signature.o -obj-$(CONFIG_DEBUG_LOCKING_API_SELFTESTS) += locking-selftest.o - -obj-$(CONFIG_GENERIC_HWEIGHT) += hweight.o - -obj-$(CONFIG_BTREE) += btree.o -obj-$(CONFIG_INTERVAL_TREE) += interval_tree.o -obj-$(CONFIG_ASSOCIATIVE_ARRAY) += assoc_array.o -obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o -obj-$(CONFIG_DEBUG_LIST) += list_debug.o -obj-$(CONFIG_DEBUG_OBJECTS) += debugobjects.o - -ifneq ($(CONFIG_HAVE_DEC_LOCK),y) - lib-y += dec_and_lock.o -endif - -obj-$(CONFIG_BITREVERSE) += bitrev.o -obj-$(CONFIG_RATIONAL) += rational.o -obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o -obj-$(CONFIG_CRC16) += crc16.o -obj-$(CONFIG_CRC_T10DIF)+= crc-t10dif.o -obj-$(CONFIG_CRC_ITU_T) += crc-itu-t.o -obj-$(CONFIG_CRC32) += crc32.o -obj-$(CONFIG_CRC7) += crc7.o -obj-$(CONFIG_LIBCRC32C) += libcrc32c.o -obj-$(CONFIG_CRC8) += crc8.o -obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o - -obj-$(CONFIG_842_COMPRESS) += 842/ -obj-$(CONFIG_842_DECOMPRESS) += 842/ -obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/ -obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/ -obj-$(CONFIG_REED_SOLOMON) += reed_solomon/ -obj-$(CONFIG_BCH) += bch.o -obj-$(CONFIG_LZO_COMPRESS) += lzo/ -obj-$(CONFIG_LZO_DECOMPRESS) += lzo/ -obj-$(CONFIG_LZ4_COMPRESS) += lz4/ -obj-$(CONFIG_LZ4HC_COMPRESS) += lz4/ -obj-$(CONFIG_LZ4_DECOMPRESS) += lz4/ -obj-$(CONFIG_XZ_DEC) += xz/ -obj-$(CONFIG_RAID6_PQ) += raid6/ - -lib-$(CONFIG_DECOMPRESS_GZIP) += decompress_inflate.o -lib-$(CONFIG_DECOMPRESS_BZIP2) += decompress_bunzip2.o -lib-$(CONFIG_DECOMPRESS_LZMA) += decompress_unlzma.o -lib-$(CONFIG_DECOMPRESS_XZ) += decompress_unxz.o -lib-$(CONFIG_DECOMPRESS_LZO) += decompress_unlzo.o -lib-$(CONFIG_DECOMPRESS_LZ4) += decompress_unlz4.o - -obj-$(CONFIG_TEXTSEARCH) += textsearch.o -obj-$(CONFIG_TEXTSEARCH_KMP) += ts_kmp.o -obj-$(CONFIG_TEXTSEARCH_BM) += ts_bm.o -obj-$(CONFIG_TEXTSEARCH_FSM) += ts_fsm.o -obj-$(CONFIG_SMP) += percpu_counter.o -obj-$(CONFIG_AUDIT_GENERIC) += audit.o -obj-$(CONFIG_AUDIT_COMPAT_GENERIC) += compat_audit.o - -obj-$(CONFIG_SWIOTLB) += swiotlb.o -obj-$(CONFIG_IOMMU_HELPER) += iommu-helper.o iommu-common.o -obj-$(CONFIG_FAULT_INJECTION) += fault-inject.o -obj-$(CONFIG_NOTIFIER_ERROR_INJECTION) += notifier-error-inject.o -obj-$(CONFIG_CPU_NOTIFIER_ERROR_INJECT) += cpu-notifier-error-inject.o -obj-$(CONFIG_PM_NOTIFIER_ERROR_INJECT) += pm-notifier-error-inject.o -obj-$(CONFIG_NETDEV_NOTIFIER_ERROR_INJECT) += netdev-notifier-error-inject.o -obj-$(CONFIG_MEMORY_NOTIFIER_ERROR_INJECT) += memory-notifier-error-inject.o -obj-$(CONFIG_OF_RECONFIG_NOTIFIER_ERROR_INJECT) += \ - of-reconfig-notifier-error-inject.o - -lib-$(CONFIG_GENERIC_BUG) += bug.o - -obj-$(CONFIG_HAVE_ARCH_TRACEHOOK) += syscall.o - -obj-$(CONFIG_DYNAMIC_DEBUG) += dynamic_debug.o - -obj-$(CONFIG_NLATTR) += nlattr.o - -obj-$(CONFIG_LRU_CACHE) += lru_cache.o - -obj-$(CONFIG_DMA_API_DEBUG) += dma-debug.o - -obj-$(CONFIG_GENERIC_CSUM) += checksum.o - -obj-$(CONFIG_GENERIC_ATOMIC64) += atomic64.o - -obj-$(CONFIG_ATOMIC64_SELFTEST) += atomic64_test.o - -obj-$(CONFIG_CPU_RMAP) += cpu_rmap.o - -obj-$(CONFIG_CORDIC) += cordic.o - -obj-$(CONFIG_DQL) += dynamic_queue_limits.o - -obj-$(CONFIG_GLOB) += glob.o - -obj-$(CONFIG_MPILIB) += mpi/ -obj-$(CONFIG_SIGNATURE) += digsig.o - -lib-$(CONFIG_CLZ_TAB) += clz_tab.o - -obj-$(CONFIG_DDR) += jedec_ddr_data.o - -obj-$(CONFIG_GENERIC_STRNCPY_FROM_USER) += strncpy_from_user.o -obj-$(CONFIG_GENERIC_STRNLEN_USER) += strnlen_user.o - -obj-$(CONFIG_GENERIC_NET_UTILS) += net_utils.o - -obj-$(CONFIG_SG_SPLIT) += sg_split.o -obj-$(CONFIG_SG_POOL) += sg_pool.o -obj-$(CONFIG_STMP_DEVICE) += stmp_device.o -obj-$(CONFIG_IRQ_POLL) += irq_poll.o - -obj-$(CONFIG_STACKDEPOT) += stackdepot.o -KASAN_SANITIZE_stackdepot.o := n -KCOV_INSTRUMENT_stackdepot.o := n - -libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o \ - fdt_empty_tree.o -$(foreach file, $(libfdt_files), \ - $(eval CFLAGS_$(file) = -I$(src)/../scripts/dtc/libfdt)) -lib-$(CONFIG_LIBFDT) += $(libfdt_files) - -obj-$(CONFIG_RBTREE_TEST) += rbtree_test.o -obj-$(CONFIG_INTERVAL_TREE_TEST) += interval_tree_test.o - -obj-$(CONFIG_PERCPU_TEST) += percpu_test.o - -obj-$(CONFIG_ASN1) += asn1_decoder.o - -obj-$(CONFIG_FONT_SUPPORT) += fonts/ - -hostprogs-y := gen_crc32table -clean-files := crc32table.h - -$(obj)/crc32.o: $(obj)/crc32table.h - -quiet_cmd_crc32 = GEN $@ - cmd_crc32 = $< > $@ - -$(obj)/crc32table.h: $(obj)/gen_crc32table - $(call cmd,crc32) - -# -# Build a fast OID lookip registry from include/linux/oid_registry.h -# -obj-$(CONFIG_OID_REGISTRY) += oid_registry.o - -$(obj)/oid_registry.o: $(obj)/oid_registry_data.c - -$(obj)/oid_registry_data.c: $(srctree)/include/linux/oid_registry.h \ - $(src)/build_OID_registry - $(call cmd,build_OID_registry) - -quiet_cmd_build_OID_registry = GEN $@ - cmd_build_OID_registry = perl $(srctree)/$(src)/build_OID_registry $< $@ - -clean-files += oid_registry_data.c - -obj-$(CONFIG_UCS2_STRING) += ucs2_string.o -obj-$(CONFIG_UBSAN) += ubsan.o - -UBSAN_SANITIZE_ubsan.o := n - -obj-$(CONFIG_SBITMAP) += sbitmap.o diff --git a/src/linux/lib/argv_split.c b/src/linux/lib/argv_split.c deleted file mode 100644 index e927ed0..0000000 --- a/src/linux/lib/argv_split.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Helper function for splitting a string into an argv-like array. - */ - -#include -#include -#include -#include -#include - -static int count_argc(const char *str) -{ - int count = 0; - bool was_space; - - for (was_space = true; *str; str++) { - if (isspace(*str)) { - was_space = true; - } else if (was_space) { - was_space = false; - count++; - } - } - - return count; -} - -/** - * argv_free - free an argv - * @argv - the argument vector to be freed - * - * Frees an argv and the strings it points to. - */ -void argv_free(char **argv) -{ - argv--; - kfree(argv[0]); - kfree(argv); -} -EXPORT_SYMBOL(argv_free); - -/** - * argv_split - split a string at whitespace, returning an argv - * @gfp: the GFP mask used to allocate memory - * @str: the string to be split - * @argcp: returned argument count - * - * Returns an array of pointers to strings which are split out from - * @str. This is performed by strictly splitting on white-space; no - * quote processing is performed. Multiple whitespace characters are - * considered to be a single argument separator. The returned array - * is always NULL-terminated. Returns NULL on memory allocation - * failure. - * - * The source string at `str' may be undergoing concurrent alteration via - * userspace sysctl activity (at least). The argv_split() implementation - * attempts to handle this gracefully by taking a local copy to work on. - */ -char **argv_split(gfp_t gfp, const char *str, int *argcp) -{ - char *argv_str; - bool was_space; - char **argv, **argv_ret; - int argc; - - argv_str = kstrndup(str, KMALLOC_MAX_SIZE - 1, gfp); - if (!argv_str) - return NULL; - - argc = count_argc(argv_str); - argv = kmalloc(sizeof(*argv) * (argc + 2), gfp); - if (!argv) { - kfree(argv_str); - return NULL; - } - - *argv = argv_str; - argv_ret = ++argv; - for (was_space = true; *argv_str; argv_str++) { - if (isspace(*argv_str)) { - was_space = true; - *argv_str = 0; - } else if (was_space) { - was_space = false; - *argv++ = argv_str; - } - } - *argv = NULL; - - if (argcp) - *argcp = argc; - return argv_ret; -} -EXPORT_SYMBOL(argv_split); diff --git a/src/linux/lib/atomic64.c b/src/linux/lib/atomic64.c deleted file mode 100644 index 53c2d5e..0000000 --- a/src/linux/lib/atomic64.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Generic implementation of 64-bit atomics using spinlocks, - * useful on processors that don't have 64-bit atomic instructions. - * - * Copyright © 2009 Paul Mackerras, IBM Corp. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include -#include -#include -#include - -/* - * We use a hashed array of spinlocks to provide exclusive access - * to each atomic64_t variable. Since this is expected to used on - * systems with small numbers of CPUs (<= 4 or so), we use a - * relatively small array of 16 spinlocks to avoid wasting too much - * memory on the spinlock array. - */ -#define NR_LOCKS 16 - -/* - * Ensure each lock is in a separate cacheline. - */ -static union { - raw_spinlock_t lock; - char pad[L1_CACHE_BYTES]; -} atomic64_lock[NR_LOCKS] __cacheline_aligned_in_smp = { - [0 ... (NR_LOCKS - 1)] = { - .lock = __RAW_SPIN_LOCK_UNLOCKED(atomic64_lock.lock), - }, -}; - -static inline raw_spinlock_t *lock_addr(const atomic64_t *v) -{ - unsigned long addr = (unsigned long) v; - - addr >>= L1_CACHE_SHIFT; - addr ^= (addr >> 8) ^ (addr >> 16); - return &atomic64_lock[addr & (NR_LOCKS - 1)].lock; -} - -long long atomic64_read(const atomic64_t *v) -{ - unsigned long flags; - raw_spinlock_t *lock = lock_addr(v); - long long val; - - raw_spin_lock_irqsave(lock, flags); - val = v->counter; - raw_spin_unlock_irqrestore(lock, flags); - return val; -} -EXPORT_SYMBOL(atomic64_read); - -void atomic64_set(atomic64_t *v, long long i) -{ - unsigned long flags; - raw_spinlock_t *lock = lock_addr(v); - - raw_spin_lock_irqsave(lock, flags); - v->counter = i; - raw_spin_unlock_irqrestore(lock, flags); -} -EXPORT_SYMBOL(atomic64_set); - -#define ATOMIC64_OP(op, c_op) \ -void atomic64_##op(long long a, atomic64_t *v) \ -{ \ - unsigned long flags; \ - raw_spinlock_t *lock = lock_addr(v); \ - \ - raw_spin_lock_irqsave(lock, flags); \ - v->counter c_op a; \ - raw_spin_unlock_irqrestore(lock, flags); \ -} \ -EXPORT_SYMBOL(atomic64_##op); - -#define ATOMIC64_OP_RETURN(op, c_op) \ -long long atomic64_##op##_return(long long a, atomic64_t *v) \ -{ \ - unsigned long flags; \ - raw_spinlock_t *lock = lock_addr(v); \ - long long val; \ - \ - raw_spin_lock_irqsave(lock, flags); \ - val = (v->counter c_op a); \ - raw_spin_unlock_irqrestore(lock, flags); \ - return val; \ -} \ -EXPORT_SYMBOL(atomic64_##op##_return); - -#define ATOMIC64_FETCH_OP(op, c_op) \ -long long atomic64_fetch_##op(long long a, atomic64_t *v) \ -{ \ - unsigned long flags; \ - raw_spinlock_t *lock = lock_addr(v); \ - long long val; \ - \ - raw_spin_lock_irqsave(lock, flags); \ - val = v->counter; \ - v->counter c_op a; \ - raw_spin_unlock_irqrestore(lock, flags); \ - return val; \ -} \ -EXPORT_SYMBOL(atomic64_fetch_##op); - -#define ATOMIC64_OPS(op, c_op) \ - ATOMIC64_OP(op, c_op) \ - ATOMIC64_OP_RETURN(op, c_op) \ - ATOMIC64_FETCH_OP(op, c_op) - -ATOMIC64_OPS(add, +=) -ATOMIC64_OPS(sub, -=) - -#undef ATOMIC64_OPS -#define ATOMIC64_OPS(op, c_op) \ - ATOMIC64_OP(op, c_op) \ - ATOMIC64_OP_RETURN(op, c_op) \ - ATOMIC64_FETCH_OP(op, c_op) - -ATOMIC64_OPS(and, &=) -ATOMIC64_OPS(or, |=) -ATOMIC64_OPS(xor, ^=) - -#undef ATOMIC64_OPS -#undef ATOMIC64_FETCH_OP -#undef ATOMIC64_OP_RETURN -#undef ATOMIC64_OP - -long long atomic64_dec_if_positive(atomic64_t *v) -{ - unsigned long flags; - raw_spinlock_t *lock = lock_addr(v); - long long val; - - raw_spin_lock_irqsave(lock, flags); - val = v->counter - 1; - if (val >= 0) - v->counter = val; - raw_spin_unlock_irqrestore(lock, flags); - return val; -} -EXPORT_SYMBOL(atomic64_dec_if_positive); - -long long atomic64_cmpxchg(atomic64_t *v, long long o, long long n) -{ - unsigned long flags; - raw_spinlock_t *lock = lock_addr(v); - long long val; - - raw_spin_lock_irqsave(lock, flags); - val = v->counter; - if (val == o) - v->counter = n; - raw_spin_unlock_irqrestore(lock, flags); - return val; -} -EXPORT_SYMBOL(atomic64_cmpxchg); - -long long atomic64_xchg(atomic64_t *v, long long new) -{ - unsigned long flags; - raw_spinlock_t *lock = lock_addr(v); - long long val; - - raw_spin_lock_irqsave(lock, flags); - val = v->counter; - v->counter = new; - raw_spin_unlock_irqrestore(lock, flags); - return val; -} -EXPORT_SYMBOL(atomic64_xchg); - -int atomic64_add_unless(atomic64_t *v, long long a, long long u) -{ - unsigned long flags; - raw_spinlock_t *lock = lock_addr(v); - int ret = 0; - - raw_spin_lock_irqsave(lock, flags); - if (v->counter != u) { - v->counter += a; - ret = 1; - } - raw_spin_unlock_irqrestore(lock, flags); - return ret; -} -EXPORT_SYMBOL(atomic64_add_unless); diff --git a/src/linux/lib/bcd.c b/src/linux/lib/bcd.c deleted file mode 100644 index 40d304e..0000000 --- a/src/linux/lib/bcd.c +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include - -unsigned _bcd2bin(unsigned char val) -{ - return (val & 0x0f) + (val >> 4) * 10; -} -EXPORT_SYMBOL(_bcd2bin); - -unsigned char _bin2bcd(unsigned val) -{ - return ((val / 10) << 4) + val % 10; -} -EXPORT_SYMBOL(_bin2bcd); diff --git a/src/linux/lib/bitmap.c b/src/linux/lib/bitmap.c deleted file mode 100644 index 0b66f0e..0000000 --- a/src/linux/lib/bitmap.c +++ /dev/null @@ -1,1214 +0,0 @@ -/* - * lib/bitmap.c - * Helper functions for bitmap.h. - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * bitmaps provide an array of bits, implemented using an an - * array of unsigned longs. The number of valid bits in a - * given bitmap does _not_ need to be an exact multiple of - * BITS_PER_LONG. - * - * The possible unused bits in the last, partially used word - * of a bitmap are 'don't care'. The implementation makes - * no particular effort to keep them zero. It ensures that - * their value will not affect the results of any operation. - * The bitmap operations that return Boolean (bitmap_empty, - * for example) or scalar (bitmap_weight, for example) results - * carefully filter out these unused bits from impacting their - * results. - * - * These operations actually hold to a slightly stronger rule: - * if you don't input any bitmaps to these ops that have some - * unused bits set, then they won't output any set unused bits - * in output bitmaps. - * - * The byte ordering of bitmaps is more natural on little - * endian architectures. See the big-endian headers - * include/asm-ppc64/bitops.h and include/asm-s390/bitops.h - * for the best explanations of this ordering. - */ - -int __bitmap_equal(const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int bits) -{ - unsigned int k, lim = bits/BITS_PER_LONG; - for (k = 0; k < lim; ++k) - if (bitmap1[k] != bitmap2[k]) - return 0; - - if (bits % BITS_PER_LONG) - if ((bitmap1[k] ^ bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) - return 0; - - return 1; -} -EXPORT_SYMBOL(__bitmap_equal); - -void __bitmap_complement(unsigned long *dst, const unsigned long *src, unsigned int bits) -{ - unsigned int k, lim = bits/BITS_PER_LONG; - for (k = 0; k < lim; ++k) - dst[k] = ~src[k]; - - if (bits % BITS_PER_LONG) - dst[k] = ~src[k]; -} -EXPORT_SYMBOL(__bitmap_complement); - -/** - * __bitmap_shift_right - logical right shift of the bits in a bitmap - * @dst : destination bitmap - * @src : source bitmap - * @shift : shift by this many bits - * @nbits : bitmap size, in bits - * - * Shifting right (dividing) means moving bits in the MS -> LS bit - * direction. Zeros are fed into the vacated MS positions and the - * LS bits shifted off the bottom are lost. - */ -void __bitmap_shift_right(unsigned long *dst, const unsigned long *src, - unsigned shift, unsigned nbits) -{ - unsigned k, lim = BITS_TO_LONGS(nbits); - unsigned off = shift/BITS_PER_LONG, rem = shift % BITS_PER_LONG; - unsigned long mask = BITMAP_LAST_WORD_MASK(nbits); - for (k = 0; off + k < lim; ++k) { - unsigned long upper, lower; - - /* - * If shift is not word aligned, take lower rem bits of - * word above and make them the top rem bits of result. - */ - if (!rem || off + k + 1 >= lim) - upper = 0; - else { - upper = src[off + k + 1]; - if (off + k + 1 == lim - 1) - upper &= mask; - upper <<= (BITS_PER_LONG - rem); - } - lower = src[off + k]; - if (off + k == lim - 1) - lower &= mask; - lower >>= rem; - dst[k] = lower | upper; - } - if (off) - memset(&dst[lim - off], 0, off*sizeof(unsigned long)); -} -EXPORT_SYMBOL(__bitmap_shift_right); - - -/** - * __bitmap_shift_left - logical left shift of the bits in a bitmap - * @dst : destination bitmap - * @src : source bitmap - * @shift : shift by this many bits - * @nbits : bitmap size, in bits - * - * Shifting left (multiplying) means moving bits in the LS -> MS - * direction. Zeros are fed into the vacated LS bit positions - * and those MS bits shifted off the top are lost. - */ - -void __bitmap_shift_left(unsigned long *dst, const unsigned long *src, - unsigned int shift, unsigned int nbits) -{ - int k; - unsigned int lim = BITS_TO_LONGS(nbits); - unsigned int off = shift/BITS_PER_LONG, rem = shift % BITS_PER_LONG; - for (k = lim - off - 1; k >= 0; --k) { - unsigned long upper, lower; - - /* - * If shift is not word aligned, take upper rem bits of - * word below and make them the bottom rem bits of result. - */ - if (rem && k > 0) - lower = src[k - 1] >> (BITS_PER_LONG - rem); - else - lower = 0; - upper = src[k] << rem; - dst[k + off] = lower | upper; - } - if (off) - memset(dst, 0, off*sizeof(unsigned long)); -} -EXPORT_SYMBOL(__bitmap_shift_left); - -int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int bits) -{ - unsigned int k; - unsigned int lim = bits/BITS_PER_LONG; - unsigned long result = 0; - - for (k = 0; k < lim; k++) - result |= (dst[k] = bitmap1[k] & bitmap2[k]); - if (bits % BITS_PER_LONG) - result |= (dst[k] = bitmap1[k] & bitmap2[k] & - BITMAP_LAST_WORD_MASK(bits)); - return result != 0; -} -EXPORT_SYMBOL(__bitmap_and); - -void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int bits) -{ - unsigned int k; - unsigned int nr = BITS_TO_LONGS(bits); - - for (k = 0; k < nr; k++) - dst[k] = bitmap1[k] | bitmap2[k]; -} -EXPORT_SYMBOL(__bitmap_or); - -void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int bits) -{ - unsigned int k; - unsigned int nr = BITS_TO_LONGS(bits); - - for (k = 0; k < nr; k++) - dst[k] = bitmap1[k] ^ bitmap2[k]; -} -EXPORT_SYMBOL(__bitmap_xor); - -int __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int bits) -{ - unsigned int k; - unsigned int lim = bits/BITS_PER_LONG; - unsigned long result = 0; - - for (k = 0; k < lim; k++) - result |= (dst[k] = bitmap1[k] & ~bitmap2[k]); - if (bits % BITS_PER_LONG) - result |= (dst[k] = bitmap1[k] & ~bitmap2[k] & - BITMAP_LAST_WORD_MASK(bits)); - return result != 0; -} -EXPORT_SYMBOL(__bitmap_andnot); - -int __bitmap_intersects(const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int bits) -{ - unsigned int k, lim = bits/BITS_PER_LONG; - for (k = 0; k < lim; ++k) - if (bitmap1[k] & bitmap2[k]) - return 1; - - if (bits % BITS_PER_LONG) - if ((bitmap1[k] & bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) - return 1; - return 0; -} -EXPORT_SYMBOL(__bitmap_intersects); - -int __bitmap_subset(const unsigned long *bitmap1, - const unsigned long *bitmap2, unsigned int bits) -{ - unsigned int k, lim = bits/BITS_PER_LONG; - for (k = 0; k < lim; ++k) - if (bitmap1[k] & ~bitmap2[k]) - return 0; - - if (bits % BITS_PER_LONG) - if ((bitmap1[k] & ~bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) - return 0; - return 1; -} -EXPORT_SYMBOL(__bitmap_subset); - -int __bitmap_weight(const unsigned long *bitmap, unsigned int bits) -{ - unsigned int k, lim = bits/BITS_PER_LONG; - int w = 0; - - for (k = 0; k < lim; k++) - w += hweight_long(bitmap[k]); - - if (bits % BITS_PER_LONG) - w += hweight_long(bitmap[k] & BITMAP_LAST_WORD_MASK(bits)); - - return w; -} -EXPORT_SYMBOL(__bitmap_weight); - -void bitmap_set(unsigned long *map, unsigned int start, int len) -{ - unsigned long *p = map + BIT_WORD(start); - const unsigned int size = start + len; - int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG); - unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start); - - while (len - bits_to_set >= 0) { - *p |= mask_to_set; - len -= bits_to_set; - bits_to_set = BITS_PER_LONG; - mask_to_set = ~0UL; - p++; - } - if (len) { - mask_to_set &= BITMAP_LAST_WORD_MASK(size); - *p |= mask_to_set; - } -} -EXPORT_SYMBOL(bitmap_set); - -void bitmap_clear(unsigned long *map, unsigned int start, int len) -{ - unsigned long *p = map + BIT_WORD(start); - const unsigned int size = start + len; - int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG); - unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start); - - while (len - bits_to_clear >= 0) { - *p &= ~mask_to_clear; - len -= bits_to_clear; - bits_to_clear = BITS_PER_LONG; - mask_to_clear = ~0UL; - p++; - } - if (len) { - mask_to_clear &= BITMAP_LAST_WORD_MASK(size); - *p &= ~mask_to_clear; - } -} -EXPORT_SYMBOL(bitmap_clear); - -/** - * bitmap_find_next_zero_area_off - find a contiguous aligned zero area - * @map: The address to base the search on - * @size: The bitmap size in bits - * @start: The bitnumber to start searching at - * @nr: The number of zeroed bits we're looking for - * @align_mask: Alignment mask for zero area - * @align_offset: Alignment offset for zero area. - * - * The @align_mask should be one less than a power of 2; the effect is that - * the bit offset of all zero areas this function finds plus @align_offset - * is multiple of that power of 2. - */ -unsigned long bitmap_find_next_zero_area_off(unsigned long *map, - unsigned long size, - unsigned long start, - unsigned int nr, - unsigned long align_mask, - unsigned long align_offset) -{ - unsigned long index, end, i; -again: - index = find_next_zero_bit(map, size, start); - - /* Align allocation */ - index = __ALIGN_MASK(index + align_offset, align_mask) - align_offset; - - end = index + nr; - if (end > size) - return end; - i = find_next_bit(map, end, index); - if (i < end) { - start = i + 1; - goto again; - } - return index; -} -EXPORT_SYMBOL(bitmap_find_next_zero_area_off); - -/* - * Bitmap printing & parsing functions: first version by Nadia Yvette Chambers, - * second version by Paul Jackson, third by Joe Korty. - */ - -#define CHUNKSZ 32 -#define nbits_to_hold_value(val) fls(val) -#define BASEDEC 10 /* fancier cpuset lists input in decimal */ - -/** - * __bitmap_parse - convert an ASCII hex string into a bitmap. - * @buf: pointer to buffer containing string. - * @buflen: buffer size in bytes. If string is smaller than this - * then it must be terminated with a \0. - * @is_user: location of buffer, 0 indicates kernel space - * @maskp: pointer to bitmap array that will contain result. - * @nmaskbits: size of bitmap, in bits. - * - * Commas group hex digits into chunks. Each chunk defines exactly 32 - * bits of the resultant bitmask. No chunk may specify a value larger - * than 32 bits (%-EOVERFLOW), and if a chunk specifies a smaller value - * then leading 0-bits are prepended. %-EINVAL is returned for illegal - * characters and for grouping errors such as "1,,5", ",44", "," and "". - * Leading and trailing whitespace accepted, but not embedded whitespace. - */ -int __bitmap_parse(const char *buf, unsigned int buflen, - int is_user, unsigned long *maskp, - int nmaskbits) -{ - int c, old_c, totaldigits, ndigits, nchunks, nbits; - u32 chunk; - const char __user __force *ubuf = (const char __user __force *)buf; - - bitmap_zero(maskp, nmaskbits); - - nchunks = nbits = totaldigits = c = 0; - do { - chunk = 0; - ndigits = totaldigits; - - /* Get the next chunk of the bitmap */ - while (buflen) { - old_c = c; - if (is_user) { - if (__get_user(c, ubuf++)) - return -EFAULT; - } - else - c = *buf++; - buflen--; - if (isspace(c)) - continue; - - /* - * If the last character was a space and the current - * character isn't '\0', we've got embedded whitespace. - * This is a no-no, so throw an error. - */ - if (totaldigits && c && isspace(old_c)) - return -EINVAL; - - /* A '\0' or a ',' signal the end of the chunk */ - if (c == '\0' || c == ',') - break; - - if (!isxdigit(c)) - return -EINVAL; - - /* - * Make sure there are at least 4 free bits in 'chunk'. - * If not, this hexdigit will overflow 'chunk', so - * throw an error. - */ - if (chunk & ~((1UL << (CHUNKSZ - 4)) - 1)) - return -EOVERFLOW; - - chunk = (chunk << 4) | hex_to_bin(c); - totaldigits++; - } - if (ndigits == totaldigits) - return -EINVAL; - if (nchunks == 0 && chunk == 0) - continue; - - __bitmap_shift_left(maskp, maskp, CHUNKSZ, nmaskbits); - *maskp |= chunk; - nchunks++; - nbits += (nchunks == 1) ? nbits_to_hold_value(chunk) : CHUNKSZ; - if (nbits > nmaskbits) - return -EOVERFLOW; - } while (buflen && c == ','); - - return 0; -} -EXPORT_SYMBOL(__bitmap_parse); - -/** - * bitmap_parse_user - convert an ASCII hex string in a user buffer into a bitmap - * - * @ubuf: pointer to user buffer containing string. - * @ulen: buffer size in bytes. If string is smaller than this - * then it must be terminated with a \0. - * @maskp: pointer to bitmap array that will contain result. - * @nmaskbits: size of bitmap, in bits. - * - * Wrapper for __bitmap_parse(), providing it with user buffer. - * - * We cannot have this as an inline function in bitmap.h because it needs - * linux/uaccess.h to get the access_ok() declaration and this causes - * cyclic dependencies. - */ -int bitmap_parse_user(const char __user *ubuf, - unsigned int ulen, unsigned long *maskp, - int nmaskbits) -{ - if (!access_ok(VERIFY_READ, ubuf, ulen)) - return -EFAULT; - return __bitmap_parse((const char __force *)ubuf, - ulen, 1, maskp, nmaskbits); - -} -EXPORT_SYMBOL(bitmap_parse_user); - -/** - * bitmap_print_to_pagebuf - convert bitmap to list or hex format ASCII string - * @list: indicates whether the bitmap must be list - * @buf: page aligned buffer into which string is placed - * @maskp: pointer to bitmap to convert - * @nmaskbits: size of bitmap, in bits - * - * Output format is a comma-separated list of decimal numbers and - * ranges if list is specified or hex digits grouped into comma-separated - * sets of 8 digits/set. Returns the number of characters written to buf. - * - * It is assumed that @buf is a pointer into a PAGE_SIZE area and that - * sufficient storage remains at @buf to accommodate the - * bitmap_print_to_pagebuf() output. - */ -int bitmap_print_to_pagebuf(bool list, char *buf, const unsigned long *maskp, - int nmaskbits) -{ - ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf; - int n = 0; - - if (len > 1) - n = list ? scnprintf(buf, len, "%*pbl\n", nmaskbits, maskp) : - scnprintf(buf, len, "%*pb\n", nmaskbits, maskp); - return n; -} -EXPORT_SYMBOL(bitmap_print_to_pagebuf); - -/** - * __bitmap_parselist - convert list format ASCII string to bitmap - * @buf: read nul-terminated user string from this buffer - * @buflen: buffer size in bytes. If string is smaller than this - * then it must be terminated with a \0. - * @is_user: location of buffer, 0 indicates kernel space - * @maskp: write resulting mask here - * @nmaskbits: number of bits in mask to be written - * - * Input format is a comma-separated list of decimal numbers and - * ranges. Consecutively set bits are shown as two hyphen-separated - * decimal numbers, the smallest and largest bit numbers set in - * the range. - * Optionally each range can be postfixed to denote that only parts of it - * should be set. The range will divided to groups of specific size. - * From each group will be used only defined amount of bits. - * Syntax: range:used_size/group_size - * Example: 0-1023:2/256 ==> 0,1,256,257,512,513,768,769 - * - * Returns 0 on success, -errno on invalid input strings. - * Error values: - * %-EINVAL: second number in range smaller than first - * %-EINVAL: invalid character in string - * %-ERANGE: bit number specified too large for mask - */ -static int __bitmap_parselist(const char *buf, unsigned int buflen, - int is_user, unsigned long *maskp, - int nmaskbits) -{ - unsigned int a, b, old_a, old_b; - unsigned int group_size, used_size; - int c, old_c, totaldigits, ndigits; - const char __user __force *ubuf = (const char __user __force *)buf; - int at_start, in_range, in_partial_range; - - totaldigits = c = 0; - old_a = old_b = 0; - group_size = used_size = 0; - bitmap_zero(maskp, nmaskbits); - do { - at_start = 1; - in_range = 0; - in_partial_range = 0; - a = b = 0; - ndigits = totaldigits; - - /* Get the next cpu# or a range of cpu#'s */ - while (buflen) { - old_c = c; - if (is_user) { - if (__get_user(c, ubuf++)) - return -EFAULT; - } else - c = *buf++; - buflen--; - if (isspace(c)) - continue; - - /* A '\0' or a ',' signal the end of a cpu# or range */ - if (c == '\0' || c == ',') - break; - /* - * whitespaces between digits are not allowed, - * but it's ok if whitespaces are on head or tail. - * when old_c is whilespace, - * if totaldigits == ndigits, whitespace is on head. - * if whitespace is on tail, it should not run here. - * as c was ',' or '\0', - * the last code line has broken the current loop. - */ - if ((totaldigits != ndigits) && isspace(old_c)) - return -EINVAL; - - if (c == '/') { - used_size = a; - at_start = 1; - in_range = 0; - a = b = 0; - continue; - } - - if (c == ':') { - old_a = a; - old_b = b; - at_start = 1; - in_range = 0; - in_partial_range = 1; - a = b = 0; - continue; - } - - if (c == '-') { - if (at_start || in_range) - return -EINVAL; - b = 0; - in_range = 1; - at_start = 1; - continue; - } - - if (!isdigit(c)) - return -EINVAL; - - b = b * 10 + (c - '0'); - if (!in_range) - a = b; - at_start = 0; - totaldigits++; - } - if (ndigits == totaldigits) - continue; - if (in_partial_range) { - group_size = a; - a = old_a; - b = old_b; - old_a = old_b = 0; - } - /* if no digit is after '-', it's wrong*/ - if (at_start && in_range) - return -EINVAL; - if (!(a <= b) || !(used_size <= group_size)) - return -EINVAL; - if (b >= nmaskbits) - return -ERANGE; - while (a <= b) { - if (in_partial_range) { - static int pos_in_group = 1; - - if (pos_in_group <= used_size) - set_bit(a, maskp); - - if (a == b || ++pos_in_group > group_size) - pos_in_group = 1; - } else - set_bit(a, maskp); - a++; - } - } while (buflen && c == ','); - return 0; -} - -int bitmap_parselist(const char *bp, unsigned long *maskp, int nmaskbits) -{ - char *nl = strchrnul(bp, '\n'); - int len = nl - bp; - - return __bitmap_parselist(bp, len, 0, maskp, nmaskbits); -} -EXPORT_SYMBOL(bitmap_parselist); - - -/** - * bitmap_parselist_user() - * - * @ubuf: pointer to user buffer containing string. - * @ulen: buffer size in bytes. If string is smaller than this - * then it must be terminated with a \0. - * @maskp: pointer to bitmap array that will contain result. - * @nmaskbits: size of bitmap, in bits. - * - * Wrapper for bitmap_parselist(), providing it with user buffer. - * - * We cannot have this as an inline function in bitmap.h because it needs - * linux/uaccess.h to get the access_ok() declaration and this causes - * cyclic dependencies. - */ -int bitmap_parselist_user(const char __user *ubuf, - unsigned int ulen, unsigned long *maskp, - int nmaskbits) -{ - if (!access_ok(VERIFY_READ, ubuf, ulen)) - return -EFAULT; - return __bitmap_parselist((const char __force *)ubuf, - ulen, 1, maskp, nmaskbits); -} -EXPORT_SYMBOL(bitmap_parselist_user); - - -/** - * bitmap_pos_to_ord - find ordinal of set bit at given position in bitmap - * @buf: pointer to a bitmap - * @pos: a bit position in @buf (0 <= @pos < @nbits) - * @nbits: number of valid bit positions in @buf - * - * Map the bit at position @pos in @buf (of length @nbits) to the - * ordinal of which set bit it is. If it is not set or if @pos - * is not a valid bit position, map to -1. - * - * If for example, just bits 4 through 7 are set in @buf, then @pos - * values 4 through 7 will get mapped to 0 through 3, respectively, - * and other @pos values will get mapped to -1. When @pos value 7 - * gets mapped to (returns) @ord value 3 in this example, that means - * that bit 7 is the 3rd (starting with 0th) set bit in @buf. - * - * The bit positions 0 through @bits are valid positions in @buf. - */ -static int bitmap_pos_to_ord(const unsigned long *buf, unsigned int pos, unsigned int nbits) -{ - if (pos >= nbits || !test_bit(pos, buf)) - return -1; - - return __bitmap_weight(buf, pos); -} - -/** - * bitmap_ord_to_pos - find position of n-th set bit in bitmap - * @buf: pointer to bitmap - * @ord: ordinal bit position (n-th set bit, n >= 0) - * @nbits: number of valid bit positions in @buf - * - * Map the ordinal offset of bit @ord in @buf to its position in @buf. - * Value of @ord should be in range 0 <= @ord < weight(buf). If @ord - * >= weight(buf), returns @nbits. - * - * If for example, just bits 4 through 7 are set in @buf, then @ord - * values 0 through 3 will get mapped to 4 through 7, respectively, - * and all other @ord values returns @nbits. When @ord value 3 - * gets mapped to (returns) @pos value 7 in this example, that means - * that the 3rd set bit (starting with 0th) is at position 7 in @buf. - * - * The bit positions 0 through @nbits-1 are valid positions in @buf. - */ -unsigned int bitmap_ord_to_pos(const unsigned long *buf, unsigned int ord, unsigned int nbits) -{ - unsigned int pos; - - for (pos = find_first_bit(buf, nbits); - pos < nbits && ord; - pos = find_next_bit(buf, nbits, pos + 1)) - ord--; - - return pos; -} - -/** - * bitmap_remap - Apply map defined by a pair of bitmaps to another bitmap - * @dst: remapped result - * @src: subset to be remapped - * @old: defines domain of map - * @new: defines range of map - * @nbits: number of bits in each of these bitmaps - * - * Let @old and @new define a mapping of bit positions, such that - * whatever position is held by the n-th set bit in @old is mapped - * to the n-th set bit in @new. In the more general case, allowing - * for the possibility that the weight 'w' of @new is less than the - * weight of @old, map the position of the n-th set bit in @old to - * the position of the m-th set bit in @new, where m == n % w. - * - * If either of the @old and @new bitmaps are empty, or if @src and - * @dst point to the same location, then this routine copies @src - * to @dst. - * - * The positions of unset bits in @old are mapped to themselves - * (the identify map). - * - * Apply the above specified mapping to @src, placing the result in - * @dst, clearing any bits previously set in @dst. - * - * For example, lets say that @old has bits 4 through 7 set, and - * @new has bits 12 through 15 set. This defines the mapping of bit - * position 4 to 12, 5 to 13, 6 to 14 and 7 to 15, and of all other - * bit positions unchanged. So if say @src comes into this routine - * with bits 1, 5 and 7 set, then @dst should leave with bits 1, - * 13 and 15 set. - */ -void bitmap_remap(unsigned long *dst, const unsigned long *src, - const unsigned long *old, const unsigned long *new, - unsigned int nbits) -{ - unsigned int oldbit, w; - - if (dst == src) /* following doesn't handle inplace remaps */ - return; - bitmap_zero(dst, nbits); - - w = bitmap_weight(new, nbits); - for_each_set_bit(oldbit, src, nbits) { - int n = bitmap_pos_to_ord(old, oldbit, nbits); - - if (n < 0 || w == 0) - set_bit(oldbit, dst); /* identity map */ - else - set_bit(bitmap_ord_to_pos(new, n % w, nbits), dst); - } -} -EXPORT_SYMBOL(bitmap_remap); - -/** - * bitmap_bitremap - Apply map defined by a pair of bitmaps to a single bit - * @oldbit: bit position to be mapped - * @old: defines domain of map - * @new: defines range of map - * @bits: number of bits in each of these bitmaps - * - * Let @old and @new define a mapping of bit positions, such that - * whatever position is held by the n-th set bit in @old is mapped - * to the n-th set bit in @new. In the more general case, allowing - * for the possibility that the weight 'w' of @new is less than the - * weight of @old, map the position of the n-th set bit in @old to - * the position of the m-th set bit in @new, where m == n % w. - * - * The positions of unset bits in @old are mapped to themselves - * (the identify map). - * - * Apply the above specified mapping to bit position @oldbit, returning - * the new bit position. - * - * For example, lets say that @old has bits 4 through 7 set, and - * @new has bits 12 through 15 set. This defines the mapping of bit - * position 4 to 12, 5 to 13, 6 to 14 and 7 to 15, and of all other - * bit positions unchanged. So if say @oldbit is 5, then this routine - * returns 13. - */ -int bitmap_bitremap(int oldbit, const unsigned long *old, - const unsigned long *new, int bits) -{ - int w = bitmap_weight(new, bits); - int n = bitmap_pos_to_ord(old, oldbit, bits); - if (n < 0 || w == 0) - return oldbit; - else - return bitmap_ord_to_pos(new, n % w, bits); -} -EXPORT_SYMBOL(bitmap_bitremap); - -/** - * bitmap_onto - translate one bitmap relative to another - * @dst: resulting translated bitmap - * @orig: original untranslated bitmap - * @relmap: bitmap relative to which translated - * @bits: number of bits in each of these bitmaps - * - * Set the n-th bit of @dst iff there exists some m such that the - * n-th bit of @relmap is set, the m-th bit of @orig is set, and - * the n-th bit of @relmap is also the m-th _set_ bit of @relmap. - * (If you understood the previous sentence the first time your - * read it, you're overqualified for your current job.) - * - * In other words, @orig is mapped onto (surjectively) @dst, - * using the map { | the n-th bit of @relmap is the - * m-th set bit of @relmap }. - * - * Any set bits in @orig above bit number W, where W is the - * weight of (number of set bits in) @relmap are mapped nowhere. - * In particular, if for all bits m set in @orig, m >= W, then - * @dst will end up empty. In situations where the possibility - * of such an empty result is not desired, one way to avoid it is - * to use the bitmap_fold() operator, below, to first fold the - * @orig bitmap over itself so that all its set bits x are in the - * range 0 <= x < W. The bitmap_fold() operator does this by - * setting the bit (m % W) in @dst, for each bit (m) set in @orig. - * - * Example [1] for bitmap_onto(): - * Let's say @relmap has bits 30-39 set, and @orig has bits - * 1, 3, 5, 7, 9 and 11 set. Then on return from this routine, - * @dst will have bits 31, 33, 35, 37 and 39 set. - * - * When bit 0 is set in @orig, it means turn on the bit in - * @dst corresponding to whatever is the first bit (if any) - * that is turned on in @relmap. Since bit 0 was off in the - * above example, we leave off that bit (bit 30) in @dst. - * - * When bit 1 is set in @orig (as in the above example), it - * means turn on the bit in @dst corresponding to whatever - * is the second bit that is turned on in @relmap. The second - * bit in @relmap that was turned on in the above example was - * bit 31, so we turned on bit 31 in @dst. - * - * Similarly, we turned on bits 33, 35, 37 and 39 in @dst, - * because they were the 4th, 6th, 8th and 10th set bits - * set in @relmap, and the 4th, 6th, 8th and 10th bits of - * @orig (i.e. bits 3, 5, 7 and 9) were also set. - * - * When bit 11 is set in @orig, it means turn on the bit in - * @dst corresponding to whatever is the twelfth bit that is - * turned on in @relmap. In the above example, there were - * only ten bits turned on in @relmap (30..39), so that bit - * 11 was set in @orig had no affect on @dst. - * - * Example [2] for bitmap_fold() + bitmap_onto(): - * Let's say @relmap has these ten bits set: - * 40 41 42 43 45 48 53 61 74 95 - * (for the curious, that's 40 plus the first ten terms of the - * Fibonacci sequence.) - * - * Further lets say we use the following code, invoking - * bitmap_fold() then bitmap_onto, as suggested above to - * avoid the possibility of an empty @dst result: - * - * unsigned long *tmp; // a temporary bitmap's bits - * - * bitmap_fold(tmp, orig, bitmap_weight(relmap, bits), bits); - * bitmap_onto(dst, tmp, relmap, bits); - * - * Then this table shows what various values of @dst would be, for - * various @orig's. I list the zero-based positions of each set bit. - * The tmp column shows the intermediate result, as computed by - * using bitmap_fold() to fold the @orig bitmap modulo ten - * (the weight of @relmap). - * - * @orig tmp @dst - * 0 0 40 - * 1 1 41 - * 9 9 95 - * 10 0 40 (*) - * 1 3 5 7 1 3 5 7 41 43 48 61 - * 0 1 2 3 4 0 1 2 3 4 40 41 42 43 45 - * 0 9 18 27 0 9 8 7 40 61 74 95 - * 0 10 20 30 0 40 - * 0 11 22 33 0 1 2 3 40 41 42 43 - * 0 12 24 36 0 2 4 6 40 42 45 53 - * 78 102 211 1 2 8 41 42 74 (*) - * - * (*) For these marked lines, if we hadn't first done bitmap_fold() - * into tmp, then the @dst result would have been empty. - * - * If either of @orig or @relmap is empty (no set bits), then @dst - * will be returned empty. - * - * If (as explained above) the only set bits in @orig are in positions - * m where m >= W, (where W is the weight of @relmap) then @dst will - * once again be returned empty. - * - * All bits in @dst not set by the above rule are cleared. - */ -void bitmap_onto(unsigned long *dst, const unsigned long *orig, - const unsigned long *relmap, unsigned int bits) -{ - unsigned int n, m; /* same meaning as in above comment */ - - if (dst == orig) /* following doesn't handle inplace mappings */ - return; - bitmap_zero(dst, bits); - - /* - * The following code is a more efficient, but less - * obvious, equivalent to the loop: - * for (m = 0; m < bitmap_weight(relmap, bits); m++) { - * n = bitmap_ord_to_pos(orig, m, bits); - * if (test_bit(m, orig)) - * set_bit(n, dst); - * } - */ - - m = 0; - for_each_set_bit(n, relmap, bits) { - /* m == bitmap_pos_to_ord(relmap, n, bits) */ - if (test_bit(m, orig)) - set_bit(n, dst); - m++; - } -} -EXPORT_SYMBOL(bitmap_onto); - -/** - * bitmap_fold - fold larger bitmap into smaller, modulo specified size - * @dst: resulting smaller bitmap - * @orig: original larger bitmap - * @sz: specified size - * @nbits: number of bits in each of these bitmaps - * - * For each bit oldbit in @orig, set bit oldbit mod @sz in @dst. - * Clear all other bits in @dst. See further the comment and - * Example [2] for bitmap_onto() for why and how to use this. - */ -void bitmap_fold(unsigned long *dst, const unsigned long *orig, - unsigned int sz, unsigned int nbits) -{ - unsigned int oldbit; - - if (dst == orig) /* following doesn't handle inplace mappings */ - return; - bitmap_zero(dst, nbits); - - for_each_set_bit(oldbit, orig, nbits) - set_bit(oldbit % sz, dst); -} -EXPORT_SYMBOL(bitmap_fold); - -/* - * Common code for bitmap_*_region() routines. - * bitmap: array of unsigned longs corresponding to the bitmap - * pos: the beginning of the region - * order: region size (log base 2 of number of bits) - * reg_op: operation(s) to perform on that region of bitmap - * - * Can set, verify and/or release a region of bits in a bitmap, - * depending on which combination of REG_OP_* flag bits is set. - * - * A region of a bitmap is a sequence of bits in the bitmap, of - * some size '1 << order' (a power of two), aligned to that same - * '1 << order' power of two. - * - * Returns 1 if REG_OP_ISFREE succeeds (region is all zero bits). - * Returns 0 in all other cases and reg_ops. - */ - -enum { - REG_OP_ISFREE, /* true if region is all zero bits */ - REG_OP_ALLOC, /* set all bits in region */ - REG_OP_RELEASE, /* clear all bits in region */ -}; - -static int __reg_op(unsigned long *bitmap, unsigned int pos, int order, int reg_op) -{ - int nbits_reg; /* number of bits in region */ - int index; /* index first long of region in bitmap */ - int offset; /* bit offset region in bitmap[index] */ - int nlongs_reg; /* num longs spanned by region in bitmap */ - int nbitsinlong; /* num bits of region in each spanned long */ - unsigned long mask; /* bitmask for one long of region */ - int i; /* scans bitmap by longs */ - int ret = 0; /* return value */ - - /* - * Either nlongs_reg == 1 (for small orders that fit in one long) - * or (offset == 0 && mask == ~0UL) (for larger multiword orders.) - */ - nbits_reg = 1 << order; - index = pos / BITS_PER_LONG; - offset = pos - (index * BITS_PER_LONG); - nlongs_reg = BITS_TO_LONGS(nbits_reg); - nbitsinlong = min(nbits_reg, BITS_PER_LONG); - - /* - * Can't do "mask = (1UL << nbitsinlong) - 1", as that - * overflows if nbitsinlong == BITS_PER_LONG. - */ - mask = (1UL << (nbitsinlong - 1)); - mask += mask - 1; - mask <<= offset; - - switch (reg_op) { - case REG_OP_ISFREE: - for (i = 0; i < nlongs_reg; i++) { - if (bitmap[index + i] & mask) - goto done; - } - ret = 1; /* all bits in region free (zero) */ - break; - - case REG_OP_ALLOC: - for (i = 0; i < nlongs_reg; i++) - bitmap[index + i] |= mask; - break; - - case REG_OP_RELEASE: - for (i = 0; i < nlongs_reg; i++) - bitmap[index + i] &= ~mask; - break; - } -done: - return ret; -} - -/** - * bitmap_find_free_region - find a contiguous aligned mem region - * @bitmap: array of unsigned longs corresponding to the bitmap - * @bits: number of bits in the bitmap - * @order: region size (log base 2 of number of bits) to find - * - * Find a region of free (zero) bits in a @bitmap of @bits bits and - * allocate them (set them to one). Only consider regions of length - * a power (@order) of two, aligned to that power of two, which - * makes the search algorithm much faster. - * - * Return the bit offset in bitmap of the allocated region, - * or -errno on failure. - */ -int bitmap_find_free_region(unsigned long *bitmap, unsigned int bits, int order) -{ - unsigned int pos, end; /* scans bitmap by regions of size order */ - - for (pos = 0 ; (end = pos + (1U << order)) <= bits; pos = end) { - if (!__reg_op(bitmap, pos, order, REG_OP_ISFREE)) - continue; - __reg_op(bitmap, pos, order, REG_OP_ALLOC); - return pos; - } - return -ENOMEM; -} -EXPORT_SYMBOL(bitmap_find_free_region); - -/** - * bitmap_release_region - release allocated bitmap region - * @bitmap: array of unsigned longs corresponding to the bitmap - * @pos: beginning of bit region to release - * @order: region size (log base 2 of number of bits) to release - * - * This is the complement to __bitmap_find_free_region() and releases - * the found region (by clearing it in the bitmap). - * - * No return value. - */ -void bitmap_release_region(unsigned long *bitmap, unsigned int pos, int order) -{ - __reg_op(bitmap, pos, order, REG_OP_RELEASE); -} -EXPORT_SYMBOL(bitmap_release_region); - -/** - * bitmap_allocate_region - allocate bitmap region - * @bitmap: array of unsigned longs corresponding to the bitmap - * @pos: beginning of bit region to allocate - * @order: region size (log base 2 of number of bits) to allocate - * - * Allocate (set bits in) a specified region of a bitmap. - * - * Return 0 on success, or %-EBUSY if specified region wasn't - * free (not all bits were zero). - */ -int bitmap_allocate_region(unsigned long *bitmap, unsigned int pos, int order) -{ - if (!__reg_op(bitmap, pos, order, REG_OP_ISFREE)) - return -EBUSY; - return __reg_op(bitmap, pos, order, REG_OP_ALLOC); -} -EXPORT_SYMBOL(bitmap_allocate_region); - -/** - * bitmap_from_u32array - copy the contents of a u32 array of bits to bitmap - * @bitmap: array of unsigned longs, the destination bitmap, non NULL - * @nbits: number of bits in @bitmap - * @buf: array of u32 (in host byte order), the source bitmap, non NULL - * @nwords: number of u32 words in @buf - * - * copy min(nbits, 32*nwords) bits from @buf to @bitmap, remaining - * bits between nword and nbits in @bitmap (if any) are cleared. In - * last word of @bitmap, the bits beyond nbits (if any) are kept - * unchanged. - * - * Return the number of bits effectively copied. - */ -unsigned int -bitmap_from_u32array(unsigned long *bitmap, unsigned int nbits, - const u32 *buf, unsigned int nwords) -{ - unsigned int dst_idx, src_idx; - - for (src_idx = dst_idx = 0; dst_idx < BITS_TO_LONGS(nbits); ++dst_idx) { - unsigned long part = 0; - - if (src_idx < nwords) - part = buf[src_idx++]; - -#if BITS_PER_LONG == 64 - if (src_idx < nwords) - part |= ((unsigned long) buf[src_idx++]) << 32; -#endif - - if (dst_idx < nbits/BITS_PER_LONG) - bitmap[dst_idx] = part; - else { - unsigned long mask = BITMAP_LAST_WORD_MASK(nbits); - - bitmap[dst_idx] = (bitmap[dst_idx] & ~mask) - | (part & mask); - } - } - - return min_t(unsigned int, nbits, 32*nwords); -} -EXPORT_SYMBOL(bitmap_from_u32array); - -/** - * bitmap_to_u32array - copy the contents of bitmap to a u32 array of bits - * @buf: array of u32 (in host byte order), the dest bitmap, non NULL - * @nwords: number of u32 words in @buf - * @bitmap: array of unsigned longs, the source bitmap, non NULL - * @nbits: number of bits in @bitmap - * - * copy min(nbits, 32*nwords) bits from @bitmap to @buf. Remaining - * bits after nbits in @buf (if any) are cleared. - * - * Return the number of bits effectively copied. - */ -unsigned int -bitmap_to_u32array(u32 *buf, unsigned int nwords, - const unsigned long *bitmap, unsigned int nbits) -{ - unsigned int dst_idx = 0, src_idx = 0; - - while (dst_idx < nwords) { - unsigned long part = 0; - - if (src_idx < BITS_TO_LONGS(nbits)) { - part = bitmap[src_idx]; - if (src_idx >= nbits/BITS_PER_LONG) - part &= BITMAP_LAST_WORD_MASK(nbits); - src_idx++; - } - - buf[dst_idx++] = part & 0xffffffffUL; - -#if BITS_PER_LONG == 64 - if (dst_idx < nwords) { - part >>= 32; - buf[dst_idx++] = part & 0xffffffffUL; - } -#endif - } - - return min_t(unsigned int, nbits, 32*nwords); -} -EXPORT_SYMBOL(bitmap_to_u32array); - -/** - * bitmap_copy_le - copy a bitmap, putting the bits into little-endian order. - * @dst: destination buffer - * @src: bitmap to copy - * @nbits: number of bits in the bitmap - * - * Require nbits % BITS_PER_LONG == 0. - */ -#ifdef __BIG_ENDIAN -void bitmap_copy_le(unsigned long *dst, const unsigned long *src, unsigned int nbits) -{ - unsigned int i; - - for (i = 0; i < nbits/BITS_PER_LONG; i++) { - if (BITS_PER_LONG == 64) - dst[i] = cpu_to_le64(src[i]); - else - dst[i] = cpu_to_le32(src[i]); - } -} -EXPORT_SYMBOL(bitmap_copy_le); -#endif diff --git a/src/linux/lib/bitrev.c b/src/linux/lib/bitrev.c deleted file mode 100644 index 40ffda9..0000000 --- a/src/linux/lib/bitrev.c +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef CONFIG_HAVE_ARCH_BITREVERSE -#include -#include -#include - -MODULE_AUTHOR("Akinobu Mita "); -MODULE_DESCRIPTION("Bit ordering reversal functions"); -MODULE_LICENSE("GPL"); - -const u8 byte_rev_table[256] = { - 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, - 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, - 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, - 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, - 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, - 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, - 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, - 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, - 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, - 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, - 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, - 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, - 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, - 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, - 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, - 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, - 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, - 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, - 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, - 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, - 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, - 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, - 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, - 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, - 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, - 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, - 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, - 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, - 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, - 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, - 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, - 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, -}; -EXPORT_SYMBOL_GPL(byte_rev_table); - -#endif /* CONFIG_HAVE_ARCH_BITREVERSE */ diff --git a/src/linux/lib/bsearch.c b/src/linux/lib/bsearch.c deleted file mode 100644 index e33c179..0000000 --- a/src/linux/lib/bsearch.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * A generic implementation of binary search for the Linux kernel - * - * Copyright (C) 2008-2009 Ksplice, Inc. - * Author: Tim Abbott - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; version 2. - */ - -#include -#include - -/* - * bsearch - binary search an array of elements - * @key: pointer to item being searched for - * @base: pointer to first element to search - * @num: number of elements - * @size: size of each element - * @cmp: pointer to comparison function - * - * This function does a binary search on the given array. The - * contents of the array should already be in ascending sorted order - * under the provided comparison function. - * - * Note that the key need not have the same type as the elements in - * the array, e.g. key could be a string and the comparison function - * could compare the string with the struct's name field. However, if - * the key and elements in the array are of the same type, you can use - * the same comparison function for both sort() and bsearch(). - */ -void *bsearch(const void *key, const void *base, size_t num, size_t size, - int (*cmp)(const void *key, const void *elt)) -{ - size_t start = 0, end = num; - int result; - - while (start < end) { - size_t mid = start + (end - start) / 2; - - result = cmp(key, base + mid * size); - if (result < 0) - end = mid; - else if (result > 0) - start = mid + 1; - else - return (void *)base + mid * size; - } - - return NULL; -} -EXPORT_SYMBOL(bsearch); diff --git a/src/linux/lib/bust_spinlocks.c b/src/linux/lib/bust_spinlocks.c deleted file mode 100644 index f8e0e53..0000000 --- a/src/linux/lib/bust_spinlocks.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * lib/bust_spinlocks.c - * - * Provides a minimal bust_spinlocks for architectures which don't have one of their own. - * - * bust_spinlocks() clears any spinlocks which would prevent oops, die(), BUG() - * and panic() information from reaching the user. - */ - -#include -#include -#include -#include -#include -#include -#include - - -void __attribute__((weak)) bust_spinlocks(int yes) -{ - if (yes) { - ++oops_in_progress; - } else { -#ifdef CONFIG_VT - unblank_screen(); -#endif - console_unblank(); - if (--oops_in_progress == 0) - wake_up_klogd(); - } -} diff --git a/src/linux/lib/chacha20.c b/src/linux/lib/chacha20.c deleted file mode 100644 index 250ceed..0000000 --- a/src/linux/lib/chacha20.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * ChaCha20 256-bit cipher algorithm, RFC7539 - * - * Copyright (C) 2015 Martin Willi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include - -static inline u32 rotl32(u32 v, u8 n) -{ - return (v << n) | (v >> (sizeof(v) * 8 - n)); -} - -extern void chacha20_block(u32 *state, void *stream) -{ - u32 x[16], *out = stream; - int i; - - for (i = 0; i < ARRAY_SIZE(x); i++) - x[i] = state[i]; - - for (i = 0; i < 20; i += 2) { - x[0] += x[4]; x[12] = rotl32(x[12] ^ x[0], 16); - x[1] += x[5]; x[13] = rotl32(x[13] ^ x[1], 16); - x[2] += x[6]; x[14] = rotl32(x[14] ^ x[2], 16); - x[3] += x[7]; x[15] = rotl32(x[15] ^ x[3], 16); - - x[8] += x[12]; x[4] = rotl32(x[4] ^ x[8], 12); - x[9] += x[13]; x[5] = rotl32(x[5] ^ x[9], 12); - x[10] += x[14]; x[6] = rotl32(x[6] ^ x[10], 12); - x[11] += x[15]; x[7] = rotl32(x[7] ^ x[11], 12); - - x[0] += x[4]; x[12] = rotl32(x[12] ^ x[0], 8); - x[1] += x[5]; x[13] = rotl32(x[13] ^ x[1], 8); - x[2] += x[6]; x[14] = rotl32(x[14] ^ x[2], 8); - x[3] += x[7]; x[15] = rotl32(x[15] ^ x[3], 8); - - x[8] += x[12]; x[4] = rotl32(x[4] ^ x[8], 7); - x[9] += x[13]; x[5] = rotl32(x[5] ^ x[9], 7); - x[10] += x[14]; x[6] = rotl32(x[6] ^ x[10], 7); - x[11] += x[15]; x[7] = rotl32(x[7] ^ x[11], 7); - - x[0] += x[5]; x[15] = rotl32(x[15] ^ x[0], 16); - x[1] += x[6]; x[12] = rotl32(x[12] ^ x[1], 16); - x[2] += x[7]; x[13] = rotl32(x[13] ^ x[2], 16); - x[3] += x[4]; x[14] = rotl32(x[14] ^ x[3], 16); - - x[10] += x[15]; x[5] = rotl32(x[5] ^ x[10], 12); - x[11] += x[12]; x[6] = rotl32(x[6] ^ x[11], 12); - x[8] += x[13]; x[7] = rotl32(x[7] ^ x[8], 12); - x[9] += x[14]; x[4] = rotl32(x[4] ^ x[9], 12); - - x[0] += x[5]; x[15] = rotl32(x[15] ^ x[0], 8); - x[1] += x[6]; x[12] = rotl32(x[12] ^ x[1], 8); - x[2] += x[7]; x[13] = rotl32(x[13] ^ x[2], 8); - x[3] += x[4]; x[14] = rotl32(x[14] ^ x[3], 8); - - x[10] += x[15]; x[5] = rotl32(x[5] ^ x[10], 7); - x[11] += x[12]; x[6] = rotl32(x[6] ^ x[11], 7); - x[8] += x[13]; x[7] = rotl32(x[7] ^ x[8], 7); - x[9] += x[14]; x[4] = rotl32(x[4] ^ x[9], 7); - } - - for (i = 0; i < ARRAY_SIZE(x); i++) - out[i] = cpu_to_le32(x[i] + state[i]); - - state[12]++; -} -EXPORT_SYMBOL(chacha20_block); diff --git a/src/linux/lib/checksum.c b/src/linux/lib/checksum.c deleted file mode 100644 index d3ec93f..0000000 --- a/src/linux/lib/checksum.c +++ /dev/null @@ -1,208 +0,0 @@ -/* - * - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * IP/TCP/UDP checksumming routines - * - * Authors: Jorge Cwik, - * Arnt Gulbrandsen, - * Tom May, - * Andreas Schwab, - * Lots of code moved from tcp.c and ip.c; see those files - * for more names. - * - * 03/02/96 Jes Sorensen, Andreas Schwab, Roman Hodek: - * Fixed some nasty bugs, causing some horrible crashes. - * A: At some points, the sum (%0) was used as - * length-counter instead of the length counter - * (%1). Thanks to Roman Hodek for pointing this out. - * B: GCC seems to mess up if one uses too many - * data-registers to hold input values and one tries to - * specify d0 and d1 as scratch registers. Letting gcc - * choose these registers itself solves the problem. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -/* Revised by Kenneth Albanowski for m68knommu. Basic problem: unaligned access - kills, so most of the assembly has to go. */ - -#include -#include - -#include - -#ifndef do_csum -static inline unsigned short from32to16(unsigned int x) -{ - /* add up 16-bit and 16-bit for 16+c bit */ - x = (x & 0xffff) + (x >> 16); - /* add up carry.. */ - x = (x & 0xffff) + (x >> 16); - return x; -} - -static unsigned int do_csum(const unsigned char *buff, int len) -{ - int odd; - unsigned int result = 0; - - if (len <= 0) - goto out; - odd = 1 & (unsigned long) buff; - if (odd) { -#ifdef __LITTLE_ENDIAN - result += (*buff << 8); -#else - result = *buff; -#endif - len--; - buff++; - } - if (len >= 2) { - if (2 & (unsigned long) buff) { - result += *(unsigned short *) buff; - len -= 2; - buff += 2; - } - if (len >= 4) { - const unsigned char *end = buff + ((unsigned)len & ~3); - unsigned int carry = 0; - do { - unsigned int w = *(unsigned int *) buff; - buff += 4; - result += carry; - result += w; - carry = (w > result); - } while (buff < end); - result += carry; - result = (result & 0xffff) + (result >> 16); - } - if (len & 2) { - result += *(unsigned short *) buff; - buff += 2; - } - } - if (len & 1) -#ifdef __LITTLE_ENDIAN - result += *buff; -#else - result += (*buff << 8); -#endif - result = from32to16(result); - if (odd) - result = ((result >> 8) & 0xff) | ((result & 0xff) << 8); -out: - return result; -} -#endif - -#ifndef ip_fast_csum -/* - * This is a version of ip_compute_csum() optimized for IP headers, - * which always checksum on 4 octet boundaries. - */ -__sum16 ip_fast_csum(const void *iph, unsigned int ihl) -{ - return (__force __sum16)~do_csum(iph, ihl*4); -} -EXPORT_SYMBOL(ip_fast_csum); -#endif - -/* - * computes the checksum of a memory block at buff, length len, - * and adds in "sum" (32-bit) - * - * returns a 32-bit number suitable for feeding into itself - * or csum_tcpudp_magic - * - * this function must be called with even lengths, except - * for the last fragment, which may be odd - * - * it's best to have buff aligned on a 32-bit boundary - */ -__wsum csum_partial(const void *buff, int len, __wsum wsum) -{ - unsigned int sum = (__force unsigned int)wsum; - unsigned int result = do_csum(buff, len); - - /* add in old sum, and carry.. */ - result += sum; - if (sum > result) - result += 1; - return (__force __wsum)result; -} -EXPORT_SYMBOL(csum_partial); - -/* - * this routine is used for miscellaneous IP-like checksums, mainly - * in icmp.c - */ -__sum16 ip_compute_csum(const void *buff, int len) -{ - return (__force __sum16)~do_csum(buff, len); -} -EXPORT_SYMBOL(ip_compute_csum); - -/* - * copy from fs while checksumming, otherwise like csum_partial - */ -__wsum -csum_partial_copy_from_user(const void __user *src, void *dst, int len, - __wsum sum, int *csum_err) -{ - int missing; - - missing = __copy_from_user(dst, src, len); - if (missing) { - memset(dst + len - missing, 0, missing); - *csum_err = -EFAULT; - } else - *csum_err = 0; - - return csum_partial(dst, len, sum); -} -EXPORT_SYMBOL(csum_partial_copy_from_user); - -/* - * copy from ds while checksumming, otherwise like csum_partial - */ -__wsum -csum_partial_copy(const void *src, void *dst, int len, __wsum sum) -{ - memcpy(dst, src, len); - return csum_partial(dst, len, sum); -} -EXPORT_SYMBOL(csum_partial_copy); - -#ifndef csum_tcpudp_nofold -static inline u32 from64to32(u64 x) -{ - /* add up 32-bit and 32-bit for 32+c bit */ - x = (x & 0xffffffff) + (x >> 32); - /* add up carry.. */ - x = (x & 0xffffffff) + (x >> 32); - return (u32)x; -} - -__wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, - __u32 len, __u8 proto, __wsum sum) -{ - unsigned long long s = (__force u32)sum; - - s += (__force u32)saddr; - s += (__force u32)daddr; -#ifdef __BIG_ENDIAN - s += proto + len; -#else - s += (proto + len) << 8; -#endif - return (__force __wsum)from64to32(s); -} -EXPORT_SYMBOL(csum_tcpudp_nofold); -#endif diff --git a/src/linux/lib/clz_ctz.c b/src/linux/lib/clz_ctz.c deleted file mode 100644 index 2e11e48..0000000 --- a/src/linux/lib/clz_ctz.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - * lib/clz_ctz.c - * - * Copyright (C) 2013 Chanho Min - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * The functions in this file aren't called directly, but are required by - * GCC builtins such as __builtin_ctz, and therefore they can't be removed - * despite appearing unreferenced in kernel source. - * - * __c[lt]z[sd]i2 can be overridden by linking arch-specific versions. - */ - -#include -#include - -int __weak __ctzsi2(int val); -int __weak __ctzsi2(int val) -{ - return __ffs(val); -} -EXPORT_SYMBOL(__ctzsi2); - -int __weak __clzsi2(int val); -int __weak __clzsi2(int val) -{ - return 32 - fls(val); -} -EXPORT_SYMBOL(__clzsi2); - -int __weak __clzdi2(long val); -int __weak __ctzdi2(long val); -#if BITS_PER_LONG == 32 - -int __weak __clzdi2(long val) -{ - return 32 - fls((int)val); -} -EXPORT_SYMBOL(__clzdi2); - -int __weak __ctzdi2(long val) -{ - return __ffs((u32)val); -} -EXPORT_SYMBOL(__ctzdi2); - -#elif BITS_PER_LONG == 64 - -int __weak __clzdi2(long val) -{ - return 64 - fls64((u64)val); -} -EXPORT_SYMBOL(__clzdi2); - -int __weak __ctzdi2(long val) -{ - return __ffs64((u64)val); -} -EXPORT_SYMBOL(__ctzdi2); - -#else -#error BITS_PER_LONG not 32 or 64 -#endif diff --git a/src/linux/lib/cmdline.c b/src/linux/lib/cmdline.c deleted file mode 100644 index 8f13cf7..0000000 --- a/src/linux/lib/cmdline.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * linux/lib/cmdline.c - * Helper functions generally used for parsing kernel command line - * and module options. - * - * Code and copyrights come from init/main.c and arch/i386/kernel/setup.c. - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. - * - * GNU Indent formatting options for this file: -kr -i8 -npsl -pcs - * - */ - -#include -#include -#include - -/* - * If a hyphen was found in get_option, this will handle the - * range of numbers, M-N. This will expand the range and insert - * the values[M, M+1, ..., N] into the ints array in get_options. - */ - -static int get_range(char **str, int *pint) -{ - int x, inc_counter, upper_range; - - (*str)++; - upper_range = simple_strtol((*str), NULL, 0); - inc_counter = upper_range - *pint; - for (x = *pint; x < upper_range; x++) - *pint++ = x; - return inc_counter; -} - -/** - * get_option - Parse integer from an option string - * @str: option string - * @pint: (output) integer value parsed from @str - * - * Read an int from an option string; if available accept a subsequent - * comma as well. - * - * Return values: - * 0 - no int in string - * 1 - int found, no subsequent comma - * 2 - int found including a subsequent comma - * 3 - hyphen found to denote a range - */ - -int get_option(char **str, int *pint) -{ - char *cur = *str; - - if (!cur || !(*cur)) - return 0; - *pint = simple_strtol(cur, str, 0); - if (cur == *str) - return 0; - if (**str == ',') { - (*str)++; - return 2; - } - if (**str == '-') - return 3; - - return 1; -} -EXPORT_SYMBOL(get_option); - -/** - * get_options - Parse a string into a list of integers - * @str: String to be parsed - * @nints: size of integer array - * @ints: integer array - * - * This function parses a string containing a comma-separated - * list of integers, a hyphen-separated range of _positive_ integers, - * or a combination of both. The parse halts when the array is - * full, or when no more numbers can be retrieved from the - * string. - * - * Return value is the character in the string which caused - * the parse to end (typically a null terminator, if @str is - * completely parseable). - */ - -char *get_options(const char *str, int nints, int *ints) -{ - int res, i = 1; - - while (i < nints) { - res = get_option((char **)&str, ints + i); - if (res == 0) - break; - if (res == 3) { - int range_nums; - range_nums = get_range((char **)&str, ints + i); - if (range_nums < 0) - break; - /* - * Decrement the result by one to leave out the - * last number in the range. The next iteration - * will handle the upper number in the range - */ - i += (range_nums - 1); - } - i++; - if (res == 1) - break; - } - ints[0] = i - 1; - return (char *)str; -} -EXPORT_SYMBOL(get_options); - -/** - * memparse - parse a string with mem suffixes into a number - * @ptr: Where parse begins - * @retptr: (output) Optional pointer to next char after parse completes - * - * Parses a string into a number. The number stored at @ptr is - * potentially suffixed with K, M, G, T, P, E. - */ - -unsigned long long memparse(const char *ptr, char **retptr) -{ - char *endptr; /* local pointer to end of parsed string */ - - unsigned long long ret = simple_strtoull(ptr, &endptr, 0); - - switch (*endptr) { - case 'E': - case 'e': - ret <<= 10; - case 'P': - case 'p': - ret <<= 10; - case 'T': - case 't': - ret <<= 10; - case 'G': - case 'g': - ret <<= 10; - case 'M': - case 'm': - ret <<= 10; - case 'K': - case 'k': - ret <<= 10; - endptr++; - default: - break; - } - - if (retptr) - *retptr = endptr; - - return ret; -} -EXPORT_SYMBOL(memparse); - -/** - * parse_option_str - Parse a string and check an option is set or not - * @str: String to be parsed - * @option: option name - * - * This function parses a string containing a comma-separated list of - * strings like a=b,c. - * - * Return true if there's such option in the string, or return false. - */ -bool parse_option_str(const char *str, const char *option) -{ - while (*str) { - if (!strncmp(str, option, strlen(option))) { - str += strlen(option); - if (!*str || *str == ',') - return true; - } - - while (*str && *str != ',') - str++; - - if (*str == ',') - str++; - } - - return false; -} diff --git a/src/linux/lib/crc16.c b/src/linux/lib/crc16.c deleted file mode 100644 index 8737b08..0000000 --- a/src/linux/lib/crc16.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * crc16.c - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. - */ - -#include -#include -#include - -/** CRC table for the CRC-16. The poly is 0x8005 (x^16 + x^15 + x^2 + 1) */ -u16 const crc16_table[256] = { - 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241, - 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440, - 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40, - 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841, - 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40, - 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41, - 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641, - 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040, - 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240, - 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441, - 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41, - 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840, - 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41, - 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40, - 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640, - 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041, - 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240, - 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441, - 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41, - 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840, - 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41, - 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40, - 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640, - 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041, - 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241, - 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440, - 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40, - 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841, - 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40, - 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41, - 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641, - 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040 -}; -EXPORT_SYMBOL(crc16_table); - -/** - * crc16 - compute the CRC-16 for the data buffer - * @crc: previous CRC value - * @buffer: data pointer - * @len: number of bytes in the buffer - * - * Returns the updated CRC value. - */ -u16 crc16(u16 crc, u8 const *buffer, size_t len) -{ - while (len--) - crc = crc16_byte(crc, *buffer++); - return crc; -} -EXPORT_SYMBOL(crc16); - -MODULE_DESCRIPTION("CRC16 calculations"); -MODULE_LICENSE("GPL"); - diff --git a/src/linux/lib/crc32.c b/src/linux/lib/crc32.c deleted file mode 100644 index 7fbd1a1..0000000 --- a/src/linux/lib/crc32.c +++ /dev/null @@ -1,1166 +0,0 @@ -/* - * Aug 8, 2011 Bob Pearson with help from Joakim Tjernlund and George Spelvin - * cleaned up code to current version of sparse and added the slicing-by-8 - * algorithm to the closely similar existing slicing-by-4 algorithm. - * - * Oct 15, 2000 Matt Domsch - * Nicer crc32 functions/docs submitted by linux@horizon.com. Thanks! - * Code was from the public domain, copyright abandoned. Code was - * subsequently included in the kernel, thus was re-licensed under the - * GNU GPL v2. - * - * Oct 12, 2000 Matt Domsch - * Same crc32 function was used in 5 other places in the kernel. - * I made one version, and deleted the others. - * There are various incantations of crc32(). Some use a seed of 0 or ~0. - * Some xor at the end with ~0. The generic crc32() function takes - * seed as an argument, and doesn't xor at the end. Then individual - * users can do whatever they need. - * drivers/net/smc9194.c uses seed ~0, doesn't xor with ~0. - * fs/jffs2 uses seed 0, doesn't xor with ~0. - * fs/partitions/efi.c uses seed ~0, xor's with ~0. - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. - */ - -/* see: Documentation/crc32.txt for a description of algorithms */ - -#include -#include -#include -#include -#include "crc32defs.h" - -#if CRC_LE_BITS > 8 -# define tole(x) ((__force u32) cpu_to_le32(x)) -#else -# define tole(x) (x) -#endif - -#if CRC_BE_BITS > 8 -# define tobe(x) ((__force u32) cpu_to_be32(x)) -#else -# define tobe(x) (x) -#endif - -#include "crc32table.h" - -MODULE_AUTHOR("Matt Domsch "); -MODULE_DESCRIPTION("Various CRC32 calculations"); -MODULE_LICENSE("GPL"); - -#if CRC_LE_BITS > 8 || CRC_BE_BITS > 8 - -/* implements slicing-by-4 or slicing-by-8 algorithm */ -static inline u32 __pure -crc32_body(u32 crc, unsigned char const *buf, size_t len, const u32 (*tab)[256]) -{ -# ifdef __LITTLE_ENDIAN -# define DO_CRC(x) crc = t0[(crc ^ (x)) & 255] ^ (crc >> 8) -# define DO_CRC4 (t3[(q) & 255] ^ t2[(q >> 8) & 255] ^ \ - t1[(q >> 16) & 255] ^ t0[(q >> 24) & 255]) -# define DO_CRC8 (t7[(q) & 255] ^ t6[(q >> 8) & 255] ^ \ - t5[(q >> 16) & 255] ^ t4[(q >> 24) & 255]) -# else -# define DO_CRC(x) crc = t0[((crc >> 24) ^ (x)) & 255] ^ (crc << 8) -# define DO_CRC4 (t0[(q) & 255] ^ t1[(q >> 8) & 255] ^ \ - t2[(q >> 16) & 255] ^ t3[(q >> 24) & 255]) -# define DO_CRC8 (t4[(q) & 255] ^ t5[(q >> 8) & 255] ^ \ - t6[(q >> 16) & 255] ^ t7[(q >> 24) & 255]) -# endif - const u32 *b; - size_t rem_len; -# ifdef CONFIG_X86 - size_t i; -# endif - const u32 *t0=tab[0], *t1=tab[1], *t2=tab[2], *t3=tab[3]; -# if CRC_LE_BITS != 32 - const u32 *t4 = tab[4], *t5 = tab[5], *t6 = tab[6], *t7 = tab[7]; -# endif - u32 q; - - /* Align it */ - if (unlikely((long)buf & 3 && len)) { - do { - DO_CRC(*buf++); - } while ((--len) && ((long)buf)&3); - } - -# if CRC_LE_BITS == 32 - rem_len = len & 3; - len = len >> 2; -# else - rem_len = len & 7; - len = len >> 3; -# endif - - b = (const u32 *)buf; -# ifdef CONFIG_X86 - --b; - for (i = 0; i < len; i++) { -# else - for (--b; len; --len) { -# endif - q = crc ^ *++b; /* use pre increment for speed */ -# if CRC_LE_BITS == 32 - crc = DO_CRC4; -# else - crc = DO_CRC8; - q = *++b; - crc ^= DO_CRC4; -# endif - } - len = rem_len; - /* And the last few bytes */ - if (len) { - u8 *p = (u8 *)(b + 1) - 1; -# ifdef CONFIG_X86 - for (i = 0; i < len; i++) - DO_CRC(*++p); /* use pre increment for speed */ -# else - do { - DO_CRC(*++p); /* use pre increment for speed */ - } while (--len); -# endif - } - return crc; -#undef DO_CRC -#undef DO_CRC4 -#undef DO_CRC8 -} -#endif - - -/** - * crc32_le_generic() - Calculate bitwise little-endian Ethernet AUTODIN II - * CRC32/CRC32C - * @crc: seed value for computation. ~0 for Ethernet, sometimes 0 for other - * uses, or the previous crc32/crc32c value if computing incrementally. - * @p: pointer to buffer over which CRC32/CRC32C is run - * @len: length of buffer @p - * @tab: little-endian Ethernet table - * @polynomial: CRC32/CRC32c LE polynomial - */ -static inline u32 __pure crc32_le_generic(u32 crc, unsigned char const *p, - size_t len, const u32 (*tab)[256], - u32 polynomial) -{ -#if CRC_LE_BITS == 1 - int i; - while (len--) { - crc ^= *p++; - for (i = 0; i < 8; i++) - crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0); - } -# elif CRC_LE_BITS == 2 - while (len--) { - crc ^= *p++; - crc = (crc >> 2) ^ tab[0][crc & 3]; - crc = (crc >> 2) ^ tab[0][crc & 3]; - crc = (crc >> 2) ^ tab[0][crc & 3]; - crc = (crc >> 2) ^ tab[0][crc & 3]; - } -# elif CRC_LE_BITS == 4 - while (len--) { - crc ^= *p++; - crc = (crc >> 4) ^ tab[0][crc & 15]; - crc = (crc >> 4) ^ tab[0][crc & 15]; - } -# elif CRC_LE_BITS == 8 - /* aka Sarwate algorithm */ - while (len--) { - crc ^= *p++; - crc = (crc >> 8) ^ tab[0][crc & 255]; - } -# else - crc = (__force u32) __cpu_to_le32(crc); - crc = crc32_body(crc, p, len, tab); - crc = __le32_to_cpu((__force __le32)crc); -#endif - return crc; -} - -#if CRC_LE_BITS == 1 -u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len) -{ - return crc32_le_generic(crc, p, len, NULL, CRCPOLY_LE); -} -u32 __pure __crc32c_le(u32 crc, unsigned char const *p, size_t len) -{ - return crc32_le_generic(crc, p, len, NULL, CRC32C_POLY_LE); -} -#else -u32 __pure crc32_le(u32 crc, unsigned char const *p, size_t len) -{ - return crc32_le_generic(crc, p, len, - (const u32 (*)[256])crc32table_le, CRCPOLY_LE); -} -u32 __pure __crc32c_le(u32 crc, unsigned char const *p, size_t len) -{ - return crc32_le_generic(crc, p, len, - (const u32 (*)[256])crc32ctable_le, CRC32C_POLY_LE); -} -#endif -EXPORT_SYMBOL(crc32_le); -EXPORT_SYMBOL(__crc32c_le); - -/* - * This multiplies the polynomials x and y modulo the given modulus. - * This follows the "little-endian" CRC convention that the lsbit - * represents the highest power of x, and the msbit represents x^0. - */ -static u32 __attribute_const__ gf2_multiply(u32 x, u32 y, u32 modulus) -{ - u32 product = x & 1 ? y : 0; - int i; - - for (i = 0; i < 31; i++) { - product = (product >> 1) ^ (product & 1 ? modulus : 0); - x >>= 1; - product ^= x & 1 ? y : 0; - } - - return product; -} - -/** - * crc32_generic_shift - Append len 0 bytes to crc, in logarithmic time - * @crc: The original little-endian CRC (i.e. lsbit is x^31 coefficient) - * @len: The number of bytes. @crc is multiplied by x^(8*@len) - * @polynomial: The modulus used to reduce the result to 32 bits. - * - * It's possible to parallelize CRC computations by computing a CRC - * over separate ranges of a buffer, then summing them. - * This shifts the given CRC by 8*len bits (i.e. produces the same effect - * as appending len bytes of zero to the data), in time proportional - * to log(len). - */ -static u32 __attribute_const__ crc32_generic_shift(u32 crc, size_t len, - u32 polynomial) -{ - u32 power = polynomial; /* CRC of x^32 */ - int i; - - /* Shift up to 32 bits in the simple linear way */ - for (i = 0; i < 8 * (int)(len & 3); i++) - crc = (crc >> 1) ^ (crc & 1 ? polynomial : 0); - - len >>= 2; - if (!len) - return crc; - - for (;;) { - /* "power" is x^(2^i), modulo the polynomial */ - if (len & 1) - crc = gf2_multiply(crc, power, polynomial); - - len >>= 1; - if (!len) - break; - - /* Square power, advancing to x^(2^(i+1)) */ - power = gf2_multiply(power, power, polynomial); - } - - return crc; -} - -u32 __attribute_const__ crc32_le_shift(u32 crc, size_t len) -{ - return crc32_generic_shift(crc, len, CRCPOLY_LE); -} - -u32 __attribute_const__ __crc32c_le_shift(u32 crc, size_t len) -{ - return crc32_generic_shift(crc, len, CRC32C_POLY_LE); -} -EXPORT_SYMBOL(crc32_le_shift); -EXPORT_SYMBOL(__crc32c_le_shift); - -/** - * crc32_be_generic() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32 - * @crc: seed value for computation. ~0 for Ethernet, sometimes 0 for - * other uses, or the previous crc32 value if computing incrementally. - * @p: pointer to buffer over which CRC32 is run - * @len: length of buffer @p - * @tab: big-endian Ethernet table - * @polynomial: CRC32 BE polynomial - */ -static inline u32 __pure crc32_be_generic(u32 crc, unsigned char const *p, - size_t len, const u32 (*tab)[256], - u32 polynomial) -{ -#if CRC_BE_BITS == 1 - int i; - while (len--) { - crc ^= *p++ << 24; - for (i = 0; i < 8; i++) - crc = - (crc << 1) ^ ((crc & 0x80000000) ? polynomial : - 0); - } -# elif CRC_BE_BITS == 2 - while (len--) { - crc ^= *p++ << 24; - crc = (crc << 2) ^ tab[0][crc >> 30]; - crc = (crc << 2) ^ tab[0][crc >> 30]; - crc = (crc << 2) ^ tab[0][crc >> 30]; - crc = (crc << 2) ^ tab[0][crc >> 30]; - } -# elif CRC_BE_BITS == 4 - while (len--) { - crc ^= *p++ << 24; - crc = (crc << 4) ^ tab[0][crc >> 28]; - crc = (crc << 4) ^ tab[0][crc >> 28]; - } -# elif CRC_BE_BITS == 8 - while (len--) { - crc ^= *p++ << 24; - crc = (crc << 8) ^ tab[0][crc >> 24]; - } -# else - crc = (__force u32) __cpu_to_be32(crc); - crc = crc32_body(crc, p, len, tab); - crc = __be32_to_cpu((__force __be32)crc); -# endif - return crc; -} - -#if CRC_LE_BITS == 1 -u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len) -{ - return crc32_be_generic(crc, p, len, NULL, CRCPOLY_BE); -} -#else -u32 __pure crc32_be(u32 crc, unsigned char const *p, size_t len) -{ - return crc32_be_generic(crc, p, len, - (const u32 (*)[256])crc32table_be, CRCPOLY_BE); -} -#endif -EXPORT_SYMBOL(crc32_be); - -#ifdef CONFIG_CRC32_SELFTEST - -/* 4096 random bytes */ -static u8 const __aligned(8) test_buf[] __initconst = -{ - 0x5b, 0x85, 0x21, 0xcb, 0x09, 0x68, 0x7d, 0x30, - 0xc7, 0x69, 0xd7, 0x30, 0x92, 0xde, 0x59, 0xe4, - 0xc9, 0x6e, 0x8b, 0xdb, 0x98, 0x6b, 0xaa, 0x60, - 0xa8, 0xb5, 0xbc, 0x6c, 0xa9, 0xb1, 0x5b, 0x2c, - 0xea, 0xb4, 0x92, 0x6a, 0x3f, 0x79, 0x91, 0xe4, - 0xe9, 0x70, 0x51, 0x8c, 0x7f, 0x95, 0x6f, 0x1a, - 0x56, 0xa1, 0x5c, 0x27, 0x03, 0x67, 0x9f, 0x3a, - 0xe2, 0x31, 0x11, 0x29, 0x6b, 0x98, 0xfc, 0xc4, - 0x53, 0x24, 0xc5, 0x8b, 0xce, 0x47, 0xb2, 0xb9, - 0x32, 0xcb, 0xc1, 0xd0, 0x03, 0x57, 0x4e, 0xd4, - 0xe9, 0x3c, 0xa1, 0x63, 0xcf, 0x12, 0x0e, 0xca, - 0xe1, 0x13, 0xd1, 0x93, 0xa6, 0x88, 0x5c, 0x61, - 0x5b, 0xbb, 0xf0, 0x19, 0x46, 0xb4, 0xcf, 0x9e, - 0xb6, 0x6b, 0x4c, 0x3a, 0xcf, 0x60, 0xf9, 0x7a, - 0x8d, 0x07, 0x63, 0xdb, 0x40, 0xe9, 0x0b, 0x6f, - 0xad, 0x97, 0xf1, 0xed, 0xd0, 0x1e, 0x26, 0xfd, - 0xbf, 0xb7, 0xc8, 0x04, 0x94, 0xf8, 0x8b, 0x8c, - 0xf1, 0xab, 0x7a, 0xd4, 0xdd, 0xf3, 0xe8, 0x88, - 0xc3, 0xed, 0x17, 0x8a, 0x9b, 0x40, 0x0d, 0x53, - 0x62, 0x12, 0x03, 0x5f, 0x1b, 0x35, 0x32, 0x1f, - 0xb4, 0x7b, 0x93, 0x78, 0x0d, 0xdb, 0xce, 0xa4, - 0xc0, 0x47, 0xd5, 0xbf, 0x68, 0xe8, 0x5d, 0x74, - 0x8f, 0x8e, 0x75, 0x1c, 0xb2, 0x4f, 0x9a, 0x60, - 0xd1, 0xbe, 0x10, 0xf4, 0x5c, 0xa1, 0x53, 0x09, - 0xa5, 0xe0, 0x09, 0x54, 0x85, 0x5c, 0xdc, 0x07, - 0xe7, 0x21, 0x69, 0x7b, 0x8a, 0xfd, 0x90, 0xf1, - 0x22, 0xd0, 0xb4, 0x36, 0x28, 0xe6, 0xb8, 0x0f, - 0x39, 0xde, 0xc8, 0xf3, 0x86, 0x60, 0x34, 0xd2, - 0x5e, 0xdf, 0xfd, 0xcf, 0x0f, 0xa9, 0x65, 0xf0, - 0xd5, 0x4d, 0x96, 0x40, 0xe3, 0xdf, 0x3f, 0x95, - 0x5a, 0x39, 0x19, 0x93, 0xf4, 0x75, 0xce, 0x22, - 0x00, 0x1c, 0x93, 0xe2, 0x03, 0x66, 0xf4, 0x93, - 0x73, 0x86, 0x81, 0x8e, 0x29, 0x44, 0x48, 0x86, - 0x61, 0x7c, 0x48, 0xa3, 0x43, 0xd2, 0x9c, 0x8d, - 0xd4, 0x95, 0xdd, 0xe1, 0x22, 0x89, 0x3a, 0x40, - 0x4c, 0x1b, 0x8a, 0x04, 0xa8, 0x09, 0x69, 0x8b, - 0xea, 0xc6, 0x55, 0x8e, 0x57, 0xe6, 0x64, 0x35, - 0xf0, 0xc7, 0x16, 0x9f, 0x5d, 0x5e, 0x86, 0x40, - 0x46, 0xbb, 0xe5, 0x45, 0x88, 0xfe, 0xc9, 0x63, - 0x15, 0xfb, 0xf5, 0xbd, 0x71, 0x61, 0xeb, 0x7b, - 0x78, 0x70, 0x07, 0x31, 0x03, 0x9f, 0xb2, 0xc8, - 0xa7, 0xab, 0x47, 0xfd, 0xdf, 0xa0, 0x78, 0x72, - 0xa4, 0x2a, 0xe4, 0xb6, 0xba, 0xc0, 0x1e, 0x86, - 0x71, 0xe6, 0x3d, 0x18, 0x37, 0x70, 0xe6, 0xff, - 0xe0, 0xbc, 0x0b, 0x22, 0xa0, 0x1f, 0xd3, 0xed, - 0xa2, 0x55, 0x39, 0xab, 0xa8, 0x13, 0x73, 0x7c, - 0x3f, 0xb2, 0xd6, 0x19, 0xac, 0xff, 0x99, 0xed, - 0xe8, 0xe6, 0xa6, 0x22, 0xe3, 0x9c, 0xf1, 0x30, - 0xdc, 0x01, 0x0a, 0x56, 0xfa, 0xe4, 0xc9, 0x99, - 0xdd, 0xa8, 0xd8, 0xda, 0x35, 0x51, 0x73, 0xb4, - 0x40, 0x86, 0x85, 0xdb, 0x5c, 0xd5, 0x85, 0x80, - 0x14, 0x9c, 0xfd, 0x98, 0xa9, 0x82, 0xc5, 0x37, - 0xff, 0x32, 0x5d, 0xd0, 0x0b, 0xfa, 0xdc, 0x04, - 0x5e, 0x09, 0xd2, 0xca, 0x17, 0x4b, 0x1a, 0x8e, - 0x15, 0xe1, 0xcc, 0x4e, 0x52, 0x88, 0x35, 0xbd, - 0x48, 0xfe, 0x15, 0xa0, 0x91, 0xfd, 0x7e, 0x6c, - 0x0e, 0x5d, 0x79, 0x1b, 0x81, 0x79, 0xd2, 0x09, - 0x34, 0x70, 0x3d, 0x81, 0xec, 0xf6, 0x24, 0xbb, - 0xfb, 0xf1, 0x7b, 0xdf, 0x54, 0xea, 0x80, 0x9b, - 0xc7, 0x99, 0x9e, 0xbd, 0x16, 0x78, 0x12, 0x53, - 0x5e, 0x01, 0xa7, 0x4e, 0xbd, 0x67, 0xe1, 0x9b, - 0x4c, 0x0e, 0x61, 0x45, 0x97, 0xd2, 0xf0, 0x0f, - 0xfe, 0x15, 0x08, 0xb7, 0x11, 0x4c, 0xe7, 0xff, - 0x81, 0x53, 0xff, 0x91, 0x25, 0x38, 0x7e, 0x40, - 0x94, 0xe5, 0xe0, 0xad, 0xe6, 0xd9, 0x79, 0xb6, - 0x92, 0xc9, 0xfc, 0xde, 0xc3, 0x1a, 0x23, 0xbb, - 0xdd, 0xc8, 0x51, 0x0c, 0x3a, 0x72, 0xfa, 0x73, - 0x6f, 0xb7, 0xee, 0x61, 0x39, 0x03, 0x01, 0x3f, - 0x7f, 0x94, 0x2e, 0x2e, 0xba, 0x3a, 0xbb, 0xb4, - 0xfa, 0x6a, 0x17, 0xfe, 0xea, 0xef, 0x5e, 0x66, - 0x97, 0x3f, 0x32, 0x3d, 0xd7, 0x3e, 0xb1, 0xf1, - 0x6c, 0x14, 0x4c, 0xfd, 0x37, 0xd3, 0x38, 0x80, - 0xfb, 0xde, 0xa6, 0x24, 0x1e, 0xc8, 0xca, 0x7f, - 0x3a, 0x93, 0xd8, 0x8b, 0x18, 0x13, 0xb2, 0xe5, - 0xe4, 0x93, 0x05, 0x53, 0x4f, 0x84, 0x66, 0xa7, - 0x58, 0x5c, 0x7b, 0x86, 0x52, 0x6d, 0x0d, 0xce, - 0xa4, 0x30, 0x7d, 0xb6, 0x18, 0x9f, 0xeb, 0xff, - 0x22, 0xbb, 0x72, 0x29, 0xb9, 0x44, 0x0b, 0x48, - 0x1e, 0x84, 0x71, 0x81, 0xe3, 0x6d, 0x73, 0x26, - 0x92, 0xb4, 0x4d, 0x2a, 0x29, 0xb8, 0x1f, 0x72, - 0xed, 0xd0, 0xe1, 0x64, 0x77, 0xea, 0x8e, 0x88, - 0x0f, 0xef, 0x3f, 0xb1, 0x3b, 0xad, 0xf9, 0xc9, - 0x8b, 0xd0, 0xac, 0xc6, 0xcc, 0xa9, 0x40, 0xcc, - 0x76, 0xf6, 0x3b, 0x53, 0xb5, 0x88, 0xcb, 0xc8, - 0x37, 0xf1, 0xa2, 0xba, 0x23, 0x15, 0x99, 0x09, - 0xcc, 0xe7, 0x7a, 0x3b, 0x37, 0xf7, 0x58, 0xc8, - 0x46, 0x8c, 0x2b, 0x2f, 0x4e, 0x0e, 0xa6, 0x5c, - 0xea, 0x85, 0x55, 0xba, 0x02, 0x0e, 0x0e, 0x48, - 0xbc, 0xe1, 0xb1, 0x01, 0x35, 0x79, 0x13, 0x3d, - 0x1b, 0xc0, 0x53, 0x68, 0x11, 0xe7, 0x95, 0x0f, - 0x9d, 0x3f, 0x4c, 0x47, 0x7b, 0x4d, 0x1c, 0xae, - 0x50, 0x9b, 0xcb, 0xdd, 0x05, 0x8d, 0x9a, 0x97, - 0xfd, 0x8c, 0xef, 0x0c, 0x1d, 0x67, 0x73, 0xa8, - 0x28, 0x36, 0xd5, 0xb6, 0x92, 0x33, 0x40, 0x75, - 0x0b, 0x51, 0xc3, 0x64, 0xba, 0x1d, 0xc2, 0xcc, - 0xee, 0x7d, 0x54, 0x0f, 0x27, 0x69, 0xa7, 0x27, - 0x63, 0x30, 0x29, 0xd9, 0xc8, 0x84, 0xd8, 0xdf, - 0x9f, 0x68, 0x8d, 0x04, 0xca, 0xa6, 0xc5, 0xc7, - 0x7a, 0x5c, 0xc8, 0xd1, 0xcb, 0x4a, 0xec, 0xd0, - 0xd8, 0x20, 0x69, 0xc5, 0x17, 0xcd, 0x78, 0xc8, - 0x75, 0x23, 0x30, 0x69, 0xc9, 0xd4, 0xea, 0x5c, - 0x4f, 0x6b, 0x86, 0x3f, 0x8b, 0xfe, 0xee, 0x44, - 0xc9, 0x7c, 0xb7, 0xdd, 0x3e, 0xe5, 0xec, 0x54, - 0x03, 0x3e, 0xaa, 0x82, 0xc6, 0xdf, 0xb2, 0x38, - 0x0e, 0x5d, 0xb3, 0x88, 0xd9, 0xd3, 0x69, 0x5f, - 0x8f, 0x70, 0x8a, 0x7e, 0x11, 0xd9, 0x1e, 0x7b, - 0x38, 0xf1, 0x42, 0x1a, 0xc0, 0x35, 0xf5, 0xc7, - 0x36, 0x85, 0xf5, 0xf7, 0xb8, 0x7e, 0xc7, 0xef, - 0x18, 0xf1, 0x63, 0xd6, 0x7a, 0xc6, 0xc9, 0x0e, - 0x4d, 0x69, 0x4f, 0x84, 0xef, 0x26, 0x41, 0x0c, - 0xec, 0xc7, 0xe0, 0x7e, 0x3c, 0x67, 0x01, 0x4c, - 0x62, 0x1a, 0x20, 0x6f, 0xee, 0x47, 0x4d, 0xc0, - 0x99, 0x13, 0x8d, 0x91, 0x4a, 0x26, 0xd4, 0x37, - 0x28, 0x90, 0x58, 0x75, 0x66, 0x2b, 0x0a, 0xdf, - 0xda, 0xee, 0x92, 0x25, 0x90, 0x62, 0x39, 0x9e, - 0x44, 0x98, 0xad, 0xc1, 0x88, 0xed, 0xe4, 0xb4, - 0xaf, 0xf5, 0x8c, 0x9b, 0x48, 0x4d, 0x56, 0x60, - 0x97, 0x0f, 0x61, 0x59, 0x9e, 0xa6, 0x27, 0xfe, - 0xc1, 0x91, 0x15, 0x38, 0xb8, 0x0f, 0xae, 0x61, - 0x7d, 0x26, 0x13, 0x5a, 0x73, 0xff, 0x1c, 0xa3, - 0x61, 0x04, 0x58, 0x48, 0x55, 0x44, 0x11, 0xfe, - 0x15, 0xca, 0xc3, 0xbd, 0xca, 0xc5, 0xb4, 0x40, - 0x5d, 0x1b, 0x7f, 0x39, 0xb5, 0x9c, 0x35, 0xec, - 0x61, 0x15, 0x32, 0x32, 0xb8, 0x4e, 0x40, 0x9f, - 0x17, 0x1f, 0x0a, 0x4d, 0xa9, 0x91, 0xef, 0xb7, - 0xb0, 0xeb, 0xc2, 0x83, 0x9a, 0x6c, 0xd2, 0x79, - 0x43, 0x78, 0x5e, 0x2f, 0xe5, 0xdd, 0x1a, 0x3c, - 0x45, 0xab, 0x29, 0x40, 0x3a, 0x37, 0x5b, 0x6f, - 0xd7, 0xfc, 0x48, 0x64, 0x3c, 0x49, 0xfb, 0x21, - 0xbe, 0xc3, 0xff, 0x07, 0xfb, 0x17, 0xe9, 0xc9, - 0x0c, 0x4c, 0x5c, 0x15, 0x9e, 0x8e, 0x22, 0x30, - 0x0a, 0xde, 0x48, 0x7f, 0xdb, 0x0d, 0xd1, 0x2b, - 0x87, 0x38, 0x9e, 0xcc, 0x5a, 0x01, 0x16, 0xee, - 0x75, 0x49, 0x0d, 0x30, 0x01, 0x34, 0x6a, 0xb6, - 0x9a, 0x5a, 0x2a, 0xec, 0xbb, 0x48, 0xac, 0xd3, - 0x77, 0x83, 0xd8, 0x08, 0x86, 0x4f, 0x48, 0x09, - 0x29, 0x41, 0x79, 0xa1, 0x03, 0x12, 0xc4, 0xcd, - 0x90, 0x55, 0x47, 0x66, 0x74, 0x9a, 0xcc, 0x4f, - 0x35, 0x8c, 0xd6, 0x98, 0xef, 0xeb, 0x45, 0xb9, - 0x9a, 0x26, 0x2f, 0x39, 0xa5, 0x70, 0x6d, 0xfc, - 0xb4, 0x51, 0xee, 0xf4, 0x9c, 0xe7, 0x38, 0x59, - 0xad, 0xf4, 0xbc, 0x46, 0xff, 0x46, 0x8e, 0x60, - 0x9c, 0xa3, 0x60, 0x1d, 0xf8, 0x26, 0x72, 0xf5, - 0x72, 0x9d, 0x68, 0x80, 0x04, 0xf6, 0x0b, 0xa1, - 0x0a, 0xd5, 0xa7, 0x82, 0x3a, 0x3e, 0x47, 0xa8, - 0x5a, 0xde, 0x59, 0x4f, 0x7b, 0x07, 0xb3, 0xe9, - 0x24, 0x19, 0x3d, 0x34, 0x05, 0xec, 0xf1, 0xab, - 0x6e, 0x64, 0x8f, 0xd3, 0xe6, 0x41, 0x86, 0x80, - 0x70, 0xe3, 0x8d, 0x60, 0x9c, 0x34, 0x25, 0x01, - 0x07, 0x4d, 0x19, 0x41, 0x4e, 0x3d, 0x5c, 0x7e, - 0xa8, 0xf5, 0xcc, 0xd5, 0x7b, 0xe2, 0x7d, 0x3d, - 0x49, 0x86, 0x7d, 0x07, 0xb7, 0x10, 0xe3, 0x35, - 0xb8, 0x84, 0x6d, 0x76, 0xab, 0x17, 0xc6, 0x38, - 0xb4, 0xd3, 0x28, 0x57, 0xad, 0xd3, 0x88, 0x5a, - 0xda, 0xea, 0xc8, 0x94, 0xcc, 0x37, 0x19, 0xac, - 0x9c, 0x9f, 0x4b, 0x00, 0x15, 0xc0, 0xc8, 0xca, - 0x1f, 0x15, 0xaa, 0xe0, 0xdb, 0xf9, 0x2f, 0x57, - 0x1b, 0x24, 0xc7, 0x6f, 0x76, 0x29, 0xfb, 0xed, - 0x25, 0x0d, 0xc0, 0xfe, 0xbd, 0x5a, 0xbf, 0x20, - 0x08, 0x51, 0x05, 0xec, 0x71, 0xa3, 0xbf, 0xef, - 0x5e, 0x99, 0x75, 0xdb, 0x3c, 0x5f, 0x9a, 0x8c, - 0xbb, 0x19, 0x5c, 0x0e, 0x93, 0x19, 0xf8, 0x6a, - 0xbc, 0xf2, 0x12, 0x54, 0x2f, 0xcb, 0x28, 0x64, - 0x88, 0xb3, 0x92, 0x0d, 0x96, 0xd1, 0xa6, 0xe4, - 0x1f, 0xf1, 0x4d, 0xa4, 0xab, 0x1c, 0xee, 0x54, - 0xf2, 0xad, 0x29, 0x6d, 0x32, 0x37, 0xb2, 0x16, - 0x77, 0x5c, 0xdc, 0x2e, 0x54, 0xec, 0x75, 0x26, - 0xc6, 0x36, 0xd9, 0x17, 0x2c, 0xf1, 0x7a, 0xdc, - 0x4b, 0xf1, 0xe2, 0xd9, 0x95, 0xba, 0xac, 0x87, - 0xc1, 0xf3, 0x8e, 0x58, 0x08, 0xd8, 0x87, 0x60, - 0xc9, 0xee, 0x6a, 0xde, 0xa4, 0xd2, 0xfc, 0x0d, - 0xe5, 0x36, 0xc4, 0x5c, 0x52, 0xb3, 0x07, 0x54, - 0x65, 0x24, 0xc1, 0xb1, 0xd1, 0xb1, 0x53, 0x13, - 0x31, 0x79, 0x7f, 0x05, 0x76, 0xeb, 0x37, 0x59, - 0x15, 0x2b, 0xd1, 0x3f, 0xac, 0x08, 0x97, 0xeb, - 0x91, 0x98, 0xdf, 0x6c, 0x09, 0x0d, 0x04, 0x9f, - 0xdc, 0x3b, 0x0e, 0x60, 0x68, 0x47, 0x23, 0x15, - 0x16, 0xc6, 0x0b, 0x35, 0xf8, 0x77, 0xa2, 0x78, - 0x50, 0xd4, 0x64, 0x22, 0x33, 0xff, 0xfb, 0x93, - 0x71, 0x46, 0x50, 0x39, 0x1b, 0x9c, 0xea, 0x4e, - 0x8d, 0x0c, 0x37, 0xe5, 0x5c, 0x51, 0x3a, 0x31, - 0xb2, 0x85, 0x84, 0x3f, 0x41, 0xee, 0xa2, 0xc1, - 0xc6, 0x13, 0x3b, 0x54, 0x28, 0xd2, 0x18, 0x37, - 0xcc, 0x46, 0x9f, 0x6a, 0x91, 0x3d, 0x5a, 0x15, - 0x3c, 0x89, 0xa3, 0x61, 0x06, 0x7d, 0x2e, 0x78, - 0xbe, 0x7d, 0x40, 0xba, 0x2f, 0x95, 0xb1, 0x2f, - 0x87, 0x3b, 0x8a, 0xbe, 0x6a, 0xf4, 0xc2, 0x31, - 0x74, 0xee, 0x91, 0xe0, 0x23, 0xaa, 0x5d, 0x7f, - 0xdd, 0xf0, 0x44, 0x8c, 0x0b, 0x59, 0x2b, 0xfc, - 0x48, 0x3a, 0xdf, 0x07, 0x05, 0x38, 0x6c, 0xc9, - 0xeb, 0x18, 0x24, 0x68, 0x8d, 0x58, 0x98, 0xd3, - 0x31, 0xa3, 0xe4, 0x70, 0x59, 0xb1, 0x21, 0xbe, - 0x7e, 0x65, 0x7d, 0xb8, 0x04, 0xab, 0xf6, 0xe4, - 0xd7, 0xda, 0xec, 0x09, 0x8f, 0xda, 0x6d, 0x24, - 0x07, 0xcc, 0x29, 0x17, 0x05, 0x78, 0x1a, 0xc1, - 0xb1, 0xce, 0xfc, 0xaa, 0x2d, 0xe7, 0xcc, 0x85, - 0x84, 0x84, 0x03, 0x2a, 0x0c, 0x3f, 0xa9, 0xf8, - 0xfd, 0x84, 0x53, 0x59, 0x5c, 0xf0, 0xd4, 0x09, - 0xf0, 0xd2, 0x6c, 0x32, 0x03, 0xb0, 0xa0, 0x8c, - 0x52, 0xeb, 0x23, 0x91, 0x88, 0x43, 0x13, 0x46, - 0xf6, 0x1e, 0xb4, 0x1b, 0xf5, 0x8e, 0x3a, 0xb5, - 0x3d, 0x00, 0xf6, 0xe5, 0x08, 0x3d, 0x5f, 0x39, - 0xd3, 0x21, 0x69, 0xbc, 0x03, 0x22, 0x3a, 0xd2, - 0x5c, 0x84, 0xf8, 0x15, 0xc4, 0x80, 0x0b, 0xbc, - 0x29, 0x3c, 0xf3, 0x95, 0x98, 0xcd, 0x8f, 0x35, - 0xbc, 0xa5, 0x3e, 0xfc, 0xd4, 0x13, 0x9e, 0xde, - 0x4f, 0xce, 0x71, 0x9d, 0x09, 0xad, 0xf2, 0x80, - 0x6b, 0x65, 0x7f, 0x03, 0x00, 0x14, 0x7c, 0x15, - 0x85, 0x40, 0x6d, 0x70, 0xea, 0xdc, 0xb3, 0x63, - 0x35, 0x4f, 0x4d, 0xe0, 0xd9, 0xd5, 0x3c, 0x58, - 0x56, 0x23, 0x80, 0xe2, 0x36, 0xdd, 0x75, 0x1d, - 0x94, 0x11, 0x41, 0x8e, 0xe0, 0x81, 0x8e, 0xcf, - 0xe0, 0xe5, 0xf6, 0xde, 0xd1, 0xe7, 0x04, 0x12, - 0x79, 0x92, 0x2b, 0x71, 0x2a, 0x79, 0x8b, 0x7c, - 0x44, 0x79, 0x16, 0x30, 0x4e, 0xf4, 0xf6, 0x9b, - 0xb7, 0x40, 0xa3, 0x5a, 0xa7, 0x69, 0x3e, 0xc1, - 0x3a, 0x04, 0xd0, 0x88, 0xa0, 0x3b, 0xdd, 0xc6, - 0x9e, 0x7e, 0x1e, 0x1e, 0x8f, 0x44, 0xf7, 0x73, - 0x67, 0x1e, 0x1a, 0x78, 0xfa, 0x62, 0xf4, 0xa9, - 0xa8, 0xc6, 0x5b, 0xb8, 0xfa, 0x06, 0x7d, 0x5e, - 0x38, 0x1c, 0x9a, 0x39, 0xe9, 0x39, 0x98, 0x22, - 0x0b, 0xa7, 0xac, 0x0b, 0xf3, 0xbc, 0xf1, 0xeb, - 0x8c, 0x81, 0xe3, 0x48, 0x8a, 0xed, 0x42, 0xc2, - 0x38, 0xcf, 0x3e, 0xda, 0xd2, 0x89, 0x8d, 0x9c, - 0x53, 0xb5, 0x2f, 0x41, 0x01, 0x26, 0x84, 0x9c, - 0xa3, 0x56, 0xf6, 0x49, 0xc7, 0xd4, 0x9f, 0x93, - 0x1b, 0x96, 0x49, 0x5e, 0xad, 0xb3, 0x84, 0x1f, - 0x3c, 0xa4, 0xe0, 0x9b, 0xd1, 0x90, 0xbc, 0x38, - 0x6c, 0xdd, 0x95, 0x4d, 0x9d, 0xb1, 0x71, 0x57, - 0x2d, 0x34, 0xe8, 0xb8, 0x42, 0xc7, 0x99, 0x03, - 0xc7, 0x07, 0x30, 0x65, 0x91, 0x55, 0xd5, 0x90, - 0x70, 0x97, 0x37, 0x68, 0xd4, 0x11, 0xf9, 0xe8, - 0xce, 0xec, 0xdc, 0x34, 0xd5, 0xd3, 0xb7, 0xc4, - 0xb8, 0x97, 0x05, 0x92, 0xad, 0xf8, 0xe2, 0x36, - 0x64, 0x41, 0xc9, 0xc5, 0x41, 0x77, 0x52, 0xd7, - 0x2c, 0xa5, 0x24, 0x2f, 0xd9, 0x34, 0x0b, 0x47, - 0x35, 0xa7, 0x28, 0x8b, 0xc5, 0xcd, 0xe9, 0x46, - 0xac, 0x39, 0x94, 0x3c, 0x10, 0xc6, 0x29, 0x73, - 0x0e, 0x0e, 0x5d, 0xe0, 0x71, 0x03, 0x8a, 0x72, - 0x0e, 0x26, 0xb0, 0x7d, 0x84, 0xed, 0x95, 0x23, - 0x49, 0x5a, 0x45, 0x83, 0x45, 0x60, 0x11, 0x4a, - 0x46, 0x31, 0xd4, 0xd8, 0x16, 0x54, 0x98, 0x58, - 0xed, 0x6d, 0xcc, 0x5d, 0xd6, 0x50, 0x61, 0x9f, - 0x9d, 0xc5, 0x3e, 0x9d, 0x32, 0x47, 0xde, 0x96, - 0xe1, 0x5d, 0xd8, 0xf8, 0xb4, 0x69, 0x6f, 0xb9, - 0x15, 0x90, 0x57, 0x7a, 0xf6, 0xad, 0xb0, 0x5b, - 0xf5, 0xa6, 0x36, 0x94, 0xfd, 0x84, 0xce, 0x1c, - 0x0f, 0x4b, 0xd0, 0xc2, 0x5b, 0x6b, 0x56, 0xef, - 0x73, 0x93, 0x0b, 0xc3, 0xee, 0xd9, 0xcf, 0xd3, - 0xa4, 0x22, 0x58, 0xcd, 0x50, 0x6e, 0x65, 0xf4, - 0xe9, 0xb7, 0x71, 0xaf, 0x4b, 0xb3, 0xb6, 0x2f, - 0x0f, 0x0e, 0x3b, 0xc9, 0x85, 0x14, 0xf5, 0x17, - 0xe8, 0x7a, 0x3a, 0xbf, 0x5f, 0x5e, 0xf8, 0x18, - 0x48, 0xa6, 0x72, 0xab, 0x06, 0x95, 0xe9, 0xc8, - 0xa7, 0xf4, 0x32, 0x44, 0x04, 0x0c, 0x84, 0x98, - 0x73, 0xe3, 0x89, 0x8d, 0x5f, 0x7e, 0x4a, 0x42, - 0x8f, 0xc5, 0x28, 0xb1, 0x82, 0xef, 0x1c, 0x97, - 0x31, 0x3b, 0x4d, 0xe0, 0x0e, 0x10, 0x10, 0x97, - 0x93, 0x49, 0x78, 0x2f, 0x0d, 0x86, 0x8b, 0xa1, - 0x53, 0xa9, 0x81, 0x20, 0x79, 0xe7, 0x07, 0x77, - 0xb6, 0xac, 0x5e, 0xd2, 0x05, 0xcd, 0xe9, 0xdb, - 0x8a, 0x94, 0x82, 0x8a, 0x23, 0xb9, 0x3d, 0x1c, - 0xa9, 0x7d, 0x72, 0x4a, 0xed, 0x33, 0xa3, 0xdb, - 0x21, 0xa7, 0x86, 0x33, 0x45, 0xa5, 0xaa, 0x56, - 0x45, 0xb5, 0x83, 0x29, 0x40, 0x47, 0x79, 0x04, - 0x6e, 0xb9, 0x95, 0xd0, 0x81, 0x77, 0x2d, 0x48, - 0x1e, 0xfe, 0xc3, 0xc2, 0x1e, 0xe5, 0xf2, 0xbe, - 0xfd, 0x3b, 0x94, 0x9f, 0xc4, 0xc4, 0x26, 0x9d, - 0xe4, 0x66, 0x1e, 0x19, 0xee, 0x6c, 0x79, 0x97, - 0x11, 0x31, 0x4b, 0x0d, 0x01, 0xcb, 0xde, 0xa8, - 0xf6, 0x6d, 0x7c, 0x39, 0x46, 0x4e, 0x7e, 0x3f, - 0x94, 0x17, 0xdf, 0xa1, 0x7d, 0xd9, 0x1c, 0x8e, - 0xbc, 0x7d, 0x33, 0x7d, 0xe3, 0x12, 0x40, 0xca, - 0xab, 0x37, 0x11, 0x46, 0xd4, 0xae, 0xef, 0x44, - 0xa2, 0xb3, 0x6a, 0x66, 0x0e, 0x0c, 0x90, 0x7f, - 0xdf, 0x5c, 0x66, 0x5f, 0xf2, 0x94, 0x9f, 0xa6, - 0x73, 0x4f, 0xeb, 0x0d, 0xad, 0xbf, 0xc0, 0x63, - 0x5c, 0xdc, 0x46, 0x51, 0xe8, 0x8e, 0x90, 0x19, - 0xa8, 0xa4, 0x3c, 0x91, 0x79, 0xfa, 0x7e, 0x58, - 0x85, 0x13, 0x55, 0xc5, 0x19, 0x82, 0x37, 0x1b, - 0x0a, 0x02, 0x1f, 0x99, 0x6b, 0x18, 0xf1, 0x28, - 0x08, 0xa2, 0x73, 0xb8, 0x0f, 0x2e, 0xcd, 0xbf, - 0xf3, 0x86, 0x7f, 0xea, 0xef, 0xd0, 0xbb, 0xa6, - 0x21, 0xdf, 0x49, 0x73, 0x51, 0xcc, 0x36, 0xd3, - 0x3e, 0xa0, 0xf8, 0x44, 0xdf, 0xd3, 0xa6, 0xbe, - 0x8a, 0xd4, 0x57, 0xdd, 0x72, 0x94, 0x61, 0x0f, - 0x82, 0xd1, 0x07, 0xb8, 0x7c, 0x18, 0x83, 0xdf, - 0x3a, 0xe5, 0x50, 0x6a, 0x82, 0x20, 0xac, 0xa9, - 0xa8, 0xff, 0xd9, 0xf3, 0x77, 0x33, 0x5a, 0x9e, - 0x7f, 0x6d, 0xfe, 0x5d, 0x33, 0x41, 0x42, 0xe7, - 0x6c, 0x19, 0xe0, 0x44, 0x8a, 0x15, 0xf6, 0x70, - 0x98, 0xb7, 0x68, 0x4d, 0xfa, 0x97, 0x39, 0xb0, - 0x8e, 0xe8, 0x84, 0x8b, 0x75, 0x30, 0xb7, 0x7d, - 0x92, 0x69, 0x20, 0x9c, 0x81, 0xfb, 0x4b, 0xf4, - 0x01, 0x50, 0xeb, 0xce, 0x0c, 0x1c, 0x6c, 0xb5, - 0x4a, 0xd7, 0x27, 0x0c, 0xce, 0xbb, 0xe5, 0x85, - 0xf0, 0xb6, 0xee, 0xd5, 0x70, 0xdd, 0x3b, 0xfc, - 0xd4, 0x99, 0xf1, 0x33, 0xdd, 0x8b, 0xc4, 0x2f, - 0xae, 0xab, 0x74, 0x96, 0x32, 0xc7, 0x4c, 0x56, - 0x3c, 0x89, 0x0f, 0x96, 0x0b, 0x42, 0xc0, 0xcb, - 0xee, 0x0f, 0x0b, 0x8c, 0xfb, 0x7e, 0x47, 0x7b, - 0x64, 0x48, 0xfd, 0xb2, 0x00, 0x80, 0x89, 0xa5, - 0x13, 0x55, 0x62, 0xfc, 0x8f, 0xe2, 0x42, 0x03, - 0xb7, 0x4e, 0x2a, 0x79, 0xb4, 0x82, 0xea, 0x23, - 0x49, 0xda, 0xaf, 0x52, 0x63, 0x1e, 0x60, 0x03, - 0x89, 0x06, 0x44, 0x46, 0x08, 0xc3, 0xc4, 0x87, - 0x70, 0x2e, 0xda, 0x94, 0xad, 0x6b, 0xe0, 0xe4, - 0xd1, 0x8a, 0x06, 0xc2, 0xa8, 0xc0, 0xa7, 0x43, - 0x3c, 0x47, 0x52, 0x0e, 0xc3, 0x77, 0x81, 0x11, - 0x67, 0x0e, 0xa0, 0x70, 0x04, 0x47, 0x29, 0x40, - 0x86, 0x0d, 0x34, 0x56, 0xa7, 0xc9, 0x35, 0x59, - 0x68, 0xdc, 0x93, 0x81, 0x70, 0xee, 0x86, 0xd9, - 0x80, 0x06, 0x40, 0x4f, 0x1a, 0x0d, 0x40, 0x30, - 0x0b, 0xcb, 0x96, 0x47, 0xc1, 0xb7, 0x52, 0xfd, - 0x56, 0xe0, 0x72, 0x4b, 0xfb, 0xbd, 0x92, 0x45, - 0x61, 0x71, 0xc2, 0x33, 0x11, 0xbf, 0x52, 0x83, - 0x79, 0x26, 0xe0, 0x49, 0x6b, 0xb7, 0x05, 0x8b, - 0xe8, 0x0e, 0x87, 0x31, 0xd7, 0x9d, 0x8a, 0xf5, - 0xc0, 0x5f, 0x2e, 0x58, 0x4a, 0xdb, 0x11, 0xb3, - 0x6c, 0x30, 0x2a, 0x46, 0x19, 0xe3, 0x27, 0x84, - 0x1f, 0x63, 0x6e, 0xf6, 0x57, 0xc7, 0xc9, 0xd8, - 0x5e, 0xba, 0xb3, 0x87, 0xd5, 0x83, 0x26, 0x34, - 0x21, 0x9e, 0x65, 0xde, 0x42, 0xd3, 0xbe, 0x7b, - 0xbc, 0x91, 0x71, 0x44, 0x4d, 0x99, 0x3b, 0x31, - 0xe5, 0x3f, 0x11, 0x4e, 0x7f, 0x13, 0x51, 0x3b, - 0xae, 0x79, 0xc9, 0xd3, 0x81, 0x8e, 0x25, 0x40, - 0x10, 0xfc, 0x07, 0x1e, 0xf9, 0x7b, 0x9a, 0x4b, - 0x6c, 0xe3, 0xb3, 0xad, 0x1a, 0x0a, 0xdd, 0x9e, - 0x59, 0x0c, 0xa2, 0xcd, 0xae, 0x48, 0x4a, 0x38, - 0x5b, 0x47, 0x41, 0x94, 0x65, 0x6b, 0xbb, 0xeb, - 0x5b, 0xe3, 0xaf, 0x07, 0x5b, 0xd4, 0x4a, 0xa2, - 0xc9, 0x5d, 0x2f, 0x64, 0x03, 0xd7, 0x3a, 0x2c, - 0x6e, 0xce, 0x76, 0x95, 0xb4, 0xb3, 0xc0, 0xf1, - 0xe2, 0x45, 0x73, 0x7a, 0x5c, 0xab, 0xc1, 0xfc, - 0x02, 0x8d, 0x81, 0x29, 0xb3, 0xac, 0x07, 0xec, - 0x40, 0x7d, 0x45, 0xd9, 0x7a, 0x59, 0xee, 0x34, - 0xf0, 0xe9, 0xd5, 0x7b, 0x96, 0xb1, 0x3d, 0x95, - 0xcc, 0x86, 0xb5, 0xb6, 0x04, 0x2d, 0xb5, 0x92, - 0x7e, 0x76, 0xf4, 0x06, 0xa9, 0xa3, 0x12, 0x0f, - 0xb1, 0xaf, 0x26, 0xba, 0x7c, 0xfc, 0x7e, 0x1c, - 0xbc, 0x2c, 0x49, 0x97, 0x53, 0x60, 0x13, 0x0b, - 0xa6, 0x61, 0x83, 0x89, 0x42, 0xd4, 0x17, 0x0c, - 0x6c, 0x26, 0x52, 0xc3, 0xb3, 0xd4, 0x67, 0xf5, - 0xe3, 0x04, 0xb7, 0xf4, 0xcb, 0x80, 0xb8, 0xcb, - 0x77, 0x56, 0x3e, 0xaa, 0x57, 0x54, 0xee, 0xb4, - 0x2c, 0x67, 0xcf, 0xf2, 0xdc, 0xbe, 0x55, 0xf9, - 0x43, 0x1f, 0x6e, 0x22, 0x97, 0x67, 0x7f, 0xc4, - 0xef, 0xb1, 0x26, 0x31, 0x1e, 0x27, 0xdf, 0x41, - 0x80, 0x47, 0x6c, 0xe2, 0xfa, 0xa9, 0x8c, 0x2a, - 0xf6, 0xf2, 0xab, 0xf0, 0x15, 0xda, 0x6c, 0xc8, - 0xfe, 0xb5, 0x23, 0xde, 0xa9, 0x05, 0x3f, 0x06, - 0x54, 0x4c, 0xcd, 0xe1, 0xab, 0xfc, 0x0e, 0x62, - 0x33, 0x31, 0x73, 0x2c, 0x76, 0xcb, 0xb4, 0x47, - 0x1e, 0x20, 0xad, 0xd8, 0xf2, 0x31, 0xdd, 0xc4, - 0x8b, 0x0c, 0x77, 0xbe, 0xe1, 0x8b, 0x26, 0x00, - 0x02, 0x58, 0xd6, 0x8d, 0xef, 0xad, 0x74, 0x67, - 0xab, 0x3f, 0xef, 0xcb, 0x6f, 0xb0, 0xcc, 0x81, - 0x44, 0x4c, 0xaf, 0xe9, 0x49, 0x4f, 0xdb, 0xa0, - 0x25, 0xa4, 0xf0, 0x89, 0xf1, 0xbe, 0xd8, 0x10, - 0xff, 0xb1, 0x3b, 0x4b, 0xfa, 0x98, 0xf5, 0x79, - 0x6d, 0x1e, 0x69, 0x4d, 0x57, 0xb1, 0xc8, 0x19, - 0x1b, 0xbd, 0x1e, 0x8c, 0x84, 0xb7, 0x7b, 0xe8, - 0xd2, 0x2d, 0x09, 0x41, 0x41, 0x37, 0x3d, 0xb1, - 0x6f, 0x26, 0x5d, 0x71, 0x16, 0x3d, 0xb7, 0x83, - 0x27, 0x2c, 0xa7, 0xb6, 0x50, 0xbd, 0x91, 0x86, - 0xab, 0x24, 0xa1, 0x38, 0xfd, 0xea, 0x71, 0x55, - 0x7e, 0x9a, 0x07, 0x77, 0x4b, 0xfa, 0x61, 0x66, - 0x20, 0x1e, 0x28, 0x95, 0x18, 0x1b, 0xa4, 0xa0, - 0xfd, 0xc0, 0x89, 0x72, 0x43, 0xd9, 0x3b, 0x49, - 0x5a, 0x3f, 0x9d, 0xbf, 0xdb, 0xb4, 0x46, 0xea, - 0x42, 0x01, 0x77, 0x23, 0x68, 0x95, 0xb6, 0x24, - 0xb3, 0xa8, 0x6c, 0x28, 0x3b, 0x11, 0x40, 0x7e, - 0x18, 0x65, 0x6d, 0xd8, 0x24, 0x42, 0x7d, 0x88, - 0xc0, 0x52, 0xd9, 0x05, 0xe4, 0x95, 0x90, 0x87, - 0x8c, 0xf4, 0xd0, 0x6b, 0xb9, 0x83, 0x99, 0x34, - 0x6d, 0xfe, 0x54, 0x40, 0x94, 0x52, 0x21, 0x4f, - 0x14, 0x25, 0xc5, 0xd6, 0x5e, 0x95, 0xdc, 0x0a, - 0x2b, 0x89, 0x20, 0x11, 0x84, 0x48, 0xd6, 0x3a, - 0xcd, 0x5c, 0x24, 0xad, 0x62, 0xe3, 0xb1, 0x93, - 0x25, 0x8d, 0xcd, 0x7e, 0xfc, 0x27, 0xa3, 0x37, - 0xfd, 0x84, 0xfc, 0x1b, 0xb2, 0xf1, 0x27, 0x38, - 0x5a, 0xb7, 0xfc, 0xf2, 0xfa, 0x95, 0x66, 0xd4, - 0xfb, 0xba, 0xa7, 0xd7, 0xa3, 0x72, 0x69, 0x48, - 0x48, 0x8c, 0xeb, 0x28, 0x89, 0xfe, 0x33, 0x65, - 0x5a, 0x36, 0x01, 0x7e, 0x06, 0x79, 0x0a, 0x09, - 0x3b, 0x74, 0x11, 0x9a, 0x6e, 0xbf, 0xd4, 0x9e, - 0x58, 0x90, 0x49, 0x4f, 0x4d, 0x08, 0xd4, 0xe5, - 0x4a, 0x09, 0x21, 0xef, 0x8b, 0xb8, 0x74, 0x3b, - 0x91, 0xdd, 0x36, 0x85, 0x60, 0x2d, 0xfa, 0xd4, - 0x45, 0x7b, 0x45, 0x53, 0xf5, 0x47, 0x87, 0x7e, - 0xa6, 0x37, 0xc8, 0x78, 0x7a, 0x68, 0x9d, 0x8d, - 0x65, 0x2c, 0x0e, 0x91, 0x5c, 0xa2, 0x60, 0xf0, - 0x8e, 0x3f, 0xe9, 0x1a, 0xcd, 0xaa, 0xe7, 0xd5, - 0x77, 0x18, 0xaf, 0xc9, 0xbc, 0x18, 0xea, 0x48, - 0x1b, 0xfb, 0x22, 0x48, 0x70, 0x16, 0x29, 0x9e, - 0x5b, 0xc1, 0x2c, 0x66, 0x23, 0xbc, 0xf0, 0x1f, - 0xef, 0xaf, 0xe4, 0xd6, 0x04, 0x19, 0x82, 0x7a, - 0x0b, 0xba, 0x4b, 0x46, 0xb1, 0x6a, 0x85, 0x5d, - 0xb4, 0x73, 0xd6, 0x21, 0xa1, 0x71, 0x60, 0x14, - 0xee, 0x0a, 0x77, 0xc4, 0x66, 0x2e, 0xf9, 0x69, - 0x30, 0xaf, 0x41, 0x0b, 0xc8, 0x83, 0x3c, 0x53, - 0x99, 0x19, 0x27, 0x46, 0xf7, 0x41, 0x6e, 0x56, - 0xdc, 0x94, 0x28, 0x67, 0x4e, 0xb7, 0x25, 0x48, - 0x8a, 0xc2, 0xe0, 0x60, 0x96, 0xcc, 0x18, 0xf4, - 0x84, 0xdd, 0xa7, 0x5e, 0x3e, 0x05, 0x0b, 0x26, - 0x26, 0xb2, 0x5c, 0x1f, 0x57, 0x1a, 0x04, 0x7e, - 0x6a, 0xe3, 0x2f, 0xb4, 0x35, 0xb6, 0x38, 0x40, - 0x40, 0xcd, 0x6f, 0x87, 0x2e, 0xef, 0xa3, 0xd7, - 0xa9, 0xc2, 0xe8, 0x0d, 0x27, 0xdf, 0x44, 0x62, - 0x99, 0xa0, 0xfc, 0xcf, 0x81, 0x78, 0xcb, 0xfe, - 0xe5, 0xa0, 0x03, 0x4e, 0x6c, 0xd7, 0xf4, 0xaf, - 0x7a, 0xbb, 0x61, 0x82, 0xfe, 0x71, 0x89, 0xb2, - 0x22, 0x7c, 0x8e, 0x83, 0x04, 0xce, 0xf6, 0x5d, - 0x84, 0x8f, 0x95, 0x6a, 0x7f, 0xad, 0xfd, 0x32, - 0x9c, 0x5e, 0xe4, 0x9c, 0x89, 0x60, 0x54, 0xaa, - 0x96, 0x72, 0xd2, 0xd7, 0x36, 0x85, 0xa9, 0x45, - 0xd2, 0x2a, 0xa1, 0x81, 0x49, 0x6f, 0x7e, 0x04, - 0xfa, 0xe2, 0xfe, 0x90, 0x26, 0x77, 0x5a, 0x33, - 0xb8, 0x04, 0x9a, 0x7a, 0xe6, 0x4c, 0x4f, 0xad, - 0x72, 0x96, 0x08, 0x28, 0x58, 0x13, 0xf8, 0xc4, - 0x1c, 0xf0, 0xc3, 0x45, 0x95, 0x49, 0x20, 0x8c, - 0x9f, 0x39, 0x70, 0xe1, 0x77, 0xfe, 0xd5, 0x4b, - 0xaf, 0x86, 0xda, 0xef, 0x22, 0x06, 0x83, 0x36, - 0x29, 0x12, 0x11, 0x40, 0xbc, 0x3b, 0x86, 0xaa, - 0xaa, 0x65, 0x60, 0xc3, 0x80, 0xca, 0xed, 0xa9, - 0xf3, 0xb0, 0x79, 0x96, 0xa2, 0x55, 0x27, 0x28, - 0x55, 0x73, 0x26, 0xa5, 0x50, 0xea, 0x92, 0x4b, - 0x3c, 0x5c, 0x82, 0x33, 0xf0, 0x01, 0x3f, 0x03, - 0xc1, 0x08, 0x05, 0xbf, 0x98, 0xf4, 0x9b, 0x6d, - 0xa5, 0xa8, 0xb4, 0x82, 0x0c, 0x06, 0xfa, 0xff, - 0x2d, 0x08, 0xf3, 0x05, 0x4f, 0x57, 0x2a, 0x39, - 0xd4, 0x83, 0x0d, 0x75, 0x51, 0xd8, 0x5b, 0x1b, - 0xd3, 0x51, 0x5a, 0x32, 0x2a, 0x9b, 0x32, 0xb2, - 0xf2, 0xa4, 0x96, 0x12, 0xf2, 0xae, 0x40, 0x34, - 0x67, 0xa8, 0xf5, 0x44, 0xd5, 0x35, 0x53, 0xfe, - 0xa3, 0x60, 0x96, 0x63, 0x0f, 0x1f, 0x6e, 0xb0, - 0x5a, 0x42, 0xa6, 0xfc, 0x51, 0x0b, 0x60, 0x27, - 0xbc, 0x06, 0x71, 0xed, 0x65, 0x5b, 0x23, 0x86, - 0x4a, 0x07, 0x3b, 0x22, 0x07, 0x46, 0xe6, 0x90, - 0x3e, 0xf3, 0x25, 0x50, 0x1b, 0x4c, 0x7f, 0x03, - 0x08, 0xa8, 0x36, 0x6b, 0x87, 0xe5, 0xe3, 0xdb, - 0x9a, 0x38, 0x83, 0xff, 0x9f, 0x1a, 0x9f, 0x57, - 0xa4, 0x2a, 0xf6, 0x37, 0xbc, 0x1a, 0xff, 0xc9, - 0x1e, 0x35, 0x0c, 0xc3, 0x7c, 0xa3, 0xb2, 0xe5, - 0xd2, 0xc6, 0xb4, 0x57, 0x47, 0xe4, 0x32, 0x16, - 0x6d, 0xa9, 0xae, 0x64, 0xe6, 0x2d, 0x8d, 0xc5, - 0x8d, 0x50, 0x8e, 0xe8, 0x1a, 0x22, 0x34, 0x2a, - 0xd9, 0xeb, 0x51, 0x90, 0x4a, 0xb1, 0x41, 0x7d, - 0x64, 0xf9, 0xb9, 0x0d, 0xf6, 0x23, 0x33, 0xb0, - 0x33, 0xf4, 0xf7, 0x3f, 0x27, 0x84, 0xc6, 0x0f, - 0x54, 0xa5, 0xc0, 0x2e, 0xec, 0x0b, 0x3a, 0x48, - 0x6e, 0x80, 0x35, 0x81, 0x43, 0x9b, 0x90, 0xb1, - 0xd0, 0x2b, 0xea, 0x21, 0xdc, 0xda, 0x5b, 0x09, - 0xf4, 0xcc, 0x10, 0xb4, 0xc7, 0xfe, 0x79, 0x51, - 0xc3, 0xc5, 0xac, 0x88, 0x74, 0x84, 0x0b, 0x4b, - 0xca, 0x79, 0x16, 0x29, 0xfb, 0x69, 0x54, 0xdf, - 0x41, 0x7e, 0xe9, 0xc7, 0x8e, 0xea, 0xa5, 0xfe, - 0xfc, 0x76, 0x0e, 0x90, 0xc4, 0x92, 0x38, 0xad, - 0x7b, 0x48, 0xe6, 0x6e, 0xf7, 0x21, 0xfd, 0x4e, - 0x93, 0x0a, 0x7b, 0x41, 0x83, 0x68, 0xfb, 0x57, - 0x51, 0x76, 0x34, 0xa9, 0x6c, 0x00, 0xaa, 0x4f, - 0x66, 0x65, 0x98, 0x4a, 0x4f, 0xa3, 0xa0, 0xef, - 0x69, 0x3f, 0xe3, 0x1c, 0x92, 0x8c, 0xfd, 0xd8, - 0xe8, 0xde, 0x7c, 0x7f, 0x3e, 0x84, 0x8e, 0x69, - 0x3c, 0xf1, 0xf2, 0x05, 0x46, 0xdc, 0x2f, 0x9d, - 0x5e, 0x6e, 0x4c, 0xfb, 0xb5, 0x99, 0x2a, 0x59, - 0x63, 0xc1, 0x34, 0xbc, 0x57, 0xc0, 0x0d, 0xb9, - 0x61, 0x25, 0xf3, 0x33, 0x23, 0x51, 0xb6, 0x0d, - 0x07, 0xa6, 0xab, 0x94, 0x4a, 0xb7, 0x2a, 0xea, - 0xee, 0xac, 0xa3, 0xc3, 0x04, 0x8b, 0x0e, 0x56, - 0xfe, 0x44, 0xa7, 0x39, 0xe2, 0xed, 0xed, 0xb4, - 0x22, 0x2b, 0xac, 0x12, 0x32, 0x28, 0x91, 0xd8, - 0xa5, 0xab, 0xff, 0x5f, 0xe0, 0x4b, 0xda, 0x78, - 0x17, 0xda, 0xf1, 0x01, 0x5b, 0xcd, 0xe2, 0x5f, - 0x50, 0x45, 0x73, 0x2b, 0xe4, 0x76, 0x77, 0xf4, - 0x64, 0x1d, 0x43, 0xfb, 0x84, 0x7a, 0xea, 0x91, - 0xae, 0xf9, 0x9e, 0xb7, 0xb4, 0xb0, 0x91, 0x5f, - 0x16, 0x35, 0x9a, 0x11, 0xb8, 0xc7, 0xc1, 0x8c, - 0xc6, 0x10, 0x8d, 0x2f, 0x63, 0x4a, 0xa7, 0x57, - 0x3a, 0x51, 0xd6, 0x32, 0x2d, 0x64, 0x72, 0xd4, - 0x66, 0xdc, 0x10, 0xa6, 0x67, 0xd6, 0x04, 0x23, - 0x9d, 0x0a, 0x11, 0x77, 0xdd, 0x37, 0x94, 0x17, - 0x3c, 0xbf, 0x8b, 0x65, 0xb0, 0x2e, 0x5e, 0x66, - 0x47, 0x64, 0xac, 0xdd, 0xf0, 0x84, 0xfd, 0x39, - 0xfa, 0x15, 0x5d, 0xef, 0xae, 0xca, 0xc1, 0x36, - 0xa7, 0x5c, 0xbf, 0xc7, 0x08, 0xc2, 0x66, 0x00, - 0x74, 0x74, 0x4e, 0x27, 0x3f, 0x55, 0x8a, 0xb7, - 0x38, 0x66, 0x83, 0x6d, 0xcf, 0x99, 0x9e, 0x60, - 0x8f, 0xdd, 0x2e, 0x62, 0x22, 0x0e, 0xef, 0x0c, - 0x98, 0xa7, 0x85, 0x74, 0x3b, 0x9d, 0xec, 0x9e, - 0xa9, 0x19, 0x72, 0xa5, 0x7f, 0x2c, 0x39, 0xb7, - 0x7d, 0xb7, 0xf1, 0x12, 0x65, 0x27, 0x4b, 0x5a, - 0xde, 0x17, 0xfe, 0xad, 0x44, 0xf3, 0x20, 0x4d, - 0xfd, 0xe4, 0x1f, 0xb5, 0x81, 0xb0, 0x36, 0x37, - 0x08, 0x6f, 0xc3, 0x0c, 0xe9, 0x85, 0x98, 0x82, - 0xa9, 0x62, 0x0c, 0xc4, 0x97, 0xc0, 0x50, 0xc8, - 0xa7, 0x3c, 0x50, 0x9f, 0x43, 0xb9, 0xcd, 0x5e, - 0x4d, 0xfa, 0x1c, 0x4b, 0x0b, 0xa9, 0x98, 0x85, - 0x38, 0x92, 0xac, 0x8d, 0xe4, 0xad, 0x9b, 0x98, - 0xab, 0xd9, 0x38, 0xac, 0x62, 0x52, 0xa3, 0x22, - 0x63, 0x0f, 0xbf, 0x95, 0x48, 0xdf, 0x69, 0xe7, - 0x8b, 0x33, 0xd5, 0xb2, 0xbd, 0x05, 0x49, 0x49, - 0x9d, 0x57, 0x73, 0x19, 0x33, 0xae, 0xfa, 0x33, - 0xf1, 0x19, 0xa8, 0x80, 0xce, 0x04, 0x9f, 0xbc, - 0x1d, 0x65, 0x82, 0x1b, 0xe5, 0x3a, 0x51, 0xc8, - 0x1c, 0x21, 0xe3, 0x5d, 0xf3, 0x7d, 0x9b, 0x2f, - 0x2c, 0x1d, 0x4a, 0x7f, 0x9b, 0x68, 0x35, 0xa3, - 0xb2, 0x50, 0xf7, 0x62, 0x79, 0xcd, 0xf4, 0x98, - 0x4f, 0xe5, 0x63, 0x7c, 0x3e, 0x45, 0x31, 0x8c, - 0x16, 0xa0, 0x12, 0xc8, 0x58, 0xce, 0x39, 0xa6, - 0xbc, 0x54, 0xdb, 0xc5, 0xe0, 0xd5, 0xba, 0xbc, - 0xb9, 0x04, 0xf4, 0x8d, 0xe8, 0x2f, 0x15, 0x9d, -}; - -/* 100 test cases */ -static struct crc_test { - u32 crc; /* random starting crc */ - u32 start; /* random 6 bit offset in buf */ - u32 length; /* random 11 bit length of test */ - u32 crc_le; /* expected crc32_le result */ - u32 crc_be; /* expected crc32_be result */ - u32 crc32c_le; /* expected crc32c_le result */ -} const test[] __initconst = -{ - {0x674bf11d, 0x00000038, 0x00000542, 0x0af6d466, 0xd8b6e4c1, 0xf6e93d6c}, - {0x35c672c6, 0x0000003a, 0x000001aa, 0xc6d3dfba, 0x28aaf3ad, 0x0fe92aca}, - {0x496da28e, 0x00000039, 0x000005af, 0xd933660f, 0x5d57e81f, 0x52e1ebb8}, - {0x09a9b90e, 0x00000027, 0x000001f8, 0xb45fe007, 0xf45fca9a, 0x0798af9a}, - {0xdc97e5a9, 0x00000025, 0x000003b6, 0xf81a3562, 0xe0126ba2, 0x18eb3152}, - {0x47c58900, 0x0000000a, 0x000000b9, 0x8e58eccf, 0xf3afc793, 0xd00d08c7}, - {0x292561e8, 0x0000000c, 0x00000403, 0xa2ba8aaf, 0x0b797aed, 0x8ba966bc}, - {0x415037f6, 0x00000003, 0x00000676, 0xa17d52e8, 0x7f0fdf35, 0x11d694a2}, - {0x3466e707, 0x00000026, 0x00000042, 0x258319be, 0x75c484a2, 0x6ab3208d}, - {0xafd1281b, 0x00000023, 0x000002ee, 0x4428eaf8, 0x06c7ad10, 0xba4603c5}, - {0xd3857b18, 0x00000028, 0x000004a2, 0x5c430821, 0xb062b7cb, 0xe6071c6f}, - {0x1d825a8f, 0x0000002b, 0x0000050b, 0xd2c45f0c, 0xd68634e0, 0x179ec30a}, - {0x5033e3bc, 0x0000000b, 0x00000078, 0xa3ea4113, 0xac6d31fb, 0x0903beb8}, - {0x94f1fb5e, 0x0000000f, 0x000003a2, 0xfbfc50b1, 0x3cfe50ed, 0x6a7cb4fa}, - {0xc9a0fe14, 0x00000009, 0x00000473, 0x5fb61894, 0x87070591, 0xdb535801}, - {0x88a034b1, 0x0000001c, 0x000005ad, 0xc1b16053, 0x46f95c67, 0x92bed597}, - {0xf0f72239, 0x00000020, 0x0000026d, 0xa6fa58f3, 0xf8c2c1dd, 0x192a3f1b}, - {0xcc20a5e3, 0x0000003b, 0x0000067a, 0x7740185a, 0x308b979a, 0xccbaec1a}, - {0xce589c95, 0x0000002b, 0x00000641, 0xd055e987, 0x40aae25b, 0x7eabae4d}, - {0x78edc885, 0x00000035, 0x000005be, 0xa39cb14b, 0x035b0d1f, 0x28c72982}, - {0x9d40a377, 0x0000003b, 0x00000038, 0x1f47ccd2, 0x197fbc9d, 0xc3cd4d18}, - {0x703d0e01, 0x0000003c, 0x000006f1, 0x88735e7c, 0xfed57c5a, 0xbca8f0e7}, - {0x776bf505, 0x0000000f, 0x000005b2, 0x5cc4fc01, 0xf32efb97, 0x713f60b3}, - {0x4a3e7854, 0x00000027, 0x000004b8, 0x8d923c82, 0x0cbfb4a2, 0xebd08fd5}, - {0x209172dd, 0x0000003b, 0x00000356, 0xb89e9c2b, 0xd7868138, 0x64406c59}, - {0x3ba4cc5b, 0x0000002f, 0x00000203, 0xe51601a9, 0x5b2a1032, 0x7421890e}, - {0xfc62f297, 0x00000000, 0x00000079, 0x71a8e1a2, 0x5d88685f, 0xe9347603}, - {0x64280b8b, 0x00000016, 0x000007ab, 0x0fa7a30c, 0xda3a455f, 0x1bef9060}, - {0x97dd724b, 0x00000033, 0x000007ad, 0x5788b2f4, 0xd7326d32, 0x34720072}, - {0x61394b52, 0x00000035, 0x00000571, 0xc66525f1, 0xcabe7fef, 0x48310f59}, - {0x29b4faff, 0x00000024, 0x0000006e, 0xca13751e, 0x993648e0, 0x783a4213}, - {0x29bfb1dc, 0x0000000b, 0x00000244, 0x436c43f7, 0x429f7a59, 0x9e8efd41}, - {0x86ae934b, 0x00000035, 0x00000104, 0x0760ec93, 0x9cf7d0f4, 0xfc3d34a5}, - {0xc4c1024e, 0x0000002e, 0x000006b1, 0x6516a3ec, 0x19321f9c, 0x17a52ae2}, - {0x3287a80a, 0x00000026, 0x00000496, 0x0b257eb1, 0x754ebd51, 0x886d935a}, - {0xa4db423e, 0x00000023, 0x0000045d, 0x9b3a66dc, 0x873e9f11, 0xeaaeaeb2}, - {0x7a1078df, 0x00000015, 0x0000014a, 0x8c2484c5, 0x6a628659, 0x8e900a4b}, - {0x6048bd5b, 0x00000006, 0x0000006a, 0x897e3559, 0xac9961af, 0xd74662b1}, - {0xd8f9ea20, 0x0000003d, 0x00000277, 0x60eb905b, 0xed2aaf99, 0xd26752ba}, - {0xea5ec3b4, 0x0000002a, 0x000004fe, 0x869965dc, 0x6c1f833b, 0x8b1fcd62}, - {0x2dfb005d, 0x00000016, 0x00000345, 0x6a3b117e, 0xf05e8521, 0xf54342fe}, - {0x5a214ade, 0x00000020, 0x000005b6, 0x467f70be, 0xcb22ccd3, 0x5b95b988}, - {0xf0ab9cca, 0x00000032, 0x00000515, 0xed223df3, 0x7f3ef01d, 0x2e1176be}, - {0x91b444f9, 0x0000002e, 0x000007f8, 0x84e9a983, 0x5676756f, 0x66120546}, - {0x1b5d2ddb, 0x0000002e, 0x0000012c, 0xba638c4c, 0x3f42047b, 0xf256a5cc}, - {0xd824d1bb, 0x0000003a, 0x000007b5, 0x6288653b, 0x3a3ebea0, 0x4af1dd69}, - {0x0470180c, 0x00000034, 0x000001f0, 0x9d5b80d6, 0x3de08195, 0x56f0a04a}, - {0xffaa3a3f, 0x00000036, 0x00000299, 0xf3a82ab8, 0x53e0c13d, 0x74f6b6b2}, - {0x6406cfeb, 0x00000023, 0x00000600, 0xa920b8e8, 0xe4e2acf4, 0x085951fd}, - {0xb24aaa38, 0x0000003e, 0x000004a1, 0x657cc328, 0x5077b2c3, 0xc65387eb}, - {0x58b2ab7c, 0x00000039, 0x000002b4, 0x3a17ee7e, 0x9dcb3643, 0x1ca9257b}, - {0x3db85970, 0x00000006, 0x000002b6, 0x95268b59, 0xb9812c10, 0xfd196d76}, - {0x857830c5, 0x00000003, 0x00000590, 0x4ef439d5, 0xf042161d, 0x5ef88339}, - {0xe1fcd978, 0x0000003e, 0x000007d8, 0xae8d8699, 0xce0a1ef5, 0x2c3714d9}, - {0xb982a768, 0x00000016, 0x000006e0, 0x62fad3df, 0x5f8a067b, 0x58576548}, - {0x1d581ce8, 0x0000001e, 0x0000058b, 0xf0f5da53, 0x26e39eee, 0xfd7c57de}, - {0x2456719b, 0x00000025, 0x00000503, 0x4296ac64, 0xd50e4c14, 0xd5fedd59}, - {0xfae6d8f2, 0x00000000, 0x0000055d, 0x057fdf2e, 0x2a31391a, 0x1cc3b17b}, - {0xcba828e3, 0x00000039, 0x000002ce, 0xe3f22351, 0x8f00877b, 0x270eed73}, - {0x13d25952, 0x0000000a, 0x0000072d, 0x76d4b4cc, 0x5eb67ec3, 0x91ecbb11}, - {0x0342be3f, 0x00000015, 0x00000599, 0xec75d9f1, 0x9d4d2826, 0x05ed8d0c}, - {0xeaa344e0, 0x00000014, 0x000004d8, 0x72a4c981, 0x2064ea06, 0x0b09ad5b}, - {0xbbb52021, 0x0000003b, 0x00000272, 0x04af99fc, 0xaf042d35, 0xf8d511fb}, - {0xb66384dc, 0x0000001d, 0x000007fc, 0xd7629116, 0x782bd801, 0x5ad832cc}, - {0x616c01b6, 0x00000022, 0x000002c8, 0x5b1dab30, 0x783ce7d2, 0x1214d196}, - {0xce2bdaad, 0x00000016, 0x0000062a, 0x932535c8, 0x3f02926d, 0x5747218a}, - {0x00fe84d7, 0x00000005, 0x00000205, 0x850e50aa, 0x753d649c, 0xde8f14de}, - {0xbebdcb4c, 0x00000006, 0x0000055d, 0xbeaa37a2, 0x2d8c9eba, 0x3563b7b9}, - {0xd8b1a02a, 0x00000010, 0x00000387, 0x5017d2fc, 0x503541a5, 0x071475d0}, - {0x3b96cad2, 0x00000036, 0x00000347, 0x1d2372ae, 0x926cd90b, 0x54c79d60}, - {0xc94c1ed7, 0x00000005, 0x0000038b, 0x9e9fdb22, 0x144a9178, 0x4c53eee6}, - {0x1aad454e, 0x00000025, 0x000002b2, 0xc3f6315c, 0x5c7a35b3, 0x10137a3c}, - {0xa4fec9a6, 0x00000000, 0x000006d6, 0x90be5080, 0xa4107605, 0xaa9d6c73}, - {0x1bbe71e2, 0x0000001f, 0x000002fd, 0x4e504c3b, 0x284ccaf1, 0xb63d23e7}, - {0x4201c7e4, 0x00000002, 0x000002b7, 0x7822e3f9, 0x0cc912a9, 0x7f53e9cf}, - {0x23fddc96, 0x00000003, 0x00000627, 0x8a385125, 0x07767e78, 0x13c1cd83}, - {0xd82ba25c, 0x00000016, 0x0000063e, 0x98e4148a, 0x283330c9, 0x49ff5867}, - {0x786f2032, 0x0000002d, 0x0000060f, 0xf201600a, 0xf561bfcd, 0x8467f211}, - {0xfebe4e1f, 0x0000002a, 0x000004f2, 0x95e51961, 0xfd80dcab, 0x3f9683b2}, - {0x1a6e0a39, 0x00000008, 0x00000672, 0x8af6c2a5, 0x78dd84cb, 0x76a3f874}, - {0x56000ab8, 0x0000000e, 0x000000e5, 0x36bacb8f, 0x22ee1f77, 0x863b702f}, - {0x4717fe0c, 0x00000000, 0x000006ec, 0x8439f342, 0x5c8e03da, 0xdc6c58ff}, - {0xd5d5d68e, 0x0000003c, 0x000003a3, 0x46fff083, 0x177d1b39, 0x0622cc95}, - {0xc25dd6c6, 0x00000024, 0x000006c0, 0x5ceb8eb4, 0x892b0d16, 0xe85605cd}, - {0xe9b11300, 0x00000023, 0x00000683, 0x07a5d59a, 0x6c6a3208, 0x31da5f06}, - {0x95cd285e, 0x00000001, 0x00000047, 0x7b3a4368, 0x0202c07e, 0xa1f2e784}, - {0xd9245a25, 0x0000001e, 0x000003a6, 0xd33c1841, 0x1936c0d5, 0xb07cc616}, - {0x103279db, 0x00000006, 0x0000039b, 0xca09b8a0, 0x77d62892, 0xbf943b6c}, - {0x1cba3172, 0x00000027, 0x000001c8, 0xcb377194, 0xebe682db, 0x2c01af1c}, - {0x8f613739, 0x0000000c, 0x000001df, 0xb4b0bc87, 0x7710bd43, 0x0fe5f56d}, - {0x1c6aa90d, 0x0000001b, 0x0000053c, 0x70559245, 0xda7894ac, 0xf8943b2d}, - {0xaabe5b93, 0x0000003d, 0x00000715, 0xcdbf42fa, 0x0c3b99e7, 0xe4d89272}, - {0xf15dd038, 0x00000006, 0x000006db, 0x6e104aea, 0x8d5967f2, 0x7c2f6bbb}, - {0x584dd49c, 0x00000020, 0x000007bc, 0x36b6cfd6, 0xad4e23b2, 0xabbf388b}, - {0x5d8c9506, 0x00000020, 0x00000470, 0x4c62378e, 0x31d92640, 0x1dca1f4e}, - {0xb80d17b0, 0x00000032, 0x00000346, 0x22a5bb88, 0x9a7ec89f, 0x5c170e23}, - {0xdaf0592e, 0x00000023, 0x000007b0, 0x3cab3f99, 0x9b1fdd99, 0xc0e9d672}, - {0x4793cc85, 0x0000000d, 0x00000706, 0xe82e04f6, 0xed3db6b7, 0xc18bdc86}, - {0x82ebf64e, 0x00000009, 0x000007c3, 0x69d590a9, 0x9efa8499, 0xa874fcdd}, - {0xb18a0319, 0x00000026, 0x000007db, 0x1cf98dcc, 0x8fa9ad6a, 0x9dc0bb48}, -}; - -#include - -static int __init crc32c_test(void) -{ - int i; - int errors = 0; - int bytes = 0; - u64 nsec; - unsigned long flags; - - /* keep static to prevent cache warming code from - * getting eliminated by the compiler */ - static u32 crc; - - /* pre-warm the cache */ - for (i = 0; i < 100; i++) { - bytes += 2*test[i].length; - - crc ^= __crc32c_le(test[i].crc, test_buf + - test[i].start, test[i].length); - } - - /* reduce OS noise */ - local_irq_save(flags); - local_irq_disable(); - - nsec = ktime_get_ns(); - for (i = 0; i < 100; i++) { - if (test[i].crc32c_le != __crc32c_le(test[i].crc, test_buf + - test[i].start, test[i].length)) - errors++; - } - nsec = ktime_get_ns() - nsec; - - local_irq_restore(flags); - local_irq_enable(); - - pr_info("crc32c: CRC_LE_BITS = %d\n", CRC_LE_BITS); - - if (errors) - pr_warn("crc32c: %d self tests failed\n", errors); - else { - pr_info("crc32c: self tests passed, processed %d bytes in %lld nsec\n", - bytes, nsec); - } - - return 0; -} - -static int __init crc32c_combine_test(void) -{ - int i, j; - int errors = 0, runs = 0; - - for (i = 0; i < 10; i++) { - u32 crc_full; - - crc_full = __crc32c_le(test[i].crc, test_buf + test[i].start, - test[i].length); - for (j = 0; j <= test[i].length; ++j) { - u32 crc1, crc2; - u32 len1 = j, len2 = test[i].length - j; - - crc1 = __crc32c_le(test[i].crc, test_buf + - test[i].start, len1); - crc2 = __crc32c_le(0, test_buf + test[i].start + - len1, len2); - - if (!(crc_full == __crc32c_le_combine(crc1, crc2, len2) && - crc_full == test[i].crc32c_le)) - errors++; - runs++; - cond_resched(); - } - } - - if (errors) - pr_warn("crc32c_combine: %d/%d self tests failed\n", errors, runs); - else - pr_info("crc32c_combine: %d self tests passed\n", runs); - - return 0; -} - -static int __init crc32_test(void) -{ - int i; - int errors = 0; - int bytes = 0; - u64 nsec; - unsigned long flags; - - /* keep static to prevent cache warming code from - * getting eliminated by the compiler */ - static u32 crc; - - /* pre-warm the cache */ - for (i = 0; i < 100; i++) { - bytes += 2*test[i].length; - - crc ^= crc32_le(test[i].crc, test_buf + - test[i].start, test[i].length); - - crc ^= crc32_be(test[i].crc, test_buf + - test[i].start, test[i].length); - } - - /* reduce OS noise */ - local_irq_save(flags); - local_irq_disable(); - - nsec = ktime_get_ns(); - for (i = 0; i < 100; i++) { - if (test[i].crc_le != crc32_le(test[i].crc, test_buf + - test[i].start, test[i].length)) - errors++; - - if (test[i].crc_be != crc32_be(test[i].crc, test_buf + - test[i].start, test[i].length)) - errors++; - } - nsec = ktime_get_ns() - nsec; - - local_irq_restore(flags); - local_irq_enable(); - - pr_info("crc32: CRC_LE_BITS = %d, CRC_BE BITS = %d\n", - CRC_LE_BITS, CRC_BE_BITS); - - if (errors) - pr_warn("crc32: %d self tests failed\n", errors); - else { - pr_info("crc32: self tests passed, processed %d bytes in %lld nsec\n", - bytes, nsec); - } - - return 0; -} - -static int __init crc32_combine_test(void) -{ - int i, j; - int errors = 0, runs = 0; - - for (i = 0; i < 10; i++) { - u32 crc_full; - - crc_full = crc32_le(test[i].crc, test_buf + test[i].start, - test[i].length); - for (j = 0; j <= test[i].length; ++j) { - u32 crc1, crc2; - u32 len1 = j, len2 = test[i].length - j; - - crc1 = crc32_le(test[i].crc, test_buf + - test[i].start, len1); - crc2 = crc32_le(0, test_buf + test[i].start + - len1, len2); - - if (!(crc_full == crc32_le_combine(crc1, crc2, len2) && - crc_full == test[i].crc_le)) - errors++; - runs++; - cond_resched(); - } - } - - if (errors) - pr_warn("crc32_combine: %d/%d self tests failed\n", errors, runs); - else - pr_info("crc32_combine: %d self tests passed\n", runs); - - return 0; -} - -static int __init crc32test_init(void) -{ - crc32_test(); - crc32c_test(); - - crc32_combine_test(); - crc32c_combine_test(); - - return 0; -} - -static void __exit crc32_exit(void) -{ -} - -module_init(crc32test_init); -module_exit(crc32_exit); -#endif /* CONFIG_CRC32_SELFTEST */ diff --git a/src/linux/lib/crc32defs.h b/src/linux/lib/crc32defs.h deleted file mode 100644 index 64cba2c..0000000 --- a/src/linux/lib/crc32defs.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * There are multiple 16-bit CRC polynomials in common use, but this is - * *the* standard CRC-32 polynomial, first popularized by Ethernet. - * x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0 - */ -#define CRCPOLY_LE 0xedb88320 -#define CRCPOLY_BE 0x04c11db7 - -/* - * This is the CRC32c polynomial, as outlined by Castagnoli. - * x^32+x^28+x^27+x^26+x^25+x^23+x^22+x^20+x^19+x^18+x^14+x^13+x^11+x^10+x^9+ - * x^8+x^6+x^0 - */ -#define CRC32C_POLY_LE 0x82F63B78 - -/* Try to choose an implementation variant via Kconfig */ -#ifdef CONFIG_CRC32_SLICEBY8 -# define CRC_LE_BITS 64 -# define CRC_BE_BITS 64 -#endif -#ifdef CONFIG_CRC32_SLICEBY4 -# define CRC_LE_BITS 32 -# define CRC_BE_BITS 32 -#endif -#ifdef CONFIG_CRC32_SARWATE -# define CRC_LE_BITS 8 -# define CRC_BE_BITS 8 -#endif -#ifdef CONFIG_CRC32_BIT -# define CRC_LE_BITS 1 -# define CRC_BE_BITS 1 -#endif - -/* - * How many bits at a time to use. Valid values are 1, 2, 4, 8, 32 and 64. - * For less performance-sensitive, use 4 or 8 to save table size. - * For larger systems choose same as CPU architecture as default. - * This works well on X86_64, SPARC64 systems. This may require some - * elaboration after experiments with other architectures. - */ -#ifndef CRC_LE_BITS -# ifdef CONFIG_64BIT -# define CRC_LE_BITS 64 -# else -# define CRC_LE_BITS 32 -# endif -#endif -#ifndef CRC_BE_BITS -# ifdef CONFIG_64BIT -# define CRC_BE_BITS 64 -# else -# define CRC_BE_BITS 32 -# endif -#endif - -/* - * Little-endian CRC computation. Used with serial bit streams sent - * lsbit-first. Be sure to use cpu_to_le32() to append the computed CRC. - */ -#if CRC_LE_BITS > 64 || CRC_LE_BITS < 1 || CRC_LE_BITS == 16 || \ - CRC_LE_BITS & CRC_LE_BITS-1 -# error "CRC_LE_BITS must be one of {1, 2, 4, 8, 32, 64}" -#endif - -/* - * Big-endian CRC computation. Used with serial bit streams sent - * msbit-first. Be sure to use cpu_to_be32() to append the computed CRC. - */ -#if CRC_BE_BITS > 64 || CRC_BE_BITS < 1 || CRC_BE_BITS == 16 || \ - CRC_BE_BITS & CRC_BE_BITS-1 -# error "CRC_BE_BITS must be one of {1, 2, 4, 8, 32, 64}" -#endif diff --git a/src/linux/lib/ctype.c b/src/linux/lib/ctype.c deleted file mode 100644 index c646df9..0000000 --- a/src/linux/lib/ctype.c +++ /dev/null @@ -1,37 +0,0 @@ -/* - * linux/lib/ctype.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#include -#include -#include - -const unsigned char _ctype[] = { -_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ -_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ -_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ -_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ -_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ -_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ -_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ -_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ -_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ -_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ -_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ -_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ -_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ -_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ -_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ -_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ -_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */ -_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */ -_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */ -_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */ -_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */ -_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */ - -EXPORT_SYMBOL(_ctype); diff --git a/src/linux/lib/debug_info.c b/src/linux/lib/debug_info.c deleted file mode 100644 index 2edbe27..0000000 --- a/src/linux/lib/debug_info.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - * This file exists solely to ensure debug information for some core - * data structures is included in the final image even for - * CONFIG_DEBUG_INFO_REDUCED. Please do not add actual code. However, - * adding appropriate #includes is fine. - */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include diff --git a/src/linux/lib/debug_locks.c b/src/linux/lib/debug_locks.c deleted file mode 100644 index 96c4c63..0000000 --- a/src/linux/lib/debug_locks.c +++ /dev/null @@ -1,48 +0,0 @@ -/* - * lib/debug_locks.c - * - * Generic place for common debugging facilities for various locks: - * spinlocks, rwlocks, mutexes and rwsems. - * - * Started by Ingo Molnar: - * - * Copyright (C) 2006 Red Hat, Inc., Ingo Molnar - */ -#include -#include -#include -#include -#include - -/* - * We want to turn all lock-debugging facilities on/off at once, - * via a global flag. The reason is that once a single bug has been - * detected and reported, there might be cascade of followup bugs - * that would just muddy the log. So we report the first one and - * shut up after that. - */ -int debug_locks = 1; -EXPORT_SYMBOL_GPL(debug_locks); - -/* - * The locking-testsuite uses to get a - * 'silent failure': nothing is printed to the console when - * a locking bug is detected. - */ -int debug_locks_silent; -EXPORT_SYMBOL_GPL(debug_locks_silent); - -/* - * Generic 'turn off all lock debugging' function: - */ -int debug_locks_off(void) -{ - if (__debug_locks_off()) { - if (!debug_locks_silent) { - console_verbose(); - return 1; - } - } - return 0; -} -EXPORT_SYMBOL_GPL(debug_locks_off); diff --git a/src/linux/lib/dec_and_lock.c b/src/linux/lib/dec_and_lock.c deleted file mode 100644 index e262785..0000000 --- a/src/linux/lib/dec_and_lock.c +++ /dev/null @@ -1,34 +0,0 @@ -#include -#include -#include - -/* - * This is an implementation of the notion of "decrement a - * reference count, and return locked if it decremented to zero". - * - * NOTE NOTE NOTE! This is _not_ equivalent to - * - * if (atomic_dec_and_test(&atomic)) { - * spin_lock(&lock); - * return 1; - * } - * return 0; - * - * because the spin-lock and the decrement must be - * "atomic". - */ -int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock) -{ - /* Subtract 1 from counter unless that drops it to 0 (ie. it was 1) */ - if (atomic_add_unless(atomic, -1, 1)) - return 0; - - /* Otherwise do it the slow way */ - spin_lock(lock); - if (atomic_dec_and_test(atomic)) - return 1; - spin_unlock(lock); - return 0; -} - -EXPORT_SYMBOL(_atomic_dec_and_lock); diff --git a/src/linux/lib/decompress.c b/src/linux/lib/decompress.c deleted file mode 100644 index 62696df..0000000 --- a/src/linux/lib/decompress.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * decompress.c - * - * Detect the decompression method based on magic number - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#ifndef CONFIG_DECOMPRESS_GZIP -# define gunzip NULL -#endif -#ifndef CONFIG_DECOMPRESS_BZIP2 -# define bunzip2 NULL -#endif -#ifndef CONFIG_DECOMPRESS_LZMA -# define unlzma NULL -#endif -#ifndef CONFIG_DECOMPRESS_XZ -# define unxz NULL -#endif -#ifndef CONFIG_DECOMPRESS_LZO -# define unlzo NULL -#endif -#ifndef CONFIG_DECOMPRESS_LZ4 -# define unlz4 NULL -#endif - -struct compress_format { - unsigned char magic[2]; - const char *name; - decompress_fn decompressor; -}; - -static const struct compress_format compressed_formats[] __initconst = { - { {0x1f, 0x8b}, "gzip", gunzip }, - { {0x1f, 0x9e}, "gzip", gunzip }, - { {0x42, 0x5a}, "bzip2", bunzip2 }, - { {0x5d, 0x00}, "lzma", unlzma }, - { {0xfd, 0x37}, "xz", unxz }, - { {0x89, 0x4c}, "lzo", unlzo }, - { {0x02, 0x21}, "lz4", unlz4 }, - { {0, 0}, NULL, NULL } -}; - -decompress_fn __init decompress_method(const unsigned char *inbuf, long len, - const char **name) -{ - const struct compress_format *cf; - - if (len < 2) { - if (name) - *name = NULL; - return NULL; /* Need at least this much... */ - } - - pr_debug("Compressed data magic: %#.2x %#.2x\n", inbuf[0], inbuf[1]); - - for (cf = compressed_formats; cf->name; cf++) { - if (!memcmp(inbuf, cf->magic, 2)) - break; - - } - if (name) - *name = cf->name; - return cf->decompressor; -} diff --git a/src/linux/lib/devres.c b/src/linux/lib/devres.c deleted file mode 100644 index cb1464c..0000000 --- a/src/linux/lib/devres.c +++ /dev/null @@ -1,430 +0,0 @@ -#include -#include -#include -#include -#include - -void devm_ioremap_release(struct device *dev, void *res) -{ - iounmap(*(void __iomem **)res); -} - -static int devm_ioremap_match(struct device *dev, void *res, void *match_data) -{ - return *(void **)res == match_data; -} - -/** - * devm_ioremap - Managed ioremap() - * @dev: Generic device to remap IO address for - * @offset: BUS offset to map - * @size: Size of map - * - * Managed ioremap(). Map is automatically unmapped on driver detach. - */ -void __iomem *devm_ioremap(struct device *dev, resource_size_t offset, - resource_size_t size) -{ - void __iomem **ptr, *addr; - - ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return NULL; - - addr = ioremap(offset, size); - if (addr) { - *ptr = addr; - devres_add(dev, ptr); - } else - devres_free(ptr); - - return addr; -} -EXPORT_SYMBOL(devm_ioremap); - -/** - * devm_ioremap_nocache - Managed ioremap_nocache() - * @dev: Generic device to remap IO address for - * @offset: BUS offset to map - * @size: Size of map - * - * Managed ioremap_nocache(). Map is automatically unmapped on driver - * detach. - */ -void __iomem *devm_ioremap_nocache(struct device *dev, resource_size_t offset, - resource_size_t size) -{ - void __iomem **ptr, *addr; - - ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return NULL; - - addr = ioremap_nocache(offset, size); - if (addr) { - *ptr = addr; - devres_add(dev, ptr); - } else - devres_free(ptr); - - return addr; -} -EXPORT_SYMBOL(devm_ioremap_nocache); - -/** - * devm_ioremap_wc - Managed ioremap_wc() - * @dev: Generic device to remap IO address for - * @offset: BUS offset to map - * @size: Size of map - * - * Managed ioremap_wc(). Map is automatically unmapped on driver detach. - */ -void __iomem *devm_ioremap_wc(struct device *dev, resource_size_t offset, - resource_size_t size) -{ - void __iomem **ptr, *addr; - - ptr = devres_alloc(devm_ioremap_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return NULL; - - addr = ioremap_wc(offset, size); - if (addr) { - *ptr = addr; - devres_add(dev, ptr); - } else - devres_free(ptr); - - return addr; -} -EXPORT_SYMBOL(devm_ioremap_wc); - -/** - * devm_iounmap - Managed iounmap() - * @dev: Generic device to unmap for - * @addr: Address to unmap - * - * Managed iounmap(). @addr must have been mapped using devm_ioremap*(). - */ -void devm_iounmap(struct device *dev, void __iomem *addr) -{ - WARN_ON(devres_destroy(dev, devm_ioremap_release, devm_ioremap_match, - (__force void *)addr)); - iounmap(addr); -} -EXPORT_SYMBOL(devm_iounmap); - -/** - * devm_ioremap_resource() - check, request region, and ioremap resource - * @dev: generic device to handle the resource for - * @res: resource to be handled - * - * Checks that a resource is a valid memory region, requests the memory - * region and ioremaps it. All operations are managed and will be undone - * on driver detach. - * - * Returns a pointer to the remapped memory or an ERR_PTR() encoded error code - * on failure. Usage example: - * - * res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - * base = devm_ioremap_resource(&pdev->dev, res); - * if (IS_ERR(base)) - * return PTR_ERR(base); - */ -void __iomem *devm_ioremap_resource(struct device *dev, struct resource *res) -{ - resource_size_t size; - const char *name; - void __iomem *dest_ptr; - - BUG_ON(!dev); - - if (!res || resource_type(res) != IORESOURCE_MEM) { - dev_err(dev, "invalid resource\n"); - return IOMEM_ERR_PTR(-EINVAL); - } - - size = resource_size(res); - name = res->name ?: dev_name(dev); - - if (!devm_request_mem_region(dev, res->start, size, name)) { - dev_err(dev, "can't request region for resource %pR\n", res); - return IOMEM_ERR_PTR(-EBUSY); - } - - dest_ptr = devm_ioremap(dev, res->start, size); - if (!dest_ptr) { - dev_err(dev, "ioremap failed for resource %pR\n", res); - devm_release_mem_region(dev, res->start, size); - dest_ptr = IOMEM_ERR_PTR(-ENOMEM); - } - - return dest_ptr; -} -EXPORT_SYMBOL(devm_ioremap_resource); - -#ifdef CONFIG_HAS_IOPORT_MAP -/* - * Generic iomap devres - */ -static void devm_ioport_map_release(struct device *dev, void *res) -{ - ioport_unmap(*(void __iomem **)res); -} - -static int devm_ioport_map_match(struct device *dev, void *res, - void *match_data) -{ - return *(void **)res == match_data; -} - -/** - * devm_ioport_map - Managed ioport_map() - * @dev: Generic device to map ioport for - * @port: Port to map - * @nr: Number of ports to map - * - * Managed ioport_map(). Map is automatically unmapped on driver - * detach. - */ -void __iomem *devm_ioport_map(struct device *dev, unsigned long port, - unsigned int nr) -{ - void __iomem **ptr, *addr; - - ptr = devres_alloc(devm_ioport_map_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return NULL; - - addr = ioport_map(port, nr); - if (addr) { - *ptr = addr; - devres_add(dev, ptr); - } else - devres_free(ptr); - - return addr; -} -EXPORT_SYMBOL(devm_ioport_map); - -/** - * devm_ioport_unmap - Managed ioport_unmap() - * @dev: Generic device to unmap for - * @addr: Address to unmap - * - * Managed ioport_unmap(). @addr must have been mapped using - * devm_ioport_map(). - */ -void devm_ioport_unmap(struct device *dev, void __iomem *addr) -{ - ioport_unmap(addr); - WARN_ON(devres_destroy(dev, devm_ioport_map_release, - devm_ioport_map_match, (__force void *)addr)); -} -EXPORT_SYMBOL(devm_ioport_unmap); -#endif /* CONFIG_HAS_IOPORT_MAP */ - -#ifdef CONFIG_PCI -/* - * PCI iomap devres - */ -#define PCIM_IOMAP_MAX PCI_ROM_RESOURCE - -struct pcim_iomap_devres { - void __iomem *table[PCIM_IOMAP_MAX]; -}; - -static void pcim_iomap_release(struct device *gendev, void *res) -{ - struct pci_dev *dev = to_pci_dev(gendev); - struct pcim_iomap_devres *this = res; - int i; - - for (i = 0; i < PCIM_IOMAP_MAX; i++) - if (this->table[i]) - pci_iounmap(dev, this->table[i]); -} - -/** - * pcim_iomap_table - access iomap allocation table - * @pdev: PCI device to access iomap table for - * - * Access iomap allocation table for @dev. If iomap table doesn't - * exist and @pdev is managed, it will be allocated. All iomaps - * recorded in the iomap table are automatically unmapped on driver - * detach. - * - * This function might sleep when the table is first allocated but can - * be safely called without context and guaranteed to succed once - * allocated. - */ -void __iomem * const *pcim_iomap_table(struct pci_dev *pdev) -{ - struct pcim_iomap_devres *dr, *new_dr; - - dr = devres_find(&pdev->dev, pcim_iomap_release, NULL, NULL); - if (dr) - return dr->table; - - new_dr = devres_alloc(pcim_iomap_release, sizeof(*new_dr), GFP_KERNEL); - if (!new_dr) - return NULL; - dr = devres_get(&pdev->dev, new_dr, NULL, NULL); - return dr->table; -} -EXPORT_SYMBOL(pcim_iomap_table); - -/** - * pcim_iomap - Managed pcim_iomap() - * @pdev: PCI device to iomap for - * @bar: BAR to iomap - * @maxlen: Maximum length of iomap - * - * Managed pci_iomap(). Map is automatically unmapped on driver - * detach. - */ -void __iomem *pcim_iomap(struct pci_dev *pdev, int bar, unsigned long maxlen) -{ - void __iomem **tbl; - - BUG_ON(bar >= PCIM_IOMAP_MAX); - - tbl = (void __iomem **)pcim_iomap_table(pdev); - if (!tbl || tbl[bar]) /* duplicate mappings not allowed */ - return NULL; - - tbl[bar] = pci_iomap(pdev, bar, maxlen); - return tbl[bar]; -} -EXPORT_SYMBOL(pcim_iomap); - -/** - * pcim_iounmap - Managed pci_iounmap() - * @pdev: PCI device to iounmap for - * @addr: Address to unmap - * - * Managed pci_iounmap(). @addr must have been mapped using pcim_iomap(). - */ -void pcim_iounmap(struct pci_dev *pdev, void __iomem *addr) -{ - void __iomem **tbl; - int i; - - pci_iounmap(pdev, addr); - - tbl = (void __iomem **)pcim_iomap_table(pdev); - BUG_ON(!tbl); - - for (i = 0; i < PCIM_IOMAP_MAX; i++) - if (tbl[i] == addr) { - tbl[i] = NULL; - return; - } - WARN_ON(1); -} -EXPORT_SYMBOL(pcim_iounmap); - -/** - * pcim_iomap_regions - Request and iomap PCI BARs - * @pdev: PCI device to map IO resources for - * @mask: Mask of BARs to request and iomap - * @name: Name used when requesting regions - * - * Request and iomap regions specified by @mask. - */ -int pcim_iomap_regions(struct pci_dev *pdev, int mask, const char *name) -{ - void __iomem * const *iomap; - int i, rc; - - iomap = pcim_iomap_table(pdev); - if (!iomap) - return -ENOMEM; - - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - unsigned long len; - - if (!(mask & (1 << i))) - continue; - - rc = -EINVAL; - len = pci_resource_len(pdev, i); - if (!len) - goto err_inval; - - rc = pci_request_region(pdev, i, name); - if (rc) - goto err_inval; - - rc = -ENOMEM; - if (!pcim_iomap(pdev, i, 0)) - goto err_region; - } - - return 0; - - err_region: - pci_release_region(pdev, i); - err_inval: - while (--i >= 0) { - if (!(mask & (1 << i))) - continue; - pcim_iounmap(pdev, iomap[i]); - pci_release_region(pdev, i); - } - - return rc; -} -EXPORT_SYMBOL(pcim_iomap_regions); - -/** - * pcim_iomap_regions_request_all - Request all BARs and iomap specified ones - * @pdev: PCI device to map IO resources for - * @mask: Mask of BARs to iomap - * @name: Name used when requesting regions - * - * Request all PCI BARs and iomap regions specified by @mask. - */ -int pcim_iomap_regions_request_all(struct pci_dev *pdev, int mask, - const char *name) -{ - int request_mask = ((1 << 6) - 1) & ~mask; - int rc; - - rc = pci_request_selected_regions(pdev, request_mask, name); - if (rc) - return rc; - - rc = pcim_iomap_regions(pdev, mask, name); - if (rc) - pci_release_selected_regions(pdev, request_mask); - return rc; -} -EXPORT_SYMBOL(pcim_iomap_regions_request_all); - -/** - * pcim_iounmap_regions - Unmap and release PCI BARs - * @pdev: PCI device to map IO resources for - * @mask: Mask of BARs to unmap and release - * - * Unmap and release regions specified by @mask. - */ -void pcim_iounmap_regions(struct pci_dev *pdev, int mask) -{ - void __iomem * const *iomap; - int i; - - iomap = pcim_iomap_table(pdev); - if (!iomap) - return; - - for (i = 0; i < PCIM_IOMAP_MAX; i++) { - if (!(mask & (1 << i))) - continue; - - pcim_iounmap(pdev, iomap[i]); - pci_release_region(pdev, i); - } -} -EXPORT_SYMBOL(pcim_iounmap_regions); -#endif /* CONFIG_PCI */ diff --git a/src/linux/lib/div64.c b/src/linux/lib/div64.c deleted file mode 100644 index 7f34525..0000000 --- a/src/linux/lib/div64.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (C) 2003 Bernardo Innocenti - * - * Based on former do_div() implementation from asm-parisc/div64.h: - * Copyright (C) 1999 Hewlett-Packard Co - * Copyright (C) 1999 David Mosberger-Tang - * - * - * Generic C version of 64bit/32bit division and modulo, with - * 64bit result and 32bit remainder. - * - * The fast case for (n>>32 == 0) is handled inline by do_div(). - * - * Code generated for this function might be very inefficient - * for some CPUs. __div64_32() can be overridden by linking arch-specific - * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S - * or by defining a preprocessor macro in arch/include/asm/div64.h. - */ - -#include -#include -#include - -/* Not needed on 64bit architectures */ -#if BITS_PER_LONG == 32 - -#ifndef __div64_32 -uint32_t __attribute__((weak)) __div64_32(uint64_t *n, uint32_t base) -{ - uint64_t rem = *n; - uint64_t b = base; - uint64_t res, d = 1; - uint32_t high = rem >> 32; - - /* Reduce the thing a bit first */ - res = 0; - if (high >= base) { - high /= base; - res = (uint64_t) high << 32; - rem -= (uint64_t) (high*base) << 32; - } - - while ((int64_t)b > 0 && b < rem) { - b = b+b; - d = d+d; - } - - do { - if (rem >= b) { - rem -= b; - res += d; - } - b >>= 1; - d >>= 1; - } while (d); - - *n = res; - return rem; -} -EXPORT_SYMBOL(__div64_32); -#endif - -#ifndef div_s64_rem -s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder) -{ - u64 quotient; - - if (dividend < 0) { - quotient = div_u64_rem(-dividend, abs(divisor), (u32 *)remainder); - *remainder = -*remainder; - if (divisor > 0) - quotient = -quotient; - } else { - quotient = div_u64_rem(dividend, abs(divisor), (u32 *)remainder); - if (divisor < 0) - quotient = -quotient; - } - return quotient; -} -EXPORT_SYMBOL(div_s64_rem); -#endif - -/** - * div64_u64_rem - unsigned 64bit divide with 64bit divisor and remainder - * @dividend: 64bit dividend - * @divisor: 64bit divisor - * @remainder: 64bit remainder - * - * This implementation is a comparable to algorithm used by div64_u64. - * But this operation, which includes math for calculating the remainder, - * is kept distinct to avoid slowing down the div64_u64 operation on 32bit - * systems. - */ -#ifndef div64_u64_rem -u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder) -{ - u32 high = divisor >> 32; - u64 quot; - - if (high == 0) { - u32 rem32; - quot = div_u64_rem(dividend, divisor, &rem32); - *remainder = rem32; - } else { - int n = 1 + fls(high); - quot = div_u64(dividend >> n, divisor >> n); - - if (quot != 0) - quot--; - - *remainder = dividend - quot * divisor; - if (*remainder >= divisor) { - quot++; - *remainder -= divisor; - } - } - - return quot; -} -EXPORT_SYMBOL(div64_u64_rem); -#endif - -/** - * div64_u64 - unsigned 64bit divide with 64bit divisor - * @dividend: 64bit dividend - * @divisor: 64bit divisor - * - * This implementation is a modified version of the algorithm proposed - * by the book 'Hacker's Delight'. The original source and full proof - * can be found here and is available for use without restriction. - * - * 'http://www.hackersdelight.org/hdcodetxt/divDouble.c.txt' - */ -#ifndef div64_u64 -u64 div64_u64(u64 dividend, u64 divisor) -{ - u32 high = divisor >> 32; - u64 quot; - - if (high == 0) { - quot = div_u64(dividend, divisor); - } else { - int n = 1 + fls(high); - quot = div_u64(dividend >> n, divisor >> n); - - if (quot != 0) - quot--; - if ((dividend - quot * divisor) >= divisor) - quot++; - } - - return quot; -} -EXPORT_SYMBOL(div64_u64); -#endif - -/** - * div64_s64 - signed 64bit divide with 64bit divisor - * @dividend: 64bit dividend - * @divisor: 64bit divisor - */ -#ifndef div64_s64 -s64 div64_s64(s64 dividend, s64 divisor) -{ - s64 quot, t; - - quot = div64_u64(abs(dividend), abs(divisor)); - t = (dividend ^ divisor) >> 63; - - return (quot ^ t) - t; -} -EXPORT_SYMBOL(div64_s64); -#endif - -#endif /* BITS_PER_LONG == 32 */ - -/* - * Iterative div/mod for use when dividend is not expected to be much - * bigger than divisor. - */ -u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder) -{ - return __iter_div_u64_rem(dividend, divisor, remainder); -} -EXPORT_SYMBOL(iter_div_u64_rem); diff --git a/src/linux/lib/dma-noop.c b/src/linux/lib/dma-noop.c deleted file mode 100644 index 3d766e7..0000000 --- a/src/linux/lib/dma-noop.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * lib/dma-noop.c - * - * Simple DMA noop-ops that map 1:1 with memory - */ -#include -#include -#include -#include - -static void *dma_noop_alloc(struct device *dev, size_t size, - dma_addr_t *dma_handle, gfp_t gfp, - unsigned long attrs) -{ - void *ret; - - ret = (void *)__get_free_pages(gfp, get_order(size)); - if (ret) - *dma_handle = virt_to_phys(ret); - return ret; -} - -static void dma_noop_free(struct device *dev, size_t size, - void *cpu_addr, dma_addr_t dma_addr, - unsigned long attrs) -{ - free_pages((unsigned long)cpu_addr, get_order(size)); -} - -static dma_addr_t dma_noop_map_page(struct device *dev, struct page *page, - unsigned long offset, size_t size, - enum dma_data_direction dir, - unsigned long attrs) -{ - return page_to_phys(page) + offset; -} - -static int dma_noop_map_sg(struct device *dev, struct scatterlist *sgl, int nents, - enum dma_data_direction dir, - unsigned long attrs) -{ - int i; - struct scatterlist *sg; - - for_each_sg(sgl, sg, nents, i) { - void *va; - - BUG_ON(!sg_page(sg)); - va = sg_virt(sg); - sg_dma_address(sg) = (dma_addr_t)virt_to_phys(va); - sg_dma_len(sg) = sg->length; - } - - return nents; -} - -static int dma_noop_mapping_error(struct device *dev, dma_addr_t dma_addr) -{ - return 0; -} - -static int dma_noop_supported(struct device *dev, u64 mask) -{ - return 1; -} - -struct dma_map_ops dma_noop_ops = { - .alloc = dma_noop_alloc, - .free = dma_noop_free, - .map_page = dma_noop_map_page, - .map_sg = dma_noop_map_sg, - .mapping_error = dma_noop_mapping_error, - .dma_supported = dma_noop_supported, -}; - -EXPORT_SYMBOL(dma_noop_ops); diff --git a/src/linux/lib/dump_stack.c b/src/linux/lib/dump_stack.c deleted file mode 100644 index c30d07e..0000000 --- a/src/linux/lib/dump_stack.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Provide a default dump_stack() function for architectures - * which don't implement their own. - */ - -#include -#include -#include -#include -#include - -static void __dump_stack(void) -{ - dump_stack_print_info(KERN_DEFAULT); - show_stack(NULL, NULL); -} - -/** - * dump_stack - dump the current task information and its stack trace - * - * Architectures can override this implementation by implementing its own. - */ -#ifdef CONFIG_SMP -static atomic_t dump_lock = ATOMIC_INIT(-1); - -asmlinkage __visible void dump_stack(void) -{ - unsigned long flags; - int was_locked; - int old; - int cpu; - - /* - * Permit this cpu to perform nested stack dumps while serialising - * against other CPUs - */ -retry: - local_irq_save(flags); - cpu = smp_processor_id(); - old = atomic_cmpxchg(&dump_lock, -1, cpu); - if (old == -1) { - was_locked = 0; - } else if (old == cpu) { - was_locked = 1; - } else { - local_irq_restore(flags); - cpu_relax(); - goto retry; - } - - __dump_stack(); - - if (!was_locked) - atomic_set(&dump_lock, -1); - - local_irq_restore(flags); -} -#else -asmlinkage __visible void dump_stack(void) -{ - __dump_stack(); -} -#endif -EXPORT_SYMBOL(dump_stack); diff --git a/src/linux/lib/dynamic_queue_limits.c b/src/linux/lib/dynamic_queue_limits.c deleted file mode 100644 index f346715..0000000 --- a/src/linux/lib/dynamic_queue_limits.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Dynamic byte queue limits. See include/linux/dynamic_queue_limits.h - * - * Copyright (c) 2011, Tom Herbert - */ -#include -#include -#include -#include -#include -#include - -#define POSDIFF(A, B) ((int)((A) - (B)) > 0 ? (A) - (B) : 0) -#define AFTER_EQ(A, B) ((int)((A) - (B)) >= 0) - -/* Records completed count and recalculates the queue limit */ -void dql_completed(struct dql *dql, unsigned int count) -{ - unsigned int inprogress, prev_inprogress, limit; - unsigned int ovlimit, completed, num_queued; - bool all_prev_completed; - - num_queued = ACCESS_ONCE(dql->num_queued); - - /* Can't complete more than what's in queue */ - BUG_ON(count > num_queued - dql->num_completed); - - completed = dql->num_completed + count; - limit = dql->limit; - ovlimit = POSDIFF(num_queued - dql->num_completed, limit); - inprogress = num_queued - completed; - prev_inprogress = dql->prev_num_queued - dql->num_completed; - all_prev_completed = AFTER_EQ(completed, dql->prev_num_queued); - - if ((ovlimit && !inprogress) || - (dql->prev_ovlimit && all_prev_completed)) { - /* - * Queue considered starved if: - * - The queue was over-limit in the last interval, - * and there is no more data in the queue. - * OR - * - The queue was over-limit in the previous interval and - * when enqueuing it was possible that all queued data - * had been consumed. This covers the case when queue - * may have becomes starved between completion processing - * running and next time enqueue was scheduled. - * - * When queue is starved increase the limit by the amount - * of bytes both sent and completed in the last interval, - * plus any previous over-limit. - */ - limit += POSDIFF(completed, dql->prev_num_queued) + - dql->prev_ovlimit; - dql->slack_start_time = jiffies; - dql->lowest_slack = UINT_MAX; - } else if (inprogress && prev_inprogress && !all_prev_completed) { - /* - * Queue was not starved, check if the limit can be decreased. - * A decrease is only considered if the queue has been busy in - * the whole interval (the check above). - * - * If there is slack, the amount of execess data queued above - * the the amount needed to prevent starvation, the queue limit - * can be decreased. To avoid hysteresis we consider the - * minimum amount of slack found over several iterations of the - * completion routine. - */ - unsigned int slack, slack_last_objs; - - /* - * Slack is the maximum of - * - The queue limit plus previous over-limit minus twice - * the number of objects completed. Note that two times - * number of completed bytes is a basis for an upper bound - * of the limit. - * - Portion of objects in the last queuing operation that - * was not part of non-zero previous over-limit. That is - * "round down" by non-overlimit portion of the last - * queueing operation. - */ - slack = POSDIFF(limit + dql->prev_ovlimit, - 2 * (completed - dql->num_completed)); - slack_last_objs = dql->prev_ovlimit ? - POSDIFF(dql->prev_last_obj_cnt, dql->prev_ovlimit) : 0; - - slack = max(slack, slack_last_objs); - - if (slack < dql->lowest_slack) - dql->lowest_slack = slack; - - if (time_after(jiffies, - dql->slack_start_time + dql->slack_hold_time)) { - limit = POSDIFF(limit, dql->lowest_slack); - dql->slack_start_time = jiffies; - dql->lowest_slack = UINT_MAX; - } - } - - /* Enforce bounds on limit */ - limit = clamp(limit, dql->min_limit, dql->max_limit); - - if (limit != dql->limit) { - dql->limit = limit; - ovlimit = 0; - } - - dql->adj_limit = limit + completed; - dql->prev_ovlimit = ovlimit; - dql->prev_last_obj_cnt = dql->last_obj_cnt; - dql->num_completed = completed; - dql->prev_num_queued = num_queued; -} -EXPORT_SYMBOL(dql_completed); - -void dql_reset(struct dql *dql) -{ - /* Reset all dynamic values */ - dql->limit = 0; - dql->num_queued = 0; - dql->num_completed = 0; - dql->last_obj_cnt = 0; - dql->prev_num_queued = 0; - dql->prev_last_obj_cnt = 0; - dql->prev_ovlimit = 0; - dql->lowest_slack = UINT_MAX; - dql->slack_start_time = jiffies; -} -EXPORT_SYMBOL(dql_reset); - -int dql_init(struct dql *dql, unsigned hold_time) -{ - dql->max_limit = DQL_MAX_LIMIT; - dql->min_limit = 0; - dql->slack_hold_time = hold_time; - dql_reset(dql); - return 0; -} -EXPORT_SYMBOL(dql_init); diff --git a/src/linux/lib/earlycpio.c b/src/linux/lib/earlycpio.c deleted file mode 100644 index db283ba..0000000 --- a/src/linux/lib/earlycpio.c +++ /dev/null @@ -1,149 +0,0 @@ -/* ----------------------------------------------------------------------- * - * - * Copyright 2012 Intel Corporation; author H. Peter Anvin - * - * This file is part of the Linux kernel, and is made available - * under the terms of the GNU General Public License version 2, as - * published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * ----------------------------------------------------------------------- */ - -/* - * earlycpio.c - * - * Find a specific cpio member; must precede any compressed content. - * This is used to locate data items in the initramfs used by the - * kernel itself during early boot (before the main initramfs is - * decompressed.) It is the responsibility of the initramfs creator - * to ensure that these items are uncompressed at the head of the - * blob. Depending on the boot loader or package tool that may be a - * separate file or part of the same file. - */ - -#include -#include -#include - -enum cpio_fields { - C_MAGIC, - C_INO, - C_MODE, - C_UID, - C_GID, - C_NLINK, - C_MTIME, - C_FILESIZE, - C_MAJ, - C_MIN, - C_RMAJ, - C_RMIN, - C_NAMESIZE, - C_CHKSUM, - C_NFIELDS -}; - -/** - * cpio_data find_cpio_data - Search for files in an uncompressed cpio - * @path: The directory to search for, including a slash at the end - * @data: Pointer to the the cpio archive or a header inside - * @len: Remaining length of the cpio based on data pointer - * @nextoff: When a matching file is found, this is the offset from the - * beginning of the cpio to the beginning of the next file, not the - * matching file itself. It can be used to iterate through the cpio - * to find all files inside of a directory path. - * - * @return: struct cpio_data containing the address, length and - * filename (with the directory path cut off) of the found file. - * If you search for a filename and not for files in a directory, - * pass the absolute path of the filename in the cpio and make sure - * the match returned an empty filename string. - */ - -struct cpio_data find_cpio_data(const char *path, void *data, - size_t len, long *nextoff) -{ - const size_t cpio_header_len = 8*C_NFIELDS - 2; - struct cpio_data cd = { NULL, 0, "" }; - const char *p, *dptr, *nptr; - unsigned int ch[C_NFIELDS], *chp, v; - unsigned char c, x; - size_t mypathsize = strlen(path); - int i, j; - - p = data; - - while (len > cpio_header_len) { - if (!*p) { - /* All cpio headers need to be 4-byte aligned */ - p += 4; - len -= 4; - continue; - } - - j = 6; /* The magic field is only 6 characters */ - chp = ch; - for (i = C_NFIELDS; i; i--) { - v = 0; - while (j--) { - v <<= 4; - c = *p++; - - x = c - '0'; - if (x < 10) { - v += x; - continue; - } - - x = (c | 0x20) - 'a'; - if (x < 6) { - v += x + 10; - continue; - } - - goto quit; /* Invalid hexadecimal */ - } - *chp++ = v; - j = 8; /* All other fields are 8 characters */ - } - - if ((ch[C_MAGIC] - 0x070701) > 1) - goto quit; /* Invalid magic */ - - len -= cpio_header_len; - - dptr = PTR_ALIGN(p + ch[C_NAMESIZE], 4); - nptr = PTR_ALIGN(dptr + ch[C_FILESIZE], 4); - - if (nptr > p + len || dptr < p || nptr < dptr) - goto quit; /* Buffer overrun */ - - if ((ch[C_MODE] & 0170000) == 0100000 && - ch[C_NAMESIZE] >= mypathsize && - !memcmp(p, path, mypathsize)) { - - if (nextoff) - *nextoff = (long)nptr - (long)data; - - if (ch[C_NAMESIZE] - mypathsize >= MAX_CPIO_FILE_NAME) { - pr_warn( - "File %s exceeding MAX_CPIO_FILE_NAME [%d]\n", - p, MAX_CPIO_FILE_NAME); - } - strlcpy(cd.name, p + mypathsize, MAX_CPIO_FILE_NAME); - - cd.data = (void *)dptr; - cd.size = ch[C_FILESIZE]; - return cd; /* Found it! */ - } - len -= (nptr - p); - p = nptr; - } - -quit: - return cd; -} diff --git a/src/linux/lib/extable.c b/src/linux/lib/extable.c deleted file mode 100644 index 0be02ad..0000000 --- a/src/linux/lib/extable.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Derived from arch/ppc/mm/extable.c and arch/i386/mm/extable.c. - * - * Copyright (C) 2004 Paul Mackerras, IBM Corp. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include - -#ifndef ARCH_HAS_RELATIVE_EXTABLE -#define ex_to_insn(x) ((x)->insn) -#else -static inline unsigned long ex_to_insn(const struct exception_table_entry *x) -{ - return (unsigned long)&x->insn + x->insn; -} -#endif - -#ifndef ARCH_HAS_SORT_EXTABLE -#ifndef ARCH_HAS_RELATIVE_EXTABLE -#define swap_ex NULL -#else -static void swap_ex(void *a, void *b, int size) -{ - struct exception_table_entry *x = a, *y = b, tmp; - int delta = b - a; - - tmp = *x; - x->insn = y->insn + delta; - y->insn = tmp.insn - delta; - -#ifdef swap_ex_entry_fixup - swap_ex_entry_fixup(x, y, tmp, delta); -#else - x->fixup = y->fixup + delta; - y->fixup = tmp.fixup - delta; -#endif -} -#endif /* ARCH_HAS_RELATIVE_EXTABLE */ - -/* - * The exception table needs to be sorted so that the binary - * search that we use to find entries in it works properly. - * This is used both for the kernel exception table and for - * the exception tables of modules that get loaded. - */ -static int cmp_ex(const void *a, const void *b) -{ - const struct exception_table_entry *x = a, *y = b; - - /* avoid overflow */ - if (ex_to_insn(x) > ex_to_insn(y)) - return 1; - if (ex_to_insn(x) < ex_to_insn(y)) - return -1; - return 0; -} - -void sort_extable(struct exception_table_entry *start, - struct exception_table_entry *finish) -{ - sort(start, finish - start, sizeof(struct exception_table_entry), - cmp_ex, swap_ex); -} - -#ifdef CONFIG_MODULES -/* - * If the exception table is sorted, any referring to the module init - * will be at the beginning or the end. - */ -void trim_init_extable(struct module *m) -{ - /*trim the beginning*/ - while (m->num_exentries && - within_module_init(ex_to_insn(&m->extable[0]), m)) { - m->extable++; - m->num_exentries--; - } - /*trim the end*/ - while (m->num_exentries && - within_module_init(ex_to_insn(&m->extable[m->num_exentries - 1]), - m)) - m->num_exentries--; -} -#endif /* CONFIG_MODULES */ -#endif /* !ARCH_HAS_SORT_EXTABLE */ - -#ifndef ARCH_HAS_SEARCH_EXTABLE -/* - * Search one exception table for an entry corresponding to the - * given instruction address, and return the address of the entry, - * or NULL if none is found. - * We use a binary search, and thus we assume that the table is - * already sorted. - */ -const struct exception_table_entry * -search_extable(const struct exception_table_entry *first, - const struct exception_table_entry *last, - unsigned long value) -{ - while (first <= last) { - const struct exception_table_entry *mid; - - mid = ((last - first) >> 1) + first; - /* - * careful, the distance between value and insn - * can be larger than MAX_LONG: - */ - if (ex_to_insn(mid) < value) - first = mid + 1; - else if (ex_to_insn(mid) > value) - last = mid - 1; - else - return mid; - } - return NULL; -} -#endif diff --git a/src/linux/lib/find_bit.c b/src/linux/lib/find_bit.c deleted file mode 100644 index 18072ea..0000000 --- a/src/linux/lib/find_bit.c +++ /dev/null @@ -1,193 +0,0 @@ -/* bit search implementation - * - * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * Copyright (C) 2008 IBM Corporation - * 'find_last_bit' is written by Rusty Russell - * (Inspired by David Howell's find_next_bit implementation) - * - * Rewritten by Yury Norov to decrease - * size and improve performance, 2015. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include - -#if !defined(find_next_bit) || !defined(find_next_zero_bit) - -/* - * This is a common helper function for find_next_bit and - * find_next_zero_bit. The difference is the "invert" argument, which - * is XORed with each fetched word before searching it for one bits. - */ -static unsigned long _find_next_bit(const unsigned long *addr, - unsigned long nbits, unsigned long start, unsigned long invert) -{ - unsigned long tmp; - - if (!nbits || start >= nbits) - return nbits; - - tmp = addr[start / BITS_PER_LONG] ^ invert; - - /* Handle 1st word. */ - tmp &= BITMAP_FIRST_WORD_MASK(start); - start = round_down(start, BITS_PER_LONG); - - while (!tmp) { - start += BITS_PER_LONG; - if (start >= nbits) - return nbits; - - tmp = addr[start / BITS_PER_LONG] ^ invert; - } - - return min(start + __ffs(tmp), nbits); -} -#endif - -#ifndef find_next_bit -/* - * Find the next set bit in a memory region. - */ -unsigned long find_next_bit(const unsigned long *addr, unsigned long size, - unsigned long offset) -{ - return _find_next_bit(addr, size, offset, 0UL); -} -EXPORT_SYMBOL(find_next_bit); -#endif - -#ifndef find_next_zero_bit -unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size, - unsigned long offset) -{ - return _find_next_bit(addr, size, offset, ~0UL); -} -EXPORT_SYMBOL(find_next_zero_bit); -#endif - -#ifndef find_first_bit -/* - * Find the first set bit in a memory region. - */ -unsigned long find_first_bit(const unsigned long *addr, unsigned long size) -{ - unsigned long idx; - - for (idx = 0; idx * BITS_PER_LONG < size; idx++) { - if (addr[idx]) - return min(idx * BITS_PER_LONG + __ffs(addr[idx]), size); - } - - return size; -} -EXPORT_SYMBOL(find_first_bit); -#endif - -#ifndef find_first_zero_bit -/* - * Find the first cleared bit in a memory region. - */ -unsigned long find_first_zero_bit(const unsigned long *addr, unsigned long size) -{ - unsigned long idx; - - for (idx = 0; idx * BITS_PER_LONG < size; idx++) { - if (addr[idx] != ~0UL) - return min(idx * BITS_PER_LONG + ffz(addr[idx]), size); - } - - return size; -} -EXPORT_SYMBOL(find_first_zero_bit); -#endif - -#ifndef find_last_bit -unsigned long find_last_bit(const unsigned long *addr, unsigned long size) -{ - if (size) { - unsigned long val = BITMAP_LAST_WORD_MASK(size); - unsigned long idx = (size-1) / BITS_PER_LONG; - - do { - val &= addr[idx]; - if (val) - return idx * BITS_PER_LONG + __fls(val); - - val = ~0ul; - } while (idx--); - } - return size; -} -EXPORT_SYMBOL(find_last_bit); -#endif - -#ifdef __BIG_ENDIAN - -/* include/linux/byteorder does not support "unsigned long" type */ -static inline unsigned long ext2_swab(const unsigned long y) -{ -#if BITS_PER_LONG == 64 - return (unsigned long) __swab64((u64) y); -#elif BITS_PER_LONG == 32 - return (unsigned long) __swab32((u32) y); -#else -#error BITS_PER_LONG not defined -#endif -} - -#if !defined(find_next_bit_le) || !defined(find_next_zero_bit_le) -static unsigned long _find_next_bit_le(const unsigned long *addr, - unsigned long nbits, unsigned long start, unsigned long invert) -{ - unsigned long tmp; - - if (!nbits || start >= nbits) - return nbits; - - tmp = addr[start / BITS_PER_LONG] ^ invert; - - /* Handle 1st word. */ - tmp &= ext2_swab(BITMAP_FIRST_WORD_MASK(start)); - start = round_down(start, BITS_PER_LONG); - - while (!tmp) { - start += BITS_PER_LONG; - if (start >= nbits) - return nbits; - - tmp = addr[start / BITS_PER_LONG] ^ invert; - } - - return min(start + __ffs(ext2_swab(tmp)), nbits); -} -#endif - -#ifndef find_next_zero_bit_le -unsigned long find_next_zero_bit_le(const void *addr, unsigned - long size, unsigned long offset) -{ - return _find_next_bit_le(addr, size, offset, ~0UL); -} -EXPORT_SYMBOL(find_next_zero_bit_le); -#endif - -#ifndef find_next_bit_le -unsigned long find_next_bit_le(const void *addr, unsigned - long size, unsigned long offset) -{ - return _find_next_bit_le(addr, size, offset, 0UL); -} -EXPORT_SYMBOL(find_next_bit_le); -#endif - -#endif /* __BIG_ENDIAN */ diff --git a/src/linux/lib/flex_array.c b/src/linux/lib/flex_array.c deleted file mode 100644 index 2eed22f..0000000 --- a/src/linux/lib/flex_array.c +++ /dev/null @@ -1,398 +0,0 @@ -/* - * Flexible array managed in PAGE_SIZE parts - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright IBM Corporation, 2009 - * - * Author: Dave Hansen - */ - -#include -#include -#include -#include -#include - -struct flex_array_part { - char elements[FLEX_ARRAY_PART_SIZE]; -}; - -/* - * If a user requests an allocation which is small - * enough, we may simply use the space in the - * flex_array->parts[] array to store the user - * data. - */ -static inline int elements_fit_in_base(struct flex_array *fa) -{ - int data_size = fa->element_size * fa->total_nr_elements; - if (data_size <= FLEX_ARRAY_BASE_BYTES_LEFT) - return 1; - return 0; -} - -/** - * flex_array_alloc - allocate a new flexible array - * @element_size: the size of individual elements in the array - * @total: total number of elements that this should hold - * @flags: page allocation flags to use for base array - * - * Note: all locking must be provided by the caller. - * - * @total is used to size internal structures. If the user ever - * accesses any array indexes >=@total, it will produce errors. - * - * The maximum number of elements is defined as: the number of - * elements that can be stored in a page times the number of - * page pointers that we can fit in the base structure or (using - * integer math): - * - * (PAGE_SIZE/element_size) * (PAGE_SIZE-8)/sizeof(void *) - * - * Here's a table showing example capacities. Note that the maximum - * index that the get/put() functions is just nr_objects-1. This - * basically means that you get 4MB of storage on 32-bit and 2MB on - * 64-bit. - * - * - * Element size | Objects | Objects | - * PAGE_SIZE=4k | 32-bit | 64-bit | - * ---------------------------------| - * 1 bytes | 4177920 | 2088960 | - * 2 bytes | 2088960 | 1044480 | - * 3 bytes | 1392300 | 696150 | - * 4 bytes | 1044480 | 522240 | - * 32 bytes | 130560 | 65408 | - * 33 bytes | 126480 | 63240 | - * 2048 bytes | 2040 | 1020 | - * 2049 bytes | 1020 | 510 | - * void * | 1044480 | 261120 | - * - * Since 64-bit pointers are twice the size, we lose half the - * capacity in the base structure. Also note that no effort is made - * to efficiently pack objects across page boundaries. - */ -struct flex_array *flex_array_alloc(int element_size, unsigned int total, - gfp_t flags) -{ - struct flex_array *ret; - int elems_per_part = 0; - int max_size = 0; - struct reciprocal_value reciprocal_elems = { 0 }; - - if (element_size) { - elems_per_part = FLEX_ARRAY_ELEMENTS_PER_PART(element_size); - reciprocal_elems = reciprocal_value(elems_per_part); - max_size = FLEX_ARRAY_NR_BASE_PTRS * elems_per_part; - } - - /* max_size will end up 0 if element_size > PAGE_SIZE */ - if (total > max_size) - return NULL; - ret = kzalloc(sizeof(struct flex_array), flags); - if (!ret) - return NULL; - ret->element_size = element_size; - ret->total_nr_elements = total; - ret->elems_per_part = elems_per_part; - ret->reciprocal_elems = reciprocal_elems; - if (elements_fit_in_base(ret) && !(flags & __GFP_ZERO)) - memset(&ret->parts[0], FLEX_ARRAY_FREE, - FLEX_ARRAY_BASE_BYTES_LEFT); - return ret; -} -EXPORT_SYMBOL(flex_array_alloc); - -static int fa_element_to_part_nr(struct flex_array *fa, - unsigned int element_nr) -{ - /* - * if element_size == 0 we don't get here, so we never touch - * the zeroed fa->reciprocal_elems, which would yield invalid - * results - */ - return reciprocal_divide(element_nr, fa->reciprocal_elems); -} - -/** - * flex_array_free_parts - just free the second-level pages - * @fa: the flex array from which to free parts - * - * This is to be used in cases where the base 'struct flex_array' - * has been statically allocated and should not be free. - */ -void flex_array_free_parts(struct flex_array *fa) -{ - int part_nr; - - if (elements_fit_in_base(fa)) - return; - for (part_nr = 0; part_nr < FLEX_ARRAY_NR_BASE_PTRS; part_nr++) - kfree(fa->parts[part_nr]); -} -EXPORT_SYMBOL(flex_array_free_parts); - -void flex_array_free(struct flex_array *fa) -{ - flex_array_free_parts(fa); - kfree(fa); -} -EXPORT_SYMBOL(flex_array_free); - -static unsigned int index_inside_part(struct flex_array *fa, - unsigned int element_nr, - unsigned int part_nr) -{ - unsigned int part_offset; - - part_offset = element_nr - part_nr * fa->elems_per_part; - return part_offset * fa->element_size; -} - -static struct flex_array_part * -__fa_get_part(struct flex_array *fa, int part_nr, gfp_t flags) -{ - struct flex_array_part *part = fa->parts[part_nr]; - if (!part) { - part = kmalloc(sizeof(struct flex_array_part), flags); - if (!part) - return NULL; - if (!(flags & __GFP_ZERO)) - memset(part, FLEX_ARRAY_FREE, - sizeof(struct flex_array_part)); - fa->parts[part_nr] = part; - } - return part; -} - -/** - * flex_array_put - copy data into the array at @element_nr - * @fa: the flex array to copy data into - * @element_nr: index of the position in which to insert - * the new element. - * @src: address of data to copy into the array - * @flags: page allocation flags to use for array expansion - * - * - * Note that this *copies* the contents of @src into - * the array. If you are trying to store an array of - * pointers, make sure to pass in &ptr instead of ptr. - * You may instead wish to use the flex_array_put_ptr() - * helper function. - * - * Locking must be provided by the caller. - */ -int flex_array_put(struct flex_array *fa, unsigned int element_nr, void *src, - gfp_t flags) -{ - int part_nr = 0; - struct flex_array_part *part; - void *dst; - - if (element_nr >= fa->total_nr_elements) - return -ENOSPC; - if (!fa->element_size) - return 0; - if (elements_fit_in_base(fa)) - part = (struct flex_array_part *)&fa->parts[0]; - else { - part_nr = fa_element_to_part_nr(fa, element_nr); - part = __fa_get_part(fa, part_nr, flags); - if (!part) - return -ENOMEM; - } - dst = &part->elements[index_inside_part(fa, element_nr, part_nr)]; - memcpy(dst, src, fa->element_size); - return 0; -} -EXPORT_SYMBOL(flex_array_put); - -/** - * flex_array_clear - clear element in array at @element_nr - * @fa: the flex array of the element. - * @element_nr: index of the position to clear. - * - * Locking must be provided by the caller. - */ -int flex_array_clear(struct flex_array *fa, unsigned int element_nr) -{ - int part_nr = 0; - struct flex_array_part *part; - void *dst; - - if (element_nr >= fa->total_nr_elements) - return -ENOSPC; - if (!fa->element_size) - return 0; - if (elements_fit_in_base(fa)) - part = (struct flex_array_part *)&fa->parts[0]; - else { - part_nr = fa_element_to_part_nr(fa, element_nr); - part = fa->parts[part_nr]; - if (!part) - return -EINVAL; - } - dst = &part->elements[index_inside_part(fa, element_nr, part_nr)]; - memset(dst, FLEX_ARRAY_FREE, fa->element_size); - return 0; -} -EXPORT_SYMBOL(flex_array_clear); - -/** - * flex_array_prealloc - guarantee that array space exists - * @fa: the flex array for which to preallocate parts - * @start: index of first array element for which space is allocated - * @nr_elements: number of elements for which space is allocated - * @flags: page allocation flags - * - * This will guarantee that no future calls to flex_array_put() - * will allocate memory. It can be used if you are expecting to - * be holding a lock or in some atomic context while writing - * data into the array. - * - * Locking must be provided by the caller. - */ -int flex_array_prealloc(struct flex_array *fa, unsigned int start, - unsigned int nr_elements, gfp_t flags) -{ - int start_part; - int end_part; - int part_nr; - unsigned int end; - struct flex_array_part *part; - - if (!start && !nr_elements) - return 0; - if (start >= fa->total_nr_elements) - return -ENOSPC; - if (!nr_elements) - return 0; - - end = start + nr_elements - 1; - - if (end >= fa->total_nr_elements) - return -ENOSPC; - if (!fa->element_size) - return 0; - if (elements_fit_in_base(fa)) - return 0; - start_part = fa_element_to_part_nr(fa, start); - end_part = fa_element_to_part_nr(fa, end); - for (part_nr = start_part; part_nr <= end_part; part_nr++) { - part = __fa_get_part(fa, part_nr, flags); - if (!part) - return -ENOMEM; - } - return 0; -} -EXPORT_SYMBOL(flex_array_prealloc); - -/** - * flex_array_get - pull data back out of the array - * @fa: the flex array from which to extract data - * @element_nr: index of the element to fetch from the array - * - * Returns a pointer to the data at index @element_nr. Note - * that this is a copy of the data that was passed in. If you - * are using this to store pointers, you'll get back &ptr. You - * may instead wish to use the flex_array_get_ptr helper. - * - * Locking must be provided by the caller. - */ -void *flex_array_get(struct flex_array *fa, unsigned int element_nr) -{ - int part_nr = 0; - struct flex_array_part *part; - - if (!fa->element_size) - return NULL; - if (element_nr >= fa->total_nr_elements) - return NULL; - if (elements_fit_in_base(fa)) - part = (struct flex_array_part *)&fa->parts[0]; - else { - part_nr = fa_element_to_part_nr(fa, element_nr); - part = fa->parts[part_nr]; - if (!part) - return NULL; - } - return &part->elements[index_inside_part(fa, element_nr, part_nr)]; -} -EXPORT_SYMBOL(flex_array_get); - -/** - * flex_array_get_ptr - pull a ptr back out of the array - * @fa: the flex array from which to extract data - * @element_nr: index of the element to fetch from the array - * - * Returns the pointer placed in the flex array at element_nr using - * flex_array_put_ptr(). This function should not be called if the - * element in question was not set using the _put_ptr() helper. - */ -void *flex_array_get_ptr(struct flex_array *fa, unsigned int element_nr) -{ - void **tmp; - - tmp = flex_array_get(fa, element_nr); - if (!tmp) - return NULL; - - return *tmp; -} -EXPORT_SYMBOL(flex_array_get_ptr); - -static int part_is_free(struct flex_array_part *part) -{ - int i; - - for (i = 0; i < sizeof(struct flex_array_part); i++) - if (part->elements[i] != FLEX_ARRAY_FREE) - return 0; - return 1; -} - -/** - * flex_array_shrink - free unused second-level pages - * @fa: the flex array to shrink - * - * Frees all second-level pages that consist solely of unused - * elements. Returns the number of pages freed. - * - * Locking must be provided by the caller. - */ -int flex_array_shrink(struct flex_array *fa) -{ - struct flex_array_part *part; - int part_nr; - int ret = 0; - - if (!fa->total_nr_elements || !fa->element_size) - return 0; - if (elements_fit_in_base(fa)) - return ret; - for (part_nr = 0; part_nr < FLEX_ARRAY_NR_BASE_PTRS; part_nr++) { - part = fa->parts[part_nr]; - if (!part) - continue; - if (part_is_free(part)) { - fa->parts[part_nr] = NULL; - kfree(part); - ret++; - } - } - return ret; -} -EXPORT_SYMBOL(flex_array_shrink); diff --git a/src/linux/lib/flex_proportions.c b/src/linux/lib/flex_proportions.c deleted file mode 100644 index a71cf1b..0000000 --- a/src/linux/lib/flex_proportions.c +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Floating proportions with flexible aging period - * - * Copyright (C) 2011, SUSE, Jan Kara - * - * The goal of this code is: Given different types of event, measure proportion - * of each type of event over time. The proportions are measured with - * exponentially decaying history to give smooth transitions. A formula - * expressing proportion of event of type 'j' is: - * - * p_{j} = (\Sum_{i>=0} x_{i,j}/2^{i+1})/(\Sum_{i>=0} x_i/2^{i+1}) - * - * Where x_{i,j} is j's number of events in i-th last time period and x_i is - * total number of events in i-th last time period. - * - * Note that p_{j}'s are normalised, i.e. - * - * \Sum_{j} p_{j} = 1, - * - * This formula can be straightforwardly computed by maintaining denominator - * (let's call it 'd') and for each event type its numerator (let's call it - * 'n_j'). When an event of type 'j' happens, we simply need to do: - * n_j++; d++; - * - * When a new period is declared, we could do: - * d /= 2 - * for each j - * n_j /= 2 - * - * To avoid iteration over all event types, we instead shift numerator of event - * j lazily when someone asks for a proportion of event j or when event j - * occurs. This can bit trivially implemented by remembering last period in - * which something happened with proportion of type j. - */ -#include - -int fprop_global_init(struct fprop_global *p, gfp_t gfp) -{ - int err; - - p->period = 0; - /* Use 1 to avoid dealing with periods with 0 events... */ - err = percpu_counter_init(&p->events, 1, gfp); - if (err) - return err; - seqcount_init(&p->sequence); - return 0; -} - -void fprop_global_destroy(struct fprop_global *p) -{ - percpu_counter_destroy(&p->events); -} - -/* - * Declare @periods new periods. It is upto the caller to make sure period - * transitions cannot happen in parallel. - * - * The function returns true if the proportions are still defined and false - * if aging zeroed out all events. This can be used to detect whether declaring - * further periods has any effect. - */ -bool fprop_new_period(struct fprop_global *p, int periods) -{ - s64 events; - unsigned long flags; - - local_irq_save(flags); - events = percpu_counter_sum(&p->events); - /* - * Don't do anything if there are no events. - */ - if (events <= 1) { - local_irq_restore(flags); - return false; - } - write_seqcount_begin(&p->sequence); - if (periods < 64) - events -= events >> periods; - /* Use addition to avoid losing events happening between sum and set */ - percpu_counter_add(&p->events, -events); - p->period += periods; - write_seqcount_end(&p->sequence); - local_irq_restore(flags); - - return true; -} - -/* - * ---- SINGLE ---- - */ - -int fprop_local_init_single(struct fprop_local_single *pl) -{ - pl->events = 0; - pl->period = 0; - raw_spin_lock_init(&pl->lock); - return 0; -} - -void fprop_local_destroy_single(struct fprop_local_single *pl) -{ -} - -static void fprop_reflect_period_single(struct fprop_global *p, - struct fprop_local_single *pl) -{ - unsigned int period = p->period; - unsigned long flags; - - /* Fast path - period didn't change */ - if (pl->period == period) - return; - raw_spin_lock_irqsave(&pl->lock, flags); - /* Someone updated pl->period while we were spinning? */ - if (pl->period >= period) { - raw_spin_unlock_irqrestore(&pl->lock, flags); - return; - } - /* Aging zeroed our fraction? */ - if (period - pl->period < BITS_PER_LONG) - pl->events >>= period - pl->period; - else - pl->events = 0; - pl->period = period; - raw_spin_unlock_irqrestore(&pl->lock, flags); -} - -/* Event of type pl happened */ -void __fprop_inc_single(struct fprop_global *p, struct fprop_local_single *pl) -{ - fprop_reflect_period_single(p, pl); - pl->events++; - percpu_counter_add(&p->events, 1); -} - -/* Return fraction of events of type pl */ -void fprop_fraction_single(struct fprop_global *p, - struct fprop_local_single *pl, - unsigned long *numerator, unsigned long *denominator) -{ - unsigned int seq; - s64 num, den; - - do { - seq = read_seqcount_begin(&p->sequence); - fprop_reflect_period_single(p, pl); - num = pl->events; - den = percpu_counter_read_positive(&p->events); - } while (read_seqcount_retry(&p->sequence, seq)); - - /* - * Make fraction <= 1 and denominator > 0 even in presence of percpu - * counter errors - */ - if (den <= num) { - if (num) - den = num; - else - den = 1; - } - *denominator = den; - *numerator = num; -} - -/* - * ---- PERCPU ---- - */ -#define PROP_BATCH (8*(1+ilog2(nr_cpu_ids))) - -int fprop_local_init_percpu(struct fprop_local_percpu *pl, gfp_t gfp) -{ - int err; - - err = percpu_counter_init(&pl->events, 0, gfp); - if (err) - return err; - pl->period = 0; - raw_spin_lock_init(&pl->lock); - return 0; -} - -void fprop_local_destroy_percpu(struct fprop_local_percpu *pl) -{ - percpu_counter_destroy(&pl->events); -} - -static void fprop_reflect_period_percpu(struct fprop_global *p, - struct fprop_local_percpu *pl) -{ - unsigned int period = p->period; - unsigned long flags; - - /* Fast path - period didn't change */ - if (pl->period == period) - return; - raw_spin_lock_irqsave(&pl->lock, flags); - /* Someone updated pl->period while we were spinning? */ - if (pl->period >= period) { - raw_spin_unlock_irqrestore(&pl->lock, flags); - return; - } - /* Aging zeroed our fraction? */ - if (period - pl->period < BITS_PER_LONG) { - s64 val = percpu_counter_read(&pl->events); - - if (val < (nr_cpu_ids * PROP_BATCH)) - val = percpu_counter_sum(&pl->events); - - __percpu_counter_add(&pl->events, - -val + (val >> (period-pl->period)), PROP_BATCH); - } else - percpu_counter_set(&pl->events, 0); - pl->period = period; - raw_spin_unlock_irqrestore(&pl->lock, flags); -} - -/* Event of type pl happened */ -void __fprop_inc_percpu(struct fprop_global *p, struct fprop_local_percpu *pl) -{ - fprop_reflect_period_percpu(p, pl); - __percpu_counter_add(&pl->events, 1, PROP_BATCH); - percpu_counter_add(&p->events, 1); -} - -void fprop_fraction_percpu(struct fprop_global *p, - struct fprop_local_percpu *pl, - unsigned long *numerator, unsigned long *denominator) -{ - unsigned int seq; - s64 num, den; - - do { - seq = read_seqcount_begin(&p->sequence); - fprop_reflect_period_percpu(p, pl); - num = percpu_counter_read_positive(&pl->events); - den = percpu_counter_read_positive(&p->events); - } while (read_seqcount_retry(&p->sequence, seq)); - - /* - * Make fraction <= 1 and denominator > 0 even in presence of percpu - * counter errors - */ - if (den <= num) { - if (num) - den = num; - else - den = 1; - } - *denominator = den; - *numerator = num; -} - -/* - * Like __fprop_inc_percpu() except that event is counted only if the given - * type has fraction smaller than @max_frac/FPROP_FRAC_BASE - */ -void __fprop_inc_percpu_max(struct fprop_global *p, - struct fprop_local_percpu *pl, int max_frac) -{ - if (unlikely(max_frac < FPROP_FRAC_BASE)) { - unsigned long numerator, denominator; - - fprop_fraction_percpu(p, pl, &numerator, &denominator); - if (numerator > - (((u64)denominator) * max_frac) >> FPROP_FRAC_SHIFT) - return; - } else - fprop_reflect_period_percpu(p, pl); - __percpu_counter_add(&pl->events, 1, PROP_BATCH); - percpu_counter_add(&p->events, 1); -} diff --git a/src/linux/lib/fonts/Kconfig b/src/linux/lib/fonts/Kconfig deleted file mode 100644 index e77dfe0..0000000 --- a/src/linux/lib/fonts/Kconfig +++ /dev/null @@ -1,126 +0,0 @@ -# -# Font configuration -# - -config FONT_SUPPORT - tristate - -if FONT_SUPPORT - -config FONTS - bool "Select compiled-in fonts" - depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE - help - Say Y here if you would like to use fonts other than the default - your frame buffer console usually use. - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about foreign fonts. - - If unsure, say N (the default choices are safe). - -config FONT_8x8 - bool "VGA 8x8 font" if FONTS - depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE - default y if !SPARC && !FONTS - help - This is the "high resolution" font for the VGA frame buffer (the one - provided by the text console 80x50 (and higher) modes). - - Note that this is a poor quality font. The VGA 8x16 font is quite a - lot more readable. - - Given the resolution provided by the frame buffer device, answer N - here is safe. - -config FONT_8x16 - bool "VGA 8x16 font" if FONTS - default y if !SPARC && !FONTS - help - This is the "high resolution" font for the VGA frame buffer (the one - provided by the VGA text console 80x25 mode. - - If unsure, say Y. - -config FONT_6x11 - bool "Mac console 6x11 font (not supported by all drivers)" if FONTS - depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE - default y if !SPARC && !FONTS && MAC - help - Small console font with Macintosh-style high-half glyphs. Some Mac - framebuffer drivers don't support this one at all. - -config FONT_7x14 - bool "console 7x14 font (not supported by all drivers)" if FONTS - depends on FRAMEBUFFER_CONSOLE - help - Console font with characters just a bit smaller than the default. - If the standard 8x16 font is a little too big for you, say Y. - Otherwise, say N. - -config FONT_PEARL_8x8 - bool "Pearl (old m68k) console 8x8 font" if FONTS - depends on FRAMEBUFFER_CONSOLE - default y if !SPARC && !FONTS && AMIGA - help - Small console font with PC-style control-character and high-half - glyphs. - -config FONT_ACORN_8x8 - bool "Acorn console 8x8 font" if FONTS - depends on FRAMEBUFFER_CONSOLE - default y if !SPARC && !FONTS && ARM && ARCH_ACORN - help - Small console font with PC-style control characters and high-half - glyphs. - -config FONT_MINI_4x6 - bool "Mini 4x6 font" - depends on !SPARC && FONTS - -config FONT_6x10 - bool "Medium-size 6x10 font" - depends on !SPARC && FONTS - help - Medium-size console font. Suitable for framebuffer consoles on - embedded devices with a 320x240 screen, to get a reasonable number - of characters (53x24) that are still at a readable size. - -config FONT_SUN8x16 - bool "Sparc console 8x16 font" - depends on FRAMEBUFFER_CONSOLE && (!SPARC && FONTS || SPARC) - help - This is the high resolution console font for Sun machines. Say Y. - -config FONT_SUN12x22 - bool "Sparc console 12x22 font (not supported by all drivers)" - depends on FRAMEBUFFER_CONSOLE && (!SPARC && FONTS || SPARC) - help - This is the high resolution console font for Sun machines with very - big letters (like the letters used in the SPARC PROM). If the - standard font is unreadable for you, say Y, otherwise say N. - -config FONT_10x18 - bool "console 10x18 font (not supported by all drivers)" if FONTS - depends on FRAMEBUFFER_CONSOLE - help - This is a high resolution console font for machines with very - big letters. It fits between the sun 12x22 and the normal 8x16 font. - If other fonts are too big or too small for you, say Y, otherwise say N. - -config FONT_AUTOSELECT - def_bool y - depends on !FONT_8x8 - depends on !FONT_6x11 - depends on !FONT_7x14 - depends on !FONT_PEARL_8x8 - depends on !FONT_ACORN_8x8 - depends on !FONT_MINI_4x6 - depends on !FONT_6x10 - depends on !FONT_SUN8x16 - depends on !FONT_SUN12x22 - depends on !FONT_10x18 - select FONT_8x16 - -endif # FONT_SUPPORT diff --git a/src/linux/lib/gcd.c b/src/linux/lib/gcd.c deleted file mode 100644 index 135ee64..0000000 --- a/src/linux/lib/gcd.c +++ /dev/null @@ -1,78 +0,0 @@ -#include -#include -#include - -/* - * This implements the binary GCD algorithm. (Often attributed to Stein, - * but as Knuth has noted, appears in a first-century Chinese math text.) - * - * This is faster than the division-based algorithm even on x86, which - * has decent hardware division. - */ - -#if !defined(CONFIG_CPU_NO_EFFICIENT_FFS) && !defined(CPU_NO_EFFICIENT_FFS) - -/* If __ffs is available, the even/odd algorithm benchmarks slower. */ -unsigned long gcd(unsigned long a, unsigned long b) -{ - unsigned long r = a | b; - - if (!a || !b) - return r; - - b >>= __ffs(b); - if (b == 1) - return r & -r; - - for (;;) { - a >>= __ffs(a); - if (a == 1) - return r & -r; - if (a == b) - return a << __ffs(r); - - if (a < b) - swap(a, b); - a -= b; - } -} - -#else - -/* If normalization is done by loops, the even/odd algorithm is a win. */ -unsigned long gcd(unsigned long a, unsigned long b) -{ - unsigned long r = a | b; - - if (!a || !b) - return r; - - /* Isolate lsbit of r */ - r &= -r; - - while (!(b & r)) - b >>= 1; - if (b == r) - return r; - - for (;;) { - while (!(a & r)) - a >>= 1; - if (a == r) - return r; - if (a == b) - return a; - - if (a < b) - swap(a, b); - a -= b; - a >>= 1; - if (a & r) - a += b; - a >>= 1; - } -} - -#endif - -EXPORT_SYMBOL_GPL(gcd); diff --git a/src/linux/lib/gen_crc32table.c b/src/linux/lib/gen_crc32table.c deleted file mode 100644 index d83a372..0000000 --- a/src/linux/lib/gen_crc32table.c +++ /dev/null @@ -1,140 +0,0 @@ -#include -#include "../include/generated/autoconf.h" -#include "crc32defs.h" -#include - -#define ENTRIES_PER_LINE 4 - -#if CRC_LE_BITS > 8 -# define LE_TABLE_ROWS (CRC_LE_BITS/8) -# define LE_TABLE_SIZE 256 -#else -# define LE_TABLE_ROWS 1 -# define LE_TABLE_SIZE (1 << CRC_LE_BITS) -#endif - -#if CRC_BE_BITS > 8 -# define BE_TABLE_ROWS (CRC_BE_BITS/8) -# define BE_TABLE_SIZE 256 -#else -# define BE_TABLE_ROWS 1 -# define BE_TABLE_SIZE (1 << CRC_BE_BITS) -#endif - -static uint32_t crc32table_le[LE_TABLE_ROWS][256]; -static uint32_t crc32table_be[BE_TABLE_ROWS][256]; -static uint32_t crc32ctable_le[LE_TABLE_ROWS][256]; - -/** - * crc32init_le() - allocate and initialize LE table data - * - * crc is the crc of the byte i; other entries are filled in based on the - * fact that crctable[i^j] = crctable[i] ^ crctable[j]. - * - */ -static void crc32init_le_generic(const uint32_t polynomial, - uint32_t (*tab)[256]) -{ - unsigned i, j; - uint32_t crc = 1; - - tab[0][0] = 0; - - for (i = LE_TABLE_SIZE >> 1; i; i >>= 1) { - crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0); - for (j = 0; j < LE_TABLE_SIZE; j += 2 * i) - tab[0][i + j] = crc ^ tab[0][j]; - } - for (i = 0; i < LE_TABLE_SIZE; i++) { - crc = tab[0][i]; - for (j = 1; j < LE_TABLE_ROWS; j++) { - crc = tab[0][crc & 0xff] ^ (crc >> 8); - tab[j][i] = crc; - } - } -} - -static void crc32init_le(void) -{ - crc32init_le_generic(CRCPOLY_LE, crc32table_le); -} - -static void crc32cinit_le(void) -{ - crc32init_le_generic(CRC32C_POLY_LE, crc32ctable_le); -} - -/** - * crc32init_be() - allocate and initialize BE table data - */ -static void crc32init_be(void) -{ - unsigned i, j; - uint32_t crc = 0x80000000; - - crc32table_be[0][0] = 0; - - for (i = 1; i < BE_TABLE_SIZE; i <<= 1) { - crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0); - for (j = 0; j < i; j++) - crc32table_be[0][i + j] = crc ^ crc32table_be[0][j]; - } - for (i = 0; i < BE_TABLE_SIZE; i++) { - crc = crc32table_be[0][i]; - for (j = 1; j < BE_TABLE_ROWS; j++) { - crc = crc32table_be[0][(crc >> 24) & 0xff] ^ (crc << 8); - crc32table_be[j][i] = crc; - } - } -} - -static void output_table(uint32_t (*table)[256], int rows, int len, char *trans) -{ - int i, j; - - for (j = 0 ; j < rows; j++) { - printf("{"); - for (i = 0; i < len - 1; i++) { - if (i % ENTRIES_PER_LINE == 0) - printf("\n"); - printf("%s(0x%8.8xL), ", trans, table[j][i]); - } - printf("%s(0x%8.8xL)},\n", trans, table[j][len - 1]); - } -} - -int main(int argc, char** argv) -{ - printf("/* this file is generated - do not edit */\n\n"); - - if (CRC_LE_BITS > 1) { - crc32init_le(); - printf("static const u32 ____cacheline_aligned " - "crc32table_le[%d][%d] = {", - LE_TABLE_ROWS, LE_TABLE_SIZE); - output_table(crc32table_le, LE_TABLE_ROWS, - LE_TABLE_SIZE, "tole"); - printf("};\n"); - } - - if (CRC_BE_BITS > 1) { - crc32init_be(); - printf("static const u32 ____cacheline_aligned " - "crc32table_be[%d][%d] = {", - BE_TABLE_ROWS, BE_TABLE_SIZE); - output_table(crc32table_be, LE_TABLE_ROWS, - BE_TABLE_SIZE, "tobe"); - printf("};\n"); - } - if (CRC_LE_BITS > 1) { - crc32cinit_le(); - printf("static const u32 ____cacheline_aligned " - "crc32ctable_le[%d][%d] = {", - LE_TABLE_ROWS, LE_TABLE_SIZE); - output_table(crc32ctable_le, LE_TABLE_ROWS, - LE_TABLE_SIZE, "tole"); - printf("};\n"); - } - - return 0; -} diff --git a/src/linux/lib/halfmd4.c b/src/linux/lib/halfmd4.c deleted file mode 100644 index 137e861..0000000 --- a/src/linux/lib/halfmd4.c +++ /dev/null @@ -1,67 +0,0 @@ -#include -#include -#include -#include - -/* F, G and H are basic MD4 functions: selection, majority, parity */ -#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) -#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z))) -#define H(x, y, z) ((x) ^ (y) ^ (z)) - -/* - * The generic round function. The application is so specific that - * we don't bother protecting all the arguments with parens, as is generally - * good macro practice, in favor of extra legibility. - * Rotation is separate from addition to prevent recomputation - */ -#define ROUND(f, a, b, c, d, x, s) \ - (a += f(b, c, d) + x, a = rol32(a, s)) -#define K1 0 -#define K2 013240474631UL -#define K3 015666365641UL - -/* - * Basic cut-down MD4 transform. Returns only 32 bits of result. - */ -__u32 half_md4_transform(__u32 buf[4], __u32 const in[8]) -{ - __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; - - /* Round 1 */ - ROUND(F, a, b, c, d, in[0] + K1, 3); - ROUND(F, d, a, b, c, in[1] + K1, 7); - ROUND(F, c, d, a, b, in[2] + K1, 11); - ROUND(F, b, c, d, a, in[3] + K1, 19); - ROUND(F, a, b, c, d, in[4] + K1, 3); - ROUND(F, d, a, b, c, in[5] + K1, 7); - ROUND(F, c, d, a, b, in[6] + K1, 11); - ROUND(F, b, c, d, a, in[7] + K1, 19); - - /* Round 2 */ - ROUND(G, a, b, c, d, in[1] + K2, 3); - ROUND(G, d, a, b, c, in[3] + K2, 5); - ROUND(G, c, d, a, b, in[5] + K2, 9); - ROUND(G, b, c, d, a, in[7] + K2, 13); - ROUND(G, a, b, c, d, in[0] + K2, 3); - ROUND(G, d, a, b, c, in[2] + K2, 5); - ROUND(G, c, d, a, b, in[4] + K2, 9); - ROUND(G, b, c, d, a, in[6] + K2, 13); - - /* Round 3 */ - ROUND(H, a, b, c, d, in[3] + K3, 3); - ROUND(H, d, a, b, c, in[7] + K3, 9); - ROUND(H, c, d, a, b, in[2] + K3, 11); - ROUND(H, b, c, d, a, in[6] + K3, 15); - ROUND(H, a, b, c, d, in[1] + K3, 3); - ROUND(H, d, a, b, c, in[5] + K3, 9); - ROUND(H, c, d, a, b, in[0] + K3, 11); - ROUND(H, b, c, d, a, in[4] + K3, 15); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; - - return buf[1]; /* "most hashed" word */ -} -EXPORT_SYMBOL(half_md4_transform); diff --git a/src/linux/lib/hexdump.c b/src/linux/lib/hexdump.c deleted file mode 100644 index 992457b..0000000 --- a/src/linux/lib/hexdump.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * lib/hexdump.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. See README and COPYING for - * more details. - */ - -#include -#include -#include -#include -#include - -const char hex_asc[] = "0123456789abcdef"; -EXPORT_SYMBOL(hex_asc); -const char hex_asc_upper[] = "0123456789ABCDEF"; -EXPORT_SYMBOL(hex_asc_upper); - -/** - * hex_to_bin - convert a hex digit to its real value - * @ch: ascii character represents hex digit - * - * hex_to_bin() converts one hex digit to its actual value or -1 in case of bad - * input. - */ -int hex_to_bin(char ch) -{ - if ((ch >= '0') && (ch <= '9')) - return ch - '0'; - ch = tolower(ch); - if ((ch >= 'a') && (ch <= 'f')) - return ch - 'a' + 10; - return -1; -} -EXPORT_SYMBOL(hex_to_bin); - -/** - * hex2bin - convert an ascii hexadecimal string to its binary representation - * @dst: binary result - * @src: ascii hexadecimal string - * @count: result length - * - * Return 0 on success, -1 in case of bad input. - */ -int hex2bin(u8 *dst, const char *src, size_t count) -{ - while (count--) { - int hi = hex_to_bin(*src++); - int lo = hex_to_bin(*src++); - - if ((hi < 0) || (lo < 0)) - return -1; - - *dst++ = (hi << 4) | lo; - } - return 0; -} -EXPORT_SYMBOL(hex2bin); - -/** - * bin2hex - convert binary data to an ascii hexadecimal string - * @dst: ascii hexadecimal result - * @src: binary data - * @count: binary data length - */ -char *bin2hex(char *dst, const void *src, size_t count) -{ - const unsigned char *_src = src; - - while (count--) - dst = hex_byte_pack(dst, *_src++); - return dst; -} -EXPORT_SYMBOL(bin2hex); - -/** - * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory - * @buf: data blob to dump - * @len: number of bytes in the @buf - * @rowsize: number of bytes to print per line; must be 16 or 32 - * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1) - * @linebuf: where to put the converted data - * @linebuflen: total size of @linebuf, including space for terminating NUL - * @ascii: include ASCII after the hex output - * - * hex_dump_to_buffer() works on one "line" of output at a time, i.e., - * 16 or 32 bytes of input data converted to hex + ASCII output. - * - * Given a buffer of u8 data, hex_dump_to_buffer() converts the input data - * to a hex + ASCII dump at the supplied memory location. - * The converted output is always NUL-terminated. - * - * E.g.: - * hex_dump_to_buffer(frame->data, frame->len, 16, 1, - * linebuf, sizeof(linebuf), true); - * - * example output buffer: - * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO - * - * Return: - * The amount of bytes placed in the buffer without terminating NUL. If the - * output was truncated, then the return value is the number of bytes - * (excluding the terminating NUL) which would have been written to the final - * string if enough space had been available. - */ -int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize, - char *linebuf, size_t linebuflen, bool ascii) -{ - const u8 *ptr = buf; - int ngroups; - u8 ch; - int j, lx = 0; - int ascii_column; - int ret; - - if (rowsize != 16 && rowsize != 32) - rowsize = 16; - - if (len > rowsize) /* limit to one line at a time */ - len = rowsize; - if (!is_power_of_2(groupsize) || groupsize > 8) - groupsize = 1; - if ((len % groupsize) != 0) /* no mixed size output */ - groupsize = 1; - - ngroups = len / groupsize; - ascii_column = rowsize * 2 + rowsize / groupsize + 1; - - if (!linebuflen) - goto overflow1; - - if (!len) - goto nil; - - if (groupsize == 8) { - const u64 *ptr8 = buf; - - for (j = 0; j < ngroups; j++) { - ret = snprintf(linebuf + lx, linebuflen - lx, - "%s%16.16llx", j ? " " : "", - get_unaligned(ptr8 + j)); - if (ret >= linebuflen - lx) - goto overflow1; - lx += ret; - } - } else if (groupsize == 4) { - const u32 *ptr4 = buf; - - for (j = 0; j < ngroups; j++) { - ret = snprintf(linebuf + lx, linebuflen - lx, - "%s%8.8x", j ? " " : "", - get_unaligned(ptr4 + j)); - if (ret >= linebuflen - lx) - goto overflow1; - lx += ret; - } - } else if (groupsize == 2) { - const u16 *ptr2 = buf; - - for (j = 0; j < ngroups; j++) { - ret = snprintf(linebuf + lx, linebuflen - lx, - "%s%4.4x", j ? " " : "", - get_unaligned(ptr2 + j)); - if (ret >= linebuflen - lx) - goto overflow1; - lx += ret; - } - } else { - for (j = 0; j < len; j++) { - if (linebuflen < lx + 2) - goto overflow2; - ch = ptr[j]; - linebuf[lx++] = hex_asc_hi(ch); - if (linebuflen < lx + 2) - goto overflow2; - linebuf[lx++] = hex_asc_lo(ch); - if (linebuflen < lx + 2) - goto overflow2; - linebuf[lx++] = ' '; - } - if (j) - lx--; - } - if (!ascii) - goto nil; - - while (lx < ascii_column) { - if (linebuflen < lx + 2) - goto overflow2; - linebuf[lx++] = ' '; - } - for (j = 0; j < len; j++) { - if (linebuflen < lx + 2) - goto overflow2; - ch = ptr[j]; - linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.'; - } -nil: - linebuf[lx] = '\0'; - return lx; -overflow2: - linebuf[lx++] = '\0'; -overflow1: - return ascii ? ascii_column + len : (groupsize * 2 + 1) * ngroups - 1; -} -EXPORT_SYMBOL(hex_dump_to_buffer); - -#ifdef CONFIG_PRINTK -/** - * print_hex_dump - print a text hex dump to syslog for a binary blob of data - * @level: kernel log level (e.g. KERN_DEBUG) - * @prefix_str: string to prefix each line with; - * caller supplies trailing spaces for alignment if desired - * @prefix_type: controls whether prefix of an offset, address, or none - * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE) - * @rowsize: number of bytes to print per line; must be 16 or 32 - * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1) - * @buf: data blob to dump - * @len: number of bytes in the @buf - * @ascii: include ASCII after the hex output - * - * Given a buffer of u8 data, print_hex_dump() prints a hex + ASCII dump - * to the kernel log at the specified kernel log level, with an optional - * leading prefix. - * - * print_hex_dump() works on one "line" of output at a time, i.e., - * 16 or 32 bytes of input data converted to hex + ASCII output. - * print_hex_dump() iterates over the entire input @buf, breaking it into - * "line size" chunks to format and print. - * - * E.g.: - * print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_ADDRESS, - * 16, 1, frame->data, frame->len, true); - * - * Example output using %DUMP_PREFIX_OFFSET and 1-byte mode: - * 0009ab42: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO - * Example output using %DUMP_PREFIX_ADDRESS and 4-byte mode: - * ffffffff88089af0: 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~. - */ -void print_hex_dump(const char *level, const char *prefix_str, int prefix_type, - int rowsize, int groupsize, - const void *buf, size_t len, bool ascii) -{ - const u8 *ptr = buf; - int i, linelen, remaining = len; - unsigned char linebuf[32 * 3 + 2 + 32 + 1]; - - if (rowsize != 16 && rowsize != 32) - rowsize = 16; - - for (i = 0; i < len; i += rowsize) { - linelen = min(remaining, rowsize); - remaining -= rowsize; - - hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize, - linebuf, sizeof(linebuf), ascii); - - switch (prefix_type) { - case DUMP_PREFIX_ADDRESS: - printk("%s%s%p: %s\n", - level, prefix_str, ptr + i, linebuf); - break; - case DUMP_PREFIX_OFFSET: - printk("%s%s%.8x: %s\n", level, prefix_str, i, linebuf); - break; - default: - printk("%s%s%s\n", level, prefix_str, linebuf); - break; - } - } -} -EXPORT_SYMBOL(print_hex_dump); - -#if !defined(CONFIG_DYNAMIC_DEBUG) -/** - * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params - * @prefix_str: string to prefix each line with; - * caller supplies trailing spaces for alignment if desired - * @prefix_type: controls whether prefix of an offset, address, or none - * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE) - * @buf: data blob to dump - * @len: number of bytes in the @buf - * - * Calls print_hex_dump(), with log level of KERN_DEBUG, - * rowsize of 16, groupsize of 1, and ASCII output included. - */ -void print_hex_dump_bytes(const char *prefix_str, int prefix_type, - const void *buf, size_t len) -{ - print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, 16, 1, - buf, len, true); -} -EXPORT_SYMBOL(print_hex_dump_bytes); -#endif /* !defined(CONFIG_DYNAMIC_DEBUG) */ -#endif /* defined(CONFIG_PRINTK) */ diff --git a/src/linux/lib/hweight.c b/src/linux/lib/hweight.c deleted file mode 100644 index 43273a7..0000000 --- a/src/linux/lib/hweight.c +++ /dev/null @@ -1,71 +0,0 @@ -#include -#include -#include - -/** - * hweightN - returns the hamming weight of a N-bit word - * @x: the word to weigh - * - * The Hamming Weight of a number is the total number of bits set in it. - */ - -#ifndef __HAVE_ARCH_SW_HWEIGHT -unsigned int __sw_hweight32(unsigned int w) -{ -#ifdef CONFIG_ARCH_HAS_FAST_MULTIPLIER - w -= (w >> 1) & 0x55555555; - w = (w & 0x33333333) + ((w >> 2) & 0x33333333); - w = (w + (w >> 4)) & 0x0f0f0f0f; - return (w * 0x01010101) >> 24; -#else - unsigned int res = w - ((w >> 1) & 0x55555555); - res = (res & 0x33333333) + ((res >> 2) & 0x33333333); - res = (res + (res >> 4)) & 0x0F0F0F0F; - res = res + (res >> 8); - return (res + (res >> 16)) & 0x000000FF; -#endif -} -EXPORT_SYMBOL(__sw_hweight32); -#endif - -unsigned int __sw_hweight16(unsigned int w) -{ - unsigned int res = w - ((w >> 1) & 0x5555); - res = (res & 0x3333) + ((res >> 2) & 0x3333); - res = (res + (res >> 4)) & 0x0F0F; - return (res + (res >> 8)) & 0x00FF; -} -EXPORT_SYMBOL(__sw_hweight16); - -unsigned int __sw_hweight8(unsigned int w) -{ - unsigned int res = w - ((w >> 1) & 0x55); - res = (res & 0x33) + ((res >> 2) & 0x33); - return (res + (res >> 4)) & 0x0F; -} -EXPORT_SYMBOL(__sw_hweight8); - -#ifndef __HAVE_ARCH_SW_HWEIGHT -unsigned long __sw_hweight64(__u64 w) -{ -#if BITS_PER_LONG == 32 - return __sw_hweight32((unsigned int)(w >> 32)) + - __sw_hweight32((unsigned int)w); -#elif BITS_PER_LONG == 64 -#ifdef CONFIG_ARCH_HAS_FAST_MULTIPLIER - w -= (w >> 1) & 0x5555555555555555ul; - w = (w & 0x3333333333333333ul) + ((w >> 2) & 0x3333333333333333ul); - w = (w + (w >> 4)) & 0x0f0f0f0f0f0f0f0ful; - return (w * 0x0101010101010101ul) >> 56; -#else - __u64 res = w - ((w >> 1) & 0x5555555555555555ul); - res = (res & 0x3333333333333333ul) + ((res >> 2) & 0x3333333333333333ul); - res = (res + (res >> 4)) & 0x0F0F0F0F0F0F0F0Ful; - res = res + (res >> 8); - res = res + (res >> 16); - return (res + (res >> 32)) & 0x00000000000000FFul; -#endif -#endif -} -EXPORT_SYMBOL(__sw_hweight64); -#endif diff --git a/src/linux/lib/idr.c b/src/linux/lib/idr.c deleted file mode 100644 index 6098336..0000000 --- a/src/linux/lib/idr.c +++ /dev/null @@ -1,1147 +0,0 @@ -/* - * 2002-10-18 written by Jim Houston jim.houston@ccur.com - * Copyright (C) 2002 by Concurrent Computer Corporation - * Distributed under the GNU GPL license version 2. - * - * Modified by George Anzinger to reuse immediately and to use - * find bit instructions. Also removed _irq on spinlocks. - * - * Modified by Nadia Derbey to make it RCU safe. - * - * Small id to pointer translation service. - * - * It uses a radix tree like structure as a sparse array indexed - * by the id to obtain the pointer. The bitmap makes allocating - * a new id quick. - * - * You call it to allocate an id (an int) an associate with that id a - * pointer or what ever, we treat it as a (void *). You can pass this - * id to a user for him to pass back at a later time. You then pass - * that id to this code and it returns your pointer. - */ - -#ifndef TEST // to test in user space... -#include -#include -#include -#endif -#include -#include -#include -#include -#include - -#define MAX_IDR_SHIFT (sizeof(int) * 8 - 1) -#define MAX_IDR_BIT (1U << MAX_IDR_SHIFT) - -/* Leave the possibility of an incomplete final layer */ -#define MAX_IDR_LEVEL ((MAX_IDR_SHIFT + IDR_BITS - 1) / IDR_BITS) - -/* Number of id_layer structs to leave in free list */ -#define MAX_IDR_FREE (MAX_IDR_LEVEL * 2) - -static struct kmem_cache *idr_layer_cache; -static DEFINE_PER_CPU(struct idr_layer *, idr_preload_head); -static DEFINE_PER_CPU(int, idr_preload_cnt); -static DEFINE_SPINLOCK(simple_ida_lock); - -/* the maximum ID which can be allocated given idr->layers */ -static int idr_max(int layers) -{ - int bits = min_t(int, layers * IDR_BITS, MAX_IDR_SHIFT); - - return (1 << bits) - 1; -} - -/* - * Prefix mask for an idr_layer at @layer. For layer 0, the prefix mask is - * all bits except for the lower IDR_BITS. For layer 1, 2 * IDR_BITS, and - * so on. - */ -static int idr_layer_prefix_mask(int layer) -{ - return ~idr_max(layer + 1); -} - -static struct idr_layer *get_from_free_list(struct idr *idp) -{ - struct idr_layer *p; - unsigned long flags; - - spin_lock_irqsave(&idp->lock, flags); - if ((p = idp->id_free)) { - idp->id_free = p->ary[0]; - idp->id_free_cnt--; - p->ary[0] = NULL; - } - spin_unlock_irqrestore(&idp->lock, flags); - return(p); -} - -/** - * idr_layer_alloc - allocate a new idr_layer - * @gfp_mask: allocation mask - * @layer_idr: optional idr to allocate from - * - * If @layer_idr is %NULL, directly allocate one using @gfp_mask or fetch - * one from the per-cpu preload buffer. If @layer_idr is not %NULL, fetch - * an idr_layer from @idr->id_free. - * - * @layer_idr is to maintain backward compatibility with the old alloc - * interface - idr_pre_get() and idr_get_new*() - and will be removed - * together with per-pool preload buffer. - */ -static struct idr_layer *idr_layer_alloc(gfp_t gfp_mask, struct idr *layer_idr) -{ - struct idr_layer *new; - - /* this is the old path, bypass to get_from_free_list() */ - if (layer_idr) - return get_from_free_list(layer_idr); - - /* - * Try to allocate directly from kmem_cache. We want to try this - * before preload buffer; otherwise, non-preloading idr_alloc() - * users will end up taking advantage of preloading ones. As the - * following is allowed to fail for preloaded cases, suppress - * warning this time. - */ - new = kmem_cache_zalloc(idr_layer_cache, gfp_mask | __GFP_NOWARN); - if (new) - return new; - - /* - * Try to fetch one from the per-cpu preload buffer if in process - * context. See idr_preload() for details. - */ - if (!in_interrupt()) { - preempt_disable(); - new = __this_cpu_read(idr_preload_head); - if (new) { - __this_cpu_write(idr_preload_head, new->ary[0]); - __this_cpu_dec(idr_preload_cnt); - new->ary[0] = NULL; - } - preempt_enable(); - if (new) - return new; - } - - /* - * Both failed. Try kmem_cache again w/o adding __GFP_NOWARN so - * that memory allocation failure warning is printed as intended. - */ - return kmem_cache_zalloc(idr_layer_cache, gfp_mask); -} - -static void idr_layer_rcu_free(struct rcu_head *head) -{ - struct idr_layer *layer; - - layer = container_of(head, struct idr_layer, rcu_head); - kmem_cache_free(idr_layer_cache, layer); -} - -static inline void free_layer(struct idr *idr, struct idr_layer *p) -{ - if (idr->hint == p) - RCU_INIT_POINTER(idr->hint, NULL); - call_rcu(&p->rcu_head, idr_layer_rcu_free); -} - -/* only called when idp->lock is held */ -static void __move_to_free_list(struct idr *idp, struct idr_layer *p) -{ - p->ary[0] = idp->id_free; - idp->id_free = p; - idp->id_free_cnt++; -} - -static void move_to_free_list(struct idr *idp, struct idr_layer *p) -{ - unsigned long flags; - - /* - * Depends on the return element being zeroed. - */ - spin_lock_irqsave(&idp->lock, flags); - __move_to_free_list(idp, p); - spin_unlock_irqrestore(&idp->lock, flags); -} - -static void idr_mark_full(struct idr_layer **pa, int id) -{ - struct idr_layer *p = pa[0]; - int l = 0; - - __set_bit(id & IDR_MASK, p->bitmap); - /* - * If this layer is full mark the bit in the layer above to - * show that this part of the radix tree is full. This may - * complete the layer above and require walking up the radix - * tree. - */ - while (bitmap_full(p->bitmap, IDR_SIZE)) { - if (!(p = pa[++l])) - break; - id = id >> IDR_BITS; - __set_bit((id & IDR_MASK), p->bitmap); - } -} - -static int __idr_pre_get(struct idr *idp, gfp_t gfp_mask) -{ - while (idp->id_free_cnt < MAX_IDR_FREE) { - struct idr_layer *new; - new = kmem_cache_zalloc(idr_layer_cache, gfp_mask); - if (new == NULL) - return (0); - move_to_free_list(idp, new); - } - return 1; -} - -/** - * sub_alloc - try to allocate an id without growing the tree depth - * @idp: idr handle - * @starting_id: id to start search at - * @pa: idr_layer[MAX_IDR_LEVEL] used as backtrack buffer - * @gfp_mask: allocation mask for idr_layer_alloc() - * @layer_idr: optional idr passed to idr_layer_alloc() - * - * Allocate an id in range [@starting_id, INT_MAX] from @idp without - * growing its depth. Returns - * - * the allocated id >= 0 if successful, - * -EAGAIN if the tree needs to grow for allocation to succeed, - * -ENOSPC if the id space is exhausted, - * -ENOMEM if more idr_layers need to be allocated. - */ -static int sub_alloc(struct idr *idp, int *starting_id, struct idr_layer **pa, - gfp_t gfp_mask, struct idr *layer_idr) -{ - int n, m, sh; - struct idr_layer *p, *new; - int l, id, oid; - - id = *starting_id; - restart: - p = idp->top; - l = idp->layers; - pa[l--] = NULL; - while (1) { - /* - * We run around this while until we reach the leaf node... - */ - n = (id >> (IDR_BITS*l)) & IDR_MASK; - m = find_next_zero_bit(p->bitmap, IDR_SIZE, n); - if (m == IDR_SIZE) { - /* no space available go back to previous layer. */ - l++; - oid = id; - id = (id | ((1 << (IDR_BITS * l)) - 1)) + 1; - - /* if already at the top layer, we need to grow */ - if (id > idr_max(idp->layers)) { - *starting_id = id; - return -EAGAIN; - } - p = pa[l]; - BUG_ON(!p); - - /* If we need to go up one layer, continue the - * loop; otherwise, restart from the top. - */ - sh = IDR_BITS * (l + 1); - if (oid >> sh == id >> sh) - continue; - else - goto restart; - } - if (m != n) { - sh = IDR_BITS*l; - id = ((id >> sh) ^ n ^ m) << sh; - } - if ((id >= MAX_IDR_BIT) || (id < 0)) - return -ENOSPC; - if (l == 0) - break; - /* - * Create the layer below if it is missing. - */ - if (!p->ary[m]) { - new = idr_layer_alloc(gfp_mask, layer_idr); - if (!new) - return -ENOMEM; - new->layer = l-1; - new->prefix = id & idr_layer_prefix_mask(new->layer); - rcu_assign_pointer(p->ary[m], new); - p->count++; - } - pa[l--] = p; - p = p->ary[m]; - } - - pa[l] = p; - return id; -} - -static int idr_get_empty_slot(struct idr *idp, int starting_id, - struct idr_layer **pa, gfp_t gfp_mask, - struct idr *layer_idr) -{ - struct idr_layer *p, *new; - int layers, v, id; - unsigned long flags; - - id = starting_id; -build_up: - p = idp->top; - layers = idp->layers; - if (unlikely(!p)) { - if (!(p = idr_layer_alloc(gfp_mask, layer_idr))) - return -ENOMEM; - p->layer = 0; - layers = 1; - } - /* - * Add a new layer to the top of the tree if the requested - * id is larger than the currently allocated space. - */ - while (id > idr_max(layers)) { - layers++; - if (!p->count) { - /* special case: if the tree is currently empty, - * then we grow the tree by moving the top node - * upwards. - */ - p->layer++; - WARN_ON_ONCE(p->prefix); - continue; - } - if (!(new = idr_layer_alloc(gfp_mask, layer_idr))) { - /* - * The allocation failed. If we built part of - * the structure tear it down. - */ - spin_lock_irqsave(&idp->lock, flags); - for (new = p; p && p != idp->top; new = p) { - p = p->ary[0]; - new->ary[0] = NULL; - new->count = 0; - bitmap_clear(new->bitmap, 0, IDR_SIZE); - __move_to_free_list(idp, new); - } - spin_unlock_irqrestore(&idp->lock, flags); - return -ENOMEM; - } - new->ary[0] = p; - new->count = 1; - new->layer = layers-1; - new->prefix = id & idr_layer_prefix_mask(new->layer); - if (bitmap_full(p->bitmap, IDR_SIZE)) - __set_bit(0, new->bitmap); - p = new; - } - rcu_assign_pointer(idp->top, p); - idp->layers = layers; - v = sub_alloc(idp, &id, pa, gfp_mask, layer_idr); - if (v == -EAGAIN) - goto build_up; - return(v); -} - -/* - * @id and @pa are from a successful allocation from idr_get_empty_slot(). - * Install the user pointer @ptr and mark the slot full. - */ -static void idr_fill_slot(struct idr *idr, void *ptr, int id, - struct idr_layer **pa) -{ - /* update hint used for lookup, cleared from free_layer() */ - rcu_assign_pointer(idr->hint, pa[0]); - - rcu_assign_pointer(pa[0]->ary[id & IDR_MASK], (struct idr_layer *)ptr); - pa[0]->count++; - idr_mark_full(pa, id); -} - - -/** - * idr_preload - preload for idr_alloc() - * @gfp_mask: allocation mask to use for preloading - * - * Preload per-cpu layer buffer for idr_alloc(). Can only be used from - * process context and each idr_preload() invocation should be matched with - * idr_preload_end(). Note that preemption is disabled while preloaded. - * - * The first idr_alloc() in the preloaded section can be treated as if it - * were invoked with @gfp_mask used for preloading. This allows using more - * permissive allocation masks for idrs protected by spinlocks. - * - * For example, if idr_alloc() below fails, the failure can be treated as - * if idr_alloc() were called with GFP_KERNEL rather than GFP_NOWAIT. - * - * idr_preload(GFP_KERNEL); - * spin_lock(lock); - * - * id = idr_alloc(idr, ptr, start, end, GFP_NOWAIT); - * - * spin_unlock(lock); - * idr_preload_end(); - * if (id < 0) - * error; - */ -void idr_preload(gfp_t gfp_mask) -{ - /* - * Consuming preload buffer from non-process context breaks preload - * allocation guarantee. Disallow usage from those contexts. - */ - WARN_ON_ONCE(in_interrupt()); - might_sleep_if(gfpflags_allow_blocking(gfp_mask)); - - preempt_disable(); - - /* - * idr_alloc() is likely to succeed w/o full idr_layer buffer and - * return value from idr_alloc() needs to be checked for failure - * anyway. Silently give up if allocation fails. The caller can - * treat failures from idr_alloc() as if idr_alloc() were called - * with @gfp_mask which should be enough. - */ - while (__this_cpu_read(idr_preload_cnt) < MAX_IDR_FREE) { - struct idr_layer *new; - - preempt_enable(); - new = kmem_cache_zalloc(idr_layer_cache, gfp_mask); - preempt_disable(); - if (!new) - break; - - /* link the new one to per-cpu preload list */ - new->ary[0] = __this_cpu_read(idr_preload_head); - __this_cpu_write(idr_preload_head, new); - __this_cpu_inc(idr_preload_cnt); - } -} -EXPORT_SYMBOL(idr_preload); - -/** - * idr_alloc - allocate new idr entry - * @idr: the (initialized) idr - * @ptr: pointer to be associated with the new id - * @start: the minimum id (inclusive) - * @end: the maximum id (exclusive, <= 0 for max) - * @gfp_mask: memory allocation flags - * - * Allocate an id in [start, end) and associate it with @ptr. If no ID is - * available in the specified range, returns -ENOSPC. On memory allocation - * failure, returns -ENOMEM. - * - * Note that @end is treated as max when <= 0. This is to always allow - * using @start + N as @end as long as N is inside integer range. - * - * The user is responsible for exclusively synchronizing all operations - * which may modify @idr. However, read-only accesses such as idr_find() - * or iteration can be performed under RCU read lock provided the user - * destroys @ptr in RCU-safe way after removal from idr. - */ -int idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp_mask) -{ - int max = end > 0 ? end - 1 : INT_MAX; /* inclusive upper limit */ - struct idr_layer *pa[MAX_IDR_LEVEL + 1]; - int id; - - might_sleep_if(gfpflags_allow_blocking(gfp_mask)); - - /* sanity checks */ - if (WARN_ON_ONCE(start < 0)) - return -EINVAL; - if (unlikely(max < start)) - return -ENOSPC; - - /* allocate id */ - id = idr_get_empty_slot(idr, start, pa, gfp_mask, NULL); - if (unlikely(id < 0)) - return id; - if (unlikely(id > max)) - return -ENOSPC; - - idr_fill_slot(idr, ptr, id, pa); - return id; -} -EXPORT_SYMBOL_GPL(idr_alloc); - -/** - * idr_alloc_cyclic - allocate new idr entry in a cyclical fashion - * @idr: the (initialized) idr - * @ptr: pointer to be associated with the new id - * @start: the minimum id (inclusive) - * @end: the maximum id (exclusive, <= 0 for max) - * @gfp_mask: memory allocation flags - * - * Essentially the same as idr_alloc, but prefers to allocate progressively - * higher ids if it can. If the "cur" counter wraps, then it will start again - * at the "start" end of the range and allocate one that has already been used. - */ -int idr_alloc_cyclic(struct idr *idr, void *ptr, int start, int end, - gfp_t gfp_mask) -{ - int id; - - id = idr_alloc(idr, ptr, max(start, idr->cur), end, gfp_mask); - if (id == -ENOSPC) - id = idr_alloc(idr, ptr, start, end, gfp_mask); - - if (likely(id >= 0)) - idr->cur = id + 1; - return id; -} -EXPORT_SYMBOL(idr_alloc_cyclic); - -static void idr_remove_warning(int id) -{ - WARN(1, "idr_remove called for id=%d which is not allocated.\n", id); -} - -static void sub_remove(struct idr *idp, int shift, int id) -{ - struct idr_layer *p = idp->top; - struct idr_layer **pa[MAX_IDR_LEVEL + 1]; - struct idr_layer ***paa = &pa[0]; - struct idr_layer *to_free; - int n; - - *paa = NULL; - *++paa = &idp->top; - - while ((shift > 0) && p) { - n = (id >> shift) & IDR_MASK; - __clear_bit(n, p->bitmap); - *++paa = &p->ary[n]; - p = p->ary[n]; - shift -= IDR_BITS; - } - n = id & IDR_MASK; - if (likely(p != NULL && test_bit(n, p->bitmap))) { - __clear_bit(n, p->bitmap); - RCU_INIT_POINTER(p->ary[n], NULL); - to_free = NULL; - while(*paa && ! --((**paa)->count)){ - if (to_free) - free_layer(idp, to_free); - to_free = **paa; - **paa-- = NULL; - } - if (!*paa) - idp->layers = 0; - if (to_free) - free_layer(idp, to_free); - } else - idr_remove_warning(id); -} - -/** - * idr_remove - remove the given id and free its slot - * @idp: idr handle - * @id: unique key - */ -void idr_remove(struct idr *idp, int id) -{ - struct idr_layer *p; - struct idr_layer *to_free; - - if (id < 0) - return; - - if (id > idr_max(idp->layers)) { - idr_remove_warning(id); - return; - } - - sub_remove(idp, (idp->layers - 1) * IDR_BITS, id); - if (idp->top && idp->top->count == 1 && (idp->layers > 1) && - idp->top->ary[0]) { - /* - * Single child at leftmost slot: we can shrink the tree. - * This level is not needed anymore since when layers are - * inserted, they are inserted at the top of the existing - * tree. - */ - to_free = idp->top; - p = idp->top->ary[0]; - rcu_assign_pointer(idp->top, p); - --idp->layers; - to_free->count = 0; - bitmap_clear(to_free->bitmap, 0, IDR_SIZE); - free_layer(idp, to_free); - } -} -EXPORT_SYMBOL(idr_remove); - -static void __idr_remove_all(struct idr *idp) -{ - int n, id, max; - int bt_mask; - struct idr_layer *p; - struct idr_layer *pa[MAX_IDR_LEVEL + 1]; - struct idr_layer **paa = &pa[0]; - - n = idp->layers * IDR_BITS; - *paa = idp->top; - RCU_INIT_POINTER(idp->top, NULL); - max = idr_max(idp->layers); - - id = 0; - while (id >= 0 && id <= max) { - p = *paa; - while (n > IDR_BITS && p) { - n -= IDR_BITS; - p = p->ary[(id >> n) & IDR_MASK]; - *++paa = p; - } - - bt_mask = id; - id += 1 << n; - /* Get the highest bit that the above add changed from 0->1. */ - while (n < fls(id ^ bt_mask)) { - if (*paa) - free_layer(idp, *paa); - n += IDR_BITS; - --paa; - } - } - idp->layers = 0; -} - -/** - * idr_destroy - release all cached layers within an idr tree - * @idp: idr handle - * - * Free all id mappings and all idp_layers. After this function, @idp is - * completely unused and can be freed / recycled. The caller is - * responsible for ensuring that no one else accesses @idp during or after - * idr_destroy(). - * - * A typical clean-up sequence for objects stored in an idr tree will use - * idr_for_each() to free all objects, if necessary, then idr_destroy() to - * free up the id mappings and cached idr_layers. - */ -void idr_destroy(struct idr *idp) -{ - __idr_remove_all(idp); - - while (idp->id_free_cnt) { - struct idr_layer *p = get_from_free_list(idp); - kmem_cache_free(idr_layer_cache, p); - } -} -EXPORT_SYMBOL(idr_destroy); - -void *idr_find_slowpath(struct idr *idp, int id) -{ - int n; - struct idr_layer *p; - - if (id < 0) - return NULL; - - p = rcu_dereference_raw(idp->top); - if (!p) - return NULL; - n = (p->layer+1) * IDR_BITS; - - if (id > idr_max(p->layer + 1)) - return NULL; - BUG_ON(n == 0); - - while (n > 0 && p) { - n -= IDR_BITS; - BUG_ON(n != p->layer*IDR_BITS); - p = rcu_dereference_raw(p->ary[(id >> n) & IDR_MASK]); - } - return((void *)p); -} -EXPORT_SYMBOL(idr_find_slowpath); - -/** - * idr_for_each - iterate through all stored pointers - * @idp: idr handle - * @fn: function to be called for each pointer - * @data: data passed back to callback function - * - * Iterate over the pointers registered with the given idr. The - * callback function will be called for each pointer currently - * registered, passing the id, the pointer and the data pointer passed - * to this function. It is not safe to modify the idr tree while in - * the callback, so functions such as idr_get_new and idr_remove are - * not allowed. - * - * We check the return of @fn each time. If it returns anything other - * than %0, we break out and return that value. - * - * The caller must serialize idr_for_each() vs idr_get_new() and idr_remove(). - */ -int idr_for_each(struct idr *idp, - int (*fn)(int id, void *p, void *data), void *data) -{ - int n, id, max, error = 0; - struct idr_layer *p; - struct idr_layer *pa[MAX_IDR_LEVEL + 1]; - struct idr_layer **paa = &pa[0]; - - n = idp->layers * IDR_BITS; - *paa = rcu_dereference_raw(idp->top); - max = idr_max(idp->layers); - - id = 0; - while (id >= 0 && id <= max) { - p = *paa; - while (n > 0 && p) { - n -= IDR_BITS; - p = rcu_dereference_raw(p->ary[(id >> n) & IDR_MASK]); - *++paa = p; - } - - if (p) { - error = fn(id, (void *)p, data); - if (error) - break; - } - - id += 1 << n; - while (n < fls(id)) { - n += IDR_BITS; - --paa; - } - } - - return error; -} -EXPORT_SYMBOL(idr_for_each); - -/** - * idr_get_next - lookup next object of id to given id. - * @idp: idr handle - * @nextidp: pointer to lookup key - * - * Returns pointer to registered object with id, which is next number to - * given id. After being looked up, *@nextidp will be updated for the next - * iteration. - * - * This function can be called under rcu_read_lock(), given that the leaf - * pointers lifetimes are correctly managed. - */ -void *idr_get_next(struct idr *idp, int *nextidp) -{ - struct idr_layer *p, *pa[MAX_IDR_LEVEL + 1]; - struct idr_layer **paa = &pa[0]; - int id = *nextidp; - int n, max; - - /* find first ent */ - p = *paa = rcu_dereference_raw(idp->top); - if (!p) - return NULL; - n = (p->layer + 1) * IDR_BITS; - max = idr_max(p->layer + 1); - - while (id >= 0 && id <= max) { - p = *paa; - while (n > 0 && p) { - n -= IDR_BITS; - p = rcu_dereference_raw(p->ary[(id >> n) & IDR_MASK]); - *++paa = p; - } - - if (p) { - *nextidp = id; - return p; - } - - /* - * Proceed to the next layer at the current level. Unlike - * idr_for_each(), @id isn't guaranteed to be aligned to - * layer boundary at this point and adding 1 << n may - * incorrectly skip IDs. Make sure we jump to the - * beginning of the next layer using round_up(). - */ - id = round_up(id + 1, 1 << n); - while (n < fls(id)) { - n += IDR_BITS; - --paa; - } - } - return NULL; -} -EXPORT_SYMBOL(idr_get_next); - - -/** - * idr_replace - replace pointer for given id - * @idp: idr handle - * @ptr: pointer you want associated with the id - * @id: lookup key - * - * Replace the pointer registered with an id and return the old value. - * A %-ENOENT return indicates that @id was not found. - * A %-EINVAL return indicates that @id was not within valid constraints. - * - * The caller must serialize with writers. - */ -void *idr_replace(struct idr *idp, void *ptr, int id) -{ - int n; - struct idr_layer *p, *old_p; - - if (id < 0) - return ERR_PTR(-EINVAL); - - p = idp->top; - if (!p) - return ERR_PTR(-ENOENT); - - if (id > idr_max(p->layer + 1)) - return ERR_PTR(-ENOENT); - - n = p->layer * IDR_BITS; - while ((n > 0) && p) { - p = p->ary[(id >> n) & IDR_MASK]; - n -= IDR_BITS; - } - - n = id & IDR_MASK; - if (unlikely(p == NULL || !test_bit(n, p->bitmap))) - return ERR_PTR(-ENOENT); - - old_p = p->ary[n]; - rcu_assign_pointer(p->ary[n], ptr); - - return old_p; -} -EXPORT_SYMBOL(idr_replace); - -void __init idr_init_cache(void) -{ - idr_layer_cache = kmem_cache_create("idr_layer_cache", - sizeof(struct idr_layer), 0, SLAB_PANIC, NULL); -} - -/** - * idr_init - initialize idr handle - * @idp: idr handle - * - * This function is use to set up the handle (@idp) that you will pass - * to the rest of the functions. - */ -void idr_init(struct idr *idp) -{ - memset(idp, 0, sizeof(struct idr)); - spin_lock_init(&idp->lock); -} -EXPORT_SYMBOL(idr_init); - -static int idr_has_entry(int id, void *p, void *data) -{ - return 1; -} - -bool idr_is_empty(struct idr *idp) -{ - return !idr_for_each(idp, idr_has_entry, NULL); -} -EXPORT_SYMBOL(idr_is_empty); - -/** - * DOC: IDA description - * IDA - IDR based ID allocator - * - * This is id allocator without id -> pointer translation. Memory - * usage is much lower than full blown idr because each id only - * occupies a bit. ida uses a custom leaf node which contains - * IDA_BITMAP_BITS slots. - * - * 2007-04-25 written by Tejun Heo - */ - -static void free_bitmap(struct ida *ida, struct ida_bitmap *bitmap) -{ - unsigned long flags; - - if (!ida->free_bitmap) { - spin_lock_irqsave(&ida->idr.lock, flags); - if (!ida->free_bitmap) { - ida->free_bitmap = bitmap; - bitmap = NULL; - } - spin_unlock_irqrestore(&ida->idr.lock, flags); - } - - kfree(bitmap); -} - -/** - * ida_pre_get - reserve resources for ida allocation - * @ida: ida handle - * @gfp_mask: memory allocation flag - * - * This function should be called prior to locking and calling the - * following function. It preallocates enough memory to satisfy the - * worst possible allocation. - * - * If the system is REALLY out of memory this function returns %0, - * otherwise %1. - */ -int ida_pre_get(struct ida *ida, gfp_t gfp_mask) -{ - /* allocate idr_layers */ - if (!__idr_pre_get(&ida->idr, gfp_mask)) - return 0; - - /* allocate free_bitmap */ - if (!ida->free_bitmap) { - struct ida_bitmap *bitmap; - - bitmap = kmalloc(sizeof(struct ida_bitmap), gfp_mask); - if (!bitmap) - return 0; - - free_bitmap(ida, bitmap); - } - - return 1; -} -EXPORT_SYMBOL(ida_pre_get); - -/** - * ida_get_new_above - allocate new ID above or equal to a start id - * @ida: ida handle - * @starting_id: id to start search at - * @p_id: pointer to the allocated handle - * - * Allocate new ID above or equal to @starting_id. It should be called - * with any required locks. - * - * If memory is required, it will return %-EAGAIN, you should unlock - * and go back to the ida_pre_get() call. If the ida is full, it will - * return %-ENOSPC. - * - * @p_id returns a value in the range @starting_id ... %0x7fffffff. - */ -int ida_get_new_above(struct ida *ida, int starting_id, int *p_id) -{ - struct idr_layer *pa[MAX_IDR_LEVEL + 1]; - struct ida_bitmap *bitmap; - unsigned long flags; - int idr_id = starting_id / IDA_BITMAP_BITS; - int offset = starting_id % IDA_BITMAP_BITS; - int t, id; - - restart: - /* get vacant slot */ - t = idr_get_empty_slot(&ida->idr, idr_id, pa, 0, &ida->idr); - if (t < 0) - return t == -ENOMEM ? -EAGAIN : t; - - if (t * IDA_BITMAP_BITS >= MAX_IDR_BIT) - return -ENOSPC; - - if (t != idr_id) - offset = 0; - idr_id = t; - - /* if bitmap isn't there, create a new one */ - bitmap = (void *)pa[0]->ary[idr_id & IDR_MASK]; - if (!bitmap) { - spin_lock_irqsave(&ida->idr.lock, flags); - bitmap = ida->free_bitmap; - ida->free_bitmap = NULL; - spin_unlock_irqrestore(&ida->idr.lock, flags); - - if (!bitmap) - return -EAGAIN; - - memset(bitmap, 0, sizeof(struct ida_bitmap)); - rcu_assign_pointer(pa[0]->ary[idr_id & IDR_MASK], - (void *)bitmap); - pa[0]->count++; - } - - /* lookup for empty slot */ - t = find_next_zero_bit(bitmap->bitmap, IDA_BITMAP_BITS, offset); - if (t == IDA_BITMAP_BITS) { - /* no empty slot after offset, continue to the next chunk */ - idr_id++; - offset = 0; - goto restart; - } - - id = idr_id * IDA_BITMAP_BITS + t; - if (id >= MAX_IDR_BIT) - return -ENOSPC; - - __set_bit(t, bitmap->bitmap); - if (++bitmap->nr_busy == IDA_BITMAP_BITS) - idr_mark_full(pa, idr_id); - - *p_id = id; - - /* Each leaf node can handle nearly a thousand slots and the - * whole idea of ida is to have small memory foot print. - * Throw away extra resources one by one after each successful - * allocation. - */ - if (ida->idr.id_free_cnt || ida->free_bitmap) { - struct idr_layer *p = get_from_free_list(&ida->idr); - if (p) - kmem_cache_free(idr_layer_cache, p); - } - - return 0; -} -EXPORT_SYMBOL(ida_get_new_above); - -/** - * ida_remove - remove the given ID - * @ida: ida handle - * @id: ID to free - */ -void ida_remove(struct ida *ida, int id) -{ - struct idr_layer *p = ida->idr.top; - int shift = (ida->idr.layers - 1) * IDR_BITS; - int idr_id = id / IDA_BITMAP_BITS; - int offset = id % IDA_BITMAP_BITS; - int n; - struct ida_bitmap *bitmap; - - if (idr_id > idr_max(ida->idr.layers)) - goto err; - - /* clear full bits while looking up the leaf idr_layer */ - while ((shift > 0) && p) { - n = (idr_id >> shift) & IDR_MASK; - __clear_bit(n, p->bitmap); - p = p->ary[n]; - shift -= IDR_BITS; - } - - if (p == NULL) - goto err; - - n = idr_id & IDR_MASK; - __clear_bit(n, p->bitmap); - - bitmap = (void *)p->ary[n]; - if (!bitmap || !test_bit(offset, bitmap->bitmap)) - goto err; - - /* update bitmap and remove it if empty */ - __clear_bit(offset, bitmap->bitmap); - if (--bitmap->nr_busy == 0) { - __set_bit(n, p->bitmap); /* to please idr_remove() */ - idr_remove(&ida->idr, idr_id); - free_bitmap(ida, bitmap); - } - - return; - - err: - WARN(1, "ida_remove called for id=%d which is not allocated.\n", id); -} -EXPORT_SYMBOL(ida_remove); - -/** - * ida_destroy - release all cached layers within an ida tree - * @ida: ida handle - */ -void ida_destroy(struct ida *ida) -{ - idr_destroy(&ida->idr); - kfree(ida->free_bitmap); -} -EXPORT_SYMBOL(ida_destroy); - -/** - * ida_simple_get - get a new id. - * @ida: the (initialized) ida. - * @start: the minimum id (inclusive, < 0x8000000) - * @end: the maximum id (exclusive, < 0x8000000 or 0) - * @gfp_mask: memory allocation flags - * - * Allocates an id in the range start <= id < end, or returns -ENOSPC. - * On memory allocation failure, returns -ENOMEM. - * - * Use ida_simple_remove() to get rid of an id. - */ -int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end, - gfp_t gfp_mask) -{ - int ret, id; - unsigned int max; - unsigned long flags; - - BUG_ON((int)start < 0); - BUG_ON((int)end < 0); - - if (end == 0) - max = 0x80000000; - else { - BUG_ON(end < start); - max = end - 1; - } - -again: - if (!ida_pre_get(ida, gfp_mask)) - return -ENOMEM; - - spin_lock_irqsave(&simple_ida_lock, flags); - ret = ida_get_new_above(ida, start, &id); - if (!ret) { - if (id > max) { - ida_remove(ida, id); - ret = -ENOSPC; - } else { - ret = id; - } - } - spin_unlock_irqrestore(&simple_ida_lock, flags); - - if (unlikely(ret == -EAGAIN)) - goto again; - - return ret; -} -EXPORT_SYMBOL(ida_simple_get); - -/** - * ida_simple_remove - remove an allocated id. - * @ida: the (initialized) ida. - * @id: the id returned by ida_simple_get. - */ -void ida_simple_remove(struct ida *ida, unsigned int id) -{ - unsigned long flags; - - BUG_ON((int)id < 0); - spin_lock_irqsave(&simple_ida_lock, flags); - ida_remove(ida, id); - spin_unlock_irqrestore(&simple_ida_lock, flags); -} -EXPORT_SYMBOL(ida_simple_remove); - -/** - * ida_init - initialize ida handle - * @ida: ida handle - * - * This function is use to set up the handle (@ida) that you will pass - * to the rest of the functions. - */ -void ida_init(struct ida *ida) -{ - memset(ida, 0, sizeof(struct ida)); - idr_init(&ida->idr); - -} -EXPORT_SYMBOL(ida_init); diff --git a/src/linux/lib/int_sqrt.c b/src/linux/lib/int_sqrt.c deleted file mode 100644 index 1ef4cc3..0000000 --- a/src/linux/lib/int_sqrt.c +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2013 Davidlohr Bueso - * - * Based on the shift-and-subtract algorithm for computing integer - * square root from Guy L. Steele. - */ - -#include -#include - -/** - * int_sqrt - rough approximation to sqrt - * @x: integer of which to calculate the sqrt - * - * A very rough approximation to the sqrt() function. - */ -unsigned long int_sqrt(unsigned long x) -{ - unsigned long b, m, y = 0; - - if (x <= 1) - return x; - - m = 1UL << (BITS_PER_LONG - 2); - while (m != 0) { - b = y + m; - y >>= 1; - - if (x >= b) { - x -= b; - y += m; - } - m >>= 2; - } - - return y; -} -EXPORT_SYMBOL(int_sqrt); diff --git a/src/linux/lib/iomap_copy.c b/src/linux/lib/iomap_copy.c deleted file mode 100644 index b8f1d6c..0000000 --- a/src/linux/lib/iomap_copy.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2006 PathScale, Inc. All Rights Reserved. - * - * This file is free software; you can redistribute it and/or modify - * it under the terms of version 2 of the GNU General Public License - * as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include - -/** - * __iowrite32_copy - copy data to MMIO space, in 32-bit units - * @to: destination, in MMIO space (must be 32-bit aligned) - * @from: source (must be 32-bit aligned) - * @count: number of 32-bit quantities to copy - * - * Copy data from kernel space to MMIO space, in units of 32 bits at a - * time. Order of access is not guaranteed, nor is a memory barrier - * performed afterwards. - */ -void __attribute__((weak)) __iowrite32_copy(void __iomem *to, - const void *from, - size_t count) -{ - u32 __iomem *dst = to; - const u32 *src = from; - const u32 *end = src + count; - - while (src < end) - __raw_writel(*src++, dst++); -} -EXPORT_SYMBOL_GPL(__iowrite32_copy); - -/** - * __ioread32_copy - copy data from MMIO space, in 32-bit units - * @to: destination (must be 32-bit aligned) - * @from: source, in MMIO space (must be 32-bit aligned) - * @count: number of 32-bit quantities to copy - * - * Copy data from MMIO space to kernel space, in units of 32 bits at a - * time. Order of access is not guaranteed, nor is a memory barrier - * performed afterwards. - */ -void __ioread32_copy(void *to, const void __iomem *from, size_t count) -{ - u32 *dst = to; - const u32 __iomem *src = from; - const u32 __iomem *end = src + count; - - while (src < end) - *dst++ = __raw_readl(src++); -} -EXPORT_SYMBOL_GPL(__ioread32_copy); - -/** - * __iowrite64_copy - copy data to MMIO space, in 64-bit or 32-bit units - * @to: destination, in MMIO space (must be 64-bit aligned) - * @from: source (must be 64-bit aligned) - * @count: number of 64-bit quantities to copy - * - * Copy data from kernel space to MMIO space, in units of 32 or 64 bits at a - * time. Order of access is not guaranteed, nor is a memory barrier - * performed afterwards. - */ -void __attribute__((weak)) __iowrite64_copy(void __iomem *to, - const void *from, - size_t count) -{ -#ifdef CONFIG_64BIT - u64 __iomem *dst = to; - const u64 *src = from; - const u64 *end = src + count; - - while (src < end) - __raw_writeq(*src++, dst++); -#else - __iowrite32_copy(to, from, count * 2); -#endif -} - -EXPORT_SYMBOL_GPL(__iowrite64_copy); diff --git a/src/linux/lib/iov_iter.c b/src/linux/lib/iov_iter.c deleted file mode 100644 index f2bd21b..0000000 --- a/src/linux/lib/iov_iter.c +++ /dev/null @@ -1,1222 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#define PIPE_PARANOIA /* for now */ - -#define iterate_iovec(i, n, __v, __p, skip, STEP) { \ - size_t left; \ - size_t wanted = n; \ - __p = i->iov; \ - __v.iov_len = min(n, __p->iov_len - skip); \ - if (likely(__v.iov_len)) { \ - __v.iov_base = __p->iov_base + skip; \ - left = (STEP); \ - __v.iov_len -= left; \ - skip += __v.iov_len; \ - n -= __v.iov_len; \ - } else { \ - left = 0; \ - } \ - while (unlikely(!left && n)) { \ - __p++; \ - __v.iov_len = min(n, __p->iov_len); \ - if (unlikely(!__v.iov_len)) \ - continue; \ - __v.iov_base = __p->iov_base; \ - left = (STEP); \ - __v.iov_len -= left; \ - skip = __v.iov_len; \ - n -= __v.iov_len; \ - } \ - n = wanted - n; \ -} - -#define iterate_kvec(i, n, __v, __p, skip, STEP) { \ - size_t wanted = n; \ - __p = i->kvec; \ - __v.iov_len = min(n, __p->iov_len - skip); \ - if (likely(__v.iov_len)) { \ - __v.iov_base = __p->iov_base + skip; \ - (void)(STEP); \ - skip += __v.iov_len; \ - n -= __v.iov_len; \ - } \ - while (unlikely(n)) { \ - __p++; \ - __v.iov_len = min(n, __p->iov_len); \ - if (unlikely(!__v.iov_len)) \ - continue; \ - __v.iov_base = __p->iov_base; \ - (void)(STEP); \ - skip = __v.iov_len; \ - n -= __v.iov_len; \ - } \ - n = wanted; \ -} - -#define iterate_bvec(i, n, __v, __bi, skip, STEP) { \ - struct bvec_iter __start; \ - __start.bi_size = n; \ - __start.bi_bvec_done = skip; \ - __start.bi_idx = 0; \ - for_each_bvec(__v, i->bvec, __bi, __start) { \ - if (!__v.bv_len) \ - continue; \ - (void)(STEP); \ - } \ -} - -#define iterate_all_kinds(i, n, v, I, B, K) { \ - size_t skip = i->iov_offset; \ - if (unlikely(i->type & ITER_BVEC)) { \ - struct bio_vec v; \ - struct bvec_iter __bi; \ - iterate_bvec(i, n, v, __bi, skip, (B)) \ - } else if (unlikely(i->type & ITER_KVEC)) { \ - const struct kvec *kvec; \ - struct kvec v; \ - iterate_kvec(i, n, v, kvec, skip, (K)) \ - } else { \ - const struct iovec *iov; \ - struct iovec v; \ - iterate_iovec(i, n, v, iov, skip, (I)) \ - } \ -} - -#define iterate_and_advance(i, n, v, I, B, K) { \ - if (unlikely(i->count < n)) \ - n = i->count; \ - if (i->count) { \ - size_t skip = i->iov_offset; \ - if (unlikely(i->type & ITER_BVEC)) { \ - const struct bio_vec *bvec = i->bvec; \ - struct bio_vec v; \ - struct bvec_iter __bi; \ - iterate_bvec(i, n, v, __bi, skip, (B)) \ - i->bvec = __bvec_iter_bvec(i->bvec, __bi); \ - i->nr_segs -= i->bvec - bvec; \ - skip = __bi.bi_bvec_done; \ - } else if (unlikely(i->type & ITER_KVEC)) { \ - const struct kvec *kvec; \ - struct kvec v; \ - iterate_kvec(i, n, v, kvec, skip, (K)) \ - if (skip == kvec->iov_len) { \ - kvec++; \ - skip = 0; \ - } \ - i->nr_segs -= kvec - i->kvec; \ - i->kvec = kvec; \ - } else { \ - const struct iovec *iov; \ - struct iovec v; \ - iterate_iovec(i, n, v, iov, skip, (I)) \ - if (skip == iov->iov_len) { \ - iov++; \ - skip = 0; \ - } \ - i->nr_segs -= iov - i->iov; \ - i->iov = iov; \ - } \ - i->count -= n; \ - i->iov_offset = skip; \ - } \ -} - -static size_t copy_page_to_iter_iovec(struct page *page, size_t offset, size_t bytes, - struct iov_iter *i) -{ - size_t skip, copy, left, wanted; - const struct iovec *iov; - char __user *buf; - void *kaddr, *from; - - if (unlikely(bytes > i->count)) - bytes = i->count; - - if (unlikely(!bytes)) - return 0; - - wanted = bytes; - iov = i->iov; - skip = i->iov_offset; - buf = iov->iov_base + skip; - copy = min(bytes, iov->iov_len - skip); - - if (IS_ENABLED(CONFIG_HIGHMEM) && !fault_in_pages_writeable(buf, copy)) { - kaddr = kmap_atomic(page); - from = kaddr + offset; - - /* first chunk, usually the only one */ - left = __copy_to_user_inatomic(buf, from, copy); - copy -= left; - skip += copy; - from += copy; - bytes -= copy; - - while (unlikely(!left && bytes)) { - iov++; - buf = iov->iov_base; - copy = min(bytes, iov->iov_len); - left = __copy_to_user_inatomic(buf, from, copy); - copy -= left; - skip = copy; - from += copy; - bytes -= copy; - } - if (likely(!bytes)) { - kunmap_atomic(kaddr); - goto done; - } - offset = from - kaddr; - buf += copy; - kunmap_atomic(kaddr); - copy = min(bytes, iov->iov_len - skip); - } - /* Too bad - revert to non-atomic kmap */ - - kaddr = kmap(page); - from = kaddr + offset; - left = __copy_to_user(buf, from, copy); - copy -= left; - skip += copy; - from += copy; - bytes -= copy; - while (unlikely(!left && bytes)) { - iov++; - buf = iov->iov_base; - copy = min(bytes, iov->iov_len); - left = __copy_to_user(buf, from, copy); - copy -= left; - skip = copy; - from += copy; - bytes -= copy; - } - kunmap(page); - -done: - if (skip == iov->iov_len) { - iov++; - skip = 0; - } - i->count -= wanted - bytes; - i->nr_segs -= iov - i->iov; - i->iov = iov; - i->iov_offset = skip; - return wanted - bytes; -} - -static size_t copy_page_from_iter_iovec(struct page *page, size_t offset, size_t bytes, - struct iov_iter *i) -{ - size_t skip, copy, left, wanted; - const struct iovec *iov; - char __user *buf; - void *kaddr, *to; - - if (unlikely(bytes > i->count)) - bytes = i->count; - - if (unlikely(!bytes)) - return 0; - - wanted = bytes; - iov = i->iov; - skip = i->iov_offset; - buf = iov->iov_base + skip; - copy = min(bytes, iov->iov_len - skip); - - if (IS_ENABLED(CONFIG_HIGHMEM) && !fault_in_pages_readable(buf, copy)) { - kaddr = kmap_atomic(page); - to = kaddr + offset; - - /* first chunk, usually the only one */ - left = __copy_from_user_inatomic(to, buf, copy); - copy -= left; - skip += copy; - to += copy; - bytes -= copy; - - while (unlikely(!left && bytes)) { - iov++; - buf = iov->iov_base; - copy = min(bytes, iov->iov_len); - left = __copy_from_user_inatomic(to, buf, copy); - copy -= left; - skip = copy; - to += copy; - bytes -= copy; - } - if (likely(!bytes)) { - kunmap_atomic(kaddr); - goto done; - } - offset = to - kaddr; - buf += copy; - kunmap_atomic(kaddr); - copy = min(bytes, iov->iov_len - skip); - } - /* Too bad - revert to non-atomic kmap */ - - kaddr = kmap(page); - to = kaddr + offset; - left = __copy_from_user(to, buf, copy); - copy -= left; - skip += copy; - to += copy; - bytes -= copy; - while (unlikely(!left && bytes)) { - iov++; - buf = iov->iov_base; - copy = min(bytes, iov->iov_len); - left = __copy_from_user(to, buf, copy); - copy -= left; - skip = copy; - to += copy; - bytes -= copy; - } - kunmap(page); - -done: - if (skip == iov->iov_len) { - iov++; - skip = 0; - } - i->count -= wanted - bytes; - i->nr_segs -= iov - i->iov; - i->iov = iov; - i->iov_offset = skip; - return wanted - bytes; -} - -#ifdef PIPE_PARANOIA -static bool sanity(const struct iov_iter *i) -{ - struct pipe_inode_info *pipe = i->pipe; - int idx = i->idx; - int next = pipe->curbuf + pipe->nrbufs; - if (i->iov_offset) { - struct pipe_buffer *p; - if (unlikely(!pipe->nrbufs)) - goto Bad; // pipe must be non-empty - if (unlikely(idx != ((next - 1) & (pipe->buffers - 1)))) - goto Bad; // must be at the last buffer... - - p = &pipe->bufs[idx]; - if (unlikely(p->offset + p->len != i->iov_offset)) - goto Bad; // ... at the end of segment - } else { - if (idx != (next & (pipe->buffers - 1))) - goto Bad; // must be right after the last buffer - } - return true; -Bad: - printk(KERN_ERR "idx = %d, offset = %zd\n", i->idx, i->iov_offset); - printk(KERN_ERR "curbuf = %d, nrbufs = %d, buffers = %d\n", - pipe->curbuf, pipe->nrbufs, pipe->buffers); - for (idx = 0; idx < pipe->buffers; idx++) - printk(KERN_ERR "[%p %p %d %d]\n", - pipe->bufs[idx].ops, - pipe->bufs[idx].page, - pipe->bufs[idx].offset, - pipe->bufs[idx].len); - WARN_ON(1); - return false; -} -#else -#define sanity(i) true -#endif - -static inline int next_idx(int idx, struct pipe_inode_info *pipe) -{ - return (idx + 1) & (pipe->buffers - 1); -} - -static size_t copy_page_to_iter_pipe(struct page *page, size_t offset, size_t bytes, - struct iov_iter *i) -{ - struct pipe_inode_info *pipe = i->pipe; - struct pipe_buffer *buf; - size_t off; - int idx; - - if (unlikely(bytes > i->count)) - bytes = i->count; - - if (unlikely(!bytes)) - return 0; - - if (!sanity(i)) - return 0; - - off = i->iov_offset; - idx = i->idx; - buf = &pipe->bufs[idx]; - if (off) { - if (offset == off && buf->page == page) { - /* merge with the last one */ - buf->len += bytes; - i->iov_offset += bytes; - goto out; - } - idx = next_idx(idx, pipe); - buf = &pipe->bufs[idx]; - } - if (idx == pipe->curbuf && pipe->nrbufs) - return 0; - pipe->nrbufs++; - buf->ops = &page_cache_pipe_buf_ops; - get_page(buf->page = page); - buf->offset = offset; - buf->len = bytes; - i->iov_offset = offset + bytes; - i->idx = idx; -out: - i->count -= bytes; - return bytes; -} - -/* - * Fault in one or more iovecs of the given iov_iter, to a maximum length of - * bytes. For each iovec, fault in each page that constitutes the iovec. - * - * Return 0 on success, or non-zero if the memory could not be accessed (i.e. - * because it is an invalid address). - */ -int iov_iter_fault_in_readable(struct iov_iter *i, size_t bytes) -{ - size_t skip = i->iov_offset; - const struct iovec *iov; - int err; - struct iovec v; - - if (!(i->type & (ITER_BVEC|ITER_KVEC))) { - iterate_iovec(i, bytes, v, iov, skip, ({ - err = fault_in_pages_readable(v.iov_base, v.iov_len); - if (unlikely(err)) - return err; - 0;})) - } - return 0; -} -EXPORT_SYMBOL(iov_iter_fault_in_readable); - -void iov_iter_init(struct iov_iter *i, int direction, - const struct iovec *iov, unsigned long nr_segs, - size_t count) -{ - /* It will get better. Eventually... */ - if (segment_eq(get_fs(), KERNEL_DS)) { - direction |= ITER_KVEC; - i->type = direction; - i->kvec = (struct kvec *)iov; - } else { - i->type = direction; - i->iov = iov; - } - i->nr_segs = nr_segs; - i->iov_offset = 0; - i->count = count; -} -EXPORT_SYMBOL(iov_iter_init); - -static void memcpy_from_page(char *to, struct page *page, size_t offset, size_t len) -{ - char *from = kmap_atomic(page); - memcpy(to, from + offset, len); - kunmap_atomic(from); -} - -static void memcpy_to_page(struct page *page, size_t offset, const char *from, size_t len) -{ - char *to = kmap_atomic(page); - memcpy(to + offset, from, len); - kunmap_atomic(to); -} - -static void memzero_page(struct page *page, size_t offset, size_t len) -{ - char *addr = kmap_atomic(page); - memset(addr + offset, 0, len); - kunmap_atomic(addr); -} - -static inline bool allocated(struct pipe_buffer *buf) -{ - return buf->ops == &default_pipe_buf_ops; -} - -static inline void data_start(const struct iov_iter *i, int *idxp, size_t *offp) -{ - size_t off = i->iov_offset; - int idx = i->idx; - if (off && (!allocated(&i->pipe->bufs[idx]) || off == PAGE_SIZE)) { - idx = next_idx(idx, i->pipe); - off = 0; - } - *idxp = idx; - *offp = off; -} - -static size_t push_pipe(struct iov_iter *i, size_t size, - int *idxp, size_t *offp) -{ - struct pipe_inode_info *pipe = i->pipe; - size_t off; - int idx; - ssize_t left; - - if (unlikely(size > i->count)) - size = i->count; - if (unlikely(!size)) - return 0; - - left = size; - data_start(i, &idx, &off); - *idxp = idx; - *offp = off; - if (off) { - left -= PAGE_SIZE - off; - if (left <= 0) { - pipe->bufs[idx].len += size; - return size; - } - pipe->bufs[idx].len = PAGE_SIZE; - idx = next_idx(idx, pipe); - } - while (idx != pipe->curbuf || !pipe->nrbufs) { - struct page *page = alloc_page(GFP_USER); - if (!page) - break; - pipe->nrbufs++; - pipe->bufs[idx].ops = &default_pipe_buf_ops; - pipe->bufs[idx].page = page; - pipe->bufs[idx].offset = 0; - if (left <= PAGE_SIZE) { - pipe->bufs[idx].len = left; - return size; - } - pipe->bufs[idx].len = PAGE_SIZE; - left -= PAGE_SIZE; - idx = next_idx(idx, pipe); - } - return size - left; -} - -static size_t copy_pipe_to_iter(const void *addr, size_t bytes, - struct iov_iter *i) -{ - struct pipe_inode_info *pipe = i->pipe; - size_t n, off; - int idx; - - if (!sanity(i)) - return 0; - - bytes = n = push_pipe(i, bytes, &idx, &off); - if (unlikely(!n)) - return 0; - for ( ; n; idx = next_idx(idx, pipe), off = 0) { - size_t chunk = min_t(size_t, n, PAGE_SIZE - off); - memcpy_to_page(pipe->bufs[idx].page, off, addr, chunk); - i->idx = idx; - i->iov_offset = off + chunk; - n -= chunk; - addr += chunk; - } - i->count -= bytes; - return bytes; -} - -size_t copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i) -{ - const char *from = addr; - if (unlikely(i->type & ITER_PIPE)) - return copy_pipe_to_iter(addr, bytes, i); - iterate_and_advance(i, bytes, v, - __copy_to_user(v.iov_base, (from += v.iov_len) - v.iov_len, - v.iov_len), - memcpy_to_page(v.bv_page, v.bv_offset, - (from += v.bv_len) - v.bv_len, v.bv_len), - memcpy(v.iov_base, (from += v.iov_len) - v.iov_len, v.iov_len) - ) - - return bytes; -} -EXPORT_SYMBOL(copy_to_iter); - -size_t copy_from_iter(void *addr, size_t bytes, struct iov_iter *i) -{ - char *to = addr; - if (unlikely(i->type & ITER_PIPE)) { - WARN_ON(1); - return 0; - } - iterate_and_advance(i, bytes, v, - __copy_from_user((to += v.iov_len) - v.iov_len, v.iov_base, - v.iov_len), - memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page, - v.bv_offset, v.bv_len), - memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len) - ) - - return bytes; -} -EXPORT_SYMBOL(copy_from_iter); - -size_t copy_from_iter_nocache(void *addr, size_t bytes, struct iov_iter *i) -{ - char *to = addr; - if (unlikely(i->type & ITER_PIPE)) { - WARN_ON(1); - return 0; - } - iterate_and_advance(i, bytes, v, - __copy_from_user_nocache((to += v.iov_len) - v.iov_len, - v.iov_base, v.iov_len), - memcpy_from_page((to += v.bv_len) - v.bv_len, v.bv_page, - v.bv_offset, v.bv_len), - memcpy((to += v.iov_len) - v.iov_len, v.iov_base, v.iov_len) - ) - - return bytes; -} -EXPORT_SYMBOL(copy_from_iter_nocache); - -size_t copy_page_to_iter(struct page *page, size_t offset, size_t bytes, - struct iov_iter *i) -{ - if (i->type & (ITER_BVEC|ITER_KVEC)) { - void *kaddr = kmap_atomic(page); - size_t wanted = copy_to_iter(kaddr + offset, bytes, i); - kunmap_atomic(kaddr); - return wanted; - } else if (likely(!(i->type & ITER_PIPE))) - return copy_page_to_iter_iovec(page, offset, bytes, i); - else - return copy_page_to_iter_pipe(page, offset, bytes, i); -} -EXPORT_SYMBOL(copy_page_to_iter); - -size_t copy_page_from_iter(struct page *page, size_t offset, size_t bytes, - struct iov_iter *i) -{ - if (unlikely(i->type & ITER_PIPE)) { - WARN_ON(1); - return 0; - } - if (i->type & (ITER_BVEC|ITER_KVEC)) { - void *kaddr = kmap_atomic(page); - size_t wanted = copy_from_iter(kaddr + offset, bytes, i); - kunmap_atomic(kaddr); - return wanted; - } else - return copy_page_from_iter_iovec(page, offset, bytes, i); -} -EXPORT_SYMBOL(copy_page_from_iter); - -static size_t pipe_zero(size_t bytes, struct iov_iter *i) -{ - struct pipe_inode_info *pipe = i->pipe; - size_t n, off; - int idx; - - if (!sanity(i)) - return 0; - - bytes = n = push_pipe(i, bytes, &idx, &off); - if (unlikely(!n)) - return 0; - - for ( ; n; idx = next_idx(idx, pipe), off = 0) { - size_t chunk = min_t(size_t, n, PAGE_SIZE - off); - memzero_page(pipe->bufs[idx].page, off, chunk); - i->idx = idx; - i->iov_offset = off + chunk; - n -= chunk; - } - i->count -= bytes; - return bytes; -} - -size_t iov_iter_zero(size_t bytes, struct iov_iter *i) -{ - if (unlikely(i->type & ITER_PIPE)) - return pipe_zero(bytes, i); - iterate_and_advance(i, bytes, v, - __clear_user(v.iov_base, v.iov_len), - memzero_page(v.bv_page, v.bv_offset, v.bv_len), - memset(v.iov_base, 0, v.iov_len) - ) - - return bytes; -} -EXPORT_SYMBOL(iov_iter_zero); - -size_t iov_iter_copy_from_user_atomic(struct page *page, - struct iov_iter *i, unsigned long offset, size_t bytes) -{ - char *kaddr = kmap_atomic(page), *p = kaddr + offset; - if (unlikely(i->type & ITER_PIPE)) { - kunmap_atomic(kaddr); - WARN_ON(1); - return 0; - } - iterate_all_kinds(i, bytes, v, - __copy_from_user_inatomic((p += v.iov_len) - v.iov_len, - v.iov_base, v.iov_len), - memcpy_from_page((p += v.bv_len) - v.bv_len, v.bv_page, - v.bv_offset, v.bv_len), - memcpy((p += v.iov_len) - v.iov_len, v.iov_base, v.iov_len) - ) - kunmap_atomic(kaddr); - return bytes; -} -EXPORT_SYMBOL(iov_iter_copy_from_user_atomic); - -static void pipe_advance(struct iov_iter *i, size_t size) -{ - struct pipe_inode_info *pipe = i->pipe; - struct pipe_buffer *buf; - int idx = i->idx; - size_t off = i->iov_offset, orig_sz; - - if (unlikely(i->count < size)) - size = i->count; - orig_sz = size; - - if (size) { - if (off) /* make it relative to the beginning of buffer */ - size += off - pipe->bufs[idx].offset; - while (1) { - buf = &pipe->bufs[idx]; - if (size <= buf->len) - break; - size -= buf->len; - idx = next_idx(idx, pipe); - } - buf->len = size; - i->idx = idx; - off = i->iov_offset = buf->offset + size; - } - if (off) - idx = next_idx(idx, pipe); - if (pipe->nrbufs) { - int unused = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1); - /* [curbuf,unused) is in use. Free [idx,unused) */ - while (idx != unused) { - pipe_buf_release(pipe, &pipe->bufs[idx]); - idx = next_idx(idx, pipe); - pipe->nrbufs--; - } - } - i->count -= orig_sz; -} - -void iov_iter_advance(struct iov_iter *i, size_t size) -{ - if (unlikely(i->type & ITER_PIPE)) { - pipe_advance(i, size); - return; - } - iterate_and_advance(i, size, v, 0, 0, 0) -} -EXPORT_SYMBOL(iov_iter_advance); - -/* - * Return the count of just the current iov_iter segment. - */ -size_t iov_iter_single_seg_count(const struct iov_iter *i) -{ - if (unlikely(i->type & ITER_PIPE)) - return i->count; // it is a silly place, anyway - if (i->nr_segs == 1) - return i->count; - else if (i->type & ITER_BVEC) - return min(i->count, i->bvec->bv_len - i->iov_offset); - else - return min(i->count, i->iov->iov_len - i->iov_offset); -} -EXPORT_SYMBOL(iov_iter_single_seg_count); - -void iov_iter_kvec(struct iov_iter *i, int direction, - const struct kvec *kvec, unsigned long nr_segs, - size_t count) -{ - BUG_ON(!(direction & ITER_KVEC)); - i->type = direction; - i->kvec = kvec; - i->nr_segs = nr_segs; - i->iov_offset = 0; - i->count = count; -} -EXPORT_SYMBOL(iov_iter_kvec); - -void iov_iter_bvec(struct iov_iter *i, int direction, - const struct bio_vec *bvec, unsigned long nr_segs, - size_t count) -{ - BUG_ON(!(direction & ITER_BVEC)); - i->type = direction; - i->bvec = bvec; - i->nr_segs = nr_segs; - i->iov_offset = 0; - i->count = count; -} -EXPORT_SYMBOL(iov_iter_bvec); - -void iov_iter_pipe(struct iov_iter *i, int direction, - struct pipe_inode_info *pipe, - size_t count) -{ - BUG_ON(direction != ITER_PIPE); - i->type = direction; - i->pipe = pipe; - i->idx = (pipe->curbuf + pipe->nrbufs) & (pipe->buffers - 1); - i->iov_offset = 0; - i->count = count; -} -EXPORT_SYMBOL(iov_iter_pipe); - -unsigned long iov_iter_alignment(const struct iov_iter *i) -{ - unsigned long res = 0; - size_t size = i->count; - - if (!size) - return 0; - - if (unlikely(i->type & ITER_PIPE)) { - if (i->iov_offset && allocated(&i->pipe->bufs[i->idx])) - return size | i->iov_offset; - return size; - } - iterate_all_kinds(i, size, v, - (res |= (unsigned long)v.iov_base | v.iov_len, 0), - res |= v.bv_offset | v.bv_len, - res |= (unsigned long)v.iov_base | v.iov_len - ) - return res; -} -EXPORT_SYMBOL(iov_iter_alignment); - -unsigned long iov_iter_gap_alignment(const struct iov_iter *i) -{ - unsigned long res = 0; - size_t size = i->count; - if (!size) - return 0; - - if (unlikely(i->type & ITER_PIPE)) { - WARN_ON(1); - return ~0U; - } - - iterate_all_kinds(i, size, v, - (res |= (!res ? 0 : (unsigned long)v.iov_base) | - (size != v.iov_len ? size : 0), 0), - (res |= (!res ? 0 : (unsigned long)v.bv_offset) | - (size != v.bv_len ? size : 0)), - (res |= (!res ? 0 : (unsigned long)v.iov_base) | - (size != v.iov_len ? size : 0)) - ); - return res; -} -EXPORT_SYMBOL(iov_iter_gap_alignment); - -static inline size_t __pipe_get_pages(struct iov_iter *i, - size_t maxsize, - struct page **pages, - int idx, - size_t *start) -{ - struct pipe_inode_info *pipe = i->pipe; - ssize_t n = push_pipe(i, maxsize, &idx, start); - if (!n) - return -EFAULT; - - maxsize = n; - n += *start; - while (n > 0) { - get_page(*pages++ = pipe->bufs[idx].page); - idx = next_idx(idx, pipe); - n -= PAGE_SIZE; - } - - return maxsize; -} - -static ssize_t pipe_get_pages(struct iov_iter *i, - struct page **pages, size_t maxsize, unsigned maxpages, - size_t *start) -{ - unsigned npages; - size_t capacity; - int idx; - - if (!sanity(i)) - return -EFAULT; - - data_start(i, &idx, start); - /* some of this one + all after this one */ - npages = ((i->pipe->curbuf - idx - 1) & (i->pipe->buffers - 1)) + 1; - capacity = min(npages,maxpages) * PAGE_SIZE - *start; - - return __pipe_get_pages(i, min(maxsize, capacity), pages, idx, start); -} - -ssize_t iov_iter_get_pages(struct iov_iter *i, - struct page **pages, size_t maxsize, unsigned maxpages, - size_t *start) -{ - if (maxsize > i->count) - maxsize = i->count; - - if (!maxsize) - return 0; - - if (unlikely(i->type & ITER_PIPE)) - return pipe_get_pages(i, pages, maxsize, maxpages, start); - iterate_all_kinds(i, maxsize, v, ({ - unsigned long addr = (unsigned long)v.iov_base; - size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1)); - int n; - int res; - - if (len > maxpages * PAGE_SIZE) - len = maxpages * PAGE_SIZE; - addr &= ~(PAGE_SIZE - 1); - n = DIV_ROUND_UP(len, PAGE_SIZE); - res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, pages); - if (unlikely(res < 0)) - return res; - return (res == n ? len : res * PAGE_SIZE) - *start; - 0;}),({ - /* can't be more than PAGE_SIZE */ - *start = v.bv_offset; - get_page(*pages = v.bv_page); - return v.bv_len; - }),({ - return -EFAULT; - }) - ) - return 0; -} -EXPORT_SYMBOL(iov_iter_get_pages); - -static struct page **get_pages_array(size_t n) -{ - struct page **p = kmalloc(n * sizeof(struct page *), GFP_KERNEL); - if (!p) - p = vmalloc(n * sizeof(struct page *)); - return p; -} - -static ssize_t pipe_get_pages_alloc(struct iov_iter *i, - struct page ***pages, size_t maxsize, - size_t *start) -{ - struct page **p; - size_t n; - int idx; - int npages; - - if (!sanity(i)) - return -EFAULT; - - data_start(i, &idx, start); - /* some of this one + all after this one */ - npages = ((i->pipe->curbuf - idx - 1) & (i->pipe->buffers - 1)) + 1; - n = npages * PAGE_SIZE - *start; - if (maxsize > n) - maxsize = n; - else - npages = DIV_ROUND_UP(maxsize + *start, PAGE_SIZE); - p = get_pages_array(npages); - if (!p) - return -ENOMEM; - n = __pipe_get_pages(i, maxsize, p, idx, start); - if (n > 0) - *pages = p; - else - kvfree(p); - return n; -} - -ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, - struct page ***pages, size_t maxsize, - size_t *start) -{ - struct page **p; - - if (maxsize > i->count) - maxsize = i->count; - - if (!maxsize) - return 0; - - if (unlikely(i->type & ITER_PIPE)) - return pipe_get_pages_alloc(i, pages, maxsize, start); - iterate_all_kinds(i, maxsize, v, ({ - unsigned long addr = (unsigned long)v.iov_base; - size_t len = v.iov_len + (*start = addr & (PAGE_SIZE - 1)); - int n; - int res; - - addr &= ~(PAGE_SIZE - 1); - n = DIV_ROUND_UP(len, PAGE_SIZE); - p = get_pages_array(n); - if (!p) - return -ENOMEM; - res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, p); - if (unlikely(res < 0)) { - kvfree(p); - return res; - } - *pages = p; - return (res == n ? len : res * PAGE_SIZE) - *start; - 0;}),({ - /* can't be more than PAGE_SIZE */ - *start = v.bv_offset; - *pages = p = get_pages_array(1); - if (!p) - return -ENOMEM; - get_page(*p = v.bv_page); - return v.bv_len; - }),({ - return -EFAULT; - }) - ) - return 0; -} -EXPORT_SYMBOL(iov_iter_get_pages_alloc); - -size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, - struct iov_iter *i) -{ - char *to = addr; - __wsum sum, next; - size_t off = 0; - sum = *csum; - if (unlikely(i->type & ITER_PIPE)) { - WARN_ON(1); - return 0; - } - iterate_and_advance(i, bytes, v, ({ - int err = 0; - next = csum_and_copy_from_user(v.iov_base, - (to += v.iov_len) - v.iov_len, - v.iov_len, 0, &err); - if (!err) { - sum = csum_block_add(sum, next, off); - off += v.iov_len; - } - err ? v.iov_len : 0; - }), ({ - char *p = kmap_atomic(v.bv_page); - next = csum_partial_copy_nocheck(p + v.bv_offset, - (to += v.bv_len) - v.bv_len, - v.bv_len, 0); - kunmap_atomic(p); - sum = csum_block_add(sum, next, off); - off += v.bv_len; - }),({ - next = csum_partial_copy_nocheck(v.iov_base, - (to += v.iov_len) - v.iov_len, - v.iov_len, 0); - sum = csum_block_add(sum, next, off); - off += v.iov_len; - }) - ) - *csum = sum; - return bytes; -} -EXPORT_SYMBOL(csum_and_copy_from_iter); - -size_t csum_and_copy_to_iter(const void *addr, size_t bytes, __wsum *csum, - struct iov_iter *i) -{ - const char *from = addr; - __wsum sum, next; - size_t off = 0; - sum = *csum; - if (unlikely(i->type & ITER_PIPE)) { - WARN_ON(1); /* for now */ - return 0; - } - iterate_and_advance(i, bytes, v, ({ - int err = 0; - next = csum_and_copy_to_user((from += v.iov_len) - v.iov_len, - v.iov_base, - v.iov_len, 0, &err); - if (!err) { - sum = csum_block_add(sum, next, off); - off += v.iov_len; - } - err ? v.iov_len : 0; - }), ({ - char *p = kmap_atomic(v.bv_page); - next = csum_partial_copy_nocheck((from += v.bv_len) - v.bv_len, - p + v.bv_offset, - v.bv_len, 0); - kunmap_atomic(p); - sum = csum_block_add(sum, next, off); - off += v.bv_len; - }),({ - next = csum_partial_copy_nocheck((from += v.iov_len) - v.iov_len, - v.iov_base, - v.iov_len, 0); - sum = csum_block_add(sum, next, off); - off += v.iov_len; - }) - ) - *csum = sum; - return bytes; -} -EXPORT_SYMBOL(csum_and_copy_to_iter); - -int iov_iter_npages(const struct iov_iter *i, int maxpages) -{ - size_t size = i->count; - int npages = 0; - - if (!size) - return 0; - - if (unlikely(i->type & ITER_PIPE)) { - struct pipe_inode_info *pipe = i->pipe; - size_t off; - int idx; - - if (!sanity(i)) - return 0; - - data_start(i, &idx, &off); - /* some of this one + all after this one */ - npages = ((pipe->curbuf - idx - 1) & (pipe->buffers - 1)) + 1; - if (npages >= maxpages) - return maxpages; - } else iterate_all_kinds(i, size, v, ({ - unsigned long p = (unsigned long)v.iov_base; - npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE) - - p / PAGE_SIZE; - if (npages >= maxpages) - return maxpages; - 0;}),({ - npages++; - if (npages >= maxpages) - return maxpages; - }),({ - unsigned long p = (unsigned long)v.iov_base; - npages += DIV_ROUND_UP(p + v.iov_len, PAGE_SIZE) - - p / PAGE_SIZE; - if (npages >= maxpages) - return maxpages; - }) - ) - return npages; -} -EXPORT_SYMBOL(iov_iter_npages); - -const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags) -{ - *new = *old; - if (unlikely(new->type & ITER_PIPE)) { - WARN_ON(1); - return NULL; - } - if (new->type & ITER_BVEC) - return new->bvec = kmemdup(new->bvec, - new->nr_segs * sizeof(struct bio_vec), - flags); - else - /* iovec and kvec have identical layout */ - return new->iov = kmemdup(new->iov, - new->nr_segs * sizeof(struct iovec), - flags); -} -EXPORT_SYMBOL(dup_iter); - -/** - * import_iovec() - Copy an array of &struct iovec from userspace - * into the kernel, check that it is valid, and initialize a new - * &struct iov_iter iterator to access it. - * - * @type: One of %READ or %WRITE. - * @uvector: Pointer to the userspace array. - * @nr_segs: Number of elements in userspace array. - * @fast_segs: Number of elements in @iov. - * @iov: (input and output parameter) Pointer to pointer to (usually small - * on-stack) kernel array. - * @i: Pointer to iterator that will be initialized on success. - * - * If the array pointed to by *@iov is large enough to hold all @nr_segs, - * then this function places %NULL in *@iov on return. Otherwise, a new - * array will be allocated and the result placed in *@iov. This means that - * the caller may call kfree() on *@iov regardless of whether the small - * on-stack array was used or not (and regardless of whether this function - * returns an error or not). - * - * Return: 0 on success or negative error code on error. - */ -int import_iovec(int type, const struct iovec __user * uvector, - unsigned nr_segs, unsigned fast_segs, - struct iovec **iov, struct iov_iter *i) -{ - ssize_t n; - struct iovec *p; - n = rw_copy_check_uvector(type, uvector, nr_segs, fast_segs, - *iov, &p); - if (n < 0) { - if (p != *iov) - kfree(p); - *iov = NULL; - return n; - } - iov_iter_init(i, type, p, nr_segs, n); - *iov = p == *iov ? NULL : p; - return 0; -} -EXPORT_SYMBOL(import_iovec); - -#ifdef CONFIG_COMPAT -#include - -int compat_import_iovec(int type, const struct compat_iovec __user * uvector, - unsigned nr_segs, unsigned fast_segs, - struct iovec **iov, struct iov_iter *i) -{ - ssize_t n; - struct iovec *p; - n = compat_rw_copy_check_uvector(type, uvector, nr_segs, fast_segs, - *iov, &p); - if (n < 0) { - if (p != *iov) - kfree(p); - *iov = NULL; - return n; - } - iov_iter_init(i, type, p, nr_segs, n); - *iov = p == *iov ? NULL : p; - return 0; -} -#endif - -int import_single_range(int rw, void __user *buf, size_t len, - struct iovec *iov, struct iov_iter *i) -{ - if (len > MAX_RW_COUNT) - len = MAX_RW_COUNT; - if (unlikely(!access_ok(!rw, buf, len))) - return -EFAULT; - - iov->iov_base = buf; - iov->iov_len = len; - iov_iter_init(i, rw, iov, 1, len); - return 0; -} -EXPORT_SYMBOL(import_single_range); diff --git a/src/linux/lib/irq_regs.c b/src/linux/lib/irq_regs.c deleted file mode 100644 index 9c0a1d7..0000000 --- a/src/linux/lib/irq_regs.c +++ /dev/null @@ -1,18 +0,0 @@ -/* saved per-CPU IRQ register pointer - * - * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include - -#ifndef ARCH_HAS_OWN_IRQ_REGS -DEFINE_PER_CPU(struct pt_regs *, __irq_regs); -EXPORT_PER_CPU_SYMBOL(__irq_regs); -#endif diff --git a/src/linux/lib/is_single_threaded.c b/src/linux/lib/is_single_threaded.c deleted file mode 100644 index 391fd23..0000000 --- a/src/linux/lib/is_single_threaded.c +++ /dev/null @@ -1,57 +0,0 @@ -/* Function to determine if a thread group is single threaded or not - * - * Copyright (C) 2008 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - Derived from security/selinux/hooks.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public Licence - * as published by the Free Software Foundation; either version - * 2 of the Licence, or (at your option) any later version. - */ - -#include - -/* - * Returns true if the task does not share ->mm with another thread/process. - */ -bool current_is_single_threaded(void) -{ - struct task_struct *task = current; - struct mm_struct *mm = task->mm; - struct task_struct *p, *t; - bool ret; - - if (atomic_read(&task->signal->live) != 1) - return false; - - if (atomic_read(&mm->mm_users) == 1) - return true; - - ret = false; - rcu_read_lock(); - for_each_process(p) { - if (unlikely(p->flags & PF_KTHREAD)) - continue; - if (unlikely(p == task->group_leader)) - continue; - - for_each_thread(p, t) { - if (unlikely(t->mm == mm)) - goto found; - if (likely(t->mm)) - break; - /* - * t->mm == NULL. Make sure next_thread/next_task - * will see other CLONE_VM tasks which might be - * forked before exiting. - */ - smp_rmb(); - } - } - ret = true; -found: - rcu_read_unlock(); - - return ret; -} diff --git a/src/linux/lib/kasprintf.c b/src/linux/lib/kasprintf.c deleted file mode 100644 index 7f6c506..0000000 --- a/src/linux/lib/kasprintf.c +++ /dev/null @@ -1,63 +0,0 @@ -/* - * linux/lib/kasprintf.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -#include -#include -#include -#include -#include - -/* Simplified asprintf. */ -char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap) -{ - unsigned int first, second; - char *p; - va_list aq; - - va_copy(aq, ap); - first = vsnprintf(NULL, 0, fmt, aq); - va_end(aq); - - p = kmalloc_track_caller(first+1, gfp); - if (!p) - return NULL; - - second = vsnprintf(p, first+1, fmt, ap); - WARN(first != second, "different return values (%u and %u) from vsnprintf(\"%s\", ...)", - first, second, fmt); - - return p; -} -EXPORT_SYMBOL(kvasprintf); - -/* - * If fmt contains no % (or is exactly %s), use kstrdup_const. If fmt - * (or the sole vararg) points to rodata, we will then save a memory - * allocation and string copy. In any case, the return value should be - * freed using kfree_const(). - */ -const char *kvasprintf_const(gfp_t gfp, const char *fmt, va_list ap) -{ - if (!strchr(fmt, '%')) - return kstrdup_const(fmt, gfp); - if (!strcmp(fmt, "%s")) - return kstrdup_const(va_arg(ap, const char*), gfp); - return kvasprintf(gfp, fmt, ap); -} -EXPORT_SYMBOL(kvasprintf_const); - -char *kasprintf(gfp_t gfp, const char *fmt, ...) -{ - va_list ap; - char *p; - - va_start(ap, fmt); - p = kvasprintf(gfp, fmt, ap); - va_end(ap); - - return p; -} -EXPORT_SYMBOL(kasprintf); diff --git a/src/linux/lib/kfifo.c b/src/linux/lib/kfifo.c deleted file mode 100644 index 90ba1eb..0000000 --- a/src/linux/lib/kfifo.c +++ /dev/null @@ -1,605 +0,0 @@ -/* - * A generic kernel FIFO implementation - * - * Copyright (C) 2009/2010 Stefani Seibold - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -/* - * internal helper to calculate the unused elements in a fifo - */ -static inline unsigned int kfifo_unused(struct __kfifo *fifo) -{ - return (fifo->mask + 1) - (fifo->in - fifo->out); -} - -int __kfifo_alloc(struct __kfifo *fifo, unsigned int size, - size_t esize, gfp_t gfp_mask) -{ - /* - * round down to the next power of 2, since our 'let the indices - * wrap' technique works only in this case. - */ - size = roundup_pow_of_two(size); - - fifo->in = 0; - fifo->out = 0; - fifo->esize = esize; - - if (size < 2) { - fifo->data = NULL; - fifo->mask = 0; - return -EINVAL; - } - - fifo->data = kmalloc(size * esize, gfp_mask); - - if (!fifo->data) { - fifo->mask = 0; - return -ENOMEM; - } - fifo->mask = size - 1; - - return 0; -} -EXPORT_SYMBOL(__kfifo_alloc); - -void __kfifo_free(struct __kfifo *fifo) -{ - kfree(fifo->data); - fifo->in = 0; - fifo->out = 0; - fifo->esize = 0; - fifo->data = NULL; - fifo->mask = 0; -} -EXPORT_SYMBOL(__kfifo_free); - -int __kfifo_init(struct __kfifo *fifo, void *buffer, - unsigned int size, size_t esize) -{ - size /= esize; - - size = roundup_pow_of_two(size); - - fifo->in = 0; - fifo->out = 0; - fifo->esize = esize; - fifo->data = buffer; - - if (size < 2) { - fifo->mask = 0; - return -EINVAL; - } - fifo->mask = size - 1; - - return 0; -} -EXPORT_SYMBOL(__kfifo_init); - -static void kfifo_copy_in(struct __kfifo *fifo, const void *src, - unsigned int len, unsigned int off) -{ - unsigned int size = fifo->mask + 1; - unsigned int esize = fifo->esize; - unsigned int l; - - off &= fifo->mask; - if (esize != 1) { - off *= esize; - size *= esize; - len *= esize; - } - l = min(len, size - off); - - memcpy(fifo->data + off, src, l); - memcpy(fifo->data, src + l, len - l); - /* - * make sure that the data in the fifo is up to date before - * incrementing the fifo->in index counter - */ - smp_wmb(); -} - -unsigned int __kfifo_in(struct __kfifo *fifo, - const void *buf, unsigned int len) -{ - unsigned int l; - - l = kfifo_unused(fifo); - if (len > l) - len = l; - - kfifo_copy_in(fifo, buf, len, fifo->in); - fifo->in += len; - return len; -} -EXPORT_SYMBOL(__kfifo_in); - -static void kfifo_copy_out(struct __kfifo *fifo, void *dst, - unsigned int len, unsigned int off) -{ - unsigned int size = fifo->mask + 1; - unsigned int esize = fifo->esize; - unsigned int l; - - off &= fifo->mask; - if (esize != 1) { - off *= esize; - size *= esize; - len *= esize; - } - l = min(len, size - off); - - memcpy(dst, fifo->data + off, l); - memcpy(dst + l, fifo->data, len - l); - /* - * make sure that the data is copied before - * incrementing the fifo->out index counter - */ - smp_wmb(); -} - -unsigned int __kfifo_out_peek(struct __kfifo *fifo, - void *buf, unsigned int len) -{ - unsigned int l; - - l = fifo->in - fifo->out; - if (len > l) - len = l; - - kfifo_copy_out(fifo, buf, len, fifo->out); - return len; -} -EXPORT_SYMBOL(__kfifo_out_peek); - -unsigned int __kfifo_out(struct __kfifo *fifo, - void *buf, unsigned int len) -{ - len = __kfifo_out_peek(fifo, buf, len); - fifo->out += len; - return len; -} -EXPORT_SYMBOL(__kfifo_out); - -static unsigned long kfifo_copy_from_user(struct __kfifo *fifo, - const void __user *from, unsigned int len, unsigned int off, - unsigned int *copied) -{ - unsigned int size = fifo->mask + 1; - unsigned int esize = fifo->esize; - unsigned int l; - unsigned long ret; - - off &= fifo->mask; - if (esize != 1) { - off *= esize; - size *= esize; - len *= esize; - } - l = min(len, size - off); - - ret = copy_from_user(fifo->data + off, from, l); - if (unlikely(ret)) - ret = DIV_ROUND_UP(ret + len - l, esize); - else { - ret = copy_from_user(fifo->data, from + l, len - l); - if (unlikely(ret)) - ret = DIV_ROUND_UP(ret, esize); - } - /* - * make sure that the data in the fifo is up to date before - * incrementing the fifo->in index counter - */ - smp_wmb(); - *copied = len - ret * esize; - /* return the number of elements which are not copied */ - return ret; -} - -int __kfifo_from_user(struct __kfifo *fifo, const void __user *from, - unsigned long len, unsigned int *copied) -{ - unsigned int l; - unsigned long ret; - unsigned int esize = fifo->esize; - int err; - - if (esize != 1) - len /= esize; - - l = kfifo_unused(fifo); - if (len > l) - len = l; - - ret = kfifo_copy_from_user(fifo, from, len, fifo->in, copied); - if (unlikely(ret)) { - len -= ret; - err = -EFAULT; - } else - err = 0; - fifo->in += len; - return err; -} -EXPORT_SYMBOL(__kfifo_from_user); - -static unsigned long kfifo_copy_to_user(struct __kfifo *fifo, void __user *to, - unsigned int len, unsigned int off, unsigned int *copied) -{ - unsigned int l; - unsigned long ret; - unsigned int size = fifo->mask + 1; - unsigned int esize = fifo->esize; - - off &= fifo->mask; - if (esize != 1) { - off *= esize; - size *= esize; - len *= esize; - } - l = min(len, size - off); - - ret = copy_to_user(to, fifo->data + off, l); - if (unlikely(ret)) - ret = DIV_ROUND_UP(ret + len - l, esize); - else { - ret = copy_to_user(to + l, fifo->data, len - l); - if (unlikely(ret)) - ret = DIV_ROUND_UP(ret, esize); - } - /* - * make sure that the data is copied before - * incrementing the fifo->out index counter - */ - smp_wmb(); - *copied = len - ret * esize; - /* return the number of elements which are not copied */ - return ret; -} - -int __kfifo_to_user(struct __kfifo *fifo, void __user *to, - unsigned long len, unsigned int *copied) -{ - unsigned int l; - unsigned long ret; - unsigned int esize = fifo->esize; - int err; - - if (esize != 1) - len /= esize; - - l = fifo->in - fifo->out; - if (len > l) - len = l; - ret = kfifo_copy_to_user(fifo, to, len, fifo->out, copied); - if (unlikely(ret)) { - len -= ret; - err = -EFAULT; - } else - err = 0; - fifo->out += len; - return err; -} -EXPORT_SYMBOL(__kfifo_to_user); - -static int setup_sgl_buf(struct scatterlist *sgl, void *buf, - int nents, unsigned int len) -{ - int n; - unsigned int l; - unsigned int off; - struct page *page; - - if (!nents) - return 0; - - if (!len) - return 0; - - n = 0; - page = virt_to_page(buf); - off = offset_in_page(buf); - l = 0; - - while (len >= l + PAGE_SIZE - off) { - struct page *npage; - - l += PAGE_SIZE; - buf += PAGE_SIZE; - npage = virt_to_page(buf); - if (page_to_phys(page) != page_to_phys(npage) - l) { - sg_set_page(sgl, page, l - off, off); - sgl = sg_next(sgl); - if (++n == nents || sgl == NULL) - return n; - page = npage; - len -= l - off; - l = off = 0; - } - } - sg_set_page(sgl, page, len, off); - return n + 1; -} - -static unsigned int setup_sgl(struct __kfifo *fifo, struct scatterlist *sgl, - int nents, unsigned int len, unsigned int off) -{ - unsigned int size = fifo->mask + 1; - unsigned int esize = fifo->esize; - unsigned int l; - unsigned int n; - - off &= fifo->mask; - if (esize != 1) { - off *= esize; - size *= esize; - len *= esize; - } - l = min(len, size - off); - - n = setup_sgl_buf(sgl, fifo->data + off, nents, l); - n += setup_sgl_buf(sgl + n, fifo->data, nents - n, len - l); - - return n; -} - -unsigned int __kfifo_dma_in_prepare(struct __kfifo *fifo, - struct scatterlist *sgl, int nents, unsigned int len) -{ - unsigned int l; - - l = kfifo_unused(fifo); - if (len > l) - len = l; - - return setup_sgl(fifo, sgl, nents, len, fifo->in); -} -EXPORT_SYMBOL(__kfifo_dma_in_prepare); - -unsigned int __kfifo_dma_out_prepare(struct __kfifo *fifo, - struct scatterlist *sgl, int nents, unsigned int len) -{ - unsigned int l; - - l = fifo->in - fifo->out; - if (len > l) - len = l; - - return setup_sgl(fifo, sgl, nents, len, fifo->out); -} -EXPORT_SYMBOL(__kfifo_dma_out_prepare); - -unsigned int __kfifo_max_r(unsigned int len, size_t recsize) -{ - unsigned int max = (1 << (recsize << 3)) - 1; - - if (len > max) - return max; - return len; -} -EXPORT_SYMBOL(__kfifo_max_r); - -#define __KFIFO_PEEK(data, out, mask) \ - ((data)[(out) & (mask)]) -/* - * __kfifo_peek_n internal helper function for determinate the length of - * the next record in the fifo - */ -static unsigned int __kfifo_peek_n(struct __kfifo *fifo, size_t recsize) -{ - unsigned int l; - unsigned int mask = fifo->mask; - unsigned char *data = fifo->data; - - l = __KFIFO_PEEK(data, fifo->out, mask); - - if (--recsize) - l |= __KFIFO_PEEK(data, fifo->out + 1, mask) << 8; - - return l; -} - -#define __KFIFO_POKE(data, in, mask, val) \ - ( \ - (data)[(in) & (mask)] = (unsigned char)(val) \ - ) - -/* - * __kfifo_poke_n internal helper function for storeing the length of - * the record into the fifo - */ -static void __kfifo_poke_n(struct __kfifo *fifo, unsigned int n, size_t recsize) -{ - unsigned int mask = fifo->mask; - unsigned char *data = fifo->data; - - __KFIFO_POKE(data, fifo->in, mask, n); - - if (recsize > 1) - __KFIFO_POKE(data, fifo->in + 1, mask, n >> 8); -} - -unsigned int __kfifo_len_r(struct __kfifo *fifo, size_t recsize) -{ - return __kfifo_peek_n(fifo, recsize); -} -EXPORT_SYMBOL(__kfifo_len_r); - -unsigned int __kfifo_in_r(struct __kfifo *fifo, const void *buf, - unsigned int len, size_t recsize) -{ - if (len + recsize > kfifo_unused(fifo)) - return 0; - - __kfifo_poke_n(fifo, len, recsize); - - kfifo_copy_in(fifo, buf, len, fifo->in + recsize); - fifo->in += len + recsize; - return len; -} -EXPORT_SYMBOL(__kfifo_in_r); - -static unsigned int kfifo_out_copy_r(struct __kfifo *fifo, - void *buf, unsigned int len, size_t recsize, unsigned int *n) -{ - *n = __kfifo_peek_n(fifo, recsize); - - if (len > *n) - len = *n; - - kfifo_copy_out(fifo, buf, len, fifo->out + recsize); - return len; -} - -unsigned int __kfifo_out_peek_r(struct __kfifo *fifo, void *buf, - unsigned int len, size_t recsize) -{ - unsigned int n; - - if (fifo->in == fifo->out) - return 0; - - return kfifo_out_copy_r(fifo, buf, len, recsize, &n); -} -EXPORT_SYMBOL(__kfifo_out_peek_r); - -unsigned int __kfifo_out_r(struct __kfifo *fifo, void *buf, - unsigned int len, size_t recsize) -{ - unsigned int n; - - if (fifo->in == fifo->out) - return 0; - - len = kfifo_out_copy_r(fifo, buf, len, recsize, &n); - fifo->out += n + recsize; - return len; -} -EXPORT_SYMBOL(__kfifo_out_r); - -void __kfifo_skip_r(struct __kfifo *fifo, size_t recsize) -{ - unsigned int n; - - n = __kfifo_peek_n(fifo, recsize); - fifo->out += n + recsize; -} -EXPORT_SYMBOL(__kfifo_skip_r); - -int __kfifo_from_user_r(struct __kfifo *fifo, const void __user *from, - unsigned long len, unsigned int *copied, size_t recsize) -{ - unsigned long ret; - - len = __kfifo_max_r(len, recsize); - - if (len + recsize > kfifo_unused(fifo)) { - *copied = 0; - return 0; - } - - __kfifo_poke_n(fifo, len, recsize); - - ret = kfifo_copy_from_user(fifo, from, len, fifo->in + recsize, copied); - if (unlikely(ret)) { - *copied = 0; - return -EFAULT; - } - fifo->in += len + recsize; - return 0; -} -EXPORT_SYMBOL(__kfifo_from_user_r); - -int __kfifo_to_user_r(struct __kfifo *fifo, void __user *to, - unsigned long len, unsigned int *copied, size_t recsize) -{ - unsigned long ret; - unsigned int n; - - if (fifo->in == fifo->out) { - *copied = 0; - return 0; - } - - n = __kfifo_peek_n(fifo, recsize); - if (len > n) - len = n; - - ret = kfifo_copy_to_user(fifo, to, len, fifo->out + recsize, copied); - if (unlikely(ret)) { - *copied = 0; - return -EFAULT; - } - fifo->out += n + recsize; - return 0; -} -EXPORT_SYMBOL(__kfifo_to_user_r); - -unsigned int __kfifo_dma_in_prepare_r(struct __kfifo *fifo, - struct scatterlist *sgl, int nents, unsigned int len, size_t recsize) -{ - BUG_ON(!nents); - - len = __kfifo_max_r(len, recsize); - - if (len + recsize > kfifo_unused(fifo)) - return 0; - - return setup_sgl(fifo, sgl, nents, len, fifo->in + recsize); -} -EXPORT_SYMBOL(__kfifo_dma_in_prepare_r); - -void __kfifo_dma_in_finish_r(struct __kfifo *fifo, - unsigned int len, size_t recsize) -{ - len = __kfifo_max_r(len, recsize); - __kfifo_poke_n(fifo, len, recsize); - fifo->in += len + recsize; -} -EXPORT_SYMBOL(__kfifo_dma_in_finish_r); - -unsigned int __kfifo_dma_out_prepare_r(struct __kfifo *fifo, - struct scatterlist *sgl, int nents, unsigned int len, size_t recsize) -{ - BUG_ON(!nents); - - len = __kfifo_max_r(len, recsize); - - if (len + recsize > fifo->in - fifo->out) - return 0; - - return setup_sgl(fifo, sgl, nents, len, fifo->out + recsize); -} -EXPORT_SYMBOL(__kfifo_dma_out_prepare_r); - -void __kfifo_dma_out_finish_r(struct __kfifo *fifo, size_t recsize) -{ - unsigned int len; - - len = __kfifo_peek_n(fifo, recsize); - fifo->out += len + recsize; -} -EXPORT_SYMBOL(__kfifo_dma_out_finish_r); diff --git a/src/linux/lib/klist.c b/src/linux/lib/klist.c deleted file mode 100644 index 0507fa5..0000000 --- a/src/linux/lib/klist.c +++ /dev/null @@ -1,406 +0,0 @@ -/* - * klist.c - Routines for manipulating klists. - * - * Copyright (C) 2005 Patrick Mochel - * - * This file is released under the GPL v2. - * - * This klist interface provides a couple of structures that wrap around - * struct list_head to provide explicit list "head" (struct klist) and list - * "node" (struct klist_node) objects. For struct klist, a spinlock is - * included that protects access to the actual list itself. struct - * klist_node provides a pointer to the klist that owns it and a kref - * reference count that indicates the number of current users of that node - * in the list. - * - * The entire point is to provide an interface for iterating over a list - * that is safe and allows for modification of the list during the - * iteration (e.g. insertion and removal), including modification of the - * current node on the list. - * - * It works using a 3rd object type - struct klist_iter - that is declared - * and initialized before an iteration. klist_next() is used to acquire the - * next element in the list. It returns NULL if there are no more items. - * Internally, that routine takes the klist's lock, decrements the - * reference count of the previous klist_node and increments the count of - * the next klist_node. It then drops the lock and returns. - * - * There are primitives for adding and removing nodes to/from a klist. - * When deleting, klist_del() will simply decrement the reference count. - * Only when the count goes to 0 is the node removed from the list. - * klist_remove() will try to delete the node from the list and block until - * it is actually removed. This is useful for objects (like devices) that - * have been removed from the system and must be freed (but must wait until - * all accessors have finished). - */ - -#include -#include -#include - -/* - * Use the lowest bit of n_klist to mark deleted nodes and exclude - * dead ones from iteration. - */ -#define KNODE_DEAD 1LU -#define KNODE_KLIST_MASK ~KNODE_DEAD - -static struct klist *knode_klist(struct klist_node *knode) -{ - return (struct klist *) - ((unsigned long)knode->n_klist & KNODE_KLIST_MASK); -} - -static bool knode_dead(struct klist_node *knode) -{ - return (unsigned long)knode->n_klist & KNODE_DEAD; -} - -static void knode_set_klist(struct klist_node *knode, struct klist *klist) -{ - knode->n_klist = klist; - /* no knode deserves to start its life dead */ - WARN_ON(knode_dead(knode)); -} - -static void knode_kill(struct klist_node *knode) -{ - /* and no knode should die twice ever either, see we're very humane */ - WARN_ON(knode_dead(knode)); - *(unsigned long *)&knode->n_klist |= KNODE_DEAD; -} - -/** - * klist_init - Initialize a klist structure. - * @k: The klist we're initializing. - * @get: The get function for the embedding object (NULL if none) - * @put: The put function for the embedding object (NULL if none) - * - * Initialises the klist structure. If the klist_node structures are - * going to be embedded in refcounted objects (necessary for safe - * deletion) then the get/put arguments are used to initialise - * functions that take and release references on the embedding - * objects. - */ -void klist_init(struct klist *k, void (*get)(struct klist_node *), - void (*put)(struct klist_node *)) -{ - INIT_LIST_HEAD(&k->k_list); - spin_lock_init(&k->k_lock); - k->get = get; - k->put = put; -} -EXPORT_SYMBOL_GPL(klist_init); - -static void add_head(struct klist *k, struct klist_node *n) -{ - spin_lock(&k->k_lock); - list_add(&n->n_node, &k->k_list); - spin_unlock(&k->k_lock); -} - -static void add_tail(struct klist *k, struct klist_node *n) -{ - spin_lock(&k->k_lock); - list_add_tail(&n->n_node, &k->k_list); - spin_unlock(&k->k_lock); -} - -static void klist_node_init(struct klist *k, struct klist_node *n) -{ - INIT_LIST_HEAD(&n->n_node); - kref_init(&n->n_ref); - knode_set_klist(n, k); - if (k->get) - k->get(n); -} - -/** - * klist_add_head - Initialize a klist_node and add it to front. - * @n: node we're adding. - * @k: klist it's going on. - */ -void klist_add_head(struct klist_node *n, struct klist *k) -{ - klist_node_init(k, n); - add_head(k, n); -} -EXPORT_SYMBOL_GPL(klist_add_head); - -/** - * klist_add_tail - Initialize a klist_node and add it to back. - * @n: node we're adding. - * @k: klist it's going on. - */ -void klist_add_tail(struct klist_node *n, struct klist *k) -{ - klist_node_init(k, n); - add_tail(k, n); -} -EXPORT_SYMBOL_GPL(klist_add_tail); - -/** - * klist_add_behind - Init a klist_node and add it after an existing node - * @n: node we're adding. - * @pos: node to put @n after - */ -void klist_add_behind(struct klist_node *n, struct klist_node *pos) -{ - struct klist *k = knode_klist(pos); - - klist_node_init(k, n); - spin_lock(&k->k_lock); - list_add(&n->n_node, &pos->n_node); - spin_unlock(&k->k_lock); -} -EXPORT_SYMBOL_GPL(klist_add_behind); - -/** - * klist_add_before - Init a klist_node and add it before an existing node - * @n: node we're adding. - * @pos: node to put @n after - */ -void klist_add_before(struct klist_node *n, struct klist_node *pos) -{ - struct klist *k = knode_klist(pos); - - klist_node_init(k, n); - spin_lock(&k->k_lock); - list_add_tail(&n->n_node, &pos->n_node); - spin_unlock(&k->k_lock); -} -EXPORT_SYMBOL_GPL(klist_add_before); - -struct klist_waiter { - struct list_head list; - struct klist_node *node; - struct task_struct *process; - int woken; -}; - -static DEFINE_SPINLOCK(klist_remove_lock); -static LIST_HEAD(klist_remove_waiters); - -static void klist_release(struct kref *kref) -{ - struct klist_waiter *waiter, *tmp; - struct klist_node *n = container_of(kref, struct klist_node, n_ref); - - WARN_ON(!knode_dead(n)); - list_del(&n->n_node); - spin_lock(&klist_remove_lock); - list_for_each_entry_safe(waiter, tmp, &klist_remove_waiters, list) { - if (waiter->node != n) - continue; - - list_del(&waiter->list); - waiter->woken = 1; - mb(); - wake_up_process(waiter->process); - } - spin_unlock(&klist_remove_lock); - knode_set_klist(n, NULL); -} - -static int klist_dec_and_del(struct klist_node *n) -{ - return kref_put(&n->n_ref, klist_release); -} - -static void klist_put(struct klist_node *n, bool kill) -{ - struct klist *k = knode_klist(n); - void (*put)(struct klist_node *) = k->put; - - spin_lock(&k->k_lock); - if (kill) - knode_kill(n); - if (!klist_dec_and_del(n)) - put = NULL; - spin_unlock(&k->k_lock); - if (put) - put(n); -} - -/** - * klist_del - Decrement the reference count of node and try to remove. - * @n: node we're deleting. - */ -void klist_del(struct klist_node *n) -{ - klist_put(n, true); -} -EXPORT_SYMBOL_GPL(klist_del); - -/** - * klist_remove - Decrement the refcount of node and wait for it to go away. - * @n: node we're removing. - */ -void klist_remove(struct klist_node *n) -{ - struct klist_waiter waiter; - - waiter.node = n; - waiter.process = current; - waiter.woken = 0; - spin_lock(&klist_remove_lock); - list_add(&waiter.list, &klist_remove_waiters); - spin_unlock(&klist_remove_lock); - - klist_del(n); - - for (;;) { - set_current_state(TASK_UNINTERRUPTIBLE); - if (waiter.woken) - break; - schedule(); - } - __set_current_state(TASK_RUNNING); -} -EXPORT_SYMBOL_GPL(klist_remove); - -/** - * klist_node_attached - Say whether a node is bound to a list or not. - * @n: Node that we're testing. - */ -int klist_node_attached(struct klist_node *n) -{ - return (n->n_klist != NULL); -} -EXPORT_SYMBOL_GPL(klist_node_attached); - -/** - * klist_iter_init_node - Initialize a klist_iter structure. - * @k: klist we're iterating. - * @i: klist_iter we're filling. - * @n: node to start with. - * - * Similar to klist_iter_init(), but starts the action off with @n, - * instead of with the list head. - */ -void klist_iter_init_node(struct klist *k, struct klist_iter *i, - struct klist_node *n) -{ - i->i_klist = k; - i->i_cur = NULL; - if (n && kref_get_unless_zero(&n->n_ref)) - i->i_cur = n; -} -EXPORT_SYMBOL_GPL(klist_iter_init_node); - -/** - * klist_iter_init - Iniitalize a klist_iter structure. - * @k: klist we're iterating. - * @i: klist_iter structure we're filling. - * - * Similar to klist_iter_init_node(), but start with the list head. - */ -void klist_iter_init(struct klist *k, struct klist_iter *i) -{ - klist_iter_init_node(k, i, NULL); -} -EXPORT_SYMBOL_GPL(klist_iter_init); - -/** - * klist_iter_exit - Finish a list iteration. - * @i: Iterator structure. - * - * Must be called when done iterating over list, as it decrements the - * refcount of the current node. Necessary in case iteration exited before - * the end of the list was reached, and always good form. - */ -void klist_iter_exit(struct klist_iter *i) -{ - if (i->i_cur) { - klist_put(i->i_cur, false); - i->i_cur = NULL; - } -} -EXPORT_SYMBOL_GPL(klist_iter_exit); - -static struct klist_node *to_klist_node(struct list_head *n) -{ - return container_of(n, struct klist_node, n_node); -} - -/** - * klist_prev - Ante up prev node in list. - * @i: Iterator structure. - * - * First grab list lock. Decrement the reference count of the previous - * node, if there was one. Grab the prev node, increment its reference - * count, drop the lock, and return that prev node. - */ -struct klist_node *klist_prev(struct klist_iter *i) -{ - void (*put)(struct klist_node *) = i->i_klist->put; - struct klist_node *last = i->i_cur; - struct klist_node *prev; - - spin_lock(&i->i_klist->k_lock); - - if (last) { - prev = to_klist_node(last->n_node.prev); - if (!klist_dec_and_del(last)) - put = NULL; - } else - prev = to_klist_node(i->i_klist->k_list.prev); - - i->i_cur = NULL; - while (prev != to_klist_node(&i->i_klist->k_list)) { - if (likely(!knode_dead(prev))) { - kref_get(&prev->n_ref); - i->i_cur = prev; - break; - } - prev = to_klist_node(prev->n_node.prev); - } - - spin_unlock(&i->i_klist->k_lock); - - if (put && last) - put(last); - return i->i_cur; -} -EXPORT_SYMBOL_GPL(klist_prev); - -/** - * klist_next - Ante up next node in list. - * @i: Iterator structure. - * - * First grab list lock. Decrement the reference count of the previous - * node, if there was one. Grab the next node, increment its reference - * count, drop the lock, and return that next node. - */ -struct klist_node *klist_next(struct klist_iter *i) -{ - void (*put)(struct klist_node *) = i->i_klist->put; - struct klist_node *last = i->i_cur; - struct klist_node *next; - - spin_lock(&i->i_klist->k_lock); - - if (last) { - next = to_klist_node(last->n_node.next); - if (!klist_dec_and_del(last)) - put = NULL; - } else - next = to_klist_node(i->i_klist->k_list.next); - - i->i_cur = NULL; - while (next != to_klist_node(&i->i_klist->k_list)) { - if (likely(!knode_dead(next))) { - kref_get(&next->n_ref); - i->i_cur = next; - break; - } - next = to_klist_node(next->n_node.next); - } - - spin_unlock(&i->i_klist->k_lock); - - if (put && last) - put(last); - return i->i_cur; -} -EXPORT_SYMBOL_GPL(klist_next); diff --git a/src/linux/lib/kobject.c b/src/linux/lib/kobject.c deleted file mode 100644 index 445dcae..0000000 --- a/src/linux/lib/kobject.c +++ /dev/null @@ -1,1073 +0,0 @@ -/* - * kobject.c - library routines for handling generic kernel objects - * - * Copyright (c) 2002-2003 Patrick Mochel - * Copyright (c) 2006-2007 Greg Kroah-Hartman - * Copyright (c) 2006-2007 Novell Inc. - * - * This file is released under the GPLv2. - * - * - * Please see the file Documentation/kobject.txt for critical information - * about using the kobject interface. - */ - -#include -#include -#include -#include -#include -#include - -/** - * kobject_namespace - return @kobj's namespace tag - * @kobj: kobject in question - * - * Returns namespace tag of @kobj if its parent has namespace ops enabled - * and thus @kobj should have a namespace tag associated with it. Returns - * %NULL otherwise. - */ -const void *kobject_namespace(struct kobject *kobj) -{ - const struct kobj_ns_type_operations *ns_ops = kobj_ns_ops(kobj); - - if (!ns_ops || ns_ops->type == KOBJ_NS_TYPE_NONE) - return NULL; - - return kobj->ktype->namespace(kobj); -} - -/* - * populate_dir - populate directory with attributes. - * @kobj: object we're working on. - * - * Most subsystems have a set of default attributes that are associated - * with an object that registers with them. This is a helper called during - * object registration that loops through the default attributes of the - * subsystem and creates attributes files for them in sysfs. - */ -static int populate_dir(struct kobject *kobj) -{ - struct kobj_type *t = get_ktype(kobj); - struct attribute *attr; - int error = 0; - int i; - - if (t && t->default_attrs) { - for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) { - error = sysfs_create_file(kobj, attr); - if (error) - break; - } - } - return error; -} - -static int create_dir(struct kobject *kobj) -{ - const struct kobj_ns_type_operations *ops; - int error; - - error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj)); - if (error) - return error; - - error = populate_dir(kobj); - if (error) { - sysfs_remove_dir(kobj); - return error; - } - - /* - * @kobj->sd may be deleted by an ancestor going away. Hold an - * extra reference so that it stays until @kobj is gone. - */ - sysfs_get(kobj->sd); - - /* - * If @kobj has ns_ops, its children need to be filtered based on - * their namespace tags. Enable namespace support on @kobj->sd. - */ - ops = kobj_child_ns_ops(kobj); - if (ops) { - BUG_ON(ops->type <= KOBJ_NS_TYPE_NONE); - BUG_ON(ops->type >= KOBJ_NS_TYPES); - BUG_ON(!kobj_ns_type_registered(ops->type)); - - sysfs_enable_ns(kobj->sd); - } - - return 0; -} - -static int get_kobj_path_length(struct kobject *kobj) -{ - int length = 1; - struct kobject *parent = kobj; - - /* walk up the ancestors until we hit the one pointing to the - * root. - * Add 1 to strlen for leading '/' of each level. - */ - do { - if (kobject_name(parent) == NULL) - return 0; - length += strlen(kobject_name(parent)) + 1; - parent = parent->parent; - } while (parent); - return length; -} - -static void fill_kobj_path(struct kobject *kobj, char *path, int length) -{ - struct kobject *parent; - - --length; - for (parent = kobj; parent; parent = parent->parent) { - int cur = strlen(kobject_name(parent)); - /* back up enough to print this name with '/' */ - length -= cur; - strncpy(path + length, kobject_name(parent), cur); - *(path + --length) = '/'; - } - - pr_debug("kobject: '%s' (%p): %s: path = '%s'\n", kobject_name(kobj), - kobj, __func__, path); -} - -/** - * kobject_get_path - generate and return the path associated with a given kobj and kset pair. - * - * @kobj: kobject in question, with which to build the path - * @gfp_mask: the allocation type used to allocate the path - * - * The result must be freed by the caller with kfree(). - */ -char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask) -{ - char *path; - int len; - - len = get_kobj_path_length(kobj); - if (len == 0) - return NULL; - path = kzalloc(len, gfp_mask); - if (!path) - return NULL; - fill_kobj_path(kobj, path, len); - - return path; -} -EXPORT_SYMBOL_GPL(kobject_get_path); - -/* add the kobject to its kset's list */ -static void kobj_kset_join(struct kobject *kobj) -{ - if (!kobj->kset) - return; - - kset_get(kobj->kset); - spin_lock(&kobj->kset->list_lock); - list_add_tail(&kobj->entry, &kobj->kset->list); - spin_unlock(&kobj->kset->list_lock); -} - -/* remove the kobject from its kset's list */ -static void kobj_kset_leave(struct kobject *kobj) -{ - if (!kobj->kset) - return; - - spin_lock(&kobj->kset->list_lock); - list_del_init(&kobj->entry); - spin_unlock(&kobj->kset->list_lock); - kset_put(kobj->kset); -} - -static void kobject_init_internal(struct kobject *kobj) -{ - if (!kobj) - return; - kref_init(&kobj->kref); - INIT_LIST_HEAD(&kobj->entry); - kobj->state_in_sysfs = 0; - kobj->state_add_uevent_sent = 0; - kobj->state_remove_uevent_sent = 0; - kobj->state_initialized = 1; -} - - -static int kobject_add_internal(struct kobject *kobj) -{ - int error = 0; - struct kobject *parent; - - if (!kobj) - return -ENOENT; - - if (!kobj->name || !kobj->name[0]) { - WARN(1, "kobject: (%p): attempted to be registered with empty " - "name!\n", kobj); - return -EINVAL; - } - - parent = kobject_get(kobj->parent); - - /* join kset if set, use it as parent if we do not already have one */ - if (kobj->kset) { - if (!parent) - parent = kobject_get(&kobj->kset->kobj); - kobj_kset_join(kobj); - kobj->parent = parent; - } - - pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n", - kobject_name(kobj), kobj, __func__, - parent ? kobject_name(parent) : "", - kobj->kset ? kobject_name(&kobj->kset->kobj) : ""); - - error = create_dir(kobj); - if (error) { - kobj_kset_leave(kobj); - kobject_put(parent); - kobj->parent = NULL; - - /* be noisy on error issues */ - if (error == -EEXIST) - WARN(1, "%s failed for %s with " - "-EEXIST, don't try to register things with " - "the same name in the same directory.\n", - __func__, kobject_name(kobj)); - else - WARN(1, "%s failed for %s (error: %d parent: %s)\n", - __func__, kobject_name(kobj), error, - parent ? kobject_name(parent) : "'none'"); - } else - kobj->state_in_sysfs = 1; - - return error; -} - -/** - * kobject_set_name_vargs - Set the name of an kobject - * @kobj: struct kobject to set the name of - * @fmt: format string used to build the name - * @vargs: vargs to format the string. - */ -int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, - va_list vargs) -{ - const char *s; - - if (kobj->name && !fmt) - return 0; - - s = kvasprintf_const(GFP_KERNEL, fmt, vargs); - if (!s) - return -ENOMEM; - - /* - * ewww... some of these buggers have '/' in the name ... If - * that's the case, we need to make sure we have an actual - * allocated copy to modify, since kvasprintf_const may have - * returned something from .rodata. - */ - if (strchr(s, '/')) { - char *t; - - t = kstrdup(s, GFP_KERNEL); - kfree_const(s); - if (!t) - return -ENOMEM; - strreplace(t, '/', '!'); - s = t; - } - kfree_const(kobj->name); - kobj->name = s; - - return 0; -} - -/** - * kobject_set_name - Set the name of a kobject - * @kobj: struct kobject to set the name of - * @fmt: format string used to build the name - * - * This sets the name of the kobject. If you have already added the - * kobject to the system, you must call kobject_rename() in order to - * change the name of the kobject. - */ -int kobject_set_name(struct kobject *kobj, const char *fmt, ...) -{ - va_list vargs; - int retval; - - va_start(vargs, fmt); - retval = kobject_set_name_vargs(kobj, fmt, vargs); - va_end(vargs); - - return retval; -} -EXPORT_SYMBOL(kobject_set_name); - -/** - * kobject_init - initialize a kobject structure - * @kobj: pointer to the kobject to initialize - * @ktype: pointer to the ktype for this kobject. - * - * This function will properly initialize a kobject such that it can then - * be passed to the kobject_add() call. - * - * After this function is called, the kobject MUST be cleaned up by a call - * to kobject_put(), not by a call to kfree directly to ensure that all of - * the memory is cleaned up properly. - */ -void kobject_init(struct kobject *kobj, struct kobj_type *ktype) -{ - char *err_str; - - if (!kobj) { - err_str = "invalid kobject pointer!"; - goto error; - } - if (!ktype) { - err_str = "must have a ktype to be initialized properly!\n"; - goto error; - } - if (kobj->state_initialized) { - /* do not error out as sometimes we can recover */ - printk(KERN_ERR "kobject (%p): tried to init an initialized " - "object, something is seriously wrong.\n", kobj); - dump_stack(); - } - - kobject_init_internal(kobj); - kobj->ktype = ktype; - return; - -error: - printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str); - dump_stack(); -} -EXPORT_SYMBOL(kobject_init); - -static __printf(3, 0) int kobject_add_varg(struct kobject *kobj, - struct kobject *parent, - const char *fmt, va_list vargs) -{ - int retval; - - retval = kobject_set_name_vargs(kobj, fmt, vargs); - if (retval) { - printk(KERN_ERR "kobject: can not set name properly!\n"); - return retval; - } - kobj->parent = parent; - return kobject_add_internal(kobj); -} - -/** - * kobject_add - the main kobject add function - * @kobj: the kobject to add - * @parent: pointer to the parent of the kobject. - * @fmt: format to name the kobject with. - * - * The kobject name is set and added to the kobject hierarchy in this - * function. - * - * If @parent is set, then the parent of the @kobj will be set to it. - * If @parent is NULL, then the parent of the @kobj will be set to the - * kobject associated with the kset assigned to this kobject. If no kset - * is assigned to the kobject, then the kobject will be located in the - * root of the sysfs tree. - * - * If this function returns an error, kobject_put() must be called to - * properly clean up the memory associated with the object. - * Under no instance should the kobject that is passed to this function - * be directly freed with a call to kfree(), that can leak memory. - * - * Note, no "add" uevent will be created with this call, the caller should set - * up all of the necessary sysfs files for the object and then call - * kobject_uevent() with the UEVENT_ADD parameter to ensure that - * userspace is properly notified of this kobject's creation. - */ -int kobject_add(struct kobject *kobj, struct kobject *parent, - const char *fmt, ...) -{ - va_list args; - int retval; - - if (!kobj) - return -EINVAL; - - if (!kobj->state_initialized) { - printk(KERN_ERR "kobject '%s' (%p): tried to add an " - "uninitialized object, something is seriously wrong.\n", - kobject_name(kobj), kobj); - dump_stack(); - return -EINVAL; - } - va_start(args, fmt); - retval = kobject_add_varg(kobj, parent, fmt, args); - va_end(args); - - return retval; -} -EXPORT_SYMBOL(kobject_add); - -/** - * kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy - * @kobj: pointer to the kobject to initialize - * @ktype: pointer to the ktype for this kobject. - * @parent: pointer to the parent of this kobject. - * @fmt: the name of the kobject. - * - * This function combines the call to kobject_init() and - * kobject_add(). The same type of error handling after a call to - * kobject_add() and kobject lifetime rules are the same here. - */ -int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, - struct kobject *parent, const char *fmt, ...) -{ - va_list args; - int retval; - - kobject_init(kobj, ktype); - - va_start(args, fmt); - retval = kobject_add_varg(kobj, parent, fmt, args); - va_end(args); - - return retval; -} -EXPORT_SYMBOL_GPL(kobject_init_and_add); - -/** - * kobject_rename - change the name of an object - * @kobj: object in question. - * @new_name: object's new name - * - * It is the responsibility of the caller to provide mutual - * exclusion between two different calls of kobject_rename - * on the same kobject and to ensure that new_name is valid and - * won't conflict with other kobjects. - */ -int kobject_rename(struct kobject *kobj, const char *new_name) -{ - int error = 0; - const char *devpath = NULL; - const char *dup_name = NULL, *name; - char *devpath_string = NULL; - char *envp[2]; - - kobj = kobject_get(kobj); - if (!kobj) - return -EINVAL; - if (!kobj->parent) - return -EINVAL; - - devpath = kobject_get_path(kobj, GFP_KERNEL); - if (!devpath) { - error = -ENOMEM; - goto out; - } - devpath_string = kmalloc(strlen(devpath) + 15, GFP_KERNEL); - if (!devpath_string) { - error = -ENOMEM; - goto out; - } - sprintf(devpath_string, "DEVPATH_OLD=%s", devpath); - envp[0] = devpath_string; - envp[1] = NULL; - - name = dup_name = kstrdup_const(new_name, GFP_KERNEL); - if (!name) { - error = -ENOMEM; - goto out; - } - - error = sysfs_rename_dir_ns(kobj, new_name, kobject_namespace(kobj)); - if (error) - goto out; - - /* Install the new kobject name */ - dup_name = kobj->name; - kobj->name = name; - - /* This function is mostly/only used for network interface. - * Some hotplug package track interfaces by their name and - * therefore want to know when the name is changed by the user. */ - kobject_uevent_env(kobj, KOBJ_MOVE, envp); - -out: - kfree_const(dup_name); - kfree(devpath_string); - kfree(devpath); - kobject_put(kobj); - - return error; -} -EXPORT_SYMBOL_GPL(kobject_rename); - -/** - * kobject_move - move object to another parent - * @kobj: object in question. - * @new_parent: object's new parent (can be NULL) - */ -int kobject_move(struct kobject *kobj, struct kobject *new_parent) -{ - int error; - struct kobject *old_parent; - const char *devpath = NULL; - char *devpath_string = NULL; - char *envp[2]; - - kobj = kobject_get(kobj); - if (!kobj) - return -EINVAL; - new_parent = kobject_get(new_parent); - if (!new_parent) { - if (kobj->kset) - new_parent = kobject_get(&kobj->kset->kobj); - } - - /* old object path */ - devpath = kobject_get_path(kobj, GFP_KERNEL); - if (!devpath) { - error = -ENOMEM; - goto out; - } - devpath_string = kmalloc(strlen(devpath) + 15, GFP_KERNEL); - if (!devpath_string) { - error = -ENOMEM; - goto out; - } - sprintf(devpath_string, "DEVPATH_OLD=%s", devpath); - envp[0] = devpath_string; - envp[1] = NULL; - error = sysfs_move_dir_ns(kobj, new_parent, kobject_namespace(kobj)); - if (error) - goto out; - old_parent = kobj->parent; - kobj->parent = new_parent; - new_parent = NULL; - kobject_put(old_parent); - kobject_uevent_env(kobj, KOBJ_MOVE, envp); -out: - kobject_put(new_parent); - kobject_put(kobj); - kfree(devpath_string); - kfree(devpath); - return error; -} -EXPORT_SYMBOL_GPL(kobject_move); - -/** - * kobject_del - unlink kobject from hierarchy. - * @kobj: object. - */ -void kobject_del(struct kobject *kobj) -{ - struct kernfs_node *sd; - - if (!kobj) - return; - - sd = kobj->sd; - sysfs_remove_dir(kobj); - sysfs_put(sd); - - kobj->state_in_sysfs = 0; - kobj_kset_leave(kobj); - kobject_put(kobj->parent); - kobj->parent = NULL; -} -EXPORT_SYMBOL(kobject_del); - -/** - * kobject_get - increment refcount for object. - * @kobj: object. - */ -struct kobject *kobject_get(struct kobject *kobj) -{ - if (kobj) { - if (!kobj->state_initialized) - WARN(1, KERN_WARNING "kobject: '%s' (%p): is not " - "initialized, yet kobject_get() is being " - "called.\n", kobject_name(kobj), kobj); - kref_get(&kobj->kref); - } - return kobj; -} -EXPORT_SYMBOL(kobject_get); - -static struct kobject * __must_check kobject_get_unless_zero(struct kobject *kobj) -{ - if (!kref_get_unless_zero(&kobj->kref)) - kobj = NULL; - return kobj; -} - -/* - * kobject_cleanup - free kobject resources. - * @kobj: object to cleanup - */ -static void kobject_cleanup(struct kobject *kobj) -{ - struct kobj_type *t = get_ktype(kobj); - const char *name = kobj->name; - - pr_debug("kobject: '%s' (%p): %s, parent %p\n", - kobject_name(kobj), kobj, __func__, kobj->parent); - - if (t && !t->release) - pr_debug("kobject: '%s' (%p): does not have a release() " - "function, it is broken and must be fixed.\n", - kobject_name(kobj), kobj); - - /* send "remove" if the caller did not do it but sent "add" */ - if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) { - pr_debug("kobject: '%s' (%p): auto cleanup 'remove' event\n", - kobject_name(kobj), kobj); - kobject_uevent(kobj, KOBJ_REMOVE); - } - - /* remove from sysfs if the caller did not do it */ - if (kobj->state_in_sysfs) { - pr_debug("kobject: '%s' (%p): auto cleanup kobject_del\n", - kobject_name(kobj), kobj); - kobject_del(kobj); - } - - if (t && t->release) { - pr_debug("kobject: '%s' (%p): calling ktype release\n", - kobject_name(kobj), kobj); - t->release(kobj); - } - - /* free name if we allocated it */ - if (name) { - pr_debug("kobject: '%s': free name\n", name); - kfree_const(name); - } -} - -#ifdef CONFIG_DEBUG_KOBJECT_RELEASE -static void kobject_delayed_cleanup(struct work_struct *work) -{ - kobject_cleanup(container_of(to_delayed_work(work), - struct kobject, release)); -} -#endif - -static void kobject_release(struct kref *kref) -{ - struct kobject *kobj = container_of(kref, struct kobject, kref); -#ifdef CONFIG_DEBUG_KOBJECT_RELEASE - unsigned long delay = HZ + HZ * (get_random_int() & 0x3); - pr_info("kobject: '%s' (%p): %s, parent %p (delayed %ld)\n", - kobject_name(kobj), kobj, __func__, kobj->parent, delay); - INIT_DELAYED_WORK(&kobj->release, kobject_delayed_cleanup); - - schedule_delayed_work(&kobj->release, delay); -#else - kobject_cleanup(kobj); -#endif -} - -/** - * kobject_put - decrement refcount for object. - * @kobj: object. - * - * Decrement the refcount, and if 0, call kobject_cleanup(). - */ -void kobject_put(struct kobject *kobj) -{ - if (kobj) { - if (!kobj->state_initialized) - WARN(1, KERN_WARNING "kobject: '%s' (%p): is not " - "initialized, yet kobject_put() is being " - "called.\n", kobject_name(kobj), kobj); - kref_put(&kobj->kref, kobject_release); - } -} -EXPORT_SYMBOL(kobject_put); - -static void dynamic_kobj_release(struct kobject *kobj) -{ - pr_debug("kobject: (%p): %s\n", kobj, __func__); - kfree(kobj); -} - -static struct kobj_type dynamic_kobj_ktype = { - .release = dynamic_kobj_release, - .sysfs_ops = &kobj_sysfs_ops, -}; - -/** - * kobject_create - create a struct kobject dynamically - * - * This function creates a kobject structure dynamically and sets it up - * to be a "dynamic" kobject with a default release function set up. - * - * If the kobject was not able to be created, NULL will be returned. - * The kobject structure returned from here must be cleaned up with a - * call to kobject_put() and not kfree(), as kobject_init() has - * already been called on this structure. - */ -struct kobject *kobject_create(void) -{ - struct kobject *kobj; - - kobj = kzalloc(sizeof(*kobj), GFP_KERNEL); - if (!kobj) - return NULL; - - kobject_init(kobj, &dynamic_kobj_ktype); - return kobj; -} - -/** - * kobject_create_and_add - create a struct kobject dynamically and register it with sysfs - * - * @name: the name for the kobject - * @parent: the parent kobject of this kobject, if any. - * - * This function creates a kobject structure dynamically and registers it - * with sysfs. When you are finished with this structure, call - * kobject_put() and the structure will be dynamically freed when - * it is no longer being used. - * - * If the kobject was not able to be created, NULL will be returned. - */ -struct kobject *kobject_create_and_add(const char *name, struct kobject *parent) -{ - struct kobject *kobj; - int retval; - - kobj = kobject_create(); - if (!kobj) - return NULL; - - retval = kobject_add(kobj, parent, "%s", name); - if (retval) { - printk(KERN_WARNING "%s: kobject_add error: %d\n", - __func__, retval); - kobject_put(kobj); - kobj = NULL; - } - return kobj; -} -EXPORT_SYMBOL_GPL(kobject_create_and_add); - -/** - * kset_init - initialize a kset for use - * @k: kset - */ -void kset_init(struct kset *k) -{ - kobject_init_internal(&k->kobj); - INIT_LIST_HEAD(&k->list); - spin_lock_init(&k->list_lock); -} - -/* default kobject attribute operations */ -static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct kobj_attribute *kattr; - ssize_t ret = -EIO; - - kattr = container_of(attr, struct kobj_attribute, attr); - if (kattr->show) - ret = kattr->show(kobj, kattr, buf); - return ret; -} - -static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t count) -{ - struct kobj_attribute *kattr; - ssize_t ret = -EIO; - - kattr = container_of(attr, struct kobj_attribute, attr); - if (kattr->store) - ret = kattr->store(kobj, kattr, buf, count); - return ret; -} - -const struct sysfs_ops kobj_sysfs_ops = { - .show = kobj_attr_show, - .store = kobj_attr_store, -}; -EXPORT_SYMBOL_GPL(kobj_sysfs_ops); - -/** - * kset_register - initialize and add a kset. - * @k: kset. - */ -int kset_register(struct kset *k) -{ - int err; - - if (!k) - return -EINVAL; - - kset_init(k); - err = kobject_add_internal(&k->kobj); - if (err) - return err; - kobject_uevent(&k->kobj, KOBJ_ADD); - return 0; -} -EXPORT_SYMBOL(kset_register); - -/** - * kset_unregister - remove a kset. - * @k: kset. - */ -void kset_unregister(struct kset *k) -{ - if (!k) - return; - kobject_del(&k->kobj); - kobject_put(&k->kobj); -} -EXPORT_SYMBOL(kset_unregister); - -/** - * kset_find_obj - search for object in kset. - * @kset: kset we're looking in. - * @name: object's name. - * - * Lock kset via @kset->subsys, and iterate over @kset->list, - * looking for a matching kobject. If matching object is found - * take a reference and return the object. - */ -struct kobject *kset_find_obj(struct kset *kset, const char *name) -{ - struct kobject *k; - struct kobject *ret = NULL; - - spin_lock(&kset->list_lock); - - list_for_each_entry(k, &kset->list, entry) { - if (kobject_name(k) && !strcmp(kobject_name(k), name)) { - ret = kobject_get_unless_zero(k); - break; - } - } - - spin_unlock(&kset->list_lock); - return ret; -} -EXPORT_SYMBOL_GPL(kset_find_obj); - -static void kset_release(struct kobject *kobj) -{ - struct kset *kset = container_of(kobj, struct kset, kobj); - pr_debug("kobject: '%s' (%p): %s\n", - kobject_name(kobj), kobj, __func__); - kfree(kset); -} - -static struct kobj_type kset_ktype = { - .sysfs_ops = &kobj_sysfs_ops, - .release = kset_release, -}; - -/** - * kset_create - create a struct kset dynamically - * - * @name: the name for the kset - * @uevent_ops: a struct kset_uevent_ops for the kset - * @parent_kobj: the parent kobject of this kset, if any. - * - * This function creates a kset structure dynamically. This structure can - * then be registered with the system and show up in sysfs with a call to - * kset_register(). When you are finished with this structure, if - * kset_register() has been called, call kset_unregister() and the - * structure will be dynamically freed when it is no longer being used. - * - * If the kset was not able to be created, NULL will be returned. - */ -static struct kset *kset_create(const char *name, - const struct kset_uevent_ops *uevent_ops, - struct kobject *parent_kobj) -{ - struct kset *kset; - int retval; - - kset = kzalloc(sizeof(*kset), GFP_KERNEL); - if (!kset) - return NULL; - retval = kobject_set_name(&kset->kobj, "%s", name); - if (retval) { - kfree(kset); - return NULL; - } - kset->uevent_ops = uevent_ops; - kset->kobj.parent = parent_kobj; - - /* - * The kobject of this kset will have a type of kset_ktype and belong to - * no kset itself. That way we can properly free it when it is - * finished being used. - */ - kset->kobj.ktype = &kset_ktype; - kset->kobj.kset = NULL; - - return kset; -} - -/** - * kset_create_and_add - create a struct kset dynamically and add it to sysfs - * - * @name: the name for the kset - * @uevent_ops: a struct kset_uevent_ops for the kset - * @parent_kobj: the parent kobject of this kset, if any. - * - * This function creates a kset structure dynamically and registers it - * with sysfs. When you are finished with this structure, call - * kset_unregister() and the structure will be dynamically freed when it - * is no longer being used. - * - * If the kset was not able to be created, NULL will be returned. - */ -struct kset *kset_create_and_add(const char *name, - const struct kset_uevent_ops *uevent_ops, - struct kobject *parent_kobj) -{ - struct kset *kset; - int error; - - kset = kset_create(name, uevent_ops, parent_kobj); - if (!kset) - return NULL; - error = kset_register(kset); - if (error) { - kfree(kset); - return NULL; - } - return kset; -} -EXPORT_SYMBOL_GPL(kset_create_and_add); - - -static DEFINE_SPINLOCK(kobj_ns_type_lock); -static const struct kobj_ns_type_operations *kobj_ns_ops_tbl[KOBJ_NS_TYPES]; - -int kobj_ns_type_register(const struct kobj_ns_type_operations *ops) -{ - enum kobj_ns_type type = ops->type; - int error; - - spin_lock(&kobj_ns_type_lock); - - error = -EINVAL; - if (type >= KOBJ_NS_TYPES) - goto out; - - error = -EINVAL; - if (type <= KOBJ_NS_TYPE_NONE) - goto out; - - error = -EBUSY; - if (kobj_ns_ops_tbl[type]) - goto out; - - error = 0; - kobj_ns_ops_tbl[type] = ops; - -out: - spin_unlock(&kobj_ns_type_lock); - return error; -} - -int kobj_ns_type_registered(enum kobj_ns_type type) -{ - int registered = 0; - - spin_lock(&kobj_ns_type_lock); - if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES)) - registered = kobj_ns_ops_tbl[type] != NULL; - spin_unlock(&kobj_ns_type_lock); - - return registered; -} - -const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent) -{ - const struct kobj_ns_type_operations *ops = NULL; - - if (parent && parent->ktype && parent->ktype->child_ns_type) - ops = parent->ktype->child_ns_type(parent); - - return ops; -} - -const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj) -{ - return kobj_child_ns_ops(kobj->parent); -} - -bool kobj_ns_current_may_mount(enum kobj_ns_type type) -{ - bool may_mount = true; - - spin_lock(&kobj_ns_type_lock); - if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) && - kobj_ns_ops_tbl[type]) - may_mount = kobj_ns_ops_tbl[type]->current_may_mount(); - spin_unlock(&kobj_ns_type_lock); - - return may_mount; -} - -void *kobj_ns_grab_current(enum kobj_ns_type type) -{ - void *ns = NULL; - - spin_lock(&kobj_ns_type_lock); - if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) && - kobj_ns_ops_tbl[type]) - ns = kobj_ns_ops_tbl[type]->grab_current_ns(); - spin_unlock(&kobj_ns_type_lock); - - return ns; -} - -const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk) -{ - const void *ns = NULL; - - spin_lock(&kobj_ns_type_lock); - if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) && - kobj_ns_ops_tbl[type]) - ns = kobj_ns_ops_tbl[type]->netlink_ns(sk); - spin_unlock(&kobj_ns_type_lock); - - return ns; -} - -const void *kobj_ns_initial(enum kobj_ns_type type) -{ - const void *ns = NULL; - - spin_lock(&kobj_ns_type_lock); - if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) && - kobj_ns_ops_tbl[type]) - ns = kobj_ns_ops_tbl[type]->initial_ns(); - spin_unlock(&kobj_ns_type_lock); - - return ns; -} - -void kobj_ns_drop(enum kobj_ns_type type, void *ns) -{ - spin_lock(&kobj_ns_type_lock); - if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) && - kobj_ns_ops_tbl[type] && kobj_ns_ops_tbl[type]->drop_ns) - kobj_ns_ops_tbl[type]->drop_ns(ns); - spin_unlock(&kobj_ns_type_lock); -} diff --git a/src/linux/lib/kobject_uevent.c b/src/linux/lib/kobject_uevent.c deleted file mode 100644 index f6c2c1e..0000000 --- a/src/linux/lib/kobject_uevent.c +++ /dev/null @@ -1,471 +0,0 @@ -/* - * kernel userspace event delivery - * - * Copyright (C) 2004 Red Hat, Inc. All rights reserved. - * Copyright (C) 2004 Novell, Inc. All rights reserved. - * Copyright (C) 2004 IBM, Inc. All rights reserved. - * - * Licensed under the GNU GPL v2. - * - * Authors: - * Robert Love - * Kay Sievers - * Arjan van de Ven - * Greg Kroah-Hartman - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -u64 uevent_seqnum; -#ifdef CONFIG_UEVENT_HELPER -char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH; -#endif -#ifdef CONFIG_NET -struct uevent_sock { - struct list_head list; - struct sock *sk; -}; -static LIST_HEAD(uevent_sock_list); -#endif - -/* This lock protects uevent_seqnum and uevent_sock_list */ -static DEFINE_MUTEX(uevent_sock_mutex); - -/* the strings here must match the enum in include/linux/kobject.h */ -static const char *kobject_actions[] = { - [KOBJ_ADD] = "add", - [KOBJ_REMOVE] = "remove", - [KOBJ_CHANGE] = "change", - [KOBJ_MOVE] = "move", - [KOBJ_ONLINE] = "online", - [KOBJ_OFFLINE] = "offline", -}; - -/** - * kobject_action_type - translate action string to numeric type - * - * @buf: buffer containing the action string, newline is ignored - * @len: length of buffer - * @type: pointer to the location to store the action type - * - * Returns 0 if the action string was recognized. - */ -int kobject_action_type(const char *buf, size_t count, - enum kobject_action *type) -{ - enum kobject_action action; - int ret = -EINVAL; - - if (count && (buf[count-1] == '\n' || buf[count-1] == '\0')) - count--; - - if (!count) - goto out; - - for (action = 0; action < ARRAY_SIZE(kobject_actions); action++) { - if (strncmp(kobject_actions[action], buf, count) != 0) - continue; - if (kobject_actions[action][count] != '\0') - continue; - *type = action; - ret = 0; - break; - } -out: - return ret; -} - -#ifdef CONFIG_NET -static int kobj_bcast_filter(struct sock *dsk, struct sk_buff *skb, void *data) -{ - struct kobject *kobj = data, *ksobj; - const struct kobj_ns_type_operations *ops; - - ops = kobj_ns_ops(kobj); - if (!ops && kobj->kset) { - ksobj = &kobj->kset->kobj; - if (ksobj->parent != NULL) - ops = kobj_ns_ops(ksobj->parent); - } - - if (ops && ops->netlink_ns && kobj->ktype->namespace) { - const void *sock_ns, *ns; - ns = kobj->ktype->namespace(kobj); - sock_ns = ops->netlink_ns(dsk); - return sock_ns != ns; - } - - return 0; -} -#endif - -#ifdef CONFIG_UEVENT_HELPER -static int kobj_usermode_filter(struct kobject *kobj) -{ - const struct kobj_ns_type_operations *ops; - - ops = kobj_ns_ops(kobj); - if (ops) { - const void *init_ns, *ns; - ns = kobj->ktype->namespace(kobj); - init_ns = ops->initial_ns(); - return ns != init_ns; - } - - return 0; -} - -static int init_uevent_argv(struct kobj_uevent_env *env, const char *subsystem) -{ - int len; - - len = strlcpy(&env->buf[env->buflen], subsystem, - sizeof(env->buf) - env->buflen); - if (len >= (sizeof(env->buf) - env->buflen)) { - WARN(1, KERN_ERR "init_uevent_argv: buffer size too small\n"); - return -ENOMEM; - } - - env->argv[0] = uevent_helper; - env->argv[1] = &env->buf[env->buflen]; - env->argv[2] = NULL; - - env->buflen += len + 1; - return 0; -} - -static void cleanup_uevent_env(struct subprocess_info *info) -{ - kfree(info->data); -} -#endif - -/** - * kobject_uevent_env - send an uevent with environmental data - * - * @action: action that is happening - * @kobj: struct kobject that the action is happening to - * @envp_ext: pointer to environmental data - * - * Returns 0 if kobject_uevent_env() is completed with success or the - * corresponding error when it fails. - */ -int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, - char *envp_ext[]) -{ - struct kobj_uevent_env *env; - const char *action_string = kobject_actions[action]; - const char *devpath = NULL; - const char *subsystem; - struct kobject *top_kobj; - struct kset *kset; - const struct kset_uevent_ops *uevent_ops; - int i = 0; - int retval = 0; -#ifdef CONFIG_NET - struct uevent_sock *ue_sk; -#endif - - pr_debug("kobject: '%s' (%p): %s\n", - kobject_name(kobj), kobj, __func__); - - /* search the kset we belong to */ - top_kobj = kobj; - while (!top_kobj->kset && top_kobj->parent) - top_kobj = top_kobj->parent; - - if (!top_kobj->kset) { - pr_debug("kobject: '%s' (%p): %s: attempted to send uevent " - "without kset!\n", kobject_name(kobj), kobj, - __func__); - return -EINVAL; - } - - kset = top_kobj->kset; - uevent_ops = kset->uevent_ops; - - /* skip the event, if uevent_suppress is set*/ - if (kobj->uevent_suppress) { - pr_debug("kobject: '%s' (%p): %s: uevent_suppress " - "caused the event to drop!\n", - kobject_name(kobj), kobj, __func__); - return 0; - } - /* skip the event, if the filter returns zero. */ - if (uevent_ops && uevent_ops->filter) - if (!uevent_ops->filter(kset, kobj)) { - pr_debug("kobject: '%s' (%p): %s: filter function " - "caused the event to drop!\n", - kobject_name(kobj), kobj, __func__); - return 0; - } - - /* originating subsystem */ - if (uevent_ops && uevent_ops->name) - subsystem = uevent_ops->name(kset, kobj); - else - subsystem = kobject_name(&kset->kobj); - if (!subsystem) { - pr_debug("kobject: '%s' (%p): %s: unset subsystem caused the " - "event to drop!\n", kobject_name(kobj), kobj, - __func__); - return 0; - } - - /* environment buffer */ - env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); - if (!env) - return -ENOMEM; - - /* complete object path */ - devpath = kobject_get_path(kobj, GFP_KERNEL); - if (!devpath) { - retval = -ENOENT; - goto exit; - } - - /* default keys */ - retval = add_uevent_var(env, "ACTION=%s", action_string); - if (retval) - goto exit; - retval = add_uevent_var(env, "DEVPATH=%s", devpath); - if (retval) - goto exit; - retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem); - if (retval) - goto exit; - - /* keys passed in from the caller */ - if (envp_ext) { - for (i = 0; envp_ext[i]; i++) { - retval = add_uevent_var(env, "%s", envp_ext[i]); - if (retval) - goto exit; - } - } - - /* let the kset specific function add its stuff */ - if (uevent_ops && uevent_ops->uevent) { - retval = uevent_ops->uevent(kset, kobj, env); - if (retval) { - pr_debug("kobject: '%s' (%p): %s: uevent() returned " - "%d\n", kobject_name(kobj), kobj, - __func__, retval); - goto exit; - } - } - - /* - * Mark "add" and "remove" events in the object to ensure proper - * events to userspace during automatic cleanup. If the object did - * send an "add" event, "remove" will automatically generated by - * the core, if not already done by the caller. - */ - if (action == KOBJ_ADD) - kobj->state_add_uevent_sent = 1; - else if (action == KOBJ_REMOVE) - kobj->state_remove_uevent_sent = 1; - - mutex_lock(&uevent_sock_mutex); - /* we will send an event, so request a new sequence number */ - retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)++uevent_seqnum); - if (retval) { - mutex_unlock(&uevent_sock_mutex); - goto exit; - } - -#if defined(CONFIG_NET) - /* send netlink message */ - list_for_each_entry(ue_sk, &uevent_sock_list, list) { - struct sock *uevent_sock = ue_sk->sk; - struct sk_buff *skb; - size_t len; - - if (!netlink_has_listeners(uevent_sock, 1)) - continue; - - /* allocate message with the maximum possible size */ - len = strlen(action_string) + strlen(devpath) + 2; - skb = alloc_skb(len + env->buflen, GFP_KERNEL); - if (skb) { - char *scratch; - - /* add header */ - scratch = skb_put(skb, len); - sprintf(scratch, "%s@%s", action_string, devpath); - - /* copy keys to our continuous event payload buffer */ - for (i = 0; i < env->envp_idx; i++) { - len = strlen(env->envp[i]) + 1; - scratch = skb_put(skb, len); - strcpy(scratch, env->envp[i]); - } - - NETLINK_CB(skb).dst_group = 1; - retval = netlink_broadcast_filtered(uevent_sock, skb, - 0, 1, GFP_KERNEL, - kobj_bcast_filter, - kobj); - /* ENOBUFS should be handled in userspace */ - if (retval == -ENOBUFS || retval == -ESRCH) - retval = 0; - } else - retval = -ENOMEM; - } -#endif - mutex_unlock(&uevent_sock_mutex); - -#ifdef CONFIG_UEVENT_HELPER - /* call uevent_helper, usually only enabled during early boot */ - if (uevent_helper[0] && !kobj_usermode_filter(kobj)) { - struct subprocess_info *info; - - retval = add_uevent_var(env, "HOME=/"); - if (retval) - goto exit; - retval = add_uevent_var(env, - "PATH=/sbin:/bin:/usr/sbin:/usr/bin"); - if (retval) - goto exit; - retval = init_uevent_argv(env, subsystem); - if (retval) - goto exit; - - retval = -ENOMEM; - info = call_usermodehelper_setup(env->argv[0], env->argv, - env->envp, GFP_KERNEL, - NULL, cleanup_uevent_env, env); - if (info) { - retval = call_usermodehelper_exec(info, UMH_NO_WAIT); - env = NULL; /* freed by cleanup_uevent_env */ - } - } -#endif - -exit: - kfree(devpath); - kfree(env); - return retval; -} -EXPORT_SYMBOL_GPL(kobject_uevent_env); - -/** - * kobject_uevent - notify userspace by sending an uevent - * - * @action: action that is happening - * @kobj: struct kobject that the action is happening to - * - * Returns 0 if kobject_uevent() is completed with success or the - * corresponding error when it fails. - */ -int kobject_uevent(struct kobject *kobj, enum kobject_action action) -{ - return kobject_uevent_env(kobj, action, NULL); -} -EXPORT_SYMBOL_GPL(kobject_uevent); - -/** - * add_uevent_var - add key value string to the environment buffer - * @env: environment buffer structure - * @format: printf format for the key=value pair - * - * Returns 0 if environment variable was added successfully or -ENOMEM - * if no space was available. - */ -int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...) -{ - va_list args; - int len; - - if (env->envp_idx >= ARRAY_SIZE(env->envp)) { - WARN(1, KERN_ERR "add_uevent_var: too many keys\n"); - return -ENOMEM; - } - - va_start(args, format); - len = vsnprintf(&env->buf[env->buflen], - sizeof(env->buf) - env->buflen, - format, args); - va_end(args); - - if (len >= (sizeof(env->buf) - env->buflen)) { - WARN(1, KERN_ERR "add_uevent_var: buffer size too small\n"); - return -ENOMEM; - } - - env->envp[env->envp_idx++] = &env->buf[env->buflen]; - env->buflen += len + 1; - return 0; -} -EXPORT_SYMBOL_GPL(add_uevent_var); - -#if defined(CONFIG_NET) -static int uevent_net_init(struct net *net) -{ - struct uevent_sock *ue_sk; - struct netlink_kernel_cfg cfg = { - .groups = 1, - .flags = NL_CFG_F_NONROOT_RECV, - }; - - ue_sk = kzalloc(sizeof(*ue_sk), GFP_KERNEL); - if (!ue_sk) - return -ENOMEM; - - ue_sk->sk = netlink_kernel_create(net, NETLINK_KOBJECT_UEVENT, &cfg); - if (!ue_sk->sk) { - printk(KERN_ERR - "kobject_uevent: unable to create netlink socket!\n"); - kfree(ue_sk); - return -ENODEV; - } - mutex_lock(&uevent_sock_mutex); - list_add_tail(&ue_sk->list, &uevent_sock_list); - mutex_unlock(&uevent_sock_mutex); - return 0; -} - -static void uevent_net_exit(struct net *net) -{ - struct uevent_sock *ue_sk; - - mutex_lock(&uevent_sock_mutex); - list_for_each_entry(ue_sk, &uevent_sock_list, list) { - if (sock_net(ue_sk->sk) == net) - goto found; - } - mutex_unlock(&uevent_sock_mutex); - return; - -found: - list_del(&ue_sk->list); - mutex_unlock(&uevent_sock_mutex); - - netlink_kernel_release(ue_sk->sk); - kfree(ue_sk); -} - -static struct pernet_operations uevent_net_ops = { - .init = uevent_net_init, - .exit = uevent_net_exit, -}; - -static int __init kobject_uevent_init(void) -{ - return register_pernet_subsys(&uevent_net_ops); -} - - -postcore_initcall(kobject_uevent_init); -#endif diff --git a/src/linux/lib/kstrtox.c b/src/linux/lib/kstrtox.c deleted file mode 100644 index b8e2080..0000000 --- a/src/linux/lib/kstrtox.c +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Convert integer string representation to an integer. - * If an integer doesn't fit into specified type, -E is returned. - * - * Integer starts with optional sign. - * kstrtou*() functions do not accept sign "-". - * - * Radix 0 means autodetection: leading "0x" implies radix 16, - * leading "0" implies radix 8, otherwise radix is 10. - * Autodetection hints work after optional sign, but not before. - * - * If -E is returned, result is not touched. - */ -#include -#include -#include -#include -#include -#include -#include -#include "kstrtox.h" - -const char *_parse_integer_fixup_radix(const char *s, unsigned int *base) -{ - if (*base == 0) { - if (s[0] == '0') { - if (_tolower(s[1]) == 'x' && isxdigit(s[2])) - *base = 16; - else - *base = 8; - } else - *base = 10; - } - if (*base == 16 && s[0] == '0' && _tolower(s[1]) == 'x') - s += 2; - return s; -} - -/* - * Convert non-negative integer string representation in explicitly given radix - * to an integer. - * Return number of characters consumed maybe or-ed with overflow bit. - * If overflow occurs, result integer (incorrect) is still returned. - * - * Don't you dare use this function. - */ -unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *p) -{ - unsigned long long res; - unsigned int rv; - - res = 0; - rv = 0; - while (*s) { - unsigned int val; - - if ('0' <= *s && *s <= '9') - val = *s - '0'; - else if ('a' <= _tolower(*s) && _tolower(*s) <= 'f') - val = _tolower(*s) - 'a' + 10; - else - break; - - if (val >= base) - break; - /* - * Check for overflow only if we are within range of - * it in the max base we support (16) - */ - if (unlikely(res & (~0ull << 60))) { - if (res > div_u64(ULLONG_MAX - val, base)) - rv |= KSTRTOX_OVERFLOW; - } - res = res * base + val; - rv++; - s++; - } - *p = res; - return rv; -} - -static int _kstrtoull(const char *s, unsigned int base, unsigned long long *res) -{ - unsigned long long _res; - unsigned int rv; - - s = _parse_integer_fixup_radix(s, &base); - rv = _parse_integer(s, base, &_res); - if (rv & KSTRTOX_OVERFLOW) - return -ERANGE; - if (rv == 0) - return -EINVAL; - s += rv; - if (*s == '\n') - s++; - if (*s) - return -EINVAL; - *res = _res; - return 0; -} - -/** - * kstrtoull - convert a string to an unsigned long long - * @s: The start of the string. The string must be null-terminated, and may also - * include a single newline before its terminating null. The first character - * may also be a plus sign, but not a minus sign. - * @base: The number base to use. The maximum supported base is 16. If base is - * given as 0, then the base of the string is automatically detected with the - * conventional semantics - If it begins with 0x the number will be parsed as a - * hexadecimal (case insensitive), if it otherwise begins with 0, it will be - * parsed as an octal number. Otherwise it will be parsed as a decimal. - * @res: Where to write the result of the conversion on success. - * - * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. - * Used as a replacement for the obsolete simple_strtoull. Return code must - * be checked. - */ -int kstrtoull(const char *s, unsigned int base, unsigned long long *res) -{ - if (s[0] == '+') - s++; - return _kstrtoull(s, base, res); -} -EXPORT_SYMBOL(kstrtoull); - -/** - * kstrtoll - convert a string to a long long - * @s: The start of the string. The string must be null-terminated, and may also - * include a single newline before its terminating null. The first character - * may also be a plus sign or a minus sign. - * @base: The number base to use. The maximum supported base is 16. If base is - * given as 0, then the base of the string is automatically detected with the - * conventional semantics - If it begins with 0x the number will be parsed as a - * hexadecimal (case insensitive), if it otherwise begins with 0, it will be - * parsed as an octal number. Otherwise it will be parsed as a decimal. - * @res: Where to write the result of the conversion on success. - * - * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. - * Used as a replacement for the obsolete simple_strtoull. Return code must - * be checked. - */ -int kstrtoll(const char *s, unsigned int base, long long *res) -{ - unsigned long long tmp; - int rv; - - if (s[0] == '-') { - rv = _kstrtoull(s + 1, base, &tmp); - if (rv < 0) - return rv; - if ((long long)-tmp > 0) - return -ERANGE; - *res = -tmp; - } else { - rv = kstrtoull(s, base, &tmp); - if (rv < 0) - return rv; - if ((long long)tmp < 0) - return -ERANGE; - *res = tmp; - } - return 0; -} -EXPORT_SYMBOL(kstrtoll); - -/* Internal, do not use. */ -int _kstrtoul(const char *s, unsigned int base, unsigned long *res) -{ - unsigned long long tmp; - int rv; - - rv = kstrtoull(s, base, &tmp); - if (rv < 0) - return rv; - if (tmp != (unsigned long long)(unsigned long)tmp) - return -ERANGE; - *res = tmp; - return 0; -} -EXPORT_SYMBOL(_kstrtoul); - -/* Internal, do not use. */ -int _kstrtol(const char *s, unsigned int base, long *res) -{ - long long tmp; - int rv; - - rv = kstrtoll(s, base, &tmp); - if (rv < 0) - return rv; - if (tmp != (long long)(long)tmp) - return -ERANGE; - *res = tmp; - return 0; -} -EXPORT_SYMBOL(_kstrtol); - -/** - * kstrtouint - convert a string to an unsigned int - * @s: The start of the string. The string must be null-terminated, and may also - * include a single newline before its terminating null. The first character - * may also be a plus sign, but not a minus sign. - * @base: The number base to use. The maximum supported base is 16. If base is - * given as 0, then the base of the string is automatically detected with the - * conventional semantics - If it begins with 0x the number will be parsed as a - * hexadecimal (case insensitive), if it otherwise begins with 0, it will be - * parsed as an octal number. Otherwise it will be parsed as a decimal. - * @res: Where to write the result of the conversion on success. - * - * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. - * Used as a replacement for the obsolete simple_strtoull. Return code must - * be checked. - */ -int kstrtouint(const char *s, unsigned int base, unsigned int *res) -{ - unsigned long long tmp; - int rv; - - rv = kstrtoull(s, base, &tmp); - if (rv < 0) - return rv; - if (tmp != (unsigned long long)(unsigned int)tmp) - return -ERANGE; - *res = tmp; - return 0; -} -EXPORT_SYMBOL(kstrtouint); - -/** - * kstrtoint - convert a string to an int - * @s: The start of the string. The string must be null-terminated, and may also - * include a single newline before its terminating null. The first character - * may also be a plus sign or a minus sign. - * @base: The number base to use. The maximum supported base is 16. If base is - * given as 0, then the base of the string is automatically detected with the - * conventional semantics - If it begins with 0x the number will be parsed as a - * hexadecimal (case insensitive), if it otherwise begins with 0, it will be - * parsed as an octal number. Otherwise it will be parsed as a decimal. - * @res: Where to write the result of the conversion on success. - * - * Returns 0 on success, -ERANGE on overflow and -EINVAL on parsing error. - * Used as a replacement for the obsolete simple_strtoull. Return code must - * be checked. - */ -int kstrtoint(const char *s, unsigned int base, int *res) -{ - long long tmp; - int rv; - - rv = kstrtoll(s, base, &tmp); - if (rv < 0) - return rv; - if (tmp != (long long)(int)tmp) - return -ERANGE; - *res = tmp; - return 0; -} -EXPORT_SYMBOL(kstrtoint); - -int kstrtou16(const char *s, unsigned int base, u16 *res) -{ - unsigned long long tmp; - int rv; - - rv = kstrtoull(s, base, &tmp); - if (rv < 0) - return rv; - if (tmp != (unsigned long long)(u16)tmp) - return -ERANGE; - *res = tmp; - return 0; -} -EXPORT_SYMBOL(kstrtou16); - -int kstrtos16(const char *s, unsigned int base, s16 *res) -{ - long long tmp; - int rv; - - rv = kstrtoll(s, base, &tmp); - if (rv < 0) - return rv; - if (tmp != (long long)(s16)tmp) - return -ERANGE; - *res = tmp; - return 0; -} -EXPORT_SYMBOL(kstrtos16); - -int kstrtou8(const char *s, unsigned int base, u8 *res) -{ - unsigned long long tmp; - int rv; - - rv = kstrtoull(s, base, &tmp); - if (rv < 0) - return rv; - if (tmp != (unsigned long long)(u8)tmp) - return -ERANGE; - *res = tmp; - return 0; -} -EXPORT_SYMBOL(kstrtou8); - -int kstrtos8(const char *s, unsigned int base, s8 *res) -{ - long long tmp; - int rv; - - rv = kstrtoll(s, base, &tmp); - if (rv < 0) - return rv; - if (tmp != (long long)(s8)tmp) - return -ERANGE; - *res = tmp; - return 0; -} -EXPORT_SYMBOL(kstrtos8); - -/** - * kstrtobool - convert common user inputs into boolean values - * @s: input string - * @res: result - * - * This routine returns 0 iff the first character is one of 'Yy1Nn0', or - * [oO][NnFf] for "on" and "off". Otherwise it will return -EINVAL. Value - * pointed to by res is updated upon finding a match. - */ -int kstrtobool(const char *s, bool *res) -{ - if (!s) - return -EINVAL; - - switch (s[0]) { - case 'y': - case 'Y': - case '1': - *res = true; - return 0; - case 'n': - case 'N': - case '0': - *res = false; - return 0; - case 'o': - case 'O': - switch (s[1]) { - case 'n': - case 'N': - *res = true; - return 0; - case 'f': - case 'F': - *res = false; - return 0; - default: - break; - } - default: - break; - } - - return -EINVAL; -} -EXPORT_SYMBOL(kstrtobool); - -/* - * Since "base" would be a nonsense argument, this open-codes the - * _from_user helper instead of using the helper macro below. - */ -int kstrtobool_from_user(const char __user *s, size_t count, bool *res) -{ - /* Longest string needed to differentiate, newline, terminator */ - char buf[4]; - - count = min(count, sizeof(buf) - 1); - if (copy_from_user(buf, s, count)) - return -EFAULT; - buf[count] = '\0'; - return kstrtobool(buf, res); -} -EXPORT_SYMBOL(kstrtobool_from_user); - -#define kstrto_from_user(f, g, type) \ -int f(const char __user *s, size_t count, unsigned int base, type *res) \ -{ \ - /* sign, base 2 representation, newline, terminator */ \ - char buf[1 + sizeof(type) * 8 + 1 + 1]; \ - \ - count = min(count, sizeof(buf) - 1); \ - if (copy_from_user(buf, s, count)) \ - return -EFAULT; \ - buf[count] = '\0'; \ - return g(buf, base, res); \ -} \ -EXPORT_SYMBOL(f) - -kstrto_from_user(kstrtoull_from_user, kstrtoull, unsigned long long); -kstrto_from_user(kstrtoll_from_user, kstrtoll, long long); -kstrto_from_user(kstrtoul_from_user, kstrtoul, unsigned long); -kstrto_from_user(kstrtol_from_user, kstrtol, long); -kstrto_from_user(kstrtouint_from_user, kstrtouint, unsigned int); -kstrto_from_user(kstrtoint_from_user, kstrtoint, int); -kstrto_from_user(kstrtou16_from_user, kstrtou16, u16); -kstrto_from_user(kstrtos16_from_user, kstrtos16, s16); -kstrto_from_user(kstrtou8_from_user, kstrtou8, u8); -kstrto_from_user(kstrtos8_from_user, kstrtos8, s8); diff --git a/src/linux/lib/kstrtox.h b/src/linux/lib/kstrtox.h deleted file mode 100644 index f13eeea..0000000 --- a/src/linux/lib/kstrtox.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _LIB_KSTRTOX_H -#define _LIB_KSTRTOX_H - -#define KSTRTOX_OVERFLOW (1U << 31) -const char *_parse_integer_fixup_radix(const char *s, unsigned int *base); -unsigned int _parse_integer(const char *s, unsigned int base, unsigned long long *res); - -#endif diff --git a/src/linux/lib/lcm.c b/src/linux/lib/lcm.c deleted file mode 100644 index 03d7fcb..0000000 --- a/src/linux/lib/lcm.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include -#include - -/* Lowest common multiple */ -unsigned long lcm(unsigned long a, unsigned long b) -{ - if (a && b) - return (a / gcd(a, b)) * b; - else - return 0; -} -EXPORT_SYMBOL_GPL(lcm); - -unsigned long lcm_not_zero(unsigned long a, unsigned long b) -{ - unsigned long l = lcm(a, b); - - if (l) - return l; - - return (b ? : a); -} -EXPORT_SYMBOL_GPL(lcm_not_zero); diff --git a/src/linux/lib/libcrc32c.c b/src/linux/lib/libcrc32c.c deleted file mode 100644 index 74a54b7..0000000 --- a/src/linux/lib/libcrc32c.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * CRC32C - *@Article{castagnoli-crc, - * author = { Guy Castagnoli and Stefan Braeuer and Martin Herrman}, - * title = {{Optimization of Cyclic Redundancy-Check Codes with 24 - * and 32 Parity Bits}}, - * journal = IEEE Transactions on Communication, - * year = {1993}, - * volume = {41}, - * number = {6}, - * pages = {}, - * month = {June}, - *} - * Used by the iSCSI driver, possibly others, and derived from the - * the iscsi-crc.c module of the linux-iscsi driver at - * http://linux-iscsi.sourceforge.net. - * - * Following the example of lib/crc32, this function is intended to be - * flexible and useful for all users. Modules that currently have their - * own crc32c, but hopefully may be able to use this one are: - * net/sctp (please add all your doco to here if you change to - * use this one!) - * - * - * Copyright (c) 2004 Cisco Systems, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - * - */ - -#include -#include -#include -#include -#include -#include - -static struct crypto_shash *tfm; - -u32 crc32c(u32 crc, const void *address, unsigned int length) -{ - SHASH_DESC_ON_STACK(shash, tfm); - u32 *ctx = (u32 *)shash_desc_ctx(shash); - int err; - - shash->tfm = tfm; - shash->flags = 0; - *ctx = crc; - - err = crypto_shash_update(shash, address, length); - BUG_ON(err); - - return *ctx; -} - -EXPORT_SYMBOL(crc32c); - -static int __init libcrc32c_mod_init(void) -{ - tfm = crypto_alloc_shash("crc32c", 0, 0); - return PTR_ERR_OR_ZERO(tfm); -} - -static void __exit libcrc32c_mod_fini(void) -{ - crypto_free_shash(tfm); -} - -module_init(libcrc32c_mod_init); -module_exit(libcrc32c_mod_fini); - -MODULE_AUTHOR("Clay Haapala "); -MODULE_DESCRIPTION("CRC32c (Castagnoli) calculations"); -MODULE_LICENSE("GPL"); -MODULE_SOFTDEP("pre: crc32c"); diff --git a/src/linux/lib/list_sort.c b/src/linux/lib/list_sort.c deleted file mode 100644 index 3fe4010..0000000 --- a/src/linux/lib/list_sort.c +++ /dev/null @@ -1,293 +0,0 @@ - -#define pr_fmt(fmt) "list_sort_test: " fmt - -#include -#include -#include -#include -#include -#include -#include - -#define MAX_LIST_LENGTH_BITS 20 - -/* - * Returns a list organized in an intermediate format suited - * to chaining of merge() calls: null-terminated, no reserved or - * sentinel head node, "prev" links not maintained. - */ -static struct list_head *merge(void *priv, - int (*cmp)(void *priv, struct list_head *a, - struct list_head *b), - struct list_head *a, struct list_head *b) -{ - struct list_head head, *tail = &head; - - while (a && b) { - /* if equal, take 'a' -- important for sort stability */ - if ((*cmp)(priv, a, b) <= 0) { - tail->next = a; - a = a->next; - } else { - tail->next = b; - b = b->next; - } - tail = tail->next; - } - tail->next = a?:b; - return head.next; -} - -/* - * Combine final list merge with restoration of standard doubly-linked - * list structure. This approach duplicates code from merge(), but - * runs faster than the tidier alternatives of either a separate final - * prev-link restoration pass, or maintaining the prev links - * throughout. - */ -static void merge_and_restore_back_links(void *priv, - int (*cmp)(void *priv, struct list_head *a, - struct list_head *b), - struct list_head *head, - struct list_head *a, struct list_head *b) -{ - struct list_head *tail = head; - u8 count = 0; - - while (a && b) { - /* if equal, take 'a' -- important for sort stability */ - if ((*cmp)(priv, a, b) <= 0) { - tail->next = a; - a->prev = tail; - a = a->next; - } else { - tail->next = b; - b->prev = tail; - b = b->next; - } - tail = tail->next; - } - tail->next = a ? : b; - - do { - /* - * In worst cases this loop may run many iterations. - * Continue callbacks to the client even though no - * element comparison is needed, so the client's cmp() - * routine can invoke cond_resched() periodically. - */ - if (unlikely(!(++count))) - (*cmp)(priv, tail->next, tail->next); - - tail->next->prev = tail; - tail = tail->next; - } while (tail->next); - - tail->next = head; - head->prev = tail; -} - -/** - * list_sort - sort a list - * @priv: private data, opaque to list_sort(), passed to @cmp - * @head: the list to sort - * @cmp: the elements comparison function - * - * This function implements "merge sort", which has O(nlog(n)) - * complexity. - * - * The comparison function @cmp must return a negative value if @a - * should sort before @b, and a positive value if @a should sort after - * @b. If @a and @b are equivalent, and their original relative - * ordering is to be preserved, @cmp must return 0. - */ -void list_sort(void *priv, struct list_head *head, - int (*cmp)(void *priv, struct list_head *a, - struct list_head *b)) -{ - struct list_head *part[MAX_LIST_LENGTH_BITS+1]; /* sorted partial lists - -- last slot is a sentinel */ - int lev; /* index into part[] */ - int max_lev = 0; - struct list_head *list; - - if (list_empty(head)) - return; - - memset(part, 0, sizeof(part)); - - head->prev->next = NULL; - list = head->next; - - while (list) { - struct list_head *cur = list; - list = list->next; - cur->next = NULL; - - for (lev = 0; part[lev]; lev++) { - cur = merge(priv, cmp, part[lev], cur); - part[lev] = NULL; - } - if (lev > max_lev) { - if (unlikely(lev >= ARRAY_SIZE(part)-1)) { - printk_once(KERN_DEBUG "list too long for efficiency\n"); - lev--; - } - max_lev = lev; - } - part[lev] = cur; - } - - for (lev = 0; lev < max_lev; lev++) - if (part[lev]) - list = merge(priv, cmp, part[lev], list); - - merge_and_restore_back_links(priv, cmp, head, part[max_lev], list); -} -EXPORT_SYMBOL(list_sort); - -#ifdef CONFIG_TEST_LIST_SORT - -#include -#include - -/* - * The pattern of set bits in the list length determines which cases - * are hit in list_sort(). - */ -#define TEST_LIST_LEN (512+128+2) /* not including head */ - -#define TEST_POISON1 0xDEADBEEF -#define TEST_POISON2 0xA324354C - -struct debug_el { - unsigned int poison1; - struct list_head list; - unsigned int poison2; - int value; - unsigned serial; -}; - -/* Array, containing pointers to all elements in the test list */ -static struct debug_el **elts __initdata; - -static int __init check(struct debug_el *ela, struct debug_el *elb) -{ - if (ela->serial >= TEST_LIST_LEN) { - pr_err("error: incorrect serial %d\n", ela->serial); - return -EINVAL; - } - if (elb->serial >= TEST_LIST_LEN) { - pr_err("error: incorrect serial %d\n", elb->serial); - return -EINVAL; - } - if (elts[ela->serial] != ela || elts[elb->serial] != elb) { - pr_err("error: phantom element\n"); - return -EINVAL; - } - if (ela->poison1 != TEST_POISON1 || ela->poison2 != TEST_POISON2) { - pr_err("error: bad poison: %#x/%#x\n", - ela->poison1, ela->poison2); - return -EINVAL; - } - if (elb->poison1 != TEST_POISON1 || elb->poison2 != TEST_POISON2) { - pr_err("error: bad poison: %#x/%#x\n", - elb->poison1, elb->poison2); - return -EINVAL; - } - return 0; -} - -static int __init cmp(void *priv, struct list_head *a, struct list_head *b) -{ - struct debug_el *ela, *elb; - - ela = container_of(a, struct debug_el, list); - elb = container_of(b, struct debug_el, list); - - check(ela, elb); - return ela->value - elb->value; -} - -static int __init list_sort_test(void) -{ - int i, count = 1, err = -ENOMEM; - struct debug_el *el; - struct list_head *cur; - LIST_HEAD(head); - - pr_debug("start testing list_sort()\n"); - - elts = kcalloc(TEST_LIST_LEN, sizeof(*elts), GFP_KERNEL); - if (!elts) { - pr_err("error: cannot allocate memory\n"); - return err; - } - - for (i = 0; i < TEST_LIST_LEN; i++) { - el = kmalloc(sizeof(*el), GFP_KERNEL); - if (!el) { - pr_err("error: cannot allocate memory\n"); - goto exit; - } - /* force some equivalencies */ - el->value = prandom_u32() % (TEST_LIST_LEN / 3); - el->serial = i; - el->poison1 = TEST_POISON1; - el->poison2 = TEST_POISON2; - elts[i] = el; - list_add_tail(&el->list, &head); - } - - list_sort(NULL, &head, cmp); - - err = -EINVAL; - for (cur = head.next; cur->next != &head; cur = cur->next) { - struct debug_el *el1; - int cmp_result; - - if (cur->next->prev != cur) { - pr_err("error: list is corrupted\n"); - goto exit; - } - - cmp_result = cmp(NULL, cur, cur->next); - if (cmp_result > 0) { - pr_err("error: list is not sorted\n"); - goto exit; - } - - el = container_of(cur, struct debug_el, list); - el1 = container_of(cur->next, struct debug_el, list); - if (cmp_result == 0 && el->serial >= el1->serial) { - pr_err("error: order of equivalent elements not " - "preserved\n"); - goto exit; - } - - if (check(el, el1)) { - pr_err("error: element check failed\n"); - goto exit; - } - count++; - } - if (head.prev != cur) { - pr_err("error: list is corrupted\n"); - goto exit; - } - - - if (count != TEST_LIST_LEN) { - pr_err("error: bad list length %d", count); - goto exit; - } - - err = 0; -exit: - for (i = 0; i < TEST_LIST_LEN; i++) - kfree(elts[i]); - kfree(elts); - return err; -} -late_initcall(list_sort_test); -#endif /* CONFIG_TEST_LIST_SORT */ diff --git a/src/linux/lib/llist.c b/src/linux/lib/llist.c deleted file mode 100644 index ae5872b..0000000 --- a/src/linux/lib/llist.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Lock-less NULL terminated single linked list - * - * The basic atomic operation of this list is cmpxchg on long. On - * architectures that don't have NMI-safe cmpxchg implementation, the - * list can NOT be used in NMI handlers. So code that uses the list in - * an NMI handler should depend on CONFIG_ARCH_HAVE_NMI_SAFE_CMPXCHG. - * - * Copyright 2010,2011 Intel Corp. - * Author: Huang Ying - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include -#include -#include - - -/** - * llist_add_batch - add several linked entries in batch - * @new_first: first entry in batch to be added - * @new_last: last entry in batch to be added - * @head: the head for your lock-less list - * - * Return whether list is empty before adding. - */ -bool llist_add_batch(struct llist_node *new_first, struct llist_node *new_last, - struct llist_head *head) -{ - struct llist_node *first; - - do { - new_last->next = first = ACCESS_ONCE(head->first); - } while (cmpxchg(&head->first, first, new_first) != first); - - return !first; -} -EXPORT_SYMBOL_GPL(llist_add_batch); - -/** - * llist_del_first - delete the first entry of lock-less list - * @head: the head for your lock-less list - * - * If list is empty, return NULL, otherwise, return the first entry - * deleted, this is the newest added one. - * - * Only one llist_del_first user can be used simultaneously with - * multiple llist_add users without lock. Because otherwise - * llist_del_first, llist_add, llist_add (or llist_del_all, llist_add, - * llist_add) sequence in another user may change @head->first->next, - * but keep @head->first. If multiple consumers are needed, please - * use llist_del_all or use lock between consumers. - */ -struct llist_node *llist_del_first(struct llist_head *head) -{ - struct llist_node *entry, *old_entry, *next; - - entry = smp_load_acquire(&head->first); - for (;;) { - if (entry == NULL) - return NULL; - old_entry = entry; - next = READ_ONCE(entry->next); - entry = cmpxchg(&head->first, old_entry, next); - if (entry == old_entry) - break; - } - - return entry; -} -EXPORT_SYMBOL_GPL(llist_del_first); - -/** - * llist_reverse_order - reverse order of a llist chain - * @head: first item of the list to be reversed - * - * Reverse the order of a chain of llist entries and return the - * new first entry. - */ -struct llist_node *llist_reverse_order(struct llist_node *head) -{ - struct llist_node *new_head = NULL; - - while (head) { - struct llist_node *tmp = head; - head = head->next; - tmp->next = new_head; - new_head = tmp; - } - - return new_head; -} -EXPORT_SYMBOL_GPL(llist_reverse_order); diff --git a/src/linux/lib/lockref.c b/src/linux/lib/lockref.c deleted file mode 100644 index 5a92189..0000000 --- a/src/linux/lib/lockref.c +++ /dev/null @@ -1,188 +0,0 @@ -#include -#include - -#if USE_CMPXCHG_LOCKREF - -/* - * Note that the "cmpxchg()" reloads the "old" value for the - * failure case. - */ -#define CMPXCHG_LOOP(CODE, SUCCESS) do { \ - struct lockref old; \ - BUILD_BUG_ON(sizeof(old) != 8); \ - old.lock_count = READ_ONCE(lockref->lock_count); \ - while (likely(arch_spin_value_unlocked(old.lock.rlock.raw_lock))) { \ - struct lockref new = old, prev = old; \ - CODE \ - old.lock_count = cmpxchg64_relaxed(&lockref->lock_count, \ - old.lock_count, \ - new.lock_count); \ - if (likely(old.lock_count == prev.lock_count)) { \ - SUCCESS; \ - } \ - cpu_relax_lowlatency(); \ - } \ -} while (0) - -#else - -#define CMPXCHG_LOOP(CODE, SUCCESS) do { } while (0) - -#endif - -/** - * lockref_get - Increments reference count unconditionally - * @lockref: pointer to lockref structure - * - * This operation is only valid if you already hold a reference - * to the object, so you know the count cannot be zero. - */ -void lockref_get(struct lockref *lockref) -{ - CMPXCHG_LOOP( - new.count++; - , - return; - ); - - spin_lock(&lockref->lock); - lockref->count++; - spin_unlock(&lockref->lock); -} -EXPORT_SYMBOL(lockref_get); - -/** - * lockref_get_not_zero - Increments count unless the count is 0 or dead - * @lockref: pointer to lockref structure - * Return: 1 if count updated successfully or 0 if count was zero - */ -int lockref_get_not_zero(struct lockref *lockref) -{ - int retval; - - CMPXCHG_LOOP( - new.count++; - if (old.count <= 0) - return 0; - , - return 1; - ); - - spin_lock(&lockref->lock); - retval = 0; - if (lockref->count > 0) { - lockref->count++; - retval = 1; - } - spin_unlock(&lockref->lock); - return retval; -} -EXPORT_SYMBOL(lockref_get_not_zero); - -/** - * lockref_get_or_lock - Increments count unless the count is 0 or dead - * @lockref: pointer to lockref structure - * Return: 1 if count updated successfully or 0 if count was zero - * and we got the lock instead. - */ -int lockref_get_or_lock(struct lockref *lockref) -{ - CMPXCHG_LOOP( - new.count++; - if (old.count <= 0) - break; - , - return 1; - ); - - spin_lock(&lockref->lock); - if (lockref->count <= 0) - return 0; - lockref->count++; - spin_unlock(&lockref->lock); - return 1; -} -EXPORT_SYMBOL(lockref_get_or_lock); - -/** - * lockref_put_return - Decrement reference count if possible - * @lockref: pointer to lockref structure - * - * Decrement the reference count and return the new value. - * If the lockref was dead or locked, return an error. - */ -int lockref_put_return(struct lockref *lockref) -{ - CMPXCHG_LOOP( - new.count--; - if (old.count <= 0) - return -1; - , - return new.count; - ); - return -1; -} -EXPORT_SYMBOL(lockref_put_return); - -/** - * lockref_put_or_lock - decrements count unless count <= 1 before decrement - * @lockref: pointer to lockref structure - * Return: 1 if count updated successfully or 0 if count <= 1 and lock taken - */ -int lockref_put_or_lock(struct lockref *lockref) -{ - CMPXCHG_LOOP( - new.count--; - if (old.count <= 1) - break; - , - return 1; - ); - - spin_lock(&lockref->lock); - if (lockref->count <= 1) - return 0; - lockref->count--; - spin_unlock(&lockref->lock); - return 1; -} -EXPORT_SYMBOL(lockref_put_or_lock); - -/** - * lockref_mark_dead - mark lockref dead - * @lockref: pointer to lockref structure - */ -void lockref_mark_dead(struct lockref *lockref) -{ - assert_spin_locked(&lockref->lock); - lockref->count = -128; -} -EXPORT_SYMBOL(lockref_mark_dead); - -/** - * lockref_get_not_dead - Increments count unless the ref is dead - * @lockref: pointer to lockref structure - * Return: 1 if count updated successfully or 0 if lockref was dead - */ -int lockref_get_not_dead(struct lockref *lockref) -{ - int retval; - - CMPXCHG_LOOP( - new.count++; - if (old.count < 0) - return 0; - , - return 1; - ); - - spin_lock(&lockref->lock); - retval = 0; - if (lockref->count >= 0) { - lockref->count++; - retval = 1; - } - spin_unlock(&lockref->lock); - return retval; -} -EXPORT_SYMBOL(lockref_get_not_dead); diff --git a/src/linux/lib/lzo/Makefile b/src/linux/lib/lzo/Makefile deleted file mode 100644 index f0f7d7c..0000000 --- a/src/linux/lib/lzo/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -lzo_compress-objs := lzo1x_compress.o -lzo_decompress-objs := lzo1x_decompress_safe.o - -obj-$(CONFIG_LZO_COMPRESS) += lzo_compress.o -obj-$(CONFIG_LZO_DECOMPRESS) += lzo_decompress.o diff --git a/src/linux/lib/lzo/lzo1x_compress.c b/src/linux/lib/lzo/lzo1x_compress.c deleted file mode 100644 index 236eb21..0000000 --- a/src/linux/lib/lzo/lzo1x_compress.c +++ /dev/null @@ -1,279 +0,0 @@ -/* - * LZO1X Compressor from LZO - * - * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer - * - * The full LZO package can be found at: - * http://www.oberhumer.com/opensource/lzo/ - * - * Changed for Linux kernel use by: - * Nitin Gupta - * Richard Purdie - */ - -#include -#include -#include -#include -#include "lzodefs.h" - -static noinline size_t -lzo1x_1_do_compress(const unsigned char *in, size_t in_len, - unsigned char *out, size_t *out_len, - size_t ti, void *wrkmem) -{ - const unsigned char *ip; - unsigned char *op; - const unsigned char * const in_end = in + in_len; - const unsigned char * const ip_end = in + in_len - 20; - const unsigned char *ii; - lzo_dict_t * const dict = (lzo_dict_t *) wrkmem; - - op = out; - ip = in; - ii = ip; - ip += ti < 4 ? 4 - ti : 0; - - for (;;) { - const unsigned char *m_pos; - size_t t, m_len, m_off; - u32 dv; -literal: - ip += 1 + ((ip - ii) >> 5); -next: - if (unlikely(ip >= ip_end)) - break; - dv = get_unaligned_le32(ip); - t = ((dv * 0x1824429d) >> (32 - D_BITS)) & D_MASK; - m_pos = in + dict[t]; - dict[t] = (lzo_dict_t) (ip - in); - if (unlikely(dv != get_unaligned_le32(m_pos))) - goto literal; - - ii -= ti; - ti = 0; - t = ip - ii; - if (t != 0) { - if (t <= 3) { - op[-2] |= t; - COPY4(op, ii); - op += t; - } else if (t <= 16) { - *op++ = (t - 3); - COPY8(op, ii); - COPY8(op + 8, ii + 8); - op += t; - } else { - if (t <= 18) { - *op++ = (t - 3); - } else { - size_t tt = t - 18; - *op++ = 0; - while (unlikely(tt > 255)) { - tt -= 255; - *op++ = 0; - } - *op++ = tt; - } - do { - COPY8(op, ii); - COPY8(op + 8, ii + 8); - op += 16; - ii += 16; - t -= 16; - } while (t >= 16); - if (t > 0) do { - *op++ = *ii++; - } while (--t > 0); - } - } - - m_len = 4; - { -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && defined(LZO_USE_CTZ64) - u64 v; - v = get_unaligned((const u64 *) (ip + m_len)) ^ - get_unaligned((const u64 *) (m_pos + m_len)); - if (unlikely(v == 0)) { - do { - m_len += 8; - v = get_unaligned((const u64 *) (ip + m_len)) ^ - get_unaligned((const u64 *) (m_pos + m_len)); - if (unlikely(ip + m_len >= ip_end)) - goto m_len_done; - } while (v == 0); - } -# if defined(__LITTLE_ENDIAN) - m_len += (unsigned) __builtin_ctzll(v) / 8; -# elif defined(__BIG_ENDIAN) - m_len += (unsigned) __builtin_clzll(v) / 8; -# else -# error "missing endian definition" -# endif -#elif defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && defined(LZO_USE_CTZ32) - u32 v; - v = get_unaligned((const u32 *) (ip + m_len)) ^ - get_unaligned((const u32 *) (m_pos + m_len)); - if (unlikely(v == 0)) { - do { - m_len += 4; - v = get_unaligned((const u32 *) (ip + m_len)) ^ - get_unaligned((const u32 *) (m_pos + m_len)); - if (v != 0) - break; - m_len += 4; - v = get_unaligned((const u32 *) (ip + m_len)) ^ - get_unaligned((const u32 *) (m_pos + m_len)); - if (unlikely(ip + m_len >= ip_end)) - goto m_len_done; - } while (v == 0); - } -# if defined(__LITTLE_ENDIAN) - m_len += (unsigned) __builtin_ctz(v) / 8; -# elif defined(__BIG_ENDIAN) - m_len += (unsigned) __builtin_clz(v) / 8; -# else -# error "missing endian definition" -# endif -#else - if (unlikely(ip[m_len] == m_pos[m_len])) { - do { - m_len += 1; - if (ip[m_len] != m_pos[m_len]) - break; - m_len += 1; - if (ip[m_len] != m_pos[m_len]) - break; - m_len += 1; - if (ip[m_len] != m_pos[m_len]) - break; - m_len += 1; - if (ip[m_len] != m_pos[m_len]) - break; - m_len += 1; - if (ip[m_len] != m_pos[m_len]) - break; - m_len += 1; - if (ip[m_len] != m_pos[m_len]) - break; - m_len += 1; - if (ip[m_len] != m_pos[m_len]) - break; - m_len += 1; - if (unlikely(ip + m_len >= ip_end)) - goto m_len_done; - } while (ip[m_len] == m_pos[m_len]); - } -#endif - } -m_len_done: - - m_off = ip - m_pos; - ip += m_len; - ii = ip; - if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) { - m_off -= 1; - *op++ = (((m_len - 1) << 5) | ((m_off & 7) << 2)); - *op++ = (m_off >> 3); - } else if (m_off <= M3_MAX_OFFSET) { - m_off -= 1; - if (m_len <= M3_MAX_LEN) - *op++ = (M3_MARKER | (m_len - 2)); - else { - m_len -= M3_MAX_LEN; - *op++ = M3_MARKER | 0; - while (unlikely(m_len > 255)) { - m_len -= 255; - *op++ = 0; - } - *op++ = (m_len); - } - *op++ = (m_off << 2); - *op++ = (m_off >> 6); - } else { - m_off -= 0x4000; - if (m_len <= M4_MAX_LEN) - *op++ = (M4_MARKER | ((m_off >> 11) & 8) - | (m_len - 2)); - else { - m_len -= M4_MAX_LEN; - *op++ = (M4_MARKER | ((m_off >> 11) & 8)); - while (unlikely(m_len > 255)) { - m_len -= 255; - *op++ = 0; - } - *op++ = (m_len); - } - *op++ = (m_off << 2); - *op++ = (m_off >> 6); - } - goto next; - } - *out_len = op - out; - return in_end - (ii - ti); -} - -int lzo1x_1_compress(const unsigned char *in, size_t in_len, - unsigned char *out, size_t *out_len, - void *wrkmem) -{ - const unsigned char *ip = in; - unsigned char *op = out; - size_t l = in_len; - size_t t = 0; - - while (l > 20) { - size_t ll = l <= (M4_MAX_OFFSET + 1) ? l : (M4_MAX_OFFSET + 1); - uintptr_t ll_end = (uintptr_t) ip + ll; - if ((ll_end + ((t + ll) >> 5)) <= ll_end) - break; - BUILD_BUG_ON(D_SIZE * sizeof(lzo_dict_t) > LZO1X_1_MEM_COMPRESS); - memset(wrkmem, 0, D_SIZE * sizeof(lzo_dict_t)); - t = lzo1x_1_do_compress(ip, ll, op, out_len, t, wrkmem); - ip += ll; - op += *out_len; - l -= ll; - } - t += l; - - if (t > 0) { - const unsigned char *ii = in + in_len - t; - - if (op == out && t <= 238) { - *op++ = (17 + t); - } else if (t <= 3) { - op[-2] |= t; - } else if (t <= 18) { - *op++ = (t - 3); - } else { - size_t tt = t - 18; - *op++ = 0; - while (tt > 255) { - tt -= 255; - *op++ = 0; - } - *op++ = tt; - } - if (t >= 16) do { - COPY8(op, ii); - COPY8(op + 8, ii + 8); - op += 16; - ii += 16; - t -= 16; - } while (t >= 16); - if (t > 0) do { - *op++ = *ii++; - } while (--t > 0); - } - - *op++ = M4_MARKER | 1; - *op++ = 0; - *op++ = 0; - - *out_len = op - out; - return LZO_E_OK; -} -EXPORT_SYMBOL_GPL(lzo1x_1_compress); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("LZO1X-1 Compressor"); diff --git a/src/linux/lib/lzo/lzo1x_decompress_safe.c b/src/linux/lib/lzo/lzo1x_decompress_safe.c deleted file mode 100644 index a1c387f..0000000 --- a/src/linux/lib/lzo/lzo1x_decompress_safe.c +++ /dev/null @@ -1,268 +0,0 @@ -/* - * LZO1X Decompressor from LZO - * - * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer - * - * The full LZO package can be found at: - * http://www.oberhumer.com/opensource/lzo/ - * - * Changed for Linux kernel use by: - * Nitin Gupta - * Richard Purdie - */ - -#ifndef STATIC -#include -#include -#endif -#include -#include -#include "lzodefs.h" - -#define HAVE_IP(x) ((size_t)(ip_end - ip) >= (size_t)(x)) -#define HAVE_OP(x) ((size_t)(op_end - op) >= (size_t)(x)) -#define NEED_IP(x) if (!HAVE_IP(x)) goto input_overrun -#define NEED_OP(x) if (!HAVE_OP(x)) goto output_overrun -#define TEST_LB(m_pos) if ((m_pos) < out) goto lookbehind_overrun - -/* This MAX_255_COUNT is the maximum number of times we can add 255 to a base - * count without overflowing an integer. The multiply will overflow when - * multiplying 255 by more than MAXINT/255. The sum will overflow earlier - * depending on the base count. Since the base count is taken from a u8 - * and a few bits, it is safe to assume that it will always be lower than - * or equal to 2*255, thus we can always prevent any overflow by accepting - * two less 255 steps. See Documentation/lzo.txt for more information. - */ -#define MAX_255_COUNT ((((size_t)~0) / 255) - 2) - -int lzo1x_decompress_safe(const unsigned char *in, size_t in_len, - unsigned char *out, size_t *out_len) -{ - unsigned char *op; - const unsigned char *ip; - size_t t, next; - size_t state = 0; - const unsigned char *m_pos; - const unsigned char * const ip_end = in + in_len; - unsigned char * const op_end = out + *out_len; - - op = out; - ip = in; - - if (unlikely(in_len < 3)) - goto input_overrun; - if (*ip > 17) { - t = *ip++ - 17; - if (t < 4) { - next = t; - goto match_next; - } - goto copy_literal_run; - } - - for (;;) { - t = *ip++; - if (t < 16) { - if (likely(state == 0)) { - if (unlikely(t == 0)) { - size_t offset; - const unsigned char *ip_last = ip; - - while (unlikely(*ip == 0)) { - ip++; - NEED_IP(1); - } - offset = ip - ip_last; - if (unlikely(offset > MAX_255_COUNT)) - return LZO_E_ERROR; - - offset = (offset << 8) - offset; - t += offset + 15 + *ip++; - } - t += 3; -copy_literal_run: -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) - if (likely(HAVE_IP(t + 15) && HAVE_OP(t + 15))) { - const unsigned char *ie = ip + t; - unsigned char *oe = op + t; - do { - COPY8(op, ip); - op += 8; - ip += 8; - COPY8(op, ip); - op += 8; - ip += 8; - } while (ip < ie); - ip = ie; - op = oe; - } else -#endif - { - NEED_OP(t); - NEED_IP(t + 3); - do { - *op++ = *ip++; - } while (--t > 0); - } - state = 4; - continue; - } else if (state != 4) { - next = t & 3; - m_pos = op - 1; - m_pos -= t >> 2; - m_pos -= *ip++ << 2; - TEST_LB(m_pos); - NEED_OP(2); - op[0] = m_pos[0]; - op[1] = m_pos[1]; - op += 2; - goto match_next; - } else { - next = t & 3; - m_pos = op - (1 + M2_MAX_OFFSET); - m_pos -= t >> 2; - m_pos -= *ip++ << 2; - t = 3; - } - } else if (t >= 64) { - next = t & 3; - m_pos = op - 1; - m_pos -= (t >> 2) & 7; - m_pos -= *ip++ << 3; - t = (t >> 5) - 1 + (3 - 1); - } else if (t >= 32) { - t = (t & 31) + (3 - 1); - if (unlikely(t == 2)) { - size_t offset; - const unsigned char *ip_last = ip; - - while (unlikely(*ip == 0)) { - ip++; - NEED_IP(1); - } - offset = ip - ip_last; - if (unlikely(offset > MAX_255_COUNT)) - return LZO_E_ERROR; - - offset = (offset << 8) - offset; - t += offset + 31 + *ip++; - NEED_IP(2); - } - m_pos = op - 1; - next = get_unaligned_le16(ip); - ip += 2; - m_pos -= next >> 2; - next &= 3; - } else { - m_pos = op; - m_pos -= (t & 8) << 11; - t = (t & 7) + (3 - 1); - if (unlikely(t == 2)) { - size_t offset; - const unsigned char *ip_last = ip; - - while (unlikely(*ip == 0)) { - ip++; - NEED_IP(1); - } - offset = ip - ip_last; - if (unlikely(offset > MAX_255_COUNT)) - return LZO_E_ERROR; - - offset = (offset << 8) - offset; - t += offset + 7 + *ip++; - NEED_IP(2); - } - next = get_unaligned_le16(ip); - ip += 2; - m_pos -= next >> 2; - next &= 3; - if (m_pos == op) - goto eof_found; - m_pos -= 0x4000; - } - TEST_LB(m_pos); -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) - if (op - m_pos >= 8) { - unsigned char *oe = op + t; - if (likely(HAVE_OP(t + 15))) { - do { - COPY8(op, m_pos); - op += 8; - m_pos += 8; - COPY8(op, m_pos); - op += 8; - m_pos += 8; - } while (op < oe); - op = oe; - if (HAVE_IP(6)) { - state = next; - COPY4(op, ip); - op += next; - ip += next; - continue; - } - } else { - NEED_OP(t); - do { - *op++ = *m_pos++; - } while (op < oe); - } - } else -#endif - { - unsigned char *oe = op + t; - NEED_OP(t); - op[0] = m_pos[0]; - op[1] = m_pos[1]; - op += 2; - m_pos += 2; - do { - *op++ = *m_pos++; - } while (op < oe); - } -match_next: - state = next; - t = next; -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) - if (likely(HAVE_IP(6) && HAVE_OP(4))) { - COPY4(op, ip); - op += t; - ip += t; - } else -#endif - { - NEED_IP(t + 3); - NEED_OP(t); - while (t > 0) { - *op++ = *ip++; - t--; - } - } - } - -eof_found: - *out_len = op - out; - return (t != 3 ? LZO_E_ERROR : - ip == ip_end ? LZO_E_OK : - ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN); - -input_overrun: - *out_len = op - out; - return LZO_E_INPUT_OVERRUN; - -output_overrun: - *out_len = op - out; - return LZO_E_OUTPUT_OVERRUN; - -lookbehind_overrun: - *out_len = op - out; - return LZO_E_LOOKBEHIND_OVERRUN; -} -#ifndef STATIC -EXPORT_SYMBOL_GPL(lzo1x_decompress_safe); - -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("LZO1X Decompressor"); - -#endif diff --git a/src/linux/lib/lzo/lzodefs.h b/src/linux/lib/lzo/lzodefs.h deleted file mode 100644 index 6710b83..0000000 --- a/src/linux/lib/lzo/lzodefs.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * lzodefs.h -- architecture, OS and compiler specific defines - * - * Copyright (C) 1996-2012 Markus F.X.J. Oberhumer - * - * The full LZO package can be found at: - * http://www.oberhumer.com/opensource/lzo/ - * - * Changed for Linux kernel use by: - * Nitin Gupta - * Richard Purdie - */ - - -#define COPY4(dst, src) \ - put_unaligned(get_unaligned((const u32 *)(src)), (u32 *)(dst)) -#if defined(__x86_64__) -#define COPY8(dst, src) \ - put_unaligned(get_unaligned((const u64 *)(src)), (u64 *)(dst)) -#else -#define COPY8(dst, src) \ - COPY4(dst, src); COPY4((dst) + 4, (src) + 4) -#endif - -#if defined(__BIG_ENDIAN) && defined(__LITTLE_ENDIAN) -#error "conflicting endian definitions" -#elif defined(__x86_64__) -#define LZO_USE_CTZ64 1 -#define LZO_USE_CTZ32 1 -#elif defined(__i386__) || defined(__powerpc__) -#define LZO_USE_CTZ32 1 -#elif defined(__arm__) && (__LINUX_ARM_ARCH__ >= 5) -#define LZO_USE_CTZ32 1 -#endif - -#define M1_MAX_OFFSET 0x0400 -#define M2_MAX_OFFSET 0x0800 -#define M3_MAX_OFFSET 0x4000 -#define M4_MAX_OFFSET 0xbfff - -#define M1_MIN_LEN 2 -#define M1_MAX_LEN 2 -#define M2_MIN_LEN 3 -#define M2_MAX_LEN 8 -#define M3_MIN_LEN 3 -#define M3_MAX_LEN 33 -#define M4_MIN_LEN 3 -#define M4_MAX_LEN 9 - -#define M1_MARKER 0 -#define M2_MARKER 64 -#define M3_MARKER 32 -#define M4_MARKER 16 - -#define lzo_dict_t unsigned short -#define D_BITS 13 -#define D_SIZE (1u << D_BITS) -#define D_MASK (D_SIZE - 1) -#define D_HIGH ((D_MASK >> 1) + 1) diff --git a/src/linux/lib/md5.c b/src/linux/lib/md5.c deleted file mode 100644 index bb0cd01..0000000 --- a/src/linux/lib/md5.c +++ /dev/null @@ -1,95 +0,0 @@ -#include -#include -#include - -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -#define MD5STEP(f, w, x, y, z, in, s) \ - (w += f(x, y, z) + in, w = (w<>(32-s)) + x) - -void md5_transform(__u32 *hash, __u32 const *in) -{ - u32 a, b, c, d; - - a = hash[0]; - b = hash[1]; - c = hash[2]; - d = hash[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - hash[0] += a; - hash[1] += b; - hash[2] += c; - hash[3] += d; -} -EXPORT_SYMBOL(md5_transform); diff --git a/src/linux/lib/memweight.c b/src/linux/lib/memweight.c deleted file mode 100644 index e35fc87..0000000 --- a/src/linux/lib/memweight.c +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include -#include - -/** - * memweight - count the total number of bits set in memory area - * @ptr: pointer to the start of the area - * @bytes: the size of the area - */ -size_t memweight(const void *ptr, size_t bytes) -{ - size_t ret = 0; - size_t longs; - const unsigned char *bitmap = ptr; - - for (; bytes > 0 && ((unsigned long)bitmap) % sizeof(long); - bytes--, bitmap++) - ret += hweight8(*bitmap); - - longs = bytes / sizeof(long); - if (longs) { - BUG_ON(longs >= INT_MAX / BITS_PER_LONG); - ret += bitmap_weight((unsigned long *)bitmap, - longs * BITS_PER_LONG); - bytes -= longs * sizeof(long); - bitmap += longs * sizeof(long); - } - /* - * The reason that this last loop is distinct from the preceding - * bitmap_weight() call is to compute 1-bits in the last region smaller - * than sizeof(long) properly on big-endian systems. - */ - for (; bytes > 0; bytes--, bitmap++) - ret += hweight8(*bitmap); - - return ret; -} -EXPORT_SYMBOL(memweight); diff --git a/src/linux/lib/net_utils.c b/src/linux/lib/net_utils.c deleted file mode 100644 index 148fc6e..0000000 --- a/src/linux/lib/net_utils.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include -#include - -bool mac_pton(const char *s, u8 *mac) -{ - int i; - - /* XX:XX:XX:XX:XX:XX */ - if (strlen(s) < 3 * ETH_ALEN - 1) - return false; - - /* Don't dirty result unless string is valid MAC. */ - for (i = 0; i < ETH_ALEN; i++) { - if (!isxdigit(s[i * 3]) || !isxdigit(s[i * 3 + 1])) - return false; - if (i != ETH_ALEN - 1 && s[i * 3 + 2] != ':') - return false; - } - for (i = 0; i < ETH_ALEN; i++) { - mac[i] = (hex_to_bin(s[i * 3]) << 4) | hex_to_bin(s[i * 3 + 1]); - } - return true; -} -EXPORT_SYMBOL(mac_pton); diff --git a/src/linux/lib/nlattr.c b/src/linux/lib/nlattr.c deleted file mode 100644 index fce1e9a..0000000 --- a/src/linux/lib/nlattr.c +++ /dev/null @@ -1,616 +0,0 @@ -/* - * NETLINK Netlink attributes - * - * Authors: Thomas Graf - * Alexey Kuznetsov - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static const u16 nla_attr_minlen[NLA_TYPE_MAX+1] = { - [NLA_U8] = sizeof(u8), - [NLA_U16] = sizeof(u16), - [NLA_U32] = sizeof(u32), - [NLA_U64] = sizeof(u64), - [NLA_MSECS] = sizeof(u64), - [NLA_NESTED] = NLA_HDRLEN, - [NLA_S8] = sizeof(s8), - [NLA_S16] = sizeof(s16), - [NLA_S32] = sizeof(s32), - [NLA_S64] = sizeof(s64), -}; - -static int validate_nla(const struct nlattr *nla, int maxtype, - const struct nla_policy *policy) -{ - const struct nla_policy *pt; - int minlen = 0, attrlen = nla_len(nla), type = nla_type(nla); - - if (type <= 0 || type > maxtype) - return 0; - - pt = &policy[type]; - - BUG_ON(pt->type > NLA_TYPE_MAX); - - switch (pt->type) { - case NLA_FLAG: - if (attrlen > 0) - return -ERANGE; - break; - - case NLA_NUL_STRING: - if (pt->len) - minlen = min_t(int, attrlen, pt->len + 1); - else - minlen = attrlen; - - if (!minlen || memchr(nla_data(nla), '\0', minlen) == NULL) - return -EINVAL; - /* fall through */ - - case NLA_STRING: - if (attrlen < 1) - return -ERANGE; - - if (pt->len) { - char *buf = nla_data(nla); - - if (buf[attrlen - 1] == '\0') - attrlen--; - - if (attrlen > pt->len) - return -ERANGE; - } - break; - - case NLA_BINARY: - if (pt->len && attrlen > pt->len) - return -ERANGE; - break; - - case NLA_NESTED_COMPAT: - if (attrlen < pt->len) - return -ERANGE; - if (attrlen < NLA_ALIGN(pt->len)) - break; - if (attrlen < NLA_ALIGN(pt->len) + NLA_HDRLEN) - return -ERANGE; - nla = nla_data(nla) + NLA_ALIGN(pt->len); - if (attrlen < NLA_ALIGN(pt->len) + NLA_HDRLEN + nla_len(nla)) - return -ERANGE; - break; - case NLA_NESTED: - /* a nested attributes is allowed to be empty; if its not, - * it must have a size of at least NLA_HDRLEN. - */ - if (attrlen == 0) - break; - default: - if (pt->len) - minlen = pt->len; - else if (pt->type != NLA_UNSPEC) - minlen = nla_attr_minlen[pt->type]; - - if (attrlen < minlen) - return -ERANGE; - } - - return 0; -} - -/** - * nla_validate - Validate a stream of attributes - * @head: head of attribute stream - * @len: length of attribute stream - * @maxtype: maximum attribute type to be expected - * @policy: validation policy - * - * Validates all attributes in the specified attribute stream against the - * specified policy. Attributes with a type exceeding maxtype will be - * ignored. See documenation of struct nla_policy for more details. - * - * Returns 0 on success or a negative error code. - */ -int nla_validate(const struct nlattr *head, int len, int maxtype, - const struct nla_policy *policy) -{ - const struct nlattr *nla; - int rem, err; - - nla_for_each_attr(nla, head, len, rem) { - err = validate_nla(nla, maxtype, policy); - if (err < 0) - goto errout; - } - - err = 0; -errout: - return err; -} -EXPORT_SYMBOL(nla_validate); - -/** - * nla_policy_len - Determin the max. length of a policy - * @policy: policy to use - * @n: number of policies - * - * Determines the max. length of the policy. It is currently used - * to allocated Netlink buffers roughly the size of the actual - * message. - * - * Returns 0 on success or a negative error code. - */ -int -nla_policy_len(const struct nla_policy *p, int n) -{ - int i, len = 0; - - for (i = 0; i < n; i++, p++) { - if (p->len) - len += nla_total_size(p->len); - else if (nla_attr_minlen[p->type]) - len += nla_total_size(nla_attr_minlen[p->type]); - } - - return len; -} -EXPORT_SYMBOL(nla_policy_len); - -/** - * nla_parse - Parse a stream of attributes into a tb buffer - * @tb: destination array with maxtype+1 elements - * @maxtype: maximum attribute type to be expected - * @head: head of attribute stream - * @len: length of attribute stream - * @policy: validation policy - * - * Parses a stream of attributes and stores a pointer to each attribute in - * the tb array accessible via the attribute type. Attributes with a type - * exceeding maxtype will be silently ignored for backwards compatibility - * reasons. policy may be set to NULL if no validation is required. - * - * Returns 0 on success or a negative error code. - */ -int nla_parse(struct nlattr **tb, int maxtype, const struct nlattr *head, - int len, const struct nla_policy *policy) -{ - const struct nlattr *nla; - int rem, err; - - memset(tb, 0, sizeof(struct nlattr *) * (maxtype + 1)); - - nla_for_each_attr(nla, head, len, rem) { - u16 type = nla_type(nla); - - if (type > 0 && type <= maxtype) { - if (policy) { - err = validate_nla(nla, maxtype, policy); - if (err < 0) - goto errout; - } - - tb[type] = (struct nlattr *)nla; - } - } - - if (unlikely(rem > 0)) - pr_warn_ratelimited("netlink: %d bytes leftover after parsing attributes in process `%s'.\n", - rem, current->comm); - - err = 0; -errout: - return err; -} -EXPORT_SYMBOL(nla_parse); - -/** - * nla_find - Find a specific attribute in a stream of attributes - * @head: head of attribute stream - * @len: length of attribute stream - * @attrtype: type of attribute to look for - * - * Returns the first attribute in the stream matching the specified type. - */ -struct nlattr *nla_find(const struct nlattr *head, int len, int attrtype) -{ - const struct nlattr *nla; - int rem; - - nla_for_each_attr(nla, head, len, rem) - if (nla_type(nla) == attrtype) - return (struct nlattr *)nla; - - return NULL; -} -EXPORT_SYMBOL(nla_find); - -/** - * nla_strlcpy - Copy string attribute payload into a sized buffer - * @dst: where to copy the string to - * @nla: attribute to copy the string from - * @dstsize: size of destination buffer - * - * Copies at most dstsize - 1 bytes into the destination buffer. - * The result is always a valid NUL-terminated string. Unlike - * strlcpy the destination buffer is always padded out. - * - * Returns the length of the source buffer. - */ -size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize) -{ - size_t srclen = nla_len(nla); - char *src = nla_data(nla); - - if (srclen > 0 && src[srclen - 1] == '\0') - srclen--; - - if (dstsize > 0) { - size_t len = (srclen >= dstsize) ? dstsize - 1 : srclen; - - memset(dst, 0, dstsize); - memcpy(dst, src, len); - } - - return srclen; -} -EXPORT_SYMBOL(nla_strlcpy); - -/** - * nla_memcpy - Copy a netlink attribute into another memory area - * @dest: where to copy to memcpy - * @src: netlink attribute to copy from - * @count: size of the destination area - * - * Note: The number of bytes copied is limited by the length of - * attribute's payload. memcpy - * - * Returns the number of bytes copied. - */ -int nla_memcpy(void *dest, const struct nlattr *src, int count) -{ - int minlen = min_t(int, count, nla_len(src)); - - memcpy(dest, nla_data(src), minlen); - if (count > minlen) - memset(dest + minlen, 0, count - minlen); - - return minlen; -} -EXPORT_SYMBOL(nla_memcpy); - -/** - * nla_memcmp - Compare an attribute with sized memory area - * @nla: netlink attribute - * @data: memory area - * @size: size of memory area - */ -int nla_memcmp(const struct nlattr *nla, const void *data, - size_t size) -{ - int d = nla_len(nla) - size; - - if (d == 0) - d = memcmp(nla_data(nla), data, size); - - return d; -} -EXPORT_SYMBOL(nla_memcmp); - -/** - * nla_strcmp - Compare a string attribute against a string - * @nla: netlink string attribute - * @str: another string - */ -int nla_strcmp(const struct nlattr *nla, const char *str) -{ - int len = strlen(str); - char *buf = nla_data(nla); - int attrlen = nla_len(nla); - int d; - - if (attrlen > 0 && buf[attrlen - 1] == '\0') - attrlen--; - - d = attrlen - len; - if (d == 0) - d = memcmp(nla_data(nla), str, len); - - return d; -} -EXPORT_SYMBOL(nla_strcmp); - -#ifdef CONFIG_NET -/** - * __nla_reserve - reserve room for attribute on the skb - * @skb: socket buffer to reserve room on - * @attrtype: attribute type - * @attrlen: length of attribute payload - * - * Adds a netlink attribute header to a socket buffer and reserves - * room for the payload but does not copy it. - * - * The caller is responsible to ensure that the skb provides enough - * tailroom for the attribute header and payload. - */ -struct nlattr *__nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) -{ - struct nlattr *nla; - - nla = (struct nlattr *) skb_put(skb, nla_total_size(attrlen)); - nla->nla_type = attrtype; - nla->nla_len = nla_attr_size(attrlen); - - memset((unsigned char *) nla + nla->nla_len, 0, nla_padlen(attrlen)); - - return nla; -} -EXPORT_SYMBOL(__nla_reserve); - -/** - * __nla_reserve_64bit - reserve room for attribute on the skb and align it - * @skb: socket buffer to reserve room on - * @attrtype: attribute type - * @attrlen: length of attribute payload - * @padattr: attribute type for the padding - * - * Adds a netlink attribute header to a socket buffer and reserves - * room for the payload but does not copy it. It also ensure that this - * attribute will have a 64-bit aligned nla_data() area. - * - * The caller is responsible to ensure that the skb provides enough - * tailroom for the attribute header and payload. - */ -struct nlattr *__nla_reserve_64bit(struct sk_buff *skb, int attrtype, - int attrlen, int padattr) -{ - if (nla_need_padding_for_64bit(skb)) - nla_align_64bit(skb, padattr); - - return __nla_reserve(skb, attrtype, attrlen); -} -EXPORT_SYMBOL(__nla_reserve_64bit); - -/** - * __nla_reserve_nohdr - reserve room for attribute without header - * @skb: socket buffer to reserve room on - * @attrlen: length of attribute payload - * - * Reserves room for attribute payload without a header. - * - * The caller is responsible to ensure that the skb provides enough - * tailroom for the payload. - */ -void *__nla_reserve_nohdr(struct sk_buff *skb, int attrlen) -{ - void *start; - - start = skb_put(skb, NLA_ALIGN(attrlen)); - memset(start, 0, NLA_ALIGN(attrlen)); - - return start; -} -EXPORT_SYMBOL(__nla_reserve_nohdr); - -/** - * nla_reserve - reserve room for attribute on the skb - * @skb: socket buffer to reserve room on - * @attrtype: attribute type - * @attrlen: length of attribute payload - * - * Adds a netlink attribute header to a socket buffer and reserves - * room for the payload but does not copy it. - * - * Returns NULL if the tailroom of the skb is insufficient to store - * the attribute header and payload. - */ -struct nlattr *nla_reserve(struct sk_buff *skb, int attrtype, int attrlen) -{ - if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen))) - return NULL; - - return __nla_reserve(skb, attrtype, attrlen); -} -EXPORT_SYMBOL(nla_reserve); - -/** - * nla_reserve_64bit - reserve room for attribute on the skb and align it - * @skb: socket buffer to reserve room on - * @attrtype: attribute type - * @attrlen: length of attribute payload - * @padattr: attribute type for the padding - * - * Adds a netlink attribute header to a socket buffer and reserves - * room for the payload but does not copy it. It also ensure that this - * attribute will have a 64-bit aligned nla_data() area. - * - * Returns NULL if the tailroom of the skb is insufficient to store - * the attribute header and payload. - */ -struct nlattr *nla_reserve_64bit(struct sk_buff *skb, int attrtype, int attrlen, - int padattr) -{ - size_t len; - - if (nla_need_padding_for_64bit(skb)) - len = nla_total_size_64bit(attrlen); - else - len = nla_total_size(attrlen); - if (unlikely(skb_tailroom(skb) < len)) - return NULL; - - return __nla_reserve_64bit(skb, attrtype, attrlen, padattr); -} -EXPORT_SYMBOL(nla_reserve_64bit); - -/** - * nla_reserve_nohdr - reserve room for attribute without header - * @skb: socket buffer to reserve room on - * @attrlen: length of attribute payload - * - * Reserves room for attribute payload without a header. - * - * Returns NULL if the tailroom of the skb is insufficient to store - * the attribute payload. - */ -void *nla_reserve_nohdr(struct sk_buff *skb, int attrlen) -{ - if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen))) - return NULL; - - return __nla_reserve_nohdr(skb, attrlen); -} -EXPORT_SYMBOL(nla_reserve_nohdr); - -/** - * __nla_put - Add a netlink attribute to a socket buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @attrlen: length of attribute payload - * @data: head of attribute payload - * - * The caller is responsible to ensure that the skb provides enough - * tailroom for the attribute header and payload. - */ -void __nla_put(struct sk_buff *skb, int attrtype, int attrlen, - const void *data) -{ - struct nlattr *nla; - - nla = __nla_reserve(skb, attrtype, attrlen); - memcpy(nla_data(nla), data, attrlen); -} -EXPORT_SYMBOL(__nla_put); - -/** - * __nla_put_64bit - Add a netlink attribute to a socket buffer and align it - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @attrlen: length of attribute payload - * @data: head of attribute payload - * @padattr: attribute type for the padding - * - * The caller is responsible to ensure that the skb provides enough - * tailroom for the attribute header and payload. - */ -void __nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen, - const void *data, int padattr) -{ - struct nlattr *nla; - - nla = __nla_reserve_64bit(skb, attrtype, attrlen, padattr); - memcpy(nla_data(nla), data, attrlen); -} -EXPORT_SYMBOL(__nla_put_64bit); - -/** - * __nla_put_nohdr - Add a netlink attribute without header - * @skb: socket buffer to add attribute to - * @attrlen: length of attribute payload - * @data: head of attribute payload - * - * The caller is responsible to ensure that the skb provides enough - * tailroom for the attribute payload. - */ -void __nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data) -{ - void *start; - - start = __nla_reserve_nohdr(skb, attrlen); - memcpy(start, data, attrlen); -} -EXPORT_SYMBOL(__nla_put_nohdr); - -/** - * nla_put - Add a netlink attribute to a socket buffer - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @attrlen: length of attribute payload - * @data: head of attribute payload - * - * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store - * the attribute header and payload. - */ -int nla_put(struct sk_buff *skb, int attrtype, int attrlen, const void *data) -{ - if (unlikely(skb_tailroom(skb) < nla_total_size(attrlen))) - return -EMSGSIZE; - - __nla_put(skb, attrtype, attrlen, data); - return 0; -} -EXPORT_SYMBOL(nla_put); - -/** - * nla_put_64bit - Add a netlink attribute to a socket buffer and align it - * @skb: socket buffer to add attribute to - * @attrtype: attribute type - * @attrlen: length of attribute payload - * @data: head of attribute payload - * @padattr: attribute type for the padding - * - * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store - * the attribute header and payload. - */ -int nla_put_64bit(struct sk_buff *skb, int attrtype, int attrlen, - const void *data, int padattr) -{ - size_t len; - - if (nla_need_padding_for_64bit(skb)) - len = nla_total_size_64bit(attrlen); - else - len = nla_total_size(attrlen); - if (unlikely(skb_tailroom(skb) < len)) - return -EMSGSIZE; - - __nla_put_64bit(skb, attrtype, attrlen, data, padattr); - return 0; -} -EXPORT_SYMBOL(nla_put_64bit); - -/** - * nla_put_nohdr - Add a netlink attribute without header - * @skb: socket buffer to add attribute to - * @attrlen: length of attribute payload - * @data: head of attribute payload - * - * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store - * the attribute payload. - */ -int nla_put_nohdr(struct sk_buff *skb, int attrlen, const void *data) -{ - if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen))) - return -EMSGSIZE; - - __nla_put_nohdr(skb, attrlen, data); - return 0; -} -EXPORT_SYMBOL(nla_put_nohdr); - -/** - * nla_append - Add a netlink attribute without header or padding - * @skb: socket buffer to add attribute to - * @attrlen: length of attribute payload - * @data: head of attribute payload - * - * Returns -EMSGSIZE if the tailroom of the skb is insufficient to store - * the attribute payload. - */ -int nla_append(struct sk_buff *skb, int attrlen, const void *data) -{ - if (unlikely(skb_tailroom(skb) < NLA_ALIGN(attrlen))) - return -EMSGSIZE; - - memcpy(skb_put(skb, attrlen), data, attrlen); - return 0; -} -EXPORT_SYMBOL(nla_append); -#endif diff --git a/src/linux/lib/nmi_backtrace.c b/src/linux/lib/nmi_backtrace.c deleted file mode 100644 index 7555475..0000000 --- a/src/linux/lib/nmi_backtrace.c +++ /dev/null @@ -1,108 +0,0 @@ -/* - * NMI backtrace support - * - * Gratuitously copied from arch/x86/kernel/apic/hw_nmi.c by Russell King, - * with the following header: - * - * HW NMI watchdog support - * - * started by Don Zickus, Copyright (C) 2010 Red Hat, Inc. - * - * Arch specific calls to support NMI watchdog - * - * Bits copied from original nmi.c file - */ -#include -#include -#include -#include -#include - -#ifdef arch_trigger_cpumask_backtrace -/* For reliability, we're prepared to waste bits here. */ -static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly; - -/* "in progress" flag of arch_trigger_cpumask_backtrace */ -static unsigned long backtrace_flag; - -/* - * When raise() is called it will be passed a pointer to the - * backtrace_mask. Architectures that call nmi_cpu_backtrace() - * directly from their raise() functions may rely on the mask - * they are passed being updated as a side effect of this call. - */ -void nmi_trigger_cpumask_backtrace(const cpumask_t *mask, - bool exclude_self, - void (*raise)(cpumask_t *mask)) -{ - int i, this_cpu = get_cpu(); - - if (test_and_set_bit(0, &backtrace_flag)) { - /* - * If there is already a trigger_all_cpu_backtrace() in progress - * (backtrace_flag == 1), don't output double cpu dump infos. - */ - put_cpu(); - return; - } - - cpumask_copy(to_cpumask(backtrace_mask), mask); - if (exclude_self) - cpumask_clear_cpu(this_cpu, to_cpumask(backtrace_mask)); - - /* - * Don't try to send an NMI to this cpu; it may work on some - * architectures, but on others it may not, and we'll get - * information at least as useful just by doing a dump_stack() here. - * Note that nmi_cpu_backtrace(NULL) will clear the cpu bit. - */ - if (cpumask_test_cpu(this_cpu, to_cpumask(backtrace_mask))) - nmi_cpu_backtrace(NULL); - - if (!cpumask_empty(to_cpumask(backtrace_mask))) { - pr_info("Sending NMI from CPU %d to CPUs %*pbl:\n", - this_cpu, nr_cpumask_bits, to_cpumask(backtrace_mask)); - raise(to_cpumask(backtrace_mask)); - } - - /* Wait for up to 10 seconds for all CPUs to do the backtrace */ - for (i = 0; i < 10 * 1000; i++) { - if (cpumask_empty(to_cpumask(backtrace_mask))) - break; - mdelay(1); - touch_softlockup_watchdog(); - } - - /* - * Force flush any remote buffers that might be stuck in IRQ context - * and therefore could not run their irq_work. - */ - printk_nmi_flush(); - - clear_bit_unlock(0, &backtrace_flag); - put_cpu(); -} - -bool nmi_cpu_backtrace(struct pt_regs *regs) -{ - int cpu = smp_processor_id(); - - if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) { - if (regs && cpu_in_idle(instruction_pointer(regs))) { - pr_warn("NMI backtrace for cpu %d skipped: idling at pc %#lx\n", - cpu, instruction_pointer(regs)); - } else { - pr_warn("NMI backtrace for cpu %d\n", cpu); - if (regs) - show_regs(regs); - else - dump_stack(); - } - cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask)); - return true; - } - - return false; -} -NOKPROBE_SYMBOL(nmi_cpu_backtrace); -#endif diff --git a/src/linux/lib/nodemask.c b/src/linux/lib/nodemask.c deleted file mode 100644 index e42a5bf..0000000 --- a/src/linux/lib/nodemask.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include - -int __next_node_in(int node, const nodemask_t *srcp) -{ - int ret = __next_node(node, srcp); - - if (ret == MAX_NUMNODES) - ret = __first_node(srcp); - return ret; -} -EXPORT_SYMBOL(__next_node_in); - -#ifdef CONFIG_NUMA -/* - * Return the bit number of a random bit set in the nodemask. - * (returns NUMA_NO_NODE if nodemask is empty) - */ -int node_random(const nodemask_t *maskp) -{ - int w, bit = NUMA_NO_NODE; - - w = nodes_weight(*maskp); - if (w) - bit = bitmap_ord_to_pos(maskp->bits, - get_random_int() % w, MAX_NUMNODES); - return bit; -} -#endif diff --git a/src/linux/lib/once.c b/src/linux/lib/once.c deleted file mode 100644 index 05c8604..0000000 --- a/src/linux/lib/once.c +++ /dev/null @@ -1,62 +0,0 @@ -#include -#include -#include -#include - -struct once_work { - struct work_struct work; - struct static_key *key; -}; - -static void once_deferred(struct work_struct *w) -{ - struct once_work *work; - - work = container_of(w, struct once_work, work); - BUG_ON(!static_key_enabled(work->key)); - static_key_slow_dec(work->key); - kfree(work); -} - -static void once_disable_jump(struct static_key *key) -{ - struct once_work *w; - - w = kmalloc(sizeof(*w), GFP_ATOMIC); - if (!w) - return; - - INIT_WORK(&w->work, once_deferred); - w->key = key; - schedule_work(&w->work); -} - -static DEFINE_SPINLOCK(once_lock); - -bool __do_once_start(bool *done, unsigned long *flags) - __acquires(once_lock) -{ - spin_lock_irqsave(&once_lock, *flags); - if (*done) { - spin_unlock_irqrestore(&once_lock, *flags); - /* Keep sparse happy by restoring an even lock count on - * this lock. In case we return here, we don't call into - * __do_once_done but return early in the DO_ONCE() macro. - */ - __acquire(once_lock); - return false; - } - - return true; -} -EXPORT_SYMBOL(__do_once_start); - -void __do_once_done(bool *done, struct static_key *once_key, - unsigned long *flags) - __releases(once_lock) -{ - *done = true; - spin_unlock_irqrestore(&once_lock, *flags); - once_disable_jump(once_key); -} -EXPORT_SYMBOL(__do_once_done); diff --git a/src/linux/lib/parser.c b/src/linux/lib/parser.c deleted file mode 100644 index b6d1163..0000000 --- a/src/linux/lib/parser.c +++ /dev/null @@ -1,289 +0,0 @@ -/* - * lib/parser.c - simple parser for mount, etc. options. - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. - */ - -#include -#include -#include -#include -#include -#include - -/** - * match_one: - Determines if a string matches a simple pattern - * @s: the string to examine for presence of the pattern - * @p: the string containing the pattern - * @args: array of %MAX_OPT_ARGS &substring_t elements. Used to return match - * locations. - * - * Description: Determines if the pattern @p is present in string @s. Can only - * match extremely simple token=arg style patterns. If the pattern is found, - * the location(s) of the arguments will be returned in the @args array. - */ -static int match_one(char *s, const char *p, substring_t args[]) -{ - char *meta; - int argc = 0; - - if (!p) - return 1; - - while(1) { - int len = -1; - meta = strchr(p, '%'); - if (!meta) - return strcmp(p, s) == 0; - - if (strncmp(p, s, meta-p)) - return 0; - - s += meta - p; - p = meta + 1; - - if (isdigit(*p)) - len = simple_strtoul(p, (char **) &p, 10); - else if (*p == '%') { - if (*s++ != '%') - return 0; - p++; - continue; - } - - if (argc >= MAX_OPT_ARGS) - return 0; - - args[argc].from = s; - switch (*p++) { - case 's': { - size_t str_len = strlen(s); - - if (str_len == 0) - return 0; - if (len == -1 || len > str_len) - len = str_len; - args[argc].to = s + len; - break; - } - case 'd': - simple_strtol(s, &args[argc].to, 0); - goto num; - case 'u': - simple_strtoul(s, &args[argc].to, 0); - goto num; - case 'o': - simple_strtoul(s, &args[argc].to, 8); - goto num; - case 'x': - simple_strtoul(s, &args[argc].to, 16); - num: - if (args[argc].to == args[argc].from) - return 0; - break; - default: - return 0; - } - s = args[argc].to; - argc++; - } -} - -/** - * match_token: - Find a token (and optional args) in a string - * @s: the string to examine for token/argument pairs - * @table: match_table_t describing the set of allowed option tokens and the - * arguments that may be associated with them. Must be terminated with a - * &struct match_token whose pattern is set to the NULL pointer. - * @args: array of %MAX_OPT_ARGS &substring_t elements. Used to return match - * locations. - * - * Description: Detects which if any of a set of token strings has been passed - * to it. Tokens can include up to MAX_OPT_ARGS instances of basic c-style - * format identifiers which will be taken into account when matching the - * tokens, and whose locations will be returned in the @args array. - */ -int match_token(char *s, const match_table_t table, substring_t args[]) -{ - const struct match_token *p; - - for (p = table; !match_one(s, p->pattern, args) ; p++) - ; - - return p->token; -} -EXPORT_SYMBOL(match_token); - -/** - * match_number: scan a number in the given base from a substring_t - * @s: substring to be scanned - * @result: resulting integer on success - * @base: base to use when converting string - * - * Description: Given a &substring_t and a base, attempts to parse the substring - * as a number in that base. On success, sets @result to the integer represented - * by the string and returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure. - */ -static int match_number(substring_t *s, int *result, int base) -{ - char *endp; - char *buf; - int ret; - long val; - size_t len = s->to - s->from; - - buf = kmalloc(len + 1, GFP_KERNEL); - if (!buf) - return -ENOMEM; - memcpy(buf, s->from, len); - buf[len] = '\0'; - - ret = 0; - val = simple_strtol(buf, &endp, base); - if (endp == buf) - ret = -EINVAL; - else if (val < (long)INT_MIN || val > (long)INT_MAX) - ret = -ERANGE; - else - *result = (int) val; - kfree(buf); - return ret; -} - -/** - * match_int: - scan a decimal representation of an integer from a substring_t - * @s: substring_t to be scanned - * @result: resulting integer on success - * - * Description: Attempts to parse the &substring_t @s as a decimal integer. On - * success, sets @result to the integer represented by the string and returns 0. - * Returns -ENOMEM, -EINVAL, or -ERANGE on failure. - */ -int match_int(substring_t *s, int *result) -{ - return match_number(s, result, 0); -} -EXPORT_SYMBOL(match_int); - -/** - * match_octal: - scan an octal representation of an integer from a substring_t - * @s: substring_t to be scanned - * @result: resulting integer on success - * - * Description: Attempts to parse the &substring_t @s as an octal integer. On - * success, sets @result to the integer represented by the string and returns - * 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure. - */ -int match_octal(substring_t *s, int *result) -{ - return match_number(s, result, 8); -} -EXPORT_SYMBOL(match_octal); - -/** - * match_hex: - scan a hex representation of an integer from a substring_t - * @s: substring_t to be scanned - * @result: resulting integer on success - * - * Description: Attempts to parse the &substring_t @s as a hexadecimal integer. - * On success, sets @result to the integer represented by the string and - * returns 0. Returns -ENOMEM, -EINVAL, or -ERANGE on failure. - */ -int match_hex(substring_t *s, int *result) -{ - return match_number(s, result, 16); -} -EXPORT_SYMBOL(match_hex); - -/** - * match_wildcard: - parse if a string matches given wildcard pattern - * @pattern: wildcard pattern - * @str: the string to be parsed - * - * Description: Parse the string @str to check if matches wildcard - * pattern @pattern. The pattern may contain two type wildcardes: - * '*' - matches zero or more characters - * '?' - matches one character - * If it's matched, return true, else return false. - */ -bool match_wildcard(const char *pattern, const char *str) -{ - const char *s = str; - const char *p = pattern; - bool star = false; - - while (*s) { - switch (*p) { - case '?': - s++; - p++; - break; - case '*': - star = true; - str = s; - if (!*++p) - return true; - pattern = p; - break; - default: - if (*s == *p) { - s++; - p++; - } else { - if (!star) - return false; - str++; - s = str; - p = pattern; - } - break; - } - } - - if (*p == '*') - ++p; - return !*p; -} -EXPORT_SYMBOL(match_wildcard); - -/** - * match_strlcpy: - Copy the characters from a substring_t to a sized buffer - * @dest: where to copy to - * @src: &substring_t to copy - * @size: size of destination buffer - * - * Description: Copy the characters in &substring_t @src to the - * c-style string @dest. Copy no more than @size - 1 characters, plus - * the terminating NUL. Return length of @src. - */ -size_t match_strlcpy(char *dest, const substring_t *src, size_t size) -{ - size_t ret = src->to - src->from; - - if (size) { - size_t len = ret >= size ? size - 1 : ret; - memcpy(dest, src->from, len); - dest[len] = '\0'; - } - return ret; -} -EXPORT_SYMBOL(match_strlcpy); - -/** - * match_strdup: - allocate a new string with the contents of a substring_t - * @s: &substring_t to copy - * - * Description: Allocates and returns a string filled with the contents of - * the &substring_t @s. The caller is responsible for freeing the returned - * string with kfree(). - */ -char *match_strdup(const substring_t *s) -{ - size_t sz = s->to - s->from + 1; - char *p = kmalloc(sz, GFP_KERNEL); - if (p) - match_strlcpy(p, s, sz); - return p; -} -EXPORT_SYMBOL(match_strdup); diff --git a/src/linux/lib/percpu-refcount.c b/src/linux/lib/percpu-refcount.c deleted file mode 100644 index 9ac959e..0000000 --- a/src/linux/lib/percpu-refcount.c +++ /dev/null @@ -1,352 +0,0 @@ -#define pr_fmt(fmt) "%s: " fmt "\n", __func__ - -#include -#include -#include -#include - -/* - * Initially, a percpu refcount is just a set of percpu counters. Initially, we - * don't try to detect the ref hitting 0 - which means that get/put can just - * increment or decrement the local counter. Note that the counter on a - * particular cpu can (and will) wrap - this is fine, when we go to shutdown the - * percpu counters will all sum to the correct value - * - * (More precisely: because modular arithmetic is commutative the sum of all the - * percpu_count vars will be equal to what it would have been if all the gets - * and puts were done to a single integer, even if some of the percpu integers - * overflow or underflow). - * - * The real trick to implementing percpu refcounts is shutdown. We can't detect - * the ref hitting 0 on every put - this would require global synchronization - * and defeat the whole purpose of using percpu refs. - * - * What we do is require the user to keep track of the initial refcount; we know - * the ref can't hit 0 before the user drops the initial ref, so as long as we - * convert to non percpu mode before the initial ref is dropped everything - * works. - * - * Converting to non percpu mode is done with some RCUish stuff in - * percpu_ref_kill. Additionally, we need a bias value so that the - * atomic_long_t can't hit 0 before we've added up all the percpu refs. - */ - -#define PERCPU_COUNT_BIAS (1LU << (BITS_PER_LONG - 1)) - -static DEFINE_SPINLOCK(percpu_ref_switch_lock); -static DECLARE_WAIT_QUEUE_HEAD(percpu_ref_switch_waitq); - -static unsigned long __percpu *percpu_count_ptr(struct percpu_ref *ref) -{ - return (unsigned long __percpu *) - (ref->percpu_count_ptr & ~__PERCPU_REF_ATOMIC_DEAD); -} - -/** - * percpu_ref_init - initialize a percpu refcount - * @ref: percpu_ref to initialize - * @release: function which will be called when refcount hits 0 - * @flags: PERCPU_REF_INIT_* flags - * @gfp: allocation mask to use - * - * Initializes @ref. If @flags is zero, @ref starts in percpu mode with a - * refcount of 1; analagous to atomic_long_set(ref, 1). See the - * definitions of PERCPU_REF_INIT_* flags for flag behaviors. - * - * Note that @release must not sleep - it may potentially be called from RCU - * callback context by percpu_ref_kill(). - */ -int percpu_ref_init(struct percpu_ref *ref, percpu_ref_func_t *release, - unsigned int flags, gfp_t gfp) -{ - size_t align = max_t(size_t, 1 << __PERCPU_REF_FLAG_BITS, - __alignof__(unsigned long)); - unsigned long start_count = 0; - - ref->percpu_count_ptr = (unsigned long) - __alloc_percpu_gfp(sizeof(unsigned long), align, gfp); - if (!ref->percpu_count_ptr) - return -ENOMEM; - - ref->force_atomic = flags & PERCPU_REF_INIT_ATOMIC; - - if (flags & (PERCPU_REF_INIT_ATOMIC | PERCPU_REF_INIT_DEAD)) - ref->percpu_count_ptr |= __PERCPU_REF_ATOMIC; - else - start_count += PERCPU_COUNT_BIAS; - - if (flags & PERCPU_REF_INIT_DEAD) - ref->percpu_count_ptr |= __PERCPU_REF_DEAD; - else - start_count++; - - atomic_long_set(&ref->count, start_count); - - ref->release = release; - ref->confirm_switch = NULL; - return 0; -} -EXPORT_SYMBOL_GPL(percpu_ref_init); - -/** - * percpu_ref_exit - undo percpu_ref_init() - * @ref: percpu_ref to exit - * - * This function exits @ref. The caller is responsible for ensuring that - * @ref is no longer in active use. The usual places to invoke this - * function from are the @ref->release() callback or in init failure path - * where percpu_ref_init() succeeded but other parts of the initialization - * of the embedding object failed. - */ -void percpu_ref_exit(struct percpu_ref *ref) -{ - unsigned long __percpu *percpu_count = percpu_count_ptr(ref); - - if (percpu_count) { - /* non-NULL confirm_switch indicates switching in progress */ - WARN_ON_ONCE(ref->confirm_switch); - free_percpu(percpu_count); - ref->percpu_count_ptr = __PERCPU_REF_ATOMIC_DEAD; - } -} -EXPORT_SYMBOL_GPL(percpu_ref_exit); - -static void percpu_ref_call_confirm_rcu(struct rcu_head *rcu) -{ - struct percpu_ref *ref = container_of(rcu, struct percpu_ref, rcu); - - ref->confirm_switch(ref); - ref->confirm_switch = NULL; - wake_up_all(&percpu_ref_switch_waitq); - - /* drop ref from percpu_ref_switch_to_atomic() */ - percpu_ref_put(ref); -} - -static void percpu_ref_switch_to_atomic_rcu(struct rcu_head *rcu) -{ - struct percpu_ref *ref = container_of(rcu, struct percpu_ref, rcu); - unsigned long __percpu *percpu_count = percpu_count_ptr(ref); - unsigned long count = 0; - int cpu; - - for_each_possible_cpu(cpu) - count += *per_cpu_ptr(percpu_count, cpu); - - pr_debug("global %ld percpu %ld", - atomic_long_read(&ref->count), (long)count); - - /* - * It's crucial that we sum the percpu counters _before_ adding the sum - * to &ref->count; since gets could be happening on one cpu while puts - * happen on another, adding a single cpu's count could cause - * @ref->count to hit 0 before we've got a consistent value - but the - * sum of all the counts will be consistent and correct. - * - * Subtracting the bias value then has to happen _after_ adding count to - * &ref->count; we need the bias value to prevent &ref->count from - * reaching 0 before we add the percpu counts. But doing it at the same - * time is equivalent and saves us atomic operations: - */ - atomic_long_add((long)count - PERCPU_COUNT_BIAS, &ref->count); - - WARN_ONCE(atomic_long_read(&ref->count) <= 0, - "percpu ref (%pf) <= 0 (%ld) after switching to atomic", - ref->release, atomic_long_read(&ref->count)); - - /* @ref is viewed as dead on all CPUs, send out switch confirmation */ - percpu_ref_call_confirm_rcu(rcu); -} - -static void percpu_ref_noop_confirm_switch(struct percpu_ref *ref) -{ -} - -static void __percpu_ref_switch_to_atomic(struct percpu_ref *ref, - percpu_ref_func_t *confirm_switch) -{ - if (ref->percpu_count_ptr & __PERCPU_REF_ATOMIC) { - if (confirm_switch) - confirm_switch(ref); - return; - } - - /* switching from percpu to atomic */ - ref->percpu_count_ptr |= __PERCPU_REF_ATOMIC; - - /* - * Non-NULL ->confirm_switch is used to indicate that switching is - * in progress. Use noop one if unspecified. - */ - ref->confirm_switch = confirm_switch ?: percpu_ref_noop_confirm_switch; - - percpu_ref_get(ref); /* put after confirmation */ - call_rcu_sched(&ref->rcu, percpu_ref_switch_to_atomic_rcu); -} - -static void __percpu_ref_switch_to_percpu(struct percpu_ref *ref) -{ - unsigned long __percpu *percpu_count = percpu_count_ptr(ref); - int cpu; - - BUG_ON(!percpu_count); - - if (!(ref->percpu_count_ptr & __PERCPU_REF_ATOMIC)) - return; - - atomic_long_add(PERCPU_COUNT_BIAS, &ref->count); - - /* - * Restore per-cpu operation. smp_store_release() is paired with - * smp_read_barrier_depends() in __ref_is_percpu() and guarantees - * that the zeroing is visible to all percpu accesses which can see - * the following __PERCPU_REF_ATOMIC clearing. - */ - for_each_possible_cpu(cpu) - *per_cpu_ptr(percpu_count, cpu) = 0; - - smp_store_release(&ref->percpu_count_ptr, - ref->percpu_count_ptr & ~__PERCPU_REF_ATOMIC); -} - -static void __percpu_ref_switch_mode(struct percpu_ref *ref, - percpu_ref_func_t *confirm_switch) -{ - lockdep_assert_held(&percpu_ref_switch_lock); - - /* - * If the previous ATOMIC switching hasn't finished yet, wait for - * its completion. If the caller ensures that ATOMIC switching - * isn't in progress, this function can be called from any context. - */ - wait_event_lock_irq(percpu_ref_switch_waitq, !ref->confirm_switch, - percpu_ref_switch_lock); - - if (ref->force_atomic || (ref->percpu_count_ptr & __PERCPU_REF_DEAD)) - __percpu_ref_switch_to_atomic(ref, confirm_switch); - else - __percpu_ref_switch_to_percpu(ref); -} - -/** - * percpu_ref_switch_to_atomic - switch a percpu_ref to atomic mode - * @ref: percpu_ref to switch to atomic mode - * @confirm_switch: optional confirmation callback - * - * There's no reason to use this function for the usual reference counting. - * Use percpu_ref_kill[_and_confirm](). - * - * Schedule switching of @ref to atomic mode. All its percpu counts will - * be collected to the main atomic counter. On completion, when all CPUs - * are guaraneed to be in atomic mode, @confirm_switch, which may not - * block, is invoked. This function may be invoked concurrently with all - * the get/put operations and can safely be mixed with kill and reinit - * operations. Note that @ref will stay in atomic mode across kill/reinit - * cycles until percpu_ref_switch_to_percpu() is called. - * - * This function may block if @ref is in the process of switching to atomic - * mode. If the caller ensures that @ref is not in the process of - * switching to atomic mode, this function can be called from any context. - */ -void percpu_ref_switch_to_atomic(struct percpu_ref *ref, - percpu_ref_func_t *confirm_switch) -{ - unsigned long flags; - - spin_lock_irqsave(&percpu_ref_switch_lock, flags); - - ref->force_atomic = true; - __percpu_ref_switch_mode(ref, confirm_switch); - - spin_unlock_irqrestore(&percpu_ref_switch_lock, flags); -} - -/** - * percpu_ref_switch_to_percpu - switch a percpu_ref to percpu mode - * @ref: percpu_ref to switch to percpu mode - * - * There's no reason to use this function for the usual reference counting. - * To re-use an expired ref, use percpu_ref_reinit(). - * - * Switch @ref to percpu mode. This function may be invoked concurrently - * with all the get/put operations and can safely be mixed with kill and - * reinit operations. This function reverses the sticky atomic state set - * by PERCPU_REF_INIT_ATOMIC or percpu_ref_switch_to_atomic(). If @ref is - * dying or dead, the actual switching takes place on the following - * percpu_ref_reinit(). - * - * This function may block if @ref is in the process of switching to atomic - * mode. If the caller ensures that @ref is not in the process of - * switching to atomic mode, this function can be called from any context. - */ -void percpu_ref_switch_to_percpu(struct percpu_ref *ref) -{ - unsigned long flags; - - spin_lock_irqsave(&percpu_ref_switch_lock, flags); - - ref->force_atomic = false; - __percpu_ref_switch_mode(ref, NULL); - - spin_unlock_irqrestore(&percpu_ref_switch_lock, flags); -} - -/** - * percpu_ref_kill_and_confirm - drop the initial ref and schedule confirmation - * @ref: percpu_ref to kill - * @confirm_kill: optional confirmation callback - * - * Equivalent to percpu_ref_kill() but also schedules kill confirmation if - * @confirm_kill is not NULL. @confirm_kill, which may not block, will be - * called after @ref is seen as dead from all CPUs at which point all - * further invocations of percpu_ref_tryget_live() will fail. See - * percpu_ref_tryget_live() for details. - * - * This function normally doesn't block and can be called from any context - * but it may block if @confirm_kill is specified and @ref is in the - * process of switching to atomic mode by percpu_ref_switch_to_atomic(). - */ -void percpu_ref_kill_and_confirm(struct percpu_ref *ref, - percpu_ref_func_t *confirm_kill) -{ - unsigned long flags; - - spin_lock_irqsave(&percpu_ref_switch_lock, flags); - - WARN_ONCE(ref->percpu_count_ptr & __PERCPU_REF_DEAD, - "%s called more than once on %pf!", __func__, ref->release); - - ref->percpu_count_ptr |= __PERCPU_REF_DEAD; - __percpu_ref_switch_mode(ref, confirm_kill); - percpu_ref_put(ref); - - spin_unlock_irqrestore(&percpu_ref_switch_lock, flags); -} -EXPORT_SYMBOL_GPL(percpu_ref_kill_and_confirm); - -/** - * percpu_ref_reinit - re-initialize a percpu refcount - * @ref: perpcu_ref to re-initialize - * - * Re-initialize @ref so that it's in the same state as when it finished - * percpu_ref_init() ignoring %PERCPU_REF_INIT_DEAD. @ref must have been - * initialized successfully and reached 0 but not exited. - * - * Note that percpu_ref_tryget[_live]() are safe to perform on @ref while - * this function is in progress. - */ -void percpu_ref_reinit(struct percpu_ref *ref) -{ - unsigned long flags; - - spin_lock_irqsave(&percpu_ref_switch_lock, flags); - - WARN_ON_ONCE(!percpu_ref_is_zero(ref)); - - ref->percpu_count_ptr &= ~__PERCPU_REF_DEAD; - percpu_ref_get(ref); - __percpu_ref_switch_mode(ref, NULL); - - spin_unlock_irqrestore(&percpu_ref_switch_lock, flags); -} -EXPORT_SYMBOL_GPL(percpu_ref_reinit); diff --git a/src/linux/lib/percpu_ida.c b/src/linux/lib/percpu_ida.c deleted file mode 100644 index 6d40944..0000000 --- a/src/linux/lib/percpu_ida.c +++ /dev/null @@ -1,390 +0,0 @@ -/* - * Percpu IDA library - * - * Copyright (C) 2013 Datera, Inc. Kent Overstreet - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct percpu_ida_cpu { - /* - * Even though this is percpu, we need a lock for tag stealing by remote - * CPUs: - */ - spinlock_t lock; - - /* nr_free/freelist form a stack of free IDs */ - unsigned nr_free; - unsigned freelist[]; -}; - -static inline void move_tags(unsigned *dst, unsigned *dst_nr, - unsigned *src, unsigned *src_nr, - unsigned nr) -{ - *src_nr -= nr; - memcpy(dst + *dst_nr, src + *src_nr, sizeof(unsigned) * nr); - *dst_nr += nr; -} - -/* - * Try to steal tags from a remote cpu's percpu freelist. - * - * We first check how many percpu freelists have tags - * - * Then we iterate through the cpus until we find some tags - we don't attempt - * to find the "best" cpu to steal from, to keep cacheline bouncing to a - * minimum. - */ -static inline void steal_tags(struct percpu_ida *pool, - struct percpu_ida_cpu *tags) -{ - unsigned cpus_have_tags, cpu = pool->cpu_last_stolen; - struct percpu_ida_cpu *remote; - - for (cpus_have_tags = cpumask_weight(&pool->cpus_have_tags); - cpus_have_tags; cpus_have_tags--) { - cpu = cpumask_next(cpu, &pool->cpus_have_tags); - - if (cpu >= nr_cpu_ids) { - cpu = cpumask_first(&pool->cpus_have_tags); - if (cpu >= nr_cpu_ids) - BUG(); - } - - pool->cpu_last_stolen = cpu; - remote = per_cpu_ptr(pool->tag_cpu, cpu); - - cpumask_clear_cpu(cpu, &pool->cpus_have_tags); - - if (remote == tags) - continue; - - spin_lock(&remote->lock); - - if (remote->nr_free) { - memcpy(tags->freelist, - remote->freelist, - sizeof(unsigned) * remote->nr_free); - - tags->nr_free = remote->nr_free; - remote->nr_free = 0; - } - - spin_unlock(&remote->lock); - - if (tags->nr_free) - break; - } -} - -/* - * Pop up to IDA_PCPU_BATCH_MOVE IDs off the global freelist, and push them onto - * our percpu freelist: - */ -static inline void alloc_global_tags(struct percpu_ida *pool, - struct percpu_ida_cpu *tags) -{ - move_tags(tags->freelist, &tags->nr_free, - pool->freelist, &pool->nr_free, - min(pool->nr_free, pool->percpu_batch_size)); -} - -static inline unsigned alloc_local_tag(struct percpu_ida_cpu *tags) -{ - int tag = -ENOSPC; - - spin_lock(&tags->lock); - if (tags->nr_free) - tag = tags->freelist[--tags->nr_free]; - spin_unlock(&tags->lock); - - return tag; -} - -/** - * percpu_ida_alloc - allocate a tag - * @pool: pool to allocate from - * @state: task state for prepare_to_wait - * - * Returns a tag - an integer in the range [0..nr_tags) (passed to - * tag_pool_init()), or otherwise -ENOSPC on allocation failure. - * - * Safe to be called from interrupt context (assuming it isn't passed - * TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, of course). - * - * @gfp indicates whether or not to wait until a free id is available (it's not - * used for internal memory allocations); thus if passed __GFP_RECLAIM we may sleep - * however long it takes until another thread frees an id (same semantics as a - * mempool). - * - * Will not fail if passed TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE. - */ -int percpu_ida_alloc(struct percpu_ida *pool, int state) -{ - DEFINE_WAIT(wait); - struct percpu_ida_cpu *tags; - unsigned long flags; - int tag; - - local_irq_save(flags); - tags = this_cpu_ptr(pool->tag_cpu); - - /* Fastpath */ - tag = alloc_local_tag(tags); - if (likely(tag >= 0)) { - local_irq_restore(flags); - return tag; - } - - while (1) { - spin_lock(&pool->lock); - - /* - * prepare_to_wait() must come before steal_tags(), in case - * percpu_ida_free() on another cpu flips a bit in - * cpus_have_tags - * - * global lock held and irqs disabled, don't need percpu lock - */ - if (state != TASK_RUNNING) - prepare_to_wait(&pool->wait, &wait, state); - - if (!tags->nr_free) - alloc_global_tags(pool, tags); - if (!tags->nr_free) - steal_tags(pool, tags); - - if (tags->nr_free) { - tag = tags->freelist[--tags->nr_free]; - if (tags->nr_free) - cpumask_set_cpu(smp_processor_id(), - &pool->cpus_have_tags); - } - - spin_unlock(&pool->lock); - local_irq_restore(flags); - - if (tag >= 0 || state == TASK_RUNNING) - break; - - if (signal_pending_state(state, current)) { - tag = -ERESTARTSYS; - break; - } - - schedule(); - - local_irq_save(flags); - tags = this_cpu_ptr(pool->tag_cpu); - } - if (state != TASK_RUNNING) - finish_wait(&pool->wait, &wait); - - return tag; -} -EXPORT_SYMBOL_GPL(percpu_ida_alloc); - -/** - * percpu_ida_free - free a tag - * @pool: pool @tag was allocated from - * @tag: a tag previously allocated with percpu_ida_alloc() - * - * Safe to be called from interrupt context. - */ -void percpu_ida_free(struct percpu_ida *pool, unsigned tag) -{ - struct percpu_ida_cpu *tags; - unsigned long flags; - unsigned nr_free; - - BUG_ON(tag >= pool->nr_tags); - - local_irq_save(flags); - tags = this_cpu_ptr(pool->tag_cpu); - - spin_lock(&tags->lock); - tags->freelist[tags->nr_free++] = tag; - - nr_free = tags->nr_free; - spin_unlock(&tags->lock); - - if (nr_free == 1) { - cpumask_set_cpu(smp_processor_id(), - &pool->cpus_have_tags); - wake_up(&pool->wait); - } - - if (nr_free == pool->percpu_max_size) { - spin_lock(&pool->lock); - - /* - * Global lock held and irqs disabled, don't need percpu - * lock - */ - if (tags->nr_free == pool->percpu_max_size) { - move_tags(pool->freelist, &pool->nr_free, - tags->freelist, &tags->nr_free, - pool->percpu_batch_size); - - wake_up(&pool->wait); - } - spin_unlock(&pool->lock); - } - - local_irq_restore(flags); -} -EXPORT_SYMBOL_GPL(percpu_ida_free); - -/** - * percpu_ida_destroy - release a tag pool's resources - * @pool: pool to free - * - * Frees the resources allocated by percpu_ida_init(). - */ -void percpu_ida_destroy(struct percpu_ida *pool) -{ - free_percpu(pool->tag_cpu); - free_pages((unsigned long) pool->freelist, - get_order(pool->nr_tags * sizeof(unsigned))); -} -EXPORT_SYMBOL_GPL(percpu_ida_destroy); - -/** - * percpu_ida_init - initialize a percpu tag pool - * @pool: pool to initialize - * @nr_tags: number of tags that will be available for allocation - * - * Initializes @pool so that it can be used to allocate tags - integers in the - * range [0, nr_tags). Typically, they'll be used by driver code to refer to a - * preallocated array of tag structures. - * - * Allocation is percpu, but sharding is limited by nr_tags - for best - * performance, the workload should not span more cpus than nr_tags / 128. - */ -int __percpu_ida_init(struct percpu_ida *pool, unsigned long nr_tags, - unsigned long max_size, unsigned long batch_size) -{ - unsigned i, cpu, order; - - memset(pool, 0, sizeof(*pool)); - - init_waitqueue_head(&pool->wait); - spin_lock_init(&pool->lock); - pool->nr_tags = nr_tags; - pool->percpu_max_size = max_size; - pool->percpu_batch_size = batch_size; - - /* Guard against overflow */ - if (nr_tags > (unsigned) INT_MAX + 1) { - pr_err("percpu_ida_init(): nr_tags too large\n"); - return -EINVAL; - } - - order = get_order(nr_tags * sizeof(unsigned)); - pool->freelist = (void *) __get_free_pages(GFP_KERNEL, order); - if (!pool->freelist) - return -ENOMEM; - - for (i = 0; i < nr_tags; i++) - pool->freelist[i] = i; - - pool->nr_free = nr_tags; - - pool->tag_cpu = __alloc_percpu(sizeof(struct percpu_ida_cpu) + - pool->percpu_max_size * sizeof(unsigned), - sizeof(unsigned)); - if (!pool->tag_cpu) - goto err; - - for_each_possible_cpu(cpu) - spin_lock_init(&per_cpu_ptr(pool->tag_cpu, cpu)->lock); - - return 0; -err: - percpu_ida_destroy(pool); - return -ENOMEM; -} -EXPORT_SYMBOL_GPL(__percpu_ida_init); - -/** - * percpu_ida_for_each_free - iterate free ids of a pool - * @pool: pool to iterate - * @fn: interate callback function - * @data: parameter for @fn - * - * Note, this doesn't guarantee to iterate all free ids restrictly. Some free - * ids might be missed, some might be iterated duplicated, and some might - * be iterated and not free soon. - */ -int percpu_ida_for_each_free(struct percpu_ida *pool, percpu_ida_cb fn, - void *data) -{ - unsigned long flags; - struct percpu_ida_cpu *remote; - unsigned cpu, i, err = 0; - - local_irq_save(flags); - for_each_possible_cpu(cpu) { - remote = per_cpu_ptr(pool->tag_cpu, cpu); - spin_lock(&remote->lock); - for (i = 0; i < remote->nr_free; i++) { - err = fn(remote->freelist[i], data); - if (err) - break; - } - spin_unlock(&remote->lock); - if (err) - goto out; - } - - spin_lock(&pool->lock); - for (i = 0; i < pool->nr_free; i++) { - err = fn(pool->freelist[i], data); - if (err) - break; - } - spin_unlock(&pool->lock); -out: - local_irq_restore(flags); - return err; -} -EXPORT_SYMBOL_GPL(percpu_ida_for_each_free); - -/** - * percpu_ida_free_tags - return free tags number of a specific cpu or global pool - * @pool: pool related - * @cpu: specific cpu or global pool if @cpu == nr_cpu_ids - * - * Note: this just returns a snapshot of free tags number. - */ -unsigned percpu_ida_free_tags(struct percpu_ida *pool, int cpu) -{ - struct percpu_ida_cpu *remote; - if (cpu == nr_cpu_ids) - return pool->nr_free; - remote = per_cpu_ptr(pool->tag_cpu, cpu); - return remote->nr_free; -} -EXPORT_SYMBOL_GPL(percpu_ida_free_tags); diff --git a/src/linux/lib/plist.c b/src/linux/lib/plist.c deleted file mode 100644 index 3a30c53..0000000 --- a/src/linux/lib/plist.c +++ /dev/null @@ -1,263 +0,0 @@ -/* - * lib/plist.c - * - * Descending-priority-sorted double-linked list - * - * (C) 2002-2003 Intel Corp - * Inaky Perez-Gonzalez . - * - * 2001-2005 (c) MontaVista Software, Inc. - * Daniel Walker - * - * (C) 2005 Thomas Gleixner - * - * Simplifications of the original code by - * Oleg Nesterov - * - * Licensed under the FSF's GNU Public License v2 or later. - * - * Based on simple lists (include/linux/list.h). - * - * This file contains the add / del functions which are considered to - * be too large to inline. See include/linux/plist.h for further - * information. - */ - -#include -#include - -#ifdef CONFIG_DEBUG_PI_LIST - -static struct plist_head test_head; - -static void plist_check_prev_next(struct list_head *t, struct list_head *p, - struct list_head *n) -{ - WARN(n->prev != p || p->next != n, - "top: %p, n: %p, p: %p\n" - "prev: %p, n: %p, p: %p\n" - "next: %p, n: %p, p: %p\n", - t, t->next, t->prev, - p, p->next, p->prev, - n, n->next, n->prev); -} - -static void plist_check_list(struct list_head *top) -{ - struct list_head *prev = top, *next = top->next; - - plist_check_prev_next(top, prev, next); - while (next != top) { - prev = next; - next = prev->next; - plist_check_prev_next(top, prev, next); - } -} - -static void plist_check_head(struct plist_head *head) -{ - if (!plist_head_empty(head)) - plist_check_list(&plist_first(head)->prio_list); - plist_check_list(&head->node_list); -} - -#else -# define plist_check_head(h) do { } while (0) -#endif - -/** - * plist_add - add @node to @head - * - * @node: &struct plist_node pointer - * @head: &struct plist_head pointer - */ -void plist_add(struct plist_node *node, struct plist_head *head) -{ - struct plist_node *first, *iter, *prev = NULL; - struct list_head *node_next = &head->node_list; - - plist_check_head(head); - WARN_ON(!plist_node_empty(node)); - WARN_ON(!list_empty(&node->prio_list)); - - if (plist_head_empty(head)) - goto ins_node; - - first = iter = plist_first(head); - - do { - if (node->prio < iter->prio) { - node_next = &iter->node_list; - break; - } - - prev = iter; - iter = list_entry(iter->prio_list.next, - struct plist_node, prio_list); - } while (iter != first); - - if (!prev || prev->prio != node->prio) - list_add_tail(&node->prio_list, &iter->prio_list); -ins_node: - list_add_tail(&node->node_list, node_next); - - plist_check_head(head); -} - -/** - * plist_del - Remove a @node from plist. - * - * @node: &struct plist_node pointer - entry to be removed - * @head: &struct plist_head pointer - list head - */ -void plist_del(struct plist_node *node, struct plist_head *head) -{ - plist_check_head(head); - - if (!list_empty(&node->prio_list)) { - if (node->node_list.next != &head->node_list) { - struct plist_node *next; - - next = list_entry(node->node_list.next, - struct plist_node, node_list); - - /* add the next plist_node into prio_list */ - if (list_empty(&next->prio_list)) - list_add(&next->prio_list, &node->prio_list); - } - list_del_init(&node->prio_list); - } - - list_del_init(&node->node_list); - - plist_check_head(head); -} - -/** - * plist_requeue - Requeue @node at end of same-prio entries. - * - * This is essentially an optimized plist_del() followed by - * plist_add(). It moves an entry already in the plist to - * after any other same-priority entries. - * - * @node: &struct plist_node pointer - entry to be moved - * @head: &struct plist_head pointer - list head - */ -void plist_requeue(struct plist_node *node, struct plist_head *head) -{ - struct plist_node *iter; - struct list_head *node_next = &head->node_list; - - plist_check_head(head); - BUG_ON(plist_head_empty(head)); - BUG_ON(plist_node_empty(node)); - - if (node == plist_last(head)) - return; - - iter = plist_next(node); - - if (node->prio != iter->prio) - return; - - plist_del(node, head); - - plist_for_each_continue(iter, head) { - if (node->prio != iter->prio) { - node_next = &iter->node_list; - break; - } - } - list_add_tail(&node->node_list, node_next); - - plist_check_head(head); -} - -#ifdef CONFIG_DEBUG_PI_LIST -#include -#include -#include - -static struct plist_node __initdata test_node[241]; - -static void __init plist_test_check(int nr_expect) -{ - struct plist_node *first, *prio_pos, *node_pos; - - if (plist_head_empty(&test_head)) { - BUG_ON(nr_expect != 0); - return; - } - - prio_pos = first = plist_first(&test_head); - plist_for_each(node_pos, &test_head) { - if (nr_expect-- < 0) - break; - if (node_pos == first) - continue; - if (node_pos->prio == prio_pos->prio) { - BUG_ON(!list_empty(&node_pos->prio_list)); - continue; - } - - BUG_ON(prio_pos->prio > node_pos->prio); - BUG_ON(prio_pos->prio_list.next != &node_pos->prio_list); - prio_pos = node_pos; - } - - BUG_ON(nr_expect != 0); - BUG_ON(prio_pos->prio_list.next != &first->prio_list); -} - -static void __init plist_test_requeue(struct plist_node *node) -{ - plist_requeue(node, &test_head); - - if (node != plist_last(&test_head)) - BUG_ON(node->prio == plist_next(node)->prio); -} - -static int __init plist_test(void) -{ - int nr_expect = 0, i, loop; - unsigned int r = local_clock(); - - printk(KERN_DEBUG "start plist test\n"); - plist_head_init(&test_head); - for (i = 0; i < ARRAY_SIZE(test_node); i++) - plist_node_init(test_node + i, 0); - - for (loop = 0; loop < 1000; loop++) { - r = r * 193939 % 47629; - i = r % ARRAY_SIZE(test_node); - if (plist_node_empty(test_node + i)) { - r = r * 193939 % 47629; - test_node[i].prio = r % 99; - plist_add(test_node + i, &test_head); - nr_expect++; - } else { - plist_del(test_node + i, &test_head); - nr_expect--; - } - plist_test_check(nr_expect); - if (!plist_node_empty(test_node + i)) { - plist_test_requeue(test_node + i); - plist_test_check(nr_expect); - } - } - - for (i = 0; i < ARRAY_SIZE(test_node); i++) { - if (plist_node_empty(test_node + i)) - continue; - plist_del(test_node + i, &test_head); - nr_expect--; - plist_test_check(nr_expect); - } - - printk(KERN_DEBUG "end plist test\n"); - return 0; -} - -module_init(plist_test); - -#endif diff --git a/src/linux/lib/radix-tree.c b/src/linux/lib/radix-tree.c deleted file mode 100644 index 8e6d552..0000000 --- a/src/linux/lib/radix-tree.c +++ /dev/null @@ -1,1673 +0,0 @@ -/* - * Copyright (C) 2001 Momchil Velikov - * Portions Copyright (C) 2001 Christoph Hellwig - * Copyright (C) 2005 SGI, Christoph Lameter - * Copyright (C) 2006 Nick Piggin - * Copyright (C) 2012 Konstantin Khlebnikov - * Copyright (C) 2016 Intel, Matthew Wilcox - * Copyright (C) 2016 Intel, Ross Zwisler - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2, or (at - * your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* in_interrupt() */ - - -/* Number of nodes in fully populated tree of given height */ -static unsigned long height_to_maxnodes[RADIX_TREE_MAX_PATH + 1] __read_mostly; - -/* - * Radix tree node cache. - */ -static struct kmem_cache *radix_tree_node_cachep; - -/* - * The radix tree is variable-height, so an insert operation not only has - * to build the branch to its corresponding item, it also has to build the - * branch to existing items if the size has to be increased (by - * radix_tree_extend). - * - * The worst case is a zero height tree with just a single item at index 0, - * and then inserting an item at index ULONG_MAX. This requires 2 new branches - * of RADIX_TREE_MAX_PATH size to be created, with only the root node shared. - * Hence: - */ -#define RADIX_TREE_PRELOAD_SIZE (RADIX_TREE_MAX_PATH * 2 - 1) - -/* - * Per-cpu pool of preloaded nodes - */ -struct radix_tree_preload { - unsigned nr; - /* nodes->private_data points to next preallocated node */ - struct radix_tree_node *nodes; -}; -static DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, }; - -static inline void *node_to_entry(void *ptr) -{ - return (void *)((unsigned long)ptr | RADIX_TREE_INTERNAL_NODE); -} - -#define RADIX_TREE_RETRY node_to_entry(NULL) - -#ifdef CONFIG_RADIX_TREE_MULTIORDER -/* Sibling slots point directly to another slot in the same node */ -static inline bool is_sibling_entry(struct radix_tree_node *parent, void *node) -{ - void **ptr = node; - return (parent->slots <= ptr) && - (ptr < parent->slots + RADIX_TREE_MAP_SIZE); -} -#else -static inline bool is_sibling_entry(struct radix_tree_node *parent, void *node) -{ - return false; -} -#endif - -static inline unsigned long get_slot_offset(struct radix_tree_node *parent, - void **slot) -{ - return slot - parent->slots; -} - -static unsigned int radix_tree_descend(struct radix_tree_node *parent, - struct radix_tree_node **nodep, unsigned long index) -{ - unsigned int offset = (index >> parent->shift) & RADIX_TREE_MAP_MASK; - void **entry = rcu_dereference_raw(parent->slots[offset]); - -#ifdef CONFIG_RADIX_TREE_MULTIORDER - if (radix_tree_is_internal_node(entry)) { - if (is_sibling_entry(parent, entry)) { - void **sibentry = (void **) entry_to_node(entry); - offset = get_slot_offset(parent, sibentry); - entry = rcu_dereference_raw(*sibentry); - } - } -#endif - - *nodep = (void *)entry; - return offset; -} - -static inline gfp_t root_gfp_mask(struct radix_tree_root *root) -{ - return root->gfp_mask & __GFP_BITS_MASK; -} - -static inline void tag_set(struct radix_tree_node *node, unsigned int tag, - int offset) -{ - __set_bit(offset, node->tags[tag]); -} - -static inline void tag_clear(struct radix_tree_node *node, unsigned int tag, - int offset) -{ - __clear_bit(offset, node->tags[tag]); -} - -static inline int tag_get(struct radix_tree_node *node, unsigned int tag, - int offset) -{ - return test_bit(offset, node->tags[tag]); -} - -static inline void root_tag_set(struct radix_tree_root *root, unsigned int tag) -{ - root->gfp_mask |= (__force gfp_t)(1 << (tag + __GFP_BITS_SHIFT)); -} - -static inline void root_tag_clear(struct radix_tree_root *root, unsigned tag) -{ - root->gfp_mask &= (__force gfp_t)~(1 << (tag + __GFP_BITS_SHIFT)); -} - -static inline void root_tag_clear_all(struct radix_tree_root *root) -{ - root->gfp_mask &= __GFP_BITS_MASK; -} - -static inline int root_tag_get(struct radix_tree_root *root, unsigned int tag) -{ - return (__force int)root->gfp_mask & (1 << (tag + __GFP_BITS_SHIFT)); -} - -static inline unsigned root_tags_get(struct radix_tree_root *root) -{ - return (__force unsigned)root->gfp_mask >> __GFP_BITS_SHIFT; -} - -/* - * Returns 1 if any slot in the node has this tag set. - * Otherwise returns 0. - */ -static inline int any_tag_set(struct radix_tree_node *node, unsigned int tag) -{ - unsigned idx; - for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) { - if (node->tags[tag][idx]) - return 1; - } - return 0; -} - -/** - * radix_tree_find_next_bit - find the next set bit in a memory region - * - * @addr: The address to base the search on - * @size: The bitmap size in bits - * @offset: The bitnumber to start searching at - * - * Unrollable variant of find_next_bit() for constant size arrays. - * Tail bits starting from size to roundup(size, BITS_PER_LONG) must be zero. - * Returns next bit offset, or size if nothing found. - */ -static __always_inline unsigned long -radix_tree_find_next_bit(const unsigned long *addr, - unsigned long size, unsigned long offset) -{ - if (!__builtin_constant_p(size)) - return find_next_bit(addr, size, offset); - - if (offset < size) { - unsigned long tmp; - - addr += offset / BITS_PER_LONG; - tmp = *addr >> (offset % BITS_PER_LONG); - if (tmp) - return __ffs(tmp) + offset; - offset = (offset + BITS_PER_LONG) & ~(BITS_PER_LONG - 1); - while (offset < size) { - tmp = *++addr; - if (tmp) - return __ffs(tmp) + offset; - offset += BITS_PER_LONG; - } - } - return size; -} - -#ifndef __KERNEL__ -static void dump_node(struct radix_tree_node *node, unsigned long index) -{ - unsigned long i; - - pr_debug("radix node: %p offset %d tags %lx %lx %lx shift %d count %d parent %p\n", - node, node->offset, - node->tags[0][0], node->tags[1][0], node->tags[2][0], - node->shift, node->count, node->parent); - - for (i = 0; i < RADIX_TREE_MAP_SIZE; i++) { - unsigned long first = index | (i << node->shift); - unsigned long last = first | ((1UL << node->shift) - 1); - void *entry = node->slots[i]; - if (!entry) - continue; - if (is_sibling_entry(node, entry)) { - pr_debug("radix sblng %p offset %ld val %p indices %ld-%ld\n", - entry, i, - *(void **)entry_to_node(entry), - first, last); - } else if (!radix_tree_is_internal_node(entry)) { - pr_debug("radix entry %p offset %ld indices %ld-%ld\n", - entry, i, first, last); - } else { - dump_node(entry_to_node(entry), first); - } - } -} - -/* For debug */ -static void radix_tree_dump(struct radix_tree_root *root) -{ - pr_debug("radix root: %p rnode %p tags %x\n", - root, root->rnode, - root->gfp_mask >> __GFP_BITS_SHIFT); - if (!radix_tree_is_internal_node(root->rnode)) - return; - dump_node(entry_to_node(root->rnode), 0); -} -#endif - -/* - * This assumes that the caller has performed appropriate preallocation, and - * that the caller has pinned this thread of control to the current CPU. - */ -static struct radix_tree_node * -radix_tree_node_alloc(struct radix_tree_root *root) -{ - struct radix_tree_node *ret = NULL; - gfp_t gfp_mask = root_gfp_mask(root); - - /* - * Preload code isn't irq safe and it doesn't make sense to use - * preloading during an interrupt anyway as all the allocations have - * to be atomic. So just do normal allocation when in interrupt. - */ - if (!gfpflags_allow_blocking(gfp_mask) && !in_interrupt()) { - struct radix_tree_preload *rtp; - - /* - * Even if the caller has preloaded, try to allocate from the - * cache first for the new node to get accounted to the memory - * cgroup. - */ - ret = kmem_cache_alloc(radix_tree_node_cachep, - gfp_mask | __GFP_NOWARN); - if (ret) - goto out; - - /* - * Provided the caller has preloaded here, we will always - * succeed in getting a node here (and never reach - * kmem_cache_alloc) - */ - rtp = this_cpu_ptr(&radix_tree_preloads); - if (rtp->nr) { - ret = rtp->nodes; - rtp->nodes = ret->private_data; - ret->private_data = NULL; - rtp->nr--; - } - /* - * Update the allocation stack trace as this is more useful - * for debugging. - */ - kmemleak_update_trace(ret); - goto out; - } - ret = kmem_cache_alloc(radix_tree_node_cachep, gfp_mask); -out: - BUG_ON(radix_tree_is_internal_node(ret)); - return ret; -} - -static void radix_tree_node_rcu_free(struct rcu_head *head) -{ - struct radix_tree_node *node = - container_of(head, struct radix_tree_node, rcu_head); - int i; - - /* - * must only free zeroed nodes into the slab. radix_tree_shrink - * can leave us with a non-NULL entry in the first slot, so clear - * that here to make sure. - */ - for (i = 0; i < RADIX_TREE_MAX_TAGS; i++) - tag_clear(node, i, 0); - - node->slots[0] = NULL; - node->count = 0; - - kmem_cache_free(radix_tree_node_cachep, node); -} - -static inline void -radix_tree_node_free(struct radix_tree_node *node) -{ - call_rcu(&node->rcu_head, radix_tree_node_rcu_free); -} - -/* - * Load up this CPU's radix_tree_node buffer with sufficient objects to - * ensure that the addition of a single element in the tree cannot fail. On - * success, return zero, with preemption disabled. On error, return -ENOMEM - * with preemption not disabled. - * - * To make use of this facility, the radix tree must be initialised without - * __GFP_DIRECT_RECLAIM being passed to INIT_RADIX_TREE(). - */ -static int __radix_tree_preload(gfp_t gfp_mask, int nr) -{ - struct radix_tree_preload *rtp; - struct radix_tree_node *node; - int ret = -ENOMEM; - - /* - * Nodes preloaded by one cgroup can be be used by another cgroup, so - * they should never be accounted to any particular memory cgroup. - */ - gfp_mask &= ~__GFP_ACCOUNT; - - preempt_disable(); - rtp = this_cpu_ptr(&radix_tree_preloads); - while (rtp->nr < nr) { - preempt_enable(); - node = kmem_cache_alloc(radix_tree_node_cachep, gfp_mask); - if (node == NULL) - goto out; - preempt_disable(); - rtp = this_cpu_ptr(&radix_tree_preloads); - if (rtp->nr < nr) { - node->private_data = rtp->nodes; - rtp->nodes = node; - rtp->nr++; - } else { - kmem_cache_free(radix_tree_node_cachep, node); - } - } - ret = 0; -out: - return ret; -} - -/* - * Load up this CPU's radix_tree_node buffer with sufficient objects to - * ensure that the addition of a single element in the tree cannot fail. On - * success, return zero, with preemption disabled. On error, return -ENOMEM - * with preemption not disabled. - * - * To make use of this facility, the radix tree must be initialised without - * __GFP_DIRECT_RECLAIM being passed to INIT_RADIX_TREE(). - */ -int radix_tree_preload(gfp_t gfp_mask) -{ - /* Warn on non-sensical use... */ - WARN_ON_ONCE(!gfpflags_allow_blocking(gfp_mask)); - return __radix_tree_preload(gfp_mask, RADIX_TREE_PRELOAD_SIZE); -} -EXPORT_SYMBOL(radix_tree_preload); - -/* - * The same as above function, except we don't guarantee preloading happens. - * We do it, if we decide it helps. On success, return zero with preemption - * disabled. On error, return -ENOMEM with preemption not disabled. - */ -int radix_tree_maybe_preload(gfp_t gfp_mask) -{ - if (gfpflags_allow_blocking(gfp_mask)) - return __radix_tree_preload(gfp_mask, RADIX_TREE_PRELOAD_SIZE); - /* Preloading doesn't help anything with this gfp mask, skip it */ - preempt_disable(); - return 0; -} -EXPORT_SYMBOL(radix_tree_maybe_preload); - -/* - * The same as function above, but preload number of nodes required to insert - * (1 << order) continuous naturally-aligned elements. - */ -int radix_tree_maybe_preload_order(gfp_t gfp_mask, int order) -{ - unsigned long nr_subtrees; - int nr_nodes, subtree_height; - - /* Preloading doesn't help anything with this gfp mask, skip it */ - if (!gfpflags_allow_blocking(gfp_mask)) { - preempt_disable(); - return 0; - } - - /* - * Calculate number and height of fully populated subtrees it takes to - * store (1 << order) elements. - */ - nr_subtrees = 1 << order; - for (subtree_height = 0; nr_subtrees > RADIX_TREE_MAP_SIZE; - subtree_height++) - nr_subtrees >>= RADIX_TREE_MAP_SHIFT; - - /* - * The worst case is zero height tree with a single item at index 0 and - * then inserting items starting at ULONG_MAX - (1 << order). - * - * This requires RADIX_TREE_MAX_PATH nodes to build branch from root to - * 0-index item. - */ - nr_nodes = RADIX_TREE_MAX_PATH; - - /* Plus branch to fully populated subtrees. */ - nr_nodes += RADIX_TREE_MAX_PATH - subtree_height; - - /* Root node is shared. */ - nr_nodes--; - - /* Plus nodes required to build subtrees. */ - nr_nodes += nr_subtrees * height_to_maxnodes[subtree_height]; - - return __radix_tree_preload(gfp_mask, nr_nodes); -} - -/* - * The maximum index which can be stored in a radix tree - */ -static inline unsigned long shift_maxindex(unsigned int shift) -{ - return (RADIX_TREE_MAP_SIZE << shift) - 1; -} - -static inline unsigned long node_maxindex(struct radix_tree_node *node) -{ - return shift_maxindex(node->shift); -} - -static unsigned radix_tree_load_root(struct radix_tree_root *root, - struct radix_tree_node **nodep, unsigned long *maxindex) -{ - struct radix_tree_node *node = rcu_dereference_raw(root->rnode); - - *nodep = node; - - if (likely(radix_tree_is_internal_node(node))) { - node = entry_to_node(node); - *maxindex = node_maxindex(node); - return node->shift + RADIX_TREE_MAP_SHIFT; - } - - *maxindex = 0; - return 0; -} - -/* - * Extend a radix tree so it can store key @index. - */ -static int radix_tree_extend(struct radix_tree_root *root, - unsigned long index, unsigned int shift) -{ - struct radix_tree_node *slot; - unsigned int maxshift; - int tag; - - /* Figure out what the shift should be. */ - maxshift = shift; - while (index > shift_maxindex(maxshift)) - maxshift += RADIX_TREE_MAP_SHIFT; - - slot = root->rnode; - if (!slot) - goto out; - - do { - struct radix_tree_node *node = radix_tree_node_alloc(root); - - if (!node) - return -ENOMEM; - - /* Propagate the aggregated tag info into the new root */ - for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { - if (root_tag_get(root, tag)) - tag_set(node, tag, 0); - } - - BUG_ON(shift > BITS_PER_LONG); - node->shift = shift; - node->offset = 0; - node->count = 1; - node->parent = NULL; - if (radix_tree_is_internal_node(slot)) - entry_to_node(slot)->parent = node; - node->slots[0] = slot; - slot = node_to_entry(node); - rcu_assign_pointer(root->rnode, slot); - shift += RADIX_TREE_MAP_SHIFT; - } while (shift <= maxshift); -out: - return maxshift + RADIX_TREE_MAP_SHIFT; -} - -/** - * __radix_tree_create - create a slot in a radix tree - * @root: radix tree root - * @index: index key - * @order: index occupies 2^order aligned slots - * @nodep: returns node - * @slotp: returns slot - * - * Create, if necessary, and return the node and slot for an item - * at position @index in the radix tree @root. - * - * Until there is more than one item in the tree, no nodes are - * allocated and @root->rnode is used as a direct slot instead of - * pointing to a node, in which case *@nodep will be NULL. - * - * Returns -ENOMEM, or 0 for success. - */ -int __radix_tree_create(struct radix_tree_root *root, unsigned long index, - unsigned order, struct radix_tree_node **nodep, - void ***slotp) -{ - struct radix_tree_node *node = NULL, *child; - void **slot = (void **)&root->rnode; - unsigned long maxindex; - unsigned int shift, offset = 0; - unsigned long max = index | ((1UL << order) - 1); - - shift = radix_tree_load_root(root, &child, &maxindex); - - /* Make sure the tree is high enough. */ - if (max > maxindex) { - int error = radix_tree_extend(root, max, shift); - if (error < 0) - return error; - shift = error; - child = root->rnode; - if (order == shift) - shift += RADIX_TREE_MAP_SHIFT; - } - - while (shift > order) { - shift -= RADIX_TREE_MAP_SHIFT; - if (child == NULL) { - /* Have to add a child node. */ - child = radix_tree_node_alloc(root); - if (!child) - return -ENOMEM; - child->shift = shift; - child->offset = offset; - child->parent = node; - rcu_assign_pointer(*slot, node_to_entry(child)); - if (node) - node->count++; - } else if (!radix_tree_is_internal_node(child)) - break; - - /* Go a level down */ - node = entry_to_node(child); - offset = radix_tree_descend(node, &child, index); - slot = &node->slots[offset]; - } - -#ifdef CONFIG_RADIX_TREE_MULTIORDER - /* Insert pointers to the canonical entry */ - if (order > shift) { - unsigned i, n = 1 << (order - shift); - offset = offset & ~(n - 1); - slot = &node->slots[offset]; - child = node_to_entry(slot); - for (i = 0; i < n; i++) { - if (slot[i]) - return -EEXIST; - } - - for (i = 1; i < n; i++) { - rcu_assign_pointer(slot[i], child); - node->count++; - } - } -#endif - - if (nodep) - *nodep = node; - if (slotp) - *slotp = slot; - return 0; -} - -/** - * __radix_tree_insert - insert into a radix tree - * @root: radix tree root - * @index: index key - * @order: key covers the 2^order indices around index - * @item: item to insert - * - * Insert an item into the radix tree at position @index. - */ -int __radix_tree_insert(struct radix_tree_root *root, unsigned long index, - unsigned order, void *item) -{ - struct radix_tree_node *node; - void **slot; - int error; - - BUG_ON(radix_tree_is_internal_node(item)); - - error = __radix_tree_create(root, index, order, &node, &slot); - if (error) - return error; - if (*slot != NULL) - return -EEXIST; - rcu_assign_pointer(*slot, item); - - if (node) { - unsigned offset = get_slot_offset(node, slot); - node->count++; - BUG_ON(tag_get(node, 0, offset)); - BUG_ON(tag_get(node, 1, offset)); - BUG_ON(tag_get(node, 2, offset)); - } else { - BUG_ON(root_tags_get(root)); - } - - return 0; -} -EXPORT_SYMBOL(__radix_tree_insert); - -/** - * __radix_tree_lookup - lookup an item in a radix tree - * @root: radix tree root - * @index: index key - * @nodep: returns node - * @slotp: returns slot - * - * Lookup and return the item at position @index in the radix - * tree @root. - * - * Until there is more than one item in the tree, no nodes are - * allocated and @root->rnode is used as a direct slot instead of - * pointing to a node, in which case *@nodep will be NULL. - */ -void *__radix_tree_lookup(struct radix_tree_root *root, unsigned long index, - struct radix_tree_node **nodep, void ***slotp) -{ - struct radix_tree_node *node, *parent; - unsigned long maxindex; - void **slot; - - restart: - parent = NULL; - slot = (void **)&root->rnode; - radix_tree_load_root(root, &node, &maxindex); - if (index > maxindex) - return NULL; - - while (radix_tree_is_internal_node(node)) { - unsigned offset; - - if (node == RADIX_TREE_RETRY) - goto restart; - parent = entry_to_node(node); - offset = radix_tree_descend(parent, &node, index); - slot = parent->slots + offset; - } - - if (nodep) - *nodep = parent; - if (slotp) - *slotp = slot; - return node; -} - -/** - * radix_tree_lookup_slot - lookup a slot in a radix tree - * @root: radix tree root - * @index: index key - * - * Returns: the slot corresponding to the position @index in the - * radix tree @root. This is useful for update-if-exists operations. - * - * This function can be called under rcu_read_lock iff the slot is not - * modified by radix_tree_replace_slot, otherwise it must be called - * exclusive from other writers. Any dereference of the slot must be done - * using radix_tree_deref_slot. - */ -void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index) -{ - void **slot; - - if (!__radix_tree_lookup(root, index, NULL, &slot)) - return NULL; - return slot; -} -EXPORT_SYMBOL(radix_tree_lookup_slot); - -/** - * radix_tree_lookup - perform lookup operation on a radix tree - * @root: radix tree root - * @index: index key - * - * Lookup the item at the position @index in the radix tree @root. - * - * This function can be called under rcu_read_lock, however the caller - * must manage lifetimes of leaf nodes (eg. RCU may also be used to free - * them safely). No RCU barriers are required to access or modify the - * returned item, however. - */ -void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index) -{ - return __radix_tree_lookup(root, index, NULL, NULL); -} -EXPORT_SYMBOL(radix_tree_lookup); - -/** - * radix_tree_tag_set - set a tag on a radix tree node - * @root: radix tree root - * @index: index key - * @tag: tag index - * - * Set the search tag (which must be < RADIX_TREE_MAX_TAGS) - * corresponding to @index in the radix tree. From - * the root all the way down to the leaf node. - * - * Returns the address of the tagged item. Setting a tag on a not-present - * item is a bug. - */ -void *radix_tree_tag_set(struct radix_tree_root *root, - unsigned long index, unsigned int tag) -{ - struct radix_tree_node *node, *parent; - unsigned long maxindex; - - radix_tree_load_root(root, &node, &maxindex); - BUG_ON(index > maxindex); - - while (radix_tree_is_internal_node(node)) { - unsigned offset; - - parent = entry_to_node(node); - offset = radix_tree_descend(parent, &node, index); - BUG_ON(!node); - - if (!tag_get(parent, tag, offset)) - tag_set(parent, tag, offset); - } - - /* set the root's tag bit */ - if (!root_tag_get(root, tag)) - root_tag_set(root, tag); - - return node; -} -EXPORT_SYMBOL(radix_tree_tag_set); - -static void node_tag_clear(struct radix_tree_root *root, - struct radix_tree_node *node, - unsigned int tag, unsigned int offset) -{ - while (node) { - if (!tag_get(node, tag, offset)) - return; - tag_clear(node, tag, offset); - if (any_tag_set(node, tag)) - return; - - offset = node->offset; - node = node->parent; - } - - /* clear the root's tag bit */ - if (root_tag_get(root, tag)) - root_tag_clear(root, tag); -} - -/** - * radix_tree_tag_clear - clear a tag on a radix tree node - * @root: radix tree root - * @index: index key - * @tag: tag index - * - * Clear the search tag (which must be < RADIX_TREE_MAX_TAGS) - * corresponding to @index in the radix tree. If this causes - * the leaf node to have no tags set then clear the tag in the - * next-to-leaf node, etc. - * - * Returns the address of the tagged item on success, else NULL. ie: - * has the same return value and semantics as radix_tree_lookup(). - */ -void *radix_tree_tag_clear(struct radix_tree_root *root, - unsigned long index, unsigned int tag) -{ - struct radix_tree_node *node, *parent; - unsigned long maxindex; - int uninitialized_var(offset); - - radix_tree_load_root(root, &node, &maxindex); - if (index > maxindex) - return NULL; - - parent = NULL; - - while (radix_tree_is_internal_node(node)) { - parent = entry_to_node(node); - offset = radix_tree_descend(parent, &node, index); - } - - if (node) - node_tag_clear(root, parent, tag, offset); - - return node; -} -EXPORT_SYMBOL(radix_tree_tag_clear); - -/** - * radix_tree_tag_get - get a tag on a radix tree node - * @root: radix tree root - * @index: index key - * @tag: tag index (< RADIX_TREE_MAX_TAGS) - * - * Return values: - * - * 0: tag not present or not set - * 1: tag set - * - * Note that the return value of this function may not be relied on, even if - * the RCU lock is held, unless tag modification and node deletion are excluded - * from concurrency. - */ -int radix_tree_tag_get(struct radix_tree_root *root, - unsigned long index, unsigned int tag) -{ - struct radix_tree_node *node, *parent; - unsigned long maxindex; - - if (!root_tag_get(root, tag)) - return 0; - - radix_tree_load_root(root, &node, &maxindex); - if (index > maxindex) - return 0; - if (node == NULL) - return 0; - - while (radix_tree_is_internal_node(node)) { - unsigned offset; - - parent = entry_to_node(node); - offset = radix_tree_descend(parent, &node, index); - - if (!node) - return 0; - if (!tag_get(parent, tag, offset)) - return 0; - if (node == RADIX_TREE_RETRY) - break; - } - - return 1; -} -EXPORT_SYMBOL(radix_tree_tag_get); - -static inline void __set_iter_shift(struct radix_tree_iter *iter, - unsigned int shift) -{ -#ifdef CONFIG_RADIX_TREE_MULTIORDER - iter->shift = shift; -#endif -} - -/** - * radix_tree_next_chunk - find next chunk of slots for iteration - * - * @root: radix tree root - * @iter: iterator state - * @flags: RADIX_TREE_ITER_* flags and tag index - * Returns: pointer to chunk first slot, or NULL if iteration is over - */ -void **radix_tree_next_chunk(struct radix_tree_root *root, - struct radix_tree_iter *iter, unsigned flags) -{ - unsigned tag = flags & RADIX_TREE_ITER_TAG_MASK; - struct radix_tree_node *node, *child; - unsigned long index, offset, maxindex; - - if ((flags & RADIX_TREE_ITER_TAGGED) && !root_tag_get(root, tag)) - return NULL; - - /* - * Catch next_index overflow after ~0UL. iter->index never overflows - * during iterating; it can be zero only at the beginning. - * And we cannot overflow iter->next_index in a single step, - * because RADIX_TREE_MAP_SHIFT < BITS_PER_LONG. - * - * This condition also used by radix_tree_next_slot() to stop - * contiguous iterating, and forbid swithing to the next chunk. - */ - index = iter->next_index; - if (!index && iter->index) - return NULL; - - restart: - radix_tree_load_root(root, &child, &maxindex); - if (index > maxindex) - return NULL; - if (!child) - return NULL; - - if (!radix_tree_is_internal_node(child)) { - /* Single-slot tree */ - iter->index = index; - iter->next_index = maxindex + 1; - iter->tags = 1; - __set_iter_shift(iter, 0); - return (void **)&root->rnode; - } - - do { - node = entry_to_node(child); - offset = radix_tree_descend(node, &child, index); - - if ((flags & RADIX_TREE_ITER_TAGGED) ? - !tag_get(node, tag, offset) : !child) { - /* Hole detected */ - if (flags & RADIX_TREE_ITER_CONTIG) - return NULL; - - if (flags & RADIX_TREE_ITER_TAGGED) - offset = radix_tree_find_next_bit( - node->tags[tag], - RADIX_TREE_MAP_SIZE, - offset + 1); - else - while (++offset < RADIX_TREE_MAP_SIZE) { - void *slot = node->slots[offset]; - if (is_sibling_entry(node, slot)) - continue; - if (slot) - break; - } - index &= ~node_maxindex(node); - index += offset << node->shift; - /* Overflow after ~0UL */ - if (!index) - return NULL; - if (offset == RADIX_TREE_MAP_SIZE) - goto restart; - child = rcu_dereference_raw(node->slots[offset]); - } - - if ((child == NULL) || (child == RADIX_TREE_RETRY)) - goto restart; - } while (radix_tree_is_internal_node(child)); - - /* Update the iterator state */ - iter->index = (index &~ node_maxindex(node)) | (offset << node->shift); - iter->next_index = (index | node_maxindex(node)) + 1; - __set_iter_shift(iter, node->shift); - - /* Construct iter->tags bit-mask from node->tags[tag] array */ - if (flags & RADIX_TREE_ITER_TAGGED) { - unsigned tag_long, tag_bit; - - tag_long = offset / BITS_PER_LONG; - tag_bit = offset % BITS_PER_LONG; - iter->tags = node->tags[tag][tag_long] >> tag_bit; - /* This never happens if RADIX_TREE_TAG_LONGS == 1 */ - if (tag_long < RADIX_TREE_TAG_LONGS - 1) { - /* Pick tags from next element */ - if (tag_bit) - iter->tags |= node->tags[tag][tag_long + 1] << - (BITS_PER_LONG - tag_bit); - /* Clip chunk size, here only BITS_PER_LONG tags */ - iter->next_index = index + BITS_PER_LONG; - } - } - - return node->slots + offset; -} -EXPORT_SYMBOL(radix_tree_next_chunk); - -/** - * radix_tree_range_tag_if_tagged - for each item in given range set given - * tag if item has another tag set - * @root: radix tree root - * @first_indexp: pointer to a starting index of a range to scan - * @last_index: last index of a range to scan - * @nr_to_tag: maximum number items to tag - * @iftag: tag index to test - * @settag: tag index to set if tested tag is set - * - * This function scans range of radix tree from first_index to last_index - * (inclusive). For each item in the range if iftag is set, the function sets - * also settag. The function stops either after tagging nr_to_tag items or - * after reaching last_index. - * - * The tags must be set from the leaf level only and propagated back up the - * path to the root. We must do this so that we resolve the full path before - * setting any tags on intermediate nodes. If we set tags as we descend, then - * we can get to the leaf node and find that the index that has the iftag - * set is outside the range we are scanning. This reults in dangling tags and - * can lead to problems with later tag operations (e.g. livelocks on lookups). - * - * The function returns the number of leaves where the tag was set and sets - * *first_indexp to the first unscanned index. - * WARNING! *first_indexp can wrap if last_index is ULONG_MAX. Caller must - * be prepared to handle that. - */ -unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root, - unsigned long *first_indexp, unsigned long last_index, - unsigned long nr_to_tag, - unsigned int iftag, unsigned int settag) -{ - struct radix_tree_node *parent, *node, *child; - unsigned long maxindex; - unsigned long tagged = 0; - unsigned long index = *first_indexp; - - radix_tree_load_root(root, &child, &maxindex); - last_index = min(last_index, maxindex); - if (index > last_index) - return 0; - if (!nr_to_tag) - return 0; - if (!root_tag_get(root, iftag)) { - *first_indexp = last_index + 1; - return 0; - } - if (!radix_tree_is_internal_node(child)) { - *first_indexp = last_index + 1; - root_tag_set(root, settag); - return 1; - } - - node = entry_to_node(child); - - for (;;) { - unsigned offset = radix_tree_descend(node, &child, index); - if (!child) - goto next; - if (!tag_get(node, iftag, offset)) - goto next; - /* Sibling slots never have tags set on them */ - if (radix_tree_is_internal_node(child)) { - node = entry_to_node(child); - continue; - } - - /* tag the leaf */ - tagged++; - tag_set(node, settag, offset); - - /* walk back up the path tagging interior nodes */ - parent = node; - for (;;) { - offset = parent->offset; - parent = parent->parent; - if (!parent) - break; - /* stop if we find a node with the tag already set */ - if (tag_get(parent, settag, offset)) - break; - tag_set(parent, settag, offset); - } - next: - /* Go to next entry in node */ - index = ((index >> node->shift) + 1) << node->shift; - /* Overflow can happen when last_index is ~0UL... */ - if (index > last_index || !index) - break; - offset = (index >> node->shift) & RADIX_TREE_MAP_MASK; - while (offset == 0) { - /* - * We've fully scanned this node. Go up. Because - * last_index is guaranteed to be in the tree, what - * we do below cannot wander astray. - */ - node = node->parent; - offset = (index >> node->shift) & RADIX_TREE_MAP_MASK; - } - if (is_sibling_entry(node, node->slots[offset])) - goto next; - if (tagged >= nr_to_tag) - break; - } - /* - * We need not to tag the root tag if there is no tag which is set with - * settag within the range from *first_indexp to last_index. - */ - if (tagged > 0) - root_tag_set(root, settag); - *first_indexp = index; - - return tagged; -} -EXPORT_SYMBOL(radix_tree_range_tag_if_tagged); - -/** - * radix_tree_gang_lookup - perform multiple lookup on a radix tree - * @root: radix tree root - * @results: where the results of the lookup are placed - * @first_index: start the lookup from this key - * @max_items: place up to this many items at *results - * - * Performs an index-ascending scan of the tree for present items. Places - * them at *@results and returns the number of items which were placed at - * *@results. - * - * The implementation is naive. - * - * Like radix_tree_lookup, radix_tree_gang_lookup may be called under - * rcu_read_lock. In this case, rather than the returned results being - * an atomic snapshot of the tree at a single point in time, the - * semantics of an RCU protected gang lookup are as though multiple - * radix_tree_lookups have been issued in individual locks, and results - * stored in 'results'. - */ -unsigned int -radix_tree_gang_lookup(struct radix_tree_root *root, void **results, - unsigned long first_index, unsigned int max_items) -{ - struct radix_tree_iter iter; - void **slot; - unsigned int ret = 0; - - if (unlikely(!max_items)) - return 0; - - radix_tree_for_each_slot(slot, root, &iter, first_index) { - results[ret] = rcu_dereference_raw(*slot); - if (!results[ret]) - continue; - if (radix_tree_is_internal_node(results[ret])) { - slot = radix_tree_iter_retry(&iter); - continue; - } - if (++ret == max_items) - break; - } - - return ret; -} -EXPORT_SYMBOL(radix_tree_gang_lookup); - -/** - * radix_tree_gang_lookup_slot - perform multiple slot lookup on radix tree - * @root: radix tree root - * @results: where the results of the lookup are placed - * @indices: where their indices should be placed (but usually NULL) - * @first_index: start the lookup from this key - * @max_items: place up to this many items at *results - * - * Performs an index-ascending scan of the tree for present items. Places - * their slots at *@results and returns the number of items which were - * placed at *@results. - * - * The implementation is naive. - * - * Like radix_tree_gang_lookup as far as RCU and locking goes. Slots must - * be dereferenced with radix_tree_deref_slot, and if using only RCU - * protection, radix_tree_deref_slot may fail requiring a retry. - */ -unsigned int -radix_tree_gang_lookup_slot(struct radix_tree_root *root, - void ***results, unsigned long *indices, - unsigned long first_index, unsigned int max_items) -{ - struct radix_tree_iter iter; - void **slot; - unsigned int ret = 0; - - if (unlikely(!max_items)) - return 0; - - radix_tree_for_each_slot(slot, root, &iter, first_index) { - results[ret] = slot; - if (indices) - indices[ret] = iter.index; - if (++ret == max_items) - break; - } - - return ret; -} -EXPORT_SYMBOL(radix_tree_gang_lookup_slot); - -/** - * radix_tree_gang_lookup_tag - perform multiple lookup on a radix tree - * based on a tag - * @root: radix tree root - * @results: where the results of the lookup are placed - * @first_index: start the lookup from this key - * @max_items: place up to this many items at *results - * @tag: the tag index (< RADIX_TREE_MAX_TAGS) - * - * Performs an index-ascending scan of the tree for present items which - * have the tag indexed by @tag set. Places the items at *@results and - * returns the number of items which were placed at *@results. - */ -unsigned int -radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, - unsigned long first_index, unsigned int max_items, - unsigned int tag) -{ - struct radix_tree_iter iter; - void **slot; - unsigned int ret = 0; - - if (unlikely(!max_items)) - return 0; - - radix_tree_for_each_tagged(slot, root, &iter, first_index, tag) { - results[ret] = rcu_dereference_raw(*slot); - if (!results[ret]) - continue; - if (radix_tree_is_internal_node(results[ret])) { - slot = radix_tree_iter_retry(&iter); - continue; - } - if (++ret == max_items) - break; - } - - return ret; -} -EXPORT_SYMBOL(radix_tree_gang_lookup_tag); - -/** - * radix_tree_gang_lookup_tag_slot - perform multiple slot lookup on a - * radix tree based on a tag - * @root: radix tree root - * @results: where the results of the lookup are placed - * @first_index: start the lookup from this key - * @max_items: place up to this many items at *results - * @tag: the tag index (< RADIX_TREE_MAX_TAGS) - * - * Performs an index-ascending scan of the tree for present items which - * have the tag indexed by @tag set. Places the slots at *@results and - * returns the number of slots which were placed at *@results. - */ -unsigned int -radix_tree_gang_lookup_tag_slot(struct radix_tree_root *root, void ***results, - unsigned long first_index, unsigned int max_items, - unsigned int tag) -{ - struct radix_tree_iter iter; - void **slot; - unsigned int ret = 0; - - if (unlikely(!max_items)) - return 0; - - radix_tree_for_each_tagged(slot, root, &iter, first_index, tag) { - results[ret] = slot; - if (++ret == max_items) - break; - } - - return ret; -} -EXPORT_SYMBOL(radix_tree_gang_lookup_tag_slot); - -#if defined(CONFIG_SHMEM) && defined(CONFIG_SWAP) -#include /* for cond_resched() */ - -struct locate_info { - unsigned long found_index; - bool stop; -}; - -/* - * This linear search is at present only useful to shmem_unuse_inode(). - */ -static unsigned long __locate(struct radix_tree_node *slot, void *item, - unsigned long index, struct locate_info *info) -{ - unsigned long i; - - do { - unsigned int shift = slot->shift; - - for (i = (index >> shift) & RADIX_TREE_MAP_MASK; - i < RADIX_TREE_MAP_SIZE; - i++, index += (1UL << shift)) { - struct radix_tree_node *node = - rcu_dereference_raw(slot->slots[i]); - if (node == RADIX_TREE_RETRY) - goto out; - if (!radix_tree_is_internal_node(node)) { - if (node == item) { - info->found_index = index; - info->stop = true; - goto out; - } - continue; - } - node = entry_to_node(node); - if (is_sibling_entry(slot, node)) - continue; - slot = node; - break; - } - } while (i < RADIX_TREE_MAP_SIZE); - -out: - if ((index == 0) && (i == RADIX_TREE_MAP_SIZE)) - info->stop = true; - return index; -} - -/** - * radix_tree_locate_item - search through radix tree for item - * @root: radix tree root - * @item: item to be found - * - * Returns index where item was found, or -1 if not found. - * Caller must hold no lock (since this time-consuming function needs - * to be preemptible), and must check afterwards if item is still there. - */ -unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item) -{ - struct radix_tree_node *node; - unsigned long max_index; - unsigned long cur_index = 0; - struct locate_info info = { - .found_index = -1, - .stop = false, - }; - - do { - rcu_read_lock(); - node = rcu_dereference_raw(root->rnode); - if (!radix_tree_is_internal_node(node)) { - rcu_read_unlock(); - if (node == item) - info.found_index = 0; - break; - } - - node = entry_to_node(node); - - max_index = node_maxindex(node); - if (cur_index > max_index) { - rcu_read_unlock(); - break; - } - - cur_index = __locate(node, item, cur_index, &info); - rcu_read_unlock(); - cond_resched(); - } while (!info.stop && cur_index <= max_index); - - return info.found_index; -} -#else -unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item) -{ - return -1; -} -#endif /* CONFIG_SHMEM && CONFIG_SWAP */ - -/** - * radix_tree_shrink - shrink radix tree to minimum height - * @root radix tree root - */ -static inline bool radix_tree_shrink(struct radix_tree_root *root) -{ - bool shrunk = false; - - for (;;) { - struct radix_tree_node *node = root->rnode; - struct radix_tree_node *child; - - if (!radix_tree_is_internal_node(node)) - break; - node = entry_to_node(node); - - /* - * The candidate node has more than one child, or its child - * is not at the leftmost slot, or the child is a multiorder - * entry, we cannot shrink. - */ - if (node->count != 1) - break; - child = node->slots[0]; - if (!child) - break; - if (!radix_tree_is_internal_node(child) && node->shift) - break; - - if (radix_tree_is_internal_node(child)) - entry_to_node(child)->parent = NULL; - - /* - * We don't need rcu_assign_pointer(), since we are simply - * moving the node from one part of the tree to another: if it - * was safe to dereference the old pointer to it - * (node->slots[0]), it will be safe to dereference the new - * one (root->rnode) as far as dependent read barriers go. - */ - root->rnode = child; - - /* - * We have a dilemma here. The node's slot[0] must not be - * NULLed in case there are concurrent lookups expecting to - * find the item. However if this was a bottom-level node, - * then it may be subject to the slot pointer being visible - * to callers dereferencing it. If item corresponding to - * slot[0] is subsequently deleted, these callers would expect - * their slot to become empty sooner or later. - * - * For example, lockless pagecache will look up a slot, deref - * the page pointer, and if the page has 0 refcount it means it - * was concurrently deleted from pagecache so try the deref - * again. Fortunately there is already a requirement for logic - * to retry the entire slot lookup -- the indirect pointer - * problem (replacing direct root node with an indirect pointer - * also results in a stale slot). So tag the slot as indirect - * to force callers to retry. - */ - if (!radix_tree_is_internal_node(child)) - node->slots[0] = RADIX_TREE_RETRY; - - radix_tree_node_free(node); - shrunk = true; - } - - return shrunk; -} - -/** - * __radix_tree_delete_node - try to free node after clearing a slot - * @root: radix tree root - * @node: node containing @index - * - * After clearing the slot at @index in @node from radix tree - * rooted at @root, call this function to attempt freeing the - * node and shrinking the tree. - * - * Returns %true if @node was freed, %false otherwise. - */ -bool __radix_tree_delete_node(struct radix_tree_root *root, - struct radix_tree_node *node) -{ - bool deleted = false; - - do { - struct radix_tree_node *parent; - - if (node->count) { - if (node == entry_to_node(root->rnode)) - deleted |= radix_tree_shrink(root); - return deleted; - } - - parent = node->parent; - if (parent) { - parent->slots[node->offset] = NULL; - parent->count--; - } else { - root_tag_clear_all(root); - root->rnode = NULL; - } - - radix_tree_node_free(node); - deleted = true; - - node = parent; - } while (node); - - return deleted; -} - -static inline void delete_sibling_entries(struct radix_tree_node *node, - void *ptr, unsigned offset) -{ -#ifdef CONFIG_RADIX_TREE_MULTIORDER - int i; - for (i = 1; offset + i < RADIX_TREE_MAP_SIZE; i++) { - if (node->slots[offset + i] != ptr) - break; - node->slots[offset + i] = NULL; - node->count--; - } -#endif -} - -/** - * radix_tree_delete_item - delete an item from a radix tree - * @root: radix tree root - * @index: index key - * @item: expected item - * - * Remove @item at @index from the radix tree rooted at @root. - * - * Returns the address of the deleted item, or NULL if it was not present - * or the entry at the given @index was not @item. - */ -void *radix_tree_delete_item(struct radix_tree_root *root, - unsigned long index, void *item) -{ - struct radix_tree_node *node; - unsigned int offset; - void **slot; - void *entry; - int tag; - - entry = __radix_tree_lookup(root, index, &node, &slot); - if (!entry) - return NULL; - - if (item && entry != item) - return NULL; - - if (!node) { - root_tag_clear_all(root); - root->rnode = NULL; - return entry; - } - - offset = get_slot_offset(node, slot); - - /* Clear all tags associated with the item to be deleted. */ - for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) - node_tag_clear(root, node, tag, offset); - - delete_sibling_entries(node, node_to_entry(slot), offset); - node->slots[offset] = NULL; - node->count--; - - __radix_tree_delete_node(root, node); - - return entry; -} -EXPORT_SYMBOL(radix_tree_delete_item); - -/** - * radix_tree_delete - delete an item from a radix tree - * @root: radix tree root - * @index: index key - * - * Remove the item at @index from the radix tree rooted at @root. - * - * Returns the address of the deleted item, or NULL if it was not present. - */ -void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) -{ - return radix_tree_delete_item(root, index, NULL); -} -EXPORT_SYMBOL(radix_tree_delete); - -void radix_tree_clear_tags(struct radix_tree_root *root, - struct radix_tree_node *node, - void **slot) -{ - if (node) { - unsigned int tag, offset = get_slot_offset(node, slot); - for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) - node_tag_clear(root, node, tag, offset); - } else { - /* Clear root node tags */ - root->gfp_mask &= __GFP_BITS_MASK; - } -} - -/** - * radix_tree_tagged - test whether any items in the tree are tagged - * @root: radix tree root - * @tag: tag to test - */ -int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag) -{ - return root_tag_get(root, tag); -} -EXPORT_SYMBOL(radix_tree_tagged); - -static void -radix_tree_node_ctor(void *arg) -{ - struct radix_tree_node *node = arg; - - memset(node, 0, sizeof(*node)); - INIT_LIST_HEAD(&node->private_list); -} - -static __init unsigned long __maxindex(unsigned int height) -{ - unsigned int width = height * RADIX_TREE_MAP_SHIFT; - int shift = RADIX_TREE_INDEX_BITS - width; - - if (shift < 0) - return ~0UL; - if (shift >= BITS_PER_LONG) - return 0UL; - return ~0UL >> shift; -} - -static __init void radix_tree_init_maxnodes(void) -{ - unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH + 1]; - unsigned int i, j; - - for (i = 0; i < ARRAY_SIZE(height_to_maxindex); i++) - height_to_maxindex[i] = __maxindex(i); - for (i = 0; i < ARRAY_SIZE(height_to_maxnodes); i++) { - for (j = i; j > 0; j--) - height_to_maxnodes[i] += height_to_maxindex[j - 1] + 1; - } -} - -static int radix_tree_callback(struct notifier_block *nfb, - unsigned long action, void *hcpu) -{ - int cpu = (long)hcpu; - struct radix_tree_preload *rtp; - struct radix_tree_node *node; - - /* Free per-cpu pool of preloaded nodes */ - if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) { - rtp = &per_cpu(radix_tree_preloads, cpu); - while (rtp->nr) { - node = rtp->nodes; - rtp->nodes = node->private_data; - kmem_cache_free(radix_tree_node_cachep, node); - rtp->nr--; - } - } - return NOTIFY_OK; -} - -void __init radix_tree_init(void) -{ - radix_tree_node_cachep = kmem_cache_create("radix_tree_node", - sizeof(struct radix_tree_node), 0, - SLAB_PANIC | SLAB_RECLAIM_ACCOUNT, - radix_tree_node_ctor); - radix_tree_init_maxnodes(); - hotcpu_notifier(radix_tree_callback, 0); -} diff --git a/src/linux/lib/raid6/.gitignore b/src/linux/lib/raid6/.gitignore deleted file mode 100644 index c2ab725..0000000 --- a/src/linux/lib/raid6/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -mktables -mktables.exe -altivec*.c -int*.c -tables.c -neon?.c -s390vx?.c diff --git a/src/linux/lib/raid6/Makefile b/src/linux/lib/raid6/Makefile deleted file mode 100644 index 3057011..0000000 --- a/src/linux/lib/raid6/Makefile +++ /dev/null @@ -1,130 +0,0 @@ -obj-$(CONFIG_RAID6_PQ) += raid6_pq.o - -raid6_pq-y += algos.o recov.o tables.o int1.o int2.o int4.o \ - int8.o int16.o int32.o - -raid6_pq-$(CONFIG_X86) += recov_ssse3.o recov_avx2.o mmx.o sse1.o sse2.o avx2.o avx512.o recov_avx512.o -raid6_pq-$(CONFIG_ALTIVEC) += altivec1.o altivec2.o altivec4.o altivec8.o -raid6_pq-$(CONFIG_KERNEL_MODE_NEON) += neon.o neon1.o neon2.o neon4.o neon8.o -raid6_pq-$(CONFIG_TILEGX) += tilegx8.o -raid6_pq-$(CONFIG_S390) += s390vx8.o recov_s390xc.o - -hostprogs-y += mktables - -quiet_cmd_unroll = UNROLL $@ - cmd_unroll = $(AWK) -f$(srctree)/$(src)/unroll.awk -vN=$(UNROLL) \ - < $< > $@ || ( rm -f $@ && exit 1 ) - -ifeq ($(CONFIG_ALTIVEC),y) -altivec_flags := -maltivec $(call cc-option,-mabi=altivec) -endif - -# The GCC option -ffreestanding is required in order to compile code containing -# ARM/NEON intrinsics in a non C99-compliant environment (such as the kernel) -ifeq ($(CONFIG_KERNEL_MODE_NEON),y) -NEON_FLAGS := -ffreestanding -ifeq ($(ARCH),arm) -NEON_FLAGS += -mfloat-abi=softfp -mfpu=neon -endif -ifeq ($(ARCH),arm64) -CFLAGS_REMOVE_neon1.o += -mgeneral-regs-only -CFLAGS_REMOVE_neon2.o += -mgeneral-regs-only -CFLAGS_REMOVE_neon4.o += -mgeneral-regs-only -CFLAGS_REMOVE_neon8.o += -mgeneral-regs-only -endif -endif - -targets += int1.c -$(obj)/int1.c: UNROLL := 1 -$(obj)/int1.c: $(src)/int.uc $(src)/unroll.awk FORCE - $(call if_changed,unroll) - -targets += int2.c -$(obj)/int2.c: UNROLL := 2 -$(obj)/int2.c: $(src)/int.uc $(src)/unroll.awk FORCE - $(call if_changed,unroll) - -targets += int4.c -$(obj)/int4.c: UNROLL := 4 -$(obj)/int4.c: $(src)/int.uc $(src)/unroll.awk FORCE - $(call if_changed,unroll) - -targets += int8.c -$(obj)/int8.c: UNROLL := 8 -$(obj)/int8.c: $(src)/int.uc $(src)/unroll.awk FORCE - $(call if_changed,unroll) - -targets += int16.c -$(obj)/int16.c: UNROLL := 16 -$(obj)/int16.c: $(src)/int.uc $(src)/unroll.awk FORCE - $(call if_changed,unroll) - -targets += int32.c -$(obj)/int32.c: UNROLL := 32 -$(obj)/int32.c: $(src)/int.uc $(src)/unroll.awk FORCE - $(call if_changed,unroll) - -CFLAGS_altivec1.o += $(altivec_flags) -targets += altivec1.c -$(obj)/altivec1.c: UNROLL := 1 -$(obj)/altivec1.c: $(src)/altivec.uc $(src)/unroll.awk FORCE - $(call if_changed,unroll) - -CFLAGS_altivec2.o += $(altivec_flags) -targets += altivec2.c -$(obj)/altivec2.c: UNROLL := 2 -$(obj)/altivec2.c: $(src)/altivec.uc $(src)/unroll.awk FORCE - $(call if_changed,unroll) - -CFLAGS_altivec4.o += $(altivec_flags) -targets += altivec4.c -$(obj)/altivec4.c: UNROLL := 4 -$(obj)/altivec4.c: $(src)/altivec.uc $(src)/unroll.awk FORCE - $(call if_changed,unroll) - -CFLAGS_altivec8.o += $(altivec_flags) -targets += altivec8.c -$(obj)/altivec8.c: UNROLL := 8 -$(obj)/altivec8.c: $(src)/altivec.uc $(src)/unroll.awk FORCE - $(call if_changed,unroll) - -CFLAGS_neon1.o += $(NEON_FLAGS) -targets += neon1.c -$(obj)/neon1.c: UNROLL := 1 -$(obj)/neon1.c: $(src)/neon.uc $(src)/unroll.awk FORCE - $(call if_changed,unroll) - -CFLAGS_neon2.o += $(NEON_FLAGS) -targets += neon2.c -$(obj)/neon2.c: UNROLL := 2 -$(obj)/neon2.c: $(src)/neon.uc $(src)/unroll.awk FORCE - $(call if_changed,unroll) - -CFLAGS_neon4.o += $(NEON_FLAGS) -targets += neon4.c -$(obj)/neon4.c: UNROLL := 4 -$(obj)/neon4.c: $(src)/neon.uc $(src)/unroll.awk FORCE - $(call if_changed,unroll) - -CFLAGS_neon8.o += $(NEON_FLAGS) -targets += neon8.c -$(obj)/neon8.c: UNROLL := 8 -$(obj)/neon8.c: $(src)/neon.uc $(src)/unroll.awk FORCE - $(call if_changed,unroll) - -targets += tilegx8.c -$(obj)/tilegx8.c: UNROLL := 8 -$(obj)/tilegx8.c: $(src)/tilegx.uc $(src)/unroll.awk FORCE - $(call if_changed,unroll) - -targets += s390vx8.c -$(obj)/s390vx8.c: UNROLL := 8 -$(obj)/s390vx8.c: $(src)/s390vx.uc $(src)/unroll.awk FORCE - $(call if_changed,unroll) - -quiet_cmd_mktable = TABLE $@ - cmd_mktable = $(obj)/mktables > $@ || ( rm -f $@ && exit 1 ) - -targets += tables.c -$(obj)/tables.c: $(obj)/mktables FORCE - $(call if_changed,mktable) diff --git a/src/linux/lib/raid6/algos.c b/src/linux/lib/raid6/algos.c deleted file mode 100644 index c829133..0000000 --- a/src/linux/lib/raid6/algos.c +++ /dev/null @@ -1,271 +0,0 @@ -/* -*- linux-c -*- ------------------------------------------------------- * - * - * Copyright 2002 H. Peter Anvin - All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, Inc., 53 Temple Place Ste 330, - * Boston MA 02111-1307, USA; either version 2 of the License, or - * (at your option) any later version; incorporated herein by reference. - * - * ----------------------------------------------------------------------- */ - -/* - * raid6/algos.c - * - * Algorithm list and algorithm selection for RAID-6 - */ - -#include -#ifndef __KERNEL__ -#include -#include -#else -#include -#include -#include -#if !RAID6_USE_EMPTY_ZERO_PAGE -/* In .bss so it's zeroed */ -const char raid6_empty_zero_page[PAGE_SIZE] __attribute__((aligned(256))); -EXPORT_SYMBOL(raid6_empty_zero_page); -#endif -#endif - -struct raid6_calls raid6_call; -EXPORT_SYMBOL_GPL(raid6_call); - -const struct raid6_calls * const raid6_algos[] = { -#ifdef CONFIG_IA64 - &raid6_intx16, - &raid6_intx32, -#endif -#ifdef CONFIG_X86_32 - &raid6_mmxx1, - &raid6_mmxx2, - &raid6_sse1x1, - &raid6_sse1x2, - &raid6_sse2x1, - &raid6_sse2x2, -#ifdef CONFIG_AS_AVX2 - &raid6_avx2x1, - &raid6_avx2x2, -#endif -#ifdef CONFIG_AS_AVX512 - &raid6_avx512x1, - &raid6_avx512x2, -#endif -#endif -#ifdef CONFIG_X86_64 - &raid6_sse2x1, - &raid6_sse2x2, - &raid6_sse2x4, -#ifdef CONFIG_AS_AVX2 - &raid6_avx2x1, - &raid6_avx2x2, - &raid6_avx2x4, -#endif -#ifdef CONFIG_AS_AVX512 - &raid6_avx512x1, - &raid6_avx512x2, - &raid6_avx512x4, -#endif -#endif -#ifdef CONFIG_ALTIVEC - &raid6_altivec1, - &raid6_altivec2, - &raid6_altivec4, - &raid6_altivec8, -#endif -#if defined(CONFIG_TILEGX) - &raid6_tilegx8, -#endif -#if defined(CONFIG_S390) - &raid6_s390vx8, -#endif - &raid6_intx1, - &raid6_intx2, - &raid6_intx4, - &raid6_intx8, -#ifdef CONFIG_KERNEL_MODE_NEON - &raid6_neonx1, - &raid6_neonx2, - &raid6_neonx4, - &raid6_neonx8, -#endif - NULL -}; - -void (*raid6_2data_recov)(int, size_t, int, int, void **); -EXPORT_SYMBOL_GPL(raid6_2data_recov); - -void (*raid6_datap_recov)(int, size_t, int, void **); -EXPORT_SYMBOL_GPL(raid6_datap_recov); - -const struct raid6_recov_calls *const raid6_recov_algos[] = { -#ifdef CONFIG_AS_AVX512 - &raid6_recov_avx512, -#endif -#ifdef CONFIG_AS_AVX2 - &raid6_recov_avx2, -#endif -#ifdef CONFIG_AS_SSSE3 - &raid6_recov_ssse3, -#endif -#ifdef CONFIG_S390 - &raid6_recov_s390xc, -#endif - &raid6_recov_intx1, - NULL -}; - -#ifdef __KERNEL__ -#define RAID6_TIME_JIFFIES_LG2 4 -#else -/* Need more time to be stable in userspace */ -#define RAID6_TIME_JIFFIES_LG2 9 -#define time_before(x, y) ((x) < (y)) -#endif - -static inline const struct raid6_recov_calls *raid6_choose_recov(void) -{ - const struct raid6_recov_calls *const *algo; - const struct raid6_recov_calls *best; - - for (best = NULL, algo = raid6_recov_algos; *algo; algo++) - if (!best || (*algo)->priority > best->priority) - if (!(*algo)->valid || (*algo)->valid()) - best = *algo; - - if (best) { - raid6_2data_recov = best->data2; - raid6_datap_recov = best->datap; - - pr_info("raid6: using %s recovery algorithm\n", best->name); - } else - pr_err("raid6: Yikes! No recovery algorithm found!\n"); - - return best; -} - -static inline const struct raid6_calls *raid6_choose_gen( - void *(*const dptrs)[(65536/PAGE_SIZE)+2], const int disks) -{ - unsigned long perf, bestgenperf, bestxorperf, j0, j1; - int start = (disks>>1)-1, stop = disks-3; /* work on the second half of the disks */ - const struct raid6_calls *const *algo; - const struct raid6_calls *best; - - for (bestgenperf = 0, bestxorperf = 0, best = NULL, algo = raid6_algos; *algo; algo++) { - if (!best || (*algo)->prefer >= best->prefer) { - if ((*algo)->valid && !(*algo)->valid()) - continue; - - perf = 0; - - preempt_disable(); - j0 = jiffies; - while ((j1 = jiffies) == j0) - cpu_relax(); - while (time_before(jiffies, - j1 + (1<gen_syndrome(disks, PAGE_SIZE, *dptrs); - perf++; - cpu_yield_to_irqs(); - } - preempt_enable(); - - if (perf > bestgenperf) { - bestgenperf = perf; - best = *algo; - } - pr_info("raid6: %-8s gen() %5ld MB/s\n", (*algo)->name, - (perf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2)); - - if (!(*algo)->xor_syndrome) - continue; - - perf = 0; - - preempt_disable(); - j0 = jiffies; - while ((j1 = jiffies) == j0) - cpu_relax(); - while (time_before(jiffies, - j1 + (1<xor_syndrome(disks, start, stop, - PAGE_SIZE, *dptrs); - perf++; - cpu_yield_to_irqs(); - } - preempt_enable(); - - if (best == *algo) - bestxorperf = perf; - - pr_info("raid6: %-8s xor() %5ld MB/s\n", (*algo)->name, - (perf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2+1)); - } - } - - if (best) { - pr_info("raid6: using algorithm %s gen() %ld MB/s\n", - best->name, - (bestgenperf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2)); - if (best->xor_syndrome) - pr_info("raid6: .... xor() %ld MB/s, rmw enabled\n", - (bestxorperf*HZ) >> (20-16+RAID6_TIME_JIFFIES_LG2+1)); - raid6_call = *best; - } else - pr_err("raid6: Yikes! No algorithm found!\n"); - - return best; -} - - -/* Try to pick the best algorithm */ -/* This code uses the gfmul table as convenient data set to abuse */ - -int __init raid6_select_algo(void) -{ - const int disks = (65536/PAGE_SIZE)+2; - - const struct raid6_calls *gen_best; - const struct raid6_recov_calls *rec_best; - char *syndromes; - void *dptrs[(65536/PAGE_SIZE)+2]; - int i; - - for (i = 0; i < disks-2; i++) - dptrs[i] = ((char *)raid6_gfmul) + PAGE_SIZE*i; - - /* Normal code - use a 2-page allocation to avoid D$ conflict */ - syndromes = (void *) __get_free_pages(GFP_KERNEL, 1); - - if (!syndromes) { - pr_err("raid6: Yikes! No memory available.\n"); - return -ENOMEM; - } - - dptrs[disks-2] = syndromes; - dptrs[disks-1] = syndromes + PAGE_SIZE; - - /* select raid gen_syndrome function */ - gen_best = raid6_choose_gen(&dptrs, disks); - - /* select raid recover functions */ - rec_best = raid6_choose_recov(); - - free_pages((unsigned long)syndromes, 1); - - return gen_best && rec_best ? 0 : -EINVAL; -} - -static void raid6_exit(void) -{ - do { } while (0); -} - -subsys_initcall(raid6_select_algo); -module_exit(raid6_exit); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("RAID6 Q-syndrome calculations"); diff --git a/src/linux/lib/raid6/int.uc b/src/linux/lib/raid6/int.uc deleted file mode 100644 index 558aeac..0000000 --- a/src/linux/lib/raid6/int.uc +++ /dev/null @@ -1,156 +0,0 @@ -/* -*- linux-c -*- ------------------------------------------------------- * - * - * Copyright 2002-2004 H. Peter Anvin - All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, Inc., 53 Temple Place Ste 330, - * Boston MA 02111-1307, USA; either version 2 of the License, or - * (at your option) any later version; incorporated herein by reference. - * - * ----------------------------------------------------------------------- */ - -/* - * int$#.c - * - * $#-way unrolled portable integer math RAID-6 instruction set - * - * This file is postprocessed using unroll.awk - */ - -#include - -/* - * This is the C data type to use - */ - -/* Change this from BITS_PER_LONG if there is something better... */ -#if BITS_PER_LONG == 64 -# define NBYTES(x) ((x) * 0x0101010101010101UL) -# define NSIZE 8 -# define NSHIFT 3 -# define NSTRING "64" -typedef u64 unative_t; -#else -# define NBYTES(x) ((x) * 0x01010101U) -# define NSIZE 4 -# define NSHIFT 2 -# define NSTRING "32" -typedef u32 unative_t; -#endif - - - -/* - * IA-64 wants insane amounts of unrolling. On other architectures that - * is just a waste of space. - */ -#if ($# <= 8) || defined(__ia64__) - - -/* - * These sub-operations are separate inlines since they can sometimes be - * specially optimized using architecture-specific hacks. - */ - -/* - * The SHLBYTE() operation shifts each byte left by 1, *not* - * rolling over into the next byte - */ -static inline __attribute_const__ unative_t SHLBYTE(unative_t v) -{ - unative_t vv; - - vv = (v << 1) & NBYTES(0xfe); - return vv; -} - -/* - * The MASK() operation returns 0xFF in any byte for which the high - * bit is 1, 0x00 for any byte for which the high bit is 0. - */ -static inline __attribute_const__ unative_t MASK(unative_t v) -{ - unative_t vv; - - vv = v & NBYTES(0x80); - vv = (vv << 1) - (vv >> 7); /* Overflow on the top bit is OK */ - return vv; -} - - -static void raid6_int$#_gen_syndrome(int disks, size_t bytes, void **ptrs) -{ - u8 **dptr = (u8 **)ptrs; - u8 *p, *q; - int d, z, z0; - - unative_t wd$$, wq$$, wp$$, w1$$, w2$$; - - z0 = disks - 3; /* Highest data disk */ - p = dptr[z0+1]; /* XOR parity */ - q = dptr[z0+2]; /* RS syndrome */ - - for ( d = 0 ; d < bytes ; d += NSIZE*$# ) { - wq$$ = wp$$ = *(unative_t *)&dptr[z0][d+$$*NSIZE]; - for ( z = z0-1 ; z >= 0 ; z-- ) { - wd$$ = *(unative_t *)&dptr[z][d+$$*NSIZE]; - wp$$ ^= wd$$; - w2$$ = MASK(wq$$); - w1$$ = SHLBYTE(wq$$); - w2$$ &= NBYTES(0x1d); - w1$$ ^= w2$$; - wq$$ = w1$$ ^ wd$$; - } - *(unative_t *)&p[d+NSIZE*$$] = wp$$; - *(unative_t *)&q[d+NSIZE*$$] = wq$$; - } -} - -static void raid6_int$#_xor_syndrome(int disks, int start, int stop, - size_t bytes, void **ptrs) -{ - u8 **dptr = (u8 **)ptrs; - u8 *p, *q; - int d, z, z0; - - unative_t wd$$, wq$$, wp$$, w1$$, w2$$; - - z0 = stop; /* P/Q right side optimization */ - p = dptr[disks-2]; /* XOR parity */ - q = dptr[disks-1]; /* RS syndrome */ - - for ( d = 0 ; d < bytes ; d += NSIZE*$# ) { - /* P/Q data pages */ - wq$$ = wp$$ = *(unative_t *)&dptr[z0][d+$$*NSIZE]; - for ( z = z0-1 ; z >= start ; z-- ) { - wd$$ = *(unative_t *)&dptr[z][d+$$*NSIZE]; - wp$$ ^= wd$$; - w2$$ = MASK(wq$$); - w1$$ = SHLBYTE(wq$$); - w2$$ &= NBYTES(0x1d); - w1$$ ^= w2$$; - wq$$ = w1$$ ^ wd$$; - } - /* P/Q left side optimization */ - for ( z = start-1 ; z >= 0 ; z-- ) { - w2$$ = MASK(wq$$); - w1$$ = SHLBYTE(wq$$); - w2$$ &= NBYTES(0x1d); - wq$$ = w1$$ ^ w2$$; - } - *(unative_t *)&p[d+NSIZE*$$] ^= wp$$; - *(unative_t *)&q[d+NSIZE*$$] ^= wq$$; - } - -} - -const struct raid6_calls raid6_intx$# = { - raid6_int$#_gen_syndrome, - raid6_int$#_xor_syndrome, - NULL, /* always valid */ - "int" NSTRING "x$#", - 0 -}; - -#endif diff --git a/src/linux/lib/raid6/mktables.c b/src/linux/lib/raid6/mktables.c deleted file mode 100644 index 39787db..0000000 --- a/src/linux/lib/raid6/mktables.c +++ /dev/null @@ -1,158 +0,0 @@ -/* -*- linux-c -*- ------------------------------------------------------- * - * - * Copyright 2002-2007 H. Peter Anvin - All Rights Reserved - * - * This file is part of the Linux kernel, and is made available under - * the terms of the GNU General Public License version 2 or (at your - * option) any later version; incorporated herein by reference. - * - * ----------------------------------------------------------------------- */ - -/* - * mktables.c - * - * Make RAID-6 tables. This is a host user space program to be run at - * compile time. - */ - -#include -#include -#include -#include -#include - -static uint8_t gfmul(uint8_t a, uint8_t b) -{ - uint8_t v = 0; - - while (b) { - if (b & 1) - v ^= a; - a = (a << 1) ^ (a & 0x80 ? 0x1d : 0); - b >>= 1; - } - - return v; -} - -static uint8_t gfpow(uint8_t a, int b) -{ - uint8_t v = 1; - - b %= 255; - if (b < 0) - b += 255; - - while (b) { - if (b & 1) - v = gfmul(v, a); - a = gfmul(a, a); - b >>= 1; - } - - return v; -} - -int main(int argc, char *argv[]) -{ - int i, j, k; - uint8_t v; - uint8_t exptbl[256], invtbl[256]; - - printf("#include \n"); - printf("#include \n"); - - /* Compute multiplication table */ - printf("\nconst u8 __attribute__((aligned(256)))\n" - "raid6_gfmul[256][256] =\n" - "{\n"); - for (i = 0; i < 256; i++) { - printf("\t{\n"); - for (j = 0; j < 256; j += 8) { - printf("\t\t"); - for (k = 0; k < 8; k++) - printf("0x%02x,%c", gfmul(i, j + k), - (k == 7) ? '\n' : ' '); - } - printf("\t},\n"); - } - printf("};\n"); - printf("#ifdef __KERNEL__\n"); - printf("EXPORT_SYMBOL(raid6_gfmul);\n"); - printf("#endif\n"); - - /* Compute vector multiplication table */ - printf("\nconst u8 __attribute__((aligned(256)))\n" - "raid6_vgfmul[256][32] =\n" - "{\n"); - for (i = 0; i < 256; i++) { - printf("\t{\n"); - for (j = 0; j < 16; j += 8) { - printf("\t\t"); - for (k = 0; k < 8; k++) - printf("0x%02x,%c", gfmul(i, j + k), - (k == 7) ? '\n' : ' '); - } - for (j = 0; j < 16; j += 8) { - printf("\t\t"); - for (k = 0; k < 8; k++) - printf("0x%02x,%c", gfmul(i, (j + k) << 4), - (k == 7) ? '\n' : ' '); - } - printf("\t},\n"); - } - printf("};\n"); - printf("#ifdef __KERNEL__\n"); - printf("EXPORT_SYMBOL(raid6_vgfmul);\n"); - printf("#endif\n"); - - /* Compute power-of-2 table (exponent) */ - v = 1; - printf("\nconst u8 __attribute__((aligned(256)))\n" - "raid6_gfexp[256] =\n" "{\n"); - for (i = 0; i < 256; i += 8) { - printf("\t"); - for (j = 0; j < 8; j++) { - exptbl[i + j] = v; - printf("0x%02x,%c", v, (j == 7) ? '\n' : ' '); - v = gfmul(v, 2); - if (v == 1) - v = 0; /* For entry 255, not a real entry */ - } - } - printf("};\n"); - printf("#ifdef __KERNEL__\n"); - printf("EXPORT_SYMBOL(raid6_gfexp);\n"); - printf("#endif\n"); - - /* Compute inverse table x^-1 == x^254 */ - printf("\nconst u8 __attribute__((aligned(256)))\n" - "raid6_gfinv[256] =\n" "{\n"); - for (i = 0; i < 256; i += 8) { - printf("\t"); - for (j = 0; j < 8; j++) { - invtbl[i + j] = v = gfpow(i + j, 254); - printf("0x%02x,%c", v, (j == 7) ? '\n' : ' '); - } - } - printf("};\n"); - printf("#ifdef __KERNEL__\n"); - printf("EXPORT_SYMBOL(raid6_gfinv);\n"); - printf("#endif\n"); - - /* Compute inv(2^x + 1) (exponent-xor-inverse) table */ - printf("\nconst u8 __attribute__((aligned(256)))\n" - "raid6_gfexi[256] =\n" "{\n"); - for (i = 0; i < 256; i += 8) { - printf("\t"); - for (j = 0; j < 8; j++) - printf("0x%02x,%c", invtbl[exptbl[i + j] ^ 1], - (j == 7) ? '\n' : ' '); - } - printf("};\n"); - printf("#ifdef __KERNEL__\n"); - printf("EXPORT_SYMBOL(raid6_gfexi);\n"); - printf("#endif\n"); - - return 0; -} diff --git a/src/linux/lib/raid6/recov.c b/src/linux/lib/raid6/recov.c deleted file mode 100644 index a95bccb..0000000 --- a/src/linux/lib/raid6/recov.c +++ /dev/null @@ -1,141 +0,0 @@ -/* -*- linux-c -*- ------------------------------------------------------- * - * - * Copyright 2002 H. Peter Anvin - All Rights Reserved - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, Inc., 53 Temple Place Ste 330, - * Boston MA 02111-1307, USA; either version 2 of the License, or - * (at your option) any later version; incorporated herein by reference. - * - * ----------------------------------------------------------------------- */ - -/* - * raid6/recov.c - * - * RAID-6 data recovery in dual failure mode. In single failure mode, - * use the RAID-5 algorithm (or, in the case of Q failure, just reconstruct - * the syndrome.) - */ - -#include -#include - -/* Recover two failed data blocks. */ -static void raid6_2data_recov_intx1(int disks, size_t bytes, int faila, - int failb, void **ptrs) -{ - u8 *p, *q, *dp, *dq; - u8 px, qx, db; - const u8 *pbmul; /* P multiplier table for B data */ - const u8 *qmul; /* Q multiplier table (for both) */ - - p = (u8 *)ptrs[disks-2]; - q = (u8 *)ptrs[disks-1]; - - /* Compute syndrome with zero for the missing data pages - Use the dead data pages as temporary storage for - delta p and delta q */ - dp = (u8 *)ptrs[faila]; - ptrs[faila] = (void *)raid6_empty_zero_page; - ptrs[disks-2] = dp; - dq = (u8 *)ptrs[failb]; - ptrs[failb] = (void *)raid6_empty_zero_page; - ptrs[disks-1] = dq; - - raid6_call.gen_syndrome(disks, bytes, ptrs); - - /* Restore pointer table */ - ptrs[faila] = dp; - ptrs[failb] = dq; - ptrs[disks-2] = p; - ptrs[disks-1] = q; - - /* Now, pick the proper data tables */ - pbmul = raid6_gfmul[raid6_gfexi[failb-faila]]; - qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]^raid6_gfexp[failb]]]; - - /* Now do it... */ - while ( bytes-- ) { - px = *p ^ *dp; - qx = qmul[*q ^ *dq]; - *dq++ = db = pbmul[px] ^ qx; /* Reconstructed B */ - *dp++ = db ^ px; /* Reconstructed A */ - p++; q++; - } -} - -/* Recover failure of one data block plus the P block */ -static void raid6_datap_recov_intx1(int disks, size_t bytes, int faila, - void **ptrs) -{ - u8 *p, *q, *dq; - const u8 *qmul; /* Q multiplier table */ - - p = (u8 *)ptrs[disks-2]; - q = (u8 *)ptrs[disks-1]; - - /* Compute syndrome with zero for the missing data page - Use the dead data page as temporary storage for delta q */ - dq = (u8 *)ptrs[faila]; - ptrs[faila] = (void *)raid6_empty_zero_page; - ptrs[disks-1] = dq; - - raid6_call.gen_syndrome(disks, bytes, ptrs); - - /* Restore pointer table */ - ptrs[faila] = dq; - ptrs[disks-1] = q; - - /* Now, pick the proper data tables */ - qmul = raid6_gfmul[raid6_gfinv[raid6_gfexp[faila]]]; - - /* Now do it... */ - while ( bytes-- ) { - *p++ ^= *dq = qmul[*q ^ *dq]; - q++; dq++; - } -} - - -const struct raid6_recov_calls raid6_recov_intx1 = { - .data2 = raid6_2data_recov_intx1, - .datap = raid6_datap_recov_intx1, - .valid = NULL, - .name = "intx1", - .priority = 0, -}; - -#ifndef __KERNEL__ -/* Testing only */ - -/* Recover two failed blocks. */ -void raid6_dual_recov(int disks, size_t bytes, int faila, int failb, void **ptrs) -{ - if ( faila > failb ) { - int tmp = faila; - faila = failb; - failb = tmp; - } - - if ( failb == disks-1 ) { - if ( faila == disks-2 ) { - /* P+Q failure. Just rebuild the syndrome. */ - raid6_call.gen_syndrome(disks, bytes, ptrs); - } else { - /* data+Q failure. Reconstruct data from P, - then rebuild syndrome. */ - /* NOT IMPLEMENTED - equivalent to RAID-5 */ - } - } else { - if ( failb == disks-2 ) { - /* data+P failure. */ - raid6_datap_recov(disks, bytes, faila, ptrs); - } else { - /* data+data failure. */ - raid6_2data_recov(disks, bytes, faila, failb, ptrs); - } - } -} - -#endif diff --git a/src/linux/lib/raid6/unroll.awk b/src/linux/lib/raid6/unroll.awk deleted file mode 100644 index c6aa036..0000000 --- a/src/linux/lib/raid6/unroll.awk +++ /dev/null @@ -1,20 +0,0 @@ - -# This filter requires one command line option of form -vN=n -# where n must be a decimal number. -# -# Repeat each input line containing $$ n times, replacing $$ with 0...n-1. -# Replace each $# with n, and each $* with a single $. - -BEGIN { - n = N + 0 -} -{ - if (/\$\$/) { rep = n } else { rep = 1 } - for (i = 0; i < rep; ++i) { - tmp = $0 - gsub(/\$\$/, i, tmp) - gsub(/\$\#/, n, tmp) - gsub(/\$\*/, "$", tmp) - print tmp - } -} diff --git a/src/linux/lib/random32.c b/src/linux/lib/random32.c deleted file mode 100644 index fa594b1..0000000 --- a/src/linux/lib/random32.c +++ /dev/null @@ -1,464 +0,0 @@ -/* - * This is a maximally equidistributed combined Tausworthe generator - * based on code from GNU Scientific Library 1.5 (30 Jun 2004) - * - * lfsr113 version: - * - * x_n = (s1_n ^ s2_n ^ s3_n ^ s4_n) - * - * s1_{n+1} = (((s1_n & 4294967294) << 18) ^ (((s1_n << 6) ^ s1_n) >> 13)) - * s2_{n+1} = (((s2_n & 4294967288) << 2) ^ (((s2_n << 2) ^ s2_n) >> 27)) - * s3_{n+1} = (((s3_n & 4294967280) << 7) ^ (((s3_n << 13) ^ s3_n) >> 21)) - * s4_{n+1} = (((s4_n & 4294967168) << 13) ^ (((s4_n << 3) ^ s4_n) >> 12)) - * - * The period of this generator is about 2^113 (see erratum paper). - * - * From: P. L'Ecuyer, "Maximally Equidistributed Combined Tausworthe - * Generators", Mathematics of Computation, 65, 213 (1996), 203--213: - * http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme.ps - * ftp://ftp.iro.umontreal.ca/pub/simulation/lecuyer/papers/tausme.ps - * - * There is an erratum in the paper "Tables of Maximally Equidistributed - * Combined LFSR Generators", Mathematics of Computation, 68, 225 (1999), - * 261--269: http://www.iro.umontreal.ca/~lecuyer/myftp/papers/tausme2.ps - * - * ... the k_j most significant bits of z_j must be non-zero, - * for each j. (Note: this restriction also applies to the - * computer code given in [4], but was mistakenly not mentioned - * in that paper.) - * - * This affects the seeding procedure by imposing the requirement - * s1 > 1, s2 > 7, s3 > 15, s4 > 127. - */ - -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_RANDOM32_SELFTEST -static void __init prandom_state_selftest(void); -#else -static inline void prandom_state_selftest(void) -{ -} -#endif - -static DEFINE_PER_CPU(struct rnd_state, net_rand_state) __latent_entropy; - -/** - * prandom_u32_state - seeded pseudo-random number generator. - * @state: pointer to state structure holding seeded state. - * - * This is used for pseudo-randomness with no outside seeding. - * For more random results, use prandom_u32(). - */ -u32 prandom_u32_state(struct rnd_state *state) -{ -#define TAUSWORTHE(s, a, b, c, d) ((s & c) << d) ^ (((s << a) ^ s) >> b) - state->s1 = TAUSWORTHE(state->s1, 6U, 13U, 4294967294U, 18U); - state->s2 = TAUSWORTHE(state->s2, 2U, 27U, 4294967288U, 2U); - state->s3 = TAUSWORTHE(state->s3, 13U, 21U, 4294967280U, 7U); - state->s4 = TAUSWORTHE(state->s4, 3U, 12U, 4294967168U, 13U); - - return (state->s1 ^ state->s2 ^ state->s3 ^ state->s4); -} -EXPORT_SYMBOL(prandom_u32_state); - -/** - * prandom_u32 - pseudo random number generator - * - * A 32 bit pseudo-random number is generated using a fast - * algorithm suitable for simulation. This algorithm is NOT - * considered safe for cryptographic use. - */ -u32 prandom_u32(void) -{ - struct rnd_state *state = &get_cpu_var(net_rand_state); - u32 res; - - res = prandom_u32_state(state); - put_cpu_var(net_rand_state); - - return res; -} -EXPORT_SYMBOL(prandom_u32); - -/** - * prandom_bytes_state - get the requested number of pseudo-random bytes - * - * @state: pointer to state structure holding seeded state. - * @buf: where to copy the pseudo-random bytes to - * @bytes: the requested number of bytes - * - * This is used for pseudo-randomness with no outside seeding. - * For more random results, use prandom_bytes(). - */ -void prandom_bytes_state(struct rnd_state *state, void *buf, size_t bytes) -{ - u8 *ptr = buf; - - while (bytes >= sizeof(u32)) { - put_unaligned(prandom_u32_state(state), (u32 *) ptr); - ptr += sizeof(u32); - bytes -= sizeof(u32); - } - - if (bytes > 0) { - u32 rem = prandom_u32_state(state); - do { - *ptr++ = (u8) rem; - bytes--; - rem >>= BITS_PER_BYTE; - } while (bytes > 0); - } -} -EXPORT_SYMBOL(prandom_bytes_state); - -/** - * prandom_bytes - get the requested number of pseudo-random bytes - * @buf: where to copy the pseudo-random bytes to - * @bytes: the requested number of bytes - */ -void prandom_bytes(void *buf, size_t bytes) -{ - struct rnd_state *state = &get_cpu_var(net_rand_state); - - prandom_bytes_state(state, buf, bytes); - put_cpu_var(net_rand_state); -} -EXPORT_SYMBOL(prandom_bytes); - -static void prandom_warmup(struct rnd_state *state) -{ - /* Calling RNG ten times to satisfy recurrence condition */ - prandom_u32_state(state); - prandom_u32_state(state); - prandom_u32_state(state); - prandom_u32_state(state); - prandom_u32_state(state); - prandom_u32_state(state); - prandom_u32_state(state); - prandom_u32_state(state); - prandom_u32_state(state); - prandom_u32_state(state); -} - -static u32 __extract_hwseed(void) -{ - unsigned int val = 0; - - (void)(arch_get_random_seed_int(&val) || - arch_get_random_int(&val)); - - return val; -} - -static void prandom_seed_early(struct rnd_state *state, u32 seed, - bool mix_with_hwseed) -{ -#define LCG(x) ((x) * 69069U) /* super-duper LCG */ -#define HWSEED() (mix_with_hwseed ? __extract_hwseed() : 0) - state->s1 = __seed(HWSEED() ^ LCG(seed), 2U); - state->s2 = __seed(HWSEED() ^ LCG(state->s1), 8U); - state->s3 = __seed(HWSEED() ^ LCG(state->s2), 16U); - state->s4 = __seed(HWSEED() ^ LCG(state->s3), 128U); -} - -/** - * prandom_seed - add entropy to pseudo random number generator - * @seed: seed value - * - * Add some additional seeding to the prandom pool. - */ -void prandom_seed(u32 entropy) -{ - int i; - /* - * No locking on the CPUs, but then somewhat random results are, well, - * expected. - */ - for_each_possible_cpu(i) { - struct rnd_state *state = &per_cpu(net_rand_state, i); - - state->s1 = __seed(state->s1 ^ entropy, 2U); - prandom_warmup(state); - } -} -EXPORT_SYMBOL(prandom_seed); - -/* - * Generate some initially weak seeding values to allow - * to start the prandom_u32() engine. - */ -static int __init prandom_init(void) -{ - int i; - - prandom_state_selftest(); - - for_each_possible_cpu(i) { - struct rnd_state *state = &per_cpu(net_rand_state, i); - u32 weak_seed = (i + jiffies) ^ random_get_entropy(); - - prandom_seed_early(state, weak_seed, true); - prandom_warmup(state); - } - - return 0; -} -core_initcall(prandom_init); - -static void __prandom_timer(unsigned long dontcare); - -static DEFINE_TIMER(seed_timer, __prandom_timer, 0, 0); - -static void __prandom_timer(unsigned long dontcare) -{ - u32 entropy; - unsigned long expires; - - get_random_bytes(&entropy, sizeof(entropy)); - prandom_seed(entropy); - - /* reseed every ~60 seconds, in [40 .. 80) interval with slack */ - expires = 40 + prandom_u32_max(40); - seed_timer.expires = jiffies + msecs_to_jiffies(expires * MSEC_PER_SEC); - - add_timer(&seed_timer); -} - -static void __init __prandom_start_seed_timer(void) -{ - seed_timer.expires = jiffies + msecs_to_jiffies(40 * MSEC_PER_SEC); - add_timer(&seed_timer); -} - -void prandom_seed_full_state(struct rnd_state __percpu *pcpu_state) -{ - int i; - - for_each_possible_cpu(i) { - struct rnd_state *state = per_cpu_ptr(pcpu_state, i); - u32 seeds[4]; - - get_random_bytes(&seeds, sizeof(seeds)); - state->s1 = __seed(seeds[0], 2U); - state->s2 = __seed(seeds[1], 8U); - state->s3 = __seed(seeds[2], 16U); - state->s4 = __seed(seeds[3], 128U); - - prandom_warmup(state); - } -} -EXPORT_SYMBOL(prandom_seed_full_state); - -/* - * Generate better values after random number generator - * is fully initialized. - */ -static void __prandom_reseed(bool late) -{ - unsigned long flags; - static bool latch = false; - static DEFINE_SPINLOCK(lock); - - /* Asking for random bytes might result in bytes getting - * moved into the nonblocking pool and thus marking it - * as initialized. In this case we would double back into - * this function and attempt to do a late reseed. - * Ignore the pointless attempt to reseed again if we're - * already waiting for bytes when the nonblocking pool - * got initialized. - */ - - /* only allow initial seeding (late == false) once */ - if (!spin_trylock_irqsave(&lock, flags)) - return; - - if (latch && !late) - goto out; - - latch = true; - prandom_seed_full_state(&net_rand_state); -out: - spin_unlock_irqrestore(&lock, flags); -} - -void prandom_reseed_late(void) -{ - __prandom_reseed(true); -} - -static int __init prandom_reseed(void) -{ - __prandom_reseed(false); - __prandom_start_seed_timer(); - return 0; -} -late_initcall(prandom_reseed); - -#ifdef CONFIG_RANDOM32_SELFTEST -static struct prandom_test1 { - u32 seed; - u32 result; -} test1[] = { - { 1U, 3484351685U }, - { 2U, 2623130059U }, - { 3U, 3125133893U }, - { 4U, 984847254U }, -}; - -static struct prandom_test2 { - u32 seed; - u32 iteration; - u32 result; -} test2[] = { - /* Test cases against taus113 from GSL library. */ - { 931557656U, 959U, 2975593782U }, - { 1339693295U, 876U, 3887776532U }, - { 1545556285U, 961U, 1615538833U }, - { 601730776U, 723U, 1776162651U }, - { 1027516047U, 687U, 511983079U }, - { 416526298U, 700U, 916156552U }, - { 1395522032U, 652U, 2222063676U }, - { 366221443U, 617U, 2992857763U }, - { 1539836965U, 714U, 3783265725U }, - { 556206671U, 994U, 799626459U }, - { 684907218U, 799U, 367789491U }, - { 2121230701U, 931U, 2115467001U }, - { 1668516451U, 644U, 3620590685U }, - { 768046066U, 883U, 2034077390U }, - { 1989159136U, 833U, 1195767305U }, - { 536585145U, 996U, 3577259204U }, - { 1008129373U, 642U, 1478080776U }, - { 1740775604U, 939U, 1264980372U }, - { 1967883163U, 508U, 10734624U }, - { 1923019697U, 730U, 3821419629U }, - { 442079932U, 560U, 3440032343U }, - { 1961302714U, 845U, 841962572U }, - { 2030205964U, 962U, 1325144227U }, - { 1160407529U, 507U, 240940858U }, - { 635482502U, 779U, 4200489746U }, - { 1252788931U, 699U, 867195434U }, - { 1961817131U, 719U, 668237657U }, - { 1071468216U, 983U, 917876630U }, - { 1281848367U, 932U, 1003100039U }, - { 582537119U, 780U, 1127273778U }, - { 1973672777U, 853U, 1071368872U }, - { 1896756996U, 762U, 1127851055U }, - { 847917054U, 500U, 1717499075U }, - { 1240520510U, 951U, 2849576657U }, - { 1685071682U, 567U, 1961810396U }, - { 1516232129U, 557U, 3173877U }, - { 1208118903U, 612U, 1613145022U }, - { 1817269927U, 693U, 4279122573U }, - { 1510091701U, 717U, 638191229U }, - { 365916850U, 807U, 600424314U }, - { 399324359U, 702U, 1803598116U }, - { 1318480274U, 779U, 2074237022U }, - { 697758115U, 840U, 1483639402U }, - { 1696507773U, 840U, 577415447U }, - { 2081979121U, 981U, 3041486449U }, - { 955646687U, 742U, 3846494357U }, - { 1250683506U, 749U, 836419859U }, - { 595003102U, 534U, 366794109U }, - { 47485338U, 558U, 3521120834U }, - { 619433479U, 610U, 3991783875U }, - { 704096520U, 518U, 4139493852U }, - { 1712224984U, 606U, 2393312003U }, - { 1318233152U, 922U, 3880361134U }, - { 855572992U, 761U, 1472974787U }, - { 64721421U, 703U, 683860550U }, - { 678931758U, 840U, 380616043U }, - { 692711973U, 778U, 1382361947U }, - { 677703619U, 530U, 2826914161U }, - { 92393223U, 586U, 1522128471U }, - { 1222592920U, 743U, 3466726667U }, - { 358288986U, 695U, 1091956998U }, - { 1935056945U, 958U, 514864477U }, - { 735675993U, 990U, 1294239989U }, - { 1560089402U, 897U, 2238551287U }, - { 70616361U, 829U, 22483098U }, - { 368234700U, 731U, 2913875084U }, - { 20221190U, 879U, 1564152970U }, - { 539444654U, 682U, 1835141259U }, - { 1314987297U, 840U, 1801114136U }, - { 2019295544U, 645U, 3286438930U }, - { 469023838U, 716U, 1637918202U }, - { 1843754496U, 653U, 2562092152U }, - { 400672036U, 809U, 4264212785U }, - { 404722249U, 965U, 2704116999U }, - { 600702209U, 758U, 584979986U }, - { 519953954U, 667U, 2574436237U }, - { 1658071126U, 694U, 2214569490U }, - { 420480037U, 749U, 3430010866U }, - { 690103647U, 969U, 3700758083U }, - { 1029424799U, 937U, 3787746841U }, - { 2012608669U, 506U, 3362628973U }, - { 1535432887U, 998U, 42610943U }, - { 1330635533U, 857U, 3040806504U }, - { 1223800550U, 539U, 3954229517U }, - { 1322411537U, 680U, 3223250324U }, - { 1877847898U, 945U, 2915147143U }, - { 1646356099U, 874U, 965988280U }, - { 805687536U, 744U, 4032277920U }, - { 1948093210U, 633U, 1346597684U }, - { 392609744U, 783U, 1636083295U }, - { 690241304U, 770U, 1201031298U }, - { 1360302965U, 696U, 1665394461U }, - { 1220090946U, 780U, 1316922812U }, - { 447092251U, 500U, 3438743375U }, - { 1613868791U, 592U, 828546883U }, - { 523430951U, 548U, 2552392304U }, - { 726692899U, 810U, 1656872867U }, - { 1364340021U, 836U, 3710513486U }, - { 1986257729U, 931U, 935013962U }, - { 407983964U, 921U, 728767059U }, -}; - -static void __init prandom_state_selftest(void) -{ - int i, j, errors = 0, runs = 0; - bool error = false; - - for (i = 0; i < ARRAY_SIZE(test1); i++) { - struct rnd_state state; - - prandom_seed_early(&state, test1[i].seed, false); - prandom_warmup(&state); - - if (test1[i].result != prandom_u32_state(&state)) - error = true; - } - - if (error) - pr_warn("prandom: seed boundary self test failed\n"); - else - pr_info("prandom: seed boundary self test passed\n"); - - for (i = 0; i < ARRAY_SIZE(test2); i++) { - struct rnd_state state; - - prandom_seed_early(&state, test2[i].seed, false); - prandom_warmup(&state); - - for (j = 0; j < test2[i].iteration - 1; j++) - prandom_u32_state(&state); - - if (test2[i].result != prandom_u32_state(&state)) - errors++; - - runs++; - cond_resched(); - } - - if (errors) - pr_warn("prandom: %d/%d self tests failed\n", errors, runs); - else - pr_info("prandom: %d self tests passed\n", runs); -} -#endif diff --git a/src/linux/lib/ratelimit.c b/src/linux/lib/ratelimit.c deleted file mode 100644 index 08f8043..0000000 --- a/src/linux/lib/ratelimit.c +++ /dev/null @@ -1,69 +0,0 @@ -/* - * ratelimit.c - Do something with rate limit. - * - * Isolated from kernel/printk.c by Dave Young - * - * 2008-05-01 rewrite the function and use a ratelimit_state data struct as - * parameter. Now every user can use their own standalone ratelimit_state. - * - * This file is released under the GPLv2. - */ - -#include -#include -#include - -/* - * __ratelimit - rate limiting - * @rs: ratelimit_state data - * @func: name of calling function - * - * This enforces a rate limit: not more than @rs->burst callbacks - * in every @rs->interval - * - * RETURNS: - * 0 means callbacks will be suppressed. - * 1 means go ahead and do it. - */ -int ___ratelimit(struct ratelimit_state *rs, const char *func) -{ - unsigned long flags; - int ret; - - if (!rs->interval) - return 1; - - /* - * If we contend on this state's lock then almost - * by definition we are too busy to print a message, - * in addition to the one that will be printed by - * the entity that is holding the lock already: - */ - if (!raw_spin_trylock_irqsave(&rs->lock, flags)) - return 0; - - if (!rs->begin) - rs->begin = jiffies; - - if (time_is_before_jiffies(rs->begin + rs->interval)) { - if (rs->missed) { - if (!(rs->flags & RATELIMIT_MSG_ON_RELEASE)) { - pr_warn("%s: %d callbacks suppressed\n", func, rs->missed); - rs->missed = 0; - } - } - rs->begin = jiffies; - rs->printed = 0; - } - if (rs->burst && rs->burst > rs->printed) { - rs->printed++; - ret = 1; - } else { - rs->missed++; - ret = 0; - } - raw_spin_unlock_irqrestore(&rs->lock, flags); - - return ret; -} -EXPORT_SYMBOL(___ratelimit); diff --git a/src/linux/lib/rbtree.c b/src/linux/lib/rbtree.c deleted file mode 100644 index eb8a19f..0000000 --- a/src/linux/lib/rbtree.c +++ /dev/null @@ -1,614 +0,0 @@ -/* - Red Black Trees - (C) 1999 Andrea Arcangeli - (C) 2002 David Woodhouse - (C) 2012 Michel Lespinasse - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - linux/lib/rbtree.c -*/ - -#include -#include - -/* - * red-black trees properties: http://en.wikipedia.org/wiki/Rbtree - * - * 1) A node is either red or black - * 2) The root is black - * 3) All leaves (NULL) are black - * 4) Both children of every red node are black - * 5) Every simple path from root to leaves contains the same number - * of black nodes. - * - * 4 and 5 give the O(log n) guarantee, since 4 implies you cannot have two - * consecutive red nodes in a path and every red node is therefore followed by - * a black. So if B is the number of black nodes on every simple path (as per - * 5), then the longest possible path due to 4 is 2B. - * - * We shall indicate color with case, where black nodes are uppercase and red - * nodes will be lowercase. Unknown color nodes shall be drawn as red within - * parentheses and have some accompanying text comment. - */ - -/* - * Notes on lockless lookups: - * - * All stores to the tree structure (rb_left and rb_right) must be done using - * WRITE_ONCE(). And we must not inadvertently cause (temporary) loops in the - * tree structure as seen in program order. - * - * These two requirements will allow lockless iteration of the tree -- not - * correct iteration mind you, tree rotations are not atomic so a lookup might - * miss entire subtrees. - * - * But they do guarantee that any such traversal will only see valid elements - * and that it will indeed complete -- does not get stuck in a loop. - * - * It also guarantees that if the lookup returns an element it is the 'correct' - * one. But not returning an element does _NOT_ mean it's not present. - * - * NOTE: - * - * Stores to __rb_parent_color are not important for simple lookups so those - * are left undone as of now. Nor did I check for loops involving parent - * pointers. - */ - -static inline void rb_set_black(struct rb_node *rb) -{ - rb->__rb_parent_color |= RB_BLACK; -} - -static inline struct rb_node *rb_red_parent(struct rb_node *red) -{ - return (struct rb_node *)red->__rb_parent_color; -} - -/* - * Helper function for rotations: - * - old's parent and color get assigned to new - * - old gets assigned new as a parent and 'color' as a color. - */ -static inline void -__rb_rotate_set_parents(struct rb_node *old, struct rb_node *new, - struct rb_root *root, int color) -{ - struct rb_node *parent = rb_parent(old); - new->__rb_parent_color = old->__rb_parent_color; - rb_set_parent_color(old, new, color); - __rb_change_child(old, new, parent, root); -} - -static __always_inline void -__rb_insert(struct rb_node *node, struct rb_root *root, - void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) -{ - struct rb_node *parent = rb_red_parent(node), *gparent, *tmp; - - while (true) { - /* - * Loop invariant: node is red - * - * If there is a black parent, we are done. - * Otherwise, take some corrective action as we don't - * want a red root or two consecutive red nodes. - */ - if (!parent) { - rb_set_parent_color(node, NULL, RB_BLACK); - break; - } else if (rb_is_black(parent)) - break; - - gparent = rb_red_parent(parent); - - tmp = gparent->rb_right; - if (parent != tmp) { /* parent == gparent->rb_left */ - if (tmp && rb_is_red(tmp)) { - /* - * Case 1 - color flips - * - * G g - * / \ / \ - * p u --> P U - * / / - * n n - * - * However, since g's parent might be red, and - * 4) does not allow this, we need to recurse - * at g. - */ - rb_set_parent_color(tmp, gparent, RB_BLACK); - rb_set_parent_color(parent, gparent, RB_BLACK); - node = gparent; - parent = rb_parent(node); - rb_set_parent_color(node, parent, RB_RED); - continue; - } - - tmp = parent->rb_right; - if (node == tmp) { - /* - * Case 2 - left rotate at parent - * - * G G - * / \ / \ - * p U --> n U - * \ / - * n p - * - * This still leaves us in violation of 4), the - * continuation into Case 3 will fix that. - */ - tmp = node->rb_left; - WRITE_ONCE(parent->rb_right, tmp); - WRITE_ONCE(node->rb_left, parent); - if (tmp) - rb_set_parent_color(tmp, parent, - RB_BLACK); - rb_set_parent_color(parent, node, RB_RED); - augment_rotate(parent, node); - parent = node; - tmp = node->rb_right; - } - - /* - * Case 3 - right rotate at gparent - * - * G P - * / \ / \ - * p U --> n g - * / \ - * n U - */ - WRITE_ONCE(gparent->rb_left, tmp); /* == parent->rb_right */ - WRITE_ONCE(parent->rb_right, gparent); - if (tmp) - rb_set_parent_color(tmp, gparent, RB_BLACK); - __rb_rotate_set_parents(gparent, parent, root, RB_RED); - augment_rotate(gparent, parent); - break; - } else { - tmp = gparent->rb_left; - if (tmp && rb_is_red(tmp)) { - /* Case 1 - color flips */ - rb_set_parent_color(tmp, gparent, RB_BLACK); - rb_set_parent_color(parent, gparent, RB_BLACK); - node = gparent; - parent = rb_parent(node); - rb_set_parent_color(node, parent, RB_RED); - continue; - } - - tmp = parent->rb_left; - if (node == tmp) { - /* Case 2 - right rotate at parent */ - tmp = node->rb_right; - WRITE_ONCE(parent->rb_left, tmp); - WRITE_ONCE(node->rb_right, parent); - if (tmp) - rb_set_parent_color(tmp, parent, - RB_BLACK); - rb_set_parent_color(parent, node, RB_RED); - augment_rotate(parent, node); - parent = node; - tmp = node->rb_left; - } - - /* Case 3 - left rotate at gparent */ - WRITE_ONCE(gparent->rb_right, tmp); /* == parent->rb_left */ - WRITE_ONCE(parent->rb_left, gparent); - if (tmp) - rb_set_parent_color(tmp, gparent, RB_BLACK); - __rb_rotate_set_parents(gparent, parent, root, RB_RED); - augment_rotate(gparent, parent); - break; - } - } -} - -/* - * Inline version for rb_erase() use - we want to be able to inline - * and eliminate the dummy_rotate callback there - */ -static __always_inline void -____rb_erase_color(struct rb_node *parent, struct rb_root *root, - void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) -{ - struct rb_node *node = NULL, *sibling, *tmp1, *tmp2; - - while (true) { - /* - * Loop invariants: - * - node is black (or NULL on first iteration) - * - node is not the root (parent is not NULL) - * - All leaf paths going through parent and node have a - * black node count that is 1 lower than other leaf paths. - */ - sibling = parent->rb_right; - if (node != sibling) { /* node == parent->rb_left */ - if (rb_is_red(sibling)) { - /* - * Case 1 - left rotate at parent - * - * P S - * / \ / \ - * N s --> p Sr - * / \ / \ - * Sl Sr N Sl - */ - tmp1 = sibling->rb_left; - WRITE_ONCE(parent->rb_right, tmp1); - WRITE_ONCE(sibling->rb_left, parent); - rb_set_parent_color(tmp1, parent, RB_BLACK); - __rb_rotate_set_parents(parent, sibling, root, - RB_RED); - augment_rotate(parent, sibling); - sibling = tmp1; - } - tmp1 = sibling->rb_right; - if (!tmp1 || rb_is_black(tmp1)) { - tmp2 = sibling->rb_left; - if (!tmp2 || rb_is_black(tmp2)) { - /* - * Case 2 - sibling color flip - * (p could be either color here) - * - * (p) (p) - * / \ / \ - * N S --> N s - * / \ / \ - * Sl Sr Sl Sr - * - * This leaves us violating 5) which - * can be fixed by flipping p to black - * if it was red, or by recursing at p. - * p is red when coming from Case 1. - */ - rb_set_parent_color(sibling, parent, - RB_RED); - if (rb_is_red(parent)) - rb_set_black(parent); - else { - node = parent; - parent = rb_parent(node); - if (parent) - continue; - } - break; - } - /* - * Case 3 - right rotate at sibling - * (p could be either color here) - * - * (p) (p) - * / \ / \ - * N S --> N Sl - * / \ \ - * sl Sr s - * \ - * Sr - */ - tmp1 = tmp2->rb_right; - WRITE_ONCE(sibling->rb_left, tmp1); - WRITE_ONCE(tmp2->rb_right, sibling); - WRITE_ONCE(parent->rb_right, tmp2); - if (tmp1) - rb_set_parent_color(tmp1, sibling, - RB_BLACK); - augment_rotate(sibling, tmp2); - tmp1 = sibling; - sibling = tmp2; - } - /* - * Case 4 - left rotate at parent + color flips - * (p and sl could be either color here. - * After rotation, p becomes black, s acquires - * p's color, and sl keeps its color) - * - * (p) (s) - * / \ / \ - * N S --> P Sr - * / \ / \ - * (sl) sr N (sl) - */ - tmp2 = sibling->rb_left; - WRITE_ONCE(parent->rb_right, tmp2); - WRITE_ONCE(sibling->rb_left, parent); - rb_set_parent_color(tmp1, sibling, RB_BLACK); - if (tmp2) - rb_set_parent(tmp2, parent); - __rb_rotate_set_parents(parent, sibling, root, - RB_BLACK); - augment_rotate(parent, sibling); - break; - } else { - sibling = parent->rb_left; - if (rb_is_red(sibling)) { - /* Case 1 - right rotate at parent */ - tmp1 = sibling->rb_right; - WRITE_ONCE(parent->rb_left, tmp1); - WRITE_ONCE(sibling->rb_right, parent); - rb_set_parent_color(tmp1, parent, RB_BLACK); - __rb_rotate_set_parents(parent, sibling, root, - RB_RED); - augment_rotate(parent, sibling); - sibling = tmp1; - } - tmp1 = sibling->rb_left; - if (!tmp1 || rb_is_black(tmp1)) { - tmp2 = sibling->rb_right; - if (!tmp2 || rb_is_black(tmp2)) { - /* Case 2 - sibling color flip */ - rb_set_parent_color(sibling, parent, - RB_RED); - if (rb_is_red(parent)) - rb_set_black(parent); - else { - node = parent; - parent = rb_parent(node); - if (parent) - continue; - } - break; - } - /* Case 3 - right rotate at sibling */ - tmp1 = tmp2->rb_left; - WRITE_ONCE(sibling->rb_right, tmp1); - WRITE_ONCE(tmp2->rb_left, sibling); - WRITE_ONCE(parent->rb_left, tmp2); - if (tmp1) - rb_set_parent_color(tmp1, sibling, - RB_BLACK); - augment_rotate(sibling, tmp2); - tmp1 = sibling; - sibling = tmp2; - } - /* Case 4 - left rotate at parent + color flips */ - tmp2 = sibling->rb_right; - WRITE_ONCE(parent->rb_left, tmp2); - WRITE_ONCE(sibling->rb_right, parent); - rb_set_parent_color(tmp1, sibling, RB_BLACK); - if (tmp2) - rb_set_parent(tmp2, parent); - __rb_rotate_set_parents(parent, sibling, root, - RB_BLACK); - augment_rotate(parent, sibling); - break; - } - } -} - -/* Non-inline version for rb_erase_augmented() use */ -void __rb_erase_color(struct rb_node *parent, struct rb_root *root, - void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) -{ - ____rb_erase_color(parent, root, augment_rotate); -} -EXPORT_SYMBOL(__rb_erase_color); - -/* - * Non-augmented rbtree manipulation functions. - * - * We use dummy augmented callbacks here, and have the compiler optimize them - * out of the rb_insert_color() and rb_erase() function definitions. - */ - -static inline void dummy_propagate(struct rb_node *node, struct rb_node *stop) {} -static inline void dummy_copy(struct rb_node *old, struct rb_node *new) {} -static inline void dummy_rotate(struct rb_node *old, struct rb_node *new) {} - -static const struct rb_augment_callbacks dummy_callbacks = { - dummy_propagate, dummy_copy, dummy_rotate -}; - -void rb_insert_color(struct rb_node *node, struct rb_root *root) -{ - __rb_insert(node, root, dummy_rotate); -} -EXPORT_SYMBOL(rb_insert_color); - -void rb_erase(struct rb_node *node, struct rb_root *root) -{ - struct rb_node *rebalance; - rebalance = __rb_erase_augmented(node, root, &dummy_callbacks); - if (rebalance) - ____rb_erase_color(rebalance, root, dummy_rotate); -} -EXPORT_SYMBOL(rb_erase); - -/* - * Augmented rbtree manipulation functions. - * - * This instantiates the same __always_inline functions as in the non-augmented - * case, but this time with user-defined callbacks. - */ - -void __rb_insert_augmented(struct rb_node *node, struct rb_root *root, - void (*augment_rotate)(struct rb_node *old, struct rb_node *new)) -{ - __rb_insert(node, root, augment_rotate); -} -EXPORT_SYMBOL(__rb_insert_augmented); - -/* - * This function returns the first node (in sort order) of the tree. - */ -struct rb_node *rb_first(const struct rb_root *root) -{ - struct rb_node *n; - - n = root->rb_node; - if (!n) - return NULL; - while (n->rb_left) - n = n->rb_left; - return n; -} -EXPORT_SYMBOL(rb_first); - -struct rb_node *rb_last(const struct rb_root *root) -{ - struct rb_node *n; - - n = root->rb_node; - if (!n) - return NULL; - while (n->rb_right) - n = n->rb_right; - return n; -} -EXPORT_SYMBOL(rb_last); - -struct rb_node *rb_next(const struct rb_node *node) -{ - struct rb_node *parent; - - if (RB_EMPTY_NODE(node)) - return NULL; - - /* - * If we have a right-hand child, go down and then left as far - * as we can. - */ - if (node->rb_right) { - node = node->rb_right; - while (node->rb_left) - node=node->rb_left; - return (struct rb_node *)node; - } - - /* - * No right-hand children. Everything down and left is smaller than us, - * so any 'next' node must be in the general direction of our parent. - * Go up the tree; any time the ancestor is a right-hand child of its - * parent, keep going up. First time it's a left-hand child of its - * parent, said parent is our 'next' node. - */ - while ((parent = rb_parent(node)) && node == parent->rb_right) - node = parent; - - return parent; -} -EXPORT_SYMBOL(rb_next); - -struct rb_node *rb_prev(const struct rb_node *node) -{ - struct rb_node *parent; - - if (RB_EMPTY_NODE(node)) - return NULL; - - /* - * If we have a left-hand child, go down and then right as far - * as we can. - */ - if (node->rb_left) { - node = node->rb_left; - while (node->rb_right) - node=node->rb_right; - return (struct rb_node *)node; - } - - /* - * No left-hand children. Go up till we find an ancestor which - * is a right-hand child of its parent. - */ - while ((parent = rb_parent(node)) && node == parent->rb_left) - node = parent; - - return parent; -} -EXPORT_SYMBOL(rb_prev); - -void rb_replace_node(struct rb_node *victim, struct rb_node *new, - struct rb_root *root) -{ - struct rb_node *parent = rb_parent(victim); - - /* Copy the pointers/colour from the victim to the replacement */ - *new = *victim; - - /* Set the surrounding nodes to point to the replacement */ - if (victim->rb_left) - rb_set_parent(victim->rb_left, new); - if (victim->rb_right) - rb_set_parent(victim->rb_right, new); - __rb_change_child(victim, new, parent, root); -} -EXPORT_SYMBOL(rb_replace_node); - -void rb_replace_node_rcu(struct rb_node *victim, struct rb_node *new, - struct rb_root *root) -{ - struct rb_node *parent = rb_parent(victim); - - /* Copy the pointers/colour from the victim to the replacement */ - *new = *victim; - - /* Set the surrounding nodes to point to the replacement */ - if (victim->rb_left) - rb_set_parent(victim->rb_left, new); - if (victim->rb_right) - rb_set_parent(victim->rb_right, new); - - /* Set the parent's pointer to the new node last after an RCU barrier - * so that the pointers onwards are seen to be set correctly when doing - * an RCU walk over the tree. - */ - __rb_change_child_rcu(victim, new, parent, root); -} -EXPORT_SYMBOL(rb_replace_node_rcu); - -static struct rb_node *rb_left_deepest_node(const struct rb_node *node) -{ - for (;;) { - if (node->rb_left) - node = node->rb_left; - else if (node->rb_right) - node = node->rb_right; - else - return (struct rb_node *)node; - } -} - -struct rb_node *rb_next_postorder(const struct rb_node *node) -{ - const struct rb_node *parent; - if (!node) - return NULL; - parent = rb_parent(node); - - /* If we're sitting on node, we've already seen our children */ - if (parent && node == parent->rb_left && parent->rb_right) { - /* If we are the parent's left node, go to the parent's right - * node then all the way down to the left */ - return rb_left_deepest_node(parent->rb_right); - } else - /* Otherwise we are the parent's right node, and the parent - * should be next */ - return (struct rb_node *)parent; -} -EXPORT_SYMBOL(rb_next_postorder); - -struct rb_node *rb_first_postorder(const struct rb_root *root) -{ - if (!root->rb_node) - return NULL; - - return rb_left_deepest_node(root->rb_node); -} -EXPORT_SYMBOL(rb_first_postorder); diff --git a/src/linux/lib/reciprocal_div.c b/src/linux/lib/reciprocal_div.c deleted file mode 100644 index 4641524..0000000 --- a/src/linux/lib/reciprocal_div.c +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include -#include - -/* - * For a description of the algorithm please have a look at - * include/linux/reciprocal_div.h - */ - -struct reciprocal_value reciprocal_value(u32 d) -{ - struct reciprocal_value R; - u64 m; - int l; - - l = fls(d - 1); - m = ((1ULL << 32) * ((1ULL << l) - d)); - do_div(m, d); - ++m; - R.m = (u32)m; - R.sh1 = min(l, 1); - R.sh2 = max(l - 1, 0); - - return R; -} -EXPORT_SYMBOL(reciprocal_value); diff --git a/src/linux/lib/rhashtable.c b/src/linux/lib/rhashtable.c deleted file mode 100644 index 32d0ad0..0000000 --- a/src/linux/lib/rhashtable.c +++ /dev/null @@ -1,1009 +0,0 @@ -/* - * Resizable, Scalable, Concurrent Hash Table - * - * Copyright (c) 2015 Herbert Xu - * Copyright (c) 2014-2015 Thomas Graf - * Copyright (c) 2008-2014 Patrick McHardy - * - * Code partially derived from nft_hash - * Rewritten with rehash code from br_multicast plus single list - * pointer as suggested by Josh Triplett - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define HASH_DEFAULT_SIZE 64UL -#define HASH_MIN_SIZE 4U -#define BUCKET_LOCKS_PER_CPU 32UL - -static u32 head_hashfn(struct rhashtable *ht, - const struct bucket_table *tbl, - const struct rhash_head *he) -{ - return rht_head_hashfn(ht, tbl, he, ht->p); -} - -#ifdef CONFIG_PROVE_LOCKING -#define ASSERT_RHT_MUTEX(HT) BUG_ON(!lockdep_rht_mutex_is_held(HT)) - -int lockdep_rht_mutex_is_held(struct rhashtable *ht) -{ - return (debug_locks) ? lockdep_is_held(&ht->mutex) : 1; -} -EXPORT_SYMBOL_GPL(lockdep_rht_mutex_is_held); - -int lockdep_rht_bucket_is_held(const struct bucket_table *tbl, u32 hash) -{ - spinlock_t *lock = rht_bucket_lock(tbl, hash); - - return (debug_locks) ? lockdep_is_held(lock) : 1; -} -EXPORT_SYMBOL_GPL(lockdep_rht_bucket_is_held); -#else -#define ASSERT_RHT_MUTEX(HT) -#endif - - -static int alloc_bucket_locks(struct rhashtable *ht, struct bucket_table *tbl, - gfp_t gfp) -{ - unsigned int i, size; -#if defined(CONFIG_PROVE_LOCKING) - unsigned int nr_pcpus = 2; -#else - unsigned int nr_pcpus = num_possible_cpus(); -#endif - - nr_pcpus = min_t(unsigned int, nr_pcpus, 64UL); - size = roundup_pow_of_two(nr_pcpus * ht->p.locks_mul); - - /* Never allocate more than 0.5 locks per bucket */ - size = min_t(unsigned int, size, tbl->size >> 1); - - if (sizeof(spinlock_t) != 0) { - tbl->locks = NULL; -#ifdef CONFIG_NUMA - if (size * sizeof(spinlock_t) > PAGE_SIZE && - gfp == GFP_KERNEL) - tbl->locks = vmalloc(size * sizeof(spinlock_t)); -#endif - if (gfp != GFP_KERNEL) - gfp |= __GFP_NOWARN | __GFP_NORETRY; - - if (!tbl->locks) - tbl->locks = kmalloc_array(size, sizeof(spinlock_t), - gfp); - if (!tbl->locks) - return -ENOMEM; - for (i = 0; i < size; i++) - spin_lock_init(&tbl->locks[i]); - } - tbl->locks_mask = size - 1; - - return 0; -} - -static void bucket_table_free(const struct bucket_table *tbl) -{ - if (tbl) - kvfree(tbl->locks); - - kvfree(tbl); -} - -static void bucket_table_free_rcu(struct rcu_head *head) -{ - bucket_table_free(container_of(head, struct bucket_table, rcu)); -} - -static struct bucket_table *bucket_table_alloc(struct rhashtable *ht, - size_t nbuckets, - gfp_t gfp) -{ - struct bucket_table *tbl = NULL; - size_t size; - int i; - - size = sizeof(*tbl) + nbuckets * sizeof(tbl->buckets[0]); - if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER) || - gfp != GFP_KERNEL) - tbl = kzalloc(size, gfp | __GFP_NOWARN | __GFP_NORETRY); - if (tbl == NULL && gfp == GFP_KERNEL) - tbl = vzalloc(size); - if (tbl == NULL) - return NULL; - - tbl->size = nbuckets; - - if (alloc_bucket_locks(ht, tbl, gfp) < 0) { - bucket_table_free(tbl); - return NULL; - } - - INIT_LIST_HEAD(&tbl->walkers); - - get_random_bytes(&tbl->hash_rnd, sizeof(tbl->hash_rnd)); - - for (i = 0; i < nbuckets; i++) - INIT_RHT_NULLS_HEAD(tbl->buckets[i], ht, i); - - return tbl; -} - -static struct bucket_table *rhashtable_last_table(struct rhashtable *ht, - struct bucket_table *tbl) -{ - struct bucket_table *new_tbl; - - do { - new_tbl = tbl; - tbl = rht_dereference_rcu(tbl->future_tbl, ht); - } while (tbl); - - return new_tbl; -} - -static int rhashtable_rehash_one(struct rhashtable *ht, unsigned int old_hash) -{ - struct bucket_table *old_tbl = rht_dereference(ht->tbl, ht); - struct bucket_table *new_tbl = rhashtable_last_table(ht, - rht_dereference_rcu(old_tbl->future_tbl, ht)); - struct rhash_head __rcu **pprev = &old_tbl->buckets[old_hash]; - int err = -ENOENT; - struct rhash_head *head, *next, *entry; - spinlock_t *new_bucket_lock; - unsigned int new_hash; - - rht_for_each(entry, old_tbl, old_hash) { - err = 0; - next = rht_dereference_bucket(entry->next, old_tbl, old_hash); - - if (rht_is_a_nulls(next)) - break; - - pprev = &entry->next; - } - - if (err) - goto out; - - new_hash = head_hashfn(ht, new_tbl, entry); - - new_bucket_lock = rht_bucket_lock(new_tbl, new_hash); - - spin_lock_nested(new_bucket_lock, SINGLE_DEPTH_NESTING); - head = rht_dereference_bucket(new_tbl->buckets[new_hash], - new_tbl, new_hash); - - RCU_INIT_POINTER(entry->next, head); - - rcu_assign_pointer(new_tbl->buckets[new_hash], entry); - spin_unlock(new_bucket_lock); - - rcu_assign_pointer(*pprev, next); - -out: - return err; -} - -static void rhashtable_rehash_chain(struct rhashtable *ht, - unsigned int old_hash) -{ - struct bucket_table *old_tbl = rht_dereference(ht->tbl, ht); - spinlock_t *old_bucket_lock; - - old_bucket_lock = rht_bucket_lock(old_tbl, old_hash); - - spin_lock_bh(old_bucket_lock); - while (!rhashtable_rehash_one(ht, old_hash)) - ; - old_tbl->rehash++; - spin_unlock_bh(old_bucket_lock); -} - -static int rhashtable_rehash_attach(struct rhashtable *ht, - struct bucket_table *old_tbl, - struct bucket_table *new_tbl) -{ - /* Protect future_tbl using the first bucket lock. */ - spin_lock_bh(old_tbl->locks); - - /* Did somebody beat us to it? */ - if (rcu_access_pointer(old_tbl->future_tbl)) { - spin_unlock_bh(old_tbl->locks); - return -EEXIST; - } - - /* Make insertions go into the new, empty table right away. Deletions - * and lookups will be attempted in both tables until we synchronize. - */ - rcu_assign_pointer(old_tbl->future_tbl, new_tbl); - - spin_unlock_bh(old_tbl->locks); - - return 0; -} - -static int rhashtable_rehash_table(struct rhashtable *ht) -{ - struct bucket_table *old_tbl = rht_dereference(ht->tbl, ht); - struct bucket_table *new_tbl; - struct rhashtable_walker *walker; - unsigned int old_hash; - - new_tbl = rht_dereference(old_tbl->future_tbl, ht); - if (!new_tbl) - return 0; - - for (old_hash = 0; old_hash < old_tbl->size; old_hash++) - rhashtable_rehash_chain(ht, old_hash); - - /* Publish the new table pointer. */ - rcu_assign_pointer(ht->tbl, new_tbl); - - spin_lock(&ht->lock); - list_for_each_entry(walker, &old_tbl->walkers, list) - walker->tbl = NULL; - spin_unlock(&ht->lock); - - /* Wait for readers. All new readers will see the new - * table, and thus no references to the old table will - * remain. - */ - call_rcu(&old_tbl->rcu, bucket_table_free_rcu); - - return rht_dereference(new_tbl->future_tbl, ht) ? -EAGAIN : 0; -} - -/** - * rhashtable_expand - Expand hash table while allowing concurrent lookups - * @ht: the hash table to expand - * - * A secondary bucket array is allocated and the hash entries are migrated. - * - * This function may only be called in a context where it is safe to call - * synchronize_rcu(), e.g. not within a rcu_read_lock() section. - * - * The caller must ensure that no concurrent resizing occurs by holding - * ht->mutex. - * - * It is valid to have concurrent insertions and deletions protected by per - * bucket locks or concurrent RCU protected lookups and traversals. - */ -static int rhashtable_expand(struct rhashtable *ht) -{ - struct bucket_table *new_tbl, *old_tbl = rht_dereference(ht->tbl, ht); - int err; - - ASSERT_RHT_MUTEX(ht); - - old_tbl = rhashtable_last_table(ht, old_tbl); - - new_tbl = bucket_table_alloc(ht, old_tbl->size * 2, GFP_KERNEL); - if (new_tbl == NULL) - return -ENOMEM; - - err = rhashtable_rehash_attach(ht, old_tbl, new_tbl); - if (err) - bucket_table_free(new_tbl); - - return err; -} - -/** - * rhashtable_shrink - Shrink hash table while allowing concurrent lookups - * @ht: the hash table to shrink - * - * This function shrinks the hash table to fit, i.e., the smallest - * size would not cause it to expand right away automatically. - * - * The caller must ensure that no concurrent resizing occurs by holding - * ht->mutex. - * - * The caller must ensure that no concurrent table mutations take place. - * It is however valid to have concurrent lookups if they are RCU protected. - * - * It is valid to have concurrent insertions and deletions protected by per - * bucket locks or concurrent RCU protected lookups and traversals. - */ -static int rhashtable_shrink(struct rhashtable *ht) -{ - struct bucket_table *new_tbl, *old_tbl = rht_dereference(ht->tbl, ht); - unsigned int nelems = atomic_read(&ht->nelems); - unsigned int size = 0; - int err; - - ASSERT_RHT_MUTEX(ht); - - if (nelems) - size = roundup_pow_of_two(nelems * 3 / 2); - if (size < ht->p.min_size) - size = ht->p.min_size; - - if (old_tbl->size <= size) - return 0; - - if (rht_dereference(old_tbl->future_tbl, ht)) - return -EEXIST; - - new_tbl = bucket_table_alloc(ht, size, GFP_KERNEL); - if (new_tbl == NULL) - return -ENOMEM; - - err = rhashtable_rehash_attach(ht, old_tbl, new_tbl); - if (err) - bucket_table_free(new_tbl); - - return err; -} - -static void rht_deferred_worker(struct work_struct *work) -{ - struct rhashtable *ht; - struct bucket_table *tbl; - int err = 0; - - ht = container_of(work, struct rhashtable, run_work); - mutex_lock(&ht->mutex); - - tbl = rht_dereference(ht->tbl, ht); - tbl = rhashtable_last_table(ht, tbl); - - if (rht_grow_above_75(ht, tbl)) - rhashtable_expand(ht); - else if (ht->p.automatic_shrinking && rht_shrink_below_30(ht, tbl)) - rhashtable_shrink(ht); - - err = rhashtable_rehash_table(ht); - - mutex_unlock(&ht->mutex); - - if (err) - schedule_work(&ht->run_work); -} - -static int rhashtable_insert_rehash(struct rhashtable *ht, - struct bucket_table *tbl) -{ - struct bucket_table *old_tbl; - struct bucket_table *new_tbl; - unsigned int size; - int err; - - old_tbl = rht_dereference_rcu(ht->tbl, ht); - - size = tbl->size; - - err = -EBUSY; - - if (rht_grow_above_75(ht, tbl)) - size *= 2; - /* Do not schedule more than one rehash */ - else if (old_tbl != tbl) - goto fail; - - err = -ENOMEM; - - new_tbl = bucket_table_alloc(ht, size, GFP_ATOMIC); - if (new_tbl == NULL) - goto fail; - - err = rhashtable_rehash_attach(ht, tbl, new_tbl); - if (err) { - bucket_table_free(new_tbl); - if (err == -EEXIST) - err = 0; - } else - schedule_work(&ht->run_work); - - return err; - -fail: - /* Do not fail the insert if someone else did a rehash. */ - if (likely(rcu_dereference_raw(tbl->future_tbl))) - return 0; - - /* Schedule async rehash to retry allocation in process context. */ - if (err == -ENOMEM) - schedule_work(&ht->run_work); - - return err; -} - -static void *rhashtable_lookup_one(struct rhashtable *ht, - struct bucket_table *tbl, unsigned int hash, - const void *key, struct rhash_head *obj) -{ - struct rhashtable_compare_arg arg = { - .ht = ht, - .key = key, - }; - struct rhash_head __rcu **pprev; - struct rhash_head *head; - int elasticity; - - elasticity = ht->elasticity; - pprev = &tbl->buckets[hash]; - rht_for_each(head, tbl, hash) { - struct rhlist_head *list; - struct rhlist_head *plist; - - elasticity--; - if (!key || - (ht->p.obj_cmpfn ? - ht->p.obj_cmpfn(&arg, rht_obj(ht, head)) : - rhashtable_compare(&arg, rht_obj(ht, head)))) - continue; - - if (!ht->rhlist) - return rht_obj(ht, head); - - list = container_of(obj, struct rhlist_head, rhead); - plist = container_of(head, struct rhlist_head, rhead); - - RCU_INIT_POINTER(list->next, plist); - head = rht_dereference_bucket(head->next, tbl, hash); - RCU_INIT_POINTER(list->rhead.next, head); - rcu_assign_pointer(*pprev, obj); - - return NULL; - } - - if (elasticity <= 0) - return ERR_PTR(-EAGAIN); - - return ERR_PTR(-ENOENT); -} - -static struct bucket_table *rhashtable_insert_one(struct rhashtable *ht, - struct bucket_table *tbl, - unsigned int hash, - struct rhash_head *obj, - void *data) -{ - struct bucket_table *new_tbl; - struct rhash_head *head; - - if (!IS_ERR_OR_NULL(data)) - return ERR_PTR(-EEXIST); - - if (PTR_ERR(data) != -EAGAIN && PTR_ERR(data) != -ENOENT) - return ERR_CAST(data); - - new_tbl = rcu_dereference(tbl->future_tbl); - if (new_tbl) - return new_tbl; - - if (PTR_ERR(data) != -ENOENT) - return ERR_CAST(data); - - if (unlikely(rht_grow_above_max(ht, tbl))) - return ERR_PTR(-E2BIG); - - if (unlikely(rht_grow_above_100(ht, tbl))) - return ERR_PTR(-EAGAIN); - - head = rht_dereference_bucket(tbl->buckets[hash], tbl, hash); - - RCU_INIT_POINTER(obj->next, head); - if (ht->rhlist) { - struct rhlist_head *list; - - list = container_of(obj, struct rhlist_head, rhead); - RCU_INIT_POINTER(list->next, NULL); - } - - rcu_assign_pointer(tbl->buckets[hash], obj); - - atomic_inc(&ht->nelems); - if (rht_grow_above_75(ht, tbl)) - schedule_work(&ht->run_work); - - return NULL; -} - -static void *rhashtable_try_insert(struct rhashtable *ht, const void *key, - struct rhash_head *obj) -{ - struct bucket_table *new_tbl; - struct bucket_table *tbl; - unsigned int hash; - spinlock_t *lock; - void *data; - - tbl = rcu_dereference(ht->tbl); - - /* All insertions must grab the oldest table containing - * the hashed bucket that is yet to be rehashed. - */ - for (;;) { - hash = rht_head_hashfn(ht, tbl, obj, ht->p); - lock = rht_bucket_lock(tbl, hash); - spin_lock_bh(lock); - - if (tbl->rehash <= hash) - break; - - spin_unlock_bh(lock); - tbl = rcu_dereference(tbl->future_tbl); - } - - data = rhashtable_lookup_one(ht, tbl, hash, key, obj); - new_tbl = rhashtable_insert_one(ht, tbl, hash, obj, data); - if (PTR_ERR(new_tbl) != -EEXIST) - data = ERR_CAST(new_tbl); - - while (!IS_ERR_OR_NULL(new_tbl)) { - tbl = new_tbl; - hash = rht_head_hashfn(ht, tbl, obj, ht->p); - spin_lock_nested(rht_bucket_lock(tbl, hash), - SINGLE_DEPTH_NESTING); - - data = rhashtable_lookup_one(ht, tbl, hash, key, obj); - new_tbl = rhashtable_insert_one(ht, tbl, hash, obj, data); - if (PTR_ERR(new_tbl) != -EEXIST) - data = ERR_CAST(new_tbl); - - spin_unlock(rht_bucket_lock(tbl, hash)); - } - - spin_unlock_bh(lock); - - if (PTR_ERR(data) == -EAGAIN) - data = ERR_PTR(rhashtable_insert_rehash(ht, tbl) ?: - -EAGAIN); - - return data; -} - -void *rhashtable_insert_slow(struct rhashtable *ht, const void *key, - struct rhash_head *obj) -{ - void *data; - - do { - rcu_read_lock(); - data = rhashtable_try_insert(ht, key, obj); - rcu_read_unlock(); - } while (PTR_ERR(data) == -EAGAIN); - - return data; -} -EXPORT_SYMBOL_GPL(rhashtable_insert_slow); - -/** - * rhashtable_walk_enter - Initialise an iterator - * @ht: Table to walk over - * @iter: Hash table Iterator - * - * This function prepares a hash table walk. - * - * Note that if you restart a walk after rhashtable_walk_stop you - * may see the same object twice. Also, you may miss objects if - * there are removals in between rhashtable_walk_stop and the next - * call to rhashtable_walk_start. - * - * For a completely stable walk you should construct your own data - * structure outside the hash table. - * - * This function may sleep so you must not call it from interrupt - * context or with spin locks held. - * - * You must call rhashtable_walk_exit after this function returns. - */ -void rhashtable_walk_enter(struct rhashtable *ht, struct rhashtable_iter *iter) -{ - iter->ht = ht; - iter->p = NULL; - iter->slot = 0; - iter->skip = 0; - - spin_lock(&ht->lock); - iter->walker.tbl = - rcu_dereference_protected(ht->tbl, lockdep_is_held(&ht->lock)); - list_add(&iter->walker.list, &iter->walker.tbl->walkers); - spin_unlock(&ht->lock); -} -EXPORT_SYMBOL_GPL(rhashtable_walk_enter); - -/** - * rhashtable_walk_exit - Free an iterator - * @iter: Hash table Iterator - * - * This function frees resources allocated by rhashtable_walk_init. - */ -void rhashtable_walk_exit(struct rhashtable_iter *iter) -{ - spin_lock(&iter->ht->lock); - if (iter->walker.tbl) - list_del(&iter->walker.list); - spin_unlock(&iter->ht->lock); -} -EXPORT_SYMBOL_GPL(rhashtable_walk_exit); - -/** - * rhashtable_walk_start - Start a hash table walk - * @iter: Hash table iterator - * - * Start a hash table walk. Note that we take the RCU lock in all - * cases including when we return an error. So you must always call - * rhashtable_walk_stop to clean up. - * - * Returns zero if successful. - * - * Returns -EAGAIN if resize event occured. Note that the iterator - * will rewind back to the beginning and you may use it immediately - * by calling rhashtable_walk_next. - */ -int rhashtable_walk_start(struct rhashtable_iter *iter) - __acquires(RCU) -{ - struct rhashtable *ht = iter->ht; - - rcu_read_lock(); - - spin_lock(&ht->lock); - if (iter->walker.tbl) - list_del(&iter->walker.list); - spin_unlock(&ht->lock); - - if (!iter->walker.tbl) { - iter->walker.tbl = rht_dereference_rcu(ht->tbl, ht); - return -EAGAIN; - } - - return 0; -} -EXPORT_SYMBOL_GPL(rhashtable_walk_start); - -/** - * rhashtable_walk_next - Return the next object and advance the iterator - * @iter: Hash table iterator - * - * Note that you must call rhashtable_walk_stop when you are finished - * with the walk. - * - * Returns the next object or NULL when the end of the table is reached. - * - * Returns -EAGAIN if resize event occured. Note that the iterator - * will rewind back to the beginning and you may continue to use it. - */ -void *rhashtable_walk_next(struct rhashtable_iter *iter) -{ - struct bucket_table *tbl = iter->walker.tbl; - struct rhlist_head *list = iter->list; - struct rhashtable *ht = iter->ht; - struct rhash_head *p = iter->p; - bool rhlist = ht->rhlist; - - if (p) { - if (!rhlist || !(list = rcu_dereference(list->next))) { - p = rcu_dereference(p->next); - list = container_of(p, struct rhlist_head, rhead); - } - goto next; - } - - for (; iter->slot < tbl->size; iter->slot++) { - int skip = iter->skip; - - rht_for_each_rcu(p, tbl, iter->slot) { - if (rhlist) { - list = container_of(p, struct rhlist_head, - rhead); - do { - if (!skip) - goto next; - skip--; - list = rcu_dereference(list->next); - } while (list); - - continue; - } - if (!skip) - break; - skip--; - } - -next: - if (!rht_is_a_nulls(p)) { - iter->skip++; - iter->p = p; - iter->list = list; - return rht_obj(ht, rhlist ? &list->rhead : p); - } - - iter->skip = 0; - } - - iter->p = NULL; - - /* Ensure we see any new tables. */ - smp_rmb(); - - iter->walker.tbl = rht_dereference_rcu(tbl->future_tbl, ht); - if (iter->walker.tbl) { - iter->slot = 0; - iter->skip = 0; - return ERR_PTR(-EAGAIN); - } - - return NULL; -} -EXPORT_SYMBOL_GPL(rhashtable_walk_next); - -/** - * rhashtable_walk_stop - Finish a hash table walk - * @iter: Hash table iterator - * - * Finish a hash table walk. - */ -void rhashtable_walk_stop(struct rhashtable_iter *iter) - __releases(RCU) -{ - struct rhashtable *ht; - struct bucket_table *tbl = iter->walker.tbl; - - if (!tbl) - goto out; - - ht = iter->ht; - - spin_lock(&ht->lock); - if (tbl->rehash < tbl->size) - list_add(&iter->walker.list, &tbl->walkers); - else - iter->walker.tbl = NULL; - spin_unlock(&ht->lock); - - iter->p = NULL; - -out: - rcu_read_unlock(); -} -EXPORT_SYMBOL_GPL(rhashtable_walk_stop); - -static size_t rounded_hashtable_size(const struct rhashtable_params *params) -{ - return max(roundup_pow_of_two(params->nelem_hint * 4 / 3), - (unsigned long)params->min_size); -} - -static u32 rhashtable_jhash2(const void *key, u32 length, u32 seed) -{ - return jhash2(key, length, seed); -} - -/** - * rhashtable_init - initialize a new hash table - * @ht: hash table to be initialized - * @params: configuration parameters - * - * Initializes a new hash table based on the provided configuration - * parameters. A table can be configured either with a variable or - * fixed length key: - * - * Configuration Example 1: Fixed length keys - * struct test_obj { - * int key; - * void * my_member; - * struct rhash_head node; - * }; - * - * struct rhashtable_params params = { - * .head_offset = offsetof(struct test_obj, node), - * .key_offset = offsetof(struct test_obj, key), - * .key_len = sizeof(int), - * .hashfn = jhash, - * .nulls_base = (1U << RHT_BASE_SHIFT), - * }; - * - * Configuration Example 2: Variable length keys - * struct test_obj { - * [...] - * struct rhash_head node; - * }; - * - * u32 my_hash_fn(const void *data, u32 len, u32 seed) - * { - * struct test_obj *obj = data; - * - * return [... hash ...]; - * } - * - * struct rhashtable_params params = { - * .head_offset = offsetof(struct test_obj, node), - * .hashfn = jhash, - * .obj_hashfn = my_hash_fn, - * }; - */ -int rhashtable_init(struct rhashtable *ht, - const struct rhashtable_params *params) -{ - struct bucket_table *tbl; - size_t size; - - size = HASH_DEFAULT_SIZE; - - if ((!params->key_len && !params->obj_hashfn) || - (params->obj_hashfn && !params->obj_cmpfn)) - return -EINVAL; - - if (params->nulls_base && params->nulls_base < (1U << RHT_BASE_SHIFT)) - return -EINVAL; - - memset(ht, 0, sizeof(*ht)); - mutex_init(&ht->mutex); - spin_lock_init(&ht->lock); - memcpy(&ht->p, params, sizeof(*params)); - - if (params->min_size) - ht->p.min_size = roundup_pow_of_two(params->min_size); - - if (params->max_size) - ht->p.max_size = rounddown_pow_of_two(params->max_size); - - if (params->insecure_max_entries) - ht->p.insecure_max_entries = - rounddown_pow_of_two(params->insecure_max_entries); - else - ht->p.insecure_max_entries = ht->p.max_size * 2; - - ht->p.min_size = max(ht->p.min_size, HASH_MIN_SIZE); - - if (params->nelem_hint) - size = rounded_hashtable_size(&ht->p); - - /* The maximum (not average) chain length grows with the - * size of the hash table, at a rate of (log N)/(log log N). - * The value of 16 is selected so that even if the hash - * table grew to 2^32 you would not expect the maximum - * chain length to exceed it unless we are under attack - * (or extremely unlucky). - * - * As this limit is only to detect attacks, we don't need - * to set it to a lower value as you'd need the chain - * length to vastly exceed 16 to have any real effect - * on the system. - */ - if (!params->insecure_elasticity) - ht->elasticity = 16; - - if (params->locks_mul) - ht->p.locks_mul = roundup_pow_of_two(params->locks_mul); - else - ht->p.locks_mul = BUCKET_LOCKS_PER_CPU; - - ht->key_len = ht->p.key_len; - if (!params->hashfn) { - ht->p.hashfn = jhash; - - if (!(ht->key_len & (sizeof(u32) - 1))) { - ht->key_len /= sizeof(u32); - ht->p.hashfn = rhashtable_jhash2; - } - } - - tbl = bucket_table_alloc(ht, size, GFP_KERNEL); - if (tbl == NULL) - return -ENOMEM; - - atomic_set(&ht->nelems, 0); - - RCU_INIT_POINTER(ht->tbl, tbl); - - INIT_WORK(&ht->run_work, rht_deferred_worker); - - return 0; -} -EXPORT_SYMBOL_GPL(rhashtable_init); - -/** - * rhltable_init - initialize a new hash list table - * @hlt: hash list table to be initialized - * @params: configuration parameters - * - * Initializes a new hash list table. - * - * See documentation for rhashtable_init. - */ -int rhltable_init(struct rhltable *hlt, const struct rhashtable_params *params) -{ - int err; - - /* No rhlist NULLs marking for now. */ - if (params->nulls_base) - return -EINVAL; - - err = rhashtable_init(&hlt->ht, params); - hlt->ht.rhlist = true; - return err; -} -EXPORT_SYMBOL_GPL(rhltable_init); - -static void rhashtable_free_one(struct rhashtable *ht, struct rhash_head *obj, - void (*free_fn)(void *ptr, void *arg), - void *arg) -{ - struct rhlist_head *list; - - if (!ht->rhlist) { - free_fn(rht_obj(ht, obj), arg); - return; - } - - list = container_of(obj, struct rhlist_head, rhead); - do { - obj = &list->rhead; - list = rht_dereference(list->next, ht); - free_fn(rht_obj(ht, obj), arg); - } while (list); -} - -/** - * rhashtable_free_and_destroy - free elements and destroy hash table - * @ht: the hash table to destroy - * @free_fn: callback to release resources of element - * @arg: pointer passed to free_fn - * - * Stops an eventual async resize. If defined, invokes free_fn for each - * element to releasal resources. Please note that RCU protected - * readers may still be accessing the elements. Releasing of resources - * must occur in a compatible manner. Then frees the bucket array. - * - * This function will eventually sleep to wait for an async resize - * to complete. The caller is responsible that no further write operations - * occurs in parallel. - */ -void rhashtable_free_and_destroy(struct rhashtable *ht, - void (*free_fn)(void *ptr, void *arg), - void *arg) -{ - const struct bucket_table *tbl; - unsigned int i; - - cancel_work_sync(&ht->run_work); - - mutex_lock(&ht->mutex); - tbl = rht_dereference(ht->tbl, ht); - if (free_fn) { - for (i = 0; i < tbl->size; i++) { - struct rhash_head *pos, *next; - - for (pos = rht_dereference(tbl->buckets[i], ht), - next = !rht_is_a_nulls(pos) ? - rht_dereference(pos->next, ht) : NULL; - !rht_is_a_nulls(pos); - pos = next, - next = !rht_is_a_nulls(pos) ? - rht_dereference(pos->next, ht) : NULL) - rhashtable_free_one(ht, pos, free_fn, arg); - } - } - - bucket_table_free(tbl); - mutex_unlock(&ht->mutex); -} -EXPORT_SYMBOL_GPL(rhashtable_free_and_destroy); - -void rhashtable_destroy(struct rhashtable *ht) -{ - return rhashtable_free_and_destroy(ht, NULL, NULL); -} -EXPORT_SYMBOL_GPL(rhashtable_destroy); diff --git a/src/linux/lib/sbitmap.c b/src/linux/lib/sbitmap.c deleted file mode 100644 index 2cecf05..0000000 --- a/src/linux/lib/sbitmap.c +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (C) 2016 Facebook - * Copyright (C) 2013-2014 Jens Axboe - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License v2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include -#include - -int sbitmap_init_node(struct sbitmap *sb, unsigned int depth, int shift, - gfp_t flags, int node) -{ - unsigned int bits_per_word; - unsigned int i; - - if (shift < 0) { - shift = ilog2(BITS_PER_LONG); - /* - * If the bitmap is small, shrink the number of bits per word so - * we spread over a few cachelines, at least. If less than 4 - * bits, just forget about it, it's not going to work optimally - * anyway. - */ - if (depth >= 4) { - while ((4U << shift) > depth) - shift--; - } - } - bits_per_word = 1U << shift; - if (bits_per_word > BITS_PER_LONG) - return -EINVAL; - - sb->shift = shift; - sb->depth = depth; - sb->map_nr = DIV_ROUND_UP(sb->depth, bits_per_word); - - if (depth == 0) { - sb->map = NULL; - return 0; - } - - sb->map = kzalloc_node(sb->map_nr * sizeof(*sb->map), flags, node); - if (!sb->map) - return -ENOMEM; - - for (i = 0; i < sb->map_nr; i++) { - sb->map[i].depth = min(depth, bits_per_word); - depth -= sb->map[i].depth; - } - return 0; -} -EXPORT_SYMBOL_GPL(sbitmap_init_node); - -void sbitmap_resize(struct sbitmap *sb, unsigned int depth) -{ - unsigned int bits_per_word = 1U << sb->shift; - unsigned int i; - - sb->depth = depth; - sb->map_nr = DIV_ROUND_UP(sb->depth, bits_per_word); - - for (i = 0; i < sb->map_nr; i++) { - sb->map[i].depth = min(depth, bits_per_word); - depth -= sb->map[i].depth; - } -} -EXPORT_SYMBOL_GPL(sbitmap_resize); - -static int __sbitmap_get_word(struct sbitmap_word *word, unsigned int hint, - bool wrap) -{ - unsigned int orig_hint = hint; - int nr; - - while (1) { - nr = find_next_zero_bit(&word->word, word->depth, hint); - if (unlikely(nr >= word->depth)) { - /* - * We started with an offset, and we didn't reset the - * offset to 0 in a failure case, so start from 0 to - * exhaust the map. - */ - if (orig_hint && hint && wrap) { - hint = orig_hint = 0; - continue; - } - return -1; - } - - if (!test_and_set_bit(nr, &word->word)) - break; - - hint = nr + 1; - if (hint >= word->depth - 1) - hint = 0; - } - - return nr; -} - -int sbitmap_get(struct sbitmap *sb, unsigned int alloc_hint, bool round_robin) -{ - unsigned int i, index; - int nr = -1; - - index = SB_NR_TO_INDEX(sb, alloc_hint); - - for (i = 0; i < sb->map_nr; i++) { - nr = __sbitmap_get_word(&sb->map[index], - SB_NR_TO_BIT(sb, alloc_hint), - !round_robin); - if (nr != -1) { - nr += index << sb->shift; - break; - } - - /* Jump to next index. */ - index++; - alloc_hint = index << sb->shift; - - if (index >= sb->map_nr) { - index = 0; - alloc_hint = 0; - } - } - - return nr; -} -EXPORT_SYMBOL_GPL(sbitmap_get); - -bool sbitmap_any_bit_set(const struct sbitmap *sb) -{ - unsigned int i; - - for (i = 0; i < sb->map_nr; i++) { - if (sb->map[i].word) - return true; - } - return false; -} -EXPORT_SYMBOL_GPL(sbitmap_any_bit_set); - -bool sbitmap_any_bit_clear(const struct sbitmap *sb) -{ - unsigned int i; - - for (i = 0; i < sb->map_nr; i++) { - const struct sbitmap_word *word = &sb->map[i]; - unsigned long ret; - - ret = find_first_zero_bit(&word->word, word->depth); - if (ret < word->depth) - return true; - } - return false; -} -EXPORT_SYMBOL_GPL(sbitmap_any_bit_clear); - -unsigned int sbitmap_weight(const struct sbitmap *sb) -{ - unsigned int i, weight = 0; - - for (i = 0; i < sb->map_nr; i++) { - const struct sbitmap_word *word = &sb->map[i]; - - weight += bitmap_weight(&word->word, word->depth); - } - return weight; -} -EXPORT_SYMBOL_GPL(sbitmap_weight); - -static unsigned int sbq_calc_wake_batch(unsigned int depth) -{ - unsigned int wake_batch; - - /* - * For each batch, we wake up one queue. We need to make sure that our - * batch size is small enough that the full depth of the bitmap is - * enough to wake up all of the queues. - */ - wake_batch = SBQ_WAKE_BATCH; - if (wake_batch > depth / SBQ_WAIT_QUEUES) - wake_batch = max(1U, depth / SBQ_WAIT_QUEUES); - - return wake_batch; -} - -int sbitmap_queue_init_node(struct sbitmap_queue *sbq, unsigned int depth, - int shift, bool round_robin, gfp_t flags, int node) -{ - int ret; - int i; - - ret = sbitmap_init_node(&sbq->sb, depth, shift, flags, node); - if (ret) - return ret; - - sbq->alloc_hint = alloc_percpu_gfp(unsigned int, flags); - if (!sbq->alloc_hint) { - sbitmap_free(&sbq->sb); - return -ENOMEM; - } - - if (depth && !round_robin) { - for_each_possible_cpu(i) - *per_cpu_ptr(sbq->alloc_hint, i) = prandom_u32() % depth; - } - - sbq->wake_batch = sbq_calc_wake_batch(depth); - atomic_set(&sbq->wake_index, 0); - - sbq->ws = kzalloc_node(SBQ_WAIT_QUEUES * sizeof(*sbq->ws), flags, node); - if (!sbq->ws) { - free_percpu(sbq->alloc_hint); - sbitmap_free(&sbq->sb); - return -ENOMEM; - } - - for (i = 0; i < SBQ_WAIT_QUEUES; i++) { - init_waitqueue_head(&sbq->ws[i].wait); - atomic_set(&sbq->ws[i].wait_cnt, sbq->wake_batch); - } - - sbq->round_robin = round_robin; - return 0; -} -EXPORT_SYMBOL_GPL(sbitmap_queue_init_node); - -void sbitmap_queue_resize(struct sbitmap_queue *sbq, unsigned int depth) -{ - sbq->wake_batch = sbq_calc_wake_batch(depth); - sbitmap_resize(&sbq->sb, depth); -} -EXPORT_SYMBOL_GPL(sbitmap_queue_resize); - -int __sbitmap_queue_get(struct sbitmap_queue *sbq) -{ - unsigned int hint, depth; - int nr; - - hint = this_cpu_read(*sbq->alloc_hint); - depth = READ_ONCE(sbq->sb.depth); - if (unlikely(hint >= depth)) { - hint = depth ? prandom_u32() % depth : 0; - this_cpu_write(*sbq->alloc_hint, hint); - } - nr = sbitmap_get(&sbq->sb, hint, sbq->round_robin); - - if (nr == -1) { - /* If the map is full, a hint won't do us much good. */ - this_cpu_write(*sbq->alloc_hint, 0); - } else if (nr == hint || unlikely(sbq->round_robin)) { - /* Only update the hint if we used it. */ - hint = nr + 1; - if (hint >= depth - 1) - hint = 0; - this_cpu_write(*sbq->alloc_hint, hint); - } - - return nr; -} -EXPORT_SYMBOL_GPL(__sbitmap_queue_get); - -static struct sbq_wait_state *sbq_wake_ptr(struct sbitmap_queue *sbq) -{ - int i, wake_index; - - wake_index = atomic_read(&sbq->wake_index); - for (i = 0; i < SBQ_WAIT_QUEUES; i++) { - struct sbq_wait_state *ws = &sbq->ws[wake_index]; - - if (waitqueue_active(&ws->wait)) { - int o = atomic_read(&sbq->wake_index); - - if (wake_index != o) - atomic_cmpxchg(&sbq->wake_index, o, wake_index); - return ws; - } - - wake_index = sbq_index_inc(wake_index); - } - - return NULL; -} - -static void sbq_wake_up(struct sbitmap_queue *sbq) -{ - struct sbq_wait_state *ws; - int wait_cnt; - - /* Ensure that the wait list checks occur after clear_bit(). */ - smp_mb(); - - ws = sbq_wake_ptr(sbq); - if (!ws) - return; - - wait_cnt = atomic_dec_return(&ws->wait_cnt); - if (unlikely(wait_cnt < 0)) - wait_cnt = atomic_inc_return(&ws->wait_cnt); - if (wait_cnt == 0) { - atomic_add(sbq->wake_batch, &ws->wait_cnt); - sbq_index_atomic_inc(&sbq->wake_index); - wake_up(&ws->wait); - } -} - -void sbitmap_queue_clear(struct sbitmap_queue *sbq, unsigned int nr, - unsigned int cpu) -{ - sbitmap_clear_bit(&sbq->sb, nr); - sbq_wake_up(sbq); - if (likely(!sbq->round_robin && nr < sbq->sb.depth)) - *per_cpu_ptr(sbq->alloc_hint, cpu) = nr; -} -EXPORT_SYMBOL_GPL(sbitmap_queue_clear); - -void sbitmap_queue_wake_all(struct sbitmap_queue *sbq) -{ - int i, wake_index; - - /* - * Make sure all changes prior to this are visible from other CPUs. - */ - smp_mb(); - wake_index = atomic_read(&sbq->wake_index); - for (i = 0; i < SBQ_WAIT_QUEUES; i++) { - struct sbq_wait_state *ws = &sbq->ws[wake_index]; - - if (waitqueue_active(&ws->wait)) - wake_up(&ws->wait); - - wake_index = sbq_index_inc(wake_index); - } -} -EXPORT_SYMBOL_GPL(sbitmap_queue_wake_all); diff --git a/src/linux/lib/scatterlist.c b/src/linux/lib/scatterlist.c deleted file mode 100644 index 004fc70..0000000 --- a/src/linux/lib/scatterlist.c +++ /dev/null @@ -1,757 +0,0 @@ -/* - * Copyright (C) 2007 Jens Axboe - * - * Scatterlist handling helpers. - * - * This source code is licensed under the GNU General Public License, - * Version 2. See the file COPYING for more details. - */ -#include -#include -#include -#include -#include - -/** - * sg_next - return the next scatterlist entry in a list - * @sg: The current sg entry - * - * Description: - * Usually the next entry will be @sg@ + 1, but if this sg element is part - * of a chained scatterlist, it could jump to the start of a new - * scatterlist array. - * - **/ -struct scatterlist *sg_next(struct scatterlist *sg) -{ -#ifdef CONFIG_DEBUG_SG - BUG_ON(sg->sg_magic != SG_MAGIC); -#endif - if (sg_is_last(sg)) - return NULL; - - sg++; - if (unlikely(sg_is_chain(sg))) - sg = sg_chain_ptr(sg); - - return sg; -} -EXPORT_SYMBOL(sg_next); - -/** - * sg_nents - return total count of entries in scatterlist - * @sg: The scatterlist - * - * Description: - * Allows to know how many entries are in sg, taking into acount - * chaining as well - * - **/ -int sg_nents(struct scatterlist *sg) -{ - int nents; - for (nents = 0; sg; sg = sg_next(sg)) - nents++; - return nents; -} -EXPORT_SYMBOL(sg_nents); - -/** - * sg_nents_for_len - return total count of entries in scatterlist - * needed to satisfy the supplied length - * @sg: The scatterlist - * @len: The total required length - * - * Description: - * Determines the number of entries in sg that are required to meet - * the supplied length, taking into acount chaining as well - * - * Returns: - * the number of sg entries needed, negative error on failure - * - **/ -int sg_nents_for_len(struct scatterlist *sg, u64 len) -{ - int nents; - u64 total; - - if (!len) - return 0; - - for (nents = 0, total = 0; sg; sg = sg_next(sg)) { - nents++; - total += sg->length; - if (total >= len) - return nents; - } - - return -EINVAL; -} -EXPORT_SYMBOL(sg_nents_for_len); - -/** - * sg_last - return the last scatterlist entry in a list - * @sgl: First entry in the scatterlist - * @nents: Number of entries in the scatterlist - * - * Description: - * Should only be used casually, it (currently) scans the entire list - * to get the last entry. - * - * Note that the @sgl@ pointer passed in need not be the first one, - * the important bit is that @nents@ denotes the number of entries that - * exist from @sgl@. - * - **/ -struct scatterlist *sg_last(struct scatterlist *sgl, unsigned int nents) -{ - struct scatterlist *sg, *ret = NULL; - unsigned int i; - - for_each_sg(sgl, sg, nents, i) - ret = sg; - -#ifdef CONFIG_DEBUG_SG - BUG_ON(sgl[0].sg_magic != SG_MAGIC); - BUG_ON(!sg_is_last(ret)); -#endif - return ret; -} -EXPORT_SYMBOL(sg_last); - -/** - * sg_init_table - Initialize SG table - * @sgl: The SG table - * @nents: Number of entries in table - * - * Notes: - * If this is part of a chained sg table, sg_mark_end() should be - * used only on the last table part. - * - **/ -void sg_init_table(struct scatterlist *sgl, unsigned int nents) -{ - memset(sgl, 0, sizeof(*sgl) * nents); -#ifdef CONFIG_DEBUG_SG - { - unsigned int i; - for (i = 0; i < nents; i++) - sgl[i].sg_magic = SG_MAGIC; - } -#endif - sg_mark_end(&sgl[nents - 1]); -} -EXPORT_SYMBOL(sg_init_table); - -/** - * sg_init_one - Initialize a single entry sg list - * @sg: SG entry - * @buf: Virtual address for IO - * @buflen: IO length - * - **/ -void sg_init_one(struct scatterlist *sg, const void *buf, unsigned int buflen) -{ - sg_init_table(sg, 1); - sg_set_buf(sg, buf, buflen); -} -EXPORT_SYMBOL(sg_init_one); - -/* - * The default behaviour of sg_alloc_table() is to use these kmalloc/kfree - * helpers. - */ -static struct scatterlist *sg_kmalloc(unsigned int nents, gfp_t gfp_mask) -{ - if (nents == SG_MAX_SINGLE_ALLOC) { - /* - * Kmemleak doesn't track page allocations as they are not - * commonly used (in a raw form) for kernel data structures. - * As we chain together a list of pages and then a normal - * kmalloc (tracked by kmemleak), in order to for that last - * allocation not to become decoupled (and thus a - * false-positive) we need to inform kmemleak of all the - * intermediate allocations. - */ - void *ptr = (void *) __get_free_page(gfp_mask); - kmemleak_alloc(ptr, PAGE_SIZE, 1, gfp_mask); - return ptr; - } else - return kmalloc(nents * sizeof(struct scatterlist), gfp_mask); -} - -static void sg_kfree(struct scatterlist *sg, unsigned int nents) -{ - if (nents == SG_MAX_SINGLE_ALLOC) { - kmemleak_free(sg); - free_page((unsigned long) sg); - } else - kfree(sg); -} - -/** - * __sg_free_table - Free a previously mapped sg table - * @table: The sg table header to use - * @max_ents: The maximum number of entries per single scatterlist - * @skip_first_chunk: don't free the (preallocated) first scatterlist chunk - * @free_fn: Free function - * - * Description: - * Free an sg table previously allocated and setup with - * __sg_alloc_table(). The @max_ents value must be identical to - * that previously used with __sg_alloc_table(). - * - **/ -void __sg_free_table(struct sg_table *table, unsigned int max_ents, - bool skip_first_chunk, sg_free_fn *free_fn) -{ - struct scatterlist *sgl, *next; - - if (unlikely(!table->sgl)) - return; - - sgl = table->sgl; - while (table->orig_nents) { - unsigned int alloc_size = table->orig_nents; - unsigned int sg_size; - - /* - * If we have more than max_ents segments left, - * then assign 'next' to the sg table after the current one. - * sg_size is then one less than alloc size, since the last - * element is the chain pointer. - */ - if (alloc_size > max_ents) { - next = sg_chain_ptr(&sgl[max_ents - 1]); - alloc_size = max_ents; - sg_size = alloc_size - 1; - } else { - sg_size = alloc_size; - next = NULL; - } - - table->orig_nents -= sg_size; - if (skip_first_chunk) - skip_first_chunk = false; - else - free_fn(sgl, alloc_size); - sgl = next; - } - - table->sgl = NULL; -} -EXPORT_SYMBOL(__sg_free_table); - -/** - * sg_free_table - Free a previously allocated sg table - * @table: The mapped sg table header - * - **/ -void sg_free_table(struct sg_table *table) -{ - __sg_free_table(table, SG_MAX_SINGLE_ALLOC, false, sg_kfree); -} -EXPORT_SYMBOL(sg_free_table); - -/** - * __sg_alloc_table - Allocate and initialize an sg table with given allocator - * @table: The sg table header to use - * @nents: Number of entries in sg list - * @max_ents: The maximum number of entries the allocator returns per call - * @gfp_mask: GFP allocation mask - * @alloc_fn: Allocator to use - * - * Description: - * This function returns a @table @nents long. The allocator is - * defined to return scatterlist chunks of maximum size @max_ents. - * Thus if @nents is bigger than @max_ents, the scatterlists will be - * chained in units of @max_ents. - * - * Notes: - * If this function returns non-0 (eg failure), the caller must call - * __sg_free_table() to cleanup any leftover allocations. - * - **/ -int __sg_alloc_table(struct sg_table *table, unsigned int nents, - unsigned int max_ents, struct scatterlist *first_chunk, - gfp_t gfp_mask, sg_alloc_fn *alloc_fn) -{ - struct scatterlist *sg, *prv; - unsigned int left; - - memset(table, 0, sizeof(*table)); - - if (nents == 0) - return -EINVAL; -#ifndef CONFIG_ARCH_HAS_SG_CHAIN - if (WARN_ON_ONCE(nents > max_ents)) - return -EINVAL; -#endif - - left = nents; - prv = NULL; - do { - unsigned int sg_size, alloc_size = left; - - if (alloc_size > max_ents) { - alloc_size = max_ents; - sg_size = alloc_size - 1; - } else - sg_size = alloc_size; - - left -= sg_size; - - if (first_chunk) { - sg = first_chunk; - first_chunk = NULL; - } else { - sg = alloc_fn(alloc_size, gfp_mask); - } - if (unlikely(!sg)) { - /* - * Adjust entry count to reflect that the last - * entry of the previous table won't be used for - * linkage. Without this, sg_kfree() may get - * confused. - */ - if (prv) - table->nents = ++table->orig_nents; - - return -ENOMEM; - } - - sg_init_table(sg, alloc_size); - table->nents = table->orig_nents += sg_size; - - /* - * If this is the first mapping, assign the sg table header. - * If this is not the first mapping, chain previous part. - */ - if (prv) - sg_chain(prv, max_ents, sg); - else - table->sgl = sg; - - /* - * If no more entries after this one, mark the end - */ - if (!left) - sg_mark_end(&sg[sg_size - 1]); - - prv = sg; - } while (left); - - return 0; -} -EXPORT_SYMBOL(__sg_alloc_table); - -/** - * sg_alloc_table - Allocate and initialize an sg table - * @table: The sg table header to use - * @nents: Number of entries in sg list - * @gfp_mask: GFP allocation mask - * - * Description: - * Allocate and initialize an sg table. If @nents@ is larger than - * SG_MAX_SINGLE_ALLOC a chained sg table will be setup. - * - **/ -int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask) -{ - int ret; - - ret = __sg_alloc_table(table, nents, SG_MAX_SINGLE_ALLOC, - NULL, gfp_mask, sg_kmalloc); - if (unlikely(ret)) - __sg_free_table(table, SG_MAX_SINGLE_ALLOC, false, sg_kfree); - - return ret; -} -EXPORT_SYMBOL(sg_alloc_table); - -/** - * sg_alloc_table_from_pages - Allocate and initialize an sg table from - * an array of pages - * @sgt: The sg table header to use - * @pages: Pointer to an array of page pointers - * @n_pages: Number of pages in the pages array - * @offset: Offset from start of the first page to the start of a buffer - * @size: Number of valid bytes in the buffer (after offset) - * @gfp_mask: GFP allocation mask - * - * Description: - * Allocate and initialize an sg table from a list of pages. Contiguous - * ranges of the pages are squashed into a single scatterlist node. A user - * may provide an offset at a start and a size of valid data in a buffer - * specified by the page array. The returned sg table is released by - * sg_free_table. - * - * Returns: - * 0 on success, negative error on failure - */ -int sg_alloc_table_from_pages(struct sg_table *sgt, - struct page **pages, unsigned int n_pages, - unsigned long offset, unsigned long size, - gfp_t gfp_mask) -{ - unsigned int chunks; - unsigned int i; - unsigned int cur_page; - int ret; - struct scatterlist *s; - - /* compute number of contiguous chunks */ - chunks = 1; - for (i = 1; i < n_pages; ++i) - if (page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1) - ++chunks; - - ret = sg_alloc_table(sgt, chunks, gfp_mask); - if (unlikely(ret)) - return ret; - - /* merging chunks and putting them into the scatterlist */ - cur_page = 0; - for_each_sg(sgt->sgl, s, sgt->orig_nents, i) { - unsigned long chunk_size; - unsigned int j; - - /* look for the end of the current chunk */ - for (j = cur_page + 1; j < n_pages; ++j) - if (page_to_pfn(pages[j]) != - page_to_pfn(pages[j - 1]) + 1) - break; - - chunk_size = ((j - cur_page) << PAGE_SHIFT) - offset; - sg_set_page(s, pages[cur_page], min(size, chunk_size), offset); - size -= chunk_size; - offset = 0; - cur_page = j; - } - - return 0; -} -EXPORT_SYMBOL(sg_alloc_table_from_pages); - -void __sg_page_iter_start(struct sg_page_iter *piter, - struct scatterlist *sglist, unsigned int nents, - unsigned long pgoffset) -{ - piter->__pg_advance = 0; - piter->__nents = nents; - - piter->sg = sglist; - piter->sg_pgoffset = pgoffset; -} -EXPORT_SYMBOL(__sg_page_iter_start); - -static int sg_page_count(struct scatterlist *sg) -{ - return PAGE_ALIGN(sg->offset + sg->length) >> PAGE_SHIFT; -} - -bool __sg_page_iter_next(struct sg_page_iter *piter) -{ - if (!piter->__nents || !piter->sg) - return false; - - piter->sg_pgoffset += piter->__pg_advance; - piter->__pg_advance = 1; - - while (piter->sg_pgoffset >= sg_page_count(piter->sg)) { - piter->sg_pgoffset -= sg_page_count(piter->sg); - piter->sg = sg_next(piter->sg); - if (!--piter->__nents || !piter->sg) - return false; - } - - return true; -} -EXPORT_SYMBOL(__sg_page_iter_next); - -/** - * sg_miter_start - start mapping iteration over a sg list - * @miter: sg mapping iter to be started - * @sgl: sg list to iterate over - * @nents: number of sg entries - * - * Description: - * Starts mapping iterator @miter. - * - * Context: - * Don't care. - */ -void sg_miter_start(struct sg_mapping_iter *miter, struct scatterlist *sgl, - unsigned int nents, unsigned int flags) -{ - memset(miter, 0, sizeof(struct sg_mapping_iter)); - - __sg_page_iter_start(&miter->piter, sgl, nents, 0); - WARN_ON(!(flags & (SG_MITER_TO_SG | SG_MITER_FROM_SG))); - miter->__flags = flags; -} -EXPORT_SYMBOL(sg_miter_start); - -static bool sg_miter_get_next_page(struct sg_mapping_iter *miter) -{ - if (!miter->__remaining) { - struct scatterlist *sg; - unsigned long pgoffset; - - if (!__sg_page_iter_next(&miter->piter)) - return false; - - sg = miter->piter.sg; - pgoffset = miter->piter.sg_pgoffset; - - miter->__offset = pgoffset ? 0 : sg->offset; - miter->__remaining = sg->offset + sg->length - - (pgoffset << PAGE_SHIFT) - miter->__offset; - miter->__remaining = min_t(unsigned long, miter->__remaining, - PAGE_SIZE - miter->__offset); - } - - return true; -} - -/** - * sg_miter_skip - reposition mapping iterator - * @miter: sg mapping iter to be skipped - * @offset: number of bytes to plus the current location - * - * Description: - * Sets the offset of @miter to its current location plus @offset bytes. - * If mapping iterator @miter has been proceeded by sg_miter_next(), this - * stops @miter. - * - * Context: - * Don't care if @miter is stopped, or not proceeded yet. - * Otherwise, preemption disabled if the SG_MITER_ATOMIC is set. - * - * Returns: - * true if @miter contains the valid mapping. false if end of sg - * list is reached. - */ -bool sg_miter_skip(struct sg_mapping_iter *miter, off_t offset) -{ - sg_miter_stop(miter); - - while (offset) { - off_t consumed; - - if (!sg_miter_get_next_page(miter)) - return false; - - consumed = min_t(off_t, offset, miter->__remaining); - miter->__offset += consumed; - miter->__remaining -= consumed; - offset -= consumed; - } - - return true; -} -EXPORT_SYMBOL(sg_miter_skip); - -/** - * sg_miter_next - proceed mapping iterator to the next mapping - * @miter: sg mapping iter to proceed - * - * Description: - * Proceeds @miter to the next mapping. @miter should have been started - * using sg_miter_start(). On successful return, @miter->page, - * @miter->addr and @miter->length point to the current mapping. - * - * Context: - * Preemption disabled if SG_MITER_ATOMIC. Preemption must stay disabled - * till @miter is stopped. May sleep if !SG_MITER_ATOMIC. - * - * Returns: - * true if @miter contains the next mapping. false if end of sg - * list is reached. - */ -bool sg_miter_next(struct sg_mapping_iter *miter) -{ - sg_miter_stop(miter); - - /* - * Get to the next page if necessary. - * __remaining, __offset is adjusted by sg_miter_stop - */ - if (!sg_miter_get_next_page(miter)) - return false; - - miter->page = sg_page_iter_page(&miter->piter); - miter->consumed = miter->length = miter->__remaining; - - if (miter->__flags & SG_MITER_ATOMIC) - miter->addr = kmap_atomic(miter->page) + miter->__offset; - else - miter->addr = kmap(miter->page) + miter->__offset; - - return true; -} -EXPORT_SYMBOL(sg_miter_next); - -/** - * sg_miter_stop - stop mapping iteration - * @miter: sg mapping iter to be stopped - * - * Description: - * Stops mapping iterator @miter. @miter should have been started - * using sg_miter_start(). A stopped iteration can be resumed by - * calling sg_miter_next() on it. This is useful when resources (kmap) - * need to be released during iteration. - * - * Context: - * Preemption disabled if the SG_MITER_ATOMIC is set. Don't care - * otherwise. - */ -void sg_miter_stop(struct sg_mapping_iter *miter) -{ - WARN_ON(miter->consumed > miter->length); - - /* drop resources from the last iteration */ - if (miter->addr) { - miter->__offset += miter->consumed; - miter->__remaining -= miter->consumed; - - if ((miter->__flags & SG_MITER_TO_SG) && - !PageSlab(miter->page)) - flush_kernel_dcache_page(miter->page); - - if (miter->__flags & SG_MITER_ATOMIC) { - WARN_ON_ONCE(preemptible()); - kunmap_atomic(miter->addr); - } else - kunmap(miter->page); - - miter->page = NULL; - miter->addr = NULL; - miter->length = 0; - miter->consumed = 0; - } -} -EXPORT_SYMBOL(sg_miter_stop); - -/** - * sg_copy_buffer - Copy data between a linear buffer and an SG list - * @sgl: The SG list - * @nents: Number of SG entries - * @buf: Where to copy from - * @buflen: The number of bytes to copy - * @skip: Number of bytes to skip before copying - * @to_buffer: transfer direction (true == from an sg list to a - * buffer, false == from a buffer to an sg list - * - * Returns the number of copied bytes. - * - **/ -size_t sg_copy_buffer(struct scatterlist *sgl, unsigned int nents, void *buf, - size_t buflen, off_t skip, bool to_buffer) -{ - unsigned int offset = 0; - struct sg_mapping_iter miter; - unsigned long flags; - unsigned int sg_flags = SG_MITER_ATOMIC; - - if (to_buffer) - sg_flags |= SG_MITER_FROM_SG; - else - sg_flags |= SG_MITER_TO_SG; - - sg_miter_start(&miter, sgl, nents, sg_flags); - - if (!sg_miter_skip(&miter, skip)) - return false; - - local_irq_save(flags); - - while (sg_miter_next(&miter) && offset < buflen) { - unsigned int len; - - len = min(miter.length, buflen - offset); - - if (to_buffer) - memcpy(buf + offset, miter.addr, len); - else - memcpy(miter.addr, buf + offset, len); - - offset += len; - } - - sg_miter_stop(&miter); - - local_irq_restore(flags); - return offset; -} -EXPORT_SYMBOL(sg_copy_buffer); - -/** - * sg_copy_from_buffer - Copy from a linear buffer to an SG list - * @sgl: The SG list - * @nents: Number of SG entries - * @buf: Where to copy from - * @buflen: The number of bytes to copy - * - * Returns the number of copied bytes. - * - **/ -size_t sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents, - const void *buf, size_t buflen) -{ - return sg_copy_buffer(sgl, nents, (void *)buf, buflen, 0, false); -} -EXPORT_SYMBOL(sg_copy_from_buffer); - -/** - * sg_copy_to_buffer - Copy from an SG list to a linear buffer - * @sgl: The SG list - * @nents: Number of SG entries - * @buf: Where to copy to - * @buflen: The number of bytes to copy - * - * Returns the number of copied bytes. - * - **/ -size_t sg_copy_to_buffer(struct scatterlist *sgl, unsigned int nents, - void *buf, size_t buflen) -{ - return sg_copy_buffer(sgl, nents, buf, buflen, 0, true); -} -EXPORT_SYMBOL(sg_copy_to_buffer); - -/** - * sg_pcopy_from_buffer - Copy from a linear buffer to an SG list - * @sgl: The SG list - * @nents: Number of SG entries - * @buf: Where to copy from - * @buflen: The number of bytes to copy - * @skip: Number of bytes to skip before copying - * - * Returns the number of copied bytes. - * - **/ -size_t sg_pcopy_from_buffer(struct scatterlist *sgl, unsigned int nents, - const void *buf, size_t buflen, off_t skip) -{ - return sg_copy_buffer(sgl, nents, (void *)buf, buflen, skip, false); -} -EXPORT_SYMBOL(sg_pcopy_from_buffer); - -/** - * sg_pcopy_to_buffer - Copy from an SG list to a linear buffer - * @sgl: The SG list - * @nents: Number of SG entries - * @buf: Where to copy to - * @buflen: The number of bytes to copy - * @skip: Number of bytes to skip before copying - * - * Returns the number of copied bytes. - * - **/ -size_t sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents, - void *buf, size_t buflen, off_t skip) -{ - return sg_copy_buffer(sgl, nents, buf, buflen, skip, true); -} -EXPORT_SYMBOL(sg_pcopy_to_buffer); diff --git a/src/linux/lib/seq_buf.c b/src/linux/lib/seq_buf.c deleted file mode 100644 index cb18469..0000000 --- a/src/linux/lib/seq_buf.c +++ /dev/null @@ -1,325 +0,0 @@ -/* - * seq_buf.c - * - * Copyright (C) 2014 Red Hat Inc, Steven Rostedt - * - * The seq_buf is a handy tool that allows you to pass a descriptor around - * to a buffer that other functions can write to. It is similar to the - * seq_file functionality but has some differences. - * - * To use it, the seq_buf must be initialized with seq_buf_init(). - * This will set up the counters within the descriptor. You can call - * seq_buf_init() more than once to reset the seq_buf to start - * from scratch. - */ -#include -#include -#include - -/** - * seq_buf_can_fit - can the new data fit in the current buffer? - * @s: the seq_buf descriptor - * @len: The length to see if it can fit in the current buffer - * - * Returns true if there's enough unused space in the seq_buf buffer - * to fit the amount of new data according to @len. - */ -static bool seq_buf_can_fit(struct seq_buf *s, size_t len) -{ - return s->len + len <= s->size; -} - -/** - * seq_buf_print_seq - move the contents of seq_buf into a seq_file - * @m: the seq_file descriptor that is the destination - * @s: the seq_buf descriptor that is the source. - * - * Returns zero on success, non zero otherwise - */ -int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s) -{ - unsigned int len = seq_buf_used(s); - - return seq_write(m, s->buffer, len); -} - -/** - * seq_buf_vprintf - sequence printing of information. - * @s: seq_buf descriptor - * @fmt: printf format string - * @args: va_list of arguments from a printf() type function - * - * Writes a vnprintf() format into the sequencce buffer. - * - * Returns zero on success, -1 on overflow. - */ -int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args) -{ - int len; - - WARN_ON(s->size == 0); - - if (s->len < s->size) { - len = vsnprintf(s->buffer + s->len, s->size - s->len, fmt, args); - if (s->len + len < s->size) { - s->len += len; - return 0; - } - } - seq_buf_set_overflow(s); - return -1; -} - -/** - * seq_buf_printf - sequence printing of information - * @s: seq_buf descriptor - * @fmt: printf format string - * - * Writes a printf() format into the sequence buffer. - * - * Returns zero on success, -1 on overflow. - */ -int seq_buf_printf(struct seq_buf *s, const char *fmt, ...) -{ - va_list ap; - int ret; - - va_start(ap, fmt); - ret = seq_buf_vprintf(s, fmt, ap); - va_end(ap); - - return ret; -} - -#ifdef CONFIG_BINARY_PRINTF -/** - * seq_buf_bprintf - Write the printf string from binary arguments - * @s: seq_buf descriptor - * @fmt: The format string for the @binary arguments - * @binary: The binary arguments for @fmt. - * - * When recording in a fast path, a printf may be recorded with just - * saving the format and the arguments as they were passed to the - * function, instead of wasting cycles converting the arguments into - * ASCII characters. Instead, the arguments are saved in a 32 bit - * word array that is defined by the format string constraints. - * - * This function will take the format and the binary array and finish - * the conversion into the ASCII string within the buffer. - * - * Returns zero on success, -1 on overflow. - */ -int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary) -{ - unsigned int len = seq_buf_buffer_left(s); - int ret; - - WARN_ON(s->size == 0); - - if (s->len < s->size) { - ret = bstr_printf(s->buffer + s->len, len, fmt, binary); - if (s->len + ret < s->size) { - s->len += ret; - return 0; - } - } - seq_buf_set_overflow(s); - return -1; -} -#endif /* CONFIG_BINARY_PRINTF */ - -/** - * seq_buf_puts - sequence printing of simple string - * @s: seq_buf descriptor - * @str: simple string to record - * - * Copy a simple string into the sequence buffer. - * - * Returns zero on success, -1 on overflow - */ -int seq_buf_puts(struct seq_buf *s, const char *str) -{ - unsigned int len = strlen(str); - - WARN_ON(s->size == 0); - - if (seq_buf_can_fit(s, len)) { - memcpy(s->buffer + s->len, str, len); - s->len += len; - return 0; - } - seq_buf_set_overflow(s); - return -1; -} - -/** - * seq_buf_putc - sequence printing of simple character - * @s: seq_buf descriptor - * @c: simple character to record - * - * Copy a single character into the sequence buffer. - * - * Returns zero on success, -1 on overflow - */ -int seq_buf_putc(struct seq_buf *s, unsigned char c) -{ - WARN_ON(s->size == 0); - - if (seq_buf_can_fit(s, 1)) { - s->buffer[s->len++] = c; - return 0; - } - seq_buf_set_overflow(s); - return -1; -} - -/** - * seq_buf_putmem - write raw data into the sequenc buffer - * @s: seq_buf descriptor - * @mem: The raw memory to copy into the buffer - * @len: The length of the raw memory to copy (in bytes) - * - * There may be cases where raw memory needs to be written into the - * buffer and a strcpy() would not work. Using this function allows - * for such cases. - * - * Returns zero on success, -1 on overflow - */ -int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len) -{ - WARN_ON(s->size == 0); - - if (seq_buf_can_fit(s, len)) { - memcpy(s->buffer + s->len, mem, len); - s->len += len; - return 0; - } - seq_buf_set_overflow(s); - return -1; -} - -#define MAX_MEMHEX_BYTES 8U -#define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1) - -/** - * seq_buf_putmem_hex - write raw memory into the buffer in ASCII hex - * @s: seq_buf descriptor - * @mem: The raw memory to write its hex ASCII representation of - * @len: The length of the raw memory to copy (in bytes) - * - * This is similar to seq_buf_putmem() except instead of just copying the - * raw memory into the buffer it writes its ASCII representation of it - * in hex characters. - * - * Returns zero on success, -1 on overflow - */ -int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, - unsigned int len) -{ - unsigned char hex[HEX_CHARS]; - const unsigned char *data = mem; - unsigned int start_len; - int i, j; - - WARN_ON(s->size == 0); - - while (len) { - start_len = min(len, HEX_CHARS - 1); -#ifdef __BIG_ENDIAN - for (i = 0, j = 0; i < start_len; i++) { -#else - for (i = start_len-1, j = 0; i >= 0; i--) { -#endif - hex[j++] = hex_asc_hi(data[i]); - hex[j++] = hex_asc_lo(data[i]); - } - if (WARN_ON_ONCE(j == 0 || j/2 > len)) - break; - - /* j increments twice per loop */ - len -= j / 2; - hex[j++] = ' '; - - seq_buf_putmem(s, hex, j); - if (seq_buf_has_overflowed(s)) - return -1; - } - return 0; -} - -/** - * seq_buf_path - copy a path into the sequence buffer - * @s: seq_buf descriptor - * @path: path to write into the sequence buffer. - * @esc: set of characters to escape in the output - * - * Write a path name into the sequence buffer. - * - * Returns the number of written bytes on success, -1 on overflow - */ -int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc) -{ - char *buf; - size_t size = seq_buf_get_buf(s, &buf); - int res = -1; - - WARN_ON(s->size == 0); - - if (size) { - char *p = d_path(path, buf, size); - if (!IS_ERR(p)) { - char *end = mangle_path(buf, p, esc); - if (end) - res = end - buf; - } - } - seq_buf_commit(s, res); - - return res; -} - -/** - * seq_buf_to_user - copy the squence buffer to user space - * @s: seq_buf descriptor - * @ubuf: The userspace memory location to copy to - * @cnt: The amount to copy - * - * Copies the sequence buffer into the userspace memory pointed to - * by @ubuf. It starts from the last read position (@s->readpos) - * and writes up to @cnt characters or till it reaches the end of - * the content in the buffer (@s->len), which ever comes first. - * - * On success, it returns a positive number of the number of bytes - * it copied. - * - * On failure it returns -EBUSY if all of the content in the - * sequence has been already read, which includes nothing in the - * sequence (@s->len == @s->readpos). - * - * Returns -EFAULT if the copy to userspace fails. - */ -int seq_buf_to_user(struct seq_buf *s, char __user *ubuf, int cnt) -{ - int len; - int ret; - - if (!cnt) - return 0; - - len = seq_buf_used(s); - - if (len <= s->readpos) - return -EBUSY; - - len -= s->readpos; - if (cnt > len) - cnt = len; - ret = copy_to_user(ubuf, s->buffer + s->readpos, cnt); - if (ret == cnt) - return -EFAULT; - - cnt -= ret; - - s->readpos += cnt; - return cnt; -} diff --git a/src/linux/lib/sha1.c b/src/linux/lib/sha1.c deleted file mode 100644 index 5a56dfd..0000000 --- a/src/linux/lib/sha1.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * SHA1 routine optimized to do word accesses rather than byte accesses, - * and to avoid unnecessary copies into the context array. - * - * This was based on the git SHA1 implementation. - */ - -#include -#include -#include -#include -#include - -/* - * If you have 32 registers or more, the compiler can (and should) - * try to change the array[] accesses into registers. However, on - * machines with less than ~25 registers, that won't really work, - * and at least gcc will make an unholy mess of it. - * - * So to avoid that mess which just slows things down, we force - * the stores to memory to actually happen (we might be better off - * with a 'W(t)=(val);asm("":"+m" (W(t))' there instead, as - * suggested by Artur Skawina - that will also make gcc unable to - * try to do the silly "optimize away loads" part because it won't - * see what the value will be). - * - * Ben Herrenschmidt reports that on PPC, the C version comes close - * to the optimized asm with this (ie on PPC you don't want that - * 'volatile', since there are lots of registers). - * - * On ARM we get the best code generation by forcing a full memory barrier - * between each SHA_ROUND, otherwise gcc happily get wild with spilling and - * the stack frame size simply explode and performance goes down the drain. - */ - -#ifdef CONFIG_X86 - #define setW(x, val) (*(volatile __u32 *)&W(x) = (val)) -#elif defined(CONFIG_ARM) - #define setW(x, val) do { W(x) = (val); __asm__("":::"memory"); } while (0) -#else - #define setW(x, val) (W(x) = (val)) -#endif - -/* This "rolls" over the 512-bit array */ -#define W(x) (array[(x)&15]) - -/* - * Where do we get the source from? The first 16 iterations get it from - * the input data, the next mix it from the 512-bit array. - */ -#define SHA_SRC(t) get_unaligned_be32((__u32 *)data + t) -#define SHA_MIX(t) rol32(W(t+13) ^ W(t+8) ^ W(t+2) ^ W(t), 1) - -#define SHA_ROUND(t, input, fn, constant, A, B, C, D, E) do { \ - __u32 TEMP = input(t); setW(t, TEMP); \ - E += TEMP + rol32(A,5) + (fn) + (constant); \ - B = ror32(B, 2); } while (0) - -#define T_0_15(t, A, B, C, D, E) SHA_ROUND(t, SHA_SRC, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E ) -#define T_16_19(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (((C^D)&B)^D) , 0x5a827999, A, B, C, D, E ) -#define T_20_39(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0x6ed9eba1, A, B, C, D, E ) -#define T_40_59(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, ((B&C)+(D&(B^C))) , 0x8f1bbcdc, A, B, C, D, E ) -#define T_60_79(t, A, B, C, D, E) SHA_ROUND(t, SHA_MIX, (B^C^D) , 0xca62c1d6, A, B, C, D, E ) - -/** - * sha_transform - single block SHA1 transform - * - * @digest: 160 bit digest to update - * @data: 512 bits of data to hash - * @array: 16 words of workspace (see note) - * - * This function generates a SHA1 digest for a single 512-bit block. - * Be warned, it does not handle padding and message digest, do not - * confuse it with the full FIPS 180-1 digest algorithm for variable - * length messages. - * - * Note: If the hash is security sensitive, the caller should be sure - * to clear the workspace. This is left to the caller to avoid - * unnecessary clears between chained hashing operations. - */ -void sha_transform(__u32 *digest, const char *data, __u32 *array) -{ - __u32 A, B, C, D, E; - - A = digest[0]; - B = digest[1]; - C = digest[2]; - D = digest[3]; - E = digest[4]; - - /* Round 1 - iterations 0-16 take their input from 'data' */ - T_0_15( 0, A, B, C, D, E); - T_0_15( 1, E, A, B, C, D); - T_0_15( 2, D, E, A, B, C); - T_0_15( 3, C, D, E, A, B); - T_0_15( 4, B, C, D, E, A); - T_0_15( 5, A, B, C, D, E); - T_0_15( 6, E, A, B, C, D); - T_0_15( 7, D, E, A, B, C); - T_0_15( 8, C, D, E, A, B); - T_0_15( 9, B, C, D, E, A); - T_0_15(10, A, B, C, D, E); - T_0_15(11, E, A, B, C, D); - T_0_15(12, D, E, A, B, C); - T_0_15(13, C, D, E, A, B); - T_0_15(14, B, C, D, E, A); - T_0_15(15, A, B, C, D, E); - - /* Round 1 - tail. Input from 512-bit mixing array */ - T_16_19(16, E, A, B, C, D); - T_16_19(17, D, E, A, B, C); - T_16_19(18, C, D, E, A, B); - T_16_19(19, B, C, D, E, A); - - /* Round 2 */ - T_20_39(20, A, B, C, D, E); - T_20_39(21, E, A, B, C, D); - T_20_39(22, D, E, A, B, C); - T_20_39(23, C, D, E, A, B); - T_20_39(24, B, C, D, E, A); - T_20_39(25, A, B, C, D, E); - T_20_39(26, E, A, B, C, D); - T_20_39(27, D, E, A, B, C); - T_20_39(28, C, D, E, A, B); - T_20_39(29, B, C, D, E, A); - T_20_39(30, A, B, C, D, E); - T_20_39(31, E, A, B, C, D); - T_20_39(32, D, E, A, B, C); - T_20_39(33, C, D, E, A, B); - T_20_39(34, B, C, D, E, A); - T_20_39(35, A, B, C, D, E); - T_20_39(36, E, A, B, C, D); - T_20_39(37, D, E, A, B, C); - T_20_39(38, C, D, E, A, B); - T_20_39(39, B, C, D, E, A); - - /* Round 3 */ - T_40_59(40, A, B, C, D, E); - T_40_59(41, E, A, B, C, D); - T_40_59(42, D, E, A, B, C); - T_40_59(43, C, D, E, A, B); - T_40_59(44, B, C, D, E, A); - T_40_59(45, A, B, C, D, E); - T_40_59(46, E, A, B, C, D); - T_40_59(47, D, E, A, B, C); - T_40_59(48, C, D, E, A, B); - T_40_59(49, B, C, D, E, A); - T_40_59(50, A, B, C, D, E); - T_40_59(51, E, A, B, C, D); - T_40_59(52, D, E, A, B, C); - T_40_59(53, C, D, E, A, B); - T_40_59(54, B, C, D, E, A); - T_40_59(55, A, B, C, D, E); - T_40_59(56, E, A, B, C, D); - T_40_59(57, D, E, A, B, C); - T_40_59(58, C, D, E, A, B); - T_40_59(59, B, C, D, E, A); - - /* Round 4 */ - T_60_79(60, A, B, C, D, E); - T_60_79(61, E, A, B, C, D); - T_60_79(62, D, E, A, B, C); - T_60_79(63, C, D, E, A, B); - T_60_79(64, B, C, D, E, A); - T_60_79(65, A, B, C, D, E); - T_60_79(66, E, A, B, C, D); - T_60_79(67, D, E, A, B, C); - T_60_79(68, C, D, E, A, B); - T_60_79(69, B, C, D, E, A); - T_60_79(70, A, B, C, D, E); - T_60_79(71, E, A, B, C, D); - T_60_79(72, D, E, A, B, C); - T_60_79(73, C, D, E, A, B); - T_60_79(74, B, C, D, E, A); - T_60_79(75, A, B, C, D, E); - T_60_79(76, E, A, B, C, D); - T_60_79(77, D, E, A, B, C); - T_60_79(78, C, D, E, A, B); - T_60_79(79, B, C, D, E, A); - - digest[0] += A; - digest[1] += B; - digest[2] += C; - digest[3] += D; - digest[4] += E; -} -EXPORT_SYMBOL(sha_transform); - -/** - * sha_init - initialize the vectors for a SHA1 digest - * @buf: vector to initialize - */ -void sha_init(__u32 *buf) -{ - buf[0] = 0x67452301; - buf[1] = 0xefcdab89; - buf[2] = 0x98badcfe; - buf[3] = 0x10325476; - buf[4] = 0xc3d2e1f0; -} -EXPORT_SYMBOL(sha_init); diff --git a/src/linux/lib/show_mem.c b/src/linux/lib/show_mem.c deleted file mode 100644 index 1feed6a..0000000 --- a/src/linux/lib/show_mem.c +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Generic show_mem() implementation - * - * Copyright (C) 2008 Johannes Weiner - * All code subject to the GPL version 2. - */ - -#include -#include -#include - -void show_mem(unsigned int filter) -{ - pg_data_t *pgdat; - unsigned long total = 0, reserved = 0, highmem = 0; - - printk("Mem-Info:\n"); - show_free_areas(filter); - - for_each_online_pgdat(pgdat) { - unsigned long flags; - int zoneid; - - pgdat_resize_lock(pgdat, &flags); - for (zoneid = 0; zoneid < MAX_NR_ZONES; zoneid++) { - struct zone *zone = &pgdat->node_zones[zoneid]; - if (!populated_zone(zone)) - continue; - - total += zone->present_pages; - reserved += zone->present_pages - zone->managed_pages; - - if (is_highmem_idx(zoneid)) - highmem += zone->present_pages; - } - pgdat_resize_unlock(pgdat, &flags); - } - - printk("%lu pages RAM\n", total); - printk("%lu pages HighMem/MovableOnly\n", highmem); - printk("%lu pages reserved\n", reserved); -#ifdef CONFIG_CMA - printk("%lu pages cma reserved\n", totalcma_pages); -#endif -#ifdef CONFIG_QUICKLIST - printk("%lu pages in pagetable cache\n", - quicklist_total_size()); -#endif -#ifdef CONFIG_MEMORY_FAILURE - printk("%lu pages hwpoisoned\n", atomic_long_read(&num_poisoned_pages)); -#endif -} diff --git a/src/linux/lib/sort.c b/src/linux/lib/sort.c deleted file mode 100644 index fc20df4..0000000 --- a/src/linux/lib/sort.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * A fast, small, non-recursive O(nlog n) sort for the Linux kernel - * - * Jan 23 2005 Matt Mackall - */ - -#include -#include -#include - -static int alignment_ok(const void *base, int align) -{ - return IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) || - ((unsigned long)base & (align - 1)) == 0; -} - -static void u32_swap(void *a, void *b, int size) -{ - u32 t = *(u32 *)a; - *(u32 *)a = *(u32 *)b; - *(u32 *)b = t; -} - -static void u64_swap(void *a, void *b, int size) -{ - u64 t = *(u64 *)a; - *(u64 *)a = *(u64 *)b; - *(u64 *)b = t; -} - -static void generic_swap(void *a, void *b, int size) -{ - char t; - - do { - t = *(char *)a; - *(char *)a++ = *(char *)b; - *(char *)b++ = t; - } while (--size > 0); -} - -/** - * sort - sort an array of elements - * @base: pointer to data to sort - * @num: number of elements - * @size: size of each element - * @cmp_func: pointer to comparison function - * @swap_func: pointer to swap function or NULL - * - * This function does a heapsort on the given array. You may provide a - * swap_func function optimized to your element type. - * - * Sorting time is O(n log n) both on average and worst-case. While - * qsort is about 20% faster on average, it suffers from exploitable - * O(n*n) worst-case behavior and extra memory requirements that make - * it less suitable for kernel use. - */ - -void sort(void *base, size_t num, size_t size, - int (*cmp_func)(const void *, const void *), - void (*swap_func)(void *, void *, int size)) -{ - /* pre-scale counters for performance */ - int i = (num/2 - 1) * size, n = num * size, c, r; - - if (!swap_func) { - if (size == 4 && alignment_ok(base, 4)) - swap_func = u32_swap; - else if (size == 8 && alignment_ok(base, 8)) - swap_func = u64_swap; - else - swap_func = generic_swap; - } - - /* heapify */ - for ( ; i >= 0; i -= size) { - for (r = i; r * 2 + size < n; r = c) { - c = r * 2 + size; - if (c < n - size && - cmp_func(base + c, base + c + size) < 0) - c += size; - if (cmp_func(base + r, base + c) >= 0) - break; - swap_func(base + r, base + c, size); - } - } - - /* sort */ - for (i = n - size; i > 0; i -= size) { - swap_func(base, base + i, size); - for (r = 0; r * 2 + size < i; r = c) { - c = r * 2 + size; - if (c < i - size && - cmp_func(base + c, base + c + size) < 0) - c += size; - if (cmp_func(base + r, base + c) >= 0) - break; - swap_func(base + r, base + c, size); - } - } -} - -EXPORT_SYMBOL(sort); - -#if 0 -#include -/* a simple boot-time regression test */ - -int cmpint(const void *a, const void *b) -{ - return *(int *)a - *(int *)b; -} - -static int sort_test(void) -{ - int *a, i, r = 1; - - a = kmalloc(1000 * sizeof(int), GFP_KERNEL); - BUG_ON(!a); - - printk("testing sort()\n"); - - for (i = 0; i < 1000; i++) { - r = (r * 725861) % 6599; - a[i] = r; - } - - sort(a, 1000, sizeof(int), cmpint, NULL); - - for (i = 0; i < 999; i++) - if (a[i] > a[i+1]) { - printk("sort() failed!\n"); - break; - } - - kfree(a); - - return 0; -} - -module_init(sort_test); -#endif diff --git a/src/linux/lib/string.c b/src/linux/lib/string.c deleted file mode 100644 index ed83562..0000000 --- a/src/linux/lib/string.c +++ /dev/null @@ -1,954 +0,0 @@ -/* - * linux/lib/string.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -/* - * stupid library routines.. The optimized versions should generally be found - * as inline code in - * - * These are buggy as well.. - * - * * Fri Jun 25 1999, Ingo Oeser - * - Added strsep() which will replace strtok() soon (because strsep() is - * reentrant and should be faster). Use only strsep() in new code, please. - * - * * Sat Feb 09 2002, Jason Thomas , - * Matthew Hawkins - * - Kissed strtok() goodbye - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifndef __HAVE_ARCH_STRNCASECMP -/** - * strncasecmp - Case insensitive, length-limited string comparison - * @s1: One string - * @s2: The other string - * @len: the maximum number of characters to compare - */ -int strncasecmp(const char *s1, const char *s2, size_t len) -{ - /* Yes, Virginia, it had better be unsigned */ - unsigned char c1, c2; - - if (!len) - return 0; - - do { - c1 = *s1++; - c2 = *s2++; - if (!c1 || !c2) - break; - if (c1 == c2) - continue; - c1 = tolower(c1); - c2 = tolower(c2); - if (c1 != c2) - break; - } while (--len); - return (int)c1 - (int)c2; -} -EXPORT_SYMBOL(strncasecmp); -#endif - -#ifndef __HAVE_ARCH_STRCASECMP -int strcasecmp(const char *s1, const char *s2) -{ - int c1, c2; - - do { - c1 = tolower(*s1++); - c2 = tolower(*s2++); - } while (c1 == c2 && c1 != 0); - return c1 - c2; -} -EXPORT_SYMBOL(strcasecmp); -#endif - -#ifndef __HAVE_ARCH_STRCPY -/** - * strcpy - Copy a %NUL terminated string - * @dest: Where to copy the string to - * @src: Where to copy the string from - */ -#undef strcpy -char *strcpy(char *dest, const char *src) -{ - char *tmp = dest; - - while ((*dest++ = *src++) != '\0') - /* nothing */; - return tmp; -} -EXPORT_SYMBOL(strcpy); -#endif - -#ifndef __HAVE_ARCH_STRNCPY -/** - * strncpy - Copy a length-limited, C-string - * @dest: Where to copy the string to - * @src: Where to copy the string from - * @count: The maximum number of bytes to copy - * - * The result is not %NUL-terminated if the source exceeds - * @count bytes. - * - * In the case where the length of @src is less than that of - * count, the remainder of @dest will be padded with %NUL. - * - */ -char *strncpy(char *dest, const char *src, size_t count) -{ - char *tmp = dest; - - while (count) { - if ((*tmp = *src) != 0) - src++; - tmp++; - count--; - } - return dest; -} -EXPORT_SYMBOL(strncpy); -#endif - -#ifndef __HAVE_ARCH_STRLCPY -/** - * strlcpy - Copy a C-string into a sized buffer - * @dest: Where to copy the string to - * @src: Where to copy the string from - * @size: size of destination buffer - * - * Compatible with *BSD: the result is always a valid - * NUL-terminated string that fits in the buffer (unless, - * of course, the buffer size is zero). It does not pad - * out the result like strncpy() does. - */ -size_t strlcpy(char *dest, const char *src, size_t size) -{ - size_t ret = strlen(src); - - if (size) { - size_t len = (ret >= size) ? size - 1 : ret; - memcpy(dest, src, len); - dest[len] = '\0'; - } - return ret; -} -EXPORT_SYMBOL(strlcpy); -#endif - -#ifndef __HAVE_ARCH_STRSCPY -/** - * strscpy - Copy a C-string into a sized buffer - * @dest: Where to copy the string to - * @src: Where to copy the string from - * @count: Size of destination buffer - * - * Copy the string, or as much of it as fits, into the dest buffer. - * The routine returns the number of characters copied (not including - * the trailing NUL) or -E2BIG if the destination buffer wasn't big enough. - * The behavior is undefined if the string buffers overlap. - * The destination buffer is always NUL terminated, unless it's zero-sized. - * - * Preferred to strlcpy() since the API doesn't require reading memory - * from the src string beyond the specified "count" bytes, and since - * the return value is easier to error-check than strlcpy()'s. - * In addition, the implementation is robust to the string changing out - * from underneath it, unlike the current strlcpy() implementation. - * - * Preferred to strncpy() since it always returns a valid string, and - * doesn't unnecessarily force the tail of the destination buffer to be - * zeroed. If the zeroing is desired, it's likely cleaner to use strscpy() - * with an overflow test, then just memset() the tail of the dest buffer. - */ -ssize_t strscpy(char *dest, const char *src, size_t count) -{ - const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS; - size_t max = count; - long res = 0; - - if (count == 0) - return -E2BIG; - -#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS - /* - * If src is unaligned, don't cross a page boundary, - * since we don't know if the next page is mapped. - */ - if ((long)src & (sizeof(long) - 1)) { - size_t limit = PAGE_SIZE - ((long)src & (PAGE_SIZE - 1)); - if (limit < max) - max = limit; - } -#else - /* If src or dest is unaligned, don't do word-at-a-time. */ - if (((long) dest | (long) src) & (sizeof(long) - 1)) - max = 0; -#endif - - while (max >= sizeof(unsigned long)) { - unsigned long c, data; - - c = *(unsigned long *)(src+res); - if (has_zero(c, &data, &constants)) { - data = prep_zero_mask(c, data, &constants); - data = create_zero_mask(data); - *(unsigned long *)(dest+res) = c & zero_bytemask(data); - return res + find_zero(data); - } - *(unsigned long *)(dest+res) = c; - res += sizeof(unsigned long); - count -= sizeof(unsigned long); - max -= sizeof(unsigned long); - } - - while (count) { - char c; - - c = src[res]; - dest[res] = c; - if (!c) - return res; - res++; - count--; - } - - /* Hit buffer length without finding a NUL; force NUL-termination. */ - if (res) - dest[res-1] = '\0'; - - return -E2BIG; -} -EXPORT_SYMBOL(strscpy); -#endif - -#ifndef __HAVE_ARCH_STRCAT -/** - * strcat - Append one %NUL-terminated string to another - * @dest: The string to be appended to - * @src: The string to append to it - */ -#undef strcat -char *strcat(char *dest, const char *src) -{ - char *tmp = dest; - - while (*dest) - dest++; - while ((*dest++ = *src++) != '\0') - ; - return tmp; -} -EXPORT_SYMBOL(strcat); -#endif - -#ifndef __HAVE_ARCH_STRNCAT -/** - * strncat - Append a length-limited, C-string to another - * @dest: The string to be appended to - * @src: The string to append to it - * @count: The maximum numbers of bytes to copy - * - * Note that in contrast to strncpy(), strncat() ensures the result is - * terminated. - */ -char *strncat(char *dest, const char *src, size_t count) -{ - char *tmp = dest; - - if (count) { - while (*dest) - dest++; - while ((*dest++ = *src++) != 0) { - if (--count == 0) { - *dest = '\0'; - break; - } - } - } - return tmp; -} -EXPORT_SYMBOL(strncat); -#endif - -#ifndef __HAVE_ARCH_STRLCAT -/** - * strlcat - Append a length-limited, C-string to another - * @dest: The string to be appended to - * @src: The string to append to it - * @count: The size of the destination buffer. - */ -size_t strlcat(char *dest, const char *src, size_t count) -{ - size_t dsize = strlen(dest); - size_t len = strlen(src); - size_t res = dsize + len; - - /* This would be a bug */ - BUG_ON(dsize >= count); - - dest += dsize; - count -= dsize; - if (len >= count) - len = count-1; - memcpy(dest, src, len); - dest[len] = 0; - return res; -} -EXPORT_SYMBOL(strlcat); -#endif - -#ifndef __HAVE_ARCH_STRCMP -/** - * strcmp - Compare two strings - * @cs: One string - * @ct: Another string - */ -#undef strcmp -int strcmp(const char *cs, const char *ct) -{ - unsigned char c1, c2; - - while (1) { - c1 = *cs++; - c2 = *ct++; - if (c1 != c2) - return c1 < c2 ? -1 : 1; - if (!c1) - break; - } - return 0; -} -EXPORT_SYMBOL(strcmp); -#endif - -#ifndef __HAVE_ARCH_STRNCMP -/** - * strncmp - Compare two length-limited strings - * @cs: One string - * @ct: Another string - * @count: The maximum number of bytes to compare - */ -int strncmp(const char *cs, const char *ct, size_t count) -{ - unsigned char c1, c2; - - while (count) { - c1 = *cs++; - c2 = *ct++; - if (c1 != c2) - return c1 < c2 ? -1 : 1; - if (!c1) - break; - count--; - } - return 0; -} -EXPORT_SYMBOL(strncmp); -#endif - -#ifndef __HAVE_ARCH_STRCHR -/** - * strchr - Find the first occurrence of a character in a string - * @s: The string to be searched - * @c: The character to search for - */ -char *strchr(const char *s, int c) -{ - for (; *s != (char)c; ++s) - if (*s == '\0') - return NULL; - return (char *)s; -} -EXPORT_SYMBOL(strchr); -#endif - -#ifndef __HAVE_ARCH_STRCHRNUL -/** - * strchrnul - Find and return a character in a string, or end of string - * @s: The string to be searched - * @c: The character to search for - * - * Returns pointer to first occurrence of 'c' in s. If c is not found, then - * return a pointer to the null byte at the end of s. - */ -char *strchrnul(const char *s, int c) -{ - while (*s && *s != (char)c) - s++; - return (char *)s; -} -EXPORT_SYMBOL(strchrnul); -#endif - -#ifndef __HAVE_ARCH_STRRCHR -/** - * strrchr - Find the last occurrence of a character in a string - * @s: The string to be searched - * @c: The character to search for - */ -char *strrchr(const char *s, int c) -{ - const char *last = NULL; - do { - if (*s == (char)c) - last = s; - } while (*s++); - return (char *)last; -} -EXPORT_SYMBOL(strrchr); -#endif - -#ifndef __HAVE_ARCH_STRNCHR -/** - * strnchr - Find a character in a length limited string - * @s: The string to be searched - * @count: The number of characters to be searched - * @c: The character to search for - */ -char *strnchr(const char *s, size_t count, int c) -{ - for (; count-- && *s != '\0'; ++s) - if (*s == (char)c) - return (char *)s; - return NULL; -} -EXPORT_SYMBOL(strnchr); -#endif - -/** - * skip_spaces - Removes leading whitespace from @str. - * @str: The string to be stripped. - * - * Returns a pointer to the first non-whitespace character in @str. - */ -char *skip_spaces(const char *str) -{ - while (isspace(*str)) - ++str; - return (char *)str; -} -EXPORT_SYMBOL(skip_spaces); - -/** - * strim - Removes leading and trailing whitespace from @s. - * @s: The string to be stripped. - * - * Note that the first trailing whitespace is replaced with a %NUL-terminator - * in the given string @s. Returns a pointer to the first non-whitespace - * character in @s. - */ -char *strim(char *s) -{ - size_t size; - char *end; - - size = strlen(s); - if (!size) - return s; - - end = s + size - 1; - while (end >= s && isspace(*end)) - end--; - *(end + 1) = '\0'; - - return skip_spaces(s); -} -EXPORT_SYMBOL(strim); - -#ifndef __HAVE_ARCH_STRLEN -/** - * strlen - Find the length of a string - * @s: The string to be sized - */ -size_t strlen(const char *s) -{ - const char *sc; - - for (sc = s; *sc != '\0'; ++sc) - /* nothing */; - return sc - s; -} -EXPORT_SYMBOL(strlen); -#endif - -#ifndef __HAVE_ARCH_STRNLEN -/** - * strnlen - Find the length of a length-limited string - * @s: The string to be sized - * @count: The maximum number of bytes to search - */ -size_t strnlen(const char *s, size_t count) -{ - const char *sc; - - for (sc = s; count-- && *sc != '\0'; ++sc) - /* nothing */; - return sc - s; -} -EXPORT_SYMBOL(strnlen); -#endif - -#ifndef __HAVE_ARCH_STRSPN -/** - * strspn - Calculate the length of the initial substring of @s which only contain letters in @accept - * @s: The string to be searched - * @accept: The string to search for - */ -size_t strspn(const char *s, const char *accept) -{ - const char *p; - const char *a; - size_t count = 0; - - for (p = s; *p != '\0'; ++p) { - for (a = accept; *a != '\0'; ++a) { - if (*p == *a) - break; - } - if (*a == '\0') - return count; - ++count; - } - return count; -} - -EXPORT_SYMBOL(strspn); -#endif - -#ifndef __HAVE_ARCH_STRCSPN -/** - * strcspn - Calculate the length of the initial substring of @s which does not contain letters in @reject - * @s: The string to be searched - * @reject: The string to avoid - */ -size_t strcspn(const char *s, const char *reject) -{ - const char *p; - const char *r; - size_t count = 0; - - for (p = s; *p != '\0'; ++p) { - for (r = reject; *r != '\0'; ++r) { - if (*p == *r) - return count; - } - ++count; - } - return count; -} -EXPORT_SYMBOL(strcspn); -#endif - -#ifndef __HAVE_ARCH_STRPBRK -/** - * strpbrk - Find the first occurrence of a set of characters - * @cs: The string to be searched - * @ct: The characters to search for - */ -char *strpbrk(const char *cs, const char *ct) -{ - const char *sc1, *sc2; - - for (sc1 = cs; *sc1 != '\0'; ++sc1) { - for (sc2 = ct; *sc2 != '\0'; ++sc2) { - if (*sc1 == *sc2) - return (char *)sc1; - } - } - return NULL; -} -EXPORT_SYMBOL(strpbrk); -#endif - -#ifndef __HAVE_ARCH_STRSEP -/** - * strsep - Split a string into tokens - * @s: The string to be searched - * @ct: The characters to search for - * - * strsep() updates @s to point after the token, ready for the next call. - * - * It returns empty tokens, too, behaving exactly like the libc function - * of that name. In fact, it was stolen from glibc2 and de-fancy-fied. - * Same semantics, slimmer shape. ;) - */ -char *strsep(char **s, const char *ct) -{ - char *sbegin = *s; - char *end; - - if (sbegin == NULL) - return NULL; - - end = strpbrk(sbegin, ct); - if (end) - *end++ = '\0'; - *s = end; - return sbegin; -} -EXPORT_SYMBOL(strsep); -#endif - -/** - * sysfs_streq - return true if strings are equal, modulo trailing newline - * @s1: one string - * @s2: another string - * - * This routine returns true iff two strings are equal, treating both - * NUL and newline-then-NUL as equivalent string terminations. It's - * geared for use with sysfs input strings, which generally terminate - * with newlines but are compared against values without newlines. - */ -bool sysfs_streq(const char *s1, const char *s2) -{ - while (*s1 && *s1 == *s2) { - s1++; - s2++; - } - - if (*s1 == *s2) - return true; - if (!*s1 && *s2 == '\n' && !s2[1]) - return true; - if (*s1 == '\n' && !s1[1] && !*s2) - return true; - return false; -} -EXPORT_SYMBOL(sysfs_streq); - -/** - * match_string - matches given string in an array - * @array: array of strings - * @n: number of strings in the array or -1 for NULL terminated arrays - * @string: string to match with - * - * Return: - * index of a @string in the @array if matches, or %-EINVAL otherwise. - */ -int match_string(const char * const *array, size_t n, const char *string) -{ - int index; - const char *item; - - for (index = 0; index < n; index++) { - item = array[index]; - if (!item) - break; - if (!strcmp(item, string)) - return index; - } - - return -EINVAL; -} -EXPORT_SYMBOL(match_string); - -#ifndef __HAVE_ARCH_MEMSET -/** - * memset - Fill a region of memory with the given value - * @s: Pointer to the start of the area. - * @c: The byte to fill the area with - * @count: The size of the area. - * - * Do not use memset() to access IO space, use memset_io() instead. - */ -void *memset(void *s, int c, size_t count) -{ - char *xs = s; - - while (count--) - *xs++ = c; - return s; -} -EXPORT_SYMBOL(memset); -#endif - -/** - * memzero_explicit - Fill a region of memory (e.g. sensitive - * keying data) with 0s. - * @s: Pointer to the start of the area. - * @count: The size of the area. - * - * Note: usually using memset() is just fine (!), but in cases - * where clearing out _local_ data at the end of a scope is - * necessary, memzero_explicit() should be used instead in - * order to prevent the compiler from optimising away zeroing. - * - * memzero_explicit() doesn't need an arch-specific version as - * it just invokes the one of memset() implicitly. - */ -void memzero_explicit(void *s, size_t count) -{ - memset(s, 0, count); - barrier_data(s); -} -EXPORT_SYMBOL(memzero_explicit); - -#ifndef __HAVE_ARCH_MEMCPY -/** - * memcpy - Copy one area of memory to another - * @dest: Where to copy to - * @src: Where to copy from - * @count: The size of the area. - * - * You should not use this function to access IO space, use memcpy_toio() - * or memcpy_fromio() instead. - */ -void *memcpy(void *dest, const void *src, size_t count) -{ - char *tmp = dest; - const char *s = src; - - while (count--) - *tmp++ = *s++; - return dest; -} -EXPORT_SYMBOL(memcpy); -#endif - -#ifndef __HAVE_ARCH_MEMMOVE -/** - * memmove - Copy one area of memory to another - * @dest: Where to copy to - * @src: Where to copy from - * @count: The size of the area. - * - * Unlike memcpy(), memmove() copes with overlapping areas. - */ -void *memmove(void *dest, const void *src, size_t count) -{ - char *tmp; - const char *s; - - if (dest <= src) { - tmp = dest; - s = src; - while (count--) - *tmp++ = *s++; - } else { - tmp = dest; - tmp += count; - s = src; - s += count; - while (count--) - *--tmp = *--s; - } - return dest; -} -EXPORT_SYMBOL(memmove); -#endif - -#ifndef __HAVE_ARCH_MEMCMP -/** - * memcmp - Compare two areas of memory - * @cs: One area of memory - * @ct: Another area of memory - * @count: The size of the area. - */ -#undef memcmp -__visible int memcmp(const void *cs, const void *ct, size_t count) -{ - const unsigned char *su1, *su2; - int res = 0; - - for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--) - if ((res = *su1 - *su2) != 0) - break; - return res; -} -EXPORT_SYMBOL(memcmp); -#endif - -#ifndef __HAVE_ARCH_MEMSCAN -/** - * memscan - Find a character in an area of memory. - * @addr: The memory area - * @c: The byte to search for - * @size: The size of the area. - * - * returns the address of the first occurrence of @c, or 1 byte past - * the area if @c is not found - */ -void *memscan(void *addr, int c, size_t size) -{ - unsigned char *p = addr; - - while (size) { - if (*p == c) - return (void *)p; - p++; - size--; - } - return (void *)p; -} -EXPORT_SYMBOL(memscan); -#endif - -#ifndef __HAVE_ARCH_STRSTR -/** - * strstr - Find the first substring in a %NUL terminated string - * @s1: The string to be searched - * @s2: The string to search for - */ -char *strstr(const char *s1, const char *s2) -{ - size_t l1, l2; - - l2 = strlen(s2); - if (!l2) - return (char *)s1; - l1 = strlen(s1); - while (l1 >= l2) { - l1--; - if (!memcmp(s1, s2, l2)) - return (char *)s1; - s1++; - } - return NULL; -} -EXPORT_SYMBOL(strstr); -#endif - -#ifndef __HAVE_ARCH_STRNSTR -/** - * strnstr - Find the first substring in a length-limited string - * @s1: The string to be searched - * @s2: The string to search for - * @len: the maximum number of characters to search - */ -char *strnstr(const char *s1, const char *s2, size_t len) -{ - size_t l2; - - l2 = strlen(s2); - if (!l2) - return (char *)s1; - while (len >= l2) { - len--; - if (!memcmp(s1, s2, l2)) - return (char *)s1; - s1++; - } - return NULL; -} -EXPORT_SYMBOL(strnstr); -#endif - -#ifndef __HAVE_ARCH_MEMCHR -/** - * memchr - Find a character in an area of memory. - * @s: The memory area - * @c: The byte to search for - * @n: The size of the area. - * - * returns the address of the first occurrence of @c, or %NULL - * if @c is not found - */ -void *memchr(const void *s, int c, size_t n) -{ - const unsigned char *p = s; - while (n-- != 0) { - if ((unsigned char)c == *p++) { - return (void *)(p - 1); - } - } - return NULL; -} -EXPORT_SYMBOL(memchr); -#endif - -static void *check_bytes8(const u8 *start, u8 value, unsigned int bytes) -{ - while (bytes) { - if (*start != value) - return (void *)start; - start++; - bytes--; - } - return NULL; -} - -/** - * memchr_inv - Find an unmatching character in an area of memory. - * @start: The memory area - * @c: Find a character other than c - * @bytes: The size of the area. - * - * returns the address of the first character other than @c, or %NULL - * if the whole buffer contains just @c. - */ -void *memchr_inv(const void *start, int c, size_t bytes) -{ - u8 value = c; - u64 value64; - unsigned int words, prefix; - - if (bytes <= 16) - return check_bytes8(start, value, bytes); - - value64 = value; -#if defined(CONFIG_ARCH_HAS_FAST_MULTIPLIER) && BITS_PER_LONG == 64 - value64 *= 0x0101010101010101ULL; -#elif defined(CONFIG_ARCH_HAS_FAST_MULTIPLIER) - value64 *= 0x01010101; - value64 |= value64 << 32; -#else - value64 |= value64 << 8; - value64 |= value64 << 16; - value64 |= value64 << 32; -#endif - - prefix = (unsigned long)start % 8; - if (prefix) { - u8 *r; - - prefix = 8 - prefix; - r = check_bytes8(start, value, prefix); - if (r) - return r; - start += prefix; - bytes -= prefix; - } - - words = bytes / 8; - - while (words) { - if (*(u64 *)start != value64) - return check_bytes8(start, value, 8); - start += 8; - words--; - } - - return check_bytes8(start, value, bytes % 8); -} -EXPORT_SYMBOL(memchr_inv); - -/** - * strreplace - Replace all occurrences of character in string. - * @s: The string to operate on. - * @old: The character being replaced. - * @new: The character @old is replaced with. - * - * Returns pointer to the nul byte at the end of @s. - */ -char *strreplace(char *s, char old, char new) -{ - for (; *s; ++s) - if (*s == old) - *s = new; - return s; -} -EXPORT_SYMBOL(strreplace); diff --git a/src/linux/lib/string_helpers.c b/src/linux/lib/string_helpers.c deleted file mode 100644 index ecaac2c..0000000 --- a/src/linux/lib/string_helpers.c +++ /dev/null @@ -1,628 +0,0 @@ -/* - * Helpers for formatting and printing strings - * - * Copyright 31 August 2008 James Bottomley - * Copyright (C) 2013, Intel Corporation - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * string_get_size - get the size in the specified units - * @size: The size to be converted in blocks - * @blk_size: Size of the block (use 1 for size in bytes) - * @units: units to use (powers of 1000 or 1024) - * @buf: buffer to format to - * @len: length of buffer - * - * This function returns a string formatted to 3 significant figures - * giving the size in the required units. @buf should have room for - * at least 9 bytes and will always be zero terminated. - * - */ -void string_get_size(u64 size, u64 blk_size, const enum string_size_units units, - char *buf, int len) -{ - static const char *const units_10[] = { - "B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" - }; - static const char *const units_2[] = { - "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB" - }; - static const char *const *const units_str[] = { - [STRING_UNITS_10] = units_10, - [STRING_UNITS_2] = units_2, - }; - static const unsigned int divisor[] = { - [STRING_UNITS_10] = 1000, - [STRING_UNITS_2] = 1024, - }; - static const unsigned int rounding[] = { 500, 50, 5 }; - int i = 0, j; - u32 remainder = 0, sf_cap; - char tmp[8]; - const char *unit; - - tmp[0] = '\0'; - - if (blk_size == 0) - size = 0; - if (size == 0) - goto out; - - /* This is Napier's algorithm. Reduce the original block size to - * - * coefficient * divisor[units]^i - * - * we do the reduction so both coefficients are just under 32 bits so - * that multiplying them together won't overflow 64 bits and we keep - * as much precision as possible in the numbers. - * - * Note: it's safe to throw away the remainders here because all the - * precision is in the coefficients. - */ - while (blk_size >> 32) { - do_div(blk_size, divisor[units]); - i++; - } - - while (size >> 32) { - do_div(size, divisor[units]); - i++; - } - - /* now perform the actual multiplication keeping i as the sum of the - * two logarithms */ - size *= blk_size; - - /* and logarithmically reduce it until it's just under the divisor */ - while (size >= divisor[units]) { - remainder = do_div(size, divisor[units]); - i++; - } - - /* work out in j how many digits of precision we need from the - * remainder */ - sf_cap = size; - for (j = 0; sf_cap*10 < 1000; j++) - sf_cap *= 10; - - if (units == STRING_UNITS_2) { - /* express the remainder as a decimal. It's currently the - * numerator of a fraction whose denominator is - * divisor[units], which is 1 << 10 for STRING_UNITS_2 */ - remainder *= 1000; - remainder >>= 10; - } - - /* add a 5 to the digit below what will be printed to ensure - * an arithmetical round up and carry it through to size */ - remainder += rounding[j]; - if (remainder >= 1000) { - remainder -= 1000; - size += 1; - } - - if (j) { - snprintf(tmp, sizeof(tmp), ".%03u", remainder); - tmp[j+1] = '\0'; - } - - out: - if (i >= ARRAY_SIZE(units_2)) - unit = "UNK"; - else - unit = units_str[units][i]; - - snprintf(buf, len, "%u%s %s", (u32)size, - tmp, unit); -} -EXPORT_SYMBOL(string_get_size); - -static bool unescape_space(char **src, char **dst) -{ - char *p = *dst, *q = *src; - - switch (*q) { - case 'n': - *p = '\n'; - break; - case 'r': - *p = '\r'; - break; - case 't': - *p = '\t'; - break; - case 'v': - *p = '\v'; - break; - case 'f': - *p = '\f'; - break; - default: - return false; - } - *dst += 1; - *src += 1; - return true; -} - -static bool unescape_octal(char **src, char **dst) -{ - char *p = *dst, *q = *src; - u8 num; - - if (isodigit(*q) == 0) - return false; - - num = (*q++) & 7; - while (num < 32 && isodigit(*q) && (q - *src < 3)) { - num <<= 3; - num += (*q++) & 7; - } - *p = num; - *dst += 1; - *src = q; - return true; -} - -static bool unescape_hex(char **src, char **dst) -{ - char *p = *dst, *q = *src; - int digit; - u8 num; - - if (*q++ != 'x') - return false; - - num = digit = hex_to_bin(*q++); - if (digit < 0) - return false; - - digit = hex_to_bin(*q); - if (digit >= 0) { - q++; - num = (num << 4) | digit; - } - *p = num; - *dst += 1; - *src = q; - return true; -} - -static bool unescape_special(char **src, char **dst) -{ - char *p = *dst, *q = *src; - - switch (*q) { - case '\"': - *p = '\"'; - break; - case '\\': - *p = '\\'; - break; - case 'a': - *p = '\a'; - break; - case 'e': - *p = '\e'; - break; - default: - return false; - } - *dst += 1; - *src += 1; - return true; -} - -/** - * string_unescape - unquote characters in the given string - * @src: source buffer (escaped) - * @dst: destination buffer (unescaped) - * @size: size of the destination buffer (0 to unlimit) - * @flags: combination of the flags (bitwise OR): - * %UNESCAPE_SPACE: - * '\f' - form feed - * '\n' - new line - * '\r' - carriage return - * '\t' - horizontal tab - * '\v' - vertical tab - * %UNESCAPE_OCTAL: - * '\NNN' - byte with octal value NNN (1 to 3 digits) - * %UNESCAPE_HEX: - * '\xHH' - byte with hexadecimal value HH (1 to 2 digits) - * %UNESCAPE_SPECIAL: - * '\"' - double quote - * '\\' - backslash - * '\a' - alert (BEL) - * '\e' - escape - * %UNESCAPE_ANY: - * all previous together - * - * Description: - * The function unquotes characters in the given string. - * - * Because the size of the output will be the same as or less than the size of - * the input, the transformation may be performed in place. - * - * Caller must provide valid source and destination pointers. Be aware that - * destination buffer will always be NULL-terminated. Source string must be - * NULL-terminated as well. - * - * Return: - * The amount of the characters processed to the destination buffer excluding - * trailing '\0' is returned. - */ -int string_unescape(char *src, char *dst, size_t size, unsigned int flags) -{ - char *out = dst; - - while (*src && --size) { - if (src[0] == '\\' && src[1] != '\0' && size > 1) { - src++; - size--; - - if (flags & UNESCAPE_SPACE && - unescape_space(&src, &out)) - continue; - - if (flags & UNESCAPE_OCTAL && - unescape_octal(&src, &out)) - continue; - - if (flags & UNESCAPE_HEX && - unescape_hex(&src, &out)) - continue; - - if (flags & UNESCAPE_SPECIAL && - unescape_special(&src, &out)) - continue; - - *out++ = '\\'; - } - *out++ = *src++; - } - *out = '\0'; - - return out - dst; -} -EXPORT_SYMBOL(string_unescape); - -static bool escape_passthrough(unsigned char c, char **dst, char *end) -{ - char *out = *dst; - - if (out < end) - *out = c; - *dst = out + 1; - return true; -} - -static bool escape_space(unsigned char c, char **dst, char *end) -{ - char *out = *dst; - unsigned char to; - - switch (c) { - case '\n': - to = 'n'; - break; - case '\r': - to = 'r'; - break; - case '\t': - to = 't'; - break; - case '\v': - to = 'v'; - break; - case '\f': - to = 'f'; - break; - default: - return false; - } - - if (out < end) - *out = '\\'; - ++out; - if (out < end) - *out = to; - ++out; - - *dst = out; - return true; -} - -static bool escape_special(unsigned char c, char **dst, char *end) -{ - char *out = *dst; - unsigned char to; - - switch (c) { - case '\\': - to = '\\'; - break; - case '\a': - to = 'a'; - break; - case '\e': - to = 'e'; - break; - default: - return false; - } - - if (out < end) - *out = '\\'; - ++out; - if (out < end) - *out = to; - ++out; - - *dst = out; - return true; -} - -static bool escape_null(unsigned char c, char **dst, char *end) -{ - char *out = *dst; - - if (c) - return false; - - if (out < end) - *out = '\\'; - ++out; - if (out < end) - *out = '0'; - ++out; - - *dst = out; - return true; -} - -static bool escape_octal(unsigned char c, char **dst, char *end) -{ - char *out = *dst; - - if (out < end) - *out = '\\'; - ++out; - if (out < end) - *out = ((c >> 6) & 0x07) + '0'; - ++out; - if (out < end) - *out = ((c >> 3) & 0x07) + '0'; - ++out; - if (out < end) - *out = ((c >> 0) & 0x07) + '0'; - ++out; - - *dst = out; - return true; -} - -static bool escape_hex(unsigned char c, char **dst, char *end) -{ - char *out = *dst; - - if (out < end) - *out = '\\'; - ++out; - if (out < end) - *out = 'x'; - ++out; - if (out < end) - *out = hex_asc_hi(c); - ++out; - if (out < end) - *out = hex_asc_lo(c); - ++out; - - *dst = out; - return true; -} - -/** - * string_escape_mem - quote characters in the given memory buffer - * @src: source buffer (unescaped) - * @isz: source buffer size - * @dst: destination buffer (escaped) - * @osz: destination buffer size - * @flags: combination of the flags (bitwise OR): - * %ESCAPE_SPACE: (special white space, not space itself) - * '\f' - form feed - * '\n' - new line - * '\r' - carriage return - * '\t' - horizontal tab - * '\v' - vertical tab - * %ESCAPE_SPECIAL: - * '\\' - backslash - * '\a' - alert (BEL) - * '\e' - escape - * %ESCAPE_NULL: - * '\0' - null - * %ESCAPE_OCTAL: - * '\NNN' - byte with octal value NNN (3 digits) - * %ESCAPE_ANY: - * all previous together - * %ESCAPE_NP: - * escape only non-printable characters (checked by isprint) - * %ESCAPE_ANY_NP: - * all previous together - * %ESCAPE_HEX: - * '\xHH' - byte with hexadecimal value HH (2 digits) - * @only: NULL-terminated string containing characters used to limit - * the selected escape class. If characters are included in @only - * that would not normally be escaped by the classes selected - * in @flags, they will be copied to @dst unescaped. - * - * Description: - * The process of escaping byte buffer includes several parts. They are applied - * in the following sequence. - * 1. The character is matched to the printable class, if asked, and in - * case of match it passes through to the output. - * 2. The character is not matched to the one from @only string and thus - * must go as-is to the output. - * 3. The character is checked if it falls into the class given by @flags. - * %ESCAPE_OCTAL and %ESCAPE_HEX are going last since they cover any - * character. Note that they actually can't go together, otherwise - * %ESCAPE_HEX will be ignored. - * - * Caller must provide valid source and destination pointers. Be aware that - * destination buffer will not be NULL-terminated, thus caller have to append - * it if needs. - * - * Return: - * The total size of the escaped output that would be generated for - * the given input and flags. To check whether the output was - * truncated, compare the return value to osz. There is room left in - * dst for a '\0' terminator if and only if ret < osz. - */ -int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz, - unsigned int flags, const char *only) -{ - char *p = dst; - char *end = p + osz; - bool is_dict = only && *only; - - while (isz--) { - unsigned char c = *src++; - - /* - * Apply rules in the following sequence: - * - the character is printable, when @flags has - * %ESCAPE_NP bit set - * - the @only string is supplied and does not contain a - * character under question - * - the character doesn't fall into a class of symbols - * defined by given @flags - * In these cases we just pass through a character to the - * output buffer. - */ - if ((flags & ESCAPE_NP && isprint(c)) || - (is_dict && !strchr(only, c))) { - /* do nothing */ - } else { - if (flags & ESCAPE_SPACE && escape_space(c, &p, end)) - continue; - - if (flags & ESCAPE_SPECIAL && escape_special(c, &p, end)) - continue; - - if (flags & ESCAPE_NULL && escape_null(c, &p, end)) - continue; - - /* ESCAPE_OCTAL and ESCAPE_HEX always go last */ - if (flags & ESCAPE_OCTAL && escape_octal(c, &p, end)) - continue; - - if (flags & ESCAPE_HEX && escape_hex(c, &p, end)) - continue; - } - - escape_passthrough(c, &p, end); - } - - return p - dst; -} -EXPORT_SYMBOL(string_escape_mem); - -/* - * Return an allocated string that has been escaped of special characters - * and double quotes, making it safe to log in quotes. - */ -char *kstrdup_quotable(const char *src, gfp_t gfp) -{ - size_t slen, dlen; - char *dst; - const int flags = ESCAPE_HEX; - const char esc[] = "\f\n\r\t\v\a\e\\\""; - - if (!src) - return NULL; - slen = strlen(src); - - dlen = string_escape_mem(src, slen, NULL, 0, flags, esc); - dst = kmalloc(dlen + 1, gfp); - if (!dst) - return NULL; - - WARN_ON(string_escape_mem(src, slen, dst, dlen, flags, esc) != dlen); - dst[dlen] = '\0'; - - return dst; -} -EXPORT_SYMBOL_GPL(kstrdup_quotable); - -/* - * Returns allocated NULL-terminated string containing process - * command line, with inter-argument NULLs replaced with spaces, - * and other special characters escaped. - */ -char *kstrdup_quotable_cmdline(struct task_struct *task, gfp_t gfp) -{ - char *buffer, *quoted; - int i, res; - - buffer = kmalloc(PAGE_SIZE, GFP_TEMPORARY); - if (!buffer) - return NULL; - - res = get_cmdline(task, buffer, PAGE_SIZE - 1); - buffer[res] = '\0'; - - /* Collapse trailing NULLs, leave res pointing to last non-NULL. */ - while (--res >= 0 && buffer[res] == '\0') - ; - - /* Replace inter-argument NULLs. */ - for (i = 0; i <= res; i++) - if (buffer[i] == '\0') - buffer[i] = ' '; - - /* Make sure result is printable. */ - quoted = kstrdup_quotable(buffer, gfp); - kfree(buffer); - return quoted; -} -EXPORT_SYMBOL_GPL(kstrdup_quotable_cmdline); - -/* - * Returns allocated NULL-terminated string containing pathname, - * with special characters escaped, able to be safely logged. If - * there is an error, the leading character will be "<". - */ -char *kstrdup_quotable_file(struct file *file, gfp_t gfp) -{ - char *temp, *pathname; - - if (!file) - return kstrdup("", gfp); - - /* We add 11 spaces for ' (deleted)' to be appended */ - temp = kmalloc(PATH_MAX + 11, GFP_TEMPORARY); - if (!temp) - return kstrdup("", gfp); - - pathname = file_path(file, temp, PATH_MAX + 11); - if (IS_ERR(pathname)) - pathname = kstrdup("", gfp); - else - pathname = kstrdup_quotable(pathname, gfp); - - kfree(temp); - return pathname; -} -EXPORT_SYMBOL_GPL(kstrdup_quotable_file); diff --git a/src/linux/lib/timerqueue.c b/src/linux/lib/timerqueue.c deleted file mode 100644 index 782ae8c..0000000 --- a/src/linux/lib/timerqueue.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Generic Timer-queue - * - * Manages a simple queue of timers, ordered by expiration time. - * Uses rbtrees for quick list adds and expiration. - * - * NOTE: All of the following functions need to be serialized - * to avoid races. No locking is done by this library code. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include -#include -#include -#include - -/** - * timerqueue_add - Adds timer to timerqueue. - * - * @head: head of timerqueue - * @node: timer node to be added - * - * Adds the timer node to the timerqueue, sorted by the - * node's expires value. - */ -bool timerqueue_add(struct timerqueue_head *head, struct timerqueue_node *node) -{ - struct rb_node **p = &head->head.rb_node; - struct rb_node *parent = NULL; - struct timerqueue_node *ptr; - - /* Make sure we don't add nodes that are already added */ - WARN_ON_ONCE(!RB_EMPTY_NODE(&node->node)); - - while (*p) { - parent = *p; - ptr = rb_entry(parent, struct timerqueue_node, node); - if (node->expires.tv64 < ptr->expires.tv64) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - rb_link_node(&node->node, parent, p); - rb_insert_color(&node->node, &head->head); - - if (!head->next || node->expires.tv64 < head->next->expires.tv64) { - head->next = node; - return true; - } - return false; -} -EXPORT_SYMBOL_GPL(timerqueue_add); - -/** - * timerqueue_del - Removes a timer from the timerqueue. - * - * @head: head of timerqueue - * @node: timer node to be removed - * - * Removes the timer node from the timerqueue. - */ -bool timerqueue_del(struct timerqueue_head *head, struct timerqueue_node *node) -{ - WARN_ON_ONCE(RB_EMPTY_NODE(&node->node)); - - /* update next pointer */ - if (head->next == node) { - struct rb_node *rbn = rb_next(&node->node); - - head->next = rbn ? - rb_entry(rbn, struct timerqueue_node, node) : NULL; - } - rb_erase(&node->node, &head->head); - RB_CLEAR_NODE(&node->node); - return head->next != NULL; -} -EXPORT_SYMBOL_GPL(timerqueue_del); - -/** - * timerqueue_iterate_next - Returns the timer after the provided timer - * - * @node: Pointer to a timer. - * - * Provides the timer that is after the given node. This is used, when - * necessary, to iterate through the list of timers in a timer list - * without modifying the list. - */ -struct timerqueue_node *timerqueue_iterate_next(struct timerqueue_node *node) -{ - struct rb_node *next; - - if (!node) - return NULL; - next = rb_next(&node->node); - if (!next) - return NULL; - return container_of(next, struct timerqueue_node, node); -} -EXPORT_SYMBOL_GPL(timerqueue_iterate_next); diff --git a/src/linux/lib/uuid.c b/src/linux/lib/uuid.c deleted file mode 100644 index 37687af..0000000 --- a/src/linux/lib/uuid.c +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Unified UUID/GUID definition - * - * Copyright (C) 2009, 2016 Intel Corp. - * Huang Ying - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation; - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include -#include -#include -#include -#include -#include - -const u8 uuid_le_index[16] = {3,2,1,0,5,4,7,6,8,9,10,11,12,13,14,15}; -EXPORT_SYMBOL(uuid_le_index); -const u8 uuid_be_index[16] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}; -EXPORT_SYMBOL(uuid_be_index); - -/*************************************************************** - * Random UUID interface - * - * Used here for a Boot ID, but can be useful for other kernel - * drivers. - ***************************************************************/ - -/* - * Generate random UUID - */ -void generate_random_uuid(unsigned char uuid[16]) -{ - get_random_bytes(uuid, 16); - /* Set UUID version to 4 --- truly random generation */ - uuid[6] = (uuid[6] & 0x0F) | 0x40; - /* Set the UUID variant to DCE */ - uuid[8] = (uuid[8] & 0x3F) | 0x80; -} -EXPORT_SYMBOL(generate_random_uuid); - -static void __uuid_gen_common(__u8 b[16]) -{ - prandom_bytes(b, 16); - /* reversion 0b10 */ - b[8] = (b[8] & 0x3F) | 0x80; -} - -void uuid_le_gen(uuid_le *lu) -{ - __uuid_gen_common(lu->b); - /* version 4 : random generation */ - lu->b[7] = (lu->b[7] & 0x0F) | 0x40; -} -EXPORT_SYMBOL_GPL(uuid_le_gen); - -void uuid_be_gen(uuid_be *bu) -{ - __uuid_gen_common(bu->b); - /* version 4 : random generation */ - bu->b[6] = (bu->b[6] & 0x0F) | 0x40; -} -EXPORT_SYMBOL_GPL(uuid_be_gen); - -/** - * uuid_is_valid - checks if UUID string valid - * @uuid: UUID string to check - * - * Description: - * It checks if the UUID string is following the format: - * xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx - * where x is a hex digit. - * - * Return: true if input is valid UUID string. - */ -bool uuid_is_valid(const char *uuid) -{ - unsigned int i; - - for (i = 0; i < UUID_STRING_LEN; i++) { - if (i == 8 || i == 13 || i == 18 || i == 23) { - if (uuid[i] != '-') - return false; - } else if (!isxdigit(uuid[i])) { - return false; - } - } - - return true; -} -EXPORT_SYMBOL(uuid_is_valid); - -static int __uuid_to_bin(const char *uuid, __u8 b[16], const u8 ei[16]) -{ - static const u8 si[16] = {0,2,4,6,9,11,14,16,19,21,24,26,28,30,32,34}; - unsigned int i; - - if (!uuid_is_valid(uuid)) - return -EINVAL; - - for (i = 0; i < 16; i++) { - int hi = hex_to_bin(uuid[si[i] + 0]); - int lo = hex_to_bin(uuid[si[i] + 1]); - - b[ei[i]] = (hi << 4) | lo; - } - - return 0; -} - -int uuid_le_to_bin(const char *uuid, uuid_le *u) -{ - return __uuid_to_bin(uuid, u->b, uuid_le_index); -} -EXPORT_SYMBOL(uuid_le_to_bin); - -int uuid_be_to_bin(const char *uuid, uuid_be *u) -{ - return __uuid_to_bin(uuid, u->b, uuid_be_index); -} -EXPORT_SYMBOL(uuid_be_to_bin); diff --git a/src/linux/lib/vsprintf.c b/src/linux/lib/vsprintf.c deleted file mode 100644 index 0967771..0000000 --- a/src/linux/lib/vsprintf.c +++ /dev/null @@ -1,2893 +0,0 @@ -/* - * linux/lib/vsprintf.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ -/* - * Wirzenius wrote this portably, Torvalds fucked it up :-) - */ - -/* - * Fri Jul 13 2001 Crutcher Dunnavant - * - changed to provide snprintf and vsnprintf functions - * So Feb 1 16:51:32 CET 2004 Juergen Quade - * - scnprintf and vscnprintf - */ - -#include -#include -#include -#include /* for KSYM_SYMBOL_LEN */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_BLOCK -#include -#endif - -#include "../mm/internal.h" /* For the trace_print_flags arrays */ - -#include /* for PAGE_SIZE */ -#include /* for dereference_function_descriptor() */ -#include /* cpu_to_le16 */ - -#include -#include "kstrtox.h" - -/** - * simple_strtoull - convert a string to an unsigned long long - * @cp: The start of the string - * @endp: A pointer to the end of the parsed string will be placed here - * @base: The number base to use - * - * This function is obsolete. Please use kstrtoull instead. - */ -unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base) -{ - unsigned long long result; - unsigned int rv; - - cp = _parse_integer_fixup_radix(cp, &base); - rv = _parse_integer(cp, base, &result); - /* FIXME */ - cp += (rv & ~KSTRTOX_OVERFLOW); - - if (endp) - *endp = (char *)cp; - - return result; -} -EXPORT_SYMBOL(simple_strtoull); - -/** - * simple_strtoul - convert a string to an unsigned long - * @cp: The start of the string - * @endp: A pointer to the end of the parsed string will be placed here - * @base: The number base to use - * - * This function is obsolete. Please use kstrtoul instead. - */ -unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) -{ - return simple_strtoull(cp, endp, base); -} -EXPORT_SYMBOL(simple_strtoul); - -/** - * simple_strtol - convert a string to a signed long - * @cp: The start of the string - * @endp: A pointer to the end of the parsed string will be placed here - * @base: The number base to use - * - * This function is obsolete. Please use kstrtol instead. - */ -long simple_strtol(const char *cp, char **endp, unsigned int base) -{ - if (*cp == '-') - return -simple_strtoul(cp + 1, endp, base); - - return simple_strtoul(cp, endp, base); -} -EXPORT_SYMBOL(simple_strtol); - -/** - * simple_strtoll - convert a string to a signed long long - * @cp: The start of the string - * @endp: A pointer to the end of the parsed string will be placed here - * @base: The number base to use - * - * This function is obsolete. Please use kstrtoll instead. - */ -long long simple_strtoll(const char *cp, char **endp, unsigned int base) -{ - if (*cp == '-') - return -simple_strtoull(cp + 1, endp, base); - - return simple_strtoull(cp, endp, base); -} -EXPORT_SYMBOL(simple_strtoll); - -static noinline_for_stack -int skip_atoi(const char **s) -{ - int i = 0; - - do { - i = i*10 + *((*s)++) - '0'; - } while (isdigit(**s)); - - return i; -} - -/* - * Decimal conversion is by far the most typical, and is used for - * /proc and /sys data. This directly impacts e.g. top performance - * with many processes running. We optimize it for speed by emitting - * two characters at a time, using a 200 byte lookup table. This - * roughly halves the number of multiplications compared to computing - * the digits one at a time. Implementation strongly inspired by the - * previous version, which in turn used ideas described at - * (with permission - * from the author, Douglas W. Jones). - * - * It turns out there is precisely one 26 bit fixed-point - * approximation a of 64/100 for which x/100 == (x * (u64)a) >> 32 - * holds for all x in [0, 10^8-1], namely a = 0x28f5c29. The actual - * range happens to be somewhat larger (x <= 1073741898), but that's - * irrelevant for our purpose. - * - * For dividing a number in the range [10^4, 10^6-1] by 100, we still - * need a 32x32->64 bit multiply, so we simply use the same constant. - * - * For dividing a number in the range [100, 10^4-1] by 100, there are - * several options. The simplest is (x * 0x147b) >> 19, which is valid - * for all x <= 43698. - */ - -static const u16 decpair[100] = { -#define _(x) (__force u16) cpu_to_le16(((x % 10) | ((x / 10) << 8)) + 0x3030) - _( 0), _( 1), _( 2), _( 3), _( 4), _( 5), _( 6), _( 7), _( 8), _( 9), - _(10), _(11), _(12), _(13), _(14), _(15), _(16), _(17), _(18), _(19), - _(20), _(21), _(22), _(23), _(24), _(25), _(26), _(27), _(28), _(29), - _(30), _(31), _(32), _(33), _(34), _(35), _(36), _(37), _(38), _(39), - _(40), _(41), _(42), _(43), _(44), _(45), _(46), _(47), _(48), _(49), - _(50), _(51), _(52), _(53), _(54), _(55), _(56), _(57), _(58), _(59), - _(60), _(61), _(62), _(63), _(64), _(65), _(66), _(67), _(68), _(69), - _(70), _(71), _(72), _(73), _(74), _(75), _(76), _(77), _(78), _(79), - _(80), _(81), _(82), _(83), _(84), _(85), _(86), _(87), _(88), _(89), - _(90), _(91), _(92), _(93), _(94), _(95), _(96), _(97), _(98), _(99), -#undef _ -}; - -/* - * This will print a single '0' even if r == 0, since we would - * immediately jump to out_r where two 0s would be written but only - * one of them accounted for in buf. This is needed by ip4_string - * below. All other callers pass a non-zero value of r. -*/ -static noinline_for_stack -char *put_dec_trunc8(char *buf, unsigned r) -{ - unsigned q; - - /* 1 <= r < 10^8 */ - if (r < 100) - goto out_r; - - /* 100 <= r < 10^8 */ - q = (r * (u64)0x28f5c29) >> 32; - *((u16 *)buf) = decpair[r - 100*q]; - buf += 2; - - /* 1 <= q < 10^6 */ - if (q < 100) - goto out_q; - - /* 100 <= q < 10^6 */ - r = (q * (u64)0x28f5c29) >> 32; - *((u16 *)buf) = decpair[q - 100*r]; - buf += 2; - - /* 1 <= r < 10^4 */ - if (r < 100) - goto out_r; - - /* 100 <= r < 10^4 */ - q = (r * 0x147b) >> 19; - *((u16 *)buf) = decpair[r - 100*q]; - buf += 2; -out_q: - /* 1 <= q < 100 */ - r = q; -out_r: - /* 1 <= r < 100 */ - *((u16 *)buf) = decpair[r]; - buf += r < 10 ? 1 : 2; - return buf; -} - -#if BITS_PER_LONG == 64 && BITS_PER_LONG_LONG == 64 -static noinline_for_stack -char *put_dec_full8(char *buf, unsigned r) -{ - unsigned q; - - /* 0 <= r < 10^8 */ - q = (r * (u64)0x28f5c29) >> 32; - *((u16 *)buf) = decpair[r - 100*q]; - buf += 2; - - /* 0 <= q < 10^6 */ - r = (q * (u64)0x28f5c29) >> 32; - *((u16 *)buf) = decpair[q - 100*r]; - buf += 2; - - /* 0 <= r < 10^4 */ - q = (r * 0x147b) >> 19; - *((u16 *)buf) = decpair[r - 100*q]; - buf += 2; - - /* 0 <= q < 100 */ - *((u16 *)buf) = decpair[q]; - buf += 2; - return buf; -} - -static noinline_for_stack -char *put_dec(char *buf, unsigned long long n) -{ - if (n >= 100*1000*1000) - buf = put_dec_full8(buf, do_div(n, 100*1000*1000)); - /* 1 <= n <= 1.6e11 */ - if (n >= 100*1000*1000) - buf = put_dec_full8(buf, do_div(n, 100*1000*1000)); - /* 1 <= n < 1e8 */ - return put_dec_trunc8(buf, n); -} - -#elif BITS_PER_LONG == 32 && BITS_PER_LONG_LONG == 64 - -static void -put_dec_full4(char *buf, unsigned r) -{ - unsigned q; - - /* 0 <= r < 10^4 */ - q = (r * 0x147b) >> 19; - *((u16 *)buf) = decpair[r - 100*q]; - buf += 2; - /* 0 <= q < 100 */ - *((u16 *)buf) = decpair[q]; -} - -/* - * Call put_dec_full4 on x % 10000, return x / 10000. - * The approximation x/10000 == (x * 0x346DC5D7) >> 43 - * holds for all x < 1,128,869,999. The largest value this - * helper will ever be asked to convert is 1,125,520,955. - * (second call in the put_dec code, assuming n is all-ones). - */ -static noinline_for_stack -unsigned put_dec_helper4(char *buf, unsigned x) -{ - uint32_t q = (x * (uint64_t)0x346DC5D7) >> 43; - - put_dec_full4(buf, x - q * 10000); - return q; -} - -/* Based on code by Douglas W. Jones found at - * - * (with permission from the author). - * Performs no 64-bit division and hence should be fast on 32-bit machines. - */ -static -char *put_dec(char *buf, unsigned long long n) -{ - uint32_t d3, d2, d1, q, h; - - if (n < 100*1000*1000) - return put_dec_trunc8(buf, n); - - d1 = ((uint32_t)n >> 16); /* implicit "& 0xffff" */ - h = (n >> 32); - d2 = (h ) & 0xffff; - d3 = (h >> 16); /* implicit "& 0xffff" */ - - /* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0 - = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */ - q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff); - q = put_dec_helper4(buf, q); - - q += 7671 * d3 + 9496 * d2 + 6 * d1; - q = put_dec_helper4(buf+4, q); - - q += 4749 * d3 + 42 * d2; - q = put_dec_helper4(buf+8, q); - - q += 281 * d3; - buf += 12; - if (q) - buf = put_dec_trunc8(buf, q); - else while (buf[-1] == '0') - --buf; - - return buf; -} - -#endif - -/* - * Convert passed number to decimal string. - * Returns the length of string. On buffer overflow, returns 0. - * - * If speed is not important, use snprintf(). It's easy to read the code. - */ -int num_to_str(char *buf, int size, unsigned long long num) -{ - /* put_dec requires 2-byte alignment of the buffer. */ - char tmp[sizeof(num) * 3] __aligned(2); - int idx, len; - - /* put_dec() may work incorrectly for num = 0 (generate "", not "0") */ - if (num <= 9) { - tmp[0] = '0' + num; - len = 1; - } else { - len = put_dec(tmp, num) - tmp; - } - - if (len > size) - return 0; - for (idx = 0; idx < len; ++idx) - buf[idx] = tmp[len - idx - 1]; - return len; -} - -#define SIGN 1 /* unsigned/signed, must be 1 */ -#define LEFT 2 /* left justified */ -#define PLUS 4 /* show plus */ -#define SPACE 8 /* space if plus */ -#define ZEROPAD 16 /* pad with zero, must be 16 == '0' - ' ' */ -#define SMALL 32 /* use lowercase in hex (must be 32 == 0x20) */ -#define SPECIAL 64 /* prefix hex with "0x", octal with "0" */ - -enum format_type { - FORMAT_TYPE_NONE, /* Just a string part */ - FORMAT_TYPE_WIDTH, - FORMAT_TYPE_PRECISION, - FORMAT_TYPE_CHAR, - FORMAT_TYPE_STR, - FORMAT_TYPE_PTR, - FORMAT_TYPE_PERCENT_CHAR, - FORMAT_TYPE_INVALID, - FORMAT_TYPE_LONG_LONG, - FORMAT_TYPE_ULONG, - FORMAT_TYPE_LONG, - FORMAT_TYPE_UBYTE, - FORMAT_TYPE_BYTE, - FORMAT_TYPE_USHORT, - FORMAT_TYPE_SHORT, - FORMAT_TYPE_UINT, - FORMAT_TYPE_INT, - FORMAT_TYPE_SIZE_T, - FORMAT_TYPE_PTRDIFF -}; - -struct printf_spec { - unsigned int type:8; /* format_type enum */ - signed int field_width:24; /* width of output field */ - unsigned int flags:8; /* flags to number() */ - unsigned int base:8; /* number base, 8, 10 or 16 only */ - signed int precision:16; /* # of digits/chars */ -} __packed; -#define FIELD_WIDTH_MAX ((1 << 23) - 1) -#define PRECISION_MAX ((1 << 15) - 1) - -static noinline_for_stack -char *number(char *buf, char *end, unsigned long long num, - struct printf_spec spec) -{ - /* put_dec requires 2-byte alignment of the buffer. */ - char tmp[3 * sizeof(num)] __aligned(2); - char sign; - char locase; - int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10); - int i; - bool is_zero = num == 0LL; - int field_width = spec.field_width; - int precision = spec.precision; - - BUILD_BUG_ON(sizeof(struct printf_spec) != 8); - - /* locase = 0 or 0x20. ORing digits or letters with 'locase' - * produces same digits or (maybe lowercased) letters */ - locase = (spec.flags & SMALL); - if (spec.flags & LEFT) - spec.flags &= ~ZEROPAD; - sign = 0; - if (spec.flags & SIGN) { - if ((signed long long)num < 0) { - sign = '-'; - num = -(signed long long)num; - field_width--; - } else if (spec.flags & PLUS) { - sign = '+'; - field_width--; - } else if (spec.flags & SPACE) { - sign = ' '; - field_width--; - } - } - if (need_pfx) { - if (spec.base == 16) - field_width -= 2; - else if (!is_zero) - field_width--; - } - - /* generate full string in tmp[], in reverse order */ - i = 0; - if (num < spec.base) - tmp[i++] = hex_asc_upper[num] | locase; - else if (spec.base != 10) { /* 8 or 16 */ - int mask = spec.base - 1; - int shift = 3; - - if (spec.base == 16) - shift = 4; - do { - tmp[i++] = (hex_asc_upper[((unsigned char)num) & mask] | locase); - num >>= shift; - } while (num); - } else { /* base 10 */ - i = put_dec(tmp, num) - tmp; - } - - /* printing 100 using %2d gives "100", not "00" */ - if (i > precision) - precision = i; - /* leading space padding */ - field_width -= precision; - if (!(spec.flags & (ZEROPAD | LEFT))) { - while (--field_width >= 0) { - if (buf < end) - *buf = ' '; - ++buf; - } - } - /* sign */ - if (sign) { - if (buf < end) - *buf = sign; - ++buf; - } - /* "0x" / "0" prefix */ - if (need_pfx) { - if (spec.base == 16 || !is_zero) { - if (buf < end) - *buf = '0'; - ++buf; - } - if (spec.base == 16) { - if (buf < end) - *buf = ('X' | locase); - ++buf; - } - } - /* zero or space padding */ - if (!(spec.flags & LEFT)) { - char c = ' ' + (spec.flags & ZEROPAD); - BUILD_BUG_ON(' ' + ZEROPAD != '0'); - while (--field_width >= 0) { - if (buf < end) - *buf = c; - ++buf; - } - } - /* hmm even more zero padding? */ - while (i <= --precision) { - if (buf < end) - *buf = '0'; - ++buf; - } - /* actual digits of result */ - while (--i >= 0) { - if (buf < end) - *buf = tmp[i]; - ++buf; - } - /* trailing space padding */ - while (--field_width >= 0) { - if (buf < end) - *buf = ' '; - ++buf; - } - - return buf; -} - -static noinline_for_stack -char *special_hex_number(char *buf, char *end, unsigned long long num, int size) -{ - struct printf_spec spec; - - spec.type = FORMAT_TYPE_PTR; - spec.field_width = 2 + 2 * size; /* 0x + hex */ - spec.flags = SPECIAL | SMALL | ZEROPAD; - spec.base = 16; - spec.precision = -1; - - return number(buf, end, num, spec); -} - -static void move_right(char *buf, char *end, unsigned len, unsigned spaces) -{ - size_t size; - if (buf >= end) /* nowhere to put anything */ - return; - size = end - buf; - if (size <= spaces) { - memset(buf, ' ', size); - return; - } - if (len) { - if (len > size - spaces) - len = size - spaces; - memmove(buf + spaces, buf, len); - } - memset(buf, ' ', spaces); -} - -/* - * Handle field width padding for a string. - * @buf: current buffer position - * @n: length of string - * @end: end of output buffer - * @spec: for field width and flags - * Returns: new buffer position after padding. - */ -static noinline_for_stack -char *widen_string(char *buf, int n, char *end, struct printf_spec spec) -{ - unsigned spaces; - - if (likely(n >= spec.field_width)) - return buf; - /* we want to pad the sucker */ - spaces = spec.field_width - n; - if (!(spec.flags & LEFT)) { - move_right(buf - n, end, n, spaces); - return buf + spaces; - } - while (spaces--) { - if (buf < end) - *buf = ' '; - ++buf; - } - return buf; -} - -static noinline_for_stack -char *string(char *buf, char *end, const char *s, struct printf_spec spec) -{ - int len = 0; - size_t lim = spec.precision; - - if ((unsigned long)s < PAGE_SIZE) - s = "(null)"; - - while (lim--) { - char c = *s++; - if (!c) - break; - if (buf < end) - *buf = c; - ++buf; - ++len; - } - return widen_string(buf, len, end, spec); -} - -static noinline_for_stack -char *dentry_name(char *buf, char *end, const struct dentry *d, struct printf_spec spec, - const char *fmt) -{ - const char *array[4], *s; - const struct dentry *p; - int depth; - int i, n; - - switch (fmt[1]) { - case '2': case '3': case '4': - depth = fmt[1] - '0'; - break; - default: - depth = 1; - } - - rcu_read_lock(); - for (i = 0; i < depth; i++, d = p) { - p = ACCESS_ONCE(d->d_parent); - array[i] = ACCESS_ONCE(d->d_name.name); - if (p == d) { - if (i) - array[i] = ""; - i++; - break; - } - } - s = array[--i]; - for (n = 0; n != spec.precision; n++, buf++) { - char c = *s++; - if (!c) { - if (!i) - break; - c = '/'; - s = array[--i]; - } - if (buf < end) - *buf = c; - } - rcu_read_unlock(); - return widen_string(buf, n, end, spec); -} - -#ifdef CONFIG_BLOCK -static noinline_for_stack -char *bdev_name(char *buf, char *end, struct block_device *bdev, - struct printf_spec spec, const char *fmt) -{ - struct gendisk *hd = bdev->bd_disk; - - buf = string(buf, end, hd->disk_name, spec); - if (bdev->bd_part->partno) { - if (isdigit(hd->disk_name[strlen(hd->disk_name)-1])) { - if (buf < end) - *buf = 'p'; - buf++; - } - buf = number(buf, end, bdev->bd_part->partno, spec); - } - return buf; -} -#endif - -static noinline_for_stack -char *symbol_string(char *buf, char *end, void *ptr, - struct printf_spec spec, const char *fmt) -{ - unsigned long value; -#ifdef CONFIG_KALLSYMS - char sym[KSYM_SYMBOL_LEN]; -#endif - - if (fmt[1] == 'R') - ptr = __builtin_extract_return_addr(ptr); - value = (unsigned long)ptr; - -#ifdef CONFIG_KALLSYMS - if (*fmt == 'B') - sprint_backtrace(sym, value); - else if (*fmt != 'f' && *fmt != 's') - sprint_symbol(sym, value); - else - sprint_symbol_no_offset(sym, value); - - return string(buf, end, sym, spec); -#else - return special_hex_number(buf, end, value, sizeof(void *)); -#endif -} - -static noinline_for_stack -char *resource_string(char *buf, char *end, struct resource *res, - struct printf_spec spec, const char *fmt) -{ -#ifndef IO_RSRC_PRINTK_SIZE -#define IO_RSRC_PRINTK_SIZE 6 -#endif - -#ifndef MEM_RSRC_PRINTK_SIZE -#define MEM_RSRC_PRINTK_SIZE 10 -#endif - static const struct printf_spec io_spec = { - .base = 16, - .field_width = IO_RSRC_PRINTK_SIZE, - .precision = -1, - .flags = SPECIAL | SMALL | ZEROPAD, - }; - static const struct printf_spec mem_spec = { - .base = 16, - .field_width = MEM_RSRC_PRINTK_SIZE, - .precision = -1, - .flags = SPECIAL | SMALL | ZEROPAD, - }; - static const struct printf_spec bus_spec = { - .base = 16, - .field_width = 2, - .precision = -1, - .flags = SMALL | ZEROPAD, - }; - static const struct printf_spec dec_spec = { - .base = 10, - .precision = -1, - .flags = 0, - }; - static const struct printf_spec str_spec = { - .field_width = -1, - .precision = 10, - .flags = LEFT, - }; - static const struct printf_spec flag_spec = { - .base = 16, - .precision = -1, - .flags = SPECIAL | SMALL, - }; - - /* 32-bit res (sizeof==4): 10 chars in dec, 10 in hex ("0x" + 8) - * 64-bit res (sizeof==8): 20 chars in dec, 18 in hex ("0x" + 16) */ -#define RSRC_BUF_SIZE ((2 * sizeof(resource_size_t)) + 4) -#define FLAG_BUF_SIZE (2 * sizeof(res->flags)) -#define DECODED_BUF_SIZE sizeof("[mem - 64bit pref window disabled]") -#define RAW_BUF_SIZE sizeof("[mem - flags 0x]") - char sym[max(2*RSRC_BUF_SIZE + DECODED_BUF_SIZE, - 2*RSRC_BUF_SIZE + FLAG_BUF_SIZE + RAW_BUF_SIZE)]; - - char *p = sym, *pend = sym + sizeof(sym); - int decode = (fmt[0] == 'R') ? 1 : 0; - const struct printf_spec *specp; - - *p++ = '['; - if (res->flags & IORESOURCE_IO) { - p = string(p, pend, "io ", str_spec); - specp = &io_spec; - } else if (res->flags & IORESOURCE_MEM) { - p = string(p, pend, "mem ", str_spec); - specp = &mem_spec; - } else if (res->flags & IORESOURCE_IRQ) { - p = string(p, pend, "irq ", str_spec); - specp = &dec_spec; - } else if (res->flags & IORESOURCE_DMA) { - p = string(p, pend, "dma ", str_spec); - specp = &dec_spec; - } else if (res->flags & IORESOURCE_BUS) { - p = string(p, pend, "bus ", str_spec); - specp = &bus_spec; - } else { - p = string(p, pend, "??? ", str_spec); - specp = &mem_spec; - decode = 0; - } - if (decode && res->flags & IORESOURCE_UNSET) { - p = string(p, pend, "size ", str_spec); - p = number(p, pend, resource_size(res), *specp); - } else { - p = number(p, pend, res->start, *specp); - if (res->start != res->end) { - *p++ = '-'; - p = number(p, pend, res->end, *specp); - } - } - if (decode) { - if (res->flags & IORESOURCE_MEM_64) - p = string(p, pend, " 64bit", str_spec); - if (res->flags & IORESOURCE_PREFETCH) - p = string(p, pend, " pref", str_spec); - if (res->flags & IORESOURCE_WINDOW) - p = string(p, pend, " window", str_spec); - if (res->flags & IORESOURCE_DISABLED) - p = string(p, pend, " disabled", str_spec); - } else { - p = string(p, pend, " flags ", str_spec); - p = number(p, pend, res->flags, flag_spec); - } - *p++ = ']'; - *p = '\0'; - - return string(buf, end, sym, spec); -} - -static noinline_for_stack -char *hex_string(char *buf, char *end, u8 *addr, struct printf_spec spec, - const char *fmt) -{ - int i, len = 1; /* if we pass '%ph[CDN]', field width remains - negative value, fallback to the default */ - char separator; - - if (spec.field_width == 0) - /* nothing to print */ - return buf; - - if (ZERO_OR_NULL_PTR(addr)) - /* NULL pointer */ - return string(buf, end, NULL, spec); - - switch (fmt[1]) { - case 'C': - separator = ':'; - break; - case 'D': - separator = '-'; - break; - case 'N': - separator = 0; - break; - default: - separator = ' '; - break; - } - - if (spec.field_width > 0) - len = min_t(int, spec.field_width, 64); - - for (i = 0; i < len; ++i) { - if (buf < end) - *buf = hex_asc_hi(addr[i]); - ++buf; - if (buf < end) - *buf = hex_asc_lo(addr[i]); - ++buf; - - if (separator && i != len - 1) { - if (buf < end) - *buf = separator; - ++buf; - } - } - - return buf; -} - -static noinline_for_stack -char *bitmap_string(char *buf, char *end, unsigned long *bitmap, - struct printf_spec spec, const char *fmt) -{ - const int CHUNKSZ = 32; - int nr_bits = max_t(int, spec.field_width, 0); - int i, chunksz; - bool first = true; - - /* reused to print numbers */ - spec = (struct printf_spec){ .flags = SMALL | ZEROPAD, .base = 16 }; - - chunksz = nr_bits & (CHUNKSZ - 1); - if (chunksz == 0) - chunksz = CHUNKSZ; - - i = ALIGN(nr_bits, CHUNKSZ) - CHUNKSZ; - for (; i >= 0; i -= CHUNKSZ) { - u32 chunkmask, val; - int word, bit; - - chunkmask = ((1ULL << chunksz) - 1); - word = i / BITS_PER_LONG; - bit = i % BITS_PER_LONG; - val = (bitmap[word] >> bit) & chunkmask; - - if (!first) { - if (buf < end) - *buf = ','; - buf++; - } - first = false; - - spec.field_width = DIV_ROUND_UP(chunksz, 4); - buf = number(buf, end, val, spec); - - chunksz = CHUNKSZ; - } - return buf; -} - -static noinline_for_stack -char *bitmap_list_string(char *buf, char *end, unsigned long *bitmap, - struct printf_spec spec, const char *fmt) -{ - int nr_bits = max_t(int, spec.field_width, 0); - /* current bit is 'cur', most recently seen range is [rbot, rtop] */ - int cur, rbot, rtop; - bool first = true; - - /* reused to print numbers */ - spec = (struct printf_spec){ .base = 10 }; - - rbot = cur = find_first_bit(bitmap, nr_bits); - while (cur < nr_bits) { - rtop = cur; - cur = find_next_bit(bitmap, nr_bits, cur + 1); - if (cur < nr_bits && cur <= rtop + 1) - continue; - - if (!first) { - if (buf < end) - *buf = ','; - buf++; - } - first = false; - - buf = number(buf, end, rbot, spec); - if (rbot < rtop) { - if (buf < end) - *buf = '-'; - buf++; - - buf = number(buf, end, rtop, spec); - } - - rbot = cur; - } - return buf; -} - -static noinline_for_stack -char *mac_address_string(char *buf, char *end, u8 *addr, - struct printf_spec spec, const char *fmt) -{ - char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")]; - char *p = mac_addr; - int i; - char separator; - bool reversed = false; - - switch (fmt[1]) { - case 'F': - separator = '-'; - break; - - case 'R': - reversed = true; - /* fall through */ - - default: - separator = ':'; - break; - } - - for (i = 0; i < 6; i++) { - if (reversed) - p = hex_byte_pack(p, addr[5 - i]); - else - p = hex_byte_pack(p, addr[i]); - - if (fmt[0] == 'M' && i != 5) - *p++ = separator; - } - *p = '\0'; - - return string(buf, end, mac_addr, spec); -} - -static noinline_for_stack -char *ip4_string(char *p, const u8 *addr, const char *fmt) -{ - int i; - bool leading_zeros = (fmt[0] == 'i'); - int index; - int step; - - switch (fmt[2]) { - case 'h': -#ifdef __BIG_ENDIAN - index = 0; - step = 1; -#else - index = 3; - step = -1; -#endif - break; - case 'l': - index = 3; - step = -1; - break; - case 'n': - case 'b': - default: - index = 0; - step = 1; - break; - } - for (i = 0; i < 4; i++) { - char temp[4] __aligned(2); /* hold each IP quad in reverse order */ - int digits = put_dec_trunc8(temp, addr[index]) - temp; - if (leading_zeros) { - if (digits < 3) - *p++ = '0'; - if (digits < 2) - *p++ = '0'; - } - /* reverse the digits in the quad */ - while (digits--) - *p++ = temp[digits]; - if (i < 3) - *p++ = '.'; - index += step; - } - *p = '\0'; - - return p; -} - -static noinline_for_stack -char *ip6_compressed_string(char *p, const char *addr) -{ - int i, j, range; - unsigned char zerolength[8]; - int longest = 1; - int colonpos = -1; - u16 word; - u8 hi, lo; - bool needcolon = false; - bool useIPv4; - struct in6_addr in6; - - memcpy(&in6, addr, sizeof(struct in6_addr)); - - useIPv4 = ipv6_addr_v4mapped(&in6) || ipv6_addr_is_isatap(&in6); - - memset(zerolength, 0, sizeof(zerolength)); - - if (useIPv4) - range = 6; - else - range = 8; - - /* find position of longest 0 run */ - for (i = 0; i < range; i++) { - for (j = i; j < range; j++) { - if (in6.s6_addr16[j] != 0) - break; - zerolength[i]++; - } - } - for (i = 0; i < range; i++) { - if (zerolength[i] > longest) { - longest = zerolength[i]; - colonpos = i; - } - } - if (longest == 1) /* don't compress a single 0 */ - colonpos = -1; - - /* emit address */ - for (i = 0; i < range; i++) { - if (i == colonpos) { - if (needcolon || i == 0) - *p++ = ':'; - *p++ = ':'; - needcolon = false; - i += longest - 1; - continue; - } - if (needcolon) { - *p++ = ':'; - needcolon = false; - } - /* hex u16 without leading 0s */ - word = ntohs(in6.s6_addr16[i]); - hi = word >> 8; - lo = word & 0xff; - if (hi) { - if (hi > 0x0f) - p = hex_byte_pack(p, hi); - else - *p++ = hex_asc_lo(hi); - p = hex_byte_pack(p, lo); - } - else if (lo > 0x0f) - p = hex_byte_pack(p, lo); - else - *p++ = hex_asc_lo(lo); - needcolon = true; - } - - if (useIPv4) { - if (needcolon) - *p++ = ':'; - p = ip4_string(p, &in6.s6_addr[12], "I4"); - } - *p = '\0'; - - return p; -} - -static noinline_for_stack -char *ip6_string(char *p, const char *addr, const char *fmt) -{ - int i; - - for (i = 0; i < 8; i++) { - p = hex_byte_pack(p, *addr++); - p = hex_byte_pack(p, *addr++); - if (fmt[0] == 'I' && i != 7) - *p++ = ':'; - } - *p = '\0'; - - return p; -} - -static noinline_for_stack -char *ip6_addr_string(char *buf, char *end, const u8 *addr, - struct printf_spec spec, const char *fmt) -{ - char ip6_addr[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255")]; - - if (fmt[0] == 'I' && fmt[2] == 'c') - ip6_compressed_string(ip6_addr, addr); - else - ip6_string(ip6_addr, addr, fmt); - - return string(buf, end, ip6_addr, spec); -} - -static noinline_for_stack -char *ip4_addr_string(char *buf, char *end, const u8 *addr, - struct printf_spec spec, const char *fmt) -{ - char ip4_addr[sizeof("255.255.255.255")]; - - ip4_string(ip4_addr, addr, fmt); - - return string(buf, end, ip4_addr, spec); -} - -static noinline_for_stack -char *ip6_addr_string_sa(char *buf, char *end, const struct sockaddr_in6 *sa, - struct printf_spec spec, const char *fmt) -{ - bool have_p = false, have_s = false, have_f = false, have_c = false; - char ip6_addr[sizeof("[xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255]") + - sizeof(":12345") + sizeof("/123456789") + - sizeof("%1234567890")]; - char *p = ip6_addr, *pend = ip6_addr + sizeof(ip6_addr); - const u8 *addr = (const u8 *) &sa->sin6_addr; - char fmt6[2] = { fmt[0], '6' }; - u8 off = 0; - - fmt++; - while (isalpha(*++fmt)) { - switch (*fmt) { - case 'p': - have_p = true; - break; - case 'f': - have_f = true; - break; - case 's': - have_s = true; - break; - case 'c': - have_c = true; - break; - } - } - - if (have_p || have_s || have_f) { - *p = '['; - off = 1; - } - - if (fmt6[0] == 'I' && have_c) - p = ip6_compressed_string(ip6_addr + off, addr); - else - p = ip6_string(ip6_addr + off, addr, fmt6); - - if (have_p || have_s || have_f) - *p++ = ']'; - - if (have_p) { - *p++ = ':'; - p = number(p, pend, ntohs(sa->sin6_port), spec); - } - if (have_f) { - *p++ = '/'; - p = number(p, pend, ntohl(sa->sin6_flowinfo & - IPV6_FLOWINFO_MASK), spec); - } - if (have_s) { - *p++ = '%'; - p = number(p, pend, sa->sin6_scope_id, spec); - } - *p = '\0'; - - return string(buf, end, ip6_addr, spec); -} - -static noinline_for_stack -char *ip4_addr_string_sa(char *buf, char *end, const struct sockaddr_in *sa, - struct printf_spec spec, const char *fmt) -{ - bool have_p = false; - char *p, ip4_addr[sizeof("255.255.255.255") + sizeof(":12345")]; - char *pend = ip4_addr + sizeof(ip4_addr); - const u8 *addr = (const u8 *) &sa->sin_addr.s_addr; - char fmt4[3] = { fmt[0], '4', 0 }; - - fmt++; - while (isalpha(*++fmt)) { - switch (*fmt) { - case 'p': - have_p = true; - break; - case 'h': - case 'l': - case 'n': - case 'b': - fmt4[2] = *fmt; - break; - } - } - - p = ip4_string(ip4_addr, addr, fmt4); - if (have_p) { - *p++ = ':'; - p = number(p, pend, ntohs(sa->sin_port), spec); - } - *p = '\0'; - - return string(buf, end, ip4_addr, spec); -} - -static noinline_for_stack -char *escaped_string(char *buf, char *end, u8 *addr, struct printf_spec spec, - const char *fmt) -{ - bool found = true; - int count = 1; - unsigned int flags = 0; - int len; - - if (spec.field_width == 0) - return buf; /* nothing to print */ - - if (ZERO_OR_NULL_PTR(addr)) - return string(buf, end, NULL, spec); /* NULL pointer */ - - - do { - switch (fmt[count++]) { - case 'a': - flags |= ESCAPE_ANY; - break; - case 'c': - flags |= ESCAPE_SPECIAL; - break; - case 'h': - flags |= ESCAPE_HEX; - break; - case 'n': - flags |= ESCAPE_NULL; - break; - case 'o': - flags |= ESCAPE_OCTAL; - break; - case 'p': - flags |= ESCAPE_NP; - break; - case 's': - flags |= ESCAPE_SPACE; - break; - default: - found = false; - break; - } - } while (found); - - if (!flags) - flags = ESCAPE_ANY_NP; - - len = spec.field_width < 0 ? 1 : spec.field_width; - - /* - * string_escape_mem() writes as many characters as it can to - * the given buffer, and returns the total size of the output - * had the buffer been big enough. - */ - buf += string_escape_mem(addr, len, buf, buf < end ? end - buf : 0, flags, NULL); - - return buf; -} - -static noinline_for_stack -char *uuid_string(char *buf, char *end, const u8 *addr, - struct printf_spec spec, const char *fmt) -{ - char uuid[UUID_STRING_LEN + 1]; - char *p = uuid; - int i; - const u8 *index = uuid_be_index; - bool uc = false; - - switch (*(++fmt)) { - case 'L': - uc = true; /* fall-through */ - case 'l': - index = uuid_le_index; - break; - case 'B': - uc = true; - break; - } - - for (i = 0; i < 16; i++) { - if (uc) - p = hex_byte_pack_upper(p, addr[index[i]]); - else - p = hex_byte_pack(p, addr[index[i]]); - switch (i) { - case 3: - case 5: - case 7: - case 9: - *p++ = '-'; - break; - } - } - - *p = 0; - - return string(buf, end, uuid, spec); -} - -static noinline_for_stack -char *netdev_bits(char *buf, char *end, const void *addr, const char *fmt) -{ - unsigned long long num; - int size; - - switch (fmt[1]) { - case 'F': - num = *(const netdev_features_t *)addr; - size = sizeof(netdev_features_t); - break; - default: - num = (unsigned long)addr; - size = sizeof(unsigned long); - break; - } - - return special_hex_number(buf, end, num, size); -} - -static noinline_for_stack -char *address_val(char *buf, char *end, const void *addr, const char *fmt) -{ - unsigned long long num; - int size; - - switch (fmt[1]) { - case 'd': - num = *(const dma_addr_t *)addr; - size = sizeof(dma_addr_t); - break; - case 'p': - default: - num = *(const phys_addr_t *)addr; - size = sizeof(phys_addr_t); - break; - } - - return special_hex_number(buf, end, num, size); -} - -static noinline_for_stack -char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec, - const char *fmt) -{ - if (!IS_ENABLED(CONFIG_HAVE_CLK) || !clk) - return string(buf, end, NULL, spec); - - switch (fmt[1]) { - case 'r': - return number(buf, end, clk_get_rate(clk), spec); - - case 'n': - default: -#ifdef CONFIG_COMMON_CLK - return string(buf, end, __clk_get_name(clk), spec); -#else - return special_hex_number(buf, end, (unsigned long)clk, sizeof(unsigned long)); -#endif - } -} - -static -char *format_flags(char *buf, char *end, unsigned long flags, - const struct trace_print_flags *names) -{ - unsigned long mask; - const struct printf_spec strspec = { - .field_width = -1, - .precision = -1, - }; - const struct printf_spec numspec = { - .flags = SPECIAL|SMALL, - .field_width = -1, - .precision = -1, - .base = 16, - }; - - for ( ; flags && names->name; names++) { - mask = names->mask; - if ((flags & mask) != mask) - continue; - - buf = string(buf, end, names->name, strspec); - - flags &= ~mask; - if (flags) { - if (buf < end) - *buf = '|'; - buf++; - } - } - - if (flags) - buf = number(buf, end, flags, numspec); - - return buf; -} - -static noinline_for_stack -char *flags_string(char *buf, char *end, void *flags_ptr, const char *fmt) -{ - unsigned long flags; - const struct trace_print_flags *names; - - switch (fmt[1]) { - case 'p': - flags = *(unsigned long *)flags_ptr; - /* Remove zone id */ - flags &= (1UL << NR_PAGEFLAGS) - 1; - names = pageflag_names; - break; - case 'v': - flags = *(unsigned long *)flags_ptr; - names = vmaflag_names; - break; - case 'g': - flags = *(gfp_t *)flags_ptr; - names = gfpflag_names; - break; - default: - WARN_ONCE(1, "Unsupported flags modifier: %c\n", fmt[1]); - return buf; - } - - return format_flags(buf, end, flags, names); -} - -int kptr_restrict __read_mostly; - -/* - * Show a '%p' thing. A kernel extension is that the '%p' is followed - * by an extra set of alphanumeric characters that are extended format - * specifiers. - * - * Right now we handle: - * - * - 'F' For symbolic function descriptor pointers with offset - * - 'f' For simple symbolic function names without offset - * - 'S' For symbolic direct pointers with offset - * - 's' For symbolic direct pointers without offset - * - '[FfSs]R' as above with __builtin_extract_return_addr() translation - * - 'B' For backtraced symbolic direct pointers with offset - * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref] - * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201] - * - 'b[l]' For a bitmap, the number of bits is determined by the field - * width which must be explicitly specified either as part of the - * format string '%32b[l]' or through '%*b[l]', [l] selects - * range-list format instead of hex format - * - 'M' For a 6-byte MAC address, it prints the address in the - * usual colon-separated hex notation - * - 'm' For a 6-byte MAC address, it prints the hex address without colons - * - 'MF' For a 6-byte MAC FDDI address, it prints the address - * with a dash-separated hex notation - * - '[mM]R' For a 6-byte MAC address, Reverse order (Bluetooth) - * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way - * IPv4 uses dot-separated decimal without leading 0's (1.2.3.4) - * IPv6 uses colon separated network-order 16 bit hex with leading 0's - * [S][pfs] - * Generic IPv4/IPv6 address (struct sockaddr *) that falls back to - * [4] or [6] and is able to print port [p], flowinfo [f], scope [s] - * - 'i' [46] for 'raw' IPv4/IPv6 addresses - * IPv6 omits the colons (01020304...0f) - * IPv4 uses dot-separated decimal with leading 0's (010.123.045.006) - * [S][pfs] - * Generic IPv4/IPv6 address (struct sockaddr *) that falls back to - * [4] or [6] and is able to print port [p], flowinfo [f], scope [s] - * - '[Ii][4S][hnbl]' IPv4 addresses in host, network, big or little endian order - * - 'I[6S]c' for IPv6 addresses printed as specified by - * http://tools.ietf.org/html/rfc5952 - * - 'E[achnops]' For an escaped buffer, where rules are defined by combination - * of the following flags (see string_escape_mem() for the - * details): - * a - ESCAPE_ANY - * c - ESCAPE_SPECIAL - * h - ESCAPE_HEX - * n - ESCAPE_NULL - * o - ESCAPE_OCTAL - * p - ESCAPE_NP - * s - ESCAPE_SPACE - * By default ESCAPE_ANY_NP is used. - * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form - * "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" - * Options for %pU are: - * b big endian lower case hex (default) - * B big endian UPPER case hex - * l little endian lower case hex - * L little endian UPPER case hex - * big endian output byte order is: - * [0][1][2][3]-[4][5]-[6][7]-[8][9]-[10][11][12][13][14][15] - * little endian output byte order is: - * [3][2][1][0]-[5][4]-[7][6]-[8][9]-[10][11][12][13][14][15] - * - 'V' For a struct va_format which contains a format string * and va_list *, - * call vsnprintf(->format, *->va_list). - * Implements a "recursive vsnprintf". - * Do not use this feature without some mechanism to verify the - * correctness of the format string and va_list arguments. - * - 'K' For a kernel pointer that should be hidden from unprivileged users - * - 'NF' For a netdev_features_t - * - 'h[CDN]' For a variable-length buffer, it prints it as a hex string with - * a certain separator (' ' by default): - * C colon - * D dash - * N no separator - * The maximum supported length is 64 bytes of the input. Consider - * to use print_hex_dump() for the larger input. - * - 'a[pd]' For address types [p] phys_addr_t, [d] dma_addr_t and derivatives - * (default assumed to be phys_addr_t, passed by reference) - * - 'd[234]' For a dentry name (optionally 2-4 last components) - * - 'D[234]' Same as 'd' but for a struct file - * - 'g' For block_device name (gendisk + partition number) - * - 'C' For a clock, it prints the name (Common Clock Framework) or address - * (legacy clock framework) of the clock - * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address - * (legacy clock framework) of the clock - * - 'Cr' For a clock, it prints the current rate of the clock - * - 'G' For flags to be printed as a collection of symbolic strings that would - * construct the specific value. Supported flags given by option: - * p page flags (see struct page) given as pointer to unsigned long - * g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t - * v vma flags (VM_*) given as pointer to unsigned long - * - * ** Please update also Documentation/printk-formats.txt when making changes ** - * - * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 - * function pointers are really function descriptors, which contain a - * pointer to the real address. - */ -static noinline_for_stack -char *pointer(const char *fmt, char *buf, char *end, void *ptr, - struct printf_spec spec) -{ - const int default_width = 2 * sizeof(void *); - - if (!ptr && *fmt != 'K') { - /* - * Print (null) with the same width as a pointer so it makes - * tabular output look nice. - */ - if (spec.field_width == -1) - spec.field_width = default_width; - return string(buf, end, "(null)", spec); - } - - switch (*fmt) { - case 'F': - case 'f': - ptr = dereference_function_descriptor(ptr); - /* Fallthrough */ - case 'S': - case 's': - case 'B': - return symbol_string(buf, end, ptr, spec, fmt); - case 'R': - case 'r': - return resource_string(buf, end, ptr, spec, fmt); - case 'h': - return hex_string(buf, end, ptr, spec, fmt); - case 'b': - switch (fmt[1]) { - case 'l': - return bitmap_list_string(buf, end, ptr, spec, fmt); - default: - return bitmap_string(buf, end, ptr, spec, fmt); - } - case 'M': /* Colon separated: 00:01:02:03:04:05 */ - case 'm': /* Contiguous: 000102030405 */ - /* [mM]F (FDDI) */ - /* [mM]R (Reverse order; Bluetooth) */ - return mac_address_string(buf, end, ptr, spec, fmt); - case 'I': /* Formatted IP supported - * 4: 1.2.3.4 - * 6: 0001:0203:...:0708 - * 6c: 1::708 or 1::1.2.3.4 - */ - case 'i': /* Contiguous: - * 4: 001.002.003.004 - * 6: 000102...0f - */ - switch (fmt[1]) { - case '6': - return ip6_addr_string(buf, end, ptr, spec, fmt); - case '4': - return ip4_addr_string(buf, end, ptr, spec, fmt); - case 'S': { - const union { - struct sockaddr raw; - struct sockaddr_in v4; - struct sockaddr_in6 v6; - } *sa = ptr; - - switch (sa->raw.sa_family) { - case AF_INET: - return ip4_addr_string_sa(buf, end, &sa->v4, spec, fmt); - case AF_INET6: - return ip6_addr_string_sa(buf, end, &sa->v6, spec, fmt); - default: - return string(buf, end, "(invalid address)", spec); - }} - } - break; - case 'E': - return escaped_string(buf, end, ptr, spec, fmt); - case 'U': - return uuid_string(buf, end, ptr, spec, fmt); - case 'V': - { - va_list va; - - va_copy(va, *((struct va_format *)ptr)->va); - buf += vsnprintf(buf, end > buf ? end - buf : 0, - ((struct va_format *)ptr)->fmt, va); - va_end(va); - return buf; - } - case 'K': - switch (kptr_restrict) { - case 0: - /* Always print %pK values */ - break; - case 1: { - const struct cred *cred; - - /* - * kptr_restrict==1 cannot be used in IRQ context - * because its test for CAP_SYSLOG would be meaningless. - */ - if (in_irq() || in_serving_softirq() || in_nmi()) { - if (spec.field_width == -1) - spec.field_width = default_width; - return string(buf, end, "pK-error", spec); - } - - /* - * Only print the real pointer value if the current - * process has CAP_SYSLOG and is running with the - * same credentials it started with. This is because - * access to files is checked at open() time, but %pK - * checks permission at read() time. We don't want to - * leak pointer values if a binary opens a file using - * %pK and then elevates privileges before reading it. - */ - cred = current_cred(); - if (!has_capability_noaudit(current, CAP_SYSLOG) || - !uid_eq(cred->euid, cred->uid) || - !gid_eq(cred->egid, cred->gid)) - ptr = NULL; - break; - } - case 2: - default: - /* Always print 0's for %pK */ - ptr = NULL; - break; - } - break; - - case 'N': - return netdev_bits(buf, end, ptr, fmt); - case 'a': - return address_val(buf, end, ptr, fmt); - case 'd': - return dentry_name(buf, end, ptr, spec, fmt); - case 'C': - return clock(buf, end, ptr, spec, fmt); - case 'D': - return dentry_name(buf, end, - ((const struct file *)ptr)->f_path.dentry, - spec, fmt); -#ifdef CONFIG_BLOCK - case 'g': - return bdev_name(buf, end, ptr, spec, fmt); -#endif - - case 'G': - return flags_string(buf, end, ptr, fmt); - } - spec.flags |= SMALL; - if (spec.field_width == -1) { - spec.field_width = default_width; - spec.flags |= ZEROPAD; - } - spec.base = 16; - - return number(buf, end, (unsigned long) ptr, spec); -} - -/* - * Helper function to decode printf style format. - * Each call decode a token from the format and return the - * number of characters read (or likely the delta where it wants - * to go on the next call). - * The decoded token is returned through the parameters - * - * 'h', 'l', or 'L' for integer fields - * 'z' support added 23/7/1999 S.H. - * 'z' changed to 'Z' --davidm 1/25/99 - * 't' added for ptrdiff_t - * - * @fmt: the format string - * @type of the token returned - * @flags: various flags such as +, -, # tokens.. - * @field_width: overwritten width - * @base: base of the number (octal, hex, ...) - * @precision: precision of a number - * @qualifier: qualifier of a number (long, size_t, ...) - */ -static noinline_for_stack -int format_decode(const char *fmt, struct printf_spec *spec) -{ - const char *start = fmt; - char qualifier; - - /* we finished early by reading the field width */ - if (spec->type == FORMAT_TYPE_WIDTH) { - if (spec->field_width < 0) { - spec->field_width = -spec->field_width; - spec->flags |= LEFT; - } - spec->type = FORMAT_TYPE_NONE; - goto precision; - } - - /* we finished early by reading the precision */ - if (spec->type == FORMAT_TYPE_PRECISION) { - if (spec->precision < 0) - spec->precision = 0; - - spec->type = FORMAT_TYPE_NONE; - goto qualifier; - } - - /* By default */ - spec->type = FORMAT_TYPE_NONE; - - for (; *fmt ; ++fmt) { - if (*fmt == '%') - break; - } - - /* Return the current non-format string */ - if (fmt != start || !*fmt) - return fmt - start; - - /* Process flags */ - spec->flags = 0; - - while (1) { /* this also skips first '%' */ - bool found = true; - - ++fmt; - - switch (*fmt) { - case '-': spec->flags |= LEFT; break; - case '+': spec->flags |= PLUS; break; - case ' ': spec->flags |= SPACE; break; - case '#': spec->flags |= SPECIAL; break; - case '0': spec->flags |= ZEROPAD; break; - default: found = false; - } - - if (!found) - break; - } - - /* get field width */ - spec->field_width = -1; - - if (isdigit(*fmt)) - spec->field_width = skip_atoi(&fmt); - else if (*fmt == '*') { - /* it's the next argument */ - spec->type = FORMAT_TYPE_WIDTH; - return ++fmt - start; - } - -precision: - /* get the precision */ - spec->precision = -1; - if (*fmt == '.') { - ++fmt; - if (isdigit(*fmt)) { - spec->precision = skip_atoi(&fmt); - if (spec->precision < 0) - spec->precision = 0; - } else if (*fmt == '*') { - /* it's the next argument */ - spec->type = FORMAT_TYPE_PRECISION; - return ++fmt - start; - } - } - -qualifier: - /* get the conversion qualifier */ - qualifier = 0; - if (*fmt == 'h' || _tolower(*fmt) == 'l' || - _tolower(*fmt) == 'z' || *fmt == 't') { - qualifier = *fmt++; - if (unlikely(qualifier == *fmt)) { - if (qualifier == 'l') { - qualifier = 'L'; - ++fmt; - } else if (qualifier == 'h') { - qualifier = 'H'; - ++fmt; - } - } - } - - /* default base */ - spec->base = 10; - switch (*fmt) { - case 'c': - spec->type = FORMAT_TYPE_CHAR; - return ++fmt - start; - - case 's': - spec->type = FORMAT_TYPE_STR; - return ++fmt - start; - - case 'p': - spec->type = FORMAT_TYPE_PTR; - return ++fmt - start; - - case '%': - spec->type = FORMAT_TYPE_PERCENT_CHAR; - return ++fmt - start; - - /* integer number formats - set up the flags and "break" */ - case 'o': - spec->base = 8; - break; - - case 'x': - spec->flags |= SMALL; - - case 'X': - spec->base = 16; - break; - - case 'd': - case 'i': - spec->flags |= SIGN; - case 'u': - break; - - case 'n': - /* - * Since %n poses a greater security risk than - * utility, treat it as any other invalid or - * unsupported format specifier. - */ - /* Fall-through */ - - default: - WARN_ONCE(1, "Please remove unsupported %%%c in format string\n", *fmt); - spec->type = FORMAT_TYPE_INVALID; - return fmt - start; - } - - if (qualifier == 'L') - spec->type = FORMAT_TYPE_LONG_LONG; - else if (qualifier == 'l') { - BUILD_BUG_ON(FORMAT_TYPE_ULONG + SIGN != FORMAT_TYPE_LONG); - spec->type = FORMAT_TYPE_ULONG + (spec->flags & SIGN); - } else if (_tolower(qualifier) == 'z') { - spec->type = FORMAT_TYPE_SIZE_T; - } else if (qualifier == 't') { - spec->type = FORMAT_TYPE_PTRDIFF; - } else if (qualifier == 'H') { - BUILD_BUG_ON(FORMAT_TYPE_UBYTE + SIGN != FORMAT_TYPE_BYTE); - spec->type = FORMAT_TYPE_UBYTE + (spec->flags & SIGN); - } else if (qualifier == 'h') { - BUILD_BUG_ON(FORMAT_TYPE_USHORT + SIGN != FORMAT_TYPE_SHORT); - spec->type = FORMAT_TYPE_USHORT + (spec->flags & SIGN); - } else { - BUILD_BUG_ON(FORMAT_TYPE_UINT + SIGN != FORMAT_TYPE_INT); - spec->type = FORMAT_TYPE_UINT + (spec->flags & SIGN); - } - - return ++fmt - start; -} - -static void -set_field_width(struct printf_spec *spec, int width) -{ - spec->field_width = width; - if (WARN_ONCE(spec->field_width != width, "field width %d too large", width)) { - spec->field_width = clamp(width, -FIELD_WIDTH_MAX, FIELD_WIDTH_MAX); - } -} - -static void -set_precision(struct printf_spec *spec, int prec) -{ - spec->precision = prec; - if (WARN_ONCE(spec->precision != prec, "precision %d too large", prec)) { - spec->precision = clamp(prec, 0, PRECISION_MAX); - } -} - -/** - * vsnprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into - * @size: The size of the buffer, including the trailing null space - * @fmt: The format string to use - * @args: Arguments for the format string - * - * This function generally follows C99 vsnprintf, but has some - * extensions and a few limitations: - * - * %n is unsupported - * %p* is handled by pointer() - * - * See pointer() or Documentation/printk-formats.txt for more - * extensive description. - * - * ** Please update the documentation in both places when making changes ** - * - * The return value is the number of characters which would - * be generated for the given input, excluding the trailing - * '\0', as per ISO C99. If you want to have the exact - * number of characters written into @buf as return value - * (not including the trailing '\0'), use vscnprintf(). If the - * return is greater than or equal to @size, the resulting - * string is truncated. - * - * If you're not already dealing with a va_list consider using snprintf(). - */ -int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) -{ - unsigned long long num; - char *str, *end; - struct printf_spec spec = {0}; - - /* Reject out-of-range values early. Large positive sizes are - used for unknown buffer sizes. */ - if (WARN_ON_ONCE(size > INT_MAX)) - return 0; - - str = buf; - end = buf + size; - - /* Make sure end is always >= buf */ - if (end < buf) { - end = ((void *)-1); - size = end - buf; - } - - while (*fmt) { - const char *old_fmt = fmt; - int read = format_decode(fmt, &spec); - - fmt += read; - - switch (spec.type) { - case FORMAT_TYPE_NONE: { - int copy = read; - if (str < end) { - if (copy > end - str) - copy = end - str; - memcpy(str, old_fmt, copy); - } - str += read; - break; - } - - case FORMAT_TYPE_WIDTH: - set_field_width(&spec, va_arg(args, int)); - break; - - case FORMAT_TYPE_PRECISION: - set_precision(&spec, va_arg(args, int)); - break; - - case FORMAT_TYPE_CHAR: { - char c; - - if (!(spec.flags & LEFT)) { - while (--spec.field_width > 0) { - if (str < end) - *str = ' '; - ++str; - - } - } - c = (unsigned char) va_arg(args, int); - if (str < end) - *str = c; - ++str; - while (--spec.field_width > 0) { - if (str < end) - *str = ' '; - ++str; - } - break; - } - - case FORMAT_TYPE_STR: - str = string(str, end, va_arg(args, char *), spec); - break; - - case FORMAT_TYPE_PTR: - str = pointer(fmt, str, end, va_arg(args, void *), - spec); - while (isalnum(*fmt)) - fmt++; - break; - - case FORMAT_TYPE_PERCENT_CHAR: - if (str < end) - *str = '%'; - ++str; - break; - - case FORMAT_TYPE_INVALID: - /* - * Presumably the arguments passed gcc's type - * checking, but there is no safe or sane way - * for us to continue parsing the format and - * fetching from the va_list; the remaining - * specifiers and arguments would be out of - * sync. - */ - goto out; - - default: - switch (spec.type) { - case FORMAT_TYPE_LONG_LONG: - num = va_arg(args, long long); - break; - case FORMAT_TYPE_ULONG: - num = va_arg(args, unsigned long); - break; - case FORMAT_TYPE_LONG: - num = va_arg(args, long); - break; - case FORMAT_TYPE_SIZE_T: - if (spec.flags & SIGN) - num = va_arg(args, ssize_t); - else - num = va_arg(args, size_t); - break; - case FORMAT_TYPE_PTRDIFF: - num = va_arg(args, ptrdiff_t); - break; - case FORMAT_TYPE_UBYTE: - num = (unsigned char) va_arg(args, int); - break; - case FORMAT_TYPE_BYTE: - num = (signed char) va_arg(args, int); - break; - case FORMAT_TYPE_USHORT: - num = (unsigned short) va_arg(args, int); - break; - case FORMAT_TYPE_SHORT: - num = (short) va_arg(args, int); - break; - case FORMAT_TYPE_INT: - num = (int) va_arg(args, int); - break; - default: - num = va_arg(args, unsigned int); - } - - str = number(str, end, num, spec); - } - } - -out: - if (size > 0) { - if (str < end) - *str = '\0'; - else - end[-1] = '\0'; - } - - /* the trailing null byte doesn't count towards the total */ - return str-buf; - -} -EXPORT_SYMBOL(vsnprintf); - -/** - * vscnprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into - * @size: The size of the buffer, including the trailing null space - * @fmt: The format string to use - * @args: Arguments for the format string - * - * The return value is the number of characters which have been written into - * the @buf not including the trailing '\0'. If @size is == 0 the function - * returns 0. - * - * If you're not already dealing with a va_list consider using scnprintf(). - * - * See the vsnprintf() documentation for format string extensions over C99. - */ -int vscnprintf(char *buf, size_t size, const char *fmt, va_list args) -{ - int i; - - i = vsnprintf(buf, size, fmt, args); - - if (likely(i < size)) - return i; - if (size != 0) - return size - 1; - return 0; -} -EXPORT_SYMBOL(vscnprintf); - -/** - * snprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into - * @size: The size of the buffer, including the trailing null space - * @fmt: The format string to use - * @...: Arguments for the format string - * - * The return value is the number of characters which would be - * generated for the given input, excluding the trailing null, - * as per ISO C99. If the return is greater than or equal to - * @size, the resulting string is truncated. - * - * See the vsnprintf() documentation for format string extensions over C99. - */ -int snprintf(char *buf, size_t size, const char *fmt, ...) -{ - va_list args; - int i; - - va_start(args, fmt); - i = vsnprintf(buf, size, fmt, args); - va_end(args); - - return i; -} -EXPORT_SYMBOL(snprintf); - -/** - * scnprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into - * @size: The size of the buffer, including the trailing null space - * @fmt: The format string to use - * @...: Arguments for the format string - * - * The return value is the number of characters written into @buf not including - * the trailing '\0'. If @size is == 0 the function returns 0. - */ - -int scnprintf(char *buf, size_t size, const char *fmt, ...) -{ - va_list args; - int i; - - va_start(args, fmt); - i = vscnprintf(buf, size, fmt, args); - va_end(args); - - return i; -} -EXPORT_SYMBOL(scnprintf); - -/** - * vsprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into - * @fmt: The format string to use - * @args: Arguments for the format string - * - * The function returns the number of characters written - * into @buf. Use vsnprintf() or vscnprintf() in order to avoid - * buffer overflows. - * - * If you're not already dealing with a va_list consider using sprintf(). - * - * See the vsnprintf() documentation for format string extensions over C99. - */ -int vsprintf(char *buf, const char *fmt, va_list args) -{ - return vsnprintf(buf, INT_MAX, fmt, args); -} -EXPORT_SYMBOL(vsprintf); - -/** - * sprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into - * @fmt: The format string to use - * @...: Arguments for the format string - * - * The function returns the number of characters written - * into @buf. Use snprintf() or scnprintf() in order to avoid - * buffer overflows. - * - * See the vsnprintf() documentation for format string extensions over C99. - */ -int sprintf(char *buf, const char *fmt, ...) -{ - va_list args; - int i; - - va_start(args, fmt); - i = vsnprintf(buf, INT_MAX, fmt, args); - va_end(args); - - return i; -} -EXPORT_SYMBOL(sprintf); - -#ifdef CONFIG_BINARY_PRINTF -/* - * bprintf service: - * vbin_printf() - VA arguments to binary data - * bstr_printf() - Binary data to text string - */ - -/** - * vbin_printf - Parse a format string and place args' binary value in a buffer - * @bin_buf: The buffer to place args' binary value - * @size: The size of the buffer(by words(32bits), not characters) - * @fmt: The format string to use - * @args: Arguments for the format string - * - * The format follows C99 vsnprintf, except %n is ignored, and its argument - * is skipped. - * - * The return value is the number of words(32bits) which would be generated for - * the given input. - * - * NOTE: - * If the return value is greater than @size, the resulting bin_buf is NOT - * valid for bstr_printf(). - */ -int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args) -{ - struct printf_spec spec = {0}; - char *str, *end; - - str = (char *)bin_buf; - end = (char *)(bin_buf + size); - -#define save_arg(type) \ -do { \ - if (sizeof(type) == 8) { \ - unsigned long long value; \ - str = PTR_ALIGN(str, sizeof(u32)); \ - value = va_arg(args, unsigned long long); \ - if (str + sizeof(type) <= end) { \ - *(u32 *)str = *(u32 *)&value; \ - *(u32 *)(str + 4) = *((u32 *)&value + 1); \ - } \ - } else { \ - unsigned long value; \ - str = PTR_ALIGN(str, sizeof(type)); \ - value = va_arg(args, int); \ - if (str + sizeof(type) <= end) \ - *(typeof(type) *)str = (type)value; \ - } \ - str += sizeof(type); \ -} while (0) - - while (*fmt) { - int read = format_decode(fmt, &spec); - - fmt += read; - - switch (spec.type) { - case FORMAT_TYPE_NONE: - case FORMAT_TYPE_PERCENT_CHAR: - break; - case FORMAT_TYPE_INVALID: - goto out; - - case FORMAT_TYPE_WIDTH: - case FORMAT_TYPE_PRECISION: - save_arg(int); - break; - - case FORMAT_TYPE_CHAR: - save_arg(char); - break; - - case FORMAT_TYPE_STR: { - const char *save_str = va_arg(args, char *); - size_t len; - - if ((unsigned long)save_str > (unsigned long)-PAGE_SIZE - || (unsigned long)save_str < PAGE_SIZE) - save_str = "(null)"; - len = strlen(save_str) + 1; - if (str + len < end) - memcpy(str, save_str, len); - str += len; - break; - } - - case FORMAT_TYPE_PTR: - save_arg(void *); - /* skip all alphanumeric pointer suffixes */ - while (isalnum(*fmt)) - fmt++; - break; - - default: - switch (spec.type) { - - case FORMAT_TYPE_LONG_LONG: - save_arg(long long); - break; - case FORMAT_TYPE_ULONG: - case FORMAT_TYPE_LONG: - save_arg(unsigned long); - break; - case FORMAT_TYPE_SIZE_T: - save_arg(size_t); - break; - case FORMAT_TYPE_PTRDIFF: - save_arg(ptrdiff_t); - break; - case FORMAT_TYPE_UBYTE: - case FORMAT_TYPE_BYTE: - save_arg(char); - break; - case FORMAT_TYPE_USHORT: - case FORMAT_TYPE_SHORT: - save_arg(short); - break; - default: - save_arg(int); - } - } - } - -out: - return (u32 *)(PTR_ALIGN(str, sizeof(u32))) - bin_buf; -#undef save_arg -} -EXPORT_SYMBOL_GPL(vbin_printf); - -/** - * bstr_printf - Format a string from binary arguments and place it in a buffer - * @buf: The buffer to place the result into - * @size: The size of the buffer, including the trailing null space - * @fmt: The format string to use - * @bin_buf: Binary arguments for the format string - * - * This function like C99 vsnprintf, but the difference is that vsnprintf gets - * arguments from stack, and bstr_printf gets arguments from @bin_buf which is - * a binary buffer that generated by vbin_printf. - * - * The format follows C99 vsnprintf, but has some extensions: - * see vsnprintf comment for details. - * - * The return value is the number of characters which would - * be generated for the given input, excluding the trailing - * '\0', as per ISO C99. If you want to have the exact - * number of characters written into @buf as return value - * (not including the trailing '\0'), use vscnprintf(). If the - * return is greater than or equal to @size, the resulting - * string is truncated. - */ -int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf) -{ - struct printf_spec spec = {0}; - char *str, *end; - const char *args = (const char *)bin_buf; - - if (WARN_ON_ONCE(size > INT_MAX)) - return 0; - - str = buf; - end = buf + size; - -#define get_arg(type) \ -({ \ - typeof(type) value; \ - if (sizeof(type) == 8) { \ - args = PTR_ALIGN(args, sizeof(u32)); \ - *(u32 *)&value = *(u32 *)args; \ - *((u32 *)&value + 1) = *(u32 *)(args + 4); \ - } else { \ - args = PTR_ALIGN(args, sizeof(type)); \ - value = *(typeof(type) *)args; \ - } \ - args += sizeof(type); \ - value; \ -}) - - /* Make sure end is always >= buf */ - if (end < buf) { - end = ((void *)-1); - size = end - buf; - } - - while (*fmt) { - const char *old_fmt = fmt; - int read = format_decode(fmt, &spec); - - fmt += read; - - switch (spec.type) { - case FORMAT_TYPE_NONE: { - int copy = read; - if (str < end) { - if (copy > end - str) - copy = end - str; - memcpy(str, old_fmt, copy); - } - str += read; - break; - } - - case FORMAT_TYPE_WIDTH: - set_field_width(&spec, get_arg(int)); - break; - - case FORMAT_TYPE_PRECISION: - set_precision(&spec, get_arg(int)); - break; - - case FORMAT_TYPE_CHAR: { - char c; - - if (!(spec.flags & LEFT)) { - while (--spec.field_width > 0) { - if (str < end) - *str = ' '; - ++str; - } - } - c = (unsigned char) get_arg(char); - if (str < end) - *str = c; - ++str; - while (--spec.field_width > 0) { - if (str < end) - *str = ' '; - ++str; - } - break; - } - - case FORMAT_TYPE_STR: { - const char *str_arg = args; - args += strlen(str_arg) + 1; - str = string(str, end, (char *)str_arg, spec); - break; - } - - case FORMAT_TYPE_PTR: - str = pointer(fmt, str, end, get_arg(void *), spec); - while (isalnum(*fmt)) - fmt++; - break; - - case FORMAT_TYPE_PERCENT_CHAR: - if (str < end) - *str = '%'; - ++str; - break; - - case FORMAT_TYPE_INVALID: - goto out; - - default: { - unsigned long long num; - - switch (spec.type) { - - case FORMAT_TYPE_LONG_LONG: - num = get_arg(long long); - break; - case FORMAT_TYPE_ULONG: - case FORMAT_TYPE_LONG: - num = get_arg(unsigned long); - break; - case FORMAT_TYPE_SIZE_T: - num = get_arg(size_t); - break; - case FORMAT_TYPE_PTRDIFF: - num = get_arg(ptrdiff_t); - break; - case FORMAT_TYPE_UBYTE: - num = get_arg(unsigned char); - break; - case FORMAT_TYPE_BYTE: - num = get_arg(signed char); - break; - case FORMAT_TYPE_USHORT: - num = get_arg(unsigned short); - break; - case FORMAT_TYPE_SHORT: - num = get_arg(short); - break; - case FORMAT_TYPE_UINT: - num = get_arg(unsigned int); - break; - default: - num = get_arg(int); - } - - str = number(str, end, num, spec); - } /* default: */ - } /* switch(spec.type) */ - } /* while(*fmt) */ - -out: - if (size > 0) { - if (str < end) - *str = '\0'; - else - end[-1] = '\0'; - } - -#undef get_arg - - /* the trailing null byte doesn't count towards the total */ - return str - buf; -} -EXPORT_SYMBOL_GPL(bstr_printf); - -/** - * bprintf - Parse a format string and place args' binary value in a buffer - * @bin_buf: The buffer to place args' binary value - * @size: The size of the buffer(by words(32bits), not characters) - * @fmt: The format string to use - * @...: Arguments for the format string - * - * The function returns the number of words(u32) written - * into @bin_buf. - */ -int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...) -{ - va_list args; - int ret; - - va_start(args, fmt); - ret = vbin_printf(bin_buf, size, fmt, args); - va_end(args); - - return ret; -} -EXPORT_SYMBOL_GPL(bprintf); - -#endif /* CONFIG_BINARY_PRINTF */ - -/** - * vsscanf - Unformat a buffer into a list of arguments - * @buf: input buffer - * @fmt: format of buffer - * @args: arguments - */ -int vsscanf(const char *buf, const char *fmt, va_list args) -{ - const char *str = buf; - char *next; - char digit; - int num = 0; - u8 qualifier; - unsigned int base; - union { - long long s; - unsigned long long u; - } val; - s16 field_width; - bool is_sign; - - while (*fmt) { - /* skip any white space in format */ - /* white space in format matchs any amount of - * white space, including none, in the input. - */ - if (isspace(*fmt)) { - fmt = skip_spaces(++fmt); - str = skip_spaces(str); - } - - /* anything that is not a conversion must match exactly */ - if (*fmt != '%' && *fmt) { - if (*fmt++ != *str++) - break; - continue; - } - - if (!*fmt) - break; - ++fmt; - - /* skip this conversion. - * advance both strings to next white space - */ - if (*fmt == '*') { - if (!*str) - break; - while (!isspace(*fmt) && *fmt != '%' && *fmt) { - /* '%*[' not yet supported, invalid format */ - if (*fmt == '[') - return num; - fmt++; - } - while (!isspace(*str) && *str) - str++; - continue; - } - - /* get field width */ - field_width = -1; - if (isdigit(*fmt)) { - field_width = skip_atoi(&fmt); - if (field_width <= 0) - break; - } - - /* get conversion qualifier */ - qualifier = -1; - if (*fmt == 'h' || _tolower(*fmt) == 'l' || - _tolower(*fmt) == 'z') { - qualifier = *fmt++; - if (unlikely(qualifier == *fmt)) { - if (qualifier == 'h') { - qualifier = 'H'; - fmt++; - } else if (qualifier == 'l') { - qualifier = 'L'; - fmt++; - } - } - } - - if (!*fmt) - break; - - if (*fmt == 'n') { - /* return number of characters read so far */ - *va_arg(args, int *) = str - buf; - ++fmt; - continue; - } - - if (!*str) - break; - - base = 10; - is_sign = false; - - switch (*fmt++) { - case 'c': - { - char *s = (char *)va_arg(args, char*); - if (field_width == -1) - field_width = 1; - do { - *s++ = *str++; - } while (--field_width > 0 && *str); - num++; - } - continue; - case 's': - { - char *s = (char *)va_arg(args, char *); - if (field_width == -1) - field_width = SHRT_MAX; - /* first, skip leading white space in buffer */ - str = skip_spaces(str); - - /* now copy until next white space */ - while (*str && !isspace(*str) && field_width--) - *s++ = *str++; - *s = '\0'; - num++; - } - continue; - /* - * Warning: This implementation of the '[' conversion specifier - * deviates from its glibc counterpart in the following ways: - * (1) It does NOT support ranges i.e. '-' is NOT a special - * character - * (2) It cannot match the closing bracket ']' itself - * (3) A field width is required - * (4) '%*[' (discard matching input) is currently not supported - * - * Example usage: - * ret = sscanf("00:0a:95","%2[^:]:%2[^:]:%2[^:]", - * buf1, buf2, buf3); - * if (ret < 3) - * // etc.. - */ - case '[': - { - char *s = (char *)va_arg(args, char *); - DECLARE_BITMAP(set, 256) = {0}; - unsigned int len = 0; - bool negate = (*fmt == '^'); - - /* field width is required */ - if (field_width == -1) - return num; - - if (negate) - ++fmt; - - for ( ; *fmt && *fmt != ']'; ++fmt, ++len) - set_bit((u8)*fmt, set); - - /* no ']' or no character set found */ - if (!*fmt || !len) - return num; - ++fmt; - - if (negate) { - bitmap_complement(set, set, 256); - /* exclude null '\0' byte */ - clear_bit(0, set); - } - - /* match must be non-empty */ - if (!test_bit((u8)*str, set)) - return num; - - while (test_bit((u8)*str, set) && field_width--) - *s++ = *str++; - *s = '\0'; - ++num; - } - continue; - case 'o': - base = 8; - break; - case 'x': - case 'X': - base = 16; - break; - case 'i': - base = 0; - case 'd': - is_sign = true; - case 'u': - break; - case '%': - /* looking for '%' in str */ - if (*str++ != '%') - return num; - continue; - default: - /* invalid format; stop here */ - return num; - } - - /* have some sort of integer conversion. - * first, skip white space in buffer. - */ - str = skip_spaces(str); - - digit = *str; - if (is_sign && digit == '-') - digit = *(str + 1); - - if (!digit - || (base == 16 && !isxdigit(digit)) - || (base == 10 && !isdigit(digit)) - || (base == 8 && (!isdigit(digit) || digit > '7')) - || (base == 0 && !isdigit(digit))) - break; - - if (is_sign) - val.s = qualifier != 'L' ? - simple_strtol(str, &next, base) : - simple_strtoll(str, &next, base); - else - val.u = qualifier != 'L' ? - simple_strtoul(str, &next, base) : - simple_strtoull(str, &next, base); - - if (field_width > 0 && next - str > field_width) { - if (base == 0) - _parse_integer_fixup_radix(str, &base); - while (next - str > field_width) { - if (is_sign) - val.s = div_s64(val.s, base); - else - val.u = div_u64(val.u, base); - --next; - } - } - - switch (qualifier) { - case 'H': /* that's 'hh' in format */ - if (is_sign) - *va_arg(args, signed char *) = val.s; - else - *va_arg(args, unsigned char *) = val.u; - break; - case 'h': - if (is_sign) - *va_arg(args, short *) = val.s; - else - *va_arg(args, unsigned short *) = val.u; - break; - case 'l': - if (is_sign) - *va_arg(args, long *) = val.s; - else - *va_arg(args, unsigned long *) = val.u; - break; - case 'L': - if (is_sign) - *va_arg(args, long long *) = val.s; - else - *va_arg(args, unsigned long long *) = val.u; - break; - case 'Z': - case 'z': - *va_arg(args, size_t *) = val.u; - break; - default: - if (is_sign) - *va_arg(args, int *) = val.s; - else - *va_arg(args, unsigned int *) = val.u; - break; - } - num++; - - if (!next) - break; - str = next; - } - - return num; -} -EXPORT_SYMBOL(vsscanf); - -/** - * sscanf - Unformat a buffer into a list of arguments - * @buf: input buffer - * @fmt: formatting of buffer - * @...: resulting arguments - */ -int sscanf(const char *buf, const char *fmt, ...) -{ - va_list args; - int i; - - va_start(args, fmt); - i = vsscanf(buf, fmt, args); - va_end(args); - - return i; -} -EXPORT_SYMBOL(sscanf); diff --git a/src/linux/lib/win_minmax.c b/src/linux/lib/win_minmax.c deleted file mode 100644 index c8420d4..0000000 --- a/src/linux/lib/win_minmax.c +++ /dev/null @@ -1,98 +0,0 @@ -/** - * lib/minmax.c: windowed min/max tracker - * - * Kathleen Nichols' algorithm for tracking the minimum (or maximum) - * value of a data stream over some fixed time interval. (E.g., - * the minimum RTT over the past five minutes.) It uses constant - * space and constant time per update yet almost always delivers - * the same minimum as an implementation that has to keep all the - * data in the window. - * - * The algorithm keeps track of the best, 2nd best & 3rd best min - * values, maintaining an invariant that the measurement time of - * the n'th best >= n-1'th best. It also makes sure that the three - * values are widely separated in the time window since that bounds - * the worse case error when that data is monotonically increasing - * over the window. - * - * Upon getting a new min, we can forget everything earlier because - * it has no value - the new min is <= everything else in the window - * by definition and it's the most recent. So we restart fresh on - * every new min and overwrites 2nd & 3rd choices. The same property - * holds for 2nd & 3rd best. - */ -#include -#include - -/* As time advances, update the 1st, 2nd, and 3rd choices. */ -static u32 minmax_subwin_update(struct minmax *m, u32 win, - const struct minmax_sample *val) -{ - u32 dt = val->t - m->s[0].t; - - if (unlikely(dt > win)) { - /* - * Passed entire window without a new val so make 2nd - * choice the new val & 3rd choice the new 2nd choice. - * we may have to iterate this since our 2nd choice - * may also be outside the window (we checked on entry - * that the third choice was in the window). - */ - m->s[0] = m->s[1]; - m->s[1] = m->s[2]; - m->s[2] = *val; - if (unlikely(val->t - m->s[0].t > win)) { - m->s[0] = m->s[1]; - m->s[1] = m->s[2]; - m->s[2] = *val; - } - } else if (unlikely(m->s[1].t == m->s[0].t) && dt > win/4) { - /* - * We've passed a quarter of the window without a new val - * so take a 2nd choice from the 2nd quarter of the window. - */ - m->s[2] = m->s[1] = *val; - } else if (unlikely(m->s[2].t == m->s[1].t) && dt > win/2) { - /* - * We've passed half the window without finding a new val - * so take a 3rd choice from the last half of the window - */ - m->s[2] = *val; - } - return m->s[0].v; -} - -/* Check if new measurement updates the 1st, 2nd or 3rd choice max. */ -u32 minmax_running_max(struct minmax *m, u32 win, u32 t, u32 meas) -{ - struct minmax_sample val = { .t = t, .v = meas }; - - if (unlikely(val.v >= m->s[0].v) || /* found new max? */ - unlikely(val.t - m->s[2].t > win)) /* nothing left in window? */ - return minmax_reset(m, t, meas); /* forget earlier samples */ - - if (unlikely(val.v >= m->s[1].v)) - m->s[2] = m->s[1] = val; - else if (unlikely(val.v >= m->s[2].v)) - m->s[2] = val; - - return minmax_subwin_update(m, win, &val); -} -EXPORT_SYMBOL(minmax_running_max); - -/* Check if new measurement updates the 1st, 2nd or 3rd choice min. */ -u32 minmax_running_min(struct minmax *m, u32 win, u32 t, u32 meas) -{ - struct minmax_sample val = { .t = t, .v = meas }; - - if (unlikely(val.v <= m->s[0].v) || /* found new min? */ - unlikely(val.t - m->s[2].t > win)) /* nothing left in window? */ - return minmax_reset(m, t, meas); /* forget earlier samples */ - - if (unlikely(val.v <= m->s[1].v)) - m->s[2] = m->s[1] = val; - else if (unlikely(val.v <= m->s[2].v)) - m->s[2] = val; - - return minmax_subwin_update(m, win, &val); -} diff --git a/src/linux/lib/xz/Kconfig b/src/linux/lib/xz/Kconfig deleted file mode 100644 index 12d2d77..0000000 --- a/src/linux/lib/xz/Kconfig +++ /dev/null @@ -1,57 +0,0 @@ -config XZ_DEC - tristate "XZ decompression support" - select CRC32 - help - LZMA2 compression algorithm and BCJ filters are supported using - the .xz file format as the container. For integrity checking, - CRC32 is supported. See Documentation/xz.txt for more information. - -if XZ_DEC - -config XZ_DEC_X86 - bool "x86 BCJ filter decoder" if EXPERT - default y - select XZ_DEC_BCJ - -config XZ_DEC_POWERPC - bool "PowerPC BCJ filter decoder" if EXPERT - default y - select XZ_DEC_BCJ - -config XZ_DEC_IA64 - bool "IA-64 BCJ filter decoder" if EXPERT - default y - select XZ_DEC_BCJ - -config XZ_DEC_ARM - bool "ARM BCJ filter decoder" if EXPERT - default y - select XZ_DEC_BCJ - -config XZ_DEC_ARMTHUMB - bool "ARM-Thumb BCJ filter decoder" if EXPERT - default y - select XZ_DEC_BCJ - -config XZ_DEC_SPARC - bool "SPARC BCJ filter decoder" if EXPERT - default y - select XZ_DEC_BCJ - -endif - -config XZ_DEC_BCJ - bool - default n - -config XZ_DEC_TEST - tristate "XZ decompressor tester" - default n - depends on XZ_DEC - help - This allows passing .xz files to the in-kernel XZ decoder via - a character special file. It calculates CRC32 of the decompressed - data and writes diagnostics to the system log. - - Unless you are developing the XZ decoder, you don't need this - and should say N. diff --git a/src/linux/lib/zlib_deflate/Makefile b/src/linux/lib/zlib_deflate/Makefile deleted file mode 100644 index 86275e3..0000000 --- a/src/linux/lib/zlib_deflate/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# This is a modified version of zlib, which does all memory -# allocation ahead of time. -# -# This is the compression code, see zlib_inflate for the -# decompression code. -# - -obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate.o - -zlib_deflate-objs := deflate.o deftree.o deflate_syms.o diff --git a/src/linux/lib/zlib_deflate/deflate.c b/src/linux/lib/zlib_deflate/deflate.c deleted file mode 100644 index d20ef45..0000000 --- a/src/linux/lib/zlib_deflate/deflate.c +++ /dev/null @@ -1,1137 +0,0 @@ -/* +++ deflate.c */ -/* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-1996 Jean-loup Gailly. - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process depends on being able to identify portions - * of the input text which are identical to earlier input (within a - * sliding window trailing behind the input currently being processed). - * - * The most straightforward technique turns out to be the fastest for - * most input files: try all possible matches and select the longest. - * The key feature of this algorithm is that insertions into the string - * dictionary are very simple and thus fast, and deletions are avoided - * completely. Insertions are performed at each input character, whereas - * string matches are performed only when the previous match ends. So it - * is preferable to spend more time in matches to allow very fast string - * insertions and avoid deletions. The matching algorithm for small - * strings is inspired from that of Rabin & Karp. A brute force approach - * is used to find longer strings when a small match has been found. - * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze - * (by Leonid Broukhis). - * A previous version of this file used a more sophisticated algorithm - * (by Fiala and Greene) which is guaranteed to run in linear amortized - * time, but has a larger average cost, uses more memory and is patented. - * However the F&G algorithm may be faster for some highly redundant - * files if the parameter max_chain_length (described below) is too large. - * - * ACKNOWLEDGEMENTS - * - * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and - * I found it in 'freeze' written by Leonid Broukhis. - * Thanks to many people for bug reports and testing. - * - * REFERENCES - * - * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". - * Available in ftp://ds.internic.net/rfc/rfc1951.txt - * - * A description of the Rabin and Karp algorithm is given in the book - * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. - * - * Fiala,E.R., and Greene,D.H. - * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 - * - */ - -#include -#include -#include "defutil.h" - - -/* =========================================================================== - * Function prototypes. - */ -typedef enum { - need_more, /* block not completed, need more input or more output */ - block_done, /* block flush performed */ - finish_started, /* finish started, need only more output at next deflate */ - finish_done /* finish done, accept no more input or output */ -} block_state; - -typedef block_state (*compress_func) (deflate_state *s, int flush); -/* Compression function. Returns the block state after the call. */ - -static void fill_window (deflate_state *s); -static block_state deflate_stored (deflate_state *s, int flush); -static block_state deflate_fast (deflate_state *s, int flush); -static block_state deflate_slow (deflate_state *s, int flush); -static void lm_init (deflate_state *s); -static void putShortMSB (deflate_state *s, uInt b); -static void flush_pending (z_streamp strm); -static int read_buf (z_streamp strm, Byte *buf, unsigned size); -static uInt longest_match (deflate_state *s, IPos cur_match); - -#ifdef DEBUG_ZLIB -static void check_match (deflate_state *s, IPos start, IPos match, - int length); -#endif - -/* =========================================================================== - * Local data - */ - -#define NIL 0 -/* Tail of hash chains */ - -#ifndef TOO_FAR -# define TOO_FAR 4096 -#endif -/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -/* Values for max_lazy_match, good_match and max_chain_length, depending on - * the desired pack level (0..9). The values given below have been tuned to - * exclude worst case performance for pathological files. Better values may be - * found for specific files. - */ -typedef struct config_s { - ush good_length; /* reduce lazy search above this match length */ - ush max_lazy; /* do not perform lazy search above this match length */ - ush nice_length; /* quit search above this match length */ - ush max_chain; - compress_func func; -} config; - -static const config configuration_table[10] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */ -/* 2 */ {4, 5, 16, 8, deflate_fast}, -/* 3 */ {4, 6, 32, 32, deflate_fast}, - -/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ -/* 5 */ {8, 16, 32, 32, deflate_slow}, -/* 6 */ {8, 16, 128, 128, deflate_slow}, -/* 7 */ {8, 32, 128, 256, deflate_slow}, -/* 8 */ {32, 128, 258, 1024, deflate_slow}, -/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */ - -/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 - * For deflate_fast() (levels <= 3) good is ignored and lazy has a different - * meaning. - */ - -#define EQUAL 0 -/* result of memcmp for equal strings */ - -/* =========================================================================== - * Update a hash value with the given input byte - * IN assertion: all calls to UPDATE_HASH are made with consecutive - * input characters, so that a running hash key can be computed from the - * previous key instead of complete recalculation each time. - */ -#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) - - -/* =========================================================================== - * Insert string str in the dictionary and set match_head to the previous head - * of the hash chain (the most recent string with same hash key). Return - * the previous length of the hash chain. - * IN assertion: all calls to INSERT_STRING are made with consecutive - * input characters and the first MIN_MATCH bytes of str are valid - * (except for the last MIN_MATCH-1 bytes of the input file). - */ -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) - -/* =========================================================================== - * Initialize the hash table (avoiding 64K overflow for 16 bit systems). - * prev[] will be initialized on the fly. - */ -#define CLEAR_HASH(s) \ - s->head[s->hash_size-1] = NIL; \ - memset((char *)s->head, 0, (unsigned)(s->hash_size-1)*sizeof(*s->head)); - -/* ========================================================================= */ -int zlib_deflateInit2( - z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy -) -{ - deflate_state *s; - int noheader = 0; - deflate_workspace *mem; - char *next; - - ush *overlay; - /* We overlay pending_buf and d_buf+l_buf. This works since the average - * output size for (length,distance) codes is <= 24 bits. - */ - - if (strm == NULL) return Z_STREAM_ERROR; - - strm->msg = NULL; - - if (level == Z_DEFAULT_COMPRESSION) level = 6; - - mem = (deflate_workspace *) strm->workspace; - - if (windowBits < 0) { /* undocumented feature: suppress zlib header */ - noheader = 1; - windowBits = -windowBits; - } - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_HUFFMAN_ONLY) { - return Z_STREAM_ERROR; - } - - /* - * Direct the workspace's pointers to the chunks that were allocated - * along with the deflate_workspace struct. - */ - next = (char *) mem; - next += sizeof(*mem); - mem->window_memory = (Byte *) next; - next += zlib_deflate_window_memsize(windowBits); - mem->prev_memory = (Pos *) next; - next += zlib_deflate_prev_memsize(windowBits); - mem->head_memory = (Pos *) next; - next += zlib_deflate_head_memsize(memLevel); - mem->overlay_memory = next; - - s = (deflate_state *) &(mem->deflate_memory); - strm->state = (struct internal_state *)s; - s->strm = strm; - - s->noheader = noheader; - s->w_bits = windowBits; - s->w_size = 1 << s->w_bits; - s->w_mask = s->w_size - 1; - - s->hash_bits = memLevel + 7; - s->hash_size = 1 << s->hash_bits; - s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); - - s->window = (Byte *) mem->window_memory; - s->prev = (Pos *) mem->prev_memory; - s->head = (Pos *) mem->head_memory; - - s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - - overlay = (ush *) mem->overlay_memory; - s->pending_buf = (uch *) overlay; - s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); - - s->d_buf = overlay + s->lit_bufsize/sizeof(ush); - s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; - - s->level = level; - s->strategy = strategy; - s->method = (Byte)method; - - return zlib_deflateReset(strm); -} - -/* ========================================================================= */ -int zlib_deflateReset( - z_streamp strm -) -{ - deflate_state *s; - - if (strm == NULL || strm->state == NULL) - return Z_STREAM_ERROR; - - strm->total_in = strm->total_out = 0; - strm->msg = NULL; - strm->data_type = Z_UNKNOWN; - - s = (deflate_state *)strm->state; - s->pending = 0; - s->pending_out = s->pending_buf; - - if (s->noheader < 0) { - s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */ - } - s->status = s->noheader ? BUSY_STATE : INIT_STATE; - strm->adler = 1; - s->last_flush = Z_NO_FLUSH; - - zlib_tr_init(s); - lm_init(s); - - return Z_OK; -} - -/* ========================================================================= - * Put a short in the pending buffer. The 16-bit value is put in MSB order. - * IN assertion: the stream state is correct and there is enough room in - * pending_buf. - */ -static void putShortMSB( - deflate_state *s, - uInt b -) -{ - put_byte(s, (Byte)(b >> 8)); - put_byte(s, (Byte)(b & 0xff)); -} - -/* ========================================================================= - * Flush as much pending output as possible. All deflate() output goes - * through this function so some applications may wish to modify it - * to avoid allocating a large strm->next_out buffer and copying into it. - * (See also read_buf()). - */ -static void flush_pending( - z_streamp strm -) -{ - deflate_state *s = (deflate_state *) strm->state; - unsigned len = s->pending; - - if (len > strm->avail_out) len = strm->avail_out; - if (len == 0) return; - - if (strm->next_out != NULL) { - memcpy(strm->next_out, s->pending_out, len); - strm->next_out += len; - } - s->pending_out += len; - strm->total_out += len; - strm->avail_out -= len; - s->pending -= len; - if (s->pending == 0) { - s->pending_out = s->pending_buf; - } -} - -/* ========================================================================= */ -int zlib_deflate( - z_streamp strm, - int flush -) -{ - int old_flush; /* value of flush param for previous deflate call */ - deflate_state *s; - - if (strm == NULL || strm->state == NULL || - flush > Z_FINISH || flush < 0) { - return Z_STREAM_ERROR; - } - s = (deflate_state *) strm->state; - - if ((strm->next_in == NULL && strm->avail_in != 0) || - (s->status == FINISH_STATE && flush != Z_FINISH)) { - return Z_STREAM_ERROR; - } - if (strm->avail_out == 0) return Z_BUF_ERROR; - - s->strm = strm; /* just in case */ - old_flush = s->last_flush; - s->last_flush = flush; - - /* Write the zlib header */ - if (s->status == INIT_STATE) { - - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; - uInt level_flags = (s->level-1) >> 1; - - if (level_flags > 3) level_flags = 3; - header |= (level_flags << 6); - if (s->strstart != 0) header |= PRESET_DICT; - header += 31 - (header % 31); - - s->status = BUSY_STATE; - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s->strstart != 0) { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - strm->adler = 1L; - } - - /* Flush as much pending output as possible */ - if (s->pending != 0) { - flush_pending(strm); - if (strm->avail_out == 0) { - /* Since avail_out is 0, deflate will be called again with - * more output space, but possibly with both pending and - * avail_in equal to zero. There won't be anything to do, - * but this is not an error situation so make sure we - * return OK instead of BUF_ERROR at next call of deflate: - */ - s->last_flush = -1; - return Z_OK; - } - - /* Make sure there is something to do and avoid duplicate consecutive - * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUFF_ERROR. - */ - } else if (strm->avail_in == 0 && flush <= old_flush && - flush != Z_FINISH) { - return Z_BUF_ERROR; - } - - /* User must not provide more input after the first FINISH: */ - if (s->status == FINISH_STATE && strm->avail_in != 0) { - return Z_BUF_ERROR; - } - - /* Start a new block or continue the current one. - */ - if (strm->avail_in != 0 || s->lookahead != 0 || - (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { - block_state bstate; - - bstate = (*(configuration_table[s->level].func))(s, flush); - - if (bstate == finish_started || bstate == finish_done) { - s->status = FINISH_STATE; - } - if (bstate == need_more || bstate == finish_started) { - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ - } - return Z_OK; - /* If flush != Z_NO_FLUSH && avail_out == 0, the next call - * of deflate should use the same flush parameter to make sure - * that the flush is complete. So we don't have to output an - * empty block here, this will be done at next call. This also - * ensures that for a very small output buffer, we emit at most - * one empty block. - */ - } - if (bstate == block_done) { - if (flush == Z_PARTIAL_FLUSH) { - zlib_tr_align(s); - } else if (flush == Z_PACKET_FLUSH) { - /* Output just the 3-bit `stored' block type value, - but not a zero length. */ - zlib_tr_stored_type_only(s); - } else { /* FULL_FLUSH or SYNC_FLUSH */ - zlib_tr_stored_block(s, (char*)0, 0L, 0); - /* For a full flush, this empty block will be recognized - * as a special marker by inflate_sync(). - */ - if (flush == Z_FULL_FLUSH) { - CLEAR_HASH(s); /* forget history */ - } - } - flush_pending(strm); - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK; - } - } - } - Assert(strm->avail_out > 0, "bug2"); - - if (flush != Z_FINISH) return Z_OK; - if (s->noheader) return Z_STREAM_END; - - /* Write the zlib trailer (adler32) */ - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - flush_pending(strm); - /* If avail_out is zero, the application will call deflate again - * to flush the rest. - */ - s->noheader = -1; /* write the trailer only once! */ - return s->pending != 0 ? Z_OK : Z_STREAM_END; -} - -/* ========================================================================= */ -int zlib_deflateEnd( - z_streamp strm -) -{ - int status; - deflate_state *s; - - if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR; - s = (deflate_state *) strm->state; - - status = s->status; - if (status != INIT_STATE && status != BUSY_STATE && - status != FINISH_STATE) { - return Z_STREAM_ERROR; - } - - strm->state = NULL; - - return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; -} - -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->next_in buffer and copying from it. - * (See also flush_pending()). - */ -static int read_buf( - z_streamp strm, - Byte *buf, - unsigned size -) -{ - unsigned len = strm->avail_in; - - if (len > size) len = size; - if (len == 0) return 0; - - strm->avail_in -= len; - - if (!((deflate_state *)(strm->state))->noheader) { - strm->adler = zlib_adler32(strm->adler, strm->next_in, len); - } - memcpy(buf, strm->next_in, len); - strm->next_in += len; - strm->total_in += len; - - return (int)len; -} - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -static void lm_init( - deflate_state *s -) -{ - s->window_size = (ulg)2L*s->w_size; - - CLEAR_HASH(s); - - /* Set the default configuration parameters: - */ - s->max_lazy_match = configuration_table[s->level].max_lazy; - s->good_match = configuration_table[s->level].good_length; - s->nice_match = configuration_table[s->level].nice_length; - s->max_chain_length = configuration_table[s->level].max_chain; - - s->strstart = 0; - s->block_start = 0L; - s->lookahead = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - s->ins_h = 0; -} - -/* =========================================================================== - * Set match_start to the longest match starting at the given string and - * return its length. Matches shorter or equal to prev_length are discarded, - * in which case the result is equal to prev_length and match_start is - * garbage. - * IN assertions: cur_match is the head of the hash chain for the current - * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 - * OUT assertion: the match length is not greater than s->lookahead. - */ -/* For 80x86 and 680x0, an optimized version will be provided in match.asm or - * match.S. The code will be functionally equivalent. - */ -static uInt longest_match( - deflate_state *s, - IPos cur_match /* current match */ -) -{ - unsigned chain_length = s->max_chain_length;/* max hash chain length */ - register Byte *scan = s->window + s->strstart; /* current string */ - register Byte *match; /* matched string */ - register int len; /* length of current match */ - int best_len = s->prev_length; /* best match length so far */ - int nice_match = s->nice_match; /* stop if match long enough */ - IPos limit = s->strstart > (IPos)MAX_DIST(s) ? - s->strstart - (IPos)MAX_DIST(s) : NIL; - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ - Pos *prev = s->prev; - uInt wmask = s->w_mask; - -#ifdef UNALIGNED_OK - /* Compare two bytes at a time. Note: this is not always beneficial. - * Try with and without -DUNALIGNED_OK to check. - */ - register Byte *strend = s->window + s->strstart + MAX_MATCH - 1; - register ush scan_start = *(ush*)scan; - register ush scan_end = *(ush*)(scan+best_len-1); -#else - register Byte *strend = s->window + s->strstart + MAX_MATCH; - register Byte scan_end1 = scan[best_len-1]; - register Byte scan_end = scan[best_len]; -#endif - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - /* Do not waste too much time if we already have a good match: */ - if (s->prev_length >= s->good_match) { - chain_length >>= 2; - } - /* Do not look for matches beyond the end of the input. This is necessary - * to make deflate deterministic. - */ - if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - do { - Assert(cur_match < s->strstart, "no future"); - match = s->window + cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2: - */ -#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) - /* This code assumes sizeof(unsigned short) == 2. Do not use - * UNALIGNED_OK if your compiler uses a different size. - */ - if (*(ush*)(match+best_len-1) != scan_end || - *(ush*)match != scan_start) continue; - - /* It is not necessary to compare scan[2] and match[2] since they are - * always equal when the other bytes match, given that the hash keys - * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - * strstart+3, +5, ... up to strstart+257. We check for insufficient - * lookahead only every 4th comparison; the 128th check will be made - * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is - * necessary to put more guard bytes at the end of the window, or - * to check more often for insufficient lookahead. - */ - Assert(scan[2] == match[2], "scan[2]?"); - scan++, match++; - do { - } while (*(ush*)(scan+=2) == *(ush*)(match+=2) && - *(ush*)(scan+=2) == *(ush*)(match+=2) && - *(ush*)(scan+=2) == *(ush*)(match+=2) && - *(ush*)(scan+=2) == *(ush*)(match+=2) && - scan < strend); - /* The funny "do {}" generates better code on most compilers */ - - /* Here, scan <= window+strstart+257 */ - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - if (*scan == *match) scan++; - - len = (MAX_MATCH - 1) - (int)(strend-scan); - scan = strend - (MAX_MATCH-1); - -#else /* UNALIGNED_OK */ - - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match++; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - scan = strend - MAX_MATCH; - -#endif /* UNALIGNED_OK */ - - if (len > best_len) { - s->match_start = cur_match; - best_len = len; - if (len >= nice_match) break; -#ifdef UNALIGNED_OK - scan_end = *(ush*)(scan+best_len-1); -#else - scan_end1 = scan[best_len-1]; - scan_end = scan[best_len]; -#endif - } - } while ((cur_match = prev[cur_match & wmask]) > limit - && --chain_length != 0); - - if ((uInt)best_len <= s->lookahead) return best_len; - return s->lookahead; -} - -#ifdef DEBUG_ZLIB -/* =========================================================================== - * Check that the match at match_start is indeed a match. - */ -static void check_match( - deflate_state *s, - IPos start, - IPos match, - int length -) -{ - /* check that the match is indeed a match */ - if (memcmp((char *)s->window + match, - (char *)s->window + start, length) != EQUAL) { - fprintf(stderr, " start %u, match %u, length %d\n", - start, match, length); - do { - fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); - } while (--length != 0); - z_error("invalid match"); - } - if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); - do { putc(s->window[start++], stderr); } while (--length != 0); - } -} -#else -# define check_match(s, start, match, length) -#endif - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -static void fill_window( - deflate_state *s -) -{ - register unsigned n, m; - register Pos *p; - unsigned more; /* Amount of free space at the end of the window. */ - uInt wsize = s->w_size; - - do { - more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); - - /* Deal with !@#$% 64K limit: */ - if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - more = wsize; - - } else if (more == (unsigned)(-1)) { - /* Very unlikely, but possible on 16 bit machine if strstart == 0 - * and lookahead == 1 (input done one byte at time) - */ - more--; - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - } else if (s->strstart >= wsize+MAX_DIST(s)) { - - memcpy((char *)s->window, (char *)s->window+wsize, - (unsigned)wsize); - s->match_start -= wsize; - s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ - s->block_start -= (long) wsize; - - /* Slide the hash table (could be avoided with 32 bit values - at the expense of memory usage). We slide even when level == 0 - to keep the hash table consistent if we switch back to level > 0 - later. (Using level 0 permanently is not an optimal usage of - zlib, so we don't care about this pathological case.) - */ - n = s->hash_size; - p = &s->head[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - } while (--n); - - n = wsize; - p = &s->prev[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m-wsize : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); - more += wsize; - } - if (s->strm->avail_in == 0) return; - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - Assert(more >= 2, "more < 2"); - - n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); - s->lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s->lookahead >= MIN_MATCH) { - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); -} - -/* =========================================================================== - * Flush the current block, with given end-of-file flag. - * IN assertion: strstart is set to the end of the current match. - */ -#define FLUSH_BLOCK_ONLY(s, eof) { \ - zlib_tr_flush_block(s, (s->block_start >= 0L ? \ - (char *)&s->window[(unsigned)s->block_start] : \ - NULL), \ - (ulg)((long)s->strstart - s->block_start), \ - (eof)); \ - s->block_start = s->strstart; \ - flush_pending(s->strm); \ - Tracev((stderr,"[FLUSH]")); \ -} - -/* Same but force premature exit if necessary. */ -#define FLUSH_BLOCK(s, eof) { \ - FLUSH_BLOCK_ONLY(s, eof); \ - if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ -} - -/* =========================================================================== - * Copy without compression as much as possible from the input stream, return - * the current block state. - * This function does not insert new strings in the dictionary since - * uncompressible data is probably not useful. This function is used - * only for the level=0 compression option. - * NOTE: this function should be optimized to avoid extra copying from - * window to pending_buf. - */ -static block_state deflate_stored( - deflate_state *s, - int flush -) -{ - /* Stored blocks are limited to 0xffff bytes, pending_buf is limited - * to pending_buf_size, and each stored block has a 5 byte header: - */ - ulg max_block_size = 0xffff; - ulg max_start; - - if (max_block_size > s->pending_buf_size - 5) { - max_block_size = s->pending_buf_size - 5; - } - - /* Copy as much as possible from input to output: */ - for (;;) { - /* Fill the window as much as possible: */ - if (s->lookahead <= 1) { - - Assert(s->strstart < s->w_size+MAX_DIST(s) || - s->block_start >= (long)s->w_size, "slide too late"); - - fill_window(s); - if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; - - if (s->lookahead == 0) break; /* flush the current block */ - } - Assert(s->block_start >= 0L, "block gone"); - - s->strstart += s->lookahead; - s->lookahead = 0; - - /* Emit a stored block if pending_buf will be full: */ - max_start = s->block_start + max_block_size; - if (s->strstart == 0 || (ulg)s->strstart >= max_start) { - /* strstart == 0 is possible when wraparound on 16-bit machine */ - s->lookahead = (uInt)(s->strstart - max_start); - s->strstart = (uInt)max_start; - FLUSH_BLOCK(s, 0); - } - /* Flush if we may have to slide, otherwise block_start may become - * negative and the data will be gone: - */ - if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { - FLUSH_BLOCK(s, 0); - } - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -/* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ -static block_state deflate_fast( - deflate_state *s, - int flush -) -{ - IPos hash_head = NIL; /* head of the hash chain */ - int bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match_length < MIN_MATCH - */ - if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - if (s->strategy != Z_HUFFMAN_ONLY) { - s->match_length = longest_match (s, hash_head); - } - /* longest_match() sets match_start */ - } - if (s->match_length >= MIN_MATCH) { - check_match(s, s->strstart, s->match_start, s->match_length); - - bflush = zlib_tr_tally(s, s->strstart - s->match_start, - s->match_length - MIN_MATCH); - - s->lookahead -= s->match_length; - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ - if (s->match_length <= s->max_insert_length && - s->lookahead >= MIN_MATCH) { - s->match_length--; /* string at strstart already in hash table */ - do { - s->strstart++; - INSERT_STRING(s, s->strstart, hash_head); - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } while (--s->match_length != 0); - s->strstart++; - } else { - s->strstart += s->match_length; - s->match_length = 0; - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - bflush = zlib_tr_tally (s, 0, s->window[s->strstart]); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -/* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -static block_state deflate_slow( - deflate_state *s, - int flush -) -{ - IPos hash_head = NIL; /* head of hash chain */ - int bflush; /* set if current block must be flushed */ - - /* Process the input block. */ - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - */ - s->prev_length = s->match_length, s->prev_match = s->match_start; - s->match_length = MIN_MATCH-1; - - if (hash_head != NIL && s->prev_length < s->max_lazy_match && - s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - if (s->strategy != Z_HUFFMAN_ONLY) { - s->match_length = longest_match (s, hash_head); - } - /* longest_match() sets match_start */ - - if (s->match_length <= 5 && (s->strategy == Z_FILTERED || - (s->match_length == MIN_MATCH && - s->strstart - s->match_start > TOO_FAR))) { - - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - s->match_length = MIN_MATCH-1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { - uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; - /* Do not insert strings in hash table beyond this. */ - - check_match(s, s->strstart-1, s->prev_match, s->prev_length); - - bflush = zlib_tr_tally(s, s->strstart -1 - s->prev_match, - s->prev_length - MIN_MATCH); - - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not - * enough lookahead, the last two strings are not inserted in - * the hash table. - */ - s->lookahead -= s->prev_length-1; - s->prev_length -= 2; - do { - if (++s->strstart <= max_insert) { - INSERT_STRING(s, s->strstart, hash_head); - } - } while (--s->prev_length != 0); - s->match_available = 0; - s->match_length = MIN_MATCH-1; - s->strstart++; - - if (bflush) FLUSH_BLOCK(s, 0); - - } else if (s->match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - if (zlib_tr_tally (s, 0, s->window[s->strstart-1])) { - FLUSH_BLOCK_ONLY(s, 0); - } - s->strstart++; - s->lookahead--; - if (s->strm->avail_out == 0) return need_more; - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - s->match_available = 1; - s->strstart++; - s->lookahead--; - } - } - Assert (flush != Z_NO_FLUSH, "no flush?"); - if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - zlib_tr_tally (s, 0, s->window[s->strstart-1]); - s->match_available = 0; - } - FLUSH_BLOCK(s, flush == Z_FINISH); - return flush == Z_FINISH ? finish_done : block_done; -} - -int zlib_deflate_workspacesize(int windowBits, int memLevel) -{ - if (windowBits < 0) /* undocumented feature: suppress zlib header */ - windowBits = -windowBits; - - /* Since the return value is typically passed to vmalloc() unchecked... */ - BUG_ON(memLevel < 1 || memLevel > MAX_MEM_LEVEL || windowBits < 9 || - windowBits > 15); - - return sizeof(deflate_workspace) - + zlib_deflate_window_memsize(windowBits) - + zlib_deflate_prev_memsize(windowBits) - + zlib_deflate_head_memsize(memLevel) - + zlib_deflate_overlay_memsize(memLevel); -} diff --git a/src/linux/lib/zlib_deflate/deflate_syms.c b/src/linux/lib/zlib_deflate/deflate_syms.c deleted file mode 100644 index ccfe25f..0000000 --- a/src/linux/lib/zlib_deflate/deflate_syms.c +++ /dev/null @@ -1,18 +0,0 @@ -/* - * linux/lib/zlib_deflate/deflate_syms.c - * - * Exported symbols for the deflate functionality. - * - */ - -#include -#include - -#include - -EXPORT_SYMBOL(zlib_deflate_workspacesize); -EXPORT_SYMBOL(zlib_deflate); -EXPORT_SYMBOL(zlib_deflateInit2); -EXPORT_SYMBOL(zlib_deflateEnd); -EXPORT_SYMBOL(zlib_deflateReset); -MODULE_LICENSE("GPL"); diff --git a/src/linux/lib/zlib_deflate/deftree.c b/src/linux/lib/zlib_deflate/deftree.c deleted file mode 100644 index 9b1756b..0000000 --- a/src/linux/lib/zlib_deflate/deftree.c +++ /dev/null @@ -1,1113 +0,0 @@ -/* +++ trees.c */ -/* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-1996 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process uses several Huffman trees. The more - * common source values are represented by shorter bit sequences. - * - * Each code tree is stored in a compressed form which is itself - * a Huffman encoding of the lengths of all the code strings (in - * ascending order by source values). The actual code strings are - * reconstructed from the lengths in the inflate process, as described - * in the deflate specification. - * - * REFERENCES - * - * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". - * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc - * - * Storer, James A. - * Data Compression: Methods and Theory, pp. 49-50. - * Computer Science Press, 1988. ISBN 0-7167-8156-5. - * - * Sedgewick, R. - * Algorithms, p290. - * Addison-Wesley, 1983. ISBN 0-201-06672-6. - */ - -/* From: trees.c,v 1.11 1996/07/24 13:41:06 me Exp $ */ - -/* #include "deflate.h" */ - -#include -#include -#include "defutil.h" - -#ifdef DEBUG_ZLIB -# include -#endif - -/* =========================================================================== - * Constants - */ - -#define MAX_BL_BITS 7 -/* Bit length codes must not exceed MAX_BL_BITS bits */ - -#define END_BLOCK 256 -/* end of block literal code */ - -#define REP_3_6 16 -/* repeat previous bit length 3-6 times (2 bits of repeat count) */ - -#define REPZ_3_10 17 -/* repeat a zero length 3-10 times (3 bits of repeat count) */ - -#define REPZ_11_138 18 -/* repeat a zero length 11-138 times (7 bits of repeat count) */ - -static const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ - = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; - -static const int extra_dbits[D_CODES] /* extra bits for each distance code */ - = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -static const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ - = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; - -static const uch bl_order[BL_CODES] - = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; -/* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ - -#define Buf_size (8 * 2*sizeof(char)) -/* Number of bits used within bi_buf. (bi_buf might be implemented on - * more than 16 bits on some systems.) - */ - -/* =========================================================================== - * Local data. These are initialized only once. - */ - -static ct_data static_ltree[L_CODES+2]; -/* The static literal tree. Since the bit lengths are imposed, there is no - * need for the L_CODES extra codes used during heap construction. However - * The codes 286 and 287 are needed to build a canonical tree (see zlib_tr_init - * below). - */ - -static ct_data static_dtree[D_CODES]; -/* The static distance tree. (Actually a trivial tree since all codes use - * 5 bits.) - */ - -static uch dist_code[512]; -/* distance codes. The first 256 values correspond to the distances - * 3 .. 258, the last 256 values correspond to the top 8 bits of - * the 15 bit distances. - */ - -static uch length_code[MAX_MATCH-MIN_MATCH+1]; -/* length code for each normalized match length (0 == MIN_MATCH) */ - -static int base_length[LENGTH_CODES]; -/* First normalized length for each code (0 = MIN_MATCH) */ - -static int base_dist[D_CODES]; -/* First normalized distance for each code (0 = distance of 1) */ - -struct static_tree_desc_s { - const ct_data *static_tree; /* static tree or NULL */ - const int *extra_bits; /* extra bits for each code or NULL */ - int extra_base; /* base index for extra_bits */ - int elems; /* max number of elements in the tree */ - int max_length; /* max bit length for the codes */ -}; - -static static_tree_desc static_l_desc = -{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; - -static static_tree_desc static_d_desc = -{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; - -static static_tree_desc static_bl_desc = -{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; - -/* =========================================================================== - * Local (static) routines in this file. - */ - -static void tr_static_init (void); -static void init_block (deflate_state *s); -static void pqdownheap (deflate_state *s, ct_data *tree, int k); -static void gen_bitlen (deflate_state *s, tree_desc *desc); -static void gen_codes (ct_data *tree, int max_code, ush *bl_count); -static void build_tree (deflate_state *s, tree_desc *desc); -static void scan_tree (deflate_state *s, ct_data *tree, int max_code); -static void send_tree (deflate_state *s, ct_data *tree, int max_code); -static int build_bl_tree (deflate_state *s); -static void send_all_trees (deflate_state *s, int lcodes, int dcodes, - int blcodes); -static void compress_block (deflate_state *s, ct_data *ltree, - ct_data *dtree); -static void set_data_type (deflate_state *s); -static void bi_windup (deflate_state *s); -static void bi_flush (deflate_state *s); -static void copy_block (deflate_state *s, char *buf, unsigned len, - int header); - -#ifndef DEBUG_ZLIB -# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) - /* Send a code of the given tree. c and tree must not have side effects */ - -#else /* DEBUG_ZLIB */ -# define send_code(s, c, tree) \ - { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ - send_bits(s, tree[c].Code, tree[c].Len); } -#endif - -#define d_code(dist) \ - ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)]) -/* Mapping from a distance to a distance code. dist is the distance - 1 and - * must not have side effects. dist_code[256] and dist_code[257] are never - * used. - */ - -/* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ -#ifdef DEBUG_ZLIB -static void send_bits (deflate_state *s, int value, int length); - -static void send_bits( - deflate_state *s, - int value, /* value to send */ - int length /* number of bits */ -) -{ - Tracevv((stderr," l %2d v %4x ", length, value)); - Assert(length > 0 && length <= 15, "invalid length"); - s->bits_sent += (ulg)length; - - /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) - * unused bits in value. - */ - if (s->bi_valid > (int)Buf_size - length) { - s->bi_buf |= (value << s->bi_valid); - put_short(s, s->bi_buf); - s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); - s->bi_valid += length - Buf_size; - } else { - s->bi_buf |= value << s->bi_valid; - s->bi_valid += length; - } -} -#else /* !DEBUG_ZLIB */ - -#define send_bits(s, value, length) \ -{ int len = length;\ - if (s->bi_valid > (int)Buf_size - len) {\ - int val = value;\ - s->bi_buf |= (val << s->bi_valid);\ - put_short(s, s->bi_buf);\ - s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ - s->bi_valid += len - Buf_size;\ - } else {\ - s->bi_buf |= (value) << s->bi_valid;\ - s->bi_valid += len;\ - }\ -} -#endif /* DEBUG_ZLIB */ - -/* =========================================================================== - * Initialize the various 'constant' tables. In a multi-threaded environment, - * this function may be called by two threads concurrently, but this is - * harmless since both invocations do exactly the same thing. - */ -static void tr_static_init(void) -{ - static int static_init_done; - int n; /* iterates over tree elements */ - int bits; /* bit counter */ - int length; /* length value */ - int code; /* code value */ - int dist; /* distance index */ - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - if (static_init_done) return; - - /* Initialize the mapping length (0..255) -> length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES-1; code++) { - base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ - dist = 0; - for (code = 0 ; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ - for ( ; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { - dist_code[256 + dist++] = (uch)code; - } - } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; - n = 0; - while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; - while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; - while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; - while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; - /* Codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES; n++) { - static_dtree[n].Len = 5; - static_dtree[n].Code = bitrev32((u32)n) >> (32 - 5); - } - static_init_done = 1; -} - -/* =========================================================================== - * Initialize the tree data structures for a new zlib stream. - */ -void zlib_tr_init( - deflate_state *s -) -{ - tr_static_init(); - - s->compressed_len = 0L; - - s->l_desc.dyn_tree = s->dyn_ltree; - s->l_desc.stat_desc = &static_l_desc; - - s->d_desc.dyn_tree = s->dyn_dtree; - s->d_desc.stat_desc = &static_d_desc; - - s->bl_desc.dyn_tree = s->bl_tree; - s->bl_desc.stat_desc = &static_bl_desc; - - s->bi_buf = 0; - s->bi_valid = 0; - s->last_eob_len = 8; /* enough lookahead for inflate */ -#ifdef DEBUG_ZLIB - s->bits_sent = 0L; -#endif - - /* Initialize the first block of the first file: */ - init_block(s); -} - -/* =========================================================================== - * Initialize a new block. - */ -static void init_block( - deflate_state *s -) -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; - - s->dyn_ltree[END_BLOCK].Freq = 1; - s->opt_len = s->static_len = 0L; - s->last_lit = s->matches = 0; -} - -#define SMALLEST 1 -/* Index within the heap array of least frequent node in the Huffman tree */ - - -/* =========================================================================== - * Remove the smallest element from the heap and recreate the heap with - * one less element. Updates heap and heap_len. - */ -#define pqremove(s, tree, top) \ -{\ - top = s->heap[SMALLEST]; \ - s->heap[SMALLEST] = s->heap[s->heap_len--]; \ - pqdownheap(s, tree, SMALLEST); \ -} - -/* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ -#define smaller(tree, n, m, depth) \ - (tree[n].Freq < tree[m].Freq || \ - (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) - -/* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ -static void pqdownheap( - deflate_state *s, - ct_data *tree, /* the tree to restore */ - int k /* node to move down */ -) -{ - int v = s->heap[k]; - int j = k << 1; /* left son of k */ - while (j <= s->heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { - j++; - } - /* Exit if v is smaller than both sons */ - if (smaller(tree, v, s->heap[j], s->depth)) break; - - /* Exchange v with the smallest son */ - s->heap[k] = s->heap[j]; k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; - } - s->heap[k] = v; -} - -/* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. - */ -static void gen_bitlen( - deflate_state *s, - tree_desc *desc /* the tree descriptor */ -) -{ - ct_data *tree = desc->dyn_tree; - int max_code = desc->max_code; - const ct_data *stree = desc->stat_desc->static_tree; - const int *extra = desc->stat_desc->extra_bits; - int base = desc->stat_desc->extra_base; - int max_length = desc->stat_desc->max_length; - int h; /* heap index */ - int n, m; /* iterate over the tree elements */ - int bits; /* bit length */ - int xbits; /* extra bits */ - ush f; /* frequency */ - int overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { - n = s->heap[h]; - bits = tree[tree[n].Dad].Len + 1; - if (bits > max_length) bits = max_length, overflow++; - tree[n].Len = (ush)bits; - /* We overwrite tree[n].Dad which is no longer needed */ - - if (n > max_code) continue; /* not a leaf node */ - - s->bl_count[bits]++; - xbits = 0; - if (n >= base) xbits = extra[n-base]; - f = tree[n].Freq; - s->opt_len += (ulg)f * (bits + xbits); - if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); - } - if (overflow == 0) return; - - Trace((stderr,"\nbit length overflow\n")); - /* This happens for example on obj2 and pic of the Calgary corpus */ - - /* Find the first bit length which could increase: */ - do { - bits = max_length-1; - while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ - s->bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits != 0; bits--) { - n = s->bl_count[bits]; - while (n != 0) { - m = s->heap[--h]; - if (m > max_code) continue; - if (tree[m].Len != (unsigned) bits) { - Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s->opt_len += ((long)bits - (long)tree[m].Len) - *(long)tree[m].Freq; - tree[m].Len = (ush)bits; - } - n--; - } - } -} - -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -static void gen_codes( - ct_data *tree, /* the tree to decorate */ - int max_code, /* largest code with non zero frequency */ - ush *bl_count /* number of codes at each bit length */ -) -{ - ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - ush code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - next_code[bits] = code = (code + bl_count[bits-1]) << 1; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert (code + bl_count[MAX_BITS]-1 == (1<> (32 - len); - - Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", - n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1)); - } -} - -/* =========================================================================== - * Construct one Huffman tree and assigns the code bit strings and lengths. - * Update the total bit length for the current block. - * IN assertion: the field freq is set for all tree elements. - * OUT assertions: the fields len and code are set to the optimal bit length - * and corresponding code. The length opt_len is updated; static_len is - * also updated if stree is not null. The field max_code is set. - */ -static void build_tree( - deflate_state *s, - tree_desc *desc /* the tree descriptor */ -) -{ - ct_data *tree = desc->dyn_tree; - const ct_data *stree = desc->stat_desc->static_tree; - int elems = desc->stat_desc->elems; - int n, m; /* iterate over heap elements */ - int max_code = -1; /* largest code with non zero frequency */ - int node; /* new node being created */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - s->heap_len = 0, s->heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n].Freq != 0) { - s->heap[++(s->heap_len)] = max_code = n; - s->depth[n] = 0; - } else { - tree[n].Len = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (s->heap_len < 2) { - node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); - tree[node].Freq = 1; - s->depth[node] = 0; - s->opt_len--; if (stree) s->static_len -= stree[node].Len; - /* node is 0 or 1 so it does not have extra bits */ - } - desc->max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - node = elems; /* next internal node of the tree */ - do { - pqremove(s, tree, n); /* n = node of least frequency */ - m = s->heap[SMALLEST]; /* m = node of next least frequency */ - - s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ - s->heap[--(s->heap_max)] = m; - - /* Create a new node father of n and m */ - tree[node].Freq = tree[n].Freq + tree[m].Freq; - s->depth[node] = (uch) (max(s->depth[n], s->depth[m]) + 1); - tree[n].Dad = tree[m].Dad = (ush)node; -#ifdef DUMP_BL_TREE - if (tree == s->bl_tree) { - fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", - node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); - } -#endif - /* and insert the new node in the heap */ - s->heap[SMALLEST] = node++; - pqdownheap(s, tree, SMALLEST); - - } while (s->heap_len >= 2); - - s->heap[--(s->heap_max)] = s->heap[SMALLEST]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen(s, (tree_desc *)desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes ((ct_data *)tree, max_code, s->bl_count); -} - -/* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. - */ -static void scan_tree( - deflate_state *s, - ct_data *tree, /* the tree to be scanned */ - int max_code /* and its largest code of non zero frequency */ -) -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - s->bl_tree[curlen].Freq += count; - } else if (curlen != 0) { - if (curlen != prevlen) s->bl_tree[curlen].Freq++; - s->bl_tree[REP_3_6].Freq++; - } else if (count <= 10) { - s->bl_tree[REPZ_3_10].Freq++; - } else { - s->bl_tree[REPZ_11_138].Freq++; - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ -static void send_tree( - deflate_state *s, - ct_data *tree, /* the tree to be scanned */ - int max_code /* and its largest code of non zero frequency */ -) -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - /* tree[max_code+1].Len = -1; */ /* guard already set */ - if (nextlen == 0) max_count = 138, min_count = 3; - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - do { send_code(s, curlen, s->bl_tree); } while (--count != 0); - - } else if (curlen != 0) { - if (curlen != prevlen) { - send_code(s, curlen, s->bl_tree); count--; - } - Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); - - } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); - - } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ -static int build_bl_tree( - deflate_state *s -) -{ - int max_blindex; /* index of last bit length code of non zero freq */ - - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); - scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); - - /* Build the bit length tree: */ - build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ - - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { - if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; - } - /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*(max_blindex+1) + 5+5+4; - Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", - s->opt_len, s->static_len)); - - return max_blindex; -} - -/* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ -static void send_all_trees( - deflate_state *s, - int lcodes, /* number of codes for each tree */ - int dcodes, /* number of codes for each tree */ - int blcodes /* number of codes for each tree */ -) -{ - int rank; /* index in bl_order */ - - Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, - "too many codes"); - Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - Tracev((stderr, "\nbl code %2d ", bl_order[rank])); - send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); - } - Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ - Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ - Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); -} - -/* =========================================================================== - * Send a stored block - */ -void zlib_tr_stored_block( - deflate_state *s, - char *buf, /* input block */ - ulg stored_len, /* length of input block */ - int eof /* true if this is the last block for a file */ -) -{ - send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ - s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; - s->compressed_len += (stored_len + 4) << 3; - - copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ -} - -/* Send just the `stored block' type code without any length bytes or data. - */ -void zlib_tr_stored_type_only( - deflate_state *s -) -{ - send_bits(s, (STORED_BLOCK << 1), 3); - bi_windup(s); - s->compressed_len = (s->compressed_len + 3) & ~7L; -} - - -/* =========================================================================== - * Send one empty static block to give enough lookahead for inflate. - * This takes 10 bits, of which 7 may remain in the bit buffer. - * The current inflate code requires 9 bits of lookahead. If the - * last two codes for the previous block (real code plus EOB) were coded - * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode - * the last real code. In this case we send two empty static blocks instead - * of one. (There are no problems if the previous block is stored or fixed.) - * To simplify the code, we assume the worst case of last real code encoded - * on one bit only. - */ -void zlib_tr_align( - deflate_state *s -) -{ - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); - s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ - bi_flush(s); - /* Of the 10 bits for the empty block, we have already sent - * (10 - bi_valid) bits. The lookahead for the last real code (before - * the EOB of the previous block) was thus at least one plus the length - * of the EOB plus what we have just sent of the empty static block. - */ - if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); - s->compressed_len += 10L; - bi_flush(s); - } - s->last_eob_len = 7; -} - -/* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and output the encoded block to the zip file. This function - * returns the total compressed length for the file so far. - */ -ulg zlib_tr_flush_block( - deflate_state *s, - char *buf, /* input block, or NULL if too old */ - ulg stored_len, /* length of input block */ - int eof /* true if this is the last block for a file */ -) -{ - ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - int max_blindex = 0; /* index of last bit length code of non zero freq */ - - /* Build the Huffman trees unless a stored block is forced */ - if (s->level > 0) { - - /* Check if the file is ascii or binary */ - if (s->data_type == Z_UNKNOWN) set_data_type(s); - - /* Construct the literal and distance trees */ - build_tree(s, (tree_desc *)(&(s->l_desc))); - Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - - build_tree(s, (tree_desc *)(&(s->d_desc))); - Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ - - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(s); - - /* Determine the best encoding. Compute first the block length in bytes*/ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; - - Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", - opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - s->last_lit)); - - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; - - } else { - Assert(buf != (char*)0, "lost buf"); - opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ - } - - /* If compression failed and this is the first and last block, - * and if the .zip file can be seeked (to rewrite the local header), - * the whole file is transformed into a stored file: - */ -#ifdef STORED_FILE_OK -# ifdef FORCE_STORED_FILE - if (eof && s->compressed_len == 0L) { /* force stored file */ -# else - if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) { -# endif - /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */ - if (buf == (char*)0) error ("block vanished"); - - copy_block(s, buf, (unsigned)stored_len, 0); /* without header */ - s->compressed_len = stored_len << 3; - s->method = STORED; - } else -#endif /* STORED_FILE_OK */ - -#ifdef FORCE_STORED - if (buf != (char*)0) { /* force stored block */ -#else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { - /* 4: two words for the lengths */ -#endif - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - zlib_tr_stored_block(s, buf, stored_len, eof); - -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else - } else if (static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+eof, 3); - compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); - s->compressed_len += 3 + s->static_len; - } else { - send_bits(s, (DYN_TREES<<1)+eof, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); - compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); - s->compressed_len += 3 + s->opt_len; - } - Assert (s->compressed_len == s->bits_sent, "bad compressed size"); - init_block(s); - - if (eof) { - bi_windup(s); - s->compressed_len += 7; /* align on byte boundary */ - } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*eof)); - - return s->compressed_len >> 3; -} - -/* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ -int zlib_tr_tally( - deflate_state *s, - unsigned dist, /* distance of matched string */ - unsigned lc /* match length-MIN_MATCH or unmatched char (if dist==0) */ -) -{ - s->d_buf[s->last_lit] = (ush)dist; - s->l_buf[s->last_lit++] = (uch)lc; - if (dist == 0) { - /* lc is the unmatched char */ - s->dyn_ltree[lc].Freq++; - } else { - s->matches++; - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - Assert((ush)dist < (ush)MAX_DIST(s) && - (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && - (ush)d_code(dist) < (ush)D_CODES, "zlib_tr_tally: bad match"); - - s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++; - s->dyn_dtree[d_code(dist)].Freq++; - } - - /* Try to guess if it is profitable to stop the current block here */ - if ((s->last_lit & 0xfff) == 0 && s->level > 2) { - /* Compute an upper bound for the compressed length */ - ulg out_length = (ulg)s->last_lit*8L; - ulg in_length = (ulg)((long)s->strstart - s->block_start); - int dcode; - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += (ulg)s->dyn_dtree[dcode].Freq * - (5L+extra_dbits[dcode]); - } - out_length >>= 3; - Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", - s->last_lit, in_length, out_length, - 100L - out_length*100L/in_length)); - if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; - } - return (s->last_lit == s->lit_bufsize-1); - /* We avoid equality with lit_bufsize because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ -} - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -static void compress_block( - deflate_state *s, - ct_data *ltree, /* literal tree */ - ct_data *dtree /* distance tree */ -) -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned lx = 0; /* running index in l_buf */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (s->last_lit != 0) do { - dist = s->d_buf[lx]; - lc = s->l_buf[lx++]; - if (dist == 0) { - send_code(s, lc, ltree); /* send a literal byte */ - Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - Assert(s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow"); - - } while (lx < s->last_lit); - - send_code(s, END_BLOCK, ltree); - s->last_eob_len = ltree[END_BLOCK].Len; -} - -/* =========================================================================== - * Set the data type to ASCII or BINARY, using a crude approximation: - * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. - * IN assertion: the fields freq of dyn_ltree are set and the total of all - * frequencies does not exceed 64K (to fit in an int on 16 bit machines). - */ -static void set_data_type( - deflate_state *s -) -{ - int n = 0; - unsigned ascii_freq = 0; - unsigned bin_freq = 0; - while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; - while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; - while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; - s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); -} - -/* =========================================================================== - * Copy a stored block, storing first the length and its - * one's complement if requested. - */ -static void copy_block( - deflate_state *s, - char *buf, /* the input data */ - unsigned len, /* its length */ - int header /* true if block header must be written */ -) -{ - bi_windup(s); /* align on byte boundary */ - s->last_eob_len = 8; /* enough lookahead for inflate */ - - if (header) { - put_short(s, (ush)len); - put_short(s, (ush)~len); -#ifdef DEBUG_ZLIB - s->bits_sent += 2*16; -#endif - } -#ifdef DEBUG_ZLIB - s->bits_sent += (ulg)len<<3; -#endif - /* bundle up the put_byte(s, *buf++) calls */ - memcpy(&s->pending_buf[s->pending], buf, len); - s->pending += len; -} - diff --git a/src/linux/lib/zlib_deflate/defutil.h b/src/linux/lib/zlib_deflate/defutil.h deleted file mode 100644 index a8c3708..0000000 --- a/src/linux/lib/zlib_deflate/defutil.h +++ /dev/null @@ -1,327 +0,0 @@ - - - -#define Assert(err, str) -#define Trace(dummy) -#define Tracev(dummy) -#define Tracecv(err, dummy) -#define Tracevv(dummy) - - - -#define LENGTH_CODES 29 -/* number of length codes, not counting the special END_BLOCK code */ - -#define LITERALS 256 -/* number of literal bytes 0..255 */ - -#define L_CODES (LITERALS+1+LENGTH_CODES) -/* number of Literal or Length codes, including the END_BLOCK code */ - -#define D_CODES 30 -/* number of distance codes */ - -#define BL_CODES 19 -/* number of codes used to transfer the bit lengths */ - -#define HEAP_SIZE (2*L_CODES+1) -/* maximum heap size */ - -#define MAX_BITS 15 -/* All codes must not exceed MAX_BITS bits */ - -#define INIT_STATE 42 -#define BUSY_STATE 113 -#define FINISH_STATE 666 -/* Stream status */ - - -/* Data structure describing a single value and its code string. */ -typedef struct ct_data_s { - union { - ush freq; /* frequency count */ - ush code; /* bit string */ - } fc; - union { - ush dad; /* father node in Huffman tree */ - ush len; /* length of bit string */ - } dl; -} ct_data; - -#define Freq fc.freq -#define Code fc.code -#define Dad dl.dad -#define Len dl.len - -typedef struct static_tree_desc_s static_tree_desc; - -typedef struct tree_desc_s { - ct_data *dyn_tree; /* the dynamic tree */ - int max_code; /* largest code with non zero frequency */ - static_tree_desc *stat_desc; /* the corresponding static tree */ -} tree_desc; - -typedef ush Pos; -typedef unsigned IPos; - -/* A Pos is an index in the character window. We use short instead of int to - * save space in the various tables. IPos is used only for parameter passing. - */ - -typedef struct deflate_state { - z_streamp strm; /* pointer back to this zlib stream */ - int status; /* as the name implies */ - Byte *pending_buf; /* output still pending */ - ulg pending_buf_size; /* size of pending_buf */ - Byte *pending_out; /* next pending byte to output to the stream */ - int pending; /* nb of bytes in the pending buffer */ - int noheader; /* suppress zlib header and adler32 */ - Byte data_type; /* UNKNOWN, BINARY or ASCII */ - Byte method; /* STORED (for zip only) or DEFLATED */ - int last_flush; /* value of flush param for previous deflate call */ - - /* used by deflate.c: */ - - uInt w_size; /* LZ77 window size (32K by default) */ - uInt w_bits; /* log2(w_size) (8..16) */ - uInt w_mask; /* w_size - 1 */ - - Byte *window; - /* Sliding window. Input bytes are read into the second half of the window, - * and move to the first half later to keep a dictionary of at least wSize - * bytes. With this organization, matches are limited to a distance of - * wSize-MAX_MATCH bytes, but this ensures that IO is always - * performed with a length multiple of the block size. Also, it limits - * the window size to 64K, which is quite useful on MSDOS. - * To do: use the user input buffer as sliding window. - */ - - ulg window_size; - /* Actual size of window: 2*wSize, except when the user input buffer - * is directly used as sliding window. - */ - - Pos *prev; - /* Link to older string with same hash index. To limit the size of this - * array to 64K, this link is maintained only for the last 32K strings. - * An index in this array is thus a window index modulo 32K. - */ - - Pos *head; /* Heads of the hash chains or NIL. */ - - uInt ins_h; /* hash index of string to be inserted */ - uInt hash_size; /* number of elements in hash table */ - uInt hash_bits; /* log2(hash_size) */ - uInt hash_mask; /* hash_size-1 */ - - uInt hash_shift; - /* Number of bits by which ins_h must be shifted at each input - * step. It must be such that after MIN_MATCH steps, the oldest - * byte no longer takes part in the hash key, that is: - * hash_shift * MIN_MATCH >= hash_bits - */ - - long block_start; - /* Window position at the beginning of the current output block. Gets - * negative when the window is moved backwards. - */ - - uInt match_length; /* length of best match */ - IPos prev_match; /* previous match */ - int match_available; /* set if previous match exists */ - uInt strstart; /* start of string to insert */ - uInt match_start; /* start of matching string */ - uInt lookahead; /* number of valid bytes ahead in window */ - - uInt prev_length; - /* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ - - uInt max_chain_length; - /* To speed up deflation, hash chains are never searched beyond this - * length. A higher limit improves compression ratio but degrades the - * speed. - */ - - uInt max_lazy_match; - /* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ -# define max_insert_length max_lazy_match - /* Insert new strings in the hash table only if the match length is not - * greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ - - int level; /* compression level (1..9) */ - int strategy; /* favor or force Huffman coding*/ - - uInt good_match; - /* Use a faster search when the previous match is longer than this */ - - int nice_match; /* Stop searching when current match exceeds this */ - - /* used by trees.c: */ - /* Didn't use ct_data typedef below to suppress compiler warning */ - struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ - struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ - struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ - - struct tree_desc_s l_desc; /* desc. for literal tree */ - struct tree_desc_s d_desc; /* desc. for distance tree */ - struct tree_desc_s bl_desc; /* desc. for bit length tree */ - - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ - int heap_len; /* number of elements in the heap */ - int heap_max; /* element of largest frequency */ - /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ - - uch depth[2*L_CODES+1]; - /* Depth of each subtree used as tie breaker for trees of equal frequency - */ - - uch *l_buf; /* buffer for literals or lengths */ - - uInt lit_bufsize; - /* Size of match buffer for literals/lengths. There are 4 reasons for - * limiting lit_bufsize to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input - * data is still in the window so we can still emit a stored block even - * when input comes from standard input. (This can also be done for - * all blocks if lit_bufsize is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * This is applicable only for zip (not gzip or zlib). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting - * trees more frequently. - * - I can't count above 4 - */ - - uInt last_lit; /* running index in l_buf */ - - ush *d_buf; - /* Buffer for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ - - ulg opt_len; /* bit length of current block with optimal trees */ - ulg static_len; /* bit length of current block with static trees */ - ulg compressed_len; /* total bit length of compressed file */ - uInt matches; /* number of string matches in current block */ - int last_eob_len; /* bit length of EOB code for last block */ - -#ifdef DEBUG_ZLIB - ulg bits_sent; /* bit length of the compressed data */ -#endif - - ush bi_buf; - /* Output buffer. bits are inserted starting at the bottom (least - * significant bits). - */ - int bi_valid; - /* Number of valid bits in bi_buf. All bits above the last valid bit - * are always zero. - */ - -} deflate_state; - -typedef struct deflate_workspace { - /* State memory for the deflator */ - deflate_state deflate_memory; - Byte *window_memory; - Pos *prev_memory; - Pos *head_memory; - char *overlay_memory; -} deflate_workspace; - -#define zlib_deflate_window_memsize(windowBits) \ - (2 * (1 << (windowBits)) * sizeof(Byte)) -#define zlib_deflate_prev_memsize(windowBits) \ - ((1 << (windowBits)) * sizeof(Pos)) -#define zlib_deflate_head_memsize(memLevel) \ - ((1 << ((memLevel)+7)) * sizeof(Pos)) -#define zlib_deflate_overlay_memsize(memLevel) \ - ((1 << ((memLevel)+6)) * (sizeof(ush)+2)) - -/* Output a byte on the stream. - * IN assertion: there is enough room in pending_buf. - */ -#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} - - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) -/* In order to simplify the code, particularly on 16 bit machines, match - * distances are limited to MAX_DIST instead of WSIZE. - */ - - /* in trees.c */ -void zlib_tr_init (deflate_state *s); -int zlib_tr_tally (deflate_state *s, unsigned dist, unsigned lc); -ulg zlib_tr_flush_block (deflate_state *s, char *buf, ulg stored_len, - int eof); -void zlib_tr_align (deflate_state *s); -void zlib_tr_stored_block (deflate_state *s, char *buf, ulg stored_len, - int eof); -void zlib_tr_stored_type_only (deflate_state *); - - -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ -#define put_short(s, w) { \ - put_byte(s, (uch)((w) & 0xff)); \ - put_byte(s, (uch)((ush)(w) >> 8)); \ -} - -/* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ -static inline void bi_flush(deflate_state *s) -{ - if (s->bi_valid == 16) { - put_short(s, s->bi_buf); - s->bi_buf = 0; - s->bi_valid = 0; - } else if (s->bi_valid >= 8) { - put_byte(s, (Byte)s->bi_buf); - s->bi_buf >>= 8; - s->bi_valid -= 8; - } -} - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -static inline void bi_windup(deflate_state *s) -{ - if (s->bi_valid > 8) { - put_short(s, s->bi_buf); - } else if (s->bi_valid > 0) { - put_byte(s, (Byte)s->bi_buf); - } - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef DEBUG_ZLIB - s->bits_sent = (s->bits_sent+7) & ~7; -#endif -} - diff --git a/src/linux/lib/zlib_inflate/Makefile b/src/linux/lib/zlib_inflate/Makefile deleted file mode 100644 index 49f8ce5..0000000 --- a/src/linux/lib/zlib_inflate/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# -# This is a modified version of zlib, which does all memory -# allocation ahead of time. -# -# This is only the decompression, see zlib_deflate for the -# the compression -# -# Decompression needs to be serialized for each memory -# allocation. -# -# (The upsides of the simplification is that you can't get in -# any nasty situations wrt memory management, and that the -# uncompression can be done without blocking on allocation). -# - -obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate.o - -zlib_inflate-objs := inffast.o inflate.o infutil.o \ - inftrees.o inflate_syms.o diff --git a/src/linux/lib/zlib_inflate/inffast.c b/src/linux/lib/zlib_inflate/inffast.c deleted file mode 100644 index 2c13ecc..0000000 --- a/src/linux/lib/zlib_inflate/inffast.c +++ /dev/null @@ -1,363 +0,0 @@ -/* inffast.c -- fast decoding - * Copyright (C) 1995-2004 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifndef ASMINF - -/* Allow machine dependent optimization for post-increment or pre-increment. - Based on testing to date, - Pre-increment preferred for: - - PowerPC G3 (Adler) - - MIPS R5000 (Randers-Pehrson) - Post-increment preferred for: - - none - No measurable difference: - - Pentium III (Anderson) - - M68060 (Nikl) - */ -union uu { - unsigned short us; - unsigned char b[2]; -}; - -/* Endian independed version */ -static inline unsigned short -get_unaligned16(const unsigned short *p) -{ - union uu mm; - unsigned char *b = (unsigned char *)p; - - mm.b[0] = b[0]; - mm.b[1] = b[1]; - return mm.us; -} - -#ifdef POSTINC -# define OFF 0 -# define PUP(a) *(a)++ -# define UP_UNALIGNED(a) get_unaligned16((a)++) -#else -# define OFF 1 -# define PUP(a) *++(a) -# define UP_UNALIGNED(a) get_unaligned16(++(a)) -#endif - -/* - Decode literal, length, and distance codes and write out the resulting - literal and match bytes until either not enough input or output is - available, an end-of-block is encountered, or a data error is encountered. - When large enough input and output buffers are supplied to inflate(), for - example, a 16K input buffer and a 64K output buffer, more than 95% of the - inflate execution time is spent in this routine. - - Entry assumptions: - - state->mode == LEN - strm->avail_in >= 6 - strm->avail_out >= 258 - start >= strm->avail_out - state->bits < 8 - - On return, state->mode is one of: - - LEN -- ran out of enough output space or enough available input - TYPE -- reached end of block code, inflate() to interpret next block - BAD -- error in block data - - Notes: - - - The maximum input bits used by a length/distance pair is 15 bits for the - length code, 5 bits for the length extra, 15 bits for the distance code, - and 13 bits for the distance extra. This totals 48 bits, or six bytes. - Therefore if strm->avail_in >= 6, then there is enough input to avoid - checking for available input while decoding. - - - The maximum bytes that a single length/distance pair can output is 258 - bytes, which is the maximum length that can be coded. inflate_fast() - requires strm->avail_out >= 258 for each loop to avoid checking for - output space. - - - @start: inflate()'s starting value for strm->avail_out - */ -void inflate_fast(z_streamp strm, unsigned start) -{ - struct inflate_state *state; - const unsigned char *in; /* local strm->next_in */ - const unsigned char *last; /* while in < last, enough input available */ - unsigned char *out; /* local strm->next_out */ - unsigned char *beg; /* inflate()'s initial strm->next_out */ - unsigned char *end; /* while out < end, enough space available */ -#ifdef INFLATE_STRICT - unsigned dmax; /* maximum distance from zlib header */ -#endif - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned write; /* window write index */ - unsigned char *window; /* allocated sliding window, if wsize != 0 */ - unsigned long hold; /* local strm->hold */ - unsigned bits; /* local strm->bits */ - code const *lcode; /* local strm->lencode */ - code const *dcode; /* local strm->distcode */ - unsigned lmask; /* mask for first level of length codes */ - unsigned dmask; /* mask for first level of distance codes */ - code this; /* retrieved table entry */ - unsigned op; /* code bits, operation, extra bits, or */ - /* window position, window bytes to copy */ - unsigned len; /* match length, unused bytes */ - unsigned dist; /* match distance */ - unsigned char *from; /* where to copy match from */ - - /* copy state to local variables */ - state = (struct inflate_state *)strm->state; - in = strm->next_in - OFF; - last = in + (strm->avail_in - 5); - out = strm->next_out - OFF; - beg = out - (start - strm->avail_out); - end = out + (strm->avail_out - 257); -#ifdef INFLATE_STRICT - dmax = state->dmax; -#endif - wsize = state->wsize; - whave = state->whave; - write = state->write; - window = state->window; - hold = state->hold; - bits = state->bits; - lcode = state->lencode; - dcode = state->distcode; - lmask = (1U << state->lenbits) - 1; - dmask = (1U << state->distbits) - 1; - - /* decode literals and length/distances until end-of-block or not enough - input data or output space */ - do { - if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - this = lcode[hold & lmask]; - dolen: - op = (unsigned)(this.bits); - hold >>= op; - bits -= op; - op = (unsigned)(this.op); - if (op == 0) { /* literal */ - PUP(out) = (unsigned char)(this.val); - } - else if (op & 16) { /* length base */ - len = (unsigned)(this.val); - op &= 15; /* number of extra bits */ - if (op) { - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - len += (unsigned)hold & ((1U << op) - 1); - hold >>= op; - bits -= op; - } - if (bits < 15) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - this = dcode[hold & dmask]; - dodist: - op = (unsigned)(this.bits); - hold >>= op; - bits -= op; - op = (unsigned)(this.op); - if (op & 16) { /* distance base */ - dist = (unsigned)(this.val); - op &= 15; /* number of extra bits */ - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - if (bits < op) { - hold += (unsigned long)(PUP(in)) << bits; - bits += 8; - } - } - dist += (unsigned)hold & ((1U << op) - 1); -#ifdef INFLATE_STRICT - if (dist > dmax) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#endif - hold >>= op; - bits -= op; - op = (unsigned)(out - beg); /* max distance in output */ - if (dist > op) { /* see if copy from window */ - op = dist - op; /* distance back in window */ - if (op > whave) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - from = window - OFF; - if (write == 0) { /* very common case */ - from += wsize - op; - if (op < len) { /* some from window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - else if (write < op) { /* wrap around window */ - from += wsize + write - op; - op -= write; - if (op < len) { /* some from end of window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = window - OFF; - if (write < len) { /* some from start of window */ - op = write; - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - } - else { /* contiguous in window */ - from += write - op; - if (op < len) { /* some from window */ - len -= op; - do { - PUP(out) = PUP(from); - } while (--op); - from = out - dist; /* rest from output */ - } - } - while (len > 2) { - PUP(out) = PUP(from); - PUP(out) = PUP(from); - PUP(out) = PUP(from); - len -= 3; - } - if (len) { - PUP(out) = PUP(from); - if (len > 1) - PUP(out) = PUP(from); - } - } - else { - unsigned short *sout; - unsigned long loops; - - from = out - dist; /* copy direct from output */ - /* minimum length is three */ - /* Align out addr */ - if (!((long)(out - 1 + OFF) & 1)) { - PUP(out) = PUP(from); - len--; - } - sout = (unsigned short *)(out - OFF); - if (dist > 2) { - unsigned short *sfrom; - - sfrom = (unsigned short *)(from - OFF); - loops = len >> 1; - do -#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS - PUP(sout) = PUP(sfrom); -#else - PUP(sout) = UP_UNALIGNED(sfrom); -#endif - while (--loops); - out = (unsigned char *)sout + OFF; - from = (unsigned char *)sfrom + OFF; - } else { /* dist == 1 or dist == 2 */ - unsigned short pat16; - - pat16 = *(sout-1+OFF); - if (dist == 1) { - union uu mm; - /* copy one char pattern to both bytes */ - mm.us = pat16; - mm.b[0] = mm.b[1]; - pat16 = mm.us; - } - loops = len >> 1; - do - PUP(sout) = pat16; - while (--loops); - out = (unsigned char *)sout + OFF; - } - if (len & 1) - PUP(out) = PUP(from); - } - } - else if ((op & 64) == 0) { /* 2nd level distance code */ - this = dcode[this.val + (hold & ((1U << op) - 1))]; - goto dodist; - } - else { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - } - else if ((op & 64) == 0) { /* 2nd level length code */ - this = lcode[this.val + (hold & ((1U << op) - 1))]; - goto dolen; - } - else if (op & 32) { /* end-of-block */ - state->mode = TYPE; - break; - } - else { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - } while (in < last && out < end); - - /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ - len = bits >> 3; - in -= len; - bits -= len << 3; - hold &= (1U << bits) - 1; - - /* update state and return */ - strm->next_in = in + OFF; - strm->next_out = out + OFF; - strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); - strm->avail_out = (unsigned)(out < end ? - 257 + (end - out) : 257 - (out - end)); - state->hold = hold; - state->bits = bits; - return; -} - -/* - inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - - Using bit fields for code structure - - Different op definition to avoid & for extra bits (do & for table bits) - - Three separate decoding do-loops for direct, window, and write == 0 - - Special case for distance > 1 copies to do overlapped load and store copy - - Explicit branch predictions (based on measured branch probabilities) - - Deferring match copy and interspersed it with decoding subsequent codes - - Swapping literal/length else - - Swapping window/direct else - - Larger unrolled copy loops (three is about right) - - Moving len -= 3 statement into middle of loop - */ - -#endif /* !ASMINF */ diff --git a/src/linux/lib/zlib_inflate/inffast.h b/src/linux/lib/zlib_inflate/inffast.h deleted file mode 100644 index 40315d9..0000000 --- a/src/linux/lib/zlib_inflate/inffast.h +++ /dev/null @@ -1,11 +0,0 @@ -/* inffast.h -- header to use inffast.c - * Copyright (C) 1995-2003 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -void inflate_fast (z_streamp strm, unsigned start); diff --git a/src/linux/lib/zlib_inflate/inffixed.h b/src/linux/lib/zlib_inflate/inffixed.h deleted file mode 100644 index 75ed4b5..0000000 --- a/src/linux/lib/zlib_inflate/inffixed.h +++ /dev/null @@ -1,94 +0,0 @@ - /* inffixed.h -- table for decoding fixed codes - * Generated automatically by makefixed(). - */ - - /* WARNING: this file should *not* be used by applications. It - is part of the implementation of the compression library and - is subject to change. Applications should only use zlib.h. - */ - - static const code lenfix[512] = { - {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, - {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, - {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, - {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, - {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, - {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, - {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, - {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, - {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, - {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, - {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, - {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, - {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, - {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, - {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, - {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, - {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, - {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, - {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, - {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, - {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, - {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, - {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, - {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, - {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, - {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, - {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, - {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, - {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, - {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, - {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, - {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, - {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, - {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, - {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, - {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, - {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, - {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, - {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, - {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, - {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, - {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, - {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, - {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, - {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, - {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, - {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, - {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, - {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, - {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, - {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, - {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, - {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, - {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, - {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, - {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, - {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, - {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, - {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, - {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, - {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, - {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, - {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, - {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, - {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, - {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, - {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, - {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, - {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, - {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, - {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, - {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, - {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, - {0,9,255} - }; - - static const code distfix[32] = { - {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, - {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, - {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, - {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, - {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, - {22,5,193},{64,5,0} - }; diff --git a/src/linux/lib/zlib_inflate/inflate.c b/src/linux/lib/zlib_inflate/inflate.c deleted file mode 100644 index 58a733b..0000000 --- a/src/linux/lib/zlib_inflate/inflate.c +++ /dev/null @@ -1,786 +0,0 @@ -/* inflate.c -- zlib decompression - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Based on zlib 1.2.3 but modified for the Linux Kernel by - * Richard Purdie - * - * Changes mainly for static instead of dynamic memory allocation - * - */ - -#include -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" -#include "infutil.h" - -int zlib_inflate_workspacesize(void) -{ - return sizeof(struct inflate_workspace); -} - -int zlib_inflateReset(z_streamp strm) -{ - struct inflate_state *state; - - if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR; - state = (struct inflate_state *)strm->state; - strm->total_in = strm->total_out = state->total = 0; - strm->msg = NULL; - strm->adler = 1; /* to support ill-conceived Java test suite */ - state->mode = HEAD; - state->last = 0; - state->havedict = 0; - state->dmax = 32768U; - state->hold = 0; - state->bits = 0; - state->lencode = state->distcode = state->next = state->codes; - - /* Initialise Window */ - state->wsize = 1U << state->wbits; - state->write = 0; - state->whave = 0; - - return Z_OK; -} - -int zlib_inflateInit2(z_streamp strm, int windowBits) -{ - struct inflate_state *state; - - if (strm == NULL) return Z_STREAM_ERROR; - strm->msg = NULL; /* in case we return an error */ - - state = &WS(strm)->inflate_state; - strm->state = (struct internal_state *)state; - - if (windowBits < 0) { - state->wrap = 0; - windowBits = -windowBits; - } - else { - state->wrap = (windowBits >> 4) + 1; - } - if (windowBits < 8 || windowBits > 15) { - return Z_STREAM_ERROR; - } - state->wbits = (unsigned)windowBits; - state->window = &WS(strm)->working_window[0]; - - return zlib_inflateReset(strm); -} - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. This returns fixed tables from inffixed.h. - */ -static void zlib_fixedtables(struct inflate_state *state) -{ -# include "inffixed.h" - state->lencode = lenfix; - state->lenbits = 9; - state->distcode = distfix; - state->distbits = 5; -} - - -/* - Update the window with the last wsize (normally 32K) bytes written before - returning. This is only called when a window is already in use, or when - output has been written during this inflate call, but the end of the deflate - stream has not been reached yet. It is also called to window dictionary data - when a dictionary is loaded. - - Providing output buffers larger than 32K to inflate() should provide a speed - advantage, since only the last 32K of output is copied to the sliding window - upon return from inflate(), and since all distances after the first 32K of - output will fall in the output data, making match copies simpler and faster. - The advantage may be dependent on the size of the processor's data caches. - */ -static void zlib_updatewindow(z_streamp strm, unsigned out) -{ - struct inflate_state *state; - unsigned copy, dist; - - state = (struct inflate_state *)strm->state; - - /* copy state->wsize or less output bytes into the circular window */ - copy = out - strm->avail_out; - if (copy >= state->wsize) { - memcpy(state->window, strm->next_out - state->wsize, state->wsize); - state->write = 0; - state->whave = state->wsize; - } - else { - dist = state->wsize - state->write; - if (dist > copy) dist = copy; - memcpy(state->window + state->write, strm->next_out - copy, dist); - copy -= dist; - if (copy) { - memcpy(state->window, strm->next_out - copy, copy); - state->write = copy; - state->whave = state->wsize; - } - else { - state->write += dist; - if (state->write == state->wsize) state->write = 0; - if (state->whave < state->wsize) state->whave += dist; - } - } -} - - -/* - * At the end of a Deflate-compressed PPP packet, we expect to have seen - * a `stored' block type value but not the (zero) length bytes. - */ -/* - Returns true if inflate is currently at the end of a block generated by - Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - implementation to provide an additional safety check. PPP uses - Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored - block. When decompressing, PPP checks that at the end of input packet, - inflate is waiting for these length bytes. - */ -static int zlib_inflateSyncPacket(z_streamp strm) -{ - struct inflate_state *state; - - if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR; - state = (struct inflate_state *)strm->state; - - if (state->mode == STORED && state->bits == 0) { - state->mode = TYPE; - return Z_OK; - } - return Z_DATA_ERROR; -} - -/* Macros for inflate(): */ - -/* check function to use adler32() for zlib or crc32() for gzip */ -#define UPDATE(check, buf, len) zlib_adler32(check, buf, len) - -/* Load registers with state in inflate() for speed */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = state->bits; \ - } while (0) - -/* Restore state from registers in inflate() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Get a byte of input into the bit accumulator, or return from inflate() - if there is no input available. */ -#define PULLBYTE() \ - do { \ - if (have == 0) goto inf_leave; \ - have--; \ - hold += (unsigned long)(*next++) << bits; \ - bits += 8; \ - } while (0) - -/* Assure that there are at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflate(). */ -#define NEEDBITS(n) \ - do { \ - while (bits < (unsigned)(n)) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - ((unsigned)hold & ((1U << (n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - hold >>= (n); \ - bits -= (unsigned)(n); \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* Reverse the bytes in a 32-bit value */ -#define REVERSE(q) \ - ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ - (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) - -/* - inflate() uses a state machine to process as much input data and generate as - much output data as possible before returning. The state machine is - structured roughly as follows: - - for (;;) switch (state) { - ... - case STATEn: - if (not enough input data or output space to make progress) - return; - ... make progress ... - state = STATEm; - break; - ... - } - - so when inflate() is called again, the same case is attempted again, and - if the appropriate resources are provided, the machine proceeds to the - next state. The NEEDBITS() macro is usually the way the state evaluates - whether it can proceed or should return. NEEDBITS() does the return if - the requested bits are not available. The typical use of the BITS macros - is: - - NEEDBITS(n); - ... do something with BITS(n) ... - DROPBITS(n); - - where NEEDBITS(n) either returns from inflate() if there isn't enough - input left to load n bits into the accumulator, or it continues. BITS(n) - gives the low n bits in the accumulator. When done, DROPBITS(n) drops - the low n bits off the accumulator. INITBITS() clears the accumulator - and sets the number of available bits to zero. BYTEBITS() discards just - enough bits to put the accumulator on a byte boundary. After BYTEBITS() - and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. - - NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return - if there is no input available. The decoding of variable length codes uses - PULLBYTE() directly in order to pull just enough bytes to decode the next - code, and no more. - - Some states loop until they get enough input, making sure that enough - state information is maintained to continue the loop where it left off - if NEEDBITS() returns in the loop. For example, want, need, and keep - would all have to actually be part of the saved state in case NEEDBITS() - returns: - - case STATEw: - while (want < need) { - NEEDBITS(n); - keep[want++] = BITS(n); - DROPBITS(n); - } - state = STATEx; - case STATEx: - - As shown above, if the next state is also the next case, then the break - is omitted. - - A state may also return if there is not enough output space available to - complete that state. Those states are copying stored data, writing a - literal byte, and copying a matching string. - - When returning, a "goto inf_leave" is used to update the total counters, - update the check value, and determine whether any progress has been made - during that inflate() call in order to return the proper return code. - Progress is defined as a change in either strm->avail_in or strm->avail_out. - When there is a window, goto inf_leave will update the window with the last - output written. If a goto inf_leave occurs in the middle of decompression - and there is no window currently, goto inf_leave will create one and copy - output to the window for the next call of inflate(). - - In this implementation, the flush parameter of inflate() only affects the - return code (per zlib.h). inflate() always writes as much as possible to - strm->next_out, given the space available and the provided input--the effect - documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers - the allocation of and copying into a sliding window until necessary, which - provides the effect documented in zlib.h for Z_FINISH when the entire input - stream available. So the only thing the flush parameter actually does is: - when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it - will return Z_BUF_ERROR if it has not reached the end of the stream. - */ - -int zlib_inflate(z_streamp strm, int flush) -{ - struct inflate_state *state; - const unsigned char *next; /* next input */ - unsigned char *put; /* next output */ - unsigned have, left; /* available input and output */ - unsigned long hold; /* bit buffer */ - unsigned bits; /* bits in bit buffer */ - unsigned in, out; /* save starting available input and output */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char *from; /* where to copy match bytes from */ - code this; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int ret; /* return code */ - static const unsigned short order[19] = /* permutation of code lengths */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - /* Do not check for strm->next_out == NULL here as ppc zImage - inflates to strm->next_out = 0 */ - - if (strm == NULL || strm->state == NULL || - (strm->next_in == NULL && strm->avail_in != 0)) - return Z_STREAM_ERROR; - - state = (struct inflate_state *)strm->state; - - if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ - LOAD(); - in = have; - out = left; - ret = Z_OK; - for (;;) - switch (state->mode) { - case HEAD: - if (state->wrap == 0) { - state->mode = TYPEDO; - break; - } - NEEDBITS(16); - if ( - ((BITS(8) << 8) + (hold >> 8)) % 31) { - strm->msg = (char *)"incorrect header check"; - state->mode = BAD; - break; - } - if (BITS(4) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - DROPBITS(4); - len = BITS(4) + 8; - if (len > state->wbits) { - strm->msg = (char *)"invalid window size"; - state->mode = BAD; - break; - } - state->dmax = 1U << len; - strm->adler = state->check = zlib_adler32(0L, NULL, 0); - state->mode = hold & 0x200 ? DICTID : TYPE; - INITBITS(); - break; - case DICTID: - NEEDBITS(32); - strm->adler = state->check = REVERSE(hold); - INITBITS(); - state->mode = DICT; - case DICT: - if (state->havedict == 0) { - RESTORE(); - return Z_NEED_DICT; - } - strm->adler = state->check = zlib_adler32(0L, NULL, 0); - state->mode = TYPE; - case TYPE: - if (flush == Z_BLOCK) goto inf_leave; - case TYPEDO: - if (state->last) { - BYTEBITS(); - state->mode = CHECK; - break; - } - NEEDBITS(3); - state->last = BITS(1); - DROPBITS(1); - switch (BITS(2)) { - case 0: /* stored block */ - state->mode = STORED; - break; - case 1: /* fixed block */ - zlib_fixedtables(state); - state->mode = LEN; /* decode codes */ - break; - case 2: /* dynamic block */ - state->mode = TABLE; - break; - case 3: - strm->msg = (char *)"invalid block type"; - state->mode = BAD; - } - DROPBITS(2); - break; - case STORED: - BYTEBITS(); /* go to byte boundary */ - NEEDBITS(32); - if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - strm->msg = (char *)"invalid stored block lengths"; - state->mode = BAD; - break; - } - state->length = (unsigned)hold & 0xffff; - INITBITS(); - state->mode = COPY; - case COPY: - copy = state->length; - if (copy) { - if (copy > have) copy = have; - if (copy > left) copy = left; - if (copy == 0) goto inf_leave; - memcpy(put, next, copy); - have -= copy; - next += copy; - left -= copy; - put += copy; - state->length -= copy; - break; - } - state->mode = TYPE; - break; - case TABLE: - NEEDBITS(14); - state->nlen = BITS(5) + 257; - DROPBITS(5); - state->ndist = BITS(5) + 1; - DROPBITS(5); - state->ncode = BITS(4) + 4; - DROPBITS(4); -#ifndef PKZIP_BUG_WORKAROUND - if (state->nlen > 286 || state->ndist > 30) { - strm->msg = (char *)"too many length or distance symbols"; - state->mode = BAD; - break; - } -#endif - state->have = 0; - state->mode = LENLENS; - case LENLENS: - while (state->have < state->ncode) { - NEEDBITS(3); - state->lens[order[state->have++]] = (unsigned short)BITS(3); - DROPBITS(3); - } - while (state->have < 19) - state->lens[order[state->have++]] = 0; - state->next = state->codes; - state->lencode = (code const *)(state->next); - state->lenbits = 7; - ret = zlib_inflate_table(CODES, state->lens, 19, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid code lengths set"; - state->mode = BAD; - break; - } - state->have = 0; - state->mode = CODELENS; - case CODELENS: - while (state->have < state->nlen + state->ndist) { - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.val < 16) { - NEEDBITS(this.bits); - DROPBITS(this.bits); - state->lens[state->have++] = this.val; - } - else { - if (this.val == 16) { - NEEDBITS(this.bits + 2); - DROPBITS(this.bits); - if (state->have == 0) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - len = state->lens[state->have - 1]; - copy = 3 + BITS(2); - DROPBITS(2); - } - else if (this.val == 17) { - NEEDBITS(this.bits + 3); - DROPBITS(this.bits); - len = 0; - copy = 3 + BITS(3); - DROPBITS(3); - } - else { - NEEDBITS(this.bits + 7); - DROPBITS(this.bits); - len = 0; - copy = 11 + BITS(7); - DROPBITS(7); - } - if (state->have + copy > state->nlen + state->ndist) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - while (copy--) - state->lens[state->have++] = (unsigned short)len; - } - } - - /* handle error breaks in while */ - if (state->mode == BAD) break; - - /* build code tables */ - state->next = state->codes; - state->lencode = (code const *)(state->next); - state->lenbits = 9; - ret = zlib_inflate_table(LENS, state->lens, state->nlen, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid literal/lengths set"; - state->mode = BAD; - break; - } - state->distcode = (code const *)(state->next); - state->distbits = 6; - ret = zlib_inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); - if (ret) { - strm->msg = (char *)"invalid distances set"; - state->mode = BAD; - break; - } - state->mode = LEN; - case LEN: - if (have >= 6 && left >= 258) { - RESTORE(); - inflate_fast(strm, out); - LOAD(); - break; - } - for (;;) { - this = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if (this.op && (this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->lencode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - state->length = (unsigned)this.val; - if ((int)(this.op) == 0) { - state->mode = LIT; - break; - } - if (this.op & 32) { - state->mode = TYPE; - break; - } - if (this.op & 64) { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - state->extra = (unsigned)(this.op) & 15; - state->mode = LENEXT; - case LENEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->length += BITS(state->extra); - DROPBITS(state->extra); - } - state->mode = DIST; - case DIST: - for (;;) { - this = state->distcode[BITS(state->distbits)]; - if ((unsigned)(this.bits) <= bits) break; - PULLBYTE(); - } - if ((this.op & 0xf0) == 0) { - last = this; - for (;;) { - this = state->distcode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + this.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - } - DROPBITS(this.bits); - if (this.op & 64) { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - state->offset = (unsigned)this.val; - state->extra = (unsigned)(this.op) & 15; - state->mode = DISTEXT; - case DISTEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->offset += BITS(state->extra); - DROPBITS(state->extra); - } -#ifdef INFLATE_STRICT - if (state->offset > state->dmax) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#endif - if (state->offset > state->whave + out - left) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } - state->mode = MATCH; - case MATCH: - if (left == 0) goto inf_leave; - copy = out - left; - if (state->offset > copy) { /* copy from window */ - copy = state->offset - copy; - if (copy > state->write) { - copy -= state->write; - from = state->window + (state->wsize - copy); - } - else - from = state->window + (state->write - copy); - if (copy > state->length) copy = state->length; - } - else { /* copy from output */ - from = put - state->offset; - copy = state->length; - } - if (copy > left) copy = left; - left -= copy; - state->length -= copy; - do { - *put++ = *from++; - } while (--copy); - if (state->length == 0) state->mode = LEN; - break; - case LIT: - if (left == 0) goto inf_leave; - *put++ = (unsigned char)(state->length); - left--; - state->mode = LEN; - break; - case CHECK: - if (state->wrap) { - NEEDBITS(32); - out -= left; - strm->total_out += out; - state->total += out; - if (out) - strm->adler = state->check = - UPDATE(state->check, put - out, out); - out = left; - if (( - REVERSE(hold)) != state->check) { - strm->msg = (char *)"incorrect data check"; - state->mode = BAD; - break; - } - INITBITS(); - } - state->mode = DONE; - case DONE: - ret = Z_STREAM_END; - goto inf_leave; - case BAD: - ret = Z_DATA_ERROR; - goto inf_leave; - case MEM: - return Z_MEM_ERROR; - case SYNC: - default: - return Z_STREAM_ERROR; - } - - /* - Return from inflate(), updating the total counts and the check value. - If there was no progress during the inflate() call, return a buffer - error. Call zlib_updatewindow() to create and/or update the window state. - */ - inf_leave: - RESTORE(); - if (state->wsize || (state->mode < CHECK && out != strm->avail_out)) - zlib_updatewindow(strm, out); - - in -= strm->avail_in; - out -= strm->avail_out; - strm->total_in += in; - strm->total_out += out; - state->total += out; - if (state->wrap && out) - strm->adler = state->check = - UPDATE(state->check, strm->next_out - out, out); - - strm->data_type = state->bits + (state->last ? 64 : 0) + - (state->mode == TYPE ? 128 : 0); - - if (flush == Z_PACKET_FLUSH && ret == Z_OK && - strm->avail_out != 0 && strm->avail_in == 0) - return zlib_inflateSyncPacket(strm); - - if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) - ret = Z_BUF_ERROR; - - return ret; -} - -int zlib_inflateEnd(z_streamp strm) -{ - if (strm == NULL || strm->state == NULL) - return Z_STREAM_ERROR; - return Z_OK; -} - -/* - * This subroutine adds the data at next_in/avail_in to the output history - * without performing any output. The output buffer must be "caught up"; - * i.e. no pending output but this should always be the case. The state must - * be waiting on the start of a block (i.e. mode == TYPE or HEAD). On exit, - * the output will also be caught up, and the checksum will have been updated - * if need be. - */ -int zlib_inflateIncomp(z_stream *z) -{ - struct inflate_state *state = (struct inflate_state *)z->state; - Byte *saved_no = z->next_out; - uInt saved_ao = z->avail_out; - - if (state->mode != TYPE && state->mode != HEAD) - return Z_DATA_ERROR; - - /* Setup some variables to allow misuse of updateWindow */ - z->avail_out = 0; - z->next_out = (unsigned char*)z->next_in + z->avail_in; - - zlib_updatewindow(z, z->avail_in); - - /* Restore saved variables */ - z->avail_out = saved_ao; - z->next_out = saved_no; - - z->adler = state->check = - UPDATE(state->check, z->next_in, z->avail_in); - - z->total_out += z->avail_in; - z->total_in += z->avail_in; - z->next_in += z->avail_in; - state->total += z->avail_in; - z->avail_in = 0; - - return Z_OK; -} diff --git a/src/linux/lib/zlib_inflate/inflate.h b/src/linux/lib/zlib_inflate/inflate.h deleted file mode 100644 index 3d17b3d..0000000 --- a/src/linux/lib/zlib_inflate/inflate.h +++ /dev/null @@ -1,111 +0,0 @@ -#ifndef INFLATE_H -#define INFLATE_H - -/* inflate.h -- internal inflate state definition - * Copyright (C) 1995-2004 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Possible inflate modes between inflate() calls */ -typedef enum { - HEAD, /* i: waiting for magic header */ - FLAGS, /* i: waiting for method and flags (gzip) */ - TIME, /* i: waiting for modification time (gzip) */ - OS, /* i: waiting for extra flags and operating system (gzip) */ - EXLEN, /* i: waiting for extra length (gzip) */ - EXTRA, /* i: waiting for extra bytes (gzip) */ - NAME, /* i: waiting for end of file name (gzip) */ - COMMENT, /* i: waiting for end of comment (gzip) */ - HCRC, /* i: waiting for header crc (gzip) */ - DICTID, /* i: waiting for dictionary check value */ - DICT, /* waiting for inflateSetDictionary() call */ - TYPE, /* i: waiting for type bits, including last-flag bit */ - TYPEDO, /* i: same, but skip check to exit inflate on new block */ - STORED, /* i: waiting for stored size (length and complement) */ - COPY, /* i/o: waiting for input or output to copy stored block */ - TABLE, /* i: waiting for dynamic block table lengths */ - LENLENS, /* i: waiting for code length code lengths */ - CODELENS, /* i: waiting for length/lit and distance code lengths */ - LEN, /* i: waiting for length/lit code */ - LENEXT, /* i: waiting for length extra bits */ - DIST, /* i: waiting for distance code */ - DISTEXT, /* i: waiting for distance extra bits */ - MATCH, /* o: waiting for output space to copy string */ - LIT, /* o: waiting for output space to write literal */ - CHECK, /* i: waiting for 32-bit check value */ - LENGTH, /* i: waiting for 32-bit length (gzip) */ - DONE, /* finished check, done -- remain here until reset */ - BAD, /* got a data error -- remain here until reset */ - MEM, /* got an inflate() memory error -- remain here until reset */ - SYNC /* looking for synchronization bytes to restart inflate() */ -} inflate_mode; - -/* - State transitions between above modes - - - (most modes can go to the BAD or MEM mode -- not shown for clarity) - - Process header: - HEAD -> (gzip) or (zlib) - (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME - NAME -> COMMENT -> HCRC -> TYPE - (zlib) -> DICTID or TYPE - DICTID -> DICT -> TYPE - Read deflate blocks: - TYPE -> STORED or TABLE or LEN or CHECK - STORED -> COPY -> TYPE - TABLE -> LENLENS -> CODELENS -> LEN - Read deflate codes: - LEN -> LENEXT or LIT or TYPE - LENEXT -> DIST -> DISTEXT -> MATCH -> LEN - LIT -> LEN - Process trailer: - CHECK -> LENGTH -> DONE - */ - -/* state maintained between inflate() calls. Approximately 7K bytes. */ -struct inflate_state { - inflate_mode mode; /* current inflate mode */ - int last; /* true if processing last block */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - int havedict; /* true if dictionary provided */ - int flags; /* gzip header method and flags (0 if zlib) */ - unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ - unsigned long check; /* protected copy of check value */ - unsigned long total; /* protected copy of output count */ - /* gz_headerp head; */ /* where to save gzip header information */ - /* sliding window */ - unsigned wbits; /* log base 2 of requested window size */ - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned write; /* window write index */ - unsigned char *window; /* allocated sliding window, if needed */ - /* bit accumulator */ - unsigned long hold; /* input bit accumulator */ - unsigned bits; /* number of bits in "in" */ - /* for string and stored block copying */ - unsigned length; /* literal or length of data to copy */ - unsigned offset; /* distance back to copy string from */ - /* for table and code decoding */ - unsigned extra; /* extra bits needed */ - /* fixed and dynamic code tables */ - code const *lencode; /* starting table for length/literal codes */ - code const *distcode; /* starting table for distance codes */ - unsigned lenbits; /* index bits for lencode */ - unsigned distbits; /* index bits for distcode */ - /* dynamic table building */ - unsigned ncode; /* number of code length code lengths */ - unsigned nlen; /* number of length code lengths */ - unsigned ndist; /* number of distance code lengths */ - unsigned have; /* number of code lengths in lens[] */ - code *next; /* next available space in codes[] */ - unsigned short lens[320]; /* temporary storage for code lengths */ - unsigned short work[288]; /* work area for code table building */ - code codes[ENOUGH]; /* space for code tables */ -}; -#endif diff --git a/src/linux/lib/zlib_inflate/inflate_syms.c b/src/linux/lib/zlib_inflate/inflate_syms.c deleted file mode 100644 index 67329fe..0000000 --- a/src/linux/lib/zlib_inflate/inflate_syms.c +++ /dev/null @@ -1,20 +0,0 @@ -/* - * linux/lib/zlib_inflate/inflate_syms.c - * - * Exported symbols for the inflate functionality. - * - */ - -#include -#include - -#include - -EXPORT_SYMBOL(zlib_inflate_workspacesize); -EXPORT_SYMBOL(zlib_inflate); -EXPORT_SYMBOL(zlib_inflateInit2); -EXPORT_SYMBOL(zlib_inflateEnd); -EXPORT_SYMBOL(zlib_inflateReset); -EXPORT_SYMBOL(zlib_inflateIncomp); -EXPORT_SYMBOL(zlib_inflate_blob); -MODULE_LICENSE("GPL"); diff --git a/src/linux/lib/zlib_inflate/inftrees.c b/src/linux/lib/zlib_inflate/inftrees.c deleted file mode 100644 index 3fe6ce5..0000000 --- a/src/linux/lib/zlib_inflate/inftrees.c +++ /dev/null @@ -1,315 +0,0 @@ -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include -#include "inftrees.h" - -#define MAXBITS 15 - -/* - Build a set of tables to decode the provided canonical Huffman code. - The code lengths are lens[0..codes-1]. The result starts at *table, - whose indices are 0..2^bits-1. work is a writable array of at least - lens shorts, which is used as a work area. type is the type of code - to be generated, CODES, LENS, or DISTS. On return, zero is success, - -1 is an invalid code, and +1 means that ENOUGH isn't enough. table - on return points to the next available entry's address. bits is the - requested root table index bits, and on return it is the actual root - table index bits. It will differ if the request is greater than the - longest code or if it is less than the shortest code. - */ -int zlib_inflate_table(codetype type, unsigned short *lens, unsigned codes, - code **table, unsigned *bits, unsigned short *work) -{ - unsigned len; /* a code's length in bits */ - unsigned sym; /* index of code symbols */ - unsigned min, max; /* minimum and maximum code lengths */ - unsigned root; /* number of index bits for root table */ - unsigned curr; /* number of index bits for current table */ - unsigned drop; /* code bits to drop for sub-table */ - int left; /* number of prefix codes available */ - unsigned used; /* code entries in table used */ - unsigned huff; /* Huffman code */ - unsigned incr; /* for incrementing code, index */ - unsigned fill; /* index for replicating entries */ - unsigned low; /* low bits for current root entry */ - unsigned mask; /* mask for low root bits */ - code this; /* table entry for duplication */ - code *next; /* next available space in table */ - const unsigned short *base; /* base value table to use */ - const unsigned short *extra; /* extra bits table to use */ - int end; /* use base and extra for symbol > end */ - unsigned short count[MAXBITS+1]; /* number of codes of each length */ - unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ - static const unsigned short lbase[31] = { /* Length codes 257..285 base */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - static const unsigned short lext[31] = { /* Length codes 257..285 extra */ - 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 201, 196}; - static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577, 0, 0}; - static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ - 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, - 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, - 28, 28, 29, 29, 64, 64}; - - /* - Process a set of code lengths to create a canonical Huffman code. The - code lengths are lens[0..codes-1]. Each length corresponds to the - symbols 0..codes-1. The Huffman code is generated by first sorting the - symbols by length from short to long, and retaining the symbol order - for codes with equal lengths. Then the code starts with all zero bits - for the first code of the shortest length, and the codes are integer - increments for the same length, and zeros are appended as the length - increases. For the deflate format, these bits are stored backwards - from their more natural integer increment ordering, and so when the - decoding tables are built in the large loop below, the integer codes - are incremented backwards. - - This routine assumes, but does not check, that all of the entries in - lens[] are in the range 0..MAXBITS. The caller must assure this. - 1..MAXBITS is interpreted as that code length. zero means that that - symbol does not occur in this code. - - The codes are sorted by computing a count of codes for each length, - creating from that a table of starting indices for each length in the - sorted table, and then entering the symbols in order in the sorted - table. The sorted table is work[], with that space being provided by - the caller. - - The length counts are used for other purposes as well, i.e. finding - the minimum and maximum length codes, determining if there are any - codes at all, checking for a valid set of lengths, and looking ahead - at length counts to determine sub-table sizes when building the - decoding tables. - */ - - /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ - for (len = 0; len <= MAXBITS; len++) - count[len] = 0; - for (sym = 0; sym < codes; sym++) - count[lens[sym]]++; - - /* bound code lengths, force root to be within code lengths */ - root = *bits; - for (max = MAXBITS; max >= 1; max--) - if (count[max] != 0) break; - if (root > max) root = max; - if (max == 0) { /* no symbols to code at all */ - this.op = (unsigned char)64; /* invalid code marker */ - this.bits = (unsigned char)1; - this.val = (unsigned short)0; - *(*table)++ = this; /* make a table to force an error */ - *(*table)++ = this; - *bits = 1; - return 0; /* no symbols, but wait for decoding to report error */ - } - for (min = 1; min <= MAXBITS; min++) - if (count[min] != 0) break; - if (root < min) root = min; - - /* check for an over-subscribed or incomplete set of lengths */ - left = 1; - for (len = 1; len <= MAXBITS; len++) { - left <<= 1; - left -= count[len]; - if (left < 0) return -1; /* over-subscribed */ - } - if (left > 0 && (type == CODES || max != 1)) - return -1; /* incomplete set */ - - /* generate offsets into symbol table for each length for sorting */ - offs[1] = 0; - for (len = 1; len < MAXBITS; len++) - offs[len + 1] = offs[len] + count[len]; - - /* sort symbols by length, by symbol order within each length */ - for (sym = 0; sym < codes; sym++) - if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; - - /* - Create and fill in decoding tables. In this loop, the table being - filled is at next and has curr index bits. The code being used is huff - with length len. That code is converted to an index by dropping drop - bits off of the bottom. For codes where len is less than drop + curr, - those top drop + curr - len bits are incremented through all values to - fill the table with replicated entries. - - root is the number of index bits for the root table. When len exceeds - root, sub-tables are created pointed to by the root entry with an index - of the low root bits of huff. This is saved in low to check for when a - new sub-table should be started. drop is zero when the root table is - being filled, and drop is root when sub-tables are being filled. - - When a new sub-table is needed, it is necessary to look ahead in the - code lengths to determine what size sub-table is needed. The length - counts are used for this, and so count[] is decremented as codes are - entered in the tables. - - used keeps track of how many table entries have been allocated from the - provided *table space. It is checked when a LENS table is being made - against the space in *table, ENOUGH, minus the maximum space needed by - the worst case distance code, MAXD. This should never happen, but the - sufficiency of ENOUGH has not been proven exhaustively, hence the check. - This assumes that when type == LENS, bits == 9. - - sym increments through all symbols, and the loop terminates when - all codes of length max, i.e. all codes, have been processed. This - routine permits incomplete codes, so another loop after this one fills - in the rest of the decoding tables with invalid code markers. - */ - - /* set up for code type */ - switch (type) { - case CODES: - base = extra = work; /* dummy value--not used */ - end = 19; - break; - case LENS: - base = lbase; - base -= 257; - extra = lext; - extra -= 257; - end = 256; - break; - default: /* DISTS */ - base = dbase; - extra = dext; - end = -1; - } - - /* initialize state for loop */ - huff = 0; /* starting code */ - sym = 0; /* starting code symbol */ - len = min; /* starting code length */ - next = *table; /* current table to fill in */ - curr = root; /* current table index bits */ - drop = 0; /* current bits to drop from code for index */ - low = (unsigned)(-1); /* trigger new sub-table when len > root */ - used = 1U << root; /* use root table entries */ - mask = used - 1; /* mask for comparing low */ - - /* check available table space */ - if (type == LENS && used >= ENOUGH - MAXD) - return 1; - - /* process all codes and make table entries */ - for (;;) { - /* create table entry */ - this.bits = (unsigned char)(len - drop); - if ((int)(work[sym]) < end) { - this.op = (unsigned char)0; - this.val = work[sym]; - } - else if ((int)(work[sym]) > end) { - this.op = (unsigned char)(extra[work[sym]]); - this.val = base[work[sym]]; - } - else { - this.op = (unsigned char)(32 + 64); /* end of block */ - this.val = 0; - } - - /* replicate for those indices with low len bits equal to huff */ - incr = 1U << (len - drop); - fill = 1U << curr; - min = fill; /* save offset to next table */ - do { - fill -= incr; - next[(huff >> drop) + fill] = this; - } while (fill != 0); - - /* backwards increment the len-bit code huff */ - incr = 1U << (len - 1); - while (huff & incr) - incr >>= 1; - if (incr != 0) { - huff &= incr - 1; - huff += incr; - } - else - huff = 0; - - /* go to next symbol, update count, len */ - sym++; - if (--(count[len]) == 0) { - if (len == max) break; - len = lens[work[sym]]; - } - - /* create new sub-table if needed */ - if (len > root && (huff & mask) != low) { - /* if first time, transition to sub-tables */ - if (drop == 0) - drop = root; - - /* increment past last table */ - next += min; /* here min is 1 << curr */ - - /* determine length of next table */ - curr = len - drop; - left = (int)(1 << curr); - while (curr + drop < max) { - left -= count[curr + drop]; - if (left <= 0) break; - curr++; - left <<= 1; - } - - /* check for enough space */ - used += 1U << curr; - if (type == LENS && used >= ENOUGH - MAXD) - return 1; - - /* point entry in root table to sub-table */ - low = huff & mask; - (*table)[low].op = (unsigned char)curr; - (*table)[low].bits = (unsigned char)root; - (*table)[low].val = (unsigned short)(next - *table); - } - } - - /* - Fill in rest of table for incomplete codes. This loop is similar to the - loop above in incrementing huff for table indices. It is assumed that - len is equal to curr + drop, so there is no loop needed to increment - through high index bits. When the current sub-table is filled, the loop - drops back to the root table to fill in any remaining entries there. - */ - this.op = (unsigned char)64; /* invalid code marker */ - this.bits = (unsigned char)(len - drop); - this.val = (unsigned short)0; - while (huff != 0) { - /* when done with sub-table, drop back to root table */ - if (drop != 0 && (huff & mask) != low) { - drop = 0; - len = root; - next = *table; - this.bits = (unsigned char)len; - } - - /* put invalid code marker in table */ - next[huff >> drop] = this; - - /* backwards increment the len-bit code huff */ - incr = 1U << (len - 1); - while (huff & incr) - incr >>= 1; - if (incr != 0) { - huff &= incr - 1; - huff += incr; - } - else - huff = 0; - } - - /* set return parameters */ - *table += used; - *bits = root; - return 0; -} diff --git a/src/linux/lib/zlib_inflate/inftrees.h b/src/linux/lib/zlib_inflate/inftrees.h deleted file mode 100644 index b70b473..0000000 --- a/src/linux/lib/zlib_inflate/inftrees.h +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef INFTREES_H -#define INFTREES_H - -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-2005 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Structure for decoding tables. Each entry provides either the - information needed to do the operation requested by the code that - indexed that table entry, or it provides a pointer to another - table that indexes more bits of the code. op indicates whether - the entry is a pointer to another table, a literal, a length or - distance, an end-of-block, or an invalid code. For a table - pointer, the low four bits of op is the number of index bits of - that table. For a length or distance, the low four bits of op - is the number of extra bits to get after the code. bits is - the number of bits in this code or part of the code to drop off - of the bit buffer. val is the actual byte to output in the case - of a literal, the base length or distance, or the offset from - the current table to the next table. Each entry is four bytes. */ -typedef struct { - unsigned char op; /* operation, extra bits, table bits */ - unsigned char bits; /* bits in this part of the code */ - unsigned short val; /* offset in table or code value */ -} code; - -/* op values as set by inflate_table(): - 00000000 - literal - 0000tttt - table link, tttt != 0 is the number of table index bits - 0001eeee - length or distance, eeee is the number of extra bits - 01100000 - end of block - 01000000 - invalid code - */ - -/* Maximum size of dynamic tree. The maximum found in a long but non- - exhaustive search was 1444 code structures (852 for length/literals - and 592 for distances, the latter actually the result of an - exhaustive search). The true maximum is not known, but the value - below is more than safe. */ -#define ENOUGH 2048 -#define MAXD 592 - -/* Type of code to build for inftable() */ -typedef enum { - CODES, - LENS, - DISTS -} codetype; - -extern int zlib_inflate_table (codetype type, unsigned short *lens, - unsigned codes, code **table, - unsigned *bits, unsigned short *work); -#endif diff --git a/src/linux/lib/zlib_inflate/infutil.c b/src/linux/lib/zlib_inflate/infutil.c deleted file mode 100644 index 4824c2c..0000000 --- a/src/linux/lib/zlib_inflate/infutil.c +++ /dev/null @@ -1,49 +0,0 @@ -#include -#include -#include -#include - -/* Utility function: initialize zlib, unpack binary blob, clean up zlib, - * return len or negative error code. - */ -int zlib_inflate_blob(void *gunzip_buf, unsigned int sz, - const void *buf, unsigned int len) -{ - const u8 *zbuf = buf; - struct z_stream_s *strm; - int rc; - - rc = -ENOMEM; - strm = kmalloc(sizeof(*strm), GFP_KERNEL); - if (strm == NULL) - goto gunzip_nomem1; - strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL); - if (strm->workspace == NULL) - goto gunzip_nomem2; - - /* gzip header (1f,8b,08... 10 bytes total + possible asciz filename) - * expected to be stripped from input - */ - strm->next_in = zbuf; - strm->avail_in = len; - strm->next_out = gunzip_buf; - strm->avail_out = sz; - - rc = zlib_inflateInit2(strm, -MAX_WBITS); - if (rc == Z_OK) { - rc = zlib_inflate(strm, Z_FINISH); - /* after Z_FINISH, only Z_STREAM_END is "we unpacked it all" */ - if (rc == Z_STREAM_END) - rc = sz - strm->avail_out; - else - rc = -EINVAL; - zlib_inflateEnd(strm); - } else - rc = -EINVAL; - - kfree(strm->workspace); -gunzip_nomem2: - kfree(strm); -gunzip_nomem1: - return rc; /* returns Z_OK (0) if successful */ -} diff --git a/src/linux/lib/zlib_inflate/infutil.h b/src/linux/lib/zlib_inflate/infutil.h deleted file mode 100644 index eb1a900..0000000 --- a/src/linux/lib/zlib_inflate/infutil.h +++ /dev/null @@ -1,25 +0,0 @@ -/* infutil.h -- types and macros common to blocks and codes - * Copyright (C) 1995-1998 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -#ifndef _INFUTIL_H -#define _INFUTIL_H - -#include - -/* memory allocation for inflation */ - -struct inflate_workspace { - struct inflate_state inflate_state; - unsigned char working_window[1 << MAX_WBITS]; -}; - -#define WS(z) ((struct inflate_workspace *)(z->workspace)) - -#endif diff --git a/src/linux/mm/Kconfig b/src/linux/mm/Kconfig deleted file mode 100644 index 86e3e0e..0000000 --- a/src/linux/mm/Kconfig +++ /dev/null @@ -1,713 +0,0 @@ -config SELECT_MEMORY_MODEL - def_bool y - depends on ARCH_SELECT_MEMORY_MODEL - -choice - prompt "Memory model" - depends on SELECT_MEMORY_MODEL - default DISCONTIGMEM_MANUAL if ARCH_DISCONTIGMEM_DEFAULT - default SPARSEMEM_MANUAL if ARCH_SPARSEMEM_DEFAULT - default FLATMEM_MANUAL - -config FLATMEM_MANUAL - bool "Flat Memory" - depends on !(ARCH_DISCONTIGMEM_ENABLE || ARCH_SPARSEMEM_ENABLE) || ARCH_FLATMEM_ENABLE - help - This option allows you to change some of the ways that - Linux manages its memory internally. Most users will - only have one option here: FLATMEM. This is normal - and a correct option. - - Some users of more advanced features like NUMA and - memory hotplug may have different options here. - DISCONTIGMEM is a more mature, better tested system, - but is incompatible with memory hotplug and may suffer - decreased performance over SPARSEMEM. If unsure between - "Sparse Memory" and "Discontiguous Memory", choose - "Discontiguous Memory". - - If unsure, choose this option (Flat Memory) over any other. - -config DISCONTIGMEM_MANUAL - bool "Discontiguous Memory" - depends on ARCH_DISCONTIGMEM_ENABLE - help - This option provides enhanced support for discontiguous - memory systems, over FLATMEM. These systems have holes - in their physical address spaces, and this option provides - more efficient handling of these holes. However, the vast - majority of hardware has quite flat address spaces, and - can have degraded performance from the extra overhead that - this option imposes. - - Many NUMA configurations will have this as the only option. - - If unsure, choose "Flat Memory" over this option. - -config SPARSEMEM_MANUAL - bool "Sparse Memory" - depends on ARCH_SPARSEMEM_ENABLE - help - This will be the only option for some systems, including - memory hotplug systems. This is normal. - - For many other systems, this will be an alternative to - "Discontiguous Memory". This option provides some potential - performance benefits, along with decreased code complexity, - but it is newer, and more experimental. - - If unsure, choose "Discontiguous Memory" or "Flat Memory" - over this option. - -endchoice - -config DISCONTIGMEM - def_bool y - depends on (!SELECT_MEMORY_MODEL && ARCH_DISCONTIGMEM_ENABLE) || DISCONTIGMEM_MANUAL - -config SPARSEMEM - def_bool y - depends on (!SELECT_MEMORY_MODEL && ARCH_SPARSEMEM_ENABLE) || SPARSEMEM_MANUAL - -config FLATMEM - def_bool y - depends on (!DISCONTIGMEM && !SPARSEMEM) || FLATMEM_MANUAL - -config FLAT_NODE_MEM_MAP - def_bool y - depends on !SPARSEMEM - -# -# Both the NUMA code and DISCONTIGMEM use arrays of pg_data_t's -# to represent different areas of memory. This variable allows -# those dependencies to exist individually. -# -config NEED_MULTIPLE_NODES - def_bool y - depends on DISCONTIGMEM || NUMA - -config HAVE_MEMORY_PRESENT - def_bool y - depends on ARCH_HAVE_MEMORY_PRESENT || SPARSEMEM - -# -# SPARSEMEM_EXTREME (which is the default) does some bootmem -# allocations when memory_present() is called. If this cannot -# be done on your architecture, select this option. However, -# statically allocating the mem_section[] array can potentially -# consume vast quantities of .bss, so be careful. -# -# This option will also potentially produce smaller runtime code -# with gcc 3.4 and later. -# -config SPARSEMEM_STATIC - bool - -# -# Architecture platforms which require a two level mem_section in SPARSEMEM -# must select this option. This is usually for architecture platforms with -# an extremely sparse physical address space. -# -config SPARSEMEM_EXTREME - def_bool y - depends on SPARSEMEM && !SPARSEMEM_STATIC - -config SPARSEMEM_VMEMMAP_ENABLE - bool - -config SPARSEMEM_ALLOC_MEM_MAP_TOGETHER - def_bool y - depends on SPARSEMEM && X86_64 - -config SPARSEMEM_VMEMMAP - bool "Sparse Memory virtual memmap" - depends on SPARSEMEM && SPARSEMEM_VMEMMAP_ENABLE - default y - help - SPARSEMEM_VMEMMAP uses a virtually mapped memmap to optimise - pfn_to_page and page_to_pfn operations. This is the most - efficient option when sufficient kernel resources are available. - -config HAVE_MEMBLOCK - bool - -config HAVE_MEMBLOCK_NODE_MAP - bool - -config HAVE_MEMBLOCK_PHYS_MAP - bool - -config HAVE_GENERIC_RCU_GUP - bool - -config ARCH_DISCARD_MEMBLOCK - bool - -config NO_BOOTMEM - bool - -config MEMORY_ISOLATION - bool - -config MOVABLE_NODE - bool "Enable to assign a node which has only movable memory" - depends on HAVE_MEMBLOCK - depends on NO_BOOTMEM - depends on X86_64 - depends on NUMA - default n - help - Allow a node to have only movable memory. Pages used by the kernel, - such as direct mapping pages cannot be migrated. So the corresponding - memory device cannot be hotplugged. This option allows the following - two things: - - When the system is booting, node full of hotpluggable memory can - be arranged to have only movable memory so that the whole node can - be hot-removed. (need movable_node boot option specified). - - After the system is up, the option allows users to online all the - memory of a node as movable memory so that the whole node can be - hot-removed. - - Users who don't use the memory hotplug feature are fine with this - option on since they don't specify movable_node boot option or they - don't online memory as movable. - - Say Y here if you want to hotplug a whole node. - Say N here if you want kernel to use memory on all nodes evenly. - -# -# Only be set on architectures that have completely implemented memory hotplug -# feature. If you are not sure, don't touch it. -# -config HAVE_BOOTMEM_INFO_NODE - def_bool n - -# eventually, we can have this option just 'select SPARSEMEM' -config MEMORY_HOTPLUG - bool "Allow for memory hot-add" - depends on SPARSEMEM || X86_64_ACPI_NUMA - depends on ARCH_ENABLE_MEMORY_HOTPLUG - depends on COMPILE_TEST || !KASAN - -config MEMORY_HOTPLUG_SPARSE - def_bool y - depends on SPARSEMEM && MEMORY_HOTPLUG - -config MEMORY_HOTPLUG_DEFAULT_ONLINE - bool "Online the newly added memory blocks by default" - default n - depends on MEMORY_HOTPLUG - help - This option sets the default policy setting for memory hotplug - onlining policy (/sys/devices/system/memory/auto_online_blocks) which - determines what happens to newly added memory regions. Policy setting - can always be changed at runtime. - See Documentation/memory-hotplug.txt for more information. - - Say Y here if you want all hot-plugged memory blocks to appear in - 'online' state by default. - Say N here if you want the default policy to keep all hot-plugged - memory blocks in 'offline' state. - -config MEMORY_HOTREMOVE - bool "Allow for memory hot remove" - select MEMORY_ISOLATION - select HAVE_BOOTMEM_INFO_NODE if (X86_64 || PPC64) - depends on MEMORY_HOTPLUG && ARCH_ENABLE_MEMORY_HOTREMOVE - depends on MIGRATION - -# Heavily threaded applications may benefit from splitting the mm-wide -# page_table_lock, so that faults on different parts of the user address -# space can be handled with less contention: split it at this NR_CPUS. -# Default to 4 for wider testing, though 8 might be more appropriate. -# ARM's adjust_pte (unused if VIPT) depends on mm-wide page_table_lock. -# PA-RISC 7xxx's spinlock_t would enlarge struct page from 32 to 44 bytes. -# DEBUG_SPINLOCK and DEBUG_LOCK_ALLOC spinlock_t also enlarge struct page. -# -config SPLIT_PTLOCK_CPUS - int - default "999999" if !MMU - default "999999" if ARM && !CPU_CACHE_VIPT - default "999999" if PARISC && !PA20 - default "4" - -config ARCH_ENABLE_SPLIT_PMD_PTLOCK - bool - -# -# support for memory balloon -config MEMORY_BALLOON - bool - -# -# support for memory balloon compaction -config BALLOON_COMPACTION - bool "Allow for balloon memory compaction/migration" - def_bool y - depends on COMPACTION && MEMORY_BALLOON - help - Memory fragmentation introduced by ballooning might reduce - significantly the number of 2MB contiguous memory blocks that can be - used within a guest, thus imposing performance penalties associated - with the reduced number of transparent huge pages that could be used - by the guest workload. Allowing the compaction & migration for memory - pages enlisted as being part of memory balloon devices avoids the - scenario aforementioned and helps improving memory defragmentation. - -# -# support for memory compaction -config COMPACTION - bool "Allow for memory compaction" - def_bool y - select MIGRATION - depends on MMU - help - Compaction is the only memory management component to form - high order (larger physically contiguous) memory blocks - reliably. The page allocator relies on compaction heavily and - the lack of the feature can lead to unexpected OOM killer - invocations for high order memory requests. You shouldn't - disable this option unless there really is a strong reason for - it and then we would be really interested to hear about that at - linux-mm@kvack.org. - -# -# support for page migration -# -config MIGRATION - bool "Page migration" - def_bool y - depends on (NUMA || ARCH_ENABLE_MEMORY_HOTREMOVE || COMPACTION || CMA) && MMU - help - Allows the migration of the physical location of pages of processes - while the virtual addresses are not changed. This is useful in - two situations. The first is on NUMA systems to put pages nearer - to the processors accessing. The second is when allocating huge - pages as migration can relocate pages to satisfy a huge page - allocation instead of reclaiming. - -config ARCH_ENABLE_HUGEPAGE_MIGRATION - bool - -config PHYS_ADDR_T_64BIT - def_bool 64BIT || ARCH_PHYS_ADDR_T_64BIT - -config BOUNCE - bool "Enable bounce buffers" - default y - depends on BLOCK && MMU && (ZONE_DMA || HIGHMEM) - help - Enable bounce buffers for devices that cannot access - the full range of memory available to the CPU. Enabled - by default when ZONE_DMA or HIGHMEM is selected, but you - may say n to override this. - -# On the 'tile' arch, USB OHCI needs the bounce pool since tilegx will often -# have more than 4GB of memory, but we don't currently use the IOTLB to present -# a 32-bit address to OHCI. So we need to use a bounce pool instead. -config NEED_BOUNCE_POOL - bool - default y if TILE && USB_OHCI_HCD - -config NR_QUICK - int - depends on QUICKLIST - default "2" if AVR32 - default "1" - -config VIRT_TO_BUS - bool - help - An architecture should select this if it implements the - deprecated interface virt_to_bus(). All new architectures - should probably not select this. - - -config MMU_NOTIFIER - bool - select SRCU - -config KSM - bool "Enable KSM for page merging" - depends on MMU - help - Enable Kernel Samepage Merging: KSM periodically scans those areas - of an application's address space that an app has advised may be - mergeable. When it finds pages of identical content, it replaces - the many instances by a single page with that content, so - saving memory until one or another app needs to modify the content. - Recommended for use with KVM, or with other duplicative applications. - See Documentation/vm/ksm.txt for more information: KSM is inactive - until a program has madvised that an area is MADV_MERGEABLE, and - root has set /sys/kernel/mm/ksm/run to 1 (if CONFIG_SYSFS is set). - -config DEFAULT_MMAP_MIN_ADDR - int "Low address space to protect from user allocation" - depends on MMU - default 4096 - help - This is the portion of low virtual memory which should be protected - from userspace allocation. Keeping a user from writing to low pages - can help reduce the impact of kernel NULL pointer bugs. - - For most ia64, ppc64 and x86 users with lots of address space - a value of 65536 is reasonable and should cause no problems. - On arm and other archs it should not be higher than 32768. - Programs which use vm86 functionality or have some need to map - this low address space will need CAP_SYS_RAWIO or disable this - protection by setting the value to 0. - - This value can be changed after boot using the - /proc/sys/vm/mmap_min_addr tunable. - -config ARCH_SUPPORTS_MEMORY_FAILURE - bool - -config MEMORY_FAILURE - depends on MMU - depends on ARCH_SUPPORTS_MEMORY_FAILURE - bool "Enable recovery from hardware memory errors" - select MEMORY_ISOLATION - select RAS - help - Enables code to recover from some memory failures on systems - with MCA recovery. This allows a system to continue running - even when some of its memory has uncorrected errors. This requires - special hardware support and typically ECC memory. - -config HWPOISON_INJECT - tristate "HWPoison pages injector" - depends on MEMORY_FAILURE && DEBUG_KERNEL && PROC_FS - select PROC_PAGE_MONITOR - -config NOMMU_INITIAL_TRIM_EXCESS - int "Turn on mmap() excess space trimming before booting" - depends on !MMU - default 1 - help - The NOMMU mmap() frequently needs to allocate large contiguous chunks - of memory on which to store mappings, but it can only ask the system - allocator for chunks in 2^N*PAGE_SIZE amounts - which is frequently - more than it requires. To deal with this, mmap() is able to trim off - the excess and return it to the allocator. - - If trimming is enabled, the excess is trimmed off and returned to the - system allocator, which can cause extra fragmentation, particularly - if there are a lot of transient processes. - - If trimming is disabled, the excess is kept, but not used, which for - long-term mappings means that the space is wasted. - - Trimming can be dynamically controlled through a sysctl option - (/proc/sys/vm/nr_trim_pages) which specifies the minimum number of - excess pages there must be before trimming should occur, or zero if - no trimming is to occur. - - This option specifies the initial value of this option. The default - of 1 says that all excess pages should be trimmed. - - See Documentation/nommu-mmap.txt for more information. - -config TRANSPARENT_HUGEPAGE - bool "Transparent Hugepage Support" - depends on HAVE_ARCH_TRANSPARENT_HUGEPAGE - select COMPACTION - select RADIX_TREE_MULTIORDER - help - Transparent Hugepages allows the kernel to use huge pages and - huge tlb transparently to the applications whenever possible. - This feature can improve computing performance to certain - applications by speeding up page faults during memory - allocation, by reducing the number of tlb misses and by speeding - up the pagetable walking. - - If memory constrained on embedded, you may want to say N. - -choice - prompt "Transparent Hugepage Support sysfs defaults" - depends on TRANSPARENT_HUGEPAGE - default TRANSPARENT_HUGEPAGE_ALWAYS - help - Selects the sysfs defaults for Transparent Hugepage Support. - - config TRANSPARENT_HUGEPAGE_ALWAYS - bool "always" - help - Enabling Transparent Hugepage always, can increase the - memory footprint of applications without a guaranteed - benefit but it will work automatically for all applications. - - config TRANSPARENT_HUGEPAGE_MADVISE - bool "madvise" - help - Enabling Transparent Hugepage madvise, will only provide a - performance improvement benefit to the applications using - madvise(MADV_HUGEPAGE) but it won't risk to increase the - memory footprint of applications without a guaranteed - benefit. -endchoice - -# -# We don't deposit page tables on file THP mapping, -# but Power makes use of them to address MMU quirk. -# -config TRANSPARENT_HUGE_PAGECACHE - def_bool y - depends on TRANSPARENT_HUGEPAGE && !PPC - -# -# UP and nommu archs use km based percpu allocator -# -config NEED_PER_CPU_KM - depends on !SMP - bool - default y - -config CLEANCACHE - bool "Enable cleancache driver to cache clean pages if tmem is present" - default n - help - Cleancache can be thought of as a page-granularity victim cache - for clean pages that the kernel's pageframe replacement algorithm - (PFRA) would like to keep around, but can't since there isn't enough - memory. So when the PFRA "evicts" a page, it first attempts to use - cleancache code to put the data contained in that page into - "transcendent memory", memory that is not directly accessible or - addressable by the kernel and is of unknown and possibly - time-varying size. And when a cleancache-enabled - filesystem wishes to access a page in a file on disk, it first - checks cleancache to see if it already contains it; if it does, - the page is copied into the kernel and a disk access is avoided. - When a transcendent memory driver is available (such as zcache or - Xen transcendent memory), a significant I/O reduction - may be achieved. When none is available, all cleancache calls - are reduced to a single pointer-compare-against-NULL resulting - in a negligible performance hit. - - If unsure, say Y to enable cleancache - -config FRONTSWAP - bool "Enable frontswap to cache swap pages if tmem is present" - depends on SWAP - default n - help - Frontswap is so named because it can be thought of as the opposite - of a "backing" store for a swap device. The data is stored into - "transcendent memory", memory that is not directly accessible or - addressable by the kernel and is of unknown and possibly - time-varying size. When space in transcendent memory is available, - a significant swap I/O reduction may be achieved. When none is - available, all frontswap calls are reduced to a single pointer- - compare-against-NULL resulting in a negligible performance hit - and swap data is stored as normal on the matching swap device. - - If unsure, say Y to enable frontswap. - -config CMA - bool "Contiguous Memory Allocator" - depends on HAVE_MEMBLOCK && MMU - select MIGRATION - select MEMORY_ISOLATION - help - This enables the Contiguous Memory Allocator which allows other - subsystems to allocate big physically-contiguous blocks of memory. - CMA reserves a region of memory and allows only movable pages to - be allocated from it. This way, the kernel can use the memory for - pagecache and when a subsystem requests for contiguous area, the - allocated pages are migrated away to serve the contiguous request. - - If unsure, say "n". - -config CMA_DEBUG - bool "CMA debug messages (DEVELOPMENT)" - depends on DEBUG_KERNEL && CMA - help - Turns on debug messages in CMA. This produces KERN_DEBUG - messages for every CMA call as well as various messages while - processing calls such as dma_alloc_from_contiguous(). - This option does not affect warning and error messages. - -config CMA_DEBUGFS - bool "CMA debugfs interface" - depends on CMA && DEBUG_FS - help - Turns on the DebugFS interface for CMA. - -config CMA_AREAS - int "Maximum count of the CMA areas" - depends on CMA - default 7 - help - CMA allows to create CMA areas for particular purpose, mainly, - used as device private area. This parameter sets the maximum - number of CMA area in the system. - - If unsure, leave the default value "7". - -config MEM_SOFT_DIRTY - bool "Track memory changes" - depends on CHECKPOINT_RESTORE && HAVE_ARCH_SOFT_DIRTY && PROC_FS - select PROC_PAGE_MONITOR - help - This option enables memory changes tracking by introducing a - soft-dirty bit on pte-s. This bit it set when someone writes - into a page just as regular dirty bit, but unlike the latter - it can be cleared by hands. - - See Documentation/vm/soft-dirty.txt for more details. - -config ZSWAP - bool "Compressed cache for swap pages (EXPERIMENTAL)" - depends on FRONTSWAP && CRYPTO=y - select CRYPTO_LZO - select ZPOOL - default n - help - A lightweight compressed cache for swap pages. It takes - pages that are in the process of being swapped out and attempts to - compress them into a dynamically allocated RAM-based memory pool. - This can result in a significant I/O reduction on swap device and, - in the case where decompressing from RAM is faster that swap device - reads, can also improve workload performance. - - This is marked experimental because it is a new feature (as of - v3.11) that interacts heavily with memory reclaim. While these - interactions don't cause any known issues on simple memory setups, - they have not be fully explored on the large set of potential - configurations and workloads that exist. - -config ZPOOL - tristate "Common API for compressed memory storage" - default n - help - Compressed memory storage API. This allows using either zbud or - zsmalloc. - -config ZBUD - tristate "Low (Up to 2x) density storage for compressed pages" - default n - help - A special purpose allocator for storing compressed pages. - It is designed to store up to two compressed pages per physical - page. While this design limits storage density, it has simple and - deterministic reclaim properties that make it preferable to a higher - density approach when reclaim will be used. - -config Z3FOLD - tristate "Up to 3x density storage for compressed pages" - depends on ZPOOL - default n - help - A special purpose allocator for storing compressed pages. - It is designed to store up to three compressed pages per physical - page. It is a ZBUD derivative so the simplicity and determinism are - still there. - -config ZSMALLOC - tristate "Memory allocator for compressed pages" - depends on MMU - default n - help - zsmalloc is a slab-based memory allocator designed to store - compressed RAM pages. zsmalloc uses virtual memory mapping - in order to reduce fragmentation. However, this results in a - non-standard allocator interface where a handle, not a pointer, is - returned by an alloc(). This handle must be mapped in order to - access the allocated space. - -config PGTABLE_MAPPING - bool "Use page table mapping to access object in zsmalloc" - depends on ZSMALLOC - help - By default, zsmalloc uses a copy-based object mapping method to - access allocations that span two pages. However, if a particular - architecture (ex, ARM) performs VM mapping faster than copying, - then you should select this. This causes zsmalloc to use page table - mapping rather than copying for object mapping. - - You can check speed with zsmalloc benchmark: - https://github.com/spartacus06/zsmapbench - -config ZSMALLOC_STAT - bool "Export zsmalloc statistics" - depends on ZSMALLOC - select DEBUG_FS - help - This option enables code in the zsmalloc to collect various - statistics about whats happening in zsmalloc and exports that - information to userspace via debugfs. - If unsure, say N. - -config GENERIC_EARLY_IOREMAP - bool - -config MAX_STACK_SIZE_MB - int "Maximum user stack size for 32-bit processes (MB)" - default 80 - range 8 256 if METAG - range 8 2048 - depends on STACK_GROWSUP && (!64BIT || COMPAT) - help - This is the maximum stack size in Megabytes in the VM layout of 32-bit - user processes when the stack grows upwards (currently only on parisc - and metag arch). The stack will be located at the highest memory - address minus the given value, unless the RLIMIT_STACK hard limit is - changed to a smaller value in which case that is used. - - A sane initial value is 80 MB. - -# For architectures that support deferred memory initialisation -config ARCH_SUPPORTS_DEFERRED_STRUCT_PAGE_INIT - bool - -config DEFERRED_STRUCT_PAGE_INIT - bool "Defer initialisation of struct pages to kthreads" - default n - depends on ARCH_SUPPORTS_DEFERRED_STRUCT_PAGE_INIT - depends on NO_BOOTMEM && MEMORY_HOTPLUG - depends on !FLATMEM - help - Ordinarily all struct pages are initialised during early boot in a - single thread. On very large machines this can take a considerable - amount of time. If this option is set, large machines will bring up - a subset of memmap at boot and then initialise the rest in parallel - by starting one-off "pgdatinitX" kernel thread for each node X. This - has a potential performance impact on processes running early in the - lifetime of the system until these kthreads finish the - initialisation. - -config IDLE_PAGE_TRACKING - bool "Enable idle page tracking" - depends on SYSFS && MMU - select PAGE_EXTENSION if !64BIT - help - This feature allows to estimate the amount of user pages that have - not been touched during a given period of time. This information can - be useful to tune memory cgroup limits and/or for job placement - within a compute cluster. - - See Documentation/vm/idle_page_tracking.txt for more details. - -config ZONE_DEVICE - bool "Device memory (pmem, etc...) hotplug support" - depends on MEMORY_HOTPLUG - depends on MEMORY_HOTREMOVE - depends on SPARSEMEM_VMEMMAP - depends on X86_64 #arch_add_memory() comprehends device memory - - help - Device memory hotplug support allows for establishing pmem, - or other device driver discovered memory regions, in the - memmap. This allows pfn_to_page() lookups of otherwise - "device-physical" addresses which is needed for using a DAX - mapping in an O_DIRECT operation, among other things. - - If FS_DAX is enabled, then say Y. - -config FRAME_VECTOR - bool - -config ARCH_USES_HIGH_VMA_FLAGS - bool -config ARCH_HAS_PKEYS - bool diff --git a/src/linux/mm/Kconfig.debug b/src/linux/mm/Kconfig.debug deleted file mode 100644 index afcc550..0000000 --- a/src/linux/mm/Kconfig.debug +++ /dev/null @@ -1,92 +0,0 @@ -config PAGE_EXTENSION - bool "Extend memmap on extra space for more information on page" - ---help--- - Extend memmap on extra space for more information on page. This - could be used for debugging features that need to insert extra - field for every page. This extension enables us to save memory - by not allocating this extra memory according to boottime - configuration. - -config DEBUG_PAGEALLOC - bool "Debug page memory allocations" - depends on DEBUG_KERNEL - depends on !HIBERNATION || ARCH_SUPPORTS_DEBUG_PAGEALLOC && !PPC && !SPARC - depends on !KMEMCHECK - select PAGE_EXTENSION - select PAGE_POISONING if !ARCH_SUPPORTS_DEBUG_PAGEALLOC - ---help--- - Unmap pages from the kernel linear mapping after free_pages(). - Depending on runtime enablement, this results in a small or large - slowdown, but helps to find certain types of memory corruption. - - For architectures which don't enable ARCH_SUPPORTS_DEBUG_PAGEALLOC, - fill the pages with poison patterns after free_pages() and verify - the patterns before alloc_pages(). Additionally, - this option cannot be enabled in combination with hibernation as - that would result in incorrect warnings of memory corruption after - a resume because free pages are not saved to the suspend image. - - By default this option will have a small overhead, e.g. by not - allowing the kernel mapping to be backed by large pages on some - architectures. Even bigger overhead comes when the debugging is - enabled by DEBUG_PAGEALLOC_ENABLE_DEFAULT or the debug_pagealloc - command line parameter. - -config DEBUG_PAGEALLOC_ENABLE_DEFAULT - bool "Enable debug page memory allocations by default?" - default n - depends on DEBUG_PAGEALLOC - ---help--- - Enable debug page memory allocations by default? This value - can be overridden by debug_pagealloc=off|on. - -config PAGE_POISONING - bool "Poison pages after freeing" - select PAGE_EXTENSION - select PAGE_POISONING_NO_SANITY if HIBERNATION - ---help--- - Fill the pages with poison patterns after free_pages() and verify - the patterns before alloc_pages. The filling of the memory helps - reduce the risk of information leaks from freed data. This does - have a potential performance impact. - - Note that "poison" here is not the same thing as the "HWPoison" - for CONFIG_MEMORY_FAILURE. This is software poisoning only. - - If unsure, say N - -config PAGE_POISONING_NO_SANITY - depends on PAGE_POISONING - bool "Only poison, don't sanity check" - ---help--- - Skip the sanity checking on alloc, only fill the pages with - poison on free. This reduces some of the overhead of the - poisoning feature. - - If you are only interested in sanitization, say Y. Otherwise - say N. - -config PAGE_POISONING_ZERO - bool "Use zero for poisoning instead of random data" - depends on PAGE_POISONING - ---help--- - Instead of using the existing poison value, fill the pages with - zeros. This makes it harder to detect when errors are occurring - due to sanitization but the zeroing at free means that it is - no longer necessary to write zeros when GFP_ZERO is used on - allocation. - - If unsure, say N - bool - -config DEBUG_PAGE_REF - bool "Enable tracepoint to track down page reference manipulation" - depends on DEBUG_KERNEL - depends on TRACEPOINTS - ---help--- - This is a feature to add tracepoint for tracking down page reference - manipulation. This tracking is useful to diagnose functional failure - due to migration failures caused by page reference mismatches. Be - careful when enabling this feature because it adds about 30 KB to the - kernel code. However the runtime performance overhead is virtually - nil until the tracepoints are actually enabled. diff --git a/src/linux/mm/Makefile b/src/linux/mm/Makefile deleted file mode 100644 index 295bd7a..0000000 --- a/src/linux/mm/Makefile +++ /dev/null @@ -1,102 +0,0 @@ -# -# Makefile for the linux memory manager. -# - -KASAN_SANITIZE_slab_common.o := n -KASAN_SANITIZE_slab.o := n -KASAN_SANITIZE_slub.o := n - -# These files are disabled because they produce non-interesting and/or -# flaky coverage that is not a function of syscall inputs. E.g. slab is out of -# free pages, or a task is migrated between nodes. -KCOV_INSTRUMENT_slab_common.o := n -KCOV_INSTRUMENT_slob.o := n -KCOV_INSTRUMENT_slab.o := n -KCOV_INSTRUMENT_slub.o := n -KCOV_INSTRUMENT_page_alloc.o := n -KCOV_INSTRUMENT_debug-pagealloc.o := n -KCOV_INSTRUMENT_kmemleak.o := n -KCOV_INSTRUMENT_kmemcheck.o := n -KCOV_INSTRUMENT_memcontrol.o := n -KCOV_INSTRUMENT_mmzone.o := n -KCOV_INSTRUMENT_vmstat.o := n - -mmu-y := nommu.o -mmu-$(CONFIG_MMU) := gup.o highmem.o memory.o mincore.o \ - mlock.o mmap.o mprotect.o mremap.o msync.o rmap.o \ - vmalloc.o pagewalk.o pgtable-generic.o - -ifdef CONFIG_CROSS_MEMORY_ATTACH -mmu-$(CONFIG_MMU) += process_vm_access.o -endif - -obj-y := filemap.o mempool.o oom_kill.o \ - maccess.o page_alloc.o page-writeback.o \ - readahead.o swap.o truncate.o vmscan.o shmem.o \ - util.o mmzone.o vmstat.o backing-dev.o \ - mm_init.o mmu_context.o percpu.o slab_common.o \ - compaction.o vmacache.o \ - interval_tree.o list_lru.o workingset.o \ - debug.o $(mmu-y) - -obj-y += init-mm.o - -ifdef CONFIG_NO_BOOTMEM - obj-y += nobootmem.o -else - obj-y += bootmem.o -endif - -obj-$(CONFIG_ADVISE_SYSCALLS) += fadvise.o -ifdef CONFIG_MMU - obj-$(CONFIG_ADVISE_SYSCALLS) += madvise.o -endif -obj-$(CONFIG_HAVE_MEMBLOCK) += memblock.o - -obj-$(CONFIG_SWAP) += page_io.o swap_state.o swapfile.o -obj-$(CONFIG_FRONTSWAP) += frontswap.o -obj-$(CONFIG_ZSWAP) += zswap.o -obj-$(CONFIG_HAS_DMA) += dmapool.o -obj-$(CONFIG_HUGETLBFS) += hugetlb.o -obj-$(CONFIG_NUMA) += mempolicy.o -obj-$(CONFIG_SPARSEMEM) += sparse.o -obj-$(CONFIG_SPARSEMEM_VMEMMAP) += sparse-vmemmap.o -obj-$(CONFIG_SLOB) += slob.o -obj-$(CONFIG_MMU_NOTIFIER) += mmu_notifier.o -obj-$(CONFIG_KSM) += ksm.o -obj-$(CONFIG_PAGE_POISONING) += page_poison.o -obj-$(CONFIG_SLAB) += slab.o -obj-$(CONFIG_SLUB) += slub.o -obj-$(CONFIG_KMEMCHECK) += kmemcheck.o -obj-$(CONFIG_KASAN) += kasan/ -obj-$(CONFIG_FAILSLAB) += failslab.o -obj-$(CONFIG_MEMORY_HOTPLUG) += memory_hotplug.o -obj-$(CONFIG_MEMTEST) += memtest.o -obj-$(CONFIG_MIGRATION) += migrate.o -obj-$(CONFIG_QUICKLIST) += quicklist.o -obj-$(CONFIG_TRANSPARENT_HUGEPAGE) += huge_memory.o khugepaged.o -obj-$(CONFIG_PAGE_COUNTER) += page_counter.o -obj-$(CONFIG_MEMCG) += memcontrol.o vmpressure.o -obj-$(CONFIG_MEMCG_SWAP) += swap_cgroup.o -obj-$(CONFIG_CGROUP_HUGETLB) += hugetlb_cgroup.o -obj-$(CONFIG_MEMORY_FAILURE) += memory-failure.o -obj-$(CONFIG_HWPOISON_INJECT) += hwpoison-inject.o -obj-$(CONFIG_DEBUG_KMEMLEAK) += kmemleak.o -obj-$(CONFIG_DEBUG_KMEMLEAK_TEST) += kmemleak-test.o -obj-$(CONFIG_PAGE_OWNER) += page_owner.o -obj-$(CONFIG_CLEANCACHE) += cleancache.o -obj-$(CONFIG_MEMORY_ISOLATION) += page_isolation.o -obj-$(CONFIG_ZPOOL) += zpool.o -obj-$(CONFIG_ZBUD) += zbud.o -obj-$(CONFIG_ZSMALLOC) += zsmalloc.o -obj-$(CONFIG_Z3FOLD) += z3fold.o -obj-$(CONFIG_GENERIC_EARLY_IOREMAP) += early_ioremap.o -obj-$(CONFIG_CMA) += cma.o -obj-$(CONFIG_MEMORY_BALLOON) += balloon_compaction.o -obj-$(CONFIG_PAGE_EXTENSION) += page_ext.o -obj-$(CONFIG_CMA_DEBUGFS) += cma_debug.o -obj-$(CONFIG_USERFAULTFD) += userfaultfd.o -obj-$(CONFIG_IDLE_PAGE_TRACKING) += page_idle.o -obj-$(CONFIG_FRAME_VECTOR) += frame_vector.o -obj-$(CONFIG_DEBUG_PAGE_REF) += debug_page_ref.o -obj-$(CONFIG_HARDENED_USERCOPY) += usercopy.o diff --git a/src/linux/mm/backing-dev.c b/src/linux/mm/backing-dev.c deleted file mode 100644 index 8fde443..0000000 --- a/src/linux/mm/backing-dev.c +++ /dev/null @@ -1,1041 +0,0 @@ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static atomic_long_t bdi_seq = ATOMIC_LONG_INIT(0); - -struct backing_dev_info noop_backing_dev_info = { - .name = "noop", - .capabilities = BDI_CAP_NO_ACCT_AND_WRITEBACK, -}; -EXPORT_SYMBOL_GPL(noop_backing_dev_info); - -static struct class *bdi_class; - -/* - * bdi_lock protects updates to bdi_list. bdi_list has RCU reader side - * locking. - */ -DEFINE_SPINLOCK(bdi_lock); -LIST_HEAD(bdi_list); - -/* bdi_wq serves all asynchronous writeback tasks */ -struct workqueue_struct *bdi_wq; - -#ifdef CONFIG_DEBUG_FS -#include -#include - -static struct dentry *bdi_debug_root; - -static void bdi_debug_init(void) -{ - bdi_debug_root = debugfs_create_dir("bdi", NULL); -} - -static int bdi_debug_stats_show(struct seq_file *m, void *v) -{ - struct backing_dev_info *bdi = m->private; - struct bdi_writeback *wb = &bdi->wb; - unsigned long background_thresh; - unsigned long dirty_thresh; - unsigned long wb_thresh; - unsigned long nr_dirty, nr_io, nr_more_io, nr_dirty_time; - struct inode *inode; - - nr_dirty = nr_io = nr_more_io = nr_dirty_time = 0; - spin_lock(&wb->list_lock); - list_for_each_entry(inode, &wb->b_dirty, i_io_list) - nr_dirty++; - list_for_each_entry(inode, &wb->b_io, i_io_list) - nr_io++; - list_for_each_entry(inode, &wb->b_more_io, i_io_list) - nr_more_io++; - list_for_each_entry(inode, &wb->b_dirty_time, i_io_list) - if (inode->i_state & I_DIRTY_TIME) - nr_dirty_time++; - spin_unlock(&wb->list_lock); - - global_dirty_limits(&background_thresh, &dirty_thresh); - wb_thresh = wb_calc_thresh(wb, dirty_thresh); - -#define K(x) ((x) << (PAGE_SHIFT - 10)) - seq_printf(m, - "BdiWriteback: %10lu kB\n" - "BdiReclaimable: %10lu kB\n" - "BdiDirtyThresh: %10lu kB\n" - "DirtyThresh: %10lu kB\n" - "BackgroundThresh: %10lu kB\n" - "BdiDirtied: %10lu kB\n" - "BdiWritten: %10lu kB\n" - "BdiWriteBandwidth: %10lu kBps\n" - "b_dirty: %10lu\n" - "b_io: %10lu\n" - "b_more_io: %10lu\n" - "b_dirty_time: %10lu\n" - "bdi_list: %10u\n" - "state: %10lx\n", - (unsigned long) K(wb_stat(wb, WB_WRITEBACK)), - (unsigned long) K(wb_stat(wb, WB_RECLAIMABLE)), - K(wb_thresh), - K(dirty_thresh), - K(background_thresh), - (unsigned long) K(wb_stat(wb, WB_DIRTIED)), - (unsigned long) K(wb_stat(wb, WB_WRITTEN)), - (unsigned long) K(wb->write_bandwidth), - nr_dirty, - nr_io, - nr_more_io, - nr_dirty_time, - !list_empty(&bdi->bdi_list), bdi->wb.state); -#undef K - - return 0; -} - -static int bdi_debug_stats_open(struct inode *inode, struct file *file) -{ - return single_open(file, bdi_debug_stats_show, inode->i_private); -} - -static const struct file_operations bdi_debug_stats_fops = { - .open = bdi_debug_stats_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static void bdi_debug_register(struct backing_dev_info *bdi, const char *name) -{ - bdi->debug_dir = debugfs_create_dir(name, bdi_debug_root); - bdi->debug_stats = debugfs_create_file("stats", 0444, bdi->debug_dir, - bdi, &bdi_debug_stats_fops); -} - -static void bdi_debug_unregister(struct backing_dev_info *bdi) -{ - debugfs_remove(bdi->debug_stats); - debugfs_remove(bdi->debug_dir); -} -#else -static inline void bdi_debug_init(void) -{ -} -static inline void bdi_debug_register(struct backing_dev_info *bdi, - const char *name) -{ -} -static inline void bdi_debug_unregister(struct backing_dev_info *bdi) -{ -} -#endif - -static ssize_t read_ahead_kb_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct backing_dev_info *bdi = dev_get_drvdata(dev); - unsigned long read_ahead_kb; - ssize_t ret; - - ret = kstrtoul(buf, 10, &read_ahead_kb); - if (ret < 0) - return ret; - - bdi->ra_pages = read_ahead_kb >> (PAGE_SHIFT - 10); - - return count; -} - -#define K(pages) ((pages) << (PAGE_SHIFT - 10)) - -#define BDI_SHOW(name, expr) \ -static ssize_t name##_show(struct device *dev, \ - struct device_attribute *attr, char *page) \ -{ \ - struct backing_dev_info *bdi = dev_get_drvdata(dev); \ - \ - return snprintf(page, PAGE_SIZE-1, "%lld\n", (long long)expr); \ -} \ -static DEVICE_ATTR_RW(name); - -BDI_SHOW(read_ahead_kb, K(bdi->ra_pages)) - -static ssize_t min_ratio_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct backing_dev_info *bdi = dev_get_drvdata(dev); - unsigned int ratio; - ssize_t ret; - - ret = kstrtouint(buf, 10, &ratio); - if (ret < 0) - return ret; - - ret = bdi_set_min_ratio(bdi, ratio); - if (!ret) - ret = count; - - return ret; -} -BDI_SHOW(min_ratio, bdi->min_ratio) - -static ssize_t max_ratio_store(struct device *dev, - struct device_attribute *attr, const char *buf, size_t count) -{ - struct backing_dev_info *bdi = dev_get_drvdata(dev); - unsigned int ratio; - ssize_t ret; - - ret = kstrtouint(buf, 10, &ratio); - if (ret < 0) - return ret; - - ret = bdi_set_max_ratio(bdi, ratio); - if (!ret) - ret = count; - - return ret; -} -BDI_SHOW(max_ratio, bdi->max_ratio) - -static ssize_t stable_pages_required_show(struct device *dev, - struct device_attribute *attr, - char *page) -{ - struct backing_dev_info *bdi = dev_get_drvdata(dev); - - return snprintf(page, PAGE_SIZE-1, "%d\n", - bdi_cap_stable_pages_required(bdi) ? 1 : 0); -} -static DEVICE_ATTR_RO(stable_pages_required); - -static struct attribute *bdi_dev_attrs[] = { - &dev_attr_read_ahead_kb.attr, - &dev_attr_min_ratio.attr, - &dev_attr_max_ratio.attr, - &dev_attr_stable_pages_required.attr, - NULL, -}; -ATTRIBUTE_GROUPS(bdi_dev); - -static __init int bdi_class_init(void) -{ - bdi_class = class_create(THIS_MODULE, "bdi"); - if (IS_ERR(bdi_class)) - return PTR_ERR(bdi_class); - - bdi_class->dev_groups = bdi_dev_groups; - bdi_debug_init(); - return 0; -} -postcore_initcall(bdi_class_init); - -static int __init default_bdi_init(void) -{ - int err; - - bdi_wq = alloc_workqueue("writeback", WQ_MEM_RECLAIM | WQ_FREEZABLE | - WQ_UNBOUND | WQ_SYSFS, 0); - if (!bdi_wq) - return -ENOMEM; - - err = bdi_init(&noop_backing_dev_info); - - return err; -} -subsys_initcall(default_bdi_init); - -/* - * This function is used when the first inode for this wb is marked dirty. It - * wakes-up the corresponding bdi thread which should then take care of the - * periodic background write-out of dirty inodes. Since the write-out would - * starts only 'dirty_writeback_interval' centisecs from now anyway, we just - * set up a timer which wakes the bdi thread up later. - * - * Note, we wouldn't bother setting up the timer, but this function is on the - * fast-path (used by '__mark_inode_dirty()'), so we save few context switches - * by delaying the wake-up. - * - * We have to be careful not to postpone flush work if it is scheduled for - * earlier. Thus we use queue_delayed_work(). - */ -void wb_wakeup_delayed(struct bdi_writeback *wb) -{ - unsigned long timeout; - - timeout = msecs_to_jiffies(dirty_writeback_interval * 10); - spin_lock_bh(&wb->work_lock); - if (test_bit(WB_registered, &wb->state)) - queue_delayed_work(bdi_wq, &wb->dwork, timeout); - spin_unlock_bh(&wb->work_lock); -} - -/* - * Initial write bandwidth: 100 MB/s - */ -#define INIT_BW (100 << (20 - PAGE_SHIFT)) - -static int wb_init(struct bdi_writeback *wb, struct backing_dev_info *bdi, - int blkcg_id, gfp_t gfp) -{ - int i, err; - - memset(wb, 0, sizeof(*wb)); - - wb->bdi = bdi; - wb->last_old_flush = jiffies; - INIT_LIST_HEAD(&wb->b_dirty); - INIT_LIST_HEAD(&wb->b_io); - INIT_LIST_HEAD(&wb->b_more_io); - INIT_LIST_HEAD(&wb->b_dirty_time); - spin_lock_init(&wb->list_lock); - - wb->bw_time_stamp = jiffies; - wb->balanced_dirty_ratelimit = INIT_BW; - wb->dirty_ratelimit = INIT_BW; - wb->write_bandwidth = INIT_BW; - wb->avg_write_bandwidth = INIT_BW; - - spin_lock_init(&wb->work_lock); - INIT_LIST_HEAD(&wb->work_list); - INIT_DELAYED_WORK(&wb->dwork, wb_workfn); - - wb->congested = wb_congested_get_create(bdi, blkcg_id, gfp); - if (!wb->congested) - return -ENOMEM; - - err = fprop_local_init_percpu(&wb->completions, gfp); - if (err) - goto out_put_cong; - - for (i = 0; i < NR_WB_STAT_ITEMS; i++) { - err = percpu_counter_init(&wb->stat[i], 0, gfp); - if (err) - goto out_destroy_stat; - } - - return 0; - -out_destroy_stat: - while (i--) - percpu_counter_destroy(&wb->stat[i]); - fprop_local_destroy_percpu(&wb->completions); -out_put_cong: - wb_congested_put(wb->congested); - return err; -} - -/* - * Remove bdi from the global list and shutdown any threads we have running - */ -static void wb_shutdown(struct bdi_writeback *wb) -{ - /* Make sure nobody queues further work */ - spin_lock_bh(&wb->work_lock); - if (!test_and_clear_bit(WB_registered, &wb->state)) { - spin_unlock_bh(&wb->work_lock); - return; - } - spin_unlock_bh(&wb->work_lock); - - /* - * Drain work list and shutdown the delayed_work. !WB_registered - * tells wb_workfn() that @wb is dying and its work_list needs to - * be drained no matter what. - */ - mod_delayed_work(bdi_wq, &wb->dwork, 0); - flush_delayed_work(&wb->dwork); - WARN_ON(!list_empty(&wb->work_list)); -} - -static void wb_exit(struct bdi_writeback *wb) -{ - int i; - - WARN_ON(delayed_work_pending(&wb->dwork)); - - for (i = 0; i < NR_WB_STAT_ITEMS; i++) - percpu_counter_destroy(&wb->stat[i]); - - fprop_local_destroy_percpu(&wb->completions); - wb_congested_put(wb->congested); -} - -#ifdef CONFIG_CGROUP_WRITEBACK - -#include - -/* - * cgwb_lock protects bdi->cgwb_tree, bdi->cgwb_congested_tree, - * blkcg->cgwb_list, and memcg->cgwb_list. bdi->cgwb_tree is also RCU - * protected. cgwb_release_wait is used to wait for the completion of cgwb - * releases from bdi destruction path. - */ -static DEFINE_SPINLOCK(cgwb_lock); -static DECLARE_WAIT_QUEUE_HEAD(cgwb_release_wait); - -/** - * wb_congested_get_create - get or create a wb_congested - * @bdi: associated bdi - * @blkcg_id: ID of the associated blkcg - * @gfp: allocation mask - * - * Look up the wb_congested for @blkcg_id on @bdi. If missing, create one. - * The returned wb_congested has its reference count incremented. Returns - * NULL on failure. - */ -struct bdi_writeback_congested * -wb_congested_get_create(struct backing_dev_info *bdi, int blkcg_id, gfp_t gfp) -{ - struct bdi_writeback_congested *new_congested = NULL, *congested; - struct rb_node **node, *parent; - unsigned long flags; -retry: - spin_lock_irqsave(&cgwb_lock, flags); - - node = &bdi->cgwb_congested_tree.rb_node; - parent = NULL; - - while (*node != NULL) { - parent = *node; - congested = container_of(parent, struct bdi_writeback_congested, - rb_node); - if (congested->blkcg_id < blkcg_id) - node = &parent->rb_left; - else if (congested->blkcg_id > blkcg_id) - node = &parent->rb_right; - else - goto found; - } - - if (new_congested) { - /* !found and storage for new one already allocated, insert */ - congested = new_congested; - new_congested = NULL; - rb_link_node(&congested->rb_node, parent, node); - rb_insert_color(&congested->rb_node, &bdi->cgwb_congested_tree); - goto found; - } - - spin_unlock_irqrestore(&cgwb_lock, flags); - - /* allocate storage for new one and retry */ - new_congested = kzalloc(sizeof(*new_congested), gfp); - if (!new_congested) - return NULL; - - atomic_set(&new_congested->refcnt, 0); - new_congested->bdi = bdi; - new_congested->blkcg_id = blkcg_id; - goto retry; - -found: - atomic_inc(&congested->refcnt); - spin_unlock_irqrestore(&cgwb_lock, flags); - kfree(new_congested); - return congested; -} - -/** - * wb_congested_put - put a wb_congested - * @congested: wb_congested to put - * - * Put @congested and destroy it if the refcnt reaches zero. - */ -void wb_congested_put(struct bdi_writeback_congested *congested) -{ - unsigned long flags; - - local_irq_save(flags); - if (!atomic_dec_and_lock(&congested->refcnt, &cgwb_lock)) { - local_irq_restore(flags); - return; - } - - /* bdi might already have been destroyed leaving @congested unlinked */ - if (congested->bdi) { - rb_erase(&congested->rb_node, - &congested->bdi->cgwb_congested_tree); - congested->bdi = NULL; - } - - spin_unlock_irqrestore(&cgwb_lock, flags); - kfree(congested); -} - -static void cgwb_release_workfn(struct work_struct *work) -{ - struct bdi_writeback *wb = container_of(work, struct bdi_writeback, - release_work); - struct backing_dev_info *bdi = wb->bdi; - - spin_lock_irq(&cgwb_lock); - list_del_rcu(&wb->bdi_node); - spin_unlock_irq(&cgwb_lock); - - wb_shutdown(wb); - - css_put(wb->memcg_css); - css_put(wb->blkcg_css); - - fprop_local_destroy_percpu(&wb->memcg_completions); - percpu_ref_exit(&wb->refcnt); - wb_exit(wb); - kfree_rcu(wb, rcu); - - if (atomic_dec_and_test(&bdi->usage_cnt)) - wake_up_all(&cgwb_release_wait); -} - -static void cgwb_release(struct percpu_ref *refcnt) -{ - struct bdi_writeback *wb = container_of(refcnt, struct bdi_writeback, - refcnt); - schedule_work(&wb->release_work); -} - -static void cgwb_kill(struct bdi_writeback *wb) -{ - lockdep_assert_held(&cgwb_lock); - - WARN_ON(!radix_tree_delete(&wb->bdi->cgwb_tree, wb->memcg_css->id)); - list_del(&wb->memcg_node); - list_del(&wb->blkcg_node); - percpu_ref_kill(&wb->refcnt); -} - -static int cgwb_create(struct backing_dev_info *bdi, - struct cgroup_subsys_state *memcg_css, gfp_t gfp) -{ - struct mem_cgroup *memcg; - struct cgroup_subsys_state *blkcg_css; - struct blkcg *blkcg; - struct list_head *memcg_cgwb_list, *blkcg_cgwb_list; - struct bdi_writeback *wb; - unsigned long flags; - int ret = 0; - - memcg = mem_cgroup_from_css(memcg_css); - blkcg_css = cgroup_get_e_css(memcg_css->cgroup, &io_cgrp_subsys); - blkcg = css_to_blkcg(blkcg_css); - memcg_cgwb_list = mem_cgroup_cgwb_list(memcg); - blkcg_cgwb_list = &blkcg->cgwb_list; - - /* look up again under lock and discard on blkcg mismatch */ - spin_lock_irqsave(&cgwb_lock, flags); - wb = radix_tree_lookup(&bdi->cgwb_tree, memcg_css->id); - if (wb && wb->blkcg_css != blkcg_css) { - cgwb_kill(wb); - wb = NULL; - } - spin_unlock_irqrestore(&cgwb_lock, flags); - if (wb) - goto out_put; - - /* need to create a new one */ - wb = kmalloc(sizeof(*wb), gfp); - if (!wb) - return -ENOMEM; - - ret = wb_init(wb, bdi, blkcg_css->id, gfp); - if (ret) - goto err_free; - - ret = percpu_ref_init(&wb->refcnt, cgwb_release, 0, gfp); - if (ret) - goto err_wb_exit; - - ret = fprop_local_init_percpu(&wb->memcg_completions, gfp); - if (ret) - goto err_ref_exit; - - wb->memcg_css = memcg_css; - wb->blkcg_css = blkcg_css; - INIT_WORK(&wb->release_work, cgwb_release_workfn); - set_bit(WB_registered, &wb->state); - - /* - * The root wb determines the registered state of the whole bdi and - * memcg_cgwb_list and blkcg_cgwb_list's next pointers indicate - * whether they're still online. Don't link @wb if any is dead. - * See wb_memcg_offline() and wb_blkcg_offline(). - */ - ret = -ENODEV; - spin_lock_irqsave(&cgwb_lock, flags); - if (test_bit(WB_registered, &bdi->wb.state) && - blkcg_cgwb_list->next && memcg_cgwb_list->next) { - /* we might have raced another instance of this function */ - ret = radix_tree_insert(&bdi->cgwb_tree, memcg_css->id, wb); - if (!ret) { - atomic_inc(&bdi->usage_cnt); - list_add_tail_rcu(&wb->bdi_node, &bdi->wb_list); - list_add(&wb->memcg_node, memcg_cgwb_list); - list_add(&wb->blkcg_node, blkcg_cgwb_list); - css_get(memcg_css); - css_get(blkcg_css); - } - } - spin_unlock_irqrestore(&cgwb_lock, flags); - if (ret) { - if (ret == -EEXIST) - ret = 0; - goto err_fprop_exit; - } - goto out_put; - -err_fprop_exit: - fprop_local_destroy_percpu(&wb->memcg_completions); -err_ref_exit: - percpu_ref_exit(&wb->refcnt); -err_wb_exit: - wb_exit(wb); -err_free: - kfree(wb); -out_put: - css_put(blkcg_css); - return ret; -} - -/** - * wb_get_create - get wb for a given memcg, create if necessary - * @bdi: target bdi - * @memcg_css: cgroup_subsys_state of the target memcg (must have positive ref) - * @gfp: allocation mask to use - * - * Try to get the wb for @memcg_css on @bdi. If it doesn't exist, try to - * create one. The returned wb has its refcount incremented. - * - * This function uses css_get() on @memcg_css and thus expects its refcnt - * to be positive on invocation. IOW, rcu_read_lock() protection on - * @memcg_css isn't enough. try_get it before calling this function. - * - * A wb is keyed by its associated memcg. As blkcg implicitly enables - * memcg on the default hierarchy, memcg association is guaranteed to be - * more specific (equal or descendant to the associated blkcg) and thus can - * identify both the memcg and blkcg associations. - * - * Because the blkcg associated with a memcg may change as blkcg is enabled - * and disabled closer to root in the hierarchy, each wb keeps track of - * both the memcg and blkcg associated with it and verifies the blkcg on - * each lookup. On mismatch, the existing wb is discarded and a new one is - * created. - */ -struct bdi_writeback *wb_get_create(struct backing_dev_info *bdi, - struct cgroup_subsys_state *memcg_css, - gfp_t gfp) -{ - struct bdi_writeback *wb; - - might_sleep_if(gfpflags_allow_blocking(gfp)); - - if (!memcg_css->parent) - return &bdi->wb; - - do { - rcu_read_lock(); - wb = radix_tree_lookup(&bdi->cgwb_tree, memcg_css->id); - if (wb) { - struct cgroup_subsys_state *blkcg_css; - - /* see whether the blkcg association has changed */ - blkcg_css = cgroup_get_e_css(memcg_css->cgroup, - &io_cgrp_subsys); - if (unlikely(wb->blkcg_css != blkcg_css || - !wb_tryget(wb))) - wb = NULL; - css_put(blkcg_css); - } - rcu_read_unlock(); - } while (!wb && !cgwb_create(bdi, memcg_css, gfp)); - - return wb; -} - -static int cgwb_bdi_init(struct backing_dev_info *bdi) -{ - int ret; - - INIT_RADIX_TREE(&bdi->cgwb_tree, GFP_ATOMIC); - bdi->cgwb_congested_tree = RB_ROOT; - atomic_set(&bdi->usage_cnt, 1); - - ret = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL); - if (!ret) { - bdi->wb.memcg_css = &root_mem_cgroup->css; - bdi->wb.blkcg_css = blkcg_root_css; - } - return ret; -} - -static void cgwb_bdi_destroy(struct backing_dev_info *bdi) -{ - struct radix_tree_iter iter; - struct rb_node *rbn; - void **slot; - - WARN_ON(test_bit(WB_registered, &bdi->wb.state)); - - spin_lock_irq(&cgwb_lock); - - radix_tree_for_each_slot(slot, &bdi->cgwb_tree, &iter, 0) - cgwb_kill(*slot); - - while ((rbn = rb_first(&bdi->cgwb_congested_tree))) { - struct bdi_writeback_congested *congested = - rb_entry(rbn, struct bdi_writeback_congested, rb_node); - - rb_erase(rbn, &bdi->cgwb_congested_tree); - congested->bdi = NULL; /* mark @congested unlinked */ - } - - spin_unlock_irq(&cgwb_lock); - - /* - * All cgwb's and their congested states must be shutdown and - * released before returning. Drain the usage counter to wait for - * all cgwb's and cgwb_congested's ever created on @bdi. - */ - atomic_dec(&bdi->usage_cnt); - wait_event(cgwb_release_wait, !atomic_read(&bdi->usage_cnt)); -} - -/** - * wb_memcg_offline - kill all wb's associated with a memcg being offlined - * @memcg: memcg being offlined - * - * Also prevents creation of any new wb's associated with @memcg. - */ -void wb_memcg_offline(struct mem_cgroup *memcg) -{ - LIST_HEAD(to_destroy); - struct list_head *memcg_cgwb_list = mem_cgroup_cgwb_list(memcg); - struct bdi_writeback *wb, *next; - - spin_lock_irq(&cgwb_lock); - list_for_each_entry_safe(wb, next, memcg_cgwb_list, memcg_node) - cgwb_kill(wb); - memcg_cgwb_list->next = NULL; /* prevent new wb's */ - spin_unlock_irq(&cgwb_lock); -} - -/** - * wb_blkcg_offline - kill all wb's associated with a blkcg being offlined - * @blkcg: blkcg being offlined - * - * Also prevents creation of any new wb's associated with @blkcg. - */ -void wb_blkcg_offline(struct blkcg *blkcg) -{ - LIST_HEAD(to_destroy); - struct bdi_writeback *wb, *next; - - spin_lock_irq(&cgwb_lock); - list_for_each_entry_safe(wb, next, &blkcg->cgwb_list, blkcg_node) - cgwb_kill(wb); - blkcg->cgwb_list.next = NULL; /* prevent new wb's */ - spin_unlock_irq(&cgwb_lock); -} - -#else /* CONFIG_CGROUP_WRITEBACK */ - -static int cgwb_bdi_init(struct backing_dev_info *bdi) -{ - int err; - - bdi->wb_congested = kzalloc(sizeof(*bdi->wb_congested), GFP_KERNEL); - if (!bdi->wb_congested) - return -ENOMEM; - - err = wb_init(&bdi->wb, bdi, 1, GFP_KERNEL); - if (err) { - kfree(bdi->wb_congested); - return err; - } - return 0; -} - -static void cgwb_bdi_destroy(struct backing_dev_info *bdi) { } - -#endif /* CONFIG_CGROUP_WRITEBACK */ - -int bdi_init(struct backing_dev_info *bdi) -{ - int ret; - - bdi->dev = NULL; - - bdi->min_ratio = 0; - bdi->max_ratio = 100; - bdi->max_prop_frac = FPROP_FRAC_BASE; - INIT_LIST_HEAD(&bdi->bdi_list); - INIT_LIST_HEAD(&bdi->wb_list); - init_waitqueue_head(&bdi->wb_waitq); - - ret = cgwb_bdi_init(bdi); - - list_add_tail_rcu(&bdi->wb.bdi_node, &bdi->wb_list); - - return ret; -} -EXPORT_SYMBOL(bdi_init); - -int bdi_register(struct backing_dev_info *bdi, struct device *parent, - const char *fmt, ...) -{ - va_list args; - struct device *dev; - - if (bdi->dev) /* The driver needs to use separate queues per device */ - return 0; - - va_start(args, fmt); - dev = device_create_vargs(bdi_class, parent, MKDEV(0, 0), bdi, fmt, args); - va_end(args); - if (IS_ERR(dev)) - return PTR_ERR(dev); - - bdi->dev = dev; - - bdi_debug_register(bdi, dev_name(dev)); - set_bit(WB_registered, &bdi->wb.state); - - spin_lock_bh(&bdi_lock); - list_add_tail_rcu(&bdi->bdi_list, &bdi_list); - spin_unlock_bh(&bdi_lock); - - trace_writeback_bdi_register(bdi); - return 0; -} -EXPORT_SYMBOL(bdi_register); - -int bdi_register_dev(struct backing_dev_info *bdi, dev_t dev) -{ - return bdi_register(bdi, NULL, "%u:%u", MAJOR(dev), MINOR(dev)); -} -EXPORT_SYMBOL(bdi_register_dev); - -int bdi_register_owner(struct backing_dev_info *bdi, struct device *owner) -{ - int rc; - - rc = bdi_register(bdi, NULL, "%u:%u", MAJOR(owner->devt), - MINOR(owner->devt)); - if (rc) - return rc; - bdi->owner = owner; - get_device(owner); - return 0; -} -EXPORT_SYMBOL(bdi_register_owner); - -/* - * Remove bdi from bdi_list, and ensure that it is no longer visible - */ -static void bdi_remove_from_list(struct backing_dev_info *bdi) -{ - spin_lock_bh(&bdi_lock); - list_del_rcu(&bdi->bdi_list); - spin_unlock_bh(&bdi_lock); - - synchronize_rcu_expedited(); -} - -void bdi_unregister(struct backing_dev_info *bdi) -{ - /* make sure nobody finds us on the bdi_list anymore */ - bdi_remove_from_list(bdi); - wb_shutdown(&bdi->wb); - cgwb_bdi_destroy(bdi); - - if (bdi->dev) { - bdi_debug_unregister(bdi); - device_unregister(bdi->dev); - bdi->dev = NULL; - } - - if (bdi->owner) { - put_device(bdi->owner); - bdi->owner = NULL; - } -} - -void bdi_exit(struct backing_dev_info *bdi) -{ - WARN_ON_ONCE(bdi->dev); - wb_exit(&bdi->wb); -} - -void bdi_destroy(struct backing_dev_info *bdi) -{ - bdi_unregister(bdi); - bdi_exit(bdi); -} -EXPORT_SYMBOL(bdi_destroy); - -/* - * For use from filesystems to quickly init and register a bdi associated - * with dirty writeback - */ -int bdi_setup_and_register(struct backing_dev_info *bdi, char *name) -{ - int err; - - bdi->name = name; - bdi->capabilities = 0; - err = bdi_init(bdi); - if (err) - return err; - - err = bdi_register(bdi, NULL, "%.28s-%ld", name, - atomic_long_inc_return(&bdi_seq)); - if (err) { - bdi_destroy(bdi); - return err; - } - - return 0; -} -EXPORT_SYMBOL(bdi_setup_and_register); - -static wait_queue_head_t congestion_wqh[2] = { - __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[0]), - __WAIT_QUEUE_HEAD_INITIALIZER(congestion_wqh[1]) - }; -static atomic_t nr_wb_congested[2]; - -void clear_wb_congested(struct bdi_writeback_congested *congested, int sync) -{ - wait_queue_head_t *wqh = &congestion_wqh[sync]; - enum wb_congested_state bit; - - bit = sync ? WB_sync_congested : WB_async_congested; - if (test_and_clear_bit(bit, &congested->state)) - atomic_dec(&nr_wb_congested[sync]); - smp_mb__after_atomic(); - if (waitqueue_active(wqh)) - wake_up(wqh); -} -EXPORT_SYMBOL(clear_wb_congested); - -void set_wb_congested(struct bdi_writeback_congested *congested, int sync) -{ - enum wb_congested_state bit; - - bit = sync ? WB_sync_congested : WB_async_congested; - if (!test_and_set_bit(bit, &congested->state)) - atomic_inc(&nr_wb_congested[sync]); -} -EXPORT_SYMBOL(set_wb_congested); - -/** - * congestion_wait - wait for a backing_dev to become uncongested - * @sync: SYNC or ASYNC IO - * @timeout: timeout in jiffies - * - * Waits for up to @timeout jiffies for a backing_dev (any backing_dev) to exit - * write congestion. If no backing_devs are congested then just wait for the - * next write to be completed. - */ -long congestion_wait(int sync, long timeout) -{ - long ret; - unsigned long start = jiffies; - DEFINE_WAIT(wait); - wait_queue_head_t *wqh = &congestion_wqh[sync]; - - prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE); - ret = io_schedule_timeout(timeout); - finish_wait(wqh, &wait); - - trace_writeback_congestion_wait(jiffies_to_usecs(timeout), - jiffies_to_usecs(jiffies - start)); - - return ret; -} -EXPORT_SYMBOL(congestion_wait); - -/** - * wait_iff_congested - Conditionally wait for a backing_dev to become uncongested or a pgdat to complete writes - * @pgdat: A pgdat to check if it is heavily congested - * @sync: SYNC or ASYNC IO - * @timeout: timeout in jiffies - * - * In the event of a congested backing_dev (any backing_dev) and the given - * @pgdat has experienced recent congestion, this waits for up to @timeout - * jiffies for either a BDI to exit congestion of the given @sync queue - * or a write to complete. - * - * In the absence of pgdat congestion, cond_resched() is called to yield - * the processor if necessary but otherwise does not sleep. - * - * The return value is 0 if the sleep is for the full timeout. Otherwise, - * it is the number of jiffies that were still remaining when the function - * returned. return_value == timeout implies the function did not sleep. - */ -long wait_iff_congested(struct pglist_data *pgdat, int sync, long timeout) -{ - long ret; - unsigned long start = jiffies; - DEFINE_WAIT(wait); - wait_queue_head_t *wqh = &congestion_wqh[sync]; - - /* - * If there is no congestion, or heavy congestion is not being - * encountered in the current pgdat, yield if necessary instead - * of sleeping on the congestion queue - */ - if (atomic_read(&nr_wb_congested[sync]) == 0 || - !test_bit(PGDAT_CONGESTED, &pgdat->flags)) { - cond_resched(); - - /* In case we scheduled, work out time remaining */ - ret = timeout - (jiffies - start); - if (ret < 0) - ret = 0; - - goto out; - } - - /* Sleep until uncongested or a write happens */ - prepare_to_wait(wqh, &wait, TASK_UNINTERRUPTIBLE); - ret = io_schedule_timeout(timeout); - finish_wait(wqh, &wait); - -out: - trace_writeback_wait_iff_congested(jiffies_to_usecs(timeout), - jiffies_to_usecs(jiffies - start)); - - return ret; -} -EXPORT_SYMBOL(wait_iff_congested); - -int pdflush_proc_obsolete(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - char kbuf[] = "0\n"; - - if (*ppos || *lenp < sizeof(kbuf)) { - *lenp = 0; - return 0; - } - - if (copy_to_user(buffer, kbuf, sizeof(kbuf))) - return -EFAULT; - pr_warn_once("%s exported in /proc is scheduled for removal\n", - table->procname); - - *lenp = 2; - *ppos += *lenp; - return 2; -} diff --git a/src/linux/mm/bootmem.c b/src/linux/mm/bootmem.c deleted file mode 100644 index e8a55a3..0000000 --- a/src/linux/mm/bootmem.c +++ /dev/null @@ -1,859 +0,0 @@ -/* - * bootmem - A boot-time physical memory allocator and configurator - * - * Copyright (C) 1999 Ingo Molnar - * 1999 Kanoj Sarcar, SGI - * 2008 Johannes Weiner - * - * Access to this subsystem has to be serialized externally (which is true - * for the boot process anyway). - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -#ifndef CONFIG_NEED_MULTIPLE_NODES -struct pglist_data __refdata contig_page_data = { - .bdata = &bootmem_node_data[0] -}; -EXPORT_SYMBOL(contig_page_data); -#endif - -unsigned long max_low_pfn; -unsigned long min_low_pfn; -unsigned long max_pfn; -unsigned long long max_possible_pfn; - -bootmem_data_t bootmem_node_data[MAX_NUMNODES] __initdata; - -static struct list_head bdata_list __initdata = LIST_HEAD_INIT(bdata_list); - -static int bootmem_debug; - -static int __init bootmem_debug_setup(char *buf) -{ - bootmem_debug = 1; - return 0; -} -early_param("bootmem_debug", bootmem_debug_setup); - -#define bdebug(fmt, args...) ({ \ - if (unlikely(bootmem_debug)) \ - pr_info("bootmem::%s " fmt, \ - __func__, ## args); \ -}) - -static unsigned long __init bootmap_bytes(unsigned long pages) -{ - unsigned long bytes = DIV_ROUND_UP(pages, 8); - - return ALIGN(bytes, sizeof(long)); -} - -/** - * bootmem_bootmap_pages - calculate bitmap size in pages - * @pages: number of pages the bitmap has to represent - */ -unsigned long __init bootmem_bootmap_pages(unsigned long pages) -{ - unsigned long bytes = bootmap_bytes(pages); - - return PAGE_ALIGN(bytes) >> PAGE_SHIFT; -} - -/* - * link bdata in order - */ -static void __init link_bootmem(bootmem_data_t *bdata) -{ - bootmem_data_t *ent; - - list_for_each_entry(ent, &bdata_list, list) { - if (bdata->node_min_pfn < ent->node_min_pfn) { - list_add_tail(&bdata->list, &ent->list); - return; - } - } - - list_add_tail(&bdata->list, &bdata_list); -} - -/* - * Called once to set up the allocator itself. - */ -static unsigned long __init init_bootmem_core(bootmem_data_t *bdata, - unsigned long mapstart, unsigned long start, unsigned long end) -{ - unsigned long mapsize; - - mminit_validate_memmodel_limits(&start, &end); - bdata->node_bootmem_map = phys_to_virt(PFN_PHYS(mapstart)); - bdata->node_min_pfn = start; - bdata->node_low_pfn = end; - link_bootmem(bdata); - - /* - * Initially all pages are reserved - setup_arch() has to - * register free RAM areas explicitly. - */ - mapsize = bootmap_bytes(end - start); - memset(bdata->node_bootmem_map, 0xff, mapsize); - - bdebug("nid=%td start=%lx map=%lx end=%lx mapsize=%lx\n", - bdata - bootmem_node_data, start, mapstart, end, mapsize); - - return mapsize; -} - -/** - * init_bootmem_node - register a node as boot memory - * @pgdat: node to register - * @freepfn: pfn where the bitmap for this node is to be placed - * @startpfn: first pfn on the node - * @endpfn: first pfn after the node - * - * Returns the number of bytes needed to hold the bitmap for this node. - */ -unsigned long __init init_bootmem_node(pg_data_t *pgdat, unsigned long freepfn, - unsigned long startpfn, unsigned long endpfn) -{ - return init_bootmem_core(pgdat->bdata, freepfn, startpfn, endpfn); -} - -/** - * init_bootmem - register boot memory - * @start: pfn where the bitmap is to be placed - * @pages: number of available physical pages - * - * Returns the number of bytes needed to hold the bitmap. - */ -unsigned long __init init_bootmem(unsigned long start, unsigned long pages) -{ - max_low_pfn = pages; - min_low_pfn = start; - return init_bootmem_core(NODE_DATA(0)->bdata, start, 0, pages); -} - -/* - * free_bootmem_late - free bootmem pages directly to page allocator - * @addr: starting physical address of the range - * @size: size of the range in bytes - * - * This is only useful when the bootmem allocator has already been torn - * down, but we are still initializing the system. Pages are given directly - * to the page allocator, no bootmem metadata is updated because it is gone. - */ -void __init free_bootmem_late(unsigned long physaddr, unsigned long size) -{ - unsigned long cursor, end; - - kmemleak_free_part_phys(physaddr, size); - - cursor = PFN_UP(physaddr); - end = PFN_DOWN(physaddr + size); - - for (; cursor < end; cursor++) { - __free_pages_bootmem(pfn_to_page(cursor), cursor, 0); - totalram_pages++; - } -} - -static unsigned long __init free_all_bootmem_core(bootmem_data_t *bdata) -{ - struct page *page; - unsigned long *map, start, end, pages, cur, count = 0; - - if (!bdata->node_bootmem_map) - return 0; - - map = bdata->node_bootmem_map; - start = bdata->node_min_pfn; - end = bdata->node_low_pfn; - - bdebug("nid=%td start=%lx end=%lx\n", - bdata - bootmem_node_data, start, end); - - while (start < end) { - unsigned long idx, vec; - unsigned shift; - - idx = start - bdata->node_min_pfn; - shift = idx & (BITS_PER_LONG - 1); - /* - * vec holds at most BITS_PER_LONG map bits, - * bit 0 corresponds to start. - */ - vec = ~map[idx / BITS_PER_LONG]; - - if (shift) { - vec >>= shift; - if (end - start >= BITS_PER_LONG) - vec |= ~map[idx / BITS_PER_LONG + 1] << - (BITS_PER_LONG - shift); - } - /* - * If we have a properly aligned and fully unreserved - * BITS_PER_LONG block of pages in front of us, free - * it in one go. - */ - if (IS_ALIGNED(start, BITS_PER_LONG) && vec == ~0UL) { - int order = ilog2(BITS_PER_LONG); - - __free_pages_bootmem(pfn_to_page(start), start, order); - count += BITS_PER_LONG; - start += BITS_PER_LONG; - } else { - cur = start; - - start = ALIGN(start + 1, BITS_PER_LONG); - while (vec && cur != start) { - if (vec & 1) { - page = pfn_to_page(cur); - __free_pages_bootmem(page, cur, 0); - count++; - } - vec >>= 1; - ++cur; - } - } - } - - cur = bdata->node_min_pfn; - page = virt_to_page(bdata->node_bootmem_map); - pages = bdata->node_low_pfn - bdata->node_min_pfn; - pages = bootmem_bootmap_pages(pages); - count += pages; - while (pages--) - __free_pages_bootmem(page++, cur++, 0); - bdata->node_bootmem_map = NULL; - - bdebug("nid=%td released=%lx\n", bdata - bootmem_node_data, count); - - return count; -} - -static int reset_managed_pages_done __initdata; - -void reset_node_managed_pages(pg_data_t *pgdat) -{ - struct zone *z; - - for (z = pgdat->node_zones; z < pgdat->node_zones + MAX_NR_ZONES; z++) - z->managed_pages = 0; -} - -void __init reset_all_zones_managed_pages(void) -{ - struct pglist_data *pgdat; - - if (reset_managed_pages_done) - return; - - for_each_online_pgdat(pgdat) - reset_node_managed_pages(pgdat); - - reset_managed_pages_done = 1; -} - -/** - * free_all_bootmem - release free pages to the buddy allocator - * - * Returns the number of pages actually released. - */ -unsigned long __init free_all_bootmem(void) -{ - unsigned long total_pages = 0; - bootmem_data_t *bdata; - - reset_all_zones_managed_pages(); - - list_for_each_entry(bdata, &bdata_list, list) - total_pages += free_all_bootmem_core(bdata); - - totalram_pages += total_pages; - - return total_pages; -} - -static void __init __free(bootmem_data_t *bdata, - unsigned long sidx, unsigned long eidx) -{ - unsigned long idx; - - bdebug("nid=%td start=%lx end=%lx\n", bdata - bootmem_node_data, - sidx + bdata->node_min_pfn, - eidx + bdata->node_min_pfn); - - if (WARN_ON(bdata->node_bootmem_map == NULL)) - return; - - if (bdata->hint_idx > sidx) - bdata->hint_idx = sidx; - - for (idx = sidx; idx < eidx; idx++) - if (!test_and_clear_bit(idx, bdata->node_bootmem_map)) - BUG(); -} - -static int __init __reserve(bootmem_data_t *bdata, unsigned long sidx, - unsigned long eidx, int flags) -{ - unsigned long idx; - int exclusive = flags & BOOTMEM_EXCLUSIVE; - - bdebug("nid=%td start=%lx end=%lx flags=%x\n", - bdata - bootmem_node_data, - sidx + bdata->node_min_pfn, - eidx + bdata->node_min_pfn, - flags); - - if (WARN_ON(bdata->node_bootmem_map == NULL)) - return 0; - - for (idx = sidx; idx < eidx; idx++) - if (test_and_set_bit(idx, bdata->node_bootmem_map)) { - if (exclusive) { - __free(bdata, sidx, idx); - return -EBUSY; - } - bdebug("silent double reserve of PFN %lx\n", - idx + bdata->node_min_pfn); - } - return 0; -} - -static int __init mark_bootmem_node(bootmem_data_t *bdata, - unsigned long start, unsigned long end, - int reserve, int flags) -{ - unsigned long sidx, eidx; - - bdebug("nid=%td start=%lx end=%lx reserve=%d flags=%x\n", - bdata - bootmem_node_data, start, end, reserve, flags); - - BUG_ON(start < bdata->node_min_pfn); - BUG_ON(end > bdata->node_low_pfn); - - sidx = start - bdata->node_min_pfn; - eidx = end - bdata->node_min_pfn; - - if (reserve) - return __reserve(bdata, sidx, eidx, flags); - else - __free(bdata, sidx, eidx); - return 0; -} - -static int __init mark_bootmem(unsigned long start, unsigned long end, - int reserve, int flags) -{ - unsigned long pos; - bootmem_data_t *bdata; - - pos = start; - list_for_each_entry(bdata, &bdata_list, list) { - int err; - unsigned long max; - - if (pos < bdata->node_min_pfn || - pos >= bdata->node_low_pfn) { - BUG_ON(pos != start); - continue; - } - - max = min(bdata->node_low_pfn, end); - - err = mark_bootmem_node(bdata, pos, max, reserve, flags); - if (reserve && err) { - mark_bootmem(start, pos, 0, 0); - return err; - } - - if (max == end) - return 0; - pos = bdata->node_low_pfn; - } - BUG(); -} - -/** - * free_bootmem_node - mark a page range as usable - * @pgdat: node the range resides on - * @physaddr: starting address of the range - * @size: size of the range in bytes - * - * Partial pages will be considered reserved and left as they are. - * - * The range must reside completely on the specified node. - */ -void __init free_bootmem_node(pg_data_t *pgdat, unsigned long physaddr, - unsigned long size) -{ - unsigned long start, end; - - kmemleak_free_part_phys(physaddr, size); - - start = PFN_UP(physaddr); - end = PFN_DOWN(physaddr + size); - - mark_bootmem_node(pgdat->bdata, start, end, 0, 0); -} - -/** - * free_bootmem - mark a page range as usable - * @addr: starting physical address of the range - * @size: size of the range in bytes - * - * Partial pages will be considered reserved and left as they are. - * - * The range must be contiguous but may span node boundaries. - */ -void __init free_bootmem(unsigned long physaddr, unsigned long size) -{ - unsigned long start, end; - - kmemleak_free_part_phys(physaddr, size); - - start = PFN_UP(physaddr); - end = PFN_DOWN(physaddr + size); - - mark_bootmem(start, end, 0, 0); -} - -/** - * reserve_bootmem_node - mark a page range as reserved - * @pgdat: node the range resides on - * @physaddr: starting address of the range - * @size: size of the range in bytes - * @flags: reservation flags (see linux/bootmem.h) - * - * Partial pages will be reserved. - * - * The range must reside completely on the specified node. - */ -int __init reserve_bootmem_node(pg_data_t *pgdat, unsigned long physaddr, - unsigned long size, int flags) -{ - unsigned long start, end; - - start = PFN_DOWN(physaddr); - end = PFN_UP(physaddr + size); - - return mark_bootmem_node(pgdat->bdata, start, end, 1, flags); -} - -/** - * reserve_bootmem - mark a page range as reserved - * @addr: starting address of the range - * @size: size of the range in bytes - * @flags: reservation flags (see linux/bootmem.h) - * - * Partial pages will be reserved. - * - * The range must be contiguous but may span node boundaries. - */ -int __init reserve_bootmem(unsigned long addr, unsigned long size, - int flags) -{ - unsigned long start, end; - - start = PFN_DOWN(addr); - end = PFN_UP(addr + size); - - return mark_bootmem(start, end, 1, flags); -} - -static unsigned long __init align_idx(struct bootmem_data *bdata, - unsigned long idx, unsigned long step) -{ - unsigned long base = bdata->node_min_pfn; - - /* - * Align the index with respect to the node start so that the - * combination of both satisfies the requested alignment. - */ - - return ALIGN(base + idx, step) - base; -} - -static unsigned long __init align_off(struct bootmem_data *bdata, - unsigned long off, unsigned long align) -{ - unsigned long base = PFN_PHYS(bdata->node_min_pfn); - - /* Same as align_idx for byte offsets */ - - return ALIGN(base + off, align) - base; -} - -static void * __init alloc_bootmem_bdata(struct bootmem_data *bdata, - unsigned long size, unsigned long align, - unsigned long goal, unsigned long limit) -{ - unsigned long fallback = 0; - unsigned long min, max, start, sidx, midx, step; - - bdebug("nid=%td size=%lx [%lu pages] align=%lx goal=%lx limit=%lx\n", - bdata - bootmem_node_data, size, PAGE_ALIGN(size) >> PAGE_SHIFT, - align, goal, limit); - - BUG_ON(!size); - BUG_ON(align & (align - 1)); - BUG_ON(limit && goal + size > limit); - - if (!bdata->node_bootmem_map) - return NULL; - - min = bdata->node_min_pfn; - max = bdata->node_low_pfn; - - goal >>= PAGE_SHIFT; - limit >>= PAGE_SHIFT; - - if (limit && max > limit) - max = limit; - if (max <= min) - return NULL; - - step = max(align >> PAGE_SHIFT, 1UL); - - if (goal && min < goal && goal < max) - start = ALIGN(goal, step); - else - start = ALIGN(min, step); - - sidx = start - bdata->node_min_pfn; - midx = max - bdata->node_min_pfn; - - if (bdata->hint_idx > sidx) { - /* - * Handle the valid case of sidx being zero and still - * catch the fallback below. - */ - fallback = sidx + 1; - sidx = align_idx(bdata, bdata->hint_idx, step); - } - - while (1) { - int merge; - void *region; - unsigned long eidx, i, start_off, end_off; -find_block: - sidx = find_next_zero_bit(bdata->node_bootmem_map, midx, sidx); - sidx = align_idx(bdata, sidx, step); - eidx = sidx + PFN_UP(size); - - if (sidx >= midx || eidx > midx) - break; - - for (i = sidx; i < eidx; i++) - if (test_bit(i, bdata->node_bootmem_map)) { - sidx = align_idx(bdata, i, step); - if (sidx == i) - sidx += step; - goto find_block; - } - - if (bdata->last_end_off & (PAGE_SIZE - 1) && - PFN_DOWN(bdata->last_end_off) + 1 == sidx) - start_off = align_off(bdata, bdata->last_end_off, align); - else - start_off = PFN_PHYS(sidx); - - merge = PFN_DOWN(start_off) < sidx; - end_off = start_off + size; - - bdata->last_end_off = end_off; - bdata->hint_idx = PFN_UP(end_off); - - /* - * Reserve the area now: - */ - if (__reserve(bdata, PFN_DOWN(start_off) + merge, - PFN_UP(end_off), BOOTMEM_EXCLUSIVE)) - BUG(); - - region = phys_to_virt(PFN_PHYS(bdata->node_min_pfn) + - start_off); - memset(region, 0, size); - /* - * The min_count is set to 0 so that bootmem allocated blocks - * are never reported as leaks. - */ - kmemleak_alloc(region, size, 0, 0); - return region; - } - - if (fallback) { - sidx = align_idx(bdata, fallback - 1, step); - fallback = 0; - goto find_block; - } - - return NULL; -} - -static void * __init alloc_bootmem_core(unsigned long size, - unsigned long align, - unsigned long goal, - unsigned long limit) -{ - bootmem_data_t *bdata; - void *region; - - if (WARN_ON_ONCE(slab_is_available())) - return kzalloc(size, GFP_NOWAIT); - - list_for_each_entry(bdata, &bdata_list, list) { - if (goal && bdata->node_low_pfn <= PFN_DOWN(goal)) - continue; - if (limit && bdata->node_min_pfn >= PFN_DOWN(limit)) - break; - - region = alloc_bootmem_bdata(bdata, size, align, goal, limit); - if (region) - return region; - } - - return NULL; -} - -static void * __init ___alloc_bootmem_nopanic(unsigned long size, - unsigned long align, - unsigned long goal, - unsigned long limit) -{ - void *ptr; - -restart: - ptr = alloc_bootmem_core(size, align, goal, limit); - if (ptr) - return ptr; - if (goal) { - goal = 0; - goto restart; - } - - return NULL; -} - -/** - * __alloc_bootmem_nopanic - allocate boot memory without panicking - * @size: size of the request in bytes - * @align: alignment of the region - * @goal: preferred starting address of the region - * - * The goal is dropped if it can not be satisfied and the allocation will - * fall back to memory below @goal. - * - * Allocation may happen on any node in the system. - * - * Returns NULL on failure. - */ -void * __init __alloc_bootmem_nopanic(unsigned long size, unsigned long align, - unsigned long goal) -{ - unsigned long limit = 0; - - return ___alloc_bootmem_nopanic(size, align, goal, limit); -} - -static void * __init ___alloc_bootmem(unsigned long size, unsigned long align, - unsigned long goal, unsigned long limit) -{ - void *mem = ___alloc_bootmem_nopanic(size, align, goal, limit); - - if (mem) - return mem; - /* - * Whoops, we cannot satisfy the allocation request. - */ - pr_alert("bootmem alloc of %lu bytes failed!\n", size); - panic("Out of memory"); - return NULL; -} - -/** - * __alloc_bootmem - allocate boot memory - * @size: size of the request in bytes - * @align: alignment of the region - * @goal: preferred starting address of the region - * - * The goal is dropped if it can not be satisfied and the allocation will - * fall back to memory below @goal. - * - * Allocation may happen on any node in the system. - * - * The function panics if the request can not be satisfied. - */ -void * __init __alloc_bootmem(unsigned long size, unsigned long align, - unsigned long goal) -{ - unsigned long limit = 0; - - return ___alloc_bootmem(size, align, goal, limit); -} - -void * __init ___alloc_bootmem_node_nopanic(pg_data_t *pgdat, - unsigned long size, unsigned long align, - unsigned long goal, unsigned long limit) -{ - void *ptr; - - if (WARN_ON_ONCE(slab_is_available())) - return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id); -again: - - /* do not panic in alloc_bootmem_bdata() */ - if (limit && goal + size > limit) - limit = 0; - - ptr = alloc_bootmem_bdata(pgdat->bdata, size, align, goal, limit); - if (ptr) - return ptr; - - ptr = alloc_bootmem_core(size, align, goal, limit); - if (ptr) - return ptr; - - if (goal) { - goal = 0; - goto again; - } - - return NULL; -} - -void * __init __alloc_bootmem_node_nopanic(pg_data_t *pgdat, unsigned long size, - unsigned long align, unsigned long goal) -{ - return ___alloc_bootmem_node_nopanic(pgdat, size, align, goal, 0); -} - -void * __init ___alloc_bootmem_node(pg_data_t *pgdat, unsigned long size, - unsigned long align, unsigned long goal, - unsigned long limit) -{ - void *ptr; - - ptr = ___alloc_bootmem_node_nopanic(pgdat, size, align, goal, 0); - if (ptr) - return ptr; - - pr_alert("bootmem alloc of %lu bytes failed!\n", size); - panic("Out of memory"); - return NULL; -} - -/** - * __alloc_bootmem_node - allocate boot memory from a specific node - * @pgdat: node to allocate from - * @size: size of the request in bytes - * @align: alignment of the region - * @goal: preferred starting address of the region - * - * The goal is dropped if it can not be satisfied and the allocation will - * fall back to memory below @goal. - * - * Allocation may fall back to any node in the system if the specified node - * can not hold the requested memory. - * - * The function panics if the request can not be satisfied. - */ -void * __init __alloc_bootmem_node(pg_data_t *pgdat, unsigned long size, - unsigned long align, unsigned long goal) -{ - if (WARN_ON_ONCE(slab_is_available())) - return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id); - - return ___alloc_bootmem_node(pgdat, size, align, goal, 0); -} - -void * __init __alloc_bootmem_node_high(pg_data_t *pgdat, unsigned long size, - unsigned long align, unsigned long goal) -{ -#ifdef MAX_DMA32_PFN - unsigned long end_pfn; - - if (WARN_ON_ONCE(slab_is_available())) - return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id); - - /* update goal according ...MAX_DMA32_PFN */ - end_pfn = pgdat_end_pfn(pgdat); - - if (end_pfn > MAX_DMA32_PFN + (128 >> (20 - PAGE_SHIFT)) && - (goal >> PAGE_SHIFT) < MAX_DMA32_PFN) { - void *ptr; - unsigned long new_goal; - - new_goal = MAX_DMA32_PFN << PAGE_SHIFT; - ptr = alloc_bootmem_bdata(pgdat->bdata, size, align, - new_goal, 0); - if (ptr) - return ptr; - } -#endif - - return __alloc_bootmem_node(pgdat, size, align, goal); - -} - -/** - * __alloc_bootmem_low - allocate low boot memory - * @size: size of the request in bytes - * @align: alignment of the region - * @goal: preferred starting address of the region - * - * The goal is dropped if it can not be satisfied and the allocation will - * fall back to memory below @goal. - * - * Allocation may happen on any node in the system. - * - * The function panics if the request can not be satisfied. - */ -void * __init __alloc_bootmem_low(unsigned long size, unsigned long align, - unsigned long goal) -{ - return ___alloc_bootmem(size, align, goal, ARCH_LOW_ADDRESS_LIMIT); -} - -void * __init __alloc_bootmem_low_nopanic(unsigned long size, - unsigned long align, - unsigned long goal) -{ - return ___alloc_bootmem_nopanic(size, align, goal, - ARCH_LOW_ADDRESS_LIMIT); -} - -/** - * __alloc_bootmem_low_node - allocate low boot memory from a specific node - * @pgdat: node to allocate from - * @size: size of the request in bytes - * @align: alignment of the region - * @goal: preferred starting address of the region - * - * The goal is dropped if it can not be satisfied and the allocation will - * fall back to memory below @goal. - * - * Allocation may fall back to any node in the system if the specified node - * can not hold the requested memory. - * - * The function panics if the request can not be satisfied. - */ -void * __init __alloc_bootmem_low_node(pg_data_t *pgdat, unsigned long size, - unsigned long align, unsigned long goal) -{ - if (WARN_ON_ONCE(slab_is_available())) - return kzalloc_node(size, GFP_NOWAIT, pgdat->node_id); - - return ___alloc_bootmem_node(pgdat, size, align, - goal, ARCH_LOW_ADDRESS_LIMIT); -} diff --git a/src/linux/mm/compaction.c b/src/linux/mm/compaction.c deleted file mode 100644 index 0409a4a..0000000 --- a/src/linux/mm/compaction.c +++ /dev/null @@ -1,2077 +0,0 @@ -/* - * linux/mm/compaction.c - * - * Memory compaction for the reduction of external fragmentation. Note that - * this heavily depends upon page migration to do all the real heavy - * lifting - * - * Copyright IBM Corp. 2007-2010 Mel Gorman - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -#ifdef CONFIG_COMPACTION -static inline void count_compact_event(enum vm_event_item item) -{ - count_vm_event(item); -} - -static inline void count_compact_events(enum vm_event_item item, long delta) -{ - count_vm_events(item, delta); -} -#else -#define count_compact_event(item) do { } while (0) -#define count_compact_events(item, delta) do { } while (0) -#endif - -#if defined CONFIG_COMPACTION || defined CONFIG_CMA - -#define CREATE_TRACE_POINTS -#include - -#define block_start_pfn(pfn, order) round_down(pfn, 1UL << (order)) -#define block_end_pfn(pfn, order) ALIGN((pfn) + 1, 1UL << (order)) -#define pageblock_start_pfn(pfn) block_start_pfn(pfn, pageblock_order) -#define pageblock_end_pfn(pfn) block_end_pfn(pfn, pageblock_order) - -static unsigned long release_freepages(struct list_head *freelist) -{ - struct page *page, *next; - unsigned long high_pfn = 0; - - list_for_each_entry_safe(page, next, freelist, lru) { - unsigned long pfn = page_to_pfn(page); - list_del(&page->lru); - __free_page(page); - if (pfn > high_pfn) - high_pfn = pfn; - } - - return high_pfn; -} - -static void map_pages(struct list_head *list) -{ - unsigned int i, order, nr_pages; - struct page *page, *next; - LIST_HEAD(tmp_list); - - list_for_each_entry_safe(page, next, list, lru) { - list_del(&page->lru); - - order = page_private(page); - nr_pages = 1 << order; - - post_alloc_hook(page, order, __GFP_MOVABLE); - if (order) - split_page(page, order); - - for (i = 0; i < nr_pages; i++) { - list_add(&page->lru, &tmp_list); - page++; - } - } - - list_splice(&tmp_list, list); -} - -static inline bool migrate_async_suitable(int migratetype) -{ - return is_migrate_cma(migratetype) || migratetype == MIGRATE_MOVABLE; -} - -#ifdef CONFIG_COMPACTION - -int PageMovable(struct page *page) -{ - struct address_space *mapping; - - VM_BUG_ON_PAGE(!PageLocked(page), page); - if (!__PageMovable(page)) - return 0; - - mapping = page_mapping(page); - if (mapping && mapping->a_ops && mapping->a_ops->isolate_page) - return 1; - - return 0; -} -EXPORT_SYMBOL(PageMovable); - -void __SetPageMovable(struct page *page, struct address_space *mapping) -{ - VM_BUG_ON_PAGE(!PageLocked(page), page); - VM_BUG_ON_PAGE((unsigned long)mapping & PAGE_MAPPING_MOVABLE, page); - page->mapping = (void *)((unsigned long)mapping | PAGE_MAPPING_MOVABLE); -} -EXPORT_SYMBOL(__SetPageMovable); - -void __ClearPageMovable(struct page *page) -{ - VM_BUG_ON_PAGE(!PageLocked(page), page); - VM_BUG_ON_PAGE(!PageMovable(page), page); - /* - * Clear registered address_space val with keeping PAGE_MAPPING_MOVABLE - * flag so that VM can catch up released page by driver after isolation. - * With it, VM migration doesn't try to put it back. - */ - page->mapping = (void *)((unsigned long)page->mapping & - PAGE_MAPPING_MOVABLE); -} -EXPORT_SYMBOL(__ClearPageMovable); - -/* Do not skip compaction more than 64 times */ -#define COMPACT_MAX_DEFER_SHIFT 6 - -/* - * Compaction is deferred when compaction fails to result in a page - * allocation success. 1 << compact_defer_limit compactions are skipped up - * to a limit of 1 << COMPACT_MAX_DEFER_SHIFT - */ -void defer_compaction(struct zone *zone, int order) -{ - zone->compact_considered = 0; - zone->compact_defer_shift++; - - if (order < zone->compact_order_failed) - zone->compact_order_failed = order; - - if (zone->compact_defer_shift > COMPACT_MAX_DEFER_SHIFT) - zone->compact_defer_shift = COMPACT_MAX_DEFER_SHIFT; - - trace_mm_compaction_defer_compaction(zone, order); -} - -/* Returns true if compaction should be skipped this time */ -bool compaction_deferred(struct zone *zone, int order) -{ - unsigned long defer_limit = 1UL << zone->compact_defer_shift; - - if (order < zone->compact_order_failed) - return false; - - /* Avoid possible overflow */ - if (++zone->compact_considered > defer_limit) - zone->compact_considered = defer_limit; - - if (zone->compact_considered >= defer_limit) - return false; - - trace_mm_compaction_deferred(zone, order); - - return true; -} - -/* - * Update defer tracking counters after successful compaction of given order, - * which means an allocation either succeeded (alloc_success == true) or is - * expected to succeed. - */ -void compaction_defer_reset(struct zone *zone, int order, - bool alloc_success) -{ - if (alloc_success) { - zone->compact_considered = 0; - zone->compact_defer_shift = 0; - } - if (order >= zone->compact_order_failed) - zone->compact_order_failed = order + 1; - - trace_mm_compaction_defer_reset(zone, order); -} - -/* Returns true if restarting compaction after many failures */ -bool compaction_restarting(struct zone *zone, int order) -{ - if (order < zone->compact_order_failed) - return false; - - return zone->compact_defer_shift == COMPACT_MAX_DEFER_SHIFT && - zone->compact_considered >= 1UL << zone->compact_defer_shift; -} - -/* Returns true if the pageblock should be scanned for pages to isolate. */ -static inline bool isolation_suitable(struct compact_control *cc, - struct page *page) -{ - if (cc->ignore_skip_hint) - return true; - - return !get_pageblock_skip(page); -} - -static void reset_cached_positions(struct zone *zone) -{ - zone->compact_cached_migrate_pfn[0] = zone->zone_start_pfn; - zone->compact_cached_migrate_pfn[1] = zone->zone_start_pfn; - zone->compact_cached_free_pfn = - pageblock_start_pfn(zone_end_pfn(zone) - 1); -} - -/* - * This function is called to clear all cached information on pageblocks that - * should be skipped for page isolation when the migrate and free page scanner - * meet. - */ -static void __reset_isolation_suitable(struct zone *zone) -{ - unsigned long start_pfn = zone->zone_start_pfn; - unsigned long end_pfn = zone_end_pfn(zone); - unsigned long pfn; - - zone->compact_blockskip_flush = false; - - /* Walk the zone and mark every pageblock as suitable for isolation */ - for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) { - struct page *page; - - cond_resched(); - - if (!pfn_valid(pfn)) - continue; - - page = pfn_to_page(pfn); - if (zone != page_zone(page)) - continue; - - clear_pageblock_skip(page); - } - - reset_cached_positions(zone); -} - -void reset_isolation_suitable(pg_data_t *pgdat) -{ - int zoneid; - - for (zoneid = 0; zoneid < MAX_NR_ZONES; zoneid++) { - struct zone *zone = &pgdat->node_zones[zoneid]; - if (!populated_zone(zone)) - continue; - - /* Only flush if a full compaction finished recently */ - if (zone->compact_blockskip_flush) - __reset_isolation_suitable(zone); - } -} - -/* - * If no pages were isolated then mark this pageblock to be skipped in the - * future. The information is later cleared by __reset_isolation_suitable(). - */ -static void update_pageblock_skip(struct compact_control *cc, - struct page *page, unsigned long nr_isolated, - bool migrate_scanner) -{ - struct zone *zone = cc->zone; - unsigned long pfn; - - if (cc->ignore_skip_hint) - return; - - if (!page) - return; - - if (nr_isolated) - return; - - set_pageblock_skip(page); - - pfn = page_to_pfn(page); - - /* Update where async and sync compaction should restart */ - if (migrate_scanner) { - if (pfn > zone->compact_cached_migrate_pfn[0]) - zone->compact_cached_migrate_pfn[0] = pfn; - if (cc->mode != MIGRATE_ASYNC && - pfn > zone->compact_cached_migrate_pfn[1]) - zone->compact_cached_migrate_pfn[1] = pfn; - } else { - if (pfn < zone->compact_cached_free_pfn) - zone->compact_cached_free_pfn = pfn; - } -} -#else -static inline bool isolation_suitable(struct compact_control *cc, - struct page *page) -{ - return true; -} - -static void update_pageblock_skip(struct compact_control *cc, - struct page *page, unsigned long nr_isolated, - bool migrate_scanner) -{ -} -#endif /* CONFIG_COMPACTION */ - -/* - * Compaction requires the taking of some coarse locks that are potentially - * very heavily contended. For async compaction, back out if the lock cannot - * be taken immediately. For sync compaction, spin on the lock if needed. - * - * Returns true if the lock is held - * Returns false if the lock is not held and compaction should abort - */ -static bool compact_trylock_irqsave(spinlock_t *lock, unsigned long *flags, - struct compact_control *cc) -{ - if (cc->mode == MIGRATE_ASYNC) { - if (!spin_trylock_irqsave(lock, *flags)) { - cc->contended = true; - return false; - } - } else { - spin_lock_irqsave(lock, *flags); - } - - return true; -} - -/* - * Compaction requires the taking of some coarse locks that are potentially - * very heavily contended. The lock should be periodically unlocked to avoid - * having disabled IRQs for a long time, even when there is nobody waiting on - * the lock. It might also be that allowing the IRQs will result in - * need_resched() becoming true. If scheduling is needed, async compaction - * aborts. Sync compaction schedules. - * Either compaction type will also abort if a fatal signal is pending. - * In either case if the lock was locked, it is dropped and not regained. - * - * Returns true if compaction should abort due to fatal signal pending, or - * async compaction due to need_resched() - * Returns false when compaction can continue (sync compaction might have - * scheduled) - */ -static bool compact_unlock_should_abort(spinlock_t *lock, - unsigned long flags, bool *locked, struct compact_control *cc) -{ - if (*locked) { - spin_unlock_irqrestore(lock, flags); - *locked = false; - } - - if (fatal_signal_pending(current)) { - cc->contended = true; - return true; - } - - if (need_resched()) { - if (cc->mode == MIGRATE_ASYNC) { - cc->contended = true; - return true; - } - cond_resched(); - } - - return false; -} - -/* - * Aside from avoiding lock contention, compaction also periodically checks - * need_resched() and either schedules in sync compaction or aborts async - * compaction. This is similar to what compact_unlock_should_abort() does, but - * is used where no lock is concerned. - * - * Returns false when no scheduling was needed, or sync compaction scheduled. - * Returns true when async compaction should abort. - */ -static inline bool compact_should_abort(struct compact_control *cc) -{ - /* async compaction aborts if contended */ - if (need_resched()) { - if (cc->mode == MIGRATE_ASYNC) { - cc->contended = true; - return true; - } - - cond_resched(); - } - - return false; -} - -/* - * Isolate free pages onto a private freelist. If @strict is true, will abort - * returning 0 on any invalid PFNs or non-free pages inside of the pageblock - * (even though it may still end up isolating some pages). - */ -static unsigned long isolate_freepages_block(struct compact_control *cc, - unsigned long *start_pfn, - unsigned long end_pfn, - struct list_head *freelist, - bool strict) -{ - int nr_scanned = 0, total_isolated = 0; - struct page *cursor, *valid_page = NULL; - unsigned long flags = 0; - bool locked = false; - unsigned long blockpfn = *start_pfn; - unsigned int order; - - cursor = pfn_to_page(blockpfn); - - /* Isolate free pages. */ - for (; blockpfn < end_pfn; blockpfn++, cursor++) { - int isolated; - struct page *page = cursor; - - /* - * Periodically drop the lock (if held) regardless of its - * contention, to give chance to IRQs. Abort if fatal signal - * pending or async compaction detects need_resched() - */ - if (!(blockpfn % SWAP_CLUSTER_MAX) - && compact_unlock_should_abort(&cc->zone->lock, flags, - &locked, cc)) - break; - - nr_scanned++; - if (!pfn_valid_within(blockpfn)) - goto isolate_fail; - - if (!valid_page) - valid_page = page; - - /* - * For compound pages such as THP and hugetlbfs, we can save - * potentially a lot of iterations if we skip them at once. - * The check is racy, but we can consider only valid values - * and the only danger is skipping too much. - */ - if (PageCompound(page)) { - unsigned int comp_order = compound_order(page); - - if (likely(comp_order < MAX_ORDER)) { - blockpfn += (1UL << comp_order) - 1; - cursor += (1UL << comp_order) - 1; - } - - goto isolate_fail; - } - - if (!PageBuddy(page)) - goto isolate_fail; - - /* - * If we already hold the lock, we can skip some rechecking. - * Note that if we hold the lock now, checked_pageblock was - * already set in some previous iteration (or strict is true), - * so it is correct to skip the suitable migration target - * recheck as well. - */ - if (!locked) { - /* - * The zone lock must be held to isolate freepages. - * Unfortunately this is a very coarse lock and can be - * heavily contended if there are parallel allocations - * or parallel compactions. For async compaction do not - * spin on the lock and we acquire the lock as late as - * possible. - */ - locked = compact_trylock_irqsave(&cc->zone->lock, - &flags, cc); - if (!locked) - break; - - /* Recheck this is a buddy page under lock */ - if (!PageBuddy(page)) - goto isolate_fail; - } - - /* Found a free page, will break it into order-0 pages */ - order = page_order(page); - isolated = __isolate_free_page(page, order); - if (!isolated) - break; - set_page_private(page, order); - - total_isolated += isolated; - cc->nr_freepages += isolated; - list_add_tail(&page->lru, freelist); - - if (!strict && cc->nr_migratepages <= cc->nr_freepages) { - blockpfn += isolated; - break; - } - /* Advance to the end of split page */ - blockpfn += isolated - 1; - cursor += isolated - 1; - continue; - -isolate_fail: - if (strict) - break; - else - continue; - - } - - if (locked) - spin_unlock_irqrestore(&cc->zone->lock, flags); - - /* - * There is a tiny chance that we have read bogus compound_order(), - * so be careful to not go outside of the pageblock. - */ - if (unlikely(blockpfn > end_pfn)) - blockpfn = end_pfn; - - trace_mm_compaction_isolate_freepages(*start_pfn, blockpfn, - nr_scanned, total_isolated); - - /* Record how far we have got within the block */ - *start_pfn = blockpfn; - - /* - * If strict isolation is requested by CMA then check that all the - * pages requested were isolated. If there were any failures, 0 is - * returned and CMA will fail. - */ - if (strict && blockpfn < end_pfn) - total_isolated = 0; - - /* Update the pageblock-skip if the whole pageblock was scanned */ - if (blockpfn == end_pfn) - update_pageblock_skip(cc, valid_page, total_isolated, false); - - count_compact_events(COMPACTFREE_SCANNED, nr_scanned); - if (total_isolated) - count_compact_events(COMPACTISOLATED, total_isolated); - return total_isolated; -} - -/** - * isolate_freepages_range() - isolate free pages. - * @start_pfn: The first PFN to start isolating. - * @end_pfn: The one-past-last PFN. - * - * Non-free pages, invalid PFNs, or zone boundaries within the - * [start_pfn, end_pfn) range are considered errors, cause function to - * undo its actions and return zero. - * - * Otherwise, function returns one-past-the-last PFN of isolated page - * (which may be greater then end_pfn if end fell in a middle of - * a free page). - */ -unsigned long -isolate_freepages_range(struct compact_control *cc, - unsigned long start_pfn, unsigned long end_pfn) -{ - unsigned long isolated, pfn, block_start_pfn, block_end_pfn; - LIST_HEAD(freelist); - - pfn = start_pfn; - block_start_pfn = pageblock_start_pfn(pfn); - if (block_start_pfn < cc->zone->zone_start_pfn) - block_start_pfn = cc->zone->zone_start_pfn; - block_end_pfn = pageblock_end_pfn(pfn); - - for (; pfn < end_pfn; pfn += isolated, - block_start_pfn = block_end_pfn, - block_end_pfn += pageblock_nr_pages) { - /* Protect pfn from changing by isolate_freepages_block */ - unsigned long isolate_start_pfn = pfn; - - block_end_pfn = min(block_end_pfn, end_pfn); - - /* - * pfn could pass the block_end_pfn if isolated freepage - * is more than pageblock order. In this case, we adjust - * scanning range to right one. - */ - if (pfn >= block_end_pfn) { - block_start_pfn = pageblock_start_pfn(pfn); - block_end_pfn = pageblock_end_pfn(pfn); - block_end_pfn = min(block_end_pfn, end_pfn); - } - - if (!pageblock_pfn_to_page(block_start_pfn, - block_end_pfn, cc->zone)) - break; - - isolated = isolate_freepages_block(cc, &isolate_start_pfn, - block_end_pfn, &freelist, true); - - /* - * In strict mode, isolate_freepages_block() returns 0 if - * there are any holes in the block (ie. invalid PFNs or - * non-free pages). - */ - if (!isolated) - break; - - /* - * If we managed to isolate pages, it is always (1 << n) * - * pageblock_nr_pages for some non-negative n. (Max order - * page may span two pageblocks). - */ - } - - /* __isolate_free_page() does not map the pages */ - map_pages(&freelist); - - if (pfn < end_pfn) { - /* Loop terminated early, cleanup. */ - release_freepages(&freelist); - return 0; - } - - /* We don't use freelists for anything. */ - return pfn; -} - -/* Update the number of anon and file isolated pages in the zone */ -static void acct_isolated(struct zone *zone, struct compact_control *cc) -{ - struct page *page; - unsigned int count[2] = { 0, }; - - if (list_empty(&cc->migratepages)) - return; - - list_for_each_entry(page, &cc->migratepages, lru) - count[!!page_is_file_cache(page)]++; - - mod_node_page_state(zone->zone_pgdat, NR_ISOLATED_ANON, count[0]); - mod_node_page_state(zone->zone_pgdat, NR_ISOLATED_FILE, count[1]); -} - -/* Similar to reclaim, but different enough that they don't share logic */ -static bool too_many_isolated(struct zone *zone) -{ - unsigned long active, inactive, isolated; - - inactive = node_page_state(zone->zone_pgdat, NR_INACTIVE_FILE) + - node_page_state(zone->zone_pgdat, NR_INACTIVE_ANON); - active = node_page_state(zone->zone_pgdat, NR_ACTIVE_FILE) + - node_page_state(zone->zone_pgdat, NR_ACTIVE_ANON); - isolated = node_page_state(zone->zone_pgdat, NR_ISOLATED_FILE) + - node_page_state(zone->zone_pgdat, NR_ISOLATED_ANON); - - return isolated > (inactive + active) / 2; -} - -/** - * isolate_migratepages_block() - isolate all migrate-able pages within - * a single pageblock - * @cc: Compaction control structure. - * @low_pfn: The first PFN to isolate - * @end_pfn: The one-past-the-last PFN to isolate, within same pageblock - * @isolate_mode: Isolation mode to be used. - * - * Isolate all pages that can be migrated from the range specified by - * [low_pfn, end_pfn). The range is expected to be within same pageblock. - * Returns zero if there is a fatal signal pending, otherwise PFN of the - * first page that was not scanned (which may be both less, equal to or more - * than end_pfn). - * - * The pages are isolated on cc->migratepages list (not required to be empty), - * and cc->nr_migratepages is updated accordingly. The cc->migrate_pfn field - * is neither read nor updated. - */ -static unsigned long -isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn, - unsigned long end_pfn, isolate_mode_t isolate_mode) -{ - struct zone *zone = cc->zone; - unsigned long nr_scanned = 0, nr_isolated = 0; - struct lruvec *lruvec; - unsigned long flags = 0; - bool locked = false; - struct page *page = NULL, *valid_page = NULL; - unsigned long start_pfn = low_pfn; - bool skip_on_failure = false; - unsigned long next_skip_pfn = 0; - - /* - * Ensure that there are not too many pages isolated from the LRU - * list by either parallel reclaimers or compaction. If there are, - * delay for some time until fewer pages are isolated - */ - while (unlikely(too_many_isolated(zone))) { - /* async migration should just abort */ - if (cc->mode == MIGRATE_ASYNC) - return 0; - - congestion_wait(BLK_RW_ASYNC, HZ/10); - - if (fatal_signal_pending(current)) - return 0; - } - - if (compact_should_abort(cc)) - return 0; - - if (cc->direct_compaction && (cc->mode == MIGRATE_ASYNC)) { - skip_on_failure = true; - next_skip_pfn = block_end_pfn(low_pfn, cc->order); - } - - /* Time to isolate some pages for migration */ - for (; low_pfn < end_pfn; low_pfn++) { - - if (skip_on_failure && low_pfn >= next_skip_pfn) { - /* - * We have isolated all migration candidates in the - * previous order-aligned block, and did not skip it due - * to failure. We should migrate the pages now and - * hopefully succeed compaction. - */ - if (nr_isolated) - break; - - /* - * We failed to isolate in the previous order-aligned - * block. Set the new boundary to the end of the - * current block. Note we can't simply increase - * next_skip_pfn by 1 << order, as low_pfn might have - * been incremented by a higher number due to skipping - * a compound or a high-order buddy page in the - * previous loop iteration. - */ - next_skip_pfn = block_end_pfn(low_pfn, cc->order); - } - - /* - * Periodically drop the lock (if held) regardless of its - * contention, to give chance to IRQs. Abort async compaction - * if contended. - */ - if (!(low_pfn % SWAP_CLUSTER_MAX) - && compact_unlock_should_abort(zone_lru_lock(zone), flags, - &locked, cc)) - break; - - if (!pfn_valid_within(low_pfn)) - goto isolate_fail; - nr_scanned++; - - page = pfn_to_page(low_pfn); - - if (!valid_page) - valid_page = page; - - /* - * Skip if free. We read page order here without zone lock - * which is generally unsafe, but the race window is small and - * the worst thing that can happen is that we skip some - * potential isolation targets. - */ - if (PageBuddy(page)) { - unsigned long freepage_order = page_order_unsafe(page); - - /* - * Without lock, we cannot be sure that what we got is - * a valid page order. Consider only values in the - * valid order range to prevent low_pfn overflow. - */ - if (freepage_order > 0 && freepage_order < MAX_ORDER) - low_pfn += (1UL << freepage_order) - 1; - continue; - } - - /* - * Regardless of being on LRU, compound pages such as THP and - * hugetlbfs are not to be compacted. We can potentially save - * a lot of iterations if we skip them at once. The check is - * racy, but we can consider only valid values and the only - * danger is skipping too much. - */ - if (PageCompound(page)) { - unsigned int comp_order = compound_order(page); - - if (likely(comp_order < MAX_ORDER)) - low_pfn += (1UL << comp_order) - 1; - - goto isolate_fail; - } - - /* - * Check may be lockless but that's ok as we recheck later. - * It's possible to migrate LRU and non-lru movable pages. - * Skip any other type of page - */ - if (!PageLRU(page)) { - /* - * __PageMovable can return false positive so we need - * to verify it under page_lock. - */ - if (unlikely(__PageMovable(page)) && - !PageIsolated(page)) { - if (locked) { - spin_unlock_irqrestore(zone_lru_lock(zone), - flags); - locked = false; - } - - if (isolate_movable_page(page, isolate_mode)) - goto isolate_success; - } - - goto isolate_fail; - } - - /* - * Migration will fail if an anonymous page is pinned in memory, - * so avoid taking lru_lock and isolating it unnecessarily in an - * admittedly racy check. - */ - if (!page_mapping(page) && - page_count(page) > page_mapcount(page)) - goto isolate_fail; - - /* If we already hold the lock, we can skip some rechecking */ - if (!locked) { - locked = compact_trylock_irqsave(zone_lru_lock(zone), - &flags, cc); - if (!locked) - break; - - /* Recheck PageLRU and PageCompound under lock */ - if (!PageLRU(page)) - goto isolate_fail; - - /* - * Page become compound since the non-locked check, - * and it's on LRU. It can only be a THP so the order - * is safe to read and it's 0 for tail pages. - */ - if (unlikely(PageCompound(page))) { - low_pfn += (1UL << compound_order(page)) - 1; - goto isolate_fail; - } - } - - lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat); - - /* Try isolate the page */ - if (__isolate_lru_page(page, isolate_mode) != 0) - goto isolate_fail; - - VM_BUG_ON_PAGE(PageCompound(page), page); - - /* Successfully isolated */ - del_page_from_lru_list(page, lruvec, page_lru(page)); - -isolate_success: - list_add(&page->lru, &cc->migratepages); - cc->nr_migratepages++; - nr_isolated++; - - /* - * Record where we could have freed pages by migration and not - * yet flushed them to buddy allocator. - * - this is the lowest page that was isolated and likely be - * then freed by migration. - */ - if (!cc->last_migrated_pfn) - cc->last_migrated_pfn = low_pfn; - - /* Avoid isolating too much */ - if (cc->nr_migratepages == COMPACT_CLUSTER_MAX) { - ++low_pfn; - break; - } - - continue; -isolate_fail: - if (!skip_on_failure) - continue; - - /* - * We have isolated some pages, but then failed. Release them - * instead of migrating, as we cannot form the cc->order buddy - * page anyway. - */ - if (nr_isolated) { - if (locked) { - spin_unlock_irqrestore(zone_lru_lock(zone), flags); - locked = false; - } - acct_isolated(zone, cc); - putback_movable_pages(&cc->migratepages); - cc->nr_migratepages = 0; - cc->last_migrated_pfn = 0; - nr_isolated = 0; - } - - if (low_pfn < next_skip_pfn) { - low_pfn = next_skip_pfn - 1; - /* - * The check near the loop beginning would have updated - * next_skip_pfn too, but this is a bit simpler. - */ - next_skip_pfn += 1UL << cc->order; - } - } - - /* - * The PageBuddy() check could have potentially brought us outside - * the range to be scanned. - */ - if (unlikely(low_pfn > end_pfn)) - low_pfn = end_pfn; - - if (locked) - spin_unlock_irqrestore(zone_lru_lock(zone), flags); - - /* - * Update the pageblock-skip information and cached scanner pfn, - * if the whole pageblock was scanned without isolating any page. - */ - if (low_pfn == end_pfn) - update_pageblock_skip(cc, valid_page, nr_isolated, true); - - trace_mm_compaction_isolate_migratepages(start_pfn, low_pfn, - nr_scanned, nr_isolated); - - count_compact_events(COMPACTMIGRATE_SCANNED, nr_scanned); - if (nr_isolated) - count_compact_events(COMPACTISOLATED, nr_isolated); - - return low_pfn; -} - -/** - * isolate_migratepages_range() - isolate migrate-able pages in a PFN range - * @cc: Compaction control structure. - * @start_pfn: The first PFN to start isolating. - * @end_pfn: The one-past-last PFN. - * - * Returns zero if isolation fails fatally due to e.g. pending signal. - * Otherwise, function returns one-past-the-last PFN of isolated page - * (which may be greater than end_pfn if end fell in a middle of a THP page). - */ -unsigned long -isolate_migratepages_range(struct compact_control *cc, unsigned long start_pfn, - unsigned long end_pfn) -{ - unsigned long pfn, block_start_pfn, block_end_pfn; - - /* Scan block by block. First and last block may be incomplete */ - pfn = start_pfn; - block_start_pfn = pageblock_start_pfn(pfn); - if (block_start_pfn < cc->zone->zone_start_pfn) - block_start_pfn = cc->zone->zone_start_pfn; - block_end_pfn = pageblock_end_pfn(pfn); - - for (; pfn < end_pfn; pfn = block_end_pfn, - block_start_pfn = block_end_pfn, - block_end_pfn += pageblock_nr_pages) { - - block_end_pfn = min(block_end_pfn, end_pfn); - - if (!pageblock_pfn_to_page(block_start_pfn, - block_end_pfn, cc->zone)) - continue; - - pfn = isolate_migratepages_block(cc, pfn, block_end_pfn, - ISOLATE_UNEVICTABLE); - - if (!pfn) - break; - - if (cc->nr_migratepages == COMPACT_CLUSTER_MAX) - break; - } - acct_isolated(cc->zone, cc); - - return pfn; -} - -#endif /* CONFIG_COMPACTION || CONFIG_CMA */ -#ifdef CONFIG_COMPACTION - -/* Returns true if the page is within a block suitable for migration to */ -static bool suitable_migration_target(struct compact_control *cc, - struct page *page) -{ - if (cc->ignore_block_suitable) - return true; - - /* If the page is a large free page, then disallow migration */ - if (PageBuddy(page)) { - /* - * We are checking page_order without zone->lock taken. But - * the only small danger is that we skip a potentially suitable - * pageblock, so it's not worth to check order for valid range. - */ - if (page_order_unsafe(page) >= pageblock_order) - return false; - } - - /* If the block is MIGRATE_MOVABLE or MIGRATE_CMA, allow migration */ - if (migrate_async_suitable(get_pageblock_migratetype(page))) - return true; - - /* Otherwise skip the block */ - return false; -} - -/* - * Test whether the free scanner has reached the same or lower pageblock than - * the migration scanner, and compaction should thus terminate. - */ -static inline bool compact_scanners_met(struct compact_control *cc) -{ - return (cc->free_pfn >> pageblock_order) - <= (cc->migrate_pfn >> pageblock_order); -} - -/* - * Based on information in the current compact_control, find blocks - * suitable for isolating free pages from and then isolate them. - */ -static void isolate_freepages(struct compact_control *cc) -{ - struct zone *zone = cc->zone; - struct page *page; - unsigned long block_start_pfn; /* start of current pageblock */ - unsigned long isolate_start_pfn; /* exact pfn we start at */ - unsigned long block_end_pfn; /* end of current pageblock */ - unsigned long low_pfn; /* lowest pfn scanner is able to scan */ - struct list_head *freelist = &cc->freepages; - - /* - * Initialise the free scanner. The starting point is where we last - * successfully isolated from, zone-cached value, or the end of the - * zone when isolating for the first time. For looping we also need - * this pfn aligned down to the pageblock boundary, because we do - * block_start_pfn -= pageblock_nr_pages in the for loop. - * For ending point, take care when isolating in last pageblock of a - * a zone which ends in the middle of a pageblock. - * The low boundary is the end of the pageblock the migration scanner - * is using. - */ - isolate_start_pfn = cc->free_pfn; - block_start_pfn = pageblock_start_pfn(cc->free_pfn); - block_end_pfn = min(block_start_pfn + pageblock_nr_pages, - zone_end_pfn(zone)); - low_pfn = pageblock_end_pfn(cc->migrate_pfn); - - /* - * Isolate free pages until enough are available to migrate the - * pages on cc->migratepages. We stop searching if the migrate - * and free page scanners meet or enough free pages are isolated. - */ - for (; block_start_pfn >= low_pfn; - block_end_pfn = block_start_pfn, - block_start_pfn -= pageblock_nr_pages, - isolate_start_pfn = block_start_pfn) { - /* - * This can iterate a massively long zone without finding any - * suitable migration targets, so periodically check if we need - * to schedule, or even abort async compaction. - */ - if (!(block_start_pfn % (SWAP_CLUSTER_MAX * pageblock_nr_pages)) - && compact_should_abort(cc)) - break; - - page = pageblock_pfn_to_page(block_start_pfn, block_end_pfn, - zone); - if (!page) - continue; - - /* Check the block is suitable for migration */ - if (!suitable_migration_target(cc, page)) - continue; - - /* If isolation recently failed, do not retry */ - if (!isolation_suitable(cc, page)) - continue; - - /* Found a block suitable for isolating free pages from. */ - isolate_freepages_block(cc, &isolate_start_pfn, block_end_pfn, - freelist, false); - - /* - * If we isolated enough freepages, or aborted due to lock - * contention, terminate. - */ - if ((cc->nr_freepages >= cc->nr_migratepages) - || cc->contended) { - if (isolate_start_pfn >= block_end_pfn) { - /* - * Restart at previous pageblock if more - * freepages can be isolated next time. - */ - isolate_start_pfn = - block_start_pfn - pageblock_nr_pages; - } - break; - } else if (isolate_start_pfn < block_end_pfn) { - /* - * If isolation failed early, do not continue - * needlessly. - */ - break; - } - } - - /* __isolate_free_page() does not map the pages */ - map_pages(freelist); - - /* - * Record where the free scanner will restart next time. Either we - * broke from the loop and set isolate_start_pfn based on the last - * call to isolate_freepages_block(), or we met the migration scanner - * and the loop terminated due to isolate_start_pfn < low_pfn - */ - cc->free_pfn = isolate_start_pfn; -} - -/* - * This is a migrate-callback that "allocates" freepages by taking pages - * from the isolated freelists in the block we are migrating to. - */ -static struct page *compaction_alloc(struct page *migratepage, - unsigned long data, - int **result) -{ - struct compact_control *cc = (struct compact_control *)data; - struct page *freepage; - - /* - * Isolate free pages if necessary, and if we are not aborting due to - * contention. - */ - if (list_empty(&cc->freepages)) { - if (!cc->contended) - isolate_freepages(cc); - - if (list_empty(&cc->freepages)) - return NULL; - } - - freepage = list_entry(cc->freepages.next, struct page, lru); - list_del(&freepage->lru); - cc->nr_freepages--; - - return freepage; -} - -/* - * This is a migrate-callback that "frees" freepages back to the isolated - * freelist. All pages on the freelist are from the same zone, so there is no - * special handling needed for NUMA. - */ -static void compaction_free(struct page *page, unsigned long data) -{ - struct compact_control *cc = (struct compact_control *)data; - - list_add(&page->lru, &cc->freepages); - cc->nr_freepages++; -} - -/* possible outcome of isolate_migratepages */ -typedef enum { - ISOLATE_ABORT, /* Abort compaction now */ - ISOLATE_NONE, /* No pages isolated, continue scanning */ - ISOLATE_SUCCESS, /* Pages isolated, migrate */ -} isolate_migrate_t; - -/* - * Allow userspace to control policy on scanning the unevictable LRU for - * compactable pages. - */ -int sysctl_compact_unevictable_allowed __read_mostly = 1; - -/* - * Isolate all pages that can be migrated from the first suitable block, - * starting at the block pointed to by the migrate scanner pfn within - * compact_control. - */ -static isolate_migrate_t isolate_migratepages(struct zone *zone, - struct compact_control *cc) -{ - unsigned long block_start_pfn; - unsigned long block_end_pfn; - unsigned long low_pfn; - struct page *page; - const isolate_mode_t isolate_mode = - (sysctl_compact_unevictable_allowed ? ISOLATE_UNEVICTABLE : 0) | - (cc->mode != MIGRATE_SYNC ? ISOLATE_ASYNC_MIGRATE : 0); - - /* - * Start at where we last stopped, or beginning of the zone as - * initialized by compact_zone() - */ - low_pfn = cc->migrate_pfn; - block_start_pfn = pageblock_start_pfn(low_pfn); - if (block_start_pfn < zone->zone_start_pfn) - block_start_pfn = zone->zone_start_pfn; - - /* Only scan within a pageblock boundary */ - block_end_pfn = pageblock_end_pfn(low_pfn); - - /* - * Iterate over whole pageblocks until we find the first suitable. - * Do not cross the free scanner. - */ - for (; block_end_pfn <= cc->free_pfn; - low_pfn = block_end_pfn, - block_start_pfn = block_end_pfn, - block_end_pfn += pageblock_nr_pages) { - - /* - * This can potentially iterate a massively long zone with - * many pageblocks unsuitable, so periodically check if we - * need to schedule, or even abort async compaction. - */ - if (!(low_pfn % (SWAP_CLUSTER_MAX * pageblock_nr_pages)) - && compact_should_abort(cc)) - break; - - page = pageblock_pfn_to_page(block_start_pfn, block_end_pfn, - zone); - if (!page) - continue; - - /* If isolation recently failed, do not retry */ - if (!isolation_suitable(cc, page)) - continue; - - /* - * For async compaction, also only scan in MOVABLE blocks. - * Async compaction is optimistic to see if the minimum amount - * of work satisfies the allocation. - */ - if (cc->mode == MIGRATE_ASYNC && - !migrate_async_suitable(get_pageblock_migratetype(page))) - continue; - - /* Perform the isolation */ - low_pfn = isolate_migratepages_block(cc, low_pfn, - block_end_pfn, isolate_mode); - - if (!low_pfn || cc->contended) { - acct_isolated(zone, cc); - return ISOLATE_ABORT; - } - - /* - * Either we isolated something and proceed with migration. Or - * we failed and compact_zone should decide if we should - * continue or not. - */ - break; - } - - acct_isolated(zone, cc); - /* Record where migration scanner will be restarted. */ - cc->migrate_pfn = low_pfn; - - return cc->nr_migratepages ? ISOLATE_SUCCESS : ISOLATE_NONE; -} - -/* - * order == -1 is expected when compacting via - * /proc/sys/vm/compact_memory - */ -static inline bool is_via_compact_memory(int order) -{ - return order == -1; -} - -static enum compact_result __compact_finished(struct zone *zone, struct compact_control *cc, - const int migratetype) -{ - unsigned int order; - unsigned long watermark; - - if (cc->contended || fatal_signal_pending(current)) - return COMPACT_CONTENDED; - - /* Compaction run completes if the migrate and free scanner meet */ - if (compact_scanners_met(cc)) { - /* Let the next compaction start anew. */ - reset_cached_positions(zone); - - /* - * Mark that the PG_migrate_skip information should be cleared - * by kswapd when it goes to sleep. kcompactd does not set the - * flag itself as the decision to be clear should be directly - * based on an allocation request. - */ - if (cc->direct_compaction) - zone->compact_blockskip_flush = true; - - if (cc->whole_zone) - return COMPACT_COMPLETE; - else - return COMPACT_PARTIAL_SKIPPED; - } - - if (is_via_compact_memory(cc->order)) - return COMPACT_CONTINUE; - - /* Compaction run is not finished if the watermark is not met */ - watermark = zone->watermark[cc->alloc_flags & ALLOC_WMARK_MASK]; - - if (!zone_watermark_ok(zone, cc->order, watermark, cc->classzone_idx, - cc->alloc_flags)) - return COMPACT_CONTINUE; - - /* Direct compactor: Is a suitable page free? */ - for (order = cc->order; order < MAX_ORDER; order++) { - struct free_area *area = &zone->free_area[order]; - bool can_steal; - - /* Job done if page is free of the right migratetype */ - if (!list_empty(&area->free_list[migratetype])) - return COMPACT_SUCCESS; - -#ifdef CONFIG_CMA - /* MIGRATE_MOVABLE can fallback on MIGRATE_CMA */ - if (migratetype == MIGRATE_MOVABLE && - !list_empty(&area->free_list[MIGRATE_CMA])) - return COMPACT_SUCCESS; -#endif - /* - * Job done if allocation would steal freepages from - * other migratetype buddy lists. - */ - if (find_suitable_fallback(area, order, migratetype, - true, &can_steal) != -1) - return COMPACT_SUCCESS; - } - - return COMPACT_NO_SUITABLE_PAGE; -} - -static enum compact_result compact_finished(struct zone *zone, - struct compact_control *cc, - const int migratetype) -{ - int ret; - - ret = __compact_finished(zone, cc, migratetype); - trace_mm_compaction_finished(zone, cc->order, ret); - if (ret == COMPACT_NO_SUITABLE_PAGE) - ret = COMPACT_CONTINUE; - - return ret; -} - -/* - * compaction_suitable: Is this suitable to run compaction on this zone now? - * Returns - * COMPACT_SKIPPED - If there are too few free pages for compaction - * COMPACT_SUCCESS - If the allocation would succeed without compaction - * COMPACT_CONTINUE - If compaction should run now - */ -static enum compact_result __compaction_suitable(struct zone *zone, int order, - unsigned int alloc_flags, - int classzone_idx, - unsigned long wmark_target) -{ - unsigned long watermark; - - if (is_via_compact_memory(order)) - return COMPACT_CONTINUE; - - watermark = zone->watermark[alloc_flags & ALLOC_WMARK_MASK]; - /* - * If watermarks for high-order allocation are already met, there - * should be no need for compaction at all. - */ - if (zone_watermark_ok(zone, order, watermark, classzone_idx, - alloc_flags)) - return COMPACT_SUCCESS; - - /* - * Watermarks for order-0 must be met for compaction to be able to - * isolate free pages for migration targets. This means that the - * watermark and alloc_flags have to match, or be more pessimistic than - * the check in __isolate_free_page(). We don't use the direct - * compactor's alloc_flags, as they are not relevant for freepage - * isolation. We however do use the direct compactor's classzone_idx to - * skip over zones where lowmem reserves would prevent allocation even - * if compaction succeeds. - * For costly orders, we require low watermark instead of min for - * compaction to proceed to increase its chances. - * ALLOC_CMA is used, as pages in CMA pageblocks are considered - * suitable migration targets - */ - watermark = (order > PAGE_ALLOC_COSTLY_ORDER) ? - low_wmark_pages(zone) : min_wmark_pages(zone); - watermark += compact_gap(order); - if (!__zone_watermark_ok(zone, 0, watermark, classzone_idx, - ALLOC_CMA, wmark_target)) - return COMPACT_SKIPPED; - - return COMPACT_CONTINUE; -} - -enum compact_result compaction_suitable(struct zone *zone, int order, - unsigned int alloc_flags, - int classzone_idx) -{ - enum compact_result ret; - int fragindex; - - ret = __compaction_suitable(zone, order, alloc_flags, classzone_idx, - zone_page_state(zone, NR_FREE_PAGES)); - /* - * fragmentation index determines if allocation failures are due to - * low memory or external fragmentation - * - * index of -1000 would imply allocations might succeed depending on - * watermarks, but we already failed the high-order watermark check - * index towards 0 implies failure is due to lack of memory - * index towards 1000 implies failure is due to fragmentation - * - * Only compact if a failure would be due to fragmentation. Also - * ignore fragindex for non-costly orders where the alternative to - * a successful reclaim/compaction is OOM. Fragindex and the - * vm.extfrag_threshold sysctl is meant as a heuristic to prevent - * excessive compaction for costly orders, but it should not be at the - * expense of system stability. - */ - if (ret == COMPACT_CONTINUE && (order > PAGE_ALLOC_COSTLY_ORDER)) { - fragindex = fragmentation_index(zone, order); - if (fragindex >= 0 && fragindex <= sysctl_extfrag_threshold) - ret = COMPACT_NOT_SUITABLE_ZONE; - } - - trace_mm_compaction_suitable(zone, order, ret); - if (ret == COMPACT_NOT_SUITABLE_ZONE) - ret = COMPACT_SKIPPED; - - return ret; -} - -bool compaction_zonelist_suitable(struct alloc_context *ac, int order, - int alloc_flags) -{ - struct zone *zone; - struct zoneref *z; - - /* - * Make sure at least one zone would pass __compaction_suitable if we continue - * retrying the reclaim. - */ - for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx, - ac->nodemask) { - unsigned long available; - enum compact_result compact_result; - - /* - * Do not consider all the reclaimable memory because we do not - * want to trash just for a single high order allocation which - * is even not guaranteed to appear even if __compaction_suitable - * is happy about the watermark check. - */ - available = zone_reclaimable_pages(zone) / order; - available += zone_page_state_snapshot(zone, NR_FREE_PAGES); - compact_result = __compaction_suitable(zone, order, alloc_flags, - ac_classzone_idx(ac), available); - if (compact_result != COMPACT_SKIPPED) - return true; - } - - return false; -} - -static enum compact_result compact_zone(struct zone *zone, struct compact_control *cc) -{ - enum compact_result ret; - unsigned long start_pfn = zone->zone_start_pfn; - unsigned long end_pfn = zone_end_pfn(zone); - const int migratetype = gfpflags_to_migratetype(cc->gfp_mask); - const bool sync = cc->mode != MIGRATE_ASYNC; - - ret = compaction_suitable(zone, cc->order, cc->alloc_flags, - cc->classzone_idx); - /* Compaction is likely to fail */ - if (ret == COMPACT_SUCCESS || ret == COMPACT_SKIPPED) - return ret; - - /* huh, compaction_suitable is returning something unexpected */ - VM_BUG_ON(ret != COMPACT_CONTINUE); - - /* - * Clear pageblock skip if there were failures recently and compaction - * is about to be retried after being deferred. - */ - if (compaction_restarting(zone, cc->order)) - __reset_isolation_suitable(zone); - - /* - * Setup to move all movable pages to the end of the zone. Used cached - * information on where the scanners should start (unless we explicitly - * want to compact the whole zone), but check that it is initialised - * by ensuring the values are within zone boundaries. - */ - if (cc->whole_zone) { - cc->migrate_pfn = start_pfn; - cc->free_pfn = pageblock_start_pfn(end_pfn - 1); - } else { - cc->migrate_pfn = zone->compact_cached_migrate_pfn[sync]; - cc->free_pfn = zone->compact_cached_free_pfn; - if (cc->free_pfn < start_pfn || cc->free_pfn >= end_pfn) { - cc->free_pfn = pageblock_start_pfn(end_pfn - 1); - zone->compact_cached_free_pfn = cc->free_pfn; - } - if (cc->migrate_pfn < start_pfn || cc->migrate_pfn >= end_pfn) { - cc->migrate_pfn = start_pfn; - zone->compact_cached_migrate_pfn[0] = cc->migrate_pfn; - zone->compact_cached_migrate_pfn[1] = cc->migrate_pfn; - } - - if (cc->migrate_pfn == start_pfn) - cc->whole_zone = true; - } - - cc->last_migrated_pfn = 0; - - trace_mm_compaction_begin(start_pfn, cc->migrate_pfn, - cc->free_pfn, end_pfn, sync); - - migrate_prep_local(); - - while ((ret = compact_finished(zone, cc, migratetype)) == - COMPACT_CONTINUE) { - int err; - - switch (isolate_migratepages(zone, cc)) { - case ISOLATE_ABORT: - ret = COMPACT_CONTENDED; - putback_movable_pages(&cc->migratepages); - cc->nr_migratepages = 0; - goto out; - case ISOLATE_NONE: - /* - * We haven't isolated and migrated anything, but - * there might still be unflushed migrations from - * previous cc->order aligned block. - */ - goto check_drain; - case ISOLATE_SUCCESS: - ; - } - - err = migrate_pages(&cc->migratepages, compaction_alloc, - compaction_free, (unsigned long)cc, cc->mode, - MR_COMPACTION); - - trace_mm_compaction_migratepages(cc->nr_migratepages, err, - &cc->migratepages); - - /* All pages were either migrated or will be released */ - cc->nr_migratepages = 0; - if (err) { - putback_movable_pages(&cc->migratepages); - /* - * migrate_pages() may return -ENOMEM when scanners meet - * and we want compact_finished() to detect it - */ - if (err == -ENOMEM && !compact_scanners_met(cc)) { - ret = COMPACT_CONTENDED; - goto out; - } - /* - * We failed to migrate at least one page in the current - * order-aligned block, so skip the rest of it. - */ - if (cc->direct_compaction && - (cc->mode == MIGRATE_ASYNC)) { - cc->migrate_pfn = block_end_pfn( - cc->migrate_pfn - 1, cc->order); - /* Draining pcplists is useless in this case */ - cc->last_migrated_pfn = 0; - - } - } - -check_drain: - /* - * Has the migration scanner moved away from the previous - * cc->order aligned block where we migrated from? If yes, - * flush the pages that were freed, so that they can merge and - * compact_finished() can detect immediately if allocation - * would succeed. - */ - if (cc->order > 0 && cc->last_migrated_pfn) { - int cpu; - unsigned long current_block_start = - block_start_pfn(cc->migrate_pfn, cc->order); - - if (cc->last_migrated_pfn < current_block_start) { - cpu = get_cpu(); - lru_add_drain_cpu(cpu); - drain_local_pages(zone); - put_cpu(); - /* No more flushing until we migrate again */ - cc->last_migrated_pfn = 0; - } - } - - } - -out: - /* - * Release free pages and update where the free scanner should restart, - * so we don't leave any returned pages behind in the next attempt. - */ - if (cc->nr_freepages > 0) { - unsigned long free_pfn = release_freepages(&cc->freepages); - - cc->nr_freepages = 0; - VM_BUG_ON(free_pfn == 0); - /* The cached pfn is always the first in a pageblock */ - free_pfn = pageblock_start_pfn(free_pfn); - /* - * Only go back, not forward. The cached pfn might have been - * already reset to zone end in compact_finished() - */ - if (free_pfn > zone->compact_cached_free_pfn) - zone->compact_cached_free_pfn = free_pfn; - } - - trace_mm_compaction_end(start_pfn, cc->migrate_pfn, - cc->free_pfn, end_pfn, sync, ret); - - return ret; -} - -static enum compact_result compact_zone_order(struct zone *zone, int order, - gfp_t gfp_mask, enum compact_priority prio, - unsigned int alloc_flags, int classzone_idx) -{ - enum compact_result ret; - struct compact_control cc = { - .nr_freepages = 0, - .nr_migratepages = 0, - .order = order, - .gfp_mask = gfp_mask, - .zone = zone, - .mode = (prio == COMPACT_PRIO_ASYNC) ? - MIGRATE_ASYNC : MIGRATE_SYNC_LIGHT, - .alloc_flags = alloc_flags, - .classzone_idx = classzone_idx, - .direct_compaction = true, - .whole_zone = (prio == MIN_COMPACT_PRIORITY), - .ignore_skip_hint = (prio == MIN_COMPACT_PRIORITY), - .ignore_block_suitable = (prio == MIN_COMPACT_PRIORITY) - }; - INIT_LIST_HEAD(&cc.freepages); - INIT_LIST_HEAD(&cc.migratepages); - - ret = compact_zone(zone, &cc); - - VM_BUG_ON(!list_empty(&cc.freepages)); - VM_BUG_ON(!list_empty(&cc.migratepages)); - - return ret; -} - -int sysctl_extfrag_threshold = 500; - -/** - * try_to_compact_pages - Direct compact to satisfy a high-order allocation - * @gfp_mask: The GFP mask of the current allocation - * @order: The order of the current allocation - * @alloc_flags: The allocation flags of the current allocation - * @ac: The context of current allocation - * @mode: The migration mode for async, sync light, or sync migration - * - * This is the main entry point for direct page compaction. - */ -enum compact_result try_to_compact_pages(gfp_t gfp_mask, unsigned int order, - unsigned int alloc_flags, const struct alloc_context *ac, - enum compact_priority prio) -{ - int may_enter_fs = gfp_mask & __GFP_FS; - int may_perform_io = gfp_mask & __GFP_IO; - struct zoneref *z; - struct zone *zone; - enum compact_result rc = COMPACT_SKIPPED; - - /* Check if the GFP flags allow compaction */ - if (!may_enter_fs || !may_perform_io) - return COMPACT_SKIPPED; - - trace_mm_compaction_try_to_compact_pages(order, gfp_mask, prio); - - /* Compact each zone in the list */ - for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx, - ac->nodemask) { - enum compact_result status; - - if (prio > MIN_COMPACT_PRIORITY - && compaction_deferred(zone, order)) { - rc = max_t(enum compact_result, COMPACT_DEFERRED, rc); - continue; - } - - status = compact_zone_order(zone, order, gfp_mask, prio, - alloc_flags, ac_classzone_idx(ac)); - rc = max(status, rc); - - /* The allocation should succeed, stop compacting */ - if (status == COMPACT_SUCCESS) { - /* - * We think the allocation will succeed in this zone, - * but it is not certain, hence the false. The caller - * will repeat this with true if allocation indeed - * succeeds in this zone. - */ - compaction_defer_reset(zone, order, false); - - break; - } - - if (prio != COMPACT_PRIO_ASYNC && (status == COMPACT_COMPLETE || - status == COMPACT_PARTIAL_SKIPPED)) - /* - * We think that allocation won't succeed in this zone - * so we defer compaction there. If it ends up - * succeeding after all, it will be reset. - */ - defer_compaction(zone, order); - - /* - * We might have stopped compacting due to need_resched() in - * async compaction, or due to a fatal signal detected. In that - * case do not try further zones - */ - if ((prio == COMPACT_PRIO_ASYNC && need_resched()) - || fatal_signal_pending(current)) - break; - } - - return rc; -} - - -/* Compact all zones within a node */ -static void compact_node(int nid) -{ - pg_data_t *pgdat = NODE_DATA(nid); - int zoneid; - struct zone *zone; - struct compact_control cc = { - .order = -1, - .mode = MIGRATE_SYNC, - .ignore_skip_hint = true, - .whole_zone = true, - }; - - - for (zoneid = 0; zoneid < MAX_NR_ZONES; zoneid++) { - - zone = &pgdat->node_zones[zoneid]; - if (!populated_zone(zone)) - continue; - - cc.nr_freepages = 0; - cc.nr_migratepages = 0; - cc.zone = zone; - INIT_LIST_HEAD(&cc.freepages); - INIT_LIST_HEAD(&cc.migratepages); - - compact_zone(zone, &cc); - - VM_BUG_ON(!list_empty(&cc.freepages)); - VM_BUG_ON(!list_empty(&cc.migratepages)); - } -} - -/* Compact all nodes in the system */ -static void compact_nodes(void) -{ - int nid; - - /* Flush pending updates to the LRU lists */ - lru_add_drain_all(); - - for_each_online_node(nid) - compact_node(nid); -} - -/* The written value is actually unused, all memory is compacted */ -int sysctl_compact_memory; - -/* - * This is the entry point for compacting all nodes via - * /proc/sys/vm/compact_memory - */ -int sysctl_compaction_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *length, loff_t *ppos) -{ - if (write) - compact_nodes(); - - return 0; -} - -int sysctl_extfrag_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *length, loff_t *ppos) -{ - proc_dointvec_minmax(table, write, buffer, length, ppos); - - return 0; -} - -#if defined(CONFIG_SYSFS) && defined(CONFIG_NUMA) -static ssize_t sysfs_compact_node(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - int nid = dev->id; - - if (nid >= 0 && nid < nr_node_ids && node_online(nid)) { - /* Flush pending updates to the LRU lists */ - lru_add_drain_all(); - - compact_node(nid); - } - - return count; -} -static DEVICE_ATTR(compact, S_IWUSR, NULL, sysfs_compact_node); - -int compaction_register_node(struct node *node) -{ - return device_create_file(&node->dev, &dev_attr_compact); -} - -void compaction_unregister_node(struct node *node) -{ - return device_remove_file(&node->dev, &dev_attr_compact); -} -#endif /* CONFIG_SYSFS && CONFIG_NUMA */ - -static inline bool kcompactd_work_requested(pg_data_t *pgdat) -{ - return pgdat->kcompactd_max_order > 0 || kthread_should_stop(); -} - -static bool kcompactd_node_suitable(pg_data_t *pgdat) -{ - int zoneid; - struct zone *zone; - enum zone_type classzone_idx = pgdat->kcompactd_classzone_idx; - - for (zoneid = 0; zoneid <= classzone_idx; zoneid++) { - zone = &pgdat->node_zones[zoneid]; - - if (!populated_zone(zone)) - continue; - - if (compaction_suitable(zone, pgdat->kcompactd_max_order, 0, - classzone_idx) == COMPACT_CONTINUE) - return true; - } - - return false; -} - -static void kcompactd_do_work(pg_data_t *pgdat) -{ - /* - * With no special task, compact all zones so that a page of requested - * order is allocatable. - */ - int zoneid; - struct zone *zone; - struct compact_control cc = { - .order = pgdat->kcompactd_max_order, - .classzone_idx = pgdat->kcompactd_classzone_idx, - .mode = MIGRATE_SYNC_LIGHT, - .ignore_skip_hint = true, - - }; - trace_mm_compaction_kcompactd_wake(pgdat->node_id, cc.order, - cc.classzone_idx); - count_vm_event(KCOMPACTD_WAKE); - - for (zoneid = 0; zoneid <= cc.classzone_idx; zoneid++) { - int status; - - zone = &pgdat->node_zones[zoneid]; - if (!populated_zone(zone)) - continue; - - if (compaction_deferred(zone, cc.order)) - continue; - - if (compaction_suitable(zone, cc.order, 0, zoneid) != - COMPACT_CONTINUE) - continue; - - cc.nr_freepages = 0; - cc.nr_migratepages = 0; - cc.zone = zone; - INIT_LIST_HEAD(&cc.freepages); - INIT_LIST_HEAD(&cc.migratepages); - - if (kthread_should_stop()) - return; - status = compact_zone(zone, &cc); - - if (status == COMPACT_SUCCESS) { - compaction_defer_reset(zone, cc.order, false); - } else if (status == COMPACT_PARTIAL_SKIPPED || status == COMPACT_COMPLETE) { - /* - * We use sync migration mode here, so we defer like - * sync direct compaction does. - */ - defer_compaction(zone, cc.order); - } - - VM_BUG_ON(!list_empty(&cc.freepages)); - VM_BUG_ON(!list_empty(&cc.migratepages)); - } - - /* - * Regardless of success, we are done until woken up next. But remember - * the requested order/classzone_idx in case it was higher/tighter than - * our current ones - */ - if (pgdat->kcompactd_max_order <= cc.order) - pgdat->kcompactd_max_order = 0; - if (pgdat->kcompactd_classzone_idx >= cc.classzone_idx) - pgdat->kcompactd_classzone_idx = pgdat->nr_zones - 1; -} - -void wakeup_kcompactd(pg_data_t *pgdat, int order, int classzone_idx) -{ - if (!order) - return; - - if (pgdat->kcompactd_max_order < order) - pgdat->kcompactd_max_order = order; - - if (pgdat->kcompactd_classzone_idx > classzone_idx) - pgdat->kcompactd_classzone_idx = classzone_idx; - - if (!waitqueue_active(&pgdat->kcompactd_wait)) - return; - - if (!kcompactd_node_suitable(pgdat)) - return; - - trace_mm_compaction_wakeup_kcompactd(pgdat->node_id, order, - classzone_idx); - wake_up_interruptible(&pgdat->kcompactd_wait); -} - -/* - * The background compaction daemon, started as a kernel thread - * from the init process. - */ -static int kcompactd(void *p) -{ - pg_data_t *pgdat = (pg_data_t*)p; - struct task_struct *tsk = current; - - const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id); - - if (!cpumask_empty(cpumask)) - set_cpus_allowed_ptr(tsk, cpumask); - - set_freezable(); - - pgdat->kcompactd_max_order = 0; - pgdat->kcompactd_classzone_idx = pgdat->nr_zones - 1; - - while (!kthread_should_stop()) { - trace_mm_compaction_kcompactd_sleep(pgdat->node_id); - wait_event_freezable(pgdat->kcompactd_wait, - kcompactd_work_requested(pgdat)); - - kcompactd_do_work(pgdat); - } - - return 0; -} - -/* - * This kcompactd start function will be called by init and node-hot-add. - * On node-hot-add, kcompactd will moved to proper cpus if cpus are hot-added. - */ -int kcompactd_run(int nid) -{ - pg_data_t *pgdat = NODE_DATA(nid); - int ret = 0; - - if (pgdat->kcompactd) - return 0; - - pgdat->kcompactd = kthread_run(kcompactd, pgdat, "kcompactd%d", nid); - if (IS_ERR(pgdat->kcompactd)) { - pr_err("Failed to start kcompactd on node %d\n", nid); - ret = PTR_ERR(pgdat->kcompactd); - pgdat->kcompactd = NULL; - } - return ret; -} - -/* - * Called by memory hotplug when all memory in a node is offlined. Caller must - * hold mem_hotplug_begin/end(). - */ -void kcompactd_stop(int nid) -{ - struct task_struct *kcompactd = NODE_DATA(nid)->kcompactd; - - if (kcompactd) { - kthread_stop(kcompactd); - NODE_DATA(nid)->kcompactd = NULL; - } -} - -/* - * It's optimal to keep kcompactd on the same CPUs as their memory, but - * not required for correctness. So if the last cpu in a node goes - * away, we get changed to run anywhere: as the first one comes back, - * restore their cpu bindings. - */ -static int cpu_callback(struct notifier_block *nfb, unsigned long action, - void *hcpu) -{ - int nid; - - if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN) { - for_each_node_state(nid, N_MEMORY) { - pg_data_t *pgdat = NODE_DATA(nid); - const struct cpumask *mask; - - mask = cpumask_of_node(pgdat->node_id); - - if (cpumask_any_and(cpu_online_mask, mask) < nr_cpu_ids) - /* One of our CPUs online: restore mask */ - set_cpus_allowed_ptr(pgdat->kcompactd, mask); - } - } - return NOTIFY_OK; -} - -static int __init kcompactd_init(void) -{ - int nid; - - for_each_node_state(nid, N_MEMORY) - kcompactd_run(nid); - hotcpu_notifier(cpu_callback, 0); - return 0; -} -subsys_initcall(kcompactd_init) - -#endif /* CONFIG_COMPACTION */ diff --git a/src/linux/mm/debug.c b/src/linux/mm/debug.c deleted file mode 100644 index 9feb699..0000000 --- a/src/linux/mm/debug.c +++ /dev/null @@ -1,164 +0,0 @@ -/* - * mm/debug.c - * - * mm/ specific debug routines. - * - */ - -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -char *migrate_reason_names[MR_TYPES] = { - "compaction", - "memory_failure", - "memory_hotplug", - "syscall_or_cpuset", - "mempolicy_mbind", - "numa_misplaced", - "cma", -}; - -const struct trace_print_flags pageflag_names[] = { - __def_pageflag_names, - {0, NULL} -}; - -const struct trace_print_flags gfpflag_names[] = { - __def_gfpflag_names, - {0, NULL} -}; - -const struct trace_print_flags vmaflag_names[] = { - __def_vmaflag_names, - {0, NULL} -}; - -void __dump_page(struct page *page, const char *reason) -{ - /* - * Avoid VM_BUG_ON() in page_mapcount(). - * page->_mapcount space in struct page is used by sl[aou]b pages to - * encode own info. - */ - int mapcount = PageSlab(page) ? 0 : page_mapcount(page); - - pr_emerg("page:%p count:%d mapcount:%d mapping:%p index:%#lx", - page, page_ref_count(page), mapcount, - page->mapping, page_to_pgoff(page)); - if (PageCompound(page)) - pr_cont(" compound_mapcount: %d", compound_mapcount(page)); - pr_cont("\n"); - BUILD_BUG_ON(ARRAY_SIZE(pageflag_names) != __NR_PAGEFLAGS + 1); - - pr_emerg("flags: %#lx(%pGp)\n", page->flags, &page->flags); - - if (reason) - pr_alert("page dumped because: %s\n", reason); - -#ifdef CONFIG_MEMCG - if (page->mem_cgroup) - pr_alert("page->mem_cgroup:%p\n", page->mem_cgroup); -#endif -} - -void dump_page(struct page *page, const char *reason) -{ - __dump_page(page, reason); - dump_page_owner(page); -} -EXPORT_SYMBOL(dump_page); - -#ifdef CONFIG_DEBUG_VM - -void dump_vma(const struct vm_area_struct *vma) -{ - pr_emerg("vma %p start %p end %p\n" - "next %p prev %p mm %p\n" - "prot %lx anon_vma %p vm_ops %p\n" - "pgoff %lx file %p private_data %p\n" - "flags: %#lx(%pGv)\n", - vma, (void *)vma->vm_start, (void *)vma->vm_end, vma->vm_next, - vma->vm_prev, vma->vm_mm, - (unsigned long)pgprot_val(vma->vm_page_prot), - vma->anon_vma, vma->vm_ops, vma->vm_pgoff, - vma->vm_file, vma->vm_private_data, - vma->vm_flags, &vma->vm_flags); -} -EXPORT_SYMBOL(dump_vma); - -void dump_mm(const struct mm_struct *mm) -{ - pr_emerg("mm %p mmap %p seqnum %d task_size %lu\n" -#ifdef CONFIG_MMU - "get_unmapped_area %p\n" -#endif - "mmap_base %lu mmap_legacy_base %lu highest_vm_end %lu\n" - "pgd %p mm_users %d mm_count %d nr_ptes %lu nr_pmds %lu map_count %d\n" - "hiwater_rss %lx hiwater_vm %lx total_vm %lx locked_vm %lx\n" - "pinned_vm %lx data_vm %lx exec_vm %lx stack_vm %lx\n" - "start_code %lx end_code %lx start_data %lx end_data %lx\n" - "start_brk %lx brk %lx start_stack %lx\n" - "arg_start %lx arg_end %lx env_start %lx env_end %lx\n" - "binfmt %p flags %lx core_state %p\n" -#ifdef CONFIG_AIO - "ioctx_table %p\n" -#endif -#ifdef CONFIG_MEMCG - "owner %p " -#endif - "exe_file %p\n" -#ifdef CONFIG_MMU_NOTIFIER - "mmu_notifier_mm %p\n" -#endif -#ifdef CONFIG_NUMA_BALANCING - "numa_next_scan %lu numa_scan_offset %lu numa_scan_seq %d\n" -#endif -#if defined(CONFIG_NUMA_BALANCING) || defined(CONFIG_COMPACTION) - "tlb_flush_pending %d\n" -#endif - "def_flags: %#lx(%pGv)\n", - - mm, mm->mmap, mm->vmacache_seqnum, mm->task_size, -#ifdef CONFIG_MMU - mm->get_unmapped_area, -#endif - mm->mmap_base, mm->mmap_legacy_base, mm->highest_vm_end, - mm->pgd, atomic_read(&mm->mm_users), - atomic_read(&mm->mm_count), - atomic_long_read((atomic_long_t *)&mm->nr_ptes), - mm_nr_pmds((struct mm_struct *)mm), - mm->map_count, - mm->hiwater_rss, mm->hiwater_vm, mm->total_vm, mm->locked_vm, - mm->pinned_vm, mm->data_vm, mm->exec_vm, mm->stack_vm, - mm->start_code, mm->end_code, mm->start_data, mm->end_data, - mm->start_brk, mm->brk, mm->start_stack, - mm->arg_start, mm->arg_end, mm->env_start, mm->env_end, - mm->binfmt, mm->flags, mm->core_state, -#ifdef CONFIG_AIO - mm->ioctx_table, -#endif -#ifdef CONFIG_MEMCG - mm->owner, -#endif - mm->exe_file, -#ifdef CONFIG_MMU_NOTIFIER - mm->mmu_notifier_mm, -#endif -#ifdef CONFIG_NUMA_BALANCING - mm->numa_next_scan, mm->numa_scan_offset, mm->numa_scan_seq, -#endif -#if defined(CONFIG_NUMA_BALANCING) || defined(CONFIG_COMPACTION) - mm->tlb_flush_pending, -#endif - mm->def_flags, &mm->def_flags - ); -} - -#endif /* CONFIG_DEBUG_VM */ diff --git a/src/linux/mm/dmapool.c b/src/linux/mm/dmapool.c deleted file mode 100644 index abcbfe8..0000000 --- a/src/linux/mm/dmapool.c +++ /dev/null @@ -1,533 +0,0 @@ -/* - * DMA Pool allocator - * - * Copyright 2001 David Brownell - * Copyright 2007 Intel Corporation - * Author: Matthew Wilcox - * - * This software may be redistributed and/or modified under the terms of - * the GNU General Public License ("GPL") version 2 as published by the - * Free Software Foundation. - * - * This allocator returns small blocks of a given size which are DMA-able by - * the given device. It uses the dma_alloc_coherent page allocator to get - * new pages, then splits them up into blocks of the required size. - * Many older drivers still have their own code to do this. - * - * The current design of this allocator is fairly simple. The pool is - * represented by the 'struct dma_pool' which keeps a doubly-linked list of - * allocated pages. Each page in the page_list is split into blocks of at - * least 'size' bytes. Free blocks are tracked in an unsorted singly-linked - * list of free blocks within the page. Used blocks aren't tracked, but we - * keep a count of how many are currently allocated from each page. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB_DEBUG_ON) -#define DMAPOOL_DEBUG 1 -#endif - -struct dma_pool { /* the pool */ - struct list_head page_list; - spinlock_t lock; - size_t size; - struct device *dev; - size_t allocation; - size_t boundary; - char name[32]; - struct list_head pools; -}; - -struct dma_page { /* cacheable header for 'allocation' bytes */ - struct list_head page_list; - void *vaddr; - dma_addr_t dma; - unsigned int in_use; - unsigned int offset; -}; - -static DEFINE_MUTEX(pools_lock); -static DEFINE_MUTEX(pools_reg_lock); - -static ssize_t -show_pools(struct device *dev, struct device_attribute *attr, char *buf) -{ - unsigned temp; - unsigned size; - char *next; - struct dma_page *page; - struct dma_pool *pool; - - next = buf; - size = PAGE_SIZE; - - temp = scnprintf(next, size, "poolinfo - 0.1\n"); - size -= temp; - next += temp; - - mutex_lock(&pools_lock); - list_for_each_entry(pool, &dev->dma_pools, pools) { - unsigned pages = 0; - unsigned blocks = 0; - - spin_lock_irq(&pool->lock); - list_for_each_entry(page, &pool->page_list, page_list) { - pages++; - blocks += page->in_use; - } - spin_unlock_irq(&pool->lock); - - /* per-pool info, no real statistics yet */ - temp = scnprintf(next, size, "%-16s %4u %4Zu %4Zu %2u\n", - pool->name, blocks, - pages * (pool->allocation / pool->size), - pool->size, pages); - size -= temp; - next += temp; - } - mutex_unlock(&pools_lock); - - return PAGE_SIZE - size; -} - -static DEVICE_ATTR(pools, S_IRUGO, show_pools, NULL); - -/** - * dma_pool_create - Creates a pool of consistent memory blocks, for dma. - * @name: name of pool, for diagnostics - * @dev: device that will be doing the DMA - * @size: size of the blocks in this pool. - * @align: alignment requirement for blocks; must be a power of two - * @boundary: returned blocks won't cross this power of two boundary - * Context: !in_interrupt() - * - * Returns a dma allocation pool with the requested characteristics, or - * null if one can't be created. Given one of these pools, dma_pool_alloc() - * may be used to allocate memory. Such memory will all have "consistent" - * DMA mappings, accessible by the device and its driver without using - * cache flushing primitives. The actual size of blocks allocated may be - * larger than requested because of alignment. - * - * If @boundary is nonzero, objects returned from dma_pool_alloc() won't - * cross that size boundary. This is useful for devices which have - * addressing restrictions on individual DMA transfers, such as not crossing - * boundaries of 4KBytes. - */ -struct dma_pool *dma_pool_create(const char *name, struct device *dev, - size_t size, size_t align, size_t boundary) -{ - struct dma_pool *retval; - size_t allocation; - bool empty = false; - - if (align == 0) - align = 1; - else if (align & (align - 1)) - return NULL; - - if (size == 0) - return NULL; - else if (size < 4) - size = 4; - - if ((size % align) != 0) - size = ALIGN(size, align); - - allocation = max_t(size_t, size, PAGE_SIZE); - - if (!boundary) - boundary = allocation; - else if ((boundary < size) || (boundary & (boundary - 1))) - return NULL; - - retval = kmalloc_node(sizeof(*retval), GFP_KERNEL, dev_to_node(dev)); - if (!retval) - return retval; - - strlcpy(retval->name, name, sizeof(retval->name)); - - retval->dev = dev; - - INIT_LIST_HEAD(&retval->page_list); - spin_lock_init(&retval->lock); - retval->size = size; - retval->boundary = boundary; - retval->allocation = allocation; - - INIT_LIST_HEAD(&retval->pools); - - /* - * pools_lock ensures that the ->dma_pools list does not get corrupted. - * pools_reg_lock ensures that there is not a race between - * dma_pool_create() and dma_pool_destroy() or within dma_pool_create() - * when the first invocation of dma_pool_create() failed on - * device_create_file() and the second assumes that it has been done (I - * know it is a short window). - */ - mutex_lock(&pools_reg_lock); - mutex_lock(&pools_lock); - if (list_empty(&dev->dma_pools)) - empty = true; - list_add(&retval->pools, &dev->dma_pools); - mutex_unlock(&pools_lock); - if (empty) { - int err; - - err = device_create_file(dev, &dev_attr_pools); - if (err) { - mutex_lock(&pools_lock); - list_del(&retval->pools); - mutex_unlock(&pools_lock); - mutex_unlock(&pools_reg_lock); - kfree(retval); - return NULL; - } - } - mutex_unlock(&pools_reg_lock); - return retval; -} -EXPORT_SYMBOL(dma_pool_create); - -static void pool_initialise_page(struct dma_pool *pool, struct dma_page *page) -{ - unsigned int offset = 0; - unsigned int next_boundary = pool->boundary; - - do { - unsigned int next = offset + pool->size; - if (unlikely((next + pool->size) >= next_boundary)) { - next = next_boundary; - next_boundary += pool->boundary; - } - *(int *)(page->vaddr + offset) = next; - offset = next; - } while (offset < pool->allocation); -} - -static struct dma_page *pool_alloc_page(struct dma_pool *pool, gfp_t mem_flags) -{ - struct dma_page *page; - - page = kmalloc(sizeof(*page), mem_flags); - if (!page) - return NULL; - page->vaddr = dma_alloc_coherent(pool->dev, pool->allocation, - &page->dma, mem_flags); - if (page->vaddr) { -#ifdef DMAPOOL_DEBUG - memset(page->vaddr, POOL_POISON_FREED, pool->allocation); -#endif - pool_initialise_page(pool, page); - page->in_use = 0; - page->offset = 0; - } else { - kfree(page); - page = NULL; - } - return page; -} - -static inline bool is_page_busy(struct dma_page *page) -{ - return page->in_use != 0; -} - -static void pool_free_page(struct dma_pool *pool, struct dma_page *page) -{ - dma_addr_t dma = page->dma; - -#ifdef DMAPOOL_DEBUG - memset(page->vaddr, POOL_POISON_FREED, pool->allocation); -#endif - dma_free_coherent(pool->dev, pool->allocation, page->vaddr, dma); - list_del(&page->page_list); - kfree(page); -} - -/** - * dma_pool_destroy - destroys a pool of dma memory blocks. - * @pool: dma pool that will be destroyed - * Context: !in_interrupt() - * - * Caller guarantees that no more memory from the pool is in use, - * and that nothing will try to use the pool after this call. - */ -void dma_pool_destroy(struct dma_pool *pool) -{ - bool empty = false; - - if (unlikely(!pool)) - return; - - mutex_lock(&pools_reg_lock); - mutex_lock(&pools_lock); - list_del(&pool->pools); - if (pool->dev && list_empty(&pool->dev->dma_pools)) - empty = true; - mutex_unlock(&pools_lock); - if (empty) - device_remove_file(pool->dev, &dev_attr_pools); - mutex_unlock(&pools_reg_lock); - - while (!list_empty(&pool->page_list)) { - struct dma_page *page; - page = list_entry(pool->page_list.next, - struct dma_page, page_list); - if (is_page_busy(page)) { - if (pool->dev) - dev_err(pool->dev, - "dma_pool_destroy %s, %p busy\n", - pool->name, page->vaddr); - else - pr_err("dma_pool_destroy %s, %p busy\n", - pool->name, page->vaddr); - /* leak the still-in-use consistent memory */ - list_del(&page->page_list); - kfree(page); - } else - pool_free_page(pool, page); - } - - kfree(pool); -} -EXPORT_SYMBOL(dma_pool_destroy); - -/** - * dma_pool_alloc - get a block of consistent memory - * @pool: dma pool that will produce the block - * @mem_flags: GFP_* bitmask - * @handle: pointer to dma address of block - * - * This returns the kernel virtual address of a currently unused block, - * and reports its dma address through the handle. - * If such a memory block can't be allocated, %NULL is returned. - */ -void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, - dma_addr_t *handle) -{ - unsigned long flags; - struct dma_page *page; - size_t offset; - void *retval; - - might_sleep_if(gfpflags_allow_blocking(mem_flags)); - - spin_lock_irqsave(&pool->lock, flags); - list_for_each_entry(page, &pool->page_list, page_list) { - if (page->offset < pool->allocation) - goto ready; - } - - /* pool_alloc_page() might sleep, so temporarily drop &pool->lock */ - spin_unlock_irqrestore(&pool->lock, flags); - - page = pool_alloc_page(pool, mem_flags & (~__GFP_ZERO)); - if (!page) - return NULL; - - spin_lock_irqsave(&pool->lock, flags); - - list_add(&page->page_list, &pool->page_list); - ready: - page->in_use++; - offset = page->offset; - page->offset = *(int *)(page->vaddr + offset); - retval = offset + page->vaddr; - *handle = offset + page->dma; -#ifdef DMAPOOL_DEBUG - { - int i; - u8 *data = retval; - /* page->offset is stored in first 4 bytes */ - for (i = sizeof(page->offset); i < pool->size; i++) { - if (data[i] == POOL_POISON_FREED) - continue; - if (pool->dev) - dev_err(pool->dev, - "dma_pool_alloc %s, %p (corrupted)\n", - pool->name, retval); - else - pr_err("dma_pool_alloc %s, %p (corrupted)\n", - pool->name, retval); - - /* - * Dump the first 4 bytes even if they are not - * POOL_POISON_FREED - */ - print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 16, 1, - data, pool->size, 1); - break; - } - } - if (!(mem_flags & __GFP_ZERO)) - memset(retval, POOL_POISON_ALLOCATED, pool->size); -#endif - spin_unlock_irqrestore(&pool->lock, flags); - - if (mem_flags & __GFP_ZERO) - memset(retval, 0, pool->size); - - return retval; -} -EXPORT_SYMBOL(dma_pool_alloc); - -static struct dma_page *pool_find_page(struct dma_pool *pool, dma_addr_t dma) -{ - struct dma_page *page; - - list_for_each_entry(page, &pool->page_list, page_list) { - if (dma < page->dma) - continue; - if ((dma - page->dma) < pool->allocation) - return page; - } - return NULL; -} - -/** - * dma_pool_free - put block back into dma pool - * @pool: the dma pool holding the block - * @vaddr: virtual address of block - * @dma: dma address of block - * - * Caller promises neither device nor driver will again touch this block - * unless it is first re-allocated. - */ -void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t dma) -{ - struct dma_page *page; - unsigned long flags; - unsigned int offset; - - spin_lock_irqsave(&pool->lock, flags); - page = pool_find_page(pool, dma); - if (!page) { - spin_unlock_irqrestore(&pool->lock, flags); - if (pool->dev) - dev_err(pool->dev, - "dma_pool_free %s, %p/%lx (bad dma)\n", - pool->name, vaddr, (unsigned long)dma); - else - pr_err("dma_pool_free %s, %p/%lx (bad dma)\n", - pool->name, vaddr, (unsigned long)dma); - return; - } - - offset = vaddr - page->vaddr; -#ifdef DMAPOOL_DEBUG - if ((dma - page->dma) != offset) { - spin_unlock_irqrestore(&pool->lock, flags); - if (pool->dev) - dev_err(pool->dev, - "dma_pool_free %s, %p (bad vaddr)/%Lx\n", - pool->name, vaddr, (unsigned long long)dma); - else - pr_err("dma_pool_free %s, %p (bad vaddr)/%Lx\n", - pool->name, vaddr, (unsigned long long)dma); - return; - } - { - unsigned int chain = page->offset; - while (chain < pool->allocation) { - if (chain != offset) { - chain = *(int *)(page->vaddr + chain); - continue; - } - spin_unlock_irqrestore(&pool->lock, flags); - if (pool->dev) - dev_err(pool->dev, "dma_pool_free %s, dma %Lx already free\n", - pool->name, (unsigned long long)dma); - else - pr_err("dma_pool_free %s, dma %Lx already free\n", - pool->name, (unsigned long long)dma); - return; - } - } - memset(vaddr, POOL_POISON_FREED, pool->size); -#endif - - page->in_use--; - *(int *)vaddr = page->offset; - page->offset = offset; - /* - * Resist a temptation to do - * if (!is_page_busy(page)) pool_free_page(pool, page); - * Better have a few empty pages hang around. - */ - spin_unlock_irqrestore(&pool->lock, flags); -} -EXPORT_SYMBOL(dma_pool_free); - -/* - * Managed DMA pool - */ -static void dmam_pool_release(struct device *dev, void *res) -{ - struct dma_pool *pool = *(struct dma_pool **)res; - - dma_pool_destroy(pool); -} - -static int dmam_pool_match(struct device *dev, void *res, void *match_data) -{ - return *(struct dma_pool **)res == match_data; -} - -/** - * dmam_pool_create - Managed dma_pool_create() - * @name: name of pool, for diagnostics - * @dev: device that will be doing the DMA - * @size: size of the blocks in this pool. - * @align: alignment requirement for blocks; must be a power of two - * @allocation: returned blocks won't cross this boundary (or zero) - * - * Managed dma_pool_create(). DMA pool created with this function is - * automatically destroyed on driver detach. - */ -struct dma_pool *dmam_pool_create(const char *name, struct device *dev, - size_t size, size_t align, size_t allocation) -{ - struct dma_pool **ptr, *pool; - - ptr = devres_alloc(dmam_pool_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return NULL; - - pool = *ptr = dma_pool_create(name, dev, size, align, allocation); - if (pool) - devres_add(dev, ptr); - else - devres_free(ptr); - - return pool; -} -EXPORT_SYMBOL(dmam_pool_create); - -/** - * dmam_pool_destroy - Managed dma_pool_destroy() - * @pool: dma pool that will be destroyed - * - * Managed dma_pool_destroy(). - */ -void dmam_pool_destroy(struct dma_pool *pool) -{ - struct device *dev = pool->dev; - - WARN_ON(devres_release(dev, dmam_pool_release, dmam_pool_match, pool)); -} -EXPORT_SYMBOL(dmam_pool_destroy); diff --git a/src/linux/mm/filemap.c b/src/linux/mm/filemap.c deleted file mode 100644 index 50b52fe..0000000 --- a/src/linux/mm/filemap.c +++ /dev/null @@ -1,2925 +0,0 @@ -/* - * linux/mm/filemap.c - * - * Copyright (C) 1994-1999 Linus Torvalds - */ - -/* - * This file handles the generic file mmap semantics used by - * most "normal" filesystems (but you don't /have/ to use this: - * the NFS filesystem used to do this differently, for example) - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for BUG_ON(!in_atomic()) only */ -#include -#include -#include -#include -#include "internal.h" - -#define CREATE_TRACE_POINTS -#include - -/* - * FIXME: remove all knowledge of the buffer layer from the core VM - */ -#include /* for try_to_free_buffers */ - -#include - -/* - * Shared mappings implemented 30.11.1994. It's not fully working yet, - * though. - * - * Shared mappings now work. 15.8.1995 Bruno. - * - * finished 'unifying' the page and buffer cache and SMP-threaded the - * page-cache, 21.05.1999, Ingo Molnar - * - * SMP-threaded pagemap-LRU 1999, Andrea Arcangeli - */ - -/* - * Lock ordering: - * - * ->i_mmap_rwsem (truncate_pagecache) - * ->private_lock (__free_pte->__set_page_dirty_buffers) - * ->swap_lock (exclusive_swap_page, others) - * ->mapping->tree_lock - * - * ->i_mutex - * ->i_mmap_rwsem (truncate->unmap_mapping_range) - * - * ->mmap_sem - * ->i_mmap_rwsem - * ->page_table_lock or pte_lock (various, mainly in memory.c) - * ->mapping->tree_lock (arch-dependent flush_dcache_mmap_lock) - * - * ->mmap_sem - * ->lock_page (access_process_vm) - * - * ->i_mutex (generic_perform_write) - * ->mmap_sem (fault_in_pages_readable->do_page_fault) - * - * bdi->wb.list_lock - * sb_lock (fs/fs-writeback.c) - * ->mapping->tree_lock (__sync_single_inode) - * - * ->i_mmap_rwsem - * ->anon_vma.lock (vma_adjust) - * - * ->anon_vma.lock - * ->page_table_lock or pte_lock (anon_vma_prepare and various) - * - * ->page_table_lock or pte_lock - * ->swap_lock (try_to_unmap_one) - * ->private_lock (try_to_unmap_one) - * ->tree_lock (try_to_unmap_one) - * ->zone_lru_lock(zone) (follow_page->mark_page_accessed) - * ->zone_lru_lock(zone) (check_pte_range->isolate_lru_page) - * ->private_lock (page_remove_rmap->set_page_dirty) - * ->tree_lock (page_remove_rmap->set_page_dirty) - * bdi.wb->list_lock (page_remove_rmap->set_page_dirty) - * ->inode->i_lock (page_remove_rmap->set_page_dirty) - * ->memcg->move_lock (page_remove_rmap->lock_page_memcg) - * bdi.wb->list_lock (zap_pte_range->set_page_dirty) - * ->inode->i_lock (zap_pte_range->set_page_dirty) - * ->private_lock (zap_pte_range->__set_page_dirty_buffers) - * - * ->i_mmap_rwsem - * ->tasklist_lock (memory_failure, collect_procs_ao) - */ - -static int page_cache_tree_insert(struct address_space *mapping, - struct page *page, void **shadowp) -{ - struct radix_tree_node *node; - void **slot; - int error; - - error = __radix_tree_create(&mapping->page_tree, page->index, 0, - &node, &slot); - if (error) - return error; - if (*slot) { - void *p; - - p = radix_tree_deref_slot_protected(slot, &mapping->tree_lock); - if (!radix_tree_exceptional_entry(p)) - return -EEXIST; - - mapping->nrexceptional--; - if (!dax_mapping(mapping)) { - if (shadowp) - *shadowp = p; - if (node) - workingset_node_shadows_dec(node); - } else { - /* DAX can replace empty locked entry with a hole */ - WARN_ON_ONCE(p != - (void *)(RADIX_TREE_EXCEPTIONAL_ENTRY | - RADIX_DAX_ENTRY_LOCK)); - /* DAX accounts exceptional entries as normal pages */ - if (node) - workingset_node_pages_dec(node); - /* Wakeup waiters for exceptional entry lock */ - dax_wake_mapping_entry_waiter(mapping, page->index, - false); - } - } - radix_tree_replace_slot(slot, page); - mapping->nrpages++; - if (node) { - workingset_node_pages_inc(node); - /* - * Don't track node that contains actual pages. - * - * Avoid acquiring the list_lru lock if already - * untracked. The list_empty() test is safe as - * node->private_list is protected by - * mapping->tree_lock. - */ - if (!list_empty(&node->private_list)) - list_lru_del(&workingset_shadow_nodes, - &node->private_list); - } - return 0; -} - -static void page_cache_tree_delete(struct address_space *mapping, - struct page *page, void *shadow) -{ - int i, nr = PageHuge(page) ? 1 : hpage_nr_pages(page); - - VM_BUG_ON_PAGE(!PageLocked(page), page); - VM_BUG_ON_PAGE(PageTail(page), page); - VM_BUG_ON_PAGE(nr != 1 && shadow, page); - - for (i = 0; i < nr; i++) { - struct radix_tree_node *node; - void **slot; - - __radix_tree_lookup(&mapping->page_tree, page->index + i, - &node, &slot); - - radix_tree_clear_tags(&mapping->page_tree, node, slot); - - if (!node) { - VM_BUG_ON_PAGE(nr != 1, page); - /* - * We need a node to properly account shadow - * entries. Don't plant any without. XXX - */ - shadow = NULL; - } - - radix_tree_replace_slot(slot, shadow); - - if (!node) - break; - - workingset_node_pages_dec(node); - if (shadow) - workingset_node_shadows_inc(node); - else - if (__radix_tree_delete_node(&mapping->page_tree, node)) - continue; - - /* - * Track node that only contains shadow entries. DAX mappings - * contain no shadow entries and may contain other exceptional - * entries so skip those. - * - * Avoid acquiring the list_lru lock if already tracked. - * The list_empty() test is safe as node->private_list is - * protected by mapping->tree_lock. - */ - if (!dax_mapping(mapping) && !workingset_node_pages(node) && - list_empty(&node->private_list)) { - node->private_data = mapping; - list_lru_add(&workingset_shadow_nodes, - &node->private_list); - } - } - - if (shadow) { - mapping->nrexceptional += nr; - /* - * Make sure the nrexceptional update is committed before - * the nrpages update so that final truncate racing - * with reclaim does not see both counters 0 at the - * same time and miss a shadow entry. - */ - smp_wmb(); - } - mapping->nrpages -= nr; -} - -/* - * Delete a page from the page cache and free it. Caller has to make - * sure the page is locked and that nobody else uses it - or that usage - * is safe. The caller must hold the mapping's tree_lock. - */ -void __delete_from_page_cache(struct page *page, void *shadow) -{ - struct address_space *mapping = page->mapping; - int nr = hpage_nr_pages(page); - - trace_mm_filemap_delete_from_page_cache(page); - /* - * if we're uptodate, flush out into the cleancache, otherwise - * invalidate any existing cleancache entries. We can't leave - * stale data around in the cleancache once our page is gone - */ - if (PageUptodate(page) && PageMappedToDisk(page)) - cleancache_put_page(page); - else - cleancache_invalidate_page(mapping, page); - - VM_BUG_ON_PAGE(PageTail(page), page); - VM_BUG_ON_PAGE(page_mapped(page), page); - if (!IS_ENABLED(CONFIG_DEBUG_VM) && unlikely(page_mapped(page))) { - int mapcount; - - pr_alert("BUG: Bad page cache in process %s pfn:%05lx\n", - current->comm, page_to_pfn(page)); - dump_page(page, "still mapped when deleted"); - dump_stack(); - add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE); - - mapcount = page_mapcount(page); - if (mapping_exiting(mapping) && - page_count(page) >= mapcount + 2) { - /* - * All vmas have already been torn down, so it's - * a good bet that actually the page is unmapped, - * and we'd prefer not to leak it: if we're wrong, - * some other bad page check should catch it later. - */ - page_mapcount_reset(page); - page_ref_sub(page, mapcount); - } - } - - page_cache_tree_delete(mapping, page, shadow); - - page->mapping = NULL; - /* Leave page->index set: truncation lookup relies upon it */ - - /* hugetlb pages do not participate in page cache accounting. */ - if (!PageHuge(page)) - __mod_node_page_state(page_pgdat(page), NR_FILE_PAGES, -nr); - if (PageSwapBacked(page)) { - __mod_node_page_state(page_pgdat(page), NR_SHMEM, -nr); - if (PageTransHuge(page)) - __dec_node_page_state(page, NR_SHMEM_THPS); - } else { - VM_BUG_ON_PAGE(PageTransHuge(page) && !PageHuge(page), page); - } - - /* - * At this point page must be either written or cleaned by truncate. - * Dirty page here signals a bug and loss of unwritten data. - * - * This fixes dirty accounting after removing the page entirely but - * leaves PageDirty set: it has no effect for truncated page and - * anyway will be cleared before returning page into buddy allocator. - */ - if (WARN_ON_ONCE(PageDirty(page))) - account_page_cleaned(page, mapping, inode_to_wb(mapping->host)); -} - -/** - * delete_from_page_cache - delete page from page cache - * @page: the page which the kernel is trying to remove from page cache - * - * This must be called only on pages that have been verified to be in the page - * cache and locked. It will never put the page into the free list, the caller - * has a reference on the page. - */ -void delete_from_page_cache(struct page *page) -{ - struct address_space *mapping = page_mapping(page); - unsigned long flags; - void (*freepage)(struct page *); - - BUG_ON(!PageLocked(page)); - - freepage = mapping->a_ops->freepage; - - spin_lock_irqsave(&mapping->tree_lock, flags); - __delete_from_page_cache(page, NULL); - spin_unlock_irqrestore(&mapping->tree_lock, flags); - - if (freepage) - freepage(page); - - if (PageTransHuge(page) && !PageHuge(page)) { - page_ref_sub(page, HPAGE_PMD_NR); - VM_BUG_ON_PAGE(page_count(page) <= 0, page); - } else { - put_page(page); - } -} -EXPORT_SYMBOL(delete_from_page_cache); - -int filemap_check_errors(struct address_space *mapping) -{ - int ret = 0; - /* Check for outstanding write errors */ - if (test_bit(AS_ENOSPC, &mapping->flags) && - test_and_clear_bit(AS_ENOSPC, &mapping->flags)) - ret = -ENOSPC; - if (test_bit(AS_EIO, &mapping->flags) && - test_and_clear_bit(AS_EIO, &mapping->flags)) - ret = -EIO; - return ret; -} -EXPORT_SYMBOL(filemap_check_errors); - -/** - * __filemap_fdatawrite_range - start writeback on mapping dirty pages in range - * @mapping: address space structure to write - * @start: offset in bytes where the range starts - * @end: offset in bytes where the range ends (inclusive) - * @sync_mode: enable synchronous operation - * - * Start writeback against all of a mapping's dirty pages that lie - * within the byte offsets inclusive. - * - * If sync_mode is WB_SYNC_ALL then this is a "data integrity" operation, as - * opposed to a regular memory cleansing writeback. The difference between - * these two operations is that if a dirty page/buffer is encountered, it must - * be waited upon, and not just skipped over. - */ -int __filemap_fdatawrite_range(struct address_space *mapping, loff_t start, - loff_t end, int sync_mode) -{ - int ret; - struct writeback_control wbc = { - .sync_mode = sync_mode, - .nr_to_write = LONG_MAX, - .range_start = start, - .range_end = end, - }; - - if (!mapping_cap_writeback_dirty(mapping)) - return 0; - - wbc_attach_fdatawrite_inode(&wbc, mapping->host); - ret = do_writepages(mapping, &wbc); - wbc_detach_inode(&wbc); - return ret; -} - -static inline int __filemap_fdatawrite(struct address_space *mapping, - int sync_mode) -{ - return __filemap_fdatawrite_range(mapping, 0, LLONG_MAX, sync_mode); -} - -int filemap_fdatawrite(struct address_space *mapping) -{ - return __filemap_fdatawrite(mapping, WB_SYNC_ALL); -} -EXPORT_SYMBOL(filemap_fdatawrite); - -int filemap_fdatawrite_range(struct address_space *mapping, loff_t start, - loff_t end) -{ - return __filemap_fdatawrite_range(mapping, start, end, WB_SYNC_ALL); -} -EXPORT_SYMBOL(filemap_fdatawrite_range); - -/** - * filemap_flush - mostly a non-blocking flush - * @mapping: target address_space - * - * This is a mostly non-blocking flush. Not suitable for data-integrity - * purposes - I/O may not be started against all dirty pages. - */ -int filemap_flush(struct address_space *mapping) -{ - return __filemap_fdatawrite(mapping, WB_SYNC_NONE); -} -EXPORT_SYMBOL(filemap_flush); - -static int __filemap_fdatawait_range(struct address_space *mapping, - loff_t start_byte, loff_t end_byte) -{ - pgoff_t index = start_byte >> PAGE_SHIFT; - pgoff_t end = end_byte >> PAGE_SHIFT; - struct pagevec pvec; - int nr_pages; - int ret = 0; - - if (end_byte < start_byte) - goto out; - - pagevec_init(&pvec, 0); - while ((index <= end) && - (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, - PAGECACHE_TAG_WRITEBACK, - min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1)) != 0) { - unsigned i; - - for (i = 0; i < nr_pages; i++) { - struct page *page = pvec.pages[i]; - - /* until radix tree lookup accepts end_index */ - if (page->index > end) - continue; - - wait_on_page_writeback(page); - if (TestClearPageError(page)) - ret = -EIO; - } - pagevec_release(&pvec); - cond_resched(); - } -out: - return ret; -} - -/** - * filemap_fdatawait_range - wait for writeback to complete - * @mapping: address space structure to wait for - * @start_byte: offset in bytes where the range starts - * @end_byte: offset in bytes where the range ends (inclusive) - * - * Walk the list of under-writeback pages of the given address space - * in the given range and wait for all of them. Check error status of - * the address space and return it. - * - * Since the error status of the address space is cleared by this function, - * callers are responsible for checking the return value and handling and/or - * reporting the error. - */ -int filemap_fdatawait_range(struct address_space *mapping, loff_t start_byte, - loff_t end_byte) -{ - int ret, ret2; - - ret = __filemap_fdatawait_range(mapping, start_byte, end_byte); - ret2 = filemap_check_errors(mapping); - if (!ret) - ret = ret2; - - return ret; -} -EXPORT_SYMBOL(filemap_fdatawait_range); - -/** - * filemap_fdatawait_keep_errors - wait for writeback without clearing errors - * @mapping: address space structure to wait for - * - * Walk the list of under-writeback pages of the given address space - * and wait for all of them. Unlike filemap_fdatawait(), this function - * does not clear error status of the address space. - * - * Use this function if callers don't handle errors themselves. Expected - * call sites are system-wide / filesystem-wide data flushers: e.g. sync(2), - * fsfreeze(8) - */ -void filemap_fdatawait_keep_errors(struct address_space *mapping) -{ - loff_t i_size = i_size_read(mapping->host); - - if (i_size == 0) - return; - - __filemap_fdatawait_range(mapping, 0, i_size - 1); -} - -/** - * filemap_fdatawait - wait for all under-writeback pages to complete - * @mapping: address space structure to wait for - * - * Walk the list of under-writeback pages of the given address space - * and wait for all of them. Check error status of the address space - * and return it. - * - * Since the error status of the address space is cleared by this function, - * callers are responsible for checking the return value and handling and/or - * reporting the error. - */ -int filemap_fdatawait(struct address_space *mapping) -{ - loff_t i_size = i_size_read(mapping->host); - - if (i_size == 0) - return 0; - - return filemap_fdatawait_range(mapping, 0, i_size - 1); -} -EXPORT_SYMBOL(filemap_fdatawait); - -int filemap_write_and_wait(struct address_space *mapping) -{ - int err = 0; - - if ((!dax_mapping(mapping) && mapping->nrpages) || - (dax_mapping(mapping) && mapping->nrexceptional)) { - err = filemap_fdatawrite(mapping); - /* - * Even if the above returned error, the pages may be - * written partially (e.g. -ENOSPC), so we wait for it. - * But the -EIO is special case, it may indicate the worst - * thing (e.g. bug) happened, so we avoid waiting for it. - */ - if (err != -EIO) { - int err2 = filemap_fdatawait(mapping); - if (!err) - err = err2; - } - } else { - err = filemap_check_errors(mapping); - } - return err; -} -EXPORT_SYMBOL(filemap_write_and_wait); - -/** - * filemap_write_and_wait_range - write out & wait on a file range - * @mapping: the address_space for the pages - * @lstart: offset in bytes where the range starts - * @lend: offset in bytes where the range ends (inclusive) - * - * Write out and wait upon file offsets lstart->lend, inclusive. - * - * Note that `lend' is inclusive (describes the last byte to be written) so - * that this function can be used to write to the very end-of-file (end = -1). - */ -int filemap_write_and_wait_range(struct address_space *mapping, - loff_t lstart, loff_t lend) -{ - int err = 0; - - if ((!dax_mapping(mapping) && mapping->nrpages) || - (dax_mapping(mapping) && mapping->nrexceptional)) { - err = __filemap_fdatawrite_range(mapping, lstart, lend, - WB_SYNC_ALL); - /* See comment of filemap_write_and_wait() */ - if (err != -EIO) { - int err2 = filemap_fdatawait_range(mapping, - lstart, lend); - if (!err) - err = err2; - } - } else { - err = filemap_check_errors(mapping); - } - return err; -} -EXPORT_SYMBOL(filemap_write_and_wait_range); - -/** - * replace_page_cache_page - replace a pagecache page with a new one - * @old: page to be replaced - * @new: page to replace with - * @gfp_mask: allocation mode - * - * This function replaces a page in the pagecache with a new one. On - * success it acquires the pagecache reference for the new page and - * drops it for the old page. Both the old and new pages must be - * locked. This function does not add the new page to the LRU, the - * caller must do that. - * - * The remove + add is atomic. The only way this function can fail is - * memory allocation failure. - */ -int replace_page_cache_page(struct page *old, struct page *new, gfp_t gfp_mask) -{ - int error; - - VM_BUG_ON_PAGE(!PageLocked(old), old); - VM_BUG_ON_PAGE(!PageLocked(new), new); - VM_BUG_ON_PAGE(new->mapping, new); - - error = radix_tree_preload(gfp_mask & ~__GFP_HIGHMEM); - if (!error) { - struct address_space *mapping = old->mapping; - void (*freepage)(struct page *); - unsigned long flags; - - pgoff_t offset = old->index; - freepage = mapping->a_ops->freepage; - - get_page(new); - new->mapping = mapping; - new->index = offset; - - spin_lock_irqsave(&mapping->tree_lock, flags); - __delete_from_page_cache(old, NULL); - error = page_cache_tree_insert(mapping, new, NULL); - BUG_ON(error); - - /* - * hugetlb pages do not participate in page cache accounting. - */ - if (!PageHuge(new)) - __inc_node_page_state(new, NR_FILE_PAGES); - if (PageSwapBacked(new)) - __inc_node_page_state(new, NR_SHMEM); - spin_unlock_irqrestore(&mapping->tree_lock, flags); - mem_cgroup_migrate(old, new); - radix_tree_preload_end(); - if (freepage) - freepage(old); - put_page(old); - } - - return error; -} -EXPORT_SYMBOL_GPL(replace_page_cache_page); - -static int __add_to_page_cache_locked(struct page *page, - struct address_space *mapping, - pgoff_t offset, gfp_t gfp_mask, - void **shadowp) -{ - int huge = PageHuge(page); - struct mem_cgroup *memcg; - int error; - - VM_BUG_ON_PAGE(!PageLocked(page), page); - VM_BUG_ON_PAGE(PageSwapBacked(page), page); - - if (!huge) { - error = mem_cgroup_try_charge(page, current->mm, - gfp_mask, &memcg, false); - if (error) - return error; - } - - error = radix_tree_maybe_preload(gfp_mask & ~__GFP_HIGHMEM); - if (error) { - if (!huge) - mem_cgroup_cancel_charge(page, memcg, false); - return error; - } - - get_page(page); - page->mapping = mapping; - page->index = offset; - - spin_lock_irq(&mapping->tree_lock); - error = page_cache_tree_insert(mapping, page, shadowp); - radix_tree_preload_end(); - if (unlikely(error)) - goto err_insert; - - /* hugetlb pages do not participate in page cache accounting. */ - if (!huge) - __inc_node_page_state(page, NR_FILE_PAGES); - spin_unlock_irq(&mapping->tree_lock); - if (!huge) - mem_cgroup_commit_charge(page, memcg, false, false); - trace_mm_filemap_add_to_page_cache(page); - return 0; -err_insert: - page->mapping = NULL; - /* Leave page->index set: truncation relies upon it */ - spin_unlock_irq(&mapping->tree_lock); - if (!huge) - mem_cgroup_cancel_charge(page, memcg, false); - put_page(page); - return error; -} - -/** - * add_to_page_cache_locked - add a locked page to the pagecache - * @page: page to add - * @mapping: the page's address_space - * @offset: page index - * @gfp_mask: page allocation mode - * - * This function is used to add a page to the pagecache. It must be locked. - * This function does not add the page to the LRU. The caller must do that. - */ -int add_to_page_cache_locked(struct page *page, struct address_space *mapping, - pgoff_t offset, gfp_t gfp_mask) -{ - return __add_to_page_cache_locked(page, mapping, offset, - gfp_mask, NULL); -} -EXPORT_SYMBOL(add_to_page_cache_locked); - -int add_to_page_cache_lru(struct page *page, struct address_space *mapping, - pgoff_t offset, gfp_t gfp_mask) -{ - void *shadow = NULL; - int ret; - - __SetPageLocked(page); - ret = __add_to_page_cache_locked(page, mapping, offset, - gfp_mask, &shadow); - if (unlikely(ret)) - __ClearPageLocked(page); - else { - /* - * The page might have been evicted from cache only - * recently, in which case it should be activated like - * any other repeatedly accessed page. - * The exception is pages getting rewritten; evicting other - * data from the working set, only to cache data that will - * get overwritten with something else, is a waste of memory. - */ - if (!(gfp_mask & __GFP_WRITE) && - shadow && workingset_refault(shadow)) { - SetPageActive(page); - workingset_activation(page); - } else - ClearPageActive(page); - lru_cache_add(page); - } - return ret; -} -EXPORT_SYMBOL_GPL(add_to_page_cache_lru); - -#ifdef CONFIG_NUMA -struct page *__page_cache_alloc(gfp_t gfp) -{ - int n; - struct page *page; - - if (cpuset_do_page_mem_spread()) { - unsigned int cpuset_mems_cookie; - do { - cpuset_mems_cookie = read_mems_allowed_begin(); - n = cpuset_mem_spread_node(); - page = __alloc_pages_node(n, gfp, 0); - } while (!page && read_mems_allowed_retry(cpuset_mems_cookie)); - - return page; - } - return alloc_pages(gfp, 0); -} -EXPORT_SYMBOL(__page_cache_alloc); -#endif - -/* - * In order to wait for pages to become available there must be - * waitqueues associated with pages. By using a hash table of - * waitqueues where the bucket discipline is to maintain all - * waiters on the same queue and wake all when any of the pages - * become available, and for the woken contexts to check to be - * sure the appropriate page became available, this saves space - * at a cost of "thundering herd" phenomena during rare hash - * collisions. - */ -wait_queue_head_t *page_waitqueue(struct page *page) -{ - return bit_waitqueue(page, 0); -} -EXPORT_SYMBOL(page_waitqueue); - -void wait_on_page_bit(struct page *page, int bit_nr) -{ - DEFINE_WAIT_BIT(wait, &page->flags, bit_nr); - - if (test_bit(bit_nr, &page->flags)) - __wait_on_bit(page_waitqueue(page), &wait, bit_wait_io, - TASK_UNINTERRUPTIBLE); -} -EXPORT_SYMBOL(wait_on_page_bit); - -int wait_on_page_bit_killable(struct page *page, int bit_nr) -{ - DEFINE_WAIT_BIT(wait, &page->flags, bit_nr); - - if (!test_bit(bit_nr, &page->flags)) - return 0; - - return __wait_on_bit(page_waitqueue(page), &wait, - bit_wait_io, TASK_KILLABLE); -} - -int wait_on_page_bit_killable_timeout(struct page *page, - int bit_nr, unsigned long timeout) -{ - DEFINE_WAIT_BIT(wait, &page->flags, bit_nr); - - wait.key.timeout = jiffies + timeout; - if (!test_bit(bit_nr, &page->flags)) - return 0; - return __wait_on_bit(page_waitqueue(page), &wait, - bit_wait_io_timeout, TASK_KILLABLE); -} -EXPORT_SYMBOL_GPL(wait_on_page_bit_killable_timeout); - -/** - * add_page_wait_queue - Add an arbitrary waiter to a page's wait queue - * @page: Page defining the wait queue of interest - * @waiter: Waiter to add to the queue - * - * Add an arbitrary @waiter to the wait queue for the nominated @page. - */ -void add_page_wait_queue(struct page *page, wait_queue_t *waiter) -{ - wait_queue_head_t *q = page_waitqueue(page); - unsigned long flags; - - spin_lock_irqsave(&q->lock, flags); - __add_wait_queue(q, waiter); - spin_unlock_irqrestore(&q->lock, flags); -} -EXPORT_SYMBOL_GPL(add_page_wait_queue); - -/** - * unlock_page - unlock a locked page - * @page: the page - * - * Unlocks the page and wakes up sleepers in ___wait_on_page_locked(). - * Also wakes sleepers in wait_on_page_writeback() because the wakeup - * mechanism between PageLocked pages and PageWriteback pages is shared. - * But that's OK - sleepers in wait_on_page_writeback() just go back to sleep. - * - * The mb is necessary to enforce ordering between the clear_bit and the read - * of the waitqueue (to avoid SMP races with a parallel wait_on_page_locked()). - */ -void unlock_page(struct page *page) -{ - page = compound_head(page); - VM_BUG_ON_PAGE(!PageLocked(page), page); - clear_bit_unlock(PG_locked, &page->flags); - smp_mb__after_atomic(); - wake_up_page(page, PG_locked); -} -EXPORT_SYMBOL(unlock_page); - -/** - * end_page_writeback - end writeback against a page - * @page: the page - */ -void end_page_writeback(struct page *page) -{ - /* - * TestClearPageReclaim could be used here but it is an atomic - * operation and overkill in this particular case. Failing to - * shuffle a page marked for immediate reclaim is too mild to - * justify taking an atomic operation penalty at the end of - * ever page writeback. - */ - if (PageReclaim(page)) { - ClearPageReclaim(page); - rotate_reclaimable_page(page); - } - - if (!test_clear_page_writeback(page)) - BUG(); - - smp_mb__after_atomic(); - wake_up_page(page, PG_writeback); -} -EXPORT_SYMBOL(end_page_writeback); - -/* - * After completing I/O on a page, call this routine to update the page - * flags appropriately - */ -void page_endio(struct page *page, bool is_write, int err) -{ - if (!is_write) { - if (!err) { - SetPageUptodate(page); - } else { - ClearPageUptodate(page); - SetPageError(page); - } - unlock_page(page); - } else { - if (err) { - SetPageError(page); - if (page->mapping) - mapping_set_error(page->mapping, err); - } - end_page_writeback(page); - } -} -EXPORT_SYMBOL_GPL(page_endio); - -/** - * __lock_page - get a lock on the page, assuming we need to sleep to get it - * @page: the page to lock - */ -void __lock_page(struct page *page) -{ - struct page *page_head = compound_head(page); - DEFINE_WAIT_BIT(wait, &page_head->flags, PG_locked); - - __wait_on_bit_lock(page_waitqueue(page_head), &wait, bit_wait_io, - TASK_UNINTERRUPTIBLE); -} -EXPORT_SYMBOL(__lock_page); - -int __lock_page_killable(struct page *page) -{ - struct page *page_head = compound_head(page); - DEFINE_WAIT_BIT(wait, &page_head->flags, PG_locked); - - return __wait_on_bit_lock(page_waitqueue(page_head), &wait, - bit_wait_io, TASK_KILLABLE); -} -EXPORT_SYMBOL_GPL(__lock_page_killable); - -/* - * Return values: - * 1 - page is locked; mmap_sem is still held. - * 0 - page is not locked. - * mmap_sem has been released (up_read()), unless flags had both - * FAULT_FLAG_ALLOW_RETRY and FAULT_FLAG_RETRY_NOWAIT set, in - * which case mmap_sem is still held. - * - * If neither ALLOW_RETRY nor KILLABLE are set, will always return 1 - * with the page locked and the mmap_sem unperturbed. - */ -int __lock_page_or_retry(struct page *page, struct mm_struct *mm, - unsigned int flags) -{ - if (flags & FAULT_FLAG_ALLOW_RETRY) { - /* - * CAUTION! In this case, mmap_sem is not released - * even though return 0. - */ - if (flags & FAULT_FLAG_RETRY_NOWAIT) - return 0; - - up_read(&mm->mmap_sem); - if (flags & FAULT_FLAG_KILLABLE) - wait_on_page_locked_killable(page); - else - wait_on_page_locked(page); - return 0; - } else { - if (flags & FAULT_FLAG_KILLABLE) { - int ret; - - ret = __lock_page_killable(page); - if (ret) { - up_read(&mm->mmap_sem); - return 0; - } - } else - __lock_page(page); - return 1; - } -} - -/** - * page_cache_next_hole - find the next hole (not-present entry) - * @mapping: mapping - * @index: index - * @max_scan: maximum range to search - * - * Search the set [index, min(index+max_scan-1, MAX_INDEX)] for the - * lowest indexed hole. - * - * Returns: the index of the hole if found, otherwise returns an index - * outside of the set specified (in which case 'return - index >= - * max_scan' will be true). In rare cases of index wrap-around, 0 will - * be returned. - * - * page_cache_next_hole may be called under rcu_read_lock. However, - * like radix_tree_gang_lookup, this will not atomically search a - * snapshot of the tree at a single point in time. For example, if a - * hole is created at index 5, then subsequently a hole is created at - * index 10, page_cache_next_hole covering both indexes may return 10 - * if called under rcu_read_lock. - */ -pgoff_t page_cache_next_hole(struct address_space *mapping, - pgoff_t index, unsigned long max_scan) -{ - unsigned long i; - - for (i = 0; i < max_scan; i++) { - struct page *page; - - page = radix_tree_lookup(&mapping->page_tree, index); - if (!page || radix_tree_exceptional_entry(page)) - break; - index++; - if (index == 0) - break; - } - - return index; -} -EXPORT_SYMBOL(page_cache_next_hole); - -/** - * page_cache_prev_hole - find the prev hole (not-present entry) - * @mapping: mapping - * @index: index - * @max_scan: maximum range to search - * - * Search backwards in the range [max(index-max_scan+1, 0), index] for - * the first hole. - * - * Returns: the index of the hole if found, otherwise returns an index - * outside of the set specified (in which case 'index - return >= - * max_scan' will be true). In rare cases of wrap-around, ULONG_MAX - * will be returned. - * - * page_cache_prev_hole may be called under rcu_read_lock. However, - * like radix_tree_gang_lookup, this will not atomically search a - * snapshot of the tree at a single point in time. For example, if a - * hole is created at index 10, then subsequently a hole is created at - * index 5, page_cache_prev_hole covering both indexes may return 5 if - * called under rcu_read_lock. - */ -pgoff_t page_cache_prev_hole(struct address_space *mapping, - pgoff_t index, unsigned long max_scan) -{ - unsigned long i; - - for (i = 0; i < max_scan; i++) { - struct page *page; - - page = radix_tree_lookup(&mapping->page_tree, index); - if (!page || radix_tree_exceptional_entry(page)) - break; - index--; - if (index == ULONG_MAX) - break; - } - - return index; -} -EXPORT_SYMBOL(page_cache_prev_hole); - -/** - * find_get_entry - find and get a page cache entry - * @mapping: the address_space to search - * @offset: the page cache index - * - * Looks up the page cache slot at @mapping & @offset. If there is a - * page cache page, it is returned with an increased refcount. - * - * If the slot holds a shadow entry of a previously evicted page, or a - * swap entry from shmem/tmpfs, it is returned. - * - * Otherwise, %NULL is returned. - */ -struct page *find_get_entry(struct address_space *mapping, pgoff_t offset) -{ - void **pagep; - struct page *head, *page; - - rcu_read_lock(); -repeat: - page = NULL; - pagep = radix_tree_lookup_slot(&mapping->page_tree, offset); - if (pagep) { - page = radix_tree_deref_slot(pagep); - if (unlikely(!page)) - goto out; - if (radix_tree_exception(page)) { - if (radix_tree_deref_retry(page)) - goto repeat; - /* - * A shadow entry of a recently evicted page, - * or a swap entry from shmem/tmpfs. Return - * it without attempting to raise page count. - */ - goto out; - } - - head = compound_head(page); - if (!page_cache_get_speculative(head)) - goto repeat; - - /* The page was split under us? */ - if (compound_head(page) != head) { - put_page(head); - goto repeat; - } - - /* - * Has the page moved? - * This is part of the lockless pagecache protocol. See - * include/linux/pagemap.h for details. - */ - if (unlikely(page != *pagep)) { - put_page(head); - goto repeat; - } - } -out: - rcu_read_unlock(); - - return page; -} -EXPORT_SYMBOL(find_get_entry); - -/** - * find_lock_entry - locate, pin and lock a page cache entry - * @mapping: the address_space to search - * @offset: the page cache index - * - * Looks up the page cache slot at @mapping & @offset. If there is a - * page cache page, it is returned locked and with an increased - * refcount. - * - * If the slot holds a shadow entry of a previously evicted page, or a - * swap entry from shmem/tmpfs, it is returned. - * - * Otherwise, %NULL is returned. - * - * find_lock_entry() may sleep. - */ -struct page *find_lock_entry(struct address_space *mapping, pgoff_t offset) -{ - struct page *page; - -repeat: - page = find_get_entry(mapping, offset); - if (page && !radix_tree_exception(page)) { - lock_page(page); - /* Has the page been truncated? */ - if (unlikely(page_mapping(page) != mapping)) { - unlock_page(page); - put_page(page); - goto repeat; - } - VM_BUG_ON_PAGE(page_to_pgoff(page) != offset, page); - } - return page; -} -EXPORT_SYMBOL(find_lock_entry); - -/** - * pagecache_get_page - find and get a page reference - * @mapping: the address_space to search - * @offset: the page index - * @fgp_flags: PCG flags - * @gfp_mask: gfp mask to use for the page cache data page allocation - * - * Looks up the page cache slot at @mapping & @offset. - * - * PCG flags modify how the page is returned. - * - * FGP_ACCESSED: the page will be marked accessed - * FGP_LOCK: Page is return locked - * FGP_CREAT: If page is not present then a new page is allocated using - * @gfp_mask and added to the page cache and the VM's LRU - * list. The page is returned locked and with an increased - * refcount. Otherwise, %NULL is returned. - * - * If FGP_LOCK or FGP_CREAT are specified then the function may sleep even - * if the GFP flags specified for FGP_CREAT are atomic. - * - * If there is a page cache page, it is returned with an increased refcount. - */ -struct page *pagecache_get_page(struct address_space *mapping, pgoff_t offset, - int fgp_flags, gfp_t gfp_mask) -{ - struct page *page; - -repeat: - page = find_get_entry(mapping, offset); - if (radix_tree_exceptional_entry(page)) - page = NULL; - if (!page) - goto no_page; - - if (fgp_flags & FGP_LOCK) { - if (fgp_flags & FGP_NOWAIT) { - if (!trylock_page(page)) { - put_page(page); - return NULL; - } - } else { - lock_page(page); - } - - /* Has the page been truncated? */ - if (unlikely(page->mapping != mapping)) { - unlock_page(page); - put_page(page); - goto repeat; - } - VM_BUG_ON_PAGE(page->index != offset, page); - } - - if (page && (fgp_flags & FGP_ACCESSED)) - mark_page_accessed(page); - -no_page: - if (!page && (fgp_flags & FGP_CREAT)) { - int err; - if ((fgp_flags & FGP_WRITE) && mapping_cap_account_dirty(mapping)) - gfp_mask |= __GFP_WRITE; - if (fgp_flags & FGP_NOFS) - gfp_mask &= ~__GFP_FS; - - page = __page_cache_alloc(gfp_mask); - if (!page) - return NULL; - - if (WARN_ON_ONCE(!(fgp_flags & FGP_LOCK))) - fgp_flags |= FGP_LOCK; - - /* Init accessed so avoid atomic mark_page_accessed later */ - if (fgp_flags & FGP_ACCESSED) - __SetPageReferenced(page); - - err = add_to_page_cache_lru(page, mapping, offset, - gfp_mask & GFP_RECLAIM_MASK); - if (unlikely(err)) { - put_page(page); - page = NULL; - if (err == -EEXIST) - goto repeat; - } - } - - return page; -} -EXPORT_SYMBOL(pagecache_get_page); - -/** - * find_get_entries - gang pagecache lookup - * @mapping: The address_space to search - * @start: The starting page cache index - * @nr_entries: The maximum number of entries - * @entries: Where the resulting entries are placed - * @indices: The cache indices corresponding to the entries in @entries - * - * find_get_entries() will search for and return a group of up to - * @nr_entries entries in the mapping. The entries are placed at - * @entries. find_get_entries() takes a reference against any actual - * pages it returns. - * - * The search returns a group of mapping-contiguous page cache entries - * with ascending indexes. There may be holes in the indices due to - * not-present pages. - * - * Any shadow entries of evicted pages, or swap entries from - * shmem/tmpfs, are included in the returned array. - * - * find_get_entries() returns the number of pages and shadow entries - * which were found. - */ -unsigned find_get_entries(struct address_space *mapping, - pgoff_t start, unsigned int nr_entries, - struct page **entries, pgoff_t *indices) -{ - void **slot; - unsigned int ret = 0; - struct radix_tree_iter iter; - - if (!nr_entries) - return 0; - - rcu_read_lock(); - radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) { - struct page *head, *page; -repeat: - page = radix_tree_deref_slot(slot); - if (unlikely(!page)) - continue; - if (radix_tree_exception(page)) { - if (radix_tree_deref_retry(page)) { - slot = radix_tree_iter_retry(&iter); - continue; - } - /* - * A shadow entry of a recently evicted page, a swap - * entry from shmem/tmpfs or a DAX entry. Return it - * without attempting to raise page count. - */ - goto export; - } - - head = compound_head(page); - if (!page_cache_get_speculative(head)) - goto repeat; - - /* The page was split under us? */ - if (compound_head(page) != head) { - put_page(head); - goto repeat; - } - - /* Has the page moved? */ - if (unlikely(page != *slot)) { - put_page(head); - goto repeat; - } -export: - indices[ret] = iter.index; - entries[ret] = page; - if (++ret == nr_entries) - break; - } - rcu_read_unlock(); - return ret; -} - -/** - * find_get_pages - gang pagecache lookup - * @mapping: The address_space to search - * @start: The starting page index - * @nr_pages: The maximum number of pages - * @pages: Where the resulting pages are placed - * - * find_get_pages() will search for and return a group of up to - * @nr_pages pages in the mapping. The pages are placed at @pages. - * find_get_pages() takes a reference against the returned pages. - * - * The search returns a group of mapping-contiguous pages with ascending - * indexes. There may be holes in the indices due to not-present pages. - * - * find_get_pages() returns the number of pages which were found. - */ -unsigned find_get_pages(struct address_space *mapping, pgoff_t start, - unsigned int nr_pages, struct page **pages) -{ - struct radix_tree_iter iter; - void **slot; - unsigned ret = 0; - - if (unlikely(!nr_pages)) - return 0; - - rcu_read_lock(); - radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) { - struct page *head, *page; -repeat: - page = radix_tree_deref_slot(slot); - if (unlikely(!page)) - continue; - - if (radix_tree_exception(page)) { - if (radix_tree_deref_retry(page)) { - slot = radix_tree_iter_retry(&iter); - continue; - } - /* - * A shadow entry of a recently evicted page, - * or a swap entry from shmem/tmpfs. Skip - * over it. - */ - continue; - } - - head = compound_head(page); - if (!page_cache_get_speculative(head)) - goto repeat; - - /* The page was split under us? */ - if (compound_head(page) != head) { - put_page(head); - goto repeat; - } - - /* Has the page moved? */ - if (unlikely(page != *slot)) { - put_page(head); - goto repeat; - } - - pages[ret] = page; - if (++ret == nr_pages) - break; - } - - rcu_read_unlock(); - return ret; -} - -/** - * find_get_pages_contig - gang contiguous pagecache lookup - * @mapping: The address_space to search - * @index: The starting page index - * @nr_pages: The maximum number of pages - * @pages: Where the resulting pages are placed - * - * find_get_pages_contig() works exactly like find_get_pages(), except - * that the returned number of pages are guaranteed to be contiguous. - * - * find_get_pages_contig() returns the number of pages which were found. - */ -unsigned find_get_pages_contig(struct address_space *mapping, pgoff_t index, - unsigned int nr_pages, struct page **pages) -{ - struct radix_tree_iter iter; - void **slot; - unsigned int ret = 0; - - if (unlikely(!nr_pages)) - return 0; - - rcu_read_lock(); - radix_tree_for_each_contig(slot, &mapping->page_tree, &iter, index) { - struct page *head, *page; -repeat: - page = radix_tree_deref_slot(slot); - /* The hole, there no reason to continue */ - if (unlikely(!page)) - break; - - if (radix_tree_exception(page)) { - if (radix_tree_deref_retry(page)) { - slot = radix_tree_iter_retry(&iter); - continue; - } - /* - * A shadow entry of a recently evicted page, - * or a swap entry from shmem/tmpfs. Stop - * looking for contiguous pages. - */ - break; - } - - head = compound_head(page); - if (!page_cache_get_speculative(head)) - goto repeat; - - /* The page was split under us? */ - if (compound_head(page) != head) { - put_page(head); - goto repeat; - } - - /* Has the page moved? */ - if (unlikely(page != *slot)) { - put_page(head); - goto repeat; - } - - /* - * must check mapping and index after taking the ref. - * otherwise we can get both false positives and false - * negatives, which is just confusing to the caller. - */ - if (page->mapping == NULL || page_to_pgoff(page) != iter.index) { - put_page(page); - break; - } - - pages[ret] = page; - if (++ret == nr_pages) - break; - } - rcu_read_unlock(); - return ret; -} -EXPORT_SYMBOL(find_get_pages_contig); - -/** - * find_get_pages_tag - find and return pages that match @tag - * @mapping: the address_space to search - * @index: the starting page index - * @tag: the tag index - * @nr_pages: the maximum number of pages - * @pages: where the resulting pages are placed - * - * Like find_get_pages, except we only return pages which are tagged with - * @tag. We update @index to index the next page for the traversal. - */ -unsigned find_get_pages_tag(struct address_space *mapping, pgoff_t *index, - int tag, unsigned int nr_pages, struct page **pages) -{ - struct radix_tree_iter iter; - void **slot; - unsigned ret = 0; - - if (unlikely(!nr_pages)) - return 0; - - rcu_read_lock(); - radix_tree_for_each_tagged(slot, &mapping->page_tree, - &iter, *index, tag) { - struct page *head, *page; -repeat: - page = radix_tree_deref_slot(slot); - if (unlikely(!page)) - continue; - - if (radix_tree_exception(page)) { - if (radix_tree_deref_retry(page)) { - slot = radix_tree_iter_retry(&iter); - continue; - } - /* - * A shadow entry of a recently evicted page. - * - * Those entries should never be tagged, but - * this tree walk is lockless and the tags are - * looked up in bulk, one radix tree node at a - * time, so there is a sizable window for page - * reclaim to evict a page we saw tagged. - * - * Skip over it. - */ - continue; - } - - head = compound_head(page); - if (!page_cache_get_speculative(head)) - goto repeat; - - /* The page was split under us? */ - if (compound_head(page) != head) { - put_page(head); - goto repeat; - } - - /* Has the page moved? */ - if (unlikely(page != *slot)) { - put_page(head); - goto repeat; - } - - pages[ret] = page; - if (++ret == nr_pages) - break; - } - - rcu_read_unlock(); - - if (ret) - *index = pages[ret - 1]->index + 1; - - return ret; -} -EXPORT_SYMBOL(find_get_pages_tag); - -/** - * find_get_entries_tag - find and return entries that match @tag - * @mapping: the address_space to search - * @start: the starting page cache index - * @tag: the tag index - * @nr_entries: the maximum number of entries - * @entries: where the resulting entries are placed - * @indices: the cache indices corresponding to the entries in @entries - * - * Like find_get_entries, except we only return entries which are tagged with - * @tag. - */ -unsigned find_get_entries_tag(struct address_space *mapping, pgoff_t start, - int tag, unsigned int nr_entries, - struct page **entries, pgoff_t *indices) -{ - void **slot; - unsigned int ret = 0; - struct radix_tree_iter iter; - - if (!nr_entries) - return 0; - - rcu_read_lock(); - radix_tree_for_each_tagged(slot, &mapping->page_tree, - &iter, start, tag) { - struct page *head, *page; -repeat: - page = radix_tree_deref_slot(slot); - if (unlikely(!page)) - continue; - if (radix_tree_exception(page)) { - if (radix_tree_deref_retry(page)) { - slot = radix_tree_iter_retry(&iter); - continue; - } - - /* - * A shadow entry of a recently evicted page, a swap - * entry from shmem/tmpfs or a DAX entry. Return it - * without attempting to raise page count. - */ - goto export; - } - - head = compound_head(page); - if (!page_cache_get_speculative(head)) - goto repeat; - - /* The page was split under us? */ - if (compound_head(page) != head) { - put_page(head); - goto repeat; - } - - /* Has the page moved? */ - if (unlikely(page != *slot)) { - put_page(head); - goto repeat; - } -export: - indices[ret] = iter.index; - entries[ret] = page; - if (++ret == nr_entries) - break; - } - rcu_read_unlock(); - return ret; -} -EXPORT_SYMBOL(find_get_entries_tag); - -/* - * CD/DVDs are error prone. When a medium error occurs, the driver may fail - * a _large_ part of the i/o request. Imagine the worst scenario: - * - * ---R__________________________________________B__________ - * ^ reading here ^ bad block(assume 4k) - * - * read(R) => miss => readahead(R...B) => media error => frustrating retries - * => failing the whole request => read(R) => read(R+1) => - * readahead(R+1...B+1) => bang => read(R+2) => read(R+3) => - * readahead(R+3...B+2) => bang => read(R+3) => read(R+4) => - * readahead(R+4...B+3) => bang => read(R+4) => read(R+5) => ...... - * - * It is going insane. Fix it by quickly scaling down the readahead size. - */ -static void shrink_readahead_size_eio(struct file *filp, - struct file_ra_state *ra) -{ - ra->ra_pages /= 4; -} - -/** - * do_generic_file_read - generic file read routine - * @filp: the file to read - * @ppos: current file position - * @iter: data destination - * @written: already copied - * - * This is a generic file read routine, and uses the - * mapping->a_ops->readpage() function for the actual low-level stuff. - * - * This is really ugly. But the goto's actually try to clarify some - * of the logic when it comes to error handling etc. - */ -static ssize_t do_generic_file_read(struct file *filp, loff_t *ppos, - struct iov_iter *iter, ssize_t written) -{ - struct address_space *mapping = filp->f_mapping; - struct inode *inode = mapping->host; - struct file_ra_state *ra = &filp->f_ra; - pgoff_t index; - pgoff_t last_index; - pgoff_t prev_index; - unsigned long offset; /* offset into pagecache page */ - unsigned int prev_offset; - int error = 0; - - if (unlikely(*ppos >= inode->i_sb->s_maxbytes)) - return -EINVAL; - iov_iter_truncate(iter, inode->i_sb->s_maxbytes); - - index = *ppos >> PAGE_SHIFT; - prev_index = ra->prev_pos >> PAGE_SHIFT; - prev_offset = ra->prev_pos & (PAGE_SIZE-1); - last_index = (*ppos + iter->count + PAGE_SIZE-1) >> PAGE_SHIFT; - offset = *ppos & ~PAGE_MASK; - - for (;;) { - struct page *page; - pgoff_t end_index; - loff_t isize; - unsigned long nr, ret; - - cond_resched(); -find_page: - page = find_get_page(mapping, index); - if (!page) { - page_cache_sync_readahead(mapping, - ra, filp, - index, last_index - index); - page = find_get_page(mapping, index); - if (unlikely(page == NULL)) - goto no_cached_page; - } - if (PageReadahead(page)) { - page_cache_async_readahead(mapping, - ra, filp, page, - index, last_index - index); - } - if (!PageUptodate(page)) { - /* - * See comment in do_read_cache_page on why - * wait_on_page_locked is used to avoid unnecessarily - * serialisations and why it's safe. - */ - error = wait_on_page_locked_killable(page); - if (unlikely(error)) - goto readpage_error; - if (PageUptodate(page)) - goto page_ok; - - if (inode->i_blkbits == PAGE_SHIFT || - !mapping->a_ops->is_partially_uptodate) - goto page_not_up_to_date; - /* pipes can't handle partially uptodate pages */ - if (unlikely(iter->type & ITER_PIPE)) - goto page_not_up_to_date; - if (!trylock_page(page)) - goto page_not_up_to_date; - /* Did it get truncated before we got the lock? */ - if (!page->mapping) - goto page_not_up_to_date_locked; - if (!mapping->a_ops->is_partially_uptodate(page, - offset, iter->count)) - goto page_not_up_to_date_locked; - unlock_page(page); - } -page_ok: - /* - * i_size must be checked after we know the page is Uptodate. - * - * Checking i_size after the check allows us to calculate - * the correct value for "nr", which means the zero-filled - * part of the page is not copied back to userspace (unless - * another truncate extends the file - this is desired though). - */ - - isize = i_size_read(inode); - end_index = (isize - 1) >> PAGE_SHIFT; - if (unlikely(!isize || index > end_index)) { - put_page(page); - goto out; - } - - /* nr is the maximum number of bytes to copy from this page */ - nr = PAGE_SIZE; - if (index == end_index) { - nr = ((isize - 1) & ~PAGE_MASK) + 1; - if (nr <= offset) { - put_page(page); - goto out; - } - } - nr = nr - offset; - - /* If users can be writing to this page using arbitrary - * virtual addresses, take care about potential aliasing - * before reading the page on the kernel side. - */ - if (mapping_writably_mapped(mapping)) - flush_dcache_page(page); - - /* - * When a sequential read accesses a page several times, - * only mark it as accessed the first time. - */ - if (prev_index != index || offset != prev_offset) - mark_page_accessed(page); - prev_index = index; - - /* - * Ok, we have the page, and it's up-to-date, so - * now we can copy it to user space... - */ - - ret = copy_page_to_iter(page, offset, nr, iter); - offset += ret; - index += offset >> PAGE_SHIFT; - offset &= ~PAGE_MASK; - prev_offset = offset; - - put_page(page); - written += ret; - if (!iov_iter_count(iter)) - goto out; - if (ret < nr) { - error = -EFAULT; - goto out; - } - continue; - -page_not_up_to_date: - /* Get exclusive access to the page ... */ - error = lock_page_killable(page); - if (unlikely(error)) - goto readpage_error; - -page_not_up_to_date_locked: - /* Did it get truncated before we got the lock? */ - if (!page->mapping) { - unlock_page(page); - put_page(page); - continue; - } - - /* Did somebody else fill it already? */ - if (PageUptodate(page)) { - unlock_page(page); - goto page_ok; - } - -readpage: - /* - * A previous I/O error may have been due to temporary - * failures, eg. multipath errors. - * PG_error will be set again if readpage fails. - */ - ClearPageError(page); - /* Start the actual read. The read will unlock the page. */ - error = mapping->a_ops->readpage(filp, page); - - if (unlikely(error)) { - if (error == AOP_TRUNCATED_PAGE) { - put_page(page); - error = 0; - goto find_page; - } - goto readpage_error; - } - - if (!PageUptodate(page)) { - error = lock_page_killable(page); - if (unlikely(error)) - goto readpage_error; - if (!PageUptodate(page)) { - if (page->mapping == NULL) { - /* - * invalidate_mapping_pages got it - */ - unlock_page(page); - put_page(page); - goto find_page; - } - unlock_page(page); - shrink_readahead_size_eio(filp, ra); - error = -EIO; - goto readpage_error; - } - unlock_page(page); - } - - goto page_ok; - -readpage_error: - /* UHHUH! A synchronous read error occurred. Report it */ - put_page(page); - goto out; - -no_cached_page: - /* - * Ok, it wasn't cached, so we need to create a new - * page.. - */ - page = page_cache_alloc_cold(mapping); - if (!page) { - error = -ENOMEM; - goto out; - } - error = add_to_page_cache_lru(page, mapping, index, - mapping_gfp_constraint(mapping, GFP_KERNEL)); - if (error) { - put_page(page); - if (error == -EEXIST) { - error = 0; - goto find_page; - } - goto out; - } - goto readpage; - } - -out: - ra->prev_pos = prev_index; - ra->prev_pos <<= PAGE_SHIFT; - ra->prev_pos |= prev_offset; - - *ppos = ((loff_t)index << PAGE_SHIFT) + offset; - file_accessed(filp); - return written ? written : error; -} - -/** - * generic_file_read_iter - generic filesystem read routine - * @iocb: kernel I/O control block - * @iter: destination for the data read - * - * This is the "read_iter()" routine for all filesystems - * that can use the page cache directly. - */ -ssize_t -generic_file_read_iter(struct kiocb *iocb, struct iov_iter *iter) -{ - struct file *file = iocb->ki_filp; - ssize_t retval = 0; - size_t count = iov_iter_count(iter); - - if (!count) - goto out; /* skip atime */ - - if (iocb->ki_flags & IOCB_DIRECT) { - struct address_space *mapping = file->f_mapping; - struct inode *inode = mapping->host; - struct iov_iter data = *iter; - loff_t size; - - size = i_size_read(inode); - retval = filemap_write_and_wait_range(mapping, iocb->ki_pos, - iocb->ki_pos + count - 1); - if (retval < 0) - goto out; - - file_accessed(file); - - retval = mapping->a_ops->direct_IO(iocb, &data); - if (retval >= 0) { - iocb->ki_pos += retval; - iov_iter_advance(iter, retval); - } - - /* - * Btrfs can have a short DIO read if we encounter - * compressed extents, so if there was an error, or if - * we've already read everything we wanted to, or if - * there was a short read because we hit EOF, go ahead - * and return. Otherwise fallthrough to buffered io for - * the rest of the read. Buffered reads will not work for - * DAX files, so don't bother trying. - */ - if (retval < 0 || !iov_iter_count(iter) || iocb->ki_pos >= size || - IS_DAX(inode)) - goto out; - } - - retval = do_generic_file_read(file, &iocb->ki_pos, iter, retval); -out: - return retval; -} -EXPORT_SYMBOL(generic_file_read_iter); - -#ifdef CONFIG_MMU -/** - * page_cache_read - adds requested page to the page cache if not already there - * @file: file to read - * @offset: page index - * @gfp_mask: memory allocation flags - * - * This adds the requested page to the page cache if it isn't already there, - * and schedules an I/O to read in its contents from disk. - */ -static int page_cache_read(struct file *file, pgoff_t offset, gfp_t gfp_mask) -{ - struct address_space *mapping = file->f_mapping; - struct page *page; - int ret; - - do { - page = __page_cache_alloc(gfp_mask|__GFP_COLD); - if (!page) - return -ENOMEM; - - ret = add_to_page_cache_lru(page, mapping, offset, gfp_mask & GFP_KERNEL); - if (ret == 0) - ret = mapping->a_ops->readpage(file, page); - else if (ret == -EEXIST) - ret = 0; /* losing race to add is OK */ - - put_page(page); - - } while (ret == AOP_TRUNCATED_PAGE); - - return ret; -} - -#define MMAP_LOTSAMISS (100) - -/* - * Synchronous readahead happens when we don't even find - * a page in the page cache at all. - */ -static void do_sync_mmap_readahead(struct vm_area_struct *vma, - struct file_ra_state *ra, - struct file *file, - pgoff_t offset) -{ - struct address_space *mapping = file->f_mapping; - - /* If we don't want any read-ahead, don't bother */ - if (vma->vm_flags & VM_RAND_READ) - return; - if (!ra->ra_pages) - return; - - if (vma->vm_flags & VM_SEQ_READ) { - page_cache_sync_readahead(mapping, ra, file, offset, - ra->ra_pages); - return; - } - - /* Avoid banging the cache line if not needed */ - if (ra->mmap_miss < MMAP_LOTSAMISS * 10) - ra->mmap_miss++; - - /* - * Do we miss much more than hit in this file? If so, - * stop bothering with read-ahead. It will only hurt. - */ - if (ra->mmap_miss > MMAP_LOTSAMISS) - return; - - /* - * mmap read-around - */ - ra->start = max_t(long, 0, offset - ra->ra_pages / 2); - ra->size = ra->ra_pages; - ra->async_size = ra->ra_pages / 4; - ra_submit(ra, mapping, file); -} - -/* - * Asynchronous readahead happens when we find the page and PG_readahead, - * so we want to possibly extend the readahead further.. - */ -static void do_async_mmap_readahead(struct vm_area_struct *vma, - struct file_ra_state *ra, - struct file *file, - struct page *page, - pgoff_t offset) -{ - struct address_space *mapping = file->f_mapping; - - /* If we don't want any read-ahead, don't bother */ - if (vma->vm_flags & VM_RAND_READ) - return; - if (ra->mmap_miss > 0) - ra->mmap_miss--; - if (PageReadahead(page)) - page_cache_async_readahead(mapping, ra, file, - page, offset, ra->ra_pages); -} - -/** - * filemap_fault - read in file data for page fault handling - * @vma: vma in which the fault was taken - * @vmf: struct vm_fault containing details of the fault - * - * filemap_fault() is invoked via the vma operations vector for a - * mapped memory region to read in file data during a page fault. - * - * The goto's are kind of ugly, but this streamlines the normal case of having - * it in the page cache, and handles the special cases reasonably without - * having a lot of duplicated code. - * - * vma->vm_mm->mmap_sem must be held on entry. - * - * If our return value has VM_FAULT_RETRY set, it's because - * lock_page_or_retry() returned 0. - * The mmap_sem has usually been released in this case. - * See __lock_page_or_retry() for the exception. - * - * If our return value does not have VM_FAULT_RETRY set, the mmap_sem - * has not been released. - * - * We never return with VM_FAULT_RETRY and a bit from VM_FAULT_ERROR set. - */ -int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - int error; - struct file *file = vma->vm_file; - struct address_space *mapping = file->f_mapping; - struct file_ra_state *ra = &file->f_ra; - struct inode *inode = mapping->host; - pgoff_t offset = vmf->pgoff; - struct page *page; - loff_t size; - int ret = 0; - - size = round_up(i_size_read(inode), PAGE_SIZE); - if (offset >= size >> PAGE_SHIFT) - return VM_FAULT_SIGBUS; - - /* - * Do we have something in the page cache already? - */ - page = find_get_page(mapping, offset); - if (likely(page) && !(vmf->flags & FAULT_FLAG_TRIED)) { - /* - * We found the page, so try async readahead before - * waiting for the lock. - */ - do_async_mmap_readahead(vma, ra, file, page, offset); - } else if (!page) { - /* No page in the page cache at all */ - do_sync_mmap_readahead(vma, ra, file, offset); - count_vm_event(PGMAJFAULT); - mem_cgroup_count_vm_event(vma->vm_mm, PGMAJFAULT); - ret = VM_FAULT_MAJOR; -retry_find: - page = find_get_page(mapping, offset); - if (!page) - goto no_cached_page; - } - - if (!lock_page_or_retry(page, vma->vm_mm, vmf->flags)) { - put_page(page); - return ret | VM_FAULT_RETRY; - } - - /* Did it get truncated? */ - if (unlikely(page->mapping != mapping)) { - unlock_page(page); - put_page(page); - goto retry_find; - } - VM_BUG_ON_PAGE(page->index != offset, page); - - /* - * We have a locked page in the page cache, now we need to check - * that it's up-to-date. If not, it is going to be due to an error. - */ - if (unlikely(!PageUptodate(page))) - goto page_not_uptodate; - - /* - * Found the page and have a reference on it. - * We must recheck i_size under page lock. - */ - size = round_up(i_size_read(inode), PAGE_SIZE); - if (unlikely(offset >= size >> PAGE_SHIFT)) { - unlock_page(page); - put_page(page); - return VM_FAULT_SIGBUS; - } - - vmf->page = page; - return ret | VM_FAULT_LOCKED; - -no_cached_page: - /* - * We're only likely to ever get here if MADV_RANDOM is in - * effect. - */ - error = page_cache_read(file, offset, vmf->gfp_mask); - - /* - * The page we want has now been added to the page cache. - * In the unlikely event that someone removed it in the - * meantime, we'll just come back here and read it again. - */ - if (error >= 0) - goto retry_find; - - /* - * An error return from page_cache_read can result if the - * system is low on memory, or a problem occurs while trying - * to schedule I/O. - */ - if (error == -ENOMEM) - return VM_FAULT_OOM; - return VM_FAULT_SIGBUS; - -page_not_uptodate: - /* - * Umm, take care of errors if the page isn't up-to-date. - * Try to re-read it _once_. We do this synchronously, - * because there really aren't any performance issues here - * and we need to check for errors. - */ - ClearPageError(page); - error = mapping->a_ops->readpage(file, page); - if (!error) { - wait_on_page_locked(page); - if (!PageUptodate(page)) - error = -EIO; - } - put_page(page); - - if (!error || error == AOP_TRUNCATED_PAGE) - goto retry_find; - - /* Things didn't work out. Return zero to tell the mm layer so. */ - shrink_readahead_size_eio(file, ra); - return VM_FAULT_SIGBUS; -} -EXPORT_SYMBOL(filemap_fault); - -void filemap_map_pages(struct fault_env *fe, - pgoff_t start_pgoff, pgoff_t end_pgoff) -{ - struct radix_tree_iter iter; - void **slot; - struct file *file = fe->vma->vm_file; - struct address_space *mapping = file->f_mapping; - pgoff_t last_pgoff = start_pgoff; - loff_t size; - struct page *head, *page; - - rcu_read_lock(); - radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, - start_pgoff) { - if (iter.index > end_pgoff) - break; -repeat: - page = radix_tree_deref_slot(slot); - if (unlikely(!page)) - goto next; - if (radix_tree_exception(page)) { - if (radix_tree_deref_retry(page)) { - slot = radix_tree_iter_retry(&iter); - continue; - } - goto next; - } - - head = compound_head(page); - if (!page_cache_get_speculative(head)) - goto repeat; - - /* The page was split under us? */ - if (compound_head(page) != head) { - put_page(head); - goto repeat; - } - - /* Has the page moved? */ - if (unlikely(page != *slot)) { - put_page(head); - goto repeat; - } - - if (!PageUptodate(page) || - PageReadahead(page) || - PageHWPoison(page)) - goto skip; - if (!trylock_page(page)) - goto skip; - - if (page->mapping != mapping || !PageUptodate(page)) - goto unlock; - - size = round_up(i_size_read(mapping->host), PAGE_SIZE); - if (page->index >= size >> PAGE_SHIFT) - goto unlock; - - if (file->f_ra.mmap_miss > 0) - file->f_ra.mmap_miss--; - - fe->address += (iter.index - last_pgoff) << PAGE_SHIFT; - if (fe->pte) - fe->pte += iter.index - last_pgoff; - last_pgoff = iter.index; - if (alloc_set_pte(fe, NULL, page)) - goto unlock; - unlock_page(page); - goto next; -unlock: - unlock_page(page); -skip: - put_page(page); -next: - /* Huge page is mapped? No need to proceed. */ - if (pmd_trans_huge(*fe->pmd)) - break; - if (iter.index == end_pgoff) - break; - } - rcu_read_unlock(); -} -EXPORT_SYMBOL(filemap_map_pages); - -int filemap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct page *page = vmf->page; - struct inode *inode = file_inode(vma->vm_file); - int ret = VM_FAULT_LOCKED; - - sb_start_pagefault(inode->i_sb); - file_update_time(vma->vm_file); - lock_page(page); - if (page->mapping != inode->i_mapping) { - unlock_page(page); - ret = VM_FAULT_NOPAGE; - goto out; - } - /* - * We mark the page dirty already here so that when freeze is in - * progress, we are guaranteed that writeback during freezing will - * see the dirty page and writeprotect it again. - */ - set_page_dirty(page); - wait_for_stable_page(page); -out: - sb_end_pagefault(inode->i_sb); - return ret; -} -EXPORT_SYMBOL(filemap_page_mkwrite); - -const struct vm_operations_struct generic_file_vm_ops = { - .fault = filemap_fault, - .map_pages = filemap_map_pages, - .page_mkwrite = filemap_page_mkwrite, -}; - -/* This is used for a general mmap of a disk file */ - -int generic_file_mmap(struct file * file, struct vm_area_struct * vma) -{ - struct address_space *mapping = file->f_mapping; - - if (!mapping->a_ops->readpage) - return -ENOEXEC; - file_accessed(file); - vma->vm_ops = &generic_file_vm_ops; - return 0; -} - -/* - * This is for filesystems which do not implement ->writepage. - */ -int generic_file_readonly_mmap(struct file *file, struct vm_area_struct *vma) -{ - if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_MAYWRITE)) - return -EINVAL; - return generic_file_mmap(file, vma); -} -#else -int generic_file_mmap(struct file * file, struct vm_area_struct * vma) -{ - return -ENOSYS; -} -int generic_file_readonly_mmap(struct file * file, struct vm_area_struct * vma) -{ - return -ENOSYS; -} -#endif /* CONFIG_MMU */ - -EXPORT_SYMBOL(generic_file_mmap); -EXPORT_SYMBOL(generic_file_readonly_mmap); - -static struct page *wait_on_page_read(struct page *page) -{ - if (!IS_ERR(page)) { - wait_on_page_locked(page); - if (!PageUptodate(page)) { - put_page(page); - page = ERR_PTR(-EIO); - } - } - return page; -} - -static struct page *do_read_cache_page(struct address_space *mapping, - pgoff_t index, - int (*filler)(void *, struct page *), - void *data, - gfp_t gfp) -{ - struct page *page; - int err; -repeat: - page = find_get_page(mapping, index); - if (!page) { - page = __page_cache_alloc(gfp | __GFP_COLD); - if (!page) - return ERR_PTR(-ENOMEM); - err = add_to_page_cache_lru(page, mapping, index, gfp); - if (unlikely(err)) { - put_page(page); - if (err == -EEXIST) - goto repeat; - /* Presumably ENOMEM for radix tree node */ - return ERR_PTR(err); - } - -filler: - err = filler(data, page); - if (err < 0) { - put_page(page); - return ERR_PTR(err); - } - - page = wait_on_page_read(page); - if (IS_ERR(page)) - return page; - goto out; - } - if (PageUptodate(page)) - goto out; - - /* - * Page is not up to date and may be locked due one of the following - * case a: Page is being filled and the page lock is held - * case b: Read/write error clearing the page uptodate status - * case c: Truncation in progress (page locked) - * case d: Reclaim in progress - * - * Case a, the page will be up to date when the page is unlocked. - * There is no need to serialise on the page lock here as the page - * is pinned so the lock gives no additional protection. Even if the - * the page is truncated, the data is still valid if PageUptodate as - * it's a race vs truncate race. - * Case b, the page will not be up to date - * Case c, the page may be truncated but in itself, the data may still - * be valid after IO completes as it's a read vs truncate race. The - * operation must restart if the page is not uptodate on unlock but - * otherwise serialising on page lock to stabilise the mapping gives - * no additional guarantees to the caller as the page lock is - * released before return. - * Case d, similar to truncation. If reclaim holds the page lock, it - * will be a race with remove_mapping that determines if the mapping - * is valid on unlock but otherwise the data is valid and there is - * no need to serialise with page lock. - * - * As the page lock gives no additional guarantee, we optimistically - * wait on the page to be unlocked and check if it's up to date and - * use the page if it is. Otherwise, the page lock is required to - * distinguish between the different cases. The motivation is that we - * avoid spurious serialisations and wakeups when multiple processes - * wait on the same page for IO to complete. - */ - wait_on_page_locked(page); - if (PageUptodate(page)) - goto out; - - /* Distinguish between all the cases under the safety of the lock */ - lock_page(page); - - /* Case c or d, restart the operation */ - if (!page->mapping) { - unlock_page(page); - put_page(page); - goto repeat; - } - - /* Someone else locked and filled the page in a very small window */ - if (PageUptodate(page)) { - unlock_page(page); - goto out; - } - goto filler; - -out: - mark_page_accessed(page); - return page; -} - -/** - * read_cache_page - read into page cache, fill it if needed - * @mapping: the page's address_space - * @index: the page index - * @filler: function to perform the read - * @data: first arg to filler(data, page) function, often left as NULL - * - * Read into the page cache. If a page already exists, and PageUptodate() is - * not set, try to fill the page and wait for it to become unlocked. - * - * If the page does not get brought uptodate, return -EIO. - */ -struct page *read_cache_page(struct address_space *mapping, - pgoff_t index, - int (*filler)(void *, struct page *), - void *data) -{ - return do_read_cache_page(mapping, index, filler, data, mapping_gfp_mask(mapping)); -} -EXPORT_SYMBOL(read_cache_page); - -/** - * read_cache_page_gfp - read into page cache, using specified page allocation flags. - * @mapping: the page's address_space - * @index: the page index - * @gfp: the page allocator flags to use if allocating - * - * This is the same as "read_mapping_page(mapping, index, NULL)", but with - * any new page allocations done using the specified allocation flags. - * - * If the page does not get brought uptodate, return -EIO. - */ -struct page *read_cache_page_gfp(struct address_space *mapping, - pgoff_t index, - gfp_t gfp) -{ - filler_t *filler = (filler_t *)mapping->a_ops->readpage; - - return do_read_cache_page(mapping, index, filler, NULL, gfp); -} -EXPORT_SYMBOL(read_cache_page_gfp); - -/* - * Performs necessary checks before doing a write - * - * Can adjust writing position or amount of bytes to write. - * Returns appropriate error code that caller should return or - * zero in case that write should be allowed. - */ -inline ssize_t generic_write_checks(struct kiocb *iocb, struct iov_iter *from) -{ - struct file *file = iocb->ki_filp; - struct inode *inode = file->f_mapping->host; - unsigned long limit = rlimit(RLIMIT_FSIZE); - loff_t pos; - - if (!iov_iter_count(from)) - return 0; - - /* FIXME: this is for backwards compatibility with 2.4 */ - if (iocb->ki_flags & IOCB_APPEND) - iocb->ki_pos = i_size_read(inode); - - pos = iocb->ki_pos; - - if (limit != RLIM_INFINITY) { - if (iocb->ki_pos >= limit) { - send_sig(SIGXFSZ, current, 0); - return -EFBIG; - } - iov_iter_truncate(from, limit - (unsigned long)pos); - } - - /* - * LFS rule - */ - if (unlikely(pos + iov_iter_count(from) > MAX_NON_LFS && - !(file->f_flags & O_LARGEFILE))) { - if (pos >= MAX_NON_LFS) - return -EFBIG; - iov_iter_truncate(from, MAX_NON_LFS - (unsigned long)pos); - } - - /* - * Are we about to exceed the fs block limit ? - * - * If we have written data it becomes a short write. If we have - * exceeded without writing data we send a signal and return EFBIG. - * Linus frestrict idea will clean these up nicely.. - */ - if (unlikely(pos >= inode->i_sb->s_maxbytes)) - return -EFBIG; - - iov_iter_truncate(from, inode->i_sb->s_maxbytes - pos); - return iov_iter_count(from); -} -EXPORT_SYMBOL(generic_write_checks); - -int pagecache_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) -{ - const struct address_space_operations *aops = mapping->a_ops; - - return aops->write_begin(file, mapping, pos, len, flags, - pagep, fsdata); -} -EXPORT_SYMBOL(pagecache_write_begin); - -int pagecache_write_end(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) -{ - const struct address_space_operations *aops = mapping->a_ops; - - return aops->write_end(file, mapping, pos, len, copied, page, fsdata); -} -EXPORT_SYMBOL(pagecache_write_end); - -ssize_t -generic_file_direct_write(struct kiocb *iocb, struct iov_iter *from) -{ - struct file *file = iocb->ki_filp; - struct address_space *mapping = file->f_mapping; - struct inode *inode = mapping->host; - loff_t pos = iocb->ki_pos; - ssize_t written; - size_t write_len; - pgoff_t end; - struct iov_iter data; - - write_len = iov_iter_count(from); - end = (pos + write_len - 1) >> PAGE_SHIFT; - - written = filemap_write_and_wait_range(mapping, pos, pos + write_len - 1); - if (written) - goto out; - - /* - * After a write we want buffered reads to be sure to go to disk to get - * the new data. We invalidate clean cached page from the region we're - * about to write. We do this *before* the write so that we can return - * without clobbering -EIOCBQUEUED from ->direct_IO(). - */ - if (mapping->nrpages) { - written = invalidate_inode_pages2_range(mapping, - pos >> PAGE_SHIFT, end); - /* - * If a page can not be invalidated, return 0 to fall back - * to buffered write. - */ - if (written) { - if (written == -EBUSY) - return 0; - goto out; - } - } - - data = *from; - written = mapping->a_ops->direct_IO(iocb, &data); - - /* - * Finally, try again to invalidate clean pages which might have been - * cached by non-direct readahead, or faulted in by get_user_pages() - * if the source of the write was an mmap'ed region of the file - * we're writing. Either one is a pretty crazy thing to do, - * so we don't support it 100%. If this invalidation - * fails, tough, the write still worked... - */ - if (mapping->nrpages) { - invalidate_inode_pages2_range(mapping, - pos >> PAGE_SHIFT, end); - } - - if (written > 0) { - pos += written; - iov_iter_advance(from, written); - if (pos > i_size_read(inode) && !S_ISBLK(inode->i_mode)) { - i_size_write(inode, pos); - mark_inode_dirty(inode); - } - iocb->ki_pos = pos; - } -out: - return written; -} -EXPORT_SYMBOL(generic_file_direct_write); - -/* - * Find or create a page at the given pagecache position. Return the locked - * page. This function is specifically for buffered writes. - */ -struct page *grab_cache_page_write_begin(struct address_space *mapping, - pgoff_t index, unsigned flags) -{ - struct page *page; - int fgp_flags = FGP_LOCK|FGP_WRITE|FGP_CREAT; - - if (flags & AOP_FLAG_NOFS) - fgp_flags |= FGP_NOFS; - - page = pagecache_get_page(mapping, index, fgp_flags, - mapping_gfp_mask(mapping)); - if (page) - wait_for_stable_page(page); - - return page; -} -EXPORT_SYMBOL(grab_cache_page_write_begin); - -ssize_t generic_perform_write(struct file *file, - struct iov_iter *i, loff_t pos) -{ - struct address_space *mapping = file->f_mapping; - const struct address_space_operations *a_ops = mapping->a_ops; - long status = 0; - ssize_t written = 0; - unsigned int flags = 0; - - /* - * Copies from kernel address space cannot fail (NFSD is a big user). - */ - if (!iter_is_iovec(i)) - flags |= AOP_FLAG_UNINTERRUPTIBLE; - - do { - struct page *page; - unsigned long offset; /* Offset into pagecache page */ - unsigned long bytes; /* Bytes to write to page */ - size_t copied; /* Bytes copied from user */ - void *fsdata; - - offset = (pos & (PAGE_SIZE - 1)); - bytes = min_t(unsigned long, PAGE_SIZE - offset, - iov_iter_count(i)); - -again: - /* - * Bring in the user page that we will copy from _first_. - * Otherwise there's a nasty deadlock on copying from the - * same page as we're writing to, without it being marked - * up-to-date. - * - * Not only is this an optimisation, but it is also required - * to check that the address is actually valid, when atomic - * usercopies are used, below. - */ - if (unlikely(iov_iter_fault_in_readable(i, bytes))) { - status = -EFAULT; - break; - } - - if (fatal_signal_pending(current)) { - status = -EINTR; - break; - } - - status = a_ops->write_begin(file, mapping, pos, bytes, flags, - &page, &fsdata); - if (unlikely(status < 0)) - break; - - if (mapping_writably_mapped(mapping)) - flush_dcache_page(page); - - copied = iov_iter_copy_from_user_atomic(page, i, offset, bytes); - flush_dcache_page(page); - - status = a_ops->write_end(file, mapping, pos, bytes, copied, - page, fsdata); - if (unlikely(status < 0)) - break; - copied = status; - - cond_resched(); - - iov_iter_advance(i, copied); - if (unlikely(copied == 0)) { - /* - * If we were unable to copy any data at all, we must - * fall back to a single segment length write. - * - * If we didn't fallback here, we could livelock - * because not all segments in the iov can be copied at - * once without a pagefault. - */ - bytes = min_t(unsigned long, PAGE_SIZE - offset, - iov_iter_single_seg_count(i)); - goto again; - } - pos += copied; - written += copied; - - balance_dirty_pages_ratelimited(mapping); - } while (iov_iter_count(i)); - - return written ? written : status; -} -EXPORT_SYMBOL(generic_perform_write); - -/** - * __generic_file_write_iter - write data to a file - * @iocb: IO state structure (file, offset, etc.) - * @from: iov_iter with data to write - * - * This function does all the work needed for actually writing data to a - * file. It does all basic checks, removes SUID from the file, updates - * modification times and calls proper subroutines depending on whether we - * do direct IO or a standard buffered write. - * - * It expects i_mutex to be grabbed unless we work on a block device or similar - * object which does not need locking at all. - * - * This function does *not* take care of syncing data in case of O_SYNC write. - * A caller has to handle it. This is mainly due to the fact that we want to - * avoid syncing under i_mutex. - */ -ssize_t __generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) -{ - struct file *file = iocb->ki_filp; - struct address_space * mapping = file->f_mapping; - struct inode *inode = mapping->host; - ssize_t written = 0; - ssize_t err; - ssize_t status; - - /* We can write back this queue in page reclaim */ - current->backing_dev_info = inode_to_bdi(inode); - err = file_remove_privs(file); - if (err) - goto out; - - err = file_update_time(file); - if (err) - goto out; - - if (iocb->ki_flags & IOCB_DIRECT) { - loff_t pos, endbyte; - - written = generic_file_direct_write(iocb, from); - /* - * If the write stopped short of completing, fall back to - * buffered writes. Some filesystems do this for writes to - * holes, for example. For DAX files, a buffered write will - * not succeed (even if it did, DAX does not handle dirty - * page-cache pages correctly). - */ - if (written < 0 || !iov_iter_count(from) || IS_DAX(inode)) - goto out; - - status = generic_perform_write(file, from, pos = iocb->ki_pos); - /* - * If generic_perform_write() returned a synchronous error - * then we want to return the number of bytes which were - * direct-written, or the error code if that was zero. Note - * that this differs from normal direct-io semantics, which - * will return -EFOO even if some bytes were written. - */ - if (unlikely(status < 0)) { - err = status; - goto out; - } - /* - * We need to ensure that the page cache pages are written to - * disk and invalidated to preserve the expected O_DIRECT - * semantics. - */ - endbyte = pos + status - 1; - err = filemap_write_and_wait_range(mapping, pos, endbyte); - if (err == 0) { - iocb->ki_pos = endbyte + 1; - written += status; - invalidate_mapping_pages(mapping, - pos >> PAGE_SHIFT, - endbyte >> PAGE_SHIFT); - } else { - /* - * We don't know how much we wrote, so just return - * the number of bytes which were direct-written - */ - } - } else { - written = generic_perform_write(file, from, iocb->ki_pos); - if (likely(written > 0)) - iocb->ki_pos += written; - } -out: - current->backing_dev_info = NULL; - return written ? written : err; -} -EXPORT_SYMBOL(__generic_file_write_iter); - -/** - * generic_file_write_iter - write data to a file - * @iocb: IO state structure - * @from: iov_iter with data to write - * - * This is a wrapper around __generic_file_write_iter() to be used by most - * filesystems. It takes care of syncing the file in case of O_SYNC file - * and acquires i_mutex as needed. - */ -ssize_t generic_file_write_iter(struct kiocb *iocb, struct iov_iter *from) -{ - struct file *file = iocb->ki_filp; - struct inode *inode = file->f_mapping->host; - ssize_t ret; - - inode_lock(inode); - ret = generic_write_checks(iocb, from); - if (ret > 0) - ret = __generic_file_write_iter(iocb, from); - inode_unlock(inode); - - if (ret > 0) - ret = generic_write_sync(iocb, ret); - return ret; -} -EXPORT_SYMBOL(generic_file_write_iter); - -/** - * try_to_release_page() - release old fs-specific metadata on a page - * - * @page: the page which the kernel is trying to free - * @gfp_mask: memory allocation flags (and I/O mode) - * - * The address_space is to try to release any data against the page - * (presumably at page->private). If the release was successful, return `1'. - * Otherwise return zero. - * - * This may also be called if PG_fscache is set on a page, indicating that the - * page is known to the local caching routines. - * - * The @gfp_mask argument specifies whether I/O may be performed to release - * this page (__GFP_IO), and whether the call may block (__GFP_RECLAIM & __GFP_FS). - * - */ -int try_to_release_page(struct page *page, gfp_t gfp_mask) -{ - struct address_space * const mapping = page->mapping; - - BUG_ON(!PageLocked(page)); - if (PageWriteback(page)) - return 0; - - if (mapping && mapping->a_ops->releasepage) - return mapping->a_ops->releasepage(page, gfp_mask); - return try_to_free_buffers(page); -} - -EXPORT_SYMBOL(try_to_release_page); diff --git a/src/linux/mm/init-mm.c b/src/linux/mm/init-mm.c deleted file mode 100644 index a56a851..0000000 --- a/src/linux/mm/init-mm.c +++ /dev/null @@ -1,25 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#ifndef INIT_MM_CONTEXT -#define INIT_MM_CONTEXT(name) -#endif - -struct mm_struct init_mm = { - .mm_rb = RB_ROOT, - .pgd = swapper_pg_dir, - .mm_users = ATOMIC_INIT(2), - .mm_count = ATOMIC_INIT(1), - .mmap_sem = __RWSEM_INITIALIZER(init_mm.mmap_sem), - .page_table_lock = __SPIN_LOCK_UNLOCKED(init_mm.page_table_lock), - .mmlist = LIST_HEAD_INIT(init_mm.mmlist), - INIT_MM_CONTEXT(init_mm) -}; diff --git a/src/linux/mm/internal.h b/src/linux/mm/internal.h deleted file mode 100644 index 537ac99..0000000 --- a/src/linux/mm/internal.h +++ /dev/null @@ -1,489 +0,0 @@ -/* internal.h: mm/ internal definitions - * - * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved. - * Written by David Howells (dhowells@redhat.com) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#ifndef __MM_INTERNAL_H -#define __MM_INTERNAL_H - -#include -#include -#include -#include - -/* - * The set of flags that only affect watermark checking and reclaim - * behaviour. This is used by the MM to obey the caller constraints - * about IO, FS and watermark checking while ignoring placement - * hints such as HIGHMEM usage. - */ -#define GFP_RECLAIM_MASK (__GFP_RECLAIM|__GFP_HIGH|__GFP_IO|__GFP_FS|\ - __GFP_NOWARN|__GFP_REPEAT|__GFP_NOFAIL|\ - __GFP_NORETRY|__GFP_MEMALLOC|__GFP_NOMEMALLOC|\ - __GFP_ATOMIC) - -/* The GFP flags allowed during early boot */ -#define GFP_BOOT_MASK (__GFP_BITS_MASK & ~(__GFP_RECLAIM|__GFP_IO|__GFP_FS)) - -/* Control allocation cpuset and node placement constraints */ -#define GFP_CONSTRAINT_MASK (__GFP_HARDWALL|__GFP_THISNODE) - -/* Do not use these with a slab allocator */ -#define GFP_SLAB_BUG_MASK (__GFP_DMA32|__GFP_HIGHMEM|~__GFP_BITS_MASK) - -int do_swap_page(struct fault_env *fe, pte_t orig_pte); - -void free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *start_vma, - unsigned long floor, unsigned long ceiling); - -void unmap_page_range(struct mmu_gather *tlb, - struct vm_area_struct *vma, - unsigned long addr, unsigned long end, - struct zap_details *details); - -extern int __do_page_cache_readahead(struct address_space *mapping, - struct file *filp, pgoff_t offset, unsigned long nr_to_read, - unsigned long lookahead_size); - -/* - * Submit IO for the read-ahead request in file_ra_state. - */ -static inline unsigned long ra_submit(struct file_ra_state *ra, - struct address_space *mapping, struct file *filp) -{ - return __do_page_cache_readahead(mapping, filp, - ra->start, ra->size, ra->async_size); -} - -/* - * Turn a non-refcounted page (->_refcount == 0) into refcounted with - * a count of one. - */ -static inline void set_page_refcounted(struct page *page) -{ - VM_BUG_ON_PAGE(PageTail(page), page); - VM_BUG_ON_PAGE(page_ref_count(page), page); - set_page_count(page, 1); -} - -extern unsigned long highest_memmap_pfn; - -/* - * in mm/vmscan.c: - */ -extern int isolate_lru_page(struct page *page); -extern void putback_lru_page(struct page *page); -extern bool pgdat_reclaimable(struct pglist_data *pgdat); - -/* - * in mm/rmap.c: - */ -extern pmd_t *mm_find_pmd(struct mm_struct *mm, unsigned long address); - -/* - * in mm/page_alloc.c - */ - -/* - * Structure for holding the mostly immutable allocation parameters passed - * between functions involved in allocations, including the alloc_pages* - * family of functions. - * - * nodemask, migratetype and high_zoneidx are initialized only once in - * __alloc_pages_nodemask() and then never change. - * - * zonelist, preferred_zone and classzone_idx are set first in - * __alloc_pages_nodemask() for the fast path, and might be later changed - * in __alloc_pages_slowpath(). All other functions pass the whole strucure - * by a const pointer. - */ -struct alloc_context { - struct zonelist *zonelist; - nodemask_t *nodemask; - struct zoneref *preferred_zoneref; - int migratetype; - enum zone_type high_zoneidx; - bool spread_dirty_pages; -}; - -#define ac_classzone_idx(ac) zonelist_zone_idx(ac->preferred_zoneref) - -/* - * Locate the struct page for both the matching buddy in our - * pair (buddy1) and the combined O(n+1) page they form (page). - * - * 1) Any buddy B1 will have an order O twin B2 which satisfies - * the following equation: - * B2 = B1 ^ (1 << O) - * For example, if the starting buddy (buddy2) is #8 its order - * 1 buddy is #10: - * B2 = 8 ^ (1 << 1) = 8 ^ 2 = 10 - * - * 2) Any buddy B will have an order O+1 parent P which - * satisfies the following equation: - * P = B & ~(1 << O) - * - * Assumption: *_mem_map is contiguous at least up to MAX_ORDER - */ -static inline unsigned long -__find_buddy_index(unsigned long page_idx, unsigned int order) -{ - return page_idx ^ (1 << order); -} - -extern struct page *__pageblock_pfn_to_page(unsigned long start_pfn, - unsigned long end_pfn, struct zone *zone); - -static inline struct page *pageblock_pfn_to_page(unsigned long start_pfn, - unsigned long end_pfn, struct zone *zone) -{ - if (zone->contiguous) - return pfn_to_page(start_pfn); - - return __pageblock_pfn_to_page(start_pfn, end_pfn, zone); -} - -extern int __isolate_free_page(struct page *page, unsigned int order); -extern void __free_pages_bootmem(struct page *page, unsigned long pfn, - unsigned int order); -extern void prep_compound_page(struct page *page, unsigned int order); -extern void post_alloc_hook(struct page *page, unsigned int order, - gfp_t gfp_flags); -extern int user_min_free_kbytes; - -#if defined CONFIG_COMPACTION || defined CONFIG_CMA - -/* - * in mm/compaction.c - */ -/* - * compact_control is used to track pages being migrated and the free pages - * they are being migrated to during memory compaction. The free_pfn starts - * at the end of a zone and migrate_pfn begins at the start. Movable pages - * are moved to the end of a zone during a compaction run and the run - * completes when free_pfn <= migrate_pfn - */ -struct compact_control { - struct list_head freepages; /* List of free pages to migrate to */ - struct list_head migratepages; /* List of pages being migrated */ - unsigned long nr_freepages; /* Number of isolated free pages */ - unsigned long nr_migratepages; /* Number of pages to migrate */ - unsigned long free_pfn; /* isolate_freepages search base */ - unsigned long migrate_pfn; /* isolate_migratepages search base */ - unsigned long last_migrated_pfn;/* Not yet flushed page being freed */ - enum migrate_mode mode; /* Async or sync migration mode */ - bool ignore_skip_hint; /* Scan blocks even if marked skip */ - bool ignore_block_suitable; /* Scan blocks considered unsuitable */ - bool direct_compaction; /* False from kcompactd or /proc/... */ - bool whole_zone; /* Whole zone should/has been scanned */ - int order; /* order a direct compactor needs */ - const gfp_t gfp_mask; /* gfp mask of a direct compactor */ - const unsigned int alloc_flags; /* alloc flags of a direct compactor */ - const int classzone_idx; /* zone index of a direct compactor */ - struct zone *zone; - bool contended; /* Signal lock or sched contention */ -}; - -unsigned long -isolate_freepages_range(struct compact_control *cc, - unsigned long start_pfn, unsigned long end_pfn); -unsigned long -isolate_migratepages_range(struct compact_control *cc, - unsigned long low_pfn, unsigned long end_pfn); -int find_suitable_fallback(struct free_area *area, unsigned int order, - int migratetype, bool only_stealable, bool *can_steal); - -#endif - -/* - * This function returns the order of a free page in the buddy system. In - * general, page_zone(page)->lock must be held by the caller to prevent the - * page from being allocated in parallel and returning garbage as the order. - * If a caller does not hold page_zone(page)->lock, it must guarantee that the - * page cannot be allocated or merged in parallel. Alternatively, it must - * handle invalid values gracefully, and use page_order_unsafe() below. - */ -static inline unsigned int page_order(struct page *page) -{ - /* PageBuddy() must be checked by the caller */ - return page_private(page); -} - -/* - * Like page_order(), but for callers who cannot afford to hold the zone lock. - * PageBuddy() should be checked first by the caller to minimize race window, - * and invalid values must be handled gracefully. - * - * READ_ONCE is used so that if the caller assigns the result into a local - * variable and e.g. tests it for valid range before using, the compiler cannot - * decide to remove the variable and inline the page_private(page) multiple - * times, potentially observing different values in the tests and the actual - * use of the result. - */ -#define page_order_unsafe(page) READ_ONCE(page_private(page)) - -static inline bool is_cow_mapping(vm_flags_t flags) -{ - return (flags & (VM_SHARED | VM_MAYWRITE)) == VM_MAYWRITE; -} - -/* - * These three helpers classifies VMAs for virtual memory accounting. - */ - -/* - * Executable code area - executable, not writable, not stack - */ -static inline bool is_exec_mapping(vm_flags_t flags) -{ - return (flags & (VM_EXEC | VM_WRITE | VM_STACK)) == VM_EXEC; -} - -/* - * Stack area - atomatically grows in one direction - * - * VM_GROWSUP / VM_GROWSDOWN VMAs are always private anonymous: - * do_mmap() forbids all other combinations. - */ -static inline bool is_stack_mapping(vm_flags_t flags) -{ - return (flags & VM_STACK) == VM_STACK; -} - -/* - * Data area - private, writable, not stack - */ -static inline bool is_data_mapping(vm_flags_t flags) -{ - return (flags & (VM_WRITE | VM_SHARED | VM_STACK)) == VM_WRITE; -} - -/* mm/util.c */ -void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma, - struct vm_area_struct *prev, struct rb_node *rb_parent); - -#ifdef CONFIG_MMU -extern long populate_vma_page_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end, int *nonblocking); -extern void munlock_vma_pages_range(struct vm_area_struct *vma, - unsigned long start, unsigned long end); -static inline void munlock_vma_pages_all(struct vm_area_struct *vma) -{ - munlock_vma_pages_range(vma, vma->vm_start, vma->vm_end); -} - -/* - * must be called with vma's mmap_sem held for read or write, and page locked. - */ -extern void mlock_vma_page(struct page *page); -extern unsigned int munlock_vma_page(struct page *page); - -/* - * Clear the page's PageMlocked(). This can be useful in a situation where - * we want to unconditionally remove a page from the pagecache -- e.g., - * on truncation or freeing. - * - * It is legal to call this function for any page, mlocked or not. - * If called for a page that is still mapped by mlocked vmas, all we do - * is revert to lazy LRU behaviour -- semantics are not broken. - */ -extern void clear_page_mlock(struct page *page); - -/* - * mlock_migrate_page - called only from migrate_misplaced_transhuge_page() - * (because that does not go through the full procedure of migration ptes): - * to migrate the Mlocked page flag; update statistics. - */ -static inline void mlock_migrate_page(struct page *newpage, struct page *page) -{ - if (TestClearPageMlocked(page)) { - int nr_pages = hpage_nr_pages(page); - - /* Holding pmd lock, no change in irq context: __mod is safe */ - __mod_zone_page_state(page_zone(page), NR_MLOCK, -nr_pages); - SetPageMlocked(newpage); - __mod_zone_page_state(page_zone(newpage), NR_MLOCK, nr_pages); - } -} - -extern pmd_t maybe_pmd_mkwrite(pmd_t pmd, struct vm_area_struct *vma); - -/* - * At what user virtual address is page expected in @vma? - */ -static inline unsigned long -__vma_address(struct page *page, struct vm_area_struct *vma) -{ - pgoff_t pgoff = page_to_pgoff(page); - return vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT); -} - -static inline unsigned long -vma_address(struct page *page, struct vm_area_struct *vma) -{ - unsigned long address = __vma_address(page, vma); - - /* page should be within @vma mapping range */ - VM_BUG_ON_VMA(address < vma->vm_start || address >= vma->vm_end, vma); - - return address; -} - -#else /* !CONFIG_MMU */ -static inline void clear_page_mlock(struct page *page) { } -static inline void mlock_vma_page(struct page *page) { } -static inline void mlock_migrate_page(struct page *new, struct page *old) { } - -#endif /* !CONFIG_MMU */ - -/* - * Return the mem_map entry representing the 'offset' subpage within - * the maximally aligned gigantic page 'base'. Handle any discontiguity - * in the mem_map at MAX_ORDER_NR_PAGES boundaries. - */ -static inline struct page *mem_map_offset(struct page *base, int offset) -{ - if (unlikely(offset >= MAX_ORDER_NR_PAGES)) - return nth_page(base, offset); - return base + offset; -} - -/* - * Iterator over all subpages within the maximally aligned gigantic - * page 'base'. Handle any discontiguity in the mem_map. - */ -static inline struct page *mem_map_next(struct page *iter, - struct page *base, int offset) -{ - if (unlikely((offset & (MAX_ORDER_NR_PAGES - 1)) == 0)) { - unsigned long pfn = page_to_pfn(base) + offset; - if (!pfn_valid(pfn)) - return NULL; - return pfn_to_page(pfn); - } - return iter + 1; -} - -/* - * FLATMEM and DISCONTIGMEM configurations use alloc_bootmem_node, - * so all functions starting at paging_init should be marked __init - * in those cases. SPARSEMEM, however, allows for memory hotplug, - * and alloc_bootmem_node is not used. - */ -#ifdef CONFIG_SPARSEMEM -#define __paginginit __meminit -#else -#define __paginginit __init -#endif - -/* Memory initialisation debug and verification */ -enum mminit_level { - MMINIT_WARNING, - MMINIT_VERIFY, - MMINIT_TRACE -}; - -#ifdef CONFIG_DEBUG_MEMORY_INIT - -extern int mminit_loglevel; - -#define mminit_dprintk(level, prefix, fmt, arg...) \ -do { \ - if (level < mminit_loglevel) { \ - if (level <= MMINIT_WARNING) \ - pr_warn("mminit::" prefix " " fmt, ##arg); \ - else \ - printk(KERN_DEBUG "mminit::" prefix " " fmt, ##arg); \ - } \ -} while (0) - -extern void mminit_verify_pageflags_layout(void); -extern void mminit_verify_zonelist(void); -#else - -static inline void mminit_dprintk(enum mminit_level level, - const char *prefix, const char *fmt, ...) -{ -} - -static inline void mminit_verify_pageflags_layout(void) -{ -} - -static inline void mminit_verify_zonelist(void) -{ -} -#endif /* CONFIG_DEBUG_MEMORY_INIT */ - -/* mminit_validate_memmodel_limits is independent of CONFIG_DEBUG_MEMORY_INIT */ -#if defined(CONFIG_SPARSEMEM) -extern void mminit_validate_memmodel_limits(unsigned long *start_pfn, - unsigned long *end_pfn); -#else -static inline void mminit_validate_memmodel_limits(unsigned long *start_pfn, - unsigned long *end_pfn) -{ -} -#endif /* CONFIG_SPARSEMEM */ - -#define NODE_RECLAIM_NOSCAN -2 -#define NODE_RECLAIM_FULL -1 -#define NODE_RECLAIM_SOME 0 -#define NODE_RECLAIM_SUCCESS 1 - -extern int hwpoison_filter(struct page *p); - -extern u32 hwpoison_filter_dev_major; -extern u32 hwpoison_filter_dev_minor; -extern u64 hwpoison_filter_flags_mask; -extern u64 hwpoison_filter_flags_value; -extern u64 hwpoison_filter_memcg; -extern u32 hwpoison_filter_enable; - -extern unsigned long __must_check vm_mmap_pgoff(struct file *, unsigned long, - unsigned long, unsigned long, - unsigned long, unsigned long); - -extern void set_pageblock_order(void); -unsigned long reclaim_clean_pages_from_list(struct zone *zone, - struct list_head *page_list); -/* The ALLOC_WMARK bits are used as an index to zone->watermark */ -#define ALLOC_WMARK_MIN WMARK_MIN -#define ALLOC_WMARK_LOW WMARK_LOW -#define ALLOC_WMARK_HIGH WMARK_HIGH -#define ALLOC_NO_WATERMARKS 0x04 /* don't check watermarks at all */ - -/* Mask to get the watermark bits */ -#define ALLOC_WMARK_MASK (ALLOC_NO_WATERMARKS-1) - -#define ALLOC_HARDER 0x10 /* try to alloc harder */ -#define ALLOC_HIGH 0x20 /* __GFP_HIGH set */ -#define ALLOC_CPUSET 0x40 /* check for correct cpuset */ -#define ALLOC_CMA 0x80 /* allow allocations from CMA areas */ - -enum ttu_flags; -struct tlbflush_unmap_batch; - -#ifdef CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH -void try_to_unmap_flush(void); -void try_to_unmap_flush_dirty(void); -#else -static inline void try_to_unmap_flush(void) -{ -} -static inline void try_to_unmap_flush_dirty(void) -{ -} - -#endif /* CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH */ - -extern const struct trace_print_flags pageflag_names[]; -extern const struct trace_print_flags vmaflag_names[]; -extern const struct trace_print_flags gfpflag_names[]; - -#endif /* __MM_INTERNAL_H */ diff --git a/src/linux/mm/interval_tree.c b/src/linux/mm/interval_tree.c deleted file mode 100644 index f2c2492..0000000 --- a/src/linux/mm/interval_tree.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * mm/interval_tree.c - interval tree for mapping->i_mmap - * - * Copyright (C) 2012, Michel Lespinasse - * - * This file is released under the GPL v2. - */ - -#include -#include -#include -#include - -static inline unsigned long vma_start_pgoff(struct vm_area_struct *v) -{ - return v->vm_pgoff; -} - -static inline unsigned long vma_last_pgoff(struct vm_area_struct *v) -{ - return v->vm_pgoff + ((v->vm_end - v->vm_start) >> PAGE_SHIFT) - 1; -} - -INTERVAL_TREE_DEFINE(struct vm_area_struct, shared.rb, - unsigned long, shared.rb_subtree_last, - vma_start_pgoff, vma_last_pgoff,, vma_interval_tree) - -/* Insert node immediately after prev in the interval tree */ -void vma_interval_tree_insert_after(struct vm_area_struct *node, - struct vm_area_struct *prev, - struct rb_root *root) -{ - struct rb_node **link; - struct vm_area_struct *parent; - unsigned long last = vma_last_pgoff(node); - - VM_BUG_ON_VMA(vma_start_pgoff(node) != vma_start_pgoff(prev), node); - - if (!prev->shared.rb.rb_right) { - parent = prev; - link = &prev->shared.rb.rb_right; - } else { - parent = rb_entry(prev->shared.rb.rb_right, - struct vm_area_struct, shared.rb); - if (parent->shared.rb_subtree_last < last) - parent->shared.rb_subtree_last = last; - while (parent->shared.rb.rb_left) { - parent = rb_entry(parent->shared.rb.rb_left, - struct vm_area_struct, shared.rb); - if (parent->shared.rb_subtree_last < last) - parent->shared.rb_subtree_last = last; - } - link = &parent->shared.rb.rb_left; - } - - node->shared.rb_subtree_last = last; - rb_link_node(&node->shared.rb, &parent->shared.rb, link); - rb_insert_augmented(&node->shared.rb, root, - &vma_interval_tree_augment); -} - -static inline unsigned long avc_start_pgoff(struct anon_vma_chain *avc) -{ - return vma_start_pgoff(avc->vma); -} - -static inline unsigned long avc_last_pgoff(struct anon_vma_chain *avc) -{ - return vma_last_pgoff(avc->vma); -} - -INTERVAL_TREE_DEFINE(struct anon_vma_chain, rb, unsigned long, rb_subtree_last, - avc_start_pgoff, avc_last_pgoff, - static inline, __anon_vma_interval_tree) - -void anon_vma_interval_tree_insert(struct anon_vma_chain *node, - struct rb_root *root) -{ -#ifdef CONFIG_DEBUG_VM_RB - node->cached_vma_start = avc_start_pgoff(node); - node->cached_vma_last = avc_last_pgoff(node); -#endif - __anon_vma_interval_tree_insert(node, root); -} - -void anon_vma_interval_tree_remove(struct anon_vma_chain *node, - struct rb_root *root) -{ - __anon_vma_interval_tree_remove(node, root); -} - -struct anon_vma_chain * -anon_vma_interval_tree_iter_first(struct rb_root *root, - unsigned long first, unsigned long last) -{ - return __anon_vma_interval_tree_iter_first(root, first, last); -} - -struct anon_vma_chain * -anon_vma_interval_tree_iter_next(struct anon_vma_chain *node, - unsigned long first, unsigned long last) -{ - return __anon_vma_interval_tree_iter_next(node, first, last); -} - -#ifdef CONFIG_DEBUG_VM_RB -void anon_vma_interval_tree_verify(struct anon_vma_chain *node) -{ - WARN_ON_ONCE(node->cached_vma_start != avc_start_pgoff(node)); - WARN_ON_ONCE(node->cached_vma_last != avc_last_pgoff(node)); -} -#endif diff --git a/src/linux/mm/list_lru.c b/src/linux/mm/list_lru.c deleted file mode 100644 index 234676e..0000000 --- a/src/linux/mm/list_lru.c +++ /dev/null @@ -1,585 +0,0 @@ -/* - * Copyright (c) 2013 Red Hat, Inc. and Parallels Inc. All rights reserved. - * Authors: David Chinner and Glauber Costa - * - * Generic LRU infrastructure - */ -#include -#include -#include -#include -#include -#include -#include - -#if defined(CONFIG_MEMCG) && !defined(CONFIG_SLOB) -static LIST_HEAD(list_lrus); -static DEFINE_MUTEX(list_lrus_mutex); - -static void list_lru_register(struct list_lru *lru) -{ - mutex_lock(&list_lrus_mutex); - list_add(&lru->list, &list_lrus); - mutex_unlock(&list_lrus_mutex); -} - -static void list_lru_unregister(struct list_lru *lru) -{ - mutex_lock(&list_lrus_mutex); - list_del(&lru->list); - mutex_unlock(&list_lrus_mutex); -} -#else -static void list_lru_register(struct list_lru *lru) -{ -} - -static void list_lru_unregister(struct list_lru *lru) -{ -} -#endif /* CONFIG_MEMCG && !CONFIG_SLOB */ - -#if defined(CONFIG_MEMCG) && !defined(CONFIG_SLOB) -static inline bool list_lru_memcg_aware(struct list_lru *lru) -{ - /* - * This needs node 0 to be always present, even - * in the systems supporting sparse numa ids. - */ - return !!lru->node[0].memcg_lrus; -} - -static inline struct list_lru_one * -list_lru_from_memcg_idx(struct list_lru_node *nlru, int idx) -{ - /* - * The lock protects the array of per cgroup lists from relocation - * (see memcg_update_list_lru_node). - */ - lockdep_assert_held(&nlru->lock); - if (nlru->memcg_lrus && idx >= 0) - return nlru->memcg_lrus->lru[idx]; - - return &nlru->lru; -} - -static __always_inline struct mem_cgroup *mem_cgroup_from_kmem(void *ptr) -{ - struct page *page; - - if (!memcg_kmem_enabled()) - return NULL; - page = virt_to_head_page(ptr); - return page->mem_cgroup; -} - -static inline struct list_lru_one * -list_lru_from_kmem(struct list_lru_node *nlru, void *ptr) -{ - struct mem_cgroup *memcg; - - if (!nlru->memcg_lrus) - return &nlru->lru; - - memcg = mem_cgroup_from_kmem(ptr); - if (!memcg) - return &nlru->lru; - - return list_lru_from_memcg_idx(nlru, memcg_cache_id(memcg)); -} -#else -static inline bool list_lru_memcg_aware(struct list_lru *lru) -{ - return false; -} - -static inline struct list_lru_one * -list_lru_from_memcg_idx(struct list_lru_node *nlru, int idx) -{ - return &nlru->lru; -} - -static inline struct list_lru_one * -list_lru_from_kmem(struct list_lru_node *nlru, void *ptr) -{ - return &nlru->lru; -} -#endif /* CONFIG_MEMCG && !CONFIG_SLOB */ - -bool list_lru_add(struct list_lru *lru, struct list_head *item) -{ - int nid = page_to_nid(virt_to_page(item)); - struct list_lru_node *nlru = &lru->node[nid]; - struct list_lru_one *l; - - spin_lock(&nlru->lock); - if (list_empty(item)) { - l = list_lru_from_kmem(nlru, item); - list_add_tail(item, &l->list); - l->nr_items++; - spin_unlock(&nlru->lock); - return true; - } - spin_unlock(&nlru->lock); - return false; -} -EXPORT_SYMBOL_GPL(list_lru_add); - -bool list_lru_del(struct list_lru *lru, struct list_head *item) -{ - int nid = page_to_nid(virt_to_page(item)); - struct list_lru_node *nlru = &lru->node[nid]; - struct list_lru_one *l; - - spin_lock(&nlru->lock); - if (!list_empty(item)) { - l = list_lru_from_kmem(nlru, item); - list_del_init(item); - l->nr_items--; - spin_unlock(&nlru->lock); - return true; - } - spin_unlock(&nlru->lock); - return false; -} -EXPORT_SYMBOL_GPL(list_lru_del); - -void list_lru_isolate(struct list_lru_one *list, struct list_head *item) -{ - list_del_init(item); - list->nr_items--; -} -EXPORT_SYMBOL_GPL(list_lru_isolate); - -void list_lru_isolate_move(struct list_lru_one *list, struct list_head *item, - struct list_head *head) -{ - list_move(item, head); - list->nr_items--; -} -EXPORT_SYMBOL_GPL(list_lru_isolate_move); - -static unsigned long __list_lru_count_one(struct list_lru *lru, - int nid, int memcg_idx) -{ - struct list_lru_node *nlru = &lru->node[nid]; - struct list_lru_one *l; - unsigned long count; - - spin_lock(&nlru->lock); - l = list_lru_from_memcg_idx(nlru, memcg_idx); - count = l->nr_items; - spin_unlock(&nlru->lock); - - return count; -} - -unsigned long list_lru_count_one(struct list_lru *lru, - int nid, struct mem_cgroup *memcg) -{ - return __list_lru_count_one(lru, nid, memcg_cache_id(memcg)); -} -EXPORT_SYMBOL_GPL(list_lru_count_one); - -unsigned long list_lru_count_node(struct list_lru *lru, int nid) -{ - long count = 0; - int memcg_idx; - - count += __list_lru_count_one(lru, nid, -1); - if (list_lru_memcg_aware(lru)) { - for_each_memcg_cache_index(memcg_idx) - count += __list_lru_count_one(lru, nid, memcg_idx); - } - return count; -} -EXPORT_SYMBOL_GPL(list_lru_count_node); - -static unsigned long -__list_lru_walk_one(struct list_lru *lru, int nid, int memcg_idx, - list_lru_walk_cb isolate, void *cb_arg, - unsigned long *nr_to_walk) -{ - - struct list_lru_node *nlru = &lru->node[nid]; - struct list_lru_one *l; - struct list_head *item, *n; - unsigned long isolated = 0; - - spin_lock(&nlru->lock); - l = list_lru_from_memcg_idx(nlru, memcg_idx); -restart: - list_for_each_safe(item, n, &l->list) { - enum lru_status ret; - - /* - * decrement nr_to_walk first so that we don't livelock if we - * get stuck on large numbesr of LRU_RETRY items - */ - if (!*nr_to_walk) - break; - --*nr_to_walk; - - ret = isolate(item, l, &nlru->lock, cb_arg); - switch (ret) { - case LRU_REMOVED_RETRY: - assert_spin_locked(&nlru->lock); - case LRU_REMOVED: - isolated++; - /* - * If the lru lock has been dropped, our list - * traversal is now invalid and so we have to - * restart from scratch. - */ - if (ret == LRU_REMOVED_RETRY) - goto restart; - break; - case LRU_ROTATE: - list_move_tail(item, &l->list); - break; - case LRU_SKIP: - break; - case LRU_RETRY: - /* - * The lru lock has been dropped, our list traversal is - * now invalid and so we have to restart from scratch. - */ - assert_spin_locked(&nlru->lock); - goto restart; - default: - BUG(); - } - } - - spin_unlock(&nlru->lock); - return isolated; -} - -unsigned long -list_lru_walk_one(struct list_lru *lru, int nid, struct mem_cgroup *memcg, - list_lru_walk_cb isolate, void *cb_arg, - unsigned long *nr_to_walk) -{ - return __list_lru_walk_one(lru, nid, memcg_cache_id(memcg), - isolate, cb_arg, nr_to_walk); -} -EXPORT_SYMBOL_GPL(list_lru_walk_one); - -unsigned long list_lru_walk_node(struct list_lru *lru, int nid, - list_lru_walk_cb isolate, void *cb_arg, - unsigned long *nr_to_walk) -{ - long isolated = 0; - int memcg_idx; - - isolated += __list_lru_walk_one(lru, nid, -1, isolate, cb_arg, - nr_to_walk); - if (*nr_to_walk > 0 && list_lru_memcg_aware(lru)) { - for_each_memcg_cache_index(memcg_idx) { - isolated += __list_lru_walk_one(lru, nid, memcg_idx, - isolate, cb_arg, nr_to_walk); - if (*nr_to_walk <= 0) - break; - } - } - return isolated; -} -EXPORT_SYMBOL_GPL(list_lru_walk_node); - -static void init_one_lru(struct list_lru_one *l) -{ - INIT_LIST_HEAD(&l->list); - l->nr_items = 0; -} - -#if defined(CONFIG_MEMCG) && !defined(CONFIG_SLOB) -static void __memcg_destroy_list_lru_node(struct list_lru_memcg *memcg_lrus, - int begin, int end) -{ - int i; - - for (i = begin; i < end; i++) - kfree(memcg_lrus->lru[i]); -} - -static int __memcg_init_list_lru_node(struct list_lru_memcg *memcg_lrus, - int begin, int end) -{ - int i; - - for (i = begin; i < end; i++) { - struct list_lru_one *l; - - l = kmalloc(sizeof(struct list_lru_one), GFP_KERNEL); - if (!l) - goto fail; - - init_one_lru(l); - memcg_lrus->lru[i] = l; - } - return 0; -fail: - __memcg_destroy_list_lru_node(memcg_lrus, begin, i - 1); - return -ENOMEM; -} - -static int memcg_init_list_lru_node(struct list_lru_node *nlru) -{ - int size = memcg_nr_cache_ids; - - nlru->memcg_lrus = kmalloc(size * sizeof(void *), GFP_KERNEL); - if (!nlru->memcg_lrus) - return -ENOMEM; - - if (__memcg_init_list_lru_node(nlru->memcg_lrus, 0, size)) { - kfree(nlru->memcg_lrus); - return -ENOMEM; - } - - return 0; -} - -static void memcg_destroy_list_lru_node(struct list_lru_node *nlru) -{ - __memcg_destroy_list_lru_node(nlru->memcg_lrus, 0, memcg_nr_cache_ids); - kfree(nlru->memcg_lrus); -} - -static int memcg_update_list_lru_node(struct list_lru_node *nlru, - int old_size, int new_size) -{ - struct list_lru_memcg *old, *new; - - BUG_ON(old_size > new_size); - - old = nlru->memcg_lrus; - new = kmalloc(new_size * sizeof(void *), GFP_KERNEL); - if (!new) - return -ENOMEM; - - if (__memcg_init_list_lru_node(new, old_size, new_size)) { - kfree(new); - return -ENOMEM; - } - - memcpy(new, old, old_size * sizeof(void *)); - - /* - * The lock guarantees that we won't race with a reader - * (see list_lru_from_memcg_idx). - * - * Since list_lru_{add,del} may be called under an IRQ-safe lock, - * we have to use IRQ-safe primitives here to avoid deadlock. - */ - spin_lock_irq(&nlru->lock); - nlru->memcg_lrus = new; - spin_unlock_irq(&nlru->lock); - - kfree(old); - return 0; -} - -static void memcg_cancel_update_list_lru_node(struct list_lru_node *nlru, - int old_size, int new_size) -{ - /* do not bother shrinking the array back to the old size, because we - * cannot handle allocation failures here */ - __memcg_destroy_list_lru_node(nlru->memcg_lrus, old_size, new_size); -} - -static int memcg_init_list_lru(struct list_lru *lru, bool memcg_aware) -{ - int i; - - if (!memcg_aware) - return 0; - - for_each_node(i) { - if (memcg_init_list_lru_node(&lru->node[i])) - goto fail; - } - return 0; -fail: - for (i = i - 1; i >= 0; i--) { - if (!lru->node[i].memcg_lrus) - continue; - memcg_destroy_list_lru_node(&lru->node[i]); - } - return -ENOMEM; -} - -static void memcg_destroy_list_lru(struct list_lru *lru) -{ - int i; - - if (!list_lru_memcg_aware(lru)) - return; - - for_each_node(i) - memcg_destroy_list_lru_node(&lru->node[i]); -} - -static int memcg_update_list_lru(struct list_lru *lru, - int old_size, int new_size) -{ - int i; - - if (!list_lru_memcg_aware(lru)) - return 0; - - for_each_node(i) { - if (memcg_update_list_lru_node(&lru->node[i], - old_size, new_size)) - goto fail; - } - return 0; -fail: - for (i = i - 1; i >= 0; i--) { - if (!lru->node[i].memcg_lrus) - continue; - - memcg_cancel_update_list_lru_node(&lru->node[i], - old_size, new_size); - } - return -ENOMEM; -} - -static void memcg_cancel_update_list_lru(struct list_lru *lru, - int old_size, int new_size) -{ - int i; - - if (!list_lru_memcg_aware(lru)) - return; - - for_each_node(i) - memcg_cancel_update_list_lru_node(&lru->node[i], - old_size, new_size); -} - -int memcg_update_all_list_lrus(int new_size) -{ - int ret = 0; - struct list_lru *lru; - int old_size = memcg_nr_cache_ids; - - mutex_lock(&list_lrus_mutex); - list_for_each_entry(lru, &list_lrus, list) { - ret = memcg_update_list_lru(lru, old_size, new_size); - if (ret) - goto fail; - } -out: - mutex_unlock(&list_lrus_mutex); - return ret; -fail: - list_for_each_entry_continue_reverse(lru, &list_lrus, list) - memcg_cancel_update_list_lru(lru, old_size, new_size); - goto out; -} - -static void memcg_drain_list_lru_node(struct list_lru_node *nlru, - int src_idx, int dst_idx) -{ - struct list_lru_one *src, *dst; - - /* - * Since list_lru_{add,del} may be called under an IRQ-safe lock, - * we have to use IRQ-safe primitives here to avoid deadlock. - */ - spin_lock_irq(&nlru->lock); - - src = list_lru_from_memcg_idx(nlru, src_idx); - dst = list_lru_from_memcg_idx(nlru, dst_idx); - - list_splice_init(&src->list, &dst->list); - dst->nr_items += src->nr_items; - src->nr_items = 0; - - spin_unlock_irq(&nlru->lock); -} - -static void memcg_drain_list_lru(struct list_lru *lru, - int src_idx, int dst_idx) -{ - int i; - - if (!list_lru_memcg_aware(lru)) - return; - - for_each_node(i) - memcg_drain_list_lru_node(&lru->node[i], src_idx, dst_idx); -} - -void memcg_drain_all_list_lrus(int src_idx, int dst_idx) -{ - struct list_lru *lru; - - mutex_lock(&list_lrus_mutex); - list_for_each_entry(lru, &list_lrus, list) - memcg_drain_list_lru(lru, src_idx, dst_idx); - mutex_unlock(&list_lrus_mutex); -} -#else -static int memcg_init_list_lru(struct list_lru *lru, bool memcg_aware) -{ - return 0; -} - -static void memcg_destroy_list_lru(struct list_lru *lru) -{ -} -#endif /* CONFIG_MEMCG && !CONFIG_SLOB */ - -int __list_lru_init(struct list_lru *lru, bool memcg_aware, - struct lock_class_key *key) -{ - int i; - size_t size = sizeof(*lru->node) * nr_node_ids; - int err = -ENOMEM; - - memcg_get_cache_ids(); - - lru->node = kzalloc(size, GFP_KERNEL); - if (!lru->node) - goto out; - - for_each_node(i) { - spin_lock_init(&lru->node[i].lock); - if (key) - lockdep_set_class(&lru->node[i].lock, key); - init_one_lru(&lru->node[i].lru); - } - - err = memcg_init_list_lru(lru, memcg_aware); - if (err) { - kfree(lru->node); - /* Do this so a list_lru_destroy() doesn't crash: */ - lru->node = NULL; - goto out; - } - - list_lru_register(lru); -out: - memcg_put_cache_ids(); - return err; -} -EXPORT_SYMBOL_GPL(__list_lru_init); - -void list_lru_destroy(struct list_lru *lru) -{ - /* Already destroyed or not yet initialized? */ - if (!lru->node) - return; - - memcg_get_cache_ids(); - - list_lru_unregister(lru); - - memcg_destroy_list_lru(lru); - kfree(lru->node); - lru->node = NULL; - - memcg_put_cache_ids(); -} -EXPORT_SYMBOL_GPL(list_lru_destroy); diff --git a/src/linux/mm/maccess.c b/src/linux/mm/maccess.c deleted file mode 100644 index 78f9274..0000000 --- a/src/linux/mm/maccess.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Access kernel memory without faulting. - */ -#include -#include -#include - -/** - * probe_kernel_read(): safely attempt to read from a location - * @dst: pointer to the buffer that shall take the data - * @src: address to read from - * @size: size of the data chunk - * - * Safely read from address @src to the buffer at @dst. If a kernel fault - * happens, handle that and return -EFAULT. - * - * We ensure that the copy_from_user is executed in atomic context so that - * do_page_fault() doesn't attempt to take mmap_sem. This makes - * probe_kernel_read() suitable for use within regions where the caller - * already holds mmap_sem, or other locks which nest inside mmap_sem. - */ - -long __weak probe_kernel_read(void *dst, const void *src, size_t size) - __attribute__((alias("__probe_kernel_read"))); - -long __probe_kernel_read(void *dst, const void *src, size_t size) -{ - long ret; - mm_segment_t old_fs = get_fs(); - - set_fs(KERNEL_DS); - pagefault_disable(); - ret = __copy_from_user_inatomic(dst, - (__force const void __user *)src, size); - pagefault_enable(); - set_fs(old_fs); - - return ret ? -EFAULT : 0; -} -EXPORT_SYMBOL_GPL(probe_kernel_read); - -/** - * probe_kernel_write(): safely attempt to write to a location - * @dst: address to write to - * @src: pointer to the data that shall be written - * @size: size of the data chunk - * - * Safely write to address @dst from the buffer at @src. If a kernel fault - * happens, handle that and return -EFAULT. - */ -long __weak probe_kernel_write(void *dst, const void *src, size_t size) - __attribute__((alias("__probe_kernel_write"))); - -long __probe_kernel_write(void *dst, const void *src, size_t size) -{ - long ret; - mm_segment_t old_fs = get_fs(); - - set_fs(KERNEL_DS); - pagefault_disable(); - ret = __copy_to_user_inatomic((__force void __user *)dst, src, size); - pagefault_enable(); - set_fs(old_fs); - - return ret ? -EFAULT : 0; -} -EXPORT_SYMBOL_GPL(probe_kernel_write); - -/** - * strncpy_from_unsafe: - Copy a NUL terminated string from unsafe address. - * @dst: Destination address, in kernel space. This buffer must be at - * least @count bytes long. - * @src: Unsafe address. - * @count: Maximum number of bytes to copy, including the trailing NUL. - * - * Copies a NUL-terminated string from unsafe address to kernel buffer. - * - * On success, returns the length of the string INCLUDING the trailing NUL. - * - * If access fails, returns -EFAULT (some data may have been copied - * and the trailing NUL added). - * - * If @count is smaller than the length of the string, copies @count-1 bytes, - * sets the last byte of @dst buffer to NUL and returns @count. - */ -long strncpy_from_unsafe(char *dst, const void *unsafe_addr, long count) -{ - mm_segment_t old_fs = get_fs(); - const void *src = unsafe_addr; - long ret; - - if (unlikely(count <= 0)) - return 0; - - set_fs(KERNEL_DS); - pagefault_disable(); - - do { - ret = __get_user(*dst++, (const char __user __force *)src++); - } while (dst[-1] && ret == 0 && src - unsafe_addr < count); - - dst[-1] = '\0'; - pagefault_enable(); - set_fs(old_fs); - - return ret ? -EFAULT : src - unsafe_addr; -} diff --git a/src/linux/mm/mempool.c b/src/linux/mm/mempool.c deleted file mode 100644 index 47a659d..0000000 --- a/src/linux/mm/mempool.c +++ /dev/null @@ -1,493 +0,0 @@ -/* - * linux/mm/mempool.c - * - * memory buffer pool support. Such pools are mostly used - * for guaranteed, deadlock-free memory allocations during - * extreme VM load. - * - * started by Ingo Molnar, Copyright (C) 2001 - * debugging by David Rientjes, Copyright (C) 2015 - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "slab.h" - -#if defined(CONFIG_DEBUG_SLAB) || defined(CONFIG_SLUB_DEBUG_ON) -static void poison_error(mempool_t *pool, void *element, size_t size, - size_t byte) -{ - const int nr = pool->curr_nr; - const int start = max_t(int, byte - (BITS_PER_LONG / 8), 0); - const int end = min_t(int, byte + (BITS_PER_LONG / 8), size); - int i; - - pr_err("BUG: mempool element poison mismatch\n"); - pr_err("Mempool %p size %zu\n", pool, size); - pr_err(" nr=%d @ %p: %s0x", nr, element, start > 0 ? "... " : ""); - for (i = start; i < end; i++) - pr_cont("%x ", *(u8 *)(element + i)); - pr_cont("%s\n", end < size ? "..." : ""); - dump_stack(); -} - -static void __check_element(mempool_t *pool, void *element, size_t size) -{ - u8 *obj = element; - size_t i; - - for (i = 0; i < size; i++) { - u8 exp = (i < size - 1) ? POISON_FREE : POISON_END; - - if (obj[i] != exp) { - poison_error(pool, element, size, i); - return; - } - } - memset(obj, POISON_INUSE, size); -} - -static void check_element(mempool_t *pool, void *element) -{ - /* Mempools backed by slab allocator */ - if (pool->free == mempool_free_slab || pool->free == mempool_kfree) - __check_element(pool, element, ksize(element)); - - /* Mempools backed by page allocator */ - if (pool->free == mempool_free_pages) { - int order = (int)(long)pool->pool_data; - void *addr = kmap_atomic((struct page *)element); - - __check_element(pool, addr, 1UL << (PAGE_SHIFT + order)); - kunmap_atomic(addr); - } -} - -static void __poison_element(void *element, size_t size) -{ - u8 *obj = element; - - memset(obj, POISON_FREE, size - 1); - obj[size - 1] = POISON_END; -} - -static void poison_element(mempool_t *pool, void *element) -{ - /* Mempools backed by slab allocator */ - if (pool->alloc == mempool_alloc_slab || pool->alloc == mempool_kmalloc) - __poison_element(element, ksize(element)); - - /* Mempools backed by page allocator */ - if (pool->alloc == mempool_alloc_pages) { - int order = (int)(long)pool->pool_data; - void *addr = kmap_atomic((struct page *)element); - - __poison_element(addr, 1UL << (PAGE_SHIFT + order)); - kunmap_atomic(addr); - } -} -#else /* CONFIG_DEBUG_SLAB || CONFIG_SLUB_DEBUG_ON */ -static inline void check_element(mempool_t *pool, void *element) -{ -} -static inline void poison_element(mempool_t *pool, void *element) -{ -} -#endif /* CONFIG_DEBUG_SLAB || CONFIG_SLUB_DEBUG_ON */ - -static void kasan_poison_element(mempool_t *pool, void *element) -{ - if (pool->alloc == mempool_alloc_slab || pool->alloc == mempool_kmalloc) - kasan_poison_kfree(element); - if (pool->alloc == mempool_alloc_pages) - kasan_free_pages(element, (unsigned long)pool->pool_data); -} - -static void kasan_unpoison_element(mempool_t *pool, void *element, gfp_t flags) -{ - if (pool->alloc == mempool_alloc_slab || pool->alloc == mempool_kmalloc) - kasan_unpoison_slab(element); - if (pool->alloc == mempool_alloc_pages) - kasan_alloc_pages(element, (unsigned long)pool->pool_data); -} - -static void add_element(mempool_t *pool, void *element) -{ - BUG_ON(pool->curr_nr >= pool->min_nr); - poison_element(pool, element); - kasan_poison_element(pool, element); - pool->elements[pool->curr_nr++] = element; -} - -static void *remove_element(mempool_t *pool, gfp_t flags) -{ - void *element = pool->elements[--pool->curr_nr]; - - BUG_ON(pool->curr_nr < 0); - kasan_unpoison_element(pool, element, flags); - check_element(pool, element); - return element; -} - -/** - * mempool_destroy - deallocate a memory pool - * @pool: pointer to the memory pool which was allocated via - * mempool_create(). - * - * Free all reserved elements in @pool and @pool itself. This function - * only sleeps if the free_fn() function sleeps. - */ -void mempool_destroy(mempool_t *pool) -{ - if (unlikely(!pool)) - return; - - while (pool->curr_nr) { - void *element = remove_element(pool, GFP_KERNEL); - pool->free(element, pool->pool_data); - } - kfree(pool->elements); - kfree(pool); -} -EXPORT_SYMBOL(mempool_destroy); - -/** - * mempool_create - create a memory pool - * @min_nr: the minimum number of elements guaranteed to be - * allocated for this pool. - * @alloc_fn: user-defined element-allocation function. - * @free_fn: user-defined element-freeing function. - * @pool_data: optional private data available to the user-defined functions. - * - * this function creates and allocates a guaranteed size, preallocated - * memory pool. The pool can be used from the mempool_alloc() and mempool_free() - * functions. This function might sleep. Both the alloc_fn() and the free_fn() - * functions might sleep - as long as the mempool_alloc() function is not called - * from IRQ contexts. - */ -mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn, - mempool_free_t *free_fn, void *pool_data) -{ - return mempool_create_node(min_nr,alloc_fn,free_fn, pool_data, - GFP_KERNEL, NUMA_NO_NODE); -} -EXPORT_SYMBOL(mempool_create); - -mempool_t *mempool_create_node(int min_nr, mempool_alloc_t *alloc_fn, - mempool_free_t *free_fn, void *pool_data, - gfp_t gfp_mask, int node_id) -{ - mempool_t *pool; - pool = kzalloc_node(sizeof(*pool), gfp_mask, node_id); - if (!pool) - return NULL; - pool->elements = kmalloc_node(min_nr * sizeof(void *), - gfp_mask, node_id); - if (!pool->elements) { - kfree(pool); - return NULL; - } - spin_lock_init(&pool->lock); - pool->min_nr = min_nr; - pool->pool_data = pool_data; - init_waitqueue_head(&pool->wait); - pool->alloc = alloc_fn; - pool->free = free_fn; - - /* - * First pre-allocate the guaranteed number of buffers. - */ - while (pool->curr_nr < pool->min_nr) { - void *element; - - element = pool->alloc(gfp_mask, pool->pool_data); - if (unlikely(!element)) { - mempool_destroy(pool); - return NULL; - } - add_element(pool, element); - } - return pool; -} -EXPORT_SYMBOL(mempool_create_node); - -/** - * mempool_resize - resize an existing memory pool - * @pool: pointer to the memory pool which was allocated via - * mempool_create(). - * @new_min_nr: the new minimum number of elements guaranteed to be - * allocated for this pool. - * - * This function shrinks/grows the pool. In the case of growing, - * it cannot be guaranteed that the pool will be grown to the new - * size immediately, but new mempool_free() calls will refill it. - * This function may sleep. - * - * Note, the caller must guarantee that no mempool_destroy is called - * while this function is running. mempool_alloc() & mempool_free() - * might be called (eg. from IRQ contexts) while this function executes. - */ -int mempool_resize(mempool_t *pool, int new_min_nr) -{ - void *element; - void **new_elements; - unsigned long flags; - - BUG_ON(new_min_nr <= 0); - might_sleep(); - - spin_lock_irqsave(&pool->lock, flags); - if (new_min_nr <= pool->min_nr) { - while (new_min_nr < pool->curr_nr) { - element = remove_element(pool, GFP_KERNEL); - spin_unlock_irqrestore(&pool->lock, flags); - pool->free(element, pool->pool_data); - spin_lock_irqsave(&pool->lock, flags); - } - pool->min_nr = new_min_nr; - goto out_unlock; - } - spin_unlock_irqrestore(&pool->lock, flags); - - /* Grow the pool */ - new_elements = kmalloc_array(new_min_nr, sizeof(*new_elements), - GFP_KERNEL); - if (!new_elements) - return -ENOMEM; - - spin_lock_irqsave(&pool->lock, flags); - if (unlikely(new_min_nr <= pool->min_nr)) { - /* Raced, other resize will do our work */ - spin_unlock_irqrestore(&pool->lock, flags); - kfree(new_elements); - goto out; - } - memcpy(new_elements, pool->elements, - pool->curr_nr * sizeof(*new_elements)); - kfree(pool->elements); - pool->elements = new_elements; - pool->min_nr = new_min_nr; - - while (pool->curr_nr < pool->min_nr) { - spin_unlock_irqrestore(&pool->lock, flags); - element = pool->alloc(GFP_KERNEL, pool->pool_data); - if (!element) - goto out; - spin_lock_irqsave(&pool->lock, flags); - if (pool->curr_nr < pool->min_nr) { - add_element(pool, element); - } else { - spin_unlock_irqrestore(&pool->lock, flags); - pool->free(element, pool->pool_data); /* Raced */ - goto out; - } - } -out_unlock: - spin_unlock_irqrestore(&pool->lock, flags); -out: - return 0; -} -EXPORT_SYMBOL(mempool_resize); - -/** - * mempool_alloc - allocate an element from a specific memory pool - * @pool: pointer to the memory pool which was allocated via - * mempool_create(). - * @gfp_mask: the usual allocation bitmask. - * - * this function only sleeps if the alloc_fn() function sleeps or - * returns NULL. Note that due to preallocation, this function - * *never* fails when called from process contexts. (it might - * fail if called from an IRQ context.) - * Note: using __GFP_ZERO is not supported. - */ -void *mempool_alloc(mempool_t *pool, gfp_t gfp_mask) -{ - void *element; - unsigned long flags; - wait_queue_t wait; - gfp_t gfp_temp; - - VM_WARN_ON_ONCE(gfp_mask & __GFP_ZERO); - might_sleep_if(gfp_mask & __GFP_DIRECT_RECLAIM); - - gfp_mask |= __GFP_NOMEMALLOC; /* don't allocate emergency reserves */ - gfp_mask |= __GFP_NORETRY; /* don't loop in __alloc_pages */ - gfp_mask |= __GFP_NOWARN; /* failures are OK */ - - gfp_temp = gfp_mask & ~(__GFP_DIRECT_RECLAIM|__GFP_IO); - -repeat_alloc: - - element = pool->alloc(gfp_temp, pool->pool_data); - if (likely(element != NULL)) - return element; - - spin_lock_irqsave(&pool->lock, flags); - if (likely(pool->curr_nr)) { - element = remove_element(pool, gfp_temp); - spin_unlock_irqrestore(&pool->lock, flags); - /* paired with rmb in mempool_free(), read comment there */ - smp_wmb(); - /* - * Update the allocation stack trace as this is more useful - * for debugging. - */ - kmemleak_update_trace(element); - return element; - } - - /* - * We use gfp mask w/o direct reclaim or IO for the first round. If - * alloc failed with that and @pool was empty, retry immediately. - */ - if (gfp_temp != gfp_mask) { - spin_unlock_irqrestore(&pool->lock, flags); - gfp_temp = gfp_mask; - goto repeat_alloc; - } - - /* We must not sleep if !__GFP_DIRECT_RECLAIM */ - if (!(gfp_mask & __GFP_DIRECT_RECLAIM)) { - spin_unlock_irqrestore(&pool->lock, flags); - return NULL; - } - - /* Let's wait for someone else to return an element to @pool */ - init_wait(&wait); - prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE); - - spin_unlock_irqrestore(&pool->lock, flags); - - /* - * FIXME: this should be io_schedule(). The timeout is there as a - * workaround for some DM problems in 2.6.18. - */ - io_schedule_timeout(5*HZ); - - finish_wait(&pool->wait, &wait); - goto repeat_alloc; -} -EXPORT_SYMBOL(mempool_alloc); - -/** - * mempool_free - return an element to the pool. - * @element: pool element pointer. - * @pool: pointer to the memory pool which was allocated via - * mempool_create(). - * - * this function only sleeps if the free_fn() function sleeps. - */ -void mempool_free(void *element, mempool_t *pool) -{ - unsigned long flags; - - if (unlikely(element == NULL)) - return; - - /* - * Paired with the wmb in mempool_alloc(). The preceding read is - * for @element and the following @pool->curr_nr. This ensures - * that the visible value of @pool->curr_nr is from after the - * allocation of @element. This is necessary for fringe cases - * where @element was passed to this task without going through - * barriers. - * - * For example, assume @p is %NULL at the beginning and one task - * performs "p = mempool_alloc(...);" while another task is doing - * "while (!p) cpu_relax(); mempool_free(p, ...);". This function - * may end up using curr_nr value which is from before allocation - * of @p without the following rmb. - */ - smp_rmb(); - - /* - * For correctness, we need a test which is guaranteed to trigger - * if curr_nr + #allocated == min_nr. Testing curr_nr < min_nr - * without locking achieves that and refilling as soon as possible - * is desirable. - * - * Because curr_nr visible here is always a value after the - * allocation of @element, any task which decremented curr_nr below - * min_nr is guaranteed to see curr_nr < min_nr unless curr_nr gets - * incremented to min_nr afterwards. If curr_nr gets incremented - * to min_nr after the allocation of @element, the elements - * allocated after that are subject to the same guarantee. - * - * Waiters happen iff curr_nr is 0 and the above guarantee also - * ensures that there will be frees which return elements to the - * pool waking up the waiters. - */ - if (unlikely(pool->curr_nr < pool->min_nr)) { - spin_lock_irqsave(&pool->lock, flags); - if (likely(pool->curr_nr < pool->min_nr)) { - add_element(pool, element); - spin_unlock_irqrestore(&pool->lock, flags); - wake_up(&pool->wait); - return; - } - spin_unlock_irqrestore(&pool->lock, flags); - } - pool->free(element, pool->pool_data); -} -EXPORT_SYMBOL(mempool_free); - -/* - * A commonly used alloc and free fn. - */ -void *mempool_alloc_slab(gfp_t gfp_mask, void *pool_data) -{ - struct kmem_cache *mem = pool_data; - VM_BUG_ON(mem->ctor); - return kmem_cache_alloc(mem, gfp_mask); -} -EXPORT_SYMBOL(mempool_alloc_slab); - -void mempool_free_slab(void *element, void *pool_data) -{ - struct kmem_cache *mem = pool_data; - kmem_cache_free(mem, element); -} -EXPORT_SYMBOL(mempool_free_slab); - -/* - * A commonly used alloc and free fn that kmalloc/kfrees the amount of memory - * specified by pool_data - */ -void *mempool_kmalloc(gfp_t gfp_mask, void *pool_data) -{ - size_t size = (size_t)pool_data; - return kmalloc(size, gfp_mask); -} -EXPORT_SYMBOL(mempool_kmalloc); - -void mempool_kfree(void *element, void *pool_data) -{ - kfree(element); -} -EXPORT_SYMBOL(mempool_kfree); - -/* - * A simple mempool-backed page allocator that allocates pages - * of the order specified by pool_data. - */ -void *mempool_alloc_pages(gfp_t gfp_mask, void *pool_data) -{ - int order = (int)(long)pool_data; - return alloc_pages(gfp_mask, order); -} -EXPORT_SYMBOL(mempool_alloc_pages); - -void mempool_free_pages(void *element, void *pool_data) -{ - int order = (int)(long)pool_data; - __free_pages(element, order); -} -EXPORT_SYMBOL(mempool_free_pages); diff --git a/src/linux/mm/mm_init.c b/src/linux/mm/mm_init.c deleted file mode 100644 index 5b72266..0000000 --- a/src/linux/mm/mm_init.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * mm_init.c - Memory initialisation verification and debugging - * - * Copyright 2008 IBM Corporation, 2008 - * Author Mel Gorman - * - */ -#include -#include -#include -#include -#include -#include -#include -#include "internal.h" - -#ifdef CONFIG_DEBUG_MEMORY_INIT -int __meminitdata mminit_loglevel; - -#ifndef SECTIONS_SHIFT -#define SECTIONS_SHIFT 0 -#endif - -/* The zonelists are simply reported, validation is manual. */ -void __init mminit_verify_zonelist(void) -{ - int nid; - - if (mminit_loglevel < MMINIT_VERIFY) - return; - - for_each_online_node(nid) { - pg_data_t *pgdat = NODE_DATA(nid); - struct zone *zone; - struct zoneref *z; - struct zonelist *zonelist; - int i, listid, zoneid; - - BUG_ON(MAX_ZONELISTS > 2); - for (i = 0; i < MAX_ZONELISTS * MAX_NR_ZONES; i++) { - - /* Identify the zone and nodelist */ - zoneid = i % MAX_NR_ZONES; - listid = i / MAX_NR_ZONES; - zonelist = &pgdat->node_zonelists[listid]; - zone = &pgdat->node_zones[zoneid]; - if (!populated_zone(zone)) - continue; - - /* Print information about the zonelist */ - printk(KERN_DEBUG "mminit::zonelist %s %d:%s = ", - listid > 0 ? "thisnode" : "general", nid, - zone->name); - - /* Iterate the zonelist */ - for_each_zone_zonelist(zone, z, zonelist, zoneid) { -#ifdef CONFIG_NUMA - pr_cont("%d:%s ", zone->node, zone->name); -#else - pr_cont("0:%s ", zone->name); -#endif /* CONFIG_NUMA */ - } - pr_cont("\n"); - } - } -} - -void __init mminit_verify_pageflags_layout(void) -{ - int shift, width; - unsigned long or_mask, add_mask; - - shift = 8 * sizeof(unsigned long); - width = shift - SECTIONS_WIDTH - NODES_WIDTH - ZONES_WIDTH - LAST_CPUPID_SHIFT; - mminit_dprintk(MMINIT_TRACE, "pageflags_layout_widths", - "Section %d Node %d Zone %d Lastcpupid %d Flags %d\n", - SECTIONS_WIDTH, - NODES_WIDTH, - ZONES_WIDTH, - LAST_CPUPID_WIDTH, - NR_PAGEFLAGS); - mminit_dprintk(MMINIT_TRACE, "pageflags_layout_shifts", - "Section %d Node %d Zone %d Lastcpupid %d\n", - SECTIONS_SHIFT, - NODES_SHIFT, - ZONES_SHIFT, - LAST_CPUPID_SHIFT); - mminit_dprintk(MMINIT_TRACE, "pageflags_layout_pgshifts", - "Section %lu Node %lu Zone %lu Lastcpupid %lu\n", - (unsigned long)SECTIONS_PGSHIFT, - (unsigned long)NODES_PGSHIFT, - (unsigned long)ZONES_PGSHIFT, - (unsigned long)LAST_CPUPID_PGSHIFT); - mminit_dprintk(MMINIT_TRACE, "pageflags_layout_nodezoneid", - "Node/Zone ID: %lu -> %lu\n", - (unsigned long)(ZONEID_PGOFF + ZONEID_SHIFT), - (unsigned long)ZONEID_PGOFF); - mminit_dprintk(MMINIT_TRACE, "pageflags_layout_usage", - "location: %d -> %d layout %d -> %d unused %d -> %d page-flags\n", - shift, width, width, NR_PAGEFLAGS, NR_PAGEFLAGS, 0); -#ifdef NODE_NOT_IN_PAGE_FLAGS - mminit_dprintk(MMINIT_TRACE, "pageflags_layout_nodeflags", - "Node not in page flags"); -#endif -#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS - mminit_dprintk(MMINIT_TRACE, "pageflags_layout_nodeflags", - "Last cpupid not in page flags"); -#endif - - if (SECTIONS_WIDTH) { - shift -= SECTIONS_WIDTH; - BUG_ON(shift != SECTIONS_PGSHIFT); - } - if (NODES_WIDTH) { - shift -= NODES_WIDTH; - BUG_ON(shift != NODES_PGSHIFT); - } - if (ZONES_WIDTH) { - shift -= ZONES_WIDTH; - BUG_ON(shift != ZONES_PGSHIFT); - } - - /* Check for bitmask overlaps */ - or_mask = (ZONES_MASK << ZONES_PGSHIFT) | - (NODES_MASK << NODES_PGSHIFT) | - (SECTIONS_MASK << SECTIONS_PGSHIFT); - add_mask = (ZONES_MASK << ZONES_PGSHIFT) + - (NODES_MASK << NODES_PGSHIFT) + - (SECTIONS_MASK << SECTIONS_PGSHIFT); - BUG_ON(or_mask != add_mask); -} - -static __init int set_mminit_loglevel(char *str) -{ - get_option(&str, &mminit_loglevel); - return 0; -} -early_param("mminit_loglevel", set_mminit_loglevel); -#endif /* CONFIG_DEBUG_MEMORY_INIT */ - -struct kobject *mm_kobj; -EXPORT_SYMBOL_GPL(mm_kobj); - -#ifdef CONFIG_SMP -s32 vm_committed_as_batch = 32; - -static void __meminit mm_compute_batch(void) -{ - u64 memsized_batch; - s32 nr = num_present_cpus(); - s32 batch = max_t(s32, nr*2, 32); - - /* batch size set to 0.4% of (total memory/#cpus), or max int32 */ - memsized_batch = min_t(u64, (totalram_pages/nr)/256, 0x7fffffff); - - vm_committed_as_batch = max_t(s32, memsized_batch, batch); -} - -static int __meminit mm_compute_batch_notifier(struct notifier_block *self, - unsigned long action, void *arg) -{ - switch (action) { - case MEM_ONLINE: - case MEM_OFFLINE: - mm_compute_batch(); - default: - break; - } - return NOTIFY_OK; -} - -static struct notifier_block compute_batch_nb __meminitdata = { - .notifier_call = mm_compute_batch_notifier, - .priority = IPC_CALLBACK_PRI, /* use lowest priority */ -}; - -static int __init mm_compute_batch_init(void) -{ - mm_compute_batch(); - register_hotmemory_notifier(&compute_batch_nb); - - return 0; -} - -__initcall(mm_compute_batch_init); - -#endif - -static int __init mm_sysfs_init(void) -{ - mm_kobj = kobject_create_and_add("mm", kernel_kobj); - if (!mm_kobj) - return -ENOMEM; - - return 0; -} -postcore_initcall(mm_sysfs_init); diff --git a/src/linux/mm/mmu_context.c b/src/linux/mm/mmu_context.c deleted file mode 100644 index 6f4d27c..0000000 --- a/src/linux/mm/mmu_context.c +++ /dev/null @@ -1,62 +0,0 @@ -/* Copyright (C) 2009 Red Hat, Inc. - * - * See ../COPYING for licensing terms. - */ - -#include -#include -#include -#include - -#include - -/* - * use_mm - * Makes the calling kernel thread take on the specified - * mm context. - * (Note: this routine is intended to be called only - * from a kernel thread context) - */ -void use_mm(struct mm_struct *mm) -{ - struct mm_struct *active_mm; - struct task_struct *tsk = current; - - task_lock(tsk); - active_mm = tsk->active_mm; - if (active_mm != mm) { - atomic_inc(&mm->mm_count); - tsk->active_mm = mm; - } - tsk->mm = mm; - switch_mm(active_mm, mm, tsk); - task_unlock(tsk); -#ifdef finish_arch_post_lock_switch - finish_arch_post_lock_switch(); -#endif - - if (active_mm != mm) - mmdrop(active_mm); -} -EXPORT_SYMBOL_GPL(use_mm); - -/* - * unuse_mm - * Reverses the effect of use_mm, i.e. releases the - * specified mm context which was earlier taken on - * by the calling kernel thread - * (Note: this routine is intended to be called only - * from a kernel thread context) - */ -void unuse_mm(struct mm_struct *mm) -{ - struct task_struct *tsk = current; - - task_lock(tsk); - sync_mm_rss(mm); - tsk->mm = NULL; - /* active_mm is still 'mm' */ - enter_lazy_tlb(mm, tsk); - task_unlock(tsk); -} -EXPORT_SYMBOL_GPL(unuse_mm); diff --git a/src/linux/mm/mmzone.c b/src/linux/mm/mmzone.c deleted file mode 100644 index 5652be8..0000000 --- a/src/linux/mm/mmzone.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * linux/mm/mmzone.c - * - * management codes for pgdats, zones and page flags - */ - - -#include -#include -#include - -struct pglist_data *first_online_pgdat(void) -{ - return NODE_DATA(first_online_node); -} - -struct pglist_data *next_online_pgdat(struct pglist_data *pgdat) -{ - int nid = next_online_node(pgdat->node_id); - - if (nid == MAX_NUMNODES) - return NULL; - return NODE_DATA(nid); -} - -/* - * next_zone - helper magic for for_each_zone() - */ -struct zone *next_zone(struct zone *zone) -{ - pg_data_t *pgdat = zone->zone_pgdat; - - if (zone < pgdat->node_zones + MAX_NR_ZONES - 1) - zone++; - else { - pgdat = next_online_pgdat(pgdat); - if (pgdat) - zone = pgdat->node_zones; - else - zone = NULL; - } - return zone; -} - -static inline int zref_in_nodemask(struct zoneref *zref, nodemask_t *nodes) -{ -#ifdef CONFIG_NUMA - return node_isset(zonelist_node_idx(zref), *nodes); -#else - return 1; -#endif /* CONFIG_NUMA */ -} - -/* Returns the next zone at or below highest_zoneidx in a zonelist */ -struct zoneref *__next_zones_zonelist(struct zoneref *z, - enum zone_type highest_zoneidx, - nodemask_t *nodes) -{ - /* - * Find the next suitable zone to use for the allocation. - * Only filter based on nodemask if it's set - */ - if (likely(nodes == NULL)) - while (zonelist_zone_idx(z) > highest_zoneidx) - z++; - else - while (zonelist_zone_idx(z) > highest_zoneidx || - (z->zone && !zref_in_nodemask(z, nodes))) - z++; - - return z; -} - -#ifdef CONFIG_ARCH_HAS_HOLES_MEMORYMODEL -bool memmap_valid_within(unsigned long pfn, - struct page *page, struct zone *zone) -{ - if (page_to_pfn(page) != pfn) - return false; - - if (page_zone(page) != zone) - return false; - - return true; -} -#endif /* CONFIG_ARCH_HAS_HOLES_MEMORYMODEL */ - -void lruvec_init(struct lruvec *lruvec) -{ - enum lru_list lru; - - memset(lruvec, 0, sizeof(struct lruvec)); - - for_each_lru(lru) - INIT_LIST_HEAD(&lruvec->lists[lru]); -} - -#if defined(CONFIG_NUMA_BALANCING) && !defined(LAST_CPUPID_NOT_IN_PAGE_FLAGS) -int page_cpupid_xchg_last(struct page *page, int cpupid) -{ - unsigned long old_flags, flags; - int last_cpupid; - - do { - old_flags = flags = page->flags; - last_cpupid = page_cpupid_last(page); - - flags &= ~(LAST_CPUPID_MASK << LAST_CPUPID_PGSHIFT); - flags |= (cpupid & LAST_CPUPID_MASK) << LAST_CPUPID_PGSHIFT; - } while (unlikely(cmpxchg(&page->flags, old_flags, flags) != old_flags)); - - return last_cpupid; -} -#endif diff --git a/src/linux/mm/nommu.c b/src/linux/mm/nommu.c deleted file mode 100644 index 8b8faaf..0000000 --- a/src/linux/mm/nommu.c +++ /dev/null @@ -1,1984 +0,0 @@ -/* - * linux/mm/nommu.c - * - * Replacement code for mm functions to support CPU's that don't - * have any form of memory management unit (thus no virtual memory). - * - * See Documentation/nommu-mmap.txt - * - * Copyright (c) 2004-2008 David Howells - * Copyright (c) 2000-2003 David McCullough - * Copyright (c) 2000-2001 D Jeff Dionne - * Copyright (c) 2002 Greg Ungerer - * Copyright (c) 2007-2010 Paul Mundt - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include "internal.h" - -void *high_memory; -EXPORT_SYMBOL(high_memory); -struct page *mem_map; -unsigned long max_mapnr; -EXPORT_SYMBOL(max_mapnr); -unsigned long highest_memmap_pfn; -int sysctl_nr_trim_pages = CONFIG_NOMMU_INITIAL_TRIM_EXCESS; -int heap_stack_gap = 0; - -atomic_long_t mmap_pages_allocated; - -EXPORT_SYMBOL(mem_map); - -/* list of mapped, potentially shareable regions */ -static struct kmem_cache *vm_region_jar; -struct rb_root nommu_region_tree = RB_ROOT; -DECLARE_RWSEM(nommu_region_sem); - -const struct vm_operations_struct generic_file_vm_ops = { -}; - -/* - * Return the total memory allocated for this pointer, not - * just what the caller asked for. - * - * Doesn't have to be accurate, i.e. may have races. - */ -unsigned int kobjsize(const void *objp) -{ - struct page *page; - - /* - * If the object we have should not have ksize performed on it, - * return size of 0 - */ - if (!objp || !virt_addr_valid(objp)) - return 0; - - page = virt_to_head_page(objp); - - /* - * If the allocator sets PageSlab, we know the pointer came from - * kmalloc(). - */ - if (PageSlab(page)) - return ksize(objp); - - /* - * If it's not a compound page, see if we have a matching VMA - * region. This test is intentionally done in reverse order, - * so if there's no VMA, we still fall through and hand back - * PAGE_SIZE for 0-order pages. - */ - if (!PageCompound(page)) { - struct vm_area_struct *vma; - - vma = find_vma(current->mm, (unsigned long)objp); - if (vma) - return vma->vm_end - vma->vm_start; - } - - /* - * The ksize() function is only guaranteed to work for pointers - * returned by kmalloc(). So handle arbitrary pointers here. - */ - return PAGE_SIZE << compound_order(page); -} - -static long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, - unsigned long start, unsigned long nr_pages, - unsigned int foll_flags, struct page **pages, - struct vm_area_struct **vmas, int *nonblocking) -{ - struct vm_area_struct *vma; - unsigned long vm_flags; - int i; - - /* calculate required read or write permissions. - * If FOLL_FORCE is set, we only require the "MAY" flags. - */ - vm_flags = (foll_flags & FOLL_WRITE) ? - (VM_WRITE | VM_MAYWRITE) : (VM_READ | VM_MAYREAD); - vm_flags &= (foll_flags & FOLL_FORCE) ? - (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE); - - for (i = 0; i < nr_pages; i++) { - vma = find_vma(mm, start); - if (!vma) - goto finish_or_fault; - - /* protect what we can, including chardevs */ - if ((vma->vm_flags & (VM_IO | VM_PFNMAP)) || - !(vm_flags & vma->vm_flags)) - goto finish_or_fault; - - if (pages) { - pages[i] = virt_to_page(start); - if (pages[i]) - get_page(pages[i]); - } - if (vmas) - vmas[i] = vma; - start = (start + PAGE_SIZE) & PAGE_MASK; - } - - return i; - -finish_or_fault: - return i ? : -EFAULT; -} - -/* - * get a list of pages in an address range belonging to the specified process - * and indicate the VMA that covers each page - * - this is potentially dodgy as we may end incrementing the page count of a - * slab page or a secondary page from a compound page - * - don't permit access to VMAs that don't support it, such as I/O mappings - */ -long get_user_pages(unsigned long start, unsigned long nr_pages, - unsigned int gup_flags, struct page **pages, - struct vm_area_struct **vmas) -{ - return __get_user_pages(current, current->mm, start, nr_pages, - gup_flags, pages, vmas, NULL); -} -EXPORT_SYMBOL(get_user_pages); - -long get_user_pages_locked(unsigned long start, unsigned long nr_pages, - unsigned int gup_flags, struct page **pages, - int *locked) -{ - return get_user_pages(start, nr_pages, gup_flags, pages, NULL); -} -EXPORT_SYMBOL(get_user_pages_locked); - -long __get_user_pages_unlocked(struct task_struct *tsk, struct mm_struct *mm, - unsigned long start, unsigned long nr_pages, - struct page **pages, unsigned int gup_flags) -{ - long ret; - down_read(&mm->mmap_sem); - ret = __get_user_pages(tsk, mm, start, nr_pages, gup_flags, pages, - NULL, NULL); - up_read(&mm->mmap_sem); - return ret; -} -EXPORT_SYMBOL(__get_user_pages_unlocked); - -long get_user_pages_unlocked(unsigned long start, unsigned long nr_pages, - struct page **pages, unsigned int gup_flags) -{ - return __get_user_pages_unlocked(current, current->mm, start, nr_pages, - pages, gup_flags); -} -EXPORT_SYMBOL(get_user_pages_unlocked); - -/** - * follow_pfn - look up PFN at a user virtual address - * @vma: memory mapping - * @address: user virtual address - * @pfn: location to store found PFN - * - * Only IO mappings and raw PFN mappings are allowed. - * - * Returns zero and the pfn at @pfn on success, -ve otherwise. - */ -int follow_pfn(struct vm_area_struct *vma, unsigned long address, - unsigned long *pfn) -{ - if (!(vma->vm_flags & (VM_IO | VM_PFNMAP))) - return -EINVAL; - - *pfn = address >> PAGE_SHIFT; - return 0; -} -EXPORT_SYMBOL(follow_pfn); - -LIST_HEAD(vmap_area_list); - -void vfree(const void *addr) -{ - kfree(addr); -} -EXPORT_SYMBOL(vfree); - -void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot) -{ - /* - * You can't specify __GFP_HIGHMEM with kmalloc() since kmalloc() - * returns only a logical address. - */ - return kmalloc(size, (gfp_mask | __GFP_COMP) & ~__GFP_HIGHMEM); -} -EXPORT_SYMBOL(__vmalloc); - -void *vmalloc_user(unsigned long size) -{ - void *ret; - - ret = __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, - PAGE_KERNEL); - if (ret) { - struct vm_area_struct *vma; - - down_write(¤t->mm->mmap_sem); - vma = find_vma(current->mm, (unsigned long)ret); - if (vma) - vma->vm_flags |= VM_USERMAP; - up_write(¤t->mm->mmap_sem); - } - - return ret; -} -EXPORT_SYMBOL(vmalloc_user); - -struct page *vmalloc_to_page(const void *addr) -{ - return virt_to_page(addr); -} -EXPORT_SYMBOL(vmalloc_to_page); - -unsigned long vmalloc_to_pfn(const void *addr) -{ - return page_to_pfn(virt_to_page(addr)); -} -EXPORT_SYMBOL(vmalloc_to_pfn); - -long vread(char *buf, char *addr, unsigned long count) -{ - /* Don't allow overflow */ - if ((unsigned long) buf + count < count) - count = -(unsigned long) buf; - - memcpy(buf, addr, count); - return count; -} - -long vwrite(char *buf, char *addr, unsigned long count) -{ - /* Don't allow overflow */ - if ((unsigned long) addr + count < count) - count = -(unsigned long) addr; - - memcpy(addr, buf, count); - return count; -} - -/* - * vmalloc - allocate virtually contiguous memory - * - * @size: allocation size - * - * Allocate enough pages to cover @size from the page level - * allocator and map them into contiguous kernel virtual space. - * - * For tight control over page level allocator and protection flags - * use __vmalloc() instead. - */ -void *vmalloc(unsigned long size) -{ - return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL); -} -EXPORT_SYMBOL(vmalloc); - -/* - * vzalloc - allocate virtually contiguous memory with zero fill - * - * @size: allocation size - * - * Allocate enough pages to cover @size from the page level - * allocator and map them into contiguous kernel virtual space. - * The memory allocated is set to zero. - * - * For tight control over page level allocator and protection flags - * use __vmalloc() instead. - */ -void *vzalloc(unsigned long size) -{ - return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, - PAGE_KERNEL); -} -EXPORT_SYMBOL(vzalloc); - -/** - * vmalloc_node - allocate memory on a specific node - * @size: allocation size - * @node: numa node - * - * Allocate enough pages to cover @size from the page level - * allocator and map them into contiguous kernel virtual space. - * - * For tight control over page level allocator and protection flags - * use __vmalloc() instead. - */ -void *vmalloc_node(unsigned long size, int node) -{ - return vmalloc(size); -} -EXPORT_SYMBOL(vmalloc_node); - -/** - * vzalloc_node - allocate memory on a specific node with zero fill - * @size: allocation size - * @node: numa node - * - * Allocate enough pages to cover @size from the page level - * allocator and map them into contiguous kernel virtual space. - * The memory allocated is set to zero. - * - * For tight control over page level allocator and protection flags - * use __vmalloc() instead. - */ -void *vzalloc_node(unsigned long size, int node) -{ - return vzalloc(size); -} -EXPORT_SYMBOL(vzalloc_node); - -#ifndef PAGE_KERNEL_EXEC -# define PAGE_KERNEL_EXEC PAGE_KERNEL -#endif - -/** - * vmalloc_exec - allocate virtually contiguous, executable memory - * @size: allocation size - * - * Kernel-internal function to allocate enough pages to cover @size - * the page level allocator and map them into contiguous and - * executable kernel virtual space. - * - * For tight control over page level allocator and protection flags - * use __vmalloc() instead. - */ - -void *vmalloc_exec(unsigned long size) -{ - return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC); -} - -/** - * vmalloc_32 - allocate virtually contiguous memory (32bit addressable) - * @size: allocation size - * - * Allocate enough 32bit PA addressable pages to cover @size from the - * page level allocator and map them into contiguous kernel virtual space. - */ -void *vmalloc_32(unsigned long size) -{ - return __vmalloc(size, GFP_KERNEL, PAGE_KERNEL); -} -EXPORT_SYMBOL(vmalloc_32); - -/** - * vmalloc_32_user - allocate zeroed virtually contiguous 32bit memory - * @size: allocation size - * - * The resulting memory area is 32bit addressable and zeroed so it can be - * mapped to userspace without leaking data. - * - * VM_USERMAP is set on the corresponding VMA so that subsequent calls to - * remap_vmalloc_range() are permissible. - */ -void *vmalloc_32_user(unsigned long size) -{ - /* - * We'll have to sort out the ZONE_DMA bits for 64-bit, - * but for now this can simply use vmalloc_user() directly. - */ - return vmalloc_user(size); -} -EXPORT_SYMBOL(vmalloc_32_user); - -void *vmap(struct page **pages, unsigned int count, unsigned long flags, pgprot_t prot) -{ - BUG(); - return NULL; -} -EXPORT_SYMBOL(vmap); - -void vunmap(const void *addr) -{ - BUG(); -} -EXPORT_SYMBOL(vunmap); - -void *vm_map_ram(struct page **pages, unsigned int count, int node, pgprot_t prot) -{ - BUG(); - return NULL; -} -EXPORT_SYMBOL(vm_map_ram); - -void vm_unmap_ram(const void *mem, unsigned int count) -{ - BUG(); -} -EXPORT_SYMBOL(vm_unmap_ram); - -void vm_unmap_aliases(void) -{ -} -EXPORT_SYMBOL_GPL(vm_unmap_aliases); - -/* - * Implement a stub for vmalloc_sync_all() if the architecture chose not to - * have one. - */ -void __weak vmalloc_sync_all(void) -{ -} - -/** - * alloc_vm_area - allocate a range of kernel address space - * @size: size of the area - * - * Returns: NULL on failure, vm_struct on success - * - * This function reserves a range of kernel address space, and - * allocates pagetables to map that range. No actual mappings - * are created. If the kernel address space is not shared - * between processes, it syncs the pagetable across all - * processes. - */ -struct vm_struct *alloc_vm_area(size_t size, pte_t **ptes) -{ - BUG(); - return NULL; -} -EXPORT_SYMBOL_GPL(alloc_vm_area); - -void free_vm_area(struct vm_struct *area) -{ - BUG(); -} -EXPORT_SYMBOL_GPL(free_vm_area); - -int vm_insert_page(struct vm_area_struct *vma, unsigned long addr, - struct page *page) -{ - return -EINVAL; -} -EXPORT_SYMBOL(vm_insert_page); - -/* - * sys_brk() for the most part doesn't need the global kernel - * lock, except when an application is doing something nasty - * like trying to un-brk an area that has already been mapped - * to a regular file. in this case, the unmapping will need - * to invoke file system routines that need the global lock. - */ -SYSCALL_DEFINE1(brk, unsigned long, brk) -{ - struct mm_struct *mm = current->mm; - - if (brk < mm->start_brk || brk > mm->context.end_brk) - return mm->brk; - - if (mm->brk == brk) - return mm->brk; - - /* - * Always allow shrinking brk - */ - if (brk <= mm->brk) { - mm->brk = brk; - return brk; - } - - /* - * Ok, looks good - let it rip. - */ - flush_icache_range(mm->brk, brk); - return mm->brk = brk; -} - -/* - * initialise the VMA and region record slabs - */ -void __init mmap_init(void) -{ - int ret; - - ret = percpu_counter_init(&vm_committed_as, 0, GFP_KERNEL); - VM_BUG_ON(ret); - vm_region_jar = KMEM_CACHE(vm_region, SLAB_PANIC|SLAB_ACCOUNT); -} - -/* - * validate the region tree - * - the caller must hold the region lock - */ -#ifdef CONFIG_DEBUG_NOMMU_REGIONS -static noinline void validate_nommu_regions(void) -{ - struct vm_region *region, *last; - struct rb_node *p, *lastp; - - lastp = rb_first(&nommu_region_tree); - if (!lastp) - return; - - last = rb_entry(lastp, struct vm_region, vm_rb); - BUG_ON(last->vm_end <= last->vm_start); - BUG_ON(last->vm_top < last->vm_end); - - while ((p = rb_next(lastp))) { - region = rb_entry(p, struct vm_region, vm_rb); - last = rb_entry(lastp, struct vm_region, vm_rb); - - BUG_ON(region->vm_end <= region->vm_start); - BUG_ON(region->vm_top < region->vm_end); - BUG_ON(region->vm_start < last->vm_top); - - lastp = p; - } -} -#else -static void validate_nommu_regions(void) -{ -} -#endif - -/* - * add a region into the global tree - */ -static void add_nommu_region(struct vm_region *region) -{ - struct vm_region *pregion; - struct rb_node **p, *parent; - - validate_nommu_regions(); - - parent = NULL; - p = &nommu_region_tree.rb_node; - while (*p) { - parent = *p; - pregion = rb_entry(parent, struct vm_region, vm_rb); - if (region->vm_start < pregion->vm_start) - p = &(*p)->rb_left; - else if (region->vm_start > pregion->vm_start) - p = &(*p)->rb_right; - else if (pregion == region) - return; - else - BUG(); - } - - rb_link_node(®ion->vm_rb, parent, p); - rb_insert_color(®ion->vm_rb, &nommu_region_tree); - - validate_nommu_regions(); -} - -/* - * delete a region from the global tree - */ -static void delete_nommu_region(struct vm_region *region) -{ - BUG_ON(!nommu_region_tree.rb_node); - - validate_nommu_regions(); - rb_erase(®ion->vm_rb, &nommu_region_tree); - validate_nommu_regions(); -} - -/* - * free a contiguous series of pages - */ -static void free_page_series(unsigned long from, unsigned long to) -{ - for (; from < to; from += PAGE_SIZE) { - struct page *page = virt_to_page(from); - - atomic_long_dec(&mmap_pages_allocated); - put_page(page); - } -} - -/* - * release a reference to a region - * - the caller must hold the region semaphore for writing, which this releases - * - the region may not have been added to the tree yet, in which case vm_top - * will equal vm_start - */ -static void __put_nommu_region(struct vm_region *region) - __releases(nommu_region_sem) -{ - BUG_ON(!nommu_region_tree.rb_node); - - if (--region->vm_usage == 0) { - if (region->vm_top > region->vm_start) - delete_nommu_region(region); - up_write(&nommu_region_sem); - - if (region->vm_file) - fput(region->vm_file); - - /* IO memory and memory shared directly out of the pagecache - * from ramfs/tmpfs mustn't be released here */ - if (region->vm_flags & VM_MAPPED_COPY) - free_page_series(region->vm_start, region->vm_top); - kmem_cache_free(vm_region_jar, region); - } else { - up_write(&nommu_region_sem); - } -} - -/* - * release a reference to a region - */ -static void put_nommu_region(struct vm_region *region) -{ - down_write(&nommu_region_sem); - __put_nommu_region(region); -} - -/* - * update protection on a vma - */ -static void protect_vma(struct vm_area_struct *vma, unsigned long flags) -{ -#ifdef CONFIG_MPU - struct mm_struct *mm = vma->vm_mm; - long start = vma->vm_start & PAGE_MASK; - while (start < vma->vm_end) { - protect_page(mm, start, flags); - start += PAGE_SIZE; - } - update_protections(mm); -#endif -} - -/* - * add a VMA into a process's mm_struct in the appropriate place in the list - * and tree and add to the address space's page tree also if not an anonymous - * page - * - should be called with mm->mmap_sem held writelocked - */ -static void add_vma_to_mm(struct mm_struct *mm, struct vm_area_struct *vma) -{ - struct vm_area_struct *pvma, *prev; - struct address_space *mapping; - struct rb_node **p, *parent, *rb_prev; - - BUG_ON(!vma->vm_region); - - mm->map_count++; - vma->vm_mm = mm; - - protect_vma(vma, vma->vm_flags); - - /* add the VMA to the mapping */ - if (vma->vm_file) { - mapping = vma->vm_file->f_mapping; - - i_mmap_lock_write(mapping); - flush_dcache_mmap_lock(mapping); - vma_interval_tree_insert(vma, &mapping->i_mmap); - flush_dcache_mmap_unlock(mapping); - i_mmap_unlock_write(mapping); - } - - /* add the VMA to the tree */ - parent = rb_prev = NULL; - p = &mm->mm_rb.rb_node; - while (*p) { - parent = *p; - pvma = rb_entry(parent, struct vm_area_struct, vm_rb); - - /* sort by: start addr, end addr, VMA struct addr in that order - * (the latter is necessary as we may get identical VMAs) */ - if (vma->vm_start < pvma->vm_start) - p = &(*p)->rb_left; - else if (vma->vm_start > pvma->vm_start) { - rb_prev = parent; - p = &(*p)->rb_right; - } else if (vma->vm_end < pvma->vm_end) - p = &(*p)->rb_left; - else if (vma->vm_end > pvma->vm_end) { - rb_prev = parent; - p = &(*p)->rb_right; - } else if (vma < pvma) - p = &(*p)->rb_left; - else if (vma > pvma) { - rb_prev = parent; - p = &(*p)->rb_right; - } else - BUG(); - } - - rb_link_node(&vma->vm_rb, parent, p); - rb_insert_color(&vma->vm_rb, &mm->mm_rb); - - /* add VMA to the VMA list also */ - prev = NULL; - if (rb_prev) - prev = rb_entry(rb_prev, struct vm_area_struct, vm_rb); - - __vma_link_list(mm, vma, prev, parent); -} - -/* - * delete a VMA from its owning mm_struct and address space - */ -static void delete_vma_from_mm(struct vm_area_struct *vma) -{ - int i; - struct address_space *mapping; - struct mm_struct *mm = vma->vm_mm; - struct task_struct *curr = current; - - protect_vma(vma, 0); - - mm->map_count--; - for (i = 0; i < VMACACHE_SIZE; i++) { - /* if the vma is cached, invalidate the entire cache */ - if (curr->vmacache[i] == vma) { - vmacache_invalidate(mm); - break; - } - } - - /* remove the VMA from the mapping */ - if (vma->vm_file) { - mapping = vma->vm_file->f_mapping; - - i_mmap_lock_write(mapping); - flush_dcache_mmap_lock(mapping); - vma_interval_tree_remove(vma, &mapping->i_mmap); - flush_dcache_mmap_unlock(mapping); - i_mmap_unlock_write(mapping); - } - - /* remove from the MM's tree and list */ - rb_erase(&vma->vm_rb, &mm->mm_rb); - - if (vma->vm_prev) - vma->vm_prev->vm_next = vma->vm_next; - else - mm->mmap = vma->vm_next; - - if (vma->vm_next) - vma->vm_next->vm_prev = vma->vm_prev; -} - -/* - * destroy a VMA record - */ -static void delete_vma(struct mm_struct *mm, struct vm_area_struct *vma) -{ - if (vma->vm_ops && vma->vm_ops->close) - vma->vm_ops->close(vma); - if (vma->vm_file) - fput(vma->vm_file); - put_nommu_region(vma->vm_region); - kmem_cache_free(vm_area_cachep, vma); -} - -/* - * look up the first VMA in which addr resides, NULL if none - * - should be called with mm->mmap_sem at least held readlocked - */ -struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr) -{ - struct vm_area_struct *vma; - - /* check the cache first */ - vma = vmacache_find(mm, addr); - if (likely(vma)) - return vma; - - /* trawl the list (there may be multiple mappings in which addr - * resides) */ - for (vma = mm->mmap; vma; vma = vma->vm_next) { - if (vma->vm_start > addr) - return NULL; - if (vma->vm_end > addr) { - vmacache_update(addr, vma); - return vma; - } - } - - return NULL; -} -EXPORT_SYMBOL(find_vma); - -/* - * find a VMA - * - we don't extend stack VMAs under NOMMU conditions - */ -struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr) -{ - return find_vma(mm, addr); -} - -/* - * expand a stack to a given address - * - not supported under NOMMU conditions - */ -int expand_stack(struct vm_area_struct *vma, unsigned long address) -{ - return -ENOMEM; -} - -/* - * look up the first VMA exactly that exactly matches addr - * - should be called with mm->mmap_sem at least held readlocked - */ -static struct vm_area_struct *find_vma_exact(struct mm_struct *mm, - unsigned long addr, - unsigned long len) -{ - struct vm_area_struct *vma; - unsigned long end = addr + len; - - /* check the cache first */ - vma = vmacache_find_exact(mm, addr, end); - if (vma) - return vma; - - /* trawl the list (there may be multiple mappings in which addr - * resides) */ - for (vma = mm->mmap; vma; vma = vma->vm_next) { - if (vma->vm_start < addr) - continue; - if (vma->vm_start > addr) - return NULL; - if (vma->vm_end == end) { - vmacache_update(addr, vma); - return vma; - } - } - - return NULL; -} - -/* - * determine whether a mapping should be permitted and, if so, what sort of - * mapping we're capable of supporting - */ -static int validate_mmap_request(struct file *file, - unsigned long addr, - unsigned long len, - unsigned long prot, - unsigned long flags, - unsigned long pgoff, - unsigned long *_capabilities) -{ - unsigned long capabilities, rlen; - int ret; - - /* do the simple checks first */ - if (flags & MAP_FIXED) - return -EINVAL; - - if ((flags & MAP_TYPE) != MAP_PRIVATE && - (flags & MAP_TYPE) != MAP_SHARED) - return -EINVAL; - - if (!len) - return -EINVAL; - - /* Careful about overflows.. */ - rlen = PAGE_ALIGN(len); - if (!rlen || rlen > TASK_SIZE) - return -ENOMEM; - - /* offset overflow? */ - if ((pgoff + (rlen >> PAGE_SHIFT)) < pgoff) - return -EOVERFLOW; - - if (file) { - /* files must support mmap */ - if (!file->f_op->mmap) - return -ENODEV; - - /* work out if what we've got could possibly be shared - * - we support chardevs that provide their own "memory" - * - we support files/blockdevs that are memory backed - */ - if (file->f_op->mmap_capabilities) { - capabilities = file->f_op->mmap_capabilities(file); - } else { - /* no explicit capabilities set, so assume some - * defaults */ - switch (file_inode(file)->i_mode & S_IFMT) { - case S_IFREG: - case S_IFBLK: - capabilities = NOMMU_MAP_COPY; - break; - - case S_IFCHR: - capabilities = - NOMMU_MAP_DIRECT | - NOMMU_MAP_READ | - NOMMU_MAP_WRITE; - break; - - default: - return -EINVAL; - } - } - - /* eliminate any capabilities that we can't support on this - * device */ - if (!file->f_op->get_unmapped_area) - capabilities &= ~NOMMU_MAP_DIRECT; - if (!(file->f_mode & FMODE_CAN_READ)) - capabilities &= ~NOMMU_MAP_COPY; - - /* The file shall have been opened with read permission. */ - if (!(file->f_mode & FMODE_READ)) - return -EACCES; - - if (flags & MAP_SHARED) { - /* do checks for writing, appending and locking */ - if ((prot & PROT_WRITE) && - !(file->f_mode & FMODE_WRITE)) - return -EACCES; - - if (IS_APPEND(file_inode(file)) && - (file->f_mode & FMODE_WRITE)) - return -EACCES; - - if (locks_verify_locked(file)) - return -EAGAIN; - - if (!(capabilities & NOMMU_MAP_DIRECT)) - return -ENODEV; - - /* we mustn't privatise shared mappings */ - capabilities &= ~NOMMU_MAP_COPY; - } else { - /* we're going to read the file into private memory we - * allocate */ - if (!(capabilities & NOMMU_MAP_COPY)) - return -ENODEV; - - /* we don't permit a private writable mapping to be - * shared with the backing device */ - if (prot & PROT_WRITE) - capabilities &= ~NOMMU_MAP_DIRECT; - } - - if (capabilities & NOMMU_MAP_DIRECT) { - if (((prot & PROT_READ) && !(capabilities & NOMMU_MAP_READ)) || - ((prot & PROT_WRITE) && !(capabilities & NOMMU_MAP_WRITE)) || - ((prot & PROT_EXEC) && !(capabilities & NOMMU_MAP_EXEC)) - ) { - capabilities &= ~NOMMU_MAP_DIRECT; - if (flags & MAP_SHARED) { - pr_warn("MAP_SHARED not completely supported on !MMU\n"); - return -EINVAL; - } - } - } - - /* handle executable mappings and implied executable - * mappings */ - if (path_noexec(&file->f_path)) { - if (prot & PROT_EXEC) - return -EPERM; - } else if ((prot & PROT_READ) && !(prot & PROT_EXEC)) { - /* handle implication of PROT_EXEC by PROT_READ */ - if (current->personality & READ_IMPLIES_EXEC) { - if (capabilities & NOMMU_MAP_EXEC) - prot |= PROT_EXEC; - } - } else if ((prot & PROT_READ) && - (prot & PROT_EXEC) && - !(capabilities & NOMMU_MAP_EXEC) - ) { - /* backing file is not executable, try to copy */ - capabilities &= ~NOMMU_MAP_DIRECT; - } - } else { - /* anonymous mappings are always memory backed and can be - * privately mapped - */ - capabilities = NOMMU_MAP_COPY; - - /* handle PROT_EXEC implication by PROT_READ */ - if ((prot & PROT_READ) && - (current->personality & READ_IMPLIES_EXEC)) - prot |= PROT_EXEC; - } - - /* allow the security API to have its say */ - ret = security_mmap_addr(addr); - if (ret < 0) - return ret; - - /* looks okay */ - *_capabilities = capabilities; - return 0; -} - -/* - * we've determined that we can make the mapping, now translate what we - * now know into VMA flags - */ -static unsigned long determine_vm_flags(struct file *file, - unsigned long prot, - unsigned long flags, - unsigned long capabilities) -{ - unsigned long vm_flags; - - vm_flags = calc_vm_prot_bits(prot, 0) | calc_vm_flag_bits(flags); - /* vm_flags |= mm->def_flags; */ - - if (!(capabilities & NOMMU_MAP_DIRECT)) { - /* attempt to share read-only copies of mapped file chunks */ - vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; - if (file && !(prot & PROT_WRITE)) - vm_flags |= VM_MAYSHARE; - } else { - /* overlay a shareable mapping on the backing device or inode - * if possible - used for chardevs, ramfs/tmpfs/shmfs and - * romfs/cramfs */ - vm_flags |= VM_MAYSHARE | (capabilities & NOMMU_VMFLAGS); - if (flags & MAP_SHARED) - vm_flags |= VM_SHARED; - } - - /* refuse to let anyone share private mappings with this process if - * it's being traced - otherwise breakpoints set in it may interfere - * with another untraced process - */ - if ((flags & MAP_PRIVATE) && current->ptrace) - vm_flags &= ~VM_MAYSHARE; - - return vm_flags; -} - -/* - * set up a shared mapping on a file (the driver or filesystem provides and - * pins the storage) - */ -static int do_mmap_shared_file(struct vm_area_struct *vma) -{ - int ret; - - ret = vma->vm_file->f_op->mmap(vma->vm_file, vma); - if (ret == 0) { - vma->vm_region->vm_top = vma->vm_region->vm_end; - return 0; - } - if (ret != -ENOSYS) - return ret; - - /* getting -ENOSYS indicates that direct mmap isn't possible (as - * opposed to tried but failed) so we can only give a suitable error as - * it's not possible to make a private copy if MAP_SHARED was given */ - return -ENODEV; -} - -/* - * set up a private mapping or an anonymous shared mapping - */ -static int do_mmap_private(struct vm_area_struct *vma, - struct vm_region *region, - unsigned long len, - unsigned long capabilities) -{ - unsigned long total, point; - void *base; - int ret, order; - - /* invoke the file's mapping function so that it can keep track of - * shared mappings on devices or memory - * - VM_MAYSHARE will be set if it may attempt to share - */ - if (capabilities & NOMMU_MAP_DIRECT) { - ret = vma->vm_file->f_op->mmap(vma->vm_file, vma); - if (ret == 0) { - /* shouldn't return success if we're not sharing */ - BUG_ON(!(vma->vm_flags & VM_MAYSHARE)); - vma->vm_region->vm_top = vma->vm_region->vm_end; - return 0; - } - if (ret != -ENOSYS) - return ret; - - /* getting an ENOSYS error indicates that direct mmap isn't - * possible (as opposed to tried but failed) so we'll try to - * make a private copy of the data and map that instead */ - } - - - /* allocate some memory to hold the mapping - * - note that this may not return a page-aligned address if the object - * we're allocating is smaller than a page - */ - order = get_order(len); - total = 1 << order; - point = len >> PAGE_SHIFT; - - /* we don't want to allocate a power-of-2 sized page set */ - if (sysctl_nr_trim_pages && total - point >= sysctl_nr_trim_pages) - total = point; - - base = alloc_pages_exact(total << PAGE_SHIFT, GFP_KERNEL); - if (!base) - goto enomem; - - atomic_long_add(total, &mmap_pages_allocated); - - region->vm_flags = vma->vm_flags |= VM_MAPPED_COPY; - region->vm_start = (unsigned long) base; - region->vm_end = region->vm_start + len; - region->vm_top = region->vm_start + (total << PAGE_SHIFT); - - vma->vm_start = region->vm_start; - vma->vm_end = region->vm_start + len; - - if (vma->vm_file) { - /* read the contents of a file into the copy */ - mm_segment_t old_fs; - loff_t fpos; - - fpos = vma->vm_pgoff; - fpos <<= PAGE_SHIFT; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - ret = __vfs_read(vma->vm_file, base, len, &fpos); - set_fs(old_fs); - - if (ret < 0) - goto error_free; - - /* clear the last little bit */ - if (ret < len) - memset(base + ret, 0, len - ret); - - } - - return 0; - -error_free: - free_page_series(region->vm_start, region->vm_top); - region->vm_start = vma->vm_start = 0; - region->vm_end = vma->vm_end = 0; - region->vm_top = 0; - return ret; - -enomem: - pr_err("Allocation of length %lu from process %d (%s) failed\n", - len, current->pid, current->comm); - show_free_areas(0); - return -ENOMEM; -} - -/* - * handle mapping creation for uClinux - */ -unsigned long do_mmap(struct file *file, - unsigned long addr, - unsigned long len, - unsigned long prot, - unsigned long flags, - vm_flags_t vm_flags, - unsigned long pgoff, - unsigned long *populate) -{ - struct vm_area_struct *vma; - struct vm_region *region; - struct rb_node *rb; - unsigned long capabilities, result; - int ret; - - *populate = 0; - - /* decide whether we should attempt the mapping, and if so what sort of - * mapping */ - ret = validate_mmap_request(file, addr, len, prot, flags, pgoff, - &capabilities); - if (ret < 0) - return ret; - - /* we ignore the address hint */ - addr = 0; - len = PAGE_ALIGN(len); - - /* we've determined that we can make the mapping, now translate what we - * now know into VMA flags */ - vm_flags |= determine_vm_flags(file, prot, flags, capabilities); - - /* we're going to need to record the mapping */ - region = kmem_cache_zalloc(vm_region_jar, GFP_KERNEL); - if (!region) - goto error_getting_region; - - vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); - if (!vma) - goto error_getting_vma; - - region->vm_usage = 1; - region->vm_flags = vm_flags; - region->vm_pgoff = pgoff; - - INIT_LIST_HEAD(&vma->anon_vma_chain); - vma->vm_flags = vm_flags; - vma->vm_pgoff = pgoff; - - if (file) { - region->vm_file = get_file(file); - vma->vm_file = get_file(file); - } - - down_write(&nommu_region_sem); - - /* if we want to share, we need to check for regions created by other - * mmap() calls that overlap with our proposed mapping - * - we can only share with a superset match on most regular files - * - shared mappings on character devices and memory backed files are - * permitted to overlap inexactly as far as we are concerned for in - * these cases, sharing is handled in the driver or filesystem rather - * than here - */ - if (vm_flags & VM_MAYSHARE) { - struct vm_region *pregion; - unsigned long pglen, rpglen, pgend, rpgend, start; - - pglen = (len + PAGE_SIZE - 1) >> PAGE_SHIFT; - pgend = pgoff + pglen; - - for (rb = rb_first(&nommu_region_tree); rb; rb = rb_next(rb)) { - pregion = rb_entry(rb, struct vm_region, vm_rb); - - if (!(pregion->vm_flags & VM_MAYSHARE)) - continue; - - /* search for overlapping mappings on the same file */ - if (file_inode(pregion->vm_file) != - file_inode(file)) - continue; - - if (pregion->vm_pgoff >= pgend) - continue; - - rpglen = pregion->vm_end - pregion->vm_start; - rpglen = (rpglen + PAGE_SIZE - 1) >> PAGE_SHIFT; - rpgend = pregion->vm_pgoff + rpglen; - if (pgoff >= rpgend) - continue; - - /* handle inexactly overlapping matches between - * mappings */ - if ((pregion->vm_pgoff != pgoff || rpglen != pglen) && - !(pgoff >= pregion->vm_pgoff && pgend <= rpgend)) { - /* new mapping is not a subset of the region */ - if (!(capabilities & NOMMU_MAP_DIRECT)) - goto sharing_violation; - continue; - } - - /* we've found a region we can share */ - pregion->vm_usage++; - vma->vm_region = pregion; - start = pregion->vm_start; - start += (pgoff - pregion->vm_pgoff) << PAGE_SHIFT; - vma->vm_start = start; - vma->vm_end = start + len; - - if (pregion->vm_flags & VM_MAPPED_COPY) - vma->vm_flags |= VM_MAPPED_COPY; - else { - ret = do_mmap_shared_file(vma); - if (ret < 0) { - vma->vm_region = NULL; - vma->vm_start = 0; - vma->vm_end = 0; - pregion->vm_usage--; - pregion = NULL; - goto error_just_free; - } - } - fput(region->vm_file); - kmem_cache_free(vm_region_jar, region); - region = pregion; - result = start; - goto share; - } - - /* obtain the address at which to make a shared mapping - * - this is the hook for quasi-memory character devices to - * tell us the location of a shared mapping - */ - if (capabilities & NOMMU_MAP_DIRECT) { - addr = file->f_op->get_unmapped_area(file, addr, len, - pgoff, flags); - if (IS_ERR_VALUE(addr)) { - ret = addr; - if (ret != -ENOSYS) - goto error_just_free; - - /* the driver refused to tell us where to site - * the mapping so we'll have to attempt to copy - * it */ - ret = -ENODEV; - if (!(capabilities & NOMMU_MAP_COPY)) - goto error_just_free; - - capabilities &= ~NOMMU_MAP_DIRECT; - } else { - vma->vm_start = region->vm_start = addr; - vma->vm_end = region->vm_end = addr + len; - } - } - } - - vma->vm_region = region; - - /* set up the mapping - * - the region is filled in if NOMMU_MAP_DIRECT is still set - */ - if (file && vma->vm_flags & VM_SHARED) - ret = do_mmap_shared_file(vma); - else - ret = do_mmap_private(vma, region, len, capabilities); - if (ret < 0) - goto error_just_free; - add_nommu_region(region); - - /* clear anonymous mappings that don't ask for uninitialized data */ - if (!vma->vm_file && !(flags & MAP_UNINITIALIZED)) - memset((void *)region->vm_start, 0, - region->vm_end - region->vm_start); - - /* okay... we have a mapping; now we have to register it */ - result = vma->vm_start; - - current->mm->total_vm += len >> PAGE_SHIFT; - -share: - add_vma_to_mm(current->mm, vma); - - /* we flush the region from the icache only when the first executable - * mapping of it is made */ - if (vma->vm_flags & VM_EXEC && !region->vm_icache_flushed) { - flush_icache_range(region->vm_start, region->vm_end); - region->vm_icache_flushed = true; - } - - up_write(&nommu_region_sem); - - return result; - -error_just_free: - up_write(&nommu_region_sem); -error: - if (region->vm_file) - fput(region->vm_file); - kmem_cache_free(vm_region_jar, region); - if (vma->vm_file) - fput(vma->vm_file); - kmem_cache_free(vm_area_cachep, vma); - return ret; - -sharing_violation: - up_write(&nommu_region_sem); - pr_warn("Attempt to share mismatched mappings\n"); - ret = -EINVAL; - goto error; - -error_getting_vma: - kmem_cache_free(vm_region_jar, region); - pr_warn("Allocation of vma for %lu byte allocation from process %d failed\n", - len, current->pid); - show_free_areas(0); - return -ENOMEM; - -error_getting_region: - pr_warn("Allocation of vm region for %lu byte allocation from process %d failed\n", - len, current->pid); - show_free_areas(0); - return -ENOMEM; -} - -SYSCALL_DEFINE6(mmap_pgoff, unsigned long, addr, unsigned long, len, - unsigned long, prot, unsigned long, flags, - unsigned long, fd, unsigned long, pgoff) -{ - struct file *file = NULL; - unsigned long retval = -EBADF; - - audit_mmap_fd(fd, flags); - if (!(flags & MAP_ANONYMOUS)) { - file = fget(fd); - if (!file) - goto out; - } - - flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); - - retval = vm_mmap_pgoff(file, addr, len, prot, flags, pgoff); - - if (file) - fput(file); -out: - return retval; -} - -#ifdef __ARCH_WANT_SYS_OLD_MMAP -struct mmap_arg_struct { - unsigned long addr; - unsigned long len; - unsigned long prot; - unsigned long flags; - unsigned long fd; - unsigned long offset; -}; - -SYSCALL_DEFINE1(old_mmap, struct mmap_arg_struct __user *, arg) -{ - struct mmap_arg_struct a; - - if (copy_from_user(&a, arg, sizeof(a))) - return -EFAULT; - if (offset_in_page(a.offset)) - return -EINVAL; - - return sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd, - a.offset >> PAGE_SHIFT); -} -#endif /* __ARCH_WANT_SYS_OLD_MMAP */ - -/* - * split a vma into two pieces at address 'addr', a new vma is allocated either - * for the first part or the tail. - */ -int split_vma(struct mm_struct *mm, struct vm_area_struct *vma, - unsigned long addr, int new_below) -{ - struct vm_area_struct *new; - struct vm_region *region; - unsigned long npages; - - /* we're only permitted to split anonymous regions (these should have - * only a single usage on the region) */ - if (vma->vm_file) - return -ENOMEM; - - if (mm->map_count >= sysctl_max_map_count) - return -ENOMEM; - - region = kmem_cache_alloc(vm_region_jar, GFP_KERNEL); - if (!region) - return -ENOMEM; - - new = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); - if (!new) { - kmem_cache_free(vm_region_jar, region); - return -ENOMEM; - } - - /* most fields are the same, copy all, and then fixup */ - *new = *vma; - *region = *vma->vm_region; - new->vm_region = region; - - npages = (addr - vma->vm_start) >> PAGE_SHIFT; - - if (new_below) { - region->vm_top = region->vm_end = new->vm_end = addr; - } else { - region->vm_start = new->vm_start = addr; - region->vm_pgoff = new->vm_pgoff += npages; - } - - if (new->vm_ops && new->vm_ops->open) - new->vm_ops->open(new); - - delete_vma_from_mm(vma); - down_write(&nommu_region_sem); - delete_nommu_region(vma->vm_region); - if (new_below) { - vma->vm_region->vm_start = vma->vm_start = addr; - vma->vm_region->vm_pgoff = vma->vm_pgoff += npages; - } else { - vma->vm_region->vm_end = vma->vm_end = addr; - vma->vm_region->vm_top = addr; - } - add_nommu_region(vma->vm_region); - add_nommu_region(new->vm_region); - up_write(&nommu_region_sem); - add_vma_to_mm(mm, vma); - add_vma_to_mm(mm, new); - return 0; -} - -/* - * shrink a VMA by removing the specified chunk from either the beginning or - * the end - */ -static int shrink_vma(struct mm_struct *mm, - struct vm_area_struct *vma, - unsigned long from, unsigned long to) -{ - struct vm_region *region; - - /* adjust the VMA's pointers, which may reposition it in the MM's tree - * and list */ - delete_vma_from_mm(vma); - if (from > vma->vm_start) - vma->vm_end = from; - else - vma->vm_start = to; - add_vma_to_mm(mm, vma); - - /* cut the backing region down to size */ - region = vma->vm_region; - BUG_ON(region->vm_usage != 1); - - down_write(&nommu_region_sem); - delete_nommu_region(region); - if (from > region->vm_start) { - to = region->vm_top; - region->vm_top = region->vm_end = from; - } else { - region->vm_start = to; - } - add_nommu_region(region); - up_write(&nommu_region_sem); - - free_page_series(from, to); - return 0; -} - -/* - * release a mapping - * - under NOMMU conditions the chunk to be unmapped must be backed by a single - * VMA, though it need not cover the whole VMA - */ -int do_munmap(struct mm_struct *mm, unsigned long start, size_t len) -{ - struct vm_area_struct *vma; - unsigned long end; - int ret; - - len = PAGE_ALIGN(len); - if (len == 0) - return -EINVAL; - - end = start + len; - - /* find the first potentially overlapping VMA */ - vma = find_vma(mm, start); - if (!vma) { - static int limit; - if (limit < 5) { - pr_warn("munmap of memory not mmapped by process %d (%s): 0x%lx-0x%lx\n", - current->pid, current->comm, - start, start + len - 1); - limit++; - } - return -EINVAL; - } - - /* we're allowed to split an anonymous VMA but not a file-backed one */ - if (vma->vm_file) { - do { - if (start > vma->vm_start) - return -EINVAL; - if (end == vma->vm_end) - goto erase_whole_vma; - vma = vma->vm_next; - } while (vma); - return -EINVAL; - } else { - /* the chunk must be a subset of the VMA found */ - if (start == vma->vm_start && end == vma->vm_end) - goto erase_whole_vma; - if (start < vma->vm_start || end > vma->vm_end) - return -EINVAL; - if (offset_in_page(start)) - return -EINVAL; - if (end != vma->vm_end && offset_in_page(end)) - return -EINVAL; - if (start != vma->vm_start && end != vma->vm_end) { - ret = split_vma(mm, vma, start, 1); - if (ret < 0) - return ret; - } - return shrink_vma(mm, vma, start, end); - } - -erase_whole_vma: - delete_vma_from_mm(vma); - delete_vma(mm, vma); - return 0; -} -EXPORT_SYMBOL(do_munmap); - -int vm_munmap(unsigned long addr, size_t len) -{ - struct mm_struct *mm = current->mm; - int ret; - - down_write(&mm->mmap_sem); - ret = do_munmap(mm, addr, len); - up_write(&mm->mmap_sem); - return ret; -} -EXPORT_SYMBOL(vm_munmap); - -SYSCALL_DEFINE2(munmap, unsigned long, addr, size_t, len) -{ - return vm_munmap(addr, len); -} - -/* - * release all the mappings made in a process's VM space - */ -void exit_mmap(struct mm_struct *mm) -{ - struct vm_area_struct *vma; - - if (!mm) - return; - - mm->total_vm = 0; - - while ((vma = mm->mmap)) { - mm->mmap = vma->vm_next; - delete_vma_from_mm(vma); - delete_vma(mm, vma); - cond_resched(); - } -} - -int vm_brk(unsigned long addr, unsigned long len) -{ - return -ENOMEM; -} - -/* - * expand (or shrink) an existing mapping, potentially moving it at the same - * time (controlled by the MREMAP_MAYMOVE flag and available VM space) - * - * under NOMMU conditions, we only permit changing a mapping's size, and only - * as long as it stays within the region allocated by do_mmap_private() and the - * block is not shareable - * - * MREMAP_FIXED is not supported under NOMMU conditions - */ -static unsigned long do_mremap(unsigned long addr, - unsigned long old_len, unsigned long new_len, - unsigned long flags, unsigned long new_addr) -{ - struct vm_area_struct *vma; - - /* insanity checks first */ - old_len = PAGE_ALIGN(old_len); - new_len = PAGE_ALIGN(new_len); - if (old_len == 0 || new_len == 0) - return (unsigned long) -EINVAL; - - if (offset_in_page(addr)) - return -EINVAL; - - if (flags & MREMAP_FIXED && new_addr != addr) - return (unsigned long) -EINVAL; - - vma = find_vma_exact(current->mm, addr, old_len); - if (!vma) - return (unsigned long) -EINVAL; - - if (vma->vm_end != vma->vm_start + old_len) - return (unsigned long) -EFAULT; - - if (vma->vm_flags & VM_MAYSHARE) - return (unsigned long) -EPERM; - - if (new_len > vma->vm_region->vm_end - vma->vm_region->vm_start) - return (unsigned long) -ENOMEM; - - /* all checks complete - do it */ - vma->vm_end = vma->vm_start + new_len; - return vma->vm_start; -} - -SYSCALL_DEFINE5(mremap, unsigned long, addr, unsigned long, old_len, - unsigned long, new_len, unsigned long, flags, - unsigned long, new_addr) -{ - unsigned long ret; - - down_write(¤t->mm->mmap_sem); - ret = do_mremap(addr, old_len, new_len, flags, new_addr); - up_write(¤t->mm->mmap_sem); - return ret; -} - -struct page *follow_page_mask(struct vm_area_struct *vma, - unsigned long address, unsigned int flags, - unsigned int *page_mask) -{ - *page_mask = 0; - return NULL; -} - -int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr, - unsigned long pfn, unsigned long size, pgprot_t prot) -{ - if (addr != (pfn << PAGE_SHIFT)) - return -EINVAL; - - vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP; - return 0; -} -EXPORT_SYMBOL(remap_pfn_range); - -int vm_iomap_memory(struct vm_area_struct *vma, phys_addr_t start, unsigned long len) -{ - unsigned long pfn = start >> PAGE_SHIFT; - unsigned long vm_len = vma->vm_end - vma->vm_start; - - pfn += vma->vm_pgoff; - return io_remap_pfn_range(vma, vma->vm_start, pfn, vm_len, vma->vm_page_prot); -} -EXPORT_SYMBOL(vm_iomap_memory); - -int remap_vmalloc_range(struct vm_area_struct *vma, void *addr, - unsigned long pgoff) -{ - unsigned int size = vma->vm_end - vma->vm_start; - - if (!(vma->vm_flags & VM_USERMAP)) - return -EINVAL; - - vma->vm_start = (unsigned long)(addr + (pgoff << PAGE_SHIFT)); - vma->vm_end = vma->vm_start + size; - - return 0; -} -EXPORT_SYMBOL(remap_vmalloc_range); - -unsigned long arch_get_unmapped_area(struct file *file, unsigned long addr, - unsigned long len, unsigned long pgoff, unsigned long flags) -{ - return -ENOMEM; -} - -void unmap_mapping_range(struct address_space *mapping, - loff_t const holebegin, loff_t const holelen, - int even_cows) -{ -} -EXPORT_SYMBOL(unmap_mapping_range); - -int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - BUG(); - return 0; -} -EXPORT_SYMBOL(filemap_fault); - -void filemap_map_pages(struct fault_env *fe, - pgoff_t start_pgoff, pgoff_t end_pgoff) -{ - BUG(); -} -EXPORT_SYMBOL(filemap_map_pages); - -static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm, - unsigned long addr, void *buf, int len, unsigned int gup_flags) -{ - struct vm_area_struct *vma; - int write = gup_flags & FOLL_WRITE; - - down_read(&mm->mmap_sem); - - /* the access must start within one of the target process's mappings */ - vma = find_vma(mm, addr); - if (vma) { - /* don't overrun this mapping */ - if (addr + len >= vma->vm_end) - len = vma->vm_end - addr; - - /* only read or write mappings where it is permitted */ - if (write && vma->vm_flags & VM_MAYWRITE) - copy_to_user_page(vma, NULL, addr, - (void *) addr, buf, len); - else if (!write && vma->vm_flags & VM_MAYREAD) - copy_from_user_page(vma, NULL, addr, - buf, (void *) addr, len); - else - len = 0; - } else { - len = 0; - } - - up_read(&mm->mmap_sem); - - return len; -} - -/** - * @access_remote_vm - access another process' address space - * @mm: the mm_struct of the target address space - * @addr: start address to access - * @buf: source or destination buffer - * @len: number of bytes to transfer - * @gup_flags: flags modifying lookup behaviour - * - * The caller must hold a reference on @mm. - */ -int access_remote_vm(struct mm_struct *mm, unsigned long addr, - void *buf, int len, unsigned int gup_flags) -{ - return __access_remote_vm(NULL, mm, addr, buf, len, gup_flags); -} - -/* - * Access another process' address space. - * - source/target buffer must be kernel space - */ -int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, int len, - unsigned int gup_flags) -{ - struct mm_struct *mm; - - if (addr + len < addr) - return 0; - - mm = get_task_mm(tsk); - if (!mm) - return 0; - - len = __access_remote_vm(tsk, mm, addr, buf, len, gup_flags); - - mmput(mm); - return len; -} - -/** - * nommu_shrink_inode_mappings - Shrink the shared mappings on an inode - * @inode: The inode to check - * @size: The current filesize of the inode - * @newsize: The proposed filesize of the inode - * - * Check the shared mappings on an inode on behalf of a shrinking truncate to - * make sure that that any outstanding VMAs aren't broken and then shrink the - * vm_regions that extend that beyond so that do_mmap_pgoff() doesn't - * automatically grant mappings that are too large. - */ -int nommu_shrink_inode_mappings(struct inode *inode, size_t size, - size_t newsize) -{ - struct vm_area_struct *vma; - struct vm_region *region; - pgoff_t low, high; - size_t r_size, r_top; - - low = newsize >> PAGE_SHIFT; - high = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - - down_write(&nommu_region_sem); - i_mmap_lock_read(inode->i_mapping); - - /* search for VMAs that fall within the dead zone */ - vma_interval_tree_foreach(vma, &inode->i_mapping->i_mmap, low, high) { - /* found one - only interested if it's shared out of the page - * cache */ - if (vma->vm_flags & VM_SHARED) { - i_mmap_unlock_read(inode->i_mapping); - up_write(&nommu_region_sem); - return -ETXTBSY; /* not quite true, but near enough */ - } - } - - /* reduce any regions that overlap the dead zone - if in existence, - * these will be pointed to by VMAs that don't overlap the dead zone - * - * we don't check for any regions that start beyond the EOF as there - * shouldn't be any - */ - vma_interval_tree_foreach(vma, &inode->i_mapping->i_mmap, 0, ULONG_MAX) { - if (!(vma->vm_flags & VM_SHARED)) - continue; - - region = vma->vm_region; - r_size = region->vm_top - region->vm_start; - r_top = (region->vm_pgoff << PAGE_SHIFT) + r_size; - - if (r_top > newsize) { - region->vm_top -= r_top - newsize; - if (region->vm_end > region->vm_top) - region->vm_end = region->vm_top; - } - } - - i_mmap_unlock_read(inode->i_mapping); - up_write(&nommu_region_sem); - return 0; -} - -/* - * Initialise sysctl_user_reserve_kbytes. - * - * This is intended to prevent a user from starting a single memory hogging - * process, such that they cannot recover (kill the hog) in OVERCOMMIT_NEVER - * mode. - * - * The default value is min(3% of free memory, 128MB) - * 128MB is enough to recover with sshd/login, bash, and top/kill. - */ -static int __meminit init_user_reserve(void) -{ - unsigned long free_kbytes; - - free_kbytes = global_page_state(NR_FREE_PAGES) << (PAGE_SHIFT - 10); - - sysctl_user_reserve_kbytes = min(free_kbytes / 32, 1UL << 17); - return 0; -} -subsys_initcall(init_user_reserve); - -/* - * Initialise sysctl_admin_reserve_kbytes. - * - * The purpose of sysctl_admin_reserve_kbytes is to allow the sys admin - * to log in and kill a memory hogging process. - * - * Systems with more than 256MB will reserve 8MB, enough to recover - * with sshd, bash, and top in OVERCOMMIT_GUESS. Smaller systems will - * only reserve 3% of free pages by default. - */ -static int __meminit init_admin_reserve(void) -{ - unsigned long free_kbytes; - - free_kbytes = global_page_state(NR_FREE_PAGES) << (PAGE_SHIFT - 10); - - sysctl_admin_reserve_kbytes = min(free_kbytes / 32, 1UL << 13); - return 0; -} -subsys_initcall(init_admin_reserve); diff --git a/src/linux/mm/oom_kill.c b/src/linux/mm/oom_kill.c deleted file mode 100644 index ec9f11d..0000000 --- a/src/linux/mm/oom_kill.c +++ /dev/null @@ -1,1077 +0,0 @@ -/* - * linux/mm/oom_kill.c - * - * Copyright (C) 1998,2000 Rik van Riel - * Thanks go out to Claus Fischer for some serious inspiration and - * for goading me into coding this file... - * Copyright (C) 2010 Google, Inc. - * Rewritten by David Rientjes - * - * The routines in this file are used to kill a process when - * we're seriously out of memory. This gets called from __alloc_pages() - * in mm/page_alloc.c when we really run out of memory. - * - * Since we won't call these routines often (on a well-configured - * machine) this file will double as a 'coding guide' and a signpost - * for newbie kernel hackers. It features several pointers to major - * kernel subsystems and hints as to where to find out what things do. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "internal.h" - -#define CREATE_TRACE_POINTS -#include - -int sysctl_panic_on_oom; -int sysctl_oom_kill_allocating_task; -int sysctl_oom_dump_tasks = 1; - -DEFINE_MUTEX(oom_lock); - -#ifdef CONFIG_NUMA -/** - * has_intersects_mems_allowed() - check task eligiblity for kill - * @start: task struct of which task to consider - * @mask: nodemask passed to page allocator for mempolicy ooms - * - * Task eligibility is determined by whether or not a candidate task, @tsk, - * shares the same mempolicy nodes as current if it is bound by such a policy - * and whether or not it has the same set of allowed cpuset nodes. - */ -static bool has_intersects_mems_allowed(struct task_struct *start, - const nodemask_t *mask) -{ - struct task_struct *tsk; - bool ret = false; - - rcu_read_lock(); - for_each_thread(start, tsk) { - if (mask) { - /* - * If this is a mempolicy constrained oom, tsk's - * cpuset is irrelevant. Only return true if its - * mempolicy intersects current, otherwise it may be - * needlessly killed. - */ - ret = mempolicy_nodemask_intersects(tsk, mask); - } else { - /* - * This is not a mempolicy constrained oom, so only - * check the mems of tsk's cpuset. - */ - ret = cpuset_mems_allowed_intersects(current, tsk); - } - if (ret) - break; - } - rcu_read_unlock(); - - return ret; -} -#else -static bool has_intersects_mems_allowed(struct task_struct *tsk, - const nodemask_t *mask) -{ - return true; -} -#endif /* CONFIG_NUMA */ - -/* - * The process p may have detached its own ->mm while exiting or through - * use_mm(), but one or more of its subthreads may still have a valid - * pointer. Return p, or any of its subthreads with a valid ->mm, with - * task_lock() held. - */ -struct task_struct *find_lock_task_mm(struct task_struct *p) -{ - struct task_struct *t; - - rcu_read_lock(); - - for_each_thread(p, t) { - task_lock(t); - if (likely(t->mm)) - goto found; - task_unlock(t); - } - t = NULL; -found: - rcu_read_unlock(); - - return t; -} - -/* - * order == -1 means the oom kill is required by sysrq, otherwise only - * for display purposes. - */ -static inline bool is_sysrq_oom(struct oom_control *oc) -{ - return oc->order == -1; -} - -static inline bool is_memcg_oom(struct oom_control *oc) -{ - return oc->memcg != NULL; -} - -/* return true if the task is not adequate as candidate victim task. */ -static bool oom_unkillable_task(struct task_struct *p, - struct mem_cgroup *memcg, const nodemask_t *nodemask) -{ - if (is_global_init(p)) - return true; - if (p->flags & PF_KTHREAD) - return true; - - /* When mem_cgroup_out_of_memory() and p is not member of the group */ - if (memcg && !task_in_mem_cgroup(p, memcg)) - return true; - - /* p may not have freeable memory in nodemask */ - if (!has_intersects_mems_allowed(p, nodemask)) - return true; - - return false; -} - -/** - * oom_badness - heuristic function to determine which candidate task to kill - * @p: task struct of which task we should calculate - * @totalpages: total present RAM allowed for page allocation - * - * The heuristic for determining which task to kill is made to be as simple and - * predictable as possible. The goal is to return the highest value for the - * task consuming the most memory to avoid subsequent oom failures. - */ -unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg, - const nodemask_t *nodemask, unsigned long totalpages) -{ - long points; - long adj; - - if (oom_unkillable_task(p, memcg, nodemask)) - return 0; - - p = find_lock_task_mm(p); - if (!p) - return 0; - - /* - * Do not even consider tasks which are explicitly marked oom - * unkillable or have been already oom reaped or the are in - * the middle of vfork - */ - adj = (long)p->signal->oom_score_adj; - if (adj == OOM_SCORE_ADJ_MIN || - test_bit(MMF_OOM_SKIP, &p->mm->flags) || - in_vfork(p)) { - task_unlock(p); - return 0; - } - - /* - * The baseline for the badness score is the proportion of RAM that each - * task's rss, pagetable and swap space use. - */ - points = get_mm_rss(p->mm) + get_mm_counter(p->mm, MM_SWAPENTS) + - atomic_long_read(&p->mm->nr_ptes) + mm_nr_pmds(p->mm); - task_unlock(p); - - /* - * Root processes get 3% bonus, just like the __vm_enough_memory() - * implementation used by LSMs. - */ - if (has_capability_noaudit(p, CAP_SYS_ADMIN)) - points -= (points * 3) / 100; - - /* Normalize to oom_score_adj units */ - adj *= totalpages / 1000; - points += adj; - - /* - * Never return 0 for an eligible task regardless of the root bonus and - * oom_score_adj (oom_score_adj can't be OOM_SCORE_ADJ_MIN here). - */ - return points > 0 ? points : 1; -} - -enum oom_constraint { - CONSTRAINT_NONE, - CONSTRAINT_CPUSET, - CONSTRAINT_MEMORY_POLICY, - CONSTRAINT_MEMCG, -}; - -/* - * Determine the type of allocation constraint. - */ -static enum oom_constraint constrained_alloc(struct oom_control *oc) -{ - struct zone *zone; - struct zoneref *z; - enum zone_type high_zoneidx = gfp_zone(oc->gfp_mask); - bool cpuset_limited = false; - int nid; - - if (is_memcg_oom(oc)) { - oc->totalpages = mem_cgroup_get_limit(oc->memcg) ?: 1; - return CONSTRAINT_MEMCG; - } - - /* Default to all available memory */ - oc->totalpages = totalram_pages + total_swap_pages; - - if (!IS_ENABLED(CONFIG_NUMA)) - return CONSTRAINT_NONE; - - if (!oc->zonelist) - return CONSTRAINT_NONE; - /* - * Reach here only when __GFP_NOFAIL is used. So, we should avoid - * to kill current.We have to random task kill in this case. - * Hopefully, CONSTRAINT_THISNODE...but no way to handle it, now. - */ - if (oc->gfp_mask & __GFP_THISNODE) - return CONSTRAINT_NONE; - - /* - * This is not a __GFP_THISNODE allocation, so a truncated nodemask in - * the page allocator means a mempolicy is in effect. Cpuset policy - * is enforced in get_page_from_freelist(). - */ - if (oc->nodemask && - !nodes_subset(node_states[N_MEMORY], *oc->nodemask)) { - oc->totalpages = total_swap_pages; - for_each_node_mask(nid, *oc->nodemask) - oc->totalpages += node_spanned_pages(nid); - return CONSTRAINT_MEMORY_POLICY; - } - - /* Check this allocation failure is caused by cpuset's wall function */ - for_each_zone_zonelist_nodemask(zone, z, oc->zonelist, - high_zoneidx, oc->nodemask) - if (!cpuset_zone_allowed(zone, oc->gfp_mask)) - cpuset_limited = true; - - if (cpuset_limited) { - oc->totalpages = total_swap_pages; - for_each_node_mask(nid, cpuset_current_mems_allowed) - oc->totalpages += node_spanned_pages(nid); - return CONSTRAINT_CPUSET; - } - return CONSTRAINT_NONE; -} - -static int oom_evaluate_task(struct task_struct *task, void *arg) -{ - struct oom_control *oc = arg; - unsigned long points; - - if (oom_unkillable_task(task, NULL, oc->nodemask)) - goto next; - - /* - * This task already has access to memory reserves and is being killed. - * Don't allow any other task to have access to the reserves unless - * the task has MMF_OOM_SKIP because chances that it would release - * any memory is quite low. - */ - if (!is_sysrq_oom(oc) && tsk_is_oom_victim(task)) { - if (test_bit(MMF_OOM_SKIP, &task->signal->oom_mm->flags)) - goto next; - goto abort; - } - - /* - * If task is allocating a lot of memory and has been marked to be - * killed first if it triggers an oom, then select it. - */ - if (oom_task_origin(task)) { - points = ULONG_MAX; - goto select; - } - - points = oom_badness(task, NULL, oc->nodemask, oc->totalpages); - if (!points || points < oc->chosen_points) - goto next; - - /* Prefer thread group leaders for display purposes */ - if (points == oc->chosen_points && thread_group_leader(oc->chosen)) - goto next; -select: - if (oc->chosen) - put_task_struct(oc->chosen); - get_task_struct(task); - oc->chosen = task; - oc->chosen_points = points; -next: - return 0; -abort: - if (oc->chosen) - put_task_struct(oc->chosen); - oc->chosen = (void *)-1UL; - return 1; -} - -/* - * Simple selection loop. We choose the process with the highest number of - * 'points'. In case scan was aborted, oc->chosen is set to -1. - */ -static void select_bad_process(struct oom_control *oc) -{ - if (is_memcg_oom(oc)) - mem_cgroup_scan_tasks(oc->memcg, oom_evaluate_task, oc); - else { - struct task_struct *p; - - rcu_read_lock(); - for_each_process(p) - if (oom_evaluate_task(p, oc)) - break; - rcu_read_unlock(); - } - - oc->chosen_points = oc->chosen_points * 1000 / oc->totalpages; -} - -/** - * dump_tasks - dump current memory state of all system tasks - * @memcg: current's memory controller, if constrained - * @nodemask: nodemask passed to page allocator for mempolicy ooms - * - * Dumps the current memory state of all eligible tasks. Tasks not in the same - * memcg, not in the same cpuset, or bound to a disjoint set of mempolicy nodes - * are not shown. - * State information includes task's pid, uid, tgid, vm size, rss, nr_ptes, - * swapents, oom_score_adj value, and name. - */ -static void dump_tasks(struct mem_cgroup *memcg, const nodemask_t *nodemask) -{ - struct task_struct *p; - struct task_struct *task; - - pr_info("[ pid ] uid tgid total_vm rss nr_ptes nr_pmds swapents oom_score_adj name\n"); - rcu_read_lock(); - for_each_process(p) { - if (oom_unkillable_task(p, memcg, nodemask)) - continue; - - task = find_lock_task_mm(p); - if (!task) { - /* - * This is a kthread or all of p's threads have already - * detached their mm's. There's no need to report - * them; they can't be oom killed anyway. - */ - continue; - } - - pr_info("[%5d] %5d %5d %8lu %8lu %7ld %7ld %8lu %5hd %s\n", - task->pid, from_kuid(&init_user_ns, task_uid(task)), - task->tgid, task->mm->total_vm, get_mm_rss(task->mm), - atomic_long_read(&task->mm->nr_ptes), - mm_nr_pmds(task->mm), - get_mm_counter(task->mm, MM_SWAPENTS), - task->signal->oom_score_adj, task->comm); - task_unlock(task); - } - rcu_read_unlock(); -} - -static void dump_header(struct oom_control *oc, struct task_struct *p) -{ - nodemask_t *nm = (oc->nodemask) ? oc->nodemask : &cpuset_current_mems_allowed; - - pr_warn("%s invoked oom-killer: gfp_mask=%#x(%pGg), nodemask=%*pbl, order=%d, oom_score_adj=%hd\n", - current->comm, oc->gfp_mask, &oc->gfp_mask, - nodemask_pr_args(nm), oc->order, - current->signal->oom_score_adj); - if (!IS_ENABLED(CONFIG_COMPACTION) && oc->order) - pr_warn("COMPACTION is disabled!!!\n"); - - cpuset_print_current_mems_allowed(); - dump_stack(); - if (oc->memcg) - mem_cgroup_print_oom_info(oc->memcg, p); - else - show_mem(SHOW_MEM_FILTER_NODES); - if (sysctl_oom_dump_tasks) - dump_tasks(oc->memcg, oc->nodemask); -} - -/* - * Number of OOM victims in flight - */ -static atomic_t oom_victims = ATOMIC_INIT(0); -static DECLARE_WAIT_QUEUE_HEAD(oom_victims_wait); - -static bool oom_killer_disabled __read_mostly; - -#define K(x) ((x) << (PAGE_SHIFT-10)) - -/* - * task->mm can be NULL if the task is the exited group leader. So to - * determine whether the task is using a particular mm, we examine all the - * task's threads: if one of those is using this mm then this task was also - * using it. - */ -bool process_shares_mm(struct task_struct *p, struct mm_struct *mm) -{ - struct task_struct *t; - - for_each_thread(p, t) { - struct mm_struct *t_mm = READ_ONCE(t->mm); - if (t_mm) - return t_mm == mm; - } - return false; -} - - -#ifdef CONFIG_MMU -/* - * OOM Reaper kernel thread which tries to reap the memory used by the OOM - * victim (if that is possible) to help the OOM killer to move on. - */ -static struct task_struct *oom_reaper_th; -static DECLARE_WAIT_QUEUE_HEAD(oom_reaper_wait); -static struct task_struct *oom_reaper_list; -static DEFINE_SPINLOCK(oom_reaper_lock); - -static bool __oom_reap_task_mm(struct task_struct *tsk, struct mm_struct *mm) -{ - struct mmu_gather tlb; - struct vm_area_struct *vma; - struct zap_details details = {.check_swap_entries = true, - .ignore_dirty = true}; - bool ret = true; - - /* - * We have to make sure to not race with the victim exit path - * and cause premature new oom victim selection: - * __oom_reap_task_mm exit_mm - * mmget_not_zero - * mmput - * atomic_dec_and_test - * exit_oom_victim - * [...] - * out_of_memory - * select_bad_process - * # no TIF_MEMDIE task selects new victim - * unmap_page_range # frees some memory - */ - mutex_lock(&oom_lock); - - if (!down_read_trylock(&mm->mmap_sem)) { - ret = false; - goto unlock_oom; - } - - /* - * increase mm_users only after we know we will reap something so - * that the mmput_async is called only when we have reaped something - * and delayed __mmput doesn't matter that much - */ - if (!mmget_not_zero(mm)) { - up_read(&mm->mmap_sem); - goto unlock_oom; - } - - /* - * Tell all users of get_user/copy_from_user etc... that the content - * is no longer stable. No barriers really needed because unmapping - * should imply barriers already and the reader would hit a page fault - * if it stumbled over a reaped memory. - */ - set_bit(MMF_UNSTABLE, &mm->flags); - - tlb_gather_mmu(&tlb, mm, 0, -1); - for (vma = mm->mmap ; vma; vma = vma->vm_next) { - if (is_vm_hugetlb_page(vma)) - continue; - - /* - * mlocked VMAs require explicit munlocking before unmap. - * Let's keep it simple here and skip such VMAs. - */ - if (vma->vm_flags & VM_LOCKED) - continue; - - /* - * Only anonymous pages have a good chance to be dropped - * without additional steps which we cannot afford as we - * are OOM already. - * - * We do not even care about fs backed pages because all - * which are reclaimable have already been reclaimed and - * we do not want to block exit_mmap by keeping mm ref - * count elevated without a good reason. - */ - if (vma_is_anonymous(vma) || !(vma->vm_flags & VM_SHARED)) - unmap_page_range(&tlb, vma, vma->vm_start, vma->vm_end, - &details); - } - tlb_finish_mmu(&tlb, 0, -1); - pr_info("oom_reaper: reaped process %d (%s), now anon-rss:%lukB, file-rss:%lukB, shmem-rss:%lukB\n", - task_pid_nr(tsk), tsk->comm, - K(get_mm_counter(mm, MM_ANONPAGES)), - K(get_mm_counter(mm, MM_FILEPAGES)), - K(get_mm_counter(mm, MM_SHMEMPAGES))); - up_read(&mm->mmap_sem); - - /* - * Drop our reference but make sure the mmput slow path is called from a - * different context because we shouldn't risk we get stuck there and - * put the oom_reaper out of the way. - */ - mmput_async(mm); -unlock_oom: - mutex_unlock(&oom_lock); - return ret; -} - -#define MAX_OOM_REAP_RETRIES 10 -static void oom_reap_task(struct task_struct *tsk) -{ - int attempts = 0; - struct mm_struct *mm = tsk->signal->oom_mm; - - /* Retry the down_read_trylock(mmap_sem) a few times */ - while (attempts++ < MAX_OOM_REAP_RETRIES && !__oom_reap_task_mm(tsk, mm)) - schedule_timeout_idle(HZ/10); - - if (attempts <= MAX_OOM_REAP_RETRIES) - goto done; - - - pr_info("oom_reaper: unable to reap pid:%d (%s)\n", - task_pid_nr(tsk), tsk->comm); - debug_show_all_locks(); - -done: - tsk->oom_reaper_list = NULL; - - /* - * Hide this mm from OOM killer because it has been either reaped or - * somebody can't call up_write(mmap_sem). - */ - set_bit(MMF_OOM_SKIP, &mm->flags); - - /* Drop a reference taken by wake_oom_reaper */ - put_task_struct(tsk); -} - -static int oom_reaper(void *unused) -{ - while (true) { - struct task_struct *tsk = NULL; - - wait_event_freezable(oom_reaper_wait, oom_reaper_list != NULL); - spin_lock(&oom_reaper_lock); - if (oom_reaper_list != NULL) { - tsk = oom_reaper_list; - oom_reaper_list = tsk->oom_reaper_list; - } - spin_unlock(&oom_reaper_lock); - - if (tsk) - oom_reap_task(tsk); - } - - return 0; -} - -static void wake_oom_reaper(struct task_struct *tsk) -{ - if (!oom_reaper_th) - return; - - /* tsk is already queued? */ - if (tsk == oom_reaper_list || tsk->oom_reaper_list) - return; - - get_task_struct(tsk); - - spin_lock(&oom_reaper_lock); - tsk->oom_reaper_list = oom_reaper_list; - oom_reaper_list = tsk; - spin_unlock(&oom_reaper_lock); - wake_up(&oom_reaper_wait); -} - -static int __init oom_init(void) -{ - oom_reaper_th = kthread_run(oom_reaper, NULL, "oom_reaper"); - if (IS_ERR(oom_reaper_th)) { - pr_err("Unable to start OOM reaper %ld. Continuing regardless\n", - PTR_ERR(oom_reaper_th)); - oom_reaper_th = NULL; - } - return 0; -} -subsys_initcall(oom_init) -#else -static inline void wake_oom_reaper(struct task_struct *tsk) -{ -} -#endif /* CONFIG_MMU */ - -/** - * mark_oom_victim - mark the given task as OOM victim - * @tsk: task to mark - * - * Has to be called with oom_lock held and never after - * oom has been disabled already. - * - * tsk->mm has to be non NULL and caller has to guarantee it is stable (either - * under task_lock or operate on the current). - */ -static void mark_oom_victim(struct task_struct *tsk) -{ - struct mm_struct *mm = tsk->mm; - - WARN_ON(oom_killer_disabled); - /* OOM killer might race with memcg OOM */ - if (test_and_set_tsk_thread_flag(tsk, TIF_MEMDIE)) - return; - - /* oom_mm is bound to the signal struct life time. */ - if (!cmpxchg(&tsk->signal->oom_mm, NULL, mm)) - atomic_inc(&tsk->signal->oom_mm->mm_count); - - /* - * Make sure that the task is woken up from uninterruptible sleep - * if it is frozen because OOM killer wouldn't be able to free - * any memory and livelock. freezing_slow_path will tell the freezer - * that TIF_MEMDIE tasks should be ignored. - */ - __thaw_task(tsk); - atomic_inc(&oom_victims); -} - -/** - * exit_oom_victim - note the exit of an OOM victim - */ -void exit_oom_victim(void) -{ - clear_thread_flag(TIF_MEMDIE); - - if (!atomic_dec_return(&oom_victims)) - wake_up_all(&oom_victims_wait); -} - -/** - * oom_killer_enable - enable OOM killer - */ -void oom_killer_enable(void) -{ - oom_killer_disabled = false; -} - -/** - * oom_killer_disable - disable OOM killer - * @timeout: maximum timeout to wait for oom victims in jiffies - * - * Forces all page allocations to fail rather than trigger OOM killer. - * Will block and wait until all OOM victims are killed or the given - * timeout expires. - * - * The function cannot be called when there are runnable user tasks because - * the userspace would see unexpected allocation failures as a result. Any - * new usage of this function should be consulted with MM people. - * - * Returns true if successful and false if the OOM killer cannot be - * disabled. - */ -bool oom_killer_disable(signed long timeout) -{ - signed long ret; - - /* - * Make sure to not race with an ongoing OOM killer. Check that the - * current is not killed (possibly due to sharing the victim's memory). - */ - if (mutex_lock_killable(&oom_lock)) - return false; - oom_killer_disabled = true; - mutex_unlock(&oom_lock); - - ret = wait_event_interruptible_timeout(oom_victims_wait, - !atomic_read(&oom_victims), timeout); - if (ret <= 0) { - oom_killer_enable(); - return false; - } - - return true; -} - -static inline bool __task_will_free_mem(struct task_struct *task) -{ - struct signal_struct *sig = task->signal; - - /* - * A coredumping process may sleep for an extended period in exit_mm(), - * so the oom killer cannot assume that the process will promptly exit - * and release memory. - */ - if (sig->flags & SIGNAL_GROUP_COREDUMP) - return false; - - if (sig->flags & SIGNAL_GROUP_EXIT) - return true; - - if (thread_group_empty(task) && (task->flags & PF_EXITING)) - return true; - - return false; -} - -/* - * Checks whether the given task is dying or exiting and likely to - * release its address space. This means that all threads and processes - * sharing the same mm have to be killed or exiting. - * Caller has to make sure that task->mm is stable (hold task_lock or - * it operates on the current). - */ -static bool task_will_free_mem(struct task_struct *task) -{ - struct mm_struct *mm = task->mm; - struct task_struct *p; - bool ret = true; - - /* - * Skip tasks without mm because it might have passed its exit_mm and - * exit_oom_victim. oom_reaper could have rescued that but do not rely - * on that for now. We can consider find_lock_task_mm in future. - */ - if (!mm) - return false; - - if (!__task_will_free_mem(task)) - return false; - - /* - * This task has already been drained by the oom reaper so there are - * only small chances it will free some more - */ - if (test_bit(MMF_OOM_SKIP, &mm->flags)) - return false; - - if (atomic_read(&mm->mm_users) <= 1) - return true; - - /* - * Make sure that all tasks which share the mm with the given tasks - * are dying as well to make sure that a) nobody pins its mm and - * b) the task is also reapable by the oom reaper. - */ - rcu_read_lock(); - for_each_process(p) { - if (!process_shares_mm(p, mm)) - continue; - if (same_thread_group(task, p)) - continue; - ret = __task_will_free_mem(p); - if (!ret) - break; - } - rcu_read_unlock(); - - return ret; -} - -static void oom_kill_process(struct oom_control *oc, const char *message) -{ - struct task_struct *p = oc->chosen; - unsigned int points = oc->chosen_points; - struct task_struct *victim = p; - struct task_struct *child; - struct task_struct *t; - struct mm_struct *mm; - unsigned int victim_points = 0; - static DEFINE_RATELIMIT_STATE(oom_rs, DEFAULT_RATELIMIT_INTERVAL, - DEFAULT_RATELIMIT_BURST); - bool can_oom_reap = true; - - /* - * If the task is already exiting, don't alarm the sysadmin or kill - * its children or threads, just set TIF_MEMDIE so it can die quickly - */ - task_lock(p); - if (task_will_free_mem(p)) { - mark_oom_victim(p); - wake_oom_reaper(p); - task_unlock(p); - put_task_struct(p); - return; - } - task_unlock(p); - - if (__ratelimit(&oom_rs)) - dump_header(oc, p); - - pr_err("%s: Kill process %d (%s) score %u or sacrifice child\n", - message, task_pid_nr(p), p->comm, points); - - /* - * If any of p's children has a different mm and is eligible for kill, - * the one with the highest oom_badness() score is sacrificed for its - * parent. This attempts to lose the minimal amount of work done while - * still freeing memory. - */ - read_lock(&tasklist_lock); - for_each_thread(p, t) { - list_for_each_entry(child, &t->children, sibling) { - unsigned int child_points; - - if (process_shares_mm(child, p->mm)) - continue; - /* - * oom_badness() returns 0 if the thread is unkillable - */ - child_points = oom_badness(child, - oc->memcg, oc->nodemask, oc->totalpages); - if (child_points > victim_points) { - put_task_struct(victim); - victim = child; - victim_points = child_points; - get_task_struct(victim); - } - } - } - read_unlock(&tasklist_lock); - - p = find_lock_task_mm(victim); - if (!p) { - put_task_struct(victim); - return; - } else if (victim != p) { - get_task_struct(p); - put_task_struct(victim); - victim = p; - } - - /* Get a reference to safely compare mm after task_unlock(victim) */ - mm = victim->mm; - atomic_inc(&mm->mm_count); - /* - * We should send SIGKILL before setting TIF_MEMDIE in order to prevent - * the OOM victim from depleting the memory reserves from the user - * space under its control. - */ - do_send_sig_info(SIGKILL, SEND_SIG_FORCED, victim, true); - mark_oom_victim(victim); - pr_err("Killed process %d (%s) total-vm:%lukB, anon-rss:%lukB, file-rss:%lukB, shmem-rss:%lukB\n", - task_pid_nr(victim), victim->comm, K(victim->mm->total_vm), - K(get_mm_counter(victim->mm, MM_ANONPAGES)), - K(get_mm_counter(victim->mm, MM_FILEPAGES)), - K(get_mm_counter(victim->mm, MM_SHMEMPAGES))); - task_unlock(victim); - - /* - * Kill all user processes sharing victim->mm in other thread groups, if - * any. They don't get access to memory reserves, though, to avoid - * depletion of all memory. This prevents mm->mmap_sem livelock when an - * oom killed thread cannot exit because it requires the semaphore and - * its contended by another thread trying to allocate memory itself. - * That thread will now get access to memory reserves since it has a - * pending fatal signal. - */ - rcu_read_lock(); - for_each_process(p) { - if (!process_shares_mm(p, mm)) - continue; - if (same_thread_group(p, victim)) - continue; - if (is_global_init(p)) { - can_oom_reap = false; - set_bit(MMF_OOM_SKIP, &mm->flags); - pr_info("oom killer %d (%s) has mm pinned by %d (%s)\n", - task_pid_nr(victim), victim->comm, - task_pid_nr(p), p->comm); - continue; - } - /* - * No use_mm() user needs to read from the userspace so we are - * ok to reap it. - */ - if (unlikely(p->flags & PF_KTHREAD)) - continue; - do_send_sig_info(SIGKILL, SEND_SIG_FORCED, p, true); - } - rcu_read_unlock(); - - if (can_oom_reap) - wake_oom_reaper(victim); - - mmdrop(mm); - put_task_struct(victim); -} -#undef K - -/* - * Determines whether the kernel must panic because of the panic_on_oom sysctl. - */ -static void check_panic_on_oom(struct oom_control *oc, - enum oom_constraint constraint) -{ - if (likely(!sysctl_panic_on_oom)) - return; - if (sysctl_panic_on_oom != 2) { - /* - * panic_on_oom == 1 only affects CONSTRAINT_NONE, the kernel - * does not panic for cpuset, mempolicy, or memcg allocation - * failures. - */ - if (constraint != CONSTRAINT_NONE) - return; - } - /* Do not panic for oom kills triggered by sysrq */ - if (is_sysrq_oom(oc)) - return; - dump_header(oc, NULL); - panic("Out of memory: %s panic_on_oom is enabled\n", - sysctl_panic_on_oom == 2 ? "compulsory" : "system-wide"); -} - -static BLOCKING_NOTIFIER_HEAD(oom_notify_list); - -int register_oom_notifier(struct notifier_block *nb) -{ - return blocking_notifier_chain_register(&oom_notify_list, nb); -} -EXPORT_SYMBOL_GPL(register_oom_notifier); - -int unregister_oom_notifier(struct notifier_block *nb) -{ - return blocking_notifier_chain_unregister(&oom_notify_list, nb); -} -EXPORT_SYMBOL_GPL(unregister_oom_notifier); - -/** - * out_of_memory - kill the "best" process when we run out of memory - * @oc: pointer to struct oom_control - * - * If we run out of memory, we have the choice between either - * killing a random task (bad), letting the system crash (worse) - * OR try to be smart about which process to kill. Note that we - * don't have to be perfect here, we just have to be good. - */ -bool out_of_memory(struct oom_control *oc) -{ - unsigned long freed = 0; - enum oom_constraint constraint = CONSTRAINT_NONE; - - if (oom_killer_disabled) - return false; - - if (!is_memcg_oom(oc)) { - blocking_notifier_call_chain(&oom_notify_list, 0, &freed); - if (freed > 0) - /* Got some memory back in the last second. */ - return true; - } - - /* - * If current has a pending SIGKILL or is exiting, then automatically - * select it. The goal is to allow it to allocate so that it may - * quickly exit and free its memory. - */ - if (task_will_free_mem(current)) { - mark_oom_victim(current); - wake_oom_reaper(current); - return true; - } - - /* - * The OOM killer does not compensate for IO-less reclaim. - * pagefault_out_of_memory lost its gfp context so we have to - * make sure exclude 0 mask - all other users should have at least - * ___GFP_DIRECT_RECLAIM to get here. - */ - if (oc->gfp_mask && !(oc->gfp_mask & (__GFP_FS|__GFP_NOFAIL))) - return true; - - /* - * Check if there were limitations on the allocation (only relevant for - * NUMA and memcg) that may require different handling. - */ - constraint = constrained_alloc(oc); - if (constraint != CONSTRAINT_MEMORY_POLICY) - oc->nodemask = NULL; - check_panic_on_oom(oc, constraint); - - if (!is_memcg_oom(oc) && sysctl_oom_kill_allocating_task && - current->mm && !oom_unkillable_task(current, NULL, oc->nodemask) && - current->signal->oom_score_adj != OOM_SCORE_ADJ_MIN) { - get_task_struct(current); - oc->chosen = current; - oom_kill_process(oc, "Out of memory (oom_kill_allocating_task)"); - return true; - } - - select_bad_process(oc); - /* Found nothing?!?! Either we hang forever, or we panic. */ - if (!oc->chosen && !is_sysrq_oom(oc) && !is_memcg_oom(oc)) { - dump_header(oc, NULL); - panic("Out of memory and no killable processes...\n"); - } - if (oc->chosen && oc->chosen != (void *)-1UL) { - oom_kill_process(oc, !is_memcg_oom(oc) ? "Out of memory" : - "Memory cgroup out of memory"); - /* - * Give the killed process a good chance to exit before trying - * to allocate memory again. - */ - schedule_timeout_killable(1); - } - return !!oc->chosen; -} - -/* - * The pagefault handler calls here because it is out of memory, so kill a - * memory-hogging task. If oom_lock is held by somebody else, a parallel oom - * killing is already in progress so do nothing. - */ -void pagefault_out_of_memory(void) -{ - struct oom_control oc = { - .zonelist = NULL, - .nodemask = NULL, - .memcg = NULL, - .gfp_mask = 0, - .order = 0, - }; - - if (mem_cgroup_oom_synchronize(true)) - return; - - if (!mutex_trylock(&oom_lock)) - return; - out_of_memory(&oc); - mutex_unlock(&oom_lock); -} diff --git a/src/linux/mm/page-writeback.c b/src/linux/mm/page-writeback.c deleted file mode 100644 index 439cc63..0000000 --- a/src/linux/mm/page-writeback.c +++ /dev/null @@ -1,2835 +0,0 @@ -/* - * mm/page-writeback.c - * - * Copyright (C) 2002, Linus Torvalds. - * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra - * - * Contains functions related to writing back dirty pages at the - * address_space level. - * - * 10Apr2002 Andrew Morton - * Initial version - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* __set_page_dirty_buffers */ -#include -#include -#include -#include -#include - -#include "internal.h" - -/* - * Sleep at most 200ms at a time in balance_dirty_pages(). - */ -#define MAX_PAUSE max(HZ/5, 1) - -/* - * Try to keep balance_dirty_pages() call intervals higher than this many pages - * by raising pause time to max_pause when falls below it. - */ -#define DIRTY_POLL_THRESH (128 >> (PAGE_SHIFT - 10)) - -/* - * Estimate write bandwidth at 200ms intervals. - */ -#define BANDWIDTH_INTERVAL max(HZ/5, 1) - -#define RATELIMIT_CALC_SHIFT 10 - -/* - * After a CPU has dirtied this many pages, balance_dirty_pages_ratelimited - * will look to see if it needs to force writeback or throttling. - */ -static long ratelimit_pages = 32; - -/* The following parameters are exported via /proc/sys/vm */ - -/* - * Start background writeback (via writeback threads) at this percentage - */ -int dirty_background_ratio = 10; - -/* - * dirty_background_bytes starts at 0 (disabled) so that it is a function of - * dirty_background_ratio * the amount of dirtyable memory - */ -unsigned long dirty_background_bytes; - -/* - * free highmem will not be subtracted from the total free memory - * for calculating free ratios if vm_highmem_is_dirtyable is true - */ -int vm_highmem_is_dirtyable; - -/* - * The generator of dirty data starts writeback at this percentage - */ -int vm_dirty_ratio = 20; - -/* - * vm_dirty_bytes starts at 0 (disabled) so that it is a function of - * vm_dirty_ratio * the amount of dirtyable memory - */ -unsigned long vm_dirty_bytes; - -/* - * The interval between `kupdate'-style writebacks - */ -unsigned int dirty_writeback_interval = 5 * 100; /* centiseconds */ - -EXPORT_SYMBOL_GPL(dirty_writeback_interval); - -/* - * The longest time for which data is allowed to remain dirty - */ -unsigned int dirty_expire_interval = 30 * 100; /* centiseconds */ - -/* - * Flag that makes the machine dump writes/reads and block dirtyings. - */ -int block_dump; - -/* - * Flag that puts the machine in "laptop mode". Doubles as a timeout in jiffies: - * a full sync is triggered after this time elapses without any disk activity. - */ -int laptop_mode; - -EXPORT_SYMBOL(laptop_mode); - -/* End of sysctl-exported parameters */ - -struct wb_domain global_wb_domain; - -/* consolidated parameters for balance_dirty_pages() and its subroutines */ -struct dirty_throttle_control { -#ifdef CONFIG_CGROUP_WRITEBACK - struct wb_domain *dom; - struct dirty_throttle_control *gdtc; /* only set in memcg dtc's */ -#endif - struct bdi_writeback *wb; - struct fprop_local_percpu *wb_completions; - - unsigned long avail; /* dirtyable */ - unsigned long dirty; /* file_dirty + write + nfs */ - unsigned long thresh; /* dirty threshold */ - unsigned long bg_thresh; /* dirty background threshold */ - - unsigned long wb_dirty; /* per-wb counterparts */ - unsigned long wb_thresh; - unsigned long wb_bg_thresh; - - unsigned long pos_ratio; -}; - -/* - * Length of period for aging writeout fractions of bdis. This is an - * arbitrarily chosen number. The longer the period, the slower fractions will - * reflect changes in current writeout rate. - */ -#define VM_COMPLETIONS_PERIOD_LEN (3*HZ) - -#ifdef CONFIG_CGROUP_WRITEBACK - -#define GDTC_INIT(__wb) .wb = (__wb), \ - .dom = &global_wb_domain, \ - .wb_completions = &(__wb)->completions - -#define GDTC_INIT_NO_WB .dom = &global_wb_domain - -#define MDTC_INIT(__wb, __gdtc) .wb = (__wb), \ - .dom = mem_cgroup_wb_domain(__wb), \ - .wb_completions = &(__wb)->memcg_completions, \ - .gdtc = __gdtc - -static bool mdtc_valid(struct dirty_throttle_control *dtc) -{ - return dtc->dom; -} - -static struct wb_domain *dtc_dom(struct dirty_throttle_control *dtc) -{ - return dtc->dom; -} - -static struct dirty_throttle_control *mdtc_gdtc(struct dirty_throttle_control *mdtc) -{ - return mdtc->gdtc; -} - -static struct fprop_local_percpu *wb_memcg_completions(struct bdi_writeback *wb) -{ - return &wb->memcg_completions; -} - -static void wb_min_max_ratio(struct bdi_writeback *wb, - unsigned long *minp, unsigned long *maxp) -{ - unsigned long this_bw = wb->avg_write_bandwidth; - unsigned long tot_bw = atomic_long_read(&wb->bdi->tot_write_bandwidth); - unsigned long long min = wb->bdi->min_ratio; - unsigned long long max = wb->bdi->max_ratio; - - /* - * @wb may already be clean by the time control reaches here and - * the total may not include its bw. - */ - if (this_bw < tot_bw) { - if (min) { - min *= this_bw; - do_div(min, tot_bw); - } - if (max < 100) { - max *= this_bw; - do_div(max, tot_bw); - } - } - - *minp = min; - *maxp = max; -} - -#else /* CONFIG_CGROUP_WRITEBACK */ - -#define GDTC_INIT(__wb) .wb = (__wb), \ - .wb_completions = &(__wb)->completions -#define GDTC_INIT_NO_WB -#define MDTC_INIT(__wb, __gdtc) - -static bool mdtc_valid(struct dirty_throttle_control *dtc) -{ - return false; -} - -static struct wb_domain *dtc_dom(struct dirty_throttle_control *dtc) -{ - return &global_wb_domain; -} - -static struct dirty_throttle_control *mdtc_gdtc(struct dirty_throttle_control *mdtc) -{ - return NULL; -} - -static struct fprop_local_percpu *wb_memcg_completions(struct bdi_writeback *wb) -{ - return NULL; -} - -static void wb_min_max_ratio(struct bdi_writeback *wb, - unsigned long *minp, unsigned long *maxp) -{ - *minp = wb->bdi->min_ratio; - *maxp = wb->bdi->max_ratio; -} - -#endif /* CONFIG_CGROUP_WRITEBACK */ - -/* - * In a memory zone, there is a certain amount of pages we consider - * available for the page cache, which is essentially the number of - * free and reclaimable pages, minus some zone reserves to protect - * lowmem and the ability to uphold the zone's watermarks without - * requiring writeback. - * - * This number of dirtyable pages is the base value of which the - * user-configurable dirty ratio is the effictive number of pages that - * are allowed to be actually dirtied. Per individual zone, or - * globally by using the sum of dirtyable pages over all zones. - * - * Because the user is allowed to specify the dirty limit globally as - * absolute number of bytes, calculating the per-zone dirty limit can - * require translating the configured limit into a percentage of - * global dirtyable memory first. - */ - -/** - * node_dirtyable_memory - number of dirtyable pages in a node - * @pgdat: the node - * - * Returns the node's number of pages potentially available for dirty - * page cache. This is the base value for the per-node dirty limits. - */ -static unsigned long node_dirtyable_memory(struct pglist_data *pgdat) -{ - unsigned long nr_pages = 0; - int z; - - for (z = 0; z < MAX_NR_ZONES; z++) { - struct zone *zone = pgdat->node_zones + z; - - if (!populated_zone(zone)) - continue; - - nr_pages += zone_page_state(zone, NR_FREE_PAGES); - } - - /* - * Pages reserved for the kernel should not be considered - * dirtyable, to prevent a situation where reclaim has to - * clean pages in order to balance the zones. - */ - nr_pages -= min(nr_pages, pgdat->totalreserve_pages); - - nr_pages += node_page_state(pgdat, NR_INACTIVE_FILE); - nr_pages += node_page_state(pgdat, NR_ACTIVE_FILE); - - return nr_pages; -} - -static unsigned long highmem_dirtyable_memory(unsigned long total) -{ -#ifdef CONFIG_HIGHMEM - int node; - unsigned long x = 0; - int i; - - for_each_node_state(node, N_HIGH_MEMORY) { - for (i = ZONE_NORMAL + 1; i < MAX_NR_ZONES; i++) { - struct zone *z; - unsigned long nr_pages; - - if (!is_highmem_idx(i)) - continue; - - z = &NODE_DATA(node)->node_zones[i]; - if (!populated_zone(z)) - continue; - - nr_pages = zone_page_state(z, NR_FREE_PAGES); - /* watch for underflows */ - nr_pages -= min(nr_pages, high_wmark_pages(z)); - nr_pages += zone_page_state(z, NR_ZONE_INACTIVE_FILE); - nr_pages += zone_page_state(z, NR_ZONE_ACTIVE_FILE); - x += nr_pages; - } - } - - /* - * Unreclaimable memory (kernel memory or anonymous memory - * without swap) can bring down the dirtyable pages below - * the zone's dirty balance reserve and the above calculation - * will underflow. However we still want to add in nodes - * which are below threshold (negative values) to get a more - * accurate calculation but make sure that the total never - * underflows. - */ - if ((long)x < 0) - x = 0; - - /* - * Make sure that the number of highmem pages is never larger - * than the number of the total dirtyable memory. This can only - * occur in very strange VM situations but we want to make sure - * that this does not occur. - */ - return min(x, total); -#else - return 0; -#endif -} - -/** - * global_dirtyable_memory - number of globally dirtyable pages - * - * Returns the global number of pages potentially available for dirty - * page cache. This is the base value for the global dirty limits. - */ -static unsigned long global_dirtyable_memory(void) -{ - unsigned long x; - - x = global_page_state(NR_FREE_PAGES); - /* - * Pages reserved for the kernel should not be considered - * dirtyable, to prevent a situation where reclaim has to - * clean pages in order to balance the zones. - */ - x -= min(x, totalreserve_pages); - - x += global_node_page_state(NR_INACTIVE_FILE); - x += global_node_page_state(NR_ACTIVE_FILE); - - if (!vm_highmem_is_dirtyable) - x -= highmem_dirtyable_memory(x); - - return x + 1; /* Ensure that we never return 0 */ -} - -/** - * domain_dirty_limits - calculate thresh and bg_thresh for a wb_domain - * @dtc: dirty_throttle_control of interest - * - * Calculate @dtc->thresh and ->bg_thresh considering - * vm_dirty_{bytes|ratio} and dirty_background_{bytes|ratio}. The caller - * must ensure that @dtc->avail is set before calling this function. The - * dirty limits will be lifted by 1/4 for PF_LESS_THROTTLE (ie. nfsd) and - * real-time tasks. - */ -static void domain_dirty_limits(struct dirty_throttle_control *dtc) -{ - const unsigned long available_memory = dtc->avail; - struct dirty_throttle_control *gdtc = mdtc_gdtc(dtc); - unsigned long bytes = vm_dirty_bytes; - unsigned long bg_bytes = dirty_background_bytes; - /* convert ratios to per-PAGE_SIZE for higher precision */ - unsigned long ratio = (vm_dirty_ratio * PAGE_SIZE) / 100; - unsigned long bg_ratio = (dirty_background_ratio * PAGE_SIZE) / 100; - unsigned long thresh; - unsigned long bg_thresh; - struct task_struct *tsk; - - /* gdtc is !NULL iff @dtc is for memcg domain */ - if (gdtc) { - unsigned long global_avail = gdtc->avail; - - /* - * The byte settings can't be applied directly to memcg - * domains. Convert them to ratios by scaling against - * globally available memory. As the ratios are in - * per-PAGE_SIZE, they can be obtained by dividing bytes by - * number of pages. - */ - if (bytes) - ratio = min(DIV_ROUND_UP(bytes, global_avail), - PAGE_SIZE); - if (bg_bytes) - bg_ratio = min(DIV_ROUND_UP(bg_bytes, global_avail), - PAGE_SIZE); - bytes = bg_bytes = 0; - } - - if (bytes) - thresh = DIV_ROUND_UP(bytes, PAGE_SIZE); - else - thresh = (ratio * available_memory) / PAGE_SIZE; - - if (bg_bytes) - bg_thresh = DIV_ROUND_UP(bg_bytes, PAGE_SIZE); - else - bg_thresh = (bg_ratio * available_memory) / PAGE_SIZE; - - if (bg_thresh >= thresh) - bg_thresh = thresh / 2; - tsk = current; - if (tsk->flags & PF_LESS_THROTTLE || rt_task(tsk)) { - bg_thresh += bg_thresh / 4 + global_wb_domain.dirty_limit / 32; - thresh += thresh / 4 + global_wb_domain.dirty_limit / 32; - } - dtc->thresh = thresh; - dtc->bg_thresh = bg_thresh; - - /* we should eventually report the domain in the TP */ - if (!gdtc) - trace_global_dirty_state(bg_thresh, thresh); -} - -/** - * global_dirty_limits - background-writeback and dirty-throttling thresholds - * @pbackground: out parameter for bg_thresh - * @pdirty: out parameter for thresh - * - * Calculate bg_thresh and thresh for global_wb_domain. See - * domain_dirty_limits() for details. - */ -void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty) -{ - struct dirty_throttle_control gdtc = { GDTC_INIT_NO_WB }; - - gdtc.avail = global_dirtyable_memory(); - domain_dirty_limits(&gdtc); - - *pbackground = gdtc.bg_thresh; - *pdirty = gdtc.thresh; -} - -/** - * node_dirty_limit - maximum number of dirty pages allowed in a node - * @pgdat: the node - * - * Returns the maximum number of dirty pages allowed in a node, based - * on the node's dirtyable memory. - */ -static unsigned long node_dirty_limit(struct pglist_data *pgdat) -{ - unsigned long node_memory = node_dirtyable_memory(pgdat); - struct task_struct *tsk = current; - unsigned long dirty; - - if (vm_dirty_bytes) - dirty = DIV_ROUND_UP(vm_dirty_bytes, PAGE_SIZE) * - node_memory / global_dirtyable_memory(); - else - dirty = vm_dirty_ratio * node_memory / 100; - - if (tsk->flags & PF_LESS_THROTTLE || rt_task(tsk)) - dirty += dirty / 4; - - return dirty; -} - -/** - * node_dirty_ok - tells whether a node is within its dirty limits - * @pgdat: the node to check - * - * Returns %true when the dirty pages in @pgdat are within the node's - * dirty limit, %false if the limit is exceeded. - */ -bool node_dirty_ok(struct pglist_data *pgdat) -{ - unsigned long limit = node_dirty_limit(pgdat); - unsigned long nr_pages = 0; - - nr_pages += node_page_state(pgdat, NR_FILE_DIRTY); - nr_pages += node_page_state(pgdat, NR_UNSTABLE_NFS); - nr_pages += node_page_state(pgdat, NR_WRITEBACK); - - return nr_pages <= limit; -} - -int dirty_background_ratio_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - int ret; - - ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); - if (ret == 0 && write) - dirty_background_bytes = 0; - return ret; -} - -int dirty_background_bytes_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - int ret; - - ret = proc_doulongvec_minmax(table, write, buffer, lenp, ppos); - if (ret == 0 && write) - dirty_background_ratio = 0; - return ret; -} - -int dirty_ratio_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - int old_ratio = vm_dirty_ratio; - int ret; - - ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos); - if (ret == 0 && write && vm_dirty_ratio != old_ratio) { - writeback_set_ratelimit(); - vm_dirty_bytes = 0; - } - return ret; -} - -int dirty_bytes_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - unsigned long old_bytes = vm_dirty_bytes; - int ret; - - ret = proc_doulongvec_minmax(table, write, buffer, lenp, ppos); - if (ret == 0 && write && vm_dirty_bytes != old_bytes) { - writeback_set_ratelimit(); - vm_dirty_ratio = 0; - } - return ret; -} - -static unsigned long wp_next_time(unsigned long cur_time) -{ - cur_time += VM_COMPLETIONS_PERIOD_LEN; - /* 0 has a special meaning... */ - if (!cur_time) - return 1; - return cur_time; -} - -static void wb_domain_writeout_inc(struct wb_domain *dom, - struct fprop_local_percpu *completions, - unsigned int max_prop_frac) -{ - __fprop_inc_percpu_max(&dom->completions, completions, - max_prop_frac); - /* First event after period switching was turned off? */ - if (!unlikely(dom->period_time)) { - /* - * We can race with other __bdi_writeout_inc calls here but - * it does not cause any harm since the resulting time when - * timer will fire and what is in writeout_period_time will be - * roughly the same. - */ - dom->period_time = wp_next_time(jiffies); - mod_timer(&dom->period_timer, dom->period_time); - } -} - -/* - * Increment @wb's writeout completion count and the global writeout - * completion count. Called from test_clear_page_writeback(). - */ -static inline void __wb_writeout_inc(struct bdi_writeback *wb) -{ - struct wb_domain *cgdom; - - __inc_wb_stat(wb, WB_WRITTEN); - wb_domain_writeout_inc(&global_wb_domain, &wb->completions, - wb->bdi->max_prop_frac); - - cgdom = mem_cgroup_wb_domain(wb); - if (cgdom) - wb_domain_writeout_inc(cgdom, wb_memcg_completions(wb), - wb->bdi->max_prop_frac); -} - -void wb_writeout_inc(struct bdi_writeback *wb) -{ - unsigned long flags; - - local_irq_save(flags); - __wb_writeout_inc(wb); - local_irq_restore(flags); -} -EXPORT_SYMBOL_GPL(wb_writeout_inc); - -/* - * On idle system, we can be called long after we scheduled because we use - * deferred timers so count with missed periods. - */ -static void writeout_period(unsigned long t) -{ - struct wb_domain *dom = (void *)t; - int miss_periods = (jiffies - dom->period_time) / - VM_COMPLETIONS_PERIOD_LEN; - - if (fprop_new_period(&dom->completions, miss_periods + 1)) { - dom->period_time = wp_next_time(dom->period_time + - miss_periods * VM_COMPLETIONS_PERIOD_LEN); - mod_timer(&dom->period_timer, dom->period_time); - } else { - /* - * Aging has zeroed all fractions. Stop wasting CPU on period - * updates. - */ - dom->period_time = 0; - } -} - -int wb_domain_init(struct wb_domain *dom, gfp_t gfp) -{ - memset(dom, 0, sizeof(*dom)); - - spin_lock_init(&dom->lock); - - init_timer_deferrable(&dom->period_timer); - dom->period_timer.function = writeout_period; - dom->period_timer.data = (unsigned long)dom; - - dom->dirty_limit_tstamp = jiffies; - - return fprop_global_init(&dom->completions, gfp); -} - -#ifdef CONFIG_CGROUP_WRITEBACK -void wb_domain_exit(struct wb_domain *dom) -{ - del_timer_sync(&dom->period_timer); - fprop_global_destroy(&dom->completions); -} -#endif - -/* - * bdi_min_ratio keeps the sum of the minimum dirty shares of all - * registered backing devices, which, for obvious reasons, can not - * exceed 100%. - */ -static unsigned int bdi_min_ratio; - -int bdi_set_min_ratio(struct backing_dev_info *bdi, unsigned int min_ratio) -{ - int ret = 0; - - spin_lock_bh(&bdi_lock); - if (min_ratio > bdi->max_ratio) { - ret = -EINVAL; - } else { - min_ratio -= bdi->min_ratio; - if (bdi_min_ratio + min_ratio < 100) { - bdi_min_ratio += min_ratio; - bdi->min_ratio += min_ratio; - } else { - ret = -EINVAL; - } - } - spin_unlock_bh(&bdi_lock); - - return ret; -} - -int bdi_set_max_ratio(struct backing_dev_info *bdi, unsigned max_ratio) -{ - int ret = 0; - - if (max_ratio > 100) - return -EINVAL; - - spin_lock_bh(&bdi_lock); - if (bdi->min_ratio > max_ratio) { - ret = -EINVAL; - } else { - bdi->max_ratio = max_ratio; - bdi->max_prop_frac = (FPROP_FRAC_BASE * max_ratio) / 100; - } - spin_unlock_bh(&bdi_lock); - - return ret; -} -EXPORT_SYMBOL(bdi_set_max_ratio); - -static unsigned long dirty_freerun_ceiling(unsigned long thresh, - unsigned long bg_thresh) -{ - return (thresh + bg_thresh) / 2; -} - -static unsigned long hard_dirty_limit(struct wb_domain *dom, - unsigned long thresh) -{ - return max(thresh, dom->dirty_limit); -} - -/* - * Memory which can be further allocated to a memcg domain is capped by - * system-wide clean memory excluding the amount being used in the domain. - */ -static void mdtc_calc_avail(struct dirty_throttle_control *mdtc, - unsigned long filepages, unsigned long headroom) -{ - struct dirty_throttle_control *gdtc = mdtc_gdtc(mdtc); - unsigned long clean = filepages - min(filepages, mdtc->dirty); - unsigned long global_clean = gdtc->avail - min(gdtc->avail, gdtc->dirty); - unsigned long other_clean = global_clean - min(global_clean, clean); - - mdtc->avail = filepages + min(headroom, other_clean); -} - -/** - * __wb_calc_thresh - @wb's share of dirty throttling threshold - * @dtc: dirty_throttle_context of interest - * - * Returns @wb's dirty limit in pages. The term "dirty" in the context of - * dirty balancing includes all PG_dirty, PG_writeback and NFS unstable pages. - * - * Note that balance_dirty_pages() will only seriously take it as a hard limit - * when sleeping max_pause per page is not enough to keep the dirty pages under - * control. For example, when the device is completely stalled due to some error - * conditions, or when there are 1000 dd tasks writing to a slow 10MB/s USB key. - * In the other normal situations, it acts more gently by throttling the tasks - * more (rather than completely block them) when the wb dirty pages go high. - * - * It allocates high/low dirty limits to fast/slow devices, in order to prevent - * - starving fast devices - * - piling up dirty pages (that will take long time to sync) on slow devices - * - * The wb's share of dirty limit will be adapting to its throughput and - * bounded by the bdi->min_ratio and/or bdi->max_ratio parameters, if set. - */ -static unsigned long __wb_calc_thresh(struct dirty_throttle_control *dtc) -{ - struct wb_domain *dom = dtc_dom(dtc); - unsigned long thresh = dtc->thresh; - u64 wb_thresh; - long numerator, denominator; - unsigned long wb_min_ratio, wb_max_ratio; - - /* - * Calculate this BDI's share of the thresh ratio. - */ - fprop_fraction_percpu(&dom->completions, dtc->wb_completions, - &numerator, &denominator); - - wb_thresh = (thresh * (100 - bdi_min_ratio)) / 100; - wb_thresh *= numerator; - do_div(wb_thresh, denominator); - - wb_min_max_ratio(dtc->wb, &wb_min_ratio, &wb_max_ratio); - - wb_thresh += (thresh * wb_min_ratio) / 100; - if (wb_thresh > (thresh * wb_max_ratio) / 100) - wb_thresh = thresh * wb_max_ratio / 100; - - return wb_thresh; -} - -unsigned long wb_calc_thresh(struct bdi_writeback *wb, unsigned long thresh) -{ - struct dirty_throttle_control gdtc = { GDTC_INIT(wb), - .thresh = thresh }; - return __wb_calc_thresh(&gdtc); -} - -/* - * setpoint - dirty 3 - * f(dirty) := 1.0 + (----------------) - * limit - setpoint - * - * it's a 3rd order polynomial that subjects to - * - * (1) f(freerun) = 2.0 => rampup dirty_ratelimit reasonably fast - * (2) f(setpoint) = 1.0 => the balance point - * (3) f(limit) = 0 => the hard limit - * (4) df/dx <= 0 => negative feedback control - * (5) the closer to setpoint, the smaller |df/dx| (and the reverse) - * => fast response on large errors; small oscillation near setpoint - */ -static long long pos_ratio_polynom(unsigned long setpoint, - unsigned long dirty, - unsigned long limit) -{ - long long pos_ratio; - long x; - - x = div64_s64(((s64)setpoint - (s64)dirty) << RATELIMIT_CALC_SHIFT, - (limit - setpoint) | 1); - pos_ratio = x; - pos_ratio = pos_ratio * x >> RATELIMIT_CALC_SHIFT; - pos_ratio = pos_ratio * x >> RATELIMIT_CALC_SHIFT; - pos_ratio += 1 << RATELIMIT_CALC_SHIFT; - - return clamp(pos_ratio, 0LL, 2LL << RATELIMIT_CALC_SHIFT); -} - -/* - * Dirty position control. - * - * (o) global/bdi setpoints - * - * We want the dirty pages be balanced around the global/wb setpoints. - * When the number of dirty pages is higher/lower than the setpoint, the - * dirty position control ratio (and hence task dirty ratelimit) will be - * decreased/increased to bring the dirty pages back to the setpoint. - * - * pos_ratio = 1 << RATELIMIT_CALC_SHIFT - * - * if (dirty < setpoint) scale up pos_ratio - * if (dirty > setpoint) scale down pos_ratio - * - * if (wb_dirty < wb_setpoint) scale up pos_ratio - * if (wb_dirty > wb_setpoint) scale down pos_ratio - * - * task_ratelimit = dirty_ratelimit * pos_ratio >> RATELIMIT_CALC_SHIFT - * - * (o) global control line - * - * ^ pos_ratio - * | - * | |<===== global dirty control scope ======>| - * 2.0 .............* - * | .* - * | . * - * | . * - * | . * - * | . * - * | . * - * 1.0 ................................* - * | . . * - * | . . * - * | . . * - * | . . * - * | . . * - * 0 +------------.------------------.----------------------*-------------> - * freerun^ setpoint^ limit^ dirty pages - * - * (o) wb control line - * - * ^ pos_ratio - * | - * | * - * | * - * | * - * | * - * | * |<=========== span ============>| - * 1.0 .......................* - * | . * - * | . * - * | . * - * | . * - * | . * - * | . * - * | . * - * | . * - * | . * - * | . * - * | . * - * 1/4 ...............................................* * * * * * * * * * * * - * | . . - * | . . - * | . . - * 0 +----------------------.-------------------------------.-------------> - * wb_setpoint^ x_intercept^ - * - * The wb control line won't drop below pos_ratio=1/4, so that wb_dirty can - * be smoothly throttled down to normal if it starts high in situations like - * - start writing to a slow SD card and a fast disk at the same time. The SD - * card's wb_dirty may rush to many times higher than wb_setpoint. - * - the wb dirty thresh drops quickly due to change of JBOD workload - */ -static void wb_position_ratio(struct dirty_throttle_control *dtc) -{ - struct bdi_writeback *wb = dtc->wb; - unsigned long write_bw = wb->avg_write_bandwidth; - unsigned long freerun = dirty_freerun_ceiling(dtc->thresh, dtc->bg_thresh); - unsigned long limit = hard_dirty_limit(dtc_dom(dtc), dtc->thresh); - unsigned long wb_thresh = dtc->wb_thresh; - unsigned long x_intercept; - unsigned long setpoint; /* dirty pages' target balance point */ - unsigned long wb_setpoint; - unsigned long span; - long long pos_ratio; /* for scaling up/down the rate limit */ - long x; - - dtc->pos_ratio = 0; - - if (unlikely(dtc->dirty >= limit)) - return; - - /* - * global setpoint - * - * See comment for pos_ratio_polynom(). - */ - setpoint = (freerun + limit) / 2; - pos_ratio = pos_ratio_polynom(setpoint, dtc->dirty, limit); - - /* - * The strictlimit feature is a tool preventing mistrusted filesystems - * from growing a large number of dirty pages before throttling. For - * such filesystems balance_dirty_pages always checks wb counters - * against wb limits. Even if global "nr_dirty" is under "freerun". - * This is especially important for fuse which sets bdi->max_ratio to - * 1% by default. Without strictlimit feature, fuse writeback may - * consume arbitrary amount of RAM because it is accounted in - * NR_WRITEBACK_TEMP which is not involved in calculating "nr_dirty". - * - * Here, in wb_position_ratio(), we calculate pos_ratio based on - * two values: wb_dirty and wb_thresh. Let's consider an example: - * total amount of RAM is 16GB, bdi->max_ratio is equal to 1%, global - * limits are set by default to 10% and 20% (background and throttle). - * Then wb_thresh is 1% of 20% of 16GB. This amounts to ~8K pages. - * wb_calc_thresh(wb, bg_thresh) is about ~4K pages. wb_setpoint is - * about ~6K pages (as the average of background and throttle wb - * limits). The 3rd order polynomial will provide positive feedback if - * wb_dirty is under wb_setpoint and vice versa. - * - * Note, that we cannot use global counters in these calculations - * because we want to throttle process writing to a strictlimit wb - * much earlier than global "freerun" is reached (~23MB vs. ~2.3GB - * in the example above). - */ - if (unlikely(wb->bdi->capabilities & BDI_CAP_STRICTLIMIT)) { - long long wb_pos_ratio; - - if (dtc->wb_dirty < 8) { - dtc->pos_ratio = min_t(long long, pos_ratio * 2, - 2 << RATELIMIT_CALC_SHIFT); - return; - } - - if (dtc->wb_dirty >= wb_thresh) - return; - - wb_setpoint = dirty_freerun_ceiling(wb_thresh, - dtc->wb_bg_thresh); - - if (wb_setpoint == 0 || wb_setpoint == wb_thresh) - return; - - wb_pos_ratio = pos_ratio_polynom(wb_setpoint, dtc->wb_dirty, - wb_thresh); - - /* - * Typically, for strictlimit case, wb_setpoint << setpoint - * and pos_ratio >> wb_pos_ratio. In the other words global - * state ("dirty") is not limiting factor and we have to - * make decision based on wb counters. But there is an - * important case when global pos_ratio should get precedence: - * global limits are exceeded (e.g. due to activities on other - * wb's) while given strictlimit wb is below limit. - * - * "pos_ratio * wb_pos_ratio" would work for the case above, - * but it would look too non-natural for the case of all - * activity in the system coming from a single strictlimit wb - * with bdi->max_ratio == 100%. - * - * Note that min() below somewhat changes the dynamics of the - * control system. Normally, pos_ratio value can be well over 3 - * (when globally we are at freerun and wb is well below wb - * setpoint). Now the maximum pos_ratio in the same situation - * is 2. We might want to tweak this if we observe the control - * system is too slow to adapt. - */ - dtc->pos_ratio = min(pos_ratio, wb_pos_ratio); - return; - } - - /* - * We have computed basic pos_ratio above based on global situation. If - * the wb is over/under its share of dirty pages, we want to scale - * pos_ratio further down/up. That is done by the following mechanism. - */ - - /* - * wb setpoint - * - * f(wb_dirty) := 1.0 + k * (wb_dirty - wb_setpoint) - * - * x_intercept - wb_dirty - * := -------------------------- - * x_intercept - wb_setpoint - * - * The main wb control line is a linear function that subjects to - * - * (1) f(wb_setpoint) = 1.0 - * (2) k = - 1 / (8 * write_bw) (in single wb case) - * or equally: x_intercept = wb_setpoint + 8 * write_bw - * - * For single wb case, the dirty pages are observed to fluctuate - * regularly within range - * [wb_setpoint - write_bw/2, wb_setpoint + write_bw/2] - * for various filesystems, where (2) can yield in a reasonable 12.5% - * fluctuation range for pos_ratio. - * - * For JBOD case, wb_thresh (not wb_dirty!) could fluctuate up to its - * own size, so move the slope over accordingly and choose a slope that - * yields 100% pos_ratio fluctuation on suddenly doubled wb_thresh. - */ - if (unlikely(wb_thresh > dtc->thresh)) - wb_thresh = dtc->thresh; - /* - * It's very possible that wb_thresh is close to 0 not because the - * device is slow, but that it has remained inactive for long time. - * Honour such devices a reasonable good (hopefully IO efficient) - * threshold, so that the occasional writes won't be blocked and active - * writes can rampup the threshold quickly. - */ - wb_thresh = max(wb_thresh, (limit - dtc->dirty) / 8); - /* - * scale global setpoint to wb's: - * wb_setpoint = setpoint * wb_thresh / thresh - */ - x = div_u64((u64)wb_thresh << 16, dtc->thresh | 1); - wb_setpoint = setpoint * (u64)x >> 16; - /* - * Use span=(8*write_bw) in single wb case as indicated by - * (thresh - wb_thresh ~= 0) and transit to wb_thresh in JBOD case. - * - * wb_thresh thresh - wb_thresh - * span = --------- * (8 * write_bw) + ------------------ * wb_thresh - * thresh thresh - */ - span = (dtc->thresh - wb_thresh + 8 * write_bw) * (u64)x >> 16; - x_intercept = wb_setpoint + span; - - if (dtc->wb_dirty < x_intercept - span / 4) { - pos_ratio = div64_u64(pos_ratio * (x_intercept - dtc->wb_dirty), - (x_intercept - wb_setpoint) | 1); - } else - pos_ratio /= 4; - - /* - * wb reserve area, safeguard against dirty pool underrun and disk idle - * It may push the desired control point of global dirty pages higher - * than setpoint. - */ - x_intercept = wb_thresh / 2; - if (dtc->wb_dirty < x_intercept) { - if (dtc->wb_dirty > x_intercept / 8) - pos_ratio = div_u64(pos_ratio * x_intercept, - dtc->wb_dirty); - else - pos_ratio *= 8; - } - - dtc->pos_ratio = pos_ratio; -} - -static void wb_update_write_bandwidth(struct bdi_writeback *wb, - unsigned long elapsed, - unsigned long written) -{ - const unsigned long period = roundup_pow_of_two(3 * HZ); - unsigned long avg = wb->avg_write_bandwidth; - unsigned long old = wb->write_bandwidth; - u64 bw; - - /* - * bw = written * HZ / elapsed - * - * bw * elapsed + write_bandwidth * (period - elapsed) - * write_bandwidth = --------------------------------------------------- - * period - * - * @written may have decreased due to account_page_redirty(). - * Avoid underflowing @bw calculation. - */ - bw = written - min(written, wb->written_stamp); - bw *= HZ; - if (unlikely(elapsed > period)) { - do_div(bw, elapsed); - avg = bw; - goto out; - } - bw += (u64)wb->write_bandwidth * (period - elapsed); - bw >>= ilog2(period); - - /* - * one more level of smoothing, for filtering out sudden spikes - */ - if (avg > old && old >= (unsigned long)bw) - avg -= (avg - old) >> 3; - - if (avg < old && old <= (unsigned long)bw) - avg += (old - avg) >> 3; - -out: - /* keep avg > 0 to guarantee that tot > 0 if there are dirty wbs */ - avg = max(avg, 1LU); - if (wb_has_dirty_io(wb)) { - long delta = avg - wb->avg_write_bandwidth; - WARN_ON_ONCE(atomic_long_add_return(delta, - &wb->bdi->tot_write_bandwidth) <= 0); - } - wb->write_bandwidth = bw; - wb->avg_write_bandwidth = avg; -} - -static void update_dirty_limit(struct dirty_throttle_control *dtc) -{ - struct wb_domain *dom = dtc_dom(dtc); - unsigned long thresh = dtc->thresh; - unsigned long limit = dom->dirty_limit; - - /* - * Follow up in one step. - */ - if (limit < thresh) { - limit = thresh; - goto update; - } - - /* - * Follow down slowly. Use the higher one as the target, because thresh - * may drop below dirty. This is exactly the reason to introduce - * dom->dirty_limit which is guaranteed to lie above the dirty pages. - */ - thresh = max(thresh, dtc->dirty); - if (limit > thresh) { - limit -= (limit - thresh) >> 5; - goto update; - } - return; -update: - dom->dirty_limit = limit; -} - -static void domain_update_bandwidth(struct dirty_throttle_control *dtc, - unsigned long now) -{ - struct wb_domain *dom = dtc_dom(dtc); - - /* - * check locklessly first to optimize away locking for the most time - */ - if (time_before(now, dom->dirty_limit_tstamp + BANDWIDTH_INTERVAL)) - return; - - spin_lock(&dom->lock); - if (time_after_eq(now, dom->dirty_limit_tstamp + BANDWIDTH_INTERVAL)) { - update_dirty_limit(dtc); - dom->dirty_limit_tstamp = now; - } - spin_unlock(&dom->lock); -} - -/* - * Maintain wb->dirty_ratelimit, the base dirty throttle rate. - * - * Normal wb tasks will be curbed at or below it in long term. - * Obviously it should be around (write_bw / N) when there are N dd tasks. - */ -static void wb_update_dirty_ratelimit(struct dirty_throttle_control *dtc, - unsigned long dirtied, - unsigned long elapsed) -{ - struct bdi_writeback *wb = dtc->wb; - unsigned long dirty = dtc->dirty; - unsigned long freerun = dirty_freerun_ceiling(dtc->thresh, dtc->bg_thresh); - unsigned long limit = hard_dirty_limit(dtc_dom(dtc), dtc->thresh); - unsigned long setpoint = (freerun + limit) / 2; - unsigned long write_bw = wb->avg_write_bandwidth; - unsigned long dirty_ratelimit = wb->dirty_ratelimit; - unsigned long dirty_rate; - unsigned long task_ratelimit; - unsigned long balanced_dirty_ratelimit; - unsigned long step; - unsigned long x; - unsigned long shift; - - /* - * The dirty rate will match the writeout rate in long term, except - * when dirty pages are truncated by userspace or re-dirtied by FS. - */ - dirty_rate = (dirtied - wb->dirtied_stamp) * HZ / elapsed; - - /* - * task_ratelimit reflects each dd's dirty rate for the past 200ms. - */ - task_ratelimit = (u64)dirty_ratelimit * - dtc->pos_ratio >> RATELIMIT_CALC_SHIFT; - task_ratelimit++; /* it helps rampup dirty_ratelimit from tiny values */ - - /* - * A linear estimation of the "balanced" throttle rate. The theory is, - * if there are N dd tasks, each throttled at task_ratelimit, the wb's - * dirty_rate will be measured to be (N * task_ratelimit). So the below - * formula will yield the balanced rate limit (write_bw / N). - * - * Note that the expanded form is not a pure rate feedback: - * rate_(i+1) = rate_(i) * (write_bw / dirty_rate) (1) - * but also takes pos_ratio into account: - * rate_(i+1) = rate_(i) * (write_bw / dirty_rate) * pos_ratio (2) - * - * (1) is not realistic because pos_ratio also takes part in balancing - * the dirty rate. Consider the state - * pos_ratio = 0.5 (3) - * rate = 2 * (write_bw / N) (4) - * If (1) is used, it will stuck in that state! Because each dd will - * be throttled at - * task_ratelimit = pos_ratio * rate = (write_bw / N) (5) - * yielding - * dirty_rate = N * task_ratelimit = write_bw (6) - * put (6) into (1) we get - * rate_(i+1) = rate_(i) (7) - * - * So we end up using (2) to always keep - * rate_(i+1) ~= (write_bw / N) (8) - * regardless of the value of pos_ratio. As long as (8) is satisfied, - * pos_ratio is able to drive itself to 1.0, which is not only where - * the dirty count meet the setpoint, but also where the slope of - * pos_ratio is most flat and hence task_ratelimit is least fluctuated. - */ - balanced_dirty_ratelimit = div_u64((u64)task_ratelimit * write_bw, - dirty_rate | 1); - /* - * balanced_dirty_ratelimit ~= (write_bw / N) <= write_bw - */ - if (unlikely(balanced_dirty_ratelimit > write_bw)) - balanced_dirty_ratelimit = write_bw; - - /* - * We could safely do this and return immediately: - * - * wb->dirty_ratelimit = balanced_dirty_ratelimit; - * - * However to get a more stable dirty_ratelimit, the below elaborated - * code makes use of task_ratelimit to filter out singular points and - * limit the step size. - * - * The below code essentially only uses the relative value of - * - * task_ratelimit - dirty_ratelimit - * = (pos_ratio - 1) * dirty_ratelimit - * - * which reflects the direction and size of dirty position error. - */ - - /* - * dirty_ratelimit will follow balanced_dirty_ratelimit iff - * task_ratelimit is on the same side of dirty_ratelimit, too. - * For example, when - * - dirty_ratelimit > balanced_dirty_ratelimit - * - dirty_ratelimit > task_ratelimit (dirty pages are above setpoint) - * lowering dirty_ratelimit will help meet both the position and rate - * control targets. Otherwise, don't update dirty_ratelimit if it will - * only help meet the rate target. After all, what the users ultimately - * feel and care are stable dirty rate and small position error. - * - * |task_ratelimit - dirty_ratelimit| is used to limit the step size - * and filter out the singular points of balanced_dirty_ratelimit. Which - * keeps jumping around randomly and can even leap far away at times - * due to the small 200ms estimation period of dirty_rate (we want to - * keep that period small to reduce time lags). - */ - step = 0; - - /* - * For strictlimit case, calculations above were based on wb counters - * and limits (starting from pos_ratio = wb_position_ratio() and up to - * balanced_dirty_ratelimit = task_ratelimit * write_bw / dirty_rate). - * Hence, to calculate "step" properly, we have to use wb_dirty as - * "dirty" and wb_setpoint as "setpoint". - * - * We rampup dirty_ratelimit forcibly if wb_dirty is low because - * it's possible that wb_thresh is close to zero due to inactivity - * of backing device. - */ - if (unlikely(wb->bdi->capabilities & BDI_CAP_STRICTLIMIT)) { - dirty = dtc->wb_dirty; - if (dtc->wb_dirty < 8) - setpoint = dtc->wb_dirty + 1; - else - setpoint = (dtc->wb_thresh + dtc->wb_bg_thresh) / 2; - } - - if (dirty < setpoint) { - x = min3(wb->balanced_dirty_ratelimit, - balanced_dirty_ratelimit, task_ratelimit); - if (dirty_ratelimit < x) - step = x - dirty_ratelimit; - } else { - x = max3(wb->balanced_dirty_ratelimit, - balanced_dirty_ratelimit, task_ratelimit); - if (dirty_ratelimit > x) - step = dirty_ratelimit - x; - } - - /* - * Don't pursue 100% rate matching. It's impossible since the balanced - * rate itself is constantly fluctuating. So decrease the track speed - * when it gets close to the target. Helps eliminate pointless tremors. - */ - shift = dirty_ratelimit / (2 * step + 1); - if (shift < BITS_PER_LONG) - step = DIV_ROUND_UP(step >> shift, 8); - else - step = 0; - - if (dirty_ratelimit < balanced_dirty_ratelimit) - dirty_ratelimit += step; - else - dirty_ratelimit -= step; - - wb->dirty_ratelimit = max(dirty_ratelimit, 1UL); - wb->balanced_dirty_ratelimit = balanced_dirty_ratelimit; - - trace_bdi_dirty_ratelimit(wb, dirty_rate, task_ratelimit); -} - -static void __wb_update_bandwidth(struct dirty_throttle_control *gdtc, - struct dirty_throttle_control *mdtc, - unsigned long start_time, - bool update_ratelimit) -{ - struct bdi_writeback *wb = gdtc->wb; - unsigned long now = jiffies; - unsigned long elapsed = now - wb->bw_time_stamp; - unsigned long dirtied; - unsigned long written; - - lockdep_assert_held(&wb->list_lock); - - /* - * rate-limit, only update once every 200ms. - */ - if (elapsed < BANDWIDTH_INTERVAL) - return; - - dirtied = percpu_counter_read(&wb->stat[WB_DIRTIED]); - written = percpu_counter_read(&wb->stat[WB_WRITTEN]); - - /* - * Skip quiet periods when disk bandwidth is under-utilized. - * (at least 1s idle time between two flusher runs) - */ - if (elapsed > HZ && time_before(wb->bw_time_stamp, start_time)) - goto snapshot; - - if (update_ratelimit) { - domain_update_bandwidth(gdtc, now); - wb_update_dirty_ratelimit(gdtc, dirtied, elapsed); - - /* - * @mdtc is always NULL if !CGROUP_WRITEBACK but the - * compiler has no way to figure that out. Help it. - */ - if (IS_ENABLED(CONFIG_CGROUP_WRITEBACK) && mdtc) { - domain_update_bandwidth(mdtc, now); - wb_update_dirty_ratelimit(mdtc, dirtied, elapsed); - } - } - wb_update_write_bandwidth(wb, elapsed, written); - -snapshot: - wb->dirtied_stamp = dirtied; - wb->written_stamp = written; - wb->bw_time_stamp = now; -} - -void wb_update_bandwidth(struct bdi_writeback *wb, unsigned long start_time) -{ - struct dirty_throttle_control gdtc = { GDTC_INIT(wb) }; - - __wb_update_bandwidth(&gdtc, NULL, start_time, false); -} - -/* - * After a task dirtied this many pages, balance_dirty_pages_ratelimited() - * will look to see if it needs to start dirty throttling. - * - * If dirty_poll_interval is too low, big NUMA machines will call the expensive - * global_page_state() too often. So scale it near-sqrt to the safety margin - * (the number of pages we may dirty without exceeding the dirty limits). - */ -static unsigned long dirty_poll_interval(unsigned long dirty, - unsigned long thresh) -{ - if (thresh > dirty) - return 1UL << (ilog2(thresh - dirty) >> 1); - - return 1; -} - -static unsigned long wb_max_pause(struct bdi_writeback *wb, - unsigned long wb_dirty) -{ - unsigned long bw = wb->avg_write_bandwidth; - unsigned long t; - - /* - * Limit pause time for small memory systems. If sleeping for too long - * time, a small pool of dirty/writeback pages may go empty and disk go - * idle. - * - * 8 serves as the safety ratio. - */ - t = wb_dirty / (1 + bw / roundup_pow_of_two(1 + HZ / 8)); - t++; - - return min_t(unsigned long, t, MAX_PAUSE); -} - -static long wb_min_pause(struct bdi_writeback *wb, - long max_pause, - unsigned long task_ratelimit, - unsigned long dirty_ratelimit, - int *nr_dirtied_pause) -{ - long hi = ilog2(wb->avg_write_bandwidth); - long lo = ilog2(wb->dirty_ratelimit); - long t; /* target pause */ - long pause; /* estimated next pause */ - int pages; /* target nr_dirtied_pause */ - - /* target for 10ms pause on 1-dd case */ - t = max(1, HZ / 100); - - /* - * Scale up pause time for concurrent dirtiers in order to reduce CPU - * overheads. - * - * (N * 10ms) on 2^N concurrent tasks. - */ - if (hi > lo) - t += (hi - lo) * (10 * HZ) / 1024; - - /* - * This is a bit convoluted. We try to base the next nr_dirtied_pause - * on the much more stable dirty_ratelimit. However the next pause time - * will be computed based on task_ratelimit and the two rate limits may - * depart considerably at some time. Especially if task_ratelimit goes - * below dirty_ratelimit/2 and the target pause is max_pause, the next - * pause time will be max_pause*2 _trimmed down_ to max_pause. As a - * result task_ratelimit won't be executed faithfully, which could - * eventually bring down dirty_ratelimit. - * - * We apply two rules to fix it up: - * 1) try to estimate the next pause time and if necessary, use a lower - * nr_dirtied_pause so as not to exceed max_pause. When this happens, - * nr_dirtied_pause will be "dancing" with task_ratelimit. - * 2) limit the target pause time to max_pause/2, so that the normal - * small fluctuations of task_ratelimit won't trigger rule (1) and - * nr_dirtied_pause will remain as stable as dirty_ratelimit. - */ - t = min(t, 1 + max_pause / 2); - pages = dirty_ratelimit * t / roundup_pow_of_two(HZ); - - /* - * Tiny nr_dirtied_pause is found to hurt I/O performance in the test - * case fio-mmap-randwrite-64k, which does 16*{sync read, async write}. - * When the 16 consecutive reads are often interrupted by some dirty - * throttling pause during the async writes, cfq will go into idles - * (deadline is fine). So push nr_dirtied_pause as high as possible - * until reaches DIRTY_POLL_THRESH=32 pages. - */ - if (pages < DIRTY_POLL_THRESH) { - t = max_pause; - pages = dirty_ratelimit * t / roundup_pow_of_two(HZ); - if (pages > DIRTY_POLL_THRESH) { - pages = DIRTY_POLL_THRESH; - t = HZ * DIRTY_POLL_THRESH / dirty_ratelimit; - } - } - - pause = HZ * pages / (task_ratelimit + 1); - if (pause > max_pause) { - t = max_pause; - pages = task_ratelimit * t / roundup_pow_of_two(HZ); - } - - *nr_dirtied_pause = pages; - /* - * The minimal pause time will normally be half the target pause time. - */ - return pages >= DIRTY_POLL_THRESH ? 1 + t / 2 : t; -} - -static inline void wb_dirty_limits(struct dirty_throttle_control *dtc) -{ - struct bdi_writeback *wb = dtc->wb; - unsigned long wb_reclaimable; - - /* - * wb_thresh is not treated as some limiting factor as - * dirty_thresh, due to reasons - * - in JBOD setup, wb_thresh can fluctuate a lot - * - in a system with HDD and USB key, the USB key may somehow - * go into state (wb_dirty >> wb_thresh) either because - * wb_dirty starts high, or because wb_thresh drops low. - * In this case we don't want to hard throttle the USB key - * dirtiers for 100 seconds until wb_dirty drops under - * wb_thresh. Instead the auxiliary wb control line in - * wb_position_ratio() will let the dirtier task progress - * at some rate <= (write_bw / 2) for bringing down wb_dirty. - */ - dtc->wb_thresh = __wb_calc_thresh(dtc); - dtc->wb_bg_thresh = dtc->thresh ? - div_u64((u64)dtc->wb_thresh * dtc->bg_thresh, dtc->thresh) : 0; - - /* - * In order to avoid the stacked BDI deadlock we need - * to ensure we accurately count the 'dirty' pages when - * the threshold is low. - * - * Otherwise it would be possible to get thresh+n pages - * reported dirty, even though there are thresh-m pages - * actually dirty; with m+n sitting in the percpu - * deltas. - */ - if (dtc->wb_thresh < 2 * wb_stat_error(wb)) { - wb_reclaimable = wb_stat_sum(wb, WB_RECLAIMABLE); - dtc->wb_dirty = wb_reclaimable + wb_stat_sum(wb, WB_WRITEBACK); - } else { - wb_reclaimable = wb_stat(wb, WB_RECLAIMABLE); - dtc->wb_dirty = wb_reclaimable + wb_stat(wb, WB_WRITEBACK); - } -} - -/* - * balance_dirty_pages() must be called by processes which are generating dirty - * data. It looks at the number of dirty pages in the machine and will force - * the caller to wait once crossing the (background_thresh + dirty_thresh) / 2. - * If we're over `background_thresh' then the writeback threads are woken to - * perform some writeout. - */ -static void balance_dirty_pages(struct address_space *mapping, - struct bdi_writeback *wb, - unsigned long pages_dirtied) -{ - struct dirty_throttle_control gdtc_stor = { GDTC_INIT(wb) }; - struct dirty_throttle_control mdtc_stor = { MDTC_INIT(wb, &gdtc_stor) }; - struct dirty_throttle_control * const gdtc = &gdtc_stor; - struct dirty_throttle_control * const mdtc = mdtc_valid(&mdtc_stor) ? - &mdtc_stor : NULL; - struct dirty_throttle_control *sdtc; - unsigned long nr_reclaimable; /* = file_dirty + unstable_nfs */ - long period; - long pause; - long max_pause; - long min_pause; - int nr_dirtied_pause; - bool dirty_exceeded = false; - unsigned long task_ratelimit; - unsigned long dirty_ratelimit; - struct backing_dev_info *bdi = wb->bdi; - bool strictlimit = bdi->capabilities & BDI_CAP_STRICTLIMIT; - unsigned long start_time = jiffies; - - for (;;) { - unsigned long now = jiffies; - unsigned long dirty, thresh, bg_thresh; - unsigned long m_dirty = 0; /* stop bogus uninit warnings */ - unsigned long m_thresh = 0; - unsigned long m_bg_thresh = 0; - - /* - * Unstable writes are a feature of certain networked - * filesystems (i.e. NFS) in which data may have been - * written to the server's write cache, but has not yet - * been flushed to permanent storage. - */ - nr_reclaimable = global_node_page_state(NR_FILE_DIRTY) + - global_node_page_state(NR_UNSTABLE_NFS); - gdtc->avail = global_dirtyable_memory(); - gdtc->dirty = nr_reclaimable + global_node_page_state(NR_WRITEBACK); - - domain_dirty_limits(gdtc); - - if (unlikely(strictlimit)) { - wb_dirty_limits(gdtc); - - dirty = gdtc->wb_dirty; - thresh = gdtc->wb_thresh; - bg_thresh = gdtc->wb_bg_thresh; - } else { - dirty = gdtc->dirty; - thresh = gdtc->thresh; - bg_thresh = gdtc->bg_thresh; - } - - if (mdtc) { - unsigned long filepages, headroom, writeback; - - /* - * If @wb belongs to !root memcg, repeat the same - * basic calculations for the memcg domain. - */ - mem_cgroup_wb_stats(wb, &filepages, &headroom, - &mdtc->dirty, &writeback); - mdtc->dirty += writeback; - mdtc_calc_avail(mdtc, filepages, headroom); - - domain_dirty_limits(mdtc); - - if (unlikely(strictlimit)) { - wb_dirty_limits(mdtc); - m_dirty = mdtc->wb_dirty; - m_thresh = mdtc->wb_thresh; - m_bg_thresh = mdtc->wb_bg_thresh; - } else { - m_dirty = mdtc->dirty; - m_thresh = mdtc->thresh; - m_bg_thresh = mdtc->bg_thresh; - } - } - - /* - * Throttle it only when the background writeback cannot - * catch-up. This avoids (excessively) small writeouts - * when the wb limits are ramping up in case of !strictlimit. - * - * In strictlimit case make decision based on the wb counters - * and limits. Small writeouts when the wb limits are ramping - * up are the price we consciously pay for strictlimit-ing. - * - * If memcg domain is in effect, @dirty should be under - * both global and memcg freerun ceilings. - */ - if (dirty <= dirty_freerun_ceiling(thresh, bg_thresh) && - (!mdtc || - m_dirty <= dirty_freerun_ceiling(m_thresh, m_bg_thresh))) { - unsigned long intv = dirty_poll_interval(dirty, thresh); - unsigned long m_intv = ULONG_MAX; - - current->dirty_paused_when = now; - current->nr_dirtied = 0; - if (mdtc) - m_intv = dirty_poll_interval(m_dirty, m_thresh); - current->nr_dirtied_pause = min(intv, m_intv); - break; - } - - if (unlikely(!writeback_in_progress(wb))) - wb_start_background_writeback(wb); - - /* - * Calculate global domain's pos_ratio and select the - * global dtc by default. - */ - if (!strictlimit) - wb_dirty_limits(gdtc); - - dirty_exceeded = (gdtc->wb_dirty > gdtc->wb_thresh) && - ((gdtc->dirty > gdtc->thresh) || strictlimit); - - wb_position_ratio(gdtc); - sdtc = gdtc; - - if (mdtc) { - /* - * If memcg domain is in effect, calculate its - * pos_ratio. @wb should satisfy constraints from - * both global and memcg domains. Choose the one - * w/ lower pos_ratio. - */ - if (!strictlimit) - wb_dirty_limits(mdtc); - - dirty_exceeded |= (mdtc->wb_dirty > mdtc->wb_thresh) && - ((mdtc->dirty > mdtc->thresh) || strictlimit); - - wb_position_ratio(mdtc); - if (mdtc->pos_ratio < gdtc->pos_ratio) - sdtc = mdtc; - } - - if (dirty_exceeded && !wb->dirty_exceeded) - wb->dirty_exceeded = 1; - - if (time_is_before_jiffies(wb->bw_time_stamp + - BANDWIDTH_INTERVAL)) { - spin_lock(&wb->list_lock); - __wb_update_bandwidth(gdtc, mdtc, start_time, true); - spin_unlock(&wb->list_lock); - } - - /* throttle according to the chosen dtc */ - dirty_ratelimit = wb->dirty_ratelimit; - task_ratelimit = ((u64)dirty_ratelimit * sdtc->pos_ratio) >> - RATELIMIT_CALC_SHIFT; - max_pause = wb_max_pause(wb, sdtc->wb_dirty); - min_pause = wb_min_pause(wb, max_pause, - task_ratelimit, dirty_ratelimit, - &nr_dirtied_pause); - - if (unlikely(task_ratelimit == 0)) { - period = max_pause; - pause = max_pause; - goto pause; - } - period = HZ * pages_dirtied / task_ratelimit; - pause = period; - if (current->dirty_paused_when) - pause -= now - current->dirty_paused_when; - /* - * For less than 1s think time (ext3/4 may block the dirtier - * for up to 800ms from time to time on 1-HDD; so does xfs, - * however at much less frequency), try to compensate it in - * future periods by updating the virtual time; otherwise just - * do a reset, as it may be a light dirtier. - */ - if (pause < min_pause) { - trace_balance_dirty_pages(wb, - sdtc->thresh, - sdtc->bg_thresh, - sdtc->dirty, - sdtc->wb_thresh, - sdtc->wb_dirty, - dirty_ratelimit, - task_ratelimit, - pages_dirtied, - period, - min(pause, 0L), - start_time); - if (pause < -HZ) { - current->dirty_paused_when = now; - current->nr_dirtied = 0; - } else if (period) { - current->dirty_paused_when += period; - current->nr_dirtied = 0; - } else if (current->nr_dirtied_pause <= pages_dirtied) - current->nr_dirtied_pause += pages_dirtied; - break; - } - if (unlikely(pause > max_pause)) { - /* for occasional dropped task_ratelimit */ - now += min(pause - max_pause, max_pause); - pause = max_pause; - } - -pause: - trace_balance_dirty_pages(wb, - sdtc->thresh, - sdtc->bg_thresh, - sdtc->dirty, - sdtc->wb_thresh, - sdtc->wb_dirty, - dirty_ratelimit, - task_ratelimit, - pages_dirtied, - period, - pause, - start_time); - __set_current_state(TASK_KILLABLE); - io_schedule_timeout(pause); - - current->dirty_paused_when = now + pause; - current->nr_dirtied = 0; - current->nr_dirtied_pause = nr_dirtied_pause; - - /* - * This is typically equal to (dirty < thresh) and can also - * keep "1000+ dd on a slow USB stick" under control. - */ - if (task_ratelimit) - break; - - /* - * In the case of an unresponding NFS server and the NFS dirty - * pages exceeds dirty_thresh, give the other good wb's a pipe - * to go through, so that tasks on them still remain responsive. - * - * In theory 1 page is enough to keep the comsumer-producer - * pipe going: the flusher cleans 1 page => the task dirties 1 - * more page. However wb_dirty has accounting errors. So use - * the larger and more IO friendly wb_stat_error. - */ - if (sdtc->wb_dirty <= wb_stat_error(wb)) - break; - - if (fatal_signal_pending(current)) - break; - } - - if (!dirty_exceeded && wb->dirty_exceeded) - wb->dirty_exceeded = 0; - - if (writeback_in_progress(wb)) - return; - - /* - * In laptop mode, we wait until hitting the higher threshold before - * starting background writeout, and then write out all the way down - * to the lower threshold. So slow writers cause minimal disk activity. - * - * In normal mode, we start background writeout at the lower - * background_thresh, to keep the amount of dirty memory low. - */ - if (laptop_mode) - return; - - if (nr_reclaimable > gdtc->bg_thresh) - wb_start_background_writeback(wb); -} - -static DEFINE_PER_CPU(int, bdp_ratelimits); - -/* - * Normal tasks are throttled by - * loop { - * dirty tsk->nr_dirtied_pause pages; - * take a snap in balance_dirty_pages(); - * } - * However there is a worst case. If every task exit immediately when dirtied - * (tsk->nr_dirtied_pause - 1) pages, balance_dirty_pages() will never be - * called to throttle the page dirties. The solution is to save the not yet - * throttled page dirties in dirty_throttle_leaks on task exit and charge them - * randomly into the running tasks. This works well for the above worst case, - * as the new task will pick up and accumulate the old task's leaked dirty - * count and eventually get throttled. - */ -DEFINE_PER_CPU(int, dirty_throttle_leaks) = 0; - -/** - * balance_dirty_pages_ratelimited - balance dirty memory state - * @mapping: address_space which was dirtied - * - * Processes which are dirtying memory should call in here once for each page - * which was newly dirtied. The function will periodically check the system's - * dirty state and will initiate writeback if needed. - * - * On really big machines, get_writeback_state is expensive, so try to avoid - * calling it too often (ratelimiting). But once we're over the dirty memory - * limit we decrease the ratelimiting by a lot, to prevent individual processes - * from overshooting the limit by (ratelimit_pages) each. - */ -void balance_dirty_pages_ratelimited(struct address_space *mapping) -{ - struct inode *inode = mapping->host; - struct backing_dev_info *bdi = inode_to_bdi(inode); - struct bdi_writeback *wb = NULL; - int ratelimit; - int *p; - - if (!bdi_cap_account_dirty(bdi)) - return; - - if (inode_cgwb_enabled(inode)) - wb = wb_get_create_current(bdi, GFP_KERNEL); - if (!wb) - wb = &bdi->wb; - - ratelimit = current->nr_dirtied_pause; - if (wb->dirty_exceeded) - ratelimit = min(ratelimit, 32 >> (PAGE_SHIFT - 10)); - - preempt_disable(); - /* - * This prevents one CPU to accumulate too many dirtied pages without - * calling into balance_dirty_pages(), which can happen when there are - * 1000+ tasks, all of them start dirtying pages at exactly the same - * time, hence all honoured too large initial task->nr_dirtied_pause. - */ - p = this_cpu_ptr(&bdp_ratelimits); - if (unlikely(current->nr_dirtied >= ratelimit)) - *p = 0; - else if (unlikely(*p >= ratelimit_pages)) { - *p = 0; - ratelimit = 0; - } - /* - * Pick up the dirtied pages by the exited tasks. This avoids lots of - * short-lived tasks (eg. gcc invocations in a kernel build) escaping - * the dirty throttling and livelock other long-run dirtiers. - */ - p = this_cpu_ptr(&dirty_throttle_leaks); - if (*p > 0 && current->nr_dirtied < ratelimit) { - unsigned long nr_pages_dirtied; - nr_pages_dirtied = min(*p, ratelimit - current->nr_dirtied); - *p -= nr_pages_dirtied; - current->nr_dirtied += nr_pages_dirtied; - } - preempt_enable(); - - if (unlikely(current->nr_dirtied >= ratelimit)) - balance_dirty_pages(mapping, wb, current->nr_dirtied); - - wb_put(wb); -} -EXPORT_SYMBOL(balance_dirty_pages_ratelimited); - -/** - * wb_over_bg_thresh - does @wb need to be written back? - * @wb: bdi_writeback of interest - * - * Determines whether background writeback should keep writing @wb or it's - * clean enough. Returns %true if writeback should continue. - */ -bool wb_over_bg_thresh(struct bdi_writeback *wb) -{ - struct dirty_throttle_control gdtc_stor = { GDTC_INIT(wb) }; - struct dirty_throttle_control mdtc_stor = { MDTC_INIT(wb, &gdtc_stor) }; - struct dirty_throttle_control * const gdtc = &gdtc_stor; - struct dirty_throttle_control * const mdtc = mdtc_valid(&mdtc_stor) ? - &mdtc_stor : NULL; - - /* - * Similar to balance_dirty_pages() but ignores pages being written - * as we're trying to decide whether to put more under writeback. - */ - gdtc->avail = global_dirtyable_memory(); - gdtc->dirty = global_node_page_state(NR_FILE_DIRTY) + - global_node_page_state(NR_UNSTABLE_NFS); - domain_dirty_limits(gdtc); - - if (gdtc->dirty > gdtc->bg_thresh) - return true; - - if (wb_stat(wb, WB_RECLAIMABLE) > - wb_calc_thresh(gdtc->wb, gdtc->bg_thresh)) - return true; - - if (mdtc) { - unsigned long filepages, headroom, writeback; - - mem_cgroup_wb_stats(wb, &filepages, &headroom, &mdtc->dirty, - &writeback); - mdtc_calc_avail(mdtc, filepages, headroom); - domain_dirty_limits(mdtc); /* ditto, ignore writeback */ - - if (mdtc->dirty > mdtc->bg_thresh) - return true; - - if (wb_stat(wb, WB_RECLAIMABLE) > - wb_calc_thresh(mdtc->wb, mdtc->bg_thresh)) - return true; - } - - return false; -} - -/* - * sysctl handler for /proc/sys/vm/dirty_writeback_centisecs - */ -int dirty_writeback_centisecs_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *length, loff_t *ppos) -{ - proc_dointvec(table, write, buffer, length, ppos); - return 0; -} - -#ifdef CONFIG_BLOCK -void laptop_mode_timer_fn(unsigned long data) -{ - struct request_queue *q = (struct request_queue *)data; - int nr_pages = global_node_page_state(NR_FILE_DIRTY) + - global_node_page_state(NR_UNSTABLE_NFS); - struct bdi_writeback *wb; - - /* - * We want to write everything out, not just down to the dirty - * threshold - */ - if (!bdi_has_dirty_io(&q->backing_dev_info)) - return; - - rcu_read_lock(); - list_for_each_entry_rcu(wb, &q->backing_dev_info.wb_list, bdi_node) - if (wb_has_dirty_io(wb)) - wb_start_writeback(wb, nr_pages, true, - WB_REASON_LAPTOP_TIMER); - rcu_read_unlock(); -} - -/* - * We've spun up the disk and we're in laptop mode: schedule writeback - * of all dirty data a few seconds from now. If the flush is already scheduled - * then push it back - the user is still using the disk. - */ -void laptop_io_completion(struct backing_dev_info *info) -{ - mod_timer(&info->laptop_mode_wb_timer, jiffies + laptop_mode); -} - -/* - * We're in laptop mode and we've just synced. The sync's writes will have - * caused another writeback to be scheduled by laptop_io_completion. - * Nothing needs to be written back anymore, so we unschedule the writeback. - */ -void laptop_sync_completion(void) -{ - struct backing_dev_info *bdi; - - rcu_read_lock(); - - list_for_each_entry_rcu(bdi, &bdi_list, bdi_list) - del_timer(&bdi->laptop_mode_wb_timer); - - rcu_read_unlock(); -} -#endif - -/* - * If ratelimit_pages is too high then we can get into dirty-data overload - * if a large number of processes all perform writes at the same time. - * If it is too low then SMP machines will call the (expensive) - * get_writeback_state too often. - * - * Here we set ratelimit_pages to a level which ensures that when all CPUs are - * dirtying in parallel, we cannot go more than 3% (1/32) over the dirty memory - * thresholds. - */ - -void writeback_set_ratelimit(void) -{ - struct wb_domain *dom = &global_wb_domain; - unsigned long background_thresh; - unsigned long dirty_thresh; - - global_dirty_limits(&background_thresh, &dirty_thresh); - dom->dirty_limit = dirty_thresh; - ratelimit_pages = dirty_thresh / (num_online_cpus() * 32); - if (ratelimit_pages < 16) - ratelimit_pages = 16; -} - -static int page_writeback_cpu_online(unsigned int cpu) -{ - writeback_set_ratelimit(); - return 0; -} - -/* - * Called early on to tune the page writeback dirty limits. - * - * We used to scale dirty pages according to how total memory - * related to pages that could be allocated for buffers (by - * comparing nr_free_buffer_pages() to vm_total_pages. - * - * However, that was when we used "dirty_ratio" to scale with - * all memory, and we don't do that any more. "dirty_ratio" - * is now applied to total non-HIGHPAGE memory (by subtracting - * totalhigh_pages from vm_total_pages), and as such we can't - * get into the old insane situation any more where we had - * large amounts of dirty pages compared to a small amount of - * non-HIGHMEM memory. - * - * But we might still want to scale the dirty_ratio by how - * much memory the box has.. - */ -void __init page_writeback_init(void) -{ - BUG_ON(wb_domain_init(&global_wb_domain, GFP_KERNEL)); - - cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "mm/writeback:online", - page_writeback_cpu_online, NULL); - cpuhp_setup_state(CPUHP_MM_WRITEBACK_DEAD, "mm/writeback:dead", NULL, - page_writeback_cpu_online); -} - -/** - * tag_pages_for_writeback - tag pages to be written by write_cache_pages - * @mapping: address space structure to write - * @start: starting page index - * @end: ending page index (inclusive) - * - * This function scans the page range from @start to @end (inclusive) and tags - * all pages that have DIRTY tag set with a special TOWRITE tag. The idea is - * that write_cache_pages (or whoever calls this function) will then use - * TOWRITE tag to identify pages eligible for writeback. This mechanism is - * used to avoid livelocking of writeback by a process steadily creating new - * dirty pages in the file (thus it is important for this function to be quick - * so that it can tag pages faster than a dirtying process can create them). - */ -/* - * We tag pages in batches of WRITEBACK_TAG_BATCH to reduce tree_lock latency. - */ -void tag_pages_for_writeback(struct address_space *mapping, - pgoff_t start, pgoff_t end) -{ -#define WRITEBACK_TAG_BATCH 4096 - unsigned long tagged; - - do { - spin_lock_irq(&mapping->tree_lock); - tagged = radix_tree_range_tag_if_tagged(&mapping->page_tree, - &start, end, WRITEBACK_TAG_BATCH, - PAGECACHE_TAG_DIRTY, PAGECACHE_TAG_TOWRITE); - spin_unlock_irq(&mapping->tree_lock); - WARN_ON_ONCE(tagged > WRITEBACK_TAG_BATCH); - cond_resched(); - /* We check 'start' to handle wrapping when end == ~0UL */ - } while (tagged >= WRITEBACK_TAG_BATCH && start); -} -EXPORT_SYMBOL(tag_pages_for_writeback); - -/** - * write_cache_pages - walk the list of dirty pages of the given address space and write all of them. - * @mapping: address space structure to write - * @wbc: subtract the number of written pages from *@wbc->nr_to_write - * @writepage: function called for each page - * @data: data passed to writepage function - * - * If a page is already under I/O, write_cache_pages() skips it, even - * if it's dirty. This is desirable behaviour for memory-cleaning writeback, - * but it is INCORRECT for data-integrity system calls such as fsync(). fsync() - * and msync() need to guarantee that all the data which was dirty at the time - * the call was made get new I/O started against them. If wbc->sync_mode is - * WB_SYNC_ALL then we were called for data integrity and we must wait for - * existing IO to complete. - * - * To avoid livelocks (when other process dirties new pages), we first tag - * pages which should be written back with TOWRITE tag and only then start - * writing them. For data-integrity sync we have to be careful so that we do - * not miss some pages (e.g., because some other process has cleared TOWRITE - * tag we set). The rule we follow is that TOWRITE tag can be cleared only - * by the process clearing the DIRTY tag (and submitting the page for IO). - */ -int write_cache_pages(struct address_space *mapping, - struct writeback_control *wbc, writepage_t writepage, - void *data) -{ - int ret = 0; - int done = 0; - struct pagevec pvec; - int nr_pages; - pgoff_t uninitialized_var(writeback_index); - pgoff_t index; - pgoff_t end; /* Inclusive */ - pgoff_t done_index; - int cycled; - int range_whole = 0; - int tag; - - pagevec_init(&pvec, 0); - if (wbc->range_cyclic) { - writeback_index = mapping->writeback_index; /* prev offset */ - index = writeback_index; - if (index == 0) - cycled = 1; - else - cycled = 0; - end = -1; - } else { - index = wbc->range_start >> PAGE_SHIFT; - end = wbc->range_end >> PAGE_SHIFT; - if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) - range_whole = 1; - cycled = 1; /* ignore range_cyclic tests */ - } - if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages) - tag = PAGECACHE_TAG_TOWRITE; - else - tag = PAGECACHE_TAG_DIRTY; -retry: - if (wbc->sync_mode == WB_SYNC_ALL || wbc->tagged_writepages) - tag_pages_for_writeback(mapping, index, end); - done_index = index; - while (!done && (index <= end)) { - int i; - - nr_pages = pagevec_lookup_tag(&pvec, mapping, &index, tag, - min(end - index, (pgoff_t)PAGEVEC_SIZE-1) + 1); - if (nr_pages == 0) - break; - - for (i = 0; i < nr_pages; i++) { - struct page *page = pvec.pages[i]; - - /* - * At this point, the page may be truncated or - * invalidated (changing page->mapping to NULL), or - * even swizzled back from swapper_space to tmpfs file - * mapping. However, page->index will not change - * because we have a reference on the page. - */ - if (page->index > end) { - /* - * can't be range_cyclic (1st pass) because - * end == -1 in that case. - */ - done = 1; - break; - } - - done_index = page->index; - - lock_page(page); - - /* - * Page truncated or invalidated. We can freely skip it - * then, even for data integrity operations: the page - * has disappeared concurrently, so there could be no - * real expectation of this data interity operation - * even if there is now a new, dirty page at the same - * pagecache address. - */ - if (unlikely(page->mapping != mapping)) { -continue_unlock: - unlock_page(page); - continue; - } - - if (!PageDirty(page)) { - /* someone wrote it for us */ - goto continue_unlock; - } - - if (PageWriteback(page)) { - if (wbc->sync_mode != WB_SYNC_NONE) - wait_on_page_writeback(page); - else - goto continue_unlock; - } - - BUG_ON(PageWriteback(page)); - if (!clear_page_dirty_for_io(page)) - goto continue_unlock; - - trace_wbc_writepage(wbc, inode_to_bdi(mapping->host)); - ret = (*writepage)(page, wbc, data); - if (unlikely(ret)) { - if (ret == AOP_WRITEPAGE_ACTIVATE) { - unlock_page(page); - ret = 0; - } else { - /* - * done_index is set past this page, - * so media errors will not choke - * background writeout for the entire - * file. This has consequences for - * range_cyclic semantics (ie. it may - * not be suitable for data integrity - * writeout). - */ - done_index = page->index + 1; - done = 1; - break; - } - } - - /* - * We stop writing back only if we are not doing - * integrity sync. In case of integrity sync we have to - * keep going until we have written all the pages - * we tagged for writeback prior to entering this loop. - */ - if (--wbc->nr_to_write <= 0 && - wbc->sync_mode == WB_SYNC_NONE) { - done = 1; - break; - } - } - pagevec_release(&pvec); - cond_resched(); - } - if (!cycled && !done) { - /* - * range_cyclic: - * We hit the last page and there is more work to be done: wrap - * back to the start of the file - */ - cycled = 1; - index = 0; - end = writeback_index - 1; - goto retry; - } - if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) - mapping->writeback_index = done_index; - - return ret; -} -EXPORT_SYMBOL(write_cache_pages); - -/* - * Function used by generic_writepages to call the real writepage - * function and set the mapping flags on error - */ -static int __writepage(struct page *page, struct writeback_control *wbc, - void *data) -{ - struct address_space *mapping = data; - int ret = mapping->a_ops->writepage(page, wbc); - mapping_set_error(mapping, ret); - return ret; -} - -/** - * generic_writepages - walk the list of dirty pages of the given address space and writepage() all of them. - * @mapping: address space structure to write - * @wbc: subtract the number of written pages from *@wbc->nr_to_write - * - * This is a library function, which implements the writepages() - * address_space_operation. - */ -int generic_writepages(struct address_space *mapping, - struct writeback_control *wbc) -{ - struct blk_plug plug; - int ret; - - /* deal with chardevs and other special file */ - if (!mapping->a_ops->writepage) - return 0; - - blk_start_plug(&plug); - ret = write_cache_pages(mapping, wbc, __writepage, mapping); - blk_finish_plug(&plug); - return ret; -} - -EXPORT_SYMBOL(generic_writepages); - -int do_writepages(struct address_space *mapping, struct writeback_control *wbc) -{ - int ret; - - if (wbc->nr_to_write <= 0) - return 0; - if (mapping->a_ops->writepages) - ret = mapping->a_ops->writepages(mapping, wbc); - else - ret = generic_writepages(mapping, wbc); - return ret; -} - -/** - * write_one_page - write out a single page and optionally wait on I/O - * @page: the page to write - * @wait: if true, wait on writeout - * - * The page must be locked by the caller and will be unlocked upon return. - * - * write_one_page() returns a negative error code if I/O failed. - */ -int write_one_page(struct page *page, int wait) -{ - struct address_space *mapping = page->mapping; - int ret = 0; - struct writeback_control wbc = { - .sync_mode = WB_SYNC_ALL, - .nr_to_write = 1, - }; - - BUG_ON(!PageLocked(page)); - - if (wait) - wait_on_page_writeback(page); - - if (clear_page_dirty_for_io(page)) { - get_page(page); - ret = mapping->a_ops->writepage(page, &wbc); - if (ret == 0 && wait) { - wait_on_page_writeback(page); - if (PageError(page)) - ret = -EIO; - } - put_page(page); - } else { - unlock_page(page); - } - return ret; -} -EXPORT_SYMBOL(write_one_page); - -/* - * For address_spaces which do not use buffers nor write back. - */ -int __set_page_dirty_no_writeback(struct page *page) -{ - if (!PageDirty(page)) - return !TestSetPageDirty(page); - return 0; -} - -/* - * Helper function for set_page_dirty family. - * - * Caller must hold lock_page_memcg(). - * - * NOTE: This relies on being atomic wrt interrupts. - */ -void account_page_dirtied(struct page *page, struct address_space *mapping) -{ - struct inode *inode = mapping->host; - - trace_writeback_dirty_page(page, mapping); - - if (mapping_cap_account_dirty(mapping)) { - struct bdi_writeback *wb; - - inode_attach_wb(inode, page); - wb = inode_to_wb(inode); - - mem_cgroup_inc_page_stat(page, MEM_CGROUP_STAT_DIRTY); - __inc_node_page_state(page, NR_FILE_DIRTY); - __inc_zone_page_state(page, NR_ZONE_WRITE_PENDING); - __inc_node_page_state(page, NR_DIRTIED); - __inc_wb_stat(wb, WB_RECLAIMABLE); - __inc_wb_stat(wb, WB_DIRTIED); - task_io_account_write(PAGE_SIZE); - current->nr_dirtied++; - this_cpu_inc(bdp_ratelimits); - } -} -EXPORT_SYMBOL(account_page_dirtied); - -/* - * Helper function for deaccounting dirty page without writeback. - * - * Caller must hold lock_page_memcg(). - */ -void account_page_cleaned(struct page *page, struct address_space *mapping, - struct bdi_writeback *wb) -{ - if (mapping_cap_account_dirty(mapping)) { - mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_DIRTY); - dec_node_page_state(page, NR_FILE_DIRTY); - dec_zone_page_state(page, NR_ZONE_WRITE_PENDING); - dec_wb_stat(wb, WB_RECLAIMABLE); - task_io_account_cancelled_write(PAGE_SIZE); - } -} - -/* - * For address_spaces which do not use buffers. Just tag the page as dirty in - * its radix tree. - * - * This is also used when a single buffer is being dirtied: we want to set the - * page dirty in that case, but not all the buffers. This is a "bottom-up" - * dirtying, whereas __set_page_dirty_buffers() is a "top-down" dirtying. - * - * The caller must ensure this doesn't race with truncation. Most will simply - * hold the page lock, but e.g. zap_pte_range() calls with the page mapped and - * the pte lock held, which also locks out truncation. - */ -int __set_page_dirty_nobuffers(struct page *page) -{ - lock_page_memcg(page); - if (!TestSetPageDirty(page)) { - struct address_space *mapping = page_mapping(page); - unsigned long flags; - - if (!mapping) { - unlock_page_memcg(page); - return 1; - } - - spin_lock_irqsave(&mapping->tree_lock, flags); - BUG_ON(page_mapping(page) != mapping); - WARN_ON_ONCE(!PagePrivate(page) && !PageUptodate(page)); - account_page_dirtied(page, mapping); - radix_tree_tag_set(&mapping->page_tree, page_index(page), - PAGECACHE_TAG_DIRTY); - spin_unlock_irqrestore(&mapping->tree_lock, flags); - unlock_page_memcg(page); - - if (mapping->host) { - /* !PageAnon && !swapper_space */ - __mark_inode_dirty(mapping->host, I_DIRTY_PAGES); - } - return 1; - } - unlock_page_memcg(page); - return 0; -} -EXPORT_SYMBOL(__set_page_dirty_nobuffers); - -/* - * Call this whenever redirtying a page, to de-account the dirty counters - * (NR_DIRTIED, BDI_DIRTIED, tsk->nr_dirtied), so that they match the written - * counters (NR_WRITTEN, BDI_WRITTEN) in long term. The mismatches will lead to - * systematic errors in balanced_dirty_ratelimit and the dirty pages position - * control. - */ -void account_page_redirty(struct page *page) -{ - struct address_space *mapping = page->mapping; - - if (mapping && mapping_cap_account_dirty(mapping)) { - struct inode *inode = mapping->host; - struct bdi_writeback *wb; - bool locked; - - wb = unlocked_inode_to_wb_begin(inode, &locked); - current->nr_dirtied--; - dec_node_page_state(page, NR_DIRTIED); - dec_wb_stat(wb, WB_DIRTIED); - unlocked_inode_to_wb_end(inode, locked); - } -} -EXPORT_SYMBOL(account_page_redirty); - -/* - * When a writepage implementation decides that it doesn't want to write this - * page for some reason, it should redirty the locked page via - * redirty_page_for_writepage() and it should then unlock the page and return 0 - */ -int redirty_page_for_writepage(struct writeback_control *wbc, struct page *page) -{ - int ret; - - wbc->pages_skipped++; - ret = __set_page_dirty_nobuffers(page); - account_page_redirty(page); - return ret; -} -EXPORT_SYMBOL(redirty_page_for_writepage); - -/* - * Dirty a page. - * - * For pages with a mapping this should be done under the page lock - * for the benefit of asynchronous memory errors who prefer a consistent - * dirty state. This rule can be broken in some special cases, - * but should be better not to. - * - * If the mapping doesn't provide a set_page_dirty a_op, then - * just fall through and assume that it wants buffer_heads. - */ -int set_page_dirty(struct page *page) -{ - struct address_space *mapping = page_mapping(page); - - page = compound_head(page); - if (likely(mapping)) { - int (*spd)(struct page *) = mapping->a_ops->set_page_dirty; - /* - * readahead/lru_deactivate_page could remain - * PG_readahead/PG_reclaim due to race with end_page_writeback - * About readahead, if the page is written, the flags would be - * reset. So no problem. - * About lru_deactivate_page, if the page is redirty, the flag - * will be reset. So no problem. but if the page is used by readahead - * it will confuse readahead and make it restart the size rampup - * process. But it's a trivial problem. - */ - if (PageReclaim(page)) - ClearPageReclaim(page); -#ifdef CONFIG_BLOCK - if (!spd) - spd = __set_page_dirty_buffers; -#endif - return (*spd)(page); - } - if (!PageDirty(page)) { - if (!TestSetPageDirty(page)) - return 1; - } - return 0; -} -EXPORT_SYMBOL(set_page_dirty); - -/* - * set_page_dirty() is racy if the caller has no reference against - * page->mapping->host, and if the page is unlocked. This is because another - * CPU could truncate the page off the mapping and then free the mapping. - * - * Usually, the page _is_ locked, or the caller is a user-space process which - * holds a reference on the inode by having an open file. - * - * In other cases, the page should be locked before running set_page_dirty(). - */ -int set_page_dirty_lock(struct page *page) -{ - int ret; - - lock_page(page); - ret = set_page_dirty(page); - unlock_page(page); - return ret; -} -EXPORT_SYMBOL(set_page_dirty_lock); - -/* - * This cancels just the dirty bit on the kernel page itself, it does NOT - * actually remove dirty bits on any mmap's that may be around. It also - * leaves the page tagged dirty, so any sync activity will still find it on - * the dirty lists, and in particular, clear_page_dirty_for_io() will still - * look at the dirty bits in the VM. - * - * Doing this should *normally* only ever be done when a page is truncated, - * and is not actually mapped anywhere at all. However, fs/buffer.c does - * this when it notices that somebody has cleaned out all the buffers on a - * page without actually doing it through the VM. Can you say "ext3 is - * horribly ugly"? Thought you could. - */ -void cancel_dirty_page(struct page *page) -{ - struct address_space *mapping = page_mapping(page); - - if (mapping_cap_account_dirty(mapping)) { - struct inode *inode = mapping->host; - struct bdi_writeback *wb; - bool locked; - - lock_page_memcg(page); - wb = unlocked_inode_to_wb_begin(inode, &locked); - - if (TestClearPageDirty(page)) - account_page_cleaned(page, mapping, wb); - - unlocked_inode_to_wb_end(inode, locked); - unlock_page_memcg(page); - } else { - ClearPageDirty(page); - } -} -EXPORT_SYMBOL(cancel_dirty_page); - -/* - * Clear a page's dirty flag, while caring for dirty memory accounting. - * Returns true if the page was previously dirty. - * - * This is for preparing to put the page under writeout. We leave the page - * tagged as dirty in the radix tree so that a concurrent write-for-sync - * can discover it via a PAGECACHE_TAG_DIRTY walk. The ->writepage - * implementation will run either set_page_writeback() or set_page_dirty(), - * at which stage we bring the page's dirty flag and radix-tree dirty tag - * back into sync. - * - * This incoherency between the page's dirty flag and radix-tree tag is - * unfortunate, but it only exists while the page is locked. - */ -int clear_page_dirty_for_io(struct page *page) -{ - struct address_space *mapping = page_mapping(page); - int ret = 0; - - BUG_ON(!PageLocked(page)); - - if (mapping && mapping_cap_account_dirty(mapping)) { - struct inode *inode = mapping->host; - struct bdi_writeback *wb; - bool locked; - - /* - * Yes, Virginia, this is indeed insane. - * - * We use this sequence to make sure that - * (a) we account for dirty stats properly - * (b) we tell the low-level filesystem to - * mark the whole page dirty if it was - * dirty in a pagetable. Only to then - * (c) clean the page again and return 1 to - * cause the writeback. - * - * This way we avoid all nasty races with the - * dirty bit in multiple places and clearing - * them concurrently from different threads. - * - * Note! Normally the "set_page_dirty(page)" - * has no effect on the actual dirty bit - since - * that will already usually be set. But we - * need the side effects, and it can help us - * avoid races. - * - * We basically use the page "master dirty bit" - * as a serialization point for all the different - * threads doing their things. - */ - if (page_mkclean(page)) - set_page_dirty(page); - /* - * We carefully synchronise fault handlers against - * installing a dirty pte and marking the page dirty - * at this point. We do this by having them hold the - * page lock while dirtying the page, and pages are - * always locked coming in here, so we get the desired - * exclusion. - */ - wb = unlocked_inode_to_wb_begin(inode, &locked); - if (TestClearPageDirty(page)) { - mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_DIRTY); - dec_node_page_state(page, NR_FILE_DIRTY); - dec_zone_page_state(page, NR_ZONE_WRITE_PENDING); - dec_wb_stat(wb, WB_RECLAIMABLE); - ret = 1; - } - unlocked_inode_to_wb_end(inode, locked); - return ret; - } - return TestClearPageDirty(page); -} -EXPORT_SYMBOL(clear_page_dirty_for_io); - -int test_clear_page_writeback(struct page *page) -{ - struct address_space *mapping = page_mapping(page); - int ret; - - lock_page_memcg(page); - if (mapping && mapping_use_writeback_tags(mapping)) { - struct inode *inode = mapping->host; - struct backing_dev_info *bdi = inode_to_bdi(inode); - unsigned long flags; - - spin_lock_irqsave(&mapping->tree_lock, flags); - ret = TestClearPageWriteback(page); - if (ret) { - radix_tree_tag_clear(&mapping->page_tree, - page_index(page), - PAGECACHE_TAG_WRITEBACK); - if (bdi_cap_account_writeback(bdi)) { - struct bdi_writeback *wb = inode_to_wb(inode); - - __dec_wb_stat(wb, WB_WRITEBACK); - __wb_writeout_inc(wb); - } - } - - if (mapping->host && !mapping_tagged(mapping, - PAGECACHE_TAG_WRITEBACK)) - sb_clear_inode_writeback(mapping->host); - - spin_unlock_irqrestore(&mapping->tree_lock, flags); - } else { - ret = TestClearPageWriteback(page); - } - if (ret) { - mem_cgroup_dec_page_stat(page, MEM_CGROUP_STAT_WRITEBACK); - dec_node_page_state(page, NR_WRITEBACK); - dec_zone_page_state(page, NR_ZONE_WRITE_PENDING); - inc_node_page_state(page, NR_WRITTEN); - } - unlock_page_memcg(page); - return ret; -} - -int __test_set_page_writeback(struct page *page, bool keep_write) -{ - struct address_space *mapping = page_mapping(page); - int ret; - - lock_page_memcg(page); - if (mapping && mapping_use_writeback_tags(mapping)) { - struct inode *inode = mapping->host; - struct backing_dev_info *bdi = inode_to_bdi(inode); - unsigned long flags; - - spin_lock_irqsave(&mapping->tree_lock, flags); - ret = TestSetPageWriteback(page); - if (!ret) { - bool on_wblist; - - on_wblist = mapping_tagged(mapping, - PAGECACHE_TAG_WRITEBACK); - - radix_tree_tag_set(&mapping->page_tree, - page_index(page), - PAGECACHE_TAG_WRITEBACK); - if (bdi_cap_account_writeback(bdi)) - __inc_wb_stat(inode_to_wb(inode), WB_WRITEBACK); - - /* - * We can come through here when swapping anonymous - * pages, so we don't necessarily have an inode to track - * for sync. - */ - if (mapping->host && !on_wblist) - sb_mark_inode_writeback(mapping->host); - } - if (!PageDirty(page)) - radix_tree_tag_clear(&mapping->page_tree, - page_index(page), - PAGECACHE_TAG_DIRTY); - if (!keep_write) - radix_tree_tag_clear(&mapping->page_tree, - page_index(page), - PAGECACHE_TAG_TOWRITE); - spin_unlock_irqrestore(&mapping->tree_lock, flags); - } else { - ret = TestSetPageWriteback(page); - } - if (!ret) { - mem_cgroup_inc_page_stat(page, MEM_CGROUP_STAT_WRITEBACK); - inc_node_page_state(page, NR_WRITEBACK); - inc_zone_page_state(page, NR_ZONE_WRITE_PENDING); - } - unlock_page_memcg(page); - return ret; - -} -EXPORT_SYMBOL(__test_set_page_writeback); - -/* - * Return true if any of the pages in the mapping are marked with the - * passed tag. - */ -int mapping_tagged(struct address_space *mapping, int tag) -{ - return radix_tree_tagged(&mapping->page_tree, tag); -} -EXPORT_SYMBOL(mapping_tagged); - -/** - * wait_for_stable_page() - wait for writeback to finish, if necessary. - * @page: The page to wait on. - * - * This function determines if the given page is related to a backing device - * that requires page contents to be held stable during writeback. If so, then - * it will wait for any pending writeback to complete. - */ -void wait_for_stable_page(struct page *page) -{ - if (bdi_cap_stable_pages_required(inode_to_bdi(page->mapping->host))) - wait_on_page_writeback(page); -} -EXPORT_SYMBOL_GPL(wait_for_stable_page); diff --git a/src/linux/mm/page_alloc.c b/src/linux/mm/page_alloc.c deleted file mode 100644 index 6de9440..0000000 --- a/src/linux/mm/page_alloc.c +++ /dev/null @@ -1,7439 +0,0 @@ -/* - * linux/mm/page_alloc.c - * - * Manages the free list, the system allocates free pages here. - * Note that kmalloc() lives in slab.c - * - * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds - * Swap reorganised 29.12.95, Stephen Tweedie - * Support of BIGMEM added by Gerhard Wichert, Siemens AG, July 1999 - * Reshaped it to be a zoned allocator, Ingo Molnar, Red Hat, 1999 - * Discontiguous memory support, Kanoj Sarcar, SGI, Nov 1999 - * Zone balancing, Kanoj Sarcar, SGI, Jan 2000 - * Per cpu hot/cold page lists, bulk allocation, Martin J. Bligh, Sept 2002 - * (lots of bits borrowed from Ingo Molnar & Andrew Morton) - */ - -#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 -#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 "internal.h" - -/* prevent >1 _updater_ of zone percpu pageset ->high and ->batch fields */ -static DEFINE_MUTEX(pcp_batch_high_lock); -#define MIN_PERCPU_PAGELIST_FRACTION (8) - -#ifdef CONFIG_USE_PERCPU_NUMA_NODE_ID -DEFINE_PER_CPU(int, numa_node); -EXPORT_PER_CPU_SYMBOL(numa_node); -#endif - -#ifdef CONFIG_HAVE_MEMORYLESS_NODES -/* - * N.B., Do NOT reference the '_numa_mem_' per cpu variable directly. - * It will not be defined when CONFIG_HAVE_MEMORYLESS_NODES is not defined. - * Use the accessor functions set_numa_mem(), numa_mem_id() and cpu_to_mem() - * defined in . - */ -DEFINE_PER_CPU(int, _numa_mem_); /* Kernel "local memory" node */ -EXPORT_PER_CPU_SYMBOL(_numa_mem_); -int _node_numa_mem_[MAX_NUMNODES]; -#endif - -#ifdef CONFIG_GCC_PLUGIN_LATENT_ENTROPY -volatile unsigned long latent_entropy __latent_entropy; -EXPORT_SYMBOL(latent_entropy); -#endif - -/* - * Array of node states. - */ -nodemask_t node_states[NR_NODE_STATES] __read_mostly = { - [N_POSSIBLE] = NODE_MASK_ALL, - [N_ONLINE] = { { [0] = 1UL } }, -#ifndef CONFIG_NUMA - [N_NORMAL_MEMORY] = { { [0] = 1UL } }, -#ifdef CONFIG_HIGHMEM - [N_HIGH_MEMORY] = { { [0] = 1UL } }, -#endif -#ifdef CONFIG_MOVABLE_NODE - [N_MEMORY] = { { [0] = 1UL } }, -#endif - [N_CPU] = { { [0] = 1UL } }, -#endif /* NUMA */ -}; -EXPORT_SYMBOL(node_states); - -/* Protect totalram_pages and zone->managed_pages */ -static DEFINE_SPINLOCK(managed_page_count_lock); - -unsigned long totalram_pages __read_mostly; -unsigned long totalreserve_pages __read_mostly; -unsigned long totalcma_pages __read_mostly; - -int percpu_pagelist_fraction; -gfp_t gfp_allowed_mask __read_mostly = GFP_BOOT_MASK; - -/* - * A cached value of the page's pageblock's migratetype, used when the page is - * put on a pcplist. Used to avoid the pageblock migratetype lookup when - * freeing from pcplists in most cases, at the cost of possibly becoming stale. - * Also the migratetype set in the page does not necessarily match the pcplist - * index, e.g. page might have MIGRATE_CMA set but be on a pcplist with any - * other index - this ensures that it will be put on the correct CMA freelist. - */ -static inline int get_pcppage_migratetype(struct page *page) -{ - return page->index; -} - -static inline void set_pcppage_migratetype(struct page *page, int migratetype) -{ - page->index = migratetype; -} - -#ifdef CONFIG_PM_SLEEP -/* - * The following functions are used by the suspend/hibernate code to temporarily - * change gfp_allowed_mask in order to avoid using I/O during memory allocations - * while devices are suspended. To avoid races with the suspend/hibernate code, - * they should always be called with pm_mutex held (gfp_allowed_mask also should - * only be modified with pm_mutex held, unless the suspend/hibernate code is - * guaranteed not to run in parallel with that modification). - */ - -static gfp_t saved_gfp_mask; - -void pm_restore_gfp_mask(void) -{ - WARN_ON(!mutex_is_locked(&pm_mutex)); - if (saved_gfp_mask) { - gfp_allowed_mask = saved_gfp_mask; - saved_gfp_mask = 0; - } -} - -void pm_restrict_gfp_mask(void) -{ - WARN_ON(!mutex_is_locked(&pm_mutex)); - WARN_ON(saved_gfp_mask); - saved_gfp_mask = gfp_allowed_mask; - gfp_allowed_mask &= ~(__GFP_IO | __GFP_FS); -} - -bool pm_suspended_storage(void) -{ - if ((gfp_allowed_mask & (__GFP_IO | __GFP_FS)) == (__GFP_IO | __GFP_FS)) - return false; - return true; -} -#endif /* CONFIG_PM_SLEEP */ - -#ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE -unsigned int pageblock_order __read_mostly; -#endif - -static void __free_pages_ok(struct page *page, unsigned int order); - -/* - * results with 256, 32 in the lowmem_reserve sysctl: - * 1G machine -> (16M dma, 800M-16M normal, 1G-800M high) - * 1G machine -> (16M dma, 784M normal, 224M high) - * NORMAL allocation will leave 784M/256 of ram reserved in the ZONE_DMA - * HIGHMEM allocation will leave 224M/32 of ram reserved in ZONE_NORMAL - * HIGHMEM allocation will leave (224M+784M)/256 of ram reserved in ZONE_DMA - * - * TBD: should special case ZONE_DMA32 machines here - in those we normally - * don't need any ZONE_NORMAL reservation - */ -int sysctl_lowmem_reserve_ratio[MAX_NR_ZONES-1] = { -#ifdef CONFIG_ZONE_DMA - 256, -#endif -#ifdef CONFIG_ZONE_DMA32 - 256, -#endif -#ifdef CONFIG_HIGHMEM - 32, -#endif - 32, -}; - -EXPORT_SYMBOL(totalram_pages); - -static char * const zone_names[MAX_NR_ZONES] = { -#ifdef CONFIG_ZONE_DMA - "DMA", -#endif -#ifdef CONFIG_ZONE_DMA32 - "DMA32", -#endif - "Normal", -#ifdef CONFIG_HIGHMEM - "HighMem", -#endif - "Movable", -#ifdef CONFIG_ZONE_DEVICE - "Device", -#endif -}; - -char * const migratetype_names[MIGRATE_TYPES] = { - "Unmovable", - "Movable", - "Reclaimable", - "HighAtomic", -#ifdef CONFIG_CMA - "CMA", -#endif -#ifdef CONFIG_MEMORY_ISOLATION - "Isolate", -#endif -}; - -compound_page_dtor * const compound_page_dtors[] = { - NULL, - free_compound_page, -#ifdef CONFIG_HUGETLB_PAGE - free_huge_page, -#endif -#ifdef CONFIG_TRANSPARENT_HUGEPAGE - free_transhuge_page, -#endif -}; - -int min_free_kbytes = 1024; -int user_min_free_kbytes = -1; -int watermark_scale_factor = 10; - -static unsigned long __meminitdata nr_kernel_pages; -static unsigned long __meminitdata nr_all_pages; -static unsigned long __meminitdata dma_reserve; - -#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP -static unsigned long __meminitdata arch_zone_lowest_possible_pfn[MAX_NR_ZONES]; -static unsigned long __meminitdata arch_zone_highest_possible_pfn[MAX_NR_ZONES]; -static unsigned long __initdata required_kernelcore; -static unsigned long __initdata required_movablecore; -static unsigned long __meminitdata zone_movable_pfn[MAX_NUMNODES]; -static bool mirrored_kernelcore; - -/* movable_zone is the "real" zone pages in ZONE_MOVABLE are taken from */ -int movable_zone; -EXPORT_SYMBOL(movable_zone); -#endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */ - -#if MAX_NUMNODES > 1 -int nr_node_ids __read_mostly = MAX_NUMNODES; -int nr_online_nodes __read_mostly = 1; -EXPORT_SYMBOL(nr_node_ids); -EXPORT_SYMBOL(nr_online_nodes); -#endif - -int page_group_by_mobility_disabled __read_mostly; - -#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT -static inline void reset_deferred_meminit(pg_data_t *pgdat) -{ - pgdat->first_deferred_pfn = ULONG_MAX; -} - -/* Returns true if the struct page for the pfn is uninitialised */ -static inline bool __meminit early_page_uninitialised(unsigned long pfn) -{ - int nid = early_pfn_to_nid(pfn); - - if (node_online(nid) && pfn >= NODE_DATA(nid)->first_deferred_pfn) - return true; - - return false; -} - -/* - * Returns false when the remaining initialisation should be deferred until - * later in the boot cycle when it can be parallelised. - */ -static inline bool update_defer_init(pg_data_t *pgdat, - unsigned long pfn, unsigned long zone_end, - unsigned long *nr_initialised) -{ - unsigned long max_initialise; - - /* Always populate low zones for address-contrained allocations */ - if (zone_end < pgdat_end_pfn(pgdat)) - return true; - /* - * Initialise at least 2G of a node but also take into account that - * two large system hashes that can take up 1GB for 0.25TB/node. - */ - max_initialise = max(2UL << (30 - PAGE_SHIFT), - (pgdat->node_spanned_pages >> 8)); - - (*nr_initialised)++; - if ((*nr_initialised > max_initialise) && - (pfn & (PAGES_PER_SECTION - 1)) == 0) { - pgdat->first_deferred_pfn = pfn; - return false; - } - - return true; -} -#else -static inline void reset_deferred_meminit(pg_data_t *pgdat) -{ -} - -static inline bool early_page_uninitialised(unsigned long pfn) -{ - return false; -} - -static inline bool update_defer_init(pg_data_t *pgdat, - unsigned long pfn, unsigned long zone_end, - unsigned long *nr_initialised) -{ - return true; -} -#endif - -/* Return a pointer to the bitmap storing bits affecting a block of pages */ -static inline unsigned long *get_pageblock_bitmap(struct page *page, - unsigned long pfn) -{ -#ifdef CONFIG_SPARSEMEM - return __pfn_to_section(pfn)->pageblock_flags; -#else - return page_zone(page)->pageblock_flags; -#endif /* CONFIG_SPARSEMEM */ -} - -static inline int pfn_to_bitidx(struct page *page, unsigned long pfn) -{ -#ifdef CONFIG_SPARSEMEM - pfn &= (PAGES_PER_SECTION-1); - return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS; -#else - pfn = pfn - round_down(page_zone(page)->zone_start_pfn, pageblock_nr_pages); - return (pfn >> pageblock_order) * NR_PAGEBLOCK_BITS; -#endif /* CONFIG_SPARSEMEM */ -} - -/** - * get_pfnblock_flags_mask - Return the requested group of flags for the pageblock_nr_pages block of pages - * @page: The page within the block of interest - * @pfn: The target page frame number - * @end_bitidx: The last bit of interest to retrieve - * @mask: mask of bits that the caller is interested in - * - * Return: pageblock_bits flags - */ -static __always_inline unsigned long __get_pfnblock_flags_mask(struct page *page, - unsigned long pfn, - unsigned long end_bitidx, - unsigned long mask) -{ - unsigned long *bitmap; - unsigned long bitidx, word_bitidx; - unsigned long word; - - bitmap = get_pageblock_bitmap(page, pfn); - bitidx = pfn_to_bitidx(page, pfn); - word_bitidx = bitidx / BITS_PER_LONG; - bitidx &= (BITS_PER_LONG-1); - - word = bitmap[word_bitidx]; - bitidx += end_bitidx; - return (word >> (BITS_PER_LONG - bitidx - 1)) & mask; -} - -unsigned long get_pfnblock_flags_mask(struct page *page, unsigned long pfn, - unsigned long end_bitidx, - unsigned long mask) -{ - return __get_pfnblock_flags_mask(page, pfn, end_bitidx, mask); -} - -static __always_inline int get_pfnblock_migratetype(struct page *page, unsigned long pfn) -{ - return __get_pfnblock_flags_mask(page, pfn, PB_migrate_end, MIGRATETYPE_MASK); -} - -/** - * set_pfnblock_flags_mask - Set the requested group of flags for a pageblock_nr_pages block of pages - * @page: The page within the block of interest - * @flags: The flags to set - * @pfn: The target page frame number - * @end_bitidx: The last bit of interest - * @mask: mask of bits that the caller is interested in - */ -void set_pfnblock_flags_mask(struct page *page, unsigned long flags, - unsigned long pfn, - unsigned long end_bitidx, - unsigned long mask) -{ - unsigned long *bitmap; - unsigned long bitidx, word_bitidx; - unsigned long old_word, word; - - BUILD_BUG_ON(NR_PAGEBLOCK_BITS != 4); - - bitmap = get_pageblock_bitmap(page, pfn); - bitidx = pfn_to_bitidx(page, pfn); - word_bitidx = bitidx / BITS_PER_LONG; - bitidx &= (BITS_PER_LONG-1); - - VM_BUG_ON_PAGE(!zone_spans_pfn(page_zone(page), pfn), page); - - bitidx += end_bitidx; - mask <<= (BITS_PER_LONG - bitidx - 1); - flags <<= (BITS_PER_LONG - bitidx - 1); - - word = READ_ONCE(bitmap[word_bitidx]); - for (;;) { - old_word = cmpxchg(&bitmap[word_bitidx], word, (word & ~mask) | flags); - if (word == old_word) - break; - word = old_word; - } -} - -void set_pageblock_migratetype(struct page *page, int migratetype) -{ - if (unlikely(page_group_by_mobility_disabled && - migratetype < MIGRATE_PCPTYPES)) - migratetype = MIGRATE_UNMOVABLE; - - set_pageblock_flags_group(page, (unsigned long)migratetype, - PB_migrate, PB_migrate_end); -} - -#ifdef CONFIG_DEBUG_VM -static int page_outside_zone_boundaries(struct zone *zone, struct page *page) -{ - int ret = 0; - unsigned seq; - unsigned long pfn = page_to_pfn(page); - unsigned long sp, start_pfn; - - do { - seq = zone_span_seqbegin(zone); - start_pfn = zone->zone_start_pfn; - sp = zone->spanned_pages; - if (!zone_spans_pfn(zone, pfn)) - ret = 1; - } while (zone_span_seqretry(zone, seq)); - - if (ret) - pr_err("page 0x%lx outside node %d zone %s [ 0x%lx - 0x%lx ]\n", - pfn, zone_to_nid(zone), zone->name, - start_pfn, start_pfn + sp); - - return ret; -} - -static int page_is_consistent(struct zone *zone, struct page *page) -{ - if (!pfn_valid_within(page_to_pfn(page))) - return 0; - if (zone != page_zone(page)) - return 0; - - return 1; -} -/* - * Temporary debugging check for pages not lying within a given zone. - */ -static int bad_range(struct zone *zone, struct page *page) -{ - if (page_outside_zone_boundaries(zone, page)) - return 1; - if (!page_is_consistent(zone, page)) - return 1; - - return 0; -} -#else -static inline int bad_range(struct zone *zone, struct page *page) -{ - return 0; -} -#endif - -static void bad_page(struct page *page, const char *reason, - unsigned long bad_flags) -{ - static unsigned long resume; - static unsigned long nr_shown; - static unsigned long nr_unshown; - - /* - * Allow a burst of 60 reports, then keep quiet for that minute; - * or allow a steady drip of one report per second. - */ - if (nr_shown == 60) { - if (time_before(jiffies, resume)) { - nr_unshown++; - goto out; - } - if (nr_unshown) { - pr_alert( - "BUG: Bad page state: %lu messages suppressed\n", - nr_unshown); - nr_unshown = 0; - } - nr_shown = 0; - } - if (nr_shown++ == 0) - resume = jiffies + 60 * HZ; - - pr_alert("BUG: Bad page state in process %s pfn:%05lx\n", - current->comm, page_to_pfn(page)); - __dump_page(page, reason); - bad_flags &= page->flags; - if (bad_flags) - pr_alert("bad because of flags: %#lx(%pGp)\n", - bad_flags, &bad_flags); - dump_page_owner(page); - - print_modules(); - dump_stack(); -out: - /* Leave bad fields for debug, except PageBuddy could make trouble */ - page_mapcount_reset(page); /* remove PageBuddy */ - add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE); -} - -/* - * Higher-order pages are called "compound pages". They are structured thusly: - * - * The first PAGE_SIZE page is called the "head page" and have PG_head set. - * - * The remaining PAGE_SIZE pages are called "tail pages". PageTail() is encoded - * in bit 0 of page->compound_head. The rest of bits is pointer to head page. - * - * The first tail page's ->compound_dtor holds the offset in array of compound - * page destructors. See compound_page_dtors. - * - * The first tail page's ->compound_order holds the order of allocation. - * This usage means that zero-order pages may not be compound. - */ - -void free_compound_page(struct page *page) -{ - __free_pages_ok(page, compound_order(page)); -} - -void prep_compound_page(struct page *page, unsigned int order) -{ - int i; - int nr_pages = 1 << order; - - set_compound_page_dtor(page, COMPOUND_PAGE_DTOR); - set_compound_order(page, order); - __SetPageHead(page); - for (i = 1; i < nr_pages; i++) { - struct page *p = page + i; - set_page_count(p, 0); - p->mapping = TAIL_MAPPING; - set_compound_head(p, page); - } - atomic_set(compound_mapcount_ptr(page), -1); -} - -#ifdef CONFIG_DEBUG_PAGEALLOC -unsigned int _debug_guardpage_minorder; -bool _debug_pagealloc_enabled __read_mostly - = IS_ENABLED(CONFIG_DEBUG_PAGEALLOC_ENABLE_DEFAULT); -EXPORT_SYMBOL(_debug_pagealloc_enabled); -bool _debug_guardpage_enabled __read_mostly; - -static int __init early_debug_pagealloc(char *buf) -{ - if (!buf) - return -EINVAL; - return kstrtobool(buf, &_debug_pagealloc_enabled); -} -early_param("debug_pagealloc", early_debug_pagealloc); - -static bool need_debug_guardpage(void) -{ - /* If we don't use debug_pagealloc, we don't need guard page */ - if (!debug_pagealloc_enabled()) - return false; - - if (!debug_guardpage_minorder()) - return false; - - return true; -} - -static void init_debug_guardpage(void) -{ - if (!debug_pagealloc_enabled()) - return; - - if (!debug_guardpage_minorder()) - return; - - _debug_guardpage_enabled = true; -} - -struct page_ext_operations debug_guardpage_ops = { - .need = need_debug_guardpage, - .init = init_debug_guardpage, -}; - -static int __init debug_guardpage_minorder_setup(char *buf) -{ - unsigned long res; - - if (kstrtoul(buf, 10, &res) < 0 || res > MAX_ORDER / 2) { - pr_err("Bad debug_guardpage_minorder value\n"); - return 0; - } - _debug_guardpage_minorder = res; - pr_info("Setting debug_guardpage_minorder to %lu\n", res); - return 0; -} -early_param("debug_guardpage_minorder", debug_guardpage_minorder_setup); - -static inline bool set_page_guard(struct zone *zone, struct page *page, - unsigned int order, int migratetype) -{ - struct page_ext *page_ext; - - if (!debug_guardpage_enabled()) - return false; - - if (order >= debug_guardpage_minorder()) - return false; - - page_ext = lookup_page_ext(page); - if (unlikely(!page_ext)) - return false; - - __set_bit(PAGE_EXT_DEBUG_GUARD, &page_ext->flags); - - INIT_LIST_HEAD(&page->lru); - set_page_private(page, order); - /* Guard pages are not available for any usage */ - __mod_zone_freepage_state(zone, -(1 << order), migratetype); - - return true; -} - -static inline void clear_page_guard(struct zone *zone, struct page *page, - unsigned int order, int migratetype) -{ - struct page_ext *page_ext; - - if (!debug_guardpage_enabled()) - return; - - page_ext = lookup_page_ext(page); - if (unlikely(!page_ext)) - return; - - __clear_bit(PAGE_EXT_DEBUG_GUARD, &page_ext->flags); - - set_page_private(page, 0); - if (!is_migrate_isolate(migratetype)) - __mod_zone_freepage_state(zone, (1 << order), migratetype); -} -#else -struct page_ext_operations debug_guardpage_ops; -static inline bool set_page_guard(struct zone *zone, struct page *page, - unsigned int order, int migratetype) { return false; } -static inline void clear_page_guard(struct zone *zone, struct page *page, - unsigned int order, int migratetype) {} -#endif - -static inline void set_page_order(struct page *page, unsigned int order) -{ - set_page_private(page, order); - __SetPageBuddy(page); -} - -static inline void rmv_page_order(struct page *page) -{ - __ClearPageBuddy(page); - set_page_private(page, 0); -} - -/* - * This function checks whether a page is free && is the buddy - * we can do coalesce a page and its buddy if - * (a) the buddy is not in a hole && - * (b) the buddy is in the buddy system && - * (c) a page and its buddy have the same order && - * (d) a page and its buddy are in the same zone. - * - * For recording whether a page is in the buddy system, we set ->_mapcount - * PAGE_BUDDY_MAPCOUNT_VALUE. - * Setting, clearing, and testing _mapcount PAGE_BUDDY_MAPCOUNT_VALUE is - * serialized by zone->lock. - * - * For recording page's order, we use page_private(page). - */ -static inline int page_is_buddy(struct page *page, struct page *buddy, - unsigned int order) -{ - if (!pfn_valid_within(page_to_pfn(buddy))) - return 0; - - if (page_is_guard(buddy) && page_order(buddy) == order) { - if (page_zone_id(page) != page_zone_id(buddy)) - return 0; - - VM_BUG_ON_PAGE(page_count(buddy) != 0, buddy); - - return 1; - } - - if (PageBuddy(buddy) && page_order(buddy) == order) { - /* - * zone check is done late to avoid uselessly - * calculating zone/node ids for pages that could - * never merge. - */ - if (page_zone_id(page) != page_zone_id(buddy)) - return 0; - - VM_BUG_ON_PAGE(page_count(buddy) != 0, buddy); - - return 1; - } - return 0; -} - -/* - * Freeing function for a buddy system allocator. - * - * The concept of a buddy system is to maintain direct-mapped table - * (containing bit values) for memory blocks of various "orders". - * The bottom level table contains the map for the smallest allocatable - * units of memory (here, pages), and each level above it describes - * pairs of units from the levels below, hence, "buddies". - * At a high level, all that happens here is marking the table entry - * at the bottom level available, and propagating the changes upward - * as necessary, plus some accounting needed to play nicely with other - * parts of the VM system. - * At each level, we keep a list of pages, which are heads of continuous - * free pages of length of (1 << order) and marked with _mapcount - * PAGE_BUDDY_MAPCOUNT_VALUE. Page's order is recorded in page_private(page) - * field. - * So when we are allocating or freeing one, we can derive the state of the - * other. That is, if we allocate a small block, and both were - * free, the remainder of the region must be split into blocks. - * If a block is freed, and its buddy is also free, then this - * triggers coalescing into a block of larger size. - * - * -- nyc - */ - -static inline void __free_one_page(struct page *page, - unsigned long pfn, - struct zone *zone, unsigned int order, - int migratetype) -{ - unsigned long page_idx; - unsigned long combined_idx; - unsigned long uninitialized_var(buddy_idx); - struct page *buddy; - unsigned int max_order; - - max_order = min_t(unsigned int, MAX_ORDER, pageblock_order + 1); - - VM_BUG_ON(!zone_is_initialized(zone)); - VM_BUG_ON_PAGE(page->flags & PAGE_FLAGS_CHECK_AT_PREP, page); - - VM_BUG_ON(migratetype == -1); - if (likely(!is_migrate_isolate(migratetype))) - __mod_zone_freepage_state(zone, 1 << order, migratetype); - - page_idx = pfn & ((1 << MAX_ORDER) - 1); - - VM_BUG_ON_PAGE(page_idx & ((1 << order) - 1), page); - VM_BUG_ON_PAGE(bad_range(zone, page), page); - -continue_merging: - while (order < max_order - 1) { - buddy_idx = __find_buddy_index(page_idx, order); - buddy = page + (buddy_idx - page_idx); - if (!page_is_buddy(page, buddy, order)) - goto done_merging; - /* - * Our buddy is free or it is CONFIG_DEBUG_PAGEALLOC guard page, - * merge with it and move up one order. - */ - if (page_is_guard(buddy)) { - clear_page_guard(zone, buddy, order, migratetype); - } else { - list_del(&buddy->lru); - zone->free_area[order].nr_free--; - rmv_page_order(buddy); - } - combined_idx = buddy_idx & page_idx; - page = page + (combined_idx - page_idx); - page_idx = combined_idx; - order++; - } - if (max_order < MAX_ORDER) { - /* If we are here, it means order is >= pageblock_order. - * We want to prevent merge between freepages on isolate - * pageblock and normal pageblock. Without this, pageblock - * isolation could cause incorrect freepage or CMA accounting. - * - * We don't want to hit this code for the more frequent - * low-order merging. - */ - if (unlikely(has_isolate_pageblock(zone))) { - int buddy_mt; - - buddy_idx = __find_buddy_index(page_idx, order); - buddy = page + (buddy_idx - page_idx); - buddy_mt = get_pageblock_migratetype(buddy); - - if (migratetype != buddy_mt - && (is_migrate_isolate(migratetype) || - is_migrate_isolate(buddy_mt))) - goto done_merging; - } - max_order++; - goto continue_merging; - } - -done_merging: - set_page_order(page, order); - - /* - * If this is not the largest possible page, check if the buddy - * of the next-highest order is free. If it is, it's possible - * that pages are being freed that will coalesce soon. In case, - * that is happening, add the free page to the tail of the list - * so it's less likely to be used soon and more likely to be merged - * as a higher order page - */ - if ((order < MAX_ORDER-2) && pfn_valid_within(page_to_pfn(buddy))) { - struct page *higher_page, *higher_buddy; - combined_idx = buddy_idx & page_idx; - higher_page = page + (combined_idx - page_idx); - buddy_idx = __find_buddy_index(combined_idx, order + 1); - higher_buddy = higher_page + (buddy_idx - combined_idx); - if (page_is_buddy(higher_page, higher_buddy, order + 1)) { - list_add_tail(&page->lru, - &zone->free_area[order].free_list[migratetype]); - goto out; - } - } - - list_add(&page->lru, &zone->free_area[order].free_list[migratetype]); -out: - zone->free_area[order].nr_free++; -} - -/* - * A bad page could be due to a number of fields. Instead of multiple branches, - * try and check multiple fields with one check. The caller must do a detailed - * check if necessary. - */ -static inline bool page_expected_state(struct page *page, - unsigned long check_flags) -{ - if (unlikely(atomic_read(&page->_mapcount) != -1)) - return false; - - if (unlikely((unsigned long)page->mapping | - page_ref_count(page) | -#ifdef CONFIG_MEMCG - (unsigned long)page->mem_cgroup | -#endif - (page->flags & check_flags))) - return false; - - return true; -} - -static void free_pages_check_bad(struct page *page) -{ - const char *bad_reason; - unsigned long bad_flags; - - bad_reason = NULL; - bad_flags = 0; - - if (unlikely(atomic_read(&page->_mapcount) != -1)) - bad_reason = "nonzero mapcount"; - if (unlikely(page->mapping != NULL)) - bad_reason = "non-NULL mapping"; - if (unlikely(page_ref_count(page) != 0)) - bad_reason = "nonzero _refcount"; - if (unlikely(page->flags & PAGE_FLAGS_CHECK_AT_FREE)) { - bad_reason = "PAGE_FLAGS_CHECK_AT_FREE flag(s) set"; - bad_flags = PAGE_FLAGS_CHECK_AT_FREE; - } -#ifdef CONFIG_MEMCG - if (unlikely(page->mem_cgroup)) - bad_reason = "page still charged to cgroup"; -#endif - bad_page(page, bad_reason, bad_flags); -} - -static inline int free_pages_check(struct page *page) -{ - if (likely(page_expected_state(page, PAGE_FLAGS_CHECK_AT_FREE))) - return 0; - - /* Something has gone sideways, find it */ - free_pages_check_bad(page); - return 1; -} - -static int free_tail_pages_check(struct page *head_page, struct page *page) -{ - int ret = 1; - - /* - * We rely page->lru.next never has bit 0 set, unless the page - * is PageTail(). Let's make sure that's true even for poisoned ->lru. - */ - BUILD_BUG_ON((unsigned long)LIST_POISON1 & 1); - - if (!IS_ENABLED(CONFIG_DEBUG_VM)) { - ret = 0; - goto out; - } - switch (page - head_page) { - case 1: - /* the first tail page: ->mapping is compound_mapcount() */ - if (unlikely(compound_mapcount(page))) { - bad_page(page, "nonzero compound_mapcount", 0); - goto out; - } - break; - case 2: - /* - * the second tail page: ->mapping is - * page_deferred_list().next -- ignore value. - */ - break; - default: - if (page->mapping != TAIL_MAPPING) { - bad_page(page, "corrupted mapping in tail page", 0); - goto out; - } - break; - } - if (unlikely(!PageTail(page))) { - bad_page(page, "PageTail not set", 0); - goto out; - } - if (unlikely(compound_head(page) != head_page)) { - bad_page(page, "compound_head not consistent", 0); - goto out; - } - ret = 0; -out: - page->mapping = NULL; - clear_compound_head(page); - return ret; -} - -static __always_inline bool free_pages_prepare(struct page *page, - unsigned int order, bool check_free) -{ - int bad = 0; - - VM_BUG_ON_PAGE(PageTail(page), page); - - trace_mm_page_free(page, order); - kmemcheck_free_shadow(page, order); - - /* - * Check tail pages before head page information is cleared to - * avoid checking PageCompound for order-0 pages. - */ - if (unlikely(order)) { - bool compound = PageCompound(page); - int i; - - VM_BUG_ON_PAGE(compound && compound_order(page) != order, page); - - if (compound) - ClearPageDoubleMap(page); - for (i = 1; i < (1 << order); i++) { - if (compound) - bad += free_tail_pages_check(page, page + i); - if (unlikely(free_pages_check(page + i))) { - bad++; - continue; - } - (page + i)->flags &= ~PAGE_FLAGS_CHECK_AT_PREP; - } - } - if (PageMappingFlags(page)) - page->mapping = NULL; - if (memcg_kmem_enabled() && PageKmemcg(page)) - memcg_kmem_uncharge(page, order); - if (check_free) - bad += free_pages_check(page); - if (bad) - return false; - - page_cpupid_reset_last(page); - page->flags &= ~PAGE_FLAGS_CHECK_AT_PREP; - reset_page_owner(page, order); - - if (!PageHighMem(page)) { - debug_check_no_locks_freed(page_address(page), - PAGE_SIZE << order); - debug_check_no_obj_freed(page_address(page), - PAGE_SIZE << order); - } - arch_free_page(page, order); - kernel_poison_pages(page, 1 << order, 0); - kernel_map_pages(page, 1 << order, 0); - kasan_free_pages(page, order); - - return true; -} - -#ifdef CONFIG_DEBUG_VM -static inline bool free_pcp_prepare(struct page *page) -{ - return free_pages_prepare(page, 0, true); -} - -static inline bool bulkfree_pcp_prepare(struct page *page) -{ - return false; -} -#else -static bool free_pcp_prepare(struct page *page) -{ - return free_pages_prepare(page, 0, false); -} - -static bool bulkfree_pcp_prepare(struct page *page) -{ - return free_pages_check(page); -} -#endif /* CONFIG_DEBUG_VM */ - -/* - * Frees a number of pages from the PCP lists - * Assumes all pages on list are in same zone, and of same order. - * count is the number of pages to free. - * - * If the zone was previously in an "all pages pinned" state then look to - * see if this freeing clears that state. - * - * And clear the zone's pages_scanned counter, to hold off the "all pages are - * pinned" detection logic. - */ -static void free_pcppages_bulk(struct zone *zone, int count, - struct per_cpu_pages *pcp) -{ - int migratetype = 0; - int batch_free = 0; - unsigned long nr_scanned; - bool isolated_pageblocks; - - spin_lock(&zone->lock); - isolated_pageblocks = has_isolate_pageblock(zone); - nr_scanned = node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED); - if (nr_scanned) - __mod_node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED, -nr_scanned); - - while (count) { - struct page *page; - struct list_head *list; - - /* - * Remove pages from lists in a round-robin fashion. A - * batch_free count is maintained that is incremented when an - * empty list is encountered. This is so more pages are freed - * off fuller lists instead of spinning excessively around empty - * lists - */ - do { - batch_free++; - if (++migratetype == MIGRATE_PCPTYPES) - migratetype = 0; - list = &pcp->lists[migratetype]; - } while (list_empty(list)); - - /* This is the only non-empty list. Free them all. */ - if (batch_free == MIGRATE_PCPTYPES) - batch_free = count; - - do { - int mt; /* migratetype of the to-be-freed page */ - - page = list_last_entry(list, struct page, lru); - /* must delete as __free_one_page list manipulates */ - list_del(&page->lru); - - mt = get_pcppage_migratetype(page); - /* MIGRATE_ISOLATE page should not go to pcplists */ - VM_BUG_ON_PAGE(is_migrate_isolate(mt), page); - /* Pageblock could have been isolated meanwhile */ - if (unlikely(isolated_pageblocks)) - mt = get_pageblock_migratetype(page); - - if (bulkfree_pcp_prepare(page)) - continue; - - __free_one_page(page, page_to_pfn(page), zone, 0, mt); - trace_mm_page_pcpu_drain(page, 0, mt); - } while (--count && --batch_free && !list_empty(list)); - } - spin_unlock(&zone->lock); -} - -static void free_one_page(struct zone *zone, - struct page *page, unsigned long pfn, - unsigned int order, - int migratetype) -{ - unsigned long nr_scanned; - spin_lock(&zone->lock); - nr_scanned = node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED); - if (nr_scanned) - __mod_node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED, -nr_scanned); - - if (unlikely(has_isolate_pageblock(zone) || - is_migrate_isolate(migratetype))) { - migratetype = get_pfnblock_migratetype(page, pfn); - } - __free_one_page(page, pfn, zone, order, migratetype); - spin_unlock(&zone->lock); -} - -static void __meminit __init_single_page(struct page *page, unsigned long pfn, - unsigned long zone, int nid) -{ - set_page_links(page, zone, nid, pfn); - init_page_count(page); - page_mapcount_reset(page); - page_cpupid_reset_last(page); - - INIT_LIST_HEAD(&page->lru); -#ifdef WANT_PAGE_VIRTUAL - /* The shift won't overflow because ZONE_NORMAL is below 4G. */ - if (!is_highmem_idx(zone)) - set_page_address(page, __va(pfn << PAGE_SHIFT)); -#endif -} - -static void __meminit __init_single_pfn(unsigned long pfn, unsigned long zone, - int nid) -{ - return __init_single_page(pfn_to_page(pfn), pfn, zone, nid); -} - -#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT -static void init_reserved_page(unsigned long pfn) -{ - pg_data_t *pgdat; - int nid, zid; - - if (!early_page_uninitialised(pfn)) - return; - - nid = early_pfn_to_nid(pfn); - pgdat = NODE_DATA(nid); - - for (zid = 0; zid < MAX_NR_ZONES; zid++) { - struct zone *zone = &pgdat->node_zones[zid]; - - if (pfn >= zone->zone_start_pfn && pfn < zone_end_pfn(zone)) - break; - } - __init_single_pfn(pfn, zid, nid); -} -#else -static inline void init_reserved_page(unsigned long pfn) -{ -} -#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */ - -/* - * Initialised pages do not have PageReserved set. This function is - * called for each range allocated by the bootmem allocator and - * marks the pages PageReserved. The remaining valid pages are later - * sent to the buddy page allocator. - */ -void __meminit reserve_bootmem_region(phys_addr_t start, phys_addr_t end) -{ - unsigned long start_pfn = PFN_DOWN(start); - unsigned long end_pfn = PFN_UP(end); - - for (; start_pfn < end_pfn; start_pfn++) { - if (pfn_valid(start_pfn)) { - struct page *page = pfn_to_page(start_pfn); - - init_reserved_page(start_pfn); - - /* Avoid false-positive PageTail() */ - INIT_LIST_HEAD(&page->lru); - - SetPageReserved(page); - } - } -} - -static void __free_pages_ok(struct page *page, unsigned int order) -{ - unsigned long flags; - int migratetype; - unsigned long pfn = page_to_pfn(page); - - if (!free_pages_prepare(page, order, true)) - return; - - migratetype = get_pfnblock_migratetype(page, pfn); - local_irq_save(flags); - __count_vm_events(PGFREE, 1 << order); - free_one_page(page_zone(page), page, pfn, order, migratetype); - local_irq_restore(flags); -} - -static void __init __free_pages_boot_core(struct page *page, unsigned int order) -{ - unsigned int nr_pages = 1 << order; - struct page *p = page; - unsigned int loop; - - prefetchw(p); - for (loop = 0; loop < (nr_pages - 1); loop++, p++) { - prefetchw(p + 1); - __ClearPageReserved(p); - set_page_count(p, 0); - } - __ClearPageReserved(p); - set_page_count(p, 0); - - page_zone(page)->managed_pages += nr_pages; - set_page_refcounted(page); - __free_pages(page, order); -} - -#if defined(CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID) || \ - defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP) - -static struct mminit_pfnnid_cache early_pfnnid_cache __meminitdata; - -int __meminit early_pfn_to_nid(unsigned long pfn) -{ - static DEFINE_SPINLOCK(early_pfn_lock); - int nid; - - spin_lock(&early_pfn_lock); - nid = __early_pfn_to_nid(pfn, &early_pfnnid_cache); - if (nid < 0) - nid = first_online_node; - spin_unlock(&early_pfn_lock); - - return nid; -} -#endif - -#ifdef CONFIG_NODES_SPAN_OTHER_NODES -static inline bool __meminit meminit_pfn_in_nid(unsigned long pfn, int node, - struct mminit_pfnnid_cache *state) -{ - int nid; - - nid = __early_pfn_to_nid(pfn, state); - if (nid >= 0 && nid != node) - return false; - return true; -} - -/* Only safe to use early in boot when initialisation is single-threaded */ -static inline bool __meminit early_pfn_in_nid(unsigned long pfn, int node) -{ - return meminit_pfn_in_nid(pfn, node, &early_pfnnid_cache); -} - -#else - -static inline bool __meminit early_pfn_in_nid(unsigned long pfn, int node) -{ - return true; -} -static inline bool __meminit meminit_pfn_in_nid(unsigned long pfn, int node, - struct mminit_pfnnid_cache *state) -{ - return true; -} -#endif - - -void __init __free_pages_bootmem(struct page *page, unsigned long pfn, - unsigned int order) -{ - if (early_page_uninitialised(pfn)) - return; - return __free_pages_boot_core(page, order); -} - -/* - * Check that the whole (or subset of) a pageblock given by the interval of - * [start_pfn, end_pfn) is valid and within the same zone, before scanning it - * with the migration of free compaction scanner. The scanners then need to - * use only pfn_valid_within() check for arches that allow holes within - * pageblocks. - * - * Return struct page pointer of start_pfn, or NULL if checks were not passed. - * - * It's possible on some configurations to have a setup like node0 node1 node0 - * i.e. it's possible that all pages within a zones range of pages do not - * belong to a single zone. We assume that a border between node0 and node1 - * can occur within a single pageblock, but not a node0 node1 node0 - * interleaving within a single pageblock. It is therefore sufficient to check - * the first and last page of a pageblock and avoid checking each individual - * page in a pageblock. - */ -struct page *__pageblock_pfn_to_page(unsigned long start_pfn, - unsigned long end_pfn, struct zone *zone) -{ - struct page *start_page; - struct page *end_page; - - /* end_pfn is one past the range we are checking */ - end_pfn--; - - if (!pfn_valid(start_pfn) || !pfn_valid(end_pfn)) - return NULL; - - start_page = pfn_to_page(start_pfn); - - if (page_zone(start_page) != zone) - return NULL; - - end_page = pfn_to_page(end_pfn); - - /* This gives a shorter code than deriving page_zone(end_page) */ - if (page_zone_id(start_page) != page_zone_id(end_page)) - return NULL; - - return start_page; -} - -void set_zone_contiguous(struct zone *zone) -{ - unsigned long block_start_pfn = zone->zone_start_pfn; - unsigned long block_end_pfn; - - block_end_pfn = ALIGN(block_start_pfn + 1, pageblock_nr_pages); - for (; block_start_pfn < zone_end_pfn(zone); - block_start_pfn = block_end_pfn, - block_end_pfn += pageblock_nr_pages) { - - block_end_pfn = min(block_end_pfn, zone_end_pfn(zone)); - - if (!__pageblock_pfn_to_page(block_start_pfn, - block_end_pfn, zone)) - return; - } - - /* We confirm that there is no hole */ - zone->contiguous = true; -} - -void clear_zone_contiguous(struct zone *zone) -{ - zone->contiguous = false; -} - -#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT -static void __init deferred_free_range(struct page *page, - unsigned long pfn, int nr_pages) -{ - int i; - - if (!page) - return; - - /* Free a large naturally-aligned chunk if possible */ - if (nr_pages == pageblock_nr_pages && - (pfn & (pageblock_nr_pages - 1)) == 0) { - set_pageblock_migratetype(page, MIGRATE_MOVABLE); - __free_pages_boot_core(page, pageblock_order); - return; - } - - for (i = 0; i < nr_pages; i++, page++, pfn++) { - if ((pfn & (pageblock_nr_pages - 1)) == 0) - set_pageblock_migratetype(page, MIGRATE_MOVABLE); - __free_pages_boot_core(page, 0); - } -} - -/* Completion tracking for deferred_init_memmap() threads */ -static atomic_t pgdat_init_n_undone __initdata; -static __initdata DECLARE_COMPLETION(pgdat_init_all_done_comp); - -static inline void __init pgdat_init_report_one_done(void) -{ - if (atomic_dec_and_test(&pgdat_init_n_undone)) - complete(&pgdat_init_all_done_comp); -} - -/* Initialise remaining memory on a node */ -static int __init deferred_init_memmap(void *data) -{ - pg_data_t *pgdat = data; - int nid = pgdat->node_id; - struct mminit_pfnnid_cache nid_init_state = { }; - unsigned long start = jiffies; - unsigned long nr_pages = 0; - unsigned long walk_start, walk_end; - int i, zid; - struct zone *zone; - unsigned long first_init_pfn = pgdat->first_deferred_pfn; - const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id); - - if (first_init_pfn == ULONG_MAX) { - pgdat_init_report_one_done(); - return 0; - } - - /* Bind memory initialisation thread to a local node if possible */ - if (!cpumask_empty(cpumask)) - set_cpus_allowed_ptr(current, cpumask); - - /* Sanity check boundaries */ - BUG_ON(pgdat->first_deferred_pfn < pgdat->node_start_pfn); - BUG_ON(pgdat->first_deferred_pfn > pgdat_end_pfn(pgdat)); - pgdat->first_deferred_pfn = ULONG_MAX; - - /* Only the highest zone is deferred so find it */ - for (zid = 0; zid < MAX_NR_ZONES; zid++) { - zone = pgdat->node_zones + zid; - if (first_init_pfn < zone_end_pfn(zone)) - break; - } - - for_each_mem_pfn_range(i, nid, &walk_start, &walk_end, NULL) { - unsigned long pfn, end_pfn; - struct page *page = NULL; - struct page *free_base_page = NULL; - unsigned long free_base_pfn = 0; - int nr_to_free = 0; - - end_pfn = min(walk_end, zone_end_pfn(zone)); - pfn = first_init_pfn; - if (pfn < walk_start) - pfn = walk_start; - if (pfn < zone->zone_start_pfn) - pfn = zone->zone_start_pfn; - - for (; pfn < end_pfn; pfn++) { - if (!pfn_valid_within(pfn)) - goto free_range; - - /* - * Ensure pfn_valid is checked every - * pageblock_nr_pages for memory holes - */ - if ((pfn & (pageblock_nr_pages - 1)) == 0) { - if (!pfn_valid(pfn)) { - page = NULL; - goto free_range; - } - } - - if (!meminit_pfn_in_nid(pfn, nid, &nid_init_state)) { - page = NULL; - goto free_range; - } - - /* Minimise pfn page lookups and scheduler checks */ - if (page && (pfn & (pageblock_nr_pages - 1)) != 0) { - page++; - } else { - nr_pages += nr_to_free; - deferred_free_range(free_base_page, - free_base_pfn, nr_to_free); - free_base_page = NULL; - free_base_pfn = nr_to_free = 0; - - page = pfn_to_page(pfn); - cond_resched(); - } - - if (page->flags) { - VM_BUG_ON(page_zone(page) != zone); - goto free_range; - } - - __init_single_page(page, pfn, zid, nid); - if (!free_base_page) { - free_base_page = page; - free_base_pfn = pfn; - nr_to_free = 0; - } - nr_to_free++; - - /* Where possible, batch up pages for a single free */ - continue; -free_range: - /* Free the current block of pages to allocator */ - nr_pages += nr_to_free; - deferred_free_range(free_base_page, free_base_pfn, - nr_to_free); - free_base_page = NULL; - free_base_pfn = nr_to_free = 0; - } - /* Free the last block of pages to allocator */ - nr_pages += nr_to_free; - deferred_free_range(free_base_page, free_base_pfn, nr_to_free); - - first_init_pfn = max(end_pfn, first_init_pfn); - } - - /* Sanity check that the next zone really is unpopulated */ - WARN_ON(++zid < MAX_NR_ZONES && populated_zone(++zone)); - - pr_info("node %d initialised, %lu pages in %ums\n", nid, nr_pages, - jiffies_to_msecs(jiffies - start)); - - pgdat_init_report_one_done(); - return 0; -} -#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */ - -void __init page_alloc_init_late(void) -{ - struct zone *zone; - -#ifdef CONFIG_DEFERRED_STRUCT_PAGE_INIT - int nid; - - /* There will be num_node_state(N_MEMORY) threads */ - atomic_set(&pgdat_init_n_undone, num_node_state(N_MEMORY)); - for_each_node_state(nid, N_MEMORY) { - kthread_run(deferred_init_memmap, NODE_DATA(nid), "pgdatinit%d", nid); - } - - /* Block until all are initialised */ - wait_for_completion(&pgdat_init_all_done_comp); - - /* Reinit limits that are based on free pages after the kernel is up */ - files_maxfiles_init(); -#endif - - for_each_populated_zone(zone) - set_zone_contiguous(zone); -} - -#ifdef CONFIG_CMA -/* Free whole pageblock and set its migration type to MIGRATE_CMA. */ -void __init init_cma_reserved_pageblock(struct page *page) -{ - unsigned i = pageblock_nr_pages; - struct page *p = page; - - do { - __ClearPageReserved(p); - set_page_count(p, 0); - } while (++p, --i); - - set_pageblock_migratetype(page, MIGRATE_CMA); - - if (pageblock_order >= MAX_ORDER) { - i = pageblock_nr_pages; - p = page; - do { - set_page_refcounted(p); - __free_pages(p, MAX_ORDER - 1); - p += MAX_ORDER_NR_PAGES; - } while (i -= MAX_ORDER_NR_PAGES); - } else { - set_page_refcounted(page); - __free_pages(page, pageblock_order); - } - - adjust_managed_page_count(page, pageblock_nr_pages); -} -#endif - -/* - * The order of subdivision here is critical for the IO subsystem. - * Please do not alter this order without good reasons and regression - * testing. Specifically, as large blocks of memory are subdivided, - * the order in which smaller blocks are delivered depends on the order - * they're subdivided in this function. This is the primary factor - * influencing the order in which pages are delivered to the IO - * subsystem according to empirical testing, and this is also justified - * by considering the behavior of a buddy system containing a single - * large block of memory acted on by a series of small allocations. - * This behavior is a critical factor in sglist merging's success. - * - * -- nyc - */ -static inline void expand(struct zone *zone, struct page *page, - int low, int high, struct free_area *area, - int migratetype) -{ - unsigned long size = 1 << high; - - while (high > low) { - area--; - high--; - size >>= 1; - VM_BUG_ON_PAGE(bad_range(zone, &page[size]), &page[size]); - - /* - * Mark as guard pages (or page), that will allow to - * merge back to allocator when buddy will be freed. - * Corresponding page table entries will not be touched, - * pages will stay not present in virtual address space - */ - if (set_page_guard(zone, &page[size], high, migratetype)) - continue; - - list_add(&page[size].lru, &area->free_list[migratetype]); - area->nr_free++; - set_page_order(&page[size], high); - } -} - -static void check_new_page_bad(struct page *page) -{ - const char *bad_reason = NULL; - unsigned long bad_flags = 0; - - if (unlikely(atomic_read(&page->_mapcount) != -1)) - bad_reason = "nonzero mapcount"; - if (unlikely(page->mapping != NULL)) - bad_reason = "non-NULL mapping"; - if (unlikely(page_ref_count(page) != 0)) - bad_reason = "nonzero _count"; - if (unlikely(page->flags & __PG_HWPOISON)) { - bad_reason = "HWPoisoned (hardware-corrupted)"; - bad_flags = __PG_HWPOISON; - /* Don't complain about hwpoisoned pages */ - page_mapcount_reset(page); /* remove PageBuddy */ - return; - } - if (unlikely(page->flags & PAGE_FLAGS_CHECK_AT_PREP)) { - bad_reason = "PAGE_FLAGS_CHECK_AT_PREP flag set"; - bad_flags = PAGE_FLAGS_CHECK_AT_PREP; - } -#ifdef CONFIG_MEMCG - if (unlikely(page->mem_cgroup)) - bad_reason = "page still charged to cgroup"; -#endif - bad_page(page, bad_reason, bad_flags); -} - -/* - * This page is about to be returned from the page allocator - */ -static inline int check_new_page(struct page *page) -{ - if (likely(page_expected_state(page, - PAGE_FLAGS_CHECK_AT_PREP|__PG_HWPOISON))) - return 0; - - check_new_page_bad(page); - return 1; -} - -static inline bool free_pages_prezeroed(bool poisoned) -{ - return IS_ENABLED(CONFIG_PAGE_POISONING_ZERO) && - page_poisoning_enabled() && poisoned; -} - -#ifdef CONFIG_DEBUG_VM -static bool check_pcp_refill(struct page *page) -{ - return false; -} - -static bool check_new_pcp(struct page *page) -{ - return check_new_page(page); -} -#else -static bool check_pcp_refill(struct page *page) -{ - return check_new_page(page); -} -static bool check_new_pcp(struct page *page) -{ - return false; -} -#endif /* CONFIG_DEBUG_VM */ - -static bool check_new_pages(struct page *page, unsigned int order) -{ - int i; - for (i = 0; i < (1 << order); i++) { - struct page *p = page + i; - - if (unlikely(check_new_page(p))) - return true; - } - - return false; -} - -inline void post_alloc_hook(struct page *page, unsigned int order, - gfp_t gfp_flags) -{ - set_page_private(page, 0); - set_page_refcounted(page); - - arch_alloc_page(page, order); - kernel_map_pages(page, 1 << order, 1); - kernel_poison_pages(page, 1 << order, 1); - kasan_alloc_pages(page, order); - set_page_owner(page, order, gfp_flags); -} - -static void prep_new_page(struct page *page, unsigned int order, gfp_t gfp_flags, - unsigned int alloc_flags) -{ - int i; - bool poisoned = true; - - for (i = 0; i < (1 << order); i++) { - struct page *p = page + i; - if (poisoned) - poisoned &= page_is_poisoned(p); - } - - post_alloc_hook(page, order, gfp_flags); - - if (!free_pages_prezeroed(poisoned) && (gfp_flags & __GFP_ZERO)) - for (i = 0; i < (1 << order); i++) - clear_highpage(page + i); - - if (order && (gfp_flags & __GFP_COMP)) - prep_compound_page(page, order); - - /* - * page is set pfmemalloc when ALLOC_NO_WATERMARKS was necessary to - * allocate the page. The expectation is that the caller is taking - * steps that will free more memory. The caller should avoid the page - * being used for !PFMEMALLOC purposes. - */ - if (alloc_flags & ALLOC_NO_WATERMARKS) - set_page_pfmemalloc(page); - else - clear_page_pfmemalloc(page); -} - -/* - * Go through the free lists for the given migratetype and remove - * the smallest available page from the freelists - */ -static inline -struct page *__rmqueue_smallest(struct zone *zone, unsigned int order, - int migratetype) -{ - unsigned int current_order; - struct free_area *area; - struct page *page; - - /* Find a page of the appropriate size in the preferred list */ - for (current_order = order; current_order < MAX_ORDER; ++current_order) { - area = &(zone->free_area[current_order]); - page = list_first_entry_or_null(&area->free_list[migratetype], - struct page, lru); - if (!page) - continue; - list_del(&page->lru); - rmv_page_order(page); - area->nr_free--; - expand(zone, page, order, current_order, area, migratetype); - set_pcppage_migratetype(page, migratetype); - return page; - } - - return NULL; -} - - -/* - * This array describes the order lists are fallen back to when - * the free lists for the desirable migrate type are depleted - */ -static int fallbacks[MIGRATE_TYPES][4] = { - [MIGRATE_UNMOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_MOVABLE, MIGRATE_TYPES }, - [MIGRATE_RECLAIMABLE] = { MIGRATE_UNMOVABLE, MIGRATE_MOVABLE, MIGRATE_TYPES }, - [MIGRATE_MOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_UNMOVABLE, MIGRATE_TYPES }, -#ifdef CONFIG_CMA - [MIGRATE_CMA] = { MIGRATE_TYPES }, /* Never used */ -#endif -#ifdef CONFIG_MEMORY_ISOLATION - [MIGRATE_ISOLATE] = { MIGRATE_TYPES }, /* Never used */ -#endif -}; - -#ifdef CONFIG_CMA -static struct page *__rmqueue_cma_fallback(struct zone *zone, - unsigned int order) -{ - return __rmqueue_smallest(zone, order, MIGRATE_CMA); -} -#else -static inline struct page *__rmqueue_cma_fallback(struct zone *zone, - unsigned int order) { return NULL; } -#endif - -/* - * Move the free pages in a range to the free lists of the requested type. - * Note that start_page and end_pages are not aligned on a pageblock - * boundary. If alignment is required, use move_freepages_block() - */ -int move_freepages(struct zone *zone, - struct page *start_page, struct page *end_page, - int migratetype) -{ - struct page *page; - unsigned int order; - int pages_moved = 0; - -#ifndef CONFIG_HOLES_IN_ZONE - /* - * page_zone is not safe to call in this context when - * CONFIG_HOLES_IN_ZONE is set. This bug check is probably redundant - * anyway as we check zone boundaries in move_freepages_block(). - * Remove at a later date when no bug reports exist related to - * grouping pages by mobility - */ - VM_BUG_ON(page_zone(start_page) != page_zone(end_page)); -#endif - - for (page = start_page; page <= end_page;) { - /* Make sure we are not inadvertently changing nodes */ - VM_BUG_ON_PAGE(page_to_nid(page) != zone_to_nid(zone), page); - - if (!pfn_valid_within(page_to_pfn(page))) { - page++; - continue; - } - - if (!PageBuddy(page)) { - page++; - continue; - } - - order = page_order(page); - list_move(&page->lru, - &zone->free_area[order].free_list[migratetype]); - page += 1 << order; - pages_moved += 1 << order; - } - - return pages_moved; -} - -int move_freepages_block(struct zone *zone, struct page *page, - int migratetype) -{ - unsigned long start_pfn, end_pfn; - struct page *start_page, *end_page; - - start_pfn = page_to_pfn(page); - start_pfn = start_pfn & ~(pageblock_nr_pages-1); - start_page = pfn_to_page(start_pfn); - end_page = start_page + pageblock_nr_pages - 1; - end_pfn = start_pfn + pageblock_nr_pages - 1; - - /* Do not cross zone boundaries */ - if (!zone_spans_pfn(zone, start_pfn)) - start_page = page; - if (!zone_spans_pfn(zone, end_pfn)) - return 0; - - return move_freepages(zone, start_page, end_page, migratetype); -} - -static void change_pageblock_range(struct page *pageblock_page, - int start_order, int migratetype) -{ - int nr_pageblocks = 1 << (start_order - pageblock_order); - - while (nr_pageblocks--) { - set_pageblock_migratetype(pageblock_page, migratetype); - pageblock_page += pageblock_nr_pages; - } -} - -/* - * When we are falling back to another migratetype during allocation, try to - * steal extra free pages from the same pageblocks to satisfy further - * allocations, instead of polluting multiple pageblocks. - * - * If we are stealing a relatively large buddy page, it is likely there will - * be more free pages in the pageblock, so try to steal them all. For - * reclaimable and unmovable allocations, we steal regardless of page size, - * as fragmentation caused by those allocations polluting movable pageblocks - * is worse than movable allocations stealing from unmovable and reclaimable - * pageblocks. - */ -static bool can_steal_fallback(unsigned int order, int start_mt) -{ - /* - * Leaving this order check is intended, although there is - * relaxed order check in next check. The reason is that - * we can actually steal whole pageblock if this condition met, - * but, below check doesn't guarantee it and that is just heuristic - * so could be changed anytime. - */ - if (order >= pageblock_order) - return true; - - if (order >= pageblock_order / 2 || - start_mt == MIGRATE_RECLAIMABLE || - start_mt == MIGRATE_UNMOVABLE || - page_group_by_mobility_disabled) - return true; - - return false; -} - -/* - * This function implements actual steal behaviour. If order is large enough, - * we can steal whole pageblock. If not, we first move freepages in this - * pageblock and check whether half of pages are moved or not. If half of - * pages are moved, we can change migratetype of pageblock and permanently - * use it's pages as requested migratetype in the future. - */ -static void steal_suitable_fallback(struct zone *zone, struct page *page, - int start_type) -{ - unsigned int current_order = page_order(page); - int pages; - - /* Take ownership for orders >= pageblock_order */ - if (current_order >= pageblock_order) { - change_pageblock_range(page, current_order, start_type); - return; - } - - pages = move_freepages_block(zone, page, start_type); - - /* Claim the whole block if over half of it is free */ - if (pages >= (1 << (pageblock_order-1)) || - page_group_by_mobility_disabled) - set_pageblock_migratetype(page, start_type); -} - -/* - * Check whether there is a suitable fallback freepage with requested order. - * If only_stealable is true, this function returns fallback_mt only if - * we can steal other freepages all together. This would help to reduce - * fragmentation due to mixed migratetype pages in one pageblock. - */ -int find_suitable_fallback(struct free_area *area, unsigned int order, - int migratetype, bool only_stealable, bool *can_steal) -{ - int i; - int fallback_mt; - - if (area->nr_free == 0) - return -1; - - *can_steal = false; - for (i = 0;; i++) { - fallback_mt = fallbacks[migratetype][i]; - if (fallback_mt == MIGRATE_TYPES) - break; - - if (list_empty(&area->free_list[fallback_mt])) - continue; - - if (can_steal_fallback(order, migratetype)) - *can_steal = true; - - if (!only_stealable) - return fallback_mt; - - if (*can_steal) - return fallback_mt; - } - - return -1; -} - -/* - * Reserve a pageblock for exclusive use of high-order atomic allocations if - * there are no empty page blocks that contain a page with a suitable order - */ -static void reserve_highatomic_pageblock(struct page *page, struct zone *zone, - unsigned int alloc_order) -{ - int mt; - unsigned long max_managed, flags; - - /* - * Limit the number reserved to 1 pageblock or roughly 1% of a zone. - * Check is race-prone but harmless. - */ - max_managed = (zone->managed_pages / 100) + pageblock_nr_pages; - if (zone->nr_reserved_highatomic >= max_managed) - return; - - spin_lock_irqsave(&zone->lock, flags); - - /* Recheck the nr_reserved_highatomic limit under the lock */ - if (zone->nr_reserved_highatomic >= max_managed) - goto out_unlock; - - /* Yoink! */ - mt = get_pageblock_migratetype(page); - if (mt != MIGRATE_HIGHATOMIC && - !is_migrate_isolate(mt) && !is_migrate_cma(mt)) { - zone->nr_reserved_highatomic += pageblock_nr_pages; - set_pageblock_migratetype(page, MIGRATE_HIGHATOMIC); - move_freepages_block(zone, page, MIGRATE_HIGHATOMIC); - } - -out_unlock: - spin_unlock_irqrestore(&zone->lock, flags); -} - -/* - * Used when an allocation is about to fail under memory pressure. This - * potentially hurts the reliability of high-order allocations when under - * intense memory pressure but failed atomic allocations should be easier - * to recover from than an OOM. - */ -static void unreserve_highatomic_pageblock(const struct alloc_context *ac) -{ - struct zonelist *zonelist = ac->zonelist; - unsigned long flags; - struct zoneref *z; - struct zone *zone; - struct page *page; - int order; - - for_each_zone_zonelist_nodemask(zone, z, zonelist, ac->high_zoneidx, - ac->nodemask) { - /* Preserve at least one pageblock */ - if (zone->nr_reserved_highatomic <= pageblock_nr_pages) - continue; - - spin_lock_irqsave(&zone->lock, flags); - for (order = 0; order < MAX_ORDER; order++) { - struct free_area *area = &(zone->free_area[order]); - - page = list_first_entry_or_null( - &area->free_list[MIGRATE_HIGHATOMIC], - struct page, lru); - if (!page) - continue; - - /* - * It should never happen but changes to locking could - * inadvertently allow a per-cpu drain to add pages - * to MIGRATE_HIGHATOMIC while unreserving so be safe - * and watch for underflows. - */ - zone->nr_reserved_highatomic -= min(pageblock_nr_pages, - zone->nr_reserved_highatomic); - - /* - * Convert to ac->migratetype and avoid the normal - * pageblock stealing heuristics. Minimally, the caller - * is doing the work and needs the pages. More - * importantly, if the block was always converted to - * MIGRATE_UNMOVABLE or another type then the number - * of pageblocks that cannot be completely freed - * may increase. - */ - set_pageblock_migratetype(page, ac->migratetype); - move_freepages_block(zone, page, ac->migratetype); - spin_unlock_irqrestore(&zone->lock, flags); - return; - } - spin_unlock_irqrestore(&zone->lock, flags); - } -} - -/* Remove an element from the buddy allocator from the fallback list */ -static inline struct page * -__rmqueue_fallback(struct zone *zone, unsigned int order, int start_migratetype) -{ - struct free_area *area; - unsigned int current_order; - struct page *page; - int fallback_mt; - bool can_steal; - - /* Find the largest possible block of pages in the other list */ - for (current_order = MAX_ORDER-1; - current_order >= order && current_order <= MAX_ORDER-1; - --current_order) { - area = &(zone->free_area[current_order]); - fallback_mt = find_suitable_fallback(area, current_order, - start_migratetype, false, &can_steal); - if (fallback_mt == -1) - continue; - - page = list_first_entry(&area->free_list[fallback_mt], - struct page, lru); - if (can_steal) - steal_suitable_fallback(zone, page, start_migratetype); - - /* Remove the page from the freelists */ - area->nr_free--; - list_del(&page->lru); - rmv_page_order(page); - - expand(zone, page, order, current_order, area, - start_migratetype); - /* - * The pcppage_migratetype may differ from pageblock's - * migratetype depending on the decisions in - * find_suitable_fallback(). This is OK as long as it does not - * differ for MIGRATE_CMA pageblocks. Those can be used as - * fallback only via special __rmqueue_cma_fallback() function - */ - set_pcppage_migratetype(page, start_migratetype); - - trace_mm_page_alloc_extfrag(page, order, current_order, - start_migratetype, fallback_mt); - - return page; - } - - return NULL; -} - -/* - * Do the hard work of removing an element from the buddy allocator. - * Call me with the zone->lock already held. - */ -static struct page *__rmqueue(struct zone *zone, unsigned int order, - int migratetype) -{ - struct page *page; - - page = __rmqueue_smallest(zone, order, migratetype); - if (unlikely(!page)) { - if (migratetype == MIGRATE_MOVABLE) - page = __rmqueue_cma_fallback(zone, order); - - if (!page) - page = __rmqueue_fallback(zone, order, migratetype); - } - - trace_mm_page_alloc_zone_locked(page, order, migratetype); - return page; -} - -/* - * Obtain a specified number of elements from the buddy allocator, all under - * a single hold of the lock, for efficiency. Add them to the supplied list. - * Returns the number of new pages which were placed at *list. - */ -static int rmqueue_bulk(struct zone *zone, unsigned int order, - unsigned long count, struct list_head *list, - int migratetype, bool cold) -{ - int i; - - spin_lock(&zone->lock); - for (i = 0; i < count; ++i) { - struct page *page = __rmqueue(zone, order, migratetype); - if (unlikely(page == NULL)) - break; - - if (unlikely(check_pcp_refill(page))) - continue; - - /* - * Split buddy pages returned by expand() are received here - * in physical page order. The page is added to the callers and - * list and the list head then moves forward. From the callers - * perspective, the linked list is ordered by page number in - * some conditions. This is useful for IO devices that can - * merge IO requests if the physical pages are ordered - * properly. - */ - if (likely(!cold)) - list_add(&page->lru, list); - else - list_add_tail(&page->lru, list); - list = &page->lru; - if (is_migrate_cma(get_pcppage_migratetype(page))) - __mod_zone_page_state(zone, NR_FREE_CMA_PAGES, - -(1 << order)); - } - __mod_zone_page_state(zone, NR_FREE_PAGES, -(i << order)); - spin_unlock(&zone->lock); - return i; -} - -#ifdef CONFIG_NUMA -/* - * Called from the vmstat counter updater to drain pagesets of this - * currently executing processor on remote nodes after they have - * expired. - * - * Note that this function must be called with the thread pinned to - * a single processor. - */ -void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp) -{ - unsigned long flags; - int to_drain, batch; - - local_irq_save(flags); - batch = READ_ONCE(pcp->batch); - to_drain = min(pcp->count, batch); - if (to_drain > 0) { - free_pcppages_bulk(zone, to_drain, pcp); - pcp->count -= to_drain; - } - local_irq_restore(flags); -} -#endif - -/* - * Drain pcplists of the indicated processor and zone. - * - * The processor must either be the current processor and the - * thread pinned to the current processor or a processor that - * is not online. - */ -static void drain_pages_zone(unsigned int cpu, struct zone *zone) -{ - unsigned long flags; - struct per_cpu_pageset *pset; - struct per_cpu_pages *pcp; - - local_irq_save(flags); - pset = per_cpu_ptr(zone->pageset, cpu); - - pcp = &pset->pcp; - if (pcp->count) { - free_pcppages_bulk(zone, pcp->count, pcp); - pcp->count = 0; - } - local_irq_restore(flags); -} - -/* - * Drain pcplists of all zones on the indicated processor. - * - * The processor must either be the current processor and the - * thread pinned to the current processor or a processor that - * is not online. - */ -static void drain_pages(unsigned int cpu) -{ - struct zone *zone; - - for_each_populated_zone(zone) { - drain_pages_zone(cpu, zone); - } -} - -/* - * Spill all of this CPU's per-cpu pages back into the buddy allocator. - * - * The CPU has to be pinned. When zone parameter is non-NULL, spill just - * the single zone's pages. - */ -void drain_local_pages(struct zone *zone) -{ - int cpu = smp_processor_id(); - - if (zone) - drain_pages_zone(cpu, zone); - else - drain_pages(cpu); -} - -/* - * Spill all the per-cpu pages from all CPUs back into the buddy allocator. - * - * When zone parameter is non-NULL, spill just the single zone's pages. - * - * Note that this code is protected against sending an IPI to an offline - * CPU but does not guarantee sending an IPI to newly hotplugged CPUs: - * on_each_cpu_mask() blocks hotplug and won't talk to offlined CPUs but - * nothing keeps CPUs from showing up after we populated the cpumask and - * before the call to on_each_cpu_mask(). - */ -void drain_all_pages(struct zone *zone) -{ - int cpu; - - /* - * Allocate in the BSS so we wont require allocation in - * direct reclaim path for CONFIG_CPUMASK_OFFSTACK=y - */ - static cpumask_t cpus_with_pcps; - - /* - * We don't care about racing with CPU hotplug event - * as offline notification will cause the notified - * cpu to drain that CPU pcps and on_each_cpu_mask - * disables preemption as part of its processing - */ - for_each_online_cpu(cpu) { - struct per_cpu_pageset *pcp; - struct zone *z; - bool has_pcps = false; - - if (zone) { - pcp = per_cpu_ptr(zone->pageset, cpu); - if (pcp->pcp.count) - has_pcps = true; - } else { - for_each_populated_zone(z) { - pcp = per_cpu_ptr(z->pageset, cpu); - if (pcp->pcp.count) { - has_pcps = true; - break; - } - } - } - - if (has_pcps) - cpumask_set_cpu(cpu, &cpus_with_pcps); - else - cpumask_clear_cpu(cpu, &cpus_with_pcps); - } - on_each_cpu_mask(&cpus_with_pcps, (smp_call_func_t) drain_local_pages, - zone, 1); -} - -#ifdef CONFIG_HIBERNATION - -void mark_free_pages(struct zone *zone) -{ - unsigned long pfn, max_zone_pfn; - unsigned long flags; - unsigned int order, t; - struct page *page; - - if (zone_is_empty(zone)) - return; - - spin_lock_irqsave(&zone->lock, flags); - - max_zone_pfn = zone_end_pfn(zone); - for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++) - if (pfn_valid(pfn)) { - page = pfn_to_page(pfn); - - if (page_zone(page) != zone) - continue; - - if (!swsusp_page_is_forbidden(page)) - swsusp_unset_page_free(page); - } - - for_each_migratetype_order(order, t) { - list_for_each_entry(page, - &zone->free_area[order].free_list[t], lru) { - unsigned long i; - - pfn = page_to_pfn(page); - for (i = 0; i < (1UL << order); i++) - swsusp_set_page_free(pfn_to_page(pfn + i)); - } - } - spin_unlock_irqrestore(&zone->lock, flags); -} -#endif /* CONFIG_PM */ - -/* - * Free a 0-order page - * cold == true ? free a cold page : free a hot page - */ -void free_hot_cold_page(struct page *page, bool cold) -{ - struct zone *zone = page_zone(page); - struct per_cpu_pages *pcp; - unsigned long flags; - unsigned long pfn = page_to_pfn(page); - int migratetype; - - if (!free_pcp_prepare(page)) - return; - - migratetype = get_pfnblock_migratetype(page, pfn); - set_pcppage_migratetype(page, migratetype); - local_irq_save(flags); - __count_vm_event(PGFREE); - - /* - * We only track unmovable, reclaimable and movable on pcp lists. - * Free ISOLATE pages back to the allocator because they are being - * offlined but treat RESERVE as movable pages so we can get those - * areas back if necessary. Otherwise, we may have to free - * excessively into the page allocator - */ - if (migratetype >= MIGRATE_PCPTYPES) { - if (unlikely(is_migrate_isolate(migratetype))) { - free_one_page(zone, page, pfn, 0, migratetype); - goto out; - } - migratetype = MIGRATE_MOVABLE; - } - - pcp = &this_cpu_ptr(zone->pageset)->pcp; - if (!cold) - list_add(&page->lru, &pcp->lists[migratetype]); - else - list_add_tail(&page->lru, &pcp->lists[migratetype]); - pcp->count++; - if (pcp->count >= pcp->high) { - unsigned long batch = READ_ONCE(pcp->batch); - free_pcppages_bulk(zone, batch, pcp); - pcp->count -= batch; - } - -out: - local_irq_restore(flags); -} - -/* - * Free a list of 0-order pages - */ -void free_hot_cold_page_list(struct list_head *list, bool cold) -{ - struct page *page, *next; - - list_for_each_entry_safe(page, next, list, lru) { - trace_mm_page_free_batched(page, cold); - free_hot_cold_page(page, cold); - } -} - -/* - * split_page takes a non-compound higher-order page, and splits it into - * n (1<lru); - zone->free_area[order].nr_free--; - rmv_page_order(page); - - /* - * Set the pageblock if the isolated page is at least half of a - * pageblock - */ - if (order >= pageblock_order - 1) { - struct page *endpage = page + (1 << order) - 1; - for (; page < endpage; page += pageblock_nr_pages) { - int mt = get_pageblock_migratetype(page); - if (!is_migrate_isolate(mt) && !is_migrate_cma(mt)) - set_pageblock_migratetype(page, - MIGRATE_MOVABLE); - } - } - - - return 1UL << order; -} - -/* - * Update NUMA hit/miss statistics - * - * Must be called with interrupts disabled. - * - * When __GFP_OTHER_NODE is set assume the node of the preferred - * zone is the local node. This is useful for daemons who allocate - * memory on behalf of other processes. - */ -static inline void zone_statistics(struct zone *preferred_zone, struct zone *z, - gfp_t flags) -{ -#ifdef CONFIG_NUMA - int local_nid = numa_node_id(); - enum zone_stat_item local_stat = NUMA_LOCAL; - - if (unlikely(flags & __GFP_OTHER_NODE)) { - local_stat = NUMA_OTHER; - local_nid = preferred_zone->node; - } - - if (z->node == local_nid) { - __inc_zone_state(z, NUMA_HIT); - __inc_zone_state(z, local_stat); - } else { - __inc_zone_state(z, NUMA_MISS); - __inc_zone_state(preferred_zone, NUMA_FOREIGN); - } -#endif -} - -/* - * Allocate a page from the given zone. Use pcplists for order-0 allocations. - */ -static inline -struct page *buffered_rmqueue(struct zone *preferred_zone, - struct zone *zone, unsigned int order, - gfp_t gfp_flags, unsigned int alloc_flags, - int migratetype) -{ - unsigned long flags; - struct page *page; - bool cold = ((gfp_flags & __GFP_COLD) != 0); - - if (likely(order == 0)) { - struct per_cpu_pages *pcp; - struct list_head *list; - - local_irq_save(flags); - do { - pcp = &this_cpu_ptr(zone->pageset)->pcp; - list = &pcp->lists[migratetype]; - if (list_empty(list)) { - pcp->count += rmqueue_bulk(zone, 0, - pcp->batch, list, - migratetype, cold); - if (unlikely(list_empty(list))) - goto failed; - } - - if (cold) - page = list_last_entry(list, struct page, lru); - else - page = list_first_entry(list, struct page, lru); - - list_del(&page->lru); - pcp->count--; - - } while (check_new_pcp(page)); - } else { - /* - * We most definitely don't want callers attempting to - * allocate greater than order-1 page units with __GFP_NOFAIL. - */ - WARN_ON_ONCE((gfp_flags & __GFP_NOFAIL) && (order > 1)); - spin_lock_irqsave(&zone->lock, flags); - - do { - page = NULL; - if (alloc_flags & ALLOC_HARDER) { - page = __rmqueue_smallest(zone, order, MIGRATE_HIGHATOMIC); - if (page) - trace_mm_page_alloc_zone_locked(page, order, migratetype); - } - if (!page) - page = __rmqueue(zone, order, migratetype); - } while (page && check_new_pages(page, order)); - spin_unlock(&zone->lock); - if (!page) - goto failed; - __mod_zone_freepage_state(zone, -(1 << order), - get_pcppage_migratetype(page)); - } - - __count_zid_vm_events(PGALLOC, page_zonenum(page), 1 << order); - zone_statistics(preferred_zone, zone, gfp_flags); - local_irq_restore(flags); - - VM_BUG_ON_PAGE(bad_range(zone, page), page); - return page; - -failed: - local_irq_restore(flags); - return NULL; -} - -#ifdef CONFIG_FAIL_PAGE_ALLOC - -static struct { - struct fault_attr attr; - - bool ignore_gfp_highmem; - bool ignore_gfp_reclaim; - u32 min_order; -} fail_page_alloc = { - .attr = FAULT_ATTR_INITIALIZER, - .ignore_gfp_reclaim = true, - .ignore_gfp_highmem = true, - .min_order = 1, -}; - -static int __init setup_fail_page_alloc(char *str) -{ - return setup_fault_attr(&fail_page_alloc.attr, str); -} -__setup("fail_page_alloc=", setup_fail_page_alloc); - -static bool should_fail_alloc_page(gfp_t gfp_mask, unsigned int order) -{ - if (order < fail_page_alloc.min_order) - return false; - if (gfp_mask & __GFP_NOFAIL) - return false; - if (fail_page_alloc.ignore_gfp_highmem && (gfp_mask & __GFP_HIGHMEM)) - return false; - if (fail_page_alloc.ignore_gfp_reclaim && - (gfp_mask & __GFP_DIRECT_RECLAIM)) - return false; - - return should_fail(&fail_page_alloc.attr, 1 << order); -} - -#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS - -static int __init fail_page_alloc_debugfs(void) -{ - umode_t mode = S_IFREG | S_IRUSR | S_IWUSR; - struct dentry *dir; - - dir = fault_create_debugfs_attr("fail_page_alloc", NULL, - &fail_page_alloc.attr); - if (IS_ERR(dir)) - return PTR_ERR(dir); - - if (!debugfs_create_bool("ignore-gfp-wait", mode, dir, - &fail_page_alloc.ignore_gfp_reclaim)) - goto fail; - if (!debugfs_create_bool("ignore-gfp-highmem", mode, dir, - &fail_page_alloc.ignore_gfp_highmem)) - goto fail; - if (!debugfs_create_u32("min-order", mode, dir, - &fail_page_alloc.min_order)) - goto fail; - - return 0; -fail: - debugfs_remove_recursive(dir); - - return -ENOMEM; -} - -late_initcall(fail_page_alloc_debugfs); - -#endif /* CONFIG_FAULT_INJECTION_DEBUG_FS */ - -#else /* CONFIG_FAIL_PAGE_ALLOC */ - -static inline bool should_fail_alloc_page(gfp_t gfp_mask, unsigned int order) -{ - return false; -} - -#endif /* CONFIG_FAIL_PAGE_ALLOC */ - -/* - * Return true if free base pages are above 'mark'. For high-order checks it - * will return true of the order-0 watermark is reached and there is at least - * one free page of a suitable size. Checking now avoids taking the zone lock - * to check in the allocation paths if no pages are free. - */ -bool __zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, - int classzone_idx, unsigned int alloc_flags, - long free_pages) -{ - long min = mark; - int o; - const bool alloc_harder = (alloc_flags & ALLOC_HARDER); - - /* free_pages may go negative - that's OK */ - free_pages -= (1 << order) - 1; - - if (alloc_flags & ALLOC_HIGH) - min -= min / 2; - - /* - * If the caller does not have rights to ALLOC_HARDER then subtract - * the high-atomic reserves. This will over-estimate the size of the - * atomic reserve but it avoids a search. - */ - if (likely(!alloc_harder)) - free_pages -= z->nr_reserved_highatomic; - else - min -= min / 4; - -#ifdef CONFIG_CMA - /* If allocation can't use CMA areas don't use free CMA pages */ - if (!(alloc_flags & ALLOC_CMA)) - free_pages -= zone_page_state(z, NR_FREE_CMA_PAGES); -#endif - - /* - * Check watermarks for an order-0 allocation request. If these - * are not met, then a high-order request also cannot go ahead - * even if a suitable page happened to be free. - */ - if (free_pages <= min + z->lowmem_reserve[classzone_idx]) - return false; - - /* If this is an order-0 request then the watermark is fine */ - if (!order) - return true; - - /* For a high-order request, check at least one suitable page is free */ - for (o = order; o < MAX_ORDER; o++) { - struct free_area *area = &z->free_area[o]; - int mt; - - if (!area->nr_free) - continue; - - if (alloc_harder) - return true; - - for (mt = 0; mt < MIGRATE_PCPTYPES; mt++) { - if (!list_empty(&area->free_list[mt])) - return true; - } - -#ifdef CONFIG_CMA - if ((alloc_flags & ALLOC_CMA) && - !list_empty(&area->free_list[MIGRATE_CMA])) { - return true; - } -#endif - } - return false; -} - -bool zone_watermark_ok(struct zone *z, unsigned int order, unsigned long mark, - int classzone_idx, unsigned int alloc_flags) -{ - return __zone_watermark_ok(z, order, mark, classzone_idx, alloc_flags, - zone_page_state(z, NR_FREE_PAGES)); -} - -static inline bool zone_watermark_fast(struct zone *z, unsigned int order, - unsigned long mark, int classzone_idx, unsigned int alloc_flags) -{ - long free_pages = zone_page_state(z, NR_FREE_PAGES); - long cma_pages = 0; - -#ifdef CONFIG_CMA - /* If allocation can't use CMA areas don't use free CMA pages */ - if (!(alloc_flags & ALLOC_CMA)) - cma_pages = zone_page_state(z, NR_FREE_CMA_PAGES); -#endif - - /* - * Fast check for order-0 only. If this fails then the reserves - * need to be calculated. There is a corner case where the check - * passes but only the high-order atomic reserve are free. If - * the caller is !atomic then it'll uselessly search the free - * list. That corner case is then slower but it is harmless. - */ - if (!order && (free_pages - cma_pages) > mark + z->lowmem_reserve[classzone_idx]) - return true; - - return __zone_watermark_ok(z, order, mark, classzone_idx, alloc_flags, - free_pages); -} - -bool zone_watermark_ok_safe(struct zone *z, unsigned int order, - unsigned long mark, int classzone_idx) -{ - long free_pages = zone_page_state(z, NR_FREE_PAGES); - - if (z->percpu_drift_mark && free_pages < z->percpu_drift_mark) - free_pages = zone_page_state_snapshot(z, NR_FREE_PAGES); - - return __zone_watermark_ok(z, order, mark, classzone_idx, 0, - free_pages); -} - -#ifdef CONFIG_NUMA -static bool zone_allows_reclaim(struct zone *local_zone, struct zone *zone) -{ - return node_distance(zone_to_nid(local_zone), zone_to_nid(zone)) < - RECLAIM_DISTANCE; -} -#else /* CONFIG_NUMA */ -static bool zone_allows_reclaim(struct zone *local_zone, struct zone *zone) -{ - return true; -} -#endif /* CONFIG_NUMA */ - -/* - * get_page_from_freelist goes through the zonelist trying to allocate - * a page. - */ -static struct page * -get_page_from_freelist(gfp_t gfp_mask, unsigned int order, int alloc_flags, - const struct alloc_context *ac) -{ - struct zoneref *z = ac->preferred_zoneref; - struct zone *zone; - struct pglist_data *last_pgdat_dirty_limit = NULL; - - /* - * Scan zonelist, looking for a zone with enough free. - * See also __cpuset_node_allowed() comment in kernel/cpuset.c. - */ - for_next_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx, - ac->nodemask) { - struct page *page; - unsigned long mark; - - if (cpusets_enabled() && - (alloc_flags & ALLOC_CPUSET) && - !__cpuset_zone_allowed(zone, gfp_mask)) - continue; - /* - * When allocating a page cache page for writing, we - * want to get it from a node that is within its dirty - * limit, such that no single node holds more than its - * proportional share of globally allowed dirty pages. - * The dirty limits take into account the node's - * lowmem reserves and high watermark so that kswapd - * should be able to balance it without having to - * write pages from its LRU list. - * - * XXX: For now, allow allocations to potentially - * exceed the per-node dirty limit in the slowpath - * (spread_dirty_pages unset) before going into reclaim, - * which is important when on a NUMA setup the allowed - * nodes are together not big enough to reach the - * global limit. The proper fix for these situations - * will require awareness of nodes in the - * dirty-throttling and the flusher threads. - */ - if (ac->spread_dirty_pages) { - if (last_pgdat_dirty_limit == zone->zone_pgdat) - continue; - - if (!node_dirty_ok(zone->zone_pgdat)) { - last_pgdat_dirty_limit = zone->zone_pgdat; - continue; - } - } - - mark = zone->watermark[alloc_flags & ALLOC_WMARK_MASK]; - if (!zone_watermark_fast(zone, order, mark, - ac_classzone_idx(ac), alloc_flags)) { - int ret; - - /* Checked here to keep the fast path fast */ - BUILD_BUG_ON(ALLOC_NO_WATERMARKS < NR_WMARK); - if (alloc_flags & ALLOC_NO_WATERMARKS) - goto try_this_zone; - - if (node_reclaim_mode == 0 || - !zone_allows_reclaim(ac->preferred_zoneref->zone, zone)) - continue; - - ret = node_reclaim(zone->zone_pgdat, gfp_mask, order); - switch (ret) { - case NODE_RECLAIM_NOSCAN: - /* did not scan */ - continue; - case NODE_RECLAIM_FULL: - /* scanned but unreclaimable */ - continue; - default: - /* did we reclaim enough */ - if (zone_watermark_ok(zone, order, mark, - ac_classzone_idx(ac), alloc_flags)) - goto try_this_zone; - - continue; - } - } - -try_this_zone: - page = buffered_rmqueue(ac->preferred_zoneref->zone, zone, order, - gfp_mask, alloc_flags, ac->migratetype); - if (page) { - prep_new_page(page, order, gfp_mask, alloc_flags); - - /* - * If this is a high-order atomic allocation then check - * if the pageblock should be reserved for the future - */ - if (unlikely(order && (alloc_flags & ALLOC_HARDER))) - reserve_highatomic_pageblock(page, zone, order); - - return page; - } - } - - return NULL; -} - -/* - * Large machines with many possible nodes should not always dump per-node - * meminfo in irq context. - */ -static inline bool should_suppress_show_mem(void) -{ - bool ret = false; - -#if NODES_SHIFT > 8 - ret = in_interrupt(); -#endif - return ret; -} - -static DEFINE_RATELIMIT_STATE(nopage_rs, - DEFAULT_RATELIMIT_INTERVAL, - DEFAULT_RATELIMIT_BURST); - -void warn_alloc(gfp_t gfp_mask, const char *fmt, ...) -{ - unsigned int filter = SHOW_MEM_FILTER_NODES; - struct va_format vaf; - va_list args; - - if ((gfp_mask & __GFP_NOWARN) || !__ratelimit(&nopage_rs) || - debug_guardpage_minorder() > 0) - return; - - /* - * This documents exceptions given to allocations in certain - * contexts that are allowed to allocate outside current's set - * of allowed nodes. - */ - if (!(gfp_mask & __GFP_NOMEMALLOC)) - if (test_thread_flag(TIF_MEMDIE) || - (current->flags & (PF_MEMALLOC | PF_EXITING))) - filter &= ~SHOW_MEM_FILTER_NODES; - if (in_interrupt() || !(gfp_mask & __GFP_DIRECT_RECLAIM)) - filter &= ~SHOW_MEM_FILTER_NODES; - - pr_warn("%s: ", current->comm); - - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; - pr_cont("%pV", &vaf); - va_end(args); - - pr_cont(", mode:%#x(%pGg)\n", gfp_mask, &gfp_mask); - - dump_stack(); - if (!should_suppress_show_mem()) - show_mem(filter); -} - -static inline struct page * -__alloc_pages_may_oom(gfp_t gfp_mask, unsigned int order, - const struct alloc_context *ac, unsigned long *did_some_progress) -{ - struct oom_control oc = { - .zonelist = ac->zonelist, - .nodemask = ac->nodemask, - .memcg = NULL, - .gfp_mask = gfp_mask, - .order = order, - }; - struct page *page; - - *did_some_progress = 0; - - /* - * Acquire the oom lock. If that fails, somebody else is - * making progress for us. - */ - if (!mutex_trylock(&oom_lock)) { - *did_some_progress = 1; - schedule_timeout_uninterruptible(1); - return NULL; - } - - /* - * Go through the zonelist yet one more time, keep very high watermark - * here, this is only to catch a parallel oom killing, we must fail if - * we're still under heavy pressure. - */ - page = get_page_from_freelist(gfp_mask | __GFP_HARDWALL, order, - ALLOC_WMARK_HIGH|ALLOC_CPUSET, ac); - if (page) - goto out; - - if (!(gfp_mask & __GFP_NOFAIL)) { - /* Coredumps can quickly deplete all memory reserves */ - if (current->flags & PF_DUMPCORE) - goto out; - /* The OOM killer will not help higher order allocs */ - if (order > PAGE_ALLOC_COSTLY_ORDER) - goto out; - /* The OOM killer does not needlessly kill tasks for lowmem */ - if (ac->high_zoneidx < ZONE_NORMAL) - goto out; - if (pm_suspended_storage()) - goto out; - /* - * XXX: GFP_NOFS allocations should rather fail than rely on - * other request to make a forward progress. - * We are in an unfortunate situation where out_of_memory cannot - * do much for this context but let's try it to at least get - * access to memory reserved if the current task is killed (see - * out_of_memory). Once filesystems are ready to handle allocation - * failures more gracefully we should just bail out here. - */ - - /* The OOM killer may not free memory on a specific node */ - if (gfp_mask & __GFP_THISNODE) - goto out; - } - /* Exhausted what can be done so it's blamo time */ - if (out_of_memory(&oc) || WARN_ON_ONCE(gfp_mask & __GFP_NOFAIL)) { - *did_some_progress = 1; - - if (gfp_mask & __GFP_NOFAIL) { - page = get_page_from_freelist(gfp_mask, order, - ALLOC_NO_WATERMARKS|ALLOC_CPUSET, ac); - /* - * fallback to ignore cpuset restriction if our nodes - * are depleted - */ - if (!page) - page = get_page_from_freelist(gfp_mask, order, - ALLOC_NO_WATERMARKS, ac); - } - } -out: - mutex_unlock(&oom_lock); - return page; -} - -/* - * Maximum number of compaction retries wit a progress before OOM - * killer is consider as the only way to move forward. - */ -#define MAX_COMPACT_RETRIES 16 - -#ifdef CONFIG_COMPACTION -/* Try memory compaction for high-order allocations before reclaim */ -static struct page * -__alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order, - unsigned int alloc_flags, const struct alloc_context *ac, - enum compact_priority prio, enum compact_result *compact_result) -{ - struct page *page; - - if (!order) - return NULL; - - current->flags |= PF_MEMALLOC; - *compact_result = try_to_compact_pages(gfp_mask, order, alloc_flags, ac, - prio); - current->flags &= ~PF_MEMALLOC; - - if (*compact_result <= COMPACT_INACTIVE) - return NULL; - - /* - * At least in one zone compaction wasn't deferred or skipped, so let's - * count a compaction stall - */ - count_vm_event(COMPACTSTALL); - - page = get_page_from_freelist(gfp_mask, order, alloc_flags, ac); - - if (page) { - struct zone *zone = page_zone(page); - - zone->compact_blockskip_flush = false; - compaction_defer_reset(zone, order, true); - count_vm_event(COMPACTSUCCESS); - return page; - } - - /* - * It's bad if compaction run occurs and fails. The most likely reason - * is that pages exist, but not enough to satisfy watermarks. - */ - count_vm_event(COMPACTFAIL); - - cond_resched(); - - return NULL; -} - -static inline bool -should_compact_retry(struct alloc_context *ac, int order, int alloc_flags, - enum compact_result compact_result, - enum compact_priority *compact_priority, - int *compaction_retries) -{ - int max_retries = MAX_COMPACT_RETRIES; - int min_priority; - - if (!order) - return false; - - if (compaction_made_progress(compact_result)) - (*compaction_retries)++; - - /* - * compaction considers all the zone as desperately out of memory - * so it doesn't really make much sense to retry except when the - * failure could be caused by insufficient priority - */ - if (compaction_failed(compact_result)) - goto check_priority; - - /* - * make sure the compaction wasn't deferred or didn't bail out early - * due to locks contention before we declare that we should give up. - * But do not retry if the given zonelist is not suitable for - * compaction. - */ - if (compaction_withdrawn(compact_result)) - return compaction_zonelist_suitable(ac, order, alloc_flags); - - /* - * !costly requests are much more important than __GFP_REPEAT - * costly ones because they are de facto nofail and invoke OOM - * killer to move on while costly can fail and users are ready - * to cope with that. 1/4 retries is rather arbitrary but we - * would need much more detailed feedback from compaction to - * make a better decision. - */ - if (order > PAGE_ALLOC_COSTLY_ORDER) - max_retries /= 4; - if (*compaction_retries <= max_retries) - return true; - - /* - * Make sure there are attempts at the highest priority if we exhausted - * all retries or failed at the lower priorities. - */ -check_priority: - min_priority = (order > PAGE_ALLOC_COSTLY_ORDER) ? - MIN_COMPACT_COSTLY_PRIORITY : MIN_COMPACT_PRIORITY; - if (*compact_priority > min_priority) { - (*compact_priority)--; - *compaction_retries = 0; - return true; - } - return false; -} -#else -static inline struct page * -__alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order, - unsigned int alloc_flags, const struct alloc_context *ac, - enum compact_priority prio, enum compact_result *compact_result) -{ - *compact_result = COMPACT_SKIPPED; - return NULL; -} - -static inline bool -should_compact_retry(struct alloc_context *ac, unsigned int order, int alloc_flags, - enum compact_result compact_result, - enum compact_priority *compact_priority, - int *compaction_retries) -{ - struct zone *zone; - struct zoneref *z; - - if (!order || order > PAGE_ALLOC_COSTLY_ORDER) - return false; - - /* - * There are setups with compaction disabled which would prefer to loop - * inside the allocator rather than hit the oom killer prematurely. - * Let's give them a good hope and keep retrying while the order-0 - * watermarks are OK. - */ - for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx, - ac->nodemask) { - if (zone_watermark_ok(zone, 0, min_wmark_pages(zone), - ac_classzone_idx(ac), alloc_flags)) - return true; - } - return false; -} -#endif /* CONFIG_COMPACTION */ - -/* Perform direct synchronous page reclaim */ -static int -__perform_reclaim(gfp_t gfp_mask, unsigned int order, - const struct alloc_context *ac) -{ - struct reclaim_state reclaim_state; - int progress; - - cond_resched(); - - /* We now go into synchronous reclaim */ - cpuset_memory_pressure_bump(); - current->flags |= PF_MEMALLOC; - lockdep_set_current_reclaim_state(gfp_mask); - reclaim_state.reclaimed_slab = 0; - current->reclaim_state = &reclaim_state; - - progress = try_to_free_pages(ac->zonelist, order, gfp_mask, - ac->nodemask); - - current->reclaim_state = NULL; - lockdep_clear_current_reclaim_state(); - current->flags &= ~PF_MEMALLOC; - - cond_resched(); - - return progress; -} - -/* The really slow allocator path where we enter direct reclaim */ -static inline struct page * -__alloc_pages_direct_reclaim(gfp_t gfp_mask, unsigned int order, - unsigned int alloc_flags, const struct alloc_context *ac, - unsigned long *did_some_progress) -{ - struct page *page = NULL; - bool drained = false; - - *did_some_progress = __perform_reclaim(gfp_mask, order, ac); - if (unlikely(!(*did_some_progress))) - return NULL; - -retry: - page = get_page_from_freelist(gfp_mask, order, alloc_flags, ac); - - /* - * If an allocation failed after direct reclaim, it could be because - * pages are pinned on the per-cpu lists or in high alloc reserves. - * Shrink them them and try again - */ - if (!page && !drained) { - unreserve_highatomic_pageblock(ac); - drain_all_pages(NULL); - drained = true; - goto retry; - } - - return page; -} - -static void wake_all_kswapds(unsigned int order, const struct alloc_context *ac) -{ - struct zoneref *z; - struct zone *zone; - pg_data_t *last_pgdat = NULL; - - for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, - ac->high_zoneidx, ac->nodemask) { - if (last_pgdat != zone->zone_pgdat) - wakeup_kswapd(zone, order, ac->high_zoneidx); - last_pgdat = zone->zone_pgdat; - } -} - -static inline unsigned int -gfp_to_alloc_flags(gfp_t gfp_mask) -{ - unsigned int alloc_flags = ALLOC_WMARK_MIN | ALLOC_CPUSET; - - /* __GFP_HIGH is assumed to be the same as ALLOC_HIGH to save a branch. */ - BUILD_BUG_ON(__GFP_HIGH != (__force gfp_t) ALLOC_HIGH); - - /* - * The caller may dip into page reserves a bit more if the caller - * cannot run direct reclaim, or if the caller has realtime scheduling - * policy or is asking for __GFP_HIGH memory. GFP_ATOMIC requests will - * set both ALLOC_HARDER (__GFP_ATOMIC) and ALLOC_HIGH (__GFP_HIGH). - */ - alloc_flags |= (__force int) (gfp_mask & __GFP_HIGH); - - if (gfp_mask & __GFP_ATOMIC) { - /* - * Not worth trying to allocate harder for __GFP_NOMEMALLOC even - * if it can't schedule. - */ - if (!(gfp_mask & __GFP_NOMEMALLOC)) - alloc_flags |= ALLOC_HARDER; - /* - * Ignore cpuset mems for GFP_ATOMIC rather than fail, see the - * comment for __cpuset_node_allowed(). - */ - alloc_flags &= ~ALLOC_CPUSET; - } else if (unlikely(rt_task(current)) && !in_interrupt()) - alloc_flags |= ALLOC_HARDER; - -#ifdef CONFIG_CMA - if (gfpflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE) - alloc_flags |= ALLOC_CMA; -#endif - return alloc_flags; -} - -bool gfp_pfmemalloc_allowed(gfp_t gfp_mask) -{ - if (unlikely(gfp_mask & __GFP_NOMEMALLOC)) - return false; - - if (gfp_mask & __GFP_MEMALLOC) - return true; - if (in_serving_softirq() && (current->flags & PF_MEMALLOC)) - return true; - if (!in_interrupt() && - ((current->flags & PF_MEMALLOC) || - unlikely(test_thread_flag(TIF_MEMDIE)))) - return true; - - return false; -} - -/* - * Maximum number of reclaim retries without any progress before OOM killer - * is consider as the only way to move forward. - */ -#define MAX_RECLAIM_RETRIES 16 - -/* - * Checks whether it makes sense to retry the reclaim to make a forward progress - * for the given allocation request. - * The reclaim feedback represented by did_some_progress (any progress during - * the last reclaim round) and no_progress_loops (number of reclaim rounds without - * any progress in a row) is considered as well as the reclaimable pages on the - * applicable zone list (with a backoff mechanism which is a function of - * no_progress_loops). - * - * Returns true if a retry is viable or false to enter the oom path. - */ -static inline bool -should_reclaim_retry(gfp_t gfp_mask, unsigned order, - struct alloc_context *ac, int alloc_flags, - bool did_some_progress, int *no_progress_loops) -{ - struct zone *zone; - struct zoneref *z; - - /* - * Costly allocations might have made a progress but this doesn't mean - * their order will become available due to high fragmentation so - * always increment the no progress counter for them - */ - if (did_some_progress && order <= PAGE_ALLOC_COSTLY_ORDER) - *no_progress_loops = 0; - else - (*no_progress_loops)++; - - /* - * Make sure we converge to OOM if we cannot make any progress - * several times in the row. - */ - if (*no_progress_loops > MAX_RECLAIM_RETRIES) - return false; - - /* - * Keep reclaiming pages while there is a chance this will lead - * somewhere. If none of the target zones can satisfy our allocation - * request even if all reclaimable pages are considered then we are - * screwed and have to go OOM. - */ - for_each_zone_zonelist_nodemask(zone, z, ac->zonelist, ac->high_zoneidx, - ac->nodemask) { - unsigned long available; - unsigned long reclaimable; - - available = reclaimable = zone_reclaimable_pages(zone); - available -= DIV_ROUND_UP((*no_progress_loops) * available, - MAX_RECLAIM_RETRIES); - available += zone_page_state_snapshot(zone, NR_FREE_PAGES); - - /* - * Would the allocation succeed if we reclaimed the whole - * available? - */ - if (__zone_watermark_ok(zone, order, min_wmark_pages(zone), - ac_classzone_idx(ac), alloc_flags, available)) { - /* - * If we didn't make any progress and have a lot of - * dirty + writeback pages then we should wait for - * an IO to complete to slow down the reclaim and - * prevent from pre mature OOM - */ - if (!did_some_progress) { - unsigned long write_pending; - - write_pending = zone_page_state_snapshot(zone, - NR_ZONE_WRITE_PENDING); - - if (2 * write_pending > reclaimable) { - congestion_wait(BLK_RW_ASYNC, HZ/10); - return true; - } - } - - /* - * Memory allocation/reclaim might be called from a WQ - * context and the current implementation of the WQ - * concurrency control doesn't recognize that - * a particular WQ is congested if the worker thread is - * looping without ever sleeping. Therefore we have to - * do a short sleep here rather than calling - * cond_resched(). - */ - if (current->flags & PF_WQ_WORKER) - schedule_timeout_uninterruptible(1); - else - cond_resched(); - - return true; - } - } - - return false; -} - -static inline struct page * -__alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order, - struct alloc_context *ac) -{ - bool can_direct_reclaim = gfp_mask & __GFP_DIRECT_RECLAIM; - struct page *page = NULL; - unsigned int alloc_flags; - unsigned long did_some_progress; - enum compact_priority compact_priority = DEF_COMPACT_PRIORITY; - enum compact_result compact_result; - int compaction_retries = 0; - int no_progress_loops = 0; - unsigned long alloc_start = jiffies; - unsigned int stall_timeout = 10 * HZ; - - /* - * In the slowpath, we sanity check order to avoid ever trying to - * reclaim >= MAX_ORDER areas which will never succeed. Callers may - * be using allocators in order of preference for an area that is - * too large. - */ - if (order >= MAX_ORDER) { - WARN_ON_ONCE(!(gfp_mask & __GFP_NOWARN)); - return NULL; - } - - /* - * We also sanity check to catch abuse of atomic reserves being used by - * callers that are not in atomic context. - */ - if (WARN_ON_ONCE((gfp_mask & (__GFP_ATOMIC|__GFP_DIRECT_RECLAIM)) == - (__GFP_ATOMIC|__GFP_DIRECT_RECLAIM))) - gfp_mask &= ~__GFP_ATOMIC; - - /* - * The fast path uses conservative alloc_flags to succeed only until - * kswapd needs to be woken up, and to avoid the cost of setting up - * alloc_flags precisely. So we do that now. - */ - alloc_flags = gfp_to_alloc_flags(gfp_mask); - - if (gfp_mask & __GFP_KSWAPD_RECLAIM) - wake_all_kswapds(order, ac); - - /* - * The adjusted alloc_flags might result in immediate success, so try - * that first - */ - page = get_page_from_freelist(gfp_mask, order, alloc_flags, ac); - if (page) - goto got_pg; - - /* - * For costly allocations, try direct compaction first, as it's likely - * that we have enough base pages and don't need to reclaim. Don't try - * that for allocations that are allowed to ignore watermarks, as the - * ALLOC_NO_WATERMARKS attempt didn't yet happen. - */ - if (can_direct_reclaim && order > PAGE_ALLOC_COSTLY_ORDER && - !gfp_pfmemalloc_allowed(gfp_mask)) { - page = __alloc_pages_direct_compact(gfp_mask, order, - alloc_flags, ac, - INIT_COMPACT_PRIORITY, - &compact_result); - if (page) - goto got_pg; - - /* - * Checks for costly allocations with __GFP_NORETRY, which - * includes THP page fault allocations - */ - if (gfp_mask & __GFP_NORETRY) { - /* - * If compaction is deferred for high-order allocations, - * it is because sync compaction recently failed. If - * this is the case and the caller requested a THP - * allocation, we do not want to heavily disrupt the - * system, so we fail the allocation instead of entering - * direct reclaim. - */ - if (compact_result == COMPACT_DEFERRED) - goto nopage; - - /* - * Looks like reclaim/compaction is worth trying, but - * sync compaction could be very expensive, so keep - * using async compaction. - */ - compact_priority = INIT_COMPACT_PRIORITY; - } - } - -retry: - /* Ensure kswapd doesn't accidentally go to sleep as long as we loop */ - if (gfp_mask & __GFP_KSWAPD_RECLAIM) - wake_all_kswapds(order, ac); - - if (gfp_pfmemalloc_allowed(gfp_mask)) - alloc_flags = ALLOC_NO_WATERMARKS; - - /* - * Reset the zonelist iterators if memory policies can be ignored. - * These allocations are high priority and system rather than user - * orientated. - */ - if (!(alloc_flags & ALLOC_CPUSET) || (alloc_flags & ALLOC_NO_WATERMARKS)) { - ac->zonelist = node_zonelist(numa_node_id(), gfp_mask); - ac->preferred_zoneref = first_zones_zonelist(ac->zonelist, - ac->high_zoneidx, ac->nodemask); - } - - /* Attempt with potentially adjusted zonelist and alloc_flags */ - page = get_page_from_freelist(gfp_mask, order, alloc_flags, ac); - if (page) - goto got_pg; - - /* Caller is not willing to reclaim, we can't balance anything */ - if (!can_direct_reclaim) { - /* - * All existing users of the __GFP_NOFAIL are blockable, so warn - * of any new users that actually allow this type of allocation - * to fail. - */ - WARN_ON_ONCE(gfp_mask & __GFP_NOFAIL); - goto nopage; - } - - /* Avoid recursion of direct reclaim */ - if (current->flags & PF_MEMALLOC) { - /* - * __GFP_NOFAIL request from this context is rather bizarre - * because we cannot reclaim anything and only can loop waiting - * for somebody to do a work for us. - */ - if (WARN_ON_ONCE(gfp_mask & __GFP_NOFAIL)) { - cond_resched(); - goto retry; - } - goto nopage; - } - - /* Avoid allocations with no watermarks from looping endlessly */ - if (test_thread_flag(TIF_MEMDIE) && !(gfp_mask & __GFP_NOFAIL)) - goto nopage; - - - /* Try direct reclaim and then allocating */ - page = __alloc_pages_direct_reclaim(gfp_mask, order, alloc_flags, ac, - &did_some_progress); - if (page) - goto got_pg; - - /* Try direct compaction and then allocating */ - page = __alloc_pages_direct_compact(gfp_mask, order, alloc_flags, ac, - compact_priority, &compact_result); - if (page) - goto got_pg; - - /* Do not loop if specifically requested */ - if (gfp_mask & __GFP_NORETRY) - goto nopage; - - /* - * Do not retry costly high order allocations unless they are - * __GFP_REPEAT - */ - if (order > PAGE_ALLOC_COSTLY_ORDER && !(gfp_mask & __GFP_REPEAT)) - goto nopage; - - /* Make sure we know about allocations which stall for too long */ - if (time_after(jiffies, alloc_start + stall_timeout)) { - warn_alloc(gfp_mask, - "page allocation stalls for %ums, order:%u", - jiffies_to_msecs(jiffies-alloc_start), order); - stall_timeout += 10 * HZ; - } - - if (should_reclaim_retry(gfp_mask, order, ac, alloc_flags, - did_some_progress > 0, &no_progress_loops)) - goto retry; - - /* - * It doesn't make any sense to retry for the compaction if the order-0 - * reclaim is not able to make any progress because the current - * implementation of the compaction depends on the sufficient amount - * of free memory (see __compaction_suitable) - */ - if (did_some_progress > 0 && - should_compact_retry(ac, order, alloc_flags, - compact_result, &compact_priority, - &compaction_retries)) - goto retry; - - /* Reclaim has failed us, start killing things */ - page = __alloc_pages_may_oom(gfp_mask, order, ac, &did_some_progress); - if (page) - goto got_pg; - - /* Retry as long as the OOM killer is making progress */ - if (did_some_progress) { - no_progress_loops = 0; - goto retry; - } - -nopage: - warn_alloc(gfp_mask, - "page allocation failure: order:%u", order); -got_pg: - return page; -} - -/* - * This is the 'heart' of the zoned buddy allocator. - */ -struct page * -__alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order, - struct zonelist *zonelist, nodemask_t *nodemask) -{ - struct page *page; - unsigned int cpuset_mems_cookie; - unsigned int alloc_flags = ALLOC_WMARK_LOW; - gfp_t alloc_mask = gfp_mask; /* The gfp_t that was actually used for allocation */ - struct alloc_context ac = { - .high_zoneidx = gfp_zone(gfp_mask), - .zonelist = zonelist, - .nodemask = nodemask, - .migratetype = gfpflags_to_migratetype(gfp_mask), - }; - - if (cpusets_enabled()) { - alloc_mask |= __GFP_HARDWALL; - alloc_flags |= ALLOC_CPUSET; - if (!ac.nodemask) - ac.nodemask = &cpuset_current_mems_allowed; - } - - gfp_mask &= gfp_allowed_mask; - - lockdep_trace_alloc(gfp_mask); - - might_sleep_if(gfp_mask & __GFP_DIRECT_RECLAIM); - - if (should_fail_alloc_page(gfp_mask, order)) - return NULL; - - /* - * Check the zones suitable for the gfp_mask contain at least one - * valid zone. It's possible to have an empty zonelist as a result - * of __GFP_THISNODE and a memoryless node - */ - if (unlikely(!zonelist->_zonerefs->zone)) - return NULL; - - if (IS_ENABLED(CONFIG_CMA) && ac.migratetype == MIGRATE_MOVABLE) - alloc_flags |= ALLOC_CMA; - -retry_cpuset: - cpuset_mems_cookie = read_mems_allowed_begin(); - - /* Dirty zone balancing only done in the fast path */ - ac.spread_dirty_pages = (gfp_mask & __GFP_WRITE); - - /* - * The preferred zone is used for statistics but crucially it is - * also used as the starting point for the zonelist iterator. It - * may get reset for allocations that ignore memory policies. - */ - ac.preferred_zoneref = first_zones_zonelist(ac.zonelist, - ac.high_zoneidx, ac.nodemask); - if (!ac.preferred_zoneref) { - page = NULL; - goto no_zone; - } - - /* First allocation attempt */ - page = get_page_from_freelist(alloc_mask, order, alloc_flags, &ac); - if (likely(page)) - goto out; - - /* - * Runtime PM, block IO and its error handling path can deadlock - * because I/O on the device might not complete. - */ - alloc_mask = memalloc_noio_flags(gfp_mask); - ac.spread_dirty_pages = false; - - /* - * Restore the original nodemask if it was potentially replaced with - * &cpuset_current_mems_allowed to optimize the fast-path attempt. - */ - if (cpusets_enabled()) - ac.nodemask = nodemask; - page = __alloc_pages_slowpath(alloc_mask, order, &ac); - -no_zone: - /* - * When updating a task's mems_allowed, it is possible to race with - * parallel threads in such a way that an allocation can fail while - * the mask is being updated. If a page allocation is about to fail, - * check if the cpuset changed during allocation and if so, retry. - */ - if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie))) { - alloc_mask = gfp_mask; - goto retry_cpuset; - } - -out: - if (memcg_kmem_enabled() && (gfp_mask & __GFP_ACCOUNT) && page && - unlikely(memcg_kmem_charge(page, gfp_mask, order) != 0)) { - __free_pages(page, order); - page = NULL; - } - - if (kmemcheck_enabled && page) - kmemcheck_pagealloc_alloc(page, order, gfp_mask); - - trace_mm_page_alloc(page, order, alloc_mask, ac.migratetype); - - return page; -} -EXPORT_SYMBOL(__alloc_pages_nodemask); - -/* - * Common helper functions. - */ -unsigned long __get_free_pages(gfp_t gfp_mask, unsigned int order) -{ - struct page *page; - - /* - * __get_free_pages() returns a 32-bit address, which cannot represent - * a highmem page - */ - VM_BUG_ON((gfp_mask & __GFP_HIGHMEM) != 0); - - page = alloc_pages(gfp_mask, order); - if (!page) - return 0; - return (unsigned long) page_address(page); -} -EXPORT_SYMBOL(__get_free_pages); - -unsigned long get_zeroed_page(gfp_t gfp_mask) -{ - return __get_free_pages(gfp_mask | __GFP_ZERO, 0); -} -EXPORT_SYMBOL(get_zeroed_page); - -void __free_pages(struct page *page, unsigned int order) -{ - if (put_page_testzero(page)) { - if (order == 0) - free_hot_cold_page(page, false); - else - __free_pages_ok(page, order); - } -} - -EXPORT_SYMBOL(__free_pages); - -void free_pages(unsigned long addr, unsigned int order) -{ - if (addr != 0) { - VM_BUG_ON(!virt_addr_valid((void *)addr)); - __free_pages(virt_to_page((void *)addr), order); - } -} - -EXPORT_SYMBOL(free_pages); - -/* - * Page Fragment: - * An arbitrary-length arbitrary-offset area of memory which resides - * within a 0 or higher order page. Multiple fragments within that page - * are individually refcounted, in the page's reference counter. - * - * The page_frag functions below provide a simple allocation framework for - * page fragments. This is used by the network stack and network device - * drivers to provide a backing region of memory for use as either an - * sk_buff->head, or to be used in the "frags" portion of skb_shared_info. - */ -static struct page *__page_frag_refill(struct page_frag_cache *nc, - gfp_t gfp_mask) -{ - struct page *page = NULL; - gfp_t gfp = gfp_mask; - -#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) - gfp_mask |= __GFP_COMP | __GFP_NOWARN | __GFP_NORETRY | - __GFP_NOMEMALLOC; - page = alloc_pages_node(NUMA_NO_NODE, gfp_mask, - PAGE_FRAG_CACHE_MAX_ORDER); - nc->size = page ? PAGE_FRAG_CACHE_MAX_SIZE : PAGE_SIZE; -#endif - if (unlikely(!page)) - page = alloc_pages_node(NUMA_NO_NODE, gfp, 0); - - nc->va = page ? page_address(page) : NULL; - - return page; -} - -void *__alloc_page_frag(struct page_frag_cache *nc, - unsigned int fragsz, gfp_t gfp_mask) -{ - unsigned int size = PAGE_SIZE; - struct page *page; - int offset; - - if (unlikely(!nc->va)) { -refill: - page = __page_frag_refill(nc, gfp_mask); - if (!page) - return NULL; - -#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) - /* if size can vary use size else just use PAGE_SIZE */ - size = nc->size; -#endif - /* Even if we own the page, we do not use atomic_set(). - * This would break get_page_unless_zero() users. - */ - page_ref_add(page, size - 1); - - /* reset page count bias and offset to start of new frag */ - nc->pfmemalloc = page_is_pfmemalloc(page); - nc->pagecnt_bias = size; - nc->offset = size; - } - - offset = nc->offset - fragsz; - if (unlikely(offset < 0)) { - page = virt_to_page(nc->va); - - if (!page_ref_sub_and_test(page, nc->pagecnt_bias)) - goto refill; - -#if (PAGE_SIZE < PAGE_FRAG_CACHE_MAX_SIZE) - /* if size can vary use size else just use PAGE_SIZE */ - size = nc->size; -#endif - /* OK, page count is 0, we can safely set it */ - set_page_count(page, size); - - /* reset page count bias and offset to start of new frag */ - nc->pagecnt_bias = size; - offset = size - fragsz; - } - - nc->pagecnt_bias--; - nc->offset = offset; - - return nc->va + offset; -} -EXPORT_SYMBOL(__alloc_page_frag); - -/* - * Frees a page fragment allocated out of either a compound or order 0 page. - */ -void __free_page_frag(void *addr) -{ - struct page *page = virt_to_head_page(addr); - - if (unlikely(put_page_testzero(page))) - __free_pages_ok(page, compound_order(page)); -} -EXPORT_SYMBOL(__free_page_frag); - -static void *make_alloc_exact(unsigned long addr, unsigned int order, - size_t size) -{ - if (addr) { - unsigned long alloc_end = addr + (PAGE_SIZE << order); - unsigned long used = addr + PAGE_ALIGN(size); - - split_page(virt_to_page((void *)addr), order); - while (used < alloc_end) { - free_page(used); - used += PAGE_SIZE; - } - } - return (void *)addr; -} - -/** - * alloc_pages_exact - allocate an exact number physically-contiguous pages. - * @size: the number of bytes to allocate - * @gfp_mask: GFP flags for the allocation - * - * This function is similar to alloc_pages(), except that it allocates the - * minimum number of pages to satisfy the request. alloc_pages() can only - * allocate memory in power-of-two pages. - * - * This function is also limited by MAX_ORDER. - * - * Memory allocated by this function must be released by free_pages_exact(). - */ -void *alloc_pages_exact(size_t size, gfp_t gfp_mask) -{ - unsigned int order = get_order(size); - unsigned long addr; - - addr = __get_free_pages(gfp_mask, order); - return make_alloc_exact(addr, order, size); -} -EXPORT_SYMBOL(alloc_pages_exact); - -/** - * alloc_pages_exact_nid - allocate an exact number of physically-contiguous - * pages on a node. - * @nid: the preferred node ID where memory should be allocated - * @size: the number of bytes to allocate - * @gfp_mask: GFP flags for the allocation - * - * Like alloc_pages_exact(), but try to allocate on node nid first before falling - * back. - */ -void * __meminit alloc_pages_exact_nid(int nid, size_t size, gfp_t gfp_mask) -{ - unsigned int order = get_order(size); - struct page *p = alloc_pages_node(nid, gfp_mask, order); - if (!p) - return NULL; - return make_alloc_exact((unsigned long)page_address(p), order, size); -} - -/** - * free_pages_exact - release memory allocated via alloc_pages_exact() - * @virt: the value returned by alloc_pages_exact. - * @size: size of allocation, same value as passed to alloc_pages_exact(). - * - * Release the memory allocated by a previous call to alloc_pages_exact. - */ -void free_pages_exact(void *virt, size_t size) -{ - unsigned long addr = (unsigned long)virt; - unsigned long end = addr + PAGE_ALIGN(size); - - while (addr < end) { - free_page(addr); - addr += PAGE_SIZE; - } -} -EXPORT_SYMBOL(free_pages_exact); - -/** - * nr_free_zone_pages - count number of pages beyond high watermark - * @offset: The zone index of the highest zone - * - * nr_free_zone_pages() counts the number of counts pages which are beyond the - * high watermark within all zones at or below a given zone index. For each - * zone, the number of pages is calculated as: - * managed_pages - high_pages - */ -static unsigned long nr_free_zone_pages(int offset) -{ - struct zoneref *z; - struct zone *zone; - - /* Just pick one node, since fallback list is circular */ - unsigned long sum = 0; - - struct zonelist *zonelist = node_zonelist(numa_node_id(), GFP_KERNEL); - - for_each_zone_zonelist(zone, z, zonelist, offset) { - unsigned long size = zone->managed_pages; - unsigned long high = high_wmark_pages(zone); - if (size > high) - sum += size - high; - } - - return sum; -} - -/** - * nr_free_buffer_pages - count number of pages beyond high watermark - * - * nr_free_buffer_pages() counts the number of pages which are beyond the high - * watermark within ZONE_DMA and ZONE_NORMAL. - */ -unsigned long nr_free_buffer_pages(void) -{ - return nr_free_zone_pages(gfp_zone(GFP_USER)); -} -EXPORT_SYMBOL_GPL(nr_free_buffer_pages); - -/** - * nr_free_pagecache_pages - count number of pages beyond high watermark - * - * nr_free_pagecache_pages() counts the number of pages which are beyond the - * high watermark within all zones. - */ -unsigned long nr_free_pagecache_pages(void) -{ - return nr_free_zone_pages(gfp_zone(GFP_HIGHUSER_MOVABLE)); -} - -static inline void show_node(struct zone *zone) -{ - if (IS_ENABLED(CONFIG_NUMA)) - printk("Node %d ", zone_to_nid(zone)); -} - -long si_mem_available(void) -{ - long available; - unsigned long pagecache; - unsigned long wmark_low = 0; - unsigned long pages[NR_LRU_LISTS]; - struct zone *zone; - int lru; - - for (lru = LRU_BASE; lru < NR_LRU_LISTS; lru++) - pages[lru] = global_node_page_state(NR_LRU_BASE + lru); - - for_each_zone(zone) - wmark_low += zone->watermark[WMARK_LOW]; - - /* - * Estimate the amount of memory available for userspace allocations, - * without causing swapping. - */ - available = global_page_state(NR_FREE_PAGES) - totalreserve_pages; - - /* - * Not all the page cache can be freed, otherwise the system will - * start swapping. Assume at least half of the page cache, or the - * low watermark worth of cache, needs to stay. - */ - pagecache = pages[LRU_ACTIVE_FILE] + pages[LRU_INACTIVE_FILE]; - pagecache -= min(pagecache / 2, wmark_low); - available += pagecache; - - /* - * Part of the reclaimable slab consists of items that are in use, - * and cannot be freed. Cap this estimate at the low watermark. - */ - available += global_page_state(NR_SLAB_RECLAIMABLE) - - min(global_page_state(NR_SLAB_RECLAIMABLE) / 2, wmark_low); - - if (available < 0) - available = 0; - return available; -} -EXPORT_SYMBOL_GPL(si_mem_available); - -void si_meminfo(struct sysinfo *val) -{ - val->totalram = totalram_pages; - val->sharedram = global_node_page_state(NR_SHMEM); - val->freeram = global_page_state(NR_FREE_PAGES); - val->bufferram = nr_blockdev_pages(); - val->totalhigh = totalhigh_pages; - val->freehigh = nr_free_highpages(); - val->mem_unit = PAGE_SIZE; -} - -EXPORT_SYMBOL(si_meminfo); - -#ifdef CONFIG_NUMA -void si_meminfo_node(struct sysinfo *val, int nid) -{ - int zone_type; /* needs to be signed */ - unsigned long managed_pages = 0; - unsigned long managed_highpages = 0; - unsigned long free_highpages = 0; - pg_data_t *pgdat = NODE_DATA(nid); - - for (zone_type = 0; zone_type < MAX_NR_ZONES; zone_type++) - managed_pages += pgdat->node_zones[zone_type].managed_pages; - val->totalram = managed_pages; - val->sharedram = node_page_state(pgdat, NR_SHMEM); - val->freeram = sum_zone_node_page_state(nid, NR_FREE_PAGES); -#ifdef CONFIG_HIGHMEM - for (zone_type = 0; zone_type < MAX_NR_ZONES; zone_type++) { - struct zone *zone = &pgdat->node_zones[zone_type]; - - if (is_highmem(zone)) { - managed_highpages += zone->managed_pages; - free_highpages += zone_page_state(zone, NR_FREE_PAGES); - } - } - val->totalhigh = managed_highpages; - val->freehigh = free_highpages; -#else - val->totalhigh = managed_highpages; - val->freehigh = free_highpages; -#endif - val->mem_unit = PAGE_SIZE; -} -#endif - -/* - * Determine whether the node should be displayed or not, depending on whether - * SHOW_MEM_FILTER_NODES was passed to show_free_areas(). - */ -bool skip_free_areas_node(unsigned int flags, int nid) -{ - bool ret = false; - unsigned int cpuset_mems_cookie; - - if (!(flags & SHOW_MEM_FILTER_NODES)) - goto out; - - do { - cpuset_mems_cookie = read_mems_allowed_begin(); - ret = !node_isset(nid, cpuset_current_mems_allowed); - } while (read_mems_allowed_retry(cpuset_mems_cookie)); -out: - return ret; -} - -#define K(x) ((x) << (PAGE_SHIFT-10)) - -static void show_migration_types(unsigned char type) -{ - static const char types[MIGRATE_TYPES] = { - [MIGRATE_UNMOVABLE] = 'U', - [MIGRATE_MOVABLE] = 'M', - [MIGRATE_RECLAIMABLE] = 'E', - [MIGRATE_HIGHATOMIC] = 'H', -#ifdef CONFIG_CMA - [MIGRATE_CMA] = 'C', -#endif -#ifdef CONFIG_MEMORY_ISOLATION - [MIGRATE_ISOLATE] = 'I', -#endif - }; - char tmp[MIGRATE_TYPES + 1]; - char *p = tmp; - int i; - - for (i = 0; i < MIGRATE_TYPES; i++) { - if (type & (1 << i)) - *p++ = types[i]; - } - - *p = '\0'; - printk(KERN_CONT "(%s) ", tmp); -} - -/* - * Show free area list (used inside shift_scroll-lock stuff) - * We also calculate the percentage fragmentation. We do this by counting the - * memory on each free list with the exception of the first item on the list. - * - * Bits in @filter: - * SHOW_MEM_FILTER_NODES: suppress nodes that are not allowed by current's - * cpuset. - */ -void show_free_areas(unsigned int filter) -{ - unsigned long free_pcp = 0; - int cpu; - struct zone *zone; - pg_data_t *pgdat; - - for_each_populated_zone(zone) { - if (skip_free_areas_node(filter, zone_to_nid(zone))) - continue; - - for_each_online_cpu(cpu) - free_pcp += per_cpu_ptr(zone->pageset, cpu)->pcp.count; - } - - printk("active_anon:%lu inactive_anon:%lu isolated_anon:%lu\n" - " active_file:%lu inactive_file:%lu isolated_file:%lu\n" - " unevictable:%lu dirty:%lu writeback:%lu unstable:%lu\n" - " slab_reclaimable:%lu slab_unreclaimable:%lu\n" - " mapped:%lu shmem:%lu pagetables:%lu bounce:%lu\n" - " free:%lu free_pcp:%lu free_cma:%lu\n", - global_node_page_state(NR_ACTIVE_ANON), - global_node_page_state(NR_INACTIVE_ANON), - global_node_page_state(NR_ISOLATED_ANON), - global_node_page_state(NR_ACTIVE_FILE), - global_node_page_state(NR_INACTIVE_FILE), - global_node_page_state(NR_ISOLATED_FILE), - global_node_page_state(NR_UNEVICTABLE), - global_node_page_state(NR_FILE_DIRTY), - global_node_page_state(NR_WRITEBACK), - global_node_page_state(NR_UNSTABLE_NFS), - global_page_state(NR_SLAB_RECLAIMABLE), - global_page_state(NR_SLAB_UNRECLAIMABLE), - global_node_page_state(NR_FILE_MAPPED), - global_node_page_state(NR_SHMEM), - global_page_state(NR_PAGETABLE), - global_page_state(NR_BOUNCE), - global_page_state(NR_FREE_PAGES), - free_pcp, - global_page_state(NR_FREE_CMA_PAGES)); - - for_each_online_pgdat(pgdat) { - printk("Node %d" - " active_anon:%lukB" - " inactive_anon:%lukB" - " active_file:%lukB" - " inactive_file:%lukB" - " unevictable:%lukB" - " isolated(anon):%lukB" - " isolated(file):%lukB" - " mapped:%lukB" - " dirty:%lukB" - " writeback:%lukB" - " shmem:%lukB" -#ifdef CONFIG_TRANSPARENT_HUGEPAGE - " shmem_thp: %lukB" - " shmem_pmdmapped: %lukB" - " anon_thp: %lukB" -#endif - " writeback_tmp:%lukB" - " unstable:%lukB" - " pages_scanned:%lu" - " all_unreclaimable? %s" - "\n", - pgdat->node_id, - K(node_page_state(pgdat, NR_ACTIVE_ANON)), - K(node_page_state(pgdat, NR_INACTIVE_ANON)), - K(node_page_state(pgdat, NR_ACTIVE_FILE)), - K(node_page_state(pgdat, NR_INACTIVE_FILE)), - K(node_page_state(pgdat, NR_UNEVICTABLE)), - K(node_page_state(pgdat, NR_ISOLATED_ANON)), - K(node_page_state(pgdat, NR_ISOLATED_FILE)), - K(node_page_state(pgdat, NR_FILE_MAPPED)), - K(node_page_state(pgdat, NR_FILE_DIRTY)), - K(node_page_state(pgdat, NR_WRITEBACK)), -#ifdef CONFIG_TRANSPARENT_HUGEPAGE - K(node_page_state(pgdat, NR_SHMEM_THPS) * HPAGE_PMD_NR), - K(node_page_state(pgdat, NR_SHMEM_PMDMAPPED) - * HPAGE_PMD_NR), - K(node_page_state(pgdat, NR_ANON_THPS) * HPAGE_PMD_NR), -#endif - K(node_page_state(pgdat, NR_SHMEM)), - K(node_page_state(pgdat, NR_WRITEBACK_TEMP)), - K(node_page_state(pgdat, NR_UNSTABLE_NFS)), - node_page_state(pgdat, NR_PAGES_SCANNED), - !pgdat_reclaimable(pgdat) ? "yes" : "no"); - } - - for_each_populated_zone(zone) { - int i; - - if (skip_free_areas_node(filter, zone_to_nid(zone))) - continue; - - free_pcp = 0; - for_each_online_cpu(cpu) - free_pcp += per_cpu_ptr(zone->pageset, cpu)->pcp.count; - - show_node(zone); - printk(KERN_CONT - "%s" - " free:%lukB" - " min:%lukB" - " low:%lukB" - " high:%lukB" - " active_anon:%lukB" - " inactive_anon:%lukB" - " active_file:%lukB" - " inactive_file:%lukB" - " unevictable:%lukB" - " writepending:%lukB" - " present:%lukB" - " managed:%lukB" - " mlocked:%lukB" - " slab_reclaimable:%lukB" - " slab_unreclaimable:%lukB" - " kernel_stack:%lukB" - " pagetables:%lukB" - " bounce:%lukB" - " free_pcp:%lukB" - " local_pcp:%ukB" - " free_cma:%lukB" - "\n", - zone->name, - K(zone_page_state(zone, NR_FREE_PAGES)), - K(min_wmark_pages(zone)), - K(low_wmark_pages(zone)), - K(high_wmark_pages(zone)), - K(zone_page_state(zone, NR_ZONE_ACTIVE_ANON)), - K(zone_page_state(zone, NR_ZONE_INACTIVE_ANON)), - K(zone_page_state(zone, NR_ZONE_ACTIVE_FILE)), - K(zone_page_state(zone, NR_ZONE_INACTIVE_FILE)), - K(zone_page_state(zone, NR_ZONE_UNEVICTABLE)), - K(zone_page_state(zone, NR_ZONE_WRITE_PENDING)), - K(zone->present_pages), - K(zone->managed_pages), - K(zone_page_state(zone, NR_MLOCK)), - K(zone_page_state(zone, NR_SLAB_RECLAIMABLE)), - K(zone_page_state(zone, NR_SLAB_UNRECLAIMABLE)), - zone_page_state(zone, NR_KERNEL_STACK_KB), - K(zone_page_state(zone, NR_PAGETABLE)), - K(zone_page_state(zone, NR_BOUNCE)), - K(free_pcp), - K(this_cpu_read(zone->pageset->pcp.count)), - K(zone_page_state(zone, NR_FREE_CMA_PAGES))); - printk("lowmem_reserve[]:"); - for (i = 0; i < MAX_NR_ZONES; i++) - printk(KERN_CONT " %ld", zone->lowmem_reserve[i]); - printk(KERN_CONT "\n"); - } - - for_each_populated_zone(zone) { - unsigned int order; - unsigned long nr[MAX_ORDER], flags, total = 0; - unsigned char types[MAX_ORDER]; - - if (skip_free_areas_node(filter, zone_to_nid(zone))) - continue; - show_node(zone); - printk(KERN_CONT "%s: ", zone->name); - - spin_lock_irqsave(&zone->lock, flags); - for (order = 0; order < MAX_ORDER; order++) { - struct free_area *area = &zone->free_area[order]; - int type; - - nr[order] = area->nr_free; - total += nr[order] << order; - - types[order] = 0; - for (type = 0; type < MIGRATE_TYPES; type++) { - if (!list_empty(&area->free_list[type])) - types[order] |= 1 << type; - } - } - spin_unlock_irqrestore(&zone->lock, flags); - for (order = 0; order < MAX_ORDER; order++) { - printk(KERN_CONT "%lu*%lukB ", - nr[order], K(1UL) << order); - if (nr[order]) - show_migration_types(types[order]); - } - printk(KERN_CONT "= %lukB\n", K(total)); - } - - hugetlb_show_meminfo(); - - printk("%ld total pagecache pages\n", global_node_page_state(NR_FILE_PAGES)); - - show_swap_cache_info(); -} - -static void zoneref_set_zone(struct zone *zone, struct zoneref *zoneref) -{ - zoneref->zone = zone; - zoneref->zone_idx = zone_idx(zone); -} - -/* - * Builds allocation fallback zone lists. - * - * Add all populated zones of a node to the zonelist. - */ -static int build_zonelists_node(pg_data_t *pgdat, struct zonelist *zonelist, - int nr_zones) -{ - struct zone *zone; - enum zone_type zone_type = MAX_NR_ZONES; - - do { - zone_type--; - zone = pgdat->node_zones + zone_type; - if (managed_zone(zone)) { - zoneref_set_zone(zone, - &zonelist->_zonerefs[nr_zones++]); - check_highest_zone(zone_type); - } - } while (zone_type); - - return nr_zones; -} - - -/* - * zonelist_order: - * 0 = automatic detection of better ordering. - * 1 = order by ([node] distance, -zonetype) - * 2 = order by (-zonetype, [node] distance) - * - * If not NUMA, ZONELIST_ORDER_ZONE and ZONELIST_ORDER_NODE will create - * the same zonelist. So only NUMA can configure this param. - */ -#define ZONELIST_ORDER_DEFAULT 0 -#define ZONELIST_ORDER_NODE 1 -#define ZONELIST_ORDER_ZONE 2 - -/* zonelist order in the kernel. - * set_zonelist_order() will set this to NODE or ZONE. - */ -static int current_zonelist_order = ZONELIST_ORDER_DEFAULT; -static char zonelist_order_name[3][8] = {"Default", "Node", "Zone"}; - - -#ifdef CONFIG_NUMA -/* The value user specified ....changed by config */ -static int user_zonelist_order = ZONELIST_ORDER_DEFAULT; -/* string for sysctl */ -#define NUMA_ZONELIST_ORDER_LEN 16 -char numa_zonelist_order[16] = "default"; - -/* - * interface for configure zonelist ordering. - * command line option "numa_zonelist_order" - * = "[dD]efault - default, automatic configuration. - * = "[nN]ode - order by node locality, then by zone within node - * = "[zZ]one - order by zone, then by locality within zone - */ - -static int __parse_numa_zonelist_order(char *s) -{ - if (*s == 'd' || *s == 'D') { - user_zonelist_order = ZONELIST_ORDER_DEFAULT; - } else if (*s == 'n' || *s == 'N') { - user_zonelist_order = ZONELIST_ORDER_NODE; - } else if (*s == 'z' || *s == 'Z') { - user_zonelist_order = ZONELIST_ORDER_ZONE; - } else { - pr_warn("Ignoring invalid numa_zonelist_order value: %s\n", s); - return -EINVAL; - } - return 0; -} - -static __init int setup_numa_zonelist_order(char *s) -{ - int ret; - - if (!s) - return 0; - - ret = __parse_numa_zonelist_order(s); - if (ret == 0) - strlcpy(numa_zonelist_order, s, NUMA_ZONELIST_ORDER_LEN); - - return ret; -} -early_param("numa_zonelist_order", setup_numa_zonelist_order); - -/* - * sysctl handler for numa_zonelist_order - */ -int numa_zonelist_order_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *length, - loff_t *ppos) -{ - char saved_string[NUMA_ZONELIST_ORDER_LEN]; - int ret; - static DEFINE_MUTEX(zl_order_mutex); - - mutex_lock(&zl_order_mutex); - if (write) { - if (strlen((char *)table->data) >= NUMA_ZONELIST_ORDER_LEN) { - ret = -EINVAL; - goto out; - } - strcpy(saved_string, (char *)table->data); - } - ret = proc_dostring(table, write, buffer, length, ppos); - if (ret) - goto out; - if (write) { - int oldval = user_zonelist_order; - - ret = __parse_numa_zonelist_order((char *)table->data); - if (ret) { - /* - * bogus value. restore saved string - */ - strncpy((char *)table->data, saved_string, - NUMA_ZONELIST_ORDER_LEN); - user_zonelist_order = oldval; - } else if (oldval != user_zonelist_order) { - mutex_lock(&zonelists_mutex); - build_all_zonelists(NULL, NULL); - mutex_unlock(&zonelists_mutex); - } - } -out: - mutex_unlock(&zl_order_mutex); - return ret; -} - - -#define MAX_NODE_LOAD (nr_online_nodes) -static int node_load[MAX_NUMNODES]; - -/** - * find_next_best_node - find the next node that should appear in a given node's fallback list - * @node: node whose fallback list we're appending - * @used_node_mask: nodemask_t of already used nodes - * - * We use a number of factors to determine which is the next node that should - * appear on a given node's fallback list. The node should not have appeared - * already in @node's fallback list, and it should be the next closest node - * according to the distance array (which contains arbitrary distance values - * from each node to each node in the system), and should also prefer nodes - * with no CPUs, since presumably they'll have very little allocation pressure - * on them otherwise. - * It returns -1 if no node is found. - */ -static int find_next_best_node(int node, nodemask_t *used_node_mask) -{ - int n, val; - int min_val = INT_MAX; - int best_node = NUMA_NO_NODE; - const struct cpumask *tmp = cpumask_of_node(0); - - /* Use the local node if we haven't already */ - if (!node_isset(node, *used_node_mask)) { - node_set(node, *used_node_mask); - return node; - } - - for_each_node_state(n, N_MEMORY) { - - /* Don't want a node to appear more than once */ - if (node_isset(n, *used_node_mask)) - continue; - - /* Use the distance array to find the distance */ - val = node_distance(node, n); - - /* Penalize nodes under us ("prefer the next node") */ - val += (n < node); - - /* Give preference to headless and unused nodes */ - tmp = cpumask_of_node(n); - if (!cpumask_empty(tmp)) - val += PENALTY_FOR_NODE_WITH_CPUS; - - /* Slight preference for less loaded node */ - val *= (MAX_NODE_LOAD*MAX_NUMNODES); - val += node_load[n]; - - if (val < min_val) { - min_val = val; - best_node = n; - } - } - - if (best_node >= 0) - node_set(best_node, *used_node_mask); - - return best_node; -} - - -/* - * Build zonelists ordered by node and zones within node. - * This results in maximum locality--normal zone overflows into local - * DMA zone, if any--but risks exhausting DMA zone. - */ -static void build_zonelists_in_node_order(pg_data_t *pgdat, int node) -{ - int j; - struct zonelist *zonelist; - - zonelist = &pgdat->node_zonelists[ZONELIST_FALLBACK]; - for (j = 0; zonelist->_zonerefs[j].zone != NULL; j++) - ; - j = build_zonelists_node(NODE_DATA(node), zonelist, j); - zonelist->_zonerefs[j].zone = NULL; - zonelist->_zonerefs[j].zone_idx = 0; -} - -/* - * Build gfp_thisnode zonelists - */ -static void build_thisnode_zonelists(pg_data_t *pgdat) -{ - int j; - struct zonelist *zonelist; - - zonelist = &pgdat->node_zonelists[ZONELIST_NOFALLBACK]; - j = build_zonelists_node(pgdat, zonelist, 0); - zonelist->_zonerefs[j].zone = NULL; - zonelist->_zonerefs[j].zone_idx = 0; -} - -/* - * Build zonelists ordered by zone and nodes within zones. - * This results in conserving DMA zone[s] until all Normal memory is - * exhausted, but results in overflowing to remote node while memory - * may still exist in local DMA zone. - */ -static int node_order[MAX_NUMNODES]; - -static void build_zonelists_in_zone_order(pg_data_t *pgdat, int nr_nodes) -{ - int pos, j, node; - int zone_type; /* needs to be signed */ - struct zone *z; - struct zonelist *zonelist; - - zonelist = &pgdat->node_zonelists[ZONELIST_FALLBACK]; - pos = 0; - for (zone_type = MAX_NR_ZONES - 1; zone_type >= 0; zone_type--) { - for (j = 0; j < nr_nodes; j++) { - node = node_order[j]; - z = &NODE_DATA(node)->node_zones[zone_type]; - if (managed_zone(z)) { - zoneref_set_zone(z, - &zonelist->_zonerefs[pos++]); - check_highest_zone(zone_type); - } - } - } - zonelist->_zonerefs[pos].zone = NULL; - zonelist->_zonerefs[pos].zone_idx = 0; -} - -#if defined(CONFIG_64BIT) -/* - * Devices that require DMA32/DMA are relatively rare and do not justify a - * penalty to every machine in case the specialised case applies. Default - * to Node-ordering on 64-bit NUMA machines - */ -static int default_zonelist_order(void) -{ - return ZONELIST_ORDER_NODE; -} -#else -/* - * On 32-bit, the Normal zone needs to be preserved for allocations accessible - * by the kernel. If processes running on node 0 deplete the low memory zone - * then reclaim will occur more frequency increasing stalls and potentially - * be easier to OOM if a large percentage of the zone is under writeback or - * dirty. The problem is significantly worse if CONFIG_HIGHPTE is not set. - * Hence, default to zone ordering on 32-bit. - */ -static int default_zonelist_order(void) -{ - return ZONELIST_ORDER_ZONE; -} -#endif /* CONFIG_64BIT */ - -static void set_zonelist_order(void) -{ - if (user_zonelist_order == ZONELIST_ORDER_DEFAULT) - current_zonelist_order = default_zonelist_order(); - else - current_zonelist_order = user_zonelist_order; -} - -static void build_zonelists(pg_data_t *pgdat) -{ - int i, node, load; - nodemask_t used_mask; - int local_node, prev_node; - struct zonelist *zonelist; - unsigned int order = current_zonelist_order; - - /* initialize zonelists */ - for (i = 0; i < MAX_ZONELISTS; i++) { - zonelist = pgdat->node_zonelists + i; - zonelist->_zonerefs[0].zone = NULL; - zonelist->_zonerefs[0].zone_idx = 0; - } - - /* NUMA-aware ordering of nodes */ - local_node = pgdat->node_id; - load = nr_online_nodes; - prev_node = local_node; - nodes_clear(used_mask); - - memset(node_order, 0, sizeof(node_order)); - i = 0; - - while ((node = find_next_best_node(local_node, &used_mask)) >= 0) { - /* - * We don't want to pressure a particular node. - * So adding penalty to the first node in same - * distance group to make it round-robin. - */ - if (node_distance(local_node, node) != - node_distance(local_node, prev_node)) - node_load[node] = load; - - prev_node = node; - load--; - if (order == ZONELIST_ORDER_NODE) - build_zonelists_in_node_order(pgdat, node); - else - node_order[i++] = node; /* remember order */ - } - - if (order == ZONELIST_ORDER_ZONE) { - /* calculate node order -- i.e., DMA last! */ - build_zonelists_in_zone_order(pgdat, i); - } - - build_thisnode_zonelists(pgdat); -} - -#ifdef CONFIG_HAVE_MEMORYLESS_NODES -/* - * Return node id of node used for "local" allocations. - * I.e., first node id of first zone in arg node's generic zonelist. - * Used for initializing percpu 'numa_mem', which is used primarily - * for kernel allocations, so use GFP_KERNEL flags to locate zonelist. - */ -int local_memory_node(int node) -{ - struct zoneref *z; - - z = first_zones_zonelist(node_zonelist(node, GFP_KERNEL), - gfp_zone(GFP_KERNEL), - NULL); - return z->zone->node; -} -#endif - -static void setup_min_unmapped_ratio(void); -static void setup_min_slab_ratio(void); -#else /* CONFIG_NUMA */ - -static void set_zonelist_order(void) -{ - current_zonelist_order = ZONELIST_ORDER_ZONE; -} - -static void build_zonelists(pg_data_t *pgdat) -{ - int node, local_node; - enum zone_type j; - struct zonelist *zonelist; - - local_node = pgdat->node_id; - - zonelist = &pgdat->node_zonelists[ZONELIST_FALLBACK]; - j = build_zonelists_node(pgdat, zonelist, 0); - - /* - * Now we build the zonelist so that it contains the zones - * of all the other nodes. - * We don't want to pressure a particular node, so when - * building the zones for node N, we make sure that the - * zones coming right after the local ones are those from - * node N+1 (modulo N) - */ - for (node = local_node + 1; node < MAX_NUMNODES; node++) { - if (!node_online(node)) - continue; - j = build_zonelists_node(NODE_DATA(node), zonelist, j); - } - for (node = 0; node < local_node; node++) { - if (!node_online(node)) - continue; - j = build_zonelists_node(NODE_DATA(node), zonelist, j); - } - - zonelist->_zonerefs[j].zone = NULL; - zonelist->_zonerefs[j].zone_idx = 0; -} - -#endif /* CONFIG_NUMA */ - -/* - * Boot pageset table. One per cpu which is going to be used for all - * zones and all nodes. The parameters will be set in such a way - * that an item put on a list will immediately be handed over to - * the buddy list. This is safe since pageset manipulation is done - * with interrupts disabled. - * - * The boot_pagesets must be kept even after bootup is complete for - * unused processors and/or zones. They do play a role for bootstrapping - * hotplugged processors. - * - * zoneinfo_show() and maybe other functions do - * not check if the processor is online before following the pageset pointer. - * Other parts of the kernel may not check if the zone is available. - */ -static void setup_pageset(struct per_cpu_pageset *p, unsigned long batch); -static DEFINE_PER_CPU(struct per_cpu_pageset, boot_pageset); -static void setup_zone_pageset(struct zone *zone); - -/* - * Global mutex to protect against size modification of zonelists - * as well as to serialize pageset setup for the new populated zone. - */ -DEFINE_MUTEX(zonelists_mutex); - -/* return values int ....just for stop_machine() */ -static int __build_all_zonelists(void *data) -{ - int nid; - int cpu; - pg_data_t *self = data; - -#ifdef CONFIG_NUMA - memset(node_load, 0, sizeof(node_load)); -#endif - - if (self && !node_online(self->node_id)) { - build_zonelists(self); - } - - for_each_online_node(nid) { - pg_data_t *pgdat = NODE_DATA(nid); - - build_zonelists(pgdat); - } - - /* - * Initialize the boot_pagesets that are going to be used - * for bootstrapping processors. The real pagesets for - * each zone will be allocated later when the per cpu - * allocator is available. - * - * boot_pagesets are used also for bootstrapping offline - * cpus if the system is already booted because the pagesets - * are needed to initialize allocators on a specific cpu too. - * F.e. the percpu allocator needs the page allocator which - * needs the percpu allocator in order to allocate its pagesets - * (a chicken-egg dilemma). - */ - for_each_possible_cpu(cpu) { - setup_pageset(&per_cpu(boot_pageset, cpu), 0); - -#ifdef CONFIG_HAVE_MEMORYLESS_NODES - /* - * We now know the "local memory node" for each node-- - * i.e., the node of the first zone in the generic zonelist. - * Set up numa_mem percpu variable for on-line cpus. During - * boot, only the boot cpu should be on-line; we'll init the - * secondary cpus' numa_mem as they come on-line. During - * node/memory hotplug, we'll fixup all on-line cpus. - */ - if (cpu_online(cpu)) - set_cpu_numa_mem(cpu, local_memory_node(cpu_to_node(cpu))); -#endif - } - - return 0; -} - -static noinline void __init -build_all_zonelists_init(void) -{ - __build_all_zonelists(NULL); - mminit_verify_zonelist(); - cpuset_init_current_mems_allowed(); -} - -/* - * Called with zonelists_mutex held always - * unless system_state == SYSTEM_BOOTING. - * - * __ref due to (1) call of __meminit annotated setup_zone_pageset - * [we're only called with non-NULL zone through __meminit paths] and - * (2) call of __init annotated helper build_all_zonelists_init - * [protected by SYSTEM_BOOTING]. - */ -void __ref build_all_zonelists(pg_data_t *pgdat, struct zone *zone) -{ - set_zonelist_order(); - - if (system_state == SYSTEM_BOOTING) { - build_all_zonelists_init(); - } else { -#ifdef CONFIG_MEMORY_HOTPLUG - if (zone) - setup_zone_pageset(zone); -#endif - /* we have to stop all cpus to guarantee there is no user - of zonelist */ - stop_machine(__build_all_zonelists, pgdat, NULL); - /* cpuset refresh routine should be here */ - } - vm_total_pages = nr_free_pagecache_pages(); - /* - * Disable grouping by mobility if the number of pages in the - * system is too low to allow the mechanism to work. It would be - * more accurate, but expensive to check per-zone. This check is - * made on memory-hotadd so a system can start with mobility - * disabled and enable it later - */ - if (vm_total_pages < (pageblock_nr_pages * MIGRATE_TYPES)) - page_group_by_mobility_disabled = 1; - else - page_group_by_mobility_disabled = 0; - - pr_info("Built %i zonelists in %s order, mobility grouping %s. Total pages: %ld\n", - nr_online_nodes, - zonelist_order_name[current_zonelist_order], - page_group_by_mobility_disabled ? "off" : "on", - vm_total_pages); -#ifdef CONFIG_NUMA - pr_info("Policy zone: %s\n", zone_names[policy_zone]); -#endif -} - -/* - * Initially all pages are reserved - free ones are freed - * up by free_all_bootmem() once the early boot process is - * done. Non-atomic initialization, single-pass. - */ -void __meminit memmap_init_zone(unsigned long size, int nid, unsigned long zone, - unsigned long start_pfn, enum memmap_context context) -{ - struct vmem_altmap *altmap = to_vmem_altmap(__pfn_to_phys(start_pfn)); - unsigned long end_pfn = start_pfn + size; - pg_data_t *pgdat = NODE_DATA(nid); - unsigned long pfn; - unsigned long nr_initialised = 0; -#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP - struct memblock_region *r = NULL, *tmp; -#endif - - if (highest_memmap_pfn < end_pfn - 1) - highest_memmap_pfn = end_pfn - 1; - - /* - * Honor reservation requested by the driver for this ZONE_DEVICE - * memory - */ - if (altmap && start_pfn == altmap->base_pfn) - start_pfn += altmap->reserve; - - for (pfn = start_pfn; pfn < end_pfn; pfn++) { - /* - * There can be holes in boot-time mem_map[]s handed to this - * function. They do not exist on hotplugged memory. - */ - if (context != MEMMAP_EARLY) - goto not_early; - - if (!early_pfn_valid(pfn)) - continue; - if (!early_pfn_in_nid(pfn, nid)) - continue; - if (!update_defer_init(pgdat, pfn, end_pfn, &nr_initialised)) - break; - -#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP - /* - * Check given memblock attribute by firmware which can affect - * kernel memory layout. If zone==ZONE_MOVABLE but memory is - * mirrored, it's an overlapped memmap init. skip it. - */ - if (mirrored_kernelcore && zone == ZONE_MOVABLE) { - if (!r || pfn >= memblock_region_memory_end_pfn(r)) { - for_each_memblock(memory, tmp) - if (pfn < memblock_region_memory_end_pfn(tmp)) - break; - r = tmp; - } - if (pfn >= memblock_region_memory_base_pfn(r) && - memblock_is_mirror(r)) { - /* already initialized as NORMAL */ - pfn = memblock_region_memory_end_pfn(r); - continue; - } - } -#endif - -not_early: - /* - * Mark the block movable so that blocks are reserved for - * movable at startup. This will force kernel allocations - * to reserve their blocks rather than leaking throughout - * the address space during boot when many long-lived - * kernel allocations are made. - * - * bitmap is created for zone's valid pfn range. but memmap - * can be created for invalid pages (for alignment) - * check here not to call set_pageblock_migratetype() against - * pfn out of zone. - */ - if (!(pfn & (pageblock_nr_pages - 1))) { - struct page *page = pfn_to_page(pfn); - - __init_single_page(page, pfn, zone, nid); - set_pageblock_migratetype(page, MIGRATE_MOVABLE); - } else { - __init_single_pfn(pfn, zone, nid); - } - } -} - -static void __meminit zone_init_free_lists(struct zone *zone) -{ - unsigned int order, t; - for_each_migratetype_order(order, t) { - INIT_LIST_HEAD(&zone->free_area[order].free_list[t]); - zone->free_area[order].nr_free = 0; - } -} - -#ifndef __HAVE_ARCH_MEMMAP_INIT -#define memmap_init(size, nid, zone, start_pfn) \ - memmap_init_zone((size), (nid), (zone), (start_pfn), MEMMAP_EARLY) -#endif - -static int zone_batchsize(struct zone *zone) -{ -#ifdef CONFIG_MMU - int batch; - - /* - * The per-cpu-pages pools are set to around 1000th of the - * size of the zone. But no more than 1/2 of a meg. - * - * OK, so we don't know how big the cache is. So guess. - */ - batch = zone->managed_pages / 1024; - if (batch * PAGE_SIZE > 512 * 1024) - batch = (512 * 1024) / PAGE_SIZE; - batch /= 4; /* We effectively *= 4 below */ - if (batch < 1) - batch = 1; - - /* - * Clamp the batch to a 2^n - 1 value. Having a power - * of 2 value was found to be more likely to have - * suboptimal cache aliasing properties in some cases. - * - * For example if 2 tasks are alternately allocating - * batches of pages, one task can end up with a lot - * of pages of one half of the possible page colors - * and the other with pages of the other colors. - */ - batch = rounddown_pow_of_two(batch + batch/2) - 1; - - return batch; - -#else - /* The deferral and batching of frees should be suppressed under NOMMU - * conditions. - * - * The problem is that NOMMU needs to be able to allocate large chunks - * of contiguous memory as there's no hardware page translation to - * assemble apparent contiguous memory from discontiguous pages. - * - * Queueing large contiguous runs of pages for batching, however, - * causes the pages to actually be freed in smaller chunks. As there - * can be a significant delay between the individual batches being - * recycled, this leads to the once large chunks of space being - * fragmented and becoming unavailable for high-order allocations. - */ - return 0; -#endif -} - -/* - * pcp->high and pcp->batch values are related and dependent on one another: - * ->batch must never be higher then ->high. - * The following function updates them in a safe manner without read side - * locking. - * - * Any new users of pcp->batch and pcp->high should ensure they can cope with - * those fields changing asynchronously (acording the the above rule). - * - * mutex_is_locked(&pcp_batch_high_lock) required when calling this function - * outside of boot time (or some other assurance that no concurrent updaters - * exist). - */ -static void pageset_update(struct per_cpu_pages *pcp, unsigned long high, - unsigned long batch) -{ - /* start with a fail safe value for batch */ - pcp->batch = 1; - smp_wmb(); - - /* Update high, then batch, in order */ - pcp->high = high; - smp_wmb(); - - pcp->batch = batch; -} - -/* a companion to pageset_set_high() */ -static void pageset_set_batch(struct per_cpu_pageset *p, unsigned long batch) -{ - pageset_update(&p->pcp, 6 * batch, max(1UL, 1 * batch)); -} - -static void pageset_init(struct per_cpu_pageset *p) -{ - struct per_cpu_pages *pcp; - int migratetype; - - memset(p, 0, sizeof(*p)); - - pcp = &p->pcp; - pcp->count = 0; - for (migratetype = 0; migratetype < MIGRATE_PCPTYPES; migratetype++) - INIT_LIST_HEAD(&pcp->lists[migratetype]); -} - -static void setup_pageset(struct per_cpu_pageset *p, unsigned long batch) -{ - pageset_init(p); - pageset_set_batch(p, batch); -} - -/* - * pageset_set_high() sets the high water mark for hot per_cpu_pagelist - * to the value high for the pageset p. - */ -static void pageset_set_high(struct per_cpu_pageset *p, - unsigned long high) -{ - unsigned long batch = max(1UL, high / 4); - if ((high / 4) > (PAGE_SHIFT * 8)) - batch = PAGE_SHIFT * 8; - - pageset_update(&p->pcp, high, batch); -} - -static void pageset_set_high_and_batch(struct zone *zone, - struct per_cpu_pageset *pcp) -{ - if (percpu_pagelist_fraction) - pageset_set_high(pcp, - (zone->managed_pages / - percpu_pagelist_fraction)); - else - pageset_set_batch(pcp, zone_batchsize(zone)); -} - -static void __meminit zone_pageset_init(struct zone *zone, int cpu) -{ - struct per_cpu_pageset *pcp = per_cpu_ptr(zone->pageset, cpu); - - pageset_init(pcp); - pageset_set_high_and_batch(zone, pcp); -} - -static void __meminit setup_zone_pageset(struct zone *zone) -{ - int cpu; - zone->pageset = alloc_percpu(struct per_cpu_pageset); - for_each_possible_cpu(cpu) - zone_pageset_init(zone, cpu); -} - -/* - * Allocate per cpu pagesets and initialize them. - * Before this call only boot pagesets were available. - */ -void __init setup_per_cpu_pageset(void) -{ - struct pglist_data *pgdat; - struct zone *zone; - - for_each_populated_zone(zone) - setup_zone_pageset(zone); - - for_each_online_pgdat(pgdat) - pgdat->per_cpu_nodestats = - alloc_percpu(struct per_cpu_nodestat); -} - -static __meminit void zone_pcp_init(struct zone *zone) -{ - /* - * per cpu subsystem is not up at this point. The following code - * relies on the ability of the linker to provide the - * offset of a (static) per cpu variable into the per cpu area. - */ - zone->pageset = &boot_pageset; - - if (populated_zone(zone)) - printk(KERN_DEBUG " %s zone: %lu pages, LIFO batch:%u\n", - zone->name, zone->present_pages, - zone_batchsize(zone)); -} - -int __meminit init_currently_empty_zone(struct zone *zone, - unsigned long zone_start_pfn, - unsigned long size) -{ - struct pglist_data *pgdat = zone->zone_pgdat; - - pgdat->nr_zones = zone_idx(zone) + 1; - - zone->zone_start_pfn = zone_start_pfn; - - mminit_dprintk(MMINIT_TRACE, "memmap_init", - "Initialising map node %d zone %lu pfns %lu -> %lu\n", - pgdat->node_id, - (unsigned long)zone_idx(zone), - zone_start_pfn, (zone_start_pfn + size)); - - zone_init_free_lists(zone); - zone->initialized = 1; - - return 0; -} - -#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP -#ifndef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID - -/* - * Required by SPARSEMEM. Given a PFN, return what node the PFN is on. - */ -int __meminit __early_pfn_to_nid(unsigned long pfn, - struct mminit_pfnnid_cache *state) -{ - unsigned long start_pfn, end_pfn; - int nid; - - if (state->last_start <= pfn && pfn < state->last_end) - return state->last_nid; - - nid = memblock_search_pfn_nid(pfn, &start_pfn, &end_pfn); - if (nid != -1) { - state->last_start = start_pfn; - state->last_end = end_pfn; - state->last_nid = nid; - } - - return nid; -} -#endif /* CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID */ - -/** - * free_bootmem_with_active_regions - Call memblock_free_early_nid for each active range - * @nid: The node to free memory on. If MAX_NUMNODES, all nodes are freed. - * @max_low_pfn: The highest PFN that will be passed to memblock_free_early_nid - * - * If an architecture guarantees that all ranges registered contain no holes - * and may be freed, this this function may be used instead of calling - * memblock_free_early_nid() manually. - */ -void __init free_bootmem_with_active_regions(int nid, unsigned long max_low_pfn) -{ - unsigned long start_pfn, end_pfn; - int i, this_nid; - - for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, &this_nid) { - start_pfn = min(start_pfn, max_low_pfn); - end_pfn = min(end_pfn, max_low_pfn); - - if (start_pfn < end_pfn) - memblock_free_early_nid(PFN_PHYS(start_pfn), - (end_pfn - start_pfn) << PAGE_SHIFT, - this_nid); - } -} - -/** - * sparse_memory_present_with_active_regions - Call memory_present for each active range - * @nid: The node to call memory_present for. If MAX_NUMNODES, all nodes will be used. - * - * If an architecture guarantees that all ranges registered contain no holes and may - * be freed, this function may be used instead of calling memory_present() manually. - */ -void __init sparse_memory_present_with_active_regions(int nid) -{ - unsigned long start_pfn, end_pfn; - int i, this_nid; - - for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, &this_nid) - memory_present(this_nid, start_pfn, end_pfn); -} - -/** - * get_pfn_range_for_nid - Return the start and end page frames for a node - * @nid: The nid to return the range for. If MAX_NUMNODES, the min and max PFN are returned. - * @start_pfn: Passed by reference. On return, it will have the node start_pfn. - * @end_pfn: Passed by reference. On return, it will have the node end_pfn. - * - * It returns the start and end page frame of a node based on information - * provided by memblock_set_node(). If called for a node - * with no available memory, a warning is printed and the start and end - * PFNs will be 0. - */ -void __meminit get_pfn_range_for_nid(unsigned int nid, - unsigned long *start_pfn, unsigned long *end_pfn) -{ - unsigned long this_start_pfn, this_end_pfn; - int i; - - *start_pfn = -1UL; - *end_pfn = 0; - - for_each_mem_pfn_range(i, nid, &this_start_pfn, &this_end_pfn, NULL) { - *start_pfn = min(*start_pfn, this_start_pfn); - *end_pfn = max(*end_pfn, this_end_pfn); - } - - if (*start_pfn == -1UL) - *start_pfn = 0; -} - -/* - * This finds a zone that can be used for ZONE_MOVABLE pages. The - * assumption is made that zones within a node are ordered in monotonic - * increasing memory addresses so that the "highest" populated zone is used - */ -static void __init find_usable_zone_for_movable(void) -{ - int zone_index; - for (zone_index = MAX_NR_ZONES - 1; zone_index >= 0; zone_index--) { - if (zone_index == ZONE_MOVABLE) - continue; - - if (arch_zone_highest_possible_pfn[zone_index] > - arch_zone_lowest_possible_pfn[zone_index]) - break; - } - - VM_BUG_ON(zone_index == -1); - movable_zone = zone_index; -} - -/* - * The zone ranges provided by the architecture do not include ZONE_MOVABLE - * because it is sized independent of architecture. Unlike the other zones, - * the starting point for ZONE_MOVABLE is not fixed. It may be different - * in each node depending on the size of each node and how evenly kernelcore - * is distributed. This helper function adjusts the zone ranges - * provided by the architecture for a given node by using the end of the - * highest usable zone for ZONE_MOVABLE. This preserves the assumption that - * zones within a node are in order of monotonic increases memory addresses - */ -static void __meminit adjust_zone_range_for_zone_movable(int nid, - unsigned long zone_type, - unsigned long node_start_pfn, - unsigned long node_end_pfn, - unsigned long *zone_start_pfn, - unsigned long *zone_end_pfn) -{ - /* Only adjust if ZONE_MOVABLE is on this node */ - if (zone_movable_pfn[nid]) { - /* Size ZONE_MOVABLE */ - if (zone_type == ZONE_MOVABLE) { - *zone_start_pfn = zone_movable_pfn[nid]; - *zone_end_pfn = min(node_end_pfn, - arch_zone_highest_possible_pfn[movable_zone]); - - /* Adjust for ZONE_MOVABLE starting within this range */ - } else if (!mirrored_kernelcore && - *zone_start_pfn < zone_movable_pfn[nid] && - *zone_end_pfn > zone_movable_pfn[nid]) { - *zone_end_pfn = zone_movable_pfn[nid]; - - /* Check if this whole range is within ZONE_MOVABLE */ - } else if (*zone_start_pfn >= zone_movable_pfn[nid]) - *zone_start_pfn = *zone_end_pfn; - } -} - -/* - * Return the number of pages a zone spans in a node, including holes - * present_pages = zone_spanned_pages_in_node() - zone_absent_pages_in_node() - */ -static unsigned long __meminit zone_spanned_pages_in_node(int nid, - unsigned long zone_type, - unsigned long node_start_pfn, - unsigned long node_end_pfn, - unsigned long *zone_start_pfn, - unsigned long *zone_end_pfn, - unsigned long *ignored) -{ - /* When hotadd a new node from cpu_up(), the node should be empty */ - if (!node_start_pfn && !node_end_pfn) - return 0; - - /* Get the start and end of the zone */ - *zone_start_pfn = arch_zone_lowest_possible_pfn[zone_type]; - *zone_end_pfn = arch_zone_highest_possible_pfn[zone_type]; - adjust_zone_range_for_zone_movable(nid, zone_type, - node_start_pfn, node_end_pfn, - zone_start_pfn, zone_end_pfn); - - /* Check that this node has pages within the zone's required range */ - if (*zone_end_pfn < node_start_pfn || *zone_start_pfn > node_end_pfn) - return 0; - - /* Move the zone boundaries inside the node if necessary */ - *zone_end_pfn = min(*zone_end_pfn, node_end_pfn); - *zone_start_pfn = max(*zone_start_pfn, node_start_pfn); - - /* Return the spanned pages */ - return *zone_end_pfn - *zone_start_pfn; -} - -/* - * Return the number of holes in a range on a node. If nid is MAX_NUMNODES, - * then all holes in the requested range will be accounted for. - */ -unsigned long __meminit __absent_pages_in_range(int nid, - unsigned long range_start_pfn, - unsigned long range_end_pfn) -{ - unsigned long nr_absent = range_end_pfn - range_start_pfn; - unsigned long start_pfn, end_pfn; - int i; - - for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) { - start_pfn = clamp(start_pfn, range_start_pfn, range_end_pfn); - end_pfn = clamp(end_pfn, range_start_pfn, range_end_pfn); - nr_absent -= end_pfn - start_pfn; - } - return nr_absent; -} - -/** - * absent_pages_in_range - Return number of page frames in holes within a range - * @start_pfn: The start PFN to start searching for holes - * @end_pfn: The end PFN to stop searching for holes - * - * It returns the number of pages frames in memory holes within a range. - */ -unsigned long __init absent_pages_in_range(unsigned long start_pfn, - unsigned long end_pfn) -{ - return __absent_pages_in_range(MAX_NUMNODES, start_pfn, end_pfn); -} - -/* Return the number of page frames in holes in a zone on a node */ -static unsigned long __meminit zone_absent_pages_in_node(int nid, - unsigned long zone_type, - unsigned long node_start_pfn, - unsigned long node_end_pfn, - unsigned long *ignored) -{ - unsigned long zone_low = arch_zone_lowest_possible_pfn[zone_type]; - unsigned long zone_high = arch_zone_highest_possible_pfn[zone_type]; - unsigned long zone_start_pfn, zone_end_pfn; - unsigned long nr_absent; - - /* When hotadd a new node from cpu_up(), the node should be empty */ - if (!node_start_pfn && !node_end_pfn) - return 0; - - zone_start_pfn = clamp(node_start_pfn, zone_low, zone_high); - zone_end_pfn = clamp(node_end_pfn, zone_low, zone_high); - - adjust_zone_range_for_zone_movable(nid, zone_type, - node_start_pfn, node_end_pfn, - &zone_start_pfn, &zone_end_pfn); - nr_absent = __absent_pages_in_range(nid, zone_start_pfn, zone_end_pfn); - - /* - * ZONE_MOVABLE handling. - * Treat pages to be ZONE_MOVABLE in ZONE_NORMAL as absent pages - * and vice versa. - */ - if (mirrored_kernelcore && zone_movable_pfn[nid]) { - unsigned long start_pfn, end_pfn; - struct memblock_region *r; - - for_each_memblock(memory, r) { - start_pfn = clamp(memblock_region_memory_base_pfn(r), - zone_start_pfn, zone_end_pfn); - end_pfn = clamp(memblock_region_memory_end_pfn(r), - zone_start_pfn, zone_end_pfn); - - if (zone_type == ZONE_MOVABLE && - memblock_is_mirror(r)) - nr_absent += end_pfn - start_pfn; - - if (zone_type == ZONE_NORMAL && - !memblock_is_mirror(r)) - nr_absent += end_pfn - start_pfn; - } - } - - return nr_absent; -} - -#else /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */ -static inline unsigned long __meminit zone_spanned_pages_in_node(int nid, - unsigned long zone_type, - unsigned long node_start_pfn, - unsigned long node_end_pfn, - unsigned long *zone_start_pfn, - unsigned long *zone_end_pfn, - unsigned long *zones_size) -{ - unsigned int zone; - - *zone_start_pfn = node_start_pfn; - for (zone = 0; zone < zone_type; zone++) - *zone_start_pfn += zones_size[zone]; - - *zone_end_pfn = *zone_start_pfn + zones_size[zone_type]; - - return zones_size[zone_type]; -} - -static inline unsigned long __meminit zone_absent_pages_in_node(int nid, - unsigned long zone_type, - unsigned long node_start_pfn, - unsigned long node_end_pfn, - unsigned long *zholes_size) -{ - if (!zholes_size) - return 0; - - return zholes_size[zone_type]; -} - -#endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */ - -static void __meminit calculate_node_totalpages(struct pglist_data *pgdat, - unsigned long node_start_pfn, - unsigned long node_end_pfn, - unsigned long *zones_size, - unsigned long *zholes_size) -{ - unsigned long realtotalpages = 0, totalpages = 0; - enum zone_type i; - - for (i = 0; i < MAX_NR_ZONES; i++) { - struct zone *zone = pgdat->node_zones + i; - unsigned long zone_start_pfn, zone_end_pfn; - unsigned long size, real_size; - - size = zone_spanned_pages_in_node(pgdat->node_id, i, - node_start_pfn, - node_end_pfn, - &zone_start_pfn, - &zone_end_pfn, - zones_size); - real_size = size - zone_absent_pages_in_node(pgdat->node_id, i, - node_start_pfn, node_end_pfn, - zholes_size); - if (size) - zone->zone_start_pfn = zone_start_pfn; - else - zone->zone_start_pfn = 0; - zone->spanned_pages = size; - zone->present_pages = real_size; - - totalpages += size; - realtotalpages += real_size; - } - - pgdat->node_spanned_pages = totalpages; - pgdat->node_present_pages = realtotalpages; - printk(KERN_DEBUG "On node %d totalpages: %lu\n", pgdat->node_id, - realtotalpages); -} - -#ifndef CONFIG_SPARSEMEM -/* - * Calculate the size of the zone->blockflags rounded to an unsigned long - * Start by making sure zonesize is a multiple of pageblock_order by rounding - * up. Then use 1 NR_PAGEBLOCK_BITS worth of bits per pageblock, finally - * round what is now in bits to nearest long in bits, then return it in - * bytes. - */ -static unsigned long __init usemap_size(unsigned long zone_start_pfn, unsigned long zonesize) -{ - unsigned long usemapsize; - - zonesize += zone_start_pfn & (pageblock_nr_pages-1); - usemapsize = roundup(zonesize, pageblock_nr_pages); - usemapsize = usemapsize >> pageblock_order; - usemapsize *= NR_PAGEBLOCK_BITS; - usemapsize = roundup(usemapsize, 8 * sizeof(unsigned long)); - - return usemapsize / 8; -} - -static void __init setup_usemap(struct pglist_data *pgdat, - struct zone *zone, - unsigned long zone_start_pfn, - unsigned long zonesize) -{ - unsigned long usemapsize = usemap_size(zone_start_pfn, zonesize); - zone->pageblock_flags = NULL; - if (usemapsize) - zone->pageblock_flags = - memblock_virt_alloc_node_nopanic(usemapsize, - pgdat->node_id); -} -#else -static inline void setup_usemap(struct pglist_data *pgdat, struct zone *zone, - unsigned long zone_start_pfn, unsigned long zonesize) {} -#endif /* CONFIG_SPARSEMEM */ - -#ifdef CONFIG_HUGETLB_PAGE_SIZE_VARIABLE - -/* Initialise the number of pages represented by NR_PAGEBLOCK_BITS */ -void __paginginit set_pageblock_order(void) -{ - unsigned int order; - - /* Check that pageblock_nr_pages has not already been setup */ - if (pageblock_order) - return; - - if (HPAGE_SHIFT > PAGE_SHIFT) - order = HUGETLB_PAGE_ORDER; - else - order = MAX_ORDER - 1; - - /* - * Assume the largest contiguous order of interest is a huge page. - * This value may be variable depending on boot parameters on IA64 and - * powerpc. - */ - pageblock_order = order; -} -#else /* CONFIG_HUGETLB_PAGE_SIZE_VARIABLE */ - -/* - * When CONFIG_HUGETLB_PAGE_SIZE_VARIABLE is not set, set_pageblock_order() - * is unused as pageblock_order is set at compile-time. See - * include/linux/pageblock-flags.h for the values of pageblock_order based on - * the kernel config - */ -void __paginginit set_pageblock_order(void) -{ -} - -#endif /* CONFIG_HUGETLB_PAGE_SIZE_VARIABLE */ - -static unsigned long __paginginit calc_memmap_size(unsigned long spanned_pages, - unsigned long present_pages) -{ - unsigned long pages = spanned_pages; - - /* - * Provide a more accurate estimation if there are holes within - * the zone and SPARSEMEM is in use. If there are holes within the - * zone, each populated memory region may cost us one or two extra - * memmap pages due to alignment because memmap pages for each - * populated regions may not naturally algined on page boundary. - * So the (present_pages >> 4) heuristic is a tradeoff for that. - */ - if (spanned_pages > present_pages + (present_pages >> 4) && - IS_ENABLED(CONFIG_SPARSEMEM)) - pages = present_pages; - - return PAGE_ALIGN(pages * sizeof(struct page)) >> PAGE_SHIFT; -} - -/* - * Set up the zone data structures: - * - mark all pages reserved - * - mark all memory queues empty - * - clear the memory bitmaps - * - * NOTE: pgdat should get zeroed by caller. - */ -static void __paginginit free_area_init_core(struct pglist_data *pgdat) -{ - enum zone_type j; - int nid = pgdat->node_id; - int ret; - - pgdat_resize_init(pgdat); -#ifdef CONFIG_NUMA_BALANCING - spin_lock_init(&pgdat->numabalancing_migrate_lock); - pgdat->numabalancing_migrate_nr_pages = 0; - pgdat->numabalancing_migrate_next_window = jiffies; -#endif -#ifdef CONFIG_TRANSPARENT_HUGEPAGE - spin_lock_init(&pgdat->split_queue_lock); - INIT_LIST_HEAD(&pgdat->split_queue); - pgdat->split_queue_len = 0; -#endif - init_waitqueue_head(&pgdat->kswapd_wait); - init_waitqueue_head(&pgdat->pfmemalloc_wait); -#ifdef CONFIG_COMPACTION - init_waitqueue_head(&pgdat->kcompactd_wait); -#endif - pgdat_page_ext_init(pgdat); - spin_lock_init(&pgdat->lru_lock); - lruvec_init(node_lruvec(pgdat)); - - for (j = 0; j < MAX_NR_ZONES; j++) { - struct zone *zone = pgdat->node_zones + j; - unsigned long size, realsize, freesize, memmap_pages; - unsigned long zone_start_pfn = zone->zone_start_pfn; - - size = zone->spanned_pages; - realsize = freesize = zone->present_pages; - - /* - * Adjust freesize so that it accounts for how much memory - * is used by this zone for memmap. This affects the watermark - * and per-cpu initialisations - */ - memmap_pages = calc_memmap_size(size, realsize); - if (!is_highmem_idx(j)) { - if (freesize >= memmap_pages) { - freesize -= memmap_pages; - if (memmap_pages) - printk(KERN_DEBUG - " %s zone: %lu pages used for memmap\n", - zone_names[j], memmap_pages); - } else - pr_warn(" %s zone: %lu pages exceeds freesize %lu\n", - zone_names[j], memmap_pages, freesize); - } - - /* Account for reserved pages */ - if (j == 0 && freesize > dma_reserve) { - freesize -= dma_reserve; - printk(KERN_DEBUG " %s zone: %lu pages reserved\n", - zone_names[0], dma_reserve); - } - - if (!is_highmem_idx(j)) - nr_kernel_pages += freesize; - /* Charge for highmem memmap if there are enough kernel pages */ - else if (nr_kernel_pages > memmap_pages * 2) - nr_kernel_pages -= memmap_pages; - nr_all_pages += freesize; - - /* - * Set an approximate value for lowmem here, it will be adjusted - * when the bootmem allocator frees pages into the buddy system. - * And all highmem pages will be managed by the buddy system. - */ - zone->managed_pages = is_highmem_idx(j) ? realsize : freesize; -#ifdef CONFIG_NUMA - zone->node = nid; -#endif - zone->name = zone_names[j]; - zone->zone_pgdat = pgdat; - spin_lock_init(&zone->lock); - zone_seqlock_init(zone); - zone_pcp_init(zone); - - if (!size) - continue; - - set_pageblock_order(); - setup_usemap(pgdat, zone, zone_start_pfn, size); - ret = init_currently_empty_zone(zone, zone_start_pfn, size); - BUG_ON(ret); - memmap_init(size, nid, j, zone_start_pfn); - } -} - -static void __ref alloc_node_mem_map(struct pglist_data *pgdat) -{ - unsigned long __maybe_unused start = 0; - unsigned long __maybe_unused offset = 0; - - /* Skip empty nodes */ - if (!pgdat->node_spanned_pages) - return; - -#ifdef CONFIG_FLAT_NODE_MEM_MAP - start = pgdat->node_start_pfn & ~(MAX_ORDER_NR_PAGES - 1); - offset = pgdat->node_start_pfn - start; - /* ia64 gets its own node_mem_map, before this, without bootmem */ - if (!pgdat->node_mem_map) { - unsigned long size, end; - struct page *map; - - /* - * The zone's endpoints aren't required to be MAX_ORDER - * aligned but the node_mem_map endpoints must be in order - * for the buddy allocator to function correctly. - */ - end = pgdat_end_pfn(pgdat); - end = ALIGN(end, MAX_ORDER_NR_PAGES); - size = (end - start) * sizeof(struct page); - map = alloc_remap(pgdat->node_id, size); - if (!map) - map = memblock_virt_alloc_node_nopanic(size, - pgdat->node_id); - pgdat->node_mem_map = map + offset; - } -#ifndef CONFIG_NEED_MULTIPLE_NODES - /* - * With no DISCONTIG, the global mem_map is just set as node 0's - */ - if (pgdat == NODE_DATA(0)) { - mem_map = NODE_DATA(0)->node_mem_map; -#if defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP) || defined(CONFIG_FLATMEM) - if (page_to_pfn(mem_map) != pgdat->node_start_pfn) - mem_map -= offset; -#endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */ - } -#endif -#endif /* CONFIG_FLAT_NODE_MEM_MAP */ -} - -void __paginginit free_area_init_node(int nid, unsigned long *zones_size, - unsigned long node_start_pfn, unsigned long *zholes_size) -{ - pg_data_t *pgdat = NODE_DATA(nid); - unsigned long start_pfn = 0; - unsigned long end_pfn = 0; - - /* pg_data_t should be reset to zero when it's allocated */ - WARN_ON(pgdat->nr_zones || pgdat->kswapd_classzone_idx); - - reset_deferred_meminit(pgdat); - pgdat->node_id = nid; - pgdat->node_start_pfn = node_start_pfn; - pgdat->per_cpu_nodestats = NULL; -#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP - get_pfn_range_for_nid(nid, &start_pfn, &end_pfn); - pr_info("Initmem setup node %d [mem %#018Lx-%#018Lx]\n", nid, - (u64)start_pfn << PAGE_SHIFT, - end_pfn ? ((u64)end_pfn << PAGE_SHIFT) - 1 : 0); -#else - start_pfn = node_start_pfn; -#endif - calculate_node_totalpages(pgdat, start_pfn, end_pfn, - zones_size, zholes_size); - - alloc_node_mem_map(pgdat); -#ifdef CONFIG_FLAT_NODE_MEM_MAP - printk(KERN_DEBUG "free_area_init_node: node %d, pgdat %08lx, node_mem_map %08lx\n", - nid, (unsigned long)pgdat, - (unsigned long)pgdat->node_mem_map); -#endif - - free_area_init_core(pgdat); -} - -#ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP - -#if MAX_NUMNODES > 1 -/* - * Figure out the number of possible node ids. - */ -void __init setup_nr_node_ids(void) -{ - unsigned int highest; - - highest = find_last_bit(node_possible_map.bits, MAX_NUMNODES); - nr_node_ids = highest + 1; -} -#endif - -/** - * node_map_pfn_alignment - determine the maximum internode alignment - * - * This function should be called after node map is populated and sorted. - * It calculates the maximum power of two alignment which can distinguish - * all the nodes. - * - * For example, if all nodes are 1GiB and aligned to 1GiB, the return value - * would indicate 1GiB alignment with (1 << (30 - PAGE_SHIFT)). If the - * nodes are shifted by 256MiB, 256MiB. Note that if only the last node is - * shifted, 1GiB is enough and this function will indicate so. - * - * This is used to test whether pfn -> nid mapping of the chosen memory - * model has fine enough granularity to avoid incorrect mapping for the - * populated node map. - * - * Returns the determined alignment in pfn's. 0 if there is no alignment - * requirement (single node). - */ -unsigned long __init node_map_pfn_alignment(void) -{ - unsigned long accl_mask = 0, last_end = 0; - unsigned long start, end, mask; - int last_nid = -1; - int i, nid; - - for_each_mem_pfn_range(i, MAX_NUMNODES, &start, &end, &nid) { - if (!start || last_nid < 0 || last_nid == nid) { - last_nid = nid; - last_end = end; - continue; - } - - /* - * Start with a mask granular enough to pin-point to the - * start pfn and tick off bits one-by-one until it becomes - * too coarse to separate the current node from the last. - */ - mask = ~((1 << __ffs(start)) - 1); - while (mask && last_end <= (start & (mask << 1))) - mask <<= 1; - - /* accumulate all internode masks */ - accl_mask |= mask; - } - - /* convert mask to number of pages */ - return ~accl_mask + 1; -} - -/* Find the lowest pfn for a node */ -static unsigned long __init find_min_pfn_for_node(int nid) -{ - unsigned long min_pfn = ULONG_MAX; - unsigned long start_pfn; - int i; - - for_each_mem_pfn_range(i, nid, &start_pfn, NULL, NULL) - min_pfn = min(min_pfn, start_pfn); - - if (min_pfn == ULONG_MAX) { - pr_warn("Could not find start_pfn for node %d\n", nid); - return 0; - } - - return min_pfn; -} - -/** - * find_min_pfn_with_active_regions - Find the minimum PFN registered - * - * It returns the minimum PFN based on information provided via - * memblock_set_node(). - */ -unsigned long __init find_min_pfn_with_active_regions(void) -{ - return find_min_pfn_for_node(MAX_NUMNODES); -} - -/* - * early_calculate_totalpages() - * Sum pages in active regions for movable zone. - * Populate N_MEMORY for calculating usable_nodes. - */ -static unsigned long __init early_calculate_totalpages(void) -{ - unsigned long totalpages = 0; - unsigned long start_pfn, end_pfn; - int i, nid; - - for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, &nid) { - unsigned long pages = end_pfn - start_pfn; - - totalpages += pages; - if (pages) - node_set_state(nid, N_MEMORY); - } - return totalpages; -} - -/* - * Find the PFN the Movable zone begins in each node. Kernel memory - * is spread evenly between nodes as long as the nodes have enough - * memory. When they don't, some nodes will have more kernelcore than - * others - */ -static void __init find_zone_movable_pfns_for_nodes(void) -{ - int i, nid; - unsigned long usable_startpfn; - unsigned long kernelcore_node, kernelcore_remaining; - /* save the state before borrow the nodemask */ - nodemask_t saved_node_state = node_states[N_MEMORY]; - unsigned long totalpages = early_calculate_totalpages(); - int usable_nodes = nodes_weight(node_states[N_MEMORY]); - struct memblock_region *r; - - /* Need to find movable_zone earlier when movable_node is specified. */ - find_usable_zone_for_movable(); - - /* - * If movable_node is specified, ignore kernelcore and movablecore - * options. - */ - if (movable_node_is_enabled()) { - for_each_memblock(memory, r) { - if (!memblock_is_hotpluggable(r)) - continue; - - nid = r->nid; - - usable_startpfn = PFN_DOWN(r->base); - zone_movable_pfn[nid] = zone_movable_pfn[nid] ? - min(usable_startpfn, zone_movable_pfn[nid]) : - usable_startpfn; - } - - goto out2; - } - - /* - * If kernelcore=mirror is specified, ignore movablecore option - */ - if (mirrored_kernelcore) { - bool mem_below_4gb_not_mirrored = false; - - for_each_memblock(memory, r) { - if (memblock_is_mirror(r)) - continue; - - nid = r->nid; - - usable_startpfn = memblock_region_memory_base_pfn(r); - - if (usable_startpfn < 0x100000) { - mem_below_4gb_not_mirrored = true; - continue; - } - - zone_movable_pfn[nid] = zone_movable_pfn[nid] ? - min(usable_startpfn, zone_movable_pfn[nid]) : - usable_startpfn; - } - - if (mem_below_4gb_not_mirrored) - pr_warn("This configuration results in unmirrored kernel memory."); - - goto out2; - } - - /* - * If movablecore=nn[KMG] was specified, calculate what size of - * kernelcore that corresponds so that memory usable for - * any allocation type is evenly spread. If both kernelcore - * and movablecore are specified, then the value of kernelcore - * will be used for required_kernelcore if it's greater than - * what movablecore would have allowed. - */ - if (required_movablecore) { - unsigned long corepages; - - /* - * Round-up so that ZONE_MOVABLE is at least as large as what - * was requested by the user - */ - required_movablecore = - roundup(required_movablecore, MAX_ORDER_NR_PAGES); - required_movablecore = min(totalpages, required_movablecore); - corepages = totalpages - required_movablecore; - - required_kernelcore = max(required_kernelcore, corepages); - } - - /* - * If kernelcore was not specified or kernelcore size is larger - * than totalpages, there is no ZONE_MOVABLE. - */ - if (!required_kernelcore || required_kernelcore >= totalpages) - goto out; - - /* usable_startpfn is the lowest possible pfn ZONE_MOVABLE can be at */ - usable_startpfn = arch_zone_lowest_possible_pfn[movable_zone]; - -restart: - /* Spread kernelcore memory as evenly as possible throughout nodes */ - kernelcore_node = required_kernelcore / usable_nodes; - for_each_node_state(nid, N_MEMORY) { - unsigned long start_pfn, end_pfn; - - /* - * Recalculate kernelcore_node if the division per node - * now exceeds what is necessary to satisfy the requested - * amount of memory for the kernel - */ - if (required_kernelcore < kernelcore_node) - kernelcore_node = required_kernelcore / usable_nodes; - - /* - * As the map is walked, we track how much memory is usable - * by the kernel using kernelcore_remaining. When it is - * 0, the rest of the node is usable by ZONE_MOVABLE - */ - kernelcore_remaining = kernelcore_node; - - /* Go through each range of PFNs within this node */ - for_each_mem_pfn_range(i, nid, &start_pfn, &end_pfn, NULL) { - unsigned long size_pages; - - start_pfn = max(start_pfn, zone_movable_pfn[nid]); - if (start_pfn >= end_pfn) - continue; - - /* Account for what is only usable for kernelcore */ - if (start_pfn < usable_startpfn) { - unsigned long kernel_pages; - kernel_pages = min(end_pfn, usable_startpfn) - - start_pfn; - - kernelcore_remaining -= min(kernel_pages, - kernelcore_remaining); - required_kernelcore -= min(kernel_pages, - required_kernelcore); - - /* Continue if range is now fully accounted */ - if (end_pfn <= usable_startpfn) { - - /* - * Push zone_movable_pfn to the end so - * that if we have to rebalance - * kernelcore across nodes, we will - * not double account here - */ - zone_movable_pfn[nid] = end_pfn; - continue; - } - start_pfn = usable_startpfn; - } - - /* - * The usable PFN range for ZONE_MOVABLE is from - * start_pfn->end_pfn. Calculate size_pages as the - * number of pages used as kernelcore - */ - size_pages = end_pfn - start_pfn; - if (size_pages > kernelcore_remaining) - size_pages = kernelcore_remaining; - zone_movable_pfn[nid] = start_pfn + size_pages; - - /* - * Some kernelcore has been met, update counts and - * break if the kernelcore for this node has been - * satisfied - */ - required_kernelcore -= min(required_kernelcore, - size_pages); - kernelcore_remaining -= size_pages; - if (!kernelcore_remaining) - break; - } - } - - /* - * If there is still required_kernelcore, we do another pass with one - * less node in the count. This will push zone_movable_pfn[nid] further - * along on the nodes that still have memory until kernelcore is - * satisfied - */ - usable_nodes--; - if (usable_nodes && required_kernelcore > usable_nodes) - goto restart; - -out2: - /* Align start of ZONE_MOVABLE on all nids to MAX_ORDER_NR_PAGES */ - for (nid = 0; nid < MAX_NUMNODES; nid++) - zone_movable_pfn[nid] = - roundup(zone_movable_pfn[nid], MAX_ORDER_NR_PAGES); - -out: - /* restore the node_state */ - node_states[N_MEMORY] = saved_node_state; -} - -/* Any regular or high memory on that node ? */ -static void check_for_memory(pg_data_t *pgdat, int nid) -{ - enum zone_type zone_type; - - if (N_MEMORY == N_NORMAL_MEMORY) - return; - - for (zone_type = 0; zone_type <= ZONE_MOVABLE - 1; zone_type++) { - struct zone *zone = &pgdat->node_zones[zone_type]; - if (populated_zone(zone)) { - node_set_state(nid, N_HIGH_MEMORY); - if (N_NORMAL_MEMORY != N_HIGH_MEMORY && - zone_type <= ZONE_NORMAL) - node_set_state(nid, N_NORMAL_MEMORY); - break; - } - } -} - -/** - * free_area_init_nodes - Initialise all pg_data_t and zone data - * @max_zone_pfn: an array of max PFNs for each zone - * - * This will call free_area_init_node() for each active node in the system. - * Using the page ranges provided by memblock_set_node(), the size of each - * zone in each node and their holes is calculated. If the maximum PFN - * between two adjacent zones match, it is assumed that the zone is empty. - * For example, if arch_max_dma_pfn == arch_max_dma32_pfn, it is assumed - * that arch_max_dma32_pfn has no pages. It is also assumed that a zone - * starts where the previous one ended. For example, ZONE_DMA32 starts - * at arch_max_dma_pfn. - */ -void __init free_area_init_nodes(unsigned long *max_zone_pfn) -{ - unsigned long start_pfn, end_pfn; - int i, nid; - - /* Record where the zone boundaries are */ - memset(arch_zone_lowest_possible_pfn, 0, - sizeof(arch_zone_lowest_possible_pfn)); - memset(arch_zone_highest_possible_pfn, 0, - sizeof(arch_zone_highest_possible_pfn)); - - start_pfn = find_min_pfn_with_active_regions(); - - for (i = 0; i < MAX_NR_ZONES; i++) { - if (i == ZONE_MOVABLE) - continue; - - end_pfn = max(max_zone_pfn[i], start_pfn); - arch_zone_lowest_possible_pfn[i] = start_pfn; - arch_zone_highest_possible_pfn[i] = end_pfn; - - start_pfn = end_pfn; - } - arch_zone_lowest_possible_pfn[ZONE_MOVABLE] = 0; - arch_zone_highest_possible_pfn[ZONE_MOVABLE] = 0; - - /* Find the PFNs that ZONE_MOVABLE begins at in each node */ - memset(zone_movable_pfn, 0, sizeof(zone_movable_pfn)); - find_zone_movable_pfns_for_nodes(); - - /* Print out the zone ranges */ - pr_info("Zone ranges:\n"); - for (i = 0; i < MAX_NR_ZONES; i++) { - if (i == ZONE_MOVABLE) - continue; - pr_info(" %-8s ", zone_names[i]); - if (arch_zone_lowest_possible_pfn[i] == - arch_zone_highest_possible_pfn[i]) - pr_cont("empty\n"); - else - pr_cont("[mem %#018Lx-%#018Lx]\n", - (u64)arch_zone_lowest_possible_pfn[i] - << PAGE_SHIFT, - ((u64)arch_zone_highest_possible_pfn[i] - << PAGE_SHIFT) - 1); - } - - /* Print out the PFNs ZONE_MOVABLE begins at in each node */ - pr_info("Movable zone start for each node\n"); - for (i = 0; i < MAX_NUMNODES; i++) { - if (zone_movable_pfn[i]) - pr_info(" Node %d: %#018Lx\n", i, - (u64)zone_movable_pfn[i] << PAGE_SHIFT); - } - - /* Print out the early node map */ - pr_info("Early memory node ranges\n"); - for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, &nid) - pr_info(" node %3d: [mem %#018Lx-%#018Lx]\n", nid, - (u64)start_pfn << PAGE_SHIFT, - ((u64)end_pfn << PAGE_SHIFT) - 1); - - /* Initialise every node */ - mminit_verify_pageflags_layout(); - setup_nr_node_ids(); - for_each_online_node(nid) { - pg_data_t *pgdat = NODE_DATA(nid); - free_area_init_node(nid, NULL, - find_min_pfn_for_node(nid), NULL); - - /* Any memory on that node */ - if (pgdat->node_present_pages) - node_set_state(nid, N_MEMORY); - check_for_memory(pgdat, nid); - } -} - -static int __init cmdline_parse_core(char *p, unsigned long *core) -{ - unsigned long long coremem; - if (!p) - return -EINVAL; - - coremem = memparse(p, &p); - *core = coremem >> PAGE_SHIFT; - - /* Paranoid check that UL is enough for the coremem value */ - WARN_ON((coremem >> PAGE_SHIFT) > ULONG_MAX); - - return 0; -} - -/* - * kernelcore=size sets the amount of memory for use for allocations that - * cannot be reclaimed or migrated. - */ -static int __init cmdline_parse_kernelcore(char *p) -{ - /* parse kernelcore=mirror */ - if (parse_option_str(p, "mirror")) { - mirrored_kernelcore = true; - return 0; - } - - return cmdline_parse_core(p, &required_kernelcore); -} - -/* - * movablecore=size sets the amount of memory for use for allocations that - * can be reclaimed or migrated. - */ -static int __init cmdline_parse_movablecore(char *p) -{ - return cmdline_parse_core(p, &required_movablecore); -} - -early_param("kernelcore", cmdline_parse_kernelcore); -early_param("movablecore", cmdline_parse_movablecore); - -#endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */ - -void adjust_managed_page_count(struct page *page, long count) -{ - spin_lock(&managed_page_count_lock); - page_zone(page)->managed_pages += count; - totalram_pages += count; -#ifdef CONFIG_HIGHMEM - if (PageHighMem(page)) - totalhigh_pages += count; -#endif - spin_unlock(&managed_page_count_lock); -} -EXPORT_SYMBOL(adjust_managed_page_count); - -unsigned long free_reserved_area(void *start, void *end, int poison, char *s) -{ - void *pos; - unsigned long pages = 0; - - start = (void *)PAGE_ALIGN((unsigned long)start); - end = (void *)((unsigned long)end & PAGE_MASK); - for (pos = start; pos < end; pos += PAGE_SIZE, pages++) { - if ((unsigned int)poison <= 0xFF) - memset(pos, poison, PAGE_SIZE); - free_reserved_page(virt_to_page(pos)); - } - - if (pages && s) - pr_info("Freeing %s memory: %ldK (%p - %p)\n", - s, pages << (PAGE_SHIFT - 10), start, end); - - return pages; -} -EXPORT_SYMBOL(free_reserved_area); - -#ifdef CONFIG_HIGHMEM -void free_highmem_page(struct page *page) -{ - __free_reserved_page(page); - totalram_pages++; - page_zone(page)->managed_pages++; - totalhigh_pages++; -} -#endif - - -void __init mem_init_print_info(const char *str) -{ - unsigned long physpages, codesize, datasize, rosize, bss_size; - unsigned long init_code_size, init_data_size; - - physpages = get_num_physpages(); - codesize = _etext - _stext; - datasize = _edata - _sdata; - rosize = __end_rodata - __start_rodata; - bss_size = __bss_stop - __bss_start; - init_data_size = __init_end - __init_begin; - init_code_size = _einittext - _sinittext; - - /* - * Detect special cases and adjust section sizes accordingly: - * 1) .init.* may be embedded into .data sections - * 2) .init.text.* may be out of [__init_begin, __init_end], - * please refer to arch/tile/kernel/vmlinux.lds.S. - * 3) .rodata.* may be embedded into .text or .data sections. - */ -#define adj_init_size(start, end, size, pos, adj) \ - do { \ - if (start <= pos && pos < end && size > adj) \ - size -= adj; \ - } while (0) - - adj_init_size(__init_begin, __init_end, init_data_size, - _sinittext, init_code_size); - adj_init_size(_stext, _etext, codesize, _sinittext, init_code_size); - adj_init_size(_sdata, _edata, datasize, __init_begin, init_data_size); - adj_init_size(_stext, _etext, codesize, __start_rodata, rosize); - adj_init_size(_sdata, _edata, datasize, __start_rodata, rosize); - -#undef adj_init_size - - pr_info("Memory: %luK/%luK available (%luK kernel code, %luK rwdata, %luK rodata, %luK init, %luK bss, %luK reserved, %luK cma-reserved" -#ifdef CONFIG_HIGHMEM - ", %luK highmem" -#endif - "%s%s)\n", - nr_free_pages() << (PAGE_SHIFT - 10), - physpages << (PAGE_SHIFT - 10), - codesize >> 10, datasize >> 10, rosize >> 10, - (init_data_size + init_code_size) >> 10, bss_size >> 10, - (physpages - totalram_pages - totalcma_pages) << (PAGE_SHIFT - 10), - totalcma_pages << (PAGE_SHIFT - 10), -#ifdef CONFIG_HIGHMEM - totalhigh_pages << (PAGE_SHIFT - 10), -#endif - str ? ", " : "", str ? str : ""); -} - -/** - * set_dma_reserve - set the specified number of pages reserved in the first zone - * @new_dma_reserve: The number of pages to mark reserved - * - * The per-cpu batchsize and zone watermarks are determined by managed_pages. - * In the DMA zone, a significant percentage may be consumed by kernel image - * and other unfreeable allocations which can skew the watermarks badly. This - * function may optionally be used to account for unfreeable pages in the - * first zone (e.g., ZONE_DMA). The effect will be lower watermarks and - * smaller per-cpu batchsize. - */ -void __init set_dma_reserve(unsigned long new_dma_reserve) -{ - dma_reserve = new_dma_reserve; -} - -void __init free_area_init(unsigned long *zones_size) -{ - free_area_init_node(0, zones_size, - __pa(PAGE_OFFSET) >> PAGE_SHIFT, NULL); -} - -static int page_alloc_cpu_notify(struct notifier_block *self, - unsigned long action, void *hcpu) -{ - int cpu = (unsigned long)hcpu; - - if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) { - lru_add_drain_cpu(cpu); - drain_pages(cpu); - - /* - * Spill the event counters of the dead processor - * into the current processors event counters. - * This artificially elevates the count of the current - * processor. - */ - vm_events_fold_cpu(cpu); - - /* - * Zero the differential counters of the dead processor - * so that the vm statistics are consistent. - * - * This is only okay since the processor is dead and cannot - * race with what we are doing. - */ - cpu_vm_stats_fold(cpu); - } - return NOTIFY_OK; -} - -void __init page_alloc_init(void) -{ - hotcpu_notifier(page_alloc_cpu_notify, 0); -} - -/* - * calculate_totalreserve_pages - called when sysctl_lowmem_reserve_ratio - * or min_free_kbytes changes. - */ -static void calculate_totalreserve_pages(void) -{ - struct pglist_data *pgdat; - unsigned long reserve_pages = 0; - enum zone_type i, j; - - for_each_online_pgdat(pgdat) { - - pgdat->totalreserve_pages = 0; - - for (i = 0; i < MAX_NR_ZONES; i++) { - struct zone *zone = pgdat->node_zones + i; - long max = 0; - - /* Find valid and maximum lowmem_reserve in the zone */ - for (j = i; j < MAX_NR_ZONES; j++) { - if (zone->lowmem_reserve[j] > max) - max = zone->lowmem_reserve[j]; - } - - /* we treat the high watermark as reserved pages. */ - max += high_wmark_pages(zone); - - if (max > zone->managed_pages) - max = zone->managed_pages; - - pgdat->totalreserve_pages += max; - - reserve_pages += max; - } - } - totalreserve_pages = reserve_pages; -} - -/* - * setup_per_zone_lowmem_reserve - called whenever - * sysctl_lowmem_reserve_ratio changes. Ensures that each zone - * has a correct pages reserved value, so an adequate number of - * pages are left in the zone after a successful __alloc_pages(). - */ -static void setup_per_zone_lowmem_reserve(void) -{ - struct pglist_data *pgdat; - enum zone_type j, idx; - - for_each_online_pgdat(pgdat) { - for (j = 0; j < MAX_NR_ZONES; j++) { - struct zone *zone = pgdat->node_zones + j; - unsigned long managed_pages = zone->managed_pages; - - zone->lowmem_reserve[j] = 0; - - idx = j; - while (idx) { - struct zone *lower_zone; - - idx--; - - if (sysctl_lowmem_reserve_ratio[idx] < 1) - sysctl_lowmem_reserve_ratio[idx] = 1; - - lower_zone = pgdat->node_zones + idx; - lower_zone->lowmem_reserve[j] = managed_pages / - sysctl_lowmem_reserve_ratio[idx]; - managed_pages += lower_zone->managed_pages; - } - } - } - - /* update totalreserve_pages */ - calculate_totalreserve_pages(); -} - -static void __setup_per_zone_wmarks(void) -{ - unsigned long pages_min = min_free_kbytes >> (PAGE_SHIFT - 10); - unsigned long lowmem_pages = 0; - struct zone *zone; - unsigned long flags; - - /* Calculate total number of !ZONE_HIGHMEM pages */ - for_each_zone(zone) { - if (!is_highmem(zone)) - lowmem_pages += zone->managed_pages; - } - - for_each_zone(zone) { - u64 tmp; - - spin_lock_irqsave(&zone->lock, flags); - tmp = (u64)pages_min * zone->managed_pages; - do_div(tmp, lowmem_pages); - if (is_highmem(zone)) { - /* - * __GFP_HIGH and PF_MEMALLOC allocations usually don't - * need highmem pages, so cap pages_min to a small - * value here. - * - * The WMARK_HIGH-WMARK_LOW and (WMARK_LOW-WMARK_MIN) - * deltas control asynch page reclaim, and so should - * not be capped for highmem. - */ - unsigned long min_pages; - - min_pages = zone->managed_pages / 1024; - min_pages = clamp(min_pages, SWAP_CLUSTER_MAX, 128UL); - zone->watermark[WMARK_MIN] = min_pages; - } else { - /* - * If it's a lowmem zone, reserve a number of pages - * proportionate to the zone's size. - */ - zone->watermark[WMARK_MIN] = tmp; - } - - /* - * Set the kswapd watermarks distance according to the - * scale factor in proportion to available memory, but - * ensure a minimum size on small systems. - */ - tmp = max_t(u64, tmp >> 2, - mult_frac(zone->managed_pages, - watermark_scale_factor, 10000)); - - zone->watermark[WMARK_LOW] = min_wmark_pages(zone) + tmp; - zone->watermark[WMARK_HIGH] = min_wmark_pages(zone) + tmp * 2; - - spin_unlock_irqrestore(&zone->lock, flags); - } - - /* update totalreserve_pages */ - calculate_totalreserve_pages(); -} - -/** - * setup_per_zone_wmarks - called when min_free_kbytes changes - * or when memory is hot-{added|removed} - * - * Ensures that the watermark[min,low,high] values for each zone are set - * correctly with respect to min_free_kbytes. - */ -void setup_per_zone_wmarks(void) -{ - mutex_lock(&zonelists_mutex); - __setup_per_zone_wmarks(); - mutex_unlock(&zonelists_mutex); -} - -/* - * Initialise min_free_kbytes. - * - * For small machines we want it small (128k min). For large machines - * we want it large (64MB max). But it is not linear, because network - * bandwidth does not increase linearly with machine size. We use - * - * min_free_kbytes = 4 * sqrt(lowmem_kbytes), for better accuracy: - * min_free_kbytes = sqrt(lowmem_kbytes * 16) - * - * which yields - * - * 16MB: 512k - * 32MB: 724k - * 64MB: 1024k - * 128MB: 1448k - * 256MB: 2048k - * 512MB: 2896k - * 1024MB: 4096k - * 2048MB: 5792k - * 4096MB: 8192k - * 8192MB: 11584k - * 16384MB: 16384k - */ -int __meminit init_per_zone_wmark_min(void) -{ - unsigned long lowmem_kbytes; - int new_min_free_kbytes; - - lowmem_kbytes = nr_free_buffer_pages() * (PAGE_SIZE >> 10); - new_min_free_kbytes = int_sqrt(lowmem_kbytes * 16); - - if (new_min_free_kbytes > user_min_free_kbytes) { - min_free_kbytes = new_min_free_kbytes; - if (min_free_kbytes < 128) - min_free_kbytes = 128; - if (min_free_kbytes > 65536) - min_free_kbytes = 65536; - } else { - pr_warn("min_free_kbytes is not updated to %d because user defined value %d is preferred\n", - new_min_free_kbytes, user_min_free_kbytes); - } - setup_per_zone_wmarks(); - refresh_zone_stat_thresholds(); - setup_per_zone_lowmem_reserve(); - -#ifdef CONFIG_NUMA - setup_min_unmapped_ratio(); - setup_min_slab_ratio(); -#endif - - return 0; -} -core_initcall(init_per_zone_wmark_min) - -/* - * min_free_kbytes_sysctl_handler - just a wrapper around proc_dointvec() so - * that we can call two helper functions whenever min_free_kbytes - * changes. - */ -int min_free_kbytes_sysctl_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *length, loff_t *ppos) -{ - int rc; - - rc = proc_dointvec_minmax(table, write, buffer, length, ppos); - if (rc) - return rc; - - if (write) { - user_min_free_kbytes = min_free_kbytes; - setup_per_zone_wmarks(); - } - return 0; -} - -int watermark_scale_factor_sysctl_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *length, loff_t *ppos) -{ - int rc; - - rc = proc_dointvec_minmax(table, write, buffer, length, ppos); - if (rc) - return rc; - - if (write) - setup_per_zone_wmarks(); - - return 0; -} - -#ifdef CONFIG_NUMA -static void setup_min_unmapped_ratio(void) -{ - pg_data_t *pgdat; - struct zone *zone; - - for_each_online_pgdat(pgdat) - pgdat->min_unmapped_pages = 0; - - for_each_zone(zone) - zone->zone_pgdat->min_unmapped_pages += (zone->managed_pages * - sysctl_min_unmapped_ratio) / 100; -} - - -int sysctl_min_unmapped_ratio_sysctl_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *length, loff_t *ppos) -{ - int rc; - - rc = proc_dointvec_minmax(table, write, buffer, length, ppos); - if (rc) - return rc; - - setup_min_unmapped_ratio(); - - return 0; -} - -static void setup_min_slab_ratio(void) -{ - pg_data_t *pgdat; - struct zone *zone; - - for_each_online_pgdat(pgdat) - pgdat->min_slab_pages = 0; - - for_each_zone(zone) - zone->zone_pgdat->min_slab_pages += (zone->managed_pages * - sysctl_min_slab_ratio) / 100; -} - -int sysctl_min_slab_ratio_sysctl_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *length, loff_t *ppos) -{ - int rc; - - rc = proc_dointvec_minmax(table, write, buffer, length, ppos); - if (rc) - return rc; - - setup_min_slab_ratio(); - - return 0; -} -#endif - -/* - * lowmem_reserve_ratio_sysctl_handler - just a wrapper around - * proc_dointvec() so that we can call setup_per_zone_lowmem_reserve() - * whenever sysctl_lowmem_reserve_ratio changes. - * - * The reserve ratio obviously has absolutely no relation with the - * minimum watermarks. The lowmem reserve ratio can only make sense - * if in function of the boot time zone sizes. - */ -int lowmem_reserve_ratio_sysctl_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *length, loff_t *ppos) -{ - proc_dointvec_minmax(table, write, buffer, length, ppos); - setup_per_zone_lowmem_reserve(); - return 0; -} - -/* - * percpu_pagelist_fraction - changes the pcp->high for each zone on each - * cpu. It is the fraction of total pages in each zone that a hot per cpu - * pagelist can have before it gets flushed back to buddy allocator. - */ -int percpu_pagelist_fraction_sysctl_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *length, loff_t *ppos) -{ - struct zone *zone; - int old_percpu_pagelist_fraction; - int ret; - - mutex_lock(&pcp_batch_high_lock); - old_percpu_pagelist_fraction = percpu_pagelist_fraction; - - ret = proc_dointvec_minmax(table, write, buffer, length, ppos); - if (!write || ret < 0) - goto out; - - /* Sanity checking to avoid pcp imbalance */ - if (percpu_pagelist_fraction && - percpu_pagelist_fraction < MIN_PERCPU_PAGELIST_FRACTION) { - percpu_pagelist_fraction = old_percpu_pagelist_fraction; - ret = -EINVAL; - goto out; - } - - /* No change? */ - if (percpu_pagelist_fraction == old_percpu_pagelist_fraction) - goto out; - - for_each_populated_zone(zone) { - unsigned int cpu; - - for_each_possible_cpu(cpu) - pageset_set_high_and_batch(zone, - per_cpu_ptr(zone->pageset, cpu)); - } -out: - mutex_unlock(&pcp_batch_high_lock); - return ret; -} - -#ifdef CONFIG_NUMA -int hashdist = HASHDIST_DEFAULT; - -static int __init set_hashdist(char *str) -{ - if (!str) - return 0; - hashdist = simple_strtoul(str, &str, 0); - return 1; -} -__setup("hashdist=", set_hashdist); -#endif - -#ifndef __HAVE_ARCH_RESERVED_KERNEL_PAGES -/* - * Returns the number of pages that arch has reserved but - * is not known to alloc_large_system_hash(). - */ -static unsigned long __init arch_reserved_kernel_pages(void) -{ - return 0; -} -#endif - -/* - * allocate a large system hash table from bootmem - * - it is assumed that the hash table must contain an exact power-of-2 - * quantity of entries - * - limit is the number of hash buckets, not the total allocation size - */ -void *__init alloc_large_system_hash(const char *tablename, - unsigned long bucketsize, - unsigned long numentries, - int scale, - int flags, - unsigned int *_hash_shift, - unsigned int *_hash_mask, - unsigned long low_limit, - unsigned long high_limit) -{ - unsigned long long max = high_limit; - unsigned long log2qty, size; - void *table = NULL; - - /* allow the kernel cmdline to have a say */ - if (!numentries) { - /* round applicable memory size up to nearest megabyte */ - numentries = nr_kernel_pages; - numentries -= arch_reserved_kernel_pages(); - - /* It isn't necessary when PAGE_SIZE >= 1MB */ - if (PAGE_SHIFT < 20) - numentries = round_up(numentries, (1<<20)/PAGE_SIZE); - - /* limit to 1 bucket per 2^scale bytes of low memory */ - if (scale > PAGE_SHIFT) - numentries >>= (scale - PAGE_SHIFT); - else - numentries <<= (PAGE_SHIFT - scale); - - /* Make sure we've got at least a 0-order allocation.. */ - if (unlikely(flags & HASH_SMALL)) { - /* Makes no sense without HASH_EARLY */ - WARN_ON(!(flags & HASH_EARLY)); - if (!(numentries >> *_hash_shift)) { - numentries = 1UL << *_hash_shift; - BUG_ON(!numentries); - } - } else if (unlikely((numentries * bucketsize) < PAGE_SIZE)) - numentries = PAGE_SIZE / bucketsize; - } - numentries = roundup_pow_of_two(numentries); - - /* limit allocation size to 1/16 total memory by default */ - if (max == 0) { - max = ((unsigned long long)nr_all_pages << PAGE_SHIFT) >> 4; - do_div(max, bucketsize); - } - max = min(max, 0x80000000ULL); - - if (numentries < low_limit) - numentries = low_limit; - if (numentries > max) - numentries = max; - - log2qty = ilog2(numentries); - - do { - size = bucketsize << log2qty; - if (flags & HASH_EARLY) - table = memblock_virt_alloc_nopanic(size, 0); - else if (hashdist) - table = __vmalloc(size, GFP_ATOMIC, PAGE_KERNEL); - else { - /* - * If bucketsize is not a power-of-two, we may free - * some pages at the end of hash table which - * alloc_pages_exact() automatically does - */ - if (get_order(size) < MAX_ORDER) { - table = alloc_pages_exact(size, GFP_ATOMIC); - kmemleak_alloc(table, size, 1, GFP_ATOMIC); - } - } - } while (!table && size > PAGE_SIZE && --log2qty); - - if (!table) - panic("Failed to allocate %s hash table\n", tablename); - - pr_info("%s hash table entries: %ld (order: %d, %lu bytes)\n", - tablename, 1UL << log2qty, ilog2(size) - PAGE_SHIFT, size); - - if (_hash_shift) - *_hash_shift = log2qty; - if (_hash_mask) - *_hash_mask = (1 << log2qty) - 1; - - return table; -} - -/* - * This function checks whether pageblock includes unmovable pages or not. - * If @count is not zero, it is okay to include less @count unmovable pages - * - * PageLRU check without isolation or lru_lock could race so that - * MIGRATE_MOVABLE block might include unmovable pages. It means you can't - * expect this function should be exact. - */ -bool has_unmovable_pages(struct zone *zone, struct page *page, int count, - bool skip_hwpoisoned_pages) -{ - unsigned long pfn, iter, found; - int mt; - - /* - * For avoiding noise data, lru_add_drain_all() should be called - * If ZONE_MOVABLE, the zone never contains unmovable pages - */ - if (zone_idx(zone) == ZONE_MOVABLE) - return false; - mt = get_pageblock_migratetype(page); - if (mt == MIGRATE_MOVABLE || is_migrate_cma(mt)) - return false; - - pfn = page_to_pfn(page); - for (found = 0, iter = 0; iter < pageblock_nr_pages; iter++) { - unsigned long check = pfn + iter; - - if (!pfn_valid_within(check)) - continue; - - page = pfn_to_page(check); - - /* - * Hugepages are not in LRU lists, but they're movable. - * We need not scan over tail pages bacause we don't - * handle each tail page individually in migration. - */ - if (PageHuge(page)) { - iter = round_up(iter + 1, 1<_refcount is zero at all time. - */ - if (!page_ref_count(page)) { - if (PageBuddy(page)) - iter += (1 << page_order(page)) - 1; - continue; - } - - /* - * The HWPoisoned page may be not in buddy system, and - * page_count() is not 0. - */ - if (skip_hwpoisoned_pages && PageHWPoison(page)) - continue; - - if (!PageLRU(page)) - found++; - /* - * If there are RECLAIMABLE pages, we need to check - * it. But now, memory offline itself doesn't call - * shrink_node_slabs() and it still to be fixed. - */ - /* - * If the page is not RAM, page_count()should be 0. - * we don't need more check. This is an _used_ not-movable page. - * - * The problematic thing here is PG_reserved pages. PG_reserved - * is set to both of a memory hole page and a _used_ kernel - * page at boot. - */ - if (found > count) - return true; - } - return false; -} - -bool is_pageblock_removable_nolock(struct page *page) -{ - struct zone *zone; - unsigned long pfn; - - /* - * We have to be careful here because we are iterating over memory - * sections which are not zone aware so we might end up outside of - * the zone but still within the section. - * We have to take care about the node as well. If the node is offline - * its NODE_DATA will be NULL - see page_zone. - */ - if (!node_online(page_to_nid(page))) - return false; - - zone = page_zone(page); - pfn = page_to_pfn(page); - if (!zone_spans_pfn(zone, pfn)) - return false; - - return !has_unmovable_pages(zone, page, 0, true); -} - -#if (defined(CONFIG_MEMORY_ISOLATION) && defined(CONFIG_COMPACTION)) || defined(CONFIG_CMA) - -static unsigned long pfn_max_align_down(unsigned long pfn) -{ - return pfn & ~(max_t(unsigned long, MAX_ORDER_NR_PAGES, - pageblock_nr_pages) - 1); -} - -static unsigned long pfn_max_align_up(unsigned long pfn) -{ - return ALIGN(pfn, max_t(unsigned long, MAX_ORDER_NR_PAGES, - pageblock_nr_pages)); -} - -/* [start, end) must belong to a single zone. */ -static int __alloc_contig_migrate_range(struct compact_control *cc, - unsigned long start, unsigned long end) -{ - /* This function is based on compact_zone() from compaction.c. */ - unsigned long nr_reclaimed; - unsigned long pfn = start; - unsigned int tries = 0; - int ret = 0; - - migrate_prep(); - - while (pfn < end || !list_empty(&cc->migratepages)) { - if (fatal_signal_pending(current)) { - ret = -EINTR; - break; - } - - if (list_empty(&cc->migratepages)) { - cc->nr_migratepages = 0; - pfn = isolate_migratepages_range(cc, pfn, end); - if (!pfn) { - ret = -EINTR; - break; - } - tries = 0; - } else if (++tries == 5) { - ret = ret < 0 ? ret : -EBUSY; - break; - } - - nr_reclaimed = reclaim_clean_pages_from_list(cc->zone, - &cc->migratepages); - cc->nr_migratepages -= nr_reclaimed; - - ret = migrate_pages(&cc->migratepages, alloc_migrate_target, - NULL, 0, cc->mode, MR_CMA); - } - if (ret < 0) { - putback_movable_pages(&cc->migratepages); - return ret; - } - return 0; -} - -/** - * alloc_contig_range() -- tries to allocate given range of pages - * @start: start PFN to allocate - * @end: one-past-the-last PFN to allocate - * @migratetype: migratetype of the underlaying pageblocks (either - * #MIGRATE_MOVABLE or #MIGRATE_CMA). All pageblocks - * in range must have the same migratetype and it must - * be either of the two. - * - * The PFN range does not have to be pageblock or MAX_ORDER_NR_PAGES - * aligned, however it's the caller's responsibility to guarantee that - * we are the only thread that changes migrate type of pageblocks the - * pages fall in. - * - * The PFN range must belong to a single zone. - * - * Returns zero on success or negative error code. On success all - * pages which PFN is in [start, end) are allocated for the caller and - * need to be freed with free_contig_range(). - */ -int alloc_contig_range(unsigned long start, unsigned long end, - unsigned migratetype) -{ - unsigned long outer_start, outer_end; - unsigned int order; - int ret = 0; - - struct compact_control cc = { - .nr_migratepages = 0, - .order = -1, - .zone = page_zone(pfn_to_page(start)), - .mode = MIGRATE_SYNC, - .ignore_skip_hint = true, - }; - INIT_LIST_HEAD(&cc.migratepages); - - /* - * What we do here is we mark all pageblocks in range as - * MIGRATE_ISOLATE. Because pageblock and max order pages may - * have different sizes, and due to the way page allocator - * work, we align the range to biggest of the two pages so - * that page allocator won't try to merge buddies from - * different pageblocks and change MIGRATE_ISOLATE to some - * other migration type. - * - * Once the pageblocks are marked as MIGRATE_ISOLATE, we - * migrate the pages from an unaligned range (ie. pages that - * we are interested in). This will put all the pages in - * range back to page allocator as MIGRATE_ISOLATE. - * - * When this is done, we take the pages in range from page - * allocator removing them from the buddy system. This way - * page allocator will never consider using them. - * - * This lets us mark the pageblocks back as - * MIGRATE_CMA/MIGRATE_MOVABLE so that free pages in the - * aligned range but not in the unaligned, original range are - * put back to page allocator so that buddy can use them. - */ - - ret = start_isolate_page_range(pfn_max_align_down(start), - pfn_max_align_up(end), migratetype, - false); - if (ret) - return ret; - - /* - * In case of -EBUSY, we'd like to know which page causes problem. - * So, just fall through. We will check it in test_pages_isolated(). - */ - ret = __alloc_contig_migrate_range(&cc, start, end); - if (ret && ret != -EBUSY) - goto done; - - /* - * Pages from [start, end) are within a MAX_ORDER_NR_PAGES - * aligned blocks that are marked as MIGRATE_ISOLATE. What's - * more, all pages in [start, end) are free in page allocator. - * What we are going to do is to allocate all pages from - * [start, end) (that is remove them from page allocator). - * - * The only problem is that pages at the beginning and at the - * end of interesting range may be not aligned with pages that - * page allocator holds, ie. they can be part of higher order - * pages. Because of this, we reserve the bigger range and - * once this is done free the pages we are not interested in. - * - * We don't have to hold zone->lock here because the pages are - * isolated thus they won't get removed from buddy. - */ - - lru_add_drain_all(); - drain_all_pages(cc.zone); - - order = 0; - outer_start = start; - while (!PageBuddy(pfn_to_page(outer_start))) { - if (++order >= MAX_ORDER) { - outer_start = start; - break; - } - outer_start &= ~0UL << order; - } - - if (outer_start != start) { - order = page_order(pfn_to_page(outer_start)); - - /* - * outer_start page could be small order buddy page and - * it doesn't include start page. Adjust outer_start - * in this case to report failed page properly - * on tracepoint in test_pages_isolated() - */ - if (outer_start + (1UL << order) <= start) - outer_start = start; - } - - /* Make sure the range is really isolated. */ - if (test_pages_isolated(outer_start, end, false)) { - pr_info("%s: [%lx, %lx) PFNs busy\n", - __func__, outer_start, end); - ret = -EBUSY; - goto done; - } - - /* Grab isolated pages from freelists. */ - outer_end = isolate_freepages_range(&cc, outer_start, end); - if (!outer_end) { - ret = -EBUSY; - goto done; - } - - /* Free head and tail (if any) */ - if (start != outer_start) - free_contig_range(outer_start, start - outer_start); - if (end != outer_end) - free_contig_range(end, outer_end - end); - -done: - undo_isolate_page_range(pfn_max_align_down(start), - pfn_max_align_up(end), migratetype); - return ret; -} - -void free_contig_range(unsigned long pfn, unsigned nr_pages) -{ - unsigned int count = 0; - - for (; nr_pages--; pfn++) { - struct page *page = pfn_to_page(pfn); - - count += page_count(page) != 1; - __free_page(page); - } - WARN(count != 0, "%d pages are still in use!\n", count); -} -#endif - -#ifdef CONFIG_MEMORY_HOTPLUG -/* - * The zone indicated has a new number of managed_pages; batch sizes and percpu - * page high values need to be recalulated. - */ -void __meminit zone_pcp_update(struct zone *zone) -{ - unsigned cpu; - mutex_lock(&pcp_batch_high_lock); - for_each_possible_cpu(cpu) - pageset_set_high_and_batch(zone, - per_cpu_ptr(zone->pageset, cpu)); - mutex_unlock(&pcp_batch_high_lock); -} -#endif - -void zone_pcp_reset(struct zone *zone) -{ - unsigned long flags; - int cpu; - struct per_cpu_pageset *pset; - - /* avoid races with drain_pages() */ - local_irq_save(flags); - if (zone->pageset != &boot_pageset) { - for_each_online_cpu(cpu) { - pset = per_cpu_ptr(zone->pageset, cpu); - drain_zonestat(zone, pset); - } - free_percpu(zone->pageset); - zone->pageset = &boot_pageset; - } - local_irq_restore(flags); -} - -#ifdef CONFIG_MEMORY_HOTREMOVE -/* - * All pages in the range must be in a single zone and isolated - * before calling this. - */ -void -__offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn) -{ - struct page *page; - struct zone *zone; - unsigned int order, i; - unsigned long pfn; - unsigned long flags; - /* find the first valid pfn */ - for (pfn = start_pfn; pfn < end_pfn; pfn++) - if (pfn_valid(pfn)) - break; - if (pfn == end_pfn) - return; - zone = page_zone(pfn_to_page(pfn)); - spin_lock_irqsave(&zone->lock, flags); - pfn = start_pfn; - while (pfn < end_pfn) { - if (!pfn_valid(pfn)) { - pfn++; - continue; - } - page = pfn_to_page(pfn); - /* - * The HWPoisoned page may be not in buddy system, and - * page_count() is not 0. - */ - if (unlikely(!PageBuddy(page) && PageHWPoison(page))) { - pfn++; - SetPageReserved(page); - continue; - } - - BUG_ON(page_count(page)); - BUG_ON(!PageBuddy(page)); - order = page_order(page); -#ifdef CONFIG_DEBUG_VM - pr_info("remove from free list %lx %d %lx\n", - pfn, 1 << order, end_pfn); -#endif - list_del(&page->lru); - rmv_page_order(page); - zone->free_area[order].nr_free--; - for (i = 0; i < (1 << order); i++) - SetPageReserved((page+i)); - pfn += (1 << order); - } - spin_unlock_irqrestore(&zone->lock, flags); -} -#endif - -bool is_free_buddy_page(struct page *page) -{ - struct zone *zone = page_zone(page); - unsigned long pfn = page_to_pfn(page); - unsigned long flags; - unsigned int order; - - spin_lock_irqsave(&zone->lock, flags); - for (order = 0; order < MAX_ORDER; order++) { - struct page *page_head = page - (pfn & ((1 << order) - 1)); - - if (PageBuddy(page_head) && page_order(page_head) >= order) - break; - } - spin_unlock_irqrestore(&zone->lock, flags); - - return order < MAX_ORDER; -} diff --git a/src/linux/mm/percpu-km.c b/src/linux/mm/percpu-km.c deleted file mode 100644 index d66911f..0000000 --- a/src/linux/mm/percpu-km.c +++ /dev/null @@ -1,110 +0,0 @@ -/* - * mm/percpu-km.c - kernel memory based chunk allocation - * - * Copyright (C) 2010 SUSE Linux Products GmbH - * Copyright (C) 2010 Tejun Heo - * - * This file is released under the GPLv2. - * - * Chunks are allocated as a contiguous kernel memory using gfp - * allocation. This is to be used on nommu architectures. - * - * To use percpu-km, - * - * - define CONFIG_NEED_PER_CPU_KM from the arch Kconfig. - * - * - CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK must not be defined. It's - * not compatible with PER_CPU_KM. EMBED_FIRST_CHUNK should work - * fine. - * - * - NUMA is not supported. When setting up the first chunk, - * @cpu_distance_fn should be NULL or report all CPUs to be nearer - * than or at LOCAL_DISTANCE. - * - * - It's best if the chunk size is power of two multiple of - * PAGE_SIZE. Because each chunk is allocated as a contiguous - * kernel memory block using alloc_pages(), memory will be wasted if - * chunk size is not aligned. percpu-km code will whine about it. - */ - -#if defined(CONFIG_SMP) && defined(CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK) -#error "contiguous percpu allocation is incompatible with paged first chunk" -#endif - -#include - -static int pcpu_populate_chunk(struct pcpu_chunk *chunk, - int page_start, int page_end) -{ - return 0; -} - -static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, - int page_start, int page_end) -{ - /* nada */ -} - -static struct pcpu_chunk *pcpu_create_chunk(void) -{ - const int nr_pages = pcpu_group_sizes[0] >> PAGE_SHIFT; - struct pcpu_chunk *chunk; - struct page *pages; - int i; - - chunk = pcpu_alloc_chunk(); - if (!chunk) - return NULL; - - pages = alloc_pages(GFP_KERNEL, order_base_2(nr_pages)); - if (!pages) { - pcpu_free_chunk(chunk); - return NULL; - } - - for (i = 0; i < nr_pages; i++) - pcpu_set_page_chunk(nth_page(pages, i), chunk); - - chunk->data = pages; - chunk->base_addr = page_address(pages) - pcpu_group_offsets[0]; - - spin_lock_irq(&pcpu_lock); - pcpu_chunk_populated(chunk, 0, nr_pages); - spin_unlock_irq(&pcpu_lock); - - return chunk; -} - -static void pcpu_destroy_chunk(struct pcpu_chunk *chunk) -{ - const int nr_pages = pcpu_group_sizes[0] >> PAGE_SHIFT; - - if (chunk && chunk->data) - __free_pages(chunk->data, order_base_2(nr_pages)); - pcpu_free_chunk(chunk); -} - -static struct page *pcpu_addr_to_page(void *addr) -{ - return virt_to_page(addr); -} - -static int __init pcpu_verify_alloc_info(const struct pcpu_alloc_info *ai) -{ - size_t nr_pages, alloc_pages; - - /* all units must be in a single group */ - if (ai->nr_groups != 1) { - pr_crit("can't handle more than one group\n"); - return -EINVAL; - } - - nr_pages = (ai->groups[0].nr_units * ai->unit_size) >> PAGE_SHIFT; - alloc_pages = roundup_pow_of_two(nr_pages); - - if (alloc_pages > nr_pages) - pr_warn("wasting %zu pages per chunk\n", - alloc_pages - nr_pages); - - return 0; -} diff --git a/src/linux/mm/percpu.c b/src/linux/mm/percpu.c deleted file mode 100644 index 2557143..0000000 --- a/src/linux/mm/percpu.c +++ /dev/null @@ -1,2308 +0,0 @@ -/* - * mm/percpu.c - percpu memory allocator - * - * Copyright (C) 2009 SUSE Linux Products GmbH - * Copyright (C) 2009 Tejun Heo - * - * This file is released under the GPLv2. - * - * This is percpu allocator which can handle both static and dynamic - * areas. Percpu areas are allocated in chunks. Each chunk is - * consisted of boot-time determined number of units and the first - * chunk is used for static percpu variables in the kernel image - * (special boot time alloc/init handling necessary as these areas - * need to be brought up before allocation services are running). - * Unit grows as necessary and all units grow or shrink in unison. - * When a chunk is filled up, another chunk is allocated. - * - * c0 c1 c2 - * ------------------- ------------------- ------------ - * | u0 | u1 | u2 | u3 | | u0 | u1 | u2 | u3 | | u0 | u1 | u - * ------------------- ...... ------------------- .... ------------ - * - * Allocation is done in offset-size areas of single unit space. Ie, - * an area of 512 bytes at 6k in c1 occupies 512 bytes at 6k of c1:u0, - * c1:u1, c1:u2 and c1:u3. On UMA, units corresponds directly to - * cpus. On NUMA, the mapping can be non-linear and even sparse. - * Percpu access can be done by configuring percpu base registers - * according to cpu to unit mapping and pcpu_unit_size. - * - * There are usually many small percpu allocations many of them being - * as small as 4 bytes. The allocator organizes chunks into lists - * according to free size and tries to allocate from the fullest one. - * Each chunk keeps the maximum contiguous area size hint which is - * guaranteed to be equal to or larger than the maximum contiguous - * area in the chunk. This helps the allocator not to iterate the - * chunk maps unnecessarily. - * - * Allocation state in each chunk is kept using an array of integers - * on chunk->map. A positive value in the map represents a free - * region and negative allocated. Allocation inside a chunk is done - * by scanning this map sequentially and serving the first matching - * entry. This is mostly copied from the percpu_modalloc() allocator. - * Chunks can be determined from the address using the index field - * in the page struct. The index field contains a pointer to the chunk. - * - * To use this allocator, arch code should do the followings. - * - * - define __addr_to_pcpu_ptr() and __pcpu_ptr_to_addr() to translate - * regular address to percpu pointer and back if they need to be - * different from the default - * - * - use pcpu_setup_first_chunk() during percpu area initialization to - * setup the first chunk containing the kernel static percpu area - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#define PCPU_SLOT_BASE_SHIFT 5 /* 1-31 shares the same slot */ -#define PCPU_DFL_MAP_ALLOC 16 /* start a map with 16 ents */ -#define PCPU_ATOMIC_MAP_MARGIN_LOW 32 -#define PCPU_ATOMIC_MAP_MARGIN_HIGH 64 -#define PCPU_EMPTY_POP_PAGES_LOW 2 -#define PCPU_EMPTY_POP_PAGES_HIGH 4 - -#ifdef CONFIG_SMP -/* default addr <-> pcpu_ptr mapping, override in asm/percpu.h if necessary */ -#ifndef __addr_to_pcpu_ptr -#define __addr_to_pcpu_ptr(addr) \ - (void __percpu *)((unsigned long)(addr) - \ - (unsigned long)pcpu_base_addr + \ - (unsigned long)__per_cpu_start) -#endif -#ifndef __pcpu_ptr_to_addr -#define __pcpu_ptr_to_addr(ptr) \ - (void __force *)((unsigned long)(ptr) + \ - (unsigned long)pcpu_base_addr - \ - (unsigned long)__per_cpu_start) -#endif -#else /* CONFIG_SMP */ -/* on UP, it's always identity mapped */ -#define __addr_to_pcpu_ptr(addr) (void __percpu *)(addr) -#define __pcpu_ptr_to_addr(ptr) (void __force *)(ptr) -#endif /* CONFIG_SMP */ - -struct pcpu_chunk { - struct list_head list; /* linked to pcpu_slot lists */ - int free_size; /* free bytes in the chunk */ - int contig_hint; /* max contiguous size hint */ - void *base_addr; /* base address of this chunk */ - - int map_used; /* # of map entries used before the sentry */ - int map_alloc; /* # of map entries allocated */ - int *map; /* allocation map */ - struct list_head map_extend_list;/* on pcpu_map_extend_chunks */ - - void *data; /* chunk data */ - int first_free; /* no free below this */ - bool immutable; /* no [de]population allowed */ - int nr_populated; /* # of populated pages */ - unsigned long populated[]; /* populated bitmap */ -}; - -static int pcpu_unit_pages __read_mostly; -static int pcpu_unit_size __read_mostly; -static int pcpu_nr_units __read_mostly; -static int pcpu_atom_size __read_mostly; -static int pcpu_nr_slots __read_mostly; -static size_t pcpu_chunk_struct_size __read_mostly; - -/* cpus with the lowest and highest unit addresses */ -static unsigned int pcpu_low_unit_cpu __read_mostly; -static unsigned int pcpu_high_unit_cpu __read_mostly; - -/* the address of the first chunk which starts with the kernel static area */ -void *pcpu_base_addr __read_mostly; -EXPORT_SYMBOL_GPL(pcpu_base_addr); - -static const int *pcpu_unit_map __read_mostly; /* cpu -> unit */ -const unsigned long *pcpu_unit_offsets __read_mostly; /* cpu -> unit offset */ - -/* group information, used for vm allocation */ -static int pcpu_nr_groups __read_mostly; -static const unsigned long *pcpu_group_offsets __read_mostly; -static const size_t *pcpu_group_sizes __read_mostly; - -/* - * The first chunk which always exists. Note that unlike other - * chunks, this one can be allocated and mapped in several different - * ways and thus often doesn't live in the vmalloc area. - */ -static struct pcpu_chunk *pcpu_first_chunk; - -/* - * Optional reserved chunk. This chunk reserves part of the first - * chunk and serves it for reserved allocations. The amount of - * reserved offset is in pcpu_reserved_chunk_limit. When reserved - * area doesn't exist, the following variables contain NULL and 0 - * respectively. - */ -static struct pcpu_chunk *pcpu_reserved_chunk; -static int pcpu_reserved_chunk_limit; - -static DEFINE_SPINLOCK(pcpu_lock); /* all internal data structures */ -static DEFINE_MUTEX(pcpu_alloc_mutex); /* chunk create/destroy, [de]pop, map ext */ - -static struct list_head *pcpu_slot __read_mostly; /* chunk list slots */ - -/* chunks which need their map areas extended, protected by pcpu_lock */ -static LIST_HEAD(pcpu_map_extend_chunks); - -/* - * The number of empty populated pages, protected by pcpu_lock. The - * reserved chunk doesn't contribute to the count. - */ -static int pcpu_nr_empty_pop_pages; - -/* - * Balance work is used to populate or destroy chunks asynchronously. We - * try to keep the number of populated free pages between - * PCPU_EMPTY_POP_PAGES_LOW and HIGH for atomic allocations and at most one - * empty chunk. - */ -static void pcpu_balance_workfn(struct work_struct *work); -static DECLARE_WORK(pcpu_balance_work, pcpu_balance_workfn); -static bool pcpu_async_enabled __read_mostly; -static bool pcpu_atomic_alloc_failed; - -static void pcpu_schedule_balance_work(void) -{ - if (pcpu_async_enabled) - schedule_work(&pcpu_balance_work); -} - -static bool pcpu_addr_in_first_chunk(void *addr) -{ - void *first_start = pcpu_first_chunk->base_addr; - - return addr >= first_start && addr < first_start + pcpu_unit_size; -} - -static bool pcpu_addr_in_reserved_chunk(void *addr) -{ - void *first_start = pcpu_first_chunk->base_addr; - - return addr >= first_start && - addr < first_start + pcpu_reserved_chunk_limit; -} - -static int __pcpu_size_to_slot(int size) -{ - int highbit = fls(size); /* size is in bytes */ - return max(highbit - PCPU_SLOT_BASE_SHIFT + 2, 1); -} - -static int pcpu_size_to_slot(int size) -{ - if (size == pcpu_unit_size) - return pcpu_nr_slots - 1; - return __pcpu_size_to_slot(size); -} - -static int pcpu_chunk_slot(const struct pcpu_chunk *chunk) -{ - if (chunk->free_size < sizeof(int) || chunk->contig_hint < sizeof(int)) - return 0; - - return pcpu_size_to_slot(chunk->free_size); -} - -/* set the pointer to a chunk in a page struct */ -static void pcpu_set_page_chunk(struct page *page, struct pcpu_chunk *pcpu) -{ - page->index = (unsigned long)pcpu; -} - -/* obtain pointer to a chunk from a page struct */ -static struct pcpu_chunk *pcpu_get_page_chunk(struct page *page) -{ - return (struct pcpu_chunk *)page->index; -} - -static int __maybe_unused pcpu_page_idx(unsigned int cpu, int page_idx) -{ - return pcpu_unit_map[cpu] * pcpu_unit_pages + page_idx; -} - -static unsigned long pcpu_chunk_addr(struct pcpu_chunk *chunk, - unsigned int cpu, int page_idx) -{ - return (unsigned long)chunk->base_addr + pcpu_unit_offsets[cpu] + - (page_idx << PAGE_SHIFT); -} - -static void __maybe_unused pcpu_next_unpop(struct pcpu_chunk *chunk, - int *rs, int *re, int end) -{ - *rs = find_next_zero_bit(chunk->populated, end, *rs); - *re = find_next_bit(chunk->populated, end, *rs + 1); -} - -static void __maybe_unused pcpu_next_pop(struct pcpu_chunk *chunk, - int *rs, int *re, int end) -{ - *rs = find_next_bit(chunk->populated, end, *rs); - *re = find_next_zero_bit(chunk->populated, end, *rs + 1); -} - -/* - * (Un)populated page region iterators. Iterate over (un)populated - * page regions between @start and @end in @chunk. @rs and @re should - * be integer variables and will be set to start and end page index of - * the current region. - */ -#define pcpu_for_each_unpop_region(chunk, rs, re, start, end) \ - for ((rs) = (start), pcpu_next_unpop((chunk), &(rs), &(re), (end)); \ - (rs) < (re); \ - (rs) = (re) + 1, pcpu_next_unpop((chunk), &(rs), &(re), (end))) - -#define pcpu_for_each_pop_region(chunk, rs, re, start, end) \ - for ((rs) = (start), pcpu_next_pop((chunk), &(rs), &(re), (end)); \ - (rs) < (re); \ - (rs) = (re) + 1, pcpu_next_pop((chunk), &(rs), &(re), (end))) - -/** - * pcpu_mem_zalloc - allocate memory - * @size: bytes to allocate - * - * Allocate @size bytes. If @size is smaller than PAGE_SIZE, - * kzalloc() is used; otherwise, vzalloc() is used. The returned - * memory is always zeroed. - * - * CONTEXT: - * Does GFP_KERNEL allocation. - * - * RETURNS: - * Pointer to the allocated area on success, NULL on failure. - */ -static void *pcpu_mem_zalloc(size_t size) -{ - if (WARN_ON_ONCE(!slab_is_available())) - return NULL; - - if (size <= PAGE_SIZE) - return kzalloc(size, GFP_KERNEL); - else - return vzalloc(size); -} - -/** - * pcpu_mem_free - free memory - * @ptr: memory to free - * - * Free @ptr. @ptr should have been allocated using pcpu_mem_zalloc(). - */ -static void pcpu_mem_free(void *ptr) -{ - kvfree(ptr); -} - -/** - * pcpu_count_occupied_pages - count the number of pages an area occupies - * @chunk: chunk of interest - * @i: index of the area in question - * - * Count the number of pages chunk's @i'th area occupies. When the area's - * start and/or end address isn't aligned to page boundary, the straddled - * page is included in the count iff the rest of the page is free. - */ -static int pcpu_count_occupied_pages(struct pcpu_chunk *chunk, int i) -{ - int off = chunk->map[i] & ~1; - int end = chunk->map[i + 1] & ~1; - - if (!PAGE_ALIGNED(off) && i > 0) { - int prev = chunk->map[i - 1]; - - if (!(prev & 1) && prev <= round_down(off, PAGE_SIZE)) - off = round_down(off, PAGE_SIZE); - } - - if (!PAGE_ALIGNED(end) && i + 1 < chunk->map_used) { - int next = chunk->map[i + 1]; - int nend = chunk->map[i + 2] & ~1; - - if (!(next & 1) && nend >= round_up(end, PAGE_SIZE)) - end = round_up(end, PAGE_SIZE); - } - - return max_t(int, PFN_DOWN(end) - PFN_UP(off), 0); -} - -/** - * pcpu_chunk_relocate - put chunk in the appropriate chunk slot - * @chunk: chunk of interest - * @oslot: the previous slot it was on - * - * This function is called after an allocation or free changed @chunk. - * New slot according to the changed state is determined and @chunk is - * moved to the slot. Note that the reserved chunk is never put on - * chunk slots. - * - * CONTEXT: - * pcpu_lock. - */ -static void pcpu_chunk_relocate(struct pcpu_chunk *chunk, int oslot) -{ - int nslot = pcpu_chunk_slot(chunk); - - if (chunk != pcpu_reserved_chunk && oslot != nslot) { - if (oslot < nslot) - list_move(&chunk->list, &pcpu_slot[nslot]); - else - list_move_tail(&chunk->list, &pcpu_slot[nslot]); - } -} - -/** - * pcpu_need_to_extend - determine whether chunk area map needs to be extended - * @chunk: chunk of interest - * @is_atomic: the allocation context - * - * Determine whether area map of @chunk needs to be extended. If - * @is_atomic, only the amount necessary for a new allocation is - * considered; however, async extension is scheduled if the left amount is - * low. If !@is_atomic, it aims for more empty space. Combined, this - * ensures that the map is likely to have enough available space to - * accomodate atomic allocations which can't extend maps directly. - * - * CONTEXT: - * pcpu_lock. - * - * RETURNS: - * New target map allocation length if extension is necessary, 0 - * otherwise. - */ -static int pcpu_need_to_extend(struct pcpu_chunk *chunk, bool is_atomic) -{ - int margin, new_alloc; - - lockdep_assert_held(&pcpu_lock); - - if (is_atomic) { - margin = 3; - - if (chunk->map_alloc < - chunk->map_used + PCPU_ATOMIC_MAP_MARGIN_LOW) { - if (list_empty(&chunk->map_extend_list)) { - list_add_tail(&chunk->map_extend_list, - &pcpu_map_extend_chunks); - pcpu_schedule_balance_work(); - } - } - } else { - margin = PCPU_ATOMIC_MAP_MARGIN_HIGH; - } - - if (chunk->map_alloc >= chunk->map_used + margin) - return 0; - - new_alloc = PCPU_DFL_MAP_ALLOC; - while (new_alloc < chunk->map_used + margin) - new_alloc *= 2; - - return new_alloc; -} - -/** - * pcpu_extend_area_map - extend area map of a chunk - * @chunk: chunk of interest - * @new_alloc: new target allocation length of the area map - * - * Extend area map of @chunk to have @new_alloc entries. - * - * CONTEXT: - * Does GFP_KERNEL allocation. Grabs and releases pcpu_lock. - * - * RETURNS: - * 0 on success, -errno on failure. - */ -static int pcpu_extend_area_map(struct pcpu_chunk *chunk, int new_alloc) -{ - int *old = NULL, *new = NULL; - size_t old_size = 0, new_size = new_alloc * sizeof(new[0]); - unsigned long flags; - - lockdep_assert_held(&pcpu_alloc_mutex); - - new = pcpu_mem_zalloc(new_size); - if (!new) - return -ENOMEM; - - /* acquire pcpu_lock and switch to new area map */ - spin_lock_irqsave(&pcpu_lock, flags); - - if (new_alloc <= chunk->map_alloc) - goto out_unlock; - - old_size = chunk->map_alloc * sizeof(chunk->map[0]); - old = chunk->map; - - memcpy(new, old, old_size); - - chunk->map_alloc = new_alloc; - chunk->map = new; - new = NULL; - -out_unlock: - spin_unlock_irqrestore(&pcpu_lock, flags); - - /* - * pcpu_mem_free() might end up calling vfree() which uses - * IRQ-unsafe lock and thus can't be called under pcpu_lock. - */ - pcpu_mem_free(old); - pcpu_mem_free(new); - - return 0; -} - -/** - * pcpu_fit_in_area - try to fit the requested allocation in a candidate area - * @chunk: chunk the candidate area belongs to - * @off: the offset to the start of the candidate area - * @this_size: the size of the candidate area - * @size: the size of the target allocation - * @align: the alignment of the target allocation - * @pop_only: only allocate from already populated region - * - * We're trying to allocate @size bytes aligned at @align. @chunk's area - * at @off sized @this_size is a candidate. This function determines - * whether the target allocation fits in the candidate area and returns the - * number of bytes to pad after @off. If the target area doesn't fit, -1 - * is returned. - * - * If @pop_only is %true, this function only considers the already - * populated part of the candidate area. - */ -static int pcpu_fit_in_area(struct pcpu_chunk *chunk, int off, int this_size, - int size, int align, bool pop_only) -{ - int cand_off = off; - - while (true) { - int head = ALIGN(cand_off, align) - off; - int page_start, page_end, rs, re; - - if (this_size < head + size) - return -1; - - if (!pop_only) - return head; - - /* - * If the first unpopulated page is beyond the end of the - * allocation, the whole allocation is populated; - * otherwise, retry from the end of the unpopulated area. - */ - page_start = PFN_DOWN(head + off); - page_end = PFN_UP(head + off + size); - - rs = page_start; - pcpu_next_unpop(chunk, &rs, &re, PFN_UP(off + this_size)); - if (rs >= page_end) - return head; - cand_off = re * PAGE_SIZE; - } -} - -/** - * pcpu_alloc_area - allocate area from a pcpu_chunk - * @chunk: chunk of interest - * @size: wanted size in bytes - * @align: wanted align - * @pop_only: allocate only from the populated area - * @occ_pages_p: out param for the number of pages the area occupies - * - * Try to allocate @size bytes area aligned at @align from @chunk. - * Note that this function only allocates the offset. It doesn't - * populate or map the area. - * - * @chunk->map must have at least two free slots. - * - * CONTEXT: - * pcpu_lock. - * - * RETURNS: - * Allocated offset in @chunk on success, -1 if no matching area is - * found. - */ -static int pcpu_alloc_area(struct pcpu_chunk *chunk, int size, int align, - bool pop_only, int *occ_pages_p) -{ - int oslot = pcpu_chunk_slot(chunk); - int max_contig = 0; - int i, off; - bool seen_free = false; - int *p; - - for (i = chunk->first_free, p = chunk->map + i; i < chunk->map_used; i++, p++) { - int head, tail; - int this_size; - - off = *p; - if (off & 1) - continue; - - this_size = (p[1] & ~1) - off; - - head = pcpu_fit_in_area(chunk, off, this_size, size, align, - pop_only); - if (head < 0) { - if (!seen_free) { - chunk->first_free = i; - seen_free = true; - } - max_contig = max(this_size, max_contig); - continue; - } - - /* - * If head is small or the previous block is free, - * merge'em. Note that 'small' is defined as smaller - * than sizeof(int), which is very small but isn't too - * uncommon for percpu allocations. - */ - if (head && (head < sizeof(int) || !(p[-1] & 1))) { - *p = off += head; - if (p[-1] & 1) - chunk->free_size -= head; - else - max_contig = max(*p - p[-1], max_contig); - this_size -= head; - head = 0; - } - - /* if tail is small, just keep it around */ - tail = this_size - head - size; - if (tail < sizeof(int)) { - tail = 0; - size = this_size - head; - } - - /* split if warranted */ - if (head || tail) { - int nr_extra = !!head + !!tail; - - /* insert new subblocks */ - memmove(p + nr_extra + 1, p + 1, - sizeof(chunk->map[0]) * (chunk->map_used - i)); - chunk->map_used += nr_extra; - - if (head) { - if (!seen_free) { - chunk->first_free = i; - seen_free = true; - } - *++p = off += head; - ++i; - max_contig = max(head, max_contig); - } - if (tail) { - p[1] = off + size; - max_contig = max(tail, max_contig); - } - } - - if (!seen_free) - chunk->first_free = i + 1; - - /* update hint and mark allocated */ - if (i + 1 == chunk->map_used) - chunk->contig_hint = max_contig; /* fully scanned */ - else - chunk->contig_hint = max(chunk->contig_hint, - max_contig); - - chunk->free_size -= size; - *p |= 1; - - *occ_pages_p = pcpu_count_occupied_pages(chunk, i); - pcpu_chunk_relocate(chunk, oslot); - return off; - } - - chunk->contig_hint = max_contig; /* fully scanned */ - pcpu_chunk_relocate(chunk, oslot); - - /* tell the upper layer that this chunk has no matching area */ - return -1; -} - -/** - * pcpu_free_area - free area to a pcpu_chunk - * @chunk: chunk of interest - * @freeme: offset of area to free - * @occ_pages_p: out param for the number of pages the area occupies - * - * Free area starting from @freeme to @chunk. Note that this function - * only modifies the allocation map. It doesn't depopulate or unmap - * the area. - * - * CONTEXT: - * pcpu_lock. - */ -static void pcpu_free_area(struct pcpu_chunk *chunk, int freeme, - int *occ_pages_p) -{ - int oslot = pcpu_chunk_slot(chunk); - int off = 0; - unsigned i, j; - int to_free = 0; - int *p; - - freeme |= 1; /* we are searching for pair */ - - i = 0; - j = chunk->map_used; - while (i != j) { - unsigned k = (i + j) / 2; - off = chunk->map[k]; - if (off < freeme) - i = k + 1; - else if (off > freeme) - j = k; - else - i = j = k; - } - BUG_ON(off != freeme); - - if (i < chunk->first_free) - chunk->first_free = i; - - p = chunk->map + i; - *p = off &= ~1; - chunk->free_size += (p[1] & ~1) - off; - - *occ_pages_p = pcpu_count_occupied_pages(chunk, i); - - /* merge with next? */ - if (!(p[1] & 1)) - to_free++; - /* merge with previous? */ - if (i > 0 && !(p[-1] & 1)) { - to_free++; - i--; - p--; - } - if (to_free) { - chunk->map_used -= to_free; - memmove(p + 1, p + 1 + to_free, - (chunk->map_used - i) * sizeof(chunk->map[0])); - } - - chunk->contig_hint = max(chunk->map[i + 1] - chunk->map[i] - 1, chunk->contig_hint); - pcpu_chunk_relocate(chunk, oslot); -} - -static struct pcpu_chunk *pcpu_alloc_chunk(void) -{ - struct pcpu_chunk *chunk; - - chunk = pcpu_mem_zalloc(pcpu_chunk_struct_size); - if (!chunk) - return NULL; - - chunk->map = pcpu_mem_zalloc(PCPU_DFL_MAP_ALLOC * - sizeof(chunk->map[0])); - if (!chunk->map) { - pcpu_mem_free(chunk); - return NULL; - } - - chunk->map_alloc = PCPU_DFL_MAP_ALLOC; - chunk->map[0] = 0; - chunk->map[1] = pcpu_unit_size | 1; - chunk->map_used = 1; - - INIT_LIST_HEAD(&chunk->list); - INIT_LIST_HEAD(&chunk->map_extend_list); - chunk->free_size = pcpu_unit_size; - chunk->contig_hint = pcpu_unit_size; - - return chunk; -} - -static void pcpu_free_chunk(struct pcpu_chunk *chunk) -{ - if (!chunk) - return; - pcpu_mem_free(chunk->map); - pcpu_mem_free(chunk); -} - -/** - * pcpu_chunk_populated - post-population bookkeeping - * @chunk: pcpu_chunk which got populated - * @page_start: the start page - * @page_end: the end page - * - * Pages in [@page_start,@page_end) have been populated to @chunk. Update - * the bookkeeping information accordingly. Must be called after each - * successful population. - */ -static void pcpu_chunk_populated(struct pcpu_chunk *chunk, - int page_start, int page_end) -{ - int nr = page_end - page_start; - - lockdep_assert_held(&pcpu_lock); - - bitmap_set(chunk->populated, page_start, nr); - chunk->nr_populated += nr; - pcpu_nr_empty_pop_pages += nr; -} - -/** - * pcpu_chunk_depopulated - post-depopulation bookkeeping - * @chunk: pcpu_chunk which got depopulated - * @page_start: the start page - * @page_end: the end page - * - * Pages in [@page_start,@page_end) have been depopulated from @chunk. - * Update the bookkeeping information accordingly. Must be called after - * each successful depopulation. - */ -static void pcpu_chunk_depopulated(struct pcpu_chunk *chunk, - int page_start, int page_end) -{ - int nr = page_end - page_start; - - lockdep_assert_held(&pcpu_lock); - - bitmap_clear(chunk->populated, page_start, nr); - chunk->nr_populated -= nr; - pcpu_nr_empty_pop_pages -= nr; -} - -/* - * Chunk management implementation. - * - * To allow different implementations, chunk alloc/free and - * [de]population are implemented in a separate file which is pulled - * into this file and compiled together. The following functions - * should be implemented. - * - * pcpu_populate_chunk - populate the specified range of a chunk - * pcpu_depopulate_chunk - depopulate the specified range of a chunk - * pcpu_create_chunk - create a new chunk - * pcpu_destroy_chunk - destroy a chunk, always preceded by full depop - * pcpu_addr_to_page - translate address to physical address - * pcpu_verify_alloc_info - check alloc_info is acceptable during init - */ -static int pcpu_populate_chunk(struct pcpu_chunk *chunk, int off, int size); -static void pcpu_depopulate_chunk(struct pcpu_chunk *chunk, int off, int size); -static struct pcpu_chunk *pcpu_create_chunk(void); -static void pcpu_destroy_chunk(struct pcpu_chunk *chunk); -static struct page *pcpu_addr_to_page(void *addr); -static int __init pcpu_verify_alloc_info(const struct pcpu_alloc_info *ai); - -#ifdef CONFIG_NEED_PER_CPU_KM -#include "percpu-km.c" -#else -#include "percpu-vm.c" -#endif - -/** - * pcpu_chunk_addr_search - determine chunk containing specified address - * @addr: address for which the chunk needs to be determined. - * - * RETURNS: - * The address of the found chunk. - */ -static struct pcpu_chunk *pcpu_chunk_addr_search(void *addr) -{ - /* is it in the first chunk? */ - if (pcpu_addr_in_first_chunk(addr)) { - /* is it in the reserved area? */ - if (pcpu_addr_in_reserved_chunk(addr)) - return pcpu_reserved_chunk; - return pcpu_first_chunk; - } - - /* - * The address is relative to unit0 which might be unused and - * thus unmapped. Offset the address to the unit space of the - * current processor before looking it up in the vmalloc - * space. Note that any possible cpu id can be used here, so - * there's no need to worry about preemption or cpu hotplug. - */ - addr += pcpu_unit_offsets[raw_smp_processor_id()]; - return pcpu_get_page_chunk(pcpu_addr_to_page(addr)); -} - -/** - * pcpu_alloc - the percpu allocator - * @size: size of area to allocate in bytes - * @align: alignment of area (max PAGE_SIZE) - * @reserved: allocate from the reserved chunk if available - * @gfp: allocation flags - * - * Allocate percpu area of @size bytes aligned at @align. If @gfp doesn't - * contain %GFP_KERNEL, the allocation is atomic. - * - * RETURNS: - * Percpu pointer to the allocated area on success, NULL on failure. - */ -static void __percpu *pcpu_alloc(size_t size, size_t align, bool reserved, - gfp_t gfp) -{ - static int warn_limit = 10; - struct pcpu_chunk *chunk; - const char *err; - bool is_atomic = (gfp & GFP_KERNEL) != GFP_KERNEL; - int occ_pages = 0; - int slot, off, new_alloc, cpu, ret; - unsigned long flags; - void __percpu *ptr; - - /* - * We want the lowest bit of offset available for in-use/free - * indicator, so force >= 16bit alignment and make size even. - */ - if (unlikely(align < 2)) - align = 2; - - size = ALIGN(size, 2); - - if (unlikely(!size || size > PCPU_MIN_UNIT_SIZE || align > PAGE_SIZE)) { - WARN(true, "illegal size (%zu) or align (%zu) for percpu allocation\n", - size, align); - return NULL; - } - - if (!is_atomic) - mutex_lock(&pcpu_alloc_mutex); - - spin_lock_irqsave(&pcpu_lock, flags); - - /* serve reserved allocations from the reserved chunk if available */ - if (reserved && pcpu_reserved_chunk) { - chunk = pcpu_reserved_chunk; - - if (size > chunk->contig_hint) { - err = "alloc from reserved chunk failed"; - goto fail_unlock; - } - - while ((new_alloc = pcpu_need_to_extend(chunk, is_atomic))) { - spin_unlock_irqrestore(&pcpu_lock, flags); - if (is_atomic || - pcpu_extend_area_map(chunk, new_alloc) < 0) { - err = "failed to extend area map of reserved chunk"; - goto fail; - } - spin_lock_irqsave(&pcpu_lock, flags); - } - - off = pcpu_alloc_area(chunk, size, align, is_atomic, - &occ_pages); - if (off >= 0) - goto area_found; - - err = "alloc from reserved chunk failed"; - goto fail_unlock; - } - -restart: - /* search through normal chunks */ - for (slot = pcpu_size_to_slot(size); slot < pcpu_nr_slots; slot++) { - list_for_each_entry(chunk, &pcpu_slot[slot], list) { - if (size > chunk->contig_hint) - continue; - - new_alloc = pcpu_need_to_extend(chunk, is_atomic); - if (new_alloc) { - if (is_atomic) - continue; - spin_unlock_irqrestore(&pcpu_lock, flags); - if (pcpu_extend_area_map(chunk, - new_alloc) < 0) { - err = "failed to extend area map"; - goto fail; - } - spin_lock_irqsave(&pcpu_lock, flags); - /* - * pcpu_lock has been dropped, need to - * restart cpu_slot list walking. - */ - goto restart; - } - - off = pcpu_alloc_area(chunk, size, align, is_atomic, - &occ_pages); - if (off >= 0) - goto area_found; - } - } - - spin_unlock_irqrestore(&pcpu_lock, flags); - - /* - * No space left. Create a new chunk. We don't want multiple - * tasks to create chunks simultaneously. Serialize and create iff - * there's still no empty chunk after grabbing the mutex. - */ - if (is_atomic) - goto fail; - - if (list_empty(&pcpu_slot[pcpu_nr_slots - 1])) { - chunk = pcpu_create_chunk(); - if (!chunk) { - err = "failed to allocate new chunk"; - goto fail; - } - - spin_lock_irqsave(&pcpu_lock, flags); - pcpu_chunk_relocate(chunk, -1); - } else { - spin_lock_irqsave(&pcpu_lock, flags); - } - - goto restart; - -area_found: - spin_unlock_irqrestore(&pcpu_lock, flags); - - /* populate if not all pages are already there */ - if (!is_atomic) { - int page_start, page_end, rs, re; - - page_start = PFN_DOWN(off); - page_end = PFN_UP(off + size); - - pcpu_for_each_unpop_region(chunk, rs, re, page_start, page_end) { - WARN_ON(chunk->immutable); - - ret = pcpu_populate_chunk(chunk, rs, re); - - spin_lock_irqsave(&pcpu_lock, flags); - if (ret) { - pcpu_free_area(chunk, off, &occ_pages); - err = "failed to populate"; - goto fail_unlock; - } - pcpu_chunk_populated(chunk, rs, re); - spin_unlock_irqrestore(&pcpu_lock, flags); - } - - mutex_unlock(&pcpu_alloc_mutex); - } - - if (chunk != pcpu_reserved_chunk) - pcpu_nr_empty_pop_pages -= occ_pages; - - if (pcpu_nr_empty_pop_pages < PCPU_EMPTY_POP_PAGES_LOW) - pcpu_schedule_balance_work(); - - /* clear the areas and return address relative to base address */ - for_each_possible_cpu(cpu) - memset((void *)pcpu_chunk_addr(chunk, cpu, 0) + off, 0, size); - - ptr = __addr_to_pcpu_ptr(chunk->base_addr + off); - kmemleak_alloc_percpu(ptr, size, gfp); - return ptr; - -fail_unlock: - spin_unlock_irqrestore(&pcpu_lock, flags); -fail: - if (!is_atomic && warn_limit) { - pr_warn("allocation failed, size=%zu align=%zu atomic=%d, %s\n", - size, align, is_atomic, err); - dump_stack(); - if (!--warn_limit) - pr_info("limit reached, disable warning\n"); - } - if (is_atomic) { - /* see the flag handling in pcpu_blance_workfn() */ - pcpu_atomic_alloc_failed = true; - pcpu_schedule_balance_work(); - } else { - mutex_unlock(&pcpu_alloc_mutex); - } - return NULL; -} - -/** - * __alloc_percpu_gfp - allocate dynamic percpu area - * @size: size of area to allocate in bytes - * @align: alignment of area (max PAGE_SIZE) - * @gfp: allocation flags - * - * Allocate zero-filled percpu area of @size bytes aligned at @align. If - * @gfp doesn't contain %GFP_KERNEL, the allocation doesn't block and can - * be called from any context but is a lot more likely to fail. - * - * RETURNS: - * Percpu pointer to the allocated area on success, NULL on failure. - */ -void __percpu *__alloc_percpu_gfp(size_t size, size_t align, gfp_t gfp) -{ - return pcpu_alloc(size, align, false, gfp); -} -EXPORT_SYMBOL_GPL(__alloc_percpu_gfp); - -/** - * __alloc_percpu - allocate dynamic percpu area - * @size: size of area to allocate in bytes - * @align: alignment of area (max PAGE_SIZE) - * - * Equivalent to __alloc_percpu_gfp(size, align, %GFP_KERNEL). - */ -void __percpu *__alloc_percpu(size_t size, size_t align) -{ - return pcpu_alloc(size, align, false, GFP_KERNEL); -} -EXPORT_SYMBOL_GPL(__alloc_percpu); - -/** - * __alloc_reserved_percpu - allocate reserved percpu area - * @size: size of area to allocate in bytes - * @align: alignment of area (max PAGE_SIZE) - * - * Allocate zero-filled percpu area of @size bytes aligned at @align - * from reserved percpu area if arch has set it up; otherwise, - * allocation is served from the same dynamic area. Might sleep. - * Might trigger writeouts. - * - * CONTEXT: - * Does GFP_KERNEL allocation. - * - * RETURNS: - * Percpu pointer to the allocated area on success, NULL on failure. - */ -void __percpu *__alloc_reserved_percpu(size_t size, size_t align) -{ - return pcpu_alloc(size, align, true, GFP_KERNEL); -} - -/** - * pcpu_balance_workfn - manage the amount of free chunks and populated pages - * @work: unused - * - * Reclaim all fully free chunks except for the first one. - */ -static void pcpu_balance_workfn(struct work_struct *work) -{ - LIST_HEAD(to_free); - struct list_head *free_head = &pcpu_slot[pcpu_nr_slots - 1]; - struct pcpu_chunk *chunk, *next; - int slot, nr_to_pop, ret; - - /* - * There's no reason to keep around multiple unused chunks and VM - * areas can be scarce. Destroy all free chunks except for one. - */ - mutex_lock(&pcpu_alloc_mutex); - spin_lock_irq(&pcpu_lock); - - list_for_each_entry_safe(chunk, next, free_head, list) { - WARN_ON(chunk->immutable); - - /* spare the first one */ - if (chunk == list_first_entry(free_head, struct pcpu_chunk, list)) - continue; - - list_del_init(&chunk->map_extend_list); - list_move(&chunk->list, &to_free); - } - - spin_unlock_irq(&pcpu_lock); - - list_for_each_entry_safe(chunk, next, &to_free, list) { - int rs, re; - - pcpu_for_each_pop_region(chunk, rs, re, 0, pcpu_unit_pages) { - pcpu_depopulate_chunk(chunk, rs, re); - spin_lock_irq(&pcpu_lock); - pcpu_chunk_depopulated(chunk, rs, re); - spin_unlock_irq(&pcpu_lock); - } - pcpu_destroy_chunk(chunk); - } - - /* service chunks which requested async area map extension */ - do { - int new_alloc = 0; - - spin_lock_irq(&pcpu_lock); - - chunk = list_first_entry_or_null(&pcpu_map_extend_chunks, - struct pcpu_chunk, map_extend_list); - if (chunk) { - list_del_init(&chunk->map_extend_list); - new_alloc = pcpu_need_to_extend(chunk, false); - } - - spin_unlock_irq(&pcpu_lock); - - if (new_alloc) - pcpu_extend_area_map(chunk, new_alloc); - } while (chunk); - - /* - * Ensure there are certain number of free populated pages for - * atomic allocs. Fill up from the most packed so that atomic - * allocs don't increase fragmentation. If atomic allocation - * failed previously, always populate the maximum amount. This - * should prevent atomic allocs larger than PAGE_SIZE from keeping - * failing indefinitely; however, large atomic allocs are not - * something we support properly and can be highly unreliable and - * inefficient. - */ -retry_pop: - if (pcpu_atomic_alloc_failed) { - nr_to_pop = PCPU_EMPTY_POP_PAGES_HIGH; - /* best effort anyway, don't worry about synchronization */ - pcpu_atomic_alloc_failed = false; - } else { - nr_to_pop = clamp(PCPU_EMPTY_POP_PAGES_HIGH - - pcpu_nr_empty_pop_pages, - 0, PCPU_EMPTY_POP_PAGES_HIGH); - } - - for (slot = pcpu_size_to_slot(PAGE_SIZE); slot < pcpu_nr_slots; slot++) { - int nr_unpop = 0, rs, re; - - if (!nr_to_pop) - break; - - spin_lock_irq(&pcpu_lock); - list_for_each_entry(chunk, &pcpu_slot[slot], list) { - nr_unpop = pcpu_unit_pages - chunk->nr_populated; - if (nr_unpop) - break; - } - spin_unlock_irq(&pcpu_lock); - - if (!nr_unpop) - continue; - - /* @chunk can't go away while pcpu_alloc_mutex is held */ - pcpu_for_each_unpop_region(chunk, rs, re, 0, pcpu_unit_pages) { - int nr = min(re - rs, nr_to_pop); - - ret = pcpu_populate_chunk(chunk, rs, rs + nr); - if (!ret) { - nr_to_pop -= nr; - spin_lock_irq(&pcpu_lock); - pcpu_chunk_populated(chunk, rs, rs + nr); - spin_unlock_irq(&pcpu_lock); - } else { - nr_to_pop = 0; - } - - if (!nr_to_pop) - break; - } - } - - if (nr_to_pop) { - /* ran out of chunks to populate, create a new one and retry */ - chunk = pcpu_create_chunk(); - if (chunk) { - spin_lock_irq(&pcpu_lock); - pcpu_chunk_relocate(chunk, -1); - spin_unlock_irq(&pcpu_lock); - goto retry_pop; - } - } - - mutex_unlock(&pcpu_alloc_mutex); -} - -/** - * free_percpu - free percpu area - * @ptr: pointer to area to free - * - * Free percpu area @ptr. - * - * CONTEXT: - * Can be called from atomic context. - */ -void free_percpu(void __percpu *ptr) -{ - void *addr; - struct pcpu_chunk *chunk; - unsigned long flags; - int off, occ_pages; - - if (!ptr) - return; - - kmemleak_free_percpu(ptr); - - addr = __pcpu_ptr_to_addr(ptr); - - spin_lock_irqsave(&pcpu_lock, flags); - - chunk = pcpu_chunk_addr_search(addr); - off = addr - chunk->base_addr; - - pcpu_free_area(chunk, off, &occ_pages); - - if (chunk != pcpu_reserved_chunk) - pcpu_nr_empty_pop_pages += occ_pages; - - /* if there are more than one fully free chunks, wake up grim reaper */ - if (chunk->free_size == pcpu_unit_size) { - struct pcpu_chunk *pos; - - list_for_each_entry(pos, &pcpu_slot[pcpu_nr_slots - 1], list) - if (pos != chunk) { - pcpu_schedule_balance_work(); - break; - } - } - - spin_unlock_irqrestore(&pcpu_lock, flags); -} -EXPORT_SYMBOL_GPL(free_percpu); - -/** - * is_kernel_percpu_address - test whether address is from static percpu area - * @addr: address to test - * - * Test whether @addr belongs to in-kernel static percpu area. Module - * static percpu areas are not considered. For those, use - * is_module_percpu_address(). - * - * RETURNS: - * %true if @addr is from in-kernel static percpu area, %false otherwise. - */ -bool is_kernel_percpu_address(unsigned long addr) -{ -#ifdef CONFIG_SMP - const size_t static_size = __per_cpu_end - __per_cpu_start; - void __percpu *base = __addr_to_pcpu_ptr(pcpu_base_addr); - unsigned int cpu; - - for_each_possible_cpu(cpu) { - void *start = per_cpu_ptr(base, cpu); - - if ((void *)addr >= start && (void *)addr < start + static_size) - return true; - } -#endif - /* on UP, can't distinguish from other static vars, always false */ - return false; -} - -/** - * per_cpu_ptr_to_phys - convert translated percpu address to physical address - * @addr: the address to be converted to physical address - * - * Given @addr which is dereferenceable address obtained via one of - * percpu access macros, this function translates it into its physical - * address. The caller is responsible for ensuring @addr stays valid - * until this function finishes. - * - * percpu allocator has special setup for the first chunk, which currently - * supports either embedding in linear address space or vmalloc mapping, - * and, from the second one, the backing allocator (currently either vm or - * km) provides translation. - * - * The addr can be translated simply without checking if it falls into the - * first chunk. But the current code reflects better how percpu allocator - * actually works, and the verification can discover both bugs in percpu - * allocator itself and per_cpu_ptr_to_phys() callers. So we keep current - * code. - * - * RETURNS: - * The physical address for @addr. - */ -phys_addr_t per_cpu_ptr_to_phys(void *addr) -{ - void __percpu *base = __addr_to_pcpu_ptr(pcpu_base_addr); - bool in_first_chunk = false; - unsigned long first_low, first_high; - unsigned int cpu; - - /* - * The following test on unit_low/high isn't strictly - * necessary but will speed up lookups of addresses which - * aren't in the first chunk. - */ - first_low = pcpu_chunk_addr(pcpu_first_chunk, pcpu_low_unit_cpu, 0); - first_high = pcpu_chunk_addr(pcpu_first_chunk, pcpu_high_unit_cpu, - pcpu_unit_pages); - if ((unsigned long)addr >= first_low && - (unsigned long)addr < first_high) { - for_each_possible_cpu(cpu) { - void *start = per_cpu_ptr(base, cpu); - - if (addr >= start && addr < start + pcpu_unit_size) { - in_first_chunk = true; - break; - } - } - } - - if (in_first_chunk) { - if (!is_vmalloc_addr(addr)) - return __pa(addr); - else - return page_to_phys(vmalloc_to_page(addr)) + - offset_in_page(addr); - } else - return page_to_phys(pcpu_addr_to_page(addr)) + - offset_in_page(addr); -} - -/** - * pcpu_alloc_alloc_info - allocate percpu allocation info - * @nr_groups: the number of groups - * @nr_units: the number of units - * - * Allocate ai which is large enough for @nr_groups groups containing - * @nr_units units. The returned ai's groups[0].cpu_map points to the - * cpu_map array which is long enough for @nr_units and filled with - * NR_CPUS. It's the caller's responsibility to initialize cpu_map - * pointer of other groups. - * - * RETURNS: - * Pointer to the allocated pcpu_alloc_info on success, NULL on - * failure. - */ -struct pcpu_alloc_info * __init pcpu_alloc_alloc_info(int nr_groups, - int nr_units) -{ - struct pcpu_alloc_info *ai; - size_t base_size, ai_size; - void *ptr; - int unit; - - base_size = ALIGN(sizeof(*ai) + nr_groups * sizeof(ai->groups[0]), - __alignof__(ai->groups[0].cpu_map[0])); - ai_size = base_size + nr_units * sizeof(ai->groups[0].cpu_map[0]); - - ptr = memblock_virt_alloc_nopanic(PFN_ALIGN(ai_size), 0); - if (!ptr) - return NULL; - ai = ptr; - ptr += base_size; - - ai->groups[0].cpu_map = ptr; - - for (unit = 0; unit < nr_units; unit++) - ai->groups[0].cpu_map[unit] = NR_CPUS; - - ai->nr_groups = nr_groups; - ai->__ai_size = PFN_ALIGN(ai_size); - - return ai; -} - -/** - * pcpu_free_alloc_info - free percpu allocation info - * @ai: pcpu_alloc_info to free - * - * Free @ai which was allocated by pcpu_alloc_alloc_info(). - */ -void __init pcpu_free_alloc_info(struct pcpu_alloc_info *ai) -{ - memblock_free_early(__pa(ai), ai->__ai_size); -} - -/** - * pcpu_dump_alloc_info - print out information about pcpu_alloc_info - * @lvl: loglevel - * @ai: allocation info to dump - * - * Print out information about @ai using loglevel @lvl. - */ -static void pcpu_dump_alloc_info(const char *lvl, - const struct pcpu_alloc_info *ai) -{ - int group_width = 1, cpu_width = 1, width; - char empty_str[] = "--------"; - int alloc = 0, alloc_end = 0; - int group, v; - int upa, apl; /* units per alloc, allocs per line */ - - v = ai->nr_groups; - while (v /= 10) - group_width++; - - v = num_possible_cpus(); - while (v /= 10) - cpu_width++; - empty_str[min_t(int, cpu_width, sizeof(empty_str) - 1)] = '\0'; - - upa = ai->alloc_size / ai->unit_size; - width = upa * (cpu_width + 1) + group_width + 3; - apl = rounddown_pow_of_two(max(60 / width, 1)); - - printk("%spcpu-alloc: s%zu r%zu d%zu u%zu alloc=%zu*%zu", - lvl, ai->static_size, ai->reserved_size, ai->dyn_size, - ai->unit_size, ai->alloc_size / ai->atom_size, ai->atom_size); - - for (group = 0; group < ai->nr_groups; group++) { - const struct pcpu_group_info *gi = &ai->groups[group]; - int unit = 0, unit_end = 0; - - BUG_ON(gi->nr_units % upa); - for (alloc_end += gi->nr_units / upa; - alloc < alloc_end; alloc++) { - if (!(alloc % apl)) { - pr_cont("\n"); - printk("%spcpu-alloc: ", lvl); - } - pr_cont("[%0*d] ", group_width, group); - - for (unit_end += upa; unit < unit_end; unit++) - if (gi->cpu_map[unit] != NR_CPUS) - pr_cont("%0*d ", - cpu_width, gi->cpu_map[unit]); - else - pr_cont("%s ", empty_str); - } - } - pr_cont("\n"); -} - -/** - * pcpu_setup_first_chunk - initialize the first percpu chunk - * @ai: pcpu_alloc_info describing how to percpu area is shaped - * @base_addr: mapped address - * - * Initialize the first percpu chunk which contains the kernel static - * perpcu area. This function is to be called from arch percpu area - * setup path. - * - * @ai contains all information necessary to initialize the first - * chunk and prime the dynamic percpu allocator. - * - * @ai->static_size is the size of static percpu area. - * - * @ai->reserved_size, if non-zero, specifies the amount of bytes to - * reserve after the static area in the first chunk. This reserves - * the first chunk such that it's available only through reserved - * percpu allocation. This is primarily used to serve module percpu - * static areas on architectures where the addressing model has - * limited offset range for symbol relocations to guarantee module - * percpu symbols fall inside the relocatable range. - * - * @ai->dyn_size determines the number of bytes available for dynamic - * allocation in the first chunk. The area between @ai->static_size + - * @ai->reserved_size + @ai->dyn_size and @ai->unit_size is unused. - * - * @ai->unit_size specifies unit size and must be aligned to PAGE_SIZE - * and equal to or larger than @ai->static_size + @ai->reserved_size + - * @ai->dyn_size. - * - * @ai->atom_size is the allocation atom size and used as alignment - * for vm areas. - * - * @ai->alloc_size is the allocation size and always multiple of - * @ai->atom_size. This is larger than @ai->atom_size if - * @ai->unit_size is larger than @ai->atom_size. - * - * @ai->nr_groups and @ai->groups describe virtual memory layout of - * percpu areas. Units which should be colocated are put into the - * same group. Dynamic VM areas will be allocated according to these - * groupings. If @ai->nr_groups is zero, a single group containing - * all units is assumed. - * - * The caller should have mapped the first chunk at @base_addr and - * copied static data to each unit. - * - * If the first chunk ends up with both reserved and dynamic areas, it - * is served by two chunks - one to serve the core static and reserved - * areas and the other for the dynamic area. They share the same vm - * and page map but uses different area allocation map to stay away - * from each other. The latter chunk is circulated in the chunk slots - * and available for dynamic allocation like any other chunks. - * - * RETURNS: - * 0 on success, -errno on failure. - */ -int __init pcpu_setup_first_chunk(const struct pcpu_alloc_info *ai, - void *base_addr) -{ - static int smap[PERCPU_DYNAMIC_EARLY_SLOTS] __initdata; - static int dmap[PERCPU_DYNAMIC_EARLY_SLOTS] __initdata; - size_t dyn_size = ai->dyn_size; - size_t size_sum = ai->static_size + ai->reserved_size + dyn_size; - struct pcpu_chunk *schunk, *dchunk = NULL; - unsigned long *group_offsets; - size_t *group_sizes; - unsigned long *unit_off; - unsigned int cpu; - int *unit_map; - int group, unit, i; - -#define PCPU_SETUP_BUG_ON(cond) do { \ - if (unlikely(cond)) { \ - pr_emerg("failed to initialize, %s\n", #cond); \ - pr_emerg("cpu_possible_mask=%*pb\n", \ - cpumask_pr_args(cpu_possible_mask)); \ - pcpu_dump_alloc_info(KERN_EMERG, ai); \ - BUG(); \ - } \ -} while (0) - - /* sanity checks */ - PCPU_SETUP_BUG_ON(ai->nr_groups <= 0); -#ifdef CONFIG_SMP - PCPU_SETUP_BUG_ON(!ai->static_size); - PCPU_SETUP_BUG_ON(offset_in_page(__per_cpu_start)); -#endif - PCPU_SETUP_BUG_ON(!base_addr); - PCPU_SETUP_BUG_ON(offset_in_page(base_addr)); - PCPU_SETUP_BUG_ON(ai->unit_size < size_sum); - PCPU_SETUP_BUG_ON(offset_in_page(ai->unit_size)); - PCPU_SETUP_BUG_ON(ai->unit_size < PCPU_MIN_UNIT_SIZE); - PCPU_SETUP_BUG_ON(ai->dyn_size < PERCPU_DYNAMIC_EARLY_SIZE); - PCPU_SETUP_BUG_ON(pcpu_verify_alloc_info(ai) < 0); - - /* process group information and build config tables accordingly */ - group_offsets = memblock_virt_alloc(ai->nr_groups * - sizeof(group_offsets[0]), 0); - group_sizes = memblock_virt_alloc(ai->nr_groups * - sizeof(group_sizes[0]), 0); - unit_map = memblock_virt_alloc(nr_cpu_ids * sizeof(unit_map[0]), 0); - unit_off = memblock_virt_alloc(nr_cpu_ids * sizeof(unit_off[0]), 0); - - for (cpu = 0; cpu < nr_cpu_ids; cpu++) - unit_map[cpu] = UINT_MAX; - - pcpu_low_unit_cpu = NR_CPUS; - pcpu_high_unit_cpu = NR_CPUS; - - for (group = 0, unit = 0; group < ai->nr_groups; group++, unit += i) { - const struct pcpu_group_info *gi = &ai->groups[group]; - - group_offsets[group] = gi->base_offset; - group_sizes[group] = gi->nr_units * ai->unit_size; - - for (i = 0; i < gi->nr_units; i++) { - cpu = gi->cpu_map[i]; - if (cpu == NR_CPUS) - continue; - - PCPU_SETUP_BUG_ON(cpu >= nr_cpu_ids); - PCPU_SETUP_BUG_ON(!cpu_possible(cpu)); - PCPU_SETUP_BUG_ON(unit_map[cpu] != UINT_MAX); - - unit_map[cpu] = unit + i; - unit_off[cpu] = gi->base_offset + i * ai->unit_size; - - /* determine low/high unit_cpu */ - if (pcpu_low_unit_cpu == NR_CPUS || - unit_off[cpu] < unit_off[pcpu_low_unit_cpu]) - pcpu_low_unit_cpu = cpu; - if (pcpu_high_unit_cpu == NR_CPUS || - unit_off[cpu] > unit_off[pcpu_high_unit_cpu]) - pcpu_high_unit_cpu = cpu; - } - } - pcpu_nr_units = unit; - - for_each_possible_cpu(cpu) - PCPU_SETUP_BUG_ON(unit_map[cpu] == UINT_MAX); - - /* we're done parsing the input, undefine BUG macro and dump config */ -#undef PCPU_SETUP_BUG_ON - pcpu_dump_alloc_info(KERN_DEBUG, ai); - - pcpu_nr_groups = ai->nr_groups; - pcpu_group_offsets = group_offsets; - pcpu_group_sizes = group_sizes; - pcpu_unit_map = unit_map; - pcpu_unit_offsets = unit_off; - - /* determine basic parameters */ - pcpu_unit_pages = ai->unit_size >> PAGE_SHIFT; - pcpu_unit_size = pcpu_unit_pages << PAGE_SHIFT; - pcpu_atom_size = ai->atom_size; - pcpu_chunk_struct_size = sizeof(struct pcpu_chunk) + - BITS_TO_LONGS(pcpu_unit_pages) * sizeof(unsigned long); - - /* - * Allocate chunk slots. The additional last slot is for - * empty chunks. - */ - pcpu_nr_slots = __pcpu_size_to_slot(pcpu_unit_size) + 2; - pcpu_slot = memblock_virt_alloc( - pcpu_nr_slots * sizeof(pcpu_slot[0]), 0); - for (i = 0; i < pcpu_nr_slots; i++) - INIT_LIST_HEAD(&pcpu_slot[i]); - - /* - * Initialize static chunk. If reserved_size is zero, the - * static chunk covers static area + dynamic allocation area - * in the first chunk. If reserved_size is not zero, it - * covers static area + reserved area (mostly used for module - * static percpu allocation). - */ - schunk = memblock_virt_alloc(pcpu_chunk_struct_size, 0); - INIT_LIST_HEAD(&schunk->list); - INIT_LIST_HEAD(&schunk->map_extend_list); - schunk->base_addr = base_addr; - schunk->map = smap; - schunk->map_alloc = ARRAY_SIZE(smap); - schunk->immutable = true; - bitmap_fill(schunk->populated, pcpu_unit_pages); - schunk->nr_populated = pcpu_unit_pages; - - if (ai->reserved_size) { - schunk->free_size = ai->reserved_size; - pcpu_reserved_chunk = schunk; - pcpu_reserved_chunk_limit = ai->static_size + ai->reserved_size; - } else { - schunk->free_size = dyn_size; - dyn_size = 0; /* dynamic area covered */ - } - schunk->contig_hint = schunk->free_size; - - schunk->map[0] = 1; - schunk->map[1] = ai->static_size; - schunk->map_used = 1; - if (schunk->free_size) - schunk->map[++schunk->map_used] = ai->static_size + schunk->free_size; - schunk->map[schunk->map_used] |= 1; - - /* init dynamic chunk if necessary */ - if (dyn_size) { - dchunk = memblock_virt_alloc(pcpu_chunk_struct_size, 0); - INIT_LIST_HEAD(&dchunk->list); - INIT_LIST_HEAD(&dchunk->map_extend_list); - dchunk->base_addr = base_addr; - dchunk->map = dmap; - dchunk->map_alloc = ARRAY_SIZE(dmap); - dchunk->immutable = true; - bitmap_fill(dchunk->populated, pcpu_unit_pages); - dchunk->nr_populated = pcpu_unit_pages; - - dchunk->contig_hint = dchunk->free_size = dyn_size; - dchunk->map[0] = 1; - dchunk->map[1] = pcpu_reserved_chunk_limit; - dchunk->map[2] = (pcpu_reserved_chunk_limit + dchunk->free_size) | 1; - dchunk->map_used = 2; - } - - /* link the first chunk in */ - pcpu_first_chunk = dchunk ?: schunk; - pcpu_nr_empty_pop_pages += - pcpu_count_occupied_pages(pcpu_first_chunk, 1); - pcpu_chunk_relocate(pcpu_first_chunk, -1); - - /* we're done */ - pcpu_base_addr = base_addr; - return 0; -} - -#ifdef CONFIG_SMP - -const char * const pcpu_fc_names[PCPU_FC_NR] __initconst = { - [PCPU_FC_AUTO] = "auto", - [PCPU_FC_EMBED] = "embed", - [PCPU_FC_PAGE] = "page", -}; - -enum pcpu_fc pcpu_chosen_fc __initdata = PCPU_FC_AUTO; - -static int __init percpu_alloc_setup(char *str) -{ - if (!str) - return -EINVAL; - - if (0) - /* nada */; -#ifdef CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK - else if (!strcmp(str, "embed")) - pcpu_chosen_fc = PCPU_FC_EMBED; -#endif -#ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK - else if (!strcmp(str, "page")) - pcpu_chosen_fc = PCPU_FC_PAGE; -#endif - else - pr_warn("unknown allocator %s specified\n", str); - - return 0; -} -early_param("percpu_alloc", percpu_alloc_setup); - -/* - * pcpu_embed_first_chunk() is used by the generic percpu setup. - * Build it if needed by the arch config or the generic setup is going - * to be used. - */ -#if defined(CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK) || \ - !defined(CONFIG_HAVE_SETUP_PER_CPU_AREA) -#define BUILD_EMBED_FIRST_CHUNK -#endif - -/* build pcpu_page_first_chunk() iff needed by the arch config */ -#if defined(CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK) -#define BUILD_PAGE_FIRST_CHUNK -#endif - -/* pcpu_build_alloc_info() is used by both embed and page first chunk */ -#if defined(BUILD_EMBED_FIRST_CHUNK) || defined(BUILD_PAGE_FIRST_CHUNK) -/** - * pcpu_build_alloc_info - build alloc_info considering distances between CPUs - * @reserved_size: the size of reserved percpu area in bytes - * @dyn_size: minimum free size for dynamic allocation in bytes - * @atom_size: allocation atom size - * @cpu_distance_fn: callback to determine distance between cpus, optional - * - * This function determines grouping of units, their mappings to cpus - * and other parameters considering needed percpu size, allocation - * atom size and distances between CPUs. - * - * Groups are always multiples of atom size and CPUs which are of - * LOCAL_DISTANCE both ways are grouped together and share space for - * units in the same group. The returned configuration is guaranteed - * to have CPUs on different nodes on different groups and >=75% usage - * of allocated virtual address space. - * - * RETURNS: - * On success, pointer to the new allocation_info is returned. On - * failure, ERR_PTR value is returned. - */ -static struct pcpu_alloc_info * __init pcpu_build_alloc_info( - size_t reserved_size, size_t dyn_size, - size_t atom_size, - pcpu_fc_cpu_distance_fn_t cpu_distance_fn) -{ - static int group_map[NR_CPUS] __initdata; - static int group_cnt[NR_CPUS] __initdata; - const size_t static_size = __per_cpu_end - __per_cpu_start; - int nr_groups = 1, nr_units = 0; - size_t size_sum, min_unit_size, alloc_size; - int upa, max_upa, uninitialized_var(best_upa); /* units_per_alloc */ - int last_allocs, group, unit; - unsigned int cpu, tcpu; - struct pcpu_alloc_info *ai; - unsigned int *cpu_map; - - /* this function may be called multiple times */ - memset(group_map, 0, sizeof(group_map)); - memset(group_cnt, 0, sizeof(group_cnt)); - - /* calculate size_sum and ensure dyn_size is enough for early alloc */ - size_sum = PFN_ALIGN(static_size + reserved_size + - max_t(size_t, dyn_size, PERCPU_DYNAMIC_EARLY_SIZE)); - dyn_size = size_sum - static_size - reserved_size; - - /* - * Determine min_unit_size, alloc_size and max_upa such that - * alloc_size is multiple of atom_size and is the smallest - * which can accommodate 4k aligned segments which are equal to - * or larger than min_unit_size. - */ - min_unit_size = max_t(size_t, size_sum, PCPU_MIN_UNIT_SIZE); - - alloc_size = roundup(min_unit_size, atom_size); - upa = alloc_size / min_unit_size; - while (alloc_size % upa || (offset_in_page(alloc_size / upa))) - upa--; - max_upa = upa; - - /* group cpus according to their proximity */ - for_each_possible_cpu(cpu) { - group = 0; - next_group: - for_each_possible_cpu(tcpu) { - if (cpu == tcpu) - break; - if (group_map[tcpu] == group && cpu_distance_fn && - (cpu_distance_fn(cpu, tcpu) > LOCAL_DISTANCE || - cpu_distance_fn(tcpu, cpu) > LOCAL_DISTANCE)) { - group++; - nr_groups = max(nr_groups, group + 1); - goto next_group; - } - } - group_map[cpu] = group; - group_cnt[group]++; - } - - /* - * Expand unit size until address space usage goes over 75% - * and then as much as possible without using more address - * space. - */ - last_allocs = INT_MAX; - for (upa = max_upa; upa; upa--) { - int allocs = 0, wasted = 0; - - if (alloc_size % upa || (offset_in_page(alloc_size / upa))) - continue; - - for (group = 0; group < nr_groups; group++) { - int this_allocs = DIV_ROUND_UP(group_cnt[group], upa); - allocs += this_allocs; - wasted += this_allocs * upa - group_cnt[group]; - } - - /* - * Don't accept if wastage is over 1/3. The - * greater-than comparison ensures upa==1 always - * passes the following check. - */ - if (wasted > num_possible_cpus() / 3) - continue; - - /* and then don't consume more memory */ - if (allocs > last_allocs) - break; - last_allocs = allocs; - best_upa = upa; - } - upa = best_upa; - - /* allocate and fill alloc_info */ - for (group = 0; group < nr_groups; group++) - nr_units += roundup(group_cnt[group], upa); - - ai = pcpu_alloc_alloc_info(nr_groups, nr_units); - if (!ai) - return ERR_PTR(-ENOMEM); - cpu_map = ai->groups[0].cpu_map; - - for (group = 0; group < nr_groups; group++) { - ai->groups[group].cpu_map = cpu_map; - cpu_map += roundup(group_cnt[group], upa); - } - - ai->static_size = static_size; - ai->reserved_size = reserved_size; - ai->dyn_size = dyn_size; - ai->unit_size = alloc_size / upa; - ai->atom_size = atom_size; - ai->alloc_size = alloc_size; - - for (group = 0, unit = 0; group_cnt[group]; group++) { - struct pcpu_group_info *gi = &ai->groups[group]; - - /* - * Initialize base_offset as if all groups are located - * back-to-back. The caller should update this to - * reflect actual allocation. - */ - gi->base_offset = unit * ai->unit_size; - - for_each_possible_cpu(cpu) - if (group_map[cpu] == group) - gi->cpu_map[gi->nr_units++] = cpu; - gi->nr_units = roundup(gi->nr_units, upa); - unit += gi->nr_units; - } - BUG_ON(unit != nr_units); - - return ai; -} -#endif /* BUILD_EMBED_FIRST_CHUNK || BUILD_PAGE_FIRST_CHUNK */ - -#if defined(BUILD_EMBED_FIRST_CHUNK) -/** - * pcpu_embed_first_chunk - embed the first percpu chunk into bootmem - * @reserved_size: the size of reserved percpu area in bytes - * @dyn_size: minimum free size for dynamic allocation in bytes - * @atom_size: allocation atom size - * @cpu_distance_fn: callback to determine distance between cpus, optional - * @alloc_fn: function to allocate percpu page - * @free_fn: function to free percpu page - * - * This is a helper to ease setting up embedded first percpu chunk and - * can be called where pcpu_setup_first_chunk() is expected. - * - * If this function is used to setup the first chunk, it is allocated - * by calling @alloc_fn and used as-is without being mapped into - * vmalloc area. Allocations are always whole multiples of @atom_size - * aligned to @atom_size. - * - * This enables the first chunk to piggy back on the linear physical - * mapping which often uses larger page size. Please note that this - * can result in very sparse cpu->unit mapping on NUMA machines thus - * requiring large vmalloc address space. Don't use this allocator if - * vmalloc space is not orders of magnitude larger than distances - * between node memory addresses (ie. 32bit NUMA machines). - * - * @dyn_size specifies the minimum dynamic area size. - * - * If the needed size is smaller than the minimum or specified unit - * size, the leftover is returned using @free_fn. - * - * RETURNS: - * 0 on success, -errno on failure. - */ -int __init pcpu_embed_first_chunk(size_t reserved_size, size_t dyn_size, - size_t atom_size, - pcpu_fc_cpu_distance_fn_t cpu_distance_fn, - pcpu_fc_alloc_fn_t alloc_fn, - pcpu_fc_free_fn_t free_fn) -{ - void *base = (void *)ULONG_MAX; - void **areas = NULL; - struct pcpu_alloc_info *ai; - size_t size_sum, areas_size; - unsigned long max_distance; - int group, i, highest_group, rc; - - ai = pcpu_build_alloc_info(reserved_size, dyn_size, atom_size, - cpu_distance_fn); - if (IS_ERR(ai)) - return PTR_ERR(ai); - - size_sum = ai->static_size + ai->reserved_size + ai->dyn_size; - areas_size = PFN_ALIGN(ai->nr_groups * sizeof(void *)); - - areas = memblock_virt_alloc_nopanic(areas_size, 0); - if (!areas) { - rc = -ENOMEM; - goto out_free; - } - - /* allocate, copy and determine base address & max_distance */ - highest_group = 0; - for (group = 0; group < ai->nr_groups; group++) { - struct pcpu_group_info *gi = &ai->groups[group]; - unsigned int cpu = NR_CPUS; - void *ptr; - - for (i = 0; i < gi->nr_units && cpu == NR_CPUS; i++) - cpu = gi->cpu_map[i]; - BUG_ON(cpu == NR_CPUS); - - /* allocate space for the whole group */ - ptr = alloc_fn(cpu, gi->nr_units * ai->unit_size, atom_size); - if (!ptr) { - rc = -ENOMEM; - goto out_free_areas; - } - /* kmemleak tracks the percpu allocations separately */ - kmemleak_free(ptr); - areas[group] = ptr; - - base = min(ptr, base); - if (ptr > areas[highest_group]) - highest_group = group; - } - max_distance = areas[highest_group] - base; - max_distance += ai->unit_size * ai->groups[highest_group].nr_units; - - /* warn if maximum distance is further than 75% of vmalloc space */ - if (max_distance > VMALLOC_TOTAL * 3 / 4) { - pr_warn("max_distance=0x%lx too large for vmalloc space 0x%lx\n", - max_distance, VMALLOC_TOTAL); -#ifdef CONFIG_NEED_PER_CPU_PAGE_FIRST_CHUNK - /* and fail if we have fallback */ - rc = -EINVAL; - goto out_free_areas; -#endif - } - - /* - * Copy data and free unused parts. This should happen after all - * allocations are complete; otherwise, we may end up with - * overlapping groups. - */ - for (group = 0; group < ai->nr_groups; group++) { - struct pcpu_group_info *gi = &ai->groups[group]; - void *ptr = areas[group]; - - for (i = 0; i < gi->nr_units; i++, ptr += ai->unit_size) { - if (gi->cpu_map[i] == NR_CPUS) { - /* unused unit, free whole */ - free_fn(ptr, ai->unit_size); - continue; - } - /* copy and return the unused part */ - memcpy(ptr, __per_cpu_load, ai->static_size); - free_fn(ptr + size_sum, ai->unit_size - size_sum); - } - } - - /* base address is now known, determine group base offsets */ - for (group = 0; group < ai->nr_groups; group++) { - ai->groups[group].base_offset = areas[group] - base; - } - - pr_info("Embedded %zu pages/cpu @%p s%zu r%zu d%zu u%zu\n", - PFN_DOWN(size_sum), base, ai->static_size, ai->reserved_size, - ai->dyn_size, ai->unit_size); - - rc = pcpu_setup_first_chunk(ai, base); - goto out_free; - -out_free_areas: - for (group = 0; group < ai->nr_groups; group++) - if (areas[group]) - free_fn(areas[group], - ai->groups[group].nr_units * ai->unit_size); -out_free: - pcpu_free_alloc_info(ai); - if (areas) - memblock_free_early(__pa(areas), areas_size); - return rc; -} -#endif /* BUILD_EMBED_FIRST_CHUNK */ - -#ifdef BUILD_PAGE_FIRST_CHUNK -/** - * pcpu_page_first_chunk - map the first chunk using PAGE_SIZE pages - * @reserved_size: the size of reserved percpu area in bytes - * @alloc_fn: function to allocate percpu page, always called with PAGE_SIZE - * @free_fn: function to free percpu page, always called with PAGE_SIZE - * @populate_pte_fn: function to populate pte - * - * This is a helper to ease setting up page-remapped first percpu - * chunk and can be called where pcpu_setup_first_chunk() is expected. - * - * This is the basic allocator. Static percpu area is allocated - * page-by-page into vmalloc area. - * - * RETURNS: - * 0 on success, -errno on failure. - */ -int __init pcpu_page_first_chunk(size_t reserved_size, - pcpu_fc_alloc_fn_t alloc_fn, - pcpu_fc_free_fn_t free_fn, - pcpu_fc_populate_pte_fn_t populate_pte_fn) -{ - static struct vm_struct vm; - struct pcpu_alloc_info *ai; - char psize_str[16]; - int unit_pages; - size_t pages_size; - struct page **pages; - int unit, i, j, rc; - - snprintf(psize_str, sizeof(psize_str), "%luK", PAGE_SIZE >> 10); - - ai = pcpu_build_alloc_info(reserved_size, 0, PAGE_SIZE, NULL); - if (IS_ERR(ai)) - return PTR_ERR(ai); - BUG_ON(ai->nr_groups != 1); - BUG_ON(ai->groups[0].nr_units != num_possible_cpus()); - - unit_pages = ai->unit_size >> PAGE_SHIFT; - - /* unaligned allocations can't be freed, round up to page size */ - pages_size = PFN_ALIGN(unit_pages * num_possible_cpus() * - sizeof(pages[0])); - pages = memblock_virt_alloc(pages_size, 0); - - /* allocate pages */ - j = 0; - for (unit = 0; unit < num_possible_cpus(); unit++) - for (i = 0; i < unit_pages; i++) { - unsigned int cpu = ai->groups[0].cpu_map[unit]; - void *ptr; - - ptr = alloc_fn(cpu, PAGE_SIZE, PAGE_SIZE); - if (!ptr) { - pr_warn("failed to allocate %s page for cpu%u\n", - psize_str, cpu); - goto enomem; - } - /* kmemleak tracks the percpu allocations separately */ - kmemleak_free(ptr); - pages[j++] = virt_to_page(ptr); - } - - /* allocate vm area, map the pages and copy static data */ - vm.flags = VM_ALLOC; - vm.size = num_possible_cpus() * ai->unit_size; - vm_area_register_early(&vm, PAGE_SIZE); - - for (unit = 0; unit < num_possible_cpus(); unit++) { - unsigned long unit_addr = - (unsigned long)vm.addr + unit * ai->unit_size; - - for (i = 0; i < unit_pages; i++) - populate_pte_fn(unit_addr + (i << PAGE_SHIFT)); - - /* pte already populated, the following shouldn't fail */ - rc = __pcpu_map_pages(unit_addr, &pages[unit * unit_pages], - unit_pages); - if (rc < 0) - panic("failed to map percpu area, err=%d\n", rc); - - /* - * FIXME: Archs with virtual cache should flush local - * cache for the linear mapping here - something - * equivalent to flush_cache_vmap() on the local cpu. - * flush_cache_vmap() can't be used as most supporting - * data structures are not set up yet. - */ - - /* copy static data */ - memcpy((void *)unit_addr, __per_cpu_load, ai->static_size); - } - - /* we're ready, commit */ - pr_info("%d %s pages/cpu @%p s%zu r%zu d%zu\n", - unit_pages, psize_str, vm.addr, ai->static_size, - ai->reserved_size, ai->dyn_size); - - rc = pcpu_setup_first_chunk(ai, vm.addr); - goto out_free_ar; - -enomem: - while (--j >= 0) - free_fn(page_address(pages[j]), PAGE_SIZE); - rc = -ENOMEM; -out_free_ar: - memblock_free_early(__pa(pages), pages_size); - pcpu_free_alloc_info(ai); - return rc; -} -#endif /* BUILD_PAGE_FIRST_CHUNK */ - -#ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA -/* - * Generic SMP percpu area setup. - * - * The embedding helper is used because its behavior closely resembles - * the original non-dynamic generic percpu area setup. This is - * important because many archs have addressing restrictions and might - * fail if the percpu area is located far away from the previous - * location. As an added bonus, in non-NUMA cases, embedding is - * generally a good idea TLB-wise because percpu area can piggy back - * on the physical linear memory mapping which uses large page - * mappings on applicable archs. - */ -unsigned long __per_cpu_offset[NR_CPUS] __read_mostly; -EXPORT_SYMBOL(__per_cpu_offset); - -static void * __init pcpu_dfl_fc_alloc(unsigned int cpu, size_t size, - size_t align) -{ - return memblock_virt_alloc_from_nopanic( - size, align, __pa(MAX_DMA_ADDRESS)); -} - -static void __init pcpu_dfl_fc_free(void *ptr, size_t size) -{ - memblock_free_early(__pa(ptr), size); -} - -void __init setup_per_cpu_areas(void) -{ - unsigned long delta; - unsigned int cpu; - int rc; - - /* - * Always reserve area for module percpu variables. That's - * what the legacy allocator did. - */ - rc = pcpu_embed_first_chunk(PERCPU_MODULE_RESERVE, - PERCPU_DYNAMIC_RESERVE, PAGE_SIZE, NULL, - pcpu_dfl_fc_alloc, pcpu_dfl_fc_free); - if (rc < 0) - panic("Failed to initialize percpu areas."); - - delta = (unsigned long)pcpu_base_addr - (unsigned long)__per_cpu_start; - for_each_possible_cpu(cpu) - __per_cpu_offset[cpu] = delta + pcpu_unit_offsets[cpu]; -} -#endif /* CONFIG_HAVE_SETUP_PER_CPU_AREA */ - -#else /* CONFIG_SMP */ - -/* - * UP percpu area setup. - * - * UP always uses km-based percpu allocator with identity mapping. - * Static percpu variables are indistinguishable from the usual static - * variables and don't require any special preparation. - */ -void __init setup_per_cpu_areas(void) -{ - const size_t unit_size = - roundup_pow_of_two(max_t(size_t, PCPU_MIN_UNIT_SIZE, - PERCPU_DYNAMIC_RESERVE)); - struct pcpu_alloc_info *ai; - void *fc; - - ai = pcpu_alloc_alloc_info(1, 1); - fc = memblock_virt_alloc_from_nopanic(unit_size, - PAGE_SIZE, - __pa(MAX_DMA_ADDRESS)); - if (!ai || !fc) - panic("Failed to allocate memory for percpu areas."); - /* kmemleak tracks the percpu allocations separately */ - kmemleak_free(fc); - - ai->dyn_size = unit_size; - ai->unit_size = unit_size; - ai->atom_size = unit_size; - ai->alloc_size = unit_size; - ai->groups[0].nr_units = 1; - ai->groups[0].cpu_map[0] = 0; - - if (pcpu_setup_first_chunk(ai, fc) < 0) - panic("Failed to initialize percpu areas."); -} - -#endif /* CONFIG_SMP */ - -/* - * First and reserved chunks are initialized with temporary allocation - * map in initdata so that they can be used before slab is online. - * This function is called after slab is brought up and replaces those - * with properly allocated maps. - */ -void __init percpu_init_late(void) -{ - struct pcpu_chunk *target_chunks[] = - { pcpu_first_chunk, pcpu_reserved_chunk, NULL }; - struct pcpu_chunk *chunk; - unsigned long flags; - int i; - - for (i = 0; (chunk = target_chunks[i]); i++) { - int *map; - const size_t size = PERCPU_DYNAMIC_EARLY_SLOTS * sizeof(map[0]); - - BUILD_BUG_ON(size > PAGE_SIZE); - - map = pcpu_mem_zalloc(size); - BUG_ON(!map); - - spin_lock_irqsave(&pcpu_lock, flags); - memcpy(map, chunk->map, size); - chunk->map = map; - spin_unlock_irqrestore(&pcpu_lock, flags); - } -} - -/* - * Percpu allocator is initialized early during boot when neither slab or - * workqueue is available. Plug async management until everything is up - * and running. - */ -static int __init percpu_enable_async(void) -{ - pcpu_async_enabled = true; - return 0; -} -subsys_initcall(percpu_enable_async); diff --git a/src/linux/mm/readahead.c b/src/linux/mm/readahead.c deleted file mode 100644 index c8a955b..0000000 --- a/src/linux/mm/readahead.c +++ /dev/null @@ -1,577 +0,0 @@ -/* - * mm/readahead.c - address_space-level file readahead. - * - * Copyright (C) 2002, Linus Torvalds - * - * 09Apr2002 Andrew Morton - * Initial version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -/* - * Initialise a struct file's readahead state. Assumes that the caller has - * memset *ra to zero. - */ -void -file_ra_state_init(struct file_ra_state *ra, struct address_space *mapping) -{ - ra->ra_pages = inode_to_bdi(mapping->host)->ra_pages; - ra->prev_pos = -1; -} -EXPORT_SYMBOL_GPL(file_ra_state_init); - -/* - * see if a page needs releasing upon read_cache_pages() failure - * - the caller of read_cache_pages() may have set PG_private or PG_fscache - * before calling, such as the NFS fs marking pages that are cached locally - * on disk, thus we need to give the fs a chance to clean up in the event of - * an error - */ -static void read_cache_pages_invalidate_page(struct address_space *mapping, - struct page *page) -{ - if (page_has_private(page)) { - if (!trylock_page(page)) - BUG(); - page->mapping = mapping; - do_invalidatepage(page, 0, PAGE_SIZE); - page->mapping = NULL; - unlock_page(page); - } - put_page(page); -} - -/* - * release a list of pages, invalidating them first if need be - */ -static void read_cache_pages_invalidate_pages(struct address_space *mapping, - struct list_head *pages) -{ - struct page *victim; - - while (!list_empty(pages)) { - victim = lru_to_page(pages); - list_del(&victim->lru); - read_cache_pages_invalidate_page(mapping, victim); - } -} - -/** - * read_cache_pages - populate an address space with some pages & start reads against them - * @mapping: the address_space - * @pages: The address of a list_head which contains the target pages. These - * pages have their ->index populated and are otherwise uninitialised. - * @filler: callback routine for filling a single page. - * @data: private data for the callback routine. - * - * Hides the details of the LRU cache etc from the filesystems. - */ -int read_cache_pages(struct address_space *mapping, struct list_head *pages, - int (*filler)(void *, struct page *), void *data) -{ - struct page *page; - int ret = 0; - - while (!list_empty(pages)) { - page = lru_to_page(pages); - list_del(&page->lru); - if (add_to_page_cache_lru(page, mapping, page->index, - readahead_gfp_mask(mapping))) { - read_cache_pages_invalidate_page(mapping, page); - continue; - } - put_page(page); - - ret = filler(data, page); - if (unlikely(ret)) { - read_cache_pages_invalidate_pages(mapping, pages); - break; - } - task_io_account_read(PAGE_SIZE); - } - return ret; -} - -EXPORT_SYMBOL(read_cache_pages); - -static int read_pages(struct address_space *mapping, struct file *filp, - struct list_head *pages, unsigned int nr_pages, gfp_t gfp) -{ - struct blk_plug plug; - unsigned page_idx; - int ret; - - blk_start_plug(&plug); - - if (mapping->a_ops->readpages) { - ret = mapping->a_ops->readpages(filp, mapping, pages, nr_pages); - /* Clean up the remaining pages */ - put_pages_list(pages); - goto out; - } - - for (page_idx = 0; page_idx < nr_pages; page_idx++) { - struct page *page = lru_to_page(pages); - list_del(&page->lru); - if (!add_to_page_cache_lru(page, mapping, page->index, gfp)) - mapping->a_ops->readpage(filp, page); - put_page(page); - } - ret = 0; - -out: - blk_finish_plug(&plug); - - return ret; -} - -/* - * __do_page_cache_readahead() actually reads a chunk of disk. It allocates all - * the pages first, then submits them all for I/O. This avoids the very bad - * behaviour which would occur if page allocations are causing VM writeback. - * We really don't want to intermingle reads and writes like that. - * - * Returns the number of pages requested, or the maximum amount of I/O allowed. - */ -int __do_page_cache_readahead(struct address_space *mapping, struct file *filp, - pgoff_t offset, unsigned long nr_to_read, - unsigned long lookahead_size) -{ - struct inode *inode = mapping->host; - struct page *page; - unsigned long end_index; /* The last page we want to read */ - LIST_HEAD(page_pool); - int page_idx; - int ret = 0; - loff_t isize = i_size_read(inode); - gfp_t gfp_mask = readahead_gfp_mask(mapping); - - if (isize == 0) - goto out; - - end_index = ((isize - 1) >> PAGE_SHIFT); - - /* - * Preallocate as many pages as we will need. - */ - for (page_idx = 0; page_idx < nr_to_read; page_idx++) { - pgoff_t page_offset = offset + page_idx; - - if (page_offset > end_index) - break; - - rcu_read_lock(); - page = radix_tree_lookup(&mapping->page_tree, page_offset); - rcu_read_unlock(); - if (page && !radix_tree_exceptional_entry(page)) - continue; - - page = __page_cache_alloc(gfp_mask); - if (!page) - break; - page->index = page_offset; - list_add(&page->lru, &page_pool); - if (page_idx == nr_to_read - lookahead_size) - SetPageReadahead(page); - ret++; - } - - /* - * Now start the IO. We ignore I/O errors - if the page is not - * uptodate then the caller will launch readpage again, and - * will then handle the error. - */ - if (ret) - read_pages(mapping, filp, &page_pool, ret, gfp_mask); - BUG_ON(!list_empty(&page_pool)); -out: - return ret; -} - -/* - * Chunk the readahead into 2 megabyte units, so that we don't pin too much - * memory at once. - */ -int force_page_cache_readahead(struct address_space *mapping, struct file *filp, - pgoff_t offset, unsigned long nr_to_read) -{ - if (unlikely(!mapping->a_ops->readpage && !mapping->a_ops->readpages)) - return -EINVAL; - - nr_to_read = min(nr_to_read, inode_to_bdi(mapping->host)->ra_pages); - while (nr_to_read) { - int err; - - unsigned long this_chunk = (2 * 1024 * 1024) / PAGE_SIZE; - - if (this_chunk > nr_to_read) - this_chunk = nr_to_read; - err = __do_page_cache_readahead(mapping, filp, - offset, this_chunk, 0); - if (err < 0) - return err; - - offset += this_chunk; - nr_to_read -= this_chunk; - } - return 0; -} - -/* - * Set the initial window size, round to next power of 2 and square - * for small size, x 4 for medium, and x 2 for large - * for 128k (32 page) max ra - * 1-8 page = 32k initial, > 8 page = 128k initial - */ -static unsigned long get_init_ra_size(unsigned long size, unsigned long max) -{ - unsigned long newsize = roundup_pow_of_two(size); - - if (newsize <= max / 32) - newsize = newsize * 4; - else if (newsize <= max / 4) - newsize = newsize * 2; - else - newsize = max; - - return newsize; -} - -/* - * Get the previous window size, ramp it up, and - * return it as the new window size. - */ -static unsigned long get_next_ra_size(struct file_ra_state *ra, - unsigned long max) -{ - unsigned long cur = ra->size; - unsigned long newsize; - - if (cur < max / 16) - newsize = 4 * cur; - else - newsize = 2 * cur; - - return min(newsize, max); -} - -/* - * On-demand readahead design. - * - * The fields in struct file_ra_state represent the most-recently-executed - * readahead attempt: - * - * |<----- async_size ---------| - * |------------------- size -------------------->| - * |==================#===========================| - * ^start ^page marked with PG_readahead - * - * To overlap application thinking time and disk I/O time, we do - * `readahead pipelining': Do not wait until the application consumed all - * readahead pages and stalled on the missing page at readahead_index; - * Instead, submit an asynchronous readahead I/O as soon as there are - * only async_size pages left in the readahead window. Normally async_size - * will be equal to size, for maximum pipelining. - * - * In interleaved sequential reads, concurrent streams on the same fd can - * be invalidating each other's readahead state. So we flag the new readahead - * page at (start+size-async_size) with PG_readahead, and use it as readahead - * indicator. The flag won't be set on already cached pages, to avoid the - * readahead-for-nothing fuss, saving pointless page cache lookups. - * - * prev_pos tracks the last visited byte in the _previous_ read request. - * It should be maintained by the caller, and will be used for detecting - * small random reads. Note that the readahead algorithm checks loosely - * for sequential patterns. Hence interleaved reads might be served as - * sequential ones. - * - * There is a special-case: if the first page which the application tries to - * read happens to be the first page of the file, it is assumed that a linear - * read is about to happen and the window is immediately set to the initial size - * based on I/O request size and the max_readahead. - * - * The code ramps up the readahead size aggressively at first, but slow down as - * it approaches max_readhead. - */ - -/* - * Count contiguously cached pages from @offset-1 to @offset-@max, - * this count is a conservative estimation of - * - length of the sequential read sequence, or - * - thrashing threshold in memory tight systems - */ -static pgoff_t count_history_pages(struct address_space *mapping, - pgoff_t offset, unsigned long max) -{ - pgoff_t head; - - rcu_read_lock(); - head = page_cache_prev_hole(mapping, offset - 1, max); - rcu_read_unlock(); - - return offset - 1 - head; -} - -/* - * page cache context based read-ahead - */ -static int try_context_readahead(struct address_space *mapping, - struct file_ra_state *ra, - pgoff_t offset, - unsigned long req_size, - unsigned long max) -{ - pgoff_t size; - - size = count_history_pages(mapping, offset, max); - - /* - * not enough history pages: - * it could be a random read - */ - if (size <= req_size) - return 0; - - /* - * starts from beginning of file: - * it is a strong indication of long-run stream (or whole-file-read) - */ - if (size >= offset) - size *= 2; - - ra->start = offset; - ra->size = min(size + req_size, max); - ra->async_size = 1; - - return 1; -} - -/* - * A minimal readahead algorithm for trivial sequential/random reads. - */ -static unsigned long -ondemand_readahead(struct address_space *mapping, - struct file_ra_state *ra, struct file *filp, - bool hit_readahead_marker, pgoff_t offset, - unsigned long req_size) -{ - unsigned long max = ra->ra_pages; - pgoff_t prev_offset; - - /* - * start of file - */ - if (!offset) - goto initial_readahead; - - /* - * It's the expected callback offset, assume sequential access. - * Ramp up sizes, and push forward the readahead window. - */ - if ((offset == (ra->start + ra->size - ra->async_size) || - offset == (ra->start + ra->size))) { - ra->start += ra->size; - ra->size = get_next_ra_size(ra, max); - ra->async_size = ra->size; - goto readit; - } - - /* - * Hit a marked page without valid readahead state. - * E.g. interleaved reads. - * Query the pagecache for async_size, which normally equals to - * readahead size. Ramp it up and use it as the new readahead size. - */ - if (hit_readahead_marker) { - pgoff_t start; - - rcu_read_lock(); - start = page_cache_next_hole(mapping, offset + 1, max); - rcu_read_unlock(); - - if (!start || start - offset > max) - return 0; - - ra->start = start; - ra->size = start - offset; /* old async_size */ - ra->size += req_size; - ra->size = get_next_ra_size(ra, max); - ra->async_size = ra->size; - goto readit; - } - - /* - * oversize read - */ - if (req_size > max) - goto initial_readahead; - - /* - * sequential cache miss - * trivial case: (offset - prev_offset) == 1 - * unaligned reads: (offset - prev_offset) == 0 - */ - prev_offset = (unsigned long long)ra->prev_pos >> PAGE_SHIFT; - if (offset - prev_offset <= 1UL) - goto initial_readahead; - - /* - * Query the page cache and look for the traces(cached history pages) - * that a sequential stream would leave behind. - */ - if (try_context_readahead(mapping, ra, offset, req_size, max)) - goto readit; - - /* - * standalone, small random read - * Read as is, and do not pollute the readahead state. - */ - return __do_page_cache_readahead(mapping, filp, offset, req_size, 0); - -initial_readahead: - ra->start = offset; - ra->size = get_init_ra_size(req_size, max); - ra->async_size = ra->size > req_size ? ra->size - req_size : ra->size; - -readit: - /* - * Will this read hit the readahead marker made by itself? - * If so, trigger the readahead marker hit now, and merge - * the resulted next readahead window into the current one. - */ - if (offset == ra->start && ra->size == ra->async_size) { - ra->async_size = get_next_ra_size(ra, max); - ra->size += ra->async_size; - } - - return ra_submit(ra, mapping, filp); -} - -/** - * page_cache_sync_readahead - generic file readahead - * @mapping: address_space which holds the pagecache and I/O vectors - * @ra: file_ra_state which holds the readahead state - * @filp: passed on to ->readpage() and ->readpages() - * @offset: start offset into @mapping, in pagecache page-sized units - * @req_size: hint: total size of the read which the caller is performing in - * pagecache pages - * - * page_cache_sync_readahead() should be called when a cache miss happened: - * it will submit the read. The readahead logic may decide to piggyback more - * pages onto the read request if access patterns suggest it will improve - * performance. - */ -void page_cache_sync_readahead(struct address_space *mapping, - struct file_ra_state *ra, struct file *filp, - pgoff_t offset, unsigned long req_size) -{ - /* no read-ahead */ - if (!ra->ra_pages) - return; - - /* be dumb */ - if (filp && (filp->f_mode & FMODE_RANDOM)) { - force_page_cache_readahead(mapping, filp, offset, req_size); - return; - } - - /* do read-ahead */ - ondemand_readahead(mapping, ra, filp, false, offset, req_size); -} -EXPORT_SYMBOL_GPL(page_cache_sync_readahead); - -/** - * page_cache_async_readahead - file readahead for marked pages - * @mapping: address_space which holds the pagecache and I/O vectors - * @ra: file_ra_state which holds the readahead state - * @filp: passed on to ->readpage() and ->readpages() - * @page: the page at @offset which has the PG_readahead flag set - * @offset: start offset into @mapping, in pagecache page-sized units - * @req_size: hint: total size of the read which the caller is performing in - * pagecache pages - * - * page_cache_async_readahead() should be called when a page is used which - * has the PG_readahead flag; this is a marker to suggest that the application - * has used up enough of the readahead window that we should start pulling in - * more pages. - */ -void -page_cache_async_readahead(struct address_space *mapping, - struct file_ra_state *ra, struct file *filp, - struct page *page, pgoff_t offset, - unsigned long req_size) -{ - /* no read-ahead */ - if (!ra->ra_pages) - return; - - /* - * Same bit is used for PG_readahead and PG_reclaim. - */ - if (PageWriteback(page)) - return; - - ClearPageReadahead(page); - - /* - * Defer asynchronous read-ahead on IO congestion. - */ - if (inode_read_congested(mapping->host)) - return; - - /* do read-ahead */ - ondemand_readahead(mapping, ra, filp, true, offset, req_size); -} -EXPORT_SYMBOL_GPL(page_cache_async_readahead); - -static ssize_t -do_readahead(struct address_space *mapping, struct file *filp, - pgoff_t index, unsigned long nr) -{ - if (!mapping || !mapping->a_ops) - return -EINVAL; - - /* - * Readahead doesn't make sense for DAX inodes, but we don't want it - * to report a failure either. Instead, we just return success and - * don't do any work. - */ - if (dax_mapping(mapping)) - return 0; - - return force_page_cache_readahead(mapping, filp, index, nr); -} - -SYSCALL_DEFINE3(readahead, int, fd, loff_t, offset, size_t, count) -{ - ssize_t ret; - struct fd f; - - ret = -EBADF; - f = fdget(fd); - if (f.file) { - if (f.file->f_mode & FMODE_READ) { - struct address_space *mapping = f.file->f_mapping; - pgoff_t start = offset >> PAGE_SHIFT; - pgoff_t end = (offset + count - 1) >> PAGE_SHIFT; - unsigned long len = end - start + 1; - ret = do_readahead(mapping, f.file, start, len); - } - fdput(f); - } - return ret; -} diff --git a/src/linux/mm/shmem.c b/src/linux/mm/shmem.c deleted file mode 100644 index 9d32e1c..0000000 --- a/src/linux/mm/shmem.c +++ /dev/null @@ -1,4126 +0,0 @@ -/* - * Resizable virtual memory filesystem for Linux. - * - * Copyright (C) 2000 Linus Torvalds. - * 2000 Transmeta Corp. - * 2000-2001 Christoph Rohland - * 2000-2001 SAP AG - * 2002 Red Hat Inc. - * Copyright (C) 2002-2011 Hugh Dickins. - * Copyright (C) 2011 Google Inc. - * Copyright (C) 2002-2005 VERITAS Software Corporation. - * Copyright (C) 2004 Andi Kleen, SuSE Labs - * - * Extended attribute support for tmpfs: - * Copyright (c) 2004, Luke Kenneth Casson Leighton - * Copyright (c) 2004 Red Hat, Inc., James Morris - * - * tiny-shmem: - * Copyright (c) 2004, 2008 Matt Mackall - * - * This file is released under the GPL. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct vfsmount *shm_mnt; - -#ifdef CONFIG_SHMEM -/* - * This virtual memory filesystem is heavily based on the ramfs. It - * extends ramfs by the ability to use swap and honor resource limits - * which makes it a completely usable filesystem. - */ - -#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 -#include - -#include "internal.h" - -#define BLOCKS_PER_PAGE (PAGE_SIZE/512) -#define VM_ACCT(size) (PAGE_ALIGN(size) >> PAGE_SHIFT) - -/* Pretend that each entry is of this size in directory's i_size */ -#define BOGO_DIRENT_SIZE 20 - -/* Symlink up to this size is kmalloc'ed instead of using a swappable page */ -#define SHORT_SYMLINK_LEN 128 - -/* - * shmem_fallocate communicates with shmem_fault or shmem_writepage via - * inode->i_private (with i_mutex making sure that it has only one user at - * a time): we would prefer not to enlarge the shmem inode just for that. - */ -struct shmem_falloc { - wait_queue_head_t *waitq; /* faults into hole wait for punch to end */ - pgoff_t start; /* start of range currently being fallocated */ - pgoff_t next; /* the next page offset to be fallocated */ - pgoff_t nr_falloced; /* how many new pages have been fallocated */ - pgoff_t nr_unswapped; /* how often writepage refused to swap out */ -}; - -#ifdef CONFIG_TMPFS -static unsigned long shmem_default_max_blocks(void) -{ - return totalram_pages / 2; -} - -static unsigned long shmem_default_max_inodes(void) -{ - return min(totalram_pages - totalhigh_pages, totalram_pages / 2); -} -#endif - -static bool shmem_should_replace_page(struct page *page, gfp_t gfp); -static int shmem_replace_page(struct page **pagep, gfp_t gfp, - struct shmem_inode_info *info, pgoff_t index); -static int shmem_getpage_gfp(struct inode *inode, pgoff_t index, - struct page **pagep, enum sgp_type sgp, - gfp_t gfp, struct mm_struct *fault_mm, int *fault_type); - -int shmem_getpage(struct inode *inode, pgoff_t index, - struct page **pagep, enum sgp_type sgp) -{ - return shmem_getpage_gfp(inode, index, pagep, sgp, - mapping_gfp_mask(inode->i_mapping), NULL, NULL); -} - -static inline struct shmem_sb_info *SHMEM_SB(struct super_block *sb) -{ - return sb->s_fs_info; -} - -/* - * shmem_file_setup pre-accounts the whole fixed size of a VM object, - * for shared memory and for shared anonymous (/dev/zero) mappings - * (unless MAP_NORESERVE and sysctl_overcommit_memory <= 1), - * consistent with the pre-accounting of private mappings ... - */ -static inline int shmem_acct_size(unsigned long flags, loff_t size) -{ - return (flags & VM_NORESERVE) ? - 0 : security_vm_enough_memory_mm(current->mm, VM_ACCT(size)); -} - -static inline void shmem_unacct_size(unsigned long flags, loff_t size) -{ - if (!(flags & VM_NORESERVE)) - vm_unacct_memory(VM_ACCT(size)); -} - -static inline int shmem_reacct_size(unsigned long flags, - loff_t oldsize, loff_t newsize) -{ - if (!(flags & VM_NORESERVE)) { - if (VM_ACCT(newsize) > VM_ACCT(oldsize)) - return security_vm_enough_memory_mm(current->mm, - VM_ACCT(newsize) - VM_ACCT(oldsize)); - else if (VM_ACCT(newsize) < VM_ACCT(oldsize)) - vm_unacct_memory(VM_ACCT(oldsize) - VM_ACCT(newsize)); - } - return 0; -} - -/* - * ... whereas tmpfs objects are accounted incrementally as - * pages are allocated, in order to allow large sparse files. - * shmem_getpage reports shmem_acct_block failure as -ENOSPC not -ENOMEM, - * so that a failure on a sparse tmpfs mapping will give SIGBUS not OOM. - */ -static inline int shmem_acct_block(unsigned long flags, long pages) -{ - if (!(flags & VM_NORESERVE)) - return 0; - - return security_vm_enough_memory_mm(current->mm, - pages * VM_ACCT(PAGE_SIZE)); -} - -static inline void shmem_unacct_blocks(unsigned long flags, long pages) -{ - if (flags & VM_NORESERVE) - vm_unacct_memory(pages * VM_ACCT(PAGE_SIZE)); -} - -static const struct super_operations shmem_ops; -static const struct address_space_operations shmem_aops; -static const struct file_operations shmem_file_operations; -static const struct inode_operations shmem_inode_operations; -static const struct inode_operations shmem_dir_inode_operations; -static const struct inode_operations shmem_special_inode_operations; -static const struct vm_operations_struct shmem_vm_ops; -static struct file_system_type shmem_fs_type; - -static LIST_HEAD(shmem_swaplist); -static DEFINE_MUTEX(shmem_swaplist_mutex); - -static int shmem_reserve_inode(struct super_block *sb) -{ - struct shmem_sb_info *sbinfo = SHMEM_SB(sb); - if (sbinfo->max_inodes) { - spin_lock(&sbinfo->stat_lock); - if (!sbinfo->free_inodes) { - spin_unlock(&sbinfo->stat_lock); - return -ENOSPC; - } - sbinfo->free_inodes--; - spin_unlock(&sbinfo->stat_lock); - } - return 0; -} - -static void shmem_free_inode(struct super_block *sb) -{ - struct shmem_sb_info *sbinfo = SHMEM_SB(sb); - if (sbinfo->max_inodes) { - spin_lock(&sbinfo->stat_lock); - sbinfo->free_inodes++; - spin_unlock(&sbinfo->stat_lock); - } -} - -/** - * shmem_recalc_inode - recalculate the block usage of an inode - * @inode: inode to recalc - * - * We have to calculate the free blocks since the mm can drop - * undirtied hole pages behind our back. - * - * But normally info->alloced == inode->i_mapping->nrpages + info->swapped - * So mm freed is info->alloced - (inode->i_mapping->nrpages + info->swapped) - * - * It has to be called with the spinlock held. - */ -static void shmem_recalc_inode(struct inode *inode) -{ - struct shmem_inode_info *info = SHMEM_I(inode); - long freed; - - freed = info->alloced - info->swapped - inode->i_mapping->nrpages; - if (freed > 0) { - struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); - if (sbinfo->max_blocks) - percpu_counter_add(&sbinfo->used_blocks, -freed); - info->alloced -= freed; - inode->i_blocks -= freed * BLOCKS_PER_PAGE; - shmem_unacct_blocks(info->flags, freed); - } -} - -bool shmem_charge(struct inode *inode, long pages) -{ - struct shmem_inode_info *info = SHMEM_I(inode); - struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); - unsigned long flags; - - if (shmem_acct_block(info->flags, pages)) - return false; - spin_lock_irqsave(&info->lock, flags); - info->alloced += pages; - inode->i_blocks += pages * BLOCKS_PER_PAGE; - shmem_recalc_inode(inode); - spin_unlock_irqrestore(&info->lock, flags); - inode->i_mapping->nrpages += pages; - - if (!sbinfo->max_blocks) - return true; - if (percpu_counter_compare(&sbinfo->used_blocks, - sbinfo->max_blocks - pages) > 0) { - inode->i_mapping->nrpages -= pages; - spin_lock_irqsave(&info->lock, flags); - info->alloced -= pages; - shmem_recalc_inode(inode); - spin_unlock_irqrestore(&info->lock, flags); - shmem_unacct_blocks(info->flags, pages); - return false; - } - percpu_counter_add(&sbinfo->used_blocks, pages); - return true; -} - -void shmem_uncharge(struct inode *inode, long pages) -{ - struct shmem_inode_info *info = SHMEM_I(inode); - struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); - unsigned long flags; - - spin_lock_irqsave(&info->lock, flags); - info->alloced -= pages; - inode->i_blocks -= pages * BLOCKS_PER_PAGE; - shmem_recalc_inode(inode); - spin_unlock_irqrestore(&info->lock, flags); - - if (sbinfo->max_blocks) - percpu_counter_sub(&sbinfo->used_blocks, pages); - shmem_unacct_blocks(info->flags, pages); -} - -/* - * Replace item expected in radix tree by a new item, while holding tree lock. - */ -static int shmem_radix_tree_replace(struct address_space *mapping, - pgoff_t index, void *expected, void *replacement) -{ - void **pslot; - void *item; - - VM_BUG_ON(!expected); - VM_BUG_ON(!replacement); - pslot = radix_tree_lookup_slot(&mapping->page_tree, index); - if (!pslot) - return -ENOENT; - item = radix_tree_deref_slot_protected(pslot, &mapping->tree_lock); - if (item != expected) - return -ENOENT; - radix_tree_replace_slot(pslot, replacement); - return 0; -} - -/* - * Sometimes, before we decide whether to proceed or to fail, we must check - * that an entry was not already brought back from swap by a racing thread. - * - * Checking page is not enough: by the time a SwapCache page is locked, it - * might be reused, and again be SwapCache, using the same swap as before. - */ -static bool shmem_confirm_swap(struct address_space *mapping, - pgoff_t index, swp_entry_t swap) -{ - void *item; - - rcu_read_lock(); - item = radix_tree_lookup(&mapping->page_tree, index); - rcu_read_unlock(); - return item == swp_to_radix_entry(swap); -} - -/* - * Definitions for "huge tmpfs": tmpfs mounted with the huge= option - * - * SHMEM_HUGE_NEVER: - * disables huge pages for the mount; - * SHMEM_HUGE_ALWAYS: - * enables huge pages for the mount; - * SHMEM_HUGE_WITHIN_SIZE: - * only allocate huge pages if the page will be fully within i_size, - * also respect fadvise()/madvise() hints; - * SHMEM_HUGE_ADVISE: - * only allocate huge pages if requested with fadvise()/madvise(); - */ - -#define SHMEM_HUGE_NEVER 0 -#define SHMEM_HUGE_ALWAYS 1 -#define SHMEM_HUGE_WITHIN_SIZE 2 -#define SHMEM_HUGE_ADVISE 3 - -/* - * Special values. - * Only can be set via /sys/kernel/mm/transparent_hugepage/shmem_enabled: - * - * SHMEM_HUGE_DENY: - * disables huge on shm_mnt and all mounts, for emergency use; - * SHMEM_HUGE_FORCE: - * enables huge on shm_mnt and all mounts, w/o needing option, for testing; - * - */ -#define SHMEM_HUGE_DENY (-1) -#define SHMEM_HUGE_FORCE (-2) - -#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE -/* ifdef here to avoid bloating shmem.o when not necessary */ - -int shmem_huge __read_mostly; - -static int shmem_parse_huge(const char *str) -{ - if (!strcmp(str, "never")) - return SHMEM_HUGE_NEVER; - if (!strcmp(str, "always")) - return SHMEM_HUGE_ALWAYS; - if (!strcmp(str, "within_size")) - return SHMEM_HUGE_WITHIN_SIZE; - if (!strcmp(str, "advise")) - return SHMEM_HUGE_ADVISE; - if (!strcmp(str, "deny")) - return SHMEM_HUGE_DENY; - if (!strcmp(str, "force")) - return SHMEM_HUGE_FORCE; - return -EINVAL; -} - -static const char *shmem_format_huge(int huge) -{ - switch (huge) { - case SHMEM_HUGE_NEVER: - return "never"; - case SHMEM_HUGE_ALWAYS: - return "always"; - case SHMEM_HUGE_WITHIN_SIZE: - return "within_size"; - case SHMEM_HUGE_ADVISE: - return "advise"; - case SHMEM_HUGE_DENY: - return "deny"; - case SHMEM_HUGE_FORCE: - return "force"; - default: - VM_BUG_ON(1); - return "bad_val"; - } -} - -static unsigned long shmem_unused_huge_shrink(struct shmem_sb_info *sbinfo, - struct shrink_control *sc, unsigned long nr_to_split) -{ - LIST_HEAD(list), *pos, *next; - struct inode *inode; - struct shmem_inode_info *info; - struct page *page; - unsigned long batch = sc ? sc->nr_to_scan : 128; - int removed = 0, split = 0; - - if (list_empty(&sbinfo->shrinklist)) - return SHRINK_STOP; - - spin_lock(&sbinfo->shrinklist_lock); - list_for_each_safe(pos, next, &sbinfo->shrinklist) { - info = list_entry(pos, struct shmem_inode_info, shrinklist); - - /* pin the inode */ - inode = igrab(&info->vfs_inode); - - /* inode is about to be evicted */ - if (!inode) { - list_del_init(&info->shrinklist); - removed++; - goto next; - } - - /* Check if there's anything to gain */ - if (round_up(inode->i_size, PAGE_SIZE) == - round_up(inode->i_size, HPAGE_PMD_SIZE)) { - list_del_init(&info->shrinklist); - removed++; - iput(inode); - goto next; - } - - list_move(&info->shrinklist, &list); -next: - if (!--batch) - break; - } - spin_unlock(&sbinfo->shrinklist_lock); - - list_for_each_safe(pos, next, &list) { - int ret; - - info = list_entry(pos, struct shmem_inode_info, shrinklist); - inode = &info->vfs_inode; - - if (nr_to_split && split >= nr_to_split) { - iput(inode); - continue; - } - - page = find_lock_page(inode->i_mapping, - (inode->i_size & HPAGE_PMD_MASK) >> PAGE_SHIFT); - if (!page) - goto drop; - - if (!PageTransHuge(page)) { - unlock_page(page); - put_page(page); - goto drop; - } - - ret = split_huge_page(page); - unlock_page(page); - put_page(page); - - if (ret) { - /* split failed: leave it on the list */ - iput(inode); - continue; - } - - split++; -drop: - list_del_init(&info->shrinklist); - removed++; - iput(inode); - } - - spin_lock(&sbinfo->shrinklist_lock); - list_splice_tail(&list, &sbinfo->shrinklist); - sbinfo->shrinklist_len -= removed; - spin_unlock(&sbinfo->shrinklist_lock); - - return split; -} - -static long shmem_unused_huge_scan(struct super_block *sb, - struct shrink_control *sc) -{ - struct shmem_sb_info *sbinfo = SHMEM_SB(sb); - - if (!READ_ONCE(sbinfo->shrinklist_len)) - return SHRINK_STOP; - - return shmem_unused_huge_shrink(sbinfo, sc, 0); -} - -static long shmem_unused_huge_count(struct super_block *sb, - struct shrink_control *sc) -{ - struct shmem_sb_info *sbinfo = SHMEM_SB(sb); - return READ_ONCE(sbinfo->shrinklist_len); -} -#else /* !CONFIG_TRANSPARENT_HUGE_PAGECACHE */ - -#define shmem_huge SHMEM_HUGE_DENY - -static unsigned long shmem_unused_huge_shrink(struct shmem_sb_info *sbinfo, - struct shrink_control *sc, unsigned long nr_to_split) -{ - return 0; -} -#endif /* CONFIG_TRANSPARENT_HUGE_PAGECACHE */ - -/* - * Like add_to_page_cache_locked, but error if expected item has gone. - */ -static int shmem_add_to_page_cache(struct page *page, - struct address_space *mapping, - pgoff_t index, void *expected) -{ - int error, nr = hpage_nr_pages(page); - - VM_BUG_ON_PAGE(PageTail(page), page); - VM_BUG_ON_PAGE(index != round_down(index, nr), page); - VM_BUG_ON_PAGE(!PageLocked(page), page); - VM_BUG_ON_PAGE(!PageSwapBacked(page), page); - VM_BUG_ON(expected && PageTransHuge(page)); - - page_ref_add(page, nr); - page->mapping = mapping; - page->index = index; - - spin_lock_irq(&mapping->tree_lock); - if (PageTransHuge(page)) { - void __rcu **results; - pgoff_t idx; - int i; - - error = 0; - if (radix_tree_gang_lookup_slot(&mapping->page_tree, - &results, &idx, index, 1) && - idx < index + HPAGE_PMD_NR) { - error = -EEXIST; - } - - if (!error) { - for (i = 0; i < HPAGE_PMD_NR; i++) { - error = radix_tree_insert(&mapping->page_tree, - index + i, page + i); - VM_BUG_ON(error); - } - count_vm_event(THP_FILE_ALLOC); - } - } else if (!expected) { - error = radix_tree_insert(&mapping->page_tree, index, page); - } else { - error = shmem_radix_tree_replace(mapping, index, expected, - page); - } - - if (!error) { - mapping->nrpages += nr; - if (PageTransHuge(page)) - __inc_node_page_state(page, NR_SHMEM_THPS); - __mod_node_page_state(page_pgdat(page), NR_FILE_PAGES, nr); - __mod_node_page_state(page_pgdat(page), NR_SHMEM, nr); - spin_unlock_irq(&mapping->tree_lock); - } else { - page->mapping = NULL; - spin_unlock_irq(&mapping->tree_lock); - page_ref_sub(page, nr); - } - return error; -} - -/* - * Like delete_from_page_cache, but substitutes swap for page. - */ -static void shmem_delete_from_page_cache(struct page *page, void *radswap) -{ - struct address_space *mapping = page->mapping; - int error; - - VM_BUG_ON_PAGE(PageCompound(page), page); - - spin_lock_irq(&mapping->tree_lock); - error = shmem_radix_tree_replace(mapping, page->index, page, radswap); - page->mapping = NULL; - mapping->nrpages--; - __dec_node_page_state(page, NR_FILE_PAGES); - __dec_node_page_state(page, NR_SHMEM); - spin_unlock_irq(&mapping->tree_lock); - put_page(page); - BUG_ON(error); -} - -/* - * Remove swap entry from radix tree, free the swap and its page cache. - */ -static int shmem_free_swap(struct address_space *mapping, - pgoff_t index, void *radswap) -{ - void *old; - - spin_lock_irq(&mapping->tree_lock); - old = radix_tree_delete_item(&mapping->page_tree, index, radswap); - spin_unlock_irq(&mapping->tree_lock); - if (old != radswap) - return -ENOENT; - free_swap_and_cache(radix_to_swp_entry(radswap)); - return 0; -} - -/* - * Determine (in bytes) how many of the shmem object's pages mapped by the - * given offsets are swapped out. - * - * This is safe to call without i_mutex or mapping->tree_lock thanks to RCU, - * as long as the inode doesn't go away and racy results are not a problem. - */ -unsigned long shmem_partial_swap_usage(struct address_space *mapping, - pgoff_t start, pgoff_t end) -{ - struct radix_tree_iter iter; - void **slot; - struct page *page; - unsigned long swapped = 0; - - rcu_read_lock(); - - radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) { - if (iter.index >= end) - break; - - page = radix_tree_deref_slot(slot); - - if (radix_tree_deref_retry(page)) { - slot = radix_tree_iter_retry(&iter); - continue; - } - - if (radix_tree_exceptional_entry(page)) - swapped++; - - if (need_resched()) { - cond_resched_rcu(); - slot = radix_tree_iter_next(&iter); - } - } - - rcu_read_unlock(); - - return swapped << PAGE_SHIFT; -} - -/* - * Determine (in bytes) how many of the shmem object's pages mapped by the - * given vma is swapped out. - * - * This is safe to call without i_mutex or mapping->tree_lock thanks to RCU, - * as long as the inode doesn't go away and racy results are not a problem. - */ -unsigned long shmem_swap_usage(struct vm_area_struct *vma) -{ - struct inode *inode = file_inode(vma->vm_file); - struct shmem_inode_info *info = SHMEM_I(inode); - struct address_space *mapping = inode->i_mapping; - unsigned long swapped; - - /* Be careful as we don't hold info->lock */ - swapped = READ_ONCE(info->swapped); - - /* - * The easier cases are when the shmem object has nothing in swap, or - * the vma maps it whole. Then we can simply use the stats that we - * already track. - */ - if (!swapped) - return 0; - - if (!vma->vm_pgoff && vma->vm_end - vma->vm_start >= inode->i_size) - return swapped << PAGE_SHIFT; - - /* Here comes the more involved part */ - return shmem_partial_swap_usage(mapping, - linear_page_index(vma, vma->vm_start), - linear_page_index(vma, vma->vm_end)); -} - -/* - * SysV IPC SHM_UNLOCK restore Unevictable pages to their evictable lists. - */ -void shmem_unlock_mapping(struct address_space *mapping) -{ - struct pagevec pvec; - pgoff_t indices[PAGEVEC_SIZE]; - pgoff_t index = 0; - - pagevec_init(&pvec, 0); - /* - * Minor point, but we might as well stop if someone else SHM_LOCKs it. - */ - while (!mapping_unevictable(mapping)) { - /* - * Avoid pagevec_lookup(): find_get_pages() returns 0 as if it - * has finished, if it hits a row of PAGEVEC_SIZE swap entries. - */ - pvec.nr = find_get_entries(mapping, index, - PAGEVEC_SIZE, pvec.pages, indices); - if (!pvec.nr) - break; - index = indices[pvec.nr - 1] + 1; - pagevec_remove_exceptionals(&pvec); - check_move_unevictable_pages(pvec.pages, pvec.nr); - pagevec_release(&pvec); - cond_resched(); - } -} - -/* - * Remove range of pages and swap entries from radix tree, and free them. - * If !unfalloc, truncate or punch hole; if unfalloc, undo failed fallocate. - */ -static void shmem_undo_range(struct inode *inode, loff_t lstart, loff_t lend, - bool unfalloc) -{ - struct address_space *mapping = inode->i_mapping; - struct shmem_inode_info *info = SHMEM_I(inode); - pgoff_t start = (lstart + PAGE_SIZE - 1) >> PAGE_SHIFT; - pgoff_t end = (lend + 1) >> PAGE_SHIFT; - unsigned int partial_start = lstart & (PAGE_SIZE - 1); - unsigned int partial_end = (lend + 1) & (PAGE_SIZE - 1); - struct pagevec pvec; - pgoff_t indices[PAGEVEC_SIZE]; - long nr_swaps_freed = 0; - pgoff_t index; - int i; - - if (lend == -1) - end = -1; /* unsigned, so actually very big */ - - pagevec_init(&pvec, 0); - index = start; - while (index < end) { - pvec.nr = find_get_entries(mapping, index, - min(end - index, (pgoff_t)PAGEVEC_SIZE), - pvec.pages, indices); - if (!pvec.nr) - break; - for (i = 0; i < pagevec_count(&pvec); i++) { - struct page *page = pvec.pages[i]; - - index = indices[i]; - if (index >= end) - break; - - if (radix_tree_exceptional_entry(page)) { - if (unfalloc) - continue; - nr_swaps_freed += !shmem_free_swap(mapping, - index, page); - continue; - } - - VM_BUG_ON_PAGE(page_to_pgoff(page) != index, page); - - if (!trylock_page(page)) - continue; - - if (PageTransTail(page)) { - /* Middle of THP: zero out the page */ - clear_highpage(page); - unlock_page(page); - continue; - } else if (PageTransHuge(page)) { - if (index == round_down(end, HPAGE_PMD_NR)) { - /* - * Range ends in the middle of THP: - * zero out the page - */ - clear_highpage(page); - unlock_page(page); - continue; - } - index += HPAGE_PMD_NR - 1; - i += HPAGE_PMD_NR - 1; - } - - if (!unfalloc || !PageUptodate(page)) { - VM_BUG_ON_PAGE(PageTail(page), page); - if (page_mapping(page) == mapping) { - VM_BUG_ON_PAGE(PageWriteback(page), page); - truncate_inode_page(mapping, page); - } - } - unlock_page(page); - } - pagevec_remove_exceptionals(&pvec); - pagevec_release(&pvec); - cond_resched(); - index++; - } - - if (partial_start) { - struct page *page = NULL; - shmem_getpage(inode, start - 1, &page, SGP_READ); - if (page) { - unsigned int top = PAGE_SIZE; - if (start > end) { - top = partial_end; - partial_end = 0; - } - zero_user_segment(page, partial_start, top); - set_page_dirty(page); - unlock_page(page); - put_page(page); - } - } - if (partial_end) { - struct page *page = NULL; - shmem_getpage(inode, end, &page, SGP_READ); - if (page) { - zero_user_segment(page, 0, partial_end); - set_page_dirty(page); - unlock_page(page); - put_page(page); - } - } - if (start >= end) - return; - - index = start; - while (index < end) { - cond_resched(); - - pvec.nr = find_get_entries(mapping, index, - min(end - index, (pgoff_t)PAGEVEC_SIZE), - pvec.pages, indices); - if (!pvec.nr) { - /* If all gone or hole-punch or unfalloc, we're done */ - if (index == start || end != -1) - break; - /* But if truncating, restart to make sure all gone */ - index = start; - continue; - } - for (i = 0; i < pagevec_count(&pvec); i++) { - struct page *page = pvec.pages[i]; - - index = indices[i]; - if (index >= end) - break; - - if (radix_tree_exceptional_entry(page)) { - if (unfalloc) - continue; - if (shmem_free_swap(mapping, index, page)) { - /* Swap was replaced by page: retry */ - index--; - break; - } - nr_swaps_freed++; - continue; - } - - lock_page(page); - - if (PageTransTail(page)) { - /* Middle of THP: zero out the page */ - clear_highpage(page); - unlock_page(page); - /* - * Partial thp truncate due 'start' in middle - * of THP: don't need to look on these pages - * again on !pvec.nr restart. - */ - if (index != round_down(end, HPAGE_PMD_NR)) - start++; - continue; - } else if (PageTransHuge(page)) { - if (index == round_down(end, HPAGE_PMD_NR)) { - /* - * Range ends in the middle of THP: - * zero out the page - */ - clear_highpage(page); - unlock_page(page); - continue; - } - index += HPAGE_PMD_NR - 1; - i += HPAGE_PMD_NR - 1; - } - - if (!unfalloc || !PageUptodate(page)) { - VM_BUG_ON_PAGE(PageTail(page), page); - if (page_mapping(page) == mapping) { - VM_BUG_ON_PAGE(PageWriteback(page), page); - truncate_inode_page(mapping, page); - } else { - /* Page was replaced by swap: retry */ - unlock_page(page); - index--; - break; - } - } - unlock_page(page); - } - pagevec_remove_exceptionals(&pvec); - pagevec_release(&pvec); - index++; - } - - spin_lock_irq(&info->lock); - info->swapped -= nr_swaps_freed; - shmem_recalc_inode(inode); - spin_unlock_irq(&info->lock); -} - -void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend) -{ - shmem_undo_range(inode, lstart, lend, false); - inode->i_ctime = inode->i_mtime = current_time(inode); -} -EXPORT_SYMBOL_GPL(shmem_truncate_range); - -static int shmem_getattr(struct vfsmount *mnt, struct dentry *dentry, - struct kstat *stat) -{ - struct inode *inode = dentry->d_inode; - struct shmem_inode_info *info = SHMEM_I(inode); - - if (info->alloced - info->swapped != inode->i_mapping->nrpages) { - spin_lock_irq(&info->lock); - shmem_recalc_inode(inode); - spin_unlock_irq(&info->lock); - } - generic_fillattr(inode, stat); - return 0; -} - -static int shmem_setattr(struct dentry *dentry, struct iattr *attr) -{ - struct inode *inode = d_inode(dentry); - struct shmem_inode_info *info = SHMEM_I(inode); - struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); - int error; - - error = setattr_prepare(dentry, attr); - if (error) - return error; - - if (S_ISREG(inode->i_mode) && (attr->ia_valid & ATTR_SIZE)) { - loff_t oldsize = inode->i_size; - loff_t newsize = attr->ia_size; - - /* protected by i_mutex */ - if ((newsize < oldsize && (info->seals & F_SEAL_SHRINK)) || - (newsize > oldsize && (info->seals & F_SEAL_GROW))) - return -EPERM; - - if (newsize != oldsize) { - error = shmem_reacct_size(SHMEM_I(inode)->flags, - oldsize, newsize); - if (error) - return error; - i_size_write(inode, newsize); - inode->i_ctime = inode->i_mtime = current_time(inode); - } - if (newsize <= oldsize) { - loff_t holebegin = round_up(newsize, PAGE_SIZE); - if (oldsize > holebegin) - unmap_mapping_range(inode->i_mapping, - holebegin, 0, 1); - if (info->alloced) - shmem_truncate_range(inode, - newsize, (loff_t)-1); - /* unmap again to remove racily COWed private pages */ - if (oldsize > holebegin) - unmap_mapping_range(inode->i_mapping, - holebegin, 0, 1); - - /* - * Part of the huge page can be beyond i_size: subject - * to shrink under memory pressure. - */ - if (IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE)) { - spin_lock(&sbinfo->shrinklist_lock); - if (list_empty(&info->shrinklist)) { - list_add_tail(&info->shrinklist, - &sbinfo->shrinklist); - sbinfo->shrinklist_len++; - } - spin_unlock(&sbinfo->shrinklist_lock); - } - } - } - - setattr_copy(inode, attr); - if (attr->ia_valid & ATTR_MODE) - error = posix_acl_chmod(inode, inode->i_mode); - return error; -} - -static void shmem_evict_inode(struct inode *inode) -{ - struct shmem_inode_info *info = SHMEM_I(inode); - struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); - - if (inode->i_mapping->a_ops == &shmem_aops) { - shmem_unacct_size(info->flags, inode->i_size); - inode->i_size = 0; - shmem_truncate_range(inode, 0, (loff_t)-1); - if (!list_empty(&info->shrinklist)) { - spin_lock(&sbinfo->shrinklist_lock); - if (!list_empty(&info->shrinklist)) { - list_del_init(&info->shrinklist); - sbinfo->shrinklist_len--; - } - spin_unlock(&sbinfo->shrinklist_lock); - } - if (!list_empty(&info->swaplist)) { - mutex_lock(&shmem_swaplist_mutex); - list_del_init(&info->swaplist); - mutex_unlock(&shmem_swaplist_mutex); - } - } - - simple_xattrs_free(&info->xattrs); - WARN_ON(inode->i_blocks); - shmem_free_inode(inode->i_sb); - clear_inode(inode); -} - -/* - * If swap found in inode, free it and move page from swapcache to filecache. - */ -static int shmem_unuse_inode(struct shmem_inode_info *info, - swp_entry_t swap, struct page **pagep) -{ - struct address_space *mapping = info->vfs_inode.i_mapping; - void *radswap; - pgoff_t index; - gfp_t gfp; - int error = 0; - - radswap = swp_to_radix_entry(swap); - index = radix_tree_locate_item(&mapping->page_tree, radswap); - if (index == -1) - return -EAGAIN; /* tell shmem_unuse we found nothing */ - - /* - * Move _head_ to start search for next from here. - * But be careful: shmem_evict_inode checks list_empty without taking - * mutex, and there's an instant in list_move_tail when info->swaplist - * would appear empty, if it were the only one on shmem_swaplist. - */ - if (shmem_swaplist.next != &info->swaplist) - list_move_tail(&shmem_swaplist, &info->swaplist); - - gfp = mapping_gfp_mask(mapping); - if (shmem_should_replace_page(*pagep, gfp)) { - mutex_unlock(&shmem_swaplist_mutex); - error = shmem_replace_page(pagep, gfp, info, index); - mutex_lock(&shmem_swaplist_mutex); - /* - * We needed to drop mutex to make that restrictive page - * allocation, but the inode might have been freed while we - * dropped it: although a racing shmem_evict_inode() cannot - * complete without emptying the radix_tree, our page lock - * on this swapcache page is not enough to prevent that - - * free_swap_and_cache() of our swap entry will only - * trylock_page(), removing swap from radix_tree whatever. - * - * We must not proceed to shmem_add_to_page_cache() if the - * inode has been freed, but of course we cannot rely on - * inode or mapping or info to check that. However, we can - * safely check if our swap entry is still in use (and here - * it can't have got reused for another page): if it's still - * in use, then the inode cannot have been freed yet, and we - * can safely proceed (if it's no longer in use, that tells - * nothing about the inode, but we don't need to unuse swap). - */ - if (!page_swapcount(*pagep)) - error = -ENOENT; - } - - /* - * We rely on shmem_swaplist_mutex, not only to protect the swaplist, - * but also to hold up shmem_evict_inode(): so inode cannot be freed - * beneath us (pagelock doesn't help until the page is in pagecache). - */ - if (!error) - error = shmem_add_to_page_cache(*pagep, mapping, index, - radswap); - if (error != -ENOMEM) { - /* - * Truncation and eviction use free_swap_and_cache(), which - * only does trylock page: if we raced, best clean up here. - */ - delete_from_swap_cache(*pagep); - set_page_dirty(*pagep); - if (!error) { - spin_lock_irq(&info->lock); - info->swapped--; - spin_unlock_irq(&info->lock); - swap_free(swap); - } - } - return error; -} - -/* - * Search through swapped inodes to find and replace swap by page. - */ -int shmem_unuse(swp_entry_t swap, struct page *page) -{ - struct list_head *this, *next; - struct shmem_inode_info *info; - struct mem_cgroup *memcg; - int error = 0; - - /* - * There's a faint possibility that swap page was replaced before - * caller locked it: caller will come back later with the right page. - */ - if (unlikely(!PageSwapCache(page) || page_private(page) != swap.val)) - goto out; - - /* - * Charge page using GFP_KERNEL while we can wait, before taking - * the shmem_swaplist_mutex which might hold up shmem_writepage(). - * Charged back to the user (not to caller) when swap account is used. - */ - error = mem_cgroup_try_charge(page, current->mm, GFP_KERNEL, &memcg, - false); - if (error) - goto out; - /* No radix_tree_preload: swap entry keeps a place for page in tree */ - error = -EAGAIN; - - mutex_lock(&shmem_swaplist_mutex); - list_for_each_safe(this, next, &shmem_swaplist) { - info = list_entry(this, struct shmem_inode_info, swaplist); - if (info->swapped) - error = shmem_unuse_inode(info, swap, &page); - else - list_del_init(&info->swaplist); - cond_resched(); - if (error != -EAGAIN) - break; - /* found nothing in this: move on to search the next */ - } - mutex_unlock(&shmem_swaplist_mutex); - - if (error) { - if (error != -ENOMEM) - error = 0; - mem_cgroup_cancel_charge(page, memcg, false); - } else - mem_cgroup_commit_charge(page, memcg, true, false); -out: - unlock_page(page); - put_page(page); - return error; -} - -/* - * Move the page from the page cache to the swap cache. - */ -static int shmem_writepage(struct page *page, struct writeback_control *wbc) -{ - struct shmem_inode_info *info; - struct address_space *mapping; - struct inode *inode; - swp_entry_t swap; - pgoff_t index; - - VM_BUG_ON_PAGE(PageCompound(page), page); - BUG_ON(!PageLocked(page)); - mapping = page->mapping; - index = page->index; - inode = mapping->host; - info = SHMEM_I(inode); - if (info->flags & VM_LOCKED) - goto redirty; - if (!total_swap_pages) - goto redirty; - - /* - * Our capabilities prevent regular writeback or sync from ever calling - * shmem_writepage; but a stacking filesystem might use ->writepage of - * its underlying filesystem, in which case tmpfs should write out to - * swap only in response to memory pressure, and not for the writeback - * threads or sync. - */ - if (!wbc->for_reclaim) { - WARN_ON_ONCE(1); /* Still happens? Tell us about it! */ - goto redirty; - } - - /* - * This is somewhat ridiculous, but without plumbing a SWAP_MAP_FALLOC - * value into swapfile.c, the only way we can correctly account for a - * fallocated page arriving here is now to initialize it and write it. - * - * That's okay for a page already fallocated earlier, but if we have - * not yet completed the fallocation, then (a) we want to keep track - * of this page in case we have to undo it, and (b) it may not be a - * good idea to continue anyway, once we're pushing into swap. So - * reactivate the page, and let shmem_fallocate() quit when too many. - */ - if (!PageUptodate(page)) { - if (inode->i_private) { - struct shmem_falloc *shmem_falloc; - spin_lock(&inode->i_lock); - shmem_falloc = inode->i_private; - if (shmem_falloc && - !shmem_falloc->waitq && - index >= shmem_falloc->start && - index < shmem_falloc->next) - shmem_falloc->nr_unswapped++; - else - shmem_falloc = NULL; - spin_unlock(&inode->i_lock); - if (shmem_falloc) - goto redirty; - } - clear_highpage(page); - flush_dcache_page(page); - SetPageUptodate(page); - } - - swap = get_swap_page(); - if (!swap.val) - goto redirty; - - if (mem_cgroup_try_charge_swap(page, swap)) - goto free_swap; - - /* - * Add inode to shmem_unuse()'s list of swapped-out inodes, - * if it's not already there. Do it now before the page is - * moved to swap cache, when its pagelock no longer protects - * the inode from eviction. But don't unlock the mutex until - * we've incremented swapped, because shmem_unuse_inode() will - * prune a !swapped inode from the swaplist under this mutex. - */ - mutex_lock(&shmem_swaplist_mutex); - if (list_empty(&info->swaplist)) - list_add_tail(&info->swaplist, &shmem_swaplist); - - if (add_to_swap_cache(page, swap, GFP_ATOMIC) == 0) { - spin_lock_irq(&info->lock); - shmem_recalc_inode(inode); - info->swapped++; - spin_unlock_irq(&info->lock); - - swap_shmem_alloc(swap); - shmem_delete_from_page_cache(page, swp_to_radix_entry(swap)); - - mutex_unlock(&shmem_swaplist_mutex); - BUG_ON(page_mapped(page)); - swap_writepage(page, wbc); - return 0; - } - - mutex_unlock(&shmem_swaplist_mutex); -free_swap: - swapcache_free(swap); -redirty: - set_page_dirty(page); - if (wbc->for_reclaim) - return AOP_WRITEPAGE_ACTIVATE; /* Return with page locked */ - unlock_page(page); - return 0; -} - -#if defined(CONFIG_NUMA) && defined(CONFIG_TMPFS) -static void shmem_show_mpol(struct seq_file *seq, struct mempolicy *mpol) -{ - char buffer[64]; - - if (!mpol || mpol->mode == MPOL_DEFAULT) - return; /* show nothing */ - - mpol_to_str(buffer, sizeof(buffer), mpol); - - seq_printf(seq, ",mpol=%s", buffer); -} - -static struct mempolicy *shmem_get_sbmpol(struct shmem_sb_info *sbinfo) -{ - struct mempolicy *mpol = NULL; - if (sbinfo->mpol) { - spin_lock(&sbinfo->stat_lock); /* prevent replace/use races */ - mpol = sbinfo->mpol; - mpol_get(mpol); - spin_unlock(&sbinfo->stat_lock); - } - return mpol; -} -#else /* !CONFIG_NUMA || !CONFIG_TMPFS */ -static inline void shmem_show_mpol(struct seq_file *seq, struct mempolicy *mpol) -{ -} -static inline struct mempolicy *shmem_get_sbmpol(struct shmem_sb_info *sbinfo) -{ - return NULL; -} -#endif /* CONFIG_NUMA && CONFIG_TMPFS */ -#ifndef CONFIG_NUMA -#define vm_policy vm_private_data -#endif - -static void shmem_pseudo_vma_init(struct vm_area_struct *vma, - struct shmem_inode_info *info, pgoff_t index) -{ - /* Create a pseudo vma that just contains the policy */ - vma->vm_start = 0; - /* Bias interleave by inode number to distribute better across nodes */ - vma->vm_pgoff = index + info->vfs_inode.i_ino; - vma->vm_ops = NULL; - vma->vm_policy = mpol_shared_policy_lookup(&info->policy, index); -} - -static void shmem_pseudo_vma_destroy(struct vm_area_struct *vma) -{ - /* Drop reference taken by mpol_shared_policy_lookup() */ - mpol_cond_put(vma->vm_policy); -} - -static struct page *shmem_swapin(swp_entry_t swap, gfp_t gfp, - struct shmem_inode_info *info, pgoff_t index) -{ - struct vm_area_struct pvma; - struct page *page; - - shmem_pseudo_vma_init(&pvma, info, index); - page = swapin_readahead(swap, gfp, &pvma, 0); - shmem_pseudo_vma_destroy(&pvma); - - return page; -} - -static struct page *shmem_alloc_hugepage(gfp_t gfp, - struct shmem_inode_info *info, pgoff_t index) -{ - struct vm_area_struct pvma; - struct inode *inode = &info->vfs_inode; - struct address_space *mapping = inode->i_mapping; - pgoff_t idx, hindex; - void __rcu **results; - struct page *page; - - if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE)) - return NULL; - - hindex = round_down(index, HPAGE_PMD_NR); - rcu_read_lock(); - if (radix_tree_gang_lookup_slot(&mapping->page_tree, &results, &idx, - hindex, 1) && idx < hindex + HPAGE_PMD_NR) { - rcu_read_unlock(); - return NULL; - } - rcu_read_unlock(); - - shmem_pseudo_vma_init(&pvma, info, hindex); - page = alloc_pages_vma(gfp | __GFP_COMP | __GFP_NORETRY | __GFP_NOWARN, - HPAGE_PMD_ORDER, &pvma, 0, numa_node_id(), true); - shmem_pseudo_vma_destroy(&pvma); - if (page) - prep_transhuge_page(page); - return page; -} - -static struct page *shmem_alloc_page(gfp_t gfp, - struct shmem_inode_info *info, pgoff_t index) -{ - struct vm_area_struct pvma; - struct page *page; - - shmem_pseudo_vma_init(&pvma, info, index); - page = alloc_page_vma(gfp, &pvma, 0); - shmem_pseudo_vma_destroy(&pvma); - - return page; -} - -static struct page *shmem_alloc_and_acct_page(gfp_t gfp, - struct shmem_inode_info *info, struct shmem_sb_info *sbinfo, - pgoff_t index, bool huge) -{ - struct page *page; - int nr; - int err = -ENOSPC; - - if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE)) - huge = false; - nr = huge ? HPAGE_PMD_NR : 1; - - if (shmem_acct_block(info->flags, nr)) - goto failed; - if (sbinfo->max_blocks) { - if (percpu_counter_compare(&sbinfo->used_blocks, - sbinfo->max_blocks - nr) > 0) - goto unacct; - percpu_counter_add(&sbinfo->used_blocks, nr); - } - - if (huge) - page = shmem_alloc_hugepage(gfp, info, index); - else - page = shmem_alloc_page(gfp, info, index); - if (page) { - __SetPageLocked(page); - __SetPageSwapBacked(page); - return page; - } - - err = -ENOMEM; - if (sbinfo->max_blocks) - percpu_counter_add(&sbinfo->used_blocks, -nr); -unacct: - shmem_unacct_blocks(info->flags, nr); -failed: - return ERR_PTR(err); -} - -/* - * When a page is moved from swapcache to shmem filecache (either by the - * usual swapin of shmem_getpage_gfp(), or by the less common swapoff of - * shmem_unuse_inode()), it may have been read in earlier from swap, in - * ignorance of the mapping it belongs to. If that mapping has special - * constraints (like the gma500 GEM driver, which requires RAM below 4GB), - * we may need to copy to a suitable page before moving to filecache. - * - * In a future release, this may well be extended to respect cpuset and - * NUMA mempolicy, and applied also to anonymous pages in do_swap_page(); - * but for now it is a simple matter of zone. - */ -static bool shmem_should_replace_page(struct page *page, gfp_t gfp) -{ - return page_zonenum(page) > gfp_zone(gfp); -} - -static int shmem_replace_page(struct page **pagep, gfp_t gfp, - struct shmem_inode_info *info, pgoff_t index) -{ - struct page *oldpage, *newpage; - struct address_space *swap_mapping; - pgoff_t swap_index; - int error; - - oldpage = *pagep; - swap_index = page_private(oldpage); - swap_mapping = page_mapping(oldpage); - - /* - * We have arrived here because our zones are constrained, so don't - * limit chance of success by further cpuset and node constraints. - */ - gfp &= ~GFP_CONSTRAINT_MASK; - newpage = shmem_alloc_page(gfp, info, index); - if (!newpage) - return -ENOMEM; - - get_page(newpage); - copy_highpage(newpage, oldpage); - flush_dcache_page(newpage); - - __SetPageLocked(newpage); - __SetPageSwapBacked(newpage); - SetPageUptodate(newpage); - set_page_private(newpage, swap_index); - SetPageSwapCache(newpage); - - /* - * Our caller will very soon move newpage out of swapcache, but it's - * a nice clean interface for us to replace oldpage by newpage there. - */ - spin_lock_irq(&swap_mapping->tree_lock); - error = shmem_radix_tree_replace(swap_mapping, swap_index, oldpage, - newpage); - if (!error) { - __inc_node_page_state(newpage, NR_FILE_PAGES); - __dec_node_page_state(oldpage, NR_FILE_PAGES); - } - spin_unlock_irq(&swap_mapping->tree_lock); - - if (unlikely(error)) { - /* - * Is this possible? I think not, now that our callers check - * both PageSwapCache and page_private after getting page lock; - * but be defensive. Reverse old to newpage for clear and free. - */ - oldpage = newpage; - } else { - mem_cgroup_migrate(oldpage, newpage); - lru_cache_add_anon(newpage); - *pagep = newpage; - } - - ClearPageSwapCache(oldpage); - set_page_private(oldpage, 0); - - unlock_page(oldpage); - put_page(oldpage); - put_page(oldpage); - return error; -} - -/* - * shmem_getpage_gfp - find page in cache, or get from swap, or allocate - * - * If we allocate a new one we do not mark it dirty. That's up to the - * vm. If we swap it in we mark it dirty since we also free the swap - * entry since a page cannot live in both the swap and page cache. - * - * fault_mm and fault_type are only supplied by shmem_fault: - * otherwise they are NULL. - */ -static int shmem_getpage_gfp(struct inode *inode, pgoff_t index, - struct page **pagep, enum sgp_type sgp, gfp_t gfp, - struct mm_struct *fault_mm, int *fault_type) -{ - struct address_space *mapping = inode->i_mapping; - struct shmem_inode_info *info; - struct shmem_sb_info *sbinfo; - struct mm_struct *charge_mm; - struct mem_cgroup *memcg; - struct page *page; - swp_entry_t swap; - enum sgp_type sgp_huge = sgp; - pgoff_t hindex = index; - int error; - int once = 0; - int alloced = 0; - - if (index > (MAX_LFS_FILESIZE >> PAGE_SHIFT)) - return -EFBIG; - if (sgp == SGP_NOHUGE || sgp == SGP_HUGE) - sgp = SGP_CACHE; -repeat: - swap.val = 0; - page = find_lock_entry(mapping, index); - if (radix_tree_exceptional_entry(page)) { - swap = radix_to_swp_entry(page); - page = NULL; - } - - if (sgp <= SGP_CACHE && - ((loff_t)index << PAGE_SHIFT) >= i_size_read(inode)) { - error = -EINVAL; - goto unlock; - } - - if (page && sgp == SGP_WRITE) - mark_page_accessed(page); - - /* fallocated page? */ - if (page && !PageUptodate(page)) { - if (sgp != SGP_READ) - goto clear; - unlock_page(page); - put_page(page); - page = NULL; - } - if (page || (sgp == SGP_READ && !swap.val)) { - *pagep = page; - return 0; - } - - /* - * Fast cache lookup did not find it: - * bring it back from swap or allocate. - */ - info = SHMEM_I(inode); - sbinfo = SHMEM_SB(inode->i_sb); - charge_mm = fault_mm ? : current->mm; - - if (swap.val) { - /* Look it up and read it in.. */ - page = lookup_swap_cache(swap); - if (!page) { - /* Or update major stats only when swapin succeeds?? */ - if (fault_type) { - *fault_type |= VM_FAULT_MAJOR; - count_vm_event(PGMAJFAULT); - mem_cgroup_count_vm_event(fault_mm, PGMAJFAULT); - } - /* Here we actually start the io */ - page = shmem_swapin(swap, gfp, info, index); - if (!page) { - error = -ENOMEM; - goto failed; - } - } - - /* We have to do this with page locked to prevent races */ - lock_page(page); - if (!PageSwapCache(page) || page_private(page) != swap.val || - !shmem_confirm_swap(mapping, index, swap)) { - error = -EEXIST; /* try again */ - goto unlock; - } - if (!PageUptodate(page)) { - error = -EIO; - goto failed; - } - wait_on_page_writeback(page); - - if (shmem_should_replace_page(page, gfp)) { - error = shmem_replace_page(&page, gfp, info, index); - if (error) - goto failed; - } - - error = mem_cgroup_try_charge(page, charge_mm, gfp, &memcg, - false); - if (!error) { - error = shmem_add_to_page_cache(page, mapping, index, - swp_to_radix_entry(swap)); - /* - * We already confirmed swap under page lock, and make - * no memory allocation here, so usually no possibility - * of error; but free_swap_and_cache() only trylocks a - * page, so it is just possible that the entry has been - * truncated or holepunched since swap was confirmed. - * shmem_undo_range() will have done some of the - * unaccounting, now delete_from_swap_cache() will do - * the rest. - * Reset swap.val? No, leave it so "failed" goes back to - * "repeat": reading a hole and writing should succeed. - */ - if (error) { - mem_cgroup_cancel_charge(page, memcg, false); - delete_from_swap_cache(page); - } - } - if (error) - goto failed; - - mem_cgroup_commit_charge(page, memcg, true, false); - - spin_lock_irq(&info->lock); - info->swapped--; - shmem_recalc_inode(inode); - spin_unlock_irq(&info->lock); - - if (sgp == SGP_WRITE) - mark_page_accessed(page); - - delete_from_swap_cache(page); - set_page_dirty(page); - swap_free(swap); - - } else { - /* shmem_symlink() */ - if (mapping->a_ops != &shmem_aops) - goto alloc_nohuge; - if (shmem_huge == SHMEM_HUGE_DENY || sgp_huge == SGP_NOHUGE) - goto alloc_nohuge; - if (shmem_huge == SHMEM_HUGE_FORCE) - goto alloc_huge; - switch (sbinfo->huge) { - loff_t i_size; - pgoff_t off; - case SHMEM_HUGE_NEVER: - goto alloc_nohuge; - case SHMEM_HUGE_WITHIN_SIZE: - off = round_up(index, HPAGE_PMD_NR); - i_size = round_up(i_size_read(inode), PAGE_SIZE); - if (i_size >= HPAGE_PMD_SIZE && - i_size >> PAGE_SHIFT >= off) - goto alloc_huge; - /* fallthrough */ - case SHMEM_HUGE_ADVISE: - if (sgp_huge == SGP_HUGE) - goto alloc_huge; - /* TODO: implement fadvise() hints */ - goto alloc_nohuge; - } - -alloc_huge: - page = shmem_alloc_and_acct_page(gfp, info, sbinfo, - index, true); - if (IS_ERR(page)) { -alloc_nohuge: page = shmem_alloc_and_acct_page(gfp, info, sbinfo, - index, false); - } - if (IS_ERR(page)) { - int retry = 5; - error = PTR_ERR(page); - page = NULL; - if (error != -ENOSPC) - goto failed; - /* - * Try to reclaim some spece by splitting a huge page - * beyond i_size on the filesystem. - */ - while (retry--) { - int ret; - ret = shmem_unused_huge_shrink(sbinfo, NULL, 1); - if (ret == SHRINK_STOP) - break; - if (ret) - goto alloc_nohuge; - } - goto failed; - } - - if (PageTransHuge(page)) - hindex = round_down(index, HPAGE_PMD_NR); - else - hindex = index; - - if (sgp == SGP_WRITE) - __SetPageReferenced(page); - - error = mem_cgroup_try_charge(page, charge_mm, gfp, &memcg, - PageTransHuge(page)); - if (error) - goto unacct; - error = radix_tree_maybe_preload_order(gfp & GFP_RECLAIM_MASK, - compound_order(page)); - if (!error) { - error = shmem_add_to_page_cache(page, mapping, hindex, - NULL); - radix_tree_preload_end(); - } - if (error) { - mem_cgroup_cancel_charge(page, memcg, - PageTransHuge(page)); - goto unacct; - } - mem_cgroup_commit_charge(page, memcg, false, - PageTransHuge(page)); - lru_cache_add_anon(page); - - spin_lock_irq(&info->lock); - info->alloced += 1 << compound_order(page); - inode->i_blocks += BLOCKS_PER_PAGE << compound_order(page); - shmem_recalc_inode(inode); - spin_unlock_irq(&info->lock); - alloced = true; - - if (PageTransHuge(page) && - DIV_ROUND_UP(i_size_read(inode), PAGE_SIZE) < - hindex + HPAGE_PMD_NR - 1) { - /* - * Part of the huge page is beyond i_size: subject - * to shrink under memory pressure. - */ - spin_lock(&sbinfo->shrinklist_lock); - if (list_empty(&info->shrinklist)) { - list_add_tail(&info->shrinklist, - &sbinfo->shrinklist); - sbinfo->shrinklist_len++; - } - spin_unlock(&sbinfo->shrinklist_lock); - } - - /* - * Let SGP_FALLOC use the SGP_WRITE optimization on a new page. - */ - if (sgp == SGP_FALLOC) - sgp = SGP_WRITE; -clear: - /* - * Let SGP_WRITE caller clear ends if write does not fill page; - * but SGP_FALLOC on a page fallocated earlier must initialize - * it now, lest undo on failure cancel our earlier guarantee. - */ - if (sgp != SGP_WRITE && !PageUptodate(page)) { - struct page *head = compound_head(page); - int i; - - for (i = 0; i < (1 << compound_order(head)); i++) { - clear_highpage(head + i); - flush_dcache_page(head + i); - } - SetPageUptodate(head); - } - } - - /* Perhaps the file has been truncated since we checked */ - if (sgp <= SGP_CACHE && - ((loff_t)index << PAGE_SHIFT) >= i_size_read(inode)) { - if (alloced) { - ClearPageDirty(page); - delete_from_page_cache(page); - spin_lock_irq(&info->lock); - shmem_recalc_inode(inode); - spin_unlock_irq(&info->lock); - } - error = -EINVAL; - goto unlock; - } - *pagep = page + index - hindex; - return 0; - - /* - * Error recovery. - */ -unacct: - if (sbinfo->max_blocks) - percpu_counter_sub(&sbinfo->used_blocks, - 1 << compound_order(page)); - shmem_unacct_blocks(info->flags, 1 << compound_order(page)); - - if (PageTransHuge(page)) { - unlock_page(page); - put_page(page); - goto alloc_nohuge; - } -failed: - if (swap.val && !shmem_confirm_swap(mapping, index, swap)) - error = -EEXIST; -unlock: - if (page) { - unlock_page(page); - put_page(page); - } - if (error == -ENOSPC && !once++) { - info = SHMEM_I(inode); - spin_lock_irq(&info->lock); - shmem_recalc_inode(inode); - spin_unlock_irq(&info->lock); - goto repeat; - } - if (error == -EEXIST) /* from above or from radix_tree_insert */ - goto repeat; - return error; -} - -/* - * This is like autoremove_wake_function, but it removes the wait queue - * entry unconditionally - even if something else had already woken the - * target. - */ -static int synchronous_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key) -{ - int ret = default_wake_function(wait, mode, sync, key); - list_del_init(&wait->task_list); - return ret; -} - -static int shmem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) -{ - struct inode *inode = file_inode(vma->vm_file); - gfp_t gfp = mapping_gfp_mask(inode->i_mapping); - enum sgp_type sgp; - int error; - int ret = VM_FAULT_LOCKED; - - /* - * Trinity finds that probing a hole which tmpfs is punching can - * prevent the hole-punch from ever completing: which in turn - * locks writers out with its hold on i_mutex. So refrain from - * faulting pages into the hole while it's being punched. Although - * shmem_undo_range() does remove the additions, it may be unable to - * keep up, as each new page needs its own unmap_mapping_range() call, - * and the i_mmap tree grows ever slower to scan if new vmas are added. - * - * It does not matter if we sometimes reach this check just before the - * hole-punch begins, so that one fault then races with the punch: - * we just need to make racing faults a rare case. - * - * The implementation below would be much simpler if we just used a - * standard mutex or completion: but we cannot take i_mutex in fault, - * and bloating every shmem inode for this unlikely case would be sad. - */ - if (unlikely(inode->i_private)) { - struct shmem_falloc *shmem_falloc; - - spin_lock(&inode->i_lock); - shmem_falloc = inode->i_private; - if (shmem_falloc && - shmem_falloc->waitq && - vmf->pgoff >= shmem_falloc->start && - vmf->pgoff < shmem_falloc->next) { - wait_queue_head_t *shmem_falloc_waitq; - DEFINE_WAIT_FUNC(shmem_fault_wait, synchronous_wake_function); - - ret = VM_FAULT_NOPAGE; - if ((vmf->flags & FAULT_FLAG_ALLOW_RETRY) && - !(vmf->flags & FAULT_FLAG_RETRY_NOWAIT)) { - /* It's polite to up mmap_sem if we can */ - up_read(&vma->vm_mm->mmap_sem); - ret = VM_FAULT_RETRY; - } - - shmem_falloc_waitq = shmem_falloc->waitq; - prepare_to_wait(shmem_falloc_waitq, &shmem_fault_wait, - TASK_UNINTERRUPTIBLE); - spin_unlock(&inode->i_lock); - schedule(); - - /* - * shmem_falloc_waitq points into the shmem_fallocate() - * stack of the hole-punching task: shmem_falloc_waitq - * is usually invalid by the time we reach here, but - * finish_wait() does not dereference it in that case; - * though i_lock needed lest racing with wake_up_all(). - */ - spin_lock(&inode->i_lock); - finish_wait(shmem_falloc_waitq, &shmem_fault_wait); - spin_unlock(&inode->i_lock); - return ret; - } - spin_unlock(&inode->i_lock); - } - - sgp = SGP_CACHE; - if (vma->vm_flags & VM_HUGEPAGE) - sgp = SGP_HUGE; - else if (vma->vm_flags & VM_NOHUGEPAGE) - sgp = SGP_NOHUGE; - - error = shmem_getpage_gfp(inode, vmf->pgoff, &vmf->page, sgp, - gfp, vma->vm_mm, &ret); - if (error) - return ((error == -ENOMEM) ? VM_FAULT_OOM : VM_FAULT_SIGBUS); - return ret; -} - -unsigned long shmem_get_unmapped_area(struct file *file, - unsigned long uaddr, unsigned long len, - unsigned long pgoff, unsigned long flags) -{ - unsigned long (*get_area)(struct file *, - unsigned long, unsigned long, unsigned long, unsigned long); - unsigned long addr; - unsigned long offset; - unsigned long inflated_len; - unsigned long inflated_addr; - unsigned long inflated_offset; - - if (len > TASK_SIZE) - return -ENOMEM; - - get_area = current->mm->get_unmapped_area; - addr = get_area(file, uaddr, len, pgoff, flags); - - if (!IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE)) - return addr; - if (IS_ERR_VALUE(addr)) - return addr; - if (addr & ~PAGE_MASK) - return addr; - if (addr > TASK_SIZE - len) - return addr; - - if (shmem_huge == SHMEM_HUGE_DENY) - return addr; - if (len < HPAGE_PMD_SIZE) - return addr; - if (flags & MAP_FIXED) - return addr; - /* - * Our priority is to support MAP_SHARED mapped hugely; - * and support MAP_PRIVATE mapped hugely too, until it is COWed. - * But if caller specified an address hint, respect that as before. - */ - if (uaddr) - return addr; - - if (shmem_huge != SHMEM_HUGE_FORCE) { - struct super_block *sb; - - if (file) { - VM_BUG_ON(file->f_op != &shmem_file_operations); - sb = file_inode(file)->i_sb; - } else { - /* - * Called directly from mm/mmap.c, or drivers/char/mem.c - * for "/dev/zero", to create a shared anonymous object. - */ - if (IS_ERR(shm_mnt)) - return addr; - sb = shm_mnt->mnt_sb; - } - if (SHMEM_SB(sb)->huge == SHMEM_HUGE_NEVER) - return addr; - } - - offset = (pgoff << PAGE_SHIFT) & (HPAGE_PMD_SIZE-1); - if (offset && offset + len < 2 * HPAGE_PMD_SIZE) - return addr; - if ((addr & (HPAGE_PMD_SIZE-1)) == offset) - return addr; - - inflated_len = len + HPAGE_PMD_SIZE - PAGE_SIZE; - if (inflated_len > TASK_SIZE) - return addr; - if (inflated_len < len) - return addr; - - inflated_addr = get_area(NULL, 0, inflated_len, 0, flags); - if (IS_ERR_VALUE(inflated_addr)) - return addr; - if (inflated_addr & ~PAGE_MASK) - return addr; - - inflated_offset = inflated_addr & (HPAGE_PMD_SIZE-1); - inflated_addr += offset - inflated_offset; - if (inflated_offset > offset) - inflated_addr += HPAGE_PMD_SIZE; - - if (inflated_addr > TASK_SIZE - len) - return addr; - return inflated_addr; -} - -#ifdef CONFIG_NUMA -static int shmem_set_policy(struct vm_area_struct *vma, struct mempolicy *mpol) -{ - struct inode *inode = file_inode(vma->vm_file); - return mpol_set_shared_policy(&SHMEM_I(inode)->policy, vma, mpol); -} - -static struct mempolicy *shmem_get_policy(struct vm_area_struct *vma, - unsigned long addr) -{ - struct inode *inode = file_inode(vma->vm_file); - pgoff_t index; - - index = ((addr - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff; - return mpol_shared_policy_lookup(&SHMEM_I(inode)->policy, index); -} -#endif - -int shmem_lock(struct file *file, int lock, struct user_struct *user) -{ - struct inode *inode = file_inode(file); - struct shmem_inode_info *info = SHMEM_I(inode); - int retval = -ENOMEM; - - spin_lock_irq(&info->lock); - if (lock && !(info->flags & VM_LOCKED)) { - if (!user_shm_lock(inode->i_size, user)) - goto out_nomem; - info->flags |= VM_LOCKED; - mapping_set_unevictable(file->f_mapping); - } - if (!lock && (info->flags & VM_LOCKED) && user) { - user_shm_unlock(inode->i_size, user); - info->flags &= ~VM_LOCKED; - mapping_clear_unevictable(file->f_mapping); - } - retval = 0; - -out_nomem: - spin_unlock_irq(&info->lock); - return retval; -} - -static int shmem_mmap(struct file *file, struct vm_area_struct *vma) -{ - file_accessed(file); - vma->vm_ops = &shmem_vm_ops; - if (IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE) && - ((vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK) < - (vma->vm_end & HPAGE_PMD_MASK)) { - khugepaged_enter(vma, vma->vm_flags); - } - return 0; -} - -static struct inode *shmem_get_inode(struct super_block *sb, const struct inode *dir, - umode_t mode, dev_t dev, unsigned long flags) -{ - struct inode *inode; - struct shmem_inode_info *info; - struct shmem_sb_info *sbinfo = SHMEM_SB(sb); - - if (shmem_reserve_inode(sb)) - return NULL; - - inode = new_inode(sb); - if (inode) { - inode->i_ino = get_next_ino(); - inode_init_owner(inode, dir, mode); - inode->i_blocks = 0; - inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode); - inode->i_generation = get_seconds(); - info = SHMEM_I(inode); - memset(info, 0, (char *)inode - (char *)info); - spin_lock_init(&info->lock); - info->seals = F_SEAL_SEAL; - info->flags = flags & VM_NORESERVE; - INIT_LIST_HEAD(&info->shrinklist); - INIT_LIST_HEAD(&info->swaplist); - simple_xattrs_init(&info->xattrs); - cache_no_acl(inode); - - switch (mode & S_IFMT) { - default: - inode->i_op = &shmem_special_inode_operations; - init_special_inode(inode, mode, dev); - break; - case S_IFREG: - inode->i_mapping->a_ops = &shmem_aops; - inode->i_op = &shmem_inode_operations; - inode->i_fop = &shmem_file_operations; - mpol_shared_policy_init(&info->policy, - shmem_get_sbmpol(sbinfo)); - break; - case S_IFDIR: - inc_nlink(inode); - /* Some things misbehave if size == 0 on a directory */ - inode->i_size = 2 * BOGO_DIRENT_SIZE; - inode->i_op = &shmem_dir_inode_operations; - inode->i_fop = &simple_dir_operations; - break; - case S_IFLNK: - /* - * Must not load anything in the rbtree, - * mpol_free_shared_policy will not be called. - */ - mpol_shared_policy_init(&info->policy, NULL); - break; - } - } else - shmem_free_inode(sb); - return inode; -} - -bool shmem_mapping(struct address_space *mapping) -{ - if (!mapping->host) - return false; - - return mapping->host->i_sb->s_op == &shmem_ops; -} - -#ifdef CONFIG_TMPFS -static const struct inode_operations shmem_symlink_inode_operations; -static const struct inode_operations shmem_short_symlink_operations; - -#ifdef CONFIG_TMPFS_XATTR -static int shmem_initxattrs(struct inode *, const struct xattr *, void *); -#else -#define shmem_initxattrs NULL -#endif - -static int -shmem_write_begin(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata) -{ - struct inode *inode = mapping->host; - struct shmem_inode_info *info = SHMEM_I(inode); - pgoff_t index = pos >> PAGE_SHIFT; - - /* i_mutex is held by caller */ - if (unlikely(info->seals)) { - if (info->seals & F_SEAL_WRITE) - return -EPERM; - if ((info->seals & F_SEAL_GROW) && pos + len > inode->i_size) - return -EPERM; - } - - return shmem_getpage(inode, index, pagep, SGP_WRITE); -} - -static int -shmem_write_end(struct file *file, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata) -{ - struct inode *inode = mapping->host; - - if (pos + copied > inode->i_size) - i_size_write(inode, pos + copied); - - if (!PageUptodate(page)) { - struct page *head = compound_head(page); - if (PageTransCompound(page)) { - int i; - - for (i = 0; i < HPAGE_PMD_NR; i++) { - if (head + i == page) - continue; - clear_highpage(head + i); - flush_dcache_page(head + i); - } - } - if (copied < PAGE_SIZE) { - unsigned from = pos & (PAGE_SIZE - 1); - zero_user_segments(page, 0, from, - from + copied, PAGE_SIZE); - } - SetPageUptodate(head); - } - set_page_dirty(page); - unlock_page(page); - put_page(page); - - return copied; -} - -static ssize_t shmem_file_read_iter(struct kiocb *iocb, struct iov_iter *to) -{ - struct file *file = iocb->ki_filp; - struct inode *inode = file_inode(file); - struct address_space *mapping = inode->i_mapping; - pgoff_t index; - unsigned long offset; - enum sgp_type sgp = SGP_READ; - int error = 0; - ssize_t retval = 0; - loff_t *ppos = &iocb->ki_pos; - - /* - * Might this read be for a stacking filesystem? Then when reading - * holes of a sparse file, we actually need to allocate those pages, - * and even mark them dirty, so it cannot exceed the max_blocks limit. - */ - if (!iter_is_iovec(to)) - sgp = SGP_CACHE; - - index = *ppos >> PAGE_SHIFT; - offset = *ppos & ~PAGE_MASK; - - for (;;) { - struct page *page = NULL; - pgoff_t end_index; - unsigned long nr, ret; - loff_t i_size = i_size_read(inode); - - end_index = i_size >> PAGE_SHIFT; - if (index > end_index) - break; - if (index == end_index) { - nr = i_size & ~PAGE_MASK; - if (nr <= offset) - break; - } - - error = shmem_getpage(inode, index, &page, sgp); - if (error) { - if (error == -EINVAL) - error = 0; - break; - } - if (page) { - if (sgp == SGP_CACHE) - set_page_dirty(page); - unlock_page(page); - } - - /* - * We must evaluate after, since reads (unlike writes) - * are called without i_mutex protection against truncate - */ - nr = PAGE_SIZE; - i_size = i_size_read(inode); - end_index = i_size >> PAGE_SHIFT; - if (index == end_index) { - nr = i_size & ~PAGE_MASK; - if (nr <= offset) { - if (page) - put_page(page); - break; - } - } - nr -= offset; - - if (page) { - /* - * If users can be writing to this page using arbitrary - * virtual addresses, take care about potential aliasing - * before reading the page on the kernel side. - */ - if (mapping_writably_mapped(mapping)) - flush_dcache_page(page); - /* - * Mark the page accessed if we read the beginning. - */ - if (!offset) - mark_page_accessed(page); - } else { - page = ZERO_PAGE(0); - get_page(page); - } - - /* - * Ok, we have the page, and it's up-to-date, so - * now we can copy it to user space... - */ - ret = copy_page_to_iter(page, offset, nr, to); - retval += ret; - offset += ret; - index += offset >> PAGE_SHIFT; - offset &= ~PAGE_MASK; - - put_page(page); - if (!iov_iter_count(to)) - break; - if (ret < nr) { - error = -EFAULT; - break; - } - cond_resched(); - } - - *ppos = ((loff_t) index << PAGE_SHIFT) + offset; - file_accessed(file); - return retval ? retval : error; -} - -/* - * llseek SEEK_DATA or SEEK_HOLE through the radix_tree. - */ -static pgoff_t shmem_seek_hole_data(struct address_space *mapping, - pgoff_t index, pgoff_t end, int whence) -{ - struct page *page; - struct pagevec pvec; - pgoff_t indices[PAGEVEC_SIZE]; - bool done = false; - int i; - - pagevec_init(&pvec, 0); - pvec.nr = 1; /* start small: we may be there already */ - while (!done) { - pvec.nr = find_get_entries(mapping, index, - pvec.nr, pvec.pages, indices); - if (!pvec.nr) { - if (whence == SEEK_DATA) - index = end; - break; - } - for (i = 0; i < pvec.nr; i++, index++) { - if (index < indices[i]) { - if (whence == SEEK_HOLE) { - done = true; - break; - } - index = indices[i]; - } - page = pvec.pages[i]; - if (page && !radix_tree_exceptional_entry(page)) { - if (!PageUptodate(page)) - page = NULL; - } - if (index >= end || - (page && whence == SEEK_DATA) || - (!page && whence == SEEK_HOLE)) { - done = true; - break; - } - } - pagevec_remove_exceptionals(&pvec); - pagevec_release(&pvec); - pvec.nr = PAGEVEC_SIZE; - cond_resched(); - } - return index; -} - -static loff_t shmem_file_llseek(struct file *file, loff_t offset, int whence) -{ - struct address_space *mapping = file->f_mapping; - struct inode *inode = mapping->host; - pgoff_t start, end; - loff_t new_offset; - - if (whence != SEEK_DATA && whence != SEEK_HOLE) - return generic_file_llseek_size(file, offset, whence, - MAX_LFS_FILESIZE, i_size_read(inode)); - inode_lock(inode); - /* We're holding i_mutex so we can access i_size directly */ - - if (offset < 0) - offset = -EINVAL; - else if (offset >= inode->i_size) - offset = -ENXIO; - else { - start = offset >> PAGE_SHIFT; - end = (inode->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT; - new_offset = shmem_seek_hole_data(mapping, start, end, whence); - new_offset <<= PAGE_SHIFT; - if (new_offset > offset) { - if (new_offset < inode->i_size) - offset = new_offset; - else if (whence == SEEK_DATA) - offset = -ENXIO; - else - offset = inode->i_size; - } - } - - if (offset >= 0) - offset = vfs_setpos(file, offset, MAX_LFS_FILESIZE); - inode_unlock(inode); - return offset; -} - -/* - * We need a tag: a new tag would expand every radix_tree_node by 8 bytes, - * so reuse a tag which we firmly believe is never set or cleared on shmem. - */ -#define SHMEM_TAG_PINNED PAGECACHE_TAG_TOWRITE -#define LAST_SCAN 4 /* about 150ms max */ - -static void shmem_tag_pins(struct address_space *mapping) -{ - struct radix_tree_iter iter; - void **slot; - pgoff_t start; - struct page *page; - - lru_add_drain(); - start = 0; - rcu_read_lock(); - - radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) { - page = radix_tree_deref_slot(slot); - if (!page || radix_tree_exception(page)) { - if (radix_tree_deref_retry(page)) { - slot = radix_tree_iter_retry(&iter); - continue; - } - } else if (page_count(page) - page_mapcount(page) > 1) { - spin_lock_irq(&mapping->tree_lock); - radix_tree_tag_set(&mapping->page_tree, iter.index, - SHMEM_TAG_PINNED); - spin_unlock_irq(&mapping->tree_lock); - } - - if (need_resched()) { - cond_resched_rcu(); - slot = radix_tree_iter_next(&iter); - } - } - rcu_read_unlock(); -} - -/* - * Setting SEAL_WRITE requires us to verify there's no pending writer. However, - * via get_user_pages(), drivers might have some pending I/O without any active - * user-space mappings (eg., direct-IO, AIO). Therefore, we look at all pages - * and see whether it has an elevated ref-count. If so, we tag them and wait for - * them to be dropped. - * The caller must guarantee that no new user will acquire writable references - * to those pages to avoid races. - */ -static int shmem_wait_for_pins(struct address_space *mapping) -{ - struct radix_tree_iter iter; - void **slot; - pgoff_t start; - struct page *page; - int error, scan; - - shmem_tag_pins(mapping); - - error = 0; - for (scan = 0; scan <= LAST_SCAN; scan++) { - if (!radix_tree_tagged(&mapping->page_tree, SHMEM_TAG_PINNED)) - break; - - if (!scan) - lru_add_drain_all(); - else if (schedule_timeout_killable((HZ << scan) / 200)) - scan = LAST_SCAN; - - start = 0; - rcu_read_lock(); - radix_tree_for_each_tagged(slot, &mapping->page_tree, &iter, - start, SHMEM_TAG_PINNED) { - - page = radix_tree_deref_slot(slot); - if (radix_tree_exception(page)) { - if (radix_tree_deref_retry(page)) { - slot = radix_tree_iter_retry(&iter); - continue; - } - - page = NULL; - } - - if (page && - page_count(page) - page_mapcount(page) != 1) { - if (scan < LAST_SCAN) - goto continue_resched; - - /* - * On the last scan, we clean up all those tags - * we inserted; but make a note that we still - * found pages pinned. - */ - error = -EBUSY; - } - - spin_lock_irq(&mapping->tree_lock); - radix_tree_tag_clear(&mapping->page_tree, - iter.index, SHMEM_TAG_PINNED); - spin_unlock_irq(&mapping->tree_lock); -continue_resched: - if (need_resched()) { - cond_resched_rcu(); - slot = radix_tree_iter_next(&iter); - } - } - rcu_read_unlock(); - } - - return error; -} - -#define F_ALL_SEALS (F_SEAL_SEAL | \ - F_SEAL_SHRINK | \ - F_SEAL_GROW | \ - F_SEAL_WRITE) - -int shmem_add_seals(struct file *file, unsigned int seals) -{ - struct inode *inode = file_inode(file); - struct shmem_inode_info *info = SHMEM_I(inode); - int error; - - /* - * SEALING - * Sealing allows multiple parties to share a shmem-file but restrict - * access to a specific subset of file operations. Seals can only be - * added, but never removed. This way, mutually untrusted parties can - * share common memory regions with a well-defined policy. A malicious - * peer can thus never perform unwanted operations on a shared object. - * - * Seals are only supported on special shmem-files and always affect - * the whole underlying inode. Once a seal is set, it may prevent some - * kinds of access to the file. Currently, the following seals are - * defined: - * SEAL_SEAL: Prevent further seals from being set on this file - * SEAL_SHRINK: Prevent the file from shrinking - * SEAL_GROW: Prevent the file from growing - * SEAL_WRITE: Prevent write access to the file - * - * As we don't require any trust relationship between two parties, we - * must prevent seals from being removed. Therefore, sealing a file - * only adds a given set of seals to the file, it never touches - * existing seals. Furthermore, the "setting seals"-operation can be - * sealed itself, which basically prevents any further seal from being - * added. - * - * Semantics of sealing are only defined on volatile files. Only - * anonymous shmem files support sealing. More importantly, seals are - * never written to disk. Therefore, there's no plan to support it on - * other file types. - */ - - if (file->f_op != &shmem_file_operations) - return -EINVAL; - if (!(file->f_mode & FMODE_WRITE)) - return -EPERM; - if (seals & ~(unsigned int)F_ALL_SEALS) - return -EINVAL; - - inode_lock(inode); - - if (info->seals & F_SEAL_SEAL) { - error = -EPERM; - goto unlock; - } - - if ((seals & F_SEAL_WRITE) && !(info->seals & F_SEAL_WRITE)) { - error = mapping_deny_writable(file->f_mapping); - if (error) - goto unlock; - - error = shmem_wait_for_pins(file->f_mapping); - if (error) { - mapping_allow_writable(file->f_mapping); - goto unlock; - } - } - - info->seals |= seals; - error = 0; - -unlock: - inode_unlock(inode); - return error; -} -EXPORT_SYMBOL_GPL(shmem_add_seals); - -int shmem_get_seals(struct file *file) -{ - if (file->f_op != &shmem_file_operations) - return -EINVAL; - - return SHMEM_I(file_inode(file))->seals; -} -EXPORT_SYMBOL_GPL(shmem_get_seals); - -long shmem_fcntl(struct file *file, unsigned int cmd, unsigned long arg) -{ - long error; - - switch (cmd) { - case F_ADD_SEALS: - /* disallow upper 32bit */ - if (arg > UINT_MAX) - return -EINVAL; - - error = shmem_add_seals(file, arg); - break; - case F_GET_SEALS: - error = shmem_get_seals(file); - break; - default: - error = -EINVAL; - break; - } - - return error; -} - -static long shmem_fallocate(struct file *file, int mode, loff_t offset, - loff_t len) -{ - struct inode *inode = file_inode(file); - struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); - struct shmem_inode_info *info = SHMEM_I(inode); - struct shmem_falloc shmem_falloc; - pgoff_t start, index, end; - int error; - - if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) - return -EOPNOTSUPP; - - inode_lock(inode); - - if (mode & FALLOC_FL_PUNCH_HOLE) { - struct address_space *mapping = file->f_mapping; - loff_t unmap_start = round_up(offset, PAGE_SIZE); - loff_t unmap_end = round_down(offset + len, PAGE_SIZE) - 1; - DECLARE_WAIT_QUEUE_HEAD_ONSTACK(shmem_falloc_waitq); - - /* protected by i_mutex */ - if (info->seals & F_SEAL_WRITE) { - error = -EPERM; - goto out; - } - - shmem_falloc.waitq = &shmem_falloc_waitq; - shmem_falloc.start = unmap_start >> PAGE_SHIFT; - shmem_falloc.next = (unmap_end + 1) >> PAGE_SHIFT; - spin_lock(&inode->i_lock); - inode->i_private = &shmem_falloc; - spin_unlock(&inode->i_lock); - - if ((u64)unmap_end > (u64)unmap_start) - unmap_mapping_range(mapping, unmap_start, - 1 + unmap_end - unmap_start, 0); - shmem_truncate_range(inode, offset, offset + len - 1); - /* No need to unmap again: hole-punching leaves COWed pages */ - - spin_lock(&inode->i_lock); - inode->i_private = NULL; - wake_up_all(&shmem_falloc_waitq); - WARN_ON_ONCE(!list_empty(&shmem_falloc_waitq.task_list)); - spin_unlock(&inode->i_lock); - error = 0; - goto out; - } - - /* We need to check rlimit even when FALLOC_FL_KEEP_SIZE */ - error = inode_newsize_ok(inode, offset + len); - if (error) - goto out; - - if ((info->seals & F_SEAL_GROW) && offset + len > inode->i_size) { - error = -EPERM; - goto out; - } - - start = offset >> PAGE_SHIFT; - end = (offset + len + PAGE_SIZE - 1) >> PAGE_SHIFT; - /* Try to avoid a swapstorm if len is impossible to satisfy */ - if (sbinfo->max_blocks && end - start > sbinfo->max_blocks) { - error = -ENOSPC; - goto out; - } - - shmem_falloc.waitq = NULL; - shmem_falloc.start = start; - shmem_falloc.next = start; - shmem_falloc.nr_falloced = 0; - shmem_falloc.nr_unswapped = 0; - spin_lock(&inode->i_lock); - inode->i_private = &shmem_falloc; - spin_unlock(&inode->i_lock); - - for (index = start; index < end; index++) { - struct page *page; - - /* - * Good, the fallocate(2) manpage permits EINTR: we may have - * been interrupted because we are using up too much memory. - */ - if (signal_pending(current)) - error = -EINTR; - else if (shmem_falloc.nr_unswapped > shmem_falloc.nr_falloced) - error = -ENOMEM; - else - error = shmem_getpage(inode, index, &page, SGP_FALLOC); - if (error) { - /* Remove the !PageUptodate pages we added */ - if (index > start) { - shmem_undo_range(inode, - (loff_t)start << PAGE_SHIFT, - ((loff_t)index << PAGE_SHIFT) - 1, true); - } - goto undone; - } - - /* - * Inform shmem_writepage() how far we have reached. - * No need for lock or barrier: we have the page lock. - */ - shmem_falloc.next++; - if (!PageUptodate(page)) - shmem_falloc.nr_falloced++; - - /* - * If !PageUptodate, leave it that way so that freeable pages - * can be recognized if we need to rollback on error later. - * But set_page_dirty so that memory pressure will swap rather - * than free the pages we are allocating (and SGP_CACHE pages - * might still be clean: we now need to mark those dirty too). - */ - set_page_dirty(page); - unlock_page(page); - put_page(page); - cond_resched(); - } - - if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > inode->i_size) - i_size_write(inode, offset + len); - inode->i_ctime = current_time(inode); -undone: - spin_lock(&inode->i_lock); - inode->i_private = NULL; - spin_unlock(&inode->i_lock); -out: - inode_unlock(inode); - return error; -} - -static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf) -{ - struct shmem_sb_info *sbinfo = SHMEM_SB(dentry->d_sb); - - buf->f_type = TMPFS_MAGIC; - buf->f_bsize = PAGE_SIZE; - buf->f_namelen = NAME_MAX; - if (sbinfo->max_blocks) { - buf->f_blocks = sbinfo->max_blocks; - buf->f_bavail = - buf->f_bfree = sbinfo->max_blocks - - percpu_counter_sum(&sbinfo->used_blocks); - } - if (sbinfo->max_inodes) { - buf->f_files = sbinfo->max_inodes; - buf->f_ffree = sbinfo->free_inodes; - } - /* else leave those fields 0 like simple_statfs */ - return 0; -} - -/* - * File creation. Allocate an inode, and we're done.. - */ -static int -shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev) -{ - struct inode *inode; - int error = -ENOSPC; - - inode = shmem_get_inode(dir->i_sb, dir, mode, dev, VM_NORESERVE); - if (inode) { - error = simple_acl_create(dir, inode); - if (error) - goto out_iput; - error = security_inode_init_security(inode, dir, - &dentry->d_name, - shmem_initxattrs, NULL); - if (error && error != -EOPNOTSUPP) - goto out_iput; - - error = 0; - dir->i_size += BOGO_DIRENT_SIZE; - dir->i_ctime = dir->i_mtime = current_time(dir); - d_instantiate(dentry, inode); - dget(dentry); /* Extra count - pin the dentry in core */ - } - return error; -out_iput: - iput(inode); - return error; -} - -static int -shmem_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode) -{ - struct inode *inode; - int error = -ENOSPC; - - inode = shmem_get_inode(dir->i_sb, dir, mode, 0, VM_NORESERVE); - if (inode) { - error = security_inode_init_security(inode, dir, - NULL, - shmem_initxattrs, NULL); - if (error && error != -EOPNOTSUPP) - goto out_iput; - error = simple_acl_create(dir, inode); - if (error) - goto out_iput; - d_tmpfile(dentry, inode); - } - return error; -out_iput: - iput(inode); - return error; -} - -static int shmem_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) -{ - int error; - - if ((error = shmem_mknod(dir, dentry, mode | S_IFDIR, 0))) - return error; - inc_nlink(dir); - return 0; -} - -static int shmem_create(struct inode *dir, struct dentry *dentry, umode_t mode, - bool excl) -{ - return shmem_mknod(dir, dentry, mode | S_IFREG, 0); -} - -/* - * Link a file.. - */ -static int shmem_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry) -{ - struct inode *inode = d_inode(old_dentry); - int ret; - - /* - * No ordinary (disk based) filesystem counts links as inodes; - * but each new link needs a new dentry, pinning lowmem, and - * tmpfs dentries cannot be pruned until they are unlinked. - */ - ret = shmem_reserve_inode(inode->i_sb); - if (ret) - goto out; - - dir->i_size += BOGO_DIRENT_SIZE; - inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode); - inc_nlink(inode); - ihold(inode); /* New dentry reference */ - dget(dentry); /* Extra pinning count for the created dentry */ - d_instantiate(dentry, inode); -out: - return ret; -} - -static int shmem_unlink(struct inode *dir, struct dentry *dentry) -{ - struct inode *inode = d_inode(dentry); - - if (inode->i_nlink > 1 && !S_ISDIR(inode->i_mode)) - shmem_free_inode(inode->i_sb); - - dir->i_size -= BOGO_DIRENT_SIZE; - inode->i_ctime = dir->i_ctime = dir->i_mtime = current_time(inode); - drop_nlink(inode); - dput(dentry); /* Undo the count from "create" - this does all the work */ - return 0; -} - -static int shmem_rmdir(struct inode *dir, struct dentry *dentry) -{ - if (!simple_empty(dentry)) - return -ENOTEMPTY; - - drop_nlink(d_inode(dentry)); - drop_nlink(dir); - return shmem_unlink(dir, dentry); -} - -static int shmem_exchange(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) -{ - bool old_is_dir = d_is_dir(old_dentry); - bool new_is_dir = d_is_dir(new_dentry); - - if (old_dir != new_dir && old_is_dir != new_is_dir) { - if (old_is_dir) { - drop_nlink(old_dir); - inc_nlink(new_dir); - } else { - drop_nlink(new_dir); - inc_nlink(old_dir); - } - } - old_dir->i_ctime = old_dir->i_mtime = - new_dir->i_ctime = new_dir->i_mtime = - d_inode(old_dentry)->i_ctime = - d_inode(new_dentry)->i_ctime = current_time(old_dir); - - return 0; -} - -static int shmem_whiteout(struct inode *old_dir, struct dentry *old_dentry) -{ - struct dentry *whiteout; - int error; - - whiteout = d_alloc(old_dentry->d_parent, &old_dentry->d_name); - if (!whiteout) - return -ENOMEM; - - error = shmem_mknod(old_dir, whiteout, - S_IFCHR | WHITEOUT_MODE, WHITEOUT_DEV); - dput(whiteout); - if (error) - return error; - - /* - * Cheat and hash the whiteout while the old dentry is still in - * place, instead of playing games with FS_RENAME_DOES_D_MOVE. - * - * d_lookup() will consistently find one of them at this point, - * not sure which one, but that isn't even important. - */ - d_rehash(whiteout); - return 0; -} - -/* - * The VFS layer already does all the dentry stuff for rename, - * we just have to decrement the usage count for the target if - * it exists so that the VFS layer correctly free's it when it - * gets overwritten. - */ -static int shmem_rename2(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, unsigned int flags) -{ - struct inode *inode = d_inode(old_dentry); - int they_are_dirs = S_ISDIR(inode->i_mode); - - if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT)) - return -EINVAL; - - if (flags & RENAME_EXCHANGE) - return shmem_exchange(old_dir, old_dentry, new_dir, new_dentry); - - if (!simple_empty(new_dentry)) - return -ENOTEMPTY; - - if (flags & RENAME_WHITEOUT) { - int error; - - error = shmem_whiteout(old_dir, old_dentry); - if (error) - return error; - } - - if (d_really_is_positive(new_dentry)) { - (void) shmem_unlink(new_dir, new_dentry); - if (they_are_dirs) { - drop_nlink(d_inode(new_dentry)); - drop_nlink(old_dir); - } - } else if (they_are_dirs) { - drop_nlink(old_dir); - inc_nlink(new_dir); - } - - old_dir->i_size -= BOGO_DIRENT_SIZE; - new_dir->i_size += BOGO_DIRENT_SIZE; - old_dir->i_ctime = old_dir->i_mtime = - new_dir->i_ctime = new_dir->i_mtime = - inode->i_ctime = current_time(old_dir); - return 0; -} - -static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *symname) -{ - int error; - int len; - struct inode *inode; - struct page *page; - struct shmem_inode_info *info; - - len = strlen(symname) + 1; - if (len > PAGE_SIZE) - return -ENAMETOOLONG; - - inode = shmem_get_inode(dir->i_sb, dir, S_IFLNK|S_IRWXUGO, 0, VM_NORESERVE); - if (!inode) - return -ENOSPC; - - error = security_inode_init_security(inode, dir, &dentry->d_name, - shmem_initxattrs, NULL); - if (error) { - if (error != -EOPNOTSUPP) { - iput(inode); - return error; - } - error = 0; - } - - info = SHMEM_I(inode); - inode->i_size = len-1; - if (len <= SHORT_SYMLINK_LEN) { - inode->i_link = kmemdup(symname, len, GFP_KERNEL); - if (!inode->i_link) { - iput(inode); - return -ENOMEM; - } - inode->i_op = &shmem_short_symlink_operations; - } else { - inode_nohighmem(inode); - error = shmem_getpage(inode, 0, &page, SGP_WRITE); - if (error) { - iput(inode); - return error; - } - inode->i_mapping->a_ops = &shmem_aops; - inode->i_op = &shmem_symlink_inode_operations; - memcpy(page_address(page), symname, len); - SetPageUptodate(page); - set_page_dirty(page); - unlock_page(page); - put_page(page); - } - dir->i_size += BOGO_DIRENT_SIZE; - dir->i_ctime = dir->i_mtime = current_time(dir); - d_instantiate(dentry, inode); - dget(dentry); - return 0; -} - -static void shmem_put_link(void *arg) -{ - mark_page_accessed(arg); - put_page(arg); -} - -static const char *shmem_get_link(struct dentry *dentry, - struct inode *inode, - struct delayed_call *done) -{ - struct page *page = NULL; - int error; - if (!dentry) { - page = find_get_page(inode->i_mapping, 0); - if (!page) - return ERR_PTR(-ECHILD); - if (!PageUptodate(page)) { - put_page(page); - return ERR_PTR(-ECHILD); - } - } else { - error = shmem_getpage(inode, 0, &page, SGP_READ); - if (error) - return ERR_PTR(error); - unlock_page(page); - } - set_delayed_call(done, shmem_put_link, page); - return page_address(page); -} - -#ifdef CONFIG_TMPFS_XATTR -/* - * Superblocks without xattr inode operations may get some security.* xattr - * support from the LSM "for free". As soon as we have any other xattrs - * like ACLs, we also need to implement the security.* handlers at - * filesystem level, though. - */ - -/* - * Callback for security_inode_init_security() for acquiring xattrs. - */ -static int shmem_initxattrs(struct inode *inode, - const struct xattr *xattr_array, - void *fs_info) -{ - struct shmem_inode_info *info = SHMEM_I(inode); - const struct xattr *xattr; - struct simple_xattr *new_xattr; - size_t len; - - for (xattr = xattr_array; xattr->name != NULL; xattr++) { - new_xattr = simple_xattr_alloc(xattr->value, xattr->value_len); - if (!new_xattr) - return -ENOMEM; - - len = strlen(xattr->name) + 1; - new_xattr->name = kmalloc(XATTR_SECURITY_PREFIX_LEN + len, - GFP_KERNEL); - if (!new_xattr->name) { - kfree(new_xattr); - return -ENOMEM; - } - - memcpy(new_xattr->name, XATTR_SECURITY_PREFIX, - XATTR_SECURITY_PREFIX_LEN); - memcpy(new_xattr->name + XATTR_SECURITY_PREFIX_LEN, - xattr->name, len); - - simple_xattr_list_add(&info->xattrs, new_xattr); - } - - return 0; -} - -static int shmem_xattr_handler_get(const struct xattr_handler *handler, - struct dentry *unused, struct inode *inode, - const char *name, void *buffer, size_t size) -{ - struct shmem_inode_info *info = SHMEM_I(inode); - - name = xattr_full_name(handler, name); - return simple_xattr_get(&info->xattrs, name, buffer, size); -} - -static int shmem_xattr_handler_set(const struct xattr_handler *handler, - struct dentry *unused, struct inode *inode, - const char *name, const void *value, - size_t size, int flags) -{ - struct shmem_inode_info *info = SHMEM_I(inode); - - name = xattr_full_name(handler, name); - return simple_xattr_set(&info->xattrs, name, value, size, flags); -} - -static const struct xattr_handler shmem_security_xattr_handler = { - .prefix = XATTR_SECURITY_PREFIX, - .get = shmem_xattr_handler_get, - .set = shmem_xattr_handler_set, -}; - -static const struct xattr_handler shmem_trusted_xattr_handler = { - .prefix = XATTR_TRUSTED_PREFIX, - .get = shmem_xattr_handler_get, - .set = shmem_xattr_handler_set, -}; - -static const struct xattr_handler *shmem_xattr_handlers[] = { -#ifdef CONFIG_TMPFS_POSIX_ACL - &posix_acl_access_xattr_handler, - &posix_acl_default_xattr_handler, -#endif - &shmem_security_xattr_handler, - &shmem_trusted_xattr_handler, - NULL -}; - -static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size) -{ - struct shmem_inode_info *info = SHMEM_I(d_inode(dentry)); - return simple_xattr_list(d_inode(dentry), &info->xattrs, buffer, size); -} -#endif /* CONFIG_TMPFS_XATTR */ - -static const struct inode_operations shmem_short_symlink_operations = { - .readlink = generic_readlink, - .get_link = simple_get_link, -#ifdef CONFIG_TMPFS_XATTR - .listxattr = shmem_listxattr, -#endif -}; - -static const struct inode_operations shmem_symlink_inode_operations = { - .readlink = generic_readlink, - .get_link = shmem_get_link, -#ifdef CONFIG_TMPFS_XATTR - .listxattr = shmem_listxattr, -#endif -}; - -static struct dentry *shmem_get_parent(struct dentry *child) -{ - return ERR_PTR(-ESTALE); -} - -static int shmem_match(struct inode *ino, void *vfh) -{ - __u32 *fh = vfh; - __u64 inum = fh[2]; - inum = (inum << 32) | fh[1]; - return ino->i_ino == inum && fh[0] == ino->i_generation; -} - -static struct dentry *shmem_fh_to_dentry(struct super_block *sb, - struct fid *fid, int fh_len, int fh_type) -{ - struct inode *inode; - struct dentry *dentry = NULL; - u64 inum; - - if (fh_len < 3) - return NULL; - - inum = fid->raw[2]; - inum = (inum << 32) | fid->raw[1]; - - inode = ilookup5(sb, (unsigned long)(inum + fid->raw[0]), - shmem_match, fid->raw); - if (inode) { - dentry = d_find_alias(inode); - iput(inode); - } - - return dentry; -} - -static int shmem_encode_fh(struct inode *inode, __u32 *fh, int *len, - struct inode *parent) -{ - if (*len < 3) { - *len = 3; - return FILEID_INVALID; - } - - if (inode_unhashed(inode)) { - /* Unfortunately insert_inode_hash is not idempotent, - * so as we hash inodes here rather than at creation - * time, we need a lock to ensure we only try - * to do it once - */ - static DEFINE_SPINLOCK(lock); - spin_lock(&lock); - if (inode_unhashed(inode)) - __insert_inode_hash(inode, - inode->i_ino + inode->i_generation); - spin_unlock(&lock); - } - - fh[0] = inode->i_generation; - fh[1] = inode->i_ino; - fh[2] = ((__u64)inode->i_ino) >> 32; - - *len = 3; - return 1; -} - -static const struct export_operations shmem_export_ops = { - .get_parent = shmem_get_parent, - .encode_fh = shmem_encode_fh, - .fh_to_dentry = shmem_fh_to_dentry, -}; - -static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo, - bool remount) -{ - char *this_char, *value, *rest; - struct mempolicy *mpol = NULL; - uid_t uid; - gid_t gid; - - while (options != NULL) { - this_char = options; - for (;;) { - /* - * NUL-terminate this option: unfortunately, - * mount options form a comma-separated list, - * but mpol's nodelist may also contain commas. - */ - options = strchr(options, ','); - if (options == NULL) - break; - options++; - if (!isdigit(*options)) { - options[-1] = '\0'; - break; - } - } - if (!*this_char) - continue; - if ((value = strchr(this_char,'=')) != NULL) { - *value++ = 0; - } else { - pr_err("tmpfs: No value for mount option '%s'\n", - this_char); - goto error; - } - - if (!strcmp(this_char,"size")) { - unsigned long long size; - size = memparse(value,&rest); - if (*rest == '%') { - size <<= PAGE_SHIFT; - size *= totalram_pages; - do_div(size, 100); - rest++; - } - if (*rest) - goto bad_val; - sbinfo->max_blocks = - DIV_ROUND_UP(size, PAGE_SIZE); - } else if (!strcmp(this_char,"nr_blocks")) { - sbinfo->max_blocks = memparse(value, &rest); - if (*rest) - goto bad_val; - } else if (!strcmp(this_char,"nr_inodes")) { - sbinfo->max_inodes = memparse(value, &rest); - if (*rest) - goto bad_val; - } else if (!strcmp(this_char,"mode")) { - if (remount) - continue; - sbinfo->mode = simple_strtoul(value, &rest, 8) & 07777; - if (*rest) - goto bad_val; - } else if (!strcmp(this_char,"uid")) { - if (remount) - continue; - uid = simple_strtoul(value, &rest, 0); - if (*rest) - goto bad_val; - sbinfo->uid = make_kuid(current_user_ns(), uid); - if (!uid_valid(sbinfo->uid)) - goto bad_val; - } else if (!strcmp(this_char,"gid")) { - if (remount) - continue; - gid = simple_strtoul(value, &rest, 0); - if (*rest) - goto bad_val; - sbinfo->gid = make_kgid(current_user_ns(), gid); - if (!gid_valid(sbinfo->gid)) - goto bad_val; -#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE - } else if (!strcmp(this_char, "huge")) { - int huge; - huge = shmem_parse_huge(value); - if (huge < 0) - goto bad_val; - if (!has_transparent_hugepage() && - huge != SHMEM_HUGE_NEVER) - goto bad_val; - sbinfo->huge = huge; -#endif -#ifdef CONFIG_NUMA - } else if (!strcmp(this_char,"mpol")) { - mpol_put(mpol); - mpol = NULL; - if (mpol_parse_str(value, &mpol)) - goto bad_val; -#endif - } else { - pr_err("tmpfs: Bad mount option %s\n", this_char); - goto error; - } - } - sbinfo->mpol = mpol; - return 0; - -bad_val: - pr_err("tmpfs: Bad value '%s' for mount option '%s'\n", - value, this_char); -error: - mpol_put(mpol); - return 1; - -} - -static int shmem_remount_fs(struct super_block *sb, int *flags, char *data) -{ - struct shmem_sb_info *sbinfo = SHMEM_SB(sb); - struct shmem_sb_info config = *sbinfo; - unsigned long inodes; - int error = -EINVAL; - - config.mpol = NULL; - if (shmem_parse_options(data, &config, true)) - return error; - - spin_lock(&sbinfo->stat_lock); - inodes = sbinfo->max_inodes - sbinfo->free_inodes; - if (percpu_counter_compare(&sbinfo->used_blocks, config.max_blocks) > 0) - goto out; - if (config.max_inodes < inodes) - goto out; - /* - * Those tests disallow limited->unlimited while any are in use; - * but we must separately disallow unlimited->limited, because - * in that case we have no record of how much is already in use. - */ - if (config.max_blocks && !sbinfo->max_blocks) - goto out; - if (config.max_inodes && !sbinfo->max_inodes) - goto out; - - error = 0; - sbinfo->huge = config.huge; - sbinfo->max_blocks = config.max_blocks; - sbinfo->max_inodes = config.max_inodes; - sbinfo->free_inodes = config.max_inodes - inodes; - - /* - * Preserve previous mempolicy unless mpol remount option was specified. - */ - if (config.mpol) { - mpol_put(sbinfo->mpol); - sbinfo->mpol = config.mpol; /* transfers initial ref */ - } -out: - spin_unlock(&sbinfo->stat_lock); - return error; -} - -static int shmem_show_options(struct seq_file *seq, struct dentry *root) -{ - struct shmem_sb_info *sbinfo = SHMEM_SB(root->d_sb); - - if (sbinfo->max_blocks != shmem_default_max_blocks()) - seq_printf(seq, ",size=%luk", - sbinfo->max_blocks << (PAGE_SHIFT - 10)); - if (sbinfo->max_inodes != shmem_default_max_inodes()) - seq_printf(seq, ",nr_inodes=%lu", sbinfo->max_inodes); - if (sbinfo->mode != (S_IRWXUGO | S_ISVTX)) - seq_printf(seq, ",mode=%03ho", sbinfo->mode); - if (!uid_eq(sbinfo->uid, GLOBAL_ROOT_UID)) - seq_printf(seq, ",uid=%u", - from_kuid_munged(&init_user_ns, sbinfo->uid)); - if (!gid_eq(sbinfo->gid, GLOBAL_ROOT_GID)) - seq_printf(seq, ",gid=%u", - from_kgid_munged(&init_user_ns, sbinfo->gid)); -#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE - /* Rightly or wrongly, show huge mount option unmasked by shmem_huge */ - if (sbinfo->huge) - seq_printf(seq, ",huge=%s", shmem_format_huge(sbinfo->huge)); -#endif - shmem_show_mpol(seq, sbinfo->mpol); - return 0; -} - -#define MFD_NAME_PREFIX "memfd:" -#define MFD_NAME_PREFIX_LEN (sizeof(MFD_NAME_PREFIX) - 1) -#define MFD_NAME_MAX_LEN (NAME_MAX - MFD_NAME_PREFIX_LEN) - -#define MFD_ALL_FLAGS (MFD_CLOEXEC | MFD_ALLOW_SEALING) - -SYSCALL_DEFINE2(memfd_create, - const char __user *, uname, - unsigned int, flags) -{ - struct shmem_inode_info *info; - struct file *file; - int fd, error; - char *name; - long len; - - if (flags & ~(unsigned int)MFD_ALL_FLAGS) - return -EINVAL; - - /* length includes terminating zero */ - len = strnlen_user(uname, MFD_NAME_MAX_LEN + 1); - if (len <= 0) - return -EFAULT; - if (len > MFD_NAME_MAX_LEN + 1) - return -EINVAL; - - name = kmalloc(len + MFD_NAME_PREFIX_LEN, GFP_TEMPORARY); - if (!name) - return -ENOMEM; - - strcpy(name, MFD_NAME_PREFIX); - if (copy_from_user(&name[MFD_NAME_PREFIX_LEN], uname, len)) { - error = -EFAULT; - goto err_name; - } - - /* terminating-zero may have changed after strnlen_user() returned */ - if (name[len + MFD_NAME_PREFIX_LEN - 1]) { - error = -EFAULT; - goto err_name; - } - - fd = get_unused_fd_flags((flags & MFD_CLOEXEC) ? O_CLOEXEC : 0); - if (fd < 0) { - error = fd; - goto err_name; - } - - file = shmem_file_setup(name, 0, VM_NORESERVE); - if (IS_ERR(file)) { - error = PTR_ERR(file); - goto err_fd; - } - info = SHMEM_I(file_inode(file)); - file->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; - file->f_flags |= O_RDWR | O_LARGEFILE; - if (flags & MFD_ALLOW_SEALING) - info->seals &= ~F_SEAL_SEAL; - - fd_install(fd, file); - kfree(name); - return fd; - -err_fd: - put_unused_fd(fd); -err_name: - kfree(name); - return error; -} - -#endif /* CONFIG_TMPFS */ - -static void shmem_put_super(struct super_block *sb) -{ - struct shmem_sb_info *sbinfo = SHMEM_SB(sb); - - percpu_counter_destroy(&sbinfo->used_blocks); - mpol_put(sbinfo->mpol); - kfree(sbinfo); - sb->s_fs_info = NULL; -} - -int shmem_fill_super(struct super_block *sb, void *data, int silent) -{ - struct inode *inode; - struct shmem_sb_info *sbinfo; - int err = -ENOMEM; - - /* Round up to L1_CACHE_BYTES to resist false sharing */ - sbinfo = kzalloc(max((int)sizeof(struct shmem_sb_info), - L1_CACHE_BYTES), GFP_KERNEL); - if (!sbinfo) - return -ENOMEM; - - sbinfo->mode = S_IRWXUGO | S_ISVTX; - sbinfo->uid = current_fsuid(); - sbinfo->gid = current_fsgid(); - sb->s_fs_info = sbinfo; - -#ifdef CONFIG_TMPFS - /* - * Per default we only allow half of the physical ram per - * tmpfs instance, limiting inodes to one per page of lowmem; - * but the internal instance is left unlimited. - */ - if (!(sb->s_flags & MS_KERNMOUNT)) { - sbinfo->max_blocks = shmem_default_max_blocks(); - sbinfo->max_inodes = shmem_default_max_inodes(); - if (shmem_parse_options(data, sbinfo, false)) { - err = -EINVAL; - goto failed; - } - } else { - sb->s_flags |= MS_NOUSER; - } - sb->s_export_op = &shmem_export_ops; - sb->s_flags |= MS_NOSEC; -#else - sb->s_flags |= MS_NOUSER; -#endif - - spin_lock_init(&sbinfo->stat_lock); - if (percpu_counter_init(&sbinfo->used_blocks, 0, GFP_KERNEL)) - goto failed; - sbinfo->free_inodes = sbinfo->max_inodes; - spin_lock_init(&sbinfo->shrinklist_lock); - INIT_LIST_HEAD(&sbinfo->shrinklist); - - sb->s_maxbytes = MAX_LFS_FILESIZE; - sb->s_blocksize = PAGE_SIZE; - sb->s_blocksize_bits = PAGE_SHIFT; - sb->s_magic = TMPFS_MAGIC; - sb->s_op = &shmem_ops; - sb->s_time_gran = 1; -#ifdef CONFIG_TMPFS_XATTR - sb->s_xattr = shmem_xattr_handlers; -#endif -#ifdef CONFIG_TMPFS_POSIX_ACL - sb->s_flags |= MS_POSIXACL; -#endif - - inode = shmem_get_inode(sb, NULL, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE); - if (!inode) - goto failed; - inode->i_uid = sbinfo->uid; - inode->i_gid = sbinfo->gid; - sb->s_root = d_make_root(inode); - if (!sb->s_root) - goto failed; - return 0; - -failed: - shmem_put_super(sb); - return err; -} - -static struct kmem_cache *shmem_inode_cachep; - -static struct inode *shmem_alloc_inode(struct super_block *sb) -{ - struct shmem_inode_info *info; - info = kmem_cache_alloc(shmem_inode_cachep, GFP_KERNEL); - if (!info) - return NULL; - return &info->vfs_inode; -} - -static void shmem_destroy_callback(struct rcu_head *head) -{ - struct inode *inode = container_of(head, struct inode, i_rcu); - if (S_ISLNK(inode->i_mode)) - kfree(inode->i_link); - kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode)); -} - -static void shmem_destroy_inode(struct inode *inode) -{ - if (S_ISREG(inode->i_mode)) - mpol_free_shared_policy(&SHMEM_I(inode)->policy); - call_rcu(&inode->i_rcu, shmem_destroy_callback); -} - -static void shmem_init_inode(void *foo) -{ - struct shmem_inode_info *info = foo; - inode_init_once(&info->vfs_inode); -} - -static int shmem_init_inodecache(void) -{ - shmem_inode_cachep = kmem_cache_create("shmem_inode_cache", - sizeof(struct shmem_inode_info), - 0, SLAB_PANIC|SLAB_ACCOUNT, shmem_init_inode); - return 0; -} - -static void shmem_destroy_inodecache(void) -{ - kmem_cache_destroy(shmem_inode_cachep); -} - -static const struct address_space_operations shmem_aops = { - .writepage = shmem_writepage, - .set_page_dirty = __set_page_dirty_no_writeback, -#ifdef CONFIG_TMPFS - .write_begin = shmem_write_begin, - .write_end = shmem_write_end, -#endif -#ifdef CONFIG_MIGRATION - .migratepage = migrate_page, -#endif - .error_remove_page = generic_error_remove_page, -}; - -static const struct file_operations shmem_file_operations = { - .mmap = shmem_mmap, - .get_unmapped_area = shmem_get_unmapped_area, -#ifdef CONFIG_TMPFS - .llseek = shmem_file_llseek, - .read_iter = shmem_file_read_iter, - .write_iter = generic_file_write_iter, - .fsync = noop_fsync, - .splice_read = generic_file_splice_read, - .splice_write = iter_file_splice_write, - .fallocate = shmem_fallocate, -#endif -}; - -static const struct inode_operations shmem_inode_operations = { - .getattr = shmem_getattr, - .setattr = shmem_setattr, -#ifdef CONFIG_TMPFS_XATTR - .listxattr = shmem_listxattr, - .set_acl = simple_set_acl, -#endif -}; - -static const struct inode_operations shmem_dir_inode_operations = { -#ifdef CONFIG_TMPFS - .create = shmem_create, - .lookup = simple_lookup, - .link = shmem_link, - .unlink = shmem_unlink, - .symlink = shmem_symlink, - .mkdir = shmem_mkdir, - .rmdir = shmem_rmdir, - .mknod = shmem_mknod, - .rename = shmem_rename2, - .tmpfile = shmem_tmpfile, -#endif -#ifdef CONFIG_TMPFS_XATTR - .listxattr = shmem_listxattr, -#endif -#ifdef CONFIG_TMPFS_POSIX_ACL - .setattr = shmem_setattr, - .set_acl = simple_set_acl, -#endif -}; - -static const struct inode_operations shmem_special_inode_operations = { -#ifdef CONFIG_TMPFS_XATTR - .listxattr = shmem_listxattr, -#endif -#ifdef CONFIG_TMPFS_POSIX_ACL - .setattr = shmem_setattr, - .set_acl = simple_set_acl, -#endif -}; - -static const struct super_operations shmem_ops = { - .alloc_inode = shmem_alloc_inode, - .destroy_inode = shmem_destroy_inode, -#ifdef CONFIG_TMPFS - .statfs = shmem_statfs, - .remount_fs = shmem_remount_fs, - .show_options = shmem_show_options, -#endif - .evict_inode = shmem_evict_inode, - .drop_inode = generic_delete_inode, - .put_super = shmem_put_super, -#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE - .nr_cached_objects = shmem_unused_huge_count, - .free_cached_objects = shmem_unused_huge_scan, -#endif -}; - -static const struct vm_operations_struct shmem_vm_ops = { - .fault = shmem_fault, - .map_pages = filemap_map_pages, -#ifdef CONFIG_NUMA - .set_policy = shmem_set_policy, - .get_policy = shmem_get_policy, -#endif -}; - -static struct dentry *shmem_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_nodev(fs_type, flags, data, shmem_fill_super); -} - -static struct file_system_type shmem_fs_type = { - .owner = THIS_MODULE, - .name = "tmpfs", - .mount = shmem_mount, - .kill_sb = kill_litter_super, - .fs_flags = FS_USERNS_MOUNT, -}; - -int __init shmem_init(void) -{ - int error; - - /* If rootfs called this, don't re-init */ - if (shmem_inode_cachep) - return 0; - - error = shmem_init_inodecache(); - if (error) - goto out3; - - error = register_filesystem(&shmem_fs_type); - if (error) { - pr_err("Could not register tmpfs\n"); - goto out2; - } - - shm_mnt = kern_mount(&shmem_fs_type); - if (IS_ERR(shm_mnt)) { - error = PTR_ERR(shm_mnt); - pr_err("Could not kern_mount tmpfs\n"); - goto out1; - } - -#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE - if (has_transparent_hugepage() && shmem_huge < SHMEM_HUGE_DENY) - SHMEM_SB(shm_mnt->mnt_sb)->huge = shmem_huge; - else - shmem_huge = 0; /* just in case it was patched */ -#endif - return 0; - -out1: - unregister_filesystem(&shmem_fs_type); -out2: - shmem_destroy_inodecache(); -out3: - shm_mnt = ERR_PTR(error); - return error; -} - -#if defined(CONFIG_TRANSPARENT_HUGE_PAGECACHE) && defined(CONFIG_SYSFS) -static ssize_t shmem_enabled_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - int values[] = { - SHMEM_HUGE_ALWAYS, - SHMEM_HUGE_WITHIN_SIZE, - SHMEM_HUGE_ADVISE, - SHMEM_HUGE_NEVER, - SHMEM_HUGE_DENY, - SHMEM_HUGE_FORCE, - }; - int i, count; - - for (i = 0, count = 0; i < ARRAY_SIZE(values); i++) { - const char *fmt = shmem_huge == values[i] ? "[%s] " : "%s "; - - count += sprintf(buf + count, fmt, - shmem_format_huge(values[i])); - } - buf[count - 1] = '\n'; - return count; -} - -static ssize_t shmem_enabled_store(struct kobject *kobj, - struct kobj_attribute *attr, const char *buf, size_t count) -{ - char tmp[16]; - int huge; - - if (count + 1 > sizeof(tmp)) - return -EINVAL; - memcpy(tmp, buf, count); - tmp[count] = '\0'; - if (count && tmp[count - 1] == '\n') - tmp[count - 1] = '\0'; - - huge = shmem_parse_huge(tmp); - if (huge == -EINVAL) - return -EINVAL; - if (!has_transparent_hugepage() && - huge != SHMEM_HUGE_NEVER && huge != SHMEM_HUGE_DENY) - return -EINVAL; - - shmem_huge = huge; - if (shmem_huge < SHMEM_HUGE_DENY) - SHMEM_SB(shm_mnt->mnt_sb)->huge = shmem_huge; - return count; -} - -struct kobj_attribute shmem_enabled_attr = - __ATTR(shmem_enabled, 0644, shmem_enabled_show, shmem_enabled_store); -#endif /* CONFIG_TRANSPARENT_HUGE_PAGECACHE && CONFIG_SYSFS */ - -#ifdef CONFIG_TRANSPARENT_HUGE_PAGECACHE -bool shmem_huge_enabled(struct vm_area_struct *vma) -{ - struct inode *inode = file_inode(vma->vm_file); - struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); - loff_t i_size; - pgoff_t off; - - if (shmem_huge == SHMEM_HUGE_FORCE) - return true; - if (shmem_huge == SHMEM_HUGE_DENY) - return false; - switch (sbinfo->huge) { - case SHMEM_HUGE_NEVER: - return false; - case SHMEM_HUGE_ALWAYS: - return true; - case SHMEM_HUGE_WITHIN_SIZE: - off = round_up(vma->vm_pgoff, HPAGE_PMD_NR); - i_size = round_up(i_size_read(inode), PAGE_SIZE); - if (i_size >= HPAGE_PMD_SIZE && - i_size >> PAGE_SHIFT >= off) - return true; - case SHMEM_HUGE_ADVISE: - /* TODO: implement fadvise() hints */ - return (vma->vm_flags & VM_HUGEPAGE); - default: - VM_BUG_ON(1); - return false; - } -} -#endif /* CONFIG_TRANSPARENT_HUGE_PAGECACHE */ - -#else /* !CONFIG_SHMEM */ - -/* - * tiny-shmem: simple shmemfs and tmpfs using ramfs code - * - * This is intended for small system where the benefits of the full - * shmem code (swap-backed and resource-limited) are outweighed by - * their complexity. On systems without swap this code should be - * effectively equivalent, but much lighter weight. - */ - -static struct file_system_type shmem_fs_type = { - .name = "tmpfs", - .mount = ramfs_mount, - .kill_sb = kill_litter_super, - .fs_flags = FS_USERNS_MOUNT, -}; - -int __init shmem_init(void) -{ - BUG_ON(register_filesystem(&shmem_fs_type) != 0); - - shm_mnt = kern_mount(&shmem_fs_type); - BUG_ON(IS_ERR(shm_mnt)); - - return 0; -} - -int shmem_unuse(swp_entry_t swap, struct page *page) -{ - return 0; -} - -int shmem_lock(struct file *file, int lock, struct user_struct *user) -{ - return 0; -} - -void shmem_unlock_mapping(struct address_space *mapping) -{ -} - -#ifdef CONFIG_MMU -unsigned long shmem_get_unmapped_area(struct file *file, - unsigned long addr, unsigned long len, - unsigned long pgoff, unsigned long flags) -{ - return current->mm->get_unmapped_area(file, addr, len, pgoff, flags); -} -#endif - -void shmem_truncate_range(struct inode *inode, loff_t lstart, loff_t lend) -{ - truncate_inode_pages_range(inode->i_mapping, lstart, lend); -} -EXPORT_SYMBOL_GPL(shmem_truncate_range); - -#define shmem_vm_ops generic_file_vm_ops -#define shmem_file_operations ramfs_file_operations -#define shmem_get_inode(sb, dir, mode, dev, flags) ramfs_get_inode(sb, dir, mode, dev) -#define shmem_acct_size(flags, size) 0 -#define shmem_unacct_size(flags, size) do {} while (0) - -#endif /* CONFIG_SHMEM */ - -/* common code */ - -static const struct dentry_operations anon_ops = { - .d_dname = simple_dname -}; - -static struct file *__shmem_file_setup(const char *name, loff_t size, - unsigned long flags, unsigned int i_flags) -{ - struct file *res; - struct inode *inode; - struct path path; - struct super_block *sb; - struct qstr this; - - if (IS_ERR(shm_mnt)) - return ERR_CAST(shm_mnt); - - if (size < 0 || size > MAX_LFS_FILESIZE) - return ERR_PTR(-EINVAL); - - if (shmem_acct_size(flags, size)) - return ERR_PTR(-ENOMEM); - - res = ERR_PTR(-ENOMEM); - this.name = name; - this.len = strlen(name); - this.hash = 0; /* will go */ - sb = shm_mnt->mnt_sb; - path.mnt = mntget(shm_mnt); - path.dentry = d_alloc_pseudo(sb, &this); - if (!path.dentry) - goto put_memory; - d_set_d_op(path.dentry, &anon_ops); - - res = ERR_PTR(-ENOSPC); - inode = shmem_get_inode(sb, NULL, S_IFREG | S_IRWXUGO, 0, flags); - if (!inode) - goto put_memory; - - inode->i_flags |= i_flags; - d_instantiate(path.dentry, inode); - inode->i_size = size; - clear_nlink(inode); /* It is unlinked */ - res = ERR_PTR(ramfs_nommu_expand_for_mapping(inode, size)); - if (IS_ERR(res)) - goto put_path; - - res = alloc_file(&path, FMODE_WRITE | FMODE_READ, - &shmem_file_operations); - if (IS_ERR(res)) - goto put_path; - - return res; - -put_memory: - shmem_unacct_size(flags, size); -put_path: - path_put(&path); - return res; -} - -/** - * shmem_kernel_file_setup - get an unlinked file living in tmpfs which must be - * kernel internal. There will be NO LSM permission checks against the - * underlying inode. So users of this interface must do LSM checks at a - * higher layer. The users are the big_key and shm implementations. LSM - * checks are provided at the key or shm level rather than the inode. - * @name: name for dentry (to be seen in /proc//maps - * @size: size to be set for the file - * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size - */ -struct file *shmem_kernel_file_setup(const char *name, loff_t size, unsigned long flags) -{ - return __shmem_file_setup(name, size, flags, S_PRIVATE); -} - -/** - * shmem_file_setup - get an unlinked file living in tmpfs - * @name: name for dentry (to be seen in /proc//maps - * @size: size to be set for the file - * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size - */ -struct file *shmem_file_setup(const char *name, loff_t size, unsigned long flags) -{ - return __shmem_file_setup(name, size, flags, 0); -} -EXPORT_SYMBOL_GPL(shmem_file_setup); - -/** - * shmem_zero_setup - setup a shared anonymous mapping - * @vma: the vma to be mmapped is prepared by do_mmap_pgoff - */ -int shmem_zero_setup(struct vm_area_struct *vma) -{ - struct file *file; - loff_t size = vma->vm_end - vma->vm_start; - - /* - * Cloning a new file under mmap_sem leads to a lock ordering conflict - * between XFS directory reading and selinux: since this file is only - * accessible to the user through its mapping, use S_PRIVATE flag to - * bypass file security, in the same way as shmem_kernel_file_setup(). - */ - file = __shmem_file_setup("dev/zero", size, vma->vm_flags, S_PRIVATE); - if (IS_ERR(file)) - return PTR_ERR(file); - - if (vma->vm_file) - fput(vma->vm_file); - vma->vm_file = file; - vma->vm_ops = &shmem_vm_ops; - - if (IS_ENABLED(CONFIG_TRANSPARENT_HUGE_PAGECACHE) && - ((vma->vm_start + ~HPAGE_PMD_MASK) & HPAGE_PMD_MASK) < - (vma->vm_end & HPAGE_PMD_MASK)) { - khugepaged_enter(vma, vma->vm_flags); - } - - return 0; -} - -/** - * shmem_read_mapping_page_gfp - read into page cache, using specified page allocation flags. - * @mapping: the page's address_space - * @index: the page index - * @gfp: the page allocator flags to use if allocating - * - * This behaves as a tmpfs "read_cache_page_gfp(mapping, index, gfp)", - * with any new page allocations done using the specified allocation flags. - * But read_cache_page_gfp() uses the ->readpage() method: which does not - * suit tmpfs, since it may have pages in swapcache, and needs to find those - * for itself; although drivers/gpu/drm i915 and ttm rely upon this support. - * - * i915_gem_object_get_pages_gtt() mixes __GFP_NORETRY | __GFP_NOWARN in - * with the mapping_gfp_mask(), to avoid OOMing the machine unnecessarily. - */ -struct page *shmem_read_mapping_page_gfp(struct address_space *mapping, - pgoff_t index, gfp_t gfp) -{ -#ifdef CONFIG_SHMEM - struct inode *inode = mapping->host; - struct page *page; - int error; - - BUG_ON(mapping->a_ops != &shmem_aops); - error = shmem_getpage_gfp(inode, index, &page, SGP_CACHE, - gfp, NULL, NULL); - if (error) - page = ERR_PTR(error); - else - unlock_page(page); - return page; -#else - /* - * The tiny !SHMEM case uses ramfs without swap - */ - return read_cache_page_gfp(mapping, index, gfp); -#endif -} -EXPORT_SYMBOL_GPL(shmem_read_mapping_page_gfp); diff --git a/src/linux/mm/slab.h b/src/linux/mm/slab.h deleted file mode 100644 index bc05fdc..0000000 --- a/src/linux/mm/slab.h +++ /dev/null @@ -1,492 +0,0 @@ -#ifndef MM_SLAB_H -#define MM_SLAB_H -/* - * Internal slab definitions - */ - -#ifdef CONFIG_SLOB -/* - * Common fields provided in kmem_cache by all slab allocators - * This struct is either used directly by the allocator (SLOB) - * or the allocator must include definitions for all fields - * provided in kmem_cache_common in their definition of kmem_cache. - * - * Once we can do anonymous structs (C11 standard) we could put a - * anonymous struct definition in these allocators so that the - * separate allocations in the kmem_cache structure of SLAB and - * SLUB is no longer needed. - */ -struct kmem_cache { - unsigned int object_size;/* The original size of the object */ - unsigned int size; /* The aligned/padded/added on size */ - unsigned int align; /* Alignment as calculated */ - unsigned long flags; /* Active flags on the slab */ - const char *name; /* Slab name for sysfs */ - int refcount; /* Use counter */ - void (*ctor)(void *); /* Called on object slot creation */ - struct list_head list; /* List of all slab caches on the system */ -}; - -#endif /* CONFIG_SLOB */ - -#ifdef CONFIG_SLAB -#include -#endif - -#ifdef CONFIG_SLUB -#include -#endif - -#include -#include -#include -#include -#include -#include - -/* - * State of the slab allocator. - * - * This is used to describe the states of the allocator during bootup. - * Allocators use this to gradually bootstrap themselves. Most allocators - * have the problem that the structures used for managing slab caches are - * allocated from slab caches themselves. - */ -enum slab_state { - DOWN, /* No slab functionality yet */ - PARTIAL, /* SLUB: kmem_cache_node available */ - PARTIAL_NODE, /* SLAB: kmalloc size for node struct available */ - UP, /* Slab caches usable but not all extras yet */ - FULL /* Everything is working */ -}; - -extern enum slab_state slab_state; - -/* The slab cache mutex protects the management structures during changes */ -extern struct mutex slab_mutex; - -/* The list of all slab caches on the system */ -extern struct list_head slab_caches; - -/* The slab cache that manages slab cache information */ -extern struct kmem_cache *kmem_cache; - -unsigned long calculate_alignment(unsigned long flags, - unsigned long align, unsigned long size); - -#ifndef CONFIG_SLOB -/* Kmalloc array related functions */ -void setup_kmalloc_cache_index_table(void); -void create_kmalloc_caches(unsigned long); - -/* Find the kmalloc slab corresponding for a certain size */ -struct kmem_cache *kmalloc_slab(size_t, gfp_t); -#endif - - -/* Functions provided by the slab allocators */ -extern int __kmem_cache_create(struct kmem_cache *, unsigned long flags); - -extern struct kmem_cache *create_kmalloc_cache(const char *name, size_t size, - unsigned long flags); -extern void create_boot_cache(struct kmem_cache *, const char *name, - size_t size, unsigned long flags); - -int slab_unmergeable(struct kmem_cache *s); -struct kmem_cache *find_mergeable(size_t size, size_t align, - unsigned long flags, const char *name, void (*ctor)(void *)); -#ifndef CONFIG_SLOB -struct kmem_cache * -__kmem_cache_alias(const char *name, size_t size, size_t align, - unsigned long flags, void (*ctor)(void *)); - -unsigned long kmem_cache_flags(unsigned long object_size, - unsigned long flags, const char *name, - void (*ctor)(void *)); -#else -static inline struct kmem_cache * -__kmem_cache_alias(const char *name, size_t size, size_t align, - unsigned long flags, void (*ctor)(void *)) -{ return NULL; } - -static inline unsigned long kmem_cache_flags(unsigned long object_size, - unsigned long flags, const char *name, - void (*ctor)(void *)) -{ - return flags; -} -#endif - - -/* Legal flag mask for kmem_cache_create(), for various configurations */ -#define SLAB_CORE_FLAGS (SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA | SLAB_PANIC | \ - SLAB_DESTROY_BY_RCU | SLAB_DEBUG_OBJECTS ) - -#if defined(CONFIG_DEBUG_SLAB) -#define SLAB_DEBUG_FLAGS (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER) -#elif defined(CONFIG_SLUB_DEBUG) -#define SLAB_DEBUG_FLAGS (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \ - SLAB_TRACE | SLAB_CONSISTENCY_CHECKS) -#else -#define SLAB_DEBUG_FLAGS (0) -#endif - -#if defined(CONFIG_SLAB) -#define SLAB_CACHE_FLAGS (SLAB_MEM_SPREAD | SLAB_NOLEAKTRACE | \ - SLAB_RECLAIM_ACCOUNT | SLAB_TEMPORARY | \ - SLAB_NOTRACK | SLAB_ACCOUNT) -#elif defined(CONFIG_SLUB) -#define SLAB_CACHE_FLAGS (SLAB_NOLEAKTRACE | SLAB_RECLAIM_ACCOUNT | \ - SLAB_TEMPORARY | SLAB_NOTRACK | SLAB_ACCOUNT) -#else -#define SLAB_CACHE_FLAGS (0) -#endif - -#define CACHE_CREATE_MASK (SLAB_CORE_FLAGS | SLAB_DEBUG_FLAGS | SLAB_CACHE_FLAGS) - -int __kmem_cache_shutdown(struct kmem_cache *); -void __kmem_cache_release(struct kmem_cache *); -int __kmem_cache_shrink(struct kmem_cache *, bool); -void slab_kmem_cache_release(struct kmem_cache *); - -struct seq_file; -struct file; - -struct slabinfo { - unsigned long active_objs; - unsigned long num_objs; - unsigned long active_slabs; - unsigned long num_slabs; - unsigned long shared_avail; - unsigned int limit; - unsigned int batchcount; - unsigned int shared; - unsigned int objects_per_slab; - unsigned int cache_order; -}; - -void get_slabinfo(struct kmem_cache *s, struct slabinfo *sinfo); -void slabinfo_show_stats(struct seq_file *m, struct kmem_cache *s); -ssize_t slabinfo_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos); - -/* - * Generic implementation of bulk operations - * These are useful for situations in which the allocator cannot - * perform optimizations. In that case segments of the object listed - * may be allocated or freed using these operations. - */ -void __kmem_cache_free_bulk(struct kmem_cache *, size_t, void **); -int __kmem_cache_alloc_bulk(struct kmem_cache *, gfp_t, size_t, void **); - -#if defined(CONFIG_MEMCG) && !defined(CONFIG_SLOB) -/* - * Iterate over all memcg caches of the given root cache. The caller must hold - * slab_mutex. - */ -#define for_each_memcg_cache(iter, root) \ - list_for_each_entry(iter, &(root)->memcg_params.list, \ - memcg_params.list) - -static inline bool is_root_cache(struct kmem_cache *s) -{ - return s->memcg_params.is_root_cache; -} - -static inline bool slab_equal_or_root(struct kmem_cache *s, - struct kmem_cache *p) -{ - return p == s || p == s->memcg_params.root_cache; -} - -/* - * We use suffixes to the name in memcg because we can't have caches - * created in the system with the same name. But when we print them - * locally, better refer to them with the base name - */ -static inline const char *cache_name(struct kmem_cache *s) -{ - if (!is_root_cache(s)) - s = s->memcg_params.root_cache; - return s->name; -} - -/* - * Note, we protect with RCU only the memcg_caches array, not per-memcg caches. - * That said the caller must assure the memcg's cache won't go away by either - * taking a css reference to the owner cgroup, or holding the slab_mutex. - */ -static inline struct kmem_cache * -cache_from_memcg_idx(struct kmem_cache *s, int idx) -{ - struct kmem_cache *cachep; - struct memcg_cache_array *arr; - - rcu_read_lock(); - arr = rcu_dereference(s->memcg_params.memcg_caches); - - /* - * Make sure we will access the up-to-date value. The code updating - * memcg_caches issues a write barrier to match this (see - * memcg_create_kmem_cache()). - */ - cachep = lockless_dereference(arr->entries[idx]); - rcu_read_unlock(); - - return cachep; -} - -static inline struct kmem_cache *memcg_root_cache(struct kmem_cache *s) -{ - if (is_root_cache(s)) - return s; - return s->memcg_params.root_cache; -} - -static __always_inline int memcg_charge_slab(struct page *page, - gfp_t gfp, int order, - struct kmem_cache *s) -{ - int ret; - - if (!memcg_kmem_enabled()) - return 0; - if (is_root_cache(s)) - return 0; - - ret = memcg_kmem_charge_memcg(page, gfp, order, s->memcg_params.memcg); - if (ret) - return ret; - - memcg_kmem_update_page_stat(page, - (s->flags & SLAB_RECLAIM_ACCOUNT) ? - MEMCG_SLAB_RECLAIMABLE : MEMCG_SLAB_UNRECLAIMABLE, - 1 << order); - return 0; -} - -static __always_inline void memcg_uncharge_slab(struct page *page, int order, - struct kmem_cache *s) -{ - if (!memcg_kmem_enabled()) - return; - - memcg_kmem_update_page_stat(page, - (s->flags & SLAB_RECLAIM_ACCOUNT) ? - MEMCG_SLAB_RECLAIMABLE : MEMCG_SLAB_UNRECLAIMABLE, - -(1 << order)); - memcg_kmem_uncharge(page, order); -} - -extern void slab_init_memcg_params(struct kmem_cache *); - -#else /* CONFIG_MEMCG && !CONFIG_SLOB */ - -#define for_each_memcg_cache(iter, root) \ - for ((void)(iter), (void)(root); 0; ) - -static inline bool is_root_cache(struct kmem_cache *s) -{ - return true; -} - -static inline bool slab_equal_or_root(struct kmem_cache *s, - struct kmem_cache *p) -{ - return true; -} - -static inline const char *cache_name(struct kmem_cache *s) -{ - return s->name; -} - -static inline struct kmem_cache * -cache_from_memcg_idx(struct kmem_cache *s, int idx) -{ - return NULL; -} - -static inline struct kmem_cache *memcg_root_cache(struct kmem_cache *s) -{ - return s; -} - -static inline int memcg_charge_slab(struct page *page, gfp_t gfp, int order, - struct kmem_cache *s) -{ - return 0; -} - -static inline void memcg_uncharge_slab(struct page *page, int order, - struct kmem_cache *s) -{ -} - -static inline void slab_init_memcg_params(struct kmem_cache *s) -{ -} -#endif /* CONFIG_MEMCG && !CONFIG_SLOB */ - -static inline struct kmem_cache *cache_from_obj(struct kmem_cache *s, void *x) -{ - struct kmem_cache *cachep; - struct page *page; - - /* - * When kmemcg is not being used, both assignments should return the - * same value. but we don't want to pay the assignment price in that - * case. If it is not compiled in, the compiler should be smart enough - * to not do even the assignment. In that case, slab_equal_or_root - * will also be a constant. - */ - if (!memcg_kmem_enabled() && - !unlikely(s->flags & SLAB_CONSISTENCY_CHECKS)) - return s; - - page = virt_to_head_page(x); - cachep = page->slab_cache; - if (slab_equal_or_root(cachep, s)) - return cachep; - - pr_err("%s: Wrong slab cache. %s but object is from %s\n", - __func__, s->name, cachep->name); - WARN_ON_ONCE(1); - return s; -} - -static inline size_t slab_ksize(const struct kmem_cache *s) -{ -#ifndef CONFIG_SLUB - return s->object_size; - -#else /* CONFIG_SLUB */ -# ifdef CONFIG_SLUB_DEBUG - /* - * Debugging requires use of the padding between object - * and whatever may come after it. - */ - if (s->flags & (SLAB_RED_ZONE | SLAB_POISON)) - return s->object_size; -# endif - if (s->flags & SLAB_KASAN) - return s->object_size; - /* - * If we have the need to store the freelist pointer - * back there or track user information then we can - * only use the space before that information. - */ - if (s->flags & (SLAB_DESTROY_BY_RCU | SLAB_STORE_USER)) - return s->inuse; - /* - * Else we can use all the padding etc for the allocation - */ - return s->size; -#endif -} - -static inline struct kmem_cache *slab_pre_alloc_hook(struct kmem_cache *s, - gfp_t flags) -{ - flags &= gfp_allowed_mask; - lockdep_trace_alloc(flags); - might_sleep_if(gfpflags_allow_blocking(flags)); - - if (should_failslab(s, flags)) - return NULL; - - if (memcg_kmem_enabled() && - ((flags & __GFP_ACCOUNT) || (s->flags & SLAB_ACCOUNT))) - return memcg_kmem_get_cache(s); - - return s; -} - -static inline void slab_post_alloc_hook(struct kmem_cache *s, gfp_t flags, - size_t size, void **p) -{ - size_t i; - - flags &= gfp_allowed_mask; - for (i = 0; i < size; i++) { - void *object = p[i]; - - kmemcheck_slab_alloc(s, flags, object, slab_ksize(s)); - kmemleak_alloc_recursive(object, s->object_size, 1, - s->flags, flags); - kasan_slab_alloc(s, object, flags); - } - - if (memcg_kmem_enabled()) - memcg_kmem_put_cache(s); -} - -#ifndef CONFIG_SLOB -/* - * The slab lists for all objects. - */ -struct kmem_cache_node { - spinlock_t list_lock; - -#ifdef CONFIG_SLAB - struct list_head slabs_partial; /* partial list first, better asm code */ - struct list_head slabs_full; - struct list_head slabs_free; - unsigned long num_slabs; - unsigned long free_objects; - unsigned int free_limit; - unsigned int colour_next; /* Per-node cache coloring */ - struct array_cache *shared; /* shared per node */ - struct alien_cache **alien; /* on other nodes */ - unsigned long next_reap; /* updated without locking */ - int free_touched; /* updated without locking */ -#endif - -#ifdef CONFIG_SLUB - unsigned long nr_partial; - struct list_head partial; -#ifdef CONFIG_SLUB_DEBUG - atomic_long_t nr_slabs; - atomic_long_t total_objects; - struct list_head full; -#endif -#endif - -}; - -static inline struct kmem_cache_node *get_node(struct kmem_cache *s, int node) -{ - return s->node[node]; -} - -/* - * Iterator over all nodes. The body will be executed for each node that has - * a kmem_cache_node structure allocated (which is true for all online nodes) - */ -#define for_each_kmem_cache_node(__s, __node, __n) \ - for (__node = 0; __node < nr_node_ids; __node++) \ - if ((__n = get_node(__s, __node))) - -#endif - -void *slab_start(struct seq_file *m, loff_t *pos); -void *slab_next(struct seq_file *m, void *p, loff_t *pos); -void slab_stop(struct seq_file *m, void *p); -int memcg_slab_show(struct seq_file *m, void *p); - -void ___cache_free(struct kmem_cache *cache, void *x, unsigned long addr); - -#ifdef CONFIG_SLAB_FREELIST_RANDOM -int cache_random_seq_create(struct kmem_cache *cachep, unsigned int count, - gfp_t gfp); -void cache_random_seq_destroy(struct kmem_cache *cachep); -#else -static inline int cache_random_seq_create(struct kmem_cache *cachep, - unsigned int count, gfp_t gfp) -{ - return 0; -} -static inline void cache_random_seq_destroy(struct kmem_cache *cachep) { } -#endif /* CONFIG_SLAB_FREELIST_RANDOM */ - -#endif /* MM_SLAB_H */ diff --git a/src/linux/mm/slab_common.c b/src/linux/mm/slab_common.c deleted file mode 100644 index 329b038..0000000 --- a/src/linux/mm/slab_common.c +++ /dev/null @@ -1,1333 +0,0 @@ -/* - * Slab allocator functions that are independent of the allocator strategy - * - * (C) 2012 Christoph Lameter - */ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define CREATE_TRACE_POINTS -#include - -#include "slab.h" - -enum slab_state slab_state; -LIST_HEAD(slab_caches); -DEFINE_MUTEX(slab_mutex); -struct kmem_cache *kmem_cache; - -/* - * Set of flags that will prevent slab merging - */ -#define SLAB_NEVER_MERGE (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER | \ - SLAB_TRACE | SLAB_DESTROY_BY_RCU | SLAB_NOLEAKTRACE | \ - SLAB_FAILSLAB | SLAB_KASAN) - -#define SLAB_MERGE_SAME (SLAB_RECLAIM_ACCOUNT | SLAB_CACHE_DMA | \ - SLAB_NOTRACK | SLAB_ACCOUNT) - -/* - * Merge control. If this is set then no merging of slab caches will occur. - * (Could be removed. This was introduced to pacify the merge skeptics.) - */ -static int slab_nomerge; - -static int __init setup_slab_nomerge(char *str) -{ - slab_nomerge = 1; - return 1; -} - -#ifdef CONFIG_SLUB -__setup_param("slub_nomerge", slub_nomerge, setup_slab_nomerge, 0); -#endif - -__setup("slab_nomerge", setup_slab_nomerge); - -/* - * Determine the size of a slab object - */ -unsigned int kmem_cache_size(struct kmem_cache *s) -{ - return s->object_size; -} -EXPORT_SYMBOL(kmem_cache_size); - -#ifdef CONFIG_DEBUG_VM -static int kmem_cache_sanity_check(const char *name, size_t size) -{ - struct kmem_cache *s = NULL; - - if (!name || in_interrupt() || size < sizeof(void *) || - size > KMALLOC_MAX_SIZE) { - pr_err("kmem_cache_create(%s) integrity check failed\n", name); - return -EINVAL; - } - - list_for_each_entry(s, &slab_caches, list) { - char tmp; - int res; - - /* - * This happens when the module gets unloaded and doesn't - * destroy its slab cache and no-one else reuses the vmalloc - * area of the module. Print a warning. - */ - res = probe_kernel_address(s->name, tmp); - if (res) { - pr_err("Slab cache with size %d has lost its name\n", - s->object_size); - continue; - } - } - - WARN_ON(strchr(name, ' ')); /* It confuses parsers */ - return 0; -} -#else -static inline int kmem_cache_sanity_check(const char *name, size_t size) -{ - return 0; -} -#endif - -void __kmem_cache_free_bulk(struct kmem_cache *s, size_t nr, void **p) -{ - size_t i; - - for (i = 0; i < nr; i++) { - if (s) - kmem_cache_free(s, p[i]); - else - kfree(p[i]); - } -} - -int __kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t nr, - void **p) -{ - size_t i; - - for (i = 0; i < nr; i++) { - void *x = p[i] = kmem_cache_alloc(s, flags); - if (!x) { - __kmem_cache_free_bulk(s, i, p); - return 0; - } - } - return i; -} - -#if defined(CONFIG_MEMCG) && !defined(CONFIG_SLOB) -void slab_init_memcg_params(struct kmem_cache *s) -{ - s->memcg_params.is_root_cache = true; - INIT_LIST_HEAD(&s->memcg_params.list); - RCU_INIT_POINTER(s->memcg_params.memcg_caches, NULL); -} - -static int init_memcg_params(struct kmem_cache *s, - struct mem_cgroup *memcg, struct kmem_cache *root_cache) -{ - struct memcg_cache_array *arr; - - if (memcg) { - s->memcg_params.is_root_cache = false; - s->memcg_params.memcg = memcg; - s->memcg_params.root_cache = root_cache; - return 0; - } - - slab_init_memcg_params(s); - - if (!memcg_nr_cache_ids) - return 0; - - arr = kzalloc(sizeof(struct memcg_cache_array) + - memcg_nr_cache_ids * sizeof(void *), - GFP_KERNEL); - if (!arr) - return -ENOMEM; - - RCU_INIT_POINTER(s->memcg_params.memcg_caches, arr); - return 0; -} - -static void destroy_memcg_params(struct kmem_cache *s) -{ - if (is_root_cache(s)) - kfree(rcu_access_pointer(s->memcg_params.memcg_caches)); -} - -static int update_memcg_params(struct kmem_cache *s, int new_array_size) -{ - struct memcg_cache_array *old, *new; - - if (!is_root_cache(s)) - return 0; - - new = kzalloc(sizeof(struct memcg_cache_array) + - new_array_size * sizeof(void *), GFP_KERNEL); - if (!new) - return -ENOMEM; - - old = rcu_dereference_protected(s->memcg_params.memcg_caches, - lockdep_is_held(&slab_mutex)); - if (old) - memcpy(new->entries, old->entries, - memcg_nr_cache_ids * sizeof(void *)); - - rcu_assign_pointer(s->memcg_params.memcg_caches, new); - if (old) - kfree_rcu(old, rcu); - return 0; -} - -int memcg_update_all_caches(int num_memcgs) -{ - struct kmem_cache *s; - int ret = 0; - - mutex_lock(&slab_mutex); - list_for_each_entry(s, &slab_caches, list) { - ret = update_memcg_params(s, num_memcgs); - /* - * Instead of freeing the memory, we'll just leave the caches - * up to this point in an updated state. - */ - if (ret) - break; - } - mutex_unlock(&slab_mutex); - return ret; -} -#else -static inline int init_memcg_params(struct kmem_cache *s, - struct mem_cgroup *memcg, struct kmem_cache *root_cache) -{ - return 0; -} - -static inline void destroy_memcg_params(struct kmem_cache *s) -{ -} -#endif /* CONFIG_MEMCG && !CONFIG_SLOB */ - -/* - * Find a mergeable slab cache - */ -int slab_unmergeable(struct kmem_cache *s) -{ - if (slab_nomerge || (s->flags & SLAB_NEVER_MERGE)) - return 1; - - if (!is_root_cache(s)) - return 1; - - if (s->ctor) - return 1; - - /* - * We may have set a slab to be unmergeable during bootstrap. - */ - if (s->refcount < 0) - return 1; - - return 0; -} - -struct kmem_cache *find_mergeable(size_t size, size_t align, - unsigned long flags, const char *name, void (*ctor)(void *)) -{ - struct kmem_cache *s; - - if (slab_nomerge || (flags & SLAB_NEVER_MERGE)) - return NULL; - - if (ctor) - return NULL; - - size = ALIGN(size, sizeof(void *)); - align = calculate_alignment(flags, align, size); - size = ALIGN(size, align); - flags = kmem_cache_flags(size, flags, name, NULL); - - list_for_each_entry_reverse(s, &slab_caches, list) { - if (slab_unmergeable(s)) - continue; - - if (size > s->size) - continue; - - if ((flags & SLAB_MERGE_SAME) != (s->flags & SLAB_MERGE_SAME)) - continue; - /* - * Check if alignment is compatible. - * Courtesy of Adrian Drzewiecki - */ - if ((s->size & ~(align - 1)) != s->size) - continue; - - if (s->size - size >= sizeof(void *)) - continue; - - if (IS_ENABLED(CONFIG_SLAB) && align && - (align > s->align || s->align % align)) - continue; - - return s; - } - return NULL; -} - -/* - * Figure out what the alignment of the objects will be given a set of - * flags, a user specified alignment and the size of the objects. - */ -unsigned long calculate_alignment(unsigned long flags, - unsigned long align, unsigned long size) -{ - /* - * If the user wants hardware cache aligned objects then follow that - * suggestion if the object is sufficiently large. - * - * The hardware cache alignment cannot override the specified - * alignment though. If that is greater then use it. - */ - if (flags & SLAB_HWCACHE_ALIGN) { - unsigned long ralign = cache_line_size(); - while (size <= ralign / 2) - ralign /= 2; - align = max(align, ralign); - } - - if (align < ARCH_SLAB_MINALIGN) - align = ARCH_SLAB_MINALIGN; - - return ALIGN(align, sizeof(void *)); -} - -static struct kmem_cache *create_cache(const char *name, - size_t object_size, size_t size, size_t align, - unsigned long flags, void (*ctor)(void *), - struct mem_cgroup *memcg, struct kmem_cache *root_cache) -{ - struct kmem_cache *s; - int err; - - err = -ENOMEM; - s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL); - if (!s) - goto out; - - s->name = name; - s->object_size = object_size; - s->size = size; - s->align = align; - s->ctor = ctor; - - err = init_memcg_params(s, memcg, root_cache); - if (err) - goto out_free_cache; - - err = __kmem_cache_create(s, flags); - if (err) - goto out_free_cache; - - s->refcount = 1; - list_add(&s->list, &slab_caches); -out: - if (err) - return ERR_PTR(err); - return s; - -out_free_cache: - destroy_memcg_params(s); - kmem_cache_free(kmem_cache, s); - goto out; -} - -/* - * kmem_cache_create - Create a cache. - * @name: A string which is used in /proc/slabinfo to identify this cache. - * @size: The size of objects to be created in this cache. - * @align: The required alignment for the objects. - * @flags: SLAB flags - * @ctor: A constructor for the objects. - * - * Returns a ptr to the cache on success, NULL on failure. - * Cannot be called within a interrupt, but can be interrupted. - * The @ctor is run when new pages are allocated by the cache. - * - * The flags are - * - * %SLAB_POISON - Poison the slab with a known test pattern (a5a5a5a5) - * to catch references to uninitialised memory. - * - * %SLAB_RED_ZONE - Insert `Red' zones around the allocated memory to check - * for buffer overruns. - * - * %SLAB_HWCACHE_ALIGN - Align the objects in this cache to a hardware - * cacheline. This can be beneficial if you're counting cycles as closely - * as davem. - */ -struct kmem_cache * -kmem_cache_create(const char *name, size_t size, size_t align, - unsigned long flags, void (*ctor)(void *)) -{ - struct kmem_cache *s = NULL; - const char *cache_name; - int err; - - get_online_cpus(); - get_online_mems(); - memcg_get_cache_ids(); - - mutex_lock(&slab_mutex); - - err = kmem_cache_sanity_check(name, size); - if (err) { - goto out_unlock; - } - - /* - * Some allocators will constraint the set of valid flags to a subset - * of all flags. We expect them to define CACHE_CREATE_MASK in this - * case, and we'll just provide them with a sanitized version of the - * passed flags. - */ - flags &= CACHE_CREATE_MASK; - - s = __kmem_cache_alias(name, size, align, flags, ctor); - if (s) - goto out_unlock; - - cache_name = kstrdup_const(name, GFP_KERNEL); - if (!cache_name) { - err = -ENOMEM; - goto out_unlock; - } - - s = create_cache(cache_name, size, size, - calculate_alignment(flags, align, size), - flags, ctor, NULL, NULL); - if (IS_ERR(s)) { - err = PTR_ERR(s); - kfree_const(cache_name); - } - -out_unlock: - mutex_unlock(&slab_mutex); - - memcg_put_cache_ids(); - put_online_mems(); - put_online_cpus(); - - if (err) { - if (flags & SLAB_PANIC) - panic("kmem_cache_create: Failed to create slab '%s'. Error %d\n", - name, err); - else { - pr_warn("kmem_cache_create(%s) failed with error %d\n", - name, err); - dump_stack(); - } - return NULL; - } - return s; -} -EXPORT_SYMBOL(kmem_cache_create); - -static int shutdown_cache(struct kmem_cache *s, - struct list_head *release, bool *need_rcu_barrier) -{ - if (__kmem_cache_shutdown(s) != 0) - return -EBUSY; - - if (s->flags & SLAB_DESTROY_BY_RCU) - *need_rcu_barrier = true; - - list_move(&s->list, release); - return 0; -} - -static void release_caches(struct list_head *release, bool need_rcu_barrier) -{ - struct kmem_cache *s, *s2; - - if (need_rcu_barrier) - rcu_barrier(); - - list_for_each_entry_safe(s, s2, release, list) { -#ifdef SLAB_SUPPORTS_SYSFS - sysfs_slab_remove(s); -#else - slab_kmem_cache_release(s); -#endif - } -} - -#if defined(CONFIG_MEMCG) && !defined(CONFIG_SLOB) -/* - * memcg_create_kmem_cache - Create a cache for a memory cgroup. - * @memcg: The memory cgroup the new cache is for. - * @root_cache: The parent of the new cache. - * - * This function attempts to create a kmem cache that will serve allocation - * requests going from @memcg to @root_cache. The new cache inherits properties - * from its parent. - */ -void memcg_create_kmem_cache(struct mem_cgroup *memcg, - struct kmem_cache *root_cache) -{ - static char memcg_name_buf[NAME_MAX + 1]; /* protected by slab_mutex */ - struct cgroup_subsys_state *css = &memcg->css; - struct memcg_cache_array *arr; - struct kmem_cache *s = NULL; - char *cache_name; - int idx; - - get_online_cpus(); - get_online_mems(); - - mutex_lock(&slab_mutex); - - /* - * The memory cgroup could have been offlined while the cache - * creation work was pending. - */ - if (memcg->kmem_state != KMEM_ONLINE) - goto out_unlock; - - idx = memcg_cache_id(memcg); - arr = rcu_dereference_protected(root_cache->memcg_params.memcg_caches, - lockdep_is_held(&slab_mutex)); - - /* - * Since per-memcg caches are created asynchronously on first - * allocation (see memcg_kmem_get_cache()), several threads can try to - * create the same cache, but only one of them may succeed. - */ - if (arr->entries[idx]) - goto out_unlock; - - cgroup_name(css->cgroup, memcg_name_buf, sizeof(memcg_name_buf)); - cache_name = kasprintf(GFP_KERNEL, "%s(%llu:%s)", root_cache->name, - css->serial_nr, memcg_name_buf); - if (!cache_name) - goto out_unlock; - - s = create_cache(cache_name, root_cache->object_size, - root_cache->size, root_cache->align, - root_cache->flags & CACHE_CREATE_MASK, - root_cache->ctor, memcg, root_cache); - /* - * If we could not create a memcg cache, do not complain, because - * that's not critical at all as we can always proceed with the root - * cache. - */ - if (IS_ERR(s)) { - kfree(cache_name); - goto out_unlock; - } - - list_add(&s->memcg_params.list, &root_cache->memcg_params.list); - - /* - * Since readers won't lock (see cache_from_memcg_idx()), we need a - * barrier here to ensure nobody will see the kmem_cache partially - * initialized. - */ - smp_wmb(); - arr->entries[idx] = s; - -out_unlock: - mutex_unlock(&slab_mutex); - - put_online_mems(); - put_online_cpus(); -} - -void memcg_deactivate_kmem_caches(struct mem_cgroup *memcg) -{ - int idx; - struct memcg_cache_array *arr; - struct kmem_cache *s, *c; - - idx = memcg_cache_id(memcg); - - get_online_cpus(); - get_online_mems(); - - mutex_lock(&slab_mutex); - list_for_each_entry(s, &slab_caches, list) { - if (!is_root_cache(s)) - continue; - - arr = rcu_dereference_protected(s->memcg_params.memcg_caches, - lockdep_is_held(&slab_mutex)); - c = arr->entries[idx]; - if (!c) - continue; - - __kmem_cache_shrink(c, true); - arr->entries[idx] = NULL; - } - mutex_unlock(&slab_mutex); - - put_online_mems(); - put_online_cpus(); -} - -static int __shutdown_memcg_cache(struct kmem_cache *s, - struct list_head *release, bool *need_rcu_barrier) -{ - BUG_ON(is_root_cache(s)); - - if (shutdown_cache(s, release, need_rcu_barrier)) - return -EBUSY; - - list_del(&s->memcg_params.list); - return 0; -} - -void memcg_destroy_kmem_caches(struct mem_cgroup *memcg) -{ - LIST_HEAD(release); - bool need_rcu_barrier = false; - struct kmem_cache *s, *s2; - - get_online_cpus(); - get_online_mems(); - - mutex_lock(&slab_mutex); - list_for_each_entry_safe(s, s2, &slab_caches, list) { - if (is_root_cache(s) || s->memcg_params.memcg != memcg) - continue; - /* - * The cgroup is about to be freed and therefore has no charges - * left. Hence, all its caches must be empty by now. - */ - BUG_ON(__shutdown_memcg_cache(s, &release, &need_rcu_barrier)); - } - mutex_unlock(&slab_mutex); - - put_online_mems(); - put_online_cpus(); - - release_caches(&release, need_rcu_barrier); -} - -static int shutdown_memcg_caches(struct kmem_cache *s, - struct list_head *release, bool *need_rcu_barrier) -{ - struct memcg_cache_array *arr; - struct kmem_cache *c, *c2; - LIST_HEAD(busy); - int i; - - BUG_ON(!is_root_cache(s)); - - /* - * First, shutdown active caches, i.e. caches that belong to online - * memory cgroups. - */ - arr = rcu_dereference_protected(s->memcg_params.memcg_caches, - lockdep_is_held(&slab_mutex)); - for_each_memcg_cache_index(i) { - c = arr->entries[i]; - if (!c) - continue; - if (__shutdown_memcg_cache(c, release, need_rcu_barrier)) - /* - * The cache still has objects. Move it to a temporary - * list so as not to try to destroy it for a second - * time while iterating over inactive caches below. - */ - list_move(&c->memcg_params.list, &busy); - else - /* - * The cache is empty and will be destroyed soon. Clear - * the pointer to it in the memcg_caches array so that - * it will never be accessed even if the root cache - * stays alive. - */ - arr->entries[i] = NULL; - } - - /* - * Second, shutdown all caches left from memory cgroups that are now - * offline. - */ - list_for_each_entry_safe(c, c2, &s->memcg_params.list, - memcg_params.list) - __shutdown_memcg_cache(c, release, need_rcu_barrier); - - list_splice(&busy, &s->memcg_params.list); - - /* - * A cache being destroyed must be empty. In particular, this means - * that all per memcg caches attached to it must be empty too. - */ - if (!list_empty(&s->memcg_params.list)) - return -EBUSY; - return 0; -} -#else -static inline int shutdown_memcg_caches(struct kmem_cache *s, - struct list_head *release, bool *need_rcu_barrier) -{ - return 0; -} -#endif /* CONFIG_MEMCG && !CONFIG_SLOB */ - -void slab_kmem_cache_release(struct kmem_cache *s) -{ - __kmem_cache_release(s); - destroy_memcg_params(s); - kfree_const(s->name); - kmem_cache_free(kmem_cache, s); -} - -void kmem_cache_destroy(struct kmem_cache *s) -{ - LIST_HEAD(release); - bool need_rcu_barrier = false; - int err; - - if (unlikely(!s)) - return; - - get_online_cpus(); - get_online_mems(); - - kasan_cache_destroy(s); - mutex_lock(&slab_mutex); - - s->refcount--; - if (s->refcount) - goto out_unlock; - - err = shutdown_memcg_caches(s, &release, &need_rcu_barrier); - if (!err) - err = shutdown_cache(s, &release, &need_rcu_barrier); - - if (err) { - pr_err("kmem_cache_destroy %s: Slab cache still has objects\n", - s->name); - dump_stack(); - } -out_unlock: - mutex_unlock(&slab_mutex); - - put_online_mems(); - put_online_cpus(); - - release_caches(&release, need_rcu_barrier); -} -EXPORT_SYMBOL(kmem_cache_destroy); - -/** - * kmem_cache_shrink - Shrink a cache. - * @cachep: The cache to shrink. - * - * Releases as many slabs as possible for a cache. - * To help debugging, a zero exit status indicates all slabs were released. - */ -int kmem_cache_shrink(struct kmem_cache *cachep) -{ - int ret; - - get_online_cpus(); - get_online_mems(); - kasan_cache_shrink(cachep); - ret = __kmem_cache_shrink(cachep, false); - put_online_mems(); - put_online_cpus(); - return ret; -} -EXPORT_SYMBOL(kmem_cache_shrink); - -bool slab_is_available(void) -{ - return slab_state >= UP; -} - -#ifndef CONFIG_SLOB -/* Create a cache during boot when no slab services are available yet */ -void __init create_boot_cache(struct kmem_cache *s, const char *name, size_t size, - unsigned long flags) -{ - int err; - - s->name = name; - s->size = s->object_size = size; - s->align = calculate_alignment(flags, ARCH_KMALLOC_MINALIGN, size); - - slab_init_memcg_params(s); - - err = __kmem_cache_create(s, flags); - - if (err) - panic("Creation of kmalloc slab %s size=%zu failed. Reason %d\n", - name, size, err); - - s->refcount = -1; /* Exempt from merging for now */ -} - -struct kmem_cache *__init create_kmalloc_cache(const char *name, size_t size, - unsigned long flags) -{ - struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT); - - if (!s) - panic("Out of memory when creating slab %s\n", name); - - create_boot_cache(s, name, size, flags); - list_add(&s->list, &slab_caches); - s->refcount = 1; - return s; -} - -struct kmem_cache *kmalloc_caches[KMALLOC_SHIFT_HIGH + 1]; -EXPORT_SYMBOL(kmalloc_caches); - -#ifdef CONFIG_ZONE_DMA -struct kmem_cache *kmalloc_dma_caches[KMALLOC_SHIFT_HIGH + 1]; -EXPORT_SYMBOL(kmalloc_dma_caches); -#endif - -/* - * Conversion table for small slabs sizes / 8 to the index in the - * kmalloc array. This is necessary for slabs < 192 since we have non power - * of two cache sizes there. The size of larger slabs can be determined using - * fls. - */ -static s8 size_index[24] = { - 3, /* 8 */ - 4, /* 16 */ - 5, /* 24 */ - 5, /* 32 */ - 6, /* 40 */ - 6, /* 48 */ - 6, /* 56 */ - 6, /* 64 */ - 1, /* 72 */ - 1, /* 80 */ - 1, /* 88 */ - 1, /* 96 */ - 7, /* 104 */ - 7, /* 112 */ - 7, /* 120 */ - 7, /* 128 */ - 2, /* 136 */ - 2, /* 144 */ - 2, /* 152 */ - 2, /* 160 */ - 2, /* 168 */ - 2, /* 176 */ - 2, /* 184 */ - 2 /* 192 */ -}; - -static inline int size_index_elem(size_t bytes) -{ - return (bytes - 1) / 8; -} - -/* - * Find the kmem_cache structure that serves a given size of - * allocation - */ -struct kmem_cache *kmalloc_slab(size_t size, gfp_t flags) -{ - int index; - - if (unlikely(size > KMALLOC_MAX_SIZE)) { - WARN_ON_ONCE(!(flags & __GFP_NOWARN)); - return NULL; - } - - if (size <= 192) { - if (!size) - return ZERO_SIZE_PTR; - - index = size_index[size_index_elem(size)]; - } else - index = fls(size - 1); - -#ifdef CONFIG_ZONE_DMA - if (unlikely((flags & GFP_DMA))) - return kmalloc_dma_caches[index]; - -#endif - return kmalloc_caches[index]; -} - -/* - * kmalloc_info[] is to make slub_debug=,kmalloc-xx option work at boot time. - * kmalloc_index() supports up to 2^26=64MB, so the final entry of the table is - * kmalloc-67108864. - */ -static struct { - const char *name; - unsigned long size; -} const kmalloc_info[] __initconst = { - {NULL, 0}, {"kmalloc-96", 96}, - {"kmalloc-192", 192}, {"kmalloc-8", 8}, - {"kmalloc-16", 16}, {"kmalloc-32", 32}, - {"kmalloc-64", 64}, {"kmalloc-128", 128}, - {"kmalloc-256", 256}, {"kmalloc-512", 512}, - {"kmalloc-1024", 1024}, {"kmalloc-2048", 2048}, - {"kmalloc-4096", 4096}, {"kmalloc-8192", 8192}, - {"kmalloc-16384", 16384}, {"kmalloc-32768", 32768}, - {"kmalloc-65536", 65536}, {"kmalloc-131072", 131072}, - {"kmalloc-262144", 262144}, {"kmalloc-524288", 524288}, - {"kmalloc-1048576", 1048576}, {"kmalloc-2097152", 2097152}, - {"kmalloc-4194304", 4194304}, {"kmalloc-8388608", 8388608}, - {"kmalloc-16777216", 16777216}, {"kmalloc-33554432", 33554432}, - {"kmalloc-67108864", 67108864} -}; - -/* - * Patch up the size_index table if we have strange large alignment - * requirements for the kmalloc array. This is only the case for - * MIPS it seems. The standard arches will not generate any code here. - * - * Largest permitted alignment is 256 bytes due to the way we - * handle the index determination for the smaller caches. - * - * Make sure that nothing crazy happens if someone starts tinkering - * around with ARCH_KMALLOC_MINALIGN - */ -void __init setup_kmalloc_cache_index_table(void) -{ - int i; - - BUILD_BUG_ON(KMALLOC_MIN_SIZE > 256 || - (KMALLOC_MIN_SIZE & (KMALLOC_MIN_SIZE - 1))); - - for (i = 8; i < KMALLOC_MIN_SIZE; i += 8) { - int elem = size_index_elem(i); - - if (elem >= ARRAY_SIZE(size_index)) - break; - size_index[elem] = KMALLOC_SHIFT_LOW; - } - - if (KMALLOC_MIN_SIZE >= 64) { - /* - * The 96 byte size cache is not used if the alignment - * is 64 byte. - */ - for (i = 64 + 8; i <= 96; i += 8) - size_index[size_index_elem(i)] = 7; - - } - - if (KMALLOC_MIN_SIZE >= 128) { - /* - * The 192 byte sized cache is not used if the alignment - * is 128 byte. Redirect kmalloc to use the 256 byte cache - * instead. - */ - for (i = 128 + 8; i <= 192; i += 8) - size_index[size_index_elem(i)] = 8; - } -} - -static void __init new_kmalloc_cache(int idx, unsigned long flags) -{ - kmalloc_caches[idx] = create_kmalloc_cache(kmalloc_info[idx].name, - kmalloc_info[idx].size, flags); -} - -/* - * Create the kmalloc array. Some of the regular kmalloc arrays - * may already have been created because they were needed to - * enable allocations for slab creation. - */ -void __init create_kmalloc_caches(unsigned long flags) -{ - int i; - - for (i = KMALLOC_SHIFT_LOW; i <= KMALLOC_SHIFT_HIGH; i++) { - if (!kmalloc_caches[i]) - new_kmalloc_cache(i, flags); - - /* - * Caches that are not of the two-to-the-power-of size. - * These have to be created immediately after the - * earlier power of two caches - */ - if (KMALLOC_MIN_SIZE <= 32 && !kmalloc_caches[1] && i == 6) - new_kmalloc_cache(1, flags); - if (KMALLOC_MIN_SIZE <= 64 && !kmalloc_caches[2] && i == 7) - new_kmalloc_cache(2, flags); - } - - /* Kmalloc array is now usable */ - slab_state = UP; - -#ifdef CONFIG_ZONE_DMA - for (i = 0; i <= KMALLOC_SHIFT_HIGH; i++) { - struct kmem_cache *s = kmalloc_caches[i]; - - if (s) { - int size = kmalloc_size(i); - char *n = kasprintf(GFP_NOWAIT, - "dma-kmalloc-%d", size); - - BUG_ON(!n); - kmalloc_dma_caches[i] = create_kmalloc_cache(n, - size, SLAB_CACHE_DMA | flags); - } - } -#endif -} -#endif /* !CONFIG_SLOB */ - -/* - * To avoid unnecessary overhead, we pass through large allocation requests - * directly to the page allocator. We use __GFP_COMP, because we will need to - * know the allocation order to free the pages properly in kfree. - */ -void *kmalloc_order(size_t size, gfp_t flags, unsigned int order) -{ - void *ret; - struct page *page; - - flags |= __GFP_COMP; - page = alloc_pages(flags, order); - ret = page ? page_address(page) : NULL; - kmemleak_alloc(ret, size, 1, flags); - kasan_kmalloc_large(ret, size, flags); - return ret; -} -EXPORT_SYMBOL(kmalloc_order); - -#ifdef CONFIG_TRACING -void *kmalloc_order_trace(size_t size, gfp_t flags, unsigned int order) -{ - void *ret = kmalloc_order(size, flags, order); - trace_kmalloc(_RET_IP_, ret, size, PAGE_SIZE << order, flags); - return ret; -} -EXPORT_SYMBOL(kmalloc_order_trace); -#endif - -#ifdef CONFIG_SLAB_FREELIST_RANDOM -/* Randomize a generic freelist */ -static void freelist_randomize(struct rnd_state *state, unsigned int *list, - size_t count) -{ - size_t i; - unsigned int rand; - - for (i = 0; i < count; i++) - list[i] = i; - - /* Fisher-Yates shuffle */ - for (i = count - 1; i > 0; i--) { - rand = prandom_u32_state(state); - rand %= (i + 1); - swap(list[i], list[rand]); - } -} - -/* Create a random sequence per cache */ -int cache_random_seq_create(struct kmem_cache *cachep, unsigned int count, - gfp_t gfp) -{ - struct rnd_state state; - - if (count < 2 || cachep->random_seq) - return 0; - - cachep->random_seq = kcalloc(count, sizeof(unsigned int), gfp); - if (!cachep->random_seq) - return -ENOMEM; - - /* Get best entropy at this stage of boot */ - prandom_seed_state(&state, get_random_long()); - - freelist_randomize(&state, cachep->random_seq, count); - return 0; -} - -/* Destroy the per-cache random freelist sequence */ -void cache_random_seq_destroy(struct kmem_cache *cachep) -{ - kfree(cachep->random_seq); - cachep->random_seq = NULL; -} -#endif /* CONFIG_SLAB_FREELIST_RANDOM */ - -#ifdef CONFIG_SLABINFO - -#ifdef CONFIG_SLAB -#define SLABINFO_RIGHTS (S_IWUSR | S_IRUSR) -#else -#define SLABINFO_RIGHTS S_IRUSR -#endif - -static void print_slabinfo_header(struct seq_file *m) -{ - /* - * Output format version, so at least we can change it - * without _too_ many complaints. - */ -#ifdef CONFIG_DEBUG_SLAB - seq_puts(m, "slabinfo - version: 2.1 (statistics)\n"); -#else - seq_puts(m, "slabinfo - version: 2.1\n"); -#endif - seq_puts(m, "# name "); - seq_puts(m, " : tunables "); - seq_puts(m, " : slabdata "); -#ifdef CONFIG_DEBUG_SLAB - seq_puts(m, " : globalstat "); - seq_puts(m, " : cpustat "); -#endif - seq_putc(m, '\n'); -} - -void *slab_start(struct seq_file *m, loff_t *pos) -{ - mutex_lock(&slab_mutex); - return seq_list_start(&slab_caches, *pos); -} - -void *slab_next(struct seq_file *m, void *p, loff_t *pos) -{ - return seq_list_next(p, &slab_caches, pos); -} - -void slab_stop(struct seq_file *m, void *p) -{ - mutex_unlock(&slab_mutex); -} - -static void -memcg_accumulate_slabinfo(struct kmem_cache *s, struct slabinfo *info) -{ - struct kmem_cache *c; - struct slabinfo sinfo; - - if (!is_root_cache(s)) - return; - - for_each_memcg_cache(c, s) { - memset(&sinfo, 0, sizeof(sinfo)); - get_slabinfo(c, &sinfo); - - info->active_slabs += sinfo.active_slabs; - info->num_slabs += sinfo.num_slabs; - info->shared_avail += sinfo.shared_avail; - info->active_objs += sinfo.active_objs; - info->num_objs += sinfo.num_objs; - } -} - -static void cache_show(struct kmem_cache *s, struct seq_file *m) -{ - struct slabinfo sinfo; - - memset(&sinfo, 0, sizeof(sinfo)); - get_slabinfo(s, &sinfo); - - memcg_accumulate_slabinfo(s, &sinfo); - - seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d", - cache_name(s), sinfo.active_objs, sinfo.num_objs, s->size, - sinfo.objects_per_slab, (1 << sinfo.cache_order)); - - seq_printf(m, " : tunables %4u %4u %4u", - sinfo.limit, sinfo.batchcount, sinfo.shared); - seq_printf(m, " : slabdata %6lu %6lu %6lu", - sinfo.active_slabs, sinfo.num_slabs, sinfo.shared_avail); - slabinfo_show_stats(m, s); - seq_putc(m, '\n'); -} - -static int slab_show(struct seq_file *m, void *p) -{ - struct kmem_cache *s = list_entry(p, struct kmem_cache, list); - - if (p == slab_caches.next) - print_slabinfo_header(m); - if (is_root_cache(s)) - cache_show(s, m); - return 0; -} - -#if defined(CONFIG_MEMCG) && !defined(CONFIG_SLOB) -int memcg_slab_show(struct seq_file *m, void *p) -{ - struct kmem_cache *s = list_entry(p, struct kmem_cache, list); - struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m)); - - if (p == slab_caches.next) - print_slabinfo_header(m); - if (!is_root_cache(s) && s->memcg_params.memcg == memcg) - cache_show(s, m); - return 0; -} -#endif - -/* - * slabinfo_op - iterator that generates /proc/slabinfo - * - * Output layout: - * cache-name - * num-active-objs - * total-objs - * object size - * num-active-slabs - * total-slabs - * num-pages-per-slab - * + further values on SMP and with statistics enabled - */ -static const struct seq_operations slabinfo_op = { - .start = slab_start, - .next = slab_next, - .stop = slab_stop, - .show = slab_show, -}; - -static int slabinfo_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &slabinfo_op); -} - -static const struct file_operations proc_slabinfo_operations = { - .open = slabinfo_open, - .read = seq_read, - .write = slabinfo_write, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int __init slab_proc_init(void) -{ - proc_create("slabinfo", SLABINFO_RIGHTS, NULL, - &proc_slabinfo_operations); - return 0; -} -module_init(slab_proc_init); -#endif /* CONFIG_SLABINFO */ - -static __always_inline void *__do_krealloc(const void *p, size_t new_size, - gfp_t flags) -{ - void *ret; - size_t ks = 0; - - if (p) - ks = ksize(p); - - if (ks >= new_size) { - kasan_krealloc((void *)p, new_size, flags); - return (void *)p; - } - - ret = kmalloc_track_caller(new_size, flags); - if (ret && p) - memcpy(ret, p, ks); - - return ret; -} - -/** - * __krealloc - like krealloc() but don't free @p. - * @p: object to reallocate memory for. - * @new_size: how many bytes of memory are required. - * @flags: the type of memory to allocate. - * - * This function is like krealloc() except it never frees the originally - * allocated buffer. Use this if you don't want to free the buffer immediately - * like, for example, with RCU. - */ -void *__krealloc(const void *p, size_t new_size, gfp_t flags) -{ - if (unlikely(!new_size)) - return ZERO_SIZE_PTR; - - return __do_krealloc(p, new_size, flags); - -} -EXPORT_SYMBOL(__krealloc); - -/** - * krealloc - reallocate memory. The contents will remain unchanged. - * @p: object to reallocate memory for. - * @new_size: how many bytes of memory are required. - * @flags: the type of memory to allocate. - * - * The contents of the object pointed to are preserved up to the - * lesser of the new and old sizes. If @p is %NULL, krealloc() - * behaves exactly like kmalloc(). If @new_size is 0 and @p is not a - * %NULL pointer, the object pointed to is freed. - */ -void *krealloc(const void *p, size_t new_size, gfp_t flags) -{ - void *ret; - - if (unlikely(!new_size)) { - kfree(p); - return ZERO_SIZE_PTR; - } - - ret = __do_krealloc(p, new_size, flags); - if (ret && p != ret) - kfree(p); - - return ret; -} -EXPORT_SYMBOL(krealloc); - -/** - * kzfree - like kfree but zero memory - * @p: object to free memory of - * - * The memory of the object @p points to is zeroed before freed. - * If @p is %NULL, kzfree() does nothing. - * - * Note: this function zeroes the whole allocated buffer which can be a good - * deal bigger than the requested buffer size passed to kmalloc(). So be - * careful when using this function in performance sensitive code. - */ -void kzfree(const void *p) -{ - size_t ks; - void *mem = (void *)p; - - if (unlikely(ZERO_OR_NULL_PTR(mem))) - return; - ks = ksize(mem); - memset(mem, 0, ks); - kfree(mem); -} -EXPORT_SYMBOL(kzfree); - -/* Tracepoints definitions. */ -EXPORT_TRACEPOINT_SYMBOL(kmalloc); -EXPORT_TRACEPOINT_SYMBOL(kmem_cache_alloc); -EXPORT_TRACEPOINT_SYMBOL(kmalloc_node); -EXPORT_TRACEPOINT_SYMBOL(kmem_cache_alloc_node); -EXPORT_TRACEPOINT_SYMBOL(kfree); -EXPORT_TRACEPOINT_SYMBOL(kmem_cache_free); diff --git a/src/linux/mm/slub.c b/src/linux/mm/slub.c deleted file mode 100644 index 2b3e740..0000000 --- a/src/linux/mm/slub.c +++ /dev/null @@ -1,5761 +0,0 @@ -/* - * SLUB: A slab allocator that limits cache line use instead of queuing - * objects in per cpu and per node lists. - * - * The allocator synchronizes using per slab locks or atomic operatios - * and only uses a centralized lock to manage a pool of partial slabs. - * - * (C) 2007 SGI, Christoph Lameter - * (C) 2011 Linux Foundation, Christoph Lameter - */ - -#include -#include /* struct reclaim_state */ -#include -#include -#include -#include -#include -#include "slab.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "internal.h" - -/* - * Lock order: - * 1. slab_mutex (Global Mutex) - * 2. node->list_lock - * 3. slab_lock(page) (Only on some arches and for debugging) - * - * slab_mutex - * - * The role of the slab_mutex is to protect the list of all the slabs - * and to synchronize major metadata changes to slab cache structures. - * - * The slab_lock is only used for debugging and on arches that do not - * have the ability to do a cmpxchg_double. It only protects the second - * double word in the page struct. Meaning - * A. page->freelist -> List of object free in a page - * B. page->counters -> Counters of objects - * C. page->frozen -> frozen state - * - * If a slab is frozen then it is exempt from list management. It is not - * on any list. The processor that froze the slab is the one who can - * perform list operations on the page. Other processors may put objects - * onto the freelist but the processor that froze the slab is the only - * one that can retrieve the objects from the page's freelist. - * - * The list_lock protects the partial and full list on each node and - * the partial slab counter. If taken then no new slabs may be added or - * removed from the lists nor make the number of partial slabs be modified. - * (Note that the total number of slabs is an atomic value that may be - * modified without taking the list lock). - * - * The list_lock is a centralized lock and thus we avoid taking it as - * much as possible. As long as SLUB does not have to handle partial - * slabs, operations can continue without any centralized lock. F.e. - * allocating a long series of objects that fill up slabs does not require - * the list lock. - * Interrupts are disabled during allocation and deallocation in order to - * make the slab allocator safe to use in the context of an irq. In addition - * interrupts are disabled to ensure that the processor does not change - * while handling per_cpu slabs, due to kernel preemption. - * - * SLUB assigns one slab for allocation to each processor. - * Allocations only occur from these slabs called cpu slabs. - * - * Slabs with free elements are kept on a partial list and during regular - * operations no list for full slabs is used. If an object in a full slab is - * freed then the slab will show up again on the partial lists. - * We track full slabs for debugging purposes though because otherwise we - * cannot scan all objects. - * - * Slabs are freed when they become empty. Teardown and setup is - * minimal so we rely on the page allocators per cpu caches for - * fast frees and allocs. - * - * Overloading of page flags that are otherwise used for LRU management. - * - * PageActive The slab is frozen and exempt from list processing. - * This means that the slab is dedicated to a purpose - * such as satisfying allocations for a specific - * processor. Objects may be freed in the slab while - * it is frozen but slab_free will then skip the usual - * list operations. It is up to the processor holding - * the slab to integrate the slab into the slab lists - * when the slab is no longer needed. - * - * One use of this flag is to mark slabs that are - * used for allocations. Then such a slab becomes a cpu - * slab. The cpu slab may be equipped with an additional - * freelist that allows lockless access to - * free objects in addition to the regular freelist - * that requires the slab lock. - * - * PageError Slab requires special handling due to debug - * options set. This moves slab handling out of - * the fast path and disables lockless freelists. - */ - -static inline int kmem_cache_debug(struct kmem_cache *s) -{ -#ifdef CONFIG_SLUB_DEBUG - return unlikely(s->flags & SLAB_DEBUG_FLAGS); -#else - return 0; -#endif -} - -void *fixup_red_left(struct kmem_cache *s, void *p) -{ - if (kmem_cache_debug(s) && s->flags & SLAB_RED_ZONE) - p += s->red_left_pad; - - return p; -} - -static inline bool kmem_cache_has_cpu_partial(struct kmem_cache *s) -{ -#ifdef CONFIG_SLUB_CPU_PARTIAL - return !kmem_cache_debug(s); -#else - return false; -#endif -} - -/* - * Issues still to be resolved: - * - * - Support PAGE_ALLOC_DEBUG. Should be easy to do. - * - * - Variable sizing of the per node arrays - */ - -/* Enable to test recovery from slab corruption on boot */ -#undef SLUB_RESILIENCY_TEST - -/* Enable to log cmpxchg failures */ -#undef SLUB_DEBUG_CMPXCHG - -/* - * Mininum number of partial slabs. These will be left on the partial - * lists even if they are empty. kmem_cache_shrink may reclaim them. - */ -#define MIN_PARTIAL 5 - -/* - * Maximum number of desirable partial slabs. - * The existence of more partial slabs makes kmem_cache_shrink - * sort the partial list by the number of objects in use. - */ -#define MAX_PARTIAL 10 - -#define DEBUG_DEFAULT_FLAGS (SLAB_CONSISTENCY_CHECKS | SLAB_RED_ZONE | \ - SLAB_POISON | SLAB_STORE_USER) - -/* - * These debug flags cannot use CMPXCHG because there might be consistency - * issues when checking or reading debug information - */ -#define SLAB_NO_CMPXCHG (SLAB_CONSISTENCY_CHECKS | SLAB_STORE_USER | \ - SLAB_TRACE) - - -/* - * Debugging flags that require metadata to be stored in the slab. These get - * disabled when slub_debug=O is used and a cache's min order increases with - * metadata. - */ -#define DEBUG_METADATA_FLAGS (SLAB_RED_ZONE | SLAB_POISON | SLAB_STORE_USER) - -#define OO_SHIFT 16 -#define OO_MASK ((1 << OO_SHIFT) - 1) -#define MAX_OBJS_PER_PAGE 32767 /* since page.objects is u15 */ - -/* Internal SLUB flags */ -#define __OBJECT_POISON 0x80000000UL /* Poison object */ -#define __CMPXCHG_DOUBLE 0x40000000UL /* Use cmpxchg_double */ - -/* - * Tracking user of a slab. - */ -#define TRACK_ADDRS_COUNT 16 -struct track { - unsigned long addr; /* Called from address */ -#ifdef CONFIG_STACKTRACE - unsigned long addrs[TRACK_ADDRS_COUNT]; /* Called from address */ -#endif - int cpu; /* Was running on cpu */ - int pid; /* Pid context */ - unsigned long when; /* When did the operation occur */ -}; - -enum track_item { TRACK_ALLOC, TRACK_FREE }; - -#ifdef CONFIG_SYSFS -static int sysfs_slab_add(struct kmem_cache *); -static int sysfs_slab_alias(struct kmem_cache *, const char *); -static void memcg_propagate_slab_attrs(struct kmem_cache *s); -#else -static inline int sysfs_slab_add(struct kmem_cache *s) { return 0; } -static inline int sysfs_slab_alias(struct kmem_cache *s, const char *p) - { return 0; } -static inline void memcg_propagate_slab_attrs(struct kmem_cache *s) { } -#endif - -static inline void stat(const struct kmem_cache *s, enum stat_item si) -{ -#ifdef CONFIG_SLUB_STATS - /* - * The rmw is racy on a preemptible kernel but this is acceptable, so - * avoid this_cpu_add()'s irq-disable overhead. - */ - raw_cpu_inc(s->cpu_slab->stat[si]); -#endif -} - -/******************************************************************** - * Core slab cache functions - *******************************************************************/ - -static inline void *get_freepointer(struct kmem_cache *s, void *object) -{ - return *(void **)(object + s->offset); -} - -static void prefetch_freepointer(const struct kmem_cache *s, void *object) -{ - prefetch(object + s->offset); -} - -static inline void *get_freepointer_safe(struct kmem_cache *s, void *object) -{ - void *p; - - if (!debug_pagealloc_enabled()) - return get_freepointer(s, object); - - probe_kernel_read(&p, (void **)(object + s->offset), sizeof(p)); - return p; -} - -static inline void set_freepointer(struct kmem_cache *s, void *object, void *fp) -{ - *(void **)(object + s->offset) = fp; -} - -/* Loop over all objects in a slab */ -#define for_each_object(__p, __s, __addr, __objects) \ - for (__p = fixup_red_left(__s, __addr); \ - __p < (__addr) + (__objects) * (__s)->size; \ - __p += (__s)->size) - -#define for_each_object_idx(__p, __idx, __s, __addr, __objects) \ - for (__p = fixup_red_left(__s, __addr), __idx = 1; \ - __idx <= __objects; \ - __p += (__s)->size, __idx++) - -/* Determine object index from a given position */ -static inline int slab_index(void *p, struct kmem_cache *s, void *addr) -{ - return (p - addr) / s->size; -} - -static inline int order_objects(int order, unsigned long size, int reserved) -{ - return ((PAGE_SIZE << order) - reserved) / size; -} - -static inline struct kmem_cache_order_objects oo_make(int order, - unsigned long size, int reserved) -{ - struct kmem_cache_order_objects x = { - (order << OO_SHIFT) + order_objects(order, size, reserved) - }; - - return x; -} - -static inline int oo_order(struct kmem_cache_order_objects x) -{ - return x.x >> OO_SHIFT; -} - -static inline int oo_objects(struct kmem_cache_order_objects x) -{ - return x.x & OO_MASK; -} - -/* - * Per slab locking using the pagelock - */ -static __always_inline void slab_lock(struct page *page) -{ - VM_BUG_ON_PAGE(PageTail(page), page); - bit_spin_lock(PG_locked, &page->flags); -} - -static __always_inline void slab_unlock(struct page *page) -{ - VM_BUG_ON_PAGE(PageTail(page), page); - __bit_spin_unlock(PG_locked, &page->flags); -} - -static inline void set_page_slub_counters(struct page *page, unsigned long counters_new) -{ - struct page tmp; - tmp.counters = counters_new; - /* - * page->counters can cover frozen/inuse/objects as well - * as page->_refcount. If we assign to ->counters directly - * we run the risk of losing updates to page->_refcount, so - * be careful and only assign to the fields we need. - */ - page->frozen = tmp.frozen; - page->inuse = tmp.inuse; - page->objects = tmp.objects; -} - -/* Interrupts must be disabled (for the fallback code to work right) */ -static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page, - void *freelist_old, unsigned long counters_old, - void *freelist_new, unsigned long counters_new, - const char *n) -{ - VM_BUG_ON(!irqs_disabled()); -#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \ - defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE) - if (s->flags & __CMPXCHG_DOUBLE) { - if (cmpxchg_double(&page->freelist, &page->counters, - freelist_old, counters_old, - freelist_new, counters_new)) - return true; - } else -#endif - { - slab_lock(page); - if (page->freelist == freelist_old && - page->counters == counters_old) { - page->freelist = freelist_new; - set_page_slub_counters(page, counters_new); - slab_unlock(page); - return true; - } - slab_unlock(page); - } - - cpu_relax(); - stat(s, CMPXCHG_DOUBLE_FAIL); - -#ifdef SLUB_DEBUG_CMPXCHG - pr_info("%s %s: cmpxchg double redo ", n, s->name); -#endif - - return false; -} - -static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page, - void *freelist_old, unsigned long counters_old, - void *freelist_new, unsigned long counters_new, - const char *n) -{ -#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \ - defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE) - if (s->flags & __CMPXCHG_DOUBLE) { - if (cmpxchg_double(&page->freelist, &page->counters, - freelist_old, counters_old, - freelist_new, counters_new)) - return true; - } else -#endif - { - unsigned long flags; - - local_irq_save(flags); - slab_lock(page); - if (page->freelist == freelist_old && - page->counters == counters_old) { - page->freelist = freelist_new; - set_page_slub_counters(page, counters_new); - slab_unlock(page); - local_irq_restore(flags); - return true; - } - slab_unlock(page); - local_irq_restore(flags); - } - - cpu_relax(); - stat(s, CMPXCHG_DOUBLE_FAIL); - -#ifdef SLUB_DEBUG_CMPXCHG - pr_info("%s %s: cmpxchg double redo ", n, s->name); -#endif - - return false; -} - -#ifdef CONFIG_SLUB_DEBUG -/* - * Determine a map of object in use on a page. - * - * Node listlock must be held to guarantee that the page does - * not vanish from under us. - */ -static void get_map(struct kmem_cache *s, struct page *page, unsigned long *map) -{ - void *p; - void *addr = page_address(page); - - for (p = page->freelist; p; p = get_freepointer(s, p)) - set_bit(slab_index(p, s, addr), map); -} - -static inline int size_from_object(struct kmem_cache *s) -{ - if (s->flags & SLAB_RED_ZONE) - return s->size - s->red_left_pad; - - return s->size; -} - -static inline void *restore_red_left(struct kmem_cache *s, void *p) -{ - if (s->flags & SLAB_RED_ZONE) - p -= s->red_left_pad; - - return p; -} - -/* - * Debug settings: - */ -#if defined(CONFIG_SLUB_DEBUG_ON) -static int slub_debug = DEBUG_DEFAULT_FLAGS; -#else -static int slub_debug; -#endif - -static char *slub_debug_slabs; -static int disable_higher_order_debug; - -/* - * slub is about to manipulate internal object metadata. This memory lies - * outside the range of the allocated object, so accessing it would normally - * be reported by kasan as a bounds error. metadata_access_enable() is used - * to tell kasan that these accesses are OK. - */ -static inline void metadata_access_enable(void) -{ - kasan_disable_current(); -} - -static inline void metadata_access_disable(void) -{ - kasan_enable_current(); -} - -/* - * Object debugging - */ - -/* Verify that a pointer has an address that is valid within a slab page */ -static inline int check_valid_pointer(struct kmem_cache *s, - struct page *page, void *object) -{ - void *base; - - if (!object) - return 1; - - base = page_address(page); - object = restore_red_left(s, object); - if (object < base || object >= base + page->objects * s->size || - (object - base) % s->size) { - return 0; - } - - return 1; -} - -static void print_section(char *text, u8 *addr, unsigned int length) -{ - metadata_access_enable(); - print_hex_dump(KERN_ERR, text, DUMP_PREFIX_ADDRESS, 16, 1, addr, - length, 1); - metadata_access_disable(); -} - -static struct track *get_track(struct kmem_cache *s, void *object, - enum track_item alloc) -{ - struct track *p; - - if (s->offset) - p = object + s->offset + sizeof(void *); - else - p = object + s->inuse; - - return p + alloc; -} - -static void set_track(struct kmem_cache *s, void *object, - enum track_item alloc, unsigned long addr) -{ - struct track *p = get_track(s, object, alloc); - - if (addr) { -#ifdef CONFIG_STACKTRACE - struct stack_trace trace; - int i; - - trace.nr_entries = 0; - trace.max_entries = TRACK_ADDRS_COUNT; - trace.entries = p->addrs; - trace.skip = 3; - metadata_access_enable(); - save_stack_trace(&trace); - metadata_access_disable(); - - /* See rant in lockdep.c */ - if (trace.nr_entries != 0 && - trace.entries[trace.nr_entries - 1] == ULONG_MAX) - trace.nr_entries--; - - for (i = trace.nr_entries; i < TRACK_ADDRS_COUNT; i++) - p->addrs[i] = 0; -#endif - p->addr = addr; - p->cpu = smp_processor_id(); - p->pid = current->pid; - p->when = jiffies; - } else - memset(p, 0, sizeof(struct track)); -} - -static void init_tracking(struct kmem_cache *s, void *object) -{ - if (!(s->flags & SLAB_STORE_USER)) - return; - - set_track(s, object, TRACK_FREE, 0UL); - set_track(s, object, TRACK_ALLOC, 0UL); -} - -static void print_track(const char *s, struct track *t) -{ - if (!t->addr) - return; - - pr_err("INFO: %s in %pS age=%lu cpu=%u pid=%d\n", - s, (void *)t->addr, jiffies - t->when, t->cpu, t->pid); -#ifdef CONFIG_STACKTRACE - { - int i; - for (i = 0; i < TRACK_ADDRS_COUNT; i++) - if (t->addrs[i]) - pr_err("\t%pS\n", (void *)t->addrs[i]); - else - break; - } -#endif -} - -static void print_tracking(struct kmem_cache *s, void *object) -{ - if (!(s->flags & SLAB_STORE_USER)) - return; - - print_track("Allocated", get_track(s, object, TRACK_ALLOC)); - print_track("Freed", get_track(s, object, TRACK_FREE)); -} - -static void print_page_info(struct page *page) -{ - pr_err("INFO: Slab 0x%p objects=%u used=%u fp=0x%p flags=0x%04lx\n", - page, page->objects, page->inuse, page->freelist, page->flags); - -} - -static void slab_bug(struct kmem_cache *s, char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; - pr_err("=============================================================================\n"); - pr_err("BUG %s (%s): %pV\n", s->name, print_tainted(), &vaf); - pr_err("-----------------------------------------------------------------------------\n\n"); - - add_taint(TAINT_BAD_PAGE, LOCKDEP_NOW_UNRELIABLE); - va_end(args); -} - -static void slab_fix(struct kmem_cache *s, char *fmt, ...) -{ - struct va_format vaf; - va_list args; - - va_start(args, fmt); - vaf.fmt = fmt; - vaf.va = &args; - pr_err("FIX %s: %pV\n", s->name, &vaf); - va_end(args); -} - -static void print_trailer(struct kmem_cache *s, struct page *page, u8 *p) -{ - unsigned int off; /* Offset of last byte */ - u8 *addr = page_address(page); - - print_tracking(s, p); - - print_page_info(page); - - pr_err("INFO: Object 0x%p @offset=%tu fp=0x%p\n\n", - p, p - addr, get_freepointer(s, p)); - - if (s->flags & SLAB_RED_ZONE) - print_section("Redzone ", p - s->red_left_pad, s->red_left_pad); - else if (p > addr + 16) - print_section("Bytes b4 ", p - 16, 16); - - print_section("Object ", p, min_t(unsigned long, s->object_size, - PAGE_SIZE)); - if (s->flags & SLAB_RED_ZONE) - print_section("Redzone ", p + s->object_size, - s->inuse - s->object_size); - - if (s->offset) - off = s->offset + sizeof(void *); - else - off = s->inuse; - - if (s->flags & SLAB_STORE_USER) - off += 2 * sizeof(struct track); - - off += kasan_metadata_size(s); - - if (off != size_from_object(s)) - /* Beginning of the filler is the free pointer */ - print_section("Padding ", p + off, size_from_object(s) - off); - - dump_stack(); -} - -void object_err(struct kmem_cache *s, struct page *page, - u8 *object, char *reason) -{ - slab_bug(s, "%s", reason); - print_trailer(s, page, object); -} - -static void slab_err(struct kmem_cache *s, struct page *page, - const char *fmt, ...) -{ - va_list args; - char buf[100]; - - va_start(args, fmt); - vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - slab_bug(s, "%s", buf); - print_page_info(page); - dump_stack(); -} - -static void init_object(struct kmem_cache *s, void *object, u8 val) -{ - u8 *p = object; - - if (s->flags & SLAB_RED_ZONE) - memset(p - s->red_left_pad, val, s->red_left_pad); - - if (s->flags & __OBJECT_POISON) { - memset(p, POISON_FREE, s->object_size - 1); - p[s->object_size - 1] = POISON_END; - } - - if (s->flags & SLAB_RED_ZONE) - memset(p + s->object_size, val, s->inuse - s->object_size); -} - -static void restore_bytes(struct kmem_cache *s, char *message, u8 data, - void *from, void *to) -{ - slab_fix(s, "Restoring 0x%p-0x%p=0x%x\n", from, to - 1, data); - memset(from, data, to - from); -} - -static int check_bytes_and_report(struct kmem_cache *s, struct page *page, - u8 *object, char *what, - u8 *start, unsigned int value, unsigned int bytes) -{ - u8 *fault; - u8 *end; - - metadata_access_enable(); - fault = memchr_inv(start, value, bytes); - metadata_access_disable(); - if (!fault) - return 1; - - end = start + bytes; - while (end > fault && end[-1] == value) - end--; - - slab_bug(s, "%s overwritten", what); - pr_err("INFO: 0x%p-0x%p. First byte 0x%x instead of 0x%x\n", - fault, end - 1, fault[0], value); - print_trailer(s, page, object); - - restore_bytes(s, what, value, fault, end); - return 0; -} - -/* - * Object layout: - * - * object address - * Bytes of the object to be managed. - * If the freepointer may overlay the object then the free - * pointer is the first word of the object. - * - * Poisoning uses 0x6b (POISON_FREE) and the last byte is - * 0xa5 (POISON_END) - * - * object + s->object_size - * Padding to reach word boundary. This is also used for Redzoning. - * Padding is extended by another word if Redzoning is enabled and - * object_size == inuse. - * - * We fill with 0xbb (RED_INACTIVE) for inactive objects and with - * 0xcc (RED_ACTIVE) for objects in use. - * - * object + s->inuse - * Meta data starts here. - * - * A. Free pointer (if we cannot overwrite object on free) - * B. Tracking data for SLAB_STORE_USER - * C. Padding to reach required alignment boundary or at mininum - * one word if debugging is on to be able to detect writes - * before the word boundary. - * - * Padding is done using 0x5a (POISON_INUSE) - * - * object + s->size - * Nothing is used beyond s->size. - * - * If slabcaches are merged then the object_size and inuse boundaries are mostly - * ignored. And therefore no slab options that rely on these boundaries - * may be used with merged slabcaches. - */ - -static int check_pad_bytes(struct kmem_cache *s, struct page *page, u8 *p) -{ - unsigned long off = s->inuse; /* The end of info */ - - if (s->offset) - /* Freepointer is placed after the object. */ - off += sizeof(void *); - - if (s->flags & SLAB_STORE_USER) - /* We also have user information there */ - off += 2 * sizeof(struct track); - - off += kasan_metadata_size(s); - - if (size_from_object(s) == off) - return 1; - - return check_bytes_and_report(s, page, p, "Object padding", - p + off, POISON_INUSE, size_from_object(s) - off); -} - -/* Check the pad bytes at the end of a slab page */ -static int slab_pad_check(struct kmem_cache *s, struct page *page) -{ - u8 *start; - u8 *fault; - u8 *end; - int length; - int remainder; - - if (!(s->flags & SLAB_POISON)) - return 1; - - start = page_address(page); - length = (PAGE_SIZE << compound_order(page)) - s->reserved; - end = start + length; - remainder = length % s->size; - if (!remainder) - return 1; - - metadata_access_enable(); - fault = memchr_inv(end - remainder, POISON_INUSE, remainder); - metadata_access_disable(); - if (!fault) - return 1; - while (end > fault && end[-1] == POISON_INUSE) - end--; - - slab_err(s, page, "Padding overwritten. 0x%p-0x%p", fault, end - 1); - print_section("Padding ", end - remainder, remainder); - - restore_bytes(s, "slab padding", POISON_INUSE, end - remainder, end); - return 0; -} - -static int check_object(struct kmem_cache *s, struct page *page, - void *object, u8 val) -{ - u8 *p = object; - u8 *endobject = object + s->object_size; - - if (s->flags & SLAB_RED_ZONE) { - if (!check_bytes_and_report(s, page, object, "Redzone", - object - s->red_left_pad, val, s->red_left_pad)) - return 0; - - if (!check_bytes_and_report(s, page, object, "Redzone", - endobject, val, s->inuse - s->object_size)) - return 0; - } else { - if ((s->flags & SLAB_POISON) && s->object_size < s->inuse) { - check_bytes_and_report(s, page, p, "Alignment padding", - endobject, POISON_INUSE, - s->inuse - s->object_size); - } - } - - if (s->flags & SLAB_POISON) { - if (val != SLUB_RED_ACTIVE && (s->flags & __OBJECT_POISON) && - (!check_bytes_and_report(s, page, p, "Poison", p, - POISON_FREE, s->object_size - 1) || - !check_bytes_and_report(s, page, p, "Poison", - p + s->object_size - 1, POISON_END, 1))) - return 0; - /* - * check_pad_bytes cleans up on its own. - */ - check_pad_bytes(s, page, p); - } - - if (!s->offset && val == SLUB_RED_ACTIVE) - /* - * Object and freepointer overlap. Cannot check - * freepointer while object is allocated. - */ - return 1; - - /* Check free pointer validity */ - if (!check_valid_pointer(s, page, get_freepointer(s, p))) { - object_err(s, page, p, "Freepointer corrupt"); - /* - * No choice but to zap it and thus lose the remainder - * of the free objects in this slab. May cause - * another error because the object count is now wrong. - */ - set_freepointer(s, p, NULL); - return 0; - } - return 1; -} - -static int check_slab(struct kmem_cache *s, struct page *page) -{ - int maxobj; - - VM_BUG_ON(!irqs_disabled()); - - if (!PageSlab(page)) { - slab_err(s, page, "Not a valid slab page"); - return 0; - } - - maxobj = order_objects(compound_order(page), s->size, s->reserved); - if (page->objects > maxobj) { - slab_err(s, page, "objects %u > max %u", - page->objects, maxobj); - return 0; - } - if (page->inuse > page->objects) { - slab_err(s, page, "inuse %u > max %u", - page->inuse, page->objects); - return 0; - } - /* Slab_pad_check fixes things up after itself */ - slab_pad_check(s, page); - return 1; -} - -/* - * Determine if a certain object on a page is on the freelist. Must hold the - * slab lock to guarantee that the chains are in a consistent state. - */ -static int on_freelist(struct kmem_cache *s, struct page *page, void *search) -{ - int nr = 0; - void *fp; - void *object = NULL; - int max_objects; - - fp = page->freelist; - while (fp && nr <= page->objects) { - if (fp == search) - return 1; - if (!check_valid_pointer(s, page, fp)) { - if (object) { - object_err(s, page, object, - "Freechain corrupt"); - set_freepointer(s, object, NULL); - } else { - slab_err(s, page, "Freepointer corrupt"); - page->freelist = NULL; - page->inuse = page->objects; - slab_fix(s, "Freelist cleared"); - return 0; - } - break; - } - object = fp; - fp = get_freepointer(s, object); - nr++; - } - - max_objects = order_objects(compound_order(page), s->size, s->reserved); - if (max_objects > MAX_OBJS_PER_PAGE) - max_objects = MAX_OBJS_PER_PAGE; - - if (page->objects != max_objects) { - slab_err(s, page, "Wrong number of objects. Found %d but should be %d", - page->objects, max_objects); - page->objects = max_objects; - slab_fix(s, "Number of objects adjusted."); - } - if (page->inuse != page->objects - nr) { - slab_err(s, page, "Wrong object count. Counter is %d but counted were %d", - page->inuse, page->objects - nr); - page->inuse = page->objects - nr; - slab_fix(s, "Object count adjusted."); - } - return search == NULL; -} - -static void trace(struct kmem_cache *s, struct page *page, void *object, - int alloc) -{ - if (s->flags & SLAB_TRACE) { - pr_info("TRACE %s %s 0x%p inuse=%d fp=0x%p\n", - s->name, - alloc ? "alloc" : "free", - object, page->inuse, - page->freelist); - - if (!alloc) - print_section("Object ", (void *)object, - s->object_size); - - dump_stack(); - } -} - -/* - * Tracking of fully allocated slabs for debugging purposes. - */ -static void add_full(struct kmem_cache *s, - struct kmem_cache_node *n, struct page *page) -{ - if (!(s->flags & SLAB_STORE_USER)) - return; - - lockdep_assert_held(&n->list_lock); - list_add(&page->lru, &n->full); -} - -static void remove_full(struct kmem_cache *s, struct kmem_cache_node *n, struct page *page) -{ - if (!(s->flags & SLAB_STORE_USER)) - return; - - lockdep_assert_held(&n->list_lock); - list_del(&page->lru); -} - -/* Tracking of the number of slabs for debugging purposes */ -static inline unsigned long slabs_node(struct kmem_cache *s, int node) -{ - struct kmem_cache_node *n = get_node(s, node); - - return atomic_long_read(&n->nr_slabs); -} - -static inline unsigned long node_nr_slabs(struct kmem_cache_node *n) -{ - return atomic_long_read(&n->nr_slabs); -} - -static inline void inc_slabs_node(struct kmem_cache *s, int node, int objects) -{ - struct kmem_cache_node *n = get_node(s, node); - - /* - * May be called early in order to allocate a slab for the - * kmem_cache_node structure. Solve the chicken-egg - * dilemma by deferring the increment of the count during - * bootstrap (see early_kmem_cache_node_alloc). - */ - if (likely(n)) { - atomic_long_inc(&n->nr_slabs); - atomic_long_add(objects, &n->total_objects); - } -} -static inline void dec_slabs_node(struct kmem_cache *s, int node, int objects) -{ - struct kmem_cache_node *n = get_node(s, node); - - atomic_long_dec(&n->nr_slabs); - atomic_long_sub(objects, &n->total_objects); -} - -/* Object debug checks for alloc/free paths */ -static void setup_object_debug(struct kmem_cache *s, struct page *page, - void *object) -{ - if (!(s->flags & (SLAB_STORE_USER|SLAB_RED_ZONE|__OBJECT_POISON))) - return; - - init_object(s, object, SLUB_RED_INACTIVE); - init_tracking(s, object); -} - -static inline int alloc_consistency_checks(struct kmem_cache *s, - struct page *page, - void *object, unsigned long addr) -{ - if (!check_slab(s, page)) - return 0; - - if (!check_valid_pointer(s, page, object)) { - object_err(s, page, object, "Freelist Pointer check fails"); - return 0; - } - - if (!check_object(s, page, object, SLUB_RED_INACTIVE)) - return 0; - - return 1; -} - -static noinline int alloc_debug_processing(struct kmem_cache *s, - struct page *page, - void *object, unsigned long addr) -{ - if (s->flags & SLAB_CONSISTENCY_CHECKS) { - if (!alloc_consistency_checks(s, page, object, addr)) - goto bad; - } - - /* Success perform special debug activities for allocs */ - if (s->flags & SLAB_STORE_USER) - set_track(s, object, TRACK_ALLOC, addr); - trace(s, page, object, 1); - init_object(s, object, SLUB_RED_ACTIVE); - return 1; - -bad: - if (PageSlab(page)) { - /* - * If this is a slab page then lets do the best we can - * to avoid issues in the future. Marking all objects - * as used avoids touching the remaining objects. - */ - slab_fix(s, "Marking all objects used"); - page->inuse = page->objects; - page->freelist = NULL; - } - return 0; -} - -static inline int free_consistency_checks(struct kmem_cache *s, - struct page *page, void *object, unsigned long addr) -{ - if (!check_valid_pointer(s, page, object)) { - slab_err(s, page, "Invalid object pointer 0x%p", object); - return 0; - } - - if (on_freelist(s, page, object)) { - object_err(s, page, object, "Object already free"); - return 0; - } - - if (!check_object(s, page, object, SLUB_RED_ACTIVE)) - return 0; - - if (unlikely(s != page->slab_cache)) { - if (!PageSlab(page)) { - slab_err(s, page, "Attempt to free object(0x%p) outside of slab", - object); - } else if (!page->slab_cache) { - pr_err("SLUB : no slab for object 0x%p.\n", - object); - dump_stack(); - } else - object_err(s, page, object, - "page slab pointer corrupt."); - return 0; - } - return 1; -} - -/* Supports checking bulk free of a constructed freelist */ -static noinline int free_debug_processing( - struct kmem_cache *s, struct page *page, - void *head, void *tail, int bulk_cnt, - unsigned long addr) -{ - struct kmem_cache_node *n = get_node(s, page_to_nid(page)); - void *object = head; - int cnt = 0; - unsigned long uninitialized_var(flags); - int ret = 0; - - spin_lock_irqsave(&n->list_lock, flags); - slab_lock(page); - - if (s->flags & SLAB_CONSISTENCY_CHECKS) { - if (!check_slab(s, page)) - goto out; - } - -next_object: - cnt++; - - if (s->flags & SLAB_CONSISTENCY_CHECKS) { - if (!free_consistency_checks(s, page, object, addr)) - goto out; - } - - if (s->flags & SLAB_STORE_USER) - set_track(s, object, TRACK_FREE, addr); - trace(s, page, object, 0); - /* Freepointer not overwritten by init_object(), SLAB_POISON moved it */ - init_object(s, object, SLUB_RED_INACTIVE); - - /* Reached end of constructed freelist yet? */ - if (object != tail) { - object = get_freepointer(s, object); - goto next_object; - } - ret = 1; - -out: - if (cnt != bulk_cnt) - slab_err(s, page, "Bulk freelist count(%d) invalid(%d)\n", - bulk_cnt, cnt); - - slab_unlock(page); - spin_unlock_irqrestore(&n->list_lock, flags); - if (!ret) - slab_fix(s, "Object at 0x%p not freed", object); - return ret; -} - -static int __init setup_slub_debug(char *str) -{ - slub_debug = DEBUG_DEFAULT_FLAGS; - if (*str++ != '=' || !*str) - /* - * No options specified. Switch on full debugging. - */ - goto out; - - if (*str == ',') - /* - * No options but restriction on slabs. This means full - * debugging for slabs matching a pattern. - */ - goto check_slabs; - - slub_debug = 0; - if (*str == '-') - /* - * Switch off all debugging measures. - */ - goto out; - - /* - * Determine which debug features should be switched on - */ - for (; *str && *str != ','; str++) { - switch (tolower(*str)) { - case 'f': - slub_debug |= SLAB_CONSISTENCY_CHECKS; - break; - case 'z': - slub_debug |= SLAB_RED_ZONE; - break; - case 'p': - slub_debug |= SLAB_POISON; - break; - case 'u': - slub_debug |= SLAB_STORE_USER; - break; - case 't': - slub_debug |= SLAB_TRACE; - break; - case 'a': - slub_debug |= SLAB_FAILSLAB; - break; - case 'o': - /* - * Avoid enabling debugging on caches if its minimum - * order would increase as a result. - */ - disable_higher_order_debug = 1; - break; - default: - pr_err("slub_debug option '%c' unknown. skipped\n", - *str); - } - } - -check_slabs: - if (*str == ',') - slub_debug_slabs = str + 1; -out: - return 1; -} - -__setup("slub_debug", setup_slub_debug); - -unsigned long kmem_cache_flags(unsigned long object_size, - unsigned long flags, const char *name, - void (*ctor)(void *)) -{ - /* - * Enable debugging if selected on the kernel commandline. - */ - if (slub_debug && (!slub_debug_slabs || (name && - !strncmp(slub_debug_slabs, name, strlen(slub_debug_slabs))))) - flags |= slub_debug; - - return flags; -} -#else /* !CONFIG_SLUB_DEBUG */ -static inline void setup_object_debug(struct kmem_cache *s, - struct page *page, void *object) {} - -static inline int alloc_debug_processing(struct kmem_cache *s, - struct page *page, void *object, unsigned long addr) { return 0; } - -static inline int free_debug_processing( - struct kmem_cache *s, struct page *page, - void *head, void *tail, int bulk_cnt, - unsigned long addr) { return 0; } - -static inline int slab_pad_check(struct kmem_cache *s, struct page *page) - { return 1; } -static inline int check_object(struct kmem_cache *s, struct page *page, - void *object, u8 val) { return 1; } -static inline void add_full(struct kmem_cache *s, struct kmem_cache_node *n, - struct page *page) {} -static inline void remove_full(struct kmem_cache *s, struct kmem_cache_node *n, - struct page *page) {} -unsigned long kmem_cache_flags(unsigned long object_size, - unsigned long flags, const char *name, - void (*ctor)(void *)) -{ - return flags; -} -#define slub_debug 0 - -#define disable_higher_order_debug 0 - -static inline unsigned long slabs_node(struct kmem_cache *s, int node) - { return 0; } -static inline unsigned long node_nr_slabs(struct kmem_cache_node *n) - { return 0; } -static inline void inc_slabs_node(struct kmem_cache *s, int node, - int objects) {} -static inline void dec_slabs_node(struct kmem_cache *s, int node, - int objects) {} - -#endif /* CONFIG_SLUB_DEBUG */ - -/* - * Hooks for other subsystems that check memory allocations. In a typical - * production configuration these hooks all should produce no code at all. - */ -static inline void kmalloc_large_node_hook(void *ptr, size_t size, gfp_t flags) -{ - kmemleak_alloc(ptr, size, 1, flags); - kasan_kmalloc_large(ptr, size, flags); -} - -static inline void kfree_hook(const void *x) -{ - kmemleak_free(x); - kasan_kfree_large(x); -} - -static inline void *slab_free_hook(struct kmem_cache *s, void *x) -{ - void *freeptr; - - kmemleak_free_recursive(x, s->flags); - - /* - * Trouble is that we may no longer disable interrupts in the fast path - * So in order to make the debug calls that expect irqs to be - * disabled we need to disable interrupts temporarily. - */ -#if defined(CONFIG_KMEMCHECK) || defined(CONFIG_LOCKDEP) - { - unsigned long flags; - - local_irq_save(flags); - kmemcheck_slab_free(s, x, s->object_size); - debug_check_no_locks_freed(x, s->object_size); - local_irq_restore(flags); - } -#endif - if (!(s->flags & SLAB_DEBUG_OBJECTS)) - debug_check_no_obj_freed(x, s->object_size); - - freeptr = get_freepointer(s, x); - /* - * kasan_slab_free() may put x into memory quarantine, delaying its - * reuse. In this case the object's freelist pointer is changed. - */ - kasan_slab_free(s, x); - return freeptr; -} - -static inline void slab_free_freelist_hook(struct kmem_cache *s, - void *head, void *tail) -{ -/* - * Compiler cannot detect this function can be removed if slab_free_hook() - * evaluates to nothing. Thus, catch all relevant config debug options here. - */ -#if defined(CONFIG_KMEMCHECK) || \ - defined(CONFIG_LOCKDEP) || \ - defined(CONFIG_DEBUG_KMEMLEAK) || \ - defined(CONFIG_DEBUG_OBJECTS_FREE) || \ - defined(CONFIG_KASAN) - - void *object = head; - void *tail_obj = tail ? : head; - void *freeptr; - - do { - freeptr = slab_free_hook(s, object); - } while ((object != tail_obj) && (object = freeptr)); -#endif -} - -static void setup_object(struct kmem_cache *s, struct page *page, - void *object) -{ - setup_object_debug(s, page, object); - kasan_init_slab_obj(s, object); - if (unlikely(s->ctor)) { - kasan_unpoison_object_data(s, object); - s->ctor(object); - kasan_poison_object_data(s, object); - } -} - -/* - * Slab allocation and freeing - */ -static inline struct page *alloc_slab_page(struct kmem_cache *s, - gfp_t flags, int node, struct kmem_cache_order_objects oo) -{ - struct page *page; - int order = oo_order(oo); - - flags |= __GFP_NOTRACK; - - if (node == NUMA_NO_NODE) - page = alloc_pages(flags, order); - else - page = __alloc_pages_node(node, flags, order); - - if (page && memcg_charge_slab(page, flags, order, s)) { - __free_pages(page, order); - page = NULL; - } - - return page; -} - -#ifdef CONFIG_SLAB_FREELIST_RANDOM -/* Pre-initialize the random sequence cache */ -static int init_cache_random_seq(struct kmem_cache *s) -{ - int err; - unsigned long i, count = oo_objects(s->oo); - - err = cache_random_seq_create(s, count, GFP_KERNEL); - if (err) { - pr_err("SLUB: Unable to initialize free list for %s\n", - s->name); - return err; - } - - /* Transform to an offset on the set of pages */ - if (s->random_seq) { - for (i = 0; i < count; i++) - s->random_seq[i] *= s->size; - } - return 0; -} - -/* Initialize each random sequence freelist per cache */ -static void __init init_freelist_randomization(void) -{ - struct kmem_cache *s; - - mutex_lock(&slab_mutex); - - list_for_each_entry(s, &slab_caches, list) - init_cache_random_seq(s); - - mutex_unlock(&slab_mutex); -} - -/* Get the next entry on the pre-computed freelist randomized */ -static void *next_freelist_entry(struct kmem_cache *s, struct page *page, - unsigned long *pos, void *start, - unsigned long page_limit, - unsigned long freelist_count) -{ - unsigned int idx; - - /* - * If the target page allocation failed, the number of objects on the - * page might be smaller than the usual size defined by the cache. - */ - do { - idx = s->random_seq[*pos]; - *pos += 1; - if (*pos >= freelist_count) - *pos = 0; - } while (unlikely(idx >= page_limit)); - - return (char *)start + idx; -} - -/* Shuffle the single linked freelist based on a random pre-computed sequence */ -static bool shuffle_freelist(struct kmem_cache *s, struct page *page) -{ - void *start; - void *cur; - void *next; - unsigned long idx, pos, page_limit, freelist_count; - - if (page->objects < 2 || !s->random_seq) - return false; - - freelist_count = oo_objects(s->oo); - pos = get_random_int() % freelist_count; - - page_limit = page->objects * s->size; - start = fixup_red_left(s, page_address(page)); - - /* First entry is used as the base of the freelist */ - cur = next_freelist_entry(s, page, &pos, start, page_limit, - freelist_count); - page->freelist = cur; - - for (idx = 1; idx < page->objects; idx++) { - setup_object(s, page, cur); - next = next_freelist_entry(s, page, &pos, start, page_limit, - freelist_count); - set_freepointer(s, cur, next); - cur = next; - } - setup_object(s, page, cur); - set_freepointer(s, cur, NULL); - - return true; -} -#else -static inline int init_cache_random_seq(struct kmem_cache *s) -{ - return 0; -} -static inline void init_freelist_randomization(void) { } -static inline bool shuffle_freelist(struct kmem_cache *s, struct page *page) -{ - return false; -} -#endif /* CONFIG_SLAB_FREELIST_RANDOM */ - -static struct page *allocate_slab(struct kmem_cache *s, gfp_t flags, int node) -{ - struct page *page; - struct kmem_cache_order_objects oo = s->oo; - gfp_t alloc_gfp; - void *start, *p; - int idx, order; - bool shuffle; - - flags &= gfp_allowed_mask; - - if (gfpflags_allow_blocking(flags)) - local_irq_enable(); - - flags |= s->allocflags; - - /* - * Let the initial higher-order allocation fail under memory pressure - * so we fall-back to the minimum order allocation. - */ - alloc_gfp = (flags | __GFP_NOWARN | __GFP_NORETRY) & ~__GFP_NOFAIL; - if ((alloc_gfp & __GFP_DIRECT_RECLAIM) && oo_order(oo) > oo_order(s->min)) - alloc_gfp = (alloc_gfp | __GFP_NOMEMALLOC) & ~(__GFP_RECLAIM|__GFP_NOFAIL); - - page = alloc_slab_page(s, alloc_gfp, node, oo); - if (unlikely(!page)) { - oo = s->min; - alloc_gfp = flags; - /* - * Allocation may have failed due to fragmentation. - * Try a lower order alloc if possible - */ - page = alloc_slab_page(s, alloc_gfp, node, oo); - if (unlikely(!page)) - goto out; - stat(s, ORDER_FALLBACK); - } - - if (kmemcheck_enabled && - !(s->flags & (SLAB_NOTRACK | DEBUG_DEFAULT_FLAGS))) { - int pages = 1 << oo_order(oo); - - kmemcheck_alloc_shadow(page, oo_order(oo), alloc_gfp, node); - - /* - * Objects from caches that have a constructor don't get - * cleared when they're allocated, so we need to do it here. - */ - if (s->ctor) - kmemcheck_mark_uninitialized_pages(page, pages); - else - kmemcheck_mark_unallocated_pages(page, pages); - } - - page->objects = oo_objects(oo); - - order = compound_order(page); - page->slab_cache = s; - __SetPageSlab(page); - if (page_is_pfmemalloc(page)) - SetPageSlabPfmemalloc(page); - - start = page_address(page); - - if (unlikely(s->flags & SLAB_POISON)) - memset(start, POISON_INUSE, PAGE_SIZE << order); - - kasan_poison_slab(page); - - shuffle = shuffle_freelist(s, page); - - if (!shuffle) { - for_each_object_idx(p, idx, s, start, page->objects) { - setup_object(s, page, p); - if (likely(idx < page->objects)) - set_freepointer(s, p, p + s->size); - else - set_freepointer(s, p, NULL); - } - page->freelist = fixup_red_left(s, start); - } - - page->inuse = page->objects; - page->frozen = 1; - -out: - if (gfpflags_allow_blocking(flags)) - local_irq_disable(); - if (!page) - return NULL; - - mod_zone_page_state(page_zone(page), - (s->flags & SLAB_RECLAIM_ACCOUNT) ? - NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE, - 1 << oo_order(oo)); - - inc_slabs_node(s, page_to_nid(page), page->objects); - - return page; -} - -static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node) -{ - if (unlikely(flags & GFP_SLAB_BUG_MASK)) { - gfp_t invalid_mask = flags & GFP_SLAB_BUG_MASK; - flags &= ~GFP_SLAB_BUG_MASK; - pr_warn("Unexpected gfp: %#x (%pGg). Fixing up to gfp: %#x (%pGg). Fix your code!\n", - invalid_mask, &invalid_mask, flags, &flags); - } - - return allocate_slab(s, - flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node); -} - -static void __free_slab(struct kmem_cache *s, struct page *page) -{ - int order = compound_order(page); - int pages = 1 << order; - - if (s->flags & SLAB_CONSISTENCY_CHECKS) { - void *p; - - slab_pad_check(s, page); - for_each_object(p, s, page_address(page), - page->objects) - check_object(s, page, p, SLUB_RED_INACTIVE); - } - - kmemcheck_free_shadow(page, compound_order(page)); - - mod_zone_page_state(page_zone(page), - (s->flags & SLAB_RECLAIM_ACCOUNT) ? - NR_SLAB_RECLAIMABLE : NR_SLAB_UNRECLAIMABLE, - -pages); - - __ClearPageSlabPfmemalloc(page); - __ClearPageSlab(page); - - page_mapcount_reset(page); - if (current->reclaim_state) - current->reclaim_state->reclaimed_slab += pages; - memcg_uncharge_slab(page, order, s); - __free_pages(page, order); -} - -#define need_reserve_slab_rcu \ - (sizeof(((struct page *)NULL)->lru) < sizeof(struct rcu_head)) - -static void rcu_free_slab(struct rcu_head *h) -{ - struct page *page; - - if (need_reserve_slab_rcu) - page = virt_to_head_page(h); - else - page = container_of((struct list_head *)h, struct page, lru); - - __free_slab(page->slab_cache, page); -} - -static void free_slab(struct kmem_cache *s, struct page *page) -{ - if (unlikely(s->flags & SLAB_DESTROY_BY_RCU)) { - struct rcu_head *head; - - if (need_reserve_slab_rcu) { - int order = compound_order(page); - int offset = (PAGE_SIZE << order) - s->reserved; - - VM_BUG_ON(s->reserved != sizeof(*head)); - head = page_address(page) + offset; - } else { - head = &page->rcu_head; - } - - call_rcu(head, rcu_free_slab); - } else - __free_slab(s, page); -} - -static void discard_slab(struct kmem_cache *s, struct page *page) -{ - dec_slabs_node(s, page_to_nid(page), page->objects); - free_slab(s, page); -} - -/* - * Management of partially allocated slabs. - */ -static inline void -__add_partial(struct kmem_cache_node *n, struct page *page, int tail) -{ - n->nr_partial++; - if (tail == DEACTIVATE_TO_TAIL) - list_add_tail(&page->lru, &n->partial); - else - list_add(&page->lru, &n->partial); -} - -static inline void add_partial(struct kmem_cache_node *n, - struct page *page, int tail) -{ - lockdep_assert_held(&n->list_lock); - __add_partial(n, page, tail); -} - -static inline void remove_partial(struct kmem_cache_node *n, - struct page *page) -{ - lockdep_assert_held(&n->list_lock); - list_del(&page->lru); - n->nr_partial--; -} - -/* - * Remove slab from the partial list, freeze it and - * return the pointer to the freelist. - * - * Returns a list of objects or NULL if it fails. - */ -static inline void *acquire_slab(struct kmem_cache *s, - struct kmem_cache_node *n, struct page *page, - int mode, int *objects) -{ - void *freelist; - unsigned long counters; - struct page new; - - lockdep_assert_held(&n->list_lock); - - /* - * Zap the freelist and set the frozen bit. - * The old freelist is the list of objects for the - * per cpu allocation list. - */ - freelist = page->freelist; - counters = page->counters; - new.counters = counters; - *objects = new.objects - new.inuse; - if (mode) { - new.inuse = page->objects; - new.freelist = NULL; - } else { - new.freelist = freelist; - } - - VM_BUG_ON(new.frozen); - new.frozen = 1; - - if (!__cmpxchg_double_slab(s, page, - freelist, counters, - new.freelist, new.counters, - "acquire_slab")) - return NULL; - - remove_partial(n, page); - WARN_ON(!freelist); - return freelist; -} - -static void put_cpu_partial(struct kmem_cache *s, struct page *page, int drain); -static inline bool pfmemalloc_match(struct page *page, gfp_t gfpflags); - -/* - * Try to allocate a partial slab from a specific node. - */ -static void *get_partial_node(struct kmem_cache *s, struct kmem_cache_node *n, - struct kmem_cache_cpu *c, gfp_t flags) -{ - struct page *page, *page2; - void *object = NULL; - int available = 0; - int objects; - - /* - * Racy check. If we mistakenly see no partial slabs then we - * just allocate an empty slab. If we mistakenly try to get a - * partial slab and there is none available then get_partials() - * will return NULL. - */ - if (!n || !n->nr_partial) - return NULL; - - spin_lock(&n->list_lock); - list_for_each_entry_safe(page, page2, &n->partial, lru) { - void *t; - - if (!pfmemalloc_match(page, flags)) - continue; - - t = acquire_slab(s, n, page, object == NULL, &objects); - if (!t) - break; - - available += objects; - if (!object) { - c->page = page; - stat(s, ALLOC_FROM_PARTIAL); - object = t; - } else { - put_cpu_partial(s, page, 0); - stat(s, CPU_PARTIAL_NODE); - } - if (!kmem_cache_has_cpu_partial(s) - || available > s->cpu_partial / 2) - break; - - } - spin_unlock(&n->list_lock); - return object; -} - -/* - * Get a page from somewhere. Search in increasing NUMA distances. - */ -static void *get_any_partial(struct kmem_cache *s, gfp_t flags, - struct kmem_cache_cpu *c) -{ -#ifdef CONFIG_NUMA - struct zonelist *zonelist; - struct zoneref *z; - struct zone *zone; - enum zone_type high_zoneidx = gfp_zone(flags); - void *object; - unsigned int cpuset_mems_cookie; - - /* - * The defrag ratio allows a configuration of the tradeoffs between - * inter node defragmentation and node local allocations. A lower - * defrag_ratio increases the tendency to do local allocations - * instead of attempting to obtain partial slabs from other nodes. - * - * If the defrag_ratio is set to 0 then kmalloc() always - * returns node local objects. If the ratio is higher then kmalloc() - * may return off node objects because partial slabs are obtained - * from other nodes and filled up. - * - * If /sys/kernel/slab/xx/remote_node_defrag_ratio is set to 100 - * (which makes defrag_ratio = 1000) then every (well almost) - * allocation will first attempt to defrag slab caches on other nodes. - * This means scanning over all nodes to look for partial slabs which - * may be expensive if we do it every time we are trying to find a slab - * with available objects. - */ - if (!s->remote_node_defrag_ratio || - get_cycles() % 1024 > s->remote_node_defrag_ratio) - return NULL; - - do { - cpuset_mems_cookie = read_mems_allowed_begin(); - zonelist = node_zonelist(mempolicy_slab_node(), flags); - for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) { - struct kmem_cache_node *n; - - n = get_node(s, zone_to_nid(zone)); - - if (n && cpuset_zone_allowed(zone, flags) && - n->nr_partial > s->min_partial) { - object = get_partial_node(s, n, c, flags); - if (object) { - /* - * Don't check read_mems_allowed_retry() - * here - if mems_allowed was updated in - * parallel, that was a harmless race - * between allocation and the cpuset - * update - */ - return object; - } - } - } - } while (read_mems_allowed_retry(cpuset_mems_cookie)); -#endif - return NULL; -} - -/* - * Get a partial page, lock it and return it. - */ -static void *get_partial(struct kmem_cache *s, gfp_t flags, int node, - struct kmem_cache_cpu *c) -{ - void *object; - int searchnode = node; - - if (node == NUMA_NO_NODE) - searchnode = numa_mem_id(); - else if (!node_present_pages(node)) - searchnode = node_to_mem_node(node); - - object = get_partial_node(s, get_node(s, searchnode), c, flags); - if (object || node != NUMA_NO_NODE) - return object; - - return get_any_partial(s, flags, c); -} - -#ifdef CONFIG_PREEMPT -/* - * Calculate the next globally unique transaction for disambiguiation - * during cmpxchg. The transactions start with the cpu number and are then - * incremented by CONFIG_NR_CPUS. - */ -#define TID_STEP roundup_pow_of_two(CONFIG_NR_CPUS) -#else -/* - * No preemption supported therefore also no need to check for - * different cpus. - */ -#define TID_STEP 1 -#endif - -static inline unsigned long next_tid(unsigned long tid) -{ - return tid + TID_STEP; -} - -static inline unsigned int tid_to_cpu(unsigned long tid) -{ - return tid % TID_STEP; -} - -static inline unsigned long tid_to_event(unsigned long tid) -{ - return tid / TID_STEP; -} - -static inline unsigned int init_tid(int cpu) -{ - return cpu; -} - -static inline void note_cmpxchg_failure(const char *n, - const struct kmem_cache *s, unsigned long tid) -{ -#ifdef SLUB_DEBUG_CMPXCHG - unsigned long actual_tid = __this_cpu_read(s->cpu_slab->tid); - - pr_info("%s %s: cmpxchg redo ", n, s->name); - -#ifdef CONFIG_PREEMPT - if (tid_to_cpu(tid) != tid_to_cpu(actual_tid)) - pr_warn("due to cpu change %d -> %d\n", - tid_to_cpu(tid), tid_to_cpu(actual_tid)); - else -#endif - if (tid_to_event(tid) != tid_to_event(actual_tid)) - pr_warn("due to cpu running other code. Event %ld->%ld\n", - tid_to_event(tid), tid_to_event(actual_tid)); - else - pr_warn("for unknown reason: actual=%lx was=%lx target=%lx\n", - actual_tid, tid, next_tid(tid)); -#endif - stat(s, CMPXCHG_DOUBLE_CPU_FAIL); -} - -static void init_kmem_cache_cpus(struct kmem_cache *s) -{ - int cpu; - - for_each_possible_cpu(cpu) - per_cpu_ptr(s->cpu_slab, cpu)->tid = init_tid(cpu); -} - -/* - * Remove the cpu slab - */ -static void deactivate_slab(struct kmem_cache *s, struct page *page, - void *freelist) -{ - enum slab_modes { M_NONE, M_PARTIAL, M_FULL, M_FREE }; - struct kmem_cache_node *n = get_node(s, page_to_nid(page)); - int lock = 0; - enum slab_modes l = M_NONE, m = M_NONE; - void *nextfree; - int tail = DEACTIVATE_TO_HEAD; - struct page new; - struct page old; - - if (page->freelist) { - stat(s, DEACTIVATE_REMOTE_FREES); - tail = DEACTIVATE_TO_TAIL; - } - - /* - * Stage one: Free all available per cpu objects back - * to the page freelist while it is still frozen. Leave the - * last one. - * - * There is no need to take the list->lock because the page - * is still frozen. - */ - while (freelist && (nextfree = get_freepointer(s, freelist))) { - void *prior; - unsigned long counters; - - do { - prior = page->freelist; - counters = page->counters; - set_freepointer(s, freelist, prior); - new.counters = counters; - new.inuse--; - VM_BUG_ON(!new.frozen); - - } while (!__cmpxchg_double_slab(s, page, - prior, counters, - freelist, new.counters, - "drain percpu freelist")); - - freelist = nextfree; - } - - /* - * Stage two: Ensure that the page is unfrozen while the - * list presence reflects the actual number of objects - * during unfreeze. - * - * We setup the list membership and then perform a cmpxchg - * with the count. If there is a mismatch then the page - * is not unfrozen but the page is on the wrong list. - * - * Then we restart the process which may have to remove - * the page from the list that we just put it on again - * because the number of objects in the slab may have - * changed. - */ -redo: - - old.freelist = page->freelist; - old.counters = page->counters; - VM_BUG_ON(!old.frozen); - - /* Determine target state of the slab */ - new.counters = old.counters; - if (freelist) { - new.inuse--; - set_freepointer(s, freelist, old.freelist); - new.freelist = freelist; - } else - new.freelist = old.freelist; - - new.frozen = 0; - - if (!new.inuse && n->nr_partial >= s->min_partial) - m = M_FREE; - else if (new.freelist) { - m = M_PARTIAL; - if (!lock) { - lock = 1; - /* - * Taking the spinlock removes the possiblity - * that acquire_slab() will see a slab page that - * is frozen - */ - spin_lock(&n->list_lock); - } - } else { - m = M_FULL; - if (kmem_cache_debug(s) && !lock) { - lock = 1; - /* - * This also ensures that the scanning of full - * slabs from diagnostic functions will not see - * any frozen slabs. - */ - spin_lock(&n->list_lock); - } - } - - if (l != m) { - - if (l == M_PARTIAL) - - remove_partial(n, page); - - else if (l == M_FULL) - - remove_full(s, n, page); - - if (m == M_PARTIAL) { - - add_partial(n, page, tail); - stat(s, tail); - - } else if (m == M_FULL) { - - stat(s, DEACTIVATE_FULL); - add_full(s, n, page); - - } - } - - l = m; - if (!__cmpxchg_double_slab(s, page, - old.freelist, old.counters, - new.freelist, new.counters, - "unfreezing slab")) - goto redo; - - if (lock) - spin_unlock(&n->list_lock); - - if (m == M_FREE) { - stat(s, DEACTIVATE_EMPTY); - discard_slab(s, page); - stat(s, FREE_SLAB); - } -} - -/* - * Unfreeze all the cpu partial slabs. - * - * This function must be called with interrupts disabled - * for the cpu using c (or some other guarantee must be there - * to guarantee no concurrent accesses). - */ -static void unfreeze_partials(struct kmem_cache *s, - struct kmem_cache_cpu *c) -{ -#ifdef CONFIG_SLUB_CPU_PARTIAL - struct kmem_cache_node *n = NULL, *n2 = NULL; - struct page *page, *discard_page = NULL; - - while ((page = c->partial)) { - struct page new; - struct page old; - - c->partial = page->next; - - n2 = get_node(s, page_to_nid(page)); - if (n != n2) { - if (n) - spin_unlock(&n->list_lock); - - n = n2; - spin_lock(&n->list_lock); - } - - do { - - old.freelist = page->freelist; - old.counters = page->counters; - VM_BUG_ON(!old.frozen); - - new.counters = old.counters; - new.freelist = old.freelist; - - new.frozen = 0; - - } while (!__cmpxchg_double_slab(s, page, - old.freelist, old.counters, - new.freelist, new.counters, - "unfreezing slab")); - - if (unlikely(!new.inuse && n->nr_partial >= s->min_partial)) { - page->next = discard_page; - discard_page = page; - } else { - add_partial(n, page, DEACTIVATE_TO_TAIL); - stat(s, FREE_ADD_PARTIAL); - } - } - - if (n) - spin_unlock(&n->list_lock); - - while (discard_page) { - page = discard_page; - discard_page = discard_page->next; - - stat(s, DEACTIVATE_EMPTY); - discard_slab(s, page); - stat(s, FREE_SLAB); - } -#endif -} - -/* - * Put a page that was just frozen (in __slab_free) into a partial page - * slot if available. This is done without interrupts disabled and without - * preemption disabled. The cmpxchg is racy and may put the partial page - * onto a random cpus partial slot. - * - * If we did not find a slot then simply move all the partials to the - * per node partial list. - */ -static void put_cpu_partial(struct kmem_cache *s, struct page *page, int drain) -{ -#ifdef CONFIG_SLUB_CPU_PARTIAL - struct page *oldpage; - int pages; - int pobjects; - - preempt_disable(); - do { - pages = 0; - pobjects = 0; - oldpage = this_cpu_read(s->cpu_slab->partial); - - if (oldpage) { - pobjects = oldpage->pobjects; - pages = oldpage->pages; - if (drain && pobjects > s->cpu_partial) { - unsigned long flags; - /* - * partial array is full. Move the existing - * set to the per node partial list. - */ - local_irq_save(flags); - unfreeze_partials(s, this_cpu_ptr(s->cpu_slab)); - local_irq_restore(flags); - oldpage = NULL; - pobjects = 0; - pages = 0; - stat(s, CPU_PARTIAL_DRAIN); - } - } - - pages++; - pobjects += page->objects - page->inuse; - - page->pages = pages; - page->pobjects = pobjects; - page->next = oldpage; - - } while (this_cpu_cmpxchg(s->cpu_slab->partial, oldpage, page) - != oldpage); - if (unlikely(!s->cpu_partial)) { - unsigned long flags; - - local_irq_save(flags); - unfreeze_partials(s, this_cpu_ptr(s->cpu_slab)); - local_irq_restore(flags); - } - preempt_enable(); -#endif -} - -static inline void flush_slab(struct kmem_cache *s, struct kmem_cache_cpu *c) -{ - stat(s, CPUSLAB_FLUSH); - deactivate_slab(s, c->page, c->freelist); - - c->tid = next_tid(c->tid); - c->page = NULL; - c->freelist = NULL; -} - -/* - * Flush cpu slab. - * - * Called from IPI handler with interrupts disabled. - */ -static inline void __flush_cpu_slab(struct kmem_cache *s, int cpu) -{ - struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu); - - if (likely(c)) { - if (c->page) - flush_slab(s, c); - - unfreeze_partials(s, c); - } -} - -static void flush_cpu_slab(void *d) -{ - struct kmem_cache *s = d; - - __flush_cpu_slab(s, smp_processor_id()); -} - -static bool has_cpu_slab(int cpu, void *info) -{ - struct kmem_cache *s = info; - struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, cpu); - - return c->page || c->partial; -} - -static void flush_all(struct kmem_cache *s) -{ - on_each_cpu_cond(has_cpu_slab, flush_cpu_slab, s, 1, GFP_ATOMIC); -} - -/* - * Use the cpu notifier to insure that the cpu slabs are flushed when - * necessary. - */ -static int slub_cpu_dead(unsigned int cpu) -{ - struct kmem_cache *s; - unsigned long flags; - - mutex_lock(&slab_mutex); - list_for_each_entry(s, &slab_caches, list) { - local_irq_save(flags); - __flush_cpu_slab(s, cpu); - local_irq_restore(flags); - } - mutex_unlock(&slab_mutex); - return 0; -} - -/* - * Check if the objects in a per cpu structure fit numa - * locality expectations. - */ -static inline int node_match(struct page *page, int node) -{ -#ifdef CONFIG_NUMA - if (!page || (node != NUMA_NO_NODE && page_to_nid(page) != node)) - return 0; -#endif - return 1; -} - -#ifdef CONFIG_SLUB_DEBUG -static int count_free(struct page *page) -{ - return page->objects - page->inuse; -} - -static inline unsigned long node_nr_objs(struct kmem_cache_node *n) -{ - return atomic_long_read(&n->total_objects); -} -#endif /* CONFIG_SLUB_DEBUG */ - -#if defined(CONFIG_SLUB_DEBUG) || defined(CONFIG_SYSFS) -static unsigned long count_partial(struct kmem_cache_node *n, - int (*get_count)(struct page *)) -{ - unsigned long flags; - unsigned long x = 0; - struct page *page; - - spin_lock_irqsave(&n->list_lock, flags); - list_for_each_entry(page, &n->partial, lru) - x += get_count(page); - spin_unlock_irqrestore(&n->list_lock, flags); - return x; -} -#endif /* CONFIG_SLUB_DEBUG || CONFIG_SYSFS */ - -static noinline void -slab_out_of_memory(struct kmem_cache *s, gfp_t gfpflags, int nid) -{ -#ifdef CONFIG_SLUB_DEBUG - static DEFINE_RATELIMIT_STATE(slub_oom_rs, DEFAULT_RATELIMIT_INTERVAL, - DEFAULT_RATELIMIT_BURST); - int node; - struct kmem_cache_node *n; - - if ((gfpflags & __GFP_NOWARN) || !__ratelimit(&slub_oom_rs)) - return; - - pr_warn("SLUB: Unable to allocate memory on node %d, gfp=%#x(%pGg)\n", - nid, gfpflags, &gfpflags); - pr_warn(" cache: %s, object size: %d, buffer size: %d, default order: %d, min order: %d\n", - s->name, s->object_size, s->size, oo_order(s->oo), - oo_order(s->min)); - - if (oo_order(s->min) > get_order(s->object_size)) - pr_warn(" %s debugging increased min order, use slub_debug=O to disable.\n", - s->name); - - for_each_kmem_cache_node(s, node, n) { - unsigned long nr_slabs; - unsigned long nr_objs; - unsigned long nr_free; - - nr_free = count_partial(n, count_free); - nr_slabs = node_nr_slabs(n); - nr_objs = node_nr_objs(n); - - pr_warn(" node %d: slabs: %ld, objs: %ld, free: %ld\n", - node, nr_slabs, nr_objs, nr_free); - } -#endif -} - -static inline void *new_slab_objects(struct kmem_cache *s, gfp_t flags, - int node, struct kmem_cache_cpu **pc) -{ - void *freelist; - struct kmem_cache_cpu *c = *pc; - struct page *page; - - freelist = get_partial(s, flags, node, c); - - if (freelist) - return freelist; - - page = new_slab(s, flags, node); - if (page) { - c = raw_cpu_ptr(s->cpu_slab); - if (c->page) - flush_slab(s, c); - - /* - * No other reference to the page yet so we can - * muck around with it freely without cmpxchg - */ - freelist = page->freelist; - page->freelist = NULL; - - stat(s, ALLOC_SLAB); - c->page = page; - *pc = c; - } else - freelist = NULL; - - return freelist; -} - -static inline bool pfmemalloc_match(struct page *page, gfp_t gfpflags) -{ - if (unlikely(PageSlabPfmemalloc(page))) - return gfp_pfmemalloc_allowed(gfpflags); - - return true; -} - -/* - * Check the page->freelist of a page and either transfer the freelist to the - * per cpu freelist or deactivate the page. - * - * The page is still frozen if the return value is not NULL. - * - * If this function returns NULL then the page has been unfrozen. - * - * This function must be called with interrupt disabled. - */ -static inline void *get_freelist(struct kmem_cache *s, struct page *page) -{ - struct page new; - unsigned long counters; - void *freelist; - - do { - freelist = page->freelist; - counters = page->counters; - - new.counters = counters; - VM_BUG_ON(!new.frozen); - - new.inuse = page->objects; - new.frozen = freelist != NULL; - - } while (!__cmpxchg_double_slab(s, page, - freelist, counters, - NULL, new.counters, - "get_freelist")); - - return freelist; -} - -/* - * Slow path. The lockless freelist is empty or we need to perform - * debugging duties. - * - * Processing is still very fast if new objects have been freed to the - * regular freelist. In that case we simply take over the regular freelist - * as the lockless freelist and zap the regular freelist. - * - * If that is not working then we fall back to the partial lists. We take the - * first element of the freelist as the object to allocate now and move the - * rest of the freelist to the lockless freelist. - * - * And if we were unable to get a new slab from the partial slab lists then - * we need to allocate a new slab. This is the slowest path since it involves - * a call to the page allocator and the setup of a new slab. - * - * Version of __slab_alloc to use when we know that interrupts are - * already disabled (which is the case for bulk allocation). - */ -static void *___slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, - unsigned long addr, struct kmem_cache_cpu *c) -{ - void *freelist; - struct page *page; - - page = c->page; - if (!page) - goto new_slab; -redo: - - if (unlikely(!node_match(page, node))) { - int searchnode = node; - - if (node != NUMA_NO_NODE && !node_present_pages(node)) - searchnode = node_to_mem_node(node); - - if (unlikely(!node_match(page, searchnode))) { - stat(s, ALLOC_NODE_MISMATCH); - deactivate_slab(s, page, c->freelist); - c->page = NULL; - c->freelist = NULL; - goto new_slab; - } - } - - /* - * By rights, we should be searching for a slab page that was - * PFMEMALLOC but right now, we are losing the pfmemalloc - * information when the page leaves the per-cpu allocator - */ - if (unlikely(!pfmemalloc_match(page, gfpflags))) { - deactivate_slab(s, page, c->freelist); - c->page = NULL; - c->freelist = NULL; - goto new_slab; - } - - /* must check again c->freelist in case of cpu migration or IRQ */ - freelist = c->freelist; - if (freelist) - goto load_freelist; - - freelist = get_freelist(s, page); - - if (!freelist) { - c->page = NULL; - stat(s, DEACTIVATE_BYPASS); - goto new_slab; - } - - stat(s, ALLOC_REFILL); - -load_freelist: - /* - * freelist is pointing to the list of objects to be used. - * page is pointing to the page from which the objects are obtained. - * That page must be frozen for per cpu allocations to work. - */ - VM_BUG_ON(!c->page->frozen); - c->freelist = get_freepointer(s, freelist); - c->tid = next_tid(c->tid); - return freelist; - -new_slab: - - if (c->partial) { - page = c->page = c->partial; - c->partial = page->next; - stat(s, CPU_PARTIAL_ALLOC); - c->freelist = NULL; - goto redo; - } - - freelist = new_slab_objects(s, gfpflags, node, &c); - - if (unlikely(!freelist)) { - slab_out_of_memory(s, gfpflags, node); - return NULL; - } - - page = c->page; - if (likely(!kmem_cache_debug(s) && pfmemalloc_match(page, gfpflags))) - goto load_freelist; - - /* Only entered in the debug case */ - if (kmem_cache_debug(s) && - !alloc_debug_processing(s, page, freelist, addr)) - goto new_slab; /* Slab failed checks. Next slab needed */ - - deactivate_slab(s, page, get_freepointer(s, freelist)); - c->page = NULL; - c->freelist = NULL; - return freelist; -} - -/* - * Another one that disabled interrupt and compensates for possible - * cpu changes by refetching the per cpu area pointer. - */ -static void *__slab_alloc(struct kmem_cache *s, gfp_t gfpflags, int node, - unsigned long addr, struct kmem_cache_cpu *c) -{ - void *p; - unsigned long flags; - - local_irq_save(flags); -#ifdef CONFIG_PREEMPT - /* - * We may have been preempted and rescheduled on a different - * cpu before disabling interrupts. Need to reload cpu area - * pointer. - */ - c = this_cpu_ptr(s->cpu_slab); -#endif - - p = ___slab_alloc(s, gfpflags, node, addr, c); - local_irq_restore(flags); - return p; -} - -/* - * Inlined fastpath so that allocation functions (kmalloc, kmem_cache_alloc) - * have the fastpath folded into their functions. So no function call - * overhead for requests that can be satisfied on the fastpath. - * - * The fastpath works by first checking if the lockless freelist can be used. - * If not then __slab_alloc is called for slow processing. - * - * Otherwise we can simply pick the next object from the lockless free list. - */ -static __always_inline void *slab_alloc_node(struct kmem_cache *s, - gfp_t gfpflags, int node, unsigned long addr) -{ - void *object; - struct kmem_cache_cpu *c; - struct page *page; - unsigned long tid; - - s = slab_pre_alloc_hook(s, gfpflags); - if (!s) - return NULL; -redo: - /* - * Must read kmem_cache cpu data via this cpu ptr. Preemption is - * enabled. We may switch back and forth between cpus while - * reading from one cpu area. That does not matter as long - * as we end up on the original cpu again when doing the cmpxchg. - * - * We should guarantee that tid and kmem_cache are retrieved on - * the same cpu. It could be different if CONFIG_PREEMPT so we need - * to check if it is matched or not. - */ - do { - tid = this_cpu_read(s->cpu_slab->tid); - c = raw_cpu_ptr(s->cpu_slab); - } while (IS_ENABLED(CONFIG_PREEMPT) && - unlikely(tid != READ_ONCE(c->tid))); - - /* - * Irqless object alloc/free algorithm used here depends on sequence - * of fetching cpu_slab's data. tid should be fetched before anything - * on c to guarantee that object and page associated with previous tid - * won't be used with current tid. If we fetch tid first, object and - * page could be one associated with next tid and our alloc/free - * request will be failed. In this case, we will retry. So, no problem. - */ - barrier(); - - /* - * The transaction ids are globally unique per cpu and per operation on - * a per cpu queue. Thus they can be guarantee that the cmpxchg_double - * occurs on the right processor and that there was no operation on the - * linked list in between. - */ - - object = c->freelist; - page = c->page; - if (unlikely(!object || !node_match(page, node))) { - object = __slab_alloc(s, gfpflags, node, addr, c); - stat(s, ALLOC_SLOWPATH); - } else { - void *next_object = get_freepointer_safe(s, object); - - /* - * The cmpxchg will only match if there was no additional - * operation and if we are on the right processor. - * - * The cmpxchg does the following atomically (without lock - * semantics!) - * 1. Relocate first pointer to the current per cpu area. - * 2. Verify that tid and freelist have not been changed - * 3. If they were not changed replace tid and freelist - * - * Since this is without lock semantics the protection is only - * against code executing on this cpu *not* from access by - * other cpus. - */ - if (unlikely(!this_cpu_cmpxchg_double( - s->cpu_slab->freelist, s->cpu_slab->tid, - object, tid, - next_object, next_tid(tid)))) { - - note_cmpxchg_failure("slab_alloc", s, tid); - goto redo; - } - prefetch_freepointer(s, next_object); - stat(s, ALLOC_FASTPATH); - } - - if (unlikely(gfpflags & __GFP_ZERO) && object) - memset(object, 0, s->object_size); - - slab_post_alloc_hook(s, gfpflags, 1, &object); - - return object; -} - -static __always_inline void *slab_alloc(struct kmem_cache *s, - gfp_t gfpflags, unsigned long addr) -{ - return slab_alloc_node(s, gfpflags, NUMA_NO_NODE, addr); -} - -void *kmem_cache_alloc(struct kmem_cache *s, gfp_t gfpflags) -{ - void *ret = slab_alloc(s, gfpflags, _RET_IP_); - - trace_kmem_cache_alloc(_RET_IP_, ret, s->object_size, - s->size, gfpflags); - - return ret; -} -EXPORT_SYMBOL(kmem_cache_alloc); - -#ifdef CONFIG_TRACING -void *kmem_cache_alloc_trace(struct kmem_cache *s, gfp_t gfpflags, size_t size) -{ - void *ret = slab_alloc(s, gfpflags, _RET_IP_); - trace_kmalloc(_RET_IP_, ret, size, s->size, gfpflags); - kasan_kmalloc(s, ret, size, gfpflags); - return ret; -} -EXPORT_SYMBOL(kmem_cache_alloc_trace); -#endif - -#ifdef CONFIG_NUMA -void *kmem_cache_alloc_node(struct kmem_cache *s, gfp_t gfpflags, int node) -{ - void *ret = slab_alloc_node(s, gfpflags, node, _RET_IP_); - - trace_kmem_cache_alloc_node(_RET_IP_, ret, - s->object_size, s->size, gfpflags, node); - - return ret; -} -EXPORT_SYMBOL(kmem_cache_alloc_node); - -#ifdef CONFIG_TRACING -void *kmem_cache_alloc_node_trace(struct kmem_cache *s, - gfp_t gfpflags, - int node, size_t size) -{ - void *ret = slab_alloc_node(s, gfpflags, node, _RET_IP_); - - trace_kmalloc_node(_RET_IP_, ret, - size, s->size, gfpflags, node); - - kasan_kmalloc(s, ret, size, gfpflags); - return ret; -} -EXPORT_SYMBOL(kmem_cache_alloc_node_trace); -#endif -#endif - -/* - * Slow path handling. This may still be called frequently since objects - * have a longer lifetime than the cpu slabs in most processing loads. - * - * So we still attempt to reduce cache line usage. Just take the slab - * lock and free the item. If there is no additional partial page - * handling required then we can return immediately. - */ -static void __slab_free(struct kmem_cache *s, struct page *page, - void *head, void *tail, int cnt, - unsigned long addr) - -{ - void *prior; - int was_frozen; - struct page new; - unsigned long counters; - struct kmem_cache_node *n = NULL; - unsigned long uninitialized_var(flags); - - stat(s, FREE_SLOWPATH); - - if (kmem_cache_debug(s) && - !free_debug_processing(s, page, head, tail, cnt, addr)) - return; - - do { - if (unlikely(n)) { - spin_unlock_irqrestore(&n->list_lock, flags); - n = NULL; - } - prior = page->freelist; - counters = page->counters; - set_freepointer(s, tail, prior); - new.counters = counters; - was_frozen = new.frozen; - new.inuse -= cnt; - if ((!new.inuse || !prior) && !was_frozen) { - - if (kmem_cache_has_cpu_partial(s) && !prior) { - - /* - * Slab was on no list before and will be - * partially empty - * We can defer the list move and instead - * freeze it. - */ - new.frozen = 1; - - } else { /* Needs to be taken off a list */ - - n = get_node(s, page_to_nid(page)); - /* - * Speculatively acquire the list_lock. - * If the cmpxchg does not succeed then we may - * drop the list_lock without any processing. - * - * Otherwise the list_lock will synchronize with - * other processors updating the list of slabs. - */ - spin_lock_irqsave(&n->list_lock, flags); - - } - } - - } while (!cmpxchg_double_slab(s, page, - prior, counters, - head, new.counters, - "__slab_free")); - - if (likely(!n)) { - - /* - * If we just froze the page then put it onto the - * per cpu partial list. - */ - if (new.frozen && !was_frozen) { - put_cpu_partial(s, page, 1); - stat(s, CPU_PARTIAL_FREE); - } - /* - * The list lock was not taken therefore no list - * activity can be necessary. - */ - if (was_frozen) - stat(s, FREE_FROZEN); - return; - } - - if (unlikely(!new.inuse && n->nr_partial >= s->min_partial)) - goto slab_empty; - - /* - * Objects left in the slab. If it was not on the partial list before - * then add it. - */ - if (!kmem_cache_has_cpu_partial(s) && unlikely(!prior)) { - if (kmem_cache_debug(s)) - remove_full(s, n, page); - add_partial(n, page, DEACTIVATE_TO_TAIL); - stat(s, FREE_ADD_PARTIAL); - } - spin_unlock_irqrestore(&n->list_lock, flags); - return; - -slab_empty: - if (prior) { - /* - * Slab on the partial list. - */ - remove_partial(n, page); - stat(s, FREE_REMOVE_PARTIAL); - } else { - /* Slab must be on the full list */ - remove_full(s, n, page); - } - - spin_unlock_irqrestore(&n->list_lock, flags); - stat(s, FREE_SLAB); - discard_slab(s, page); -} - -/* - * Fastpath with forced inlining to produce a kfree and kmem_cache_free that - * can perform fastpath freeing without additional function calls. - * - * The fastpath is only possible if we are freeing to the current cpu slab - * of this processor. This typically the case if we have just allocated - * the item before. - * - * If fastpath is not possible then fall back to __slab_free where we deal - * with all sorts of special processing. - * - * Bulk free of a freelist with several objects (all pointing to the - * same page) possible by specifying head and tail ptr, plus objects - * count (cnt). Bulk free indicated by tail pointer being set. - */ -static __always_inline void do_slab_free(struct kmem_cache *s, - struct page *page, void *head, void *tail, - int cnt, unsigned long addr) -{ - void *tail_obj = tail ? : head; - struct kmem_cache_cpu *c; - unsigned long tid; -redo: - /* - * Determine the currently cpus per cpu slab. - * The cpu may change afterward. However that does not matter since - * data is retrieved via this pointer. If we are on the same cpu - * during the cmpxchg then the free will succeed. - */ - do { - tid = this_cpu_read(s->cpu_slab->tid); - c = raw_cpu_ptr(s->cpu_slab); - } while (IS_ENABLED(CONFIG_PREEMPT) && - unlikely(tid != READ_ONCE(c->tid))); - - /* Same with comment on barrier() in slab_alloc_node() */ - barrier(); - - if (likely(page == c->page)) { - set_freepointer(s, tail_obj, c->freelist); - - if (unlikely(!this_cpu_cmpxchg_double( - s->cpu_slab->freelist, s->cpu_slab->tid, - c->freelist, tid, - head, next_tid(tid)))) { - - note_cmpxchg_failure("slab_free", s, tid); - goto redo; - } - stat(s, FREE_FASTPATH); - } else - __slab_free(s, page, head, tail_obj, cnt, addr); - -} - -static __always_inline void slab_free(struct kmem_cache *s, struct page *page, - void *head, void *tail, int cnt, - unsigned long addr) -{ - slab_free_freelist_hook(s, head, tail); - /* - * slab_free_freelist_hook() could have put the items into quarantine. - * If so, no need to free them. - */ - if (s->flags & SLAB_KASAN && !(s->flags & SLAB_DESTROY_BY_RCU)) - return; - do_slab_free(s, page, head, tail, cnt, addr); -} - -#ifdef CONFIG_KASAN -void ___cache_free(struct kmem_cache *cache, void *x, unsigned long addr) -{ - do_slab_free(cache, virt_to_head_page(x), x, NULL, 1, addr); -} -#endif - -void kmem_cache_free(struct kmem_cache *s, void *x) -{ - s = cache_from_obj(s, x); - if (!s) - return; - slab_free(s, virt_to_head_page(x), x, NULL, 1, _RET_IP_); - trace_kmem_cache_free(_RET_IP_, x); -} -EXPORT_SYMBOL(kmem_cache_free); - -struct detached_freelist { - struct page *page; - void *tail; - void *freelist; - int cnt; - struct kmem_cache *s; -}; - -/* - * This function progressively scans the array with free objects (with - * a limited look ahead) and extract objects belonging to the same - * page. It builds a detached freelist directly within the given - * page/objects. This can happen without any need for - * synchronization, because the objects are owned by running process. - * The freelist is build up as a single linked list in the objects. - * The idea is, that this detached freelist can then be bulk - * transferred to the real freelist(s), but only requiring a single - * synchronization primitive. Look ahead in the array is limited due - * to performance reasons. - */ -static inline -int build_detached_freelist(struct kmem_cache *s, size_t size, - void **p, struct detached_freelist *df) -{ - size_t first_skipped_index = 0; - int lookahead = 3; - void *object; - struct page *page; - - /* Always re-init detached_freelist */ - df->page = NULL; - - do { - object = p[--size]; - /* Do we need !ZERO_OR_NULL_PTR(object) here? (for kfree) */ - } while (!object && size); - - if (!object) - return 0; - - page = virt_to_head_page(object); - if (!s) { - /* Handle kalloc'ed objects */ - if (unlikely(!PageSlab(page))) { - BUG_ON(!PageCompound(page)); - kfree_hook(object); - __free_pages(page, compound_order(page)); - p[size] = NULL; /* mark object processed */ - return size; - } - /* Derive kmem_cache from object */ - df->s = page->slab_cache; - } else { - df->s = cache_from_obj(s, object); /* Support for memcg */ - } - - /* Start new detached freelist */ - df->page = page; - set_freepointer(df->s, object, NULL); - df->tail = object; - df->freelist = object; - p[size] = NULL; /* mark object processed */ - df->cnt = 1; - - while (size) { - object = p[--size]; - if (!object) - continue; /* Skip processed objects */ - - /* df->page is always set at this point */ - if (df->page == virt_to_head_page(object)) { - /* Opportunity build freelist */ - set_freepointer(df->s, object, df->freelist); - df->freelist = object; - df->cnt++; - p[size] = NULL; /* mark object processed */ - - continue; - } - - /* Limit look ahead search */ - if (!--lookahead) - break; - - if (!first_skipped_index) - first_skipped_index = size + 1; - } - - return first_skipped_index; -} - -/* Note that interrupts must be enabled when calling this function. */ -void kmem_cache_free_bulk(struct kmem_cache *s, size_t size, void **p) -{ - if (WARN_ON(!size)) - return; - - do { - struct detached_freelist df; - - size = build_detached_freelist(s, size, p, &df); - if (unlikely(!df.page)) - continue; - - slab_free(df.s, df.page, df.freelist, df.tail, df.cnt,_RET_IP_); - } while (likely(size)); -} -EXPORT_SYMBOL(kmem_cache_free_bulk); - -/* Note that interrupts must be enabled when calling this function. */ -int kmem_cache_alloc_bulk(struct kmem_cache *s, gfp_t flags, size_t size, - void **p) -{ - struct kmem_cache_cpu *c; - int i; - - /* memcg and kmem_cache debug support */ - s = slab_pre_alloc_hook(s, flags); - if (unlikely(!s)) - return false; - /* - * Drain objects in the per cpu slab, while disabling local - * IRQs, which protects against PREEMPT and interrupts - * handlers invoking normal fastpath. - */ - local_irq_disable(); - c = this_cpu_ptr(s->cpu_slab); - - for (i = 0; i < size; i++) { - void *object = c->freelist; - - if (unlikely(!object)) { - /* - * Invoking slow path likely have side-effect - * of re-populating per CPU c->freelist - */ - p[i] = ___slab_alloc(s, flags, NUMA_NO_NODE, - _RET_IP_, c); - if (unlikely(!p[i])) - goto error; - - c = this_cpu_ptr(s->cpu_slab); - continue; /* goto for-loop */ - } - c->freelist = get_freepointer(s, object); - p[i] = object; - } - c->tid = next_tid(c->tid); - local_irq_enable(); - - /* Clear memory outside IRQ disabled fastpath loop */ - if (unlikely(flags & __GFP_ZERO)) { - int j; - - for (j = 0; j < i; j++) - memset(p[j], 0, s->object_size); - } - - /* memcg and kmem_cache debug support */ - slab_post_alloc_hook(s, flags, size, p); - return i; -error: - local_irq_enable(); - slab_post_alloc_hook(s, flags, i, p); - __kmem_cache_free_bulk(s, i, p); - return 0; -} -EXPORT_SYMBOL(kmem_cache_alloc_bulk); - - -/* - * Object placement in a slab is made very easy because we always start at - * offset 0. If we tune the size of the object to the alignment then we can - * get the required alignment by putting one properly sized object after - * another. - * - * Notice that the allocation order determines the sizes of the per cpu - * caches. Each processor has always one slab available for allocations. - * Increasing the allocation order reduces the number of times that slabs - * must be moved on and off the partial lists and is therefore a factor in - * locking overhead. - */ - -/* - * Mininum / Maximum order of slab pages. This influences locking overhead - * and slab fragmentation. A higher order reduces the number of partial slabs - * and increases the number of allocations possible without having to - * take the list_lock. - */ -static int slub_min_order; -static int slub_max_order = PAGE_ALLOC_COSTLY_ORDER; -static int slub_min_objects; - -/* - * Calculate the order of allocation given an slab object size. - * - * The order of allocation has significant impact on performance and other - * system components. Generally order 0 allocations should be preferred since - * order 0 does not cause fragmentation in the page allocator. Larger objects - * be problematic to put into order 0 slabs because there may be too much - * unused space left. We go to a higher order if more than 1/16th of the slab - * would be wasted. - * - * In order to reach satisfactory performance we must ensure that a minimum - * number of objects is in one slab. Otherwise we may generate too much - * activity on the partial lists which requires taking the list_lock. This is - * less a concern for large slabs though which are rarely used. - * - * slub_max_order specifies the order where we begin to stop considering the - * number of objects in a slab as critical. If we reach slub_max_order then - * we try to keep the page order as low as possible. So we accept more waste - * of space in favor of a small page order. - * - * Higher order allocations also allow the placement of more objects in a - * slab and thereby reduce object handling overhead. If the user has - * requested a higher mininum order then we start with that one instead of - * the smallest order which will fit the object. - */ -static inline int slab_order(int size, int min_objects, - int max_order, int fract_leftover, int reserved) -{ - int order; - int rem; - int min_order = slub_min_order; - - if (order_objects(min_order, size, reserved) > MAX_OBJS_PER_PAGE) - return get_order(size * MAX_OBJS_PER_PAGE) - 1; - - for (order = max(min_order, get_order(min_objects * size + reserved)); - order <= max_order; order++) { - - unsigned long slab_size = PAGE_SIZE << order; - - rem = (slab_size - reserved) % size; - - if (rem <= slab_size / fract_leftover) - break; - } - - return order; -} - -static inline int calculate_order(int size, int reserved) -{ - int order; - int min_objects; - int fraction; - int max_objects; - - /* - * Attempt to find best configuration for a slab. This - * works by first attempting to generate a layout with - * the best configuration and backing off gradually. - * - * First we increase the acceptable waste in a slab. Then - * we reduce the minimum objects required in a slab. - */ - min_objects = slub_min_objects; - if (!min_objects) - min_objects = 4 * (fls(nr_cpu_ids) + 1); - max_objects = order_objects(slub_max_order, size, reserved); - min_objects = min(min_objects, max_objects); - - while (min_objects > 1) { - fraction = 16; - while (fraction >= 4) { - order = slab_order(size, min_objects, - slub_max_order, fraction, reserved); - if (order <= slub_max_order) - return order; - fraction /= 2; - } - min_objects--; - } - - /* - * We were unable to place multiple objects in a slab. Now - * lets see if we can place a single object there. - */ - order = slab_order(size, 1, slub_max_order, 1, reserved); - if (order <= slub_max_order) - return order; - - /* - * Doh this slab cannot be placed using slub_max_order. - */ - order = slab_order(size, 1, MAX_ORDER, 1, reserved); - if (order < MAX_ORDER) - return order; - return -ENOSYS; -} - -static void -init_kmem_cache_node(struct kmem_cache_node *n) -{ - n->nr_partial = 0; - spin_lock_init(&n->list_lock); - INIT_LIST_HEAD(&n->partial); -#ifdef CONFIG_SLUB_DEBUG - atomic_long_set(&n->nr_slabs, 0); - atomic_long_set(&n->total_objects, 0); - INIT_LIST_HEAD(&n->full); -#endif -} - -static inline int alloc_kmem_cache_cpus(struct kmem_cache *s) -{ - BUILD_BUG_ON(PERCPU_DYNAMIC_EARLY_SIZE < - KMALLOC_SHIFT_HIGH * sizeof(struct kmem_cache_cpu)); - - /* - * Must align to double word boundary for the double cmpxchg - * instructions to work; see __pcpu_double_call_return_bool(). - */ - s->cpu_slab = __alloc_percpu(sizeof(struct kmem_cache_cpu), - 2 * sizeof(void *)); - - if (!s->cpu_slab) - return 0; - - init_kmem_cache_cpus(s); - - return 1; -} - -static struct kmem_cache *kmem_cache_node; - -/* - * No kmalloc_node yet so do it by hand. We know that this is the first - * slab on the node for this slabcache. There are no concurrent accesses - * possible. - * - * Note that this function only works on the kmem_cache_node - * when allocating for the kmem_cache_node. This is used for bootstrapping - * memory on a fresh node that has no slab structures yet. - */ -static void early_kmem_cache_node_alloc(int node) -{ - struct page *page; - struct kmem_cache_node *n; - - BUG_ON(kmem_cache_node->size < sizeof(struct kmem_cache_node)); - - page = new_slab(kmem_cache_node, GFP_NOWAIT, node); - - BUG_ON(!page); - if (page_to_nid(page) != node) { - pr_err("SLUB: Unable to allocate memory from node %d\n", node); - pr_err("SLUB: Allocating a useless per node structure in order to be able to continue\n"); - } - - n = page->freelist; - BUG_ON(!n); - page->freelist = get_freepointer(kmem_cache_node, n); - page->inuse = 1; - page->frozen = 0; - kmem_cache_node->node[node] = n; -#ifdef CONFIG_SLUB_DEBUG - init_object(kmem_cache_node, n, SLUB_RED_ACTIVE); - init_tracking(kmem_cache_node, n); -#endif - kasan_kmalloc(kmem_cache_node, n, sizeof(struct kmem_cache_node), - GFP_KERNEL); - init_kmem_cache_node(n); - inc_slabs_node(kmem_cache_node, node, page->objects); - - /* - * No locks need to be taken here as it has just been - * initialized and there is no concurrent access. - */ - __add_partial(n, page, DEACTIVATE_TO_HEAD); -} - -static void free_kmem_cache_nodes(struct kmem_cache *s) -{ - int node; - struct kmem_cache_node *n; - - for_each_kmem_cache_node(s, node, n) { - kmem_cache_free(kmem_cache_node, n); - s->node[node] = NULL; - } -} - -void __kmem_cache_release(struct kmem_cache *s) -{ - cache_random_seq_destroy(s); - free_percpu(s->cpu_slab); - free_kmem_cache_nodes(s); -} - -static int init_kmem_cache_nodes(struct kmem_cache *s) -{ - int node; - - for_each_node_state(node, N_NORMAL_MEMORY) { - struct kmem_cache_node *n; - - if (slab_state == DOWN) { - early_kmem_cache_node_alloc(node); - continue; - } - n = kmem_cache_alloc_node(kmem_cache_node, - GFP_KERNEL, node); - - if (!n) { - free_kmem_cache_nodes(s); - return 0; - } - - s->node[node] = n; - init_kmem_cache_node(n); - } - return 1; -} - -static void set_min_partial(struct kmem_cache *s, unsigned long min) -{ - if (min < MIN_PARTIAL) - min = MIN_PARTIAL; - else if (min > MAX_PARTIAL) - min = MAX_PARTIAL; - s->min_partial = min; -} - -/* - * calculate_sizes() determines the order and the distribution of data within - * a slab object. - */ -static int calculate_sizes(struct kmem_cache *s, int forced_order) -{ - unsigned long flags = s->flags; - size_t size = s->object_size; - int order; - - /* - * Round up object size to the next word boundary. We can only - * place the free pointer at word boundaries and this determines - * the possible location of the free pointer. - */ - size = ALIGN(size, sizeof(void *)); - -#ifdef CONFIG_SLUB_DEBUG - /* - * Determine if we can poison the object itself. If the user of - * the slab may touch the object after free or before allocation - * then we should never poison the object itself. - */ - if ((flags & SLAB_POISON) && !(flags & SLAB_DESTROY_BY_RCU) && - !s->ctor) - s->flags |= __OBJECT_POISON; - else - s->flags &= ~__OBJECT_POISON; - - - /* - * If we are Redzoning then check if there is some space between the - * end of the object and the free pointer. If not then add an - * additional word to have some bytes to store Redzone information. - */ - if ((flags & SLAB_RED_ZONE) && size == s->object_size) - size += sizeof(void *); -#endif - - /* - * With that we have determined the number of bytes in actual use - * by the object. This is the potential offset to the free pointer. - */ - s->inuse = size; - - if (((flags & (SLAB_DESTROY_BY_RCU | SLAB_POISON)) || - s->ctor)) { - /* - * Relocate free pointer after the object if it is not - * permitted to overwrite the first word of the object on - * kmem_cache_free. - * - * This is the case if we do RCU, have a constructor or - * destructor or are poisoning the objects. - */ - s->offset = size; - size += sizeof(void *); - } - -#ifdef CONFIG_SLUB_DEBUG - if (flags & SLAB_STORE_USER) - /* - * Need to store information about allocs and frees after - * the object. - */ - size += 2 * sizeof(struct track); -#endif - - kasan_cache_create(s, &size, &s->flags); -#ifdef CONFIG_SLUB_DEBUG - if (flags & SLAB_RED_ZONE) { - /* - * Add some empty padding so that we can catch - * overwrites from earlier objects rather than let - * tracking information or the free pointer be - * corrupted if a user writes before the start - * of the object. - */ - size += sizeof(void *); - - s->red_left_pad = sizeof(void *); - s->red_left_pad = ALIGN(s->red_left_pad, s->align); - size += s->red_left_pad; - } -#endif - - /* - * SLUB stores one object immediately after another beginning from - * offset 0. In order to align the objects we have to simply size - * each object to conform to the alignment. - */ - size = ALIGN(size, s->align); - s->size = size; - if (forced_order >= 0) - order = forced_order; - else - order = calculate_order(size, s->reserved); - - if (order < 0) - return 0; - - s->allocflags = 0; - if (order) - s->allocflags |= __GFP_COMP; - - if (s->flags & SLAB_CACHE_DMA) - s->allocflags |= GFP_DMA; - - if (s->flags & SLAB_RECLAIM_ACCOUNT) - s->allocflags |= __GFP_RECLAIMABLE; - - /* - * Determine the number of objects per slab - */ - s->oo = oo_make(order, size, s->reserved); - s->min = oo_make(get_order(size), size, s->reserved); - if (oo_objects(s->oo) > oo_objects(s->max)) - s->max = s->oo; - - return !!oo_objects(s->oo); -} - -static int kmem_cache_open(struct kmem_cache *s, unsigned long flags) -{ - s->flags = kmem_cache_flags(s->size, flags, s->name, s->ctor); - s->reserved = 0; - - if (need_reserve_slab_rcu && (s->flags & SLAB_DESTROY_BY_RCU)) - s->reserved = sizeof(struct rcu_head); - - if (!calculate_sizes(s, -1)) - goto error; - if (disable_higher_order_debug) { - /* - * Disable debugging flags that store metadata if the min slab - * order increased. - */ - if (get_order(s->size) > get_order(s->object_size)) { - s->flags &= ~DEBUG_METADATA_FLAGS; - s->offset = 0; - if (!calculate_sizes(s, -1)) - goto error; - } - } - -#if defined(CONFIG_HAVE_CMPXCHG_DOUBLE) && \ - defined(CONFIG_HAVE_ALIGNED_STRUCT_PAGE) - if (system_has_cmpxchg_double() && (s->flags & SLAB_NO_CMPXCHG) == 0) - /* Enable fast mode */ - s->flags |= __CMPXCHG_DOUBLE; -#endif - - /* - * The larger the object size is, the more pages we want on the partial - * list to avoid pounding the page allocator excessively. - */ - set_min_partial(s, ilog2(s->size) / 2); - - /* - * cpu_partial determined the maximum number of objects kept in the - * per cpu partial lists of a processor. - * - * Per cpu partial lists mainly contain slabs that just have one - * object freed. If they are used for allocation then they can be - * filled up again with minimal effort. The slab will never hit the - * per node partial lists and therefore no locking will be required. - * - * This setting also determines - * - * A) The number of objects from per cpu partial slabs dumped to the - * per node list when we reach the limit. - * B) The number of objects in cpu partial slabs to extract from the - * per node list when we run out of per cpu objects. We only fetch - * 50% to keep some capacity around for frees. - */ - if (!kmem_cache_has_cpu_partial(s)) - s->cpu_partial = 0; - else if (s->size >= PAGE_SIZE) - s->cpu_partial = 2; - else if (s->size >= 1024) - s->cpu_partial = 6; - else if (s->size >= 256) - s->cpu_partial = 13; - else - s->cpu_partial = 30; - -#ifdef CONFIG_NUMA - s->remote_node_defrag_ratio = 1000; -#endif - - /* Initialize the pre-computed randomized freelist if slab is up */ - if (slab_state >= UP) { - if (init_cache_random_seq(s)) - goto error; - } - - if (!init_kmem_cache_nodes(s)) - goto error; - - if (alloc_kmem_cache_cpus(s)) - return 0; - - free_kmem_cache_nodes(s); -error: - if (flags & SLAB_PANIC) - panic("Cannot create slab %s size=%lu realsize=%u order=%u offset=%u flags=%lx\n", - s->name, (unsigned long)s->size, s->size, - oo_order(s->oo), s->offset, flags); - return -EINVAL; -} - -static void list_slab_objects(struct kmem_cache *s, struct page *page, - const char *text) -{ -#ifdef CONFIG_SLUB_DEBUG - void *addr = page_address(page); - void *p; - unsigned long *map = kzalloc(BITS_TO_LONGS(page->objects) * - sizeof(long), GFP_ATOMIC); - if (!map) - return; - slab_err(s, page, text, s->name); - slab_lock(page); - - get_map(s, page, map); - for_each_object(p, s, addr, page->objects) { - - if (!test_bit(slab_index(p, s, addr), map)) { - pr_err("INFO: Object 0x%p @offset=%tu\n", p, p - addr); - print_tracking(s, p); - } - } - slab_unlock(page); - kfree(map); -#endif -} - -/* - * Attempt to free all partial slabs on a node. - * This is called from __kmem_cache_shutdown(). We must take list_lock - * because sysfs file might still access partial list after the shutdowning. - */ -static void free_partial(struct kmem_cache *s, struct kmem_cache_node *n) -{ - LIST_HEAD(discard); - struct page *page, *h; - - BUG_ON(irqs_disabled()); - spin_lock_irq(&n->list_lock); - list_for_each_entry_safe(page, h, &n->partial, lru) { - if (!page->inuse) { - remove_partial(n, page); - list_add(&page->lru, &discard); - } else { - list_slab_objects(s, page, - "Objects remaining in %s on __kmem_cache_shutdown()"); - } - } - spin_unlock_irq(&n->list_lock); - - list_for_each_entry_safe(page, h, &discard, lru) - discard_slab(s, page); -} - -/* - * Release all resources used by a slab cache. - */ -int __kmem_cache_shutdown(struct kmem_cache *s) -{ - int node; - struct kmem_cache_node *n; - - flush_all(s); - /* Attempt to free all objects */ - for_each_kmem_cache_node(s, node, n) { - free_partial(s, n); - if (n->nr_partial || slabs_node(s, node)) - return 1; - } - return 0; -} - -/******************************************************************** - * Kmalloc subsystem - *******************************************************************/ - -static int __init setup_slub_min_order(char *str) -{ - get_option(&str, &slub_min_order); - - return 1; -} - -__setup("slub_min_order=", setup_slub_min_order); - -static int __init setup_slub_max_order(char *str) -{ - get_option(&str, &slub_max_order); - slub_max_order = min(slub_max_order, MAX_ORDER - 1); - - return 1; -} - -__setup("slub_max_order=", setup_slub_max_order); - -static int __init setup_slub_min_objects(char *str) -{ - get_option(&str, &slub_min_objects); - - return 1; -} - -__setup("slub_min_objects=", setup_slub_min_objects); - -void *__kmalloc(size_t size, gfp_t flags) -{ - struct kmem_cache *s; - void *ret; - - if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) - return kmalloc_large(size, flags); - - s = kmalloc_slab(size, flags); - - if (unlikely(ZERO_OR_NULL_PTR(s))) - return s; - - ret = slab_alloc(s, flags, _RET_IP_); - - trace_kmalloc(_RET_IP_, ret, size, s->size, flags); - - kasan_kmalloc(s, ret, size, flags); - - return ret; -} -EXPORT_SYMBOL(__kmalloc); - -#ifdef CONFIG_NUMA -static void *kmalloc_large_node(size_t size, gfp_t flags, int node) -{ - struct page *page; - void *ptr = NULL; - - flags |= __GFP_COMP | __GFP_NOTRACK; - page = alloc_pages_node(node, flags, get_order(size)); - if (page) - ptr = page_address(page); - - kmalloc_large_node_hook(ptr, size, flags); - return ptr; -} - -void *__kmalloc_node(size_t size, gfp_t flags, int node) -{ - struct kmem_cache *s; - void *ret; - - if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) { - ret = kmalloc_large_node(size, flags, node); - - trace_kmalloc_node(_RET_IP_, ret, - size, PAGE_SIZE << get_order(size), - flags, node); - - return ret; - } - - s = kmalloc_slab(size, flags); - - if (unlikely(ZERO_OR_NULL_PTR(s))) - return s; - - ret = slab_alloc_node(s, flags, node, _RET_IP_); - - trace_kmalloc_node(_RET_IP_, ret, size, s->size, flags, node); - - kasan_kmalloc(s, ret, size, flags); - - return ret; -} -EXPORT_SYMBOL(__kmalloc_node); -#endif - -#ifdef CONFIG_HARDENED_USERCOPY -/* - * Rejects objects that are incorrectly sized. - * - * Returns NULL if check passes, otherwise const char * to name of cache - * to indicate an error. - */ -const char *__check_heap_object(const void *ptr, unsigned long n, - struct page *page) -{ - struct kmem_cache *s; - unsigned long offset; - size_t object_size; - - /* Find object and usable object size. */ - s = page->slab_cache; - object_size = slab_ksize(s); - - /* Reject impossible pointers. */ - if (ptr < page_address(page)) - return s->name; - - /* Find offset within object. */ - offset = (ptr - page_address(page)) % s->size; - - /* Adjust for redzone and reject if within the redzone. */ - if (kmem_cache_debug(s) && s->flags & SLAB_RED_ZONE) { - if (offset < s->red_left_pad) - return s->name; - offset -= s->red_left_pad; - } - - /* Allow address range falling entirely within object size. */ - if (offset <= object_size && n <= object_size - offset) - return NULL; - - return s->name; -} -#endif /* CONFIG_HARDENED_USERCOPY */ - -static size_t __ksize(const void *object) -{ - struct page *page; - - if (unlikely(object == ZERO_SIZE_PTR)) - return 0; - - page = virt_to_head_page(object); - - if (unlikely(!PageSlab(page))) { - WARN_ON(!PageCompound(page)); - return PAGE_SIZE << compound_order(page); - } - - return slab_ksize(page->slab_cache); -} - -size_t ksize(const void *object) -{ - size_t size = __ksize(object); - /* We assume that ksize callers could use whole allocated area, - * so we need to unpoison this area. - */ - kasan_unpoison_shadow(object, size); - return size; -} -EXPORT_SYMBOL(ksize); - -void kfree(const void *x) -{ - struct page *page; - void *object = (void *)x; - - trace_kfree(_RET_IP_, x); - - if (unlikely(ZERO_OR_NULL_PTR(x))) - return; - - page = virt_to_head_page(x); - if (unlikely(!PageSlab(page))) { - BUG_ON(!PageCompound(page)); - kfree_hook(x); - __free_pages(page, compound_order(page)); - return; - } - slab_free(page->slab_cache, page, object, NULL, 1, _RET_IP_); -} -EXPORT_SYMBOL(kfree); - -#define SHRINK_PROMOTE_MAX 32 - -/* - * kmem_cache_shrink discards empty slabs and promotes the slabs filled - * up most to the head of the partial lists. New allocations will then - * fill those up and thus they can be removed from the partial lists. - * - * The slabs with the least items are placed last. This results in them - * being allocated from last increasing the chance that the last objects - * are freed in them. - */ -int __kmem_cache_shrink(struct kmem_cache *s, bool deactivate) -{ - int node; - int i; - struct kmem_cache_node *n; - struct page *page; - struct page *t; - struct list_head discard; - struct list_head promote[SHRINK_PROMOTE_MAX]; - unsigned long flags; - int ret = 0; - - if (deactivate) { - /* - * Disable empty slabs caching. Used to avoid pinning offline - * memory cgroups by kmem pages that can be freed. - */ - s->cpu_partial = 0; - s->min_partial = 0; - - /* - * s->cpu_partial is checked locklessly (see put_cpu_partial), - * so we have to make sure the change is visible. - */ - synchronize_sched(); - } - - flush_all(s); - for_each_kmem_cache_node(s, node, n) { - INIT_LIST_HEAD(&discard); - for (i = 0; i < SHRINK_PROMOTE_MAX; i++) - INIT_LIST_HEAD(promote + i); - - spin_lock_irqsave(&n->list_lock, flags); - - /* - * Build lists of slabs to discard or promote. - * - * Note that concurrent frees may occur while we hold the - * list_lock. page->inuse here is the upper limit. - */ - list_for_each_entry_safe(page, t, &n->partial, lru) { - int free = page->objects - page->inuse; - - /* Do not reread page->inuse */ - barrier(); - - /* We do not keep full slabs on the list */ - BUG_ON(free <= 0); - - if (free == page->objects) { - list_move(&page->lru, &discard); - n->nr_partial--; - } else if (free <= SHRINK_PROMOTE_MAX) - list_move(&page->lru, promote + free - 1); - } - - /* - * Promote the slabs filled up most to the head of the - * partial list. - */ - for (i = SHRINK_PROMOTE_MAX - 1; i >= 0; i--) - list_splice(promote + i, &n->partial); - - spin_unlock_irqrestore(&n->list_lock, flags); - - /* Release empty slabs */ - list_for_each_entry_safe(page, t, &discard, lru) - discard_slab(s, page); - - if (slabs_node(s, node)) - ret = 1; - } - - return ret; -} - -static int slab_mem_going_offline_callback(void *arg) -{ - struct kmem_cache *s; - - mutex_lock(&slab_mutex); - list_for_each_entry(s, &slab_caches, list) - __kmem_cache_shrink(s, false); - mutex_unlock(&slab_mutex); - - return 0; -} - -static void slab_mem_offline_callback(void *arg) -{ - struct kmem_cache_node *n; - struct kmem_cache *s; - struct memory_notify *marg = arg; - int offline_node; - - offline_node = marg->status_change_nid_normal; - - /* - * If the node still has available memory. we need kmem_cache_node - * for it yet. - */ - if (offline_node < 0) - return; - - mutex_lock(&slab_mutex); - list_for_each_entry(s, &slab_caches, list) { - n = get_node(s, offline_node); - if (n) { - /* - * if n->nr_slabs > 0, slabs still exist on the node - * that is going down. We were unable to free them, - * and offline_pages() function shouldn't call this - * callback. So, we must fail. - */ - BUG_ON(slabs_node(s, offline_node)); - - s->node[offline_node] = NULL; - kmem_cache_free(kmem_cache_node, n); - } - } - mutex_unlock(&slab_mutex); -} - -static int slab_mem_going_online_callback(void *arg) -{ - struct kmem_cache_node *n; - struct kmem_cache *s; - struct memory_notify *marg = arg; - int nid = marg->status_change_nid_normal; - int ret = 0; - - /* - * If the node's memory is already available, then kmem_cache_node is - * already created. Nothing to do. - */ - if (nid < 0) - return 0; - - /* - * We are bringing a node online. No memory is available yet. We must - * allocate a kmem_cache_node structure in order to bring the node - * online. - */ - mutex_lock(&slab_mutex); - list_for_each_entry(s, &slab_caches, list) { - /* - * XXX: kmem_cache_alloc_node will fallback to other nodes - * since memory is not yet available from the node that - * is brought up. - */ - n = kmem_cache_alloc(kmem_cache_node, GFP_KERNEL); - if (!n) { - ret = -ENOMEM; - goto out; - } - init_kmem_cache_node(n); - s->node[nid] = n; - } -out: - mutex_unlock(&slab_mutex); - return ret; -} - -static int slab_memory_callback(struct notifier_block *self, - unsigned long action, void *arg) -{ - int ret = 0; - - switch (action) { - case MEM_GOING_ONLINE: - ret = slab_mem_going_online_callback(arg); - break; - case MEM_GOING_OFFLINE: - ret = slab_mem_going_offline_callback(arg); - break; - case MEM_OFFLINE: - case MEM_CANCEL_ONLINE: - slab_mem_offline_callback(arg); - break; - case MEM_ONLINE: - case MEM_CANCEL_OFFLINE: - break; - } - if (ret) - ret = notifier_from_errno(ret); - else - ret = NOTIFY_OK; - return ret; -} - -static struct notifier_block slab_memory_callback_nb = { - .notifier_call = slab_memory_callback, - .priority = SLAB_CALLBACK_PRI, -}; - -/******************************************************************** - * Basic setup of slabs - *******************************************************************/ - -/* - * Used for early kmem_cache structures that were allocated using - * the page allocator. Allocate them properly then fix up the pointers - * that may be pointing to the wrong kmem_cache structure. - */ - -static struct kmem_cache * __init bootstrap(struct kmem_cache *static_cache) -{ - int node; - struct kmem_cache *s = kmem_cache_zalloc(kmem_cache, GFP_NOWAIT); - struct kmem_cache_node *n; - - memcpy(s, static_cache, kmem_cache->object_size); - - /* - * This runs very early, and only the boot processor is supposed to be - * up. Even if it weren't true, IRQs are not up so we couldn't fire - * IPIs around. - */ - __flush_cpu_slab(s, smp_processor_id()); - for_each_kmem_cache_node(s, node, n) { - struct page *p; - - list_for_each_entry(p, &n->partial, lru) - p->slab_cache = s; - -#ifdef CONFIG_SLUB_DEBUG - list_for_each_entry(p, &n->full, lru) - p->slab_cache = s; -#endif - } - slab_init_memcg_params(s); - list_add(&s->list, &slab_caches); - return s; -} - -void __init kmem_cache_init(void) -{ - static __initdata struct kmem_cache boot_kmem_cache, - boot_kmem_cache_node; - - if (debug_guardpage_minorder()) - slub_max_order = 0; - - kmem_cache_node = &boot_kmem_cache_node; - kmem_cache = &boot_kmem_cache; - - create_boot_cache(kmem_cache_node, "kmem_cache_node", - sizeof(struct kmem_cache_node), SLAB_HWCACHE_ALIGN); - - register_hotmemory_notifier(&slab_memory_callback_nb); - - /* Able to allocate the per node structures */ - slab_state = PARTIAL; - - create_boot_cache(kmem_cache, "kmem_cache", - offsetof(struct kmem_cache, node) + - nr_node_ids * sizeof(struct kmem_cache_node *), - SLAB_HWCACHE_ALIGN); - - kmem_cache = bootstrap(&boot_kmem_cache); - - /* - * Allocate kmem_cache_node properly from the kmem_cache slab. - * kmem_cache_node is separately allocated so no need to - * update any list pointers. - */ - kmem_cache_node = bootstrap(&boot_kmem_cache_node); - - /* Now we can use the kmem_cache to allocate kmalloc slabs */ - setup_kmalloc_cache_index_table(); - create_kmalloc_caches(0); - - /* Setup random freelists for each cache */ - init_freelist_randomization(); - - cpuhp_setup_state_nocalls(CPUHP_SLUB_DEAD, "slub:dead", NULL, - slub_cpu_dead); - - pr_info("SLUB: HWalign=%d, Order=%d-%d, MinObjects=%d, CPUs=%d, Nodes=%d\n", - cache_line_size(), - slub_min_order, slub_max_order, slub_min_objects, - nr_cpu_ids, nr_node_ids); -} - -void __init kmem_cache_init_late(void) -{ -} - -struct kmem_cache * -__kmem_cache_alias(const char *name, size_t size, size_t align, - unsigned long flags, void (*ctor)(void *)) -{ - struct kmem_cache *s, *c; - - s = find_mergeable(size, align, flags, name, ctor); - if (s) { - s->refcount++; - - /* - * Adjust the object sizes so that we clear - * the complete object on kzalloc. - */ - s->object_size = max(s->object_size, (int)size); - s->inuse = max_t(int, s->inuse, ALIGN(size, sizeof(void *))); - - for_each_memcg_cache(c, s) { - c->object_size = s->object_size; - c->inuse = max_t(int, c->inuse, - ALIGN(size, sizeof(void *))); - } - - if (sysfs_slab_alias(s, name)) { - s->refcount--; - s = NULL; - } - } - - return s; -} - -int __kmem_cache_create(struct kmem_cache *s, unsigned long flags) -{ - int err; - - err = kmem_cache_open(s, flags); - if (err) - return err; - - /* Mutex is not taken during early boot */ - if (slab_state <= UP) - return 0; - - memcg_propagate_slab_attrs(s); - err = sysfs_slab_add(s); - if (err) - __kmem_cache_release(s); - - return err; -} - -void *__kmalloc_track_caller(size_t size, gfp_t gfpflags, unsigned long caller) -{ - struct kmem_cache *s; - void *ret; - - if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) - return kmalloc_large(size, gfpflags); - - s = kmalloc_slab(size, gfpflags); - - if (unlikely(ZERO_OR_NULL_PTR(s))) - return s; - - ret = slab_alloc(s, gfpflags, caller); - - /* Honor the call site pointer we received. */ - trace_kmalloc(caller, ret, size, s->size, gfpflags); - - return ret; -} - -#ifdef CONFIG_NUMA -void *__kmalloc_node_track_caller(size_t size, gfp_t gfpflags, - int node, unsigned long caller) -{ - struct kmem_cache *s; - void *ret; - - if (unlikely(size > KMALLOC_MAX_CACHE_SIZE)) { - ret = kmalloc_large_node(size, gfpflags, node); - - trace_kmalloc_node(caller, ret, - size, PAGE_SIZE << get_order(size), - gfpflags, node); - - return ret; - } - - s = kmalloc_slab(size, gfpflags); - - if (unlikely(ZERO_OR_NULL_PTR(s))) - return s; - - ret = slab_alloc_node(s, gfpflags, node, caller); - - /* Honor the call site pointer we received. */ - trace_kmalloc_node(caller, ret, size, s->size, gfpflags, node); - - return ret; -} -#endif - -#ifdef CONFIG_SYSFS -static int count_inuse(struct page *page) -{ - return page->inuse; -} - -static int count_total(struct page *page) -{ - return page->objects; -} -#endif - -#ifdef CONFIG_SLUB_DEBUG -static int validate_slab(struct kmem_cache *s, struct page *page, - unsigned long *map) -{ - void *p; - void *addr = page_address(page); - - if (!check_slab(s, page) || - !on_freelist(s, page, NULL)) - return 0; - - /* Now we know that a valid freelist exists */ - bitmap_zero(map, page->objects); - - get_map(s, page, map); - for_each_object(p, s, addr, page->objects) { - if (test_bit(slab_index(p, s, addr), map)) - if (!check_object(s, page, p, SLUB_RED_INACTIVE)) - return 0; - } - - for_each_object(p, s, addr, page->objects) - if (!test_bit(slab_index(p, s, addr), map)) - if (!check_object(s, page, p, SLUB_RED_ACTIVE)) - return 0; - return 1; -} - -static void validate_slab_slab(struct kmem_cache *s, struct page *page, - unsigned long *map) -{ - slab_lock(page); - validate_slab(s, page, map); - slab_unlock(page); -} - -static int validate_slab_node(struct kmem_cache *s, - struct kmem_cache_node *n, unsigned long *map) -{ - unsigned long count = 0; - struct page *page; - unsigned long flags; - - spin_lock_irqsave(&n->list_lock, flags); - - list_for_each_entry(page, &n->partial, lru) { - validate_slab_slab(s, page, map); - count++; - } - if (count != n->nr_partial) - pr_err("SLUB %s: %ld partial slabs counted but counter=%ld\n", - s->name, count, n->nr_partial); - - if (!(s->flags & SLAB_STORE_USER)) - goto out; - - list_for_each_entry(page, &n->full, lru) { - validate_slab_slab(s, page, map); - count++; - } - if (count != atomic_long_read(&n->nr_slabs)) - pr_err("SLUB: %s %ld slabs counted but counter=%ld\n", - s->name, count, atomic_long_read(&n->nr_slabs)); - -out: - spin_unlock_irqrestore(&n->list_lock, flags); - return count; -} - -static long validate_slab_cache(struct kmem_cache *s) -{ - int node; - unsigned long count = 0; - unsigned long *map = kmalloc(BITS_TO_LONGS(oo_objects(s->max)) * - sizeof(unsigned long), GFP_KERNEL); - struct kmem_cache_node *n; - - if (!map) - return -ENOMEM; - - flush_all(s); - for_each_kmem_cache_node(s, node, n) - count += validate_slab_node(s, n, map); - kfree(map); - return count; -} -/* - * Generate lists of code addresses where slabcache objects are allocated - * and freed. - */ - -struct location { - unsigned long count; - unsigned long addr; - long long sum_time; - long min_time; - long max_time; - long min_pid; - long max_pid; - DECLARE_BITMAP(cpus, NR_CPUS); - nodemask_t nodes; -}; - -struct loc_track { - unsigned long max; - unsigned long count; - struct location *loc; -}; - -static void free_loc_track(struct loc_track *t) -{ - if (t->max) - free_pages((unsigned long)t->loc, - get_order(sizeof(struct location) * t->max)); -} - -static int alloc_loc_track(struct loc_track *t, unsigned long max, gfp_t flags) -{ - struct location *l; - int order; - - order = get_order(sizeof(struct location) * max); - - l = (void *)__get_free_pages(flags, order); - if (!l) - return 0; - - if (t->count) { - memcpy(l, t->loc, sizeof(struct location) * t->count); - free_loc_track(t); - } - t->max = max; - t->loc = l; - return 1; -} - -static int add_location(struct loc_track *t, struct kmem_cache *s, - const struct track *track) -{ - long start, end, pos; - struct location *l; - unsigned long caddr; - unsigned long age = jiffies - track->when; - - start = -1; - end = t->count; - - for ( ; ; ) { - pos = start + (end - start + 1) / 2; - - /* - * There is nothing at "end". If we end up there - * we need to add something to before end. - */ - if (pos == end) - break; - - caddr = t->loc[pos].addr; - if (track->addr == caddr) { - - l = &t->loc[pos]; - l->count++; - if (track->when) { - l->sum_time += age; - if (age < l->min_time) - l->min_time = age; - if (age > l->max_time) - l->max_time = age; - - if (track->pid < l->min_pid) - l->min_pid = track->pid; - if (track->pid > l->max_pid) - l->max_pid = track->pid; - - cpumask_set_cpu(track->cpu, - to_cpumask(l->cpus)); - } - node_set(page_to_nid(virt_to_page(track)), l->nodes); - return 1; - } - - if (track->addr < caddr) - end = pos; - else - start = pos; - } - - /* - * Not found. Insert new tracking element. - */ - if (t->count >= t->max && !alloc_loc_track(t, 2 * t->max, GFP_ATOMIC)) - return 0; - - l = t->loc + pos; - if (pos < t->count) - memmove(l + 1, l, - (t->count - pos) * sizeof(struct location)); - t->count++; - l->count = 1; - l->addr = track->addr; - l->sum_time = age; - l->min_time = age; - l->max_time = age; - l->min_pid = track->pid; - l->max_pid = track->pid; - cpumask_clear(to_cpumask(l->cpus)); - cpumask_set_cpu(track->cpu, to_cpumask(l->cpus)); - nodes_clear(l->nodes); - node_set(page_to_nid(virt_to_page(track)), l->nodes); - return 1; -} - -static void process_slab(struct loc_track *t, struct kmem_cache *s, - struct page *page, enum track_item alloc, - unsigned long *map) -{ - void *addr = page_address(page); - void *p; - - bitmap_zero(map, page->objects); - get_map(s, page, map); - - for_each_object(p, s, addr, page->objects) - if (!test_bit(slab_index(p, s, addr), map)) - add_location(t, s, get_track(s, p, alloc)); -} - -static int list_locations(struct kmem_cache *s, char *buf, - enum track_item alloc) -{ - int len = 0; - unsigned long i; - struct loc_track t = { 0, 0, NULL }; - int node; - unsigned long *map = kmalloc(BITS_TO_LONGS(oo_objects(s->max)) * - sizeof(unsigned long), GFP_KERNEL); - struct kmem_cache_node *n; - - if (!map || !alloc_loc_track(&t, PAGE_SIZE / sizeof(struct location), - GFP_TEMPORARY)) { - kfree(map); - return sprintf(buf, "Out of memory\n"); - } - /* Push back cpu slabs */ - flush_all(s); - - for_each_kmem_cache_node(s, node, n) { - unsigned long flags; - struct page *page; - - if (!atomic_long_read(&n->nr_slabs)) - continue; - - spin_lock_irqsave(&n->list_lock, flags); - list_for_each_entry(page, &n->partial, lru) - process_slab(&t, s, page, alloc, map); - list_for_each_entry(page, &n->full, lru) - process_slab(&t, s, page, alloc, map); - spin_unlock_irqrestore(&n->list_lock, flags); - } - - for (i = 0; i < t.count; i++) { - struct location *l = &t.loc[i]; - - if (len > PAGE_SIZE - KSYM_SYMBOL_LEN - 100) - break; - len += sprintf(buf + len, "%7ld ", l->count); - - if (l->addr) - len += sprintf(buf + len, "%pS", (void *)l->addr); - else - len += sprintf(buf + len, ""); - - if (l->sum_time != l->min_time) { - len += sprintf(buf + len, " age=%ld/%ld/%ld", - l->min_time, - (long)div_u64(l->sum_time, l->count), - l->max_time); - } else - len += sprintf(buf + len, " age=%ld", - l->min_time); - - if (l->min_pid != l->max_pid) - len += sprintf(buf + len, " pid=%ld-%ld", - l->min_pid, l->max_pid); - else - len += sprintf(buf + len, " pid=%ld", - l->min_pid); - - if (num_online_cpus() > 1 && - !cpumask_empty(to_cpumask(l->cpus)) && - len < PAGE_SIZE - 60) - len += scnprintf(buf + len, PAGE_SIZE - len - 50, - " cpus=%*pbl", - cpumask_pr_args(to_cpumask(l->cpus))); - - if (nr_online_nodes > 1 && !nodes_empty(l->nodes) && - len < PAGE_SIZE - 60) - len += scnprintf(buf + len, PAGE_SIZE - len - 50, - " nodes=%*pbl", - nodemask_pr_args(&l->nodes)); - - len += sprintf(buf + len, "\n"); - } - - free_loc_track(&t); - kfree(map); - if (!t.count) - len += sprintf(buf, "No data\n"); - return len; -} -#endif - -#ifdef SLUB_RESILIENCY_TEST -static void __init resiliency_test(void) -{ - u8 *p; - - BUILD_BUG_ON(KMALLOC_MIN_SIZE > 16 || KMALLOC_SHIFT_HIGH < 10); - - pr_err("SLUB resiliency testing\n"); - pr_err("-----------------------\n"); - pr_err("A. Corruption after allocation\n"); - - p = kzalloc(16, GFP_KERNEL); - p[16] = 0x12; - pr_err("\n1. kmalloc-16: Clobber Redzone/next pointer 0x12->0x%p\n\n", - p + 16); - - validate_slab_cache(kmalloc_caches[4]); - - /* Hmmm... The next two are dangerous */ - p = kzalloc(32, GFP_KERNEL); - p[32 + sizeof(void *)] = 0x34; - pr_err("\n2. kmalloc-32: Clobber next pointer/next slab 0x34 -> -0x%p\n", - p); - pr_err("If allocated object is overwritten then not detectable\n\n"); - - validate_slab_cache(kmalloc_caches[5]); - p = kzalloc(64, GFP_KERNEL); - p += 64 + (get_cycles() & 0xff) * sizeof(void *); - *p = 0x56; - pr_err("\n3. kmalloc-64: corrupting random byte 0x56->0x%p\n", - p); - pr_err("If allocated object is overwritten then not detectable\n\n"); - validate_slab_cache(kmalloc_caches[6]); - - pr_err("\nB. Corruption after free\n"); - p = kzalloc(128, GFP_KERNEL); - kfree(p); - *p = 0x78; - pr_err("1. kmalloc-128: Clobber first word 0x78->0x%p\n\n", p); - validate_slab_cache(kmalloc_caches[7]); - - p = kzalloc(256, GFP_KERNEL); - kfree(p); - p[50] = 0x9a; - pr_err("\n2. kmalloc-256: Clobber 50th byte 0x9a->0x%p\n\n", p); - validate_slab_cache(kmalloc_caches[8]); - - p = kzalloc(512, GFP_KERNEL); - kfree(p); - p[512] = 0xab; - pr_err("\n3. kmalloc-512: Clobber redzone 0xab->0x%p\n\n", p); - validate_slab_cache(kmalloc_caches[9]); -} -#else -#ifdef CONFIG_SYSFS -static void resiliency_test(void) {}; -#endif -#endif - -#ifdef CONFIG_SYSFS -enum slab_stat_type { - SL_ALL, /* All slabs */ - SL_PARTIAL, /* Only partially allocated slabs */ - SL_CPU, /* Only slabs used for cpu caches */ - SL_OBJECTS, /* Determine allocated objects not slabs */ - SL_TOTAL /* Determine object capacity not slabs */ -}; - -#define SO_ALL (1 << SL_ALL) -#define SO_PARTIAL (1 << SL_PARTIAL) -#define SO_CPU (1 << SL_CPU) -#define SO_OBJECTS (1 << SL_OBJECTS) -#define SO_TOTAL (1 << SL_TOTAL) - -static ssize_t show_slab_objects(struct kmem_cache *s, - char *buf, unsigned long flags) -{ - unsigned long total = 0; - int node; - int x; - unsigned long *nodes; - - nodes = kzalloc(sizeof(unsigned long) * nr_node_ids, GFP_KERNEL); - if (!nodes) - return -ENOMEM; - - if (flags & SO_CPU) { - int cpu; - - for_each_possible_cpu(cpu) { - struct kmem_cache_cpu *c = per_cpu_ptr(s->cpu_slab, - cpu); - int node; - struct page *page; - - page = READ_ONCE(c->page); - if (!page) - continue; - - node = page_to_nid(page); - if (flags & SO_TOTAL) - x = page->objects; - else if (flags & SO_OBJECTS) - x = page->inuse; - else - x = 1; - - total += x; - nodes[node] += x; - - page = READ_ONCE(c->partial); - if (page) { - node = page_to_nid(page); - if (flags & SO_TOTAL) - WARN_ON_ONCE(1); - else if (flags & SO_OBJECTS) - WARN_ON_ONCE(1); - else - x = page->pages; - total += x; - nodes[node] += x; - } - } - } - - get_online_mems(); -#ifdef CONFIG_SLUB_DEBUG - if (flags & SO_ALL) { - struct kmem_cache_node *n; - - for_each_kmem_cache_node(s, node, n) { - - if (flags & SO_TOTAL) - x = atomic_long_read(&n->total_objects); - else if (flags & SO_OBJECTS) - x = atomic_long_read(&n->total_objects) - - count_partial(n, count_free); - else - x = atomic_long_read(&n->nr_slabs); - total += x; - nodes[node] += x; - } - - } else -#endif - if (flags & SO_PARTIAL) { - struct kmem_cache_node *n; - - for_each_kmem_cache_node(s, node, n) { - if (flags & SO_TOTAL) - x = count_partial(n, count_total); - else if (flags & SO_OBJECTS) - x = count_partial(n, count_inuse); - else - x = n->nr_partial; - total += x; - nodes[node] += x; - } - } - x = sprintf(buf, "%lu", total); -#ifdef CONFIG_NUMA - for (node = 0; node < nr_node_ids; node++) - if (nodes[node]) - x += sprintf(buf + x, " N%d=%lu", - node, nodes[node]); -#endif - put_online_mems(); - kfree(nodes); - return x + sprintf(buf + x, "\n"); -} - -#ifdef CONFIG_SLUB_DEBUG -static int any_slab_objects(struct kmem_cache *s) -{ - int node; - struct kmem_cache_node *n; - - for_each_kmem_cache_node(s, node, n) - if (atomic_long_read(&n->total_objects)) - return 1; - - return 0; -} -#endif - -#define to_slab_attr(n) container_of(n, struct slab_attribute, attr) -#define to_slab(n) container_of(n, struct kmem_cache, kobj) - -struct slab_attribute { - struct attribute attr; - ssize_t (*show)(struct kmem_cache *s, char *buf); - ssize_t (*store)(struct kmem_cache *s, const char *x, size_t count); -}; - -#define SLAB_ATTR_RO(_name) \ - static struct slab_attribute _name##_attr = \ - __ATTR(_name, 0400, _name##_show, NULL) - -#define SLAB_ATTR(_name) \ - static struct slab_attribute _name##_attr = \ - __ATTR(_name, 0600, _name##_show, _name##_store) - -static ssize_t slab_size_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%d\n", s->size); -} -SLAB_ATTR_RO(slab_size); - -static ssize_t align_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%d\n", s->align); -} -SLAB_ATTR_RO(align); - -static ssize_t object_size_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%d\n", s->object_size); -} -SLAB_ATTR_RO(object_size); - -static ssize_t objs_per_slab_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%d\n", oo_objects(s->oo)); -} -SLAB_ATTR_RO(objs_per_slab); - -static ssize_t order_store(struct kmem_cache *s, - const char *buf, size_t length) -{ - unsigned long order; - int err; - - err = kstrtoul(buf, 10, &order); - if (err) - return err; - - if (order > slub_max_order || order < slub_min_order) - return -EINVAL; - - calculate_sizes(s, order); - return length; -} - -static ssize_t order_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%d\n", oo_order(s->oo)); -} -SLAB_ATTR(order); - -static ssize_t min_partial_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%lu\n", s->min_partial); -} - -static ssize_t min_partial_store(struct kmem_cache *s, const char *buf, - size_t length) -{ - unsigned long min; - int err; - - err = kstrtoul(buf, 10, &min); - if (err) - return err; - - set_min_partial(s, min); - return length; -} -SLAB_ATTR(min_partial); - -static ssize_t cpu_partial_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%u\n", s->cpu_partial); -} - -static ssize_t cpu_partial_store(struct kmem_cache *s, const char *buf, - size_t length) -{ - unsigned long objects; - int err; - - err = kstrtoul(buf, 10, &objects); - if (err) - return err; - if (objects && !kmem_cache_has_cpu_partial(s)) - return -EINVAL; - - s->cpu_partial = objects; - flush_all(s); - return length; -} -SLAB_ATTR(cpu_partial); - -static ssize_t ctor_show(struct kmem_cache *s, char *buf) -{ - if (!s->ctor) - return 0; - return sprintf(buf, "%pS\n", s->ctor); -} -SLAB_ATTR_RO(ctor); - -static ssize_t aliases_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%d\n", s->refcount < 0 ? 0 : s->refcount - 1); -} -SLAB_ATTR_RO(aliases); - -static ssize_t partial_show(struct kmem_cache *s, char *buf) -{ - return show_slab_objects(s, buf, SO_PARTIAL); -} -SLAB_ATTR_RO(partial); - -static ssize_t cpu_slabs_show(struct kmem_cache *s, char *buf) -{ - return show_slab_objects(s, buf, SO_CPU); -} -SLAB_ATTR_RO(cpu_slabs); - -static ssize_t objects_show(struct kmem_cache *s, char *buf) -{ - return show_slab_objects(s, buf, SO_ALL|SO_OBJECTS); -} -SLAB_ATTR_RO(objects); - -static ssize_t objects_partial_show(struct kmem_cache *s, char *buf) -{ - return show_slab_objects(s, buf, SO_PARTIAL|SO_OBJECTS); -} -SLAB_ATTR_RO(objects_partial); - -static ssize_t slabs_cpu_partial_show(struct kmem_cache *s, char *buf) -{ - int objects = 0; - int pages = 0; - int cpu; - int len; - - for_each_online_cpu(cpu) { - struct page *page = per_cpu_ptr(s->cpu_slab, cpu)->partial; - - if (page) { - pages += page->pages; - objects += page->pobjects; - } - } - - len = sprintf(buf, "%d(%d)", objects, pages); - -#ifdef CONFIG_SMP - for_each_online_cpu(cpu) { - struct page *page = per_cpu_ptr(s->cpu_slab, cpu) ->partial; - - if (page && len < PAGE_SIZE - 20) - len += sprintf(buf + len, " C%d=%d(%d)", cpu, - page->pobjects, page->pages); - } -#endif - return len + sprintf(buf + len, "\n"); -} -SLAB_ATTR_RO(slabs_cpu_partial); - -static ssize_t reclaim_account_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%d\n", !!(s->flags & SLAB_RECLAIM_ACCOUNT)); -} - -static ssize_t reclaim_account_store(struct kmem_cache *s, - const char *buf, size_t length) -{ - s->flags &= ~SLAB_RECLAIM_ACCOUNT; - if (buf[0] == '1') - s->flags |= SLAB_RECLAIM_ACCOUNT; - return length; -} -SLAB_ATTR(reclaim_account); - -static ssize_t hwcache_align_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%d\n", !!(s->flags & SLAB_HWCACHE_ALIGN)); -} -SLAB_ATTR_RO(hwcache_align); - -#ifdef CONFIG_ZONE_DMA -static ssize_t cache_dma_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%d\n", !!(s->flags & SLAB_CACHE_DMA)); -} -SLAB_ATTR_RO(cache_dma); -#endif - -static ssize_t destroy_by_rcu_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%d\n", !!(s->flags & SLAB_DESTROY_BY_RCU)); -} -SLAB_ATTR_RO(destroy_by_rcu); - -static ssize_t reserved_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%d\n", s->reserved); -} -SLAB_ATTR_RO(reserved); - -#ifdef CONFIG_SLUB_DEBUG -static ssize_t slabs_show(struct kmem_cache *s, char *buf) -{ - return show_slab_objects(s, buf, SO_ALL); -} -SLAB_ATTR_RO(slabs); - -static ssize_t total_objects_show(struct kmem_cache *s, char *buf) -{ - return show_slab_objects(s, buf, SO_ALL|SO_TOTAL); -} -SLAB_ATTR_RO(total_objects); - -static ssize_t sanity_checks_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%d\n", !!(s->flags & SLAB_CONSISTENCY_CHECKS)); -} - -static ssize_t sanity_checks_store(struct kmem_cache *s, - const char *buf, size_t length) -{ - s->flags &= ~SLAB_CONSISTENCY_CHECKS; - if (buf[0] == '1') { - s->flags &= ~__CMPXCHG_DOUBLE; - s->flags |= SLAB_CONSISTENCY_CHECKS; - } - return length; -} -SLAB_ATTR(sanity_checks); - -static ssize_t trace_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%d\n", !!(s->flags & SLAB_TRACE)); -} - -static ssize_t trace_store(struct kmem_cache *s, const char *buf, - size_t length) -{ - /* - * Tracing a merged cache is going to give confusing results - * as well as cause other issues like converting a mergeable - * cache into an umergeable one. - */ - if (s->refcount > 1) - return -EINVAL; - - s->flags &= ~SLAB_TRACE; - if (buf[0] == '1') { - s->flags &= ~__CMPXCHG_DOUBLE; - s->flags |= SLAB_TRACE; - } - return length; -} -SLAB_ATTR(trace); - -static ssize_t red_zone_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%d\n", !!(s->flags & SLAB_RED_ZONE)); -} - -static ssize_t red_zone_store(struct kmem_cache *s, - const char *buf, size_t length) -{ - if (any_slab_objects(s)) - return -EBUSY; - - s->flags &= ~SLAB_RED_ZONE; - if (buf[0] == '1') { - s->flags |= SLAB_RED_ZONE; - } - calculate_sizes(s, -1); - return length; -} -SLAB_ATTR(red_zone); - -static ssize_t poison_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%d\n", !!(s->flags & SLAB_POISON)); -} - -static ssize_t poison_store(struct kmem_cache *s, - const char *buf, size_t length) -{ - if (any_slab_objects(s)) - return -EBUSY; - - s->flags &= ~SLAB_POISON; - if (buf[0] == '1') { - s->flags |= SLAB_POISON; - } - calculate_sizes(s, -1); - return length; -} -SLAB_ATTR(poison); - -static ssize_t store_user_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%d\n", !!(s->flags & SLAB_STORE_USER)); -} - -static ssize_t store_user_store(struct kmem_cache *s, - const char *buf, size_t length) -{ - if (any_slab_objects(s)) - return -EBUSY; - - s->flags &= ~SLAB_STORE_USER; - if (buf[0] == '1') { - s->flags &= ~__CMPXCHG_DOUBLE; - s->flags |= SLAB_STORE_USER; - } - calculate_sizes(s, -1); - return length; -} -SLAB_ATTR(store_user); - -static ssize_t validate_show(struct kmem_cache *s, char *buf) -{ - return 0; -} - -static ssize_t validate_store(struct kmem_cache *s, - const char *buf, size_t length) -{ - int ret = -EINVAL; - - if (buf[0] == '1') { - ret = validate_slab_cache(s); - if (ret >= 0) - ret = length; - } - return ret; -} -SLAB_ATTR(validate); - -static ssize_t alloc_calls_show(struct kmem_cache *s, char *buf) -{ - if (!(s->flags & SLAB_STORE_USER)) - return -ENOSYS; - return list_locations(s, buf, TRACK_ALLOC); -} -SLAB_ATTR_RO(alloc_calls); - -static ssize_t free_calls_show(struct kmem_cache *s, char *buf) -{ - if (!(s->flags & SLAB_STORE_USER)) - return -ENOSYS; - return list_locations(s, buf, TRACK_FREE); -} -SLAB_ATTR_RO(free_calls); -#endif /* CONFIG_SLUB_DEBUG */ - -#ifdef CONFIG_FAILSLAB -static ssize_t failslab_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%d\n", !!(s->flags & SLAB_FAILSLAB)); -} - -static ssize_t failslab_store(struct kmem_cache *s, const char *buf, - size_t length) -{ - if (s->refcount > 1) - return -EINVAL; - - s->flags &= ~SLAB_FAILSLAB; - if (buf[0] == '1') - s->flags |= SLAB_FAILSLAB; - return length; -} -SLAB_ATTR(failslab); -#endif - -static ssize_t shrink_show(struct kmem_cache *s, char *buf) -{ - return 0; -} - -static ssize_t shrink_store(struct kmem_cache *s, - const char *buf, size_t length) -{ - if (buf[0] == '1') - kmem_cache_shrink(s); - else - return -EINVAL; - return length; -} -SLAB_ATTR(shrink); - -#ifdef CONFIG_NUMA -static ssize_t remote_node_defrag_ratio_show(struct kmem_cache *s, char *buf) -{ - return sprintf(buf, "%d\n", s->remote_node_defrag_ratio / 10); -} - -static ssize_t remote_node_defrag_ratio_store(struct kmem_cache *s, - const char *buf, size_t length) -{ - unsigned long ratio; - int err; - - err = kstrtoul(buf, 10, &ratio); - if (err) - return err; - - if (ratio <= 100) - s->remote_node_defrag_ratio = ratio * 10; - - return length; -} -SLAB_ATTR(remote_node_defrag_ratio); -#endif - -#ifdef CONFIG_SLUB_STATS -static int show_stat(struct kmem_cache *s, char *buf, enum stat_item si) -{ - unsigned long sum = 0; - int cpu; - int len; - int *data = kmalloc(nr_cpu_ids * sizeof(int), GFP_KERNEL); - - if (!data) - return -ENOMEM; - - for_each_online_cpu(cpu) { - unsigned x = per_cpu_ptr(s->cpu_slab, cpu)->stat[si]; - - data[cpu] = x; - sum += x; - } - - len = sprintf(buf, "%lu", sum); - -#ifdef CONFIG_SMP - for_each_online_cpu(cpu) { - if (data[cpu] && len < PAGE_SIZE - 20) - len += sprintf(buf + len, " C%d=%u", cpu, data[cpu]); - } -#endif - kfree(data); - return len + sprintf(buf + len, "\n"); -} - -static void clear_stat(struct kmem_cache *s, enum stat_item si) -{ - int cpu; - - for_each_online_cpu(cpu) - per_cpu_ptr(s->cpu_slab, cpu)->stat[si] = 0; -} - -#define STAT_ATTR(si, text) \ -static ssize_t text##_show(struct kmem_cache *s, char *buf) \ -{ \ - return show_stat(s, buf, si); \ -} \ -static ssize_t text##_store(struct kmem_cache *s, \ - const char *buf, size_t length) \ -{ \ - if (buf[0] != '0') \ - return -EINVAL; \ - clear_stat(s, si); \ - return length; \ -} \ -SLAB_ATTR(text); \ - -STAT_ATTR(ALLOC_FASTPATH, alloc_fastpath); -STAT_ATTR(ALLOC_SLOWPATH, alloc_slowpath); -STAT_ATTR(FREE_FASTPATH, free_fastpath); -STAT_ATTR(FREE_SLOWPATH, free_slowpath); -STAT_ATTR(FREE_FROZEN, free_frozen); -STAT_ATTR(FREE_ADD_PARTIAL, free_add_partial); -STAT_ATTR(FREE_REMOVE_PARTIAL, free_remove_partial); -STAT_ATTR(ALLOC_FROM_PARTIAL, alloc_from_partial); -STAT_ATTR(ALLOC_SLAB, alloc_slab); -STAT_ATTR(ALLOC_REFILL, alloc_refill); -STAT_ATTR(ALLOC_NODE_MISMATCH, alloc_node_mismatch); -STAT_ATTR(FREE_SLAB, free_slab); -STAT_ATTR(CPUSLAB_FLUSH, cpuslab_flush); -STAT_ATTR(DEACTIVATE_FULL, deactivate_full); -STAT_ATTR(DEACTIVATE_EMPTY, deactivate_empty); -STAT_ATTR(DEACTIVATE_TO_HEAD, deactivate_to_head); -STAT_ATTR(DEACTIVATE_TO_TAIL, deactivate_to_tail); -STAT_ATTR(DEACTIVATE_REMOTE_FREES, deactivate_remote_frees); -STAT_ATTR(DEACTIVATE_BYPASS, deactivate_bypass); -STAT_ATTR(ORDER_FALLBACK, order_fallback); -STAT_ATTR(CMPXCHG_DOUBLE_CPU_FAIL, cmpxchg_double_cpu_fail); -STAT_ATTR(CMPXCHG_DOUBLE_FAIL, cmpxchg_double_fail); -STAT_ATTR(CPU_PARTIAL_ALLOC, cpu_partial_alloc); -STAT_ATTR(CPU_PARTIAL_FREE, cpu_partial_free); -STAT_ATTR(CPU_PARTIAL_NODE, cpu_partial_node); -STAT_ATTR(CPU_PARTIAL_DRAIN, cpu_partial_drain); -#endif - -static struct attribute *slab_attrs[] = { - &slab_size_attr.attr, - &object_size_attr.attr, - &objs_per_slab_attr.attr, - &order_attr.attr, - &min_partial_attr.attr, - &cpu_partial_attr.attr, - &objects_attr.attr, - &objects_partial_attr.attr, - &partial_attr.attr, - &cpu_slabs_attr.attr, - &ctor_attr.attr, - &aliases_attr.attr, - &align_attr.attr, - &hwcache_align_attr.attr, - &reclaim_account_attr.attr, - &destroy_by_rcu_attr.attr, - &shrink_attr.attr, - &reserved_attr.attr, - &slabs_cpu_partial_attr.attr, -#ifdef CONFIG_SLUB_DEBUG - &total_objects_attr.attr, - &slabs_attr.attr, - &sanity_checks_attr.attr, - &trace_attr.attr, - &red_zone_attr.attr, - &poison_attr.attr, - &store_user_attr.attr, - &validate_attr.attr, - &alloc_calls_attr.attr, - &free_calls_attr.attr, -#endif -#ifdef CONFIG_ZONE_DMA - &cache_dma_attr.attr, -#endif -#ifdef CONFIG_NUMA - &remote_node_defrag_ratio_attr.attr, -#endif -#ifdef CONFIG_SLUB_STATS - &alloc_fastpath_attr.attr, - &alloc_slowpath_attr.attr, - &free_fastpath_attr.attr, - &free_slowpath_attr.attr, - &free_frozen_attr.attr, - &free_add_partial_attr.attr, - &free_remove_partial_attr.attr, - &alloc_from_partial_attr.attr, - &alloc_slab_attr.attr, - &alloc_refill_attr.attr, - &alloc_node_mismatch_attr.attr, - &free_slab_attr.attr, - &cpuslab_flush_attr.attr, - &deactivate_full_attr.attr, - &deactivate_empty_attr.attr, - &deactivate_to_head_attr.attr, - &deactivate_to_tail_attr.attr, - &deactivate_remote_frees_attr.attr, - &deactivate_bypass_attr.attr, - &order_fallback_attr.attr, - &cmpxchg_double_fail_attr.attr, - &cmpxchg_double_cpu_fail_attr.attr, - &cpu_partial_alloc_attr.attr, - &cpu_partial_free_attr.attr, - &cpu_partial_node_attr.attr, - &cpu_partial_drain_attr.attr, -#endif -#ifdef CONFIG_FAILSLAB - &failslab_attr.attr, -#endif - - NULL -}; - -static struct attribute_group slab_attr_group = { - .attrs = slab_attrs, -}; - -static ssize_t slab_attr_show(struct kobject *kobj, - struct attribute *attr, - char *buf) -{ - struct slab_attribute *attribute; - struct kmem_cache *s; - int err; - - attribute = to_slab_attr(attr); - s = to_slab(kobj); - - if (!attribute->show) - return -EIO; - - err = attribute->show(s, buf); - - return err; -} - -static ssize_t slab_attr_store(struct kobject *kobj, - struct attribute *attr, - const char *buf, size_t len) -{ - struct slab_attribute *attribute; - struct kmem_cache *s; - int err; - - attribute = to_slab_attr(attr); - s = to_slab(kobj); - - if (!attribute->store) - return -EIO; - - err = attribute->store(s, buf, len); -#ifdef CONFIG_MEMCG - if (slab_state >= FULL && err >= 0 && is_root_cache(s)) { - struct kmem_cache *c; - - mutex_lock(&slab_mutex); - if (s->max_attr_size < len) - s->max_attr_size = len; - - /* - * This is a best effort propagation, so this function's return - * value will be determined by the parent cache only. This is - * basically because not all attributes will have a well - * defined semantics for rollbacks - most of the actions will - * have permanent effects. - * - * Returning the error value of any of the children that fail - * is not 100 % defined, in the sense that users seeing the - * error code won't be able to know anything about the state of - * the cache. - * - * Only returning the error code for the parent cache at least - * has well defined semantics. The cache being written to - * directly either failed or succeeded, in which case we loop - * through the descendants with best-effort propagation. - */ - for_each_memcg_cache(c, s) - attribute->store(c, buf, len); - mutex_unlock(&slab_mutex); - } -#endif - return err; -} - -static void memcg_propagate_slab_attrs(struct kmem_cache *s) -{ -#ifdef CONFIG_MEMCG - int i; - char *buffer = NULL; - struct kmem_cache *root_cache; - - if (is_root_cache(s)) - return; - - root_cache = s->memcg_params.root_cache; - - /* - * This mean this cache had no attribute written. Therefore, no point - * in copying default values around - */ - if (!root_cache->max_attr_size) - return; - - for (i = 0; i < ARRAY_SIZE(slab_attrs); i++) { - char mbuf[64]; - char *buf; - struct slab_attribute *attr = to_slab_attr(slab_attrs[i]); - - if (!attr || !attr->store || !attr->show) - continue; - - /* - * It is really bad that we have to allocate here, so we will - * do it only as a fallback. If we actually allocate, though, - * we can just use the allocated buffer until the end. - * - * Most of the slub attributes will tend to be very small in - * size, but sysfs allows buffers up to a page, so they can - * theoretically happen. - */ - if (buffer) - buf = buffer; - else if (root_cache->max_attr_size < ARRAY_SIZE(mbuf)) - buf = mbuf; - else { - buffer = (char *) get_zeroed_page(GFP_KERNEL); - if (WARN_ON(!buffer)) - continue; - buf = buffer; - } - - attr->show(root_cache, buf); - attr->store(s, buf, strlen(buf)); - } - - if (buffer) - free_page((unsigned long)buffer); -#endif -} - -static void kmem_cache_release(struct kobject *k) -{ - slab_kmem_cache_release(to_slab(k)); -} - -static const struct sysfs_ops slab_sysfs_ops = { - .show = slab_attr_show, - .store = slab_attr_store, -}; - -static struct kobj_type slab_ktype = { - .sysfs_ops = &slab_sysfs_ops, - .release = kmem_cache_release, -}; - -static int uevent_filter(struct kset *kset, struct kobject *kobj) -{ - struct kobj_type *ktype = get_ktype(kobj); - - if (ktype == &slab_ktype) - return 1; - return 0; -} - -static const struct kset_uevent_ops slab_uevent_ops = { - .filter = uevent_filter, -}; - -static struct kset *slab_kset; - -static inline struct kset *cache_kset(struct kmem_cache *s) -{ -#ifdef CONFIG_MEMCG - if (!is_root_cache(s)) - return s->memcg_params.root_cache->memcg_kset; -#endif - return slab_kset; -} - -#define ID_STR_LENGTH 64 - -/* Create a unique string id for a slab cache: - * - * Format :[flags-]size - */ -static char *create_unique_id(struct kmem_cache *s) -{ - char *name = kmalloc(ID_STR_LENGTH, GFP_KERNEL); - char *p = name; - - BUG_ON(!name); - - *p++ = ':'; - /* - * First flags affecting slabcache operations. We will only - * get here for aliasable slabs so we do not need to support - * too many flags. The flags here must cover all flags that - * are matched during merging to guarantee that the id is - * unique. - */ - if (s->flags & SLAB_CACHE_DMA) - *p++ = 'd'; - if (s->flags & SLAB_RECLAIM_ACCOUNT) - *p++ = 'a'; - if (s->flags & SLAB_CONSISTENCY_CHECKS) - *p++ = 'F'; - if (!(s->flags & SLAB_NOTRACK)) - *p++ = 't'; - if (s->flags & SLAB_ACCOUNT) - *p++ = 'A'; - if (p != name + 1) - *p++ = '-'; - p += sprintf(p, "%07d", s->size); - - BUG_ON(p > name + ID_STR_LENGTH - 1); - return name; -} - -static int sysfs_slab_add(struct kmem_cache *s) -{ - int err; - const char *name; - int unmergeable = slab_unmergeable(s); - - if (unmergeable) { - /* - * Slabcache can never be merged so we can use the name proper. - * This is typically the case for debug situations. In that - * case we can catch duplicate names easily. - */ - sysfs_remove_link(&slab_kset->kobj, s->name); - name = s->name; - } else { - /* - * Create a unique name for the slab as a target - * for the symlinks. - */ - name = create_unique_id(s); - } - - s->kobj.kset = cache_kset(s); - err = kobject_init_and_add(&s->kobj, &slab_ktype, NULL, "%s", name); - if (err) - goto out; - - err = sysfs_create_group(&s->kobj, &slab_attr_group); - if (err) - goto out_del_kobj; - -#ifdef CONFIG_MEMCG - if (is_root_cache(s)) { - s->memcg_kset = kset_create_and_add("cgroup", NULL, &s->kobj); - if (!s->memcg_kset) { - err = -ENOMEM; - goto out_del_kobj; - } - } -#endif - - kobject_uevent(&s->kobj, KOBJ_ADD); - if (!unmergeable) { - /* Setup first alias */ - sysfs_slab_alias(s, s->name); - } -out: - if (!unmergeable) - kfree(name); - return err; -out_del_kobj: - kobject_del(&s->kobj); - goto out; -} - -void sysfs_slab_remove(struct kmem_cache *s) -{ - if (slab_state < FULL) - /* - * Sysfs has not been setup yet so no need to remove the - * cache from sysfs. - */ - return; - -#ifdef CONFIG_MEMCG - kset_unregister(s->memcg_kset); -#endif - kobject_uevent(&s->kobj, KOBJ_REMOVE); - kobject_del(&s->kobj); - kobject_put(&s->kobj); -} - -/* - * Need to buffer aliases during bootup until sysfs becomes - * available lest we lose that information. - */ -struct saved_alias { - struct kmem_cache *s; - const char *name; - struct saved_alias *next; -}; - -static struct saved_alias *alias_list; - -static int sysfs_slab_alias(struct kmem_cache *s, const char *name) -{ - struct saved_alias *al; - - if (slab_state == FULL) { - /* - * If we have a leftover link then remove it. - */ - sysfs_remove_link(&slab_kset->kobj, name); - return sysfs_create_link(&slab_kset->kobj, &s->kobj, name); - } - - al = kmalloc(sizeof(struct saved_alias), GFP_KERNEL); - if (!al) - return -ENOMEM; - - al->s = s; - al->name = name; - al->next = alias_list; - alias_list = al; - return 0; -} - -static int __init slab_sysfs_init(void) -{ - struct kmem_cache *s; - int err; - - mutex_lock(&slab_mutex); - - slab_kset = kset_create_and_add("slab", &slab_uevent_ops, kernel_kobj); - if (!slab_kset) { - mutex_unlock(&slab_mutex); - pr_err("Cannot register slab subsystem.\n"); - return -ENOSYS; - } - - slab_state = FULL; - - list_for_each_entry(s, &slab_caches, list) { - err = sysfs_slab_add(s); - if (err) - pr_err("SLUB: Unable to add boot slab %s to sysfs\n", - s->name); - } - - while (alias_list) { - struct saved_alias *al = alias_list; - - alias_list = alias_list->next; - err = sysfs_slab_alias(al->s, al->name); - if (err) - pr_err("SLUB: Unable to add boot slab alias %s to sysfs\n", - al->name); - kfree(al); - } - - mutex_unlock(&slab_mutex); - resiliency_test(); - return 0; -} - -__initcall(slab_sysfs_init); -#endif /* CONFIG_SYSFS */ - -/* - * The /proc/slabinfo ABI - */ -#ifdef CONFIG_SLABINFO -void get_slabinfo(struct kmem_cache *s, struct slabinfo *sinfo) -{ - unsigned long nr_slabs = 0; - unsigned long nr_objs = 0; - unsigned long nr_free = 0; - int node; - struct kmem_cache_node *n; - - for_each_kmem_cache_node(s, node, n) { - nr_slabs += node_nr_slabs(n); - nr_objs += node_nr_objs(n); - nr_free += count_partial(n, count_free); - } - - sinfo->active_objs = nr_objs - nr_free; - sinfo->num_objs = nr_objs; - sinfo->active_slabs = nr_slabs; - sinfo->num_slabs = nr_slabs; - sinfo->objects_per_slab = oo_objects(s->oo); - sinfo->cache_order = oo_order(s->oo); -} - -void slabinfo_show_stats(struct seq_file *m, struct kmem_cache *s) -{ -} - -ssize_t slabinfo_write(struct file *file, const char __user *buffer, - size_t count, loff_t *ppos) -{ - return -EIO; -} -#endif /* CONFIG_SLABINFO */ diff --git a/src/linux/mm/swap.c b/src/linux/mm/swap.c deleted file mode 100644 index 4dcf852..0000000 --- a/src/linux/mm/swap.c +++ /dev/null @@ -1,988 +0,0 @@ -/* - * linux/mm/swap.c - * - * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds - */ - -/* - * This file contains the default values for the operation of the - * Linux VM subsystem. Fine-tuning documentation can be found in - * Documentation/sysctl/vm.txt. - * Started 18.12.91 - * Swap aging added 23.2.95, Stephen Tweedie. - * Buffermem limits added 12.3.98, Rik van Riel. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -#define CREATE_TRACE_POINTS -#include - -/* How many pages do we try to swap or page in/out together? */ -int page_cluster; - -static DEFINE_PER_CPU(struct pagevec, lru_add_pvec); -static DEFINE_PER_CPU(struct pagevec, lru_rotate_pvecs); -static DEFINE_PER_CPU(struct pagevec, lru_deactivate_file_pvecs); -static DEFINE_PER_CPU(struct pagevec, lru_deactivate_pvecs); -#ifdef CONFIG_SMP -static DEFINE_PER_CPU(struct pagevec, activate_page_pvecs); -#endif - -/* - * This path almost never happens for VM activity - pages are normally - * freed via pagevecs. But it gets used by networking. - */ -static void __page_cache_release(struct page *page) -{ - if (PageLRU(page)) { - struct zone *zone = page_zone(page); - struct lruvec *lruvec; - unsigned long flags; - - spin_lock_irqsave(zone_lru_lock(zone), flags); - lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat); - VM_BUG_ON_PAGE(!PageLRU(page), page); - __ClearPageLRU(page); - del_page_from_lru_list(page, lruvec, page_off_lru(page)); - spin_unlock_irqrestore(zone_lru_lock(zone), flags); - } - mem_cgroup_uncharge(page); -} - -static void __put_single_page(struct page *page) -{ - __page_cache_release(page); - free_hot_cold_page(page, false); -} - -static void __put_compound_page(struct page *page) -{ - compound_page_dtor *dtor; - - /* - * __page_cache_release() is supposed to be called for thp, not for - * hugetlb. This is because hugetlb page does never have PageLRU set - * (it's never listed to any LRU lists) and no memcg routines should - * be called for hugetlb (it has a separate hugetlb_cgroup.) - */ - if (!PageHuge(page)) - __page_cache_release(page); - dtor = get_compound_page_dtor(page); - (*dtor)(page); -} - -void __put_page(struct page *page) -{ - if (unlikely(PageCompound(page))) - __put_compound_page(page); - else - __put_single_page(page); -} -EXPORT_SYMBOL(__put_page); - -/** - * put_pages_list() - release a list of pages - * @pages: list of pages threaded on page->lru - * - * Release a list of pages which are strung together on page.lru. Currently - * used by read_cache_pages() and related error recovery code. - */ -void put_pages_list(struct list_head *pages) -{ - while (!list_empty(pages)) { - struct page *victim; - - victim = list_entry(pages->prev, struct page, lru); - list_del(&victim->lru); - put_page(victim); - } -} -EXPORT_SYMBOL(put_pages_list); - -/* - * get_kernel_pages() - pin kernel pages in memory - * @kiov: An array of struct kvec structures - * @nr_segs: number of segments to pin - * @write: pinning for read/write, currently ignored - * @pages: array that receives pointers to the pages pinned. - * Should be at least nr_segs long. - * - * Returns number of pages pinned. This may be fewer than the number - * requested. If nr_pages is 0 or negative, returns 0. If no pages - * were pinned, returns -errno. Each page returned must be released - * with a put_page() call when it is finished with. - */ -int get_kernel_pages(const struct kvec *kiov, int nr_segs, int write, - struct page **pages) -{ - int seg; - - for (seg = 0; seg < nr_segs; seg++) { - if (WARN_ON(kiov[seg].iov_len != PAGE_SIZE)) - return seg; - - pages[seg] = kmap_to_page(kiov[seg].iov_base); - get_page(pages[seg]); - } - - return seg; -} -EXPORT_SYMBOL_GPL(get_kernel_pages); - -/* - * get_kernel_page() - pin a kernel page in memory - * @start: starting kernel address - * @write: pinning for read/write, currently ignored - * @pages: array that receives pointer to the page pinned. - * Must be at least nr_segs long. - * - * Returns 1 if page is pinned. If the page was not pinned, returns - * -errno. The page returned must be released with a put_page() call - * when it is finished with. - */ -int get_kernel_page(unsigned long start, int write, struct page **pages) -{ - const struct kvec kiov = { - .iov_base = (void *)start, - .iov_len = PAGE_SIZE - }; - - return get_kernel_pages(&kiov, 1, write, pages); -} -EXPORT_SYMBOL_GPL(get_kernel_page); - -static void pagevec_lru_move_fn(struct pagevec *pvec, - void (*move_fn)(struct page *page, struct lruvec *lruvec, void *arg), - void *arg) -{ - int i; - struct pglist_data *pgdat = NULL; - struct lruvec *lruvec; - unsigned long flags = 0; - - for (i = 0; i < pagevec_count(pvec); i++) { - struct page *page = pvec->pages[i]; - struct pglist_data *pagepgdat = page_pgdat(page); - - if (pagepgdat != pgdat) { - if (pgdat) - spin_unlock_irqrestore(&pgdat->lru_lock, flags); - pgdat = pagepgdat; - spin_lock_irqsave(&pgdat->lru_lock, flags); - } - - lruvec = mem_cgroup_page_lruvec(page, pgdat); - (*move_fn)(page, lruvec, arg); - } - if (pgdat) - spin_unlock_irqrestore(&pgdat->lru_lock, flags); - release_pages(pvec->pages, pvec->nr, pvec->cold); - pagevec_reinit(pvec); -} - -static void pagevec_move_tail_fn(struct page *page, struct lruvec *lruvec, - void *arg) -{ - int *pgmoved = arg; - - if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { - enum lru_list lru = page_lru_base_type(page); - list_move_tail(&page->lru, &lruvec->lists[lru]); - (*pgmoved)++; - } -} - -/* - * pagevec_move_tail() must be called with IRQ disabled. - * Otherwise this may cause nasty races. - */ -static void pagevec_move_tail(struct pagevec *pvec) -{ - int pgmoved = 0; - - pagevec_lru_move_fn(pvec, pagevec_move_tail_fn, &pgmoved); - __count_vm_events(PGROTATED, pgmoved); -} - -/* - * Writeback is about to end against a page which has been marked for immediate - * reclaim. If it still appears to be reclaimable, move it to the tail of the - * inactive list. - */ -void rotate_reclaimable_page(struct page *page) -{ - if (!PageLocked(page) && !PageDirty(page) && !PageActive(page) && - !PageUnevictable(page) && PageLRU(page)) { - struct pagevec *pvec; - unsigned long flags; - - get_page(page); - local_irq_save(flags); - pvec = this_cpu_ptr(&lru_rotate_pvecs); - if (!pagevec_add(pvec, page) || PageCompound(page)) - pagevec_move_tail(pvec); - local_irq_restore(flags); - } -} - -static void update_page_reclaim_stat(struct lruvec *lruvec, - int file, int rotated) -{ - struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat; - - reclaim_stat->recent_scanned[file]++; - if (rotated) - reclaim_stat->recent_rotated[file]++; -} - -static void __activate_page(struct page *page, struct lruvec *lruvec, - void *arg) -{ - if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { - int file = page_is_file_cache(page); - int lru = page_lru_base_type(page); - - del_page_from_lru_list(page, lruvec, lru); - SetPageActive(page); - lru += LRU_ACTIVE; - add_page_to_lru_list(page, lruvec, lru); - trace_mm_lru_activate(page); - - __count_vm_event(PGACTIVATE); - update_page_reclaim_stat(lruvec, file, 1); - } -} - -#ifdef CONFIG_SMP -static void activate_page_drain(int cpu) -{ - struct pagevec *pvec = &per_cpu(activate_page_pvecs, cpu); - - if (pagevec_count(pvec)) - pagevec_lru_move_fn(pvec, __activate_page, NULL); -} - -static bool need_activate_page_drain(int cpu) -{ - return pagevec_count(&per_cpu(activate_page_pvecs, cpu)) != 0; -} - -void activate_page(struct page *page) -{ - page = compound_head(page); - if (PageLRU(page) && !PageActive(page) && !PageUnevictable(page)) { - struct pagevec *pvec = &get_cpu_var(activate_page_pvecs); - - get_page(page); - if (!pagevec_add(pvec, page) || PageCompound(page)) - pagevec_lru_move_fn(pvec, __activate_page, NULL); - put_cpu_var(activate_page_pvecs); - } -} - -#else -static inline void activate_page_drain(int cpu) -{ -} - -static bool need_activate_page_drain(int cpu) -{ - return false; -} - -void activate_page(struct page *page) -{ - struct zone *zone = page_zone(page); - - page = compound_head(page); - spin_lock_irq(zone_lru_lock(zone)); - __activate_page(page, mem_cgroup_page_lruvec(page, zone->zone_pgdat), NULL); - spin_unlock_irq(zone_lru_lock(zone)); -} -#endif - -static void __lru_cache_activate_page(struct page *page) -{ - struct pagevec *pvec = &get_cpu_var(lru_add_pvec); - int i; - - /* - * Search backwards on the optimistic assumption that the page being - * activated has just been added to this pagevec. Note that only - * the local pagevec is examined as a !PageLRU page could be in the - * process of being released, reclaimed, migrated or on a remote - * pagevec that is currently being drained. Furthermore, marking - * a remote pagevec's page PageActive potentially hits a race where - * a page is marked PageActive just after it is added to the inactive - * list causing accounting errors and BUG_ON checks to trigger. - */ - for (i = pagevec_count(pvec) - 1; i >= 0; i--) { - struct page *pagevec_page = pvec->pages[i]; - - if (pagevec_page == page) { - SetPageActive(page); - break; - } - } - - put_cpu_var(lru_add_pvec); -} - -/* - * Mark a page as having seen activity. - * - * inactive,unreferenced -> inactive,referenced - * inactive,referenced -> active,unreferenced - * active,unreferenced -> active,referenced - * - * When a newly allocated page is not yet visible, so safe for non-atomic ops, - * __SetPageReferenced(page) may be substituted for mark_page_accessed(page). - */ -void mark_page_accessed(struct page *page) -{ - page = compound_head(page); - if (!PageActive(page) && !PageUnevictable(page) && - PageReferenced(page)) { - - /* - * If the page is on the LRU, queue it for activation via - * activate_page_pvecs. Otherwise, assume the page is on a - * pagevec, mark it active and it'll be moved to the active - * LRU on the next drain. - */ - if (PageLRU(page)) - activate_page(page); - else - __lru_cache_activate_page(page); - ClearPageReferenced(page); - if (page_is_file_cache(page)) - workingset_activation(page); - } else if (!PageReferenced(page)) { - SetPageReferenced(page); - } - if (page_is_idle(page)) - clear_page_idle(page); -} -EXPORT_SYMBOL(mark_page_accessed); - -static void __lru_cache_add(struct page *page) -{ - struct pagevec *pvec = &get_cpu_var(lru_add_pvec); - - get_page(page); - if (!pagevec_add(pvec, page) || PageCompound(page)) - __pagevec_lru_add(pvec); - put_cpu_var(lru_add_pvec); -} - -/** - * lru_cache_add: add a page to the page lists - * @page: the page to add - */ -void lru_cache_add_anon(struct page *page) -{ - if (PageActive(page)) - ClearPageActive(page); - __lru_cache_add(page); -} - -void lru_cache_add_file(struct page *page) -{ - if (PageActive(page)) - ClearPageActive(page); - __lru_cache_add(page); -} -EXPORT_SYMBOL(lru_cache_add_file); - -/** - * lru_cache_add - add a page to a page list - * @page: the page to be added to the LRU. - * - * Queue the page for addition to the LRU via pagevec. The decision on whether - * to add the page to the [in]active [file|anon] list is deferred until the - * pagevec is drained. This gives a chance for the caller of lru_cache_add() - * have the page added to the active list using mark_page_accessed(). - */ -void lru_cache_add(struct page *page) -{ - VM_BUG_ON_PAGE(PageActive(page) && PageUnevictable(page), page); - VM_BUG_ON_PAGE(PageLRU(page), page); - __lru_cache_add(page); -} - -/** - * add_page_to_unevictable_list - add a page to the unevictable list - * @page: the page to be added to the unevictable list - * - * Add page directly to its zone's unevictable list. To avoid races with - * tasks that might be making the page evictable, through eg. munlock, - * munmap or exit, while it's not on the lru, we want to add the page - * while it's locked or otherwise "invisible" to other tasks. This is - * difficult to do when using the pagevec cache, so bypass that. - */ -void add_page_to_unevictable_list(struct page *page) -{ - struct pglist_data *pgdat = page_pgdat(page); - struct lruvec *lruvec; - - spin_lock_irq(&pgdat->lru_lock); - lruvec = mem_cgroup_page_lruvec(page, pgdat); - ClearPageActive(page); - SetPageUnevictable(page); - SetPageLRU(page); - add_page_to_lru_list(page, lruvec, LRU_UNEVICTABLE); - spin_unlock_irq(&pgdat->lru_lock); -} - -/** - * lru_cache_add_active_or_unevictable - * @page: the page to be added to LRU - * @vma: vma in which page is mapped for determining reclaimability - * - * Place @page on the active or unevictable LRU list, depending on its - * evictability. Note that if the page is not evictable, it goes - * directly back onto it's zone's unevictable list, it does NOT use a - * per cpu pagevec. - */ -void lru_cache_add_active_or_unevictable(struct page *page, - struct vm_area_struct *vma) -{ - VM_BUG_ON_PAGE(PageLRU(page), page); - - if (likely((vma->vm_flags & (VM_LOCKED | VM_SPECIAL)) != VM_LOCKED)) { - SetPageActive(page); - lru_cache_add(page); - return; - } - - if (!TestSetPageMlocked(page)) { - /* - * We use the irq-unsafe __mod_zone_page_stat because this - * counter is not modified from interrupt context, and the pte - * lock is held(spinlock), which implies preemption disabled. - */ - __mod_zone_page_state(page_zone(page), NR_MLOCK, - hpage_nr_pages(page)); - count_vm_event(UNEVICTABLE_PGMLOCKED); - } - add_page_to_unevictable_list(page); -} - -/* - * If the page can not be invalidated, it is moved to the - * inactive list to speed up its reclaim. It is moved to the - * head of the list, rather than the tail, to give the flusher - * threads some time to write it out, as this is much more - * effective than the single-page writeout from reclaim. - * - * If the page isn't page_mapped and dirty/writeback, the page - * could reclaim asap using PG_reclaim. - * - * 1. active, mapped page -> none - * 2. active, dirty/writeback page -> inactive, head, PG_reclaim - * 3. inactive, mapped page -> none - * 4. inactive, dirty/writeback page -> inactive, head, PG_reclaim - * 5. inactive, clean -> inactive, tail - * 6. Others -> none - * - * In 4, why it moves inactive's head, the VM expects the page would - * be write it out by flusher threads as this is much more effective - * than the single-page writeout from reclaim. - */ -static void lru_deactivate_file_fn(struct page *page, struct lruvec *lruvec, - void *arg) -{ - int lru, file; - bool active; - - if (!PageLRU(page)) - return; - - if (PageUnevictable(page)) - return; - - /* Some processes are using the page */ - if (page_mapped(page)) - return; - - active = PageActive(page); - file = page_is_file_cache(page); - lru = page_lru_base_type(page); - - del_page_from_lru_list(page, lruvec, lru + active); - ClearPageActive(page); - ClearPageReferenced(page); - add_page_to_lru_list(page, lruvec, lru); - - if (PageWriteback(page) || PageDirty(page)) { - /* - * PG_reclaim could be raced with end_page_writeback - * It can make readahead confusing. But race window - * is _really_ small and it's non-critical problem. - */ - SetPageReclaim(page); - } else { - /* - * The page's writeback ends up during pagevec - * We moves tha page into tail of inactive. - */ - list_move_tail(&page->lru, &lruvec->lists[lru]); - __count_vm_event(PGROTATED); - } - - if (active) - __count_vm_event(PGDEACTIVATE); - update_page_reclaim_stat(lruvec, file, 0); -} - - -static void lru_deactivate_fn(struct page *page, struct lruvec *lruvec, - void *arg) -{ - if (PageLRU(page) && PageActive(page) && !PageUnevictable(page)) { - int file = page_is_file_cache(page); - int lru = page_lru_base_type(page); - - del_page_from_lru_list(page, lruvec, lru + LRU_ACTIVE); - ClearPageActive(page); - ClearPageReferenced(page); - add_page_to_lru_list(page, lruvec, lru); - - __count_vm_event(PGDEACTIVATE); - update_page_reclaim_stat(lruvec, file, 0); - } -} - -/* - * Drain pages out of the cpu's pagevecs. - * Either "cpu" is the current CPU, and preemption has already been - * disabled; or "cpu" is being hot-unplugged, and is already dead. - */ -void lru_add_drain_cpu(int cpu) -{ - struct pagevec *pvec = &per_cpu(lru_add_pvec, cpu); - - if (pagevec_count(pvec)) - __pagevec_lru_add(pvec); - - pvec = &per_cpu(lru_rotate_pvecs, cpu); - if (pagevec_count(pvec)) { - unsigned long flags; - - /* No harm done if a racing interrupt already did this */ - local_irq_save(flags); - pagevec_move_tail(pvec); - local_irq_restore(flags); - } - - pvec = &per_cpu(lru_deactivate_file_pvecs, cpu); - if (pagevec_count(pvec)) - pagevec_lru_move_fn(pvec, lru_deactivate_file_fn, NULL); - - pvec = &per_cpu(lru_deactivate_pvecs, cpu); - if (pagevec_count(pvec)) - pagevec_lru_move_fn(pvec, lru_deactivate_fn, NULL); - - activate_page_drain(cpu); -} - -/** - * deactivate_file_page - forcefully deactivate a file page - * @page: page to deactivate - * - * This function hints the VM that @page is a good reclaim candidate, - * for example if its invalidation fails due to the page being dirty - * or under writeback. - */ -void deactivate_file_page(struct page *page) -{ - /* - * In a workload with many unevictable page such as mprotect, - * unevictable page deactivation for accelerating reclaim is pointless. - */ - if (PageUnevictable(page)) - return; - - if (likely(get_page_unless_zero(page))) { - struct pagevec *pvec = &get_cpu_var(lru_deactivate_file_pvecs); - - if (!pagevec_add(pvec, page) || PageCompound(page)) - pagevec_lru_move_fn(pvec, lru_deactivate_file_fn, NULL); - put_cpu_var(lru_deactivate_file_pvecs); - } -} - -/** - * deactivate_page - deactivate a page - * @page: page to deactivate - * - * deactivate_page() moves @page to the inactive list if @page was on the active - * list and was not an unevictable page. This is done to accelerate the reclaim - * of @page. - */ -void deactivate_page(struct page *page) -{ - if (PageLRU(page) && PageActive(page) && !PageUnevictable(page)) { - struct pagevec *pvec = &get_cpu_var(lru_deactivate_pvecs); - - get_page(page); - if (!pagevec_add(pvec, page) || PageCompound(page)) - pagevec_lru_move_fn(pvec, lru_deactivate_fn, NULL); - put_cpu_var(lru_deactivate_pvecs); - } -} - -void lru_add_drain(void) -{ - lru_add_drain_cpu(get_cpu()); - put_cpu(); -} - -static void lru_add_drain_per_cpu(struct work_struct *dummy) -{ - lru_add_drain(); -} - -static DEFINE_PER_CPU(struct work_struct, lru_add_drain_work); - -/* - * lru_add_drain_wq is used to do lru_add_drain_all() from a WQ_MEM_RECLAIM - * workqueue, aiding in getting memory freed. - */ -static struct workqueue_struct *lru_add_drain_wq; - -static int __init lru_init(void) -{ - lru_add_drain_wq = alloc_workqueue("lru-add-drain", WQ_MEM_RECLAIM, 0); - - if (WARN(!lru_add_drain_wq, - "Failed to create workqueue lru_add_drain_wq")) - return -ENOMEM; - - return 0; -} -early_initcall(lru_init); - -void lru_add_drain_all(void) -{ - static DEFINE_MUTEX(lock); - static struct cpumask has_work; - int cpu; - - mutex_lock(&lock); - get_online_cpus(); - cpumask_clear(&has_work); - - for_each_online_cpu(cpu) { - struct work_struct *work = &per_cpu(lru_add_drain_work, cpu); - - if (pagevec_count(&per_cpu(lru_add_pvec, cpu)) || - pagevec_count(&per_cpu(lru_rotate_pvecs, cpu)) || - pagevec_count(&per_cpu(lru_deactivate_file_pvecs, cpu)) || - pagevec_count(&per_cpu(lru_deactivate_pvecs, cpu)) || - need_activate_page_drain(cpu)) { - INIT_WORK(work, lru_add_drain_per_cpu); - queue_work_on(cpu, lru_add_drain_wq, work); - cpumask_set_cpu(cpu, &has_work); - } - } - - for_each_cpu(cpu, &has_work) - flush_work(&per_cpu(lru_add_drain_work, cpu)); - - put_online_cpus(); - mutex_unlock(&lock); -} - -/** - * release_pages - batched put_page() - * @pages: array of pages to release - * @nr: number of pages - * @cold: whether the pages are cache cold - * - * Decrement the reference count on all the pages in @pages. If it - * fell to zero, remove the page from the LRU and free it. - */ -void release_pages(struct page **pages, int nr, bool cold) -{ - int i; - LIST_HEAD(pages_to_free); - struct pglist_data *locked_pgdat = NULL; - struct lruvec *lruvec; - unsigned long uninitialized_var(flags); - unsigned int uninitialized_var(lock_batch); - - for (i = 0; i < nr; i++) { - struct page *page = pages[i]; - - /* - * Make sure the IRQ-safe lock-holding time does not get - * excessive with a continuous string of pages from the - * same pgdat. The lock is held only if pgdat != NULL. - */ - if (locked_pgdat && ++lock_batch == SWAP_CLUSTER_MAX) { - spin_unlock_irqrestore(&locked_pgdat->lru_lock, flags); - locked_pgdat = NULL; - } - - if (is_huge_zero_page(page)) - continue; - - page = compound_head(page); - if (!put_page_testzero(page)) - continue; - - if (PageCompound(page)) { - if (locked_pgdat) { - spin_unlock_irqrestore(&locked_pgdat->lru_lock, flags); - locked_pgdat = NULL; - } - __put_compound_page(page); - continue; - } - - if (PageLRU(page)) { - struct pglist_data *pgdat = page_pgdat(page); - - if (pgdat != locked_pgdat) { - if (locked_pgdat) - spin_unlock_irqrestore(&locked_pgdat->lru_lock, - flags); - lock_batch = 0; - locked_pgdat = pgdat; - spin_lock_irqsave(&locked_pgdat->lru_lock, flags); - } - - lruvec = mem_cgroup_page_lruvec(page, locked_pgdat); - VM_BUG_ON_PAGE(!PageLRU(page), page); - __ClearPageLRU(page); - del_page_from_lru_list(page, lruvec, page_off_lru(page)); - } - - /* Clear Active bit in case of parallel mark_page_accessed */ - __ClearPageActive(page); - - list_add(&page->lru, &pages_to_free); - } - if (locked_pgdat) - spin_unlock_irqrestore(&locked_pgdat->lru_lock, flags); - - mem_cgroup_uncharge_list(&pages_to_free); - free_hot_cold_page_list(&pages_to_free, cold); -} -EXPORT_SYMBOL(release_pages); - -/* - * The pages which we're about to release may be in the deferred lru-addition - * queues. That would prevent them from really being freed right now. That's - * OK from a correctness point of view but is inefficient - those pages may be - * cache-warm and we want to give them back to the page allocator ASAP. - * - * So __pagevec_release() will drain those queues here. __pagevec_lru_add() - * and __pagevec_lru_add_active() call release_pages() directly to avoid - * mutual recursion. - */ -void __pagevec_release(struct pagevec *pvec) -{ - lru_add_drain(); - release_pages(pvec->pages, pagevec_count(pvec), pvec->cold); - pagevec_reinit(pvec); -} -EXPORT_SYMBOL(__pagevec_release); - -#ifdef CONFIG_TRANSPARENT_HUGEPAGE -/* used by __split_huge_page_refcount() */ -void lru_add_page_tail(struct page *page, struct page *page_tail, - struct lruvec *lruvec, struct list_head *list) -{ - const int file = 0; - - VM_BUG_ON_PAGE(!PageHead(page), page); - VM_BUG_ON_PAGE(PageCompound(page_tail), page); - VM_BUG_ON_PAGE(PageLRU(page_tail), page); - VM_BUG_ON(NR_CPUS != 1 && - !spin_is_locked(&lruvec_pgdat(lruvec)->lru_lock)); - - if (!list) - SetPageLRU(page_tail); - - if (likely(PageLRU(page))) - list_add_tail(&page_tail->lru, &page->lru); - else if (list) { - /* page reclaim is reclaiming a huge page */ - get_page(page_tail); - list_add_tail(&page_tail->lru, list); - } else { - struct list_head *list_head; - /* - * Head page has not yet been counted, as an hpage, - * so we must account for each subpage individually. - * - * Use the standard add function to put page_tail on the list, - * but then correct its position so they all end up in order. - */ - add_page_to_lru_list(page_tail, lruvec, page_lru(page_tail)); - list_head = page_tail->lru.prev; - list_move_tail(&page_tail->lru, list_head); - } - - if (!PageUnevictable(page)) - update_page_reclaim_stat(lruvec, file, PageActive(page_tail)); -} -#endif /* CONFIG_TRANSPARENT_HUGEPAGE */ - -static void __pagevec_lru_add_fn(struct page *page, struct lruvec *lruvec, - void *arg) -{ - int file = page_is_file_cache(page); - int active = PageActive(page); - enum lru_list lru = page_lru(page); - - VM_BUG_ON_PAGE(PageLRU(page), page); - - SetPageLRU(page); - add_page_to_lru_list(page, lruvec, lru); - update_page_reclaim_stat(lruvec, file, active); - trace_mm_lru_insertion(page, lru); -} - -/* - * Add the passed pages to the LRU, then drop the caller's refcount - * on them. Reinitialises the caller's pagevec. - */ -void __pagevec_lru_add(struct pagevec *pvec) -{ - pagevec_lru_move_fn(pvec, __pagevec_lru_add_fn, NULL); -} -EXPORT_SYMBOL(__pagevec_lru_add); - -/** - * pagevec_lookup_entries - gang pagecache lookup - * @pvec: Where the resulting entries are placed - * @mapping: The address_space to search - * @start: The starting entry index - * @nr_entries: The maximum number of entries - * @indices: The cache indices corresponding to the entries in @pvec - * - * pagevec_lookup_entries() will search for and return a group of up - * to @nr_entries pages and shadow entries in the mapping. All - * entries are placed in @pvec. pagevec_lookup_entries() takes a - * reference against actual pages in @pvec. - * - * The search returns a group of mapping-contiguous entries with - * ascending indexes. There may be holes in the indices due to - * not-present entries. - * - * pagevec_lookup_entries() returns the number of entries which were - * found. - */ -unsigned pagevec_lookup_entries(struct pagevec *pvec, - struct address_space *mapping, - pgoff_t start, unsigned nr_pages, - pgoff_t *indices) -{ - pvec->nr = find_get_entries(mapping, start, nr_pages, - pvec->pages, indices); - return pagevec_count(pvec); -} - -/** - * pagevec_remove_exceptionals - pagevec exceptionals pruning - * @pvec: The pagevec to prune - * - * pagevec_lookup_entries() fills both pages and exceptional radix - * tree entries into the pagevec. This function prunes all - * exceptionals from @pvec without leaving holes, so that it can be - * passed on to page-only pagevec operations. - */ -void pagevec_remove_exceptionals(struct pagevec *pvec) -{ - int i, j; - - for (i = 0, j = 0; i < pagevec_count(pvec); i++) { - struct page *page = pvec->pages[i]; - if (!radix_tree_exceptional_entry(page)) - pvec->pages[j++] = page; - } - pvec->nr = j; -} - -/** - * pagevec_lookup - gang pagecache lookup - * @pvec: Where the resulting pages are placed - * @mapping: The address_space to search - * @start: The starting page index - * @nr_pages: The maximum number of pages - * - * pagevec_lookup() will search for and return a group of up to @nr_pages pages - * in the mapping. The pages are placed in @pvec. pagevec_lookup() takes a - * reference against the pages in @pvec. - * - * The search returns a group of mapping-contiguous pages with ascending - * indexes. There may be holes in the indices due to not-present pages. - * - * pagevec_lookup() returns the number of pages which were found. - */ -unsigned pagevec_lookup(struct pagevec *pvec, struct address_space *mapping, - pgoff_t start, unsigned nr_pages) -{ - pvec->nr = find_get_pages(mapping, start, nr_pages, pvec->pages); - return pagevec_count(pvec); -} -EXPORT_SYMBOL(pagevec_lookup); - -unsigned pagevec_lookup_tag(struct pagevec *pvec, struct address_space *mapping, - pgoff_t *index, int tag, unsigned nr_pages) -{ - pvec->nr = find_get_pages_tag(mapping, index, tag, - nr_pages, pvec->pages); - return pagevec_count(pvec); -} -EXPORT_SYMBOL(pagevec_lookup_tag); - -/* - * Perform any setup for the swap system - */ -void __init swap_setup(void) -{ - unsigned long megs = totalram_pages >> (20 - PAGE_SHIFT); -#ifdef CONFIG_SWAP - int i; - - for (i = 0; i < MAX_SWAPFILES; i++) - spin_lock_init(&swapper_spaces[i].tree_lock); -#endif - - /* Use a smaller cluster for small-memory machines */ - if (megs < 16) - page_cluster = 2; - else - page_cluster = 3; - /* - * Right now other parts of the system means that we - * _really_ don't want to cluster much more - */ -} diff --git a/src/linux/mm/truncate.c b/src/linux/mm/truncate.c deleted file mode 100644 index 8d8c62d..0000000 --- a/src/linux/mm/truncate.c +++ /dev/null @@ -1,822 +0,0 @@ -/* - * mm/truncate.c - code for taking down pages from address_spaces - * - * Copyright (C) 2002, Linus Torvalds - * - * 10Sep2002 Andrew Morton - * Initial version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* grr. try_to_release_page, - do_invalidatepage */ -#include -#include -#include "internal.h" - -static void clear_exceptional_entry(struct address_space *mapping, - pgoff_t index, void *entry) -{ - struct radix_tree_node *node; - void **slot; - - /* Handled by shmem itself */ - if (shmem_mapping(mapping)) - return; - - if (dax_mapping(mapping)) { - dax_delete_mapping_entry(mapping, index); - return; - } - spin_lock_irq(&mapping->tree_lock); - /* - * Regular page slots are stabilized by the page lock even - * without the tree itself locked. These unlocked entries - * need verification under the tree lock. - */ - if (!__radix_tree_lookup(&mapping->page_tree, index, &node, - &slot)) - goto unlock; - if (*slot != entry) - goto unlock; - radix_tree_replace_slot(slot, NULL); - mapping->nrexceptional--; - if (!node) - goto unlock; - workingset_node_shadows_dec(node); - /* - * Don't track node without shadow entries. - * - * Avoid acquiring the list_lru lock if already untracked. - * The list_empty() test is safe as node->private_list is - * protected by mapping->tree_lock. - */ - if (!workingset_node_shadows(node) && - !list_empty(&node->private_list)) - list_lru_del(&workingset_shadow_nodes, - &node->private_list); - __radix_tree_delete_node(&mapping->page_tree, node); -unlock: - spin_unlock_irq(&mapping->tree_lock); -} - -/** - * do_invalidatepage - invalidate part or all of a page - * @page: the page which is affected - * @offset: start of the range to invalidate - * @length: length of the range to invalidate - * - * do_invalidatepage() is called when all or part of the page has become - * invalidated by a truncate operation. - * - * do_invalidatepage() does not have to release all buffers, but it must - * ensure that no dirty buffer is left outside @offset and that no I/O - * is underway against any of the blocks which are outside the truncation - * point. Because the caller is about to free (and possibly reuse) those - * blocks on-disk. - */ -void do_invalidatepage(struct page *page, unsigned int offset, - unsigned int length) -{ - void (*invalidatepage)(struct page *, unsigned int, unsigned int); - - invalidatepage = page->mapping->a_ops->invalidatepage; -#ifdef CONFIG_BLOCK - if (!invalidatepage) - invalidatepage = block_invalidatepage; -#endif - if (invalidatepage) - (*invalidatepage)(page, offset, length); -} - -/* - * If truncate cannot remove the fs-private metadata from the page, the page - * becomes orphaned. It will be left on the LRU and may even be mapped into - * user pagetables if we're racing with filemap_fault(). - * - * We need to bale out if page->mapping is no longer equal to the original - * mapping. This happens a) when the VM reclaimed the page while we waited on - * its lock, b) when a concurrent invalidate_mapping_pages got there first and - * c) when tmpfs swizzles a page between a tmpfs inode and swapper_space. - */ -static int -truncate_complete_page(struct address_space *mapping, struct page *page) -{ - if (page->mapping != mapping) - return -EIO; - - if (page_has_private(page)) - do_invalidatepage(page, 0, PAGE_SIZE); - - /* - * Some filesystems seem to re-dirty the page even after - * the VM has canceled the dirty bit (eg ext3 journaling). - * Hence dirty accounting check is placed after invalidation. - */ - cancel_dirty_page(page); - ClearPageMappedToDisk(page); - delete_from_page_cache(page); - return 0; -} - -/* - * This is for invalidate_mapping_pages(). That function can be called at - * any time, and is not supposed to throw away dirty pages. But pages can - * be marked dirty at any time too, so use remove_mapping which safely - * discards clean, unused pages. - * - * Returns non-zero if the page was successfully invalidated. - */ -static int -invalidate_complete_page(struct address_space *mapping, struct page *page) -{ - int ret; - - if (page->mapping != mapping) - return 0; - - if (page_has_private(page) && !try_to_release_page(page, 0)) - return 0; - - ret = remove_mapping(mapping, page); - - return ret; -} - -int truncate_inode_page(struct address_space *mapping, struct page *page) -{ - loff_t holelen; - VM_BUG_ON_PAGE(PageTail(page), page); - - holelen = PageTransHuge(page) ? HPAGE_PMD_SIZE : PAGE_SIZE; - if (page_mapped(page)) { - unmap_mapping_range(mapping, - (loff_t)page->index << PAGE_SHIFT, - holelen, 0); - } - return truncate_complete_page(mapping, page); -} - -/* - * Used to get rid of pages on hardware memory corruption. - */ -int generic_error_remove_page(struct address_space *mapping, struct page *page) -{ - if (!mapping) - return -EINVAL; - /* - * Only punch for normal data pages for now. - * Handling other types like directories would need more auditing. - */ - if (!S_ISREG(mapping->host->i_mode)) - return -EIO; - return truncate_inode_page(mapping, page); -} -EXPORT_SYMBOL(generic_error_remove_page); - -/* - * Safely invalidate one page from its pagecache mapping. - * It only drops clean, unused pages. The page must be locked. - * - * Returns 1 if the page is successfully invalidated, otherwise 0. - */ -int invalidate_inode_page(struct page *page) -{ - struct address_space *mapping = page_mapping(page); - if (!mapping) - return 0; - if (PageDirty(page) || PageWriteback(page)) - return 0; - if (page_mapped(page)) - return 0; - return invalidate_complete_page(mapping, page); -} - -/** - * truncate_inode_pages_range - truncate range of pages specified by start & end byte offsets - * @mapping: mapping to truncate - * @lstart: offset from which to truncate - * @lend: offset to which to truncate (inclusive) - * - * Truncate the page cache, removing the pages that are between - * specified offsets (and zeroing out partial pages - * if lstart or lend + 1 is not page aligned). - * - * Truncate takes two passes - the first pass is nonblocking. It will not - * block on page locks and it will not block on writeback. The second pass - * will wait. This is to prevent as much IO as possible in the affected region. - * The first pass will remove most pages, so the search cost of the second pass - * is low. - * - * We pass down the cache-hot hint to the page freeing code. Even if the - * mapping is large, it is probably the case that the final pages are the most - * recently touched, and freeing happens in ascending file offset order. - * - * Note that since ->invalidatepage() accepts range to invalidate - * truncate_inode_pages_range is able to handle cases where lend + 1 is not - * page aligned properly. - */ -void truncate_inode_pages_range(struct address_space *mapping, - loff_t lstart, loff_t lend) -{ - pgoff_t start; /* inclusive */ - pgoff_t end; /* exclusive */ - unsigned int partial_start; /* inclusive */ - unsigned int partial_end; /* exclusive */ - struct pagevec pvec; - pgoff_t indices[PAGEVEC_SIZE]; - pgoff_t index; - int i; - - cleancache_invalidate_inode(mapping); - if (mapping->nrpages == 0 && mapping->nrexceptional == 0) - return; - - /* Offsets within partial pages */ - partial_start = lstart & (PAGE_SIZE - 1); - partial_end = (lend + 1) & (PAGE_SIZE - 1); - - /* - * 'start' and 'end' always covers the range of pages to be fully - * truncated. Partial pages are covered with 'partial_start' at the - * start of the range and 'partial_end' at the end of the range. - * Note that 'end' is exclusive while 'lend' is inclusive. - */ - start = (lstart + PAGE_SIZE - 1) >> PAGE_SHIFT; - if (lend == -1) - /* - * lend == -1 indicates end-of-file so we have to set 'end' - * to the highest possible pgoff_t and since the type is - * unsigned we're using -1. - */ - end = -1; - else - end = (lend + 1) >> PAGE_SHIFT; - - pagevec_init(&pvec, 0); - index = start; - while (index < end && pagevec_lookup_entries(&pvec, mapping, index, - min(end - index, (pgoff_t)PAGEVEC_SIZE), - indices)) { - for (i = 0; i < pagevec_count(&pvec); i++) { - struct page *page = pvec.pages[i]; - - /* We rely upon deletion not changing page->index */ - index = indices[i]; - if (index >= end) - break; - - if (radix_tree_exceptional_entry(page)) { - clear_exceptional_entry(mapping, index, page); - continue; - } - - if (!trylock_page(page)) - continue; - WARN_ON(page_to_index(page) != index); - if (PageWriteback(page)) { - unlock_page(page); - continue; - } - truncate_inode_page(mapping, page); - unlock_page(page); - } - pagevec_remove_exceptionals(&pvec); - pagevec_release(&pvec); - cond_resched(); - index++; - } - - if (partial_start) { - struct page *page = find_lock_page(mapping, start - 1); - if (page) { - unsigned int top = PAGE_SIZE; - if (start > end) { - /* Truncation within a single page */ - top = partial_end; - partial_end = 0; - } - wait_on_page_writeback(page); - zero_user_segment(page, partial_start, top); - cleancache_invalidate_page(mapping, page); - if (page_has_private(page)) - do_invalidatepage(page, partial_start, - top - partial_start); - unlock_page(page); - put_page(page); - } - } - if (partial_end) { - struct page *page = find_lock_page(mapping, end); - if (page) { - wait_on_page_writeback(page); - zero_user_segment(page, 0, partial_end); - cleancache_invalidate_page(mapping, page); - if (page_has_private(page)) - do_invalidatepage(page, 0, - partial_end); - unlock_page(page); - put_page(page); - } - } - /* - * If the truncation happened within a single page no pages - * will be released, just zeroed, so we can bail out now. - */ - if (start >= end) - return; - - index = start; - for ( ; ; ) { - cond_resched(); - if (!pagevec_lookup_entries(&pvec, mapping, index, - min(end - index, (pgoff_t)PAGEVEC_SIZE), indices)) { - /* If all gone from start onwards, we're done */ - if (index == start) - break; - /* Otherwise restart to make sure all gone */ - index = start; - continue; - } - if (index == start && indices[0] >= end) { - /* All gone out of hole to be punched, we're done */ - pagevec_remove_exceptionals(&pvec); - pagevec_release(&pvec); - break; - } - for (i = 0; i < pagevec_count(&pvec); i++) { - struct page *page = pvec.pages[i]; - - /* We rely upon deletion not changing page->index */ - index = indices[i]; - if (index >= end) { - /* Restart punch to make sure all gone */ - index = start - 1; - break; - } - - if (radix_tree_exceptional_entry(page)) { - clear_exceptional_entry(mapping, index, page); - continue; - } - - lock_page(page); - WARN_ON(page_to_index(page) != index); - wait_on_page_writeback(page); - truncate_inode_page(mapping, page); - unlock_page(page); - } - pagevec_remove_exceptionals(&pvec); - pagevec_release(&pvec); - index++; - } - cleancache_invalidate_inode(mapping); -} -EXPORT_SYMBOL(truncate_inode_pages_range); - -/** - * truncate_inode_pages - truncate *all* the pages from an offset - * @mapping: mapping to truncate - * @lstart: offset from which to truncate - * - * Called under (and serialised by) inode->i_mutex. - * - * Note: When this function returns, there can be a page in the process of - * deletion (inside __delete_from_page_cache()) in the specified range. Thus - * mapping->nrpages can be non-zero when this function returns even after - * truncation of the whole mapping. - */ -void truncate_inode_pages(struct address_space *mapping, loff_t lstart) -{ - truncate_inode_pages_range(mapping, lstart, (loff_t)-1); -} -EXPORT_SYMBOL(truncate_inode_pages); - -/** - * truncate_inode_pages_final - truncate *all* pages before inode dies - * @mapping: mapping to truncate - * - * Called under (and serialized by) inode->i_mutex. - * - * Filesystems have to use this in the .evict_inode path to inform the - * VM that this is the final truncate and the inode is going away. - */ -void truncate_inode_pages_final(struct address_space *mapping) -{ - unsigned long nrexceptional; - unsigned long nrpages; - - /* - * Page reclaim can not participate in regular inode lifetime - * management (can't call iput()) and thus can race with the - * inode teardown. Tell it when the address space is exiting, - * so that it does not install eviction information after the - * final truncate has begun. - */ - mapping_set_exiting(mapping); - - /* - * When reclaim installs eviction entries, it increases - * nrexceptional first, then decreases nrpages. Make sure we see - * this in the right order or we might miss an entry. - */ - nrpages = mapping->nrpages; - smp_rmb(); - nrexceptional = mapping->nrexceptional; - - if (nrpages || nrexceptional) { - /* - * As truncation uses a lockless tree lookup, cycle - * the tree lock to make sure any ongoing tree - * modification that does not see AS_EXITING is - * completed before starting the final truncate. - */ - spin_lock_irq(&mapping->tree_lock); - spin_unlock_irq(&mapping->tree_lock); - - truncate_inode_pages(mapping, 0); - } -} -EXPORT_SYMBOL(truncate_inode_pages_final); - -/** - * invalidate_mapping_pages - Invalidate all the unlocked pages of one inode - * @mapping: the address_space which holds the pages to invalidate - * @start: the offset 'from' which to invalidate - * @end: the offset 'to' which to invalidate (inclusive) - * - * This function only removes the unlocked pages, if you want to - * remove all the pages of one inode, you must call truncate_inode_pages. - * - * invalidate_mapping_pages() will not block on IO activity. It will not - * invalidate pages which are dirty, locked, under writeback or mapped into - * pagetables. - */ -unsigned long invalidate_mapping_pages(struct address_space *mapping, - pgoff_t start, pgoff_t end) -{ - pgoff_t indices[PAGEVEC_SIZE]; - struct pagevec pvec; - pgoff_t index = start; - unsigned long ret; - unsigned long count = 0; - int i; - - pagevec_init(&pvec, 0); - while (index <= end && pagevec_lookup_entries(&pvec, mapping, index, - min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1, - indices)) { - for (i = 0; i < pagevec_count(&pvec); i++) { - struct page *page = pvec.pages[i]; - - /* We rely upon deletion not changing page->index */ - index = indices[i]; - if (index > end) - break; - - if (radix_tree_exceptional_entry(page)) { - clear_exceptional_entry(mapping, index, page); - continue; - } - - if (!trylock_page(page)) - continue; - - WARN_ON(page_to_index(page) != index); - - /* Middle of THP: skip */ - if (PageTransTail(page)) { - unlock_page(page); - continue; - } else if (PageTransHuge(page)) { - index += HPAGE_PMD_NR - 1; - i += HPAGE_PMD_NR - 1; - /* 'end' is in the middle of THP */ - if (index == round_down(end, HPAGE_PMD_NR)) - continue; - } - - ret = invalidate_inode_page(page); - unlock_page(page); - /* - * Invalidation is a hint that the page is no longer - * of interest and try to speed up its reclaim. - */ - if (!ret) - deactivate_file_page(page); - count += ret; - } - pagevec_remove_exceptionals(&pvec); - pagevec_release(&pvec); - cond_resched(); - index++; - } - return count; -} -EXPORT_SYMBOL(invalidate_mapping_pages); - -/* - * This is like invalidate_complete_page(), except it ignores the page's - * refcount. We do this because invalidate_inode_pages2() needs stronger - * invalidation guarantees, and cannot afford to leave pages behind because - * shrink_page_list() has a temp ref on them, or because they're transiently - * sitting in the lru_cache_add() pagevecs. - */ -static int -invalidate_complete_page2(struct address_space *mapping, struct page *page) -{ - unsigned long flags; - - if (page->mapping != mapping) - return 0; - - if (page_has_private(page) && !try_to_release_page(page, GFP_KERNEL)) - return 0; - - spin_lock_irqsave(&mapping->tree_lock, flags); - if (PageDirty(page)) - goto failed; - - BUG_ON(page_has_private(page)); - __delete_from_page_cache(page, NULL); - spin_unlock_irqrestore(&mapping->tree_lock, flags); - - if (mapping->a_ops->freepage) - mapping->a_ops->freepage(page); - - put_page(page); /* pagecache ref */ - return 1; -failed: - spin_unlock_irqrestore(&mapping->tree_lock, flags); - return 0; -} - -static int do_launder_page(struct address_space *mapping, struct page *page) -{ - if (!PageDirty(page)) - return 0; - if (page->mapping != mapping || mapping->a_ops->launder_page == NULL) - return 0; - return mapping->a_ops->launder_page(page); -} - -/** - * invalidate_inode_pages2_range - remove range of pages from an address_space - * @mapping: the address_space - * @start: the page offset 'from' which to invalidate - * @end: the page offset 'to' which to invalidate (inclusive) - * - * Any pages which are found to be mapped into pagetables are unmapped prior to - * invalidation. - * - * Returns -EBUSY if any pages could not be invalidated. - */ -int invalidate_inode_pages2_range(struct address_space *mapping, - pgoff_t start, pgoff_t end) -{ - pgoff_t indices[PAGEVEC_SIZE]; - struct pagevec pvec; - pgoff_t index; - int i; - int ret = 0; - int ret2 = 0; - int did_range_unmap = 0; - - cleancache_invalidate_inode(mapping); - pagevec_init(&pvec, 0); - index = start; - while (index <= end && pagevec_lookup_entries(&pvec, mapping, index, - min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1, - indices)) { - for (i = 0; i < pagevec_count(&pvec); i++) { - struct page *page = pvec.pages[i]; - - /* We rely upon deletion not changing page->index */ - index = indices[i]; - if (index > end) - break; - - if (radix_tree_exceptional_entry(page)) { - clear_exceptional_entry(mapping, index, page); - continue; - } - - lock_page(page); - WARN_ON(page_to_index(page) != index); - if (page->mapping != mapping) { - unlock_page(page); - continue; - } - wait_on_page_writeback(page); - if (page_mapped(page)) { - if (!did_range_unmap) { - /* - * Zap the rest of the file in one hit. - */ - unmap_mapping_range(mapping, - (loff_t)index << PAGE_SHIFT, - (loff_t)(1 + end - index) - << PAGE_SHIFT, - 0); - did_range_unmap = 1; - } else { - /* - * Just zap this page - */ - unmap_mapping_range(mapping, - (loff_t)index << PAGE_SHIFT, - PAGE_SIZE, 0); - } - } - BUG_ON(page_mapped(page)); - ret2 = do_launder_page(mapping, page); - if (ret2 == 0) { - if (!invalidate_complete_page2(mapping, page)) - ret2 = -EBUSY; - } - if (ret2 < 0) - ret = ret2; - unlock_page(page); - } - pagevec_remove_exceptionals(&pvec); - pagevec_release(&pvec); - cond_resched(); - index++; - } - cleancache_invalidate_inode(mapping); - return ret; -} -EXPORT_SYMBOL_GPL(invalidate_inode_pages2_range); - -/** - * invalidate_inode_pages2 - remove all pages from an address_space - * @mapping: the address_space - * - * Any pages which are found to be mapped into pagetables are unmapped prior to - * invalidation. - * - * Returns -EBUSY if any pages could not be invalidated. - */ -int invalidate_inode_pages2(struct address_space *mapping) -{ - return invalidate_inode_pages2_range(mapping, 0, -1); -} -EXPORT_SYMBOL_GPL(invalidate_inode_pages2); - -/** - * truncate_pagecache - unmap and remove pagecache that has been truncated - * @inode: inode - * @newsize: new file size - * - * inode's new i_size must already be written before truncate_pagecache - * is called. - * - * This function should typically be called before the filesystem - * releases resources associated with the freed range (eg. deallocates - * blocks). This way, pagecache will always stay logically coherent - * with on-disk format, and the filesystem would not have to deal with - * situations such as writepage being called for a page that has already - * had its underlying blocks deallocated. - */ -void truncate_pagecache(struct inode *inode, loff_t newsize) -{ - struct address_space *mapping = inode->i_mapping; - loff_t holebegin = round_up(newsize, PAGE_SIZE); - - /* - * unmap_mapping_range is called twice, first simply for - * efficiency so that truncate_inode_pages does fewer - * single-page unmaps. However after this first call, and - * before truncate_inode_pages finishes, it is possible for - * private pages to be COWed, which remain after - * truncate_inode_pages finishes, hence the second - * unmap_mapping_range call must be made for correctness. - */ - unmap_mapping_range(mapping, holebegin, 0, 1); - truncate_inode_pages(mapping, newsize); - unmap_mapping_range(mapping, holebegin, 0, 1); -} -EXPORT_SYMBOL(truncate_pagecache); - -/** - * truncate_setsize - update inode and pagecache for a new file size - * @inode: inode - * @newsize: new file size - * - * truncate_setsize updates i_size and performs pagecache truncation (if - * necessary) to @newsize. It will be typically be called from the filesystem's - * setattr function when ATTR_SIZE is passed in. - * - * Must be called with a lock serializing truncates and writes (generally - * i_mutex but e.g. xfs uses a different lock) and before all filesystem - * specific block truncation has been performed. - */ -void truncate_setsize(struct inode *inode, loff_t newsize) -{ - loff_t oldsize = inode->i_size; - - i_size_write(inode, newsize); - if (newsize > oldsize) - pagecache_isize_extended(inode, oldsize, newsize); - truncate_pagecache(inode, newsize); -} -EXPORT_SYMBOL(truncate_setsize); - -/** - * pagecache_isize_extended - update pagecache after extension of i_size - * @inode: inode for which i_size was extended - * @from: original inode size - * @to: new inode size - * - * Handle extension of inode size either caused by extending truncate or by - * write starting after current i_size. We mark the page straddling current - * i_size RO so that page_mkwrite() is called on the nearest write access to - * the page. This way filesystem can be sure that page_mkwrite() is called on - * the page before user writes to the page via mmap after the i_size has been - * changed. - * - * The function must be called after i_size is updated so that page fault - * coming after we unlock the page will already see the new i_size. - * The function must be called while we still hold i_mutex - this not only - * makes sure i_size is stable but also that userspace cannot observe new - * i_size value before we are prepared to store mmap writes at new inode size. - */ -void pagecache_isize_extended(struct inode *inode, loff_t from, loff_t to) -{ - int bsize = 1 << inode->i_blkbits; - loff_t rounded_from; - struct page *page; - pgoff_t index; - - WARN_ON(to > inode->i_size); - - if (from >= to || bsize == PAGE_SIZE) - return; - /* Page straddling @from will not have any hole block created? */ - rounded_from = round_up(from, bsize); - if (to <= rounded_from || !(rounded_from & (PAGE_SIZE - 1))) - return; - - index = from >> PAGE_SHIFT; - page = find_lock_page(inode->i_mapping, index); - /* Page not cached? Nothing to do */ - if (!page) - return; - /* - * See clear_page_dirty_for_io() for details why set_page_dirty() - * is needed. - */ - if (page_mkclean(page)) - set_page_dirty(page); - unlock_page(page); - put_page(page); -} -EXPORT_SYMBOL(pagecache_isize_extended); - -/** - * truncate_pagecache_range - unmap and remove pagecache that is hole-punched - * @inode: inode - * @lstart: offset of beginning of hole - * @lend: offset of last byte of hole - * - * This function should typically be called before the filesystem - * releases resources associated with the freed range (eg. deallocates - * blocks). This way, pagecache will always stay logically coherent - * with on-disk format, and the filesystem would not have to deal with - * situations such as writepage being called for a page that has already - * had its underlying blocks deallocated. - */ -void truncate_pagecache_range(struct inode *inode, loff_t lstart, loff_t lend) -{ - struct address_space *mapping = inode->i_mapping; - loff_t unmap_start = round_up(lstart, PAGE_SIZE); - loff_t unmap_end = round_down(1 + lend, PAGE_SIZE) - 1; - /* - * This rounding is currently just for example: unmap_mapping_range - * expands its hole outwards, whereas we want it to contract the hole - * inwards. However, existing callers of truncate_pagecache_range are - * doing their own page rounding first. Note that unmap_mapping_range - * allows holelen 0 for all, and we allow lend -1 for end of file. - */ - - /* - * Unlike in truncate_pagecache, unmap_mapping_range is called only - * once (before truncating pagecache), and without "even_cows" flag: - * hole-punching should not remove private COWed pages from the hole. - */ - if ((u64)unmap_end > (u64)unmap_start) - unmap_mapping_range(mapping, unmap_start, - 1 + unmap_end - unmap_start, 0); - truncate_inode_pages_range(mapping, lstart, lend); -} -EXPORT_SYMBOL(truncate_pagecache_range); diff --git a/src/linux/mm/util.c b/src/linux/mm/util.c deleted file mode 100644 index 1a41553..0000000 --- a/src/linux/mm/util.c +++ /dev/null @@ -1,653 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include "internal.h" - -static inline int is_kernel_rodata(unsigned long addr) -{ - return addr >= (unsigned long)__start_rodata && - addr < (unsigned long)__end_rodata; -} - -/** - * kfree_const - conditionally free memory - * @x: pointer to the memory - * - * Function calls kfree only if @x is not in .rodata section. - */ -void kfree_const(const void *x) -{ - if (!is_kernel_rodata((unsigned long)x)) - kfree(x); -} -EXPORT_SYMBOL(kfree_const); - -/** - * kstrdup - allocate space for and copy an existing string - * @s: the string to duplicate - * @gfp: the GFP mask used in the kmalloc() call when allocating memory - */ -char *kstrdup(const char *s, gfp_t gfp) -{ - size_t len; - char *buf; - - if (!s) - return NULL; - - len = strlen(s) + 1; - buf = kmalloc_track_caller(len, gfp); - if (buf) - memcpy(buf, s, len); - return buf; -} -EXPORT_SYMBOL(kstrdup); - -/** - * kstrdup_const - conditionally duplicate an existing const string - * @s: the string to duplicate - * @gfp: the GFP mask used in the kmalloc() call when allocating memory - * - * Function returns source string if it is in .rodata section otherwise it - * fallbacks to kstrdup. - * Strings allocated by kstrdup_const should be freed by kfree_const. - */ -const char *kstrdup_const(const char *s, gfp_t gfp) -{ - if (is_kernel_rodata((unsigned long)s)) - return s; - - return kstrdup(s, gfp); -} -EXPORT_SYMBOL(kstrdup_const); - -/** - * kstrndup - allocate space for and copy an existing string - * @s: the string to duplicate - * @max: read at most @max chars from @s - * @gfp: the GFP mask used in the kmalloc() call when allocating memory - */ -char *kstrndup(const char *s, size_t max, gfp_t gfp) -{ - size_t len; - char *buf; - - if (!s) - return NULL; - - len = strnlen(s, max); - buf = kmalloc_track_caller(len+1, gfp); - if (buf) { - memcpy(buf, s, len); - buf[len] = '\0'; - } - return buf; -} -EXPORT_SYMBOL(kstrndup); - -/** - * kmemdup - duplicate region of memory - * - * @src: memory region to duplicate - * @len: memory region length - * @gfp: GFP mask to use - */ -void *kmemdup(const void *src, size_t len, gfp_t gfp) -{ - void *p; - - p = kmalloc_track_caller(len, gfp); - if (p) - memcpy(p, src, len); - return p; -} -EXPORT_SYMBOL(kmemdup); - -/** - * memdup_user - duplicate memory region from user space - * - * @src: source address in user space - * @len: number of bytes to copy - * - * Returns an ERR_PTR() on failure. - */ -void *memdup_user(const void __user *src, size_t len) -{ - void *p; - - /* - * Always use GFP_KERNEL, since copy_from_user() can sleep and - * cause pagefault, which makes it pointless to use GFP_NOFS - * or GFP_ATOMIC. - */ - p = kmalloc_track_caller(len, GFP_KERNEL); - if (!p) - return ERR_PTR(-ENOMEM); - - if (copy_from_user(p, src, len)) { - kfree(p); - return ERR_PTR(-EFAULT); - } - - return p; -} -EXPORT_SYMBOL(memdup_user); - -/* - * strndup_user - duplicate an existing string from user space - * @s: The string to duplicate - * @n: Maximum number of bytes to copy, including the trailing NUL. - */ -char *strndup_user(const char __user *s, long n) -{ - char *p; - long length; - - length = strnlen_user(s, n); - - if (!length) - return ERR_PTR(-EFAULT); - - if (length > n) - return ERR_PTR(-EINVAL); - - p = memdup_user(s, length); - - if (IS_ERR(p)) - return p; - - p[length - 1] = '\0'; - - return p; -} -EXPORT_SYMBOL(strndup_user); - -/** - * memdup_user_nul - duplicate memory region from user space and NUL-terminate - * - * @src: source address in user space - * @len: number of bytes to copy - * - * Returns an ERR_PTR() on failure. - */ -void *memdup_user_nul(const void __user *src, size_t len) -{ - char *p; - - /* - * Always use GFP_KERNEL, since copy_from_user() can sleep and - * cause pagefault, which makes it pointless to use GFP_NOFS - * or GFP_ATOMIC. - */ - p = kmalloc_track_caller(len + 1, GFP_KERNEL); - if (!p) - return ERR_PTR(-ENOMEM); - - if (copy_from_user(p, src, len)) { - kfree(p); - return ERR_PTR(-EFAULT); - } - p[len] = '\0'; - - return p; -} -EXPORT_SYMBOL(memdup_user_nul); - -void __vma_link_list(struct mm_struct *mm, struct vm_area_struct *vma, - struct vm_area_struct *prev, struct rb_node *rb_parent) -{ - struct vm_area_struct *next; - - vma->vm_prev = prev; - if (prev) { - next = prev->vm_next; - prev->vm_next = vma; - } else { - mm->mmap = vma; - if (rb_parent) - next = rb_entry(rb_parent, - struct vm_area_struct, vm_rb); - else - next = NULL; - } - vma->vm_next = next; - if (next) - next->vm_prev = vma; -} - -/* Check if the vma is being used as a stack by this task */ -int vma_is_stack_for_current(struct vm_area_struct *vma) -{ - struct task_struct * __maybe_unused t = current; - - return (vma->vm_start <= KSTK_ESP(t) && vma->vm_end >= KSTK_ESP(t)); -} - -#if defined(CONFIG_MMU) && !defined(HAVE_ARCH_PICK_MMAP_LAYOUT) -void arch_pick_mmap_layout(struct mm_struct *mm) -{ - mm->mmap_base = TASK_UNMAPPED_BASE; - mm->get_unmapped_area = arch_get_unmapped_area; -} -#endif - -/* - * Like get_user_pages_fast() except its IRQ-safe in that it won't fall - * back to the regular GUP. - * If the architecture not support this function, simply return with no - * page pinned - */ -int __weak __get_user_pages_fast(unsigned long start, - int nr_pages, int write, struct page **pages) -{ - return 0; -} -EXPORT_SYMBOL_GPL(__get_user_pages_fast); - -/** - * get_user_pages_fast() - pin user pages in memory - * @start: starting user address - * @nr_pages: number of pages from start to pin - * @write: whether pages will be written to - * @pages: array that receives pointers to the pages pinned. - * Should be at least nr_pages long. - * - * Returns number of pages pinned. This may be fewer than the number - * requested. If nr_pages is 0 or negative, returns 0. If no pages - * were pinned, returns -errno. - * - * get_user_pages_fast provides equivalent functionality to get_user_pages, - * operating on current and current->mm, with force=0 and vma=NULL. However - * unlike get_user_pages, it must be called without mmap_sem held. - * - * get_user_pages_fast may take mmap_sem and page table locks, so no - * assumptions can be made about lack of locking. get_user_pages_fast is to be - * implemented in a way that is advantageous (vs get_user_pages()) when the - * user memory area is already faulted in and present in ptes. However if the - * pages have to be faulted in, it may turn out to be slightly slower so - * callers need to carefully consider what to use. On many architectures, - * get_user_pages_fast simply falls back to get_user_pages. - */ -int __weak get_user_pages_fast(unsigned long start, - int nr_pages, int write, struct page **pages) -{ - return get_user_pages_unlocked(start, nr_pages, pages, - write ? FOLL_WRITE : 0); -} -EXPORT_SYMBOL_GPL(get_user_pages_fast); - -unsigned long vm_mmap_pgoff(struct file *file, unsigned long addr, - unsigned long len, unsigned long prot, - unsigned long flag, unsigned long pgoff) -{ - unsigned long ret; - struct mm_struct *mm = current->mm; - unsigned long populate; - - ret = security_mmap_file(file, prot, flag); - if (!ret) { - if (down_write_killable(&mm->mmap_sem)) - return -EINTR; - ret = do_mmap_pgoff(file, addr, len, prot, flag, pgoff, - &populate); - up_write(&mm->mmap_sem); - if (populate) - mm_populate(ret, populate); - } - return ret; -} - -unsigned long vm_mmap(struct file *file, unsigned long addr, - unsigned long len, unsigned long prot, - unsigned long flag, unsigned long offset) -{ - if (unlikely(offset + PAGE_ALIGN(len) < offset)) - return -EINVAL; - if (unlikely(offset_in_page(offset))) - return -EINVAL; - - return vm_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT); -} -EXPORT_SYMBOL(vm_mmap); - -void kvfree(const void *addr) -{ - if (is_vmalloc_addr(addr)) - vfree(addr); - else - kfree(addr); -} -EXPORT_SYMBOL(kvfree); - -static inline void *__page_rmapping(struct page *page) -{ - unsigned long mapping; - - mapping = (unsigned long)page->mapping; - mapping &= ~PAGE_MAPPING_FLAGS; - - return (void *)mapping; -} - -/* Neutral page->mapping pointer to address_space or anon_vma or other */ -void *page_rmapping(struct page *page) -{ - page = compound_head(page); - return __page_rmapping(page); -} - -/* - * Return true if this page is mapped into pagetables. - * For compound page it returns true if any subpage of compound page is mapped. - */ -bool page_mapped(struct page *page) -{ - int i; - - if (likely(!PageCompound(page))) - return atomic_read(&page->_mapcount) >= 0; - page = compound_head(page); - if (atomic_read(compound_mapcount_ptr(page)) >= 0) - return true; - if (PageHuge(page)) - return false; - for (i = 0; i < hpage_nr_pages(page); i++) { - if (atomic_read(&page[i]._mapcount) >= 0) - return true; - } - return false; -} -EXPORT_SYMBOL(page_mapped); - -struct anon_vma *page_anon_vma(struct page *page) -{ - unsigned long mapping; - - page = compound_head(page); - mapping = (unsigned long)page->mapping; - if ((mapping & PAGE_MAPPING_FLAGS) != PAGE_MAPPING_ANON) - return NULL; - return __page_rmapping(page); -} - -struct address_space *page_mapping(struct page *page) -{ - struct address_space *mapping; - - page = compound_head(page); - - /* This happens if someone calls flush_dcache_page on slab page */ - if (unlikely(PageSlab(page))) - return NULL; - - if (unlikely(PageSwapCache(page))) { - swp_entry_t entry; - - entry.val = page_private(page); - return swap_address_space(entry); - } - - mapping = page->mapping; - if ((unsigned long)mapping & PAGE_MAPPING_ANON) - return NULL; - - return (void *)((unsigned long)mapping & ~PAGE_MAPPING_FLAGS); -} -EXPORT_SYMBOL(page_mapping); - -/* Slow path of page_mapcount() for compound pages */ -int __page_mapcount(struct page *page) -{ - int ret; - - ret = atomic_read(&page->_mapcount) + 1; - /* - * For file THP page->_mapcount contains total number of mapping - * of the page: no need to look into compound_mapcount. - */ - if (!PageAnon(page) && !PageHuge(page)) - return ret; - page = compound_head(page); - ret += atomic_read(compound_mapcount_ptr(page)) + 1; - if (PageDoubleMap(page)) - ret--; - return ret; -} -EXPORT_SYMBOL_GPL(__page_mapcount); - -int sysctl_overcommit_memory __read_mostly = OVERCOMMIT_GUESS; -int sysctl_overcommit_ratio __read_mostly = 50; -unsigned long sysctl_overcommit_kbytes __read_mostly; -int sysctl_max_map_count __read_mostly = DEFAULT_MAX_MAP_COUNT; -unsigned long sysctl_user_reserve_kbytes __read_mostly = 1UL << 17; /* 128MB */ -unsigned long sysctl_admin_reserve_kbytes __read_mostly = 1UL << 13; /* 8MB */ - -int overcommit_ratio_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - int ret; - - ret = proc_dointvec(table, write, buffer, lenp, ppos); - if (ret == 0 && write) - sysctl_overcommit_kbytes = 0; - return ret; -} - -int overcommit_kbytes_handler(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - int ret; - - ret = proc_doulongvec_minmax(table, write, buffer, lenp, ppos); - if (ret == 0 && write) - sysctl_overcommit_ratio = 0; - return ret; -} - -/* - * Committed memory limit enforced when OVERCOMMIT_NEVER policy is used - */ -unsigned long vm_commit_limit(void) -{ - unsigned long allowed; - - if (sysctl_overcommit_kbytes) - allowed = sysctl_overcommit_kbytes >> (PAGE_SHIFT - 10); - else - allowed = ((totalram_pages - hugetlb_total_pages()) - * sysctl_overcommit_ratio / 100); - allowed += total_swap_pages; - - return allowed; -} - -/* - * Make sure vm_committed_as in one cacheline and not cacheline shared with - * other variables. It can be updated by several CPUs frequently. - */ -struct percpu_counter vm_committed_as ____cacheline_aligned_in_smp; - -/* - * The global memory commitment made in the system can be a metric - * that can be used to drive ballooning decisions when Linux is hosted - * as a guest. On Hyper-V, the host implements a policy engine for dynamically - * balancing memory across competing virtual machines that are hosted. - * Several metrics drive this policy engine including the guest reported - * memory commitment. - */ -unsigned long vm_memory_committed(void) -{ - return percpu_counter_read_positive(&vm_committed_as); -} -EXPORT_SYMBOL_GPL(vm_memory_committed); - -/* - * Check that a process has enough memory to allocate a new virtual - * mapping. 0 means there is enough memory for the allocation to - * succeed and -ENOMEM implies there is not. - * - * We currently support three overcommit policies, which are set via the - * vm.overcommit_memory sysctl. See Documentation/vm/overcommit-accounting - * - * Strict overcommit modes added 2002 Feb 26 by Alan Cox. - * Additional code 2002 Jul 20 by Robert Love. - * - * cap_sys_admin is 1 if the process has admin privileges, 0 otherwise. - * - * Note this is a helper function intended to be used by LSMs which - * wish to use this logic. - */ -int __vm_enough_memory(struct mm_struct *mm, long pages, int cap_sys_admin) -{ - long free, allowed, reserve; - - VM_WARN_ONCE(percpu_counter_read(&vm_committed_as) < - -(s64)vm_committed_as_batch * num_online_cpus(), - "memory commitment underflow"); - - vm_acct_memory(pages); - - /* - * Sometimes we want to use more memory than we have - */ - if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS) - return 0; - - if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) { - free = global_page_state(NR_FREE_PAGES); - free += global_node_page_state(NR_FILE_PAGES); - - /* - * shmem pages shouldn't be counted as free in this - * case, they can't be purged, only swapped out, and - * that won't affect the overall amount of available - * memory in the system. - */ - free -= global_node_page_state(NR_SHMEM); - - free += get_nr_swap_pages(); - - /* - * Any slabs which are created with the - * SLAB_RECLAIM_ACCOUNT flag claim to have contents - * which are reclaimable, under pressure. The dentry - * cache and most inode caches should fall into this - */ - free += global_page_state(NR_SLAB_RECLAIMABLE); - - /* - * Leave reserved pages. The pages are not for anonymous pages. - */ - if (free <= totalreserve_pages) - goto error; - else - free -= totalreserve_pages; - - /* - * Reserve some for root - */ - if (!cap_sys_admin) - free -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10); - - if (free > pages) - return 0; - - goto error; - } - - allowed = vm_commit_limit(); - /* - * Reserve some for root - */ - if (!cap_sys_admin) - allowed -= sysctl_admin_reserve_kbytes >> (PAGE_SHIFT - 10); - - /* - * Don't let a single process grow so big a user can't recover - */ - if (mm) { - reserve = sysctl_user_reserve_kbytes >> (PAGE_SHIFT - 10); - allowed -= min_t(long, mm->total_vm / 32, reserve); - } - - if (percpu_counter_read_positive(&vm_committed_as) < allowed) - return 0; -error: - vm_unacct_memory(pages); - - return -ENOMEM; -} - -/** - * get_cmdline() - copy the cmdline value to a buffer. - * @task: the task whose cmdline value to copy. - * @buffer: the buffer to copy to. - * @buflen: the length of the buffer. Larger cmdline values are truncated - * to this length. - * Returns the size of the cmdline field copied. Note that the copy does - * not guarantee an ending NULL byte. - */ -int get_cmdline(struct task_struct *task, char *buffer, int buflen) -{ - int res = 0; - unsigned int len; - struct mm_struct *mm = get_task_mm(task); - unsigned long arg_start, arg_end, env_start, env_end; - if (!mm) - goto out; - if (!mm->arg_end) - goto out_mm; /* Shh! No looking before we're done */ - - down_read(&mm->mmap_sem); - arg_start = mm->arg_start; - arg_end = mm->arg_end; - env_start = mm->env_start; - env_end = mm->env_end; - up_read(&mm->mmap_sem); - - len = arg_end - arg_start; - - if (len > buflen) - len = buflen; - - res = access_process_vm(task, arg_start, buffer, len, FOLL_FORCE); - - /* - * If the nul at the end of args has been overwritten, then - * assume application is using setproctitle(3). - */ - if (res > 0 && buffer[res-1] != '\0' && len < buflen) { - len = strnlen(buffer, res); - if (len < res) { - res = len; - } else { - len = env_end - env_start; - if (len > buflen - res) - len = buflen - res; - res += access_process_vm(task, env_start, - buffer+res, len, - FOLL_FORCE); - res = strnlen(buffer, res); - } - } -out_mm: - mmput(mm); -out: - return res; -} diff --git a/src/linux/mm/vmacache.c b/src/linux/mm/vmacache.c deleted file mode 100644 index 035fdeb..0000000 --- a/src/linux/mm/vmacache.c +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2014 Davidlohr Bueso. - */ -#include -#include -#include - -/* - * Flush vma caches for threads that share a given mm. - * - * The operation is safe because the caller holds the mmap_sem - * exclusively and other threads accessing the vma cache will - * have mmap_sem held at least for read, so no extra locking - * is required to maintain the vma cache. - */ -void vmacache_flush_all(struct mm_struct *mm) -{ - struct task_struct *g, *p; - - count_vm_vmacache_event(VMACACHE_FULL_FLUSHES); - - /* - * Single threaded tasks need not iterate the entire - * list of process. We can avoid the flushing as well - * since the mm's seqnum was increased and don't have - * to worry about other threads' seqnum. Current's - * flush will occur upon the next lookup. - */ - if (atomic_read(&mm->mm_users) == 1) - return; - - rcu_read_lock(); - for_each_process_thread(g, p) { - /* - * Only flush the vmacache pointers as the - * mm seqnum is already set and curr's will - * be set upon invalidation when the next - * lookup is done. - */ - if (mm == p->mm) - vmacache_flush(p); - } - rcu_read_unlock(); -} - -/* - * This task may be accessing a foreign mm via (for example) - * get_user_pages()->find_vma(). The vmacache is task-local and this - * task's vmacache pertains to a different mm (ie, its own). There is - * nothing we can do here. - * - * Also handle the case where a kernel thread has adopted this mm via use_mm(). - * That kernel thread's vmacache is not applicable to this mm. - */ -static inline bool vmacache_valid_mm(struct mm_struct *mm) -{ - return current->mm == mm && !(current->flags & PF_KTHREAD); -} - -void vmacache_update(unsigned long addr, struct vm_area_struct *newvma) -{ - if (vmacache_valid_mm(newvma->vm_mm)) - current->vmacache[VMACACHE_HASH(addr)] = newvma; -} - -static bool vmacache_valid(struct mm_struct *mm) -{ - struct task_struct *curr; - - if (!vmacache_valid_mm(mm)) - return false; - - curr = current; - if (mm->vmacache_seqnum != curr->vmacache_seqnum) { - /* - * First attempt will always be invalid, initialize - * the new cache for this task here. - */ - curr->vmacache_seqnum = mm->vmacache_seqnum; - vmacache_flush(curr); - return false; - } - return true; -} - -struct vm_area_struct *vmacache_find(struct mm_struct *mm, unsigned long addr) -{ - int i; - - count_vm_vmacache_event(VMACACHE_FIND_CALLS); - - if (!vmacache_valid(mm)) - return NULL; - - for (i = 0; i < VMACACHE_SIZE; i++) { - struct vm_area_struct *vma = current->vmacache[i]; - - if (!vma) - continue; - if (WARN_ON_ONCE(vma->vm_mm != mm)) - break; - if (vma->vm_start <= addr && vma->vm_end > addr) { - count_vm_vmacache_event(VMACACHE_FIND_HITS); - return vma; - } - } - - return NULL; -} - -#ifndef CONFIG_MMU -struct vm_area_struct *vmacache_find_exact(struct mm_struct *mm, - unsigned long start, - unsigned long end) -{ - int i; - - count_vm_vmacache_event(VMACACHE_FIND_CALLS); - - if (!vmacache_valid(mm)) - return NULL; - - for (i = 0; i < VMACACHE_SIZE; i++) { - struct vm_area_struct *vma = current->vmacache[i]; - - if (vma && vma->vm_start == start && vma->vm_end == end) { - count_vm_vmacache_event(VMACACHE_FIND_HITS); - return vma; - } - } - - return NULL; -} -#endif diff --git a/src/linux/mm/vmscan.c b/src/linux/mm/vmscan.c deleted file mode 100644 index d75cdf3..0000000 --- a/src/linux/mm/vmscan.c +++ /dev/null @@ -1,3871 +0,0 @@ -/* - * linux/mm/vmscan.c - * - * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds - * - * Swap reorganised 29.12.95, Stephen Tweedie. - * kswapd added: 7.1.96 sct - * Removed kswapd_ctl limits, and swap out as many pages as needed - * to bring the system back to freepages.high: 2.4.97, Rik van Riel. - * Zone aware kswapd started 02/00, Kanoj Sarcar (kanoj@sgi.com). - * Multiqueue VM started 5.8.00, Rik van Riel. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include /* for try_to_release_page(), - buffer_heads_over_limit */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include "internal.h" - -#define CREATE_TRACE_POINTS -#include - -struct scan_control { - /* How many pages shrink_list() should reclaim */ - unsigned long nr_to_reclaim; - - /* This context's GFP mask */ - gfp_t gfp_mask; - - /* Allocation order */ - int order; - - /* - * Nodemask of nodes allowed by the caller. If NULL, all nodes - * are scanned. - */ - nodemask_t *nodemask; - - /* - * The memory cgroup that hit its limit and as a result is the - * primary target of this reclaim invocation. - */ - struct mem_cgroup *target_mem_cgroup; - - /* Scan (total_size >> priority) pages at once */ - int priority; - - /* The highest zone to isolate pages for reclaim from */ - enum zone_type reclaim_idx; - - unsigned int may_writepage:1; - - /* Can mapped pages be reclaimed? */ - unsigned int may_unmap:1; - - /* Can pages be swapped as part of reclaim? */ - unsigned int may_swap:1; - - /* Can cgroups be reclaimed below their normal consumption range? */ - unsigned int may_thrash:1; - - unsigned int hibernation_mode:1; - - /* One of the zones is ready for compaction */ - unsigned int compaction_ready:1; - - /* Incremented by the number of inactive pages that were scanned */ - unsigned long nr_scanned; - - /* Number of pages freed so far during a call to shrink_zones() */ - unsigned long nr_reclaimed; -}; - -#ifdef ARCH_HAS_PREFETCH -#define prefetch_prev_lru_page(_page, _base, _field) \ - do { \ - if ((_page)->lru.prev != _base) { \ - struct page *prev; \ - \ - prev = lru_to_page(&(_page->lru)); \ - prefetch(&prev->_field); \ - } \ - } while (0) -#else -#define prefetch_prev_lru_page(_page, _base, _field) do { } while (0) -#endif - -#ifdef ARCH_HAS_PREFETCHW -#define prefetchw_prev_lru_page(_page, _base, _field) \ - do { \ - if ((_page)->lru.prev != _base) { \ - struct page *prev; \ - \ - prev = lru_to_page(&(_page->lru)); \ - prefetchw(&prev->_field); \ - } \ - } while (0) -#else -#define prefetchw_prev_lru_page(_page, _base, _field) do { } while (0) -#endif - -/* - * From 0 .. 100. Higher means more swappy. - */ -int vm_swappiness = 60; -/* - * The total number of pages which are beyond the high watermark within all - * zones. - */ -unsigned long vm_total_pages; - -static LIST_HEAD(shrinker_list); -static DECLARE_RWSEM(shrinker_rwsem); - -#ifdef CONFIG_MEMCG -static bool global_reclaim(struct scan_control *sc) -{ - return !sc->target_mem_cgroup; -} - -/** - * sane_reclaim - is the usual dirty throttling mechanism operational? - * @sc: scan_control in question - * - * The normal page dirty throttling mechanism in balance_dirty_pages() is - * completely broken with the legacy memcg and direct stalling in - * shrink_page_list() is used for throttling instead, which lacks all the - * niceties such as fairness, adaptive pausing, bandwidth proportional - * allocation and configurability. - * - * This function tests whether the vmscan currently in progress can assume - * that the normal dirty throttling mechanism is operational. - */ -static bool sane_reclaim(struct scan_control *sc) -{ - struct mem_cgroup *memcg = sc->target_mem_cgroup; - - if (!memcg) - return true; -#ifdef CONFIG_CGROUP_WRITEBACK - if (cgroup_subsys_on_dfl(memory_cgrp_subsys)) - return true; -#endif - return false; -} -#else -static bool global_reclaim(struct scan_control *sc) -{ - return true; -} - -static bool sane_reclaim(struct scan_control *sc) -{ - return true; -} -#endif - -/* - * This misses isolated pages which are not accounted for to save counters. - * As the data only determines if reclaim or compaction continues, it is - * not expected that isolated pages will be a dominating factor. - */ -unsigned long zone_reclaimable_pages(struct zone *zone) -{ - unsigned long nr; - - nr = zone_page_state_snapshot(zone, NR_ZONE_INACTIVE_FILE) + - zone_page_state_snapshot(zone, NR_ZONE_ACTIVE_FILE); - if (get_nr_swap_pages() > 0) - nr += zone_page_state_snapshot(zone, NR_ZONE_INACTIVE_ANON) + - zone_page_state_snapshot(zone, NR_ZONE_ACTIVE_ANON); - - return nr; -} - -unsigned long pgdat_reclaimable_pages(struct pglist_data *pgdat) -{ - unsigned long nr; - - nr = node_page_state_snapshot(pgdat, NR_ACTIVE_FILE) + - node_page_state_snapshot(pgdat, NR_INACTIVE_FILE) + - node_page_state_snapshot(pgdat, NR_ISOLATED_FILE); - - if (get_nr_swap_pages() > 0) - nr += node_page_state_snapshot(pgdat, NR_ACTIVE_ANON) + - node_page_state_snapshot(pgdat, NR_INACTIVE_ANON) + - node_page_state_snapshot(pgdat, NR_ISOLATED_ANON); - - return nr; -} - -bool pgdat_reclaimable(struct pglist_data *pgdat) -{ - return node_page_state_snapshot(pgdat, NR_PAGES_SCANNED) < - pgdat_reclaimable_pages(pgdat) * 6; -} - -unsigned long lruvec_lru_size(struct lruvec *lruvec, enum lru_list lru) -{ - if (!mem_cgroup_disabled()) - return mem_cgroup_get_lru_size(lruvec, lru); - - return node_page_state(lruvec_pgdat(lruvec), NR_LRU_BASE + lru); -} - -/* - * Add a shrinker callback to be called from the vm. - */ -int register_shrinker(struct shrinker *shrinker) -{ - size_t size = sizeof(*shrinker->nr_deferred); - - if (shrinker->flags & SHRINKER_NUMA_AWARE) - size *= nr_node_ids; - - shrinker->nr_deferred = kzalloc(size, GFP_KERNEL); - if (!shrinker->nr_deferred) - return -ENOMEM; - - down_write(&shrinker_rwsem); - list_add_tail(&shrinker->list, &shrinker_list); - up_write(&shrinker_rwsem); - return 0; -} -EXPORT_SYMBOL(register_shrinker); - -/* - * Remove one - */ -void unregister_shrinker(struct shrinker *shrinker) -{ - down_write(&shrinker_rwsem); - list_del(&shrinker->list); - up_write(&shrinker_rwsem); - kfree(shrinker->nr_deferred); -} -EXPORT_SYMBOL(unregister_shrinker); - -#define SHRINK_BATCH 128 - -static unsigned long do_shrink_slab(struct shrink_control *shrinkctl, - struct shrinker *shrinker, - unsigned long nr_scanned, - unsigned long nr_eligible) -{ - unsigned long freed = 0; - unsigned long long delta; - long total_scan; - long freeable; - long nr; - long new_nr; - int nid = shrinkctl->nid; - long batch_size = shrinker->batch ? shrinker->batch - : SHRINK_BATCH; - - freeable = shrinker->count_objects(shrinker, shrinkctl); - if (freeable == 0) - return 0; - - /* - * copy the current shrinker scan count into a local variable - * and zero it so that other concurrent shrinker invocations - * don't also do this scanning work. - */ - nr = atomic_long_xchg(&shrinker->nr_deferred[nid], 0); - - total_scan = nr; - delta = (4 * nr_scanned) / shrinker->seeks; - delta *= freeable; - do_div(delta, nr_eligible + 1); - total_scan += delta; - if (total_scan < 0) { - pr_err("shrink_slab: %pF negative objects to delete nr=%ld\n", - shrinker->scan_objects, total_scan); - total_scan = freeable; - } - - /* - * We need to avoid excessive windup on filesystem shrinkers - * due to large numbers of GFP_NOFS allocations causing the - * shrinkers to return -1 all the time. This results in a large - * nr being built up so when a shrink that can do some work - * comes along it empties the entire cache due to nr >>> - * freeable. This is bad for sustaining a working set in - * memory. - * - * Hence only allow the shrinker to scan the entire cache when - * a large delta change is calculated directly. - */ - if (delta < freeable / 4) - total_scan = min(total_scan, freeable / 2); - - /* - * Avoid risking looping forever due to too large nr value: - * never try to free more than twice the estimate number of - * freeable entries. - */ - if (total_scan > freeable * 2) - total_scan = freeable * 2; - - trace_mm_shrink_slab_start(shrinker, shrinkctl, nr, - nr_scanned, nr_eligible, - freeable, delta, total_scan); - - /* - * Normally, we should not scan less than batch_size objects in one - * pass to avoid too frequent shrinker calls, but if the slab has less - * than batch_size objects in total and we are really tight on memory, - * we will try to reclaim all available objects, otherwise we can end - * up failing allocations although there are plenty of reclaimable - * objects spread over several slabs with usage less than the - * batch_size. - * - * We detect the "tight on memory" situations by looking at the total - * number of objects we want to scan (total_scan). If it is greater - * than the total number of objects on slab (freeable), we must be - * scanning at high prio and therefore should try to reclaim as much as - * possible. - */ - while (total_scan >= batch_size || - total_scan >= freeable) { - unsigned long ret; - unsigned long nr_to_scan = min(batch_size, total_scan); - - shrinkctl->nr_to_scan = nr_to_scan; - ret = shrinker->scan_objects(shrinker, shrinkctl); - if (ret == SHRINK_STOP) - break; - freed += ret; - - count_vm_events(SLABS_SCANNED, nr_to_scan); - total_scan -= nr_to_scan; - - cond_resched(); - } - - /* - * move the unused scan count back into the shrinker in a - * manner that handles concurrent updates. If we exhausted the - * scan, there is no need to do an update. - */ - if (total_scan > 0) - new_nr = atomic_long_add_return(total_scan, - &shrinker->nr_deferred[nid]); - else - new_nr = atomic_long_read(&shrinker->nr_deferred[nid]); - - trace_mm_shrink_slab_end(shrinker, nid, freed, nr, new_nr, total_scan); - return freed; -} - -/** - * shrink_slab - shrink slab caches - * @gfp_mask: allocation context - * @nid: node whose slab caches to target - * @memcg: memory cgroup whose slab caches to target - * @nr_scanned: pressure numerator - * @nr_eligible: pressure denominator - * - * Call the shrink functions to age shrinkable caches. - * - * @nid is passed along to shrinkers with SHRINKER_NUMA_AWARE set, - * unaware shrinkers will receive a node id of 0 instead. - * - * @memcg specifies the memory cgroup to target. If it is not NULL, - * only shrinkers with SHRINKER_MEMCG_AWARE set will be called to scan - * objects from the memory cgroup specified. Otherwise, only unaware - * shrinkers are called. - * - * @nr_scanned and @nr_eligible form a ratio that indicate how much of - * the available objects should be scanned. Page reclaim for example - * passes the number of pages scanned and the number of pages on the - * LRU lists that it considered on @nid, plus a bias in @nr_scanned - * when it encountered mapped pages. The ratio is further biased by - * the ->seeks setting of the shrink function, which indicates the - * cost to recreate an object relative to that of an LRU page. - * - * Returns the number of reclaimed slab objects. - */ -static unsigned long shrink_slab(gfp_t gfp_mask, int nid, - struct mem_cgroup *memcg, - unsigned long nr_scanned, - unsigned long nr_eligible) -{ - struct shrinker *shrinker; - unsigned long freed = 0; - - if (memcg && (!memcg_kmem_enabled() || !mem_cgroup_online(memcg))) - return 0; - - if (nr_scanned == 0) - nr_scanned = SWAP_CLUSTER_MAX; - - if (!down_read_trylock(&shrinker_rwsem)) { - /* - * If we would return 0, our callers would understand that we - * have nothing else to shrink and give up trying. By returning - * 1 we keep it going and assume we'll be able to shrink next - * time. - */ - freed = 1; - goto out; - } - - list_for_each_entry(shrinker, &shrinker_list, list) { - struct shrink_control sc = { - .gfp_mask = gfp_mask, - .nid = nid, - .memcg = memcg, - }; - - /* - * If kernel memory accounting is disabled, we ignore - * SHRINKER_MEMCG_AWARE flag and call all shrinkers - * passing NULL for memcg. - */ - if (memcg_kmem_enabled() && - !!memcg != !!(shrinker->flags & SHRINKER_MEMCG_AWARE)) - continue; - - if (!(shrinker->flags & SHRINKER_NUMA_AWARE)) - sc.nid = 0; - - freed += do_shrink_slab(&sc, shrinker, nr_scanned, nr_eligible); - } - - up_read(&shrinker_rwsem); -out: - cond_resched(); - return freed; -} - -void drop_slab_node(int nid) -{ - unsigned long freed; - - do { - struct mem_cgroup *memcg = NULL; - - freed = 0; - do { - freed += shrink_slab(GFP_KERNEL, nid, memcg, - 1000, 1000); - } while ((memcg = mem_cgroup_iter(NULL, memcg, NULL)) != NULL); - } while (freed > 10); -} - -void drop_slab(void) -{ - int nid; - - for_each_online_node(nid) - drop_slab_node(nid); -} - -static inline int is_page_cache_freeable(struct page *page) -{ - /* - * A freeable page cache page is referenced only by the caller - * that isolated the page, the page cache radix tree and - * optional buffer heads at page->private. - */ - return page_count(page) - page_has_private(page) == 2; -} - -static int may_write_to_inode(struct inode *inode, struct scan_control *sc) -{ - if (current->flags & PF_SWAPWRITE) - return 1; - if (!inode_write_congested(inode)) - return 1; - if (inode_to_bdi(inode) == current->backing_dev_info) - return 1; - return 0; -} - -/* - * We detected a synchronous write error writing a page out. Probably - * -ENOSPC. We need to propagate that into the address_space for a subsequent - * fsync(), msync() or close(). - * - * The tricky part is that after writepage we cannot touch the mapping: nothing - * prevents it from being freed up. But we have a ref on the page and once - * that page is locked, the mapping is pinned. - * - * We're allowed to run sleeping lock_page() here because we know the caller has - * __GFP_FS. - */ -static void handle_write_error(struct address_space *mapping, - struct page *page, int error) -{ - lock_page(page); - if (page_mapping(page) == mapping) - mapping_set_error(mapping, error); - unlock_page(page); -} - -/* possible outcome of pageout() */ -typedef enum { - /* failed to write page out, page is locked */ - PAGE_KEEP, - /* move page to the active list, page is locked */ - PAGE_ACTIVATE, - /* page has been sent to the disk successfully, page is unlocked */ - PAGE_SUCCESS, - /* page is clean and locked */ - PAGE_CLEAN, -} pageout_t; - -/* - * pageout is called by shrink_page_list() for each dirty page. - * Calls ->writepage(). - */ -static pageout_t pageout(struct page *page, struct address_space *mapping, - struct scan_control *sc) -{ - /* - * If the page is dirty, only perform writeback if that write - * will be non-blocking. To prevent this allocation from being - * stalled by pagecache activity. But note that there may be - * stalls if we need to run get_block(). We could test - * PagePrivate for that. - * - * If this process is currently in __generic_file_write_iter() against - * this page's queue, we can perform writeback even if that - * will block. - * - * If the page is swapcache, write it back even if that would - * block, for some throttling. This happens by accident, because - * swap_backing_dev_info is bust: it doesn't reflect the - * congestion state of the swapdevs. Easy to fix, if needed. - */ - if (!is_page_cache_freeable(page)) - return PAGE_KEEP; - if (!mapping) { - /* - * Some data journaling orphaned pages can have - * page->mapping == NULL while being dirty with clean buffers. - */ - if (page_has_private(page)) { - if (try_to_free_buffers(page)) { - ClearPageDirty(page); - pr_info("%s: orphaned page\n", __func__); - return PAGE_CLEAN; - } - } - return PAGE_KEEP; - } - if (mapping->a_ops->writepage == NULL) - return PAGE_ACTIVATE; - if (!may_write_to_inode(mapping->host, sc)) - return PAGE_KEEP; - - if (clear_page_dirty_for_io(page)) { - int res; - struct writeback_control wbc = { - .sync_mode = WB_SYNC_NONE, - .nr_to_write = SWAP_CLUSTER_MAX, - .range_start = 0, - .range_end = LLONG_MAX, - .for_reclaim = 1, - }; - - SetPageReclaim(page); - res = mapping->a_ops->writepage(page, &wbc); - if (res < 0) - handle_write_error(mapping, page, res); - if (res == AOP_WRITEPAGE_ACTIVATE) { - ClearPageReclaim(page); - return PAGE_ACTIVATE; - } - - if (!PageWriteback(page)) { - /* synchronous write or broken a_ops? */ - ClearPageReclaim(page); - } - trace_mm_vmscan_writepage(page); - inc_node_page_state(page, NR_VMSCAN_WRITE); - return PAGE_SUCCESS; - } - - return PAGE_CLEAN; -} - -/* - * Same as remove_mapping, but if the page is removed from the mapping, it - * gets returned with a refcount of 0. - */ -static int __remove_mapping(struct address_space *mapping, struct page *page, - bool reclaimed) -{ - unsigned long flags; - - BUG_ON(!PageLocked(page)); - BUG_ON(mapping != page_mapping(page)); - - spin_lock_irqsave(&mapping->tree_lock, flags); - /* - * The non racy check for a busy page. - * - * Must be careful with the order of the tests. When someone has - * a ref to the page, it may be possible that they dirty it then - * drop the reference. So if PageDirty is tested before page_count - * here, then the following race may occur: - * - * get_user_pages(&page); - * [user mapping goes away] - * write_to(page); - * !PageDirty(page) [good] - * SetPageDirty(page); - * put_page(page); - * !page_count(page) [good, discard it] - * - * [oops, our write_to data is lost] - * - * Reversing the order of the tests ensures such a situation cannot - * escape unnoticed. The smp_rmb is needed to ensure the page->flags - * load is not satisfied before that of page->_refcount. - * - * Note that if SetPageDirty is always performed via set_page_dirty, - * and thus under tree_lock, then this ordering is not required. - */ - if (!page_ref_freeze(page, 2)) - goto cannot_free; - /* note: atomic_cmpxchg in page_freeze_refs provides the smp_rmb */ - if (unlikely(PageDirty(page))) { - page_ref_unfreeze(page, 2); - goto cannot_free; - } - - if (PageSwapCache(page)) { - swp_entry_t swap = { .val = page_private(page) }; - mem_cgroup_swapout(page, swap); - __delete_from_swap_cache(page); - spin_unlock_irqrestore(&mapping->tree_lock, flags); - swapcache_free(swap); - } else { - void (*freepage)(struct page *); - void *shadow = NULL; - - freepage = mapping->a_ops->freepage; - /* - * Remember a shadow entry for reclaimed file cache in - * order to detect refaults, thus thrashing, later on. - * - * But don't store shadows in an address space that is - * already exiting. This is not just an optizimation, - * inode reclaim needs to empty out the radix tree or - * the nodes are lost. Don't plant shadows behind its - * back. - * - * We also don't store shadows for DAX mappings because the - * only page cache pages found in these are zero pages - * covering holes, and because we don't want to mix DAX - * exceptional entries and shadow exceptional entries in the - * same page_tree. - */ - if (reclaimed && page_is_file_cache(page) && - !mapping_exiting(mapping) && !dax_mapping(mapping)) - shadow = workingset_eviction(mapping, page); - __delete_from_page_cache(page, shadow); - spin_unlock_irqrestore(&mapping->tree_lock, flags); - - if (freepage != NULL) - freepage(page); - } - - return 1; - -cannot_free: - spin_unlock_irqrestore(&mapping->tree_lock, flags); - return 0; -} - -/* - * Attempt to detach a locked page from its ->mapping. If it is dirty or if - * someone else has a ref on the page, abort and return 0. If it was - * successfully detached, return 1. Assumes the caller has a single ref on - * this page. - */ -int remove_mapping(struct address_space *mapping, struct page *page) -{ - if (__remove_mapping(mapping, page, false)) { - /* - * Unfreezing the refcount with 1 rather than 2 effectively - * drops the pagecache ref for us without requiring another - * atomic operation. - */ - page_ref_unfreeze(page, 1); - return 1; - } - return 0; -} - -/** - * putback_lru_page - put previously isolated page onto appropriate LRU list - * @page: page to be put back to appropriate lru list - * - * Add previously isolated @page to appropriate LRU list. - * Page may still be unevictable for other reasons. - * - * lru_lock must not be held, interrupts must be enabled. - */ -void putback_lru_page(struct page *page) -{ - bool is_unevictable; - int was_unevictable = PageUnevictable(page); - - VM_BUG_ON_PAGE(PageLRU(page), page); - -redo: - ClearPageUnevictable(page); - - if (page_evictable(page)) { - /* - * For evictable pages, we can use the cache. - * In event of a race, worst case is we end up with an - * unevictable page on [in]active list. - * We know how to handle that. - */ - is_unevictable = false; - lru_cache_add(page); - } else { - /* - * Put unevictable pages directly on zone's unevictable - * list. - */ - is_unevictable = true; - add_page_to_unevictable_list(page); - /* - * When racing with an mlock or AS_UNEVICTABLE clearing - * (page is unlocked) make sure that if the other thread - * does not observe our setting of PG_lru and fails - * isolation/check_move_unevictable_pages, - * we see PG_mlocked/AS_UNEVICTABLE cleared below and move - * the page back to the evictable list. - * - * The other side is TestClearPageMlocked() or shmem_lock(). - */ - smp_mb(); - } - - /* - * page's status can change while we move it among lru. If an evictable - * page is on unevictable list, it never be freed. To avoid that, - * check after we added it to the list, again. - */ - if (is_unevictable && page_evictable(page)) { - if (!isolate_lru_page(page)) { - put_page(page); - goto redo; - } - /* This means someone else dropped this page from LRU - * So, it will be freed or putback to LRU again. There is - * nothing to do here. - */ - } - - if (was_unevictable && !is_unevictable) - count_vm_event(UNEVICTABLE_PGRESCUED); - else if (!was_unevictable && is_unevictable) - count_vm_event(UNEVICTABLE_PGCULLED); - - put_page(page); /* drop ref from isolate */ -} - -enum page_references { - PAGEREF_RECLAIM, - PAGEREF_RECLAIM_CLEAN, - PAGEREF_KEEP, - PAGEREF_ACTIVATE, -}; - -static enum page_references page_check_references(struct page *page, - struct scan_control *sc) -{ - int referenced_ptes, referenced_page; - unsigned long vm_flags; - - referenced_ptes = page_referenced(page, 1, sc->target_mem_cgroup, - &vm_flags); - referenced_page = TestClearPageReferenced(page); - - /* - * Mlock lost the isolation race with us. Let try_to_unmap() - * move the page to the unevictable list. - */ - if (vm_flags & VM_LOCKED) - return PAGEREF_RECLAIM; - - if (referenced_ptes) { - if (PageSwapBacked(page)) - return PAGEREF_ACTIVATE; - /* - * All mapped pages start out with page table - * references from the instantiating fault, so we need - * to look twice if a mapped file page is used more - * than once. - * - * Mark it and spare it for another trip around the - * inactive list. Another page table reference will - * lead to its activation. - * - * Note: the mark is set for activated pages as well - * so that recently deactivated but used pages are - * quickly recovered. - */ - SetPageReferenced(page); - - if (referenced_page || referenced_ptes > 1) - return PAGEREF_ACTIVATE; - - /* - * Activate file-backed executable pages after first usage. - */ - if (vm_flags & VM_EXEC) - return PAGEREF_ACTIVATE; - - return PAGEREF_KEEP; - } - - /* Reclaim if clean, defer dirty pages to writeback */ - if (referenced_page && !PageSwapBacked(page)) - return PAGEREF_RECLAIM_CLEAN; - - return PAGEREF_RECLAIM; -} - -/* Check if a page is dirty or under writeback */ -static void page_check_dirty_writeback(struct page *page, - bool *dirty, bool *writeback) -{ - struct address_space *mapping; - - /* - * Anonymous pages are not handled by flushers and must be written - * from reclaim context. Do not stall reclaim based on them - */ - if (!page_is_file_cache(page)) { - *dirty = false; - *writeback = false; - return; - } - - /* By default assume that the page flags are accurate */ - *dirty = PageDirty(page); - *writeback = PageWriteback(page); - - /* Verify dirty/writeback state if the filesystem supports it */ - if (!page_has_private(page)) - return; - - mapping = page_mapping(page); - if (mapping && mapping->a_ops->is_dirty_writeback) - mapping->a_ops->is_dirty_writeback(page, dirty, writeback); -} - -/* - * shrink_page_list() returns the number of reclaimed pages - */ -static unsigned long shrink_page_list(struct list_head *page_list, - struct pglist_data *pgdat, - struct scan_control *sc, - enum ttu_flags ttu_flags, - unsigned long *ret_nr_dirty, - unsigned long *ret_nr_unqueued_dirty, - unsigned long *ret_nr_congested, - unsigned long *ret_nr_writeback, - unsigned long *ret_nr_immediate, - bool force_reclaim) -{ - LIST_HEAD(ret_pages); - LIST_HEAD(free_pages); - int pgactivate = 0; - unsigned long nr_unqueued_dirty = 0; - unsigned long nr_dirty = 0; - unsigned long nr_congested = 0; - unsigned long nr_reclaimed = 0; - unsigned long nr_writeback = 0; - unsigned long nr_immediate = 0; - - cond_resched(); - - while (!list_empty(page_list)) { - struct address_space *mapping; - struct page *page; - int may_enter_fs; - enum page_references references = PAGEREF_RECLAIM_CLEAN; - bool dirty, writeback; - bool lazyfree = false; - int ret = SWAP_SUCCESS; - - cond_resched(); - - page = lru_to_page(page_list); - list_del(&page->lru); - - if (!trylock_page(page)) - goto keep; - - VM_BUG_ON_PAGE(PageActive(page), page); - - sc->nr_scanned++; - - if (unlikely(!page_evictable(page))) - goto cull_mlocked; - - if (!sc->may_unmap && page_mapped(page)) - goto keep_locked; - - /* Double the slab pressure for mapped and swapcache pages */ - if (page_mapped(page) || PageSwapCache(page)) - sc->nr_scanned++; - - may_enter_fs = (sc->gfp_mask & __GFP_FS) || - (PageSwapCache(page) && (sc->gfp_mask & __GFP_IO)); - - /* - * The number of dirty pages determines if a zone is marked - * reclaim_congested which affects wait_iff_congested. kswapd - * will stall and start writing pages if the tail of the LRU - * is all dirty unqueued pages. - */ - page_check_dirty_writeback(page, &dirty, &writeback); - if (dirty || writeback) - nr_dirty++; - - if (dirty && !writeback) - nr_unqueued_dirty++; - - /* - * Treat this page as congested if the underlying BDI is or if - * pages are cycling through the LRU so quickly that the - * pages marked for immediate reclaim are making it to the - * end of the LRU a second time. - */ - mapping = page_mapping(page); - if (((dirty || writeback) && mapping && - inode_write_congested(mapping->host)) || - (writeback && PageReclaim(page))) - nr_congested++; - - /* - * If a page at the tail of the LRU is under writeback, there - * are three cases to consider. - * - * 1) If reclaim is encountering an excessive number of pages - * under writeback and this page is both under writeback and - * PageReclaim then it indicates that pages are being queued - * for IO but are being recycled through the LRU before the - * IO can complete. Waiting on the page itself risks an - * indefinite stall if it is impossible to writeback the - * page due to IO error or disconnected storage so instead - * note that the LRU is being scanned too quickly and the - * caller can stall after page list has been processed. - * - * 2) Global or new memcg reclaim encounters a page that is - * not marked for immediate reclaim, or the caller does not - * have __GFP_FS (or __GFP_IO if it's simply going to swap, - * not to fs). In this case mark the page for immediate - * reclaim and continue scanning. - * - * Require may_enter_fs because we would wait on fs, which - * may not have submitted IO yet. And the loop driver might - * enter reclaim, and deadlock if it waits on a page for - * which it is needed to do the write (loop masks off - * __GFP_IO|__GFP_FS for this reason); but more thought - * would probably show more reasons. - * - * 3) Legacy memcg encounters a page that is already marked - * PageReclaim. memcg does not have any dirty pages - * throttling so we could easily OOM just because too many - * pages are in writeback and there is nothing else to - * reclaim. Wait for the writeback to complete. - */ - if (PageWriteback(page)) { - /* Case 1 above */ - if (current_is_kswapd() && - PageReclaim(page) && - test_bit(PGDAT_WRITEBACK, &pgdat->flags)) { - nr_immediate++; - goto keep_locked; - - /* Case 2 above */ - } else if (sane_reclaim(sc) || - !PageReclaim(page) || !may_enter_fs) { - /* - * This is slightly racy - end_page_writeback() - * might have just cleared PageReclaim, then - * setting PageReclaim here end up interpreted - * as PageReadahead - but that does not matter - * enough to care. What we do want is for this - * page to have PageReclaim set next time memcg - * reclaim reaches the tests above, so it will - * then wait_on_page_writeback() to avoid OOM; - * and it's also appropriate in global reclaim. - */ - SetPageReclaim(page); - nr_writeback++; - goto keep_locked; - - /* Case 3 above */ - } else { - unlock_page(page); - wait_on_page_writeback(page); - /* then go back and try same page again */ - list_add_tail(&page->lru, page_list); - continue; - } - } - - if (!force_reclaim) - references = page_check_references(page, sc); - - switch (references) { - case PAGEREF_ACTIVATE: - goto activate_locked; - case PAGEREF_KEEP: - goto keep_locked; - case PAGEREF_RECLAIM: - case PAGEREF_RECLAIM_CLEAN: - ; /* try to reclaim the page below */ - } - - /* - * Anonymous process memory has backing store? - * Try to allocate it some swap space here. - */ - if (PageAnon(page) && !PageSwapCache(page)) { - if (!(sc->gfp_mask & __GFP_IO)) - goto keep_locked; - if (!add_to_swap(page, page_list)) - goto activate_locked; - lazyfree = true; - may_enter_fs = 1; - - /* Adding to swap updated mapping */ - mapping = page_mapping(page); - } else if (unlikely(PageTransHuge(page))) { - /* Split file THP */ - if (split_huge_page_to_list(page, page_list)) - goto keep_locked; - } - - VM_BUG_ON_PAGE(PageTransHuge(page), page); - - /* - * The page is mapped into the page tables of one or more - * processes. Try to unmap it here. - */ - if (page_mapped(page) && mapping) { - switch (ret = try_to_unmap(page, lazyfree ? - (ttu_flags | TTU_BATCH_FLUSH | TTU_LZFREE) : - (ttu_flags | TTU_BATCH_FLUSH))) { - case SWAP_FAIL: - goto activate_locked; - case SWAP_AGAIN: - goto keep_locked; - case SWAP_MLOCK: - goto cull_mlocked; - case SWAP_LZFREE: - goto lazyfree; - case SWAP_SUCCESS: - ; /* try to free the page below */ - } - } - - if (PageDirty(page)) { - /* - * Only kswapd can writeback filesystem pages to - * avoid risk of stack overflow but only writeback - * if many dirty pages have been encountered. - */ - if (page_is_file_cache(page) && - (!current_is_kswapd() || - !test_bit(PGDAT_DIRTY, &pgdat->flags))) { - /* - * Immediately reclaim when written back. - * Similar in principal to deactivate_page() - * except we already have the page isolated - * and know it's dirty - */ - inc_node_page_state(page, NR_VMSCAN_IMMEDIATE); - SetPageReclaim(page); - - goto keep_locked; - } - - if (references == PAGEREF_RECLAIM_CLEAN) - goto keep_locked; - if (!may_enter_fs) - goto keep_locked; - if (!sc->may_writepage) - goto keep_locked; - - /* - * Page is dirty. Flush the TLB if a writable entry - * potentially exists to avoid CPU writes after IO - * starts and then write it out here. - */ - try_to_unmap_flush_dirty(); - switch (pageout(page, mapping, sc)) { - case PAGE_KEEP: - goto keep_locked; - case PAGE_ACTIVATE: - goto activate_locked; - case PAGE_SUCCESS: - if (PageWriteback(page)) - goto keep; - if (PageDirty(page)) - goto keep; - - /* - * A synchronous write - probably a ramdisk. Go - * ahead and try to reclaim the page. - */ - if (!trylock_page(page)) - goto keep; - if (PageDirty(page) || PageWriteback(page)) - goto keep_locked; - mapping = page_mapping(page); - case PAGE_CLEAN: - ; /* try to free the page below */ - } - } - - /* - * If the page has buffers, try to free the buffer mappings - * associated with this page. If we succeed we try to free - * the page as well. - * - * We do this even if the page is PageDirty(). - * try_to_release_page() does not perform I/O, but it is - * possible for a page to have PageDirty set, but it is actually - * clean (all its buffers are clean). This happens if the - * buffers were written out directly, with submit_bh(). ext3 - * will do this, as well as the blockdev mapping. - * try_to_release_page() will discover that cleanness and will - * drop the buffers and mark the page clean - it can be freed. - * - * Rarely, pages can have buffers and no ->mapping. These are - * the pages which were not successfully invalidated in - * truncate_complete_page(). We try to drop those buffers here - * and if that worked, and the page is no longer mapped into - * process address space (page_count == 1) it can be freed. - * Otherwise, leave the page on the LRU so it is swappable. - */ - if (page_has_private(page)) { - if (!try_to_release_page(page, sc->gfp_mask)) - goto activate_locked; - if (!mapping && page_count(page) == 1) { - unlock_page(page); - if (put_page_testzero(page)) - goto free_it; - else { - /* - * rare race with speculative reference. - * the speculative reference will free - * this page shortly, so we may - * increment nr_reclaimed here (and - * leave it off the LRU). - */ - nr_reclaimed++; - continue; - } - } - } - -lazyfree: - if (!mapping || !__remove_mapping(mapping, page, true)) - goto keep_locked; - - /* - * At this point, we have no other references and there is - * no way to pick any more up (removed from LRU, removed - * from pagecache). Can use non-atomic bitops now (and - * we obviously don't have to worry about waking up a process - * waiting on the page lock, because there are no references. - */ - __ClearPageLocked(page); -free_it: - if (ret == SWAP_LZFREE) - count_vm_event(PGLAZYFREED); - - nr_reclaimed++; - - /* - * Is there need to periodically free_page_list? It would - * appear not as the counts should be low - */ - list_add(&page->lru, &free_pages); - continue; - -cull_mlocked: - if (PageSwapCache(page)) - try_to_free_swap(page); - unlock_page(page); - list_add(&page->lru, &ret_pages); - continue; - -activate_locked: - /* Not a candidate for swapping, so reclaim swap space. */ - if (PageSwapCache(page) && mem_cgroup_swap_full(page)) - try_to_free_swap(page); - VM_BUG_ON_PAGE(PageActive(page), page); - SetPageActive(page); - pgactivate++; -keep_locked: - unlock_page(page); -keep: - list_add(&page->lru, &ret_pages); - VM_BUG_ON_PAGE(PageLRU(page) || PageUnevictable(page), page); - } - - mem_cgroup_uncharge_list(&free_pages); - try_to_unmap_flush(); - free_hot_cold_page_list(&free_pages, true); - - list_splice(&ret_pages, page_list); - count_vm_events(PGACTIVATE, pgactivate); - - *ret_nr_dirty += nr_dirty; - *ret_nr_congested += nr_congested; - *ret_nr_unqueued_dirty += nr_unqueued_dirty; - *ret_nr_writeback += nr_writeback; - *ret_nr_immediate += nr_immediate; - return nr_reclaimed; -} - -unsigned long reclaim_clean_pages_from_list(struct zone *zone, - struct list_head *page_list) -{ - struct scan_control sc = { - .gfp_mask = GFP_KERNEL, - .priority = DEF_PRIORITY, - .may_unmap = 1, - }; - unsigned long ret, dummy1, dummy2, dummy3, dummy4, dummy5; - struct page *page, *next; - LIST_HEAD(clean_pages); - - list_for_each_entry_safe(page, next, page_list, lru) { - if (page_is_file_cache(page) && !PageDirty(page) && - !__PageMovable(page)) { - ClearPageActive(page); - list_move(&page->lru, &clean_pages); - } - } - - ret = shrink_page_list(&clean_pages, zone->zone_pgdat, &sc, - TTU_UNMAP|TTU_IGNORE_ACCESS, - &dummy1, &dummy2, &dummy3, &dummy4, &dummy5, true); - list_splice(&clean_pages, page_list); - mod_node_page_state(zone->zone_pgdat, NR_ISOLATED_FILE, -ret); - return ret; -} - -/* - * Attempt to remove the specified page from its LRU. Only take this page - * if it is of the appropriate PageActive status. Pages which are being - * freed elsewhere are also ignored. - * - * page: page to consider - * mode: one of the LRU isolation modes defined above - * - * returns 0 on success, -ve errno on failure. - */ -int __isolate_lru_page(struct page *page, isolate_mode_t mode) -{ - int ret = -EINVAL; - - /* Only take pages on the LRU. */ - if (!PageLRU(page)) - return ret; - - /* Compaction should not handle unevictable pages but CMA can do so */ - if (PageUnevictable(page) && !(mode & ISOLATE_UNEVICTABLE)) - return ret; - - ret = -EBUSY; - - /* - * To minimise LRU disruption, the caller can indicate that it only - * wants to isolate pages it will be able to operate on without - * blocking - clean pages for the most part. - * - * ISOLATE_CLEAN means that only clean pages should be isolated. This - * is used by reclaim when it is cannot write to backing storage - * - * ISOLATE_ASYNC_MIGRATE is used to indicate that it only wants to pages - * that it is possible to migrate without blocking - */ - if (mode & (ISOLATE_CLEAN|ISOLATE_ASYNC_MIGRATE)) { - /* All the caller can do on PageWriteback is block */ - if (PageWriteback(page)) - return ret; - - if (PageDirty(page)) { - struct address_space *mapping; - - /* ISOLATE_CLEAN means only clean pages */ - if (mode & ISOLATE_CLEAN) - return ret; - - /* - * Only pages without mappings or that have a - * ->migratepage callback are possible to migrate - * without blocking - */ - mapping = page_mapping(page); - if (mapping && !mapping->a_ops->migratepage) - return ret; - } - } - - if ((mode & ISOLATE_UNMAPPED) && page_mapped(page)) - return ret; - - if (likely(get_page_unless_zero(page))) { - /* - * Be careful not to clear PageLRU until after we're - * sure the page is not being freed elsewhere -- the - * page release code relies on it. - */ - ClearPageLRU(page); - ret = 0; - } - - return ret; -} - - -/* - * Update LRU sizes after isolating pages. The LRU size updates must - * be complete before mem_cgroup_update_lru_size due to a santity check. - */ -static __always_inline void update_lru_sizes(struct lruvec *lruvec, - enum lru_list lru, unsigned long *nr_zone_taken, - unsigned long nr_taken) -{ - int zid; - - for (zid = 0; zid < MAX_NR_ZONES; zid++) { - if (!nr_zone_taken[zid]) - continue; - - __update_lru_size(lruvec, lru, zid, -nr_zone_taken[zid]); - } - -#ifdef CONFIG_MEMCG - mem_cgroup_update_lru_size(lruvec, lru, -nr_taken); -#endif -} - -/* - * zone_lru_lock is heavily contended. Some of the functions that - * shrink the lists perform better by taking out a batch of pages - * and working on them outside the LRU lock. - * - * For pagecache intensive workloads, this function is the hottest - * spot in the kernel (apart from copy_*_user functions). - * - * Appropriate locks must be held before calling this function. - * - * @nr_to_scan: The number of pages to look through on the list. - * @lruvec: The LRU vector to pull pages from. - * @dst: The temp list to put pages on to. - * @nr_scanned: The number of pages that were scanned. - * @sc: The scan_control struct for this reclaim session - * @mode: One of the LRU isolation modes - * @lru: LRU list id for isolating - * - * returns how many pages were moved onto *@dst. - */ -static unsigned long isolate_lru_pages(unsigned long nr_to_scan, - struct lruvec *lruvec, struct list_head *dst, - unsigned long *nr_scanned, struct scan_control *sc, - isolate_mode_t mode, enum lru_list lru) -{ - struct list_head *src = &lruvec->lists[lru]; - unsigned long nr_taken = 0; - unsigned long nr_zone_taken[MAX_NR_ZONES] = { 0 }; - unsigned long nr_skipped[MAX_NR_ZONES] = { 0, }; - unsigned long scan, nr_pages; - LIST_HEAD(pages_skipped); - - for (scan = 0; scan < nr_to_scan && nr_taken < nr_to_scan && - !list_empty(src);) { - struct page *page; - - page = lru_to_page(src); - prefetchw_prev_lru_page(page, src, flags); - - VM_BUG_ON_PAGE(!PageLRU(page), page); - - if (page_zonenum(page) > sc->reclaim_idx) { - list_move(&page->lru, &pages_skipped); - nr_skipped[page_zonenum(page)]++; - continue; - } - - /* - * Account for scanned and skipped separetly to avoid the pgdat - * being prematurely marked unreclaimable by pgdat_reclaimable. - */ - scan++; - - switch (__isolate_lru_page(page, mode)) { - case 0: - nr_pages = hpage_nr_pages(page); - nr_taken += nr_pages; - nr_zone_taken[page_zonenum(page)] += nr_pages; - list_move(&page->lru, dst); - break; - - case -EBUSY: - /* else it is being freed elsewhere */ - list_move(&page->lru, src); - continue; - - default: - BUG(); - } - } - - /* - * Splice any skipped pages to the start of the LRU list. Note that - * this disrupts the LRU order when reclaiming for lower zones but - * we cannot splice to the tail. If we did then the SWAP_CLUSTER_MAX - * scanning would soon rescan the same pages to skip and put the - * system at risk of premature OOM. - */ - if (!list_empty(&pages_skipped)) { - int zid; - unsigned long total_skipped = 0; - - for (zid = 0; zid < MAX_NR_ZONES; zid++) { - if (!nr_skipped[zid]) - continue; - - __count_zid_vm_events(PGSCAN_SKIP, zid, nr_skipped[zid]); - total_skipped += nr_skipped[zid]; - } - - /* - * Account skipped pages as a partial scan as the pgdat may be - * close to unreclaimable. If the LRU list is empty, account - * skipped pages as a full scan. - */ - scan += list_empty(src) ? total_skipped : total_skipped >> 2; - - list_splice(&pages_skipped, src); - } - *nr_scanned = scan; - trace_mm_vmscan_lru_isolate(sc->reclaim_idx, sc->order, nr_to_scan, scan, - nr_taken, mode, is_file_lru(lru)); - update_lru_sizes(lruvec, lru, nr_zone_taken, nr_taken); - return nr_taken; -} - -/** - * isolate_lru_page - tries to isolate a page from its LRU list - * @page: page to isolate from its LRU list - * - * Isolates a @page from an LRU list, clears PageLRU and adjusts the - * vmstat statistic corresponding to whatever LRU list the page was on. - * - * Returns 0 if the page was removed from an LRU list. - * Returns -EBUSY if the page was not on an LRU list. - * - * The returned page will have PageLRU() cleared. If it was found on - * the active list, it will have PageActive set. If it was found on - * the unevictable list, it will have the PageUnevictable bit set. That flag - * may need to be cleared by the caller before letting the page go. - * - * The vmstat statistic corresponding to the list on which the page was - * found will be decremented. - * - * Restrictions: - * (1) Must be called with an elevated refcount on the page. This is a - * fundamentnal difference from isolate_lru_pages (which is called - * without a stable reference). - * (2) the lru_lock must not be held. - * (3) interrupts must be enabled. - */ -int isolate_lru_page(struct page *page) -{ - int ret = -EBUSY; - - VM_BUG_ON_PAGE(!page_count(page), page); - WARN_RATELIMIT(PageTail(page), "trying to isolate tail page"); - - if (PageLRU(page)) { - struct zone *zone = page_zone(page); - struct lruvec *lruvec; - - spin_lock_irq(zone_lru_lock(zone)); - lruvec = mem_cgroup_page_lruvec(page, zone->zone_pgdat); - if (PageLRU(page)) { - int lru = page_lru(page); - get_page(page); - ClearPageLRU(page); - del_page_from_lru_list(page, lruvec, lru); - ret = 0; - } - spin_unlock_irq(zone_lru_lock(zone)); - } - return ret; -} - -/* - * A direct reclaimer may isolate SWAP_CLUSTER_MAX pages from the LRU list and - * then get resheduled. When there are massive number of tasks doing page - * allocation, such sleeping direct reclaimers may keep piling up on each CPU, - * the LRU list will go small and be scanned faster than necessary, leading to - * unnecessary swapping, thrashing and OOM. - */ -static int too_many_isolated(struct pglist_data *pgdat, int file, - struct scan_control *sc) -{ - unsigned long inactive, isolated; - - if (current_is_kswapd()) - return 0; - - if (!sane_reclaim(sc)) - return 0; - - if (file) { - inactive = node_page_state(pgdat, NR_INACTIVE_FILE); - isolated = node_page_state(pgdat, NR_ISOLATED_FILE); - } else { - inactive = node_page_state(pgdat, NR_INACTIVE_ANON); - isolated = node_page_state(pgdat, NR_ISOLATED_ANON); - } - - /* - * GFP_NOIO/GFP_NOFS callers are allowed to isolate more pages, so they - * won't get blocked by normal direct-reclaimers, forming a circular - * deadlock. - */ - if ((sc->gfp_mask & (__GFP_IO | __GFP_FS)) == (__GFP_IO | __GFP_FS)) - inactive >>= 3; - - return isolated > inactive; -} - -static noinline_for_stack void -putback_inactive_pages(struct lruvec *lruvec, struct list_head *page_list) -{ - struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat; - struct pglist_data *pgdat = lruvec_pgdat(lruvec); - LIST_HEAD(pages_to_free); - - /* - * Put back any unfreeable pages. - */ - while (!list_empty(page_list)) { - struct page *page = lru_to_page(page_list); - int lru; - - VM_BUG_ON_PAGE(PageLRU(page), page); - list_del(&page->lru); - if (unlikely(!page_evictable(page))) { - spin_unlock_irq(&pgdat->lru_lock); - putback_lru_page(page); - spin_lock_irq(&pgdat->lru_lock); - continue; - } - - lruvec = mem_cgroup_page_lruvec(page, pgdat); - - SetPageLRU(page); - lru = page_lru(page); - add_page_to_lru_list(page, lruvec, lru); - - if (is_active_lru(lru)) { - int file = is_file_lru(lru); - int numpages = hpage_nr_pages(page); - reclaim_stat->recent_rotated[file] += numpages; - } - if (put_page_testzero(page)) { - __ClearPageLRU(page); - __ClearPageActive(page); - del_page_from_lru_list(page, lruvec, lru); - - if (unlikely(PageCompound(page))) { - spin_unlock_irq(&pgdat->lru_lock); - mem_cgroup_uncharge(page); - (*get_compound_page_dtor(page))(page); - spin_lock_irq(&pgdat->lru_lock); - } else - list_add(&page->lru, &pages_to_free); - } - } - - /* - * To save our caller's stack, now use input list for pages to free. - */ - list_splice(&pages_to_free, page_list); -} - -/* - * If a kernel thread (such as nfsd for loop-back mounts) services - * a backing device by writing to the page cache it sets PF_LESS_THROTTLE. - * In that case we should only throttle if the backing device it is - * writing to is congested. In other cases it is safe to throttle. - */ -static int current_may_throttle(void) -{ - return !(current->flags & PF_LESS_THROTTLE) || - current->backing_dev_info == NULL || - bdi_write_congested(current->backing_dev_info); -} - -static bool inactive_reclaimable_pages(struct lruvec *lruvec, - struct scan_control *sc, enum lru_list lru) -{ - int zid; - struct zone *zone; - int file = is_file_lru(lru); - struct pglist_data *pgdat = lruvec_pgdat(lruvec); - - if (!global_reclaim(sc)) - return true; - - for (zid = sc->reclaim_idx; zid >= 0; zid--) { - zone = &pgdat->node_zones[zid]; - if (!managed_zone(zone)) - continue; - - if (zone_page_state_snapshot(zone, NR_ZONE_LRU_BASE + - LRU_FILE * file) >= SWAP_CLUSTER_MAX) - return true; - } - - return false; -} - -/* - * shrink_inactive_list() is a helper for shrink_node(). It returns the number - * of reclaimed pages - */ -static noinline_for_stack unsigned long -shrink_inactive_list(unsigned long nr_to_scan, struct lruvec *lruvec, - struct scan_control *sc, enum lru_list lru) -{ - LIST_HEAD(page_list); - unsigned long nr_scanned; - unsigned long nr_reclaimed = 0; - unsigned long nr_taken; - unsigned long nr_dirty = 0; - unsigned long nr_congested = 0; - unsigned long nr_unqueued_dirty = 0; - unsigned long nr_writeback = 0; - unsigned long nr_immediate = 0; - isolate_mode_t isolate_mode = 0; - int file = is_file_lru(lru); - struct pglist_data *pgdat = lruvec_pgdat(lruvec); - struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat; - - if (!inactive_reclaimable_pages(lruvec, sc, lru)) - return 0; - - while (unlikely(too_many_isolated(pgdat, file, sc))) { - congestion_wait(BLK_RW_ASYNC, HZ/10); - - /* We are about to die and free our memory. Return now. */ - if (fatal_signal_pending(current)) - return SWAP_CLUSTER_MAX; - } - - lru_add_drain(); - - if (!sc->may_unmap) - isolate_mode |= ISOLATE_UNMAPPED; - if (!sc->may_writepage) - isolate_mode |= ISOLATE_CLEAN; - - spin_lock_irq(&pgdat->lru_lock); - - nr_taken = isolate_lru_pages(nr_to_scan, lruvec, &page_list, - &nr_scanned, sc, isolate_mode, lru); - - __mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, nr_taken); - reclaim_stat->recent_scanned[file] += nr_taken; - - if (global_reclaim(sc)) { - __mod_node_page_state(pgdat, NR_PAGES_SCANNED, nr_scanned); - if (current_is_kswapd()) - __count_vm_events(PGSCAN_KSWAPD, nr_scanned); - else - __count_vm_events(PGSCAN_DIRECT, nr_scanned); - } - spin_unlock_irq(&pgdat->lru_lock); - - if (nr_taken == 0) - return 0; - - nr_reclaimed = shrink_page_list(&page_list, pgdat, sc, TTU_UNMAP, - &nr_dirty, &nr_unqueued_dirty, &nr_congested, - &nr_writeback, &nr_immediate, - false); - - spin_lock_irq(&pgdat->lru_lock); - - if (global_reclaim(sc)) { - if (current_is_kswapd()) - __count_vm_events(PGSTEAL_KSWAPD, nr_reclaimed); - else - __count_vm_events(PGSTEAL_DIRECT, nr_reclaimed); - } - - putback_inactive_pages(lruvec, &page_list); - - __mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, -nr_taken); - - spin_unlock_irq(&pgdat->lru_lock); - - mem_cgroup_uncharge_list(&page_list); - free_hot_cold_page_list(&page_list, true); - - /* - * If reclaim is isolating dirty pages under writeback, it implies - * that the long-lived page allocation rate is exceeding the page - * laundering rate. Either the global limits are not being effective - * at throttling processes due to the page distribution throughout - * zones or there is heavy usage of a slow backing device. The - * only option is to throttle from reclaim context which is not ideal - * as there is no guarantee the dirtying process is throttled in the - * same way balance_dirty_pages() manages. - * - * Once a zone is flagged ZONE_WRITEBACK, kswapd will count the number - * of pages under pages flagged for immediate reclaim and stall if any - * are encountered in the nr_immediate check below. - */ - if (nr_writeback && nr_writeback == nr_taken) - set_bit(PGDAT_WRITEBACK, &pgdat->flags); - - /* - * Legacy memcg will stall in page writeback so avoid forcibly - * stalling here. - */ - if (sane_reclaim(sc)) { - /* - * Tag a zone as congested if all the dirty pages scanned were - * backed by a congested BDI and wait_iff_congested will stall. - */ - if (nr_dirty && nr_dirty == nr_congested) - set_bit(PGDAT_CONGESTED, &pgdat->flags); - - /* - * If dirty pages are scanned that are not queued for IO, it - * implies that flushers are not keeping up. In this case, flag - * the pgdat PGDAT_DIRTY and kswapd will start writing pages from - * reclaim context. - */ - if (nr_unqueued_dirty == nr_taken) - set_bit(PGDAT_DIRTY, &pgdat->flags); - - /* - * If kswapd scans pages marked marked for immediate - * reclaim and under writeback (nr_immediate), it implies - * that pages are cycling through the LRU faster than - * they are written so also forcibly stall. - */ - if (nr_immediate && current_may_throttle()) - congestion_wait(BLK_RW_ASYNC, HZ/10); - } - - /* - * Stall direct reclaim for IO completions if underlying BDIs or zone - * is congested. Allow kswapd to continue until it starts encountering - * unqueued dirty pages or cycling through the LRU too quickly. - */ - if (!sc->hibernation_mode && !current_is_kswapd() && - current_may_throttle()) - wait_iff_congested(pgdat, BLK_RW_ASYNC, HZ/10); - - trace_mm_vmscan_lru_shrink_inactive(pgdat->node_id, - nr_scanned, nr_reclaimed, - sc->priority, file); - return nr_reclaimed; -} - -/* - * This moves pages from the active list to the inactive list. - * - * We move them the other way if the page is referenced by one or more - * processes, from rmap. - * - * If the pages are mostly unmapped, the processing is fast and it is - * appropriate to hold zone_lru_lock across the whole operation. But if - * the pages are mapped, the processing is slow (page_referenced()) so we - * should drop zone_lru_lock around each page. It's impossible to balance - * this, so instead we remove the pages from the LRU while processing them. - * It is safe to rely on PG_active against the non-LRU pages in here because - * nobody will play with that bit on a non-LRU page. - * - * The downside is that we have to touch page->_refcount against each page. - * But we had to alter page->flags anyway. - */ - -static void move_active_pages_to_lru(struct lruvec *lruvec, - struct list_head *list, - struct list_head *pages_to_free, - enum lru_list lru) -{ - struct pglist_data *pgdat = lruvec_pgdat(lruvec); - unsigned long pgmoved = 0; - struct page *page; - int nr_pages; - - while (!list_empty(list)) { - page = lru_to_page(list); - lruvec = mem_cgroup_page_lruvec(page, pgdat); - - VM_BUG_ON_PAGE(PageLRU(page), page); - SetPageLRU(page); - - nr_pages = hpage_nr_pages(page); - update_lru_size(lruvec, lru, page_zonenum(page), nr_pages); - list_move(&page->lru, &lruvec->lists[lru]); - pgmoved += nr_pages; - - if (put_page_testzero(page)) { - __ClearPageLRU(page); - __ClearPageActive(page); - del_page_from_lru_list(page, lruvec, lru); - - if (unlikely(PageCompound(page))) { - spin_unlock_irq(&pgdat->lru_lock); - mem_cgroup_uncharge(page); - (*get_compound_page_dtor(page))(page); - spin_lock_irq(&pgdat->lru_lock); - } else - list_add(&page->lru, pages_to_free); - } - } - - if (!is_active_lru(lru)) - __count_vm_events(PGDEACTIVATE, pgmoved); -} - -static void shrink_active_list(unsigned long nr_to_scan, - struct lruvec *lruvec, - struct scan_control *sc, - enum lru_list lru) -{ - unsigned long nr_taken; - unsigned long nr_scanned; - unsigned long vm_flags; - LIST_HEAD(l_hold); /* The pages which were snipped off */ - LIST_HEAD(l_active); - LIST_HEAD(l_inactive); - struct page *page; - struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat; - unsigned long nr_rotated = 0; - isolate_mode_t isolate_mode = 0; - int file = is_file_lru(lru); - struct pglist_data *pgdat = lruvec_pgdat(lruvec); - - lru_add_drain(); - - if (!sc->may_unmap) - isolate_mode |= ISOLATE_UNMAPPED; - if (!sc->may_writepage) - isolate_mode |= ISOLATE_CLEAN; - - spin_lock_irq(&pgdat->lru_lock); - - nr_taken = isolate_lru_pages(nr_to_scan, lruvec, &l_hold, - &nr_scanned, sc, isolate_mode, lru); - - __mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, nr_taken); - reclaim_stat->recent_scanned[file] += nr_taken; - - if (global_reclaim(sc)) - __mod_node_page_state(pgdat, NR_PAGES_SCANNED, nr_scanned); - __count_vm_events(PGREFILL, nr_scanned); - - spin_unlock_irq(&pgdat->lru_lock); - - while (!list_empty(&l_hold)) { - cond_resched(); - page = lru_to_page(&l_hold); - list_del(&page->lru); - - if (unlikely(!page_evictable(page))) { - putback_lru_page(page); - continue; - } - - if (unlikely(buffer_heads_over_limit)) { - if (page_has_private(page) && trylock_page(page)) { - if (page_has_private(page)) - try_to_release_page(page, 0); - unlock_page(page); - } - } - - if (page_referenced(page, 0, sc->target_mem_cgroup, - &vm_flags)) { - nr_rotated += hpage_nr_pages(page); - /* - * Identify referenced, file-backed active pages and - * give them one more trip around the active list. So - * that executable code get better chances to stay in - * memory under moderate memory pressure. Anon pages - * are not likely to be evicted by use-once streaming - * IO, plus JVM can create lots of anon VM_EXEC pages, - * so we ignore them here. - */ - if ((vm_flags & VM_EXEC) && page_is_file_cache(page)) { - list_add(&page->lru, &l_active); - continue; - } - } - - ClearPageActive(page); /* we are de-activating */ - list_add(&page->lru, &l_inactive); - } - - /* - * Move pages back to the lru list. - */ - spin_lock_irq(&pgdat->lru_lock); - /* - * Count referenced pages from currently used mappings as rotated, - * even though only some of them are actually re-activated. This - * helps balance scan pressure between file and anonymous pages in - * get_scan_count. - */ - reclaim_stat->recent_rotated[file] += nr_rotated; - - move_active_pages_to_lru(lruvec, &l_active, &l_hold, lru); - move_active_pages_to_lru(lruvec, &l_inactive, &l_hold, lru - LRU_ACTIVE); - __mod_node_page_state(pgdat, NR_ISOLATED_ANON + file, -nr_taken); - spin_unlock_irq(&pgdat->lru_lock); - - mem_cgroup_uncharge_list(&l_hold); - free_hot_cold_page_list(&l_hold, true); -} - -/* - * The inactive anon list should be small enough that the VM never has - * to do too much work. - * - * The inactive file list should be small enough to leave most memory - * to the established workingset on the scan-resistant active list, - * but large enough to avoid thrashing the aggregate readahead window. - * - * Both inactive lists should also be large enough that each inactive - * page has a chance to be referenced again before it is reclaimed. - * - * The inactive_ratio is the target ratio of ACTIVE to INACTIVE pages - * on this LRU, maintained by the pageout code. A zone->inactive_ratio - * of 3 means 3:1 or 25% of the pages are kept on the inactive list. - * - * total target max - * memory ratio inactive - * ------------------------------------- - * 10MB 1 5MB - * 100MB 1 50MB - * 1GB 3 250MB - * 10GB 10 0.9GB - * 100GB 31 3GB - * 1TB 101 10GB - * 10TB 320 32GB - */ -static bool inactive_list_is_low(struct lruvec *lruvec, bool file, - struct scan_control *sc) -{ - unsigned long inactive_ratio; - unsigned long inactive; - unsigned long active; - unsigned long gb; - struct pglist_data *pgdat = lruvec_pgdat(lruvec); - int zid; - - /* - * If we don't have swap space, anonymous page deactivation - * is pointless. - */ - if (!file && !total_swap_pages) - return false; - - inactive = lruvec_lru_size(lruvec, file * LRU_FILE); - active = lruvec_lru_size(lruvec, file * LRU_FILE + LRU_ACTIVE); - - /* - * For zone-constrained allocations, it is necessary to check if - * deactivations are required for lowmem to be reclaimed. This - * calculates the inactive/active pages available in eligible zones. - */ - for (zid = sc->reclaim_idx + 1; zid < MAX_NR_ZONES; zid++) { - struct zone *zone = &pgdat->node_zones[zid]; - unsigned long inactive_zone, active_zone; - - if (!managed_zone(zone)) - continue; - - inactive_zone = zone_page_state(zone, - NR_ZONE_LRU_BASE + (file * LRU_FILE)); - active_zone = zone_page_state(zone, - NR_ZONE_LRU_BASE + (file * LRU_FILE) + LRU_ACTIVE); - - inactive -= min(inactive, inactive_zone); - active -= min(active, active_zone); - } - - gb = (inactive + active) >> (30 - PAGE_SHIFT); - if (gb) - inactive_ratio = int_sqrt(10 * gb); - else - inactive_ratio = 1; - - return inactive * inactive_ratio < active; -} - -static unsigned long shrink_list(enum lru_list lru, unsigned long nr_to_scan, - struct lruvec *lruvec, struct scan_control *sc) -{ - if (is_active_lru(lru)) { - if (inactive_list_is_low(lruvec, is_file_lru(lru), sc)) - shrink_active_list(nr_to_scan, lruvec, sc, lru); - return 0; - } - - return shrink_inactive_list(nr_to_scan, lruvec, sc, lru); -} - -enum scan_balance { - SCAN_EQUAL, - SCAN_FRACT, - SCAN_ANON, - SCAN_FILE, -}; - -/* - * Determine how aggressively the anon and file LRU lists should be - * scanned. The relative value of each set of LRU lists is determined - * by looking at the fraction of the pages scanned we did rotate back - * onto the active list instead of evict. - * - * nr[0] = anon inactive pages to scan; nr[1] = anon active pages to scan - * nr[2] = file inactive pages to scan; nr[3] = file active pages to scan - */ -static void get_scan_count(struct lruvec *lruvec, struct mem_cgroup *memcg, - struct scan_control *sc, unsigned long *nr, - unsigned long *lru_pages) -{ - int swappiness = mem_cgroup_swappiness(memcg); - struct zone_reclaim_stat *reclaim_stat = &lruvec->reclaim_stat; - u64 fraction[2]; - u64 denominator = 0; /* gcc */ - struct pglist_data *pgdat = lruvec_pgdat(lruvec); - unsigned long anon_prio, file_prio; - enum scan_balance scan_balance; - unsigned long anon, file; - bool force_scan = false; - unsigned long ap, fp; - enum lru_list lru; - bool some_scanned; - int pass; - - /* - * If the zone or memcg is small, nr[l] can be 0. This - * results in no scanning on this priority and a potential - * priority drop. Global direct reclaim can go to the next - * zone and tends to have no problems. Global kswapd is for - * zone balancing and it needs to scan a minimum amount. When - * reclaiming for a memcg, a priority drop can cause high - * latencies, so it's better to scan a minimum amount there as - * well. - */ - if (current_is_kswapd()) { - if (!pgdat_reclaimable(pgdat)) - force_scan = true; - if (!mem_cgroup_online(memcg)) - force_scan = true; - } - if (!global_reclaim(sc)) - force_scan = true; - - /* If we have no swap space, do not bother scanning anon pages. */ - if (!sc->may_swap || mem_cgroup_get_nr_swap_pages(memcg) <= 0) { - scan_balance = SCAN_FILE; - goto out; - } - - /* - * Global reclaim will swap to prevent OOM even with no - * swappiness, but memcg users want to use this knob to - * disable swapping for individual groups completely when - * using the memory controller's swap limit feature would be - * too expensive. - */ - if (!global_reclaim(sc) && !swappiness) { - scan_balance = SCAN_FILE; - goto out; - } - - /* - * Do not apply any pressure balancing cleverness when the - * system is close to OOM, scan both anon and file equally - * (unless the swappiness setting disagrees with swapping). - */ - if (!sc->priority && swappiness) { - scan_balance = SCAN_EQUAL; - goto out; - } - - /* - * Prevent the reclaimer from falling into the cache trap: as - * cache pages start out inactive, every cache fault will tip - * the scan balance towards the file LRU. And as the file LRU - * shrinks, so does the window for rotation from references. - * This means we have a runaway feedback loop where a tiny - * thrashing file LRU becomes infinitely more attractive than - * anon pages. Try to detect this based on file LRU size. - */ - if (global_reclaim(sc)) { - unsigned long pgdatfile; - unsigned long pgdatfree; - int z; - unsigned long total_high_wmark = 0; - - pgdatfree = sum_zone_node_page_state(pgdat->node_id, NR_FREE_PAGES); - pgdatfile = node_page_state(pgdat, NR_ACTIVE_FILE) + - node_page_state(pgdat, NR_INACTIVE_FILE); - - for (z = 0; z < MAX_NR_ZONES; z++) { - struct zone *zone = &pgdat->node_zones[z]; - if (!managed_zone(zone)) - continue; - - total_high_wmark += high_wmark_pages(zone); - } - - if (unlikely(pgdatfile + pgdatfree <= total_high_wmark)) { - scan_balance = SCAN_ANON; - goto out; - } - } - - /* - * If there is enough inactive page cache, i.e. if the size of the - * inactive list is greater than that of the active list *and* the - * inactive list actually has some pages to scan on this priority, we - * do not reclaim anything from the anonymous working set right now. - * Without the second condition we could end up never scanning an - * lruvec even if it has plenty of old anonymous pages unless the - * system is under heavy pressure. - */ - if (!inactive_list_is_low(lruvec, true, sc) && - lruvec_lru_size(lruvec, LRU_INACTIVE_FILE) >> sc->priority) { - scan_balance = SCAN_FILE; - goto out; - } - - scan_balance = SCAN_FRACT; - - /* - * With swappiness at 100, anonymous and file have the same priority. - * This scanning priority is essentially the inverse of IO cost. - */ - anon_prio = swappiness; - file_prio = 200 - anon_prio; - - /* - * OK, so we have swap space and a fair amount of page cache - * pages. We use the recently rotated / recently scanned - * ratios to determine how valuable each cache is. - * - * Because workloads change over time (and to avoid overflow) - * we keep these statistics as a floating average, which ends - * up weighing recent references more than old ones. - * - * anon in [0], file in [1] - */ - - anon = lruvec_lru_size(lruvec, LRU_ACTIVE_ANON) + - lruvec_lru_size(lruvec, LRU_INACTIVE_ANON); - file = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE) + - lruvec_lru_size(lruvec, LRU_INACTIVE_FILE); - - spin_lock_irq(&pgdat->lru_lock); - if (unlikely(reclaim_stat->recent_scanned[0] > anon / 4)) { - reclaim_stat->recent_scanned[0] /= 2; - reclaim_stat->recent_rotated[0] /= 2; - } - - if (unlikely(reclaim_stat->recent_scanned[1] > file / 4)) { - reclaim_stat->recent_scanned[1] /= 2; - reclaim_stat->recent_rotated[1] /= 2; - } - - /* - * The amount of pressure on anon vs file pages is inversely - * proportional to the fraction of recently scanned pages on - * each list that were recently referenced and in active use. - */ - ap = anon_prio * (reclaim_stat->recent_scanned[0] + 1); - ap /= reclaim_stat->recent_rotated[0] + 1; - - fp = file_prio * (reclaim_stat->recent_scanned[1] + 1); - fp /= reclaim_stat->recent_rotated[1] + 1; - spin_unlock_irq(&pgdat->lru_lock); - - fraction[0] = ap; - fraction[1] = fp; - denominator = ap + fp + 1; -out: - some_scanned = false; - /* Only use force_scan on second pass. */ - for (pass = 0; !some_scanned && pass < 2; pass++) { - *lru_pages = 0; - for_each_evictable_lru(lru) { - int file = is_file_lru(lru); - unsigned long size; - unsigned long scan; - - size = lruvec_lru_size(lruvec, lru); - scan = size >> sc->priority; - - if (!scan && pass && force_scan) - scan = min(size, SWAP_CLUSTER_MAX); - - switch (scan_balance) { - case SCAN_EQUAL: - /* Scan lists relative to size */ - break; - case SCAN_FRACT: - /* - * Scan types proportional to swappiness and - * their relative recent reclaim efficiency. - */ - scan = div64_u64(scan * fraction[file], - denominator); - break; - case SCAN_FILE: - case SCAN_ANON: - /* Scan one type exclusively */ - if ((scan_balance == SCAN_FILE) != file) { - size = 0; - scan = 0; - } - break; - default: - /* Look ma, no brain */ - BUG(); - } - - *lru_pages += size; - nr[lru] = scan; - - /* - * Skip the second pass and don't force_scan, - * if we found something to scan. - */ - some_scanned |= !!scan; - } - } -} - -/* - * This is a basic per-node page freer. Used by both kswapd and direct reclaim. - */ -static void shrink_node_memcg(struct pglist_data *pgdat, struct mem_cgroup *memcg, - struct scan_control *sc, unsigned long *lru_pages) -{ - struct lruvec *lruvec = mem_cgroup_lruvec(pgdat, memcg); - unsigned long nr[NR_LRU_LISTS]; - unsigned long targets[NR_LRU_LISTS]; - unsigned long nr_to_scan; - enum lru_list lru; - unsigned long nr_reclaimed = 0; - unsigned long nr_to_reclaim = sc->nr_to_reclaim; - struct blk_plug plug; - bool scan_adjusted; - - get_scan_count(lruvec, memcg, sc, nr, lru_pages); - - /* Record the original scan target for proportional adjustments later */ - memcpy(targets, nr, sizeof(nr)); - - /* - * Global reclaiming within direct reclaim at DEF_PRIORITY is a normal - * event that can occur when there is little memory pressure e.g. - * multiple streaming readers/writers. Hence, we do not abort scanning - * when the requested number of pages are reclaimed when scanning at - * DEF_PRIORITY on the assumption that the fact we are direct - * reclaiming implies that kswapd is not keeping up and it is best to - * do a batch of work at once. For memcg reclaim one check is made to - * abort proportional reclaim if either the file or anon lru has already - * dropped to zero at the first pass. - */ - scan_adjusted = (global_reclaim(sc) && !current_is_kswapd() && - sc->priority == DEF_PRIORITY); - - blk_start_plug(&plug); - while (nr[LRU_INACTIVE_ANON] || nr[LRU_ACTIVE_FILE] || - nr[LRU_INACTIVE_FILE]) { - unsigned long nr_anon, nr_file, percentage; - unsigned long nr_scanned; - - for_each_evictable_lru(lru) { - if (nr[lru]) { - nr_to_scan = min(nr[lru], SWAP_CLUSTER_MAX); - nr[lru] -= nr_to_scan; - - nr_reclaimed += shrink_list(lru, nr_to_scan, - lruvec, sc); - } - } - - cond_resched(); - - if (nr_reclaimed < nr_to_reclaim || scan_adjusted) - continue; - - /* - * For kswapd and memcg, reclaim at least the number of pages - * requested. Ensure that the anon and file LRUs are scanned - * proportionally what was requested by get_scan_count(). We - * stop reclaiming one LRU and reduce the amount scanning - * proportional to the original scan target. - */ - nr_file = nr[LRU_INACTIVE_FILE] + nr[LRU_ACTIVE_FILE]; - nr_anon = nr[LRU_INACTIVE_ANON] + nr[LRU_ACTIVE_ANON]; - - /* - * It's just vindictive to attack the larger once the smaller - * has gone to zero. And given the way we stop scanning the - * smaller below, this makes sure that we only make one nudge - * towards proportionality once we've got nr_to_reclaim. - */ - if (!nr_file || !nr_anon) - break; - - if (nr_file > nr_anon) { - unsigned long scan_target = targets[LRU_INACTIVE_ANON] + - targets[LRU_ACTIVE_ANON] + 1; - lru = LRU_BASE; - percentage = nr_anon * 100 / scan_target; - } else { - unsigned long scan_target = targets[LRU_INACTIVE_FILE] + - targets[LRU_ACTIVE_FILE] + 1; - lru = LRU_FILE; - percentage = nr_file * 100 / scan_target; - } - - /* Stop scanning the smaller of the LRU */ - nr[lru] = 0; - nr[lru + LRU_ACTIVE] = 0; - - /* - * Recalculate the other LRU scan count based on its original - * scan target and the percentage scanning already complete - */ - lru = (lru == LRU_FILE) ? LRU_BASE : LRU_FILE; - nr_scanned = targets[lru] - nr[lru]; - nr[lru] = targets[lru] * (100 - percentage) / 100; - nr[lru] -= min(nr[lru], nr_scanned); - - lru += LRU_ACTIVE; - nr_scanned = targets[lru] - nr[lru]; - nr[lru] = targets[lru] * (100 - percentage) / 100; - nr[lru] -= min(nr[lru], nr_scanned); - - scan_adjusted = true; - } - blk_finish_plug(&plug); - sc->nr_reclaimed += nr_reclaimed; - - /* - * Even if we did not try to evict anon pages at all, we want to - * rebalance the anon lru active/inactive ratio. - */ - if (inactive_list_is_low(lruvec, false, sc)) - shrink_active_list(SWAP_CLUSTER_MAX, lruvec, - sc, LRU_ACTIVE_ANON); -} - -/* Use reclaim/compaction for costly allocs or under memory pressure */ -static bool in_reclaim_compaction(struct scan_control *sc) -{ - if (IS_ENABLED(CONFIG_COMPACTION) && sc->order && - (sc->order > PAGE_ALLOC_COSTLY_ORDER || - sc->priority < DEF_PRIORITY - 2)) - return true; - - return false; -} - -/* - * Reclaim/compaction is used for high-order allocation requests. It reclaims - * order-0 pages before compacting the zone. should_continue_reclaim() returns - * true if more pages should be reclaimed such that when the page allocator - * calls try_to_compact_zone() that it will have enough free pages to succeed. - * It will give up earlier than that if there is difficulty reclaiming pages. - */ -static inline bool should_continue_reclaim(struct pglist_data *pgdat, - unsigned long nr_reclaimed, - unsigned long nr_scanned, - struct scan_control *sc) -{ - unsigned long pages_for_compaction; - unsigned long inactive_lru_pages; - int z; - - /* If not in reclaim/compaction mode, stop */ - if (!in_reclaim_compaction(sc)) - return false; - - /* Consider stopping depending on scan and reclaim activity */ - if (sc->gfp_mask & __GFP_REPEAT) { - /* - * For __GFP_REPEAT allocations, stop reclaiming if the - * full LRU list has been scanned and we are still failing - * to reclaim pages. This full LRU scan is potentially - * expensive but a __GFP_REPEAT caller really wants to succeed - */ - if (!nr_reclaimed && !nr_scanned) - return false; - } else { - /* - * For non-__GFP_REPEAT allocations which can presumably - * fail without consequence, stop if we failed to reclaim - * any pages from the last SWAP_CLUSTER_MAX number of - * pages that were scanned. This will return to the - * caller faster at the risk reclaim/compaction and - * the resulting allocation attempt fails - */ - if (!nr_reclaimed) - return false; - } - - /* - * If we have not reclaimed enough pages for compaction and the - * inactive lists are large enough, continue reclaiming - */ - pages_for_compaction = compact_gap(sc->order); - inactive_lru_pages = node_page_state(pgdat, NR_INACTIVE_FILE); - if (get_nr_swap_pages() > 0) - inactive_lru_pages += node_page_state(pgdat, NR_INACTIVE_ANON); - if (sc->nr_reclaimed < pages_for_compaction && - inactive_lru_pages > pages_for_compaction) - return true; - - /* If compaction would go ahead or the allocation would succeed, stop */ - for (z = 0; z <= sc->reclaim_idx; z++) { - struct zone *zone = &pgdat->node_zones[z]; - if (!managed_zone(zone)) - continue; - - switch (compaction_suitable(zone, sc->order, 0, sc->reclaim_idx)) { - case COMPACT_SUCCESS: - case COMPACT_CONTINUE: - return false; - default: - /* check next zone */ - ; - } - } - return true; -} - -static bool shrink_node(pg_data_t *pgdat, struct scan_control *sc) -{ - struct reclaim_state *reclaim_state = current->reclaim_state; - unsigned long nr_reclaimed, nr_scanned; - bool reclaimable = false; - - do { - struct mem_cgroup *root = sc->target_mem_cgroup; - struct mem_cgroup_reclaim_cookie reclaim = { - .pgdat = pgdat, - .priority = sc->priority, - }; - unsigned long node_lru_pages = 0; - struct mem_cgroup *memcg; - - nr_reclaimed = sc->nr_reclaimed; - nr_scanned = sc->nr_scanned; - - memcg = mem_cgroup_iter(root, NULL, &reclaim); - do { - unsigned long lru_pages; - unsigned long reclaimed; - unsigned long scanned; - - if (mem_cgroup_low(root, memcg)) { - if (!sc->may_thrash) - continue; - mem_cgroup_events(memcg, MEMCG_LOW, 1); - } - - reclaimed = sc->nr_reclaimed; - scanned = sc->nr_scanned; - - shrink_node_memcg(pgdat, memcg, sc, &lru_pages); - node_lru_pages += lru_pages; - - if (memcg) - shrink_slab(sc->gfp_mask, pgdat->node_id, - memcg, sc->nr_scanned - scanned, - lru_pages); - - /* Record the group's reclaim efficiency */ - vmpressure(sc->gfp_mask, memcg, false, - sc->nr_scanned - scanned, - sc->nr_reclaimed - reclaimed); - - /* - * Direct reclaim and kswapd have to scan all memory - * cgroups to fulfill the overall scan target for the - * node. - * - * Limit reclaim, on the other hand, only cares about - * nr_to_reclaim pages to be reclaimed and it will - * retry with decreasing priority if one round over the - * whole hierarchy is not sufficient. - */ - if (!global_reclaim(sc) && - sc->nr_reclaimed >= sc->nr_to_reclaim) { - mem_cgroup_iter_break(root, memcg); - break; - } - } while ((memcg = mem_cgroup_iter(root, memcg, &reclaim))); - - /* - * Shrink the slab caches in the same proportion that - * the eligible LRU pages were scanned. - */ - if (global_reclaim(sc)) - shrink_slab(sc->gfp_mask, pgdat->node_id, NULL, - sc->nr_scanned - nr_scanned, - node_lru_pages); - - if (reclaim_state) { - sc->nr_reclaimed += reclaim_state->reclaimed_slab; - reclaim_state->reclaimed_slab = 0; - } - - /* Record the subtree's reclaim efficiency */ - vmpressure(sc->gfp_mask, sc->target_mem_cgroup, true, - sc->nr_scanned - nr_scanned, - sc->nr_reclaimed - nr_reclaimed); - - if (sc->nr_reclaimed - nr_reclaimed) - reclaimable = true; - - } while (should_continue_reclaim(pgdat, sc->nr_reclaimed - nr_reclaimed, - sc->nr_scanned - nr_scanned, sc)); - - return reclaimable; -} - -/* - * Returns true if compaction should go ahead for a costly-order request, or - * the allocation would already succeed without compaction. Return false if we - * should reclaim first. - */ -static inline bool compaction_ready(struct zone *zone, struct scan_control *sc) -{ - unsigned long watermark; - enum compact_result suitable; - - suitable = compaction_suitable(zone, sc->order, 0, sc->reclaim_idx); - if (suitable == COMPACT_SUCCESS) - /* Allocation should succeed already. Don't reclaim. */ - return true; - if (suitable == COMPACT_SKIPPED) - /* Compaction cannot yet proceed. Do reclaim. */ - return false; - - /* - * Compaction is already possible, but it takes time to run and there - * are potentially other callers using the pages just freed. So proceed - * with reclaim to make a buffer of free pages available to give - * compaction a reasonable chance of completing and allocating the page. - * Note that we won't actually reclaim the whole buffer in one attempt - * as the target watermark in should_continue_reclaim() is lower. But if - * we are already above the high+gap watermark, don't reclaim at all. - */ - watermark = high_wmark_pages(zone) + compact_gap(sc->order); - - return zone_watermark_ok_safe(zone, 0, watermark, sc->reclaim_idx); -} - -/* - * This is the direct reclaim path, for page-allocating processes. We only - * try to reclaim pages from zones which will satisfy the caller's allocation - * request. - * - * If a zone is deemed to be full of pinned pages then just give it a light - * scan then give up on it. - */ -static void shrink_zones(struct zonelist *zonelist, struct scan_control *sc) -{ - struct zoneref *z; - struct zone *zone; - unsigned long nr_soft_reclaimed; - unsigned long nr_soft_scanned; - gfp_t orig_mask; - pg_data_t *last_pgdat = NULL; - - /* - * If the number of buffer_heads in the machine exceeds the maximum - * allowed level, force direct reclaim to scan the highmem zone as - * highmem pages could be pinning lowmem pages storing buffer_heads - */ - orig_mask = sc->gfp_mask; - if (buffer_heads_over_limit) { - sc->gfp_mask |= __GFP_HIGHMEM; - sc->reclaim_idx = gfp_zone(sc->gfp_mask); - } - - for_each_zone_zonelist_nodemask(zone, z, zonelist, - sc->reclaim_idx, sc->nodemask) { - /* - * Take care memory controller reclaiming has small influence - * to global LRU. - */ - if (global_reclaim(sc)) { - if (!cpuset_zone_allowed(zone, - GFP_KERNEL | __GFP_HARDWALL)) - continue; - - if (sc->priority != DEF_PRIORITY && - !pgdat_reclaimable(zone->zone_pgdat)) - continue; /* Let kswapd poll it */ - - /* - * If we already have plenty of memory free for - * compaction in this zone, don't free any more. - * Even though compaction is invoked for any - * non-zero order, only frequent costly order - * reclamation is disruptive enough to become a - * noticeable problem, like transparent huge - * page allocations. - */ - if (IS_ENABLED(CONFIG_COMPACTION) && - sc->order > PAGE_ALLOC_COSTLY_ORDER && - compaction_ready(zone, sc)) { - sc->compaction_ready = true; - continue; - } - - /* - * Shrink each node in the zonelist once. If the - * zonelist is ordered by zone (not the default) then a - * node may be shrunk multiple times but in that case - * the user prefers lower zones being preserved. - */ - if (zone->zone_pgdat == last_pgdat) - continue; - - /* - * This steals pages from memory cgroups over softlimit - * and returns the number of reclaimed pages and - * scanned pages. This works for global memory pressure - * and balancing, not for a memcg's limit. - */ - nr_soft_scanned = 0; - nr_soft_reclaimed = mem_cgroup_soft_limit_reclaim(zone->zone_pgdat, - sc->order, sc->gfp_mask, - &nr_soft_scanned); - sc->nr_reclaimed += nr_soft_reclaimed; - sc->nr_scanned += nr_soft_scanned; - /* need some check for avoid more shrink_zone() */ - } - - /* See comment about same check for global reclaim above */ - if (zone->zone_pgdat == last_pgdat) - continue; - last_pgdat = zone->zone_pgdat; - shrink_node(zone->zone_pgdat, sc); - } - - /* - * Restore to original mask to avoid the impact on the caller if we - * promoted it to __GFP_HIGHMEM. - */ - sc->gfp_mask = orig_mask; -} - -/* - * This is the main entry point to direct page reclaim. - * - * If a full scan of the inactive list fails to free enough memory then we - * are "out of memory" and something needs to be killed. - * - * If the caller is !__GFP_FS then the probability of a failure is reasonably - * high - the zone may be full of dirty or under-writeback pages, which this - * caller can't do much about. We kick the writeback threads and take explicit - * naps in the hope that some of these pages can be written. But if the - * allocating task holds filesystem locks which prevent writeout this might not - * work, and the allocation attempt will fail. - * - * returns: 0, if no pages reclaimed - * else, the number of pages reclaimed - */ -static unsigned long do_try_to_free_pages(struct zonelist *zonelist, - struct scan_control *sc) -{ - int initial_priority = sc->priority; - unsigned long total_scanned = 0; - unsigned long writeback_threshold; -retry: - delayacct_freepages_start(); - - if (global_reclaim(sc)) - __count_zid_vm_events(ALLOCSTALL, sc->reclaim_idx, 1); - - do { - vmpressure_prio(sc->gfp_mask, sc->target_mem_cgroup, - sc->priority); - sc->nr_scanned = 0; - shrink_zones(zonelist, sc); - - total_scanned += sc->nr_scanned; - if (sc->nr_reclaimed >= sc->nr_to_reclaim) - break; - - if (sc->compaction_ready) - break; - - /* - * If we're getting trouble reclaiming, start doing - * writepage even in laptop mode. - */ - if (sc->priority < DEF_PRIORITY - 2) - sc->may_writepage = 1; - - /* - * Try to write back as many pages as we just scanned. This - * tends to cause slow streaming writers to write data to the - * disk smoothly, at the dirtying rate, which is nice. But - * that's undesirable in laptop mode, where we *want* lumpy - * writeout. So in laptop mode, write out the whole world. - */ - writeback_threshold = sc->nr_to_reclaim + sc->nr_to_reclaim / 2; - if (total_scanned > writeback_threshold) { - wakeup_flusher_threads(laptop_mode ? 0 : total_scanned, - WB_REASON_TRY_TO_FREE_PAGES); - sc->may_writepage = 1; - } - } while (--sc->priority >= 0); - - delayacct_freepages_end(); - - if (sc->nr_reclaimed) - return sc->nr_reclaimed; - - /* Aborted reclaim to try compaction? don't OOM, then */ - if (sc->compaction_ready) - return 1; - - /* Untapped cgroup reserves? Don't OOM, retry. */ - if (!sc->may_thrash) { - sc->priority = initial_priority; - sc->may_thrash = 1; - goto retry; - } - - return 0; -} - -static bool pfmemalloc_watermark_ok(pg_data_t *pgdat) -{ - struct zone *zone; - unsigned long pfmemalloc_reserve = 0; - unsigned long free_pages = 0; - int i; - bool wmark_ok; - - for (i = 0; i <= ZONE_NORMAL; i++) { - zone = &pgdat->node_zones[i]; - if (!managed_zone(zone) || - pgdat_reclaimable_pages(pgdat) == 0) - continue; - - pfmemalloc_reserve += min_wmark_pages(zone); - free_pages += zone_page_state(zone, NR_FREE_PAGES); - } - - /* If there are no reserves (unexpected config) then do not throttle */ - if (!pfmemalloc_reserve) - return true; - - wmark_ok = free_pages > pfmemalloc_reserve / 2; - - /* kswapd must be awake if processes are being throttled */ - if (!wmark_ok && waitqueue_active(&pgdat->kswapd_wait)) { - pgdat->kswapd_classzone_idx = min(pgdat->kswapd_classzone_idx, - (enum zone_type)ZONE_NORMAL); - wake_up_interruptible(&pgdat->kswapd_wait); - } - - return wmark_ok; -} - -/* - * Throttle direct reclaimers if backing storage is backed by the network - * and the PFMEMALLOC reserve for the preferred node is getting dangerously - * depleted. kswapd will continue to make progress and wake the processes - * when the low watermark is reached. - * - * Returns true if a fatal signal was delivered during throttling. If this - * happens, the page allocator should not consider triggering the OOM killer. - */ -static bool throttle_direct_reclaim(gfp_t gfp_mask, struct zonelist *zonelist, - nodemask_t *nodemask) -{ - struct zoneref *z; - struct zone *zone; - pg_data_t *pgdat = NULL; - - /* - * Kernel threads should not be throttled as they may be indirectly - * responsible for cleaning pages necessary for reclaim to make forward - * progress. kjournald for example may enter direct reclaim while - * committing a transaction where throttling it could forcing other - * processes to block on log_wait_commit(). - */ - if (current->flags & PF_KTHREAD) - goto out; - - /* - * If a fatal signal is pending, this process should not throttle. - * It should return quickly so it can exit and free its memory - */ - if (fatal_signal_pending(current)) - goto out; - - /* - * Check if the pfmemalloc reserves are ok by finding the first node - * with a usable ZONE_NORMAL or lower zone. The expectation is that - * GFP_KERNEL will be required for allocating network buffers when - * swapping over the network so ZONE_HIGHMEM is unusable. - * - * Throttling is based on the first usable node and throttled processes - * wait on a queue until kswapd makes progress and wakes them. There - * is an affinity then between processes waking up and where reclaim - * progress has been made assuming the process wakes on the same node. - * More importantly, processes running on remote nodes will not compete - * for remote pfmemalloc reserves and processes on different nodes - * should make reasonable progress. - */ - for_each_zone_zonelist_nodemask(zone, z, zonelist, - gfp_zone(gfp_mask), nodemask) { - if (zone_idx(zone) > ZONE_NORMAL) - continue; - - /* Throttle based on the first usable node */ - pgdat = zone->zone_pgdat; - if (pfmemalloc_watermark_ok(pgdat)) - goto out; - break; - } - - /* If no zone was usable by the allocation flags then do not throttle */ - if (!pgdat) - goto out; - - /* Account for the throttling */ - count_vm_event(PGSCAN_DIRECT_THROTTLE); - - /* - * If the caller cannot enter the filesystem, it's possible that it - * is due to the caller holding an FS lock or performing a journal - * transaction in the case of a filesystem like ext[3|4]. In this case, - * it is not safe to block on pfmemalloc_wait as kswapd could be - * blocked waiting on the same lock. Instead, throttle for up to a - * second before continuing. - */ - if (!(gfp_mask & __GFP_FS)) { - wait_event_interruptible_timeout(pgdat->pfmemalloc_wait, - pfmemalloc_watermark_ok(pgdat), HZ); - - goto check_pending; - } - - /* Throttle until kswapd wakes the process */ - wait_event_killable(zone->zone_pgdat->pfmemalloc_wait, - pfmemalloc_watermark_ok(pgdat)); - -check_pending: - if (fatal_signal_pending(current)) - return true; - -out: - return false; -} - -unsigned long try_to_free_pages(struct zonelist *zonelist, int order, - gfp_t gfp_mask, nodemask_t *nodemask) -{ - unsigned long nr_reclaimed; - struct scan_control sc = { - .nr_to_reclaim = SWAP_CLUSTER_MAX, - .gfp_mask = (gfp_mask = memalloc_noio_flags(gfp_mask)), - .reclaim_idx = gfp_zone(gfp_mask), - .order = order, - .nodemask = nodemask, - .priority = DEF_PRIORITY, - .may_writepage = !laptop_mode, - .may_unmap = 1, - .may_swap = 1, - }; - - /* - * Do not enter reclaim if fatal signal was delivered while throttled. - * 1 is returned so that the page allocator does not OOM kill at this - * point. - */ - if (throttle_direct_reclaim(gfp_mask, zonelist, nodemask)) - return 1; - - trace_mm_vmscan_direct_reclaim_begin(order, - sc.may_writepage, - gfp_mask, - sc.reclaim_idx); - - nr_reclaimed = do_try_to_free_pages(zonelist, &sc); - - trace_mm_vmscan_direct_reclaim_end(nr_reclaimed); - - return nr_reclaimed; -} - -#ifdef CONFIG_MEMCG - -unsigned long mem_cgroup_shrink_node(struct mem_cgroup *memcg, - gfp_t gfp_mask, bool noswap, - pg_data_t *pgdat, - unsigned long *nr_scanned) -{ - struct scan_control sc = { - .nr_to_reclaim = SWAP_CLUSTER_MAX, - .target_mem_cgroup = memcg, - .may_writepage = !laptop_mode, - .may_unmap = 1, - .reclaim_idx = MAX_NR_ZONES - 1, - .may_swap = !noswap, - }; - unsigned long lru_pages; - - sc.gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) | - (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK); - - trace_mm_vmscan_memcg_softlimit_reclaim_begin(sc.order, - sc.may_writepage, - sc.gfp_mask, - sc.reclaim_idx); - - /* - * NOTE: Although we can get the priority field, using it - * here is not a good idea, since it limits the pages we can scan. - * if we don't reclaim here, the shrink_node from balance_pgdat - * will pick up pages from other mem cgroup's as well. We hack - * the priority and make it zero. - */ - shrink_node_memcg(pgdat, memcg, &sc, &lru_pages); - - trace_mm_vmscan_memcg_softlimit_reclaim_end(sc.nr_reclaimed); - - *nr_scanned = sc.nr_scanned; - return sc.nr_reclaimed; -} - -unsigned long try_to_free_mem_cgroup_pages(struct mem_cgroup *memcg, - unsigned long nr_pages, - gfp_t gfp_mask, - bool may_swap) -{ - struct zonelist *zonelist; - unsigned long nr_reclaimed; - int nid; - struct scan_control sc = { - .nr_to_reclaim = max(nr_pages, SWAP_CLUSTER_MAX), - .gfp_mask = (gfp_mask & GFP_RECLAIM_MASK) | - (GFP_HIGHUSER_MOVABLE & ~GFP_RECLAIM_MASK), - .reclaim_idx = MAX_NR_ZONES - 1, - .target_mem_cgroup = memcg, - .priority = DEF_PRIORITY, - .may_writepage = !laptop_mode, - .may_unmap = 1, - .may_swap = may_swap, - }; - - /* - * Unlike direct reclaim via alloc_pages(), memcg's reclaim doesn't - * take care of from where we get pages. So the node where we start the - * scan does not need to be the current node. - */ - nid = mem_cgroup_select_victim_node(memcg); - - zonelist = &NODE_DATA(nid)->node_zonelists[ZONELIST_FALLBACK]; - - trace_mm_vmscan_memcg_reclaim_begin(0, - sc.may_writepage, - sc.gfp_mask, - sc.reclaim_idx); - - current->flags |= PF_MEMALLOC; - nr_reclaimed = do_try_to_free_pages(zonelist, &sc); - current->flags &= ~PF_MEMALLOC; - - trace_mm_vmscan_memcg_reclaim_end(nr_reclaimed); - - return nr_reclaimed; -} -#endif - -static void age_active_anon(struct pglist_data *pgdat, - struct scan_control *sc) -{ - struct mem_cgroup *memcg; - - if (!total_swap_pages) - return; - - memcg = mem_cgroup_iter(NULL, NULL, NULL); - do { - struct lruvec *lruvec = mem_cgroup_lruvec(pgdat, memcg); - - if (inactive_list_is_low(lruvec, false, sc)) - shrink_active_list(SWAP_CLUSTER_MAX, lruvec, - sc, LRU_ACTIVE_ANON); - - memcg = mem_cgroup_iter(NULL, memcg, NULL); - } while (memcg); -} - -static bool zone_balanced(struct zone *zone, int order, int classzone_idx) -{ - unsigned long mark = high_wmark_pages(zone); - - if (!zone_watermark_ok_safe(zone, order, mark, classzone_idx)) - return false; - - /* - * If any eligible zone is balanced then the node is not considered - * to be congested or dirty - */ - clear_bit(PGDAT_CONGESTED, &zone->zone_pgdat->flags); - clear_bit(PGDAT_DIRTY, &zone->zone_pgdat->flags); - - return true; -} - -/* - * Prepare kswapd for sleeping. This verifies that there are no processes - * waiting in throttle_direct_reclaim() and that watermarks have been met. - * - * Returns true if kswapd is ready to sleep - */ -static bool prepare_kswapd_sleep(pg_data_t *pgdat, int order, int classzone_idx) -{ - int i; - - /* - * The throttled processes are normally woken up in balance_pgdat() as - * soon as pfmemalloc_watermark_ok() is true. But there is a potential - * race between when kswapd checks the watermarks and a process gets - * throttled. There is also a potential race if processes get - * throttled, kswapd wakes, a large process exits thereby balancing the - * zones, which causes kswapd to exit balance_pgdat() before reaching - * the wake up checks. If kswapd is going to sleep, no process should - * be sleeping on pfmemalloc_wait, so wake them now if necessary. If - * the wake up is premature, processes will wake kswapd and get - * throttled again. The difference from wake ups in balance_pgdat() is - * that here we are under prepare_to_wait(). - */ - if (waitqueue_active(&pgdat->pfmemalloc_wait)) - wake_up_all(&pgdat->pfmemalloc_wait); - - for (i = 0; i <= classzone_idx; i++) { - struct zone *zone = pgdat->node_zones + i; - - if (!managed_zone(zone)) - continue; - - if (!zone_balanced(zone, order, classzone_idx)) - return false; - } - - return true; -} - -/* - * kswapd shrinks a node of pages that are at or below the highest usable - * zone that is currently unbalanced. - * - * Returns true if kswapd scanned at least the requested number of pages to - * reclaim or if the lack of progress was due to pages under writeback. - * This is used to determine if the scanning priority needs to be raised. - */ -static bool kswapd_shrink_node(pg_data_t *pgdat, - struct scan_control *sc) -{ - struct zone *zone; - int z; - - /* Reclaim a number of pages proportional to the number of zones */ - sc->nr_to_reclaim = 0; - for (z = 0; z <= sc->reclaim_idx; z++) { - zone = pgdat->node_zones + z; - if (!managed_zone(zone)) - continue; - - sc->nr_to_reclaim += max(high_wmark_pages(zone), SWAP_CLUSTER_MAX); - } - - /* - * Historically care was taken to put equal pressure on all zones but - * now pressure is applied based on node LRU order. - */ - shrink_node(pgdat, sc); - - /* - * Fragmentation may mean that the system cannot be rebalanced for - * high-order allocations. If twice the allocation size has been - * reclaimed then recheck watermarks only at order-0 to prevent - * excessive reclaim. Assume that a process requested a high-order - * can direct reclaim/compact. - */ - if (sc->order && sc->nr_reclaimed >= compact_gap(sc->order)) - sc->order = 0; - - return sc->nr_scanned >= sc->nr_to_reclaim; -} - -/* - * For kswapd, balance_pgdat() will reclaim pages across a node from zones - * that are eligible for use by the caller until at least one zone is - * balanced. - * - * Returns the order kswapd finished reclaiming at. - * - * kswapd scans the zones in the highmem->normal->dma direction. It skips - * zones which have free_pages > high_wmark_pages(zone), but once a zone is - * found to have free_pages <= high_wmark_pages(zone), any page is that zone - * or lower is eligible for reclaim until at least one usable zone is - * balanced. - */ -static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx) -{ - int i; - unsigned long nr_soft_reclaimed; - unsigned long nr_soft_scanned; - struct zone *zone; - struct scan_control sc = { - .gfp_mask = GFP_KERNEL, - .order = order, - .priority = DEF_PRIORITY, - .may_writepage = !laptop_mode, - .may_unmap = 1, - .may_swap = 1, - }; - count_vm_event(PAGEOUTRUN); - - do { - bool raise_priority = true; - - sc.nr_reclaimed = 0; - sc.reclaim_idx = classzone_idx; - - /* - * If the number of buffer_heads exceeds the maximum allowed - * then consider reclaiming from all zones. This has a dual - * purpose -- on 64-bit systems it is expected that - * buffer_heads are stripped during active rotation. On 32-bit - * systems, highmem pages can pin lowmem memory and shrinking - * buffers can relieve lowmem pressure. Reclaim may still not - * go ahead if all eligible zones for the original allocation - * request are balanced to avoid excessive reclaim from kswapd. - */ - if (buffer_heads_over_limit) { - for (i = MAX_NR_ZONES - 1; i >= 0; i--) { - zone = pgdat->node_zones + i; - if (!managed_zone(zone)) - continue; - - sc.reclaim_idx = i; - break; - } - } - - /* - * Only reclaim if there are no eligible zones. Check from - * high to low zone as allocations prefer higher zones. - * Scanning from low to high zone would allow congestion to be - * cleared during a very small window when a small low - * zone was balanced even under extreme pressure when the - * overall node may be congested. Note that sc.reclaim_idx - * is not used as buffer_heads_over_limit may have adjusted - * it. - */ - for (i = classzone_idx; i >= 0; i--) { - zone = pgdat->node_zones + i; - if (!managed_zone(zone)) - continue; - - if (zone_balanced(zone, sc.order, classzone_idx)) - goto out; - } - - /* - * Do some background aging of the anon list, to give - * pages a chance to be referenced before reclaiming. All - * pages are rotated regardless of classzone as this is - * about consistent aging. - */ - age_active_anon(pgdat, &sc); - - /* - * If we're getting trouble reclaiming, start doing writepage - * even in laptop mode. - */ - if (sc.priority < DEF_PRIORITY - 2 || !pgdat_reclaimable(pgdat)) - sc.may_writepage = 1; - - /* Call soft limit reclaim before calling shrink_node. */ - sc.nr_scanned = 0; - nr_soft_scanned = 0; - nr_soft_reclaimed = mem_cgroup_soft_limit_reclaim(pgdat, sc.order, - sc.gfp_mask, &nr_soft_scanned); - sc.nr_reclaimed += nr_soft_reclaimed; - - /* - * There should be no need to raise the scanning priority if - * enough pages are already being scanned that that high - * watermark would be met at 100% efficiency. - */ - if (kswapd_shrink_node(pgdat, &sc)) - raise_priority = false; - - /* - * If the low watermark is met there is no need for processes - * to be throttled on pfmemalloc_wait as they should not be - * able to safely make forward progress. Wake them - */ - if (waitqueue_active(&pgdat->pfmemalloc_wait) && - pfmemalloc_watermark_ok(pgdat)) - wake_up_all(&pgdat->pfmemalloc_wait); - - /* Check if kswapd should be suspending */ - if (try_to_freeze() || kthread_should_stop()) - break; - - /* - * Raise priority if scanning rate is too low or there was no - * progress in reclaiming pages - */ - if (raise_priority || !sc.nr_reclaimed) - sc.priority--; - } while (sc.priority >= 1); - -out: - /* - * Return the order kswapd stopped reclaiming at as - * prepare_kswapd_sleep() takes it into account. If another caller - * entered the allocator slow path while kswapd was awake, order will - * remain at the higher level. - */ - return sc.order; -} - -static void kswapd_try_to_sleep(pg_data_t *pgdat, int alloc_order, int reclaim_order, - unsigned int classzone_idx) -{ - long remaining = 0; - DEFINE_WAIT(wait); - - if (freezing(current) || kthread_should_stop()) - return; - - prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE); - - /* Try to sleep for a short interval */ - if (prepare_kswapd_sleep(pgdat, reclaim_order, classzone_idx)) { - /* - * Compaction records what page blocks it recently failed to - * isolate pages from and skips them in the future scanning. - * When kswapd is going to sleep, it is reasonable to assume - * that pages and compaction may succeed so reset the cache. - */ - reset_isolation_suitable(pgdat); - - /* - * We have freed the memory, now we should compact it to make - * allocation of the requested order possible. - */ - wakeup_kcompactd(pgdat, alloc_order, classzone_idx); - - remaining = schedule_timeout(HZ/10); - - /* - * If woken prematurely then reset kswapd_classzone_idx and - * order. The values will either be from a wakeup request or - * the previous request that slept prematurely. - */ - if (remaining) { - pgdat->kswapd_classzone_idx = max(pgdat->kswapd_classzone_idx, classzone_idx); - pgdat->kswapd_order = max(pgdat->kswapd_order, reclaim_order); - } - - finish_wait(&pgdat->kswapd_wait, &wait); - prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE); - } - - /* - * After a short sleep, check if it was a premature sleep. If not, then - * go fully to sleep until explicitly woken up. - */ - if (!remaining && - prepare_kswapd_sleep(pgdat, reclaim_order, classzone_idx)) { - trace_mm_vmscan_kswapd_sleep(pgdat->node_id); - - /* - * vmstat counters are not perfectly accurate and the estimated - * value for counters such as NR_FREE_PAGES can deviate from the - * true value by nr_online_cpus * threshold. To avoid the zone - * watermarks being breached while under pressure, we reduce the - * per-cpu vmstat threshold while kswapd is awake and restore - * them before going back to sleep. - */ - set_pgdat_percpu_threshold(pgdat, calculate_normal_threshold); - - if (!kthread_should_stop()) - schedule(); - - set_pgdat_percpu_threshold(pgdat, calculate_pressure_threshold); - } else { - if (remaining) - count_vm_event(KSWAPD_LOW_WMARK_HIT_QUICKLY); - else - count_vm_event(KSWAPD_HIGH_WMARK_HIT_QUICKLY); - } - finish_wait(&pgdat->kswapd_wait, &wait); -} - -/* - * The background pageout daemon, started as a kernel thread - * from the init process. - * - * This basically trickles out pages so that we have _some_ - * free memory available even if there is no other activity - * that frees anything up. This is needed for things like routing - * etc, where we otherwise might have all activity going on in - * asynchronous contexts that cannot page things out. - * - * If there are applications that are active memory-allocators - * (most normal use), this basically shouldn't matter. - */ -static int kswapd(void *p) -{ - unsigned int alloc_order, reclaim_order, classzone_idx; - pg_data_t *pgdat = (pg_data_t*)p; - struct task_struct *tsk = current; - - struct reclaim_state reclaim_state = { - .reclaimed_slab = 0, - }; - const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id); - - lockdep_set_current_reclaim_state(GFP_KERNEL); - - if (!cpumask_empty(cpumask)) - set_cpus_allowed_ptr(tsk, cpumask); - current->reclaim_state = &reclaim_state; - - /* - * Tell the memory management that we're a "memory allocator", - * and that if we need more memory we should get access to it - * regardless (see "__alloc_pages()"). "kswapd" should - * never get caught in the normal page freeing logic. - * - * (Kswapd normally doesn't need memory anyway, but sometimes - * you need a small amount of memory in order to be able to - * page out something else, and this flag essentially protects - * us from recursively trying to free more memory as we're - * trying to free the first piece of memory in the first place). - */ - tsk->flags |= PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD; - set_freezable(); - - pgdat->kswapd_order = alloc_order = reclaim_order = 0; - pgdat->kswapd_classzone_idx = classzone_idx = 0; - for ( ; ; ) { - bool ret; - -kswapd_try_sleep: - kswapd_try_to_sleep(pgdat, alloc_order, reclaim_order, - classzone_idx); - - /* Read the new order and classzone_idx */ - alloc_order = reclaim_order = pgdat->kswapd_order; - classzone_idx = pgdat->kswapd_classzone_idx; - pgdat->kswapd_order = 0; - pgdat->kswapd_classzone_idx = 0; - - ret = try_to_freeze(); - if (kthread_should_stop()) - break; - - /* - * We can speed up thawing tasks if we don't call balance_pgdat - * after returning from the refrigerator - */ - if (ret) - continue; - - /* - * Reclaim begins at the requested order but if a high-order - * reclaim fails then kswapd falls back to reclaiming for - * order-0. If that happens, kswapd will consider sleeping - * for the order it finished reclaiming at (reclaim_order) - * but kcompactd is woken to compact for the original - * request (alloc_order). - */ - trace_mm_vmscan_kswapd_wake(pgdat->node_id, classzone_idx, - alloc_order); - reclaim_order = balance_pgdat(pgdat, alloc_order, classzone_idx); - if (reclaim_order < alloc_order) - goto kswapd_try_sleep; - - alloc_order = reclaim_order = pgdat->kswapd_order; - classzone_idx = pgdat->kswapd_classzone_idx; - } - - tsk->flags &= ~(PF_MEMALLOC | PF_SWAPWRITE | PF_KSWAPD); - current->reclaim_state = NULL; - lockdep_clear_current_reclaim_state(); - - return 0; -} - -/* - * A zone is low on free memory, so wake its kswapd task to service it. - */ -void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx) -{ - pg_data_t *pgdat; - int z; - - if (!managed_zone(zone)) - return; - - if (!cpuset_zone_allowed(zone, GFP_KERNEL | __GFP_HARDWALL)) - return; - pgdat = zone->zone_pgdat; - pgdat->kswapd_classzone_idx = max(pgdat->kswapd_classzone_idx, classzone_idx); - pgdat->kswapd_order = max(pgdat->kswapd_order, order); - if (!waitqueue_active(&pgdat->kswapd_wait)) - return; - - /* Only wake kswapd if all zones are unbalanced */ - for (z = 0; z <= classzone_idx; z++) { - zone = pgdat->node_zones + z; - if (!managed_zone(zone)) - continue; - - if (zone_balanced(zone, order, classzone_idx)) - return; - } - - trace_mm_vmscan_wakeup_kswapd(pgdat->node_id, zone_idx(zone), order); - wake_up_interruptible(&pgdat->kswapd_wait); -} - -#ifdef CONFIG_HIBERNATION -/* - * Try to free `nr_to_reclaim' of memory, system-wide, and return the number of - * freed pages. - * - * Rather than trying to age LRUs the aim is to preserve the overall - * LRU order by reclaiming preferentially - * inactive > active > active referenced > active mapped - */ -unsigned long shrink_all_memory(unsigned long nr_to_reclaim) -{ - struct reclaim_state reclaim_state; - struct scan_control sc = { - .nr_to_reclaim = nr_to_reclaim, - .gfp_mask = GFP_HIGHUSER_MOVABLE, - .reclaim_idx = MAX_NR_ZONES - 1, - .priority = DEF_PRIORITY, - .may_writepage = 1, - .may_unmap = 1, - .may_swap = 1, - .hibernation_mode = 1, - }; - struct zonelist *zonelist = node_zonelist(numa_node_id(), sc.gfp_mask); - struct task_struct *p = current; - unsigned long nr_reclaimed; - - p->flags |= PF_MEMALLOC; - lockdep_set_current_reclaim_state(sc.gfp_mask); - reclaim_state.reclaimed_slab = 0; - p->reclaim_state = &reclaim_state; - - nr_reclaimed = do_try_to_free_pages(zonelist, &sc); - - p->reclaim_state = NULL; - lockdep_clear_current_reclaim_state(); - p->flags &= ~PF_MEMALLOC; - - return nr_reclaimed; -} -#endif /* CONFIG_HIBERNATION */ - -/* It's optimal to keep kswapds on the same CPUs as their memory, but - not required for correctness. So if the last cpu in a node goes - away, we get changed to run anywhere: as the first one comes back, - restore their cpu bindings. */ -static int cpu_callback(struct notifier_block *nfb, unsigned long action, - void *hcpu) -{ - int nid; - - if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN) { - for_each_node_state(nid, N_MEMORY) { - pg_data_t *pgdat = NODE_DATA(nid); - const struct cpumask *mask; - - mask = cpumask_of_node(pgdat->node_id); - - if (cpumask_any_and(cpu_online_mask, mask) < nr_cpu_ids) - /* One of our CPUs online: restore mask */ - set_cpus_allowed_ptr(pgdat->kswapd, mask); - } - } - return NOTIFY_OK; -} - -/* - * This kswapd start function will be called by init and node-hot-add. - * On node-hot-add, kswapd will moved to proper cpus if cpus are hot-added. - */ -int kswapd_run(int nid) -{ - pg_data_t *pgdat = NODE_DATA(nid); - int ret = 0; - - if (pgdat->kswapd) - return 0; - - pgdat->kswapd = kthread_run(kswapd, pgdat, "kswapd%d", nid); - if (IS_ERR(pgdat->kswapd)) { - /* failure at boot is fatal */ - BUG_ON(system_state == SYSTEM_BOOTING); - pr_err("Failed to start kswapd on node %d\n", nid); - ret = PTR_ERR(pgdat->kswapd); - pgdat->kswapd = NULL; - } - return ret; -} - -/* - * Called by memory hotplug when all memory in a node is offlined. Caller must - * hold mem_hotplug_begin/end(). - */ -void kswapd_stop(int nid) -{ - struct task_struct *kswapd = NODE_DATA(nid)->kswapd; - - if (kswapd) { - kthread_stop(kswapd); - NODE_DATA(nid)->kswapd = NULL; - } -} - -static int __init kswapd_init(void) -{ - int nid; - - swap_setup(); - for_each_node_state(nid, N_MEMORY) - kswapd_run(nid); - hotcpu_notifier(cpu_callback, 0); - return 0; -} - -module_init(kswapd_init) - -#ifdef CONFIG_NUMA -/* - * Node reclaim mode - * - * If non-zero call node_reclaim when the number of free pages falls below - * the watermarks. - */ -int node_reclaim_mode __read_mostly; - -#define RECLAIM_OFF 0 -#define RECLAIM_ZONE (1<<0) /* Run shrink_inactive_list on the zone */ -#define RECLAIM_WRITE (1<<1) /* Writeout pages during reclaim */ -#define RECLAIM_UNMAP (1<<2) /* Unmap pages during reclaim */ - -/* - * Priority for NODE_RECLAIM. This determines the fraction of pages - * of a node considered for each zone_reclaim. 4 scans 1/16th of - * a zone. - */ -#define NODE_RECLAIM_PRIORITY 4 - -/* - * Percentage of pages in a zone that must be unmapped for node_reclaim to - * occur. - */ -int sysctl_min_unmapped_ratio = 1; - -/* - * If the number of slab pages in a zone grows beyond this percentage then - * slab reclaim needs to occur. - */ -int sysctl_min_slab_ratio = 5; - -static inline unsigned long node_unmapped_file_pages(struct pglist_data *pgdat) -{ - unsigned long file_mapped = node_page_state(pgdat, NR_FILE_MAPPED); - unsigned long file_lru = node_page_state(pgdat, NR_INACTIVE_FILE) + - node_page_state(pgdat, NR_ACTIVE_FILE); - - /* - * It's possible for there to be more file mapped pages than - * accounted for by the pages on the file LRU lists because - * tmpfs pages accounted for as ANON can also be FILE_MAPPED - */ - return (file_lru > file_mapped) ? (file_lru - file_mapped) : 0; -} - -/* Work out how many page cache pages we can reclaim in this reclaim_mode */ -static unsigned long node_pagecache_reclaimable(struct pglist_data *pgdat) -{ - unsigned long nr_pagecache_reclaimable; - unsigned long delta = 0; - - /* - * If RECLAIM_UNMAP is set, then all file pages are considered - * potentially reclaimable. Otherwise, we have to worry about - * pages like swapcache and node_unmapped_file_pages() provides - * a better estimate - */ - if (node_reclaim_mode & RECLAIM_UNMAP) - nr_pagecache_reclaimable = node_page_state(pgdat, NR_FILE_PAGES); - else - nr_pagecache_reclaimable = node_unmapped_file_pages(pgdat); - - /* If we can't clean pages, remove dirty pages from consideration */ - if (!(node_reclaim_mode & RECLAIM_WRITE)) - delta += node_page_state(pgdat, NR_FILE_DIRTY); - - /* Watch for any possible underflows due to delta */ - if (unlikely(delta > nr_pagecache_reclaimable)) - delta = nr_pagecache_reclaimable; - - return nr_pagecache_reclaimable - delta; -} - -/* - * Try to free up some pages from this node through reclaim. - */ -static int __node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned int order) -{ - /* Minimum pages needed in order to stay on node */ - const unsigned long nr_pages = 1 << order; - struct task_struct *p = current; - struct reclaim_state reclaim_state; - int classzone_idx = gfp_zone(gfp_mask); - struct scan_control sc = { - .nr_to_reclaim = max(nr_pages, SWAP_CLUSTER_MAX), - .gfp_mask = (gfp_mask = memalloc_noio_flags(gfp_mask)), - .order = order, - .priority = NODE_RECLAIM_PRIORITY, - .may_writepage = !!(node_reclaim_mode & RECLAIM_WRITE), - .may_unmap = !!(node_reclaim_mode & RECLAIM_UNMAP), - .may_swap = 1, - .reclaim_idx = classzone_idx, - }; - - cond_resched(); - /* - * We need to be able to allocate from the reserves for RECLAIM_UNMAP - * and we also need to be able to write out pages for RECLAIM_WRITE - * and RECLAIM_UNMAP. - */ - p->flags |= PF_MEMALLOC | PF_SWAPWRITE; - lockdep_set_current_reclaim_state(gfp_mask); - reclaim_state.reclaimed_slab = 0; - p->reclaim_state = &reclaim_state; - - if (node_pagecache_reclaimable(pgdat) > pgdat->min_unmapped_pages) { - /* - * Free memory by calling shrink zone with increasing - * priorities until we have enough memory freed. - */ - do { - shrink_node(pgdat, &sc); - } while (sc.nr_reclaimed < nr_pages && --sc.priority >= 0); - } - - p->reclaim_state = NULL; - current->flags &= ~(PF_MEMALLOC | PF_SWAPWRITE); - lockdep_clear_current_reclaim_state(); - return sc.nr_reclaimed >= nr_pages; -} - -int node_reclaim(struct pglist_data *pgdat, gfp_t gfp_mask, unsigned int order) -{ - int ret; - - /* - * Node reclaim reclaims unmapped file backed pages and - * slab pages if we are over the defined limits. - * - * A small portion of unmapped file backed pages is needed for - * file I/O otherwise pages read by file I/O will be immediately - * thrown out if the node is overallocated. So we do not reclaim - * if less than a specified percentage of the node is used by - * unmapped file backed pages. - */ - if (node_pagecache_reclaimable(pgdat) <= pgdat->min_unmapped_pages && - sum_zone_node_page_state(pgdat->node_id, NR_SLAB_RECLAIMABLE) <= pgdat->min_slab_pages) - return NODE_RECLAIM_FULL; - - if (!pgdat_reclaimable(pgdat)) - return NODE_RECLAIM_FULL; - - /* - * Do not scan if the allocation should not be delayed. - */ - if (!gfpflags_allow_blocking(gfp_mask) || (current->flags & PF_MEMALLOC)) - return NODE_RECLAIM_NOSCAN; - - /* - * Only run node reclaim on the local node or on nodes that do not - * have associated processors. This will favor the local processor - * over remote processors and spread off node memory allocations - * as wide as possible. - */ - if (node_state(pgdat->node_id, N_CPU) && pgdat->node_id != numa_node_id()) - return NODE_RECLAIM_NOSCAN; - - if (test_and_set_bit(PGDAT_RECLAIM_LOCKED, &pgdat->flags)) - return NODE_RECLAIM_NOSCAN; - - ret = __node_reclaim(pgdat, gfp_mask, order); - clear_bit(PGDAT_RECLAIM_LOCKED, &pgdat->flags); - - if (!ret) - count_vm_event(PGSCAN_ZONE_RECLAIM_FAILED); - - return ret; -} -#endif - -/* - * page_evictable - test whether a page is evictable - * @page: the page to test - * - * Test whether page is evictable--i.e., should be placed on active/inactive - * lists vs unevictable list. - * - * Reasons page might not be evictable: - * (1) page's mapping marked unevictable - * (2) page is part of an mlocked VMA - * - */ -int page_evictable(struct page *page) -{ - return !mapping_unevictable(page_mapping(page)) && !PageMlocked(page); -} - -#ifdef CONFIG_SHMEM -/** - * check_move_unevictable_pages - check pages for evictability and move to appropriate zone lru list - * @pages: array of pages to check - * @nr_pages: number of pages to check - * - * Checks pages for evictability and moves them to the appropriate lru list. - * - * This function is only used for SysV IPC SHM_UNLOCK. - */ -void check_move_unevictable_pages(struct page **pages, int nr_pages) -{ - struct lruvec *lruvec; - struct pglist_data *pgdat = NULL; - int pgscanned = 0; - int pgrescued = 0; - int i; - - for (i = 0; i < nr_pages; i++) { - struct page *page = pages[i]; - struct pglist_data *pagepgdat = page_pgdat(page); - - pgscanned++; - if (pagepgdat != pgdat) { - if (pgdat) - spin_unlock_irq(&pgdat->lru_lock); - pgdat = pagepgdat; - spin_lock_irq(&pgdat->lru_lock); - } - lruvec = mem_cgroup_page_lruvec(page, pgdat); - - if (!PageLRU(page) || !PageUnevictable(page)) - continue; - - if (page_evictable(page)) { - enum lru_list lru = page_lru_base_type(page); - - VM_BUG_ON_PAGE(PageActive(page), page); - ClearPageUnevictable(page); - del_page_from_lru_list(page, lruvec, LRU_UNEVICTABLE); - add_page_to_lru_list(page, lruvec, lru); - pgrescued++; - } - } - - if (pgdat) { - __count_vm_events(UNEVICTABLE_PGRESCUED, pgrescued); - __count_vm_events(UNEVICTABLE_PGSCANNED, pgscanned); - spin_unlock_irq(&pgdat->lru_lock); - } -} -#endif /* CONFIG_SHMEM */ diff --git a/src/linux/mm/vmstat.c b/src/linux/mm/vmstat.c deleted file mode 100644 index 604f26a..0000000 --- a/src/linux/mm/vmstat.c +++ /dev/null @@ -1,1962 +0,0 @@ -/* - * linux/mm/vmstat.c - * - * Manages VM statistics - * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds - * - * zoned VM statistics - * Copyright (C) 2006 Silicon Graphics, Inc., - * Christoph Lameter - * Copyright (C) 2008-2014 Christoph Lameter - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "internal.h" - -#ifdef CONFIG_VM_EVENT_COUNTERS -DEFINE_PER_CPU(struct vm_event_state, vm_event_states) = {{0}}; -EXPORT_PER_CPU_SYMBOL(vm_event_states); - -static void sum_vm_events(unsigned long *ret) -{ - int cpu; - int i; - - memset(ret, 0, NR_VM_EVENT_ITEMS * sizeof(unsigned long)); - - for_each_online_cpu(cpu) { - struct vm_event_state *this = &per_cpu(vm_event_states, cpu); - - for (i = 0; i < NR_VM_EVENT_ITEMS; i++) - ret[i] += this->event[i]; - } -} - -/* - * Accumulate the vm event counters across all CPUs. - * The result is unavoidably approximate - it can change - * during and after execution of this function. -*/ -void all_vm_events(unsigned long *ret) -{ - get_online_cpus(); - sum_vm_events(ret); - put_online_cpus(); -} -EXPORT_SYMBOL_GPL(all_vm_events); - -/* - * Fold the foreign cpu events into our own. - * - * This is adding to the events on one processor - * but keeps the global counts constant. - */ -void vm_events_fold_cpu(int cpu) -{ - struct vm_event_state *fold_state = &per_cpu(vm_event_states, cpu); - int i; - - for (i = 0; i < NR_VM_EVENT_ITEMS; i++) { - count_vm_events(i, fold_state->event[i]); - fold_state->event[i] = 0; - } -} - -#endif /* CONFIG_VM_EVENT_COUNTERS */ - -/* - * Manage combined zone based / global counters - * - * vm_stat contains the global counters - */ -atomic_long_t vm_zone_stat[NR_VM_ZONE_STAT_ITEMS] __cacheline_aligned_in_smp; -atomic_long_t vm_node_stat[NR_VM_NODE_STAT_ITEMS] __cacheline_aligned_in_smp; -EXPORT_SYMBOL(vm_zone_stat); -EXPORT_SYMBOL(vm_node_stat); - -#ifdef CONFIG_SMP - -int calculate_pressure_threshold(struct zone *zone) -{ - int threshold; - int watermark_distance; - - /* - * As vmstats are not up to date, there is drift between the estimated - * and real values. For high thresholds and a high number of CPUs, it - * is possible for the min watermark to be breached while the estimated - * value looks fine. The pressure threshold is a reduced value such - * that even the maximum amount of drift will not accidentally breach - * the min watermark - */ - watermark_distance = low_wmark_pages(zone) - min_wmark_pages(zone); - threshold = max(1, (int)(watermark_distance / num_online_cpus())); - - /* - * Maximum threshold is 125 - */ - threshold = min(125, threshold); - - return threshold; -} - -int calculate_normal_threshold(struct zone *zone) -{ - int threshold; - int mem; /* memory in 128 MB units */ - - /* - * The threshold scales with the number of processors and the amount - * of memory per zone. More memory means that we can defer updates for - * longer, more processors could lead to more contention. - * fls() is used to have a cheap way of logarithmic scaling. - * - * Some sample thresholds: - * - * Threshold Processors (fls) Zonesize fls(mem+1) - * ------------------------------------------------------------------ - * 8 1 1 0.9-1 GB 4 - * 16 2 2 0.9-1 GB 4 - * 20 2 2 1-2 GB 5 - * 24 2 2 2-4 GB 6 - * 28 2 2 4-8 GB 7 - * 32 2 2 8-16 GB 8 - * 4 2 2 <128M 1 - * 30 4 3 2-4 GB 5 - * 48 4 3 8-16 GB 8 - * 32 8 4 1-2 GB 4 - * 32 8 4 0.9-1GB 4 - * 10 16 5 <128M 1 - * 40 16 5 900M 4 - * 70 64 7 2-4 GB 5 - * 84 64 7 4-8 GB 6 - * 108 512 9 4-8 GB 6 - * 125 1024 10 8-16 GB 8 - * 125 1024 10 16-32 GB 9 - */ - - mem = zone->managed_pages >> (27 - PAGE_SHIFT); - - threshold = 2 * fls(num_online_cpus()) * (1 + fls(mem)); - - /* - * Maximum threshold is 125 - */ - threshold = min(125, threshold); - - return threshold; -} - -/* - * Refresh the thresholds for each zone. - */ -void refresh_zone_stat_thresholds(void) -{ - struct pglist_data *pgdat; - struct zone *zone; - int cpu; - int threshold; - - /* Zero current pgdat thresholds */ - for_each_online_pgdat(pgdat) { - for_each_online_cpu(cpu) { - per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold = 0; - } - } - - for_each_populated_zone(zone) { - struct pglist_data *pgdat = zone->zone_pgdat; - unsigned long max_drift, tolerate_drift; - - threshold = calculate_normal_threshold(zone); - - for_each_online_cpu(cpu) { - int pgdat_threshold; - - per_cpu_ptr(zone->pageset, cpu)->stat_threshold - = threshold; - - /* Base nodestat threshold on the largest populated zone. */ - pgdat_threshold = per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold; - per_cpu_ptr(pgdat->per_cpu_nodestats, cpu)->stat_threshold - = max(threshold, pgdat_threshold); - } - - /* - * Only set percpu_drift_mark if there is a danger that - * NR_FREE_PAGES reports the low watermark is ok when in fact - * the min watermark could be breached by an allocation - */ - tolerate_drift = low_wmark_pages(zone) - min_wmark_pages(zone); - max_drift = num_online_cpus() * threshold; - if (max_drift > tolerate_drift) - zone->percpu_drift_mark = high_wmark_pages(zone) + - max_drift; - } -} - -void set_pgdat_percpu_threshold(pg_data_t *pgdat, - int (*calculate_pressure)(struct zone *)) -{ - struct zone *zone; - int cpu; - int threshold; - int i; - - for (i = 0; i < pgdat->nr_zones; i++) { - zone = &pgdat->node_zones[i]; - if (!zone->percpu_drift_mark) - continue; - - threshold = (*calculate_pressure)(zone); - for_each_online_cpu(cpu) - per_cpu_ptr(zone->pageset, cpu)->stat_threshold - = threshold; - } -} - -/* - * For use when we know that interrupts are disabled, - * or when we know that preemption is disabled and that - * particular counter cannot be updated from interrupt context. - */ -void __mod_zone_page_state(struct zone *zone, enum zone_stat_item item, - long delta) -{ - struct per_cpu_pageset __percpu *pcp = zone->pageset; - s8 __percpu *p = pcp->vm_stat_diff + item; - long x; - long t; - - x = delta + __this_cpu_read(*p); - - t = __this_cpu_read(pcp->stat_threshold); - - if (unlikely(x > t || x < -t)) { - zone_page_state_add(x, zone, item); - x = 0; - } - __this_cpu_write(*p, x); -} -EXPORT_SYMBOL(__mod_zone_page_state); - -void __mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item, - long delta) -{ - struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats; - s8 __percpu *p = pcp->vm_node_stat_diff + item; - long x; - long t; - - x = delta + __this_cpu_read(*p); - - t = __this_cpu_read(pcp->stat_threshold); - - if (unlikely(x > t || x < -t)) { - node_page_state_add(x, pgdat, item); - x = 0; - } - __this_cpu_write(*p, x); -} -EXPORT_SYMBOL(__mod_node_page_state); - -/* - * Optimized increment and decrement functions. - * - * These are only for a single page and therefore can take a struct page * - * argument instead of struct zone *. This allows the inclusion of the code - * generated for page_zone(page) into the optimized functions. - * - * No overflow check is necessary and therefore the differential can be - * incremented or decremented in place which may allow the compilers to - * generate better code. - * The increment or decrement is known and therefore one boundary check can - * be omitted. - * - * NOTE: These functions are very performance sensitive. Change only - * with care. - * - * Some processors have inc/dec instructions that are atomic vs an interrupt. - * However, the code must first determine the differential location in a zone - * based on the processor number and then inc/dec the counter. There is no - * guarantee without disabling preemption that the processor will not change - * in between and therefore the atomicity vs. interrupt cannot be exploited - * in a useful way here. - */ -void __inc_zone_state(struct zone *zone, enum zone_stat_item item) -{ - struct per_cpu_pageset __percpu *pcp = zone->pageset; - s8 __percpu *p = pcp->vm_stat_diff + item; - s8 v, t; - - v = __this_cpu_inc_return(*p); - t = __this_cpu_read(pcp->stat_threshold); - if (unlikely(v > t)) { - s8 overstep = t >> 1; - - zone_page_state_add(v + overstep, zone, item); - __this_cpu_write(*p, -overstep); - } -} - -void __inc_node_state(struct pglist_data *pgdat, enum node_stat_item item) -{ - struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats; - s8 __percpu *p = pcp->vm_node_stat_diff + item; - s8 v, t; - - v = __this_cpu_inc_return(*p); - t = __this_cpu_read(pcp->stat_threshold); - if (unlikely(v > t)) { - s8 overstep = t >> 1; - - node_page_state_add(v + overstep, pgdat, item); - __this_cpu_write(*p, -overstep); - } -} - -void __inc_zone_page_state(struct page *page, enum zone_stat_item item) -{ - __inc_zone_state(page_zone(page), item); -} -EXPORT_SYMBOL(__inc_zone_page_state); - -void __inc_node_page_state(struct page *page, enum node_stat_item item) -{ - __inc_node_state(page_pgdat(page), item); -} -EXPORT_SYMBOL(__inc_node_page_state); - -void __dec_zone_state(struct zone *zone, enum zone_stat_item item) -{ - struct per_cpu_pageset __percpu *pcp = zone->pageset; - s8 __percpu *p = pcp->vm_stat_diff + item; - s8 v, t; - - v = __this_cpu_dec_return(*p); - t = __this_cpu_read(pcp->stat_threshold); - if (unlikely(v < - t)) { - s8 overstep = t >> 1; - - zone_page_state_add(v - overstep, zone, item); - __this_cpu_write(*p, overstep); - } -} - -void __dec_node_state(struct pglist_data *pgdat, enum node_stat_item item) -{ - struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats; - s8 __percpu *p = pcp->vm_node_stat_diff + item; - s8 v, t; - - v = __this_cpu_dec_return(*p); - t = __this_cpu_read(pcp->stat_threshold); - if (unlikely(v < - t)) { - s8 overstep = t >> 1; - - node_page_state_add(v - overstep, pgdat, item); - __this_cpu_write(*p, overstep); - } -} - -void __dec_zone_page_state(struct page *page, enum zone_stat_item item) -{ - __dec_zone_state(page_zone(page), item); -} -EXPORT_SYMBOL(__dec_zone_page_state); - -void __dec_node_page_state(struct page *page, enum node_stat_item item) -{ - __dec_node_state(page_pgdat(page), item); -} -EXPORT_SYMBOL(__dec_node_page_state); - -#ifdef CONFIG_HAVE_CMPXCHG_LOCAL -/* - * If we have cmpxchg_local support then we do not need to incur the overhead - * that comes with local_irq_save/restore if we use this_cpu_cmpxchg. - * - * mod_state() modifies the zone counter state through atomic per cpu - * operations. - * - * Overstep mode specifies how overstep should handled: - * 0 No overstepping - * 1 Overstepping half of threshold - * -1 Overstepping minus half of threshold -*/ -static inline void mod_zone_state(struct zone *zone, - enum zone_stat_item item, long delta, int overstep_mode) -{ - struct per_cpu_pageset __percpu *pcp = zone->pageset; - s8 __percpu *p = pcp->vm_stat_diff + item; - long o, n, t, z; - - do { - z = 0; /* overflow to zone counters */ - - /* - * The fetching of the stat_threshold is racy. We may apply - * a counter threshold to the wrong the cpu if we get - * rescheduled while executing here. However, the next - * counter update will apply the threshold again and - * therefore bring the counter under the threshold again. - * - * Most of the time the thresholds are the same anyways - * for all cpus in a zone. - */ - t = this_cpu_read(pcp->stat_threshold); - - o = this_cpu_read(*p); - n = delta + o; - - if (n > t || n < -t) { - int os = overstep_mode * (t >> 1) ; - - /* Overflow must be added to zone counters */ - z = n + os; - n = -os; - } - } while (this_cpu_cmpxchg(*p, o, n) != o); - - if (z) - zone_page_state_add(z, zone, item); -} - -void mod_zone_page_state(struct zone *zone, enum zone_stat_item item, - long delta) -{ - mod_zone_state(zone, item, delta, 0); -} -EXPORT_SYMBOL(mod_zone_page_state); - -void inc_zone_page_state(struct page *page, enum zone_stat_item item) -{ - mod_zone_state(page_zone(page), item, 1, 1); -} -EXPORT_SYMBOL(inc_zone_page_state); - -void dec_zone_page_state(struct page *page, enum zone_stat_item item) -{ - mod_zone_state(page_zone(page), item, -1, -1); -} -EXPORT_SYMBOL(dec_zone_page_state); - -static inline void mod_node_state(struct pglist_data *pgdat, - enum node_stat_item item, int delta, int overstep_mode) -{ - struct per_cpu_nodestat __percpu *pcp = pgdat->per_cpu_nodestats; - s8 __percpu *p = pcp->vm_node_stat_diff + item; - long o, n, t, z; - - do { - z = 0; /* overflow to node counters */ - - /* - * The fetching of the stat_threshold is racy. We may apply - * a counter threshold to the wrong the cpu if we get - * rescheduled while executing here. However, the next - * counter update will apply the threshold again and - * therefore bring the counter under the threshold again. - * - * Most of the time the thresholds are the same anyways - * for all cpus in a node. - */ - t = this_cpu_read(pcp->stat_threshold); - - o = this_cpu_read(*p); - n = delta + o; - - if (n > t || n < -t) { - int os = overstep_mode * (t >> 1) ; - - /* Overflow must be added to node counters */ - z = n + os; - n = -os; - } - } while (this_cpu_cmpxchg(*p, o, n) != o); - - if (z) - node_page_state_add(z, pgdat, item); -} - -void mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item, - long delta) -{ - mod_node_state(pgdat, item, delta, 0); -} -EXPORT_SYMBOL(mod_node_page_state); - -void inc_node_state(struct pglist_data *pgdat, enum node_stat_item item) -{ - mod_node_state(pgdat, item, 1, 1); -} - -void inc_node_page_state(struct page *page, enum node_stat_item item) -{ - mod_node_state(page_pgdat(page), item, 1, 1); -} -EXPORT_SYMBOL(inc_node_page_state); - -void dec_node_page_state(struct page *page, enum node_stat_item item) -{ - mod_node_state(page_pgdat(page), item, -1, -1); -} -EXPORT_SYMBOL(dec_node_page_state); -#else -/* - * Use interrupt disable to serialize counter updates - */ -void mod_zone_page_state(struct zone *zone, enum zone_stat_item item, - long delta) -{ - unsigned long flags; - - local_irq_save(flags); - __mod_zone_page_state(zone, item, delta); - local_irq_restore(flags); -} -EXPORT_SYMBOL(mod_zone_page_state); - -void inc_zone_page_state(struct page *page, enum zone_stat_item item) -{ - unsigned long flags; - struct zone *zone; - - zone = page_zone(page); - local_irq_save(flags); - __inc_zone_state(zone, item); - local_irq_restore(flags); -} -EXPORT_SYMBOL(inc_zone_page_state); - -void dec_zone_page_state(struct page *page, enum zone_stat_item item) -{ - unsigned long flags; - - local_irq_save(flags); - __dec_zone_page_state(page, item); - local_irq_restore(flags); -} -EXPORT_SYMBOL(dec_zone_page_state); - -void inc_node_state(struct pglist_data *pgdat, enum node_stat_item item) -{ - unsigned long flags; - - local_irq_save(flags); - __inc_node_state(pgdat, item); - local_irq_restore(flags); -} -EXPORT_SYMBOL(inc_node_state); - -void mod_node_page_state(struct pglist_data *pgdat, enum node_stat_item item, - long delta) -{ - unsigned long flags; - - local_irq_save(flags); - __mod_node_page_state(pgdat, item, delta); - local_irq_restore(flags); -} -EXPORT_SYMBOL(mod_node_page_state); - -void inc_node_page_state(struct page *page, enum node_stat_item item) -{ - unsigned long flags; - struct pglist_data *pgdat; - - pgdat = page_pgdat(page); - local_irq_save(flags); - __inc_node_state(pgdat, item); - local_irq_restore(flags); -} -EXPORT_SYMBOL(inc_node_page_state); - -void dec_node_page_state(struct page *page, enum node_stat_item item) -{ - unsigned long flags; - - local_irq_save(flags); - __dec_node_page_state(page, item); - local_irq_restore(flags); -} -EXPORT_SYMBOL(dec_node_page_state); -#endif - -/* - * Fold a differential into the global counters. - * Returns the number of counters updated. - */ -static int fold_diff(int *zone_diff, int *node_diff) -{ - int i; - int changes = 0; - - for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) - if (zone_diff[i]) { - atomic_long_add(zone_diff[i], &vm_zone_stat[i]); - changes++; - } - - for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) - if (node_diff[i]) { - atomic_long_add(node_diff[i], &vm_node_stat[i]); - changes++; - } - return changes; -} - -/* - * Update the zone counters for the current cpu. - * - * Note that refresh_cpu_vm_stats strives to only access - * node local memory. The per cpu pagesets on remote zones are placed - * in the memory local to the processor using that pageset. So the - * loop over all zones will access a series of cachelines local to - * the processor. - * - * The call to zone_page_state_add updates the cachelines with the - * statistics in the remote zone struct as well as the global cachelines - * with the global counters. These could cause remote node cache line - * bouncing and will have to be only done when necessary. - * - * The function returns the number of global counters updated. - */ -static int refresh_cpu_vm_stats(bool do_pagesets) -{ - struct pglist_data *pgdat; - struct zone *zone; - int i; - int global_zone_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, }; - int global_node_diff[NR_VM_NODE_STAT_ITEMS] = { 0, }; - int changes = 0; - - for_each_populated_zone(zone) { - struct per_cpu_pageset __percpu *p = zone->pageset; - - for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) { - int v; - - v = this_cpu_xchg(p->vm_stat_diff[i], 0); - if (v) { - - atomic_long_add(v, &zone->vm_stat[i]); - global_zone_diff[i] += v; -#ifdef CONFIG_NUMA - /* 3 seconds idle till flush */ - __this_cpu_write(p->expire, 3); -#endif - } - } -#ifdef CONFIG_NUMA - if (do_pagesets) { - cond_resched(); - /* - * Deal with draining the remote pageset of this - * processor - * - * Check if there are pages remaining in this pageset - * if not then there is nothing to expire. - */ - if (!__this_cpu_read(p->expire) || - !__this_cpu_read(p->pcp.count)) - continue; - - /* - * We never drain zones local to this processor. - */ - if (zone_to_nid(zone) == numa_node_id()) { - __this_cpu_write(p->expire, 0); - continue; - } - - if (__this_cpu_dec_return(p->expire)) - continue; - - if (__this_cpu_read(p->pcp.count)) { - drain_zone_pages(zone, this_cpu_ptr(&p->pcp)); - changes++; - } - } -#endif - } - - for_each_online_pgdat(pgdat) { - struct per_cpu_nodestat __percpu *p = pgdat->per_cpu_nodestats; - - for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) { - int v; - - v = this_cpu_xchg(p->vm_node_stat_diff[i], 0); - if (v) { - atomic_long_add(v, &pgdat->vm_stat[i]); - global_node_diff[i] += v; - } - } - } - - changes += fold_diff(global_zone_diff, global_node_diff); - return changes; -} - -/* - * Fold the data for an offline cpu into the global array. - * There cannot be any access by the offline cpu and therefore - * synchronization is simplified. - */ -void cpu_vm_stats_fold(int cpu) -{ - struct pglist_data *pgdat; - struct zone *zone; - int i; - int global_zone_diff[NR_VM_ZONE_STAT_ITEMS] = { 0, }; - int global_node_diff[NR_VM_NODE_STAT_ITEMS] = { 0, }; - - for_each_populated_zone(zone) { - struct per_cpu_pageset *p; - - p = per_cpu_ptr(zone->pageset, cpu); - - for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) - if (p->vm_stat_diff[i]) { - int v; - - v = p->vm_stat_diff[i]; - p->vm_stat_diff[i] = 0; - atomic_long_add(v, &zone->vm_stat[i]); - global_zone_diff[i] += v; - } - } - - for_each_online_pgdat(pgdat) { - struct per_cpu_nodestat *p; - - p = per_cpu_ptr(pgdat->per_cpu_nodestats, cpu); - - for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) - if (p->vm_node_stat_diff[i]) { - int v; - - v = p->vm_node_stat_diff[i]; - p->vm_node_stat_diff[i] = 0; - atomic_long_add(v, &pgdat->vm_stat[i]); - global_node_diff[i] += v; - } - } - - fold_diff(global_zone_diff, global_node_diff); -} - -/* - * this is only called if !populated_zone(zone), which implies no other users of - * pset->vm_stat_diff[] exsist. - */ -void drain_zonestat(struct zone *zone, struct per_cpu_pageset *pset) -{ - int i; - - for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) - if (pset->vm_stat_diff[i]) { - int v = pset->vm_stat_diff[i]; - pset->vm_stat_diff[i] = 0; - atomic_long_add(v, &zone->vm_stat[i]); - atomic_long_add(v, &vm_zone_stat[i]); - } -} -#endif - -#ifdef CONFIG_NUMA -/* - * Determine the per node value of a stat item. This function - * is called frequently in a NUMA machine, so try to be as - * frugal as possible. - */ -unsigned long sum_zone_node_page_state(int node, - enum zone_stat_item item) -{ - struct zone *zones = NODE_DATA(node)->node_zones; - int i; - unsigned long count = 0; - - for (i = 0; i < MAX_NR_ZONES; i++) - count += zone_page_state(zones + i, item); - - return count; -} - -/* - * Determine the per node value of a stat item. - */ -unsigned long node_page_state(struct pglist_data *pgdat, - enum node_stat_item item) -{ - long x = atomic_long_read(&pgdat->vm_stat[item]); -#ifdef CONFIG_SMP - if (x < 0) - x = 0; -#endif - return x; -} -#endif - -#ifdef CONFIG_COMPACTION - -struct contig_page_info { - unsigned long free_pages; - unsigned long free_blocks_total; - unsigned long free_blocks_suitable; -}; - -/* - * Calculate the number of free pages in a zone, how many contiguous - * pages are free and how many are large enough to satisfy an allocation of - * the target size. Note that this function makes no attempt to estimate - * how many suitable free blocks there *might* be if MOVABLE pages were - * migrated. Calculating that is possible, but expensive and can be - * figured out from userspace - */ -static void fill_contig_page_info(struct zone *zone, - unsigned int suitable_order, - struct contig_page_info *info) -{ - unsigned int order; - - info->free_pages = 0; - info->free_blocks_total = 0; - info->free_blocks_suitable = 0; - - for (order = 0; order < MAX_ORDER; order++) { - unsigned long blocks; - - /* Count number of free blocks */ - blocks = zone->free_area[order].nr_free; - info->free_blocks_total += blocks; - - /* Count free base pages */ - info->free_pages += blocks << order; - - /* Count the suitable free blocks */ - if (order >= suitable_order) - info->free_blocks_suitable += blocks << - (order - suitable_order); - } -} - -/* - * A fragmentation index only makes sense if an allocation of a requested - * size would fail. If that is true, the fragmentation index indicates - * whether external fragmentation or a lack of memory was the problem. - * The value can be used to determine if page reclaim or compaction - * should be used - */ -static int __fragmentation_index(unsigned int order, struct contig_page_info *info) -{ - unsigned long requested = 1UL << order; - - if (!info->free_blocks_total) - return 0; - - /* Fragmentation index only makes sense when a request would fail */ - if (info->free_blocks_suitable) - return -1000; - - /* - * Index is between 0 and 1 so return within 3 decimal places - * - * 0 => allocation would fail due to lack of memory - * 1 => allocation would fail due to fragmentation - */ - return 1000 - div_u64( (1000+(div_u64(info->free_pages * 1000ULL, requested))), info->free_blocks_total); -} - -/* Same as __fragmentation index but allocs contig_page_info on stack */ -int fragmentation_index(struct zone *zone, unsigned int order) -{ - struct contig_page_info info; - - fill_contig_page_info(zone, order, &info); - return __fragmentation_index(order, &info); -} -#endif - -#if defined(CONFIG_PROC_FS) || defined(CONFIG_SYSFS) || defined(CONFIG_NUMA) -#ifdef CONFIG_ZONE_DMA -#define TEXT_FOR_DMA(xx) xx "_dma", -#else -#define TEXT_FOR_DMA(xx) -#endif - -#ifdef CONFIG_ZONE_DMA32 -#define TEXT_FOR_DMA32(xx) xx "_dma32", -#else -#define TEXT_FOR_DMA32(xx) -#endif - -#ifdef CONFIG_HIGHMEM -#define TEXT_FOR_HIGHMEM(xx) xx "_high", -#else -#define TEXT_FOR_HIGHMEM(xx) -#endif - -#define TEXTS_FOR_ZONES(xx) TEXT_FOR_DMA(xx) TEXT_FOR_DMA32(xx) xx "_normal", \ - TEXT_FOR_HIGHMEM(xx) xx "_movable", - -const char * const vmstat_text[] = { - /* enum zone_stat_item countes */ - "nr_free_pages", - "nr_zone_inactive_anon", - "nr_zone_active_anon", - "nr_zone_inactive_file", - "nr_zone_active_file", - "nr_zone_unevictable", - "nr_zone_write_pending", - "nr_mlock", - "nr_slab_reclaimable", - "nr_slab_unreclaimable", - "nr_page_table_pages", - "nr_kernel_stack", - "nr_bounce", -#if IS_ENABLED(CONFIG_ZSMALLOC) - "nr_zspages", -#endif -#ifdef CONFIG_NUMA - "numa_hit", - "numa_miss", - "numa_foreign", - "numa_interleave", - "numa_local", - "numa_other", -#endif - "nr_free_cma", - - /* Node-based counters */ - "nr_inactive_anon", - "nr_active_anon", - "nr_inactive_file", - "nr_active_file", - "nr_unevictable", - "nr_isolated_anon", - "nr_isolated_file", - "nr_pages_scanned", - "workingset_refault", - "workingset_activate", - "workingset_nodereclaim", - "nr_anon_pages", - "nr_mapped", - "nr_file_pages", - "nr_dirty", - "nr_writeback", - "nr_writeback_temp", - "nr_shmem", - "nr_shmem_hugepages", - "nr_shmem_pmdmapped", - "nr_anon_transparent_hugepages", - "nr_unstable", - "nr_vmscan_write", - "nr_vmscan_immediate_reclaim", - "nr_dirtied", - "nr_written", - - /* enum writeback_stat_item counters */ - "nr_dirty_threshold", - "nr_dirty_background_threshold", - -#ifdef CONFIG_VM_EVENT_COUNTERS - /* enum vm_event_item counters */ - "pgpgin", - "pgpgout", - "pswpin", - "pswpout", - - TEXTS_FOR_ZONES("pgalloc") - TEXTS_FOR_ZONES("allocstall") - TEXTS_FOR_ZONES("pgskip") - - "pgfree", - "pgactivate", - "pgdeactivate", - - "pgfault", - "pgmajfault", - "pglazyfreed", - - "pgrefill", - "pgsteal_kswapd", - "pgsteal_direct", - "pgscan_kswapd", - "pgscan_direct", - "pgscan_direct_throttle", - -#ifdef CONFIG_NUMA - "zone_reclaim_failed", -#endif - "pginodesteal", - "slabs_scanned", - "kswapd_inodesteal", - "kswapd_low_wmark_hit_quickly", - "kswapd_high_wmark_hit_quickly", - "pageoutrun", - - "pgrotated", - - "drop_pagecache", - "drop_slab", - -#ifdef CONFIG_NUMA_BALANCING - "numa_pte_updates", - "numa_huge_pte_updates", - "numa_hint_faults", - "numa_hint_faults_local", - "numa_pages_migrated", -#endif -#ifdef CONFIG_MIGRATION - "pgmigrate_success", - "pgmigrate_fail", -#endif -#ifdef CONFIG_COMPACTION - "compact_migrate_scanned", - "compact_free_scanned", - "compact_isolated", - "compact_stall", - "compact_fail", - "compact_success", - "compact_daemon_wake", -#endif - -#ifdef CONFIG_HUGETLB_PAGE - "htlb_buddy_alloc_success", - "htlb_buddy_alloc_fail", -#endif - "unevictable_pgs_culled", - "unevictable_pgs_scanned", - "unevictable_pgs_rescued", - "unevictable_pgs_mlocked", - "unevictable_pgs_munlocked", - "unevictable_pgs_cleared", - "unevictable_pgs_stranded", - -#ifdef CONFIG_TRANSPARENT_HUGEPAGE - "thp_fault_alloc", - "thp_fault_fallback", - "thp_collapse_alloc", - "thp_collapse_alloc_failed", - "thp_file_alloc", - "thp_file_mapped", - "thp_split_page", - "thp_split_page_failed", - "thp_deferred_split_page", - "thp_split_pmd", - "thp_zero_page_alloc", - "thp_zero_page_alloc_failed", -#endif -#ifdef CONFIG_MEMORY_BALLOON - "balloon_inflate", - "balloon_deflate", -#ifdef CONFIG_BALLOON_COMPACTION - "balloon_migrate", -#endif -#endif /* CONFIG_MEMORY_BALLOON */ -#ifdef CONFIG_DEBUG_TLBFLUSH -#ifdef CONFIG_SMP - "nr_tlb_remote_flush", - "nr_tlb_remote_flush_received", -#endif /* CONFIG_SMP */ - "nr_tlb_local_flush_all", - "nr_tlb_local_flush_one", -#endif /* CONFIG_DEBUG_TLBFLUSH */ - -#ifdef CONFIG_DEBUG_VM_VMACACHE - "vmacache_find_calls", - "vmacache_find_hits", - "vmacache_full_flushes", -#endif -#endif /* CONFIG_VM_EVENTS_COUNTERS */ -}; -#endif /* CONFIG_PROC_FS || CONFIG_SYSFS || CONFIG_NUMA */ - - -#if (defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMPACTION)) || \ - defined(CONFIG_PROC_FS) -static void *frag_start(struct seq_file *m, loff_t *pos) -{ - pg_data_t *pgdat; - loff_t node = *pos; - - for (pgdat = first_online_pgdat(); - pgdat && node; - pgdat = next_online_pgdat(pgdat)) - --node; - - return pgdat; -} - -static void *frag_next(struct seq_file *m, void *arg, loff_t *pos) -{ - pg_data_t *pgdat = (pg_data_t *)arg; - - (*pos)++; - return next_online_pgdat(pgdat); -} - -static void frag_stop(struct seq_file *m, void *arg) -{ -} - -/* Walk all the zones in a node and print using a callback */ -static void walk_zones_in_node(struct seq_file *m, pg_data_t *pgdat, - void (*print)(struct seq_file *m, pg_data_t *, struct zone *)) -{ - struct zone *zone; - struct zone *node_zones = pgdat->node_zones; - unsigned long flags; - - for (zone = node_zones; zone - node_zones < MAX_NR_ZONES; ++zone) { - if (!populated_zone(zone)) - continue; - - spin_lock_irqsave(&zone->lock, flags); - print(m, pgdat, zone); - spin_unlock_irqrestore(&zone->lock, flags); - } -} -#endif - -#ifdef CONFIG_PROC_FS -static void frag_show_print(struct seq_file *m, pg_data_t *pgdat, - struct zone *zone) -{ - int order; - - seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name); - for (order = 0; order < MAX_ORDER; ++order) - seq_printf(m, "%6lu ", zone->free_area[order].nr_free); - seq_putc(m, '\n'); -} - -/* - * This walks the free areas for each zone. - */ -static int frag_show(struct seq_file *m, void *arg) -{ - pg_data_t *pgdat = (pg_data_t *)arg; - walk_zones_in_node(m, pgdat, frag_show_print); - return 0; -} - -static void pagetypeinfo_showfree_print(struct seq_file *m, - pg_data_t *pgdat, struct zone *zone) -{ - int order, mtype; - - for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) { - seq_printf(m, "Node %4d, zone %8s, type %12s ", - pgdat->node_id, - zone->name, - migratetype_names[mtype]); - for (order = 0; order < MAX_ORDER; ++order) { - unsigned long freecount = 0; - struct free_area *area; - struct list_head *curr; - - area = &(zone->free_area[order]); - - list_for_each(curr, &area->free_list[mtype]) - freecount++; - seq_printf(m, "%6lu ", freecount); - } - seq_putc(m, '\n'); - } -} - -/* Print out the free pages at each order for each migatetype */ -static int pagetypeinfo_showfree(struct seq_file *m, void *arg) -{ - int order; - pg_data_t *pgdat = (pg_data_t *)arg; - - /* Print header */ - seq_printf(m, "%-43s ", "Free pages count per migrate type at order"); - for (order = 0; order < MAX_ORDER; ++order) - seq_printf(m, "%6d ", order); - seq_putc(m, '\n'); - - walk_zones_in_node(m, pgdat, pagetypeinfo_showfree_print); - - return 0; -} - -static void pagetypeinfo_showblockcount_print(struct seq_file *m, - pg_data_t *pgdat, struct zone *zone) -{ - int mtype; - unsigned long pfn; - unsigned long start_pfn = zone->zone_start_pfn; - unsigned long end_pfn = zone_end_pfn(zone); - unsigned long count[MIGRATE_TYPES] = { 0, }; - - for (pfn = start_pfn; pfn < end_pfn; pfn += pageblock_nr_pages) { - struct page *page; - - if (!pfn_valid(pfn)) - continue; - - page = pfn_to_page(pfn); - - /* Watch for unexpected holes punched in the memmap */ - if (!memmap_valid_within(pfn, page, zone)) - continue; - - if (page_zone(page) != zone) - continue; - - mtype = get_pageblock_migratetype(page); - - if (mtype < MIGRATE_TYPES) - count[mtype]++; - } - - /* Print counts */ - seq_printf(m, "Node %d, zone %8s ", pgdat->node_id, zone->name); - for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) - seq_printf(m, "%12lu ", count[mtype]); - seq_putc(m, '\n'); -} - -/* Print out the free pages at each order for each migratetype */ -static int pagetypeinfo_showblockcount(struct seq_file *m, void *arg) -{ - int mtype; - pg_data_t *pgdat = (pg_data_t *)arg; - - seq_printf(m, "\n%-23s", "Number of blocks type "); - for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) - seq_printf(m, "%12s ", migratetype_names[mtype]); - seq_putc(m, '\n'); - walk_zones_in_node(m, pgdat, pagetypeinfo_showblockcount_print); - - return 0; -} - -/* - * Print out the number of pageblocks for each migratetype that contain pages - * of other types. This gives an indication of how well fallbacks are being - * contained by rmqueue_fallback(). It requires information from PAGE_OWNER - * to determine what is going on - */ -static void pagetypeinfo_showmixedcount(struct seq_file *m, pg_data_t *pgdat) -{ -#ifdef CONFIG_PAGE_OWNER - int mtype; - - if (!static_branch_unlikely(&page_owner_inited)) - return; - - drain_all_pages(NULL); - - seq_printf(m, "\n%-23s", "Number of mixed blocks "); - for (mtype = 0; mtype < MIGRATE_TYPES; mtype++) - seq_printf(m, "%12s ", migratetype_names[mtype]); - seq_putc(m, '\n'); - - walk_zones_in_node(m, pgdat, pagetypeinfo_showmixedcount_print); -#endif /* CONFIG_PAGE_OWNER */ -} - -/* - * This prints out statistics in relation to grouping pages by mobility. - * It is expensive to collect so do not constantly read the file. - */ -static int pagetypeinfo_show(struct seq_file *m, void *arg) -{ - pg_data_t *pgdat = (pg_data_t *)arg; - - /* check memoryless node */ - if (!node_state(pgdat->node_id, N_MEMORY)) - return 0; - - seq_printf(m, "Page block order: %d\n", pageblock_order); - seq_printf(m, "Pages per block: %lu\n", pageblock_nr_pages); - seq_putc(m, '\n'); - pagetypeinfo_showfree(m, pgdat); - pagetypeinfo_showblockcount(m, pgdat); - pagetypeinfo_showmixedcount(m, pgdat); - - return 0; -} - -static const struct seq_operations fragmentation_op = { - .start = frag_start, - .next = frag_next, - .stop = frag_stop, - .show = frag_show, -}; - -static int fragmentation_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &fragmentation_op); -} - -static const struct file_operations fragmentation_file_operations = { - .open = fragmentation_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static const struct seq_operations pagetypeinfo_op = { - .start = frag_start, - .next = frag_next, - .stop = frag_stop, - .show = pagetypeinfo_show, -}; - -static int pagetypeinfo_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &pagetypeinfo_op); -} - -static const struct file_operations pagetypeinfo_file_ops = { - .open = pagetypeinfo_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static bool is_zone_first_populated(pg_data_t *pgdat, struct zone *zone) -{ - int zid; - - for (zid = 0; zid < MAX_NR_ZONES; zid++) { - struct zone *compare = &pgdat->node_zones[zid]; - - if (populated_zone(compare)) - return zone == compare; - } - - /* The zone must be somewhere! */ - WARN_ON_ONCE(1); - return false; -} - -static void zoneinfo_show_print(struct seq_file *m, pg_data_t *pgdat, - struct zone *zone) -{ - int i; - seq_printf(m, "Node %d, zone %8s", pgdat->node_id, zone->name); - if (is_zone_first_populated(pgdat, zone)) { - seq_printf(m, "\n per-node stats"); - for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) { - seq_printf(m, "\n %-12s %lu", - vmstat_text[i + NR_VM_ZONE_STAT_ITEMS], - node_page_state(pgdat, i)); - } - } - seq_printf(m, - "\n pages free %lu" - "\n min %lu" - "\n low %lu" - "\n high %lu" - "\n node_scanned %lu" - "\n spanned %lu" - "\n present %lu" - "\n managed %lu", - zone_page_state(zone, NR_FREE_PAGES), - min_wmark_pages(zone), - low_wmark_pages(zone), - high_wmark_pages(zone), - node_page_state(zone->zone_pgdat, NR_PAGES_SCANNED), - zone->spanned_pages, - zone->present_pages, - zone->managed_pages); - - for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) - seq_printf(m, "\n %-12s %lu", vmstat_text[i], - zone_page_state(zone, i)); - - seq_printf(m, - "\n protection: (%ld", - zone->lowmem_reserve[0]); - for (i = 1; i < ARRAY_SIZE(zone->lowmem_reserve); i++) - seq_printf(m, ", %ld", zone->lowmem_reserve[i]); - seq_printf(m, - ")" - "\n pagesets"); - for_each_online_cpu(i) { - struct per_cpu_pageset *pageset; - - pageset = per_cpu_ptr(zone->pageset, i); - seq_printf(m, - "\n cpu: %i" - "\n count: %i" - "\n high: %i" - "\n batch: %i", - i, - pageset->pcp.count, - pageset->pcp.high, - pageset->pcp.batch); -#ifdef CONFIG_SMP - seq_printf(m, "\n vm stats threshold: %d", - pageset->stat_threshold); -#endif - } - seq_printf(m, - "\n node_unreclaimable: %u" - "\n start_pfn: %lu" - "\n node_inactive_ratio: %u", - !pgdat_reclaimable(zone->zone_pgdat), - zone->zone_start_pfn, - zone->zone_pgdat->inactive_ratio); - seq_putc(m, '\n'); -} - -/* - * Output information about zones in @pgdat. - */ -static int zoneinfo_show(struct seq_file *m, void *arg) -{ - pg_data_t *pgdat = (pg_data_t *)arg; - walk_zones_in_node(m, pgdat, zoneinfo_show_print); - return 0; -} - -static const struct seq_operations zoneinfo_op = { - .start = frag_start, /* iterate over all zones. The same as in - * fragmentation. */ - .next = frag_next, - .stop = frag_stop, - .show = zoneinfo_show, -}; - -static int zoneinfo_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &zoneinfo_op); -} - -static const struct file_operations proc_zoneinfo_file_operations = { - .open = zoneinfo_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -enum writeback_stat_item { - NR_DIRTY_THRESHOLD, - NR_DIRTY_BG_THRESHOLD, - NR_VM_WRITEBACK_STAT_ITEMS, -}; - -static void *vmstat_start(struct seq_file *m, loff_t *pos) -{ - unsigned long *v; - int i, stat_items_size; - - if (*pos >= ARRAY_SIZE(vmstat_text)) - return NULL; - stat_items_size = NR_VM_ZONE_STAT_ITEMS * sizeof(unsigned long) + - NR_VM_NODE_STAT_ITEMS * sizeof(unsigned long) + - NR_VM_WRITEBACK_STAT_ITEMS * sizeof(unsigned long); - -#ifdef CONFIG_VM_EVENT_COUNTERS - stat_items_size += sizeof(struct vm_event_state); -#endif - - v = kmalloc(stat_items_size, GFP_KERNEL); - m->private = v; - if (!v) - return ERR_PTR(-ENOMEM); - for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) - v[i] = global_page_state(i); - v += NR_VM_ZONE_STAT_ITEMS; - - for (i = 0; i < NR_VM_NODE_STAT_ITEMS; i++) - v[i] = global_node_page_state(i); - v += NR_VM_NODE_STAT_ITEMS; - - global_dirty_limits(v + NR_DIRTY_BG_THRESHOLD, - v + NR_DIRTY_THRESHOLD); - v += NR_VM_WRITEBACK_STAT_ITEMS; - -#ifdef CONFIG_VM_EVENT_COUNTERS - all_vm_events(v); - v[PGPGIN] /= 2; /* sectors -> kbytes */ - v[PGPGOUT] /= 2; -#endif - return (unsigned long *)m->private + *pos; -} - -static void *vmstat_next(struct seq_file *m, void *arg, loff_t *pos) -{ - (*pos)++; - if (*pos >= ARRAY_SIZE(vmstat_text)) - return NULL; - return (unsigned long *)m->private + *pos; -} - -static int vmstat_show(struct seq_file *m, void *arg) -{ - unsigned long *l = arg; - unsigned long off = l - (unsigned long *)m->private; - - seq_puts(m, vmstat_text[off]); - seq_put_decimal_ull(m, " ", *l); - seq_putc(m, '\n'); - return 0; -} - -static void vmstat_stop(struct seq_file *m, void *arg) -{ - kfree(m->private); - m->private = NULL; -} - -static const struct seq_operations vmstat_op = { - .start = vmstat_start, - .next = vmstat_next, - .stop = vmstat_stop, - .show = vmstat_show, -}; - -static int vmstat_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &vmstat_op); -} - -static const struct file_operations proc_vmstat_file_operations = { - .open = vmstat_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; -#endif /* CONFIG_PROC_FS */ - -#ifdef CONFIG_SMP -static struct workqueue_struct *vmstat_wq; -static DEFINE_PER_CPU(struct delayed_work, vmstat_work); -int sysctl_stat_interval __read_mostly = HZ; - -#ifdef CONFIG_PROC_FS -static void refresh_vm_stats(struct work_struct *work) -{ - refresh_cpu_vm_stats(true); -} - -int vmstat_refresh(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - long val; - int err; - int i; - - /* - * The regular update, every sysctl_stat_interval, may come later - * than expected: leaving a significant amount in per_cpu buckets. - * This is particularly misleading when checking a quantity of HUGE - * pages, immediately after running a test. /proc/sys/vm/stat_refresh, - * which can equally be echo'ed to or cat'ted from (by root), - * can be used to update the stats just before reading them. - * - * Oh, and since global_page_state() etc. are so careful to hide - * transiently negative values, report an error here if any of - * the stats is negative, so we know to go looking for imbalance. - */ - err = schedule_on_each_cpu(refresh_vm_stats); - if (err) - return err; - for (i = 0; i < NR_VM_ZONE_STAT_ITEMS; i++) { - val = atomic_long_read(&vm_zone_stat[i]); - if (val < 0) { - switch (i) { - case NR_PAGES_SCANNED: - /* - * This is often seen to go negative in - * recent kernels, but not to go permanently - * negative. Whilst it would be nicer not to - * have exceptions, rooting them out would be - * another task, of rather low priority. - */ - break; - default: - pr_warn("%s: %s %ld\n", - __func__, vmstat_text[i], val); - err = -EINVAL; - break; - } - } - } - if (err) - return err; - if (write) - *ppos += *lenp; - else - *lenp = 0; - return 0; -} -#endif /* CONFIG_PROC_FS */ - -static void vmstat_update(struct work_struct *w) -{ - if (refresh_cpu_vm_stats(true)) { - /* - * Counters were updated so we expect more updates - * to occur in the future. Keep on running the - * update worker thread. - */ - queue_delayed_work_on(smp_processor_id(), vmstat_wq, - this_cpu_ptr(&vmstat_work), - round_jiffies_relative(sysctl_stat_interval)); - } -} - -/* - * Switch off vmstat processing and then fold all the remaining differentials - * until the diffs stay at zero. The function is used by NOHZ and can only be - * invoked when tick processing is not active. - */ -/* - * Check if the diffs for a certain cpu indicate that - * an update is needed. - */ -static bool need_update(int cpu) -{ - struct zone *zone; - - for_each_populated_zone(zone) { - struct per_cpu_pageset *p = per_cpu_ptr(zone->pageset, cpu); - - BUILD_BUG_ON(sizeof(p->vm_stat_diff[0]) != 1); - /* - * The fast way of checking if there are any vmstat diffs. - * This works because the diffs are byte sized items. - */ - if (memchr_inv(p->vm_stat_diff, 0, NR_VM_ZONE_STAT_ITEMS)) - return true; - - } - return false; -} - -/* - * Switch off vmstat processing and then fold all the remaining differentials - * until the diffs stay at zero. The function is used by NOHZ and can only be - * invoked when tick processing is not active. - */ -void quiet_vmstat(void) -{ - if (system_state != SYSTEM_RUNNING) - return; - - if (!delayed_work_pending(this_cpu_ptr(&vmstat_work))) - return; - - if (!need_update(smp_processor_id())) - return; - - /* - * Just refresh counters and do not care about the pending delayed - * vmstat_update. It doesn't fire that often to matter and canceling - * it would be too expensive from this path. - * vmstat_shepherd will take care about that for us. - */ - refresh_cpu_vm_stats(false); -} - -/* - * Shepherd worker thread that checks the - * differentials of processors that have their worker - * threads for vm statistics updates disabled because of - * inactivity. - */ -static void vmstat_shepherd(struct work_struct *w); - -static DECLARE_DEFERRABLE_WORK(shepherd, vmstat_shepherd); - -static void vmstat_shepherd(struct work_struct *w) -{ - int cpu; - - get_online_cpus(); - /* Check processors whose vmstat worker threads have been disabled */ - for_each_online_cpu(cpu) { - struct delayed_work *dw = &per_cpu(vmstat_work, cpu); - - if (!delayed_work_pending(dw) && need_update(cpu)) - queue_delayed_work_on(cpu, vmstat_wq, dw, 0); - } - put_online_cpus(); - - schedule_delayed_work(&shepherd, - round_jiffies_relative(sysctl_stat_interval)); -} - -static void __init start_shepherd_timer(void) -{ - int cpu; - - for_each_possible_cpu(cpu) - INIT_DEFERRABLE_WORK(per_cpu_ptr(&vmstat_work, cpu), - vmstat_update); - - vmstat_wq = alloc_workqueue("vmstat", WQ_FREEZABLE|WQ_MEM_RECLAIM, 0); - schedule_delayed_work(&shepherd, - round_jiffies_relative(sysctl_stat_interval)); -} - -static void __init init_cpu_node_state(void) -{ - int cpu; - - get_online_cpus(); - for_each_online_cpu(cpu) - node_set_state(cpu_to_node(cpu), N_CPU); - put_online_cpus(); -} - -static void vmstat_cpu_dead(int node) -{ - int cpu; - - get_online_cpus(); - for_each_online_cpu(cpu) - if (cpu_to_node(cpu) == node) - goto end; - - node_clear_state(node, N_CPU); -end: - put_online_cpus(); -} - -/* - * Use the cpu notifier to insure that the thresholds are recalculated - * when necessary. - */ -static int vmstat_cpuup_callback(struct notifier_block *nfb, - unsigned long action, - void *hcpu) -{ - long cpu = (long)hcpu; - - switch (action) { - case CPU_ONLINE: - case CPU_ONLINE_FROZEN: - refresh_zone_stat_thresholds(); - node_set_state(cpu_to_node(cpu), N_CPU); - break; - case CPU_DOWN_PREPARE: - case CPU_DOWN_PREPARE_FROZEN: - cancel_delayed_work_sync(&per_cpu(vmstat_work, cpu)); - break; - case CPU_DOWN_FAILED: - case CPU_DOWN_FAILED_FROZEN: - break; - case CPU_DEAD: - case CPU_DEAD_FROZEN: - refresh_zone_stat_thresholds(); - vmstat_cpu_dead(cpu_to_node(cpu)); - break; - default: - break; - } - return NOTIFY_OK; -} - -static struct notifier_block vmstat_notifier = - { &vmstat_cpuup_callback, NULL, 0 }; -#endif - -static int __init setup_vmstat(void) -{ -#ifdef CONFIG_SMP - cpu_notifier_register_begin(); - __register_cpu_notifier(&vmstat_notifier); - init_cpu_node_state(); - - start_shepherd_timer(); - cpu_notifier_register_done(); -#endif -#ifdef CONFIG_PROC_FS - proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations); - proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops); - proc_create("vmstat", S_IRUGO, NULL, &proc_vmstat_file_operations); - proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations); -#endif - return 0; -} -module_init(setup_vmstat) - -#if defined(CONFIG_DEBUG_FS) && defined(CONFIG_COMPACTION) - -/* - * Return an index indicating how much of the available free memory is - * unusable for an allocation of the requested size. - */ -static int unusable_free_index(unsigned int order, - struct contig_page_info *info) -{ - /* No free memory is interpreted as all free memory is unusable */ - if (info->free_pages == 0) - return 1000; - - /* - * Index should be a value between 0 and 1. Return a value to 3 - * decimal places. - * - * 0 => no fragmentation - * 1 => high fragmentation - */ - return div_u64((info->free_pages - (info->free_blocks_suitable << order)) * 1000ULL, info->free_pages); - -} - -static void unusable_show_print(struct seq_file *m, - pg_data_t *pgdat, struct zone *zone) -{ - unsigned int order; - int index; - struct contig_page_info info; - - seq_printf(m, "Node %d, zone %8s ", - pgdat->node_id, - zone->name); - for (order = 0; order < MAX_ORDER; ++order) { - fill_contig_page_info(zone, order, &info); - index = unusable_free_index(order, &info); - seq_printf(m, "%d.%03d ", index / 1000, index % 1000); - } - - seq_putc(m, '\n'); -} - -/* - * Display unusable free space index - * - * The unusable free space index measures how much of the available free - * memory cannot be used to satisfy an allocation of a given size and is a - * value between 0 and 1. The higher the value, the more of free memory is - * unusable and by implication, the worse the external fragmentation is. This - * can be expressed as a percentage by multiplying by 100. - */ -static int unusable_show(struct seq_file *m, void *arg) -{ - pg_data_t *pgdat = (pg_data_t *)arg; - - /* check memoryless node */ - if (!node_state(pgdat->node_id, N_MEMORY)) - return 0; - - walk_zones_in_node(m, pgdat, unusable_show_print); - - return 0; -} - -static const struct seq_operations unusable_op = { - .start = frag_start, - .next = frag_next, - .stop = frag_stop, - .show = unusable_show, -}; - -static int unusable_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &unusable_op); -} - -static const struct file_operations unusable_file_ops = { - .open = unusable_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static void extfrag_show_print(struct seq_file *m, - pg_data_t *pgdat, struct zone *zone) -{ - unsigned int order; - int index; - - /* Alloc on stack as interrupts are disabled for zone walk */ - struct contig_page_info info; - - seq_printf(m, "Node %d, zone %8s ", - pgdat->node_id, - zone->name); - for (order = 0; order < MAX_ORDER; ++order) { - fill_contig_page_info(zone, order, &info); - index = __fragmentation_index(order, &info); - seq_printf(m, "%d.%03d ", index / 1000, index % 1000); - } - - seq_putc(m, '\n'); -} - -/* - * Display fragmentation index for orders that allocations would fail for - */ -static int extfrag_show(struct seq_file *m, void *arg) -{ - pg_data_t *pgdat = (pg_data_t *)arg; - - walk_zones_in_node(m, pgdat, extfrag_show_print); - - return 0; -} - -static const struct seq_operations extfrag_op = { - .start = frag_start, - .next = frag_next, - .stop = frag_stop, - .show = extfrag_show, -}; - -static int extfrag_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &extfrag_op); -} - -static const struct file_operations extfrag_file_ops = { - .open = extfrag_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static int __init extfrag_debug_init(void) -{ - struct dentry *extfrag_debug_root; - - extfrag_debug_root = debugfs_create_dir("extfrag", NULL); - if (!extfrag_debug_root) - return -ENOMEM; - - if (!debugfs_create_file("unusable_index", 0444, - extfrag_debug_root, NULL, &unusable_file_ops)) - goto fail; - - if (!debugfs_create_file("extfrag_index", 0444, - extfrag_debug_root, NULL, &extfrag_file_ops)) - goto fail; - - return 0; -fail: - debugfs_remove_recursive(extfrag_debug_root); - return -ENOMEM; -} - -module_init(extfrag_debug_init); -#endif diff --git a/src/linux/mm/workingset.c b/src/linux/mm/workingset.c deleted file mode 100644 index fb1f918..0000000 --- a/src/linux/mm/workingset.c +++ /dev/null @@ -1,507 +0,0 @@ -/* - * Workingset detection - * - * Copyright (C) 2013 Red Hat, Inc., Johannes Weiner - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Double CLOCK lists - * - * Per node, two clock lists are maintained for file pages: the - * inactive and the active list. Freshly faulted pages start out at - * the head of the inactive list and page reclaim scans pages from the - * tail. Pages that are accessed multiple times on the inactive list - * are promoted to the active list, to protect them from reclaim, - * whereas active pages are demoted to the inactive list when the - * active list grows too big. - * - * fault ------------------------+ - * | - * +--------------+ | +-------------+ - * reclaim <- | inactive | <-+-- demotion | active | <--+ - * +--------------+ +-------------+ | - * | | - * +-------------- promotion ------------------+ - * - * - * Access frequency and refault distance - * - * A workload is thrashing when its pages are frequently used but they - * are evicted from the inactive list every time before another access - * would have promoted them to the active list. - * - * In cases where the average access distance between thrashing pages - * is bigger than the size of memory there is nothing that can be - * done - the thrashing set could never fit into memory under any - * circumstance. - * - * However, the average access distance could be bigger than the - * inactive list, yet smaller than the size of memory. In this case, - * the set could fit into memory if it weren't for the currently - * active pages - which may be used more, hopefully less frequently: - * - * +-memory available to cache-+ - * | | - * +-inactive------+-active----+ - * a b | c d e f g h i | J K L M N | - * +---------------+-----------+ - * - * It is prohibitively expensive to accurately track access frequency - * of pages. But a reasonable approximation can be made to measure - * thrashing on the inactive list, after which refaulting pages can be - * activated optimistically to compete with the existing active pages. - * - * Approximating inactive page access frequency - Observations: - * - * 1. When a page is accessed for the first time, it is added to the - * head of the inactive list, slides every existing inactive page - * towards the tail by one slot, and pushes the current tail page - * out of memory. - * - * 2. When a page is accessed for the second time, it is promoted to - * the active list, shrinking the inactive list by one slot. This - * also slides all inactive pages that were faulted into the cache - * more recently than the activated page towards the tail of the - * inactive list. - * - * Thus: - * - * 1. The sum of evictions and activations between any two points in - * time indicate the minimum number of inactive pages accessed in - * between. - * - * 2. Moving one inactive page N page slots towards the tail of the - * list requires at least N inactive page accesses. - * - * Combining these: - * - * 1. When a page is finally evicted from memory, the number of - * inactive pages accessed while the page was in cache is at least - * the number of page slots on the inactive list. - * - * 2. In addition, measuring the sum of evictions and activations (E) - * at the time of a page's eviction, and comparing it to another - * reading (R) at the time the page faults back into memory tells - * the minimum number of accesses while the page was not cached. - * This is called the refault distance. - * - * Because the first access of the page was the fault and the second - * access the refault, we combine the in-cache distance with the - * out-of-cache distance to get the complete minimum access distance - * of this page: - * - * NR_inactive + (R - E) - * - * And knowing the minimum access distance of a page, we can easily - * tell if the page would be able to stay in cache assuming all page - * slots in the cache were available: - * - * NR_inactive + (R - E) <= NR_inactive + NR_active - * - * which can be further simplified to - * - * (R - E) <= NR_active - * - * Put into words, the refault distance (out-of-cache) can be seen as - * a deficit in inactive list space (in-cache). If the inactive list - * had (R - E) more page slots, the page would not have been evicted - * in between accesses, but activated instead. And on a full system, - * the only thing eating into inactive list space is active pages. - * - * - * Activating refaulting pages - * - * All that is known about the active list is that the pages have been - * accessed more than once in the past. This means that at any given - * time there is actually a good chance that pages on the active list - * are no longer in active use. - * - * So when a refault distance of (R - E) is observed and there are at - * least (R - E) active pages, the refaulting page is activated - * optimistically in the hope that (R - E) active pages are actually - * used less frequently than the refaulting page - or even not used at - * all anymore. - * - * If this is wrong and demotion kicks in, the pages which are truly - * used more frequently will be reactivated while the less frequently - * used once will be evicted from memory. - * - * But if this is right, the stale pages will be pushed out of memory - * and the used pages get to stay in cache. - * - * - * Implementation - * - * For each node's file LRU lists, a counter for inactive evictions - * and activations is maintained (node->inactive_age). - * - * On eviction, a snapshot of this counter (along with some bits to - * identify the node) is stored in the now empty page cache radix tree - * slot of the evicted page. This is called a shadow entry. - * - * On cache misses for which there are shadow entries, an eligible - * refault distance will immediately activate the refaulting page. - */ - -#define EVICTION_SHIFT (RADIX_TREE_EXCEPTIONAL_ENTRY + \ - NODES_SHIFT + \ - MEM_CGROUP_ID_SHIFT) -#define EVICTION_MASK (~0UL >> EVICTION_SHIFT) - -/* - * Eviction timestamps need to be able to cover the full range of - * actionable refaults. However, bits are tight in the radix tree - * entry, and after storing the identifier for the lruvec there might - * not be enough left to represent every single actionable refault. In - * that case, we have to sacrifice granularity for distance, and group - * evictions into coarser buckets by shaving off lower timestamp bits. - */ -static unsigned int bucket_order __read_mostly; - -static void *pack_shadow(int memcgid, pg_data_t *pgdat, unsigned long eviction) -{ - eviction >>= bucket_order; - eviction = (eviction << MEM_CGROUP_ID_SHIFT) | memcgid; - eviction = (eviction << NODES_SHIFT) | pgdat->node_id; - eviction = (eviction << RADIX_TREE_EXCEPTIONAL_SHIFT); - - return (void *)(eviction | RADIX_TREE_EXCEPTIONAL_ENTRY); -} - -static void unpack_shadow(void *shadow, int *memcgidp, pg_data_t **pgdat, - unsigned long *evictionp) -{ - unsigned long entry = (unsigned long)shadow; - int memcgid, nid; - - entry >>= RADIX_TREE_EXCEPTIONAL_SHIFT; - nid = entry & ((1UL << NODES_SHIFT) - 1); - entry >>= NODES_SHIFT; - memcgid = entry & ((1UL << MEM_CGROUP_ID_SHIFT) - 1); - entry >>= MEM_CGROUP_ID_SHIFT; - - *memcgidp = memcgid; - *pgdat = NODE_DATA(nid); - *evictionp = entry << bucket_order; -} - -/** - * workingset_eviction - note the eviction of a page from memory - * @mapping: address space the page was backing - * @page: the page being evicted - * - * Returns a shadow entry to be stored in @mapping->page_tree in place - * of the evicted @page so that a later refault can be detected. - */ -void *workingset_eviction(struct address_space *mapping, struct page *page) -{ - struct mem_cgroup *memcg = page_memcg(page); - struct pglist_data *pgdat = page_pgdat(page); - int memcgid = mem_cgroup_id(memcg); - unsigned long eviction; - struct lruvec *lruvec; - - /* Page is fully exclusive and pins page->mem_cgroup */ - VM_BUG_ON_PAGE(PageLRU(page), page); - VM_BUG_ON_PAGE(page_count(page), page); - VM_BUG_ON_PAGE(!PageLocked(page), page); - - lruvec = mem_cgroup_lruvec(pgdat, memcg); - eviction = atomic_long_inc_return(&lruvec->inactive_age); - return pack_shadow(memcgid, pgdat, eviction); -} - -/** - * workingset_refault - evaluate the refault of a previously evicted page - * @shadow: shadow entry of the evicted page - * - * Calculates and evaluates the refault distance of the previously - * evicted page in the context of the node it was allocated in. - * - * Returns %true if the page should be activated, %false otherwise. - */ -bool workingset_refault(void *shadow) -{ - unsigned long refault_distance; - unsigned long active_file; - struct mem_cgroup *memcg; - unsigned long eviction; - struct lruvec *lruvec; - unsigned long refault; - struct pglist_data *pgdat; - int memcgid; - - unpack_shadow(shadow, &memcgid, &pgdat, &eviction); - - rcu_read_lock(); - /* - * Look up the memcg associated with the stored ID. It might - * have been deleted since the page's eviction. - * - * Note that in rare events the ID could have been recycled - * for a new cgroup that refaults a shared page. This is - * impossible to tell from the available data. However, this - * should be a rare and limited disturbance, and activations - * are always speculative anyway. Ultimately, it's the aging - * algorithm's job to shake out the minimum access frequency - * for the active cache. - * - * XXX: On !CONFIG_MEMCG, this will always return NULL; it - * would be better if the root_mem_cgroup existed in all - * configurations instead. - */ - memcg = mem_cgroup_from_id(memcgid); - if (!mem_cgroup_disabled() && !memcg) { - rcu_read_unlock(); - return false; - } - lruvec = mem_cgroup_lruvec(pgdat, memcg); - refault = atomic_long_read(&lruvec->inactive_age); - active_file = lruvec_lru_size(lruvec, LRU_ACTIVE_FILE); - rcu_read_unlock(); - - /* - * The unsigned subtraction here gives an accurate distance - * across inactive_age overflows in most cases. - * - * There is a special case: usually, shadow entries have a - * short lifetime and are either refaulted or reclaimed along - * with the inode before they get too old. But it is not - * impossible for the inactive_age to lap a shadow entry in - * the field, which can then can result in a false small - * refault distance, leading to a false activation should this - * old entry actually refault again. However, earlier kernels - * used to deactivate unconditionally with *every* reclaim - * invocation for the longest time, so the occasional - * inappropriate activation leading to pressure on the active - * list is not a problem. - */ - refault_distance = (refault - eviction) & EVICTION_MASK; - - inc_node_state(pgdat, WORKINGSET_REFAULT); - - if (refault_distance <= active_file) { - inc_node_state(pgdat, WORKINGSET_ACTIVATE); - return true; - } - return false; -} - -/** - * workingset_activation - note a page activation - * @page: page that is being activated - */ -void workingset_activation(struct page *page) -{ - struct mem_cgroup *memcg; - struct lruvec *lruvec; - - rcu_read_lock(); - /* - * Filter non-memcg pages here, e.g. unmap can call - * mark_page_accessed() on VDSO pages. - * - * XXX: See workingset_refault() - this should return - * root_mem_cgroup even for !CONFIG_MEMCG. - */ - memcg = page_memcg_rcu(page); - if (!mem_cgroup_disabled() && !memcg) - goto out; - lruvec = mem_cgroup_lruvec(page_pgdat(page), memcg); - atomic_long_inc(&lruvec->inactive_age); -out: - rcu_read_unlock(); -} - -/* - * Shadow entries reflect the share of the working set that does not - * fit into memory, so their number depends on the access pattern of - * the workload. In most cases, they will refault or get reclaimed - * along with the inode, but a (malicious) workload that streams - * through files with a total size several times that of available - * memory, while preventing the inodes from being reclaimed, can - * create excessive amounts of shadow nodes. To keep a lid on this, - * track shadow nodes and reclaim them when they grow way past the - * point where they would still be useful. - */ - -struct list_lru workingset_shadow_nodes; - -static unsigned long count_shadow_nodes(struct shrinker *shrinker, - struct shrink_control *sc) -{ - unsigned long shadow_nodes; - unsigned long max_nodes; - unsigned long pages; - - /* list_lru lock nests inside IRQ-safe mapping->tree_lock */ - local_irq_disable(); - shadow_nodes = list_lru_shrink_count(&workingset_shadow_nodes, sc); - local_irq_enable(); - - if (sc->memcg) { - pages = mem_cgroup_node_nr_lru_pages(sc->memcg, sc->nid, - LRU_ALL_FILE); - } else { - pages = node_page_state(NODE_DATA(sc->nid), NR_ACTIVE_FILE) + - node_page_state(NODE_DATA(sc->nid), NR_INACTIVE_FILE); - } - - /* - * Active cache pages are limited to 50% of memory, and shadow - * entries that represent a refault distance bigger than that - * do not have any effect. Limit the number of shadow nodes - * such that shadow entries do not exceed the number of active - * cache pages, assuming a worst-case node population density - * of 1/8th on average. - * - * On 64-bit with 7 radix_tree_nodes per page and 64 slots - * each, this will reclaim shadow entries when they consume - * ~2% of available memory: - * - * PAGE_SIZE / radix_tree_nodes / node_entries / PAGE_SIZE - */ - max_nodes = pages >> (1 + RADIX_TREE_MAP_SHIFT - 3); - - if (shadow_nodes <= max_nodes) - return 0; - - return shadow_nodes - max_nodes; -} - -static enum lru_status shadow_lru_isolate(struct list_head *item, - struct list_lru_one *lru, - spinlock_t *lru_lock, - void *arg) -{ - struct address_space *mapping; - struct radix_tree_node *node; - unsigned int i; - int ret; - - /* - * Page cache insertions and deletions synchroneously maintain - * the shadow node LRU under the mapping->tree_lock and the - * lru_lock. Because the page cache tree is emptied before - * the inode can be destroyed, holding the lru_lock pins any - * address_space that has radix tree nodes on the LRU. - * - * We can then safely transition to the mapping->tree_lock to - * pin only the address_space of the particular node we want - * to reclaim, take the node off-LRU, and drop the lru_lock. - */ - - node = container_of(item, struct radix_tree_node, private_list); - mapping = node->private_data; - - /* Coming from the list, invert the lock order */ - if (!spin_trylock(&mapping->tree_lock)) { - spin_unlock(lru_lock); - ret = LRU_RETRY; - goto out; - } - - list_lru_isolate(lru, item); - spin_unlock(lru_lock); - - /* - * The nodes should only contain one or more shadow entries, - * no pages, so we expect to be able to remove them all and - * delete and free the empty node afterwards. - */ - BUG_ON(!workingset_node_shadows(node)); - BUG_ON(workingset_node_pages(node)); - - for (i = 0; i < RADIX_TREE_MAP_SIZE; i++) { - if (node->slots[i]) { - BUG_ON(!radix_tree_exceptional_entry(node->slots[i])); - node->slots[i] = NULL; - workingset_node_shadows_dec(node); - BUG_ON(!mapping->nrexceptional); - mapping->nrexceptional--; - } - } - BUG_ON(workingset_node_shadows(node)); - inc_node_state(page_pgdat(virt_to_page(node)), WORKINGSET_NODERECLAIM); - if (!__radix_tree_delete_node(&mapping->page_tree, node)) - BUG(); - - spin_unlock(&mapping->tree_lock); - ret = LRU_REMOVED_RETRY; -out: - local_irq_enable(); - cond_resched(); - local_irq_disable(); - spin_lock(lru_lock); - return ret; -} - -static unsigned long scan_shadow_nodes(struct shrinker *shrinker, - struct shrink_control *sc) -{ - unsigned long ret; - - /* list_lru lock nests inside IRQ-safe mapping->tree_lock */ - local_irq_disable(); - ret = list_lru_shrink_walk(&workingset_shadow_nodes, sc, - shadow_lru_isolate, NULL); - local_irq_enable(); - return ret; -} - -static struct shrinker workingset_shadow_shrinker = { - .count_objects = count_shadow_nodes, - .scan_objects = scan_shadow_nodes, - .seeks = DEFAULT_SEEKS, - .flags = SHRINKER_NUMA_AWARE | SHRINKER_MEMCG_AWARE, -}; - -/* - * Our list_lru->lock is IRQ-safe as it nests inside the IRQ-safe - * mapping->tree_lock. - */ -static struct lock_class_key shadow_nodes_key; - -static int __init workingset_init(void) -{ - unsigned int timestamp_bits; - unsigned int max_order; - int ret; - - BUILD_BUG_ON(BITS_PER_LONG < EVICTION_SHIFT); - /* - * Calculate the eviction bucket size to cover the longest - * actionable refault distance, which is currently half of - * memory (totalram_pages/2). However, memory hotplug may add - * some more pages at runtime, so keep working with up to - * double the initial memory by using totalram_pages as-is. - */ - timestamp_bits = BITS_PER_LONG - EVICTION_SHIFT; - max_order = fls_long(totalram_pages - 1); - if (max_order > timestamp_bits) - bucket_order = max_order - timestamp_bits; - pr_info("workingset: timestamp_bits=%d max_order=%d bucket_order=%u\n", - timestamp_bits, max_order, bucket_order); - - ret = list_lru_init_key(&workingset_shadow_nodes, &shadow_nodes_key); - if (ret) - goto err; - ret = register_shrinker(&workingset_shadow_shrinker); - if (ret) - goto err_list_lru; - return 0; -err_list_lru: - list_lru_destroy(&workingset_shadow_nodes); -err: - return ret; -} -module_init(workingset_init); diff --git a/src/linux/net/6lowpan/Kconfig b/src/linux/net/6lowpan/Kconfig deleted file mode 100644 index 9c05151..0000000 --- a/src/linux/net/6lowpan/Kconfig +++ /dev/null @@ -1,104 +0,0 @@ -menuconfig 6LOWPAN - tristate "6LoWPAN Support" - depends on IPV6 - ---help--- - This enables IPv6 over Low power Wireless Personal Area Network - - "6LoWPAN" which is supported by IEEE 802.15.4 or Bluetooth stacks. - -config 6LOWPAN_DEBUGFS - bool "6LoWPAN debugfs support" - depends on 6LOWPAN - depends on DEBUG_FS - ---help--- - This enables 6LoWPAN debugfs support. For example to manipulate - IPHC context information at runtime. - -menuconfig 6LOWPAN_NHC - tristate "Next Header and Generic Header Compression Support" - depends on 6LOWPAN - default y - ---help--- - Support for next header and generic header compression defined in - RFC6282 and RFC7400. - -if 6LOWPAN_NHC - -config 6LOWPAN_NHC_DEST - tristate "Destination Options Header Support" - default y - ---help--- - 6LoWPAN IPv6 Destination Options Header compression according to - RFC6282. - -config 6LOWPAN_NHC_FRAGMENT - tristate "Fragment Header Support" - default y - ---help--- - 6LoWPAN IPv6 Fragment Header compression according to RFC6282. - -config 6LOWPAN_NHC_HOP - tristate "Hop-by-Hop Options Header Support" - default y - ---help--- - 6LoWPAN IPv6 Hop-by-Hop Options Header compression according to - RFC6282. - -config 6LOWPAN_NHC_IPV6 - tristate "IPv6 Header Support" - default y - ---help--- - 6LoWPAN IPv6 Header compression according to RFC6282. - -config 6LOWPAN_NHC_MOBILITY - tristate "Mobility Header Support" - default y - ---help--- - 6LoWPAN IPv6 Mobility Header compression according to RFC6282. - -config 6LOWPAN_NHC_ROUTING - tristate "Routing Header Support" - default y - ---help--- - 6LoWPAN IPv6 Routing Header compression according to RFC6282. - -config 6LOWPAN_NHC_UDP - tristate "UDP Header Support" - default y - ---help--- - 6LoWPAN IPv6 UDP Header compression according to RFC6282. - -config 6LOWPAN_GHC_EXT_HDR_HOP - tristate "GHC Hop-by-Hop Options Header Support" - ---help--- - 6LoWPAN IPv6 Hop-by-Hop option generic header compression according - to RFC7400. - -config 6LOWPAN_GHC_UDP - tristate "GHC UDP Support" - ---help--- - 6LoWPAN IPv6 UDP generic header compression according to RFC7400. - -config 6LOWPAN_GHC_ICMPV6 - tristate "GHC ICMPv6 Support" - ---help--- - 6LoWPAN IPv6 ICMPv6 generic header compression according to RFC7400. - -config 6LOWPAN_GHC_EXT_HDR_DEST - tristate "GHC Destination Options Header Support" - ---help--- - 6LoWPAN IPv6 destination option generic header compression according - to RFC7400. - -config 6LOWPAN_GHC_EXT_HDR_FRAG - tristate "GHC Fragmentation Options Header Support" - ---help--- - 6LoWPAN IPv6 fragmentation option generic header compression - according to RFC7400. - -config 6LOWPAN_GHC_EXT_HDR_ROUTE - tristate "GHC Routing Options Header Support" - ---help--- - 6LoWPAN IPv6 routing option generic header compression according - to RFC7400. - -endif diff --git a/src/linux/net/802/Kconfig b/src/linux/net/802/Kconfig deleted file mode 100644 index 80d4bf7..0000000 --- a/src/linux/net/802/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config STP - tristate - select LLC - -config GARP - tristate - select STP - -config MRP - tristate diff --git a/src/linux/net/802/Makefile b/src/linux/net/802/Makefile deleted file mode 100644 index 37e654d..0000000 --- a/src/linux/net/802/Makefile +++ /dev/null @@ -1,14 +0,0 @@ -# -# Makefile for the Linux 802.x protocol layers. -# - -# Check the p8022 selections against net/core/Makefile. -obj-$(CONFIG_LLC) += p8022.o psnap.o -obj-$(CONFIG_NET_FC) += fc.o -obj-$(CONFIG_FDDI) += fddi.o -obj-$(CONFIG_HIPPI) += hippi.o -obj-$(CONFIG_IPX) += p8022.o psnap.o p8023.o -obj-$(CONFIG_ATALK) += p8022.o psnap.o -obj-$(CONFIG_STP) += stp.o -obj-$(CONFIG_GARP) += garp.o -obj-$(CONFIG_MRP) += mrp.o diff --git a/src/linux/net/8021q/Kconfig b/src/linux/net/8021q/Kconfig deleted file mode 100644 index 4232018..0000000 --- a/src/linux/net/8021q/Kconfig +++ /dev/null @@ -1,40 +0,0 @@ -# -# Configuration for 802.1Q VLAN support -# - -config VLAN_8021Q - tristate "802.1Q/802.1ad VLAN Support" - ---help--- - Select this and you will be able to create 802.1Q VLAN interfaces - on your Ethernet interfaces. 802.1Q VLAN supports almost - everything a regular Ethernet interface does, including - firewalling, bridging, and of course IP traffic. You will need - the 'ip' utility in order to effectively use VLANs. - See the VLAN web page for more information: - - - To compile this code as a module, choose M here: the module - will be called 8021q. - - If unsure, say N. - -config VLAN_8021Q_GVRP - bool "GVRP (GARP VLAN Registration Protocol) support" - depends on VLAN_8021Q - select GARP - help - Select this to enable GVRP end-system support. GVRP is used for - automatic propagation of registered VLANs to switches. - - If unsure, say N. - -config VLAN_8021Q_MVRP - bool "MVRP (Multiple VLAN Registration Protocol) support" - depends on VLAN_8021Q - select MRP - help - Select this to enable MVRP end-system support. MVRP is used for - automatic propagation of registered VLANs to switches; it - supersedes GVRP and is not backwards-compatible. - - If unsure, say N. diff --git a/src/linux/net/9p/Kconfig b/src/linux/net/9p/Kconfig deleted file mode 100644 index a75174a..0000000 --- a/src/linux/net/9p/Kconfig +++ /dev/null @@ -1,36 +0,0 @@ -# -# 9P protocol configuration -# - -menuconfig NET_9P - depends on NET - tristate "Plan 9 Resource Sharing Support (9P2000)" - help - If you say Y here, you will get experimental support for - Plan 9 resource sharing via the 9P2000 protocol. - - See for more information. - - If unsure, say N. - -if NET_9P - -config NET_9P_VIRTIO - depends on VIRTIO - tristate "9P Virtio Transport" - help - This builds support for a transports between - guest partitions and a host partition. - -config NET_9P_RDMA - depends on INET && INFINIBAND && INFINIBAND_ADDR_TRANS - tristate "9P RDMA Transport (Experimental)" - help - This builds support for an RDMA transport. - -config NET_9P_DEBUG - bool "Debug information" - help - Say Y if you want the 9P subsystem to log debug information. - -endif diff --git a/src/linux/net/Kconfig b/src/linux/net/Kconfig deleted file mode 100644 index 7b6cd34..0000000 --- a/src/linux/net/Kconfig +++ /dev/null @@ -1,437 +0,0 @@ -# -# Network configuration -# - -menuconfig NET - bool "Networking support" - select NLATTR - select GENERIC_NET_UTILS - select BPF - ---help--- - Unless you really know what you are doing, you should say Y here. - The reason is that some programs need kernel networking support even - when running on a stand-alone machine that isn't connected to any - other computer. - - If you are upgrading from an older kernel, you - should consider updating your networking tools too because changes - in the kernel and the tools often go hand in hand. The tools are - contained in the package net-tools, the location and version number - of which are given in . - - For a general introduction to Linux networking, it is highly - recommended to read the NET-HOWTO, available from - . - -if NET - -config WANT_COMPAT_NETLINK_MESSAGES - bool - help - This option can be selected by other options that need compat - netlink messages. - -config COMPAT_NETLINK_MESSAGES - def_bool y - depends on COMPAT - depends on WEXT_CORE || WANT_COMPAT_NETLINK_MESSAGES - help - This option makes it possible to send different netlink messages - to tasks depending on whether the task is a compat task or not. To - achieve this, you need to set skb_shinfo(skb)->frag_list to the - compat skb before sending the skb, the netlink code will sort out - which message to actually pass to the task. - - Newly written code should NEVER need this option but do - compat-independent messages instead! - -config NET_INGRESS - bool - -config NET_EGRESS - bool - -menu "Networking options" - -source "net/packet/Kconfig" -source "net/unix/Kconfig" -source "net/xfrm/Kconfig" -source "net/iucv/Kconfig" - -config INET - bool "TCP/IP networking" - select CRYPTO - select CRYPTO_AES - ---help--- - These are the protocols used on the Internet and on most local - Ethernets. It is highly recommended to say Y here (this will enlarge - your kernel by about 400 KB), since some programs (e.g. the X window - system) use TCP/IP even if your machine is not connected to any - other computer. You will get the so-called loopback device which - allows you to ping yourself (great fun, that!). - - For an excellent introduction to Linux networking, please read the - Linux Networking HOWTO, available from - . - - If you say Y here and also to "/proc file system support" and - "Sysctl support" below, you can change various aspects of the - behavior of the TCP/IP code by writing to the (virtual) files in - /proc/sys/net/ipv4/*; the options are explained in the file - . - - Short answer: say Y. - -if INET -source "net/ipv4/Kconfig" -source "net/ipv6/Kconfig" -source "net/netlabel/Kconfig" - -endif # if INET - -config NETWORK_SECMARK - bool "Security Marking" - help - This enables security marking of network packets, similar - to nfmark, but designated for security purposes. - If you are unsure how to answer this question, answer N. - -config NET_PTP_CLASSIFY - def_bool n - -config NETWORK_PHY_TIMESTAMPING - bool "Timestamping in PHY devices" - select NET_PTP_CLASSIFY - help - This allows timestamping of network packets by PHYs with - hardware timestamping capabilities. This option adds some - overhead in the transmit and receive paths. - - If you are unsure how to answer this question, answer N. - -menuconfig NETFILTER - bool "Network packet filtering framework (Netfilter)" - ---help--- - Netfilter is a framework for filtering and mangling network packets - that pass through your Linux box. - - The most common use of packet filtering is to run your Linux box as - a firewall protecting a local network from the Internet. The type of - firewall provided by this kernel support is called a "packet - filter", which means that it can reject individual network packets - based on type, source, destination etc. The other kind of firewall, - a "proxy-based" one, is more secure but more intrusive and more - bothersome to set up; it inspects the network traffic much more - closely, modifies it and has knowledge about the higher level - protocols, which a packet filter lacks. Moreover, proxy-based - firewalls often require changes to the programs running on the local - clients. Proxy-based firewalls don't need support by the kernel, but - they are often combined with a packet filter, which only works if - you say Y here. - - You should also say Y here if you intend to use your Linux box as - the gateway to the Internet for a local network of machines without - globally valid IP addresses. This is called "masquerading": if one - of the computers on your local network wants to send something to - the outside, your box can "masquerade" as that computer, i.e. it - forwards the traffic to the intended outside destination, but - modifies the packets to make it look like they came from the - firewall box itself. It works both ways: if the outside host - replies, the Linux box will silently forward the traffic to the - correct local computer. This way, the computers on your local net - are completely invisible to the outside world, even though they can - reach the outside and can receive replies. It is even possible to - run globally visible servers from within a masqueraded local network - using a mechanism called portforwarding. Masquerading is also often - called NAT (Network Address Translation). - - Another use of Netfilter is in transparent proxying: if a machine on - the local network tries to connect to an outside host, your Linux - box can transparently forward the traffic to a local server, - typically a caching proxy server. - - Yet another use of Netfilter is building a bridging firewall. Using - a bridge with Network packet filtering enabled makes iptables "see" - the bridged traffic. For filtering on the lower network and Ethernet - protocols over the bridge, use ebtables (under bridge netfilter - configuration). - - Various modules exist for netfilter which replace the previous - masquerading (ipmasqadm), packet filtering (ipchains), transparent - proxying, and portforwarding mechanisms. Please see - under "iptables" for the location of - these packages. - -if NETFILTER - -config NETFILTER_DEBUG - bool "Network packet filtering debugging" - depends on NETFILTER - help - You can say Y here if you want to get additional messages useful in - debugging the netfilter code. - -config NETFILTER_ADVANCED - bool "Advanced netfilter configuration" - depends on NETFILTER - default y - help - If you say Y here you can select between all the netfilter modules. - If you say N the more unusual ones will not be shown and the - basic ones needed by most people will default to 'M'. - - If unsure, say Y. - -config BRIDGE_NETFILTER - tristate "Bridged IP/ARP packets filtering" - depends on BRIDGE - depends on NETFILTER && INET - depends on NETFILTER_ADVANCED - default m - ---help--- - Enabling this option will let arptables resp. iptables see bridged - ARP resp. IP traffic. If you want a bridging firewall, you probably - want this option enabled. - Enabling or disabling this option doesn't enable or disable - ebtables. - - If unsure, say N. - -source "net/netfilter/Kconfig" -source "net/ipv4/netfilter/Kconfig" -source "net/ipv6/netfilter/Kconfig" -source "net/decnet/netfilter/Kconfig" -source "net/bridge/netfilter/Kconfig" - -endif - -source "net/dccp/Kconfig" -source "net/sctp/Kconfig" -source "net/rds/Kconfig" -source "net/tipc/Kconfig" -source "net/atm/Kconfig" -source "net/l2tp/Kconfig" -source "net/802/Kconfig" -source "net/bridge/Kconfig" -source "net/dsa/Kconfig" -source "net/8021q/Kconfig" -source "net/decnet/Kconfig" -source "net/llc/Kconfig" -source "net/ipx/Kconfig" -source "drivers/net/appletalk/Kconfig" -source "net/x25/Kconfig" -source "net/lapb/Kconfig" -source "net/phonet/Kconfig" -source "net/6lowpan/Kconfig" -source "net/ieee802154/Kconfig" -source "net/mac802154/Kconfig" -source "net/sched/Kconfig" -source "net/dcb/Kconfig" -source "net/dns_resolver/Kconfig" -source "net/batman-adv/Kconfig" -source "net/openvswitch/Kconfig" -source "net/vmw_vsock/Kconfig" -source "net/netlink/Kconfig" -source "net/mpls/Kconfig" -source "net/hsr/Kconfig" -source "net/switchdev/Kconfig" -source "net/l3mdev/Kconfig" -source "net/qrtr/Kconfig" -source "net/ncsi/Kconfig" - -config RPS - bool - depends on SMP && SYSFS - default y - -config RFS_ACCEL - bool - depends on RPS - select CPU_RMAP - default y - -config XPS - bool - depends on SMP - default y - -config HWBM - bool - -config SOCK_CGROUP_DATA - bool - default n - -config CGROUP_NET_PRIO - bool "Network priority cgroup" - depends on CGROUPS - select SOCK_CGROUP_DATA - ---help--- - Cgroup subsystem for use in assigning processes to network priorities on - a per-interface basis. - -config CGROUP_NET_CLASSID - bool "Network classid cgroup" - depends on CGROUPS - select SOCK_CGROUP_DATA - ---help--- - Cgroup subsystem for use as general purpose socket classid marker that is - being used in cls_cgroup and for netfilter matching. - -config NET_RX_BUSY_POLL - bool - default y - -config BQL - bool - depends on SYSFS - select DQL - default y - -config BPF_JIT - bool "enable BPF Just In Time compiler" - depends on HAVE_CBPF_JIT || HAVE_EBPF_JIT - depends on MODULES - ---help--- - Berkeley Packet Filter filtering capabilities are normally handled - by an interpreter. This option allows kernel to generate a native - code when filter is loaded in memory. This should speedup - packet sniffing (libpcap/tcpdump). - - Note, admin should enable this feature changing: - /proc/sys/net/core/bpf_jit_enable - /proc/sys/net/core/bpf_jit_harden (optional) - -config NET_FLOW_LIMIT - bool - depends on RPS - default y - ---help--- - The network stack has to drop packets when a receive processing CPU's - backlog reaches netdev_max_backlog. If a few out of many active flows - generate the vast majority of load, drop their traffic earlier to - maintain capacity for the other flows. This feature provides servers - with many clients some protection against DoS by a single (spoofed) - flow that greatly exceeds average workload. - -menu "Network testing" - -config NET_PKTGEN - tristate "Packet Generator (USE WITH CAUTION)" - depends on INET && PROC_FS - ---help--- - This module will inject preconfigured packets, at a configurable - rate, out of a given interface. It is used for network interface - stress testing and performance analysis. If you don't understand - what was just said, you don't need it: say N. - - Documentation on how to use the packet generator can be found - at . - - To compile this code as a module, choose M here: the - module will be called pktgen. - -config NET_TCPPROBE - tristate "TCP connection probing" - depends on INET && PROC_FS && KPROBES - ---help--- - This module allows for capturing the changes to TCP connection - state in response to incoming packets. It is used for debugging - TCP congestion avoidance modules. If you don't understand - what was just said, you don't need it: say N. - - Documentation on how to use TCP connection probing can be found - at: - - http://www.linuxfoundation.org/collaborate/workgroups/networking/tcpprobe - - To compile this code as a module, choose M here: the - module will be called tcp_probe. - -config NET_DROP_MONITOR - tristate "Network packet drop alerting service" - depends on INET && TRACEPOINTS - ---help--- - This feature provides an alerting service to userspace in the - event that packets are discarded in the network stack. Alerts - are broadcast via netlink socket to any listening user space - process. If you don't need network drop alerts, or if you are ok - just checking the various proc files and other utilities for - drop statistics, say N here. - -endmenu - -endmenu - -source "net/ax25/Kconfig" -source "net/can/Kconfig" -source "net/irda/Kconfig" -source "net/bluetooth/Kconfig" -source "net/rxrpc/Kconfig" -source "net/kcm/Kconfig" -source "net/strparser/Kconfig" - -config FIB_RULES - bool - -menuconfig WIRELESS - bool "Wireless" - depends on !S390 - default y - -if WIRELESS - -source "net/wireless/Kconfig" -source "net/mac80211/Kconfig" - -endif # WIRELESS - -source "net/wimax/Kconfig" - -source "net/rfkill/Kconfig" -source "net/9p/Kconfig" -source "net/caif/Kconfig" -source "net/ceph/Kconfig" -source "net/nfc/Kconfig" - -config LWTUNNEL - bool "Network light weight tunnels" - ---help--- - This feature provides an infrastructure to support light weight - tunnels like mpls. There is no netdevice associated with a light - weight tunnel endpoint. Tunnel encapsulation parameters are stored - with light weight tunnel state associated with fib routes. - -config DST_CACHE - bool - default n - -config NET_DEVLINK - tristate "Network physical/parent device Netlink interface" - help - Network physical/parent device Netlink interface provides - infrastructure to support access to physical chip-wide config and - monitoring. - -config MAY_USE_DEVLINK - tristate - default m if NET_DEVLINK=m - default y if NET_DEVLINK=y || NET_DEVLINK=n - help - Drivers using the devlink infrastructure should have a dependency - on MAY_USE_DEVLINK to ensure they do not cause link errors when - devlink is a loadable module and the driver using it is built-in. - -endif # if NET - -# Used by archs to tell that they support BPF JIT compiler plus which flavour. -# Only one of the two can be selected for a specific arch since eBPF JIT supersedes -# the cBPF JIT. - -# Classic BPF JIT (cBPF) -config HAVE_CBPF_JIT - bool - -# Extended BPF JIT (eBPF) -config HAVE_EBPF_JIT - bool diff --git a/src/linux/net/Makefile b/src/linux/net/Makefile deleted file mode 100644 index 4cafaa2..0000000 --- a/src/linux/net/Makefile +++ /dev/null @@ -1,83 +0,0 @@ -# -# Makefile for the linux networking. -# -# 2 Sep 2000, Christoph Hellwig -# Rewritten to use lists instead of if-statements. -# - -obj-$(CONFIG_NET) := socket.o core/ - -tmp-$(CONFIG_COMPAT) := compat.o -obj-$(CONFIG_NET) += $(tmp-y) - -# LLC has to be linked before the files in net/802/ -obj-$(CONFIG_LLC) += llc/ -obj-$(CONFIG_NET) += ethernet/ 802/ sched/ netlink/ -obj-$(CONFIG_NETFILTER) += netfilter/ -obj-$(CONFIG_INET) += ipv4/ -obj-$(CONFIG_XFRM) += xfrm/ -obj-$(CONFIG_UNIX) += unix/ -obj-$(CONFIG_NET) += ipv6/ -obj-$(CONFIG_PACKET) += packet/ -obj-$(CONFIG_NET_KEY) += key/ -obj-$(CONFIG_BRIDGE) += bridge/ -obj-$(CONFIG_NET_DSA) += dsa/ -obj-$(CONFIG_IPX) += ipx/ -obj-$(CONFIG_ATALK) += appletalk/ -obj-$(CONFIG_X25) += x25/ -obj-$(CONFIG_LAPB) += lapb/ -obj-$(CONFIG_NETROM) += netrom/ -obj-$(CONFIG_ROSE) += rose/ -obj-$(CONFIG_AX25) += ax25/ -obj-$(CONFIG_CAN) += can/ -obj-$(CONFIG_IRDA) += irda/ -obj-$(CONFIG_BT) += bluetooth/ -obj-$(CONFIG_SUNRPC) += sunrpc/ -obj-$(CONFIG_AF_RXRPC) += rxrpc/ -obj-$(CONFIG_AF_KCM) += kcm/ -obj-$(CONFIG_STREAM_PARSER) += strparser/ -obj-$(CONFIG_ATM) += atm/ -obj-$(CONFIG_L2TP) += l2tp/ -obj-$(CONFIG_DECNET) += decnet/ -obj-$(CONFIG_PHONET) += phonet/ -ifneq ($(CONFIG_VLAN_8021Q),) -obj-y += 8021q/ -endif -obj-$(CONFIG_IP_DCCP) += dccp/ -obj-$(CONFIG_IP_SCTP) += sctp/ -obj-$(CONFIG_RDS) += rds/ -obj-$(CONFIG_WIRELESS) += wireless/ -obj-$(CONFIG_MAC80211) += mac80211/ -obj-$(CONFIG_TIPC) += tipc/ -obj-$(CONFIG_NETLABEL) += netlabel/ -obj-$(CONFIG_IUCV) += iucv/ -obj-$(CONFIG_RFKILL) += rfkill/ -obj-$(CONFIG_NET_9P) += 9p/ -obj-$(CONFIG_CAIF) += caif/ -ifneq ($(CONFIG_DCB),) -obj-y += dcb/ -endif -obj-$(CONFIG_6LOWPAN) += 6lowpan/ -obj-$(CONFIG_IEEE802154) += ieee802154/ -obj-$(CONFIG_MAC802154) += mac802154/ - -ifeq ($(CONFIG_NET),y) -obj-$(CONFIG_SYSCTL) += sysctl_net.o -endif -obj-$(CONFIG_WIMAX) += wimax/ -obj-$(CONFIG_DNS_RESOLVER) += dns_resolver/ -obj-$(CONFIG_CEPH_LIB) += ceph/ -obj-$(CONFIG_BATMAN_ADV) += batman-adv/ -obj-$(CONFIG_NFC) += nfc/ -obj-$(CONFIG_OPENVSWITCH) += openvswitch/ -obj-$(CONFIG_VSOCKETS) += vmw_vsock/ -obj-$(CONFIG_MPLS) += mpls/ -obj-$(CONFIG_HSR) += hsr/ -ifneq ($(CONFIG_NET_SWITCHDEV),) -obj-y += switchdev/ -endif -ifneq ($(CONFIG_NET_L3_MASTER_DEV),) -obj-y += l3mdev/ -endif -obj-$(CONFIG_QRTR) += qrtr/ -obj-$(CONFIG_NET_NCSI) += ncsi/ diff --git a/src/linux/net/atm/Kconfig b/src/linux/net/atm/Kconfig deleted file mode 100644 index 754ea10..0000000 --- a/src/linux/net/atm/Kconfig +++ /dev/null @@ -1,73 +0,0 @@ -# -# Asynchronous Transfer Mode (ATM) -# - -config ATM - tristate "Asynchronous Transfer Mode (ATM)" - ---help--- - ATM is a high-speed networking technology for Local Area Networks - and Wide Area Networks. It uses a fixed packet size and is - connection oriented, allowing for the negotiation of minimum - bandwidth requirements. - - In order to participate in an ATM network, your Linux box needs an - ATM networking card. If you have that, say Y here and to the driver - of your ATM card below. - - Note that you need a set of user-space programs to actually make use - of ATM. See the file for - further details. - -config ATM_CLIP - tristate "Classical IP over ATM" - depends on ATM && INET - help - Classical IP over ATM for PVCs and SVCs, supporting InARP and - ATMARP. If you want to communication with other IP hosts on your ATM - network, you will typically either say Y here or to "LAN Emulation - (LANE)" below. - -config ATM_CLIP_NO_ICMP - bool "Do NOT send ICMP if no neighbour" - depends on ATM_CLIP - help - Normally, an "ICMP host unreachable" message is sent if a neighbour - cannot be reached because there is no VC to it in the kernel's - ATMARP table. This may cause problems when ATMARP table entries are - briefly removed during revalidation. If you say Y here, packets to - such neighbours are silently discarded instead. - -config ATM_LANE - tristate "LAN Emulation (LANE) support" - depends on ATM - help - LAN Emulation emulates services of existing LANs across an ATM - network. Besides operating as a normal ATM end station client, Linux - LANE client can also act as an proxy client bridging packets between - ELAN and Ethernet segments. You need LANE if you want to try MPOA. - -config ATM_MPOA - tristate "Multi-Protocol Over ATM (MPOA) support" - depends on ATM && INET && ATM_LANE!=n - help - Multi-Protocol Over ATM allows ATM edge devices such as routers, - bridges and ATM attached hosts establish direct ATM VCs across - subnetwork boundaries. These shortcut connections bypass routers - enhancing overall network performance. - -config ATM_BR2684 - tristate "RFC1483/2684 Bridged protocols" - depends on ATM && INET - help - ATM PVCs can carry ethernet PDUs according to RFC2684 (formerly 1483) - This device will act like an ethernet from the kernels point of view, - with the traffic being carried by ATM PVCs (currently 1 PVC/device). - This is sometimes used over DSL lines. If in doubt, say N. - -config ATM_BR2684_IPFILTER - bool "Per-VC IP filter kludge" - depends on ATM_BR2684 - help - This is an experimental mechanism for users who need to terminate a - large number of IP-only vcc's. Do not enable this unless you are sure - you know what you are doing. diff --git a/src/linux/net/ax25/Kconfig b/src/linux/net/ax25/Kconfig deleted file mode 100644 index 705e53e..0000000 --- a/src/linux/net/ax25/Kconfig +++ /dev/null @@ -1,121 +0,0 @@ -# -# Amateur Radio protocols and AX.25 device configuration -# - -menuconfig HAMRADIO - depends on NET && !S390 - bool "Amateur Radio support" - help - If you want to connect your Linux box to an amateur radio, answer Y - here. You want to read - and more specifically about AX.25 on Linux - . - - Note that the answer to this question won't directly affect the - kernel: saying N will just cause the configurator to skip all - the questions about amateur radio. - -comment "Packet Radio protocols" - depends on HAMRADIO - -config AX25 - tristate "Amateur Radio AX.25 Level 2 protocol" - depends on HAMRADIO - help - This is the protocol used for computer communication over amateur - radio. It is either used by itself for point-to-point links, or to - carry other protocols such as tcp/ip. To use it, you need a device - that connects your Linux box to your amateur radio. You can either - use a low speed TNC (a Terminal Node Controller acts as a kind of - modem connecting your computer's serial port to your radio's - microphone input and speaker output) supporting the KISS protocol or - one of the various SCC cards that are supported by the generic Z8530 - or the DMA SCC driver. Another option are the Baycom modem serial - and parallel port hacks or the sound card modem (supported by their - own drivers). If you say Y here, you also have to say Y to one of - those drivers. - - Information about where to get supporting software for Linux amateur - radio as well as information about how to configure an AX.25 port is - contained in the AX25-HOWTO, available from - . You might also want to - check out the file in the - kernel source. More information about digital amateur radio in - general is on the WWW at - . - - To compile this driver as a module, choose M here: the - module will be called ax25. - -config AX25_DAMA_SLAVE - bool "AX.25 DAMA Slave support" - default y - depends on AX25 - help - DAMA is a mechanism to prevent collisions when doing AX.25 - networking. A DAMA server (called "master") accepts incoming traffic - from clients (called "slaves") and redistributes it to other slaves. - If you say Y here, your Linux box will act as a DAMA slave; this is - transparent in that you don't have to do any special DAMA - configuration. Linux cannot yet act as a DAMA server. This option - only compiles DAMA slave support into the kernel. It still needs to - be enabled at runtime. For more about DAMA see - . If unsure, say Y. - -# placeholder until implemented -config AX25_DAMA_MASTER - bool 'AX.25 DAMA Master support' - depends on AX25_DAMA_SLAVE && BROKEN - help - DAMA is a mechanism to prevent collisions when doing AX.25 - networking. A DAMA server (called "master") accepts incoming traffic - from clients (called "slaves") and redistributes it to other slaves. - If you say Y here, your Linux box will act as a DAMA master; this is - transparent in that you don't have to do any special DAMA - configuration. Linux cannot yet act as a DAMA server. This option - only compiles DAMA slave support into the kernel. It still needs to - be explicitly enabled, so if unsure, say Y. - -config NETROM - tristate "Amateur Radio NET/ROM protocol" - depends on AX25 - help - NET/ROM is a network layer protocol on top of AX.25 useful for - routing. - - A comprehensive listing of all the software for Linux amateur radio - users as well as information about how to configure an AX.25 port is - contained in the Linux Ham Wiki, available from - . You also might want to check out the - file . More information about - digital amateur radio in general is on the WWW at - . - - To compile this driver as a module, choose M here: the - module will be called netrom. - -config ROSE - tristate "Amateur Radio X.25 PLP (Rose)" - depends on AX25 - help - The Packet Layer Protocol (PLP) is a way to route packets over X.25 - connections in general and amateur radio AX.25 connections in - particular, essentially an alternative to NET/ROM. - - A comprehensive listing of all the software for Linux amateur radio - users as well as information about how to configure an AX.25 port is - contained in the Linux Ham Wiki, available from - . You also might want to check out the - file . More information about - digital amateur radio in general is on the WWW at - . - - To compile this driver as a module, choose M here: the - module will be called rose. - -menu "AX.25 network device drivers" - depends on HAMRADIO && AX25 - -source "drivers/net/hamradio/Kconfig" - -endmenu diff --git a/src/linux/net/batman-adv/Kconfig b/src/linux/net/batman-adv/Kconfig deleted file mode 100644 index f20742c..0000000 --- a/src/linux/net/batman-adv/Kconfig +++ /dev/null @@ -1,95 +0,0 @@ -# -# B.A.T.M.A.N meshing protocol -# - -config BATMAN_ADV - tristate "B.A.T.M.A.N. Advanced Meshing Protocol" - depends on NET - select CRC16 - select LIBCRC32C - default n - help - B.A.T.M.A.N. (better approach to mobile ad-hoc networking) is - a routing protocol for multi-hop ad-hoc mesh networks. The - networks may be wired or wireless. See - https://www.open-mesh.org/ for more information and user space - tools. - -config BATMAN_ADV_BATMAN_V - bool "B.A.T.M.A.N. V protocol (experimental)" - depends on BATMAN_ADV && CFG80211=y || (CFG80211=m && BATMAN_ADV=m) - default n - help - This option enables the B.A.T.M.A.N. V protocol, the successor - of the currently used B.A.T.M.A.N. IV protocol. The main - changes include splitting of the OGM protocol into a neighbor - discovery protocol (Echo Location Protocol, ELP) and a new OGM - Protocol OGMv2 for flooding protocol information through the - network, as well as a throughput based metric. - B.A.T.M.A.N. V is currently considered experimental and not - compatible to B.A.T.M.A.N. IV networks. - -config BATMAN_ADV_BLA - bool "Bridge Loop Avoidance" - depends on BATMAN_ADV && INET - default y - help - This option enables BLA (Bridge Loop Avoidance), a mechanism - to avoid Ethernet frames looping when mesh nodes are connected - to both the same LAN and the same mesh. If you will never use - more than one mesh node in the same LAN, you can safely remove - this feature and save some space. - -config BATMAN_ADV_DAT - bool "Distributed ARP Table" - depends on BATMAN_ADV && INET - default n - help - This option enables DAT (Distributed ARP Table), a DHT based - mechanism that increases ARP reliability on sparse wireless - mesh networks. If you think that your network does not need - this option you can safely remove it and save some space. - -config BATMAN_ADV_NC - bool "Network Coding" - depends on BATMAN_ADV - default n - help - This option enables network coding, a mechanism that aims to - increase the overall network throughput by fusing multiple - packets in one transmission. - Note that interfaces controlled by batman-adv must be manually - configured to have promiscuous mode enabled in order to make - network coding work. - If you think that your network does not need this feature you - can safely disable it and save some space. - -config BATMAN_ADV_MCAST - bool "Multicast optimisation" - depends on BATMAN_ADV && INET && !(BRIDGE=m && BATMAN_ADV=y) - default n - help - This option enables the multicast optimisation which aims to - reduce the air overhead while improving the reliability of - multicast messages. - -config BATMAN_ADV_DEBUGFS - bool "batman-adv debugfs entries" - depends on BATMAN_ADV - depends on DEBUG_FS - default y - help - Enable this to export routing related debug tables via debugfs. - The information for each soft-interface and used hard-interface can be - found under batman_adv/ - - If unsure, say Y. - -config BATMAN_ADV_DEBUG - bool "B.A.T.M.A.N. debugging" - depends on BATMAN_ADV_DEBUGFS - help - This is an option for use by developers; most people should - say N here. This enables compilation of support for - outputting debugging information to the kernel log. The - output is controlled via the module parameter debug. diff --git a/src/linux/net/bluetooth/Kconfig b/src/linux/net/bluetooth/Kconfig deleted file mode 100644 index 06c31b9..0000000 --- a/src/linux/net/bluetooth/Kconfig +++ /dev/null @@ -1,116 +0,0 @@ -# -# Bluetooth subsystem configuration -# - -menuconfig BT - tristate "Bluetooth subsystem support" - depends on NET && !S390 - depends on RFKILL || !RFKILL - select CRC16 - select CRYPTO - select CRYPTO_BLKCIPHER - select CRYPTO_AES - select CRYPTO_CMAC - select CRYPTO_ECB - select CRYPTO_SHA256 - help - Bluetooth is low-cost, low-power, short-range wireless technology. - It was designed as a replacement for cables and other short-range - technologies like IrDA. Bluetooth operates in personal area range - that typically extends up to 10 meters. More information about - Bluetooth can be found at . - - Linux Bluetooth subsystem consist of several layers: - Bluetooth Core - HCI device and connection manager, scheduler - SCO audio links - L2CAP (Logical Link Control and Adaptation Protocol) - SMP (Security Manager Protocol) on LE (Low Energy) links - HCI Device drivers (Interface to the hardware) - RFCOMM Module (RFCOMM Protocol) - BNEP Module (Bluetooth Network Encapsulation Protocol) - CMTP Module (CAPI Message Transport Protocol) - HIDP Module (Human Interface Device Protocol) - - Say Y here to compile Bluetooth support into the kernel or say M to - compile it as module (bluetooth). - - To use Linux Bluetooth subsystem, you will need several user-space - utilities like hciconfig and bluetoothd. These utilities and updates - to Bluetooth kernel modules are provided in the BlueZ packages. For - more information, see . - -config BT_BREDR - bool "Bluetooth Classic (BR/EDR) features" - depends on BT - default y - -source "net/bluetooth/rfcomm/Kconfig" - -source "net/bluetooth/bnep/Kconfig" - -source "net/bluetooth/cmtp/Kconfig" - -source "net/bluetooth/hidp/Kconfig" - -config BT_HS - bool "Bluetooth High Speed (HS) features" - depends on BT_BREDR - default y - -config BT_LE - bool "Bluetooth Low Energy (LE) features" - depends on BT - default y - -config BT_6LOWPAN - tristate "Bluetooth 6LoWPAN support" - depends on BT_LE && 6LOWPAN - help - IPv6 compression over Bluetooth Low Energy. - -config BT_LEDS - bool "Enable LED triggers" - depends on BT - depends on LEDS_CLASS - select LEDS_TRIGGERS - help - This option selects a few LED triggers for different - Bluetooth events. - -config BT_SELFTEST - bool "Bluetooth self testing support" - depends on BT && DEBUG_KERNEL - help - Run self tests when initializing the Bluetooth subsystem. This - is a developer option and can cause significant delay when booting - the system. - - When the Bluetooth subsystem is built as module, then the test - cases are run first thing at module load time. When the Bluetooth - subsystem is compiled into the kernel image, then the test cases - are run late in the initcall hierarchy. - -config BT_SELFTEST_ECDH - bool "ECDH test cases" - depends on BT_LE && BT_SELFTEST - help - Run test cases for ECDH cryptographic functionality used by the - Bluetooth Low Energy Secure Connections feature. - -config BT_SELFTEST_SMP - bool "SMP test cases" - depends on BT_LE && BT_SELFTEST - help - Run test cases for SMP cryptographic functionality, including both - legacy SMP as well as the Secure Connections features. - -config BT_DEBUGFS - bool "Export Bluetooth internals in debugfs" - depends on BT && DEBUG_FS - default y - help - Provide extensive information about internal Bluetooth states - in debugfs. - -source "drivers/bluetooth/Kconfig" diff --git a/src/linux/net/bluetooth/bnep/Kconfig b/src/linux/net/bluetooth/bnep/Kconfig deleted file mode 100644 index 9b70317..0000000 --- a/src/linux/net/bluetooth/bnep/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -config BT_BNEP - tristate "BNEP protocol support" - depends on BT_BREDR - select CRC32 - help - BNEP (Bluetooth Network Encapsulation Protocol) is Ethernet - emulation layer on top of Bluetooth. BNEP is required for - Bluetooth PAN (Personal Area Network). - - Say Y here to compile BNEP support into the kernel or say M to - compile it as module (bnep). - -config BT_BNEP_MC_FILTER - bool "Multicast filter support" - depends on BT_BNEP - help - This option enables the multicast filter support for BNEP. - -config BT_BNEP_PROTO_FILTER - bool "Protocol filter support" - depends on BT_BNEP - help - This option enables the protocol filter support for BNEP. - diff --git a/src/linux/net/bluetooth/cmtp/Kconfig b/src/linux/net/bluetooth/cmtp/Kconfig deleted file mode 100644 index 939da0f..0000000 --- a/src/linux/net/bluetooth/cmtp/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config BT_CMTP - tristate "CMTP protocol support" - depends on BT_BREDR && ISDN_CAPI - help - CMTP (CAPI Message Transport Protocol) is a transport layer - for CAPI messages. CMTP is required for the Bluetooth Common - ISDN Access Profile. - - Say Y here to compile CMTP support into the kernel or say M to - compile it as module (cmtp). - diff --git a/src/linux/net/bluetooth/hidp/Kconfig b/src/linux/net/bluetooth/hidp/Kconfig deleted file mode 100644 index bc8610b..0000000 --- a/src/linux/net/bluetooth/hidp/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config BT_HIDP - tristate "HIDP protocol support" - depends on BT_BREDR && INPUT - select HID - help - HIDP (Human Interface Device Protocol) is a transport layer - for HID reports. HIDP is required for the Bluetooth Human - Interface Device Profile. - - Say Y here to compile HIDP support into the kernel or say M to - compile it as module (hidp). - diff --git a/src/linux/net/bluetooth/rfcomm/Kconfig b/src/linux/net/bluetooth/rfcomm/Kconfig deleted file mode 100644 index 335df75..0000000 --- a/src/linux/net/bluetooth/rfcomm/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config BT_RFCOMM - tristate "RFCOMM protocol support" - depends on BT_BREDR - help - RFCOMM provides connection oriented stream transport. RFCOMM - support is required for Dialup Networking, OBEX and other Bluetooth - applications. - - Say Y here to compile RFCOMM support into the kernel or say M to - compile it as module (rfcomm). - -config BT_RFCOMM_TTY - bool "RFCOMM TTY support" - depends on BT_RFCOMM - depends on TTY - help - This option enables TTY emulation support for RFCOMM channels. - diff --git a/src/linux/net/bridge/Kconfig b/src/linux/net/bridge/Kconfig deleted file mode 100644 index aa0d3b2..0000000 --- a/src/linux/net/bridge/Kconfig +++ /dev/null @@ -1,62 +0,0 @@ -# -# 802.1d Ethernet Bridging -# - -config BRIDGE - tristate "802.1d Ethernet Bridging" - select LLC - select STP - depends on IPV6 || IPV6=n - ---help--- - If you say Y here, then your Linux box will be able to act as an - Ethernet bridge, which means that the different Ethernet segments it - is connected to will appear as one Ethernet to the participants. - Several such bridges can work together to create even larger - networks of Ethernets using the IEEE 802.1 spanning tree algorithm. - As this is a standard, Linux bridges will cooperate properly with - other third party bridge products. - - In order to use the Ethernet bridge, you'll need the bridge - configuration tools; see - for location. Please read the Bridge mini-HOWTO for more - information. - - If you enable iptables support along with the bridge support then you - turn your bridge into a bridging IP firewall. - iptables will then see the IP packets being bridged, so you need to - take this into account when setting up your firewall rules. - Enabling arptables support when bridging will let arptables see - bridged ARP traffic in the arptables FORWARD chain. - - To compile this code as a module, choose M here: the module - will be called bridge. - - If unsure, say N. - -config BRIDGE_IGMP_SNOOPING - bool "IGMP/MLD snooping" - depends on BRIDGE - depends on INET - default y - ---help--- - If you say Y here, then the Ethernet bridge will be able selectively - forward multicast traffic based on IGMP/MLD traffic received from - each port. - - Say N to exclude this support and reduce the binary size. - - If unsure, say Y. - -config BRIDGE_VLAN_FILTERING - bool "VLAN filtering" - depends on BRIDGE - depends on VLAN_8021Q - default n - ---help--- - If you say Y here, then the Ethernet bridge will be able selectively - receive and forward traffic based on VLAN information in the packet - any VLAN information configured on the bridge port or bridge device. - - Say N to exclude this support and reduce the binary size. - - If unsure, say Y. diff --git a/src/linux/net/bridge/netfilter/Kconfig b/src/linux/net/bridge/netfilter/Kconfig deleted file mode 100644 index 9cebf47..0000000 --- a/src/linux/net/bridge/netfilter/Kconfig +++ /dev/null @@ -1,227 +0,0 @@ -# -# Bridge netfilter configuration -# -# -menuconfig NF_TABLES_BRIDGE - depends on BRIDGE && NETFILTER && NF_TABLES - tristate "Ethernet Bridge nf_tables support" - -if NF_TABLES_BRIDGE - -config NFT_BRIDGE_META - tristate "Netfilter nf_table bridge meta support" - depends on NFT_META - help - Add support for bridge dedicated meta key. - -config NFT_BRIDGE_REJECT - tristate "Netfilter nf_tables bridge reject support" - depends on NFT_REJECT && NFT_REJECT_IPV4 && NFT_REJECT_IPV6 - help - Add support to reject packets. - -config NF_LOG_BRIDGE - tristate "Bridge packet logging" - -endif # NF_TABLES_BRIDGE - -menuconfig BRIDGE_NF_EBTABLES - tristate "Ethernet Bridge tables (ebtables) support" - depends on BRIDGE && NETFILTER && NETFILTER_XTABLES - help - ebtables is a general, extensible frame/packet identification - framework. Say 'Y' or 'M' here if you want to do Ethernet - filtering/NAT/brouting on the Ethernet bridge. - -if BRIDGE_NF_EBTABLES - -# -# tables -# -config BRIDGE_EBT_BROUTE - tristate "ebt: broute table support" - help - The ebtables broute table is used to define rules that decide between - bridging and routing frames, giving Linux the functionality of a - brouter. See the man page for ebtables(8) and examples on the ebtables - website. - - To compile it as a module, choose M here. If unsure, say N. - -config BRIDGE_EBT_T_FILTER - tristate "ebt: filter table support" - help - The ebtables filter table is used to define frame filtering rules at - local input, forwarding and local output. See the man page for - ebtables(8). - - To compile it as a module, choose M here. If unsure, say N. - -config BRIDGE_EBT_T_NAT - tristate "ebt: nat table support" - help - The ebtables nat table is used to define rules that alter the MAC - source address (MAC SNAT) or the MAC destination address (MAC DNAT). - See the man page for ebtables(8). - - To compile it as a module, choose M here. If unsure, say N. -# -# matches -# -config BRIDGE_EBT_802_3 - tristate "ebt: 802.3 filter support" - help - This option adds matching support for 802.3 Ethernet frames. - - To compile it as a module, choose M here. If unsure, say N. - -config BRIDGE_EBT_AMONG - tristate "ebt: among filter support" - help - This option adds the among match, which allows matching the MAC source - and/or destination address on a list of addresses. Optionally, - MAC/IP address pairs can be matched, f.e. for anti-spoofing rules. - - To compile it as a module, choose M here. If unsure, say N. - -config BRIDGE_EBT_ARP - tristate "ebt: ARP filter support" - help - This option adds the ARP match, which allows ARP and RARP header field - filtering. - - To compile it as a module, choose M here. If unsure, say N. - -config BRIDGE_EBT_IP - tristate "ebt: IP filter support" - help - This option adds the IP match, which allows basic IP header field - filtering. - - To compile it as a module, choose M here. If unsure, say N. - -config BRIDGE_EBT_IP6 - tristate "ebt: IP6 filter support" - depends on BRIDGE_NF_EBTABLES && IPV6 - help - This option adds the IP6 match, which allows basic IPV6 header field - filtering. - - To compile it as a module, choose M here. If unsure, say N. - -config BRIDGE_EBT_LIMIT - tristate "ebt: limit match support" - help - This option adds the limit match, which allows you to control - the rate at which a rule can be matched. This match is the - equivalent of the iptables limit match. - - If you want to compile it as a module, say M here and read - . If unsure, say `N'. - -config BRIDGE_EBT_MARK - tristate "ebt: mark filter support" - help - This option adds the mark match, which allows matching frames based on - the 'nfmark' value in the frame. This can be set by the mark target. - This value is the same as the one used in the iptables mark match and - target. - - To compile it as a module, choose M here. If unsure, say N. - -config BRIDGE_EBT_PKTTYPE - tristate "ebt: packet type filter support" - help - This option adds the packet type match, which allows matching on the - type of packet based on its Ethernet "class" (as determined by - the generic networking code): broadcast, multicast, - for this host alone or for another host. - - To compile it as a module, choose M here. If unsure, say N. - -config BRIDGE_EBT_STP - tristate "ebt: STP filter support" - help - This option adds the Spanning Tree Protocol match, which - allows STP header field filtering. - - To compile it as a module, choose M here. If unsure, say N. - -config BRIDGE_EBT_VLAN - tristate "ebt: 802.1Q VLAN filter support" - help - This option adds the 802.1Q vlan match, which allows the filtering of - 802.1Q vlan fields. - - To compile it as a module, choose M here. If unsure, say N. -# -# targets -# -config BRIDGE_EBT_ARPREPLY - tristate "ebt: arp reply target support" - depends on BRIDGE_NF_EBTABLES && INET - help - This option adds the arp reply target, which allows - automatically sending arp replies to arp requests. - - To compile it as a module, choose M here. If unsure, say N. - -config BRIDGE_EBT_DNAT - tristate "ebt: dnat target support" - help - This option adds the MAC DNAT target, which allows altering the MAC - destination address of frames. - - To compile it as a module, choose M here. If unsure, say N. - -config BRIDGE_EBT_MARK_T - tristate "ebt: mark target support" - help - This option adds the mark target, which allows marking frames by - setting the 'nfmark' value in the frame. - This value is the same as the one used in the iptables mark match and - target. - - To compile it as a module, choose M here. If unsure, say N. - -config BRIDGE_EBT_REDIRECT - tristate "ebt: redirect target support" - help - This option adds the MAC redirect target, which allows altering the MAC - destination address of a frame to that of the device it arrived on. - - To compile it as a module, choose M here. If unsure, say N. - -config BRIDGE_EBT_SNAT - tristate "ebt: snat target support" - help - This option adds the MAC SNAT target, which allows altering the MAC - source address of frames. - - To compile it as a module, choose M here. If unsure, say N. -# -# watchers -# -config BRIDGE_EBT_LOG - tristate "ebt: log support" - help - This option adds the log watcher, that you can use in any rule - in any ebtables table. It records info about the frame header - to the syslog. - - To compile it as a module, choose M here. If unsure, say N. - -config BRIDGE_EBT_NFLOG - tristate "ebt: nflog support" - help - This option enables the nflog watcher, which allows to LOG - messages through the netfilter logging API, which can use - either the old LOG target, the old ULOG target or nfnetlink_log - as backend. - - This option adds the nflog watcher, that you can use in any rule - in any ebtables table. - - To compile it as a module, choose M here. If unsure, say N. - -endif # BRIDGE_NF_EBTABLES diff --git a/src/linux/net/caif/Kconfig b/src/linux/net/caif/Kconfig deleted file mode 100644 index d369495..0000000 --- a/src/linux/net/caif/Kconfig +++ /dev/null @@ -1,53 +0,0 @@ -# -# CAIF net configurations -# - -menuconfig CAIF - tristate "CAIF support" - select CRC_CCITT - default n - ---help--- - The "Communication CPU to Application CPU Interface" (CAIF) is a packet - based connection-oriented MUX protocol developed by ST-Ericsson for use - with its modems. It is accessed from user space as sockets (PF_CAIF). - - Say Y (or M) here if you build for a phone product (e.g. Android or - MeeGo ) that uses CAIF as transport, if unsure say N. - - If you select to build it as module then CAIF_NETDEV also needs to be - built as modules. You will also need to say yes to any CAIF physical - devices that your platform requires. - - See Documentation/networking/caif for a further explanation on how to - use and configure CAIF. - -config CAIF_DEBUG - bool "Enable Debug" - depends on CAIF - default n - ---help--- - Enable the inclusion of debug code in the CAIF stack. - Be aware that doing this will impact performance. - If unsure say N. - -config CAIF_NETDEV - tristate "CAIF GPRS Network device" - depends on CAIF - default CAIF - ---help--- - Say Y if you will be using a CAIF based GPRS network device. - This can be either built-in or a loadable module, - If you select to build it as a built-in then the main CAIF device must - also be a built-in. - If unsure say Y. - -config CAIF_USB - tristate "CAIF USB support" - depends on CAIF - default n - ---help--- - Say Y if you are using CAIF over USB CDC NCM. - This can be either built-in or a loadable module, - If you select to build it as a built-in then the main CAIF device must - also be a built-in. - If unsure say N. diff --git a/src/linux/net/can/Kconfig b/src/linux/net/can/Kconfig deleted file mode 100644 index a15c0e0..0000000 --- a/src/linux/net/can/Kconfig +++ /dev/null @@ -1,56 +0,0 @@ -# -# Controller Area Network (CAN) network layer core configuration -# - -menuconfig CAN - depends on NET - tristate "CAN bus subsystem support" - ---help--- - Controller Area Network (CAN) is a slow (up to 1Mbit/s) serial - communications protocol which was developed by Bosch in - 1991, mainly for automotive, but now widely used in marine - (NMEA2000), industrial, and medical applications. - More information on the CAN network protocol family PF_CAN - is contained in . - - If you want CAN support you should say Y here and also to the - specific driver for your controller(s) below. - -if CAN - -config CAN_RAW - tristate "Raw CAN Protocol (raw access with CAN-ID filtering)" - default y - ---help--- - The raw CAN protocol option offers access to the CAN bus via - the BSD socket API. You probably want to use the raw socket in - most cases where no higher level protocol is being used. The raw - socket has several filter options e.g. ID masking / error frames. - To receive/send raw CAN messages, use AF_CAN with protocol CAN_RAW. - -config CAN_BCM - tristate "Broadcast Manager CAN Protocol (with content filtering)" - default y - ---help--- - The Broadcast Manager offers content filtering, timeout monitoring, - sending of RTR frames, and cyclic CAN messages without permanent user - interaction. The BCM can be 'programmed' via the BSD socket API and - informs you on demand e.g. only on content updates / timeouts. - You probably want to use the bcm socket in most cases where cyclic - CAN messages are used on the bus (e.g. in automotive environments). - To use the Broadcast Manager, use AF_CAN with protocol CAN_BCM. - -config CAN_GW - tristate "CAN Gateway/Router (with netlink configuration)" - default y - ---help--- - The CAN Gateway/Router is used to route (and modify) CAN frames. - It is based on the PF_CAN core infrastructure for msg filtering and - msg sending and can optionally modify routed CAN frames on the fly. - CAN frames can be routed between CAN network interfaces (one hop). - They can be modified with AND/OR/XOR/SET operations as configured - by the netlink configuration interface known e.g. from iptables. - -source "drivers/net/can/Kconfig" - -endif diff --git a/src/linux/net/ceph/Kconfig b/src/linux/net/ceph/Kconfig deleted file mode 100644 index f8cceb9..0000000 --- a/src/linux/net/ceph/Kconfig +++ /dev/null @@ -1,44 +0,0 @@ -config CEPH_LIB - tristate "Ceph core library" - depends on INET - select LIBCRC32C - select CRYPTO_AES - select CRYPTO_CBC - select CRYPTO - select KEYS - default n - help - Choose Y or M here to include cephlib, which provides the - common functionality to both the Ceph filesystem and - to the rados block device (rbd). - - More information at http://ceph.newdream.net/. - - If unsure, say N. - -config CEPH_LIB_PRETTYDEBUG - bool "Include file:line in ceph debug output" - depends on CEPH_LIB - default n - help - If you say Y here, debug output will include a filename and - line to aid debugging. This increases kernel size and slows - execution slightly when debug call sites are enabled (e.g., - via CONFIG_DYNAMIC_DEBUG). - - If unsure, say N. - -config CEPH_LIB_USE_DNS_RESOLVER - bool "Use in-kernel support for DNS lookup" - depends on CEPH_LIB - select DNS_RESOLVER - default n - help - If you say Y here, hostnames (e.g. monitor addresses) will - be resolved using the CONFIG_DNS_RESOLVER facility. - - For information on how to use CONFIG_DNS_RESOLVER consult - Documentation/networking/dns_resolver.txt - - If unsure, say N. - diff --git a/src/linux/net/core/Makefile b/src/linux/net/core/Makefile deleted file mode 100644 index d6508c2..0000000 --- a/src/linux/net/core/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -# -# Makefile for the Linux networking core. -# - -obj-y := sock.o request_sock.o skbuff.o datagram.o stream.o scm.o \ - gen_stats.o gen_estimator.o net_namespace.o secure_seq.o flow_dissector.o - -obj-$(CONFIG_SYSCTL) += sysctl_net_core.o - -obj-y += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \ - neighbour.o rtnetlink.o utils.o link_watch.o filter.o \ - sock_diag.o dev_ioctl.o tso.o sock_reuseport.o - -obj-$(CONFIG_XFRM) += flow.o -obj-y += net-sysfs.o -obj-$(CONFIG_PROC_FS) += net-procfs.o -obj-$(CONFIG_NET_PKTGEN) += pktgen.o -obj-$(CONFIG_NETPOLL) += netpoll.o -obj-$(CONFIG_FIB_RULES) += fib_rules.o -obj-$(CONFIG_TRACEPOINTS) += net-traces.o -obj-$(CONFIG_NET_DROP_MONITOR) += drop_monitor.o -obj-$(CONFIG_NETWORK_PHY_TIMESTAMPING) += timestamping.o -obj-$(CONFIG_NET_PTP_CLASSIFY) += ptp_classifier.o -obj-$(CONFIG_CGROUP_NET_PRIO) += netprio_cgroup.o -obj-$(CONFIG_CGROUP_NET_CLASSID) += netclassid_cgroup.o -obj-$(CONFIG_LWTUNNEL) += lwtunnel.o -obj-$(CONFIG_DST_CACHE) += dst_cache.o -obj-$(CONFIG_HWBM) += hwbm.o -obj-$(CONFIG_NET_DEVLINK) += devlink.o diff --git a/src/linux/net/core/datagram.c b/src/linux/net/core/datagram.c deleted file mode 100644 index b7de71f..0000000 --- a/src/linux/net/core/datagram.c +++ /dev/null @@ -1,814 +0,0 @@ -/* - * SUCS NET3: - * - * Generic datagram handling routines. These are generic for all - * protocols. Possibly a generic IP version on top of these would - * make sense. Not tonight however 8-). - * This is used because UDP, RAW, PACKET, DDP, IPX, AX.25 and - * NetROM layer all have identical poll code and mostly - * identical recvmsg() code. So we share it here. The poll was - * shared before but buried in udp.c so I moved it. - * - * Authors: Alan Cox . (datagram_poll() from old - * udp.c code) - * - * Fixes: - * Alan Cox : NULL return from skb_peek_copy() - * understood - * Alan Cox : Rewrote skb_read_datagram to avoid the - * skb_peek_copy stuff. - * Alan Cox : Added support for SOCK_SEQPACKET. - * IPX can no longer use the SO_TYPE hack - * but AX.25 now works right, and SPX is - * feasible. - * Alan Cox : Fixed write poll of non IP protocol - * crash. - * Florian La Roche: Changed for my new skbuff handling. - * Darryl Miles : Fixed non-blocking SOCK_SEQPACKET. - * Linus Torvalds : BSD semantic fixes. - * Alan Cox : Datagram iovec handling - * Darryl Miles : Fixed non-blocking SOCK_STREAM. - * Alan Cox : POSIXisms - * Pete Wyckoff : Unconnected accept() fix. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include - -/* - * Is a socket 'connection oriented' ? - */ -static inline int connection_based(struct sock *sk) -{ - return sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM; -} - -static int receiver_wake_function(wait_queue_t *wait, unsigned int mode, int sync, - void *key) -{ - unsigned long bits = (unsigned long)key; - - /* - * Avoid a wakeup if event not interesting for us - */ - if (bits && !(bits & (POLLIN | POLLERR))) - return 0; - return autoremove_wake_function(wait, mode, sync, key); -} -/* - * Wait for the last received packet to be different from skb - */ -int __skb_wait_for_more_packets(struct sock *sk, int *err, long *timeo_p, - const struct sk_buff *skb) -{ - int error; - DEFINE_WAIT_FUNC(wait, receiver_wake_function); - - prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - - /* Socket errors? */ - error = sock_error(sk); - if (error) - goto out_err; - - if (sk->sk_receive_queue.prev != skb) - goto out; - - /* Socket shut down? */ - if (sk->sk_shutdown & RCV_SHUTDOWN) - goto out_noerr; - - /* Sequenced packets can come disconnected. - * If so we report the problem - */ - error = -ENOTCONN; - if (connection_based(sk) && - !(sk->sk_state == TCP_ESTABLISHED || sk->sk_state == TCP_LISTEN)) - goto out_err; - - /* handle signals */ - if (signal_pending(current)) - goto interrupted; - - error = 0; - *timeo_p = schedule_timeout(*timeo_p); -out: - finish_wait(sk_sleep(sk), &wait); - return error; -interrupted: - error = sock_intr_errno(*timeo_p); -out_err: - *err = error; - goto out; -out_noerr: - *err = 0; - error = 1; - goto out; -} -EXPORT_SYMBOL(__skb_wait_for_more_packets); - -static struct sk_buff *skb_set_peeked(struct sk_buff *skb) -{ - struct sk_buff *nskb; - - if (skb->peeked) - return skb; - - /* We have to unshare an skb before modifying it. */ - if (!skb_shared(skb)) - goto done; - - nskb = skb_clone(skb, GFP_ATOMIC); - if (!nskb) - return ERR_PTR(-ENOMEM); - - skb->prev->next = nskb; - skb->next->prev = nskb; - nskb->prev = skb->prev; - nskb->next = skb->next; - - consume_skb(skb); - skb = nskb; - -done: - skb->peeked = 1; - - return skb; -} - -/** - * __skb_try_recv_datagram - Receive a datagram skbuff - * @sk: socket - * @flags: MSG_ flags - * @peeked: returns non-zero if this packet has been seen before - * @off: an offset in bytes to peek skb from. Returns an offset - * within an skb where data actually starts - * @err: error code returned - * @last: set to last peeked message to inform the wait function - * what to look for when peeking - * - * Get a datagram skbuff, understands the peeking, nonblocking wakeups - * and possible races. This replaces identical code in packet, raw and - * udp, as well as the IPX AX.25 and Appletalk. It also finally fixes - * the long standing peek and read race for datagram sockets. If you - * alter this routine remember it must be re-entrant. - * - * This function will lock the socket if a skb is returned, so - * the caller needs to unlock the socket in that case (usually by - * calling skb_free_datagram). Returns NULL with *err set to - * -EAGAIN if no data was available or to some other value if an - * error was detected. - * - * * It does not lock socket since today. This function is - * * free of race conditions. This measure should/can improve - * * significantly datagram socket latencies at high loads, - * * when data copying to user space takes lots of time. - * * (BTW I've just killed the last cli() in IP/IPv6/core/netlink/packet - * * 8) Great win.) - * * --ANK (980729) - * - * The order of the tests when we find no data waiting are specified - * quite explicitly by POSIX 1003.1g, don't change them without having - * the standard around please. - */ -struct sk_buff *__skb_try_recv_datagram(struct sock *sk, unsigned int flags, - int *peeked, int *off, int *err, - struct sk_buff **last) -{ - struct sk_buff_head *queue = &sk->sk_receive_queue; - struct sk_buff *skb; - unsigned long cpu_flags; - /* - * Caller is allowed not to check sk->sk_err before skb_recv_datagram() - */ - int error = sock_error(sk); - - if (error) - goto no_packet; - - do { - /* Again only user level code calls this function, so nothing - * interrupt level will suddenly eat the receive_queue. - * - * Look at current nfs client by the way... - * However, this function was correct in any case. 8) - */ - int _off = *off; - - *last = (struct sk_buff *)queue; - spin_lock_irqsave(&queue->lock, cpu_flags); - skb_queue_walk(queue, skb) { - *last = skb; - *peeked = skb->peeked; - if (flags & MSG_PEEK) { - if (_off >= skb->len && (skb->len || _off || - skb->peeked)) { - _off -= skb->len; - continue; - } - - skb = skb_set_peeked(skb); - error = PTR_ERR(skb); - if (IS_ERR(skb)) { - spin_unlock_irqrestore(&queue->lock, - cpu_flags); - goto no_packet; - } - - atomic_inc(&skb->users); - } else - __skb_unlink(skb, queue); - - spin_unlock_irqrestore(&queue->lock, cpu_flags); - *off = _off; - return skb; - } - - spin_unlock_irqrestore(&queue->lock, cpu_flags); - } while (sk_can_busy_loop(sk) && - sk_busy_loop(sk, flags & MSG_DONTWAIT)); - - error = -EAGAIN; - -no_packet: - *err = error; - return NULL; -} -EXPORT_SYMBOL(__skb_try_recv_datagram); - -struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, - int *peeked, int *off, int *err) -{ - struct sk_buff *skb, *last; - long timeo; - - timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); - - do { - skb = __skb_try_recv_datagram(sk, flags, peeked, off, err, - &last); - if (skb) - return skb; - - if (*err != -EAGAIN) - break; - } while (timeo && - !__skb_wait_for_more_packets(sk, err, &timeo, last)); - - return NULL; -} -EXPORT_SYMBOL(__skb_recv_datagram); - -struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned int flags, - int noblock, int *err) -{ - int peeked, off = 0; - - return __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), - &peeked, &off, err); -} -EXPORT_SYMBOL(skb_recv_datagram); - -void skb_free_datagram(struct sock *sk, struct sk_buff *skb) -{ - consume_skb(skb); - sk_mem_reclaim_partial(sk); -} -EXPORT_SYMBOL(skb_free_datagram); - -void __skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb, int len) -{ - bool slow; - - if (likely(atomic_read(&skb->users) == 1)) - smp_rmb(); - else if (likely(!atomic_dec_and_test(&skb->users))) { - sk_peek_offset_bwd(sk, len); - return; - } - - slow = lock_sock_fast(sk); - sk_peek_offset_bwd(sk, len); - skb_orphan(skb); - sk_mem_reclaim_partial(sk); - unlock_sock_fast(sk, slow); - - /* skb is now orphaned, can be freed outside of locked section */ - __kfree_skb(skb); -} -EXPORT_SYMBOL(__skb_free_datagram_locked); - -/** - * skb_kill_datagram - Free a datagram skbuff forcibly - * @sk: socket - * @skb: datagram skbuff - * @flags: MSG_ flags - * - * This function frees a datagram skbuff that was received by - * skb_recv_datagram. The flags argument must match the one - * used for skb_recv_datagram. - * - * If the MSG_PEEK flag is set, and the packet is still on the - * receive queue of the socket, it will be taken off the queue - * before it is freed. - * - * This function currently only disables BH when acquiring the - * sk_receive_queue lock. Therefore it must not be used in a - * context where that lock is acquired in an IRQ context. - * - * It returns 0 if the packet was removed by us. - */ - -int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags) -{ - int err = 0; - - if (flags & MSG_PEEK) { - err = -ENOENT; - spin_lock_bh(&sk->sk_receive_queue.lock); - if (skb == skb_peek(&sk->sk_receive_queue)) { - __skb_unlink(skb, &sk->sk_receive_queue); - atomic_dec(&skb->users); - err = 0; - } - spin_unlock_bh(&sk->sk_receive_queue.lock); - } - - kfree_skb(skb); - atomic_inc(&sk->sk_drops); - sk_mem_reclaim_partial(sk); - - return err; -} -EXPORT_SYMBOL(skb_kill_datagram); - -/** - * skb_copy_datagram_iter - Copy a datagram to an iovec iterator. - * @skb: buffer to copy - * @offset: offset in the buffer to start copying from - * @to: iovec iterator to copy to - * @len: amount of data to copy from buffer to iovec - */ -int skb_copy_datagram_iter(const struct sk_buff *skb, int offset, - struct iov_iter *to, int len) -{ - int start = skb_headlen(skb); - int i, copy = start - offset; - struct sk_buff *frag_iter; - - trace_skb_copy_datagram_iovec(skb, len); - - /* Copy header. */ - if (copy > 0) { - if (copy > len) - copy = len; - if (copy_to_iter(skb->data + offset, copy, to) != copy) - goto short_copy; - if ((len -= copy) == 0) - return 0; - offset += copy; - } - - /* Copy paged appendix. Hmm... why does this look so complicated? */ - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - int end; - const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - WARN_ON(start > offset + len); - - end = start + skb_frag_size(frag); - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - if (copy_page_to_iter(skb_frag_page(frag), - frag->page_offset + offset - - start, copy, to) != copy) - goto short_copy; - if (!(len -= copy)) - return 0; - offset += copy; - } - start = end; - } - - skb_walk_frags(skb, frag_iter) { - int end; - - WARN_ON(start > offset + len); - - end = start + frag_iter->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - if (skb_copy_datagram_iter(frag_iter, offset - start, - to, copy)) - goto fault; - if ((len -= copy) == 0) - return 0; - offset += copy; - } - start = end; - } - if (!len) - return 0; - - /* This is not really a user copy fault, but rather someone - * gave us a bogus length on the skb. We should probably - * print a warning here as it may indicate a kernel bug. - */ - -fault: - return -EFAULT; - -short_copy: - if (iov_iter_count(to)) - goto fault; - - return 0; -} -EXPORT_SYMBOL(skb_copy_datagram_iter); - -/** - * skb_copy_datagram_from_iter - Copy a datagram from an iov_iter. - * @skb: buffer to copy - * @offset: offset in the buffer to start copying to - * @from: the copy source - * @len: amount of data to copy to buffer from iovec - * - * Returns 0 or -EFAULT. - */ -int skb_copy_datagram_from_iter(struct sk_buff *skb, int offset, - struct iov_iter *from, - int len) -{ - int start = skb_headlen(skb); - int i, copy = start - offset; - struct sk_buff *frag_iter; - - /* Copy header. */ - if (copy > 0) { - if (copy > len) - copy = len; - if (copy_from_iter(skb->data + offset, copy, from) != copy) - goto fault; - if ((len -= copy) == 0) - return 0; - offset += copy; - } - - /* Copy paged appendix. Hmm... why does this look so complicated? */ - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - int end; - const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - WARN_ON(start > offset + len); - - end = start + skb_frag_size(frag); - if ((copy = end - offset) > 0) { - size_t copied; - - if (copy > len) - copy = len; - copied = copy_page_from_iter(skb_frag_page(frag), - frag->page_offset + offset - start, - copy, from); - if (copied != copy) - goto fault; - - if (!(len -= copy)) - return 0; - offset += copy; - } - start = end; - } - - skb_walk_frags(skb, frag_iter) { - int end; - - WARN_ON(start > offset + len); - - end = start + frag_iter->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - if (skb_copy_datagram_from_iter(frag_iter, - offset - start, - from, copy)) - goto fault; - if ((len -= copy) == 0) - return 0; - offset += copy; - } - start = end; - } - if (!len) - return 0; - -fault: - return -EFAULT; -} -EXPORT_SYMBOL(skb_copy_datagram_from_iter); - -/** - * zerocopy_sg_from_iter - Build a zerocopy datagram from an iov_iter - * @skb: buffer to copy - * @from: the source to copy from - * - * The function will first copy up to headlen, and then pin the userspace - * pages and build frags through them. - * - * Returns 0, -EFAULT or -EMSGSIZE. - */ -int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *from) -{ - int len = iov_iter_count(from); - int copy = min_t(int, skb_headlen(skb), len); - int frag = 0; - - /* copy up to skb headlen */ - if (skb_copy_datagram_from_iter(skb, 0, from, copy)) - return -EFAULT; - - while (iov_iter_count(from)) { - struct page *pages[MAX_SKB_FRAGS]; - size_t start; - ssize_t copied; - unsigned long truesize; - int n = 0; - - if (frag == MAX_SKB_FRAGS) - return -EMSGSIZE; - - copied = iov_iter_get_pages(from, pages, ~0U, - MAX_SKB_FRAGS - frag, &start); - if (copied < 0) - return -EFAULT; - - iov_iter_advance(from, copied); - - truesize = PAGE_ALIGN(copied + start); - skb->data_len += copied; - skb->len += copied; - skb->truesize += truesize; - atomic_add(truesize, &skb->sk->sk_wmem_alloc); - while (copied) { - int size = min_t(int, copied, PAGE_SIZE - start); - skb_fill_page_desc(skb, frag++, pages[n], start, size); - start = 0; - copied -= size; - n++; - } - } - return 0; -} -EXPORT_SYMBOL(zerocopy_sg_from_iter); - -static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, - struct iov_iter *to, int len, - __wsum *csump) -{ - int start = skb_headlen(skb); - int i, copy = start - offset; - struct sk_buff *frag_iter; - int pos = 0; - int n; - - /* Copy header. */ - if (copy > 0) { - if (copy > len) - copy = len; - n = csum_and_copy_to_iter(skb->data + offset, copy, csump, to); - if (n != copy) - goto fault; - if ((len -= copy) == 0) - return 0; - offset += copy; - pos = copy; - } - - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - int end; - const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - WARN_ON(start > offset + len); - - end = start + skb_frag_size(frag); - if ((copy = end - offset) > 0) { - __wsum csum2 = 0; - struct page *page = skb_frag_page(frag); - u8 *vaddr = kmap(page); - - if (copy > len) - copy = len; - n = csum_and_copy_to_iter(vaddr + frag->page_offset + - offset - start, copy, - &csum2, to); - kunmap(page); - if (n != copy) - goto fault; - *csump = csum_block_add(*csump, csum2, pos); - if (!(len -= copy)) - return 0; - offset += copy; - pos += copy; - } - start = end; - } - - skb_walk_frags(skb, frag_iter) { - int end; - - WARN_ON(start > offset + len); - - end = start + frag_iter->len; - if ((copy = end - offset) > 0) { - __wsum csum2 = 0; - if (copy > len) - copy = len; - if (skb_copy_and_csum_datagram(frag_iter, - offset - start, - to, copy, - &csum2)) - goto fault; - *csump = csum_block_add(*csump, csum2, pos); - if ((len -= copy) == 0) - return 0; - offset += copy; - pos += copy; - } - start = end; - } - if (!len) - return 0; - -fault: - return -EFAULT; -} - -__sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len) -{ - __sum16 sum; - - sum = csum_fold(skb_checksum(skb, 0, len, skb->csum)); - if (likely(!sum)) { - if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && - !skb->csum_complete_sw) - netdev_rx_csum_fault(skb->dev); - } - if (!skb_shared(skb)) - skb->csum_valid = !sum; - return sum; -} -EXPORT_SYMBOL(__skb_checksum_complete_head); - -__sum16 __skb_checksum_complete(struct sk_buff *skb) -{ - __wsum csum; - __sum16 sum; - - csum = skb_checksum(skb, 0, skb->len, 0); - - /* skb->csum holds pseudo checksum */ - sum = csum_fold(csum_add(skb->csum, csum)); - if (likely(!sum)) { - if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && - !skb->csum_complete_sw) - netdev_rx_csum_fault(skb->dev); - } - - if (!skb_shared(skb)) { - /* Save full packet checksum */ - skb->csum = csum; - skb->ip_summed = CHECKSUM_COMPLETE; - skb->csum_complete_sw = 1; - skb->csum_valid = !sum; - } - - return sum; -} -EXPORT_SYMBOL(__skb_checksum_complete); - -/** - * skb_copy_and_csum_datagram_msg - Copy and checksum skb to user iovec. - * @skb: skbuff - * @hlen: hardware length - * @msg: destination - * - * Caller _must_ check that skb will fit to this iovec. - * - * Returns: 0 - success. - * -EINVAL - checksum failure. - * -EFAULT - fault during copy. - */ -int skb_copy_and_csum_datagram_msg(struct sk_buff *skb, - int hlen, struct msghdr *msg) -{ - __wsum csum; - int chunk = skb->len - hlen; - - if (!chunk) - return 0; - - if (msg_data_left(msg) < chunk) { - if (__skb_checksum_complete(skb)) - goto csum_error; - if (skb_copy_datagram_msg(skb, hlen, msg, chunk)) - goto fault; - } else { - csum = csum_partial(skb->data, hlen, skb->csum); - if (skb_copy_and_csum_datagram(skb, hlen, &msg->msg_iter, - chunk, &csum)) - goto fault; - if (csum_fold(csum)) - goto csum_error; - if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE)) - netdev_rx_csum_fault(skb->dev); - } - return 0; -csum_error: - return -EINVAL; -fault: - return -EFAULT; -} -EXPORT_SYMBOL(skb_copy_and_csum_datagram_msg); - -/** - * datagram_poll - generic datagram poll - * @file: file struct - * @sock: socket - * @wait: poll table - * - * Datagram poll: Again totally generic. This also handles - * sequenced packet sockets providing the socket receive queue - * is only ever holding data ready to receive. - * - * Note: when you _don't_ use this routine for this protocol, - * and you use a different write policy from sock_writeable() - * then please supply your own write_space callback. - */ -unsigned int datagram_poll(struct file *file, struct socket *sock, - poll_table *wait) -{ - struct sock *sk = sock->sk; - unsigned int mask; - - sock_poll_wait(file, sk_sleep(sk), wait); - mask = 0; - - /* exceptional events? */ - if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) - mask |= POLLERR | - (sock_flag(sk, SOCK_SELECT_ERR_QUEUE) ? POLLPRI : 0); - - if (sk->sk_shutdown & RCV_SHUTDOWN) - mask |= POLLRDHUP | POLLIN | POLLRDNORM; - if (sk->sk_shutdown == SHUTDOWN_MASK) - mask |= POLLHUP; - - /* readable? */ - if (!skb_queue_empty(&sk->sk_receive_queue)) - mask |= POLLIN | POLLRDNORM; - - /* Connection-based need to check for termination and startup */ - if (connection_based(sk)) { - if (sk->sk_state == TCP_CLOSE) - mask |= POLLHUP; - /* connection hasn't started yet? */ - if (sk->sk_state == TCP_SYN_SENT) - return mask; - } - - /* writable? */ - if (sock_writeable(sk)) - mask |= POLLOUT | POLLWRNORM | POLLWRBAND; - else - sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); - - return mask; -} -EXPORT_SYMBOL(datagram_poll); diff --git a/src/linux/net/core/dev.c b/src/linux/net/core/dev.c deleted file mode 100644 index 6666b28..0000000 --- a/src/linux/net/core/dev.c +++ /dev/null @@ -1,8356 +0,0 @@ -/* - * NET3 Protocol independent device support routines. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Derived from the non IP parts of dev.c 1.0.19 - * Authors: Ross Biro - * Fred N. van Kempen, - * Mark Evans, - * - * Additional Authors: - * Florian la Roche - * Alan Cox - * David Hinds - * Alexey Kuznetsov - * Adam Sulmicki - * Pekka Riikonen - * - * Changes: - * D.J. Barrow : Fixed bug where dev->refcnt gets set - * to 2 if register_netdev gets called - * before net_dev_init & also removed a - * few lines of code in the process. - * Alan Cox : device private ioctl copies fields back. - * Alan Cox : Transmit queue code does relevant - * stunts to keep the queue safe. - * Alan Cox : Fixed double lock. - * Alan Cox : Fixed promisc NULL pointer trap - * ???????? : Support the full private ioctl range - * Alan Cox : Moved ioctl permission check into - * drivers - * Tim Kordas : SIOCADDMULTI/SIOCDELMULTI - * Alan Cox : 100 backlog just doesn't cut it when - * you start doing multicast video 8) - * Alan Cox : Rewrote net_bh and list manager. - * Alan Cox : Fix ETH_P_ALL echoback lengths. - * Alan Cox : Took out transmit every packet pass - * Saved a few bytes in the ioctl handler - * Alan Cox : Network driver sets packet type before - * calling netif_rx. Saves a function - * call a packet. - * Alan Cox : Hashed net_bh() - * Richard Kooijman: Timestamp fixes. - * Alan Cox : Wrong field in SIOCGIFDSTADDR - * Alan Cox : Device lock protection. - * Alan Cox : Fixed nasty side effect of device close - * changes. - * Rudi Cilibrasi : Pass the right thing to - * set_mac_address() - * Dave Miller : 32bit quantity for the device lock to - * make it work out on a Sparc. - * Bjorn Ekwall : Added KERNELD hack. - * Alan Cox : Cleaned up the backlog initialise. - * Craig Metz : SIOCGIFCONF fix if space for under - * 1 device. - * Thomas Bogendoerfer : Return ENODEV for dev_open, if there - * is no device open function. - * Andi Kleen : Fix error reporting for SIOCGIFCONF - * Michael Chastain : Fix signed/unsigned for SIOCGIFCONF - * Cyrus Durgin : Cleaned for KMOD - * Adam Sulmicki : Bug Fix : Network Device Unload - * A network device unload needs to purge - * the backlog queue. - * Paul Rusty Russell : SIOCSIFNAME - * Pekka Riikonen : Netdev boot-time settings code - * Andrew Morton : Make unregister_netdevice wait - * indefinitely on dev->refcnt - * J Hadi Salim : - Backlog queue sampling - * - netif_rx() feedback - */ - -#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 -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "net-sysfs.h" - -/* Instead of increasing this, you should create a hash table. */ -#define MAX_GRO_SKBS 8 - -/* This should be increased if a protocol with a bigger head is added. */ -#define GRO_MAX_HEAD (MAX_HEADER + 128) - -static DEFINE_SPINLOCK(ptype_lock); -static DEFINE_SPINLOCK(offload_lock); -struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly; -struct list_head ptype_all __read_mostly; /* Taps */ -static struct list_head offload_base __read_mostly; - -static int netif_rx_internal(struct sk_buff *skb); -static int call_netdevice_notifiers_info(unsigned long val, - struct net_device *dev, - struct netdev_notifier_info *info); - -/* - * The @dev_base_head list is protected by @dev_base_lock and the rtnl - * semaphore. - * - * Pure readers hold dev_base_lock for reading, or rcu_read_lock() - * - * Writers must hold the rtnl semaphore while they loop through the - * dev_base_head list, and hold dev_base_lock for writing when they do the - * actual updates. This allows pure readers to access the list even - * while a writer is preparing to update it. - * - * To put it another way, dev_base_lock is held for writing only to - * protect against pure readers; the rtnl semaphore provides the - * protection against other writers. - * - * See, for example usages, register_netdevice() and - * unregister_netdevice(), which must be called with the rtnl - * semaphore held. - */ -DEFINE_RWLOCK(dev_base_lock); -EXPORT_SYMBOL(dev_base_lock); - -/* protects napi_hash addition/deletion and napi_gen_id */ -static DEFINE_SPINLOCK(napi_hash_lock); - -static unsigned int napi_gen_id = NR_CPUS; -static DEFINE_READ_MOSTLY_HASHTABLE(napi_hash, 8); - -static seqcount_t devnet_rename_seq; - -static inline void dev_base_seq_inc(struct net *net) -{ - while (++net->dev_base_seq == 0); -} - -static inline struct hlist_head *dev_name_hash(struct net *net, const char *name) -{ - unsigned int hash = full_name_hash(net, name, strnlen(name, IFNAMSIZ)); - - return &net->dev_name_head[hash_32(hash, NETDEV_HASHBITS)]; -} - -static inline struct hlist_head *dev_index_hash(struct net *net, int ifindex) -{ - return &net->dev_index_head[ifindex & (NETDEV_HASHENTRIES - 1)]; -} - -static inline void rps_lock(struct softnet_data *sd) -{ -#ifdef CONFIG_RPS - spin_lock(&sd->input_pkt_queue.lock); -#endif -} - -static inline void rps_unlock(struct softnet_data *sd) -{ -#ifdef CONFIG_RPS - spin_unlock(&sd->input_pkt_queue.lock); -#endif -} - -/* Device list insertion */ -static void list_netdevice(struct net_device *dev) -{ - struct net *net = dev_net(dev); - - ASSERT_RTNL(); - - write_lock_bh(&dev_base_lock); - list_add_tail_rcu(&dev->dev_list, &net->dev_base_head); - hlist_add_head_rcu(&dev->name_hlist, dev_name_hash(net, dev->name)); - hlist_add_head_rcu(&dev->index_hlist, - dev_index_hash(net, dev->ifindex)); - write_unlock_bh(&dev_base_lock); - - dev_base_seq_inc(net); -} - -/* Device list removal - * caller must respect a RCU grace period before freeing/reusing dev - */ -static void unlist_netdevice(struct net_device *dev) -{ - ASSERT_RTNL(); - - /* Unlink dev from the device chain */ - write_lock_bh(&dev_base_lock); - list_del_rcu(&dev->dev_list); - hlist_del_rcu(&dev->name_hlist); - hlist_del_rcu(&dev->index_hlist); - write_unlock_bh(&dev_base_lock); - - dev_base_seq_inc(dev_net(dev)); -} - -/* - * Our notifier list - */ - -static RAW_NOTIFIER_HEAD(netdev_chain); - -/* - * Device drivers call our routines to queue packets here. We empty the - * queue in the local softnet handler. - */ - -DEFINE_PER_CPU_ALIGNED(struct softnet_data, softnet_data); -EXPORT_PER_CPU_SYMBOL(softnet_data); - -#ifdef CONFIG_LOCKDEP -/* - * register_netdevice() inits txq->_xmit_lock and sets lockdep class - * according to dev->type - */ -static const unsigned short netdev_lock_type[] = - {ARPHRD_NETROM, ARPHRD_ETHER, ARPHRD_EETHER, ARPHRD_AX25, - ARPHRD_PRONET, ARPHRD_CHAOS, ARPHRD_IEEE802, ARPHRD_ARCNET, - ARPHRD_APPLETLK, ARPHRD_DLCI, ARPHRD_ATM, ARPHRD_METRICOM, - ARPHRD_IEEE1394, ARPHRD_EUI64, ARPHRD_INFINIBAND, ARPHRD_SLIP, - ARPHRD_CSLIP, ARPHRD_SLIP6, ARPHRD_CSLIP6, ARPHRD_RSRVD, - ARPHRD_ADAPT, ARPHRD_ROSE, ARPHRD_X25, ARPHRD_HWX25, - ARPHRD_PPP, ARPHRD_CISCO, ARPHRD_LAPB, ARPHRD_DDCMP, - ARPHRD_RAWHDLC, ARPHRD_TUNNEL, ARPHRD_TUNNEL6, ARPHRD_FRAD, - ARPHRD_SKIP, ARPHRD_LOOPBACK, ARPHRD_LOCALTLK, ARPHRD_FDDI, - ARPHRD_BIF, ARPHRD_SIT, ARPHRD_IPDDP, ARPHRD_IPGRE, - ARPHRD_PIMREG, ARPHRD_HIPPI, ARPHRD_ASH, ARPHRD_ECONET, - ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL, - ARPHRD_FCFABRIC, ARPHRD_IEEE80211, ARPHRD_IEEE80211_PRISM, - ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET, ARPHRD_PHONET_PIPE, - ARPHRD_IEEE802154, ARPHRD_VOID, ARPHRD_NONE}; - -static const char *const netdev_lock_name[] = - {"_xmit_NETROM", "_xmit_ETHER", "_xmit_EETHER", "_xmit_AX25", - "_xmit_PRONET", "_xmit_CHAOS", "_xmit_IEEE802", "_xmit_ARCNET", - "_xmit_APPLETLK", "_xmit_DLCI", "_xmit_ATM", "_xmit_METRICOM", - "_xmit_IEEE1394", "_xmit_EUI64", "_xmit_INFINIBAND", "_xmit_SLIP", - "_xmit_CSLIP", "_xmit_SLIP6", "_xmit_CSLIP6", "_xmit_RSRVD", - "_xmit_ADAPT", "_xmit_ROSE", "_xmit_X25", "_xmit_HWX25", - "_xmit_PPP", "_xmit_CISCO", "_xmit_LAPB", "_xmit_DDCMP", - "_xmit_RAWHDLC", "_xmit_TUNNEL", "_xmit_TUNNEL6", "_xmit_FRAD", - "_xmit_SKIP", "_xmit_LOOPBACK", "_xmit_LOCALTLK", "_xmit_FDDI", - "_xmit_BIF", "_xmit_SIT", "_xmit_IPDDP", "_xmit_IPGRE", - "_xmit_PIMREG", "_xmit_HIPPI", "_xmit_ASH", "_xmit_ECONET", - "_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL", - "_xmit_FCFABRIC", "_xmit_IEEE80211", "_xmit_IEEE80211_PRISM", - "_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET", "_xmit_PHONET_PIPE", - "_xmit_IEEE802154", "_xmit_VOID", "_xmit_NONE"}; - -static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)]; -static struct lock_class_key netdev_addr_lock_key[ARRAY_SIZE(netdev_lock_type)]; - -static inline unsigned short netdev_lock_pos(unsigned short dev_type) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(netdev_lock_type); i++) - if (netdev_lock_type[i] == dev_type) - return i; - /* the last key is used by default */ - return ARRAY_SIZE(netdev_lock_type) - 1; -} - -static inline void netdev_set_xmit_lockdep_class(spinlock_t *lock, - unsigned short dev_type) -{ - int i; - - i = netdev_lock_pos(dev_type); - lockdep_set_class_and_name(lock, &netdev_xmit_lock_key[i], - netdev_lock_name[i]); -} - -static inline void netdev_set_addr_lockdep_class(struct net_device *dev) -{ - int i; - - i = netdev_lock_pos(dev->type); - lockdep_set_class_and_name(&dev->addr_list_lock, - &netdev_addr_lock_key[i], - netdev_lock_name[i]); -} -#else -static inline void netdev_set_xmit_lockdep_class(spinlock_t *lock, - unsigned short dev_type) -{ -} -static inline void netdev_set_addr_lockdep_class(struct net_device *dev) -{ -} -#endif - -/******************************************************************************* - - Protocol management and registration routines - -*******************************************************************************/ - -/* - * Add a protocol ID to the list. Now that the input handler is - * smarter we can dispense with all the messy stuff that used to be - * here. - * - * BEWARE!!! Protocol handlers, mangling input packets, - * MUST BE last in hash buckets and checking protocol handlers - * MUST start from promiscuous ptype_all chain in net_bh. - * It is true now, do not change it. - * Explanation follows: if protocol handler, mangling packet, will - * be the first on list, it is not able to sense, that packet - * is cloned and should be copied-on-write, so that it will - * change it and subsequent readers will get broken packet. - * --ANK (980803) - */ - -static inline struct list_head *ptype_head(const struct packet_type *pt) -{ - if (pt->type == htons(ETH_P_ALL)) - return pt->dev ? &pt->dev->ptype_all : &ptype_all; - else - return pt->dev ? &pt->dev->ptype_specific : - &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK]; -} - -/** - * dev_add_pack - add packet handler - * @pt: packet type declaration - * - * Add a protocol handler to the networking stack. The passed &packet_type - * is linked into kernel lists and may not be freed until it has been - * removed from the kernel lists. - * - * This call does not sleep therefore it can not - * guarantee all CPU's that are in middle of receiving packets - * will see the new packet type (until the next received packet). - */ - -void dev_add_pack(struct packet_type *pt) -{ - struct list_head *head = ptype_head(pt); - - spin_lock(&ptype_lock); - list_add_rcu(&pt->list, head); - spin_unlock(&ptype_lock); -} -EXPORT_SYMBOL(dev_add_pack); - -/** - * __dev_remove_pack - remove packet handler - * @pt: packet type declaration - * - * Remove a protocol handler that was previously added to the kernel - * protocol handlers by dev_add_pack(). The passed &packet_type is removed - * from the kernel lists and can be freed or reused once this function - * returns. - * - * The packet type might still be in use by receivers - * and must not be freed until after all the CPU's have gone - * through a quiescent state. - */ -void __dev_remove_pack(struct packet_type *pt) -{ - struct list_head *head = ptype_head(pt); - struct packet_type *pt1; - - spin_lock(&ptype_lock); - - list_for_each_entry(pt1, head, list) { - if (pt == pt1) { - list_del_rcu(&pt->list); - goto out; - } - } - - pr_warn("dev_remove_pack: %p not found\n", pt); -out: - spin_unlock(&ptype_lock); -} -EXPORT_SYMBOL(__dev_remove_pack); - -/** - * dev_remove_pack - remove packet handler - * @pt: packet type declaration - * - * Remove a protocol handler that was previously added to the kernel - * protocol handlers by dev_add_pack(). The passed &packet_type is removed - * from the kernel lists and can be freed or reused once this function - * returns. - * - * This call sleeps to guarantee that no CPU is looking at the packet - * type after return. - */ -void dev_remove_pack(struct packet_type *pt) -{ - __dev_remove_pack(pt); - - synchronize_net(); -} -EXPORT_SYMBOL(dev_remove_pack); - - -/** - * dev_add_offload - register offload handlers - * @po: protocol offload declaration - * - * Add protocol offload handlers to the networking stack. The passed - * &proto_offload is linked into kernel lists and may not be freed until - * it has been removed from the kernel lists. - * - * This call does not sleep therefore it can not - * guarantee all CPU's that are in middle of receiving packets - * will see the new offload handlers (until the next received packet). - */ -void dev_add_offload(struct packet_offload *po) -{ - struct packet_offload *elem; - - spin_lock(&offload_lock); - list_for_each_entry(elem, &offload_base, list) { - if (po->priority < elem->priority) - break; - } - list_add_rcu(&po->list, elem->list.prev); - spin_unlock(&offload_lock); -} -EXPORT_SYMBOL(dev_add_offload); - -/** - * __dev_remove_offload - remove offload handler - * @po: packet offload declaration - * - * Remove a protocol offload handler that was previously added to the - * kernel offload handlers by dev_add_offload(). The passed &offload_type - * is removed from the kernel lists and can be freed or reused once this - * function returns. - * - * The packet type might still be in use by receivers - * and must not be freed until after all the CPU's have gone - * through a quiescent state. - */ -static void __dev_remove_offload(struct packet_offload *po) -{ - struct list_head *head = &offload_base; - struct packet_offload *po1; - - spin_lock(&offload_lock); - - list_for_each_entry(po1, head, list) { - if (po == po1) { - list_del_rcu(&po->list); - goto out; - } - } - - pr_warn("dev_remove_offload: %p not found\n", po); -out: - spin_unlock(&offload_lock); -} - -/** - * dev_remove_offload - remove packet offload handler - * @po: packet offload declaration - * - * Remove a packet offload handler that was previously added to the kernel - * offload handlers by dev_add_offload(). The passed &offload_type is - * removed from the kernel lists and can be freed or reused once this - * function returns. - * - * This call sleeps to guarantee that no CPU is looking at the packet - * type after return. - */ -void dev_remove_offload(struct packet_offload *po) -{ - __dev_remove_offload(po); - - synchronize_net(); -} -EXPORT_SYMBOL(dev_remove_offload); - -/****************************************************************************** - - Device Boot-time Settings Routines - -*******************************************************************************/ - -/* Boot time configuration table */ -static struct netdev_boot_setup dev_boot_setup[NETDEV_BOOT_SETUP_MAX]; - -/** - * netdev_boot_setup_add - add new setup entry - * @name: name of the device - * @map: configured settings for the device - * - * Adds new setup entry to the dev_boot_setup list. The function - * returns 0 on error and 1 on success. This is a generic routine to - * all netdevices. - */ -static int netdev_boot_setup_add(char *name, struct ifmap *map) -{ - struct netdev_boot_setup *s; - int i; - - s = dev_boot_setup; - for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) { - if (s[i].name[0] == '\0' || s[i].name[0] == ' ') { - memset(s[i].name, 0, sizeof(s[i].name)); - strlcpy(s[i].name, name, IFNAMSIZ); - memcpy(&s[i].map, map, sizeof(s[i].map)); - break; - } - } - - return i >= NETDEV_BOOT_SETUP_MAX ? 0 : 1; -} - -/** - * netdev_boot_setup_check - check boot time settings - * @dev: the netdevice - * - * Check boot time settings for the device. - * The found settings are set for the device to be used - * later in the device probing. - * Returns 0 if no settings found, 1 if they are. - */ -int netdev_boot_setup_check(struct net_device *dev) -{ - struct netdev_boot_setup *s = dev_boot_setup; - int i; - - for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) { - if (s[i].name[0] != '\0' && s[i].name[0] != ' ' && - !strcmp(dev->name, s[i].name)) { - dev->irq = s[i].map.irq; - dev->base_addr = s[i].map.base_addr; - dev->mem_start = s[i].map.mem_start; - dev->mem_end = s[i].map.mem_end; - return 1; - } - } - return 0; -} -EXPORT_SYMBOL(netdev_boot_setup_check); - - -/** - * netdev_boot_base - get address from boot time settings - * @prefix: prefix for network device - * @unit: id for network device - * - * Check boot time settings for the base address of device. - * The found settings are set for the device to be used - * later in the device probing. - * Returns 0 if no settings found. - */ -unsigned long netdev_boot_base(const char *prefix, int unit) -{ - const struct netdev_boot_setup *s = dev_boot_setup; - char name[IFNAMSIZ]; - int i; - - sprintf(name, "%s%d", prefix, unit); - - /* - * If device already registered then return base of 1 - * to indicate not to probe for this interface - */ - if (__dev_get_by_name(&init_net, name)) - return 1; - - for (i = 0; i < NETDEV_BOOT_SETUP_MAX; i++) - if (!strcmp(name, s[i].name)) - return s[i].map.base_addr; - return 0; -} - -/* - * Saves at boot time configured settings for any netdevice. - */ -int __init netdev_boot_setup(char *str) -{ - int ints[5]; - struct ifmap map; - - str = get_options(str, ARRAY_SIZE(ints), ints); - if (!str || !*str) - return 0; - - /* Save settings */ - memset(&map, 0, sizeof(map)); - if (ints[0] > 0) - map.irq = ints[1]; - if (ints[0] > 1) - map.base_addr = ints[2]; - if (ints[0] > 2) - map.mem_start = ints[3]; - if (ints[0] > 3) - map.mem_end = ints[4]; - - /* Add new entry to the list */ - return netdev_boot_setup_add(str, &map); -} - -__setup("netdev=", netdev_boot_setup); - -/******************************************************************************* - - Device Interface Subroutines - -*******************************************************************************/ - -/** - * dev_get_iflink - get 'iflink' value of a interface - * @dev: targeted interface - * - * Indicates the ifindex the interface is linked to. - * Physical interfaces have the same 'ifindex' and 'iflink' values. - */ - -int dev_get_iflink(const struct net_device *dev) -{ - if (dev->netdev_ops && dev->netdev_ops->ndo_get_iflink) - return dev->netdev_ops->ndo_get_iflink(dev); - - return dev->ifindex; -} -EXPORT_SYMBOL(dev_get_iflink); - -/** - * dev_fill_metadata_dst - Retrieve tunnel egress information. - * @dev: targeted interface - * @skb: The packet. - * - * For better visibility of tunnel traffic OVS needs to retrieve - * egress tunnel information for a packet. Following API allows - * user to get this info. - */ -int dev_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) -{ - struct ip_tunnel_info *info; - - if (!dev->netdev_ops || !dev->netdev_ops->ndo_fill_metadata_dst) - return -EINVAL; - - info = skb_tunnel_info_unclone(skb); - if (!info) - return -ENOMEM; - if (unlikely(!(info->mode & IP_TUNNEL_INFO_TX))) - return -EINVAL; - - return dev->netdev_ops->ndo_fill_metadata_dst(dev, skb); -} -EXPORT_SYMBOL_GPL(dev_fill_metadata_dst); - -/** - * __dev_get_by_name - find a device by its name - * @net: the applicable net namespace - * @name: name to find - * - * Find an interface by name. Must be called under RTNL semaphore - * or @dev_base_lock. If the name is found a pointer to the device - * is returned. If the name is not found then %NULL is returned. The - * reference counters are not incremented so the caller must be - * careful with locks. - */ - -struct net_device *__dev_get_by_name(struct net *net, const char *name) -{ - struct net_device *dev; - struct hlist_head *head = dev_name_hash(net, name); - - hlist_for_each_entry(dev, head, name_hlist) - if (!strncmp(dev->name, name, IFNAMSIZ)) - return dev; - - return NULL; -} -EXPORT_SYMBOL(__dev_get_by_name); - -/** - * dev_get_by_name_rcu - find a device by its name - * @net: the applicable net namespace - * @name: name to find - * - * Find an interface by name. - * If the name is found a pointer to the device is returned. - * If the name is not found then %NULL is returned. - * The reference counters are not incremented so the caller must be - * careful with locks. The caller must hold RCU lock. - */ - -struct net_device *dev_get_by_name_rcu(struct net *net, const char *name) -{ - struct net_device *dev; - struct hlist_head *head = dev_name_hash(net, name); - - hlist_for_each_entry_rcu(dev, head, name_hlist) - if (!strncmp(dev->name, name, IFNAMSIZ)) - return dev; - - return NULL; -} -EXPORT_SYMBOL(dev_get_by_name_rcu); - -/** - * dev_get_by_name - find a device by its name - * @net: the applicable net namespace - * @name: name to find - * - * Find an interface by name. This can be called from any - * context and does its own locking. The returned handle has - * the usage count incremented and the caller must use dev_put() to - * release it when it is no longer needed. %NULL is returned if no - * matching device is found. - */ - -struct net_device *dev_get_by_name(struct net *net, const char *name) -{ - struct net_device *dev; - - rcu_read_lock(); - dev = dev_get_by_name_rcu(net, name); - if (dev) - dev_hold(dev); - rcu_read_unlock(); - return dev; -} -EXPORT_SYMBOL(dev_get_by_name); - -/** - * __dev_get_by_index - find a device by its ifindex - * @net: the applicable net namespace - * @ifindex: index of device - * - * Search for an interface by index. Returns %NULL if the device - * is not found or a pointer to the device. The device has not - * had its reference counter increased so the caller must be careful - * about locking. The caller must hold either the RTNL semaphore - * or @dev_base_lock. - */ - -struct net_device *__dev_get_by_index(struct net *net, int ifindex) -{ - struct net_device *dev; - struct hlist_head *head = dev_index_hash(net, ifindex); - - hlist_for_each_entry(dev, head, index_hlist) - if (dev->ifindex == ifindex) - return dev; - - return NULL; -} -EXPORT_SYMBOL(__dev_get_by_index); - -/** - * dev_get_by_index_rcu - find a device by its ifindex - * @net: the applicable net namespace - * @ifindex: index of device - * - * Search for an interface by index. Returns %NULL if the device - * is not found or a pointer to the device. The device has not - * had its reference counter increased so the caller must be careful - * about locking. The caller must hold RCU lock. - */ - -struct net_device *dev_get_by_index_rcu(struct net *net, int ifindex) -{ - struct net_device *dev; - struct hlist_head *head = dev_index_hash(net, ifindex); - - hlist_for_each_entry_rcu(dev, head, index_hlist) - if (dev->ifindex == ifindex) - return dev; - - return NULL; -} -EXPORT_SYMBOL(dev_get_by_index_rcu); - - -/** - * dev_get_by_index - find a device by its ifindex - * @net: the applicable net namespace - * @ifindex: index of device - * - * Search for an interface by index. Returns NULL if the device - * is not found or a pointer to the device. The device returned has - * had a reference added and the pointer is safe until the user calls - * dev_put to indicate they have finished with it. - */ - -struct net_device *dev_get_by_index(struct net *net, int ifindex) -{ - struct net_device *dev; - - rcu_read_lock(); - dev = dev_get_by_index_rcu(net, ifindex); - if (dev) - dev_hold(dev); - rcu_read_unlock(); - return dev; -} -EXPORT_SYMBOL(dev_get_by_index); - -/** - * netdev_get_name - get a netdevice name, knowing its ifindex. - * @net: network namespace - * @name: a pointer to the buffer where the name will be stored. - * @ifindex: the ifindex of the interface to get the name from. - * - * The use of raw_seqcount_begin() and cond_resched() before - * retrying is required as we want to give the writers a chance - * to complete when CONFIG_PREEMPT is not set. - */ -int netdev_get_name(struct net *net, char *name, int ifindex) -{ - struct net_device *dev; - unsigned int seq; - -retry: - seq = raw_seqcount_begin(&devnet_rename_seq); - rcu_read_lock(); - dev = dev_get_by_index_rcu(net, ifindex); - if (!dev) { - rcu_read_unlock(); - return -ENODEV; - } - - strcpy(name, dev->name); - rcu_read_unlock(); - if (read_seqcount_retry(&devnet_rename_seq, seq)) { - cond_resched(); - goto retry; - } - - return 0; -} - -/** - * dev_getbyhwaddr_rcu - find a device by its hardware address - * @net: the applicable net namespace - * @type: media type of device - * @ha: hardware address - * - * Search for an interface by MAC address. Returns NULL if the device - * is not found or a pointer to the device. - * The caller must hold RCU or RTNL. - * The returned device has not had its ref count increased - * and the caller must therefore be careful about locking - * - */ - -struct net_device *dev_getbyhwaddr_rcu(struct net *net, unsigned short type, - const char *ha) -{ - struct net_device *dev; - - for_each_netdev_rcu(net, dev) - if (dev->type == type && - !memcmp(dev->dev_addr, ha, dev->addr_len)) - return dev; - - return NULL; -} -EXPORT_SYMBOL(dev_getbyhwaddr_rcu); - -struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type) -{ - struct net_device *dev; - - ASSERT_RTNL(); - for_each_netdev(net, dev) - if (dev->type == type) - return dev; - - return NULL; -} -EXPORT_SYMBOL(__dev_getfirstbyhwtype); - -struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type) -{ - struct net_device *dev, *ret = NULL; - - rcu_read_lock(); - for_each_netdev_rcu(net, dev) - if (dev->type == type) { - dev_hold(dev); - ret = dev; - break; - } - rcu_read_unlock(); - return ret; -} -EXPORT_SYMBOL(dev_getfirstbyhwtype); - -/** - * __dev_get_by_flags - find any device with given flags - * @net: the applicable net namespace - * @if_flags: IFF_* values - * @mask: bitmask of bits in if_flags to check - * - * Search for any interface with the given flags. Returns NULL if a device - * is not found or a pointer to the device. Must be called inside - * rtnl_lock(), and result refcount is unchanged. - */ - -struct net_device *__dev_get_by_flags(struct net *net, unsigned short if_flags, - unsigned short mask) -{ - struct net_device *dev, *ret; - - ASSERT_RTNL(); - - ret = NULL; - for_each_netdev(net, dev) { - if (((dev->flags ^ if_flags) & mask) == 0) { - ret = dev; - break; - } - } - return ret; -} -EXPORT_SYMBOL(__dev_get_by_flags); - -/** - * dev_valid_name - check if name is okay for network device - * @name: name string - * - * Network device names need to be valid file names to - * to allow sysfs to work. We also disallow any kind of - * whitespace. - */ -bool dev_valid_name(const char *name) -{ - if (*name == '\0') - return false; - if (strlen(name) >= IFNAMSIZ) - return false; - if (!strcmp(name, ".") || !strcmp(name, "..")) - return false; - - while (*name) { - if (*name == '/' || *name == ':' || isspace(*name)) - return false; - name++; - } - return true; -} -EXPORT_SYMBOL(dev_valid_name); - -/** - * __dev_alloc_name - allocate a name for a device - * @net: network namespace to allocate the device name in - * @name: name format string - * @buf: scratch buffer and result name string - * - * Passed a format string - eg "lt%d" it will try and find a suitable - * id. It scans list of devices to build up a free map, then chooses - * the first empty slot. The caller must hold the dev_base or rtnl lock - * while allocating the name and adding the device in order to avoid - * duplicates. - * Limited to bits_per_byte * page size devices (ie 32K on most platforms). - * Returns the number of the unit assigned or a negative errno code. - */ - -static int __dev_alloc_name(struct net *net, const char *name, char *buf) -{ - int i = 0; - const char *p; - const int max_netdevices = 8*PAGE_SIZE; - unsigned long *inuse; - struct net_device *d; - - p = strnchr(name, IFNAMSIZ-1, '%'); - if (p) { - /* - * Verify the string as this thing may have come from - * the user. There must be either one "%d" and no other "%" - * characters. - */ - if (p[1] != 'd' || strchr(p + 2, '%')) - return -EINVAL; - - /* Use one page as a bit array of possible slots */ - inuse = (unsigned long *) get_zeroed_page(GFP_ATOMIC); - if (!inuse) - return -ENOMEM; - - for_each_netdev(net, d) { - if (!sscanf(d->name, name, &i)) - continue; - if (i < 0 || i >= max_netdevices) - continue; - - /* avoid cases where sscanf is not exact inverse of printf */ - snprintf(buf, IFNAMSIZ, name, i); - if (!strncmp(buf, d->name, IFNAMSIZ)) - set_bit(i, inuse); - } - - i = find_first_zero_bit(inuse, max_netdevices); - free_page((unsigned long) inuse); - } - - if (buf != name) - snprintf(buf, IFNAMSIZ, name, i); - if (!__dev_get_by_name(net, buf)) - return i; - - /* It is possible to run out of possible slots - * when the name is long and there isn't enough space left - * for the digits, or if all bits are used. - */ - return -ENFILE; -} - -/** - * dev_alloc_name - allocate a name for a device - * @dev: device - * @name: name format string - * - * Passed a format string - eg "lt%d" it will try and find a suitable - * id. It scans list of devices to build up a free map, then chooses - * the first empty slot. The caller must hold the dev_base or rtnl lock - * while allocating the name and adding the device in order to avoid - * duplicates. - * Limited to bits_per_byte * page size devices (ie 32K on most platforms). - * Returns the number of the unit assigned or a negative errno code. - */ - -int dev_alloc_name(struct net_device *dev, const char *name) -{ - char buf[IFNAMSIZ]; - struct net *net; - int ret; - - BUG_ON(!dev_net(dev)); - net = dev_net(dev); - ret = __dev_alloc_name(net, name, buf); - if (ret >= 0) - strlcpy(dev->name, buf, IFNAMSIZ); - return ret; -} -EXPORT_SYMBOL(dev_alloc_name); - -static int dev_alloc_name_ns(struct net *net, - struct net_device *dev, - const char *name) -{ - char buf[IFNAMSIZ]; - int ret; - - ret = __dev_alloc_name(net, name, buf); - if (ret >= 0) - strlcpy(dev->name, buf, IFNAMSIZ); - return ret; -} - -static int dev_get_valid_name(struct net *net, - struct net_device *dev, - const char *name) -{ - BUG_ON(!net); - - if (!dev_valid_name(name)) - return -EINVAL; - - if (strchr(name, '%')) - return dev_alloc_name_ns(net, dev, name); - else if (__dev_get_by_name(net, name)) - return -EEXIST; - else if (dev->name != name) - strlcpy(dev->name, name, IFNAMSIZ); - - return 0; -} - -/** - * dev_change_name - change name of a device - * @dev: device - * @newname: name (or format string) must be at least IFNAMSIZ - * - * Change name of a device, can pass format strings "eth%d". - * for wildcarding. - */ -int dev_change_name(struct net_device *dev, const char *newname) -{ - unsigned char old_assign_type; - char oldname[IFNAMSIZ]; - int err = 0; - int ret; - struct net *net; - - ASSERT_RTNL(); - BUG_ON(!dev_net(dev)); - - net = dev_net(dev); - if (dev->flags & IFF_UP) - return -EBUSY; - - write_seqcount_begin(&devnet_rename_seq); - - if (strncmp(newname, dev->name, IFNAMSIZ) == 0) { - write_seqcount_end(&devnet_rename_seq); - return 0; - } - - memcpy(oldname, dev->name, IFNAMSIZ); - - err = dev_get_valid_name(net, dev, newname); - if (err < 0) { - write_seqcount_end(&devnet_rename_seq); - return err; - } - - if (oldname[0] && !strchr(oldname, '%')) - netdev_info(dev, "renamed from %s\n", oldname); - - old_assign_type = dev->name_assign_type; - dev->name_assign_type = NET_NAME_RENAMED; - -rollback: - ret = device_rename(&dev->dev, dev->name); - if (ret) { - memcpy(dev->name, oldname, IFNAMSIZ); - dev->name_assign_type = old_assign_type; - write_seqcount_end(&devnet_rename_seq); - return ret; - } - - write_seqcount_end(&devnet_rename_seq); - - netdev_adjacent_rename_links(dev, oldname); - - write_lock_bh(&dev_base_lock); - hlist_del_rcu(&dev->name_hlist); - write_unlock_bh(&dev_base_lock); - - synchronize_rcu(); - - write_lock_bh(&dev_base_lock); - hlist_add_head_rcu(&dev->name_hlist, dev_name_hash(net, dev->name)); - write_unlock_bh(&dev_base_lock); - - ret = call_netdevice_notifiers(NETDEV_CHANGENAME, dev); - ret = notifier_to_errno(ret); - - if (ret) { - /* err >= 0 after dev_alloc_name() or stores the first errno */ - if (err >= 0) { - err = ret; - write_seqcount_begin(&devnet_rename_seq); - memcpy(dev->name, oldname, IFNAMSIZ); - memcpy(oldname, newname, IFNAMSIZ); - dev->name_assign_type = old_assign_type; - old_assign_type = NET_NAME_RENAMED; - goto rollback; - } else { - pr_err("%s: name change rollback failed: %d\n", - dev->name, ret); - } - } - - return err; -} - -/** - * dev_set_alias - change ifalias of a device - * @dev: device - * @alias: name up to IFALIASZ - * @len: limit of bytes to copy from info - * - * Set ifalias for a device, - */ -int dev_set_alias(struct net_device *dev, const char *alias, size_t len) -{ - char *new_ifalias; - - ASSERT_RTNL(); - - if (len >= IFALIASZ) - return -EINVAL; - - if (!len) { - kfree(dev->ifalias); - dev->ifalias = NULL; - return 0; - } - - new_ifalias = krealloc(dev->ifalias, len + 1, GFP_KERNEL); - if (!new_ifalias) - return -ENOMEM; - dev->ifalias = new_ifalias; - - strlcpy(dev->ifalias, alias, len+1); - return len; -} - - -/** - * netdev_features_change - device changes features - * @dev: device to cause notification - * - * Called to indicate a device has changed features. - */ -void netdev_features_change(struct net_device *dev) -{ - call_netdevice_notifiers(NETDEV_FEAT_CHANGE, dev); -} -EXPORT_SYMBOL(netdev_features_change); - -/** - * netdev_state_change - device changes state - * @dev: device to cause notification - * - * Called to indicate a device has changed state. This function calls - * the notifier chains for netdev_chain and sends a NEWLINK message - * to the routing socket. - */ -void netdev_state_change(struct net_device *dev) -{ - if (dev->flags & IFF_UP) { - struct netdev_notifier_change_info change_info; - - change_info.flags_changed = 0; - call_netdevice_notifiers_info(NETDEV_CHANGE, dev, - &change_info.info); - rtmsg_ifinfo(RTM_NEWLINK, dev, 0, GFP_KERNEL); - } -} -EXPORT_SYMBOL(netdev_state_change); - -/** - * netdev_notify_peers - notify network peers about existence of @dev - * @dev: network device - * - * Generate traffic such that interested network peers are aware of - * @dev, such as by generating a gratuitous ARP. This may be used when - * a device wants to inform the rest of the network about some sort of - * reconfiguration such as a failover event or virtual machine - * migration. - */ -void netdev_notify_peers(struct net_device *dev) -{ - rtnl_lock(); - call_netdevice_notifiers(NETDEV_NOTIFY_PEERS, dev); - rtnl_unlock(); -} -EXPORT_SYMBOL(netdev_notify_peers); - -static int __dev_open(struct net_device *dev) -{ - const struct net_device_ops *ops = dev->netdev_ops; - int ret; - - ASSERT_RTNL(); - - if (!netif_device_present(dev)) - return -ENODEV; - - /* Block netpoll from trying to do any rx path servicing. - * If we don't do this there is a chance ndo_poll_controller - * or ndo_poll may be running while we open the device - */ - netpoll_poll_disable(dev); - - ret = call_netdevice_notifiers(NETDEV_PRE_UP, dev); - ret = notifier_to_errno(ret); - if (ret) - return ret; - - set_bit(__LINK_STATE_START, &dev->state); - - if (ops->ndo_validate_addr) - ret = ops->ndo_validate_addr(dev); - - if (!ret && ops->ndo_open) - ret = ops->ndo_open(dev); - - netpoll_poll_enable(dev); - - if (ret) - clear_bit(__LINK_STATE_START, &dev->state); - else { - dev->flags |= IFF_UP; - dev_set_rx_mode(dev); - dev_activate(dev); - add_device_randomness(dev->dev_addr, dev->addr_len); - } - - return ret; -} - -/** - * dev_open - prepare an interface for use. - * @dev: device to open - * - * Takes a device from down to up state. The device's private open - * function is invoked and then the multicast lists are loaded. Finally - * the device is moved into the up state and a %NETDEV_UP message is - * sent to the netdev notifier chain. - * - * Calling this function on an active interface is a nop. On a failure - * a negative errno code is returned. - */ -int dev_open(struct net_device *dev) -{ - int ret; - - if (dev->flags & IFF_UP) - return 0; - - ret = __dev_open(dev); - if (ret < 0) - return ret; - - rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING, GFP_KERNEL); - call_netdevice_notifiers(NETDEV_UP, dev); - - return ret; -} -EXPORT_SYMBOL(dev_open); - -static int __dev_close_many(struct list_head *head) -{ - struct net_device *dev; - - ASSERT_RTNL(); - might_sleep(); - - list_for_each_entry(dev, head, close_list) { - /* Temporarily disable netpoll until the interface is down */ - netpoll_poll_disable(dev); - - call_netdevice_notifiers(NETDEV_GOING_DOWN, dev); - - clear_bit(__LINK_STATE_START, &dev->state); - - /* Synchronize to scheduled poll. We cannot touch poll list, it - * can be even on different cpu. So just clear netif_running(). - * - * dev->stop() will invoke napi_disable() on all of it's - * napi_struct instances on this device. - */ - smp_mb__after_atomic(); /* Commit netif_running(). */ - } - - dev_deactivate_many(head); - - list_for_each_entry(dev, head, close_list) { - const struct net_device_ops *ops = dev->netdev_ops; - - /* - * Call the device specific close. This cannot fail. - * Only if device is UP - * - * We allow it to be called even after a DETACH hot-plug - * event. - */ - if (ops->ndo_stop) - ops->ndo_stop(dev); - - dev->flags &= ~IFF_UP; - netpoll_poll_enable(dev); - } - - return 0; -} - -static int __dev_close(struct net_device *dev) -{ - int retval; - LIST_HEAD(single); - - list_add(&dev->close_list, &single); - retval = __dev_close_many(&single); - list_del(&single); - - return retval; -} - -int dev_close_many(struct list_head *head, bool unlink) -{ - struct net_device *dev, *tmp; - - /* Remove the devices that don't need to be closed */ - list_for_each_entry_safe(dev, tmp, head, close_list) - if (!(dev->flags & IFF_UP)) - list_del_init(&dev->close_list); - - __dev_close_many(head); - - list_for_each_entry_safe(dev, tmp, head, close_list) { - rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING, GFP_KERNEL); - call_netdevice_notifiers(NETDEV_DOWN, dev); - if (unlink) - list_del_init(&dev->close_list); - } - - return 0; -} -EXPORT_SYMBOL(dev_close_many); - -/** - * dev_close - shutdown an interface. - * @dev: device to shutdown - * - * This function moves an active device into down state. A - * %NETDEV_GOING_DOWN is sent to the netdev notifier chain. The device - * is then deactivated and finally a %NETDEV_DOWN is sent to the notifier - * chain. - */ -int dev_close(struct net_device *dev) -{ - if (dev->flags & IFF_UP) { - LIST_HEAD(single); - - list_add(&dev->close_list, &single); - dev_close_many(&single, true); - list_del(&single); - } - return 0; -} -EXPORT_SYMBOL(dev_close); - - -/** - * dev_disable_lro - disable Large Receive Offload on a device - * @dev: device - * - * Disable Large Receive Offload (LRO) on a net device. Must be - * called under RTNL. This is needed if received packets may be - * forwarded to another interface. - */ -void dev_disable_lro(struct net_device *dev) -{ - struct net_device *lower_dev; - struct list_head *iter; - - dev->wanted_features &= ~NETIF_F_LRO; - netdev_update_features(dev); - - if (unlikely(dev->features & NETIF_F_LRO)) - netdev_WARN(dev, "failed to disable LRO!\n"); - - netdev_for_each_lower_dev(dev, lower_dev, iter) - dev_disable_lro(lower_dev); -} -EXPORT_SYMBOL(dev_disable_lro); - -static int call_netdevice_notifier(struct notifier_block *nb, unsigned long val, - struct net_device *dev) -{ - struct netdev_notifier_info info; - - netdev_notifier_info_init(&info, dev); - return nb->notifier_call(nb, val, &info); -} - -static int dev_boot_phase = 1; - -/** - * register_netdevice_notifier - register a network notifier block - * @nb: notifier - * - * Register a notifier to be called when network device events occur. - * The notifier passed is linked into the kernel structures and must - * not be reused until it has been unregistered. A negative errno code - * is returned on a failure. - * - * When registered all registration and up events are replayed - * to the new notifier to allow device to have a race free - * view of the network device list. - */ - -int register_netdevice_notifier(struct notifier_block *nb) -{ - struct net_device *dev; - struct net_device *last; - struct net *net; - int err; - - rtnl_lock(); - err = raw_notifier_chain_register(&netdev_chain, nb); - if (err) - goto unlock; - if (dev_boot_phase) - goto unlock; - for_each_net(net) { - for_each_netdev(net, dev) { - err = call_netdevice_notifier(nb, NETDEV_REGISTER, dev); - err = notifier_to_errno(err); - if (err) - goto rollback; - - if (!(dev->flags & IFF_UP)) - continue; - - call_netdevice_notifier(nb, NETDEV_UP, dev); - } - } - -unlock: - rtnl_unlock(); - return err; - -rollback: - last = dev; - for_each_net(net) { - for_each_netdev(net, dev) { - if (dev == last) - goto outroll; - - if (dev->flags & IFF_UP) { - call_netdevice_notifier(nb, NETDEV_GOING_DOWN, - dev); - call_netdevice_notifier(nb, NETDEV_DOWN, dev); - } - call_netdevice_notifier(nb, NETDEV_UNREGISTER, dev); - } - } - -outroll: - raw_notifier_chain_unregister(&netdev_chain, nb); - goto unlock; -} -EXPORT_SYMBOL(register_netdevice_notifier); - -/** - * unregister_netdevice_notifier - unregister a network notifier block - * @nb: notifier - * - * Unregister a notifier previously registered by - * register_netdevice_notifier(). The notifier is unlinked into the - * kernel structures and may then be reused. A negative errno code - * is returned on a failure. - * - * After unregistering unregister and down device events are synthesized - * for all devices on the device list to the removed notifier to remove - * the need for special case cleanup code. - */ - -int unregister_netdevice_notifier(struct notifier_block *nb) -{ - struct net_device *dev; - struct net *net; - int err; - - rtnl_lock(); - err = raw_notifier_chain_unregister(&netdev_chain, nb); - if (err) - goto unlock; - - for_each_net(net) { - for_each_netdev(net, dev) { - if (dev->flags & IFF_UP) { - call_netdevice_notifier(nb, NETDEV_GOING_DOWN, - dev); - call_netdevice_notifier(nb, NETDEV_DOWN, dev); - } - call_netdevice_notifier(nb, NETDEV_UNREGISTER, dev); - } - } -unlock: - rtnl_unlock(); - return err; -} -EXPORT_SYMBOL(unregister_netdevice_notifier); - -/** - * call_netdevice_notifiers_info - call all network notifier blocks - * @val: value passed unmodified to notifier function - * @dev: net_device pointer passed unmodified to notifier function - * @info: notifier information data - * - * Call all network notifier blocks. Parameters and return value - * are as for raw_notifier_call_chain(). - */ - -static int call_netdevice_notifiers_info(unsigned long val, - struct net_device *dev, - struct netdev_notifier_info *info) -{ - ASSERT_RTNL(); - netdev_notifier_info_init(info, dev); - return raw_notifier_call_chain(&netdev_chain, val, info); -} - -/** - * call_netdevice_notifiers - call all network notifier blocks - * @val: value passed unmodified to notifier function - * @dev: net_device pointer passed unmodified to notifier function - * - * Call all network notifier blocks. Parameters and return value - * are as for raw_notifier_call_chain(). - */ - -int call_netdevice_notifiers(unsigned long val, struct net_device *dev) -{ - struct netdev_notifier_info info; - - return call_netdevice_notifiers_info(val, dev, &info); -} -EXPORT_SYMBOL(call_netdevice_notifiers); - -#ifdef CONFIG_NET_INGRESS -static struct static_key ingress_needed __read_mostly; - -void net_inc_ingress_queue(void) -{ - static_key_slow_inc(&ingress_needed); -} -EXPORT_SYMBOL_GPL(net_inc_ingress_queue); - -void net_dec_ingress_queue(void) -{ - static_key_slow_dec(&ingress_needed); -} -EXPORT_SYMBOL_GPL(net_dec_ingress_queue); -#endif - -#ifdef CONFIG_NET_EGRESS -static struct static_key egress_needed __read_mostly; - -void net_inc_egress_queue(void) -{ - static_key_slow_inc(&egress_needed); -} -EXPORT_SYMBOL_GPL(net_inc_egress_queue); - -void net_dec_egress_queue(void) -{ - static_key_slow_dec(&egress_needed); -} -EXPORT_SYMBOL_GPL(net_dec_egress_queue); -#endif - -static struct static_key netstamp_needed __read_mostly; -#ifdef HAVE_JUMP_LABEL -/* We are not allowed to call static_key_slow_dec() from irq context - * If net_disable_timestamp() is called from irq context, defer the - * static_key_slow_dec() calls. - */ -static atomic_t netstamp_needed_deferred; -#endif - -void net_enable_timestamp(void) -{ -#ifdef HAVE_JUMP_LABEL - int deferred = atomic_xchg(&netstamp_needed_deferred, 0); - - if (deferred) { - while (--deferred) - static_key_slow_dec(&netstamp_needed); - return; - } -#endif - static_key_slow_inc(&netstamp_needed); -} -EXPORT_SYMBOL(net_enable_timestamp); - -void net_disable_timestamp(void) -{ -#ifdef HAVE_JUMP_LABEL - if (in_interrupt()) { - atomic_inc(&netstamp_needed_deferred); - return; - } -#endif - static_key_slow_dec(&netstamp_needed); -} -EXPORT_SYMBOL(net_disable_timestamp); - -static inline void net_timestamp_set(struct sk_buff *skb) -{ - skb->tstamp.tv64 = 0; - if (static_key_false(&netstamp_needed)) - __net_timestamp(skb); -} - -#define net_timestamp_check(COND, SKB) \ - if (static_key_false(&netstamp_needed)) { \ - if ((COND) && !(SKB)->tstamp.tv64) \ - __net_timestamp(SKB); \ - } \ - -bool is_skb_forwardable(const struct net_device *dev, const struct sk_buff *skb) -{ - unsigned int len; - - if (!(dev->flags & IFF_UP)) - return false; - - len = dev->mtu + dev->hard_header_len + VLAN_HLEN; - if (skb->len <= len) - return true; - - /* if TSO is enabled, we don't care about the length as the packet - * could be forwarded without being segmented before - */ - if (skb_is_gso(skb)) - return true; - - return false; -} -EXPORT_SYMBOL_GPL(is_skb_forwardable); - -int __dev_forward_skb(struct net_device *dev, struct sk_buff *skb) -{ - int ret = ____dev_forward_skb(dev, skb); - - if (likely(!ret)) { - skb->protocol = eth_type_trans(skb, dev); - skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); - } - - return ret; -} -EXPORT_SYMBOL_GPL(__dev_forward_skb); - -/** - * dev_forward_skb - loopback an skb to another netif - * - * @dev: destination network device - * @skb: buffer to forward - * - * return values: - * NET_RX_SUCCESS (no congestion) - * NET_RX_DROP (packet was dropped, but freed) - * - * dev_forward_skb can be used for injecting an skb from the - * start_xmit function of one device into the receive queue - * of another device. - * - * The receiving device may be in another namespace, so - * we have to clear all information in the skb that could - * impact namespace isolation. - */ -int dev_forward_skb(struct net_device *dev, struct sk_buff *skb) -{ - return __dev_forward_skb(dev, skb) ?: netif_rx_internal(skb); -} -EXPORT_SYMBOL_GPL(dev_forward_skb); - -static inline int deliver_skb(struct sk_buff *skb, - struct packet_type *pt_prev, - struct net_device *orig_dev) -{ - if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC))) - return -ENOMEM; - atomic_inc(&skb->users); - return pt_prev->func(skb, skb->dev, pt_prev, orig_dev); -} - -static inline void deliver_ptype_list_skb(struct sk_buff *skb, - struct packet_type **pt, - struct net_device *orig_dev, - __be16 type, - struct list_head *ptype_list) -{ - struct packet_type *ptype, *pt_prev = *pt; - - list_for_each_entry_rcu(ptype, ptype_list, list) { - if (ptype->type != type) - continue; - if (pt_prev) - deliver_skb(skb, pt_prev, orig_dev); - pt_prev = ptype; - } - *pt = pt_prev; -} - -static inline bool skb_loop_sk(struct packet_type *ptype, struct sk_buff *skb) -{ - if (!ptype->af_packet_priv || !skb->sk) - return false; - - if (ptype->id_match) - return ptype->id_match(ptype, skb->sk); - else if ((struct sock *)ptype->af_packet_priv == skb->sk) - return true; - - return false; -} - -/* - * Support routine. Sends outgoing frames to any network - * taps currently in use. - */ - -void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev) -{ - struct packet_type *ptype; - struct sk_buff *skb2 = NULL; - struct packet_type *pt_prev = NULL; - struct list_head *ptype_list = &ptype_all; - - rcu_read_lock(); -again: - list_for_each_entry_rcu(ptype, ptype_list, list) { - /* Never send packets back to the socket - * they originated from - MvS (miquels@drinkel.ow.org) - */ - if (skb_loop_sk(ptype, skb)) - continue; - - if (pt_prev) { - deliver_skb(skb2, pt_prev, skb->dev); - pt_prev = ptype; - continue; - } - - /* need to clone skb, done only once */ - skb2 = skb_clone(skb, GFP_ATOMIC); - if (!skb2) - goto out_unlock; - - net_timestamp_set(skb2); - - /* skb->nh should be correctly - * set by sender, so that the second statement is - * just protection against buggy protocols. - */ - skb_reset_mac_header(skb2); - - if (skb_network_header(skb2) < skb2->data || - skb_network_header(skb2) > skb_tail_pointer(skb2)) { - net_crit_ratelimited("protocol %04x is buggy, dev %s\n", - ntohs(skb2->protocol), - dev->name); - skb_reset_network_header(skb2); - } - - skb2->transport_header = skb2->network_header; - skb2->pkt_type = PACKET_OUTGOING; - pt_prev = ptype; - } - - if (ptype_list == &ptype_all) { - ptype_list = &dev->ptype_all; - goto again; - } -out_unlock: - if (pt_prev) - pt_prev->func(skb2, skb->dev, pt_prev, skb->dev); - rcu_read_unlock(); -} -EXPORT_SYMBOL_GPL(dev_queue_xmit_nit); - -/** - * netif_setup_tc - Handle tc mappings on real_num_tx_queues change - * @dev: Network device - * @txq: number of queues available - * - * If real_num_tx_queues is changed the tc mappings may no longer be - * valid. To resolve this verify the tc mapping remains valid and if - * not NULL the mapping. With no priorities mapping to this - * offset/count pair it will no longer be used. In the worst case TC0 - * is invalid nothing can be done so disable priority mappings. If is - * expected that drivers will fix this mapping if they can before - * calling netif_set_real_num_tx_queues. - */ -static void netif_setup_tc(struct net_device *dev, unsigned int txq) -{ - int i; - struct netdev_tc_txq *tc = &dev->tc_to_txq[0]; - - /* If TC0 is invalidated disable TC mapping */ - if (tc->offset + tc->count > txq) { - pr_warn("Number of in use tx queues changed invalidating tc mappings. Priority traffic classification disabled!\n"); - dev->num_tc = 0; - return; - } - - /* Invalidated prio to tc mappings set to TC0 */ - for (i = 1; i < TC_BITMASK + 1; i++) { - int q = netdev_get_prio_tc_map(dev, i); - - tc = &dev->tc_to_txq[q]; - if (tc->offset + tc->count > txq) { - pr_warn("Number of in use tx queues changed. Priority %i to tc mapping %i is no longer valid. Setting map to 0\n", - i, q); - netdev_set_prio_tc_map(dev, i, 0); - } - } -} - -#ifdef CONFIG_XPS -static DEFINE_MUTEX(xps_map_mutex); -#define xmap_dereference(P) \ - rcu_dereference_protected((P), lockdep_is_held(&xps_map_mutex)) - -static struct xps_map *remove_xps_queue(struct xps_dev_maps *dev_maps, - int cpu, u16 index) -{ - struct xps_map *map = NULL; - int pos; - - if (dev_maps) - map = xmap_dereference(dev_maps->cpu_map[cpu]); - - for (pos = 0; map && pos < map->len; pos++) { - if (map->queues[pos] == index) { - if (map->len > 1) { - map->queues[pos] = map->queues[--map->len]; - } else { - RCU_INIT_POINTER(dev_maps->cpu_map[cpu], NULL); - kfree_rcu(map, rcu); - map = NULL; - } - break; - } - } - - return map; -} - -static void netif_reset_xps_queues_gt(struct net_device *dev, u16 index) -{ - struct xps_dev_maps *dev_maps; - int cpu, i; - bool active = false; - - mutex_lock(&xps_map_mutex); - dev_maps = xmap_dereference(dev->xps_maps); - - if (!dev_maps) - goto out_no_maps; - - for_each_possible_cpu(cpu) { - for (i = index; i < dev->num_tx_queues; i++) { - if (!remove_xps_queue(dev_maps, cpu, i)) - break; - } - if (i == dev->num_tx_queues) - active = true; - } - - if (!active) { - RCU_INIT_POINTER(dev->xps_maps, NULL); - kfree_rcu(dev_maps, rcu); - } - - for (i = index; i < dev->num_tx_queues; i++) - netdev_queue_numa_node_write(netdev_get_tx_queue(dev, i), - NUMA_NO_NODE); - -out_no_maps: - mutex_unlock(&xps_map_mutex); -} - -static struct xps_map *expand_xps_map(struct xps_map *map, - int cpu, u16 index) -{ - struct xps_map *new_map; - int alloc_len = XPS_MIN_MAP_ALLOC; - int i, pos; - - for (pos = 0; map && pos < map->len; pos++) { - if (map->queues[pos] != index) - continue; - return map; - } - - /* Need to add queue to this CPU's existing map */ - if (map) { - if (pos < map->alloc_len) - return map; - - alloc_len = map->alloc_len * 2; - } - - /* Need to allocate new map to store queue on this CPU's map */ - new_map = kzalloc_node(XPS_MAP_SIZE(alloc_len), GFP_KERNEL, - cpu_to_node(cpu)); - if (!new_map) - return NULL; - - for (i = 0; i < pos; i++) - new_map->queues[i] = map->queues[i]; - new_map->alloc_len = alloc_len; - new_map->len = pos; - - return new_map; -} - -int netif_set_xps_queue(struct net_device *dev, const struct cpumask *mask, - u16 index) -{ - struct xps_dev_maps *dev_maps, *new_dev_maps = NULL; - struct xps_map *map, *new_map; - int maps_sz = max_t(unsigned int, XPS_DEV_MAPS_SIZE, L1_CACHE_BYTES); - int cpu, numa_node_id = -2; - bool active = false; - - mutex_lock(&xps_map_mutex); - - dev_maps = xmap_dereference(dev->xps_maps); - - /* allocate memory for queue storage */ - for_each_online_cpu(cpu) { - if (!cpumask_test_cpu(cpu, mask)) - continue; - - if (!new_dev_maps) - new_dev_maps = kzalloc(maps_sz, GFP_KERNEL); - if (!new_dev_maps) { - mutex_unlock(&xps_map_mutex); - return -ENOMEM; - } - - map = dev_maps ? xmap_dereference(dev_maps->cpu_map[cpu]) : - NULL; - - map = expand_xps_map(map, cpu, index); - if (!map) - goto error; - - RCU_INIT_POINTER(new_dev_maps->cpu_map[cpu], map); - } - - if (!new_dev_maps) - goto out_no_new_maps; - - for_each_possible_cpu(cpu) { - if (cpumask_test_cpu(cpu, mask) && cpu_online(cpu)) { - /* add queue to CPU maps */ - int pos = 0; - - map = xmap_dereference(new_dev_maps->cpu_map[cpu]); - while ((pos < map->len) && (map->queues[pos] != index)) - pos++; - - if (pos == map->len) - map->queues[map->len++] = index; -#ifdef CONFIG_NUMA - if (numa_node_id == -2) - numa_node_id = cpu_to_node(cpu); - else if (numa_node_id != cpu_to_node(cpu)) - numa_node_id = -1; -#endif - } else if (dev_maps) { - /* fill in the new device map from the old device map */ - map = xmap_dereference(dev_maps->cpu_map[cpu]); - RCU_INIT_POINTER(new_dev_maps->cpu_map[cpu], map); - } - - } - - rcu_assign_pointer(dev->xps_maps, new_dev_maps); - - /* Cleanup old maps */ - if (dev_maps) { - for_each_possible_cpu(cpu) { - new_map = xmap_dereference(new_dev_maps->cpu_map[cpu]); - map = xmap_dereference(dev_maps->cpu_map[cpu]); - if (map && map != new_map) - kfree_rcu(map, rcu); - } - - kfree_rcu(dev_maps, rcu); - } - - dev_maps = new_dev_maps; - active = true; - -out_no_new_maps: - /* update Tx queue numa node */ - netdev_queue_numa_node_write(netdev_get_tx_queue(dev, index), - (numa_node_id >= 0) ? numa_node_id : - NUMA_NO_NODE); - - if (!dev_maps) - goto out_no_maps; - - /* removes queue from unused CPUs */ - for_each_possible_cpu(cpu) { - if (cpumask_test_cpu(cpu, mask) && cpu_online(cpu)) - continue; - - if (remove_xps_queue(dev_maps, cpu, index)) - active = true; - } - - /* free map if not active */ - if (!active) { - RCU_INIT_POINTER(dev->xps_maps, NULL); - kfree_rcu(dev_maps, rcu); - } - -out_no_maps: - mutex_unlock(&xps_map_mutex); - - return 0; -error: - /* remove any maps that we added */ - for_each_possible_cpu(cpu) { - new_map = xmap_dereference(new_dev_maps->cpu_map[cpu]); - map = dev_maps ? xmap_dereference(dev_maps->cpu_map[cpu]) : - NULL; - if (new_map && new_map != map) - kfree(new_map); - } - - mutex_unlock(&xps_map_mutex); - - kfree(new_dev_maps); - return -ENOMEM; -} -EXPORT_SYMBOL(netif_set_xps_queue); - -#endif -/* - * Routine to help set real_num_tx_queues. To avoid skbs mapped to queues - * greater then real_num_tx_queues stale skbs on the qdisc must be flushed. - */ -int netif_set_real_num_tx_queues(struct net_device *dev, unsigned int txq) -{ - int rc; - - if (txq < 1 || txq > dev->num_tx_queues) - return -EINVAL; - - if (dev->reg_state == NETREG_REGISTERED || - dev->reg_state == NETREG_UNREGISTERING) { - ASSERT_RTNL(); - - rc = netdev_queue_update_kobjects(dev, dev->real_num_tx_queues, - txq); - if (rc) - return rc; - - if (dev->num_tc) - netif_setup_tc(dev, txq); - - if (txq < dev->real_num_tx_queues) { - qdisc_reset_all_tx_gt(dev, txq); -#ifdef CONFIG_XPS - netif_reset_xps_queues_gt(dev, txq); -#endif - } - } - - dev->real_num_tx_queues = txq; - return 0; -} -EXPORT_SYMBOL(netif_set_real_num_tx_queues); - -#ifdef CONFIG_SYSFS -/** - * netif_set_real_num_rx_queues - set actual number of RX queues used - * @dev: Network device - * @rxq: Actual number of RX queues - * - * This must be called either with the rtnl_lock held or before - * registration of the net device. Returns 0 on success, or a - * negative error code. If called before registration, it always - * succeeds. - */ -int netif_set_real_num_rx_queues(struct net_device *dev, unsigned int rxq) -{ - int rc; - - if (rxq < 1 || rxq > dev->num_rx_queues) - return -EINVAL; - - if (dev->reg_state == NETREG_REGISTERED) { - ASSERT_RTNL(); - - rc = net_rx_queue_update_kobjects(dev, dev->real_num_rx_queues, - rxq); - if (rc) - return rc; - } - - dev->real_num_rx_queues = rxq; - return 0; -} -EXPORT_SYMBOL(netif_set_real_num_rx_queues); -#endif - -/** - * netif_get_num_default_rss_queues - default number of RSS queues - * - * This routine should set an upper limit on the number of RSS queues - * used by default by multiqueue devices. - */ -int netif_get_num_default_rss_queues(void) -{ - return is_kdump_kernel() ? - 1 : min_t(int, DEFAULT_MAX_NUM_RSS_QUEUES, num_online_cpus()); -} -EXPORT_SYMBOL(netif_get_num_default_rss_queues); - -static void __netif_reschedule(struct Qdisc *q) -{ - struct softnet_data *sd; - unsigned long flags; - - local_irq_save(flags); - sd = this_cpu_ptr(&softnet_data); - q->next_sched = NULL; - *sd->output_queue_tailp = q; - sd->output_queue_tailp = &q->next_sched; - raise_softirq_irqoff(NET_TX_SOFTIRQ); - local_irq_restore(flags); -} - -void __netif_schedule(struct Qdisc *q) -{ - if (!test_and_set_bit(__QDISC_STATE_SCHED, &q->state)) - __netif_reschedule(q); -} -EXPORT_SYMBOL(__netif_schedule); - -struct dev_kfree_skb_cb { - enum skb_free_reason reason; -}; - -static struct dev_kfree_skb_cb *get_kfree_skb_cb(const struct sk_buff *skb) -{ - return (struct dev_kfree_skb_cb *)skb->cb; -} - -void netif_schedule_queue(struct netdev_queue *txq) -{ - rcu_read_lock(); - if (!(txq->state & QUEUE_STATE_ANY_XOFF)) { - struct Qdisc *q = rcu_dereference(txq->qdisc); - - __netif_schedule(q); - } - rcu_read_unlock(); -} -EXPORT_SYMBOL(netif_schedule_queue); - -/** - * netif_wake_subqueue - allow sending packets on subqueue - * @dev: network device - * @queue_index: sub queue index - * - * Resume individual transmit queue of a device with multiple transmit queues. - */ -void netif_wake_subqueue(struct net_device *dev, u16 queue_index) -{ - struct netdev_queue *txq = netdev_get_tx_queue(dev, queue_index); - - if (test_and_clear_bit(__QUEUE_STATE_DRV_XOFF, &txq->state)) { - struct Qdisc *q; - - rcu_read_lock(); - q = rcu_dereference(txq->qdisc); - __netif_schedule(q); - rcu_read_unlock(); - } -} -EXPORT_SYMBOL(netif_wake_subqueue); - -void netif_tx_wake_queue(struct netdev_queue *dev_queue) -{ - if (test_and_clear_bit(__QUEUE_STATE_DRV_XOFF, &dev_queue->state)) { - struct Qdisc *q; - - rcu_read_lock(); - q = rcu_dereference(dev_queue->qdisc); - __netif_schedule(q); - rcu_read_unlock(); - } -} -EXPORT_SYMBOL(netif_tx_wake_queue); - -void __dev_kfree_skb_irq(struct sk_buff *skb, enum skb_free_reason reason) -{ - unsigned long flags; - - if (likely(atomic_read(&skb->users) == 1)) { - smp_rmb(); - atomic_set(&skb->users, 0); - } else if (likely(!atomic_dec_and_test(&skb->users))) { - return; - } - get_kfree_skb_cb(skb)->reason = reason; - local_irq_save(flags); - skb->next = __this_cpu_read(softnet_data.completion_queue); - __this_cpu_write(softnet_data.completion_queue, skb); - raise_softirq_irqoff(NET_TX_SOFTIRQ); - local_irq_restore(flags); -} -EXPORT_SYMBOL(__dev_kfree_skb_irq); - -void __dev_kfree_skb_any(struct sk_buff *skb, enum skb_free_reason reason) -{ - if (in_irq() || irqs_disabled()) - __dev_kfree_skb_irq(skb, reason); - else - dev_kfree_skb(skb); -} -EXPORT_SYMBOL(__dev_kfree_skb_any); - - -/** - * netif_device_detach - mark device as removed - * @dev: network device - * - * Mark device as removed from system and therefore no longer available. - */ -void netif_device_detach(struct net_device *dev) -{ - if (test_and_clear_bit(__LINK_STATE_PRESENT, &dev->state) && - netif_running(dev)) { - netif_tx_stop_all_queues(dev); - } -} -EXPORT_SYMBOL(netif_device_detach); - -/** - * netif_device_attach - mark device as attached - * @dev: network device - * - * Mark device as attached from system and restart if needed. - */ -void netif_device_attach(struct net_device *dev) -{ - if (!test_and_set_bit(__LINK_STATE_PRESENT, &dev->state) && - netif_running(dev)) { - netif_tx_wake_all_queues(dev); - __netdev_watchdog_up(dev); - } -} -EXPORT_SYMBOL(netif_device_attach); - -/* - * Returns a Tx hash based on the given packet descriptor a Tx queues' number - * to be used as a distribution range. - */ -u16 __skb_tx_hash(const struct net_device *dev, struct sk_buff *skb, - unsigned int num_tx_queues) -{ - u32 hash; - u16 qoffset = 0; - u16 qcount = num_tx_queues; - - if (skb_rx_queue_recorded(skb)) { - hash = skb_get_rx_queue(skb); - while (unlikely(hash >= num_tx_queues)) - hash -= num_tx_queues; - return hash; - } - - if (dev->num_tc) { - u8 tc = netdev_get_prio_tc_map(dev, skb->priority); - qoffset = dev->tc_to_txq[tc].offset; - qcount = dev->tc_to_txq[tc].count; - } - - return (u16) reciprocal_scale(skb_get_hash(skb), qcount) + qoffset; -} -EXPORT_SYMBOL(__skb_tx_hash); - -static void skb_warn_bad_offload(const struct sk_buff *skb) -{ - static const netdev_features_t null_features; - struct net_device *dev = skb->dev; - const char *name = ""; - - if (!net_ratelimit()) - return; - - if (dev) { - if (dev->dev.parent) - name = dev_driver_string(dev->dev.parent); - else - name = netdev_name(dev); - } - WARN(1, "%s: caps=(%pNF, %pNF) len=%d data_len=%d gso_size=%d " - "gso_type=%d ip_summed=%d\n", - name, dev ? &dev->features : &null_features, - skb->sk ? &skb->sk->sk_route_caps : &null_features, - skb->len, skb->data_len, skb_shinfo(skb)->gso_size, - skb_shinfo(skb)->gso_type, skb->ip_summed); -} - -/* - * Invalidate hardware checksum when packet is to be mangled, and - * complete checksum manually on outgoing path. - */ -int skb_checksum_help(struct sk_buff *skb) -{ - __wsum csum; - int ret = 0, offset; - - if (skb->ip_summed == CHECKSUM_COMPLETE) - goto out_set_summed; - - if (unlikely(skb_shinfo(skb)->gso_size)) { - skb_warn_bad_offload(skb); - return -EINVAL; - } - - /* Before computing a checksum, we should make sure no frag could - * be modified by an external entity : checksum could be wrong. - */ - if (skb_has_shared_frag(skb)) { - ret = __skb_linearize(skb); - if (ret) - goto out; - } - - offset = skb_checksum_start_offset(skb); - BUG_ON(offset >= skb_headlen(skb)); - csum = skb_checksum(skb, offset, skb->len - offset, 0); - - offset += skb->csum_offset; - BUG_ON(offset + sizeof(__sum16) > skb_headlen(skb)); - - if (skb_cloned(skb) && - !skb_clone_writable(skb, offset + sizeof(__sum16))) { - ret = pskb_expand_head(skb, 0, 0, GFP_ATOMIC); - if (ret) - goto out; - } - - *(__sum16 *)(skb->data + offset) = csum_fold(csum) ?: CSUM_MANGLED_0; -out_set_summed: - skb->ip_summed = CHECKSUM_NONE; -out: - return ret; -} -EXPORT_SYMBOL(skb_checksum_help); - -/* skb_csum_offload_check - Driver helper function to determine if a device - * with limited checksum offload capabilities is able to offload the checksum - * for a given packet. - * - * Arguments: - * skb - sk_buff for the packet in question - * spec - contains the description of what device can offload - * csum_encapped - returns true if the checksum being offloaded is - * encpasulated. That is it is checksum for the transport header - * in the inner headers. - * checksum_help - when set indicates that helper function should - * call skb_checksum_help if offload checks fail - * - * Returns: - * true: Packet has passed the checksum checks and should be offloadable to - * the device (a driver may still need to check for additional - * restrictions of its device) - * false: Checksum is not offloadable. If checksum_help was set then - * skb_checksum_help was called to resolve checksum for non-GSO - * packets and when IP protocol is not SCTP - */ -bool __skb_csum_offload_chk(struct sk_buff *skb, - const struct skb_csum_offl_spec *spec, - bool *csum_encapped, - bool csum_help) -{ - struct iphdr *iph; - struct ipv6hdr *ipv6; - void *nhdr; - int protocol; - u8 ip_proto; - - if (skb->protocol == htons(ETH_P_8021Q) || - skb->protocol == htons(ETH_P_8021AD)) { - if (!spec->vlan_okay) - goto need_help; - } - - /* We check whether the checksum refers to a transport layer checksum in - * the outermost header or an encapsulated transport layer checksum that - * corresponds to the inner headers of the skb. If the checksum is for - * something else in the packet we need help. - */ - if (skb_checksum_start_offset(skb) == skb_transport_offset(skb)) { - /* Non-encapsulated checksum */ - protocol = eproto_to_ipproto(vlan_get_protocol(skb)); - nhdr = skb_network_header(skb); - *csum_encapped = false; - if (spec->no_not_encapped) - goto need_help; - } else if (skb->encapsulation && spec->encap_okay && - skb_checksum_start_offset(skb) == - skb_inner_transport_offset(skb)) { - /* Encapsulated checksum */ - *csum_encapped = true; - switch (skb->inner_protocol_type) { - case ENCAP_TYPE_ETHER: - protocol = eproto_to_ipproto(skb->inner_protocol); - break; - case ENCAP_TYPE_IPPROTO: - protocol = skb->inner_protocol; - break; - } - nhdr = skb_inner_network_header(skb); - } else { - goto need_help; - } - - switch (protocol) { - case IPPROTO_IP: - if (!spec->ipv4_okay) - goto need_help; - iph = nhdr; - ip_proto = iph->protocol; - if (iph->ihl != 5 && !spec->ip_options_okay) - goto need_help; - break; - case IPPROTO_IPV6: - if (!spec->ipv6_okay) - goto need_help; - if (spec->no_encapped_ipv6 && *csum_encapped) - goto need_help; - ipv6 = nhdr; - nhdr += sizeof(*ipv6); - ip_proto = ipv6->nexthdr; - break; - default: - goto need_help; - } - -ip_proto_again: - switch (ip_proto) { - case IPPROTO_TCP: - if (!spec->tcp_okay || - skb->csum_offset != offsetof(struct tcphdr, check)) - goto need_help; - break; - case IPPROTO_UDP: - if (!spec->udp_okay || - skb->csum_offset != offsetof(struct udphdr, check)) - goto need_help; - break; - case IPPROTO_SCTP: - if (!spec->sctp_okay || - skb->csum_offset != offsetof(struct sctphdr, checksum)) - goto cant_help; - break; - case NEXTHDR_HOP: - case NEXTHDR_ROUTING: - case NEXTHDR_DEST: { - u8 *opthdr = nhdr; - - if (protocol != IPPROTO_IPV6 || !spec->ext_hdrs_okay) - goto need_help; - - ip_proto = opthdr[0]; - nhdr += (opthdr[1] + 1) << 3; - - goto ip_proto_again; - } - default: - goto need_help; - } - - /* Passed the tests for offloading checksum */ - return true; - -need_help: - if (csum_help && !skb_shinfo(skb)->gso_size) - skb_checksum_help(skb); -cant_help: - return false; -} -EXPORT_SYMBOL(__skb_csum_offload_chk); - -__be16 skb_network_protocol(struct sk_buff *skb, int *depth) -{ - __be16 type = skb->protocol; - - /* Tunnel gso handlers can set protocol to ethernet. */ - if (type == htons(ETH_P_TEB)) { - struct ethhdr *eth; - - if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr)))) - return 0; - - eth = (struct ethhdr *)skb_mac_header(skb); - type = eth->h_proto; - } - - return __vlan_get_protocol(skb, type, depth); -} - -/** - * skb_mac_gso_segment - mac layer segmentation handler. - * @skb: buffer to segment - * @features: features for the output path (see dev->features) - */ -struct sk_buff *skb_mac_gso_segment(struct sk_buff *skb, - netdev_features_t features) -{ - struct sk_buff *segs = ERR_PTR(-EPROTONOSUPPORT); - struct packet_offload *ptype; - int vlan_depth = skb->mac_len; - __be16 type = skb_network_protocol(skb, &vlan_depth); - - if (unlikely(!type)) - return ERR_PTR(-EINVAL); - - __skb_pull(skb, vlan_depth); - - rcu_read_lock(); - list_for_each_entry_rcu(ptype, &offload_base, list) { - if (ptype->type == type && ptype->callbacks.gso_segment) { - segs = ptype->callbacks.gso_segment(skb, features); - break; - } - } - rcu_read_unlock(); - - __skb_push(skb, skb->data - skb_mac_header(skb)); - - return segs; -} -EXPORT_SYMBOL(skb_mac_gso_segment); - - -/* openvswitch calls this on rx path, so we need a different check. - */ -static inline bool skb_needs_check(struct sk_buff *skb, bool tx_path) -{ - if (tx_path) - return skb->ip_summed != CHECKSUM_PARTIAL; - else - return skb->ip_summed == CHECKSUM_NONE; -} - -/** - * __skb_gso_segment - Perform segmentation on skb. - * @skb: buffer to segment - * @features: features for the output path (see dev->features) - * @tx_path: whether it is called in TX path - * - * This function segments the given skb and returns a list of segments. - * - * It may return NULL if the skb requires no segmentation. This is - * only possible when GSO is used for verifying header integrity. - * - * Segmentation preserves SKB_SGO_CB_OFFSET bytes of previous skb cb. - */ -struct sk_buff *__skb_gso_segment(struct sk_buff *skb, - netdev_features_t features, bool tx_path) -{ - if (unlikely(skb_needs_check(skb, tx_path))) { - int err; - - skb_warn_bad_offload(skb); - - err = skb_cow_head(skb, 0); - if (err < 0) - return ERR_PTR(err); - } - - /* Only report GSO partial support if it will enable us to - * support segmentation on this frame without needing additional - * work. - */ - if (features & NETIF_F_GSO_PARTIAL) { - netdev_features_t partial_features = NETIF_F_GSO_ROBUST; - struct net_device *dev = skb->dev; - - partial_features |= dev->features & dev->gso_partial_features; - if (!skb_gso_ok(skb, features | partial_features)) - features &= ~NETIF_F_GSO_PARTIAL; - } - - BUILD_BUG_ON(SKB_SGO_CB_OFFSET + - sizeof(*SKB_GSO_CB(skb)) > sizeof(skb->cb)); - - SKB_GSO_CB(skb)->mac_offset = skb_headroom(skb); - SKB_GSO_CB(skb)->encap_level = 0; - - skb_reset_mac_header(skb); - skb_reset_mac_len(skb); - - return skb_mac_gso_segment(skb, features); -} -EXPORT_SYMBOL(__skb_gso_segment); - -/* Take action when hardware reception checksum errors are detected. */ -#ifdef CONFIG_BUG -void netdev_rx_csum_fault(struct net_device *dev) -{ - if (net_ratelimit()) { - pr_err("%s: hw csum failure\n", dev ? dev->name : ""); - dump_stack(); - } -} -EXPORT_SYMBOL(netdev_rx_csum_fault); -#endif - -/* Actually, we should eliminate this check as soon as we know, that: - * 1. IOMMU is present and allows to map all the memory. - * 2. No high memory really exists on this machine. - */ - -static int illegal_highdma(struct net_device *dev, struct sk_buff *skb) -{ -#ifdef CONFIG_HIGHMEM - int i; - if (!(dev->features & NETIF_F_HIGHDMA)) { - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - if (PageHighMem(skb_frag_page(frag))) - return 1; - } - } - - if (PCI_DMA_BUS_IS_PHYS) { - struct device *pdev = dev->dev.parent; - - if (!pdev) - return 0; - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - dma_addr_t addr = page_to_phys(skb_frag_page(frag)); - if (!pdev->dma_mask || addr + PAGE_SIZE - 1 > *pdev->dma_mask) - return 1; - } - } -#endif - return 0; -} - -/* If MPLS offload request, verify we are testing hardware MPLS features - * instead of standard features for the netdev. - */ -#if IS_ENABLED(CONFIG_NET_MPLS_GSO) -static netdev_features_t net_mpls_features(struct sk_buff *skb, - netdev_features_t features, - __be16 type) -{ - if (eth_p_mpls(type)) - features &= skb->dev->mpls_features; - - return features; -} -#else -static netdev_features_t net_mpls_features(struct sk_buff *skb, - netdev_features_t features, - __be16 type) -{ - return features; -} -#endif - -static netdev_features_t harmonize_features(struct sk_buff *skb, - netdev_features_t features) -{ - int tmp; - __be16 type; - - type = skb_network_protocol(skb, &tmp); - features = net_mpls_features(skb, features, type); - - if (skb->ip_summed != CHECKSUM_NONE && - !can_checksum_protocol(features, type)) { - features &= ~(NETIF_F_CSUM_MASK | NETIF_F_GSO_MASK); - } else if (illegal_highdma(skb->dev, skb)) { - features &= ~NETIF_F_SG; - } - - return features; -} - -netdev_features_t passthru_features_check(struct sk_buff *skb, - struct net_device *dev, - netdev_features_t features) -{ - return features; -} -EXPORT_SYMBOL(passthru_features_check); - -static netdev_features_t dflt_features_check(const struct sk_buff *skb, - struct net_device *dev, - netdev_features_t features) -{ - return vlan_features_check(skb, features); -} - -static netdev_features_t gso_features_check(const struct sk_buff *skb, - struct net_device *dev, - netdev_features_t features) -{ - u16 gso_segs = skb_shinfo(skb)->gso_segs; - - if (gso_segs > dev->gso_max_segs) - return features & ~NETIF_F_GSO_MASK; - - /* Support for GSO partial features requires software - * intervention before we can actually process the packets - * so we need to strip support for any partial features now - * and we can pull them back in after we have partially - * segmented the frame. - */ - if (!(skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL)) - features &= ~dev->gso_partial_features; - - /* Make sure to clear the IPv4 ID mangling feature if the - * IPv4 header has the potential to be fragmented. - */ - if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) { - struct iphdr *iph = skb->encapsulation ? - inner_ip_hdr(skb) : ip_hdr(skb); - - if (!(iph->frag_off & htons(IP_DF))) - features &= ~NETIF_F_TSO_MANGLEID; - } - - return features; -} - -netdev_features_t netif_skb_features(struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - netdev_features_t features = dev->features; - - if (skb_is_gso(skb)) - features = gso_features_check(skb, dev, features); - - /* If encapsulation offload request, verify we are testing - * hardware encapsulation features instead of standard - * features for the netdev - */ - if (skb->encapsulation) - features &= dev->hw_enc_features; - - if (skb_vlan_tagged(skb)) - features = netdev_intersect_features(features, - dev->vlan_features | - NETIF_F_HW_VLAN_CTAG_TX | - NETIF_F_HW_VLAN_STAG_TX); - - if (dev->netdev_ops->ndo_features_check) - features &= dev->netdev_ops->ndo_features_check(skb, dev, - features); - else - features &= dflt_features_check(skb, dev, features); - - return harmonize_features(skb, features); -} -EXPORT_SYMBOL(netif_skb_features); - -static int xmit_one(struct sk_buff *skb, struct net_device *dev, - struct netdev_queue *txq, bool more) -{ - unsigned int len; - int rc; - - if (!list_empty(&ptype_all) || !list_empty(&dev->ptype_all)) - dev_queue_xmit_nit(skb, dev); - - len = skb->len; - trace_net_dev_start_xmit(skb, dev); - rc = netdev_start_xmit(skb, dev, txq, more); - trace_net_dev_xmit(skb, rc, dev, len); - - return rc; -} - -struct sk_buff *dev_hard_start_xmit(struct sk_buff *first, struct net_device *dev, - struct netdev_queue *txq, int *ret) -{ - struct sk_buff *skb = first; - int rc = NETDEV_TX_OK; - - while (skb) { - struct sk_buff *next = skb->next; - - skb->next = NULL; - rc = xmit_one(skb, dev, txq, next != NULL); - if (unlikely(!dev_xmit_complete(rc))) { - skb->next = next; - goto out; - } - - skb = next; - if (netif_xmit_stopped(txq) && skb) { - rc = NETDEV_TX_BUSY; - break; - } - } - -out: - *ret = rc; - return skb; -} - -static struct sk_buff *validate_xmit_vlan(struct sk_buff *skb, - netdev_features_t features) -{ - if (skb_vlan_tag_present(skb) && - !vlan_hw_offload_capable(features, skb->vlan_proto)) - skb = __vlan_hwaccel_push_inside(skb); - return skb; -} - -static struct sk_buff *validate_xmit_skb(struct sk_buff *skb, struct net_device *dev) -{ - netdev_features_t features; - - features = netif_skb_features(skb); - skb = validate_xmit_vlan(skb, features); - if (unlikely(!skb)) - goto out_null; - - if (netif_needs_gso(skb, features)) { - struct sk_buff *segs; - - segs = skb_gso_segment(skb, features); - if (IS_ERR(segs)) { - goto out_kfree_skb; - } else if (segs) { - consume_skb(skb); - skb = segs; - } - } else { - if (skb_needs_linearize(skb, features) && - __skb_linearize(skb)) - goto out_kfree_skb; - - /* If packet is not checksummed and device does not - * support checksumming for this protocol, complete - * checksumming here. - */ - if (skb->ip_summed == CHECKSUM_PARTIAL) { - if (skb->encapsulation) - skb_set_inner_transport_header(skb, - skb_checksum_start_offset(skb)); - else - skb_set_transport_header(skb, - skb_checksum_start_offset(skb)); - if (!(features & NETIF_F_CSUM_MASK) && - skb_checksum_help(skb)) - goto out_kfree_skb; - } - } - - return skb; - -out_kfree_skb: - kfree_skb(skb); -out_null: - atomic_long_inc(&dev->tx_dropped); - return NULL; -} - -struct sk_buff *validate_xmit_skb_list(struct sk_buff *skb, struct net_device *dev) -{ - struct sk_buff *next, *head = NULL, *tail; - - for (; skb != NULL; skb = next) { - next = skb->next; - skb->next = NULL; - - /* in case skb wont be segmented, point to itself */ - skb->prev = skb; - - skb = validate_xmit_skb(skb, dev); - if (!skb) - continue; - - if (!head) - head = skb; - else - tail->next = skb; - /* If skb was segmented, skb->prev points to - * the last segment. If not, it still contains skb. - */ - tail = skb->prev; - } - return head; -} -EXPORT_SYMBOL_GPL(validate_xmit_skb_list); - -static void qdisc_pkt_len_init(struct sk_buff *skb) -{ - const struct skb_shared_info *shinfo = skb_shinfo(skb); - - qdisc_skb_cb(skb)->pkt_len = skb->len; - - /* To get more precise estimation of bytes sent on wire, - * we add to pkt_len the headers size of all segments - */ - if (shinfo->gso_size) { - unsigned int hdr_len; - u16 gso_segs = shinfo->gso_segs; - - /* mac layer + network layer */ - hdr_len = skb_transport_header(skb) - skb_mac_header(skb); - - /* + transport layer */ - if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) - hdr_len += tcp_hdrlen(skb); - else - hdr_len += sizeof(struct udphdr); - - if (shinfo->gso_type & SKB_GSO_DODGY) - gso_segs = DIV_ROUND_UP(skb->len - hdr_len, - shinfo->gso_size); - - qdisc_skb_cb(skb)->pkt_len += (gso_segs - 1) * hdr_len; - } -} - -static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q, - struct net_device *dev, - struct netdev_queue *txq) -{ - spinlock_t *root_lock = qdisc_lock(q); - struct sk_buff *to_free = NULL; - bool contended; - int rc; - - qdisc_calculate_pkt_len(skb, q); - /* - * Heuristic to force contended enqueues to serialize on a - * separate lock before trying to get qdisc main lock. - * This permits qdisc->running owner to get the lock more - * often and dequeue packets faster. - */ - contended = qdisc_is_running(q); - if (unlikely(contended)) - spin_lock(&q->busylock); - - spin_lock(root_lock); - if (unlikely(test_bit(__QDISC_STATE_DEACTIVATED, &q->state))) { - __qdisc_drop(skb, &to_free); - rc = NET_XMIT_DROP; - } else if ((q->flags & TCQ_F_CAN_BYPASS) && !qdisc_qlen(q) && - qdisc_run_begin(q)) { - /* - * This is a work-conserving queue; there are no old skbs - * waiting to be sent out; and the qdisc is not running - - * xmit the skb directly. - */ - - qdisc_bstats_update(q, skb); - - if (sch_direct_xmit(skb, q, dev, txq, root_lock, true)) { - if (unlikely(contended)) { - spin_unlock(&q->busylock); - contended = false; - } - __qdisc_run(q); - } else - qdisc_run_end(q); - - rc = NET_XMIT_SUCCESS; - } else { - rc = q->enqueue(skb, q, &to_free) & NET_XMIT_MASK; - if (qdisc_run_begin(q)) { - if (unlikely(contended)) { - spin_unlock(&q->busylock); - contended = false; - } - __qdisc_run(q); - } - } - spin_unlock(root_lock); - if (unlikely(to_free)) - kfree_skb_list(to_free); - if (unlikely(contended)) - spin_unlock(&q->busylock); - return rc; -} - -#if IS_ENABLED(CONFIG_CGROUP_NET_PRIO) -static void skb_update_prio(struct sk_buff *skb) -{ - struct netprio_map *map = rcu_dereference_bh(skb->dev->priomap); - - if (!skb->priority && skb->sk && map) { - unsigned int prioidx = - sock_cgroup_prioidx(&skb->sk->sk_cgrp_data); - - if (prioidx < map->priomap_len) - skb->priority = map->priomap[prioidx]; - } -} -#else -#define skb_update_prio(skb) -#endif - -DEFINE_PER_CPU(int, xmit_recursion); -EXPORT_SYMBOL(xmit_recursion); - -/** - * dev_loopback_xmit - loop back @skb - * @net: network namespace this loopback is happening in - * @sk: sk needed to be a netfilter okfn - * @skb: buffer to transmit - */ -int dev_loopback_xmit(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - skb_reset_mac_header(skb); - __skb_pull(skb, skb_network_offset(skb)); - skb->pkt_type = PACKET_LOOPBACK; - skb->ip_summed = CHECKSUM_UNNECESSARY; - WARN_ON(!skb_dst(skb)); - skb_dst_force(skb); - netif_rx_ni(skb); - return 0; -} -EXPORT_SYMBOL(dev_loopback_xmit); - -#ifdef CONFIG_NET_EGRESS -static struct sk_buff * -sch_handle_egress(struct sk_buff *skb, int *ret, struct net_device *dev) -{ - struct tcf_proto *cl = rcu_dereference_bh(dev->egress_cl_list); - struct tcf_result cl_res; - - if (!cl) - return skb; - - /* skb->tc_verd and qdisc_skb_cb(skb)->pkt_len were already set - * earlier by the caller. - */ - qdisc_bstats_cpu_update(cl->q, skb); - - switch (tc_classify(skb, cl, &cl_res, false)) { - case TC_ACT_OK: - case TC_ACT_RECLASSIFY: - skb->tc_index = TC_H_MIN(cl_res.classid); - break; - case TC_ACT_SHOT: - qdisc_qstats_cpu_drop(cl->q); - *ret = NET_XMIT_DROP; - kfree_skb(skb); - return NULL; - case TC_ACT_STOLEN: - case TC_ACT_QUEUED: - *ret = NET_XMIT_SUCCESS; - consume_skb(skb); - return NULL; - case TC_ACT_REDIRECT: - /* No need to push/pop skb's mac_header here on egress! */ - skb_do_redirect(skb); - *ret = NET_XMIT_SUCCESS; - return NULL; - default: - break; - } - - return skb; -} -#endif /* CONFIG_NET_EGRESS */ - -static inline int get_xps_queue(struct net_device *dev, struct sk_buff *skb) -{ -#ifdef CONFIG_XPS - struct xps_dev_maps *dev_maps; - struct xps_map *map; - int queue_index = -1; - - rcu_read_lock(); - dev_maps = rcu_dereference(dev->xps_maps); - if (dev_maps) { - map = rcu_dereference( - dev_maps->cpu_map[skb->sender_cpu - 1]); - if (map) { - if (map->len == 1) - queue_index = map->queues[0]; - else - queue_index = map->queues[reciprocal_scale(skb_get_hash(skb), - map->len)]; - if (unlikely(queue_index >= dev->real_num_tx_queues)) - queue_index = -1; - } - } - rcu_read_unlock(); - - return queue_index; -#else - return -1; -#endif -} - -static u16 __netdev_pick_tx(struct net_device *dev, struct sk_buff *skb) -{ - struct sock *sk = skb->sk; - int queue_index = sk_tx_queue_get(sk); - - if (queue_index < 0 || skb->ooo_okay || - queue_index >= dev->real_num_tx_queues) { - int new_index = get_xps_queue(dev, skb); - if (new_index < 0) - new_index = skb_tx_hash(dev, skb); - - if (queue_index != new_index && sk && - sk_fullsock(sk) && - rcu_access_pointer(sk->sk_dst_cache)) - sk_tx_queue_set(sk, new_index); - - queue_index = new_index; - } - - return queue_index; -} - -struct netdev_queue *netdev_pick_tx(struct net_device *dev, - struct sk_buff *skb, - void *accel_priv) -{ - int queue_index = 0; - -#ifdef CONFIG_XPS - u32 sender_cpu = skb->sender_cpu - 1; - - if (sender_cpu >= (u32)NR_CPUS) - skb->sender_cpu = raw_smp_processor_id() + 1; -#endif - - if (dev->real_num_tx_queues != 1) { - const struct net_device_ops *ops = dev->netdev_ops; - if (ops->ndo_select_queue) - queue_index = ops->ndo_select_queue(dev, skb, accel_priv, - __netdev_pick_tx); - else - queue_index = __netdev_pick_tx(dev, skb); - - if (!accel_priv) - queue_index = netdev_cap_txqueue(dev, queue_index); - } - - skb_set_queue_mapping(skb, queue_index); - return netdev_get_tx_queue(dev, queue_index); -} - -/** - * __dev_queue_xmit - transmit a buffer - * @skb: buffer to transmit - * @accel_priv: private data used for L2 forwarding offload - * - * Queue a buffer for transmission to a network device. The caller must - * have set the device and priority and built the buffer before calling - * this function. The function can be called from an interrupt. - * - * A negative errno code is returned on a failure. A success does not - * guarantee the frame will be transmitted as it may be dropped due - * to congestion or traffic shaping. - * - * ----------------------------------------------------------------------------------- - * I notice this method can also return errors from the queue disciplines, - * including NET_XMIT_DROP, which is a positive value. So, errors can also - * be positive. - * - * Regardless of the return value, the skb is consumed, so it is currently - * difficult to retry a send to this method. (You can bump the ref count - * before sending to hold a reference for retry if you are careful.) - * - * When calling this method, interrupts MUST be enabled. This is because - * the BH enable code must have IRQs enabled so that it will not deadlock. - * --BLG - */ -static int __dev_queue_xmit(struct sk_buff *skb, void *accel_priv) -{ - struct net_device *dev = skb->dev; - struct netdev_queue *txq; - struct Qdisc *q; - int rc = -ENOMEM; - - skb_reset_mac_header(skb); - - if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_SCHED_TSTAMP)) - __skb_tstamp_tx(skb, NULL, skb->sk, SCM_TSTAMP_SCHED); - - /* Disable soft irqs for various locks below. Also - * stops preemption for RCU. - */ - rcu_read_lock_bh(); - - skb_update_prio(skb); - - qdisc_pkt_len_init(skb); -#ifdef CONFIG_NET_CLS_ACT - skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_EGRESS); -# ifdef CONFIG_NET_EGRESS - if (static_key_false(&egress_needed)) { - skb = sch_handle_egress(skb, &rc, dev); - if (!skb) - goto out; - } -# endif -#endif - /* If device/qdisc don't need skb->dst, release it right now while - * its hot in this cpu cache. - */ - if (dev->priv_flags & IFF_XMIT_DST_RELEASE) - skb_dst_drop(skb); - else - skb_dst_force(skb); - - txq = netdev_pick_tx(dev, skb, accel_priv); - q = rcu_dereference_bh(txq->qdisc); - - trace_net_dev_queue(skb); - if (q->enqueue) { - rc = __dev_xmit_skb(skb, q, dev, txq); - goto out; - } - - /* The device has no queue. Common case for software devices: - loopback, all the sorts of tunnels... - - Really, it is unlikely that netif_tx_lock protection is necessary - here. (f.e. loopback and IP tunnels are clean ignoring statistics - counters.) - However, it is possible, that they rely on protection - made by us here. - - Check this and shot the lock. It is not prone from deadlocks. - Either shot noqueue qdisc, it is even simpler 8) - */ - if (dev->flags & IFF_UP) { - int cpu = smp_processor_id(); /* ok because BHs are off */ - - if (txq->xmit_lock_owner != cpu) { - if (unlikely(__this_cpu_read(xmit_recursion) > - XMIT_RECURSION_LIMIT)) - goto recursion_alert; - - skb = validate_xmit_skb(skb, dev); - if (!skb) - goto out; - - HARD_TX_LOCK(dev, txq, cpu); - - if (!netif_xmit_stopped(txq)) { - __this_cpu_inc(xmit_recursion); - skb = dev_hard_start_xmit(skb, dev, txq, &rc); - __this_cpu_dec(xmit_recursion); - if (dev_xmit_complete(rc)) { - HARD_TX_UNLOCK(dev, txq); - goto out; - } - } - HARD_TX_UNLOCK(dev, txq); - net_crit_ratelimited("Virtual device %s asks to queue packet!\n", - dev->name); - } else { - /* Recursion is detected! It is possible, - * unfortunately - */ -recursion_alert: - net_crit_ratelimited("Dead loop on virtual device %s, fix it urgently!\n", - dev->name); - } - } - - rc = -ENETDOWN; - rcu_read_unlock_bh(); - - atomic_long_inc(&dev->tx_dropped); - kfree_skb_list(skb); - return rc; -out: - rcu_read_unlock_bh(); - return rc; -} - -int dev_queue_xmit(struct sk_buff *skb) -{ - return __dev_queue_xmit(skb, NULL); -} -EXPORT_SYMBOL(dev_queue_xmit); - -int dev_queue_xmit_accel(struct sk_buff *skb, void *accel_priv) -{ - return __dev_queue_xmit(skb, accel_priv); -} -EXPORT_SYMBOL(dev_queue_xmit_accel); - - -/*======================================================================= - Receiver routines - =======================================================================*/ - -int netdev_max_backlog __read_mostly = 1000; -EXPORT_SYMBOL(netdev_max_backlog); - -int netdev_tstamp_prequeue __read_mostly = 1; -int netdev_budget __read_mostly = 300; -int weight_p __read_mostly = 64; /* old backlog weight */ - -/* Called with irq disabled */ -static inline void ____napi_schedule(struct softnet_data *sd, - struct napi_struct *napi) -{ - list_add_tail(&napi->poll_list, &sd->poll_list); - __raise_softirq_irqoff(NET_RX_SOFTIRQ); -} - -#ifdef CONFIG_RPS - -/* One global table that all flow-based protocols share. */ -struct rps_sock_flow_table __rcu *rps_sock_flow_table __read_mostly; -EXPORT_SYMBOL(rps_sock_flow_table); -u32 rps_cpu_mask __read_mostly; -EXPORT_SYMBOL(rps_cpu_mask); - -struct static_key rps_needed __read_mostly; -EXPORT_SYMBOL(rps_needed); - -static struct rps_dev_flow * -set_rps_cpu(struct net_device *dev, struct sk_buff *skb, - struct rps_dev_flow *rflow, u16 next_cpu) -{ - if (next_cpu < nr_cpu_ids) { -#ifdef CONFIG_RFS_ACCEL - struct netdev_rx_queue *rxqueue; - struct rps_dev_flow_table *flow_table; - struct rps_dev_flow *old_rflow; - u32 flow_id; - u16 rxq_index; - int rc; - - /* Should we steer this flow to a different hardware queue? */ - if (!skb_rx_queue_recorded(skb) || !dev->rx_cpu_rmap || - !(dev->features & NETIF_F_NTUPLE)) - goto out; - rxq_index = cpu_rmap_lookup_index(dev->rx_cpu_rmap, next_cpu); - if (rxq_index == skb_get_rx_queue(skb)) - goto out; - - rxqueue = dev->_rx + rxq_index; - flow_table = rcu_dereference(rxqueue->rps_flow_table); - if (!flow_table) - goto out; - flow_id = skb_get_hash(skb) & flow_table->mask; - rc = dev->netdev_ops->ndo_rx_flow_steer(dev, skb, - rxq_index, flow_id); - if (rc < 0) - goto out; - old_rflow = rflow; - rflow = &flow_table->flows[flow_id]; - rflow->filter = rc; - if (old_rflow->filter == rflow->filter) - old_rflow->filter = RPS_NO_FILTER; - out: -#endif - rflow->last_qtail = - per_cpu(softnet_data, next_cpu).input_queue_head; - } - - rflow->cpu = next_cpu; - return rflow; -} - -/* - * get_rps_cpu is called from netif_receive_skb and returns the target - * CPU from the RPS map of the receiving queue for a given skb. - * rcu_read_lock must be held on entry. - */ -static int get_rps_cpu(struct net_device *dev, struct sk_buff *skb, - struct rps_dev_flow **rflowp) -{ - const struct rps_sock_flow_table *sock_flow_table; - struct netdev_rx_queue *rxqueue = dev->_rx; - struct rps_dev_flow_table *flow_table; - struct rps_map *map; - int cpu = -1; - u32 tcpu; - u32 hash; - - if (skb_rx_queue_recorded(skb)) { - u16 index = skb_get_rx_queue(skb); - - if (unlikely(index >= dev->real_num_rx_queues)) { - WARN_ONCE(dev->real_num_rx_queues > 1, - "%s received packet on queue %u, but number " - "of RX queues is %u\n", - dev->name, index, dev->real_num_rx_queues); - goto done; - } - rxqueue += index; - } - - /* Avoid computing hash if RFS/RPS is not active for this rxqueue */ - - flow_table = rcu_dereference(rxqueue->rps_flow_table); - map = rcu_dereference(rxqueue->rps_map); - if (!flow_table && !map) - goto done; - - skb_reset_network_header(skb); - hash = skb_get_hash(skb); - if (!hash) - goto done; - - sock_flow_table = rcu_dereference(rps_sock_flow_table); - if (flow_table && sock_flow_table) { - struct rps_dev_flow *rflow; - u32 next_cpu; - u32 ident; - - /* First check into global flow table if there is a match */ - ident = sock_flow_table->ents[hash & sock_flow_table->mask]; - if ((ident ^ hash) & ~rps_cpu_mask) - goto try_rps; - - next_cpu = ident & rps_cpu_mask; - - /* OK, now we know there is a match, - * we can look at the local (per receive queue) flow table - */ - rflow = &flow_table->flows[hash & flow_table->mask]; - tcpu = rflow->cpu; - - /* - * If the desired CPU (where last recvmsg was done) is - * different from current CPU (one in the rx-queue flow - * table entry), switch if one of the following holds: - * - Current CPU is unset (>= nr_cpu_ids). - * - Current CPU is offline. - * - The current CPU's queue tail has advanced beyond the - * last packet that was enqueued using this table entry. - * This guarantees that all previous packets for the flow - * have been dequeued, thus preserving in order delivery. - */ - if (unlikely(tcpu != next_cpu) && - (tcpu >= nr_cpu_ids || !cpu_online(tcpu) || - ((int)(per_cpu(softnet_data, tcpu).input_queue_head - - rflow->last_qtail)) >= 0)) { - tcpu = next_cpu; - rflow = set_rps_cpu(dev, skb, rflow, next_cpu); - } - - if (tcpu < nr_cpu_ids && cpu_online(tcpu)) { - *rflowp = rflow; - cpu = tcpu; - goto done; - } - } - -try_rps: - - if (map) { - tcpu = map->cpus[reciprocal_scale(hash, map->len)]; - if (cpu_online(tcpu)) { - cpu = tcpu; - goto done; - } - } - -done: - return cpu; -} - -#ifdef CONFIG_RFS_ACCEL - -/** - * rps_may_expire_flow - check whether an RFS hardware filter may be removed - * @dev: Device on which the filter was set - * @rxq_index: RX queue index - * @flow_id: Flow ID passed to ndo_rx_flow_steer() - * @filter_id: Filter ID returned by ndo_rx_flow_steer() - * - * Drivers that implement ndo_rx_flow_steer() should periodically call - * this function for each installed filter and remove the filters for - * which it returns %true. - */ -bool rps_may_expire_flow(struct net_device *dev, u16 rxq_index, - u32 flow_id, u16 filter_id) -{ - struct netdev_rx_queue *rxqueue = dev->_rx + rxq_index; - struct rps_dev_flow_table *flow_table; - struct rps_dev_flow *rflow; - bool expire = true; - unsigned int cpu; - - rcu_read_lock(); - flow_table = rcu_dereference(rxqueue->rps_flow_table); - if (flow_table && flow_id <= flow_table->mask) { - rflow = &flow_table->flows[flow_id]; - cpu = ACCESS_ONCE(rflow->cpu); - if (rflow->filter == filter_id && cpu < nr_cpu_ids && - ((int)(per_cpu(softnet_data, cpu).input_queue_head - - rflow->last_qtail) < - (int)(10 * flow_table->mask))) - expire = false; - } - rcu_read_unlock(); - return expire; -} -EXPORT_SYMBOL(rps_may_expire_flow); - -#endif /* CONFIG_RFS_ACCEL */ - -/* Called from hardirq (IPI) context */ -static void rps_trigger_softirq(void *data) -{ - struct softnet_data *sd = data; - - ____napi_schedule(sd, &sd->backlog); - sd->received_rps++; -} - -#endif /* CONFIG_RPS */ - -/* - * Check if this softnet_data structure is another cpu one - * If yes, queue it to our IPI list and return 1 - * If no, return 0 - */ -static int rps_ipi_queued(struct softnet_data *sd) -{ -#ifdef CONFIG_RPS - struct softnet_data *mysd = this_cpu_ptr(&softnet_data); - - if (sd != mysd) { - sd->rps_ipi_next = mysd->rps_ipi_list; - mysd->rps_ipi_list = sd; - - __raise_softirq_irqoff(NET_RX_SOFTIRQ); - return 1; - } -#endif /* CONFIG_RPS */ - return 0; -} - -#ifdef CONFIG_NET_FLOW_LIMIT -int netdev_flow_limit_table_len __read_mostly = (1 << 12); -#endif - -static bool skb_flow_limit(struct sk_buff *skb, unsigned int qlen) -{ -#ifdef CONFIG_NET_FLOW_LIMIT - struct sd_flow_limit *fl; - struct softnet_data *sd; - unsigned int old_flow, new_flow; - - if (qlen < (netdev_max_backlog >> 1)) - return false; - - sd = this_cpu_ptr(&softnet_data); - - rcu_read_lock(); - fl = rcu_dereference(sd->flow_limit); - if (fl) { - new_flow = skb_get_hash(skb) & (fl->num_buckets - 1); - old_flow = fl->history[fl->history_head]; - fl->history[fl->history_head] = new_flow; - - fl->history_head++; - fl->history_head &= FLOW_LIMIT_HISTORY - 1; - - if (likely(fl->buckets[old_flow])) - fl->buckets[old_flow]--; - - if (++fl->buckets[new_flow] > (FLOW_LIMIT_HISTORY >> 1)) { - fl->count++; - rcu_read_unlock(); - return true; - } - } - rcu_read_unlock(); -#endif - return false; -} - -/* - * enqueue_to_backlog is called to queue an skb to a per CPU backlog - * queue (may be a remote CPU queue). - */ -static int enqueue_to_backlog(struct sk_buff *skb, int cpu, - unsigned int *qtail) -{ - struct softnet_data *sd; - unsigned long flags; - unsigned int qlen; - - sd = &per_cpu(softnet_data, cpu); - - local_irq_save(flags); - - rps_lock(sd); - if (!netif_running(skb->dev)) - goto drop; - qlen = skb_queue_len(&sd->input_pkt_queue); - if (qlen <= netdev_max_backlog && !skb_flow_limit(skb, qlen)) { - if (qlen) { -enqueue: - __skb_queue_tail(&sd->input_pkt_queue, skb); - input_queue_tail_incr_save(sd, qtail); - rps_unlock(sd); - local_irq_restore(flags); - return NET_RX_SUCCESS; - } - - /* Schedule NAPI for backlog device - * We can use non atomic operation since we own the queue lock - */ - if (!__test_and_set_bit(NAPI_STATE_SCHED, &sd->backlog.state)) { - if (!rps_ipi_queued(sd)) - ____napi_schedule(sd, &sd->backlog); - } - goto enqueue; - } - -drop: - sd->dropped++; - rps_unlock(sd); - - local_irq_restore(flags); - - atomic_long_inc(&skb->dev->rx_dropped); - kfree_skb(skb); - return NET_RX_DROP; -} - -static int netif_rx_internal(struct sk_buff *skb) -{ - int ret; - - net_timestamp_check(netdev_tstamp_prequeue, skb); - - trace_netif_rx(skb); -#ifdef CONFIG_RPS - if (static_key_false(&rps_needed)) { - struct rps_dev_flow voidflow, *rflow = &voidflow; - int cpu; - - preempt_disable(); - rcu_read_lock(); - - cpu = get_rps_cpu(skb->dev, skb, &rflow); - if (cpu < 0) - cpu = smp_processor_id(); - - ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail); - - rcu_read_unlock(); - preempt_enable(); - } else -#endif - { - unsigned int qtail; - ret = enqueue_to_backlog(skb, get_cpu(), &qtail); - put_cpu(); - } - return ret; -} - -/** - * netif_rx - post buffer to the network code - * @skb: buffer to post - * - * This function receives a packet from a device driver and queues it for - * the upper (protocol) levels to process. It always succeeds. The buffer - * may be dropped during processing for congestion control or by the - * protocol layers. - * - * return values: - * NET_RX_SUCCESS (no congestion) - * NET_RX_DROP (packet was dropped) - * - */ - -int netif_rx(struct sk_buff *skb) -{ - trace_netif_rx_entry(skb); - - return netif_rx_internal(skb); -} -EXPORT_SYMBOL(netif_rx); - -int netif_rx_ni(struct sk_buff *skb) -{ - int err; - - trace_netif_rx_ni_entry(skb); - - preempt_disable(); - err = netif_rx_internal(skb); - if (local_softirq_pending()) - do_softirq(); - preempt_enable(); - - return err; -} -EXPORT_SYMBOL(netif_rx_ni); - -static __latent_entropy void net_tx_action(struct softirq_action *h) -{ - struct softnet_data *sd = this_cpu_ptr(&softnet_data); - - if (sd->completion_queue) { - struct sk_buff *clist; - - local_irq_disable(); - clist = sd->completion_queue; - sd->completion_queue = NULL; - local_irq_enable(); - - while (clist) { - struct sk_buff *skb = clist; - clist = clist->next; - - WARN_ON(atomic_read(&skb->users)); - if (likely(get_kfree_skb_cb(skb)->reason == SKB_REASON_CONSUMED)) - trace_consume_skb(skb); - else - trace_kfree_skb(skb, net_tx_action); - - if (skb->fclone != SKB_FCLONE_UNAVAILABLE) - __kfree_skb(skb); - else - __kfree_skb_defer(skb); - } - - __kfree_skb_flush(); - } - - if (sd->output_queue) { - struct Qdisc *head; - - local_irq_disable(); - head = sd->output_queue; - sd->output_queue = NULL; - sd->output_queue_tailp = &sd->output_queue; - local_irq_enable(); - - while (head) { - struct Qdisc *q = head; - spinlock_t *root_lock; - - head = head->next_sched; - - root_lock = qdisc_lock(q); - spin_lock(root_lock); - /* We need to make sure head->next_sched is read - * before clearing __QDISC_STATE_SCHED - */ - smp_mb__before_atomic(); - clear_bit(__QDISC_STATE_SCHED, &q->state); - qdisc_run(q); - spin_unlock(root_lock); - } - } -} - -#if IS_ENABLED(CONFIG_BRIDGE) && IS_ENABLED(CONFIG_ATM_LANE) -/* This hook is defined here for ATM LANE */ -int (*br_fdb_test_addr_hook)(struct net_device *dev, - unsigned char *addr) __read_mostly; -EXPORT_SYMBOL_GPL(br_fdb_test_addr_hook); -#endif - -static inline struct sk_buff * -sch_handle_ingress(struct sk_buff *skb, struct packet_type **pt_prev, int *ret, - struct net_device *orig_dev) -{ -#ifdef CONFIG_NET_CLS_ACT - struct tcf_proto *cl = rcu_dereference_bh(skb->dev->ingress_cl_list); - struct tcf_result cl_res; - - /* If there's at least one ingress present somewhere (so - * we get here via enabled static key), remaining devices - * that are not configured with an ingress qdisc will bail - * out here. - */ - if (!cl) - return skb; - if (*pt_prev) { - *ret = deliver_skb(skb, *pt_prev, orig_dev); - *pt_prev = NULL; - } - - qdisc_skb_cb(skb)->pkt_len = skb->len; - skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_INGRESS); - qdisc_bstats_cpu_update(cl->q, skb); - - switch (tc_classify(skb, cl, &cl_res, false)) { - case TC_ACT_OK: - case TC_ACT_RECLASSIFY: - skb->tc_index = TC_H_MIN(cl_res.classid); - break; - case TC_ACT_SHOT: - qdisc_qstats_cpu_drop(cl->q); - kfree_skb(skb); - return NULL; - case TC_ACT_STOLEN: - case TC_ACT_QUEUED: - consume_skb(skb); - return NULL; - case TC_ACT_REDIRECT: - /* skb_mac_header check was done by cls/act_bpf, so - * we can safely push the L2 header back before - * redirecting to another netdev - */ - __skb_push(skb, skb->mac_len); - skb_do_redirect(skb); - return NULL; - default: - break; - } -#endif /* CONFIG_NET_CLS_ACT */ - return skb; -} - -/** - * netdev_is_rx_handler_busy - check if receive handler is registered - * @dev: device to check - * - * Check if a receive handler is already registered for a given device. - * Return true if there one. - * - * The caller must hold the rtnl_mutex. - */ -bool netdev_is_rx_handler_busy(struct net_device *dev) -{ - ASSERT_RTNL(); - return dev && rtnl_dereference(dev->rx_handler); -} -EXPORT_SYMBOL_GPL(netdev_is_rx_handler_busy); - -/** - * netdev_rx_handler_register - register receive handler - * @dev: device to register a handler for - * @rx_handler: receive handler to register - * @rx_handler_data: data pointer that is used by rx handler - * - * Register a receive handler for a device. This handler will then be - * called from __netif_receive_skb. A negative errno code is returned - * on a failure. - * - * The caller must hold the rtnl_mutex. - * - * For a general description of rx_handler, see enum rx_handler_result. - */ -int netdev_rx_handler_register(struct net_device *dev, - rx_handler_func_t *rx_handler, - void *rx_handler_data) -{ - ASSERT_RTNL(); - - if (dev->rx_handler) - return -EBUSY; - - /* Note: rx_handler_data must be set before rx_handler */ - rcu_assign_pointer(dev->rx_handler_data, rx_handler_data); - rcu_assign_pointer(dev->rx_handler, rx_handler); - - return 0; -} -EXPORT_SYMBOL_GPL(netdev_rx_handler_register); - -/** - * netdev_rx_handler_unregister - unregister receive handler - * @dev: device to unregister a handler from - * - * Unregister a receive handler from a device. - * - * The caller must hold the rtnl_mutex. - */ -void netdev_rx_handler_unregister(struct net_device *dev) -{ - - ASSERT_RTNL(); - RCU_INIT_POINTER(dev->rx_handler, NULL); - /* a reader seeing a non NULL rx_handler in a rcu_read_lock() - * section has a guarantee to see a non NULL rx_handler_data - * as well. - */ - synchronize_net(); - RCU_INIT_POINTER(dev->rx_handler_data, NULL); -} -EXPORT_SYMBOL_GPL(netdev_rx_handler_unregister); - -/* - * Limit the use of PFMEMALLOC reserves to those protocols that implement - * the special handling of PFMEMALLOC skbs. - */ -static bool skb_pfmemalloc_protocol(struct sk_buff *skb) -{ - switch (skb->protocol) { - case htons(ETH_P_ARP): - case htons(ETH_P_IP): - case htons(ETH_P_IPV6): - case htons(ETH_P_8021Q): - case htons(ETH_P_8021AD): - return true; - default: - return false; - } -} - -static inline int nf_ingress(struct sk_buff *skb, struct packet_type **pt_prev, - int *ret, struct net_device *orig_dev) -{ -#ifdef CONFIG_NETFILTER_INGRESS - if (nf_hook_ingress_active(skb)) { - int ingress_retval; - - if (*pt_prev) { - *ret = deliver_skb(skb, *pt_prev, orig_dev); - *pt_prev = NULL; - } - - rcu_read_lock(); - ingress_retval = nf_hook_ingress(skb); - rcu_read_unlock(); - return ingress_retval; - } -#endif /* CONFIG_NETFILTER_INGRESS */ - return 0; -} - -static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc) -{ - struct packet_type *ptype, *pt_prev; - rx_handler_func_t *rx_handler; - struct net_device *orig_dev; - bool deliver_exact = false; - int ret = NET_RX_DROP; - __be16 type; - - net_timestamp_check(!netdev_tstamp_prequeue, skb); - - trace_netif_receive_skb(skb); - - orig_dev = skb->dev; - - skb_reset_network_header(skb); - if (!skb_transport_header_was_set(skb)) - skb_reset_transport_header(skb); - skb_reset_mac_len(skb); - - pt_prev = NULL; - -another_round: - skb->skb_iif = skb->dev->ifindex; - - __this_cpu_inc(softnet_data.processed); - - if (skb->protocol == cpu_to_be16(ETH_P_8021Q) || - skb->protocol == cpu_to_be16(ETH_P_8021AD)) { - skb = skb_vlan_untag(skb); - if (unlikely(!skb)) - goto out; - } - -#ifdef CONFIG_NET_CLS_ACT - if (skb->tc_verd & TC_NCLS) { - skb->tc_verd = CLR_TC_NCLS(skb->tc_verd); - goto ncls; - } -#endif - - if (pfmemalloc) - goto skip_taps; - - list_for_each_entry_rcu(ptype, &ptype_all, list) { - if (pt_prev) - ret = deliver_skb(skb, pt_prev, orig_dev); - pt_prev = ptype; - } - - list_for_each_entry_rcu(ptype, &skb->dev->ptype_all, list) { - if (pt_prev) - ret = deliver_skb(skb, pt_prev, orig_dev); - pt_prev = ptype; - } - -skip_taps: -#ifdef CONFIG_NET_INGRESS - if (static_key_false(&ingress_needed)) { - skb = sch_handle_ingress(skb, &pt_prev, &ret, orig_dev); - if (!skb) - goto out; - - if (nf_ingress(skb, &pt_prev, &ret, orig_dev) < 0) - goto out; - } -#endif -#ifdef CONFIG_NET_CLS_ACT - skb->tc_verd = 0; -ncls: -#endif - if (pfmemalloc && !skb_pfmemalloc_protocol(skb)) - goto drop; - - if (skb_vlan_tag_present(skb)) { - if (pt_prev) { - ret = deliver_skb(skb, pt_prev, orig_dev); - pt_prev = NULL; - } - if (vlan_do_receive(&skb)) - goto another_round; - else if (unlikely(!skb)) - goto out; - } - - rx_handler = rcu_dereference(skb->dev->rx_handler); - if (rx_handler) { - if (pt_prev) { - ret = deliver_skb(skb, pt_prev, orig_dev); - pt_prev = NULL; - } - switch (rx_handler(&skb)) { - case RX_HANDLER_CONSUMED: - ret = NET_RX_SUCCESS; - goto out; - case RX_HANDLER_ANOTHER: - goto another_round; - case RX_HANDLER_EXACT: - deliver_exact = true; - case RX_HANDLER_PASS: - break; - default: - BUG(); - } - } - - if (unlikely(skb_vlan_tag_present(skb))) { - if (skb_vlan_tag_get_id(skb)) - skb->pkt_type = PACKET_OTHERHOST; - /* Note: we might in the future use prio bits - * and set skb->priority like in vlan_do_receive() - * For the time being, just ignore Priority Code Point - */ - skb->vlan_tci = 0; - } - - type = skb->protocol; - - /* deliver only exact match when indicated */ - if (likely(!deliver_exact)) { - deliver_ptype_list_skb(skb, &pt_prev, orig_dev, type, - &ptype_base[ntohs(type) & - PTYPE_HASH_MASK]); - } - - deliver_ptype_list_skb(skb, &pt_prev, orig_dev, type, - &orig_dev->ptype_specific); - - if (unlikely(skb->dev != orig_dev)) { - deliver_ptype_list_skb(skb, &pt_prev, orig_dev, type, - &skb->dev->ptype_specific); - } - - if (pt_prev) { - if (unlikely(skb_orphan_frags(skb, GFP_ATOMIC))) - goto drop; - else - ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev); - } else { -drop: - if (!deliver_exact) - atomic_long_inc(&skb->dev->rx_dropped); - else - atomic_long_inc(&skb->dev->rx_nohandler); - kfree_skb(skb); - /* Jamal, now you will not able to escape explaining - * me how you were going to use this. :-) - */ - ret = NET_RX_DROP; - } - -out: - return ret; -} - -static int __netif_receive_skb(struct sk_buff *skb) -{ - int ret; - - if (sk_memalloc_socks() && skb_pfmemalloc(skb)) { - unsigned long pflags = current->flags; - - /* - * PFMEMALLOC skbs are special, they should - * - be delivered to SOCK_MEMALLOC sockets only - * - stay away from userspace - * - have bounded memory usage - * - * Use PF_MEMALLOC as this saves us from propagating the allocation - * context down to all allocation sites. - */ - current->flags |= PF_MEMALLOC; - ret = __netif_receive_skb_core(skb, true); - tsk_restore_flags(current, pflags, PF_MEMALLOC); - } else - ret = __netif_receive_skb_core(skb, false); - - return ret; -} - -static int netif_receive_skb_internal(struct sk_buff *skb) -{ - int ret; - - net_timestamp_check(netdev_tstamp_prequeue, skb); - - if (skb_defer_rx_timestamp(skb)) - return NET_RX_SUCCESS; - - rcu_read_lock(); - -#ifdef CONFIG_RPS - if (static_key_false(&rps_needed)) { - struct rps_dev_flow voidflow, *rflow = &voidflow; - int cpu = get_rps_cpu(skb->dev, skb, &rflow); - - if (cpu >= 0) { - ret = enqueue_to_backlog(skb, cpu, &rflow->last_qtail); - rcu_read_unlock(); - return ret; - } - } -#endif - ret = __netif_receive_skb(skb); - rcu_read_unlock(); - return ret; -} - -/** - * netif_receive_skb - process receive buffer from network - * @skb: buffer to process - * - * netif_receive_skb() is the main receive data processing function. - * It always succeeds. The buffer may be dropped during processing - * for congestion control or by the protocol layers. - * - * This function may only be called from softirq context and interrupts - * should be enabled. - * - * Return values (usually ignored): - * NET_RX_SUCCESS: no congestion - * NET_RX_DROP: packet was dropped - */ -int netif_receive_skb(struct sk_buff *skb) -{ - trace_netif_receive_skb_entry(skb); - - return netif_receive_skb_internal(skb); -} -EXPORT_SYMBOL(netif_receive_skb); - -DEFINE_PER_CPU(struct work_struct, flush_works); - -/* Network device is going away, flush any packets still pending */ -static void flush_backlog(struct work_struct *work) -{ - struct sk_buff *skb, *tmp; - struct softnet_data *sd; - - local_bh_disable(); - sd = this_cpu_ptr(&softnet_data); - - local_irq_disable(); - rps_lock(sd); - skb_queue_walk_safe(&sd->input_pkt_queue, skb, tmp) { - if (skb->dev->reg_state == NETREG_UNREGISTERING) { - __skb_unlink(skb, &sd->input_pkt_queue); - kfree_skb(skb); - input_queue_head_incr(sd); - } - } - rps_unlock(sd); - local_irq_enable(); - - skb_queue_walk_safe(&sd->process_queue, skb, tmp) { - if (skb->dev->reg_state == NETREG_UNREGISTERING) { - __skb_unlink(skb, &sd->process_queue); - kfree_skb(skb); - input_queue_head_incr(sd); - } - } - local_bh_enable(); -} - -static void flush_all_backlogs(void) -{ - unsigned int cpu; - - get_online_cpus(); - - for_each_online_cpu(cpu) - queue_work_on(cpu, system_highpri_wq, - per_cpu_ptr(&flush_works, cpu)); - - for_each_online_cpu(cpu) - flush_work(per_cpu_ptr(&flush_works, cpu)); - - put_online_cpus(); -} - -static int napi_gro_complete(struct sk_buff *skb) -{ - struct packet_offload *ptype; - __be16 type = skb->protocol; - struct list_head *head = &offload_base; - int err = -ENOENT; - - BUILD_BUG_ON(sizeof(struct napi_gro_cb) > sizeof(skb->cb)); - - if (NAPI_GRO_CB(skb)->count == 1) { - skb_shinfo(skb)->gso_size = 0; - goto out; - } - - rcu_read_lock(); - list_for_each_entry_rcu(ptype, head, list) { - if (ptype->type != type || !ptype->callbacks.gro_complete) - continue; - - err = ptype->callbacks.gro_complete(skb, 0); - break; - } - rcu_read_unlock(); - - if (err) { - WARN_ON(&ptype->list == head); - kfree_skb(skb); - return NET_RX_SUCCESS; - } - -out: - return netif_receive_skb_internal(skb); -} - -/* napi->gro_list contains packets ordered by age. - * youngest packets at the head of it. - * Complete skbs in reverse order to reduce latencies. - */ -void napi_gro_flush(struct napi_struct *napi, bool flush_old) -{ - struct sk_buff *skb, *prev = NULL; - - /* scan list and build reverse chain */ - for (skb = napi->gro_list; skb != NULL; skb = skb->next) { - skb->prev = prev; - prev = skb; - } - - for (skb = prev; skb; skb = prev) { - skb->next = NULL; - - if (flush_old && NAPI_GRO_CB(skb)->age == jiffies) - return; - - prev = skb->prev; - napi_gro_complete(skb); - napi->gro_count--; - } - - napi->gro_list = NULL; -} -EXPORT_SYMBOL(napi_gro_flush); - -static void gro_list_prepare(struct napi_struct *napi, struct sk_buff *skb) -{ - struct sk_buff *p; - unsigned int maclen = skb->dev->hard_header_len; - u32 hash = skb_get_hash_raw(skb); - - for (p = napi->gro_list; p; p = p->next) { - unsigned long diffs; - - NAPI_GRO_CB(p)->flush = 0; - - if (hash != skb_get_hash_raw(p)) { - NAPI_GRO_CB(p)->same_flow = 0; - continue; - } - - diffs = (unsigned long)p->dev ^ (unsigned long)skb->dev; - diffs |= p->vlan_tci ^ skb->vlan_tci; - diffs |= skb_metadata_dst_cmp(p, skb); - if (maclen == ETH_HLEN) - diffs |= compare_ether_header(skb_mac_header(p), - skb_mac_header(skb)); - else if (!diffs) - diffs = memcmp(skb_mac_header(p), - skb_mac_header(skb), - maclen); - NAPI_GRO_CB(p)->same_flow = !diffs; - } -} - -static void skb_gro_reset_offset(struct sk_buff *skb) -{ - const struct skb_shared_info *pinfo = skb_shinfo(skb); - const skb_frag_t *frag0 = &pinfo->frags[0]; - - NAPI_GRO_CB(skb)->data_offset = 0; - NAPI_GRO_CB(skb)->frag0 = NULL; - NAPI_GRO_CB(skb)->frag0_len = 0; - - if (skb_mac_header(skb) == skb_tail_pointer(skb) && - pinfo->nr_frags && - !PageHighMem(skb_frag_page(frag0))) { - NAPI_GRO_CB(skb)->frag0 = skb_frag_address(frag0); - NAPI_GRO_CB(skb)->frag0_len = skb_frag_size(frag0); - } -} - -static void gro_pull_from_frag0(struct sk_buff *skb, int grow) -{ - struct skb_shared_info *pinfo = skb_shinfo(skb); - - BUG_ON(skb->end - skb->tail < grow); - - memcpy(skb_tail_pointer(skb), NAPI_GRO_CB(skb)->frag0, grow); - - skb->data_len -= grow; - skb->tail += grow; - - pinfo->frags[0].page_offset += grow; - skb_frag_size_sub(&pinfo->frags[0], grow); - - if (unlikely(!skb_frag_size(&pinfo->frags[0]))) { - skb_frag_unref(skb, 0); - memmove(pinfo->frags, pinfo->frags + 1, - --pinfo->nr_frags * sizeof(pinfo->frags[0])); - } -} - -static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb) -{ - struct sk_buff **pp = NULL; - struct packet_offload *ptype; - __be16 type = skb->protocol; - struct list_head *head = &offload_base; - int same_flow; - enum gro_result ret; - int grow; - - if (!(skb->dev->features & NETIF_F_GRO)) - goto normal; - - if (skb_is_gso(skb) || skb_has_frag_list(skb) || skb->csum_bad) - goto normal; - - gro_list_prepare(napi, skb); - - rcu_read_lock(); - list_for_each_entry_rcu(ptype, head, list) { - if (ptype->type != type || !ptype->callbacks.gro_receive) - continue; - - skb_set_network_header(skb, skb_gro_offset(skb)); - skb_reset_mac_len(skb); - NAPI_GRO_CB(skb)->same_flow = 0; - NAPI_GRO_CB(skb)->flush = 0; - NAPI_GRO_CB(skb)->free = 0; - NAPI_GRO_CB(skb)->encap_mark = 0; - NAPI_GRO_CB(skb)->recursion_counter = 0; - NAPI_GRO_CB(skb)->is_fou = 0; - NAPI_GRO_CB(skb)->is_atomic = 1; - NAPI_GRO_CB(skb)->gro_remcsum_start = 0; - - /* Setup for GRO checksum validation */ - switch (skb->ip_summed) { - case CHECKSUM_COMPLETE: - NAPI_GRO_CB(skb)->csum = skb->csum; - NAPI_GRO_CB(skb)->csum_valid = 1; - NAPI_GRO_CB(skb)->csum_cnt = 0; - break; - case CHECKSUM_UNNECESSARY: - NAPI_GRO_CB(skb)->csum_cnt = skb->csum_level + 1; - NAPI_GRO_CB(skb)->csum_valid = 0; - break; - default: - NAPI_GRO_CB(skb)->csum_cnt = 0; - NAPI_GRO_CB(skb)->csum_valid = 0; - } - - pp = ptype->callbacks.gro_receive(&napi->gro_list, skb); - break; - } - rcu_read_unlock(); - - if (&ptype->list == head) - goto normal; - - same_flow = NAPI_GRO_CB(skb)->same_flow; - ret = NAPI_GRO_CB(skb)->free ? GRO_MERGED_FREE : GRO_MERGED; - - if (pp) { - struct sk_buff *nskb = *pp; - - *pp = nskb->next; - nskb->next = NULL; - napi_gro_complete(nskb); - napi->gro_count--; - } - - if (same_flow) - goto ok; - - if (NAPI_GRO_CB(skb)->flush) - goto normal; - - if (unlikely(napi->gro_count >= MAX_GRO_SKBS)) { - struct sk_buff *nskb = napi->gro_list; - - /* locate the end of the list to select the 'oldest' flow */ - while (nskb->next) { - pp = &nskb->next; - nskb = *pp; - } - *pp = NULL; - nskb->next = NULL; - napi_gro_complete(nskb); - } else { - napi->gro_count++; - } - NAPI_GRO_CB(skb)->count = 1; - NAPI_GRO_CB(skb)->age = jiffies; - NAPI_GRO_CB(skb)->last = skb; - skb_shinfo(skb)->gso_size = skb_gro_len(skb); - skb->next = napi->gro_list; - napi->gro_list = skb; - ret = GRO_HELD; - -pull: - grow = skb_gro_offset(skb) - skb_headlen(skb); - if (grow > 0) - gro_pull_from_frag0(skb, grow); -ok: - return ret; - -normal: - ret = GRO_NORMAL; - goto pull; -} - -struct packet_offload *gro_find_receive_by_type(__be16 type) -{ - struct list_head *offload_head = &offload_base; - struct packet_offload *ptype; - - list_for_each_entry_rcu(ptype, offload_head, list) { - if (ptype->type != type || !ptype->callbacks.gro_receive) - continue; - return ptype; - } - return NULL; -} -EXPORT_SYMBOL(gro_find_receive_by_type); - -struct packet_offload *gro_find_complete_by_type(__be16 type) -{ - struct list_head *offload_head = &offload_base; - struct packet_offload *ptype; - - list_for_each_entry_rcu(ptype, offload_head, list) { - if (ptype->type != type || !ptype->callbacks.gro_complete) - continue; - return ptype; - } - return NULL; -} -EXPORT_SYMBOL(gro_find_complete_by_type); - -static gro_result_t napi_skb_finish(gro_result_t ret, struct sk_buff *skb) -{ - switch (ret) { - case GRO_NORMAL: - if (netif_receive_skb_internal(skb)) - ret = GRO_DROP; - break; - - case GRO_DROP: - kfree_skb(skb); - break; - - case GRO_MERGED_FREE: - if (NAPI_GRO_CB(skb)->free == NAPI_GRO_FREE_STOLEN_HEAD) { - skb_dst_drop(skb); - kmem_cache_free(skbuff_head_cache, skb); - } else { - __kfree_skb(skb); - } - break; - - case GRO_HELD: - case GRO_MERGED: - break; - } - - return ret; -} - -gro_result_t napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) -{ - skb_mark_napi_id(skb, napi); - trace_napi_gro_receive_entry(skb); - - skb_gro_reset_offset(skb); - - return napi_skb_finish(dev_gro_receive(napi, skb), skb); -} -EXPORT_SYMBOL(napi_gro_receive); - -static void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb) -{ - if (unlikely(skb->pfmemalloc)) { - consume_skb(skb); - return; - } - __skb_pull(skb, skb_headlen(skb)); - /* restore the reserve we had after netdev_alloc_skb_ip_align() */ - skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN - skb_headroom(skb)); - skb->vlan_tci = 0; - skb->dev = napi->dev; - skb->skb_iif = 0; - skb->encapsulation = 0; - skb_shinfo(skb)->gso_type = 0; - skb->truesize = SKB_TRUESIZE(skb_end_offset(skb)); - - napi->skb = skb; -} - -struct sk_buff *napi_get_frags(struct napi_struct *napi) -{ - struct sk_buff *skb = napi->skb; - - if (!skb) { - skb = napi_alloc_skb(napi, GRO_MAX_HEAD); - if (skb) { - napi->skb = skb; - skb_mark_napi_id(skb, napi); - } - } - return skb; -} -EXPORT_SYMBOL(napi_get_frags); - -static gro_result_t napi_frags_finish(struct napi_struct *napi, - struct sk_buff *skb, - gro_result_t ret) -{ - switch (ret) { - case GRO_NORMAL: - case GRO_HELD: - __skb_push(skb, ETH_HLEN); - skb->protocol = eth_type_trans(skb, skb->dev); - if (ret == GRO_NORMAL && netif_receive_skb_internal(skb)) - ret = GRO_DROP; - break; - - case GRO_DROP: - case GRO_MERGED_FREE: - napi_reuse_skb(napi, skb); - break; - - case GRO_MERGED: - break; - } - - return ret; -} - -/* Upper GRO stack assumes network header starts at gro_offset=0 - * Drivers could call both napi_gro_frags() and napi_gro_receive() - * We copy ethernet header into skb->data to have a common layout. - */ -static struct sk_buff *napi_frags_skb(struct napi_struct *napi) -{ - struct sk_buff *skb = napi->skb; - const struct ethhdr *eth; - unsigned int hlen = sizeof(*eth); - - napi->skb = NULL; - - skb_reset_mac_header(skb); - skb_gro_reset_offset(skb); - - eth = skb_gro_header_fast(skb, 0); - if (unlikely(skb_gro_header_hard(skb, hlen))) { - eth = skb_gro_header_slow(skb, hlen, 0); - if (unlikely(!eth)) { - net_warn_ratelimited("%s: dropping impossible skb from %s\n", - __func__, napi->dev->name); - napi_reuse_skb(napi, skb); - return NULL; - } - } else { - gro_pull_from_frag0(skb, hlen); - NAPI_GRO_CB(skb)->frag0 += hlen; - NAPI_GRO_CB(skb)->frag0_len -= hlen; - } - __skb_pull(skb, hlen); - - /* - * This works because the only protocols we care about don't require - * special handling. - * We'll fix it up properly in napi_frags_finish() - */ - skb->protocol = eth->h_proto; - - return skb; -} - -gro_result_t napi_gro_frags(struct napi_struct *napi) -{ - struct sk_buff *skb = napi_frags_skb(napi); - - if (!skb) - return GRO_DROP; - - trace_napi_gro_frags_entry(skb); - - return napi_frags_finish(napi, skb, dev_gro_receive(napi, skb)); -} -EXPORT_SYMBOL(napi_gro_frags); - -/* Compute the checksum from gro_offset and return the folded value - * after adding in any pseudo checksum. - */ -__sum16 __skb_gro_checksum_complete(struct sk_buff *skb) -{ - __wsum wsum; - __sum16 sum; - - wsum = skb_checksum(skb, skb_gro_offset(skb), skb_gro_len(skb), 0); - - /* NAPI_GRO_CB(skb)->csum holds pseudo checksum */ - sum = csum_fold(csum_add(NAPI_GRO_CB(skb)->csum, wsum)); - if (likely(!sum)) { - if (unlikely(skb->ip_summed == CHECKSUM_COMPLETE) && - !skb->csum_complete_sw) - netdev_rx_csum_fault(skb->dev); - } - - NAPI_GRO_CB(skb)->csum = wsum; - NAPI_GRO_CB(skb)->csum_valid = 1; - - return sum; -} -EXPORT_SYMBOL(__skb_gro_checksum_complete); - -/* - * net_rps_action_and_irq_enable sends any pending IPI's for rps. - * Note: called with local irq disabled, but exits with local irq enabled. - */ -static void net_rps_action_and_irq_enable(struct softnet_data *sd) -{ -#ifdef CONFIG_RPS - struct softnet_data *remsd = sd->rps_ipi_list; - - if (remsd) { - sd->rps_ipi_list = NULL; - - local_irq_enable(); - - /* Send pending IPI's to kick RPS processing on remote cpus. */ - while (remsd) { - struct softnet_data *next = remsd->rps_ipi_next; - - if (cpu_online(remsd->cpu)) - smp_call_function_single_async(remsd->cpu, - &remsd->csd); - remsd = next; - } - } else -#endif - local_irq_enable(); -} - -static bool sd_has_rps_ipi_waiting(struct softnet_data *sd) -{ -#ifdef CONFIG_RPS - return sd->rps_ipi_list != NULL; -#else - return false; -#endif -} - -static int process_backlog(struct napi_struct *napi, int quota) -{ - struct softnet_data *sd = container_of(napi, struct softnet_data, backlog); - bool again = true; - int work = 0; - - /* Check if we have pending ipi, its better to send them now, - * not waiting net_rx_action() end. - */ - if (sd_has_rps_ipi_waiting(sd)) { - local_irq_disable(); - net_rps_action_and_irq_enable(sd); - } - - napi->weight = weight_p; - while (again) { - struct sk_buff *skb; - - while ((skb = __skb_dequeue(&sd->process_queue))) { - rcu_read_lock(); - __netif_receive_skb(skb); - rcu_read_unlock(); - input_queue_head_incr(sd); - if (++work >= quota) - return work; - - } - - local_irq_disable(); - rps_lock(sd); - if (skb_queue_empty(&sd->input_pkt_queue)) { - /* - * Inline a custom version of __napi_complete(). - * only current cpu owns and manipulates this napi, - * and NAPI_STATE_SCHED is the only possible flag set - * on backlog. - * We can use a plain write instead of clear_bit(), - * and we dont need an smp_mb() memory barrier. - */ - napi->state = 0; - again = false; - } else { - skb_queue_splice_tail_init(&sd->input_pkt_queue, - &sd->process_queue); - } - rps_unlock(sd); - local_irq_enable(); - } - - return work; -} - -/** - * __napi_schedule - schedule for receive - * @n: entry to schedule - * - * The entry's receive function will be scheduled to run. - * Consider using __napi_schedule_irqoff() if hard irqs are masked. - */ -void __napi_schedule(struct napi_struct *n) -{ - unsigned long flags; - - local_irq_save(flags); - ____napi_schedule(this_cpu_ptr(&softnet_data), n); - local_irq_restore(flags); -} -EXPORT_SYMBOL(__napi_schedule); - -/** - * __napi_schedule_irqoff - schedule for receive - * @n: entry to schedule - * - * Variant of __napi_schedule() assuming hard irqs are masked - */ -void __napi_schedule_irqoff(struct napi_struct *n) -{ - ____napi_schedule(this_cpu_ptr(&softnet_data), n); -} -EXPORT_SYMBOL(__napi_schedule_irqoff); - -void __napi_complete(struct napi_struct *n) -{ - BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); - - list_del_init(&n->poll_list); - smp_mb__before_atomic(); - clear_bit(NAPI_STATE_SCHED, &n->state); -} -EXPORT_SYMBOL(__napi_complete); - -void napi_complete_done(struct napi_struct *n, int work_done) -{ - unsigned long flags; - - /* - * don't let napi dequeue from the cpu poll list - * just in case its running on a different cpu - */ - if (unlikely(test_bit(NAPI_STATE_NPSVC, &n->state))) - return; - - if (n->gro_list) { - unsigned long timeout = 0; - - if (work_done) - timeout = n->dev->gro_flush_timeout; - - if (timeout) - hrtimer_start(&n->timer, ns_to_ktime(timeout), - HRTIMER_MODE_REL_PINNED); - else - napi_gro_flush(n, false); - } - if (likely(list_empty(&n->poll_list))) { - WARN_ON_ONCE(!test_and_clear_bit(NAPI_STATE_SCHED, &n->state)); - } else { - /* If n->poll_list is not empty, we need to mask irqs */ - local_irq_save(flags); - __napi_complete(n); - local_irq_restore(flags); - } -} -EXPORT_SYMBOL(napi_complete_done); - -/* must be called under rcu_read_lock(), as we dont take a reference */ -static struct napi_struct *napi_by_id(unsigned int napi_id) -{ - unsigned int hash = napi_id % HASH_SIZE(napi_hash); - struct napi_struct *napi; - - hlist_for_each_entry_rcu(napi, &napi_hash[hash], napi_hash_node) - if (napi->napi_id == napi_id) - return napi; - - return NULL; -} - -#if defined(CONFIG_NET_RX_BUSY_POLL) -#define BUSY_POLL_BUDGET 8 -bool sk_busy_loop(struct sock *sk, int nonblock) -{ - unsigned long end_time = !nonblock ? sk_busy_loop_end_time(sk) : 0; - int (*busy_poll)(struct napi_struct *dev); - struct napi_struct *napi; - int rc = false; - - rcu_read_lock(); - - napi = napi_by_id(sk->sk_napi_id); - if (!napi) - goto out; - - /* Note: ndo_busy_poll method is optional in linux-4.5 */ - busy_poll = napi->dev->netdev_ops->ndo_busy_poll; - - do { - rc = 0; - local_bh_disable(); - if (busy_poll) { - rc = busy_poll(napi); - } else if (napi_schedule_prep(napi)) { - void *have = netpoll_poll_lock(napi); - - if (test_bit(NAPI_STATE_SCHED, &napi->state)) { - rc = napi->poll(napi, BUSY_POLL_BUDGET); - trace_napi_poll(napi, rc, BUSY_POLL_BUDGET); - if (rc == BUSY_POLL_BUDGET) { - napi_complete_done(napi, rc); - napi_schedule(napi); - } - } - netpoll_poll_unlock(have); - } - if (rc > 0) - __NET_ADD_STATS(sock_net(sk), - LINUX_MIB_BUSYPOLLRXPACKETS, rc); - local_bh_enable(); - - if (rc == LL_FLUSH_FAILED) - break; /* permanent failure */ - - cpu_relax(); - } while (!nonblock && skb_queue_empty(&sk->sk_receive_queue) && - !need_resched() && !busy_loop_timeout(end_time)); - - rc = !skb_queue_empty(&sk->sk_receive_queue); -out: - rcu_read_unlock(); - return rc; -} -EXPORT_SYMBOL(sk_busy_loop); - -#endif /* CONFIG_NET_RX_BUSY_POLL */ - -void napi_hash_add(struct napi_struct *napi) -{ - if (test_bit(NAPI_STATE_NO_BUSY_POLL, &napi->state) || - test_and_set_bit(NAPI_STATE_HASHED, &napi->state)) - return; - - spin_lock(&napi_hash_lock); - - /* 0..NR_CPUS+1 range is reserved for sender_cpu use */ - do { - if (unlikely(++napi_gen_id < NR_CPUS + 1)) - napi_gen_id = NR_CPUS + 1; - } while (napi_by_id(napi_gen_id)); - napi->napi_id = napi_gen_id; - - hlist_add_head_rcu(&napi->napi_hash_node, - &napi_hash[napi->napi_id % HASH_SIZE(napi_hash)]); - - spin_unlock(&napi_hash_lock); -} -EXPORT_SYMBOL_GPL(napi_hash_add); - -/* Warning : caller is responsible to make sure rcu grace period - * is respected before freeing memory containing @napi - */ -bool napi_hash_del(struct napi_struct *napi) -{ - bool rcu_sync_needed = false; - - spin_lock(&napi_hash_lock); - - if (test_and_clear_bit(NAPI_STATE_HASHED, &napi->state)) { - rcu_sync_needed = true; - hlist_del_rcu(&napi->napi_hash_node); - } - spin_unlock(&napi_hash_lock); - return rcu_sync_needed; -} -EXPORT_SYMBOL_GPL(napi_hash_del); - -static enum hrtimer_restart napi_watchdog(struct hrtimer *timer) -{ - struct napi_struct *napi; - - napi = container_of(timer, struct napi_struct, timer); - if (napi->gro_list) - napi_schedule(napi); - - return HRTIMER_NORESTART; -} - -void netif_napi_add(struct net_device *dev, struct napi_struct *napi, - int (*poll)(struct napi_struct *, int), int weight) -{ - INIT_LIST_HEAD(&napi->poll_list); - hrtimer_init(&napi->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); - napi->timer.function = napi_watchdog; - napi->gro_count = 0; - napi->gro_list = NULL; - napi->skb = NULL; - napi->poll = poll; - if (weight > NAPI_POLL_WEIGHT) - pr_err_once("netif_napi_add() called with weight %d on device %s\n", - weight, dev->name); - napi->weight = weight; - list_add(&napi->dev_list, &dev->napi_list); - napi->dev = dev; -#ifdef CONFIG_NETPOLL - spin_lock_init(&napi->poll_lock); - napi->poll_owner = -1; -#endif - set_bit(NAPI_STATE_SCHED, &napi->state); - napi_hash_add(napi); -} -EXPORT_SYMBOL(netif_napi_add); - -void napi_disable(struct napi_struct *n) -{ - might_sleep(); - set_bit(NAPI_STATE_DISABLE, &n->state); - - while (test_and_set_bit(NAPI_STATE_SCHED, &n->state)) - msleep(1); - while (test_and_set_bit(NAPI_STATE_NPSVC, &n->state)) - msleep(1); - - hrtimer_cancel(&n->timer); - - clear_bit(NAPI_STATE_DISABLE, &n->state); -} -EXPORT_SYMBOL(napi_disable); - -/* Must be called in process context */ -void netif_napi_del(struct napi_struct *napi) -{ - might_sleep(); - if (napi_hash_del(napi)) - synchronize_net(); - list_del_init(&napi->dev_list); - napi_free_frags(napi); - - kfree_skb_list(napi->gro_list); - napi->gro_list = NULL; - napi->gro_count = 0; -} -EXPORT_SYMBOL(netif_napi_del); - -static int napi_poll(struct napi_struct *n, struct list_head *repoll) -{ - void *have; - int work, weight; - - list_del_init(&n->poll_list); - - have = netpoll_poll_lock(n); - - weight = n->weight; - - /* This NAPI_STATE_SCHED test is for avoiding a race - * with netpoll's poll_napi(). Only the entity which - * obtains the lock and sees NAPI_STATE_SCHED set will - * actually make the ->poll() call. Therefore we avoid - * accidentally calling ->poll() when NAPI is not scheduled. - */ - work = 0; - if (test_bit(NAPI_STATE_SCHED, &n->state)) { - work = n->poll(n, weight); - trace_napi_poll(n, work, weight); - } - - WARN_ON_ONCE(work > weight); - - if (likely(work < weight)) - goto out_unlock; - - /* Drivers must not modify the NAPI state if they - * consume the entire weight. In such cases this code - * still "owns" the NAPI instance and therefore can - * move the instance around on the list at-will. - */ - if (unlikely(napi_disable_pending(n))) { - napi_complete(n); - goto out_unlock; - } - - if (n->gro_list) { - /* flush too old packets - * If HZ < 1000, flush all packets. - */ - napi_gro_flush(n, HZ >= 1000); - } - - /* Some drivers may have called napi_schedule - * prior to exhausting their budget. - */ - if (unlikely(!list_empty(&n->poll_list))) { - pr_warn_once("%s: Budget exhausted after napi rescheduled\n", - n->dev ? n->dev->name : "backlog"); - goto out_unlock; - } - - list_add_tail(&n->poll_list, repoll); - -out_unlock: - netpoll_poll_unlock(have); - - return work; -} - -static __latent_entropy void net_rx_action(struct softirq_action *h) -{ - struct softnet_data *sd = this_cpu_ptr(&softnet_data); - unsigned long time_limit = jiffies + 2; - int budget = netdev_budget; - LIST_HEAD(list); - LIST_HEAD(repoll); - - local_irq_disable(); - list_splice_init(&sd->poll_list, &list); - local_irq_enable(); - - for (;;) { - struct napi_struct *n; - - if (list_empty(&list)) { - if (!sd_has_rps_ipi_waiting(sd) && list_empty(&repoll)) - return; - break; - } - - n = list_first_entry(&list, struct napi_struct, poll_list); - budget -= napi_poll(n, &repoll); - - /* If softirq window is exhausted then punt. - * Allow this to run for 2 jiffies since which will allow - * an average latency of 1.5/HZ. - */ - if (unlikely(budget <= 0 || - time_after_eq(jiffies, time_limit))) { - sd->time_squeeze++; - break; - } - } - - __kfree_skb_flush(); - local_irq_disable(); - - list_splice_tail_init(&sd->poll_list, &list); - list_splice_tail(&repoll, &list); - list_splice(&list, &sd->poll_list); - if (!list_empty(&sd->poll_list)) - __raise_softirq_irqoff(NET_RX_SOFTIRQ); - - net_rps_action_and_irq_enable(sd); -} - -struct netdev_adjacent { - struct net_device *dev; - - /* upper master flag, there can only be one master device per list */ - bool master; - - /* counter for the number of times this device was added to us */ - u16 ref_nr; - - /* private field for the users */ - void *private; - - struct list_head list; - struct rcu_head rcu; -}; - -static struct netdev_adjacent *__netdev_find_adj(struct net_device *adj_dev, - struct list_head *adj_list) -{ - struct netdev_adjacent *adj; - - list_for_each_entry(adj, adj_list, list) { - if (adj->dev == adj_dev) - return adj; - } - return NULL; -} - -/** - * netdev_has_upper_dev - Check if device is linked to an upper device - * @dev: device - * @upper_dev: upper device to check - * - * Find out if a device is linked to specified upper device and return true - * in case it is. Note that this checks only immediate upper device, - * not through a complete stack of devices. The caller must hold the RTNL lock. - */ -bool netdev_has_upper_dev(struct net_device *dev, - struct net_device *upper_dev) -{ - ASSERT_RTNL(); - - return __netdev_find_adj(upper_dev, &dev->all_adj_list.upper); -} -EXPORT_SYMBOL(netdev_has_upper_dev); - -/** - * netdev_has_any_upper_dev - Check if device is linked to some device - * @dev: device - * - * Find out if a device is linked to an upper device and return true in case - * it is. The caller must hold the RTNL lock. - */ -static bool netdev_has_any_upper_dev(struct net_device *dev) -{ - ASSERT_RTNL(); - - return !list_empty(&dev->all_adj_list.upper); -} - -/** - * netdev_master_upper_dev_get - Get master upper device - * @dev: device - * - * Find a master upper device and return pointer to it or NULL in case - * it's not there. The caller must hold the RTNL lock. - */ -struct net_device *netdev_master_upper_dev_get(struct net_device *dev) -{ - struct netdev_adjacent *upper; - - ASSERT_RTNL(); - - if (list_empty(&dev->adj_list.upper)) - return NULL; - - upper = list_first_entry(&dev->adj_list.upper, - struct netdev_adjacent, list); - if (likely(upper->master)) - return upper->dev; - return NULL; -} -EXPORT_SYMBOL(netdev_master_upper_dev_get); - -void *netdev_adjacent_get_private(struct list_head *adj_list) -{ - struct netdev_adjacent *adj; - - adj = list_entry(adj_list, struct netdev_adjacent, list); - - return adj->private; -} -EXPORT_SYMBOL(netdev_adjacent_get_private); - -/** - * netdev_upper_get_next_dev_rcu - Get the next dev from upper list - * @dev: device - * @iter: list_head ** of the current position - * - * Gets the next device from the dev's upper list, starting from iter - * position. The caller must hold RCU read lock. - */ -struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev, - struct list_head **iter) -{ - struct netdev_adjacent *upper; - - WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_rtnl_is_held()); - - upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); - - if (&upper->list == &dev->adj_list.upper) - return NULL; - - *iter = &upper->list; - - return upper->dev; -} -EXPORT_SYMBOL(netdev_upper_get_next_dev_rcu); - -/** - * netdev_all_upper_get_next_dev_rcu - Get the next dev from upper list - * @dev: device - * @iter: list_head ** of the current position - * - * Gets the next device from the dev's upper list, starting from iter - * position. The caller must hold RCU read lock. - */ -struct net_device *netdev_all_upper_get_next_dev_rcu(struct net_device *dev, - struct list_head **iter) -{ - struct netdev_adjacent *upper; - - WARN_ON_ONCE(!rcu_read_lock_held() && !lockdep_rtnl_is_held()); - - upper = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); - - if (&upper->list == &dev->all_adj_list.upper) - return NULL; - - *iter = &upper->list; - - return upper->dev; -} -EXPORT_SYMBOL(netdev_all_upper_get_next_dev_rcu); - -/** - * netdev_lower_get_next_private - Get the next ->private from the - * lower neighbour list - * @dev: device - * @iter: list_head ** of the current position - * - * Gets the next netdev_adjacent->private from the dev's lower neighbour - * list, starting from iter position. The caller must hold either hold the - * RTNL lock or its own locking that guarantees that the neighbour lower - * list will remain unchanged. - */ -void *netdev_lower_get_next_private(struct net_device *dev, - struct list_head **iter) -{ - struct netdev_adjacent *lower; - - lower = list_entry(*iter, struct netdev_adjacent, list); - - if (&lower->list == &dev->adj_list.lower) - return NULL; - - *iter = lower->list.next; - - return lower->private; -} -EXPORT_SYMBOL(netdev_lower_get_next_private); - -/** - * netdev_lower_get_next_private_rcu - Get the next ->private from the - * lower neighbour list, RCU - * variant - * @dev: device - * @iter: list_head ** of the current position - * - * Gets the next netdev_adjacent->private from the dev's lower neighbour - * list, starting from iter position. The caller must hold RCU read lock. - */ -void *netdev_lower_get_next_private_rcu(struct net_device *dev, - struct list_head **iter) -{ - struct netdev_adjacent *lower; - - WARN_ON_ONCE(!rcu_read_lock_held()); - - lower = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); - - if (&lower->list == &dev->adj_list.lower) - return NULL; - - *iter = &lower->list; - - return lower->private; -} -EXPORT_SYMBOL(netdev_lower_get_next_private_rcu); - -/** - * netdev_lower_get_next - Get the next device from the lower neighbour - * list - * @dev: device - * @iter: list_head ** of the current position - * - * Gets the next netdev_adjacent from the dev's lower neighbour - * list, starting from iter position. The caller must hold RTNL lock or - * its own locking that guarantees that the neighbour lower - * list will remain unchanged. - */ -void *netdev_lower_get_next(struct net_device *dev, struct list_head **iter) -{ - struct netdev_adjacent *lower; - - lower = list_entry(*iter, struct netdev_adjacent, list); - - if (&lower->list == &dev->adj_list.lower) - return NULL; - - *iter = lower->list.next; - - return lower->dev; -} -EXPORT_SYMBOL(netdev_lower_get_next); - -/** - * netdev_all_lower_get_next - Get the next device from all lower neighbour list - * @dev: device - * @iter: list_head ** of the current position - * - * Gets the next netdev_adjacent from the dev's all lower neighbour - * list, starting from iter position. The caller must hold RTNL lock or - * its own locking that guarantees that the neighbour all lower - * list will remain unchanged. - */ -struct net_device *netdev_all_lower_get_next(struct net_device *dev, struct list_head **iter) -{ - struct netdev_adjacent *lower; - - lower = list_entry(*iter, struct netdev_adjacent, list); - - if (&lower->list == &dev->all_adj_list.lower) - return NULL; - - *iter = lower->list.next; - - return lower->dev; -} -EXPORT_SYMBOL(netdev_all_lower_get_next); - -/** - * netdev_all_lower_get_next_rcu - Get the next device from all - * lower neighbour list, RCU variant - * @dev: device - * @iter: list_head ** of the current position - * - * Gets the next netdev_adjacent from the dev's all lower neighbour - * list, starting from iter position. The caller must hold RCU read lock. - */ -struct net_device *netdev_all_lower_get_next_rcu(struct net_device *dev, - struct list_head **iter) -{ - struct netdev_adjacent *lower; - - lower = list_entry_rcu((*iter)->next, struct netdev_adjacent, list); - - if (&lower->list == &dev->all_adj_list.lower) - return NULL; - - *iter = &lower->list; - - return lower->dev; -} -EXPORT_SYMBOL(netdev_all_lower_get_next_rcu); - -/** - * netdev_lower_get_first_private_rcu - Get the first ->private from the - * lower neighbour list, RCU - * variant - * @dev: device - * - * Gets the first netdev_adjacent->private from the dev's lower neighbour - * list. The caller must hold RCU read lock. - */ -void *netdev_lower_get_first_private_rcu(struct net_device *dev) -{ - struct netdev_adjacent *lower; - - lower = list_first_or_null_rcu(&dev->adj_list.lower, - struct netdev_adjacent, list); - if (lower) - return lower->private; - return NULL; -} -EXPORT_SYMBOL(netdev_lower_get_first_private_rcu); - -/** - * netdev_master_upper_dev_get_rcu - Get master upper device - * @dev: device - * - * Find a master upper device and return pointer to it or NULL in case - * it's not there. The caller must hold the RCU read lock. - */ -struct net_device *netdev_master_upper_dev_get_rcu(struct net_device *dev) -{ - struct netdev_adjacent *upper; - - upper = list_first_or_null_rcu(&dev->adj_list.upper, - struct netdev_adjacent, list); - if (upper && likely(upper->master)) - return upper->dev; - return NULL; -} -EXPORT_SYMBOL(netdev_master_upper_dev_get_rcu); - -static int netdev_adjacent_sysfs_add(struct net_device *dev, - struct net_device *adj_dev, - struct list_head *dev_list) -{ - char linkname[IFNAMSIZ+7]; - sprintf(linkname, dev_list == &dev->adj_list.upper ? - "upper_%s" : "lower_%s", adj_dev->name); - return sysfs_create_link(&(dev->dev.kobj), &(adj_dev->dev.kobj), - linkname); -} -static void netdev_adjacent_sysfs_del(struct net_device *dev, - char *name, - struct list_head *dev_list) -{ - char linkname[IFNAMSIZ+7]; - sprintf(linkname, dev_list == &dev->adj_list.upper ? - "upper_%s" : "lower_%s", name); - sysfs_remove_link(&(dev->dev.kobj), linkname); -} - -static inline bool netdev_adjacent_is_neigh_list(struct net_device *dev, - struct net_device *adj_dev, - struct list_head *dev_list) -{ - return (dev_list == &dev->adj_list.upper || - dev_list == &dev->adj_list.lower) && - net_eq(dev_net(dev), dev_net(adj_dev)); -} - -static int __netdev_adjacent_dev_insert(struct net_device *dev, - struct net_device *adj_dev, - u16 ref_nr, - struct list_head *dev_list, - void *private, bool master) -{ - struct netdev_adjacent *adj; - int ret; - - adj = __netdev_find_adj(adj_dev, dev_list); - - if (adj) { - adj->ref_nr += ref_nr; - return 0; - } - - adj = kmalloc(sizeof(*adj), GFP_KERNEL); - if (!adj) - return -ENOMEM; - - adj->dev = adj_dev; - adj->master = master; - adj->ref_nr = ref_nr; - adj->private = private; - dev_hold(adj_dev); - - pr_debug("dev_hold for %s, because of link added from %s to %s\n", - adj_dev->name, dev->name, adj_dev->name); - - if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list)) { - ret = netdev_adjacent_sysfs_add(dev, adj_dev, dev_list); - if (ret) - goto free_adj; - } - - /* Ensure that master link is always the first item in list. */ - if (master) { - ret = sysfs_create_link(&(dev->dev.kobj), - &(adj_dev->dev.kobj), "master"); - if (ret) - goto remove_symlinks; - - list_add_rcu(&adj->list, dev_list); - } else { - list_add_tail_rcu(&adj->list, dev_list); - } - - return 0; - -remove_symlinks: - if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list)) - netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list); -free_adj: - kfree(adj); - dev_put(adj_dev); - - return ret; -} - -static void __netdev_adjacent_dev_remove(struct net_device *dev, - struct net_device *adj_dev, - u16 ref_nr, - struct list_head *dev_list) -{ - struct netdev_adjacent *adj; - - adj = __netdev_find_adj(adj_dev, dev_list); - - if (!adj) { - pr_err("tried to remove device %s from %s\n", - dev->name, adj_dev->name); - BUG(); - } - - if (adj->ref_nr > ref_nr) { - pr_debug("%s to %s ref_nr-%d = %d\n", dev->name, adj_dev->name, - ref_nr, adj->ref_nr-ref_nr); - adj->ref_nr -= ref_nr; - return; - } - - if (adj->master) - sysfs_remove_link(&(dev->dev.kobj), "master"); - - if (netdev_adjacent_is_neigh_list(dev, adj_dev, dev_list)) - netdev_adjacent_sysfs_del(dev, adj_dev->name, dev_list); - - list_del_rcu(&adj->list); - pr_debug("dev_put for %s, because link removed from %s to %s\n", - adj_dev->name, dev->name, adj_dev->name); - dev_put(adj_dev); - kfree_rcu(adj, rcu); -} - -static int __netdev_adjacent_dev_link_lists(struct net_device *dev, - struct net_device *upper_dev, - u16 ref_nr, - struct list_head *up_list, - struct list_head *down_list, - void *private, bool master) -{ - int ret; - - ret = __netdev_adjacent_dev_insert(dev, upper_dev, ref_nr, up_list, - private, master); - if (ret) - return ret; - - ret = __netdev_adjacent_dev_insert(upper_dev, dev, ref_nr, down_list, - private, false); - if (ret) { - __netdev_adjacent_dev_remove(dev, upper_dev, ref_nr, up_list); - return ret; - } - - return 0; -} - -static int __netdev_adjacent_dev_link(struct net_device *dev, - struct net_device *upper_dev, - u16 ref_nr) -{ - return __netdev_adjacent_dev_link_lists(dev, upper_dev, ref_nr, - &dev->all_adj_list.upper, - &upper_dev->all_adj_list.lower, - NULL, false); -} - -static void __netdev_adjacent_dev_unlink_lists(struct net_device *dev, - struct net_device *upper_dev, - u16 ref_nr, - struct list_head *up_list, - struct list_head *down_list) -{ - __netdev_adjacent_dev_remove(dev, upper_dev, ref_nr, up_list); - __netdev_adjacent_dev_remove(upper_dev, dev, ref_nr, down_list); -} - -static void __netdev_adjacent_dev_unlink(struct net_device *dev, - struct net_device *upper_dev, - u16 ref_nr) -{ - __netdev_adjacent_dev_unlink_lists(dev, upper_dev, ref_nr, - &dev->all_adj_list.upper, - &upper_dev->all_adj_list.lower); -} - -static int __netdev_adjacent_dev_link_neighbour(struct net_device *dev, - struct net_device *upper_dev, - void *private, bool master) -{ - int ret = __netdev_adjacent_dev_link(dev, upper_dev, 1); - - if (ret) - return ret; - - ret = __netdev_adjacent_dev_link_lists(dev, upper_dev, 1, - &dev->adj_list.upper, - &upper_dev->adj_list.lower, - private, master); - if (ret) { - __netdev_adjacent_dev_unlink(dev, upper_dev, 1); - return ret; - } - - return 0; -} - -static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev, - struct net_device *upper_dev) -{ - __netdev_adjacent_dev_unlink(dev, upper_dev, 1); - __netdev_adjacent_dev_unlink_lists(dev, upper_dev, 1, - &dev->adj_list.upper, - &upper_dev->adj_list.lower); -} - -static int __netdev_upper_dev_link(struct net_device *dev, - struct net_device *upper_dev, bool master, - void *upper_priv, void *upper_info) -{ - struct netdev_notifier_changeupper_info changeupper_info; - struct netdev_adjacent *i, *j, *to_i, *to_j; - int ret = 0; - - ASSERT_RTNL(); - - if (dev == upper_dev) - return -EBUSY; - - /* To prevent loops, check if dev is not upper device to upper_dev. */ - if (__netdev_find_adj(dev, &upper_dev->all_adj_list.upper)) - return -EBUSY; - - if (__netdev_find_adj(upper_dev, &dev->adj_list.upper)) - return -EEXIST; - - if (master && netdev_master_upper_dev_get(dev)) - return -EBUSY; - - changeupper_info.upper_dev = upper_dev; - changeupper_info.master = master; - changeupper_info.linking = true; - changeupper_info.upper_info = upper_info; - - ret = call_netdevice_notifiers_info(NETDEV_PRECHANGEUPPER, dev, - &changeupper_info.info); - ret = notifier_to_errno(ret); - if (ret) - return ret; - - ret = __netdev_adjacent_dev_link_neighbour(dev, upper_dev, upper_priv, - master); - if (ret) - return ret; - - /* Now that we linked these devs, make all the upper_dev's - * all_adj_list.upper visible to every dev's all_adj_list.lower an - * versa, and don't forget the devices itself. All of these - * links are non-neighbours. - */ - list_for_each_entry(i, &dev->all_adj_list.lower, list) { - list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) { - pr_debug("Interlinking %s with %s, non-neighbour\n", - i->dev->name, j->dev->name); - ret = __netdev_adjacent_dev_link(i->dev, j->dev, i->ref_nr); - if (ret) - goto rollback_mesh; - } - } - - /* add dev to every upper_dev's upper device */ - list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) { - pr_debug("linking %s's upper device %s with %s\n", - upper_dev->name, i->dev->name, dev->name); - ret = __netdev_adjacent_dev_link(dev, i->dev, i->ref_nr); - if (ret) - goto rollback_upper_mesh; - } - - /* add upper_dev to every dev's lower device */ - list_for_each_entry(i, &dev->all_adj_list.lower, list) { - pr_debug("linking %s's lower device %s with %s\n", dev->name, - i->dev->name, upper_dev->name); - ret = __netdev_adjacent_dev_link(i->dev, upper_dev, i->ref_nr); - if (ret) - goto rollback_lower_mesh; - } - - ret = call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev, - &changeupper_info.info); - ret = notifier_to_errno(ret); - if (ret) - goto rollback_lower_mesh; - - return 0; - -rollback_lower_mesh: - to_i = i; - list_for_each_entry(i, &dev->all_adj_list.lower, list) { - if (i == to_i) - break; - __netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr); - } - - i = NULL; - -rollback_upper_mesh: - to_i = i; - list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) { - if (i == to_i) - break; - __netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr); - } - - i = j = NULL; - -rollback_mesh: - to_i = i; - to_j = j; - list_for_each_entry(i, &dev->all_adj_list.lower, list) { - list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) { - if (i == to_i && j == to_j) - break; - __netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr); - } - if (i == to_i) - break; - } - - __netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); - - return ret; -} - -/** - * netdev_upper_dev_link - Add a link to the upper device - * @dev: device - * @upper_dev: new upper device - * - * Adds a link to device which is upper to this one. The caller must hold - * the RTNL lock. On a failure a negative errno code is returned. - * On success the reference counts are adjusted and the function - * returns zero. - */ -int netdev_upper_dev_link(struct net_device *dev, - struct net_device *upper_dev) -{ - return __netdev_upper_dev_link(dev, upper_dev, false, NULL, NULL); -} -EXPORT_SYMBOL(netdev_upper_dev_link); - -/** - * netdev_master_upper_dev_link - Add a master link to the upper device - * @dev: device - * @upper_dev: new upper device - * @upper_priv: upper device private - * @upper_info: upper info to be passed down via notifier - * - * Adds a link to device which is upper to this one. In this case, only - * one master upper device can be linked, although other non-master devices - * might be linked as well. The caller must hold the RTNL lock. - * On a failure a negative errno code is returned. On success the reference - * counts are adjusted and the function returns zero. - */ -int netdev_master_upper_dev_link(struct net_device *dev, - struct net_device *upper_dev, - void *upper_priv, void *upper_info) -{ - return __netdev_upper_dev_link(dev, upper_dev, true, - upper_priv, upper_info); -} -EXPORT_SYMBOL(netdev_master_upper_dev_link); - -/** - * netdev_upper_dev_unlink - Removes a link to upper device - * @dev: device - * @upper_dev: new upper device - * - * Removes a link to device which is upper to this one. The caller must hold - * the RTNL lock. - */ -void netdev_upper_dev_unlink(struct net_device *dev, - struct net_device *upper_dev) -{ - struct netdev_notifier_changeupper_info changeupper_info; - struct netdev_adjacent *i, *j; - ASSERT_RTNL(); - - changeupper_info.upper_dev = upper_dev; - changeupper_info.master = netdev_master_upper_dev_get(dev) == upper_dev; - changeupper_info.linking = false; - - call_netdevice_notifiers_info(NETDEV_PRECHANGEUPPER, dev, - &changeupper_info.info); - - __netdev_adjacent_dev_unlink_neighbour(dev, upper_dev); - - /* Here is the tricky part. We must remove all dev's lower - * devices from all upper_dev's upper devices and vice - * versa, to maintain the graph relationship. - */ - list_for_each_entry(i, &dev->all_adj_list.lower, list) - list_for_each_entry(j, &upper_dev->all_adj_list.upper, list) - __netdev_adjacent_dev_unlink(i->dev, j->dev, i->ref_nr); - - /* remove also the devices itself from lower/upper device - * list - */ - list_for_each_entry(i, &dev->all_adj_list.lower, list) - __netdev_adjacent_dev_unlink(i->dev, upper_dev, i->ref_nr); - - list_for_each_entry(i, &upper_dev->all_adj_list.upper, list) - __netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr); - - call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev, - &changeupper_info.info); -} -EXPORT_SYMBOL(netdev_upper_dev_unlink); - -/** - * netdev_bonding_info_change - Dispatch event about slave change - * @dev: device - * @bonding_info: info to dispatch - * - * Send NETDEV_BONDING_INFO to netdev notifiers with info. - * The caller must hold the RTNL lock. - */ -void netdev_bonding_info_change(struct net_device *dev, - struct netdev_bonding_info *bonding_info) -{ - struct netdev_notifier_bonding_info info; - - memcpy(&info.bonding_info, bonding_info, - sizeof(struct netdev_bonding_info)); - call_netdevice_notifiers_info(NETDEV_BONDING_INFO, dev, - &info.info); -} -EXPORT_SYMBOL(netdev_bonding_info_change); - -static void netdev_adjacent_add_links(struct net_device *dev) -{ - struct netdev_adjacent *iter; - - struct net *net = dev_net(dev); - - list_for_each_entry(iter, &dev->adj_list.upper, list) { - if (!net_eq(net, dev_net(iter->dev))) - continue; - netdev_adjacent_sysfs_add(iter->dev, dev, - &iter->dev->adj_list.lower); - netdev_adjacent_sysfs_add(dev, iter->dev, - &dev->adj_list.upper); - } - - list_for_each_entry(iter, &dev->adj_list.lower, list) { - if (!net_eq(net, dev_net(iter->dev))) - continue; - netdev_adjacent_sysfs_add(iter->dev, dev, - &iter->dev->adj_list.upper); - netdev_adjacent_sysfs_add(dev, iter->dev, - &dev->adj_list.lower); - } -} - -static void netdev_adjacent_del_links(struct net_device *dev) -{ - struct netdev_adjacent *iter; - - struct net *net = dev_net(dev); - - list_for_each_entry(iter, &dev->adj_list.upper, list) { - if (!net_eq(net, dev_net(iter->dev))) - continue; - netdev_adjacent_sysfs_del(iter->dev, dev->name, - &iter->dev->adj_list.lower); - netdev_adjacent_sysfs_del(dev, iter->dev->name, - &dev->adj_list.upper); - } - - list_for_each_entry(iter, &dev->adj_list.lower, list) { - if (!net_eq(net, dev_net(iter->dev))) - continue; - netdev_adjacent_sysfs_del(iter->dev, dev->name, - &iter->dev->adj_list.upper); - netdev_adjacent_sysfs_del(dev, iter->dev->name, - &dev->adj_list.lower); - } -} - -void netdev_adjacent_rename_links(struct net_device *dev, char *oldname) -{ - struct netdev_adjacent *iter; - - struct net *net = dev_net(dev); - - list_for_each_entry(iter, &dev->adj_list.upper, list) { - if (!net_eq(net, dev_net(iter->dev))) - continue; - netdev_adjacent_sysfs_del(iter->dev, oldname, - &iter->dev->adj_list.lower); - netdev_adjacent_sysfs_add(iter->dev, dev, - &iter->dev->adj_list.lower); - } - - list_for_each_entry(iter, &dev->adj_list.lower, list) { - if (!net_eq(net, dev_net(iter->dev))) - continue; - netdev_adjacent_sysfs_del(iter->dev, oldname, - &iter->dev->adj_list.upper); - netdev_adjacent_sysfs_add(iter->dev, dev, - &iter->dev->adj_list.upper); - } -} - -void *netdev_lower_dev_get_private(struct net_device *dev, - struct net_device *lower_dev) -{ - struct netdev_adjacent *lower; - - if (!lower_dev) - return NULL; - lower = __netdev_find_adj(lower_dev, &dev->adj_list.lower); - if (!lower) - return NULL; - - return lower->private; -} -EXPORT_SYMBOL(netdev_lower_dev_get_private); - - -int dev_get_nest_level(struct net_device *dev) -{ - struct net_device *lower = NULL; - struct list_head *iter; - int max_nest = -1; - int nest; - - ASSERT_RTNL(); - - netdev_for_each_lower_dev(dev, lower, iter) { - nest = dev_get_nest_level(lower); - if (max_nest < nest) - max_nest = nest; - } - - return max_nest + 1; -} -EXPORT_SYMBOL(dev_get_nest_level); - -/** - * netdev_lower_change - Dispatch event about lower device state change - * @lower_dev: device - * @lower_state_info: state to dispatch - * - * Send NETDEV_CHANGELOWERSTATE to netdev notifiers with info. - * The caller must hold the RTNL lock. - */ -void netdev_lower_state_changed(struct net_device *lower_dev, - void *lower_state_info) -{ - struct netdev_notifier_changelowerstate_info changelowerstate_info; - - ASSERT_RTNL(); - changelowerstate_info.lower_state_info = lower_state_info; - call_netdevice_notifiers_info(NETDEV_CHANGELOWERSTATE, lower_dev, - &changelowerstate_info.info); -} -EXPORT_SYMBOL(netdev_lower_state_changed); - -int netdev_default_l2upper_neigh_construct(struct net_device *dev, - struct neighbour *n) -{ - struct net_device *lower_dev, *stop_dev; - struct list_head *iter; - int err; - - netdev_for_each_lower_dev(dev, lower_dev, iter) { - if (!lower_dev->netdev_ops->ndo_neigh_construct) - continue; - err = lower_dev->netdev_ops->ndo_neigh_construct(lower_dev, n); - if (err) { - stop_dev = lower_dev; - goto rollback; - } - } - return 0; - -rollback: - netdev_for_each_lower_dev(dev, lower_dev, iter) { - if (lower_dev == stop_dev) - break; - if (!lower_dev->netdev_ops->ndo_neigh_destroy) - continue; - lower_dev->netdev_ops->ndo_neigh_destroy(lower_dev, n); - } - return err; -} -EXPORT_SYMBOL_GPL(netdev_default_l2upper_neigh_construct); - -void netdev_default_l2upper_neigh_destroy(struct net_device *dev, - struct neighbour *n) -{ - struct net_device *lower_dev; - struct list_head *iter; - - netdev_for_each_lower_dev(dev, lower_dev, iter) { - if (!lower_dev->netdev_ops->ndo_neigh_destroy) - continue; - lower_dev->netdev_ops->ndo_neigh_destroy(lower_dev, n); - } -} -EXPORT_SYMBOL_GPL(netdev_default_l2upper_neigh_destroy); - -static void dev_change_rx_flags(struct net_device *dev, int flags) -{ - const struct net_device_ops *ops = dev->netdev_ops; - - if (ops->ndo_change_rx_flags) - ops->ndo_change_rx_flags(dev, flags); -} - -static int __dev_set_promiscuity(struct net_device *dev, int inc, bool notify) -{ - unsigned int old_flags = dev->flags; - kuid_t uid; - kgid_t gid; - - ASSERT_RTNL(); - - dev->flags |= IFF_PROMISC; - dev->promiscuity += inc; - if (dev->promiscuity == 0) { - /* - * Avoid overflow. - * If inc causes overflow, untouch promisc and return error. - */ - if (inc < 0) - dev->flags &= ~IFF_PROMISC; - else { - dev->promiscuity -= inc; - pr_warn("%s: promiscuity touches roof, set promiscuity failed. promiscuity feature of device might be broken.\n", - dev->name); - return -EOVERFLOW; - } - } - if (dev->flags != old_flags) { - pr_info("device %s %s promiscuous mode\n", - dev->name, - dev->flags & IFF_PROMISC ? "entered" : "left"); - if (audit_enabled) { - current_uid_gid(&uid, &gid); - audit_log(current->audit_context, GFP_ATOMIC, - AUDIT_ANOM_PROMISCUOUS, - "dev=%s prom=%d old_prom=%d auid=%u uid=%u gid=%u ses=%u", - dev->name, (dev->flags & IFF_PROMISC), - (old_flags & IFF_PROMISC), - from_kuid(&init_user_ns, audit_get_loginuid(current)), - from_kuid(&init_user_ns, uid), - from_kgid(&init_user_ns, gid), - audit_get_sessionid(current)); - } - - dev_change_rx_flags(dev, IFF_PROMISC); - } - if (notify) - __dev_notify_flags(dev, old_flags, IFF_PROMISC); - return 0; -} - -/** - * dev_set_promiscuity - update promiscuity count on a device - * @dev: device - * @inc: modifier - * - * Add or remove promiscuity from a device. While the count in the device - * remains above zero the interface remains promiscuous. Once it hits zero - * the device reverts back to normal filtering operation. A negative inc - * value is used to drop promiscuity on the device. - * Return 0 if successful or a negative errno code on error. - */ -int dev_set_promiscuity(struct net_device *dev, int inc) -{ - unsigned int old_flags = dev->flags; - int err; - - err = __dev_set_promiscuity(dev, inc, true); - if (err < 0) - return err; - if (dev->flags != old_flags) - dev_set_rx_mode(dev); - return err; -} -EXPORT_SYMBOL(dev_set_promiscuity); - -static int __dev_set_allmulti(struct net_device *dev, int inc, bool notify) -{ - unsigned int old_flags = dev->flags, old_gflags = dev->gflags; - - ASSERT_RTNL(); - - dev->flags |= IFF_ALLMULTI; - dev->allmulti += inc; - if (dev->allmulti == 0) { - /* - * Avoid overflow. - * If inc causes overflow, untouch allmulti and return error. - */ - if (inc < 0) - dev->flags &= ~IFF_ALLMULTI; - else { - dev->allmulti -= inc; - pr_warn("%s: allmulti touches roof, set allmulti failed. allmulti feature of device might be broken.\n", - dev->name); - return -EOVERFLOW; - } - } - if (dev->flags ^ old_flags) { - dev_change_rx_flags(dev, IFF_ALLMULTI); - dev_set_rx_mode(dev); - if (notify) - __dev_notify_flags(dev, old_flags, - dev->gflags ^ old_gflags); - } - return 0; -} - -/** - * dev_set_allmulti - update allmulti count on a device - * @dev: device - * @inc: modifier - * - * Add or remove reception of all multicast frames to a device. While the - * count in the device remains above zero the interface remains listening - * to all interfaces. Once it hits zero the device reverts back to normal - * filtering operation. A negative @inc value is used to drop the counter - * when releasing a resource needing all multicasts. - * Return 0 if successful or a negative errno code on error. - */ - -int dev_set_allmulti(struct net_device *dev, int inc) -{ - return __dev_set_allmulti(dev, inc, true); -} -EXPORT_SYMBOL(dev_set_allmulti); - -/* - * Upload unicast and multicast address lists to device and - * configure RX filtering. When the device doesn't support unicast - * filtering it is put in promiscuous mode while unicast addresses - * are present. - */ -void __dev_set_rx_mode(struct net_device *dev) -{ - const struct net_device_ops *ops = dev->netdev_ops; - - /* dev_open will call this function so the list will stay sane. */ - if (!(dev->flags&IFF_UP)) - return; - - if (!netif_device_present(dev)) - return; - - if (!(dev->priv_flags & IFF_UNICAST_FLT)) { - /* Unicast addresses changes may only happen under the rtnl, - * therefore calling __dev_set_promiscuity here is safe. - */ - if (!netdev_uc_empty(dev) && !dev->uc_promisc) { - __dev_set_promiscuity(dev, 1, false); - dev->uc_promisc = true; - } else if (netdev_uc_empty(dev) && dev->uc_promisc) { - __dev_set_promiscuity(dev, -1, false); - dev->uc_promisc = false; - } - } - - if (ops->ndo_set_rx_mode) - ops->ndo_set_rx_mode(dev); -} - -void dev_set_rx_mode(struct net_device *dev) -{ - netif_addr_lock_bh(dev); - __dev_set_rx_mode(dev); - netif_addr_unlock_bh(dev); -} - -/** - * dev_get_flags - get flags reported to userspace - * @dev: device - * - * Get the combination of flag bits exported through APIs to userspace. - */ -unsigned int dev_get_flags(const struct net_device *dev) -{ - unsigned int flags; - - flags = (dev->flags & ~(IFF_PROMISC | - IFF_ALLMULTI | - IFF_RUNNING | - IFF_LOWER_UP | - IFF_DORMANT)) | - (dev->gflags & (IFF_PROMISC | - IFF_ALLMULTI)); - - if (netif_running(dev)) { - if (netif_oper_up(dev)) - flags |= IFF_RUNNING; - if (netif_carrier_ok(dev)) - flags |= IFF_LOWER_UP; - if (netif_dormant(dev)) - flags |= IFF_DORMANT; - } - - return flags; -} -EXPORT_SYMBOL(dev_get_flags); - -int __dev_change_flags(struct net_device *dev, unsigned int flags) -{ - unsigned int old_flags = dev->flags; - int ret; - - ASSERT_RTNL(); - - /* - * Set the flags on our device. - */ - - dev->flags = (flags & (IFF_DEBUG | IFF_NOTRAILERS | IFF_NOARP | - IFF_DYNAMIC | IFF_MULTICAST | IFF_PORTSEL | - IFF_AUTOMEDIA)) | - (dev->flags & (IFF_UP | IFF_VOLATILE | IFF_PROMISC | - IFF_ALLMULTI)); - - /* - * Load in the correct multicast list now the flags have changed. - */ - - if ((old_flags ^ flags) & IFF_MULTICAST) - dev_change_rx_flags(dev, IFF_MULTICAST); - - dev_set_rx_mode(dev); - - /* - * Have we downed the interface. We handle IFF_UP ourselves - * according to user attempts to set it, rather than blindly - * setting it. - */ - - ret = 0; - if ((old_flags ^ flags) & IFF_UP) - ret = ((old_flags & IFF_UP) ? __dev_close : __dev_open)(dev); - - if ((flags ^ dev->gflags) & IFF_PROMISC) { - int inc = (flags & IFF_PROMISC) ? 1 : -1; - unsigned int old_flags = dev->flags; - - dev->gflags ^= IFF_PROMISC; - - if (__dev_set_promiscuity(dev, inc, false) >= 0) - if (dev->flags != old_flags) - dev_set_rx_mode(dev); - } - - /* NOTE: order of synchronization of IFF_PROMISC and IFF_ALLMULTI - is important. Some (broken) drivers set IFF_PROMISC, when - IFF_ALLMULTI is requested not asking us and not reporting. - */ - if ((flags ^ dev->gflags) & IFF_ALLMULTI) { - int inc = (flags & IFF_ALLMULTI) ? 1 : -1; - - dev->gflags ^= IFF_ALLMULTI; - __dev_set_allmulti(dev, inc, false); - } - - return ret; -} - -void __dev_notify_flags(struct net_device *dev, unsigned int old_flags, - unsigned int gchanges) -{ - unsigned int changes = dev->flags ^ old_flags; - - if (gchanges) - rtmsg_ifinfo(RTM_NEWLINK, dev, gchanges, GFP_ATOMIC); - - if (changes & IFF_UP) { - if (dev->flags & IFF_UP) - call_netdevice_notifiers(NETDEV_UP, dev); - else - call_netdevice_notifiers(NETDEV_DOWN, dev); - } - - if (dev->flags & IFF_UP && - (changes & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI | IFF_VOLATILE))) { - struct netdev_notifier_change_info change_info; - - change_info.flags_changed = changes; - call_netdevice_notifiers_info(NETDEV_CHANGE, dev, - &change_info.info); - } -} - -/** - * dev_change_flags - change device settings - * @dev: device - * @flags: device state flags - * - * Change settings on device based state flags. The flags are - * in the userspace exported format. - */ -int dev_change_flags(struct net_device *dev, unsigned int flags) -{ - int ret; - unsigned int changes, old_flags = dev->flags, old_gflags = dev->gflags; - - ret = __dev_change_flags(dev, flags); - if (ret < 0) - return ret; - - changes = (old_flags ^ dev->flags) | (old_gflags ^ dev->gflags); - __dev_notify_flags(dev, old_flags, changes); - return ret; -} -EXPORT_SYMBOL(dev_change_flags); - -static int __dev_set_mtu(struct net_device *dev, int new_mtu) -{ - const struct net_device_ops *ops = dev->netdev_ops; - - if (ops->ndo_change_mtu) - return ops->ndo_change_mtu(dev, new_mtu); - - dev->mtu = new_mtu; - return 0; -} - -/** - * dev_set_mtu - Change maximum transfer unit - * @dev: device - * @new_mtu: new transfer unit - * - * Change the maximum transfer size of the network device. - */ -int dev_set_mtu(struct net_device *dev, int new_mtu) -{ - int err, orig_mtu; - - if (new_mtu == dev->mtu) - return 0; - - /* MTU must be positive. */ - if (new_mtu < 0) - return -EINVAL; - - if (!netif_device_present(dev)) - return -ENODEV; - - err = call_netdevice_notifiers(NETDEV_PRECHANGEMTU, dev); - err = notifier_to_errno(err); - if (err) - return err; - - orig_mtu = dev->mtu; - err = __dev_set_mtu(dev, new_mtu); - - if (!err) { - err = call_netdevice_notifiers(NETDEV_CHANGEMTU, dev); - err = notifier_to_errno(err); - if (err) { - /* setting mtu back and notifying everyone again, - * so that they have a chance to revert changes. - */ - __dev_set_mtu(dev, orig_mtu); - call_netdevice_notifiers(NETDEV_CHANGEMTU, dev); - } - } - return err; -} -EXPORT_SYMBOL(dev_set_mtu); - -/** - * dev_set_group - Change group this device belongs to - * @dev: device - * @new_group: group this device should belong to - */ -void dev_set_group(struct net_device *dev, int new_group) -{ - dev->group = new_group; -} -EXPORT_SYMBOL(dev_set_group); - -/** - * dev_set_mac_address - Change Media Access Control Address - * @dev: device - * @sa: new address - * - * Change the hardware (MAC) address of the device - */ -int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa) -{ - const struct net_device_ops *ops = dev->netdev_ops; - int err; - - if (!ops->ndo_set_mac_address) - return -EOPNOTSUPP; - if (sa->sa_family != dev->type) - return -EINVAL; - if (!netif_device_present(dev)) - return -ENODEV; - err = ops->ndo_set_mac_address(dev, sa); - if (err) - return err; - dev->addr_assign_type = NET_ADDR_SET; - call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); - add_device_randomness(dev->dev_addr, dev->addr_len); - return 0; -} -EXPORT_SYMBOL(dev_set_mac_address); - -/** - * dev_change_carrier - Change device carrier - * @dev: device - * @new_carrier: new value - * - * Change device carrier - */ -int dev_change_carrier(struct net_device *dev, bool new_carrier) -{ - const struct net_device_ops *ops = dev->netdev_ops; - - if (!ops->ndo_change_carrier) - return -EOPNOTSUPP; - if (!netif_device_present(dev)) - return -ENODEV; - return ops->ndo_change_carrier(dev, new_carrier); -} -EXPORT_SYMBOL(dev_change_carrier); - -/** - * dev_get_phys_port_id - Get device physical port ID - * @dev: device - * @ppid: port ID - * - * Get device physical port ID - */ -int dev_get_phys_port_id(struct net_device *dev, - struct netdev_phys_item_id *ppid) -{ - const struct net_device_ops *ops = dev->netdev_ops; - - if (!ops->ndo_get_phys_port_id) - return -EOPNOTSUPP; - return ops->ndo_get_phys_port_id(dev, ppid); -} -EXPORT_SYMBOL(dev_get_phys_port_id); - -/** - * dev_get_phys_port_name - Get device physical port name - * @dev: device - * @name: port name - * @len: limit of bytes to copy to name - * - * Get device physical port name - */ -int dev_get_phys_port_name(struct net_device *dev, - char *name, size_t len) -{ - const struct net_device_ops *ops = dev->netdev_ops; - - if (!ops->ndo_get_phys_port_name) - return -EOPNOTSUPP; - return ops->ndo_get_phys_port_name(dev, name, len); -} -EXPORT_SYMBOL(dev_get_phys_port_name); - -/** - * dev_change_proto_down - update protocol port state information - * @dev: device - * @proto_down: new value - * - * This info can be used by switch drivers to set the phys state of the - * port. - */ -int dev_change_proto_down(struct net_device *dev, bool proto_down) -{ - const struct net_device_ops *ops = dev->netdev_ops; - - if (!ops->ndo_change_proto_down) - return -EOPNOTSUPP; - if (!netif_device_present(dev)) - return -ENODEV; - return ops->ndo_change_proto_down(dev, proto_down); -} -EXPORT_SYMBOL(dev_change_proto_down); - -/** - * dev_change_xdp_fd - set or clear a bpf program for a device rx path - * @dev: device - * @fd: new program fd or negative value to clear - * - * Set or clear a bpf program for a device - */ -int dev_change_xdp_fd(struct net_device *dev, int fd) -{ - const struct net_device_ops *ops = dev->netdev_ops; - struct bpf_prog *prog = NULL; - struct netdev_xdp xdp = {}; - int err; - - if (!ops->ndo_xdp) - return -EOPNOTSUPP; - if (fd >= 0) { - prog = bpf_prog_get_type(fd, BPF_PROG_TYPE_XDP); - if (IS_ERR(prog)) - return PTR_ERR(prog); - } - - xdp.command = XDP_SETUP_PROG; - xdp.prog = prog; - err = ops->ndo_xdp(dev, &xdp); - if (err < 0 && prog) - bpf_prog_put(prog); - - return err; -} -EXPORT_SYMBOL(dev_change_xdp_fd); - -/** - * dev_new_index - allocate an ifindex - * @net: the applicable net namespace - * - * Returns a suitable unique value for a new device interface - * number. The caller must hold the rtnl semaphore or the - * dev_base_lock to be sure it remains unique. - */ -static int dev_new_index(struct net *net) -{ - int ifindex = net->ifindex; - for (;;) { - if (++ifindex <= 0) - ifindex = 1; - if (!__dev_get_by_index(net, ifindex)) - return net->ifindex = ifindex; - } -} - -/* Delayed registration/unregisteration */ -static LIST_HEAD(net_todo_list); -DECLARE_WAIT_QUEUE_HEAD(netdev_unregistering_wq); - -static void net_set_todo(struct net_device *dev) -{ - list_add_tail(&dev->todo_list, &net_todo_list); - dev_net(dev)->dev_unreg_count++; -} - -static void rollback_registered_many(struct list_head *head) -{ - struct net_device *dev, *tmp; - LIST_HEAD(close_head); - - BUG_ON(dev_boot_phase); - ASSERT_RTNL(); - - list_for_each_entry_safe(dev, tmp, head, unreg_list) { - /* Some devices call without registering - * for initialization unwind. Remove those - * devices and proceed with the remaining. - */ - if (dev->reg_state == NETREG_UNINITIALIZED) { - pr_debug("unregister_netdevice: device %s/%p never was registered\n", - dev->name, dev); - - WARN_ON(1); - list_del(&dev->unreg_list); - continue; - } - dev->dismantle = true; - BUG_ON(dev->reg_state != NETREG_REGISTERED); - } - - /* If device is running, close it first. */ - list_for_each_entry(dev, head, unreg_list) - list_add_tail(&dev->close_list, &close_head); - dev_close_many(&close_head, true); - - list_for_each_entry(dev, head, unreg_list) { - /* And unlink it from device chain. */ - unlist_netdevice(dev); - - dev->reg_state = NETREG_UNREGISTERING; - } - flush_all_backlogs(); - - synchronize_net(); - - list_for_each_entry(dev, head, unreg_list) { - struct sk_buff *skb = NULL; - - /* Shutdown queueing discipline. */ - dev_shutdown(dev); - - - /* Notify protocols, that we are about to destroy - this device. They should clean all the things. - */ - call_netdevice_notifiers(NETDEV_UNREGISTER, dev); - - if (!dev->rtnl_link_ops || - dev->rtnl_link_state == RTNL_LINK_INITIALIZED) - skb = rtmsg_ifinfo_build_skb(RTM_DELLINK, dev, ~0U, - GFP_KERNEL); - - /* - * Flush the unicast and multicast chains - */ - dev_uc_flush(dev); - dev_mc_flush(dev); - - if (dev->netdev_ops->ndo_uninit) - dev->netdev_ops->ndo_uninit(dev); - - if (skb) - rtmsg_ifinfo_send(skb, dev, GFP_KERNEL); - - /* Notifier chain MUST detach us all upper devices. */ - WARN_ON(netdev_has_any_upper_dev(dev)); - - /* Remove entries from kobject tree */ - netdev_unregister_kobject(dev); -#ifdef CONFIG_XPS - /* Remove XPS queueing entries */ - netif_reset_xps_queues_gt(dev, 0); -#endif - } - - synchronize_net(); - - list_for_each_entry(dev, head, unreg_list) - dev_put(dev); -} - -static void rollback_registered(struct net_device *dev) -{ - LIST_HEAD(single); - - list_add(&dev->unreg_list, &single); - rollback_registered_many(&single); - list_del(&single); -} - -static netdev_features_t netdev_sync_upper_features(struct net_device *lower, - struct net_device *upper, netdev_features_t features) -{ - netdev_features_t upper_disables = NETIF_F_UPPER_DISABLES; - netdev_features_t feature; - int feature_bit; - - for_each_netdev_feature(&upper_disables, feature_bit) { - feature = __NETIF_F_BIT(feature_bit); - if (!(upper->wanted_features & feature) - && (features & feature)) { - netdev_dbg(lower, "Dropping feature %pNF, upper dev %s has it off.\n", - &feature, upper->name); - features &= ~feature; - } - } - - return features; -} - -static void netdev_sync_lower_features(struct net_device *upper, - struct net_device *lower, netdev_features_t features) -{ - netdev_features_t upper_disables = NETIF_F_UPPER_DISABLES; - netdev_features_t feature; - int feature_bit; - - for_each_netdev_feature(&upper_disables, feature_bit) { - feature = __NETIF_F_BIT(feature_bit); - if (!(features & feature) && (lower->features & feature)) { - netdev_dbg(upper, "Disabling feature %pNF on lower dev %s.\n", - &feature, lower->name); - lower->wanted_features &= ~feature; - netdev_update_features(lower); - - if (unlikely(lower->features & feature)) - netdev_WARN(upper, "failed to disable %pNF on %s!\n", - &feature, lower->name); - } - } -} - -static netdev_features_t netdev_fix_features(struct net_device *dev, - netdev_features_t features) -{ - /* Fix illegal checksum combinations */ - if ((features & NETIF_F_HW_CSUM) && - (features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) { - netdev_warn(dev, "mixed HW and IP checksum settings.\n"); - features &= ~(NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM); - } - - /* TSO requires that SG is present as well. */ - if ((features & NETIF_F_ALL_TSO) && !(features & NETIF_F_SG)) { - netdev_dbg(dev, "Dropping TSO features since no SG feature.\n"); - features &= ~NETIF_F_ALL_TSO; - } - - if ((features & NETIF_F_TSO) && !(features & NETIF_F_HW_CSUM) && - !(features & NETIF_F_IP_CSUM)) { - netdev_dbg(dev, "Dropping TSO features since no CSUM feature.\n"); - features &= ~NETIF_F_TSO; - features &= ~NETIF_F_TSO_ECN; - } - - if ((features & NETIF_F_TSO6) && !(features & NETIF_F_HW_CSUM) && - !(features & NETIF_F_IPV6_CSUM)) { - netdev_dbg(dev, "Dropping TSO6 features since no CSUM feature.\n"); - features &= ~NETIF_F_TSO6; - } - - /* TSO with IPv4 ID mangling requires IPv4 TSO be enabled */ - if ((features & NETIF_F_TSO_MANGLEID) && !(features & NETIF_F_TSO)) - features &= ~NETIF_F_TSO_MANGLEID; - - /* TSO ECN requires that TSO is present as well. */ - if ((features & NETIF_F_ALL_TSO) == NETIF_F_TSO_ECN) - features &= ~NETIF_F_TSO_ECN; - - /* Software GSO depends on SG. */ - if ((features & NETIF_F_GSO) && !(features & NETIF_F_SG)) { - netdev_dbg(dev, "Dropping NETIF_F_GSO since no SG feature.\n"); - features &= ~NETIF_F_GSO; - } - - /* UFO needs SG and checksumming */ - if (features & NETIF_F_UFO) { - /* maybe split UFO into V4 and V6? */ - if (!(features & NETIF_F_HW_CSUM) && - ((features & (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM)) != - (NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM))) { - netdev_dbg(dev, - "Dropping NETIF_F_UFO since no checksum offload features.\n"); - features &= ~NETIF_F_UFO; - } - - if (!(features & NETIF_F_SG)) { - netdev_dbg(dev, - "Dropping NETIF_F_UFO since no NETIF_F_SG feature.\n"); - features &= ~NETIF_F_UFO; - } - } - - /* GSO partial features require GSO partial be set */ - if ((features & dev->gso_partial_features) && - !(features & NETIF_F_GSO_PARTIAL)) { - netdev_dbg(dev, - "Dropping partially supported GSO features since no GSO partial.\n"); - features &= ~dev->gso_partial_features; - } - -#ifdef CONFIG_NET_RX_BUSY_POLL - if (dev->netdev_ops->ndo_busy_poll) - features |= NETIF_F_BUSY_POLL; - else -#endif - features &= ~NETIF_F_BUSY_POLL; - - return features; -} - -int __netdev_update_features(struct net_device *dev) -{ - struct net_device *upper, *lower; - netdev_features_t features; - struct list_head *iter; - int err = -1; - - ASSERT_RTNL(); - - features = netdev_get_wanted_features(dev); - - if (dev->netdev_ops->ndo_fix_features) - features = dev->netdev_ops->ndo_fix_features(dev, features); - - /* driver might be less strict about feature dependencies */ - features = netdev_fix_features(dev, features); - - /* some features can't be enabled if they're off an an upper device */ - netdev_for_each_upper_dev_rcu(dev, upper, iter) - features = netdev_sync_upper_features(dev, upper, features); - - if (dev->features == features) - goto sync_lower; - - netdev_dbg(dev, "Features changed: %pNF -> %pNF\n", - &dev->features, &features); - - if (dev->netdev_ops->ndo_set_features) - err = dev->netdev_ops->ndo_set_features(dev, features); - else - err = 0; - - if (unlikely(err < 0)) { - netdev_err(dev, - "set_features() failed (%d); wanted %pNF, left %pNF\n", - err, &features, &dev->features); - /* return non-0 since some features might have changed and - * it's better to fire a spurious notification than miss it - */ - return -1; - } - -sync_lower: - /* some features must be disabled on lower devices when disabled - * on an upper device (think: bonding master or bridge) - */ - netdev_for_each_lower_dev(dev, lower, iter) - netdev_sync_lower_features(dev, lower, features); - - if (!err) - dev->features = features; - - return err < 0 ? 0 : 1; -} - -/** - * netdev_update_features - recalculate device features - * @dev: the device to check - * - * Recalculate dev->features set and send notifications if it - * has changed. Should be called after driver or hardware dependent - * conditions might have changed that influence the features. - */ -void netdev_update_features(struct net_device *dev) -{ - if (__netdev_update_features(dev)) - netdev_features_change(dev); -} -EXPORT_SYMBOL(netdev_update_features); - -/** - * netdev_change_features - recalculate device features - * @dev: the device to check - * - * Recalculate dev->features set and send notifications even - * if they have not changed. Should be called instead of - * netdev_update_features() if also dev->vlan_features might - * have changed to allow the changes to be propagated to stacked - * VLAN devices. - */ -void netdev_change_features(struct net_device *dev) -{ - __netdev_update_features(dev); - netdev_features_change(dev); -} -EXPORT_SYMBOL(netdev_change_features); - -/** - * netif_stacked_transfer_operstate - transfer operstate - * @rootdev: the root or lower level device to transfer state from - * @dev: the device to transfer operstate to - * - * Transfer operational state from root to device. This is normally - * called when a stacking relationship exists between the root - * device and the device(a leaf device). - */ -void netif_stacked_transfer_operstate(const struct net_device *rootdev, - struct net_device *dev) -{ - if (rootdev->operstate == IF_OPER_DORMANT) - netif_dormant_on(dev); - else - netif_dormant_off(dev); - - if (netif_carrier_ok(rootdev)) { - if (!netif_carrier_ok(dev)) - netif_carrier_on(dev); - } else { - if (netif_carrier_ok(dev)) - netif_carrier_off(dev); - } -} -EXPORT_SYMBOL(netif_stacked_transfer_operstate); - -#ifdef CONFIG_SYSFS -static int netif_alloc_rx_queues(struct net_device *dev) -{ - unsigned int i, count = dev->num_rx_queues; - struct netdev_rx_queue *rx; - size_t sz = count * sizeof(*rx); - - BUG_ON(count < 1); - - rx = kzalloc(sz, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT); - if (!rx) { - rx = vzalloc(sz); - if (!rx) - return -ENOMEM; - } - dev->_rx = rx; - - for (i = 0; i < count; i++) - rx[i].dev = dev; - return 0; -} -#endif - -static void netdev_init_one_queue(struct net_device *dev, - struct netdev_queue *queue, void *_unused) -{ - /* Initialize queue lock */ - spin_lock_init(&queue->_xmit_lock); - netdev_set_xmit_lockdep_class(&queue->_xmit_lock, dev->type); - queue->xmit_lock_owner = -1; - netdev_queue_numa_node_write(queue, NUMA_NO_NODE); - queue->dev = dev; -#ifdef CONFIG_BQL - dql_init(&queue->dql, HZ); -#endif -} - -static void netif_free_tx_queues(struct net_device *dev) -{ - kvfree(dev->_tx); -} - -static int netif_alloc_netdev_queues(struct net_device *dev) -{ - unsigned int count = dev->num_tx_queues; - struct netdev_queue *tx; - size_t sz = count * sizeof(*tx); - - if (count < 1 || count > 0xffff) - return -EINVAL; - - tx = kzalloc(sz, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT); - if (!tx) { - tx = vzalloc(sz); - if (!tx) - return -ENOMEM; - } - dev->_tx = tx; - - netdev_for_each_tx_queue(dev, netdev_init_one_queue, NULL); - spin_lock_init(&dev->tx_global_lock); - - return 0; -} - -void netif_tx_stop_all_queues(struct net_device *dev) -{ - unsigned int i; - - for (i = 0; i < dev->num_tx_queues; i++) { - struct netdev_queue *txq = netdev_get_tx_queue(dev, i); - netif_tx_stop_queue(txq); - } -} -EXPORT_SYMBOL(netif_tx_stop_all_queues); - -/** - * register_netdevice - register a network device - * @dev: device to register - * - * Take a completed network device structure and add it to the kernel - * interfaces. A %NETDEV_REGISTER message is sent to the netdev notifier - * chain. 0 is returned on success. A negative errno code is returned - * on a failure to set up the device, or if the name is a duplicate. - * - * Callers must hold the rtnl semaphore. You may want - * register_netdev() instead of this. - * - * BUGS: - * The locking appears insufficient to guarantee two parallel registers - * will not get the same name. - */ - -int register_netdevice(struct net_device *dev) -{ - int ret; - struct net *net = dev_net(dev); - - BUG_ON(dev_boot_phase); - ASSERT_RTNL(); - - might_sleep(); - - /* When net_device's are persistent, this will be fatal. */ - BUG_ON(dev->reg_state != NETREG_UNINITIALIZED); - BUG_ON(!net); - - spin_lock_init(&dev->addr_list_lock); - netdev_set_addr_lockdep_class(dev); - - ret = dev_get_valid_name(net, dev, dev->name); - if (ret < 0) - goto out; - - /* Init, if this function is available */ - if (dev->netdev_ops->ndo_init) { - ret = dev->netdev_ops->ndo_init(dev); - if (ret) { - if (ret > 0) - ret = -EIO; - goto out; - } - } - - if (((dev->hw_features | dev->features) & - NETIF_F_HW_VLAN_CTAG_FILTER) && - (!dev->netdev_ops->ndo_vlan_rx_add_vid || - !dev->netdev_ops->ndo_vlan_rx_kill_vid)) { - netdev_WARN(dev, "Buggy VLAN acceleration in driver!\n"); - ret = -EINVAL; - goto err_uninit; - } - - ret = -EBUSY; - if (!dev->ifindex) - dev->ifindex = dev_new_index(net); - else if (__dev_get_by_index(net, dev->ifindex)) - goto err_uninit; - - /* Transfer changeable features to wanted_features and enable - * software offloads (GSO and GRO). - */ - dev->hw_features |= NETIF_F_SOFT_FEATURES; - dev->features |= NETIF_F_SOFT_FEATURES; - dev->wanted_features = dev->features & dev->hw_features; - - if (!(dev->flags & IFF_LOOPBACK)) - dev->hw_features |= NETIF_F_NOCACHE_COPY; - - /* If IPv4 TCP segmentation offload is supported we should also - * allow the device to enable segmenting the frame with the option - * of ignoring a static IP ID value. This doesn't enable the - * feature itself but allows the user to enable it later. - */ - if (dev->hw_features & NETIF_F_TSO) - dev->hw_features |= NETIF_F_TSO_MANGLEID; - if (dev->vlan_features & NETIF_F_TSO) - dev->vlan_features |= NETIF_F_TSO_MANGLEID; - if (dev->mpls_features & NETIF_F_TSO) - dev->mpls_features |= NETIF_F_TSO_MANGLEID; - if (dev->hw_enc_features & NETIF_F_TSO) - dev->hw_enc_features |= NETIF_F_TSO_MANGLEID; - - /* Make NETIF_F_HIGHDMA inheritable to VLAN devices. - */ - dev->vlan_features |= NETIF_F_HIGHDMA; - - /* Make NETIF_F_SG inheritable to tunnel devices. - */ - dev->hw_enc_features |= NETIF_F_SG | NETIF_F_GSO_PARTIAL; - - /* Make NETIF_F_SG inheritable to MPLS. - */ - dev->mpls_features |= NETIF_F_SG; - - ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev); - ret = notifier_to_errno(ret); - if (ret) - goto err_uninit; - - ret = netdev_register_kobject(dev); - if (ret) - goto err_uninit; - dev->reg_state = NETREG_REGISTERED; - - __netdev_update_features(dev); - - /* - * Default initial state at registry is that the - * device is present. - */ - - set_bit(__LINK_STATE_PRESENT, &dev->state); - - linkwatch_init_dev(dev); - - dev_init_scheduler(dev); - dev_hold(dev); - list_netdevice(dev); - add_device_randomness(dev->dev_addr, dev->addr_len); - - /* If the device has permanent device address, driver should - * set dev_addr and also addr_assign_type should be set to - * NET_ADDR_PERM (default value). - */ - if (dev->addr_assign_type == NET_ADDR_PERM) - memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - - /* Notify protocols, that a new device appeared. */ - ret = call_netdevice_notifiers(NETDEV_REGISTER, dev); - ret = notifier_to_errno(ret); - if (ret) { - rollback_registered(dev); - dev->reg_state = NETREG_UNREGISTERED; - } - /* - * Prevent userspace races by waiting until the network - * device is fully setup before sending notifications. - */ - if (!dev->rtnl_link_ops || - dev->rtnl_link_state == RTNL_LINK_INITIALIZED) - rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U, GFP_KERNEL); - -out: - return ret; - -err_uninit: - if (dev->netdev_ops->ndo_uninit) - dev->netdev_ops->ndo_uninit(dev); - goto out; -} -EXPORT_SYMBOL(register_netdevice); - -/** - * init_dummy_netdev - init a dummy network device for NAPI - * @dev: device to init - * - * This takes a network device structure and initialize the minimum - * amount of fields so it can be used to schedule NAPI polls without - * registering a full blown interface. This is to be used by drivers - * that need to tie several hardware interfaces to a single NAPI - * poll scheduler due to HW limitations. - */ -int init_dummy_netdev(struct net_device *dev) -{ - /* Clear everything. Note we don't initialize spinlocks - * are they aren't supposed to be taken by any of the - * NAPI code and this dummy netdev is supposed to be - * only ever used for NAPI polls - */ - memset(dev, 0, sizeof(struct net_device)); - - /* make sure we BUG if trying to hit standard - * register/unregister code path - */ - dev->reg_state = NETREG_DUMMY; - - /* NAPI wants this */ - INIT_LIST_HEAD(&dev->napi_list); - - /* a dummy interface is started by default */ - set_bit(__LINK_STATE_PRESENT, &dev->state); - set_bit(__LINK_STATE_START, &dev->state); - - /* Note : We dont allocate pcpu_refcnt for dummy devices, - * because users of this 'device' dont need to change - * its refcount. - */ - - return 0; -} -EXPORT_SYMBOL_GPL(init_dummy_netdev); - - -/** - * register_netdev - register a network device - * @dev: device to register - * - * Take a completed network device structure and add it to the kernel - * interfaces. A %NETDEV_REGISTER message is sent to the netdev notifier - * chain. 0 is returned on success. A negative errno code is returned - * on a failure to set up the device, or if the name is a duplicate. - * - * This is a wrapper around register_netdevice that takes the rtnl semaphore - * and expands the device name if you passed a format string to - * alloc_netdev. - */ -int register_netdev(struct net_device *dev) -{ - int err; - - rtnl_lock(); - err = register_netdevice(dev); - rtnl_unlock(); - return err; -} -EXPORT_SYMBOL(register_netdev); - -int netdev_refcnt_read(const struct net_device *dev) -{ - int i, refcnt = 0; - - for_each_possible_cpu(i) - refcnt += *per_cpu_ptr(dev->pcpu_refcnt, i); - return refcnt; -} -EXPORT_SYMBOL(netdev_refcnt_read); - -/** - * netdev_wait_allrefs - wait until all references are gone. - * @dev: target net_device - * - * This is called when unregistering network devices. - * - * Any protocol or device that holds a reference should register - * for netdevice notification, and cleanup and put back the - * reference if they receive an UNREGISTER event. - * We can get stuck here if buggy protocols don't correctly - * call dev_put. - */ -static void netdev_wait_allrefs(struct net_device *dev) -{ - unsigned long rebroadcast_time, warning_time; - int refcnt; - - linkwatch_forget_dev(dev); - - rebroadcast_time = warning_time = jiffies; - refcnt = netdev_refcnt_read(dev); - - while (refcnt != 0) { - if (time_after(jiffies, rebroadcast_time + 1 * HZ)) { - rtnl_lock(); - - /* Rebroadcast unregister notification */ - call_netdevice_notifiers(NETDEV_UNREGISTER, dev); - - __rtnl_unlock(); - rcu_barrier(); - rtnl_lock(); - - call_netdevice_notifiers(NETDEV_UNREGISTER_FINAL, dev); - if (test_bit(__LINK_STATE_LINKWATCH_PENDING, - &dev->state)) { - /* We must not have linkwatch events - * pending on unregister. If this - * happens, we simply run the queue - * unscheduled, resulting in a noop - * for this device. - */ - linkwatch_run_queue(); - } - - __rtnl_unlock(); - - rebroadcast_time = jiffies; - } - - msleep(250); - - refcnt = netdev_refcnt_read(dev); - - if (time_after(jiffies, warning_time + 10 * HZ)) { - pr_emerg("unregister_netdevice: waiting for %s to become free. Usage count = %d\n", - dev->name, refcnt); - warning_time = jiffies; - } - } -} - -/* The sequence is: - * - * rtnl_lock(); - * ... - * register_netdevice(x1); - * register_netdevice(x2); - * ... - * unregister_netdevice(y1); - * unregister_netdevice(y2); - * ... - * rtnl_unlock(); - * free_netdev(y1); - * free_netdev(y2); - * - * We are invoked by rtnl_unlock(). - * This allows us to deal with problems: - * 1) We can delete sysfs objects which invoke hotplug - * without deadlocking with linkwatch via keventd. - * 2) Since we run with the RTNL semaphore not held, we can sleep - * safely in order to wait for the netdev refcnt to drop to zero. - * - * We must not return until all unregister events added during - * the interval the lock was held have been completed. - */ -void netdev_run_todo(void) -{ - struct list_head list; - - /* Snapshot list, allow later requests */ - list_replace_init(&net_todo_list, &list); - - __rtnl_unlock(); - - - /* Wait for rcu callbacks to finish before next phase */ - if (!list_empty(&list)) - rcu_barrier(); - - while (!list_empty(&list)) { - struct net_device *dev - = list_first_entry(&list, struct net_device, todo_list); - list_del(&dev->todo_list); - - rtnl_lock(); - call_netdevice_notifiers(NETDEV_UNREGISTER_FINAL, dev); - __rtnl_unlock(); - - if (unlikely(dev->reg_state != NETREG_UNREGISTERING)) { - pr_err("network todo '%s' but state %d\n", - dev->name, dev->reg_state); - dump_stack(); - continue; - } - - dev->reg_state = NETREG_UNREGISTERED; - - netdev_wait_allrefs(dev); - - /* paranoia */ - BUG_ON(netdev_refcnt_read(dev)); - BUG_ON(!list_empty(&dev->ptype_all)); - BUG_ON(!list_empty(&dev->ptype_specific)); - WARN_ON(rcu_access_pointer(dev->ip_ptr)); - WARN_ON(rcu_access_pointer(dev->ip6_ptr)); - WARN_ON(dev->dn_ptr); - - if (dev->destructor) - dev->destructor(dev); - - /* Report a network device has been unregistered */ - rtnl_lock(); - dev_net(dev)->dev_unreg_count--; - __rtnl_unlock(); - wake_up(&netdev_unregistering_wq); - - /* Free network device */ - kobject_put(&dev->dev.kobj); - } -} - -/* Convert net_device_stats to rtnl_link_stats64. rtnl_link_stats64 has - * all the same fields in the same order as net_device_stats, with only - * the type differing, but rtnl_link_stats64 may have additional fields - * at the end for newer counters. - */ -void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64, - const struct net_device_stats *netdev_stats) -{ -#if BITS_PER_LONG == 64 - BUILD_BUG_ON(sizeof(*stats64) < sizeof(*netdev_stats)); - memcpy(stats64, netdev_stats, sizeof(*stats64)); - /* zero out counters that only exist in rtnl_link_stats64 */ - memset((char *)stats64 + sizeof(*netdev_stats), 0, - sizeof(*stats64) - sizeof(*netdev_stats)); -#else - size_t i, n = sizeof(*netdev_stats) / sizeof(unsigned long); - const unsigned long *src = (const unsigned long *)netdev_stats; - u64 *dst = (u64 *)stats64; - - BUILD_BUG_ON(n > sizeof(*stats64) / sizeof(u64)); - for (i = 0; i < n; i++) - dst[i] = src[i]; - /* zero out counters that only exist in rtnl_link_stats64 */ - memset((char *)stats64 + n * sizeof(u64), 0, - sizeof(*stats64) - n * sizeof(u64)); -#endif -} -EXPORT_SYMBOL(netdev_stats_to_stats64); - -/** - * dev_get_stats - get network device statistics - * @dev: device to get statistics from - * @storage: place to store stats - * - * Get network statistics from device. Return @storage. - * The device driver may provide its own method by setting - * dev->netdev_ops->get_stats64 or dev->netdev_ops->get_stats; - * otherwise the internal statistics structure is used. - */ -struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev, - struct rtnl_link_stats64 *storage) -{ - const struct net_device_ops *ops = dev->netdev_ops; - - if (ops->ndo_get_stats64) { - memset(storage, 0, sizeof(*storage)); - ops->ndo_get_stats64(dev, storage); - } else if (ops->ndo_get_stats) { - netdev_stats_to_stats64(storage, ops->ndo_get_stats(dev)); - } else { - netdev_stats_to_stats64(storage, &dev->stats); - } - storage->rx_dropped += atomic_long_read(&dev->rx_dropped); - storage->tx_dropped += atomic_long_read(&dev->tx_dropped); - storage->rx_nohandler += atomic_long_read(&dev->rx_nohandler); - return storage; -} -EXPORT_SYMBOL(dev_get_stats); - -struct netdev_queue *dev_ingress_queue_create(struct net_device *dev) -{ - struct netdev_queue *queue = dev_ingress_queue(dev); - -#ifdef CONFIG_NET_CLS_ACT - if (queue) - return queue; - queue = kzalloc(sizeof(*queue), GFP_KERNEL); - if (!queue) - return NULL; - netdev_init_one_queue(dev, queue, NULL); - RCU_INIT_POINTER(queue->qdisc, &noop_qdisc); - queue->qdisc_sleeping = &noop_qdisc; - rcu_assign_pointer(dev->ingress_queue, queue); -#endif - return queue; -} - -static const struct ethtool_ops default_ethtool_ops; - -void netdev_set_default_ethtool_ops(struct net_device *dev, - const struct ethtool_ops *ops) -{ - if (dev->ethtool_ops == &default_ethtool_ops) - dev->ethtool_ops = ops; -} -EXPORT_SYMBOL_GPL(netdev_set_default_ethtool_ops); - -void netdev_freemem(struct net_device *dev) -{ - char *addr = (char *)dev - dev->padded; - - kvfree(addr); -} - -/** - * alloc_netdev_mqs - allocate network device - * @sizeof_priv: size of private data to allocate space for - * @name: device name format string - * @name_assign_type: origin of device name - * @setup: callback to initialize device - * @txqs: the number of TX subqueues to allocate - * @rxqs: the number of RX subqueues to allocate - * - * Allocates a struct net_device with private data area for driver use - * and performs basic initialization. Also allocates subqueue structs - * for each queue on the device. - */ -struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name, - unsigned char name_assign_type, - void (*setup)(struct net_device *), - unsigned int txqs, unsigned int rxqs) -{ - struct net_device *dev; - size_t alloc_size; - struct net_device *p; - - BUG_ON(strlen(name) >= sizeof(dev->name)); - - if (txqs < 1) { - pr_err("alloc_netdev: Unable to allocate device with zero queues\n"); - return NULL; - } - -#ifdef CONFIG_SYSFS - if (rxqs < 1) { - pr_err("alloc_netdev: Unable to allocate device with zero RX queues\n"); - return NULL; - } -#endif - - alloc_size = sizeof(struct net_device); - if (sizeof_priv) { - /* ensure 32-byte alignment of private area */ - alloc_size = ALIGN(alloc_size, NETDEV_ALIGN); - alloc_size += sizeof_priv; - } - /* ensure 32-byte alignment of whole construct */ - alloc_size += NETDEV_ALIGN - 1; - - p = kzalloc(alloc_size, GFP_KERNEL | __GFP_NOWARN | __GFP_REPEAT); - if (!p) - p = vzalloc(alloc_size); - if (!p) - return NULL; - - dev = PTR_ALIGN(p, NETDEV_ALIGN); - dev->padded = (char *)dev - (char *)p; - - dev->pcpu_refcnt = alloc_percpu(int); - if (!dev->pcpu_refcnt) - goto free_dev; - - if (dev_addr_init(dev)) - goto free_pcpu; - - dev_mc_init(dev); - dev_uc_init(dev); - - dev_net_set(dev, &init_net); - - dev->gso_max_size = GSO_MAX_SIZE; - dev->gso_max_segs = GSO_MAX_SEGS; - - INIT_LIST_HEAD(&dev->napi_list); - INIT_LIST_HEAD(&dev->unreg_list); - INIT_LIST_HEAD(&dev->close_list); - INIT_LIST_HEAD(&dev->link_watch_list); - INIT_LIST_HEAD(&dev->adj_list.upper); - INIT_LIST_HEAD(&dev->adj_list.lower); - INIT_LIST_HEAD(&dev->all_adj_list.upper); - INIT_LIST_HEAD(&dev->all_adj_list.lower); - INIT_LIST_HEAD(&dev->ptype_all); - INIT_LIST_HEAD(&dev->ptype_specific); -#ifdef CONFIG_NET_SCHED - hash_init(dev->qdisc_hash); -#endif - dev->priv_flags = IFF_XMIT_DST_RELEASE | IFF_XMIT_DST_RELEASE_PERM; - setup(dev); - - if (!dev->tx_queue_len) { - dev->priv_flags |= IFF_NO_QUEUE; - dev->tx_queue_len = 1; - } - - dev->num_tx_queues = txqs; - dev->real_num_tx_queues = txqs; - if (netif_alloc_netdev_queues(dev)) - goto free_all; - -#ifdef CONFIG_SYSFS - dev->num_rx_queues = rxqs; - dev->real_num_rx_queues = rxqs; - if (netif_alloc_rx_queues(dev)) - goto free_all; -#endif - - strcpy(dev->name, name); - dev->name_assign_type = name_assign_type; - dev->group = INIT_NETDEV_GROUP; - if (!dev->ethtool_ops) - dev->ethtool_ops = &default_ethtool_ops; - - nf_hook_ingress_init(dev); - - return dev; - -free_all: - free_netdev(dev); - return NULL; - -free_pcpu: - free_percpu(dev->pcpu_refcnt); -free_dev: - netdev_freemem(dev); - return NULL; -} -EXPORT_SYMBOL(alloc_netdev_mqs); - -/** - * free_netdev - free network device - * @dev: device - * - * This function does the last stage of destroying an allocated device - * interface. The reference to the device object is released. - * If this is the last reference then it will be freed. - * Must be called in process context. - */ -void free_netdev(struct net_device *dev) -{ - struct napi_struct *p, *n; - - might_sleep(); - netif_free_tx_queues(dev); -#ifdef CONFIG_SYSFS - kvfree(dev->_rx); -#endif - - kfree(rcu_dereference_protected(dev->ingress_queue, 1)); - - /* Flush device addresses */ - dev_addr_flush(dev); - - list_for_each_entry_safe(p, n, &dev->napi_list, dev_list) - netif_napi_del(p); - - free_percpu(dev->pcpu_refcnt); - dev->pcpu_refcnt = NULL; - - /* Compatibility with error handling in drivers */ - if (dev->reg_state == NETREG_UNINITIALIZED) { - netdev_freemem(dev); - return; - } - - BUG_ON(dev->reg_state != NETREG_UNREGISTERED); - dev->reg_state = NETREG_RELEASED; - - /* will free via device release */ - put_device(&dev->dev); -} -EXPORT_SYMBOL(free_netdev); - -/** - * synchronize_net - Synchronize with packet receive processing - * - * Wait for packets currently being received to be done. - * Does not block later packets from starting. - */ -void synchronize_net(void) -{ - might_sleep(); - if (rtnl_is_locked()) - synchronize_rcu_expedited(); - else - synchronize_rcu(); -} -EXPORT_SYMBOL(synchronize_net); - -/** - * unregister_netdevice_queue - remove device from the kernel - * @dev: device - * @head: list - * - * This function shuts down a device interface and removes it - * from the kernel tables. - * If head not NULL, device is queued to be unregistered later. - * - * Callers must hold the rtnl semaphore. You may want - * unregister_netdev() instead of this. - */ - -void unregister_netdevice_queue(struct net_device *dev, struct list_head *head) -{ - ASSERT_RTNL(); - - if (head) { - list_move_tail(&dev->unreg_list, head); - } else { - rollback_registered(dev); - /* Finish processing unregister after unlock */ - net_set_todo(dev); - } -} -EXPORT_SYMBOL(unregister_netdevice_queue); - -/** - * unregister_netdevice_many - unregister many devices - * @head: list of devices - * - * Note: As most callers use a stack allocated list_head, - * we force a list_del() to make sure stack wont be corrupted later. - */ -void unregister_netdevice_many(struct list_head *head) -{ - struct net_device *dev; - - if (!list_empty(head)) { - rollback_registered_many(head); - list_for_each_entry(dev, head, unreg_list) - net_set_todo(dev); - list_del(head); - } -} -EXPORT_SYMBOL(unregister_netdevice_many); - -/** - * unregister_netdev - remove device from the kernel - * @dev: device - * - * This function shuts down a device interface and removes it - * from the kernel tables. - * - * This is just a wrapper for unregister_netdevice that takes - * the rtnl semaphore. In general you want to use this and not - * unregister_netdevice. - */ -void unregister_netdev(struct net_device *dev) -{ - rtnl_lock(); - unregister_netdevice(dev); - rtnl_unlock(); -} -EXPORT_SYMBOL(unregister_netdev); - -/** - * dev_change_net_namespace - move device to different nethost namespace - * @dev: device - * @net: network namespace - * @pat: If not NULL name pattern to try if the current device name - * is already taken in the destination network namespace. - * - * This function shuts down a device interface and moves it - * to a new network namespace. On success 0 is returned, on - * a failure a netagive errno code is returned. - * - * Callers must hold the rtnl semaphore. - */ - -int dev_change_net_namespace(struct net_device *dev, struct net *net, const char *pat) -{ - int err; - - ASSERT_RTNL(); - - /* Don't allow namespace local devices to be moved. */ - err = -EINVAL; - if (dev->features & NETIF_F_NETNS_LOCAL) - goto out; - - /* Ensure the device has been registrered */ - if (dev->reg_state != NETREG_REGISTERED) - goto out; - - /* Get out if there is nothing todo */ - err = 0; - if (net_eq(dev_net(dev), net)) - goto out; - - /* Pick the destination device name, and ensure - * we can use it in the destination network namespace. - */ - err = -EEXIST; - if (__dev_get_by_name(net, dev->name)) { - /* We get here if we can't use the current device name */ - if (!pat) - goto out; - if (dev_get_valid_name(net, dev, pat) < 0) - goto out; - } - - /* - * And now a mini version of register_netdevice unregister_netdevice. - */ - - /* If device is running close it first. */ - dev_close(dev); - - /* And unlink it from device chain */ - err = -ENODEV; - unlist_netdevice(dev); - - synchronize_net(); - - /* Shutdown queueing discipline. */ - dev_shutdown(dev); - - /* Notify protocols, that we are about to destroy - this device. They should clean all the things. - - Note that dev->reg_state stays at NETREG_REGISTERED. - This is wanted because this way 8021q and macvlan know - the device is just moving and can keep their slaves up. - */ - call_netdevice_notifiers(NETDEV_UNREGISTER, dev); - rcu_barrier(); - call_netdevice_notifiers(NETDEV_UNREGISTER_FINAL, dev); - rtmsg_ifinfo(RTM_DELLINK, dev, ~0U, GFP_KERNEL); - - /* - * Flush the unicast and multicast chains - */ - dev_uc_flush(dev); - dev_mc_flush(dev); - - /* Send a netdev-removed uevent to the old namespace */ - kobject_uevent(&dev->dev.kobj, KOBJ_REMOVE); - netdev_adjacent_del_links(dev); - - /* Actually switch the network namespace */ - dev_net_set(dev, net); - - /* If there is an ifindex conflict assign a new one */ - if (__dev_get_by_index(net, dev->ifindex)) - dev->ifindex = dev_new_index(net); - - /* Send a netdev-add uevent to the new namespace */ - kobject_uevent(&dev->dev.kobj, KOBJ_ADD); - netdev_adjacent_add_links(dev); - - /* Fixup kobjects */ - err = device_rename(&dev->dev, dev->name); - WARN_ON(err); - - /* Add the device back in the hashes */ - list_netdevice(dev); - - /* Notify protocols, that a new device appeared. */ - call_netdevice_notifiers(NETDEV_REGISTER, dev); - - /* - * Prevent userspace races by waiting until the network - * device is fully setup before sending notifications. - */ - rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U, GFP_KERNEL); - - synchronize_net(); - err = 0; -out: - return err; -} -EXPORT_SYMBOL_GPL(dev_change_net_namespace); - -static int dev_cpu_callback(struct notifier_block *nfb, - unsigned long action, - void *ocpu) -{ - struct sk_buff **list_skb; - struct sk_buff *skb; - unsigned int cpu, oldcpu = (unsigned long)ocpu; - struct softnet_data *sd, *oldsd; - - if (action != CPU_DEAD && action != CPU_DEAD_FROZEN) - return NOTIFY_OK; - - local_irq_disable(); - cpu = smp_processor_id(); - sd = &per_cpu(softnet_data, cpu); - oldsd = &per_cpu(softnet_data, oldcpu); - - /* Find end of our completion_queue. */ - list_skb = &sd->completion_queue; - while (*list_skb) - list_skb = &(*list_skb)->next; - /* Append completion queue from offline CPU. */ - *list_skb = oldsd->completion_queue; - oldsd->completion_queue = NULL; - - /* Append output queue from offline CPU. */ - if (oldsd->output_queue) { - *sd->output_queue_tailp = oldsd->output_queue; - sd->output_queue_tailp = oldsd->output_queue_tailp; - oldsd->output_queue = NULL; - oldsd->output_queue_tailp = &oldsd->output_queue; - } - /* Append NAPI poll list from offline CPU, with one exception : - * process_backlog() must be called by cpu owning percpu backlog. - * We properly handle process_queue & input_pkt_queue later. - */ - while (!list_empty(&oldsd->poll_list)) { - struct napi_struct *napi = list_first_entry(&oldsd->poll_list, - struct napi_struct, - poll_list); - - list_del_init(&napi->poll_list); - if (napi->poll == process_backlog) - napi->state = 0; - else - ____napi_schedule(sd, napi); - } - - raise_softirq_irqoff(NET_TX_SOFTIRQ); - local_irq_enable(); - - /* Process offline CPU's input_pkt_queue */ - while ((skb = __skb_dequeue(&oldsd->process_queue))) { - netif_rx_ni(skb); - input_queue_head_incr(oldsd); - } - while ((skb = skb_dequeue(&oldsd->input_pkt_queue))) { - netif_rx_ni(skb); - input_queue_head_incr(oldsd); - } - - return NOTIFY_OK; -} - - -/** - * netdev_increment_features - increment feature set by one - * @all: current feature set - * @one: new feature set - * @mask: mask feature set - * - * Computes a new feature set after adding a device with feature set - * @one to the master device with current feature set @all. Will not - * enable anything that is off in @mask. Returns the new feature set. - */ -netdev_features_t netdev_increment_features(netdev_features_t all, - netdev_features_t one, netdev_features_t mask) -{ - if (mask & NETIF_F_HW_CSUM) - mask |= NETIF_F_CSUM_MASK; - mask |= NETIF_F_VLAN_CHALLENGED; - - all |= one & (NETIF_F_ONE_FOR_ALL | NETIF_F_CSUM_MASK) & mask; - all &= one | ~NETIF_F_ALL_FOR_ALL; - - /* If one device supports hw checksumming, set for all. */ - if (all & NETIF_F_HW_CSUM) - all &= ~(NETIF_F_CSUM_MASK & ~NETIF_F_HW_CSUM); - - return all; -} -EXPORT_SYMBOL(netdev_increment_features); - -static struct hlist_head * __net_init netdev_create_hash(void) -{ - int i; - struct hlist_head *hash; - - hash = kmalloc(sizeof(*hash) * NETDEV_HASHENTRIES, GFP_KERNEL); - if (hash != NULL) - for (i = 0; i < NETDEV_HASHENTRIES; i++) - INIT_HLIST_HEAD(&hash[i]); - - return hash; -} - -/* Initialize per network namespace state */ -static int __net_init netdev_init(struct net *net) -{ - if (net != &init_net) - INIT_LIST_HEAD(&net->dev_base_head); - - net->dev_name_head = netdev_create_hash(); - if (net->dev_name_head == NULL) - goto err_name; - - net->dev_index_head = netdev_create_hash(); - if (net->dev_index_head == NULL) - goto err_idx; - - return 0; - -err_idx: - kfree(net->dev_name_head); -err_name: - return -ENOMEM; -} - -/** - * netdev_drivername - network driver for the device - * @dev: network device - * - * Determine network driver for device. - */ -const char *netdev_drivername(const struct net_device *dev) -{ - const struct device_driver *driver; - const struct device *parent; - const char *empty = ""; - - parent = dev->dev.parent; - if (!parent) - return empty; - - driver = parent->driver; - if (driver && driver->name) - return driver->name; - return empty; -} - -static void __netdev_printk(const char *level, const struct net_device *dev, - struct va_format *vaf) -{ - if (dev && dev->dev.parent) { - dev_printk_emit(level[1] - '0', - dev->dev.parent, - "%s %s %s%s: %pV", - dev_driver_string(dev->dev.parent), - dev_name(dev->dev.parent), - netdev_name(dev), netdev_reg_state(dev), - vaf); - } else if (dev) { - printk("%s%s%s: %pV", - level, netdev_name(dev), netdev_reg_state(dev), vaf); - } else { - printk("%s(NULL net_device): %pV", level, vaf); - } -} - -void netdev_printk(const char *level, const struct net_device *dev, - const char *format, ...) -{ - struct va_format vaf; - va_list args; - - va_start(args, format); - - vaf.fmt = format; - vaf.va = &args; - - __netdev_printk(level, dev, &vaf); - - va_end(args); -} -EXPORT_SYMBOL(netdev_printk); - -#define define_netdev_printk_level(func, level) \ -void func(const struct net_device *dev, const char *fmt, ...) \ -{ \ - struct va_format vaf; \ - va_list args; \ - \ - va_start(args, fmt); \ - \ - vaf.fmt = fmt; \ - vaf.va = &args; \ - \ - __netdev_printk(level, dev, &vaf); \ - \ - va_end(args); \ -} \ -EXPORT_SYMBOL(func); - -define_netdev_printk_level(netdev_emerg, KERN_EMERG); -define_netdev_printk_level(netdev_alert, KERN_ALERT); -define_netdev_printk_level(netdev_crit, KERN_CRIT); -define_netdev_printk_level(netdev_err, KERN_ERR); -define_netdev_printk_level(netdev_warn, KERN_WARNING); -define_netdev_printk_level(netdev_notice, KERN_NOTICE); -define_netdev_printk_level(netdev_info, KERN_INFO); - -static void __net_exit netdev_exit(struct net *net) -{ - kfree(net->dev_name_head); - kfree(net->dev_index_head); -} - -static struct pernet_operations __net_initdata netdev_net_ops = { - .init = netdev_init, - .exit = netdev_exit, -}; - -static void __net_exit default_device_exit(struct net *net) -{ - struct net_device *dev, *aux; - /* - * Push all migratable network devices back to the - * initial network namespace - */ - rtnl_lock(); - for_each_netdev_safe(net, dev, aux) { - int err; - char fb_name[IFNAMSIZ]; - - /* Ignore unmoveable devices (i.e. loopback) */ - if (dev->features & NETIF_F_NETNS_LOCAL) - continue; - - /* Leave virtual devices for the generic cleanup */ - if (dev->rtnl_link_ops) - continue; - - /* Push remaining network devices to init_net */ - snprintf(fb_name, IFNAMSIZ, "dev%d", dev->ifindex); - err = dev_change_net_namespace(dev, &init_net, fb_name); - if (err) { - pr_emerg("%s: failed to move %s to init_net: %d\n", - __func__, dev->name, err); - BUG(); - } - } - rtnl_unlock(); -} - -static void __net_exit rtnl_lock_unregistering(struct list_head *net_list) -{ - /* Return with the rtnl_lock held when there are no network - * devices unregistering in any network namespace in net_list. - */ - struct net *net; - bool unregistering; - DEFINE_WAIT_FUNC(wait, woken_wake_function); - - add_wait_queue(&netdev_unregistering_wq, &wait); - for (;;) { - unregistering = false; - rtnl_lock(); - list_for_each_entry(net, net_list, exit_list) { - if (net->dev_unreg_count > 0) { - unregistering = true; - break; - } - } - if (!unregistering) - break; - __rtnl_unlock(); - - wait_woken(&wait, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); - } - remove_wait_queue(&netdev_unregistering_wq, &wait); -} - -static void __net_exit default_device_exit_batch(struct list_head *net_list) -{ - /* At exit all network devices most be removed from a network - * namespace. Do this in the reverse order of registration. - * Do this across as many network namespaces as possible to - * improve batching efficiency. - */ - struct net_device *dev; - struct net *net; - LIST_HEAD(dev_kill_list); - - /* To prevent network device cleanup code from dereferencing - * loopback devices or network devices that have been freed - * wait here for all pending unregistrations to complete, - * before unregistring the loopback device and allowing the - * network namespace be freed. - * - * The netdev todo list containing all network devices - * unregistrations that happen in default_device_exit_batch - * will run in the rtnl_unlock() at the end of - * default_device_exit_batch. - */ - rtnl_lock_unregistering(net_list); - list_for_each_entry(net, net_list, exit_list) { - for_each_netdev_reverse(net, dev) { - if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink) - dev->rtnl_link_ops->dellink(dev, &dev_kill_list); - else - unregister_netdevice_queue(dev, &dev_kill_list); - } - } - unregister_netdevice_many(&dev_kill_list); - rtnl_unlock(); -} - -static struct pernet_operations __net_initdata default_device_ops = { - .exit = default_device_exit, - .exit_batch = default_device_exit_batch, -}; - -/* - * Initialize the DEV module. At boot time this walks the device list and - * unhooks any devices that fail to initialise (normally hardware not - * present) and leaves us with a valid list of present and active devices. - * - */ - -/* - * This is called single threaded during boot, so no need - * to take the rtnl semaphore. - */ -static int __init net_dev_init(void) -{ - int i, rc = -ENOMEM; - - BUG_ON(!dev_boot_phase); - - if (dev_proc_init()) - goto out; - - if (netdev_kobject_init()) - goto out; - - INIT_LIST_HEAD(&ptype_all); - for (i = 0; i < PTYPE_HASH_SIZE; i++) - INIT_LIST_HEAD(&ptype_base[i]); - - INIT_LIST_HEAD(&offload_base); - - if (register_pernet_subsys(&netdev_net_ops)) - goto out; - - /* - * Initialise the packet receive queues. - */ - - for_each_possible_cpu(i) { - struct work_struct *flush = per_cpu_ptr(&flush_works, i); - struct softnet_data *sd = &per_cpu(softnet_data, i); - - INIT_WORK(flush, flush_backlog); - - skb_queue_head_init(&sd->input_pkt_queue); - skb_queue_head_init(&sd->process_queue); - INIT_LIST_HEAD(&sd->poll_list); - sd->output_queue_tailp = &sd->output_queue; -#ifdef CONFIG_RPS - sd->csd.func = rps_trigger_softirq; - sd->csd.info = sd; - sd->cpu = i; -#endif - - sd->backlog.poll = process_backlog; - sd->backlog.weight = weight_p; - } - - dev_boot_phase = 0; - - /* The loopback device is special if any other network devices - * is present in a network namespace the loopback device must - * be present. Since we now dynamically allocate and free the - * loopback device ensure this invariant is maintained by - * keeping the loopback device as the first device on the - * list of network devices. Ensuring the loopback devices - * is the first device that appears and the last network device - * that disappears. - */ - if (register_pernet_device(&loopback_net_ops)) - goto out; - - if (register_pernet_device(&default_device_ops)) - goto out; - - open_softirq(NET_TX_SOFTIRQ, net_tx_action); - open_softirq(NET_RX_SOFTIRQ, net_rx_action); - - hotcpu_notifier(dev_cpu_callback, 0); - dst_subsys_init(); - rc = 0; -out: - return rc; -} - -subsys_initcall(net_dev_init); diff --git a/src/linux/net/core/dev_addr_lists.c b/src/linux/net/core/dev_addr_lists.c deleted file mode 100644 index c0548d2..0000000 --- a/src/linux/net/core/dev_addr_lists.c +++ /dev/null @@ -1,851 +0,0 @@ -/* - * net/core/dev_addr_lists.c - Functions for handling net device lists - * Copyright (c) 2010 Jiri Pirko - * - * This file contains functions for working with unicast, multicast and device - * addresses lists. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include - -/* - * General list handling functions - */ - -static int __hw_addr_create_ex(struct netdev_hw_addr_list *list, - const unsigned char *addr, int addr_len, - unsigned char addr_type, bool global, - bool sync) -{ - struct netdev_hw_addr *ha; - int alloc_size; - - alloc_size = sizeof(*ha); - if (alloc_size < L1_CACHE_BYTES) - alloc_size = L1_CACHE_BYTES; - ha = kmalloc(alloc_size, GFP_ATOMIC); - if (!ha) - return -ENOMEM; - memcpy(ha->addr, addr, addr_len); - ha->type = addr_type; - ha->refcount = 1; - ha->global_use = global; - ha->synced = sync ? 1 : 0; - ha->sync_cnt = 0; - list_add_tail_rcu(&ha->list, &list->list); - list->count++; - - return 0; -} - -static int __hw_addr_add_ex(struct netdev_hw_addr_list *list, - const unsigned char *addr, int addr_len, - unsigned char addr_type, bool global, bool sync, - int sync_count) -{ - struct netdev_hw_addr *ha; - - if (addr_len > MAX_ADDR_LEN) - return -EINVAL; - - list_for_each_entry(ha, &list->list, list) { - if (!memcmp(ha->addr, addr, addr_len) && - ha->type == addr_type) { - if (global) { - /* check if addr is already used as global */ - if (ha->global_use) - return 0; - else - ha->global_use = true; - } - if (sync) { - if (ha->synced && sync_count) - return -EEXIST; - else - ha->synced++; - } - ha->refcount++; - return 0; - } - } - - return __hw_addr_create_ex(list, addr, addr_len, addr_type, global, - sync); -} - -static int __hw_addr_add(struct netdev_hw_addr_list *list, - const unsigned char *addr, int addr_len, - unsigned char addr_type) -{ - return __hw_addr_add_ex(list, addr, addr_len, addr_type, false, false, - 0); -} - -static int __hw_addr_del_entry(struct netdev_hw_addr_list *list, - struct netdev_hw_addr *ha, bool global, - bool sync) -{ - if (global && !ha->global_use) - return -ENOENT; - - if (sync && !ha->synced) - return -ENOENT; - - if (global) - ha->global_use = false; - - if (sync) - ha->synced--; - - if (--ha->refcount) - return 0; - list_del_rcu(&ha->list); - kfree_rcu(ha, rcu_head); - list->count--; - return 0; -} - -static int __hw_addr_del_ex(struct netdev_hw_addr_list *list, - const unsigned char *addr, int addr_len, - unsigned char addr_type, bool global, bool sync) -{ - struct netdev_hw_addr *ha; - - list_for_each_entry(ha, &list->list, list) { - if (!memcmp(ha->addr, addr, addr_len) && - (ha->type == addr_type || !addr_type)) - return __hw_addr_del_entry(list, ha, global, sync); - } - return -ENOENT; -} - -static int __hw_addr_del(struct netdev_hw_addr_list *list, - const unsigned char *addr, int addr_len, - unsigned char addr_type) -{ - return __hw_addr_del_ex(list, addr, addr_len, addr_type, false, false); -} - -static int __hw_addr_sync_one(struct netdev_hw_addr_list *to_list, - struct netdev_hw_addr *ha, - int addr_len) -{ - int err; - - err = __hw_addr_add_ex(to_list, ha->addr, addr_len, ha->type, - false, true, ha->sync_cnt); - if (err && err != -EEXIST) - return err; - - if (!err) { - ha->sync_cnt++; - ha->refcount++; - } - - return 0; -} - -static void __hw_addr_unsync_one(struct netdev_hw_addr_list *to_list, - struct netdev_hw_addr_list *from_list, - struct netdev_hw_addr *ha, - int addr_len) -{ - int err; - - err = __hw_addr_del_ex(to_list, ha->addr, addr_len, ha->type, - false, true); - if (err) - return; - ha->sync_cnt--; - /* address on from list is not marked synced */ - __hw_addr_del_entry(from_list, ha, false, false); -} - -static int __hw_addr_sync_multiple(struct netdev_hw_addr_list *to_list, - struct netdev_hw_addr_list *from_list, - int addr_len) -{ - int err = 0; - struct netdev_hw_addr *ha, *tmp; - - list_for_each_entry_safe(ha, tmp, &from_list->list, list) { - if (ha->sync_cnt == ha->refcount) { - __hw_addr_unsync_one(to_list, from_list, ha, addr_len); - } else { - err = __hw_addr_sync_one(to_list, ha, addr_len); - if (err) - break; - } - } - return err; -} - -/* This function only works where there is a strict 1-1 relationship - * between source and destionation of they synch. If you ever need to - * sync addresses to more then 1 destination, you need to use - * __hw_addr_sync_multiple(). - */ -int __hw_addr_sync(struct netdev_hw_addr_list *to_list, - struct netdev_hw_addr_list *from_list, - int addr_len) -{ - int err = 0; - struct netdev_hw_addr *ha, *tmp; - - list_for_each_entry_safe(ha, tmp, &from_list->list, list) { - if (!ha->sync_cnt) { - err = __hw_addr_sync_one(to_list, ha, addr_len); - if (err) - break; - } else if (ha->refcount == 1) - __hw_addr_unsync_one(to_list, from_list, ha, addr_len); - } - return err; -} -EXPORT_SYMBOL(__hw_addr_sync); - -void __hw_addr_unsync(struct netdev_hw_addr_list *to_list, - struct netdev_hw_addr_list *from_list, - int addr_len) -{ - struct netdev_hw_addr *ha, *tmp; - - list_for_each_entry_safe(ha, tmp, &from_list->list, list) { - if (ha->sync_cnt) - __hw_addr_unsync_one(to_list, from_list, ha, addr_len); - } -} -EXPORT_SYMBOL(__hw_addr_unsync); - -/** - * __hw_addr_sync_dev - Synchonize device's multicast list - * @list: address list to syncronize - * @dev: device to sync - * @sync: function to call if address should be added - * @unsync: function to call if address should be removed - * - * This funciton is intended to be called from the ndo_set_rx_mode - * function of devices that require explicit address add/remove - * notifications. The unsync function may be NULL in which case - * the addresses requiring removal will simply be removed without - * any notification to the device. - **/ -int __hw_addr_sync_dev(struct netdev_hw_addr_list *list, - struct net_device *dev, - int (*sync)(struct net_device *, const unsigned char *), - int (*unsync)(struct net_device *, - const unsigned char *)) -{ - struct netdev_hw_addr *ha, *tmp; - int err; - - /* first go through and flush out any stale entries */ - list_for_each_entry_safe(ha, tmp, &list->list, list) { - if (!ha->sync_cnt || ha->refcount != 1) - continue; - - /* if unsync is defined and fails defer unsyncing address */ - if (unsync && unsync(dev, ha->addr)) - continue; - - ha->sync_cnt--; - __hw_addr_del_entry(list, ha, false, false); - } - - /* go through and sync new entries to the list */ - list_for_each_entry_safe(ha, tmp, &list->list, list) { - if (ha->sync_cnt) - continue; - - err = sync(dev, ha->addr); - if (err) - return err; - - ha->sync_cnt++; - ha->refcount++; - } - - return 0; -} -EXPORT_SYMBOL(__hw_addr_sync_dev); - -/** - * __hw_addr_unsync_dev - Remove synchronized addresses from device - * @list: address list to remove synchronized addresses from - * @dev: device to sync - * @unsync: function to call if address should be removed - * - * Remove all addresses that were added to the device by __hw_addr_sync_dev(). - * This function is intended to be called from the ndo_stop or ndo_open - * functions on devices that require explicit address add/remove - * notifications. If the unsync function pointer is NULL then this function - * can be used to just reset the sync_cnt for the addresses in the list. - **/ -void __hw_addr_unsync_dev(struct netdev_hw_addr_list *list, - struct net_device *dev, - int (*unsync)(struct net_device *, - const unsigned char *)) -{ - struct netdev_hw_addr *ha, *tmp; - - list_for_each_entry_safe(ha, tmp, &list->list, list) { - if (!ha->sync_cnt) - continue; - - /* if unsync is defined and fails defer unsyncing address */ - if (unsync && unsync(dev, ha->addr)) - continue; - - ha->sync_cnt--; - __hw_addr_del_entry(list, ha, false, false); - } -} -EXPORT_SYMBOL(__hw_addr_unsync_dev); - -static void __hw_addr_flush(struct netdev_hw_addr_list *list) -{ - struct netdev_hw_addr *ha, *tmp; - - list_for_each_entry_safe(ha, tmp, &list->list, list) { - list_del_rcu(&ha->list); - kfree_rcu(ha, rcu_head); - } - list->count = 0; -} - -void __hw_addr_init(struct netdev_hw_addr_list *list) -{ - INIT_LIST_HEAD(&list->list); - list->count = 0; -} -EXPORT_SYMBOL(__hw_addr_init); - -/* - * Device addresses handling functions - */ - -/** - * dev_addr_flush - Flush device address list - * @dev: device - * - * Flush device address list and reset ->dev_addr. - * - * The caller must hold the rtnl_mutex. - */ -void dev_addr_flush(struct net_device *dev) -{ - /* rtnl_mutex must be held here */ - - __hw_addr_flush(&dev->dev_addrs); - dev->dev_addr = NULL; -} -EXPORT_SYMBOL(dev_addr_flush); - -/** - * dev_addr_init - Init device address list - * @dev: device - * - * Init device address list and create the first element, - * used by ->dev_addr. - * - * The caller must hold the rtnl_mutex. - */ -int dev_addr_init(struct net_device *dev) -{ - unsigned char addr[MAX_ADDR_LEN]; - struct netdev_hw_addr *ha; - int err; - - /* rtnl_mutex must be held here */ - - __hw_addr_init(&dev->dev_addrs); - memset(addr, 0, sizeof(addr)); - err = __hw_addr_add(&dev->dev_addrs, addr, sizeof(addr), - NETDEV_HW_ADDR_T_LAN); - if (!err) { - /* - * Get the first (previously created) address from the list - * and set dev_addr pointer to this location. - */ - ha = list_first_entry(&dev->dev_addrs.list, - struct netdev_hw_addr, list); - dev->dev_addr = ha->addr; - } - return err; -} -EXPORT_SYMBOL(dev_addr_init); - -/** - * dev_addr_add - Add a device address - * @dev: device - * @addr: address to add - * @addr_type: address type - * - * Add a device address to the device or increase the reference count if - * it already exists. - * - * The caller must hold the rtnl_mutex. - */ -int dev_addr_add(struct net_device *dev, const unsigned char *addr, - unsigned char addr_type) -{ - int err; - - ASSERT_RTNL(); - - err = __hw_addr_add(&dev->dev_addrs, addr, dev->addr_len, addr_type); - if (!err) - call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); - return err; -} -EXPORT_SYMBOL(dev_addr_add); - -/** - * dev_addr_del - Release a device address. - * @dev: device - * @addr: address to delete - * @addr_type: address type - * - * Release reference to a device address and remove it from the device - * if the reference count drops to zero. - * - * The caller must hold the rtnl_mutex. - */ -int dev_addr_del(struct net_device *dev, const unsigned char *addr, - unsigned char addr_type) -{ - int err; - struct netdev_hw_addr *ha; - - ASSERT_RTNL(); - - /* - * We can not remove the first address from the list because - * dev->dev_addr points to that. - */ - ha = list_first_entry(&dev->dev_addrs.list, - struct netdev_hw_addr, list); - if (!memcmp(ha->addr, addr, dev->addr_len) && - ha->type == addr_type && ha->refcount == 1) - return -ENOENT; - - err = __hw_addr_del(&dev->dev_addrs, addr, dev->addr_len, - addr_type); - if (!err) - call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); - return err; -} -EXPORT_SYMBOL(dev_addr_del); - -/* - * Unicast list handling functions - */ - -/** - * dev_uc_add_excl - Add a global secondary unicast address - * @dev: device - * @addr: address to add - */ -int dev_uc_add_excl(struct net_device *dev, const unsigned char *addr) -{ - struct netdev_hw_addr *ha; - int err; - - netif_addr_lock_bh(dev); - list_for_each_entry(ha, &dev->uc.list, list) { - if (!memcmp(ha->addr, addr, dev->addr_len) && - ha->type == NETDEV_HW_ADDR_T_UNICAST) { - err = -EEXIST; - goto out; - } - } - err = __hw_addr_create_ex(&dev->uc, addr, dev->addr_len, - NETDEV_HW_ADDR_T_UNICAST, true, false); - if (!err) - __dev_set_rx_mode(dev); -out: - netif_addr_unlock_bh(dev); - return err; -} -EXPORT_SYMBOL(dev_uc_add_excl); - -/** - * dev_uc_add - Add a secondary unicast address - * @dev: device - * @addr: address to add - * - * Add a secondary unicast address to the device or increase - * the reference count if it already exists. - */ -int dev_uc_add(struct net_device *dev, const unsigned char *addr) -{ - int err; - - netif_addr_lock_bh(dev); - err = __hw_addr_add(&dev->uc, addr, dev->addr_len, - NETDEV_HW_ADDR_T_UNICAST); - if (!err) - __dev_set_rx_mode(dev); - netif_addr_unlock_bh(dev); - return err; -} -EXPORT_SYMBOL(dev_uc_add); - -/** - * dev_uc_del - Release secondary unicast address. - * @dev: device - * @addr: address to delete - * - * Release reference to a secondary unicast address and remove it - * from the device if the reference count drops to zero. - */ -int dev_uc_del(struct net_device *dev, const unsigned char *addr) -{ - int err; - - netif_addr_lock_bh(dev); - err = __hw_addr_del(&dev->uc, addr, dev->addr_len, - NETDEV_HW_ADDR_T_UNICAST); - if (!err) - __dev_set_rx_mode(dev); - netif_addr_unlock_bh(dev); - return err; -} -EXPORT_SYMBOL(dev_uc_del); - -/** - * dev_uc_sync - Synchronize device's unicast list to another device - * @to: destination device - * @from: source device - * - * Add newly added addresses to the destination device and release - * addresses that have no users left. The source device must be - * locked by netif_addr_lock_bh. - * - * This function is intended to be called from the dev->set_rx_mode - * function of layered software devices. This function assumes that - * addresses will only ever be synced to the @to devices and no other. - */ -int dev_uc_sync(struct net_device *to, struct net_device *from) -{ - int err = 0; - - if (to->addr_len != from->addr_len) - return -EINVAL; - - netif_addr_lock_nested(to); - err = __hw_addr_sync(&to->uc, &from->uc, to->addr_len); - if (!err) - __dev_set_rx_mode(to); - netif_addr_unlock(to); - return err; -} -EXPORT_SYMBOL(dev_uc_sync); - -/** - * dev_uc_sync_multiple - Synchronize device's unicast list to another - * device, but allow for multiple calls to sync to multiple devices. - * @to: destination device - * @from: source device - * - * Add newly added addresses to the destination device and release - * addresses that have been deleted from the source. The source device - * must be locked by netif_addr_lock_bh. - * - * This function is intended to be called from the dev->set_rx_mode - * function of layered software devices. It allows for a single source - * device to be synced to multiple destination devices. - */ -int dev_uc_sync_multiple(struct net_device *to, struct net_device *from) -{ - int err = 0; - - if (to->addr_len != from->addr_len) - return -EINVAL; - - netif_addr_lock_nested(to); - err = __hw_addr_sync_multiple(&to->uc, &from->uc, to->addr_len); - if (!err) - __dev_set_rx_mode(to); - netif_addr_unlock(to); - return err; -} -EXPORT_SYMBOL(dev_uc_sync_multiple); - -/** - * dev_uc_unsync - Remove synchronized addresses from the destination device - * @to: destination device - * @from: source device - * - * Remove all addresses that were added to the destination device by - * dev_uc_sync(). This function is intended to be called from the - * dev->stop function of layered software devices. - */ -void dev_uc_unsync(struct net_device *to, struct net_device *from) -{ - if (to->addr_len != from->addr_len) - return; - - netif_addr_lock_bh(from); - netif_addr_lock_nested(to); - __hw_addr_unsync(&to->uc, &from->uc, to->addr_len); - __dev_set_rx_mode(to); - netif_addr_unlock(to); - netif_addr_unlock_bh(from); -} -EXPORT_SYMBOL(dev_uc_unsync); - -/** - * dev_uc_flush - Flush unicast addresses - * @dev: device - * - * Flush unicast addresses. - */ -void dev_uc_flush(struct net_device *dev) -{ - netif_addr_lock_bh(dev); - __hw_addr_flush(&dev->uc); - netif_addr_unlock_bh(dev); -} -EXPORT_SYMBOL(dev_uc_flush); - -/** - * dev_uc_flush - Init unicast address list - * @dev: device - * - * Init unicast address list. - */ -void dev_uc_init(struct net_device *dev) -{ - __hw_addr_init(&dev->uc); -} -EXPORT_SYMBOL(dev_uc_init); - -/* - * Multicast list handling functions - */ - -/** - * dev_mc_add_excl - Add a global secondary multicast address - * @dev: device - * @addr: address to add - */ -int dev_mc_add_excl(struct net_device *dev, const unsigned char *addr) -{ - struct netdev_hw_addr *ha; - int err; - - netif_addr_lock_bh(dev); - list_for_each_entry(ha, &dev->mc.list, list) { - if (!memcmp(ha->addr, addr, dev->addr_len) && - ha->type == NETDEV_HW_ADDR_T_MULTICAST) { - err = -EEXIST; - goto out; - } - } - err = __hw_addr_create_ex(&dev->mc, addr, dev->addr_len, - NETDEV_HW_ADDR_T_MULTICAST, true, false); - if (!err) - __dev_set_rx_mode(dev); -out: - netif_addr_unlock_bh(dev); - return err; -} -EXPORT_SYMBOL(dev_mc_add_excl); - -static int __dev_mc_add(struct net_device *dev, const unsigned char *addr, - bool global) -{ - int err; - - netif_addr_lock_bh(dev); - err = __hw_addr_add_ex(&dev->mc, addr, dev->addr_len, - NETDEV_HW_ADDR_T_MULTICAST, global, false, 0); - if (!err) - __dev_set_rx_mode(dev); - netif_addr_unlock_bh(dev); - return err; -} -/** - * dev_mc_add - Add a multicast address - * @dev: device - * @addr: address to add - * - * Add a multicast address to the device or increase - * the reference count if it already exists. - */ -int dev_mc_add(struct net_device *dev, const unsigned char *addr) -{ - return __dev_mc_add(dev, addr, false); -} -EXPORT_SYMBOL(dev_mc_add); - -/** - * dev_mc_add_global - Add a global multicast address - * @dev: device - * @addr: address to add - * - * Add a global multicast address to the device. - */ -int dev_mc_add_global(struct net_device *dev, const unsigned char *addr) -{ - return __dev_mc_add(dev, addr, true); -} -EXPORT_SYMBOL(dev_mc_add_global); - -static int __dev_mc_del(struct net_device *dev, const unsigned char *addr, - bool global) -{ - int err; - - netif_addr_lock_bh(dev); - err = __hw_addr_del_ex(&dev->mc, addr, dev->addr_len, - NETDEV_HW_ADDR_T_MULTICAST, global, false); - if (!err) - __dev_set_rx_mode(dev); - netif_addr_unlock_bh(dev); - return err; -} - -/** - * dev_mc_del - Delete a multicast address. - * @dev: device - * @addr: address to delete - * - * Release reference to a multicast address and remove it - * from the device if the reference count drops to zero. - */ -int dev_mc_del(struct net_device *dev, const unsigned char *addr) -{ - return __dev_mc_del(dev, addr, false); -} -EXPORT_SYMBOL(dev_mc_del); - -/** - * dev_mc_del_global - Delete a global multicast address. - * @dev: device - * @addr: address to delete - * - * Release reference to a multicast address and remove it - * from the device if the reference count drops to zero. - */ -int dev_mc_del_global(struct net_device *dev, const unsigned char *addr) -{ - return __dev_mc_del(dev, addr, true); -} -EXPORT_SYMBOL(dev_mc_del_global); - -/** - * dev_mc_sync - Synchronize device's multicast list to another device - * @to: destination device - * @from: source device - * - * Add newly added addresses to the destination device and release - * addresses that have no users left. The source device must be - * locked by netif_addr_lock_bh. - * - * This function is intended to be called from the ndo_set_rx_mode - * function of layered software devices. - */ -int dev_mc_sync(struct net_device *to, struct net_device *from) -{ - int err = 0; - - if (to->addr_len != from->addr_len) - return -EINVAL; - - netif_addr_lock_nested(to); - err = __hw_addr_sync(&to->mc, &from->mc, to->addr_len); - if (!err) - __dev_set_rx_mode(to); - netif_addr_unlock(to); - return err; -} -EXPORT_SYMBOL(dev_mc_sync); - -/** - * dev_mc_sync_multiple - Synchronize device's multicast list to another - * device, but allow for multiple calls to sync to multiple devices. - * @to: destination device - * @from: source device - * - * Add newly added addresses to the destination device and release - * addresses that have no users left. The source device must be - * locked by netif_addr_lock_bh. - * - * This function is intended to be called from the ndo_set_rx_mode - * function of layered software devices. It allows for a single - * source device to be synced to multiple destination devices. - */ -int dev_mc_sync_multiple(struct net_device *to, struct net_device *from) -{ - int err = 0; - - if (to->addr_len != from->addr_len) - return -EINVAL; - - netif_addr_lock_nested(to); - err = __hw_addr_sync_multiple(&to->mc, &from->mc, to->addr_len); - if (!err) - __dev_set_rx_mode(to); - netif_addr_unlock(to); - return err; -} -EXPORT_SYMBOL(dev_mc_sync_multiple); - -/** - * dev_mc_unsync - Remove synchronized addresses from the destination device - * @to: destination device - * @from: source device - * - * Remove all addresses that were added to the destination device by - * dev_mc_sync(). This function is intended to be called from the - * dev->stop function of layered software devices. - */ -void dev_mc_unsync(struct net_device *to, struct net_device *from) -{ - if (to->addr_len != from->addr_len) - return; - - netif_addr_lock_bh(from); - netif_addr_lock_nested(to); - __hw_addr_unsync(&to->mc, &from->mc, to->addr_len); - __dev_set_rx_mode(to); - netif_addr_unlock(to); - netif_addr_unlock_bh(from); -} -EXPORT_SYMBOL(dev_mc_unsync); - -/** - * dev_mc_flush - Flush multicast addresses - * @dev: device - * - * Flush multicast addresses. - */ -void dev_mc_flush(struct net_device *dev) -{ - netif_addr_lock_bh(dev); - __hw_addr_flush(&dev->mc); - netif_addr_unlock_bh(dev); -} -EXPORT_SYMBOL(dev_mc_flush); - -/** - * dev_mc_flush - Init multicast address list - * @dev: device - * - * Init multicast address list. - */ -void dev_mc_init(struct net_device *dev) -{ - __hw_addr_init(&dev->mc); -} -EXPORT_SYMBOL(dev_mc_init); diff --git a/src/linux/net/core/dev_ioctl.c b/src/linux/net/core/dev_ioctl.c deleted file mode 100644 index b94b1d2..0000000 --- a/src/linux/net/core/dev_ioctl.c +++ /dev/null @@ -1,567 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -/* - * Map an interface index to its name (SIOCGIFNAME) - */ - -/* - * We need this ioctl for efficient implementation of the - * if_indextoname() function required by the IPv6 API. Without - * it, we would have to search all the interfaces to find a - * match. --pb - */ - -static int dev_ifname(struct net *net, struct ifreq __user *arg) -{ - struct ifreq ifr; - int error; - - /* - * Fetch the caller's info block. - */ - - if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) - return -EFAULT; - - error = netdev_get_name(net, ifr.ifr_name, ifr.ifr_ifindex); - if (error) - return error; - - if (copy_to_user(arg, &ifr, sizeof(struct ifreq))) - return -EFAULT; - return 0; -} - -static gifconf_func_t *gifconf_list[NPROTO]; - -/** - * register_gifconf - register a SIOCGIF handler - * @family: Address family - * @gifconf: Function handler - * - * Register protocol dependent address dumping routines. The handler - * that is passed must not be freed or reused until it has been replaced - * by another handler. - */ -int register_gifconf(unsigned int family, gifconf_func_t *gifconf) -{ - if (family >= NPROTO) - return -EINVAL; - gifconf_list[family] = gifconf; - return 0; -} -EXPORT_SYMBOL(register_gifconf); - -/* - * Perform a SIOCGIFCONF call. This structure will change - * size eventually, and there is nothing I can do about it. - * Thus we will need a 'compatibility mode'. - */ - -static int dev_ifconf(struct net *net, char __user *arg) -{ - struct ifconf ifc; - struct net_device *dev; - char __user *pos; - int len; - int total; - int i; - - /* - * Fetch the caller's info block. - */ - - if (copy_from_user(&ifc, arg, sizeof(struct ifconf))) - return -EFAULT; - - pos = ifc.ifc_buf; - len = ifc.ifc_len; - - /* - * Loop over the interfaces, and write an info block for each. - */ - - total = 0; - for_each_netdev(net, dev) { - for (i = 0; i < NPROTO; i++) { - if (gifconf_list[i]) { - int done; - if (!pos) - done = gifconf_list[i](dev, NULL, 0); - else - done = gifconf_list[i](dev, pos + total, - len - total); - if (done < 0) - return -EFAULT; - total += done; - } - } - } - - /* - * All done. Write the updated control block back to the caller. - */ - ifc.ifc_len = total; - - /* - * Both BSD and Solaris return 0 here, so we do too. - */ - return copy_to_user(arg, &ifc, sizeof(struct ifconf)) ? -EFAULT : 0; -} - -/* - * Perform the SIOCxIFxxx calls, inside rcu_read_lock() - */ -static int dev_ifsioc_locked(struct net *net, struct ifreq *ifr, unsigned int cmd) -{ - int err; - struct net_device *dev = dev_get_by_name_rcu(net, ifr->ifr_name); - - if (!dev) - return -ENODEV; - - switch (cmd) { - case SIOCGIFFLAGS: /* Get interface flags */ - ifr->ifr_flags = (short) dev_get_flags(dev); - return 0; - - case SIOCGIFMETRIC: /* Get the metric on the interface - (currently unused) */ - ifr->ifr_metric = 0; - return 0; - - case SIOCGIFMTU: /* Get the MTU of a device */ - ifr->ifr_mtu = dev->mtu; - return 0; - - case SIOCGIFHWADDR: - if (!dev->addr_len) - memset(ifr->ifr_hwaddr.sa_data, 0, - sizeof(ifr->ifr_hwaddr.sa_data)); - else - memcpy(ifr->ifr_hwaddr.sa_data, dev->dev_addr, - min(sizeof(ifr->ifr_hwaddr.sa_data), - (size_t)dev->addr_len)); - ifr->ifr_hwaddr.sa_family = dev->type; - return 0; - - case SIOCGIFSLAVE: - err = -EINVAL; - break; - - case SIOCGIFMAP: - ifr->ifr_map.mem_start = dev->mem_start; - ifr->ifr_map.mem_end = dev->mem_end; - ifr->ifr_map.base_addr = dev->base_addr; - ifr->ifr_map.irq = dev->irq; - ifr->ifr_map.dma = dev->dma; - ifr->ifr_map.port = dev->if_port; - return 0; - - case SIOCGIFINDEX: - ifr->ifr_ifindex = dev->ifindex; - return 0; - - case SIOCGIFTXQLEN: - ifr->ifr_qlen = dev->tx_queue_len; - return 0; - - default: - /* dev_ioctl() should ensure this case - * is never reached - */ - WARN_ON(1); - err = -ENOTTY; - break; - - } - return err; -} - -static int net_hwtstamp_validate(struct ifreq *ifr) -{ - struct hwtstamp_config cfg; - enum hwtstamp_tx_types tx_type; - enum hwtstamp_rx_filters rx_filter; - int tx_type_valid = 0; - int rx_filter_valid = 0; - - if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) - return -EFAULT; - - if (cfg.flags) /* reserved for future extensions */ - return -EINVAL; - - tx_type = cfg.tx_type; - rx_filter = cfg.rx_filter; - - switch (tx_type) { - case HWTSTAMP_TX_OFF: - case HWTSTAMP_TX_ON: - case HWTSTAMP_TX_ONESTEP_SYNC: - tx_type_valid = 1; - break; - } - - switch (rx_filter) { - case HWTSTAMP_FILTER_NONE: - case HWTSTAMP_FILTER_ALL: - case HWTSTAMP_FILTER_SOME: - case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: - case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: - case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: - case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: - case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: - case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: - case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: - case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: - case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: - case HWTSTAMP_FILTER_PTP_V2_EVENT: - case HWTSTAMP_FILTER_PTP_V2_SYNC: - case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: - rx_filter_valid = 1; - break; - } - - if (!tx_type_valid || !rx_filter_valid) - return -ERANGE; - - return 0; -} - -/* - * Perform the SIOCxIFxxx calls, inside rtnl_lock() - */ -static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) -{ - int err; - struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); - const struct net_device_ops *ops; - - if (!dev) - return -ENODEV; - - ops = dev->netdev_ops; - - switch (cmd) { - case SIOCSIFFLAGS: /* Set interface flags */ - return dev_change_flags(dev, ifr->ifr_flags); - - case SIOCSIFMETRIC: /* Set the metric on the interface - (currently unused) */ - return -EOPNOTSUPP; - - case SIOCSIFMTU: /* Set the MTU of a device */ - return dev_set_mtu(dev, ifr->ifr_mtu); - - case SIOCSIFHWADDR: - return dev_set_mac_address(dev, &ifr->ifr_hwaddr); - - case SIOCSIFHWBROADCAST: - if (ifr->ifr_hwaddr.sa_family != dev->type) - return -EINVAL; - memcpy(dev->broadcast, ifr->ifr_hwaddr.sa_data, - min(sizeof(ifr->ifr_hwaddr.sa_data), - (size_t)dev->addr_len)); - call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); - return 0; - - case SIOCSIFMAP: - if (ops->ndo_set_config) { - if (!netif_device_present(dev)) - return -ENODEV; - return ops->ndo_set_config(dev, &ifr->ifr_map); - } - return -EOPNOTSUPP; - - case SIOCADDMULTI: - if (!ops->ndo_set_rx_mode || - ifr->ifr_hwaddr.sa_family != AF_UNSPEC) - return -EINVAL; - if (!netif_device_present(dev)) - return -ENODEV; - return dev_mc_add_global(dev, ifr->ifr_hwaddr.sa_data); - - case SIOCDELMULTI: - if (!ops->ndo_set_rx_mode || - ifr->ifr_hwaddr.sa_family != AF_UNSPEC) - return -EINVAL; - if (!netif_device_present(dev)) - return -ENODEV; - return dev_mc_del_global(dev, ifr->ifr_hwaddr.sa_data); - - case SIOCSIFTXQLEN: - if (ifr->ifr_qlen < 0) - return -EINVAL; - dev->tx_queue_len = ifr->ifr_qlen; - return 0; - - case SIOCSIFNAME: - ifr->ifr_newname[IFNAMSIZ-1] = '\0'; - return dev_change_name(dev, ifr->ifr_newname); - - case SIOCSHWTSTAMP: - err = net_hwtstamp_validate(ifr); - if (err) - return err; - /* fall through */ - - /* - * Unknown or private ioctl - */ - default: - if ((cmd >= SIOCDEVPRIVATE && - cmd <= SIOCDEVPRIVATE + 15) || - cmd == SIOCBONDENSLAVE || - cmd == SIOCBONDRELEASE || - cmd == SIOCBONDSETHWADDR || - cmd == SIOCBONDSLAVEINFOQUERY || - cmd == SIOCBONDINFOQUERY || - cmd == SIOCBONDCHANGEACTIVE || - cmd == SIOCGMIIPHY || - cmd == SIOCGMIIREG || - cmd == SIOCSMIIREG || - cmd == SIOCBRADDIF || - cmd == SIOCBRDELIF || - cmd == SIOCSHWTSTAMP || - cmd == SIOCGHWTSTAMP || - cmd == SIOCWANDEV) { - err = -EOPNOTSUPP; - if (ops->ndo_do_ioctl) { - if (netif_device_present(dev)) - err = ops->ndo_do_ioctl(dev, ifr, cmd); - else - err = -ENODEV; - } - } else - err = -EINVAL; - - } - return err; -} - -/** - * dev_load - load a network module - * @net: the applicable net namespace - * @name: name of interface - * - * If a network interface is not present and the process has suitable - * privileges this function loads the module. If module loading is not - * available in this kernel then it becomes a nop. - */ - -void dev_load(struct net *net, const char *name) -{ - struct net_device *dev; - int no_module; - - rcu_read_lock(); - dev = dev_get_by_name_rcu(net, name); - rcu_read_unlock(); - - no_module = !dev; - if (no_module && capable(CAP_NET_ADMIN)) - no_module = request_module("netdev-%s", name); - if (no_module && capable(CAP_SYS_MODULE)) - request_module("%s", name); -} -EXPORT_SYMBOL(dev_load); - -/* - * This function handles all "interface"-type I/O control requests. The actual - * 'doing' part of this is dev_ifsioc above. - */ - -/** - * dev_ioctl - network device ioctl - * @net: the applicable net namespace - * @cmd: command to issue - * @arg: pointer to a struct ifreq in user space - * - * Issue ioctl functions to devices. This is normally called by the - * user space syscall interfaces but can sometimes be useful for - * other purposes. The return value is the return from the syscall if - * positive or a negative errno code on error. - */ - -int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg) -{ - struct ifreq ifr; - int ret; - char *colon; - - /* One special case: SIOCGIFCONF takes ifconf argument - and requires shared lock, because it sleeps writing - to user space. - */ - - if (cmd == SIOCGIFCONF) { - rtnl_lock(); - ret = dev_ifconf(net, (char __user *) arg); - rtnl_unlock(); - return ret; - } - if (cmd == SIOCGIFNAME) - return dev_ifname(net, (struct ifreq __user *)arg); - - if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) - return -EFAULT; - - ifr.ifr_name[IFNAMSIZ-1] = 0; - - colon = strchr(ifr.ifr_name, ':'); - if (colon) - *colon = 0; - - /* - * See which interface the caller is talking about. - */ - - switch (cmd) { - /* - * These ioctl calls: - * - can be done by all. - * - atomic and do not require locking. - * - return a value - */ - case SIOCGIFFLAGS: - case SIOCGIFMETRIC: - case SIOCGIFMTU: - case SIOCGIFHWADDR: - case SIOCGIFSLAVE: - case SIOCGIFMAP: - case SIOCGIFINDEX: - case SIOCGIFTXQLEN: - dev_load(net, ifr.ifr_name); - rcu_read_lock(); - ret = dev_ifsioc_locked(net, &ifr, cmd); - rcu_read_unlock(); - if (!ret) { - if (colon) - *colon = ':'; - if (copy_to_user(arg, &ifr, - sizeof(struct ifreq))) - ret = -EFAULT; - } - return ret; - - case SIOCETHTOOL: - dev_load(net, ifr.ifr_name); - rtnl_lock(); - ret = dev_ethtool(net, &ifr); - rtnl_unlock(); - if (!ret) { - if (colon) - *colon = ':'; - if (copy_to_user(arg, &ifr, - sizeof(struct ifreq))) - ret = -EFAULT; - } - return ret; - - /* - * These ioctl calls: - * - require superuser power. - * - require strict serialization. - * - return a value - */ - case SIOCGMIIPHY: - case SIOCGMIIREG: - case SIOCSIFNAME: - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - return -EPERM; - dev_load(net, ifr.ifr_name); - rtnl_lock(); - ret = dev_ifsioc(net, &ifr, cmd); - rtnl_unlock(); - if (!ret) { - if (colon) - *colon = ':'; - if (copy_to_user(arg, &ifr, - sizeof(struct ifreq))) - ret = -EFAULT; - } - return ret; - - /* - * These ioctl calls: - * - require superuser power. - * - require strict serialization. - * - do not return a value - */ - case SIOCSIFMAP: - case SIOCSIFTXQLEN: - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - /* fall through */ - /* - * These ioctl calls: - * - require local superuser power. - * - require strict serialization. - * - do not return a value - */ - case SIOCSIFFLAGS: - case SIOCSIFMETRIC: - case SIOCSIFMTU: - case SIOCSIFHWADDR: - case SIOCSIFSLAVE: - case SIOCADDMULTI: - case SIOCDELMULTI: - case SIOCSIFHWBROADCAST: - case SIOCSMIIREG: - case SIOCBONDENSLAVE: - case SIOCBONDRELEASE: - case SIOCBONDSETHWADDR: - case SIOCBONDCHANGEACTIVE: - case SIOCBRADDIF: - case SIOCBRDELIF: - case SIOCSHWTSTAMP: - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - return -EPERM; - /* fall through */ - case SIOCBONDSLAVEINFOQUERY: - case SIOCBONDINFOQUERY: - dev_load(net, ifr.ifr_name); - rtnl_lock(); - ret = dev_ifsioc(net, &ifr, cmd); - rtnl_unlock(); - return ret; - - case SIOCGIFMEM: - /* Get the per device memory space. We can add this but - * currently do not support it */ - case SIOCSIFMEM: - /* Set the per device memory buffer space. - * Not applicable in our case */ - case SIOCSIFLINK: - return -ENOTTY; - - /* - * Unknown or private ioctl. - */ - default: - if (cmd == SIOCWANDEV || - cmd == SIOCGHWTSTAMP || - (cmd >= SIOCDEVPRIVATE && - cmd <= SIOCDEVPRIVATE + 15)) { - dev_load(net, ifr.ifr_name); - rtnl_lock(); - ret = dev_ifsioc(net, &ifr, cmd); - rtnl_unlock(); - if (!ret && copy_to_user(arg, &ifr, - sizeof(struct ifreq))) - ret = -EFAULT; - return ret; - } - /* Take care of Wireless Extensions */ - if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) - return wext_handle_ioctl(net, &ifr, cmd, arg); - return -ENOTTY; - } -} diff --git a/src/linux/net/core/dst.c b/src/linux/net/core/dst.c deleted file mode 100644 index b5cbbe0..0000000 --- a/src/linux/net/core/dst.c +++ /dev/null @@ -1,490 +0,0 @@ -/* - * net/core/dst.c Protocol independent destination cache. - * - * Authors: Alexey Kuznetsov, - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -/* - * Theory of operations: - * 1) We use a list, protected by a spinlock, to add - * new entries from both BH and non-BH context. - * 2) In order to keep spinlock held for a small delay, - * we use a second list where are stored long lived - * entries, that are handled by the garbage collect thread - * fired by a workqueue. - * 3) This list is guarded by a mutex, - * so that the gc_task and dst_dev_event() can be synchronized. - */ - -/* - * We want to keep lock & list close together - * to dirty as few cache lines as possible in __dst_free(). - * As this is not a very strong hint, we dont force an alignment on SMP. - */ -static struct { - spinlock_t lock; - struct dst_entry *list; - unsigned long timer_inc; - unsigned long timer_expires; -} dst_garbage = { - .lock = __SPIN_LOCK_UNLOCKED(dst_garbage.lock), - .timer_inc = DST_GC_MAX, -}; -static void dst_gc_task(struct work_struct *work); -static void ___dst_free(struct dst_entry *dst); - -static DECLARE_DELAYED_WORK(dst_gc_work, dst_gc_task); - -static DEFINE_MUTEX(dst_gc_mutex); -/* - * long lived entries are maintained in this list, guarded by dst_gc_mutex - */ -static struct dst_entry *dst_busy_list; - -static void dst_gc_task(struct work_struct *work) -{ - int delayed = 0; - int work_performed = 0; - unsigned long expires = ~0L; - struct dst_entry *dst, *next, head; - struct dst_entry *last = &head; - - mutex_lock(&dst_gc_mutex); - next = dst_busy_list; - -loop: - while ((dst = next) != NULL) { - next = dst->next; - prefetch(&next->next); - cond_resched(); - if (likely(atomic_read(&dst->__refcnt))) { - last->next = dst; - last = dst; - delayed++; - continue; - } - work_performed++; - - dst = dst_destroy(dst); - if (dst) { - /* NOHASH and still referenced. Unless it is already - * on gc list, invalidate it and add to gc list. - * - * Note: this is temporary. Actually, NOHASH dst's - * must be obsoleted when parent is obsoleted. - * But we do not have state "obsoleted, but - * referenced by parent", so it is right. - */ - if (dst->obsolete > 0) - continue; - - ___dst_free(dst); - dst->next = next; - next = dst; - } - } - - spin_lock_bh(&dst_garbage.lock); - next = dst_garbage.list; - if (next) { - dst_garbage.list = NULL; - spin_unlock_bh(&dst_garbage.lock); - goto loop; - } - last->next = NULL; - dst_busy_list = head.next; - if (!dst_busy_list) - dst_garbage.timer_inc = DST_GC_MAX; - else { - /* - * if we freed less than 1/10 of delayed entries, - * we can sleep longer. - */ - if (work_performed <= delayed/10) { - dst_garbage.timer_expires += dst_garbage.timer_inc; - if (dst_garbage.timer_expires > DST_GC_MAX) - dst_garbage.timer_expires = DST_GC_MAX; - dst_garbage.timer_inc += DST_GC_INC; - } else { - dst_garbage.timer_inc = DST_GC_INC; - dst_garbage.timer_expires = DST_GC_MIN; - } - expires = dst_garbage.timer_expires; - /* - * if the next desired timer is more than 4 seconds in the - * future then round the timer to whole seconds - */ - if (expires > 4*HZ) - expires = round_jiffies_relative(expires); - schedule_delayed_work(&dst_gc_work, expires); - } - - spin_unlock_bh(&dst_garbage.lock); - mutex_unlock(&dst_gc_mutex); -} - -int dst_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - kfree_skb(skb); - return 0; -} -EXPORT_SYMBOL(dst_discard_out); - -const u32 dst_default_metrics[RTAX_MAX + 1] = { - /* This initializer is needed to force linker to place this variable - * into const section. Otherwise it might end into bss section. - * We really want to avoid false sharing on this variable, and catch - * any writes on it. - */ - [RTAX_MAX] = 0xdeadbeef, -}; - -void dst_init(struct dst_entry *dst, struct dst_ops *ops, - struct net_device *dev, int initial_ref, int initial_obsolete, - unsigned short flags) -{ - dst->child = NULL; - dst->dev = dev; - if (dev) - dev_hold(dev); - dst->ops = ops; - dst_init_metrics(dst, dst_default_metrics, true); - dst->expires = 0UL; - dst->path = dst; - dst->from = NULL; -#ifdef CONFIG_XFRM - dst->xfrm = NULL; -#endif - dst->input = dst_discard; - dst->output = dst_discard_out; - dst->error = 0; - dst->obsolete = initial_obsolete; - dst->header_len = 0; - dst->trailer_len = 0; -#ifdef CONFIG_IP_ROUTE_CLASSID - dst->tclassid = 0; -#endif - dst->lwtstate = NULL; - atomic_set(&dst->__refcnt, initial_ref); - dst->__use = 0; - dst->lastuse = jiffies; - dst->flags = flags; - dst->pending_confirm = 0; - dst->next = NULL; - if (!(flags & DST_NOCOUNT)) - dst_entries_add(ops, 1); -} -EXPORT_SYMBOL(dst_init); - -void *dst_alloc(struct dst_ops *ops, struct net_device *dev, - int initial_ref, int initial_obsolete, unsigned short flags) -{ - struct dst_entry *dst; - - if (ops->gc && dst_entries_get_fast(ops) > ops->gc_thresh) { - if (ops->gc(ops)) - return NULL; - } - - dst = kmem_cache_alloc(ops->kmem_cachep, GFP_ATOMIC); - if (!dst) - return NULL; - - dst_init(dst, ops, dev, initial_ref, initial_obsolete, flags); - - return dst; -} -EXPORT_SYMBOL(dst_alloc); - -static void ___dst_free(struct dst_entry *dst) -{ - /* The first case (dev==NULL) is required, when - protocol module is unloaded. - */ - if (dst->dev == NULL || !(dst->dev->flags&IFF_UP)) { - dst->input = dst_discard; - dst->output = dst_discard_out; - } - dst->obsolete = DST_OBSOLETE_DEAD; -} - -void __dst_free(struct dst_entry *dst) -{ - spin_lock_bh(&dst_garbage.lock); - ___dst_free(dst); - dst->next = dst_garbage.list; - dst_garbage.list = dst; - if (dst_garbage.timer_inc > DST_GC_INC) { - dst_garbage.timer_inc = DST_GC_INC; - dst_garbage.timer_expires = DST_GC_MIN; - mod_delayed_work(system_wq, &dst_gc_work, - dst_garbage.timer_expires); - } - spin_unlock_bh(&dst_garbage.lock); -} -EXPORT_SYMBOL(__dst_free); - -struct dst_entry *dst_destroy(struct dst_entry * dst) -{ - struct dst_entry *child; - - smp_rmb(); - -again: - child = dst->child; - - if (!(dst->flags & DST_NOCOUNT)) - dst_entries_add(dst->ops, -1); - - if (dst->ops->destroy) - dst->ops->destroy(dst); - if (dst->dev) - dev_put(dst->dev); - - lwtstate_put(dst->lwtstate); - - if (dst->flags & DST_METADATA) - metadata_dst_free((struct metadata_dst *)dst); - else - kmem_cache_free(dst->ops->kmem_cachep, dst); - - dst = child; - if (dst) { - int nohash = dst->flags & DST_NOHASH; - - if (atomic_dec_and_test(&dst->__refcnt)) { - /* We were real parent of this dst, so kill child. */ - if (nohash) - goto again; - } else { - /* Child is still referenced, return it for freeing. */ - if (nohash) - return dst; - /* Child is still in his hash table */ - } - } - return NULL; -} -EXPORT_SYMBOL(dst_destroy); - -static void dst_destroy_rcu(struct rcu_head *head) -{ - struct dst_entry *dst = container_of(head, struct dst_entry, rcu_head); - - dst = dst_destroy(dst); - if (dst) - __dst_free(dst); -} - -void dst_release(struct dst_entry *dst) -{ - if (dst) { - int newrefcnt; - unsigned short nocache = dst->flags & DST_NOCACHE; - - newrefcnt = atomic_dec_return(&dst->__refcnt); - if (unlikely(newrefcnt < 0)) - net_warn_ratelimited("%s: dst:%p refcnt:%d\n", - __func__, dst, newrefcnt); - if (!newrefcnt && unlikely(nocache)) - call_rcu(&dst->rcu_head, dst_destroy_rcu); - } -} -EXPORT_SYMBOL(dst_release); - -u32 *dst_cow_metrics_generic(struct dst_entry *dst, unsigned long old) -{ - u32 *p = kmalloc(sizeof(u32) * RTAX_MAX, GFP_ATOMIC); - - if (p) { - u32 *old_p = __DST_METRICS_PTR(old); - unsigned long prev, new; - - memcpy(p, old_p, sizeof(u32) * RTAX_MAX); - - new = (unsigned long) p; - prev = cmpxchg(&dst->_metrics, old, new); - - if (prev != old) { - kfree(p); - p = __DST_METRICS_PTR(prev); - if (prev & DST_METRICS_READ_ONLY) - p = NULL; - } - } - return p; -} -EXPORT_SYMBOL(dst_cow_metrics_generic); - -/* Caller asserts that dst_metrics_read_only(dst) is false. */ -void __dst_destroy_metrics_generic(struct dst_entry *dst, unsigned long old) -{ - unsigned long prev, new; - - new = ((unsigned long) dst_default_metrics) | DST_METRICS_READ_ONLY; - prev = cmpxchg(&dst->_metrics, old, new); - if (prev == old) - kfree(__DST_METRICS_PTR(old)); -} -EXPORT_SYMBOL(__dst_destroy_metrics_generic); - -static struct dst_ops md_dst_ops = { - .family = AF_UNSPEC, -}; - -static int dst_md_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - WARN_ONCE(1, "Attempting to call output on metadata dst\n"); - kfree_skb(skb); - return 0; -} - -static int dst_md_discard(struct sk_buff *skb) -{ - WARN_ONCE(1, "Attempting to call input on metadata dst\n"); - kfree_skb(skb); - return 0; -} - -static void __metadata_dst_init(struct metadata_dst *md_dst, u8 optslen) -{ - struct dst_entry *dst; - - dst = &md_dst->dst; - dst_init(dst, &md_dst_ops, NULL, 1, DST_OBSOLETE_NONE, - DST_METADATA | DST_NOCACHE | DST_NOCOUNT); - - dst->input = dst_md_discard; - dst->output = dst_md_discard_out; - - memset(dst + 1, 0, sizeof(*md_dst) + optslen - sizeof(*dst)); -} - -struct metadata_dst *metadata_dst_alloc(u8 optslen, gfp_t flags) -{ - struct metadata_dst *md_dst; - - md_dst = kmalloc(sizeof(*md_dst) + optslen, flags); - if (!md_dst) - return NULL; - - __metadata_dst_init(md_dst, optslen); - - return md_dst; -} -EXPORT_SYMBOL_GPL(metadata_dst_alloc); - -void metadata_dst_free(struct metadata_dst *md_dst) -{ -#ifdef CONFIG_DST_CACHE - dst_cache_destroy(&md_dst->u.tun_info.dst_cache); -#endif - kfree(md_dst); -} - -struct metadata_dst __percpu *metadata_dst_alloc_percpu(u8 optslen, gfp_t flags) -{ - int cpu; - struct metadata_dst __percpu *md_dst; - - md_dst = __alloc_percpu_gfp(sizeof(struct metadata_dst) + optslen, - __alignof__(struct metadata_dst), flags); - if (!md_dst) - return NULL; - - for_each_possible_cpu(cpu) - __metadata_dst_init(per_cpu_ptr(md_dst, cpu), optslen); - - return md_dst; -} -EXPORT_SYMBOL_GPL(metadata_dst_alloc_percpu); - -/* Dirty hack. We did it in 2.2 (in __dst_free), - * we have _very_ good reasons not to repeat - * this mistake in 2.3, but we have no choice - * now. _It_ _is_ _explicit_ _deliberate_ - * _race_ _condition_. - * - * Commented and originally written by Alexey. - */ -static void dst_ifdown(struct dst_entry *dst, struct net_device *dev, - int unregister) -{ - if (dst->ops->ifdown) - dst->ops->ifdown(dst, dev, unregister); - - if (dev != dst->dev) - return; - - if (!unregister) { - dst->input = dst_discard; - dst->output = dst_discard_out; - } else { - dst->dev = dev_net(dst->dev)->loopback_dev; - dev_hold(dst->dev); - dev_put(dev); - } -} - -static int dst_dev_event(struct notifier_block *this, unsigned long event, - void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct dst_entry *dst, *last = NULL; - - switch (event) { - case NETDEV_UNREGISTER_FINAL: - case NETDEV_DOWN: - mutex_lock(&dst_gc_mutex); - for (dst = dst_busy_list; dst; dst = dst->next) { - last = dst; - dst_ifdown(dst, dev, event != NETDEV_DOWN); - } - - spin_lock_bh(&dst_garbage.lock); - dst = dst_garbage.list; - dst_garbage.list = NULL; - spin_unlock_bh(&dst_garbage.lock); - - if (last) - last->next = dst; - else - dst_busy_list = dst; - for (; dst; dst = dst->next) - dst_ifdown(dst, dev, event != NETDEV_DOWN); - mutex_unlock(&dst_gc_mutex); - break; - } - return NOTIFY_DONE; -} - -static struct notifier_block dst_dev_notifier = { - .notifier_call = dst_dev_event, - .priority = -10, /* must be called after other network notifiers */ -}; - -void __init dst_subsys_init(void) -{ - register_netdevice_notifier(&dst_dev_notifier); -} diff --git a/src/linux/net/core/dst_cache.c b/src/linux/net/core/dst_cache.c deleted file mode 100644 index 554d364..0000000 --- a/src/linux/net/core/dst_cache.c +++ /dev/null @@ -1,168 +0,0 @@ -/* - * net/core/dst_cache.c - dst entry cache - * - * Copyright (c) 2016 Paolo Abeni - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#if IS_ENABLED(CONFIG_IPV6) -#include -#endif -#include - -struct dst_cache_pcpu { - unsigned long refresh_ts; - struct dst_entry *dst; - u32 cookie; - union { - struct in_addr in_saddr; - struct in6_addr in6_saddr; - }; -}; - -static void dst_cache_per_cpu_dst_set(struct dst_cache_pcpu *dst_cache, - struct dst_entry *dst, u32 cookie) -{ - dst_release(dst_cache->dst); - if (dst) - dst_hold(dst); - - dst_cache->cookie = cookie; - dst_cache->dst = dst; -} - -static struct dst_entry *dst_cache_per_cpu_get(struct dst_cache *dst_cache, - struct dst_cache_pcpu *idst) -{ - struct dst_entry *dst; - - dst = idst->dst; - if (!dst) - goto fail; - - /* the cache already hold a dst reference; it can't go away */ - dst_hold(dst); - - if (unlikely(!time_after(idst->refresh_ts, dst_cache->reset_ts) || - (dst->obsolete && !dst->ops->check(dst, idst->cookie)))) { - dst_cache_per_cpu_dst_set(idst, NULL, 0); - dst_release(dst); - goto fail; - } - return dst; - -fail: - idst->refresh_ts = jiffies; - return NULL; -} - -struct dst_entry *dst_cache_get(struct dst_cache *dst_cache) -{ - if (!dst_cache->cache) - return NULL; - - return dst_cache_per_cpu_get(dst_cache, this_cpu_ptr(dst_cache->cache)); -} -EXPORT_SYMBOL_GPL(dst_cache_get); - -struct rtable *dst_cache_get_ip4(struct dst_cache *dst_cache, __be32 *saddr) -{ - struct dst_cache_pcpu *idst; - struct dst_entry *dst; - - if (!dst_cache->cache) - return NULL; - - idst = this_cpu_ptr(dst_cache->cache); - dst = dst_cache_per_cpu_get(dst_cache, idst); - if (!dst) - return NULL; - - *saddr = idst->in_saddr.s_addr; - return container_of(dst, struct rtable, dst); -} -EXPORT_SYMBOL_GPL(dst_cache_get_ip4); - -void dst_cache_set_ip4(struct dst_cache *dst_cache, struct dst_entry *dst, - __be32 saddr) -{ - struct dst_cache_pcpu *idst; - - if (!dst_cache->cache) - return; - - idst = this_cpu_ptr(dst_cache->cache); - dst_cache_per_cpu_dst_set(idst, dst, 0); - idst->in_saddr.s_addr = saddr; -} -EXPORT_SYMBOL_GPL(dst_cache_set_ip4); - -#if IS_ENABLED(CONFIG_IPV6) -void dst_cache_set_ip6(struct dst_cache *dst_cache, struct dst_entry *dst, - const struct in6_addr *addr) -{ - struct dst_cache_pcpu *idst; - - if (!dst_cache->cache) - return; - - idst = this_cpu_ptr(dst_cache->cache); - dst_cache_per_cpu_dst_set(this_cpu_ptr(dst_cache->cache), dst, - rt6_get_cookie((struct rt6_info *)dst)); - idst->in6_saddr = *addr; -} -EXPORT_SYMBOL_GPL(dst_cache_set_ip6); - -struct dst_entry *dst_cache_get_ip6(struct dst_cache *dst_cache, - struct in6_addr *saddr) -{ - struct dst_cache_pcpu *idst; - struct dst_entry *dst; - - if (!dst_cache->cache) - return NULL; - - idst = this_cpu_ptr(dst_cache->cache); - dst = dst_cache_per_cpu_get(dst_cache, idst); - if (!dst) - return NULL; - - *saddr = idst->in6_saddr; - return dst; -} -EXPORT_SYMBOL_GPL(dst_cache_get_ip6); -#endif - -int dst_cache_init(struct dst_cache *dst_cache, gfp_t gfp) -{ - dst_cache->cache = alloc_percpu_gfp(struct dst_cache_pcpu, - gfp | __GFP_ZERO); - if (!dst_cache->cache) - return -ENOMEM; - - dst_cache_reset(dst_cache); - return 0; -} -EXPORT_SYMBOL_GPL(dst_cache_init); - -void dst_cache_destroy(struct dst_cache *dst_cache) -{ - int i; - - if (!dst_cache->cache) - return; - - for_each_possible_cpu(i) - dst_release(per_cpu_ptr(dst_cache->cache, i)->dst); - - free_percpu(dst_cache->cache); -} -EXPORT_SYMBOL_GPL(dst_cache_destroy); diff --git a/src/linux/net/core/ethtool.c b/src/linux/net/core/ethtool.c deleted file mode 100644 index 047a175..0000000 --- a/src/linux/net/core/ethtool.c +++ /dev/null @@ -1,2699 +0,0 @@ -/* - * net/core/ethtool.c - Ethtool ioctl handler - * Copyright (c) 2003 Matthew Wilcox - * - * This file is where we call all the ethtool_ops commands to get - * the information ethtool needs. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Some useful ethtool_ops methods that're device independent. - * If we find that all drivers want to do the same thing here, - * we can turn these into dev_() function calls. - */ - -u32 ethtool_op_get_link(struct net_device *dev) -{ - return netif_carrier_ok(dev) ? 1 : 0; -} -EXPORT_SYMBOL(ethtool_op_get_link); - -int ethtool_op_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info) -{ - info->so_timestamping = - SOF_TIMESTAMPING_TX_SOFTWARE | - SOF_TIMESTAMPING_RX_SOFTWARE | - SOF_TIMESTAMPING_SOFTWARE; - info->phc_index = -1; - return 0; -} -EXPORT_SYMBOL(ethtool_op_get_ts_info); - -/* Handlers for each ethtool command */ - -#define ETHTOOL_DEV_FEATURE_WORDS ((NETDEV_FEATURE_COUNT + 31) / 32) - -static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = { - [NETIF_F_SG_BIT] = "tx-scatter-gather", - [NETIF_F_IP_CSUM_BIT] = "tx-checksum-ipv4", - [NETIF_F_HW_CSUM_BIT] = "tx-checksum-ip-generic", - [NETIF_F_IPV6_CSUM_BIT] = "tx-checksum-ipv6", - [NETIF_F_HIGHDMA_BIT] = "highdma", - [NETIF_F_FRAGLIST_BIT] = "tx-scatter-gather-fraglist", - [NETIF_F_HW_VLAN_CTAG_TX_BIT] = "tx-vlan-hw-insert", - - [NETIF_F_HW_VLAN_CTAG_RX_BIT] = "rx-vlan-hw-parse", - [NETIF_F_HW_VLAN_CTAG_FILTER_BIT] = "rx-vlan-filter", - [NETIF_F_HW_VLAN_STAG_TX_BIT] = "tx-vlan-stag-hw-insert", - [NETIF_F_HW_VLAN_STAG_RX_BIT] = "rx-vlan-stag-hw-parse", - [NETIF_F_HW_VLAN_STAG_FILTER_BIT] = "rx-vlan-stag-filter", - [NETIF_F_VLAN_CHALLENGED_BIT] = "vlan-challenged", - [NETIF_F_GSO_BIT] = "tx-generic-segmentation", - [NETIF_F_LLTX_BIT] = "tx-lockless", - [NETIF_F_NETNS_LOCAL_BIT] = "netns-local", - [NETIF_F_GRO_BIT] = "rx-gro", - [NETIF_F_LRO_BIT] = "rx-lro", - - [NETIF_F_TSO_BIT] = "tx-tcp-segmentation", - [NETIF_F_UFO_BIT] = "tx-udp-fragmentation", - [NETIF_F_GSO_ROBUST_BIT] = "tx-gso-robust", - [NETIF_F_TSO_ECN_BIT] = "tx-tcp-ecn-segmentation", - [NETIF_F_TSO_MANGLEID_BIT] = "tx-tcp-mangleid-segmentation", - [NETIF_F_TSO6_BIT] = "tx-tcp6-segmentation", - [NETIF_F_FSO_BIT] = "tx-fcoe-segmentation", - [NETIF_F_GSO_GRE_BIT] = "tx-gre-segmentation", - [NETIF_F_GSO_GRE_CSUM_BIT] = "tx-gre-csum-segmentation", - [NETIF_F_GSO_IPXIP4_BIT] = "tx-ipxip4-segmentation", - [NETIF_F_GSO_IPXIP6_BIT] = "tx-ipxip6-segmentation", - [NETIF_F_GSO_UDP_TUNNEL_BIT] = "tx-udp_tnl-segmentation", - [NETIF_F_GSO_UDP_TUNNEL_CSUM_BIT] = "tx-udp_tnl-csum-segmentation", - [NETIF_F_GSO_PARTIAL_BIT] = "tx-gso-partial", - [NETIF_F_GSO_SCTP_BIT] = "tx-sctp-segmentation", - - [NETIF_F_FCOE_CRC_BIT] = "tx-checksum-fcoe-crc", - [NETIF_F_SCTP_CRC_BIT] = "tx-checksum-sctp", - [NETIF_F_FCOE_MTU_BIT] = "fcoe-mtu", - [NETIF_F_NTUPLE_BIT] = "rx-ntuple-filter", - [NETIF_F_RXHASH_BIT] = "rx-hashing", - [NETIF_F_RXCSUM_BIT] = "rx-checksum", - [NETIF_F_NOCACHE_COPY_BIT] = "tx-nocache-copy", - [NETIF_F_LOOPBACK_BIT] = "loopback", - [NETIF_F_RXFCS_BIT] = "rx-fcs", - [NETIF_F_RXALL_BIT] = "rx-all", - [NETIF_F_HW_L2FW_DOFFLOAD_BIT] = "l2-fwd-offload", - [NETIF_F_BUSY_POLL_BIT] = "busy-poll", - [NETIF_F_HW_TC_BIT] = "hw-tc-offload", -}; - -static const char -rss_hash_func_strings[ETH_RSS_HASH_FUNCS_COUNT][ETH_GSTRING_LEN] = { - [ETH_RSS_HASH_TOP_BIT] = "toeplitz", - [ETH_RSS_HASH_XOR_BIT] = "xor", -}; - -static const char -tunable_strings[__ETHTOOL_TUNABLE_COUNT][ETH_GSTRING_LEN] = { - [ETHTOOL_ID_UNSPEC] = "Unspec", - [ETHTOOL_RX_COPYBREAK] = "rx-copybreak", - [ETHTOOL_TX_COPYBREAK] = "tx-copybreak", -}; - -static int ethtool_get_features(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_gfeatures cmd = { - .cmd = ETHTOOL_GFEATURES, - .size = ETHTOOL_DEV_FEATURE_WORDS, - }; - struct ethtool_get_features_block features[ETHTOOL_DEV_FEATURE_WORDS]; - u32 __user *sizeaddr; - u32 copy_size; - int i; - - /* in case feature bits run out again */ - BUILD_BUG_ON(ETHTOOL_DEV_FEATURE_WORDS * sizeof(u32) > sizeof(netdev_features_t)); - - for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) { - features[i].available = (u32)(dev->hw_features >> (32 * i)); - features[i].requested = (u32)(dev->wanted_features >> (32 * i)); - features[i].active = (u32)(dev->features >> (32 * i)); - features[i].never_changed = - (u32)(NETIF_F_NEVER_CHANGE >> (32 * i)); - } - - sizeaddr = useraddr + offsetof(struct ethtool_gfeatures, size); - if (get_user(copy_size, sizeaddr)) - return -EFAULT; - - if (copy_size > ETHTOOL_DEV_FEATURE_WORDS) - copy_size = ETHTOOL_DEV_FEATURE_WORDS; - - if (copy_to_user(useraddr, &cmd, sizeof(cmd))) - return -EFAULT; - useraddr += sizeof(cmd); - if (copy_to_user(useraddr, features, copy_size * sizeof(*features))) - return -EFAULT; - - return 0; -} - -static int ethtool_set_features(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_sfeatures cmd; - struct ethtool_set_features_block features[ETHTOOL_DEV_FEATURE_WORDS]; - netdev_features_t wanted = 0, valid = 0; - int i, ret = 0; - - if (copy_from_user(&cmd, useraddr, sizeof(cmd))) - return -EFAULT; - useraddr += sizeof(cmd); - - if (cmd.size != ETHTOOL_DEV_FEATURE_WORDS) - return -EINVAL; - - if (copy_from_user(features, useraddr, sizeof(features))) - return -EFAULT; - - for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) { - valid |= (netdev_features_t)features[i].valid << (32 * i); - wanted |= (netdev_features_t)features[i].requested << (32 * i); - } - - if (valid & ~NETIF_F_ETHTOOL_BITS) - return -EINVAL; - - if (valid & ~dev->hw_features) { - valid &= dev->hw_features; - ret |= ETHTOOL_F_UNSUPPORTED; - } - - dev->wanted_features &= ~valid; - dev->wanted_features |= wanted & valid; - __netdev_update_features(dev); - - if ((dev->wanted_features ^ dev->features) & valid) - ret |= ETHTOOL_F_WISH; - - return ret; -} - -static int phy_get_sset_count(struct phy_device *phydev) -{ - int ret; - - if (phydev->drv->get_sset_count && - phydev->drv->get_strings && - phydev->drv->get_stats) { - mutex_lock(&phydev->lock); - ret = phydev->drv->get_sset_count(phydev); - mutex_unlock(&phydev->lock); - - return ret; - } - - return -EOPNOTSUPP; -} - -static int __ethtool_get_sset_count(struct net_device *dev, int sset) -{ - const struct ethtool_ops *ops = dev->ethtool_ops; - - if (sset == ETH_SS_FEATURES) - return ARRAY_SIZE(netdev_features_strings); - - if (sset == ETH_SS_RSS_HASH_FUNCS) - return ARRAY_SIZE(rss_hash_func_strings); - - if (sset == ETH_SS_TUNABLES) - return ARRAY_SIZE(tunable_strings); - - if (sset == ETH_SS_PHY_STATS) { - if (dev->phydev) - return phy_get_sset_count(dev->phydev); - else - return -EOPNOTSUPP; - } - - if (ops->get_sset_count && ops->get_strings) - return ops->get_sset_count(dev, sset); - else - return -EOPNOTSUPP; -} - -static void __ethtool_get_strings(struct net_device *dev, - u32 stringset, u8 *data) -{ - const struct ethtool_ops *ops = dev->ethtool_ops; - - if (stringset == ETH_SS_FEATURES) - memcpy(data, netdev_features_strings, - sizeof(netdev_features_strings)); - else if (stringset == ETH_SS_RSS_HASH_FUNCS) - memcpy(data, rss_hash_func_strings, - sizeof(rss_hash_func_strings)); - else if (stringset == ETH_SS_TUNABLES) - memcpy(data, tunable_strings, sizeof(tunable_strings)); - else if (stringset == ETH_SS_PHY_STATS) { - struct phy_device *phydev = dev->phydev; - - if (phydev) { - mutex_lock(&phydev->lock); - phydev->drv->get_strings(phydev, data); - mutex_unlock(&phydev->lock); - } else { - return; - } - } else - /* ops->get_strings is valid because checked earlier */ - ops->get_strings(dev, stringset, data); -} - -static netdev_features_t ethtool_get_feature_mask(u32 eth_cmd) -{ - /* feature masks of legacy discrete ethtool ops */ - - switch (eth_cmd) { - case ETHTOOL_GTXCSUM: - case ETHTOOL_STXCSUM: - return NETIF_F_CSUM_MASK | NETIF_F_SCTP_CRC; - case ETHTOOL_GRXCSUM: - case ETHTOOL_SRXCSUM: - return NETIF_F_RXCSUM; - case ETHTOOL_GSG: - case ETHTOOL_SSG: - return NETIF_F_SG; - case ETHTOOL_GTSO: - case ETHTOOL_STSO: - return NETIF_F_ALL_TSO; - case ETHTOOL_GUFO: - case ETHTOOL_SUFO: - return NETIF_F_UFO; - case ETHTOOL_GGSO: - case ETHTOOL_SGSO: - return NETIF_F_GSO; - case ETHTOOL_GGRO: - case ETHTOOL_SGRO: - return NETIF_F_GRO; - default: - BUG(); - } -} - -static int ethtool_get_one_feature(struct net_device *dev, - char __user *useraddr, u32 ethcmd) -{ - netdev_features_t mask = ethtool_get_feature_mask(ethcmd); - struct ethtool_value edata = { - .cmd = ethcmd, - .data = !!(dev->features & mask), - }; - - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; -} - -static int ethtool_set_one_feature(struct net_device *dev, - void __user *useraddr, u32 ethcmd) -{ - struct ethtool_value edata; - netdev_features_t mask; - - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - - mask = ethtool_get_feature_mask(ethcmd); - mask &= dev->hw_features; - if (!mask) - return -EOPNOTSUPP; - - if (edata.data) - dev->wanted_features |= mask; - else - dev->wanted_features &= ~mask; - - __netdev_update_features(dev); - - return 0; -} - -#define ETH_ALL_FLAGS (ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | \ - ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH) -#define ETH_ALL_FEATURES (NETIF_F_LRO | NETIF_F_HW_VLAN_CTAG_RX | \ - NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_NTUPLE | \ - NETIF_F_RXHASH) - -static u32 __ethtool_get_flags(struct net_device *dev) -{ - u32 flags = 0; - - if (dev->features & NETIF_F_LRO) - flags |= ETH_FLAG_LRO; - if (dev->features & NETIF_F_HW_VLAN_CTAG_RX) - flags |= ETH_FLAG_RXVLAN; - if (dev->features & NETIF_F_HW_VLAN_CTAG_TX) - flags |= ETH_FLAG_TXVLAN; - if (dev->features & NETIF_F_NTUPLE) - flags |= ETH_FLAG_NTUPLE; - if (dev->features & NETIF_F_RXHASH) - flags |= ETH_FLAG_RXHASH; - - return flags; -} - -static int __ethtool_set_flags(struct net_device *dev, u32 data) -{ - netdev_features_t features = 0, changed; - - if (data & ~ETH_ALL_FLAGS) - return -EINVAL; - - if (data & ETH_FLAG_LRO) - features |= NETIF_F_LRO; - if (data & ETH_FLAG_RXVLAN) - features |= NETIF_F_HW_VLAN_CTAG_RX; - if (data & ETH_FLAG_TXVLAN) - features |= NETIF_F_HW_VLAN_CTAG_TX; - if (data & ETH_FLAG_NTUPLE) - features |= NETIF_F_NTUPLE; - if (data & ETH_FLAG_RXHASH) - features |= NETIF_F_RXHASH; - - /* allow changing only bits set in hw_features */ - changed = (features ^ dev->features) & ETH_ALL_FEATURES; - if (changed & ~dev->hw_features) - return (changed & dev->hw_features) ? -EINVAL : -EOPNOTSUPP; - - dev->wanted_features = - (dev->wanted_features & ~changed) | (features & changed); - - __netdev_update_features(dev); - - return 0; -} - -void ethtool_convert_legacy_u32_to_link_mode(unsigned long *dst, - u32 legacy_u32) -{ - bitmap_zero(dst, __ETHTOOL_LINK_MODE_MASK_NBITS); - dst[0] = legacy_u32; -} -EXPORT_SYMBOL(ethtool_convert_legacy_u32_to_link_mode); - -/* return false if src had higher bits set. lower bits always updated. */ -bool ethtool_convert_link_mode_to_legacy_u32(u32 *legacy_u32, - const unsigned long *src) -{ - bool retval = true; - - /* TODO: following test will soon always be true */ - if (__ETHTOOL_LINK_MODE_MASK_NBITS > 32) { - __ETHTOOL_DECLARE_LINK_MODE_MASK(ext); - - bitmap_zero(ext, __ETHTOOL_LINK_MODE_MASK_NBITS); - bitmap_fill(ext, 32); - bitmap_complement(ext, ext, __ETHTOOL_LINK_MODE_MASK_NBITS); - if (bitmap_intersects(ext, src, - __ETHTOOL_LINK_MODE_MASK_NBITS)) { - /* src mask goes beyond bit 31 */ - retval = false; - } - } - *legacy_u32 = src[0]; - return retval; -} -EXPORT_SYMBOL(ethtool_convert_link_mode_to_legacy_u32); - -/* return false if legacy contained non-0 deprecated fields - * transceiver/maxtxpkt/maxrxpkt. rest of ksettings always updated - */ -static bool -convert_legacy_settings_to_link_ksettings( - struct ethtool_link_ksettings *link_ksettings, - const struct ethtool_cmd *legacy_settings) -{ - bool retval = true; - - memset(link_ksettings, 0, sizeof(*link_ksettings)); - - /* This is used to tell users that driver is still using these - * deprecated legacy fields, and they should not use - * %ETHTOOL_GLINKSETTINGS/%ETHTOOL_SLINKSETTINGS - */ - if (legacy_settings->transceiver || - legacy_settings->maxtxpkt || - legacy_settings->maxrxpkt) - retval = false; - - ethtool_convert_legacy_u32_to_link_mode( - link_ksettings->link_modes.supported, - legacy_settings->supported); - ethtool_convert_legacy_u32_to_link_mode( - link_ksettings->link_modes.advertising, - legacy_settings->advertising); - ethtool_convert_legacy_u32_to_link_mode( - link_ksettings->link_modes.lp_advertising, - legacy_settings->lp_advertising); - link_ksettings->base.speed - = ethtool_cmd_speed(legacy_settings); - link_ksettings->base.duplex - = legacy_settings->duplex; - link_ksettings->base.port - = legacy_settings->port; - link_ksettings->base.phy_address - = legacy_settings->phy_address; - link_ksettings->base.autoneg - = legacy_settings->autoneg; - link_ksettings->base.mdio_support - = legacy_settings->mdio_support; - link_ksettings->base.eth_tp_mdix - = legacy_settings->eth_tp_mdix; - link_ksettings->base.eth_tp_mdix_ctrl - = legacy_settings->eth_tp_mdix_ctrl; - return retval; -} - -/* return false if ksettings link modes had higher bits - * set. legacy_settings always updated (best effort) - */ -static bool -convert_link_ksettings_to_legacy_settings( - struct ethtool_cmd *legacy_settings, - const struct ethtool_link_ksettings *link_ksettings) -{ - bool retval = true; - - memset(legacy_settings, 0, sizeof(*legacy_settings)); - /* this also clears the deprecated fields in legacy structure: - * __u8 transceiver; - * __u32 maxtxpkt; - * __u32 maxrxpkt; - */ - - retval &= ethtool_convert_link_mode_to_legacy_u32( - &legacy_settings->supported, - link_ksettings->link_modes.supported); - retval &= ethtool_convert_link_mode_to_legacy_u32( - &legacy_settings->advertising, - link_ksettings->link_modes.advertising); - retval &= ethtool_convert_link_mode_to_legacy_u32( - &legacy_settings->lp_advertising, - link_ksettings->link_modes.lp_advertising); - ethtool_cmd_speed_set(legacy_settings, link_ksettings->base.speed); - legacy_settings->duplex - = link_ksettings->base.duplex; - legacy_settings->port - = link_ksettings->base.port; - legacy_settings->phy_address - = link_ksettings->base.phy_address; - legacy_settings->autoneg - = link_ksettings->base.autoneg; - legacy_settings->mdio_support - = link_ksettings->base.mdio_support; - legacy_settings->eth_tp_mdix - = link_ksettings->base.eth_tp_mdix; - legacy_settings->eth_tp_mdix_ctrl - = link_ksettings->base.eth_tp_mdix_ctrl; - return retval; -} - -/* number of 32-bit words to store the user's link mode bitmaps */ -#define __ETHTOOL_LINK_MODE_MASK_NU32 \ - DIV_ROUND_UP(__ETHTOOL_LINK_MODE_MASK_NBITS, 32) - -/* layout of the struct passed from/to userland */ -struct ethtool_link_usettings { - struct ethtool_link_settings base; - struct { - __u32 supported[__ETHTOOL_LINK_MODE_MASK_NU32]; - __u32 advertising[__ETHTOOL_LINK_MODE_MASK_NU32]; - __u32 lp_advertising[__ETHTOOL_LINK_MODE_MASK_NU32]; - } link_modes; -}; - -/* Internal kernel helper to query a device ethtool_link_settings. - * - * Backward compatibility note: for compatibility with legacy drivers - * that implement only the ethtool_cmd API, this has to work with both - * drivers implementing get_link_ksettings API and drivers - * implementing get_settings API. When drivers implement get_settings - * and report ethtool_cmd deprecated fields - * (transceiver/maxrxpkt/maxtxpkt), these fields are silently ignored - * because the resulting struct ethtool_link_settings does not report them. - */ -int __ethtool_get_link_ksettings(struct net_device *dev, - struct ethtool_link_ksettings *link_ksettings) -{ - int err; - struct ethtool_cmd cmd; - - ASSERT_RTNL(); - - if (dev->ethtool_ops->get_link_ksettings) { - memset(link_ksettings, 0, sizeof(*link_ksettings)); - return dev->ethtool_ops->get_link_ksettings(dev, - link_ksettings); - } - - /* driver doesn't support %ethtool_link_ksettings API. revert to - * legacy %ethtool_cmd API, unless it's not supported either. - * TODO: remove when ethtool_ops::get_settings disappears internally - */ - if (!dev->ethtool_ops->get_settings) - return -EOPNOTSUPP; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = ETHTOOL_GSET; - err = dev->ethtool_ops->get_settings(dev, &cmd); - if (err < 0) - return err; - - /* we ignore deprecated fields transceiver/maxrxpkt/maxtxpkt - */ - convert_legacy_settings_to_link_ksettings(link_ksettings, &cmd); - return err; -} -EXPORT_SYMBOL(__ethtool_get_link_ksettings); - -/* convert ethtool_link_usettings in user space to a kernel internal - * ethtool_link_ksettings. return 0 on success, errno on error. - */ -static int load_link_ksettings_from_user(struct ethtool_link_ksettings *to, - const void __user *from) -{ - struct ethtool_link_usettings link_usettings; - - if (copy_from_user(&link_usettings, from, sizeof(link_usettings))) - return -EFAULT; - - memcpy(&to->base, &link_usettings.base, sizeof(to->base)); - bitmap_from_u32array(to->link_modes.supported, - __ETHTOOL_LINK_MODE_MASK_NBITS, - link_usettings.link_modes.supported, - __ETHTOOL_LINK_MODE_MASK_NU32); - bitmap_from_u32array(to->link_modes.advertising, - __ETHTOOL_LINK_MODE_MASK_NBITS, - link_usettings.link_modes.advertising, - __ETHTOOL_LINK_MODE_MASK_NU32); - bitmap_from_u32array(to->link_modes.lp_advertising, - __ETHTOOL_LINK_MODE_MASK_NBITS, - link_usettings.link_modes.lp_advertising, - __ETHTOOL_LINK_MODE_MASK_NU32); - - return 0; -} - -/* convert a kernel internal ethtool_link_ksettings to - * ethtool_link_usettings in user space. return 0 on success, errno on - * error. - */ -static int -store_link_ksettings_for_user(void __user *to, - const struct ethtool_link_ksettings *from) -{ - struct ethtool_link_usettings link_usettings; - - memcpy(&link_usettings.base, &from->base, sizeof(link_usettings)); - bitmap_to_u32array(link_usettings.link_modes.supported, - __ETHTOOL_LINK_MODE_MASK_NU32, - from->link_modes.supported, - __ETHTOOL_LINK_MODE_MASK_NBITS); - bitmap_to_u32array(link_usettings.link_modes.advertising, - __ETHTOOL_LINK_MODE_MASK_NU32, - from->link_modes.advertising, - __ETHTOOL_LINK_MODE_MASK_NBITS); - bitmap_to_u32array(link_usettings.link_modes.lp_advertising, - __ETHTOOL_LINK_MODE_MASK_NU32, - from->link_modes.lp_advertising, - __ETHTOOL_LINK_MODE_MASK_NBITS); - - if (copy_to_user(to, &link_usettings, sizeof(link_usettings))) - return -EFAULT; - - return 0; -} - -/* Query device for its ethtool_link_settings. - * - * Backward compatibility note: this function must fail when driver - * does not implement ethtool::get_link_ksettings, even if legacy - * ethtool_ops::get_settings is implemented. This tells new versions - * of ethtool that they should use the legacy API %ETHTOOL_GSET for - * this driver, so that they can correctly access the ethtool_cmd - * deprecated fields (transceiver/maxrxpkt/maxtxpkt), until no driver - * implements ethtool_ops::get_settings anymore. - */ -static int ethtool_get_link_ksettings(struct net_device *dev, - void __user *useraddr) -{ - int err = 0; - struct ethtool_link_ksettings link_ksettings; - - ASSERT_RTNL(); - - if (!dev->ethtool_ops->get_link_ksettings) - return -EOPNOTSUPP; - - /* handle bitmap nbits handshake */ - if (copy_from_user(&link_ksettings.base, useraddr, - sizeof(link_ksettings.base))) - return -EFAULT; - - if (__ETHTOOL_LINK_MODE_MASK_NU32 - != link_ksettings.base.link_mode_masks_nwords) { - /* wrong link mode nbits requested */ - memset(&link_ksettings, 0, sizeof(link_ksettings)); - link_ksettings.base.cmd = ETHTOOL_GLINKSETTINGS; - /* send back number of words required as negative val */ - compiletime_assert(__ETHTOOL_LINK_MODE_MASK_NU32 <= S8_MAX, - "need too many bits for link modes!"); - link_ksettings.base.link_mode_masks_nwords - = -((s8)__ETHTOOL_LINK_MODE_MASK_NU32); - - /* copy the base fields back to user, not the link - * mode bitmaps - */ - if (copy_to_user(useraddr, &link_ksettings.base, - sizeof(link_ksettings.base))) - return -EFAULT; - - return 0; - } - - /* handshake successful: user/kernel agree on - * link_mode_masks_nwords - */ - - memset(&link_ksettings, 0, sizeof(link_ksettings)); - err = dev->ethtool_ops->get_link_ksettings(dev, &link_ksettings); - if (err < 0) - return err; - - /* make sure we tell the right values to user */ - link_ksettings.base.cmd = ETHTOOL_GLINKSETTINGS; - link_ksettings.base.link_mode_masks_nwords - = __ETHTOOL_LINK_MODE_MASK_NU32; - - return store_link_ksettings_for_user(useraddr, &link_ksettings); -} - -/* Update device ethtool_link_settings. - * - * Backward compatibility note: this function must fail when driver - * does not implement ethtool::set_link_ksettings, even if legacy - * ethtool_ops::set_settings is implemented. This tells new versions - * of ethtool that they should use the legacy API %ETHTOOL_SSET for - * this driver, so that they can correctly update the ethtool_cmd - * deprecated fields (transceiver/maxrxpkt/maxtxpkt), until no driver - * implements ethtool_ops::get_settings anymore. - */ -static int ethtool_set_link_ksettings(struct net_device *dev, - void __user *useraddr) -{ - int err; - struct ethtool_link_ksettings link_ksettings; - - ASSERT_RTNL(); - - if (!dev->ethtool_ops->set_link_ksettings) - return -EOPNOTSUPP; - - /* make sure nbits field has expected value */ - if (copy_from_user(&link_ksettings.base, useraddr, - sizeof(link_ksettings.base))) - return -EFAULT; - - if (__ETHTOOL_LINK_MODE_MASK_NU32 - != link_ksettings.base.link_mode_masks_nwords) - return -EINVAL; - - /* copy the whole structure, now that we know it has expected - * format - */ - err = load_link_ksettings_from_user(&link_ksettings, useraddr); - if (err) - return err; - - /* re-check nwords field, just in case */ - if (__ETHTOOL_LINK_MODE_MASK_NU32 - != link_ksettings.base.link_mode_masks_nwords) - return -EINVAL; - - return dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings); -} - -static void -warn_incomplete_ethtool_legacy_settings_conversion(const char *details) -{ - char name[sizeof(current->comm)]; - - pr_info_once("warning: `%s' uses legacy ethtool link settings API, %s\n", - get_task_comm(name, current), details); -} - -/* Query device for its ethtool_cmd settings. - * - * Backward compatibility note: for compatibility with legacy ethtool, - * this has to work with both drivers implementing get_link_ksettings - * API and drivers implementing get_settings API. When drivers - * implement get_link_ksettings and report higher link mode bits, a - * kernel warning is logged once (with name of 1st driver/device) to - * recommend user to upgrade ethtool, but the command is successful - * (only the lower link mode bits reported back to user). - */ -static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_cmd cmd; - - ASSERT_RTNL(); - - if (dev->ethtool_ops->get_link_ksettings) { - /* First, use link_ksettings API if it is supported */ - int err; - struct ethtool_link_ksettings link_ksettings; - - memset(&link_ksettings, 0, sizeof(link_ksettings)); - err = dev->ethtool_ops->get_link_ksettings(dev, - &link_ksettings); - if (err < 0) - return err; - if (!convert_link_ksettings_to_legacy_settings(&cmd, - &link_ksettings)) - warn_incomplete_ethtool_legacy_settings_conversion( - "link modes are only partially reported"); - - /* send a sensible cmd tag back to user */ - cmd.cmd = ETHTOOL_GSET; - } else { - /* driver doesn't support %ethtool_link_ksettings - * API. revert to legacy %ethtool_cmd API, unless it's - * not supported either. - */ - int err; - - if (!dev->ethtool_ops->get_settings) - return -EOPNOTSUPP; - - memset(&cmd, 0, sizeof(cmd)); - cmd.cmd = ETHTOOL_GSET; - err = dev->ethtool_ops->get_settings(dev, &cmd); - if (err < 0) - return err; - } - - if (copy_to_user(useraddr, &cmd, sizeof(cmd))) - return -EFAULT; - - return 0; -} - -/* Update device link settings with given ethtool_cmd. - * - * Backward compatibility note: for compatibility with legacy ethtool, - * this has to work with both drivers implementing set_link_ksettings - * API and drivers implementing set_settings API. When drivers - * implement set_link_ksettings and user's request updates deprecated - * ethtool_cmd fields (transceiver/maxrxpkt/maxtxpkt), a kernel - * warning is logged once (with name of 1st driver/device) to - * recommend user to upgrade ethtool, and the request is rejected. - */ -static int ethtool_set_settings(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_cmd cmd; - - ASSERT_RTNL(); - - if (copy_from_user(&cmd, useraddr, sizeof(cmd))) - return -EFAULT; - - /* first, try new %ethtool_link_ksettings API. */ - if (dev->ethtool_ops->set_link_ksettings) { - struct ethtool_link_ksettings link_ksettings; - - if (!convert_legacy_settings_to_link_ksettings(&link_ksettings, - &cmd)) - return -EINVAL; - - link_ksettings.base.cmd = ETHTOOL_SLINKSETTINGS; - link_ksettings.base.link_mode_masks_nwords - = __ETHTOOL_LINK_MODE_MASK_NU32; - return dev->ethtool_ops->set_link_ksettings(dev, - &link_ksettings); - } - - /* legacy %ethtool_cmd API */ - - /* TODO: return -EOPNOTSUPP when ethtool_ops::get_settings - * disappears internally - */ - - if (!dev->ethtool_ops->set_settings) - return -EOPNOTSUPP; - - return dev->ethtool_ops->set_settings(dev, &cmd); -} - -static noinline_for_stack int ethtool_get_drvinfo(struct net_device *dev, - void __user *useraddr) -{ - struct ethtool_drvinfo info; - const struct ethtool_ops *ops = dev->ethtool_ops; - - memset(&info, 0, sizeof(info)); - info.cmd = ETHTOOL_GDRVINFO; - if (ops->get_drvinfo) { - ops->get_drvinfo(dev, &info); - } else if (dev->dev.parent && dev->dev.parent->driver) { - strlcpy(info.bus_info, dev_name(dev->dev.parent), - sizeof(info.bus_info)); - strlcpy(info.driver, dev->dev.parent->driver->name, - sizeof(info.driver)); - } else { - return -EOPNOTSUPP; - } - - /* - * this method of obtaining string set info is deprecated; - * Use ETHTOOL_GSSET_INFO instead. - */ - if (ops->get_sset_count) { - int rc; - - rc = ops->get_sset_count(dev, ETH_SS_TEST); - if (rc >= 0) - info.testinfo_len = rc; - rc = ops->get_sset_count(dev, ETH_SS_STATS); - if (rc >= 0) - info.n_stats = rc; - rc = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS); - if (rc >= 0) - info.n_priv_flags = rc; - } - if (ops->get_regs_len) - info.regdump_len = ops->get_regs_len(dev); - if (ops->get_eeprom_len) - info.eedump_len = ops->get_eeprom_len(dev); - - if (copy_to_user(useraddr, &info, sizeof(info))) - return -EFAULT; - return 0; -} - -static noinline_for_stack int ethtool_get_sset_info(struct net_device *dev, - void __user *useraddr) -{ - struct ethtool_sset_info info; - u64 sset_mask; - int i, idx = 0, n_bits = 0, ret, rc; - u32 *info_buf = NULL; - - if (copy_from_user(&info, useraddr, sizeof(info))) - return -EFAULT; - - /* store copy of mask, because we zero struct later on */ - sset_mask = info.sset_mask; - if (!sset_mask) - return 0; - - /* calculate size of return buffer */ - n_bits = hweight64(sset_mask); - - memset(&info, 0, sizeof(info)); - info.cmd = ETHTOOL_GSSET_INFO; - - info_buf = kzalloc(n_bits * sizeof(u32), GFP_USER); - if (!info_buf) - return -ENOMEM; - - /* - * fill return buffer based on input bitmask and successful - * get_sset_count return - */ - for (i = 0; i < 64; i++) { - if (!(sset_mask & (1ULL << i))) - continue; - - rc = __ethtool_get_sset_count(dev, i); - if (rc >= 0) { - info.sset_mask |= (1ULL << i); - info_buf[idx++] = rc; - } - } - - ret = -EFAULT; - if (copy_to_user(useraddr, &info, sizeof(info))) - goto out; - - useraddr += offsetof(struct ethtool_sset_info, data); - if (copy_to_user(useraddr, info_buf, idx * sizeof(u32))) - goto out; - - ret = 0; - -out: - kfree(info_buf); - return ret; -} - -static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev, - u32 cmd, void __user *useraddr) -{ - struct ethtool_rxnfc info; - size_t info_size = sizeof(info); - int rc; - - if (!dev->ethtool_ops->set_rxnfc) - return -EOPNOTSUPP; - - /* struct ethtool_rxnfc was originally defined for - * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data - * members. User-space might still be using that - * definition. */ - if (cmd == ETHTOOL_SRXFH) - info_size = (offsetof(struct ethtool_rxnfc, data) + - sizeof(info.data)); - - if (copy_from_user(&info, useraddr, info_size)) - return -EFAULT; - - rc = dev->ethtool_ops->set_rxnfc(dev, &info); - if (rc) - return rc; - - if (cmd == ETHTOOL_SRXCLSRLINS && - copy_to_user(useraddr, &info, info_size)) - return -EFAULT; - - return 0; -} - -static noinline_for_stack int ethtool_get_rxnfc(struct net_device *dev, - u32 cmd, void __user *useraddr) -{ - struct ethtool_rxnfc info; - size_t info_size = sizeof(info); - const struct ethtool_ops *ops = dev->ethtool_ops; - int ret; - void *rule_buf = NULL; - - if (!ops->get_rxnfc) - return -EOPNOTSUPP; - - /* struct ethtool_rxnfc was originally defined for - * ETHTOOL_{G,S}RXFH with only the cmd, flow_type and data - * members. User-space might still be using that - * definition. */ - if (cmd == ETHTOOL_GRXFH) - info_size = (offsetof(struct ethtool_rxnfc, data) + - sizeof(info.data)); - - if (copy_from_user(&info, useraddr, info_size)) - return -EFAULT; - - if (info.cmd == ETHTOOL_GRXCLSRLALL) { - if (info.rule_cnt > 0) { - if (info.rule_cnt <= KMALLOC_MAX_SIZE / sizeof(u32)) - rule_buf = kzalloc(info.rule_cnt * sizeof(u32), - GFP_USER); - if (!rule_buf) - return -ENOMEM; - } - } - - ret = ops->get_rxnfc(dev, &info, rule_buf); - if (ret < 0) - goto err_out; - - ret = -EFAULT; - if (copy_to_user(useraddr, &info, info_size)) - goto err_out; - - if (rule_buf) { - useraddr += offsetof(struct ethtool_rxnfc, rule_locs); - if (copy_to_user(useraddr, rule_buf, - info.rule_cnt * sizeof(u32))) - goto err_out; - } - ret = 0; - -err_out: - kfree(rule_buf); - - return ret; -} - -static int ethtool_copy_validate_indir(u32 *indir, void __user *useraddr, - struct ethtool_rxnfc *rx_rings, - u32 size) -{ - int i; - - if (copy_from_user(indir, useraddr, size * sizeof(indir[0]))) - return -EFAULT; - - /* Validate ring indices */ - for (i = 0; i < size; i++) - if (indir[i] >= rx_rings->data) - return -EINVAL; - - return 0; -} - -u8 netdev_rss_key[NETDEV_RSS_KEY_LEN] __read_mostly; - -void netdev_rss_key_fill(void *buffer, size_t len) -{ - BUG_ON(len > sizeof(netdev_rss_key)); - net_get_random_once(netdev_rss_key, sizeof(netdev_rss_key)); - memcpy(buffer, netdev_rss_key, len); -} -EXPORT_SYMBOL(netdev_rss_key_fill); - -static int ethtool_get_max_rxfh_channel(struct net_device *dev, u32 *max) -{ - u32 dev_size, current_max = 0; - u32 *indir; - int ret; - - if (!dev->ethtool_ops->get_rxfh_indir_size || - !dev->ethtool_ops->get_rxfh) - return -EOPNOTSUPP; - dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev); - if (dev_size == 0) - return -EOPNOTSUPP; - - indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER); - if (!indir) - return -ENOMEM; - - ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL, NULL); - if (ret) - goto out; - - while (dev_size--) - current_max = max(current_max, indir[dev_size]); - - *max = current_max; - -out: - kfree(indir); - return ret; -} - -static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, - void __user *useraddr) -{ - u32 user_size, dev_size; - u32 *indir; - int ret; - - if (!dev->ethtool_ops->get_rxfh_indir_size || - !dev->ethtool_ops->get_rxfh) - return -EOPNOTSUPP; - dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev); - if (dev_size == 0) - return -EOPNOTSUPP; - - if (copy_from_user(&user_size, - useraddr + offsetof(struct ethtool_rxfh_indir, size), - sizeof(user_size))) - return -EFAULT; - - if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh_indir, size), - &dev_size, sizeof(dev_size))) - return -EFAULT; - - /* If the user buffer size is 0, this is just a query for the - * device table size. Otherwise, if it's smaller than the - * device table size it's an error. - */ - if (user_size < dev_size) - return user_size == 0 ? 0 : -EINVAL; - - indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER); - if (!indir) - return -ENOMEM; - - ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL, NULL); - if (ret) - goto out; - - if (copy_to_user(useraddr + - offsetof(struct ethtool_rxfh_indir, ring_index[0]), - indir, dev_size * sizeof(indir[0]))) - ret = -EFAULT; - -out: - kfree(indir); - return ret; -} - -static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev, - void __user *useraddr) -{ - struct ethtool_rxnfc rx_rings; - u32 user_size, dev_size, i; - u32 *indir; - const struct ethtool_ops *ops = dev->ethtool_ops; - int ret; - u32 ringidx_offset = offsetof(struct ethtool_rxfh_indir, ring_index[0]); - - if (!ops->get_rxfh_indir_size || !ops->set_rxfh || - !ops->get_rxnfc) - return -EOPNOTSUPP; - - dev_size = ops->get_rxfh_indir_size(dev); - if (dev_size == 0) - return -EOPNOTSUPP; - - if (copy_from_user(&user_size, - useraddr + offsetof(struct ethtool_rxfh_indir, size), - sizeof(user_size))) - return -EFAULT; - - if (user_size != 0 && user_size != dev_size) - return -EINVAL; - - indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER); - if (!indir) - return -ENOMEM; - - rx_rings.cmd = ETHTOOL_GRXRINGS; - ret = ops->get_rxnfc(dev, &rx_rings, NULL); - if (ret) - goto out; - - if (user_size == 0) { - for (i = 0; i < dev_size; i++) - indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data); - } else { - ret = ethtool_copy_validate_indir(indir, - useraddr + ringidx_offset, - &rx_rings, - dev_size); - if (ret) - goto out; - } - - ret = ops->set_rxfh(dev, indir, NULL, ETH_RSS_HASH_NO_CHANGE); - if (ret) - goto out; - - /* indicate whether rxfh was set to default */ - if (user_size == 0) - dev->priv_flags &= ~IFF_RXFH_CONFIGURED; - else - dev->priv_flags |= IFF_RXFH_CONFIGURED; - -out: - kfree(indir); - return ret; -} - -static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev, - void __user *useraddr) -{ - int ret; - const struct ethtool_ops *ops = dev->ethtool_ops; - u32 user_indir_size, user_key_size; - u32 dev_indir_size = 0, dev_key_size = 0; - struct ethtool_rxfh rxfh; - u32 total_size; - u32 indir_bytes; - u32 *indir = NULL; - u8 dev_hfunc = 0; - u8 *hkey = NULL; - u8 *rss_config; - - if (!ops->get_rxfh) - return -EOPNOTSUPP; - - if (ops->get_rxfh_indir_size) - dev_indir_size = ops->get_rxfh_indir_size(dev); - if (ops->get_rxfh_key_size) - dev_key_size = ops->get_rxfh_key_size(dev); - - if (copy_from_user(&rxfh, useraddr, sizeof(rxfh))) - return -EFAULT; - user_indir_size = rxfh.indir_size; - user_key_size = rxfh.key_size; - - /* Check that reserved fields are 0 for now */ - if (rxfh.rss_context || rxfh.rsvd8[0] || rxfh.rsvd8[1] || - rxfh.rsvd8[2] || rxfh.rsvd32) - return -EINVAL; - - rxfh.indir_size = dev_indir_size; - rxfh.key_size = dev_key_size; - if (copy_to_user(useraddr, &rxfh, sizeof(rxfh))) - return -EFAULT; - - if ((user_indir_size && (user_indir_size != dev_indir_size)) || - (user_key_size && (user_key_size != dev_key_size))) - return -EINVAL; - - indir_bytes = user_indir_size * sizeof(indir[0]); - total_size = indir_bytes + user_key_size; - rss_config = kzalloc(total_size, GFP_USER); - if (!rss_config) - return -ENOMEM; - - if (user_indir_size) - indir = (u32 *)rss_config; - - if (user_key_size) - hkey = rss_config + indir_bytes; - - ret = dev->ethtool_ops->get_rxfh(dev, indir, hkey, &dev_hfunc); - if (ret) - goto out; - - if (copy_to_user(useraddr + offsetof(struct ethtool_rxfh, hfunc), - &dev_hfunc, sizeof(rxfh.hfunc))) { - ret = -EFAULT; - } else if (copy_to_user(useraddr + - offsetof(struct ethtool_rxfh, rss_config[0]), - rss_config, total_size)) { - ret = -EFAULT; - } -out: - kfree(rss_config); - - return ret; -} - -static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, - void __user *useraddr) -{ - int ret; - const struct ethtool_ops *ops = dev->ethtool_ops; - struct ethtool_rxnfc rx_rings; - struct ethtool_rxfh rxfh; - u32 dev_indir_size = 0, dev_key_size = 0, i; - u32 *indir = NULL, indir_bytes = 0; - u8 *hkey = NULL; - u8 *rss_config; - u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]); - - if (!ops->get_rxnfc || !ops->set_rxfh) - return -EOPNOTSUPP; - - if (ops->get_rxfh_indir_size) - dev_indir_size = ops->get_rxfh_indir_size(dev); - if (ops->get_rxfh_key_size) - dev_key_size = ops->get_rxfh_key_size(dev); - - if (copy_from_user(&rxfh, useraddr, sizeof(rxfh))) - return -EFAULT; - - /* Check that reserved fields are 0 for now */ - if (rxfh.rss_context || rxfh.rsvd8[0] || rxfh.rsvd8[1] || - rxfh.rsvd8[2] || rxfh.rsvd32) - return -EINVAL; - - /* If either indir, hash key or function is valid, proceed further. - * Must request at least one change: indir size, hash key or function. - */ - if ((rxfh.indir_size && - rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE && - rxfh.indir_size != dev_indir_size) || - (rxfh.key_size && (rxfh.key_size != dev_key_size)) || - (rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE && - rxfh.key_size == 0 && rxfh.hfunc == ETH_RSS_HASH_NO_CHANGE)) - return -EINVAL; - - if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) - indir_bytes = dev_indir_size * sizeof(indir[0]); - - rss_config = kzalloc(indir_bytes + rxfh.key_size, GFP_USER); - if (!rss_config) - return -ENOMEM; - - rx_rings.cmd = ETHTOOL_GRXRINGS; - ret = ops->get_rxnfc(dev, &rx_rings, NULL); - if (ret) - goto out; - - /* rxfh.indir_size == 0 means reset the indir table to default. - * rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE means leave it unchanged. - */ - if (rxfh.indir_size && - rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) { - indir = (u32 *)rss_config; - ret = ethtool_copy_validate_indir(indir, - useraddr + rss_cfg_offset, - &rx_rings, - rxfh.indir_size); - if (ret) - goto out; - } else if (rxfh.indir_size == 0) { - indir = (u32 *)rss_config; - for (i = 0; i < dev_indir_size; i++) - indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data); - } - - if (rxfh.key_size) { - hkey = rss_config + indir_bytes; - if (copy_from_user(hkey, - useraddr + rss_cfg_offset + indir_bytes, - rxfh.key_size)) { - ret = -EFAULT; - goto out; - } - } - - ret = ops->set_rxfh(dev, indir, hkey, rxfh.hfunc); - if (ret) - goto out; - - /* indicate whether rxfh was set to default */ - if (rxfh.indir_size == 0) - dev->priv_flags &= ~IFF_RXFH_CONFIGURED; - else if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) - dev->priv_flags |= IFF_RXFH_CONFIGURED; - -out: - kfree(rss_config); - return ret; -} - -static int ethtool_get_regs(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_regs regs; - const struct ethtool_ops *ops = dev->ethtool_ops; - void *regbuf; - int reglen, ret; - - if (!ops->get_regs || !ops->get_regs_len) - return -EOPNOTSUPP; - - if (copy_from_user(®s, useraddr, sizeof(regs))) - return -EFAULT; - - reglen = ops->get_regs_len(dev); - if (regs.len > reglen) - regs.len = reglen; - - regbuf = vzalloc(reglen); - if (reglen && !regbuf) - return -ENOMEM; - - ops->get_regs(dev, ®s, regbuf); - - ret = -EFAULT; - if (copy_to_user(useraddr, ®s, sizeof(regs))) - goto out; - useraddr += offsetof(struct ethtool_regs, data); - if (regbuf && copy_to_user(useraddr, regbuf, regs.len)) - goto out; - ret = 0; - - out: - vfree(regbuf); - return ret; -} - -static int ethtool_reset(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value reset; - int ret; - - if (!dev->ethtool_ops->reset) - return -EOPNOTSUPP; - - if (copy_from_user(&reset, useraddr, sizeof(reset))) - return -EFAULT; - - ret = dev->ethtool_ops->reset(dev, &reset.data); - if (ret) - return ret; - - if (copy_to_user(useraddr, &reset, sizeof(reset))) - return -EFAULT; - return 0; -} - -static int ethtool_get_wol(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; - - if (!dev->ethtool_ops->get_wol) - return -EOPNOTSUPP; - - dev->ethtool_ops->get_wol(dev, &wol); - - if (copy_to_user(useraddr, &wol, sizeof(wol))) - return -EFAULT; - return 0; -} - -static int ethtool_set_wol(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_wolinfo wol; - - if (!dev->ethtool_ops->set_wol) - return -EOPNOTSUPP; - - if (copy_from_user(&wol, useraddr, sizeof(wol))) - return -EFAULT; - - return dev->ethtool_ops->set_wol(dev, &wol); -} - -static int ethtool_get_eee(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_eee edata; - int rc; - - if (!dev->ethtool_ops->get_eee) - return -EOPNOTSUPP; - - memset(&edata, 0, sizeof(struct ethtool_eee)); - edata.cmd = ETHTOOL_GEEE; - rc = dev->ethtool_ops->get_eee(dev, &edata); - - if (rc) - return rc; - - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - - return 0; -} - -static int ethtool_set_eee(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_eee edata; - - if (!dev->ethtool_ops->set_eee) - return -EOPNOTSUPP; - - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - - return dev->ethtool_ops->set_eee(dev, &edata); -} - -static int ethtool_nway_reset(struct net_device *dev) -{ - if (!dev->ethtool_ops->nway_reset) - return -EOPNOTSUPP; - - return dev->ethtool_ops->nway_reset(dev); -} - -static int ethtool_get_link(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_value edata = { .cmd = ETHTOOL_GLINK }; - - if (!dev->ethtool_ops->get_link) - return -EOPNOTSUPP; - - edata.data = netif_running(dev) && dev->ethtool_ops->get_link(dev); - - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; -} - -static int ethtool_get_any_eeprom(struct net_device *dev, void __user *useraddr, - int (*getter)(struct net_device *, - struct ethtool_eeprom *, u8 *), - u32 total_len) -{ - struct ethtool_eeprom eeprom; - void __user *userbuf = useraddr + sizeof(eeprom); - u32 bytes_remaining; - u8 *data; - int ret = 0; - - if (copy_from_user(&eeprom, useraddr, sizeof(eeprom))) - return -EFAULT; - - /* Check for wrap and zero */ - if (eeprom.offset + eeprom.len <= eeprom.offset) - return -EINVAL; - - /* Check for exceeding total eeprom len */ - if (eeprom.offset + eeprom.len > total_len) - return -EINVAL; - - data = kmalloc(PAGE_SIZE, GFP_USER); - if (!data) - return -ENOMEM; - - bytes_remaining = eeprom.len; - while (bytes_remaining > 0) { - eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE); - - ret = getter(dev, &eeprom, data); - if (ret) - break; - if (copy_to_user(userbuf, data, eeprom.len)) { - ret = -EFAULT; - break; - } - userbuf += eeprom.len; - eeprom.offset += eeprom.len; - bytes_remaining -= eeprom.len; - } - - eeprom.len = userbuf - (useraddr + sizeof(eeprom)); - eeprom.offset -= eeprom.len; - if (copy_to_user(useraddr, &eeprom, sizeof(eeprom))) - ret = -EFAULT; - - kfree(data); - return ret; -} - -static int ethtool_get_eeprom(struct net_device *dev, void __user *useraddr) -{ - const struct ethtool_ops *ops = dev->ethtool_ops; - - if (!ops->get_eeprom || !ops->get_eeprom_len || - !ops->get_eeprom_len(dev)) - return -EOPNOTSUPP; - - return ethtool_get_any_eeprom(dev, useraddr, ops->get_eeprom, - ops->get_eeprom_len(dev)); -} - -static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_eeprom eeprom; - const struct ethtool_ops *ops = dev->ethtool_ops; - void __user *userbuf = useraddr + sizeof(eeprom); - u32 bytes_remaining; - u8 *data; - int ret = 0; - - if (!ops->set_eeprom || !ops->get_eeprom_len || - !ops->get_eeprom_len(dev)) - return -EOPNOTSUPP; - - if (copy_from_user(&eeprom, useraddr, sizeof(eeprom))) - return -EFAULT; - - /* Check for wrap and zero */ - if (eeprom.offset + eeprom.len <= eeprom.offset) - return -EINVAL; - - /* Check for exceeding total eeprom len */ - if (eeprom.offset + eeprom.len > ops->get_eeprom_len(dev)) - return -EINVAL; - - data = kmalloc(PAGE_SIZE, GFP_USER); - if (!data) - return -ENOMEM; - - bytes_remaining = eeprom.len; - while (bytes_remaining > 0) { - eeprom.len = min(bytes_remaining, (u32)PAGE_SIZE); - - if (copy_from_user(data, userbuf, eeprom.len)) { - ret = -EFAULT; - break; - } - ret = ops->set_eeprom(dev, &eeprom, data); - if (ret) - break; - userbuf += eeprom.len; - eeprom.offset += eeprom.len; - bytes_remaining -= eeprom.len; - } - - kfree(data); - return ret; -} - -static noinline_for_stack int ethtool_get_coalesce(struct net_device *dev, - void __user *useraddr) -{ - struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE }; - - if (!dev->ethtool_ops->get_coalesce) - return -EOPNOTSUPP; - - dev->ethtool_ops->get_coalesce(dev, &coalesce); - - if (copy_to_user(useraddr, &coalesce, sizeof(coalesce))) - return -EFAULT; - return 0; -} - -static noinline_for_stack int ethtool_set_coalesce(struct net_device *dev, - void __user *useraddr) -{ - struct ethtool_coalesce coalesce; - - if (!dev->ethtool_ops->set_coalesce) - return -EOPNOTSUPP; - - if (copy_from_user(&coalesce, useraddr, sizeof(coalesce))) - return -EFAULT; - - return dev->ethtool_ops->set_coalesce(dev, &coalesce); -} - -static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_ringparam ringparam = { .cmd = ETHTOOL_GRINGPARAM }; - - if (!dev->ethtool_ops->get_ringparam) - return -EOPNOTSUPP; - - dev->ethtool_ops->get_ringparam(dev, &ringparam); - - if (copy_to_user(useraddr, &ringparam, sizeof(ringparam))) - return -EFAULT; - return 0; -} - -static int ethtool_set_ringparam(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_ringparam ringparam; - - if (!dev->ethtool_ops->set_ringparam) - return -EOPNOTSUPP; - - if (copy_from_user(&ringparam, useraddr, sizeof(ringparam))) - return -EFAULT; - - return dev->ethtool_ops->set_ringparam(dev, &ringparam); -} - -static noinline_for_stack int ethtool_get_channels(struct net_device *dev, - void __user *useraddr) -{ - struct ethtool_channels channels = { .cmd = ETHTOOL_GCHANNELS }; - - if (!dev->ethtool_ops->get_channels) - return -EOPNOTSUPP; - - dev->ethtool_ops->get_channels(dev, &channels); - - if (copy_to_user(useraddr, &channels, sizeof(channels))) - return -EFAULT; - return 0; -} - -static noinline_for_stack int ethtool_set_channels(struct net_device *dev, - void __user *useraddr) -{ - struct ethtool_channels channels, max; - u32 max_rx_in_use = 0; - - if (!dev->ethtool_ops->set_channels || !dev->ethtool_ops->get_channels) - return -EOPNOTSUPP; - - if (copy_from_user(&channels, useraddr, sizeof(channels))) - return -EFAULT; - - dev->ethtool_ops->get_channels(dev, &max); - - /* ensure new counts are within the maximums */ - if ((channels.rx_count > max.max_rx) || - (channels.tx_count > max.max_tx) || - (channels.combined_count > max.max_combined) || - (channels.other_count > max.max_other)) - return -EINVAL; - - /* ensure the new Rx count fits within the configured Rx flow - * indirection table settings */ - if (netif_is_rxfh_configured(dev) && - !ethtool_get_max_rxfh_channel(dev, &max_rx_in_use) && - (channels.combined_count + channels.rx_count) <= max_rx_in_use) - return -EINVAL; - - return dev->ethtool_ops->set_channels(dev, &channels); -} - -static int ethtool_get_pauseparam(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_pauseparam pauseparam = { ETHTOOL_GPAUSEPARAM }; - - if (!dev->ethtool_ops->get_pauseparam) - return -EOPNOTSUPP; - - dev->ethtool_ops->get_pauseparam(dev, &pauseparam); - - if (copy_to_user(useraddr, &pauseparam, sizeof(pauseparam))) - return -EFAULT; - return 0; -} - -static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_pauseparam pauseparam; - - if (!dev->ethtool_ops->set_pauseparam) - return -EOPNOTSUPP; - - if (copy_from_user(&pauseparam, useraddr, sizeof(pauseparam))) - return -EFAULT; - - return dev->ethtool_ops->set_pauseparam(dev, &pauseparam); -} - -static int ethtool_self_test(struct net_device *dev, char __user *useraddr) -{ - struct ethtool_test test; - const struct ethtool_ops *ops = dev->ethtool_ops; - u64 *data; - int ret, test_len; - - if (!ops->self_test || !ops->get_sset_count) - return -EOPNOTSUPP; - - test_len = ops->get_sset_count(dev, ETH_SS_TEST); - if (test_len < 0) - return test_len; - WARN_ON(test_len == 0); - - if (copy_from_user(&test, useraddr, sizeof(test))) - return -EFAULT; - - test.len = test_len; - data = kmalloc(test_len * sizeof(u64), GFP_USER); - if (!data) - return -ENOMEM; - - ops->self_test(dev, &test, data); - - ret = -EFAULT; - if (copy_to_user(useraddr, &test, sizeof(test))) - goto out; - useraddr += sizeof(test); - if (copy_to_user(useraddr, data, test.len * sizeof(u64))) - goto out; - ret = 0; - - out: - kfree(data); - return ret; -} - -static int ethtool_get_strings(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_gstrings gstrings; - u8 *data; - int ret; - - if (copy_from_user(&gstrings, useraddr, sizeof(gstrings))) - return -EFAULT; - - ret = __ethtool_get_sset_count(dev, gstrings.string_set); - if (ret < 0) - return ret; - - gstrings.len = ret; - - data = kcalloc(gstrings.len, ETH_GSTRING_LEN, GFP_USER); - if (!data) - return -ENOMEM; - - __ethtool_get_strings(dev, gstrings.string_set, data); - - ret = -EFAULT; - if (copy_to_user(useraddr, &gstrings, sizeof(gstrings))) - goto out; - useraddr += sizeof(gstrings); - if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN)) - goto out; - ret = 0; - -out: - kfree(data); - return ret; -} - -static int ethtool_phys_id(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_value id; - static bool busy; - const struct ethtool_ops *ops = dev->ethtool_ops; - int rc; - - if (!ops->set_phys_id) - return -EOPNOTSUPP; - - if (busy) - return -EBUSY; - - if (copy_from_user(&id, useraddr, sizeof(id))) - return -EFAULT; - - rc = ops->set_phys_id(dev, ETHTOOL_ID_ACTIVE); - if (rc < 0) - return rc; - - /* Drop the RTNL lock while waiting, but prevent reentry or - * removal of the device. - */ - busy = true; - dev_hold(dev); - rtnl_unlock(); - - if (rc == 0) { - /* Driver will handle this itself */ - schedule_timeout_interruptible( - id.data ? (id.data * HZ) : MAX_SCHEDULE_TIMEOUT); - } else { - /* Driver expects to be called at twice the frequency in rc */ - int n = rc * 2, i, interval = HZ / n; - - /* Count down seconds */ - do { - /* Count down iterations per second */ - i = n; - do { - rtnl_lock(); - rc = ops->set_phys_id(dev, - (i & 1) ? ETHTOOL_ID_OFF : ETHTOOL_ID_ON); - rtnl_unlock(); - if (rc) - break; - schedule_timeout_interruptible(interval); - } while (!signal_pending(current) && --i != 0); - } while (!signal_pending(current) && - (id.data == 0 || --id.data != 0)); - } - - rtnl_lock(); - dev_put(dev); - busy = false; - - (void) ops->set_phys_id(dev, ETHTOOL_ID_INACTIVE); - return rc; -} - -static int ethtool_get_stats(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_stats stats; - const struct ethtool_ops *ops = dev->ethtool_ops; - u64 *data; - int ret, n_stats; - - if (!ops->get_ethtool_stats || !ops->get_sset_count) - return -EOPNOTSUPP; - - n_stats = ops->get_sset_count(dev, ETH_SS_STATS); - if (n_stats < 0) - return n_stats; - WARN_ON(n_stats == 0); - - if (copy_from_user(&stats, useraddr, sizeof(stats))) - return -EFAULT; - - stats.n_stats = n_stats; - data = kmalloc(n_stats * sizeof(u64), GFP_USER); - if (!data) - return -ENOMEM; - - ops->get_ethtool_stats(dev, &stats, data); - - ret = -EFAULT; - if (copy_to_user(useraddr, &stats, sizeof(stats))) - goto out; - useraddr += sizeof(stats); - if (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64))) - goto out; - ret = 0; - - out: - kfree(data); - return ret; -} - -static int ethtool_get_phy_stats(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_stats stats; - struct phy_device *phydev = dev->phydev; - u64 *data; - int ret, n_stats; - - if (!phydev) - return -EOPNOTSUPP; - - n_stats = phy_get_sset_count(phydev); - - if (n_stats < 0) - return n_stats; - WARN_ON(n_stats == 0); - - if (copy_from_user(&stats, useraddr, sizeof(stats))) - return -EFAULT; - - stats.n_stats = n_stats; - data = kmalloc_array(n_stats, sizeof(u64), GFP_USER); - if (!data) - return -ENOMEM; - - mutex_lock(&phydev->lock); - phydev->drv->get_stats(phydev, &stats, data); - mutex_unlock(&phydev->lock); - - ret = -EFAULT; - if (copy_to_user(useraddr, &stats, sizeof(stats))) - goto out; - useraddr += sizeof(stats); - if (copy_to_user(useraddr, data, stats.n_stats * sizeof(u64))) - goto out; - ret = 0; - - out: - kfree(data); - return ret; -} - -static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_perm_addr epaddr; - - if (copy_from_user(&epaddr, useraddr, sizeof(epaddr))) - return -EFAULT; - - if (epaddr.size < dev->addr_len) - return -ETOOSMALL; - epaddr.size = dev->addr_len; - - if (copy_to_user(useraddr, &epaddr, sizeof(epaddr))) - return -EFAULT; - useraddr += sizeof(epaddr); - if (copy_to_user(useraddr, dev->perm_addr, epaddr.size)) - return -EFAULT; - return 0; -} - -static int ethtool_get_value(struct net_device *dev, char __user *useraddr, - u32 cmd, u32 (*actor)(struct net_device *)) -{ - struct ethtool_value edata = { .cmd = cmd }; - - if (!actor) - return -EOPNOTSUPP; - - edata.data = actor(dev); - - if (copy_to_user(useraddr, &edata, sizeof(edata))) - return -EFAULT; - return 0; -} - -static int ethtool_set_value_void(struct net_device *dev, char __user *useraddr, - void (*actor)(struct net_device *, u32)) -{ - struct ethtool_value edata; - - if (!actor) - return -EOPNOTSUPP; - - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - - actor(dev, edata.data); - return 0; -} - -static int ethtool_set_value(struct net_device *dev, char __user *useraddr, - int (*actor)(struct net_device *, u32)) -{ - struct ethtool_value edata; - - if (!actor) - return -EOPNOTSUPP; - - if (copy_from_user(&edata, useraddr, sizeof(edata))) - return -EFAULT; - - return actor(dev, edata.data); -} - -static noinline_for_stack int ethtool_flash_device(struct net_device *dev, - char __user *useraddr) -{ - struct ethtool_flash efl; - - if (copy_from_user(&efl, useraddr, sizeof(efl))) - return -EFAULT; - - if (!dev->ethtool_ops->flash_device) - return -EOPNOTSUPP; - - efl.data[ETHTOOL_FLASH_MAX_FILENAME - 1] = 0; - - return dev->ethtool_ops->flash_device(dev, &efl); -} - -static int ethtool_set_dump(struct net_device *dev, - void __user *useraddr) -{ - struct ethtool_dump dump; - - if (!dev->ethtool_ops->set_dump) - return -EOPNOTSUPP; - - if (copy_from_user(&dump, useraddr, sizeof(dump))) - return -EFAULT; - - return dev->ethtool_ops->set_dump(dev, &dump); -} - -static int ethtool_get_dump_flag(struct net_device *dev, - void __user *useraddr) -{ - int ret; - struct ethtool_dump dump; - const struct ethtool_ops *ops = dev->ethtool_ops; - - if (!ops->get_dump_flag) - return -EOPNOTSUPP; - - if (copy_from_user(&dump, useraddr, sizeof(dump))) - return -EFAULT; - - ret = ops->get_dump_flag(dev, &dump); - if (ret) - return ret; - - if (copy_to_user(useraddr, &dump, sizeof(dump))) - return -EFAULT; - return 0; -} - -static int ethtool_get_dump_data(struct net_device *dev, - void __user *useraddr) -{ - int ret; - __u32 len; - struct ethtool_dump dump, tmp; - const struct ethtool_ops *ops = dev->ethtool_ops; - void *data = NULL; - - if (!ops->get_dump_data || !ops->get_dump_flag) - return -EOPNOTSUPP; - - if (copy_from_user(&dump, useraddr, sizeof(dump))) - return -EFAULT; - - memset(&tmp, 0, sizeof(tmp)); - tmp.cmd = ETHTOOL_GET_DUMP_FLAG; - ret = ops->get_dump_flag(dev, &tmp); - if (ret) - return ret; - - len = min(tmp.len, dump.len); - if (!len) - return -EFAULT; - - /* Don't ever let the driver think there's more space available - * than it requested with .get_dump_flag(). - */ - dump.len = len; - - /* Always allocate enough space to hold the whole thing so that the - * driver does not need to check the length and bother with partial - * dumping. - */ - data = vzalloc(tmp.len); - if (!data) - return -ENOMEM; - ret = ops->get_dump_data(dev, &dump, data); - if (ret) - goto out; - - /* There are two sane possibilities: - * 1. The driver's .get_dump_data() does not touch dump.len. - * 2. Or it may set dump.len to how much it really writes, which - * should be tmp.len (or len if it can do a partial dump). - * In any case respond to userspace with the actual length of data - * it's receiving. - */ - WARN_ON(dump.len != len && dump.len != tmp.len); - dump.len = len; - - if (copy_to_user(useraddr, &dump, sizeof(dump))) { - ret = -EFAULT; - goto out; - } - useraddr += offsetof(struct ethtool_dump, data); - if (copy_to_user(useraddr, data, len)) - ret = -EFAULT; -out: - vfree(data); - return ret; -} - -static int ethtool_get_ts_info(struct net_device *dev, void __user *useraddr) -{ - int err = 0; - struct ethtool_ts_info info; - const struct ethtool_ops *ops = dev->ethtool_ops; - struct phy_device *phydev = dev->phydev; - - memset(&info, 0, sizeof(info)); - info.cmd = ETHTOOL_GET_TS_INFO; - - if (phydev && phydev->drv && phydev->drv->ts_info) { - err = phydev->drv->ts_info(phydev, &info); - } else if (ops->get_ts_info) { - err = ops->get_ts_info(dev, &info); - } else { - info.so_timestamping = - SOF_TIMESTAMPING_RX_SOFTWARE | - SOF_TIMESTAMPING_SOFTWARE; - info.phc_index = -1; - } - - if (err) - return err; - - if (copy_to_user(useraddr, &info, sizeof(info))) - err = -EFAULT; - - return err; -} - -static int __ethtool_get_module_info(struct net_device *dev, - struct ethtool_modinfo *modinfo) -{ - const struct ethtool_ops *ops = dev->ethtool_ops; - struct phy_device *phydev = dev->phydev; - - if (phydev && phydev->drv && phydev->drv->module_info) - return phydev->drv->module_info(phydev, modinfo); - - if (ops->get_module_info) - return ops->get_module_info(dev, modinfo); - - return -EOPNOTSUPP; -} - -static int ethtool_get_module_info(struct net_device *dev, - void __user *useraddr) -{ - int ret; - struct ethtool_modinfo modinfo; - - if (copy_from_user(&modinfo, useraddr, sizeof(modinfo))) - return -EFAULT; - - ret = __ethtool_get_module_info(dev, &modinfo); - if (ret) - return ret; - - if (copy_to_user(useraddr, &modinfo, sizeof(modinfo))) - return -EFAULT; - - return 0; -} - -static int __ethtool_get_module_eeprom(struct net_device *dev, - struct ethtool_eeprom *ee, u8 *data) -{ - const struct ethtool_ops *ops = dev->ethtool_ops; - struct phy_device *phydev = dev->phydev; - - if (phydev && phydev->drv && phydev->drv->module_eeprom) - return phydev->drv->module_eeprom(phydev, ee, data); - - if (ops->get_module_eeprom) - return ops->get_module_eeprom(dev, ee, data); - - return -EOPNOTSUPP; -} - -static int ethtool_get_module_eeprom(struct net_device *dev, - void __user *useraddr) -{ - int ret; - struct ethtool_modinfo modinfo; - - ret = __ethtool_get_module_info(dev, &modinfo); - if (ret) - return ret; - - return ethtool_get_any_eeprom(dev, useraddr, - __ethtool_get_module_eeprom, - modinfo.eeprom_len); -} - -static int ethtool_tunable_valid(const struct ethtool_tunable *tuna) -{ - switch (tuna->id) { - case ETHTOOL_RX_COPYBREAK: - case ETHTOOL_TX_COPYBREAK: - if (tuna->len != sizeof(u32) || - tuna->type_id != ETHTOOL_TUNABLE_U32) - return -EINVAL; - break; - default: - return -EINVAL; - } - - return 0; -} - -static int ethtool_get_tunable(struct net_device *dev, void __user *useraddr) -{ - int ret; - struct ethtool_tunable tuna; - const struct ethtool_ops *ops = dev->ethtool_ops; - void *data; - - if (!ops->get_tunable) - return -EOPNOTSUPP; - if (copy_from_user(&tuna, useraddr, sizeof(tuna))) - return -EFAULT; - ret = ethtool_tunable_valid(&tuna); - if (ret) - return ret; - data = kmalloc(tuna.len, GFP_USER); - if (!data) - return -ENOMEM; - ret = ops->get_tunable(dev, &tuna, data); - if (ret) - goto out; - useraddr += sizeof(tuna); - ret = -EFAULT; - if (copy_to_user(useraddr, data, tuna.len)) - goto out; - ret = 0; - -out: - kfree(data); - return ret; -} - -static int ethtool_set_tunable(struct net_device *dev, void __user *useraddr) -{ - int ret; - struct ethtool_tunable tuna; - const struct ethtool_ops *ops = dev->ethtool_ops; - void *data; - - if (!ops->set_tunable) - return -EOPNOTSUPP; - if (copy_from_user(&tuna, useraddr, sizeof(tuna))) - return -EFAULT; - ret = ethtool_tunable_valid(&tuna); - if (ret) - return ret; - data = kmalloc(tuna.len, GFP_USER); - if (!data) - return -ENOMEM; - useraddr += sizeof(tuna); - ret = -EFAULT; - if (copy_from_user(data, useraddr, tuna.len)) - goto out; - ret = ops->set_tunable(dev, &tuna, data); - -out: - kfree(data); - return ret; -} - -static int ethtool_get_per_queue_coalesce(struct net_device *dev, - void __user *useraddr, - struct ethtool_per_queue_op *per_queue_opt) -{ - u32 bit; - int ret; - DECLARE_BITMAP(queue_mask, MAX_NUM_QUEUE); - - if (!dev->ethtool_ops->get_per_queue_coalesce) - return -EOPNOTSUPP; - - useraddr += sizeof(*per_queue_opt); - - bitmap_from_u32array(queue_mask, - MAX_NUM_QUEUE, - per_queue_opt->queue_mask, - DIV_ROUND_UP(MAX_NUM_QUEUE, 32)); - - for_each_set_bit(bit, queue_mask, MAX_NUM_QUEUE) { - struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE }; - - ret = dev->ethtool_ops->get_per_queue_coalesce(dev, bit, &coalesce); - if (ret != 0) - return ret; - if (copy_to_user(useraddr, &coalesce, sizeof(coalesce))) - return -EFAULT; - useraddr += sizeof(coalesce); - } - - return 0; -} - -static int ethtool_set_per_queue_coalesce(struct net_device *dev, - void __user *useraddr, - struct ethtool_per_queue_op *per_queue_opt) -{ - u32 bit; - int i, ret = 0; - int n_queue; - struct ethtool_coalesce *backup = NULL, *tmp = NULL; - DECLARE_BITMAP(queue_mask, MAX_NUM_QUEUE); - - if ((!dev->ethtool_ops->set_per_queue_coalesce) || - (!dev->ethtool_ops->get_per_queue_coalesce)) - return -EOPNOTSUPP; - - useraddr += sizeof(*per_queue_opt); - - bitmap_from_u32array(queue_mask, - MAX_NUM_QUEUE, - per_queue_opt->queue_mask, - DIV_ROUND_UP(MAX_NUM_QUEUE, 32)); - n_queue = bitmap_weight(queue_mask, MAX_NUM_QUEUE); - tmp = backup = kmalloc_array(n_queue, sizeof(*backup), GFP_KERNEL); - if (!backup) - return -ENOMEM; - - for_each_set_bit(bit, queue_mask, MAX_NUM_QUEUE) { - struct ethtool_coalesce coalesce; - - ret = dev->ethtool_ops->get_per_queue_coalesce(dev, bit, tmp); - if (ret != 0) - goto roll_back; - - tmp++; - - if (copy_from_user(&coalesce, useraddr, sizeof(coalesce))) { - ret = -EFAULT; - goto roll_back; - } - - ret = dev->ethtool_ops->set_per_queue_coalesce(dev, bit, &coalesce); - if (ret != 0) - goto roll_back; - - useraddr += sizeof(coalesce); - } - -roll_back: - if (ret != 0) { - tmp = backup; - for_each_set_bit(i, queue_mask, bit) { - dev->ethtool_ops->set_per_queue_coalesce(dev, i, tmp); - tmp++; - } - } - kfree(backup); - - return ret; -} - -static int ethtool_set_per_queue(struct net_device *dev, void __user *useraddr) -{ - struct ethtool_per_queue_op per_queue_opt; - - if (copy_from_user(&per_queue_opt, useraddr, sizeof(per_queue_opt))) - return -EFAULT; - - switch (per_queue_opt.sub_command) { - case ETHTOOL_GCOALESCE: - return ethtool_get_per_queue_coalesce(dev, useraddr, &per_queue_opt); - case ETHTOOL_SCOALESCE: - return ethtool_set_per_queue_coalesce(dev, useraddr, &per_queue_opt); - default: - return -EOPNOTSUPP; - }; -} - -/* The main entry point in this file. Called from net/core/dev_ioctl.c */ - -int dev_ethtool(struct net *net, struct ifreq *ifr) -{ - struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); - void __user *useraddr = ifr->ifr_data; - u32 ethcmd, sub_cmd; - int rc; - netdev_features_t old_features; - - if (!dev || !netif_device_present(dev)) - return -ENODEV; - - if (copy_from_user(ðcmd, useraddr, sizeof(ethcmd))) - return -EFAULT; - - if (ethcmd == ETHTOOL_PERQUEUE) { - if (copy_from_user(&sub_cmd, useraddr + sizeof(ethcmd), sizeof(sub_cmd))) - return -EFAULT; - } else { - sub_cmd = ethcmd; - } - /* Allow some commands to be done by anyone */ - switch (sub_cmd) { - case ETHTOOL_GSET: - case ETHTOOL_GDRVINFO: - case ETHTOOL_GMSGLVL: - case ETHTOOL_GLINK: - case ETHTOOL_GCOALESCE: - case ETHTOOL_GRINGPARAM: - case ETHTOOL_GPAUSEPARAM: - case ETHTOOL_GRXCSUM: - case ETHTOOL_GTXCSUM: - case ETHTOOL_GSG: - case ETHTOOL_GSSET_INFO: - case ETHTOOL_GSTRINGS: - case ETHTOOL_GSTATS: - case ETHTOOL_GPHYSTATS: - case ETHTOOL_GTSO: - case ETHTOOL_GPERMADDR: - case ETHTOOL_GUFO: - case ETHTOOL_GGSO: - case ETHTOOL_GGRO: - case ETHTOOL_GFLAGS: - case ETHTOOL_GPFLAGS: - case ETHTOOL_GRXFH: - case ETHTOOL_GRXRINGS: - case ETHTOOL_GRXCLSRLCNT: - case ETHTOOL_GRXCLSRULE: - case ETHTOOL_GRXCLSRLALL: - case ETHTOOL_GRXFHINDIR: - case ETHTOOL_GRSSH: - case ETHTOOL_GFEATURES: - case ETHTOOL_GCHANNELS: - case ETHTOOL_GET_TS_INFO: - case ETHTOOL_GEEE: - case ETHTOOL_GTUNABLE: - case ETHTOOL_GLINKSETTINGS: - break; - default: - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - return -EPERM; - } - - if (dev->ethtool_ops->begin) { - rc = dev->ethtool_ops->begin(dev); - if (rc < 0) - return rc; - } - old_features = dev->features; - - switch (ethcmd) { - case ETHTOOL_GSET: - rc = ethtool_get_settings(dev, useraddr); - break; - case ETHTOOL_SSET: - rc = ethtool_set_settings(dev, useraddr); - break; - case ETHTOOL_GDRVINFO: - rc = ethtool_get_drvinfo(dev, useraddr); - break; - case ETHTOOL_GREGS: - rc = ethtool_get_regs(dev, useraddr); - break; - case ETHTOOL_GWOL: - rc = ethtool_get_wol(dev, useraddr); - break; - case ETHTOOL_SWOL: - rc = ethtool_set_wol(dev, useraddr); - break; - case ETHTOOL_GMSGLVL: - rc = ethtool_get_value(dev, useraddr, ethcmd, - dev->ethtool_ops->get_msglevel); - break; - case ETHTOOL_SMSGLVL: - rc = ethtool_set_value_void(dev, useraddr, - dev->ethtool_ops->set_msglevel); - break; - case ETHTOOL_GEEE: - rc = ethtool_get_eee(dev, useraddr); - break; - case ETHTOOL_SEEE: - rc = ethtool_set_eee(dev, useraddr); - break; - case ETHTOOL_NWAY_RST: - rc = ethtool_nway_reset(dev); - break; - case ETHTOOL_GLINK: - rc = ethtool_get_link(dev, useraddr); - break; - case ETHTOOL_GEEPROM: - rc = ethtool_get_eeprom(dev, useraddr); - break; - case ETHTOOL_SEEPROM: - rc = ethtool_set_eeprom(dev, useraddr); - break; - case ETHTOOL_GCOALESCE: - rc = ethtool_get_coalesce(dev, useraddr); - break; - case ETHTOOL_SCOALESCE: - rc = ethtool_set_coalesce(dev, useraddr); - break; - case ETHTOOL_GRINGPARAM: - rc = ethtool_get_ringparam(dev, useraddr); - break; - case ETHTOOL_SRINGPARAM: - rc = ethtool_set_ringparam(dev, useraddr); - break; - case ETHTOOL_GPAUSEPARAM: - rc = ethtool_get_pauseparam(dev, useraddr); - break; - case ETHTOOL_SPAUSEPARAM: - rc = ethtool_set_pauseparam(dev, useraddr); - break; - case ETHTOOL_TEST: - rc = ethtool_self_test(dev, useraddr); - break; - case ETHTOOL_GSTRINGS: - rc = ethtool_get_strings(dev, useraddr); - break; - case ETHTOOL_PHYS_ID: - rc = ethtool_phys_id(dev, useraddr); - break; - case ETHTOOL_GSTATS: - rc = ethtool_get_stats(dev, useraddr); - break; - case ETHTOOL_GPERMADDR: - rc = ethtool_get_perm_addr(dev, useraddr); - break; - case ETHTOOL_GFLAGS: - rc = ethtool_get_value(dev, useraddr, ethcmd, - __ethtool_get_flags); - break; - case ETHTOOL_SFLAGS: - rc = ethtool_set_value(dev, useraddr, __ethtool_set_flags); - break; - case ETHTOOL_GPFLAGS: - rc = ethtool_get_value(dev, useraddr, ethcmd, - dev->ethtool_ops->get_priv_flags); - break; - case ETHTOOL_SPFLAGS: - rc = ethtool_set_value(dev, useraddr, - dev->ethtool_ops->set_priv_flags); - break; - case ETHTOOL_GRXFH: - case ETHTOOL_GRXRINGS: - case ETHTOOL_GRXCLSRLCNT: - case ETHTOOL_GRXCLSRULE: - case ETHTOOL_GRXCLSRLALL: - rc = ethtool_get_rxnfc(dev, ethcmd, useraddr); - break; - case ETHTOOL_SRXFH: - case ETHTOOL_SRXCLSRLDEL: - case ETHTOOL_SRXCLSRLINS: - rc = ethtool_set_rxnfc(dev, ethcmd, useraddr); - break; - case ETHTOOL_FLASHDEV: - rc = ethtool_flash_device(dev, useraddr); - break; - case ETHTOOL_RESET: - rc = ethtool_reset(dev, useraddr); - break; - case ETHTOOL_GSSET_INFO: - rc = ethtool_get_sset_info(dev, useraddr); - break; - case ETHTOOL_GRXFHINDIR: - rc = ethtool_get_rxfh_indir(dev, useraddr); - break; - case ETHTOOL_SRXFHINDIR: - rc = ethtool_set_rxfh_indir(dev, useraddr); - break; - case ETHTOOL_GRSSH: - rc = ethtool_get_rxfh(dev, useraddr); - break; - case ETHTOOL_SRSSH: - rc = ethtool_set_rxfh(dev, useraddr); - break; - case ETHTOOL_GFEATURES: - rc = ethtool_get_features(dev, useraddr); - break; - case ETHTOOL_SFEATURES: - rc = ethtool_set_features(dev, useraddr); - break; - case ETHTOOL_GTXCSUM: - case ETHTOOL_GRXCSUM: - case ETHTOOL_GSG: - case ETHTOOL_GTSO: - case ETHTOOL_GUFO: - case ETHTOOL_GGSO: - case ETHTOOL_GGRO: - rc = ethtool_get_one_feature(dev, useraddr, ethcmd); - break; - case ETHTOOL_STXCSUM: - case ETHTOOL_SRXCSUM: - case ETHTOOL_SSG: - case ETHTOOL_STSO: - case ETHTOOL_SUFO: - case ETHTOOL_SGSO: - case ETHTOOL_SGRO: - rc = ethtool_set_one_feature(dev, useraddr, ethcmd); - break; - case ETHTOOL_GCHANNELS: - rc = ethtool_get_channels(dev, useraddr); - break; - case ETHTOOL_SCHANNELS: - rc = ethtool_set_channels(dev, useraddr); - break; - case ETHTOOL_SET_DUMP: - rc = ethtool_set_dump(dev, useraddr); - break; - case ETHTOOL_GET_DUMP_FLAG: - rc = ethtool_get_dump_flag(dev, useraddr); - break; - case ETHTOOL_GET_DUMP_DATA: - rc = ethtool_get_dump_data(dev, useraddr); - break; - case ETHTOOL_GET_TS_INFO: - rc = ethtool_get_ts_info(dev, useraddr); - break; - case ETHTOOL_GMODULEINFO: - rc = ethtool_get_module_info(dev, useraddr); - break; - case ETHTOOL_GMODULEEEPROM: - rc = ethtool_get_module_eeprom(dev, useraddr); - break; - case ETHTOOL_GTUNABLE: - rc = ethtool_get_tunable(dev, useraddr); - break; - case ETHTOOL_STUNABLE: - rc = ethtool_set_tunable(dev, useraddr); - break; - case ETHTOOL_GPHYSTATS: - rc = ethtool_get_phy_stats(dev, useraddr); - break; - case ETHTOOL_PERQUEUE: - rc = ethtool_set_per_queue(dev, useraddr); - break; - case ETHTOOL_GLINKSETTINGS: - rc = ethtool_get_link_ksettings(dev, useraddr); - break; - case ETHTOOL_SLINKSETTINGS: - rc = ethtool_set_link_ksettings(dev, useraddr); - break; - default: - rc = -EOPNOTSUPP; - } - - if (dev->ethtool_ops->complete) - dev->ethtool_ops->complete(dev); - - if (old_features != dev->features) - netdev_features_change(dev); - - return rc; -} diff --git a/src/linux/net/core/filter.c b/src/linux/net/core/filter.c deleted file mode 100644 index b391209..0000000 --- a/src/linux/net/core/filter.c +++ /dev/null @@ -1,3086 +0,0 @@ -/* - * Linux Socket Filter - Kernel level socket filtering - * - * Based on the design of the Berkeley Packet Filter. The new - * internal format has been designed by PLUMgrid: - * - * Copyright (c) 2011 - 2014 PLUMgrid, http://plumgrid.com - * - * Authors: - * - * Jay Schulist - * Alexei Starovoitov - * Daniel Borkmann - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Andi Kleen - Fix a few bad bugs and races. - * Kris Katterjohn - Added many additional checks in bpf_check_classic() - */ - -#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 -#include -#include - -/** - * sk_filter_trim_cap - run a packet through a socket filter - * @sk: sock associated with &sk_buff - * @skb: buffer to filter - * @cap: limit on how short the eBPF program may trim the packet - * - * Run the eBPF program and then cut skb->data to correct size returned by - * the program. If pkt_len is 0 we toss packet. If skb->len is smaller - * than pkt_len we keep whole skb->data. This is the socket level - * wrapper to BPF_PROG_RUN. It returns 0 if the packet should - * be accepted or -EPERM if the packet should be tossed. - * - */ -int sk_filter_trim_cap(struct sock *sk, struct sk_buff *skb, unsigned int cap) -{ - int err; - struct sk_filter *filter; - - /* - * If the skb was allocated from pfmemalloc reserves, only - * allow SOCK_MEMALLOC sockets to use it as this socket is - * helping free memory - */ - if (skb_pfmemalloc(skb) && !sock_flag(sk, SOCK_MEMALLOC)) - return -ENOMEM; - - err = security_sock_rcv_skb(sk, skb); - if (err) - return err; - - rcu_read_lock(); - filter = rcu_dereference(sk->sk_filter); - if (filter) { - unsigned int pkt_len = bpf_prog_run_save_cb(filter->prog, skb); - err = pkt_len ? pskb_trim(skb, max(cap, pkt_len)) : -EPERM; - } - rcu_read_unlock(); - - return err; -} -EXPORT_SYMBOL(sk_filter_trim_cap); - -BPF_CALL_1(__skb_get_pay_offset, struct sk_buff *, skb) -{ - return skb_get_poff(skb); -} - -BPF_CALL_3(__skb_get_nlattr, struct sk_buff *, skb, u32, a, u32, x) -{ - struct nlattr *nla; - - if (skb_is_nonlinear(skb)) - return 0; - - if (skb->len < sizeof(struct nlattr)) - return 0; - - if (a > skb->len - sizeof(struct nlattr)) - return 0; - - nla = nla_find((struct nlattr *) &skb->data[a], skb->len - a, x); - if (nla) - return (void *) nla - (void *) skb->data; - - return 0; -} - -BPF_CALL_3(__skb_get_nlattr_nest, struct sk_buff *, skb, u32, a, u32, x) -{ - struct nlattr *nla; - - if (skb_is_nonlinear(skb)) - return 0; - - if (skb->len < sizeof(struct nlattr)) - return 0; - - if (a > skb->len - sizeof(struct nlattr)) - return 0; - - nla = (struct nlattr *) &skb->data[a]; - if (nla->nla_len > skb->len - a) - return 0; - - nla = nla_find_nested(nla, x); - if (nla) - return (void *) nla - (void *) skb->data; - - return 0; -} - -BPF_CALL_0(__get_raw_cpu_id) -{ - return raw_smp_processor_id(); -} - -static const struct bpf_func_proto bpf_get_raw_smp_processor_id_proto = { - .func = __get_raw_cpu_id, - .gpl_only = false, - .ret_type = RET_INTEGER, -}; - -static u32 convert_skb_access(int skb_field, int dst_reg, int src_reg, - struct bpf_insn *insn_buf) -{ - struct bpf_insn *insn = insn_buf; - - switch (skb_field) { - case SKF_AD_MARK: - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4); - - *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, src_reg, - offsetof(struct sk_buff, mark)); - break; - - case SKF_AD_PKTTYPE: - *insn++ = BPF_LDX_MEM(BPF_B, dst_reg, src_reg, PKT_TYPE_OFFSET()); - *insn++ = BPF_ALU32_IMM(BPF_AND, dst_reg, PKT_TYPE_MAX); -#ifdef __BIG_ENDIAN_BITFIELD - *insn++ = BPF_ALU32_IMM(BPF_RSH, dst_reg, 5); -#endif - break; - - case SKF_AD_QUEUE: - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, queue_mapping) != 2); - - *insn++ = BPF_LDX_MEM(BPF_H, dst_reg, src_reg, - offsetof(struct sk_buff, queue_mapping)); - break; - - case SKF_AD_VLAN_TAG: - case SKF_AD_VLAN_TAG_PRESENT: - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_tci) != 2); - BUILD_BUG_ON(VLAN_TAG_PRESENT != 0x1000); - - /* dst_reg = *(u16 *) (src_reg + offsetof(vlan_tci)) */ - *insn++ = BPF_LDX_MEM(BPF_H, dst_reg, src_reg, - offsetof(struct sk_buff, vlan_tci)); - if (skb_field == SKF_AD_VLAN_TAG) { - *insn++ = BPF_ALU32_IMM(BPF_AND, dst_reg, - ~VLAN_TAG_PRESENT); - } else { - /* dst_reg >>= 12 */ - *insn++ = BPF_ALU32_IMM(BPF_RSH, dst_reg, 12); - /* dst_reg &= 1 */ - *insn++ = BPF_ALU32_IMM(BPF_AND, dst_reg, 1); - } - break; - } - - return insn - insn_buf; -} - -static bool convert_bpf_extensions(struct sock_filter *fp, - struct bpf_insn **insnp) -{ - struct bpf_insn *insn = *insnp; - u32 cnt; - - switch (fp->k) { - case SKF_AD_OFF + SKF_AD_PROTOCOL: - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2); - - /* A = *(u16 *) (CTX + offsetof(protocol)) */ - *insn++ = BPF_LDX_MEM(BPF_H, BPF_REG_A, BPF_REG_CTX, - offsetof(struct sk_buff, protocol)); - /* A = ntohs(A) [emitting a nop or swap16] */ - *insn = BPF_ENDIAN(BPF_FROM_BE, BPF_REG_A, 16); - break; - - case SKF_AD_OFF + SKF_AD_PKTTYPE: - cnt = convert_skb_access(SKF_AD_PKTTYPE, BPF_REG_A, BPF_REG_CTX, insn); - insn += cnt - 1; - break; - - case SKF_AD_OFF + SKF_AD_IFINDEX: - case SKF_AD_OFF + SKF_AD_HATYPE: - BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4); - BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, type) != 2); - - *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, dev), - BPF_REG_TMP, BPF_REG_CTX, - offsetof(struct sk_buff, dev)); - /* if (tmp != 0) goto pc + 1 */ - *insn++ = BPF_JMP_IMM(BPF_JNE, BPF_REG_TMP, 0, 1); - *insn++ = BPF_EXIT_INSN(); - if (fp->k == SKF_AD_OFF + SKF_AD_IFINDEX) - *insn = BPF_LDX_MEM(BPF_W, BPF_REG_A, BPF_REG_TMP, - offsetof(struct net_device, ifindex)); - else - *insn = BPF_LDX_MEM(BPF_H, BPF_REG_A, BPF_REG_TMP, - offsetof(struct net_device, type)); - break; - - case SKF_AD_OFF + SKF_AD_MARK: - cnt = convert_skb_access(SKF_AD_MARK, BPF_REG_A, BPF_REG_CTX, insn); - insn += cnt - 1; - break; - - case SKF_AD_OFF + SKF_AD_RXHASH: - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4); - - *insn = BPF_LDX_MEM(BPF_W, BPF_REG_A, BPF_REG_CTX, - offsetof(struct sk_buff, hash)); - break; - - case SKF_AD_OFF + SKF_AD_QUEUE: - cnt = convert_skb_access(SKF_AD_QUEUE, BPF_REG_A, BPF_REG_CTX, insn); - insn += cnt - 1; - break; - - case SKF_AD_OFF + SKF_AD_VLAN_TAG: - cnt = convert_skb_access(SKF_AD_VLAN_TAG, - BPF_REG_A, BPF_REG_CTX, insn); - insn += cnt - 1; - break; - - case SKF_AD_OFF + SKF_AD_VLAN_TAG_PRESENT: - cnt = convert_skb_access(SKF_AD_VLAN_TAG_PRESENT, - BPF_REG_A, BPF_REG_CTX, insn); - insn += cnt - 1; - break; - - case SKF_AD_OFF + SKF_AD_VLAN_TPID: - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_proto) != 2); - - /* A = *(u16 *) (CTX + offsetof(vlan_proto)) */ - *insn++ = BPF_LDX_MEM(BPF_H, BPF_REG_A, BPF_REG_CTX, - offsetof(struct sk_buff, vlan_proto)); - /* A = ntohs(A) [emitting a nop or swap16] */ - *insn = BPF_ENDIAN(BPF_FROM_BE, BPF_REG_A, 16); - break; - - case SKF_AD_OFF + SKF_AD_PAY_OFFSET: - case SKF_AD_OFF + SKF_AD_NLATTR: - case SKF_AD_OFF + SKF_AD_NLATTR_NEST: - case SKF_AD_OFF + SKF_AD_CPU: - case SKF_AD_OFF + SKF_AD_RANDOM: - /* arg1 = CTX */ - *insn++ = BPF_MOV64_REG(BPF_REG_ARG1, BPF_REG_CTX); - /* arg2 = A */ - *insn++ = BPF_MOV64_REG(BPF_REG_ARG2, BPF_REG_A); - /* arg3 = X */ - *insn++ = BPF_MOV64_REG(BPF_REG_ARG3, BPF_REG_X); - /* Emit call(arg1=CTX, arg2=A, arg3=X) */ - switch (fp->k) { - case SKF_AD_OFF + SKF_AD_PAY_OFFSET: - *insn = BPF_EMIT_CALL(__skb_get_pay_offset); - break; - case SKF_AD_OFF + SKF_AD_NLATTR: - *insn = BPF_EMIT_CALL(__skb_get_nlattr); - break; - case SKF_AD_OFF + SKF_AD_NLATTR_NEST: - *insn = BPF_EMIT_CALL(__skb_get_nlattr_nest); - break; - case SKF_AD_OFF + SKF_AD_CPU: - *insn = BPF_EMIT_CALL(__get_raw_cpu_id); - break; - case SKF_AD_OFF + SKF_AD_RANDOM: - *insn = BPF_EMIT_CALL(bpf_user_rnd_u32); - bpf_user_rnd_init_once(); - break; - } - break; - - case SKF_AD_OFF + SKF_AD_ALU_XOR_X: - /* A ^= X */ - *insn = BPF_ALU32_REG(BPF_XOR, BPF_REG_A, BPF_REG_X); - break; - - default: - /* This is just a dummy call to avoid letting the compiler - * evict __bpf_call_base() as an optimization. Placed here - * where no-one bothers. - */ - BUG_ON(__bpf_call_base(0, 0, 0, 0, 0) != 0); - return false; - } - - *insnp = insn; - return true; -} - -/** - * bpf_convert_filter - convert filter program - * @prog: the user passed filter program - * @len: the length of the user passed filter program - * @new_prog: buffer where converted program will be stored - * @new_len: pointer to store length of converted program - * - * Remap 'sock_filter' style BPF instruction set to 'sock_filter_ext' style. - * Conversion workflow: - * - * 1) First pass for calculating the new program length: - * bpf_convert_filter(old_prog, old_len, NULL, &new_len) - * - * 2) 2nd pass to remap in two passes: 1st pass finds new - * jump offsets, 2nd pass remapping: - * new_prog = kmalloc(sizeof(struct bpf_insn) * new_len); - * bpf_convert_filter(old_prog, old_len, new_prog, &new_len); - */ -static int bpf_convert_filter(struct sock_filter *prog, int len, - struct bpf_insn *new_prog, int *new_len) -{ - int new_flen = 0, pass = 0, target, i; - struct bpf_insn *new_insn; - struct sock_filter *fp; - int *addrs = NULL; - u8 bpf_src; - - BUILD_BUG_ON(BPF_MEMWORDS * sizeof(u32) > MAX_BPF_STACK); - BUILD_BUG_ON(BPF_REG_FP + 1 != MAX_BPF_REG); - - if (len <= 0 || len > BPF_MAXINSNS) - return -EINVAL; - - if (new_prog) { - addrs = kcalloc(len, sizeof(*addrs), - GFP_KERNEL | __GFP_NOWARN); - if (!addrs) - return -ENOMEM; - } - -do_pass: - new_insn = new_prog; - fp = prog; - - /* Classic BPF related prologue emission. */ - if (new_insn) { - /* Classic BPF expects A and X to be reset first. These need - * to be guaranteed to be the first two instructions. - */ - *new_insn++ = BPF_ALU64_REG(BPF_XOR, BPF_REG_A, BPF_REG_A); - *new_insn++ = BPF_ALU64_REG(BPF_XOR, BPF_REG_X, BPF_REG_X); - - /* All programs must keep CTX in callee saved BPF_REG_CTX. - * In eBPF case it's done by the compiler, here we need to - * do this ourself. Initial CTX is present in BPF_REG_ARG1. - */ - *new_insn++ = BPF_MOV64_REG(BPF_REG_CTX, BPF_REG_ARG1); - } else { - new_insn += 3; - } - - for (i = 0; i < len; fp++, i++) { - struct bpf_insn tmp_insns[6] = { }; - struct bpf_insn *insn = tmp_insns; - - if (addrs) - addrs[i] = new_insn - new_prog; - - switch (fp->code) { - /* All arithmetic insns and skb loads map as-is. */ - case BPF_ALU | BPF_ADD | BPF_X: - case BPF_ALU | BPF_ADD | BPF_K: - case BPF_ALU | BPF_SUB | BPF_X: - case BPF_ALU | BPF_SUB | BPF_K: - case BPF_ALU | BPF_AND | BPF_X: - case BPF_ALU | BPF_AND | BPF_K: - case BPF_ALU | BPF_OR | BPF_X: - case BPF_ALU | BPF_OR | BPF_K: - case BPF_ALU | BPF_LSH | BPF_X: - case BPF_ALU | BPF_LSH | BPF_K: - case BPF_ALU | BPF_RSH | BPF_X: - case BPF_ALU | BPF_RSH | BPF_K: - case BPF_ALU | BPF_XOR | BPF_X: - case BPF_ALU | BPF_XOR | BPF_K: - case BPF_ALU | BPF_MUL | BPF_X: - case BPF_ALU | BPF_MUL | BPF_K: - case BPF_ALU | BPF_DIV | BPF_X: - case BPF_ALU | BPF_DIV | BPF_K: - case BPF_ALU | BPF_MOD | BPF_X: - case BPF_ALU | BPF_MOD | BPF_K: - case BPF_ALU | BPF_NEG: - case BPF_LD | BPF_ABS | BPF_W: - case BPF_LD | BPF_ABS | BPF_H: - case BPF_LD | BPF_ABS | BPF_B: - case BPF_LD | BPF_IND | BPF_W: - case BPF_LD | BPF_IND | BPF_H: - case BPF_LD | BPF_IND | BPF_B: - /* Check for overloaded BPF extension and - * directly convert it if found, otherwise - * just move on with mapping. - */ - if (BPF_CLASS(fp->code) == BPF_LD && - BPF_MODE(fp->code) == BPF_ABS && - convert_bpf_extensions(fp, &insn)) - break; - - *insn = BPF_RAW_INSN(fp->code, BPF_REG_A, BPF_REG_X, 0, fp->k); - break; - - /* Jump transformation cannot use BPF block macros - * everywhere as offset calculation and target updates - * require a bit more work than the rest, i.e. jump - * opcodes map as-is, but offsets need adjustment. - */ - -#define BPF_EMIT_JMP \ - do { \ - if (target >= len || target < 0) \ - goto err; \ - insn->off = addrs ? addrs[target] - addrs[i] - 1 : 0; \ - /* Adjust pc relative offset for 2nd or 3rd insn. */ \ - insn->off -= insn - tmp_insns; \ - } while (0) - - case BPF_JMP | BPF_JA: - target = i + fp->k + 1; - insn->code = fp->code; - BPF_EMIT_JMP; - break; - - case BPF_JMP | BPF_JEQ | BPF_K: - case BPF_JMP | BPF_JEQ | BPF_X: - case BPF_JMP | BPF_JSET | BPF_K: - case BPF_JMP | BPF_JSET | BPF_X: - case BPF_JMP | BPF_JGT | BPF_K: - case BPF_JMP | BPF_JGT | BPF_X: - case BPF_JMP | BPF_JGE | BPF_K: - case BPF_JMP | BPF_JGE | BPF_X: - if (BPF_SRC(fp->code) == BPF_K && (int) fp->k < 0) { - /* BPF immediates are signed, zero extend - * immediate into tmp register and use it - * in compare insn. - */ - *insn++ = BPF_MOV32_IMM(BPF_REG_TMP, fp->k); - - insn->dst_reg = BPF_REG_A; - insn->src_reg = BPF_REG_TMP; - bpf_src = BPF_X; - } else { - insn->dst_reg = BPF_REG_A; - insn->imm = fp->k; - bpf_src = BPF_SRC(fp->code); - insn->src_reg = bpf_src == BPF_X ? BPF_REG_X : 0; - } - - /* Common case where 'jump_false' is next insn. */ - if (fp->jf == 0) { - insn->code = BPF_JMP | BPF_OP(fp->code) | bpf_src; - target = i + fp->jt + 1; - BPF_EMIT_JMP; - break; - } - - /* Convert JEQ into JNE when 'jump_true' is next insn. */ - if (fp->jt == 0 && BPF_OP(fp->code) == BPF_JEQ) { - insn->code = BPF_JMP | BPF_JNE | bpf_src; - target = i + fp->jf + 1; - BPF_EMIT_JMP; - break; - } - - /* Other jumps are mapped into two insns: Jxx and JA. */ - target = i + fp->jt + 1; - insn->code = BPF_JMP | BPF_OP(fp->code) | bpf_src; - BPF_EMIT_JMP; - insn++; - - insn->code = BPF_JMP | BPF_JA; - target = i + fp->jf + 1; - BPF_EMIT_JMP; - break; - - /* ldxb 4 * ([14] & 0xf) is remaped into 6 insns. */ - case BPF_LDX | BPF_MSH | BPF_B: - /* tmp = A */ - *insn++ = BPF_MOV64_REG(BPF_REG_TMP, BPF_REG_A); - /* A = BPF_R0 = *(u8 *) (skb->data + K) */ - *insn++ = BPF_LD_ABS(BPF_B, fp->k); - /* A &= 0xf */ - *insn++ = BPF_ALU32_IMM(BPF_AND, BPF_REG_A, 0xf); - /* A <<= 2 */ - *insn++ = BPF_ALU32_IMM(BPF_LSH, BPF_REG_A, 2); - /* X = A */ - *insn++ = BPF_MOV64_REG(BPF_REG_X, BPF_REG_A); - /* A = tmp */ - *insn = BPF_MOV64_REG(BPF_REG_A, BPF_REG_TMP); - break; - - /* RET_K is remaped into 2 insns. RET_A case doesn't need an - * extra mov as BPF_REG_0 is already mapped into BPF_REG_A. - */ - case BPF_RET | BPF_A: - case BPF_RET | BPF_K: - if (BPF_RVAL(fp->code) == BPF_K) - *insn++ = BPF_MOV32_RAW(BPF_K, BPF_REG_0, - 0, fp->k); - *insn = BPF_EXIT_INSN(); - break; - - /* Store to stack. */ - case BPF_ST: - case BPF_STX: - *insn = BPF_STX_MEM(BPF_W, BPF_REG_FP, BPF_CLASS(fp->code) == - BPF_ST ? BPF_REG_A : BPF_REG_X, - -(BPF_MEMWORDS - fp->k) * 4); - break; - - /* Load from stack. */ - case BPF_LD | BPF_MEM: - case BPF_LDX | BPF_MEM: - *insn = BPF_LDX_MEM(BPF_W, BPF_CLASS(fp->code) == BPF_LD ? - BPF_REG_A : BPF_REG_X, BPF_REG_FP, - -(BPF_MEMWORDS - fp->k) * 4); - break; - - /* A = K or X = K */ - case BPF_LD | BPF_IMM: - case BPF_LDX | BPF_IMM: - *insn = BPF_MOV32_IMM(BPF_CLASS(fp->code) == BPF_LD ? - BPF_REG_A : BPF_REG_X, fp->k); - break; - - /* X = A */ - case BPF_MISC | BPF_TAX: - *insn = BPF_MOV64_REG(BPF_REG_X, BPF_REG_A); - break; - - /* A = X */ - case BPF_MISC | BPF_TXA: - *insn = BPF_MOV64_REG(BPF_REG_A, BPF_REG_X); - break; - - /* A = skb->len or X = skb->len */ - case BPF_LD | BPF_W | BPF_LEN: - case BPF_LDX | BPF_W | BPF_LEN: - *insn = BPF_LDX_MEM(BPF_W, BPF_CLASS(fp->code) == BPF_LD ? - BPF_REG_A : BPF_REG_X, BPF_REG_CTX, - offsetof(struct sk_buff, len)); - break; - - /* Access seccomp_data fields. */ - case BPF_LDX | BPF_ABS | BPF_W: - /* A = *(u32 *) (ctx + K) */ - *insn = BPF_LDX_MEM(BPF_W, BPF_REG_A, BPF_REG_CTX, fp->k); - break; - - /* Unknown instruction. */ - default: - goto err; - } - - insn++; - if (new_prog) - memcpy(new_insn, tmp_insns, - sizeof(*insn) * (insn - tmp_insns)); - new_insn += insn - tmp_insns; - } - - if (!new_prog) { - /* Only calculating new length. */ - *new_len = new_insn - new_prog; - return 0; - } - - pass++; - if (new_flen != new_insn - new_prog) { - new_flen = new_insn - new_prog; - if (pass > 2) - goto err; - goto do_pass; - } - - kfree(addrs); - BUG_ON(*new_len != new_flen); - return 0; -err: - kfree(addrs); - return -EINVAL; -} - -/* Security: - * - * As we dont want to clear mem[] array for each packet going through - * __bpf_prog_run(), we check that filter loaded by user never try to read - * a cell if not previously written, and we check all branches to be sure - * a malicious user doesn't try to abuse us. - */ -static int check_load_and_stores(const struct sock_filter *filter, int flen) -{ - u16 *masks, memvalid = 0; /* One bit per cell, 16 cells */ - int pc, ret = 0; - - BUILD_BUG_ON(BPF_MEMWORDS > 16); - - masks = kmalloc_array(flen, sizeof(*masks), GFP_KERNEL); - if (!masks) - return -ENOMEM; - - memset(masks, 0xff, flen * sizeof(*masks)); - - for (pc = 0; pc < flen; pc++) { - memvalid &= masks[pc]; - - switch (filter[pc].code) { - case BPF_ST: - case BPF_STX: - memvalid |= (1 << filter[pc].k); - break; - case BPF_LD | BPF_MEM: - case BPF_LDX | BPF_MEM: - if (!(memvalid & (1 << filter[pc].k))) { - ret = -EINVAL; - goto error; - } - break; - case BPF_JMP | BPF_JA: - /* A jump must set masks on target */ - masks[pc + 1 + filter[pc].k] &= memvalid; - memvalid = ~0; - break; - case BPF_JMP | BPF_JEQ | BPF_K: - case BPF_JMP | BPF_JEQ | BPF_X: - case BPF_JMP | BPF_JGE | BPF_K: - case BPF_JMP | BPF_JGE | BPF_X: - case BPF_JMP | BPF_JGT | BPF_K: - case BPF_JMP | BPF_JGT | BPF_X: - case BPF_JMP | BPF_JSET | BPF_K: - case BPF_JMP | BPF_JSET | BPF_X: - /* A jump must set masks on targets */ - masks[pc + 1 + filter[pc].jt] &= memvalid; - masks[pc + 1 + filter[pc].jf] &= memvalid; - memvalid = ~0; - break; - } - } -error: - kfree(masks); - return ret; -} - -static bool chk_code_allowed(u16 code_to_probe) -{ - static const bool codes[] = { - /* 32 bit ALU operations */ - [BPF_ALU | BPF_ADD | BPF_K] = true, - [BPF_ALU | BPF_ADD | BPF_X] = true, - [BPF_ALU | BPF_SUB | BPF_K] = true, - [BPF_ALU | BPF_SUB | BPF_X] = true, - [BPF_ALU | BPF_MUL | BPF_K] = true, - [BPF_ALU | BPF_MUL | BPF_X] = true, - [BPF_ALU | BPF_DIV | BPF_K] = true, - [BPF_ALU | BPF_DIV | BPF_X] = true, - [BPF_ALU | BPF_MOD | BPF_K] = true, - [BPF_ALU | BPF_MOD | BPF_X] = true, - [BPF_ALU | BPF_AND | BPF_K] = true, - [BPF_ALU | BPF_AND | BPF_X] = true, - [BPF_ALU | BPF_OR | BPF_K] = true, - [BPF_ALU | BPF_OR | BPF_X] = true, - [BPF_ALU | BPF_XOR | BPF_K] = true, - [BPF_ALU | BPF_XOR | BPF_X] = true, - [BPF_ALU | BPF_LSH | BPF_K] = true, - [BPF_ALU | BPF_LSH | BPF_X] = true, - [BPF_ALU | BPF_RSH | BPF_K] = true, - [BPF_ALU | BPF_RSH | BPF_X] = true, - [BPF_ALU | BPF_NEG] = true, - /* Load instructions */ - [BPF_LD | BPF_W | BPF_ABS] = true, - [BPF_LD | BPF_H | BPF_ABS] = true, - [BPF_LD | BPF_B | BPF_ABS] = true, - [BPF_LD | BPF_W | BPF_LEN] = true, - [BPF_LD | BPF_W | BPF_IND] = true, - [BPF_LD | BPF_H | BPF_IND] = true, - [BPF_LD | BPF_B | BPF_IND] = true, - [BPF_LD | BPF_IMM] = true, - [BPF_LD | BPF_MEM] = true, - [BPF_LDX | BPF_W | BPF_LEN] = true, - [BPF_LDX | BPF_B | BPF_MSH] = true, - [BPF_LDX | BPF_IMM] = true, - [BPF_LDX | BPF_MEM] = true, - /* Store instructions */ - [BPF_ST] = true, - [BPF_STX] = true, - /* Misc instructions */ - [BPF_MISC | BPF_TAX] = true, - [BPF_MISC | BPF_TXA] = true, - /* Return instructions */ - [BPF_RET | BPF_K] = true, - [BPF_RET | BPF_A] = true, - /* Jump instructions */ - [BPF_JMP | BPF_JA] = true, - [BPF_JMP | BPF_JEQ | BPF_K] = true, - [BPF_JMP | BPF_JEQ | BPF_X] = true, - [BPF_JMP | BPF_JGE | BPF_K] = true, - [BPF_JMP | BPF_JGE | BPF_X] = true, - [BPF_JMP | BPF_JGT | BPF_K] = true, - [BPF_JMP | BPF_JGT | BPF_X] = true, - [BPF_JMP | BPF_JSET | BPF_K] = true, - [BPF_JMP | BPF_JSET | BPF_X] = true, - }; - - if (code_to_probe >= ARRAY_SIZE(codes)) - return false; - - return codes[code_to_probe]; -} - -static bool bpf_check_basics_ok(const struct sock_filter *filter, - unsigned int flen) -{ - if (filter == NULL) - return false; - if (flen == 0 || flen > BPF_MAXINSNS) - return false; - - return true; -} - -/** - * bpf_check_classic - verify socket filter code - * @filter: filter to verify - * @flen: length of filter - * - * Check the user's filter code. If we let some ugly - * filter code slip through kaboom! The filter must contain - * no references or jumps that are out of range, no illegal - * instructions, and must end with a RET instruction. - * - * All jumps are forward as they are not signed. - * - * Returns 0 if the rule set is legal or -EINVAL if not. - */ -static int bpf_check_classic(const struct sock_filter *filter, - unsigned int flen) -{ - bool anc_found; - int pc; - - /* Check the filter code now */ - for (pc = 0; pc < flen; pc++) { - const struct sock_filter *ftest = &filter[pc]; - - /* May we actually operate on this code? */ - if (!chk_code_allowed(ftest->code)) - return -EINVAL; - - /* Some instructions need special checks */ - switch (ftest->code) { - case BPF_ALU | BPF_DIV | BPF_K: - case BPF_ALU | BPF_MOD | BPF_K: - /* Check for division by zero */ - if (ftest->k == 0) - return -EINVAL; - break; - case BPF_ALU | BPF_LSH | BPF_K: - case BPF_ALU | BPF_RSH | BPF_K: - if (ftest->k >= 32) - return -EINVAL; - break; - case BPF_LD | BPF_MEM: - case BPF_LDX | BPF_MEM: - case BPF_ST: - case BPF_STX: - /* Check for invalid memory addresses */ - if (ftest->k >= BPF_MEMWORDS) - return -EINVAL; - break; - case BPF_JMP | BPF_JA: - /* Note, the large ftest->k might cause loops. - * Compare this with conditional jumps below, - * where offsets are limited. --ANK (981016) - */ - if (ftest->k >= (unsigned int)(flen - pc - 1)) - return -EINVAL; - break; - case BPF_JMP | BPF_JEQ | BPF_K: - case BPF_JMP | BPF_JEQ | BPF_X: - case BPF_JMP | BPF_JGE | BPF_K: - case BPF_JMP | BPF_JGE | BPF_X: - case BPF_JMP | BPF_JGT | BPF_K: - case BPF_JMP | BPF_JGT | BPF_X: - case BPF_JMP | BPF_JSET | BPF_K: - case BPF_JMP | BPF_JSET | BPF_X: - /* Both conditionals must be safe */ - if (pc + ftest->jt + 1 >= flen || - pc + ftest->jf + 1 >= flen) - return -EINVAL; - break; - case BPF_LD | BPF_W | BPF_ABS: - case BPF_LD | BPF_H | BPF_ABS: - case BPF_LD | BPF_B | BPF_ABS: - anc_found = false; - if (bpf_anc_helper(ftest) & BPF_ANC) - anc_found = true; - /* Ancillary operation unknown or unsupported */ - if (anc_found == false && ftest->k >= SKF_AD_OFF) - return -EINVAL; - } - } - - /* Last instruction must be a RET code */ - switch (filter[flen - 1].code) { - case BPF_RET | BPF_K: - case BPF_RET | BPF_A: - return check_load_and_stores(filter, flen); - } - - return -EINVAL; -} - -static int bpf_prog_store_orig_filter(struct bpf_prog *fp, - const struct sock_fprog *fprog) -{ - unsigned int fsize = bpf_classic_proglen(fprog); - struct sock_fprog_kern *fkprog; - - fp->orig_prog = kmalloc(sizeof(*fkprog), GFP_KERNEL); - if (!fp->orig_prog) - return -ENOMEM; - - fkprog = fp->orig_prog; - fkprog->len = fprog->len; - - fkprog->filter = kmemdup(fp->insns, fsize, - GFP_KERNEL | __GFP_NOWARN); - if (!fkprog->filter) { - kfree(fp->orig_prog); - return -ENOMEM; - } - - return 0; -} - -static void bpf_release_orig_filter(struct bpf_prog *fp) -{ - struct sock_fprog_kern *fprog = fp->orig_prog; - - if (fprog) { - kfree(fprog->filter); - kfree(fprog); - } -} - -static void __bpf_prog_release(struct bpf_prog *prog) -{ - if (prog->type == BPF_PROG_TYPE_SOCKET_FILTER) { - bpf_prog_put(prog); - } else { - bpf_release_orig_filter(prog); - bpf_prog_free(prog); - } -} - -static void __sk_filter_release(struct sk_filter *fp) -{ - __bpf_prog_release(fp->prog); - kfree(fp); -} - -/** - * sk_filter_release_rcu - Release a socket filter by rcu_head - * @rcu: rcu_head that contains the sk_filter to free - */ -static void sk_filter_release_rcu(struct rcu_head *rcu) -{ - struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu); - - __sk_filter_release(fp); -} - -/** - * sk_filter_release - release a socket filter - * @fp: filter to remove - * - * Remove a filter from a socket and release its resources. - */ -static void sk_filter_release(struct sk_filter *fp) -{ - if (atomic_dec_and_test(&fp->refcnt)) - call_rcu(&fp->rcu, sk_filter_release_rcu); -} - -void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp) -{ - u32 filter_size = bpf_prog_size(fp->prog->len); - - atomic_sub(filter_size, &sk->sk_omem_alloc); - sk_filter_release(fp); -} - -/* try to charge the socket memory if there is space available - * return true on success - */ -bool sk_filter_charge(struct sock *sk, struct sk_filter *fp) -{ - u32 filter_size = bpf_prog_size(fp->prog->len); - - /* same check as in sock_kmalloc() */ - if (filter_size <= sysctl_optmem_max && - atomic_read(&sk->sk_omem_alloc) + filter_size < sysctl_optmem_max) { - atomic_inc(&fp->refcnt); - atomic_add(filter_size, &sk->sk_omem_alloc); - return true; - } - return false; -} - -static struct bpf_prog *bpf_migrate_filter(struct bpf_prog *fp) -{ - struct sock_filter *old_prog; - struct bpf_prog *old_fp; - int err, new_len, old_len = fp->len; - - /* We are free to overwrite insns et al right here as it - * won't be used at this point in time anymore internally - * after the migration to the internal BPF instruction - * representation. - */ - BUILD_BUG_ON(sizeof(struct sock_filter) != - sizeof(struct bpf_insn)); - - /* Conversion cannot happen on overlapping memory areas, - * so we need to keep the user BPF around until the 2nd - * pass. At this time, the user BPF is stored in fp->insns. - */ - old_prog = kmemdup(fp->insns, old_len * sizeof(struct sock_filter), - GFP_KERNEL | __GFP_NOWARN); - if (!old_prog) { - err = -ENOMEM; - goto out_err; - } - - /* 1st pass: calculate the new program length. */ - err = bpf_convert_filter(old_prog, old_len, NULL, &new_len); - if (err) - goto out_err_free; - - /* Expand fp for appending the new filter representation. */ - old_fp = fp; - fp = bpf_prog_realloc(old_fp, bpf_prog_size(new_len), 0); - if (!fp) { - /* The old_fp is still around in case we couldn't - * allocate new memory, so uncharge on that one. - */ - fp = old_fp; - err = -ENOMEM; - goto out_err_free; - } - - fp->len = new_len; - - /* 2nd pass: remap sock_filter insns into bpf_insn insns. */ - err = bpf_convert_filter(old_prog, old_len, fp->insnsi, &new_len); - if (err) - /* 2nd bpf_convert_filter() can fail only if it fails - * to allocate memory, remapping must succeed. Note, - * that at this time old_fp has already been released - * by krealloc(). - */ - goto out_err_free; - - /* We are guaranteed to never error here with cBPF to eBPF - * transitions, since there's no issue with type compatibility - * checks on program arrays. - */ - fp = bpf_prog_select_runtime(fp, &err); - - kfree(old_prog); - return fp; - -out_err_free: - kfree(old_prog); -out_err: - __bpf_prog_release(fp); - return ERR_PTR(err); -} - -static struct bpf_prog *bpf_prepare_filter(struct bpf_prog *fp, - bpf_aux_classic_check_t trans) -{ - int err; - - fp->bpf_func = NULL; - fp->jited = 0; - - err = bpf_check_classic(fp->insns, fp->len); - if (err) { - __bpf_prog_release(fp); - return ERR_PTR(err); - } - - /* There might be additional checks and transformations - * needed on classic filters, f.e. in case of seccomp. - */ - if (trans) { - err = trans(fp->insns, fp->len); - if (err) { - __bpf_prog_release(fp); - return ERR_PTR(err); - } - } - - /* Probe if we can JIT compile the filter and if so, do - * the compilation of the filter. - */ - bpf_jit_compile(fp); - - /* JIT compiler couldn't process this filter, so do the - * internal BPF translation for the optimized interpreter. - */ - if (!fp->jited) - fp = bpf_migrate_filter(fp); - - return fp; -} - -/** - * bpf_prog_create - create an unattached filter - * @pfp: the unattached filter that is created - * @fprog: the filter program - * - * Create a filter independent of any socket. We first run some - * sanity checks on it to make sure it does not explode on us later. - * If an error occurs or there is insufficient memory for the filter - * a negative errno code is returned. On success the return is zero. - */ -int bpf_prog_create(struct bpf_prog **pfp, struct sock_fprog_kern *fprog) -{ - unsigned int fsize = bpf_classic_proglen(fprog); - struct bpf_prog *fp; - - /* Make sure new filter is there and in the right amounts. */ - if (!bpf_check_basics_ok(fprog->filter, fprog->len)) - return -EINVAL; - - fp = bpf_prog_alloc(bpf_prog_size(fprog->len), 0); - if (!fp) - return -ENOMEM; - - memcpy(fp->insns, fprog->filter, fsize); - - fp->len = fprog->len; - /* Since unattached filters are not copied back to user - * space through sk_get_filter(), we do not need to hold - * a copy here, and can spare us the work. - */ - fp->orig_prog = NULL; - - /* bpf_prepare_filter() already takes care of freeing - * memory in case something goes wrong. - */ - fp = bpf_prepare_filter(fp, NULL); - if (IS_ERR(fp)) - return PTR_ERR(fp); - - *pfp = fp; - return 0; -} -EXPORT_SYMBOL_GPL(bpf_prog_create); - -/** - * bpf_prog_create_from_user - create an unattached filter from user buffer - * @pfp: the unattached filter that is created - * @fprog: the filter program - * @trans: post-classic verifier transformation handler - * @save_orig: save classic BPF program - * - * This function effectively does the same as bpf_prog_create(), only - * that it builds up its insns buffer from user space provided buffer. - * It also allows for passing a bpf_aux_classic_check_t handler. - */ -int bpf_prog_create_from_user(struct bpf_prog **pfp, struct sock_fprog *fprog, - bpf_aux_classic_check_t trans, bool save_orig) -{ - unsigned int fsize = bpf_classic_proglen(fprog); - struct bpf_prog *fp; - int err; - - /* Make sure new filter is there and in the right amounts. */ - if (!bpf_check_basics_ok(fprog->filter, fprog->len)) - return -EINVAL; - - fp = bpf_prog_alloc(bpf_prog_size(fprog->len), 0); - if (!fp) - return -ENOMEM; - - if (copy_from_user(fp->insns, fprog->filter, fsize)) { - __bpf_prog_free(fp); - return -EFAULT; - } - - fp->len = fprog->len; - fp->orig_prog = NULL; - - if (save_orig) { - err = bpf_prog_store_orig_filter(fp, fprog); - if (err) { - __bpf_prog_free(fp); - return -ENOMEM; - } - } - - /* bpf_prepare_filter() already takes care of freeing - * memory in case something goes wrong. - */ - fp = bpf_prepare_filter(fp, trans); - if (IS_ERR(fp)) - return PTR_ERR(fp); - - *pfp = fp; - return 0; -} -EXPORT_SYMBOL_GPL(bpf_prog_create_from_user); - -void bpf_prog_destroy(struct bpf_prog *fp) -{ - __bpf_prog_release(fp); -} -EXPORT_SYMBOL_GPL(bpf_prog_destroy); - -static int __sk_attach_prog(struct bpf_prog *prog, struct sock *sk) -{ - struct sk_filter *fp, *old_fp; - - fp = kmalloc(sizeof(*fp), GFP_KERNEL); - if (!fp) - return -ENOMEM; - - fp->prog = prog; - atomic_set(&fp->refcnt, 0); - - if (!sk_filter_charge(sk, fp)) { - kfree(fp); - return -ENOMEM; - } - - old_fp = rcu_dereference_protected(sk->sk_filter, - lockdep_sock_is_held(sk)); - rcu_assign_pointer(sk->sk_filter, fp); - - if (old_fp) - sk_filter_uncharge(sk, old_fp); - - return 0; -} - -static int __reuseport_attach_prog(struct bpf_prog *prog, struct sock *sk) -{ - struct bpf_prog *old_prog; - int err; - - if (bpf_prog_size(prog->len) > sysctl_optmem_max) - return -ENOMEM; - - if (sk_unhashed(sk) && sk->sk_reuseport) { - err = reuseport_alloc(sk); - if (err) - return err; - } else if (!rcu_access_pointer(sk->sk_reuseport_cb)) { - /* The socket wasn't bound with SO_REUSEPORT */ - return -EINVAL; - } - - old_prog = reuseport_attach_prog(sk, prog); - if (old_prog) - bpf_prog_destroy(old_prog); - - return 0; -} - -static -struct bpf_prog *__get_filter(struct sock_fprog *fprog, struct sock *sk) -{ - unsigned int fsize = bpf_classic_proglen(fprog); - struct bpf_prog *prog; - int err; - - if (sock_flag(sk, SOCK_FILTER_LOCKED)) - return ERR_PTR(-EPERM); - - /* Make sure new filter is there and in the right amounts. */ - if (!bpf_check_basics_ok(fprog->filter, fprog->len)) - return ERR_PTR(-EINVAL); - - prog = bpf_prog_alloc(bpf_prog_size(fprog->len), 0); - if (!prog) - return ERR_PTR(-ENOMEM); - - if (copy_from_user(prog->insns, fprog->filter, fsize)) { - __bpf_prog_free(prog); - return ERR_PTR(-EFAULT); - } - - prog->len = fprog->len; - - err = bpf_prog_store_orig_filter(prog, fprog); - if (err) { - __bpf_prog_free(prog); - return ERR_PTR(-ENOMEM); - } - - /* bpf_prepare_filter() already takes care of freeing - * memory in case something goes wrong. - */ - return bpf_prepare_filter(prog, NULL); -} - -/** - * sk_attach_filter - attach a socket filter - * @fprog: the filter program - * @sk: the socket to use - * - * Attach the user's filter code. We first run some sanity checks on - * it to make sure it does not explode on us later. If an error - * occurs or there is insufficient memory for the filter a negative - * errno code is returned. On success the return is zero. - */ -int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) -{ - struct bpf_prog *prog = __get_filter(fprog, sk); - int err; - - if (IS_ERR(prog)) - return PTR_ERR(prog); - - err = __sk_attach_prog(prog, sk); - if (err < 0) { - __bpf_prog_release(prog); - return err; - } - - return 0; -} -EXPORT_SYMBOL_GPL(sk_attach_filter); - -int sk_reuseport_attach_filter(struct sock_fprog *fprog, struct sock *sk) -{ - struct bpf_prog *prog = __get_filter(fprog, sk); - int err; - - if (IS_ERR(prog)) - return PTR_ERR(prog); - - err = __reuseport_attach_prog(prog, sk); - if (err < 0) { - __bpf_prog_release(prog); - return err; - } - - return 0; -} - -static struct bpf_prog *__get_bpf(u32 ufd, struct sock *sk) -{ - if (sock_flag(sk, SOCK_FILTER_LOCKED)) - return ERR_PTR(-EPERM); - - return bpf_prog_get_type(ufd, BPF_PROG_TYPE_SOCKET_FILTER); -} - -int sk_attach_bpf(u32 ufd, struct sock *sk) -{ - struct bpf_prog *prog = __get_bpf(ufd, sk); - int err; - - if (IS_ERR(prog)) - return PTR_ERR(prog); - - err = __sk_attach_prog(prog, sk); - if (err < 0) { - bpf_prog_put(prog); - return err; - } - - return 0; -} - -int sk_reuseport_attach_bpf(u32 ufd, struct sock *sk) -{ - struct bpf_prog *prog = __get_bpf(ufd, sk); - int err; - - if (IS_ERR(prog)) - return PTR_ERR(prog); - - err = __reuseport_attach_prog(prog, sk); - if (err < 0) { - bpf_prog_put(prog); - return err; - } - - return 0; -} - -struct bpf_scratchpad { - union { - __be32 diff[MAX_BPF_STACK / sizeof(__be32)]; - u8 buff[MAX_BPF_STACK]; - }; -}; - -static DEFINE_PER_CPU(struct bpf_scratchpad, bpf_sp); - -static inline int __bpf_try_make_writable(struct sk_buff *skb, - unsigned int write_len) -{ - return skb_ensure_writable(skb, write_len); -} - -static inline int bpf_try_make_writable(struct sk_buff *skb, - unsigned int write_len) -{ - int err = __bpf_try_make_writable(skb, write_len); - - bpf_compute_data_end(skb); - return err; -} - -static int bpf_try_make_head_writable(struct sk_buff *skb) -{ - return bpf_try_make_writable(skb, skb_headlen(skb)); -} - -static inline void bpf_push_mac_rcsum(struct sk_buff *skb) -{ - if (skb_at_tc_ingress(skb)) - skb_postpush_rcsum(skb, skb_mac_header(skb), skb->mac_len); -} - -static inline void bpf_pull_mac_rcsum(struct sk_buff *skb) -{ - if (skb_at_tc_ingress(skb)) - skb_postpull_rcsum(skb, skb_mac_header(skb), skb->mac_len); -} - -BPF_CALL_5(bpf_skb_store_bytes, struct sk_buff *, skb, u32, offset, - const void *, from, u32, len, u64, flags) -{ - void *ptr; - - if (unlikely(flags & ~(BPF_F_RECOMPUTE_CSUM | BPF_F_INVALIDATE_HASH))) - return -EINVAL; - if (unlikely(offset > 0xffff)) - return -EFAULT; - if (unlikely(bpf_try_make_writable(skb, offset + len))) - return -EFAULT; - - ptr = skb->data + offset; - if (flags & BPF_F_RECOMPUTE_CSUM) - __skb_postpull_rcsum(skb, ptr, len, offset); - - memcpy(ptr, from, len); - - if (flags & BPF_F_RECOMPUTE_CSUM) - __skb_postpush_rcsum(skb, ptr, len, offset); - if (flags & BPF_F_INVALIDATE_HASH) - skb_clear_hash(skb); - - return 0; -} - -static const struct bpf_func_proto bpf_skb_store_bytes_proto = { - .func = bpf_skb_store_bytes, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_ANYTHING, - .arg3_type = ARG_PTR_TO_STACK, - .arg4_type = ARG_CONST_STACK_SIZE, - .arg5_type = ARG_ANYTHING, -}; - -BPF_CALL_4(bpf_skb_load_bytes, const struct sk_buff *, skb, u32, offset, - void *, to, u32, len) -{ - void *ptr; - - if (unlikely(offset > 0xffff)) - goto err_clear; - - ptr = skb_header_pointer(skb, offset, len, to); - if (unlikely(!ptr)) - goto err_clear; - if (ptr != to) - memcpy(to, ptr, len); - - return 0; -err_clear: - memset(to, 0, len); - return -EFAULT; -} - -static const struct bpf_func_proto bpf_skb_load_bytes_proto = { - .func = bpf_skb_load_bytes, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_ANYTHING, - .arg3_type = ARG_PTR_TO_RAW_STACK, - .arg4_type = ARG_CONST_STACK_SIZE, -}; - -BPF_CALL_2(bpf_skb_pull_data, struct sk_buff *, skb, u32, len) -{ - /* Idea is the following: should the needed direct read/write - * test fail during runtime, we can pull in more data and redo - * again, since implicitly, we invalidate previous checks here. - * - * Or, since we know how much we need to make read/writeable, - * this can be done once at the program beginning for direct - * access case. By this we overcome limitations of only current - * headroom being accessible. - */ - return bpf_try_make_writable(skb, len ? : skb_headlen(skb)); -} - -static const struct bpf_func_proto bpf_skb_pull_data_proto = { - .func = bpf_skb_pull_data, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_ANYTHING, -}; - -BPF_CALL_5(bpf_l3_csum_replace, struct sk_buff *, skb, u32, offset, - u64, from, u64, to, u64, flags) -{ - __sum16 *ptr; - - if (unlikely(flags & ~(BPF_F_HDR_FIELD_MASK))) - return -EINVAL; - if (unlikely(offset > 0xffff || offset & 1)) - return -EFAULT; - if (unlikely(bpf_try_make_writable(skb, offset + sizeof(*ptr)))) - return -EFAULT; - - ptr = (__sum16 *)(skb->data + offset); - switch (flags & BPF_F_HDR_FIELD_MASK) { - case 0: - if (unlikely(from != 0)) - return -EINVAL; - - csum_replace_by_diff(ptr, to); - break; - case 2: - csum_replace2(ptr, from, to); - break; - case 4: - csum_replace4(ptr, from, to); - break; - default: - return -EINVAL; - } - - return 0; -} - -static const struct bpf_func_proto bpf_l3_csum_replace_proto = { - .func = bpf_l3_csum_replace, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_ANYTHING, - .arg3_type = ARG_ANYTHING, - .arg4_type = ARG_ANYTHING, - .arg5_type = ARG_ANYTHING, -}; - -BPF_CALL_5(bpf_l4_csum_replace, struct sk_buff *, skb, u32, offset, - u64, from, u64, to, u64, flags) -{ - bool is_pseudo = flags & BPF_F_PSEUDO_HDR; - bool is_mmzero = flags & BPF_F_MARK_MANGLED_0; - __sum16 *ptr; - - if (unlikely(flags & ~(BPF_F_MARK_MANGLED_0 | BPF_F_PSEUDO_HDR | - BPF_F_HDR_FIELD_MASK))) - return -EINVAL; - if (unlikely(offset > 0xffff || offset & 1)) - return -EFAULT; - if (unlikely(bpf_try_make_writable(skb, offset + sizeof(*ptr)))) - return -EFAULT; - - ptr = (__sum16 *)(skb->data + offset); - if (is_mmzero && !*ptr) - return 0; - - switch (flags & BPF_F_HDR_FIELD_MASK) { - case 0: - if (unlikely(from != 0)) - return -EINVAL; - - inet_proto_csum_replace_by_diff(ptr, skb, to, is_pseudo); - break; - case 2: - inet_proto_csum_replace2(ptr, skb, from, to, is_pseudo); - break; - case 4: - inet_proto_csum_replace4(ptr, skb, from, to, is_pseudo); - break; - default: - return -EINVAL; - } - - if (is_mmzero && !*ptr) - *ptr = CSUM_MANGLED_0; - return 0; -} - -static const struct bpf_func_proto bpf_l4_csum_replace_proto = { - .func = bpf_l4_csum_replace, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_ANYTHING, - .arg3_type = ARG_ANYTHING, - .arg4_type = ARG_ANYTHING, - .arg5_type = ARG_ANYTHING, -}; - -BPF_CALL_5(bpf_csum_diff, __be32 *, from, u32, from_size, - __be32 *, to, u32, to_size, __wsum, seed) -{ - struct bpf_scratchpad *sp = this_cpu_ptr(&bpf_sp); - u32 diff_size = from_size + to_size; - int i, j = 0; - - /* This is quite flexible, some examples: - * - * from_size == 0, to_size > 0, seed := csum --> pushing data - * from_size > 0, to_size == 0, seed := csum --> pulling data - * from_size > 0, to_size > 0, seed := 0 --> diffing data - * - * Even for diffing, from_size and to_size don't need to be equal. - */ - if (unlikely(((from_size | to_size) & (sizeof(__be32) - 1)) || - diff_size > sizeof(sp->diff))) - return -EINVAL; - - for (i = 0; i < from_size / sizeof(__be32); i++, j++) - sp->diff[j] = ~from[i]; - for (i = 0; i < to_size / sizeof(__be32); i++, j++) - sp->diff[j] = to[i]; - - return csum_partial(sp->diff, diff_size, seed); -} - -static const struct bpf_func_proto bpf_csum_diff_proto = { - .func = bpf_csum_diff, - .gpl_only = false, - .pkt_access = true, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_STACK, - .arg2_type = ARG_CONST_STACK_SIZE_OR_ZERO, - .arg3_type = ARG_PTR_TO_STACK, - .arg4_type = ARG_CONST_STACK_SIZE_OR_ZERO, - .arg5_type = ARG_ANYTHING, -}; - -BPF_CALL_2(bpf_csum_update, struct sk_buff *, skb, __wsum, csum) -{ - /* The interface is to be used in combination with bpf_csum_diff() - * for direct packet writes. csum rotation for alignment as well - * as emulating csum_sub() can be done from the eBPF program. - */ - if (skb->ip_summed == CHECKSUM_COMPLETE) - return (skb->csum = csum_add(skb->csum, csum)); - - return -ENOTSUPP; -} - -static const struct bpf_func_proto bpf_csum_update_proto = { - .func = bpf_csum_update, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_ANYTHING, -}; - -static inline int __bpf_rx_skb(struct net_device *dev, struct sk_buff *skb) -{ - return dev_forward_skb(dev, skb); -} - -static inline int __bpf_rx_skb_no_mac(struct net_device *dev, - struct sk_buff *skb) -{ - int ret = ____dev_forward_skb(dev, skb); - - if (likely(!ret)) { - skb->dev = dev; - ret = netif_rx(skb); - } - - return ret; -} - -static inline int __bpf_tx_skb(struct net_device *dev, struct sk_buff *skb) -{ - int ret; - - if (unlikely(__this_cpu_read(xmit_recursion) > XMIT_RECURSION_LIMIT)) { - net_crit_ratelimited("bpf: recursion limit reached on datapath, buggy bpf program?\n"); - kfree_skb(skb); - return -ENETDOWN; - } - - skb->dev = dev; - - __this_cpu_inc(xmit_recursion); - ret = dev_queue_xmit(skb); - __this_cpu_dec(xmit_recursion); - - return ret; -} - -static int __bpf_redirect_no_mac(struct sk_buff *skb, struct net_device *dev, - u32 flags) -{ - /* skb->mac_len is not set on normal egress */ - unsigned int mlen = skb->network_header - skb->mac_header; - - __skb_pull(skb, mlen); - - /* At ingress, the mac header has already been pulled once. - * At egress, skb_pospull_rcsum has to be done in case that - * the skb is originated from ingress (i.e. a forwarded skb) - * to ensure that rcsum starts at net header. - */ - if (!skb_at_tc_ingress(skb)) - skb_postpull_rcsum(skb, skb_mac_header(skb), mlen); - skb_pop_mac_header(skb); - skb_reset_mac_len(skb); - return flags & BPF_F_INGRESS ? - __bpf_rx_skb_no_mac(dev, skb) : __bpf_tx_skb(dev, skb); -} - -static int __bpf_redirect_common(struct sk_buff *skb, struct net_device *dev, - u32 flags) -{ - bpf_push_mac_rcsum(skb); - return flags & BPF_F_INGRESS ? - __bpf_rx_skb(dev, skb) : __bpf_tx_skb(dev, skb); -} - -static int __bpf_redirect(struct sk_buff *skb, struct net_device *dev, - u32 flags) -{ - switch (dev->type) { - case ARPHRD_TUNNEL: - case ARPHRD_TUNNEL6: - case ARPHRD_SIT: - case ARPHRD_IPGRE: - case ARPHRD_VOID: - case ARPHRD_NONE: - return __bpf_redirect_no_mac(skb, dev, flags); - default: - return __bpf_redirect_common(skb, dev, flags); - } -} - -BPF_CALL_3(bpf_clone_redirect, struct sk_buff *, skb, u32, ifindex, u64, flags) -{ - struct net_device *dev; - struct sk_buff *clone; - int ret; - - if (unlikely(flags & ~(BPF_F_INGRESS))) - return -EINVAL; - - dev = dev_get_by_index_rcu(dev_net(skb->dev), ifindex); - if (unlikely(!dev)) - return -EINVAL; - - clone = skb_clone(skb, GFP_ATOMIC); - if (unlikely(!clone)) - return -ENOMEM; - - /* For direct write, we need to keep the invariant that the skbs - * we're dealing with need to be uncloned. Should uncloning fail - * here, we need to free the just generated clone to unclone once - * again. - */ - ret = bpf_try_make_head_writable(skb); - if (unlikely(ret)) { - kfree_skb(clone); - return -ENOMEM; - } - - return __bpf_redirect(clone, dev, flags); -} - -static const struct bpf_func_proto bpf_clone_redirect_proto = { - .func = bpf_clone_redirect, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_ANYTHING, - .arg3_type = ARG_ANYTHING, -}; - -struct redirect_info { - u32 ifindex; - u32 flags; -}; - -static DEFINE_PER_CPU(struct redirect_info, redirect_info); - -BPF_CALL_2(bpf_redirect, u32, ifindex, u64, flags) -{ - struct redirect_info *ri = this_cpu_ptr(&redirect_info); - - if (unlikely(flags & ~(BPF_F_INGRESS))) - return TC_ACT_SHOT; - - ri->ifindex = ifindex; - ri->flags = flags; - - return TC_ACT_REDIRECT; -} - -int skb_do_redirect(struct sk_buff *skb) -{ - struct redirect_info *ri = this_cpu_ptr(&redirect_info); - struct net_device *dev; - - dev = dev_get_by_index_rcu(dev_net(skb->dev), ri->ifindex); - ri->ifindex = 0; - if (unlikely(!dev)) { - kfree_skb(skb); - return -EINVAL; - } - - return __bpf_redirect(skb, dev, ri->flags); -} - -static const struct bpf_func_proto bpf_redirect_proto = { - .func = bpf_redirect, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_ANYTHING, - .arg2_type = ARG_ANYTHING, -}; - -BPF_CALL_1(bpf_get_cgroup_classid, const struct sk_buff *, skb) -{ - return task_get_classid(skb); -} - -static const struct bpf_func_proto bpf_get_cgroup_classid_proto = { - .func = bpf_get_cgroup_classid, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, -}; - -BPF_CALL_1(bpf_get_route_realm, const struct sk_buff *, skb) -{ - return dst_tclassid(skb); -} - -static const struct bpf_func_proto bpf_get_route_realm_proto = { - .func = bpf_get_route_realm, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, -}; - -BPF_CALL_1(bpf_get_hash_recalc, struct sk_buff *, skb) -{ - /* If skb_clear_hash() was called due to mangling, we can - * trigger SW recalculation here. Later access to hash - * can then use the inline skb->hash via context directly - * instead of calling this helper again. - */ - return skb_get_hash(skb); -} - -static const struct bpf_func_proto bpf_get_hash_recalc_proto = { - .func = bpf_get_hash_recalc, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, -}; - -BPF_CALL_1(bpf_set_hash_invalid, struct sk_buff *, skb) -{ - /* After all direct packet write, this can be used once for - * triggering a lazy recalc on next skb_get_hash() invocation. - */ - skb_clear_hash(skb); - return 0; -} - -static const struct bpf_func_proto bpf_set_hash_invalid_proto = { - .func = bpf_set_hash_invalid, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, -}; - -BPF_CALL_3(bpf_skb_vlan_push, struct sk_buff *, skb, __be16, vlan_proto, - u16, vlan_tci) -{ - int ret; - - if (unlikely(vlan_proto != htons(ETH_P_8021Q) && - vlan_proto != htons(ETH_P_8021AD))) - vlan_proto = htons(ETH_P_8021Q); - - bpf_push_mac_rcsum(skb); - ret = skb_vlan_push(skb, vlan_proto, vlan_tci); - bpf_pull_mac_rcsum(skb); - - bpf_compute_data_end(skb); - return ret; -} - -const struct bpf_func_proto bpf_skb_vlan_push_proto = { - .func = bpf_skb_vlan_push, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_ANYTHING, - .arg3_type = ARG_ANYTHING, -}; -EXPORT_SYMBOL_GPL(bpf_skb_vlan_push_proto); - -BPF_CALL_1(bpf_skb_vlan_pop, struct sk_buff *, skb) -{ - int ret; - - bpf_push_mac_rcsum(skb); - ret = skb_vlan_pop(skb); - bpf_pull_mac_rcsum(skb); - - bpf_compute_data_end(skb); - return ret; -} - -const struct bpf_func_proto bpf_skb_vlan_pop_proto = { - .func = bpf_skb_vlan_pop, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, -}; -EXPORT_SYMBOL_GPL(bpf_skb_vlan_pop_proto); - -static int bpf_skb_generic_push(struct sk_buff *skb, u32 off, u32 len) -{ - /* Caller already did skb_cow() with len as headroom, - * so no need to do it here. - */ - skb_push(skb, len); - memmove(skb->data, skb->data + len, off); - memset(skb->data + off, 0, len); - - /* No skb_postpush_rcsum(skb, skb->data + off, len) - * needed here as it does not change the skb->csum - * result for checksum complete when summing over - * zeroed blocks. - */ - return 0; -} - -static int bpf_skb_generic_pop(struct sk_buff *skb, u32 off, u32 len) -{ - /* skb_ensure_writable() is not needed here, as we're - * already working on an uncloned skb. - */ - if (unlikely(!pskb_may_pull(skb, off + len))) - return -ENOMEM; - - skb_postpull_rcsum(skb, skb->data + off, len); - memmove(skb->data + len, skb->data, off); - __skb_pull(skb, len); - - return 0; -} - -static int bpf_skb_net_hdr_push(struct sk_buff *skb, u32 off, u32 len) -{ - bool trans_same = skb->transport_header == skb->network_header; - int ret; - - /* There's no need for __skb_push()/__skb_pull() pair to - * get to the start of the mac header as we're guaranteed - * to always start from here under eBPF. - */ - ret = bpf_skb_generic_push(skb, off, len); - if (likely(!ret)) { - skb->mac_header -= len; - skb->network_header -= len; - if (trans_same) - skb->transport_header = skb->network_header; - } - - return ret; -} - -static int bpf_skb_net_hdr_pop(struct sk_buff *skb, u32 off, u32 len) -{ - bool trans_same = skb->transport_header == skb->network_header; - int ret; - - /* Same here, __skb_push()/__skb_pull() pair not needed. */ - ret = bpf_skb_generic_pop(skb, off, len); - if (likely(!ret)) { - skb->mac_header += len; - skb->network_header += len; - if (trans_same) - skb->transport_header = skb->network_header; - } - - return ret; -} - -static int bpf_skb_proto_4_to_6(struct sk_buff *skb) -{ - const u32 len_diff = sizeof(struct ipv6hdr) - sizeof(struct iphdr); - u32 off = skb->network_header - skb->mac_header; - int ret; - - ret = skb_cow(skb, len_diff); - if (unlikely(ret < 0)) - return ret; - - ret = bpf_skb_net_hdr_push(skb, off, len_diff); - if (unlikely(ret < 0)) - return ret; - - if (skb_is_gso(skb)) { - /* SKB_GSO_UDP stays as is. SKB_GSO_TCPV4 needs to - * be changed into SKB_GSO_TCPV6. - */ - if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4) { - skb_shinfo(skb)->gso_type &= ~SKB_GSO_TCPV4; - skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV6; - } - - /* Due to IPv6 header, MSS needs to be downgraded. */ - skb_shinfo(skb)->gso_size -= len_diff; - /* Header must be checked, and gso_segs recomputed. */ - skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; - skb_shinfo(skb)->gso_segs = 0; - } - - skb->protocol = htons(ETH_P_IPV6); - skb_clear_hash(skb); - - return 0; -} - -static int bpf_skb_proto_6_to_4(struct sk_buff *skb) -{ - const u32 len_diff = sizeof(struct ipv6hdr) - sizeof(struct iphdr); - u32 off = skb->network_header - skb->mac_header; - int ret; - - ret = skb_unclone(skb, GFP_ATOMIC); - if (unlikely(ret < 0)) - return ret; - - ret = bpf_skb_net_hdr_pop(skb, off, len_diff); - if (unlikely(ret < 0)) - return ret; - - if (skb_is_gso(skb)) { - /* SKB_GSO_UDP stays as is. SKB_GSO_TCPV6 needs to - * be changed into SKB_GSO_TCPV4. - */ - if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) { - skb_shinfo(skb)->gso_type &= ~SKB_GSO_TCPV6; - skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4; - } - - /* Due to IPv4 header, MSS can be upgraded. */ - skb_shinfo(skb)->gso_size += len_diff; - /* Header must be checked, and gso_segs recomputed. */ - skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY; - skb_shinfo(skb)->gso_segs = 0; - } - - skb->protocol = htons(ETH_P_IP); - skb_clear_hash(skb); - - return 0; -} - -static int bpf_skb_proto_xlat(struct sk_buff *skb, __be16 to_proto) -{ - __be16 from_proto = skb->protocol; - - if (from_proto == htons(ETH_P_IP) && - to_proto == htons(ETH_P_IPV6)) - return bpf_skb_proto_4_to_6(skb); - - if (from_proto == htons(ETH_P_IPV6) && - to_proto == htons(ETH_P_IP)) - return bpf_skb_proto_6_to_4(skb); - - return -ENOTSUPP; -} - -BPF_CALL_3(bpf_skb_change_proto, struct sk_buff *, skb, __be16, proto, - u64, flags) -{ - int ret; - - if (unlikely(flags)) - return -EINVAL; - - /* General idea is that this helper does the basic groundwork - * needed for changing the protocol, and eBPF program fills the - * rest through bpf_skb_store_bytes(), bpf_lX_csum_replace() - * and other helpers, rather than passing a raw buffer here. - * - * The rationale is to keep this minimal and without a need to - * deal with raw packet data. F.e. even if we would pass buffers - * here, the program still needs to call the bpf_lX_csum_replace() - * helpers anyway. Plus, this way we keep also separation of - * concerns, since f.e. bpf_skb_store_bytes() should only take - * care of stores. - * - * Currently, additional options and extension header space are - * not supported, but flags register is reserved so we can adapt - * that. For offloads, we mark packet as dodgy, so that headers - * need to be verified first. - */ - ret = bpf_skb_proto_xlat(skb, proto); - bpf_compute_data_end(skb); - return ret; -} - -static const struct bpf_func_proto bpf_skb_change_proto_proto = { - .func = bpf_skb_change_proto, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_ANYTHING, - .arg3_type = ARG_ANYTHING, -}; - -BPF_CALL_2(bpf_skb_change_type, struct sk_buff *, skb, u32, pkt_type) -{ - /* We only allow a restricted subset to be changed for now. */ - if (unlikely(!skb_pkt_type_ok(skb->pkt_type) || - !skb_pkt_type_ok(pkt_type))) - return -EINVAL; - - skb->pkt_type = pkt_type; - return 0; -} - -static const struct bpf_func_proto bpf_skb_change_type_proto = { - .func = bpf_skb_change_type, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_ANYTHING, -}; - -static u32 __bpf_skb_min_len(const struct sk_buff *skb) -{ - u32 min_len = skb_network_offset(skb); - - if (skb_transport_header_was_set(skb)) - min_len = skb_transport_offset(skb); - if (skb->ip_summed == CHECKSUM_PARTIAL) - min_len = skb_checksum_start_offset(skb) + - skb->csum_offset + sizeof(__sum16); - return min_len; -} - -static u32 __bpf_skb_max_len(const struct sk_buff *skb) -{ - return skb->dev->mtu + skb->dev->hard_header_len; -} - -static int bpf_skb_grow_rcsum(struct sk_buff *skb, unsigned int new_len) -{ - unsigned int old_len = skb->len; - int ret; - - ret = __skb_grow_rcsum(skb, new_len); - if (!ret) - memset(skb->data + old_len, 0, new_len - old_len); - return ret; -} - -static int bpf_skb_trim_rcsum(struct sk_buff *skb, unsigned int new_len) -{ - return __skb_trim_rcsum(skb, new_len); -} - -BPF_CALL_3(bpf_skb_change_tail, struct sk_buff *, skb, u32, new_len, - u64, flags) -{ - u32 max_len = __bpf_skb_max_len(skb); - u32 min_len = __bpf_skb_min_len(skb); - int ret; - - if (unlikely(flags || new_len > max_len || new_len < min_len)) - return -EINVAL; - if (skb->encapsulation) - return -ENOTSUPP; - - /* The basic idea of this helper is that it's performing the - * needed work to either grow or trim an skb, and eBPF program - * rewrites the rest via helpers like bpf_skb_store_bytes(), - * bpf_lX_csum_replace() and others rather than passing a raw - * buffer here. This one is a slow path helper and intended - * for replies with control messages. - * - * Like in bpf_skb_change_proto(), we want to keep this rather - * minimal and without protocol specifics so that we are able - * to separate concerns as in bpf_skb_store_bytes() should only - * be the one responsible for writing buffers. - * - * It's really expected to be a slow path operation here for - * control message replies, so we're implicitly linearizing, - * uncloning and drop offloads from the skb by this. - */ - ret = __bpf_try_make_writable(skb, skb->len); - if (!ret) { - if (new_len > skb->len) - ret = bpf_skb_grow_rcsum(skb, new_len); - else if (new_len < skb->len) - ret = bpf_skb_trim_rcsum(skb, new_len); - if (!ret && skb_is_gso(skb)) - skb_gso_reset(skb); - } - - bpf_compute_data_end(skb); - return ret; -} - -static const struct bpf_func_proto bpf_skb_change_tail_proto = { - .func = bpf_skb_change_tail, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_ANYTHING, - .arg3_type = ARG_ANYTHING, -}; - -bool bpf_helper_changes_skb_data(void *func) -{ - if (func == bpf_skb_vlan_push || - func == bpf_skb_vlan_pop || - func == bpf_skb_store_bytes || - func == bpf_skb_change_proto || - func == bpf_skb_change_tail || - func == bpf_skb_pull_data || - func == bpf_l3_csum_replace || - func == bpf_l4_csum_replace) - return true; - - return false; -} - -static unsigned long bpf_skb_copy(void *dst_buff, const void *skb, - unsigned long off, unsigned long len) -{ - void *ptr = skb_header_pointer(skb, off, len, dst_buff); - - if (unlikely(!ptr)) - return len; - if (ptr != dst_buff) - memcpy(dst_buff, ptr, len); - - return 0; -} - -BPF_CALL_5(bpf_skb_event_output, struct sk_buff *, skb, struct bpf_map *, map, - u64, flags, void *, meta, u64, meta_size) -{ - u64 skb_size = (flags & BPF_F_CTXLEN_MASK) >> 32; - - if (unlikely(flags & ~(BPF_F_CTXLEN_MASK | BPF_F_INDEX_MASK))) - return -EINVAL; - if (unlikely(skb_size > skb->len)) - return -EFAULT; - - return bpf_event_output(map, flags, meta, meta_size, skb, skb_size, - bpf_skb_copy); -} - -static const struct bpf_func_proto bpf_skb_event_output_proto = { - .func = bpf_skb_event_output, - .gpl_only = true, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_CONST_MAP_PTR, - .arg3_type = ARG_ANYTHING, - .arg4_type = ARG_PTR_TO_STACK, - .arg5_type = ARG_CONST_STACK_SIZE, -}; - -static unsigned short bpf_tunnel_key_af(u64 flags) -{ - return flags & BPF_F_TUNINFO_IPV6 ? AF_INET6 : AF_INET; -} - -BPF_CALL_4(bpf_skb_get_tunnel_key, struct sk_buff *, skb, struct bpf_tunnel_key *, to, - u32, size, u64, flags) -{ - const struct ip_tunnel_info *info = skb_tunnel_info(skb); - u8 compat[sizeof(struct bpf_tunnel_key)]; - void *to_orig = to; - int err; - - if (unlikely(!info || (flags & ~(BPF_F_TUNINFO_IPV6)))) { - err = -EINVAL; - goto err_clear; - } - if (ip_tunnel_info_af(info) != bpf_tunnel_key_af(flags)) { - err = -EPROTO; - goto err_clear; - } - if (unlikely(size != sizeof(struct bpf_tunnel_key))) { - err = -EINVAL; - switch (size) { - case offsetof(struct bpf_tunnel_key, tunnel_label): - case offsetof(struct bpf_tunnel_key, tunnel_ext): - goto set_compat; - case offsetof(struct bpf_tunnel_key, remote_ipv6[1]): - /* Fixup deprecated structure layouts here, so we have - * a common path later on. - */ - if (ip_tunnel_info_af(info) != AF_INET) - goto err_clear; -set_compat: - to = (struct bpf_tunnel_key *)compat; - break; - default: - goto err_clear; - } - } - - to->tunnel_id = be64_to_cpu(info->key.tun_id); - to->tunnel_tos = info->key.tos; - to->tunnel_ttl = info->key.ttl; - - if (flags & BPF_F_TUNINFO_IPV6) { - memcpy(to->remote_ipv6, &info->key.u.ipv6.src, - sizeof(to->remote_ipv6)); - to->tunnel_label = be32_to_cpu(info->key.label); - } else { - to->remote_ipv4 = be32_to_cpu(info->key.u.ipv4.src); - } - - if (unlikely(size != sizeof(struct bpf_tunnel_key))) - memcpy(to_orig, to, size); - - return 0; -err_clear: - memset(to_orig, 0, size); - return err; -} - -static const struct bpf_func_proto bpf_skb_get_tunnel_key_proto = { - .func = bpf_skb_get_tunnel_key, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_PTR_TO_RAW_STACK, - .arg3_type = ARG_CONST_STACK_SIZE, - .arg4_type = ARG_ANYTHING, -}; - -BPF_CALL_3(bpf_skb_get_tunnel_opt, struct sk_buff *, skb, u8 *, to, u32, size) -{ - const struct ip_tunnel_info *info = skb_tunnel_info(skb); - int err; - - if (unlikely(!info || - !(info->key.tun_flags & TUNNEL_OPTIONS_PRESENT))) { - err = -ENOENT; - goto err_clear; - } - if (unlikely(size < info->options_len)) { - err = -ENOMEM; - goto err_clear; - } - - ip_tunnel_info_opts_get(to, info); - if (size > info->options_len) - memset(to + info->options_len, 0, size - info->options_len); - - return info->options_len; -err_clear: - memset(to, 0, size); - return err; -} - -static const struct bpf_func_proto bpf_skb_get_tunnel_opt_proto = { - .func = bpf_skb_get_tunnel_opt, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_PTR_TO_RAW_STACK, - .arg3_type = ARG_CONST_STACK_SIZE, -}; - -static struct metadata_dst __percpu *md_dst; - -BPF_CALL_4(bpf_skb_set_tunnel_key, struct sk_buff *, skb, - const struct bpf_tunnel_key *, from, u32, size, u64, flags) -{ - struct metadata_dst *md = this_cpu_ptr(md_dst); - u8 compat[sizeof(struct bpf_tunnel_key)]; - struct ip_tunnel_info *info; - - if (unlikely(flags & ~(BPF_F_TUNINFO_IPV6 | BPF_F_ZERO_CSUM_TX | - BPF_F_DONT_FRAGMENT))) - return -EINVAL; - if (unlikely(size != sizeof(struct bpf_tunnel_key))) { - switch (size) { - case offsetof(struct bpf_tunnel_key, tunnel_label): - case offsetof(struct bpf_tunnel_key, tunnel_ext): - case offsetof(struct bpf_tunnel_key, remote_ipv6[1]): - /* Fixup deprecated structure layouts here, so we have - * a common path later on. - */ - memcpy(compat, from, size); - memset(compat + size, 0, sizeof(compat) - size); - from = (const struct bpf_tunnel_key *) compat; - break; - default: - return -EINVAL; - } - } - if (unlikely((!(flags & BPF_F_TUNINFO_IPV6) && from->tunnel_label) || - from->tunnel_ext)) - return -EINVAL; - - skb_dst_drop(skb); - dst_hold((struct dst_entry *) md); - skb_dst_set(skb, (struct dst_entry *) md); - - info = &md->u.tun_info; - info->mode = IP_TUNNEL_INFO_TX; - - info->key.tun_flags = TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_NOCACHE; - if (flags & BPF_F_DONT_FRAGMENT) - info->key.tun_flags |= TUNNEL_DONT_FRAGMENT; - - info->key.tun_id = cpu_to_be64(from->tunnel_id); - info->key.tos = from->tunnel_tos; - info->key.ttl = from->tunnel_ttl; - - if (flags & BPF_F_TUNINFO_IPV6) { - info->mode |= IP_TUNNEL_INFO_IPV6; - memcpy(&info->key.u.ipv6.dst, from->remote_ipv6, - sizeof(from->remote_ipv6)); - info->key.label = cpu_to_be32(from->tunnel_label) & - IPV6_FLOWLABEL_MASK; - } else { - info->key.u.ipv4.dst = cpu_to_be32(from->remote_ipv4); - if (flags & BPF_F_ZERO_CSUM_TX) - info->key.tun_flags &= ~TUNNEL_CSUM; - } - - return 0; -} - -static const struct bpf_func_proto bpf_skb_set_tunnel_key_proto = { - .func = bpf_skb_set_tunnel_key, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_PTR_TO_STACK, - .arg3_type = ARG_CONST_STACK_SIZE, - .arg4_type = ARG_ANYTHING, -}; - -BPF_CALL_3(bpf_skb_set_tunnel_opt, struct sk_buff *, skb, - const u8 *, from, u32, size) -{ - struct ip_tunnel_info *info = skb_tunnel_info(skb); - const struct metadata_dst *md = this_cpu_ptr(md_dst); - - if (unlikely(info != &md->u.tun_info || (size & (sizeof(u32) - 1)))) - return -EINVAL; - if (unlikely(size > IP_TUNNEL_OPTS_MAX)) - return -ENOMEM; - - ip_tunnel_info_opts_set(info, from, size); - - return 0; -} - -static const struct bpf_func_proto bpf_skb_set_tunnel_opt_proto = { - .func = bpf_skb_set_tunnel_opt, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_PTR_TO_STACK, - .arg3_type = ARG_CONST_STACK_SIZE, -}; - -static const struct bpf_func_proto * -bpf_get_skb_set_tunnel_proto(enum bpf_func_id which) -{ - if (!md_dst) { - /* Race is not possible, since it's called from verifier - * that is holding verifier mutex. - */ - md_dst = metadata_dst_alloc_percpu(IP_TUNNEL_OPTS_MAX, - GFP_KERNEL); - if (!md_dst) - return NULL; - } - - switch (which) { - case BPF_FUNC_skb_set_tunnel_key: - return &bpf_skb_set_tunnel_key_proto; - case BPF_FUNC_skb_set_tunnel_opt: - return &bpf_skb_set_tunnel_opt_proto; - default: - return NULL; - } -} - -BPF_CALL_3(bpf_skb_under_cgroup, struct sk_buff *, skb, struct bpf_map *, map, - u32, idx) -{ - struct bpf_array *array = container_of(map, struct bpf_array, map); - struct cgroup *cgrp; - struct sock *sk; - - sk = skb_to_full_sk(skb); - if (!sk || !sk_fullsock(sk)) - return -ENOENT; - if (unlikely(idx >= array->map.max_entries)) - return -E2BIG; - - cgrp = READ_ONCE(array->ptrs[idx]); - if (unlikely(!cgrp)) - return -EAGAIN; - - return sk_under_cgroup_hierarchy(sk, cgrp); -} - -static const struct bpf_func_proto bpf_skb_under_cgroup_proto = { - .func = bpf_skb_under_cgroup, - .gpl_only = false, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_CONST_MAP_PTR, - .arg3_type = ARG_ANYTHING, -}; - -static unsigned long bpf_xdp_copy(void *dst_buff, const void *src_buff, - unsigned long off, unsigned long len) -{ - memcpy(dst_buff, src_buff + off, len); - return 0; -} - -BPF_CALL_5(bpf_xdp_event_output, struct xdp_buff *, xdp, struct bpf_map *, map, - u64, flags, void *, meta, u64, meta_size) -{ - u64 xdp_size = (flags & BPF_F_CTXLEN_MASK) >> 32; - - if (unlikely(flags & ~(BPF_F_CTXLEN_MASK | BPF_F_INDEX_MASK))) - return -EINVAL; - if (unlikely(xdp_size > (unsigned long)(xdp->data_end - xdp->data))) - return -EFAULT; - - return bpf_event_output(map, flags, meta, meta_size, xdp, xdp_size, - bpf_xdp_copy); -} - -static const struct bpf_func_proto bpf_xdp_event_output_proto = { - .func = bpf_xdp_event_output, - .gpl_only = true, - .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_CONST_MAP_PTR, - .arg3_type = ARG_ANYTHING, - .arg4_type = ARG_PTR_TO_STACK, - .arg5_type = ARG_CONST_STACK_SIZE, -}; - -static const struct bpf_func_proto * -sk_filter_func_proto(enum bpf_func_id func_id) -{ - switch (func_id) { - case BPF_FUNC_map_lookup_elem: - return &bpf_map_lookup_elem_proto; - case BPF_FUNC_map_update_elem: - return &bpf_map_update_elem_proto; - case BPF_FUNC_map_delete_elem: - return &bpf_map_delete_elem_proto; - case BPF_FUNC_get_prandom_u32: - return &bpf_get_prandom_u32_proto; - case BPF_FUNC_get_smp_processor_id: - return &bpf_get_raw_smp_processor_id_proto; - case BPF_FUNC_tail_call: - return &bpf_tail_call_proto; - case BPF_FUNC_ktime_get_ns: - return &bpf_ktime_get_ns_proto; - case BPF_FUNC_trace_printk: - if (capable(CAP_SYS_ADMIN)) - return bpf_get_trace_printk_proto(); - default: - return NULL; - } -} - -static const struct bpf_func_proto * -tc_cls_act_func_proto(enum bpf_func_id func_id) -{ - switch (func_id) { - case BPF_FUNC_skb_store_bytes: - return &bpf_skb_store_bytes_proto; - case BPF_FUNC_skb_load_bytes: - return &bpf_skb_load_bytes_proto; - case BPF_FUNC_skb_pull_data: - return &bpf_skb_pull_data_proto; - case BPF_FUNC_csum_diff: - return &bpf_csum_diff_proto; - case BPF_FUNC_csum_update: - return &bpf_csum_update_proto; - case BPF_FUNC_l3_csum_replace: - return &bpf_l3_csum_replace_proto; - case BPF_FUNC_l4_csum_replace: - return &bpf_l4_csum_replace_proto; - case BPF_FUNC_clone_redirect: - return &bpf_clone_redirect_proto; - case BPF_FUNC_get_cgroup_classid: - return &bpf_get_cgroup_classid_proto; - case BPF_FUNC_skb_vlan_push: - return &bpf_skb_vlan_push_proto; - case BPF_FUNC_skb_vlan_pop: - return &bpf_skb_vlan_pop_proto; - case BPF_FUNC_skb_change_proto: - return &bpf_skb_change_proto_proto; - case BPF_FUNC_skb_change_type: - return &bpf_skb_change_type_proto; - case BPF_FUNC_skb_change_tail: - return &bpf_skb_change_tail_proto; - case BPF_FUNC_skb_get_tunnel_key: - return &bpf_skb_get_tunnel_key_proto; - case BPF_FUNC_skb_set_tunnel_key: - return bpf_get_skb_set_tunnel_proto(func_id); - case BPF_FUNC_skb_get_tunnel_opt: - return &bpf_skb_get_tunnel_opt_proto; - case BPF_FUNC_skb_set_tunnel_opt: - return bpf_get_skb_set_tunnel_proto(func_id); - case BPF_FUNC_redirect: - return &bpf_redirect_proto; - case BPF_FUNC_get_route_realm: - return &bpf_get_route_realm_proto; - case BPF_FUNC_get_hash_recalc: - return &bpf_get_hash_recalc_proto; - case BPF_FUNC_set_hash_invalid: - return &bpf_set_hash_invalid_proto; - case BPF_FUNC_perf_event_output: - return &bpf_skb_event_output_proto; - case BPF_FUNC_get_smp_processor_id: - return &bpf_get_smp_processor_id_proto; - case BPF_FUNC_skb_under_cgroup: - return &bpf_skb_under_cgroup_proto; - default: - return sk_filter_func_proto(func_id); - } -} - -static const struct bpf_func_proto * -xdp_func_proto(enum bpf_func_id func_id) -{ - switch (func_id) { - case BPF_FUNC_perf_event_output: - return &bpf_xdp_event_output_proto; - case BPF_FUNC_get_smp_processor_id: - return &bpf_get_smp_processor_id_proto; - default: - return sk_filter_func_proto(func_id); - } -} - -static bool __is_valid_access(int off, int size, enum bpf_access_type type) -{ - if (off < 0 || off >= sizeof(struct __sk_buff)) - return false; - /* The verifier guarantees that size > 0. */ - if (off % size != 0) - return false; - if (size != sizeof(__u32)) - return false; - - return true; -} - -static bool sk_filter_is_valid_access(int off, int size, - enum bpf_access_type type, - enum bpf_reg_type *reg_type) -{ - switch (off) { - case offsetof(struct __sk_buff, tc_classid): - case offsetof(struct __sk_buff, data): - case offsetof(struct __sk_buff, data_end): - return false; - } - - if (type == BPF_WRITE) { - switch (off) { - case offsetof(struct __sk_buff, cb[0]) ... - offsetof(struct __sk_buff, cb[4]): - break; - default: - return false; - } - } - - return __is_valid_access(off, size, type); -} - -static int tc_cls_act_prologue(struct bpf_insn *insn_buf, bool direct_write, - const struct bpf_prog *prog) -{ - struct bpf_insn *insn = insn_buf; - - if (!direct_write) - return 0; - - /* if (!skb->cloned) - * goto start; - * - * (Fast-path, otherwise approximation that we might be - * a clone, do the rest in helper.) - */ - *insn++ = BPF_LDX_MEM(BPF_B, BPF_REG_6, BPF_REG_1, CLONED_OFFSET()); - *insn++ = BPF_ALU32_IMM(BPF_AND, BPF_REG_6, CLONED_MASK); - *insn++ = BPF_JMP_IMM(BPF_JEQ, BPF_REG_6, 0, 7); - - /* ret = bpf_skb_pull_data(skb, 0); */ - *insn++ = BPF_MOV64_REG(BPF_REG_6, BPF_REG_1); - *insn++ = BPF_ALU64_REG(BPF_XOR, BPF_REG_2, BPF_REG_2); - *insn++ = BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, - BPF_FUNC_skb_pull_data); - /* if (!ret) - * goto restore; - * return TC_ACT_SHOT; - */ - *insn++ = BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2); - *insn++ = BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, TC_ACT_SHOT); - *insn++ = BPF_EXIT_INSN(); - - /* restore: */ - *insn++ = BPF_MOV64_REG(BPF_REG_1, BPF_REG_6); - /* start: */ - *insn++ = prog->insnsi[0]; - - return insn - insn_buf; -} - -static bool tc_cls_act_is_valid_access(int off, int size, - enum bpf_access_type type, - enum bpf_reg_type *reg_type) -{ - if (type == BPF_WRITE) { - switch (off) { - case offsetof(struct __sk_buff, mark): - case offsetof(struct __sk_buff, tc_index): - case offsetof(struct __sk_buff, priority): - case offsetof(struct __sk_buff, cb[0]) ... - offsetof(struct __sk_buff, cb[4]): - case offsetof(struct __sk_buff, tc_classid): - break; - default: - return false; - } - } - - switch (off) { - case offsetof(struct __sk_buff, data): - *reg_type = PTR_TO_PACKET; - break; - case offsetof(struct __sk_buff, data_end): - *reg_type = PTR_TO_PACKET_END; - break; - } - - return __is_valid_access(off, size, type); -} - -static bool __is_valid_xdp_access(int off, int size, - enum bpf_access_type type) -{ - if (off < 0 || off >= sizeof(struct xdp_md)) - return false; - if (off % size != 0) - return false; - if (size != sizeof(__u32)) - return false; - - return true; -} - -static bool xdp_is_valid_access(int off, int size, - enum bpf_access_type type, - enum bpf_reg_type *reg_type) -{ - if (type == BPF_WRITE) - return false; - - switch (off) { - case offsetof(struct xdp_md, data): - *reg_type = PTR_TO_PACKET; - break; - case offsetof(struct xdp_md, data_end): - *reg_type = PTR_TO_PACKET_END; - break; - } - - return __is_valid_xdp_access(off, size, type); -} - -void bpf_warn_invalid_xdp_action(u32 act) -{ - WARN_ONCE(1, "Illegal XDP return value %u, expect packet loss\n", act); -} -EXPORT_SYMBOL_GPL(bpf_warn_invalid_xdp_action); - -static u32 sk_filter_convert_ctx_access(enum bpf_access_type type, int dst_reg, - int src_reg, int ctx_off, - struct bpf_insn *insn_buf, - struct bpf_prog *prog) -{ - struct bpf_insn *insn = insn_buf; - - switch (ctx_off) { - case offsetof(struct __sk_buff, len): - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4); - - *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, src_reg, - offsetof(struct sk_buff, len)); - break; - - case offsetof(struct __sk_buff, protocol): - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, protocol) != 2); - - *insn++ = BPF_LDX_MEM(BPF_H, dst_reg, src_reg, - offsetof(struct sk_buff, protocol)); - break; - - case offsetof(struct __sk_buff, vlan_proto): - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, vlan_proto) != 2); - - *insn++ = BPF_LDX_MEM(BPF_H, dst_reg, src_reg, - offsetof(struct sk_buff, vlan_proto)); - break; - - case offsetof(struct __sk_buff, priority): - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, priority) != 4); - - if (type == BPF_WRITE) - *insn++ = BPF_STX_MEM(BPF_W, dst_reg, src_reg, - offsetof(struct sk_buff, priority)); - else - *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, src_reg, - offsetof(struct sk_buff, priority)); - break; - - case offsetof(struct __sk_buff, ingress_ifindex): - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, skb_iif) != 4); - - *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, src_reg, - offsetof(struct sk_buff, skb_iif)); - break; - - case offsetof(struct __sk_buff, ifindex): - BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4); - - *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, dev), - dst_reg, src_reg, - offsetof(struct sk_buff, dev)); - *insn++ = BPF_JMP_IMM(BPF_JEQ, dst_reg, 0, 1); - *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, dst_reg, - offsetof(struct net_device, ifindex)); - break; - - case offsetof(struct __sk_buff, hash): - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, hash) != 4); - - *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, src_reg, - offsetof(struct sk_buff, hash)); - break; - - case offsetof(struct __sk_buff, mark): - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4); - - if (type == BPF_WRITE) - *insn++ = BPF_STX_MEM(BPF_W, dst_reg, src_reg, - offsetof(struct sk_buff, mark)); - else - *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, src_reg, - offsetof(struct sk_buff, mark)); - break; - - case offsetof(struct __sk_buff, pkt_type): - return convert_skb_access(SKF_AD_PKTTYPE, dst_reg, src_reg, insn); - - case offsetof(struct __sk_buff, queue_mapping): - return convert_skb_access(SKF_AD_QUEUE, dst_reg, src_reg, insn); - - case offsetof(struct __sk_buff, vlan_present): - return convert_skb_access(SKF_AD_VLAN_TAG_PRESENT, - dst_reg, src_reg, insn); - - case offsetof(struct __sk_buff, vlan_tci): - return convert_skb_access(SKF_AD_VLAN_TAG, - dst_reg, src_reg, insn); - - case offsetof(struct __sk_buff, cb[0]) ... - offsetof(struct __sk_buff, cb[4]): - BUILD_BUG_ON(FIELD_SIZEOF(struct qdisc_skb_cb, data) < 20); - - prog->cb_access = 1; - ctx_off -= offsetof(struct __sk_buff, cb[0]); - ctx_off += offsetof(struct sk_buff, cb); - ctx_off += offsetof(struct qdisc_skb_cb, data); - if (type == BPF_WRITE) - *insn++ = BPF_STX_MEM(BPF_W, dst_reg, src_reg, ctx_off); - else - *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, src_reg, ctx_off); - break; - - case offsetof(struct __sk_buff, tc_classid): - ctx_off -= offsetof(struct __sk_buff, tc_classid); - ctx_off += offsetof(struct sk_buff, cb); - ctx_off += offsetof(struct qdisc_skb_cb, tc_classid); - if (type == BPF_WRITE) - *insn++ = BPF_STX_MEM(BPF_H, dst_reg, src_reg, ctx_off); - else - *insn++ = BPF_LDX_MEM(BPF_H, dst_reg, src_reg, ctx_off); - break; - - case offsetof(struct __sk_buff, data): - *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, data), - dst_reg, src_reg, - offsetof(struct sk_buff, data)); - break; - - case offsetof(struct __sk_buff, data_end): - ctx_off -= offsetof(struct __sk_buff, data_end); - ctx_off += offsetof(struct sk_buff, cb); - ctx_off += offsetof(struct bpf_skb_data_end, data_end); - *insn++ = BPF_LDX_MEM(BPF_SIZEOF(void *), dst_reg, src_reg, - ctx_off); - break; - - case offsetof(struct __sk_buff, tc_index): -#ifdef CONFIG_NET_SCHED - BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, tc_index) != 2); - - if (type == BPF_WRITE) - *insn++ = BPF_STX_MEM(BPF_H, dst_reg, src_reg, - offsetof(struct sk_buff, tc_index)); - else - *insn++ = BPF_LDX_MEM(BPF_H, dst_reg, src_reg, - offsetof(struct sk_buff, tc_index)); - break; -#else - if (type == BPF_WRITE) - *insn++ = BPF_MOV64_REG(dst_reg, dst_reg); - else - *insn++ = BPF_MOV64_IMM(dst_reg, 0); - break; -#endif - } - - return insn - insn_buf; -} - -static u32 tc_cls_act_convert_ctx_access(enum bpf_access_type type, int dst_reg, - int src_reg, int ctx_off, - struct bpf_insn *insn_buf, - struct bpf_prog *prog) -{ - struct bpf_insn *insn = insn_buf; - - switch (ctx_off) { - case offsetof(struct __sk_buff, ifindex): - BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, ifindex) != 4); - - *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct sk_buff, dev), - dst_reg, src_reg, - offsetof(struct sk_buff, dev)); - *insn++ = BPF_LDX_MEM(BPF_W, dst_reg, dst_reg, - offsetof(struct net_device, ifindex)); - break; - default: - return sk_filter_convert_ctx_access(type, dst_reg, src_reg, - ctx_off, insn_buf, prog); - } - - return insn - insn_buf; -} - -static u32 xdp_convert_ctx_access(enum bpf_access_type type, int dst_reg, - int src_reg, int ctx_off, - struct bpf_insn *insn_buf, - struct bpf_prog *prog) -{ - struct bpf_insn *insn = insn_buf; - - switch (ctx_off) { - case offsetof(struct xdp_md, data): - *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct xdp_buff, data), - dst_reg, src_reg, - offsetof(struct xdp_buff, data)); - break; - case offsetof(struct xdp_md, data_end): - *insn++ = BPF_LDX_MEM(BPF_FIELD_SIZEOF(struct xdp_buff, data_end), - dst_reg, src_reg, - offsetof(struct xdp_buff, data_end)); - break; - } - - return insn - insn_buf; -} - -static const struct bpf_verifier_ops sk_filter_ops = { - .get_func_proto = sk_filter_func_proto, - .is_valid_access = sk_filter_is_valid_access, - .convert_ctx_access = sk_filter_convert_ctx_access, -}; - -static const struct bpf_verifier_ops tc_cls_act_ops = { - .get_func_proto = tc_cls_act_func_proto, - .is_valid_access = tc_cls_act_is_valid_access, - .convert_ctx_access = tc_cls_act_convert_ctx_access, - .gen_prologue = tc_cls_act_prologue, -}; - -static const struct bpf_verifier_ops xdp_ops = { - .get_func_proto = xdp_func_proto, - .is_valid_access = xdp_is_valid_access, - .convert_ctx_access = xdp_convert_ctx_access, -}; - -static struct bpf_prog_type_list sk_filter_type __read_mostly = { - .ops = &sk_filter_ops, - .type = BPF_PROG_TYPE_SOCKET_FILTER, -}; - -static struct bpf_prog_type_list sched_cls_type __read_mostly = { - .ops = &tc_cls_act_ops, - .type = BPF_PROG_TYPE_SCHED_CLS, -}; - -static struct bpf_prog_type_list sched_act_type __read_mostly = { - .ops = &tc_cls_act_ops, - .type = BPF_PROG_TYPE_SCHED_ACT, -}; - -static struct bpf_prog_type_list xdp_type __read_mostly = { - .ops = &xdp_ops, - .type = BPF_PROG_TYPE_XDP, -}; - -static int __init register_sk_filter_ops(void) -{ - bpf_register_prog_type(&sk_filter_type); - bpf_register_prog_type(&sched_cls_type); - bpf_register_prog_type(&sched_act_type); - bpf_register_prog_type(&xdp_type); - - return 0; -} -late_initcall(register_sk_filter_ops); - -int sk_detach_filter(struct sock *sk) -{ - int ret = -ENOENT; - struct sk_filter *filter; - - if (sock_flag(sk, SOCK_FILTER_LOCKED)) - return -EPERM; - - filter = rcu_dereference_protected(sk->sk_filter, - lockdep_sock_is_held(sk)); - if (filter) { - RCU_INIT_POINTER(sk->sk_filter, NULL); - sk_filter_uncharge(sk, filter); - ret = 0; - } - - return ret; -} -EXPORT_SYMBOL_GPL(sk_detach_filter); - -int sk_get_filter(struct sock *sk, struct sock_filter __user *ubuf, - unsigned int len) -{ - struct sock_fprog_kern *fprog; - struct sk_filter *filter; - int ret = 0; - - lock_sock(sk); - filter = rcu_dereference_protected(sk->sk_filter, - lockdep_sock_is_held(sk)); - if (!filter) - goto out; - - /* We're copying the filter that has been originally attached, - * so no conversion/decode needed anymore. eBPF programs that - * have no original program cannot be dumped through this. - */ - ret = -EACCES; - fprog = filter->prog->orig_prog; - if (!fprog) - goto out; - - ret = fprog->len; - if (!len) - /* User space only enquires number of filter blocks. */ - goto out; - - ret = -EINVAL; - if (len < fprog->len) - goto out; - - ret = -EFAULT; - if (copy_to_user(ubuf, fprog->filter, bpf_classic_proglen(fprog))) - goto out; - - /* Instead of bytes, the API requests to return the number - * of filter blocks. - */ - ret = fprog->len; -out: - release_sock(sk); - return ret; -} diff --git a/src/linux/net/core/flow.c b/src/linux/net/core/flow.c deleted file mode 100644 index 18e8893..0000000 --- a/src/linux/net/core/flow.c +++ /dev/null @@ -1,521 +0,0 @@ -/* flow.c: Generic flow cache. - * - * Copyright (C) 2003 Alexey N. Kuznetsov (kuznet@ms2.inr.ac.ru) - * Copyright (C) 2003 David S. Miller (davem@redhat.com) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct flow_cache_entry { - union { - struct hlist_node hlist; - struct list_head gc_list; - } u; - struct net *net; - u16 family; - u8 dir; - u32 genid; - struct flowi key; - struct flow_cache_object *object; -}; - -struct flow_flush_info { - struct flow_cache *cache; - atomic_t cpuleft; - struct completion completion; -}; - -static struct kmem_cache *flow_cachep __read_mostly; - -#define flow_cache_hash_size(cache) (1 << (cache)->hash_shift) -#define FLOW_HASH_RND_PERIOD (10 * 60 * HZ) - -static void flow_cache_new_hashrnd(unsigned long arg) -{ - struct flow_cache *fc = (void *) arg; - int i; - - for_each_possible_cpu(i) - per_cpu_ptr(fc->percpu, i)->hash_rnd_recalc = 1; - - fc->rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD; - add_timer(&fc->rnd_timer); -} - -static int flow_entry_valid(struct flow_cache_entry *fle, - struct netns_xfrm *xfrm) -{ - if (atomic_read(&xfrm->flow_cache_genid) != fle->genid) - return 0; - if (fle->object && !fle->object->ops->check(fle->object)) - return 0; - return 1; -} - -static void flow_entry_kill(struct flow_cache_entry *fle, - struct netns_xfrm *xfrm) -{ - if (fle->object) - fle->object->ops->delete(fle->object); - kmem_cache_free(flow_cachep, fle); -} - -static void flow_cache_gc_task(struct work_struct *work) -{ - struct list_head gc_list; - struct flow_cache_entry *fce, *n; - struct netns_xfrm *xfrm = container_of(work, struct netns_xfrm, - flow_cache_gc_work); - - INIT_LIST_HEAD(&gc_list); - spin_lock_bh(&xfrm->flow_cache_gc_lock); - list_splice_tail_init(&xfrm->flow_cache_gc_list, &gc_list); - spin_unlock_bh(&xfrm->flow_cache_gc_lock); - - list_for_each_entry_safe(fce, n, &gc_list, u.gc_list) { - flow_entry_kill(fce, xfrm); - atomic_dec(&xfrm->flow_cache_gc_count); - } -} - -static void flow_cache_queue_garbage(struct flow_cache_percpu *fcp, - int deleted, struct list_head *gc_list, - struct netns_xfrm *xfrm) -{ - if (deleted) { - atomic_add(deleted, &xfrm->flow_cache_gc_count); - fcp->hash_count -= deleted; - spin_lock_bh(&xfrm->flow_cache_gc_lock); - list_splice_tail(gc_list, &xfrm->flow_cache_gc_list); - spin_unlock_bh(&xfrm->flow_cache_gc_lock); - schedule_work(&xfrm->flow_cache_gc_work); - } -} - -static void __flow_cache_shrink(struct flow_cache *fc, - struct flow_cache_percpu *fcp, - int shrink_to) -{ - struct flow_cache_entry *fle; - struct hlist_node *tmp; - LIST_HEAD(gc_list); - int i, deleted = 0; - struct netns_xfrm *xfrm = container_of(fc, struct netns_xfrm, - flow_cache_global); - - for (i = 0; i < flow_cache_hash_size(fc); i++) { - int saved = 0; - - hlist_for_each_entry_safe(fle, tmp, - &fcp->hash_table[i], u.hlist) { - if (saved < shrink_to && - flow_entry_valid(fle, xfrm)) { - saved++; - } else { - deleted++; - hlist_del(&fle->u.hlist); - list_add_tail(&fle->u.gc_list, &gc_list); - } - } - } - - flow_cache_queue_garbage(fcp, deleted, &gc_list, xfrm); -} - -static void flow_cache_shrink(struct flow_cache *fc, - struct flow_cache_percpu *fcp) -{ - int shrink_to = fc->low_watermark / flow_cache_hash_size(fc); - - __flow_cache_shrink(fc, fcp, shrink_to); -} - -static void flow_new_hash_rnd(struct flow_cache *fc, - struct flow_cache_percpu *fcp) -{ - get_random_bytes(&fcp->hash_rnd, sizeof(u32)); - fcp->hash_rnd_recalc = 0; - __flow_cache_shrink(fc, fcp, 0); -} - -static u32 flow_hash_code(struct flow_cache *fc, - struct flow_cache_percpu *fcp, - const struct flowi *key, - size_t keysize) -{ - const u32 *k = (const u32 *) key; - const u32 length = keysize * sizeof(flow_compare_t) / sizeof(u32); - - return jhash2(k, length, fcp->hash_rnd) - & (flow_cache_hash_size(fc) - 1); -} - -/* I hear what you're saying, use memcmp. But memcmp cannot make - * important assumptions that we can here, such as alignment. - */ -static int flow_key_compare(const struct flowi *key1, const struct flowi *key2, - size_t keysize) -{ - const flow_compare_t *k1, *k1_lim, *k2; - - k1 = (const flow_compare_t *) key1; - k1_lim = k1 + keysize; - - k2 = (const flow_compare_t *) key2; - - do { - if (*k1++ != *k2++) - return 1; - } while (k1 < k1_lim); - - return 0; -} - -struct flow_cache_object * -flow_cache_lookup(struct net *net, const struct flowi *key, u16 family, u8 dir, - flow_resolve_t resolver, void *ctx) -{ - struct flow_cache *fc = &net->xfrm.flow_cache_global; - struct flow_cache_percpu *fcp; - struct flow_cache_entry *fle, *tfle; - struct flow_cache_object *flo; - size_t keysize; - unsigned int hash; - - local_bh_disable(); - fcp = this_cpu_ptr(fc->percpu); - - fle = NULL; - flo = NULL; - - keysize = flow_key_size(family); - if (!keysize) - goto nocache; - - /* Packet really early in init? Making flow_cache_init a - * pre-smp initcall would solve this. --RR */ - if (!fcp->hash_table) - goto nocache; - - if (fcp->hash_rnd_recalc) - flow_new_hash_rnd(fc, fcp); - - hash = flow_hash_code(fc, fcp, key, keysize); - hlist_for_each_entry(tfle, &fcp->hash_table[hash], u.hlist) { - if (tfle->net == net && - tfle->family == family && - tfle->dir == dir && - flow_key_compare(key, &tfle->key, keysize) == 0) { - fle = tfle; - break; - } - } - - if (unlikely(!fle)) { - if (fcp->hash_count > fc->high_watermark) - flow_cache_shrink(fc, fcp); - - if (atomic_read(&net->xfrm.flow_cache_gc_count) > - 2 * num_online_cpus() * fc->high_watermark) { - flo = ERR_PTR(-ENOBUFS); - goto ret_object; - } - - fle = kmem_cache_alloc(flow_cachep, GFP_ATOMIC); - if (fle) { - fle->net = net; - fle->family = family; - fle->dir = dir; - memcpy(&fle->key, key, keysize * sizeof(flow_compare_t)); - fle->object = NULL; - hlist_add_head(&fle->u.hlist, &fcp->hash_table[hash]); - fcp->hash_count++; - } - } else if (likely(fle->genid == atomic_read(&net->xfrm.flow_cache_genid))) { - flo = fle->object; - if (!flo) - goto ret_object; - flo = flo->ops->get(flo); - if (flo) - goto ret_object; - } else if (fle->object) { - flo = fle->object; - flo->ops->delete(flo); - fle->object = NULL; - } - -nocache: - flo = NULL; - if (fle) { - flo = fle->object; - fle->object = NULL; - } - flo = resolver(net, key, family, dir, flo, ctx); - if (fle) { - fle->genid = atomic_read(&net->xfrm.flow_cache_genid); - if (!IS_ERR(flo)) - fle->object = flo; - else - fle->genid--; - } else { - if (!IS_ERR_OR_NULL(flo)) - flo->ops->delete(flo); - } -ret_object: - local_bh_enable(); - return flo; -} -EXPORT_SYMBOL(flow_cache_lookup); - -static void flow_cache_flush_tasklet(unsigned long data) -{ - struct flow_flush_info *info = (void *)data; - struct flow_cache *fc = info->cache; - struct flow_cache_percpu *fcp; - struct flow_cache_entry *fle; - struct hlist_node *tmp; - LIST_HEAD(gc_list); - int i, deleted = 0; - struct netns_xfrm *xfrm = container_of(fc, struct netns_xfrm, - flow_cache_global); - - fcp = this_cpu_ptr(fc->percpu); - for (i = 0; i < flow_cache_hash_size(fc); i++) { - hlist_for_each_entry_safe(fle, tmp, - &fcp->hash_table[i], u.hlist) { - if (flow_entry_valid(fle, xfrm)) - continue; - - deleted++; - hlist_del(&fle->u.hlist); - list_add_tail(&fle->u.gc_list, &gc_list); - } - } - - flow_cache_queue_garbage(fcp, deleted, &gc_list, xfrm); - - if (atomic_dec_and_test(&info->cpuleft)) - complete(&info->completion); -} - -/* - * Return whether a cpu needs flushing. Conservatively, we assume - * the presence of any entries means the core may require flushing, - * since the flow_cache_ops.check() function may assume it's running - * on the same core as the per-cpu cache component. - */ -static int flow_cache_percpu_empty(struct flow_cache *fc, int cpu) -{ - struct flow_cache_percpu *fcp; - int i; - - fcp = per_cpu_ptr(fc->percpu, cpu); - for (i = 0; i < flow_cache_hash_size(fc); i++) - if (!hlist_empty(&fcp->hash_table[i])) - return 0; - return 1; -} - -static void flow_cache_flush_per_cpu(void *data) -{ - struct flow_flush_info *info = data; - struct tasklet_struct *tasklet; - - tasklet = &this_cpu_ptr(info->cache->percpu)->flush_tasklet; - tasklet->data = (unsigned long)info; - tasklet_schedule(tasklet); -} - -void flow_cache_flush(struct net *net) -{ - struct flow_flush_info info; - cpumask_var_t mask; - int i, self; - - /* Track which cpus need flushing to avoid disturbing all cores. */ - if (!alloc_cpumask_var(&mask, GFP_KERNEL)) - return; - cpumask_clear(mask); - - /* Don't want cpus going down or up during this. */ - get_online_cpus(); - mutex_lock(&net->xfrm.flow_flush_sem); - info.cache = &net->xfrm.flow_cache_global; - for_each_online_cpu(i) - if (!flow_cache_percpu_empty(info.cache, i)) - cpumask_set_cpu(i, mask); - atomic_set(&info.cpuleft, cpumask_weight(mask)); - if (atomic_read(&info.cpuleft) == 0) - goto done; - - init_completion(&info.completion); - - local_bh_disable(); - self = cpumask_test_and_clear_cpu(smp_processor_id(), mask); - on_each_cpu_mask(mask, flow_cache_flush_per_cpu, &info, 0); - if (self) - flow_cache_flush_tasklet((unsigned long)&info); - local_bh_enable(); - - wait_for_completion(&info.completion); - -done: - mutex_unlock(&net->xfrm.flow_flush_sem); - put_online_cpus(); - free_cpumask_var(mask); -} - -static void flow_cache_flush_task(struct work_struct *work) -{ - struct netns_xfrm *xfrm = container_of(work, struct netns_xfrm, - flow_cache_flush_work); - struct net *net = container_of(xfrm, struct net, xfrm); - - flow_cache_flush(net); -} - -void flow_cache_flush_deferred(struct net *net) -{ - schedule_work(&net->xfrm.flow_cache_flush_work); -} - -static int flow_cache_cpu_prepare(struct flow_cache *fc, int cpu) -{ - struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, cpu); - size_t sz = sizeof(struct hlist_head) * flow_cache_hash_size(fc); - - if (!fcp->hash_table) { - fcp->hash_table = kzalloc_node(sz, GFP_KERNEL, cpu_to_node(cpu)); - if (!fcp->hash_table) { - pr_err("NET: failed to allocate flow cache sz %zu\n", sz); - return -ENOMEM; - } - fcp->hash_rnd_recalc = 1; - fcp->hash_count = 0; - tasklet_init(&fcp->flush_tasklet, flow_cache_flush_tasklet, 0); - } - return 0; -} - -static int flow_cache_cpu(struct notifier_block *nfb, - unsigned long action, - void *hcpu) -{ - struct flow_cache *fc = container_of(nfb, struct flow_cache, - hotcpu_notifier); - int res, cpu = (unsigned long) hcpu; - struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, cpu); - - switch (action) { - case CPU_UP_PREPARE: - case CPU_UP_PREPARE_FROZEN: - res = flow_cache_cpu_prepare(fc, cpu); - if (res) - return notifier_from_errno(res); - break; - case CPU_DEAD: - case CPU_DEAD_FROZEN: - __flow_cache_shrink(fc, fcp, 0); - break; - } - return NOTIFY_OK; -} - -int flow_cache_init(struct net *net) -{ - int i; - struct flow_cache *fc = &net->xfrm.flow_cache_global; - - if (!flow_cachep) - flow_cachep = kmem_cache_create("flow_cache", - sizeof(struct flow_cache_entry), - 0, SLAB_PANIC, NULL); - spin_lock_init(&net->xfrm.flow_cache_gc_lock); - INIT_LIST_HEAD(&net->xfrm.flow_cache_gc_list); - INIT_WORK(&net->xfrm.flow_cache_gc_work, flow_cache_gc_task); - INIT_WORK(&net->xfrm.flow_cache_flush_work, flow_cache_flush_task); - mutex_init(&net->xfrm.flow_flush_sem); - atomic_set(&net->xfrm.flow_cache_gc_count, 0); - - fc->hash_shift = 10; - fc->low_watermark = 2 * flow_cache_hash_size(fc); - fc->high_watermark = 4 * flow_cache_hash_size(fc); - - fc->percpu = alloc_percpu(struct flow_cache_percpu); - if (!fc->percpu) - return -ENOMEM; - - cpu_notifier_register_begin(); - - for_each_online_cpu(i) { - if (flow_cache_cpu_prepare(fc, i)) - goto err; - } - fc->hotcpu_notifier = (struct notifier_block){ - .notifier_call = flow_cache_cpu, - }; - __register_hotcpu_notifier(&fc->hotcpu_notifier); - - cpu_notifier_register_done(); - - setup_timer(&fc->rnd_timer, flow_cache_new_hashrnd, - (unsigned long) fc); - fc->rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD; - add_timer(&fc->rnd_timer); - - return 0; - -err: - for_each_possible_cpu(i) { - struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, i); - kfree(fcp->hash_table); - fcp->hash_table = NULL; - } - - cpu_notifier_register_done(); - - free_percpu(fc->percpu); - fc->percpu = NULL; - - return -ENOMEM; -} -EXPORT_SYMBOL(flow_cache_init); - -void flow_cache_fini(struct net *net) -{ - int i; - struct flow_cache *fc = &net->xfrm.flow_cache_global; - - del_timer_sync(&fc->rnd_timer); - unregister_hotcpu_notifier(&fc->hotcpu_notifier); - - for_each_possible_cpu(i) { - struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, i); - kfree(fcp->hash_table); - fcp->hash_table = NULL; - } - - free_percpu(fc->percpu); - fc->percpu = NULL; -} -EXPORT_SYMBOL(flow_cache_fini); diff --git a/src/linux/net/core/flow_dissector.c b/src/linux/net/core/flow_dissector.c deleted file mode 100644 index c6d8207..0000000 --- a/src/linux/net/core/flow_dissector.c +++ /dev/null @@ -1,1016 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void dissector_set_key(struct flow_dissector *flow_dissector, - enum flow_dissector_key_id key_id) -{ - flow_dissector->used_keys |= (1 << key_id); -} - -void skb_flow_dissector_init(struct flow_dissector *flow_dissector, - const struct flow_dissector_key *key, - unsigned int key_count) -{ - unsigned int i; - - memset(flow_dissector, 0, sizeof(*flow_dissector)); - - for (i = 0; i < key_count; i++, key++) { - /* User should make sure that every key target offset is withing - * boundaries of unsigned short. - */ - BUG_ON(key->offset > USHRT_MAX); - BUG_ON(dissector_uses_key(flow_dissector, - key->key_id)); - - dissector_set_key(flow_dissector, key->key_id); - flow_dissector->offset[key->key_id] = key->offset; - } - - /* Ensure that the dissector always includes control and basic key. - * That way we are able to avoid handling lack of these in fast path. - */ - BUG_ON(!dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_CONTROL)); - BUG_ON(!dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_BASIC)); -} -EXPORT_SYMBOL(skb_flow_dissector_init); - -/** - * __skb_flow_get_ports - extract the upper layer ports and return them - * @skb: sk_buff to extract the ports from - * @thoff: transport header offset - * @ip_proto: protocol for which to get port offset - * @data: raw buffer pointer to the packet, if NULL use skb->data - * @hlen: packet header length, if @data is NULL use skb_headlen(skb) - * - * The function will try to retrieve the ports at offset thoff + poff where poff - * is the protocol port offset returned from proto_ports_offset - */ -__be32 __skb_flow_get_ports(const struct sk_buff *skb, int thoff, u8 ip_proto, - void *data, int hlen) -{ - int poff = proto_ports_offset(ip_proto); - - if (!data) { - data = skb->data; - hlen = skb_headlen(skb); - } - - if (poff >= 0) { - __be32 *ports, _ports; - - ports = __skb_header_pointer(skb, thoff + poff, - sizeof(_ports), data, hlen, &_ports); - if (ports) - return *ports; - } - - return 0; -} -EXPORT_SYMBOL(__skb_flow_get_ports); - -/** - * __skb_flow_dissect - extract the flow_keys struct and return it - * @skb: sk_buff to extract the flow from, can be NULL if the rest are specified - * @flow_dissector: list of keys to dissect - * @target_container: target structure to put dissected values into - * @data: raw buffer pointer to the packet, if NULL use skb->data - * @proto: protocol for which to get the flow, if @data is NULL use skb->protocol - * @nhoff: network header offset, if @data is NULL use skb_network_offset(skb) - * @hlen: packet header length, if @data is NULL use skb_headlen(skb) - * - * The function will try to retrieve individual keys into target specified - * by flow_dissector from either the skbuff or a raw buffer specified by the - * rest parameters. - * - * Caller must take care of zeroing target container memory. - */ -bool __skb_flow_dissect(const struct sk_buff *skb, - struct flow_dissector *flow_dissector, - void *target_container, - void *data, __be16 proto, int nhoff, int hlen, - unsigned int flags) -{ - struct flow_dissector_key_control *key_control; - struct flow_dissector_key_basic *key_basic; - struct flow_dissector_key_addrs *key_addrs; - struct flow_dissector_key_ports *key_ports; - struct flow_dissector_key_tags *key_tags; - struct flow_dissector_key_vlan *key_vlan; - struct flow_dissector_key_keyid *key_keyid; - bool skip_vlan = false; - u8 ip_proto = 0; - bool ret; - - if (!data) { - data = skb->data; - proto = skb_vlan_tag_present(skb) ? - skb->vlan_proto : skb->protocol; - nhoff = skb_network_offset(skb); - hlen = skb_headlen(skb); - } - - /* It is ensured by skb_flow_dissector_init() that control key will - * be always present. - */ - key_control = skb_flow_dissector_target(flow_dissector, - FLOW_DISSECTOR_KEY_CONTROL, - target_container); - - /* It is ensured by skb_flow_dissector_init() that basic key will - * be always present. - */ - key_basic = skb_flow_dissector_target(flow_dissector, - FLOW_DISSECTOR_KEY_BASIC, - target_container); - - if (dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_ETH_ADDRS)) { - struct ethhdr *eth = eth_hdr(skb); - struct flow_dissector_key_eth_addrs *key_eth_addrs; - - key_eth_addrs = skb_flow_dissector_target(flow_dissector, - FLOW_DISSECTOR_KEY_ETH_ADDRS, - target_container); - memcpy(key_eth_addrs, ð->h_dest, sizeof(*key_eth_addrs)); - } - -again: - switch (proto) { - case htons(ETH_P_IP): { - const struct iphdr *iph; - struct iphdr _iph; -ip: - iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph); - if (!iph || iph->ihl < 5) - goto out_bad; - nhoff += iph->ihl * 4; - - ip_proto = iph->protocol; - - if (dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_IPV4_ADDRS)) { - key_addrs = skb_flow_dissector_target(flow_dissector, - FLOW_DISSECTOR_KEY_IPV4_ADDRS, - target_container); - - memcpy(&key_addrs->v4addrs, &iph->saddr, - sizeof(key_addrs->v4addrs)); - key_control->addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; - } - - if (ip_is_fragment(iph)) { - key_control->flags |= FLOW_DIS_IS_FRAGMENT; - - if (iph->frag_off & htons(IP_OFFSET)) { - goto out_good; - } else { - key_control->flags |= FLOW_DIS_FIRST_FRAG; - if (!(flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG)) - goto out_good; - } - } - - if (flags & FLOW_DISSECTOR_F_STOP_AT_L3) - goto out_good; - - break; - } - case htons(ETH_P_IPV6): { - const struct ipv6hdr *iph; - struct ipv6hdr _iph; - -ipv6: - iph = __skb_header_pointer(skb, nhoff, sizeof(_iph), data, hlen, &_iph); - if (!iph) - goto out_bad; - - ip_proto = iph->nexthdr; - nhoff += sizeof(struct ipv6hdr); - - if (dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_IPV6_ADDRS)) { - key_addrs = skb_flow_dissector_target(flow_dissector, - FLOW_DISSECTOR_KEY_IPV6_ADDRS, - target_container); - - memcpy(&key_addrs->v6addrs, &iph->saddr, - sizeof(key_addrs->v6addrs)); - key_control->addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; - } - - if ((dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_FLOW_LABEL) || - (flags & FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL)) && - ip6_flowlabel(iph)) { - __be32 flow_label = ip6_flowlabel(iph); - - if (dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_FLOW_LABEL)) { - key_tags = skb_flow_dissector_target(flow_dissector, - FLOW_DISSECTOR_KEY_FLOW_LABEL, - target_container); - key_tags->flow_label = ntohl(flow_label); - } - if (flags & FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL) - goto out_good; - } - - if (flags & FLOW_DISSECTOR_F_STOP_AT_L3) - goto out_good; - - break; - } - case htons(ETH_P_8021AD): - case htons(ETH_P_8021Q): { - const struct vlan_hdr *vlan; - struct vlan_hdr _vlan; - bool vlan_tag_present = skb && skb_vlan_tag_present(skb); - - if (vlan_tag_present) - proto = skb->protocol; - - if (!vlan_tag_present || eth_type_vlan(skb->protocol)) { - vlan = __skb_header_pointer(skb, nhoff, sizeof(_vlan), - data, hlen, &_vlan); - if (!vlan) - goto out_bad; - proto = vlan->h_vlan_encapsulated_proto; - nhoff += sizeof(*vlan); - if (skip_vlan) - goto again; - } - - skip_vlan = true; - if (dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_VLAN)) { - key_vlan = skb_flow_dissector_target(flow_dissector, - FLOW_DISSECTOR_KEY_VLAN, - target_container); - - if (vlan_tag_present) { - key_vlan->vlan_id = skb_vlan_tag_get_id(skb); - key_vlan->vlan_priority = - (skb_vlan_tag_get_prio(skb) >> VLAN_PRIO_SHIFT); - } else { - key_vlan->vlan_id = ntohs(vlan->h_vlan_TCI) & - VLAN_VID_MASK; - key_vlan->vlan_priority = - (ntohs(vlan->h_vlan_TCI) & - VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT; - } - } - - goto again; - } - case htons(ETH_P_PPP_SES): { - struct { - struct pppoe_hdr hdr; - __be16 proto; - } *hdr, _hdr; - hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr); - if (!hdr) - goto out_bad; - proto = hdr->proto; - nhoff += PPPOE_SES_HLEN; - switch (proto) { - case htons(PPP_IP): - goto ip; - case htons(PPP_IPV6): - goto ipv6; - default: - goto out_bad; - } - } - case htons(ETH_P_TIPC): { - struct { - __be32 pre[3]; - __be32 srcnode; - } *hdr, _hdr; - hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr); - if (!hdr) - goto out_bad; - - if (dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_TIPC_ADDRS)) { - key_addrs = skb_flow_dissector_target(flow_dissector, - FLOW_DISSECTOR_KEY_TIPC_ADDRS, - target_container); - key_addrs->tipcaddrs.srcnode = hdr->srcnode; - key_control->addr_type = FLOW_DISSECTOR_KEY_TIPC_ADDRS; - } - goto out_good; - } - - case htons(ETH_P_MPLS_UC): - case htons(ETH_P_MPLS_MC): { - struct mpls_label *hdr, _hdr[2]; -mpls: - hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, - hlen, &_hdr); - if (!hdr) - goto out_bad; - - if ((ntohl(hdr[0].entry) & MPLS_LS_LABEL_MASK) >> - MPLS_LS_LABEL_SHIFT == MPLS_LABEL_ENTROPY) { - if (dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_MPLS_ENTROPY)) { - key_keyid = skb_flow_dissector_target(flow_dissector, - FLOW_DISSECTOR_KEY_MPLS_ENTROPY, - target_container); - key_keyid->keyid = hdr[1].entry & - htonl(MPLS_LS_LABEL_MASK); - } - - goto out_good; - } - - goto out_good; - } - - case htons(ETH_P_FCOE): - if ((hlen - nhoff) < FCOE_HEADER_LEN) - goto out_bad; - - nhoff += FCOE_HEADER_LEN; - goto out_good; - default: - goto out_bad; - } - -ip_proto_again: - switch (ip_proto) { - case IPPROTO_GRE: { - struct gre_base_hdr *hdr, _hdr; - u16 gre_ver; - int offset = 0; - - hdr = __skb_header_pointer(skb, nhoff, sizeof(_hdr), data, hlen, &_hdr); - if (!hdr) - goto out_bad; - - /* Only look inside GRE without routing */ - if (hdr->flags & GRE_ROUTING) - break; - - /* Only look inside GRE for version 0 and 1 */ - gre_ver = ntohs(hdr->flags & GRE_VERSION); - if (gre_ver > 1) - break; - - proto = hdr->protocol; - if (gre_ver) { - /* Version1 must be PPTP, and check the flags */ - if (!(proto == GRE_PROTO_PPP && (hdr->flags & GRE_KEY))) - break; - } - - offset += sizeof(struct gre_base_hdr); - - if (hdr->flags & GRE_CSUM) - offset += sizeof(((struct gre_full_hdr *)0)->csum) + - sizeof(((struct gre_full_hdr *)0)->reserved1); - - if (hdr->flags & GRE_KEY) { - const __be32 *keyid; - __be32 _keyid; - - keyid = __skb_header_pointer(skb, nhoff + offset, sizeof(_keyid), - data, hlen, &_keyid); - if (!keyid) - goto out_bad; - - if (dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_GRE_KEYID)) { - key_keyid = skb_flow_dissector_target(flow_dissector, - FLOW_DISSECTOR_KEY_GRE_KEYID, - target_container); - if (gre_ver == 0) - key_keyid->keyid = *keyid; - else - key_keyid->keyid = *keyid & GRE_PPTP_KEY_MASK; - } - offset += sizeof(((struct gre_full_hdr *)0)->key); - } - - if (hdr->flags & GRE_SEQ) - offset += sizeof(((struct pptp_gre_header *)0)->seq); - - if (gre_ver == 0) { - if (proto == htons(ETH_P_TEB)) { - const struct ethhdr *eth; - struct ethhdr _eth; - - eth = __skb_header_pointer(skb, nhoff + offset, - sizeof(_eth), - data, hlen, &_eth); - if (!eth) - goto out_bad; - proto = eth->h_proto; - offset += sizeof(*eth); - - /* Cap headers that we access via pointers at the - * end of the Ethernet header as our maximum alignment - * at that point is only 2 bytes. - */ - if (NET_IP_ALIGN) - hlen = (nhoff + offset); - } - } else { /* version 1, must be PPTP */ - u8 _ppp_hdr[PPP_HDRLEN]; - u8 *ppp_hdr; - - if (hdr->flags & GRE_ACK) - offset += sizeof(((struct pptp_gre_header *)0)->ack); - - ppp_hdr = skb_header_pointer(skb, nhoff + offset, - sizeof(_ppp_hdr), _ppp_hdr); - if (!ppp_hdr) - goto out_bad; - - switch (PPP_PROTOCOL(ppp_hdr)) { - case PPP_IP: - proto = htons(ETH_P_IP); - break; - case PPP_IPV6: - proto = htons(ETH_P_IPV6); - break; - default: - /* Could probably catch some more like MPLS */ - break; - } - - offset += PPP_HDRLEN; - } - - nhoff += offset; - key_control->flags |= FLOW_DIS_ENCAPSULATION; - if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) - goto out_good; - - goto again; - } - case NEXTHDR_HOP: - case NEXTHDR_ROUTING: - case NEXTHDR_DEST: { - u8 _opthdr[2], *opthdr; - - if (proto != htons(ETH_P_IPV6)) - break; - - opthdr = __skb_header_pointer(skb, nhoff, sizeof(_opthdr), - data, hlen, &_opthdr); - if (!opthdr) - goto out_bad; - - ip_proto = opthdr[0]; - nhoff += (opthdr[1] + 1) << 3; - - goto ip_proto_again; - } - case NEXTHDR_FRAGMENT: { - struct frag_hdr _fh, *fh; - - if (proto != htons(ETH_P_IPV6)) - break; - - fh = __skb_header_pointer(skb, nhoff, sizeof(_fh), - data, hlen, &_fh); - - if (!fh) - goto out_bad; - - key_control->flags |= FLOW_DIS_IS_FRAGMENT; - - nhoff += sizeof(_fh); - ip_proto = fh->nexthdr; - - if (!(fh->frag_off & htons(IP6_OFFSET))) { - key_control->flags |= FLOW_DIS_FIRST_FRAG; - if (flags & FLOW_DISSECTOR_F_PARSE_1ST_FRAG) - goto ip_proto_again; - } - goto out_good; - } - case IPPROTO_IPIP: - proto = htons(ETH_P_IP); - - key_control->flags |= FLOW_DIS_ENCAPSULATION; - if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) - goto out_good; - - goto ip; - case IPPROTO_IPV6: - proto = htons(ETH_P_IPV6); - - key_control->flags |= FLOW_DIS_ENCAPSULATION; - if (flags & FLOW_DISSECTOR_F_STOP_AT_ENCAP) - goto out_good; - - goto ipv6; - case IPPROTO_MPLS: - proto = htons(ETH_P_MPLS_UC); - goto mpls; - default: - break; - } - - if (dissector_uses_key(flow_dissector, - FLOW_DISSECTOR_KEY_PORTS)) { - key_ports = skb_flow_dissector_target(flow_dissector, - FLOW_DISSECTOR_KEY_PORTS, - target_container); - key_ports->ports = __skb_flow_get_ports(skb, nhoff, ip_proto, - data, hlen); - } - -out_good: - ret = true; - - key_control->thoff = (u16)nhoff; -out: - key_basic->n_proto = proto; - key_basic->ip_proto = ip_proto; - - return ret; - -out_bad: - ret = false; - key_control->thoff = min_t(u16, nhoff, skb ? skb->len : hlen); - goto out; -} -EXPORT_SYMBOL(__skb_flow_dissect); - -static u32 hashrnd __read_mostly; -static __always_inline void __flow_hash_secret_init(void) -{ - net_get_random_once(&hashrnd, sizeof(hashrnd)); -} - -static __always_inline u32 __flow_hash_words(const u32 *words, u32 length, - u32 keyval) -{ - return jhash2(words, length, keyval); -} - -static inline const u32 *flow_keys_hash_start(const struct flow_keys *flow) -{ - const void *p = flow; - - BUILD_BUG_ON(FLOW_KEYS_HASH_OFFSET % sizeof(u32)); - return (const u32 *)(p + FLOW_KEYS_HASH_OFFSET); -} - -static inline size_t flow_keys_hash_length(const struct flow_keys *flow) -{ - size_t diff = FLOW_KEYS_HASH_OFFSET + sizeof(flow->addrs); - BUILD_BUG_ON((sizeof(*flow) - FLOW_KEYS_HASH_OFFSET) % sizeof(u32)); - BUILD_BUG_ON(offsetof(typeof(*flow), addrs) != - sizeof(*flow) - sizeof(flow->addrs)); - - switch (flow->control.addr_type) { - case FLOW_DISSECTOR_KEY_IPV4_ADDRS: - diff -= sizeof(flow->addrs.v4addrs); - break; - case FLOW_DISSECTOR_KEY_IPV6_ADDRS: - diff -= sizeof(flow->addrs.v6addrs); - break; - case FLOW_DISSECTOR_KEY_TIPC_ADDRS: - diff -= sizeof(flow->addrs.tipcaddrs); - break; - } - return (sizeof(*flow) - diff) / sizeof(u32); -} - -__be32 flow_get_u32_src(const struct flow_keys *flow) -{ - switch (flow->control.addr_type) { - case FLOW_DISSECTOR_KEY_IPV4_ADDRS: - return flow->addrs.v4addrs.src; - case FLOW_DISSECTOR_KEY_IPV6_ADDRS: - return (__force __be32)ipv6_addr_hash( - &flow->addrs.v6addrs.src); - case FLOW_DISSECTOR_KEY_TIPC_ADDRS: - return flow->addrs.tipcaddrs.srcnode; - default: - return 0; - } -} -EXPORT_SYMBOL(flow_get_u32_src); - -__be32 flow_get_u32_dst(const struct flow_keys *flow) -{ - switch (flow->control.addr_type) { - case FLOW_DISSECTOR_KEY_IPV4_ADDRS: - return flow->addrs.v4addrs.dst; - case FLOW_DISSECTOR_KEY_IPV6_ADDRS: - return (__force __be32)ipv6_addr_hash( - &flow->addrs.v6addrs.dst); - default: - return 0; - } -} -EXPORT_SYMBOL(flow_get_u32_dst); - -static inline void __flow_hash_consistentify(struct flow_keys *keys) -{ - int addr_diff, i; - - switch (keys->control.addr_type) { - case FLOW_DISSECTOR_KEY_IPV4_ADDRS: - addr_diff = (__force u32)keys->addrs.v4addrs.dst - - (__force u32)keys->addrs.v4addrs.src; - if ((addr_diff < 0) || - (addr_diff == 0 && - ((__force u16)keys->ports.dst < - (__force u16)keys->ports.src))) { - swap(keys->addrs.v4addrs.src, keys->addrs.v4addrs.dst); - swap(keys->ports.src, keys->ports.dst); - } - break; - case FLOW_DISSECTOR_KEY_IPV6_ADDRS: - addr_diff = memcmp(&keys->addrs.v6addrs.dst, - &keys->addrs.v6addrs.src, - sizeof(keys->addrs.v6addrs.dst)); - if ((addr_diff < 0) || - (addr_diff == 0 && - ((__force u16)keys->ports.dst < - (__force u16)keys->ports.src))) { - for (i = 0; i < 4; i++) - swap(keys->addrs.v6addrs.src.s6_addr32[i], - keys->addrs.v6addrs.dst.s6_addr32[i]); - swap(keys->ports.src, keys->ports.dst); - } - break; - } -} - -static inline u32 __flow_hash_from_keys(struct flow_keys *keys, u32 keyval) -{ - u32 hash; - - __flow_hash_consistentify(keys); - - hash = __flow_hash_words(flow_keys_hash_start(keys), - flow_keys_hash_length(keys), keyval); - if (!hash) - hash = 1; - - return hash; -} - -u32 flow_hash_from_keys(struct flow_keys *keys) -{ - __flow_hash_secret_init(); - return __flow_hash_from_keys(keys, hashrnd); -} -EXPORT_SYMBOL(flow_hash_from_keys); - -static inline u32 ___skb_get_hash(const struct sk_buff *skb, - struct flow_keys *keys, u32 keyval) -{ - skb_flow_dissect_flow_keys(skb, keys, - FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); - - return __flow_hash_from_keys(keys, keyval); -} - -struct _flow_keys_digest_data { - __be16 n_proto; - u8 ip_proto; - u8 padding; - __be32 ports; - __be32 src; - __be32 dst; -}; - -void make_flow_keys_digest(struct flow_keys_digest *digest, - const struct flow_keys *flow) -{ - struct _flow_keys_digest_data *data = - (struct _flow_keys_digest_data *)digest; - - BUILD_BUG_ON(sizeof(*data) > sizeof(*digest)); - - memset(digest, 0, sizeof(*digest)); - - data->n_proto = flow->basic.n_proto; - data->ip_proto = flow->basic.ip_proto; - data->ports = flow->ports.ports; - data->src = flow->addrs.v4addrs.src; - data->dst = flow->addrs.v4addrs.dst; -} -EXPORT_SYMBOL(make_flow_keys_digest); - -static struct flow_dissector flow_keys_dissector_symmetric __read_mostly; - -u32 __skb_get_hash_symmetric(struct sk_buff *skb) -{ - struct flow_keys keys; - - __flow_hash_secret_init(); - - memset(&keys, 0, sizeof(keys)); - __skb_flow_dissect(skb, &flow_keys_dissector_symmetric, &keys, - NULL, 0, 0, 0, - FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL); - - return __flow_hash_from_keys(&keys, hashrnd); -} -EXPORT_SYMBOL_GPL(__skb_get_hash_symmetric); - -/** - * __skb_get_hash: calculate a flow hash - * @skb: sk_buff to calculate flow hash from - * - * This function calculates a flow hash based on src/dst addresses - * and src/dst port numbers. Sets hash in skb to non-zero hash value - * on success, zero indicates no valid hash. Also, sets l4_hash in skb - * if hash is a canonical 4-tuple hash over transport ports. - */ -void __skb_get_hash(struct sk_buff *skb) -{ - struct flow_keys keys; - u32 hash; - - __flow_hash_secret_init(); - - hash = ___skb_get_hash(skb, &keys, hashrnd); - - __skb_set_sw_hash(skb, hash, flow_keys_have_l4(&keys)); -} -EXPORT_SYMBOL(__skb_get_hash); - -__u32 skb_get_hash_perturb(const struct sk_buff *skb, u32 perturb) -{ - struct flow_keys keys; - - return ___skb_get_hash(skb, &keys, perturb); -} -EXPORT_SYMBOL(skb_get_hash_perturb); - -__u32 __skb_get_hash_flowi6(struct sk_buff *skb, const struct flowi6 *fl6) -{ - struct flow_keys keys; - - memset(&keys, 0, sizeof(keys)); - - memcpy(&keys.addrs.v6addrs.src, &fl6->saddr, - sizeof(keys.addrs.v6addrs.src)); - memcpy(&keys.addrs.v6addrs.dst, &fl6->daddr, - sizeof(keys.addrs.v6addrs.dst)); - keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; - keys.ports.src = fl6->fl6_sport; - keys.ports.dst = fl6->fl6_dport; - keys.keyid.keyid = fl6->fl6_gre_key; - keys.tags.flow_label = (__force u32)fl6->flowlabel; - keys.basic.ip_proto = fl6->flowi6_proto; - - __skb_set_sw_hash(skb, flow_hash_from_keys(&keys), - flow_keys_have_l4(&keys)); - - return skb->hash; -} -EXPORT_SYMBOL(__skb_get_hash_flowi6); - -__u32 __skb_get_hash_flowi4(struct sk_buff *skb, const struct flowi4 *fl4) -{ - struct flow_keys keys; - - memset(&keys, 0, sizeof(keys)); - - keys.addrs.v4addrs.src = fl4->saddr; - keys.addrs.v4addrs.dst = fl4->daddr; - keys.control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; - keys.ports.src = fl4->fl4_sport; - keys.ports.dst = fl4->fl4_dport; - keys.keyid.keyid = fl4->fl4_gre_key; - keys.basic.ip_proto = fl4->flowi4_proto; - - __skb_set_sw_hash(skb, flow_hash_from_keys(&keys), - flow_keys_have_l4(&keys)); - - return skb->hash; -} -EXPORT_SYMBOL(__skb_get_hash_flowi4); - -u32 __skb_get_poff(const struct sk_buff *skb, void *data, - const struct flow_keys *keys, int hlen) -{ - u32 poff = keys->control.thoff; - - /* skip L4 headers for fragments after the first */ - if ((keys->control.flags & FLOW_DIS_IS_FRAGMENT) && - !(keys->control.flags & FLOW_DIS_FIRST_FRAG)) - return poff; - - switch (keys->basic.ip_proto) { - case IPPROTO_TCP: { - /* access doff as u8 to avoid unaligned access */ - const u8 *doff; - u8 _doff; - - doff = __skb_header_pointer(skb, poff + 12, sizeof(_doff), - data, hlen, &_doff); - if (!doff) - return poff; - - poff += max_t(u32, sizeof(struct tcphdr), (*doff & 0xF0) >> 2); - break; - } - case IPPROTO_UDP: - case IPPROTO_UDPLITE: - poff += sizeof(struct udphdr); - break; - /* For the rest, we do not really care about header - * extensions at this point for now. - */ - case IPPROTO_ICMP: - poff += sizeof(struct icmphdr); - break; - case IPPROTO_ICMPV6: - poff += sizeof(struct icmp6hdr); - break; - case IPPROTO_IGMP: - poff += sizeof(struct igmphdr); - break; - case IPPROTO_DCCP: - poff += sizeof(struct dccp_hdr); - break; - case IPPROTO_SCTP: - poff += sizeof(struct sctphdr); - break; - } - - return poff; -} - -/** - * skb_get_poff - get the offset to the payload - * @skb: sk_buff to get the payload offset from - * - * The function will get the offset to the payload as far as it could - * be dissected. The main user is currently BPF, so that we can dynamically - * truncate packets without needing to push actual payload to the user - * space and can analyze headers only, instead. - */ -u32 skb_get_poff(const struct sk_buff *skb) -{ - struct flow_keys keys; - - if (!skb_flow_dissect_flow_keys(skb, &keys, 0)) - return 0; - - return __skb_get_poff(skb, skb->data, &keys, skb_headlen(skb)); -} - -__u32 __get_hash_from_flowi6(const struct flowi6 *fl6, struct flow_keys *keys) -{ - memset(keys, 0, sizeof(*keys)); - - memcpy(&keys->addrs.v6addrs.src, &fl6->saddr, - sizeof(keys->addrs.v6addrs.src)); - memcpy(&keys->addrs.v6addrs.dst, &fl6->daddr, - sizeof(keys->addrs.v6addrs.dst)); - keys->control.addr_type = FLOW_DISSECTOR_KEY_IPV6_ADDRS; - keys->ports.src = fl6->fl6_sport; - keys->ports.dst = fl6->fl6_dport; - keys->keyid.keyid = fl6->fl6_gre_key; - keys->tags.flow_label = (__force u32)fl6->flowlabel; - keys->basic.ip_proto = fl6->flowi6_proto; - - return flow_hash_from_keys(keys); -} -EXPORT_SYMBOL(__get_hash_from_flowi6); - -__u32 __get_hash_from_flowi4(const struct flowi4 *fl4, struct flow_keys *keys) -{ - memset(keys, 0, sizeof(*keys)); - - keys->addrs.v4addrs.src = fl4->saddr; - keys->addrs.v4addrs.dst = fl4->daddr; - keys->control.addr_type = FLOW_DISSECTOR_KEY_IPV4_ADDRS; - keys->ports.src = fl4->fl4_sport; - keys->ports.dst = fl4->fl4_dport; - keys->keyid.keyid = fl4->fl4_gre_key; - keys->basic.ip_proto = fl4->flowi4_proto; - - return flow_hash_from_keys(keys); -} -EXPORT_SYMBOL(__get_hash_from_flowi4); - -static const struct flow_dissector_key flow_keys_dissector_keys[] = { - { - .key_id = FLOW_DISSECTOR_KEY_CONTROL, - .offset = offsetof(struct flow_keys, control), - }, - { - .key_id = FLOW_DISSECTOR_KEY_BASIC, - .offset = offsetof(struct flow_keys, basic), - }, - { - .key_id = FLOW_DISSECTOR_KEY_IPV4_ADDRS, - .offset = offsetof(struct flow_keys, addrs.v4addrs), - }, - { - .key_id = FLOW_DISSECTOR_KEY_IPV6_ADDRS, - .offset = offsetof(struct flow_keys, addrs.v6addrs), - }, - { - .key_id = FLOW_DISSECTOR_KEY_TIPC_ADDRS, - .offset = offsetof(struct flow_keys, addrs.tipcaddrs), - }, - { - .key_id = FLOW_DISSECTOR_KEY_PORTS, - .offset = offsetof(struct flow_keys, ports), - }, - { - .key_id = FLOW_DISSECTOR_KEY_VLAN, - .offset = offsetof(struct flow_keys, vlan), - }, - { - .key_id = FLOW_DISSECTOR_KEY_FLOW_LABEL, - .offset = offsetof(struct flow_keys, tags), - }, - { - .key_id = FLOW_DISSECTOR_KEY_GRE_KEYID, - .offset = offsetof(struct flow_keys, keyid), - }, -}; - -static const struct flow_dissector_key flow_keys_dissector_symmetric_keys[] = { - { - .key_id = FLOW_DISSECTOR_KEY_CONTROL, - .offset = offsetof(struct flow_keys, control), - }, - { - .key_id = FLOW_DISSECTOR_KEY_BASIC, - .offset = offsetof(struct flow_keys, basic), - }, - { - .key_id = FLOW_DISSECTOR_KEY_IPV4_ADDRS, - .offset = offsetof(struct flow_keys, addrs.v4addrs), - }, - { - .key_id = FLOW_DISSECTOR_KEY_IPV6_ADDRS, - .offset = offsetof(struct flow_keys, addrs.v6addrs), - }, - { - .key_id = FLOW_DISSECTOR_KEY_PORTS, - .offset = offsetof(struct flow_keys, ports), - }, -}; - -static const struct flow_dissector_key flow_keys_buf_dissector_keys[] = { - { - .key_id = FLOW_DISSECTOR_KEY_CONTROL, - .offset = offsetof(struct flow_keys, control), - }, - { - .key_id = FLOW_DISSECTOR_KEY_BASIC, - .offset = offsetof(struct flow_keys, basic), - }, -}; - -struct flow_dissector flow_keys_dissector __read_mostly; -EXPORT_SYMBOL(flow_keys_dissector); - -struct flow_dissector flow_keys_buf_dissector __read_mostly; - -static int __init init_default_flow_dissectors(void) -{ - skb_flow_dissector_init(&flow_keys_dissector, - flow_keys_dissector_keys, - ARRAY_SIZE(flow_keys_dissector_keys)); - skb_flow_dissector_init(&flow_keys_dissector_symmetric, - flow_keys_dissector_symmetric_keys, - ARRAY_SIZE(flow_keys_dissector_symmetric_keys)); - skb_flow_dissector_init(&flow_keys_buf_dissector, - flow_keys_buf_dissector_keys, - ARRAY_SIZE(flow_keys_buf_dissector_keys)); - return 0; -} - -core_initcall(init_default_flow_dissectors); diff --git a/src/linux/net/core/gen_estimator.c b/src/linux/net/core/gen_estimator.c deleted file mode 100644 index cad8e79..0000000 --- a/src/linux/net/core/gen_estimator.c +++ /dev/null @@ -1,339 +0,0 @@ -/* - * net/sched/gen_estimator.c Simple rate estimator. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, - * - * Changes: - * Jamal Hadi Salim - moved it to net/core and reshulfed - * names to make it usable in general net subsystem. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - This code is NOT intended to be used for statistics collection, - its purpose is to provide a base for statistical multiplexing - for controlled load service. - If you need only statistics, run a user level daemon which - periodically reads byte counters. - - Unfortunately, rate estimation is not a very easy task. - F.e. I did not find a simple way to estimate the current peak rate - and even failed to formulate the problem 8)8) - - So I preferred not to built an estimator into the scheduler, - but run this task separately. - Ideally, it should be kernel thread(s), but for now it runs - from timers, which puts apparent top bounds on the number of rated - flows, has minimal overhead on small, but is enough - to handle controlled load service, sets of aggregates. - - We measure rate over A=(1<stats_lock) - spin_lock(e->stats_lock); - read_lock(&est_lock); - if (e->bstats == NULL) - goto skip; - - __gnet_stats_copy_basic(e->running, &b, e->cpu_bstats, e->bstats); - - brate = (b.bytes - e->last_bytes)<<(7 - idx); - e->last_bytes = b.bytes; - e->avbps += (brate >> e->ewma_log) - (e->avbps >> e->ewma_log); - WRITE_ONCE(e->rate_est->bps, (e->avbps + 0xF) >> 5); - - rate = b.packets - e->last_packets; - rate <<= (7 - idx); - e->last_packets = b.packets; - e->avpps += (rate >> e->ewma_log) - (e->avpps >> e->ewma_log); - WRITE_ONCE(e->rate_est->pps, (e->avpps + 0xF) >> 5); -skip: - read_unlock(&est_lock); - if (e->stats_lock) - spin_unlock(e->stats_lock); - } - - if (!list_empty(&elist[idx].list)) - mod_timer(&elist[idx].timer, jiffies + ((HZ/4) << idx)); - rcu_read_unlock(); -} - -static void gen_add_node(struct gen_estimator *est) -{ - struct rb_node **p = &est_root.rb_node, *parent = NULL; - - while (*p) { - struct gen_estimator *e; - - parent = *p; - e = rb_entry(parent, struct gen_estimator, node); - - if (est->bstats > e->bstats) - p = &parent->rb_right; - else - p = &parent->rb_left; - } - rb_link_node(&est->node, parent, p); - rb_insert_color(&est->node, &est_root); -} - -static -struct gen_estimator *gen_find_node(const struct gnet_stats_basic_packed *bstats, - const struct gnet_stats_rate_est64 *rate_est) -{ - struct rb_node *p = est_root.rb_node; - - while (p) { - struct gen_estimator *e; - - e = rb_entry(p, struct gen_estimator, node); - - if (bstats > e->bstats) - p = p->rb_right; - else if (bstats < e->bstats || rate_est != e->rate_est) - p = p->rb_left; - else - return e; - } - return NULL; -} - -/** - * gen_new_estimator - create a new rate estimator - * @bstats: basic statistics - * @cpu_bstats: bstats per cpu - * @rate_est: rate estimator statistics - * @stats_lock: statistics lock - * @running: qdisc running seqcount - * @opt: rate estimator configuration TLV - * - * Creates a new rate estimator with &bstats as source and &rate_est - * as destination. A new timer with the interval specified in the - * configuration TLV is created. Upon each interval, the latest statistics - * will be read from &bstats and the estimated rate will be stored in - * &rate_est with the statistics lock grabbed during this period. - * - * Returns 0 on success or a negative error code. - * - */ -int gen_new_estimator(struct gnet_stats_basic_packed *bstats, - struct gnet_stats_basic_cpu __percpu *cpu_bstats, - struct gnet_stats_rate_est64 *rate_est, - spinlock_t *stats_lock, - seqcount_t *running, - struct nlattr *opt) -{ - struct gen_estimator *est; - struct gnet_estimator *parm = nla_data(opt); - struct gnet_stats_basic_packed b = {0}; - int idx; - - if (nla_len(opt) < sizeof(*parm)) - return -EINVAL; - - if (parm->interval < -2 || parm->interval > 3) - return -EINVAL; - - est = kzalloc(sizeof(*est), GFP_KERNEL); - if (est == NULL) - return -ENOBUFS; - - __gnet_stats_copy_basic(running, &b, cpu_bstats, bstats); - - idx = parm->interval + 2; - est->bstats = bstats; - est->rate_est = rate_est; - est->stats_lock = stats_lock; - est->running = running; - est->ewma_log = parm->ewma_log; - est->last_bytes = b.bytes; - est->avbps = rate_est->bps<<5; - est->last_packets = b.packets; - est->avpps = rate_est->pps<<10; - est->cpu_bstats = cpu_bstats; - - spin_lock_bh(&est_tree_lock); - if (!elist[idx].timer.function) { - INIT_LIST_HEAD(&elist[idx].list); - setup_timer(&elist[idx].timer, est_timer, idx); - } - - if (list_empty(&elist[idx].list)) - mod_timer(&elist[idx].timer, jiffies + ((HZ/4) << idx)); - - list_add_rcu(&est->list, &elist[idx].list); - gen_add_node(est); - spin_unlock_bh(&est_tree_lock); - - return 0; -} -EXPORT_SYMBOL(gen_new_estimator); - -/** - * gen_kill_estimator - remove a rate estimator - * @bstats: basic statistics - * @rate_est: rate estimator statistics - * - * Removes the rate estimator specified by &bstats and &rate_est. - * - * Note : Caller should respect an RCU grace period before freeing stats_lock - */ -void gen_kill_estimator(struct gnet_stats_basic_packed *bstats, - struct gnet_stats_rate_est64 *rate_est) -{ - struct gen_estimator *e; - - spin_lock_bh(&est_tree_lock); - while ((e = gen_find_node(bstats, rate_est))) { - rb_erase(&e->node, &est_root); - - write_lock(&est_lock); - e->bstats = NULL; - write_unlock(&est_lock); - - list_del_rcu(&e->list); - kfree_rcu(e, e_rcu); - } - spin_unlock_bh(&est_tree_lock); -} -EXPORT_SYMBOL(gen_kill_estimator); - -/** - * gen_replace_estimator - replace rate estimator configuration - * @bstats: basic statistics - * @cpu_bstats: bstats per cpu - * @rate_est: rate estimator statistics - * @stats_lock: statistics lock - * @running: qdisc running seqcount (might be NULL) - * @opt: rate estimator configuration TLV - * - * Replaces the configuration of a rate estimator by calling - * gen_kill_estimator() and gen_new_estimator(). - * - * Returns 0 on success or a negative error code. - */ -int gen_replace_estimator(struct gnet_stats_basic_packed *bstats, - struct gnet_stats_basic_cpu __percpu *cpu_bstats, - struct gnet_stats_rate_est64 *rate_est, - spinlock_t *stats_lock, - seqcount_t *running, struct nlattr *opt) -{ - gen_kill_estimator(bstats, rate_est); - return gen_new_estimator(bstats, cpu_bstats, rate_est, stats_lock, running, opt); -} -EXPORT_SYMBOL(gen_replace_estimator); - -/** - * gen_estimator_active - test if estimator is currently in use - * @bstats: basic statistics - * @rate_est: rate estimator statistics - * - * Returns true if estimator is active, and false if not. - */ -bool gen_estimator_active(const struct gnet_stats_basic_packed *bstats, - const struct gnet_stats_rate_est64 *rate_est) -{ - bool res; - - ASSERT_RTNL(); - - spin_lock_bh(&est_tree_lock); - res = gen_find_node(bstats, rate_est) != NULL; - spin_unlock_bh(&est_tree_lock); - - return res; -} -EXPORT_SYMBOL(gen_estimator_active); diff --git a/src/linux/net/core/gen_stats.c b/src/linux/net/core/gen_stats.c deleted file mode 100644 index 508e051..0000000 --- a/src/linux/net/core/gen_stats.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - * net/core/gen_stats.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Thomas Graf - * Jamal Hadi Salim - * Alexey Kuznetsov, - * - * See Documentation/networking/gen_stats.txt - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -static inline int -gnet_stats_copy(struct gnet_dump *d, int type, void *buf, int size, int padattr) -{ - if (nla_put_64bit(d->skb, type, size, buf, padattr)) - goto nla_put_failure; - return 0; - -nla_put_failure: - if (d->lock) - spin_unlock_bh(d->lock); - kfree(d->xstats); - d->xstats = NULL; - d->xstats_len = 0; - return -1; -} - -/** - * gnet_stats_start_copy_compat - start dumping procedure in compatibility mode - * @skb: socket buffer to put statistics TLVs into - * @type: TLV type for top level statistic TLV - * @tc_stats_type: TLV type for backward compatibility struct tc_stats TLV - * @xstats_type: TLV type for backward compatibility xstats TLV - * @lock: statistics lock - * @d: dumping handle - * @padattr: padding attribute - * - * Initializes the dumping handle, grabs the statistic lock and appends - * an empty TLV header to the socket buffer for use a container for all - * other statistic TLVS. - * - * The dumping handle is marked to be in backward compatibility mode telling - * all gnet_stats_copy_XXX() functions to fill a local copy of struct tc_stats. - * - * Returns 0 on success or -1 if the room in the socket buffer was not sufficient. - */ -int -gnet_stats_start_copy_compat(struct sk_buff *skb, int type, int tc_stats_type, - int xstats_type, spinlock_t *lock, - struct gnet_dump *d, int padattr) - __acquires(lock) -{ - memset(d, 0, sizeof(*d)); - - if (type) - d->tail = (struct nlattr *)skb_tail_pointer(skb); - d->skb = skb; - d->compat_tc_stats = tc_stats_type; - d->compat_xstats = xstats_type; - d->padattr = padattr; - if (lock) { - d->lock = lock; - spin_lock_bh(lock); - } - if (d->tail) - return gnet_stats_copy(d, type, NULL, 0, padattr); - - return 0; -} -EXPORT_SYMBOL(gnet_stats_start_copy_compat); - -/** - * gnet_stats_start_copy - start dumping procedure in compatibility mode - * @skb: socket buffer to put statistics TLVs into - * @type: TLV type for top level statistic TLV - * @lock: statistics lock - * @d: dumping handle - * @padattr: padding attribute - * - * Initializes the dumping handle, grabs the statistic lock and appends - * an empty TLV header to the socket buffer for use a container for all - * other statistic TLVS. - * - * Returns 0 on success or -1 if the room in the socket buffer was not sufficient. - */ -int -gnet_stats_start_copy(struct sk_buff *skb, int type, spinlock_t *lock, - struct gnet_dump *d, int padattr) -{ - return gnet_stats_start_copy_compat(skb, type, 0, 0, lock, d, padattr); -} -EXPORT_SYMBOL(gnet_stats_start_copy); - -static void -__gnet_stats_copy_basic_cpu(struct gnet_stats_basic_packed *bstats, - struct gnet_stats_basic_cpu __percpu *cpu) -{ - int i; - - for_each_possible_cpu(i) { - struct gnet_stats_basic_cpu *bcpu = per_cpu_ptr(cpu, i); - unsigned int start; - u64 bytes; - u32 packets; - - do { - start = u64_stats_fetch_begin_irq(&bcpu->syncp); - bytes = bcpu->bstats.bytes; - packets = bcpu->bstats.packets; - } while (u64_stats_fetch_retry_irq(&bcpu->syncp, start)); - - bstats->bytes += bytes; - bstats->packets += packets; - } -} - -void -__gnet_stats_copy_basic(const seqcount_t *running, - struct gnet_stats_basic_packed *bstats, - struct gnet_stats_basic_cpu __percpu *cpu, - struct gnet_stats_basic_packed *b) -{ - unsigned int seq; - - if (cpu) { - __gnet_stats_copy_basic_cpu(bstats, cpu); - return; - } - do { - if (running) - seq = read_seqcount_begin(running); - bstats->bytes = b->bytes; - bstats->packets = b->packets; - } while (running && read_seqcount_retry(running, seq)); -} -EXPORT_SYMBOL(__gnet_stats_copy_basic); - -/** - * gnet_stats_copy_basic - copy basic statistics into statistic TLV - * @running: seqcount_t pointer - * @d: dumping handle - * @cpu: copy statistic per cpu - * @b: basic statistics - * - * Appends the basic statistics to the top level TLV created by - * gnet_stats_start_copy(). - * - * Returns 0 on success or -1 with the statistic lock released - * if the room in the socket buffer was not sufficient. - */ -int -gnet_stats_copy_basic(const seqcount_t *running, - struct gnet_dump *d, - struct gnet_stats_basic_cpu __percpu *cpu, - struct gnet_stats_basic_packed *b) -{ - struct gnet_stats_basic_packed bstats = {0}; - - __gnet_stats_copy_basic(running, &bstats, cpu, b); - - if (d->compat_tc_stats) { - d->tc_stats.bytes = bstats.bytes; - d->tc_stats.packets = bstats.packets; - } - - if (d->tail) { - struct gnet_stats_basic sb; - - memset(&sb, 0, sizeof(sb)); - sb.bytes = bstats.bytes; - sb.packets = bstats.packets; - return gnet_stats_copy(d, TCA_STATS_BASIC, &sb, sizeof(sb), - TCA_STATS_PAD); - } - return 0; -} -EXPORT_SYMBOL(gnet_stats_copy_basic); - -/** - * gnet_stats_copy_rate_est - copy rate estimator statistics into statistics TLV - * @d: dumping handle - * @b: basic statistics - * @r: rate estimator statistics - * - * Appends the rate estimator statistics to the top level TLV created by - * gnet_stats_start_copy(). - * - * Returns 0 on success or -1 with the statistic lock released - * if the room in the socket buffer was not sufficient. - */ -int -gnet_stats_copy_rate_est(struct gnet_dump *d, - const struct gnet_stats_basic_packed *b, - struct gnet_stats_rate_est64 *r) -{ - struct gnet_stats_rate_est est; - int res; - - if (b && !gen_estimator_active(b, r)) - return 0; - - est.bps = min_t(u64, UINT_MAX, r->bps); - /* we have some time before reaching 2^32 packets per second */ - est.pps = r->pps; - - if (d->compat_tc_stats) { - d->tc_stats.bps = est.bps; - d->tc_stats.pps = est.pps; - } - - if (d->tail) { - res = gnet_stats_copy(d, TCA_STATS_RATE_EST, &est, sizeof(est), - TCA_STATS_PAD); - if (res < 0 || est.bps == r->bps) - return res; - /* emit 64bit stats only if needed */ - return gnet_stats_copy(d, TCA_STATS_RATE_EST64, r, sizeof(*r), - TCA_STATS_PAD); - } - - return 0; -} -EXPORT_SYMBOL(gnet_stats_copy_rate_est); - -static void -__gnet_stats_copy_queue_cpu(struct gnet_stats_queue *qstats, - const struct gnet_stats_queue __percpu *q) -{ - int i; - - for_each_possible_cpu(i) { - const struct gnet_stats_queue *qcpu = per_cpu_ptr(q, i); - - qstats->qlen = 0; - qstats->backlog += qcpu->backlog; - qstats->drops += qcpu->drops; - qstats->requeues += qcpu->requeues; - qstats->overlimits += qcpu->overlimits; - } -} - -static void __gnet_stats_copy_queue(struct gnet_stats_queue *qstats, - const struct gnet_stats_queue __percpu *cpu, - const struct gnet_stats_queue *q, - __u32 qlen) -{ - if (cpu) { - __gnet_stats_copy_queue_cpu(qstats, cpu); - } else { - qstats->qlen = q->qlen; - qstats->backlog = q->backlog; - qstats->drops = q->drops; - qstats->requeues = q->requeues; - qstats->overlimits = q->overlimits; - } - - qstats->qlen = qlen; -} - -/** - * gnet_stats_copy_queue - copy queue statistics into statistics TLV - * @d: dumping handle - * @cpu_q: per cpu queue statistics - * @q: queue statistics - * @qlen: queue length statistics - * - * Appends the queue statistics to the top level TLV created by - * gnet_stats_start_copy(). Using per cpu queue statistics if - * they are available. - * - * Returns 0 on success or -1 with the statistic lock released - * if the room in the socket buffer was not sufficient. - */ -int -gnet_stats_copy_queue(struct gnet_dump *d, - struct gnet_stats_queue __percpu *cpu_q, - struct gnet_stats_queue *q, __u32 qlen) -{ - struct gnet_stats_queue qstats = {0}; - - __gnet_stats_copy_queue(&qstats, cpu_q, q, qlen); - - if (d->compat_tc_stats) { - d->tc_stats.drops = qstats.drops; - d->tc_stats.qlen = qstats.qlen; - d->tc_stats.backlog = qstats.backlog; - d->tc_stats.overlimits = qstats.overlimits; - } - - if (d->tail) - return gnet_stats_copy(d, TCA_STATS_QUEUE, - &qstats, sizeof(qstats), - TCA_STATS_PAD); - - return 0; -} -EXPORT_SYMBOL(gnet_stats_copy_queue); - -/** - * gnet_stats_copy_app - copy application specific statistics into statistics TLV - * @d: dumping handle - * @st: application specific statistics data - * @len: length of data - * - * Appends the application specific statistics to the top level TLV created by - * gnet_stats_start_copy() and remembers the data for XSTATS if the dumping - * handle is in backward compatibility mode. - * - * Returns 0 on success or -1 with the statistic lock released - * if the room in the socket buffer was not sufficient. - */ -int -gnet_stats_copy_app(struct gnet_dump *d, void *st, int len) -{ - if (d->compat_xstats) { - d->xstats = kmemdup(st, len, GFP_ATOMIC); - if (!d->xstats) - goto err_out; - d->xstats_len = len; - } - - if (d->tail) - return gnet_stats_copy(d, TCA_STATS_APP, st, len, - TCA_STATS_PAD); - - return 0; - -err_out: - if (d->lock) - spin_unlock_bh(d->lock); - d->xstats_len = 0; - return -1; -} -EXPORT_SYMBOL(gnet_stats_copy_app); - -/** - * gnet_stats_finish_copy - finish dumping procedure - * @d: dumping handle - * - * Corrects the length of the top level TLV to include all TLVs added - * by gnet_stats_copy_XXX() calls. Adds the backward compatibility TLVs - * if gnet_stats_start_copy_compat() was used and releases the statistics - * lock. - * - * Returns 0 on success or -1 with the statistic lock released - * if the room in the socket buffer was not sufficient. - */ -int -gnet_stats_finish_copy(struct gnet_dump *d) -{ - if (d->tail) - d->tail->nla_len = skb_tail_pointer(d->skb) - (u8 *)d->tail; - - if (d->compat_tc_stats) - if (gnet_stats_copy(d, d->compat_tc_stats, &d->tc_stats, - sizeof(d->tc_stats), d->padattr) < 0) - return -1; - - if (d->compat_xstats && d->xstats) { - if (gnet_stats_copy(d, d->compat_xstats, d->xstats, - d->xstats_len, d->padattr) < 0) - return -1; - } - - if (d->lock) - spin_unlock_bh(d->lock); - kfree(d->xstats); - d->xstats = NULL; - d->xstats_len = 0; - return 0; -} -EXPORT_SYMBOL(gnet_stats_finish_copy); diff --git a/src/linux/net/core/link_watch.c b/src/linux/net/core/link_watch.c deleted file mode 100644 index 9828616..0000000 --- a/src/linux/net/core/link_watch.c +++ /dev/null @@ -1,253 +0,0 @@ -/* - * Linux network device link state notification - * - * Author: - * Stefan Rompf - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -enum lw_bits { - LW_URGENT = 0, -}; - -static unsigned long linkwatch_flags; -static unsigned long linkwatch_nextevent; - -static void linkwatch_event(struct work_struct *dummy); -static DECLARE_DELAYED_WORK(linkwatch_work, linkwatch_event); - -static LIST_HEAD(lweventlist); -static DEFINE_SPINLOCK(lweventlist_lock); - -static unsigned char default_operstate(const struct net_device *dev) -{ - if (!netif_carrier_ok(dev)) - return (dev->ifindex != dev_get_iflink(dev) ? - IF_OPER_LOWERLAYERDOWN : IF_OPER_DOWN); - - if (netif_dormant(dev)) - return IF_OPER_DORMANT; - - return IF_OPER_UP; -} - - -static void rfc2863_policy(struct net_device *dev) -{ - unsigned char operstate = default_operstate(dev); - - if (operstate == dev->operstate) - return; - - write_lock_bh(&dev_base_lock); - - switch(dev->link_mode) { - case IF_LINK_MODE_DORMANT: - if (operstate == IF_OPER_UP) - operstate = IF_OPER_DORMANT; - break; - - case IF_LINK_MODE_DEFAULT: - default: - break; - } - - dev->operstate = operstate; - - write_unlock_bh(&dev_base_lock); -} - - -void linkwatch_init_dev(struct net_device *dev) -{ - /* Handle pre-registration link state changes */ - if (!netif_carrier_ok(dev) || netif_dormant(dev)) - rfc2863_policy(dev); -} - - -static bool linkwatch_urgent_event(struct net_device *dev) -{ - if (!netif_running(dev)) - return false; - - if (dev->ifindex != dev_get_iflink(dev)) - return true; - - if (dev->priv_flags & IFF_TEAM_PORT) - return true; - - return netif_carrier_ok(dev) && qdisc_tx_changing(dev); -} - - -static void linkwatch_add_event(struct net_device *dev) -{ - unsigned long flags; - - spin_lock_irqsave(&lweventlist_lock, flags); - if (list_empty(&dev->link_watch_list)) { - list_add_tail(&dev->link_watch_list, &lweventlist); - dev_hold(dev); - } - spin_unlock_irqrestore(&lweventlist_lock, flags); -} - - -static void linkwatch_schedule_work(int urgent) -{ - unsigned long delay = linkwatch_nextevent - jiffies; - - if (test_bit(LW_URGENT, &linkwatch_flags)) - return; - - /* Minimise down-time: drop delay for up event. */ - if (urgent) { - if (test_and_set_bit(LW_URGENT, &linkwatch_flags)) - return; - delay = 0; - } - - /* If we wrap around we'll delay it by at most HZ. */ - if (delay > HZ) - delay = 0; - - /* - * If urgent, schedule immediate execution; otherwise, don't - * override the existing timer. - */ - if (test_bit(LW_URGENT, &linkwatch_flags)) - mod_delayed_work(system_wq, &linkwatch_work, 0); - else - schedule_delayed_work(&linkwatch_work, delay); -} - - -static void linkwatch_do_dev(struct net_device *dev) -{ - /* - * Make sure the above read is complete since it can be - * rewritten as soon as we clear the bit below. - */ - smp_mb__before_atomic(); - - /* We are about to handle this device, - * so new events can be accepted - */ - clear_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state); - - rfc2863_policy(dev); - if (dev->flags & IFF_UP) { - if (netif_carrier_ok(dev)) - dev_activate(dev); - else - dev_deactivate(dev); - - netdev_state_change(dev); - } - dev_put(dev); -} - -static void __linkwatch_run_queue(int urgent_only) -{ - struct net_device *dev; - LIST_HEAD(wrk); - - /* - * Limit the number of linkwatch events to one - * per second so that a runaway driver does not - * cause a storm of messages on the netlink - * socket. This limit does not apply to up events - * while the device qdisc is down. - */ - if (!urgent_only) - linkwatch_nextevent = jiffies + HZ; - /* Limit wrap-around effect on delay. */ - else if (time_after(linkwatch_nextevent, jiffies + HZ)) - linkwatch_nextevent = jiffies; - - clear_bit(LW_URGENT, &linkwatch_flags); - - spin_lock_irq(&lweventlist_lock); - list_splice_init(&lweventlist, &wrk); - - while (!list_empty(&wrk)) { - - dev = list_first_entry(&wrk, struct net_device, link_watch_list); - list_del_init(&dev->link_watch_list); - - if (urgent_only && !linkwatch_urgent_event(dev)) { - list_add_tail(&dev->link_watch_list, &lweventlist); - continue; - } - spin_unlock_irq(&lweventlist_lock); - linkwatch_do_dev(dev); - spin_lock_irq(&lweventlist_lock); - } - - if (!list_empty(&lweventlist)) - linkwatch_schedule_work(0); - spin_unlock_irq(&lweventlist_lock); -} - -void linkwatch_forget_dev(struct net_device *dev) -{ - unsigned long flags; - int clean = 0; - - spin_lock_irqsave(&lweventlist_lock, flags); - if (!list_empty(&dev->link_watch_list)) { - list_del_init(&dev->link_watch_list); - clean = 1; - } - spin_unlock_irqrestore(&lweventlist_lock, flags); - if (clean) - linkwatch_do_dev(dev); -} - - -/* Must be called with the rtnl semaphore held */ -void linkwatch_run_queue(void) -{ - __linkwatch_run_queue(0); -} - - -static void linkwatch_event(struct work_struct *dummy) -{ - rtnl_lock(); - __linkwatch_run_queue(time_after(linkwatch_nextevent, jiffies)); - rtnl_unlock(); -} - - -void linkwatch_fire_event(struct net_device *dev) -{ - bool urgent = linkwatch_urgent_event(dev); - - if (!test_and_set_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) { - linkwatch_add_event(dev); - } else if (!urgent) - return; - - linkwatch_schedule_work(urgent); -} -EXPORT_SYMBOL(linkwatch_fire_event); diff --git a/src/linux/net/core/neighbour.c b/src/linux/net/core/neighbour.c deleted file mode 100644 index 2ae929f..0000000 --- a/src/linux/net/core/neighbour.c +++ /dev/null @@ -1,3228 +0,0 @@ -/* - * Generic address resolution entity - * - * Authors: - * Pedro Roque - * Alexey Kuznetsov - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Fixes: - * Vitaly E. Lavrov releasing NULL neighbor in neigh_add. - * Harald Welte Add neighbour cache statistics like rtstat - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_SYSCTL -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DEBUG -#define NEIGH_DEBUG 1 -#define neigh_dbg(level, fmt, ...) \ -do { \ - if (level <= NEIGH_DEBUG) \ - pr_debug(fmt, ##__VA_ARGS__); \ -} while (0) - -#define PNEIGH_HASHMASK 0xF - -static void neigh_timer_handler(unsigned long arg); -static void __neigh_notify(struct neighbour *n, int type, int flags); -static void neigh_update_notify(struct neighbour *neigh); -static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev); - -#ifdef CONFIG_PROC_FS -static const struct file_operations neigh_stat_seq_fops; -#endif - -/* - Neighbour hash table buckets are protected with rwlock tbl->lock. - - - All the scans/updates to hash buckets MUST be made under this lock. - - NOTHING clever should be made under this lock: no callbacks - to protocol backends, no attempts to send something to network. - It will result in deadlocks, if backend/driver wants to use neighbour - cache. - - If the entry requires some non-trivial actions, increase - its reference count and release table lock. - - Neighbour entries are protected: - - with reference count. - - with rwlock neigh->lock - - Reference count prevents destruction. - - neigh->lock mainly serializes ll address data and its validity state. - However, the same lock is used to protect another entry fields: - - timer - - resolution queue - - Again, nothing clever shall be made under neigh->lock, - the most complicated procedure, which we allow is dev->hard_header. - It is supposed, that dev->hard_header is simplistic and does - not make callbacks to neighbour tables. - */ - -static int neigh_blackhole(struct neighbour *neigh, struct sk_buff *skb) -{ - kfree_skb(skb); - return -ENETDOWN; -} - -static void neigh_cleanup_and_release(struct neighbour *neigh) -{ - if (neigh->parms->neigh_cleanup) - neigh->parms->neigh_cleanup(neigh); - - __neigh_notify(neigh, RTM_DELNEIGH, 0); - neigh_release(neigh); -} - -/* - * It is random distribution in the interval (1/2)*base...(3/2)*base. - * It corresponds to default IPv6 settings and is not overridable, - * because it is really reasonable choice. - */ - -unsigned long neigh_rand_reach_time(unsigned long base) -{ - return base ? (prandom_u32() % base) + (base >> 1) : 0; -} -EXPORT_SYMBOL(neigh_rand_reach_time); - - -static int neigh_forced_gc(struct neigh_table *tbl) -{ - int shrunk = 0; - int i; - struct neigh_hash_table *nht; - - NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs); - - write_lock_bh(&tbl->lock); - nht = rcu_dereference_protected(tbl->nht, - lockdep_is_held(&tbl->lock)); - for (i = 0; i < (1 << nht->hash_shift); i++) { - struct neighbour *n; - struct neighbour __rcu **np; - - np = &nht->hash_buckets[i]; - while ((n = rcu_dereference_protected(*np, - lockdep_is_held(&tbl->lock))) != NULL) { - /* Neighbour record may be discarded if: - * - nobody refers to it. - * - it is not permanent - */ - write_lock(&n->lock); - if (atomic_read(&n->refcnt) == 1 && - !(n->nud_state & NUD_PERMANENT)) { - rcu_assign_pointer(*np, - rcu_dereference_protected(n->next, - lockdep_is_held(&tbl->lock))); - n->dead = 1; - shrunk = 1; - write_unlock(&n->lock); - neigh_cleanup_and_release(n); - continue; - } - write_unlock(&n->lock); - np = &n->next; - } - } - - tbl->last_flush = jiffies; - - write_unlock_bh(&tbl->lock); - - return shrunk; -} - -static void neigh_add_timer(struct neighbour *n, unsigned long when) -{ - neigh_hold(n); - if (unlikely(mod_timer(&n->timer, when))) { - printk("NEIGH: BUG, double timer add, state is %x\n", - n->nud_state); - dump_stack(); - } -} - -static int neigh_del_timer(struct neighbour *n) -{ - if ((n->nud_state & NUD_IN_TIMER) && - del_timer(&n->timer)) { - neigh_release(n); - return 1; - } - return 0; -} - -static void pneigh_queue_purge(struct sk_buff_head *list) -{ - struct sk_buff *skb; - - while ((skb = skb_dequeue(list)) != NULL) { - dev_put(skb->dev); - kfree_skb(skb); - } -} - -static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev) -{ - int i; - struct neigh_hash_table *nht; - - nht = rcu_dereference_protected(tbl->nht, - lockdep_is_held(&tbl->lock)); - - for (i = 0; i < (1 << nht->hash_shift); i++) { - struct neighbour *n; - struct neighbour __rcu **np = &nht->hash_buckets[i]; - - while ((n = rcu_dereference_protected(*np, - lockdep_is_held(&tbl->lock))) != NULL) { - if (dev && n->dev != dev) { - np = &n->next; - continue; - } - rcu_assign_pointer(*np, - rcu_dereference_protected(n->next, - lockdep_is_held(&tbl->lock))); - write_lock(&n->lock); - neigh_del_timer(n); - n->dead = 1; - - if (atomic_read(&n->refcnt) != 1) { - /* The most unpleasant situation. - We must destroy neighbour entry, - but someone still uses it. - - The destroy will be delayed until - the last user releases us, but - we must kill timers etc. and move - it to safe state. - */ - __skb_queue_purge(&n->arp_queue); - n->arp_queue_len_bytes = 0; - n->output = neigh_blackhole; - if (n->nud_state & NUD_VALID) - n->nud_state = NUD_NOARP; - else - n->nud_state = NUD_NONE; - neigh_dbg(2, "neigh %p is stray\n", n); - } - write_unlock(&n->lock); - neigh_cleanup_and_release(n); - } - } -} - -void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev) -{ - write_lock_bh(&tbl->lock); - neigh_flush_dev(tbl, dev); - write_unlock_bh(&tbl->lock); -} -EXPORT_SYMBOL(neigh_changeaddr); - -int neigh_ifdown(struct neigh_table *tbl, struct net_device *dev) -{ - write_lock_bh(&tbl->lock); - neigh_flush_dev(tbl, dev); - pneigh_ifdown(tbl, dev); - write_unlock_bh(&tbl->lock); - - del_timer_sync(&tbl->proxy_timer); - pneigh_queue_purge(&tbl->proxy_queue); - return 0; -} -EXPORT_SYMBOL(neigh_ifdown); - -static struct neighbour *neigh_alloc(struct neigh_table *tbl, struct net_device *dev) -{ - struct neighbour *n = NULL; - unsigned long now = jiffies; - int entries; - - entries = atomic_inc_return(&tbl->entries) - 1; - if (entries >= tbl->gc_thresh3 || - (entries >= tbl->gc_thresh2 && - time_after(now, tbl->last_flush + 5 * HZ))) { - if (!neigh_forced_gc(tbl) && - entries >= tbl->gc_thresh3) { - net_info_ratelimited("%s: neighbor table overflow!\n", - tbl->id); - NEIGH_CACHE_STAT_INC(tbl, table_fulls); - goto out_entries; - } - } - - n = kzalloc(tbl->entry_size + dev->neigh_priv_len, GFP_ATOMIC); - if (!n) - goto out_entries; - - __skb_queue_head_init(&n->arp_queue); - rwlock_init(&n->lock); - seqlock_init(&n->ha_lock); - n->updated = n->used = now; - n->nud_state = NUD_NONE; - n->output = neigh_blackhole; - seqlock_init(&n->hh.hh_lock); - n->parms = neigh_parms_clone(&tbl->parms); - setup_timer(&n->timer, neigh_timer_handler, (unsigned long)n); - - NEIGH_CACHE_STAT_INC(tbl, allocs); - n->tbl = tbl; - atomic_set(&n->refcnt, 1); - n->dead = 1; -out: - return n; - -out_entries: - atomic_dec(&tbl->entries); - goto out; -} - -static void neigh_get_hash_rnd(u32 *x) -{ - get_random_bytes(x, sizeof(*x)); - *x |= 1; -} - -static struct neigh_hash_table *neigh_hash_alloc(unsigned int shift) -{ - size_t size = (1 << shift) * sizeof(struct neighbour *); - struct neigh_hash_table *ret; - struct neighbour __rcu **buckets; - int i; - - ret = kmalloc(sizeof(*ret), GFP_ATOMIC); - if (!ret) - return NULL; - if (size <= PAGE_SIZE) - buckets = kzalloc(size, GFP_ATOMIC); - else - buckets = (struct neighbour __rcu **) - __get_free_pages(GFP_ATOMIC | __GFP_ZERO, - get_order(size)); - if (!buckets) { - kfree(ret); - return NULL; - } - ret->hash_buckets = buckets; - ret->hash_shift = shift; - for (i = 0; i < NEIGH_NUM_HASH_RND; i++) - neigh_get_hash_rnd(&ret->hash_rnd[i]); - return ret; -} - -static void neigh_hash_free_rcu(struct rcu_head *head) -{ - struct neigh_hash_table *nht = container_of(head, - struct neigh_hash_table, - rcu); - size_t size = (1 << nht->hash_shift) * sizeof(struct neighbour *); - struct neighbour __rcu **buckets = nht->hash_buckets; - - if (size <= PAGE_SIZE) - kfree(buckets); - else - free_pages((unsigned long)buckets, get_order(size)); - kfree(nht); -} - -static struct neigh_hash_table *neigh_hash_grow(struct neigh_table *tbl, - unsigned long new_shift) -{ - unsigned int i, hash; - struct neigh_hash_table *new_nht, *old_nht; - - NEIGH_CACHE_STAT_INC(tbl, hash_grows); - - old_nht = rcu_dereference_protected(tbl->nht, - lockdep_is_held(&tbl->lock)); - new_nht = neigh_hash_alloc(new_shift); - if (!new_nht) - return old_nht; - - for (i = 0; i < (1 << old_nht->hash_shift); i++) { - struct neighbour *n, *next; - - for (n = rcu_dereference_protected(old_nht->hash_buckets[i], - lockdep_is_held(&tbl->lock)); - n != NULL; - n = next) { - hash = tbl->hash(n->primary_key, n->dev, - new_nht->hash_rnd); - - hash >>= (32 - new_nht->hash_shift); - next = rcu_dereference_protected(n->next, - lockdep_is_held(&tbl->lock)); - - rcu_assign_pointer(n->next, - rcu_dereference_protected( - new_nht->hash_buckets[hash], - lockdep_is_held(&tbl->lock))); - rcu_assign_pointer(new_nht->hash_buckets[hash], n); - } - } - - rcu_assign_pointer(tbl->nht, new_nht); - call_rcu(&old_nht->rcu, neigh_hash_free_rcu); - return new_nht; -} - -struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey, - struct net_device *dev) -{ - struct neighbour *n; - - NEIGH_CACHE_STAT_INC(tbl, lookups); - - rcu_read_lock_bh(); - n = __neigh_lookup_noref(tbl, pkey, dev); - if (n) { - if (!atomic_inc_not_zero(&n->refcnt)) - n = NULL; - NEIGH_CACHE_STAT_INC(tbl, hits); - } - - rcu_read_unlock_bh(); - return n; -} -EXPORT_SYMBOL(neigh_lookup); - -struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, struct net *net, - const void *pkey) -{ - struct neighbour *n; - int key_len = tbl->key_len; - u32 hash_val; - struct neigh_hash_table *nht; - - NEIGH_CACHE_STAT_INC(tbl, lookups); - - rcu_read_lock_bh(); - nht = rcu_dereference_bh(tbl->nht); - hash_val = tbl->hash(pkey, NULL, nht->hash_rnd) >> (32 - nht->hash_shift); - - for (n = rcu_dereference_bh(nht->hash_buckets[hash_val]); - n != NULL; - n = rcu_dereference_bh(n->next)) { - if (!memcmp(n->primary_key, pkey, key_len) && - net_eq(dev_net(n->dev), net)) { - if (!atomic_inc_not_zero(&n->refcnt)) - n = NULL; - NEIGH_CACHE_STAT_INC(tbl, hits); - break; - } - } - - rcu_read_unlock_bh(); - return n; -} -EXPORT_SYMBOL(neigh_lookup_nodev); - -struct neighbour *__neigh_create(struct neigh_table *tbl, const void *pkey, - struct net_device *dev, bool want_ref) -{ - u32 hash_val; - int key_len = tbl->key_len; - int error; - struct neighbour *n1, *rc, *n = neigh_alloc(tbl, dev); - struct neigh_hash_table *nht; - - if (!n) { - rc = ERR_PTR(-ENOBUFS); - goto out; - } - - memcpy(n->primary_key, pkey, key_len); - n->dev = dev; - dev_hold(dev); - - /* Protocol specific setup. */ - if (tbl->constructor && (error = tbl->constructor(n)) < 0) { - rc = ERR_PTR(error); - goto out_neigh_release; - } - - if (dev->netdev_ops->ndo_neigh_construct) { - error = dev->netdev_ops->ndo_neigh_construct(dev, n); - if (error < 0) { - rc = ERR_PTR(error); - goto out_neigh_release; - } - } - - /* Device specific setup. */ - if (n->parms->neigh_setup && - (error = n->parms->neigh_setup(n)) < 0) { - rc = ERR_PTR(error); - goto out_neigh_release; - } - - n->confirmed = jiffies - (NEIGH_VAR(n->parms, BASE_REACHABLE_TIME) << 1); - - write_lock_bh(&tbl->lock); - nht = rcu_dereference_protected(tbl->nht, - lockdep_is_held(&tbl->lock)); - - if (atomic_read(&tbl->entries) > (1 << nht->hash_shift)) - nht = neigh_hash_grow(tbl, nht->hash_shift + 1); - - hash_val = tbl->hash(pkey, dev, nht->hash_rnd) >> (32 - nht->hash_shift); - - if (n->parms->dead) { - rc = ERR_PTR(-EINVAL); - goto out_tbl_unlock; - } - - for (n1 = rcu_dereference_protected(nht->hash_buckets[hash_val], - lockdep_is_held(&tbl->lock)); - n1 != NULL; - n1 = rcu_dereference_protected(n1->next, - lockdep_is_held(&tbl->lock))) { - if (dev == n1->dev && !memcmp(n1->primary_key, pkey, key_len)) { - if (want_ref) - neigh_hold(n1); - rc = n1; - goto out_tbl_unlock; - } - } - - n->dead = 0; - if (want_ref) - neigh_hold(n); - rcu_assign_pointer(n->next, - rcu_dereference_protected(nht->hash_buckets[hash_val], - lockdep_is_held(&tbl->lock))); - rcu_assign_pointer(nht->hash_buckets[hash_val], n); - write_unlock_bh(&tbl->lock); - neigh_dbg(2, "neigh %p is created\n", n); - rc = n; -out: - return rc; -out_tbl_unlock: - write_unlock_bh(&tbl->lock); -out_neigh_release: - neigh_release(n); - goto out; -} -EXPORT_SYMBOL(__neigh_create); - -static u32 pneigh_hash(const void *pkey, int key_len) -{ - u32 hash_val = *(u32 *)(pkey + key_len - 4); - hash_val ^= (hash_val >> 16); - hash_val ^= hash_val >> 8; - hash_val ^= hash_val >> 4; - hash_val &= PNEIGH_HASHMASK; - return hash_val; -} - -static struct pneigh_entry *__pneigh_lookup_1(struct pneigh_entry *n, - struct net *net, - const void *pkey, - int key_len, - struct net_device *dev) -{ - while (n) { - if (!memcmp(n->key, pkey, key_len) && - net_eq(pneigh_net(n), net) && - (n->dev == dev || !n->dev)) - return n; - n = n->next; - } - return NULL; -} - -struct pneigh_entry *__pneigh_lookup(struct neigh_table *tbl, - struct net *net, const void *pkey, struct net_device *dev) -{ - int key_len = tbl->key_len; - u32 hash_val = pneigh_hash(pkey, key_len); - - return __pneigh_lookup_1(tbl->phash_buckets[hash_val], - net, pkey, key_len, dev); -} -EXPORT_SYMBOL_GPL(__pneigh_lookup); - -struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, - struct net *net, const void *pkey, - struct net_device *dev, int creat) -{ - struct pneigh_entry *n; - int key_len = tbl->key_len; - u32 hash_val = pneigh_hash(pkey, key_len); - - read_lock_bh(&tbl->lock); - n = __pneigh_lookup_1(tbl->phash_buckets[hash_val], - net, pkey, key_len, dev); - read_unlock_bh(&tbl->lock); - - if (n || !creat) - goto out; - - ASSERT_RTNL(); - - n = kmalloc(sizeof(*n) + key_len, GFP_KERNEL); - if (!n) - goto out; - - write_pnet(&n->net, net); - memcpy(n->key, pkey, key_len); - n->dev = dev; - if (dev) - dev_hold(dev); - - if (tbl->pconstructor && tbl->pconstructor(n)) { - if (dev) - dev_put(dev); - kfree(n); - n = NULL; - goto out; - } - - write_lock_bh(&tbl->lock); - n->next = tbl->phash_buckets[hash_val]; - tbl->phash_buckets[hash_val] = n; - write_unlock_bh(&tbl->lock); -out: - return n; -} -EXPORT_SYMBOL(pneigh_lookup); - - -int pneigh_delete(struct neigh_table *tbl, struct net *net, const void *pkey, - struct net_device *dev) -{ - struct pneigh_entry *n, **np; - int key_len = tbl->key_len; - u32 hash_val = pneigh_hash(pkey, key_len); - - write_lock_bh(&tbl->lock); - for (np = &tbl->phash_buckets[hash_val]; (n = *np) != NULL; - np = &n->next) { - if (!memcmp(n->key, pkey, key_len) && n->dev == dev && - net_eq(pneigh_net(n), net)) { - *np = n->next; - write_unlock_bh(&tbl->lock); - if (tbl->pdestructor) - tbl->pdestructor(n); - if (n->dev) - dev_put(n->dev); - kfree(n); - return 0; - } - } - write_unlock_bh(&tbl->lock); - return -ENOENT; -} - -static int pneigh_ifdown(struct neigh_table *tbl, struct net_device *dev) -{ - struct pneigh_entry *n, **np; - u32 h; - - for (h = 0; h <= PNEIGH_HASHMASK; h++) { - np = &tbl->phash_buckets[h]; - while ((n = *np) != NULL) { - if (!dev || n->dev == dev) { - *np = n->next; - if (tbl->pdestructor) - tbl->pdestructor(n); - if (n->dev) - dev_put(n->dev); - kfree(n); - continue; - } - np = &n->next; - } - } - return -ENOENT; -} - -static void neigh_parms_destroy(struct neigh_parms *parms); - -static inline void neigh_parms_put(struct neigh_parms *parms) -{ - if (atomic_dec_and_test(&parms->refcnt)) - neigh_parms_destroy(parms); -} - -/* - * neighbour must already be out of the table; - * - */ -void neigh_destroy(struct neighbour *neigh) -{ - struct net_device *dev = neigh->dev; - - NEIGH_CACHE_STAT_INC(neigh->tbl, destroys); - - if (!neigh->dead) { - pr_warn("Destroying alive neighbour %p\n", neigh); - dump_stack(); - return; - } - - if (neigh_del_timer(neigh)) - pr_warn("Impossible event\n"); - - write_lock_bh(&neigh->lock); - __skb_queue_purge(&neigh->arp_queue); - write_unlock_bh(&neigh->lock); - neigh->arp_queue_len_bytes = 0; - - if (dev->netdev_ops->ndo_neigh_destroy) - dev->netdev_ops->ndo_neigh_destroy(dev, neigh); - - dev_put(dev); - neigh_parms_put(neigh->parms); - - neigh_dbg(2, "neigh %p is destroyed\n", neigh); - - atomic_dec(&neigh->tbl->entries); - kfree_rcu(neigh, rcu); -} -EXPORT_SYMBOL(neigh_destroy); - -/* Neighbour state is suspicious; - disable fast path. - - Called with write_locked neigh. - */ -static void neigh_suspect(struct neighbour *neigh) -{ - neigh_dbg(2, "neigh %p is suspected\n", neigh); - - neigh->output = neigh->ops->output; -} - -/* Neighbour state is OK; - enable fast path. - - Called with write_locked neigh. - */ -static void neigh_connect(struct neighbour *neigh) -{ - neigh_dbg(2, "neigh %p is connected\n", neigh); - - neigh->output = neigh->ops->connected_output; -} - -static void neigh_periodic_work(struct work_struct *work) -{ - struct neigh_table *tbl = container_of(work, struct neigh_table, gc_work.work); - struct neighbour *n; - struct neighbour __rcu **np; - unsigned int i; - struct neigh_hash_table *nht; - - NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs); - - write_lock_bh(&tbl->lock); - nht = rcu_dereference_protected(tbl->nht, - lockdep_is_held(&tbl->lock)); - - /* - * periodically recompute ReachableTime from random function - */ - - if (time_after(jiffies, tbl->last_rand + 300 * HZ)) { - struct neigh_parms *p; - tbl->last_rand = jiffies; - list_for_each_entry(p, &tbl->parms_list, list) - p->reachable_time = - neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); - } - - if (atomic_read(&tbl->entries) < tbl->gc_thresh1) - goto out; - - for (i = 0 ; i < (1 << nht->hash_shift); i++) { - np = &nht->hash_buckets[i]; - - while ((n = rcu_dereference_protected(*np, - lockdep_is_held(&tbl->lock))) != NULL) { - unsigned int state; - - write_lock(&n->lock); - - state = n->nud_state; - if (state & (NUD_PERMANENT | NUD_IN_TIMER)) { - write_unlock(&n->lock); - goto next_elt; - } - - if (time_before(n->used, n->confirmed)) - n->used = n->confirmed; - - if (atomic_read(&n->refcnt) == 1 && - (state == NUD_FAILED || - time_after(jiffies, n->used + NEIGH_VAR(n->parms, GC_STALETIME)))) { - *np = n->next; - n->dead = 1; - write_unlock(&n->lock); - neigh_cleanup_and_release(n); - continue; - } - write_unlock(&n->lock); - -next_elt: - np = &n->next; - } - /* - * It's fine to release lock here, even if hash table - * grows while we are preempted. - */ - write_unlock_bh(&tbl->lock); - cond_resched(); - write_lock_bh(&tbl->lock); - nht = rcu_dereference_protected(tbl->nht, - lockdep_is_held(&tbl->lock)); - } -out: - /* Cycle through all hash buckets every BASE_REACHABLE_TIME/2 ticks. - * ARP entry timeouts range from 1/2 BASE_REACHABLE_TIME to 3/2 - * BASE_REACHABLE_TIME. - */ - queue_delayed_work(system_power_efficient_wq, &tbl->gc_work, - NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME) >> 1); - write_unlock_bh(&tbl->lock); -} - -static __inline__ int neigh_max_probes(struct neighbour *n) -{ - struct neigh_parms *p = n->parms; - return NEIGH_VAR(p, UCAST_PROBES) + NEIGH_VAR(p, APP_PROBES) + - (n->nud_state & NUD_PROBE ? NEIGH_VAR(p, MCAST_REPROBES) : - NEIGH_VAR(p, MCAST_PROBES)); -} - -static void neigh_invalidate(struct neighbour *neigh) - __releases(neigh->lock) - __acquires(neigh->lock) -{ - struct sk_buff *skb; - - NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed); - neigh_dbg(2, "neigh %p is failed\n", neigh); - neigh->updated = jiffies; - - /* It is very thin place. report_unreachable is very complicated - routine. Particularly, it can hit the same neighbour entry! - - So that, we try to be accurate and avoid dead loop. --ANK - */ - while (neigh->nud_state == NUD_FAILED && - (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) { - write_unlock(&neigh->lock); - neigh->ops->error_report(neigh, skb); - write_lock(&neigh->lock); - } - __skb_queue_purge(&neigh->arp_queue); - neigh->arp_queue_len_bytes = 0; -} - -static void neigh_probe(struct neighbour *neigh) - __releases(neigh->lock) -{ - struct sk_buff *skb = skb_peek_tail(&neigh->arp_queue); - /* keep skb alive even if arp_queue overflows */ - if (skb) - skb = skb_clone(skb, GFP_ATOMIC); - write_unlock(&neigh->lock); - neigh->ops->solicit(neigh, skb); - atomic_inc(&neigh->probes); - kfree_skb(skb); -} - -/* Called when a timer expires for a neighbour entry. */ - -static void neigh_timer_handler(unsigned long arg) -{ - unsigned long now, next; - struct neighbour *neigh = (struct neighbour *)arg; - unsigned int state; - int notify = 0; - - write_lock(&neigh->lock); - - state = neigh->nud_state; - now = jiffies; - next = now + HZ; - - if (!(state & NUD_IN_TIMER)) - goto out; - - if (state & NUD_REACHABLE) { - if (time_before_eq(now, - neigh->confirmed + neigh->parms->reachable_time)) { - neigh_dbg(2, "neigh %p is still alive\n", neigh); - next = neigh->confirmed + neigh->parms->reachable_time; - } else if (time_before_eq(now, - neigh->used + - NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) { - neigh_dbg(2, "neigh %p is delayed\n", neigh); - neigh->nud_state = NUD_DELAY; - neigh->updated = jiffies; - neigh_suspect(neigh); - next = now + NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME); - } else { - neigh_dbg(2, "neigh %p is suspected\n", neigh); - neigh->nud_state = NUD_STALE; - neigh->updated = jiffies; - neigh_suspect(neigh); - notify = 1; - } - } else if (state & NUD_DELAY) { - if (time_before_eq(now, - neigh->confirmed + - NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME))) { - neigh_dbg(2, "neigh %p is now reachable\n", neigh); - neigh->nud_state = NUD_REACHABLE; - neigh->updated = jiffies; - neigh_connect(neigh); - notify = 1; - next = neigh->confirmed + neigh->parms->reachable_time; - } else { - neigh_dbg(2, "neigh %p is probed\n", neigh); - neigh->nud_state = NUD_PROBE; - neigh->updated = jiffies; - atomic_set(&neigh->probes, 0); - notify = 1; - next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME); - } - } else { - /* NUD_PROBE|NUD_INCOMPLETE */ - next = now + NEIGH_VAR(neigh->parms, RETRANS_TIME); - } - - if ((neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) && - atomic_read(&neigh->probes) >= neigh_max_probes(neigh)) { - neigh->nud_state = NUD_FAILED; - notify = 1; - neigh_invalidate(neigh); - goto out; - } - - if (neigh->nud_state & NUD_IN_TIMER) { - if (time_before(next, jiffies + HZ/2)) - next = jiffies + HZ/2; - if (!mod_timer(&neigh->timer, next)) - neigh_hold(neigh); - } - if (neigh->nud_state & (NUD_INCOMPLETE | NUD_PROBE)) { - neigh_probe(neigh); - } else { -out: - write_unlock(&neigh->lock); - } - - if (notify) - neigh_update_notify(neigh); - - neigh_release(neigh); -} - -int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb) -{ - int rc; - bool immediate_probe = false; - - write_lock_bh(&neigh->lock); - - rc = 0; - if (neigh->nud_state & (NUD_CONNECTED | NUD_DELAY | NUD_PROBE)) - goto out_unlock_bh; - if (neigh->dead) - goto out_dead; - - if (!(neigh->nud_state & (NUD_STALE | NUD_INCOMPLETE))) { - if (NEIGH_VAR(neigh->parms, MCAST_PROBES) + - NEIGH_VAR(neigh->parms, APP_PROBES)) { - unsigned long next, now = jiffies; - - atomic_set(&neigh->probes, - NEIGH_VAR(neigh->parms, UCAST_PROBES)); - neigh->nud_state = NUD_INCOMPLETE; - neigh->updated = now; - next = now + max(NEIGH_VAR(neigh->parms, RETRANS_TIME), - HZ/2); - neigh_add_timer(neigh, next); - immediate_probe = true; - } else { - neigh->nud_state = NUD_FAILED; - neigh->updated = jiffies; - write_unlock_bh(&neigh->lock); - - kfree_skb(skb); - return 1; - } - } else if (neigh->nud_state & NUD_STALE) { - neigh_dbg(2, "neigh %p is delayed\n", neigh); - neigh->nud_state = NUD_DELAY; - neigh->updated = jiffies; - neigh_add_timer(neigh, jiffies + - NEIGH_VAR(neigh->parms, DELAY_PROBE_TIME)); - } - - if (neigh->nud_state == NUD_INCOMPLETE) { - if (skb) { - while (neigh->arp_queue_len_bytes + skb->truesize > - NEIGH_VAR(neigh->parms, QUEUE_LEN_BYTES)) { - struct sk_buff *buff; - - buff = __skb_dequeue(&neigh->arp_queue); - if (!buff) - break; - neigh->arp_queue_len_bytes -= buff->truesize; - kfree_skb(buff); - NEIGH_CACHE_STAT_INC(neigh->tbl, unres_discards); - } - skb_dst_force(skb); - __skb_queue_tail(&neigh->arp_queue, skb); - neigh->arp_queue_len_bytes += skb->truesize; - } - rc = 1; - } -out_unlock_bh: - if (immediate_probe) - neigh_probe(neigh); - else - write_unlock(&neigh->lock); - local_bh_enable(); - return rc; - -out_dead: - if (neigh->nud_state & NUD_STALE) - goto out_unlock_bh; - write_unlock_bh(&neigh->lock); - kfree_skb(skb); - return 1; -} -EXPORT_SYMBOL(__neigh_event_send); - -static void neigh_update_hhs(struct neighbour *neigh) -{ - struct hh_cache *hh; - void (*update)(struct hh_cache*, const struct net_device*, const unsigned char *) - = NULL; - - if (neigh->dev->header_ops) - update = neigh->dev->header_ops->cache_update; - - if (update) { - hh = &neigh->hh; - if (hh->hh_len) { - write_seqlock_bh(&hh->hh_lock); - update(hh, neigh->dev, neigh->ha); - write_sequnlock_bh(&hh->hh_lock); - } - } -} - - - -/* Generic update routine. - -- lladdr is new lladdr or NULL, if it is not supplied. - -- new is new state. - -- flags - NEIGH_UPDATE_F_OVERRIDE allows to override existing lladdr, - if it is different. - NEIGH_UPDATE_F_WEAK_OVERRIDE will suspect existing "connected" - lladdr instead of overriding it - if it is different. - NEIGH_UPDATE_F_ADMIN means that the change is administrative. - - NEIGH_UPDATE_F_OVERRIDE_ISROUTER allows to override existing - NTF_ROUTER flag. - NEIGH_UPDATE_F_ISROUTER indicates if the neighbour is known as - a router. - - Caller MUST hold reference count on the entry. - */ - -int neigh_update(struct neighbour *neigh, const u8 *lladdr, u8 new, - u32 flags) -{ - u8 old; - int err; - int notify = 0; - struct net_device *dev; - int update_isrouter = 0; - - write_lock_bh(&neigh->lock); - - dev = neigh->dev; - old = neigh->nud_state; - err = -EPERM; - - if (!(flags & NEIGH_UPDATE_F_ADMIN) && - (old & (NUD_NOARP | NUD_PERMANENT))) - goto out; - if (neigh->dead) - goto out; - - if (!(new & NUD_VALID)) { - neigh_del_timer(neigh); - if (old & NUD_CONNECTED) - neigh_suspect(neigh); - neigh->nud_state = new; - err = 0; - notify = old & NUD_VALID; - if ((old & (NUD_INCOMPLETE | NUD_PROBE)) && - (new & NUD_FAILED)) { - neigh_invalidate(neigh); - notify = 1; - } - goto out; - } - - /* Compare new lladdr with cached one */ - if (!dev->addr_len) { - /* First case: device needs no address. */ - lladdr = neigh->ha; - } else if (lladdr) { - /* The second case: if something is already cached - and a new address is proposed: - - compare new & old - - if they are different, check override flag - */ - if ((old & NUD_VALID) && - !memcmp(lladdr, neigh->ha, dev->addr_len)) - lladdr = neigh->ha; - } else { - /* No address is supplied; if we know something, - use it, otherwise discard the request. - */ - err = -EINVAL; - if (!(old & NUD_VALID)) - goto out; - lladdr = neigh->ha; - } - - if (new & NUD_CONNECTED) - neigh->confirmed = jiffies; - neigh->updated = jiffies; - - /* If entry was valid and address is not changed, - do not change entry state, if new one is STALE. - */ - err = 0; - update_isrouter = flags & NEIGH_UPDATE_F_OVERRIDE_ISROUTER; - if (old & NUD_VALID) { - if (lladdr != neigh->ha && !(flags & NEIGH_UPDATE_F_OVERRIDE)) { - update_isrouter = 0; - if ((flags & NEIGH_UPDATE_F_WEAK_OVERRIDE) && - (old & NUD_CONNECTED)) { - lladdr = neigh->ha; - new = NUD_STALE; - } else - goto out; - } else { - if (lladdr == neigh->ha && new == NUD_STALE && - !(flags & NEIGH_UPDATE_F_ADMIN)) - new = old; - } - } - - if (new != old) { - neigh_del_timer(neigh); - if (new & NUD_PROBE) - atomic_set(&neigh->probes, 0); - if (new & NUD_IN_TIMER) - neigh_add_timer(neigh, (jiffies + - ((new & NUD_REACHABLE) ? - neigh->parms->reachable_time : - 0))); - neigh->nud_state = new; - notify = 1; - } - - if (lladdr != neigh->ha) { - write_seqlock(&neigh->ha_lock); - memcpy(&neigh->ha, lladdr, dev->addr_len); - write_sequnlock(&neigh->ha_lock); - neigh_update_hhs(neigh); - if (!(new & NUD_CONNECTED)) - neigh->confirmed = jiffies - - (NEIGH_VAR(neigh->parms, BASE_REACHABLE_TIME) << 1); - notify = 1; - } - if (new == old) - goto out; - if (new & NUD_CONNECTED) - neigh_connect(neigh); - else - neigh_suspect(neigh); - if (!(old & NUD_VALID)) { - struct sk_buff *skb; - - /* Again: avoid dead loop if something went wrong */ - - while (neigh->nud_state & NUD_VALID && - (skb = __skb_dequeue(&neigh->arp_queue)) != NULL) { - struct dst_entry *dst = skb_dst(skb); - struct neighbour *n2, *n1 = neigh; - write_unlock_bh(&neigh->lock); - - rcu_read_lock(); - - /* Why not just use 'neigh' as-is? The problem is that - * things such as shaper, eql, and sch_teql can end up - * using alternative, different, neigh objects to output - * the packet in the output path. So what we need to do - * here is re-lookup the top-level neigh in the path so - * we can reinject the packet there. - */ - n2 = NULL; - if (dst) { - n2 = dst_neigh_lookup_skb(dst, skb); - if (n2) - n1 = n2; - } - n1->output(n1, skb); - if (n2) - neigh_release(n2); - rcu_read_unlock(); - - write_lock_bh(&neigh->lock); - } - __skb_queue_purge(&neigh->arp_queue); - neigh->arp_queue_len_bytes = 0; - } -out: - if (update_isrouter) { - neigh->flags = (flags & NEIGH_UPDATE_F_ISROUTER) ? - (neigh->flags | NTF_ROUTER) : - (neigh->flags & ~NTF_ROUTER); - } - write_unlock_bh(&neigh->lock); - - if (notify) - neigh_update_notify(neigh); - - return err; -} -EXPORT_SYMBOL(neigh_update); - -/* Update the neigh to listen temporarily for probe responses, even if it is - * in a NUD_FAILED state. The caller has to hold neigh->lock for writing. - */ -void __neigh_set_probe_once(struct neighbour *neigh) -{ - if (neigh->dead) - return; - neigh->updated = jiffies; - if (!(neigh->nud_state & NUD_FAILED)) - return; - neigh->nud_state = NUD_INCOMPLETE; - atomic_set(&neigh->probes, neigh_max_probes(neigh)); - neigh_add_timer(neigh, - jiffies + NEIGH_VAR(neigh->parms, RETRANS_TIME)); -} -EXPORT_SYMBOL(__neigh_set_probe_once); - -struct neighbour *neigh_event_ns(struct neigh_table *tbl, - u8 *lladdr, void *saddr, - struct net_device *dev) -{ - struct neighbour *neigh = __neigh_lookup(tbl, saddr, dev, - lladdr || !dev->addr_len); - if (neigh) - neigh_update(neigh, lladdr, NUD_STALE, - NEIGH_UPDATE_F_OVERRIDE); - return neigh; -} -EXPORT_SYMBOL(neigh_event_ns); - -/* called with read_lock_bh(&n->lock); */ -static void neigh_hh_init(struct neighbour *n) -{ - struct net_device *dev = n->dev; - __be16 prot = n->tbl->protocol; - struct hh_cache *hh = &n->hh; - - write_lock_bh(&n->lock); - - /* Only one thread can come in here and initialize the - * hh_cache entry. - */ - if (!hh->hh_len) - dev->header_ops->cache(n, hh, prot); - - write_unlock_bh(&n->lock); -} - -/* Slow and careful. */ - -int neigh_resolve_output(struct neighbour *neigh, struct sk_buff *skb) -{ - int rc = 0; - - if (!neigh_event_send(neigh, skb)) { - int err; - struct net_device *dev = neigh->dev; - unsigned int seq; - - if (dev->header_ops->cache && !neigh->hh.hh_len) - neigh_hh_init(neigh); - - do { - __skb_pull(skb, skb_network_offset(skb)); - seq = read_seqbegin(&neigh->ha_lock); - err = dev_hard_header(skb, dev, ntohs(skb->protocol), - neigh->ha, NULL, skb->len); - } while (read_seqretry(&neigh->ha_lock, seq)); - - if (err >= 0) - rc = dev_queue_xmit(skb); - else - goto out_kfree_skb; - } -out: - return rc; -out_kfree_skb: - rc = -EINVAL; - kfree_skb(skb); - goto out; -} -EXPORT_SYMBOL(neigh_resolve_output); - -/* As fast as possible without hh cache */ - -int neigh_connected_output(struct neighbour *neigh, struct sk_buff *skb) -{ - struct net_device *dev = neigh->dev; - unsigned int seq; - int err; - - do { - __skb_pull(skb, skb_network_offset(skb)); - seq = read_seqbegin(&neigh->ha_lock); - err = dev_hard_header(skb, dev, ntohs(skb->protocol), - neigh->ha, NULL, skb->len); - } while (read_seqretry(&neigh->ha_lock, seq)); - - if (err >= 0) - err = dev_queue_xmit(skb); - else { - err = -EINVAL; - kfree_skb(skb); - } - return err; -} -EXPORT_SYMBOL(neigh_connected_output); - -int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb) -{ - return dev_queue_xmit(skb); -} -EXPORT_SYMBOL(neigh_direct_output); - -static void neigh_proxy_process(unsigned long arg) -{ - struct neigh_table *tbl = (struct neigh_table *)arg; - long sched_next = 0; - unsigned long now = jiffies; - struct sk_buff *skb, *n; - - spin_lock(&tbl->proxy_queue.lock); - - skb_queue_walk_safe(&tbl->proxy_queue, skb, n) { - long tdif = NEIGH_CB(skb)->sched_next - now; - - if (tdif <= 0) { - struct net_device *dev = skb->dev; - - __skb_unlink(skb, &tbl->proxy_queue); - if (tbl->proxy_redo && netif_running(dev)) { - rcu_read_lock(); - tbl->proxy_redo(skb); - rcu_read_unlock(); - } else { - kfree_skb(skb); - } - - dev_put(dev); - } else if (!sched_next || tdif < sched_next) - sched_next = tdif; - } - del_timer(&tbl->proxy_timer); - if (sched_next) - mod_timer(&tbl->proxy_timer, jiffies + sched_next); - spin_unlock(&tbl->proxy_queue.lock); -} - -void pneigh_enqueue(struct neigh_table *tbl, struct neigh_parms *p, - struct sk_buff *skb) -{ - unsigned long now = jiffies; - - unsigned long sched_next = now + (prandom_u32() % - NEIGH_VAR(p, PROXY_DELAY)); - - if (tbl->proxy_queue.qlen > NEIGH_VAR(p, PROXY_QLEN)) { - kfree_skb(skb); - return; - } - - NEIGH_CB(skb)->sched_next = sched_next; - NEIGH_CB(skb)->flags |= LOCALLY_ENQUEUED; - - spin_lock(&tbl->proxy_queue.lock); - if (del_timer(&tbl->proxy_timer)) { - if (time_before(tbl->proxy_timer.expires, sched_next)) - sched_next = tbl->proxy_timer.expires; - } - skb_dst_drop(skb); - dev_hold(skb->dev); - __skb_queue_tail(&tbl->proxy_queue, skb); - mod_timer(&tbl->proxy_timer, sched_next); - spin_unlock(&tbl->proxy_queue.lock); -} -EXPORT_SYMBOL(pneigh_enqueue); - -static inline struct neigh_parms *lookup_neigh_parms(struct neigh_table *tbl, - struct net *net, int ifindex) -{ - struct neigh_parms *p; - - list_for_each_entry(p, &tbl->parms_list, list) { - if ((p->dev && p->dev->ifindex == ifindex && net_eq(neigh_parms_net(p), net)) || - (!p->dev && !ifindex && net_eq(net, &init_net))) - return p; - } - - return NULL; -} - -struct neigh_parms *neigh_parms_alloc(struct net_device *dev, - struct neigh_table *tbl) -{ - struct neigh_parms *p; - struct net *net = dev_net(dev); - const struct net_device_ops *ops = dev->netdev_ops; - - p = kmemdup(&tbl->parms, sizeof(*p), GFP_KERNEL); - if (p) { - p->tbl = tbl; - atomic_set(&p->refcnt, 1); - p->reachable_time = - neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); - dev_hold(dev); - p->dev = dev; - write_pnet(&p->net, net); - p->sysctl_table = NULL; - - if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) { - dev_put(dev); - kfree(p); - return NULL; - } - - write_lock_bh(&tbl->lock); - list_add(&p->list, &tbl->parms.list); - write_unlock_bh(&tbl->lock); - - neigh_parms_data_state_cleanall(p); - } - return p; -} -EXPORT_SYMBOL(neigh_parms_alloc); - -static void neigh_rcu_free_parms(struct rcu_head *head) -{ - struct neigh_parms *parms = - container_of(head, struct neigh_parms, rcu_head); - - neigh_parms_put(parms); -} - -void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *parms) -{ - if (!parms || parms == &tbl->parms) - return; - write_lock_bh(&tbl->lock); - list_del(&parms->list); - parms->dead = 1; - write_unlock_bh(&tbl->lock); - if (parms->dev) - dev_put(parms->dev); - call_rcu(&parms->rcu_head, neigh_rcu_free_parms); -} -EXPORT_SYMBOL(neigh_parms_release); - -static void neigh_parms_destroy(struct neigh_parms *parms) -{ - kfree(parms); -} - -static struct lock_class_key neigh_table_proxy_queue_class; - -static struct neigh_table *neigh_tables[NEIGH_NR_TABLES] __read_mostly; - -void neigh_table_init(int index, struct neigh_table *tbl) -{ - unsigned long now = jiffies; - unsigned long phsize; - - INIT_LIST_HEAD(&tbl->parms_list); - list_add(&tbl->parms.list, &tbl->parms_list); - write_pnet(&tbl->parms.net, &init_net); - atomic_set(&tbl->parms.refcnt, 1); - tbl->parms.reachable_time = - neigh_rand_reach_time(NEIGH_VAR(&tbl->parms, BASE_REACHABLE_TIME)); - - tbl->stats = alloc_percpu(struct neigh_statistics); - if (!tbl->stats) - panic("cannot create neighbour cache statistics"); - -#ifdef CONFIG_PROC_FS - if (!proc_create_data(tbl->id, 0, init_net.proc_net_stat, - &neigh_stat_seq_fops, tbl)) - panic("cannot create neighbour proc dir entry"); -#endif - - RCU_INIT_POINTER(tbl->nht, neigh_hash_alloc(3)); - - phsize = (PNEIGH_HASHMASK + 1) * sizeof(struct pneigh_entry *); - tbl->phash_buckets = kzalloc(phsize, GFP_KERNEL); - - if (!tbl->nht || !tbl->phash_buckets) - panic("cannot allocate neighbour cache hashes"); - - if (!tbl->entry_size) - tbl->entry_size = ALIGN(offsetof(struct neighbour, primary_key) + - tbl->key_len, NEIGH_PRIV_ALIGN); - else - WARN_ON(tbl->entry_size % NEIGH_PRIV_ALIGN); - - rwlock_init(&tbl->lock); - INIT_DEFERRABLE_WORK(&tbl->gc_work, neigh_periodic_work); - queue_delayed_work(system_power_efficient_wq, &tbl->gc_work, - tbl->parms.reachable_time); - setup_timer(&tbl->proxy_timer, neigh_proxy_process, (unsigned long)tbl); - skb_queue_head_init_class(&tbl->proxy_queue, - &neigh_table_proxy_queue_class); - - tbl->last_flush = now; - tbl->last_rand = now + tbl->parms.reachable_time * 20; - - neigh_tables[index] = tbl; -} -EXPORT_SYMBOL(neigh_table_init); - -int neigh_table_clear(int index, struct neigh_table *tbl) -{ - neigh_tables[index] = NULL; - /* It is not clean... Fix it to unload IPv6 module safely */ - cancel_delayed_work_sync(&tbl->gc_work); - del_timer_sync(&tbl->proxy_timer); - pneigh_queue_purge(&tbl->proxy_queue); - neigh_ifdown(tbl, NULL); - if (atomic_read(&tbl->entries)) - pr_crit("neighbour leakage\n"); - - call_rcu(&rcu_dereference_protected(tbl->nht, 1)->rcu, - neigh_hash_free_rcu); - tbl->nht = NULL; - - kfree(tbl->phash_buckets); - tbl->phash_buckets = NULL; - - remove_proc_entry(tbl->id, init_net.proc_net_stat); - - free_percpu(tbl->stats); - tbl->stats = NULL; - - return 0; -} -EXPORT_SYMBOL(neigh_table_clear); - -static struct neigh_table *neigh_find_table(int family) -{ - struct neigh_table *tbl = NULL; - - switch (family) { - case AF_INET: - tbl = neigh_tables[NEIGH_ARP_TABLE]; - break; - case AF_INET6: - tbl = neigh_tables[NEIGH_ND_TABLE]; - break; - case AF_DECnet: - tbl = neigh_tables[NEIGH_DN_TABLE]; - break; - } - - return tbl; -} - -static int neigh_delete(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct ndmsg *ndm; - struct nlattr *dst_attr; - struct neigh_table *tbl; - struct neighbour *neigh; - struct net_device *dev = NULL; - int err = -EINVAL; - - ASSERT_RTNL(); - if (nlmsg_len(nlh) < sizeof(*ndm)) - goto out; - - dst_attr = nlmsg_find_attr(nlh, sizeof(*ndm), NDA_DST); - if (dst_attr == NULL) - goto out; - - ndm = nlmsg_data(nlh); - if (ndm->ndm_ifindex) { - dev = __dev_get_by_index(net, ndm->ndm_ifindex); - if (dev == NULL) { - err = -ENODEV; - goto out; - } - } - - tbl = neigh_find_table(ndm->ndm_family); - if (tbl == NULL) - return -EAFNOSUPPORT; - - if (nla_len(dst_attr) < tbl->key_len) - goto out; - - if (ndm->ndm_flags & NTF_PROXY) { - err = pneigh_delete(tbl, net, nla_data(dst_attr), dev); - goto out; - } - - if (dev == NULL) - goto out; - - neigh = neigh_lookup(tbl, nla_data(dst_attr), dev); - if (neigh == NULL) { - err = -ENOENT; - goto out; - } - - err = neigh_update(neigh, NULL, NUD_FAILED, - NEIGH_UPDATE_F_OVERRIDE | - NEIGH_UPDATE_F_ADMIN); - neigh_release(neigh); - -out: - return err; -} - -static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - int flags = NEIGH_UPDATE_F_ADMIN | NEIGH_UPDATE_F_OVERRIDE; - struct net *net = sock_net(skb->sk); - struct ndmsg *ndm; - struct nlattr *tb[NDA_MAX+1]; - struct neigh_table *tbl; - struct net_device *dev = NULL; - struct neighbour *neigh; - void *dst, *lladdr; - int err; - - ASSERT_RTNL(); - err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL); - if (err < 0) - goto out; - - err = -EINVAL; - if (tb[NDA_DST] == NULL) - goto out; - - ndm = nlmsg_data(nlh); - if (ndm->ndm_ifindex) { - dev = __dev_get_by_index(net, ndm->ndm_ifindex); - if (dev == NULL) { - err = -ENODEV; - goto out; - } - - if (tb[NDA_LLADDR] && nla_len(tb[NDA_LLADDR]) < dev->addr_len) - goto out; - } - - tbl = neigh_find_table(ndm->ndm_family); - if (tbl == NULL) - return -EAFNOSUPPORT; - - if (nla_len(tb[NDA_DST]) < tbl->key_len) - goto out; - dst = nla_data(tb[NDA_DST]); - lladdr = tb[NDA_LLADDR] ? nla_data(tb[NDA_LLADDR]) : NULL; - - if (ndm->ndm_flags & NTF_PROXY) { - struct pneigh_entry *pn; - - err = -ENOBUFS; - pn = pneigh_lookup(tbl, net, dst, dev, 1); - if (pn) { - pn->flags = ndm->ndm_flags; - err = 0; - } - goto out; - } - - if (dev == NULL) - goto out; - - neigh = neigh_lookup(tbl, dst, dev); - if (neigh == NULL) { - if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { - err = -ENOENT; - goto out; - } - - neigh = __neigh_lookup_errno(tbl, dst, dev); - if (IS_ERR(neigh)) { - err = PTR_ERR(neigh); - goto out; - } - } else { - if (nlh->nlmsg_flags & NLM_F_EXCL) { - err = -EEXIST; - neigh_release(neigh); - goto out; - } - - if (!(nlh->nlmsg_flags & NLM_F_REPLACE)) - flags &= ~NEIGH_UPDATE_F_OVERRIDE; - } - - if (ndm->ndm_flags & NTF_USE) { - neigh_event_send(neigh, NULL); - err = 0; - } else - err = neigh_update(neigh, lladdr, ndm->ndm_state, flags); - neigh_release(neigh); - -out: - return err; -} - -static int neightbl_fill_parms(struct sk_buff *skb, struct neigh_parms *parms) -{ - struct nlattr *nest; - - nest = nla_nest_start(skb, NDTA_PARMS); - if (nest == NULL) - return -ENOBUFS; - - if ((parms->dev && - nla_put_u32(skb, NDTPA_IFINDEX, parms->dev->ifindex)) || - nla_put_u32(skb, NDTPA_REFCNT, atomic_read(&parms->refcnt)) || - nla_put_u32(skb, NDTPA_QUEUE_LENBYTES, - NEIGH_VAR(parms, QUEUE_LEN_BYTES)) || - /* approximative value for deprecated QUEUE_LEN (in packets) */ - nla_put_u32(skb, NDTPA_QUEUE_LEN, - NEIGH_VAR(parms, QUEUE_LEN_BYTES) / SKB_TRUESIZE(ETH_FRAME_LEN)) || - nla_put_u32(skb, NDTPA_PROXY_QLEN, NEIGH_VAR(parms, PROXY_QLEN)) || - nla_put_u32(skb, NDTPA_APP_PROBES, NEIGH_VAR(parms, APP_PROBES)) || - nla_put_u32(skb, NDTPA_UCAST_PROBES, - NEIGH_VAR(parms, UCAST_PROBES)) || - nla_put_u32(skb, NDTPA_MCAST_PROBES, - NEIGH_VAR(parms, MCAST_PROBES)) || - nla_put_u32(skb, NDTPA_MCAST_REPROBES, - NEIGH_VAR(parms, MCAST_REPROBES)) || - nla_put_msecs(skb, NDTPA_REACHABLE_TIME, parms->reachable_time, - NDTPA_PAD) || - nla_put_msecs(skb, NDTPA_BASE_REACHABLE_TIME, - NEIGH_VAR(parms, BASE_REACHABLE_TIME), NDTPA_PAD) || - nla_put_msecs(skb, NDTPA_GC_STALETIME, - NEIGH_VAR(parms, GC_STALETIME), NDTPA_PAD) || - nla_put_msecs(skb, NDTPA_DELAY_PROBE_TIME, - NEIGH_VAR(parms, DELAY_PROBE_TIME), NDTPA_PAD) || - nla_put_msecs(skb, NDTPA_RETRANS_TIME, - NEIGH_VAR(parms, RETRANS_TIME), NDTPA_PAD) || - nla_put_msecs(skb, NDTPA_ANYCAST_DELAY, - NEIGH_VAR(parms, ANYCAST_DELAY), NDTPA_PAD) || - nla_put_msecs(skb, NDTPA_PROXY_DELAY, - NEIGH_VAR(parms, PROXY_DELAY), NDTPA_PAD) || - nla_put_msecs(skb, NDTPA_LOCKTIME, - NEIGH_VAR(parms, LOCKTIME), NDTPA_PAD)) - goto nla_put_failure; - return nla_nest_end(skb, nest); - -nla_put_failure: - nla_nest_cancel(skb, nest); - return -EMSGSIZE; -} - -static int neightbl_fill_info(struct sk_buff *skb, struct neigh_table *tbl, - u32 pid, u32 seq, int type, int flags) -{ - struct nlmsghdr *nlh; - struct ndtmsg *ndtmsg; - - nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags); - if (nlh == NULL) - return -EMSGSIZE; - - ndtmsg = nlmsg_data(nlh); - - read_lock_bh(&tbl->lock); - ndtmsg->ndtm_family = tbl->family; - ndtmsg->ndtm_pad1 = 0; - ndtmsg->ndtm_pad2 = 0; - - if (nla_put_string(skb, NDTA_NAME, tbl->id) || - nla_put_msecs(skb, NDTA_GC_INTERVAL, tbl->gc_interval, NDTA_PAD) || - nla_put_u32(skb, NDTA_THRESH1, tbl->gc_thresh1) || - nla_put_u32(skb, NDTA_THRESH2, tbl->gc_thresh2) || - nla_put_u32(skb, NDTA_THRESH3, tbl->gc_thresh3)) - goto nla_put_failure; - { - unsigned long now = jiffies; - unsigned int flush_delta = now - tbl->last_flush; - unsigned int rand_delta = now - tbl->last_rand; - struct neigh_hash_table *nht; - struct ndt_config ndc = { - .ndtc_key_len = tbl->key_len, - .ndtc_entry_size = tbl->entry_size, - .ndtc_entries = atomic_read(&tbl->entries), - .ndtc_last_flush = jiffies_to_msecs(flush_delta), - .ndtc_last_rand = jiffies_to_msecs(rand_delta), - .ndtc_proxy_qlen = tbl->proxy_queue.qlen, - }; - - rcu_read_lock_bh(); - nht = rcu_dereference_bh(tbl->nht); - ndc.ndtc_hash_rnd = nht->hash_rnd[0]; - ndc.ndtc_hash_mask = ((1 << nht->hash_shift) - 1); - rcu_read_unlock_bh(); - - if (nla_put(skb, NDTA_CONFIG, sizeof(ndc), &ndc)) - goto nla_put_failure; - } - - { - int cpu; - struct ndt_stats ndst; - - memset(&ndst, 0, sizeof(ndst)); - - for_each_possible_cpu(cpu) { - struct neigh_statistics *st; - - st = per_cpu_ptr(tbl->stats, cpu); - ndst.ndts_allocs += st->allocs; - ndst.ndts_destroys += st->destroys; - ndst.ndts_hash_grows += st->hash_grows; - ndst.ndts_res_failed += st->res_failed; - ndst.ndts_lookups += st->lookups; - ndst.ndts_hits += st->hits; - ndst.ndts_rcv_probes_mcast += st->rcv_probes_mcast; - ndst.ndts_rcv_probes_ucast += st->rcv_probes_ucast; - ndst.ndts_periodic_gc_runs += st->periodic_gc_runs; - ndst.ndts_forced_gc_runs += st->forced_gc_runs; - ndst.ndts_table_fulls += st->table_fulls; - } - - if (nla_put_64bit(skb, NDTA_STATS, sizeof(ndst), &ndst, - NDTA_PAD)) - goto nla_put_failure; - } - - BUG_ON(tbl->parms.dev); - if (neightbl_fill_parms(skb, &tbl->parms) < 0) - goto nla_put_failure; - - read_unlock_bh(&tbl->lock); - nlmsg_end(skb, nlh); - return 0; - -nla_put_failure: - read_unlock_bh(&tbl->lock); - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -static int neightbl_fill_param_info(struct sk_buff *skb, - struct neigh_table *tbl, - struct neigh_parms *parms, - u32 pid, u32 seq, int type, - unsigned int flags) -{ - struct ndtmsg *ndtmsg; - struct nlmsghdr *nlh; - - nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndtmsg), flags); - if (nlh == NULL) - return -EMSGSIZE; - - ndtmsg = nlmsg_data(nlh); - - read_lock_bh(&tbl->lock); - ndtmsg->ndtm_family = tbl->family; - ndtmsg->ndtm_pad1 = 0; - ndtmsg->ndtm_pad2 = 0; - - if (nla_put_string(skb, NDTA_NAME, tbl->id) < 0 || - neightbl_fill_parms(skb, parms) < 0) - goto errout; - - read_unlock_bh(&tbl->lock); - nlmsg_end(skb, nlh); - return 0; -errout: - read_unlock_bh(&tbl->lock); - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -static const struct nla_policy nl_neightbl_policy[NDTA_MAX+1] = { - [NDTA_NAME] = { .type = NLA_STRING }, - [NDTA_THRESH1] = { .type = NLA_U32 }, - [NDTA_THRESH2] = { .type = NLA_U32 }, - [NDTA_THRESH3] = { .type = NLA_U32 }, - [NDTA_GC_INTERVAL] = { .type = NLA_U64 }, - [NDTA_PARMS] = { .type = NLA_NESTED }, -}; - -static const struct nla_policy nl_ntbl_parm_policy[NDTPA_MAX+1] = { - [NDTPA_IFINDEX] = { .type = NLA_U32 }, - [NDTPA_QUEUE_LEN] = { .type = NLA_U32 }, - [NDTPA_PROXY_QLEN] = { .type = NLA_U32 }, - [NDTPA_APP_PROBES] = { .type = NLA_U32 }, - [NDTPA_UCAST_PROBES] = { .type = NLA_U32 }, - [NDTPA_MCAST_PROBES] = { .type = NLA_U32 }, - [NDTPA_MCAST_REPROBES] = { .type = NLA_U32 }, - [NDTPA_BASE_REACHABLE_TIME] = { .type = NLA_U64 }, - [NDTPA_GC_STALETIME] = { .type = NLA_U64 }, - [NDTPA_DELAY_PROBE_TIME] = { .type = NLA_U64 }, - [NDTPA_RETRANS_TIME] = { .type = NLA_U64 }, - [NDTPA_ANYCAST_DELAY] = { .type = NLA_U64 }, - [NDTPA_PROXY_DELAY] = { .type = NLA_U64 }, - [NDTPA_LOCKTIME] = { .type = NLA_U64 }, -}; - -static int neightbl_set(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct neigh_table *tbl; - struct ndtmsg *ndtmsg; - struct nlattr *tb[NDTA_MAX+1]; - bool found = false; - int err, tidx; - - err = nlmsg_parse(nlh, sizeof(*ndtmsg), tb, NDTA_MAX, - nl_neightbl_policy); - if (err < 0) - goto errout; - - if (tb[NDTA_NAME] == NULL) { - err = -EINVAL; - goto errout; - } - - ndtmsg = nlmsg_data(nlh); - - for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) { - tbl = neigh_tables[tidx]; - if (!tbl) - continue; - if (ndtmsg->ndtm_family && tbl->family != ndtmsg->ndtm_family) - continue; - if (nla_strcmp(tb[NDTA_NAME], tbl->id) == 0) { - found = true; - break; - } - } - - if (!found) - return -ENOENT; - - /* - * We acquire tbl->lock to be nice to the periodic timers and - * make sure they always see a consistent set of values. - */ - write_lock_bh(&tbl->lock); - - if (tb[NDTA_PARMS]) { - struct nlattr *tbp[NDTPA_MAX+1]; - struct neigh_parms *p; - int i, ifindex = 0; - - err = nla_parse_nested(tbp, NDTPA_MAX, tb[NDTA_PARMS], - nl_ntbl_parm_policy); - if (err < 0) - goto errout_tbl_lock; - - if (tbp[NDTPA_IFINDEX]) - ifindex = nla_get_u32(tbp[NDTPA_IFINDEX]); - - p = lookup_neigh_parms(tbl, net, ifindex); - if (p == NULL) { - err = -ENOENT; - goto errout_tbl_lock; - } - - for (i = 1; i <= NDTPA_MAX; i++) { - if (tbp[i] == NULL) - continue; - - switch (i) { - case NDTPA_QUEUE_LEN: - NEIGH_VAR_SET(p, QUEUE_LEN_BYTES, - nla_get_u32(tbp[i]) * - SKB_TRUESIZE(ETH_FRAME_LEN)); - break; - case NDTPA_QUEUE_LENBYTES: - NEIGH_VAR_SET(p, QUEUE_LEN_BYTES, - nla_get_u32(tbp[i])); - break; - case NDTPA_PROXY_QLEN: - NEIGH_VAR_SET(p, PROXY_QLEN, - nla_get_u32(tbp[i])); - break; - case NDTPA_APP_PROBES: - NEIGH_VAR_SET(p, APP_PROBES, - nla_get_u32(tbp[i])); - break; - case NDTPA_UCAST_PROBES: - NEIGH_VAR_SET(p, UCAST_PROBES, - nla_get_u32(tbp[i])); - break; - case NDTPA_MCAST_PROBES: - NEIGH_VAR_SET(p, MCAST_PROBES, - nla_get_u32(tbp[i])); - break; - case NDTPA_MCAST_REPROBES: - NEIGH_VAR_SET(p, MCAST_REPROBES, - nla_get_u32(tbp[i])); - break; - case NDTPA_BASE_REACHABLE_TIME: - NEIGH_VAR_SET(p, BASE_REACHABLE_TIME, - nla_get_msecs(tbp[i])); - /* update reachable_time as well, otherwise, the change will - * only be effective after the next time neigh_periodic_work - * decides to recompute it (can be multiple minutes) - */ - p->reachable_time = - neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); - break; - case NDTPA_GC_STALETIME: - NEIGH_VAR_SET(p, GC_STALETIME, - nla_get_msecs(tbp[i])); - break; - case NDTPA_DELAY_PROBE_TIME: - NEIGH_VAR_SET(p, DELAY_PROBE_TIME, - nla_get_msecs(tbp[i])); - call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p); - break; - case NDTPA_RETRANS_TIME: - NEIGH_VAR_SET(p, RETRANS_TIME, - nla_get_msecs(tbp[i])); - break; - case NDTPA_ANYCAST_DELAY: - NEIGH_VAR_SET(p, ANYCAST_DELAY, - nla_get_msecs(tbp[i])); - break; - case NDTPA_PROXY_DELAY: - NEIGH_VAR_SET(p, PROXY_DELAY, - nla_get_msecs(tbp[i])); - break; - case NDTPA_LOCKTIME: - NEIGH_VAR_SET(p, LOCKTIME, - nla_get_msecs(tbp[i])); - break; - } - } - } - - err = -ENOENT; - if ((tb[NDTA_THRESH1] || tb[NDTA_THRESH2] || - tb[NDTA_THRESH3] || tb[NDTA_GC_INTERVAL]) && - !net_eq(net, &init_net)) - goto errout_tbl_lock; - - if (tb[NDTA_THRESH1]) - tbl->gc_thresh1 = nla_get_u32(tb[NDTA_THRESH1]); - - if (tb[NDTA_THRESH2]) - tbl->gc_thresh2 = nla_get_u32(tb[NDTA_THRESH2]); - - if (tb[NDTA_THRESH3]) - tbl->gc_thresh3 = nla_get_u32(tb[NDTA_THRESH3]); - - if (tb[NDTA_GC_INTERVAL]) - tbl->gc_interval = nla_get_msecs(tb[NDTA_GC_INTERVAL]); - - err = 0; - -errout_tbl_lock: - write_unlock_bh(&tbl->lock); -errout: - return err; -} - -static int neightbl_dump_info(struct sk_buff *skb, struct netlink_callback *cb) -{ - struct net *net = sock_net(skb->sk); - int family, tidx, nidx = 0; - int tbl_skip = cb->args[0]; - int neigh_skip = cb->args[1]; - struct neigh_table *tbl; - - family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; - - for (tidx = 0; tidx < NEIGH_NR_TABLES; tidx++) { - struct neigh_parms *p; - - tbl = neigh_tables[tidx]; - if (!tbl) - continue; - - if (tidx < tbl_skip || (family && tbl->family != family)) - continue; - - if (neightbl_fill_info(skb, tbl, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, RTM_NEWNEIGHTBL, - NLM_F_MULTI) < 0) - break; - - nidx = 0; - p = list_next_entry(&tbl->parms, list); - list_for_each_entry_from(p, &tbl->parms_list, list) { - if (!net_eq(neigh_parms_net(p), net)) - continue; - - if (nidx < neigh_skip) - goto next; - - if (neightbl_fill_param_info(skb, tbl, p, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWNEIGHTBL, - NLM_F_MULTI) < 0) - goto out; - next: - nidx++; - } - - neigh_skip = 0; - } -out: - cb->args[0] = tidx; - cb->args[1] = nidx; - - return skb->len; -} - -static int neigh_fill_info(struct sk_buff *skb, struct neighbour *neigh, - u32 pid, u32 seq, int type, unsigned int flags) -{ - unsigned long now = jiffies; - struct nda_cacheinfo ci; - struct nlmsghdr *nlh; - struct ndmsg *ndm; - - nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags); - if (nlh == NULL) - return -EMSGSIZE; - - ndm = nlmsg_data(nlh); - ndm->ndm_family = neigh->ops->family; - ndm->ndm_pad1 = 0; - ndm->ndm_pad2 = 0; - ndm->ndm_flags = neigh->flags; - ndm->ndm_type = neigh->type; - ndm->ndm_ifindex = neigh->dev->ifindex; - - if (nla_put(skb, NDA_DST, neigh->tbl->key_len, neigh->primary_key)) - goto nla_put_failure; - - read_lock_bh(&neigh->lock); - ndm->ndm_state = neigh->nud_state; - if (neigh->nud_state & NUD_VALID) { - char haddr[MAX_ADDR_LEN]; - - neigh_ha_snapshot(haddr, neigh, neigh->dev); - if (nla_put(skb, NDA_LLADDR, neigh->dev->addr_len, haddr) < 0) { - read_unlock_bh(&neigh->lock); - goto nla_put_failure; - } - } - - ci.ndm_used = jiffies_to_clock_t(now - neigh->used); - ci.ndm_confirmed = jiffies_to_clock_t(now - neigh->confirmed); - ci.ndm_updated = jiffies_to_clock_t(now - neigh->updated); - ci.ndm_refcnt = atomic_read(&neigh->refcnt) - 1; - read_unlock_bh(&neigh->lock); - - if (nla_put_u32(skb, NDA_PROBES, atomic_read(&neigh->probes)) || - nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci)) - goto nla_put_failure; - - nlmsg_end(skb, nlh); - return 0; - -nla_put_failure: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -static int pneigh_fill_info(struct sk_buff *skb, struct pneigh_entry *pn, - u32 pid, u32 seq, int type, unsigned int flags, - struct neigh_table *tbl) -{ - struct nlmsghdr *nlh; - struct ndmsg *ndm; - - nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), flags); - if (nlh == NULL) - return -EMSGSIZE; - - ndm = nlmsg_data(nlh); - ndm->ndm_family = tbl->family; - ndm->ndm_pad1 = 0; - ndm->ndm_pad2 = 0; - ndm->ndm_flags = pn->flags | NTF_PROXY; - ndm->ndm_type = RTN_UNICAST; - ndm->ndm_ifindex = pn->dev ? pn->dev->ifindex : 0; - ndm->ndm_state = NUD_NONE; - - if (nla_put(skb, NDA_DST, tbl->key_len, pn->key)) - goto nla_put_failure; - - nlmsg_end(skb, nlh); - return 0; - -nla_put_failure: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -static void neigh_update_notify(struct neighbour *neigh) -{ - call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, neigh); - __neigh_notify(neigh, RTM_NEWNEIGH, 0); -} - -static bool neigh_master_filtered(struct net_device *dev, int master_idx) -{ - struct net_device *master; - - if (!master_idx) - return false; - - master = netdev_master_upper_dev_get(dev); - if (!master || master->ifindex != master_idx) - return true; - - return false; -} - -static bool neigh_ifindex_filtered(struct net_device *dev, int filter_idx) -{ - if (filter_idx && dev->ifindex != filter_idx) - return true; - - return false; -} - -static int neigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, - struct netlink_callback *cb) -{ - struct net *net = sock_net(skb->sk); - const struct nlmsghdr *nlh = cb->nlh; - struct nlattr *tb[NDA_MAX + 1]; - struct neighbour *n; - int rc, h, s_h = cb->args[1]; - int idx, s_idx = idx = cb->args[2]; - struct neigh_hash_table *nht; - int filter_master_idx = 0, filter_idx = 0; - unsigned int flags = NLM_F_MULTI; - int err; - - err = nlmsg_parse(nlh, sizeof(struct ndmsg), tb, NDA_MAX, NULL); - if (!err) { - if (tb[NDA_IFINDEX]) - filter_idx = nla_get_u32(tb[NDA_IFINDEX]); - - if (tb[NDA_MASTER]) - filter_master_idx = nla_get_u32(tb[NDA_MASTER]); - - if (filter_idx || filter_master_idx) - flags |= NLM_F_DUMP_FILTERED; - } - - rcu_read_lock_bh(); - nht = rcu_dereference_bh(tbl->nht); - - for (h = s_h; h < (1 << nht->hash_shift); h++) { - if (h > s_h) - s_idx = 0; - for (n = rcu_dereference_bh(nht->hash_buckets[h]), idx = 0; - n != NULL; - n = rcu_dereference_bh(n->next)) { - if (!net_eq(dev_net(n->dev), net)) - continue; - if (neigh_ifindex_filtered(n->dev, filter_idx)) - continue; - if (neigh_master_filtered(n->dev, filter_master_idx)) - continue; - if (idx < s_idx) - goto next; - if (neigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWNEIGH, - flags) < 0) { - rc = -1; - goto out; - } -next: - idx++; - } - } - rc = skb->len; -out: - rcu_read_unlock_bh(); - cb->args[1] = h; - cb->args[2] = idx; - return rc; -} - -static int pneigh_dump_table(struct neigh_table *tbl, struct sk_buff *skb, - struct netlink_callback *cb) -{ - struct pneigh_entry *n; - struct net *net = sock_net(skb->sk); - int rc, h, s_h = cb->args[3]; - int idx, s_idx = idx = cb->args[4]; - - read_lock_bh(&tbl->lock); - - for (h = s_h; h <= PNEIGH_HASHMASK; h++) { - if (h > s_h) - s_idx = 0; - for (n = tbl->phash_buckets[h], idx = 0; n; n = n->next) { - if (pneigh_net(n) != net) - continue; - if (idx < s_idx) - goto next; - if (pneigh_fill_info(skb, n, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWNEIGH, - NLM_F_MULTI, tbl) < 0) { - read_unlock_bh(&tbl->lock); - rc = -1; - goto out; - } - next: - idx++; - } - } - - read_unlock_bh(&tbl->lock); - rc = skb->len; -out: - cb->args[3] = h; - cb->args[4] = idx; - return rc; - -} - -static int neigh_dump_info(struct sk_buff *skb, struct netlink_callback *cb) -{ - struct neigh_table *tbl; - int t, family, s_t; - int proxy = 0; - int err; - - family = ((struct rtgenmsg *) nlmsg_data(cb->nlh))->rtgen_family; - - /* check for full ndmsg structure presence, family member is - * the same for both structures - */ - if (nlmsg_len(cb->nlh) >= sizeof(struct ndmsg) && - ((struct ndmsg *) nlmsg_data(cb->nlh))->ndm_flags == NTF_PROXY) - proxy = 1; - - s_t = cb->args[0]; - - for (t = 0; t < NEIGH_NR_TABLES; t++) { - tbl = neigh_tables[t]; - - if (!tbl) - continue; - if (t < s_t || (family && tbl->family != family)) - continue; - if (t > s_t) - memset(&cb->args[1], 0, sizeof(cb->args) - - sizeof(cb->args[0])); - if (proxy) - err = pneigh_dump_table(tbl, skb, cb); - else - err = neigh_dump_table(tbl, skb, cb); - if (err < 0) - break; - } - - cb->args[0] = t; - return skb->len; -} - -void neigh_for_each(struct neigh_table *tbl, void (*cb)(struct neighbour *, void *), void *cookie) -{ - int chain; - struct neigh_hash_table *nht; - - rcu_read_lock_bh(); - nht = rcu_dereference_bh(tbl->nht); - - read_lock(&tbl->lock); /* avoid resizes */ - for (chain = 0; chain < (1 << nht->hash_shift); chain++) { - struct neighbour *n; - - for (n = rcu_dereference_bh(nht->hash_buckets[chain]); - n != NULL; - n = rcu_dereference_bh(n->next)) - cb(n, cookie); - } - read_unlock(&tbl->lock); - rcu_read_unlock_bh(); -} -EXPORT_SYMBOL(neigh_for_each); - -/* The tbl->lock must be held as a writer and BH disabled. */ -void __neigh_for_each_release(struct neigh_table *tbl, - int (*cb)(struct neighbour *)) -{ - int chain; - struct neigh_hash_table *nht; - - nht = rcu_dereference_protected(tbl->nht, - lockdep_is_held(&tbl->lock)); - for (chain = 0; chain < (1 << nht->hash_shift); chain++) { - struct neighbour *n; - struct neighbour __rcu **np; - - np = &nht->hash_buckets[chain]; - while ((n = rcu_dereference_protected(*np, - lockdep_is_held(&tbl->lock))) != NULL) { - int release; - - write_lock(&n->lock); - release = cb(n); - if (release) { - rcu_assign_pointer(*np, - rcu_dereference_protected(n->next, - lockdep_is_held(&tbl->lock))); - n->dead = 1; - } else - np = &n->next; - write_unlock(&n->lock); - if (release) - neigh_cleanup_and_release(n); - } - } -} -EXPORT_SYMBOL(__neigh_for_each_release); - -int neigh_xmit(int index, struct net_device *dev, - const void *addr, struct sk_buff *skb) -{ - int err = -EAFNOSUPPORT; - if (likely(index < NEIGH_NR_TABLES)) { - struct neigh_table *tbl; - struct neighbour *neigh; - - tbl = neigh_tables[index]; - if (!tbl) - goto out; - rcu_read_lock_bh(); - neigh = __neigh_lookup_noref(tbl, addr, dev); - if (!neigh) - neigh = __neigh_create(tbl, addr, dev, false); - err = PTR_ERR(neigh); - if (IS_ERR(neigh)) { - rcu_read_unlock_bh(); - goto out_kfree_skb; - } - err = neigh->output(neigh, skb); - rcu_read_unlock_bh(); - } - else if (index == NEIGH_LINK_TABLE) { - err = dev_hard_header(skb, dev, ntohs(skb->protocol), - addr, NULL, skb->len); - if (err < 0) - goto out_kfree_skb; - err = dev_queue_xmit(skb); - } -out: - return err; -out_kfree_skb: - kfree_skb(skb); - goto out; -} -EXPORT_SYMBOL(neigh_xmit); - -#ifdef CONFIG_PROC_FS - -static struct neighbour *neigh_get_first(struct seq_file *seq) -{ - struct neigh_seq_state *state = seq->private; - struct net *net = seq_file_net(seq); - struct neigh_hash_table *nht = state->nht; - struct neighbour *n = NULL; - int bucket = state->bucket; - - state->flags &= ~NEIGH_SEQ_IS_PNEIGH; - for (bucket = 0; bucket < (1 << nht->hash_shift); bucket++) { - n = rcu_dereference_bh(nht->hash_buckets[bucket]); - - while (n) { - if (!net_eq(dev_net(n->dev), net)) - goto next; - if (state->neigh_sub_iter) { - loff_t fakep = 0; - void *v; - - v = state->neigh_sub_iter(state, n, &fakep); - if (!v) - goto next; - } - if (!(state->flags & NEIGH_SEQ_SKIP_NOARP)) - break; - if (n->nud_state & ~NUD_NOARP) - break; -next: - n = rcu_dereference_bh(n->next); - } - - if (n) - break; - } - state->bucket = bucket; - - return n; -} - -static struct neighbour *neigh_get_next(struct seq_file *seq, - struct neighbour *n, - loff_t *pos) -{ - struct neigh_seq_state *state = seq->private; - struct net *net = seq_file_net(seq); - struct neigh_hash_table *nht = state->nht; - - if (state->neigh_sub_iter) { - void *v = state->neigh_sub_iter(state, n, pos); - if (v) - return n; - } - n = rcu_dereference_bh(n->next); - - while (1) { - while (n) { - if (!net_eq(dev_net(n->dev), net)) - goto next; - if (state->neigh_sub_iter) { - void *v = state->neigh_sub_iter(state, n, pos); - if (v) - return n; - goto next; - } - if (!(state->flags & NEIGH_SEQ_SKIP_NOARP)) - break; - - if (n->nud_state & ~NUD_NOARP) - break; -next: - n = rcu_dereference_bh(n->next); - } - - if (n) - break; - - if (++state->bucket >= (1 << nht->hash_shift)) - break; - - n = rcu_dereference_bh(nht->hash_buckets[state->bucket]); - } - - if (n && pos) - --(*pos); - return n; -} - -static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos) -{ - struct neighbour *n = neigh_get_first(seq); - - if (n) { - --(*pos); - while (*pos) { - n = neigh_get_next(seq, n, pos); - if (!n) - break; - } - } - return *pos ? NULL : n; -} - -static struct pneigh_entry *pneigh_get_first(struct seq_file *seq) -{ - struct neigh_seq_state *state = seq->private; - struct net *net = seq_file_net(seq); - struct neigh_table *tbl = state->tbl; - struct pneigh_entry *pn = NULL; - int bucket = state->bucket; - - state->flags |= NEIGH_SEQ_IS_PNEIGH; - for (bucket = 0; bucket <= PNEIGH_HASHMASK; bucket++) { - pn = tbl->phash_buckets[bucket]; - while (pn && !net_eq(pneigh_net(pn), net)) - pn = pn->next; - if (pn) - break; - } - state->bucket = bucket; - - return pn; -} - -static struct pneigh_entry *pneigh_get_next(struct seq_file *seq, - struct pneigh_entry *pn, - loff_t *pos) -{ - struct neigh_seq_state *state = seq->private; - struct net *net = seq_file_net(seq); - struct neigh_table *tbl = state->tbl; - - do { - pn = pn->next; - } while (pn && !net_eq(pneigh_net(pn), net)); - - while (!pn) { - if (++state->bucket > PNEIGH_HASHMASK) - break; - pn = tbl->phash_buckets[state->bucket]; - while (pn && !net_eq(pneigh_net(pn), net)) - pn = pn->next; - if (pn) - break; - } - - if (pn && pos) - --(*pos); - - return pn; -} - -static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t *pos) -{ - struct pneigh_entry *pn = pneigh_get_first(seq); - - if (pn) { - --(*pos); - while (*pos) { - pn = pneigh_get_next(seq, pn, pos); - if (!pn) - break; - } - } - return *pos ? NULL : pn; -} - -static void *neigh_get_idx_any(struct seq_file *seq, loff_t *pos) -{ - struct neigh_seq_state *state = seq->private; - void *rc; - loff_t idxpos = *pos; - - rc = neigh_get_idx(seq, &idxpos); - if (!rc && !(state->flags & NEIGH_SEQ_NEIGH_ONLY)) - rc = pneigh_get_idx(seq, &idxpos); - - return rc; -} - -void *neigh_seq_start(struct seq_file *seq, loff_t *pos, struct neigh_table *tbl, unsigned int neigh_seq_flags) - __acquires(rcu_bh) -{ - struct neigh_seq_state *state = seq->private; - - state->tbl = tbl; - state->bucket = 0; - state->flags = (neigh_seq_flags & ~NEIGH_SEQ_IS_PNEIGH); - - rcu_read_lock_bh(); - state->nht = rcu_dereference_bh(tbl->nht); - - return *pos ? neigh_get_idx_any(seq, pos) : SEQ_START_TOKEN; -} -EXPORT_SYMBOL(neigh_seq_start); - -void *neigh_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct neigh_seq_state *state; - void *rc; - - if (v == SEQ_START_TOKEN) { - rc = neigh_get_first(seq); - goto out; - } - - state = seq->private; - if (!(state->flags & NEIGH_SEQ_IS_PNEIGH)) { - rc = neigh_get_next(seq, v, NULL); - if (rc) - goto out; - if (!(state->flags & NEIGH_SEQ_NEIGH_ONLY)) - rc = pneigh_get_first(seq); - } else { - BUG_ON(state->flags & NEIGH_SEQ_NEIGH_ONLY); - rc = pneigh_get_next(seq, v, NULL); - } -out: - ++(*pos); - return rc; -} -EXPORT_SYMBOL(neigh_seq_next); - -void neigh_seq_stop(struct seq_file *seq, void *v) - __releases(rcu_bh) -{ - rcu_read_unlock_bh(); -} -EXPORT_SYMBOL(neigh_seq_stop); - -/* statistics via seq_file */ - -static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos) -{ - struct neigh_table *tbl = seq->private; - int cpu; - - if (*pos == 0) - return SEQ_START_TOKEN; - - for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) { - if (!cpu_possible(cpu)) - continue; - *pos = cpu+1; - return per_cpu_ptr(tbl->stats, cpu); - } - return NULL; -} - -static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct neigh_table *tbl = seq->private; - int cpu; - - for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) { - if (!cpu_possible(cpu)) - continue; - *pos = cpu+1; - return per_cpu_ptr(tbl->stats, cpu); - } - return NULL; -} - -static void neigh_stat_seq_stop(struct seq_file *seq, void *v) -{ - -} - -static int neigh_stat_seq_show(struct seq_file *seq, void *v) -{ - struct neigh_table *tbl = seq->private; - struct neigh_statistics *st = v; - - if (v == SEQ_START_TOKEN) { - seq_printf(seq, "entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs unresolved_discards table_fulls\n"); - return 0; - } - - seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx " - "%08lx %08lx %08lx %08lx %08lx %08lx\n", - atomic_read(&tbl->entries), - - st->allocs, - st->destroys, - st->hash_grows, - - st->lookups, - st->hits, - - st->res_failed, - - st->rcv_probes_mcast, - st->rcv_probes_ucast, - - st->periodic_gc_runs, - st->forced_gc_runs, - st->unres_discards, - st->table_fulls - ); - - return 0; -} - -static const struct seq_operations neigh_stat_seq_ops = { - .start = neigh_stat_seq_start, - .next = neigh_stat_seq_next, - .stop = neigh_stat_seq_stop, - .show = neigh_stat_seq_show, -}; - -static int neigh_stat_seq_open(struct inode *inode, struct file *file) -{ - int ret = seq_open(file, &neigh_stat_seq_ops); - - if (!ret) { - struct seq_file *sf = file->private_data; - sf->private = PDE_DATA(inode); - } - return ret; -}; - -static const struct file_operations neigh_stat_seq_fops = { - .owner = THIS_MODULE, - .open = neigh_stat_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -#endif /* CONFIG_PROC_FS */ - -static inline size_t neigh_nlmsg_size(void) -{ - return NLMSG_ALIGN(sizeof(struct ndmsg)) - + nla_total_size(MAX_ADDR_LEN) /* NDA_DST */ - + nla_total_size(MAX_ADDR_LEN) /* NDA_LLADDR */ - + nla_total_size(sizeof(struct nda_cacheinfo)) - + nla_total_size(4); /* NDA_PROBES */ -} - -static void __neigh_notify(struct neighbour *n, int type, int flags) -{ - struct net *net = dev_net(n->dev); - struct sk_buff *skb; - int err = -ENOBUFS; - - skb = nlmsg_new(neigh_nlmsg_size(), GFP_ATOMIC); - if (skb == NULL) - goto errout; - - err = neigh_fill_info(skb, n, 0, 0, type, flags); - if (err < 0) { - /* -EMSGSIZE implies BUG in neigh_nlmsg_size() */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - goto errout; - } - rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); - return; -errout: - if (err < 0) - rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); -} - -void neigh_app_ns(struct neighbour *n) -{ - __neigh_notify(n, RTM_GETNEIGH, NLM_F_REQUEST); -} -EXPORT_SYMBOL(neigh_app_ns); - -#ifdef CONFIG_SYSCTL -static int zero; -static int int_max = INT_MAX; -static int unres_qlen_max = INT_MAX / SKB_TRUESIZE(ETH_FRAME_LEN); - -static int proc_unres_qlen(struct ctl_table *ctl, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - int size, ret; - struct ctl_table tmp = *ctl; - - tmp.extra1 = &zero; - tmp.extra2 = &unres_qlen_max; - tmp.data = &size; - - size = *(int *)ctl->data / SKB_TRUESIZE(ETH_FRAME_LEN); - ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); - - if (write && !ret) - *(int *)ctl->data = size * SKB_TRUESIZE(ETH_FRAME_LEN); - return ret; -} - -static struct neigh_parms *neigh_get_dev_parms_rcu(struct net_device *dev, - int family) -{ - switch (family) { - case AF_INET: - return __in_dev_arp_parms_get_rcu(dev); - case AF_INET6: - return __in6_dev_nd_parms_get_rcu(dev); - } - return NULL; -} - -static void neigh_copy_dflt_parms(struct net *net, struct neigh_parms *p, - int index) -{ - struct net_device *dev; - int family = neigh_parms_family(p); - - rcu_read_lock(); - for_each_netdev_rcu(net, dev) { - struct neigh_parms *dst_p = - neigh_get_dev_parms_rcu(dev, family); - - if (dst_p && !test_bit(index, dst_p->data_state)) - dst_p->data[index] = p->data[index]; - } - rcu_read_unlock(); -} - -static void neigh_proc_update(struct ctl_table *ctl, int write) -{ - struct net_device *dev = ctl->extra1; - struct neigh_parms *p = ctl->extra2; - struct net *net = neigh_parms_net(p); - int index = (int *) ctl->data - p->data; - - if (!write) - return; - - set_bit(index, p->data_state); - call_netevent_notifiers(NETEVENT_DELAY_PROBE_TIME_UPDATE, p); - if (!dev) /* NULL dev means this is default value */ - neigh_copy_dflt_parms(net, p, index); -} - -static int neigh_proc_dointvec_zero_intmax(struct ctl_table *ctl, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - struct ctl_table tmp = *ctl; - int ret; - - tmp.extra1 = &zero; - tmp.extra2 = &int_max; - - ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); - neigh_proc_update(ctl, write); - return ret; -} - -int neigh_proc_dointvec(struct ctl_table *ctl, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); - - neigh_proc_update(ctl, write); - return ret; -} -EXPORT_SYMBOL(neigh_proc_dointvec); - -int neigh_proc_dointvec_jiffies(struct ctl_table *ctl, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - int ret = proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos); - - neigh_proc_update(ctl, write); - return ret; -} -EXPORT_SYMBOL(neigh_proc_dointvec_jiffies); - -static int neigh_proc_dointvec_userhz_jiffies(struct ctl_table *ctl, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - int ret = proc_dointvec_userhz_jiffies(ctl, write, buffer, lenp, ppos); - - neigh_proc_update(ctl, write); - return ret; -} - -int neigh_proc_dointvec_ms_jiffies(struct ctl_table *ctl, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - int ret = proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos); - - neigh_proc_update(ctl, write); - return ret; -} -EXPORT_SYMBOL(neigh_proc_dointvec_ms_jiffies); - -static int neigh_proc_dointvec_unres_qlen(struct ctl_table *ctl, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - int ret = proc_unres_qlen(ctl, write, buffer, lenp, ppos); - - neigh_proc_update(ctl, write); - return ret; -} - -static int neigh_proc_base_reachable_time(struct ctl_table *ctl, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - struct neigh_parms *p = ctl->extra2; - int ret; - - if (strcmp(ctl->procname, "base_reachable_time") == 0) - ret = neigh_proc_dointvec_jiffies(ctl, write, buffer, lenp, ppos); - else if (strcmp(ctl->procname, "base_reachable_time_ms") == 0) - ret = neigh_proc_dointvec_ms_jiffies(ctl, write, buffer, lenp, ppos); - else - ret = -1; - - if (write && ret == 0) { - /* update reachable_time as well, otherwise, the change will - * only be effective after the next time neigh_periodic_work - * decides to recompute it - */ - p->reachable_time = - neigh_rand_reach_time(NEIGH_VAR(p, BASE_REACHABLE_TIME)); - } - return ret; -} - -#define NEIGH_PARMS_DATA_OFFSET(index) \ - (&((struct neigh_parms *) 0)->data[index]) - -#define NEIGH_SYSCTL_ENTRY(attr, data_attr, name, mval, proc) \ - [NEIGH_VAR_ ## attr] = { \ - .procname = name, \ - .data = NEIGH_PARMS_DATA_OFFSET(NEIGH_VAR_ ## data_attr), \ - .maxlen = sizeof(int), \ - .mode = mval, \ - .proc_handler = proc, \ - } - -#define NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(attr, name) \ - NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_zero_intmax) - -#define NEIGH_SYSCTL_JIFFIES_ENTRY(attr, name) \ - NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_jiffies) - -#define NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(attr, name) \ - NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_userhz_jiffies) - -#define NEIGH_SYSCTL_MS_JIFFIES_ENTRY(attr, name) \ - NEIGH_SYSCTL_ENTRY(attr, attr, name, 0644, neigh_proc_dointvec_ms_jiffies) - -#define NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(attr, data_attr, name) \ - NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_ms_jiffies) - -#define NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(attr, data_attr, name) \ - NEIGH_SYSCTL_ENTRY(attr, data_attr, name, 0644, neigh_proc_dointvec_unres_qlen) - -static struct neigh_sysctl_table { - struct ctl_table_header *sysctl_header; - struct ctl_table neigh_vars[NEIGH_VAR_MAX + 1]; -} neigh_sysctl_template __read_mostly = { - .neigh_vars = { - NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_PROBES, "mcast_solicit"), - NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(UCAST_PROBES, "ucast_solicit"), - NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(APP_PROBES, "app_solicit"), - NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(MCAST_REPROBES, "mcast_resolicit"), - NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(RETRANS_TIME, "retrans_time"), - NEIGH_SYSCTL_JIFFIES_ENTRY(BASE_REACHABLE_TIME, "base_reachable_time"), - NEIGH_SYSCTL_JIFFIES_ENTRY(DELAY_PROBE_TIME, "delay_first_probe_time"), - NEIGH_SYSCTL_JIFFIES_ENTRY(GC_STALETIME, "gc_stale_time"), - NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(QUEUE_LEN_BYTES, "unres_qlen_bytes"), - NEIGH_SYSCTL_ZERO_INTMAX_ENTRY(PROXY_QLEN, "proxy_qlen"), - NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(ANYCAST_DELAY, "anycast_delay"), - NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(PROXY_DELAY, "proxy_delay"), - NEIGH_SYSCTL_USERHZ_JIFFIES_ENTRY(LOCKTIME, "locktime"), - NEIGH_SYSCTL_UNRES_QLEN_REUSED_ENTRY(QUEUE_LEN, QUEUE_LEN_BYTES, "unres_qlen"), - NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(RETRANS_TIME_MS, RETRANS_TIME, "retrans_time_ms"), - NEIGH_SYSCTL_MS_JIFFIES_REUSED_ENTRY(BASE_REACHABLE_TIME_MS, BASE_REACHABLE_TIME, "base_reachable_time_ms"), - [NEIGH_VAR_GC_INTERVAL] = { - .procname = "gc_interval", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - [NEIGH_VAR_GC_THRESH1] = { - .procname = "gc_thresh1", - .maxlen = sizeof(int), - .mode = 0644, - .extra1 = &zero, - .extra2 = &int_max, - .proc_handler = proc_dointvec_minmax, - }, - [NEIGH_VAR_GC_THRESH2] = { - .procname = "gc_thresh2", - .maxlen = sizeof(int), - .mode = 0644, - .extra1 = &zero, - .extra2 = &int_max, - .proc_handler = proc_dointvec_minmax, - }, - [NEIGH_VAR_GC_THRESH3] = { - .procname = "gc_thresh3", - .maxlen = sizeof(int), - .mode = 0644, - .extra1 = &zero, - .extra2 = &int_max, - .proc_handler = proc_dointvec_minmax, - }, - {}, - }, -}; - -int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p, - proc_handler *handler) -{ - int i; - struct neigh_sysctl_table *t; - const char *dev_name_source; - char neigh_path[ sizeof("net//neigh/") + IFNAMSIZ + IFNAMSIZ ]; - char *p_name; - - t = kmemdup(&neigh_sysctl_template, sizeof(*t), GFP_KERNEL); - if (!t) - goto err; - - for (i = 0; i < NEIGH_VAR_GC_INTERVAL; i++) { - t->neigh_vars[i].data += (long) p; - t->neigh_vars[i].extra1 = dev; - t->neigh_vars[i].extra2 = p; - } - - if (dev) { - dev_name_source = dev->name; - /* Terminate the table early */ - memset(&t->neigh_vars[NEIGH_VAR_GC_INTERVAL], 0, - sizeof(t->neigh_vars[NEIGH_VAR_GC_INTERVAL])); - } else { - struct neigh_table *tbl = p->tbl; - dev_name_source = "default"; - t->neigh_vars[NEIGH_VAR_GC_INTERVAL].data = &tbl->gc_interval; - t->neigh_vars[NEIGH_VAR_GC_THRESH1].data = &tbl->gc_thresh1; - t->neigh_vars[NEIGH_VAR_GC_THRESH2].data = &tbl->gc_thresh2; - t->neigh_vars[NEIGH_VAR_GC_THRESH3].data = &tbl->gc_thresh3; - } - - if (handler) { - /* RetransTime */ - t->neigh_vars[NEIGH_VAR_RETRANS_TIME].proc_handler = handler; - /* ReachableTime */ - t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = handler; - /* RetransTime (in milliseconds)*/ - t->neigh_vars[NEIGH_VAR_RETRANS_TIME_MS].proc_handler = handler; - /* ReachableTime (in milliseconds) */ - t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = handler; - } else { - /* Those handlers will update p->reachable_time after - * base_reachable_time(_ms) is set to ensure the new timer starts being - * applied after the next neighbour update instead of waiting for - * neigh_periodic_work to update its value (can be multiple minutes) - * So any handler that replaces them should do this as well - */ - /* ReachableTime */ - t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME].proc_handler = - neigh_proc_base_reachable_time; - /* ReachableTime (in milliseconds) */ - t->neigh_vars[NEIGH_VAR_BASE_REACHABLE_TIME_MS].proc_handler = - neigh_proc_base_reachable_time; - } - - /* Don't export sysctls to unprivileged users */ - if (neigh_parms_net(p)->user_ns != &init_user_ns) - t->neigh_vars[0].procname = NULL; - - switch (neigh_parms_family(p)) { - case AF_INET: - p_name = "ipv4"; - break; - case AF_INET6: - p_name = "ipv6"; - break; - default: - BUG(); - } - - snprintf(neigh_path, sizeof(neigh_path), "net/%s/neigh/%s", - p_name, dev_name_source); - t->sysctl_header = - register_net_sysctl(neigh_parms_net(p), neigh_path, t->neigh_vars); - if (!t->sysctl_header) - goto free; - - p->sysctl_table = t; - return 0; - -free: - kfree(t); -err: - return -ENOBUFS; -} -EXPORT_SYMBOL(neigh_sysctl_register); - -void neigh_sysctl_unregister(struct neigh_parms *p) -{ - if (p->sysctl_table) { - struct neigh_sysctl_table *t = p->sysctl_table; - p->sysctl_table = NULL; - unregister_net_sysctl_table(t->sysctl_header); - kfree(t); - } -} -EXPORT_SYMBOL(neigh_sysctl_unregister); - -#endif /* CONFIG_SYSCTL */ - -static int __init neigh_init(void) -{ - rtnl_register(PF_UNSPEC, RTM_NEWNEIGH, neigh_add, NULL, NULL); - rtnl_register(PF_UNSPEC, RTM_DELNEIGH, neigh_delete, NULL, NULL); - rtnl_register(PF_UNSPEC, RTM_GETNEIGH, NULL, neigh_dump_info, NULL); - - rtnl_register(PF_UNSPEC, RTM_GETNEIGHTBL, NULL, neightbl_dump_info, - NULL); - rtnl_register(PF_UNSPEC, RTM_SETNEIGHTBL, neightbl_set, NULL, NULL); - - return 0; -} - -subsys_initcall(neigh_init); - diff --git a/src/linux/net/core/net-procfs.c b/src/linux/net/core/net-procfs.c deleted file mode 100644 index 14d0934..0000000 --- a/src/linux/net/core/net-procfs.c +++ /dev/null @@ -1,424 +0,0 @@ -#include -#include -#include -#include - -#define BUCKET_SPACE (32 - NETDEV_HASHBITS - 1) - -#define get_bucket(x) ((x) >> BUCKET_SPACE) -#define get_offset(x) ((x) & ((1 << BUCKET_SPACE) - 1)) -#define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o)) - -extern struct list_head ptype_all __read_mostly; -extern struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly; - -static inline struct net_device *dev_from_same_bucket(struct seq_file *seq, loff_t *pos) -{ - struct net *net = seq_file_net(seq); - struct net_device *dev; - struct hlist_head *h; - unsigned int count = 0, offset = get_offset(*pos); - - h = &net->dev_name_head[get_bucket(*pos)]; - hlist_for_each_entry_rcu(dev, h, name_hlist) { - if (++count == offset) - return dev; - } - - return NULL; -} - -static inline struct net_device *dev_from_bucket(struct seq_file *seq, loff_t *pos) -{ - struct net_device *dev; - unsigned int bucket; - - do { - dev = dev_from_same_bucket(seq, pos); - if (dev) - return dev; - - bucket = get_bucket(*pos) + 1; - *pos = set_bucket_offset(bucket, 1); - } while (bucket < NETDEV_HASHENTRIES); - - return NULL; -} - -/* - * This is invoked by the /proc filesystem handler to display a device - * in detail. - */ -static void *dev_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(RCU) -{ - rcu_read_lock(); - if (!*pos) - return SEQ_START_TOKEN; - - if (get_bucket(*pos) >= NETDEV_HASHENTRIES) - return NULL; - - return dev_from_bucket(seq, pos); -} - -static void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - ++*pos; - return dev_from_bucket(seq, pos); -} - -static void dev_seq_stop(struct seq_file *seq, void *v) - __releases(RCU) -{ - rcu_read_unlock(); -} - -static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev) -{ - struct rtnl_link_stats64 temp; - const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp); - - seq_printf(seq, "%6s: %7llu %7llu %4llu %4llu %4llu %5llu %10llu %9llu " - "%8llu %7llu %4llu %4llu %4llu %5llu %7llu %10llu\n", - dev->name, stats->rx_bytes, stats->rx_packets, - stats->rx_errors, - stats->rx_dropped + stats->rx_missed_errors, - stats->rx_fifo_errors, - stats->rx_length_errors + stats->rx_over_errors + - stats->rx_crc_errors + stats->rx_frame_errors, - stats->rx_compressed, stats->multicast, - stats->tx_bytes, stats->tx_packets, - stats->tx_errors, stats->tx_dropped, - stats->tx_fifo_errors, stats->collisions, - stats->tx_carrier_errors + - stats->tx_aborted_errors + - stats->tx_window_errors + - stats->tx_heartbeat_errors, - stats->tx_compressed); -} - -/* - * Called from the PROCfs module. This now uses the new arbitrary sized - * /proc/net interface to create /proc/net/dev - */ -static int dev_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) - seq_puts(seq, "Inter-| Receive " - " | Transmit\n" - " face |bytes packets errs drop fifo frame " - "compressed multicast|bytes packets errs " - "drop fifo colls carrier compressed\n"); - else - dev_seq_printf_stats(seq, v); - return 0; -} - -static struct softnet_data *softnet_get_online(loff_t *pos) -{ - struct softnet_data *sd = NULL; - - while (*pos < nr_cpu_ids) - if (cpu_online(*pos)) { - sd = &per_cpu(softnet_data, *pos); - break; - } else - ++*pos; - return sd; -} - -static void *softnet_seq_start(struct seq_file *seq, loff_t *pos) -{ - return softnet_get_online(pos); -} - -static void *softnet_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - ++*pos; - return softnet_get_online(pos); -} - -static void softnet_seq_stop(struct seq_file *seq, void *v) -{ -} - -static int softnet_seq_show(struct seq_file *seq, void *v) -{ - struct softnet_data *sd = v; - unsigned int flow_limit_count = 0; - -#ifdef CONFIG_NET_FLOW_LIMIT - struct sd_flow_limit *fl; - - rcu_read_lock(); - fl = rcu_dereference(sd->flow_limit); - if (fl) - flow_limit_count = fl->count; - rcu_read_unlock(); -#endif - - seq_printf(seq, - "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n", - sd->processed, sd->dropped, sd->time_squeeze, 0, - 0, 0, 0, 0, /* was fastroute */ - 0, /* was cpu_collision */ - sd->received_rps, flow_limit_count); - return 0; -} - -static const struct seq_operations dev_seq_ops = { - .start = dev_seq_start, - .next = dev_seq_next, - .stop = dev_seq_stop, - .show = dev_seq_show, -}; - -static int dev_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &dev_seq_ops, - sizeof(struct seq_net_private)); -} - -static const struct file_operations dev_seq_fops = { - .owner = THIS_MODULE, - .open = dev_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -static const struct seq_operations softnet_seq_ops = { - .start = softnet_seq_start, - .next = softnet_seq_next, - .stop = softnet_seq_stop, - .show = softnet_seq_show, -}; - -static int softnet_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &softnet_seq_ops); -} - -static const struct file_operations softnet_seq_fops = { - .owner = THIS_MODULE, - .open = softnet_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -static void *ptype_get_idx(loff_t pos) -{ - struct packet_type *pt = NULL; - loff_t i = 0; - int t; - - list_for_each_entry_rcu(pt, &ptype_all, list) { - if (i == pos) - return pt; - ++i; - } - - for (t = 0; t < PTYPE_HASH_SIZE; t++) { - list_for_each_entry_rcu(pt, &ptype_base[t], list) { - if (i == pos) - return pt; - ++i; - } - } - return NULL; -} - -static void *ptype_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(RCU) -{ - rcu_read_lock(); - return *pos ? ptype_get_idx(*pos - 1) : SEQ_START_TOKEN; -} - -static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct packet_type *pt; - struct list_head *nxt; - int hash; - - ++*pos; - if (v == SEQ_START_TOKEN) - return ptype_get_idx(0); - - pt = v; - nxt = pt->list.next; - if (pt->type == htons(ETH_P_ALL)) { - if (nxt != &ptype_all) - goto found; - hash = 0; - nxt = ptype_base[0].next; - } else - hash = ntohs(pt->type) & PTYPE_HASH_MASK; - - while (nxt == &ptype_base[hash]) { - if (++hash >= PTYPE_HASH_SIZE) - return NULL; - nxt = ptype_base[hash].next; - } -found: - return list_entry(nxt, struct packet_type, list); -} - -static void ptype_seq_stop(struct seq_file *seq, void *v) - __releases(RCU) -{ - rcu_read_unlock(); -} - -static int ptype_seq_show(struct seq_file *seq, void *v) -{ - struct packet_type *pt = v; - - if (v == SEQ_START_TOKEN) - seq_puts(seq, "Type Device Function\n"); - else if (pt->dev == NULL || dev_net(pt->dev) == seq_file_net(seq)) { - if (pt->type == htons(ETH_P_ALL)) - seq_puts(seq, "ALL "); - else - seq_printf(seq, "%04x", ntohs(pt->type)); - - seq_printf(seq, " %-8s %pf\n", - pt->dev ? pt->dev->name : "", pt->func); - } - - return 0; -} - -static const struct seq_operations ptype_seq_ops = { - .start = ptype_seq_start, - .next = ptype_seq_next, - .stop = ptype_seq_stop, - .show = ptype_seq_show, -}; - -static int ptype_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &ptype_seq_ops, - sizeof(struct seq_net_private)); -} - -static const struct file_operations ptype_seq_fops = { - .owner = THIS_MODULE, - .open = ptype_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - - -static int __net_init dev_proc_net_init(struct net *net) -{ - int rc = -ENOMEM; - - if (!proc_create("dev", S_IRUGO, net->proc_net, &dev_seq_fops)) - goto out; - if (!proc_create("softnet_stat", S_IRUGO, net->proc_net, - &softnet_seq_fops)) - goto out_dev; - if (!proc_create("ptype", S_IRUGO, net->proc_net, &ptype_seq_fops)) - goto out_softnet; - - if (wext_proc_init(net)) - goto out_ptype; - rc = 0; -out: - return rc; -out_ptype: - remove_proc_entry("ptype", net->proc_net); -out_softnet: - remove_proc_entry("softnet_stat", net->proc_net); -out_dev: - remove_proc_entry("dev", net->proc_net); - goto out; -} - -static void __net_exit dev_proc_net_exit(struct net *net) -{ - wext_proc_exit(net); - - remove_proc_entry("ptype", net->proc_net); - remove_proc_entry("softnet_stat", net->proc_net); - remove_proc_entry("dev", net->proc_net); -} - -static struct pernet_operations __net_initdata dev_proc_ops = { - .init = dev_proc_net_init, - .exit = dev_proc_net_exit, -}; - -static int dev_mc_seq_show(struct seq_file *seq, void *v) -{ - struct netdev_hw_addr *ha; - struct net_device *dev = v; - - if (v == SEQ_START_TOKEN) - return 0; - - netif_addr_lock_bh(dev); - netdev_for_each_mc_addr(ha, dev) { - int i; - - seq_printf(seq, "%-4d %-15s %-5d %-5d ", dev->ifindex, - dev->name, ha->refcount, ha->global_use); - - for (i = 0; i < dev->addr_len; i++) - seq_printf(seq, "%02x", ha->addr[i]); - - seq_putc(seq, '\n'); - } - netif_addr_unlock_bh(dev); - return 0; -} - -static const struct seq_operations dev_mc_seq_ops = { - .start = dev_seq_start, - .next = dev_seq_next, - .stop = dev_seq_stop, - .show = dev_mc_seq_show, -}; - -static int dev_mc_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &dev_mc_seq_ops, - sizeof(struct seq_net_private)); -} - -static const struct file_operations dev_mc_seq_fops = { - .owner = THIS_MODULE, - .open = dev_mc_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -static int __net_init dev_mc_net_init(struct net *net) -{ - if (!proc_create("dev_mcast", 0, net->proc_net, &dev_mc_seq_fops)) - return -ENOMEM; - return 0; -} - -static void __net_exit dev_mc_net_exit(struct net *net) -{ - remove_proc_entry("dev_mcast", net->proc_net); -} - -static struct pernet_operations __net_initdata dev_mc_net_ops = { - .init = dev_mc_net_init, - .exit = dev_mc_net_exit, -}; - -int __init dev_proc_init(void) -{ - int ret = register_pernet_subsys(&dev_proc_ops); - if (!ret) - return register_pernet_subsys(&dev_mc_net_ops); - return ret; -} diff --git a/src/linux/net/core/net-sysfs.c b/src/linux/net/core/net-sysfs.c deleted file mode 100644 index 6e4f347..0000000 --- a/src/linux/net/core/net-sysfs.c +++ /dev/null @@ -1,1601 +0,0 @@ -/* - * net-sysfs.c - network device class and attributes - * - * Copyright (c) 2003 Stephen Hemminger - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "net-sysfs.h" - -#ifdef CONFIG_SYSFS -static const char fmt_hex[] = "%#x\n"; -static const char fmt_dec[] = "%d\n"; -static const char fmt_ulong[] = "%lu\n"; -static const char fmt_u64[] = "%llu\n"; - -static inline int dev_isalive(const struct net_device *dev) -{ - return dev->reg_state <= NETREG_REGISTERED; -} - -/* use same locking rules as GIF* ioctl's */ -static ssize_t netdev_show(const struct device *dev, - struct device_attribute *attr, char *buf, - ssize_t (*format)(const struct net_device *, char *)) -{ - struct net_device *ndev = to_net_dev(dev); - ssize_t ret = -EINVAL; - - read_lock(&dev_base_lock); - if (dev_isalive(ndev)) - ret = (*format)(ndev, buf); - read_unlock(&dev_base_lock); - - return ret; -} - -/* generate a show function for simple field */ -#define NETDEVICE_SHOW(field, format_string) \ -static ssize_t format_##field(const struct net_device *dev, char *buf) \ -{ \ - return sprintf(buf, format_string, dev->field); \ -} \ -static ssize_t field##_show(struct device *dev, \ - struct device_attribute *attr, char *buf) \ -{ \ - return netdev_show(dev, attr, buf, format_##field); \ -} \ - -#define NETDEVICE_SHOW_RO(field, format_string) \ -NETDEVICE_SHOW(field, format_string); \ -static DEVICE_ATTR_RO(field) - -#define NETDEVICE_SHOW_RW(field, format_string) \ -NETDEVICE_SHOW(field, format_string); \ -static DEVICE_ATTR_RW(field) - -/* use same locking and permission rules as SIF* ioctl's */ -static ssize_t netdev_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len, - int (*set)(struct net_device *, unsigned long)) -{ - struct net_device *netdev = to_net_dev(dev); - struct net *net = dev_net(netdev); - unsigned long new; - int ret = -EINVAL; - - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - return -EPERM; - - ret = kstrtoul(buf, 0, &new); - if (ret) - goto err; - - if (!rtnl_trylock()) - return restart_syscall(); - - if (dev_isalive(netdev)) { - if ((ret = (*set)(netdev, new)) == 0) - ret = len; - } - rtnl_unlock(); - err: - return ret; -} - -NETDEVICE_SHOW_RO(dev_id, fmt_hex); -NETDEVICE_SHOW_RO(dev_port, fmt_dec); -NETDEVICE_SHOW_RO(addr_assign_type, fmt_dec); -NETDEVICE_SHOW_RO(addr_len, fmt_dec); -NETDEVICE_SHOW_RO(ifindex, fmt_dec); -NETDEVICE_SHOW_RO(type, fmt_dec); -NETDEVICE_SHOW_RO(link_mode, fmt_dec); - -static ssize_t iflink_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct net_device *ndev = to_net_dev(dev); - - return sprintf(buf, fmt_dec, dev_get_iflink(ndev)); -} -static DEVICE_ATTR_RO(iflink); - -static ssize_t format_name_assign_type(const struct net_device *dev, char *buf) -{ - return sprintf(buf, fmt_dec, dev->name_assign_type); -} - -static ssize_t name_assign_type_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct net_device *ndev = to_net_dev(dev); - ssize_t ret = -EINVAL; - - if (ndev->name_assign_type != NET_NAME_UNKNOWN) - ret = netdev_show(dev, attr, buf, format_name_assign_type); - - return ret; -} -static DEVICE_ATTR_RO(name_assign_type); - -/* use same locking rules as GIFHWADDR ioctl's */ -static ssize_t address_show(struct device *dev, struct device_attribute *attr, - char *buf) -{ - struct net_device *ndev = to_net_dev(dev); - ssize_t ret = -EINVAL; - - read_lock(&dev_base_lock); - if (dev_isalive(ndev)) - ret = sysfs_format_mac(buf, ndev->dev_addr, ndev->addr_len); - read_unlock(&dev_base_lock); - return ret; -} -static DEVICE_ATTR_RO(address); - -static ssize_t broadcast_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct net_device *ndev = to_net_dev(dev); - if (dev_isalive(ndev)) - return sysfs_format_mac(buf, ndev->broadcast, ndev->addr_len); - return -EINVAL; -} -static DEVICE_ATTR_RO(broadcast); - -static int change_carrier(struct net_device *dev, unsigned long new_carrier) -{ - if (!netif_running(dev)) - return -EINVAL; - return dev_change_carrier(dev, (bool) new_carrier); -} - -static ssize_t carrier_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ - return netdev_store(dev, attr, buf, len, change_carrier); -} - -static ssize_t carrier_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct net_device *netdev = to_net_dev(dev); - if (netif_running(netdev)) { - return sprintf(buf, fmt_dec, !!netif_carrier_ok(netdev)); - } - return -EINVAL; -} -static DEVICE_ATTR_RW(carrier); - -static ssize_t speed_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct net_device *netdev = to_net_dev(dev); - int ret = -EINVAL; - - if (!rtnl_trylock()) - return restart_syscall(); - - if (netif_running(netdev)) { - struct ethtool_link_ksettings cmd; - - if (!__ethtool_get_link_ksettings(netdev, &cmd)) - ret = sprintf(buf, fmt_dec, cmd.base.speed); - } - rtnl_unlock(); - return ret; -} -static DEVICE_ATTR_RO(speed); - -static ssize_t duplex_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct net_device *netdev = to_net_dev(dev); - int ret = -EINVAL; - - if (!rtnl_trylock()) - return restart_syscall(); - - if (netif_running(netdev)) { - struct ethtool_link_ksettings cmd; - - if (!__ethtool_get_link_ksettings(netdev, &cmd)) { - const char *duplex; - - switch (cmd.base.duplex) { - case DUPLEX_HALF: - duplex = "half"; - break; - case DUPLEX_FULL: - duplex = "full"; - break; - default: - duplex = "unknown"; - break; - } - ret = sprintf(buf, "%s\n", duplex); - } - } - rtnl_unlock(); - return ret; -} -static DEVICE_ATTR_RO(duplex); - -static ssize_t dormant_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct net_device *netdev = to_net_dev(dev); - - if (netif_running(netdev)) - return sprintf(buf, fmt_dec, !!netif_dormant(netdev)); - - return -EINVAL; -} -static DEVICE_ATTR_RO(dormant); - -static const char *const operstates[] = { - "unknown", - "notpresent", /* currently unused */ - "down", - "lowerlayerdown", - "testing", /* currently unused */ - "dormant", - "up" -}; - -static ssize_t operstate_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - const struct net_device *netdev = to_net_dev(dev); - unsigned char operstate; - - read_lock(&dev_base_lock); - operstate = netdev->operstate; - if (!netif_running(netdev)) - operstate = IF_OPER_DOWN; - read_unlock(&dev_base_lock); - - if (operstate >= ARRAY_SIZE(operstates)) - return -EINVAL; /* should not happen */ - - return sprintf(buf, "%s\n", operstates[operstate]); -} -static DEVICE_ATTR_RO(operstate); - -static ssize_t carrier_changes_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct net_device *netdev = to_net_dev(dev); - return sprintf(buf, fmt_dec, - atomic_read(&netdev->carrier_changes)); -} -static DEVICE_ATTR_RO(carrier_changes); - -/* read-write attributes */ - -static int change_mtu(struct net_device *dev, unsigned long new_mtu) -{ - return dev_set_mtu(dev, (int) new_mtu); -} - -static ssize_t mtu_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ - return netdev_store(dev, attr, buf, len, change_mtu); -} -NETDEVICE_SHOW_RW(mtu, fmt_dec); - -static int change_flags(struct net_device *dev, unsigned long new_flags) -{ - return dev_change_flags(dev, (unsigned int) new_flags); -} - -static ssize_t flags_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ - return netdev_store(dev, attr, buf, len, change_flags); -} -NETDEVICE_SHOW_RW(flags, fmt_hex); - -static int change_tx_queue_len(struct net_device *dev, unsigned long new_len) -{ - int res, orig_len = dev->tx_queue_len; - - if (new_len != orig_len) { - dev->tx_queue_len = new_len; - res = call_netdevice_notifiers(NETDEV_CHANGE_TX_QUEUE_LEN, dev); - res = notifier_to_errno(res); - if (res) { - netdev_err(dev, - "refused to change device tx_queue_len\n"); - dev->tx_queue_len = orig_len; - return -EFAULT; - } - } - - return 0; -} - -static ssize_t tx_queue_len_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - return netdev_store(dev, attr, buf, len, change_tx_queue_len); -} -NETDEVICE_SHOW_RW(tx_queue_len, fmt_ulong); - -static int change_gro_flush_timeout(struct net_device *dev, unsigned long val) -{ - dev->gro_flush_timeout = val; - return 0; -} - -static ssize_t gro_flush_timeout_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - return netdev_store(dev, attr, buf, len, change_gro_flush_timeout); -} -NETDEVICE_SHOW_RW(gro_flush_timeout, fmt_ulong); - -static ssize_t ifalias_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ - struct net_device *netdev = to_net_dev(dev); - struct net *net = dev_net(netdev); - size_t count = len; - ssize_t ret; - - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - return -EPERM; - - /* ignore trailing newline */ - if (len > 0 && buf[len - 1] == '\n') - --count; - - if (!rtnl_trylock()) - return restart_syscall(); - ret = dev_set_alias(netdev, buf, count); - rtnl_unlock(); - - return ret < 0 ? ret : len; -} - -static ssize_t ifalias_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - const struct net_device *netdev = to_net_dev(dev); - ssize_t ret = 0; - - if (!rtnl_trylock()) - return restart_syscall(); - if (netdev->ifalias) - ret = sprintf(buf, "%s\n", netdev->ifalias); - rtnl_unlock(); - return ret; -} -static DEVICE_ATTR_RW(ifalias); - -static int change_group(struct net_device *dev, unsigned long new_group) -{ - dev_set_group(dev, (int) new_group); - return 0; -} - -static ssize_t group_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t len) -{ - return netdev_store(dev, attr, buf, len, change_group); -} -NETDEVICE_SHOW(group, fmt_dec); -static DEVICE_ATTR(netdev_group, S_IRUGO | S_IWUSR, group_show, group_store); - -static int change_proto_down(struct net_device *dev, unsigned long proto_down) -{ - return dev_change_proto_down(dev, (bool) proto_down); -} - -static ssize_t proto_down_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t len) -{ - return netdev_store(dev, attr, buf, len, change_proto_down); -} -NETDEVICE_SHOW_RW(proto_down, fmt_dec); - -static ssize_t phys_port_id_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct net_device *netdev = to_net_dev(dev); - ssize_t ret = -EINVAL; - - if (!rtnl_trylock()) - return restart_syscall(); - - if (dev_isalive(netdev)) { - struct netdev_phys_item_id ppid; - - ret = dev_get_phys_port_id(netdev, &ppid); - if (!ret) - ret = sprintf(buf, "%*phN\n", ppid.id_len, ppid.id); - } - rtnl_unlock(); - - return ret; -} -static DEVICE_ATTR_RO(phys_port_id); - -static ssize_t phys_port_name_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct net_device *netdev = to_net_dev(dev); - ssize_t ret = -EINVAL; - - if (!rtnl_trylock()) - return restart_syscall(); - - if (dev_isalive(netdev)) { - char name[IFNAMSIZ]; - - ret = dev_get_phys_port_name(netdev, name, sizeof(name)); - if (!ret) - ret = sprintf(buf, "%s\n", name); - } - rtnl_unlock(); - - return ret; -} -static DEVICE_ATTR_RO(phys_port_name); - -static ssize_t phys_switch_id_show(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct net_device *netdev = to_net_dev(dev); - ssize_t ret = -EINVAL; - - if (!rtnl_trylock()) - return restart_syscall(); - - if (dev_isalive(netdev)) { - struct switchdev_attr attr = { - .orig_dev = netdev, - .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID, - .flags = SWITCHDEV_F_NO_RECURSE, - }; - - ret = switchdev_port_attr_get(netdev, &attr); - if (!ret) - ret = sprintf(buf, "%*phN\n", attr.u.ppid.id_len, - attr.u.ppid.id); - } - rtnl_unlock(); - - return ret; -} -static DEVICE_ATTR_RO(phys_switch_id); - -static struct attribute *net_class_attrs[] = { - &dev_attr_netdev_group.attr, - &dev_attr_type.attr, - &dev_attr_dev_id.attr, - &dev_attr_dev_port.attr, - &dev_attr_iflink.attr, - &dev_attr_ifindex.attr, - &dev_attr_name_assign_type.attr, - &dev_attr_addr_assign_type.attr, - &dev_attr_addr_len.attr, - &dev_attr_link_mode.attr, - &dev_attr_address.attr, - &dev_attr_broadcast.attr, - &dev_attr_speed.attr, - &dev_attr_duplex.attr, - &dev_attr_dormant.attr, - &dev_attr_operstate.attr, - &dev_attr_carrier_changes.attr, - &dev_attr_ifalias.attr, - &dev_attr_carrier.attr, - &dev_attr_mtu.attr, - &dev_attr_flags.attr, - &dev_attr_tx_queue_len.attr, - &dev_attr_gro_flush_timeout.attr, - &dev_attr_phys_port_id.attr, - &dev_attr_phys_port_name.attr, - &dev_attr_phys_switch_id.attr, - &dev_attr_proto_down.attr, - NULL, -}; -ATTRIBUTE_GROUPS(net_class); - -/* Show a given an attribute in the statistics group */ -static ssize_t netstat_show(const struct device *d, - struct device_attribute *attr, char *buf, - unsigned long offset) -{ - struct net_device *dev = to_net_dev(d); - ssize_t ret = -EINVAL; - - WARN_ON(offset > sizeof(struct rtnl_link_stats64) || - offset % sizeof(u64) != 0); - - read_lock(&dev_base_lock); - if (dev_isalive(dev)) { - struct rtnl_link_stats64 temp; - const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp); - - ret = sprintf(buf, fmt_u64, *(u64 *)(((u8 *) stats) + offset)); - } - read_unlock(&dev_base_lock); - return ret; -} - -/* generate a read-only statistics attribute */ -#define NETSTAT_ENTRY(name) \ -static ssize_t name##_show(struct device *d, \ - struct device_attribute *attr, char *buf) \ -{ \ - return netstat_show(d, attr, buf, \ - offsetof(struct rtnl_link_stats64, name)); \ -} \ -static DEVICE_ATTR_RO(name) - -NETSTAT_ENTRY(rx_packets); -NETSTAT_ENTRY(tx_packets); -NETSTAT_ENTRY(rx_bytes); -NETSTAT_ENTRY(tx_bytes); -NETSTAT_ENTRY(rx_errors); -NETSTAT_ENTRY(tx_errors); -NETSTAT_ENTRY(rx_dropped); -NETSTAT_ENTRY(tx_dropped); -NETSTAT_ENTRY(multicast); -NETSTAT_ENTRY(collisions); -NETSTAT_ENTRY(rx_length_errors); -NETSTAT_ENTRY(rx_over_errors); -NETSTAT_ENTRY(rx_crc_errors); -NETSTAT_ENTRY(rx_frame_errors); -NETSTAT_ENTRY(rx_fifo_errors); -NETSTAT_ENTRY(rx_missed_errors); -NETSTAT_ENTRY(tx_aborted_errors); -NETSTAT_ENTRY(tx_carrier_errors); -NETSTAT_ENTRY(tx_fifo_errors); -NETSTAT_ENTRY(tx_heartbeat_errors); -NETSTAT_ENTRY(tx_window_errors); -NETSTAT_ENTRY(rx_compressed); -NETSTAT_ENTRY(tx_compressed); -NETSTAT_ENTRY(rx_nohandler); - -static struct attribute *netstat_attrs[] = { - &dev_attr_rx_packets.attr, - &dev_attr_tx_packets.attr, - &dev_attr_rx_bytes.attr, - &dev_attr_tx_bytes.attr, - &dev_attr_rx_errors.attr, - &dev_attr_tx_errors.attr, - &dev_attr_rx_dropped.attr, - &dev_attr_tx_dropped.attr, - &dev_attr_multicast.attr, - &dev_attr_collisions.attr, - &dev_attr_rx_length_errors.attr, - &dev_attr_rx_over_errors.attr, - &dev_attr_rx_crc_errors.attr, - &dev_attr_rx_frame_errors.attr, - &dev_attr_rx_fifo_errors.attr, - &dev_attr_rx_missed_errors.attr, - &dev_attr_tx_aborted_errors.attr, - &dev_attr_tx_carrier_errors.attr, - &dev_attr_tx_fifo_errors.attr, - &dev_attr_tx_heartbeat_errors.attr, - &dev_attr_tx_window_errors.attr, - &dev_attr_rx_compressed.attr, - &dev_attr_tx_compressed.attr, - &dev_attr_rx_nohandler.attr, - NULL -}; - - -static struct attribute_group netstat_group = { - .name = "statistics", - .attrs = netstat_attrs, -}; - -#if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) -static struct attribute *wireless_attrs[] = { - NULL -}; - -static struct attribute_group wireless_group = { - .name = "wireless", - .attrs = wireless_attrs, -}; -#endif - -#else /* CONFIG_SYSFS */ -#define net_class_groups NULL -#endif /* CONFIG_SYSFS */ - -#ifdef CONFIG_SYSFS -#define to_rx_queue_attr(_attr) container_of(_attr, \ - struct rx_queue_attribute, attr) - -#define to_rx_queue(obj) container_of(obj, struct netdev_rx_queue, kobj) - -static ssize_t rx_queue_attr_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct rx_queue_attribute *attribute = to_rx_queue_attr(attr); - struct netdev_rx_queue *queue = to_rx_queue(kobj); - - if (!attribute->show) - return -EIO; - - return attribute->show(queue, attribute, buf); -} - -static ssize_t rx_queue_attr_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t count) -{ - struct rx_queue_attribute *attribute = to_rx_queue_attr(attr); - struct netdev_rx_queue *queue = to_rx_queue(kobj); - - if (!attribute->store) - return -EIO; - - return attribute->store(queue, attribute, buf, count); -} - -static const struct sysfs_ops rx_queue_sysfs_ops = { - .show = rx_queue_attr_show, - .store = rx_queue_attr_store, -}; - -#ifdef CONFIG_RPS -static ssize_t show_rps_map(struct netdev_rx_queue *queue, - struct rx_queue_attribute *attribute, char *buf) -{ - struct rps_map *map; - cpumask_var_t mask; - int i, len; - - if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) - return -ENOMEM; - - rcu_read_lock(); - map = rcu_dereference(queue->rps_map); - if (map) - for (i = 0; i < map->len; i++) - cpumask_set_cpu(map->cpus[i], mask); - - len = snprintf(buf, PAGE_SIZE, "%*pb\n", cpumask_pr_args(mask)); - rcu_read_unlock(); - free_cpumask_var(mask); - - return len < PAGE_SIZE ? len : -EINVAL; -} - -static ssize_t store_rps_map(struct netdev_rx_queue *queue, - struct rx_queue_attribute *attribute, - const char *buf, size_t len) -{ - struct rps_map *old_map, *map; - cpumask_var_t mask; - int err, cpu, i; - static DEFINE_MUTEX(rps_map_mutex); - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (!alloc_cpumask_var(&mask, GFP_KERNEL)) - return -ENOMEM; - - err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); - if (err) { - free_cpumask_var(mask); - return err; - } - - map = kzalloc(max_t(unsigned int, - RPS_MAP_SIZE(cpumask_weight(mask)), L1_CACHE_BYTES), - GFP_KERNEL); - if (!map) { - free_cpumask_var(mask); - return -ENOMEM; - } - - i = 0; - for_each_cpu_and(cpu, mask, cpu_online_mask) - map->cpus[i++] = cpu; - - if (i) - map->len = i; - else { - kfree(map); - map = NULL; - } - - mutex_lock(&rps_map_mutex); - old_map = rcu_dereference_protected(queue->rps_map, - mutex_is_locked(&rps_map_mutex)); - rcu_assign_pointer(queue->rps_map, map); - - if (map) - static_key_slow_inc(&rps_needed); - if (old_map) - static_key_slow_dec(&rps_needed); - - mutex_unlock(&rps_map_mutex); - - if (old_map) - kfree_rcu(old_map, rcu); - - free_cpumask_var(mask); - return len; -} - -static ssize_t show_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, - struct rx_queue_attribute *attr, - char *buf) -{ - struct rps_dev_flow_table *flow_table; - unsigned long val = 0; - - rcu_read_lock(); - flow_table = rcu_dereference(queue->rps_flow_table); - if (flow_table) - val = (unsigned long)flow_table->mask + 1; - rcu_read_unlock(); - - return sprintf(buf, "%lu\n", val); -} - -static void rps_dev_flow_table_release(struct rcu_head *rcu) -{ - struct rps_dev_flow_table *table = container_of(rcu, - struct rps_dev_flow_table, rcu); - vfree(table); -} - -static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, - struct rx_queue_attribute *attr, - const char *buf, size_t len) -{ - unsigned long mask, count; - struct rps_dev_flow_table *table, *old_table; - static DEFINE_SPINLOCK(rps_dev_flow_lock); - int rc; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - rc = kstrtoul(buf, 0, &count); - if (rc < 0) - return rc; - - if (count) { - mask = count - 1; - /* mask = roundup_pow_of_two(count) - 1; - * without overflows... - */ - while ((mask | (mask >> 1)) != mask) - mask |= (mask >> 1); - /* On 64 bit arches, must check mask fits in table->mask (u32), - * and on 32bit arches, must check - * RPS_DEV_FLOW_TABLE_SIZE(mask + 1) doesn't overflow. - */ -#if BITS_PER_LONG > 32 - if (mask > (unsigned long)(u32)mask) - return -EINVAL; -#else - if (mask > (ULONG_MAX - RPS_DEV_FLOW_TABLE_SIZE(1)) - / sizeof(struct rps_dev_flow)) { - /* Enforce a limit to prevent overflow */ - return -EINVAL; - } -#endif - table = vmalloc(RPS_DEV_FLOW_TABLE_SIZE(mask + 1)); - if (!table) - return -ENOMEM; - - table->mask = mask; - for (count = 0; count <= mask; count++) - table->flows[count].cpu = RPS_NO_CPU; - } else - table = NULL; - - spin_lock(&rps_dev_flow_lock); - old_table = rcu_dereference_protected(queue->rps_flow_table, - lockdep_is_held(&rps_dev_flow_lock)); - rcu_assign_pointer(queue->rps_flow_table, table); - spin_unlock(&rps_dev_flow_lock); - - if (old_table) - call_rcu(&old_table->rcu, rps_dev_flow_table_release); - - return len; -} - -static struct rx_queue_attribute rps_cpus_attribute = - __ATTR(rps_cpus, S_IRUGO | S_IWUSR, show_rps_map, store_rps_map); - - -static struct rx_queue_attribute rps_dev_flow_table_cnt_attribute = - __ATTR(rps_flow_cnt, S_IRUGO | S_IWUSR, - show_rps_dev_flow_table_cnt, store_rps_dev_flow_table_cnt); -#endif /* CONFIG_RPS */ - -static struct attribute *rx_queue_default_attrs[] = { -#ifdef CONFIG_RPS - &rps_cpus_attribute.attr, - &rps_dev_flow_table_cnt_attribute.attr, -#endif - NULL -}; - -static void rx_queue_release(struct kobject *kobj) -{ - struct netdev_rx_queue *queue = to_rx_queue(kobj); -#ifdef CONFIG_RPS - struct rps_map *map; - struct rps_dev_flow_table *flow_table; - - - map = rcu_dereference_protected(queue->rps_map, 1); - if (map) { - RCU_INIT_POINTER(queue->rps_map, NULL); - kfree_rcu(map, rcu); - } - - flow_table = rcu_dereference_protected(queue->rps_flow_table, 1); - if (flow_table) { - RCU_INIT_POINTER(queue->rps_flow_table, NULL); - call_rcu(&flow_table->rcu, rps_dev_flow_table_release); - } -#endif - - memset(kobj, 0, sizeof(*kobj)); - dev_put(queue->dev); -} - -static const void *rx_queue_namespace(struct kobject *kobj) -{ - struct netdev_rx_queue *queue = to_rx_queue(kobj); - struct device *dev = &queue->dev->dev; - const void *ns = NULL; - - if (dev->class && dev->class->ns_type) - ns = dev->class->namespace(dev); - - return ns; -} - -static struct kobj_type rx_queue_ktype = { - .sysfs_ops = &rx_queue_sysfs_ops, - .release = rx_queue_release, - .default_attrs = rx_queue_default_attrs, - .namespace = rx_queue_namespace -}; - -static int rx_queue_add_kobject(struct net_device *dev, int index) -{ - struct netdev_rx_queue *queue = dev->_rx + index; - struct kobject *kobj = &queue->kobj; - int error = 0; - - kobj->kset = dev->queues_kset; - error = kobject_init_and_add(kobj, &rx_queue_ktype, NULL, - "rx-%u", index); - if (error) - goto exit; - - if (dev->sysfs_rx_queue_group) { - error = sysfs_create_group(kobj, dev->sysfs_rx_queue_group); - if (error) - goto exit; - } - - kobject_uevent(kobj, KOBJ_ADD); - dev_hold(queue->dev); - - return error; -exit: - kobject_put(kobj); - return error; -} -#endif /* CONFIG_SYSFS */ - -int -net_rx_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) -{ -#ifdef CONFIG_SYSFS - int i; - int error = 0; - -#ifndef CONFIG_RPS - if (!dev->sysfs_rx_queue_group) - return 0; -#endif - for (i = old_num; i < new_num; i++) { - error = rx_queue_add_kobject(dev, i); - if (error) { - new_num = old_num; - break; - } - } - - while (--i >= new_num) { - if (dev->sysfs_rx_queue_group) - sysfs_remove_group(&dev->_rx[i].kobj, - dev->sysfs_rx_queue_group); - kobject_put(&dev->_rx[i].kobj); - } - - return error; -#else - return 0; -#endif -} - -#ifdef CONFIG_SYSFS -/* - * netdev_queue sysfs structures and functions. - */ -struct netdev_queue_attribute { - struct attribute attr; - ssize_t (*show)(struct netdev_queue *queue, - struct netdev_queue_attribute *attr, char *buf); - ssize_t (*store)(struct netdev_queue *queue, - struct netdev_queue_attribute *attr, const char *buf, size_t len); -}; -#define to_netdev_queue_attr(_attr) container_of(_attr, \ - struct netdev_queue_attribute, attr) - -#define to_netdev_queue(obj) container_of(obj, struct netdev_queue, kobj) - -static ssize_t netdev_queue_attr_show(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - struct netdev_queue_attribute *attribute = to_netdev_queue_attr(attr); - struct netdev_queue *queue = to_netdev_queue(kobj); - - if (!attribute->show) - return -EIO; - - return attribute->show(queue, attribute, buf); -} - -static ssize_t netdev_queue_attr_store(struct kobject *kobj, - struct attribute *attr, - const char *buf, size_t count) -{ - struct netdev_queue_attribute *attribute = to_netdev_queue_attr(attr); - struct netdev_queue *queue = to_netdev_queue(kobj); - - if (!attribute->store) - return -EIO; - - return attribute->store(queue, attribute, buf, count); -} - -static const struct sysfs_ops netdev_queue_sysfs_ops = { - .show = netdev_queue_attr_show, - .store = netdev_queue_attr_store, -}; - -static ssize_t show_trans_timeout(struct netdev_queue *queue, - struct netdev_queue_attribute *attribute, - char *buf) -{ - unsigned long trans_timeout; - - spin_lock_irq(&queue->_xmit_lock); - trans_timeout = queue->trans_timeout; - spin_unlock_irq(&queue->_xmit_lock); - - return sprintf(buf, "%lu", trans_timeout); -} - -#ifdef CONFIG_XPS -static unsigned int get_netdev_queue_index(struct netdev_queue *queue) -{ - struct net_device *dev = queue->dev; - unsigned int i; - - i = queue - dev->_tx; - BUG_ON(i >= dev->num_tx_queues); - - return i; -} - -static ssize_t show_tx_maxrate(struct netdev_queue *queue, - struct netdev_queue_attribute *attribute, - char *buf) -{ - return sprintf(buf, "%lu\n", queue->tx_maxrate); -} - -static ssize_t set_tx_maxrate(struct netdev_queue *queue, - struct netdev_queue_attribute *attribute, - const char *buf, size_t len) -{ - struct net_device *dev = queue->dev; - int err, index = get_netdev_queue_index(queue); - u32 rate = 0; - - err = kstrtou32(buf, 10, &rate); - if (err < 0) - return err; - - if (!rtnl_trylock()) - return restart_syscall(); - - err = -EOPNOTSUPP; - if (dev->netdev_ops->ndo_set_tx_maxrate) - err = dev->netdev_ops->ndo_set_tx_maxrate(dev, index, rate); - - rtnl_unlock(); - if (!err) { - queue->tx_maxrate = rate; - return len; - } - return err; -} - -static struct netdev_queue_attribute queue_tx_maxrate = - __ATTR(tx_maxrate, S_IRUGO | S_IWUSR, - show_tx_maxrate, set_tx_maxrate); -#endif - -static struct netdev_queue_attribute queue_trans_timeout = - __ATTR(tx_timeout, S_IRUGO, show_trans_timeout, NULL); - -#ifdef CONFIG_BQL -/* - * Byte queue limits sysfs structures and functions. - */ -static ssize_t bql_show(char *buf, unsigned int value) -{ - return sprintf(buf, "%u\n", value); -} - -static ssize_t bql_set(const char *buf, const size_t count, - unsigned int *pvalue) -{ - unsigned int value; - int err; - - if (!strcmp(buf, "max") || !strcmp(buf, "max\n")) - value = DQL_MAX_LIMIT; - else { - err = kstrtouint(buf, 10, &value); - if (err < 0) - return err; - if (value > DQL_MAX_LIMIT) - return -EINVAL; - } - - *pvalue = value; - - return count; -} - -static ssize_t bql_show_hold_time(struct netdev_queue *queue, - struct netdev_queue_attribute *attr, - char *buf) -{ - struct dql *dql = &queue->dql; - - return sprintf(buf, "%u\n", jiffies_to_msecs(dql->slack_hold_time)); -} - -static ssize_t bql_set_hold_time(struct netdev_queue *queue, - struct netdev_queue_attribute *attribute, - const char *buf, size_t len) -{ - struct dql *dql = &queue->dql; - unsigned int value; - int err; - - err = kstrtouint(buf, 10, &value); - if (err < 0) - return err; - - dql->slack_hold_time = msecs_to_jiffies(value); - - return len; -} - -static struct netdev_queue_attribute bql_hold_time_attribute = - __ATTR(hold_time, S_IRUGO | S_IWUSR, bql_show_hold_time, - bql_set_hold_time); - -static ssize_t bql_show_inflight(struct netdev_queue *queue, - struct netdev_queue_attribute *attr, - char *buf) -{ - struct dql *dql = &queue->dql; - - return sprintf(buf, "%u\n", dql->num_queued - dql->num_completed); -} - -static struct netdev_queue_attribute bql_inflight_attribute = - __ATTR(inflight, S_IRUGO, bql_show_inflight, NULL); - -#define BQL_ATTR(NAME, FIELD) \ -static ssize_t bql_show_ ## NAME(struct netdev_queue *queue, \ - struct netdev_queue_attribute *attr, \ - char *buf) \ -{ \ - return bql_show(buf, queue->dql.FIELD); \ -} \ - \ -static ssize_t bql_set_ ## NAME(struct netdev_queue *queue, \ - struct netdev_queue_attribute *attr, \ - const char *buf, size_t len) \ -{ \ - return bql_set(buf, len, &queue->dql.FIELD); \ -} \ - \ -static struct netdev_queue_attribute bql_ ## NAME ## _attribute = \ - __ATTR(NAME, S_IRUGO | S_IWUSR, bql_show_ ## NAME, \ - bql_set_ ## NAME); - -BQL_ATTR(limit, limit) -BQL_ATTR(limit_max, max_limit) -BQL_ATTR(limit_min, min_limit) - -static struct attribute *dql_attrs[] = { - &bql_limit_attribute.attr, - &bql_limit_max_attribute.attr, - &bql_limit_min_attribute.attr, - &bql_hold_time_attribute.attr, - &bql_inflight_attribute.attr, - NULL -}; - -static struct attribute_group dql_group = { - .name = "byte_queue_limits", - .attrs = dql_attrs, -}; -#endif /* CONFIG_BQL */ - -#ifdef CONFIG_XPS -static ssize_t show_xps_map(struct netdev_queue *queue, - struct netdev_queue_attribute *attribute, char *buf) -{ - struct net_device *dev = queue->dev; - struct xps_dev_maps *dev_maps; - cpumask_var_t mask; - unsigned long index; - int i, len; - - if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) - return -ENOMEM; - - index = get_netdev_queue_index(queue); - - rcu_read_lock(); - dev_maps = rcu_dereference(dev->xps_maps); - if (dev_maps) { - for_each_possible_cpu(i) { - struct xps_map *map = - rcu_dereference(dev_maps->cpu_map[i]); - if (map) { - int j; - for (j = 0; j < map->len; j++) { - if (map->queues[j] == index) { - cpumask_set_cpu(i, mask); - break; - } - } - } - } - } - rcu_read_unlock(); - - len = snprintf(buf, PAGE_SIZE, "%*pb\n", cpumask_pr_args(mask)); - free_cpumask_var(mask); - return len < PAGE_SIZE ? len : -EINVAL; -} - -static ssize_t store_xps_map(struct netdev_queue *queue, - struct netdev_queue_attribute *attribute, - const char *buf, size_t len) -{ - struct net_device *dev = queue->dev; - unsigned long index; - cpumask_var_t mask; - int err; - - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - - if (!alloc_cpumask_var(&mask, GFP_KERNEL)) - return -ENOMEM; - - index = get_netdev_queue_index(queue); - - err = bitmap_parse(buf, len, cpumask_bits(mask), nr_cpumask_bits); - if (err) { - free_cpumask_var(mask); - return err; - } - - err = netif_set_xps_queue(dev, mask, index); - - free_cpumask_var(mask); - - return err ? : len; -} - -static struct netdev_queue_attribute xps_cpus_attribute = - __ATTR(xps_cpus, S_IRUGO | S_IWUSR, show_xps_map, store_xps_map); -#endif /* CONFIG_XPS */ - -static struct attribute *netdev_queue_default_attrs[] = { - &queue_trans_timeout.attr, -#ifdef CONFIG_XPS - &xps_cpus_attribute.attr, - &queue_tx_maxrate.attr, -#endif - NULL -}; - -static void netdev_queue_release(struct kobject *kobj) -{ - struct netdev_queue *queue = to_netdev_queue(kobj); - - memset(kobj, 0, sizeof(*kobj)); - dev_put(queue->dev); -} - -static const void *netdev_queue_namespace(struct kobject *kobj) -{ - struct netdev_queue *queue = to_netdev_queue(kobj); - struct device *dev = &queue->dev->dev; - const void *ns = NULL; - - if (dev->class && dev->class->ns_type) - ns = dev->class->namespace(dev); - - return ns; -} - -static struct kobj_type netdev_queue_ktype = { - .sysfs_ops = &netdev_queue_sysfs_ops, - .release = netdev_queue_release, - .default_attrs = netdev_queue_default_attrs, - .namespace = netdev_queue_namespace, -}; - -static int netdev_queue_add_kobject(struct net_device *dev, int index) -{ - struct netdev_queue *queue = dev->_tx + index; - struct kobject *kobj = &queue->kobj; - int error = 0; - - kobj->kset = dev->queues_kset; - error = kobject_init_and_add(kobj, &netdev_queue_ktype, NULL, - "tx-%u", index); - if (error) - goto exit; - -#ifdef CONFIG_BQL - error = sysfs_create_group(kobj, &dql_group); - if (error) - goto exit; -#endif - - kobject_uevent(kobj, KOBJ_ADD); - dev_hold(queue->dev); - - return 0; -exit: - kobject_put(kobj); - return error; -} -#endif /* CONFIG_SYSFS */ - -int -netdev_queue_update_kobjects(struct net_device *dev, int old_num, int new_num) -{ -#ifdef CONFIG_SYSFS - int i; - int error = 0; - - for (i = old_num; i < new_num; i++) { - error = netdev_queue_add_kobject(dev, i); - if (error) { - new_num = old_num; - break; - } - } - - while (--i >= new_num) { - struct netdev_queue *queue = dev->_tx + i; - -#ifdef CONFIG_BQL - sysfs_remove_group(&queue->kobj, &dql_group); -#endif - kobject_put(&queue->kobj); - } - - return error; -#else - return 0; -#endif /* CONFIG_SYSFS */ -} - -static int register_queue_kobjects(struct net_device *dev) -{ - int error = 0, txq = 0, rxq = 0, real_rx = 0, real_tx = 0; - -#ifdef CONFIG_SYSFS - dev->queues_kset = kset_create_and_add("queues", - NULL, &dev->dev.kobj); - if (!dev->queues_kset) - return -ENOMEM; - real_rx = dev->real_num_rx_queues; -#endif - real_tx = dev->real_num_tx_queues; - - error = net_rx_queue_update_kobjects(dev, 0, real_rx); - if (error) - goto error; - rxq = real_rx; - - error = netdev_queue_update_kobjects(dev, 0, real_tx); - if (error) - goto error; - txq = real_tx; - - return 0; - -error: - netdev_queue_update_kobjects(dev, txq, 0); - net_rx_queue_update_kobjects(dev, rxq, 0); - return error; -} - -static void remove_queue_kobjects(struct net_device *dev) -{ - int real_rx = 0, real_tx = 0; - -#ifdef CONFIG_SYSFS - real_rx = dev->real_num_rx_queues; -#endif - real_tx = dev->real_num_tx_queues; - - net_rx_queue_update_kobjects(dev, real_rx, 0); - netdev_queue_update_kobjects(dev, real_tx, 0); -#ifdef CONFIG_SYSFS - kset_unregister(dev->queues_kset); -#endif -} - -static bool net_current_may_mount(void) -{ - struct net *net = current->nsproxy->net_ns; - - return ns_capable(net->user_ns, CAP_SYS_ADMIN); -} - -static void *net_grab_current_ns(void) -{ - struct net *ns = current->nsproxy->net_ns; -#ifdef CONFIG_NET_NS - if (ns) - atomic_inc(&ns->passive); -#endif - return ns; -} - -static const void *net_initial_ns(void) -{ - return &init_net; -} - -static const void *net_netlink_ns(struct sock *sk) -{ - return sock_net(sk); -} - -struct kobj_ns_type_operations net_ns_type_operations = { - .type = KOBJ_NS_TYPE_NET, - .current_may_mount = net_current_may_mount, - .grab_current_ns = net_grab_current_ns, - .netlink_ns = net_netlink_ns, - .initial_ns = net_initial_ns, - .drop_ns = net_drop_ns, -}; -EXPORT_SYMBOL_GPL(net_ns_type_operations); - -static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) -{ - struct net_device *dev = to_net_dev(d); - int retval; - - /* pass interface to uevent. */ - retval = add_uevent_var(env, "INTERFACE=%s", dev->name); - if (retval) - goto exit; - - /* pass ifindex to uevent. - * ifindex is useful as it won't change (interface name may change) - * and is what RtNetlink uses natively. */ - retval = add_uevent_var(env, "IFINDEX=%d", dev->ifindex); - -exit: - return retval; -} - -/* - * netdev_release -- destroy and free a dead device. - * Called when last reference to device kobject is gone. - */ -static void netdev_release(struct device *d) -{ - struct net_device *dev = to_net_dev(d); - - BUG_ON(dev->reg_state != NETREG_RELEASED); - - kfree(dev->ifalias); - netdev_freemem(dev); -} - -static const void *net_namespace(struct device *d) -{ - struct net_device *dev = to_net_dev(d); - - return dev_net(dev); -} - -static struct class net_class = { - .name = "net", - .dev_release = netdev_release, - .dev_groups = net_class_groups, - .dev_uevent = netdev_uevent, - .ns_type = &net_ns_type_operations, - .namespace = net_namespace, -}; - -#ifdef CONFIG_OF_NET -static int of_dev_node_match(struct device *dev, const void *data) -{ - int ret = 0; - - if (dev->parent) - ret = dev->parent->of_node == data; - - return ret == 0 ? dev->of_node == data : ret; -} - -/* - * of_find_net_device_by_node - lookup the net device for the device node - * @np: OF device node - * - * Looks up the net_device structure corresponding with the device node. - * If successful, returns a pointer to the net_device with the embedded - * struct device refcount incremented by one, or NULL on failure. The - * refcount must be dropped when done with the net_device. - */ -struct net_device *of_find_net_device_by_node(struct device_node *np) -{ - struct device *dev; - - dev = class_find_device(&net_class, NULL, np, of_dev_node_match); - if (!dev) - return NULL; - - return to_net_dev(dev); -} -EXPORT_SYMBOL(of_find_net_device_by_node); -#endif - -/* Delete sysfs entries but hold kobject reference until after all - * netdev references are gone. - */ -void netdev_unregister_kobject(struct net_device *ndev) -{ - struct device *dev = &(ndev->dev); - - kobject_get(&dev->kobj); - - remove_queue_kobjects(ndev); - - pm_runtime_set_memalloc_noio(dev, false); - - device_del(dev); -} - -/* Create sysfs entries for network device. */ -int netdev_register_kobject(struct net_device *ndev) -{ - struct device *dev = &(ndev->dev); - const struct attribute_group **groups = ndev->sysfs_groups; - int error = 0; - - device_initialize(dev); - dev->class = &net_class; - dev->platform_data = ndev; - dev->groups = groups; - - dev_set_name(dev, "%s", ndev->name); - -#ifdef CONFIG_SYSFS - /* Allow for a device specific group */ - if (*groups) - groups++; - - *groups++ = &netstat_group; - -#if IS_ENABLED(CONFIG_WIRELESS_EXT) || IS_ENABLED(CONFIG_CFG80211) - if (ndev->ieee80211_ptr) - *groups++ = &wireless_group; -#if IS_ENABLED(CONFIG_WIRELESS_EXT) - else if (ndev->wireless_handlers) - *groups++ = &wireless_group; -#endif -#endif -#endif /* CONFIG_SYSFS */ - - error = device_add(dev); - if (error) - return error; - - error = register_queue_kobjects(ndev); - if (error) { - device_del(dev); - return error; - } - - pm_runtime_set_memalloc_noio(dev, true); - - return error; -} - -int netdev_class_create_file_ns(struct class_attribute *class_attr, - const void *ns) -{ - return class_create_file_ns(&net_class, class_attr, ns); -} -EXPORT_SYMBOL(netdev_class_create_file_ns); - -void netdev_class_remove_file_ns(struct class_attribute *class_attr, - const void *ns) -{ - class_remove_file_ns(&net_class, class_attr, ns); -} -EXPORT_SYMBOL(netdev_class_remove_file_ns); - -int __init netdev_kobject_init(void) -{ - kobj_ns_type_register(&net_ns_type_operations); - return class_register(&net_class); -} diff --git a/src/linux/net/core/net-sysfs.h b/src/linux/net/core/net-sysfs.h deleted file mode 100644 index 2745a1b..0000000 --- a/src/linux/net/core/net-sysfs.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef __NET_SYSFS_H__ -#define __NET_SYSFS_H__ - -int __init netdev_kobject_init(void); -int netdev_register_kobject(struct net_device *); -void netdev_unregister_kobject(struct net_device *); -int net_rx_queue_update_kobjects(struct net_device *, int old_num, int new_num); -int netdev_queue_update_kobjects(struct net_device *net, - int old_num, int new_num); - -#endif diff --git a/src/linux/net/core/net_namespace.c b/src/linux/net/core/net_namespace.c deleted file mode 100644 index 7001da9..0000000 --- a/src/linux/net/core/net_namespace.c +++ /dev/null @@ -1,1047 +0,0 @@ -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Our network namespace constructor/destructor lists - */ - -static LIST_HEAD(pernet_list); -static struct list_head *first_device = &pernet_list; -DEFINE_MUTEX(net_mutex); - -LIST_HEAD(net_namespace_list); -EXPORT_SYMBOL_GPL(net_namespace_list); - -struct net init_net = { - .dev_base_head = LIST_HEAD_INIT(init_net.dev_base_head), -}; -EXPORT_SYMBOL(init_net); - -static bool init_net_initialized; - -#define INITIAL_NET_GEN_PTRS 13 /* +1 for len +2 for rcu_head */ - -static unsigned int max_gen_ptrs = INITIAL_NET_GEN_PTRS; - -static struct net_generic *net_alloc_generic(void) -{ - struct net_generic *ng; - size_t generic_size = offsetof(struct net_generic, ptr[max_gen_ptrs]); - - ng = kzalloc(generic_size, GFP_KERNEL); - if (ng) - ng->len = max_gen_ptrs; - - return ng; -} - -static int net_assign_generic(struct net *net, int id, void *data) -{ - struct net_generic *ng, *old_ng; - - BUG_ON(!mutex_is_locked(&net_mutex)); - BUG_ON(id == 0); - - old_ng = rcu_dereference_protected(net->gen, - lockdep_is_held(&net_mutex)); - ng = old_ng; - if (old_ng->len >= id) - goto assign; - - ng = net_alloc_generic(); - if (ng == NULL) - return -ENOMEM; - - /* - * Some synchronisation notes: - * - * The net_generic explores the net->gen array inside rcu - * read section. Besides once set the net->gen->ptr[x] - * pointer never changes (see rules in netns/generic.h). - * - * That said, we simply duplicate this array and schedule - * the old copy for kfree after a grace period. - */ - - memcpy(&ng->ptr, &old_ng->ptr, old_ng->len * sizeof(void*)); - - rcu_assign_pointer(net->gen, ng); - kfree_rcu(old_ng, rcu); -assign: - ng->ptr[id - 1] = data; - return 0; -} - -static int ops_init(const struct pernet_operations *ops, struct net *net) -{ - int err = -ENOMEM; - void *data = NULL; - - if (ops->id && ops->size) { - data = kzalloc(ops->size, GFP_KERNEL); - if (!data) - goto out; - - err = net_assign_generic(net, *ops->id, data); - if (err) - goto cleanup; - } - err = 0; - if (ops->init) - err = ops->init(net); - if (!err) - return 0; - -cleanup: - kfree(data); - -out: - return err; -} - -static void ops_free(const struct pernet_operations *ops, struct net *net) -{ - if (ops->id && ops->size) { - int id = *ops->id; - kfree(net_generic(net, id)); - } -} - -static void ops_exit_list(const struct pernet_operations *ops, - struct list_head *net_exit_list) -{ - struct net *net; - if (ops->exit) { - list_for_each_entry(net, net_exit_list, exit_list) - ops->exit(net); - } - if (ops->exit_batch) - ops->exit_batch(net_exit_list); -} - -static void ops_free_list(const struct pernet_operations *ops, - struct list_head *net_exit_list) -{ - struct net *net; - if (ops->size && ops->id) { - list_for_each_entry(net, net_exit_list, exit_list) - ops_free(ops, net); - } -} - -/* should be called with nsid_lock held */ -static int alloc_netid(struct net *net, struct net *peer, int reqid) -{ - int min = 0, max = 0; - - if (reqid >= 0) { - min = reqid; - max = reqid + 1; - } - - return idr_alloc(&net->netns_ids, peer, min, max, GFP_ATOMIC); -} - -/* This function is used by idr_for_each(). If net is equal to peer, the - * function returns the id so that idr_for_each() stops. Because we cannot - * returns the id 0 (idr_for_each() will not stop), we return the magic value - * NET_ID_ZERO (-1) for it. - */ -#define NET_ID_ZERO -1 -static int net_eq_idr(int id, void *net, void *peer) -{ - if (net_eq(net, peer)) - return id ? : NET_ID_ZERO; - return 0; -} - -/* Should be called with nsid_lock held. If a new id is assigned, the bool alloc - * is set to true, thus the caller knows that the new id must be notified via - * rtnl. - */ -static int __peernet2id_alloc(struct net *net, struct net *peer, bool *alloc) -{ - int id = idr_for_each(&net->netns_ids, net_eq_idr, peer); - bool alloc_it = *alloc; - - *alloc = false; - - /* Magic value for id 0. */ - if (id == NET_ID_ZERO) - return 0; - if (id > 0) - return id; - - if (alloc_it) { - id = alloc_netid(net, peer, -1); - *alloc = true; - return id >= 0 ? id : NETNSA_NSID_NOT_ASSIGNED; - } - - return NETNSA_NSID_NOT_ASSIGNED; -} - -/* should be called with nsid_lock held */ -static int __peernet2id(struct net *net, struct net *peer) -{ - bool no = false; - - return __peernet2id_alloc(net, peer, &no); -} - -static void rtnl_net_notifyid(struct net *net, int cmd, int id); -/* This function returns the id of a peer netns. If no id is assigned, one will - * be allocated and returned. - */ -int peernet2id_alloc(struct net *net, struct net *peer) -{ - unsigned long flags; - bool alloc; - int id; - - if (atomic_read(&net->count) == 0) - return NETNSA_NSID_NOT_ASSIGNED; - spin_lock_irqsave(&net->nsid_lock, flags); - alloc = atomic_read(&peer->count) == 0 ? false : true; - id = __peernet2id_alloc(net, peer, &alloc); - spin_unlock_irqrestore(&net->nsid_lock, flags); - if (alloc && id >= 0) - rtnl_net_notifyid(net, RTM_NEWNSID, id); - return id; -} - -/* This function returns, if assigned, the id of a peer netns. */ -int peernet2id(struct net *net, struct net *peer) -{ - unsigned long flags; - int id; - - spin_lock_irqsave(&net->nsid_lock, flags); - id = __peernet2id(net, peer); - spin_unlock_irqrestore(&net->nsid_lock, flags); - return id; -} -EXPORT_SYMBOL(peernet2id); - -/* This function returns true is the peer netns has an id assigned into the - * current netns. - */ -bool peernet_has_id(struct net *net, struct net *peer) -{ - return peernet2id(net, peer) >= 0; -} - -struct net *get_net_ns_by_id(struct net *net, int id) -{ - unsigned long flags; - struct net *peer; - - if (id < 0) - return NULL; - - rcu_read_lock(); - spin_lock_irqsave(&net->nsid_lock, flags); - peer = idr_find(&net->netns_ids, id); - if (peer) - get_net(peer); - spin_unlock_irqrestore(&net->nsid_lock, flags); - rcu_read_unlock(); - - return peer; -} - -/* - * setup_net runs the initializers for the network namespace object. - */ -static __net_init int setup_net(struct net *net, struct user_namespace *user_ns) -{ - /* Must be called with net_mutex held */ - const struct pernet_operations *ops, *saved_ops; - int error = 0; - LIST_HEAD(net_exit_list); - - atomic_set(&net->count, 1); - atomic_set(&net->passive, 1); - net->dev_base_seq = 1; - net->user_ns = user_ns; - idr_init(&net->netns_ids); - spin_lock_init(&net->nsid_lock); - - list_for_each_entry(ops, &pernet_list, list) { - error = ops_init(ops, net); - if (error < 0) - goto out_undo; - } -out: - return error; - -out_undo: - /* Walk through the list backwards calling the exit functions - * for the pernet modules whose init functions did not fail. - */ - list_add(&net->exit_list, &net_exit_list); - saved_ops = ops; - list_for_each_entry_continue_reverse(ops, &pernet_list, list) - ops_exit_list(ops, &net_exit_list); - - ops = saved_ops; - list_for_each_entry_continue_reverse(ops, &pernet_list, list) - ops_free_list(ops, &net_exit_list); - - rcu_barrier(); - goto out; -} - - -#ifdef CONFIG_NET_NS -static struct ucounts *inc_net_namespaces(struct user_namespace *ns) -{ - return inc_ucount(ns, current_euid(), UCOUNT_NET_NAMESPACES); -} - -static void dec_net_namespaces(struct ucounts *ucounts) -{ - dec_ucount(ucounts, UCOUNT_NET_NAMESPACES); -} - -static struct kmem_cache *net_cachep; -static struct workqueue_struct *netns_wq; - -static struct net *net_alloc(void) -{ - struct net *net = NULL; - struct net_generic *ng; - - ng = net_alloc_generic(); - if (!ng) - goto out; - - net = kmem_cache_zalloc(net_cachep, GFP_KERNEL); - if (!net) - goto out_free; - - rcu_assign_pointer(net->gen, ng); -out: - return net; - -out_free: - kfree(ng); - goto out; -} - -static void net_free(struct net *net) -{ - kfree(rcu_access_pointer(net->gen)); - kmem_cache_free(net_cachep, net); -} - -void net_drop_ns(void *p) -{ - struct net *ns = p; - if (ns && atomic_dec_and_test(&ns->passive)) - net_free(ns); -} - -struct net *copy_net_ns(unsigned long flags, - struct user_namespace *user_ns, struct net *old_net) -{ - struct ucounts *ucounts; - struct net *net; - int rv; - - if (!(flags & CLONE_NEWNET)) - return get_net(old_net); - - ucounts = inc_net_namespaces(user_ns); - if (!ucounts) - return ERR_PTR(-ENOSPC); - - net = net_alloc(); - if (!net) { - dec_net_namespaces(ucounts); - return ERR_PTR(-ENOMEM); - } - - get_user_ns(user_ns); - - mutex_lock(&net_mutex); - net->ucounts = ucounts; - rv = setup_net(net, user_ns); - if (rv == 0) { - rtnl_lock(); - list_add_tail_rcu(&net->list, &net_namespace_list); - rtnl_unlock(); - } - mutex_unlock(&net_mutex); - if (rv < 0) { - dec_net_namespaces(ucounts); - put_user_ns(user_ns); - net_drop_ns(net); - return ERR_PTR(rv); - } - return net; -} - -static DEFINE_SPINLOCK(cleanup_list_lock); -static LIST_HEAD(cleanup_list); /* Must hold cleanup_list_lock to touch */ - -static void cleanup_net(struct work_struct *work) -{ - const struct pernet_operations *ops; - struct net *net, *tmp; - struct list_head net_kill_list; - LIST_HEAD(net_exit_list); - - /* Atomically snapshot the list of namespaces to cleanup */ - spin_lock_irq(&cleanup_list_lock); - list_replace_init(&cleanup_list, &net_kill_list); - spin_unlock_irq(&cleanup_list_lock); - - mutex_lock(&net_mutex); - - /* Don't let anyone else find us. */ - rtnl_lock(); - list_for_each_entry(net, &net_kill_list, cleanup_list) { - list_del_rcu(&net->list); - list_add_tail(&net->exit_list, &net_exit_list); - for_each_net(tmp) { - int id; - - spin_lock_irq(&tmp->nsid_lock); - id = __peernet2id(tmp, net); - if (id >= 0) - idr_remove(&tmp->netns_ids, id); - spin_unlock_irq(&tmp->nsid_lock); - if (id >= 0) - rtnl_net_notifyid(tmp, RTM_DELNSID, id); - } - spin_lock_irq(&net->nsid_lock); - idr_destroy(&net->netns_ids); - spin_unlock_irq(&net->nsid_lock); - - } - rtnl_unlock(); - - /* - * Another CPU might be rcu-iterating the list, wait for it. - * This needs to be before calling the exit() notifiers, so - * the rcu_barrier() below isn't sufficient alone. - */ - synchronize_rcu(); - - /* Run all of the network namespace exit methods */ - list_for_each_entry_reverse(ops, &pernet_list, list) - ops_exit_list(ops, &net_exit_list); - - /* Free the net generic variables */ - list_for_each_entry_reverse(ops, &pernet_list, list) - ops_free_list(ops, &net_exit_list); - - mutex_unlock(&net_mutex); - - /* Ensure there are no outstanding rcu callbacks using this - * network namespace. - */ - rcu_barrier(); - - /* Finally it is safe to free my network namespace structure */ - list_for_each_entry_safe(net, tmp, &net_exit_list, exit_list) { - list_del_init(&net->exit_list); - dec_net_namespaces(net->ucounts); - put_user_ns(net->user_ns); - net_drop_ns(net); - } -} -static DECLARE_WORK(net_cleanup_work, cleanup_net); - -void __put_net(struct net *net) -{ - /* Cleanup the network namespace in process context */ - unsigned long flags; - - spin_lock_irqsave(&cleanup_list_lock, flags); - list_add(&net->cleanup_list, &cleanup_list); - spin_unlock_irqrestore(&cleanup_list_lock, flags); - - queue_work(netns_wq, &net_cleanup_work); -} -EXPORT_SYMBOL_GPL(__put_net); - -struct net *get_net_ns_by_fd(int fd) -{ - struct file *file; - struct ns_common *ns; - struct net *net; - - file = proc_ns_fget(fd); - if (IS_ERR(file)) - return ERR_CAST(file); - - ns = get_proc_ns(file_inode(file)); - if (ns->ops == &netns_operations) - net = get_net(container_of(ns, struct net, ns)); - else - net = ERR_PTR(-EINVAL); - - fput(file); - return net; -} - -#else -struct net *get_net_ns_by_fd(int fd) -{ - return ERR_PTR(-EINVAL); -} -#endif -EXPORT_SYMBOL_GPL(get_net_ns_by_fd); - -struct net *get_net_ns_by_pid(pid_t pid) -{ - struct task_struct *tsk; - struct net *net; - - /* Lookup the network namespace */ - net = ERR_PTR(-ESRCH); - rcu_read_lock(); - tsk = find_task_by_vpid(pid); - if (tsk) { - struct nsproxy *nsproxy; - task_lock(tsk); - nsproxy = tsk->nsproxy; - if (nsproxy) - net = get_net(nsproxy->net_ns); - task_unlock(tsk); - } - rcu_read_unlock(); - return net; -} -EXPORT_SYMBOL_GPL(get_net_ns_by_pid); - -static __net_init int net_ns_net_init(struct net *net) -{ -#ifdef CONFIG_NET_NS - net->ns.ops = &netns_operations; -#endif - return ns_alloc_inum(&net->ns); -} - -static __net_exit void net_ns_net_exit(struct net *net) -{ - ns_free_inum(&net->ns); -} - -static struct pernet_operations __net_initdata net_ns_ops = { - .init = net_ns_net_init, - .exit = net_ns_net_exit, -}; - -static const struct nla_policy rtnl_net_policy[NETNSA_MAX + 1] = { - [NETNSA_NONE] = { .type = NLA_UNSPEC }, - [NETNSA_NSID] = { .type = NLA_S32 }, - [NETNSA_PID] = { .type = NLA_U32 }, - [NETNSA_FD] = { .type = NLA_U32 }, -}; - -static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct nlattr *tb[NETNSA_MAX + 1]; - unsigned long flags; - struct net *peer; - int nsid, err; - - err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX, - rtnl_net_policy); - if (err < 0) - return err; - if (!tb[NETNSA_NSID]) - return -EINVAL; - nsid = nla_get_s32(tb[NETNSA_NSID]); - - if (tb[NETNSA_PID]) - peer = get_net_ns_by_pid(nla_get_u32(tb[NETNSA_PID])); - else if (tb[NETNSA_FD]) - peer = get_net_ns_by_fd(nla_get_u32(tb[NETNSA_FD])); - else - return -EINVAL; - if (IS_ERR(peer)) - return PTR_ERR(peer); - - spin_lock_irqsave(&net->nsid_lock, flags); - if (__peernet2id(net, peer) >= 0) { - spin_unlock_irqrestore(&net->nsid_lock, flags); - err = -EEXIST; - goto out; - } - - err = alloc_netid(net, peer, nsid); - spin_unlock_irqrestore(&net->nsid_lock, flags); - if (err >= 0) { - rtnl_net_notifyid(net, RTM_NEWNSID, err); - err = 0; - } -out: - put_net(peer); - return err; -} - -static int rtnl_net_get_size(void) -{ - return NLMSG_ALIGN(sizeof(struct rtgenmsg)) - + nla_total_size(sizeof(s32)) /* NETNSA_NSID */ - ; -} - -static int rtnl_net_fill(struct sk_buff *skb, u32 portid, u32 seq, int flags, - int cmd, struct net *net, int nsid) -{ - struct nlmsghdr *nlh; - struct rtgenmsg *rth; - - nlh = nlmsg_put(skb, portid, seq, cmd, sizeof(*rth), flags); - if (!nlh) - return -EMSGSIZE; - - rth = nlmsg_data(nlh); - rth->rtgen_family = AF_UNSPEC; - - if (nla_put_s32(skb, NETNSA_NSID, nsid)) - goto nla_put_failure; - - nlmsg_end(skb, nlh); - return 0; - -nla_put_failure: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct nlattr *tb[NETNSA_MAX + 1]; - struct sk_buff *msg; - struct net *peer; - int err, id; - - err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX, - rtnl_net_policy); - if (err < 0) - return err; - if (tb[NETNSA_PID]) - peer = get_net_ns_by_pid(nla_get_u32(tb[NETNSA_PID])); - else if (tb[NETNSA_FD]) - peer = get_net_ns_by_fd(nla_get_u32(tb[NETNSA_FD])); - else - return -EINVAL; - - if (IS_ERR(peer)) - return PTR_ERR(peer); - - msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL); - if (!msg) { - err = -ENOMEM; - goto out; - } - - id = peernet2id(net, peer); - err = rtnl_net_fill(msg, NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0, - RTM_NEWNSID, net, id); - if (err < 0) - goto err_out; - - err = rtnl_unicast(msg, net, NETLINK_CB(skb).portid); - goto out; - -err_out: - nlmsg_free(msg); -out: - put_net(peer); - return err; -} - -struct rtnl_net_dump_cb { - struct net *net; - struct sk_buff *skb; - struct netlink_callback *cb; - int idx; - int s_idx; -}; - -static int rtnl_net_dumpid_one(int id, void *peer, void *data) -{ - struct rtnl_net_dump_cb *net_cb = (struct rtnl_net_dump_cb *)data; - int ret; - - if (net_cb->idx < net_cb->s_idx) - goto cont; - - ret = rtnl_net_fill(net_cb->skb, NETLINK_CB(net_cb->cb->skb).portid, - net_cb->cb->nlh->nlmsg_seq, NLM_F_MULTI, - RTM_NEWNSID, net_cb->net, id); - if (ret < 0) - return ret; - -cont: - net_cb->idx++; - return 0; -} - -static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb) -{ - struct net *net = sock_net(skb->sk); - struct rtnl_net_dump_cb net_cb = { - .net = net, - .skb = skb, - .cb = cb, - .idx = 0, - .s_idx = cb->args[0], - }; - unsigned long flags; - - spin_lock_irqsave(&net->nsid_lock, flags); - idr_for_each(&net->netns_ids, rtnl_net_dumpid_one, &net_cb); - spin_unlock_irqrestore(&net->nsid_lock, flags); - - cb->args[0] = net_cb.idx; - return skb->len; -} - -static void rtnl_net_notifyid(struct net *net, int cmd, int id) -{ - struct sk_buff *msg; - int err = -ENOMEM; - - msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL); - if (!msg) - goto out; - - err = rtnl_net_fill(msg, 0, 0, 0, cmd, net, id); - if (err < 0) - goto err_out; - - rtnl_notify(msg, net, 0, RTNLGRP_NSID, NULL, 0); - return; - -err_out: - nlmsg_free(msg); -out: - rtnl_set_sk_err(net, RTNLGRP_NSID, err); -} - -static int __init net_ns_init(void) -{ - struct net_generic *ng; - -#ifdef CONFIG_NET_NS - net_cachep = kmem_cache_create("net_namespace", sizeof(struct net), - SMP_CACHE_BYTES, - SLAB_PANIC, NULL); - - /* Create workqueue for cleanup */ - netns_wq = create_singlethread_workqueue("netns"); - if (!netns_wq) - panic("Could not create netns workq"); -#endif - - ng = net_alloc_generic(); - if (!ng) - panic("Could not allocate generic netns"); - - rcu_assign_pointer(init_net.gen, ng); - - mutex_lock(&net_mutex); - if (setup_net(&init_net, &init_user_ns)) - panic("Could not setup the initial network namespace"); - - init_net_initialized = true; - - rtnl_lock(); - list_add_tail_rcu(&init_net.list, &net_namespace_list); - rtnl_unlock(); - - mutex_unlock(&net_mutex); - - register_pernet_subsys(&net_ns_ops); - - rtnl_register(PF_UNSPEC, RTM_NEWNSID, rtnl_net_newid, NULL, NULL); - rtnl_register(PF_UNSPEC, RTM_GETNSID, rtnl_net_getid, rtnl_net_dumpid, - NULL); - - return 0; -} - -pure_initcall(net_ns_init); - -#ifdef CONFIG_NET_NS -static int __register_pernet_operations(struct list_head *list, - struct pernet_operations *ops) -{ - struct net *net; - int error; - LIST_HEAD(net_exit_list); - - list_add_tail(&ops->list, list); - if (ops->init || (ops->id && ops->size)) { - for_each_net(net) { - error = ops_init(ops, net); - if (error) - goto out_undo; - list_add_tail(&net->exit_list, &net_exit_list); - } - } - return 0; - -out_undo: - /* If I have an error cleanup all namespaces I initialized */ - list_del(&ops->list); - ops_exit_list(ops, &net_exit_list); - ops_free_list(ops, &net_exit_list); - return error; -} - -static void __unregister_pernet_operations(struct pernet_operations *ops) -{ - struct net *net; - LIST_HEAD(net_exit_list); - - list_del(&ops->list); - for_each_net(net) - list_add_tail(&net->exit_list, &net_exit_list); - ops_exit_list(ops, &net_exit_list); - ops_free_list(ops, &net_exit_list); -} - -#else - -static int __register_pernet_operations(struct list_head *list, - struct pernet_operations *ops) -{ - if (!init_net_initialized) { - list_add_tail(&ops->list, list); - return 0; - } - - return ops_init(ops, &init_net); -} - -static void __unregister_pernet_operations(struct pernet_operations *ops) -{ - if (!init_net_initialized) { - list_del(&ops->list); - } else { - LIST_HEAD(net_exit_list); - list_add(&init_net.exit_list, &net_exit_list); - ops_exit_list(ops, &net_exit_list); - ops_free_list(ops, &net_exit_list); - } -} - -#endif /* CONFIG_NET_NS */ - -static DEFINE_IDA(net_generic_ids); - -static int register_pernet_operations(struct list_head *list, - struct pernet_operations *ops) -{ - int error; - - if (ops->id) { -again: - error = ida_get_new_above(&net_generic_ids, 1, ops->id); - if (error < 0) { - if (error == -EAGAIN) { - ida_pre_get(&net_generic_ids, GFP_KERNEL); - goto again; - } - return error; - } - max_gen_ptrs = max_t(unsigned int, max_gen_ptrs, *ops->id); - } - error = __register_pernet_operations(list, ops); - if (error) { - rcu_barrier(); - if (ops->id) - ida_remove(&net_generic_ids, *ops->id); - } - - return error; -} - -static void unregister_pernet_operations(struct pernet_operations *ops) -{ - - __unregister_pernet_operations(ops); - rcu_barrier(); - if (ops->id) - ida_remove(&net_generic_ids, *ops->id); -} - -/** - * register_pernet_subsys - register a network namespace subsystem - * @ops: pernet operations structure for the subsystem - * - * Register a subsystem which has init and exit functions - * that are called when network namespaces are created and - * destroyed respectively. - * - * When registered all network namespace init functions are - * called for every existing network namespace. Allowing kernel - * modules to have a race free view of the set of network namespaces. - * - * When a new network namespace is created all of the init - * methods are called in the order in which they were registered. - * - * When a network namespace is destroyed all of the exit methods - * are called in the reverse of the order with which they were - * registered. - */ -int register_pernet_subsys(struct pernet_operations *ops) -{ - int error; - mutex_lock(&net_mutex); - error = register_pernet_operations(first_device, ops); - mutex_unlock(&net_mutex); - return error; -} -EXPORT_SYMBOL_GPL(register_pernet_subsys); - -/** - * unregister_pernet_subsys - unregister a network namespace subsystem - * @ops: pernet operations structure to manipulate - * - * Remove the pernet operations structure from the list to be - * used when network namespaces are created or destroyed. In - * addition run the exit method for all existing network - * namespaces. - */ -void unregister_pernet_subsys(struct pernet_operations *ops) -{ - mutex_lock(&net_mutex); - unregister_pernet_operations(ops); - mutex_unlock(&net_mutex); -} -EXPORT_SYMBOL_GPL(unregister_pernet_subsys); - -/** - * register_pernet_device - register a network namespace device - * @ops: pernet operations structure for the subsystem - * - * Register a device which has init and exit functions - * that are called when network namespaces are created and - * destroyed respectively. - * - * When registered all network namespace init functions are - * called for every existing network namespace. Allowing kernel - * modules to have a race free view of the set of network namespaces. - * - * When a new network namespace is created all of the init - * methods are called in the order in which they were registered. - * - * When a network namespace is destroyed all of the exit methods - * are called in the reverse of the order with which they were - * registered. - */ -int register_pernet_device(struct pernet_operations *ops) -{ - int error; - mutex_lock(&net_mutex); - error = register_pernet_operations(&pernet_list, ops); - if (!error && (first_device == &pernet_list)) - first_device = &ops->list; - mutex_unlock(&net_mutex); - return error; -} -EXPORT_SYMBOL_GPL(register_pernet_device); - -/** - * unregister_pernet_device - unregister a network namespace netdevice - * @ops: pernet operations structure to manipulate - * - * Remove the pernet operations structure from the list to be - * used when network namespaces are created or destroyed. In - * addition run the exit method for all existing network - * namespaces. - */ -void unregister_pernet_device(struct pernet_operations *ops) -{ - mutex_lock(&net_mutex); - if (&ops->list == first_device) - first_device = first_device->next; - unregister_pernet_operations(ops); - mutex_unlock(&net_mutex); -} -EXPORT_SYMBOL_GPL(unregister_pernet_device); - -#ifdef CONFIG_NET_NS -static struct ns_common *netns_get(struct task_struct *task) -{ - struct net *net = NULL; - struct nsproxy *nsproxy; - - task_lock(task); - nsproxy = task->nsproxy; - if (nsproxy) - net = get_net(nsproxy->net_ns); - task_unlock(task); - - return net ? &net->ns : NULL; -} - -static inline struct net *to_net_ns(struct ns_common *ns) -{ - return container_of(ns, struct net, ns); -} - -static void netns_put(struct ns_common *ns) -{ - put_net(to_net_ns(ns)); -} - -static int netns_install(struct nsproxy *nsproxy, struct ns_common *ns) -{ - struct net *net = to_net_ns(ns); - - if (!ns_capable(net->user_ns, CAP_SYS_ADMIN) || - !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) - return -EPERM; - - put_net(nsproxy->net_ns); - nsproxy->net_ns = get_net(net); - return 0; -} - -static struct user_namespace *netns_owner(struct ns_common *ns) -{ - return to_net_ns(ns)->user_ns; -} - -const struct proc_ns_operations netns_operations = { - .name = "net", - .type = CLONE_NEWNET, - .get = netns_get, - .put = netns_put, - .install = netns_install, - .owner = netns_owner, -}; -#endif diff --git a/src/linux/net/core/netevent.c b/src/linux/net/core/netevent.c deleted file mode 100644 index 8b3bc4f..0000000 --- a/src/linux/net/core/netevent.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Network event notifiers - * - * Authors: - * Tom Tucker - * Steve Wise - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Fixes: - */ - -#include -#include -#include -#include - -static ATOMIC_NOTIFIER_HEAD(netevent_notif_chain); - -/** - * register_netevent_notifier - register a netevent notifier block - * @nb: notifier - * - * Register a notifier to be called when a netevent occurs. - * The notifier passed is linked into the kernel structures and must - * not be reused until it has been unregistered. A negative errno code - * is returned on a failure. - */ -int register_netevent_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&netevent_notif_chain, nb); -} -EXPORT_SYMBOL_GPL(register_netevent_notifier); - -/** - * netevent_unregister_notifier - unregister a netevent notifier block - * @nb: notifier - * - * Unregister a notifier previously registered by - * register_neigh_notifier(). The notifier is unlinked into the - * kernel structures and may then be reused. A negative errno code - * is returned on a failure. - */ - -int unregister_netevent_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&netevent_notif_chain, nb); -} -EXPORT_SYMBOL_GPL(unregister_netevent_notifier); - -/** - * call_netevent_notifiers - call all netevent notifier blocks - * @val: value passed unmodified to notifier function - * @v: pointer passed unmodified to notifier function - * - * Call all neighbour notifier blocks. Parameters and return value - * are as for notifier_call_chain(). - */ - -int call_netevent_notifiers(unsigned long val, void *v) -{ - return atomic_notifier_call_chain(&netevent_notif_chain, val, v); -} -EXPORT_SYMBOL_GPL(call_netevent_notifiers); diff --git a/src/linux/net/core/request_sock.c b/src/linux/net/core/request_sock.c deleted file mode 100644 index 5d26056..0000000 --- a/src/linux/net/core/request_sock.c +++ /dev/null @@ -1,138 +0,0 @@ -/* - * NET Generic infrastructure for Network protocols. - * - * Authors: Arnaldo Carvalho de Melo - * - * From code originally in include/net/tcp.h - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include - -#include - -/* - * Maximum number of SYN_RECV sockets in queue per LISTEN socket. - * One SYN_RECV socket costs about 80bytes on a 32bit machine. - * It would be better to replace it with a global counter for all sockets - * but then some measure against one socket starving all other sockets - * would be needed. - * - * The minimum value of it is 128. Experiments with real servers show that - * it is absolutely not enough even at 100conn/sec. 256 cures most - * of problems. - * This value is adjusted to 128 for low memory machines, - * and it will increase in proportion to the memory of machine. - * Note : Dont forget somaxconn that may limit backlog too. - */ -int sysctl_max_syn_backlog = 256; -EXPORT_SYMBOL(sysctl_max_syn_backlog); - -void reqsk_queue_alloc(struct request_sock_queue *queue) -{ - spin_lock_init(&queue->rskq_lock); - - spin_lock_init(&queue->fastopenq.lock); - queue->fastopenq.rskq_rst_head = NULL; - queue->fastopenq.rskq_rst_tail = NULL; - queue->fastopenq.qlen = 0; - - queue->rskq_accept_head = NULL; -} - -/* - * This function is called to set a Fast Open socket's "fastopen_rsk" field - * to NULL when a TFO socket no longer needs to access the request_sock. - * This happens only after 3WHS has been either completed or aborted (e.g., - * RST is received). - * - * Before TFO, a child socket is created only after 3WHS is completed, - * hence it never needs to access the request_sock. things get a lot more - * complex with TFO. A child socket, accepted or not, has to access its - * request_sock for 3WHS processing, e.g., to retransmit SYN-ACK pkts, - * until 3WHS is either completed or aborted. Afterwards the req will stay - * until either the child socket is accepted, or in the rare case when the - * listener is closed before the child is accepted. - * - * In short, a request socket is only freed after BOTH 3WHS has completed - * (or aborted) and the child socket has been accepted (or listener closed). - * When a child socket is accepted, its corresponding req->sk is set to - * NULL since it's no longer needed. More importantly, "req->sk == NULL" - * will be used by the code below to determine if a child socket has been - * accepted or not, and the check is protected by the fastopenq->lock - * described below. - * - * Note that fastopen_rsk is only accessed from the child socket's context - * with its socket lock held. But a request_sock (req) can be accessed by - * both its child socket through fastopen_rsk, and a listener socket through - * icsk_accept_queue.rskq_accept_head. To protect the access a simple spin - * lock per listener "icsk->icsk_accept_queue.fastopenq->lock" is created. - * only in the rare case when both the listener and the child locks are held, - * e.g., in inet_csk_listen_stop() do we not need to acquire the lock. - * The lock also protects other fields such as fastopenq->qlen, which is - * decremented by this function when fastopen_rsk is no longer needed. - * - * Note that another solution was to simply use the existing socket lock - * from the listener. But first socket lock is difficult to use. It is not - * a simple spin lock - one must consider sock_owned_by_user() and arrange - * to use sk_add_backlog() stuff. But what really makes it infeasible is the - * locking hierarchy violation. E.g., inet_csk_listen_stop() may try to - * acquire a child's lock while holding listener's socket lock. A corner - * case might also exist in tcp_v4_hnd_req() that will trigger this locking - * order. - * - * This function also sets "treq->tfo_listener" to false. - * treq->tfo_listener is used by the listener so it is protected by the - * fastopenq->lock in this function. - */ -void reqsk_fastopen_remove(struct sock *sk, struct request_sock *req, - bool reset) -{ - struct sock *lsk = req->rsk_listener; - struct fastopen_queue *fastopenq; - - fastopenq = &inet_csk(lsk)->icsk_accept_queue.fastopenq; - - tcp_sk(sk)->fastopen_rsk = NULL; - spin_lock_bh(&fastopenq->lock); - fastopenq->qlen--; - tcp_rsk(req)->tfo_listener = false; - if (req->sk) /* the child socket hasn't been accepted yet */ - goto out; - - if (!reset || lsk->sk_state != TCP_LISTEN) { - /* If the listener has been closed don't bother with the - * special RST handling below. - */ - spin_unlock_bh(&fastopenq->lock); - reqsk_put(req); - return; - } - /* Wait for 60secs before removing a req that has triggered RST. - * This is a simple defense against TFO spoofing attack - by - * counting the req against fastopen.max_qlen, and disabling - * TFO when the qlen exceeds max_qlen. - * - * For more details see CoNext'11 "TCP Fast Open" paper. - */ - req->rsk_timer.expires = jiffies + 60*HZ; - if (fastopenq->rskq_rst_head == NULL) - fastopenq->rskq_rst_head = req; - else - fastopenq->rskq_rst_tail->dl_next = req; - - req->dl_next = NULL; - fastopenq->rskq_rst_tail = req; - fastopenq->qlen++; -out: - spin_unlock_bh(&fastopenq->lock); -} diff --git a/src/linux/net/core/rtnetlink.c b/src/linux/net/core/rtnetlink.c deleted file mode 100644 index a6196cf..0000000 --- a/src/linux/net/core/rtnetlink.c +++ /dev/null @@ -1,4129 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Routing netlink socket interface: protocol independent part. - * - * Authors: Alexey Kuznetsov, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Fixes: - * Vitaly E. Lavrov RTA_OK arithmetics was wrong. - */ - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct rtnl_link { - rtnl_doit_func doit; - rtnl_dumpit_func dumpit; - rtnl_calcit_func calcit; -}; - -static DEFINE_MUTEX(rtnl_mutex); - -void rtnl_lock(void) -{ - mutex_lock(&rtnl_mutex); -} -EXPORT_SYMBOL(rtnl_lock); - -static struct sk_buff *defer_kfree_skb_list; -void rtnl_kfree_skbs(struct sk_buff *head, struct sk_buff *tail) -{ - if (head && tail) { - tail->next = defer_kfree_skb_list; - defer_kfree_skb_list = head; - } -} -EXPORT_SYMBOL(rtnl_kfree_skbs); - -void __rtnl_unlock(void) -{ - struct sk_buff *head = defer_kfree_skb_list; - - defer_kfree_skb_list = NULL; - - mutex_unlock(&rtnl_mutex); - - while (head) { - struct sk_buff *next = head->next; - - kfree_skb(head); - cond_resched(); - head = next; - } -} - -void rtnl_unlock(void) -{ - /* This fellow will unlock it for us. */ - netdev_run_todo(); -} -EXPORT_SYMBOL(rtnl_unlock); - -int rtnl_trylock(void) -{ - return mutex_trylock(&rtnl_mutex); -} -EXPORT_SYMBOL(rtnl_trylock); - -int rtnl_is_locked(void) -{ - return mutex_is_locked(&rtnl_mutex); -} -EXPORT_SYMBOL(rtnl_is_locked); - -#ifdef CONFIG_PROVE_LOCKING -bool lockdep_rtnl_is_held(void) -{ - return lockdep_is_held(&rtnl_mutex); -} -EXPORT_SYMBOL(lockdep_rtnl_is_held); -#endif /* #ifdef CONFIG_PROVE_LOCKING */ - -static struct rtnl_link *rtnl_msg_handlers[RTNL_FAMILY_MAX + 1]; - -static inline int rtm_msgindex(int msgtype) -{ - int msgindex = msgtype - RTM_BASE; - - /* - * msgindex < 0 implies someone tried to register a netlink - * control code. msgindex >= RTM_NR_MSGTYPES may indicate that - * the message type has not been added to linux/rtnetlink.h - */ - BUG_ON(msgindex < 0 || msgindex >= RTM_NR_MSGTYPES); - - return msgindex; -} - -static rtnl_doit_func rtnl_get_doit(int protocol, int msgindex) -{ - struct rtnl_link *tab; - - if (protocol <= RTNL_FAMILY_MAX) - tab = rtnl_msg_handlers[protocol]; - else - tab = NULL; - - if (tab == NULL || tab[msgindex].doit == NULL) - tab = rtnl_msg_handlers[PF_UNSPEC]; - - return tab[msgindex].doit; -} - -static rtnl_dumpit_func rtnl_get_dumpit(int protocol, int msgindex) -{ - struct rtnl_link *tab; - - if (protocol <= RTNL_FAMILY_MAX) - tab = rtnl_msg_handlers[protocol]; - else - tab = NULL; - - if (tab == NULL || tab[msgindex].dumpit == NULL) - tab = rtnl_msg_handlers[PF_UNSPEC]; - - return tab[msgindex].dumpit; -} - -static rtnl_calcit_func rtnl_get_calcit(int protocol, int msgindex) -{ - struct rtnl_link *tab; - - if (protocol <= RTNL_FAMILY_MAX) - tab = rtnl_msg_handlers[protocol]; - else - tab = NULL; - - if (tab == NULL || tab[msgindex].calcit == NULL) - tab = rtnl_msg_handlers[PF_UNSPEC]; - - return tab[msgindex].calcit; -} - -/** - * __rtnl_register - Register a rtnetlink message type - * @protocol: Protocol family or PF_UNSPEC - * @msgtype: rtnetlink message type - * @doit: Function pointer called for each request message - * @dumpit: Function pointer called for each dump request (NLM_F_DUMP) message - * @calcit: Function pointer to calc size of dump message - * - * Registers the specified function pointers (at least one of them has - * to be non-NULL) to be called whenever a request message for the - * specified protocol family and message type is received. - * - * The special protocol family PF_UNSPEC may be used to define fallback - * function pointers for the case when no entry for the specific protocol - * family exists. - * - * Returns 0 on success or a negative error code. - */ -int __rtnl_register(int protocol, int msgtype, - rtnl_doit_func doit, rtnl_dumpit_func dumpit, - rtnl_calcit_func calcit) -{ - struct rtnl_link *tab; - int msgindex; - - BUG_ON(protocol < 0 || protocol > RTNL_FAMILY_MAX); - msgindex = rtm_msgindex(msgtype); - - tab = rtnl_msg_handlers[protocol]; - if (tab == NULL) { - tab = kcalloc(RTM_NR_MSGTYPES, sizeof(*tab), GFP_KERNEL); - if (tab == NULL) - return -ENOBUFS; - - rtnl_msg_handlers[protocol] = tab; - } - - if (doit) - tab[msgindex].doit = doit; - - if (dumpit) - tab[msgindex].dumpit = dumpit; - - if (calcit) - tab[msgindex].calcit = calcit; - - return 0; -} -EXPORT_SYMBOL_GPL(__rtnl_register); - -/** - * rtnl_register - Register a rtnetlink message type - * - * Identical to __rtnl_register() but panics on failure. This is useful - * as failure of this function is very unlikely, it can only happen due - * to lack of memory when allocating the chain to store all message - * handlers for a protocol. Meant for use in init functions where lack - * of memory implies no sense in continuing. - */ -void rtnl_register(int protocol, int msgtype, - rtnl_doit_func doit, rtnl_dumpit_func dumpit, - rtnl_calcit_func calcit) -{ - if (__rtnl_register(protocol, msgtype, doit, dumpit, calcit) < 0) - panic("Unable to register rtnetlink message handler, " - "protocol = %d, message type = %d\n", - protocol, msgtype); -} -EXPORT_SYMBOL_GPL(rtnl_register); - -/** - * rtnl_unregister - Unregister a rtnetlink message type - * @protocol: Protocol family or PF_UNSPEC - * @msgtype: rtnetlink message type - * - * Returns 0 on success or a negative error code. - */ -int rtnl_unregister(int protocol, int msgtype) -{ - int msgindex; - - BUG_ON(protocol < 0 || protocol > RTNL_FAMILY_MAX); - msgindex = rtm_msgindex(msgtype); - - if (rtnl_msg_handlers[protocol] == NULL) - return -ENOENT; - - rtnl_msg_handlers[protocol][msgindex].doit = NULL; - rtnl_msg_handlers[protocol][msgindex].dumpit = NULL; - rtnl_msg_handlers[protocol][msgindex].calcit = NULL; - - return 0; -} -EXPORT_SYMBOL_GPL(rtnl_unregister); - -/** - * rtnl_unregister_all - Unregister all rtnetlink message type of a protocol - * @protocol : Protocol family or PF_UNSPEC - * - * Identical to calling rtnl_unregster() for all registered message types - * of a certain protocol family. - */ -void rtnl_unregister_all(int protocol) -{ - BUG_ON(protocol < 0 || protocol > RTNL_FAMILY_MAX); - - kfree(rtnl_msg_handlers[protocol]); - rtnl_msg_handlers[protocol] = NULL; -} -EXPORT_SYMBOL_GPL(rtnl_unregister_all); - -static LIST_HEAD(link_ops); - -static const struct rtnl_link_ops *rtnl_link_ops_get(const char *kind) -{ - const struct rtnl_link_ops *ops; - - list_for_each_entry(ops, &link_ops, list) { - if (!strcmp(ops->kind, kind)) - return ops; - } - return NULL; -} - -/** - * __rtnl_link_register - Register rtnl_link_ops with rtnetlink. - * @ops: struct rtnl_link_ops * to register - * - * The caller must hold the rtnl_mutex. This function should be used - * by drivers that create devices during module initialization. It - * must be called before registering the devices. - * - * Returns 0 on success or a negative error code. - */ -int __rtnl_link_register(struct rtnl_link_ops *ops) -{ - if (rtnl_link_ops_get(ops->kind)) - return -EEXIST; - - /* The check for setup is here because if ops - * does not have that filled up, it is not possible - * to use the ops for creating device. So do not - * fill up dellink as well. That disables rtnl_dellink. - */ - if (ops->setup && !ops->dellink) - ops->dellink = unregister_netdevice_queue; - - list_add_tail(&ops->list, &link_ops); - return 0; -} -EXPORT_SYMBOL_GPL(__rtnl_link_register); - -/** - * rtnl_link_register - Register rtnl_link_ops with rtnetlink. - * @ops: struct rtnl_link_ops * to register - * - * Returns 0 on success or a negative error code. - */ -int rtnl_link_register(struct rtnl_link_ops *ops) -{ - int err; - - rtnl_lock(); - err = __rtnl_link_register(ops); - rtnl_unlock(); - return err; -} -EXPORT_SYMBOL_GPL(rtnl_link_register); - -static void __rtnl_kill_links(struct net *net, struct rtnl_link_ops *ops) -{ - struct net_device *dev; - LIST_HEAD(list_kill); - - for_each_netdev(net, dev) { - if (dev->rtnl_link_ops == ops) - ops->dellink(dev, &list_kill); - } - unregister_netdevice_many(&list_kill); -} - -/** - * __rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink. - * @ops: struct rtnl_link_ops * to unregister - * - * The caller must hold the rtnl_mutex. - */ -void __rtnl_link_unregister(struct rtnl_link_ops *ops) -{ - struct net *net; - - for_each_net(net) { - __rtnl_kill_links(net, ops); - } - list_del(&ops->list); -} -EXPORT_SYMBOL_GPL(__rtnl_link_unregister); - -/* Return with the rtnl_lock held when there are no network - * devices unregistering in any network namespace. - */ -static void rtnl_lock_unregistering_all(void) -{ - struct net *net; - bool unregistering; - DEFINE_WAIT_FUNC(wait, woken_wake_function); - - add_wait_queue(&netdev_unregistering_wq, &wait); - for (;;) { - unregistering = false; - rtnl_lock(); - for_each_net(net) { - if (net->dev_unreg_count > 0) { - unregistering = true; - break; - } - } - if (!unregistering) - break; - __rtnl_unlock(); - - wait_woken(&wait, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT); - } - remove_wait_queue(&netdev_unregistering_wq, &wait); -} - -/** - * rtnl_link_unregister - Unregister rtnl_link_ops from rtnetlink. - * @ops: struct rtnl_link_ops * to unregister - */ -void rtnl_link_unregister(struct rtnl_link_ops *ops) -{ - /* Close the race with cleanup_net() */ - mutex_lock(&net_mutex); - rtnl_lock_unregistering_all(); - __rtnl_link_unregister(ops); - rtnl_unlock(); - mutex_unlock(&net_mutex); -} -EXPORT_SYMBOL_GPL(rtnl_link_unregister); - -static size_t rtnl_link_get_slave_info_data_size(const struct net_device *dev) -{ - struct net_device *master_dev; - const struct rtnl_link_ops *ops; - - master_dev = netdev_master_upper_dev_get((struct net_device *) dev); - if (!master_dev) - return 0; - ops = master_dev->rtnl_link_ops; - if (!ops || !ops->get_slave_size) - return 0; - /* IFLA_INFO_SLAVE_DATA + nested data */ - return nla_total_size(sizeof(struct nlattr)) + - ops->get_slave_size(master_dev, dev); -} - -static size_t rtnl_link_get_size(const struct net_device *dev) -{ - const struct rtnl_link_ops *ops = dev->rtnl_link_ops; - size_t size; - - if (!ops) - return 0; - - size = nla_total_size(sizeof(struct nlattr)) + /* IFLA_LINKINFO */ - nla_total_size(strlen(ops->kind) + 1); /* IFLA_INFO_KIND */ - - if (ops->get_size) - /* IFLA_INFO_DATA + nested data */ - size += nla_total_size(sizeof(struct nlattr)) + - ops->get_size(dev); - - if (ops->get_xstats_size) - /* IFLA_INFO_XSTATS */ - size += nla_total_size(ops->get_xstats_size(dev)); - - size += rtnl_link_get_slave_info_data_size(dev); - - return size; -} - -static LIST_HEAD(rtnl_af_ops); - -static const struct rtnl_af_ops *rtnl_af_lookup(const int family) -{ - const struct rtnl_af_ops *ops; - - list_for_each_entry(ops, &rtnl_af_ops, list) { - if (ops->family == family) - return ops; - } - - return NULL; -} - -/** - * rtnl_af_register - Register rtnl_af_ops with rtnetlink. - * @ops: struct rtnl_af_ops * to register - * - * Returns 0 on success or a negative error code. - */ -void rtnl_af_register(struct rtnl_af_ops *ops) -{ - rtnl_lock(); - list_add_tail(&ops->list, &rtnl_af_ops); - rtnl_unlock(); -} -EXPORT_SYMBOL_GPL(rtnl_af_register); - -/** - * __rtnl_af_unregister - Unregister rtnl_af_ops from rtnetlink. - * @ops: struct rtnl_af_ops * to unregister - * - * The caller must hold the rtnl_mutex. - */ -void __rtnl_af_unregister(struct rtnl_af_ops *ops) -{ - list_del(&ops->list); -} -EXPORT_SYMBOL_GPL(__rtnl_af_unregister); - -/** - * rtnl_af_unregister - Unregister rtnl_af_ops from rtnetlink. - * @ops: struct rtnl_af_ops * to unregister - */ -void rtnl_af_unregister(struct rtnl_af_ops *ops) -{ - rtnl_lock(); - __rtnl_af_unregister(ops); - rtnl_unlock(); -} -EXPORT_SYMBOL_GPL(rtnl_af_unregister); - -static size_t rtnl_link_get_af_size(const struct net_device *dev, - u32 ext_filter_mask) -{ - struct rtnl_af_ops *af_ops; - size_t size; - - /* IFLA_AF_SPEC */ - size = nla_total_size(sizeof(struct nlattr)); - - list_for_each_entry(af_ops, &rtnl_af_ops, list) { - if (af_ops->get_link_af_size) { - /* AF_* + nested data */ - size += nla_total_size(sizeof(struct nlattr)) + - af_ops->get_link_af_size(dev, ext_filter_mask); - } - } - - return size; -} - -static bool rtnl_have_link_slave_info(const struct net_device *dev) -{ - struct net_device *master_dev; - - master_dev = netdev_master_upper_dev_get((struct net_device *) dev); - if (master_dev && master_dev->rtnl_link_ops) - return true; - return false; -} - -static int rtnl_link_slave_info_fill(struct sk_buff *skb, - const struct net_device *dev) -{ - struct net_device *master_dev; - const struct rtnl_link_ops *ops; - struct nlattr *slave_data; - int err; - - master_dev = netdev_master_upper_dev_get((struct net_device *) dev); - if (!master_dev) - return 0; - ops = master_dev->rtnl_link_ops; - if (!ops) - return 0; - if (nla_put_string(skb, IFLA_INFO_SLAVE_KIND, ops->kind) < 0) - return -EMSGSIZE; - if (ops->fill_slave_info) { - slave_data = nla_nest_start(skb, IFLA_INFO_SLAVE_DATA); - if (!slave_data) - return -EMSGSIZE; - err = ops->fill_slave_info(skb, master_dev, dev); - if (err < 0) - goto err_cancel_slave_data; - nla_nest_end(skb, slave_data); - } - return 0; - -err_cancel_slave_data: - nla_nest_cancel(skb, slave_data); - return err; -} - -static int rtnl_link_info_fill(struct sk_buff *skb, - const struct net_device *dev) -{ - const struct rtnl_link_ops *ops = dev->rtnl_link_ops; - struct nlattr *data; - int err; - - if (!ops) - return 0; - if (nla_put_string(skb, IFLA_INFO_KIND, ops->kind) < 0) - return -EMSGSIZE; - if (ops->fill_xstats) { - err = ops->fill_xstats(skb, dev); - if (err < 0) - return err; - } - if (ops->fill_info) { - data = nla_nest_start(skb, IFLA_INFO_DATA); - if (data == NULL) - return -EMSGSIZE; - err = ops->fill_info(skb, dev); - if (err < 0) - goto err_cancel_data; - nla_nest_end(skb, data); - } - return 0; - -err_cancel_data: - nla_nest_cancel(skb, data); - return err; -} - -static int rtnl_link_fill(struct sk_buff *skb, const struct net_device *dev) -{ - struct nlattr *linkinfo; - int err = -EMSGSIZE; - - linkinfo = nla_nest_start(skb, IFLA_LINKINFO); - if (linkinfo == NULL) - goto out; - - err = rtnl_link_info_fill(skb, dev); - if (err < 0) - goto err_cancel_link; - - err = rtnl_link_slave_info_fill(skb, dev); - if (err < 0) - goto err_cancel_link; - - nla_nest_end(skb, linkinfo); - return 0; - -err_cancel_link: - nla_nest_cancel(skb, linkinfo); -out: - return err; -} - -int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned int group, int echo) -{ - struct sock *rtnl = net->rtnl; - int err = 0; - - NETLINK_CB(skb).dst_group = group; - if (echo) - atomic_inc(&skb->users); - netlink_broadcast(rtnl, skb, pid, group, GFP_KERNEL); - if (echo) - err = netlink_unicast(rtnl, skb, pid, MSG_DONTWAIT); - return err; -} - -int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid) -{ - struct sock *rtnl = net->rtnl; - - return nlmsg_unicast(rtnl, skb, pid); -} -EXPORT_SYMBOL(rtnl_unicast); - -void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group, - struct nlmsghdr *nlh, gfp_t flags) -{ - struct sock *rtnl = net->rtnl; - int report = 0; - - if (nlh) - report = nlmsg_report(nlh); - - nlmsg_notify(rtnl, skb, pid, group, report, flags); -} -EXPORT_SYMBOL(rtnl_notify); - -void rtnl_set_sk_err(struct net *net, u32 group, int error) -{ - struct sock *rtnl = net->rtnl; - - netlink_set_err(rtnl, 0, group, error); -} -EXPORT_SYMBOL(rtnl_set_sk_err); - -int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics) -{ - struct nlattr *mx; - int i, valid = 0; - - mx = nla_nest_start(skb, RTA_METRICS); - if (mx == NULL) - return -ENOBUFS; - - for (i = 0; i < RTAX_MAX; i++) { - if (metrics[i]) { - if (i == RTAX_CC_ALGO - 1) { - char tmp[TCP_CA_NAME_MAX], *name; - - name = tcp_ca_get_name_by_key(metrics[i], tmp); - if (!name) - continue; - if (nla_put_string(skb, i + 1, name)) - goto nla_put_failure; - } else if (i == RTAX_FEATURES - 1) { - u32 user_features = metrics[i] & RTAX_FEATURE_MASK; - - if (!user_features) - continue; - BUILD_BUG_ON(RTAX_FEATURE_MASK & DST_FEATURE_MASK); - if (nla_put_u32(skb, i + 1, user_features)) - goto nla_put_failure; - } else { - if (nla_put_u32(skb, i + 1, metrics[i])) - goto nla_put_failure; - } - valid++; - } - } - - if (!valid) { - nla_nest_cancel(skb, mx); - return 0; - } - - return nla_nest_end(skb, mx); - -nla_put_failure: - nla_nest_cancel(skb, mx); - return -EMSGSIZE; -} -EXPORT_SYMBOL(rtnetlink_put_metrics); - -int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst, u32 id, - long expires, u32 error) -{ - struct rta_cacheinfo ci = { - .rta_lastuse = jiffies_delta_to_clock_t(jiffies - dst->lastuse), - .rta_used = dst->__use, - .rta_clntref = atomic_read(&(dst->__refcnt)), - .rta_error = error, - .rta_id = id, - }; - - if (expires) { - unsigned long clock; - - clock = jiffies_to_clock_t(abs(expires)); - clock = min_t(unsigned long, clock, INT_MAX); - ci.rta_expires = (expires > 0) ? clock : -clock; - } - return nla_put(skb, RTA_CACHEINFO, sizeof(ci), &ci); -} -EXPORT_SYMBOL_GPL(rtnl_put_cacheinfo); - -static void set_operstate(struct net_device *dev, unsigned char transition) -{ - unsigned char operstate = dev->operstate; - - switch (transition) { - case IF_OPER_UP: - if ((operstate == IF_OPER_DORMANT || - operstate == IF_OPER_UNKNOWN) && - !netif_dormant(dev)) - operstate = IF_OPER_UP; - break; - - case IF_OPER_DORMANT: - if (operstate == IF_OPER_UP || - operstate == IF_OPER_UNKNOWN) - operstate = IF_OPER_DORMANT; - break; - } - - if (dev->operstate != operstate) { - write_lock_bh(&dev_base_lock); - dev->operstate = operstate; - write_unlock_bh(&dev_base_lock); - netdev_state_change(dev); - } -} - -static unsigned int rtnl_dev_get_flags(const struct net_device *dev) -{ - return (dev->flags & ~(IFF_PROMISC | IFF_ALLMULTI)) | - (dev->gflags & (IFF_PROMISC | IFF_ALLMULTI)); -} - -static unsigned int rtnl_dev_combine_flags(const struct net_device *dev, - const struct ifinfomsg *ifm) -{ - unsigned int flags = ifm->ifi_flags; - - /* bugwards compatibility: ifi_change == 0 is treated as ~0 */ - if (ifm->ifi_change) - flags = (flags & ifm->ifi_change) | - (rtnl_dev_get_flags(dev) & ~ifm->ifi_change); - - return flags; -} - -static void copy_rtnl_link_stats(struct rtnl_link_stats *a, - const struct rtnl_link_stats64 *b) -{ - a->rx_packets = b->rx_packets; - a->tx_packets = b->tx_packets; - a->rx_bytes = b->rx_bytes; - a->tx_bytes = b->tx_bytes; - a->rx_errors = b->rx_errors; - a->tx_errors = b->tx_errors; - a->rx_dropped = b->rx_dropped; - a->tx_dropped = b->tx_dropped; - - a->multicast = b->multicast; - a->collisions = b->collisions; - - a->rx_length_errors = b->rx_length_errors; - a->rx_over_errors = b->rx_over_errors; - a->rx_crc_errors = b->rx_crc_errors; - a->rx_frame_errors = b->rx_frame_errors; - a->rx_fifo_errors = b->rx_fifo_errors; - a->rx_missed_errors = b->rx_missed_errors; - - a->tx_aborted_errors = b->tx_aborted_errors; - a->tx_carrier_errors = b->tx_carrier_errors; - a->tx_fifo_errors = b->tx_fifo_errors; - a->tx_heartbeat_errors = b->tx_heartbeat_errors; - a->tx_window_errors = b->tx_window_errors; - - a->rx_compressed = b->rx_compressed; - a->tx_compressed = b->tx_compressed; - - a->rx_nohandler = b->rx_nohandler; -} - -/* All VF info */ -static inline int rtnl_vfinfo_size(const struct net_device *dev, - u32 ext_filter_mask) -{ - if (dev->dev.parent && dev_is_pci(dev->dev.parent) && - (ext_filter_mask & RTEXT_FILTER_VF)) { - int num_vfs = dev_num_vf(dev->dev.parent); - size_t size = nla_total_size(0); - size += num_vfs * - (nla_total_size(0) + - nla_total_size(sizeof(struct ifla_vf_mac)) + - nla_total_size(sizeof(struct ifla_vf_vlan)) + - nla_total_size(0) + /* nest IFLA_VF_VLAN_LIST */ - nla_total_size(MAX_VLAN_LIST_LEN * - sizeof(struct ifla_vf_vlan_info)) + - nla_total_size(sizeof(struct ifla_vf_spoofchk)) + - nla_total_size(sizeof(struct ifla_vf_tx_rate)) + - nla_total_size(sizeof(struct ifla_vf_rate)) + - nla_total_size(sizeof(struct ifla_vf_link_state)) + - nla_total_size(sizeof(struct ifla_vf_rss_query_en)) + - nla_total_size(0) + /* nest IFLA_VF_STATS */ - /* IFLA_VF_STATS_RX_PACKETS */ - nla_total_size_64bit(sizeof(__u64)) + - /* IFLA_VF_STATS_TX_PACKETS */ - nla_total_size_64bit(sizeof(__u64)) + - /* IFLA_VF_STATS_RX_BYTES */ - nla_total_size_64bit(sizeof(__u64)) + - /* IFLA_VF_STATS_TX_BYTES */ - nla_total_size_64bit(sizeof(__u64)) + - /* IFLA_VF_STATS_BROADCAST */ - nla_total_size_64bit(sizeof(__u64)) + - /* IFLA_VF_STATS_MULTICAST */ - nla_total_size_64bit(sizeof(__u64)) + - nla_total_size(sizeof(struct ifla_vf_trust))); - return size; - } else - return 0; -} - -static size_t rtnl_port_size(const struct net_device *dev, - u32 ext_filter_mask) -{ - size_t port_size = nla_total_size(4) /* PORT_VF */ - + nla_total_size(PORT_PROFILE_MAX) /* PORT_PROFILE */ - + nla_total_size(sizeof(struct ifla_port_vsi)) - /* PORT_VSI_TYPE */ - + nla_total_size(PORT_UUID_MAX) /* PORT_INSTANCE_UUID */ - + nla_total_size(PORT_UUID_MAX) /* PORT_HOST_UUID */ - + nla_total_size(1) /* PROT_VDP_REQUEST */ - + nla_total_size(2); /* PORT_VDP_RESPONSE */ - size_t vf_ports_size = nla_total_size(sizeof(struct nlattr)); - size_t vf_port_size = nla_total_size(sizeof(struct nlattr)) - + port_size; - size_t port_self_size = nla_total_size(sizeof(struct nlattr)) - + port_size; - - if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent || - !(ext_filter_mask & RTEXT_FILTER_VF)) - return 0; - if (dev_num_vf(dev->dev.parent)) - return port_self_size + vf_ports_size + - vf_port_size * dev_num_vf(dev->dev.parent); - else - return port_self_size; -} - -static size_t rtnl_xdp_size(const struct net_device *dev) -{ - size_t xdp_size = nla_total_size(0) + /* nest IFLA_XDP */ - nla_total_size(1); /* XDP_ATTACHED */ - - if (!dev->netdev_ops->ndo_xdp) - return 0; - else - return xdp_size; -} - -static noinline size_t if_nlmsg_size(const struct net_device *dev, - u32 ext_filter_mask) -{ - return NLMSG_ALIGN(sizeof(struct ifinfomsg)) - + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ - + nla_total_size(IFALIASZ) /* IFLA_IFALIAS */ - + nla_total_size(IFNAMSIZ) /* IFLA_QDISC */ - + nla_total_size_64bit(sizeof(struct rtnl_link_ifmap)) - + nla_total_size(sizeof(struct rtnl_link_stats)) - + nla_total_size_64bit(sizeof(struct rtnl_link_stats64)) - + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ - + nla_total_size(MAX_ADDR_LEN) /* IFLA_BROADCAST */ - + nla_total_size(4) /* IFLA_TXQLEN */ - + nla_total_size(4) /* IFLA_WEIGHT */ - + nla_total_size(4) /* IFLA_MTU */ - + nla_total_size(4) /* IFLA_LINK */ - + nla_total_size(4) /* IFLA_MASTER */ - + nla_total_size(1) /* IFLA_CARRIER */ - + nla_total_size(4) /* IFLA_PROMISCUITY */ - + nla_total_size(4) /* IFLA_NUM_TX_QUEUES */ - + nla_total_size(4) /* IFLA_NUM_RX_QUEUES */ - + nla_total_size(4) /* IFLA_GSO_MAX_SEGS */ - + nla_total_size(4) /* IFLA_GSO_MAX_SIZE */ - + nla_total_size(1) /* IFLA_OPERSTATE */ - + nla_total_size(1) /* IFLA_LINKMODE */ - + nla_total_size(4) /* IFLA_CARRIER_CHANGES */ - + nla_total_size(4) /* IFLA_LINK_NETNSID */ - + nla_total_size(ext_filter_mask - & RTEXT_FILTER_VF ? 4 : 0) /* IFLA_NUM_VF */ - + rtnl_vfinfo_size(dev, ext_filter_mask) /* IFLA_VFINFO_LIST */ - + rtnl_port_size(dev, ext_filter_mask) /* IFLA_VF_PORTS + IFLA_PORT_SELF */ - + rtnl_link_get_size(dev) /* IFLA_LINKINFO */ - + rtnl_link_get_af_size(dev, ext_filter_mask) /* IFLA_AF_SPEC */ - + nla_total_size(MAX_PHYS_ITEM_ID_LEN) /* IFLA_PHYS_PORT_ID */ - + nla_total_size(MAX_PHYS_ITEM_ID_LEN) /* IFLA_PHYS_SWITCH_ID */ - + nla_total_size(IFNAMSIZ) /* IFLA_PHYS_PORT_NAME */ - + rtnl_xdp_size(dev) /* IFLA_XDP */ - + nla_total_size(1); /* IFLA_PROTO_DOWN */ - -} - -static int rtnl_vf_ports_fill(struct sk_buff *skb, struct net_device *dev) -{ - struct nlattr *vf_ports; - struct nlattr *vf_port; - int vf; - int err; - - vf_ports = nla_nest_start(skb, IFLA_VF_PORTS); - if (!vf_ports) - return -EMSGSIZE; - - for (vf = 0; vf < dev_num_vf(dev->dev.parent); vf++) { - vf_port = nla_nest_start(skb, IFLA_VF_PORT); - if (!vf_port) - goto nla_put_failure; - if (nla_put_u32(skb, IFLA_PORT_VF, vf)) - goto nla_put_failure; - err = dev->netdev_ops->ndo_get_vf_port(dev, vf, skb); - if (err == -EMSGSIZE) - goto nla_put_failure; - if (err) { - nla_nest_cancel(skb, vf_port); - continue; - } - nla_nest_end(skb, vf_port); - } - - nla_nest_end(skb, vf_ports); - - return 0; - -nla_put_failure: - nla_nest_cancel(skb, vf_ports); - return -EMSGSIZE; -} - -static int rtnl_port_self_fill(struct sk_buff *skb, struct net_device *dev) -{ - struct nlattr *port_self; - int err; - - port_self = nla_nest_start(skb, IFLA_PORT_SELF); - if (!port_self) - return -EMSGSIZE; - - err = dev->netdev_ops->ndo_get_vf_port(dev, PORT_SELF_VF, skb); - if (err) { - nla_nest_cancel(skb, port_self); - return (err == -EMSGSIZE) ? err : 0; - } - - nla_nest_end(skb, port_self); - - return 0; -} - -static int rtnl_port_fill(struct sk_buff *skb, struct net_device *dev, - u32 ext_filter_mask) -{ - int err; - - if (!dev->netdev_ops->ndo_get_vf_port || !dev->dev.parent || - !(ext_filter_mask & RTEXT_FILTER_VF)) - return 0; - - err = rtnl_port_self_fill(skb, dev); - if (err) - return err; - - if (dev_num_vf(dev->dev.parent)) { - err = rtnl_vf_ports_fill(skb, dev); - if (err) - return err; - } - - return 0; -} - -static int rtnl_phys_port_id_fill(struct sk_buff *skb, struct net_device *dev) -{ - int err; - struct netdev_phys_item_id ppid; - - err = dev_get_phys_port_id(dev, &ppid); - if (err) { - if (err == -EOPNOTSUPP) - return 0; - return err; - } - - if (nla_put(skb, IFLA_PHYS_PORT_ID, ppid.id_len, ppid.id)) - return -EMSGSIZE; - - return 0; -} - -static int rtnl_phys_port_name_fill(struct sk_buff *skb, struct net_device *dev) -{ - char name[IFNAMSIZ]; - int err; - - err = dev_get_phys_port_name(dev, name, sizeof(name)); - if (err) { - if (err == -EOPNOTSUPP) - return 0; - return err; - } - - if (nla_put(skb, IFLA_PHYS_PORT_NAME, strlen(name), name)) - return -EMSGSIZE; - - return 0; -} - -static int rtnl_phys_switch_id_fill(struct sk_buff *skb, struct net_device *dev) -{ - int err; - struct switchdev_attr attr = { - .orig_dev = dev, - .id = SWITCHDEV_ATTR_ID_PORT_PARENT_ID, - .flags = SWITCHDEV_F_NO_RECURSE, - }; - - err = switchdev_port_attr_get(dev, &attr); - if (err) { - if (err == -EOPNOTSUPP) - return 0; - return err; - } - - if (nla_put(skb, IFLA_PHYS_SWITCH_ID, attr.u.ppid.id_len, - attr.u.ppid.id)) - return -EMSGSIZE; - - return 0; -} - -static noinline_for_stack int rtnl_fill_stats(struct sk_buff *skb, - struct net_device *dev) -{ - struct rtnl_link_stats64 *sp; - struct nlattr *attr; - - attr = nla_reserve_64bit(skb, IFLA_STATS64, - sizeof(struct rtnl_link_stats64), IFLA_PAD); - if (!attr) - return -EMSGSIZE; - - sp = nla_data(attr); - dev_get_stats(dev, sp); - - attr = nla_reserve(skb, IFLA_STATS, - sizeof(struct rtnl_link_stats)); - if (!attr) - return -EMSGSIZE; - - copy_rtnl_link_stats(nla_data(attr), sp); - - return 0; -} - -static noinline_for_stack int rtnl_fill_vfinfo(struct sk_buff *skb, - struct net_device *dev, - int vfs_num, - struct nlattr *vfinfo) -{ - struct ifla_vf_rss_query_en vf_rss_query_en; - struct nlattr *vf, *vfstats, *vfvlanlist; - struct ifla_vf_link_state vf_linkstate; - struct ifla_vf_vlan_info vf_vlan_info; - struct ifla_vf_spoofchk vf_spoofchk; - struct ifla_vf_tx_rate vf_tx_rate; - struct ifla_vf_stats vf_stats; - struct ifla_vf_trust vf_trust; - struct ifla_vf_vlan vf_vlan; - struct ifla_vf_rate vf_rate; - struct ifla_vf_mac vf_mac; - struct ifla_vf_info ivi; - - /* Not all SR-IOV capable drivers support the - * spoofcheck and "RSS query enable" query. Preset to - * -1 so the user space tool can detect that the driver - * didn't report anything. - */ - ivi.spoofchk = -1; - ivi.rss_query_en = -1; - ivi.trusted = -1; - memset(ivi.mac, 0, sizeof(ivi.mac)); - /* The default value for VF link state is "auto" - * IFLA_VF_LINK_STATE_AUTO which equals zero - */ - ivi.linkstate = 0; - /* VLAN Protocol by default is 802.1Q */ - ivi.vlan_proto = htons(ETH_P_8021Q); - if (dev->netdev_ops->ndo_get_vf_config(dev, vfs_num, &ivi)) - return 0; - - memset(&vf_vlan_info, 0, sizeof(vf_vlan_info)); - - vf_mac.vf = - vf_vlan.vf = - vf_vlan_info.vf = - vf_rate.vf = - vf_tx_rate.vf = - vf_spoofchk.vf = - vf_linkstate.vf = - vf_rss_query_en.vf = - vf_trust.vf = ivi.vf; - - memcpy(vf_mac.mac, ivi.mac, sizeof(ivi.mac)); - vf_vlan.vlan = ivi.vlan; - vf_vlan.qos = ivi.qos; - vf_vlan_info.vlan = ivi.vlan; - vf_vlan_info.qos = ivi.qos; - vf_vlan_info.vlan_proto = ivi.vlan_proto; - vf_tx_rate.rate = ivi.max_tx_rate; - vf_rate.min_tx_rate = ivi.min_tx_rate; - vf_rate.max_tx_rate = ivi.max_tx_rate; - vf_spoofchk.setting = ivi.spoofchk; - vf_linkstate.link_state = ivi.linkstate; - vf_rss_query_en.setting = ivi.rss_query_en; - vf_trust.setting = ivi.trusted; - vf = nla_nest_start(skb, IFLA_VF_INFO); - if (!vf) - goto nla_put_vfinfo_failure; - if (nla_put(skb, IFLA_VF_MAC, sizeof(vf_mac), &vf_mac) || - nla_put(skb, IFLA_VF_VLAN, sizeof(vf_vlan), &vf_vlan) || - nla_put(skb, IFLA_VF_RATE, sizeof(vf_rate), - &vf_rate) || - nla_put(skb, IFLA_VF_TX_RATE, sizeof(vf_tx_rate), - &vf_tx_rate) || - nla_put(skb, IFLA_VF_SPOOFCHK, sizeof(vf_spoofchk), - &vf_spoofchk) || - nla_put(skb, IFLA_VF_LINK_STATE, sizeof(vf_linkstate), - &vf_linkstate) || - nla_put(skb, IFLA_VF_RSS_QUERY_EN, - sizeof(vf_rss_query_en), - &vf_rss_query_en) || - nla_put(skb, IFLA_VF_TRUST, - sizeof(vf_trust), &vf_trust)) - goto nla_put_vf_failure; - vfvlanlist = nla_nest_start(skb, IFLA_VF_VLAN_LIST); - if (!vfvlanlist) - goto nla_put_vf_failure; - if (nla_put(skb, IFLA_VF_VLAN_INFO, sizeof(vf_vlan_info), - &vf_vlan_info)) { - nla_nest_cancel(skb, vfvlanlist); - goto nla_put_vf_failure; - } - nla_nest_end(skb, vfvlanlist); - memset(&vf_stats, 0, sizeof(vf_stats)); - if (dev->netdev_ops->ndo_get_vf_stats) - dev->netdev_ops->ndo_get_vf_stats(dev, vfs_num, - &vf_stats); - vfstats = nla_nest_start(skb, IFLA_VF_STATS); - if (!vfstats) - goto nla_put_vf_failure; - if (nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_PACKETS, - vf_stats.rx_packets, IFLA_VF_STATS_PAD) || - nla_put_u64_64bit(skb, IFLA_VF_STATS_TX_PACKETS, - vf_stats.tx_packets, IFLA_VF_STATS_PAD) || - nla_put_u64_64bit(skb, IFLA_VF_STATS_RX_BYTES, - vf_stats.rx_bytes, IFLA_VF_STATS_PAD) || - nla_put_u64_64bit(skb, IFLA_VF_STATS_TX_BYTES, - vf_stats.tx_bytes, IFLA_VF_STATS_PAD) || - nla_put_u64_64bit(skb, IFLA_VF_STATS_BROADCAST, - vf_stats.broadcast, IFLA_VF_STATS_PAD) || - nla_put_u64_64bit(skb, IFLA_VF_STATS_MULTICAST, - vf_stats.multicast, IFLA_VF_STATS_PAD)) { - nla_nest_cancel(skb, vfstats); - goto nla_put_vf_failure; - } - nla_nest_end(skb, vfstats); - nla_nest_end(skb, vf); - return 0; - -nla_put_vf_failure: - nla_nest_cancel(skb, vf); -nla_put_vfinfo_failure: - nla_nest_cancel(skb, vfinfo); - return -EMSGSIZE; -} - -static int rtnl_fill_link_ifmap(struct sk_buff *skb, struct net_device *dev) -{ - struct rtnl_link_ifmap map; - - memset(&map, 0, sizeof(map)); - map.mem_start = dev->mem_start; - map.mem_end = dev->mem_end; - map.base_addr = dev->base_addr; - map.irq = dev->irq; - map.dma = dev->dma; - map.port = dev->if_port; - - if (nla_put_64bit(skb, IFLA_MAP, sizeof(map), &map, IFLA_PAD)) - return -EMSGSIZE; - - return 0; -} - -static int rtnl_xdp_fill(struct sk_buff *skb, struct net_device *dev) -{ - struct netdev_xdp xdp_op = {}; - struct nlattr *xdp; - int err; - - if (!dev->netdev_ops->ndo_xdp) - return 0; - xdp = nla_nest_start(skb, IFLA_XDP); - if (!xdp) - return -EMSGSIZE; - xdp_op.command = XDP_QUERY_PROG; - err = dev->netdev_ops->ndo_xdp(dev, &xdp_op); - if (err) - goto err_cancel; - err = nla_put_u8(skb, IFLA_XDP_ATTACHED, xdp_op.prog_attached); - if (err) - goto err_cancel; - - nla_nest_end(skb, xdp); - return 0; - -err_cancel: - nla_nest_cancel(skb, xdp); - return err; -} - -static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, - int type, u32 pid, u32 seq, u32 change, - unsigned int flags, u32 ext_filter_mask) -{ - struct ifinfomsg *ifm; - struct nlmsghdr *nlh; - struct nlattr *af_spec; - struct rtnl_af_ops *af_ops; - struct net_device *upper_dev = netdev_master_upper_dev_get(dev); - - ASSERT_RTNL(); - nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags); - if (nlh == NULL) - return -EMSGSIZE; - - ifm = nlmsg_data(nlh); - ifm->ifi_family = AF_UNSPEC; - ifm->__ifi_pad = 0; - ifm->ifi_type = dev->type; - ifm->ifi_index = dev->ifindex; - ifm->ifi_flags = dev_get_flags(dev); - ifm->ifi_change = change; - - if (nla_put_string(skb, IFLA_IFNAME, dev->name) || - nla_put_u32(skb, IFLA_TXQLEN, dev->tx_queue_len) || - nla_put_u8(skb, IFLA_OPERSTATE, - netif_running(dev) ? dev->operstate : IF_OPER_DOWN) || - nla_put_u8(skb, IFLA_LINKMODE, dev->link_mode) || - nla_put_u32(skb, IFLA_MTU, dev->mtu) || - nla_put_u32(skb, IFLA_GROUP, dev->group) || - nla_put_u32(skb, IFLA_PROMISCUITY, dev->promiscuity) || - nla_put_u32(skb, IFLA_NUM_TX_QUEUES, dev->num_tx_queues) || - nla_put_u32(skb, IFLA_GSO_MAX_SEGS, dev->gso_max_segs) || - nla_put_u32(skb, IFLA_GSO_MAX_SIZE, dev->gso_max_size) || -#ifdef CONFIG_RPS - nla_put_u32(skb, IFLA_NUM_RX_QUEUES, dev->num_rx_queues) || -#endif - (dev->ifindex != dev_get_iflink(dev) && - nla_put_u32(skb, IFLA_LINK, dev_get_iflink(dev))) || - (upper_dev && - nla_put_u32(skb, IFLA_MASTER, upper_dev->ifindex)) || - nla_put_u8(skb, IFLA_CARRIER, netif_carrier_ok(dev)) || - (dev->qdisc && - nla_put_string(skb, IFLA_QDISC, dev->qdisc->ops->id)) || - (dev->ifalias && - nla_put_string(skb, IFLA_IFALIAS, dev->ifalias)) || - nla_put_u32(skb, IFLA_CARRIER_CHANGES, - atomic_read(&dev->carrier_changes)) || - nla_put_u8(skb, IFLA_PROTO_DOWN, dev->proto_down)) - goto nla_put_failure; - - if (rtnl_fill_link_ifmap(skb, dev)) - goto nla_put_failure; - - if (dev->addr_len) { - if (nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr) || - nla_put(skb, IFLA_BROADCAST, dev->addr_len, dev->broadcast)) - goto nla_put_failure; - } - - if (rtnl_phys_port_id_fill(skb, dev)) - goto nla_put_failure; - - if (rtnl_phys_port_name_fill(skb, dev)) - goto nla_put_failure; - - if (rtnl_phys_switch_id_fill(skb, dev)) - goto nla_put_failure; - - if (rtnl_fill_stats(skb, dev)) - goto nla_put_failure; - - if (dev->dev.parent && (ext_filter_mask & RTEXT_FILTER_VF) && - nla_put_u32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent))) - goto nla_put_failure; - - if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent && - ext_filter_mask & RTEXT_FILTER_VF) { - int i; - struct nlattr *vfinfo; - int num_vfs = dev_num_vf(dev->dev.parent); - - vfinfo = nla_nest_start(skb, IFLA_VFINFO_LIST); - if (!vfinfo) - goto nla_put_failure; - for (i = 0; i < num_vfs; i++) { - if (rtnl_fill_vfinfo(skb, dev, i, vfinfo)) - goto nla_put_failure; - } - - nla_nest_end(skb, vfinfo); - } - - if (rtnl_port_fill(skb, dev, ext_filter_mask)) - goto nla_put_failure; - - if (rtnl_xdp_fill(skb, dev)) - goto nla_put_failure; - - if (dev->rtnl_link_ops || rtnl_have_link_slave_info(dev)) { - if (rtnl_link_fill(skb, dev) < 0) - goto nla_put_failure; - } - - if (dev->rtnl_link_ops && - dev->rtnl_link_ops->get_link_net) { - struct net *link_net = dev->rtnl_link_ops->get_link_net(dev); - - if (!net_eq(dev_net(dev), link_net)) { - int id = peernet2id_alloc(dev_net(dev), link_net); - - if (nla_put_s32(skb, IFLA_LINK_NETNSID, id)) - goto nla_put_failure; - } - } - - if (!(af_spec = nla_nest_start(skb, IFLA_AF_SPEC))) - goto nla_put_failure; - - list_for_each_entry(af_ops, &rtnl_af_ops, list) { - if (af_ops->fill_link_af) { - struct nlattr *af; - int err; - - if (!(af = nla_nest_start(skb, af_ops->family))) - goto nla_put_failure; - - err = af_ops->fill_link_af(skb, dev, ext_filter_mask); - - /* - * Caller may return ENODATA to indicate that there - * was no data to be dumped. This is not an error, it - * means we should trim the attribute header and - * continue. - */ - if (err == -ENODATA) - nla_nest_cancel(skb, af); - else if (err < 0) - goto nla_put_failure; - - nla_nest_end(skb, af); - } - } - - nla_nest_end(skb, af_spec); - - nlmsg_end(skb, nlh); - return 0; - -nla_put_failure: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -static const struct nla_policy ifla_policy[IFLA_MAX+1] = { - [IFLA_IFNAME] = { .type = NLA_STRING, .len = IFNAMSIZ-1 }, - [IFLA_ADDRESS] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, - [IFLA_BROADCAST] = { .type = NLA_BINARY, .len = MAX_ADDR_LEN }, - [IFLA_MAP] = { .len = sizeof(struct rtnl_link_ifmap) }, - [IFLA_MTU] = { .type = NLA_U32 }, - [IFLA_LINK] = { .type = NLA_U32 }, - [IFLA_MASTER] = { .type = NLA_U32 }, - [IFLA_CARRIER] = { .type = NLA_U8 }, - [IFLA_TXQLEN] = { .type = NLA_U32 }, - [IFLA_WEIGHT] = { .type = NLA_U32 }, - [IFLA_OPERSTATE] = { .type = NLA_U8 }, - [IFLA_LINKMODE] = { .type = NLA_U8 }, - [IFLA_LINKINFO] = { .type = NLA_NESTED }, - [IFLA_NET_NS_PID] = { .type = NLA_U32 }, - [IFLA_NET_NS_FD] = { .type = NLA_U32 }, - [IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 }, - [IFLA_VFINFO_LIST] = {. type = NLA_NESTED }, - [IFLA_VF_PORTS] = { .type = NLA_NESTED }, - [IFLA_PORT_SELF] = { .type = NLA_NESTED }, - [IFLA_AF_SPEC] = { .type = NLA_NESTED }, - [IFLA_EXT_MASK] = { .type = NLA_U32 }, - [IFLA_PROMISCUITY] = { .type = NLA_U32 }, - [IFLA_NUM_TX_QUEUES] = { .type = NLA_U32 }, - [IFLA_NUM_RX_QUEUES] = { .type = NLA_U32 }, - [IFLA_PHYS_PORT_ID] = { .type = NLA_BINARY, .len = MAX_PHYS_ITEM_ID_LEN }, - [IFLA_CARRIER_CHANGES] = { .type = NLA_U32 }, /* ignored */ - [IFLA_PHYS_SWITCH_ID] = { .type = NLA_BINARY, .len = MAX_PHYS_ITEM_ID_LEN }, - [IFLA_LINK_NETNSID] = { .type = NLA_S32 }, - [IFLA_PROTO_DOWN] = { .type = NLA_U8 }, - [IFLA_XDP] = { .type = NLA_NESTED }, -}; - -static const struct nla_policy ifla_info_policy[IFLA_INFO_MAX+1] = { - [IFLA_INFO_KIND] = { .type = NLA_STRING }, - [IFLA_INFO_DATA] = { .type = NLA_NESTED }, - [IFLA_INFO_SLAVE_KIND] = { .type = NLA_STRING }, - [IFLA_INFO_SLAVE_DATA] = { .type = NLA_NESTED }, -}; - -static const struct nla_policy ifla_vf_policy[IFLA_VF_MAX+1] = { - [IFLA_VF_MAC] = { .len = sizeof(struct ifla_vf_mac) }, - [IFLA_VF_VLAN] = { .len = sizeof(struct ifla_vf_vlan) }, - [IFLA_VF_VLAN_LIST] = { .type = NLA_NESTED }, - [IFLA_VF_TX_RATE] = { .len = sizeof(struct ifla_vf_tx_rate) }, - [IFLA_VF_SPOOFCHK] = { .len = sizeof(struct ifla_vf_spoofchk) }, - [IFLA_VF_RATE] = { .len = sizeof(struct ifla_vf_rate) }, - [IFLA_VF_LINK_STATE] = { .len = sizeof(struct ifla_vf_link_state) }, - [IFLA_VF_RSS_QUERY_EN] = { .len = sizeof(struct ifla_vf_rss_query_en) }, - [IFLA_VF_STATS] = { .type = NLA_NESTED }, - [IFLA_VF_TRUST] = { .len = sizeof(struct ifla_vf_trust) }, - [IFLA_VF_IB_NODE_GUID] = { .len = sizeof(struct ifla_vf_guid) }, - [IFLA_VF_IB_PORT_GUID] = { .len = sizeof(struct ifla_vf_guid) }, -}; - -static const struct nla_policy ifla_port_policy[IFLA_PORT_MAX+1] = { - [IFLA_PORT_VF] = { .type = NLA_U32 }, - [IFLA_PORT_PROFILE] = { .type = NLA_STRING, - .len = PORT_PROFILE_MAX }, - [IFLA_PORT_VSI_TYPE] = { .type = NLA_BINARY, - .len = sizeof(struct ifla_port_vsi)}, - [IFLA_PORT_INSTANCE_UUID] = { .type = NLA_BINARY, - .len = PORT_UUID_MAX }, - [IFLA_PORT_HOST_UUID] = { .type = NLA_STRING, - .len = PORT_UUID_MAX }, - [IFLA_PORT_REQUEST] = { .type = NLA_U8, }, - [IFLA_PORT_RESPONSE] = { .type = NLA_U16, }, -}; - -static const struct nla_policy ifla_xdp_policy[IFLA_XDP_MAX + 1] = { - [IFLA_XDP_FD] = { .type = NLA_S32 }, - [IFLA_XDP_ATTACHED] = { .type = NLA_U8 }, -}; - -static const struct rtnl_link_ops *linkinfo_to_kind_ops(const struct nlattr *nla) -{ - const struct rtnl_link_ops *ops = NULL; - struct nlattr *linfo[IFLA_INFO_MAX + 1]; - - if (nla_parse_nested(linfo, IFLA_INFO_MAX, nla, ifla_info_policy) < 0) - return NULL; - - if (linfo[IFLA_INFO_KIND]) { - char kind[MODULE_NAME_LEN]; - - nla_strlcpy(kind, linfo[IFLA_INFO_KIND], sizeof(kind)); - ops = rtnl_link_ops_get(kind); - } - - return ops; -} - -static bool link_master_filtered(struct net_device *dev, int master_idx) -{ - struct net_device *master; - - if (!master_idx) - return false; - - master = netdev_master_upper_dev_get(dev); - if (!master || master->ifindex != master_idx) - return true; - - return false; -} - -static bool link_kind_filtered(const struct net_device *dev, - const struct rtnl_link_ops *kind_ops) -{ - if (kind_ops && dev->rtnl_link_ops != kind_ops) - return true; - - return false; -} - -static bool link_dump_filtered(struct net_device *dev, - int master_idx, - const struct rtnl_link_ops *kind_ops) -{ - if (link_master_filtered(dev, master_idx) || - link_kind_filtered(dev, kind_ops)) - return true; - - return false; -} - -static int rtnl_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) -{ - struct net *net = sock_net(skb->sk); - int h, s_h; - int idx = 0, s_idx; - struct net_device *dev; - struct hlist_head *head; - struct nlattr *tb[IFLA_MAX+1]; - u32 ext_filter_mask = 0; - const struct rtnl_link_ops *kind_ops = NULL; - unsigned int flags = NLM_F_MULTI; - int master_idx = 0; - int err; - int hdrlen; - - s_h = cb->args[0]; - s_idx = cb->args[1]; - - cb->seq = net->dev_base_seq; - - /* A hack to preserve kernel<->userspace interface. - * The correct header is ifinfomsg. It is consistent with rtnl_getlink. - * However, before Linux v3.9 the code here assumed rtgenmsg and that's - * what iproute2 < v3.9.0 used. - * We can detect the old iproute2. Even including the IFLA_EXT_MASK - * attribute, its netlink message is shorter than struct ifinfomsg. - */ - hdrlen = nlmsg_len(cb->nlh) < sizeof(struct ifinfomsg) ? - sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg); - - if (nlmsg_parse(cb->nlh, hdrlen, tb, IFLA_MAX, ifla_policy) >= 0) { - - if (tb[IFLA_EXT_MASK]) - ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); - - if (tb[IFLA_MASTER]) - master_idx = nla_get_u32(tb[IFLA_MASTER]); - - if (tb[IFLA_LINKINFO]) - kind_ops = linkinfo_to_kind_ops(tb[IFLA_LINKINFO]); - - if (master_idx || kind_ops) - flags |= NLM_F_DUMP_FILTERED; - } - - for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { - idx = 0; - head = &net->dev_index_head[h]; - hlist_for_each_entry(dev, head, index_hlist) { - if (link_dump_filtered(dev, master_idx, kind_ops)) - goto cont; - if (idx < s_idx) - goto cont; - err = rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, 0, - flags, - ext_filter_mask); - /* If we ran out of room on the first message, - * we're in trouble - */ - WARN_ON((err == -EMSGSIZE) && (skb->len == 0)); - - if (err < 0) - goto out; - - nl_dump_check_consistent(cb, nlmsg_hdr(skb)); -cont: - idx++; - } - } -out: - cb->args[1] = idx; - cb->args[0] = h; - - return skb->len; -} - -int rtnl_nla_parse_ifla(struct nlattr **tb, const struct nlattr *head, int len) -{ - return nla_parse(tb, IFLA_MAX, head, len, ifla_policy); -} -EXPORT_SYMBOL(rtnl_nla_parse_ifla); - -struct net *rtnl_link_get_net(struct net *src_net, struct nlattr *tb[]) -{ - struct net *net; - /* Examine the link attributes and figure out which - * network namespace we are talking about. - */ - if (tb[IFLA_NET_NS_PID]) - net = get_net_ns_by_pid(nla_get_u32(tb[IFLA_NET_NS_PID])); - else if (tb[IFLA_NET_NS_FD]) - net = get_net_ns_by_fd(nla_get_u32(tb[IFLA_NET_NS_FD])); - else - net = get_net(src_net); - return net; -} -EXPORT_SYMBOL(rtnl_link_get_net); - -static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) -{ - if (dev) { - if (tb[IFLA_ADDRESS] && - nla_len(tb[IFLA_ADDRESS]) < dev->addr_len) - return -EINVAL; - - if (tb[IFLA_BROADCAST] && - nla_len(tb[IFLA_BROADCAST]) < dev->addr_len) - return -EINVAL; - } - - if (tb[IFLA_AF_SPEC]) { - struct nlattr *af; - int rem, err; - - nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) { - const struct rtnl_af_ops *af_ops; - - if (!(af_ops = rtnl_af_lookup(nla_type(af)))) - return -EAFNOSUPPORT; - - if (!af_ops->set_link_af) - return -EOPNOTSUPP; - - if (af_ops->validate_link_af) { - err = af_ops->validate_link_af(dev, af); - if (err < 0) - return err; - } - } - } - - return 0; -} - -static int handle_infiniband_guid(struct net_device *dev, struct ifla_vf_guid *ivt, - int guid_type) -{ - const struct net_device_ops *ops = dev->netdev_ops; - - return ops->ndo_set_vf_guid(dev, ivt->vf, ivt->guid, guid_type); -} - -static int handle_vf_guid(struct net_device *dev, struct ifla_vf_guid *ivt, int guid_type) -{ - if (dev->type != ARPHRD_INFINIBAND) - return -EOPNOTSUPP; - - return handle_infiniband_guid(dev, ivt, guid_type); -} - -static int do_setvfinfo(struct net_device *dev, struct nlattr **tb) -{ - const struct net_device_ops *ops = dev->netdev_ops; - int err = -EINVAL; - - if (tb[IFLA_VF_MAC]) { - struct ifla_vf_mac *ivm = nla_data(tb[IFLA_VF_MAC]); - - err = -EOPNOTSUPP; - if (ops->ndo_set_vf_mac) - err = ops->ndo_set_vf_mac(dev, ivm->vf, - ivm->mac); - if (err < 0) - return err; - } - - if (tb[IFLA_VF_VLAN]) { - struct ifla_vf_vlan *ivv = nla_data(tb[IFLA_VF_VLAN]); - - err = -EOPNOTSUPP; - if (ops->ndo_set_vf_vlan) - err = ops->ndo_set_vf_vlan(dev, ivv->vf, ivv->vlan, - ivv->qos, - htons(ETH_P_8021Q)); - if (err < 0) - return err; - } - - if (tb[IFLA_VF_VLAN_LIST]) { - struct ifla_vf_vlan_info *ivvl[MAX_VLAN_LIST_LEN]; - struct nlattr *attr; - int rem, len = 0; - - err = -EOPNOTSUPP; - if (!ops->ndo_set_vf_vlan) - return err; - - nla_for_each_nested(attr, tb[IFLA_VF_VLAN_LIST], rem) { - if (nla_type(attr) != IFLA_VF_VLAN_INFO || - nla_len(attr) < NLA_HDRLEN) { - return -EINVAL; - } - if (len >= MAX_VLAN_LIST_LEN) - return -EOPNOTSUPP; - ivvl[len] = nla_data(attr); - - len++; - } - if (len == 0) - return -EINVAL; - - err = ops->ndo_set_vf_vlan(dev, ivvl[0]->vf, ivvl[0]->vlan, - ivvl[0]->qos, ivvl[0]->vlan_proto); - if (err < 0) - return err; - } - - if (tb[IFLA_VF_TX_RATE]) { - struct ifla_vf_tx_rate *ivt = nla_data(tb[IFLA_VF_TX_RATE]); - struct ifla_vf_info ivf; - - err = -EOPNOTSUPP; - if (ops->ndo_get_vf_config) - err = ops->ndo_get_vf_config(dev, ivt->vf, &ivf); - if (err < 0) - return err; - - err = -EOPNOTSUPP; - if (ops->ndo_set_vf_rate) - err = ops->ndo_set_vf_rate(dev, ivt->vf, - ivf.min_tx_rate, - ivt->rate); - if (err < 0) - return err; - } - - if (tb[IFLA_VF_RATE]) { - struct ifla_vf_rate *ivt = nla_data(tb[IFLA_VF_RATE]); - - err = -EOPNOTSUPP; - if (ops->ndo_set_vf_rate) - err = ops->ndo_set_vf_rate(dev, ivt->vf, - ivt->min_tx_rate, - ivt->max_tx_rate); - if (err < 0) - return err; - } - - if (tb[IFLA_VF_SPOOFCHK]) { - struct ifla_vf_spoofchk *ivs = nla_data(tb[IFLA_VF_SPOOFCHK]); - - err = -EOPNOTSUPP; - if (ops->ndo_set_vf_spoofchk) - err = ops->ndo_set_vf_spoofchk(dev, ivs->vf, - ivs->setting); - if (err < 0) - return err; - } - - if (tb[IFLA_VF_LINK_STATE]) { - struct ifla_vf_link_state *ivl = nla_data(tb[IFLA_VF_LINK_STATE]); - - err = -EOPNOTSUPP; - if (ops->ndo_set_vf_link_state) - err = ops->ndo_set_vf_link_state(dev, ivl->vf, - ivl->link_state); - if (err < 0) - return err; - } - - if (tb[IFLA_VF_RSS_QUERY_EN]) { - struct ifla_vf_rss_query_en *ivrssq_en; - - err = -EOPNOTSUPP; - ivrssq_en = nla_data(tb[IFLA_VF_RSS_QUERY_EN]); - if (ops->ndo_set_vf_rss_query_en) - err = ops->ndo_set_vf_rss_query_en(dev, ivrssq_en->vf, - ivrssq_en->setting); - if (err < 0) - return err; - } - - if (tb[IFLA_VF_TRUST]) { - struct ifla_vf_trust *ivt = nla_data(tb[IFLA_VF_TRUST]); - - err = -EOPNOTSUPP; - if (ops->ndo_set_vf_trust) - err = ops->ndo_set_vf_trust(dev, ivt->vf, ivt->setting); - if (err < 0) - return err; - } - - if (tb[IFLA_VF_IB_NODE_GUID]) { - struct ifla_vf_guid *ivt = nla_data(tb[IFLA_VF_IB_NODE_GUID]); - - if (!ops->ndo_set_vf_guid) - return -EOPNOTSUPP; - - return handle_vf_guid(dev, ivt, IFLA_VF_IB_NODE_GUID); - } - - if (tb[IFLA_VF_IB_PORT_GUID]) { - struct ifla_vf_guid *ivt = nla_data(tb[IFLA_VF_IB_PORT_GUID]); - - if (!ops->ndo_set_vf_guid) - return -EOPNOTSUPP; - - return handle_vf_guid(dev, ivt, IFLA_VF_IB_PORT_GUID); - } - - return err; -} - -static int do_set_master(struct net_device *dev, int ifindex) -{ - struct net_device *upper_dev = netdev_master_upper_dev_get(dev); - const struct net_device_ops *ops; - int err; - - if (upper_dev) { - if (upper_dev->ifindex == ifindex) - return 0; - ops = upper_dev->netdev_ops; - if (ops->ndo_del_slave) { - err = ops->ndo_del_slave(upper_dev, dev); - if (err) - return err; - } else { - return -EOPNOTSUPP; - } - } - - if (ifindex) { - upper_dev = __dev_get_by_index(dev_net(dev), ifindex); - if (!upper_dev) - return -EINVAL; - ops = upper_dev->netdev_ops; - if (ops->ndo_add_slave) { - err = ops->ndo_add_slave(upper_dev, dev); - if (err) - return err; - } else { - return -EOPNOTSUPP; - } - } - return 0; -} - -#define DO_SETLINK_MODIFIED 0x01 -/* notify flag means notify + modified. */ -#define DO_SETLINK_NOTIFY 0x03 -static int do_setlink(const struct sk_buff *skb, - struct net_device *dev, struct ifinfomsg *ifm, - struct nlattr **tb, char *ifname, int status) -{ - const struct net_device_ops *ops = dev->netdev_ops; - int err; - - if (tb[IFLA_NET_NS_PID] || tb[IFLA_NET_NS_FD]) { - struct net *net = rtnl_link_get_net(dev_net(dev), tb); - if (IS_ERR(net)) { - err = PTR_ERR(net); - goto errout; - } - if (!netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) { - put_net(net); - err = -EPERM; - goto errout; - } - err = dev_change_net_namespace(dev, net, ifname); - put_net(net); - if (err) - goto errout; - status |= DO_SETLINK_MODIFIED; - } - - if (tb[IFLA_MAP]) { - struct rtnl_link_ifmap *u_map; - struct ifmap k_map; - - if (!ops->ndo_set_config) { - err = -EOPNOTSUPP; - goto errout; - } - - if (!netif_device_present(dev)) { - err = -ENODEV; - goto errout; - } - - u_map = nla_data(tb[IFLA_MAP]); - k_map.mem_start = (unsigned long) u_map->mem_start; - k_map.mem_end = (unsigned long) u_map->mem_end; - k_map.base_addr = (unsigned short) u_map->base_addr; - k_map.irq = (unsigned char) u_map->irq; - k_map.dma = (unsigned char) u_map->dma; - k_map.port = (unsigned char) u_map->port; - - err = ops->ndo_set_config(dev, &k_map); - if (err < 0) - goto errout; - - status |= DO_SETLINK_NOTIFY; - } - - if (tb[IFLA_ADDRESS]) { - struct sockaddr *sa; - int len; - - len = sizeof(sa_family_t) + dev->addr_len; - sa = kmalloc(len, GFP_KERNEL); - if (!sa) { - err = -ENOMEM; - goto errout; - } - sa->sa_family = dev->type; - memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]), - dev->addr_len); - err = dev_set_mac_address(dev, sa); - kfree(sa); - if (err) - goto errout; - status |= DO_SETLINK_MODIFIED; - } - - if (tb[IFLA_MTU]) { - err = dev_set_mtu(dev, nla_get_u32(tb[IFLA_MTU])); - if (err < 0) - goto errout; - status |= DO_SETLINK_MODIFIED; - } - - if (tb[IFLA_GROUP]) { - dev_set_group(dev, nla_get_u32(tb[IFLA_GROUP])); - status |= DO_SETLINK_NOTIFY; - } - - /* - * Interface selected by interface index but interface - * name provided implies that a name change has been - * requested. - */ - if (ifm->ifi_index > 0 && ifname[0]) { - err = dev_change_name(dev, ifname); - if (err < 0) - goto errout; - status |= DO_SETLINK_MODIFIED; - } - - if (tb[IFLA_IFALIAS]) { - err = dev_set_alias(dev, nla_data(tb[IFLA_IFALIAS]), - nla_len(tb[IFLA_IFALIAS])); - if (err < 0) - goto errout; - status |= DO_SETLINK_NOTIFY; - } - - if (tb[IFLA_BROADCAST]) { - nla_memcpy(dev->broadcast, tb[IFLA_BROADCAST], dev->addr_len); - call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); - } - - if (ifm->ifi_flags || ifm->ifi_change) { - err = dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm)); - if (err < 0) - goto errout; - } - - if (tb[IFLA_MASTER]) { - err = do_set_master(dev, nla_get_u32(tb[IFLA_MASTER])); - if (err) - goto errout; - status |= DO_SETLINK_MODIFIED; - } - - if (tb[IFLA_CARRIER]) { - err = dev_change_carrier(dev, nla_get_u8(tb[IFLA_CARRIER])); - if (err) - goto errout; - status |= DO_SETLINK_MODIFIED; - } - - if (tb[IFLA_TXQLEN]) { - unsigned long value = nla_get_u32(tb[IFLA_TXQLEN]); - unsigned long orig_len = dev->tx_queue_len; - - if (dev->tx_queue_len ^ value) { - dev->tx_queue_len = value; - err = call_netdevice_notifiers( - NETDEV_CHANGE_TX_QUEUE_LEN, dev); - err = notifier_to_errno(err); - if (err) { - dev->tx_queue_len = orig_len; - goto errout; - } - status |= DO_SETLINK_NOTIFY; - } - } - - if (tb[IFLA_OPERSTATE]) - set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); - - if (tb[IFLA_LINKMODE]) { - unsigned char value = nla_get_u8(tb[IFLA_LINKMODE]); - - write_lock_bh(&dev_base_lock); - if (dev->link_mode ^ value) - status |= DO_SETLINK_NOTIFY; - dev->link_mode = value; - write_unlock_bh(&dev_base_lock); - } - - if (tb[IFLA_VFINFO_LIST]) { - struct nlattr *vfinfo[IFLA_VF_MAX + 1]; - struct nlattr *attr; - int rem; - - nla_for_each_nested(attr, tb[IFLA_VFINFO_LIST], rem) { - if (nla_type(attr) != IFLA_VF_INFO || - nla_len(attr) < NLA_HDRLEN) { - err = -EINVAL; - goto errout; - } - err = nla_parse_nested(vfinfo, IFLA_VF_MAX, attr, - ifla_vf_policy); - if (err < 0) - goto errout; - err = do_setvfinfo(dev, vfinfo); - if (err < 0) - goto errout; - status |= DO_SETLINK_NOTIFY; - } - } - err = 0; - - if (tb[IFLA_VF_PORTS]) { - struct nlattr *port[IFLA_PORT_MAX+1]; - struct nlattr *attr; - int vf; - int rem; - - err = -EOPNOTSUPP; - if (!ops->ndo_set_vf_port) - goto errout; - - nla_for_each_nested(attr, tb[IFLA_VF_PORTS], rem) { - if (nla_type(attr) != IFLA_VF_PORT || - nla_len(attr) < NLA_HDRLEN) { - err = -EINVAL; - goto errout; - } - err = nla_parse_nested(port, IFLA_PORT_MAX, attr, - ifla_port_policy); - if (err < 0) - goto errout; - if (!port[IFLA_PORT_VF]) { - err = -EOPNOTSUPP; - goto errout; - } - vf = nla_get_u32(port[IFLA_PORT_VF]); - err = ops->ndo_set_vf_port(dev, vf, port); - if (err < 0) - goto errout; - status |= DO_SETLINK_NOTIFY; - } - } - err = 0; - - if (tb[IFLA_PORT_SELF]) { - struct nlattr *port[IFLA_PORT_MAX+1]; - - err = nla_parse_nested(port, IFLA_PORT_MAX, - tb[IFLA_PORT_SELF], ifla_port_policy); - if (err < 0) - goto errout; - - err = -EOPNOTSUPP; - if (ops->ndo_set_vf_port) - err = ops->ndo_set_vf_port(dev, PORT_SELF_VF, port); - if (err < 0) - goto errout; - status |= DO_SETLINK_NOTIFY; - } - - if (tb[IFLA_AF_SPEC]) { - struct nlattr *af; - int rem; - - nla_for_each_nested(af, tb[IFLA_AF_SPEC], rem) { - const struct rtnl_af_ops *af_ops; - - if (!(af_ops = rtnl_af_lookup(nla_type(af)))) - BUG(); - - err = af_ops->set_link_af(dev, af); - if (err < 0) - goto errout; - - status |= DO_SETLINK_NOTIFY; - } - } - err = 0; - - if (tb[IFLA_PROTO_DOWN]) { - err = dev_change_proto_down(dev, - nla_get_u8(tb[IFLA_PROTO_DOWN])); - if (err) - goto errout; - status |= DO_SETLINK_NOTIFY; - } - - if (tb[IFLA_XDP]) { - struct nlattr *xdp[IFLA_XDP_MAX + 1]; - - err = nla_parse_nested(xdp, IFLA_XDP_MAX, tb[IFLA_XDP], - ifla_xdp_policy); - if (err < 0) - goto errout; - - if (xdp[IFLA_XDP_ATTACHED]) { - err = -EINVAL; - goto errout; - } - if (xdp[IFLA_XDP_FD]) { - err = dev_change_xdp_fd(dev, - nla_get_s32(xdp[IFLA_XDP_FD])); - if (err) - goto errout; - status |= DO_SETLINK_NOTIFY; - } - } - -errout: - if (status & DO_SETLINK_MODIFIED) { - if (status & DO_SETLINK_NOTIFY) - netdev_state_change(dev); - - if (err < 0) - net_warn_ratelimited("A link change request failed with some changes committed already. Interface %s may have been left with an inconsistent configuration, please check.\n", - dev->name); - } - - return err; -} - -static int rtnl_setlink(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct ifinfomsg *ifm; - struct net_device *dev; - int err; - struct nlattr *tb[IFLA_MAX+1]; - char ifname[IFNAMSIZ]; - - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); - if (err < 0) - goto errout; - - if (tb[IFLA_IFNAME]) - nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); - else - ifname[0] = '\0'; - - err = -EINVAL; - ifm = nlmsg_data(nlh); - if (ifm->ifi_index > 0) - dev = __dev_get_by_index(net, ifm->ifi_index); - else if (tb[IFLA_IFNAME]) - dev = __dev_get_by_name(net, ifname); - else - goto errout; - - if (dev == NULL) { - err = -ENODEV; - goto errout; - } - - err = validate_linkmsg(dev, tb); - if (err < 0) - goto errout; - - err = do_setlink(skb, dev, ifm, tb, ifname, 0); -errout: - return err; -} - -static int rtnl_group_dellink(const struct net *net, int group) -{ - struct net_device *dev, *aux; - LIST_HEAD(list_kill); - bool found = false; - - if (!group) - return -EPERM; - - for_each_netdev(net, dev) { - if (dev->group == group) { - const struct rtnl_link_ops *ops; - - found = true; - ops = dev->rtnl_link_ops; - if (!ops || !ops->dellink) - return -EOPNOTSUPP; - } - } - - if (!found) - return -ENODEV; - - for_each_netdev_safe(net, dev, aux) { - if (dev->group == group) { - const struct rtnl_link_ops *ops; - - ops = dev->rtnl_link_ops; - ops->dellink(dev, &list_kill); - } - } - unregister_netdevice_many(&list_kill); - - return 0; -} - -int rtnl_delete_link(struct net_device *dev) -{ - const struct rtnl_link_ops *ops; - LIST_HEAD(list_kill); - - ops = dev->rtnl_link_ops; - if (!ops || !ops->dellink) - return -EOPNOTSUPP; - - ops->dellink(dev, &list_kill); - unregister_netdevice_many(&list_kill); - - return 0; -} -EXPORT_SYMBOL_GPL(rtnl_delete_link); - -static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct net_device *dev; - struct ifinfomsg *ifm; - char ifname[IFNAMSIZ]; - struct nlattr *tb[IFLA_MAX+1]; - int err; - - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); - if (err < 0) - return err; - - if (tb[IFLA_IFNAME]) - nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); - - ifm = nlmsg_data(nlh); - if (ifm->ifi_index > 0) - dev = __dev_get_by_index(net, ifm->ifi_index); - else if (tb[IFLA_IFNAME]) - dev = __dev_get_by_name(net, ifname); - else if (tb[IFLA_GROUP]) - return rtnl_group_dellink(net, nla_get_u32(tb[IFLA_GROUP])); - else - return -EINVAL; - - if (!dev) - return -ENODEV; - - return rtnl_delete_link(dev); -} - -int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm) -{ - unsigned int old_flags; - int err; - - old_flags = dev->flags; - if (ifm && (ifm->ifi_flags || ifm->ifi_change)) { - err = __dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm)); - if (err < 0) - return err; - } - - dev->rtnl_link_state = RTNL_LINK_INITIALIZED; - - __dev_notify_flags(dev, old_flags, ~0U); - return 0; -} -EXPORT_SYMBOL(rtnl_configure_link); - -struct net_device *rtnl_create_link(struct net *net, - const char *ifname, unsigned char name_assign_type, - const struct rtnl_link_ops *ops, struct nlattr *tb[]) -{ - int err; - struct net_device *dev; - unsigned int num_tx_queues = 1; - unsigned int num_rx_queues = 1; - - if (tb[IFLA_NUM_TX_QUEUES]) - num_tx_queues = nla_get_u32(tb[IFLA_NUM_TX_QUEUES]); - else if (ops->get_num_tx_queues) - num_tx_queues = ops->get_num_tx_queues(); - - if (tb[IFLA_NUM_RX_QUEUES]) - num_rx_queues = nla_get_u32(tb[IFLA_NUM_RX_QUEUES]); - else if (ops->get_num_rx_queues) - num_rx_queues = ops->get_num_rx_queues(); - - err = -ENOMEM; - dev = alloc_netdev_mqs(ops->priv_size, ifname, name_assign_type, - ops->setup, num_tx_queues, num_rx_queues); - if (!dev) - goto err; - - dev_net_set(dev, net); - dev->rtnl_link_ops = ops; - dev->rtnl_link_state = RTNL_LINK_INITIALIZING; - - if (tb[IFLA_MTU]) - dev->mtu = nla_get_u32(tb[IFLA_MTU]); - if (tb[IFLA_ADDRESS]) { - memcpy(dev->dev_addr, nla_data(tb[IFLA_ADDRESS]), - nla_len(tb[IFLA_ADDRESS])); - dev->addr_assign_type = NET_ADDR_SET; - } - if (tb[IFLA_BROADCAST]) - memcpy(dev->broadcast, nla_data(tb[IFLA_BROADCAST]), - nla_len(tb[IFLA_BROADCAST])); - if (tb[IFLA_TXQLEN]) - dev->tx_queue_len = nla_get_u32(tb[IFLA_TXQLEN]); - if (tb[IFLA_OPERSTATE]) - set_operstate(dev, nla_get_u8(tb[IFLA_OPERSTATE])); - if (tb[IFLA_LINKMODE]) - dev->link_mode = nla_get_u8(tb[IFLA_LINKMODE]); - if (tb[IFLA_GROUP]) - dev_set_group(dev, nla_get_u32(tb[IFLA_GROUP])); - - return dev; - -err: - return ERR_PTR(err); -} -EXPORT_SYMBOL(rtnl_create_link); - -static int rtnl_group_changelink(const struct sk_buff *skb, - struct net *net, int group, - struct ifinfomsg *ifm, - struct nlattr **tb) -{ - struct net_device *dev, *aux; - int err; - - for_each_netdev_safe(net, dev, aux) { - if (dev->group == group) { - err = do_setlink(skb, dev, ifm, tb, NULL, 0); - if (err < 0) - return err; - } - } - - return 0; -} - -static int rtnl_newlink(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - const struct rtnl_link_ops *ops; - const struct rtnl_link_ops *m_ops = NULL; - struct net_device *dev; - struct net_device *master_dev = NULL; - struct ifinfomsg *ifm; - char kind[MODULE_NAME_LEN]; - char ifname[IFNAMSIZ]; - struct nlattr *tb[IFLA_MAX+1]; - struct nlattr *linkinfo[IFLA_INFO_MAX+1]; - unsigned char name_assign_type = NET_NAME_USER; - int err; - -#ifdef CONFIG_MODULES -replay: -#endif - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); - if (err < 0) - return err; - - if (tb[IFLA_IFNAME]) - nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); - else - ifname[0] = '\0'; - - ifm = nlmsg_data(nlh); - if (ifm->ifi_index > 0) - dev = __dev_get_by_index(net, ifm->ifi_index); - else { - if (ifname[0]) - dev = __dev_get_by_name(net, ifname); - else - dev = NULL; - } - - if (dev) { - master_dev = netdev_master_upper_dev_get(dev); - if (master_dev) - m_ops = master_dev->rtnl_link_ops; - } - - err = validate_linkmsg(dev, tb); - if (err < 0) - return err; - - if (tb[IFLA_LINKINFO]) { - err = nla_parse_nested(linkinfo, IFLA_INFO_MAX, - tb[IFLA_LINKINFO], ifla_info_policy); - if (err < 0) - return err; - } else - memset(linkinfo, 0, sizeof(linkinfo)); - - if (linkinfo[IFLA_INFO_KIND]) { - nla_strlcpy(kind, linkinfo[IFLA_INFO_KIND], sizeof(kind)); - ops = rtnl_link_ops_get(kind); - } else { - kind[0] = '\0'; - ops = NULL; - } - - if (1) { - struct nlattr *attr[ops ? ops->maxtype + 1 : 1]; - struct nlattr *slave_attr[m_ops ? m_ops->slave_maxtype + 1 : 1]; - struct nlattr **data = NULL; - struct nlattr **slave_data = NULL; - struct net *dest_net, *link_net = NULL; - - if (ops) { - if (ops->maxtype && linkinfo[IFLA_INFO_DATA]) { - err = nla_parse_nested(attr, ops->maxtype, - linkinfo[IFLA_INFO_DATA], - ops->policy); - if (err < 0) - return err; - data = attr; - } - if (ops->validate) { - err = ops->validate(tb, data); - if (err < 0) - return err; - } - } - - if (m_ops) { - if (m_ops->slave_maxtype && - linkinfo[IFLA_INFO_SLAVE_DATA]) { - err = nla_parse_nested(slave_attr, - m_ops->slave_maxtype, - linkinfo[IFLA_INFO_SLAVE_DATA], - m_ops->slave_policy); - if (err < 0) - return err; - slave_data = slave_attr; - } - if (m_ops->slave_validate) { - err = m_ops->slave_validate(tb, slave_data); - if (err < 0) - return err; - } - } - - if (dev) { - int status = 0; - - if (nlh->nlmsg_flags & NLM_F_EXCL) - return -EEXIST; - if (nlh->nlmsg_flags & NLM_F_REPLACE) - return -EOPNOTSUPP; - - if (linkinfo[IFLA_INFO_DATA]) { - if (!ops || ops != dev->rtnl_link_ops || - !ops->changelink) - return -EOPNOTSUPP; - - err = ops->changelink(dev, tb, data); - if (err < 0) - return err; - status |= DO_SETLINK_NOTIFY; - } - - if (linkinfo[IFLA_INFO_SLAVE_DATA]) { - if (!m_ops || !m_ops->slave_changelink) - return -EOPNOTSUPP; - - err = m_ops->slave_changelink(master_dev, dev, - tb, slave_data); - if (err < 0) - return err; - status |= DO_SETLINK_NOTIFY; - } - - return do_setlink(skb, dev, ifm, tb, ifname, status); - } - - if (!(nlh->nlmsg_flags & NLM_F_CREATE)) { - if (ifm->ifi_index == 0 && tb[IFLA_GROUP]) - return rtnl_group_changelink(skb, net, - nla_get_u32(tb[IFLA_GROUP]), - ifm, tb); - return -ENODEV; - } - - if (tb[IFLA_MAP] || tb[IFLA_MASTER] || tb[IFLA_PROTINFO]) - return -EOPNOTSUPP; - - if (!ops) { -#ifdef CONFIG_MODULES - if (kind[0]) { - __rtnl_unlock(); - request_module("rtnl-link-%s", kind); - rtnl_lock(); - ops = rtnl_link_ops_get(kind); - if (ops) - goto replay; - } -#endif - return -EOPNOTSUPP; - } - - if (!ops->setup) - return -EOPNOTSUPP; - - if (!ifname[0]) { - snprintf(ifname, IFNAMSIZ, "%s%%d", ops->kind); - name_assign_type = NET_NAME_ENUM; - } - - dest_net = rtnl_link_get_net(net, tb); - if (IS_ERR(dest_net)) - return PTR_ERR(dest_net); - - err = -EPERM; - if (!netlink_ns_capable(skb, dest_net->user_ns, CAP_NET_ADMIN)) - goto out; - - if (tb[IFLA_LINK_NETNSID]) { - int id = nla_get_s32(tb[IFLA_LINK_NETNSID]); - - link_net = get_net_ns_by_id(dest_net, id); - if (!link_net) { - err = -EINVAL; - goto out; - } - err = -EPERM; - if (!netlink_ns_capable(skb, link_net->user_ns, CAP_NET_ADMIN)) - goto out; - } - - dev = rtnl_create_link(link_net ? : dest_net, ifname, - name_assign_type, ops, tb); - if (IS_ERR(dev)) { - err = PTR_ERR(dev); - goto out; - } - - dev->ifindex = ifm->ifi_index; - - if (ops->newlink) { - err = ops->newlink(link_net ? : net, dev, tb, data); - /* Drivers should call free_netdev() in ->destructor - * and unregister it on failure after registration - * so that device could be finally freed in rtnl_unlock. - */ - if (err < 0) { - /* If device is not registered at all, free it now */ - if (dev->reg_state == NETREG_UNINITIALIZED) - free_netdev(dev); - goto out; - } - } else { - err = register_netdevice(dev); - if (err < 0) { - free_netdev(dev); - goto out; - } - } - err = rtnl_configure_link(dev, ifm); - if (err < 0) - goto out_unregister; - if (link_net) { - err = dev_change_net_namespace(dev, dest_net, ifname); - if (err < 0) - goto out_unregister; - } -out: - if (link_net) - put_net(link_net); - put_net(dest_net); - return err; -out_unregister: - if (ops->newlink) { - LIST_HEAD(list_kill); - - ops->dellink(dev, &list_kill); - unregister_netdevice_many(&list_kill); - } else { - unregister_netdevice(dev); - } - goto out; - } -} - -static int rtnl_getlink(struct sk_buff *skb, struct nlmsghdr* nlh) -{ - struct net *net = sock_net(skb->sk); - struct ifinfomsg *ifm; - char ifname[IFNAMSIZ]; - struct nlattr *tb[IFLA_MAX+1]; - struct net_device *dev = NULL; - struct sk_buff *nskb; - int err; - u32 ext_filter_mask = 0; - - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFLA_MAX, ifla_policy); - if (err < 0) - return err; - - if (tb[IFLA_IFNAME]) - nla_strlcpy(ifname, tb[IFLA_IFNAME], IFNAMSIZ); - - if (tb[IFLA_EXT_MASK]) - ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); - - ifm = nlmsg_data(nlh); - if (ifm->ifi_index > 0) - dev = __dev_get_by_index(net, ifm->ifi_index); - else if (tb[IFLA_IFNAME]) - dev = __dev_get_by_name(net, ifname); - else - return -EINVAL; - - if (dev == NULL) - return -ENODEV; - - nskb = nlmsg_new(if_nlmsg_size(dev, ext_filter_mask), GFP_KERNEL); - if (nskb == NULL) - return -ENOBUFS; - - err = rtnl_fill_ifinfo(nskb, dev, RTM_NEWLINK, NETLINK_CB(skb).portid, - nlh->nlmsg_seq, 0, 0, ext_filter_mask); - if (err < 0) { - /* -EMSGSIZE implies BUG in if_nlmsg_size */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(nskb); - } else - err = rtnl_unicast(nskb, net, NETLINK_CB(skb).portid); - - return err; -} - -static u16 rtnl_calcit(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct net_device *dev; - struct nlattr *tb[IFLA_MAX+1]; - u32 ext_filter_mask = 0; - u16 min_ifinfo_dump_size = 0; - int hdrlen; - - /* Same kernel<->userspace interface hack as in rtnl_dump_ifinfo. */ - hdrlen = nlmsg_len(nlh) < sizeof(struct ifinfomsg) ? - sizeof(struct rtgenmsg) : sizeof(struct ifinfomsg); - - if (nlmsg_parse(nlh, hdrlen, tb, IFLA_MAX, ifla_policy) >= 0) { - if (tb[IFLA_EXT_MASK]) - ext_filter_mask = nla_get_u32(tb[IFLA_EXT_MASK]); - } - - if (!ext_filter_mask) - return NLMSG_GOODSIZE; - /* - * traverse the list of net devices and compute the minimum - * buffer size based upon the filter mask. - */ - list_for_each_entry(dev, &net->dev_base_head, dev_list) { - min_ifinfo_dump_size = max_t(u16, min_ifinfo_dump_size, - if_nlmsg_size(dev, - ext_filter_mask)); - } - - return nlmsg_total_size(min_ifinfo_dump_size); -} - -static int rtnl_dump_all(struct sk_buff *skb, struct netlink_callback *cb) -{ - int idx; - int s_idx = cb->family; - - if (s_idx == 0) - s_idx = 1; - for (idx = 1; idx <= RTNL_FAMILY_MAX; idx++) { - int type = cb->nlh->nlmsg_type-RTM_BASE; - if (idx < s_idx || idx == PF_PACKET) - continue; - if (rtnl_msg_handlers[idx] == NULL || - rtnl_msg_handlers[idx][type].dumpit == NULL) - continue; - if (idx > s_idx) { - memset(&cb->args[0], 0, sizeof(cb->args)); - cb->prev_seq = 0; - cb->seq = 0; - } - if (rtnl_msg_handlers[idx][type].dumpit(skb, cb)) - break; - } - cb->family = idx; - - return skb->len; -} - -struct sk_buff *rtmsg_ifinfo_build_skb(int type, struct net_device *dev, - unsigned int change, gfp_t flags) -{ - struct net *net = dev_net(dev); - struct sk_buff *skb; - int err = -ENOBUFS; - size_t if_info_size; - - skb = nlmsg_new((if_info_size = if_nlmsg_size(dev, 0)), flags); - if (skb == NULL) - goto errout; - - err = rtnl_fill_ifinfo(skb, dev, type, 0, 0, change, 0, 0); - if (err < 0) { - /* -EMSGSIZE implies BUG in if_nlmsg_size() */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - goto errout; - } - return skb; -errout: - if (err < 0) - rtnl_set_sk_err(net, RTNLGRP_LINK, err); - return NULL; -} - -void rtmsg_ifinfo_send(struct sk_buff *skb, struct net_device *dev, gfp_t flags) -{ - struct net *net = dev_net(dev); - - rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, flags); -} - -void rtmsg_ifinfo(int type, struct net_device *dev, unsigned int change, - gfp_t flags) -{ - struct sk_buff *skb; - - if (dev->reg_state != NETREG_REGISTERED) - return; - - skb = rtmsg_ifinfo_build_skb(type, dev, change, flags); - if (skb) - rtmsg_ifinfo_send(skb, dev, flags); -} -EXPORT_SYMBOL(rtmsg_ifinfo); - -static int nlmsg_populate_fdb_fill(struct sk_buff *skb, - struct net_device *dev, - u8 *addr, u16 vid, u32 pid, u32 seq, - int type, unsigned int flags, - int nlflags, u16 ndm_state) -{ - struct nlmsghdr *nlh; - struct ndmsg *ndm; - - nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ndm), nlflags); - if (!nlh) - return -EMSGSIZE; - - ndm = nlmsg_data(nlh); - ndm->ndm_family = AF_BRIDGE; - ndm->ndm_pad1 = 0; - ndm->ndm_pad2 = 0; - ndm->ndm_flags = flags; - ndm->ndm_type = 0; - ndm->ndm_ifindex = dev->ifindex; - ndm->ndm_state = ndm_state; - - if (nla_put(skb, NDA_LLADDR, ETH_ALEN, addr)) - goto nla_put_failure; - if (vid) - if (nla_put(skb, NDA_VLAN, sizeof(u16), &vid)) - goto nla_put_failure; - - nlmsg_end(skb, nlh); - return 0; - -nla_put_failure: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -static inline size_t rtnl_fdb_nlmsg_size(void) -{ - return NLMSG_ALIGN(sizeof(struct ndmsg)) + - nla_total_size(ETH_ALEN) + /* NDA_LLADDR */ - nla_total_size(sizeof(u16)) + /* NDA_VLAN */ - 0; -} - -static void rtnl_fdb_notify(struct net_device *dev, u8 *addr, u16 vid, int type, - u16 ndm_state) -{ - struct net *net = dev_net(dev); - struct sk_buff *skb; - int err = -ENOBUFS; - - skb = nlmsg_new(rtnl_fdb_nlmsg_size(), GFP_ATOMIC); - if (!skb) - goto errout; - - err = nlmsg_populate_fdb_fill(skb, dev, addr, vid, - 0, 0, type, NTF_SELF, 0, ndm_state); - if (err < 0) { - kfree_skb(skb); - goto errout; - } - - rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC); - return; -errout: - rtnl_set_sk_err(net, RTNLGRP_NEIGH, err); -} - -/** - * ndo_dflt_fdb_add - default netdevice operation to add an FDB entry - */ -int ndo_dflt_fdb_add(struct ndmsg *ndm, - struct nlattr *tb[], - struct net_device *dev, - const unsigned char *addr, u16 vid, - u16 flags) -{ - int err = -EINVAL; - - /* If aging addresses are supported device will need to - * implement its own handler for this. - */ - if (ndm->ndm_state && !(ndm->ndm_state & NUD_PERMANENT)) { - pr_info("%s: FDB only supports static addresses\n", dev->name); - return err; - } - - if (vid) { - pr_info("%s: vlans aren't supported yet for dev_uc|mc_add()\n", dev->name); - return err; - } - - if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) - err = dev_uc_add_excl(dev, addr); - else if (is_multicast_ether_addr(addr)) - err = dev_mc_add_excl(dev, addr); - - /* Only return duplicate errors if NLM_F_EXCL is set */ - if (err == -EEXIST && !(flags & NLM_F_EXCL)) - err = 0; - - return err; -} -EXPORT_SYMBOL(ndo_dflt_fdb_add); - -static int fdb_vid_parse(struct nlattr *vlan_attr, u16 *p_vid) -{ - u16 vid = 0; - - if (vlan_attr) { - if (nla_len(vlan_attr) != sizeof(u16)) { - pr_info("PF_BRIDGE: RTM_NEWNEIGH with invalid vlan\n"); - return -EINVAL; - } - - vid = nla_get_u16(vlan_attr); - - if (!vid || vid >= VLAN_VID_MASK) { - pr_info("PF_BRIDGE: RTM_NEWNEIGH with invalid vlan id %d\n", - vid); - return -EINVAL; - } - } - *p_vid = vid; - return 0; -} - -static int rtnl_fdb_add(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct ndmsg *ndm; - struct nlattr *tb[NDA_MAX+1]; - struct net_device *dev; - u8 *addr; - u16 vid; - int err; - - err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL); - if (err < 0) - return err; - - ndm = nlmsg_data(nlh); - if (ndm->ndm_ifindex == 0) { - pr_info("PF_BRIDGE: RTM_NEWNEIGH with invalid ifindex\n"); - return -EINVAL; - } - - dev = __dev_get_by_index(net, ndm->ndm_ifindex); - if (dev == NULL) { - pr_info("PF_BRIDGE: RTM_NEWNEIGH with unknown ifindex\n"); - return -ENODEV; - } - - if (!tb[NDA_LLADDR] || nla_len(tb[NDA_LLADDR]) != ETH_ALEN) { - pr_info("PF_BRIDGE: RTM_NEWNEIGH with invalid address\n"); - return -EINVAL; - } - - addr = nla_data(tb[NDA_LLADDR]); - - err = fdb_vid_parse(tb[NDA_VLAN], &vid); - if (err) - return err; - - err = -EOPNOTSUPP; - - /* Support fdb on master device the net/bridge default case */ - if ((!ndm->ndm_flags || ndm->ndm_flags & NTF_MASTER) && - (dev->priv_flags & IFF_BRIDGE_PORT)) { - struct net_device *br_dev = netdev_master_upper_dev_get(dev); - const struct net_device_ops *ops = br_dev->netdev_ops; - - err = ops->ndo_fdb_add(ndm, tb, dev, addr, vid, - nlh->nlmsg_flags); - if (err) - goto out; - else - ndm->ndm_flags &= ~NTF_MASTER; - } - - /* Embedded bridge, macvlan, and any other device support */ - if ((ndm->ndm_flags & NTF_SELF)) { - if (dev->netdev_ops->ndo_fdb_add) - err = dev->netdev_ops->ndo_fdb_add(ndm, tb, dev, addr, - vid, - nlh->nlmsg_flags); - else - err = ndo_dflt_fdb_add(ndm, tb, dev, addr, vid, - nlh->nlmsg_flags); - - if (!err) { - rtnl_fdb_notify(dev, addr, vid, RTM_NEWNEIGH, - ndm->ndm_state); - ndm->ndm_flags &= ~NTF_SELF; - } - } -out: - return err; -} - -/** - * ndo_dflt_fdb_del - default netdevice operation to delete an FDB entry - */ -int ndo_dflt_fdb_del(struct ndmsg *ndm, - struct nlattr *tb[], - struct net_device *dev, - const unsigned char *addr, u16 vid) -{ - int err = -EINVAL; - - /* If aging addresses are supported device will need to - * implement its own handler for this. - */ - if (!(ndm->ndm_state & NUD_PERMANENT)) { - pr_info("%s: FDB only supports static addresses\n", dev->name); - return err; - } - - if (is_unicast_ether_addr(addr) || is_link_local_ether_addr(addr)) - err = dev_uc_del(dev, addr); - else if (is_multicast_ether_addr(addr)) - err = dev_mc_del(dev, addr); - - return err; -} -EXPORT_SYMBOL(ndo_dflt_fdb_del); - -static int rtnl_fdb_del(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct ndmsg *ndm; - struct nlattr *tb[NDA_MAX+1]; - struct net_device *dev; - int err = -EINVAL; - __u8 *addr; - u16 vid; - - if (!netlink_capable(skb, CAP_NET_ADMIN)) - return -EPERM; - - err = nlmsg_parse(nlh, sizeof(*ndm), tb, NDA_MAX, NULL); - if (err < 0) - return err; - - ndm = nlmsg_data(nlh); - if (ndm->ndm_ifindex == 0) { - pr_info("PF_BRIDGE: RTM_DELNEIGH with invalid ifindex\n"); - return -EINVAL; - } - - dev = __dev_get_by_index(net, ndm->ndm_ifindex); - if (dev == NULL) { - pr_info("PF_BRIDGE: RTM_DELNEIGH with unknown ifindex\n"); - return -ENODEV; - } - - if (!tb[NDA_LLADDR] || nla_len(tb[NDA_LLADDR]) != ETH_ALEN) { - pr_info("PF_BRIDGE: RTM_DELNEIGH with invalid address\n"); - return -EINVAL; - } - - addr = nla_data(tb[NDA_LLADDR]); - - err = fdb_vid_parse(tb[NDA_VLAN], &vid); - if (err) - return err; - - err = -EOPNOTSUPP; - - /* Support fdb on master device the net/bridge default case */ - if ((!ndm->ndm_flags || ndm->ndm_flags & NTF_MASTER) && - (dev->priv_flags & IFF_BRIDGE_PORT)) { - struct net_device *br_dev = netdev_master_upper_dev_get(dev); - const struct net_device_ops *ops = br_dev->netdev_ops; - - if (ops->ndo_fdb_del) - err = ops->ndo_fdb_del(ndm, tb, dev, addr, vid); - - if (err) - goto out; - else - ndm->ndm_flags &= ~NTF_MASTER; - } - - /* Embedded bridge, macvlan, and any other device support */ - if (ndm->ndm_flags & NTF_SELF) { - if (dev->netdev_ops->ndo_fdb_del) - err = dev->netdev_ops->ndo_fdb_del(ndm, tb, dev, addr, - vid); - else - err = ndo_dflt_fdb_del(ndm, tb, dev, addr, vid); - - if (!err) { - rtnl_fdb_notify(dev, addr, vid, RTM_DELNEIGH, - ndm->ndm_state); - ndm->ndm_flags &= ~NTF_SELF; - } - } -out: - return err; -} - -static int nlmsg_populate_fdb(struct sk_buff *skb, - struct netlink_callback *cb, - struct net_device *dev, - int *idx, - struct netdev_hw_addr_list *list) -{ - struct netdev_hw_addr *ha; - int err; - u32 portid, seq; - - portid = NETLINK_CB(cb->skb).portid; - seq = cb->nlh->nlmsg_seq; - - list_for_each_entry(ha, &list->list, list) { - if (*idx < cb->args[2]) - goto skip; - - err = nlmsg_populate_fdb_fill(skb, dev, ha->addr, 0, - portid, seq, - RTM_NEWNEIGH, NTF_SELF, - NLM_F_MULTI, NUD_PERMANENT); - if (err < 0) - return err; -skip: - *idx += 1; - } - return 0; -} - -/** - * ndo_dflt_fdb_dump - default netdevice operation to dump an FDB table. - * @nlh: netlink message header - * @dev: netdevice - * - * Default netdevice operation to dump the existing unicast address list. - * Returns number of addresses from list put in skb. - */ -int ndo_dflt_fdb_dump(struct sk_buff *skb, - struct netlink_callback *cb, - struct net_device *dev, - struct net_device *filter_dev, - int *idx) -{ - int err; - - netif_addr_lock_bh(dev); - err = nlmsg_populate_fdb(skb, cb, dev, idx, &dev->uc); - if (err) - goto out; - nlmsg_populate_fdb(skb, cb, dev, idx, &dev->mc); -out: - netif_addr_unlock_bh(dev); - return err; -} -EXPORT_SYMBOL(ndo_dflt_fdb_dump); - -static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) -{ - struct net_device *dev; - struct nlattr *tb[IFLA_MAX+1]; - struct net_device *br_dev = NULL; - const struct net_device_ops *ops = NULL; - const struct net_device_ops *cops = NULL; - struct ifinfomsg *ifm = nlmsg_data(cb->nlh); - struct net *net = sock_net(skb->sk); - struct hlist_head *head; - int brport_idx = 0; - int br_idx = 0; - int h, s_h; - int idx = 0, s_idx; - int err = 0; - int fidx = 0; - - if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX, - ifla_policy) == 0) { - if (tb[IFLA_MASTER]) - br_idx = nla_get_u32(tb[IFLA_MASTER]); - } - - brport_idx = ifm->ifi_index; - - if (br_idx) { - br_dev = __dev_get_by_index(net, br_idx); - if (!br_dev) - return -ENODEV; - - ops = br_dev->netdev_ops; - } - - s_h = cb->args[0]; - s_idx = cb->args[1]; - - for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { - idx = 0; - head = &net->dev_index_head[h]; - hlist_for_each_entry(dev, head, index_hlist) { - - if (brport_idx && (dev->ifindex != brport_idx)) - continue; - - if (!br_idx) { /* user did not specify a specific bridge */ - if (dev->priv_flags & IFF_BRIDGE_PORT) { - br_dev = netdev_master_upper_dev_get(dev); - cops = br_dev->netdev_ops; - } - } else { - if (dev != br_dev && - !(dev->priv_flags & IFF_BRIDGE_PORT)) - continue; - - if (br_dev != netdev_master_upper_dev_get(dev) && - !(dev->priv_flags & IFF_EBRIDGE)) - continue; - cops = ops; - } - - if (idx < s_idx) - goto cont; - - if (dev->priv_flags & IFF_BRIDGE_PORT) { - if (cops && cops->ndo_fdb_dump) { - err = cops->ndo_fdb_dump(skb, cb, - br_dev, dev, - &fidx); - if (err == -EMSGSIZE) - goto out; - } - } - - if (dev->netdev_ops->ndo_fdb_dump) - err = dev->netdev_ops->ndo_fdb_dump(skb, cb, - dev, NULL, - &fidx); - else - err = ndo_dflt_fdb_dump(skb, cb, dev, NULL, - &fidx); - if (err == -EMSGSIZE) - goto out; - - cops = NULL; - - /* reset fdb offset to 0 for rest of the interfaces */ - cb->args[2] = 0; - fidx = 0; -cont: - idx++; - } - } - -out: - cb->args[0] = h; - cb->args[1] = idx; - cb->args[2] = fidx; - - return skb->len; -} - -static int brport_nla_put_flag(struct sk_buff *skb, u32 flags, u32 mask, - unsigned int attrnum, unsigned int flag) -{ - if (mask & flag) - return nla_put_u8(skb, attrnum, !!(flags & flag)); - return 0; -} - -int ndo_dflt_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, - struct net_device *dev, u16 mode, - u32 flags, u32 mask, int nlflags, - u32 filter_mask, - int (*vlan_fill)(struct sk_buff *skb, - struct net_device *dev, - u32 filter_mask)) -{ - struct nlmsghdr *nlh; - struct ifinfomsg *ifm; - struct nlattr *br_afspec; - struct nlattr *protinfo; - u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; - struct net_device *br_dev = netdev_master_upper_dev_get(dev); - int err = 0; - - nlh = nlmsg_put(skb, pid, seq, RTM_NEWLINK, sizeof(*ifm), nlflags); - if (nlh == NULL) - return -EMSGSIZE; - - ifm = nlmsg_data(nlh); - ifm->ifi_family = AF_BRIDGE; - ifm->__ifi_pad = 0; - ifm->ifi_type = dev->type; - ifm->ifi_index = dev->ifindex; - ifm->ifi_flags = dev_get_flags(dev); - ifm->ifi_change = 0; - - - if (nla_put_string(skb, IFLA_IFNAME, dev->name) || - nla_put_u32(skb, IFLA_MTU, dev->mtu) || - nla_put_u8(skb, IFLA_OPERSTATE, operstate) || - (br_dev && - nla_put_u32(skb, IFLA_MASTER, br_dev->ifindex)) || - (dev->addr_len && - nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) || - (dev->ifindex != dev_get_iflink(dev) && - nla_put_u32(skb, IFLA_LINK, dev_get_iflink(dev)))) - goto nla_put_failure; - - br_afspec = nla_nest_start(skb, IFLA_AF_SPEC); - if (!br_afspec) - goto nla_put_failure; - - if (nla_put_u16(skb, IFLA_BRIDGE_FLAGS, BRIDGE_FLAGS_SELF)) { - nla_nest_cancel(skb, br_afspec); - goto nla_put_failure; - } - - if (mode != BRIDGE_MODE_UNDEF) { - if (nla_put_u16(skb, IFLA_BRIDGE_MODE, mode)) { - nla_nest_cancel(skb, br_afspec); - goto nla_put_failure; - } - } - if (vlan_fill) { - err = vlan_fill(skb, dev, filter_mask); - if (err) { - nla_nest_cancel(skb, br_afspec); - goto nla_put_failure; - } - } - nla_nest_end(skb, br_afspec); - - protinfo = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED); - if (!protinfo) - goto nla_put_failure; - - if (brport_nla_put_flag(skb, flags, mask, - IFLA_BRPORT_MODE, BR_HAIRPIN_MODE) || - brport_nla_put_flag(skb, flags, mask, - IFLA_BRPORT_GUARD, BR_BPDU_GUARD) || - brport_nla_put_flag(skb, flags, mask, - IFLA_BRPORT_FAST_LEAVE, - BR_MULTICAST_FAST_LEAVE) || - brport_nla_put_flag(skb, flags, mask, - IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK) || - brport_nla_put_flag(skb, flags, mask, - IFLA_BRPORT_LEARNING, BR_LEARNING) || - brport_nla_put_flag(skb, flags, mask, - IFLA_BRPORT_LEARNING_SYNC, BR_LEARNING_SYNC) || - brport_nla_put_flag(skb, flags, mask, - IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD) || - brport_nla_put_flag(skb, flags, mask, - IFLA_BRPORT_PROXYARP, BR_PROXYARP)) { - nla_nest_cancel(skb, protinfo); - goto nla_put_failure; - } - - nla_nest_end(skb, protinfo); - - nlmsg_end(skb, nlh); - return 0; -nla_put_failure: - nlmsg_cancel(skb, nlh); - return err ? err : -EMSGSIZE; -} -EXPORT_SYMBOL_GPL(ndo_dflt_bridge_getlink); - -static int rtnl_bridge_getlink(struct sk_buff *skb, struct netlink_callback *cb) -{ - struct net *net = sock_net(skb->sk); - struct net_device *dev; - int idx = 0; - u32 portid = NETLINK_CB(cb->skb).portid; - u32 seq = cb->nlh->nlmsg_seq; - u32 filter_mask = 0; - int err; - - if (nlmsg_len(cb->nlh) > sizeof(struct ifinfomsg)) { - struct nlattr *extfilt; - - extfilt = nlmsg_find_attr(cb->nlh, sizeof(struct ifinfomsg), - IFLA_EXT_MASK); - if (extfilt) { - if (nla_len(extfilt) < sizeof(filter_mask)) - return -EINVAL; - - filter_mask = nla_get_u32(extfilt); - } - } - - rcu_read_lock(); - for_each_netdev_rcu(net, dev) { - const struct net_device_ops *ops = dev->netdev_ops; - struct net_device *br_dev = netdev_master_upper_dev_get(dev); - - if (br_dev && br_dev->netdev_ops->ndo_bridge_getlink) { - if (idx >= cb->args[0]) { - err = br_dev->netdev_ops->ndo_bridge_getlink( - skb, portid, seq, dev, - filter_mask, NLM_F_MULTI); - if (err < 0 && err != -EOPNOTSUPP) - break; - } - idx++; - } - - if (ops->ndo_bridge_getlink) { - if (idx >= cb->args[0]) { - err = ops->ndo_bridge_getlink(skb, portid, - seq, dev, - filter_mask, - NLM_F_MULTI); - if (err < 0 && err != -EOPNOTSUPP) - break; - } - idx++; - } - } - rcu_read_unlock(); - cb->args[0] = idx; - - return skb->len; -} - -static inline size_t bridge_nlmsg_size(void) -{ - return NLMSG_ALIGN(sizeof(struct ifinfomsg)) - + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ - + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ - + nla_total_size(sizeof(u32)) /* IFLA_MASTER */ - + nla_total_size(sizeof(u32)) /* IFLA_MTU */ - + nla_total_size(sizeof(u32)) /* IFLA_LINK */ - + nla_total_size(sizeof(u32)) /* IFLA_OPERSTATE */ - + nla_total_size(sizeof(u8)) /* IFLA_PROTINFO */ - + nla_total_size(sizeof(struct nlattr)) /* IFLA_AF_SPEC */ - + nla_total_size(sizeof(u16)) /* IFLA_BRIDGE_FLAGS */ - + nla_total_size(sizeof(u16)); /* IFLA_BRIDGE_MODE */ -} - -static int rtnl_bridge_notify(struct net_device *dev) -{ - struct net *net = dev_net(dev); - struct sk_buff *skb; - int err = -EOPNOTSUPP; - - if (!dev->netdev_ops->ndo_bridge_getlink) - return 0; - - skb = nlmsg_new(bridge_nlmsg_size(), GFP_ATOMIC); - if (!skb) { - err = -ENOMEM; - goto errout; - } - - err = dev->netdev_ops->ndo_bridge_getlink(skb, 0, 0, dev, 0, 0); - if (err < 0) - goto errout; - - if (!skb->len) - goto errout; - - rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC); - return 0; -errout: - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - if (err) - rtnl_set_sk_err(net, RTNLGRP_LINK, err); - return err; -} - -static int rtnl_bridge_setlink(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct ifinfomsg *ifm; - struct net_device *dev; - struct nlattr *br_spec, *attr = NULL; - int rem, err = -EOPNOTSUPP; - u16 flags = 0; - bool have_flags = false; - - if (nlmsg_len(nlh) < sizeof(*ifm)) - return -EINVAL; - - ifm = nlmsg_data(nlh); - if (ifm->ifi_family != AF_BRIDGE) - return -EPFNOSUPPORT; - - dev = __dev_get_by_index(net, ifm->ifi_index); - if (!dev) { - pr_info("PF_BRIDGE: RTM_SETLINK with unknown ifindex\n"); - return -ENODEV; - } - - br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); - if (br_spec) { - nla_for_each_nested(attr, br_spec, rem) { - if (nla_type(attr) == IFLA_BRIDGE_FLAGS) { - if (nla_len(attr) < sizeof(flags)) - return -EINVAL; - - have_flags = true; - flags = nla_get_u16(attr); - break; - } - } - } - - if (!flags || (flags & BRIDGE_FLAGS_MASTER)) { - struct net_device *br_dev = netdev_master_upper_dev_get(dev); - - if (!br_dev || !br_dev->netdev_ops->ndo_bridge_setlink) { - err = -EOPNOTSUPP; - goto out; - } - - err = br_dev->netdev_ops->ndo_bridge_setlink(dev, nlh, flags); - if (err) - goto out; - - flags &= ~BRIDGE_FLAGS_MASTER; - } - - if ((flags & BRIDGE_FLAGS_SELF)) { - if (!dev->netdev_ops->ndo_bridge_setlink) - err = -EOPNOTSUPP; - else - err = dev->netdev_ops->ndo_bridge_setlink(dev, nlh, - flags); - if (!err) { - flags &= ~BRIDGE_FLAGS_SELF; - - /* Generate event to notify upper layer of bridge - * change - */ - err = rtnl_bridge_notify(dev); - } - } - - if (have_flags) - memcpy(nla_data(attr), &flags, sizeof(flags)); -out: - return err; -} - -static int rtnl_bridge_dellink(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct ifinfomsg *ifm; - struct net_device *dev; - struct nlattr *br_spec, *attr = NULL; - int rem, err = -EOPNOTSUPP; - u16 flags = 0; - bool have_flags = false; - - if (nlmsg_len(nlh) < sizeof(*ifm)) - return -EINVAL; - - ifm = nlmsg_data(nlh); - if (ifm->ifi_family != AF_BRIDGE) - return -EPFNOSUPPORT; - - dev = __dev_get_by_index(net, ifm->ifi_index); - if (!dev) { - pr_info("PF_BRIDGE: RTM_SETLINK with unknown ifindex\n"); - return -ENODEV; - } - - br_spec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC); - if (br_spec) { - nla_for_each_nested(attr, br_spec, rem) { - if (nla_type(attr) == IFLA_BRIDGE_FLAGS) { - if (nla_len(attr) < sizeof(flags)) - return -EINVAL; - - have_flags = true; - flags = nla_get_u16(attr); - break; - } - } - } - - if (!flags || (flags & BRIDGE_FLAGS_MASTER)) { - struct net_device *br_dev = netdev_master_upper_dev_get(dev); - - if (!br_dev || !br_dev->netdev_ops->ndo_bridge_dellink) { - err = -EOPNOTSUPP; - goto out; - } - - err = br_dev->netdev_ops->ndo_bridge_dellink(dev, nlh, flags); - if (err) - goto out; - - flags &= ~BRIDGE_FLAGS_MASTER; - } - - if ((flags & BRIDGE_FLAGS_SELF)) { - if (!dev->netdev_ops->ndo_bridge_dellink) - err = -EOPNOTSUPP; - else - err = dev->netdev_ops->ndo_bridge_dellink(dev, nlh, - flags); - - if (!err) { - flags &= ~BRIDGE_FLAGS_SELF; - - /* Generate event to notify upper layer of bridge - * change - */ - err = rtnl_bridge_notify(dev); - } - } - - if (have_flags) - memcpy(nla_data(attr), &flags, sizeof(flags)); -out: - return err; -} - -static bool stats_attr_valid(unsigned int mask, int attrid, int idxattr) -{ - return (mask & IFLA_STATS_FILTER_BIT(attrid)) && - (!idxattr || idxattr == attrid); -} - -#define IFLA_OFFLOAD_XSTATS_FIRST (IFLA_OFFLOAD_XSTATS_UNSPEC + 1) -static int rtnl_get_offload_stats_attr_size(int attr_id) -{ - switch (attr_id) { - case IFLA_OFFLOAD_XSTATS_CPU_HIT: - return sizeof(struct rtnl_link_stats64); - } - - return 0; -} - -static int rtnl_get_offload_stats(struct sk_buff *skb, struct net_device *dev, - int *prividx) -{ - struct nlattr *attr = NULL; - int attr_id, size; - void *attr_data; - int err; - - if (!(dev->netdev_ops && dev->netdev_ops->ndo_has_offload_stats && - dev->netdev_ops->ndo_get_offload_stats)) - return -ENODATA; - - for (attr_id = IFLA_OFFLOAD_XSTATS_FIRST; - attr_id <= IFLA_OFFLOAD_XSTATS_MAX; attr_id++) { - if (attr_id < *prividx) - continue; - - size = rtnl_get_offload_stats_attr_size(attr_id); - if (!size) - continue; - - if (!dev->netdev_ops->ndo_has_offload_stats(attr_id)) - continue; - - attr = nla_reserve_64bit(skb, attr_id, size, - IFLA_OFFLOAD_XSTATS_UNSPEC); - if (!attr) - goto nla_put_failure; - - attr_data = nla_data(attr); - memset(attr_data, 0, size); - err = dev->netdev_ops->ndo_get_offload_stats(attr_id, dev, - attr_data); - if (err) - goto get_offload_stats_failure; - } - - if (!attr) - return -ENODATA; - - *prividx = 0; - return 0; - -nla_put_failure: - err = -EMSGSIZE; -get_offload_stats_failure: - *prividx = attr_id; - return err; -} - -static int rtnl_get_offload_stats_size(const struct net_device *dev) -{ - int nla_size = 0; - int attr_id; - int size; - - if (!(dev->netdev_ops && dev->netdev_ops->ndo_has_offload_stats && - dev->netdev_ops->ndo_get_offload_stats)) - return 0; - - for (attr_id = IFLA_OFFLOAD_XSTATS_FIRST; - attr_id <= IFLA_OFFLOAD_XSTATS_MAX; attr_id++) { - if (!dev->netdev_ops->ndo_has_offload_stats(attr_id)) - continue; - size = rtnl_get_offload_stats_attr_size(attr_id); - nla_size += nla_total_size_64bit(size); - } - - if (nla_size != 0) - nla_size += nla_total_size(0); - - return nla_size; -} - -static int rtnl_fill_statsinfo(struct sk_buff *skb, struct net_device *dev, - int type, u32 pid, u32 seq, u32 change, - unsigned int flags, unsigned int filter_mask, - int *idxattr, int *prividx) -{ - struct if_stats_msg *ifsm; - struct nlmsghdr *nlh; - struct nlattr *attr; - int s_prividx = *prividx; - int err; - - ASSERT_RTNL(); - - nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifsm), flags); - if (!nlh) - return -EMSGSIZE; - - ifsm = nlmsg_data(nlh); - ifsm->ifindex = dev->ifindex; - ifsm->filter_mask = filter_mask; - - if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_64, *idxattr)) { - struct rtnl_link_stats64 *sp; - - attr = nla_reserve_64bit(skb, IFLA_STATS_LINK_64, - sizeof(struct rtnl_link_stats64), - IFLA_STATS_UNSPEC); - if (!attr) - goto nla_put_failure; - - sp = nla_data(attr); - dev_get_stats(dev, sp); - } - - if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_XSTATS, *idxattr)) { - const struct rtnl_link_ops *ops = dev->rtnl_link_ops; - - if (ops && ops->fill_linkxstats) { - *idxattr = IFLA_STATS_LINK_XSTATS; - attr = nla_nest_start(skb, - IFLA_STATS_LINK_XSTATS); - if (!attr) - goto nla_put_failure; - - err = ops->fill_linkxstats(skb, dev, prividx, *idxattr); - nla_nest_end(skb, attr); - if (err) - goto nla_put_failure; - *idxattr = 0; - } - } - - if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_XSTATS_SLAVE, - *idxattr)) { - const struct rtnl_link_ops *ops = NULL; - const struct net_device *master; - - master = netdev_master_upper_dev_get(dev); - if (master) - ops = master->rtnl_link_ops; - if (ops && ops->fill_linkxstats) { - *idxattr = IFLA_STATS_LINK_XSTATS_SLAVE; - attr = nla_nest_start(skb, - IFLA_STATS_LINK_XSTATS_SLAVE); - if (!attr) - goto nla_put_failure; - - err = ops->fill_linkxstats(skb, dev, prividx, *idxattr); - nla_nest_end(skb, attr); - if (err) - goto nla_put_failure; - *idxattr = 0; - } - } - - if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_OFFLOAD_XSTATS, - *idxattr)) { - *idxattr = IFLA_STATS_LINK_OFFLOAD_XSTATS; - attr = nla_nest_start(skb, IFLA_STATS_LINK_OFFLOAD_XSTATS); - if (!attr) - goto nla_put_failure; - - err = rtnl_get_offload_stats(skb, dev, prividx); - if (err == -ENODATA) - nla_nest_cancel(skb, attr); - else - nla_nest_end(skb, attr); - - if (err && err != -ENODATA) - goto nla_put_failure; - *idxattr = 0; - } - - nlmsg_end(skb, nlh); - - return 0; - -nla_put_failure: - /* not a multi message or no progress mean a real error */ - if (!(flags & NLM_F_MULTI) || s_prividx == *prividx) - nlmsg_cancel(skb, nlh); - else - nlmsg_end(skb, nlh); - - return -EMSGSIZE; -} - -static size_t if_nlmsg_stats_size(const struct net_device *dev, - u32 filter_mask) -{ - size_t size = 0; - - if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_64, 0)) - size += nla_total_size_64bit(sizeof(struct rtnl_link_stats64)); - - if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_XSTATS, 0)) { - const struct rtnl_link_ops *ops = dev->rtnl_link_ops; - int attr = IFLA_STATS_LINK_XSTATS; - - if (ops && ops->get_linkxstats_size) { - size += nla_total_size(ops->get_linkxstats_size(dev, - attr)); - /* for IFLA_STATS_LINK_XSTATS */ - size += nla_total_size(0); - } - } - - if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_XSTATS_SLAVE, 0)) { - struct net_device *_dev = (struct net_device *)dev; - const struct rtnl_link_ops *ops = NULL; - const struct net_device *master; - - /* netdev_master_upper_dev_get can't take const */ - master = netdev_master_upper_dev_get(_dev); - if (master) - ops = master->rtnl_link_ops; - if (ops && ops->get_linkxstats_size) { - int attr = IFLA_STATS_LINK_XSTATS_SLAVE; - - size += nla_total_size(ops->get_linkxstats_size(dev, - attr)); - /* for IFLA_STATS_LINK_XSTATS_SLAVE */ - size += nla_total_size(0); - } - } - - if (stats_attr_valid(filter_mask, IFLA_STATS_LINK_OFFLOAD_XSTATS, 0)) - size += rtnl_get_offload_stats_size(dev); - - return size; -} - -static int rtnl_stats_get(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct net_device *dev = NULL; - int idxattr = 0, prividx = 0; - struct if_stats_msg *ifsm; - struct sk_buff *nskb; - u32 filter_mask; - int err; - - ifsm = nlmsg_data(nlh); - if (ifsm->ifindex > 0) - dev = __dev_get_by_index(net, ifsm->ifindex); - else - return -EINVAL; - - if (!dev) - return -ENODEV; - - filter_mask = ifsm->filter_mask; - if (!filter_mask) - return -EINVAL; - - nskb = nlmsg_new(if_nlmsg_stats_size(dev, filter_mask), GFP_KERNEL); - if (!nskb) - return -ENOBUFS; - - err = rtnl_fill_statsinfo(nskb, dev, RTM_NEWSTATS, - NETLINK_CB(skb).portid, nlh->nlmsg_seq, 0, - 0, filter_mask, &idxattr, &prividx); - if (err < 0) { - /* -EMSGSIZE implies BUG in if_nlmsg_stats_size */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(nskb); - } else { - err = rtnl_unicast(nskb, net, NETLINK_CB(skb).portid); - } - - return err; -} - -static int rtnl_stats_dump(struct sk_buff *skb, struct netlink_callback *cb) -{ - int h, s_h, err, s_idx, s_idxattr, s_prividx; - struct net *net = sock_net(skb->sk); - unsigned int flags = NLM_F_MULTI; - struct if_stats_msg *ifsm; - struct hlist_head *head; - struct net_device *dev; - u32 filter_mask = 0; - int idx = 0; - - s_h = cb->args[0]; - s_idx = cb->args[1]; - s_idxattr = cb->args[2]; - s_prividx = cb->args[3]; - - cb->seq = net->dev_base_seq; - - ifsm = nlmsg_data(cb->nlh); - filter_mask = ifsm->filter_mask; - if (!filter_mask) - return -EINVAL; - - for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { - idx = 0; - head = &net->dev_index_head[h]; - hlist_for_each_entry(dev, head, index_hlist) { - if (idx < s_idx) - goto cont; - err = rtnl_fill_statsinfo(skb, dev, RTM_NEWSTATS, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, 0, - flags, filter_mask, - &s_idxattr, &s_prividx); - /* If we ran out of room on the first message, - * we're in trouble - */ - WARN_ON((err == -EMSGSIZE) && (skb->len == 0)); - - if (err < 0) - goto out; - s_prividx = 0; - s_idxattr = 0; - nl_dump_check_consistent(cb, nlmsg_hdr(skb)); -cont: - idx++; - } - } -out: - cb->args[3] = s_prividx; - cb->args[2] = s_idxattr; - cb->args[1] = idx; - cb->args[0] = h; - - return skb->len; -} - -/* Process one rtnetlink message. */ - -static int rtnetlink_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - rtnl_doit_func doit; - int kind; - int family; - int type; - int err; - - type = nlh->nlmsg_type; - if (type > RTM_MAX) - return -EOPNOTSUPP; - - type -= RTM_BASE; - - /* All the messages must have at least 1 byte length */ - if (nlmsg_len(nlh) < sizeof(struct rtgenmsg)) - return 0; - - family = ((struct rtgenmsg *)nlmsg_data(nlh))->rtgen_family; - kind = type&3; - - if (kind != 2 && !netlink_net_capable(skb, CAP_NET_ADMIN)) - return -EPERM; - - if (kind == 2 && nlh->nlmsg_flags&NLM_F_DUMP) { - struct sock *rtnl; - rtnl_dumpit_func dumpit; - rtnl_calcit_func calcit; - u16 min_dump_alloc = 0; - - dumpit = rtnl_get_dumpit(family, type); - if (dumpit == NULL) - return -EOPNOTSUPP; - calcit = rtnl_get_calcit(family, type); - if (calcit) - min_dump_alloc = calcit(skb, nlh); - - __rtnl_unlock(); - rtnl = net->rtnl; - { - struct netlink_dump_control c = { - .dump = dumpit, - .min_dump_alloc = min_dump_alloc, - }; - err = netlink_dump_start(rtnl, skb, nlh, &c); - } - rtnl_lock(); - return err; - } - - doit = rtnl_get_doit(family, type); - if (doit == NULL) - return -EOPNOTSUPP; - - return doit(skb, nlh); -} - -static void rtnetlink_rcv(struct sk_buff *skb) -{ - rtnl_lock(); - netlink_rcv_skb(skb, &rtnetlink_rcv_msg); - rtnl_unlock(); -} - -static int rtnetlink_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - - switch (event) { - case NETDEV_UP: - case NETDEV_DOWN: - case NETDEV_PRE_UP: - case NETDEV_POST_INIT: - case NETDEV_REGISTER: - case NETDEV_CHANGE: - case NETDEV_PRE_TYPE_CHANGE: - case NETDEV_GOING_DOWN: - case NETDEV_UNREGISTER: - case NETDEV_UNREGISTER_FINAL: - case NETDEV_RELEASE: - case NETDEV_JOIN: - case NETDEV_BONDING_INFO: - break; - default: - rtmsg_ifinfo(RTM_NEWLINK, dev, 0, GFP_KERNEL); - break; - } - return NOTIFY_DONE; -} - -static struct notifier_block rtnetlink_dev_notifier = { - .notifier_call = rtnetlink_event, -}; - - -static int __net_init rtnetlink_net_init(struct net *net) -{ - struct sock *sk; - struct netlink_kernel_cfg cfg = { - .groups = RTNLGRP_MAX, - .input = rtnetlink_rcv, - .cb_mutex = &rtnl_mutex, - .flags = NL_CFG_F_NONROOT_RECV, - }; - - sk = netlink_kernel_create(net, NETLINK_ROUTE, &cfg); - if (!sk) - return -ENOMEM; - net->rtnl = sk; - return 0; -} - -static void __net_exit rtnetlink_net_exit(struct net *net) -{ - netlink_kernel_release(net->rtnl); - net->rtnl = NULL; -} - -static struct pernet_operations rtnetlink_net_ops = { - .init = rtnetlink_net_init, - .exit = rtnetlink_net_exit, -}; - -void __init rtnetlink_init(void) -{ - if (register_pernet_subsys(&rtnetlink_net_ops)) - panic("rtnetlink_init: cannot initialize rtnetlink\n"); - - register_netdevice_notifier(&rtnetlink_dev_notifier); - - rtnl_register(PF_UNSPEC, RTM_GETLINK, rtnl_getlink, - rtnl_dump_ifinfo, rtnl_calcit); - rtnl_register(PF_UNSPEC, RTM_SETLINK, rtnl_setlink, NULL, NULL); - rtnl_register(PF_UNSPEC, RTM_NEWLINK, rtnl_newlink, NULL, NULL); - rtnl_register(PF_UNSPEC, RTM_DELLINK, rtnl_dellink, NULL, NULL); - - rtnl_register(PF_UNSPEC, RTM_GETADDR, NULL, rtnl_dump_all, NULL); - rtnl_register(PF_UNSPEC, RTM_GETROUTE, NULL, rtnl_dump_all, NULL); - - rtnl_register(PF_BRIDGE, RTM_NEWNEIGH, rtnl_fdb_add, NULL, NULL); - rtnl_register(PF_BRIDGE, RTM_DELNEIGH, rtnl_fdb_del, NULL, NULL); - rtnl_register(PF_BRIDGE, RTM_GETNEIGH, NULL, rtnl_fdb_dump, NULL); - - rtnl_register(PF_BRIDGE, RTM_GETLINK, NULL, rtnl_bridge_getlink, NULL); - rtnl_register(PF_BRIDGE, RTM_DELLINK, rtnl_bridge_dellink, NULL, NULL); - rtnl_register(PF_BRIDGE, RTM_SETLINK, rtnl_bridge_setlink, NULL, NULL); - - rtnl_register(PF_UNSPEC, RTM_GETSTATS, rtnl_stats_get, rtnl_stats_dump, - NULL); -} diff --git a/src/linux/net/core/scm.c b/src/linux/net/core/scm.c deleted file mode 100644 index 2696aef..0000000 --- a/src/linux/net/core/scm.c +++ /dev/null @@ -1,349 +0,0 @@ -/* scm.c - Socket level control messages processing. - * - * Author: Alexey Kuznetsov, - * Alignment and value checking mods by Craig Metz - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#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 - - -/* - * Only allow a user to send credentials, that they could set with - * setu(g)id. - */ - -static __inline__ int scm_check_creds(struct ucred *creds) -{ - const struct cred *cred = current_cred(); - kuid_t uid = make_kuid(cred->user_ns, creds->uid); - kgid_t gid = make_kgid(cred->user_ns, creds->gid); - - if (!uid_valid(uid) || !gid_valid(gid)) - return -EINVAL; - - if ((creds->pid == task_tgid_vnr(current) || - ns_capable(task_active_pid_ns(current)->user_ns, CAP_SYS_ADMIN)) && - ((uid_eq(uid, cred->uid) || uid_eq(uid, cred->euid) || - uid_eq(uid, cred->suid)) || ns_capable(cred->user_ns, CAP_SETUID)) && - ((gid_eq(gid, cred->gid) || gid_eq(gid, cred->egid) || - gid_eq(gid, cred->sgid)) || ns_capable(cred->user_ns, CAP_SETGID))) { - return 0; - } - return -EPERM; -} - -static int scm_fp_copy(struct cmsghdr *cmsg, struct scm_fp_list **fplp) -{ - int *fdp = (int*)CMSG_DATA(cmsg); - struct scm_fp_list *fpl = *fplp; - struct file **fpp; - int i, num; - - num = (cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)))/sizeof(int); - - if (num <= 0) - return 0; - - if (num > SCM_MAX_FD) - return -EINVAL; - - if (!fpl) - { - fpl = kmalloc(sizeof(struct scm_fp_list), GFP_KERNEL); - if (!fpl) - return -ENOMEM; - *fplp = fpl; - fpl->count = 0; - fpl->max = SCM_MAX_FD; - fpl->user = NULL; - } - fpp = &fpl->fp[fpl->count]; - - if (fpl->count + num > fpl->max) - return -EINVAL; - - /* - * Verify the descriptors and increment the usage count. - */ - - for (i=0; i< num; i++) - { - int fd = fdp[i]; - struct file *file; - - if (fd < 0 || !(file = fget_raw(fd))) - return -EBADF; - *fpp++ = file; - fpl->count++; - } - - if (!fpl->user) - fpl->user = get_uid(current_user()); - - return num; -} - -void __scm_destroy(struct scm_cookie *scm) -{ - struct scm_fp_list *fpl = scm->fp; - int i; - - if (fpl) { - scm->fp = NULL; - for (i=fpl->count-1; i>=0; i--) - fput(fpl->fp[i]); - free_uid(fpl->user); - kfree(fpl); - } -} -EXPORT_SYMBOL(__scm_destroy); - -int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p) -{ - struct cmsghdr *cmsg; - int err; - - for_each_cmsghdr(cmsg, msg) { - err = -EINVAL; - - /* Verify that cmsg_len is at least sizeof(struct cmsghdr) */ - /* The first check was omitted in <= 2.2.5. The reasoning was - that parser checks cmsg_len in any case, so that - additional check would be work duplication. - But if cmsg_level is not SOL_SOCKET, we do not check - for too short ancillary data object at all! Oops. - OK, let's add it... - */ - if (!CMSG_OK(msg, cmsg)) - goto error; - - if (cmsg->cmsg_level != SOL_SOCKET) - continue; - - switch (cmsg->cmsg_type) - { - case SCM_RIGHTS: - if (!sock->ops || sock->ops->family != PF_UNIX) - goto error; - err=scm_fp_copy(cmsg, &p->fp); - if (err<0) - goto error; - break; - case SCM_CREDENTIALS: - { - struct ucred creds; - kuid_t uid; - kgid_t gid; - if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct ucred))) - goto error; - memcpy(&creds, CMSG_DATA(cmsg), sizeof(struct ucred)); - err = scm_check_creds(&creds); - if (err) - goto error; - - p->creds.pid = creds.pid; - if (!p->pid || pid_vnr(p->pid) != creds.pid) { - struct pid *pid; - err = -ESRCH; - pid = find_get_pid(creds.pid); - if (!pid) - goto error; - put_pid(p->pid); - p->pid = pid; - } - - err = -EINVAL; - uid = make_kuid(current_user_ns(), creds.uid); - gid = make_kgid(current_user_ns(), creds.gid); - if (!uid_valid(uid) || !gid_valid(gid)) - goto error; - - p->creds.uid = uid; - p->creds.gid = gid; - break; - } - default: - goto error; - } - } - - if (p->fp && !p->fp->count) - { - kfree(p->fp); - p->fp = NULL; - } - return 0; - -error: - scm_destroy(p); - return err; -} -EXPORT_SYMBOL(__scm_send); - -int put_cmsg(struct msghdr * msg, int level, int type, int len, void *data) -{ - struct cmsghdr __user *cm - = (__force struct cmsghdr __user *)msg->msg_control; - struct cmsghdr cmhdr; - int cmlen = CMSG_LEN(len); - int err; - - if (MSG_CMSG_COMPAT & msg->msg_flags) - return put_cmsg_compat(msg, level, type, len, data); - - if (cm==NULL || msg->msg_controllen < sizeof(*cm)) { - msg->msg_flags |= MSG_CTRUNC; - return 0; /* XXX: return error? check spec. */ - } - if (msg->msg_controllen < cmlen) { - msg->msg_flags |= MSG_CTRUNC; - cmlen = msg->msg_controllen; - } - cmhdr.cmsg_level = level; - cmhdr.cmsg_type = type; - cmhdr.cmsg_len = cmlen; - - err = -EFAULT; - if (copy_to_user(cm, &cmhdr, sizeof cmhdr)) - goto out; - if (copy_to_user(CMSG_DATA(cm), data, cmlen - sizeof(struct cmsghdr))) - goto out; - cmlen = CMSG_SPACE(len); - if (msg->msg_controllen < cmlen) - cmlen = msg->msg_controllen; - msg->msg_control += cmlen; - msg->msg_controllen -= cmlen; - err = 0; -out: - return err; -} -EXPORT_SYMBOL(put_cmsg); - -void scm_detach_fds(struct msghdr *msg, struct scm_cookie *scm) -{ - struct cmsghdr __user *cm - = (__force struct cmsghdr __user*)msg->msg_control; - - int fdmax = 0; - int fdnum = scm->fp->count; - struct file **fp = scm->fp->fp; - int __user *cmfptr; - int err = 0, i; - - if (MSG_CMSG_COMPAT & msg->msg_flags) { - scm_detach_fds_compat(msg, scm); - return; - } - - if (msg->msg_controllen > sizeof(struct cmsghdr)) - fdmax = ((msg->msg_controllen - sizeof(struct cmsghdr)) - / sizeof(int)); - - if (fdnum < fdmax) - fdmax = fdnum; - - for (i=0, cmfptr=(__force int __user *)CMSG_DATA(cm); imsg_flags - ? O_CLOEXEC : 0); - if (err < 0) - break; - new_fd = err; - err = put_user(new_fd, cmfptr); - if (err) { - put_unused_fd(new_fd); - break; - } - /* Bump the usage count and install the file. */ - sock = sock_from_file(fp[i], &err); - if (sock) { - sock_update_netprioidx(&sock->sk->sk_cgrp_data); - sock_update_classid(&sock->sk->sk_cgrp_data); - } - fd_install(new_fd, get_file(fp[i])); - } - - if (i > 0) - { - int cmlen = CMSG_LEN(i*sizeof(int)); - err = put_user(SOL_SOCKET, &cm->cmsg_level); - if (!err) - err = put_user(SCM_RIGHTS, &cm->cmsg_type); - if (!err) - err = put_user(cmlen, &cm->cmsg_len); - if (!err) { - cmlen = CMSG_SPACE(i*sizeof(int)); - if (msg->msg_controllen < cmlen) - cmlen = msg->msg_controllen; - msg->msg_control += cmlen; - msg->msg_controllen -= cmlen; - } - } - if (i < fdnum || (fdnum && fdmax <= 0)) - msg->msg_flags |= MSG_CTRUNC; - - /* - * All of the files that fit in the message have had their - * usage counts incremented, so we just free the list. - */ - __scm_destroy(scm); -} -EXPORT_SYMBOL(scm_detach_fds); - -struct scm_fp_list *scm_fp_dup(struct scm_fp_list *fpl) -{ - struct scm_fp_list *new_fpl; - int i; - - if (!fpl) - return NULL; - - new_fpl = kmemdup(fpl, offsetof(struct scm_fp_list, fp[fpl->count]), - GFP_KERNEL); - if (new_fpl) { - for (i = 0; i < fpl->count; i++) - get_file(fpl->fp[i]); - new_fpl->max = new_fpl->count; - new_fpl->user = get_uid(fpl->user); - } - return new_fpl; -} -EXPORT_SYMBOL(scm_fp_dup); diff --git a/src/linux/net/core/secure_seq.c b/src/linux/net/core/secure_seq.c deleted file mode 100644 index fd3ce46..0000000 --- a/src/linux/net/core/secure_seq.c +++ /dev/null @@ -1,173 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#if IS_ENABLED(CONFIG_IPV6) || IS_ENABLED(CONFIG_INET) -#define NET_SECRET_SIZE (MD5_MESSAGE_BYTES / 4) - -static u32 net_secret[NET_SECRET_SIZE] ____cacheline_aligned; - -static __always_inline void net_secret_init(void) -{ - net_get_random_once(net_secret, sizeof(net_secret)); -} -#endif - -#ifdef CONFIG_INET -static u32 seq_scale(u32 seq) -{ - /* - * As close as possible to RFC 793, which - * suggests using a 250 kHz clock. - * Further reading shows this assumes 2 Mb/s networks. - * For 10 Mb/s Ethernet, a 1 MHz clock is appropriate. - * For 10 Gb/s Ethernet, a 1 GHz clock should be ok, but - * we also need to limit the resolution so that the u32 seq - * overlaps less than one time per MSL (2 minutes). - * Choosing a clock of 64 ns period is OK. (period of 274 s) - */ - return seq + (ktime_get_real_ns() >> 6); -} -#endif - -#if IS_ENABLED(CONFIG_IPV6) -__u32 secure_tcpv6_sequence_number(const __be32 *saddr, const __be32 *daddr, - __be16 sport, __be16 dport) -{ - u32 secret[MD5_MESSAGE_BYTES / 4]; - u32 hash[MD5_DIGEST_WORDS]; - u32 i; - - net_secret_init(); - memcpy(hash, saddr, 16); - for (i = 0; i < 4; i++) - secret[i] = net_secret[i] + (__force u32)daddr[i]; - secret[4] = net_secret[4] + - (((__force u16)sport << 16) + (__force u16)dport); - for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++) - secret[i] = net_secret[i]; - - md5_transform(hash, secret); - - return seq_scale(hash[0]); -} -EXPORT_SYMBOL(secure_tcpv6_sequence_number); - -u32 secure_ipv6_port_ephemeral(const __be32 *saddr, const __be32 *daddr, - __be16 dport) -{ - u32 secret[MD5_MESSAGE_BYTES / 4]; - u32 hash[MD5_DIGEST_WORDS]; - u32 i; - - net_secret_init(); - memcpy(hash, saddr, 16); - for (i = 0; i < 4; i++) - secret[i] = net_secret[i] + (__force u32) daddr[i]; - secret[4] = net_secret[4] + (__force u32)dport; - for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++) - secret[i] = net_secret[i]; - - md5_transform(hash, secret); - - return hash[0]; -} -EXPORT_SYMBOL(secure_ipv6_port_ephemeral); -#endif - -#ifdef CONFIG_INET - -__u32 secure_tcp_sequence_number(__be32 saddr, __be32 daddr, - __be16 sport, __be16 dport) -{ - u32 hash[MD5_DIGEST_WORDS]; - - net_secret_init(); - hash[0] = (__force u32)saddr; - hash[1] = (__force u32)daddr; - hash[2] = ((__force u16)sport << 16) + (__force u16)dport; - hash[3] = net_secret[15]; - - md5_transform(hash, net_secret); - - return seq_scale(hash[0]); -} - -u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport) -{ - u32 hash[MD5_DIGEST_WORDS]; - - net_secret_init(); - hash[0] = (__force u32)saddr; - hash[1] = (__force u32)daddr; - hash[2] = (__force u32)dport ^ net_secret[14]; - hash[3] = net_secret[15]; - - md5_transform(hash, net_secret); - - return hash[0]; -} -EXPORT_SYMBOL_GPL(secure_ipv4_port_ephemeral); -#endif - -#if IS_ENABLED(CONFIG_IP_DCCP) -u64 secure_dccp_sequence_number(__be32 saddr, __be32 daddr, - __be16 sport, __be16 dport) -{ - u32 hash[MD5_DIGEST_WORDS]; - u64 seq; - - net_secret_init(); - hash[0] = (__force u32)saddr; - hash[1] = (__force u32)daddr; - hash[2] = ((__force u16)sport << 16) + (__force u16)dport; - hash[3] = net_secret[15]; - - md5_transform(hash, net_secret); - - seq = hash[0] | (((u64)hash[1]) << 32); - seq += ktime_get_real_ns(); - seq &= (1ull << 48) - 1; - - return seq; -} -EXPORT_SYMBOL(secure_dccp_sequence_number); - -#if IS_ENABLED(CONFIG_IPV6) -u64 secure_dccpv6_sequence_number(__be32 *saddr, __be32 *daddr, - __be16 sport, __be16 dport) -{ - u32 secret[MD5_MESSAGE_BYTES / 4]; - u32 hash[MD5_DIGEST_WORDS]; - u64 seq; - u32 i; - - net_secret_init(); - memcpy(hash, saddr, 16); - for (i = 0; i < 4; i++) - secret[i] = net_secret[i] + (__force u32)daddr[i]; - secret[4] = net_secret[4] + - (((__force u16)sport << 16) + (__force u16)dport); - for (i = 5; i < MD5_MESSAGE_BYTES / 4; i++) - secret[i] = net_secret[i]; - - md5_transform(hash, secret); - - seq = hash[0] | (((u64)hash[1]) << 32); - seq += ktime_get_real_ns(); - seq &= (1ull << 48) - 1; - - return seq; -} -EXPORT_SYMBOL(secure_dccpv6_sequence_number); -#endif -#endif diff --git a/src/linux/net/core/skbuff.c b/src/linux/net/core/skbuff.c deleted file mode 100644 index 1e3e008..0000000 --- a/src/linux/net/core/skbuff.c +++ /dev/null @@ -1,4915 +0,0 @@ -/* - * Routines having to do with the 'struct sk_buff' memory handlers. - * - * Authors: Alan Cox - * Florian La Roche - * - * Fixes: - * Alan Cox : Fixed the worst of the load - * balancer bugs. - * Dave Platt : Interrupt stacking fix. - * Richard Kooijman : Timestamp fixes. - * Alan Cox : Changed buffer format. - * Alan Cox : destructor hook for AF_UNIX etc. - * Linus Torvalds : Better skb_clone. - * Alan Cox : Added skb_copy. - * Alan Cox : Added all the changed routines Linus - * only put in the headers - * Ray VanTassle : Fixed --skb->lock in free - * Alan Cox : skb_copy copy arp field - * Andi Kleen : slabified it. - * Robert Olsson : Removed skb_head_pool - * - * NOTE: - * The __skb_ routines should be called with interrupts - * disabled, or you better be *real* sure that the operation is atomic - * with respect to whatever list is being frobbed (e.g. via lock_sock() - * or via disabling bottom half handlers, etc). - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -/* - * The functions in this file will not compile correctly with gcc 2.4.x - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_NET_CLS_ACT -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -struct kmem_cache *skbuff_head_cache __read_mostly; -static struct kmem_cache *skbuff_fclone_cache __read_mostly; -int sysctl_max_skb_frags __read_mostly = MAX_SKB_FRAGS; -EXPORT_SYMBOL(sysctl_max_skb_frags); - -/** - * skb_panic - private function for out-of-line support - * @skb: buffer - * @sz: size - * @addr: address - * @msg: skb_over_panic or skb_under_panic - * - * Out-of-line support for skb_put() and skb_push(). - * Called via the wrapper skb_over_panic() or skb_under_panic(). - * Keep out of line to prevent kernel bloat. - * __builtin_return_address is not used because it is not always reliable. - */ -static void skb_panic(struct sk_buff *skb, unsigned int sz, void *addr, - const char msg[]) -{ - pr_emerg("%s: text:%p len:%d put:%d head:%p data:%p tail:%#lx end:%#lx dev:%s\n", - msg, addr, skb->len, sz, skb->head, skb->data, - (unsigned long)skb->tail, (unsigned long)skb->end, - skb->dev ? skb->dev->name : ""); - BUG(); -} - -static void skb_over_panic(struct sk_buff *skb, unsigned int sz, void *addr) -{ - skb_panic(skb, sz, addr, __func__); -} - -static void skb_under_panic(struct sk_buff *skb, unsigned int sz, void *addr) -{ - skb_panic(skb, sz, addr, __func__); -} - -/* - * kmalloc_reserve is a wrapper around kmalloc_node_track_caller that tells - * the caller if emergency pfmemalloc reserves are being used. If it is and - * the socket is later found to be SOCK_MEMALLOC then PFMEMALLOC reserves - * may be used. Otherwise, the packet data may be discarded until enough - * memory is free - */ -#define kmalloc_reserve(size, gfp, node, pfmemalloc) \ - __kmalloc_reserve(size, gfp, node, _RET_IP_, pfmemalloc) - -static void *__kmalloc_reserve(size_t size, gfp_t flags, int node, - unsigned long ip, bool *pfmemalloc) -{ - void *obj; - bool ret_pfmemalloc = false; - - /* - * Try a regular allocation, when that fails and we're not entitled - * to the reserves, fail. - */ - obj = kmalloc_node_track_caller(size, - flags | __GFP_NOMEMALLOC | __GFP_NOWARN, - node); - if (obj || !(gfp_pfmemalloc_allowed(flags))) - goto out; - - /* Try again but now we are using pfmemalloc reserves */ - ret_pfmemalloc = true; - obj = kmalloc_node_track_caller(size, flags, node); - -out: - if (pfmemalloc) - *pfmemalloc = ret_pfmemalloc; - - return obj; -} - -/* Allocate a new skbuff. We do this ourselves so we can fill in a few - * 'private' fields and also do memory statistics to find all the - * [BEEP] leaks. - * - */ - -struct sk_buff *__alloc_skb_head(gfp_t gfp_mask, int node) -{ - struct sk_buff *skb; - - /* Get the HEAD */ - skb = kmem_cache_alloc_node(skbuff_head_cache, - gfp_mask & ~__GFP_DMA, node); - if (!skb) - goto out; - - /* - * Only clear those fields we need to clear, not those that we will - * actually initialise below. Hence, don't put any more fields after - * the tail pointer in struct sk_buff! - */ - memset(skb, 0, offsetof(struct sk_buff, tail)); - skb->head = NULL; - skb->truesize = sizeof(struct sk_buff); - atomic_set(&skb->users, 1); - - skb->mac_header = (typeof(skb->mac_header))~0U; -out: - return skb; -} - -/** - * __alloc_skb - allocate a network buffer - * @size: size to allocate - * @gfp_mask: allocation mask - * @flags: If SKB_ALLOC_FCLONE is set, allocate from fclone cache - * instead of head cache and allocate a cloned (child) skb. - * If SKB_ALLOC_RX is set, __GFP_MEMALLOC will be used for - * allocations in case the data is required for writeback - * @node: numa node to allocate memory on - * - * Allocate a new &sk_buff. The returned buffer has no headroom and a - * tail room of at least size bytes. The object has a reference count - * of one. The return is the buffer. On a failure the return is %NULL. - * - * Buffers may only be allocated from interrupts using a @gfp_mask of - * %GFP_ATOMIC. - */ -struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, - int flags, int node) -{ - struct kmem_cache *cache; - struct skb_shared_info *shinfo; - struct sk_buff *skb; - u8 *data; - bool pfmemalloc; - - cache = (flags & SKB_ALLOC_FCLONE) - ? skbuff_fclone_cache : skbuff_head_cache; - - if (sk_memalloc_socks() && (flags & SKB_ALLOC_RX)) - gfp_mask |= __GFP_MEMALLOC; - - /* Get the HEAD */ - skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node); - if (!skb) - goto out; - prefetchw(skb); - - /* We do our best to align skb_shared_info on a separate cache - * line. It usually works because kmalloc(X > SMP_CACHE_BYTES) gives - * aligned memory blocks, unless SLUB/SLAB debug is enabled. - * Both skb->head and skb_shared_info are cache line aligned. - */ - size = SKB_DATA_ALIGN(size); - size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); - data = kmalloc_reserve(size, gfp_mask, node, &pfmemalloc); - if (!data) - goto nodata; - /* kmalloc(size) might give us more room than requested. - * Put skb_shared_info exactly at the end of allocated zone, - * to allow max possible filling before reallocation. - */ - size = SKB_WITH_OVERHEAD(ksize(data)); - prefetchw(data + size); - - /* - * Only clear those fields we need to clear, not those that we will - * actually initialise below. Hence, don't put any more fields after - * the tail pointer in struct sk_buff! - */ - memset(skb, 0, offsetof(struct sk_buff, tail)); - /* Account for allocated memory : skb + skb->head */ - skb->truesize = SKB_TRUESIZE(size); - skb->pfmemalloc = pfmemalloc; - atomic_set(&skb->users, 1); - skb->head = data; - skb->data = data; - skb_reset_tail_pointer(skb); - skb->end = skb->tail + size; - skb->mac_header = (typeof(skb->mac_header))~0U; - skb->transport_header = (typeof(skb->transport_header))~0U; - - /* make sure we initialize shinfo sequentially */ - shinfo = skb_shinfo(skb); - memset(shinfo, 0, offsetof(struct skb_shared_info, dataref)); - atomic_set(&shinfo->dataref, 1); - kmemcheck_annotate_variable(shinfo->destructor_arg); - - if (flags & SKB_ALLOC_FCLONE) { - struct sk_buff_fclones *fclones; - - fclones = container_of(skb, struct sk_buff_fclones, skb1); - - kmemcheck_annotate_bitfield(&fclones->skb2, flags1); - skb->fclone = SKB_FCLONE_ORIG; - atomic_set(&fclones->fclone_ref, 1); - - fclones->skb2.fclone = SKB_FCLONE_CLONE; - fclones->skb2.pfmemalloc = pfmemalloc; - } -out: - return skb; -nodata: - kmem_cache_free(cache, skb); - skb = NULL; - goto out; -} -EXPORT_SYMBOL(__alloc_skb); - -/** - * __build_skb - build a network buffer - * @data: data buffer provided by caller - * @frag_size: size of data, or 0 if head was kmalloced - * - * Allocate a new &sk_buff. Caller provides space holding head and - * skb_shared_info. @data must have been allocated by kmalloc() only if - * @frag_size is 0, otherwise data should come from the page allocator - * or vmalloc() - * The return is the new skb buffer. - * On a failure the return is %NULL, and @data is not freed. - * Notes : - * Before IO, driver allocates only data buffer where NIC put incoming frame - * Driver should add room at head (NET_SKB_PAD) and - * MUST add room at tail (SKB_DATA_ALIGN(skb_shared_info)) - * After IO, driver calls build_skb(), to allocate sk_buff and populate it - * before giving packet to stack. - * RX rings only contains data buffers, not full skbs. - */ -struct sk_buff *__build_skb(void *data, unsigned int frag_size) -{ - struct skb_shared_info *shinfo; - struct sk_buff *skb; - unsigned int size = frag_size ? : ksize(data); - - skb = kmem_cache_alloc(skbuff_head_cache, GFP_ATOMIC); - if (!skb) - return NULL; - - size -= SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); - - memset(skb, 0, offsetof(struct sk_buff, tail)); - skb->truesize = SKB_TRUESIZE(size); - atomic_set(&skb->users, 1); - skb->head = data; - skb->data = data; - skb_reset_tail_pointer(skb); - skb->end = skb->tail + size; - skb->mac_header = (typeof(skb->mac_header))~0U; - skb->transport_header = (typeof(skb->transport_header))~0U; - - /* make sure we initialize shinfo sequentially */ - shinfo = skb_shinfo(skb); - memset(shinfo, 0, offsetof(struct skb_shared_info, dataref)); - atomic_set(&shinfo->dataref, 1); - kmemcheck_annotate_variable(shinfo->destructor_arg); - - return skb; -} - -/* build_skb() is wrapper over __build_skb(), that specifically - * takes care of skb->head and skb->pfmemalloc - * This means that if @frag_size is not zero, then @data must be backed - * by a page fragment, not kmalloc() or vmalloc() - */ -struct sk_buff *build_skb(void *data, unsigned int frag_size) -{ - struct sk_buff *skb = __build_skb(data, frag_size); - - if (skb && frag_size) { - skb->head_frag = 1; - if (page_is_pfmemalloc(virt_to_head_page(data))) - skb->pfmemalloc = 1; - } - return skb; -} -EXPORT_SYMBOL(build_skb); - -#define NAPI_SKB_CACHE_SIZE 64 - -struct napi_alloc_cache { - struct page_frag_cache page; - size_t skb_count; - void *skb_cache[NAPI_SKB_CACHE_SIZE]; -}; - -static DEFINE_PER_CPU(struct page_frag_cache, netdev_alloc_cache); -static DEFINE_PER_CPU(struct napi_alloc_cache, napi_alloc_cache); - -static void *__netdev_alloc_frag(unsigned int fragsz, gfp_t gfp_mask) -{ - struct page_frag_cache *nc; - unsigned long flags; - void *data; - - local_irq_save(flags); - nc = this_cpu_ptr(&netdev_alloc_cache); - data = __alloc_page_frag(nc, fragsz, gfp_mask); - local_irq_restore(flags); - return data; -} - -/** - * netdev_alloc_frag - allocate a page fragment - * @fragsz: fragment size - * - * Allocates a frag from a page for receive buffer. - * Uses GFP_ATOMIC allocations. - */ -void *netdev_alloc_frag(unsigned int fragsz) -{ - return __netdev_alloc_frag(fragsz, GFP_ATOMIC | __GFP_COLD); -} -EXPORT_SYMBOL(netdev_alloc_frag); - -static void *__napi_alloc_frag(unsigned int fragsz, gfp_t gfp_mask) -{ - struct napi_alloc_cache *nc = this_cpu_ptr(&napi_alloc_cache); - - return __alloc_page_frag(&nc->page, fragsz, gfp_mask); -} - -void *napi_alloc_frag(unsigned int fragsz) -{ - return __napi_alloc_frag(fragsz, GFP_ATOMIC | __GFP_COLD); -} -EXPORT_SYMBOL(napi_alloc_frag); - -/** - * __netdev_alloc_skb - allocate an skbuff for rx on a specific device - * @dev: network device to receive on - * @len: length to allocate - * @gfp_mask: get_free_pages mask, passed to alloc_skb - * - * Allocate a new &sk_buff and assign it a usage count of one. The - * buffer has NET_SKB_PAD headroom built in. Users should allocate - * the headroom they think they need without accounting for the - * built in space. The built in space is used for optimisations. - * - * %NULL is returned if there is no free memory. - */ -struct sk_buff *__netdev_alloc_skb(struct net_device *dev, unsigned int len, - gfp_t gfp_mask) -{ - struct page_frag_cache *nc; - unsigned long flags; - struct sk_buff *skb; - bool pfmemalloc; - void *data; - - len += NET_SKB_PAD; - - if ((len > SKB_WITH_OVERHEAD(PAGE_SIZE)) || - (gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA))) { - skb = __alloc_skb(len, gfp_mask, SKB_ALLOC_RX, NUMA_NO_NODE); - if (!skb) - goto skb_fail; - goto skb_success; - } - - len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); - len = SKB_DATA_ALIGN(len); - - if (sk_memalloc_socks()) - gfp_mask |= __GFP_MEMALLOC; - - local_irq_save(flags); - - nc = this_cpu_ptr(&netdev_alloc_cache); - data = __alloc_page_frag(nc, len, gfp_mask); - pfmemalloc = nc->pfmemalloc; - - local_irq_restore(flags); - - if (unlikely(!data)) - return NULL; - - skb = __build_skb(data, len); - if (unlikely(!skb)) { - skb_free_frag(data); - return NULL; - } - - /* use OR instead of assignment to avoid clearing of bits in mask */ - if (pfmemalloc) - skb->pfmemalloc = 1; - skb->head_frag = 1; - -skb_success: - skb_reserve(skb, NET_SKB_PAD); - skb->dev = dev; - -skb_fail: - return skb; -} -EXPORT_SYMBOL(__netdev_alloc_skb); - -/** - * __napi_alloc_skb - allocate skbuff for rx in a specific NAPI instance - * @napi: napi instance this buffer was allocated for - * @len: length to allocate - * @gfp_mask: get_free_pages mask, passed to alloc_skb and alloc_pages - * - * Allocate a new sk_buff for use in NAPI receive. This buffer will - * attempt to allocate the head from a special reserved region used - * only for NAPI Rx allocation. By doing this we can save several - * CPU cycles by avoiding having to disable and re-enable IRQs. - * - * %NULL is returned if there is no free memory. - */ -struct sk_buff *__napi_alloc_skb(struct napi_struct *napi, unsigned int len, - gfp_t gfp_mask) -{ - struct napi_alloc_cache *nc = this_cpu_ptr(&napi_alloc_cache); - struct sk_buff *skb; - void *data; - - len += NET_SKB_PAD + NET_IP_ALIGN; - - if ((len > SKB_WITH_OVERHEAD(PAGE_SIZE)) || - (gfp_mask & (__GFP_DIRECT_RECLAIM | GFP_DMA))) { - skb = __alloc_skb(len, gfp_mask, SKB_ALLOC_RX, NUMA_NO_NODE); - if (!skb) - goto skb_fail; - goto skb_success; - } - - len += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); - len = SKB_DATA_ALIGN(len); - - if (sk_memalloc_socks()) - gfp_mask |= __GFP_MEMALLOC; - - data = __alloc_page_frag(&nc->page, len, gfp_mask); - if (unlikely(!data)) - return NULL; - - skb = __build_skb(data, len); - if (unlikely(!skb)) { - skb_free_frag(data); - return NULL; - } - - /* use OR instead of assignment to avoid clearing of bits in mask */ - if (nc->page.pfmemalloc) - skb->pfmemalloc = 1; - skb->head_frag = 1; - -skb_success: - skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN); - skb->dev = napi->dev; - -skb_fail: - return skb; -} -EXPORT_SYMBOL(__napi_alloc_skb); - -void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off, - int size, unsigned int truesize) -{ - skb_fill_page_desc(skb, i, page, off, size); - skb->len += size; - skb->data_len += size; - skb->truesize += truesize; -} -EXPORT_SYMBOL(skb_add_rx_frag); - -void skb_coalesce_rx_frag(struct sk_buff *skb, int i, int size, - unsigned int truesize) -{ - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - skb_frag_size_add(frag, size); - skb->len += size; - skb->data_len += size; - skb->truesize += truesize; -} -EXPORT_SYMBOL(skb_coalesce_rx_frag); - -static void skb_drop_list(struct sk_buff **listp) -{ - kfree_skb_list(*listp); - *listp = NULL; -} - -static inline void skb_drop_fraglist(struct sk_buff *skb) -{ - skb_drop_list(&skb_shinfo(skb)->frag_list); -} - -static void skb_clone_fraglist(struct sk_buff *skb) -{ - struct sk_buff *list; - - skb_walk_frags(skb, list) - skb_get(list); -} - -static void skb_free_head(struct sk_buff *skb) -{ - unsigned char *head = skb->head; - - if (skb->head_frag) - skb_free_frag(head); - else - kfree(head); -} - -static void skb_release_data(struct sk_buff *skb) -{ - struct skb_shared_info *shinfo = skb_shinfo(skb); - int i; - - if (skb->cloned && - atomic_sub_return(skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1, - &shinfo->dataref)) - return; - - for (i = 0; i < shinfo->nr_frags; i++) - __skb_frag_unref(&shinfo->frags[i]); - - /* - * If skb buf is from userspace, we need to notify the caller - * the lower device DMA has done; - */ - if (shinfo->tx_flags & SKBTX_DEV_ZEROCOPY) { - struct ubuf_info *uarg; - - uarg = shinfo->destructor_arg; - if (uarg->callback) - uarg->callback(uarg, true); - } - - if (shinfo->frag_list) - kfree_skb_list(shinfo->frag_list); - - skb_free_head(skb); -} - -/* - * Free an skbuff by memory without cleaning the state. - */ -static void kfree_skbmem(struct sk_buff *skb) -{ - struct sk_buff_fclones *fclones; - - switch (skb->fclone) { - case SKB_FCLONE_UNAVAILABLE: - kmem_cache_free(skbuff_head_cache, skb); - return; - - case SKB_FCLONE_ORIG: - fclones = container_of(skb, struct sk_buff_fclones, skb1); - - /* We usually free the clone (TX completion) before original skb - * This test would have no chance to be true for the clone, - * while here, branch prediction will be good. - */ - if (atomic_read(&fclones->fclone_ref) == 1) - goto fastpath; - break; - - default: /* SKB_FCLONE_CLONE */ - fclones = container_of(skb, struct sk_buff_fclones, skb2); - break; - } - if (!atomic_dec_and_test(&fclones->fclone_ref)) - return; -fastpath: - kmem_cache_free(skbuff_fclone_cache, fclones); -} - -static void skb_release_head_state(struct sk_buff *skb) -{ - skb_dst_drop(skb); -#ifdef CONFIG_XFRM - secpath_put(skb->sp); -#endif - if (skb->destructor) { - WARN_ON(in_irq()); - skb->destructor(skb); - } -#if IS_ENABLED(CONFIG_NF_CONNTRACK) - nf_conntrack_put(skb->nfct); -#endif -#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) - nf_bridge_put(skb->nf_bridge); -#endif -} - -/* Free everything but the sk_buff shell. */ -static void skb_release_all(struct sk_buff *skb) -{ - skb_release_head_state(skb); - if (likely(skb->head)) - skb_release_data(skb); -} - -/** - * __kfree_skb - private function - * @skb: buffer - * - * Free an sk_buff. Release anything attached to the buffer. - * Clean the state. This is an internal helper function. Users should - * always call kfree_skb - */ - -void __kfree_skb(struct sk_buff *skb) -{ - skb_release_all(skb); - kfree_skbmem(skb); -} -EXPORT_SYMBOL(__kfree_skb); - -/** - * kfree_skb - free an sk_buff - * @skb: buffer to free - * - * Drop a reference to the buffer and free it if the usage count has - * hit zero. - */ -void kfree_skb(struct sk_buff *skb) -{ - if (unlikely(!skb)) - return; - if (likely(atomic_read(&skb->users) == 1)) - smp_rmb(); - else if (likely(!atomic_dec_and_test(&skb->users))) - return; - trace_kfree_skb(skb, __builtin_return_address(0)); - __kfree_skb(skb); -} -EXPORT_SYMBOL(kfree_skb); - -void kfree_skb_list(struct sk_buff *segs) -{ - while (segs) { - struct sk_buff *next = segs->next; - - kfree_skb(segs); - segs = next; - } -} -EXPORT_SYMBOL(kfree_skb_list); - -/** - * skb_tx_error - report an sk_buff xmit error - * @skb: buffer that triggered an error - * - * Report xmit error if a device callback is tracking this skb. - * skb must be freed afterwards. - */ -void skb_tx_error(struct sk_buff *skb) -{ - if (skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) { - struct ubuf_info *uarg; - - uarg = skb_shinfo(skb)->destructor_arg; - if (uarg->callback) - uarg->callback(uarg, false); - skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY; - } -} -EXPORT_SYMBOL(skb_tx_error); - -/** - * consume_skb - free an skbuff - * @skb: buffer to free - * - * Drop a ref to the buffer and free it if the usage count has hit zero - * Functions identically to kfree_skb, but kfree_skb assumes that the frame - * is being dropped after a failure and notes that - */ -void consume_skb(struct sk_buff *skb) -{ - if (unlikely(!skb)) - return; - if (likely(atomic_read(&skb->users) == 1)) - smp_rmb(); - else if (likely(!atomic_dec_and_test(&skb->users))) - return; - trace_consume_skb(skb); - __kfree_skb(skb); -} -EXPORT_SYMBOL(consume_skb); - -void __kfree_skb_flush(void) -{ - struct napi_alloc_cache *nc = this_cpu_ptr(&napi_alloc_cache); - - /* flush skb_cache if containing objects */ - if (nc->skb_count) { - kmem_cache_free_bulk(skbuff_head_cache, nc->skb_count, - nc->skb_cache); - nc->skb_count = 0; - } -} - -static inline void _kfree_skb_defer(struct sk_buff *skb) -{ - struct napi_alloc_cache *nc = this_cpu_ptr(&napi_alloc_cache); - - /* drop skb->head and call any destructors for packet */ - skb_release_all(skb); - - /* record skb to CPU local list */ - nc->skb_cache[nc->skb_count++] = skb; - -#ifdef CONFIG_SLUB - /* SLUB writes into objects when freeing */ - prefetchw(skb); -#endif - - /* flush skb_cache if it is filled */ - if (unlikely(nc->skb_count == NAPI_SKB_CACHE_SIZE)) { - kmem_cache_free_bulk(skbuff_head_cache, NAPI_SKB_CACHE_SIZE, - nc->skb_cache); - nc->skb_count = 0; - } -} -void __kfree_skb_defer(struct sk_buff *skb) -{ - _kfree_skb_defer(skb); -} - -void napi_consume_skb(struct sk_buff *skb, int budget) -{ - if (unlikely(!skb)) - return; - - /* Zero budget indicate non-NAPI context called us, like netpoll */ - if (unlikely(!budget)) { - dev_consume_skb_any(skb); - return; - } - - if (likely(atomic_read(&skb->users) == 1)) - smp_rmb(); - else if (likely(!atomic_dec_and_test(&skb->users))) - return; - /* if reaching here SKB is ready to free */ - trace_consume_skb(skb); - - /* if SKB is a clone, don't handle this case */ - if (skb->fclone != SKB_FCLONE_UNAVAILABLE) { - __kfree_skb(skb); - return; - } - - _kfree_skb_defer(skb); -} -EXPORT_SYMBOL(napi_consume_skb); - -/* Make sure a field is enclosed inside headers_start/headers_end section */ -#define CHECK_SKB_FIELD(field) \ - BUILD_BUG_ON(offsetof(struct sk_buff, field) < \ - offsetof(struct sk_buff, headers_start)); \ - BUILD_BUG_ON(offsetof(struct sk_buff, field) > \ - offsetof(struct sk_buff, headers_end)); \ - -static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) -{ - new->tstamp = old->tstamp; - /* We do not copy old->sk */ - new->dev = old->dev; - memcpy(new->cb, old->cb, sizeof(old->cb)); - skb_dst_copy(new, old); -#ifdef CONFIG_XFRM - new->sp = secpath_get(old->sp); -#endif - __nf_copy(new, old, false); - - /* Note : this field could be in headers_start/headers_end section - * It is not yet because we do not want to have a 16 bit hole - */ - new->queue_mapping = old->queue_mapping; - - memcpy(&new->headers_start, &old->headers_start, - offsetof(struct sk_buff, headers_end) - - offsetof(struct sk_buff, headers_start)); - CHECK_SKB_FIELD(protocol); - CHECK_SKB_FIELD(csum); - CHECK_SKB_FIELD(hash); - CHECK_SKB_FIELD(priority); - CHECK_SKB_FIELD(skb_iif); - CHECK_SKB_FIELD(vlan_proto); - CHECK_SKB_FIELD(vlan_tci); - CHECK_SKB_FIELD(transport_header); - CHECK_SKB_FIELD(network_header); - CHECK_SKB_FIELD(mac_header); - CHECK_SKB_FIELD(inner_protocol); - CHECK_SKB_FIELD(inner_transport_header); - CHECK_SKB_FIELD(inner_network_header); - CHECK_SKB_FIELD(inner_mac_header); - CHECK_SKB_FIELD(mark); -#ifdef CONFIG_NETWORK_SECMARK - CHECK_SKB_FIELD(secmark); -#endif -#ifdef CONFIG_NET_RX_BUSY_POLL - CHECK_SKB_FIELD(napi_id); -#endif -#ifdef CONFIG_XPS - CHECK_SKB_FIELD(sender_cpu); -#endif -#ifdef CONFIG_NET_SCHED - CHECK_SKB_FIELD(tc_index); -#ifdef CONFIG_NET_CLS_ACT - CHECK_SKB_FIELD(tc_verd); -#endif -#endif - -} - -/* - * You should not add any new code to this function. Add it to - * __copy_skb_header above instead. - */ -static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb) -{ -#define C(x) n->x = skb->x - - n->next = n->prev = NULL; - n->sk = NULL; - __copy_skb_header(n, skb); - - C(len); - C(data_len); - C(mac_len); - n->hdr_len = skb->nohdr ? skb_headroom(skb) : skb->hdr_len; - n->cloned = 1; - n->nohdr = 0; - n->destructor = NULL; - C(tail); - C(end); - C(head); - C(head_frag); - C(data); - C(truesize); - atomic_set(&n->users, 1); - - atomic_inc(&(skb_shinfo(skb)->dataref)); - skb->cloned = 1; - - return n; -#undef C -} - -/** - * skb_morph - morph one skb into another - * @dst: the skb to receive the contents - * @src: the skb to supply the contents - * - * This is identical to skb_clone except that the target skb is - * supplied by the user. - * - * The target skb is returned upon exit. - */ -struct sk_buff *skb_morph(struct sk_buff *dst, struct sk_buff *src) -{ - skb_release_all(dst); - return __skb_clone(dst, src); -} -EXPORT_SYMBOL_GPL(skb_morph); - -/** - * skb_copy_ubufs - copy userspace skb frags buffers to kernel - * @skb: the skb to modify - * @gfp_mask: allocation priority - * - * This must be called on SKBTX_DEV_ZEROCOPY skb. - * It will copy all frags into kernel and drop the reference - * to userspace pages. - * - * If this function is called from an interrupt gfp_mask() must be - * %GFP_ATOMIC. - * - * Returns 0 on success or a negative error code on failure - * to allocate kernel memory to copy to. - */ -int skb_copy_ubufs(struct sk_buff *skb, gfp_t gfp_mask) -{ - int i; - int num_frags = skb_shinfo(skb)->nr_frags; - struct page *page, *head = NULL; - struct ubuf_info *uarg = skb_shinfo(skb)->destructor_arg; - - for (i = 0; i < num_frags; i++) { - u8 *vaddr; - skb_frag_t *f = &skb_shinfo(skb)->frags[i]; - - page = alloc_page(gfp_mask); - if (!page) { - while (head) { - struct page *next = (struct page *)page_private(head); - put_page(head); - head = next; - } - return -ENOMEM; - } - vaddr = kmap_atomic(skb_frag_page(f)); - memcpy(page_address(page), - vaddr + f->page_offset, skb_frag_size(f)); - kunmap_atomic(vaddr); - set_page_private(page, (unsigned long)head); - head = page; - } - - /* skb frags release userspace buffers */ - for (i = 0; i < num_frags; i++) - skb_frag_unref(skb, i); - - uarg->callback(uarg, false); - - /* skb frags point to kernel buffers */ - for (i = num_frags - 1; i >= 0; i--) { - __skb_fill_page_desc(skb, i, head, 0, - skb_shinfo(skb)->frags[i].size); - head = (struct page *)page_private(head); - } - - skb_shinfo(skb)->tx_flags &= ~SKBTX_DEV_ZEROCOPY; - return 0; -} -EXPORT_SYMBOL_GPL(skb_copy_ubufs); - -/** - * skb_clone - duplicate an sk_buff - * @skb: buffer to clone - * @gfp_mask: allocation priority - * - * Duplicate an &sk_buff. The new one is not owned by a socket. Both - * copies share the same packet data but not structure. The new - * buffer has a reference count of 1. If the allocation fails the - * function returns %NULL otherwise the new buffer is returned. - * - * If this function is called from an interrupt gfp_mask() must be - * %GFP_ATOMIC. - */ - -struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask) -{ - struct sk_buff_fclones *fclones = container_of(skb, - struct sk_buff_fclones, - skb1); - struct sk_buff *n; - - if (skb_orphan_frags(skb, gfp_mask)) - return NULL; - - if (skb->fclone == SKB_FCLONE_ORIG && - atomic_read(&fclones->fclone_ref) == 1) { - n = &fclones->skb2; - atomic_set(&fclones->fclone_ref, 2); - } else { - if (skb_pfmemalloc(skb)) - gfp_mask |= __GFP_MEMALLOC; - - n = kmem_cache_alloc(skbuff_head_cache, gfp_mask); - if (!n) - return NULL; - - kmemcheck_annotate_bitfield(n, flags1); - n->fclone = SKB_FCLONE_UNAVAILABLE; - } - - return __skb_clone(n, skb); -} -EXPORT_SYMBOL(skb_clone); - -static void skb_headers_offset_update(struct sk_buff *skb, int off) -{ - /* Only adjust this if it actually is csum_start rather than csum */ - if (skb->ip_summed == CHECKSUM_PARTIAL) - skb->csum_start += off; - /* {transport,network,mac}_header and tail are relative to skb->head */ - skb->transport_header += off; - skb->network_header += off; - if (skb_mac_header_was_set(skb)) - skb->mac_header += off; - skb->inner_transport_header += off; - skb->inner_network_header += off; - skb->inner_mac_header += off; -} - -static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old) -{ - __copy_skb_header(new, old); - - skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size; - skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs; - skb_shinfo(new)->gso_type = skb_shinfo(old)->gso_type; -} - -static inline int skb_alloc_rx_flag(const struct sk_buff *skb) -{ - if (skb_pfmemalloc(skb)) - return SKB_ALLOC_RX; - return 0; -} - -/** - * skb_copy - create private copy of an sk_buff - * @skb: buffer to copy - * @gfp_mask: allocation priority - * - * Make a copy of both an &sk_buff and its data. This is used when the - * caller wishes to modify the data and needs a private copy of the - * data to alter. Returns %NULL on failure or the pointer to the buffer - * on success. The returned buffer has a reference count of 1. - * - * As by-product this function converts non-linear &sk_buff to linear - * one, so that &sk_buff becomes completely private and caller is allowed - * to modify all the data of returned buffer. This means that this - * function is not recommended for use in circumstances when only - * header is going to be modified. Use pskb_copy() instead. - */ - -struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask) -{ - int headerlen = skb_headroom(skb); - unsigned int size = skb_end_offset(skb) + skb->data_len; - struct sk_buff *n = __alloc_skb(size, gfp_mask, - skb_alloc_rx_flag(skb), NUMA_NO_NODE); - - if (!n) - return NULL; - - /* Set the data pointer */ - skb_reserve(n, headerlen); - /* Set the tail pointer and length */ - skb_put(n, skb->len); - - if (skb_copy_bits(skb, -headerlen, n->head, headerlen + skb->len)) - BUG(); - - copy_skb_header(n, skb); - return n; -} -EXPORT_SYMBOL(skb_copy); - -/** - * __pskb_copy_fclone - create copy of an sk_buff with private head. - * @skb: buffer to copy - * @headroom: headroom of new skb - * @gfp_mask: allocation priority - * @fclone: if true allocate the copy of the skb from the fclone - * cache instead of the head cache; it is recommended to set this - * to true for the cases where the copy will likely be cloned - * - * Make a copy of both an &sk_buff and part of its data, located - * in header. Fragmented data remain shared. This is used when - * the caller wishes to modify only header of &sk_buff and needs - * private copy of the header to alter. Returns %NULL on failure - * or the pointer to the buffer on success. - * The returned buffer has a reference count of 1. - */ - -struct sk_buff *__pskb_copy_fclone(struct sk_buff *skb, int headroom, - gfp_t gfp_mask, bool fclone) -{ - unsigned int size = skb_headlen(skb) + headroom; - int flags = skb_alloc_rx_flag(skb) | (fclone ? SKB_ALLOC_FCLONE : 0); - struct sk_buff *n = __alloc_skb(size, gfp_mask, flags, NUMA_NO_NODE); - - if (!n) - goto out; - - /* Set the data pointer */ - skb_reserve(n, headroom); - /* Set the tail pointer and length */ - skb_put(n, skb_headlen(skb)); - /* Copy the bytes */ - skb_copy_from_linear_data(skb, n->data, n->len); - - n->truesize += skb->data_len; - n->data_len = skb->data_len; - n->len = skb->len; - - if (skb_shinfo(skb)->nr_frags) { - int i; - - if (skb_orphan_frags(skb, gfp_mask)) { - kfree_skb(n); - n = NULL; - goto out; - } - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - skb_shinfo(n)->frags[i] = skb_shinfo(skb)->frags[i]; - skb_frag_ref(skb, i); - } - skb_shinfo(n)->nr_frags = i; - } - - if (skb_has_frag_list(skb)) { - skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list; - skb_clone_fraglist(n); - } - - copy_skb_header(n, skb); -out: - return n; -} -EXPORT_SYMBOL(__pskb_copy_fclone); - -/** - * pskb_expand_head - reallocate header of &sk_buff - * @skb: buffer to reallocate - * @nhead: room to add at head - * @ntail: room to add at tail - * @gfp_mask: allocation priority - * - * Expands (or creates identical copy, if @nhead and @ntail are zero) - * header of @skb. &sk_buff itself is not changed. &sk_buff MUST have - * reference count of 1. Returns zero in the case of success or error, - * if expansion failed. In the last case, &sk_buff is not changed. - * - * All the pointers pointing into skb header may change and must be - * reloaded after call to this function. - */ - -int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, - gfp_t gfp_mask) -{ - int i; - u8 *data; - int size = nhead + skb_end_offset(skb) + ntail; - long off; - - BUG_ON(nhead < 0); - - if (skb_shared(skb)) - BUG(); - - size = SKB_DATA_ALIGN(size); - - if (skb_pfmemalloc(skb)) - gfp_mask |= __GFP_MEMALLOC; - data = kmalloc_reserve(size + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)), - gfp_mask, NUMA_NO_NODE, NULL); - if (!data) - goto nodata; - size = SKB_WITH_OVERHEAD(ksize(data)); - - /* Copy only real data... and, alas, header. This should be - * optimized for the cases when header is void. - */ - memcpy(data + nhead, skb->head, skb_tail_pointer(skb) - skb->head); - - memcpy((struct skb_shared_info *)(data + size), - skb_shinfo(skb), - offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags])); - - /* - * if shinfo is shared we must drop the old head gracefully, but if it - * is not we can just drop the old head and let the existing refcount - * be since all we did is relocate the values - */ - if (skb_cloned(skb)) { - /* copy this zero copy skb frags */ - if (skb_orphan_frags(skb, gfp_mask)) - goto nofrags; - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) - skb_frag_ref(skb, i); - - if (skb_has_frag_list(skb)) - skb_clone_fraglist(skb); - - skb_release_data(skb); - } else { - skb_free_head(skb); - } - off = (data + nhead) - skb->head; - - skb->head = data; - skb->head_frag = 0; - skb->data += off; -#ifdef NET_SKBUFF_DATA_USES_OFFSET - skb->end = size; - off = nhead; -#else - skb->end = skb->head + size; -#endif - skb->tail += off; - skb_headers_offset_update(skb, nhead); - skb->cloned = 0; - skb->hdr_len = 0; - skb->nohdr = 0; - atomic_set(&skb_shinfo(skb)->dataref, 1); - return 0; - -nofrags: - kfree(data); -nodata: - return -ENOMEM; -} -EXPORT_SYMBOL(pskb_expand_head); - -/* Make private copy of skb with writable head and some headroom */ - -struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom) -{ - struct sk_buff *skb2; - int delta = headroom - skb_headroom(skb); - - if (delta <= 0) - skb2 = pskb_copy(skb, GFP_ATOMIC); - else { - skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2 && pskb_expand_head(skb2, SKB_DATA_ALIGN(delta), 0, - GFP_ATOMIC)) { - kfree_skb(skb2); - skb2 = NULL; - } - } - return skb2; -} -EXPORT_SYMBOL(skb_realloc_headroom); - -/** - * skb_copy_expand - copy and expand sk_buff - * @skb: buffer to copy - * @newheadroom: new free bytes at head - * @newtailroom: new free bytes at tail - * @gfp_mask: allocation priority - * - * Make a copy of both an &sk_buff and its data and while doing so - * allocate additional space. - * - * This is used when the caller wishes to modify the data and needs a - * private copy of the data to alter as well as more space for new fields. - * Returns %NULL on failure or the pointer to the buffer - * on success. The returned buffer has a reference count of 1. - * - * You must pass %GFP_ATOMIC as the allocation priority if this function - * is called from an interrupt. - */ -struct sk_buff *skb_copy_expand(const struct sk_buff *skb, - int newheadroom, int newtailroom, - gfp_t gfp_mask) -{ - /* - * Allocate the copy buffer - */ - struct sk_buff *n = __alloc_skb(newheadroom + skb->len + newtailroom, - gfp_mask, skb_alloc_rx_flag(skb), - NUMA_NO_NODE); - int oldheadroom = skb_headroom(skb); - int head_copy_len, head_copy_off; - - if (!n) - return NULL; - - skb_reserve(n, newheadroom); - - /* Set the tail pointer and length */ - skb_put(n, skb->len); - - head_copy_len = oldheadroom; - head_copy_off = 0; - if (newheadroom <= head_copy_len) - head_copy_len = newheadroom; - else - head_copy_off = newheadroom - head_copy_len; - - /* Copy the linear header and data. */ - if (skb_copy_bits(skb, -head_copy_len, n->head + head_copy_off, - skb->len + head_copy_len)) - BUG(); - - copy_skb_header(n, skb); - - skb_headers_offset_update(n, newheadroom - oldheadroom); - - return n; -} -EXPORT_SYMBOL(skb_copy_expand); - -/** - * skb_pad - zero pad the tail of an skb - * @skb: buffer to pad - * @pad: space to pad - * - * Ensure that a buffer is followed by a padding area that is zero - * filled. Used by network drivers which may DMA or transfer data - * beyond the buffer end onto the wire. - * - * May return error in out of memory cases. The skb is freed on error. - */ - -int skb_pad(struct sk_buff *skb, int pad) -{ - int err; - int ntail; - - /* If the skbuff is non linear tailroom is always zero.. */ - if (!skb_cloned(skb) && skb_tailroom(skb) >= pad) { - memset(skb->data+skb->len, 0, pad); - return 0; - } - - ntail = skb->data_len + pad - (skb->end - skb->tail); - if (likely(skb_cloned(skb) || ntail > 0)) { - err = pskb_expand_head(skb, 0, ntail, GFP_ATOMIC); - if (unlikely(err)) - goto free_skb; - } - - /* FIXME: The use of this function with non-linear skb's really needs - * to be audited. - */ - err = skb_linearize(skb); - if (unlikely(err)) - goto free_skb; - - memset(skb->data + skb->len, 0, pad); - return 0; - -free_skb: - kfree_skb(skb); - return err; -} -EXPORT_SYMBOL(skb_pad); - -/** - * pskb_put - add data to the tail of a potentially fragmented buffer - * @skb: start of the buffer to use - * @tail: tail fragment of the buffer to use - * @len: amount of data to add - * - * This function extends the used data area of the potentially - * fragmented buffer. @tail must be the last fragment of @skb -- or - * @skb itself. If this would exceed the total buffer size the kernel - * will panic. A pointer to the first byte of the extra data is - * returned. - */ - -unsigned char *pskb_put(struct sk_buff *skb, struct sk_buff *tail, int len) -{ - if (tail != skb) { - skb->data_len += len; - skb->len += len; - } - return skb_put(tail, len); -} -EXPORT_SYMBOL_GPL(pskb_put); - -/** - * skb_put - add data to a buffer - * @skb: buffer to use - * @len: amount of data to add - * - * This function extends the used data area of the buffer. If this would - * exceed the total buffer size the kernel will panic. A pointer to the - * first byte of the extra data is returned. - */ -unsigned char *skb_put(struct sk_buff *skb, unsigned int len) -{ - unsigned char *tmp = skb_tail_pointer(skb); - SKB_LINEAR_ASSERT(skb); - skb->tail += len; - skb->len += len; - if (unlikely(skb->tail > skb->end)) - skb_over_panic(skb, len, __builtin_return_address(0)); - return tmp; -} -EXPORT_SYMBOL(skb_put); - -/** - * skb_push - add data to the start of a buffer - * @skb: buffer to use - * @len: amount of data to add - * - * This function extends the used data area of the buffer at the buffer - * start. If this would exceed the total buffer headroom the kernel will - * panic. A pointer to the first byte of the extra data is returned. - */ -unsigned char *skb_push(struct sk_buff *skb, unsigned int len) -{ - skb->data -= len; - skb->len += len; - if (unlikely(skb->datahead)) - skb_under_panic(skb, len, __builtin_return_address(0)); - return skb->data; -} -EXPORT_SYMBOL(skb_push); - -/** - * skb_pull - remove data from the start of a buffer - * @skb: buffer to use - * @len: amount of data to remove - * - * This function removes data from the start of a buffer, returning - * the memory to the headroom. A pointer to the next data in the buffer - * is returned. Once the data has been pulled future pushes will overwrite - * the old data. - */ -unsigned char *skb_pull(struct sk_buff *skb, unsigned int len) -{ - return skb_pull_inline(skb, len); -} -EXPORT_SYMBOL(skb_pull); - -/** - * skb_trim - remove end from a buffer - * @skb: buffer to alter - * @len: new length - * - * Cut the length of a buffer down by removing data from the tail. If - * the buffer is already under the length specified it is not modified. - * The skb must be linear. - */ -void skb_trim(struct sk_buff *skb, unsigned int len) -{ - if (skb->len > len) - __skb_trim(skb, len); -} -EXPORT_SYMBOL(skb_trim); - -/* Trims skb to length len. It can change skb pointers. - */ - -int ___pskb_trim(struct sk_buff *skb, unsigned int len) -{ - struct sk_buff **fragp; - struct sk_buff *frag; - int offset = skb_headlen(skb); - int nfrags = skb_shinfo(skb)->nr_frags; - int i; - int err; - - if (skb_cloned(skb) && - unlikely((err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))) - return err; - - i = 0; - if (offset >= len) - goto drop_pages; - - for (; i < nfrags; i++) { - int end = offset + skb_frag_size(&skb_shinfo(skb)->frags[i]); - - if (end < len) { - offset = end; - continue; - } - - skb_frag_size_set(&skb_shinfo(skb)->frags[i++], len - offset); - -drop_pages: - skb_shinfo(skb)->nr_frags = i; - - for (; i < nfrags; i++) - skb_frag_unref(skb, i); - - if (skb_has_frag_list(skb)) - skb_drop_fraglist(skb); - goto done; - } - - for (fragp = &skb_shinfo(skb)->frag_list; (frag = *fragp); - fragp = &frag->next) { - int end = offset + frag->len; - - if (skb_shared(frag)) { - struct sk_buff *nfrag; - - nfrag = skb_clone(frag, GFP_ATOMIC); - if (unlikely(!nfrag)) - return -ENOMEM; - - nfrag->next = frag->next; - consume_skb(frag); - frag = nfrag; - *fragp = frag; - } - - if (end < len) { - offset = end; - continue; - } - - if (end > len && - unlikely((err = pskb_trim(frag, len - offset)))) - return err; - - if (frag->next) - skb_drop_list(&frag->next); - break; - } - -done: - if (len > skb_headlen(skb)) { - skb->data_len -= skb->len - len; - skb->len = len; - } else { - skb->len = len; - skb->data_len = 0; - skb_set_tail_pointer(skb, len); - } - - return 0; -} -EXPORT_SYMBOL(___pskb_trim); - -/** - * __pskb_pull_tail - advance tail of skb header - * @skb: buffer to reallocate - * @delta: number of bytes to advance tail - * - * The function makes a sense only on a fragmented &sk_buff, - * it expands header moving its tail forward and copying necessary - * data from fragmented part. - * - * &sk_buff MUST have reference count of 1. - * - * Returns %NULL (and &sk_buff does not change) if pull failed - * or value of new tail of skb in the case of success. - * - * All the pointers pointing into skb header may change and must be - * reloaded after call to this function. - */ - -/* Moves tail of skb head forward, copying data from fragmented part, - * when it is necessary. - * 1. It may fail due to malloc failure. - * 2. It may change skb pointers. - * - * It is pretty complicated. Luckily, it is called only in exceptional cases. - */ -unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta) -{ - /* If skb has not enough free space at tail, get new one - * plus 128 bytes for future expansions. If we have enough - * room at tail, reallocate without expansion only if skb is cloned. - */ - int i, k, eat = (skb->tail + delta) - skb->end; - - if (eat > 0 || skb_cloned(skb)) { - if (pskb_expand_head(skb, 0, eat > 0 ? eat + 128 : 0, - GFP_ATOMIC)) - return NULL; - } - - if (skb_copy_bits(skb, skb_headlen(skb), skb_tail_pointer(skb), delta)) - BUG(); - - /* Optimization: no fragments, no reasons to preestimate - * size of pulled pages. Superb. - */ - if (!skb_has_frag_list(skb)) - goto pull_pages; - - /* Estimate size of pulled pages. */ - eat = delta; - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - int size = skb_frag_size(&skb_shinfo(skb)->frags[i]); - - if (size >= eat) - goto pull_pages; - eat -= size; - } - - /* If we need update frag list, we are in troubles. - * Certainly, it possible to add an offset to skb data, - * but taking into account that pulling is expected to - * be very rare operation, it is worth to fight against - * further bloating skb head and crucify ourselves here instead. - * Pure masohism, indeed. 8)8) - */ - if (eat) { - struct sk_buff *list = skb_shinfo(skb)->frag_list; - struct sk_buff *clone = NULL; - struct sk_buff *insp = NULL; - - do { - BUG_ON(!list); - - if (list->len <= eat) { - /* Eaten as whole. */ - eat -= list->len; - list = list->next; - insp = list; - } else { - /* Eaten partially. */ - - if (skb_shared(list)) { - /* Sucks! We need to fork list. :-( */ - clone = skb_clone(list, GFP_ATOMIC); - if (!clone) - return NULL; - insp = list->next; - list = clone; - } else { - /* This may be pulled without - * problems. */ - insp = list; - } - if (!pskb_pull(list, eat)) { - kfree_skb(clone); - return NULL; - } - break; - } - } while (eat); - - /* Free pulled out fragments. */ - while ((list = skb_shinfo(skb)->frag_list) != insp) { - skb_shinfo(skb)->frag_list = list->next; - kfree_skb(list); - } - /* And insert new clone at head. */ - if (clone) { - clone->next = list; - skb_shinfo(skb)->frag_list = clone; - } - } - /* Success! Now we may commit changes to skb data. */ - -pull_pages: - eat = delta; - k = 0; - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - int size = skb_frag_size(&skb_shinfo(skb)->frags[i]); - - if (size <= eat) { - skb_frag_unref(skb, i); - eat -= size; - } else { - skb_shinfo(skb)->frags[k] = skb_shinfo(skb)->frags[i]; - if (eat) { - skb_shinfo(skb)->frags[k].page_offset += eat; - skb_frag_size_sub(&skb_shinfo(skb)->frags[k], eat); - eat = 0; - } - k++; - } - } - skb_shinfo(skb)->nr_frags = k; - - skb->tail += delta; - skb->data_len -= delta; - - return skb_tail_pointer(skb); -} -EXPORT_SYMBOL(__pskb_pull_tail); - -/** - * skb_copy_bits - copy bits from skb to kernel buffer - * @skb: source skb - * @offset: offset in source - * @to: destination buffer - * @len: number of bytes to copy - * - * Copy the specified number of bytes from the source skb to the - * destination buffer. - * - * CAUTION ! : - * If its prototype is ever changed, - * check arch/{*}/net/{*}.S files, - * since it is called from BPF assembly code. - */ -int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len) -{ - int start = skb_headlen(skb); - struct sk_buff *frag_iter; - int i, copy; - - if (offset > (int)skb->len - len) - goto fault; - - /* Copy header. */ - if ((copy = start - offset) > 0) { - if (copy > len) - copy = len; - skb_copy_from_linear_data_offset(skb, offset, to, copy); - if ((len -= copy) == 0) - return 0; - offset += copy; - to += copy; - } - - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - int end; - skb_frag_t *f = &skb_shinfo(skb)->frags[i]; - - WARN_ON(start > offset + len); - - end = start + skb_frag_size(f); - if ((copy = end - offset) > 0) { - u8 *vaddr; - - if (copy > len) - copy = len; - - vaddr = kmap_atomic(skb_frag_page(f)); - memcpy(to, - vaddr + f->page_offset + offset - start, - copy); - kunmap_atomic(vaddr); - - if ((len -= copy) == 0) - return 0; - offset += copy; - to += copy; - } - start = end; - } - - skb_walk_frags(skb, frag_iter) { - int end; - - WARN_ON(start > offset + len); - - end = start + frag_iter->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - if (skb_copy_bits(frag_iter, offset - start, to, copy)) - goto fault; - if ((len -= copy) == 0) - return 0; - offset += copy; - to += copy; - } - start = end; - } - - if (!len) - return 0; - -fault: - return -EFAULT; -} -EXPORT_SYMBOL(skb_copy_bits); - -/* - * Callback from splice_to_pipe(), if we need to release some pages - * at the end of the spd in case we error'ed out in filling the pipe. - */ -static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i) -{ - put_page(spd->pages[i]); -} - -static struct page *linear_to_page(struct page *page, unsigned int *len, - unsigned int *offset, - struct sock *sk) -{ - struct page_frag *pfrag = sk_page_frag(sk); - - if (!sk_page_frag_refill(sk, pfrag)) - return NULL; - - *len = min_t(unsigned int, *len, pfrag->size - pfrag->offset); - - memcpy(page_address(pfrag->page) + pfrag->offset, - page_address(page) + *offset, *len); - *offset = pfrag->offset; - pfrag->offset += *len; - - return pfrag->page; -} - -static bool spd_can_coalesce(const struct splice_pipe_desc *spd, - struct page *page, - unsigned int offset) -{ - return spd->nr_pages && - spd->pages[spd->nr_pages - 1] == page && - (spd->partial[spd->nr_pages - 1].offset + - spd->partial[spd->nr_pages - 1].len == offset); -} - -/* - * Fill page/offset/length into spd, if it can hold more pages. - */ -static bool spd_fill_page(struct splice_pipe_desc *spd, - struct pipe_inode_info *pipe, struct page *page, - unsigned int *len, unsigned int offset, - bool linear, - struct sock *sk) -{ - if (unlikely(spd->nr_pages == MAX_SKB_FRAGS)) - return true; - - if (linear) { - page = linear_to_page(page, len, &offset, sk); - if (!page) - return true; - } - if (spd_can_coalesce(spd, page, offset)) { - spd->partial[spd->nr_pages - 1].len += *len; - return false; - } - get_page(page); - spd->pages[spd->nr_pages] = page; - spd->partial[spd->nr_pages].len = *len; - spd->partial[spd->nr_pages].offset = offset; - spd->nr_pages++; - - return false; -} - -static bool __splice_segment(struct page *page, unsigned int poff, - unsigned int plen, unsigned int *off, - unsigned int *len, - struct splice_pipe_desc *spd, bool linear, - struct sock *sk, - struct pipe_inode_info *pipe) -{ - if (!*len) - return true; - - /* skip this segment if already processed */ - if (*off >= plen) { - *off -= plen; - return false; - } - - /* ignore any bits we already processed */ - poff += *off; - plen -= *off; - *off = 0; - - do { - unsigned int flen = min(*len, plen); - - if (spd_fill_page(spd, pipe, page, &flen, poff, - linear, sk)) - return true; - poff += flen; - plen -= flen; - *len -= flen; - } while (*len && plen); - - return false; -} - -/* - * Map linear and fragment data from the skb to spd. It reports true if the - * pipe is full or if we already spliced the requested length. - */ -static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe, - unsigned int *offset, unsigned int *len, - struct splice_pipe_desc *spd, struct sock *sk) -{ - int seg; - struct sk_buff *iter; - - /* map the linear part : - * If skb->head_frag is set, this 'linear' part is backed by a - * fragment, and if the head is not shared with any clones then - * we can avoid a copy since we own the head portion of this page. - */ - if (__splice_segment(virt_to_page(skb->data), - (unsigned long) skb->data & (PAGE_SIZE - 1), - skb_headlen(skb), - offset, len, spd, - skb_head_is_locked(skb), - sk, pipe)) - return true; - - /* - * then map the fragments - */ - for (seg = 0; seg < skb_shinfo(skb)->nr_frags; seg++) { - const skb_frag_t *f = &skb_shinfo(skb)->frags[seg]; - - if (__splice_segment(skb_frag_page(f), - f->page_offset, skb_frag_size(f), - offset, len, spd, false, sk, pipe)) - return true; - } - - skb_walk_frags(skb, iter) { - if (*offset >= iter->len) { - *offset -= iter->len; - continue; - } - /* __skb_splice_bits() only fails if the output has no room - * left, so no point in going over the frag_list for the error - * case. - */ - if (__skb_splice_bits(iter, pipe, offset, len, spd, sk)) - return true; - } - - return false; -} - -/* - * Map data from the skb to a pipe. Should handle both the linear part, - * the fragments, and the frag list. - */ -int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset, - struct pipe_inode_info *pipe, unsigned int tlen, - unsigned int flags) -{ - struct partial_page partial[MAX_SKB_FRAGS]; - struct page *pages[MAX_SKB_FRAGS]; - struct splice_pipe_desc spd = { - .pages = pages, - .partial = partial, - .nr_pages_max = MAX_SKB_FRAGS, - .flags = flags, - .ops = &nosteal_pipe_buf_ops, - .spd_release = sock_spd_release, - }; - int ret = 0; - - __skb_splice_bits(skb, pipe, &offset, &tlen, &spd, sk); - - if (spd.nr_pages) - ret = splice_to_pipe(pipe, &spd); - - return ret; -} -EXPORT_SYMBOL_GPL(skb_splice_bits); - -/** - * skb_store_bits - store bits from kernel buffer to skb - * @skb: destination buffer - * @offset: offset in destination - * @from: source buffer - * @len: number of bytes to copy - * - * Copy the specified number of bytes from the source buffer to the - * destination skb. This function handles all the messy bits of - * traversing fragment lists and such. - */ - -int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len) -{ - int start = skb_headlen(skb); - struct sk_buff *frag_iter; - int i, copy; - - if (offset > (int)skb->len - len) - goto fault; - - if ((copy = start - offset) > 0) { - if (copy > len) - copy = len; - skb_copy_to_linear_data_offset(skb, offset, from, copy); - if ((len -= copy) == 0) - return 0; - offset += copy; - from += copy; - } - - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - int end; - - WARN_ON(start > offset + len); - - end = start + skb_frag_size(frag); - if ((copy = end - offset) > 0) { - u8 *vaddr; - - if (copy > len) - copy = len; - - vaddr = kmap_atomic(skb_frag_page(frag)); - memcpy(vaddr + frag->page_offset + offset - start, - from, copy); - kunmap_atomic(vaddr); - - if ((len -= copy) == 0) - return 0; - offset += copy; - from += copy; - } - start = end; - } - - skb_walk_frags(skb, frag_iter) { - int end; - - WARN_ON(start > offset + len); - - end = start + frag_iter->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - if (skb_store_bits(frag_iter, offset - start, - from, copy)) - goto fault; - if ((len -= copy) == 0) - return 0; - offset += copy; - from += copy; - } - start = end; - } - if (!len) - return 0; - -fault: - return -EFAULT; -} -EXPORT_SYMBOL(skb_store_bits); - -/* Checksum skb data. */ -__wsum __skb_checksum(const struct sk_buff *skb, int offset, int len, - __wsum csum, const struct skb_checksum_ops *ops) -{ - int start = skb_headlen(skb); - int i, copy = start - offset; - struct sk_buff *frag_iter; - int pos = 0; - - /* Checksum header. */ - if (copy > 0) { - if (copy > len) - copy = len; - csum = ops->update(skb->data + offset, copy, csum); - if ((len -= copy) == 0) - return csum; - offset += copy; - pos = copy; - } - - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - int end; - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - WARN_ON(start > offset + len); - - end = start + skb_frag_size(frag); - if ((copy = end - offset) > 0) { - __wsum csum2; - u8 *vaddr; - - if (copy > len) - copy = len; - vaddr = kmap_atomic(skb_frag_page(frag)); - csum2 = ops->update(vaddr + frag->page_offset + - offset - start, copy, 0); - kunmap_atomic(vaddr); - csum = ops->combine(csum, csum2, pos, copy); - if (!(len -= copy)) - return csum; - offset += copy; - pos += copy; - } - start = end; - } - - skb_walk_frags(skb, frag_iter) { - int end; - - WARN_ON(start > offset + len); - - end = start + frag_iter->len; - if ((copy = end - offset) > 0) { - __wsum csum2; - if (copy > len) - copy = len; - csum2 = __skb_checksum(frag_iter, offset - start, - copy, 0, ops); - csum = ops->combine(csum, csum2, pos, copy); - if ((len -= copy) == 0) - return csum; - offset += copy; - pos += copy; - } - start = end; - } - BUG_ON(len); - - return csum; -} -EXPORT_SYMBOL(__skb_checksum); - -__wsum skb_checksum(const struct sk_buff *skb, int offset, - int len, __wsum csum) -{ - const struct skb_checksum_ops ops = { - .update = csum_partial_ext, - .combine = csum_block_add_ext, - }; - - return __skb_checksum(skb, offset, len, csum, &ops); -} -EXPORT_SYMBOL(skb_checksum); - -/* Both of above in one bottle. */ - -__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, - u8 *to, int len, __wsum csum) -{ - int start = skb_headlen(skb); - int i, copy = start - offset; - struct sk_buff *frag_iter; - int pos = 0; - - /* Copy header. */ - if (copy > 0) { - if (copy > len) - copy = len; - csum = csum_partial_copy_nocheck(skb->data + offset, to, - copy, csum); - if ((len -= copy) == 0) - return csum; - offset += copy; - to += copy; - pos = copy; - } - - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - int end; - - WARN_ON(start > offset + len); - - end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]); - if ((copy = end - offset) > 0) { - __wsum csum2; - u8 *vaddr; - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - if (copy > len) - copy = len; - vaddr = kmap_atomic(skb_frag_page(frag)); - csum2 = csum_partial_copy_nocheck(vaddr + - frag->page_offset + - offset - start, to, - copy, 0); - kunmap_atomic(vaddr); - csum = csum_block_add(csum, csum2, pos); - if (!(len -= copy)) - return csum; - offset += copy; - to += copy; - pos += copy; - } - start = end; - } - - skb_walk_frags(skb, frag_iter) { - __wsum csum2; - int end; - - WARN_ON(start > offset + len); - - end = start + frag_iter->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - csum2 = skb_copy_and_csum_bits(frag_iter, - offset - start, - to, copy, 0); - csum = csum_block_add(csum, csum2, pos); - if ((len -= copy) == 0) - return csum; - offset += copy; - to += copy; - pos += copy; - } - start = end; - } - BUG_ON(len); - return csum; -} -EXPORT_SYMBOL(skb_copy_and_csum_bits); - - /** - * skb_zerocopy_headlen - Calculate headroom needed for skb_zerocopy() - * @from: source buffer - * - * Calculates the amount of linear headroom needed in the 'to' skb passed - * into skb_zerocopy(). - */ -unsigned int -skb_zerocopy_headlen(const struct sk_buff *from) -{ - unsigned int hlen = 0; - - if (!from->head_frag || - skb_headlen(from) < L1_CACHE_BYTES || - skb_shinfo(from)->nr_frags >= MAX_SKB_FRAGS) - hlen = skb_headlen(from); - - if (skb_has_frag_list(from)) - hlen = from->len; - - return hlen; -} -EXPORT_SYMBOL_GPL(skb_zerocopy_headlen); - -/** - * skb_zerocopy - Zero copy skb to skb - * @to: destination buffer - * @from: source buffer - * @len: number of bytes to copy from source buffer - * @hlen: size of linear headroom in destination buffer - * - * Copies up to `len` bytes from `from` to `to` by creating references - * to the frags in the source buffer. - * - * The `hlen` as calculated by skb_zerocopy_headlen() specifies the - * headroom in the `to` buffer. - * - * Return value: - * 0: everything is OK - * -ENOMEM: couldn't orphan frags of @from due to lack of memory - * -EFAULT: skb_copy_bits() found some problem with skb geometry - */ -int -skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen) -{ - int i, j = 0; - int plen = 0; /* length of skb->head fragment */ - int ret; - struct page *page; - unsigned int offset; - - BUG_ON(!from->head_frag && !hlen); - - /* dont bother with small payloads */ - if (len <= skb_tailroom(to)) - return skb_copy_bits(from, 0, skb_put(to, len), len); - - if (hlen) { - ret = skb_copy_bits(from, 0, skb_put(to, hlen), hlen); - if (unlikely(ret)) - return ret; - len -= hlen; - } else { - plen = min_t(int, skb_headlen(from), len); - if (plen) { - page = virt_to_head_page(from->head); - offset = from->data - (unsigned char *)page_address(page); - __skb_fill_page_desc(to, 0, page, offset, plen); - get_page(page); - j = 1; - len -= plen; - } - } - - to->truesize += len + plen; - to->len += len + plen; - to->data_len += len + plen; - - if (unlikely(skb_orphan_frags(from, GFP_ATOMIC))) { - skb_tx_error(from); - return -ENOMEM; - } - - for (i = 0; i < skb_shinfo(from)->nr_frags; i++) { - if (!len) - break; - skb_shinfo(to)->frags[j] = skb_shinfo(from)->frags[i]; - skb_shinfo(to)->frags[j].size = min_t(int, skb_shinfo(to)->frags[j].size, len); - len -= skb_shinfo(to)->frags[j].size; - skb_frag_ref(to, j); - j++; - } - skb_shinfo(to)->nr_frags = j; - - return 0; -} -EXPORT_SYMBOL_GPL(skb_zerocopy); - -void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to) -{ - __wsum csum; - long csstart; - - if (skb->ip_summed == CHECKSUM_PARTIAL) - csstart = skb_checksum_start_offset(skb); - else - csstart = skb_headlen(skb); - - BUG_ON(csstart > skb_headlen(skb)); - - skb_copy_from_linear_data(skb, to, csstart); - - csum = 0; - if (csstart != skb->len) - csum = skb_copy_and_csum_bits(skb, csstart, to + csstart, - skb->len - csstart, 0); - - if (skb->ip_summed == CHECKSUM_PARTIAL) { - long csstuff = csstart + skb->csum_offset; - - *((__sum16 *)(to + csstuff)) = csum_fold(csum); - } -} -EXPORT_SYMBOL(skb_copy_and_csum_dev); - -/** - * skb_dequeue - remove from the head of the queue - * @list: list to dequeue from - * - * Remove the head of the list. The list lock is taken so the function - * may be used safely with other locking list functions. The head item is - * returned or %NULL if the list is empty. - */ - -struct sk_buff *skb_dequeue(struct sk_buff_head *list) -{ - unsigned long flags; - struct sk_buff *result; - - spin_lock_irqsave(&list->lock, flags); - result = __skb_dequeue(list); - spin_unlock_irqrestore(&list->lock, flags); - return result; -} -EXPORT_SYMBOL(skb_dequeue); - -/** - * skb_dequeue_tail - remove from the tail of the queue - * @list: list to dequeue from - * - * Remove the tail of the list. The list lock is taken so the function - * may be used safely with other locking list functions. The tail item is - * returned or %NULL if the list is empty. - */ -struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list) -{ - unsigned long flags; - struct sk_buff *result; - - spin_lock_irqsave(&list->lock, flags); - result = __skb_dequeue_tail(list); - spin_unlock_irqrestore(&list->lock, flags); - return result; -} -EXPORT_SYMBOL(skb_dequeue_tail); - -/** - * skb_queue_purge - empty a list - * @list: list to empty - * - * Delete all buffers on an &sk_buff list. Each buffer is removed from - * the list and one reference dropped. This function takes the list - * lock and is atomic with respect to other list locking functions. - */ -void skb_queue_purge(struct sk_buff_head *list) -{ - struct sk_buff *skb; - while ((skb = skb_dequeue(list)) != NULL) - kfree_skb(skb); -} -EXPORT_SYMBOL(skb_queue_purge); - -/** - * skb_rbtree_purge - empty a skb rbtree - * @root: root of the rbtree to empty - * - * Delete all buffers on an &sk_buff rbtree. Each buffer is removed from - * the list and one reference dropped. This function does not take - * any lock. Synchronization should be handled by the caller (e.g., TCP - * out-of-order queue is protected by the socket lock). - */ -void skb_rbtree_purge(struct rb_root *root) -{ - struct sk_buff *skb, *next; - - rbtree_postorder_for_each_entry_safe(skb, next, root, rbnode) - kfree_skb(skb); - - *root = RB_ROOT; -} - -/** - * skb_queue_head - queue a buffer at the list head - * @list: list to use - * @newsk: buffer to queue - * - * Queue a buffer at the start of the list. This function takes the - * list lock and can be used safely with other locking &sk_buff functions - * safely. - * - * A buffer cannot be placed on two lists at the same time. - */ -void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk) -{ - unsigned long flags; - - spin_lock_irqsave(&list->lock, flags); - __skb_queue_head(list, newsk); - spin_unlock_irqrestore(&list->lock, flags); -} -EXPORT_SYMBOL(skb_queue_head); - -/** - * skb_queue_tail - queue a buffer at the list tail - * @list: list to use - * @newsk: buffer to queue - * - * Queue a buffer at the tail of the list. This function takes the - * list lock and can be used safely with other locking &sk_buff functions - * safely. - * - * A buffer cannot be placed on two lists at the same time. - */ -void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk) -{ - unsigned long flags; - - spin_lock_irqsave(&list->lock, flags); - __skb_queue_tail(list, newsk); - spin_unlock_irqrestore(&list->lock, flags); -} -EXPORT_SYMBOL(skb_queue_tail); - -/** - * skb_unlink - remove a buffer from a list - * @skb: buffer to remove - * @list: list to use - * - * Remove a packet from a list. The list locks are taken and this - * function is atomic with respect to other list locked calls - * - * You must know what list the SKB is on. - */ -void skb_unlink(struct sk_buff *skb, struct sk_buff_head *list) -{ - unsigned long flags; - - spin_lock_irqsave(&list->lock, flags); - __skb_unlink(skb, list); - spin_unlock_irqrestore(&list->lock, flags); -} -EXPORT_SYMBOL(skb_unlink); - -/** - * skb_append - append a buffer - * @old: buffer to insert after - * @newsk: buffer to insert - * @list: list to use - * - * Place a packet after a given packet in a list. The list locks are taken - * and this function is atomic with respect to other list locked calls. - * A buffer cannot be placed on two lists at the same time. - */ -void skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list) -{ - unsigned long flags; - - spin_lock_irqsave(&list->lock, flags); - __skb_queue_after(list, old, newsk); - spin_unlock_irqrestore(&list->lock, flags); -} -EXPORT_SYMBOL(skb_append); - -/** - * skb_insert - insert a buffer - * @old: buffer to insert before - * @newsk: buffer to insert - * @list: list to use - * - * Place a packet before a given packet in a list. The list locks are - * taken and this function is atomic with respect to other list locked - * calls. - * - * A buffer cannot be placed on two lists at the same time. - */ -void skb_insert(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head *list) -{ - unsigned long flags; - - spin_lock_irqsave(&list->lock, flags); - __skb_insert(newsk, old->prev, old, list); - spin_unlock_irqrestore(&list->lock, flags); -} -EXPORT_SYMBOL(skb_insert); - -static inline void skb_split_inside_header(struct sk_buff *skb, - struct sk_buff* skb1, - const u32 len, const int pos) -{ - int i; - - skb_copy_from_linear_data_offset(skb, len, skb_put(skb1, pos - len), - pos - len); - /* And move data appendix as is. */ - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) - skb_shinfo(skb1)->frags[i] = skb_shinfo(skb)->frags[i]; - - skb_shinfo(skb1)->nr_frags = skb_shinfo(skb)->nr_frags; - skb_shinfo(skb)->nr_frags = 0; - skb1->data_len = skb->data_len; - skb1->len += skb1->data_len; - skb->data_len = 0; - skb->len = len; - skb_set_tail_pointer(skb, len); -} - -static inline void skb_split_no_header(struct sk_buff *skb, - struct sk_buff* skb1, - const u32 len, int pos) -{ - int i, k = 0; - const int nfrags = skb_shinfo(skb)->nr_frags; - - skb_shinfo(skb)->nr_frags = 0; - skb1->len = skb1->data_len = skb->len - len; - skb->len = len; - skb->data_len = len - pos; - - for (i = 0; i < nfrags; i++) { - int size = skb_frag_size(&skb_shinfo(skb)->frags[i]); - - if (pos + size > len) { - skb_shinfo(skb1)->frags[k] = skb_shinfo(skb)->frags[i]; - - if (pos < len) { - /* Split frag. - * We have two variants in this case: - * 1. Move all the frag to the second - * part, if it is possible. F.e. - * this approach is mandatory for TUX, - * where splitting is expensive. - * 2. Split is accurately. We make this. - */ - skb_frag_ref(skb, i); - skb_shinfo(skb1)->frags[0].page_offset += len - pos; - skb_frag_size_sub(&skb_shinfo(skb1)->frags[0], len - pos); - skb_frag_size_set(&skb_shinfo(skb)->frags[i], len - pos); - skb_shinfo(skb)->nr_frags++; - } - k++; - } else - skb_shinfo(skb)->nr_frags++; - pos += size; - } - skb_shinfo(skb1)->nr_frags = k; -} - -/** - * skb_split - Split fragmented skb to two parts at length len. - * @skb: the buffer to split - * @skb1: the buffer to receive the second part - * @len: new length for skb - */ -void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len) -{ - int pos = skb_headlen(skb); - - skb_shinfo(skb1)->tx_flags = skb_shinfo(skb)->tx_flags & SKBTX_SHARED_FRAG; - if (len < pos) /* Split line is inside header. */ - skb_split_inside_header(skb, skb1, len, pos); - else /* Second chunk has no header, nothing to copy. */ - skb_split_no_header(skb, skb1, len, pos); -} -EXPORT_SYMBOL(skb_split); - -/* Shifting from/to a cloned skb is a no-go. - * - * Caller cannot keep skb_shinfo related pointers past calling here! - */ -static int skb_prepare_for_shift(struct sk_buff *skb) -{ - return skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC); -} - -/** - * skb_shift - Shifts paged data partially from skb to another - * @tgt: buffer into which tail data gets added - * @skb: buffer from which the paged data comes from - * @shiftlen: shift up to this many bytes - * - * Attempts to shift up to shiftlen worth of bytes, which may be less than - * the length of the skb, from skb to tgt. Returns number bytes shifted. - * It's up to caller to free skb if everything was shifted. - * - * If @tgt runs out of frags, the whole operation is aborted. - * - * Skb cannot include anything else but paged data while tgt is allowed - * to have non-paged data as well. - * - * TODO: full sized shift could be optimized but that would need - * specialized skb free'er to handle frags without up-to-date nr_frags. - */ -int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen) -{ - int from, to, merge, todo; - struct skb_frag_struct *fragfrom, *fragto; - - BUG_ON(shiftlen > skb->len); - BUG_ON(skb_headlen(skb)); /* Would corrupt stream */ - - todo = shiftlen; - from = 0; - to = skb_shinfo(tgt)->nr_frags; - fragfrom = &skb_shinfo(skb)->frags[from]; - - /* Actual merge is delayed until the point when we know we can - * commit all, so that we don't have to undo partial changes - */ - if (!to || - !skb_can_coalesce(tgt, to, skb_frag_page(fragfrom), - fragfrom->page_offset)) { - merge = -1; - } else { - merge = to - 1; - - todo -= skb_frag_size(fragfrom); - if (todo < 0) { - if (skb_prepare_for_shift(skb) || - skb_prepare_for_shift(tgt)) - return 0; - - /* All previous frag pointers might be stale! */ - fragfrom = &skb_shinfo(skb)->frags[from]; - fragto = &skb_shinfo(tgt)->frags[merge]; - - skb_frag_size_add(fragto, shiftlen); - skb_frag_size_sub(fragfrom, shiftlen); - fragfrom->page_offset += shiftlen; - - goto onlymerged; - } - - from++; - } - - /* Skip full, not-fitting skb to avoid expensive operations */ - if ((shiftlen == skb->len) && - (skb_shinfo(skb)->nr_frags - from) > (MAX_SKB_FRAGS - to)) - return 0; - - if (skb_prepare_for_shift(skb) || skb_prepare_for_shift(tgt)) - return 0; - - while ((todo > 0) && (from < skb_shinfo(skb)->nr_frags)) { - if (to == MAX_SKB_FRAGS) - return 0; - - fragfrom = &skb_shinfo(skb)->frags[from]; - fragto = &skb_shinfo(tgt)->frags[to]; - - if (todo >= skb_frag_size(fragfrom)) { - *fragto = *fragfrom; - todo -= skb_frag_size(fragfrom); - from++; - to++; - - } else { - __skb_frag_ref(fragfrom); - fragto->page = fragfrom->page; - fragto->page_offset = fragfrom->page_offset; - skb_frag_size_set(fragto, todo); - - fragfrom->page_offset += todo; - skb_frag_size_sub(fragfrom, todo); - todo = 0; - - to++; - break; - } - } - - /* Ready to "commit" this state change to tgt */ - skb_shinfo(tgt)->nr_frags = to; - - if (merge >= 0) { - fragfrom = &skb_shinfo(skb)->frags[0]; - fragto = &skb_shinfo(tgt)->frags[merge]; - - skb_frag_size_add(fragto, skb_frag_size(fragfrom)); - __skb_frag_unref(fragfrom); - } - - /* Reposition in the original skb */ - to = 0; - while (from < skb_shinfo(skb)->nr_frags) - skb_shinfo(skb)->frags[to++] = skb_shinfo(skb)->frags[from++]; - skb_shinfo(skb)->nr_frags = to; - - BUG_ON(todo > 0 && !skb_shinfo(skb)->nr_frags); - -onlymerged: - /* Most likely the tgt won't ever need its checksum anymore, skb on - * the other hand might need it if it needs to be resent - */ - tgt->ip_summed = CHECKSUM_PARTIAL; - skb->ip_summed = CHECKSUM_PARTIAL; - - /* Yak, is it really working this way? Some helper please? */ - skb->len -= shiftlen; - skb->data_len -= shiftlen; - skb->truesize -= shiftlen; - tgt->len += shiftlen; - tgt->data_len += shiftlen; - tgt->truesize += shiftlen; - - return shiftlen; -} - -/** - * skb_prepare_seq_read - Prepare a sequential read of skb data - * @skb: the buffer to read - * @from: lower offset of data to be read - * @to: upper offset of data to be read - * @st: state variable - * - * Initializes the specified state variable. Must be called before - * invoking skb_seq_read() for the first time. - */ -void skb_prepare_seq_read(struct sk_buff *skb, unsigned int from, - unsigned int to, struct skb_seq_state *st) -{ - st->lower_offset = from; - st->upper_offset = to; - st->root_skb = st->cur_skb = skb; - st->frag_idx = st->stepped_offset = 0; - st->frag_data = NULL; -} -EXPORT_SYMBOL(skb_prepare_seq_read); - -/** - * skb_seq_read - Sequentially read skb data - * @consumed: number of bytes consumed by the caller so far - * @data: destination pointer for data to be returned - * @st: state variable - * - * Reads a block of skb data at @consumed relative to the - * lower offset specified to skb_prepare_seq_read(). Assigns - * the head of the data block to @data and returns the length - * of the block or 0 if the end of the skb data or the upper - * offset has been reached. - * - * The caller is not required to consume all of the data - * returned, i.e. @consumed is typically set to the number - * of bytes already consumed and the next call to - * skb_seq_read() will return the remaining part of the block. - * - * Note 1: The size of each block of data returned can be arbitrary, - * this limitation is the cost for zerocopy sequential - * reads of potentially non linear data. - * - * Note 2: Fragment lists within fragments are not implemented - * at the moment, state->root_skb could be replaced with - * a stack for this purpose. - */ -unsigned int skb_seq_read(unsigned int consumed, const u8 **data, - struct skb_seq_state *st) -{ - unsigned int block_limit, abs_offset = consumed + st->lower_offset; - skb_frag_t *frag; - - if (unlikely(abs_offset >= st->upper_offset)) { - if (st->frag_data) { - kunmap_atomic(st->frag_data); - st->frag_data = NULL; - } - return 0; - } - -next_skb: - block_limit = skb_headlen(st->cur_skb) + st->stepped_offset; - - if (abs_offset < block_limit && !st->frag_data) { - *data = st->cur_skb->data + (abs_offset - st->stepped_offset); - return block_limit - abs_offset; - } - - if (st->frag_idx == 0 && !st->frag_data) - st->stepped_offset += skb_headlen(st->cur_skb); - - while (st->frag_idx < skb_shinfo(st->cur_skb)->nr_frags) { - frag = &skb_shinfo(st->cur_skb)->frags[st->frag_idx]; - block_limit = skb_frag_size(frag) + st->stepped_offset; - - if (abs_offset < block_limit) { - if (!st->frag_data) - st->frag_data = kmap_atomic(skb_frag_page(frag)); - - *data = (u8 *) st->frag_data + frag->page_offset + - (abs_offset - st->stepped_offset); - - return block_limit - abs_offset; - } - - if (st->frag_data) { - kunmap_atomic(st->frag_data); - st->frag_data = NULL; - } - - st->frag_idx++; - st->stepped_offset += skb_frag_size(frag); - } - - if (st->frag_data) { - kunmap_atomic(st->frag_data); - st->frag_data = NULL; - } - - if (st->root_skb == st->cur_skb && skb_has_frag_list(st->root_skb)) { - st->cur_skb = skb_shinfo(st->root_skb)->frag_list; - st->frag_idx = 0; - goto next_skb; - } else if (st->cur_skb->next) { - st->cur_skb = st->cur_skb->next; - st->frag_idx = 0; - goto next_skb; - } - - return 0; -} -EXPORT_SYMBOL(skb_seq_read); - -/** - * skb_abort_seq_read - Abort a sequential read of skb data - * @st: state variable - * - * Must be called if skb_seq_read() was not called until it - * returned 0. - */ -void skb_abort_seq_read(struct skb_seq_state *st) -{ - if (st->frag_data) - kunmap_atomic(st->frag_data); -} -EXPORT_SYMBOL(skb_abort_seq_read); - -#define TS_SKB_CB(state) ((struct skb_seq_state *) &((state)->cb)) - -static unsigned int skb_ts_get_next_block(unsigned int offset, const u8 **text, - struct ts_config *conf, - struct ts_state *state) -{ - return skb_seq_read(offset, text, TS_SKB_CB(state)); -} - -static void skb_ts_finish(struct ts_config *conf, struct ts_state *state) -{ - skb_abort_seq_read(TS_SKB_CB(state)); -} - -/** - * skb_find_text - Find a text pattern in skb data - * @skb: the buffer to look in - * @from: search offset - * @to: search limit - * @config: textsearch configuration - * - * Finds a pattern in the skb data according to the specified - * textsearch configuration. Use textsearch_next() to retrieve - * subsequent occurrences of the pattern. Returns the offset - * to the first occurrence or UINT_MAX if no match was found. - */ -unsigned int skb_find_text(struct sk_buff *skb, unsigned int from, - unsigned int to, struct ts_config *config) -{ - struct ts_state state; - unsigned int ret; - - config->get_next_block = skb_ts_get_next_block; - config->finish = skb_ts_finish; - - skb_prepare_seq_read(skb, from, to, TS_SKB_CB(&state)); - - ret = textsearch_find(config, &state); - return (ret <= to - from ? ret : UINT_MAX); -} -EXPORT_SYMBOL(skb_find_text); - -/** - * skb_append_datato_frags - append the user data to a skb - * @sk: sock structure - * @skb: skb structure to be appended with user data. - * @getfrag: call back function to be used for getting the user data - * @from: pointer to user message iov - * @length: length of the iov message - * - * Description: This procedure append the user data in the fragment part - * of the skb if any page alloc fails user this procedure returns -ENOMEM - */ -int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb, - int (*getfrag)(void *from, char *to, int offset, - int len, int odd, struct sk_buff *skb), - void *from, int length) -{ - int frg_cnt = skb_shinfo(skb)->nr_frags; - int copy; - int offset = 0; - int ret; - struct page_frag *pfrag = ¤t->task_frag; - - do { - /* Return error if we don't have space for new frag */ - if (frg_cnt >= MAX_SKB_FRAGS) - return -EMSGSIZE; - - if (!sk_page_frag_refill(sk, pfrag)) - return -ENOMEM; - - /* copy the user data to page */ - copy = min_t(int, length, pfrag->size - pfrag->offset); - - ret = getfrag(from, page_address(pfrag->page) + pfrag->offset, - offset, copy, 0, skb); - if (ret < 0) - return -EFAULT; - - /* copy was successful so update the size parameters */ - skb_fill_page_desc(skb, frg_cnt, pfrag->page, pfrag->offset, - copy); - frg_cnt++; - pfrag->offset += copy; - get_page(pfrag->page); - - skb->truesize += copy; - atomic_add(copy, &sk->sk_wmem_alloc); - skb->len += copy; - skb->data_len += copy; - offset += copy; - length -= copy; - - } while (length > 0); - - return 0; -} -EXPORT_SYMBOL(skb_append_datato_frags); - -int skb_append_pagefrags(struct sk_buff *skb, struct page *page, - int offset, size_t size) -{ - int i = skb_shinfo(skb)->nr_frags; - - if (skb_can_coalesce(skb, i, page, offset)) { - skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], size); - } else if (i < MAX_SKB_FRAGS) { - get_page(page); - skb_fill_page_desc(skb, i, page, offset, size); - } else { - return -EMSGSIZE; - } - - return 0; -} -EXPORT_SYMBOL_GPL(skb_append_pagefrags); - -/** - * skb_pull_rcsum - pull skb and update receive checksum - * @skb: buffer to update - * @len: length of data pulled - * - * This function performs an skb_pull on the packet and updates - * the CHECKSUM_COMPLETE checksum. It should be used on - * receive path processing instead of skb_pull unless you know - * that the checksum difference is zero (e.g., a valid IP header) - * or you are setting ip_summed to CHECKSUM_NONE. - */ -unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len) -{ - unsigned char *data = skb->data; - - BUG_ON(len > skb->len); - __skb_pull(skb, len); - skb_postpull_rcsum(skb, data, len); - return skb->data; -} -EXPORT_SYMBOL_GPL(skb_pull_rcsum); - -/** - * skb_segment - Perform protocol segmentation on skb. - * @head_skb: buffer to segment - * @features: features for the output path (see dev->features) - * - * This function performs segmentation on the given skb. It returns - * a pointer to the first in a list of new skbs for the segments. - * In case of error it returns ERR_PTR(err). - */ -struct sk_buff *skb_segment(struct sk_buff *head_skb, - netdev_features_t features) -{ - struct sk_buff *segs = NULL; - struct sk_buff *tail = NULL; - struct sk_buff *list_skb = skb_shinfo(head_skb)->frag_list; - skb_frag_t *frag = skb_shinfo(head_skb)->frags; - unsigned int mss = skb_shinfo(head_skb)->gso_size; - unsigned int doffset = head_skb->data - skb_mac_header(head_skb); - struct sk_buff *frag_skb = head_skb; - unsigned int offset = doffset; - unsigned int tnl_hlen = skb_tnl_header_len(head_skb); - unsigned int partial_segs = 0; - unsigned int headroom; - unsigned int len = head_skb->len; - __be16 proto; - bool csum, sg; - int nfrags = skb_shinfo(head_skb)->nr_frags; - int err = -ENOMEM; - int i = 0; - int pos; - int dummy; - - __skb_push(head_skb, doffset); - proto = skb_network_protocol(head_skb, &dummy); - if (unlikely(!proto)) - return ERR_PTR(-EINVAL); - - sg = !!(features & NETIF_F_SG); - csum = !!can_checksum_protocol(features, proto); - - if (sg && csum && (mss != GSO_BY_FRAGS)) { - if (!(features & NETIF_F_GSO_PARTIAL)) { - struct sk_buff *iter; - - if (!list_skb || - !net_gso_ok(features, skb_shinfo(head_skb)->gso_type)) - goto normal; - - /* Split the buffer at the frag_list pointer. - * This is based on the assumption that all - * buffers in the chain excluding the last - * containing the same amount of data. - */ - skb_walk_frags(head_skb, iter) { - if (skb_headlen(iter)) - goto normal; - - len -= iter->len; - } - } - - /* GSO partial only requires that we trim off any excess that - * doesn't fit into an MSS sized block, so take care of that - * now. - */ - partial_segs = len / mss; - if (partial_segs > 1) - mss *= partial_segs; - else - partial_segs = 0; - } - -normal: - headroom = skb_headroom(head_skb); - pos = skb_headlen(head_skb); - - do { - struct sk_buff *nskb; - skb_frag_t *nskb_frag; - int hsize; - int size; - - if (unlikely(mss == GSO_BY_FRAGS)) { - len = list_skb->len; - } else { - len = head_skb->len - offset; - if (len > mss) - len = mss; - } - - hsize = skb_headlen(head_skb) - offset; - if (hsize < 0) - hsize = 0; - if (hsize > len || !sg) - hsize = len; - - if (!hsize && i >= nfrags && skb_headlen(list_skb) && - (skb_headlen(list_skb) == len || sg)) { - BUG_ON(skb_headlen(list_skb) > len); - - i = 0; - nfrags = skb_shinfo(list_skb)->nr_frags; - frag = skb_shinfo(list_skb)->frags; - frag_skb = list_skb; - pos += skb_headlen(list_skb); - - while (pos < offset + len) { - BUG_ON(i >= nfrags); - - size = skb_frag_size(frag); - if (pos + size > offset + len) - break; - - i++; - pos += size; - frag++; - } - - nskb = skb_clone(list_skb, GFP_ATOMIC); - list_skb = list_skb->next; - - if (unlikely(!nskb)) - goto err; - - if (unlikely(pskb_trim(nskb, len))) { - kfree_skb(nskb); - goto err; - } - - hsize = skb_end_offset(nskb); - if (skb_cow_head(nskb, doffset + headroom)) { - kfree_skb(nskb); - goto err; - } - - nskb->truesize += skb_end_offset(nskb) - hsize; - skb_release_head_state(nskb); - __skb_push(nskb, doffset); - } else { - nskb = __alloc_skb(hsize + doffset + headroom, - GFP_ATOMIC, skb_alloc_rx_flag(head_skb), - NUMA_NO_NODE); - - if (unlikely(!nskb)) - goto err; - - skb_reserve(nskb, headroom); - __skb_put(nskb, doffset); - } - - if (segs) - tail->next = nskb; - else - segs = nskb; - tail = nskb; - - __copy_skb_header(nskb, head_skb); - - skb_headers_offset_update(nskb, skb_headroom(nskb) - headroom); - skb_reset_mac_len(nskb); - - skb_copy_from_linear_data_offset(head_skb, -tnl_hlen, - nskb->data - tnl_hlen, - doffset + tnl_hlen); - - if (nskb->len == len + doffset) - goto perform_csum_check; - - if (!sg) { - if (!nskb->remcsum_offload) - nskb->ip_summed = CHECKSUM_NONE; - SKB_GSO_CB(nskb)->csum = - skb_copy_and_csum_bits(head_skb, offset, - skb_put(nskb, len), - len, 0); - SKB_GSO_CB(nskb)->csum_start = - skb_headroom(nskb) + doffset; - continue; - } - - nskb_frag = skb_shinfo(nskb)->frags; - - skb_copy_from_linear_data_offset(head_skb, offset, - skb_put(nskb, hsize), hsize); - - skb_shinfo(nskb)->tx_flags = skb_shinfo(head_skb)->tx_flags & - SKBTX_SHARED_FRAG; - - while (pos < offset + len) { - if (i >= nfrags) { - BUG_ON(skb_headlen(list_skb)); - - i = 0; - nfrags = skb_shinfo(list_skb)->nr_frags; - frag = skb_shinfo(list_skb)->frags; - frag_skb = list_skb; - - BUG_ON(!nfrags); - - list_skb = list_skb->next; - } - - if (unlikely(skb_shinfo(nskb)->nr_frags >= - MAX_SKB_FRAGS)) { - net_warn_ratelimited( - "skb_segment: too many frags: %u %u\n", - pos, mss); - goto err; - } - - if (unlikely(skb_orphan_frags(frag_skb, GFP_ATOMIC))) - goto err; - - *nskb_frag = *frag; - __skb_frag_ref(nskb_frag); - size = skb_frag_size(nskb_frag); - - if (pos < offset) { - nskb_frag->page_offset += offset - pos; - skb_frag_size_sub(nskb_frag, offset - pos); - } - - skb_shinfo(nskb)->nr_frags++; - - if (pos + size <= offset + len) { - i++; - frag++; - pos += size; - } else { - skb_frag_size_sub(nskb_frag, pos + size - (offset + len)); - goto skip_fraglist; - } - - nskb_frag++; - } - -skip_fraglist: - nskb->data_len = len - hsize; - nskb->len += nskb->data_len; - nskb->truesize += nskb->data_len; - -perform_csum_check: - if (!csum) { - if (skb_has_shared_frag(nskb)) { - err = __skb_linearize(nskb); - if (err) - goto err; - } - if (!nskb->remcsum_offload) - nskb->ip_summed = CHECKSUM_NONE; - SKB_GSO_CB(nskb)->csum = - skb_checksum(nskb, doffset, - nskb->len - doffset, 0); - SKB_GSO_CB(nskb)->csum_start = - skb_headroom(nskb) + doffset; - } - } while ((offset += len) < head_skb->len); - - /* Some callers want to get the end of the list. - * Put it in segs->prev to avoid walking the list. - * (see validate_xmit_skb_list() for example) - */ - segs->prev = tail; - - if (partial_segs) { - struct sk_buff *iter; - int type = skb_shinfo(head_skb)->gso_type; - unsigned short gso_size = skb_shinfo(head_skb)->gso_size; - - /* Update type to add partial and then remove dodgy if set */ - type |= (features & NETIF_F_GSO_PARTIAL) / NETIF_F_GSO_PARTIAL * SKB_GSO_PARTIAL; - type &= ~SKB_GSO_DODGY; - - /* Update GSO info and prepare to start updating headers on - * our way back down the stack of protocols. - */ - for (iter = segs; iter; iter = iter->next) { - skb_shinfo(iter)->gso_size = gso_size; - skb_shinfo(iter)->gso_segs = partial_segs; - skb_shinfo(iter)->gso_type = type; - SKB_GSO_CB(iter)->data_offset = skb_headroom(iter) + doffset; - } - - if (tail->len - doffset <= gso_size) - skb_shinfo(tail)->gso_size = 0; - else if (tail != segs) - skb_shinfo(tail)->gso_segs = DIV_ROUND_UP(tail->len - doffset, gso_size); - } - - /* Following permits correct backpressure, for protocols - * using skb_set_owner_w(). - * Idea is to tranfert ownership from head_skb to last segment. - */ - if (head_skb->destructor == sock_wfree) { - swap(tail->truesize, head_skb->truesize); - swap(tail->destructor, head_skb->destructor); - swap(tail->sk, head_skb->sk); - } - return segs; - -err: - kfree_skb_list(segs); - return ERR_PTR(err); -} -EXPORT_SYMBOL_GPL(skb_segment); - -int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) -{ - struct skb_shared_info *pinfo, *skbinfo = skb_shinfo(skb); - unsigned int offset = skb_gro_offset(skb); - unsigned int headlen = skb_headlen(skb); - unsigned int len = skb_gro_len(skb); - struct sk_buff *lp, *p = *head; - unsigned int delta_truesize; - - if (unlikely(p->len + len >= 65536)) - return -E2BIG; - - lp = NAPI_GRO_CB(p)->last; - pinfo = skb_shinfo(lp); - - if (headlen <= offset) { - skb_frag_t *frag; - skb_frag_t *frag2; - int i = skbinfo->nr_frags; - int nr_frags = pinfo->nr_frags + i; - - if (nr_frags > MAX_SKB_FRAGS) - goto merge; - - offset -= headlen; - pinfo->nr_frags = nr_frags; - skbinfo->nr_frags = 0; - - frag = pinfo->frags + nr_frags; - frag2 = skbinfo->frags + i; - do { - *--frag = *--frag2; - } while (--i); - - frag->page_offset += offset; - skb_frag_size_sub(frag, offset); - - /* all fragments truesize : remove (head size + sk_buff) */ - delta_truesize = skb->truesize - - SKB_TRUESIZE(skb_end_offset(skb)); - - skb->truesize -= skb->data_len; - skb->len -= skb->data_len; - skb->data_len = 0; - - NAPI_GRO_CB(skb)->free = NAPI_GRO_FREE; - goto done; - } else if (skb->head_frag) { - int nr_frags = pinfo->nr_frags; - skb_frag_t *frag = pinfo->frags + nr_frags; - struct page *page = virt_to_head_page(skb->head); - unsigned int first_size = headlen - offset; - unsigned int first_offset; - - if (nr_frags + 1 + skbinfo->nr_frags > MAX_SKB_FRAGS) - goto merge; - - first_offset = skb->data - - (unsigned char *)page_address(page) + - offset; - - pinfo->nr_frags = nr_frags + 1 + skbinfo->nr_frags; - - frag->page.p = page; - frag->page_offset = first_offset; - skb_frag_size_set(frag, first_size); - - memcpy(frag + 1, skbinfo->frags, sizeof(*frag) * skbinfo->nr_frags); - /* We dont need to clear skbinfo->nr_frags here */ - - delta_truesize = skb->truesize - SKB_DATA_ALIGN(sizeof(struct sk_buff)); - NAPI_GRO_CB(skb)->free = NAPI_GRO_FREE_STOLEN_HEAD; - goto done; - } - -merge: - delta_truesize = skb->truesize; - if (offset > headlen) { - unsigned int eat = offset - headlen; - - skbinfo->frags[0].page_offset += eat; - skb_frag_size_sub(&skbinfo->frags[0], eat); - skb->data_len -= eat; - skb->len -= eat; - offset = headlen; - } - - __skb_pull(skb, offset); - - if (NAPI_GRO_CB(p)->last == p) - skb_shinfo(p)->frag_list = skb; - else - NAPI_GRO_CB(p)->last->next = skb; - NAPI_GRO_CB(p)->last = skb; - __skb_header_release(skb); - lp = p; - -done: - NAPI_GRO_CB(p)->count++; - p->data_len += len; - p->truesize += delta_truesize; - p->len += len; - if (lp != p) { - lp->data_len += len; - lp->truesize += delta_truesize; - lp->len += len; - } - NAPI_GRO_CB(skb)->same_flow = 1; - return 0; -} -EXPORT_SYMBOL_GPL(skb_gro_receive); - -void __init skb_init(void) -{ - skbuff_head_cache = kmem_cache_create("skbuff_head_cache", - sizeof(struct sk_buff), - 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, - NULL); - skbuff_fclone_cache = kmem_cache_create("skbuff_fclone_cache", - sizeof(struct sk_buff_fclones), - 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, - NULL); -} - -/** - * skb_to_sgvec - Fill a scatter-gather list from a socket buffer - * @skb: Socket buffer containing the buffers to be mapped - * @sg: The scatter-gather list to map into - * @offset: The offset into the buffer's contents to start mapping - * @len: Length of buffer space to be mapped - * - * Fill the specified scatter-gather list with mappings/pointers into a - * region of the buffer space attached to a socket buffer. - */ -static int -__skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) -{ - int start = skb_headlen(skb); - int i, copy = start - offset; - struct sk_buff *frag_iter; - int elt = 0; - - if (copy > 0) { - if (copy > len) - copy = len; - sg_set_buf(sg, skb->data + offset, copy); - elt++; - if ((len -= copy) == 0) - return elt; - offset += copy; - } - - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { - int end; - - WARN_ON(start > offset + len); - - end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]); - if ((copy = end - offset) > 0) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - - if (copy > len) - copy = len; - sg_set_page(&sg[elt], skb_frag_page(frag), copy, - frag->page_offset+offset-start); - elt++; - if (!(len -= copy)) - return elt; - offset += copy; - } - start = end; - } - - skb_walk_frags(skb, frag_iter) { - int end; - - WARN_ON(start > offset + len); - - end = start + frag_iter->len; - if ((copy = end - offset) > 0) { - if (copy > len) - copy = len; - elt += __skb_to_sgvec(frag_iter, sg+elt, offset - start, - copy); - if ((len -= copy) == 0) - return elt; - offset += copy; - } - start = end; - } - BUG_ON(len); - return elt; -} - -/* As compared with skb_to_sgvec, skb_to_sgvec_nomark only map skb to given - * sglist without mark the sg which contain last skb data as the end. - * So the caller can mannipulate sg list as will when padding new data after - * the first call without calling sg_unmark_end to expend sg list. - * - * Scenario to use skb_to_sgvec_nomark: - * 1. sg_init_table - * 2. skb_to_sgvec_nomark(payload1) - * 3. skb_to_sgvec_nomark(payload2) - * - * This is equivalent to: - * 1. sg_init_table - * 2. skb_to_sgvec(payload1) - * 3. sg_unmark_end - * 4. skb_to_sgvec(payload2) - * - * When mapping mutilple payload conditionally, skb_to_sgvec_nomark - * is more preferable. - */ -int skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg, - int offset, int len) -{ - return __skb_to_sgvec(skb, sg, offset, len); -} -EXPORT_SYMBOL_GPL(skb_to_sgvec_nomark); - -int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len) -{ - int nsg = __skb_to_sgvec(skb, sg, offset, len); - - sg_mark_end(&sg[nsg - 1]); - - return nsg; -} -EXPORT_SYMBOL_GPL(skb_to_sgvec); - -/** - * skb_cow_data - Check that a socket buffer's data buffers are writable - * @skb: The socket buffer to check. - * @tailbits: Amount of trailing space to be added - * @trailer: Returned pointer to the skb where the @tailbits space begins - * - * Make sure that the data buffers attached to a socket buffer are - * writable. If they are not, private copies are made of the data buffers - * and the socket buffer is set to use these instead. - * - * If @tailbits is given, make sure that there is space to write @tailbits - * bytes of data beyond current end of socket buffer. @trailer will be - * set to point to the skb in which this space begins. - * - * The number of scatterlist elements required to completely map the - * COW'd and extended socket buffer will be returned. - */ -int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer) -{ - int copyflag; - int elt; - struct sk_buff *skb1, **skb_p; - - /* If skb is cloned or its head is paged, reallocate - * head pulling out all the pages (pages are considered not writable - * at the moment even if they are anonymous). - */ - if ((skb_cloned(skb) || skb_shinfo(skb)->nr_frags) && - __pskb_pull_tail(skb, skb_pagelen(skb)-skb_headlen(skb)) == NULL) - return -ENOMEM; - - /* Easy case. Most of packets will go this way. */ - if (!skb_has_frag_list(skb)) { - /* A little of trouble, not enough of space for trailer. - * This should not happen, when stack is tuned to generate - * good frames. OK, on miss we reallocate and reserve even more - * space, 128 bytes is fair. */ - - if (skb_tailroom(skb) < tailbits && - pskb_expand_head(skb, 0, tailbits-skb_tailroom(skb)+128, GFP_ATOMIC)) - return -ENOMEM; - - /* Voila! */ - *trailer = skb; - return 1; - } - - /* Misery. We are in troubles, going to mincer fragments... */ - - elt = 1; - skb_p = &skb_shinfo(skb)->frag_list; - copyflag = 0; - - while ((skb1 = *skb_p) != NULL) { - int ntail = 0; - - /* The fragment is partially pulled by someone, - * this can happen on input. Copy it and everything - * after it. */ - - if (skb_shared(skb1)) - copyflag = 1; - - /* If the skb is the last, worry about trailer. */ - - if (skb1->next == NULL && tailbits) { - if (skb_shinfo(skb1)->nr_frags || - skb_has_frag_list(skb1) || - skb_tailroom(skb1) < tailbits) - ntail = tailbits + 128; - } - - if (copyflag || - skb_cloned(skb1) || - ntail || - skb_shinfo(skb1)->nr_frags || - skb_has_frag_list(skb1)) { - struct sk_buff *skb2; - - /* Fuck, we are miserable poor guys... */ - if (ntail == 0) - skb2 = skb_copy(skb1, GFP_ATOMIC); - else - skb2 = skb_copy_expand(skb1, - skb_headroom(skb1), - ntail, - GFP_ATOMIC); - if (unlikely(skb2 == NULL)) - return -ENOMEM; - - if (skb1->sk) - skb_set_owner_w(skb2, skb1->sk); - - /* Looking around. Are we still alive? - * OK, link new skb, drop old one */ - - skb2->next = skb1->next; - *skb_p = skb2; - kfree_skb(skb1); - skb1 = skb2; - } - elt++; - *trailer = skb1; - skb_p = &skb1->next; - } - - return elt; -} -EXPORT_SYMBOL_GPL(skb_cow_data); - -static void sock_rmem_free(struct sk_buff *skb) -{ - struct sock *sk = skb->sk; - - atomic_sub(skb->truesize, &sk->sk_rmem_alloc); -} - -/* - * Note: We dont mem charge error packets (no sk_forward_alloc changes) - */ -int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb) -{ - if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= - (unsigned int)sk->sk_rcvbuf) - return -ENOMEM; - - skb_orphan(skb); - skb->sk = sk; - skb->destructor = sock_rmem_free; - atomic_add(skb->truesize, &sk->sk_rmem_alloc); - - /* before exiting rcu section, make sure dst is refcounted */ - skb_dst_force(skb); - - skb_queue_tail(&sk->sk_error_queue, skb); - if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_data_ready(sk); - return 0; -} -EXPORT_SYMBOL(sock_queue_err_skb); - -struct sk_buff *sock_dequeue_err_skb(struct sock *sk) -{ - struct sk_buff_head *q = &sk->sk_error_queue; - struct sk_buff *skb, *skb_next; - unsigned long flags; - int err = 0; - - spin_lock_irqsave(&q->lock, flags); - skb = __skb_dequeue(q); - if (skb && (skb_next = skb_peek(q))) - err = SKB_EXT_ERR(skb_next)->ee.ee_errno; - spin_unlock_irqrestore(&q->lock, flags); - - sk->sk_err = err; - if (err) - sk->sk_error_report(sk); - - return skb; -} -EXPORT_SYMBOL(sock_dequeue_err_skb); - -/** - * skb_clone_sk - create clone of skb, and take reference to socket - * @skb: the skb to clone - * - * This function creates a clone of a buffer that holds a reference on - * sk_refcnt. Buffers created via this function are meant to be - * returned using sock_queue_err_skb, or free via kfree_skb. - * - * When passing buffers allocated with this function to sock_queue_err_skb - * it is necessary to wrap the call with sock_hold/sock_put in order to - * prevent the socket from being released prior to being enqueued on - * the sk_error_queue. - */ -struct sk_buff *skb_clone_sk(struct sk_buff *skb) -{ - struct sock *sk = skb->sk; - struct sk_buff *clone; - - if (!sk || !atomic_inc_not_zero(&sk->sk_refcnt)) - return NULL; - - clone = skb_clone(skb, GFP_ATOMIC); - if (!clone) { - sock_put(sk); - return NULL; - } - - clone->sk = sk; - clone->destructor = sock_efree; - - return clone; -} -EXPORT_SYMBOL(skb_clone_sk); - -static void __skb_complete_tx_timestamp(struct sk_buff *skb, - struct sock *sk, - int tstype) -{ - struct sock_exterr_skb *serr; - int err; - - serr = SKB_EXT_ERR(skb); - memset(serr, 0, sizeof(*serr)); - serr->ee.ee_errno = ENOMSG; - serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; - serr->ee.ee_info = tstype; - if (sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) { - serr->ee.ee_data = skb_shinfo(skb)->tskey; - if (sk->sk_protocol == IPPROTO_TCP && - sk->sk_type == SOCK_STREAM) - serr->ee.ee_data -= sk->sk_tskey; - } - - err = sock_queue_err_skb(sk, skb); - - if (err) - kfree_skb(skb); -} - -static bool skb_may_tx_timestamp(struct sock *sk, bool tsonly) -{ - bool ret; - - if (likely(sysctl_tstamp_allow_data || tsonly)) - return true; - - read_lock_bh(&sk->sk_callback_lock); - ret = sk->sk_socket && sk->sk_socket->file && - file_ns_capable(sk->sk_socket->file, &init_user_ns, CAP_NET_RAW); - read_unlock_bh(&sk->sk_callback_lock); - return ret; -} - -void skb_complete_tx_timestamp(struct sk_buff *skb, - struct skb_shared_hwtstamps *hwtstamps) -{ - struct sock *sk = skb->sk; - - if (!skb_may_tx_timestamp(sk, false)) - return; - - /* take a reference to prevent skb_orphan() from freeing the socket */ - sock_hold(sk); - - *skb_hwtstamps(skb) = *hwtstamps; - __skb_complete_tx_timestamp(skb, sk, SCM_TSTAMP_SND); - - sock_put(sk); -} -EXPORT_SYMBOL_GPL(skb_complete_tx_timestamp); - -void __skb_tstamp_tx(struct sk_buff *orig_skb, - struct skb_shared_hwtstamps *hwtstamps, - struct sock *sk, int tstype) -{ - struct sk_buff *skb; - bool tsonly; - - if (!sk) - return; - - tsonly = sk->sk_tsflags & SOF_TIMESTAMPING_OPT_TSONLY; - if (!skb_may_tx_timestamp(sk, tsonly)) - return; - - if (tsonly) - skb = alloc_skb(0, GFP_ATOMIC); - else - skb = skb_clone(orig_skb, GFP_ATOMIC); - if (!skb) - return; - - if (tsonly) { - skb_shinfo(skb)->tx_flags = skb_shinfo(orig_skb)->tx_flags; - skb_shinfo(skb)->tskey = skb_shinfo(orig_skb)->tskey; - } - - if (hwtstamps) - *skb_hwtstamps(skb) = *hwtstamps; - else - skb->tstamp = ktime_get_real(); - - __skb_complete_tx_timestamp(skb, sk, tstype); -} -EXPORT_SYMBOL_GPL(__skb_tstamp_tx); - -void skb_tstamp_tx(struct sk_buff *orig_skb, - struct skb_shared_hwtstamps *hwtstamps) -{ - return __skb_tstamp_tx(orig_skb, hwtstamps, orig_skb->sk, - SCM_TSTAMP_SND); -} -EXPORT_SYMBOL_GPL(skb_tstamp_tx); - -void skb_complete_wifi_ack(struct sk_buff *skb, bool acked) -{ - struct sock *sk = skb->sk; - struct sock_exterr_skb *serr; - int err; - - skb->wifi_acked_valid = 1; - skb->wifi_acked = acked; - - serr = SKB_EXT_ERR(skb); - memset(serr, 0, sizeof(*serr)); - serr->ee.ee_errno = ENOMSG; - serr->ee.ee_origin = SO_EE_ORIGIN_TXSTATUS; - - /* take a reference to prevent skb_orphan() from freeing the socket */ - sock_hold(sk); - - err = sock_queue_err_skb(sk, skb); - if (err) - kfree_skb(skb); - - sock_put(sk); -} -EXPORT_SYMBOL_GPL(skb_complete_wifi_ack); - -/** - * skb_partial_csum_set - set up and verify partial csum values for packet - * @skb: the skb to set - * @start: the number of bytes after skb->data to start checksumming. - * @off: the offset from start to place the checksum. - * - * For untrusted partially-checksummed packets, we need to make sure the values - * for skb->csum_start and skb->csum_offset are valid so we don't oops. - * - * This function checks and sets those values and skb->ip_summed: if this - * returns false you should drop the packet. - */ -bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off) -{ - if (unlikely(start > skb_headlen(skb)) || - unlikely((int)start + off > skb_headlen(skb) - 2)) { - net_warn_ratelimited("bad partial csum: csum=%u/%u len=%u\n", - start, off, skb_headlen(skb)); - return false; - } - skb->ip_summed = CHECKSUM_PARTIAL; - skb->csum_start = skb_headroom(skb) + start; - skb->csum_offset = off; - skb_set_transport_header(skb, start); - return true; -} -EXPORT_SYMBOL_GPL(skb_partial_csum_set); - -static int skb_maybe_pull_tail(struct sk_buff *skb, unsigned int len, - unsigned int max) -{ - if (skb_headlen(skb) >= len) - return 0; - - /* If we need to pullup then pullup to the max, so we - * won't need to do it again. - */ - if (max > skb->len) - max = skb->len; - - if (__pskb_pull_tail(skb, max - skb_headlen(skb)) == NULL) - return -ENOMEM; - - if (skb_headlen(skb) < len) - return -EPROTO; - - return 0; -} - -#define MAX_TCP_HDR_LEN (15 * 4) - -static __sum16 *skb_checksum_setup_ip(struct sk_buff *skb, - typeof(IPPROTO_IP) proto, - unsigned int off) -{ - switch (proto) { - int err; - - case IPPROTO_TCP: - err = skb_maybe_pull_tail(skb, off + sizeof(struct tcphdr), - off + MAX_TCP_HDR_LEN); - if (!err && !skb_partial_csum_set(skb, off, - offsetof(struct tcphdr, - check))) - err = -EPROTO; - return err ? ERR_PTR(err) : &tcp_hdr(skb)->check; - - case IPPROTO_UDP: - err = skb_maybe_pull_tail(skb, off + sizeof(struct udphdr), - off + sizeof(struct udphdr)); - if (!err && !skb_partial_csum_set(skb, off, - offsetof(struct udphdr, - check))) - err = -EPROTO; - return err ? ERR_PTR(err) : &udp_hdr(skb)->check; - } - - return ERR_PTR(-EPROTO); -} - -/* This value should be large enough to cover a tagged ethernet header plus - * maximally sized IP and TCP or UDP headers. - */ -#define MAX_IP_HDR_LEN 128 - -static int skb_checksum_setup_ipv4(struct sk_buff *skb, bool recalculate) -{ - unsigned int off; - bool fragment; - __sum16 *csum; - int err; - - fragment = false; - - err = skb_maybe_pull_tail(skb, - sizeof(struct iphdr), - MAX_IP_HDR_LEN); - if (err < 0) - goto out; - - if (ip_hdr(skb)->frag_off & htons(IP_OFFSET | IP_MF)) - fragment = true; - - off = ip_hdrlen(skb); - - err = -EPROTO; - - if (fragment) - goto out; - - csum = skb_checksum_setup_ip(skb, ip_hdr(skb)->protocol, off); - if (IS_ERR(csum)) - return PTR_ERR(csum); - - if (recalculate) - *csum = ~csum_tcpudp_magic(ip_hdr(skb)->saddr, - ip_hdr(skb)->daddr, - skb->len - off, - ip_hdr(skb)->protocol, 0); - err = 0; - -out: - return err; -} - -/* This value should be large enough to cover a tagged ethernet header plus - * an IPv6 header, all options, and a maximal TCP or UDP header. - */ -#define MAX_IPV6_HDR_LEN 256 - -#define OPT_HDR(type, skb, off) \ - (type *)(skb_network_header(skb) + (off)) - -static int skb_checksum_setup_ipv6(struct sk_buff *skb, bool recalculate) -{ - int err; - u8 nexthdr; - unsigned int off; - unsigned int len; - bool fragment; - bool done; - __sum16 *csum; - - fragment = false; - done = false; - - off = sizeof(struct ipv6hdr); - - err = skb_maybe_pull_tail(skb, off, MAX_IPV6_HDR_LEN); - if (err < 0) - goto out; - - nexthdr = ipv6_hdr(skb)->nexthdr; - - len = sizeof(struct ipv6hdr) + ntohs(ipv6_hdr(skb)->payload_len); - while (off <= len && !done) { - switch (nexthdr) { - case IPPROTO_DSTOPTS: - case IPPROTO_HOPOPTS: - case IPPROTO_ROUTING: { - struct ipv6_opt_hdr *hp; - - err = skb_maybe_pull_tail(skb, - off + - sizeof(struct ipv6_opt_hdr), - MAX_IPV6_HDR_LEN); - if (err < 0) - goto out; - - hp = OPT_HDR(struct ipv6_opt_hdr, skb, off); - nexthdr = hp->nexthdr; - off += ipv6_optlen(hp); - break; - } - case IPPROTO_AH: { - struct ip_auth_hdr *hp; - - err = skb_maybe_pull_tail(skb, - off + - sizeof(struct ip_auth_hdr), - MAX_IPV6_HDR_LEN); - if (err < 0) - goto out; - - hp = OPT_HDR(struct ip_auth_hdr, skb, off); - nexthdr = hp->nexthdr; - off += ipv6_authlen(hp); - break; - } - case IPPROTO_FRAGMENT: { - struct frag_hdr *hp; - - err = skb_maybe_pull_tail(skb, - off + - sizeof(struct frag_hdr), - MAX_IPV6_HDR_LEN); - if (err < 0) - goto out; - - hp = OPT_HDR(struct frag_hdr, skb, off); - - if (hp->frag_off & htons(IP6_OFFSET | IP6_MF)) - fragment = true; - - nexthdr = hp->nexthdr; - off += sizeof(struct frag_hdr); - break; - } - default: - done = true; - break; - } - } - - err = -EPROTO; - - if (!done || fragment) - goto out; - - csum = skb_checksum_setup_ip(skb, nexthdr, off); - if (IS_ERR(csum)) - return PTR_ERR(csum); - - if (recalculate) - *csum = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - skb->len - off, nexthdr, 0); - err = 0; - -out: - return err; -} - -/** - * skb_checksum_setup - set up partial checksum offset - * @skb: the skb to set up - * @recalculate: if true the pseudo-header checksum will be recalculated - */ -int skb_checksum_setup(struct sk_buff *skb, bool recalculate) -{ - int err; - - switch (skb->protocol) { - case htons(ETH_P_IP): - err = skb_checksum_setup_ipv4(skb, recalculate); - break; - - case htons(ETH_P_IPV6): - err = skb_checksum_setup_ipv6(skb, recalculate); - break; - - default: - err = -EPROTO; - break; - } - - return err; -} -EXPORT_SYMBOL(skb_checksum_setup); - -/** - * skb_checksum_maybe_trim - maybe trims the given skb - * @skb: the skb to check - * @transport_len: the data length beyond the network header - * - * Checks whether the given skb has data beyond the given transport length. - * If so, returns a cloned skb trimmed to this transport length. - * Otherwise returns the provided skb. Returns NULL in error cases - * (e.g. transport_len exceeds skb length or out-of-memory). - * - * Caller needs to set the skb transport header and free any returned skb if it - * differs from the provided skb. - */ -static struct sk_buff *skb_checksum_maybe_trim(struct sk_buff *skb, - unsigned int transport_len) -{ - struct sk_buff *skb_chk; - unsigned int len = skb_transport_offset(skb) + transport_len; - int ret; - - if (skb->len < len) - return NULL; - else if (skb->len == len) - return skb; - - skb_chk = skb_clone(skb, GFP_ATOMIC); - if (!skb_chk) - return NULL; - - ret = pskb_trim_rcsum(skb_chk, len); - if (ret) { - kfree_skb(skb_chk); - return NULL; - } - - return skb_chk; -} - -/** - * skb_checksum_trimmed - validate checksum of an skb - * @skb: the skb to check - * @transport_len: the data length beyond the network header - * @skb_chkf: checksum function to use - * - * Applies the given checksum function skb_chkf to the provided skb. - * Returns a checked and maybe trimmed skb. Returns NULL on error. - * - * If the skb has data beyond the given transport length, then a - * trimmed & cloned skb is checked and returned. - * - * Caller needs to set the skb transport header and free any returned skb if it - * differs from the provided skb. - */ -struct sk_buff *skb_checksum_trimmed(struct sk_buff *skb, - unsigned int transport_len, - __sum16(*skb_chkf)(struct sk_buff *skb)) -{ - struct sk_buff *skb_chk; - unsigned int offset = skb_transport_offset(skb); - __sum16 ret; - - skb_chk = skb_checksum_maybe_trim(skb, transport_len); - if (!skb_chk) - goto err; - - if (!pskb_may_pull(skb_chk, offset)) - goto err; - - skb_pull_rcsum(skb_chk, offset); - ret = skb_chkf(skb_chk); - skb_push_rcsum(skb_chk, offset); - - if (ret) - goto err; - - return skb_chk; - -err: - if (skb_chk && skb_chk != skb) - kfree_skb(skb_chk); - - return NULL; - -} -EXPORT_SYMBOL(skb_checksum_trimmed); - -void __skb_warn_lro_forwarding(const struct sk_buff *skb) -{ - net_warn_ratelimited("%s: received packets cannot be forwarded while LRO is enabled\n", - skb->dev->name); -} -EXPORT_SYMBOL(__skb_warn_lro_forwarding); - -void kfree_skb_partial(struct sk_buff *skb, bool head_stolen) -{ - if (head_stolen) { - skb_release_head_state(skb); - kmem_cache_free(skbuff_head_cache, skb); - } else { - __kfree_skb(skb); - } -} -EXPORT_SYMBOL(kfree_skb_partial); - -/** - * skb_try_coalesce - try to merge skb to prior one - * @to: prior buffer - * @from: buffer to add - * @fragstolen: pointer to boolean - * @delta_truesize: how much more was allocated than was requested - */ -bool skb_try_coalesce(struct sk_buff *to, struct sk_buff *from, - bool *fragstolen, int *delta_truesize) -{ - int i, delta, len = from->len; - - *fragstolen = false; - - if (skb_cloned(to)) - return false; - - if (len <= skb_tailroom(to)) { - if (len) - BUG_ON(skb_copy_bits(from, 0, skb_put(to, len), len)); - *delta_truesize = 0; - return true; - } - - if (skb_has_frag_list(to) || skb_has_frag_list(from)) - return false; - - if (skb_headlen(from) != 0) { - struct page *page; - unsigned int offset; - - if (skb_shinfo(to)->nr_frags + - skb_shinfo(from)->nr_frags >= MAX_SKB_FRAGS) - return false; - - if (skb_head_is_locked(from)) - return false; - - delta = from->truesize - SKB_DATA_ALIGN(sizeof(struct sk_buff)); - - page = virt_to_head_page(from->head); - offset = from->data - (unsigned char *)page_address(page); - - skb_fill_page_desc(to, skb_shinfo(to)->nr_frags, - page, offset, skb_headlen(from)); - *fragstolen = true; - } else { - if (skb_shinfo(to)->nr_frags + - skb_shinfo(from)->nr_frags > MAX_SKB_FRAGS) - return false; - - delta = from->truesize - SKB_TRUESIZE(skb_end_offset(from)); - } - - WARN_ON_ONCE(delta < len); - - memcpy(skb_shinfo(to)->frags + skb_shinfo(to)->nr_frags, - skb_shinfo(from)->frags, - skb_shinfo(from)->nr_frags * sizeof(skb_frag_t)); - skb_shinfo(to)->nr_frags += skb_shinfo(from)->nr_frags; - - if (!skb_cloned(from)) - skb_shinfo(from)->nr_frags = 0; - - /* if the skb is not cloned this does nothing - * since we set nr_frags to 0. - */ - for (i = 0; i < skb_shinfo(from)->nr_frags; i++) - skb_frag_ref(from, i); - - to->truesize += delta; - to->len += len; - to->data_len += len; - - *delta_truesize = delta; - return true; -} -EXPORT_SYMBOL(skb_try_coalesce); - -/** - * skb_scrub_packet - scrub an skb - * - * @skb: buffer to clean - * @xnet: packet is crossing netns - * - * skb_scrub_packet can be used after encapsulating or decapsulting a packet - * into/from a tunnel. Some information have to be cleared during these - * operations. - * skb_scrub_packet can also be used to clean a skb before injecting it in - * another namespace (@xnet == true). We have to clear all information in the - * skb that could impact namespace isolation. - */ -void skb_scrub_packet(struct sk_buff *skb, bool xnet) -{ - skb->tstamp.tv64 = 0; - skb->pkt_type = PACKET_HOST; - skb->skb_iif = 0; - skb->ignore_df = 0; - skb_dst_drop(skb); - secpath_reset(skb); - nf_reset(skb); - nf_reset_trace(skb); - - if (!xnet) - return; - - skb_orphan(skb); - skb->mark = 0; -} -EXPORT_SYMBOL_GPL(skb_scrub_packet); - -/** - * skb_gso_transport_seglen - Return length of individual segments of a gso packet - * - * @skb: GSO skb - * - * skb_gso_transport_seglen is used to determine the real size of the - * individual segments, including Layer4 headers (TCP/UDP). - * - * The MAC/L2 or network (IP, IPv6) headers are not accounted for. - */ -unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) -{ - const struct skb_shared_info *shinfo = skb_shinfo(skb); - unsigned int thlen = 0; - - if (skb->encapsulation) { - thlen = skb_inner_transport_header(skb) - - skb_transport_header(skb); - - if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) - thlen += inner_tcp_hdrlen(skb); - } else if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) { - thlen = tcp_hdrlen(skb); - } else if (unlikely(shinfo->gso_type & SKB_GSO_SCTP)) { - thlen = sizeof(struct sctphdr); - } - /* UFO sets gso_size to the size of the fragmentation - * payload, i.e. the size of the L4 (UDP) header is already - * accounted for. - */ - return thlen + shinfo->gso_size; -} -EXPORT_SYMBOL_GPL(skb_gso_transport_seglen); - -/** - * skb_gso_validate_mtu - Return in case such skb fits a given MTU - * - * @skb: GSO skb - * @mtu: MTU to validate against - * - * skb_gso_validate_mtu validates if a given skb will fit a wanted MTU - * once split. - */ -bool skb_gso_validate_mtu(const struct sk_buff *skb, unsigned int mtu) -{ - const struct skb_shared_info *shinfo = skb_shinfo(skb); - const struct sk_buff *iter; - unsigned int hlen; - - hlen = skb_gso_network_seglen(skb); - - if (shinfo->gso_size != GSO_BY_FRAGS) - return hlen <= mtu; - - /* Undo this so we can re-use header sizes */ - hlen -= GSO_BY_FRAGS; - - skb_walk_frags(skb, iter) { - if (hlen + skb_headlen(iter) > mtu) - return false; - } - - return true; -} -EXPORT_SYMBOL_GPL(skb_gso_validate_mtu); - -static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb) -{ - if (skb_cow(skb, skb_headroom(skb)) < 0) { - kfree_skb(skb); - return NULL; - } - - memmove(skb->data - ETH_HLEN, skb->data - skb->mac_len - VLAN_HLEN, - 2 * ETH_ALEN); - skb->mac_header += VLAN_HLEN; - return skb; -} - -struct sk_buff *skb_vlan_untag(struct sk_buff *skb) -{ - struct vlan_hdr *vhdr; - u16 vlan_tci; - - if (unlikely(skb_vlan_tag_present(skb))) { - /* vlan_tci is already set-up so leave this for another time */ - return skb; - } - - skb = skb_share_check(skb, GFP_ATOMIC); - if (unlikely(!skb)) - goto err_free; - - if (unlikely(!pskb_may_pull(skb, VLAN_HLEN))) - goto err_free; - - vhdr = (struct vlan_hdr *)skb->data; - vlan_tci = ntohs(vhdr->h_vlan_TCI); - __vlan_hwaccel_put_tag(skb, skb->protocol, vlan_tci); - - skb_pull_rcsum(skb, VLAN_HLEN); - vlan_set_encap_proto(skb, vhdr); - - skb = skb_reorder_vlan_header(skb); - if (unlikely(!skb)) - goto err_free; - - skb_reset_network_header(skb); - skb_reset_transport_header(skb); - skb_reset_mac_len(skb); - - return skb; - -err_free: - kfree_skb(skb); - return NULL; -} -EXPORT_SYMBOL(skb_vlan_untag); - -int skb_ensure_writable(struct sk_buff *skb, int write_len) -{ - if (!pskb_may_pull(skb, write_len)) - return -ENOMEM; - - if (!skb_cloned(skb) || skb_clone_writable(skb, write_len)) - return 0; - - return pskb_expand_head(skb, 0, 0, GFP_ATOMIC); -} -EXPORT_SYMBOL(skb_ensure_writable); - -/* remove VLAN header from packet and update csum accordingly. - * expects a non skb_vlan_tag_present skb with a vlan tag payload - */ -int __skb_vlan_pop(struct sk_buff *skb, u16 *vlan_tci) -{ - struct vlan_hdr *vhdr; - int offset = skb->data - skb_mac_header(skb); - int err; - - if (WARN_ONCE(offset, - "__skb_vlan_pop got skb with skb->data not at mac header (offset %d)\n", - offset)) { - return -EINVAL; - } - - err = skb_ensure_writable(skb, VLAN_ETH_HLEN); - if (unlikely(err)) - return err; - - skb_postpull_rcsum(skb, skb->data + (2 * ETH_ALEN), VLAN_HLEN); - - vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN); - *vlan_tci = ntohs(vhdr->h_vlan_TCI); - - memmove(skb->data + VLAN_HLEN, skb->data, 2 * ETH_ALEN); - __skb_pull(skb, VLAN_HLEN); - - vlan_set_encap_proto(skb, vhdr); - skb->mac_header += VLAN_HLEN; - - if (skb_network_offset(skb) < ETH_HLEN) - skb_set_network_header(skb, ETH_HLEN); - - skb_reset_mac_len(skb); - - return err; -} -EXPORT_SYMBOL(__skb_vlan_pop); - -/* Pop a vlan tag either from hwaccel or from payload. - * Expects skb->data at mac header. - */ -int skb_vlan_pop(struct sk_buff *skb) -{ - u16 vlan_tci; - __be16 vlan_proto; - int err; - - if (likely(skb_vlan_tag_present(skb))) { - skb->vlan_tci = 0; - } else { - if (unlikely(!eth_type_vlan(skb->protocol))) - return 0; - - err = __skb_vlan_pop(skb, &vlan_tci); - if (err) - return err; - } - /* move next vlan tag to hw accel tag */ - if (likely(!eth_type_vlan(skb->protocol))) - return 0; - - vlan_proto = skb->protocol; - err = __skb_vlan_pop(skb, &vlan_tci); - if (unlikely(err)) - return err; - - __vlan_hwaccel_put_tag(skb, vlan_proto, vlan_tci); - return 0; -} -EXPORT_SYMBOL(skb_vlan_pop); - -/* Push a vlan tag either into hwaccel or into payload (if hwaccel tag present). - * Expects skb->data at mac header. - */ -int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci) -{ - if (skb_vlan_tag_present(skb)) { - int offset = skb->data - skb_mac_header(skb); - int err; - - if (WARN_ONCE(offset, - "skb_vlan_push got skb with skb->data not at mac header (offset %d)\n", - offset)) { - return -EINVAL; - } - - err = __vlan_insert_tag(skb, skb->vlan_proto, - skb_vlan_tag_get(skb)); - if (err) - return err; - - skb->protocol = skb->vlan_proto; - skb->mac_len += VLAN_HLEN; - - skb_postpush_rcsum(skb, skb->data + (2 * ETH_ALEN), VLAN_HLEN); - } - __vlan_hwaccel_put_tag(skb, vlan_proto, vlan_tci); - return 0; -} -EXPORT_SYMBOL(skb_vlan_push); - -/** - * alloc_skb_with_frags - allocate skb with page frags - * - * @header_len: size of linear part - * @data_len: needed length in frags - * @max_page_order: max page order desired. - * @errcode: pointer to error code if any - * @gfp_mask: allocation mask - * - * This can be used to allocate a paged skb, given a maximal order for frags. - */ -struct sk_buff *alloc_skb_with_frags(unsigned long header_len, - unsigned long data_len, - int max_page_order, - int *errcode, - gfp_t gfp_mask) -{ - int npages = (data_len + (PAGE_SIZE - 1)) >> PAGE_SHIFT; - unsigned long chunk; - struct sk_buff *skb; - struct page *page; - gfp_t gfp_head; - int i; - - *errcode = -EMSGSIZE; - /* Note this test could be relaxed, if we succeed to allocate - * high order pages... - */ - if (npages > MAX_SKB_FRAGS) - return NULL; - - gfp_head = gfp_mask; - if (gfp_head & __GFP_DIRECT_RECLAIM) - gfp_head |= __GFP_REPEAT; - - *errcode = -ENOBUFS; - skb = alloc_skb(header_len, gfp_head); - if (!skb) - return NULL; - - skb->truesize += npages << PAGE_SHIFT; - - for (i = 0; npages > 0; i++) { - int order = max_page_order; - - while (order) { - if (npages >= 1 << order) { - page = alloc_pages((gfp_mask & ~__GFP_DIRECT_RECLAIM) | - __GFP_COMP | - __GFP_NOWARN | - __GFP_NORETRY, - order); - if (page) - goto fill_page; - /* Do not retry other high order allocations */ - order = 1; - max_page_order = 0; - } - order--; - } - page = alloc_page(gfp_mask); - if (!page) - goto failure; -fill_page: - chunk = min_t(unsigned long, data_len, - PAGE_SIZE << order); - skb_fill_page_desc(skb, i, page, 0, chunk); - data_len -= chunk; - npages -= 1 << order; - } - return skb; - -failure: - kfree_skb(skb); - return NULL; -} -EXPORT_SYMBOL(alloc_skb_with_frags); - -/* carve out the first off bytes from skb when off < headlen */ -static int pskb_carve_inside_header(struct sk_buff *skb, const u32 off, - const int headlen, gfp_t gfp_mask) -{ - int i; - int size = skb_end_offset(skb); - int new_hlen = headlen - off; - u8 *data; - - size = SKB_DATA_ALIGN(size); - - if (skb_pfmemalloc(skb)) - gfp_mask |= __GFP_MEMALLOC; - data = kmalloc_reserve(size + - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)), - gfp_mask, NUMA_NO_NODE, NULL); - if (!data) - return -ENOMEM; - - size = SKB_WITH_OVERHEAD(ksize(data)); - - /* Copy real data, and all frags */ - skb_copy_from_linear_data_offset(skb, off, data, new_hlen); - skb->len -= off; - - memcpy((struct skb_shared_info *)(data + size), - skb_shinfo(skb), - offsetof(struct skb_shared_info, - frags[skb_shinfo(skb)->nr_frags])); - if (skb_cloned(skb)) { - /* drop the old head gracefully */ - if (skb_orphan_frags(skb, gfp_mask)) { - kfree(data); - return -ENOMEM; - } - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) - skb_frag_ref(skb, i); - if (skb_has_frag_list(skb)) - skb_clone_fraglist(skb); - skb_release_data(skb); - } else { - /* we can reuse existing recount- all we did was - * relocate values - */ - skb_free_head(skb); - } - - skb->head = data; - skb->data = data; - skb->head_frag = 0; -#ifdef NET_SKBUFF_DATA_USES_OFFSET - skb->end = size; -#else - skb->end = skb->head + size; -#endif - skb_set_tail_pointer(skb, skb_headlen(skb)); - skb_headers_offset_update(skb, 0); - skb->cloned = 0; - skb->hdr_len = 0; - skb->nohdr = 0; - atomic_set(&skb_shinfo(skb)->dataref, 1); - - return 0; -} - -static int pskb_carve(struct sk_buff *skb, const u32 off, gfp_t gfp); - -/* carve out the first eat bytes from skb's frag_list. May recurse into - * pskb_carve() - */ -static int pskb_carve_frag_list(struct sk_buff *skb, - struct skb_shared_info *shinfo, int eat, - gfp_t gfp_mask) -{ - struct sk_buff *list = shinfo->frag_list; - struct sk_buff *clone = NULL; - struct sk_buff *insp = NULL; - - do { - if (!list) { - pr_err("Not enough bytes to eat. Want %d\n", eat); - return -EFAULT; - } - if (list->len <= eat) { - /* Eaten as whole. */ - eat -= list->len; - list = list->next; - insp = list; - } else { - /* Eaten partially. */ - if (skb_shared(list)) { - clone = skb_clone(list, gfp_mask); - if (!clone) - return -ENOMEM; - insp = list->next; - list = clone; - } else { - /* This may be pulled without problems. */ - insp = list; - } - if (pskb_carve(list, eat, gfp_mask) < 0) { - kfree_skb(clone); - return -ENOMEM; - } - break; - } - } while (eat); - - /* Free pulled out fragments. */ - while ((list = shinfo->frag_list) != insp) { - shinfo->frag_list = list->next; - kfree_skb(list); - } - /* And insert new clone at head. */ - if (clone) { - clone->next = list; - shinfo->frag_list = clone; - } - return 0; -} - -/* carve off first len bytes from skb. Split line (off) is in the - * non-linear part of skb - */ -static int pskb_carve_inside_nonlinear(struct sk_buff *skb, const u32 off, - int pos, gfp_t gfp_mask) -{ - int i, k = 0; - int size = skb_end_offset(skb); - u8 *data; - const int nfrags = skb_shinfo(skb)->nr_frags; - struct skb_shared_info *shinfo; - - size = SKB_DATA_ALIGN(size); - - if (skb_pfmemalloc(skb)) - gfp_mask |= __GFP_MEMALLOC; - data = kmalloc_reserve(size + - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)), - gfp_mask, NUMA_NO_NODE, NULL); - if (!data) - return -ENOMEM; - - size = SKB_WITH_OVERHEAD(ksize(data)); - - memcpy((struct skb_shared_info *)(data + size), - skb_shinfo(skb), offsetof(struct skb_shared_info, - frags[skb_shinfo(skb)->nr_frags])); - if (skb_orphan_frags(skb, gfp_mask)) { - kfree(data); - return -ENOMEM; - } - shinfo = (struct skb_shared_info *)(data + size); - for (i = 0; i < nfrags; i++) { - int fsize = skb_frag_size(&skb_shinfo(skb)->frags[i]); - - if (pos + fsize > off) { - shinfo->frags[k] = skb_shinfo(skb)->frags[i]; - - if (pos < off) { - /* Split frag. - * We have two variants in this case: - * 1. Move all the frag to the second - * part, if it is possible. F.e. - * this approach is mandatory for TUX, - * where splitting is expensive. - * 2. Split is accurately. We make this. - */ - shinfo->frags[0].page_offset += off - pos; - skb_frag_size_sub(&shinfo->frags[0], off - pos); - } - skb_frag_ref(skb, i); - k++; - } - pos += fsize; - } - shinfo->nr_frags = k; - if (skb_has_frag_list(skb)) - skb_clone_fraglist(skb); - - if (k == 0) { - /* split line is in frag list */ - pskb_carve_frag_list(skb, shinfo, off - pos, gfp_mask); - } - skb_release_data(skb); - - skb->head = data; - skb->head_frag = 0; - skb->data = data; -#ifdef NET_SKBUFF_DATA_USES_OFFSET - skb->end = size; -#else - skb->end = skb->head + size; -#endif - skb_reset_tail_pointer(skb); - skb_headers_offset_update(skb, 0); - skb->cloned = 0; - skb->hdr_len = 0; - skb->nohdr = 0; - skb->len -= off; - skb->data_len = skb->len; - atomic_set(&skb_shinfo(skb)->dataref, 1); - return 0; -} - -/* remove len bytes from the beginning of the skb */ -static int pskb_carve(struct sk_buff *skb, const u32 len, gfp_t gfp) -{ - int headlen = skb_headlen(skb); - - if (len < headlen) - return pskb_carve_inside_header(skb, len, headlen, gfp); - else - return pskb_carve_inside_nonlinear(skb, len, headlen, gfp); -} - -/* Extract to_copy bytes starting at off from skb, and return this in - * a new skb - */ -struct sk_buff *pskb_extract(struct sk_buff *skb, int off, - int to_copy, gfp_t gfp) -{ - struct sk_buff *clone = skb_clone(skb, gfp); - - if (!clone) - return NULL; - - if (pskb_carve(clone, off, gfp) < 0 || - pskb_trim(clone, to_copy)) { - kfree_skb(clone); - return NULL; - } - return clone; -} -EXPORT_SYMBOL(pskb_extract); diff --git a/src/linux/net/core/sock.c b/src/linux/net/core/sock.c deleted file mode 100644 index 00a074d..0000000 --- a/src/linux/net/core/sock.c +++ /dev/null @@ -1,3089 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Generic socket support routines. Memory allocators, socket lock/release - * handler for protocols to use and generic option handler. - * - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Florian La Roche, - * Alan Cox, - * - * Fixes: - * Alan Cox : Numerous verify_area() problems - * Alan Cox : Connecting on a connecting socket - * now returns an error for tcp. - * Alan Cox : sock->protocol is set correctly. - * and is not sometimes left as 0. - * Alan Cox : connect handles icmp errors on a - * connect properly. Unfortunately there - * is a restart syscall nasty there. I - * can't match BSD without hacking the C - * library. Ideas urgently sought! - * Alan Cox : Disallow bind() to addresses that are - * not ours - especially broadcast ones!! - * Alan Cox : Socket 1024 _IS_ ok for users. (fencepost) - * Alan Cox : sock_wfree/sock_rfree don't destroy sockets, - * instead they leave that for the DESTROY timer. - * Alan Cox : Clean up error flag in accept - * Alan Cox : TCP ack handling is buggy, the DESTROY timer - * was buggy. Put a remove_sock() in the handler - * for memory when we hit 0. Also altered the timer - * code. The ACK stuff can wait and needs major - * TCP layer surgery. - * Alan Cox : Fixed TCP ack bug, removed remove sock - * and fixed timer/inet_bh race. - * Alan Cox : Added zapped flag for TCP - * Alan Cox : Move kfree_skb into skbuff.c and tidied up surplus code - * Alan Cox : for new sk_buff allocations wmalloc/rmalloc now call alloc_skb - * Alan Cox : kfree_s calls now are kfree_skbmem so we can track skb resources - * Alan Cox : Supports socket option broadcast now as does udp. Packet and raw need fixing. - * Alan Cox : Added RCVBUF,SNDBUF size setting. It suddenly occurred to me how easy it was so... - * Rick Sladkey : Relaxed UDP rules for matching packets. - * C.E.Hawkins : IFF_PROMISC/SIOCGHWADDR support - * Pauline Middelink : identd support - * Alan Cox : Fixed connect() taking signals I think. - * Alan Cox : SO_LINGER supported - * Alan Cox : Error reporting fixes - * Anonymous : inet_create tidied up (sk->reuse setting) - * Alan Cox : inet sockets don't set sk->type! - * Alan Cox : Split socket option code - * Alan Cox : Callbacks - * Alan Cox : Nagle flag for Charles & Johannes stuff - * Alex : Removed restriction on inet fioctl - * Alan Cox : Splitting INET from NET core - * Alan Cox : Fixed bogus SO_TYPE handling in getsockopt() - * Adam Caldwell : Missing return in SO_DONTROUTE/SO_DEBUG code - * Alan Cox : Split IP from generic code - * Alan Cox : New kfree_skbmem() - * Alan Cox : Make SO_DEBUG superuser only. - * Alan Cox : Allow anyone to clear SO_DEBUG - * (compatibility fix) - * Alan Cox : Added optimistic memory grabbing for AF_UNIX throughput. - * Alan Cox : Allocator for a socket is settable. - * Alan Cox : SO_ERROR includes soft errors. - * Alan Cox : Allow NULL arguments on some SO_ opts - * Alan Cox : Generic socket allocation to make hooks - * easier (suggested by Craig Metz). - * Michael Pall : SO_ERROR returns positive errno again - * Steve Whitehouse: Added default destructor to free - * protocol private data. - * Steve Whitehouse: Added various other default routines - * common to several socket families. - * Chris Evans : Call suser() check last on F_SETOWN - * Jay Schulist : Added SO_ATTACH_FILTER and SO_DETACH_FILTER. - * Andi Kleen : Add sock_kmalloc()/sock_kfree_s() - * Andi Kleen : Fix write_space callback - * Chris Evans : Security fixes - signedness again - * Arnaldo C. Melo : cleanups, use skb_queue_purge - * - * To Fix: - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#ifdef CONFIG_INET -#include -#endif - -#include - -static DEFINE_MUTEX(proto_list_mutex); -static LIST_HEAD(proto_list); - -/** - * sk_ns_capable - General socket capability test - * @sk: Socket to use a capability on or through - * @user_ns: The user namespace of the capability to use - * @cap: The capability to use - * - * Test to see if the opener of the socket had when the socket was - * created and the current process has the capability @cap in the user - * namespace @user_ns. - */ -bool sk_ns_capable(const struct sock *sk, - struct user_namespace *user_ns, int cap) -{ - return file_ns_capable(sk->sk_socket->file, user_ns, cap) && - ns_capable(user_ns, cap); -} -EXPORT_SYMBOL(sk_ns_capable); - -/** - * sk_capable - Socket global capability test - * @sk: Socket to use a capability on or through - * @cap: The global capability to use - * - * Test to see if the opener of the socket had when the socket was - * created and the current process has the capability @cap in all user - * namespaces. - */ -bool sk_capable(const struct sock *sk, int cap) -{ - return sk_ns_capable(sk, &init_user_ns, cap); -} -EXPORT_SYMBOL(sk_capable); - -/** - * sk_net_capable - Network namespace socket capability test - * @sk: Socket to use a capability on or through - * @cap: The capability to use - * - * Test to see if the opener of the socket had when the socket was created - * and the current process has the capability @cap over the network namespace - * the socket is a member of. - */ -bool sk_net_capable(const struct sock *sk, int cap) -{ - return sk_ns_capable(sk, sock_net(sk)->user_ns, cap); -} -EXPORT_SYMBOL(sk_net_capable); - -/* - * Each address family might have different locking rules, so we have - * one slock key per address family: - */ -static struct lock_class_key af_family_keys[AF_MAX]; -static struct lock_class_key af_family_slock_keys[AF_MAX]; - -/* - * Make lock validator output more readable. (we pre-construct these - * strings build-time, so that runtime initialization of socket - * locks is fast): - */ -static const char *const af_family_key_strings[AF_MAX+1] = { - "sk_lock-AF_UNSPEC", "sk_lock-AF_UNIX" , "sk_lock-AF_INET" , - "sk_lock-AF_AX25" , "sk_lock-AF_IPX" , "sk_lock-AF_APPLETALK", - "sk_lock-AF_NETROM", "sk_lock-AF_BRIDGE" , "sk_lock-AF_ATMPVC" , - "sk_lock-AF_X25" , "sk_lock-AF_INET6" , "sk_lock-AF_ROSE" , - "sk_lock-AF_DECnet", "sk_lock-AF_NETBEUI" , "sk_lock-AF_SECURITY" , - "sk_lock-AF_KEY" , "sk_lock-AF_NETLINK" , "sk_lock-AF_PACKET" , - "sk_lock-AF_ASH" , "sk_lock-AF_ECONET" , "sk_lock-AF_ATMSVC" , - "sk_lock-AF_RDS" , "sk_lock-AF_SNA" , "sk_lock-AF_IRDA" , - "sk_lock-AF_PPPOX" , "sk_lock-AF_WANPIPE" , "sk_lock-AF_LLC" , - "sk_lock-27" , "sk_lock-28" , "sk_lock-AF_CAN" , - "sk_lock-AF_TIPC" , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV" , - "sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN" , "sk_lock-AF_PHONET" , - "sk_lock-AF_IEEE802154", "sk_lock-AF_CAIF" , "sk_lock-AF_ALG" , - "sk_lock-AF_NFC" , "sk_lock-AF_VSOCK" , "sk_lock-AF_KCM" , - "sk_lock-AF_MAX" -}; -static const char *const af_family_slock_key_strings[AF_MAX+1] = { - "slock-AF_UNSPEC", "slock-AF_UNIX" , "slock-AF_INET" , - "slock-AF_AX25" , "slock-AF_IPX" , "slock-AF_APPLETALK", - "slock-AF_NETROM", "slock-AF_BRIDGE" , "slock-AF_ATMPVC" , - "slock-AF_X25" , "slock-AF_INET6" , "slock-AF_ROSE" , - "slock-AF_DECnet", "slock-AF_NETBEUI" , "slock-AF_SECURITY" , - "slock-AF_KEY" , "slock-AF_NETLINK" , "slock-AF_PACKET" , - "slock-AF_ASH" , "slock-AF_ECONET" , "slock-AF_ATMSVC" , - "slock-AF_RDS" , "slock-AF_SNA" , "slock-AF_IRDA" , - "slock-AF_PPPOX" , "slock-AF_WANPIPE" , "slock-AF_LLC" , - "slock-27" , "slock-28" , "slock-AF_CAN" , - "slock-AF_TIPC" , "slock-AF_BLUETOOTH", "slock-AF_IUCV" , - "slock-AF_RXRPC" , "slock-AF_ISDN" , "slock-AF_PHONET" , - "slock-AF_IEEE802154", "slock-AF_CAIF" , "slock-AF_ALG" , - "slock-AF_NFC" , "slock-AF_VSOCK" ,"slock-AF_KCM" , - "slock-AF_MAX" -}; -static const char *const af_family_clock_key_strings[AF_MAX+1] = { - "clock-AF_UNSPEC", "clock-AF_UNIX" , "clock-AF_INET" , - "clock-AF_AX25" , "clock-AF_IPX" , "clock-AF_APPLETALK", - "clock-AF_NETROM", "clock-AF_BRIDGE" , "clock-AF_ATMPVC" , - "clock-AF_X25" , "clock-AF_INET6" , "clock-AF_ROSE" , - "clock-AF_DECnet", "clock-AF_NETBEUI" , "clock-AF_SECURITY" , - "clock-AF_KEY" , "clock-AF_NETLINK" , "clock-AF_PACKET" , - "clock-AF_ASH" , "clock-AF_ECONET" , "clock-AF_ATMSVC" , - "clock-AF_RDS" , "clock-AF_SNA" , "clock-AF_IRDA" , - "clock-AF_PPPOX" , "clock-AF_WANPIPE" , "clock-AF_LLC" , - "clock-27" , "clock-28" , "clock-AF_CAN" , - "clock-AF_TIPC" , "clock-AF_BLUETOOTH", "clock-AF_IUCV" , - "clock-AF_RXRPC" , "clock-AF_ISDN" , "clock-AF_PHONET" , - "clock-AF_IEEE802154", "clock-AF_CAIF" , "clock-AF_ALG" , - "clock-AF_NFC" , "clock-AF_VSOCK" , "clock-AF_KCM" , - "clock-AF_MAX" -}; - -/* - * sk_callback_lock locking rules are per-address-family, - * so split the lock classes by using a per-AF key: - */ -static struct lock_class_key af_callback_keys[AF_MAX]; - -/* Take into consideration the size of the struct sk_buff overhead in the - * determination of these values, since that is non-constant across - * platforms. This makes socket queueing behavior and performance - * not depend upon such differences. - */ -#define _SK_MEM_PACKETS 256 -#define _SK_MEM_OVERHEAD SKB_TRUESIZE(256) -#define SK_WMEM_MAX (_SK_MEM_OVERHEAD * _SK_MEM_PACKETS) -#define SK_RMEM_MAX (_SK_MEM_OVERHEAD * _SK_MEM_PACKETS) - -/* Run time adjustable parameters. */ -__u32 sysctl_wmem_max __read_mostly = SK_WMEM_MAX; -EXPORT_SYMBOL(sysctl_wmem_max); -__u32 sysctl_rmem_max __read_mostly = SK_RMEM_MAX; -EXPORT_SYMBOL(sysctl_rmem_max); -__u32 sysctl_wmem_default __read_mostly = SK_WMEM_MAX; -__u32 sysctl_rmem_default __read_mostly = SK_RMEM_MAX; - -/* Maximal space eaten by iovec or ancillary data plus some space */ -int sysctl_optmem_max __read_mostly = sizeof(unsigned long)*(2*UIO_MAXIOV+512); -EXPORT_SYMBOL(sysctl_optmem_max); - -int sysctl_tstamp_allow_data __read_mostly = 1; - -struct static_key memalloc_socks = STATIC_KEY_INIT_FALSE; -EXPORT_SYMBOL_GPL(memalloc_socks); - -/** - * sk_set_memalloc - sets %SOCK_MEMALLOC - * @sk: socket to set it on - * - * Set %SOCK_MEMALLOC on a socket for access to emergency reserves. - * It's the responsibility of the admin to adjust min_free_kbytes - * to meet the requirements - */ -void sk_set_memalloc(struct sock *sk) -{ - sock_set_flag(sk, SOCK_MEMALLOC); - sk->sk_allocation |= __GFP_MEMALLOC; - static_key_slow_inc(&memalloc_socks); -} -EXPORT_SYMBOL_GPL(sk_set_memalloc); - -void sk_clear_memalloc(struct sock *sk) -{ - sock_reset_flag(sk, SOCK_MEMALLOC); - sk->sk_allocation &= ~__GFP_MEMALLOC; - static_key_slow_dec(&memalloc_socks); - - /* - * SOCK_MEMALLOC is allowed to ignore rmem limits to ensure forward - * progress of swapping. SOCK_MEMALLOC may be cleared while - * it has rmem allocations due to the last swapfile being deactivated - * but there is a risk that the socket is unusable due to exceeding - * the rmem limits. Reclaim the reserves and obey rmem limits again. - */ - sk_mem_reclaim(sk); -} -EXPORT_SYMBOL_GPL(sk_clear_memalloc); - -int __sk_backlog_rcv(struct sock *sk, struct sk_buff *skb) -{ - int ret; - unsigned long pflags = current->flags; - - /* these should have been dropped before queueing */ - BUG_ON(!sock_flag(sk, SOCK_MEMALLOC)); - - current->flags |= PF_MEMALLOC; - ret = sk->sk_backlog_rcv(sk, skb); - tsk_restore_flags(current, pflags, PF_MEMALLOC); - - return ret; -} -EXPORT_SYMBOL(__sk_backlog_rcv); - -static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen) -{ - struct timeval tv; - - if (optlen < sizeof(tv)) - return -EINVAL; - if (copy_from_user(&tv, optval, sizeof(tv))) - return -EFAULT; - if (tv.tv_usec < 0 || tv.tv_usec >= USEC_PER_SEC) - return -EDOM; - - if (tv.tv_sec < 0) { - static int warned __read_mostly; - - *timeo_p = 0; - if (warned < 10 && net_ratelimit()) { - warned++; - pr_info("%s: `%s' (pid %d) tries to set negative timeout\n", - __func__, current->comm, task_pid_nr(current)); - } - return 0; - } - *timeo_p = MAX_SCHEDULE_TIMEOUT; - if (tv.tv_sec == 0 && tv.tv_usec == 0) - return 0; - if (tv.tv_sec < (MAX_SCHEDULE_TIMEOUT/HZ - 1)) - *timeo_p = tv.tv_sec*HZ + (tv.tv_usec+(1000000/HZ-1))/(1000000/HZ); - return 0; -} - -static void sock_warn_obsolete_bsdism(const char *name) -{ - static int warned; - static char warncomm[TASK_COMM_LEN]; - if (strcmp(warncomm, current->comm) && warned < 5) { - strcpy(warncomm, current->comm); - pr_warn("process `%s' is using obsolete %s SO_BSDCOMPAT\n", - warncomm, name); - warned++; - } -} - -static bool sock_needs_netstamp(const struct sock *sk) -{ - switch (sk->sk_family) { - case AF_UNSPEC: - case AF_UNIX: - return false; - default: - return true; - } -} - -static void sock_disable_timestamp(struct sock *sk, unsigned long flags) -{ - if (sk->sk_flags & flags) { - sk->sk_flags &= ~flags; - if (sock_needs_netstamp(sk) && - !(sk->sk_flags & SK_FLAGS_TIMESTAMP)) - net_disable_timestamp(); - } -} - - -int __sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) -{ - unsigned long flags; - struct sk_buff_head *list = &sk->sk_receive_queue; - - if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) { - atomic_inc(&sk->sk_drops); - trace_sock_rcvqueue_full(sk, skb); - return -ENOMEM; - } - - if (!sk_rmem_schedule(sk, skb, skb->truesize)) { - atomic_inc(&sk->sk_drops); - return -ENOBUFS; - } - - skb->dev = NULL; - skb_set_owner_r(skb, sk); - - /* we escape from rcu protected region, make sure we dont leak - * a norefcounted dst - */ - skb_dst_force(skb); - - spin_lock_irqsave(&list->lock, flags); - sock_skb_set_dropcount(sk, skb); - __skb_queue_tail(list, skb); - spin_unlock_irqrestore(&list->lock, flags); - - if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_data_ready(sk); - return 0; -} -EXPORT_SYMBOL(__sock_queue_rcv_skb); - -int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) -{ - int err; - - err = sk_filter(sk, skb); - if (err) - return err; - - return __sock_queue_rcv_skb(sk, skb); -} -EXPORT_SYMBOL(sock_queue_rcv_skb); - -int __sk_receive_skb(struct sock *sk, struct sk_buff *skb, - const int nested, unsigned int trim_cap, bool refcounted) -{ - int rc = NET_RX_SUCCESS; - - if (sk_filter_trim_cap(sk, skb, trim_cap)) - goto discard_and_relse; - - skb->dev = NULL; - - if (sk_rcvqueues_full(sk, sk->sk_rcvbuf)) { - atomic_inc(&sk->sk_drops); - goto discard_and_relse; - } - if (nested) - bh_lock_sock_nested(sk); - else - bh_lock_sock(sk); - if (!sock_owned_by_user(sk)) { - /* - * trylock + unlock semantics: - */ - mutex_acquire(&sk->sk_lock.dep_map, 0, 1, _RET_IP_); - - rc = sk_backlog_rcv(sk, skb); - - mutex_release(&sk->sk_lock.dep_map, 1, _RET_IP_); - } else if (sk_add_backlog(sk, skb, sk->sk_rcvbuf)) { - bh_unlock_sock(sk); - atomic_inc(&sk->sk_drops); - goto discard_and_relse; - } - - bh_unlock_sock(sk); -out: - if (refcounted) - sock_put(sk); - return rc; -discard_and_relse: - kfree_skb(skb); - goto out; -} -EXPORT_SYMBOL(__sk_receive_skb); - -struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie) -{ - struct dst_entry *dst = __sk_dst_get(sk); - - if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) { - sk_tx_queue_clear(sk); - RCU_INIT_POINTER(sk->sk_dst_cache, NULL); - dst_release(dst); - return NULL; - } - - return dst; -} -EXPORT_SYMBOL(__sk_dst_check); - -struct dst_entry *sk_dst_check(struct sock *sk, u32 cookie) -{ - struct dst_entry *dst = sk_dst_get(sk); - - if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) { - sk_dst_reset(sk); - dst_release(dst); - return NULL; - } - - return dst; -} -EXPORT_SYMBOL(sk_dst_check); - -static int sock_setbindtodevice(struct sock *sk, char __user *optval, - int optlen) -{ - int ret = -ENOPROTOOPT; -#ifdef CONFIG_NETDEVICES - struct net *net = sock_net(sk); - char devname[IFNAMSIZ]; - int index; - - /* Sorry... */ - ret = -EPERM; - if (!ns_capable(net->user_ns, CAP_NET_RAW)) - goto out; - - ret = -EINVAL; - if (optlen < 0) - goto out; - - /* Bind this socket to a particular device like "eth0", - * as specified in the passed interface name. If the - * name is "" or the option length is zero the socket - * is not bound. - */ - if (optlen > IFNAMSIZ - 1) - optlen = IFNAMSIZ - 1; - memset(devname, 0, sizeof(devname)); - - ret = -EFAULT; - if (copy_from_user(devname, optval, optlen)) - goto out; - - index = 0; - if (devname[0] != '\0') { - struct net_device *dev; - - rcu_read_lock(); - dev = dev_get_by_name_rcu(net, devname); - if (dev) - index = dev->ifindex; - rcu_read_unlock(); - ret = -ENODEV; - if (!dev) - goto out; - } - - lock_sock(sk); - sk->sk_bound_dev_if = index; - sk_dst_reset(sk); - release_sock(sk); - - ret = 0; - -out: -#endif - - return ret; -} - -static int sock_getbindtodevice(struct sock *sk, char __user *optval, - int __user *optlen, int len) -{ - int ret = -ENOPROTOOPT; -#ifdef CONFIG_NETDEVICES - struct net *net = sock_net(sk); - char devname[IFNAMSIZ]; - - if (sk->sk_bound_dev_if == 0) { - len = 0; - goto zero; - } - - ret = -EINVAL; - if (len < IFNAMSIZ) - goto out; - - ret = netdev_get_name(net, devname, sk->sk_bound_dev_if); - if (ret) - goto out; - - len = strlen(devname) + 1; - - ret = -EFAULT; - if (copy_to_user(optval, devname, len)) - goto out; - -zero: - ret = -EFAULT; - if (put_user(len, optlen)) - goto out; - - ret = 0; - -out: -#endif - - return ret; -} - -static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool) -{ - if (valbool) - sock_set_flag(sk, bit); - else - sock_reset_flag(sk, bit); -} - -bool sk_mc_loop(struct sock *sk) -{ - if (dev_recursion_level()) - return false; - if (!sk) - return true; - switch (sk->sk_family) { - case AF_INET: - return inet_sk(sk)->mc_loop; -#if IS_ENABLED(CONFIG_IPV6) - case AF_INET6: - return inet6_sk(sk)->mc_loop; -#endif - } - WARN_ON(1); - return true; -} -EXPORT_SYMBOL(sk_mc_loop); - -/* - * This is meant for all protocols to use and covers goings on - * at the socket level. Everything here is generic. - */ - -int sock_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, unsigned int optlen) -{ - struct sock *sk = sock->sk; - int val; - int valbool; - struct linger ling; - int ret = 0; - - /* - * Options without arguments - */ - - if (optname == SO_BINDTODEVICE) - return sock_setbindtodevice(sk, optval, optlen); - - if (optlen < sizeof(int)) - return -EINVAL; - - if (get_user(val, (int __user *)optval)) - return -EFAULT; - - valbool = val ? 1 : 0; - - lock_sock(sk); - - switch (optname) { - case SO_DEBUG: - if (val && !capable(CAP_NET_ADMIN)) - ret = -EACCES; - else - sock_valbool_flag(sk, SOCK_DBG, valbool); - break; - case SO_REUSEADDR: - sk->sk_reuse = (valbool ? SK_CAN_REUSE : SK_NO_REUSE); - break; - case SO_REUSEPORT: - sk->sk_reuseport = valbool; - break; - case SO_TYPE: - case SO_PROTOCOL: - case SO_DOMAIN: - case SO_ERROR: - ret = -ENOPROTOOPT; - break; - case SO_DONTROUTE: - sock_valbool_flag(sk, SOCK_LOCALROUTE, valbool); - break; - case SO_BROADCAST: - sock_valbool_flag(sk, SOCK_BROADCAST, valbool); - break; - case SO_SNDBUF: - /* Don't error on this BSD doesn't and if you think - * about it this is right. Otherwise apps have to - * play 'guess the biggest size' games. RCVBUF/SNDBUF - * are treated in BSD as hints - */ - val = min_t(u32, val, sysctl_wmem_max); -set_sndbuf: - sk->sk_userlocks |= SOCK_SNDBUF_LOCK; - sk->sk_sndbuf = max_t(int, val * 2, SOCK_MIN_SNDBUF); - /* Wake up sending tasks if we upped the value. */ - sk->sk_write_space(sk); - break; - - case SO_SNDBUFFORCE: - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } - goto set_sndbuf; - - case SO_RCVBUF: - /* Don't error on this BSD doesn't and if you think - * about it this is right. Otherwise apps have to - * play 'guess the biggest size' games. RCVBUF/SNDBUF - * are treated in BSD as hints - */ - val = min_t(u32, val, sysctl_rmem_max); -set_rcvbuf: - sk->sk_userlocks |= SOCK_RCVBUF_LOCK; - /* - * We double it on the way in to account for - * "struct sk_buff" etc. overhead. Applications - * assume that the SO_RCVBUF setting they make will - * allow that much actual data to be received on that - * socket. - * - * Applications are unaware that "struct sk_buff" and - * other overheads allocate from the receive buffer - * during socket buffer allocation. - * - * And after considering the possible alternatives, - * returning the value we actually used in getsockopt - * is the most desirable behavior. - */ - sk->sk_rcvbuf = max_t(int, val * 2, SOCK_MIN_RCVBUF); - break; - - case SO_RCVBUFFORCE: - if (!capable(CAP_NET_ADMIN)) { - ret = -EPERM; - break; - } - goto set_rcvbuf; - - case SO_KEEPALIVE: -#ifdef CONFIG_INET - if (sk->sk_protocol == IPPROTO_TCP && - sk->sk_type == SOCK_STREAM) - tcp_set_keepalive(sk, valbool); -#endif - sock_valbool_flag(sk, SOCK_KEEPOPEN, valbool); - break; - - case SO_OOBINLINE: - sock_valbool_flag(sk, SOCK_URGINLINE, valbool); - break; - - case SO_NO_CHECK: - sk->sk_no_check_tx = valbool; - break; - - case SO_PRIORITY: - if ((val >= 0 && val <= 6) || - ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) - sk->sk_priority = val; - else - ret = -EPERM; - break; - - case SO_LINGER: - if (optlen < sizeof(ling)) { - ret = -EINVAL; /* 1003.1g */ - break; - } - if (copy_from_user(&ling, optval, sizeof(ling))) { - ret = -EFAULT; - break; - } - if (!ling.l_onoff) - sock_reset_flag(sk, SOCK_LINGER); - else { -#if (BITS_PER_LONG == 32) - if ((unsigned int)ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ) - sk->sk_lingertime = MAX_SCHEDULE_TIMEOUT; - else -#endif - sk->sk_lingertime = (unsigned int)ling.l_linger * HZ; - sock_set_flag(sk, SOCK_LINGER); - } - break; - - case SO_BSDCOMPAT: - sock_warn_obsolete_bsdism("setsockopt"); - break; - - case SO_PASSCRED: - if (valbool) - set_bit(SOCK_PASSCRED, &sock->flags); - else - clear_bit(SOCK_PASSCRED, &sock->flags); - break; - - case SO_TIMESTAMP: - case SO_TIMESTAMPNS: - if (valbool) { - if (optname == SO_TIMESTAMP) - sock_reset_flag(sk, SOCK_RCVTSTAMPNS); - else - sock_set_flag(sk, SOCK_RCVTSTAMPNS); - sock_set_flag(sk, SOCK_RCVTSTAMP); - sock_enable_timestamp(sk, SOCK_TIMESTAMP); - } else { - sock_reset_flag(sk, SOCK_RCVTSTAMP); - sock_reset_flag(sk, SOCK_RCVTSTAMPNS); - } - break; - - case SO_TIMESTAMPING: - if (val & ~SOF_TIMESTAMPING_MASK) { - ret = -EINVAL; - break; - } - - if (val & SOF_TIMESTAMPING_OPT_ID && - !(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)) { - if (sk->sk_protocol == IPPROTO_TCP && - sk->sk_type == SOCK_STREAM) { - if ((1 << sk->sk_state) & - (TCPF_CLOSE | TCPF_LISTEN)) { - ret = -EINVAL; - break; - } - sk->sk_tskey = tcp_sk(sk)->snd_una; - } else { - sk->sk_tskey = 0; - } - } - sk->sk_tsflags = val; - if (val & SOF_TIMESTAMPING_RX_SOFTWARE) - sock_enable_timestamp(sk, - SOCK_TIMESTAMPING_RX_SOFTWARE); - else - sock_disable_timestamp(sk, - (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)); - break; - - case SO_RCVLOWAT: - if (val < 0) - val = INT_MAX; - sk->sk_rcvlowat = val ? : 1; - break; - - case SO_RCVTIMEO: - ret = sock_set_timeout(&sk->sk_rcvtimeo, optval, optlen); - break; - - case SO_SNDTIMEO: - ret = sock_set_timeout(&sk->sk_sndtimeo, optval, optlen); - break; - - case SO_ATTACH_FILTER: - ret = -EINVAL; - if (optlen == sizeof(struct sock_fprog)) { - struct sock_fprog fprog; - - ret = -EFAULT; - if (copy_from_user(&fprog, optval, sizeof(fprog))) - break; - - ret = sk_attach_filter(&fprog, sk); - } - break; - - case SO_ATTACH_BPF: - ret = -EINVAL; - if (optlen == sizeof(u32)) { - u32 ufd; - - ret = -EFAULT; - if (copy_from_user(&ufd, optval, sizeof(ufd))) - break; - - ret = sk_attach_bpf(ufd, sk); - } - break; - - case SO_ATTACH_REUSEPORT_CBPF: - ret = -EINVAL; - if (optlen == sizeof(struct sock_fprog)) { - struct sock_fprog fprog; - - ret = -EFAULT; - if (copy_from_user(&fprog, optval, sizeof(fprog))) - break; - - ret = sk_reuseport_attach_filter(&fprog, sk); - } - break; - - case SO_ATTACH_REUSEPORT_EBPF: - ret = -EINVAL; - if (optlen == sizeof(u32)) { - u32 ufd; - - ret = -EFAULT; - if (copy_from_user(&ufd, optval, sizeof(ufd))) - break; - - ret = sk_reuseport_attach_bpf(ufd, sk); - } - break; - - case SO_DETACH_FILTER: - ret = sk_detach_filter(sk); - break; - - case SO_LOCK_FILTER: - if (sock_flag(sk, SOCK_FILTER_LOCKED) && !valbool) - ret = -EPERM; - else - sock_valbool_flag(sk, SOCK_FILTER_LOCKED, valbool); - break; - - case SO_PASSSEC: - if (valbool) - set_bit(SOCK_PASSSEC, &sock->flags); - else - clear_bit(SOCK_PASSSEC, &sock->flags); - break; - case SO_MARK: - if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) - ret = -EPERM; - else - sk->sk_mark = val; - break; - - case SO_RXQ_OVFL: - sock_valbool_flag(sk, SOCK_RXQ_OVFL, valbool); - break; - - case SO_WIFI_STATUS: - sock_valbool_flag(sk, SOCK_WIFI_STATUS, valbool); - break; - - case SO_PEEK_OFF: - if (sock->ops->set_peek_off) - ret = sock->ops->set_peek_off(sk, val); - else - ret = -EOPNOTSUPP; - break; - - case SO_NOFCS: - sock_valbool_flag(sk, SOCK_NOFCS, valbool); - break; - - case SO_SELECT_ERR_QUEUE: - sock_valbool_flag(sk, SOCK_SELECT_ERR_QUEUE, valbool); - break; - -#ifdef CONFIG_NET_RX_BUSY_POLL - case SO_BUSY_POLL: - /* allow unprivileged users to decrease the value */ - if ((val > sk->sk_ll_usec) && !capable(CAP_NET_ADMIN)) - ret = -EPERM; - else { - if (val < 0) - ret = -EINVAL; - else - sk->sk_ll_usec = val; - } - break; -#endif - - case SO_MAX_PACING_RATE: - sk->sk_max_pacing_rate = val; - sk->sk_pacing_rate = min(sk->sk_pacing_rate, - sk->sk_max_pacing_rate); - break; - - case SO_INCOMING_CPU: - sk->sk_incoming_cpu = val; - break; - - case SO_CNX_ADVICE: - if (val == 1) - dst_negative_advice(sk); - break; - default: - ret = -ENOPROTOOPT; - break; - } - release_sock(sk); - return ret; -} -EXPORT_SYMBOL(sock_setsockopt); - - -static void cred_to_ucred(struct pid *pid, const struct cred *cred, - struct ucred *ucred) -{ - ucred->pid = pid_vnr(pid); - ucred->uid = ucred->gid = -1; - if (cred) { - struct user_namespace *current_ns = current_user_ns(); - - ucred->uid = from_kuid_munged(current_ns, cred->euid); - ucred->gid = from_kgid_munged(current_ns, cred->egid); - } -} - -int sock_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) -{ - struct sock *sk = sock->sk; - - union { - int val; - struct linger ling; - struct timeval tm; - } v; - - int lv = sizeof(int); - int len; - - if (get_user(len, optlen)) - return -EFAULT; - if (len < 0) - return -EINVAL; - - memset(&v, 0, sizeof(v)); - - switch (optname) { - case SO_DEBUG: - v.val = sock_flag(sk, SOCK_DBG); - break; - - case SO_DONTROUTE: - v.val = sock_flag(sk, SOCK_LOCALROUTE); - break; - - case SO_BROADCAST: - v.val = sock_flag(sk, SOCK_BROADCAST); - break; - - case SO_SNDBUF: - v.val = sk->sk_sndbuf; - break; - - case SO_RCVBUF: - v.val = sk->sk_rcvbuf; - break; - - case SO_REUSEADDR: - v.val = sk->sk_reuse; - break; - - case SO_REUSEPORT: - v.val = sk->sk_reuseport; - break; - - case SO_KEEPALIVE: - v.val = sock_flag(sk, SOCK_KEEPOPEN); - break; - - case SO_TYPE: - v.val = sk->sk_type; - break; - - case SO_PROTOCOL: - v.val = sk->sk_protocol; - break; - - case SO_DOMAIN: - v.val = sk->sk_family; - break; - - case SO_ERROR: - v.val = -sock_error(sk); - if (v.val == 0) - v.val = xchg(&sk->sk_err_soft, 0); - break; - - case SO_OOBINLINE: - v.val = sock_flag(sk, SOCK_URGINLINE); - break; - - case SO_NO_CHECK: - v.val = sk->sk_no_check_tx; - break; - - case SO_PRIORITY: - v.val = sk->sk_priority; - break; - - case SO_LINGER: - lv = sizeof(v.ling); - v.ling.l_onoff = sock_flag(sk, SOCK_LINGER); - v.ling.l_linger = sk->sk_lingertime / HZ; - break; - - case SO_BSDCOMPAT: - sock_warn_obsolete_bsdism("getsockopt"); - break; - - case SO_TIMESTAMP: - v.val = sock_flag(sk, SOCK_RCVTSTAMP) && - !sock_flag(sk, SOCK_RCVTSTAMPNS); - break; - - case SO_TIMESTAMPNS: - v.val = sock_flag(sk, SOCK_RCVTSTAMPNS); - break; - - case SO_TIMESTAMPING: - v.val = sk->sk_tsflags; - break; - - case SO_RCVTIMEO: - lv = sizeof(struct timeval); - if (sk->sk_rcvtimeo == MAX_SCHEDULE_TIMEOUT) { - v.tm.tv_sec = 0; - v.tm.tv_usec = 0; - } else { - v.tm.tv_sec = sk->sk_rcvtimeo / HZ; - v.tm.tv_usec = ((sk->sk_rcvtimeo % HZ) * 1000000) / HZ; - } - break; - - case SO_SNDTIMEO: - lv = sizeof(struct timeval); - if (sk->sk_sndtimeo == MAX_SCHEDULE_TIMEOUT) { - v.tm.tv_sec = 0; - v.tm.tv_usec = 0; - } else { - v.tm.tv_sec = sk->sk_sndtimeo / HZ; - v.tm.tv_usec = ((sk->sk_sndtimeo % HZ) * 1000000) / HZ; - } - break; - - case SO_RCVLOWAT: - v.val = sk->sk_rcvlowat; - break; - - case SO_SNDLOWAT: - v.val = 1; - break; - - case SO_PASSCRED: - v.val = !!test_bit(SOCK_PASSCRED, &sock->flags); - break; - - case SO_PEERCRED: - { - struct ucred peercred; - if (len > sizeof(peercred)) - len = sizeof(peercred); - cred_to_ucred(sk->sk_peer_pid, sk->sk_peer_cred, &peercred); - if (copy_to_user(optval, &peercred, len)) - return -EFAULT; - goto lenout; - } - - case SO_PEERNAME: - { - char address[128]; - - if (sock->ops->getname(sock, (struct sockaddr *)address, &lv, 2)) - return -ENOTCONN; - if (lv < len) - return -EINVAL; - if (copy_to_user(optval, address, len)) - return -EFAULT; - goto lenout; - } - - /* Dubious BSD thing... Probably nobody even uses it, but - * the UNIX standard wants it for whatever reason... -DaveM - */ - case SO_ACCEPTCONN: - v.val = sk->sk_state == TCP_LISTEN; - break; - - case SO_PASSSEC: - v.val = !!test_bit(SOCK_PASSSEC, &sock->flags); - break; - - case SO_PEERSEC: - return security_socket_getpeersec_stream(sock, optval, optlen, len); - - case SO_MARK: - v.val = sk->sk_mark; - break; - - case SO_RXQ_OVFL: - v.val = sock_flag(sk, SOCK_RXQ_OVFL); - break; - - case SO_WIFI_STATUS: - v.val = sock_flag(sk, SOCK_WIFI_STATUS); - break; - - case SO_PEEK_OFF: - if (!sock->ops->set_peek_off) - return -EOPNOTSUPP; - - v.val = sk->sk_peek_off; - break; - case SO_NOFCS: - v.val = sock_flag(sk, SOCK_NOFCS); - break; - - case SO_BINDTODEVICE: - return sock_getbindtodevice(sk, optval, optlen, len); - - case SO_GET_FILTER: - len = sk_get_filter(sk, (struct sock_filter __user *)optval, len); - if (len < 0) - return len; - - goto lenout; - - case SO_LOCK_FILTER: - v.val = sock_flag(sk, SOCK_FILTER_LOCKED); - break; - - case SO_BPF_EXTENSIONS: - v.val = bpf_tell_extensions(); - break; - - case SO_SELECT_ERR_QUEUE: - v.val = sock_flag(sk, SOCK_SELECT_ERR_QUEUE); - break; - -#ifdef CONFIG_NET_RX_BUSY_POLL - case SO_BUSY_POLL: - v.val = sk->sk_ll_usec; - break; -#endif - - case SO_MAX_PACING_RATE: - v.val = sk->sk_max_pacing_rate; - break; - - case SO_INCOMING_CPU: - v.val = sk->sk_incoming_cpu; - break; - - default: - /* We implement the SO_SNDLOWAT etc to not be settable - * (1003.1g 7). - */ - return -ENOPROTOOPT; - } - - if (len > lv) - len = lv; - if (copy_to_user(optval, &v, len)) - return -EFAULT; -lenout: - if (put_user(len, optlen)) - return -EFAULT; - return 0; -} - -/* - * Initialize an sk_lock. - * - * (We also register the sk_lock with the lock validator.) - */ -static inline void sock_lock_init(struct sock *sk) -{ - sock_lock_init_class_and_name(sk, - af_family_slock_key_strings[sk->sk_family], - af_family_slock_keys + sk->sk_family, - af_family_key_strings[sk->sk_family], - af_family_keys + sk->sk_family); -} - -/* - * Copy all fields from osk to nsk but nsk->sk_refcnt must not change yet, - * even temporarly, because of RCU lookups. sk_node should also be left as is. - * We must not copy fields between sk_dontcopy_begin and sk_dontcopy_end - */ -static void sock_copy(struct sock *nsk, const struct sock *osk) -{ -#ifdef CONFIG_SECURITY_NETWORK - void *sptr = nsk->sk_security; -#endif - memcpy(nsk, osk, offsetof(struct sock, sk_dontcopy_begin)); - - memcpy(&nsk->sk_dontcopy_end, &osk->sk_dontcopy_end, - osk->sk_prot->obj_size - offsetof(struct sock, sk_dontcopy_end)); - -#ifdef CONFIG_SECURITY_NETWORK - nsk->sk_security = sptr; - security_sk_clone(osk, nsk); -#endif -} - -static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority, - int family) -{ - struct sock *sk; - struct kmem_cache *slab; - - slab = prot->slab; - if (slab != NULL) { - sk = kmem_cache_alloc(slab, priority & ~__GFP_ZERO); - if (!sk) - return sk; - if (priority & __GFP_ZERO) - sk_prot_clear_nulls(sk, prot->obj_size); - } else - sk = kmalloc(prot->obj_size, priority); - - if (sk != NULL) { - kmemcheck_annotate_bitfield(sk, flags); - - if (security_sk_alloc(sk, family, priority)) - goto out_free; - - if (!try_module_get(prot->owner)) - goto out_free_sec; - sk_tx_queue_clear(sk); - } - - return sk; - -out_free_sec: - security_sk_free(sk); -out_free: - if (slab != NULL) - kmem_cache_free(slab, sk); - else - kfree(sk); - return NULL; -} - -static void sk_prot_free(struct proto *prot, struct sock *sk) -{ - struct kmem_cache *slab; - struct module *owner; - - owner = prot->owner; - slab = prot->slab; - - cgroup_sk_free(&sk->sk_cgrp_data); - mem_cgroup_sk_free(sk); - security_sk_free(sk); - if (slab != NULL) - kmem_cache_free(slab, sk); - else - kfree(sk); - module_put(owner); -} - -/** - * sk_alloc - All socket objects are allocated here - * @net: the applicable net namespace - * @family: protocol family - * @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc) - * @prot: struct proto associated with this new sock instance - * @kern: is this to be a kernel socket? - */ -struct sock *sk_alloc(struct net *net, int family, gfp_t priority, - struct proto *prot, int kern) -{ - struct sock *sk; - - sk = sk_prot_alloc(prot, priority | __GFP_ZERO, family); - if (sk) { - sk->sk_family = family; - /* - * See comment in struct sock definition to understand - * why we need sk_prot_creator -acme - */ - sk->sk_prot = sk->sk_prot_creator = prot; - sock_lock_init(sk); - sk->sk_net_refcnt = kern ? 0 : 1; - if (likely(sk->sk_net_refcnt)) - get_net(net); - sock_net_set(sk, net); - atomic_set(&sk->sk_wmem_alloc, 1); - - mem_cgroup_sk_alloc(sk); - cgroup_sk_alloc(&sk->sk_cgrp_data); - sock_update_classid(&sk->sk_cgrp_data); - sock_update_netprioidx(&sk->sk_cgrp_data); - } - - return sk; -} -EXPORT_SYMBOL(sk_alloc); - -/* Sockets having SOCK_RCU_FREE will call this function after one RCU - * grace period. This is the case for UDP sockets and TCP listeners. - */ -static void __sk_destruct(struct rcu_head *head) -{ - struct sock *sk = container_of(head, struct sock, sk_rcu); - struct sk_filter *filter; - - if (sk->sk_destruct) - sk->sk_destruct(sk); - - filter = rcu_dereference_check(sk->sk_filter, - atomic_read(&sk->sk_wmem_alloc) == 0); - if (filter) { - sk_filter_uncharge(sk, filter); - RCU_INIT_POINTER(sk->sk_filter, NULL); - } - if (rcu_access_pointer(sk->sk_reuseport_cb)) - reuseport_detach_sock(sk); - - sock_disable_timestamp(sk, SK_FLAGS_TIMESTAMP); - - if (atomic_read(&sk->sk_omem_alloc)) - pr_debug("%s: optmem leakage (%d bytes) detected\n", - __func__, atomic_read(&sk->sk_omem_alloc)); - - if (sk->sk_peer_cred) - put_cred(sk->sk_peer_cred); - put_pid(sk->sk_peer_pid); - if (likely(sk->sk_net_refcnt)) - put_net(sock_net(sk)); - sk_prot_free(sk->sk_prot_creator, sk); -} - -void sk_destruct(struct sock *sk) -{ - if (sock_flag(sk, SOCK_RCU_FREE)) - call_rcu(&sk->sk_rcu, __sk_destruct); - else - __sk_destruct(&sk->sk_rcu); -} - -static void __sk_free(struct sock *sk) -{ - if (unlikely(sock_diag_has_destroy_listeners(sk) && sk->sk_net_refcnt)) - sock_diag_broadcast_destroy(sk); - else - sk_destruct(sk); -} - -void sk_free(struct sock *sk) -{ - /* - * We subtract one from sk_wmem_alloc and can know if - * some packets are still in some tx queue. - * If not null, sock_wfree() will call __sk_free(sk) later - */ - if (atomic_dec_and_test(&sk->sk_wmem_alloc)) - __sk_free(sk); -} -EXPORT_SYMBOL(sk_free); - -/** - * sk_clone_lock - clone a socket, and lock its clone - * @sk: the socket to clone - * @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc) - * - * Caller must unlock socket even in error path (bh_unlock_sock(newsk)) - */ -struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority) -{ - struct sock *newsk; - bool is_charged = true; - - newsk = sk_prot_alloc(sk->sk_prot, priority, sk->sk_family); - if (newsk != NULL) { - struct sk_filter *filter; - - sock_copy(newsk, sk); - - /* SANITY */ - if (likely(newsk->sk_net_refcnt)) - get_net(sock_net(newsk)); - sk_node_init(&newsk->sk_node); - sock_lock_init(newsk); - bh_lock_sock(newsk); - newsk->sk_backlog.head = newsk->sk_backlog.tail = NULL; - newsk->sk_backlog.len = 0; - - atomic_set(&newsk->sk_rmem_alloc, 0); - /* - * sk_wmem_alloc set to one (see sk_free() and sock_wfree()) - */ - atomic_set(&newsk->sk_wmem_alloc, 1); - atomic_set(&newsk->sk_omem_alloc, 0); - skb_queue_head_init(&newsk->sk_receive_queue); - skb_queue_head_init(&newsk->sk_write_queue); - - rwlock_init(&newsk->sk_callback_lock); - lockdep_set_class_and_name(&newsk->sk_callback_lock, - af_callback_keys + newsk->sk_family, - af_family_clock_key_strings[newsk->sk_family]); - - newsk->sk_dst_cache = NULL; - newsk->sk_wmem_queued = 0; - newsk->sk_forward_alloc = 0; - atomic_set(&newsk->sk_drops, 0); - newsk->sk_send_head = NULL; - newsk->sk_userlocks = sk->sk_userlocks & ~SOCK_BINDPORT_LOCK; - - sock_reset_flag(newsk, SOCK_DONE); - skb_queue_head_init(&newsk->sk_error_queue); - - filter = rcu_dereference_protected(newsk->sk_filter, 1); - if (filter != NULL) - /* though it's an empty new sock, the charging may fail - * if sysctl_optmem_max was changed between creation of - * original socket and cloning - */ - is_charged = sk_filter_charge(newsk, filter); - - if (unlikely(!is_charged || xfrm_sk_clone_policy(newsk, sk))) { - /* It is still raw copy of parent, so invalidate - * destructor and make plain sk_free() */ - newsk->sk_destruct = NULL; - bh_unlock_sock(newsk); - sk_free(newsk); - newsk = NULL; - goto out; - } - RCU_INIT_POINTER(newsk->sk_reuseport_cb, NULL); - - newsk->sk_err = 0; - newsk->sk_err_soft = 0; - newsk->sk_priority = 0; - newsk->sk_incoming_cpu = raw_smp_processor_id(); - atomic64_set(&newsk->sk_cookie, 0); - - mem_cgroup_sk_alloc(newsk); - cgroup_sk_alloc(&newsk->sk_cgrp_data); - - /* - * Before updating sk_refcnt, we must commit prior changes to memory - * (Documentation/RCU/rculist_nulls.txt for details) - */ - smp_wmb(); - atomic_set(&newsk->sk_refcnt, 2); - - /* - * Increment the counter in the same struct proto as the master - * sock (sk_refcnt_debug_inc uses newsk->sk_prot->socks, that - * is the same as sk->sk_prot->socks, as this field was copied - * with memcpy). - * - * This _changes_ the previous behaviour, where - * tcp_create_openreq_child always was incrementing the - * equivalent to tcp_prot->socks (inet_sock_nr), so this have - * to be taken into account in all callers. -acme - */ - sk_refcnt_debug_inc(newsk); - sk_set_socket(newsk, NULL); - newsk->sk_wq = NULL; - - if (newsk->sk_prot->sockets_allocated) - sk_sockets_allocated_inc(newsk); - - if (sock_needs_netstamp(sk) && - newsk->sk_flags & SK_FLAGS_TIMESTAMP) - net_enable_timestamp(); - } -out: - return newsk; -} -EXPORT_SYMBOL_GPL(sk_clone_lock); - -void sk_setup_caps(struct sock *sk, struct dst_entry *dst) -{ - u32 max_segs = 1; - - sk_dst_set(sk, dst); - sk->sk_route_caps = dst->dev->features; - if (sk->sk_route_caps & NETIF_F_GSO) - sk->sk_route_caps |= NETIF_F_GSO_SOFTWARE; - sk->sk_route_caps &= ~sk->sk_route_nocaps; - if (sk_can_gso(sk)) { - if (dst->header_len) { - sk->sk_route_caps &= ~NETIF_F_GSO_MASK; - } else { - sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM; - sk->sk_gso_max_size = dst->dev->gso_max_size; - max_segs = max_t(u32, dst->dev->gso_max_segs, 1); - } - } - sk->sk_gso_max_segs = max_segs; -} -EXPORT_SYMBOL_GPL(sk_setup_caps); - -/* - * Simple resource managers for sockets. - */ - - -/* - * Write buffer destructor automatically called from kfree_skb. - */ -void sock_wfree(struct sk_buff *skb) -{ - struct sock *sk = skb->sk; - unsigned int len = skb->truesize; - - if (!sock_flag(sk, SOCK_USE_WRITE_QUEUE)) { - /* - * Keep a reference on sk_wmem_alloc, this will be released - * after sk_write_space() call - */ - atomic_sub(len - 1, &sk->sk_wmem_alloc); - sk->sk_write_space(sk); - len = 1; - } - /* - * if sk_wmem_alloc reaches 0, we must finish what sk_free() - * could not do because of in-flight packets - */ - if (atomic_sub_and_test(len, &sk->sk_wmem_alloc)) - __sk_free(sk); -} -EXPORT_SYMBOL(sock_wfree); - -/* This variant of sock_wfree() is used by TCP, - * since it sets SOCK_USE_WRITE_QUEUE. - */ -void __sock_wfree(struct sk_buff *skb) -{ - struct sock *sk = skb->sk; - - if (atomic_sub_and_test(skb->truesize, &sk->sk_wmem_alloc)) - __sk_free(sk); -} - -void skb_set_owner_w(struct sk_buff *skb, struct sock *sk) -{ - skb_orphan(skb); - skb->sk = sk; -#ifdef CONFIG_INET - if (unlikely(!sk_fullsock(sk))) { - skb->destructor = sock_edemux; - sock_hold(sk); - return; - } -#endif - skb->destructor = sock_wfree; - skb_set_hash_from_sk(skb, sk); - /* - * We used to take a refcount on sk, but following operation - * is enough to guarantee sk_free() wont free this sock until - * all in-flight packets are completed - */ - atomic_add(skb->truesize, &sk->sk_wmem_alloc); -} -EXPORT_SYMBOL(skb_set_owner_w); - -/* This helper is used by netem, as it can hold packets in its - * delay queue. We want to allow the owner socket to send more - * packets, as if they were already TX completed by a typical driver. - * But we also want to keep skb->sk set because some packet schedulers - * rely on it (sch_fq for example). So we set skb->truesize to a small - * amount (1) and decrease sk_wmem_alloc accordingly. - */ -void skb_orphan_partial(struct sk_buff *skb) -{ - /* If this skb is a TCP pure ACK or already went here, - * we have nothing to do. 2 is already a very small truesize. - */ - if (skb->truesize <= 2) - return; - - /* TCP stack sets skb->ooo_okay based on sk_wmem_alloc, - * so we do not completely orphan skb, but transfert all - * accounted bytes but one, to avoid unexpected reorders. - */ - if (skb->destructor == sock_wfree -#ifdef CONFIG_INET - || skb->destructor == tcp_wfree -#endif - ) { - atomic_sub(skb->truesize - 1, &skb->sk->sk_wmem_alloc); - skb->truesize = 1; - } else { - skb_orphan(skb); - } -} -EXPORT_SYMBOL(skb_orphan_partial); - -/* - * Read buffer destructor automatically called from kfree_skb. - */ -void sock_rfree(struct sk_buff *skb) -{ - struct sock *sk = skb->sk; - unsigned int len = skb->truesize; - - atomic_sub(len, &sk->sk_rmem_alloc); - sk_mem_uncharge(sk, len); -} -EXPORT_SYMBOL(sock_rfree); - -/* - * Buffer destructor for skbs that are not used directly in read or write - * path, e.g. for error handler skbs. Automatically called from kfree_skb. - */ -void sock_efree(struct sk_buff *skb) -{ - sock_put(skb->sk); -} -EXPORT_SYMBOL(sock_efree); - -kuid_t sock_i_uid(struct sock *sk) -{ - kuid_t uid; - - read_lock_bh(&sk->sk_callback_lock); - uid = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : GLOBAL_ROOT_UID; - read_unlock_bh(&sk->sk_callback_lock); - return uid; -} -EXPORT_SYMBOL(sock_i_uid); - -unsigned long sock_i_ino(struct sock *sk) -{ - unsigned long ino; - - read_lock_bh(&sk->sk_callback_lock); - ino = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_ino : 0; - read_unlock_bh(&sk->sk_callback_lock); - return ino; -} -EXPORT_SYMBOL(sock_i_ino); - -/* - * Allocate a skb from the socket's send buffer. - */ -struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, - gfp_t priority) -{ - if (force || atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) { - struct sk_buff *skb = alloc_skb(size, priority); - if (skb) { - skb_set_owner_w(skb, sk); - return skb; - } - } - return NULL; -} -EXPORT_SYMBOL(sock_wmalloc); - -/* - * Allocate a memory block from the socket's option memory buffer. - */ -void *sock_kmalloc(struct sock *sk, int size, gfp_t priority) -{ - if ((unsigned int)size <= sysctl_optmem_max && - atomic_read(&sk->sk_omem_alloc) + size < sysctl_optmem_max) { - void *mem; - /* First do the add, to avoid the race if kmalloc - * might sleep. - */ - atomic_add(size, &sk->sk_omem_alloc); - mem = kmalloc(size, priority); - if (mem) - return mem; - atomic_sub(size, &sk->sk_omem_alloc); - } - return NULL; -} -EXPORT_SYMBOL(sock_kmalloc); - -/* Free an option memory block. Note, we actually want the inline - * here as this allows gcc to detect the nullify and fold away the - * condition entirely. - */ -static inline void __sock_kfree_s(struct sock *sk, void *mem, int size, - const bool nullify) -{ - if (WARN_ON_ONCE(!mem)) - return; - if (nullify) - kzfree(mem); - else - kfree(mem); - atomic_sub(size, &sk->sk_omem_alloc); -} - -void sock_kfree_s(struct sock *sk, void *mem, int size) -{ - __sock_kfree_s(sk, mem, size, false); -} -EXPORT_SYMBOL(sock_kfree_s); - -void sock_kzfree_s(struct sock *sk, void *mem, int size) -{ - __sock_kfree_s(sk, mem, size, true); -} -EXPORT_SYMBOL(sock_kzfree_s); - -/* It is almost wait_for_tcp_memory minus release_sock/lock_sock. - I think, these locks should be removed for datagram sockets. - */ -static long sock_wait_for_wmem(struct sock *sk, long timeo) -{ - DEFINE_WAIT(wait); - - sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); - for (;;) { - if (!timeo) - break; - if (signal_pending(current)) - break; - set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); - prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) - break; - if (sk->sk_shutdown & SEND_SHUTDOWN) - break; - if (sk->sk_err) - break; - timeo = schedule_timeout(timeo); - } - finish_wait(sk_sleep(sk), &wait); - return timeo; -} - - -/* - * Generic send/receive buffer handlers - */ - -struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len, - unsigned long data_len, int noblock, - int *errcode, int max_page_order) -{ - struct sk_buff *skb; - long timeo; - int err; - - timeo = sock_sndtimeo(sk, noblock); - for (;;) { - err = sock_error(sk); - if (err != 0) - goto failure; - - err = -EPIPE; - if (sk->sk_shutdown & SEND_SHUTDOWN) - goto failure; - - if (sk_wmem_alloc_get(sk) < sk->sk_sndbuf) - break; - - sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); - set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); - err = -EAGAIN; - if (!timeo) - goto failure; - if (signal_pending(current)) - goto interrupted; - timeo = sock_wait_for_wmem(sk, timeo); - } - skb = alloc_skb_with_frags(header_len, data_len, max_page_order, - errcode, sk->sk_allocation); - if (skb) - skb_set_owner_w(skb, sk); - return skb; - -interrupted: - err = sock_intr_errno(timeo); -failure: - *errcode = err; - return NULL; -} -EXPORT_SYMBOL(sock_alloc_send_pskb); - -struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size, - int noblock, int *errcode) -{ - return sock_alloc_send_pskb(sk, size, 0, noblock, errcode, 0); -} -EXPORT_SYMBOL(sock_alloc_send_skb); - -int __sock_cmsg_send(struct sock *sk, struct msghdr *msg, struct cmsghdr *cmsg, - struct sockcm_cookie *sockc) -{ - u32 tsflags; - - switch (cmsg->cmsg_type) { - case SO_MARK: - if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) - return -EPERM; - if (cmsg->cmsg_len != CMSG_LEN(sizeof(u32))) - return -EINVAL; - sockc->mark = *(u32 *)CMSG_DATA(cmsg); - break; - case SO_TIMESTAMPING: - if (cmsg->cmsg_len != CMSG_LEN(sizeof(u32))) - return -EINVAL; - - tsflags = *(u32 *)CMSG_DATA(cmsg); - if (tsflags & ~SOF_TIMESTAMPING_TX_RECORD_MASK) - return -EINVAL; - - sockc->tsflags &= ~SOF_TIMESTAMPING_TX_RECORD_MASK; - sockc->tsflags |= tsflags; - break; - /* SCM_RIGHTS and SCM_CREDENTIALS are semantically in SOL_UNIX. */ - case SCM_RIGHTS: - case SCM_CREDENTIALS: - break; - default: - return -EINVAL; - } - return 0; -} -EXPORT_SYMBOL(__sock_cmsg_send); - -int sock_cmsg_send(struct sock *sk, struct msghdr *msg, - struct sockcm_cookie *sockc) -{ - struct cmsghdr *cmsg; - int ret; - - for_each_cmsghdr(cmsg, msg) { - if (!CMSG_OK(msg, cmsg)) - return -EINVAL; - if (cmsg->cmsg_level != SOL_SOCKET) - continue; - ret = __sock_cmsg_send(sk, msg, cmsg, sockc); - if (ret) - return ret; - } - return 0; -} -EXPORT_SYMBOL(sock_cmsg_send); - -/* On 32bit arches, an skb frag is limited to 2^15 */ -#define SKB_FRAG_PAGE_ORDER get_order(32768) - -/** - * skb_page_frag_refill - check that a page_frag contains enough room - * @sz: minimum size of the fragment we want to get - * @pfrag: pointer to page_frag - * @gfp: priority for memory allocation - * - * Note: While this allocator tries to use high order pages, there is - * no guarantee that allocations succeed. Therefore, @sz MUST be - * less or equal than PAGE_SIZE. - */ -bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t gfp) -{ - if (pfrag->page) { - if (page_ref_count(pfrag->page) == 1) { - pfrag->offset = 0; - return true; - } - if (pfrag->offset + sz <= pfrag->size) - return true; - put_page(pfrag->page); - } - - pfrag->offset = 0; - if (SKB_FRAG_PAGE_ORDER) { - /* Avoid direct reclaim but allow kswapd to wake */ - pfrag->page = alloc_pages((gfp & ~__GFP_DIRECT_RECLAIM) | - __GFP_COMP | __GFP_NOWARN | - __GFP_NORETRY, - SKB_FRAG_PAGE_ORDER); - if (likely(pfrag->page)) { - pfrag->size = PAGE_SIZE << SKB_FRAG_PAGE_ORDER; - return true; - } - } - pfrag->page = alloc_page(gfp); - if (likely(pfrag->page)) { - pfrag->size = PAGE_SIZE; - return true; - } - return false; -} -EXPORT_SYMBOL(skb_page_frag_refill); - -bool sk_page_frag_refill(struct sock *sk, struct page_frag *pfrag) -{ - if (likely(skb_page_frag_refill(32U, pfrag, sk->sk_allocation))) - return true; - - sk_enter_memory_pressure(sk); - sk_stream_moderate_sndbuf(sk); - return false; -} -EXPORT_SYMBOL(sk_page_frag_refill); - -static void __lock_sock(struct sock *sk) - __releases(&sk->sk_lock.slock) - __acquires(&sk->sk_lock.slock) -{ - DEFINE_WAIT(wait); - - for (;;) { - prepare_to_wait_exclusive(&sk->sk_lock.wq, &wait, - TASK_UNINTERRUPTIBLE); - spin_unlock_bh(&sk->sk_lock.slock); - schedule(); - spin_lock_bh(&sk->sk_lock.slock); - if (!sock_owned_by_user(sk)) - break; - } - finish_wait(&sk->sk_lock.wq, &wait); -} - -static void __release_sock(struct sock *sk) - __releases(&sk->sk_lock.slock) - __acquires(&sk->sk_lock.slock) -{ - struct sk_buff *skb, *next; - - while ((skb = sk->sk_backlog.head) != NULL) { - sk->sk_backlog.head = sk->sk_backlog.tail = NULL; - - spin_unlock_bh(&sk->sk_lock.slock); - - do { - next = skb->next; - prefetch(next); - WARN_ON_ONCE(skb_dst_is_noref(skb)); - skb->next = NULL; - sk_backlog_rcv(sk, skb); - - cond_resched(); - - skb = next; - } while (skb != NULL); - - spin_lock_bh(&sk->sk_lock.slock); - } - - /* - * Doing the zeroing here guarantee we can not loop forever - * while a wild producer attempts to flood us. - */ - sk->sk_backlog.len = 0; -} - -void __sk_flush_backlog(struct sock *sk) -{ - spin_lock_bh(&sk->sk_lock.slock); - __release_sock(sk); - spin_unlock_bh(&sk->sk_lock.slock); -} - -/** - * sk_wait_data - wait for data to arrive at sk_receive_queue - * @sk: sock to wait on - * @timeo: for how long - * @skb: last skb seen on sk_receive_queue - * - * Now socket state including sk->sk_err is changed only under lock, - * hence we may omit checks after joining wait queue. - * We check receive queue before schedule() only as optimization; - * it is very likely that release_sock() added new data. - */ -int sk_wait_data(struct sock *sk, long *timeo, const struct sk_buff *skb) -{ - int rc; - DEFINE_WAIT(wait); - - prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - sk_set_bit(SOCKWQ_ASYNC_WAITDATA, sk); - rc = sk_wait_event(sk, timeo, skb_peek_tail(&sk->sk_receive_queue) != skb); - sk_clear_bit(SOCKWQ_ASYNC_WAITDATA, sk); - finish_wait(sk_sleep(sk), &wait); - return rc; -} -EXPORT_SYMBOL(sk_wait_data); - -/** - * __sk_mem_schedule - increase sk_forward_alloc and memory_allocated - * @sk: socket - * @size: memory size to allocate - * @kind: allocation type - * - * If kind is SK_MEM_SEND, it means wmem allocation. Otherwise it means - * rmem allocation. This function assumes that protocols which have - * memory_pressure use sk_wmem_queued as write buffer accounting. - */ -int __sk_mem_schedule(struct sock *sk, int size, int kind) -{ - struct proto *prot = sk->sk_prot; - int amt = sk_mem_pages(size); - long allocated; - - sk->sk_forward_alloc += amt * SK_MEM_QUANTUM; - - allocated = sk_memory_allocated_add(sk, amt); - - if (mem_cgroup_sockets_enabled && sk->sk_memcg && - !mem_cgroup_charge_skmem(sk->sk_memcg, amt)) - goto suppress_allocation; - - /* Under limit. */ - if (allocated <= sk_prot_mem_limits(sk, 0)) { - sk_leave_memory_pressure(sk); - return 1; - } - - /* Under pressure. */ - if (allocated > sk_prot_mem_limits(sk, 1)) - sk_enter_memory_pressure(sk); - - /* Over hard limit. */ - if (allocated > sk_prot_mem_limits(sk, 2)) - goto suppress_allocation; - - /* guarantee minimum buffer size under pressure */ - if (kind == SK_MEM_RECV) { - if (atomic_read(&sk->sk_rmem_alloc) < prot->sysctl_rmem[0]) - return 1; - - } else { /* SK_MEM_SEND */ - if (sk->sk_type == SOCK_STREAM) { - if (sk->sk_wmem_queued < prot->sysctl_wmem[0]) - return 1; - } else if (atomic_read(&sk->sk_wmem_alloc) < - prot->sysctl_wmem[0]) - return 1; - } - - if (sk_has_memory_pressure(sk)) { - int alloc; - - if (!sk_under_memory_pressure(sk)) - return 1; - alloc = sk_sockets_allocated_read_positive(sk); - if (sk_prot_mem_limits(sk, 2) > alloc * - sk_mem_pages(sk->sk_wmem_queued + - atomic_read(&sk->sk_rmem_alloc) + - sk->sk_forward_alloc)) - return 1; - } - -suppress_allocation: - - if (kind == SK_MEM_SEND && sk->sk_type == SOCK_STREAM) { - sk_stream_moderate_sndbuf(sk); - - /* Fail only if socket is _under_ its sndbuf. - * In this case we cannot block, so that we have to fail. - */ - if (sk->sk_wmem_queued + size >= sk->sk_sndbuf) - return 1; - } - - trace_sock_exceed_buf_limit(sk, prot, allocated); - - /* Alas. Undo changes. */ - sk->sk_forward_alloc -= amt * SK_MEM_QUANTUM; - - sk_memory_allocated_sub(sk, amt); - - if (mem_cgroup_sockets_enabled && sk->sk_memcg) - mem_cgroup_uncharge_skmem(sk->sk_memcg, amt); - - return 0; -} -EXPORT_SYMBOL(__sk_mem_schedule); - -/** - * __sk_mem_reclaim - reclaim memory_allocated - * @sk: socket - * @amount: number of bytes (rounded down to a SK_MEM_QUANTUM multiple) - */ -void __sk_mem_reclaim(struct sock *sk, int amount) -{ - amount >>= SK_MEM_QUANTUM_SHIFT; - sk_memory_allocated_sub(sk, amount); - sk->sk_forward_alloc -= amount << SK_MEM_QUANTUM_SHIFT; - - if (mem_cgroup_sockets_enabled && sk->sk_memcg) - mem_cgroup_uncharge_skmem(sk->sk_memcg, amount); - - if (sk_under_memory_pressure(sk) && - (sk_memory_allocated(sk) < sk_prot_mem_limits(sk, 0))) - sk_leave_memory_pressure(sk); -} -EXPORT_SYMBOL(__sk_mem_reclaim); - -int sk_set_peek_off(struct sock *sk, int val) -{ - if (val < 0) - return -EINVAL; - - sk->sk_peek_off = val; - return 0; -} -EXPORT_SYMBOL_GPL(sk_set_peek_off); - -/* - * Set of default routines for initialising struct proto_ops when - * the protocol does not support a particular function. In certain - * cases where it makes no sense for a protocol to have a "do nothing" - * function, some default processing is provided. - */ - -int sock_no_bind(struct socket *sock, struct sockaddr *saddr, int len) -{ - return -EOPNOTSUPP; -} -EXPORT_SYMBOL(sock_no_bind); - -int sock_no_connect(struct socket *sock, struct sockaddr *saddr, - int len, int flags) -{ - return -EOPNOTSUPP; -} -EXPORT_SYMBOL(sock_no_connect); - -int sock_no_socketpair(struct socket *sock1, struct socket *sock2) -{ - return -EOPNOTSUPP; -} -EXPORT_SYMBOL(sock_no_socketpair); - -int sock_no_accept(struct socket *sock, struct socket *newsock, int flags) -{ - return -EOPNOTSUPP; -} -EXPORT_SYMBOL(sock_no_accept); - -int sock_no_getname(struct socket *sock, struct sockaddr *saddr, - int *len, int peer) -{ - return -EOPNOTSUPP; -} -EXPORT_SYMBOL(sock_no_getname); - -unsigned int sock_no_poll(struct file *file, struct socket *sock, poll_table *pt) -{ - return 0; -} -EXPORT_SYMBOL(sock_no_poll); - -int sock_no_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - return -EOPNOTSUPP; -} -EXPORT_SYMBOL(sock_no_ioctl); - -int sock_no_listen(struct socket *sock, int backlog) -{ - return -EOPNOTSUPP; -} -EXPORT_SYMBOL(sock_no_listen); - -int sock_no_shutdown(struct socket *sock, int how) -{ - return -EOPNOTSUPP; -} -EXPORT_SYMBOL(sock_no_shutdown); - -int sock_no_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, unsigned int optlen) -{ - return -EOPNOTSUPP; -} -EXPORT_SYMBOL(sock_no_setsockopt); - -int sock_no_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) -{ - return -EOPNOTSUPP; -} -EXPORT_SYMBOL(sock_no_getsockopt); - -int sock_no_sendmsg(struct socket *sock, struct msghdr *m, size_t len) -{ - return -EOPNOTSUPP; -} -EXPORT_SYMBOL(sock_no_sendmsg); - -int sock_no_recvmsg(struct socket *sock, struct msghdr *m, size_t len, - int flags) -{ - return -EOPNOTSUPP; -} -EXPORT_SYMBOL(sock_no_recvmsg); - -int sock_no_mmap(struct file *file, struct socket *sock, struct vm_area_struct *vma) -{ - /* Mirror missing mmap method error code */ - return -ENODEV; -} -EXPORT_SYMBOL(sock_no_mmap); - -ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags) -{ - ssize_t res; - struct msghdr msg = {.msg_flags = flags}; - struct kvec iov; - char *kaddr = kmap(page); - iov.iov_base = kaddr + offset; - iov.iov_len = size; - res = kernel_sendmsg(sock, &msg, &iov, 1, size); - kunmap(page); - return res; -} -EXPORT_SYMBOL(sock_no_sendpage); - -/* - * Default Socket Callbacks - */ - -static void sock_def_wakeup(struct sock *sk) -{ - struct socket_wq *wq; - - rcu_read_lock(); - wq = rcu_dereference(sk->sk_wq); - if (skwq_has_sleeper(wq)) - wake_up_interruptible_all(&wq->wait); - rcu_read_unlock(); -} - -static void sock_def_error_report(struct sock *sk) -{ - struct socket_wq *wq; - - rcu_read_lock(); - wq = rcu_dereference(sk->sk_wq); - if (skwq_has_sleeper(wq)) - wake_up_interruptible_poll(&wq->wait, POLLERR); - sk_wake_async(sk, SOCK_WAKE_IO, POLL_ERR); - rcu_read_unlock(); -} - -static void sock_def_readable(struct sock *sk) -{ - struct socket_wq *wq; - - rcu_read_lock(); - wq = rcu_dereference(sk->sk_wq); - if (skwq_has_sleeper(wq)) - wake_up_interruptible_sync_poll(&wq->wait, POLLIN | POLLPRI | - POLLRDNORM | POLLRDBAND); - sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); - rcu_read_unlock(); -} - -static void sock_def_write_space(struct sock *sk) -{ - struct socket_wq *wq; - - rcu_read_lock(); - - /* Do not wake up a writer until he can make "significant" - * progress. --DaveM - */ - if ((atomic_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf) { - wq = rcu_dereference(sk->sk_wq); - if (skwq_has_sleeper(wq)) - wake_up_interruptible_sync_poll(&wq->wait, POLLOUT | - POLLWRNORM | POLLWRBAND); - - /* Should agree with poll, otherwise some programs break */ - if (sock_writeable(sk)) - sk_wake_async(sk, SOCK_WAKE_SPACE, POLL_OUT); - } - - rcu_read_unlock(); -} - -static void sock_def_destruct(struct sock *sk) -{ -} - -void sk_send_sigurg(struct sock *sk) -{ - if (sk->sk_socket && sk->sk_socket->file) - if (send_sigurg(&sk->sk_socket->file->f_owner)) - sk_wake_async(sk, SOCK_WAKE_URG, POLL_PRI); -} -EXPORT_SYMBOL(sk_send_sigurg); - -void sk_reset_timer(struct sock *sk, struct timer_list* timer, - unsigned long expires) -{ - if (!mod_timer(timer, expires)) - sock_hold(sk); -} -EXPORT_SYMBOL(sk_reset_timer); - -void sk_stop_timer(struct sock *sk, struct timer_list* timer) -{ - if (del_timer(timer)) - __sock_put(sk); -} -EXPORT_SYMBOL(sk_stop_timer); - -void sock_init_data(struct socket *sock, struct sock *sk) -{ - skb_queue_head_init(&sk->sk_receive_queue); - skb_queue_head_init(&sk->sk_write_queue); - skb_queue_head_init(&sk->sk_error_queue); - - sk->sk_send_head = NULL; - - init_timer(&sk->sk_timer); - - sk->sk_allocation = GFP_KERNEL; - sk->sk_rcvbuf = sysctl_rmem_default; - sk->sk_sndbuf = sysctl_wmem_default; - sk->sk_state = TCP_CLOSE; - sk_set_socket(sk, sock); - - sock_set_flag(sk, SOCK_ZAPPED); - - if (sock) { - sk->sk_type = sock->type; - sk->sk_wq = sock->wq; - sock->sk = sk; - } else - sk->sk_wq = NULL; - - rwlock_init(&sk->sk_callback_lock); - lockdep_set_class_and_name(&sk->sk_callback_lock, - af_callback_keys + sk->sk_family, - af_family_clock_key_strings[sk->sk_family]); - - sk->sk_state_change = sock_def_wakeup; - sk->sk_data_ready = sock_def_readable; - sk->sk_write_space = sock_def_write_space; - sk->sk_error_report = sock_def_error_report; - sk->sk_destruct = sock_def_destruct; - - sk->sk_frag.page = NULL; - sk->sk_frag.offset = 0; - sk->sk_peek_off = -1; - - sk->sk_peer_pid = NULL; - sk->sk_peer_cred = NULL; - sk->sk_write_pending = 0; - sk->sk_rcvlowat = 1; - sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; - sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; - - sk->sk_stamp = ktime_set(-1L, 0); - -#ifdef CONFIG_NET_RX_BUSY_POLL - sk->sk_napi_id = 0; - sk->sk_ll_usec = sysctl_net_busy_read; -#endif - - sk->sk_max_pacing_rate = ~0U; - sk->sk_pacing_rate = ~0U; - sk->sk_incoming_cpu = -1; - /* - * Before updating sk_refcnt, we must commit prior changes to memory - * (Documentation/RCU/rculist_nulls.txt for details) - */ - smp_wmb(); - atomic_set(&sk->sk_refcnt, 1); - atomic_set(&sk->sk_drops, 0); -} -EXPORT_SYMBOL(sock_init_data); - -void lock_sock_nested(struct sock *sk, int subclass) -{ - might_sleep(); - spin_lock_bh(&sk->sk_lock.slock); - if (sk->sk_lock.owned) - __lock_sock(sk); - sk->sk_lock.owned = 1; - spin_unlock(&sk->sk_lock.slock); - /* - * The sk_lock has mutex_lock() semantics here: - */ - mutex_acquire(&sk->sk_lock.dep_map, subclass, 0, _RET_IP_); - local_bh_enable(); -} -EXPORT_SYMBOL(lock_sock_nested); - -void release_sock(struct sock *sk) -{ - spin_lock_bh(&sk->sk_lock.slock); - if (sk->sk_backlog.tail) - __release_sock(sk); - - /* Warning : release_cb() might need to release sk ownership, - * ie call sock_release_ownership(sk) before us. - */ - if (sk->sk_prot->release_cb) - sk->sk_prot->release_cb(sk); - - sock_release_ownership(sk); - if (waitqueue_active(&sk->sk_lock.wq)) - wake_up(&sk->sk_lock.wq); - spin_unlock_bh(&sk->sk_lock.slock); -} -EXPORT_SYMBOL(release_sock); - -/** - * lock_sock_fast - fast version of lock_sock - * @sk: socket - * - * This version should be used for very small section, where process wont block - * return false if fast path is taken - * sk_lock.slock locked, owned = 0, BH disabled - * return true if slow path is taken - * sk_lock.slock unlocked, owned = 1, BH enabled - */ -bool lock_sock_fast(struct sock *sk) -{ - might_sleep(); - spin_lock_bh(&sk->sk_lock.slock); - - if (!sk->sk_lock.owned) - /* - * Note : We must disable BH - */ - return false; - - __lock_sock(sk); - sk->sk_lock.owned = 1; - spin_unlock(&sk->sk_lock.slock); - /* - * The sk_lock has mutex_lock() semantics here: - */ - mutex_acquire(&sk->sk_lock.dep_map, 0, 0, _RET_IP_); - local_bh_enable(); - return true; -} -EXPORT_SYMBOL(lock_sock_fast); - -int sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp) -{ - struct timeval tv; - if (!sock_flag(sk, SOCK_TIMESTAMP)) - sock_enable_timestamp(sk, SOCK_TIMESTAMP); - tv = ktime_to_timeval(sk->sk_stamp); - if (tv.tv_sec == -1) - return -ENOENT; - if (tv.tv_sec == 0) { - sk->sk_stamp = ktime_get_real(); - tv = ktime_to_timeval(sk->sk_stamp); - } - return copy_to_user(userstamp, &tv, sizeof(tv)) ? -EFAULT : 0; -} -EXPORT_SYMBOL(sock_get_timestamp); - -int sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp) -{ - struct timespec ts; - if (!sock_flag(sk, SOCK_TIMESTAMP)) - sock_enable_timestamp(sk, SOCK_TIMESTAMP); - ts = ktime_to_timespec(sk->sk_stamp); - if (ts.tv_sec == -1) - return -ENOENT; - if (ts.tv_sec == 0) { - sk->sk_stamp = ktime_get_real(); - ts = ktime_to_timespec(sk->sk_stamp); - } - return copy_to_user(userstamp, &ts, sizeof(ts)) ? -EFAULT : 0; -} -EXPORT_SYMBOL(sock_get_timestampns); - -void sock_enable_timestamp(struct sock *sk, int flag) -{ - if (!sock_flag(sk, flag)) { - unsigned long previous_flags = sk->sk_flags; - - sock_set_flag(sk, flag); - /* - * we just set one of the two flags which require net - * time stamping, but time stamping might have been on - * already because of the other one - */ - if (sock_needs_netstamp(sk) && - !(previous_flags & SK_FLAGS_TIMESTAMP)) - net_enable_timestamp(); - } -} - -int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len, - int level, int type) -{ - struct sock_exterr_skb *serr; - struct sk_buff *skb; - int copied, err; - - err = -EAGAIN; - skb = sock_dequeue_err_skb(sk); - if (skb == NULL) - goto out; - - copied = skb->len; - if (copied > len) { - msg->msg_flags |= MSG_TRUNC; - copied = len; - } - err = skb_copy_datagram_msg(skb, 0, msg, copied); - if (err) - goto out_free_skb; - - sock_recv_timestamp(msg, sk, skb); - - serr = SKB_EXT_ERR(skb); - put_cmsg(msg, level, type, sizeof(serr->ee), &serr->ee); - - msg->msg_flags |= MSG_ERRQUEUE; - err = copied; - -out_free_skb: - kfree_skb(skb); -out: - return err; -} -EXPORT_SYMBOL(sock_recv_errqueue); - -/* - * Get a socket option on an socket. - * - * FIX: POSIX 1003.1g is very ambiguous here. It states that - * asynchronous errors should be reported by getsockopt. We assume - * this means if you specify SO_ERROR (otherwise whats the point of it). - */ -int sock_common_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) -{ - struct sock *sk = sock->sk; - - return sk->sk_prot->getsockopt(sk, level, optname, optval, optlen); -} -EXPORT_SYMBOL(sock_common_getsockopt); - -#ifdef CONFIG_COMPAT -int compat_sock_common_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) -{ - struct sock *sk = sock->sk; - - if (sk->sk_prot->compat_getsockopt != NULL) - return sk->sk_prot->compat_getsockopt(sk, level, optname, - optval, optlen); - return sk->sk_prot->getsockopt(sk, level, optname, optval, optlen); -} -EXPORT_SYMBOL(compat_sock_common_getsockopt); -#endif - -int sock_common_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, - int flags) -{ - struct sock *sk = sock->sk; - int addr_len = 0; - int err; - - err = sk->sk_prot->recvmsg(sk, msg, size, flags & MSG_DONTWAIT, - flags & ~MSG_DONTWAIT, &addr_len); - if (err >= 0) - msg->msg_namelen = addr_len; - return err; -} -EXPORT_SYMBOL(sock_common_recvmsg); - -/* - * Set socket options on an inet socket. - */ -int sock_common_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, unsigned int optlen) -{ - struct sock *sk = sock->sk; - - return sk->sk_prot->setsockopt(sk, level, optname, optval, optlen); -} -EXPORT_SYMBOL(sock_common_setsockopt); - -#ifdef CONFIG_COMPAT -int compat_sock_common_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, unsigned int optlen) -{ - struct sock *sk = sock->sk; - - if (sk->sk_prot->compat_setsockopt != NULL) - return sk->sk_prot->compat_setsockopt(sk, level, optname, - optval, optlen); - return sk->sk_prot->setsockopt(sk, level, optname, optval, optlen); -} -EXPORT_SYMBOL(compat_sock_common_setsockopt); -#endif - -void sk_common_release(struct sock *sk) -{ - if (sk->sk_prot->destroy) - sk->sk_prot->destroy(sk); - - /* - * Observation: when sock_common_release is called, processes have - * no access to socket. But net still has. - * Step one, detach it from networking: - * - * A. Remove from hash tables. - */ - - sk->sk_prot->unhash(sk); - - /* - * In this point socket cannot receive new packets, but it is possible - * that some packets are in flight because some CPU runs receiver and - * did hash table lookup before we unhashed socket. They will achieve - * receive queue and will be purged by socket destructor. - * - * Also we still have packets pending on receive queue and probably, - * our own packets waiting in device queues. sock_destroy will drain - * receive queue, but transmitted packets will delay socket destruction - * until the last reference will be released. - */ - - sock_orphan(sk); - - xfrm_sk_free_policy(sk); - - sk_refcnt_debug_release(sk); - - if (sk->sk_frag.page) { - put_page(sk->sk_frag.page); - sk->sk_frag.page = NULL; - } - - sock_put(sk); -} -EXPORT_SYMBOL(sk_common_release); - -#ifdef CONFIG_PROC_FS -#define PROTO_INUSE_NR 64 /* should be enough for the first time */ -struct prot_inuse { - int val[PROTO_INUSE_NR]; -}; - -static DECLARE_BITMAP(proto_inuse_idx, PROTO_INUSE_NR); - -#ifdef CONFIG_NET_NS -void sock_prot_inuse_add(struct net *net, struct proto *prot, int val) -{ - __this_cpu_add(net->core.inuse->val[prot->inuse_idx], val); -} -EXPORT_SYMBOL_GPL(sock_prot_inuse_add); - -int sock_prot_inuse_get(struct net *net, struct proto *prot) -{ - int cpu, idx = prot->inuse_idx; - int res = 0; - - for_each_possible_cpu(cpu) - res += per_cpu_ptr(net->core.inuse, cpu)->val[idx]; - - return res >= 0 ? res : 0; -} -EXPORT_SYMBOL_GPL(sock_prot_inuse_get); - -static int __net_init sock_inuse_init_net(struct net *net) -{ - net->core.inuse = alloc_percpu(struct prot_inuse); - return net->core.inuse ? 0 : -ENOMEM; -} - -static void __net_exit sock_inuse_exit_net(struct net *net) -{ - free_percpu(net->core.inuse); -} - -static struct pernet_operations net_inuse_ops = { - .init = sock_inuse_init_net, - .exit = sock_inuse_exit_net, -}; - -static __init int net_inuse_init(void) -{ - if (register_pernet_subsys(&net_inuse_ops)) - panic("Cannot initialize net inuse counters"); - - return 0; -} - -core_initcall(net_inuse_init); -#else -static DEFINE_PER_CPU(struct prot_inuse, prot_inuse); - -void sock_prot_inuse_add(struct net *net, struct proto *prot, int val) -{ - __this_cpu_add(prot_inuse.val[prot->inuse_idx], val); -} -EXPORT_SYMBOL_GPL(sock_prot_inuse_add); - -int sock_prot_inuse_get(struct net *net, struct proto *prot) -{ - int cpu, idx = prot->inuse_idx; - int res = 0; - - for_each_possible_cpu(cpu) - res += per_cpu(prot_inuse, cpu).val[idx]; - - return res >= 0 ? res : 0; -} -EXPORT_SYMBOL_GPL(sock_prot_inuse_get); -#endif - -static void assign_proto_idx(struct proto *prot) -{ - prot->inuse_idx = find_first_zero_bit(proto_inuse_idx, PROTO_INUSE_NR); - - if (unlikely(prot->inuse_idx == PROTO_INUSE_NR - 1)) { - pr_err("PROTO_INUSE_NR exhausted\n"); - return; - } - - set_bit(prot->inuse_idx, proto_inuse_idx); -} - -static void release_proto_idx(struct proto *prot) -{ - if (prot->inuse_idx != PROTO_INUSE_NR - 1) - clear_bit(prot->inuse_idx, proto_inuse_idx); -} -#else -static inline void assign_proto_idx(struct proto *prot) -{ -} - -static inline void release_proto_idx(struct proto *prot) -{ -} -#endif - -static void req_prot_cleanup(struct request_sock_ops *rsk_prot) -{ - if (!rsk_prot) - return; - kfree(rsk_prot->slab_name); - rsk_prot->slab_name = NULL; - kmem_cache_destroy(rsk_prot->slab); - rsk_prot->slab = NULL; -} - -static int req_prot_init(const struct proto *prot) -{ - struct request_sock_ops *rsk_prot = prot->rsk_prot; - - if (!rsk_prot) - return 0; - - rsk_prot->slab_name = kasprintf(GFP_KERNEL, "request_sock_%s", - prot->name); - if (!rsk_prot->slab_name) - return -ENOMEM; - - rsk_prot->slab = kmem_cache_create(rsk_prot->slab_name, - rsk_prot->obj_size, 0, - prot->slab_flags, NULL); - - if (!rsk_prot->slab) { - pr_crit("%s: Can't create request sock SLAB cache!\n", - prot->name); - return -ENOMEM; - } - return 0; -} - -int proto_register(struct proto *prot, int alloc_slab) -{ - if (alloc_slab) { - prot->slab = kmem_cache_create(prot->name, prot->obj_size, 0, - SLAB_HWCACHE_ALIGN | prot->slab_flags, - NULL); - - if (prot->slab == NULL) { - pr_crit("%s: Can't create sock SLAB cache!\n", - prot->name); - goto out; - } - - if (req_prot_init(prot)) - goto out_free_request_sock_slab; - - if (prot->twsk_prot != NULL) { - prot->twsk_prot->twsk_slab_name = kasprintf(GFP_KERNEL, "tw_sock_%s", prot->name); - - if (prot->twsk_prot->twsk_slab_name == NULL) - goto out_free_request_sock_slab; - - prot->twsk_prot->twsk_slab = - kmem_cache_create(prot->twsk_prot->twsk_slab_name, - prot->twsk_prot->twsk_obj_size, - 0, - prot->slab_flags, - NULL); - if (prot->twsk_prot->twsk_slab == NULL) - goto out_free_timewait_sock_slab_name; - } - } - - mutex_lock(&proto_list_mutex); - list_add(&prot->node, &proto_list); - assign_proto_idx(prot); - mutex_unlock(&proto_list_mutex); - return 0; - -out_free_timewait_sock_slab_name: - kfree(prot->twsk_prot->twsk_slab_name); -out_free_request_sock_slab: - req_prot_cleanup(prot->rsk_prot); - - kmem_cache_destroy(prot->slab); - prot->slab = NULL; -out: - return -ENOBUFS; -} -EXPORT_SYMBOL(proto_register); - -void proto_unregister(struct proto *prot) -{ - mutex_lock(&proto_list_mutex); - release_proto_idx(prot); - list_del(&prot->node); - mutex_unlock(&proto_list_mutex); - - kmem_cache_destroy(prot->slab); - prot->slab = NULL; - - req_prot_cleanup(prot->rsk_prot); - - if (prot->twsk_prot != NULL && prot->twsk_prot->twsk_slab != NULL) { - kmem_cache_destroy(prot->twsk_prot->twsk_slab); - kfree(prot->twsk_prot->twsk_slab_name); - prot->twsk_prot->twsk_slab = NULL; - } -} -EXPORT_SYMBOL(proto_unregister); - -#ifdef CONFIG_PROC_FS -static void *proto_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(proto_list_mutex) -{ - mutex_lock(&proto_list_mutex); - return seq_list_start_head(&proto_list, *pos); -} - -static void *proto_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - return seq_list_next(v, &proto_list, pos); -} - -static void proto_seq_stop(struct seq_file *seq, void *v) - __releases(proto_list_mutex) -{ - mutex_unlock(&proto_list_mutex); -} - -static char proto_method_implemented(const void *method) -{ - return method == NULL ? 'n' : 'y'; -} -static long sock_prot_memory_allocated(struct proto *proto) -{ - return proto->memory_allocated != NULL ? proto_memory_allocated(proto) : -1L; -} - -static char *sock_prot_memory_pressure(struct proto *proto) -{ - return proto->memory_pressure != NULL ? - proto_memory_pressure(proto) ? "yes" : "no" : "NI"; -} - -static void proto_seq_printf(struct seq_file *seq, struct proto *proto) -{ - - seq_printf(seq, "%-9s %4u %6d %6ld %-3s %6u %-3s %-10s " - "%2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c\n", - proto->name, - proto->obj_size, - sock_prot_inuse_get(seq_file_net(seq), proto), - sock_prot_memory_allocated(proto), - sock_prot_memory_pressure(proto), - proto->max_header, - proto->slab == NULL ? "no" : "yes", - module_name(proto->owner), - proto_method_implemented(proto->close), - proto_method_implemented(proto->connect), - proto_method_implemented(proto->disconnect), - proto_method_implemented(proto->accept), - proto_method_implemented(proto->ioctl), - proto_method_implemented(proto->init), - proto_method_implemented(proto->destroy), - proto_method_implemented(proto->shutdown), - proto_method_implemented(proto->setsockopt), - proto_method_implemented(proto->getsockopt), - proto_method_implemented(proto->sendmsg), - proto_method_implemented(proto->recvmsg), - proto_method_implemented(proto->sendpage), - proto_method_implemented(proto->bind), - proto_method_implemented(proto->backlog_rcv), - proto_method_implemented(proto->hash), - proto_method_implemented(proto->unhash), - proto_method_implemented(proto->get_port), - proto_method_implemented(proto->enter_memory_pressure)); -} - -static int proto_seq_show(struct seq_file *seq, void *v) -{ - if (v == &proto_list) - seq_printf(seq, "%-9s %-4s %-8s %-6s %-5s %-7s %-4s %-10s %s", - "protocol", - "size", - "sockets", - "memory", - "press", - "maxhdr", - "slab", - "module", - "cl co di ac io in de sh ss gs se re sp bi br ha uh gp em\n"); - else - proto_seq_printf(seq, list_entry(v, struct proto, node)); - return 0; -} - -static const struct seq_operations proto_seq_ops = { - .start = proto_seq_start, - .next = proto_seq_next, - .stop = proto_seq_stop, - .show = proto_seq_show, -}; - -static int proto_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &proto_seq_ops, - sizeof(struct seq_net_private)); -} - -static const struct file_operations proto_seq_fops = { - .owner = THIS_MODULE, - .open = proto_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -static __net_init int proto_init_net(struct net *net) -{ - if (!proc_create("protocols", S_IRUGO, net->proc_net, &proto_seq_fops)) - return -ENOMEM; - - return 0; -} - -static __net_exit void proto_exit_net(struct net *net) -{ - remove_proc_entry("protocols", net->proc_net); -} - - -static __net_initdata struct pernet_operations proto_net_ops = { - .init = proto_init_net, - .exit = proto_exit_net, -}; - -static int __init proto_init(void) -{ - return register_pernet_subsys(&proto_net_ops); -} - -subsys_initcall(proto_init); - -#endif /* PROC_FS */ diff --git a/src/linux/net/core/sock_diag.c b/src/linux/net/core/sock_diag.c deleted file mode 100644 index 6b10573..0000000 --- a/src/linux/net/core/sock_diag.c +++ /dev/null @@ -1,346 +0,0 @@ -/* License: GPL */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static const struct sock_diag_handler *sock_diag_handlers[AF_MAX]; -static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh); -static DEFINE_MUTEX(sock_diag_table_mutex); -static struct workqueue_struct *broadcast_wq; - -static u64 sock_gen_cookie(struct sock *sk) -{ - while (1) { - u64 res = atomic64_read(&sk->sk_cookie); - - if (res) - return res; - res = atomic64_inc_return(&sock_net(sk)->cookie_gen); - atomic64_cmpxchg(&sk->sk_cookie, 0, res); - } -} - -int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie) -{ - u64 res; - - if (cookie[0] == INET_DIAG_NOCOOKIE && cookie[1] == INET_DIAG_NOCOOKIE) - return 0; - - res = sock_gen_cookie(sk); - if ((u32)res != cookie[0] || (u32)(res >> 32) != cookie[1]) - return -ESTALE; - - return 0; -} -EXPORT_SYMBOL_GPL(sock_diag_check_cookie); - -void sock_diag_save_cookie(struct sock *sk, __u32 *cookie) -{ - u64 res = sock_gen_cookie(sk); - - cookie[0] = (u32)res; - cookie[1] = (u32)(res >> 32); -} -EXPORT_SYMBOL_GPL(sock_diag_save_cookie); - -int sock_diag_put_meminfo(struct sock *sk, struct sk_buff *skb, int attrtype) -{ - u32 mem[SK_MEMINFO_VARS]; - - mem[SK_MEMINFO_RMEM_ALLOC] = sk_rmem_alloc_get(sk); - mem[SK_MEMINFO_RCVBUF] = sk->sk_rcvbuf; - mem[SK_MEMINFO_WMEM_ALLOC] = sk_wmem_alloc_get(sk); - mem[SK_MEMINFO_SNDBUF] = sk->sk_sndbuf; - mem[SK_MEMINFO_FWD_ALLOC] = sk->sk_forward_alloc; - mem[SK_MEMINFO_WMEM_QUEUED] = sk->sk_wmem_queued; - mem[SK_MEMINFO_OPTMEM] = atomic_read(&sk->sk_omem_alloc); - mem[SK_MEMINFO_BACKLOG] = sk->sk_backlog.len; - mem[SK_MEMINFO_DROPS] = atomic_read(&sk->sk_drops); - - return nla_put(skb, attrtype, sizeof(mem), &mem); -} -EXPORT_SYMBOL_GPL(sock_diag_put_meminfo); - -int sock_diag_put_filterinfo(bool may_report_filterinfo, struct sock *sk, - struct sk_buff *skb, int attrtype) -{ - struct sock_fprog_kern *fprog; - struct sk_filter *filter; - struct nlattr *attr; - unsigned int flen; - int err = 0; - - if (!may_report_filterinfo) { - nla_reserve(skb, attrtype, 0); - return 0; - } - - rcu_read_lock(); - filter = rcu_dereference(sk->sk_filter); - if (!filter) - goto out; - - fprog = filter->prog->orig_prog; - if (!fprog) - goto out; - - flen = bpf_classic_proglen(fprog); - - attr = nla_reserve(skb, attrtype, flen); - if (attr == NULL) { - err = -EMSGSIZE; - goto out; - } - - memcpy(nla_data(attr), fprog->filter, flen); -out: - rcu_read_unlock(); - return err; -} -EXPORT_SYMBOL(sock_diag_put_filterinfo); - -struct broadcast_sk { - struct sock *sk; - struct work_struct work; -}; - -static size_t sock_diag_nlmsg_size(void) -{ - return NLMSG_ALIGN(sizeof(struct inet_diag_msg) - + nla_total_size(sizeof(u8)) /* INET_DIAG_PROTOCOL */ - + nla_total_size_64bit(sizeof(struct tcp_info))); /* INET_DIAG_INFO */ -} - -static void sock_diag_broadcast_destroy_work(struct work_struct *work) -{ - struct broadcast_sk *bsk = - container_of(work, struct broadcast_sk, work); - struct sock *sk = bsk->sk; - const struct sock_diag_handler *hndl; - struct sk_buff *skb; - const enum sknetlink_groups group = sock_diag_destroy_group(sk); - int err = -1; - - WARN_ON(group == SKNLGRP_NONE); - - skb = nlmsg_new(sock_diag_nlmsg_size(), GFP_KERNEL); - if (!skb) - goto out; - - mutex_lock(&sock_diag_table_mutex); - hndl = sock_diag_handlers[sk->sk_family]; - if (hndl && hndl->get_info) - err = hndl->get_info(skb, sk); - mutex_unlock(&sock_diag_table_mutex); - - if (!err) - nlmsg_multicast(sock_net(sk)->diag_nlsk, skb, 0, group, - GFP_KERNEL); - else - kfree_skb(skb); -out: - sk_destruct(sk); - kfree(bsk); -} - -void sock_diag_broadcast_destroy(struct sock *sk) -{ - /* Note, this function is often called from an interrupt context. */ - struct broadcast_sk *bsk = - kmalloc(sizeof(struct broadcast_sk), GFP_ATOMIC); - if (!bsk) - return sk_destruct(sk); - bsk->sk = sk; - INIT_WORK(&bsk->work, sock_diag_broadcast_destroy_work); - queue_work(broadcast_wq, &bsk->work); -} - -void sock_diag_register_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh)) -{ - mutex_lock(&sock_diag_table_mutex); - inet_rcv_compat = fn; - mutex_unlock(&sock_diag_table_mutex); -} -EXPORT_SYMBOL_GPL(sock_diag_register_inet_compat); - -void sock_diag_unregister_inet_compat(int (*fn)(struct sk_buff *skb, struct nlmsghdr *nlh)) -{ - mutex_lock(&sock_diag_table_mutex); - inet_rcv_compat = NULL; - mutex_unlock(&sock_diag_table_mutex); -} -EXPORT_SYMBOL_GPL(sock_diag_unregister_inet_compat); - -int sock_diag_register(const struct sock_diag_handler *hndl) -{ - int err = 0; - - if (hndl->family >= AF_MAX) - return -EINVAL; - - mutex_lock(&sock_diag_table_mutex); - if (sock_diag_handlers[hndl->family]) - err = -EBUSY; - else - sock_diag_handlers[hndl->family] = hndl; - mutex_unlock(&sock_diag_table_mutex); - - return err; -} -EXPORT_SYMBOL_GPL(sock_diag_register); - -void sock_diag_unregister(const struct sock_diag_handler *hnld) -{ - int family = hnld->family; - - if (family >= AF_MAX) - return; - - mutex_lock(&sock_diag_table_mutex); - BUG_ON(sock_diag_handlers[family] != hnld); - sock_diag_handlers[family] = NULL; - mutex_unlock(&sock_diag_table_mutex); -} -EXPORT_SYMBOL_GPL(sock_diag_unregister); - -static int __sock_diag_cmd(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - int err; - struct sock_diag_req *req = nlmsg_data(nlh); - const struct sock_diag_handler *hndl; - - if (nlmsg_len(nlh) < sizeof(*req)) - return -EINVAL; - - if (req->sdiag_family >= AF_MAX) - return -EINVAL; - - if (sock_diag_handlers[req->sdiag_family] == NULL) - request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, - NETLINK_SOCK_DIAG, req->sdiag_family); - - mutex_lock(&sock_diag_table_mutex); - hndl = sock_diag_handlers[req->sdiag_family]; - if (hndl == NULL) - err = -ENOENT; - else if (nlh->nlmsg_type == SOCK_DIAG_BY_FAMILY) - err = hndl->dump(skb, nlh); - else if (nlh->nlmsg_type == SOCK_DESTROY && hndl->destroy) - err = hndl->destroy(skb, nlh); - else - err = -EOPNOTSUPP; - mutex_unlock(&sock_diag_table_mutex); - - return err; -} - -static int sock_diag_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - int ret; - - switch (nlh->nlmsg_type) { - case TCPDIAG_GETSOCK: - case DCCPDIAG_GETSOCK: - if (inet_rcv_compat == NULL) - request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, - NETLINK_SOCK_DIAG, AF_INET); - - mutex_lock(&sock_diag_table_mutex); - if (inet_rcv_compat != NULL) - ret = inet_rcv_compat(skb, nlh); - else - ret = -EOPNOTSUPP; - mutex_unlock(&sock_diag_table_mutex); - - return ret; - case SOCK_DIAG_BY_FAMILY: - case SOCK_DESTROY: - return __sock_diag_cmd(skb, nlh); - default: - return -EINVAL; - } -} - -static DEFINE_MUTEX(sock_diag_mutex); - -static void sock_diag_rcv(struct sk_buff *skb) -{ - mutex_lock(&sock_diag_mutex); - netlink_rcv_skb(skb, &sock_diag_rcv_msg); - mutex_unlock(&sock_diag_mutex); -} - -static int sock_diag_bind(struct net *net, int group) -{ - switch (group) { - case SKNLGRP_INET_TCP_DESTROY: - case SKNLGRP_INET_UDP_DESTROY: - if (!sock_diag_handlers[AF_INET]) - request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, - NETLINK_SOCK_DIAG, AF_INET); - break; - case SKNLGRP_INET6_TCP_DESTROY: - case SKNLGRP_INET6_UDP_DESTROY: - if (!sock_diag_handlers[AF_INET6]) - request_module("net-pf-%d-proto-%d-type-%d", PF_NETLINK, - NETLINK_SOCK_DIAG, AF_INET); - break; - } - return 0; -} - -int sock_diag_destroy(struct sock *sk, int err) -{ - if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) - return -EPERM; - - if (!sk->sk_prot->diag_destroy) - return -EOPNOTSUPP; - - return sk->sk_prot->diag_destroy(sk, err); -} -EXPORT_SYMBOL_GPL(sock_diag_destroy); - -static int __net_init diag_net_init(struct net *net) -{ - struct netlink_kernel_cfg cfg = { - .groups = SKNLGRP_MAX, - .input = sock_diag_rcv, - .bind = sock_diag_bind, - .flags = NL_CFG_F_NONROOT_RECV, - }; - - net->diag_nlsk = netlink_kernel_create(net, NETLINK_SOCK_DIAG, &cfg); - return net->diag_nlsk == NULL ? -ENOMEM : 0; -} - -static void __net_exit diag_net_exit(struct net *net) -{ - netlink_kernel_release(net->diag_nlsk); - net->diag_nlsk = NULL; -} - -static struct pernet_operations diag_net_ops = { - .init = diag_net_init, - .exit = diag_net_exit, -}; - -static int __init sock_diag_init(void) -{ - broadcast_wq = alloc_workqueue("sock_diag_events", 0, 0); - BUG_ON(!broadcast_wq); - return register_pernet_subsys(&diag_net_ops); -} -device_initcall(sock_diag_init); diff --git a/src/linux/net/core/sock_reuseport.c b/src/linux/net/core/sock_reuseport.c deleted file mode 100644 index 9a1a352..0000000 --- a/src/linux/net/core/sock_reuseport.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * To speed up listener socket lookup, create an array to store all sockets - * listening on the same port. This allows a decision to be made after finding - * the first socket. An optional BPF program can also be configured for - * selecting the socket index from the array of available sockets. - */ - -#include -#include -#include - -#define INIT_SOCKS 128 - -static DEFINE_SPINLOCK(reuseport_lock); - -static struct sock_reuseport *__reuseport_alloc(u16 max_socks) -{ - size_t size = sizeof(struct sock_reuseport) + - sizeof(struct sock *) * max_socks; - struct sock_reuseport *reuse = kzalloc(size, GFP_ATOMIC); - - if (!reuse) - return NULL; - - reuse->max_socks = max_socks; - - RCU_INIT_POINTER(reuse->prog, NULL); - return reuse; -} - -int reuseport_alloc(struct sock *sk) -{ - struct sock_reuseport *reuse; - - /* bh lock used since this function call may precede hlist lock in - * soft irq of receive path or setsockopt from process context - */ - spin_lock_bh(&reuseport_lock); - WARN_ONCE(rcu_dereference_protected(sk->sk_reuseport_cb, - lockdep_is_held(&reuseport_lock)), - "multiple allocations for the same socket"); - reuse = __reuseport_alloc(INIT_SOCKS); - if (!reuse) { - spin_unlock_bh(&reuseport_lock); - return -ENOMEM; - } - - reuse->socks[0] = sk; - reuse->num_socks = 1; - rcu_assign_pointer(sk->sk_reuseport_cb, reuse); - - spin_unlock_bh(&reuseport_lock); - - return 0; -} -EXPORT_SYMBOL(reuseport_alloc); - -static struct sock_reuseport *reuseport_grow(struct sock_reuseport *reuse) -{ - struct sock_reuseport *more_reuse; - u32 more_socks_size, i; - - more_socks_size = reuse->max_socks * 2U; - if (more_socks_size > U16_MAX) - return NULL; - - more_reuse = __reuseport_alloc(more_socks_size); - if (!more_reuse) - return NULL; - - more_reuse->max_socks = more_socks_size; - more_reuse->num_socks = reuse->num_socks; - more_reuse->prog = reuse->prog; - - memcpy(more_reuse->socks, reuse->socks, - reuse->num_socks * sizeof(struct sock *)); - - for (i = 0; i < reuse->num_socks; ++i) - rcu_assign_pointer(reuse->socks[i]->sk_reuseport_cb, - more_reuse); - - /* Note: we use kfree_rcu here instead of reuseport_free_rcu so - * that reuse and more_reuse can temporarily share a reference - * to prog. - */ - kfree_rcu(reuse, rcu); - return more_reuse; -} - -/** - * reuseport_add_sock - Add a socket to the reuseport group of another. - * @sk: New socket to add to the group. - * @sk2: Socket belonging to the existing reuseport group. - * May return ENOMEM and not add socket to group under memory pressure. - */ -int reuseport_add_sock(struct sock *sk, struct sock *sk2) -{ - struct sock_reuseport *reuse; - - if (!rcu_access_pointer(sk2->sk_reuseport_cb)) { - int err = reuseport_alloc(sk2); - - if (err) - return err; - } - - spin_lock_bh(&reuseport_lock); - reuse = rcu_dereference_protected(sk2->sk_reuseport_cb, - lockdep_is_held(&reuseport_lock)), - WARN_ONCE(rcu_dereference_protected(sk->sk_reuseport_cb, - lockdep_is_held(&reuseport_lock)), - "socket already in reuseport group"); - - if (reuse->num_socks == reuse->max_socks) { - reuse = reuseport_grow(reuse); - if (!reuse) { - spin_unlock_bh(&reuseport_lock); - return -ENOMEM; - } - } - - reuse->socks[reuse->num_socks] = sk; - /* paired with smp_rmb() in reuseport_select_sock() */ - smp_wmb(); - reuse->num_socks++; - rcu_assign_pointer(sk->sk_reuseport_cb, reuse); - - spin_unlock_bh(&reuseport_lock); - - return 0; -} - -static void reuseport_free_rcu(struct rcu_head *head) -{ - struct sock_reuseport *reuse; - - reuse = container_of(head, struct sock_reuseport, rcu); - if (reuse->prog) - bpf_prog_destroy(reuse->prog); - kfree(reuse); -} - -void reuseport_detach_sock(struct sock *sk) -{ - struct sock_reuseport *reuse; - int i; - - spin_lock_bh(&reuseport_lock); - reuse = rcu_dereference_protected(sk->sk_reuseport_cb, - lockdep_is_held(&reuseport_lock)); - rcu_assign_pointer(sk->sk_reuseport_cb, NULL); - - for (i = 0; i < reuse->num_socks; i++) { - if (reuse->socks[i] == sk) { - reuse->socks[i] = reuse->socks[reuse->num_socks - 1]; - reuse->num_socks--; - if (reuse->num_socks == 0) - call_rcu(&reuse->rcu, reuseport_free_rcu); - break; - } - } - spin_unlock_bh(&reuseport_lock); -} -EXPORT_SYMBOL(reuseport_detach_sock); - -static struct sock *run_bpf(struct sock_reuseport *reuse, u16 socks, - struct bpf_prog *prog, struct sk_buff *skb, - int hdr_len) -{ - struct sk_buff *nskb = NULL; - u32 index; - - if (skb_shared(skb)) { - nskb = skb_clone(skb, GFP_ATOMIC); - if (!nskb) - return NULL; - skb = nskb; - } - - /* temporarily advance data past protocol header */ - if (!pskb_pull(skb, hdr_len)) { - kfree_skb(nskb); - return NULL; - } - index = bpf_prog_run_save_cb(prog, skb); - __skb_push(skb, hdr_len); - - consume_skb(nskb); - - if (index >= socks) - return NULL; - - return reuse->socks[index]; -} - -/** - * reuseport_select_sock - Select a socket from an SO_REUSEPORT group. - * @sk: First socket in the group. - * @hash: When no BPF filter is available, use this hash to select. - * @skb: skb to run through BPF filter. - * @hdr_len: BPF filter expects skb data pointer at payload data. If - * the skb does not yet point at the payload, this parameter represents - * how far the pointer needs to advance to reach the payload. - * Returns a socket that should receive the packet (or NULL on error). - */ -struct sock *reuseport_select_sock(struct sock *sk, - u32 hash, - struct sk_buff *skb, - int hdr_len) -{ - struct sock_reuseport *reuse; - struct bpf_prog *prog; - struct sock *sk2 = NULL; - u16 socks; - - rcu_read_lock(); - reuse = rcu_dereference(sk->sk_reuseport_cb); - - /* if memory allocation failed or add call is not yet complete */ - if (!reuse) - goto out; - - prog = rcu_dereference(reuse->prog); - socks = READ_ONCE(reuse->num_socks); - if (likely(socks)) { - /* paired with smp_wmb() in reuseport_add_sock() */ - smp_rmb(); - - if (prog && skb) - sk2 = run_bpf(reuse, socks, prog, skb, hdr_len); - else - sk2 = reuse->socks[reciprocal_scale(hash, socks)]; - } - -out: - rcu_read_unlock(); - return sk2; -} -EXPORT_SYMBOL(reuseport_select_sock); - -struct bpf_prog * -reuseport_attach_prog(struct sock *sk, struct bpf_prog *prog) -{ - struct sock_reuseport *reuse; - struct bpf_prog *old_prog; - - spin_lock_bh(&reuseport_lock); - reuse = rcu_dereference_protected(sk->sk_reuseport_cb, - lockdep_is_held(&reuseport_lock)); - old_prog = rcu_dereference_protected(reuse->prog, - lockdep_is_held(&reuseport_lock)); - rcu_assign_pointer(reuse->prog, prog); - spin_unlock_bh(&reuseport_lock); - - return old_prog; -} -EXPORT_SYMBOL(reuseport_attach_prog); diff --git a/src/linux/net/core/stream.c b/src/linux/net/core/stream.c deleted file mode 100644 index 1086c8b..0000000 --- a/src/linux/net/core/stream.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - * SUCS NET3: - * - * Generic stream handling routines. These are generic for most - * protocols. Even IP. Tonight 8-). - * This is used because TCP, LLC (others too) layer all have mostly - * identical sendmsg() and recvmsg() code. - * So we (will) share it here. - * - * Authors: Arnaldo Carvalho de Melo - * (from old tcp.c code) - * Alan Cox (Borrowed comments 8-)) - */ - -#include -#include -#include -#include -#include -#include - -/** - * sk_stream_write_space - stream socket write_space callback. - * @sk: socket - * - * FIXME: write proper description - */ -void sk_stream_write_space(struct sock *sk) -{ - struct socket *sock = sk->sk_socket; - struct socket_wq *wq; - - if (sk_stream_is_writeable(sk) && sock) { - clear_bit(SOCK_NOSPACE, &sock->flags); - - rcu_read_lock(); - wq = rcu_dereference(sk->sk_wq); - if (skwq_has_sleeper(wq)) - wake_up_interruptible_poll(&wq->wait, POLLOUT | - POLLWRNORM | POLLWRBAND); - if (wq && wq->fasync_list && !(sk->sk_shutdown & SEND_SHUTDOWN)) - sock_wake_async(wq, SOCK_WAKE_SPACE, POLL_OUT); - rcu_read_unlock(); - } -} - -/** - * sk_stream_wait_connect - Wait for a socket to get into the connected state - * @sk: sock to wait on - * @timeo_p: for how long to wait - * - * Must be called with the socket locked. - */ -int sk_stream_wait_connect(struct sock *sk, long *timeo_p) -{ - struct task_struct *tsk = current; - DEFINE_WAIT(wait); - int done; - - do { - int err = sock_error(sk); - if (err) - return err; - if ((1 << sk->sk_state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) - return -EPIPE; - if (!*timeo_p) - return -EAGAIN; - if (signal_pending(tsk)) - return sock_intr_errno(*timeo_p); - - prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - sk->sk_write_pending++; - done = sk_wait_event(sk, timeo_p, - !sk->sk_err && - !((1 << sk->sk_state) & - ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))); - finish_wait(sk_sleep(sk), &wait); - sk->sk_write_pending--; - } while (!done); - return 0; -} -EXPORT_SYMBOL(sk_stream_wait_connect); - -/** - * sk_stream_closing - Return 1 if we still have things to send in our buffers. - * @sk: socket to verify - */ -static inline int sk_stream_closing(struct sock *sk) -{ - return (1 << sk->sk_state) & - (TCPF_FIN_WAIT1 | TCPF_CLOSING | TCPF_LAST_ACK); -} - -void sk_stream_wait_close(struct sock *sk, long timeout) -{ - if (timeout) { - DEFINE_WAIT(wait); - - do { - prepare_to_wait(sk_sleep(sk), &wait, - TASK_INTERRUPTIBLE); - if (sk_wait_event(sk, &timeout, !sk_stream_closing(sk))) - break; - } while (!signal_pending(current) && timeout); - - finish_wait(sk_sleep(sk), &wait); - } -} -EXPORT_SYMBOL(sk_stream_wait_close); - -/** - * sk_stream_wait_memory - Wait for more memory for a socket - * @sk: socket to wait for memory - * @timeo_p: for how long - */ -int sk_stream_wait_memory(struct sock *sk, long *timeo_p) -{ - int err = 0; - long vm_wait = 0; - long current_timeo = *timeo_p; - bool noblock = (*timeo_p ? false : true); - DEFINE_WAIT(wait); - - if (sk_stream_memory_free(sk)) - current_timeo = vm_wait = (prandom_u32() % (HZ / 5)) + 2; - - while (1) { - sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); - - prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); - - if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) - goto do_error; - if (!*timeo_p) { - if (noblock) - set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); - goto do_nonblock; - } - if (signal_pending(current)) - goto do_interrupted; - sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); - if (sk_stream_memory_free(sk) && !vm_wait) - break; - - set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); - sk->sk_write_pending++; - sk_wait_event(sk, ¤t_timeo, sk->sk_err || - (sk->sk_shutdown & SEND_SHUTDOWN) || - (sk_stream_memory_free(sk) && - !vm_wait)); - sk->sk_write_pending--; - - if (vm_wait) { - vm_wait -= current_timeo; - current_timeo = *timeo_p; - if (current_timeo != MAX_SCHEDULE_TIMEOUT && - (current_timeo -= vm_wait) < 0) - current_timeo = 0; - vm_wait = 0; - } - *timeo_p = current_timeo; - } -out: - finish_wait(sk_sleep(sk), &wait); - return err; - -do_error: - err = -EPIPE; - goto out; -do_nonblock: - err = -EAGAIN; - goto out; -do_interrupted: - err = sock_intr_errno(*timeo_p); - goto out; -} -EXPORT_SYMBOL(sk_stream_wait_memory); - -int sk_stream_error(struct sock *sk, int flags, int err) -{ - if (err == -EPIPE) - err = sock_error(sk) ? : -EPIPE; - if (err == -EPIPE && !(flags & MSG_NOSIGNAL)) - send_sig(SIGPIPE, current, 0); - return err; -} -EXPORT_SYMBOL(sk_stream_error); - -void sk_stream_kill_queues(struct sock *sk) -{ - /* First the read buffer. */ - __skb_queue_purge(&sk->sk_receive_queue); - - /* Next, the error queue. */ - __skb_queue_purge(&sk->sk_error_queue); - - /* Next, the write queue. */ - WARN_ON(!skb_queue_empty(&sk->sk_write_queue)); - - /* Account for returned memory. */ - sk_mem_reclaim(sk); - - WARN_ON(sk->sk_wmem_queued); - WARN_ON(sk->sk_forward_alloc); - - /* It is _impossible_ for the backlog to contain anything - * when we get here. All user references to this socket - * have gone away, only the net layer knows can touch it. - */ -} -EXPORT_SYMBOL(sk_stream_kill_queues); diff --git a/src/linux/net/core/sysctl_net_core.c b/src/linux/net/core/sysctl_net_core.c deleted file mode 100644 index 0df2aa6..0000000 --- a/src/linux/net/core/sysctl_net_core.c +++ /dev/null @@ -1,483 +0,0 @@ -/* -*- linux-c -*- - * sysctl_net_core.c: sysctl interface to net core subsystem. - * - * Begun April 1, 1996, Mike Shaver. - * Added /proc/sys/net/core directory entry (empty =) ). [MS] - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -static int zero = 0; -static int one = 1; -static int min_sndbuf = SOCK_MIN_SNDBUF; -static int min_rcvbuf = SOCK_MIN_RCVBUF; -static int max_skb_frags = MAX_SKB_FRAGS; - -static int net_msg_warn; /* Unused, but still a sysctl */ - -#ifdef CONFIG_RPS -static int rps_sock_flow_sysctl(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - unsigned int orig_size, size; - int ret, i; - struct ctl_table tmp = { - .data = &size, - .maxlen = sizeof(size), - .mode = table->mode - }; - struct rps_sock_flow_table *orig_sock_table, *sock_table; - static DEFINE_MUTEX(sock_flow_mutex); - - mutex_lock(&sock_flow_mutex); - - orig_sock_table = rcu_dereference_protected(rps_sock_flow_table, - lockdep_is_held(&sock_flow_mutex)); - size = orig_size = orig_sock_table ? orig_sock_table->mask + 1 : 0; - - ret = proc_dointvec(&tmp, write, buffer, lenp, ppos); - - if (write) { - if (size) { - if (size > 1<<29) { - /* Enforce limit to prevent overflow */ - mutex_unlock(&sock_flow_mutex); - return -EINVAL; - } - size = roundup_pow_of_two(size); - if (size != orig_size) { - sock_table = - vmalloc(RPS_SOCK_FLOW_TABLE_SIZE(size)); - if (!sock_table) { - mutex_unlock(&sock_flow_mutex); - return -ENOMEM; - } - rps_cpu_mask = roundup_pow_of_two(nr_cpu_ids) - 1; - sock_table->mask = size - 1; - } else - sock_table = orig_sock_table; - - for (i = 0; i < size; i++) - sock_table->ents[i] = RPS_NO_CPU; - } else - sock_table = NULL; - - if (sock_table != orig_sock_table) { - rcu_assign_pointer(rps_sock_flow_table, sock_table); - if (sock_table) - static_key_slow_inc(&rps_needed); - if (orig_sock_table) { - static_key_slow_dec(&rps_needed); - synchronize_rcu(); - vfree(orig_sock_table); - } - } - } - - mutex_unlock(&sock_flow_mutex); - - return ret; -} -#endif /* CONFIG_RPS */ - -#ifdef CONFIG_NET_FLOW_LIMIT -static DEFINE_MUTEX(flow_limit_update_mutex); - -static int flow_limit_cpu_sysctl(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - struct sd_flow_limit *cur; - struct softnet_data *sd; - cpumask_var_t mask; - int i, len, ret = 0; - - if (!alloc_cpumask_var(&mask, GFP_KERNEL)) - return -ENOMEM; - - if (write) { - ret = cpumask_parse_user(buffer, *lenp, mask); - if (ret) - goto done; - - mutex_lock(&flow_limit_update_mutex); - len = sizeof(*cur) + netdev_flow_limit_table_len; - for_each_possible_cpu(i) { - sd = &per_cpu(softnet_data, i); - cur = rcu_dereference_protected(sd->flow_limit, - lockdep_is_held(&flow_limit_update_mutex)); - if (cur && !cpumask_test_cpu(i, mask)) { - RCU_INIT_POINTER(sd->flow_limit, NULL); - synchronize_rcu(); - kfree(cur); - } else if (!cur && cpumask_test_cpu(i, mask)) { - cur = kzalloc_node(len, GFP_KERNEL, - cpu_to_node(i)); - if (!cur) { - /* not unwinding previous changes */ - ret = -ENOMEM; - goto write_unlock; - } - cur->num_buckets = netdev_flow_limit_table_len; - rcu_assign_pointer(sd->flow_limit, cur); - } - } -write_unlock: - mutex_unlock(&flow_limit_update_mutex); - } else { - char kbuf[128]; - - if (*ppos || !*lenp) { - *lenp = 0; - goto done; - } - - cpumask_clear(mask); - rcu_read_lock(); - for_each_possible_cpu(i) { - sd = &per_cpu(softnet_data, i); - if (rcu_dereference(sd->flow_limit)) - cpumask_set_cpu(i, mask); - } - rcu_read_unlock(); - - len = min(sizeof(kbuf) - 1, *lenp); - len = scnprintf(kbuf, len, "%*pb", cpumask_pr_args(mask)); - if (!len) { - *lenp = 0; - goto done; - } - if (len < *lenp) - kbuf[len++] = '\n'; - if (copy_to_user(buffer, kbuf, len)) { - ret = -EFAULT; - goto done; - } - *lenp = len; - *ppos += len; - } - -done: - free_cpumask_var(mask); - return ret; -} - -static int flow_limit_table_len_sysctl(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - unsigned int old, *ptr; - int ret; - - mutex_lock(&flow_limit_update_mutex); - - ptr = table->data; - old = *ptr; - ret = proc_dointvec(table, write, buffer, lenp, ppos); - if (!ret && write && !is_power_of_2(*ptr)) { - *ptr = old; - ret = -EINVAL; - } - - mutex_unlock(&flow_limit_update_mutex); - return ret; -} -#endif /* CONFIG_NET_FLOW_LIMIT */ - -#ifdef CONFIG_NET_SCHED -static int set_default_qdisc(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - char id[IFNAMSIZ]; - struct ctl_table tbl = { - .data = id, - .maxlen = IFNAMSIZ, - }; - int ret; - - qdisc_get_default(id, IFNAMSIZ); - - ret = proc_dostring(&tbl, write, buffer, lenp, ppos); - if (write && ret == 0) - ret = qdisc_set_default(id); - return ret; -} -#endif - -static int proc_do_rss_key(struct ctl_table *table, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - struct ctl_table fake_table; - char buf[NETDEV_RSS_KEY_LEN * 3]; - - snprintf(buf, sizeof(buf), "%*phC", NETDEV_RSS_KEY_LEN, netdev_rss_key); - fake_table.data = buf; - fake_table.maxlen = sizeof(buf); - return proc_dostring(&fake_table, write, buffer, lenp, ppos); -} - -static struct ctl_table net_core_table[] = { -#ifdef CONFIG_NET - { - .procname = "wmem_max", - .data = &sysctl_wmem_max, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_sndbuf, - }, - { - .procname = "rmem_max", - .data = &sysctl_rmem_max, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_rcvbuf, - }, - { - .procname = "wmem_default", - .data = &sysctl_wmem_default, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_sndbuf, - }, - { - .procname = "rmem_default", - .data = &sysctl_rmem_default, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_rcvbuf, - }, - { - .procname = "dev_weight", - .data = &weight_p, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "netdev_max_backlog", - .data = &netdev_max_backlog, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "netdev_rss_key", - .data = &netdev_rss_key, - .maxlen = sizeof(int), - .mode = 0444, - .proc_handler = proc_do_rss_key, - }, -#ifdef CONFIG_BPF_JIT - { - .procname = "bpf_jit_enable", - .data = &bpf_jit_enable, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, -# ifdef CONFIG_HAVE_EBPF_JIT - { - .procname = "bpf_jit_harden", - .data = &bpf_jit_harden, - .maxlen = sizeof(int), - .mode = 0600, - .proc_handler = proc_dointvec, - }, -# endif -#endif - { - .procname = "netdev_tstamp_prequeue", - .data = &netdev_tstamp_prequeue, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "message_cost", - .data = &net_ratelimit_state.interval, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "message_burst", - .data = &net_ratelimit_state.burst, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "optmem_max", - .data = &sysctl_optmem_max, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tstamp_allow_data", - .data = &sysctl_tstamp_allow_data, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one - }, -#ifdef CONFIG_RPS - { - .procname = "rps_sock_flow_entries", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = rps_sock_flow_sysctl - }, -#endif -#ifdef CONFIG_NET_FLOW_LIMIT - { - .procname = "flow_limit_cpu_bitmap", - .mode = 0644, - .proc_handler = flow_limit_cpu_sysctl - }, - { - .procname = "flow_limit_table_len", - .data = &netdev_flow_limit_table_len, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = flow_limit_table_len_sysctl - }, -#endif /* CONFIG_NET_FLOW_LIMIT */ -#ifdef CONFIG_NET_RX_BUSY_POLL - { - .procname = "busy_poll", - .data = &sysctl_net_busy_poll, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "busy_read", - .data = &sysctl_net_busy_read, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec - }, -#endif -#ifdef CONFIG_NET_SCHED - { - .procname = "default_qdisc", - .mode = 0644, - .maxlen = IFNAMSIZ, - .proc_handler = set_default_qdisc - }, -#endif -#endif /* CONFIG_NET */ - { - .procname = "netdev_budget", - .data = &netdev_budget, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "warnings", - .data = &net_msg_warn, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "max_skb_frags", - .data = &sysctl_max_skb_frags, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &one, - .extra2 = &max_skb_frags, - }, - { } -}; - -static struct ctl_table netns_core_table[] = { - { - .procname = "somaxconn", - .data = &init_net.core.sysctl_somaxconn, - .maxlen = sizeof(int), - .mode = 0644, - .extra1 = &zero, - .proc_handler = proc_dointvec_minmax - }, - { } -}; - -static __net_init int sysctl_core_net_init(struct net *net) -{ - struct ctl_table *tbl; - - net->core.sysctl_somaxconn = SOMAXCONN; - - tbl = netns_core_table; - if (!net_eq(net, &init_net)) { - tbl = kmemdup(tbl, sizeof(netns_core_table), GFP_KERNEL); - if (tbl == NULL) - goto err_dup; - - tbl[0].data = &net->core.sysctl_somaxconn; - - /* Don't export any sysctls to unprivileged users */ - if (net->user_ns != &init_user_ns) { - tbl[0].procname = NULL; - } - } - - net->core.sysctl_hdr = register_net_sysctl(net, "net/core", tbl); - if (net->core.sysctl_hdr == NULL) - goto err_reg; - - return 0; - -err_reg: - if (tbl != netns_core_table) - kfree(tbl); -err_dup: - return -ENOMEM; -} - -static __net_exit void sysctl_core_net_exit(struct net *net) -{ - struct ctl_table *tbl; - - tbl = net->core.sysctl_hdr->ctl_table_arg; - unregister_net_sysctl_table(net->core.sysctl_hdr); - BUG_ON(tbl == netns_core_table); - kfree(tbl); -} - -static __net_initdata struct pernet_operations sysctl_core_ops = { - .init = sysctl_core_net_init, - .exit = sysctl_core_net_exit, -}; - -static __init int sysctl_core_init(void) -{ - register_net_sysctl(&init_net, "net/core", net_core_table); - return register_pernet_subsys(&sysctl_core_ops); -} - -fs_initcall(sysctl_core_init); diff --git a/src/linux/net/core/tso.c b/src/linux/net/core/tso.c deleted file mode 100644 index 5dca7ce..0000000 --- a/src/linux/net/core/tso.c +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include -#include -#include -#include - -/* Calculate expected number of TX descriptors */ -int tso_count_descs(struct sk_buff *skb) -{ - /* The Marvell Way */ - return skb_shinfo(skb)->gso_segs * 2 + skb_shinfo(skb)->nr_frags; -} -EXPORT_SYMBOL(tso_count_descs); - -void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso, - int size, bool is_last) -{ - struct tcphdr *tcph; - int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); - int mac_hdr_len = skb_network_offset(skb); - - memcpy(hdr, skb->data, hdr_len); - if (!tso->ipv6) { - struct iphdr *iph = (void *)(hdr + mac_hdr_len); - - iph->id = htons(tso->ip_id); - iph->tot_len = htons(size + hdr_len - mac_hdr_len); - tso->ip_id++; - } else { - struct ipv6hdr *iph = (void *)(hdr + mac_hdr_len); - - iph->payload_len = htons(size + tcp_hdrlen(skb)); - } - tcph = (struct tcphdr *)(hdr + skb_transport_offset(skb)); - put_unaligned_be32(tso->tcp_seq, &tcph->seq); - - if (!is_last) { - /* Clear all special flags for not last packet */ - tcph->psh = 0; - tcph->fin = 0; - tcph->rst = 0; - } -} -EXPORT_SYMBOL(tso_build_hdr); - -void tso_build_data(struct sk_buff *skb, struct tso_t *tso, int size) -{ - tso->tcp_seq += size; - tso->size -= size; - tso->data += size; - - if ((tso->size == 0) && - (tso->next_frag_idx < skb_shinfo(skb)->nr_frags)) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[tso->next_frag_idx]; - - /* Move to next segment */ - tso->size = frag->size; - tso->data = page_address(frag->page.p) + frag->page_offset; - tso->next_frag_idx++; - } -} -EXPORT_SYMBOL(tso_build_data); - -void tso_start(struct sk_buff *skb, struct tso_t *tso) -{ - int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); - - tso->ip_id = ntohs(ip_hdr(skb)->id); - tso->tcp_seq = ntohl(tcp_hdr(skb)->seq); - tso->next_frag_idx = 0; - tso->ipv6 = vlan_get_protocol(skb) == htons(ETH_P_IPV6); - - /* Build first data */ - tso->size = skb_headlen(skb) - hdr_len; - tso->data = skb->data + hdr_len; - if ((tso->size == 0) && - (tso->next_frag_idx < skb_shinfo(skb)->nr_frags)) { - skb_frag_t *frag = &skb_shinfo(skb)->frags[tso->next_frag_idx]; - - /* Move to next segment */ - tso->size = frag->size; - tso->data = page_address(frag->page.p) + frag->page_offset; - tso->next_frag_idx++; - } -} -EXPORT_SYMBOL(tso_start); diff --git a/src/linux/net/core/utils.c b/src/linux/net/core/utils.c deleted file mode 100644 index cf5622b..0000000 --- a/src/linux/net/core/utils.c +++ /dev/null @@ -1,350 +0,0 @@ -/* - * Generic address resultion entity - * - * Authors: - * net_random Alan Cox - * net_ratelimit Andi Kleen - * in{4,6}_pton YOSHIFUJI Hideaki, Copyright (C)2006 USAGI/WIDE Project - * - * Created by Alexey Kuznetsov - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -DEFINE_RATELIMIT_STATE(net_ratelimit_state, 5 * HZ, 10); -/* - * All net warning printk()s should be guarded by this function. - */ -int net_ratelimit(void) -{ - return __ratelimit(&net_ratelimit_state); -} -EXPORT_SYMBOL(net_ratelimit); - -/* - * Convert an ASCII string to binary IP. - * This is outside of net/ipv4/ because various code that uses IP addresses - * is otherwise not dependent on the TCP/IP stack. - */ - -__be32 in_aton(const char *str) -{ - unsigned long l; - unsigned int val; - int i; - - l = 0; - for (i = 0; i < 4; i++) { - l <<= 8; - if (*str != '\0') { - val = 0; - while (*str != '\0' && *str != '.' && *str != '\n') { - val *= 10; - val += *str - '0'; - str++; - } - l |= val; - if (*str != '\0') - str++; - } - } - return htonl(l); -} -EXPORT_SYMBOL(in_aton); - -#define IN6PTON_XDIGIT 0x00010000 -#define IN6PTON_DIGIT 0x00020000 -#define IN6PTON_COLON_MASK 0x00700000 -#define IN6PTON_COLON_1 0x00100000 /* single : requested */ -#define IN6PTON_COLON_2 0x00200000 /* second : requested */ -#define IN6PTON_COLON_1_2 0x00400000 /* :: requested */ -#define IN6PTON_DOT 0x00800000 /* . */ -#define IN6PTON_DELIM 0x10000000 -#define IN6PTON_NULL 0x20000000 /* first/tail */ -#define IN6PTON_UNKNOWN 0x40000000 - -static inline int xdigit2bin(char c, int delim) -{ - int val; - - if (c == delim || c == '\0') - return IN6PTON_DELIM; - if (c == ':') - return IN6PTON_COLON_MASK; - if (c == '.') - return IN6PTON_DOT; - - val = hex_to_bin(c); - if (val >= 0) - return val | IN6PTON_XDIGIT | (val < 10 ? IN6PTON_DIGIT : 0); - - if (delim == -1) - return IN6PTON_DELIM; - return IN6PTON_UNKNOWN; -} - -/** - * in4_pton - convert an IPv4 address from literal to binary representation - * @src: the start of the IPv4 address string - * @srclen: the length of the string, -1 means strlen(src) - * @dst: the binary (u8[4] array) representation of the IPv4 address - * @delim: the delimiter of the IPv4 address in @src, -1 means no delimiter - * @end: A pointer to the end of the parsed string will be placed here - * - * Return one on success, return zero when any error occurs - * and @end will point to the end of the parsed string. - * - */ -int in4_pton(const char *src, int srclen, - u8 *dst, - int delim, const char **end) -{ - const char *s; - u8 *d; - u8 dbuf[4]; - int ret = 0; - int i; - int w = 0; - - if (srclen < 0) - srclen = strlen(src); - s = src; - d = dbuf; - i = 0; - while (1) { - int c; - c = xdigit2bin(srclen > 0 ? *s : '\0', delim); - if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK))) { - goto out; - } - if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) { - if (w == 0) - goto out; - *d++ = w & 0xff; - w = 0; - i++; - if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) { - if (i != 4) - goto out; - break; - } - goto cont; - } - w = (w * 10) + c; - if ((w & 0xffff) > 255) { - goto out; - } -cont: - if (i >= 4) - goto out; - s++; - srclen--; - } - ret = 1; - memcpy(dst, dbuf, sizeof(dbuf)); -out: - if (end) - *end = s; - return ret; -} -EXPORT_SYMBOL(in4_pton); - -/** - * in6_pton - convert an IPv6 address from literal to binary representation - * @src: the start of the IPv6 address string - * @srclen: the length of the string, -1 means strlen(src) - * @dst: the binary (u8[16] array) representation of the IPv6 address - * @delim: the delimiter of the IPv6 address in @src, -1 means no delimiter - * @end: A pointer to the end of the parsed string will be placed here - * - * Return one on success, return zero when any error occurs - * and @end will point to the end of the parsed string. - * - */ -int in6_pton(const char *src, int srclen, - u8 *dst, - int delim, const char **end) -{ - const char *s, *tok = NULL; - u8 *d, *dc = NULL; - u8 dbuf[16]; - int ret = 0; - int i; - int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL; - int w = 0; - - memset(dbuf, 0, sizeof(dbuf)); - - s = src; - d = dbuf; - if (srclen < 0) - srclen = strlen(src); - - while (1) { - int c; - - c = xdigit2bin(srclen > 0 ? *s : '\0', delim); - if (!(c & state)) - goto out; - if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) { - /* process one 16-bit word */ - if (!(state & IN6PTON_NULL)) { - *d++ = (w >> 8) & 0xff; - *d++ = w & 0xff; - } - w = 0; - if (c & IN6PTON_DELIM) { - /* We've processed last word */ - break; - } - /* - * COLON_1 => XDIGIT - * COLON_2 => XDIGIT|DELIM - * COLON_1_2 => COLON_2 - */ - switch (state & IN6PTON_COLON_MASK) { - case IN6PTON_COLON_2: - dc = d; - state = IN6PTON_XDIGIT | IN6PTON_DELIM; - if (dc - dbuf >= sizeof(dbuf)) - state |= IN6PTON_NULL; - break; - case IN6PTON_COLON_1|IN6PTON_COLON_1_2: - state = IN6PTON_XDIGIT | IN6PTON_COLON_2; - break; - case IN6PTON_COLON_1: - state = IN6PTON_XDIGIT; - break; - case IN6PTON_COLON_1_2: - state = IN6PTON_COLON_2; - break; - default: - state = 0; - } - tok = s + 1; - goto cont; - } - - if (c & IN6PTON_DOT) { - ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok), d, delim, &s); - if (ret > 0) { - d += 4; - break; - } - goto out; - } - - w = (w << 4) | (0xff & c); - state = IN6PTON_COLON_1 | IN6PTON_DELIM; - if (!(w & 0xf000)) { - state |= IN6PTON_XDIGIT; - } - if (!dc && d + 2 < dbuf + sizeof(dbuf)) { - state |= IN6PTON_COLON_1_2; - state &= ~IN6PTON_DELIM; - } - if (d + 2 >= dbuf + sizeof(dbuf)) { - state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2); - } -cont: - if ((dc && d + 4 < dbuf + sizeof(dbuf)) || - d + 4 == dbuf + sizeof(dbuf)) { - state |= IN6PTON_DOT; - } - if (d >= dbuf + sizeof(dbuf)) { - state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK); - } - s++; - srclen--; - } - - i = 15; d--; - - if (dc) { - while (d >= dc) - dst[i--] = *d--; - while (i >= dc - dbuf) - dst[i--] = 0; - while (i >= 0) - dst[i--] = *d--; - } else - memcpy(dst, dbuf, sizeof(dbuf)); - - ret = 1; -out: - if (end) - *end = s; - return ret; -} -EXPORT_SYMBOL(in6_pton); - -void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb, - __be32 from, __be32 to, bool pseudohdr) -{ - if (skb->ip_summed != CHECKSUM_PARTIAL) { - csum_replace4(sum, from, to); - if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr) - skb->csum = ~csum_add(csum_sub(~(skb->csum), - (__force __wsum)from), - (__force __wsum)to); - } else if (pseudohdr) - *sum = ~csum_fold(csum_add(csum_sub(csum_unfold(*sum), - (__force __wsum)from), - (__force __wsum)to)); -} -EXPORT_SYMBOL(inet_proto_csum_replace4); - -void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb, - const __be32 *from, const __be32 *to, - bool pseudohdr) -{ - __be32 diff[] = { - ~from[0], ~from[1], ~from[2], ~from[3], - to[0], to[1], to[2], to[3], - }; - if (skb->ip_summed != CHECKSUM_PARTIAL) { - *sum = csum_fold(csum_partial(diff, sizeof(diff), - ~csum_unfold(*sum))); - if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr) - skb->csum = ~csum_partial(diff, sizeof(diff), - ~skb->csum); - } else if (pseudohdr) - *sum = ~csum_fold(csum_partial(diff, sizeof(diff), - csum_unfold(*sum))); -} -EXPORT_SYMBOL(inet_proto_csum_replace16); - -void inet_proto_csum_replace_by_diff(__sum16 *sum, struct sk_buff *skb, - __wsum diff, bool pseudohdr) -{ - if (skb->ip_summed != CHECKSUM_PARTIAL) { - *sum = csum_fold(csum_add(diff, ~csum_unfold(*sum))); - if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr) - skb->csum = ~csum_add(diff, ~skb->csum); - } else if (pseudohdr) { - *sum = ~csum_fold(csum_add(diff, csum_unfold(*sum))); - } -} -EXPORT_SYMBOL(inet_proto_csum_replace_by_diff); diff --git a/src/linux/net/dcb/Kconfig b/src/linux/net/dcb/Kconfig deleted file mode 100644 index 4066d59..0000000 --- a/src/linux/net/dcb/Kconfig +++ /dev/null @@ -1,22 +0,0 @@ -config DCB - bool "Data Center Bridging support" - default n - ---help--- - This enables support for configuring Data Center Bridging (DCB) - features on DCB capable Ethernet adapters via rtnetlink. Say 'Y' - if you have a DCB capable Ethernet adapter which supports this - interface and you are connected to a DCB capable switch. - - DCB is a collection of Ethernet enhancements which allow DCB capable - NICs and switches to support network traffic with differing - requirements (highly reliable, no drops vs. best effort vs. low - latency) to co-exist on Ethernet. - - DCB features include: - Enhanced Transmission Selection (aka Priority Grouping) - provides a - framework for assigning bandwidth guarantees to traffic classes. - Priority-based Flow Control (PFC) - a MAC control pause frame which - works at the granularity of the 802.1p priority instead of the - link (802.3x). - - If unsure, say N. diff --git a/src/linux/net/dccp/Kconfig b/src/linux/net/dccp/Kconfig deleted file mode 100644 index 8c0ef71..0000000 --- a/src/linux/net/dccp/Kconfig +++ /dev/null @@ -1,62 +0,0 @@ -menuconfig IP_DCCP - tristate "The DCCP Protocol" - depends on INET - ---help--- - Datagram Congestion Control Protocol (RFC 4340) - - From http://www.ietf.org/rfc/rfc4340.txt: - - The Datagram Congestion Control Protocol (DCCP) is a transport - protocol that implements bidirectional, unicast connections of - congestion-controlled, unreliable datagrams. It should be suitable - for use by applications such as streaming media, Internet telephony, - and on-line games. - - To compile this protocol support as a module, choose M here: the - module will be called dccp. - - If in doubt, say N. - -if IP_DCCP - -config INET_DCCP_DIAG - depends on INET_DIAG - def_tristate y if (IP_DCCP = y && INET_DIAG = y) - def_tristate m - -source "net/dccp/ccids/Kconfig" - -menu "DCCP Kernel Hacking" - depends on DEBUG_KERNEL=y - -config IP_DCCP_DEBUG - bool "DCCP debug messages" - ---help--- - Only use this if you're hacking DCCP. - - When compiling DCCP as a module, this debugging output can be toggled - by setting the parameter dccp_debug of the `dccp' module to 0 or 1. - - Just say N. - -config NET_DCCPPROBE - tristate "DCCP connection probing" - depends on PROC_FS && KPROBES - ---help--- - This module allows for capturing the changes to DCCP connection - state in response to incoming packets. It is used for debugging - DCCP congestion avoidance modules. If you don't understand - what was just said, you don't need it: say N. - - Documentation on how to use DCCP connection probing can be found - at: - - http://www.linuxfoundation.org/collaborate/workgroups/networking/dccpprobe - - To compile this code as a module, choose M here: the - module will be called dccp_probe. - - -endmenu - -endif # IP_DDCP diff --git a/src/linux/net/dccp/ccids/Kconfig b/src/linux/net/dccp/ccids/Kconfig deleted file mode 100644 index 8ba3fc9..0000000 --- a/src/linux/net/dccp/ccids/Kconfig +++ /dev/null @@ -1,54 +0,0 @@ -menu "DCCP CCIDs Configuration" - -config IP_DCCP_CCID2_DEBUG - bool "CCID-2 debugging messages" - ---help--- - Enable CCID-2 specific debugging messages. - - The debugging output can additionally be toggled by setting the - ccid2_debug parameter to 0 or 1. - - If in doubt, say N. - -config IP_DCCP_CCID3 - bool "CCID-3 (TCP-Friendly)" - def_bool y if (IP_DCCP = y || IP_DCCP = m) - ---help--- - CCID-3 denotes TCP-Friendly Rate Control (TFRC), an equation-based - rate-controlled congestion control mechanism. TFRC is designed to - be reasonably fair when competing for bandwidth with TCP-like flows, - where a flow is "reasonably fair" if its sending rate is generally - within a factor of two of the sending rate of a TCP flow under the - same conditions. However, TFRC has a much lower variation of - throughput over time compared with TCP, which makes CCID-3 more - suitable than CCID-2 for applications such streaming media where a - relatively smooth sending rate is of importance. - - CCID-3 is further described in RFC 4342, - http://www.ietf.org/rfc/rfc4342.txt - - The TFRC congestion control algorithms were initially described in - RFC 5348. - - This text was extracted from RFC 4340 (sec. 10.2), - http://www.ietf.org/rfc/rfc4340.txt - - If in doubt, say N. - -config IP_DCCP_CCID3_DEBUG - bool "CCID-3 debugging messages" - depends on IP_DCCP_CCID3 - ---help--- - Enable CCID-3 specific debugging messages. - - The debugging output can additionally be toggled by setting the - ccid3_debug parameter to 0 or 1. - - If in doubt, say N. - -config IP_DCCP_TFRC_LIB - def_bool y if IP_DCCP_CCID3 - -config IP_DCCP_TFRC_DEBUG - def_bool y if IP_DCCP_CCID3_DEBUG -endmenu diff --git a/src/linux/net/decnet/Kconfig b/src/linux/net/decnet/Kconfig deleted file mode 100644 index f3393e1..0000000 --- a/src/linux/net/decnet/Kconfig +++ /dev/null @@ -1,43 +0,0 @@ -# -# DECnet configuration -# -config DECNET - tristate "DECnet Support" - ---help--- - The DECnet networking protocol was used in many products made by - Digital (now Compaq). It provides reliable stream and sequenced - packet communications over which run a variety of services similar - to those which run over TCP/IP. - - To find some tools to use with the kernel layer support, please - look at Patrick Caulfield's web site: - . - - More detailed documentation is available in - . - - Be sure to say Y to "/proc file system support" and "Sysctl support" - below when using DECnet, since you will need sysctl support to aid - in configuration at run time. - - The DECnet code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module is called decnet. - -config DECNET_ROUTER - bool "DECnet: router support" - depends on DECNET - select FIB_RULES - ---help--- - Add support for turning your DECnet Endnode into a level 1 or 2 - router. This is an experimental, but functional option. If you - do say Y here, then make sure that you also say Y to "Kernel/User - network link driver", "Routing messages" and "Network packet - filtering". The first two are required to allow configuration via - rtnetlink (you will need Alexey Kuznetsov's iproute2 package - from ). The "Network packet - filtering" option will be required for the forthcoming routing daemon - to work. - - See for more information. - diff --git a/src/linux/net/decnet/netfilter/Kconfig b/src/linux/net/decnet/netfilter/Kconfig deleted file mode 100644 index 8d7c109..0000000 --- a/src/linux/net/decnet/netfilter/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# -# DECnet netfilter configuration -# - -menu "DECnet: Netfilter Configuration" - depends on DECNET && NETFILTER - depends on NETFILTER_ADVANCED - -config DECNET_NF_GRABULATOR - tristate "Routing message grabulator (for userland routing daemon)" - help - Enable this module if you want to use the userland DECnet routing - daemon. You will also need to enable routing support for DECnet - unless you just want to monitor routing messages from other nodes. - -endmenu diff --git a/src/linux/net/dns_resolver/Kconfig b/src/linux/net/dns_resolver/Kconfig deleted file mode 100644 index 50d49f7..0000000 --- a/src/linux/net/dns_resolver/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -# -# Configuration for DNS Resolver -# -config DNS_RESOLVER - tristate "DNS Resolver support" - depends on NET && KEYS - help - Saying Y here will include support for the DNS Resolver key type - which can be used to make upcalls to perform DNS lookups in - userspace. - - DNS Resolver is used to query DNS server for information. Examples - being resolving a UNC hostname element to an IP address for CIFS or - performing a DNS query for AFSDB records so that AFS can locate a - cell's volume location database servers. - - DNS Resolver is used by the CIFS and AFS modules, and would support - SMB2 later. DNS Resolver is supported by the userspace upcall - helper "/sbin/dns.resolver" via /etc/request-key.conf. - - See for further - information. - - To compile this as a module, choose M here: the module will be called - dnsresolver. - - If unsure, say N. diff --git a/src/linux/net/dsa/Kconfig b/src/linux/net/dsa/Kconfig deleted file mode 100644 index 96e47c5..0000000 --- a/src/linux/net/dsa/Kconfig +++ /dev/null @@ -1,44 +0,0 @@ -config HAVE_NET_DSA - def_bool y - depends on NETDEVICES && !S390 - -# Drivers must select NET_DSA and the appropriate tagging format - -config NET_DSA - tristate "Distributed Switch Architecture" - depends on HAVE_NET_DSA && NET_SWITCHDEV - select PHYLIB - ---help--- - Say Y if you want to enable support for the hardware switches supported - by the Distributed Switch Architecture. - -if NET_DSA - -config NET_DSA_HWMON - bool "Distributed Switch Architecture HWMON support" - default y - depends on HWMON && !(NET_DSA=y && HWMON=m) - ---help--- - Say Y if you want to expose thermal sensor data on switches supported - by the Distributed Switch Architecture. - - Some of those switches contain thermal sensors. This data is available - via the hwmon sysfs interface and exposes the onboard sensors. - -# tagging formats -config NET_DSA_TAG_BRCM - bool - -config NET_DSA_TAG_DSA - bool - -config NET_DSA_TAG_EDSA - bool - -config NET_DSA_TAG_TRAILER - bool - -config NET_DSA_TAG_QCA - bool - -endif diff --git a/src/linux/net/ethernet/Makefile b/src/linux/net/ethernet/Makefile deleted file mode 100644 index 3231775..0000000 --- a/src/linux/net/ethernet/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -# -# Makefile for the Linux Ethernet layer. -# - -obj-y += eth.o diff --git a/src/linux/net/ethernet/eth.c b/src/linux/net/ethernet/eth.c deleted file mode 100644 index 02acfff..0000000 --- a/src/linux/net/ethernet/eth.c +++ /dev/null @@ -1,519 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Ethernet-type device handling. - * - * Version: @(#)eth.c 1.0.7 05/25/93 - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Mark Evans, - * Florian La Roche, - * Alan Cox, - * - * Fixes: - * Mr Linux : Arp problems - * Alan Cox : Generic queue tidyup (very tiny here) - * Alan Cox : eth_header ntohs should be htons - * Alan Cox : eth_rebuild_header missing an htons and - * minor other things. - * Tegge : Arp bug fixes. - * Florian : Removed many unnecessary functions, code cleanup - * and changes for new arp and skbuff. - * Alan Cox : Redid header building to reflect new format. - * Alan Cox : ARP only when compiled with CONFIG_INET - * Greg Page : 802.2 and SNAP stuff. - * Alan Cox : MAC layer pointers/new format. - * Paul Gortmaker : eth_copy_and_sum shouldn't csum padding. - * Alan Cox : Protect against forwarding explosions with - * older network drivers and IFF_ALLMULTI. - * Christer Weinigel : Better rebuild header message. - * Andrew Morton : 26Feb01: kill ether_setup() - use netdev_boot_setup(). - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#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 - -__setup("ether=", netdev_boot_setup); - -/** - * eth_header - create the Ethernet header - * @skb: buffer to alter - * @dev: source device - * @type: Ethernet type field - * @daddr: destination address (NULL leave destination address) - * @saddr: source address (NULL use device source address) - * @len: packet length (<= skb->len) - * - * - * Set the protocol type. For a packet of type ETH_P_802_3/2 we put the length - * in here instead. - */ -int eth_header(struct sk_buff *skb, struct net_device *dev, - unsigned short type, - const void *daddr, const void *saddr, unsigned int len) -{ - struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN); - - if (type != ETH_P_802_3 && type != ETH_P_802_2) - eth->h_proto = htons(type); - else - eth->h_proto = htons(len); - - /* - * Set the source hardware address. - */ - - if (!saddr) - saddr = dev->dev_addr; - memcpy(eth->h_source, saddr, ETH_ALEN); - - if (daddr) { - memcpy(eth->h_dest, daddr, ETH_ALEN); - return ETH_HLEN; - } - - /* - * Anyway, the loopback-device should never use this function... - */ - - if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) { - eth_zero_addr(eth->h_dest); - return ETH_HLEN; - } - - return -ETH_HLEN; -} -EXPORT_SYMBOL(eth_header); - -/** - * eth_get_headlen - determine the length of header for an ethernet frame - * @data: pointer to start of frame - * @len: total length of frame - * - * Make a best effort attempt to pull the length for all of the headers for - * a given frame in a linear buffer. - */ -u32 eth_get_headlen(void *data, unsigned int len) -{ - const unsigned int flags = FLOW_DISSECTOR_F_PARSE_1ST_FRAG; - const struct ethhdr *eth = (const struct ethhdr *)data; - struct flow_keys keys; - - /* this should never happen, but better safe than sorry */ - if (unlikely(len < sizeof(*eth))) - return len; - - /* parse any remaining L2/L3 headers, check for L4 */ - if (!skb_flow_dissect_flow_keys_buf(&keys, data, eth->h_proto, - sizeof(*eth), len, flags)) - return max_t(u32, keys.control.thoff, sizeof(*eth)); - - /* parse for any L4 headers */ - return min_t(u32, __skb_get_poff(NULL, data, &keys, len), len); -} -EXPORT_SYMBOL(eth_get_headlen); - -/** - * eth_type_trans - determine the packet's protocol ID. - * @skb: received socket data - * @dev: receiving network device - * - * The rule here is that we - * assume 802.3 if the type field is short enough to be a length. - * This is normal practice and works for any 'now in use' protocol. - */ -__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) -{ - unsigned short _service_access_point; - const unsigned short *sap; - const struct ethhdr *eth; - - skb->dev = dev; - skb_reset_mac_header(skb); - - eth = (struct ethhdr *)skb->data; - skb_pull_inline(skb, ETH_HLEN); - - if (unlikely(is_multicast_ether_addr_64bits(eth->h_dest))) { - if (ether_addr_equal_64bits(eth->h_dest, dev->broadcast)) - skb->pkt_type = PACKET_BROADCAST; - else - skb->pkt_type = PACKET_MULTICAST; - } - else if (unlikely(!ether_addr_equal_64bits(eth->h_dest, - dev->dev_addr))) - skb->pkt_type = PACKET_OTHERHOST; - - /* - * Some variants of DSA tagging don't have an ethertype field - * at all, so we check here whether one of those tagging - * variants has been configured on the receiving interface, - * and if so, set skb->protocol without looking at the packet. - */ - if (unlikely(netdev_uses_dsa(dev))) - return htons(ETH_P_XDSA); - - if (likely(eth_proto_is_802_3(eth->h_proto))) - return eth->h_proto; - - /* - * This is a magic hack to spot IPX packets. Older Novell breaks - * the protocol design and runs IPX over 802.3 without an 802.2 LLC - * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This - * won't work for fault tolerant netware but does for the rest. - */ - sap = skb_header_pointer(skb, 0, sizeof(*sap), &_service_access_point); - if (sap && *sap == 0xFFFF) - return htons(ETH_P_802_3); - - /* - * Real 802.2 LLC - */ - return htons(ETH_P_802_2); -} -EXPORT_SYMBOL(eth_type_trans); - -/** - * eth_header_parse - extract hardware address from packet - * @skb: packet to extract header from - * @haddr: destination buffer - */ -int eth_header_parse(const struct sk_buff *skb, unsigned char *haddr) -{ - const struct ethhdr *eth = eth_hdr(skb); - memcpy(haddr, eth->h_source, ETH_ALEN); - return ETH_ALEN; -} -EXPORT_SYMBOL(eth_header_parse); - -/** - * eth_header_cache - fill cache entry from neighbour - * @neigh: source neighbour - * @hh: destination cache entry - * @type: Ethernet type field - * - * Create an Ethernet header template from the neighbour. - */ -int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh, __be16 type) -{ - struct ethhdr *eth; - const struct net_device *dev = neigh->dev; - - eth = (struct ethhdr *) - (((u8 *) hh->hh_data) + (HH_DATA_OFF(sizeof(*eth)))); - - if (type == htons(ETH_P_802_3)) - return -1; - - eth->h_proto = type; - memcpy(eth->h_source, dev->dev_addr, ETH_ALEN); - memcpy(eth->h_dest, neigh->ha, ETH_ALEN); - hh->hh_len = ETH_HLEN; - return 0; -} -EXPORT_SYMBOL(eth_header_cache); - -/** - * eth_header_cache_update - update cache entry - * @hh: destination cache entry - * @dev: network device - * @haddr: new hardware address - * - * Called by Address Resolution module to notify changes in address. - */ -void eth_header_cache_update(struct hh_cache *hh, - const struct net_device *dev, - const unsigned char *haddr) -{ - memcpy(((u8 *) hh->hh_data) + HH_DATA_OFF(sizeof(struct ethhdr)), - haddr, ETH_ALEN); -} -EXPORT_SYMBOL(eth_header_cache_update); - -/** - * eth_prepare_mac_addr_change - prepare for mac change - * @dev: network device - * @p: socket address - */ -int eth_prepare_mac_addr_change(struct net_device *dev, void *p) -{ - struct sockaddr *addr = p; - - if (!(dev->priv_flags & IFF_LIVE_ADDR_CHANGE) && netif_running(dev)) - return -EBUSY; - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; - return 0; -} -EXPORT_SYMBOL(eth_prepare_mac_addr_change); - -/** - * eth_commit_mac_addr_change - commit mac change - * @dev: network device - * @p: socket address - */ -void eth_commit_mac_addr_change(struct net_device *dev, void *p) -{ - struct sockaddr *addr = p; - - memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); -} -EXPORT_SYMBOL(eth_commit_mac_addr_change); - -/** - * eth_mac_addr - set new Ethernet hardware address - * @dev: network device - * @p: socket address - * - * Change hardware address of device. - * - * This doesn't change hardware matching, so needs to be overridden - * for most real devices. - */ -int eth_mac_addr(struct net_device *dev, void *p) -{ - int ret; - - ret = eth_prepare_mac_addr_change(dev, p); - if (ret < 0) - return ret; - eth_commit_mac_addr_change(dev, p); - return 0; -} -EXPORT_SYMBOL(eth_mac_addr); - -/** - * eth_change_mtu - set new MTU size - * @dev: network device - * @new_mtu: new Maximum Transfer Unit - * - * Allow changing MTU size. Needs to be overridden for devices - * supporting jumbo frames. - */ -int eth_change_mtu(struct net_device *dev, int new_mtu) -{ - if (new_mtu < 68 || new_mtu > ETH_DATA_LEN) - return -EINVAL; - dev->mtu = new_mtu; - return 0; -} -EXPORT_SYMBOL(eth_change_mtu); - -int eth_validate_addr(struct net_device *dev) -{ - if (!is_valid_ether_addr(dev->dev_addr)) - return -EADDRNOTAVAIL; - - return 0; -} -EXPORT_SYMBOL(eth_validate_addr); - -const struct header_ops eth_header_ops ____cacheline_aligned = { - .create = eth_header, - .parse = eth_header_parse, - .cache = eth_header_cache, - .cache_update = eth_header_cache_update, -}; - -/** - * ether_setup - setup Ethernet network device - * @dev: network device - * - * Fill in the fields of the device structure with Ethernet-generic values. - */ -void ether_setup(struct net_device *dev) -{ - dev->header_ops = ð_header_ops; - dev->type = ARPHRD_ETHER; - dev->hard_header_len = ETH_HLEN; - dev->mtu = ETH_DATA_LEN; - dev->addr_len = ETH_ALEN; - dev->tx_queue_len = 1000; /* Ethernet wants good queues */ - dev->flags = IFF_BROADCAST|IFF_MULTICAST; - dev->priv_flags |= IFF_TX_SKB_SHARING; - - eth_broadcast_addr(dev->broadcast); - -} -EXPORT_SYMBOL(ether_setup); - -/** - * alloc_etherdev_mqs - Allocates and sets up an Ethernet device - * @sizeof_priv: Size of additional driver-private structure to be allocated - * for this Ethernet device - * @txqs: The number of TX queues this device has. - * @rxqs: The number of RX queues this device has. - * - * Fill in the fields of the device structure with Ethernet-generic - * values. Basically does everything except registering the device. - * - * Constructs a new net device, complete with a private data area of - * size (sizeof_priv). A 32-byte (not bit) alignment is enforced for - * this private data area. - */ - -struct net_device *alloc_etherdev_mqs(int sizeof_priv, unsigned int txqs, - unsigned int rxqs) -{ - return alloc_netdev_mqs(sizeof_priv, "eth%d", NET_NAME_UNKNOWN, - ether_setup, txqs, rxqs); -} -EXPORT_SYMBOL(alloc_etherdev_mqs); - -ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len) -{ - return scnprintf(buf, PAGE_SIZE, "%*phC\n", len, addr); -} -EXPORT_SYMBOL(sysfs_format_mac); - -struct sk_buff **eth_gro_receive(struct sk_buff **head, - struct sk_buff *skb) -{ - struct sk_buff *p, **pp = NULL; - struct ethhdr *eh, *eh2; - unsigned int hlen, off_eth; - const struct packet_offload *ptype; - __be16 type; - int flush = 1; - - off_eth = skb_gro_offset(skb); - hlen = off_eth + sizeof(*eh); - eh = skb_gro_header_fast(skb, off_eth); - if (skb_gro_header_hard(skb, hlen)) { - eh = skb_gro_header_slow(skb, hlen, off_eth); - if (unlikely(!eh)) - goto out; - } - - flush = 0; - - for (p = *head; p; p = p->next) { - if (!NAPI_GRO_CB(p)->same_flow) - continue; - - eh2 = (struct ethhdr *)(p->data + off_eth); - if (compare_ether_header(eh, eh2)) { - NAPI_GRO_CB(p)->same_flow = 0; - continue; - } - } - - type = eh->h_proto; - - rcu_read_lock(); - ptype = gro_find_receive_by_type(type); - if (ptype == NULL) { - flush = 1; - goto out_unlock; - } - - skb_gro_pull(skb, sizeof(*eh)); - skb_gro_postpull_rcsum(skb, eh, sizeof(*eh)); - pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb); - -out_unlock: - rcu_read_unlock(); -out: - NAPI_GRO_CB(skb)->flush |= flush; - - return pp; -} -EXPORT_SYMBOL(eth_gro_receive); - -int eth_gro_complete(struct sk_buff *skb, int nhoff) -{ - struct ethhdr *eh = (struct ethhdr *)(skb->data + nhoff); - __be16 type = eh->h_proto; - struct packet_offload *ptype; - int err = -ENOSYS; - - if (skb->encapsulation) - skb_set_inner_mac_header(skb, nhoff); - - rcu_read_lock(); - ptype = gro_find_complete_by_type(type); - if (ptype != NULL) - err = ptype->callbacks.gro_complete(skb, nhoff + - sizeof(struct ethhdr)); - - rcu_read_unlock(); - return err; -} -EXPORT_SYMBOL(eth_gro_complete); - -static struct packet_offload eth_packet_offload __read_mostly = { - .type = cpu_to_be16(ETH_P_TEB), - .priority = 10, - .callbacks = { - .gro_receive = eth_gro_receive, - .gro_complete = eth_gro_complete, - }, -}; - -static int __init eth_offload_init(void) -{ - dev_add_offload(ð_packet_offload); - - return 0; -} - -fs_initcall(eth_offload_init); - -unsigned char * __weak arch_get_platform_mac_address(void) -{ - return NULL; -} - -int eth_platform_get_mac_address(struct device *dev, u8 *mac_addr) -{ - const unsigned char *addr; - struct device_node *dp; - - if (dev_is_pci(dev)) - dp = pci_device_to_OF_node(to_pci_dev(dev)); - else - dp = dev->of_node; - - addr = NULL; - if (dp) - addr = of_get_mac_address(dp); - if (!addr) - addr = arch_get_platform_mac_address(); - - if (!addr) - return -ENODEV; - - ether_addr_copy(mac_addr, addr); - return 0; -} -EXPORT_SYMBOL(eth_platform_get_mac_address); diff --git a/src/linux/net/hsr/Kconfig b/src/linux/net/hsr/Kconfig deleted file mode 100644 index 4b683fd..0000000 --- a/src/linux/net/hsr/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -# -# IEC 62439-3 High-availability Seamless Redundancy -# - -config HSR - tristate "High-availability Seamless Redundancy (HSR)" - ---help--- - If you say Y here, then your Linux box will be able to act as a - DANH ("Doubly attached node implementing HSR"). For this to work, - your Linux box needs (at least) two physical Ethernet interfaces, - and it must be connected as a node in a ring network together with - other HSR capable nodes. - - All Ethernet frames sent over the hsr device will be sent in both - directions on the ring (over both slave ports), giving a redundant, - instant fail-over network. Each HSR node in the ring acts like a - bridge for HSR frames, but filters frames that have been forwarded - earlier. - - This code is a "best effort" to comply with the HSR standard as - described in IEC 62439-3:2010 (HSRv0) and IEC 62439-3:2012 (HSRv1), - but no compliancy tests have been made. Use iproute2 to select - the version you desire. - - You need to perform any and all necessary tests yourself before - relying on this code in a safety critical system! - - If unsure, say N. diff --git a/src/linux/net/ieee802154/6lowpan/Kconfig b/src/linux/net/ieee802154/6lowpan/Kconfig deleted file mode 100644 index d24f985..0000000 --- a/src/linux/net/ieee802154/6lowpan/Kconfig +++ /dev/null @@ -1,5 +0,0 @@ -config IEEE802154_6LOWPAN - tristate "6lowpan support over IEEE 802.15.4" - depends on 6LOWPAN - ---help--- - IPv6 compression over IEEE 802.15.4. diff --git a/src/linux/net/ieee802154/Kconfig b/src/linux/net/ieee802154/Kconfig deleted file mode 100644 index 188135b..0000000 --- a/src/linux/net/ieee802154/Kconfig +++ /dev/null @@ -1,30 +0,0 @@ -menuconfig IEEE802154 - tristate "IEEE Std 802.15.4 Low-Rate Wireless Personal Area Networks support" - ---help--- - IEEE Std 802.15.4 defines a low data rate, low power and low - complexity short range wireless personal area networks. It was - designed to organise networks of sensors, switches, etc automation - devices. Maximum allowed data rate is 250 kb/s and typical personal - operating space around 10m. - - Say Y here to compile LR-WPAN support into the kernel or say M to - compile it as modules. - -if IEEE802154 - -config IEEE802154_NL802154_EXPERIMENTAL - bool "IEEE 802.15.4 experimental netlink support" - ---help--- - Adds experimental netlink support for nl802154. - -config IEEE802154_SOCKET - tristate "IEEE 802.15.4 socket interface" - default y - ---help--- - Socket interface for IEEE 802.15.4. Contains DGRAM sockets interface - for 802.15.4 dataframes. Also RAW socket interface to build MAC - header from userspace. - -source "net/ieee802154/6lowpan/Kconfig" - -endif diff --git a/src/linux/net/ipv4/Kconfig b/src/linux/net/ipv4/Kconfig deleted file mode 100644 index b54b3ca..0000000 --- a/src/linux/net/ipv4/Kconfig +++ /dev/null @@ -1,730 +0,0 @@ -# -# IP configuration -# -config IP_MULTICAST - bool "IP: multicasting" - help - This is code for addressing several networked computers at once, - enlarging your kernel by about 2 KB. You need multicasting if you - intend to participate in the MBONE, a high bandwidth network on top - of the Internet which carries audio and video broadcasts. More - information about the MBONE is on the WWW at - . For most people, it's safe to say N. - -config IP_ADVANCED_ROUTER - bool "IP: advanced router" - ---help--- - If you intend to run your Linux box mostly as a router, i.e. as a - computer that forwards and redistributes network packets, say Y; you - will then be presented with several options that allow more precise - control about the routing process. - - The answer to this question won't directly affect the kernel: - answering N will just cause the configurator to skip all the - questions about advanced routing. - - Note that your box can only act as a router if you enable IP - forwarding in your kernel; you can do that by saying Y to "/proc - file system support" and "Sysctl support" below and executing the - line - - echo "1" > /proc/sys/net/ipv4/ip_forward - - at boot time after the /proc file system has been mounted. - - If you turn on IP forwarding, you should consider the rp_filter, which - automatically rejects incoming packets if the routing table entry - for their source address doesn't match the network interface they're - arriving on. This has security advantages because it prevents the - so-called IP spoofing, however it can pose problems if you use - asymmetric routing (packets from you to a host take a different path - than packets from that host to you) or if you operate a non-routing - host which has several IP addresses on different interfaces. To turn - rp_filter on use: - - echo 1 > /proc/sys/net/ipv4/conf//rp_filter - or - echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter - - Note that some distributions enable it in startup scripts. - For details about rp_filter strict and loose mode read - . - - If unsure, say N here. - -config IP_FIB_TRIE_STATS - bool "FIB TRIE statistics" - depends on IP_ADVANCED_ROUTER - ---help--- - Keep track of statistics on structure of FIB TRIE table. - Useful for testing and measuring TRIE performance. - -config IP_MULTIPLE_TABLES - bool "IP: policy routing" - depends on IP_ADVANCED_ROUTER - select FIB_RULES - ---help--- - Normally, a router decides what to do with a received packet based - solely on the packet's final destination address. If you say Y here, - the Linux router will also be able to take the packet's source - address into account. Furthermore, the TOS (Type-Of-Service) field - of the packet can be used for routing decisions as well. - - If you are interested in this, please see the preliminary - documentation at - and . - You will need supporting software from - . - - If unsure, say N. - -config IP_ROUTE_MULTIPATH - bool "IP: equal cost multipath" - depends on IP_ADVANCED_ROUTER - help - Normally, the routing tables specify a single action to be taken in - a deterministic manner for a given packet. If you say Y here - however, it becomes possible to attach several actions to a packet - pattern, in effect specifying several alternative paths to travel - for those packets. The router considers all these paths to be of - equal "cost" and chooses one of them in a non-deterministic fashion - if a matching packet arrives. - -config IP_ROUTE_VERBOSE - bool "IP: verbose route monitoring" - depends on IP_ADVANCED_ROUTER - help - If you say Y here, which is recommended, then the kernel will print - verbose messages regarding the routing, for example warnings about - received packets which look strange and could be evidence of an - attack or a misconfigured system somewhere. The information is - handled by the klogd daemon which is responsible for kernel messages - ("man klogd"). - -config IP_ROUTE_CLASSID - bool - -config IP_PNP - bool "IP: kernel level autoconfiguration" - help - This enables automatic configuration of IP addresses of devices and - of the routing table during kernel boot, based on either information - supplied on the kernel command line or by BOOTP or RARP protocols. - You need to say Y only for diskless machines requiring network - access to boot (in which case you want to say Y to "Root file system - on NFS" as well), because all other machines configure the network - in their startup scripts. - -config IP_PNP_DHCP - bool "IP: DHCP support" - depends on IP_PNP - ---help--- - If you want your Linux box to mount its whole root file system (the - one containing the directory /) from some other computer over the - net via NFS and you want the IP address of your computer to be - discovered automatically at boot time using the DHCP protocol (a - special protocol designed for doing this job), say Y here. In case - the boot ROM of your network card was designed for booting Linux and - does DHCP itself, providing all necessary information on the kernel - command line, you can say N here. - - If unsure, say Y. Note that if you want to use DHCP, a DHCP server - must be operating on your network. Read - for details. - -config IP_PNP_BOOTP - bool "IP: BOOTP support" - depends on IP_PNP - ---help--- - If you want your Linux box to mount its whole root file system (the - one containing the directory /) from some other computer over the - net via NFS and you want the IP address of your computer to be - discovered automatically at boot time using the BOOTP protocol (a - special protocol designed for doing this job), say Y here. In case - the boot ROM of your network card was designed for booting Linux and - does BOOTP itself, providing all necessary information on the kernel - command line, you can say N here. If unsure, say Y. Note that if you - want to use BOOTP, a BOOTP server must be operating on your network. - Read for details. - -config IP_PNP_RARP - bool "IP: RARP support" - depends on IP_PNP - help - If you want your Linux box to mount its whole root file system (the - one containing the directory /) from some other computer over the - net via NFS and you want the IP address of your computer to be - discovered automatically at boot time using the RARP protocol (an - older protocol which is being obsoleted by BOOTP and DHCP), say Y - here. Note that if you want to use RARP, a RARP server must be - operating on your network. Read - for details. - -config NET_IPIP - tristate "IP: tunneling" - select INET_TUNNEL - select NET_IP_TUNNEL - ---help--- - Tunneling means encapsulating data of one protocol type within - another protocol and sending it over a channel that understands the - encapsulating protocol. This particular tunneling driver implements - encapsulation of IP within IP, which sounds kind of pointless, but - can be useful if you want to make your (or some other) machine - appear on a different network than it physically is, or to use - mobile-IP facilities (allowing laptops to seamlessly move between - networks without changing their IP addresses). - - Saying Y to this option will produce two modules ( = code which can - be inserted in and removed from the running kernel whenever you - want). Most people won't need this and can say N. - -config NET_IPGRE_DEMUX - tristate "IP: GRE demultiplexer" - help - This is helper module to demultiplex GRE packets on GRE version field criteria. - Required by ip_gre and pptp modules. - -config NET_IP_TUNNEL - tristate - select DST_CACHE - default n - -config NET_IPGRE - tristate "IP: GRE tunnels over IP" - depends on (IPV6 || IPV6=n) && NET_IPGRE_DEMUX - select NET_IP_TUNNEL - help - Tunneling means encapsulating data of one protocol type within - another protocol and sending it over a channel that understands the - encapsulating protocol. This particular tunneling driver implements - GRE (Generic Routing Encapsulation) and at this time allows - encapsulating of IPv4 or IPv6 over existing IPv4 infrastructure. - This driver is useful if the other endpoint is a Cisco router: Cisco - likes GRE much better than the other Linux tunneling driver ("IP - tunneling" above). In addition, GRE allows multicast redistribution - through the tunnel. - -config NET_IPGRE_BROADCAST - bool "IP: broadcast GRE over IP" - depends on IP_MULTICAST && NET_IPGRE - help - One application of GRE/IP is to construct a broadcast WAN (Wide Area - Network), which looks like a normal Ethernet LAN (Local Area - Network), but can be distributed all over the Internet. If you want - to do that, say Y here and to "IP multicast routing" below. - -config IP_MROUTE - bool "IP: multicast routing" - depends on IP_MULTICAST - help - This is used if you want your machine to act as a router for IP - packets that have several destination addresses. It is needed on the - MBONE, a high bandwidth network on top of the Internet which carries - audio and video broadcasts. In order to do that, you would most - likely run the program mrouted. If you haven't heard about it, you - don't need it. - -config IP_MROUTE_MULTIPLE_TABLES - bool "IP: multicast policy routing" - depends on IP_MROUTE && IP_ADVANCED_ROUTER - select FIB_RULES - help - Normally, a multicast router runs a userspace daemon and decides - what to do with a multicast packet based on the source and - destination addresses. If you say Y here, the multicast router - will also be able to take interfaces and packet marks into - account and run multiple instances of userspace daemons - simultaneously, each one handling a single table. - - If unsure, say N. - -config IP_PIMSM_V1 - bool "IP: PIM-SM version 1 support" - depends on IP_MROUTE - help - Kernel side support for Sparse Mode PIM (Protocol Independent - Multicast) version 1. This multicast routing protocol is used widely - because Cisco supports it. You need special software to use it - (pimd-v1). Please see for more - information about PIM. - - Say Y if you want to use PIM-SM v1. Note that you can say N here if - you just want to use Dense Mode PIM. - -config IP_PIMSM_V2 - bool "IP: PIM-SM version 2 support" - depends on IP_MROUTE - help - Kernel side support for Sparse Mode PIM version 2. In order to use - this, you need an experimental routing daemon supporting it (pimd or - gated-5). This routing protocol is not used widely, so say N unless - you want to play with it. - -config SYN_COOKIES - bool "IP: TCP syncookie support" - ---help--- - Normal TCP/IP networking is open to an attack known as "SYN - flooding". This denial-of-service attack prevents legitimate remote - users from being able to connect to your computer during an ongoing - attack and requires very little work from the attacker, who can - operate from anywhere on the Internet. - - SYN cookies provide protection against this type of attack. If you - say Y here, the TCP/IP stack will use a cryptographic challenge - protocol known as "SYN cookies" to enable legitimate users to - continue to connect, even when your machine is under attack. There - is no need for the legitimate users to change their TCP/IP software; - SYN cookies work transparently to them. For technical information - about SYN cookies, check out . - - If you are SYN flooded, the source address reported by the kernel is - likely to have been forged by the attacker; it is only reported as - an aid in tracing the packets to their actual source and should not - be taken as absolute truth. - - SYN cookies may prevent correct error reporting on clients when the - server is really overloaded. If this happens frequently better turn - them off. - - If you say Y here, you can disable SYN cookies at run time by - saying Y to "/proc file system support" and - "Sysctl support" below and executing the command - - echo 0 > /proc/sys/net/ipv4/tcp_syncookies - - after the /proc file system has been mounted. - - If unsure, say N. - -config NET_IPVTI - tristate "Virtual (secure) IP: tunneling" - select INET_TUNNEL - select NET_IP_TUNNEL - depends on INET_XFRM_MODE_TUNNEL - ---help--- - Tunneling means encapsulating data of one protocol type within - another protocol and sending it over a channel that understands the - encapsulating protocol. This can be used with xfrm mode tunnel to give - the notion of a secure tunnel for IPSEC and then use routing protocol - on top. - -config NET_UDP_TUNNEL - tristate - select NET_IP_TUNNEL - default n - -config NET_FOU - tristate "IP: Foo (IP protocols) over UDP" - select XFRM - select NET_UDP_TUNNEL - ---help--- - Foo over UDP allows any IP protocol to be directly encapsulated - over UDP include tunnels (IPIP, GRE, SIT). By encapsulating in UDP - network mechanisms and optimizations for UDP (such as ECMP - and RSS) can be leveraged to provide better service. - -config NET_FOU_IP_TUNNELS - bool "IP: FOU encapsulation of IP tunnels" - depends on NET_IPIP || NET_IPGRE || IPV6_SIT - select NET_FOU - ---help--- - Allow configuration of FOU or GUE encapsulation for IP tunnels. - When this option is enabled IP tunnels can be configured to use - FOU or GUE encapsulation. - -config INET_AH - tristate "IP: AH transformation" - select XFRM_ALGO - select CRYPTO - select CRYPTO_HMAC - select CRYPTO_MD5 - select CRYPTO_SHA1 - ---help--- - Support for IPsec AH. - - If unsure, say Y. - -config INET_ESP - tristate "IP: ESP transformation" - select XFRM_ALGO - select CRYPTO - select CRYPTO_AUTHENC - select CRYPTO_HMAC - select CRYPTO_MD5 - select CRYPTO_CBC - select CRYPTO_SHA1 - select CRYPTO_DES - select CRYPTO_ECHAINIV - ---help--- - Support for IPsec ESP. - - If unsure, say Y. - -config INET_IPCOMP - tristate "IP: IPComp transformation" - select INET_XFRM_TUNNEL - select XFRM_IPCOMP - ---help--- - Support for IP Payload Compression Protocol (IPComp) (RFC3173), - typically needed for IPsec. - - If unsure, say Y. - -config INET_XFRM_TUNNEL - tristate - select INET_TUNNEL - default n - -config INET_TUNNEL - tristate - default n - -config INET_XFRM_MODE_TRANSPORT - tristate "IP: IPsec transport mode" - default y - select XFRM - ---help--- - Support for IPsec transport mode. - - If unsure, say Y. - -config INET_XFRM_MODE_TUNNEL - tristate "IP: IPsec tunnel mode" - default y - select XFRM - ---help--- - Support for IPsec tunnel mode. - - If unsure, say Y. - -config INET_XFRM_MODE_BEET - tristate "IP: IPsec BEET mode" - default y - select XFRM - ---help--- - Support for IPsec BEET mode. - - If unsure, say Y. - -config INET_DIAG - tristate "INET: socket monitoring interface" - default y - ---help--- - Support for INET (TCP, DCCP, etc) socket monitoring interface used by - native Linux tools such as ss. ss is included in iproute2, currently - downloadable at: - - http://www.linuxfoundation.org/collaborate/workgroups/networking/iproute2 - - If unsure, say Y. - -config INET_TCP_DIAG - depends on INET_DIAG - def_tristate INET_DIAG - -config INET_UDP_DIAG - tristate "UDP: socket monitoring interface" - depends on INET_DIAG && (IPV6 || IPV6=n) - default n - ---help--- - Support for UDP socket monitoring interface used by the ss tool. - If unsure, say Y. - -config INET_DIAG_DESTROY - bool "INET: allow privileged process to administratively close sockets" - depends on INET_DIAG - default n - ---help--- - Provides a SOCK_DESTROY operation that allows privileged processes - (e.g., a connection manager or a network administration tool such as - ss) to close sockets opened by other processes. Closing a socket in - this way interrupts any blocking read/write/connect operations on - the socket and causes future socket calls to behave as if the socket - had been disconnected. - If unsure, say N. - -menuconfig TCP_CONG_ADVANCED - bool "TCP: advanced congestion control" - ---help--- - Support for selection of various TCP congestion control - modules. - - Nearly all users can safely say no here, and a safe default - selection will be made (CUBIC with new Reno as a fallback). - - If unsure, say N. - -if TCP_CONG_ADVANCED - -config TCP_CONG_BIC - tristate "Binary Increase Congestion (BIC) control" - default m - ---help--- - BIC-TCP is a sender-side only change that ensures a linear RTT - fairness under large windows while offering both scalability and - bounded TCP-friendliness. The protocol combines two schemes - called additive increase and binary search increase. When the - congestion window is large, additive increase with a large - increment ensures linear RTT fairness as well as good - scalability. Under small congestion windows, binary search - increase provides TCP friendliness. - See http://www.csc.ncsu.edu/faculty/rhee/export/bitcp/ - -config TCP_CONG_CUBIC - tristate "CUBIC TCP" - default y - ---help--- - This is version 2.0 of BIC-TCP which uses a cubic growth function - among other techniques. - See http://www.csc.ncsu.edu/faculty/rhee/export/bitcp/cubic-paper.pdf - -config TCP_CONG_WESTWOOD - tristate "TCP Westwood+" - default m - ---help--- - TCP Westwood+ is a sender-side only modification of the TCP Reno - protocol stack that optimizes the performance of TCP congestion - control. It is based on end-to-end bandwidth estimation to set - congestion window and slow start threshold after a congestion - episode. Using this estimation, TCP Westwood+ adaptively sets a - slow start threshold and a congestion window which takes into - account the bandwidth used at the time congestion is experienced. - TCP Westwood+ significantly increases fairness wrt TCP Reno in - wired networks and throughput over wireless links. - -config TCP_CONG_HTCP - tristate "H-TCP" - default m - ---help--- - H-TCP is a send-side only modifications of the TCP Reno - protocol stack that optimizes the performance of TCP - congestion control for high speed network links. It uses a - modeswitch to change the alpha and beta parameters of TCP Reno - based on network conditions and in a way so as to be fair with - other Reno and H-TCP flows. - -config TCP_CONG_HSTCP - tristate "High Speed TCP" - default n - ---help--- - Sally Floyd's High Speed TCP (RFC 3649) congestion control. - A modification to TCP's congestion control mechanism for use - with large congestion windows. A table indicates how much to - increase the congestion window by when an ACK is received. - For more detail see http://www.icir.org/floyd/hstcp.html - -config TCP_CONG_HYBLA - tristate "TCP-Hybla congestion control algorithm" - default n - ---help--- - TCP-Hybla is a sender-side only change that eliminates penalization of - long-RTT, large-bandwidth connections, like when satellite legs are - involved, especially when sharing a common bottleneck with normal - terrestrial connections. - -config TCP_CONG_VEGAS - tristate "TCP Vegas" - default n - ---help--- - TCP Vegas is a sender-side only change to TCP that anticipates - the onset of congestion by estimating the bandwidth. TCP Vegas - adjusts the sending rate by modifying the congestion - window. TCP Vegas should provide less packet loss, but it is - not as aggressive as TCP Reno. - -config TCP_CONG_NV - tristate "TCP NV" - default n - ---help--- - TCP NV is a follow up to TCP Vegas. It has been modified to deal with - 10G networks, measurement noise introduced by LRO, GRO and interrupt - coalescence. In addition, it will decrease its cwnd multiplicatively - instead of linearly. - - Note that in general congestion avoidance (cwnd decreased when # packets - queued grows) cannot coexist with congestion control (cwnd decreased only - when there is packet loss) due to fairness issues. One scenario when they - can coexist safely is when the CA flows have RTTs << CC flows RTTs. - - For further details see http://www.brakmo.org/networking/tcp-nv/ - -config TCP_CONG_SCALABLE - tristate "Scalable TCP" - default n - ---help--- - Scalable TCP is a sender-side only change to TCP which uses a - MIMD congestion control algorithm which has some nice scaling - properties, though is known to have fairness issues. - See http://www.deneholme.net/tom/scalable/ - -config TCP_CONG_LP - tristate "TCP Low Priority" - default n - ---help--- - TCP Low Priority (TCP-LP), a distributed algorithm whose goal is - to utilize only the excess network bandwidth as compared to the - ``fair share`` of bandwidth as targeted by TCP. - See http://www-ece.rice.edu/networks/TCP-LP/ - -config TCP_CONG_VENO - tristate "TCP Veno" - default n - ---help--- - TCP Veno is a sender-side only enhancement of TCP to obtain better - throughput over wireless networks. TCP Veno makes use of state - distinguishing to circumvent the difficult judgment of the packet loss - type. TCP Veno cuts down less congestion window in response to random - loss packets. - See - -config TCP_CONG_YEAH - tristate "YeAH TCP" - select TCP_CONG_VEGAS - default n - ---help--- - YeAH-TCP is a sender-side high-speed enabled TCP congestion control - algorithm, which uses a mixed loss/delay approach to compute the - congestion window. It's design goals target high efficiency, - internal, RTT and Reno fairness, resilience to link loss while - keeping network elements load as low as possible. - - For further details look here: - http://wil.cs.caltech.edu/pfldnet2007/paper/YeAH_TCP.pdf - -config TCP_CONG_ILLINOIS - tristate "TCP Illinois" - default n - ---help--- - TCP-Illinois is a sender-side modification of TCP Reno for - high speed long delay links. It uses round-trip-time to - adjust the alpha and beta parameters to achieve a higher average - throughput and maintain fairness. - - For further details see: - http://www.ews.uiuc.edu/~shaoliu/tcpillinois/index.html - -config TCP_CONG_DCTCP - tristate "DataCenter TCP (DCTCP)" - default n - ---help--- - DCTCP leverages Explicit Congestion Notification (ECN) in the network to - provide multi-bit feedback to the end hosts. It is designed to provide: - - - High burst tolerance (incast due to partition/aggregate), - - Low latency (short flows, queries), - - High throughput (continuous data updates, large file transfers) with - commodity, shallow-buffered switches. - - All switches in the data center network running DCTCP must support - ECN marking and be configured for marking when reaching defined switch - buffer thresholds. The default ECN marking threshold heuristic for - DCTCP on switches is 20 packets (30KB) at 1Gbps, and 65 packets - (~100KB) at 10Gbps, but might need further careful tweaking. - - For further details see: - http://simula.stanford.edu/~alizade/Site/DCTCP_files/dctcp-final.pdf - -config TCP_CONG_CDG - tristate "CAIA Delay-Gradient (CDG)" - default n - ---help--- - CAIA Delay-Gradient (CDG) is a TCP congestion control that modifies - the TCP sender in order to: - - o Use the delay gradient as a congestion signal. - o Back off with an average probability that is independent of the RTT. - o Coexist with flows that use loss-based congestion control. - o Tolerate packet loss unrelated to congestion. - - For further details see: - D.A. Hayes and G. Armitage. "Revisiting TCP congestion control using - delay gradients." In Networking 2011. Preprint: http://goo.gl/No3vdg - -config TCP_CONG_BBR - tristate "BBR TCP" - default n - ---help--- - - BBR (Bottleneck Bandwidth and RTT) TCP congestion control aims to - maximize network utilization and minimize queues. It builds an explicit - model of the the bottleneck delivery rate and path round-trip - propagation delay. It tolerates packet loss and delay unrelated to - congestion. It can operate over LAN, WAN, cellular, wifi, or cable - modem links. It can coexist with flows that use loss-based congestion - control, and can operate with shallow buffers, deep buffers, - bufferbloat, policers, or AQM schemes that do not provide a delay - signal. It requires the fq ("Fair Queue") pacing packet scheduler. - -choice - prompt "Default TCP congestion control" - default DEFAULT_CUBIC - help - Select the TCP congestion control that will be used by default - for all connections. - - config DEFAULT_BIC - bool "Bic" if TCP_CONG_BIC=y - - config DEFAULT_CUBIC - bool "Cubic" if TCP_CONG_CUBIC=y - - config DEFAULT_HTCP - bool "Htcp" if TCP_CONG_HTCP=y - - config DEFAULT_HYBLA - bool "Hybla" if TCP_CONG_HYBLA=y - - config DEFAULT_VEGAS - bool "Vegas" if TCP_CONG_VEGAS=y - - config DEFAULT_VENO - bool "Veno" if TCP_CONG_VENO=y - - config DEFAULT_WESTWOOD - bool "Westwood" if TCP_CONG_WESTWOOD=y - - config DEFAULT_DCTCP - bool "DCTCP" if TCP_CONG_DCTCP=y - - config DEFAULT_CDG - bool "CDG" if TCP_CONG_CDG=y - - config DEFAULT_BBR - bool "BBR" if TCP_CONG_BBR=y - - config DEFAULT_RENO - bool "Reno" -endchoice - -endif - -config TCP_CONG_CUBIC - tristate - depends on !TCP_CONG_ADVANCED - default y - -config DEFAULT_TCP_CONG - string - default "bic" if DEFAULT_BIC - default "cubic" if DEFAULT_CUBIC - default "htcp" if DEFAULT_HTCP - default "hybla" if DEFAULT_HYBLA - default "vegas" if DEFAULT_VEGAS - default "westwood" if DEFAULT_WESTWOOD - default "veno" if DEFAULT_VENO - default "reno" if DEFAULT_RENO - default "dctcp" if DEFAULT_DCTCP - default "cdg" if DEFAULT_CDG - default "bbr" if DEFAULT_BBR - default "cubic" - -config TCP_MD5SIG - bool "TCP: MD5 Signature Option support (RFC2385)" - select CRYPTO - select CRYPTO_MD5 - ---help--- - RFC2385 specifies a method of giving MD5 protection to TCP sessions. - Its main (only?) use is to protect BGP sessions between core routers - on the Internet. - - If unsure, say N. diff --git a/src/linux/net/ipv4/Makefile b/src/linux/net/ipv4/Makefile deleted file mode 100644 index bc6a6c8..0000000 --- a/src/linux/net/ipv4/Makefile +++ /dev/null @@ -1,63 +0,0 @@ -# -# Makefile for the Linux TCP/IP (INET) layer. -# - -obj-y := route.o inetpeer.o protocol.o \ - ip_input.o ip_fragment.o ip_forward.o ip_options.o \ - ip_output.o ip_sockglue.o inet_hashtables.o \ - inet_timewait_sock.o inet_connection_sock.o \ - tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \ - tcp_minisocks.o tcp_cong.o tcp_metrics.o tcp_fastopen.o \ - tcp_rate.o tcp_recovery.o \ - tcp_offload.o datagram.o raw.o udp.o udplite.o \ - udp_offload.o arp.o icmp.o devinet.o af_inet.o igmp.o \ - fib_frontend.o fib_semantics.o fib_trie.o \ - inet_fragment.o ping.o ip_tunnel_core.o gre_offload.o - -obj-$(CONFIG_NET_IP_TUNNEL) += ip_tunnel.o -obj-$(CONFIG_SYSCTL) += sysctl_net_ipv4.o -obj-$(CONFIG_PROC_FS) += proc.o -obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o -obj-$(CONFIG_IP_MROUTE) += ipmr.o -obj-$(CONFIG_NET_IPIP) += ipip.o -gre-y := gre_demux.o -obj-$(CONFIG_NET_FOU) += fou.o -obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o -obj-$(CONFIG_NET_IPGRE) += ip_gre.o -obj-$(CONFIG_NET_UDP_TUNNEL) += udp_tunnel.o -obj-$(CONFIG_NET_IPVTI) += ip_vti.o -obj-$(CONFIG_SYN_COOKIES) += syncookies.o -obj-$(CONFIG_INET_AH) += ah4.o -obj-$(CONFIG_INET_ESP) += esp4.o -obj-$(CONFIG_INET_IPCOMP) += ipcomp.o -obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o -obj-$(CONFIG_INET_XFRM_MODE_BEET) += xfrm4_mode_beet.o -obj-$(CONFIG_INET_TUNNEL) += tunnel4.o -obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o -obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o -obj-$(CONFIG_IP_PNP) += ipconfig.o -obj-$(CONFIG_NETFILTER) += netfilter.o netfilter/ -obj-$(CONFIG_INET_DIAG) += inet_diag.o -obj-$(CONFIG_INET_TCP_DIAG) += tcp_diag.o -obj-$(CONFIG_INET_UDP_DIAG) += udp_diag.o -obj-$(CONFIG_NET_TCPPROBE) += tcp_probe.o -obj-$(CONFIG_TCP_CONG_BBR) += tcp_bbr.o -obj-$(CONFIG_TCP_CONG_BIC) += tcp_bic.o -obj-$(CONFIG_TCP_CONG_CDG) += tcp_cdg.o -obj-$(CONFIG_TCP_CONG_CUBIC) += tcp_cubic.o -obj-$(CONFIG_TCP_CONG_DCTCP) += tcp_dctcp.o -obj-$(CONFIG_TCP_CONG_WESTWOOD) += tcp_westwood.o -obj-$(CONFIG_TCP_CONG_HSTCP) += tcp_highspeed.o -obj-$(CONFIG_TCP_CONG_HYBLA) += tcp_hybla.o -obj-$(CONFIG_TCP_CONG_HTCP) += tcp_htcp.o -obj-$(CONFIG_TCP_CONG_VEGAS) += tcp_vegas.o -obj-$(CONFIG_TCP_CONG_NV) += tcp_nv.o -obj-$(CONFIG_TCP_CONG_VENO) += tcp_veno.o -obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o -obj-$(CONFIG_TCP_CONG_LP) += tcp_lp.o -obj-$(CONFIG_TCP_CONG_YEAH) += tcp_yeah.o -obj-$(CONFIG_TCP_CONG_ILLINOIS) += tcp_illinois.o -obj-$(CONFIG_NETLABEL) += cipso_ipv4.o - -obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \ - xfrm4_output.o xfrm4_protocol.o diff --git a/src/linux/net/ipv4/af_inet.c b/src/linux/net/ipv4/af_inet.c deleted file mode 100644 index 2151432..0000000 --- a/src/linux/net/ipv4/af_inet.c +++ /dev/null @@ -1,1920 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * PF_INET protocol family socket handler. - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Florian La Roche, - * Alan Cox, - * - * Changes (see also sock.c) - * - * piggy, - * Karl Knutson : Socket protocol table - * A.N.Kuznetsov : Socket death error in accept(). - * John Richardson : Fix non blocking error in connect() - * so sockets that fail to connect - * don't return -EINPROGRESS. - * Alan Cox : Asynchronous I/O support - * Alan Cox : Keep correct socket pointer on sock - * structures - * when accept() ed - * Alan Cox : Semantics of SO_LINGER aren't state - * moved to close when you look carefully. - * With this fixed and the accept bug fixed - * some RPC stuff seems happier. - * Niibe Yutaka : 4.4BSD style write async I/O - * Alan Cox, - * Tony Gale : Fixed reuse semantics. - * Alan Cox : bind() shouldn't abort existing but dead - * sockets. Stops FTP netin:.. I hope. - * Alan Cox : bind() works correctly for RAW sockets. - * Note that FreeBSD at least was broken - * in this respect so be careful with - * compatibility tests... - * Alan Cox : routing cache support - * Alan Cox : memzero the socket structure for - * compactness. - * Matt Day : nonblock connect error handler - * Alan Cox : Allow large numbers of pending sockets - * (eg for big web sites), but only if - * specifically application requested. - * Alan Cox : New buffering throughout IP. Used - * dumbly. - * Alan Cox : New buffering now used smartly. - * Alan Cox : BSD rather than common sense - * interpretation of listen. - * Germano Caronni : Assorted small races. - * Alan Cox : sendmsg/recvmsg basic support. - * Alan Cox : Only sendmsg/recvmsg now supported. - * Alan Cox : Locked down bind (see security list). - * Alan Cox : Loosened bind a little. - * Mike McLagan : ADD/DEL DLCI Ioctls - * Willy Konynenberg : Transparent proxying support. - * David S. Miller : New socket lookup architecture. - * Some other random speedups. - * Cyrus Durgin : Cleaned up file for kmod hacks. - * Andi Kleen : Fix inet_stream_connect TCP race. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#define pr_fmt(fmt) "IPv4: " fmt - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_IP_MROUTE -#include -#endif -#include - - -/* The inetsw table contains everything that inet_create needs to - * build a new socket. - */ -static struct list_head inetsw[SOCK_MAX]; -static DEFINE_SPINLOCK(inetsw_lock); - -/* New destruction routine */ - -void inet_sock_destruct(struct sock *sk) -{ - struct inet_sock *inet = inet_sk(sk); - - __skb_queue_purge(&sk->sk_receive_queue); - __skb_queue_purge(&sk->sk_error_queue); - - sk_mem_reclaim(sk); - - if (sk->sk_type == SOCK_STREAM && sk->sk_state != TCP_CLOSE) { - pr_err("Attempt to release TCP socket in state %d %p\n", - sk->sk_state, sk); - return; - } - if (!sock_flag(sk, SOCK_DEAD)) { - pr_err("Attempt to release alive inet socket %p\n", sk); - return; - } - - WARN_ON(atomic_read(&sk->sk_rmem_alloc)); - WARN_ON(atomic_read(&sk->sk_wmem_alloc)); - WARN_ON(sk->sk_wmem_queued); - WARN_ON(sk->sk_forward_alloc); - - kfree(rcu_dereference_protected(inet->inet_opt, 1)); - dst_release(rcu_dereference_check(sk->sk_dst_cache, 1)); - dst_release(sk->sk_rx_dst); - sk_refcnt_debug_dec(sk); -} -EXPORT_SYMBOL(inet_sock_destruct); - -/* - * The routines beyond this point handle the behaviour of an AF_INET - * socket object. Mostly it punts to the subprotocols of IP to do - * the work. - */ - -/* - * Automatically bind an unbound socket. - */ - -static int inet_autobind(struct sock *sk) -{ - struct inet_sock *inet; - /* We may need to bind the socket. */ - lock_sock(sk); - inet = inet_sk(sk); - if (!inet->inet_num) { - if (sk->sk_prot->get_port(sk, 0)) { - release_sock(sk); - return -EAGAIN; - } - inet->inet_sport = htons(inet->inet_num); - } - release_sock(sk); - return 0; -} - -/* - * Move a socket into listening state. - */ -int inet_listen(struct socket *sock, int backlog) -{ - struct sock *sk = sock->sk; - unsigned char old_state; - int err; - - lock_sock(sk); - - err = -EINVAL; - if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM) - goto out; - - old_state = sk->sk_state; - if (!((1 << old_state) & (TCPF_CLOSE | TCPF_LISTEN))) - goto out; - - /* Really, if the socket is already in listen state - * we can only allow the backlog to be adjusted. - */ - if (old_state != TCP_LISTEN) { - /* Enable TFO w/o requiring TCP_FASTOPEN socket option. - * Note that only TCP sockets (SOCK_STREAM) will reach here. - * Also fastopen backlog may already been set via the option - * because the socket was in TCP_LISTEN state previously but - * was shutdown() rather than close(). - */ - if ((sysctl_tcp_fastopen & TFO_SERVER_WO_SOCKOPT1) && - (sysctl_tcp_fastopen & TFO_SERVER_ENABLE) && - !inet_csk(sk)->icsk_accept_queue.fastopenq.max_qlen) { - fastopen_queue_tune(sk, backlog); - tcp_fastopen_init_key_once(true); - } - - err = inet_csk_listen_start(sk, backlog); - if (err) - goto out; - } - sk->sk_max_ack_backlog = backlog; - err = 0; - -out: - release_sock(sk); - return err; -} -EXPORT_SYMBOL(inet_listen); - -/* - * Create an inet socket. - */ - -static int inet_create(struct net *net, struct socket *sock, int protocol, - int kern) -{ - struct sock *sk; - struct inet_protosw *answer; - struct inet_sock *inet; - struct proto *answer_prot; - unsigned char answer_flags; - int try_loading_module = 0; - int err; - - if (protocol < 0 || protocol >= IPPROTO_MAX) - return -EINVAL; - - sock->state = SS_UNCONNECTED; - - /* Look for the requested type/protocol pair. */ -lookup_protocol: - err = -ESOCKTNOSUPPORT; - rcu_read_lock(); - list_for_each_entry_rcu(answer, &inetsw[sock->type], list) { - - err = 0; - /* Check the non-wild match. */ - if (protocol == answer->protocol) { - if (protocol != IPPROTO_IP) - break; - } else { - /* Check for the two wild cases. */ - if (IPPROTO_IP == protocol) { - protocol = answer->protocol; - break; - } - if (IPPROTO_IP == answer->protocol) - break; - } - err = -EPROTONOSUPPORT; - } - - if (unlikely(err)) { - if (try_loading_module < 2) { - rcu_read_unlock(); - /* - * Be more specific, e.g. net-pf-2-proto-132-type-1 - * (net-pf-PF_INET-proto-IPPROTO_SCTP-type-SOCK_STREAM) - */ - if (++try_loading_module == 1) - request_module("net-pf-%d-proto-%d-type-%d", - PF_INET, protocol, sock->type); - /* - * Fall back to generic, e.g. net-pf-2-proto-132 - * (net-pf-PF_INET-proto-IPPROTO_SCTP) - */ - else - request_module("net-pf-%d-proto-%d", - PF_INET, protocol); - goto lookup_protocol; - } else - goto out_rcu_unlock; - } - - err = -EPERM; - if (sock->type == SOCK_RAW && !kern && - !ns_capable(net->user_ns, CAP_NET_RAW)) - goto out_rcu_unlock; - - sock->ops = answer->ops; - answer_prot = answer->prot; - answer_flags = answer->flags; - rcu_read_unlock(); - - WARN_ON(!answer_prot->slab); - - err = -ENOBUFS; - sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot, kern); - if (!sk) - goto out; - - err = 0; - if (INET_PROTOSW_REUSE & answer_flags) - sk->sk_reuse = SK_CAN_REUSE; - - inet = inet_sk(sk); - inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0; - - inet->nodefrag = 0; - - if (SOCK_RAW == sock->type) { - inet->inet_num = protocol; - if (IPPROTO_RAW == protocol) - inet->hdrincl = 1; - } - - if (net->ipv4.sysctl_ip_no_pmtu_disc) - inet->pmtudisc = IP_PMTUDISC_DONT; - else - inet->pmtudisc = IP_PMTUDISC_WANT; - - inet->inet_id = 0; - - sock_init_data(sock, sk); - - sk->sk_destruct = inet_sock_destruct; - sk->sk_protocol = protocol; - sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv; - - inet->uc_ttl = -1; - inet->mc_loop = 1; - inet->mc_ttl = 1; - inet->mc_all = 1; - inet->mc_index = 0; - inet->mc_list = NULL; - inet->rcv_tos = 0; - - sk_refcnt_debug_inc(sk); - - if (inet->inet_num) { - /* It assumes that any protocol which allows - * the user to assign a number at socket - * creation time automatically - * shares. - */ - inet->inet_sport = htons(inet->inet_num); - /* Add to protocol hash chains. */ - err = sk->sk_prot->hash(sk); - if (err) { - sk_common_release(sk); - goto out; - } - } - - if (sk->sk_prot->init) { - err = sk->sk_prot->init(sk); - if (err) - sk_common_release(sk); - } -out: - return err; -out_rcu_unlock: - rcu_read_unlock(); - goto out; -} - - -/* - * The peer socket should always be NULL (or else). When we call this - * function we are destroying the object and from then on nobody - * should refer to it. - */ -int inet_release(struct socket *sock) -{ - struct sock *sk = sock->sk; - - if (sk) { - long timeout; - - /* Applications forget to leave groups before exiting */ - ip_mc_drop_socket(sk); - - /* If linger is set, we don't return until the close - * is complete. Otherwise we return immediately. The - * actually closing is done the same either way. - * - * If the close is due to the process exiting, we never - * linger.. - */ - timeout = 0; - if (sock_flag(sk, SOCK_LINGER) && - !(current->flags & PF_EXITING)) - timeout = sk->sk_lingertime; - sock->sk = NULL; - sk->sk_prot->close(sk, timeout); - } - return 0; -} -EXPORT_SYMBOL(inet_release); - -int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) -{ - struct sockaddr_in *addr = (struct sockaddr_in *)uaddr; - struct sock *sk = sock->sk; - struct inet_sock *inet = inet_sk(sk); - struct net *net = sock_net(sk); - unsigned short snum; - int chk_addr_ret; - u32 tb_id = RT_TABLE_LOCAL; - int err; - - /* If the socket has its own bind function then use it. (RAW) */ - if (sk->sk_prot->bind) { - err = sk->sk_prot->bind(sk, uaddr, addr_len); - goto out; - } - err = -EINVAL; - if (addr_len < sizeof(struct sockaddr_in)) - goto out; - - if (addr->sin_family != AF_INET) { - /* Compatibility games : accept AF_UNSPEC (mapped to AF_INET) - * only if s_addr is INADDR_ANY. - */ - err = -EAFNOSUPPORT; - if (addr->sin_family != AF_UNSPEC || - addr->sin_addr.s_addr != htonl(INADDR_ANY)) - goto out; - } - - tb_id = l3mdev_fib_table_by_index(net, sk->sk_bound_dev_if) ? : tb_id; - chk_addr_ret = inet_addr_type_table(net, addr->sin_addr.s_addr, tb_id); - - /* Not specified by any standard per-se, however it breaks too - * many applications when removed. It is unfortunate since - * allowing applications to make a non-local bind solves - * several problems with systems using dynamic addressing. - * (ie. your servers still start up even if your ISDN link - * is temporarily down) - */ - err = -EADDRNOTAVAIL; - if (!net->ipv4.sysctl_ip_nonlocal_bind && - !(inet->freebind || inet->transparent) && - addr->sin_addr.s_addr != htonl(INADDR_ANY) && - chk_addr_ret != RTN_LOCAL && - chk_addr_ret != RTN_MULTICAST && - chk_addr_ret != RTN_BROADCAST) - goto out; - - snum = ntohs(addr->sin_port); - err = -EACCES; - if (snum && snum < PROT_SOCK && - !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) - goto out; - - /* We keep a pair of addresses. rcv_saddr is the one - * used by hash lookups, and saddr is used for transmit. - * - * In the BSD API these are the same except where it - * would be illegal to use them (multicast/broadcast) in - * which case the sending device address is used. - */ - lock_sock(sk); - - /* Check these errors (active socket, double bind). */ - err = -EINVAL; - if (sk->sk_state != TCP_CLOSE || inet->inet_num) - goto out_release_sock; - - inet->inet_rcv_saddr = inet->inet_saddr = addr->sin_addr.s_addr; - if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) - inet->inet_saddr = 0; /* Use device */ - - /* Make sure we are allowed to bind here. */ - if ((snum || !inet->bind_address_no_port) && - sk->sk_prot->get_port(sk, snum)) { - inet->inet_saddr = inet->inet_rcv_saddr = 0; - err = -EADDRINUSE; - goto out_release_sock; - } - - if (inet->inet_rcv_saddr) - sk->sk_userlocks |= SOCK_BINDADDR_LOCK; - if (snum) - sk->sk_userlocks |= SOCK_BINDPORT_LOCK; - inet->inet_sport = htons(inet->inet_num); - inet->inet_daddr = 0; - inet->inet_dport = 0; - sk_dst_reset(sk); - err = 0; -out_release_sock: - release_sock(sk); -out: - return err; -} -EXPORT_SYMBOL(inet_bind); - -int inet_dgram_connect(struct socket *sock, struct sockaddr *uaddr, - int addr_len, int flags) -{ - struct sock *sk = sock->sk; - - if (addr_len < sizeof(uaddr->sa_family)) - return -EINVAL; - if (uaddr->sa_family == AF_UNSPEC) - return sk->sk_prot->disconnect(sk, flags); - - if (!inet_sk(sk)->inet_num && inet_autobind(sk)) - return -EAGAIN; - return sk->sk_prot->connect(sk, uaddr, addr_len); -} -EXPORT_SYMBOL(inet_dgram_connect); - -static long inet_wait_for_connect(struct sock *sk, long timeo, int writebias) -{ - DEFINE_WAIT_FUNC(wait, woken_wake_function); - - add_wait_queue(sk_sleep(sk), &wait); - sk->sk_write_pending += writebias; - - /* Basic assumption: if someone sets sk->sk_err, he _must_ - * change state of the socket from TCP_SYN_*. - * Connect() does not allow to get error notifications - * without closing the socket. - */ - while ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { - release_sock(sk); - timeo = wait_woken(&wait, TASK_INTERRUPTIBLE, timeo); - lock_sock(sk); - if (signal_pending(current) || !timeo) - break; - } - remove_wait_queue(sk_sleep(sk), &wait); - sk->sk_write_pending -= writebias; - return timeo; -} - -/* - * Connect to a remote host. There is regrettably still a little - * TCP 'magic' in here. - */ -int __inet_stream_connect(struct socket *sock, struct sockaddr *uaddr, - int addr_len, int flags) -{ - struct sock *sk = sock->sk; - int err; - long timeo; - - if (addr_len < sizeof(uaddr->sa_family)) - return -EINVAL; - - if (uaddr->sa_family == AF_UNSPEC) { - err = sk->sk_prot->disconnect(sk, flags); - sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED; - goto out; - } - - switch (sock->state) { - default: - err = -EINVAL; - goto out; - case SS_CONNECTED: - err = -EISCONN; - goto out; - case SS_CONNECTING: - err = -EALREADY; - /* Fall out of switch with err, set for this state */ - break; - case SS_UNCONNECTED: - err = -EISCONN; - if (sk->sk_state != TCP_CLOSE) - goto out; - - err = sk->sk_prot->connect(sk, uaddr, addr_len); - if (err < 0) - goto out; - - sock->state = SS_CONNECTING; - - /* Just entered SS_CONNECTING state; the only - * difference is that return value in non-blocking - * case is EINPROGRESS, rather than EALREADY. - */ - err = -EINPROGRESS; - break; - } - - timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); - - if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { - int writebias = (sk->sk_protocol == IPPROTO_TCP) && - tcp_sk(sk)->fastopen_req && - tcp_sk(sk)->fastopen_req->data ? 1 : 0; - - /* Error code is set above */ - if (!timeo || !inet_wait_for_connect(sk, timeo, writebias)) - goto out; - - err = sock_intr_errno(timeo); - if (signal_pending(current)) - goto out; - } - - /* Connection was closed by RST, timeout, ICMP error - * or another process disconnected us. - */ - if (sk->sk_state == TCP_CLOSE) - goto sock_error; - - /* sk->sk_err may be not zero now, if RECVERR was ordered by user - * and error was received after socket entered established state. - * Hence, it is handled normally after connect() return successfully. - */ - - sock->state = SS_CONNECTED; - err = 0; -out: - return err; - -sock_error: - err = sock_error(sk) ? : -ECONNABORTED; - sock->state = SS_UNCONNECTED; - if (sk->sk_prot->disconnect(sk, flags)) - sock->state = SS_DISCONNECTING; - goto out; -} -EXPORT_SYMBOL(__inet_stream_connect); - -int inet_stream_connect(struct socket *sock, struct sockaddr *uaddr, - int addr_len, int flags) -{ - int err; - - lock_sock(sock->sk); - err = __inet_stream_connect(sock, uaddr, addr_len, flags); - release_sock(sock->sk); - return err; -} -EXPORT_SYMBOL(inet_stream_connect); - -/* - * Accept a pending connection. The TCP layer now gives BSD semantics. - */ - -int inet_accept(struct socket *sock, struct socket *newsock, int flags) -{ - struct sock *sk1 = sock->sk; - int err = -EINVAL; - struct sock *sk2 = sk1->sk_prot->accept(sk1, flags, &err); - - if (!sk2) - goto do_err; - - lock_sock(sk2); - - sock_rps_record_flow(sk2); - WARN_ON(!((1 << sk2->sk_state) & - (TCPF_ESTABLISHED | TCPF_SYN_RECV | - TCPF_CLOSE_WAIT | TCPF_CLOSE))); - - sock_graft(sk2, newsock); - - newsock->state = SS_CONNECTED; - err = 0; - release_sock(sk2); -do_err: - return err; -} -EXPORT_SYMBOL(inet_accept); - - -/* - * This does both peername and sockname. - */ -int inet_getname(struct socket *sock, struct sockaddr *uaddr, - int *uaddr_len, int peer) -{ - struct sock *sk = sock->sk; - struct inet_sock *inet = inet_sk(sk); - DECLARE_SOCKADDR(struct sockaddr_in *, sin, uaddr); - - sin->sin_family = AF_INET; - if (peer) { - if (!inet->inet_dport || - (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) && - peer == 1)) - return -ENOTCONN; - sin->sin_port = inet->inet_dport; - sin->sin_addr.s_addr = inet->inet_daddr; - } else { - __be32 addr = inet->inet_rcv_saddr; - if (!addr) - addr = inet->inet_saddr; - sin->sin_port = inet->inet_sport; - sin->sin_addr.s_addr = addr; - } - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - *uaddr_len = sizeof(*sin); - return 0; -} -EXPORT_SYMBOL(inet_getname); - -int inet_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) -{ - struct sock *sk = sock->sk; - - sock_rps_record_flow(sk); - - /* We may need to bind the socket. */ - if (!inet_sk(sk)->inet_num && !sk->sk_prot->no_autobind && - inet_autobind(sk)) - return -EAGAIN; - - return sk->sk_prot->sendmsg(sk, msg, size); -} -EXPORT_SYMBOL(inet_sendmsg); - -ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset, - size_t size, int flags) -{ - struct sock *sk = sock->sk; - - sock_rps_record_flow(sk); - - /* We may need to bind the socket. */ - if (!inet_sk(sk)->inet_num && !sk->sk_prot->no_autobind && - inet_autobind(sk)) - return -EAGAIN; - - if (sk->sk_prot->sendpage) - return sk->sk_prot->sendpage(sk, page, offset, size, flags); - return sock_no_sendpage(sock, page, offset, size, flags); -} -EXPORT_SYMBOL(inet_sendpage); - -int inet_recvmsg(struct socket *sock, struct msghdr *msg, size_t size, - int flags) -{ - struct sock *sk = sock->sk; - int addr_len = 0; - int err; - - sock_rps_record_flow(sk); - - err = sk->sk_prot->recvmsg(sk, msg, size, flags & MSG_DONTWAIT, - flags & ~MSG_DONTWAIT, &addr_len); - if (err >= 0) - msg->msg_namelen = addr_len; - return err; -} -EXPORT_SYMBOL(inet_recvmsg); - -int inet_shutdown(struct socket *sock, int how) -{ - struct sock *sk = sock->sk; - int err = 0; - - /* This should really check to make sure - * the socket is a TCP socket. (WHY AC...) - */ - how++; /* maps 0->1 has the advantage of making bit 1 rcvs and - 1->2 bit 2 snds. - 2->3 */ - if ((how & ~SHUTDOWN_MASK) || !how) /* MAXINT->0 */ - return -EINVAL; - - lock_sock(sk); - if (sock->state == SS_CONNECTING) { - if ((1 << sk->sk_state) & - (TCPF_SYN_SENT | TCPF_SYN_RECV | TCPF_CLOSE)) - sock->state = SS_DISCONNECTING; - else - sock->state = SS_CONNECTED; - } - - switch (sk->sk_state) { - case TCP_CLOSE: - err = -ENOTCONN; - /* Hack to wake up other listeners, who can poll for - POLLHUP, even on eg. unconnected UDP sockets -- RR */ - default: - sk->sk_shutdown |= how; - if (sk->sk_prot->shutdown) - sk->sk_prot->shutdown(sk, how); - break; - - /* Remaining two branches are temporary solution for missing - * close() in multithreaded environment. It is _not_ a good idea, - * but we have no choice until close() is repaired at VFS level. - */ - case TCP_LISTEN: - if (!(how & RCV_SHUTDOWN)) - break; - /* Fall through */ - case TCP_SYN_SENT: - err = sk->sk_prot->disconnect(sk, O_NONBLOCK); - sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED; - break; - } - - /* Wake up anyone sleeping in poll. */ - sk->sk_state_change(sk); - release_sock(sk); - return err; -} -EXPORT_SYMBOL(inet_shutdown); - -/* - * ioctl() calls you can issue on an INET socket. Most of these are - * device configuration and stuff and very rarely used. Some ioctls - * pass on to the socket itself. - * - * NOTE: I like the idea of a module for the config stuff. ie ifconfig - * loads the devconfigure module does its configuring and unloads it. - * There's a good 20K of config code hanging around the kernel. - */ - -int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - struct sock *sk = sock->sk; - int err = 0; - struct net *net = sock_net(sk); - - switch (cmd) { - case SIOCGSTAMP: - err = sock_get_timestamp(sk, (struct timeval __user *)arg); - break; - case SIOCGSTAMPNS: - err = sock_get_timestampns(sk, (struct timespec __user *)arg); - break; - case SIOCADDRT: - case SIOCDELRT: - case SIOCRTMSG: - err = ip_rt_ioctl(net, cmd, (void __user *)arg); - break; - case SIOCDARP: - case SIOCGARP: - case SIOCSARP: - err = arp_ioctl(net, cmd, (void __user *)arg); - break; - case SIOCGIFADDR: - case SIOCSIFADDR: - case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - case SIOCSIFPFLAGS: - case SIOCGIFPFLAGS: - case SIOCSIFFLAGS: - err = devinet_ioctl(net, cmd, (void __user *)arg); - break; - default: - if (sk->sk_prot->ioctl) - err = sk->sk_prot->ioctl(sk, cmd, arg); - else - err = -ENOIOCTLCMD; - break; - } - return err; -} -EXPORT_SYMBOL(inet_ioctl); - -#ifdef CONFIG_COMPAT -static int inet_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - struct sock *sk = sock->sk; - int err = -ENOIOCTLCMD; - - if (sk->sk_prot->compat_ioctl) - err = sk->sk_prot->compat_ioctl(sk, cmd, arg); - - return err; -} -#endif - -const struct proto_ops inet_stream_ops = { - .family = PF_INET, - .owner = THIS_MODULE, - .release = inet_release, - .bind = inet_bind, - .connect = inet_stream_connect, - .socketpair = sock_no_socketpair, - .accept = inet_accept, - .getname = inet_getname, - .poll = tcp_poll, - .ioctl = inet_ioctl, - .listen = inet_listen, - .shutdown = inet_shutdown, - .setsockopt = sock_common_setsockopt, - .getsockopt = sock_common_getsockopt, - .sendmsg = inet_sendmsg, - .recvmsg = inet_recvmsg, - .mmap = sock_no_mmap, - .sendpage = inet_sendpage, - .splice_read = tcp_splice_read, - .read_sock = tcp_read_sock, - .peek_len = tcp_peek_len, -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_sock_common_setsockopt, - .compat_getsockopt = compat_sock_common_getsockopt, - .compat_ioctl = inet_compat_ioctl, -#endif -}; -EXPORT_SYMBOL(inet_stream_ops); - -const struct proto_ops inet_dgram_ops = { - .family = PF_INET, - .owner = THIS_MODULE, - .release = inet_release, - .bind = inet_bind, - .connect = inet_dgram_connect, - .socketpair = sock_no_socketpair, - .accept = sock_no_accept, - .getname = inet_getname, - .poll = udp_poll, - .ioctl = inet_ioctl, - .listen = sock_no_listen, - .shutdown = inet_shutdown, - .setsockopt = sock_common_setsockopt, - .getsockopt = sock_common_getsockopt, - .sendmsg = inet_sendmsg, - .recvmsg = inet_recvmsg, - .mmap = sock_no_mmap, - .sendpage = inet_sendpage, - .set_peek_off = sk_set_peek_off, -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_sock_common_setsockopt, - .compat_getsockopt = compat_sock_common_getsockopt, - .compat_ioctl = inet_compat_ioctl, -#endif -}; -EXPORT_SYMBOL(inet_dgram_ops); - -/* - * For SOCK_RAW sockets; should be the same as inet_dgram_ops but without - * udp_poll - */ -static const struct proto_ops inet_sockraw_ops = { - .family = PF_INET, - .owner = THIS_MODULE, - .release = inet_release, - .bind = inet_bind, - .connect = inet_dgram_connect, - .socketpair = sock_no_socketpair, - .accept = sock_no_accept, - .getname = inet_getname, - .poll = datagram_poll, - .ioctl = inet_ioctl, - .listen = sock_no_listen, - .shutdown = inet_shutdown, - .setsockopt = sock_common_setsockopt, - .getsockopt = sock_common_getsockopt, - .sendmsg = inet_sendmsg, - .recvmsg = inet_recvmsg, - .mmap = sock_no_mmap, - .sendpage = inet_sendpage, -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_sock_common_setsockopt, - .compat_getsockopt = compat_sock_common_getsockopt, - .compat_ioctl = inet_compat_ioctl, -#endif -}; - -static const struct net_proto_family inet_family_ops = { - .family = PF_INET, - .create = inet_create, - .owner = THIS_MODULE, -}; - -/* Upon startup we insert all the elements in inetsw_array[] into - * the linked list inetsw. - */ -static struct inet_protosw inetsw_array[] = -{ - { - .type = SOCK_STREAM, - .protocol = IPPROTO_TCP, - .prot = &tcp_prot, - .ops = &inet_stream_ops, - .flags = INET_PROTOSW_PERMANENT | - INET_PROTOSW_ICSK, - }, - - { - .type = SOCK_DGRAM, - .protocol = IPPROTO_UDP, - .prot = &udp_prot, - .ops = &inet_dgram_ops, - .flags = INET_PROTOSW_PERMANENT, - }, - - { - .type = SOCK_DGRAM, - .protocol = IPPROTO_ICMP, - .prot = &ping_prot, - .ops = &inet_dgram_ops, - .flags = INET_PROTOSW_REUSE, - }, - - { - .type = SOCK_RAW, - .protocol = IPPROTO_IP, /* wild card */ - .prot = &raw_prot, - .ops = &inet_sockraw_ops, - .flags = INET_PROTOSW_REUSE, - } -}; - -#define INETSW_ARRAY_LEN ARRAY_SIZE(inetsw_array) - -void inet_register_protosw(struct inet_protosw *p) -{ - struct list_head *lh; - struct inet_protosw *answer; - int protocol = p->protocol; - struct list_head *last_perm; - - spin_lock_bh(&inetsw_lock); - - if (p->type >= SOCK_MAX) - goto out_illegal; - - /* If we are trying to override a permanent protocol, bail. */ - last_perm = &inetsw[p->type]; - list_for_each(lh, &inetsw[p->type]) { - answer = list_entry(lh, struct inet_protosw, list); - /* Check only the non-wild match. */ - if ((INET_PROTOSW_PERMANENT & answer->flags) == 0) - break; - if (protocol == answer->protocol) - goto out_permanent; - last_perm = lh; - } - - /* Add the new entry after the last permanent entry if any, so that - * the new entry does not override a permanent entry when matched with - * a wild-card protocol. But it is allowed to override any existing - * non-permanent entry. This means that when we remove this entry, the - * system automatically returns to the old behavior. - */ - list_add_rcu(&p->list, last_perm); -out: - spin_unlock_bh(&inetsw_lock); - - return; - -out_permanent: - pr_err("Attempt to override permanent protocol %d\n", protocol); - goto out; - -out_illegal: - pr_err("Ignoring attempt to register invalid socket type %d\n", - p->type); - goto out; -} -EXPORT_SYMBOL(inet_register_protosw); - -void inet_unregister_protosw(struct inet_protosw *p) -{ - if (INET_PROTOSW_PERMANENT & p->flags) { - pr_err("Attempt to unregister permanent protocol %d\n", - p->protocol); - } else { - spin_lock_bh(&inetsw_lock); - list_del_rcu(&p->list); - spin_unlock_bh(&inetsw_lock); - - synchronize_net(); - } -} -EXPORT_SYMBOL(inet_unregister_protosw); - -static int inet_sk_reselect_saddr(struct sock *sk) -{ - struct inet_sock *inet = inet_sk(sk); - __be32 old_saddr = inet->inet_saddr; - __be32 daddr = inet->inet_daddr; - struct flowi4 *fl4; - struct rtable *rt; - __be32 new_saddr; - struct ip_options_rcu *inet_opt; - - inet_opt = rcu_dereference_protected(inet->inet_opt, - lockdep_sock_is_held(sk)); - if (inet_opt && inet_opt->opt.srr) - daddr = inet_opt->opt.faddr; - - /* Query new route. */ - fl4 = &inet->cork.fl.u.ip4; - rt = ip_route_connect(fl4, daddr, 0, RT_CONN_FLAGS(sk), - sk->sk_bound_dev_if, sk->sk_protocol, - inet->inet_sport, inet->inet_dport, sk); - if (IS_ERR(rt)) - return PTR_ERR(rt); - - sk_setup_caps(sk, &rt->dst); - - new_saddr = fl4->saddr; - - if (new_saddr == old_saddr) - return 0; - - if (sock_net(sk)->ipv4.sysctl_ip_dynaddr > 1) { - pr_info("%s(): shifting inet->saddr from %pI4 to %pI4\n", - __func__, &old_saddr, &new_saddr); - } - - inet->inet_saddr = inet->inet_rcv_saddr = new_saddr; - - /* - * XXX The only one ugly spot where we need to - * XXX really change the sockets identity after - * XXX it has entered the hashes. -DaveM - * - * Besides that, it does not check for connection - * uniqueness. Wait for troubles. - */ - return __sk_prot_rehash(sk); -} - -int inet_sk_rebuild_header(struct sock *sk) -{ - struct inet_sock *inet = inet_sk(sk); - struct rtable *rt = (struct rtable *)__sk_dst_check(sk, 0); - __be32 daddr; - struct ip_options_rcu *inet_opt; - struct flowi4 *fl4; - int err; - - /* Route is OK, nothing to do. */ - if (rt) - return 0; - - /* Reroute. */ - rcu_read_lock(); - inet_opt = rcu_dereference(inet->inet_opt); - daddr = inet->inet_daddr; - if (inet_opt && inet_opt->opt.srr) - daddr = inet_opt->opt.faddr; - rcu_read_unlock(); - fl4 = &inet->cork.fl.u.ip4; - rt = ip_route_output_ports(sock_net(sk), fl4, sk, daddr, inet->inet_saddr, - inet->inet_dport, inet->inet_sport, - sk->sk_protocol, RT_CONN_FLAGS(sk), - sk->sk_bound_dev_if); - if (!IS_ERR(rt)) { - err = 0; - sk_setup_caps(sk, &rt->dst); - } else { - err = PTR_ERR(rt); - - /* Routing failed... */ - sk->sk_route_caps = 0; - /* - * Other protocols have to map its equivalent state to TCP_SYN_SENT. - * DCCP maps its DCCP_REQUESTING state to TCP_SYN_SENT. -acme - */ - if (!sock_net(sk)->ipv4.sysctl_ip_dynaddr || - sk->sk_state != TCP_SYN_SENT || - (sk->sk_userlocks & SOCK_BINDADDR_LOCK) || - (err = inet_sk_reselect_saddr(sk)) != 0) - sk->sk_err_soft = -err; - } - - return err; -} -EXPORT_SYMBOL(inet_sk_rebuild_header); - -struct sk_buff *inet_gso_segment(struct sk_buff *skb, - netdev_features_t features) -{ - bool udpfrag = false, fixedid = false, gso_partial, encap; - struct sk_buff *segs = ERR_PTR(-EINVAL); - const struct net_offload *ops; - unsigned int offset = 0; - struct iphdr *iph; - int proto, tot_len; - int nhoff; - int ihl; - int id; - - skb_reset_network_header(skb); - nhoff = skb_network_header(skb) - skb_mac_header(skb); - if (unlikely(!pskb_may_pull(skb, sizeof(*iph)))) - goto out; - - iph = ip_hdr(skb); - ihl = iph->ihl * 4; - if (ihl < sizeof(*iph)) - goto out; - - id = ntohs(iph->id); - proto = iph->protocol; - - /* Warning: after this point, iph might be no longer valid */ - if (unlikely(!pskb_may_pull(skb, ihl))) - goto out; - __skb_pull(skb, ihl); - - encap = SKB_GSO_CB(skb)->encap_level > 0; - if (encap) - features &= skb->dev->hw_enc_features; - SKB_GSO_CB(skb)->encap_level += ihl; - - skb_reset_transport_header(skb); - - segs = ERR_PTR(-EPROTONOSUPPORT); - - if (!skb->encapsulation || encap) { - udpfrag = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP); - fixedid = !!(skb_shinfo(skb)->gso_type & SKB_GSO_TCP_FIXEDID); - - /* fixed ID is invalid if DF bit is not set */ - if (fixedid && !(ip_hdr(skb)->frag_off & htons(IP_DF))) - goto out; - } - - ops = rcu_dereference(inet_offloads[proto]); - if (likely(ops && ops->callbacks.gso_segment)) - segs = ops->callbacks.gso_segment(skb, features); - - if (IS_ERR_OR_NULL(segs)) - goto out; - - gso_partial = !!(skb_shinfo(segs)->gso_type & SKB_GSO_PARTIAL); - - skb = segs; - do { - iph = (struct iphdr *)(skb_mac_header(skb) + nhoff); - if (udpfrag) { - iph->frag_off = htons(offset >> 3); - if (skb->next) - iph->frag_off |= htons(IP_MF); - offset += skb->len - nhoff - ihl; - tot_len = skb->len - nhoff; - } else if (skb_is_gso(skb)) { - if (!fixedid) { - iph->id = htons(id); - id += skb_shinfo(skb)->gso_segs; - } - - if (gso_partial) - tot_len = skb_shinfo(skb)->gso_size + - SKB_GSO_CB(skb)->data_offset + - skb->head - (unsigned char *)iph; - else - tot_len = skb->len - nhoff; - } else { - if (!fixedid) - iph->id = htons(id++); - tot_len = skb->len - nhoff; - } - iph->tot_len = htons(tot_len); - ip_send_check(iph); - if (encap) - skb_reset_inner_headers(skb); - skb->network_header = (u8 *)iph - skb->head; - } while ((skb = skb->next)); - -out: - return segs; -} -EXPORT_SYMBOL(inet_gso_segment); - -struct sk_buff **inet_gro_receive(struct sk_buff **head, struct sk_buff *skb) -{ - const struct net_offload *ops; - struct sk_buff **pp = NULL; - struct sk_buff *p; - const struct iphdr *iph; - unsigned int hlen; - unsigned int off; - unsigned int id; - int flush = 1; - int proto; - - off = skb_gro_offset(skb); - hlen = off + sizeof(*iph); - iph = skb_gro_header_fast(skb, off); - if (skb_gro_header_hard(skb, hlen)) { - iph = skb_gro_header_slow(skb, hlen, off); - if (unlikely(!iph)) - goto out; - } - - proto = iph->protocol; - - rcu_read_lock(); - ops = rcu_dereference(inet_offloads[proto]); - if (!ops || !ops->callbacks.gro_receive) - goto out_unlock; - - if (*(u8 *)iph != 0x45) - goto out_unlock; - - if (unlikely(ip_fast_csum((u8 *)iph, 5))) - goto out_unlock; - - id = ntohl(*(__be32 *)&iph->id); - flush = (u16)((ntohl(*(__be32 *)iph) ^ skb_gro_len(skb)) | (id & ~IP_DF)); - id >>= 16; - - for (p = *head; p; p = p->next) { - struct iphdr *iph2; - u16 flush_id; - - if (!NAPI_GRO_CB(p)->same_flow) - continue; - - iph2 = (struct iphdr *)(p->data + off); - /* The above works because, with the exception of the top - * (inner most) layer, we only aggregate pkts with the same - * hdr length so all the hdrs we'll need to verify will start - * at the same offset. - */ - if ((iph->protocol ^ iph2->protocol) | - ((__force u32)iph->saddr ^ (__force u32)iph2->saddr) | - ((__force u32)iph->daddr ^ (__force u32)iph2->daddr)) { - NAPI_GRO_CB(p)->same_flow = 0; - continue; - } - - /* All fields must match except length and checksum. */ - NAPI_GRO_CB(p)->flush |= - (iph->ttl ^ iph2->ttl) | - (iph->tos ^ iph2->tos) | - ((iph->frag_off ^ iph2->frag_off) & htons(IP_DF)); - - NAPI_GRO_CB(p)->flush |= flush; - - /* We need to store of the IP ID check to be included later - * when we can verify that this packet does in fact belong - * to a given flow. - */ - flush_id = (u16)(id - ntohs(iph2->id)); - - /* This bit of code makes it much easier for us to identify - * the cases where we are doing atomic vs non-atomic IP ID - * checks. Specifically an atomic check can return IP ID - * values 0 - 0xFFFF, while a non-atomic check can only - * return 0 or 0xFFFF. - */ - if (!NAPI_GRO_CB(p)->is_atomic || - !(iph->frag_off & htons(IP_DF))) { - flush_id ^= NAPI_GRO_CB(p)->count; - flush_id = flush_id ? 0xFFFF : 0; - } - - /* If the previous IP ID value was based on an atomic - * datagram we can overwrite the value and ignore it. - */ - if (NAPI_GRO_CB(skb)->is_atomic) - NAPI_GRO_CB(p)->flush_id = flush_id; - else - NAPI_GRO_CB(p)->flush_id |= flush_id; - } - - NAPI_GRO_CB(skb)->is_atomic = !!(iph->frag_off & htons(IP_DF)); - NAPI_GRO_CB(skb)->flush |= flush; - skb_set_network_header(skb, off); - /* The above will be needed by the transport layer if there is one - * immediately following this IP hdr. - */ - - /* Note : No need to call skb_gro_postpull_rcsum() here, - * as we already checked checksum over ipv4 header was 0 - */ - skb_gro_pull(skb, sizeof(*iph)); - skb_set_transport_header(skb, skb_gro_offset(skb)); - - pp = call_gro_receive(ops->callbacks.gro_receive, head, skb); - -out_unlock: - rcu_read_unlock(); - -out: - NAPI_GRO_CB(skb)->flush |= flush; - - return pp; -} -EXPORT_SYMBOL(inet_gro_receive); - -static struct sk_buff **ipip_gro_receive(struct sk_buff **head, - struct sk_buff *skb) -{ - if (NAPI_GRO_CB(skb)->encap_mark) { - NAPI_GRO_CB(skb)->flush = 1; - return NULL; - } - - NAPI_GRO_CB(skb)->encap_mark = 1; - - return inet_gro_receive(head, skb); -} - -#define SECONDS_PER_DAY 86400 - -/* inet_current_timestamp - Return IP network timestamp - * - * Return milliseconds since midnight in network byte order. - */ -__be32 inet_current_timestamp(void) -{ - u32 secs; - u32 msecs; - struct timespec64 ts; - - ktime_get_real_ts64(&ts); - - /* Get secs since midnight. */ - (void)div_u64_rem(ts.tv_sec, SECONDS_PER_DAY, &secs); - /* Convert to msecs. */ - msecs = secs * MSEC_PER_SEC; - /* Convert nsec to msec. */ - msecs += (u32)ts.tv_nsec / NSEC_PER_MSEC; - - /* Convert to network byte order. */ - return htonl(msecs); -} -EXPORT_SYMBOL(inet_current_timestamp); - -int inet_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) -{ - if (sk->sk_family == AF_INET) - return ip_recv_error(sk, msg, len, addr_len); -#if IS_ENABLED(CONFIG_IPV6) - if (sk->sk_family == AF_INET6) - return pingv6_ops.ipv6_recv_error(sk, msg, len, addr_len); -#endif - return -EINVAL; -} - -int inet_gro_complete(struct sk_buff *skb, int nhoff) -{ - __be16 newlen = htons(skb->len - nhoff); - struct iphdr *iph = (struct iphdr *)(skb->data + nhoff); - const struct net_offload *ops; - int proto = iph->protocol; - int err = -ENOSYS; - - if (skb->encapsulation) - skb_set_inner_network_header(skb, nhoff); - - csum_replace2(&iph->check, iph->tot_len, newlen); - iph->tot_len = newlen; - - rcu_read_lock(); - ops = rcu_dereference(inet_offloads[proto]); - if (WARN_ON(!ops || !ops->callbacks.gro_complete)) - goto out_unlock; - - /* Only need to add sizeof(*iph) to get to the next hdr below - * because any hdr with option will have been flushed in - * inet_gro_receive(). - */ - err = ops->callbacks.gro_complete(skb, nhoff + sizeof(*iph)); - -out_unlock: - rcu_read_unlock(); - - return err; -} -EXPORT_SYMBOL(inet_gro_complete); - -static int ipip_gro_complete(struct sk_buff *skb, int nhoff) -{ - skb->encapsulation = 1; - skb_shinfo(skb)->gso_type |= SKB_GSO_IPXIP4; - return inet_gro_complete(skb, nhoff); -} - -int inet_ctl_sock_create(struct sock **sk, unsigned short family, - unsigned short type, unsigned char protocol, - struct net *net) -{ - struct socket *sock; - int rc = sock_create_kern(net, family, type, protocol, &sock); - - if (rc == 0) { - *sk = sock->sk; - (*sk)->sk_allocation = GFP_ATOMIC; - /* - * Unhash it so that IP input processing does not even see it, - * we do not wish this socket to see incoming packets. - */ - (*sk)->sk_prot->unhash(*sk); - } - return rc; -} -EXPORT_SYMBOL_GPL(inet_ctl_sock_create); - -u64 snmp_get_cpu_field(void __percpu *mib, int cpu, int offt) -{ - return *(((unsigned long *)per_cpu_ptr(mib, cpu)) + offt); -} -EXPORT_SYMBOL_GPL(snmp_get_cpu_field); - -unsigned long snmp_fold_field(void __percpu *mib, int offt) -{ - unsigned long res = 0; - int i; - - for_each_possible_cpu(i) - res += snmp_get_cpu_field(mib, i, offt); - return res; -} -EXPORT_SYMBOL_GPL(snmp_fold_field); - -#if BITS_PER_LONG==32 - -u64 snmp_get_cpu_field64(void __percpu *mib, int cpu, int offt, - size_t syncp_offset) -{ - void *bhptr; - struct u64_stats_sync *syncp; - u64 v; - unsigned int start; - - bhptr = per_cpu_ptr(mib, cpu); - syncp = (struct u64_stats_sync *)(bhptr + syncp_offset); - do { - start = u64_stats_fetch_begin_irq(syncp); - v = *(((u64 *)bhptr) + offt); - } while (u64_stats_fetch_retry_irq(syncp, start)); - - return v; -} -EXPORT_SYMBOL_GPL(snmp_get_cpu_field64); - -u64 snmp_fold_field64(void __percpu *mib, int offt, size_t syncp_offset) -{ - u64 res = 0; - int cpu; - - for_each_possible_cpu(cpu) { - res += snmp_get_cpu_field64(mib, cpu, offt, syncp_offset); - } - return res; -} -EXPORT_SYMBOL_GPL(snmp_fold_field64); -#endif - -#ifdef CONFIG_IP_MULTICAST -static const struct net_protocol igmp_protocol = { - .handler = igmp_rcv, - .netns_ok = 1, -}; -#endif - -static const struct net_protocol tcp_protocol = { - .early_demux = tcp_v4_early_demux, - .handler = tcp_v4_rcv, - .err_handler = tcp_v4_err, - .no_policy = 1, - .netns_ok = 1, - .icmp_strict_tag_validation = 1, -}; - -static const struct net_protocol udp_protocol = { - .early_demux = udp_v4_early_demux, - .handler = udp_rcv, - .err_handler = udp_err, - .no_policy = 1, - .netns_ok = 1, -}; - -static const struct net_protocol icmp_protocol = { - .handler = icmp_rcv, - .err_handler = icmp_err, - .no_policy = 1, - .netns_ok = 1, -}; - -static __net_init int ipv4_mib_init_net(struct net *net) -{ - int i; - - net->mib.tcp_statistics = alloc_percpu(struct tcp_mib); - if (!net->mib.tcp_statistics) - goto err_tcp_mib; - net->mib.ip_statistics = alloc_percpu(struct ipstats_mib); - if (!net->mib.ip_statistics) - goto err_ip_mib; - - for_each_possible_cpu(i) { - struct ipstats_mib *af_inet_stats; - af_inet_stats = per_cpu_ptr(net->mib.ip_statistics, i); - u64_stats_init(&af_inet_stats->syncp); - } - - net->mib.net_statistics = alloc_percpu(struct linux_mib); - if (!net->mib.net_statistics) - goto err_net_mib; - net->mib.udp_statistics = alloc_percpu(struct udp_mib); - if (!net->mib.udp_statistics) - goto err_udp_mib; - net->mib.udplite_statistics = alloc_percpu(struct udp_mib); - if (!net->mib.udplite_statistics) - goto err_udplite_mib; - net->mib.icmp_statistics = alloc_percpu(struct icmp_mib); - if (!net->mib.icmp_statistics) - goto err_icmp_mib; - net->mib.icmpmsg_statistics = kzalloc(sizeof(struct icmpmsg_mib), - GFP_KERNEL); - if (!net->mib.icmpmsg_statistics) - goto err_icmpmsg_mib; - - tcp_mib_init(net); - return 0; - -err_icmpmsg_mib: - free_percpu(net->mib.icmp_statistics); -err_icmp_mib: - free_percpu(net->mib.udplite_statistics); -err_udplite_mib: - free_percpu(net->mib.udp_statistics); -err_udp_mib: - free_percpu(net->mib.net_statistics); -err_net_mib: - free_percpu(net->mib.ip_statistics); -err_ip_mib: - free_percpu(net->mib.tcp_statistics); -err_tcp_mib: - return -ENOMEM; -} - -static __net_exit void ipv4_mib_exit_net(struct net *net) -{ - kfree(net->mib.icmpmsg_statistics); - free_percpu(net->mib.icmp_statistics); - free_percpu(net->mib.udplite_statistics); - free_percpu(net->mib.udp_statistics); - free_percpu(net->mib.net_statistics); - free_percpu(net->mib.ip_statistics); - free_percpu(net->mib.tcp_statistics); -} - -static __net_initdata struct pernet_operations ipv4_mib_ops = { - .init = ipv4_mib_init_net, - .exit = ipv4_mib_exit_net, -}; - -static int __init init_ipv4_mibs(void) -{ - return register_pernet_subsys(&ipv4_mib_ops); -} - -static __net_init int inet_init_net(struct net *net) -{ - /* - * Set defaults for local port range - */ - seqlock_init(&net->ipv4.ip_local_ports.lock); - net->ipv4.ip_local_ports.range[0] = 32768; - net->ipv4.ip_local_ports.range[1] = 60999; - - seqlock_init(&net->ipv4.ping_group_range.lock); - /* - * Sane defaults - nobody may create ping sockets. - * Boot scripts should set this to distro-specific group. - */ - net->ipv4.ping_group_range.range[0] = make_kgid(&init_user_ns, 1); - net->ipv4.ping_group_range.range[1] = make_kgid(&init_user_ns, 0); - - /* Default values for sysctl-controlled parameters. - * We set them here, in case sysctl is not compiled. - */ - net->ipv4.sysctl_ip_default_ttl = IPDEFTTL; - net->ipv4.sysctl_ip_dynaddr = 0; - net->ipv4.sysctl_ip_early_demux = 1; - - return 0; -} - -static __net_exit void inet_exit_net(struct net *net) -{ -} - -static __net_initdata struct pernet_operations af_inet_ops = { - .init = inet_init_net, - .exit = inet_exit_net, -}; - -static int __init init_inet_pernet_ops(void) -{ - return register_pernet_subsys(&af_inet_ops); -} - -static int ipv4_proc_init(void); - -/* - * IP protocol layer initialiser - */ - -static struct packet_offload ip_packet_offload __read_mostly = { - .type = cpu_to_be16(ETH_P_IP), - .callbacks = { - .gso_segment = inet_gso_segment, - .gro_receive = inet_gro_receive, - .gro_complete = inet_gro_complete, - }, -}; - -static const struct net_offload ipip_offload = { - .callbacks = { - .gso_segment = inet_gso_segment, - .gro_receive = ipip_gro_receive, - .gro_complete = ipip_gro_complete, - }, -}; - -static int __init ipv4_offload_init(void) -{ - /* - * Add offloads - */ - if (udpv4_offload_init() < 0) - pr_crit("%s: Cannot add UDP protocol offload\n", __func__); - if (tcpv4_offload_init() < 0) - pr_crit("%s: Cannot add TCP protocol offload\n", __func__); - - dev_add_offload(&ip_packet_offload); - inet_add_offload(&ipip_offload, IPPROTO_IPIP); - return 0; -} - -fs_initcall(ipv4_offload_init); - -static struct packet_type ip_packet_type __read_mostly = { - .type = cpu_to_be16(ETH_P_IP), - .func = ip_rcv, -}; - -static int __init inet_init(void) -{ - struct inet_protosw *q; - struct list_head *r; - int rc = -EINVAL; - - sock_skb_cb_check_size(sizeof(struct inet_skb_parm)); - - rc = proto_register(&tcp_prot, 1); - if (rc) - goto out; - - rc = proto_register(&udp_prot, 1); - if (rc) - goto out_unregister_tcp_proto; - - rc = proto_register(&raw_prot, 1); - if (rc) - goto out_unregister_udp_proto; - - rc = proto_register(&ping_prot, 1); - if (rc) - goto out_unregister_raw_proto; - - /* - * Tell SOCKET that we are alive... - */ - - (void)sock_register(&inet_family_ops); - -#ifdef CONFIG_SYSCTL - ip_static_sysctl_init(); -#endif - - /* - * Add all the base protocols. - */ - - if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0) - pr_crit("%s: Cannot add ICMP protocol\n", __func__); - if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0) - pr_crit("%s: Cannot add UDP protocol\n", __func__); - if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0) - pr_crit("%s: Cannot add TCP protocol\n", __func__); -#ifdef CONFIG_IP_MULTICAST - if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0) - pr_crit("%s: Cannot add IGMP protocol\n", __func__); -#endif - - /* Register the socket-side information for inet_create. */ - for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r) - INIT_LIST_HEAD(r); - - for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q) - inet_register_protosw(q); - - /* - * Set the ARP module up - */ - - arp_init(); - - /* - * Set the IP module up - */ - - ip_init(); - - tcp_v4_init(); - - /* Setup TCP slab cache for open requests. */ - tcp_init(); - - /* Setup UDP memory threshold */ - udp_init(); - - /* Add UDP-Lite (RFC 3828) */ - udplite4_register(); - - ping_init(); - - /* - * Set the ICMP layer up - */ - - if (icmp_init() < 0) - panic("Failed to create the ICMP control socket.\n"); - - /* - * Initialise the multicast router - */ -#if defined(CONFIG_IP_MROUTE) - if (ip_mr_init()) - pr_crit("%s: Cannot init ipv4 mroute\n", __func__); -#endif - - if (init_inet_pernet_ops()) - pr_crit("%s: Cannot init ipv4 inet pernet ops\n", __func__); - /* - * Initialise per-cpu ipv4 mibs - */ - - if (init_ipv4_mibs()) - pr_crit("%s: Cannot init ipv4 mibs\n", __func__); - - ipv4_proc_init(); - - ipfrag_init(); - - dev_add_pack(&ip_packet_type); - - ip_tunnel_core_init(); - - rc = 0; -out: - return rc; -out_unregister_raw_proto: - proto_unregister(&raw_prot); -out_unregister_udp_proto: - proto_unregister(&udp_prot); -out_unregister_tcp_proto: - proto_unregister(&tcp_prot); - goto out; -} - -fs_initcall(inet_init); - -/* ------------------------------------------------------------------------ */ - -#ifdef CONFIG_PROC_FS -static int __init ipv4_proc_init(void) -{ - int rc = 0; - - if (raw_proc_init()) - goto out_raw; - if (tcp4_proc_init()) - goto out_tcp; - if (udp4_proc_init()) - goto out_udp; - if (ping_proc_init()) - goto out_ping; - if (ip_misc_proc_init()) - goto out_misc; -out: - return rc; -out_misc: - ping_proc_exit(); -out_ping: - udp4_proc_exit(); -out_udp: - tcp4_proc_exit(); -out_tcp: - raw_proc_exit(); -out_raw: - rc = -ENOMEM; - goto out; -} - -#else /* CONFIG_PROC_FS */ -static int __init ipv4_proc_init(void) -{ - return 0; -} -#endif /* CONFIG_PROC_FS */ diff --git a/src/linux/net/ipv4/arp.c b/src/linux/net/ipv4/arp.c deleted file mode 100644 index 89a8cac..0000000 --- a/src/linux/net/ipv4/arp.c +++ /dev/null @@ -1,1421 +0,0 @@ -/* linux/net/ipv4/arp.c - * - * Copyright (C) 1994 by Florian La Roche - * - * This module implements the Address Resolution Protocol ARP (RFC 826), - * which is used to convert IP addresses (or in the future maybe other - * high-level addresses) into a low-level hardware address (like an Ethernet - * address). - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Fixes: - * Alan Cox : Removed the Ethernet assumptions in - * Florian's code - * Alan Cox : Fixed some small errors in the ARP - * logic - * Alan Cox : Allow >4K in /proc - * Alan Cox : Make ARP add its own protocol entry - * Ross Martin : Rewrote arp_rcv() and arp_get_info() - * Stephen Henson : Add AX25 support to arp_get_info() - * Alan Cox : Drop data when a device is downed. - * Alan Cox : Use init_timer(). - * Alan Cox : Double lock fixes. - * Martin Seine : Move the arphdr structure - * to if_arp.h for compatibility. - * with BSD based programs. - * Andrew Tridgell : Added ARP netmask code and - * re-arranged proxy handling. - * Alan Cox : Changed to use notifiers. - * Niibe Yutaka : Reply for this device or proxies only. - * Alan Cox : Don't proxy across hardware types! - * Jonathan Naylor : Added support for NET/ROM. - * Mike Shaver : RFC1122 checks. - * Jonathan Naylor : Only lookup the hardware address for - * the correct hardware type. - * Germano Caronni : Assorted subtle races. - * Craig Schlenter : Don't modify permanent entry - * during arp_rcv. - * Russ Nelson : Tidied up a few bits. - * Alexey Kuznetsov: Major changes to caching and behaviour, - * eg intelligent arp probing and - * generation - * of host down events. - * Alan Cox : Missing unlock in device events. - * Eckes : ARP ioctl control errors. - * Alexey Kuznetsov: Arp free fix. - * Manuel Rodriguez: Gratuitous ARP. - * Jonathan Layes : Added arpd support through kerneld - * message queue (960314) - * Mike Shaver : /proc/sys/net/ipv4/arp_* support - * Mike McLagan : Routing by source - * Stuart Cheshire : Metricom and grat arp fixes - * *** FOR 2.1 clean this up *** - * Lawrence V. Stefani: (08/12/96) Added FDDI support. - * Alan Cox : Took the AP1000 nasty FDDI hack and - * folded into the mainstream FDDI code. - * Ack spit, Linus how did you allow that - * one in... - * Jes Sorensen : Make FDDI work again in 2.1.x and - * clean up the APFDDI & gen. FDDI bits. - * Alexey Kuznetsov: new arp state machine; - * now it is in net/core/neighbour.c. - * Krzysztof Halasa: Added Frame Relay ARP support. - * Arnaldo C. Melo : convert /proc/net/arp to seq_file - * Shmulik Hen: Split arp_send to arp_create and - * arp_xmit so intermediate drivers like - * bonding can change the skb before - * sending (e.g. insert 8021q tag). - * Harald Welte : convert to make use of jenkins hash - * Jesper D. Brouer: Proxy ARP PVLAN RFC 3069 support. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_SYSCTL -#include -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -/* - * Interface to generic neighbour cache. - */ -static u32 arp_hash(const void *pkey, const struct net_device *dev, __u32 *hash_rnd); -static bool arp_key_eq(const struct neighbour *n, const void *pkey); -static int arp_constructor(struct neighbour *neigh); -static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb); -static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb); -static void parp_redo(struct sk_buff *skb); - -static const struct neigh_ops arp_generic_ops = { - .family = AF_INET, - .solicit = arp_solicit, - .error_report = arp_error_report, - .output = neigh_resolve_output, - .connected_output = neigh_connected_output, -}; - -static const struct neigh_ops arp_hh_ops = { - .family = AF_INET, - .solicit = arp_solicit, - .error_report = arp_error_report, - .output = neigh_resolve_output, - .connected_output = neigh_resolve_output, -}; - -static const struct neigh_ops arp_direct_ops = { - .family = AF_INET, - .output = neigh_direct_output, - .connected_output = neigh_direct_output, -}; - -struct neigh_table arp_tbl = { - .family = AF_INET, - .key_len = 4, - .protocol = cpu_to_be16(ETH_P_IP), - .hash = arp_hash, - .key_eq = arp_key_eq, - .constructor = arp_constructor, - .proxy_redo = parp_redo, - .id = "arp_cache", - .parms = { - .tbl = &arp_tbl, - .reachable_time = 30 * HZ, - .data = { - [NEIGH_VAR_MCAST_PROBES] = 3, - [NEIGH_VAR_UCAST_PROBES] = 3, - [NEIGH_VAR_RETRANS_TIME] = 1 * HZ, - [NEIGH_VAR_BASE_REACHABLE_TIME] = 30 * HZ, - [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ, - [NEIGH_VAR_GC_STALETIME] = 60 * HZ, - [NEIGH_VAR_QUEUE_LEN_BYTES] = 64 * 1024, - [NEIGH_VAR_PROXY_QLEN] = 64, - [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ, - [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10, - [NEIGH_VAR_LOCKTIME] = 1 * HZ, - }, - }, - .gc_interval = 30 * HZ, - .gc_thresh1 = 128, - .gc_thresh2 = 512, - .gc_thresh3 = 1024, -}; -EXPORT_SYMBOL(arp_tbl); - -int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir) -{ - switch (dev->type) { - case ARPHRD_ETHER: - case ARPHRD_FDDI: - case ARPHRD_IEEE802: - ip_eth_mc_map(addr, haddr); - return 0; - case ARPHRD_INFINIBAND: - ip_ib_mc_map(addr, dev->broadcast, haddr); - return 0; - case ARPHRD_IPGRE: - ip_ipgre_mc_map(addr, dev->broadcast, haddr); - return 0; - default: - if (dir) { - memcpy(haddr, dev->broadcast, dev->addr_len); - return 0; - } - } - return -EINVAL; -} - - -static u32 arp_hash(const void *pkey, - const struct net_device *dev, - __u32 *hash_rnd) -{ - return arp_hashfn(pkey, dev, hash_rnd); -} - -static bool arp_key_eq(const struct neighbour *neigh, const void *pkey) -{ - return neigh_key_eq32(neigh, pkey); -} - -static int arp_constructor(struct neighbour *neigh) -{ - __be32 addr = *(__be32 *)neigh->primary_key; - struct net_device *dev = neigh->dev; - struct in_device *in_dev; - struct neigh_parms *parms; - - rcu_read_lock(); - in_dev = __in_dev_get_rcu(dev); - if (!in_dev) { - rcu_read_unlock(); - return -EINVAL; - } - - neigh->type = inet_addr_type_dev_table(dev_net(dev), dev, addr); - - parms = in_dev->arp_parms; - __neigh_parms_put(neigh->parms); - neigh->parms = neigh_parms_clone(parms); - rcu_read_unlock(); - - if (!dev->header_ops) { - neigh->nud_state = NUD_NOARP; - neigh->ops = &arp_direct_ops; - neigh->output = neigh_direct_output; - } else { - /* Good devices (checked by reading texts, but only Ethernet is - tested) - - ARPHRD_ETHER: (ethernet, apfddi) - ARPHRD_FDDI: (fddi) - ARPHRD_IEEE802: (tr) - ARPHRD_METRICOM: (strip) - ARPHRD_ARCNET: - etc. etc. etc. - - ARPHRD_IPDDP will also work, if author repairs it. - I did not it, because this driver does not work even - in old paradigm. - */ - - if (neigh->type == RTN_MULTICAST) { - neigh->nud_state = NUD_NOARP; - arp_mc_map(addr, neigh->ha, dev, 1); - } else if (dev->flags & (IFF_NOARP | IFF_LOOPBACK)) { - neigh->nud_state = NUD_NOARP; - memcpy(neigh->ha, dev->dev_addr, dev->addr_len); - } else if (neigh->type == RTN_BROADCAST || - (dev->flags & IFF_POINTOPOINT)) { - neigh->nud_state = NUD_NOARP; - memcpy(neigh->ha, dev->broadcast, dev->addr_len); - } - - if (dev->header_ops->cache) - neigh->ops = &arp_hh_ops; - else - neigh->ops = &arp_generic_ops; - - if (neigh->nud_state & NUD_VALID) - neigh->output = neigh->ops->connected_output; - else - neigh->output = neigh->ops->output; - } - return 0; -} - -static void arp_error_report(struct neighbour *neigh, struct sk_buff *skb) -{ - dst_link_failure(skb); - kfree_skb(skb); -} - -/* Create and send an arp packet. */ -static void arp_send_dst(int type, int ptype, __be32 dest_ip, - struct net_device *dev, __be32 src_ip, - const unsigned char *dest_hw, - const unsigned char *src_hw, - const unsigned char *target_hw, - struct dst_entry *dst) -{ - struct sk_buff *skb; - - /* arp on this interface. */ - if (dev->flags & IFF_NOARP) - return; - - skb = arp_create(type, ptype, dest_ip, dev, src_ip, - dest_hw, src_hw, target_hw); - if (!skb) - return; - - skb_dst_set(skb, dst_clone(dst)); - arp_xmit(skb); -} - -void arp_send(int type, int ptype, __be32 dest_ip, - struct net_device *dev, __be32 src_ip, - const unsigned char *dest_hw, const unsigned char *src_hw, - const unsigned char *target_hw) -{ - arp_send_dst(type, ptype, dest_ip, dev, src_ip, dest_hw, src_hw, - target_hw, NULL); -} -EXPORT_SYMBOL(arp_send); - -static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) -{ - __be32 saddr = 0; - u8 dst_ha[MAX_ADDR_LEN], *dst_hw = NULL; - struct net_device *dev = neigh->dev; - __be32 target = *(__be32 *)neigh->primary_key; - int probes = atomic_read(&neigh->probes); - struct in_device *in_dev; - struct dst_entry *dst = NULL; - - rcu_read_lock(); - in_dev = __in_dev_get_rcu(dev); - if (!in_dev) { - rcu_read_unlock(); - return; - } - switch (IN_DEV_ARP_ANNOUNCE(in_dev)) { - default: - case 0: /* By default announce any local IP */ - if (skb && inet_addr_type_dev_table(dev_net(dev), dev, - ip_hdr(skb)->saddr) == RTN_LOCAL) - saddr = ip_hdr(skb)->saddr; - break; - case 1: /* Restrict announcements of saddr in same subnet */ - if (!skb) - break; - saddr = ip_hdr(skb)->saddr; - if (inet_addr_type_dev_table(dev_net(dev), dev, - saddr) == RTN_LOCAL) { - /* saddr should be known to target */ - if (inet_addr_onlink(in_dev, target, saddr)) - break; - } - saddr = 0; - break; - case 2: /* Avoid secondary IPs, get a primary/preferred one */ - break; - } - rcu_read_unlock(); - - if (!saddr) - saddr = inet_select_addr(dev, target, RT_SCOPE_LINK); - - probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES); - if (probes < 0) { - if (!(neigh->nud_state & NUD_VALID)) - pr_debug("trying to ucast probe in NUD_INVALID\n"); - neigh_ha_snapshot(dst_ha, neigh, dev); - dst_hw = dst_ha; - } else { - probes -= NEIGH_VAR(neigh->parms, APP_PROBES); - if (probes < 0) { - neigh_app_ns(neigh); - return; - } - } - - if (skb && !(dev->priv_flags & IFF_XMIT_DST_RELEASE)) - dst = skb_dst(skb); - arp_send_dst(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr, - dst_hw, dev->dev_addr, NULL, dst); -} - -static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) -{ - struct net *net = dev_net(in_dev->dev); - int scope; - - switch (IN_DEV_ARP_IGNORE(in_dev)) { - case 0: /* Reply, the tip is already validated */ - return 0; - case 1: /* Reply only if tip is configured on the incoming interface */ - sip = 0; - scope = RT_SCOPE_HOST; - break; - case 2: /* - * Reply only if tip is configured on the incoming interface - * and is in same subnet as sip - */ - scope = RT_SCOPE_HOST; - break; - case 3: /* Do not reply for scope host addresses */ - sip = 0; - scope = RT_SCOPE_LINK; - in_dev = NULL; - break; - case 4: /* Reserved */ - case 5: - case 6: - case 7: - return 0; - case 8: /* Do not reply */ - return 1; - default: - return 0; - } - return !inet_confirm_addr(net, in_dev, sip, tip, scope); -} - -static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) -{ - struct rtable *rt; - int flag = 0; - /*unsigned long now; */ - struct net *net = dev_net(dev); - - rt = ip_route_output(net, sip, tip, 0, 0); - if (IS_ERR(rt)) - return 1; - if (rt->dst.dev != dev) { - __NET_INC_STATS(net, LINUX_MIB_ARPFILTER); - flag = 1; - } - ip_rt_put(rt); - return flag; -} - -/* - * Check if we can use proxy ARP for this path - */ -static inline int arp_fwd_proxy(struct in_device *in_dev, - struct net_device *dev, struct rtable *rt) -{ - struct in_device *out_dev; - int imi, omi = -1; - - if (rt->dst.dev == dev) - return 0; - - if (!IN_DEV_PROXY_ARP(in_dev)) - return 0; - imi = IN_DEV_MEDIUM_ID(in_dev); - if (imi == 0) - return 1; - if (imi == -1) - return 0; - - /* place to check for proxy_arp for routes */ - - out_dev = __in_dev_get_rcu(rt->dst.dev); - if (out_dev) - omi = IN_DEV_MEDIUM_ID(out_dev); - - return omi != imi && omi != -1; -} - -/* - * Check for RFC3069 proxy arp private VLAN (allow to send back to same dev) - * - * RFC3069 supports proxy arp replies back to the same interface. This - * is done to support (ethernet) switch features, like RFC 3069, where - * the individual ports are not allowed to communicate with each - * other, BUT they are allowed to talk to the upstream router. As - * described in RFC 3069, it is possible to allow these hosts to - * communicate through the upstream router, by proxy_arp'ing. - * - * RFC 3069: "VLAN Aggregation for Efficient IP Address Allocation" - * - * This technology is known by different names: - * In RFC 3069 it is called VLAN Aggregation. - * Cisco and Allied Telesyn call it Private VLAN. - * Hewlett-Packard call it Source-Port filtering or port-isolation. - * Ericsson call it MAC-Forced Forwarding (RFC Draft). - * - */ -static inline int arp_fwd_pvlan(struct in_device *in_dev, - struct net_device *dev, struct rtable *rt, - __be32 sip, __be32 tip) -{ - /* Private VLAN is only concerned about the same ethernet segment */ - if (rt->dst.dev != dev) - return 0; - - /* Don't reply on self probes (often done by windowz boxes)*/ - if (sip == tip) - return 0; - - if (IN_DEV_PROXY_ARP_PVLAN(in_dev)) - return 1; - else - return 0; -} - -/* - * Interface to link layer: send routine and receive handler. - */ - -/* - * Create an arp packet. If dest_hw is not set, we create a broadcast - * message. - */ -struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, - struct net_device *dev, __be32 src_ip, - const unsigned char *dest_hw, - const unsigned char *src_hw, - const unsigned char *target_hw) -{ - struct sk_buff *skb; - struct arphdr *arp; - unsigned char *arp_ptr; - int hlen = LL_RESERVED_SPACE(dev); - int tlen = dev->needed_tailroom; - - /* - * Allocate a buffer - */ - - skb = alloc_skb(arp_hdr_len(dev) + hlen + tlen, GFP_ATOMIC); - if (!skb) - return NULL; - - skb_reserve(skb, hlen); - skb_reset_network_header(skb); - arp = (struct arphdr *) skb_put(skb, arp_hdr_len(dev)); - skb->dev = dev; - skb->protocol = htons(ETH_P_ARP); - if (!src_hw) - src_hw = dev->dev_addr; - if (!dest_hw) - dest_hw = dev->broadcast; - - /* - * Fill the device header for the ARP frame - */ - if (dev_hard_header(skb, dev, ptype, dest_hw, src_hw, skb->len) < 0) - goto out; - - /* - * Fill out the arp protocol part. - * - * The arp hardware type should match the device type, except for FDDI, - * which (according to RFC 1390) should always equal 1 (Ethernet). - */ - /* - * Exceptions everywhere. AX.25 uses the AX.25 PID value not the - * DIX code for the protocol. Make these device structure fields. - */ - switch (dev->type) { - default: - arp->ar_hrd = htons(dev->type); - arp->ar_pro = htons(ETH_P_IP); - break; - -#if IS_ENABLED(CONFIG_AX25) - case ARPHRD_AX25: - arp->ar_hrd = htons(ARPHRD_AX25); - arp->ar_pro = htons(AX25_P_IP); - break; - -#if IS_ENABLED(CONFIG_NETROM) - case ARPHRD_NETROM: - arp->ar_hrd = htons(ARPHRD_NETROM); - arp->ar_pro = htons(AX25_P_IP); - break; -#endif -#endif - -#if IS_ENABLED(CONFIG_FDDI) - case ARPHRD_FDDI: - arp->ar_hrd = htons(ARPHRD_ETHER); - arp->ar_pro = htons(ETH_P_IP); - break; -#endif - } - - arp->ar_hln = dev->addr_len; - arp->ar_pln = 4; - arp->ar_op = htons(type); - - arp_ptr = (unsigned char *)(arp + 1); - - memcpy(arp_ptr, src_hw, dev->addr_len); - arp_ptr += dev->addr_len; - memcpy(arp_ptr, &src_ip, 4); - arp_ptr += 4; - - switch (dev->type) { -#if IS_ENABLED(CONFIG_FIREWIRE_NET) - case ARPHRD_IEEE1394: - break; -#endif - default: - if (target_hw) - memcpy(arp_ptr, target_hw, dev->addr_len); - else - memset(arp_ptr, 0, dev->addr_len); - arp_ptr += dev->addr_len; - } - memcpy(arp_ptr, &dest_ip, 4); - - return skb; - -out: - kfree_skb(skb); - return NULL; -} -EXPORT_SYMBOL(arp_create); - -static int arp_xmit_finish(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - return dev_queue_xmit(skb); -} - -/* - * Send an arp packet. - */ -void arp_xmit(struct sk_buff *skb) -{ - /* Send it off, maybe filter it using firewalling first. */ - NF_HOOK(NFPROTO_ARP, NF_ARP_OUT, - dev_net(skb->dev), NULL, skb, NULL, skb->dev, - arp_xmit_finish); -} -EXPORT_SYMBOL(arp_xmit); - -/* - * Process an arp request. - */ - -static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - struct in_device *in_dev = __in_dev_get_rcu(dev); - struct arphdr *arp; - unsigned char *arp_ptr; - struct rtable *rt; - unsigned char *sha; - __be32 sip, tip; - u16 dev_type = dev->type; - int addr_type; - struct neighbour *n; - struct dst_entry *reply_dst = NULL; - bool is_garp = false; - - /* arp_rcv below verifies the ARP header and verifies the device - * is ARP'able. - */ - - if (!in_dev) - goto out_free_skb; - - arp = arp_hdr(skb); - - switch (dev_type) { - default: - if (arp->ar_pro != htons(ETH_P_IP) || - htons(dev_type) != arp->ar_hrd) - goto out_free_skb; - break; - case ARPHRD_ETHER: - case ARPHRD_FDDI: - case ARPHRD_IEEE802: - /* - * ETHERNET, and Fibre Channel (which are IEEE 802 - * devices, according to RFC 2625) devices will accept ARP - * hardware types of either 1 (Ethernet) or 6 (IEEE 802.2). - * This is the case also of FDDI, where the RFC 1390 says that - * FDDI devices should accept ARP hardware of (1) Ethernet, - * however, to be more robust, we'll accept both 1 (Ethernet) - * or 6 (IEEE 802.2) - */ - if ((arp->ar_hrd != htons(ARPHRD_ETHER) && - arp->ar_hrd != htons(ARPHRD_IEEE802)) || - arp->ar_pro != htons(ETH_P_IP)) - goto out_free_skb; - break; - case ARPHRD_AX25: - if (arp->ar_pro != htons(AX25_P_IP) || - arp->ar_hrd != htons(ARPHRD_AX25)) - goto out_free_skb; - break; - case ARPHRD_NETROM: - if (arp->ar_pro != htons(AX25_P_IP) || - arp->ar_hrd != htons(ARPHRD_NETROM)) - goto out_free_skb; - break; - } - - /* Understand only these message types */ - - if (arp->ar_op != htons(ARPOP_REPLY) && - arp->ar_op != htons(ARPOP_REQUEST)) - goto out_free_skb; - -/* - * Extract fields - */ - arp_ptr = (unsigned char *)(arp + 1); - sha = arp_ptr; - arp_ptr += dev->addr_len; - memcpy(&sip, arp_ptr, 4); - arp_ptr += 4; - switch (dev_type) { -#if IS_ENABLED(CONFIG_FIREWIRE_NET) - case ARPHRD_IEEE1394: - break; -#endif - default: - arp_ptr += dev->addr_len; - } - memcpy(&tip, arp_ptr, 4); -/* - * Check for bad requests for 127.x.x.x and requests for multicast - * addresses. If this is one such, delete it. - */ - if (ipv4_is_multicast(tip) || - (!IN_DEV_ROUTE_LOCALNET(in_dev) && ipv4_is_loopback(tip))) - goto out_free_skb; - - /* - * For some 802.11 wireless deployments (and possibly other networks), - * there will be an ARP proxy and gratuitous ARP frames are attacks - * and thus should not be accepted. - */ - if (sip == tip && IN_DEV_ORCONF(in_dev, DROP_GRATUITOUS_ARP)) - goto out_free_skb; - -/* - * Special case: We must set Frame Relay source Q.922 address - */ - if (dev_type == ARPHRD_DLCI) - sha = dev->broadcast; - -/* - * Process entry. The idea here is we want to send a reply if it is a - * request for us or if it is a request for someone else that we hold - * a proxy for. We want to add an entry to our cache if it is a reply - * to us or if it is a request for our address. - * (The assumption for this last is that if someone is requesting our - * address, they are probably intending to talk to us, so it saves time - * if we cache their address. Their address is also probably not in - * our cache, since ours is not in their cache.) - * - * Putting this another way, we only care about replies if they are to - * us, in which case we add them to the cache. For requests, we care - * about those for us and those for our proxies. We reply to both, - * and in the case of requests for us we add the requester to the arp - * cache. - */ - - if (arp->ar_op == htons(ARPOP_REQUEST) && skb_metadata_dst(skb)) - reply_dst = (struct dst_entry *) - iptunnel_metadata_reply(skb_metadata_dst(skb), - GFP_ATOMIC); - - /* Special case: IPv4 duplicate address detection packet (RFC2131) */ - if (sip == 0) { - if (arp->ar_op == htons(ARPOP_REQUEST) && - inet_addr_type_dev_table(net, dev, tip) == RTN_LOCAL && - !arp_ignore(in_dev, sip, tip)) - arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, - sha, dev->dev_addr, sha, reply_dst); - goto out_consume_skb; - } - - if (arp->ar_op == htons(ARPOP_REQUEST) && - ip_route_input_noref(skb, tip, sip, 0, dev) == 0) { - - rt = skb_rtable(skb); - addr_type = rt->rt_type; - - if (addr_type == RTN_LOCAL) { - int dont_send; - - dont_send = arp_ignore(in_dev, sip, tip); - if (!dont_send && IN_DEV_ARPFILTER(in_dev)) - dont_send = arp_filter(sip, tip, dev); - if (!dont_send) { - n = neigh_event_ns(&arp_tbl, sha, &sip, dev); - if (n) { - arp_send_dst(ARPOP_REPLY, ETH_P_ARP, - sip, dev, tip, sha, - dev->dev_addr, sha, - reply_dst); - neigh_release(n); - } - } - goto out_consume_skb; - } else if (IN_DEV_FORWARD(in_dev)) { - if (addr_type == RTN_UNICAST && - (arp_fwd_proxy(in_dev, dev, rt) || - arp_fwd_pvlan(in_dev, dev, rt, sip, tip) || - (rt->dst.dev != dev && - pneigh_lookup(&arp_tbl, net, &tip, dev, 0)))) { - n = neigh_event_ns(&arp_tbl, sha, &sip, dev); - if (n) - neigh_release(n); - - if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED || - skb->pkt_type == PACKET_HOST || - NEIGH_VAR(in_dev->arp_parms, PROXY_DELAY) == 0) { - arp_send_dst(ARPOP_REPLY, ETH_P_ARP, - sip, dev, tip, sha, - dev->dev_addr, sha, - reply_dst); - } else { - pneigh_enqueue(&arp_tbl, - in_dev->arp_parms, skb); - goto out_free_dst; - } - goto out_consume_skb; - } - } - } - - /* Update our ARP tables */ - - n = __neigh_lookup(&arp_tbl, &sip, dev, 0); - - if (IN_DEV_ARP_ACCEPT(in_dev)) { - unsigned int addr_type = inet_addr_type_dev_table(net, dev, sip); - - /* Unsolicited ARP is not accepted by default. - It is possible, that this option should be enabled for some - devices (strip is candidate) - */ - is_garp = arp->ar_op == htons(ARPOP_REQUEST) && tip == sip && - addr_type == RTN_UNICAST; - - if (!n && - ((arp->ar_op == htons(ARPOP_REPLY) && - addr_type == RTN_UNICAST) || is_garp)) - n = __neigh_lookup(&arp_tbl, &sip, dev, 1); - } - - if (n) { - int state = NUD_REACHABLE; - int override; - - /* If several different ARP replies follows back-to-back, - use the FIRST one. It is possible, if several proxy - agents are active. Taking the first reply prevents - arp trashing and chooses the fastest router. - */ - override = time_after(jiffies, - n->updated + - NEIGH_VAR(n->parms, LOCKTIME)) || - is_garp; - - /* Broadcast replies and request packets - do not assert neighbour reachability. - */ - if (arp->ar_op != htons(ARPOP_REPLY) || - skb->pkt_type != PACKET_HOST) - state = NUD_STALE; - neigh_update(n, sha, state, - override ? NEIGH_UPDATE_F_OVERRIDE : 0); - neigh_release(n); - } - -out_consume_skb: - consume_skb(skb); - -out_free_dst: - dst_release(reply_dst); - return NET_RX_SUCCESS; - -out_free_skb: - kfree_skb(skb); - return NET_RX_DROP; -} - -static void parp_redo(struct sk_buff *skb) -{ - arp_process(dev_net(skb->dev), NULL, skb); -} - - -/* - * Receive an arp request from the device layer. - */ - -static int arp_rcv(struct sk_buff *skb, struct net_device *dev, - struct packet_type *pt, struct net_device *orig_dev) -{ - const struct arphdr *arp; - - /* do not tweak dropwatch on an ARP we will ignore */ - if (dev->flags & IFF_NOARP || - skb->pkt_type == PACKET_OTHERHOST || - skb->pkt_type == PACKET_LOOPBACK) - goto consumeskb; - - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) - goto out_of_mem; - - /* ARP header, plus 2 device addresses, plus 2 IP addresses. */ - if (!pskb_may_pull(skb, arp_hdr_len(dev))) - goto freeskb; - - arp = arp_hdr(skb); - if (arp->ar_hln != dev->addr_len || arp->ar_pln != 4) - goto freeskb; - - memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb)); - - return NF_HOOK(NFPROTO_ARP, NF_ARP_IN, - dev_net(dev), NULL, skb, dev, NULL, - arp_process); - -consumeskb: - consume_skb(skb); - return NET_RX_SUCCESS; -freeskb: - kfree_skb(skb); -out_of_mem: - return NET_RX_DROP; -} - -/* - * User level interface (ioctl) - */ - -/* - * Set (create) an ARP cache entry. - */ - -static int arp_req_set_proxy(struct net *net, struct net_device *dev, int on) -{ - if (!dev) { - IPV4_DEVCONF_ALL(net, PROXY_ARP) = on; - return 0; - } - if (__in_dev_get_rtnl(dev)) { - IN_DEV_CONF_SET(__in_dev_get_rtnl(dev), PROXY_ARP, on); - return 0; - } - return -ENXIO; -} - -static int arp_req_set_public(struct net *net, struct arpreq *r, - struct net_device *dev) -{ - __be32 ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; - __be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr; - - if (mask && mask != htonl(0xFFFFFFFF)) - return -EINVAL; - if (!dev && (r->arp_flags & ATF_COM)) { - dev = dev_getbyhwaddr_rcu(net, r->arp_ha.sa_family, - r->arp_ha.sa_data); - if (!dev) - return -ENODEV; - } - if (mask) { - if (!pneigh_lookup(&arp_tbl, net, &ip, dev, 1)) - return -ENOBUFS; - return 0; - } - - return arp_req_set_proxy(net, dev, 1); -} - -static int arp_req_set(struct net *net, struct arpreq *r, - struct net_device *dev) -{ - __be32 ip; - struct neighbour *neigh; - int err; - - if (r->arp_flags & ATF_PUBL) - return arp_req_set_public(net, r, dev); - - ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; - if (r->arp_flags & ATF_PERM) - r->arp_flags |= ATF_COM; - if (!dev) { - struct rtable *rt = ip_route_output(net, ip, 0, RTO_ONLINK, 0); - - if (IS_ERR(rt)) - return PTR_ERR(rt); - dev = rt->dst.dev; - ip_rt_put(rt); - if (!dev) - return -EINVAL; - } - switch (dev->type) { -#if IS_ENABLED(CONFIG_FDDI) - case ARPHRD_FDDI: - /* - * According to RFC 1390, FDDI devices should accept ARP - * hardware types of 1 (Ethernet). However, to be more - * robust, we'll accept hardware types of either 1 (Ethernet) - * or 6 (IEEE 802.2). - */ - if (r->arp_ha.sa_family != ARPHRD_FDDI && - r->arp_ha.sa_family != ARPHRD_ETHER && - r->arp_ha.sa_family != ARPHRD_IEEE802) - return -EINVAL; - break; -#endif - default: - if (r->arp_ha.sa_family != dev->type) - return -EINVAL; - break; - } - - neigh = __neigh_lookup_errno(&arp_tbl, &ip, dev); - err = PTR_ERR(neigh); - if (!IS_ERR(neigh)) { - unsigned int state = NUD_STALE; - if (r->arp_flags & ATF_PERM) - state = NUD_PERMANENT; - err = neigh_update(neigh, (r->arp_flags & ATF_COM) ? - r->arp_ha.sa_data : NULL, state, - NEIGH_UPDATE_F_OVERRIDE | - NEIGH_UPDATE_F_ADMIN); - neigh_release(neigh); - } - return err; -} - -static unsigned int arp_state_to_flags(struct neighbour *neigh) -{ - if (neigh->nud_state&NUD_PERMANENT) - return ATF_PERM | ATF_COM; - else if (neigh->nud_state&NUD_VALID) - return ATF_COM; - else - return 0; -} - -/* - * Get an ARP cache entry. - */ - -static int arp_req_get(struct arpreq *r, struct net_device *dev) -{ - __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; - struct neighbour *neigh; - int err = -ENXIO; - - neigh = neigh_lookup(&arp_tbl, &ip, dev); - if (neigh) { - if (!(neigh->nud_state & NUD_NOARP)) { - read_lock_bh(&neigh->lock); - memcpy(r->arp_ha.sa_data, neigh->ha, dev->addr_len); - r->arp_flags = arp_state_to_flags(neigh); - read_unlock_bh(&neigh->lock); - r->arp_ha.sa_family = dev->type; - strlcpy(r->arp_dev, dev->name, sizeof(r->arp_dev)); - err = 0; - } - neigh_release(neigh); - } - return err; -} - -static int arp_invalidate(struct net_device *dev, __be32 ip) -{ - struct neighbour *neigh = neigh_lookup(&arp_tbl, &ip, dev); - int err = -ENXIO; - - if (neigh) { - if (neigh->nud_state & ~NUD_NOARP) - err = neigh_update(neigh, NULL, NUD_FAILED, - NEIGH_UPDATE_F_OVERRIDE| - NEIGH_UPDATE_F_ADMIN); - neigh_release(neigh); - } - - return err; -} - -static int arp_req_delete_public(struct net *net, struct arpreq *r, - struct net_device *dev) -{ - __be32 ip = ((struct sockaddr_in *) &r->arp_pa)->sin_addr.s_addr; - __be32 mask = ((struct sockaddr_in *)&r->arp_netmask)->sin_addr.s_addr; - - if (mask == htonl(0xFFFFFFFF)) - return pneigh_delete(&arp_tbl, net, &ip, dev); - - if (mask) - return -EINVAL; - - return arp_req_set_proxy(net, dev, 0); -} - -static int arp_req_delete(struct net *net, struct arpreq *r, - struct net_device *dev) -{ - __be32 ip; - - if (r->arp_flags & ATF_PUBL) - return arp_req_delete_public(net, r, dev); - - ip = ((struct sockaddr_in *)&r->arp_pa)->sin_addr.s_addr; - if (!dev) { - struct rtable *rt = ip_route_output(net, ip, 0, RTO_ONLINK, 0); - if (IS_ERR(rt)) - return PTR_ERR(rt); - dev = rt->dst.dev; - ip_rt_put(rt); - if (!dev) - return -EINVAL; - } - return arp_invalidate(dev, ip); -} - -/* - * Handle an ARP layer I/O control request. - */ - -int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg) -{ - int err; - struct arpreq r; - struct net_device *dev = NULL; - - switch (cmd) { - case SIOCDARP: - case SIOCSARP: - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - return -EPERM; - case SIOCGARP: - err = copy_from_user(&r, arg, sizeof(struct arpreq)); - if (err) - return -EFAULT; - break; - default: - return -EINVAL; - } - - if (r.arp_pa.sa_family != AF_INET) - return -EPFNOSUPPORT; - - if (!(r.arp_flags & ATF_PUBL) && - (r.arp_flags & (ATF_NETMASK | ATF_DONTPUB))) - return -EINVAL; - if (!(r.arp_flags & ATF_NETMASK)) - ((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr = - htonl(0xFFFFFFFFUL); - rtnl_lock(); - if (r.arp_dev[0]) { - err = -ENODEV; - dev = __dev_get_by_name(net, r.arp_dev); - if (!dev) - goto out; - - /* Mmmm... It is wrong... ARPHRD_NETROM==0 */ - if (!r.arp_ha.sa_family) - r.arp_ha.sa_family = dev->type; - err = -EINVAL; - if ((r.arp_flags & ATF_COM) && r.arp_ha.sa_family != dev->type) - goto out; - } else if (cmd == SIOCGARP) { - err = -ENODEV; - goto out; - } - - switch (cmd) { - case SIOCDARP: - err = arp_req_delete(net, &r, dev); - break; - case SIOCSARP: - err = arp_req_set(net, &r, dev); - break; - case SIOCGARP: - err = arp_req_get(&r, dev); - break; - } -out: - rtnl_unlock(); - if (cmd == SIOCGARP && !err && copy_to_user(arg, &r, sizeof(r))) - err = -EFAULT; - return err; -} - -static int arp_netdev_event(struct notifier_block *this, unsigned long event, - void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct netdev_notifier_change_info *change_info; - - switch (event) { - case NETDEV_CHANGEADDR: - neigh_changeaddr(&arp_tbl, dev); - rt_cache_flush(dev_net(dev)); - break; - case NETDEV_CHANGE: - change_info = ptr; - if (change_info->flags_changed & IFF_NOARP) - neigh_changeaddr(&arp_tbl, dev); - break; - default: - break; - } - - return NOTIFY_DONE; -} - -static struct notifier_block arp_netdev_notifier = { - .notifier_call = arp_netdev_event, -}; - -/* Note, that it is not on notifier chain. - It is necessary, that this routine was called after route cache will be - flushed. - */ -void arp_ifdown(struct net_device *dev) -{ - neigh_ifdown(&arp_tbl, dev); -} - - -/* - * Called once on startup. - */ - -static struct packet_type arp_packet_type __read_mostly = { - .type = cpu_to_be16(ETH_P_ARP), - .func = arp_rcv, -}; - -static int arp_proc_init(void); - -void __init arp_init(void) -{ - neigh_table_init(NEIGH_ARP_TABLE, &arp_tbl); - - dev_add_pack(&arp_packet_type); - arp_proc_init(); -#ifdef CONFIG_SYSCTL - neigh_sysctl_register(NULL, &arp_tbl.parms, NULL); -#endif - register_netdevice_notifier(&arp_netdev_notifier); -} - -#ifdef CONFIG_PROC_FS -#if IS_ENABLED(CONFIG_AX25) - -/* ------------------------------------------------------------------------ */ -/* - * ax25 -> ASCII conversion - */ -static char *ax2asc2(ax25_address *a, char *buf) -{ - char c, *s; - int n; - - for (n = 0, s = buf; n < 6; n++) { - c = (a->ax25_call[n] >> 1) & 0x7F; - - if (c != ' ') - *s++ = c; - } - - *s++ = '-'; - n = (a->ax25_call[6] >> 1) & 0x0F; - if (n > 9) { - *s++ = '1'; - n -= 10; - } - - *s++ = n + '0'; - *s++ = '\0'; - - if (*buf == '\0' || *buf == '-') - return "*"; - - return buf; -} -#endif /* CONFIG_AX25 */ - -#define HBUFFERLEN 30 - -static void arp_format_neigh_entry(struct seq_file *seq, - struct neighbour *n) -{ - char hbuffer[HBUFFERLEN]; - int k, j; - char tbuf[16]; - struct net_device *dev = n->dev; - int hatype = dev->type; - - read_lock(&n->lock); - /* Convert hardware address to XX:XX:XX:XX ... form. */ -#if IS_ENABLED(CONFIG_AX25) - if (hatype == ARPHRD_AX25 || hatype == ARPHRD_NETROM) - ax2asc2((ax25_address *)n->ha, hbuffer); - else { -#endif - for (k = 0, j = 0; k < HBUFFERLEN - 3 && j < dev->addr_len; j++) { - hbuffer[k++] = hex_asc_hi(n->ha[j]); - hbuffer[k++] = hex_asc_lo(n->ha[j]); - hbuffer[k++] = ':'; - } - if (k != 0) - --k; - hbuffer[k] = 0; -#if IS_ENABLED(CONFIG_AX25) - } -#endif - sprintf(tbuf, "%pI4", n->primary_key); - seq_printf(seq, "%-16s 0x%-10x0x%-10x%s * %s\n", - tbuf, hatype, arp_state_to_flags(n), hbuffer, dev->name); - read_unlock(&n->lock); -} - -static void arp_format_pneigh_entry(struct seq_file *seq, - struct pneigh_entry *n) -{ - struct net_device *dev = n->dev; - int hatype = dev ? dev->type : 0; - char tbuf[16]; - - sprintf(tbuf, "%pI4", n->key); - seq_printf(seq, "%-16s 0x%-10x0x%-10x%s * %s\n", - tbuf, hatype, ATF_PUBL | ATF_PERM, "00:00:00:00:00:00", - dev ? dev->name : "*"); -} - -static int arp_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) { - seq_puts(seq, "IP address HW type Flags " - "HW address Mask Device\n"); - } else { - struct neigh_seq_state *state = seq->private; - - if (state->flags & NEIGH_SEQ_IS_PNEIGH) - arp_format_pneigh_entry(seq, v); - else - arp_format_neigh_entry(seq, v); - } - - return 0; -} - -static void *arp_seq_start(struct seq_file *seq, loff_t *pos) -{ - /* Don't want to confuse "arp -a" w/ magic entries, - * so we tell the generic iterator to skip NUD_NOARP. - */ - return neigh_seq_start(seq, pos, &arp_tbl, NEIGH_SEQ_SKIP_NOARP); -} - -/* ------------------------------------------------------------------------ */ - -static const struct seq_operations arp_seq_ops = { - .start = arp_seq_start, - .next = neigh_seq_next, - .stop = neigh_seq_stop, - .show = arp_seq_show, -}; - -static int arp_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &arp_seq_ops, - sizeof(struct neigh_seq_state)); -} - -static const struct file_operations arp_seq_fops = { - .owner = THIS_MODULE, - .open = arp_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - - -static int __net_init arp_net_init(struct net *net) -{ - if (!proc_create("arp", S_IRUGO, net->proc_net, &arp_seq_fops)) - return -ENOMEM; - return 0; -} - -static void __net_exit arp_net_exit(struct net *net) -{ - remove_proc_entry("arp", net->proc_net); -} - -static struct pernet_operations arp_net_ops = { - .init = arp_net_init, - .exit = arp_net_exit, -}; - -static int __init arp_proc_init(void) -{ - return register_pernet_subsys(&arp_net_ops); -} - -#else /* CONFIG_PROC_FS */ - -static int __init arp_proc_init(void) -{ - return 0; -} - -#endif /* CONFIG_PROC_FS */ diff --git a/src/linux/net/ipv4/datagram.c b/src/linux/net/ipv4/datagram.c deleted file mode 100644 index f915abf..0000000 --- a/src/linux/net/ipv4/datagram.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * common UDP/RAW code - * Linux INET implementation - * - * Authors: - * Hideaki YOSHIFUJI - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -int __ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) -{ - struct inet_sock *inet = inet_sk(sk); - struct sockaddr_in *usin = (struct sockaddr_in *) uaddr; - struct flowi4 *fl4; - struct rtable *rt; - __be32 saddr; - int oif; - int err; - - - if (addr_len < sizeof(*usin)) - return -EINVAL; - - if (usin->sin_family != AF_INET) - return -EAFNOSUPPORT; - - sk_dst_reset(sk); - - oif = sk->sk_bound_dev_if; - saddr = inet->inet_saddr; - if (ipv4_is_multicast(usin->sin_addr.s_addr)) { - if (!oif) - oif = inet->mc_index; - if (!saddr) - saddr = inet->mc_addr; - } - fl4 = &inet->cork.fl.u.ip4; - rt = ip_route_connect(fl4, usin->sin_addr.s_addr, saddr, - RT_CONN_FLAGS(sk), oif, - sk->sk_protocol, - inet->inet_sport, usin->sin_port, sk); - if (IS_ERR(rt)) { - err = PTR_ERR(rt); - if (err == -ENETUNREACH) - IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); - goto out; - } - - if ((rt->rt_flags & RTCF_BROADCAST) && !sock_flag(sk, SOCK_BROADCAST)) { - ip_rt_put(rt); - err = -EACCES; - goto out; - } - if (!inet->inet_saddr) - inet->inet_saddr = fl4->saddr; /* Update source address */ - if (!inet->inet_rcv_saddr) { - inet->inet_rcv_saddr = fl4->saddr; - if (sk->sk_prot->rehash) - sk->sk_prot->rehash(sk); - } - inet->inet_daddr = fl4->daddr; - inet->inet_dport = usin->sin_port; - sk->sk_state = TCP_ESTABLISHED; - sk_set_txhash(sk); - inet->inet_id = jiffies; - - sk_dst_set(sk, &rt->dst); - err = 0; -out: - return err; -} -EXPORT_SYMBOL(__ip4_datagram_connect); - -int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) -{ - int res; - - lock_sock(sk); - res = __ip4_datagram_connect(sk, uaddr, addr_len); - release_sock(sk); - return res; -} -EXPORT_SYMBOL(ip4_datagram_connect); - -/* Because UDP xmit path can manipulate sk_dst_cache without holding - * socket lock, we need to use sk_dst_set() here, - * even if we own the socket lock. - */ -void ip4_datagram_release_cb(struct sock *sk) -{ - const struct inet_sock *inet = inet_sk(sk); - const struct ip_options_rcu *inet_opt; - __be32 daddr = inet->inet_daddr; - struct dst_entry *dst; - struct flowi4 fl4; - struct rtable *rt; - - rcu_read_lock(); - - dst = __sk_dst_get(sk); - if (!dst || !dst->obsolete || dst->ops->check(dst, 0)) { - rcu_read_unlock(); - return; - } - inet_opt = rcu_dereference(inet->inet_opt); - if (inet_opt && inet_opt->opt.srr) - daddr = inet_opt->opt.faddr; - rt = ip_route_output_ports(sock_net(sk), &fl4, sk, daddr, - inet->inet_saddr, inet->inet_dport, - inet->inet_sport, sk->sk_protocol, - RT_CONN_FLAGS(sk), sk->sk_bound_dev_if); - - dst = !IS_ERR(rt) ? &rt->dst : NULL; - sk_dst_set(sk, dst); - - rcu_read_unlock(); -} -EXPORT_SYMBOL_GPL(ip4_datagram_release_cb); diff --git a/src/linux/net/ipv4/devinet.c b/src/linux/net/ipv4/devinet.c deleted file mode 100644 index 062a67c..0000000 --- a/src/linux/net/ipv4/devinet.c +++ /dev/null @@ -1,2440 +0,0 @@ -/* - * NET3 IP device support routines. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Derived from the IP parts of dev.c 1.0.19 - * Authors: Ross Biro - * Fred N. van Kempen, - * Mark Evans, - * - * Additional Authors: - * Alan Cox, - * Alexey Kuznetsov, - * - * Changes: - * Alexey Kuznetsov: pa_* fields are replaced with ifaddr - * lists. - * Cyrus Durgin: updated for kmod - * Matthias Andree: in devinet_ioctl, compare label and - * address (4.4BSD alias style support), - * fall back to comparing just the label - * if no match found. - */ - - -#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 -#ifdef CONFIG_SYSCTL -#include -#endif -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "fib_lookup.h" - -static struct ipv4_devconf ipv4_devconf = { - .data = { - [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1, - [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1, - [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1, - [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1, - [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/, - [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/, - }, -}; - -static struct ipv4_devconf ipv4_devconf_dflt = { - .data = { - [IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1, - [IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1, - [IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1, - [IPV4_DEVCONF_SHARED_MEDIA - 1] = 1, - [IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1, - [IPV4_DEVCONF_IGMPV2_UNSOLICITED_REPORT_INTERVAL - 1] = 10000 /*ms*/, - [IPV4_DEVCONF_IGMPV3_UNSOLICITED_REPORT_INTERVAL - 1] = 1000 /*ms*/, - }, -}; - -#define IPV4_DEVCONF_DFLT(net, attr) \ - IPV4_DEVCONF((*net->ipv4.devconf_dflt), attr) - -static const struct nla_policy ifa_ipv4_policy[IFA_MAX+1] = { - [IFA_LOCAL] = { .type = NLA_U32 }, - [IFA_ADDRESS] = { .type = NLA_U32 }, - [IFA_BROADCAST] = { .type = NLA_U32 }, - [IFA_LABEL] = { .type = NLA_STRING, .len = IFNAMSIZ - 1 }, - [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, - [IFA_FLAGS] = { .type = NLA_U32 }, -}; - -#define IN4_ADDR_HSIZE_SHIFT 8 -#define IN4_ADDR_HSIZE (1U << IN4_ADDR_HSIZE_SHIFT) - -static struct hlist_head inet_addr_lst[IN4_ADDR_HSIZE]; - -static u32 inet_addr_hash(const struct net *net, __be32 addr) -{ - u32 val = (__force u32) addr ^ net_hash_mix(net); - - return hash_32(val, IN4_ADDR_HSIZE_SHIFT); -} - -static void inet_hash_insert(struct net *net, struct in_ifaddr *ifa) -{ - u32 hash = inet_addr_hash(net, ifa->ifa_local); - - ASSERT_RTNL(); - hlist_add_head_rcu(&ifa->hash, &inet_addr_lst[hash]); -} - -static void inet_hash_remove(struct in_ifaddr *ifa) -{ - ASSERT_RTNL(); - hlist_del_init_rcu(&ifa->hash); -} - -/** - * __ip_dev_find - find the first device with a given source address. - * @net: the net namespace - * @addr: the source address - * @devref: if true, take a reference on the found device - * - * If a caller uses devref=false, it should be protected by RCU, or RTNL - */ -struct net_device *__ip_dev_find(struct net *net, __be32 addr, bool devref) -{ - u32 hash = inet_addr_hash(net, addr); - struct net_device *result = NULL; - struct in_ifaddr *ifa; - - rcu_read_lock(); - hlist_for_each_entry_rcu(ifa, &inet_addr_lst[hash], hash) { - if (ifa->ifa_local == addr) { - struct net_device *dev = ifa->ifa_dev->dev; - - if (!net_eq(dev_net(dev), net)) - continue; - result = dev; - break; - } - } - if (!result) { - struct flowi4 fl4 = { .daddr = addr }; - struct fib_result res = { 0 }; - struct fib_table *local; - - /* Fallback to FIB local table so that communication - * over loopback subnets work. - */ - local = fib_get_table(net, RT_TABLE_LOCAL); - if (local && - !fib_table_lookup(local, &fl4, &res, FIB_LOOKUP_NOREF) && - res.type == RTN_LOCAL) - result = FIB_RES_DEV(res); - } - if (result && devref) - dev_hold(result); - rcu_read_unlock(); - return result; -} -EXPORT_SYMBOL(__ip_dev_find); - -static void rtmsg_ifa(int event, struct in_ifaddr *, struct nlmsghdr *, u32); - -static BLOCKING_NOTIFIER_HEAD(inetaddr_chain); -static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, - int destroy); -#ifdef CONFIG_SYSCTL -static int devinet_sysctl_register(struct in_device *idev); -static void devinet_sysctl_unregister(struct in_device *idev); -#else -static int devinet_sysctl_register(struct in_device *idev) -{ - return 0; -} -static void devinet_sysctl_unregister(struct in_device *idev) -{ -} -#endif - -/* Locks all the inet devices. */ - -static struct in_ifaddr *inet_alloc_ifa(void) -{ - return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL); -} - -static void inet_rcu_free_ifa(struct rcu_head *head) -{ - struct in_ifaddr *ifa = container_of(head, struct in_ifaddr, rcu_head); - if (ifa->ifa_dev) - in_dev_put(ifa->ifa_dev); - kfree(ifa); -} - -static void inet_free_ifa(struct in_ifaddr *ifa) -{ - call_rcu(&ifa->rcu_head, inet_rcu_free_ifa); -} - -void in_dev_finish_destroy(struct in_device *idev) -{ - struct net_device *dev = idev->dev; - - WARN_ON(idev->ifa_list); - WARN_ON(idev->mc_list); - kfree(rcu_dereference_protected(idev->mc_hash, 1)); -#ifdef NET_REFCNT_DEBUG - pr_debug("%s: %p=%s\n", __func__, idev, dev ? dev->name : "NIL"); -#endif - dev_put(dev); - if (!idev->dead) - pr_err("Freeing alive in_device %p\n", idev); - else - kfree(idev); -} -EXPORT_SYMBOL(in_dev_finish_destroy); - -static struct in_device *inetdev_init(struct net_device *dev) -{ - struct in_device *in_dev; - int err = -ENOMEM; - - ASSERT_RTNL(); - - in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL); - if (!in_dev) - goto out; - memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt, - sizeof(in_dev->cnf)); - in_dev->cnf.sysctl = NULL; - in_dev->dev = dev; - in_dev->arp_parms = neigh_parms_alloc(dev, &arp_tbl); - if (!in_dev->arp_parms) - goto out_kfree; - if (IPV4_DEVCONF(in_dev->cnf, FORWARDING)) - dev_disable_lro(dev); - /* Reference in_dev->dev */ - dev_hold(dev); - /* Account for reference dev->ip_ptr (below) */ - in_dev_hold(in_dev); - - err = devinet_sysctl_register(in_dev); - if (err) { - in_dev->dead = 1; - in_dev_put(in_dev); - in_dev = NULL; - goto out; - } - ip_mc_init_dev(in_dev); - if (dev->flags & IFF_UP) - ip_mc_up(in_dev); - - /* we can receive as soon as ip_ptr is set -- do this last */ - rcu_assign_pointer(dev->ip_ptr, in_dev); -out: - return in_dev ?: ERR_PTR(err); -out_kfree: - kfree(in_dev); - in_dev = NULL; - goto out; -} - -static void in_dev_rcu_put(struct rcu_head *head) -{ - struct in_device *idev = container_of(head, struct in_device, rcu_head); - in_dev_put(idev); -} - -static void inetdev_destroy(struct in_device *in_dev) -{ - struct in_ifaddr *ifa; - struct net_device *dev; - - ASSERT_RTNL(); - - dev = in_dev->dev; - - in_dev->dead = 1; - - ip_mc_destroy_dev(in_dev); - - while ((ifa = in_dev->ifa_list) != NULL) { - inet_del_ifa(in_dev, &in_dev->ifa_list, 0); - inet_free_ifa(ifa); - } - - RCU_INIT_POINTER(dev->ip_ptr, NULL); - - devinet_sysctl_unregister(in_dev); - neigh_parms_release(&arp_tbl, in_dev->arp_parms); - arp_ifdown(dev); - - call_rcu(&in_dev->rcu_head, in_dev_rcu_put); -} - -int inet_addr_onlink(struct in_device *in_dev, __be32 a, __be32 b) -{ - rcu_read_lock(); - for_primary_ifa(in_dev) { - if (inet_ifa_match(a, ifa)) { - if (!b || inet_ifa_match(b, ifa)) { - rcu_read_unlock(); - return 1; - } - } - } endfor_ifa(in_dev); - rcu_read_unlock(); - return 0; -} - -static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, - int destroy, struct nlmsghdr *nlh, u32 portid) -{ - struct in_ifaddr *promote = NULL; - struct in_ifaddr *ifa, *ifa1 = *ifap; - struct in_ifaddr *last_prim = in_dev->ifa_list; - struct in_ifaddr *prev_prom = NULL; - int do_promote = IN_DEV_PROMOTE_SECONDARIES(in_dev); - - ASSERT_RTNL(); - - if (in_dev->dead) - goto no_promotions; - - /* 1. Deleting primary ifaddr forces deletion all secondaries - * unless alias promotion is set - **/ - - if (!(ifa1->ifa_flags & IFA_F_SECONDARY)) { - struct in_ifaddr **ifap1 = &ifa1->ifa_next; - - while ((ifa = *ifap1) != NULL) { - if (!(ifa->ifa_flags & IFA_F_SECONDARY) && - ifa1->ifa_scope <= ifa->ifa_scope) - last_prim = ifa; - - if (!(ifa->ifa_flags & IFA_F_SECONDARY) || - ifa1->ifa_mask != ifa->ifa_mask || - !inet_ifa_match(ifa1->ifa_address, ifa)) { - ifap1 = &ifa->ifa_next; - prev_prom = ifa; - continue; - } - - if (!do_promote) { - inet_hash_remove(ifa); - *ifap1 = ifa->ifa_next; - - rtmsg_ifa(RTM_DELADDR, ifa, nlh, portid); - blocking_notifier_call_chain(&inetaddr_chain, - NETDEV_DOWN, ifa); - inet_free_ifa(ifa); - } else { - promote = ifa; - break; - } - } - } - - /* On promotion all secondaries from subnet are changing - * the primary IP, we must remove all their routes silently - * and later to add them back with new prefsrc. Do this - * while all addresses are on the device list. - */ - for (ifa = promote; ifa; ifa = ifa->ifa_next) { - if (ifa1->ifa_mask == ifa->ifa_mask && - inet_ifa_match(ifa1->ifa_address, ifa)) - fib_del_ifaddr(ifa, ifa1); - } - -no_promotions: - /* 2. Unlink it */ - - *ifap = ifa1->ifa_next; - inet_hash_remove(ifa1); - - /* 3. Announce address deletion */ - - /* Send message first, then call notifier. - At first sight, FIB update triggered by notifier - will refer to already deleted ifaddr, that could confuse - netlink listeners. It is not true: look, gated sees - that route deleted and if it still thinks that ifaddr - is valid, it will try to restore deleted routes... Grr. - So that, this order is correct. - */ - rtmsg_ifa(RTM_DELADDR, ifa1, nlh, portid); - blocking_notifier_call_chain(&inetaddr_chain, NETDEV_DOWN, ifa1); - - if (promote) { - struct in_ifaddr *next_sec = promote->ifa_next; - - if (prev_prom) { - prev_prom->ifa_next = promote->ifa_next; - promote->ifa_next = last_prim->ifa_next; - last_prim->ifa_next = promote; - } - - promote->ifa_flags &= ~IFA_F_SECONDARY; - rtmsg_ifa(RTM_NEWADDR, promote, nlh, portid); - blocking_notifier_call_chain(&inetaddr_chain, - NETDEV_UP, promote); - for (ifa = next_sec; ifa; ifa = ifa->ifa_next) { - if (ifa1->ifa_mask != ifa->ifa_mask || - !inet_ifa_match(ifa1->ifa_address, ifa)) - continue; - fib_add_ifaddr(ifa); - } - - } - if (destroy) - inet_free_ifa(ifa1); -} - -static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, - int destroy) -{ - __inet_del_ifa(in_dev, ifap, destroy, NULL, 0); -} - -static void check_lifetime(struct work_struct *work); - -static DECLARE_DELAYED_WORK(check_lifetime_work, check_lifetime); - -static int __inet_insert_ifa(struct in_ifaddr *ifa, struct nlmsghdr *nlh, - u32 portid) -{ - struct in_device *in_dev = ifa->ifa_dev; - struct in_ifaddr *ifa1, **ifap, **last_primary; - - ASSERT_RTNL(); - - if (!ifa->ifa_local) { - inet_free_ifa(ifa); - return 0; - } - - ifa->ifa_flags &= ~IFA_F_SECONDARY; - last_primary = &in_dev->ifa_list; - - for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL; - ifap = &ifa1->ifa_next) { - if (!(ifa1->ifa_flags & IFA_F_SECONDARY) && - ifa->ifa_scope <= ifa1->ifa_scope) - last_primary = &ifa1->ifa_next; - if (ifa1->ifa_mask == ifa->ifa_mask && - inet_ifa_match(ifa1->ifa_address, ifa)) { - if (ifa1->ifa_local == ifa->ifa_local) { - inet_free_ifa(ifa); - return -EEXIST; - } - if (ifa1->ifa_scope != ifa->ifa_scope) { - inet_free_ifa(ifa); - return -EINVAL; - } - ifa->ifa_flags |= IFA_F_SECONDARY; - } - } - - if (!(ifa->ifa_flags & IFA_F_SECONDARY)) { - prandom_seed((__force u32) ifa->ifa_local); - ifap = last_primary; - } - - ifa->ifa_next = *ifap; - *ifap = ifa; - - inet_hash_insert(dev_net(in_dev->dev), ifa); - - cancel_delayed_work(&check_lifetime_work); - queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0); - - /* Send message first, then call notifier. - Notifier will trigger FIB update, so that - listeners of netlink will know about new ifaddr */ - rtmsg_ifa(RTM_NEWADDR, ifa, nlh, portid); - blocking_notifier_call_chain(&inetaddr_chain, NETDEV_UP, ifa); - - return 0; -} - -static int inet_insert_ifa(struct in_ifaddr *ifa) -{ - return __inet_insert_ifa(ifa, NULL, 0); -} - -static int inet_set_ifa(struct net_device *dev, struct in_ifaddr *ifa) -{ - struct in_device *in_dev = __in_dev_get_rtnl(dev); - - ASSERT_RTNL(); - - if (!in_dev) { - inet_free_ifa(ifa); - return -ENOBUFS; - } - ipv4_devconf_setall(in_dev); - neigh_parms_data_state_setall(in_dev->arp_parms); - if (ifa->ifa_dev != in_dev) { - WARN_ON(ifa->ifa_dev); - in_dev_hold(in_dev); - ifa->ifa_dev = in_dev; - } - if (ipv4_is_loopback(ifa->ifa_local)) - ifa->ifa_scope = RT_SCOPE_HOST; - return inet_insert_ifa(ifa); -} - -/* Caller must hold RCU or RTNL : - * We dont take a reference on found in_device - */ -struct in_device *inetdev_by_index(struct net *net, int ifindex) -{ - struct net_device *dev; - struct in_device *in_dev = NULL; - - rcu_read_lock(); - dev = dev_get_by_index_rcu(net, ifindex); - if (dev) - in_dev = rcu_dereference_rtnl(dev->ip_ptr); - rcu_read_unlock(); - return in_dev; -} -EXPORT_SYMBOL(inetdev_by_index); - -/* Called only from RTNL semaphored context. No locks. */ - -struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, - __be32 mask) -{ - ASSERT_RTNL(); - - for_primary_ifa(in_dev) { - if (ifa->ifa_mask == mask && inet_ifa_match(prefix, ifa)) - return ifa; - } endfor_ifa(in_dev); - return NULL; -} - -static int ip_mc_config(struct sock *sk, bool join, const struct in_ifaddr *ifa) -{ - struct ip_mreqn mreq = { - .imr_multiaddr.s_addr = ifa->ifa_address, - .imr_ifindex = ifa->ifa_dev->dev->ifindex, - }; - int ret; - - ASSERT_RTNL(); - - lock_sock(sk); - if (join) - ret = ip_mc_join_group(sk, &mreq); - else - ret = ip_mc_leave_group(sk, &mreq); - release_sock(sk); - - return ret; -} - -static int inet_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct nlattr *tb[IFA_MAX+1]; - struct in_device *in_dev; - struct ifaddrmsg *ifm; - struct in_ifaddr *ifa, **ifap; - int err = -EINVAL; - - ASSERT_RTNL(); - - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy); - if (err < 0) - goto errout; - - ifm = nlmsg_data(nlh); - in_dev = inetdev_by_index(net, ifm->ifa_index); - if (!in_dev) { - err = -ENODEV; - goto errout; - } - - for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; - ifap = &ifa->ifa_next) { - if (tb[IFA_LOCAL] && - ifa->ifa_local != nla_get_in_addr(tb[IFA_LOCAL])) - continue; - - if (tb[IFA_LABEL] && nla_strcmp(tb[IFA_LABEL], ifa->ifa_label)) - continue; - - if (tb[IFA_ADDRESS] && - (ifm->ifa_prefixlen != ifa->ifa_prefixlen || - !inet_ifa_match(nla_get_in_addr(tb[IFA_ADDRESS]), ifa))) - continue; - - if (ipv4_is_multicast(ifa->ifa_address)) - ip_mc_config(net->ipv4.mc_autojoin_sk, false, ifa); - __inet_del_ifa(in_dev, ifap, 1, nlh, NETLINK_CB(skb).portid); - return 0; - } - - err = -EADDRNOTAVAIL; -errout: - return err; -} - -#define INFINITY_LIFE_TIME 0xFFFFFFFF - -static void check_lifetime(struct work_struct *work) -{ - unsigned long now, next, next_sec, next_sched; - struct in_ifaddr *ifa; - struct hlist_node *n; - int i; - - now = jiffies; - next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY); - - for (i = 0; i < IN4_ADDR_HSIZE; i++) { - bool change_needed = false; - - rcu_read_lock(); - hlist_for_each_entry_rcu(ifa, &inet_addr_lst[i], hash) { - unsigned long age; - - if (ifa->ifa_flags & IFA_F_PERMANENT) - continue; - - /* We try to batch several events at once. */ - age = (now - ifa->ifa_tstamp + - ADDRCONF_TIMER_FUZZ_MINUS) / HZ; - - if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME && - age >= ifa->ifa_valid_lft) { - change_needed = true; - } else if (ifa->ifa_preferred_lft == - INFINITY_LIFE_TIME) { - continue; - } else if (age >= ifa->ifa_preferred_lft) { - if (time_before(ifa->ifa_tstamp + - ifa->ifa_valid_lft * HZ, next)) - next = ifa->ifa_tstamp + - ifa->ifa_valid_lft * HZ; - - if (!(ifa->ifa_flags & IFA_F_DEPRECATED)) - change_needed = true; - } else if (time_before(ifa->ifa_tstamp + - ifa->ifa_preferred_lft * HZ, - next)) { - next = ifa->ifa_tstamp + - ifa->ifa_preferred_lft * HZ; - } - } - rcu_read_unlock(); - if (!change_needed) - continue; - rtnl_lock(); - hlist_for_each_entry_safe(ifa, n, &inet_addr_lst[i], hash) { - unsigned long age; - - if (ifa->ifa_flags & IFA_F_PERMANENT) - continue; - - /* We try to batch several events at once. */ - age = (now - ifa->ifa_tstamp + - ADDRCONF_TIMER_FUZZ_MINUS) / HZ; - - if (ifa->ifa_valid_lft != INFINITY_LIFE_TIME && - age >= ifa->ifa_valid_lft) { - struct in_ifaddr **ifap; - - for (ifap = &ifa->ifa_dev->ifa_list; - *ifap != NULL; ifap = &(*ifap)->ifa_next) { - if (*ifap == ifa) { - inet_del_ifa(ifa->ifa_dev, - ifap, 1); - break; - } - } - } else if (ifa->ifa_preferred_lft != - INFINITY_LIFE_TIME && - age >= ifa->ifa_preferred_lft && - !(ifa->ifa_flags & IFA_F_DEPRECATED)) { - ifa->ifa_flags |= IFA_F_DEPRECATED; - rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0); - } - } - rtnl_unlock(); - } - - next_sec = round_jiffies_up(next); - next_sched = next; - - /* If rounded timeout is accurate enough, accept it. */ - if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ)) - next_sched = next_sec; - - now = jiffies; - /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */ - if (time_before(next_sched, now + ADDRCONF_TIMER_FUZZ_MAX)) - next_sched = now + ADDRCONF_TIMER_FUZZ_MAX; - - queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, - next_sched - now); -} - -static void set_ifa_lifetime(struct in_ifaddr *ifa, __u32 valid_lft, - __u32 prefered_lft) -{ - unsigned long timeout; - - ifa->ifa_flags &= ~(IFA_F_PERMANENT | IFA_F_DEPRECATED); - - timeout = addrconf_timeout_fixup(valid_lft, HZ); - if (addrconf_finite_timeout(timeout)) - ifa->ifa_valid_lft = timeout; - else - ifa->ifa_flags |= IFA_F_PERMANENT; - - timeout = addrconf_timeout_fixup(prefered_lft, HZ); - if (addrconf_finite_timeout(timeout)) { - if (timeout == 0) - ifa->ifa_flags |= IFA_F_DEPRECATED; - ifa->ifa_preferred_lft = timeout; - } - ifa->ifa_tstamp = jiffies; - if (!ifa->ifa_cstamp) - ifa->ifa_cstamp = ifa->ifa_tstamp; -} - -static struct in_ifaddr *rtm_to_ifaddr(struct net *net, struct nlmsghdr *nlh, - __u32 *pvalid_lft, __u32 *pprefered_lft) -{ - struct nlattr *tb[IFA_MAX+1]; - struct in_ifaddr *ifa; - struct ifaddrmsg *ifm; - struct net_device *dev; - struct in_device *in_dev; - int err; - - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv4_policy); - if (err < 0) - goto errout; - - ifm = nlmsg_data(nlh); - err = -EINVAL; - if (ifm->ifa_prefixlen > 32 || !tb[IFA_LOCAL]) - goto errout; - - dev = __dev_get_by_index(net, ifm->ifa_index); - err = -ENODEV; - if (!dev) - goto errout; - - in_dev = __in_dev_get_rtnl(dev); - err = -ENOBUFS; - if (!in_dev) - goto errout; - - ifa = inet_alloc_ifa(); - if (!ifa) - /* - * A potential indev allocation can be left alive, it stays - * assigned to its device and is destroy with it. - */ - goto errout; - - ipv4_devconf_setall(in_dev); - neigh_parms_data_state_setall(in_dev->arp_parms); - in_dev_hold(in_dev); - - if (!tb[IFA_ADDRESS]) - tb[IFA_ADDRESS] = tb[IFA_LOCAL]; - - INIT_HLIST_NODE(&ifa->hash); - ifa->ifa_prefixlen = ifm->ifa_prefixlen; - ifa->ifa_mask = inet_make_mask(ifm->ifa_prefixlen); - ifa->ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : - ifm->ifa_flags; - ifa->ifa_scope = ifm->ifa_scope; - ifa->ifa_dev = in_dev; - - ifa->ifa_local = nla_get_in_addr(tb[IFA_LOCAL]); - ifa->ifa_address = nla_get_in_addr(tb[IFA_ADDRESS]); - - if (tb[IFA_BROADCAST]) - ifa->ifa_broadcast = nla_get_in_addr(tb[IFA_BROADCAST]); - - if (tb[IFA_LABEL]) - nla_strlcpy(ifa->ifa_label, tb[IFA_LABEL], IFNAMSIZ); - else - memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); - - if (tb[IFA_CACHEINFO]) { - struct ifa_cacheinfo *ci; - - ci = nla_data(tb[IFA_CACHEINFO]); - if (!ci->ifa_valid || ci->ifa_prefered > ci->ifa_valid) { - err = -EINVAL; - goto errout_free; - } - *pvalid_lft = ci->ifa_valid; - *pprefered_lft = ci->ifa_prefered; - } - - return ifa; - -errout_free: - inet_free_ifa(ifa); -errout: - return ERR_PTR(err); -} - -static struct in_ifaddr *find_matching_ifa(struct in_ifaddr *ifa) -{ - struct in_device *in_dev = ifa->ifa_dev; - struct in_ifaddr *ifa1, **ifap; - - if (!ifa->ifa_local) - return NULL; - - for (ifap = &in_dev->ifa_list; (ifa1 = *ifap) != NULL; - ifap = &ifa1->ifa_next) { - if (ifa1->ifa_mask == ifa->ifa_mask && - inet_ifa_match(ifa1->ifa_address, ifa) && - ifa1->ifa_local == ifa->ifa_local) - return ifa1; - } - return NULL; -} - -static int inet_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct in_ifaddr *ifa; - struct in_ifaddr *ifa_existing; - __u32 valid_lft = INFINITY_LIFE_TIME; - __u32 prefered_lft = INFINITY_LIFE_TIME; - - ASSERT_RTNL(); - - ifa = rtm_to_ifaddr(net, nlh, &valid_lft, &prefered_lft); - if (IS_ERR(ifa)) - return PTR_ERR(ifa); - - ifa_existing = find_matching_ifa(ifa); - if (!ifa_existing) { - /* It would be best to check for !NLM_F_CREATE here but - * userspace already relies on not having to provide this. - */ - set_ifa_lifetime(ifa, valid_lft, prefered_lft); - if (ifa->ifa_flags & IFA_F_MCAUTOJOIN) { - int ret = ip_mc_config(net->ipv4.mc_autojoin_sk, - true, ifa); - - if (ret < 0) { - inet_free_ifa(ifa); - return ret; - } - } - return __inet_insert_ifa(ifa, nlh, NETLINK_CB(skb).portid); - } else { - inet_free_ifa(ifa); - - if (nlh->nlmsg_flags & NLM_F_EXCL || - !(nlh->nlmsg_flags & NLM_F_REPLACE)) - return -EEXIST; - ifa = ifa_existing; - set_ifa_lifetime(ifa, valid_lft, prefered_lft); - cancel_delayed_work(&check_lifetime_work); - queue_delayed_work(system_power_efficient_wq, - &check_lifetime_work, 0); - rtmsg_ifa(RTM_NEWADDR, ifa, nlh, NETLINK_CB(skb).portid); - } - return 0; -} - -/* - * Determine a default network mask, based on the IP address. - */ - -static int inet_abc_len(__be32 addr) -{ - int rc = -1; /* Something else, probably a multicast. */ - - if (ipv4_is_zeronet(addr)) - rc = 0; - else { - __u32 haddr = ntohl(addr); - - if (IN_CLASSA(haddr)) - rc = 8; - else if (IN_CLASSB(haddr)) - rc = 16; - else if (IN_CLASSC(haddr)) - rc = 24; - } - - return rc; -} - - -int devinet_ioctl(struct net *net, unsigned int cmd, void __user *arg) -{ - struct ifreq ifr; - struct sockaddr_in sin_orig; - struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr; - struct in_device *in_dev; - struct in_ifaddr **ifap = NULL; - struct in_ifaddr *ifa = NULL; - struct net_device *dev; - char *colon; - int ret = -EFAULT; - int tryaddrmatch = 0; - - /* - * Fetch the caller's info block into kernel space - */ - - if (copy_from_user(&ifr, arg, sizeof(struct ifreq))) - goto out; - ifr.ifr_name[IFNAMSIZ - 1] = 0; - - /* save original address for comparison */ - memcpy(&sin_orig, sin, sizeof(*sin)); - - colon = strchr(ifr.ifr_name, ':'); - if (colon) - *colon = 0; - - dev_load(net, ifr.ifr_name); - - switch (cmd) { - case SIOCGIFADDR: /* Get interface address */ - case SIOCGIFBRDADDR: /* Get the broadcast address */ - case SIOCGIFDSTADDR: /* Get the destination address */ - case SIOCGIFNETMASK: /* Get the netmask for the interface */ - /* Note that these ioctls will not sleep, - so that we do not impose a lock. - One day we will be forced to put shlock here (I mean SMP) - */ - tryaddrmatch = (sin_orig.sin_family == AF_INET); - memset(sin, 0, sizeof(*sin)); - sin->sin_family = AF_INET; - break; - - case SIOCSIFFLAGS: - ret = -EPERM; - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - goto out; - break; - case SIOCSIFADDR: /* Set interface address (and family) */ - case SIOCSIFBRDADDR: /* Set the broadcast address */ - case SIOCSIFDSTADDR: /* Set the destination address */ - case SIOCSIFNETMASK: /* Set the netmask for the interface */ - ret = -EPERM; - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - goto out; - ret = -EINVAL; - if (sin->sin_family != AF_INET) - goto out; - break; - default: - ret = -EINVAL; - goto out; - } - - rtnl_lock(); - - ret = -ENODEV; - dev = __dev_get_by_name(net, ifr.ifr_name); - if (!dev) - goto done; - - if (colon) - *colon = ':'; - - in_dev = __in_dev_get_rtnl(dev); - if (in_dev) { - if (tryaddrmatch) { - /* Matthias Andree */ - /* compare label and address (4.4BSD style) */ - /* note: we only do this for a limited set of ioctls - and only if the original address family was AF_INET. - This is checked above. */ - for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; - ifap = &ifa->ifa_next) { - if (!strcmp(ifr.ifr_name, ifa->ifa_label) && - sin_orig.sin_addr.s_addr == - ifa->ifa_local) { - break; /* found */ - } - } - } - /* we didn't get a match, maybe the application is - 4.3BSD-style and passed in junk so we fall back to - comparing just the label */ - if (!ifa) { - for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; - ifap = &ifa->ifa_next) - if (!strcmp(ifr.ifr_name, ifa->ifa_label)) - break; - } - } - - ret = -EADDRNOTAVAIL; - if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS) - goto done; - - switch (cmd) { - case SIOCGIFADDR: /* Get interface address */ - sin->sin_addr.s_addr = ifa->ifa_local; - goto rarok; - - case SIOCGIFBRDADDR: /* Get the broadcast address */ - sin->sin_addr.s_addr = ifa->ifa_broadcast; - goto rarok; - - case SIOCGIFDSTADDR: /* Get the destination address */ - sin->sin_addr.s_addr = ifa->ifa_address; - goto rarok; - - case SIOCGIFNETMASK: /* Get the netmask for the interface */ - sin->sin_addr.s_addr = ifa->ifa_mask; - goto rarok; - - case SIOCSIFFLAGS: - if (colon) { - ret = -EADDRNOTAVAIL; - if (!ifa) - break; - ret = 0; - if (!(ifr.ifr_flags & IFF_UP)) - inet_del_ifa(in_dev, ifap, 1); - break; - } - ret = dev_change_flags(dev, ifr.ifr_flags); - break; - - case SIOCSIFADDR: /* Set interface address (and family) */ - ret = -EINVAL; - if (inet_abc_len(sin->sin_addr.s_addr) < 0) - break; - - if (!ifa) { - ret = -ENOBUFS; - ifa = inet_alloc_ifa(); - if (!ifa) - break; - INIT_HLIST_NODE(&ifa->hash); - if (colon) - memcpy(ifa->ifa_label, ifr.ifr_name, IFNAMSIZ); - else - memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); - } else { - ret = 0; - if (ifa->ifa_local == sin->sin_addr.s_addr) - break; - inet_del_ifa(in_dev, ifap, 0); - ifa->ifa_broadcast = 0; - ifa->ifa_scope = 0; - } - - ifa->ifa_address = ifa->ifa_local = sin->sin_addr.s_addr; - - if (!(dev->flags & IFF_POINTOPOINT)) { - ifa->ifa_prefixlen = inet_abc_len(ifa->ifa_address); - ifa->ifa_mask = inet_make_mask(ifa->ifa_prefixlen); - if ((dev->flags & IFF_BROADCAST) && - ifa->ifa_prefixlen < 31) - ifa->ifa_broadcast = ifa->ifa_address | - ~ifa->ifa_mask; - } else { - ifa->ifa_prefixlen = 32; - ifa->ifa_mask = inet_make_mask(32); - } - set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); - ret = inet_set_ifa(dev, ifa); - break; - - case SIOCSIFBRDADDR: /* Set the broadcast address */ - ret = 0; - if (ifa->ifa_broadcast != sin->sin_addr.s_addr) { - inet_del_ifa(in_dev, ifap, 0); - ifa->ifa_broadcast = sin->sin_addr.s_addr; - inet_insert_ifa(ifa); - } - break; - - case SIOCSIFDSTADDR: /* Set the destination address */ - ret = 0; - if (ifa->ifa_address == sin->sin_addr.s_addr) - break; - ret = -EINVAL; - if (inet_abc_len(sin->sin_addr.s_addr) < 0) - break; - ret = 0; - inet_del_ifa(in_dev, ifap, 0); - ifa->ifa_address = sin->sin_addr.s_addr; - inet_insert_ifa(ifa); - break; - - case SIOCSIFNETMASK: /* Set the netmask for the interface */ - - /* - * The mask we set must be legal. - */ - ret = -EINVAL; - if (bad_mask(sin->sin_addr.s_addr, 0)) - break; - ret = 0; - if (ifa->ifa_mask != sin->sin_addr.s_addr) { - __be32 old_mask = ifa->ifa_mask; - inet_del_ifa(in_dev, ifap, 0); - ifa->ifa_mask = sin->sin_addr.s_addr; - ifa->ifa_prefixlen = inet_mask_len(ifa->ifa_mask); - - /* See if current broadcast address matches - * with current netmask, then recalculate - * the broadcast address. Otherwise it's a - * funny address, so don't touch it since - * the user seems to know what (s)he's doing... - */ - if ((dev->flags & IFF_BROADCAST) && - (ifa->ifa_prefixlen < 31) && - (ifa->ifa_broadcast == - (ifa->ifa_local|~old_mask))) { - ifa->ifa_broadcast = (ifa->ifa_local | - ~sin->sin_addr.s_addr); - } - inet_insert_ifa(ifa); - } - break; - } -done: - rtnl_unlock(); -out: - return ret; -rarok: - rtnl_unlock(); - ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0; - goto out; -} - -static int inet_gifconf(struct net_device *dev, char __user *buf, int len) -{ - struct in_device *in_dev = __in_dev_get_rtnl(dev); - struct in_ifaddr *ifa; - struct ifreq ifr; - int done = 0; - - if (!in_dev) - goto out; - - for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { - if (!buf) { - done += sizeof(ifr); - continue; - } - if (len < (int) sizeof(ifr)) - break; - memset(&ifr, 0, sizeof(struct ifreq)); - strcpy(ifr.ifr_name, ifa->ifa_label); - - (*(struct sockaddr_in *)&ifr.ifr_addr).sin_family = AF_INET; - (*(struct sockaddr_in *)&ifr.ifr_addr).sin_addr.s_addr = - ifa->ifa_local; - - if (copy_to_user(buf, &ifr, sizeof(struct ifreq))) { - done = -EFAULT; - break; - } - buf += sizeof(struct ifreq); - len -= sizeof(struct ifreq); - done += sizeof(struct ifreq); - } -out: - return done; -} - -__be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) -{ - __be32 addr = 0; - struct in_device *in_dev; - struct net *net = dev_net(dev); - int master_idx; - - rcu_read_lock(); - in_dev = __in_dev_get_rcu(dev); - if (!in_dev) - goto no_in_dev; - - for_primary_ifa(in_dev) { - if (ifa->ifa_scope > scope) - continue; - if (!dst || inet_ifa_match(dst, ifa)) { - addr = ifa->ifa_local; - break; - } - if (!addr) - addr = ifa->ifa_local; - } endfor_ifa(in_dev); - - if (addr) - goto out_unlock; -no_in_dev: - master_idx = l3mdev_master_ifindex_rcu(dev); - - /* For VRFs, the VRF device takes the place of the loopback device, - * with addresses on it being preferred. Note in such cases the - * loopback device will be among the devices that fail the master_idx - * equality check in the loop below. - */ - if (master_idx && - (dev = dev_get_by_index_rcu(net, master_idx)) && - (in_dev = __in_dev_get_rcu(dev))) { - for_primary_ifa(in_dev) { - if (ifa->ifa_scope != RT_SCOPE_LINK && - ifa->ifa_scope <= scope) { - addr = ifa->ifa_local; - goto out_unlock; - } - } endfor_ifa(in_dev); - } - - /* Not loopback addresses on loopback should be preferred - in this case. It is important that lo is the first interface - in dev_base list. - */ - for_each_netdev_rcu(net, dev) { - if (l3mdev_master_ifindex_rcu(dev) != master_idx) - continue; - - in_dev = __in_dev_get_rcu(dev); - if (!in_dev) - continue; - - for_primary_ifa(in_dev) { - if (ifa->ifa_scope != RT_SCOPE_LINK && - ifa->ifa_scope <= scope) { - addr = ifa->ifa_local; - goto out_unlock; - } - } endfor_ifa(in_dev); - } -out_unlock: - rcu_read_unlock(); - return addr; -} -EXPORT_SYMBOL(inet_select_addr); - -static __be32 confirm_addr_indev(struct in_device *in_dev, __be32 dst, - __be32 local, int scope) -{ - int same = 0; - __be32 addr = 0; - - for_ifa(in_dev) { - if (!addr && - (local == ifa->ifa_local || !local) && - ifa->ifa_scope <= scope) { - addr = ifa->ifa_local; - if (same) - break; - } - if (!same) { - same = (!local || inet_ifa_match(local, ifa)) && - (!dst || inet_ifa_match(dst, ifa)); - if (same && addr) { - if (local || !dst) - break; - /* Is the selected addr into dst subnet? */ - if (inet_ifa_match(addr, ifa)) - break; - /* No, then can we use new local src? */ - if (ifa->ifa_scope <= scope) { - addr = ifa->ifa_local; - break; - } - /* search for large dst subnet for addr */ - same = 0; - } - } - } endfor_ifa(in_dev); - - return same ? addr : 0; -} - -/* - * Confirm that local IP address exists using wildcards: - * - net: netns to check, cannot be NULL - * - in_dev: only on this interface, NULL=any interface - * - dst: only in the same subnet as dst, 0=any dst - * - local: address, 0=autoselect the local address - * - scope: maximum allowed scope value for the local address - */ -__be32 inet_confirm_addr(struct net *net, struct in_device *in_dev, - __be32 dst, __be32 local, int scope) -{ - __be32 addr = 0; - struct net_device *dev; - - if (in_dev) - return confirm_addr_indev(in_dev, dst, local, scope); - - rcu_read_lock(); - for_each_netdev_rcu(net, dev) { - in_dev = __in_dev_get_rcu(dev); - if (in_dev) { - addr = confirm_addr_indev(in_dev, dst, local, scope); - if (addr) - break; - } - } - rcu_read_unlock(); - - return addr; -} -EXPORT_SYMBOL(inet_confirm_addr); - -/* - * Device notifier - */ - -int register_inetaddr_notifier(struct notifier_block *nb) -{ - return blocking_notifier_chain_register(&inetaddr_chain, nb); -} -EXPORT_SYMBOL(register_inetaddr_notifier); - -int unregister_inetaddr_notifier(struct notifier_block *nb) -{ - return blocking_notifier_chain_unregister(&inetaddr_chain, nb); -} -EXPORT_SYMBOL(unregister_inetaddr_notifier); - -/* Rename ifa_labels for a device name change. Make some effort to preserve - * existing alias numbering and to create unique labels if possible. -*/ -static void inetdev_changename(struct net_device *dev, struct in_device *in_dev) -{ - struct in_ifaddr *ifa; - int named = 0; - - for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { - char old[IFNAMSIZ], *dot; - - memcpy(old, ifa->ifa_label, IFNAMSIZ); - memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); - if (named++ == 0) - goto skip; - dot = strchr(old, ':'); - if (!dot) { - sprintf(old, ":%d", named); - dot = old; - } - if (strlen(dot) + strlen(dev->name) < IFNAMSIZ) - strcat(ifa->ifa_label, dot); - else - strcpy(ifa->ifa_label + (IFNAMSIZ - strlen(dot) - 1), dot); -skip: - rtmsg_ifa(RTM_NEWADDR, ifa, NULL, 0); - } -} - -static bool inetdev_valid_mtu(unsigned int mtu) -{ - return mtu >= 68; -} - -static void inetdev_send_gratuitous_arp(struct net_device *dev, - struct in_device *in_dev) - -{ - struct in_ifaddr *ifa; - - for (ifa = in_dev->ifa_list; ifa; - ifa = ifa->ifa_next) { - arp_send(ARPOP_REQUEST, ETH_P_ARP, - ifa->ifa_local, dev, - ifa->ifa_local, NULL, - dev->dev_addr, NULL); - } -} - -/* Called only under RTNL semaphore */ - -static int inetdev_event(struct notifier_block *this, unsigned long event, - void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct in_device *in_dev = __in_dev_get_rtnl(dev); - - ASSERT_RTNL(); - - if (!in_dev) { - if (event == NETDEV_REGISTER) { - in_dev = inetdev_init(dev); - if (IS_ERR(in_dev)) - return notifier_from_errno(PTR_ERR(in_dev)); - if (dev->flags & IFF_LOOPBACK) { - IN_DEV_CONF_SET(in_dev, NOXFRM, 1); - IN_DEV_CONF_SET(in_dev, NOPOLICY, 1); - } - } else if (event == NETDEV_CHANGEMTU) { - /* Re-enabling IP */ - if (inetdev_valid_mtu(dev->mtu)) - in_dev = inetdev_init(dev); - } - goto out; - } - - switch (event) { - case NETDEV_REGISTER: - pr_debug("%s: bug\n", __func__); - RCU_INIT_POINTER(dev->ip_ptr, NULL); - break; - case NETDEV_UP: - if (!inetdev_valid_mtu(dev->mtu)) - break; - if (dev->flags & IFF_LOOPBACK) { - struct in_ifaddr *ifa = inet_alloc_ifa(); - - if (ifa) { - INIT_HLIST_NODE(&ifa->hash); - ifa->ifa_local = - ifa->ifa_address = htonl(INADDR_LOOPBACK); - ifa->ifa_prefixlen = 8; - ifa->ifa_mask = inet_make_mask(8); - in_dev_hold(in_dev); - ifa->ifa_dev = in_dev; - ifa->ifa_scope = RT_SCOPE_HOST; - memcpy(ifa->ifa_label, dev->name, IFNAMSIZ); - set_ifa_lifetime(ifa, INFINITY_LIFE_TIME, - INFINITY_LIFE_TIME); - ipv4_devconf_setall(in_dev); - neigh_parms_data_state_setall(in_dev->arp_parms); - inet_insert_ifa(ifa); - } - } - ip_mc_up(in_dev); - /* fall through */ - case NETDEV_CHANGEADDR: - if (!IN_DEV_ARP_NOTIFY(in_dev)) - break; - /* fall through */ - case NETDEV_NOTIFY_PEERS: - /* Send gratuitous ARP to notify of link change */ - inetdev_send_gratuitous_arp(dev, in_dev); - break; - case NETDEV_DOWN: - ip_mc_down(in_dev); - break; - case NETDEV_PRE_TYPE_CHANGE: - ip_mc_unmap(in_dev); - break; - case NETDEV_POST_TYPE_CHANGE: - ip_mc_remap(in_dev); - break; - case NETDEV_CHANGEMTU: - if (inetdev_valid_mtu(dev->mtu)) - break; - /* disable IP when MTU is not enough */ - case NETDEV_UNREGISTER: - inetdev_destroy(in_dev); - break; - case NETDEV_CHANGENAME: - /* Do not notify about label change, this event is - * not interesting to applications using netlink. - */ - inetdev_changename(dev, in_dev); - - devinet_sysctl_unregister(in_dev); - devinet_sysctl_register(in_dev); - break; - } -out: - return NOTIFY_DONE; -} - -static struct notifier_block ip_netdev_notifier = { - .notifier_call = inetdev_event, -}; - -static size_t inet_nlmsg_size(void) -{ - return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) - + nla_total_size(4) /* IFA_ADDRESS */ - + nla_total_size(4) /* IFA_LOCAL */ - + nla_total_size(4) /* IFA_BROADCAST */ - + nla_total_size(IFNAMSIZ) /* IFA_LABEL */ - + nla_total_size(4) /* IFA_FLAGS */ - + nla_total_size(sizeof(struct ifa_cacheinfo)); /* IFA_CACHEINFO */ -} - -static inline u32 cstamp_delta(unsigned long cstamp) -{ - return (cstamp - INITIAL_JIFFIES) * 100UL / HZ; -} - -static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp, - unsigned long tstamp, u32 preferred, u32 valid) -{ - struct ifa_cacheinfo ci; - - ci.cstamp = cstamp_delta(cstamp); - ci.tstamp = cstamp_delta(tstamp); - ci.ifa_prefered = preferred; - ci.ifa_valid = valid; - - return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci); -} - -static int inet_fill_ifaddr(struct sk_buff *skb, struct in_ifaddr *ifa, - u32 portid, u32 seq, int event, unsigned int flags) -{ - struct ifaddrmsg *ifm; - struct nlmsghdr *nlh; - u32 preferred, valid; - - nlh = nlmsg_put(skb, portid, seq, event, sizeof(*ifm), flags); - if (!nlh) - return -EMSGSIZE; - - ifm = nlmsg_data(nlh); - ifm->ifa_family = AF_INET; - ifm->ifa_prefixlen = ifa->ifa_prefixlen; - ifm->ifa_flags = ifa->ifa_flags; - ifm->ifa_scope = ifa->ifa_scope; - ifm->ifa_index = ifa->ifa_dev->dev->ifindex; - - if (!(ifm->ifa_flags & IFA_F_PERMANENT)) { - preferred = ifa->ifa_preferred_lft; - valid = ifa->ifa_valid_lft; - if (preferred != INFINITY_LIFE_TIME) { - long tval = (jiffies - ifa->ifa_tstamp) / HZ; - - if (preferred > tval) - preferred -= tval; - else - preferred = 0; - if (valid != INFINITY_LIFE_TIME) { - if (valid > tval) - valid -= tval; - else - valid = 0; - } - } - } else { - preferred = INFINITY_LIFE_TIME; - valid = INFINITY_LIFE_TIME; - } - if ((ifa->ifa_address && - nla_put_in_addr(skb, IFA_ADDRESS, ifa->ifa_address)) || - (ifa->ifa_local && - nla_put_in_addr(skb, IFA_LOCAL, ifa->ifa_local)) || - (ifa->ifa_broadcast && - nla_put_in_addr(skb, IFA_BROADCAST, ifa->ifa_broadcast)) || - (ifa->ifa_label[0] && - nla_put_string(skb, IFA_LABEL, ifa->ifa_label)) || - nla_put_u32(skb, IFA_FLAGS, ifa->ifa_flags) || - put_cacheinfo(skb, ifa->ifa_cstamp, ifa->ifa_tstamp, - preferred, valid)) - goto nla_put_failure; - - nlmsg_end(skb, nlh); - return 0; - -nla_put_failure: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -static int inet_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) -{ - struct net *net = sock_net(skb->sk); - int h, s_h; - int idx, s_idx; - int ip_idx, s_ip_idx; - struct net_device *dev; - struct in_device *in_dev; - struct in_ifaddr *ifa; - struct hlist_head *head; - - s_h = cb->args[0]; - s_idx = idx = cb->args[1]; - s_ip_idx = ip_idx = cb->args[2]; - - for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { - idx = 0; - head = &net->dev_index_head[h]; - rcu_read_lock(); - cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^ - net->dev_base_seq; - hlist_for_each_entry_rcu(dev, head, index_hlist) { - if (idx < s_idx) - goto cont; - if (h > s_h || idx > s_idx) - s_ip_idx = 0; - in_dev = __in_dev_get_rcu(dev); - if (!in_dev) - goto cont; - - for (ifa = in_dev->ifa_list, ip_idx = 0; ifa; - ifa = ifa->ifa_next, ip_idx++) { - if (ip_idx < s_ip_idx) - continue; - if (inet_fill_ifaddr(skb, ifa, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWADDR, NLM_F_MULTI) < 0) { - rcu_read_unlock(); - goto done; - } - nl_dump_check_consistent(cb, nlmsg_hdr(skb)); - } -cont: - idx++; - } - rcu_read_unlock(); - } - -done: - cb->args[0] = h; - cb->args[1] = idx; - cb->args[2] = ip_idx; - - return skb->len; -} - -static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh, - u32 portid) -{ - struct sk_buff *skb; - u32 seq = nlh ? nlh->nlmsg_seq : 0; - int err = -ENOBUFS; - struct net *net; - - net = dev_net(ifa->ifa_dev->dev); - skb = nlmsg_new(inet_nlmsg_size(), GFP_KERNEL); - if (!skb) - goto errout; - - err = inet_fill_ifaddr(skb, ifa, portid, seq, event, 0); - if (err < 0) { - /* -EMSGSIZE implies BUG in inet_nlmsg_size() */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - goto errout; - } - rtnl_notify(skb, net, portid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL); - return; -errout: - if (err < 0) - rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err); -} - -static size_t inet_get_link_af_size(const struct net_device *dev, - u32 ext_filter_mask) -{ - struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr); - - if (!in_dev) - return 0; - - return nla_total_size(IPV4_DEVCONF_MAX * 4); /* IFLA_INET_CONF */ -} - -static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev, - u32 ext_filter_mask) -{ - struct in_device *in_dev = rcu_dereference_rtnl(dev->ip_ptr); - struct nlattr *nla; - int i; - - if (!in_dev) - return -ENODATA; - - nla = nla_reserve(skb, IFLA_INET_CONF, IPV4_DEVCONF_MAX * 4); - if (!nla) - return -EMSGSIZE; - - for (i = 0; i < IPV4_DEVCONF_MAX; i++) - ((u32 *) nla_data(nla))[i] = in_dev->cnf.data[i]; - - return 0; -} - -static const struct nla_policy inet_af_policy[IFLA_INET_MAX+1] = { - [IFLA_INET_CONF] = { .type = NLA_NESTED }, -}; - -static int inet_validate_link_af(const struct net_device *dev, - const struct nlattr *nla) -{ - struct nlattr *a, *tb[IFLA_INET_MAX+1]; - int err, rem; - - if (dev && !__in_dev_get_rtnl(dev)) - return -EAFNOSUPPORT; - - err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy); - if (err < 0) - return err; - - if (tb[IFLA_INET_CONF]) { - nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) { - int cfgid = nla_type(a); - - if (nla_len(a) < 4) - return -EINVAL; - - if (cfgid <= 0 || cfgid > IPV4_DEVCONF_MAX) - return -EINVAL; - } - } - - return 0; -} - -static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla) -{ - struct in_device *in_dev = __in_dev_get_rtnl(dev); - struct nlattr *a, *tb[IFLA_INET_MAX+1]; - int rem; - - if (!in_dev) - return -EAFNOSUPPORT; - - if (nla_parse_nested(tb, IFLA_INET_MAX, nla, NULL) < 0) - BUG(); - - if (tb[IFLA_INET_CONF]) { - nla_for_each_nested(a, tb[IFLA_INET_CONF], rem) - ipv4_devconf_set(in_dev, nla_type(a), nla_get_u32(a)); - } - - return 0; -} - -static int inet_netconf_msgsize_devconf(int type) -{ - int size = NLMSG_ALIGN(sizeof(struct netconfmsg)) - + nla_total_size(4); /* NETCONFA_IFINDEX */ - bool all = false; - - if (type == NETCONFA_ALL) - all = true; - - if (all || type == NETCONFA_FORWARDING) - size += nla_total_size(4); - if (all || type == NETCONFA_RP_FILTER) - size += nla_total_size(4); - if (all || type == NETCONFA_MC_FORWARDING) - size += nla_total_size(4); - if (all || type == NETCONFA_PROXY_NEIGH) - size += nla_total_size(4); - if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) - size += nla_total_size(4); - - return size; -} - -static int inet_netconf_fill_devconf(struct sk_buff *skb, int ifindex, - struct ipv4_devconf *devconf, u32 portid, - u32 seq, int event, unsigned int flags, - int type) -{ - struct nlmsghdr *nlh; - struct netconfmsg *ncm; - bool all = false; - - nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg), - flags); - if (!nlh) - return -EMSGSIZE; - - if (type == NETCONFA_ALL) - all = true; - - ncm = nlmsg_data(nlh); - ncm->ncm_family = AF_INET; - - if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0) - goto nla_put_failure; - - if ((all || type == NETCONFA_FORWARDING) && - nla_put_s32(skb, NETCONFA_FORWARDING, - IPV4_DEVCONF(*devconf, FORWARDING)) < 0) - goto nla_put_failure; - if ((all || type == NETCONFA_RP_FILTER) && - nla_put_s32(skb, NETCONFA_RP_FILTER, - IPV4_DEVCONF(*devconf, RP_FILTER)) < 0) - goto nla_put_failure; - if ((all || type == NETCONFA_MC_FORWARDING) && - nla_put_s32(skb, NETCONFA_MC_FORWARDING, - IPV4_DEVCONF(*devconf, MC_FORWARDING)) < 0) - goto nla_put_failure; - if ((all || type == NETCONFA_PROXY_NEIGH) && - nla_put_s32(skb, NETCONFA_PROXY_NEIGH, - IPV4_DEVCONF(*devconf, PROXY_ARP)) < 0) - goto nla_put_failure; - if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) && - nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, - IPV4_DEVCONF(*devconf, IGNORE_ROUTES_WITH_LINKDOWN)) < 0) - goto nla_put_failure; - - nlmsg_end(skb, nlh); - return 0; - -nla_put_failure: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -void inet_netconf_notify_devconf(struct net *net, int type, int ifindex, - struct ipv4_devconf *devconf) -{ - struct sk_buff *skb; - int err = -ENOBUFS; - - skb = nlmsg_new(inet_netconf_msgsize_devconf(type), GFP_KERNEL); - if (!skb) - goto errout; - - err = inet_netconf_fill_devconf(skb, ifindex, devconf, 0, 0, - RTM_NEWNETCONF, 0, type); - if (err < 0) { - /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - goto errout; - } - rtnl_notify(skb, net, 0, RTNLGRP_IPV4_NETCONF, NULL, GFP_KERNEL); - return; -errout: - if (err < 0) - rtnl_set_sk_err(net, RTNLGRP_IPV4_NETCONF, err); -} - -static const struct nla_policy devconf_ipv4_policy[NETCONFA_MAX+1] = { - [NETCONFA_IFINDEX] = { .len = sizeof(int) }, - [NETCONFA_FORWARDING] = { .len = sizeof(int) }, - [NETCONFA_RP_FILTER] = { .len = sizeof(int) }, - [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) }, - [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) }, -}; - -static int inet_netconf_get_devconf(struct sk_buff *in_skb, - struct nlmsghdr *nlh) -{ - struct net *net = sock_net(in_skb->sk); - struct nlattr *tb[NETCONFA_MAX+1]; - struct netconfmsg *ncm; - struct sk_buff *skb; - struct ipv4_devconf *devconf; - struct in_device *in_dev; - struct net_device *dev; - int ifindex; - int err; - - err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX, - devconf_ipv4_policy); - if (err < 0) - goto errout; - - err = -EINVAL; - if (!tb[NETCONFA_IFINDEX]) - goto errout; - - ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]); - switch (ifindex) { - case NETCONFA_IFINDEX_ALL: - devconf = net->ipv4.devconf_all; - break; - case NETCONFA_IFINDEX_DEFAULT: - devconf = net->ipv4.devconf_dflt; - break; - default: - dev = __dev_get_by_index(net, ifindex); - if (!dev) - goto errout; - in_dev = __in_dev_get_rtnl(dev); - if (!in_dev) - goto errout; - devconf = &in_dev->cnf; - break; - } - - err = -ENOBUFS; - skb = nlmsg_new(inet_netconf_msgsize_devconf(NETCONFA_ALL), GFP_KERNEL); - if (!skb) - goto errout; - - err = inet_netconf_fill_devconf(skb, ifindex, devconf, - NETLINK_CB(in_skb).portid, - nlh->nlmsg_seq, RTM_NEWNETCONF, 0, - NETCONFA_ALL); - if (err < 0) { - /* -EMSGSIZE implies BUG in inet_netconf_msgsize_devconf() */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - goto errout; - } - err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); -errout: - return err; -} - -static int inet_netconf_dump_devconf(struct sk_buff *skb, - struct netlink_callback *cb) -{ - struct net *net = sock_net(skb->sk); - int h, s_h; - int idx, s_idx; - struct net_device *dev; - struct in_device *in_dev; - struct hlist_head *head; - - s_h = cb->args[0]; - s_idx = idx = cb->args[1]; - - for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { - idx = 0; - head = &net->dev_index_head[h]; - rcu_read_lock(); - cb->seq = atomic_read(&net->ipv4.dev_addr_genid) ^ - net->dev_base_seq; - hlist_for_each_entry_rcu(dev, head, index_hlist) { - if (idx < s_idx) - goto cont; - in_dev = __in_dev_get_rcu(dev); - if (!in_dev) - goto cont; - - if (inet_netconf_fill_devconf(skb, dev->ifindex, - &in_dev->cnf, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWNETCONF, - NLM_F_MULTI, - NETCONFA_ALL) < 0) { - rcu_read_unlock(); - goto done; - } - nl_dump_check_consistent(cb, nlmsg_hdr(skb)); -cont: - idx++; - } - rcu_read_unlock(); - } - if (h == NETDEV_HASHENTRIES) { - if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL, - net->ipv4.devconf_all, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWNETCONF, NLM_F_MULTI, - NETCONFA_ALL) < 0) - goto done; - else - h++; - } - if (h == NETDEV_HASHENTRIES + 1) { - if (inet_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT, - net->ipv4.devconf_dflt, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWNETCONF, NLM_F_MULTI, - NETCONFA_ALL) < 0) - goto done; - else - h++; - } -done: - cb->args[0] = h; - cb->args[1] = idx; - - return skb->len; -} - -#ifdef CONFIG_SYSCTL - -static void devinet_copy_dflt_conf(struct net *net, int i) -{ - struct net_device *dev; - - rcu_read_lock(); - for_each_netdev_rcu(net, dev) { - struct in_device *in_dev; - - in_dev = __in_dev_get_rcu(dev); - if (in_dev && !test_bit(i, in_dev->cnf.state)) - in_dev->cnf.data[i] = net->ipv4.devconf_dflt->data[i]; - } - rcu_read_unlock(); -} - -/* called with RTNL locked */ -static void inet_forward_change(struct net *net) -{ - struct net_device *dev; - int on = IPV4_DEVCONF_ALL(net, FORWARDING); - - IPV4_DEVCONF_ALL(net, ACCEPT_REDIRECTS) = !on; - IPV4_DEVCONF_DFLT(net, FORWARDING) = on; - inet_netconf_notify_devconf(net, NETCONFA_FORWARDING, - NETCONFA_IFINDEX_ALL, - net->ipv4.devconf_all); - inet_netconf_notify_devconf(net, NETCONFA_FORWARDING, - NETCONFA_IFINDEX_DEFAULT, - net->ipv4.devconf_dflt); - - for_each_netdev(net, dev) { - struct in_device *in_dev; - - if (on) - dev_disable_lro(dev); - - in_dev = __in_dev_get_rtnl(dev); - if (in_dev) { - IN_DEV_CONF_SET(in_dev, FORWARDING, on); - inet_netconf_notify_devconf(net, NETCONFA_FORWARDING, - dev->ifindex, &in_dev->cnf); - } - } -} - -static int devinet_conf_ifindex(struct net *net, struct ipv4_devconf *cnf) -{ - if (cnf == net->ipv4.devconf_dflt) - return NETCONFA_IFINDEX_DEFAULT; - else if (cnf == net->ipv4.devconf_all) - return NETCONFA_IFINDEX_ALL; - else { - struct in_device *idev - = container_of(cnf, struct in_device, cnf); - return idev->dev->ifindex; - } -} - -static int devinet_conf_proc(struct ctl_table *ctl, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - int old_value = *(int *)ctl->data; - int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); - int new_value = *(int *)ctl->data; - - if (write) { - struct ipv4_devconf *cnf = ctl->extra1; - struct net *net = ctl->extra2; - int i = (int *)ctl->data - cnf->data; - int ifindex; - - set_bit(i, cnf->state); - - if (cnf == net->ipv4.devconf_dflt) - devinet_copy_dflt_conf(net, i); - if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1 || - i == IPV4_DEVCONF_ROUTE_LOCALNET - 1) - if ((new_value == 0) && (old_value != 0)) - rt_cache_flush(net); - - if (i == IPV4_DEVCONF_RP_FILTER - 1 && - new_value != old_value) { - ifindex = devinet_conf_ifindex(net, cnf); - inet_netconf_notify_devconf(net, NETCONFA_RP_FILTER, - ifindex, cnf); - } - if (i == IPV4_DEVCONF_PROXY_ARP - 1 && - new_value != old_value) { - ifindex = devinet_conf_ifindex(net, cnf); - inet_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH, - ifindex, cnf); - } - if (i == IPV4_DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN - 1 && - new_value != old_value) { - ifindex = devinet_conf_ifindex(net, cnf); - inet_netconf_notify_devconf(net, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, - ifindex, cnf); - } - } - - return ret; -} - -static int devinet_sysctl_forward(struct ctl_table *ctl, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - int *valp = ctl->data; - int val = *valp; - loff_t pos = *ppos; - int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); - - if (write && *valp != val) { - struct net *net = ctl->extra2; - - if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) { - if (!rtnl_trylock()) { - /* Restore the original values before restarting */ - *valp = val; - *ppos = pos; - return restart_syscall(); - } - if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) { - inet_forward_change(net); - } else { - struct ipv4_devconf *cnf = ctl->extra1; - struct in_device *idev = - container_of(cnf, struct in_device, cnf); - if (*valp) - dev_disable_lro(idev->dev); - inet_netconf_notify_devconf(net, - NETCONFA_FORWARDING, - idev->dev->ifindex, - cnf); - } - rtnl_unlock(); - rt_cache_flush(net); - } else - inet_netconf_notify_devconf(net, NETCONFA_FORWARDING, - NETCONFA_IFINDEX_DEFAULT, - net->ipv4.devconf_dflt); - } - - return ret; -} - -static int ipv4_doint_and_flush(struct ctl_table *ctl, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - int *valp = ctl->data; - int val = *valp; - int ret = proc_dointvec(ctl, write, buffer, lenp, ppos); - struct net *net = ctl->extra2; - - if (write && *valp != val) - rt_cache_flush(net); - - return ret; -} - -#define DEVINET_SYSCTL_ENTRY(attr, name, mval, proc) \ - { \ - .procname = name, \ - .data = ipv4_devconf.data + \ - IPV4_DEVCONF_ ## attr - 1, \ - .maxlen = sizeof(int), \ - .mode = mval, \ - .proc_handler = proc, \ - .extra1 = &ipv4_devconf, \ - } - -#define DEVINET_SYSCTL_RW_ENTRY(attr, name) \ - DEVINET_SYSCTL_ENTRY(attr, name, 0644, devinet_conf_proc) - -#define DEVINET_SYSCTL_RO_ENTRY(attr, name) \ - DEVINET_SYSCTL_ENTRY(attr, name, 0444, devinet_conf_proc) - -#define DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, proc) \ - DEVINET_SYSCTL_ENTRY(attr, name, 0644, proc) - -#define DEVINET_SYSCTL_FLUSHING_ENTRY(attr, name) \ - DEVINET_SYSCTL_COMPLEX_ENTRY(attr, name, ipv4_doint_and_flush) - -static struct devinet_sysctl_table { - struct ctl_table_header *sysctl_header; - struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX]; -} devinet_sysctl = { - .devinet_vars = { - DEVINET_SYSCTL_COMPLEX_ENTRY(FORWARDING, "forwarding", - devinet_sysctl_forward), - DEVINET_SYSCTL_RO_ENTRY(MC_FORWARDING, "mc_forwarding"), - - DEVINET_SYSCTL_RW_ENTRY(ACCEPT_REDIRECTS, "accept_redirects"), - DEVINET_SYSCTL_RW_ENTRY(SECURE_REDIRECTS, "secure_redirects"), - DEVINET_SYSCTL_RW_ENTRY(SHARED_MEDIA, "shared_media"), - DEVINET_SYSCTL_RW_ENTRY(RP_FILTER, "rp_filter"), - DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"), - DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE, - "accept_source_route"), - DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"), - DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"), - DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"), - DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"), - DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"), - DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"), - DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"), - DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"), - DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"), - DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"), - DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"), - DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"), - DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"), - DEVINET_SYSCTL_RW_ENTRY(FORCE_IGMP_VERSION, - "force_igmp_version"), - DEVINET_SYSCTL_RW_ENTRY(IGMPV2_UNSOLICITED_REPORT_INTERVAL, - "igmpv2_unsolicited_report_interval"), - DEVINET_SYSCTL_RW_ENTRY(IGMPV3_UNSOLICITED_REPORT_INTERVAL, - "igmpv3_unsolicited_report_interval"), - DEVINET_SYSCTL_RW_ENTRY(IGNORE_ROUTES_WITH_LINKDOWN, - "ignore_routes_with_linkdown"), - DEVINET_SYSCTL_RW_ENTRY(DROP_GRATUITOUS_ARP, - "drop_gratuitous_arp"), - - DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"), - DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"), - DEVINET_SYSCTL_FLUSHING_ENTRY(PROMOTE_SECONDARIES, - "promote_secondaries"), - DEVINET_SYSCTL_FLUSHING_ENTRY(ROUTE_LOCALNET, - "route_localnet"), - DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST, - "drop_unicast_in_l2_multicast"), - }, -}; - -static int __devinet_sysctl_register(struct net *net, char *dev_name, - int ifindex, struct ipv4_devconf *p) -{ - int i; - struct devinet_sysctl_table *t; - char path[sizeof("net/ipv4/conf/") + IFNAMSIZ]; - - t = kmemdup(&devinet_sysctl, sizeof(*t), GFP_KERNEL); - if (!t) - goto out; - - for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) { - t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf; - t->devinet_vars[i].extra1 = p; - t->devinet_vars[i].extra2 = net; - } - - snprintf(path, sizeof(path), "net/ipv4/conf/%s", dev_name); - - t->sysctl_header = register_net_sysctl(net, path, t->devinet_vars); - if (!t->sysctl_header) - goto free; - - p->sysctl = t; - - inet_netconf_notify_devconf(net, NETCONFA_ALL, ifindex, p); - return 0; - -free: - kfree(t); -out: - return -ENOBUFS; -} - -static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf) -{ - struct devinet_sysctl_table *t = cnf->sysctl; - - if (!t) - return; - - cnf->sysctl = NULL; - unregister_net_sysctl_table(t->sysctl_header); - kfree(t); -} - -static int devinet_sysctl_register(struct in_device *idev) -{ - int err; - - if (!sysctl_dev_name_is_allowed(idev->dev->name)) - return -EINVAL; - - err = neigh_sysctl_register(idev->dev, idev->arp_parms, NULL); - if (err) - return err; - err = __devinet_sysctl_register(dev_net(idev->dev), idev->dev->name, - idev->dev->ifindex, &idev->cnf); - if (err) - neigh_sysctl_unregister(idev->arp_parms); - return err; -} - -static void devinet_sysctl_unregister(struct in_device *idev) -{ - __devinet_sysctl_unregister(&idev->cnf); - neigh_sysctl_unregister(idev->arp_parms); -} - -static struct ctl_table ctl_forward_entry[] = { - { - .procname = "ip_forward", - .data = &ipv4_devconf.data[ - IPV4_DEVCONF_FORWARDING - 1], - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = devinet_sysctl_forward, - .extra1 = &ipv4_devconf, - .extra2 = &init_net, - }, - { }, -}; -#endif - -static __net_init int devinet_init_net(struct net *net) -{ - int err; - struct ipv4_devconf *all, *dflt; -#ifdef CONFIG_SYSCTL - struct ctl_table *tbl = ctl_forward_entry; - struct ctl_table_header *forw_hdr; -#endif - - err = -ENOMEM; - all = &ipv4_devconf; - dflt = &ipv4_devconf_dflt; - - if (!net_eq(net, &init_net)) { - all = kmemdup(all, sizeof(ipv4_devconf), GFP_KERNEL); - if (!all) - goto err_alloc_all; - - dflt = kmemdup(dflt, sizeof(ipv4_devconf_dflt), GFP_KERNEL); - if (!dflt) - goto err_alloc_dflt; - -#ifdef CONFIG_SYSCTL - tbl = kmemdup(tbl, sizeof(ctl_forward_entry), GFP_KERNEL); - if (!tbl) - goto err_alloc_ctl; - - tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1]; - tbl[0].extra1 = all; - tbl[0].extra2 = net; -#endif - } - -#ifdef CONFIG_SYSCTL - err = __devinet_sysctl_register(net, "all", NETCONFA_IFINDEX_ALL, all); - if (err < 0) - goto err_reg_all; - - err = __devinet_sysctl_register(net, "default", - NETCONFA_IFINDEX_DEFAULT, dflt); - if (err < 0) - goto err_reg_dflt; - - err = -ENOMEM; - forw_hdr = register_net_sysctl(net, "net/ipv4", tbl); - if (!forw_hdr) - goto err_reg_ctl; - net->ipv4.forw_hdr = forw_hdr; -#endif - - net->ipv4.devconf_all = all; - net->ipv4.devconf_dflt = dflt; - return 0; - -#ifdef CONFIG_SYSCTL -err_reg_ctl: - __devinet_sysctl_unregister(dflt); -err_reg_dflt: - __devinet_sysctl_unregister(all); -err_reg_all: - if (tbl != ctl_forward_entry) - kfree(tbl); -err_alloc_ctl: -#endif - if (dflt != &ipv4_devconf_dflt) - kfree(dflt); -err_alloc_dflt: - if (all != &ipv4_devconf) - kfree(all); -err_alloc_all: - return err; -} - -static __net_exit void devinet_exit_net(struct net *net) -{ -#ifdef CONFIG_SYSCTL - struct ctl_table *tbl; - - tbl = net->ipv4.forw_hdr->ctl_table_arg; - unregister_net_sysctl_table(net->ipv4.forw_hdr); - __devinet_sysctl_unregister(net->ipv4.devconf_dflt); - __devinet_sysctl_unregister(net->ipv4.devconf_all); - kfree(tbl); -#endif - kfree(net->ipv4.devconf_dflt); - kfree(net->ipv4.devconf_all); -} - -static __net_initdata struct pernet_operations devinet_ops = { - .init = devinet_init_net, - .exit = devinet_exit_net, -}; - -static struct rtnl_af_ops inet_af_ops __read_mostly = { - .family = AF_INET, - .fill_link_af = inet_fill_link_af, - .get_link_af_size = inet_get_link_af_size, - .validate_link_af = inet_validate_link_af, - .set_link_af = inet_set_link_af, -}; - -void __init devinet_init(void) -{ - int i; - - for (i = 0; i < IN4_ADDR_HSIZE; i++) - INIT_HLIST_HEAD(&inet_addr_lst[i]); - - register_pernet_subsys(&devinet_ops); - - register_gifconf(PF_INET, inet_gifconf); - register_netdevice_notifier(&ip_netdev_notifier); - - queue_delayed_work(system_power_efficient_wq, &check_lifetime_work, 0); - - rtnl_af_register(&inet_af_ops); - - rtnl_register(PF_INET, RTM_NEWADDR, inet_rtm_newaddr, NULL, NULL); - rtnl_register(PF_INET, RTM_DELADDR, inet_rtm_deladdr, NULL, NULL); - rtnl_register(PF_INET, RTM_GETADDR, NULL, inet_dump_ifaddr, NULL); - rtnl_register(PF_INET, RTM_GETNETCONF, inet_netconf_get_devconf, - inet_netconf_dump_devconf, NULL); -} diff --git a/src/linux/net/ipv4/fib_frontend.c b/src/linux/net/ipv4/fib_frontend.c deleted file mode 100644 index 161fc0f..0000000 --- a/src/linux/net/ipv4/fib_frontend.c +++ /dev/null @@ -1,1315 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * IPv4 Forwarding Information Base: FIB frontend. - * - * Authors: Alexey Kuznetsov, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#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 -#include -#include -#include -#include -#include - -#ifndef CONFIG_IP_MULTIPLE_TABLES - -static int __net_init fib4_rules_init(struct net *net) -{ - struct fib_table *local_table, *main_table; - - main_table = fib_trie_table(RT_TABLE_MAIN, NULL); - if (!main_table) - return -ENOMEM; - - local_table = fib_trie_table(RT_TABLE_LOCAL, main_table); - if (!local_table) - goto fail; - - hlist_add_head_rcu(&local_table->tb_hlist, - &net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX]); - hlist_add_head_rcu(&main_table->tb_hlist, - &net->ipv4.fib_table_hash[TABLE_MAIN_INDEX]); - return 0; - -fail: - fib_free_table(main_table); - return -ENOMEM; -} -#else - -struct fib_table *fib_new_table(struct net *net, u32 id) -{ - struct fib_table *tb, *alias = NULL; - unsigned int h; - - if (id == 0) - id = RT_TABLE_MAIN; - tb = fib_get_table(net, id); - if (tb) - return tb; - - if (id == RT_TABLE_LOCAL) - alias = fib_new_table(net, RT_TABLE_MAIN); - - tb = fib_trie_table(id, alias); - if (!tb) - return NULL; - - switch (id) { - case RT_TABLE_MAIN: - rcu_assign_pointer(net->ipv4.fib_main, tb); - break; - case RT_TABLE_DEFAULT: - rcu_assign_pointer(net->ipv4.fib_default, tb); - break; - default: - break; - } - - h = id & (FIB_TABLE_HASHSZ - 1); - hlist_add_head_rcu(&tb->tb_hlist, &net->ipv4.fib_table_hash[h]); - return tb; -} -EXPORT_SYMBOL_GPL(fib_new_table); - -/* caller must hold either rtnl or rcu read lock */ -struct fib_table *fib_get_table(struct net *net, u32 id) -{ - struct fib_table *tb; - struct hlist_head *head; - unsigned int h; - - if (id == 0) - id = RT_TABLE_MAIN; - h = id & (FIB_TABLE_HASHSZ - 1); - - head = &net->ipv4.fib_table_hash[h]; - hlist_for_each_entry_rcu(tb, head, tb_hlist) { - if (tb->tb_id == id) - return tb; - } - return NULL; -} -#endif /* CONFIG_IP_MULTIPLE_TABLES */ - -static void fib_replace_table(struct net *net, struct fib_table *old, - struct fib_table *new) -{ -#ifdef CONFIG_IP_MULTIPLE_TABLES - switch (new->tb_id) { - case RT_TABLE_MAIN: - rcu_assign_pointer(net->ipv4.fib_main, new); - break; - case RT_TABLE_DEFAULT: - rcu_assign_pointer(net->ipv4.fib_default, new); - break; - default: - break; - } - -#endif - /* replace the old table in the hlist */ - hlist_replace_rcu(&old->tb_hlist, &new->tb_hlist); -} - -int fib_unmerge(struct net *net) -{ - struct fib_table *old, *new, *main_table; - - /* attempt to fetch local table if it has been allocated */ - old = fib_get_table(net, RT_TABLE_LOCAL); - if (!old) - return 0; - - new = fib_trie_unmerge(old); - if (!new) - return -ENOMEM; - - /* table is already unmerged */ - if (new == old) - return 0; - - /* replace merged table with clean table */ - fib_replace_table(net, old, new); - fib_free_table(old); - - /* attempt to fetch main table if it has been allocated */ - main_table = fib_get_table(net, RT_TABLE_MAIN); - if (!main_table) - return 0; - - /* flush local entries from main table */ - fib_table_flush_external(main_table); - - return 0; -} - -static void fib_flush(struct net *net) -{ - int flushed = 0; - unsigned int h; - - for (h = 0; h < FIB_TABLE_HASHSZ; h++) { - struct hlist_head *head = &net->ipv4.fib_table_hash[h]; - struct hlist_node *tmp; - struct fib_table *tb; - - hlist_for_each_entry_safe(tb, tmp, head, tb_hlist) - flushed += fib_table_flush(net, tb); - } - - if (flushed) - rt_cache_flush(net); -} - -/* - * Find address type as if only "dev" was present in the system. If - * on_dev is NULL then all interfaces are taken into consideration. - */ -static inline unsigned int __inet_dev_addr_type(struct net *net, - const struct net_device *dev, - __be32 addr, u32 tb_id) -{ - struct flowi4 fl4 = { .daddr = addr }; - struct fib_result res; - unsigned int ret = RTN_BROADCAST; - struct fib_table *table; - - if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr)) - return RTN_BROADCAST; - if (ipv4_is_multicast(addr)) - return RTN_MULTICAST; - - rcu_read_lock(); - - table = fib_get_table(net, tb_id); - if (table) { - ret = RTN_UNICAST; - if (!fib_table_lookup(table, &fl4, &res, FIB_LOOKUP_NOREF)) { - if (!dev || dev == res.fi->fib_dev) - ret = res.type; - } - } - - rcu_read_unlock(); - return ret; -} - -unsigned int inet_addr_type_table(struct net *net, __be32 addr, u32 tb_id) -{ - return __inet_dev_addr_type(net, NULL, addr, tb_id); -} -EXPORT_SYMBOL(inet_addr_type_table); - -unsigned int inet_addr_type(struct net *net, __be32 addr) -{ - return __inet_dev_addr_type(net, NULL, addr, RT_TABLE_LOCAL); -} -EXPORT_SYMBOL(inet_addr_type); - -unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev, - __be32 addr) -{ - u32 rt_table = l3mdev_fib_table(dev) ? : RT_TABLE_LOCAL; - - return __inet_dev_addr_type(net, dev, addr, rt_table); -} -EXPORT_SYMBOL(inet_dev_addr_type); - -/* inet_addr_type with dev == NULL but using the table from a dev - * if one is associated - */ -unsigned int inet_addr_type_dev_table(struct net *net, - const struct net_device *dev, - __be32 addr) -{ - u32 rt_table = l3mdev_fib_table(dev) ? : RT_TABLE_LOCAL; - - return __inet_dev_addr_type(net, NULL, addr, rt_table); -} -EXPORT_SYMBOL(inet_addr_type_dev_table); - -__be32 fib_compute_spec_dst(struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - struct in_device *in_dev; - struct fib_result res; - struct rtable *rt; - struct net *net; - int scope; - - rt = skb_rtable(skb); - if ((rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST | RTCF_LOCAL)) == - RTCF_LOCAL) - return ip_hdr(skb)->daddr; - - in_dev = __in_dev_get_rcu(dev); - BUG_ON(!in_dev); - - net = dev_net(dev); - - scope = RT_SCOPE_UNIVERSE; - if (!ipv4_is_zeronet(ip_hdr(skb)->saddr)) { - struct flowi4 fl4 = { - .flowi4_iif = LOOPBACK_IFINDEX, - .daddr = ip_hdr(skb)->saddr, - .flowi4_tos = RT_TOS(ip_hdr(skb)->tos), - .flowi4_scope = scope, - .flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0, - }; - if (!fib_lookup(net, &fl4, &res, 0)) - return FIB_RES_PREFSRC(net, res); - } else { - scope = RT_SCOPE_LINK; - } - - return inet_select_addr(dev, ip_hdr(skb)->saddr, scope); -} - -/* Given (packet source, input interface) and optional (dst, oif, tos): - * - (main) check, that source is valid i.e. not broadcast or our local - * address. - * - figure out what "logical" interface this packet arrived - * and calculate "specific destination" address. - * - check, that packet arrived from expected physical interface. - * called with rcu_read_lock() - */ -static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, - u8 tos, int oif, struct net_device *dev, - int rpf, struct in_device *idev, u32 *itag) -{ - int ret, no_addr; - struct fib_result res; - struct flowi4 fl4; - struct net *net; - bool dev_match; - - fl4.flowi4_oif = 0; - fl4.flowi4_iif = l3mdev_master_ifindex_rcu(dev); - if (!fl4.flowi4_iif) - fl4.flowi4_iif = oif ? : LOOPBACK_IFINDEX; - fl4.daddr = src; - fl4.saddr = dst; - fl4.flowi4_tos = tos; - fl4.flowi4_scope = RT_SCOPE_UNIVERSE; - fl4.flowi4_tun_key.tun_id = 0; - fl4.flowi4_flags = 0; - - no_addr = idev->ifa_list == NULL; - - fl4.flowi4_mark = IN_DEV_SRC_VMARK(idev) ? skb->mark : 0; - - trace_fib_validate_source(dev, &fl4); - - net = dev_net(dev); - if (fib_lookup(net, &fl4, &res, 0)) - goto last_resort; - if (res.type != RTN_UNICAST && - (res.type != RTN_LOCAL || !IN_DEV_ACCEPT_LOCAL(idev))) - goto e_inval; - if (!rpf && !fib_num_tclassid_users(dev_net(dev)) && - (dev->ifindex != oif || !IN_DEV_TX_REDIRECTS(idev))) - goto last_resort; - fib_combine_itag(itag, &res); - dev_match = false; - -#ifdef CONFIG_IP_ROUTE_MULTIPATH - for (ret = 0; ret < res.fi->fib_nhs; ret++) { - struct fib_nh *nh = &res.fi->fib_nh[ret]; - - if (nh->nh_dev == dev) { - dev_match = true; - break; - } else if (l3mdev_master_ifindex_rcu(nh->nh_dev) == dev->ifindex) { - dev_match = true; - break; - } - } -#else - if (FIB_RES_DEV(res) == dev) - dev_match = true; -#endif - if (dev_match) { - ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; - return ret; - } - if (no_addr) - goto last_resort; - if (rpf == 1) - goto e_rpf; - fl4.flowi4_oif = dev->ifindex; - - ret = 0; - if (fib_lookup(net, &fl4, &res, FIB_LOOKUP_IGNORE_LINKSTATE) == 0) { - if (res.type == RTN_UNICAST) - ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; - } - return ret; - -last_resort: - if (rpf) - goto e_rpf; - *itag = 0; - return 0; - -e_inval: - return -EINVAL; -e_rpf: - return -EXDEV; -} - -/* Ignore rp_filter for packets protected by IPsec. */ -int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, - u8 tos, int oif, struct net_device *dev, - struct in_device *idev, u32 *itag) -{ - int r = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev); - - if (!r && !fib_num_tclassid_users(dev_net(dev)) && - IN_DEV_ACCEPT_LOCAL(idev) && - (dev->ifindex != oif || !IN_DEV_TX_REDIRECTS(idev))) { - *itag = 0; - return 0; - } - return __fib_validate_source(skb, src, dst, tos, oif, dev, r, idev, itag); -} - -static inline __be32 sk_extract_addr(struct sockaddr *addr) -{ - return ((struct sockaddr_in *) addr)->sin_addr.s_addr; -} - -static int put_rtax(struct nlattr *mx, int len, int type, u32 value) -{ - struct nlattr *nla; - - nla = (struct nlattr *) ((char *) mx + len); - nla->nla_type = type; - nla->nla_len = nla_attr_size(4); - *(u32 *) nla_data(nla) = value; - - return len + nla_total_size(4); -} - -static int rtentry_to_fib_config(struct net *net, int cmd, struct rtentry *rt, - struct fib_config *cfg) -{ - __be32 addr; - int plen; - - memset(cfg, 0, sizeof(*cfg)); - cfg->fc_nlinfo.nl_net = net; - - if (rt->rt_dst.sa_family != AF_INET) - return -EAFNOSUPPORT; - - /* - * Check mask for validity: - * a) it must be contiguous. - * b) destination must have all host bits clear. - * c) if application forgot to set correct family (AF_INET), - * reject request unless it is absolutely clear i.e. - * both family and mask are zero. - */ - plen = 32; - addr = sk_extract_addr(&rt->rt_dst); - if (!(rt->rt_flags & RTF_HOST)) { - __be32 mask = sk_extract_addr(&rt->rt_genmask); - - if (rt->rt_genmask.sa_family != AF_INET) { - if (mask || rt->rt_genmask.sa_family) - return -EAFNOSUPPORT; - } - - if (bad_mask(mask, addr)) - return -EINVAL; - - plen = inet_mask_len(mask); - } - - cfg->fc_dst_len = plen; - cfg->fc_dst = addr; - - if (cmd != SIOCDELRT) { - cfg->fc_nlflags = NLM_F_CREATE; - cfg->fc_protocol = RTPROT_BOOT; - } - - if (rt->rt_metric) - cfg->fc_priority = rt->rt_metric - 1; - - if (rt->rt_flags & RTF_REJECT) { - cfg->fc_scope = RT_SCOPE_HOST; - cfg->fc_type = RTN_UNREACHABLE; - return 0; - } - - cfg->fc_scope = RT_SCOPE_NOWHERE; - cfg->fc_type = RTN_UNICAST; - - if (rt->rt_dev) { - char *colon; - struct net_device *dev; - char devname[IFNAMSIZ]; - - if (copy_from_user(devname, rt->rt_dev, IFNAMSIZ-1)) - return -EFAULT; - - devname[IFNAMSIZ-1] = 0; - colon = strchr(devname, ':'); - if (colon) - *colon = 0; - dev = __dev_get_by_name(net, devname); - if (!dev) - return -ENODEV; - cfg->fc_oif = dev->ifindex; - cfg->fc_table = l3mdev_fib_table(dev); - if (colon) { - struct in_ifaddr *ifa; - struct in_device *in_dev = __in_dev_get_rtnl(dev); - if (!in_dev) - return -ENODEV; - *colon = ':'; - for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) - if (strcmp(ifa->ifa_label, devname) == 0) - break; - if (!ifa) - return -ENODEV; - cfg->fc_prefsrc = ifa->ifa_local; - } - } - - addr = sk_extract_addr(&rt->rt_gateway); - if (rt->rt_gateway.sa_family == AF_INET && addr) { - unsigned int addr_type; - - cfg->fc_gw = addr; - addr_type = inet_addr_type_table(net, addr, cfg->fc_table); - if (rt->rt_flags & RTF_GATEWAY && - addr_type == RTN_UNICAST) - cfg->fc_scope = RT_SCOPE_UNIVERSE; - } - - if (cmd == SIOCDELRT) - return 0; - - if (rt->rt_flags & RTF_GATEWAY && !cfg->fc_gw) - return -EINVAL; - - if (cfg->fc_scope == RT_SCOPE_NOWHERE) - cfg->fc_scope = RT_SCOPE_LINK; - - if (rt->rt_flags & (RTF_MTU | RTF_WINDOW | RTF_IRTT)) { - struct nlattr *mx; - int len = 0; - - mx = kzalloc(3 * nla_total_size(4), GFP_KERNEL); - if (!mx) - return -ENOMEM; - - if (rt->rt_flags & RTF_MTU) - len = put_rtax(mx, len, RTAX_ADVMSS, rt->rt_mtu - 40); - - if (rt->rt_flags & RTF_WINDOW) - len = put_rtax(mx, len, RTAX_WINDOW, rt->rt_window); - - if (rt->rt_flags & RTF_IRTT) - len = put_rtax(mx, len, RTAX_RTT, rt->rt_irtt << 3); - - cfg->fc_mx = mx; - cfg->fc_mx_len = len; - } - - return 0; -} - -/* - * Handle IP routing ioctl calls. - * These are used to manipulate the routing tables - */ -int ip_rt_ioctl(struct net *net, unsigned int cmd, void __user *arg) -{ - struct fib_config cfg; - struct rtentry rt; - int err; - - switch (cmd) { - case SIOCADDRT: /* Add a route */ - case SIOCDELRT: /* Delete a route */ - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - return -EPERM; - - if (copy_from_user(&rt, arg, sizeof(rt))) - return -EFAULT; - - rtnl_lock(); - err = rtentry_to_fib_config(net, cmd, &rt, &cfg); - if (err == 0) { - struct fib_table *tb; - - if (cmd == SIOCDELRT) { - tb = fib_get_table(net, cfg.fc_table); - if (tb) - err = fib_table_delete(net, tb, &cfg); - else - err = -ESRCH; - } else { - tb = fib_new_table(net, cfg.fc_table); - if (tb) - err = fib_table_insert(net, tb, &cfg); - else - err = -ENOBUFS; - } - - /* allocated by rtentry_to_fib_config() */ - kfree(cfg.fc_mx); - } - rtnl_unlock(); - return err; - } - return -EINVAL; -} - -const struct nla_policy rtm_ipv4_policy[RTA_MAX + 1] = { - [RTA_DST] = { .type = NLA_U32 }, - [RTA_SRC] = { .type = NLA_U32 }, - [RTA_IIF] = { .type = NLA_U32 }, - [RTA_OIF] = { .type = NLA_U32 }, - [RTA_GATEWAY] = { .type = NLA_U32 }, - [RTA_PRIORITY] = { .type = NLA_U32 }, - [RTA_PREFSRC] = { .type = NLA_U32 }, - [RTA_METRICS] = { .type = NLA_NESTED }, - [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) }, - [RTA_FLOW] = { .type = NLA_U32 }, - [RTA_ENCAP_TYPE] = { .type = NLA_U16 }, - [RTA_ENCAP] = { .type = NLA_NESTED }, -}; - -static int rtm_to_fib_config(struct net *net, struct sk_buff *skb, - struct nlmsghdr *nlh, struct fib_config *cfg) -{ - struct nlattr *attr; - int err, remaining; - struct rtmsg *rtm; - - err = nlmsg_validate(nlh, sizeof(*rtm), RTA_MAX, rtm_ipv4_policy); - if (err < 0) - goto errout; - - memset(cfg, 0, sizeof(*cfg)); - - rtm = nlmsg_data(nlh); - cfg->fc_dst_len = rtm->rtm_dst_len; - cfg->fc_tos = rtm->rtm_tos; - cfg->fc_table = rtm->rtm_table; - cfg->fc_protocol = rtm->rtm_protocol; - cfg->fc_scope = rtm->rtm_scope; - cfg->fc_type = rtm->rtm_type; - cfg->fc_flags = rtm->rtm_flags; - cfg->fc_nlflags = nlh->nlmsg_flags; - - cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid; - cfg->fc_nlinfo.nlh = nlh; - cfg->fc_nlinfo.nl_net = net; - - if (cfg->fc_type > RTN_MAX) { - err = -EINVAL; - goto errout; - } - - nlmsg_for_each_attr(attr, nlh, sizeof(struct rtmsg), remaining) { - switch (nla_type(attr)) { - case RTA_DST: - cfg->fc_dst = nla_get_be32(attr); - break; - case RTA_OIF: - cfg->fc_oif = nla_get_u32(attr); - break; - case RTA_GATEWAY: - cfg->fc_gw = nla_get_be32(attr); - break; - case RTA_PRIORITY: - cfg->fc_priority = nla_get_u32(attr); - break; - case RTA_PREFSRC: - cfg->fc_prefsrc = nla_get_be32(attr); - break; - case RTA_METRICS: - cfg->fc_mx = nla_data(attr); - cfg->fc_mx_len = nla_len(attr); - break; - case RTA_MULTIPATH: - cfg->fc_mp = nla_data(attr); - cfg->fc_mp_len = nla_len(attr); - break; - case RTA_FLOW: - cfg->fc_flow = nla_get_u32(attr); - break; - case RTA_TABLE: - cfg->fc_table = nla_get_u32(attr); - break; - case RTA_ENCAP: - cfg->fc_encap = attr; - break; - case RTA_ENCAP_TYPE: - cfg->fc_encap_type = nla_get_u16(attr); - break; - } - } - - return 0; -errout: - return err; -} - -static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct fib_config cfg; - struct fib_table *tb; - int err; - - err = rtm_to_fib_config(net, skb, nlh, &cfg); - if (err < 0) - goto errout; - - tb = fib_get_table(net, cfg.fc_table); - if (!tb) { - err = -ESRCH; - goto errout; - } - - err = fib_table_delete(net, tb, &cfg); -errout: - return err; -} - -static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct fib_config cfg; - struct fib_table *tb; - int err; - - err = rtm_to_fib_config(net, skb, nlh, &cfg); - if (err < 0) - goto errout; - - tb = fib_new_table(net, cfg.fc_table); - if (!tb) { - err = -ENOBUFS; - goto errout; - } - - err = fib_table_insert(net, tb, &cfg); -errout: - return err; -} - -static int inet_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) -{ - struct net *net = sock_net(skb->sk); - unsigned int h, s_h; - unsigned int e = 0, s_e; - struct fib_table *tb; - struct hlist_head *head; - int dumped = 0; - - if (nlmsg_len(cb->nlh) >= sizeof(struct rtmsg) && - ((struct rtmsg *) nlmsg_data(cb->nlh))->rtm_flags & RTM_F_CLONED) - return skb->len; - - s_h = cb->args[0]; - s_e = cb->args[1]; - - rcu_read_lock(); - - for (h = s_h; h < FIB_TABLE_HASHSZ; h++, s_e = 0) { - e = 0; - head = &net->ipv4.fib_table_hash[h]; - hlist_for_each_entry_rcu(tb, head, tb_hlist) { - if (e < s_e) - goto next; - if (dumped) - memset(&cb->args[2], 0, sizeof(cb->args) - - 2 * sizeof(cb->args[0])); - if (fib_table_dump(tb, skb, cb) < 0) - goto out; - dumped = 1; -next: - e++; - } - } -out: - rcu_read_unlock(); - - cb->args[1] = e; - cb->args[0] = h; - - return skb->len; -} - -/* Prepare and feed intra-kernel routing request. - * Really, it should be netlink message, but :-( netlink - * can be not configured, so that we feed it directly - * to fib engine. It is legal, because all events occur - * only when netlink is already locked. - */ -static void fib_magic(int cmd, int type, __be32 dst, int dst_len, struct in_ifaddr *ifa) -{ - struct net *net = dev_net(ifa->ifa_dev->dev); - u32 tb_id = l3mdev_fib_table(ifa->ifa_dev->dev); - struct fib_table *tb; - struct fib_config cfg = { - .fc_protocol = RTPROT_KERNEL, - .fc_type = type, - .fc_dst = dst, - .fc_dst_len = dst_len, - .fc_prefsrc = ifa->ifa_local, - .fc_oif = ifa->ifa_dev->dev->ifindex, - .fc_nlflags = NLM_F_CREATE | NLM_F_APPEND, - .fc_nlinfo = { - .nl_net = net, - }, - }; - - if (!tb_id) - tb_id = (type == RTN_UNICAST) ? RT_TABLE_MAIN : RT_TABLE_LOCAL; - - tb = fib_new_table(net, tb_id); - if (!tb) - return; - - cfg.fc_table = tb->tb_id; - - if (type != RTN_LOCAL) - cfg.fc_scope = RT_SCOPE_LINK; - else - cfg.fc_scope = RT_SCOPE_HOST; - - if (cmd == RTM_NEWROUTE) - fib_table_insert(net, tb, &cfg); - else - fib_table_delete(net, tb, &cfg); -} - -void fib_add_ifaddr(struct in_ifaddr *ifa) -{ - struct in_device *in_dev = ifa->ifa_dev; - struct net_device *dev = in_dev->dev; - struct in_ifaddr *prim = ifa; - __be32 mask = ifa->ifa_mask; - __be32 addr = ifa->ifa_local; - __be32 prefix = ifa->ifa_address & mask; - - if (ifa->ifa_flags & IFA_F_SECONDARY) { - prim = inet_ifa_byprefix(in_dev, prefix, mask); - if (!prim) { - pr_warn("%s: bug: prim == NULL\n", __func__); - return; - } - } - - fib_magic(RTM_NEWROUTE, RTN_LOCAL, addr, 32, prim); - - if (!(dev->flags & IFF_UP)) - return; - - /* Add broadcast address, if it is explicitly assigned. */ - if (ifa->ifa_broadcast && ifa->ifa_broadcast != htonl(0xFFFFFFFF)) - fib_magic(RTM_NEWROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); - - if (!ipv4_is_zeronet(prefix) && !(ifa->ifa_flags & IFA_F_SECONDARY) && - (prefix != addr || ifa->ifa_prefixlen < 32)) { - if (!(ifa->ifa_flags & IFA_F_NOPREFIXROUTE)) - fib_magic(RTM_NEWROUTE, - dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST, - prefix, ifa->ifa_prefixlen, prim); - - /* Add network specific broadcasts, when it takes a sense */ - if (ifa->ifa_prefixlen < 31) { - fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix, 32, prim); - fib_magic(RTM_NEWROUTE, RTN_BROADCAST, prefix | ~mask, - 32, prim); - } - } -} - -/* Delete primary or secondary address. - * Optionally, on secondary address promotion consider the addresses - * from subnet iprim as deleted, even if they are in device list. - * In this case the secondary ifa can be in device list. - */ -void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim) -{ - struct in_device *in_dev = ifa->ifa_dev; - struct net_device *dev = in_dev->dev; - struct in_ifaddr *ifa1; - struct in_ifaddr *prim = ifa, *prim1 = NULL; - __be32 brd = ifa->ifa_address | ~ifa->ifa_mask; - __be32 any = ifa->ifa_address & ifa->ifa_mask; -#define LOCAL_OK 1 -#define BRD_OK 2 -#define BRD0_OK 4 -#define BRD1_OK 8 - unsigned int ok = 0; - int subnet = 0; /* Primary network */ - int gone = 1; /* Address is missing */ - int same_prefsrc = 0; /* Another primary with same IP */ - - if (ifa->ifa_flags & IFA_F_SECONDARY) { - prim = inet_ifa_byprefix(in_dev, any, ifa->ifa_mask); - if (!prim) { - /* if the device has been deleted, we don't perform - * address promotion - */ - if (!in_dev->dead) - pr_warn("%s: bug: prim == NULL\n", __func__); - return; - } - if (iprim && iprim != prim) { - pr_warn("%s: bug: iprim != prim\n", __func__); - return; - } - } else if (!ipv4_is_zeronet(any) && - (any != ifa->ifa_local || ifa->ifa_prefixlen < 32)) { - if (!(ifa->ifa_flags & IFA_F_NOPREFIXROUTE)) - fib_magic(RTM_DELROUTE, - dev->flags & IFF_LOOPBACK ? RTN_LOCAL : RTN_UNICAST, - any, ifa->ifa_prefixlen, prim); - subnet = 1; - } - - if (in_dev->dead) - goto no_promotions; - - /* Deletion is more complicated than add. - * We should take care of not to delete too much :-) - * - * Scan address list to be sure that addresses are really gone. - */ - - for (ifa1 = in_dev->ifa_list; ifa1; ifa1 = ifa1->ifa_next) { - if (ifa1 == ifa) { - /* promotion, keep the IP */ - gone = 0; - continue; - } - /* Ignore IFAs from our subnet */ - if (iprim && ifa1->ifa_mask == iprim->ifa_mask && - inet_ifa_match(ifa1->ifa_address, iprim)) - continue; - - /* Ignore ifa1 if it uses different primary IP (prefsrc) */ - if (ifa1->ifa_flags & IFA_F_SECONDARY) { - /* Another address from our subnet? */ - if (ifa1->ifa_mask == prim->ifa_mask && - inet_ifa_match(ifa1->ifa_address, prim)) - prim1 = prim; - else { - /* We reached the secondaries, so - * same_prefsrc should be determined. - */ - if (!same_prefsrc) - continue; - /* Search new prim1 if ifa1 is not - * using the current prim1 - */ - if (!prim1 || - ifa1->ifa_mask != prim1->ifa_mask || - !inet_ifa_match(ifa1->ifa_address, prim1)) - prim1 = inet_ifa_byprefix(in_dev, - ifa1->ifa_address, - ifa1->ifa_mask); - if (!prim1) - continue; - if (prim1->ifa_local != prim->ifa_local) - continue; - } - } else { - if (prim->ifa_local != ifa1->ifa_local) - continue; - prim1 = ifa1; - if (prim != prim1) - same_prefsrc = 1; - } - if (ifa->ifa_local == ifa1->ifa_local) - ok |= LOCAL_OK; - if (ifa->ifa_broadcast == ifa1->ifa_broadcast) - ok |= BRD_OK; - if (brd == ifa1->ifa_broadcast) - ok |= BRD1_OK; - if (any == ifa1->ifa_broadcast) - ok |= BRD0_OK; - /* primary has network specific broadcasts */ - if (prim1 == ifa1 && ifa1->ifa_prefixlen < 31) { - __be32 brd1 = ifa1->ifa_address | ~ifa1->ifa_mask; - __be32 any1 = ifa1->ifa_address & ifa1->ifa_mask; - - if (!ipv4_is_zeronet(any1)) { - if (ifa->ifa_broadcast == brd1 || - ifa->ifa_broadcast == any1) - ok |= BRD_OK; - if (brd == brd1 || brd == any1) - ok |= BRD1_OK; - if (any == brd1 || any == any1) - ok |= BRD0_OK; - } - } - } - -no_promotions: - if (!(ok & BRD_OK)) - fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); - if (subnet && ifa->ifa_prefixlen < 31) { - if (!(ok & BRD1_OK)) - fib_magic(RTM_DELROUTE, RTN_BROADCAST, brd, 32, prim); - if (!(ok & BRD0_OK)) - fib_magic(RTM_DELROUTE, RTN_BROADCAST, any, 32, prim); - } - if (!(ok & LOCAL_OK)) { - unsigned int addr_type; - - fib_magic(RTM_DELROUTE, RTN_LOCAL, ifa->ifa_local, 32, prim); - - /* Check, that this local address finally disappeared. */ - addr_type = inet_addr_type_dev_table(dev_net(dev), dev, - ifa->ifa_local); - if (gone && addr_type != RTN_LOCAL) { - /* And the last, but not the least thing. - * We must flush stray FIB entries. - * - * First of all, we scan fib_info list searching - * for stray nexthop entries, then ignite fib_flush. - */ - if (fib_sync_down_addr(dev, ifa->ifa_local)) - fib_flush(dev_net(dev)); - } - } -#undef LOCAL_OK -#undef BRD_OK -#undef BRD0_OK -#undef BRD1_OK -} - -static void nl_fib_lookup(struct net *net, struct fib_result_nl *frn) -{ - - struct fib_result res; - struct flowi4 fl4 = { - .flowi4_mark = frn->fl_mark, - .daddr = frn->fl_addr, - .flowi4_tos = frn->fl_tos, - .flowi4_scope = frn->fl_scope, - }; - struct fib_table *tb; - - rcu_read_lock(); - - tb = fib_get_table(net, frn->tb_id_in); - - frn->err = -ENOENT; - if (tb) { - local_bh_disable(); - - frn->tb_id = tb->tb_id; - frn->err = fib_table_lookup(tb, &fl4, &res, FIB_LOOKUP_NOREF); - - if (!frn->err) { - frn->prefixlen = res.prefixlen; - frn->nh_sel = res.nh_sel; - frn->type = res.type; - frn->scope = res.scope; - } - local_bh_enable(); - } - - rcu_read_unlock(); -} - -static void nl_fib_input(struct sk_buff *skb) -{ - struct net *net; - struct fib_result_nl *frn; - struct nlmsghdr *nlh; - u32 portid; - - net = sock_net(skb->sk); - nlh = nlmsg_hdr(skb); - if (skb->len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len || - nlmsg_len(nlh) < sizeof(*frn)) - return; - - skb = netlink_skb_clone(skb, GFP_KERNEL); - if (!skb) - return; - nlh = nlmsg_hdr(skb); - - frn = (struct fib_result_nl *) nlmsg_data(nlh); - nl_fib_lookup(net, frn); - - portid = NETLINK_CB(skb).portid; /* netlink portid */ - NETLINK_CB(skb).portid = 0; /* from kernel */ - NETLINK_CB(skb).dst_group = 0; /* unicast */ - netlink_unicast(net->ipv4.fibnl, skb, portid, MSG_DONTWAIT); -} - -static int __net_init nl_fib_lookup_init(struct net *net) -{ - struct sock *sk; - struct netlink_kernel_cfg cfg = { - .input = nl_fib_input, - }; - - sk = netlink_kernel_create(net, NETLINK_FIB_LOOKUP, &cfg); - if (!sk) - return -EAFNOSUPPORT; - net->ipv4.fibnl = sk; - return 0; -} - -static void nl_fib_lookup_exit(struct net *net) -{ - netlink_kernel_release(net->ipv4.fibnl); - net->ipv4.fibnl = NULL; -} - -static void fib_disable_ip(struct net_device *dev, unsigned long event, - bool force) -{ - if (fib_sync_down_dev(dev, event, force)) - fib_flush(dev_net(dev)); - rt_cache_flush(dev_net(dev)); - arp_ifdown(dev); -} - -static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; - struct net_device *dev = ifa->ifa_dev->dev; - struct net *net = dev_net(dev); - - switch (event) { - case NETDEV_UP: - fib_add_ifaddr(ifa); -#ifdef CONFIG_IP_ROUTE_MULTIPATH - fib_sync_up(dev, RTNH_F_DEAD); -#endif - atomic_inc(&net->ipv4.dev_addr_genid); - rt_cache_flush(dev_net(dev)); - break; - case NETDEV_DOWN: - fib_del_ifaddr(ifa, NULL); - atomic_inc(&net->ipv4.dev_addr_genid); - if (!ifa->ifa_dev->ifa_list) { - /* Last address was deleted from this interface. - * Disable IP. - */ - fib_disable_ip(dev, event, true); - } else { - rt_cache_flush(dev_net(dev)); - } - break; - } - return NOTIFY_DONE; -} - -static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct netdev_notifier_changeupper_info *info; - struct in_device *in_dev; - struct net *net = dev_net(dev); - unsigned int flags; - - if (event == NETDEV_UNREGISTER) { - fib_disable_ip(dev, event, true); - rt_flush_dev(dev); - return NOTIFY_DONE; - } - - in_dev = __in_dev_get_rtnl(dev); - if (!in_dev) - return NOTIFY_DONE; - - switch (event) { - case NETDEV_UP: - for_ifa(in_dev) { - fib_add_ifaddr(ifa); - } endfor_ifa(in_dev); -#ifdef CONFIG_IP_ROUTE_MULTIPATH - fib_sync_up(dev, RTNH_F_DEAD); -#endif - atomic_inc(&net->ipv4.dev_addr_genid); - rt_cache_flush(net); - break; - case NETDEV_DOWN: - fib_disable_ip(dev, event, false); - break; - case NETDEV_CHANGE: - flags = dev_get_flags(dev); - if (flags & (IFF_RUNNING | IFF_LOWER_UP)) - fib_sync_up(dev, RTNH_F_LINKDOWN); - else - fib_sync_down_dev(dev, event, false); - /* fall through */ - case NETDEV_CHANGEMTU: - rt_cache_flush(net); - break; - case NETDEV_CHANGEUPPER: - info = ptr; - /* flush all routes if dev is linked to or unlinked from - * an L3 master device (e.g., VRF) - */ - if (info->upper_dev && netif_is_l3_master(info->upper_dev)) - fib_disable_ip(dev, NETDEV_DOWN, true); - break; - } - return NOTIFY_DONE; -} - -static struct notifier_block fib_inetaddr_notifier = { - .notifier_call = fib_inetaddr_event, -}; - -static struct notifier_block fib_netdev_notifier = { - .notifier_call = fib_netdev_event, -}; - -static int __net_init ip_fib_net_init(struct net *net) -{ - int err; - size_t size = sizeof(struct hlist_head) * FIB_TABLE_HASHSZ; - - /* Avoid false sharing : Use at least a full cache line */ - size = max_t(size_t, size, L1_CACHE_BYTES); - - net->ipv4.fib_table_hash = kzalloc(size, GFP_KERNEL); - if (!net->ipv4.fib_table_hash) - return -ENOMEM; - - err = fib4_rules_init(net); - if (err < 0) - goto fail; - return 0; - -fail: - kfree(net->ipv4.fib_table_hash); - return err; -} - -static void ip_fib_net_exit(struct net *net) -{ - unsigned int i; - - rtnl_lock(); -#ifdef CONFIG_IP_MULTIPLE_TABLES - RCU_INIT_POINTER(net->ipv4.fib_main, NULL); - RCU_INIT_POINTER(net->ipv4.fib_default, NULL); -#endif - for (i = 0; i < FIB_TABLE_HASHSZ; i++) { - struct hlist_head *head = &net->ipv4.fib_table_hash[i]; - struct hlist_node *tmp; - struct fib_table *tb; - - hlist_for_each_entry_safe(tb, tmp, head, tb_hlist) { - hlist_del(&tb->tb_hlist); - fib_table_flush(net, tb); - fib_free_table(tb); - } - } - -#ifdef CONFIG_IP_MULTIPLE_TABLES - fib4_rules_exit(net); -#endif - rtnl_unlock(); - kfree(net->ipv4.fib_table_hash); -} - -static int __net_init fib_net_init(struct net *net) -{ - int error; - -#ifdef CONFIG_IP_ROUTE_CLASSID - net->ipv4.fib_num_tclassid_users = 0; -#endif - error = ip_fib_net_init(net); - if (error < 0) - goto out; - error = nl_fib_lookup_init(net); - if (error < 0) - goto out_nlfl; - error = fib_proc_init(net); - if (error < 0) - goto out_proc; -out: - return error; - -out_proc: - nl_fib_lookup_exit(net); -out_nlfl: - ip_fib_net_exit(net); - goto out; -} - -static void __net_exit fib_net_exit(struct net *net) -{ - fib_proc_exit(net); - nl_fib_lookup_exit(net); - ip_fib_net_exit(net); -} - -static struct pernet_operations fib_net_ops = { - .init = fib_net_init, - .exit = fib_net_exit, -}; - -void __init ip_fib_init(void) -{ - rtnl_register(PF_INET, RTM_NEWROUTE, inet_rtm_newroute, NULL, NULL); - rtnl_register(PF_INET, RTM_DELROUTE, inet_rtm_delroute, NULL, NULL); - rtnl_register(PF_INET, RTM_GETROUTE, NULL, inet_dump_fib, NULL); - - register_pernet_subsys(&fib_net_ops); - register_netdevice_notifier(&fib_netdev_notifier); - register_inetaddr_notifier(&fib_inetaddr_notifier); - - fib_trie_init(); -} diff --git a/src/linux/net/ipv4/fib_lookup.h b/src/linux/net/ipv4/fib_lookup.h deleted file mode 100644 index 9c02920..0000000 --- a/src/linux/net/ipv4/fib_lookup.h +++ /dev/null @@ -1,53 +0,0 @@ -#ifndef _FIB_LOOKUP_H -#define _FIB_LOOKUP_H - -#include -#include -#include - -struct fib_alias { - struct hlist_node fa_list; - struct fib_info *fa_info; - u8 fa_tos; - u8 fa_type; - u8 fa_state; - u8 fa_slen; - u32 tb_id; - s16 fa_default; - struct rcu_head rcu; -}; - -#define FA_S_ACCESSED 0x01 - -/* Dont write on fa_state unless needed, to keep it shared on all cpus */ -static inline void fib_alias_accessed(struct fib_alias *fa) -{ - if (!(fa->fa_state & FA_S_ACCESSED)) - fa->fa_state |= FA_S_ACCESSED; -} - -/* Exported by fib_semantics.c */ -void fib_release_info(struct fib_info *); -struct fib_info *fib_create_info(struct fib_config *cfg); -int fib_nh_match(struct fib_config *cfg, struct fib_info *fi); -int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, u32 tb_id, - u8 type, __be32 dst, int dst_len, u8 tos, struct fib_info *fi, - unsigned int); -void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, int dst_len, - u32 tb_id, const struct nl_info *info, unsigned int nlm_flags); - -static inline void fib_result_assign(struct fib_result *res, - struct fib_info *fi) -{ - /* we used to play games with refcounts, but we now use RCU */ - res->fi = fi; -} - -struct fib_prop { - int error; - u8 scope; -}; - -extern const struct fib_prop fib_props[RTN_MAX + 1]; - -#endif /* _FIB_LOOKUP_H */ diff --git a/src/linux/net/ipv4/fib_semantics.c b/src/linux/net/ipv4/fib_semantics.c deleted file mode 100644 index 388d3e2..0000000 --- a/src/linux/net/ipv4/fib_semantics.c +++ /dev/null @@ -1,1637 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * IPv4 Forwarding Information Base: semantics. - * - * Authors: Alexey Kuznetsov, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#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 -#include - -#include "fib_lookup.h" - -static DEFINE_SPINLOCK(fib_info_lock); -static struct hlist_head *fib_info_hash; -static struct hlist_head *fib_info_laddrhash; -static unsigned int fib_info_hash_size; -static unsigned int fib_info_cnt; - -#define DEVINDEX_HASHBITS 8 -#define DEVINDEX_HASHSIZE (1U << DEVINDEX_HASHBITS) -static struct hlist_head fib_info_devhash[DEVINDEX_HASHSIZE]; - -#ifdef CONFIG_IP_ROUTE_MULTIPATH -u32 fib_multipath_secret __read_mostly; - -#define for_nexthops(fi) { \ - int nhsel; const struct fib_nh *nh; \ - for (nhsel = 0, nh = (fi)->fib_nh; \ - nhsel < (fi)->fib_nhs; \ - nh++, nhsel++) - -#define change_nexthops(fi) { \ - int nhsel; struct fib_nh *nexthop_nh; \ - for (nhsel = 0, nexthop_nh = (struct fib_nh *)((fi)->fib_nh); \ - nhsel < (fi)->fib_nhs; \ - nexthop_nh++, nhsel++) - -#else /* CONFIG_IP_ROUTE_MULTIPATH */ - -/* Hope, that gcc will optimize it to get rid of dummy loop */ - -#define for_nexthops(fi) { \ - int nhsel; const struct fib_nh *nh = (fi)->fib_nh; \ - for (nhsel = 0; nhsel < 1; nhsel++) - -#define change_nexthops(fi) { \ - int nhsel; \ - struct fib_nh *nexthop_nh = (struct fib_nh *)((fi)->fib_nh); \ - for (nhsel = 0; nhsel < 1; nhsel++) - -#endif /* CONFIG_IP_ROUTE_MULTIPATH */ - -#define endfor_nexthops(fi) } - - -const struct fib_prop fib_props[RTN_MAX + 1] = { - [RTN_UNSPEC] = { - .error = 0, - .scope = RT_SCOPE_NOWHERE, - }, - [RTN_UNICAST] = { - .error = 0, - .scope = RT_SCOPE_UNIVERSE, - }, - [RTN_LOCAL] = { - .error = 0, - .scope = RT_SCOPE_HOST, - }, - [RTN_BROADCAST] = { - .error = 0, - .scope = RT_SCOPE_LINK, - }, - [RTN_ANYCAST] = { - .error = 0, - .scope = RT_SCOPE_LINK, - }, - [RTN_MULTICAST] = { - .error = 0, - .scope = RT_SCOPE_UNIVERSE, - }, - [RTN_BLACKHOLE] = { - .error = -EINVAL, - .scope = RT_SCOPE_UNIVERSE, - }, - [RTN_UNREACHABLE] = { - .error = -EHOSTUNREACH, - .scope = RT_SCOPE_UNIVERSE, - }, - [RTN_PROHIBIT] = { - .error = -EACCES, - .scope = RT_SCOPE_UNIVERSE, - }, - [RTN_THROW] = { - .error = -EAGAIN, - .scope = RT_SCOPE_UNIVERSE, - }, - [RTN_NAT] = { - .error = -EINVAL, - .scope = RT_SCOPE_NOWHERE, - }, - [RTN_XRESOLVE] = { - .error = -EINVAL, - .scope = RT_SCOPE_NOWHERE, - }, -}; - -static void rt_fibinfo_free(struct rtable __rcu **rtp) -{ - struct rtable *rt = rcu_dereference_protected(*rtp, 1); - - if (!rt) - return; - - /* Not even needed : RCU_INIT_POINTER(*rtp, NULL); - * because we waited an RCU grace period before calling - * free_fib_info_rcu() - */ - - dst_free(&rt->dst); -} - -static void free_nh_exceptions(struct fib_nh *nh) -{ - struct fnhe_hash_bucket *hash; - int i; - - hash = rcu_dereference_protected(nh->nh_exceptions, 1); - if (!hash) - return; - for (i = 0; i < FNHE_HASH_SIZE; i++) { - struct fib_nh_exception *fnhe; - - fnhe = rcu_dereference_protected(hash[i].chain, 1); - while (fnhe) { - struct fib_nh_exception *next; - - next = rcu_dereference_protected(fnhe->fnhe_next, 1); - - rt_fibinfo_free(&fnhe->fnhe_rth_input); - rt_fibinfo_free(&fnhe->fnhe_rth_output); - - kfree(fnhe); - - fnhe = next; - } - } - kfree(hash); -} - -static void rt_fibinfo_free_cpus(struct rtable __rcu * __percpu *rtp) -{ - int cpu; - - if (!rtp) - return; - - for_each_possible_cpu(cpu) { - struct rtable *rt; - - rt = rcu_dereference_protected(*per_cpu_ptr(rtp, cpu), 1); - if (rt) - dst_free(&rt->dst); - } - free_percpu(rtp); -} - -/* Release a nexthop info record */ -static void free_fib_info_rcu(struct rcu_head *head) -{ - struct fib_info *fi = container_of(head, struct fib_info, rcu); - - change_nexthops(fi) { - if (nexthop_nh->nh_dev) - dev_put(nexthop_nh->nh_dev); - lwtstate_put(nexthop_nh->nh_lwtstate); - free_nh_exceptions(nexthop_nh); - rt_fibinfo_free_cpus(nexthop_nh->nh_pcpu_rth_output); - rt_fibinfo_free(&nexthop_nh->nh_rth_input); - } endfor_nexthops(fi); - - if (fi->fib_metrics != (u32 *) dst_default_metrics) - kfree(fi->fib_metrics); - kfree(fi); -} - -void free_fib_info(struct fib_info *fi) -{ - if (fi->fib_dead == 0) { - pr_warn("Freeing alive fib_info %p\n", fi); - return; - } - fib_info_cnt--; -#ifdef CONFIG_IP_ROUTE_CLASSID - change_nexthops(fi) { - if (nexthop_nh->nh_tclassid) - fi->fib_net->ipv4.fib_num_tclassid_users--; - } endfor_nexthops(fi); -#endif - call_rcu(&fi->rcu, free_fib_info_rcu); -} - -void fib_release_info(struct fib_info *fi) -{ - spin_lock_bh(&fib_info_lock); - if (fi && --fi->fib_treeref == 0) { - hlist_del(&fi->fib_hash); - if (fi->fib_prefsrc) - hlist_del(&fi->fib_lhash); - change_nexthops(fi) { - if (!nexthop_nh->nh_dev) - continue; - hlist_del(&nexthop_nh->nh_hash); - } endfor_nexthops(fi) - fi->fib_dead = 1; - fib_info_put(fi); - } - spin_unlock_bh(&fib_info_lock); -} - -static inline int nh_comp(const struct fib_info *fi, const struct fib_info *ofi) -{ - const struct fib_nh *onh = ofi->fib_nh; - - for_nexthops(fi) { - if (nh->nh_oif != onh->nh_oif || - nh->nh_gw != onh->nh_gw || - nh->nh_scope != onh->nh_scope || -#ifdef CONFIG_IP_ROUTE_MULTIPATH - nh->nh_weight != onh->nh_weight || -#endif -#ifdef CONFIG_IP_ROUTE_CLASSID - nh->nh_tclassid != onh->nh_tclassid || -#endif - lwtunnel_cmp_encap(nh->nh_lwtstate, onh->nh_lwtstate) || - ((nh->nh_flags ^ onh->nh_flags) & ~RTNH_COMPARE_MASK)) - return -1; - onh++; - } endfor_nexthops(fi); - return 0; -} - -static inline unsigned int fib_devindex_hashfn(unsigned int val) -{ - unsigned int mask = DEVINDEX_HASHSIZE - 1; - - return (val ^ - (val >> DEVINDEX_HASHBITS) ^ - (val >> (DEVINDEX_HASHBITS * 2))) & mask; -} - -static inline unsigned int fib_info_hashfn(const struct fib_info *fi) -{ - unsigned int mask = (fib_info_hash_size - 1); - unsigned int val = fi->fib_nhs; - - val ^= (fi->fib_protocol << 8) | fi->fib_scope; - val ^= (__force u32)fi->fib_prefsrc; - val ^= fi->fib_priority; - for_nexthops(fi) { - val ^= fib_devindex_hashfn(nh->nh_oif); - } endfor_nexthops(fi) - - return (val ^ (val >> 7) ^ (val >> 12)) & mask; -} - -static struct fib_info *fib_find_info(const struct fib_info *nfi) -{ - struct hlist_head *head; - struct fib_info *fi; - unsigned int hash; - - hash = fib_info_hashfn(nfi); - head = &fib_info_hash[hash]; - - hlist_for_each_entry(fi, head, fib_hash) { - if (!net_eq(fi->fib_net, nfi->fib_net)) - continue; - if (fi->fib_nhs != nfi->fib_nhs) - continue; - if (nfi->fib_protocol == fi->fib_protocol && - nfi->fib_scope == fi->fib_scope && - nfi->fib_prefsrc == fi->fib_prefsrc && - nfi->fib_priority == fi->fib_priority && - nfi->fib_type == fi->fib_type && - memcmp(nfi->fib_metrics, fi->fib_metrics, - sizeof(u32) * RTAX_MAX) == 0 && - !((nfi->fib_flags ^ fi->fib_flags) & ~RTNH_COMPARE_MASK) && - (nfi->fib_nhs == 0 || nh_comp(fi, nfi) == 0)) - return fi; - } - - return NULL; -} - -/* Check, that the gateway is already configured. - * Used only by redirect accept routine. - */ -int ip_fib_check_default(__be32 gw, struct net_device *dev) -{ - struct hlist_head *head; - struct fib_nh *nh; - unsigned int hash; - - spin_lock(&fib_info_lock); - - hash = fib_devindex_hashfn(dev->ifindex); - head = &fib_info_devhash[hash]; - hlist_for_each_entry(nh, head, nh_hash) { - if (nh->nh_dev == dev && - nh->nh_gw == gw && - !(nh->nh_flags & RTNH_F_DEAD)) { - spin_unlock(&fib_info_lock); - return 0; - } - } - - spin_unlock(&fib_info_lock); - - return -1; -} - -static inline size_t fib_nlmsg_size(struct fib_info *fi) -{ - size_t payload = NLMSG_ALIGN(sizeof(struct rtmsg)) - + nla_total_size(4) /* RTA_TABLE */ - + nla_total_size(4) /* RTA_DST */ - + nla_total_size(4) /* RTA_PRIORITY */ - + nla_total_size(4) /* RTA_PREFSRC */ - + nla_total_size(TCP_CA_NAME_MAX); /* RTAX_CC_ALGO */ - - /* space for nested metrics */ - payload += nla_total_size((RTAX_MAX * nla_total_size(4))); - - if (fi->fib_nhs) { - size_t nh_encapsize = 0; - /* Also handles the special case fib_nhs == 1 */ - - /* each nexthop is packed in an attribute */ - size_t nhsize = nla_total_size(sizeof(struct rtnexthop)); - - /* may contain flow and gateway attribute */ - nhsize += 2 * nla_total_size(4); - - /* grab encap info */ - for_nexthops(fi) { - if (nh->nh_lwtstate) { - /* RTA_ENCAP_TYPE */ - nh_encapsize += lwtunnel_get_encap_size( - nh->nh_lwtstate); - /* RTA_ENCAP */ - nh_encapsize += nla_total_size(2); - } - } endfor_nexthops(fi); - - /* all nexthops are packed in a nested attribute */ - payload += nla_total_size((fi->fib_nhs * nhsize) + - nh_encapsize); - - } - - return payload; -} - -void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, - int dst_len, u32 tb_id, const struct nl_info *info, - unsigned int nlm_flags) -{ - struct sk_buff *skb; - u32 seq = info->nlh ? info->nlh->nlmsg_seq : 0; - int err = -ENOBUFS; - - skb = nlmsg_new(fib_nlmsg_size(fa->fa_info), GFP_KERNEL); - if (!skb) - goto errout; - - err = fib_dump_info(skb, info->portid, seq, event, tb_id, - fa->fa_type, key, dst_len, - fa->fa_tos, fa->fa_info, nlm_flags); - if (err < 0) { - /* -EMSGSIZE implies BUG in fib_nlmsg_size() */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - goto errout; - } - rtnl_notify(skb, info->nl_net, info->portid, RTNLGRP_IPV4_ROUTE, - info->nlh, GFP_KERNEL); - return; -errout: - if (err < 0) - rtnl_set_sk_err(info->nl_net, RTNLGRP_IPV4_ROUTE, err); -} - -static int fib_detect_death(struct fib_info *fi, int order, - struct fib_info **last_resort, int *last_idx, - int dflt) -{ - struct neighbour *n; - int state = NUD_NONE; - - n = neigh_lookup(&arp_tbl, &fi->fib_nh[0].nh_gw, fi->fib_dev); - if (n) { - state = n->nud_state; - neigh_release(n); - } else { - return 0; - } - if (state == NUD_REACHABLE) - return 0; - if ((state & NUD_VALID) && order != dflt) - return 0; - if ((state & NUD_VALID) || - (*last_idx < 0 && order > dflt && state != NUD_INCOMPLETE)) { - *last_resort = fi; - *last_idx = order; - } - return 1; -} - -#ifdef CONFIG_IP_ROUTE_MULTIPATH - -static int fib_count_nexthops(struct rtnexthop *rtnh, int remaining) -{ - int nhs = 0; - - while (rtnh_ok(rtnh, remaining)) { - nhs++; - rtnh = rtnh_next(rtnh, &remaining); - } - - /* leftover implies invalid nexthop configuration, discard it */ - return remaining > 0 ? 0 : nhs; -} - -static int fib_get_nhs(struct fib_info *fi, struct rtnexthop *rtnh, - int remaining, struct fib_config *cfg) -{ - struct net *net = cfg->fc_nlinfo.nl_net; - int ret; - - change_nexthops(fi) { - int attrlen; - - if (!rtnh_ok(rtnh, remaining)) - return -EINVAL; - - if (rtnh->rtnh_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN)) - return -EINVAL; - - nexthop_nh->nh_flags = - (cfg->fc_flags & ~0xFF) | rtnh->rtnh_flags; - nexthop_nh->nh_oif = rtnh->rtnh_ifindex; - nexthop_nh->nh_weight = rtnh->rtnh_hops + 1; - - attrlen = rtnh_attrlen(rtnh); - if (attrlen > 0) { - struct nlattr *nla, *attrs = rtnh_attrs(rtnh); - - nla = nla_find(attrs, attrlen, RTA_GATEWAY); - nexthop_nh->nh_gw = nla ? nla_get_in_addr(nla) : 0; -#ifdef CONFIG_IP_ROUTE_CLASSID - nla = nla_find(attrs, attrlen, RTA_FLOW); - nexthop_nh->nh_tclassid = nla ? nla_get_u32(nla) : 0; - if (nexthop_nh->nh_tclassid) - fi->fib_net->ipv4.fib_num_tclassid_users++; -#endif - nla = nla_find(attrs, attrlen, RTA_ENCAP); - if (nla) { - struct lwtunnel_state *lwtstate; - struct net_device *dev = NULL; - struct nlattr *nla_entype; - - nla_entype = nla_find(attrs, attrlen, - RTA_ENCAP_TYPE); - if (!nla_entype) - goto err_inval; - if (cfg->fc_oif) - dev = __dev_get_by_index(net, cfg->fc_oif); - ret = lwtunnel_build_state(dev, nla_get_u16( - nla_entype), - nla, AF_INET, cfg, - &lwtstate); - if (ret) - goto errout; - nexthop_nh->nh_lwtstate = - lwtstate_get(lwtstate); - } - } - - rtnh = rtnh_next(rtnh, &remaining); - } endfor_nexthops(fi); - - return 0; - -err_inval: - ret = -EINVAL; - -errout: - return ret; -} - -static void fib_rebalance(struct fib_info *fi) -{ - int total; - int w; - struct in_device *in_dev; - - if (fi->fib_nhs < 2) - return; - - total = 0; - for_nexthops(fi) { - if (nh->nh_flags & RTNH_F_DEAD) - continue; - - in_dev = __in_dev_get_rtnl(nh->nh_dev); - - if (in_dev && - IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) && - nh->nh_flags & RTNH_F_LINKDOWN) - continue; - - total += nh->nh_weight; - } endfor_nexthops(fi); - - w = 0; - change_nexthops(fi) { - int upper_bound; - - in_dev = __in_dev_get_rtnl(nexthop_nh->nh_dev); - - if (nexthop_nh->nh_flags & RTNH_F_DEAD) { - upper_bound = -1; - } else if (in_dev && - IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) && - nexthop_nh->nh_flags & RTNH_F_LINKDOWN) { - upper_bound = -1; - } else { - w += nexthop_nh->nh_weight; - upper_bound = DIV_ROUND_CLOSEST_ULL((u64)w << 31, - total) - 1; - } - - atomic_set(&nexthop_nh->nh_upper_bound, upper_bound); - } endfor_nexthops(fi); - - net_get_random_once(&fib_multipath_secret, - sizeof(fib_multipath_secret)); -} - -static inline void fib_add_weight(struct fib_info *fi, - const struct fib_nh *nh) -{ - fi->fib_weight += nh->nh_weight; -} - -#else /* CONFIG_IP_ROUTE_MULTIPATH */ - -#define fib_rebalance(fi) do { } while (0) -#define fib_add_weight(fi, nh) do { } while (0) - -#endif /* CONFIG_IP_ROUTE_MULTIPATH */ - -static int fib_encap_match(struct net *net, u16 encap_type, - struct nlattr *encap, - int oif, const struct fib_nh *nh, - const struct fib_config *cfg) -{ - struct lwtunnel_state *lwtstate; - struct net_device *dev = NULL; - int ret, result = 0; - - if (encap_type == LWTUNNEL_ENCAP_NONE) - return 0; - - if (oif) - dev = __dev_get_by_index(net, oif); - ret = lwtunnel_build_state(dev, encap_type, encap, - AF_INET, cfg, &lwtstate); - if (!ret) { - result = lwtunnel_cmp_encap(lwtstate, nh->nh_lwtstate); - lwtstate_free(lwtstate); - } - - return result; -} - -int fib_nh_match(struct fib_config *cfg, struct fib_info *fi) -{ - struct net *net = cfg->fc_nlinfo.nl_net; -#ifdef CONFIG_IP_ROUTE_MULTIPATH - struct rtnexthop *rtnh; - int remaining; -#endif - - if (cfg->fc_priority && cfg->fc_priority != fi->fib_priority) - return 1; - - if (cfg->fc_oif || cfg->fc_gw) { - if (cfg->fc_encap) { - if (fib_encap_match(net, cfg->fc_encap_type, - cfg->fc_encap, cfg->fc_oif, - fi->fib_nh, cfg)) - return 1; - } - if ((!cfg->fc_oif || cfg->fc_oif == fi->fib_nh->nh_oif) && - (!cfg->fc_gw || cfg->fc_gw == fi->fib_nh->nh_gw)) - return 0; - return 1; - } - -#ifdef CONFIG_IP_ROUTE_MULTIPATH - if (!cfg->fc_mp) - return 0; - - rtnh = cfg->fc_mp; - remaining = cfg->fc_mp_len; - - for_nexthops(fi) { - int attrlen; - - if (!rtnh_ok(rtnh, remaining)) - return -EINVAL; - - if (rtnh->rtnh_ifindex && rtnh->rtnh_ifindex != nh->nh_oif) - return 1; - - attrlen = rtnh_attrlen(rtnh); - if (attrlen > 0) { - struct nlattr *nla, *attrs = rtnh_attrs(rtnh); - - nla = nla_find(attrs, attrlen, RTA_GATEWAY); - if (nla && nla_get_in_addr(nla) != nh->nh_gw) - return 1; -#ifdef CONFIG_IP_ROUTE_CLASSID - nla = nla_find(attrs, attrlen, RTA_FLOW); - if (nla && nla_get_u32(nla) != nh->nh_tclassid) - return 1; -#endif - } - - rtnh = rtnh_next(rtnh, &remaining); - } endfor_nexthops(fi); -#endif - return 0; -} - - -/* - * Picture - * ------- - * - * Semantics of nexthop is very messy by historical reasons. - * We have to take into account, that: - * a) gateway can be actually local interface address, - * so that gatewayed route is direct. - * b) gateway must be on-link address, possibly - * described not by an ifaddr, but also by a direct route. - * c) If both gateway and interface are specified, they should not - * contradict. - * d) If we use tunnel routes, gateway could be not on-link. - * - * Attempt to reconcile all of these (alas, self-contradictory) conditions - * results in pretty ugly and hairy code with obscure logic. - * - * I chose to generalized it instead, so that the size - * of code does not increase practically, but it becomes - * much more general. - * Every prefix is assigned a "scope" value: "host" is local address, - * "link" is direct route, - * [ ... "site" ... "interior" ... ] - * and "universe" is true gateway route with global meaning. - * - * Every prefix refers to a set of "nexthop"s (gw, oif), - * where gw must have narrower scope. This recursion stops - * when gw has LOCAL scope or if "nexthop" is declared ONLINK, - * which means that gw is forced to be on link. - * - * Code is still hairy, but now it is apparently logically - * consistent and very flexible. F.e. as by-product it allows - * to co-exists in peace independent exterior and interior - * routing processes. - * - * Normally it looks as following. - * - * {universe prefix} -> (gw, oif) [scope link] - * | - * |-> {link prefix} -> (gw, oif) [scope local] - * | - * |-> {local prefix} (terminal node) - */ -static int fib_check_nh(struct fib_config *cfg, struct fib_info *fi, - struct fib_nh *nh) -{ - int err = 0; - struct net *net; - struct net_device *dev; - - net = cfg->fc_nlinfo.nl_net; - if (nh->nh_gw) { - struct fib_result res; - - if (nh->nh_flags & RTNH_F_ONLINK) { - unsigned int addr_type; - - if (cfg->fc_scope >= RT_SCOPE_LINK) - return -EINVAL; - dev = __dev_get_by_index(net, nh->nh_oif); - if (!dev) - return -ENODEV; - if (!(dev->flags & IFF_UP)) - return -ENETDOWN; - addr_type = inet_addr_type_dev_table(net, dev, nh->nh_gw); - if (addr_type != RTN_UNICAST) - return -EINVAL; - if (!netif_carrier_ok(dev)) - nh->nh_flags |= RTNH_F_LINKDOWN; - nh->nh_dev = dev; - dev_hold(dev); - nh->nh_scope = RT_SCOPE_LINK; - return 0; - } - rcu_read_lock(); - { - struct fib_table *tbl = NULL; - struct flowi4 fl4 = { - .daddr = nh->nh_gw, - .flowi4_scope = cfg->fc_scope + 1, - .flowi4_oif = nh->nh_oif, - .flowi4_iif = LOOPBACK_IFINDEX, - }; - - /* It is not necessary, but requires a bit of thinking */ - if (fl4.flowi4_scope < RT_SCOPE_LINK) - fl4.flowi4_scope = RT_SCOPE_LINK; - - if (cfg->fc_table) - tbl = fib_get_table(net, cfg->fc_table); - - if (tbl) - err = fib_table_lookup(tbl, &fl4, &res, - FIB_LOOKUP_IGNORE_LINKSTATE | - FIB_LOOKUP_NOREF); - - /* on error or if no table given do full lookup. This - * is needed for example when nexthops are in the local - * table rather than the given table - */ - if (!tbl || err) { - err = fib_lookup(net, &fl4, &res, - FIB_LOOKUP_IGNORE_LINKSTATE); - } - - if (err) { - rcu_read_unlock(); - return err; - } - } - err = -EINVAL; - if (res.type != RTN_UNICAST && res.type != RTN_LOCAL) - goto out; - nh->nh_scope = res.scope; - nh->nh_oif = FIB_RES_OIF(res); - nh->nh_dev = dev = FIB_RES_DEV(res); - if (!dev) - goto out; - dev_hold(dev); - if (!netif_carrier_ok(dev)) - nh->nh_flags |= RTNH_F_LINKDOWN; - err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN; - } else { - struct in_device *in_dev; - - if (nh->nh_flags & (RTNH_F_PERVASIVE | RTNH_F_ONLINK)) - return -EINVAL; - - rcu_read_lock(); - err = -ENODEV; - in_dev = inetdev_by_index(net, nh->nh_oif); - if (!in_dev) - goto out; - err = -ENETDOWN; - if (!(in_dev->dev->flags & IFF_UP)) - goto out; - nh->nh_dev = in_dev->dev; - dev_hold(nh->nh_dev); - nh->nh_scope = RT_SCOPE_HOST; - if (!netif_carrier_ok(nh->nh_dev)) - nh->nh_flags |= RTNH_F_LINKDOWN; - err = 0; - } -out: - rcu_read_unlock(); - return err; -} - -static inline unsigned int fib_laddr_hashfn(__be32 val) -{ - unsigned int mask = (fib_info_hash_size - 1); - - return ((__force u32)val ^ - ((__force u32)val >> 7) ^ - ((__force u32)val >> 14)) & mask; -} - -static struct hlist_head *fib_info_hash_alloc(int bytes) -{ - if (bytes <= PAGE_SIZE) - return kzalloc(bytes, GFP_KERNEL); - else - return (struct hlist_head *) - __get_free_pages(GFP_KERNEL | __GFP_ZERO, - get_order(bytes)); -} - -static void fib_info_hash_free(struct hlist_head *hash, int bytes) -{ - if (!hash) - return; - - if (bytes <= PAGE_SIZE) - kfree(hash); - else - free_pages((unsigned long) hash, get_order(bytes)); -} - -static void fib_info_hash_move(struct hlist_head *new_info_hash, - struct hlist_head *new_laddrhash, - unsigned int new_size) -{ - struct hlist_head *old_info_hash, *old_laddrhash; - unsigned int old_size = fib_info_hash_size; - unsigned int i, bytes; - - spin_lock_bh(&fib_info_lock); - old_info_hash = fib_info_hash; - old_laddrhash = fib_info_laddrhash; - fib_info_hash_size = new_size; - - for (i = 0; i < old_size; i++) { - struct hlist_head *head = &fib_info_hash[i]; - struct hlist_node *n; - struct fib_info *fi; - - hlist_for_each_entry_safe(fi, n, head, fib_hash) { - struct hlist_head *dest; - unsigned int new_hash; - - new_hash = fib_info_hashfn(fi); - dest = &new_info_hash[new_hash]; - hlist_add_head(&fi->fib_hash, dest); - } - } - fib_info_hash = new_info_hash; - - for (i = 0; i < old_size; i++) { - struct hlist_head *lhead = &fib_info_laddrhash[i]; - struct hlist_node *n; - struct fib_info *fi; - - hlist_for_each_entry_safe(fi, n, lhead, fib_lhash) { - struct hlist_head *ldest; - unsigned int new_hash; - - new_hash = fib_laddr_hashfn(fi->fib_prefsrc); - ldest = &new_laddrhash[new_hash]; - hlist_add_head(&fi->fib_lhash, ldest); - } - } - fib_info_laddrhash = new_laddrhash; - - spin_unlock_bh(&fib_info_lock); - - bytes = old_size * sizeof(struct hlist_head *); - fib_info_hash_free(old_info_hash, bytes); - fib_info_hash_free(old_laddrhash, bytes); -} - -__be32 fib_info_update_nh_saddr(struct net *net, struct fib_nh *nh) -{ - nh->nh_saddr = inet_select_addr(nh->nh_dev, - nh->nh_gw, - nh->nh_parent->fib_scope); - nh->nh_saddr_genid = atomic_read(&net->ipv4.dev_addr_genid); - - return nh->nh_saddr; -} - -static bool fib_valid_prefsrc(struct fib_config *cfg, __be32 fib_prefsrc) -{ - if (cfg->fc_type != RTN_LOCAL || !cfg->fc_dst || - fib_prefsrc != cfg->fc_dst) { - u32 tb_id = cfg->fc_table; - int rc; - - if (tb_id == RT_TABLE_MAIN) - tb_id = RT_TABLE_LOCAL; - - rc = inet_addr_type_table(cfg->fc_nlinfo.nl_net, - fib_prefsrc, tb_id); - - if (rc != RTN_LOCAL && tb_id != RT_TABLE_LOCAL) { - rc = inet_addr_type_table(cfg->fc_nlinfo.nl_net, - fib_prefsrc, RT_TABLE_LOCAL); - } - - if (rc != RTN_LOCAL) - return false; - } - return true; -} - -static int -fib_convert_metrics(struct fib_info *fi, const struct fib_config *cfg) -{ - bool ecn_ca = false; - struct nlattr *nla; - int remaining; - - if (!cfg->fc_mx) - return 0; - - nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { - int type = nla_type(nla); - u32 val; - - if (!type) - continue; - if (type > RTAX_MAX) - return -EINVAL; - - if (type == RTAX_CC_ALGO) { - char tmp[TCP_CA_NAME_MAX]; - - nla_strlcpy(tmp, nla, sizeof(tmp)); - val = tcp_ca_get_key_by_name(tmp, &ecn_ca); - if (val == TCP_CA_UNSPEC) - return -EINVAL; - } else { - val = nla_get_u32(nla); - } - if (type == RTAX_ADVMSS && val > 65535 - 40) - val = 65535 - 40; - if (type == RTAX_MTU && val > 65535 - 15) - val = 65535 - 15; - if (type == RTAX_HOPLIMIT && val > 255) - val = 255; - if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK)) - return -EINVAL; - fi->fib_metrics[type - 1] = val; - } - - if (ecn_ca) - fi->fib_metrics[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA; - - return 0; -} - -struct fib_info *fib_create_info(struct fib_config *cfg) -{ - int err; - struct fib_info *fi = NULL; - struct fib_info *ofi; - int nhs = 1; - struct net *net = cfg->fc_nlinfo.nl_net; - - if (cfg->fc_type > RTN_MAX) - goto err_inval; - - /* Fast check to catch the most weird cases */ - if (fib_props[cfg->fc_type].scope > cfg->fc_scope) - goto err_inval; - - if (cfg->fc_flags & (RTNH_F_DEAD | RTNH_F_LINKDOWN)) - goto err_inval; - -#ifdef CONFIG_IP_ROUTE_MULTIPATH - if (cfg->fc_mp) { - nhs = fib_count_nexthops(cfg->fc_mp, cfg->fc_mp_len); - if (nhs == 0) - goto err_inval; - } -#endif - - err = -ENOBUFS; - if (fib_info_cnt >= fib_info_hash_size) { - unsigned int new_size = fib_info_hash_size << 1; - struct hlist_head *new_info_hash; - struct hlist_head *new_laddrhash; - unsigned int bytes; - - if (!new_size) - new_size = 16; - bytes = new_size * sizeof(struct hlist_head *); - new_info_hash = fib_info_hash_alloc(bytes); - new_laddrhash = fib_info_hash_alloc(bytes); - if (!new_info_hash || !new_laddrhash) { - fib_info_hash_free(new_info_hash, bytes); - fib_info_hash_free(new_laddrhash, bytes); - } else - fib_info_hash_move(new_info_hash, new_laddrhash, new_size); - - if (!fib_info_hash_size) - goto failure; - } - - fi = kzalloc(sizeof(*fi)+nhs*sizeof(struct fib_nh), GFP_KERNEL); - if (!fi) - goto failure; - fib_info_cnt++; - if (cfg->fc_mx) { - fi->fib_metrics = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL); - if (!fi->fib_metrics) - goto failure; - } else - fi->fib_metrics = (u32 *) dst_default_metrics; - - fi->fib_net = net; - fi->fib_protocol = cfg->fc_protocol; - fi->fib_scope = cfg->fc_scope; - fi->fib_flags = cfg->fc_flags; - fi->fib_priority = cfg->fc_priority; - fi->fib_prefsrc = cfg->fc_prefsrc; - fi->fib_type = cfg->fc_type; - fi->fib_tb_id = cfg->fc_table; - - fi->fib_nhs = nhs; - change_nexthops(fi) { - nexthop_nh->nh_parent = fi; - nexthop_nh->nh_pcpu_rth_output = alloc_percpu(struct rtable __rcu *); - if (!nexthop_nh->nh_pcpu_rth_output) - goto failure; - } endfor_nexthops(fi) - - err = fib_convert_metrics(fi, cfg); - if (err) - goto failure; - - if (cfg->fc_mp) { -#ifdef CONFIG_IP_ROUTE_MULTIPATH - err = fib_get_nhs(fi, cfg->fc_mp, cfg->fc_mp_len, cfg); - if (err != 0) - goto failure; - if (cfg->fc_oif && fi->fib_nh->nh_oif != cfg->fc_oif) - goto err_inval; - if (cfg->fc_gw && fi->fib_nh->nh_gw != cfg->fc_gw) - goto err_inval; -#ifdef CONFIG_IP_ROUTE_CLASSID - if (cfg->fc_flow && fi->fib_nh->nh_tclassid != cfg->fc_flow) - goto err_inval; -#endif -#else - goto err_inval; -#endif - } else { - struct fib_nh *nh = fi->fib_nh; - - if (cfg->fc_encap) { - struct lwtunnel_state *lwtstate; - struct net_device *dev = NULL; - - if (cfg->fc_encap_type == LWTUNNEL_ENCAP_NONE) - goto err_inval; - if (cfg->fc_oif) - dev = __dev_get_by_index(net, cfg->fc_oif); - err = lwtunnel_build_state(dev, cfg->fc_encap_type, - cfg->fc_encap, AF_INET, cfg, - &lwtstate); - if (err) - goto failure; - - nh->nh_lwtstate = lwtstate_get(lwtstate); - } - nh->nh_oif = cfg->fc_oif; - nh->nh_gw = cfg->fc_gw; - nh->nh_flags = cfg->fc_flags; -#ifdef CONFIG_IP_ROUTE_CLASSID - nh->nh_tclassid = cfg->fc_flow; - if (nh->nh_tclassid) - fi->fib_net->ipv4.fib_num_tclassid_users++; -#endif -#ifdef CONFIG_IP_ROUTE_MULTIPATH - nh->nh_weight = 1; -#endif - } - - if (fib_props[cfg->fc_type].error) { - if (cfg->fc_gw || cfg->fc_oif || cfg->fc_mp) - goto err_inval; - goto link_it; - } else { - switch (cfg->fc_type) { - case RTN_UNICAST: - case RTN_LOCAL: - case RTN_BROADCAST: - case RTN_ANYCAST: - case RTN_MULTICAST: - break; - default: - goto err_inval; - } - } - - if (cfg->fc_scope > RT_SCOPE_HOST) - goto err_inval; - - if (cfg->fc_scope == RT_SCOPE_HOST) { - struct fib_nh *nh = fi->fib_nh; - - /* Local address is added. */ - if (nhs != 1 || nh->nh_gw) - goto err_inval; - nh->nh_scope = RT_SCOPE_NOWHERE; - nh->nh_dev = dev_get_by_index(net, fi->fib_nh->nh_oif); - err = -ENODEV; - if (!nh->nh_dev) - goto failure; - } else { - int linkdown = 0; - - change_nexthops(fi) { - err = fib_check_nh(cfg, fi, nexthop_nh); - if (err != 0) - goto failure; - if (nexthop_nh->nh_flags & RTNH_F_LINKDOWN) - linkdown++; - } endfor_nexthops(fi) - if (linkdown == fi->fib_nhs) - fi->fib_flags |= RTNH_F_LINKDOWN; - } - - if (fi->fib_prefsrc && !fib_valid_prefsrc(cfg, fi->fib_prefsrc)) - goto err_inval; - - change_nexthops(fi) { - fib_info_update_nh_saddr(net, nexthop_nh); - fib_add_weight(fi, nexthop_nh); - } endfor_nexthops(fi) - - fib_rebalance(fi); - -link_it: - ofi = fib_find_info(fi); - if (ofi) { - fi->fib_dead = 1; - free_fib_info(fi); - ofi->fib_treeref++; - return ofi; - } - - fi->fib_treeref++; - atomic_inc(&fi->fib_clntref); - spin_lock_bh(&fib_info_lock); - hlist_add_head(&fi->fib_hash, - &fib_info_hash[fib_info_hashfn(fi)]); - if (fi->fib_prefsrc) { - struct hlist_head *head; - - head = &fib_info_laddrhash[fib_laddr_hashfn(fi->fib_prefsrc)]; - hlist_add_head(&fi->fib_lhash, head); - } - change_nexthops(fi) { - struct hlist_head *head; - unsigned int hash; - - if (!nexthop_nh->nh_dev) - continue; - hash = fib_devindex_hashfn(nexthop_nh->nh_dev->ifindex); - head = &fib_info_devhash[hash]; - hlist_add_head(&nexthop_nh->nh_hash, head); - } endfor_nexthops(fi) - spin_unlock_bh(&fib_info_lock); - return fi; - -err_inval: - err = -EINVAL; - -failure: - if (fi) { - fi->fib_dead = 1; - free_fib_info(fi); - } - - return ERR_PTR(err); -} - -int fib_dump_info(struct sk_buff *skb, u32 portid, u32 seq, int event, - u32 tb_id, u8 type, __be32 dst, int dst_len, u8 tos, - struct fib_info *fi, unsigned int flags) -{ - struct nlmsghdr *nlh; - struct rtmsg *rtm; - - nlh = nlmsg_put(skb, portid, seq, event, sizeof(*rtm), flags); - if (!nlh) - return -EMSGSIZE; - - rtm = nlmsg_data(nlh); - rtm->rtm_family = AF_INET; - rtm->rtm_dst_len = dst_len; - rtm->rtm_src_len = 0; - rtm->rtm_tos = tos; - if (tb_id < 256) - rtm->rtm_table = tb_id; - else - rtm->rtm_table = RT_TABLE_COMPAT; - if (nla_put_u32(skb, RTA_TABLE, tb_id)) - goto nla_put_failure; - rtm->rtm_type = type; - rtm->rtm_flags = fi->fib_flags; - rtm->rtm_scope = fi->fib_scope; - rtm->rtm_protocol = fi->fib_protocol; - - if (rtm->rtm_dst_len && - nla_put_in_addr(skb, RTA_DST, dst)) - goto nla_put_failure; - if (fi->fib_priority && - nla_put_u32(skb, RTA_PRIORITY, fi->fib_priority)) - goto nla_put_failure; - if (rtnetlink_put_metrics(skb, fi->fib_metrics) < 0) - goto nla_put_failure; - - if (fi->fib_prefsrc && - nla_put_in_addr(skb, RTA_PREFSRC, fi->fib_prefsrc)) - goto nla_put_failure; - if (fi->fib_nhs == 1) { - struct in_device *in_dev; - - if (fi->fib_nh->nh_gw && - nla_put_in_addr(skb, RTA_GATEWAY, fi->fib_nh->nh_gw)) - goto nla_put_failure; - if (fi->fib_nh->nh_oif && - nla_put_u32(skb, RTA_OIF, fi->fib_nh->nh_oif)) - goto nla_put_failure; - if (fi->fib_nh->nh_flags & RTNH_F_LINKDOWN) { - in_dev = __in_dev_get_rtnl(fi->fib_nh->nh_dev); - if (in_dev && - IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev)) - rtm->rtm_flags |= RTNH_F_DEAD; - } -#ifdef CONFIG_IP_ROUTE_CLASSID - if (fi->fib_nh[0].nh_tclassid && - nla_put_u32(skb, RTA_FLOW, fi->fib_nh[0].nh_tclassid)) - goto nla_put_failure; -#endif - if (fi->fib_nh->nh_lwtstate) - lwtunnel_fill_encap(skb, fi->fib_nh->nh_lwtstate); - } -#ifdef CONFIG_IP_ROUTE_MULTIPATH - if (fi->fib_nhs > 1) { - struct rtnexthop *rtnh; - struct nlattr *mp; - - mp = nla_nest_start(skb, RTA_MULTIPATH); - if (!mp) - goto nla_put_failure; - - for_nexthops(fi) { - struct in_device *in_dev; - - rtnh = nla_reserve_nohdr(skb, sizeof(*rtnh)); - if (!rtnh) - goto nla_put_failure; - - rtnh->rtnh_flags = nh->nh_flags & 0xFF; - if (nh->nh_flags & RTNH_F_LINKDOWN) { - in_dev = __in_dev_get_rtnl(nh->nh_dev); - if (in_dev && - IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev)) - rtnh->rtnh_flags |= RTNH_F_DEAD; - } - rtnh->rtnh_hops = nh->nh_weight - 1; - rtnh->rtnh_ifindex = nh->nh_oif; - - if (nh->nh_gw && - nla_put_in_addr(skb, RTA_GATEWAY, nh->nh_gw)) - goto nla_put_failure; -#ifdef CONFIG_IP_ROUTE_CLASSID - if (nh->nh_tclassid && - nla_put_u32(skb, RTA_FLOW, nh->nh_tclassid)) - goto nla_put_failure; -#endif - if (nh->nh_lwtstate) - lwtunnel_fill_encap(skb, nh->nh_lwtstate); - /* length of rtnetlink header + attributes */ - rtnh->rtnh_len = nlmsg_get_pos(skb) - (void *) rtnh; - } endfor_nexthops(fi); - - nla_nest_end(skb, mp); - } -#endif - nlmsg_end(skb, nlh); - return 0; - -nla_put_failure: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -/* - * Update FIB if: - * - local address disappeared -> we must delete all the entries - * referring to it. - * - device went down -> we must shutdown all nexthops going via it. - */ -int fib_sync_down_addr(struct net_device *dev, __be32 local) -{ - int ret = 0; - unsigned int hash = fib_laddr_hashfn(local); - struct hlist_head *head = &fib_info_laddrhash[hash]; - struct net *net = dev_net(dev); - int tb_id = l3mdev_fib_table(dev); - struct fib_info *fi; - - if (!fib_info_laddrhash || local == 0) - return 0; - - hlist_for_each_entry(fi, head, fib_lhash) { - if (!net_eq(fi->fib_net, net) || - fi->fib_tb_id != tb_id) - continue; - if (fi->fib_prefsrc == local) { - fi->fib_flags |= RTNH_F_DEAD; - ret++; - } - } - return ret; -} - -/* Event force Flags Description - * NETDEV_CHANGE 0 LINKDOWN Carrier OFF, not for scope host - * NETDEV_DOWN 0 LINKDOWN|DEAD Link down, not for scope host - * NETDEV_DOWN 1 LINKDOWN|DEAD Last address removed - * NETDEV_UNREGISTER 1 LINKDOWN|DEAD Device removed - */ -int fib_sync_down_dev(struct net_device *dev, unsigned long event, bool force) -{ - int ret = 0; - int scope = RT_SCOPE_NOWHERE; - struct fib_info *prev_fi = NULL; - unsigned int hash = fib_devindex_hashfn(dev->ifindex); - struct hlist_head *head = &fib_info_devhash[hash]; - struct fib_nh *nh; - - if (force) - scope = -1; - - hlist_for_each_entry(nh, head, nh_hash) { - struct fib_info *fi = nh->nh_parent; - int dead; - - BUG_ON(!fi->fib_nhs); - if (nh->nh_dev != dev || fi == prev_fi) - continue; - prev_fi = fi; - dead = 0; - change_nexthops(fi) { - if (nexthop_nh->nh_flags & RTNH_F_DEAD) - dead++; - else if (nexthop_nh->nh_dev == dev && - nexthop_nh->nh_scope != scope) { - switch (event) { - case NETDEV_DOWN: - case NETDEV_UNREGISTER: - nexthop_nh->nh_flags |= RTNH_F_DEAD; - /* fall through */ - case NETDEV_CHANGE: - nexthop_nh->nh_flags |= RTNH_F_LINKDOWN; - break; - } - dead++; - } -#ifdef CONFIG_IP_ROUTE_MULTIPATH - if (event == NETDEV_UNREGISTER && - nexthop_nh->nh_dev == dev) { - dead = fi->fib_nhs; - break; - } -#endif - } endfor_nexthops(fi) - if (dead == fi->fib_nhs) { - switch (event) { - case NETDEV_DOWN: - case NETDEV_UNREGISTER: - fi->fib_flags |= RTNH_F_DEAD; - /* fall through */ - case NETDEV_CHANGE: - fi->fib_flags |= RTNH_F_LINKDOWN; - break; - } - ret++; - } - - fib_rebalance(fi); - } - - return ret; -} - -/* Must be invoked inside of an RCU protected region. */ -void fib_select_default(const struct flowi4 *flp, struct fib_result *res) -{ - struct fib_info *fi = NULL, *last_resort = NULL; - struct hlist_head *fa_head = res->fa_head; - struct fib_table *tb = res->table; - u8 slen = 32 - res->prefixlen; - int order = -1, last_idx = -1; - struct fib_alias *fa, *fa1 = NULL; - u32 last_prio = res->fi->fib_priority; - u8 last_tos = 0; - - hlist_for_each_entry_rcu(fa, fa_head, fa_list) { - struct fib_info *next_fi = fa->fa_info; - - if (fa->fa_slen != slen) - continue; - if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos) - continue; - if (fa->tb_id != tb->tb_id) - continue; - if (next_fi->fib_priority > last_prio && - fa->fa_tos == last_tos) { - if (last_tos) - continue; - break; - } - if (next_fi->fib_flags & RTNH_F_DEAD) - continue; - last_tos = fa->fa_tos; - last_prio = next_fi->fib_priority; - - if (next_fi->fib_scope != res->scope || - fa->fa_type != RTN_UNICAST) - continue; - if (!next_fi->fib_nh[0].nh_gw || - next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK) - continue; - - fib_alias_accessed(fa); - - if (!fi) { - if (next_fi != res->fi) - break; - fa1 = fa; - } else if (!fib_detect_death(fi, order, &last_resort, - &last_idx, fa1->fa_default)) { - fib_result_assign(res, fi); - fa1->fa_default = order; - goto out; - } - fi = next_fi; - order++; - } - - if (order <= 0 || !fi) { - if (fa1) - fa1->fa_default = -1; - goto out; - } - - if (!fib_detect_death(fi, order, &last_resort, &last_idx, - fa1->fa_default)) { - fib_result_assign(res, fi); - fa1->fa_default = order; - goto out; - } - - if (last_idx >= 0) - fib_result_assign(res, last_resort); - fa1->fa_default = last_idx; -out: - return; -} - -/* - * Dead device goes up. We wake up dead nexthops. - * It takes sense only on multipath routes. - */ -int fib_sync_up(struct net_device *dev, unsigned int nh_flags) -{ - struct fib_info *prev_fi; - unsigned int hash; - struct hlist_head *head; - struct fib_nh *nh; - int ret; - - if (!(dev->flags & IFF_UP)) - return 0; - - if (nh_flags & RTNH_F_DEAD) { - unsigned int flags = dev_get_flags(dev); - - if (flags & (IFF_RUNNING | IFF_LOWER_UP)) - nh_flags |= RTNH_F_LINKDOWN; - } - - prev_fi = NULL; - hash = fib_devindex_hashfn(dev->ifindex); - head = &fib_info_devhash[hash]; - ret = 0; - - hlist_for_each_entry(nh, head, nh_hash) { - struct fib_info *fi = nh->nh_parent; - int alive; - - BUG_ON(!fi->fib_nhs); - if (nh->nh_dev != dev || fi == prev_fi) - continue; - - prev_fi = fi; - alive = 0; - change_nexthops(fi) { - if (!(nexthop_nh->nh_flags & nh_flags)) { - alive++; - continue; - } - if (!nexthop_nh->nh_dev || - !(nexthop_nh->nh_dev->flags & IFF_UP)) - continue; - if (nexthop_nh->nh_dev != dev || - !__in_dev_get_rtnl(dev)) - continue; - alive++; - nexthop_nh->nh_flags &= ~nh_flags; - } endfor_nexthops(fi) - - if (alive > 0) { - fi->fib_flags &= ~nh_flags; - ret++; - } - - fib_rebalance(fi); - } - - return ret; -} - -#ifdef CONFIG_IP_ROUTE_MULTIPATH -static bool fib_good_nh(const struct fib_nh *nh) -{ - int state = NUD_REACHABLE; - - if (nh->nh_scope == RT_SCOPE_LINK) { - struct neighbour *n; - - rcu_read_lock_bh(); - - n = __ipv4_neigh_lookup_noref(nh->nh_dev, - (__force u32)nh->nh_gw); - if (n) - state = n->nud_state; - - rcu_read_unlock_bh(); - } - - return !!(state & NUD_VALID); -} - -void fib_select_multipath(struct fib_result *res, int hash) -{ - struct fib_info *fi = res->fi; - struct net *net = fi->fib_net; - bool first = false; - - for_nexthops(fi) { - if (hash > atomic_read(&nh->nh_upper_bound)) - continue; - - if (!net->ipv4.sysctl_fib_multipath_use_neigh || - fib_good_nh(nh)) { - res->nh_sel = nhsel; - return; - } - if (!first) { - res->nh_sel = nhsel; - first = true; - } - } endfor_nexthops(fi); -} -#endif - -void fib_select_path(struct net *net, struct fib_result *res, - struct flowi4 *fl4, int mp_hash) -{ -#ifdef CONFIG_IP_ROUTE_MULTIPATH - if (res->fi->fib_nhs > 1 && fl4->flowi4_oif == 0) { - if (mp_hash < 0) - mp_hash = get_hash_from_flowi4(fl4) >> 1; - - fib_select_multipath(res, mp_hash); - } - else -#endif - if (!res->prefixlen && - res->table->tb_num_default > 1 && - res->type == RTN_UNICAST && !fl4->flowi4_oif) - fib_select_default(fl4, res); - - if (!fl4->saddr) - fl4->saddr = FIB_RES_PREFSRC(net, *res); -} -EXPORT_SYMBOL_GPL(fib_select_path); diff --git a/src/linux/net/ipv4/fib_trie.c b/src/linux/net/ipv4/fib_trie.c deleted file mode 100644 index e3665bf..0000000 --- a/src/linux/net/ipv4/fib_trie.c +++ /dev/null @@ -1,2694 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Robert Olsson Uppsala Universitet - * & Swedish University of Agricultural Sciences. - * - * Jens Laas Swedish University of - * Agricultural Sciences. - * - * Hans Liss Uppsala Universitet - * - * This work is based on the LPC-trie which is originally described in: - * - * An experimental study of compression methods for dynamic tries - * Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002. - * http://www.csc.kth.se/~snilsson/software/dyntrie2/ - * - * - * IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson - * IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, June 1999 - * - * - * Code from fib_hash has been reused which includes the following header: - * - * - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * IPv4 FIB: lookup engine and maintenance routines. - * - * - * Authors: Alexey Kuznetsov, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Substantial contributions to this work comes from: - * - * David S. Miller, - * Stephen Hemminger - * Paul E. McKenney - * Patrick McHardy - */ - -#define VERSION "0.409" - -#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 -#include -#include -#include -#include -#include "fib_lookup.h" - -static BLOCKING_NOTIFIER_HEAD(fib_chain); - -int register_fib_notifier(struct notifier_block *nb) -{ - return blocking_notifier_chain_register(&fib_chain, nb); -} -EXPORT_SYMBOL(register_fib_notifier); - -int unregister_fib_notifier(struct notifier_block *nb) -{ - return blocking_notifier_chain_unregister(&fib_chain, nb); -} -EXPORT_SYMBOL(unregister_fib_notifier); - -int call_fib_notifiers(struct net *net, enum fib_event_type event_type, - struct fib_notifier_info *info) -{ - info->net = net; - return blocking_notifier_call_chain(&fib_chain, event_type, info); -} - -static int call_fib_entry_notifiers(struct net *net, - enum fib_event_type event_type, u32 dst, - int dst_len, struct fib_info *fi, - u8 tos, u8 type, u32 tb_id, u32 nlflags) -{ - struct fib_entry_notifier_info info = { - .dst = dst, - .dst_len = dst_len, - .fi = fi, - .tos = tos, - .type = type, - .tb_id = tb_id, - .nlflags = nlflags, - }; - return call_fib_notifiers(net, event_type, &info.info); -} - -#define MAX_STAT_DEPTH 32 - -#define KEYLENGTH (8*sizeof(t_key)) -#define KEY_MAX ((t_key)~0) - -typedef unsigned int t_key; - -#define IS_TRIE(n) ((n)->pos >= KEYLENGTH) -#define IS_TNODE(n) ((n)->bits) -#define IS_LEAF(n) (!(n)->bits) - -struct key_vector { - t_key key; - unsigned char pos; /* 2log(KEYLENGTH) bits needed */ - unsigned char bits; /* 2log(KEYLENGTH) bits needed */ - unsigned char slen; - union { - /* This list pointer if valid if (pos | bits) == 0 (LEAF) */ - struct hlist_head leaf; - /* This array is valid if (pos | bits) > 0 (TNODE) */ - struct key_vector __rcu *tnode[0]; - }; -}; - -struct tnode { - struct rcu_head rcu; - t_key empty_children; /* KEYLENGTH bits needed */ - t_key full_children; /* KEYLENGTH bits needed */ - struct key_vector __rcu *parent; - struct key_vector kv[1]; -#define tn_bits kv[0].bits -}; - -#define TNODE_SIZE(n) offsetof(struct tnode, kv[0].tnode[n]) -#define LEAF_SIZE TNODE_SIZE(1) - -#ifdef CONFIG_IP_FIB_TRIE_STATS -struct trie_use_stats { - unsigned int gets; - unsigned int backtrack; - unsigned int semantic_match_passed; - unsigned int semantic_match_miss; - unsigned int null_node_hit; - unsigned int resize_node_skipped; -}; -#endif - -struct trie_stat { - unsigned int totdepth; - unsigned int maxdepth; - unsigned int tnodes; - unsigned int leaves; - unsigned int nullpointers; - unsigned int prefixes; - unsigned int nodesizes[MAX_STAT_DEPTH]; -}; - -struct trie { - struct key_vector kv[1]; -#ifdef CONFIG_IP_FIB_TRIE_STATS - struct trie_use_stats __percpu *stats; -#endif -}; - -static struct key_vector *resize(struct trie *t, struct key_vector *tn); -static size_t tnode_free_size; - -/* - * synchronize_rcu after call_rcu for that many pages; it should be especially - * useful before resizing the root node with PREEMPT_NONE configs; the value was - * obtained experimentally, aiming to avoid visible slowdown. - */ -static const int sync_pages = 128; - -static struct kmem_cache *fn_alias_kmem __read_mostly; -static struct kmem_cache *trie_leaf_kmem __read_mostly; - -static inline struct tnode *tn_info(struct key_vector *kv) -{ - return container_of(kv, struct tnode, kv[0]); -} - -/* caller must hold RTNL */ -#define node_parent(tn) rtnl_dereference(tn_info(tn)->parent) -#define get_child(tn, i) rtnl_dereference((tn)->tnode[i]) - -/* caller must hold RCU read lock or RTNL */ -#define node_parent_rcu(tn) rcu_dereference_rtnl(tn_info(tn)->parent) -#define get_child_rcu(tn, i) rcu_dereference_rtnl((tn)->tnode[i]) - -/* wrapper for rcu_assign_pointer */ -static inline void node_set_parent(struct key_vector *n, struct key_vector *tp) -{ - if (n) - rcu_assign_pointer(tn_info(n)->parent, tp); -} - -#define NODE_INIT_PARENT(n, p) RCU_INIT_POINTER(tn_info(n)->parent, p) - -/* This provides us with the number of children in this node, in the case of a - * leaf this will return 0 meaning none of the children are accessible. - */ -static inline unsigned long child_length(const struct key_vector *tn) -{ - return (1ul << tn->bits) & ~(1ul); -} - -#define get_cindex(key, kv) (((key) ^ (kv)->key) >> (kv)->pos) - -static inline unsigned long get_index(t_key key, struct key_vector *kv) -{ - unsigned long index = key ^ kv->key; - - if ((BITS_PER_LONG <= KEYLENGTH) && (KEYLENGTH == kv->pos)) - return 0; - - return index >> kv->pos; -} - -/* To understand this stuff, an understanding of keys and all their bits is - * necessary. Every node in the trie has a key associated with it, but not - * all of the bits in that key are significant. - * - * Consider a node 'n' and its parent 'tp'. - * - * If n is a leaf, every bit in its key is significant. Its presence is - * necessitated by path compression, since during a tree traversal (when - * searching for a leaf - unless we are doing an insertion) we will completely - * ignore all skipped bits we encounter. Thus we need to verify, at the end of - * a potentially successful search, that we have indeed been walking the - * correct key path. - * - * Note that we can never "miss" the correct key in the tree if present by - * following the wrong path. Path compression ensures that segments of the key - * that are the same for all keys with a given prefix are skipped, but the - * skipped part *is* identical for each node in the subtrie below the skipped - * bit! trie_insert() in this implementation takes care of that. - * - * if n is an internal node - a 'tnode' here, the various parts of its key - * have many different meanings. - * - * Example: - * _________________________________________________________________ - * | i | i | i | i | i | i | i | N | N | N | S | S | S | S | S | C | - * ----------------------------------------------------------------- - * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 - * - * _________________________________________________________________ - * | C | C | C | u | u | u | u | u | u | u | u | u | u | u | u | u | - * ----------------------------------------------------------------- - * 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 - * - * tp->pos = 22 - * tp->bits = 3 - * n->pos = 13 - * n->bits = 4 - * - * First, let's just ignore the bits that come before the parent tp, that is - * the bits from (tp->pos + tp->bits) to 31. They are *known* but at this - * point we do not use them for anything. - * - * The bits from (tp->pos) to (tp->pos + tp->bits - 1) - "N", above - are the - * index into the parent's child array. That is, they will be used to find - * 'n' among tp's children. - * - * The bits from (n->pos + n->bits) to (tp->pos - 1) - "S" - are skipped bits - * for the node n. - * - * All the bits we have seen so far are significant to the node n. The rest - * of the bits are really not needed or indeed known in n->key. - * - * The bits from (n->pos) to (n->pos + n->bits - 1) - "C" - are the index into - * n's child array, and will of course be different for each child. - * - * The rest of the bits, from 0 to (n->pos -1) - "u" - are completely unknown - * at this point. - */ - -static const int halve_threshold = 25; -static const int inflate_threshold = 50; -static const int halve_threshold_root = 15; -static const int inflate_threshold_root = 30; - -static void __alias_free_mem(struct rcu_head *head) -{ - struct fib_alias *fa = container_of(head, struct fib_alias, rcu); - kmem_cache_free(fn_alias_kmem, fa); -} - -static inline void alias_free_mem_rcu(struct fib_alias *fa) -{ - call_rcu(&fa->rcu, __alias_free_mem); -} - -#define TNODE_KMALLOC_MAX \ - ilog2((PAGE_SIZE - TNODE_SIZE(0)) / sizeof(struct key_vector *)) -#define TNODE_VMALLOC_MAX \ - ilog2((SIZE_MAX - TNODE_SIZE(0)) / sizeof(struct key_vector *)) - -static void __node_free_rcu(struct rcu_head *head) -{ - struct tnode *n = container_of(head, struct tnode, rcu); - - if (!n->tn_bits) - kmem_cache_free(trie_leaf_kmem, n); - else - kvfree(n); -} - -#define node_free(n) call_rcu(&tn_info(n)->rcu, __node_free_rcu) - -static struct tnode *tnode_alloc(int bits) -{ - size_t size; - - /* verify bits is within bounds */ - if (bits > TNODE_VMALLOC_MAX) - return NULL; - - /* determine size and verify it is non-zero and didn't overflow */ - size = TNODE_SIZE(1ul << bits); - - if (size <= PAGE_SIZE) - return kzalloc(size, GFP_KERNEL); - else - return vzalloc(size); -} - -static inline void empty_child_inc(struct key_vector *n) -{ - ++tn_info(n)->empty_children ? : ++tn_info(n)->full_children; -} - -static inline void empty_child_dec(struct key_vector *n) -{ - tn_info(n)->empty_children-- ? : tn_info(n)->full_children--; -} - -static struct key_vector *leaf_new(t_key key, struct fib_alias *fa) -{ - struct key_vector *l; - struct tnode *kv; - - kv = kmem_cache_alloc(trie_leaf_kmem, GFP_KERNEL); - if (!kv) - return NULL; - - /* initialize key vector */ - l = kv->kv; - l->key = key; - l->pos = 0; - l->bits = 0; - l->slen = fa->fa_slen; - - /* link leaf to fib alias */ - INIT_HLIST_HEAD(&l->leaf); - hlist_add_head(&fa->fa_list, &l->leaf); - - return l; -} - -static struct key_vector *tnode_new(t_key key, int pos, int bits) -{ - unsigned int shift = pos + bits; - struct key_vector *tn; - struct tnode *tnode; - - /* verify bits and pos their msb bits clear and values are valid */ - BUG_ON(!bits || (shift > KEYLENGTH)); - - tnode = tnode_alloc(bits); - if (!tnode) - return NULL; - - pr_debug("AT %p s=%zu %zu\n", tnode, TNODE_SIZE(0), - sizeof(struct key_vector *) << bits); - - if (bits == KEYLENGTH) - tnode->full_children = 1; - else - tnode->empty_children = 1ul << bits; - - tn = tnode->kv; - tn->key = (shift < KEYLENGTH) ? (key >> shift) << shift : 0; - tn->pos = pos; - tn->bits = bits; - tn->slen = pos; - - return tn; -} - -/* Check whether a tnode 'n' is "full", i.e. it is an internal node - * and no bits are skipped. See discussion in dyntree paper p. 6 - */ -static inline int tnode_full(struct key_vector *tn, struct key_vector *n) -{ - return n && ((n->pos + n->bits) == tn->pos) && IS_TNODE(n); -} - -/* Add a child at position i overwriting the old value. - * Update the value of full_children and empty_children. - */ -static void put_child(struct key_vector *tn, unsigned long i, - struct key_vector *n) -{ - struct key_vector *chi = get_child(tn, i); - int isfull, wasfull; - - BUG_ON(i >= child_length(tn)); - - /* update emptyChildren, overflow into fullChildren */ - if (!n && chi) - empty_child_inc(tn); - if (n && !chi) - empty_child_dec(tn); - - /* update fullChildren */ - wasfull = tnode_full(tn, chi); - isfull = tnode_full(tn, n); - - if (wasfull && !isfull) - tn_info(tn)->full_children--; - else if (!wasfull && isfull) - tn_info(tn)->full_children++; - - if (n && (tn->slen < n->slen)) - tn->slen = n->slen; - - rcu_assign_pointer(tn->tnode[i], n); -} - -static void update_children(struct key_vector *tn) -{ - unsigned long i; - - /* update all of the child parent pointers */ - for (i = child_length(tn); i;) { - struct key_vector *inode = get_child(tn, --i); - - if (!inode) - continue; - - /* Either update the children of a tnode that - * already belongs to us or update the child - * to point to ourselves. - */ - if (node_parent(inode) == tn) - update_children(inode); - else - node_set_parent(inode, tn); - } -} - -static inline void put_child_root(struct key_vector *tp, t_key key, - struct key_vector *n) -{ - if (IS_TRIE(tp)) - rcu_assign_pointer(tp->tnode[0], n); - else - put_child(tp, get_index(key, tp), n); -} - -static inline void tnode_free_init(struct key_vector *tn) -{ - tn_info(tn)->rcu.next = NULL; -} - -static inline void tnode_free_append(struct key_vector *tn, - struct key_vector *n) -{ - tn_info(n)->rcu.next = tn_info(tn)->rcu.next; - tn_info(tn)->rcu.next = &tn_info(n)->rcu; -} - -static void tnode_free(struct key_vector *tn) -{ - struct callback_head *head = &tn_info(tn)->rcu; - - while (head) { - head = head->next; - tnode_free_size += TNODE_SIZE(1ul << tn->bits); - node_free(tn); - - tn = container_of(head, struct tnode, rcu)->kv; - } - - if (tnode_free_size >= PAGE_SIZE * sync_pages) { - tnode_free_size = 0; - synchronize_rcu(); - } -} - -static struct key_vector *replace(struct trie *t, - struct key_vector *oldtnode, - struct key_vector *tn) -{ - struct key_vector *tp = node_parent(oldtnode); - unsigned long i; - - /* setup the parent pointer out of and back into this node */ - NODE_INIT_PARENT(tn, tp); - put_child_root(tp, tn->key, tn); - - /* update all of the child parent pointers */ - update_children(tn); - - /* all pointers should be clean so we are done */ - tnode_free(oldtnode); - - /* resize children now that oldtnode is freed */ - for (i = child_length(tn); i;) { - struct key_vector *inode = get_child(tn, --i); - - /* resize child node */ - if (tnode_full(tn, inode)) - tn = resize(t, inode); - } - - return tp; -} - -static struct key_vector *inflate(struct trie *t, - struct key_vector *oldtnode) -{ - struct key_vector *tn; - unsigned long i; - t_key m; - - pr_debug("In inflate\n"); - - tn = tnode_new(oldtnode->key, oldtnode->pos - 1, oldtnode->bits + 1); - if (!tn) - goto notnode; - - /* prepare oldtnode to be freed */ - tnode_free_init(oldtnode); - - /* Assemble all of the pointers in our cluster, in this case that - * represents all of the pointers out of our allocated nodes that - * point to existing tnodes and the links between our allocated - * nodes. - */ - for (i = child_length(oldtnode), m = 1u << tn->pos; i;) { - struct key_vector *inode = get_child(oldtnode, --i); - struct key_vector *node0, *node1; - unsigned long j, k; - - /* An empty child */ - if (!inode) - continue; - - /* A leaf or an internal node with skipped bits */ - if (!tnode_full(oldtnode, inode)) { - put_child(tn, get_index(inode->key, tn), inode); - continue; - } - - /* drop the node in the old tnode free list */ - tnode_free_append(oldtnode, inode); - - /* An internal node with two children */ - if (inode->bits == 1) { - put_child(tn, 2 * i + 1, get_child(inode, 1)); - put_child(tn, 2 * i, get_child(inode, 0)); - continue; - } - - /* We will replace this node 'inode' with two new - * ones, 'node0' and 'node1', each with half of the - * original children. The two new nodes will have - * a position one bit further down the key and this - * means that the "significant" part of their keys - * (see the discussion near the top of this file) - * will differ by one bit, which will be "0" in - * node0's key and "1" in node1's key. Since we are - * moving the key position by one step, the bit that - * we are moving away from - the bit at position - * (tn->pos) - is the one that will differ between - * node0 and node1. So... we synthesize that bit in the - * two new keys. - */ - node1 = tnode_new(inode->key | m, inode->pos, inode->bits - 1); - if (!node1) - goto nomem; - node0 = tnode_new(inode->key, inode->pos, inode->bits - 1); - - tnode_free_append(tn, node1); - if (!node0) - goto nomem; - tnode_free_append(tn, node0); - - /* populate child pointers in new nodes */ - for (k = child_length(inode), j = k / 2; j;) { - put_child(node1, --j, get_child(inode, --k)); - put_child(node0, j, get_child(inode, j)); - put_child(node1, --j, get_child(inode, --k)); - put_child(node0, j, get_child(inode, j)); - } - - /* link new nodes to parent */ - NODE_INIT_PARENT(node1, tn); - NODE_INIT_PARENT(node0, tn); - - /* link parent to nodes */ - put_child(tn, 2 * i + 1, node1); - put_child(tn, 2 * i, node0); - } - - /* setup the parent pointers into and out of this node */ - return replace(t, oldtnode, tn); -nomem: - /* all pointers should be clean so we are done */ - tnode_free(tn); -notnode: - return NULL; -} - -static struct key_vector *halve(struct trie *t, - struct key_vector *oldtnode) -{ - struct key_vector *tn; - unsigned long i; - - pr_debug("In halve\n"); - - tn = tnode_new(oldtnode->key, oldtnode->pos + 1, oldtnode->bits - 1); - if (!tn) - goto notnode; - - /* prepare oldtnode to be freed */ - tnode_free_init(oldtnode); - - /* Assemble all of the pointers in our cluster, in this case that - * represents all of the pointers out of our allocated nodes that - * point to existing tnodes and the links between our allocated - * nodes. - */ - for (i = child_length(oldtnode); i;) { - struct key_vector *node1 = get_child(oldtnode, --i); - struct key_vector *node0 = get_child(oldtnode, --i); - struct key_vector *inode; - - /* At least one of the children is empty */ - if (!node1 || !node0) { - put_child(tn, i / 2, node1 ? : node0); - continue; - } - - /* Two nonempty children */ - inode = tnode_new(node0->key, oldtnode->pos, 1); - if (!inode) - goto nomem; - tnode_free_append(tn, inode); - - /* initialize pointers out of node */ - put_child(inode, 1, node1); - put_child(inode, 0, node0); - NODE_INIT_PARENT(inode, tn); - - /* link parent to node */ - put_child(tn, i / 2, inode); - } - - /* setup the parent pointers into and out of this node */ - return replace(t, oldtnode, tn); -nomem: - /* all pointers should be clean so we are done */ - tnode_free(tn); -notnode: - return NULL; -} - -static struct key_vector *collapse(struct trie *t, - struct key_vector *oldtnode) -{ - struct key_vector *n, *tp; - unsigned long i; - - /* scan the tnode looking for that one child that might still exist */ - for (n = NULL, i = child_length(oldtnode); !n && i;) - n = get_child(oldtnode, --i); - - /* compress one level */ - tp = node_parent(oldtnode); - put_child_root(tp, oldtnode->key, n); - node_set_parent(n, tp); - - /* drop dead node */ - node_free(oldtnode); - - return tp; -} - -static unsigned char update_suffix(struct key_vector *tn) -{ - unsigned char slen = tn->pos; - unsigned long stride, i; - unsigned char slen_max; - - /* only vector 0 can have a suffix length greater than or equal to - * tn->pos + tn->bits, the second highest node will have a suffix - * length at most of tn->pos + tn->bits - 1 - */ - slen_max = min_t(unsigned char, tn->pos + tn->bits - 1, tn->slen); - - /* search though the list of children looking for nodes that might - * have a suffix greater than the one we currently have. This is - * why we start with a stride of 2 since a stride of 1 would - * represent the nodes with suffix length equal to tn->pos - */ - for (i = 0, stride = 0x2ul ; i < child_length(tn); i += stride) { - struct key_vector *n = get_child(tn, i); - - if (!n || (n->slen <= slen)) - continue; - - /* update stride and slen based on new value */ - stride <<= (n->slen - slen); - slen = n->slen; - i &= ~(stride - 1); - - /* stop searching if we have hit the maximum possible value */ - if (slen >= slen_max) - break; - } - - tn->slen = slen; - - return slen; -} - -/* From "Implementing a dynamic compressed trie" by Stefan Nilsson of - * the Helsinki University of Technology and Matti Tikkanen of Nokia - * Telecommunications, page 6: - * "A node is doubled if the ratio of non-empty children to all - * children in the *doubled* node is at least 'high'." - * - * 'high' in this instance is the variable 'inflate_threshold'. It - * is expressed as a percentage, so we multiply it with - * child_length() and instead of multiplying by 2 (since the - * child array will be doubled by inflate()) and multiplying - * the left-hand side by 100 (to handle the percentage thing) we - * multiply the left-hand side by 50. - * - * The left-hand side may look a bit weird: child_length(tn) - * - tn->empty_children is of course the number of non-null children - * in the current node. tn->full_children is the number of "full" - * children, that is non-null tnodes with a skip value of 0. - * All of those will be doubled in the resulting inflated tnode, so - * we just count them one extra time here. - * - * A clearer way to write this would be: - * - * to_be_doubled = tn->full_children; - * not_to_be_doubled = child_length(tn) - tn->empty_children - - * tn->full_children; - * - * new_child_length = child_length(tn) * 2; - * - * new_fill_factor = 100 * (not_to_be_doubled + 2*to_be_doubled) / - * new_child_length; - * if (new_fill_factor >= inflate_threshold) - * - * ...and so on, tho it would mess up the while () loop. - * - * anyway, - * 100 * (not_to_be_doubled + 2*to_be_doubled) / new_child_length >= - * inflate_threshold - * - * avoid a division: - * 100 * (not_to_be_doubled + 2*to_be_doubled) >= - * inflate_threshold * new_child_length - * - * expand not_to_be_doubled and to_be_doubled, and shorten: - * 100 * (child_length(tn) - tn->empty_children + - * tn->full_children) >= inflate_threshold * new_child_length - * - * expand new_child_length: - * 100 * (child_length(tn) - tn->empty_children + - * tn->full_children) >= - * inflate_threshold * child_length(tn) * 2 - * - * shorten again: - * 50 * (tn->full_children + child_length(tn) - - * tn->empty_children) >= inflate_threshold * - * child_length(tn) - * - */ -static inline bool should_inflate(struct key_vector *tp, struct key_vector *tn) -{ - unsigned long used = child_length(tn); - unsigned long threshold = used; - - /* Keep root node larger */ - threshold *= IS_TRIE(tp) ? inflate_threshold_root : inflate_threshold; - used -= tn_info(tn)->empty_children; - used += tn_info(tn)->full_children; - - /* if bits == KEYLENGTH then pos = 0, and will fail below */ - - return (used > 1) && tn->pos && ((50 * used) >= threshold); -} - -static inline bool should_halve(struct key_vector *tp, struct key_vector *tn) -{ - unsigned long used = child_length(tn); - unsigned long threshold = used; - - /* Keep root node larger */ - threshold *= IS_TRIE(tp) ? halve_threshold_root : halve_threshold; - used -= tn_info(tn)->empty_children; - - /* if bits == KEYLENGTH then used = 100% on wrap, and will fail below */ - - return (used > 1) && (tn->bits > 1) && ((100 * used) < threshold); -} - -static inline bool should_collapse(struct key_vector *tn) -{ - unsigned long used = child_length(tn); - - used -= tn_info(tn)->empty_children; - - /* account for bits == KEYLENGTH case */ - if ((tn->bits == KEYLENGTH) && tn_info(tn)->full_children) - used -= KEY_MAX; - - /* One child or none, time to drop us from the trie */ - return used < 2; -} - -#define MAX_WORK 10 -static struct key_vector *resize(struct trie *t, struct key_vector *tn) -{ -#ifdef CONFIG_IP_FIB_TRIE_STATS - struct trie_use_stats __percpu *stats = t->stats; -#endif - struct key_vector *tp = node_parent(tn); - unsigned long cindex = get_index(tn->key, tp); - int max_work = MAX_WORK; - - pr_debug("In tnode_resize %p inflate_threshold=%d threshold=%d\n", - tn, inflate_threshold, halve_threshold); - - /* track the tnode via the pointer from the parent instead of - * doing it ourselves. This way we can let RCU fully do its - * thing without us interfering - */ - BUG_ON(tn != get_child(tp, cindex)); - - /* Double as long as the resulting node has a number of - * nonempty nodes that are above the threshold. - */ - while (should_inflate(tp, tn) && max_work) { - tp = inflate(t, tn); - if (!tp) { -#ifdef CONFIG_IP_FIB_TRIE_STATS - this_cpu_inc(stats->resize_node_skipped); -#endif - break; - } - - max_work--; - tn = get_child(tp, cindex); - } - - /* update parent in case inflate failed */ - tp = node_parent(tn); - - /* Return if at least one inflate is run */ - if (max_work != MAX_WORK) - return tp; - - /* Halve as long as the number of empty children in this - * node is above threshold. - */ - while (should_halve(tp, tn) && max_work) { - tp = halve(t, tn); - if (!tp) { -#ifdef CONFIG_IP_FIB_TRIE_STATS - this_cpu_inc(stats->resize_node_skipped); -#endif - break; - } - - max_work--; - tn = get_child(tp, cindex); - } - - /* Only one child remains */ - if (should_collapse(tn)) - return collapse(t, tn); - - /* update parent in case halve failed */ - return node_parent(tn); -} - -static void node_pull_suffix(struct key_vector *tn, unsigned char slen) -{ - unsigned char node_slen = tn->slen; - - while ((node_slen > tn->pos) && (node_slen > slen)) { - slen = update_suffix(tn); - if (node_slen == slen) - break; - - tn = node_parent(tn); - node_slen = tn->slen; - } -} - -static void node_push_suffix(struct key_vector *tn, unsigned char slen) -{ - while (tn->slen < slen) { - tn->slen = slen; - tn = node_parent(tn); - } -} - -/* rcu_read_lock needs to be hold by caller from readside */ -static struct key_vector *fib_find_node(struct trie *t, - struct key_vector **tp, u32 key) -{ - struct key_vector *pn, *n = t->kv; - unsigned long index = 0; - - do { - pn = n; - n = get_child_rcu(n, index); - - if (!n) - break; - - index = get_cindex(key, n); - - /* This bit of code is a bit tricky but it combines multiple - * checks into a single check. The prefix consists of the - * prefix plus zeros for the bits in the cindex. The index - * is the difference between the key and this value. From - * this we can actually derive several pieces of data. - * if (index >= (1ul << bits)) - * we have a mismatch in skip bits and failed - * else - * we know the value is cindex - * - * This check is safe even if bits == KEYLENGTH due to the - * fact that we can only allocate a node with 32 bits if a - * long is greater than 32 bits. - */ - if (index >= (1ul << n->bits)) { - n = NULL; - break; - } - - /* keep searching until we find a perfect match leaf or NULL */ - } while (IS_TNODE(n)); - - *tp = pn; - - return n; -} - -/* Return the first fib alias matching TOS with - * priority less than or equal to PRIO. - */ -static struct fib_alias *fib_find_alias(struct hlist_head *fah, u8 slen, - u8 tos, u32 prio, u32 tb_id) -{ - struct fib_alias *fa; - - if (!fah) - return NULL; - - hlist_for_each_entry(fa, fah, fa_list) { - if (fa->fa_slen < slen) - continue; - if (fa->fa_slen != slen) - break; - if (fa->tb_id > tb_id) - continue; - if (fa->tb_id != tb_id) - break; - if (fa->fa_tos > tos) - continue; - if (fa->fa_info->fib_priority >= prio || fa->fa_tos < tos) - return fa; - } - - return NULL; -} - -static void trie_rebalance(struct trie *t, struct key_vector *tn) -{ - while (!IS_TRIE(tn)) - tn = resize(t, tn); -} - -static int fib_insert_node(struct trie *t, struct key_vector *tp, - struct fib_alias *new, t_key key) -{ - struct key_vector *n, *l; - - l = leaf_new(key, new); - if (!l) - goto noleaf; - - /* retrieve child from parent node */ - n = get_child(tp, get_index(key, tp)); - - /* Case 2: n is a LEAF or a TNODE and the key doesn't match. - * - * Add a new tnode here - * first tnode need some special handling - * leaves us in position for handling as case 3 - */ - if (n) { - struct key_vector *tn; - - tn = tnode_new(key, __fls(key ^ n->key), 1); - if (!tn) - goto notnode; - - /* initialize routes out of node */ - NODE_INIT_PARENT(tn, tp); - put_child(tn, get_index(key, tn) ^ 1, n); - - /* start adding routes into the node */ - put_child_root(tp, key, tn); - node_set_parent(n, tn); - - /* parent now has a NULL spot where the leaf can go */ - tp = tn; - } - - /* Case 3: n is NULL, and will just insert a new leaf */ - node_push_suffix(tp, new->fa_slen); - NODE_INIT_PARENT(l, tp); - put_child_root(tp, key, l); - trie_rebalance(t, tp); - - return 0; -notnode: - node_free(l); -noleaf: - return -ENOMEM; -} - -static int fib_insert_alias(struct trie *t, struct key_vector *tp, - struct key_vector *l, struct fib_alias *new, - struct fib_alias *fa, t_key key) -{ - if (!l) - return fib_insert_node(t, tp, new, key); - - if (fa) { - hlist_add_before_rcu(&new->fa_list, &fa->fa_list); - } else { - struct fib_alias *last; - - hlist_for_each_entry(last, &l->leaf, fa_list) { - if (new->fa_slen < last->fa_slen) - break; - if ((new->fa_slen == last->fa_slen) && - (new->tb_id > last->tb_id)) - break; - fa = last; - } - - if (fa) - hlist_add_behind_rcu(&new->fa_list, &fa->fa_list); - else - hlist_add_head_rcu(&new->fa_list, &l->leaf); - } - - /* if we added to the tail node then we need to update slen */ - if (l->slen < new->fa_slen) { - l->slen = new->fa_slen; - node_push_suffix(tp, new->fa_slen); - } - - return 0; -} - -/* Caller must hold RTNL. */ -int fib_table_insert(struct net *net, struct fib_table *tb, - struct fib_config *cfg) -{ - struct trie *t = (struct trie *)tb->tb_data; - struct fib_alias *fa, *new_fa; - struct key_vector *l, *tp; - u16 nlflags = NLM_F_EXCL; - struct fib_info *fi; - u8 plen = cfg->fc_dst_len; - u8 slen = KEYLENGTH - plen; - u8 tos = cfg->fc_tos; - u32 key; - int err; - - if (plen > KEYLENGTH) - return -EINVAL; - - key = ntohl(cfg->fc_dst); - - pr_debug("Insert table=%u %08x/%d\n", tb->tb_id, key, plen); - - if ((plen < KEYLENGTH) && (key << plen)) - return -EINVAL; - - fi = fib_create_info(cfg); - if (IS_ERR(fi)) { - err = PTR_ERR(fi); - goto err; - } - - l = fib_find_node(t, &tp, key); - fa = l ? fib_find_alias(&l->leaf, slen, tos, fi->fib_priority, - tb->tb_id) : NULL; - - /* Now fa, if non-NULL, points to the first fib alias - * with the same keys [prefix,tos,priority], if such key already - * exists or to the node before which we will insert new one. - * - * If fa is NULL, we will need to allocate a new one and - * insert to the tail of the section matching the suffix length - * of the new alias. - */ - - if (fa && fa->fa_tos == tos && - fa->fa_info->fib_priority == fi->fib_priority) { - struct fib_alias *fa_first, *fa_match; - - err = -EEXIST; - if (cfg->fc_nlflags & NLM_F_EXCL) - goto out; - - nlflags &= ~NLM_F_EXCL; - - /* We have 2 goals: - * 1. Find exact match for type, scope, fib_info to avoid - * duplicate routes - * 2. Find next 'fa' (or head), NLM_F_APPEND inserts before it - */ - fa_match = NULL; - fa_first = fa; - hlist_for_each_entry_from(fa, fa_list) { - if ((fa->fa_slen != slen) || - (fa->tb_id != tb->tb_id) || - (fa->fa_tos != tos)) - break; - if (fa->fa_info->fib_priority != fi->fib_priority) - break; - if (fa->fa_type == cfg->fc_type && - fa->fa_info == fi) { - fa_match = fa; - break; - } - } - - if (cfg->fc_nlflags & NLM_F_REPLACE) { - struct fib_info *fi_drop; - u8 state; - - nlflags |= NLM_F_REPLACE; - fa = fa_first; - if (fa_match) { - if (fa == fa_match) - err = 0; - goto out; - } - err = -ENOBUFS; - new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); - if (!new_fa) - goto out; - - fi_drop = fa->fa_info; - new_fa->fa_tos = fa->fa_tos; - new_fa->fa_info = fi; - new_fa->fa_type = cfg->fc_type; - state = fa->fa_state; - new_fa->fa_state = state & ~FA_S_ACCESSED; - new_fa->fa_slen = fa->fa_slen; - new_fa->tb_id = tb->tb_id; - new_fa->fa_default = -1; - - hlist_replace_rcu(&fa->fa_list, &new_fa->fa_list); - - alias_free_mem_rcu(fa); - - fib_release_info(fi_drop); - if (state & FA_S_ACCESSED) - rt_cache_flush(cfg->fc_nlinfo.nl_net); - - call_fib_entry_notifiers(net, FIB_EVENT_ENTRY_ADD, - key, plen, fi, - new_fa->fa_tos, cfg->fc_type, - tb->tb_id, cfg->fc_nlflags); - rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, - tb->tb_id, &cfg->fc_nlinfo, nlflags); - - goto succeeded; - } - /* Error if we find a perfect match which - * uses the same scope, type, and nexthop - * information. - */ - if (fa_match) - goto out; - - if (cfg->fc_nlflags & NLM_F_APPEND) - nlflags |= NLM_F_APPEND; - else - fa = fa_first; - } - err = -ENOENT; - if (!(cfg->fc_nlflags & NLM_F_CREATE)) - goto out; - - nlflags |= NLM_F_CREATE; - err = -ENOBUFS; - new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); - if (!new_fa) - goto out; - - new_fa->fa_info = fi; - new_fa->fa_tos = tos; - new_fa->fa_type = cfg->fc_type; - new_fa->fa_state = 0; - new_fa->fa_slen = slen; - new_fa->tb_id = tb->tb_id; - new_fa->fa_default = -1; - - /* Insert new entry to the list. */ - err = fib_insert_alias(t, tp, l, new_fa, fa, key); - if (err) - goto out_free_new_fa; - - if (!plen) - tb->tb_num_default++; - - rt_cache_flush(cfg->fc_nlinfo.nl_net); - call_fib_entry_notifiers(net, FIB_EVENT_ENTRY_ADD, key, plen, fi, tos, - cfg->fc_type, tb->tb_id, cfg->fc_nlflags); - rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, new_fa->tb_id, - &cfg->fc_nlinfo, nlflags); -succeeded: - return 0; - -out_free_new_fa: - kmem_cache_free(fn_alias_kmem, new_fa); -out: - fib_release_info(fi); -err: - return err; -} - -static inline t_key prefix_mismatch(t_key key, struct key_vector *n) -{ - t_key prefix = n->key; - - return (key ^ prefix) & (prefix | -prefix); -} - -/* should be called with rcu_read_lock */ -int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, - struct fib_result *res, int fib_flags) -{ - struct trie *t = (struct trie *) tb->tb_data; -#ifdef CONFIG_IP_FIB_TRIE_STATS - struct trie_use_stats __percpu *stats = t->stats; -#endif - const t_key key = ntohl(flp->daddr); - struct key_vector *n, *pn; - struct fib_alias *fa; - unsigned long index; - t_key cindex; - - trace_fib_table_lookup(tb->tb_id, flp); - - pn = t->kv; - cindex = 0; - - n = get_child_rcu(pn, cindex); - if (!n) - return -EAGAIN; - -#ifdef CONFIG_IP_FIB_TRIE_STATS - this_cpu_inc(stats->gets); -#endif - - /* Step 1: Travel to the longest prefix match in the trie */ - for (;;) { - index = get_cindex(key, n); - - /* This bit of code is a bit tricky but it combines multiple - * checks into a single check. The prefix consists of the - * prefix plus zeros for the "bits" in the prefix. The index - * is the difference between the key and this value. From - * this we can actually derive several pieces of data. - * if (index >= (1ul << bits)) - * we have a mismatch in skip bits and failed - * else - * we know the value is cindex - * - * This check is safe even if bits == KEYLENGTH due to the - * fact that we can only allocate a node with 32 bits if a - * long is greater than 32 bits. - */ - if (index >= (1ul << n->bits)) - break; - - /* we have found a leaf. Prefixes have already been compared */ - if (IS_LEAF(n)) - goto found; - - /* only record pn and cindex if we are going to be chopping - * bits later. Otherwise we are just wasting cycles. - */ - if (n->slen > n->pos) { - pn = n; - cindex = index; - } - - n = get_child_rcu(n, index); - if (unlikely(!n)) - goto backtrace; - } - - /* Step 2: Sort out leaves and begin backtracing for longest prefix */ - for (;;) { - /* record the pointer where our next node pointer is stored */ - struct key_vector __rcu **cptr = n->tnode; - - /* This test verifies that none of the bits that differ - * between the key and the prefix exist in the region of - * the lsb and higher in the prefix. - */ - if (unlikely(prefix_mismatch(key, n)) || (n->slen == n->pos)) - goto backtrace; - - /* exit out and process leaf */ - if (unlikely(IS_LEAF(n))) - break; - - /* Don't bother recording parent info. Since we are in - * prefix match mode we will have to come back to wherever - * we started this traversal anyway - */ - - while ((n = rcu_dereference(*cptr)) == NULL) { -backtrace: -#ifdef CONFIG_IP_FIB_TRIE_STATS - if (!n) - this_cpu_inc(stats->null_node_hit); -#endif - /* If we are at cindex 0 there are no more bits for - * us to strip at this level so we must ascend back - * up one level to see if there are any more bits to - * be stripped there. - */ - while (!cindex) { - t_key pkey = pn->key; - - /* If we don't have a parent then there is - * nothing for us to do as we do not have any - * further nodes to parse. - */ - if (IS_TRIE(pn)) - return -EAGAIN; -#ifdef CONFIG_IP_FIB_TRIE_STATS - this_cpu_inc(stats->backtrack); -#endif - /* Get Child's index */ - pn = node_parent_rcu(pn); - cindex = get_index(pkey, pn); - } - - /* strip the least significant bit from the cindex */ - cindex &= cindex - 1; - - /* grab pointer for next child node */ - cptr = &pn->tnode[cindex]; - } - } - -found: - /* this line carries forward the xor from earlier in the function */ - index = key ^ n->key; - - /* Step 3: Process the leaf, if that fails fall back to backtracing */ - hlist_for_each_entry_rcu(fa, &n->leaf, fa_list) { - struct fib_info *fi = fa->fa_info; - int nhsel, err; - - if ((BITS_PER_LONG > KEYLENGTH) || (fa->fa_slen < KEYLENGTH)) { - if (index >= (1ul << fa->fa_slen)) - continue; - } - if (fa->fa_tos && fa->fa_tos != flp->flowi4_tos) - continue; - if (fi->fib_dead) - continue; - if (fa->fa_info->fib_scope < flp->flowi4_scope) - continue; - fib_alias_accessed(fa); - err = fib_props[fa->fa_type].error; - if (unlikely(err < 0)) { -#ifdef CONFIG_IP_FIB_TRIE_STATS - this_cpu_inc(stats->semantic_match_passed); -#endif - return err; - } - if (fi->fib_flags & RTNH_F_DEAD) - continue; - for (nhsel = 0; nhsel < fi->fib_nhs; nhsel++) { - const struct fib_nh *nh = &fi->fib_nh[nhsel]; - struct in_device *in_dev = __in_dev_get_rcu(nh->nh_dev); - - if (nh->nh_flags & RTNH_F_DEAD) - continue; - if (in_dev && - IN_DEV_IGNORE_ROUTES_WITH_LINKDOWN(in_dev) && - nh->nh_flags & RTNH_F_LINKDOWN && - !(fib_flags & FIB_LOOKUP_IGNORE_LINKSTATE)) - continue; - if (!(flp->flowi4_flags & FLOWI_FLAG_SKIP_NH_OIF)) { - if (flp->flowi4_oif && - flp->flowi4_oif != nh->nh_oif) - continue; - } - - if (!(fib_flags & FIB_LOOKUP_NOREF)) - atomic_inc(&fi->fib_clntref); - - res->prefixlen = KEYLENGTH - fa->fa_slen; - res->nh_sel = nhsel; - res->type = fa->fa_type; - res->scope = fi->fib_scope; - res->fi = fi; - res->table = tb; - res->fa_head = &n->leaf; -#ifdef CONFIG_IP_FIB_TRIE_STATS - this_cpu_inc(stats->semantic_match_passed); -#endif - trace_fib_table_lookup_nh(nh); - - return err; - } - } -#ifdef CONFIG_IP_FIB_TRIE_STATS - this_cpu_inc(stats->semantic_match_miss); -#endif - goto backtrace; -} -EXPORT_SYMBOL_GPL(fib_table_lookup); - -static void fib_remove_alias(struct trie *t, struct key_vector *tp, - struct key_vector *l, struct fib_alias *old) -{ - /* record the location of the previous list_info entry */ - struct hlist_node **pprev = old->fa_list.pprev; - struct fib_alias *fa = hlist_entry(pprev, typeof(*fa), fa_list.next); - - /* remove the fib_alias from the list */ - hlist_del_rcu(&old->fa_list); - - /* if we emptied the list this leaf will be freed and we can sort - * out parent suffix lengths as a part of trie_rebalance - */ - if (hlist_empty(&l->leaf)) { - if (tp->slen == l->slen) - node_pull_suffix(tp, tp->pos); - put_child_root(tp, l->key, NULL); - node_free(l); - trie_rebalance(t, tp); - return; - } - - /* only access fa if it is pointing at the last valid hlist_node */ - if (*pprev) - return; - - /* update the trie with the latest suffix length */ - l->slen = fa->fa_slen; - node_pull_suffix(tp, fa->fa_slen); -} - -/* Caller must hold RTNL. */ -int fib_table_delete(struct net *net, struct fib_table *tb, - struct fib_config *cfg) -{ - struct trie *t = (struct trie *) tb->tb_data; - struct fib_alias *fa, *fa_to_delete; - struct key_vector *l, *tp; - u8 plen = cfg->fc_dst_len; - u8 slen = KEYLENGTH - plen; - u8 tos = cfg->fc_tos; - u32 key; - - if (plen > KEYLENGTH) - return -EINVAL; - - key = ntohl(cfg->fc_dst); - - if ((plen < KEYLENGTH) && (key << plen)) - return -EINVAL; - - l = fib_find_node(t, &tp, key); - if (!l) - return -ESRCH; - - fa = fib_find_alias(&l->leaf, slen, tos, 0, tb->tb_id); - if (!fa) - return -ESRCH; - - pr_debug("Deleting %08x/%d tos=%d t=%p\n", key, plen, tos, t); - - fa_to_delete = NULL; - hlist_for_each_entry_from(fa, fa_list) { - struct fib_info *fi = fa->fa_info; - - if ((fa->fa_slen != slen) || - (fa->tb_id != tb->tb_id) || - (fa->fa_tos != tos)) - break; - - if ((!cfg->fc_type || fa->fa_type == cfg->fc_type) && - (cfg->fc_scope == RT_SCOPE_NOWHERE || - fa->fa_info->fib_scope == cfg->fc_scope) && - (!cfg->fc_prefsrc || - fi->fib_prefsrc == cfg->fc_prefsrc) && - (!cfg->fc_protocol || - fi->fib_protocol == cfg->fc_protocol) && - fib_nh_match(cfg, fi) == 0) { - fa_to_delete = fa; - break; - } - } - - if (!fa_to_delete) - return -ESRCH; - - call_fib_entry_notifiers(net, FIB_EVENT_ENTRY_DEL, key, plen, - fa_to_delete->fa_info, tos, cfg->fc_type, - tb->tb_id, 0); - rtmsg_fib(RTM_DELROUTE, htonl(key), fa_to_delete, plen, tb->tb_id, - &cfg->fc_nlinfo, 0); - - if (!plen) - tb->tb_num_default--; - - fib_remove_alias(t, tp, l, fa_to_delete); - - if (fa_to_delete->fa_state & FA_S_ACCESSED) - rt_cache_flush(cfg->fc_nlinfo.nl_net); - - fib_release_info(fa_to_delete->fa_info); - alias_free_mem_rcu(fa_to_delete); - return 0; -} - -/* Scan for the next leaf starting at the provided key value */ -static struct key_vector *leaf_walk_rcu(struct key_vector **tn, t_key key) -{ - struct key_vector *pn, *n = *tn; - unsigned long cindex; - - /* this loop is meant to try and find the key in the trie */ - do { - /* record parent and next child index */ - pn = n; - cindex = (key > pn->key) ? get_index(key, pn) : 0; - - if (cindex >> pn->bits) - break; - - /* descend into the next child */ - n = get_child_rcu(pn, cindex++); - if (!n) - break; - - /* guarantee forward progress on the keys */ - if (IS_LEAF(n) && (n->key >= key)) - goto found; - } while (IS_TNODE(n)); - - /* this loop will search for the next leaf with a greater key */ - while (!IS_TRIE(pn)) { - /* if we exhausted the parent node we will need to climb */ - if (cindex >= (1ul << pn->bits)) { - t_key pkey = pn->key; - - pn = node_parent_rcu(pn); - cindex = get_index(pkey, pn) + 1; - continue; - } - - /* grab the next available node */ - n = get_child_rcu(pn, cindex++); - if (!n) - continue; - - /* no need to compare keys since we bumped the index */ - if (IS_LEAF(n)) - goto found; - - /* Rescan start scanning in new node */ - pn = n; - cindex = 0; - } - - *tn = pn; - return NULL; /* Root of trie */ -found: - /* if we are at the limit for keys just return NULL for the tnode */ - *tn = pn; - return n; -} - -static void fib_trie_free(struct fib_table *tb) -{ - struct trie *t = (struct trie *)tb->tb_data; - struct key_vector *pn = t->kv; - unsigned long cindex = 1; - struct hlist_node *tmp; - struct fib_alias *fa; - - /* walk trie in reverse order and free everything */ - for (;;) { - struct key_vector *n; - - if (!(cindex--)) { - t_key pkey = pn->key; - - if (IS_TRIE(pn)) - break; - - n = pn; - pn = node_parent(pn); - - /* drop emptied tnode */ - put_child_root(pn, n->key, NULL); - node_free(n); - - cindex = get_index(pkey, pn); - - continue; - } - - /* grab the next available node */ - n = get_child(pn, cindex); - if (!n) - continue; - - if (IS_TNODE(n)) { - /* record pn and cindex for leaf walking */ - pn = n; - cindex = 1ul << n->bits; - - continue; - } - - hlist_for_each_entry_safe(fa, tmp, &n->leaf, fa_list) { - hlist_del_rcu(&fa->fa_list); - alias_free_mem_rcu(fa); - } - - put_child_root(pn, n->key, NULL); - node_free(n); - } - -#ifdef CONFIG_IP_FIB_TRIE_STATS - free_percpu(t->stats); -#endif - kfree(tb); -} - -struct fib_table *fib_trie_unmerge(struct fib_table *oldtb) -{ - struct trie *ot = (struct trie *)oldtb->tb_data; - struct key_vector *l, *tp = ot->kv; - struct fib_table *local_tb; - struct fib_alias *fa; - struct trie *lt; - t_key key = 0; - - if (oldtb->tb_data == oldtb->__data) - return oldtb; - - local_tb = fib_trie_table(RT_TABLE_LOCAL, NULL); - if (!local_tb) - return NULL; - - lt = (struct trie *)local_tb->tb_data; - - while ((l = leaf_walk_rcu(&tp, key)) != NULL) { - struct key_vector *local_l = NULL, *local_tp; - - hlist_for_each_entry_rcu(fa, &l->leaf, fa_list) { - struct fib_alias *new_fa; - - if (local_tb->tb_id != fa->tb_id) - continue; - - /* clone fa for new local table */ - new_fa = kmem_cache_alloc(fn_alias_kmem, GFP_KERNEL); - if (!new_fa) - goto out; - - memcpy(new_fa, fa, sizeof(*fa)); - - /* insert clone into table */ - if (!local_l) - local_l = fib_find_node(lt, &local_tp, l->key); - - if (fib_insert_alias(lt, local_tp, local_l, new_fa, - NULL, l->key)) { - kmem_cache_free(fn_alias_kmem, new_fa); - goto out; - } - } - - /* stop loop if key wrapped back to 0 */ - key = l->key + 1; - if (key < l->key) - break; - } - - return local_tb; -out: - fib_trie_free(local_tb); - - return NULL; -} - -/* Caller must hold RTNL */ -void fib_table_flush_external(struct fib_table *tb) -{ - struct trie *t = (struct trie *)tb->tb_data; - struct key_vector *pn = t->kv; - unsigned long cindex = 1; - struct hlist_node *tmp; - struct fib_alias *fa; - - /* walk trie in reverse order */ - for (;;) { - unsigned char slen = 0; - struct key_vector *n; - - if (!(cindex--)) { - t_key pkey = pn->key; - - /* cannot resize the trie vector */ - if (IS_TRIE(pn)) - break; - - /* update the suffix to address pulled leaves */ - if (pn->slen > pn->pos) - update_suffix(pn); - - /* resize completed node */ - pn = resize(t, pn); - cindex = get_index(pkey, pn); - - continue; - } - - /* grab the next available node */ - n = get_child(pn, cindex); - if (!n) - continue; - - if (IS_TNODE(n)) { - /* record pn and cindex for leaf walking */ - pn = n; - cindex = 1ul << n->bits; - - continue; - } - - hlist_for_each_entry_safe(fa, tmp, &n->leaf, fa_list) { - /* if alias was cloned to local then we just - * need to remove the local copy from main - */ - if (tb->tb_id != fa->tb_id) { - hlist_del_rcu(&fa->fa_list); - alias_free_mem_rcu(fa); - continue; - } - - /* record local slen */ - slen = fa->fa_slen; - } - - /* update leaf slen */ - n->slen = slen; - - if (hlist_empty(&n->leaf)) { - put_child_root(pn, n->key, NULL); - node_free(n); - } - } -} - -/* Caller must hold RTNL. */ -int fib_table_flush(struct net *net, struct fib_table *tb) -{ - struct trie *t = (struct trie *)tb->tb_data; - struct key_vector *pn = t->kv; - unsigned long cindex = 1; - struct hlist_node *tmp; - struct fib_alias *fa; - int found = 0; - - /* walk trie in reverse order */ - for (;;) { - unsigned char slen = 0; - struct key_vector *n; - - if (!(cindex--)) { - t_key pkey = pn->key; - - /* cannot resize the trie vector */ - if (IS_TRIE(pn)) - break; - - /* update the suffix to address pulled leaves */ - if (pn->slen > pn->pos) - update_suffix(pn); - - /* resize completed node */ - pn = resize(t, pn); - cindex = get_index(pkey, pn); - - continue; - } - - /* grab the next available node */ - n = get_child(pn, cindex); - if (!n) - continue; - - if (IS_TNODE(n)) { - /* record pn and cindex for leaf walking */ - pn = n; - cindex = 1ul << n->bits; - - continue; - } - - hlist_for_each_entry_safe(fa, tmp, &n->leaf, fa_list) { - struct fib_info *fi = fa->fa_info; - - if (!fi || !(fi->fib_flags & RTNH_F_DEAD)) { - slen = fa->fa_slen; - continue; - } - - call_fib_entry_notifiers(net, FIB_EVENT_ENTRY_DEL, - n->key, - KEYLENGTH - fa->fa_slen, - fi, fa->fa_tos, fa->fa_type, - tb->tb_id, 0); - hlist_del_rcu(&fa->fa_list); - fib_release_info(fa->fa_info); - alias_free_mem_rcu(fa); - found++; - } - - /* update leaf slen */ - n->slen = slen; - - if (hlist_empty(&n->leaf)) { - put_child_root(pn, n->key, NULL); - node_free(n); - } - } - - pr_debug("trie_flush found=%d\n", found); - return found; -} - -static void __trie_free_rcu(struct rcu_head *head) -{ - struct fib_table *tb = container_of(head, struct fib_table, rcu); -#ifdef CONFIG_IP_FIB_TRIE_STATS - struct trie *t = (struct trie *)tb->tb_data; - - if (tb->tb_data == tb->__data) - free_percpu(t->stats); -#endif /* CONFIG_IP_FIB_TRIE_STATS */ - kfree(tb); -} - -void fib_free_table(struct fib_table *tb) -{ - call_rcu(&tb->rcu, __trie_free_rcu); -} - -static int fn_trie_dump_leaf(struct key_vector *l, struct fib_table *tb, - struct sk_buff *skb, struct netlink_callback *cb) -{ - __be32 xkey = htonl(l->key); - struct fib_alias *fa; - int i, s_i; - - s_i = cb->args[4]; - i = 0; - - /* rcu_read_lock is hold by caller */ - hlist_for_each_entry_rcu(fa, &l->leaf, fa_list) { - if (i < s_i) { - i++; - continue; - } - - if (tb->tb_id != fa->tb_id) { - i++; - continue; - } - - if (fib_dump_info(skb, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWROUTE, - tb->tb_id, - fa->fa_type, - xkey, - KEYLENGTH - fa->fa_slen, - fa->fa_tos, - fa->fa_info, NLM_F_MULTI) < 0) { - cb->args[4] = i; - return -1; - } - i++; - } - - cb->args[4] = i; - return skb->len; -} - -/* rcu_read_lock needs to be hold by caller from readside */ -int fib_table_dump(struct fib_table *tb, struct sk_buff *skb, - struct netlink_callback *cb) -{ - struct trie *t = (struct trie *)tb->tb_data; - struct key_vector *l, *tp = t->kv; - /* Dump starting at last key. - * Note: 0.0.0.0/0 (ie default) is first key. - */ - int count = cb->args[2]; - t_key key = cb->args[3]; - - while ((l = leaf_walk_rcu(&tp, key)) != NULL) { - if (fn_trie_dump_leaf(l, tb, skb, cb) < 0) { - cb->args[3] = key; - cb->args[2] = count; - return -1; - } - - ++count; - key = l->key + 1; - - memset(&cb->args[4], 0, - sizeof(cb->args) - 4*sizeof(cb->args[0])); - - /* stop loop if key wrapped back to 0 */ - if (key < l->key) - break; - } - - cb->args[3] = key; - cb->args[2] = count; - - return skb->len; -} - -void __init fib_trie_init(void) -{ - fn_alias_kmem = kmem_cache_create("ip_fib_alias", - sizeof(struct fib_alias), - 0, SLAB_PANIC, NULL); - - trie_leaf_kmem = kmem_cache_create("ip_fib_trie", - LEAF_SIZE, - 0, SLAB_PANIC, NULL); -} - -struct fib_table *fib_trie_table(u32 id, struct fib_table *alias) -{ - struct fib_table *tb; - struct trie *t; - size_t sz = sizeof(*tb); - - if (!alias) - sz += sizeof(struct trie); - - tb = kzalloc(sz, GFP_KERNEL); - if (!tb) - return NULL; - - tb->tb_id = id; - tb->tb_num_default = 0; - tb->tb_data = (alias ? alias->__data : tb->__data); - - if (alias) - return tb; - - t = (struct trie *) tb->tb_data; - t->kv[0].pos = KEYLENGTH; - t->kv[0].slen = KEYLENGTH; -#ifdef CONFIG_IP_FIB_TRIE_STATS - t->stats = alloc_percpu(struct trie_use_stats); - if (!t->stats) { - kfree(tb); - tb = NULL; - } -#endif - - return tb; -} - -#ifdef CONFIG_PROC_FS -/* Depth first Trie walk iterator */ -struct fib_trie_iter { - struct seq_net_private p; - struct fib_table *tb; - struct key_vector *tnode; - unsigned int index; - unsigned int depth; -}; - -static struct key_vector *fib_trie_get_next(struct fib_trie_iter *iter) -{ - unsigned long cindex = iter->index; - struct key_vector *pn = iter->tnode; - t_key pkey; - - pr_debug("get_next iter={node=%p index=%d depth=%d}\n", - iter->tnode, iter->index, iter->depth); - - while (!IS_TRIE(pn)) { - while (cindex < child_length(pn)) { - struct key_vector *n = get_child_rcu(pn, cindex++); - - if (!n) - continue; - - if (IS_LEAF(n)) { - iter->tnode = pn; - iter->index = cindex; - } else { - /* push down one level */ - iter->tnode = n; - iter->index = 0; - ++iter->depth; - } - - return n; - } - - /* Current node exhausted, pop back up */ - pkey = pn->key; - pn = node_parent_rcu(pn); - cindex = get_index(pkey, pn) + 1; - --iter->depth; - } - - /* record root node so further searches know we are done */ - iter->tnode = pn; - iter->index = 0; - - return NULL; -} - -static struct key_vector *fib_trie_get_first(struct fib_trie_iter *iter, - struct trie *t) -{ - struct key_vector *n, *pn; - - if (!t) - return NULL; - - pn = t->kv; - n = rcu_dereference(pn->tnode[0]); - if (!n) - return NULL; - - if (IS_TNODE(n)) { - iter->tnode = n; - iter->index = 0; - iter->depth = 1; - } else { - iter->tnode = pn; - iter->index = 0; - iter->depth = 0; - } - - return n; -} - -static void trie_collect_stats(struct trie *t, struct trie_stat *s) -{ - struct key_vector *n; - struct fib_trie_iter iter; - - memset(s, 0, sizeof(*s)); - - rcu_read_lock(); - for (n = fib_trie_get_first(&iter, t); n; n = fib_trie_get_next(&iter)) { - if (IS_LEAF(n)) { - struct fib_alias *fa; - - s->leaves++; - s->totdepth += iter.depth; - if (iter.depth > s->maxdepth) - s->maxdepth = iter.depth; - - hlist_for_each_entry_rcu(fa, &n->leaf, fa_list) - ++s->prefixes; - } else { - s->tnodes++; - if (n->bits < MAX_STAT_DEPTH) - s->nodesizes[n->bits]++; - s->nullpointers += tn_info(n)->empty_children; - } - } - rcu_read_unlock(); -} - -/* - * This outputs /proc/net/fib_triestats - */ -static void trie_show_stats(struct seq_file *seq, struct trie_stat *stat) -{ - unsigned int i, max, pointers, bytes, avdepth; - - if (stat->leaves) - avdepth = stat->totdepth*100 / stat->leaves; - else - avdepth = 0; - - seq_printf(seq, "\tAver depth: %u.%02d\n", - avdepth / 100, avdepth % 100); - seq_printf(seq, "\tMax depth: %u\n", stat->maxdepth); - - seq_printf(seq, "\tLeaves: %u\n", stat->leaves); - bytes = LEAF_SIZE * stat->leaves; - - seq_printf(seq, "\tPrefixes: %u\n", stat->prefixes); - bytes += sizeof(struct fib_alias) * stat->prefixes; - - seq_printf(seq, "\tInternal nodes: %u\n\t", stat->tnodes); - bytes += TNODE_SIZE(0) * stat->tnodes; - - max = MAX_STAT_DEPTH; - while (max > 0 && stat->nodesizes[max-1] == 0) - max--; - - pointers = 0; - for (i = 1; i < max; i++) - if (stat->nodesizes[i] != 0) { - seq_printf(seq, " %u: %u", i, stat->nodesizes[i]); - pointers += (1<nodesizes[i]; - } - seq_putc(seq, '\n'); - seq_printf(seq, "\tPointers: %u\n", pointers); - - bytes += sizeof(struct key_vector *) * pointers; - seq_printf(seq, "Null ptrs: %u\n", stat->nullpointers); - seq_printf(seq, "Total size: %u kB\n", (bytes + 1023) / 1024); -} - -#ifdef CONFIG_IP_FIB_TRIE_STATS -static void trie_show_usage(struct seq_file *seq, - const struct trie_use_stats __percpu *stats) -{ - struct trie_use_stats s = { 0 }; - int cpu; - - /* loop through all of the CPUs and gather up the stats */ - for_each_possible_cpu(cpu) { - const struct trie_use_stats *pcpu = per_cpu_ptr(stats, cpu); - - s.gets += pcpu->gets; - s.backtrack += pcpu->backtrack; - s.semantic_match_passed += pcpu->semantic_match_passed; - s.semantic_match_miss += pcpu->semantic_match_miss; - s.null_node_hit += pcpu->null_node_hit; - s.resize_node_skipped += pcpu->resize_node_skipped; - } - - seq_printf(seq, "\nCounters:\n---------\n"); - seq_printf(seq, "gets = %u\n", s.gets); - seq_printf(seq, "backtracks = %u\n", s.backtrack); - seq_printf(seq, "semantic match passed = %u\n", - s.semantic_match_passed); - seq_printf(seq, "semantic match miss = %u\n", s.semantic_match_miss); - seq_printf(seq, "null node hit= %u\n", s.null_node_hit); - seq_printf(seq, "skipped node resize = %u\n\n", s.resize_node_skipped); -} -#endif /* CONFIG_IP_FIB_TRIE_STATS */ - -static void fib_table_print(struct seq_file *seq, struct fib_table *tb) -{ - if (tb->tb_id == RT_TABLE_LOCAL) - seq_puts(seq, "Local:\n"); - else if (tb->tb_id == RT_TABLE_MAIN) - seq_puts(seq, "Main:\n"); - else - seq_printf(seq, "Id %d:\n", tb->tb_id); -} - - -static int fib_triestat_seq_show(struct seq_file *seq, void *v) -{ - struct net *net = (struct net *)seq->private; - unsigned int h; - - seq_printf(seq, - "Basic info: size of leaf:" - " %Zd bytes, size of tnode: %Zd bytes.\n", - LEAF_SIZE, TNODE_SIZE(0)); - - for (h = 0; h < FIB_TABLE_HASHSZ; h++) { - struct hlist_head *head = &net->ipv4.fib_table_hash[h]; - struct fib_table *tb; - - hlist_for_each_entry_rcu(tb, head, tb_hlist) { - struct trie *t = (struct trie *) tb->tb_data; - struct trie_stat stat; - - if (!t) - continue; - - fib_table_print(seq, tb); - - trie_collect_stats(t, &stat); - trie_show_stats(seq, &stat); -#ifdef CONFIG_IP_FIB_TRIE_STATS - trie_show_usage(seq, t->stats); -#endif - } - } - - return 0; -} - -static int fib_triestat_seq_open(struct inode *inode, struct file *file) -{ - return single_open_net(inode, file, fib_triestat_seq_show); -} - -static const struct file_operations fib_triestat_fops = { - .owner = THIS_MODULE, - .open = fib_triestat_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release_net, -}; - -static struct key_vector *fib_trie_get_idx(struct seq_file *seq, loff_t pos) -{ - struct fib_trie_iter *iter = seq->private; - struct net *net = seq_file_net(seq); - loff_t idx = 0; - unsigned int h; - - for (h = 0; h < FIB_TABLE_HASHSZ; h++) { - struct hlist_head *head = &net->ipv4.fib_table_hash[h]; - struct fib_table *tb; - - hlist_for_each_entry_rcu(tb, head, tb_hlist) { - struct key_vector *n; - - for (n = fib_trie_get_first(iter, - (struct trie *) tb->tb_data); - n; n = fib_trie_get_next(iter)) - if (pos == idx++) { - iter->tb = tb; - return n; - } - } - } - - return NULL; -} - -static void *fib_trie_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(RCU) -{ - rcu_read_lock(); - return fib_trie_get_idx(seq, *pos); -} - -static void *fib_trie_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct fib_trie_iter *iter = seq->private; - struct net *net = seq_file_net(seq); - struct fib_table *tb = iter->tb; - struct hlist_node *tb_node; - unsigned int h; - struct key_vector *n; - - ++*pos; - /* next node in same table */ - n = fib_trie_get_next(iter); - if (n) - return n; - - /* walk rest of this hash chain */ - h = tb->tb_id & (FIB_TABLE_HASHSZ - 1); - while ((tb_node = rcu_dereference(hlist_next_rcu(&tb->tb_hlist)))) { - tb = hlist_entry(tb_node, struct fib_table, tb_hlist); - n = fib_trie_get_first(iter, (struct trie *) tb->tb_data); - if (n) - goto found; - } - - /* new hash chain */ - while (++h < FIB_TABLE_HASHSZ) { - struct hlist_head *head = &net->ipv4.fib_table_hash[h]; - hlist_for_each_entry_rcu(tb, head, tb_hlist) { - n = fib_trie_get_first(iter, (struct trie *) tb->tb_data); - if (n) - goto found; - } - } - return NULL; - -found: - iter->tb = tb; - return n; -} - -static void fib_trie_seq_stop(struct seq_file *seq, void *v) - __releases(RCU) -{ - rcu_read_unlock(); -} - -static void seq_indent(struct seq_file *seq, int n) -{ - while (n-- > 0) - seq_puts(seq, " "); -} - -static inline const char *rtn_scope(char *buf, size_t len, enum rt_scope_t s) -{ - switch (s) { - case RT_SCOPE_UNIVERSE: return "universe"; - case RT_SCOPE_SITE: return "site"; - case RT_SCOPE_LINK: return "link"; - case RT_SCOPE_HOST: return "host"; - case RT_SCOPE_NOWHERE: return "nowhere"; - default: - snprintf(buf, len, "scope=%d", s); - return buf; - } -} - -static const char *const rtn_type_names[__RTN_MAX] = { - [RTN_UNSPEC] = "UNSPEC", - [RTN_UNICAST] = "UNICAST", - [RTN_LOCAL] = "LOCAL", - [RTN_BROADCAST] = "BROADCAST", - [RTN_ANYCAST] = "ANYCAST", - [RTN_MULTICAST] = "MULTICAST", - [RTN_BLACKHOLE] = "BLACKHOLE", - [RTN_UNREACHABLE] = "UNREACHABLE", - [RTN_PROHIBIT] = "PROHIBIT", - [RTN_THROW] = "THROW", - [RTN_NAT] = "NAT", - [RTN_XRESOLVE] = "XRESOLVE", -}; - -static inline const char *rtn_type(char *buf, size_t len, unsigned int t) -{ - if (t < __RTN_MAX && rtn_type_names[t]) - return rtn_type_names[t]; - snprintf(buf, len, "type %u", t); - return buf; -} - -/* Pretty print the trie */ -static int fib_trie_seq_show(struct seq_file *seq, void *v) -{ - const struct fib_trie_iter *iter = seq->private; - struct key_vector *n = v; - - if (IS_TRIE(node_parent_rcu(n))) - fib_table_print(seq, iter->tb); - - if (IS_TNODE(n)) { - __be32 prf = htonl(n->key); - - seq_indent(seq, iter->depth-1); - seq_printf(seq, " +-- %pI4/%zu %u %u %u\n", - &prf, KEYLENGTH - n->pos - n->bits, n->bits, - tn_info(n)->full_children, - tn_info(n)->empty_children); - } else { - __be32 val = htonl(n->key); - struct fib_alias *fa; - - seq_indent(seq, iter->depth); - seq_printf(seq, " |-- %pI4\n", &val); - - hlist_for_each_entry_rcu(fa, &n->leaf, fa_list) { - char buf1[32], buf2[32]; - - seq_indent(seq, iter->depth + 1); - seq_printf(seq, " /%zu %s %s", - KEYLENGTH - fa->fa_slen, - rtn_scope(buf1, sizeof(buf1), - fa->fa_info->fib_scope), - rtn_type(buf2, sizeof(buf2), - fa->fa_type)); - if (fa->fa_tos) - seq_printf(seq, " tos=%d", fa->fa_tos); - seq_putc(seq, '\n'); - } - } - - return 0; -} - -static const struct seq_operations fib_trie_seq_ops = { - .start = fib_trie_seq_start, - .next = fib_trie_seq_next, - .stop = fib_trie_seq_stop, - .show = fib_trie_seq_show, -}; - -static int fib_trie_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &fib_trie_seq_ops, - sizeof(struct fib_trie_iter)); -} - -static const struct file_operations fib_trie_fops = { - .owner = THIS_MODULE, - .open = fib_trie_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -struct fib_route_iter { - struct seq_net_private p; - struct fib_table *main_tb; - struct key_vector *tnode; - loff_t pos; - t_key key; -}; - -static struct key_vector *fib_route_get_idx(struct fib_route_iter *iter, - loff_t pos) -{ - struct key_vector *l, **tp = &iter->tnode; - t_key key; - - /* use cached location of previously found key */ - if (iter->pos > 0 && pos >= iter->pos) { - key = iter->key; - } else { - iter->pos = 1; - key = 0; - } - - pos -= iter->pos; - - while ((l = leaf_walk_rcu(tp, key)) && (pos-- > 0)) { - key = l->key + 1; - iter->pos++; - l = NULL; - - /* handle unlikely case of a key wrap */ - if (!key) - break; - } - - if (l) - iter->key = l->key; /* remember it */ - else - iter->pos = 0; /* forget it */ - - return l; -} - -static void *fib_route_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(RCU) -{ - struct fib_route_iter *iter = seq->private; - struct fib_table *tb; - struct trie *t; - - rcu_read_lock(); - - tb = fib_get_table(seq_file_net(seq), RT_TABLE_MAIN); - if (!tb) - return NULL; - - iter->main_tb = tb; - t = (struct trie *)tb->tb_data; - iter->tnode = t->kv; - - if (*pos != 0) - return fib_route_get_idx(iter, *pos); - - iter->pos = 0; - iter->key = KEY_MAX; - - return SEQ_START_TOKEN; -} - -static void *fib_route_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct fib_route_iter *iter = seq->private; - struct key_vector *l = NULL; - t_key key = iter->key + 1; - - ++*pos; - - /* only allow key of 0 for start of sequence */ - if ((v == SEQ_START_TOKEN) || key) - l = leaf_walk_rcu(&iter->tnode, key); - - if (l) { - iter->key = l->key; - iter->pos++; - } else { - iter->pos = 0; - } - - return l; -} - -static void fib_route_seq_stop(struct seq_file *seq, void *v) - __releases(RCU) -{ - rcu_read_unlock(); -} - -static unsigned int fib_flag_trans(int type, __be32 mask, const struct fib_info *fi) -{ - unsigned int flags = 0; - - if (type == RTN_UNREACHABLE || type == RTN_PROHIBIT) - flags = RTF_REJECT; - if (fi && fi->fib_nh->nh_gw) - flags |= RTF_GATEWAY; - if (mask == htonl(0xFFFFFFFF)) - flags |= RTF_HOST; - flags |= RTF_UP; - return flags; -} - -/* - * This outputs /proc/net/route. - * The format of the file is not supposed to be changed - * and needs to be same as fib_hash output to avoid breaking - * legacy utilities - */ -static int fib_route_seq_show(struct seq_file *seq, void *v) -{ - struct fib_route_iter *iter = seq->private; - struct fib_table *tb = iter->main_tb; - struct fib_alias *fa; - struct key_vector *l = v; - __be32 prefix; - - if (v == SEQ_START_TOKEN) { - seq_printf(seq, "%-127s\n", "Iface\tDestination\tGateway " - "\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU" - "\tWindow\tIRTT"); - return 0; - } - - prefix = htonl(l->key); - - hlist_for_each_entry_rcu(fa, &l->leaf, fa_list) { - const struct fib_info *fi = fa->fa_info; - __be32 mask = inet_make_mask(KEYLENGTH - fa->fa_slen); - unsigned int flags = fib_flag_trans(fa->fa_type, mask, fi); - - if ((fa->fa_type == RTN_BROADCAST) || - (fa->fa_type == RTN_MULTICAST)) - continue; - - if (fa->tb_id != tb->tb_id) - continue; - - seq_setwidth(seq, 127); - - if (fi) - seq_printf(seq, - "%s\t%08X\t%08X\t%04X\t%d\t%u\t" - "%d\t%08X\t%d\t%u\t%u", - fi->fib_dev ? fi->fib_dev->name : "*", - prefix, - fi->fib_nh->nh_gw, flags, 0, 0, - fi->fib_priority, - mask, - (fi->fib_advmss ? - fi->fib_advmss + 40 : 0), - fi->fib_window, - fi->fib_rtt >> 3); - else - seq_printf(seq, - "*\t%08X\t%08X\t%04X\t%d\t%u\t" - "%d\t%08X\t%d\t%u\t%u", - prefix, 0, flags, 0, 0, 0, - mask, 0, 0, 0); - - seq_pad(seq, '\n'); - } - - return 0; -} - -static const struct seq_operations fib_route_seq_ops = { - .start = fib_route_seq_start, - .next = fib_route_seq_next, - .stop = fib_route_seq_stop, - .show = fib_route_seq_show, -}; - -static int fib_route_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &fib_route_seq_ops, - sizeof(struct fib_route_iter)); -} - -static const struct file_operations fib_route_fops = { - .owner = THIS_MODULE, - .open = fib_route_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -int __net_init fib_proc_init(struct net *net) -{ - if (!proc_create("fib_trie", S_IRUGO, net->proc_net, &fib_trie_fops)) - goto out1; - - if (!proc_create("fib_triestat", S_IRUGO, net->proc_net, - &fib_triestat_fops)) - goto out2; - - if (!proc_create("route", S_IRUGO, net->proc_net, &fib_route_fops)) - goto out3; - - return 0; - -out3: - remove_proc_entry("fib_triestat", net->proc_net); -out2: - remove_proc_entry("fib_trie", net->proc_net); -out1: - return -ENOMEM; -} - -void __net_exit fib_proc_exit(struct net *net) -{ - remove_proc_entry("fib_trie", net->proc_net); - remove_proc_entry("fib_triestat", net->proc_net); - remove_proc_entry("route", net->proc_net); -} - -#endif /* CONFIG_PROC_FS */ diff --git a/src/linux/net/ipv4/gre_offload.c b/src/linux/net/ipv4/gre_offload.c deleted file mode 100644 index d5cac99..0000000 --- a/src/linux/net/ipv4/gre_offload.c +++ /dev/null @@ -1,297 +0,0 @@ -/* - * IPV4 GSO/GRO offload support - * Linux INET implementation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * GRE GSO support - */ - -#include -#include -#include -#include - -static struct sk_buff *gre_gso_segment(struct sk_buff *skb, - netdev_features_t features) -{ - int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb); - struct sk_buff *segs = ERR_PTR(-EINVAL); - u16 mac_offset = skb->mac_header; - __be16 protocol = skb->protocol; - u16 mac_len = skb->mac_len; - int gre_offset, outer_hlen; - bool need_csum, ufo, gso_partial; - - if (!skb->encapsulation) - goto out; - - if (unlikely(tnl_hlen < sizeof(struct gre_base_hdr))) - goto out; - - if (unlikely(!pskb_may_pull(skb, tnl_hlen))) - goto out; - - /* setup inner skb. */ - skb->encapsulation = 0; - SKB_GSO_CB(skb)->encap_level = 0; - __skb_pull(skb, tnl_hlen); - skb_reset_mac_header(skb); - skb_set_network_header(skb, skb_inner_network_offset(skb)); - skb->mac_len = skb_inner_network_offset(skb); - skb->protocol = skb->inner_protocol; - - need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_GRE_CSUM); - skb->encap_hdr_csum = need_csum; - - ufo = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP); - - features &= skb->dev->hw_enc_features; - - /* The only checksum offload we care about from here on out is the - * outer one so strip the existing checksum feature flags based - * on the fact that we will be computing our checksum in software. - */ - if (ufo) { - features &= ~NETIF_F_CSUM_MASK; - if (!need_csum) - features |= NETIF_F_HW_CSUM; - } - - /* segment inner packet. */ - segs = skb_mac_gso_segment(skb, features); - if (IS_ERR_OR_NULL(segs)) { - skb_gso_error_unwind(skb, protocol, tnl_hlen, mac_offset, - mac_len); - goto out; - } - - gso_partial = !!(skb_shinfo(segs)->gso_type & SKB_GSO_PARTIAL); - - outer_hlen = skb_tnl_header_len(skb); - gre_offset = outer_hlen - tnl_hlen; - skb = segs; - do { - struct gre_base_hdr *greh; - __sum16 *pcsum; - - /* Set up inner headers if we are offloading inner checksum */ - if (skb->ip_summed == CHECKSUM_PARTIAL) { - skb_reset_inner_headers(skb); - skb->encapsulation = 1; - } - - skb->mac_len = mac_len; - skb->protocol = protocol; - - __skb_push(skb, outer_hlen); - skb_reset_mac_header(skb); - skb_set_network_header(skb, mac_len); - skb_set_transport_header(skb, gre_offset); - - if (!need_csum) - continue; - - greh = (struct gre_base_hdr *)skb_transport_header(skb); - pcsum = (__sum16 *)(greh + 1); - - if (gso_partial) { - unsigned int partial_adj; - - /* Adjust checksum to account for the fact that - * the partial checksum is based on actual size - * whereas headers should be based on MSS size. - */ - partial_adj = skb->len + skb_headroom(skb) - - SKB_GSO_CB(skb)->data_offset - - skb_shinfo(skb)->gso_size; - *pcsum = ~csum_fold((__force __wsum)htonl(partial_adj)); - } else { - *pcsum = 0; - } - - *(pcsum + 1) = 0; - *pcsum = gso_make_checksum(skb, 0); - } while ((skb = skb->next)); -out: - return segs; -} - -static struct sk_buff **gre_gro_receive(struct sk_buff **head, - struct sk_buff *skb) -{ - struct sk_buff **pp = NULL; - struct sk_buff *p; - const struct gre_base_hdr *greh; - unsigned int hlen, grehlen; - unsigned int off; - int flush = 1; - struct packet_offload *ptype; - __be16 type; - - if (NAPI_GRO_CB(skb)->encap_mark) - goto out; - - NAPI_GRO_CB(skb)->encap_mark = 1; - - off = skb_gro_offset(skb); - hlen = off + sizeof(*greh); - greh = skb_gro_header_fast(skb, off); - if (skb_gro_header_hard(skb, hlen)) { - greh = skb_gro_header_slow(skb, hlen, off); - if (unlikely(!greh)) - goto out; - } - - /* Only support version 0 and K (key), C (csum) flags. Note that - * although the support for the S (seq#) flag can be added easily - * for GRO, this is problematic for GSO hence can not be enabled - * here because a GRO pkt may end up in the forwarding path, thus - * requiring GSO support to break it up correctly. - */ - if ((greh->flags & ~(GRE_KEY|GRE_CSUM)) != 0) - goto out; - - /* We can only support GRE_CSUM if we can track the location of - * the GRE header. In the case of FOU/GUE we cannot because the - * outer UDP header displaces the GRE header leaving us in a state - * of limbo. - */ - if ((greh->flags & GRE_CSUM) && NAPI_GRO_CB(skb)->is_fou) - goto out; - - type = greh->protocol; - - rcu_read_lock(); - ptype = gro_find_receive_by_type(type); - if (!ptype) - goto out_unlock; - - grehlen = GRE_HEADER_SECTION; - - if (greh->flags & GRE_KEY) - grehlen += GRE_HEADER_SECTION; - - if (greh->flags & GRE_CSUM) - grehlen += GRE_HEADER_SECTION; - - hlen = off + grehlen; - if (skb_gro_header_hard(skb, hlen)) { - greh = skb_gro_header_slow(skb, hlen, off); - if (unlikely(!greh)) - goto out_unlock; - } - - /* Don't bother verifying checksum if we're going to flush anyway. */ - if ((greh->flags & GRE_CSUM) && !NAPI_GRO_CB(skb)->flush) { - if (skb_gro_checksum_simple_validate(skb)) - goto out_unlock; - - skb_gro_checksum_try_convert(skb, IPPROTO_GRE, 0, - null_compute_pseudo); - } - - for (p = *head; p; p = p->next) { - const struct gre_base_hdr *greh2; - - if (!NAPI_GRO_CB(p)->same_flow) - continue; - - /* The following checks are needed to ensure only pkts - * from the same tunnel are considered for aggregation. - * The criteria for "the same tunnel" includes: - * 1) same version (we only support version 0 here) - * 2) same protocol (we only support ETH_P_IP for now) - * 3) same set of flags - * 4) same key if the key field is present. - */ - greh2 = (struct gre_base_hdr *)(p->data + off); - - if (greh2->flags != greh->flags || - greh2->protocol != greh->protocol) { - NAPI_GRO_CB(p)->same_flow = 0; - continue; - } - if (greh->flags & GRE_KEY) { - /* compare keys */ - if (*(__be32 *)(greh2+1) != *(__be32 *)(greh+1)) { - NAPI_GRO_CB(p)->same_flow = 0; - continue; - } - } - } - - skb_gro_pull(skb, grehlen); - - /* Adjusted NAPI_GRO_CB(skb)->csum after skb_gro_pull()*/ - skb_gro_postpull_rcsum(skb, greh, grehlen); - - pp = call_gro_receive(ptype->callbacks.gro_receive, head, skb); - flush = 0; - -out_unlock: - rcu_read_unlock(); -out: - NAPI_GRO_CB(skb)->flush |= flush; - - return pp; -} - -static int gre_gro_complete(struct sk_buff *skb, int nhoff) -{ - struct gre_base_hdr *greh = (struct gre_base_hdr *)(skb->data + nhoff); - struct packet_offload *ptype; - unsigned int grehlen = sizeof(*greh); - int err = -ENOENT; - __be16 type; - - skb->encapsulation = 1; - skb_shinfo(skb)->gso_type = SKB_GSO_GRE; - - type = greh->protocol; - if (greh->flags & GRE_KEY) - grehlen += GRE_HEADER_SECTION; - - if (greh->flags & GRE_CSUM) - grehlen += GRE_HEADER_SECTION; - - rcu_read_lock(); - ptype = gro_find_complete_by_type(type); - if (ptype) - err = ptype->callbacks.gro_complete(skb, nhoff + grehlen); - - rcu_read_unlock(); - - skb_set_inner_mac_header(skb, nhoff + grehlen); - - return err; -} - -static const struct net_offload gre_offload = { - .callbacks = { - .gso_segment = gre_gso_segment, - .gro_receive = gre_gro_receive, - .gro_complete = gre_gro_complete, - }, -}; - -static int __init gre_offload_init(void) -{ - int err; - - err = inet_add_offload(&gre_offload, IPPROTO_GRE); -#if IS_ENABLED(CONFIG_IPV6) - if (err) - return err; - - err = inet6_add_offload(&gre_offload, IPPROTO_GRE); - if (err) - inet_del_offload(&gre_offload, IPPROTO_GRE); -#endif - - return err; -} -device_initcall(gre_offload_init); diff --git a/src/linux/net/ipv4/icmp.c b/src/linux/net/ipv4/icmp.c deleted file mode 100644 index 48734ee..0000000 --- a/src/linux/net/ipv4/icmp.c +++ /dev/null @@ -1,1239 +0,0 @@ -/* - * NET3: Implementation of the ICMP protocol layer. - * - * Alan Cox, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Some of the function names and the icmp unreach table for this - * module were derived from [icmp.c 1.0.11 06/02/93] by - * Ross Biro, Fred N. van Kempen, Mark Evans, Alan Cox, Gerhard Koerting. - * Other than that this module is a complete rewrite. - * - * Fixes: - * Clemens Fruhwirth : introduce global icmp rate limiting - * with icmp type masking ability instead - * of broken per type icmp timeouts. - * Mike Shaver : RFC1122 checks. - * Alan Cox : Multicast ping reply as self. - * Alan Cox : Fix atomicity lockup in ip_build_xmit - * call. - * Alan Cox : Added 216,128 byte paths to the MTU - * code. - * Martin Mares : RFC1812 checks. - * Martin Mares : Can be configured to follow redirects - * if acting as a router _without_ a - * routing protocol (RFC 1812). - * Martin Mares : Echo requests may be configured to - * be ignored (RFC 1812). - * Martin Mares : Limitation of ICMP error message - * transmit rate (RFC 1812). - * Martin Mares : TOS and Precedence set correctly - * (RFC 1812). - * Martin Mares : Now copying as much data from the - * original packet as we can without - * exceeding 576 bytes (RFC 1812). - * Willy Konynenberg : Transparent proxying support. - * Keith Owens : RFC1191 correction for 4.2BSD based - * path MTU bug. - * Thomas Quinot : ICMP Dest Unreach codes up to 15 are - * valid (RFC 1812). - * Andi Kleen : Check all packet lengths properly - * and moved all kfree_skb() up to - * icmp_rcv. - * Andi Kleen : Move the rate limit bookkeeping - * into the dest entry and use a token - * bucket filter (thanks to ANK). Make - * the rates sysctl configurable. - * Yu Tianli : Fixed two ugly bugs in icmp_send - * - IP option length was accounted wrongly - * - ICMP header length was not accounted - * at all. - * Tristan Greaves : Added sysctl option to ignore bogus - * broadcast responses from broken routers. - * - * To Fix: - * - * - Should use skb_pull() instead of all the manual checking. - * This would also greatly simply some upper layer error handlers. --AK - * - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#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 -#include -#include -#include -#include -#include - -/* - * Build xmit assembly blocks - */ - -struct icmp_bxm { - struct sk_buff *skb; - int offset; - int data_len; - - struct { - struct icmphdr icmph; - __be32 times[3]; - } data; - int head_len; - struct ip_options_data replyopts; -}; - -/* An array of errno for error messages from dest unreach. */ -/* RFC 1122: 3.2.2.1 States that NET_UNREACH, HOST_UNREACH and SR_FAILED MUST be considered 'transient errs'. */ - -const struct icmp_err icmp_err_convert[] = { - { - .errno = ENETUNREACH, /* ICMP_NET_UNREACH */ - .fatal = 0, - }, - { - .errno = EHOSTUNREACH, /* ICMP_HOST_UNREACH */ - .fatal = 0, - }, - { - .errno = ENOPROTOOPT /* ICMP_PROT_UNREACH */, - .fatal = 1, - }, - { - .errno = ECONNREFUSED, /* ICMP_PORT_UNREACH */ - .fatal = 1, - }, - { - .errno = EMSGSIZE, /* ICMP_FRAG_NEEDED */ - .fatal = 0, - }, - { - .errno = EOPNOTSUPP, /* ICMP_SR_FAILED */ - .fatal = 0, - }, - { - .errno = ENETUNREACH, /* ICMP_NET_UNKNOWN */ - .fatal = 1, - }, - { - .errno = EHOSTDOWN, /* ICMP_HOST_UNKNOWN */ - .fatal = 1, - }, - { - .errno = ENONET, /* ICMP_HOST_ISOLATED */ - .fatal = 1, - }, - { - .errno = ENETUNREACH, /* ICMP_NET_ANO */ - .fatal = 1, - }, - { - .errno = EHOSTUNREACH, /* ICMP_HOST_ANO */ - .fatal = 1, - }, - { - .errno = ENETUNREACH, /* ICMP_NET_UNR_TOS */ - .fatal = 0, - }, - { - .errno = EHOSTUNREACH, /* ICMP_HOST_UNR_TOS */ - .fatal = 0, - }, - { - .errno = EHOSTUNREACH, /* ICMP_PKT_FILTERED */ - .fatal = 1, - }, - { - .errno = EHOSTUNREACH, /* ICMP_PREC_VIOLATION */ - .fatal = 1, - }, - { - .errno = EHOSTUNREACH, /* ICMP_PREC_CUTOFF */ - .fatal = 1, - }, -}; -EXPORT_SYMBOL(icmp_err_convert); - -/* - * ICMP control array. This specifies what to do with each ICMP. - */ - -struct icmp_control { - bool (*handler)(struct sk_buff *skb); - short error; /* This ICMP is classed as an error message */ -}; - -static const struct icmp_control icmp_pointers[NR_ICMP_TYPES+1]; - -/* - * The ICMP socket(s). This is the most convenient way to flow control - * our ICMP output as well as maintain a clean interface throughout - * all layers. All Socketless IP sends will soon be gone. - * - * On SMP we have one ICMP socket per-cpu. - */ -static struct sock *icmp_sk(struct net *net) -{ - return *this_cpu_ptr(net->ipv4.icmp_sk); -} - -static inline struct sock *icmp_xmit_lock(struct net *net) -{ - struct sock *sk; - - local_bh_disable(); - - sk = icmp_sk(net); - - if (unlikely(!spin_trylock(&sk->sk_lock.slock))) { - /* This can happen if the output path signals a - * dst_link_failure() for an outgoing ICMP packet. - */ - local_bh_enable(); - return NULL; - } - return sk; -} - -static inline void icmp_xmit_unlock(struct sock *sk) -{ - spin_unlock_bh(&sk->sk_lock.slock); -} - -int sysctl_icmp_msgs_per_sec __read_mostly = 1000; -int sysctl_icmp_msgs_burst __read_mostly = 50; - -static struct { - spinlock_t lock; - u32 credit; - u32 stamp; -} icmp_global = { - .lock = __SPIN_LOCK_UNLOCKED(icmp_global.lock), -}; - -/** - * icmp_global_allow - Are we allowed to send one more ICMP message ? - * - * Uses a token bucket to limit our ICMP messages to sysctl_icmp_msgs_per_sec. - * Returns false if we reached the limit and can not send another packet. - * Note: called with BH disabled - */ -bool icmp_global_allow(void) -{ - u32 credit, delta, incr = 0, now = (u32)jiffies; - bool rc = false; - - /* Check if token bucket is empty and cannot be refilled - * without taking the spinlock. - */ - if (!icmp_global.credit) { - delta = min_t(u32, now - icmp_global.stamp, HZ); - if (delta < HZ / 50) - return false; - } - - spin_lock(&icmp_global.lock); - delta = min_t(u32, now - icmp_global.stamp, HZ); - if (delta >= HZ / 50) { - incr = sysctl_icmp_msgs_per_sec * delta / HZ ; - if (incr) - icmp_global.stamp = now; - } - credit = min_t(u32, icmp_global.credit + incr, sysctl_icmp_msgs_burst); - if (credit) { - credit--; - rc = true; - } - icmp_global.credit = credit; - spin_unlock(&icmp_global.lock); - return rc; -} -EXPORT_SYMBOL(icmp_global_allow); - -/* - * Send an ICMP frame. - */ - -static bool icmpv4_xrlim_allow(struct net *net, struct rtable *rt, - struct flowi4 *fl4, int type, int code) -{ - struct dst_entry *dst = &rt->dst; - bool rc = true; - - if (type > NR_ICMP_TYPES) - goto out; - - /* Don't limit PMTU discovery. */ - if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) - goto out; - - /* No rate limit on loopback */ - if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) - goto out; - - /* Limit if icmp type is enabled in ratemask. */ - if (!((1 << type) & net->ipv4.sysctl_icmp_ratemask)) - goto out; - - rc = false; - if (icmp_global_allow()) { - int vif = l3mdev_master_ifindex(dst->dev); - struct inet_peer *peer; - - peer = inet_getpeer_v4(net->ipv4.peers, fl4->daddr, vif, 1); - rc = inet_peer_xrlim_allow(peer, - net->ipv4.sysctl_icmp_ratelimit); - if (peer) - inet_putpeer(peer); - } -out: - return rc; -} - -/* - * Maintain the counters used in the SNMP statistics for outgoing ICMP - */ -void icmp_out_count(struct net *net, unsigned char type) -{ - ICMPMSGOUT_INC_STATS(net, type); - ICMP_INC_STATS(net, ICMP_MIB_OUTMSGS); -} - -/* - * Checksum each fragment, and on the first include the headers and final - * checksum. - */ -static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd, - struct sk_buff *skb) -{ - struct icmp_bxm *icmp_param = (struct icmp_bxm *)from; - __wsum csum; - - csum = skb_copy_and_csum_bits(icmp_param->skb, - icmp_param->offset + offset, - to, len, 0); - - skb->csum = csum_block_add(skb->csum, csum, odd); - if (icmp_pointers[icmp_param->data.icmph.type].error) - nf_ct_attach(skb, icmp_param->skb); - return 0; -} - -static void icmp_push_reply(struct icmp_bxm *icmp_param, - struct flowi4 *fl4, - struct ipcm_cookie *ipc, struct rtable **rt) -{ - struct sock *sk; - struct sk_buff *skb; - - sk = icmp_sk(dev_net((*rt)->dst.dev)); - if (ip_append_data(sk, fl4, icmp_glue_bits, icmp_param, - icmp_param->data_len+icmp_param->head_len, - icmp_param->head_len, - ipc, rt, MSG_DONTWAIT) < 0) { - __ICMP_INC_STATS(sock_net(sk), ICMP_MIB_OUTERRORS); - ip_flush_pending_frames(sk); - } else if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) { - struct icmphdr *icmph = icmp_hdr(skb); - __wsum csum = 0; - struct sk_buff *skb1; - - skb_queue_walk(&sk->sk_write_queue, skb1) { - csum = csum_add(csum, skb1->csum); - } - csum = csum_partial_copy_nocheck((void *)&icmp_param->data, - (char *)icmph, - icmp_param->head_len, csum); - icmph->checksum = csum_fold(csum); - skb->ip_summed = CHECKSUM_NONE; - ip_push_pending_frames(sk, fl4); - } -} - -/* - * Driving logic for building and sending ICMP messages. - */ - -static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) -{ - struct ipcm_cookie ipc; - struct rtable *rt = skb_rtable(skb); - struct net *net = dev_net(rt->dst.dev); - struct flowi4 fl4; - struct sock *sk; - struct inet_sock *inet; - __be32 daddr, saddr; - u32 mark = IP4_REPLY_MARK(net, skb->mark); - - if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb)) - return; - - sk = icmp_xmit_lock(net); - if (!sk) - return; - inet = inet_sk(sk); - - icmp_param->data.icmph.checksum = 0; - - inet->tos = ip_hdr(skb)->tos; - sk->sk_mark = mark; - daddr = ipc.addr = ip_hdr(skb)->saddr; - saddr = fib_compute_spec_dst(skb); - ipc.opt = NULL; - ipc.tx_flags = 0; - ipc.ttl = 0; - ipc.tos = -1; - - if (icmp_param->replyopts.opt.opt.optlen) { - ipc.opt = &icmp_param->replyopts.opt; - if (ipc.opt->opt.srr) - daddr = icmp_param->replyopts.opt.opt.faddr; - } - memset(&fl4, 0, sizeof(fl4)); - fl4.daddr = daddr; - fl4.saddr = saddr; - fl4.flowi4_mark = mark; - fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); - fl4.flowi4_proto = IPPROTO_ICMP; - fl4.flowi4_oif = l3mdev_master_ifindex(skb->dev); - security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); - rt = ip_route_output_key(net, &fl4); - if (IS_ERR(rt)) - goto out_unlock; - if (icmpv4_xrlim_allow(net, rt, &fl4, icmp_param->data.icmph.type, - icmp_param->data.icmph.code)) - icmp_push_reply(icmp_param, &fl4, &ipc, &rt); - ip_rt_put(rt); -out_unlock: - icmp_xmit_unlock(sk); -} - -#ifdef CONFIG_IP_ROUTE_MULTIPATH - -/* Source and destination is swapped. See ip_multipath_icmp_hash */ -static int icmp_multipath_hash_skb(const struct sk_buff *skb) -{ - const struct iphdr *iph = ip_hdr(skb); - - return fib_multipath_hash(iph->daddr, iph->saddr); -} - -#else - -#define icmp_multipath_hash_skb(skb) (-1) - -#endif - -static struct rtable *icmp_route_lookup(struct net *net, - struct flowi4 *fl4, - struct sk_buff *skb_in, - const struct iphdr *iph, - __be32 saddr, u8 tos, u32 mark, - int type, int code, - struct icmp_bxm *param) -{ - struct rtable *rt, *rt2; - struct flowi4 fl4_dec; - int err; - - memset(fl4, 0, sizeof(*fl4)); - fl4->daddr = (param->replyopts.opt.opt.srr ? - param->replyopts.opt.opt.faddr : iph->saddr); - fl4->saddr = saddr; - fl4->flowi4_mark = mark; - fl4->flowi4_tos = RT_TOS(tos); - fl4->flowi4_proto = IPPROTO_ICMP; - fl4->fl4_icmp_type = type; - fl4->fl4_icmp_code = code; - fl4->flowi4_oif = l3mdev_master_ifindex(skb_dst(skb_in)->dev); - - security_skb_classify_flow(skb_in, flowi4_to_flowi(fl4)); - rt = __ip_route_output_key_hash(net, fl4, - icmp_multipath_hash_skb(skb_in)); - if (IS_ERR(rt)) - return rt; - - /* No need to clone since we're just using its address. */ - rt2 = rt; - - rt = (struct rtable *) xfrm_lookup(net, &rt->dst, - flowi4_to_flowi(fl4), NULL, 0); - if (!IS_ERR(rt)) { - if (rt != rt2) - return rt; - } else if (PTR_ERR(rt) == -EPERM) { - rt = NULL; - } else - return rt; - - err = xfrm_decode_session_reverse(skb_in, flowi4_to_flowi(&fl4_dec), AF_INET); - if (err) - goto relookup_failed; - - if (inet_addr_type_dev_table(net, skb_dst(skb_in)->dev, - fl4_dec.saddr) == RTN_LOCAL) { - rt2 = __ip_route_output_key(net, &fl4_dec); - if (IS_ERR(rt2)) - err = PTR_ERR(rt2); - } else { - struct flowi4 fl4_2 = {}; - unsigned long orefdst; - - fl4_2.daddr = fl4_dec.saddr; - rt2 = ip_route_output_key(net, &fl4_2); - if (IS_ERR(rt2)) { - err = PTR_ERR(rt2); - goto relookup_failed; - } - /* Ugh! */ - orefdst = skb_in->_skb_refdst; /* save old refdst */ - skb_dst_set(skb_in, NULL); - err = ip_route_input(skb_in, fl4_dec.daddr, fl4_dec.saddr, - RT_TOS(tos), rt2->dst.dev); - - dst_release(&rt2->dst); - rt2 = skb_rtable(skb_in); - skb_in->_skb_refdst = orefdst; /* restore old refdst */ - } - - if (err) - goto relookup_failed; - - rt2 = (struct rtable *) xfrm_lookup(net, &rt2->dst, - flowi4_to_flowi(&fl4_dec), NULL, - XFRM_LOOKUP_ICMP); - if (!IS_ERR(rt2)) { - dst_release(&rt->dst); - memcpy(fl4, &fl4_dec, sizeof(*fl4)); - rt = rt2; - } else if (PTR_ERR(rt2) == -EPERM) { - if (rt) - dst_release(&rt->dst); - return rt2; - } else { - err = PTR_ERR(rt2); - goto relookup_failed; - } - return rt; - -relookup_failed: - if (rt) - return rt; - return ERR_PTR(err); -} - -/* - * Send an ICMP message in response to a situation - * - * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. - * MAY send more (we do). - * MUST NOT change this header information. - * MUST NOT reply to a multicast/broadcast IP address. - * MUST NOT reply to a multicast/broadcast MAC address. - * MUST reply to only the first fragment. - */ - -void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) -{ - struct iphdr *iph; - int room; - struct icmp_bxm *icmp_param; - struct rtable *rt = skb_rtable(skb_in); - struct ipcm_cookie ipc; - struct flowi4 fl4; - __be32 saddr; - u8 tos; - u32 mark; - struct net *net; - struct sock *sk; - - if (!rt) - goto out; - net = dev_net(rt->dst.dev); - - /* - * Find the original header. It is expected to be valid, of course. - * Check this, icmp_send is called from the most obscure devices - * sometimes. - */ - iph = ip_hdr(skb_in); - - if ((u8 *)iph < skb_in->head || - (skb_network_header(skb_in) + sizeof(*iph)) > - skb_tail_pointer(skb_in)) - goto out; - - /* - * No replies to physical multicast/broadcast - */ - if (skb_in->pkt_type != PACKET_HOST) - goto out; - - /* - * Now check at the protocol level - */ - if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) - goto out; - - /* - * Only reply to fragment 0. We byte re-order the constant - * mask for efficiency. - */ - if (iph->frag_off & htons(IP_OFFSET)) - goto out; - - /* - * If we send an ICMP error to an ICMP error a mess would result.. - */ - if (icmp_pointers[type].error) { - /* - * We are an error, check if we are replying to an - * ICMP error - */ - if (iph->protocol == IPPROTO_ICMP) { - u8 _inner_type, *itp; - - itp = skb_header_pointer(skb_in, - skb_network_header(skb_in) + - (iph->ihl << 2) + - offsetof(struct icmphdr, - type) - - skb_in->data, - sizeof(_inner_type), - &_inner_type); - if (!itp) - goto out; - - /* - * Assume any unknown ICMP type is an error. This - * isn't specified by the RFC, but think about it.. - */ - if (*itp > NR_ICMP_TYPES || - icmp_pointers[*itp].error) - goto out; - } - } - - icmp_param = kmalloc(sizeof(*icmp_param), GFP_ATOMIC); - if (!icmp_param) - return; - - sk = icmp_xmit_lock(net); - if (!sk) - goto out_free; - - /* - * Construct source address and options. - */ - - saddr = iph->daddr; - if (!(rt->rt_flags & RTCF_LOCAL)) { - struct net_device *dev = NULL; - - rcu_read_lock(); - if (rt_is_input_route(rt) && - net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr) - dev = dev_get_by_index_rcu(net, inet_iif(skb_in)); - - if (dev) - saddr = inet_select_addr(dev, 0, RT_SCOPE_LINK); - else - saddr = 0; - rcu_read_unlock(); - } - - tos = icmp_pointers[type].error ? ((iph->tos & IPTOS_TOS_MASK) | - IPTOS_PREC_INTERNETCONTROL) : - iph->tos; - mark = IP4_REPLY_MARK(net, skb_in->mark); - - if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb_in)) - goto out_unlock; - - - /* - * Prepare data for ICMP header. - */ - - icmp_param->data.icmph.type = type; - icmp_param->data.icmph.code = code; - icmp_param->data.icmph.un.gateway = info; - icmp_param->data.icmph.checksum = 0; - icmp_param->skb = skb_in; - icmp_param->offset = skb_network_offset(skb_in); - inet_sk(sk)->tos = tos; - sk->sk_mark = mark; - ipc.addr = iph->saddr; - ipc.opt = &icmp_param->replyopts.opt; - ipc.tx_flags = 0; - ipc.ttl = 0; - ipc.tos = -1; - - rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos, mark, - type, code, icmp_param); - if (IS_ERR(rt)) - goto out_unlock; - - if (!icmpv4_xrlim_allow(net, rt, &fl4, type, code)) - goto ende; - - /* RFC says return as much as we can without exceeding 576 bytes. */ - - room = dst_mtu(&rt->dst); - if (room > 576) - room = 576; - room -= sizeof(struct iphdr) + icmp_param->replyopts.opt.opt.optlen; - room -= sizeof(struct icmphdr); - - icmp_param->data_len = skb_in->len - icmp_param->offset; - if (icmp_param->data_len > room) - icmp_param->data_len = room; - icmp_param->head_len = sizeof(struct icmphdr); - - icmp_push_reply(icmp_param, &fl4, &ipc, &rt); -ende: - ip_rt_put(rt); -out_unlock: - icmp_xmit_unlock(sk); -out_free: - kfree(icmp_param); -out:; -} -EXPORT_SYMBOL(icmp_send); - - -static void icmp_socket_deliver(struct sk_buff *skb, u32 info) -{ - const struct iphdr *iph = (const struct iphdr *) skb->data; - const struct net_protocol *ipprot; - int protocol = iph->protocol; - - /* Checkin full IP header plus 8 bytes of protocol to - * avoid additional coding at protocol handlers. - */ - if (!pskb_may_pull(skb, iph->ihl * 4 + 8)) { - __ICMP_INC_STATS(dev_net(skb->dev), ICMP_MIB_INERRORS); - return; - } - - raw_icmp_error(skb, protocol, info); - - ipprot = rcu_dereference(inet_protos[protocol]); - if (ipprot && ipprot->err_handler) - ipprot->err_handler(skb, info); -} - -static bool icmp_tag_validation(int proto) -{ - bool ok; - - rcu_read_lock(); - ok = rcu_dereference(inet_protos[proto])->icmp_strict_tag_validation; - rcu_read_unlock(); - return ok; -} - -/* - * Handle ICMP_DEST_UNREACH, ICMP_TIME_EXCEED, ICMP_QUENCH, and - * ICMP_PARAMETERPROB. - */ - -static bool icmp_unreach(struct sk_buff *skb) -{ - const struct iphdr *iph; - struct icmphdr *icmph; - struct net *net; - u32 info = 0; - - net = dev_net(skb_dst(skb)->dev); - - /* - * Incomplete header ? - * Only checks for the IP header, there should be an - * additional check for longer headers in upper levels. - */ - - if (!pskb_may_pull(skb, sizeof(struct iphdr))) - goto out_err; - - icmph = icmp_hdr(skb); - iph = (const struct iphdr *)skb->data; - - if (iph->ihl < 5) /* Mangled header, drop. */ - goto out_err; - - if (icmph->type == ICMP_DEST_UNREACH) { - switch (icmph->code & 15) { - case ICMP_NET_UNREACH: - case ICMP_HOST_UNREACH: - case ICMP_PROT_UNREACH: - case ICMP_PORT_UNREACH: - break; - case ICMP_FRAG_NEEDED: - /* for documentation of the ip_no_pmtu_disc - * values please see - * Documentation/networking/ip-sysctl.txt - */ - switch (net->ipv4.sysctl_ip_no_pmtu_disc) { - default: - net_dbg_ratelimited("%pI4: fragmentation needed and DF set\n", - &iph->daddr); - break; - case 2: - goto out; - case 3: - if (!icmp_tag_validation(iph->protocol)) - goto out; - /* fall through */ - case 0: - info = ntohs(icmph->un.frag.mtu); - } - break; - case ICMP_SR_FAILED: - net_dbg_ratelimited("%pI4: Source Route Failed\n", - &iph->daddr); - break; - default: - break; - } - if (icmph->code > NR_ICMP_UNREACH) - goto out; - } else if (icmph->type == ICMP_PARAMETERPROB) - info = ntohl(icmph->un.gateway) >> 24; - - /* - * Throw it at our lower layers - * - * RFC 1122: 3.2.2 MUST extract the protocol ID from the passed - * header. - * RFC 1122: 3.2.2.1 MUST pass ICMP unreach messages to the - * transport layer. - * RFC 1122: 3.2.2.2 MUST pass ICMP time expired messages to - * transport layer. - */ - - /* - * Check the other end isn't violating RFC 1122. Some routers send - * bogus responses to broadcast frames. If you see this message - * first check your netmask matches at both ends, if it does then - * get the other vendor to fix their kit. - */ - - if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses && - inet_addr_type_dev_table(net, skb->dev, iph->daddr) == RTN_BROADCAST) { - net_warn_ratelimited("%pI4 sent an invalid ICMP type %u, code %u error to a broadcast: %pI4 on %s\n", - &ip_hdr(skb)->saddr, - icmph->type, icmph->code, - &iph->daddr, skb->dev->name); - goto out; - } - - icmp_socket_deliver(skb, info); - -out: - return true; -out_err: - __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); - return false; -} - - -/* - * Handle ICMP_REDIRECT. - */ - -static bool icmp_redirect(struct sk_buff *skb) -{ - if (skb->len < sizeof(struct iphdr)) { - __ICMP_INC_STATS(dev_net(skb->dev), ICMP_MIB_INERRORS); - return false; - } - - if (!pskb_may_pull(skb, sizeof(struct iphdr))) { - /* there aught to be a stat */ - return false; - } - - icmp_socket_deliver(skb, icmp_hdr(skb)->un.gateway); - return true; -} - -/* - * Handle ICMP_ECHO ("ping") requests. - * - * RFC 1122: 3.2.2.6 MUST have an echo server that answers ICMP echo - * requests. - * RFC 1122: 3.2.2.6 Data received in the ICMP_ECHO request MUST be - * included in the reply. - * RFC 1812: 4.3.3.6 SHOULD have a config option for silently ignoring - * echo requests, MUST have default=NOT. - * See also WRT handling of options once they are done and working. - */ - -static bool icmp_echo(struct sk_buff *skb) -{ - struct net *net; - - net = dev_net(skb_dst(skb)->dev); - if (!net->ipv4.sysctl_icmp_echo_ignore_all) { - struct icmp_bxm icmp_param; - - icmp_param.data.icmph = *icmp_hdr(skb); - icmp_param.data.icmph.type = ICMP_ECHOREPLY; - icmp_param.skb = skb; - icmp_param.offset = 0; - icmp_param.data_len = skb->len; - icmp_param.head_len = sizeof(struct icmphdr); - icmp_reply(&icmp_param, skb); - } - /* should there be an ICMP stat for ignored echos? */ - return true; -} - -/* - * Handle ICMP Timestamp requests. - * RFC 1122: 3.2.2.8 MAY implement ICMP timestamp requests. - * SHOULD be in the kernel for minimum random latency. - * MUST be accurate to a few minutes. - * MUST be updated at least at 15Hz. - */ -static bool icmp_timestamp(struct sk_buff *skb) -{ - struct icmp_bxm icmp_param; - /* - * Too short. - */ - if (skb->len < 4) - goto out_err; - - /* - * Fill in the current time as ms since midnight UT: - */ - icmp_param.data.times[1] = inet_current_timestamp(); - icmp_param.data.times[2] = icmp_param.data.times[1]; - if (skb_copy_bits(skb, 0, &icmp_param.data.times[0], 4)) - BUG(); - icmp_param.data.icmph = *icmp_hdr(skb); - icmp_param.data.icmph.type = ICMP_TIMESTAMPREPLY; - icmp_param.data.icmph.code = 0; - icmp_param.skb = skb; - icmp_param.offset = 0; - icmp_param.data_len = 0; - icmp_param.head_len = sizeof(struct icmphdr) + 12; - icmp_reply(&icmp_param, skb); - return true; - -out_err: - __ICMP_INC_STATS(dev_net(skb_dst(skb)->dev), ICMP_MIB_INERRORS); - return false; -} - -static bool icmp_discard(struct sk_buff *skb) -{ - /* pretend it was a success */ - return true; -} - -/* - * Deal with incoming ICMP packets. - */ -int icmp_rcv(struct sk_buff *skb) -{ - struct icmphdr *icmph; - struct rtable *rt = skb_rtable(skb); - struct net *net = dev_net(rt->dst.dev); - bool success; - - if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { - struct sec_path *sp = skb_sec_path(skb); - int nh; - - if (!(sp && sp->xvec[sp->len - 1]->props.flags & - XFRM_STATE_ICMP)) - goto drop; - - if (!pskb_may_pull(skb, sizeof(*icmph) + sizeof(struct iphdr))) - goto drop; - - nh = skb_network_offset(skb); - skb_set_network_header(skb, sizeof(*icmph)); - - if (!xfrm4_policy_check_reverse(NULL, XFRM_POLICY_IN, skb)) - goto drop; - - skb_set_network_header(skb, nh); - } - - __ICMP_INC_STATS(net, ICMP_MIB_INMSGS); - - if (skb_checksum_simple_validate(skb)) - goto csum_error; - - if (!pskb_pull(skb, sizeof(*icmph))) - goto error; - - icmph = icmp_hdr(skb); - - ICMPMSGIN_INC_STATS(net, icmph->type); - /* - * 18 is the highest 'known' ICMP type. Anything else is a mystery - * - * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently - * discarded. - */ - if (icmph->type > NR_ICMP_TYPES) - goto error; - - - /* - * Parse the ICMP message - */ - - if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) { - /* - * RFC 1122: 3.2.2.6 An ICMP_ECHO to broadcast MAY be - * silently ignored (we let user decide with a sysctl). - * RFC 1122: 3.2.2.8 An ICMP_TIMESTAMP MAY be silently - * discarded if to broadcast/multicast. - */ - if ((icmph->type == ICMP_ECHO || - icmph->type == ICMP_TIMESTAMP) && - net->ipv4.sysctl_icmp_echo_ignore_broadcasts) { - goto error; - } - if (icmph->type != ICMP_ECHO && - icmph->type != ICMP_TIMESTAMP && - icmph->type != ICMP_ADDRESS && - icmph->type != ICMP_ADDRESSREPLY) { - goto error; - } - } - - success = icmp_pointers[icmph->type].handler(skb); - - if (success) { - consume_skb(skb); - return 0; - } - -drop: - kfree_skb(skb); - return 0; -csum_error: - __ICMP_INC_STATS(net, ICMP_MIB_CSUMERRORS); -error: - __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); - goto drop; -} - -void icmp_err(struct sk_buff *skb, u32 info) -{ - struct iphdr *iph = (struct iphdr *)skb->data; - int offset = iph->ihl<<2; - struct icmphdr *icmph = (struct icmphdr *)(skb->data + offset); - int type = icmp_hdr(skb)->type; - int code = icmp_hdr(skb)->code; - struct net *net = dev_net(skb->dev); - - /* - * Use ping_err to handle all icmp errors except those - * triggered by ICMP_ECHOREPLY which sent from kernel. - */ - if (icmph->type != ICMP_ECHOREPLY) { - ping_err(skb, offset, info); - return; - } - - if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) - ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ICMP, 0); - else if (type == ICMP_REDIRECT) - ipv4_redirect(skb, net, 0, 0, IPPROTO_ICMP, 0); -} - -/* - * This table is the definition of how we handle ICMP. - */ -static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = { - [ICMP_ECHOREPLY] = { - .handler = ping_rcv, - }, - [1] = { - .handler = icmp_discard, - .error = 1, - }, - [2] = { - .handler = icmp_discard, - .error = 1, - }, - [ICMP_DEST_UNREACH] = { - .handler = icmp_unreach, - .error = 1, - }, - [ICMP_SOURCE_QUENCH] = { - .handler = icmp_unreach, - .error = 1, - }, - [ICMP_REDIRECT] = { - .handler = icmp_redirect, - .error = 1, - }, - [6] = { - .handler = icmp_discard, - .error = 1, - }, - [7] = { - .handler = icmp_discard, - .error = 1, - }, - [ICMP_ECHO] = { - .handler = icmp_echo, - }, - [9] = { - .handler = icmp_discard, - .error = 1, - }, - [10] = { - .handler = icmp_discard, - .error = 1, - }, - [ICMP_TIME_EXCEEDED] = { - .handler = icmp_unreach, - .error = 1, - }, - [ICMP_PARAMETERPROB] = { - .handler = icmp_unreach, - .error = 1, - }, - [ICMP_TIMESTAMP] = { - .handler = icmp_timestamp, - }, - [ICMP_TIMESTAMPREPLY] = { - .handler = icmp_discard, - }, - [ICMP_INFO_REQUEST] = { - .handler = icmp_discard, - }, - [ICMP_INFO_REPLY] = { - .handler = icmp_discard, - }, - [ICMP_ADDRESS] = { - .handler = icmp_discard, - }, - [ICMP_ADDRESSREPLY] = { - .handler = icmp_discard, - }, -}; - -static void __net_exit icmp_sk_exit(struct net *net) -{ - int i; - - for_each_possible_cpu(i) - inet_ctl_sock_destroy(*per_cpu_ptr(net->ipv4.icmp_sk, i)); - free_percpu(net->ipv4.icmp_sk); - net->ipv4.icmp_sk = NULL; -} - -static int __net_init icmp_sk_init(struct net *net) -{ - int i, err; - - net->ipv4.icmp_sk = alloc_percpu(struct sock *); - if (!net->ipv4.icmp_sk) - return -ENOMEM; - - for_each_possible_cpu(i) { - struct sock *sk; - - err = inet_ctl_sock_create(&sk, PF_INET, - SOCK_RAW, IPPROTO_ICMP, net); - if (err < 0) - goto fail; - - *per_cpu_ptr(net->ipv4.icmp_sk, i) = sk; - - /* Enough space for 2 64K ICMP packets, including - * sk_buff/skb_shared_info struct overhead. - */ - sk->sk_sndbuf = 2 * SKB_TRUESIZE(64 * 1024); - - /* - * Speedup sock_wfree() - */ - sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); - inet_sk(sk)->pmtudisc = IP_PMTUDISC_DONT; - } - - /* Control parameters for ECHO replies. */ - net->ipv4.sysctl_icmp_echo_ignore_all = 0; - net->ipv4.sysctl_icmp_echo_ignore_broadcasts = 1; - - /* Control parameter - ignore bogus broadcast responses? */ - net->ipv4.sysctl_icmp_ignore_bogus_error_responses = 1; - - /* - * Configurable global rate limit. - * - * ratelimit defines tokens/packet consumed for dst->rate_token - * bucket ratemask defines which icmp types are ratelimited by - * setting it's bit position. - * - * default: - * dest unreachable (3), source quench (4), - * time exceeded (11), parameter problem (12) - */ - - net->ipv4.sysctl_icmp_ratelimit = 1 * HZ; - net->ipv4.sysctl_icmp_ratemask = 0x1818; - net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr = 0; - - return 0; - -fail: - for_each_possible_cpu(i) - inet_ctl_sock_destroy(*per_cpu_ptr(net->ipv4.icmp_sk, i)); - free_percpu(net->ipv4.icmp_sk); - return err; -} - -static struct pernet_operations __net_initdata icmp_sk_ops = { - .init = icmp_sk_init, - .exit = icmp_sk_exit, -}; - -int __init icmp_init(void) -{ - return register_pernet_subsys(&icmp_sk_ops); -} diff --git a/src/linux/net/ipv4/igmp.c b/src/linux/net/ipv4/igmp.c deleted file mode 100644 index 15db786..0000000 --- a/src/linux/net/ipv4/igmp.c +++ /dev/null @@ -1,3035 +0,0 @@ -/* - * Linux NET3: Internet Group Management Protocol [IGMP] - * - * This code implements the IGMP protocol as defined in RFC1112. There has - * been a further revision of this protocol since which is now supported. - * - * If you have trouble with this module be careful what gcc you have used, - * the older version didn't come out right using gcc 2.5.8, the newer one - * seems to fall out with gcc 2.6.2. - * - * Authors: - * Alan Cox - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Fixes: - * - * Alan Cox : Added lots of __inline__ to optimise - * the memory usage of all the tiny little - * functions. - * Alan Cox : Dumped the header building experiment. - * Alan Cox : Minor tweaks ready for multicast routing - * and extended IGMP protocol. - * Alan Cox : Removed a load of inline directives. Gcc 2.5.8 - * writes utterly bogus code otherwise (sigh) - * fixed IGMP loopback to behave in the manner - * desired by mrouted, fixed the fact it has been - * broken since 1.3.6 and cleaned up a few minor - * points. - * - * Chih-Jen Chang : Tried to revise IGMP to Version 2 - * Tsu-Sheng Tsao E-mail: chihjenc@scf.usc.edu and tsusheng@scf.usc.edu - * The enhancements are mainly based on Steve Deering's - * ipmulti-3.5 source code. - * Chih-Jen Chang : Added the igmp_get_mrouter_info and - * Tsu-Sheng Tsao igmp_set_mrouter_info to keep track of - * the mrouted version on that device. - * Chih-Jen Chang : Added the max_resp_time parameter to - * Tsu-Sheng Tsao igmp_heard_query(). Using this parameter - * to identify the multicast router version - * and do what the IGMP version 2 specified. - * Chih-Jen Chang : Added a timer to revert to IGMP V2 router - * Tsu-Sheng Tsao if the specified time expired. - * Alan Cox : Stop IGMP from 0.0.0.0 being accepted. - * Alan Cox : Use GFP_ATOMIC in the right places. - * Christian Daudt : igmp timer wasn't set for local group - * memberships but was being deleted, - * which caused a "del_timer() called - * from %p with timer not initialized\n" - * message (960131). - * Christian Daudt : removed del_timer from - * igmp_timer_expire function (960205). - * Christian Daudt : igmp_heard_report now only calls - * igmp_timer_expire if tm->running is - * true (960216). - * Malcolm Beattie : ttl comparison wrong in igmp_rcv made - * igmp_heard_query never trigger. Expiry - * miscalculation fixed in igmp_heard_query - * and random() made to return unsigned to - * prevent negative expiry times. - * Alexey Kuznetsov: Wrong group leaving behaviour, backport - * fix from pending 2.1.x patches. - * Alan Cox: Forget to enable FDDI support earlier. - * Alexey Kuznetsov: Fixed leaving groups on device down. - * Alexey Kuznetsov: Accordance to igmp-v2-06 draft. - * David L Stevens: IGMPv3 support, with help from - * Vinay Kulkarni - */ - -#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 -#ifdef CONFIG_IP_MROUTE -#include -#endif -#ifdef CONFIG_PROC_FS -#include -#include -#endif - -#ifdef CONFIG_IP_MULTICAST -/* Parameter names and values are taken from igmp-v2-06 draft */ - -#define IGMP_V1_ROUTER_PRESENT_TIMEOUT (400*HZ) -#define IGMP_V2_ROUTER_PRESENT_TIMEOUT (400*HZ) -#define IGMP_V2_UNSOLICITED_REPORT_INTERVAL (10*HZ) -#define IGMP_V3_UNSOLICITED_REPORT_INTERVAL (1*HZ) -#define IGMP_QUERY_RESPONSE_INTERVAL (10*HZ) -#define IGMP_QUERY_ROBUSTNESS_VARIABLE 2 - - -#define IGMP_INITIAL_REPORT_DELAY (1) - -/* IGMP_INITIAL_REPORT_DELAY is not from IGMP specs! - * IGMP specs require to report membership immediately after - * joining a group, but we delay the first report by a - * small interval. It seems more natural and still does not - * contradict to specs provided this delay is small enough. - */ - -#define IGMP_V1_SEEN(in_dev) \ - (IPV4_DEVCONF_ALL(dev_net(in_dev->dev), FORCE_IGMP_VERSION) == 1 || \ - IN_DEV_CONF_GET((in_dev), FORCE_IGMP_VERSION) == 1 || \ - ((in_dev)->mr_v1_seen && \ - time_before(jiffies, (in_dev)->mr_v1_seen))) -#define IGMP_V2_SEEN(in_dev) \ - (IPV4_DEVCONF_ALL(dev_net(in_dev->dev), FORCE_IGMP_VERSION) == 2 || \ - IN_DEV_CONF_GET((in_dev), FORCE_IGMP_VERSION) == 2 || \ - ((in_dev)->mr_v2_seen && \ - time_before(jiffies, (in_dev)->mr_v2_seen))) - -static int unsolicited_report_interval(struct in_device *in_dev) -{ - int interval_ms, interval_jiffies; - - if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) - interval_ms = IN_DEV_CONF_GET( - in_dev, - IGMPV2_UNSOLICITED_REPORT_INTERVAL); - else /* v3 */ - interval_ms = IN_DEV_CONF_GET( - in_dev, - IGMPV3_UNSOLICITED_REPORT_INTERVAL); - - interval_jiffies = msecs_to_jiffies(interval_ms); - - /* _timer functions can't handle a delay of 0 jiffies so ensure - * we always return a positive value. - */ - if (interval_jiffies <= 0) - interval_jiffies = 1; - return interval_jiffies; -} - -static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im); -static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im); -static void igmpv3_clear_delrec(struct in_device *in_dev); -static int sf_setstate(struct ip_mc_list *pmc); -static void sf_markstate(struct ip_mc_list *pmc); -#endif -static void ip_mc_clear_src(struct ip_mc_list *pmc); -static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, - int sfcount, __be32 *psfsrc, int delta); - -static void ip_ma_put(struct ip_mc_list *im) -{ - if (atomic_dec_and_test(&im->refcnt)) { - in_dev_put(im->interface); - kfree_rcu(im, rcu); - } -} - -#define for_each_pmc_rcu(in_dev, pmc) \ - for (pmc = rcu_dereference(in_dev->mc_list); \ - pmc != NULL; \ - pmc = rcu_dereference(pmc->next_rcu)) - -#define for_each_pmc_rtnl(in_dev, pmc) \ - for (pmc = rtnl_dereference(in_dev->mc_list); \ - pmc != NULL; \ - pmc = rtnl_dereference(pmc->next_rcu)) - -#ifdef CONFIG_IP_MULTICAST - -/* - * Timer management - */ - -static void igmp_stop_timer(struct ip_mc_list *im) -{ - spin_lock_bh(&im->lock); - if (del_timer(&im->timer)) - atomic_dec(&im->refcnt); - im->tm_running = 0; - im->reporter = 0; - im->unsolicit_count = 0; - spin_unlock_bh(&im->lock); -} - -/* It must be called with locked im->lock */ -static void igmp_start_timer(struct ip_mc_list *im, int max_delay) -{ - int tv = prandom_u32() % max_delay; - - im->tm_running = 1; - if (!mod_timer(&im->timer, jiffies+tv+2)) - atomic_inc(&im->refcnt); -} - -static void igmp_gq_start_timer(struct in_device *in_dev) -{ - int tv = prandom_u32() % in_dev->mr_maxdelay; - - in_dev->mr_gq_running = 1; - if (!mod_timer(&in_dev->mr_gq_timer, jiffies+tv+2)) - in_dev_hold(in_dev); -} - -static void igmp_ifc_start_timer(struct in_device *in_dev, int delay) -{ - int tv = prandom_u32() % delay; - - if (!mod_timer(&in_dev->mr_ifc_timer, jiffies+tv+2)) - in_dev_hold(in_dev); -} - -static void igmp_mod_timer(struct ip_mc_list *im, int max_delay) -{ - spin_lock_bh(&im->lock); - im->unsolicit_count = 0; - if (del_timer(&im->timer)) { - if ((long)(im->timer.expires-jiffies) < max_delay) { - add_timer(&im->timer); - im->tm_running = 1; - spin_unlock_bh(&im->lock); - return; - } - atomic_dec(&im->refcnt); - } - igmp_start_timer(im, max_delay); - spin_unlock_bh(&im->lock); -} - - -/* - * Send an IGMP report. - */ - -#define IGMP_SIZE (sizeof(struct igmphdr)+sizeof(struct iphdr)+4) - - -static int is_in(struct ip_mc_list *pmc, struct ip_sf_list *psf, int type, - int gdeleted, int sdeleted) -{ - switch (type) { - case IGMPV3_MODE_IS_INCLUDE: - case IGMPV3_MODE_IS_EXCLUDE: - if (gdeleted || sdeleted) - return 0; - if (!(pmc->gsquery && !psf->sf_gsresp)) { - if (pmc->sfmode == MCAST_INCLUDE) - return 1; - /* don't include if this source is excluded - * in all filters - */ - if (psf->sf_count[MCAST_INCLUDE]) - return type == IGMPV3_MODE_IS_INCLUDE; - return pmc->sfcount[MCAST_EXCLUDE] == - psf->sf_count[MCAST_EXCLUDE]; - } - return 0; - case IGMPV3_CHANGE_TO_INCLUDE: - if (gdeleted || sdeleted) - return 0; - return psf->sf_count[MCAST_INCLUDE] != 0; - case IGMPV3_CHANGE_TO_EXCLUDE: - if (gdeleted || sdeleted) - return 0; - if (pmc->sfcount[MCAST_EXCLUDE] == 0 || - psf->sf_count[MCAST_INCLUDE]) - return 0; - return pmc->sfcount[MCAST_EXCLUDE] == - psf->sf_count[MCAST_EXCLUDE]; - case IGMPV3_ALLOW_NEW_SOURCES: - if (gdeleted || !psf->sf_crcount) - return 0; - return (pmc->sfmode == MCAST_INCLUDE) ^ sdeleted; - case IGMPV3_BLOCK_OLD_SOURCES: - if (pmc->sfmode == MCAST_INCLUDE) - return gdeleted || (psf->sf_crcount && sdeleted); - return psf->sf_crcount && !gdeleted && !sdeleted; - } - return 0; -} - -static int -igmp_scount(struct ip_mc_list *pmc, int type, int gdeleted, int sdeleted) -{ - struct ip_sf_list *psf; - int scount = 0; - - for (psf = pmc->sources; psf; psf = psf->sf_next) { - if (!is_in(pmc, psf, type, gdeleted, sdeleted)) - continue; - scount++; - } - return scount; -} - -static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu) -{ - struct sk_buff *skb; - struct rtable *rt; - struct iphdr *pip; - struct igmpv3_report *pig; - struct net *net = dev_net(dev); - struct flowi4 fl4; - int hlen = LL_RESERVED_SPACE(dev); - int tlen = dev->needed_tailroom; - unsigned int size = mtu; - - while (1) { - skb = alloc_skb(size + hlen + tlen, - GFP_ATOMIC | __GFP_NOWARN); - if (skb) - break; - size >>= 1; - if (size < 256) - return NULL; - } - skb->priority = TC_PRIO_CONTROL; - - rt = ip_route_output_ports(net, &fl4, NULL, IGMPV3_ALL_MCR, 0, - 0, 0, - IPPROTO_IGMP, 0, dev->ifindex); - if (IS_ERR(rt)) { - kfree_skb(skb); - return NULL; - } - - skb_dst_set(skb, &rt->dst); - skb->dev = dev; - - skb_reserve(skb, hlen); - skb_tailroom_reserve(skb, mtu, tlen); - - skb_reset_network_header(skb); - pip = ip_hdr(skb); - skb_put(skb, sizeof(struct iphdr) + 4); - - pip->version = 4; - pip->ihl = (sizeof(struct iphdr)+4)>>2; - pip->tos = 0xc0; - pip->frag_off = htons(IP_DF); - pip->ttl = 1; - pip->daddr = fl4.daddr; - pip->saddr = fl4.saddr; - pip->protocol = IPPROTO_IGMP; - pip->tot_len = 0; /* filled in later */ - ip_select_ident(net, skb, NULL); - ((u8 *)&pip[1])[0] = IPOPT_RA; - ((u8 *)&pip[1])[1] = 4; - ((u8 *)&pip[1])[2] = 0; - ((u8 *)&pip[1])[3] = 0; - - skb->transport_header = skb->network_header + sizeof(struct iphdr) + 4; - skb_put(skb, sizeof(*pig)); - pig = igmpv3_report_hdr(skb); - pig->type = IGMPV3_HOST_MEMBERSHIP_REPORT; - pig->resv1 = 0; - pig->csum = 0; - pig->resv2 = 0; - pig->ngrec = 0; - return skb; -} - -static int igmpv3_sendpack(struct sk_buff *skb) -{ - struct igmphdr *pig = igmp_hdr(skb); - const int igmplen = skb_tail_pointer(skb) - skb_transport_header(skb); - - pig->csum = ip_compute_csum(igmp_hdr(skb), igmplen); - - return ip_local_out(dev_net(skb_dst(skb)->dev), skb->sk, skb); -} - -static int grec_size(struct ip_mc_list *pmc, int type, int gdel, int sdel) -{ - return sizeof(struct igmpv3_grec) + 4*igmp_scount(pmc, type, gdel, sdel); -} - -static struct sk_buff *add_grhead(struct sk_buff *skb, struct ip_mc_list *pmc, - int type, struct igmpv3_grec **ppgr) -{ - struct net_device *dev = pmc->interface->dev; - struct igmpv3_report *pih; - struct igmpv3_grec *pgr; - - if (!skb) - skb = igmpv3_newpack(dev, dev->mtu); - if (!skb) - return NULL; - pgr = (struct igmpv3_grec *)skb_put(skb, sizeof(struct igmpv3_grec)); - pgr->grec_type = type; - pgr->grec_auxwords = 0; - pgr->grec_nsrcs = 0; - pgr->grec_mca = pmc->multiaddr; - pih = igmpv3_report_hdr(skb); - pih->ngrec = htons(ntohs(pih->ngrec)+1); - *ppgr = pgr; - return skb; -} - -#define AVAILABLE(skb) ((skb) ? skb_availroom(skb) : 0) - -static struct sk_buff *add_grec(struct sk_buff *skb, struct ip_mc_list *pmc, - int type, int gdeleted, int sdeleted) -{ - struct net_device *dev = pmc->interface->dev; - struct net *net = dev_net(dev); - struct igmpv3_report *pih; - struct igmpv3_grec *pgr = NULL; - struct ip_sf_list *psf, *psf_next, *psf_prev, **psf_list; - int scount, stotal, first, isquery, truncate; - - if (pmc->multiaddr == IGMP_ALL_HOSTS) - return skb; - if (ipv4_is_local_multicast(pmc->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports) - return skb; - - isquery = type == IGMPV3_MODE_IS_INCLUDE || - type == IGMPV3_MODE_IS_EXCLUDE; - truncate = type == IGMPV3_MODE_IS_EXCLUDE || - type == IGMPV3_CHANGE_TO_EXCLUDE; - - stotal = scount = 0; - - psf_list = sdeleted ? &pmc->tomb : &pmc->sources; - - if (!*psf_list) - goto empty_source; - - pih = skb ? igmpv3_report_hdr(skb) : NULL; - - /* EX and TO_EX get a fresh packet, if needed */ - if (truncate) { - if (pih && pih->ngrec && - AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) { - if (skb) - igmpv3_sendpack(skb); - skb = igmpv3_newpack(dev, dev->mtu); - } - } - first = 1; - psf_prev = NULL; - for (psf = *psf_list; psf; psf = psf_next) { - __be32 *psrc; - - psf_next = psf->sf_next; - - if (!is_in(pmc, psf, type, gdeleted, sdeleted)) { - psf_prev = psf; - continue; - } - - /* Based on RFC3376 5.1. Should not send source-list change - * records when there is a filter mode change. - */ - if (((gdeleted && pmc->sfmode == MCAST_EXCLUDE) || - (!gdeleted && pmc->crcount)) && - (type == IGMPV3_ALLOW_NEW_SOURCES || - type == IGMPV3_BLOCK_OLD_SOURCES) && psf->sf_crcount) - goto decrease_sf_crcount; - - /* clear marks on query responses */ - if (isquery) - psf->sf_gsresp = 0; - - if (AVAILABLE(skb) < sizeof(__be32) + - first*sizeof(struct igmpv3_grec)) { - if (truncate && !first) - break; /* truncate these */ - if (pgr) - pgr->grec_nsrcs = htons(scount); - if (skb) - igmpv3_sendpack(skb); - skb = igmpv3_newpack(dev, dev->mtu); - first = 1; - scount = 0; - } - if (first) { - skb = add_grhead(skb, pmc, type, &pgr); - first = 0; - } - if (!skb) - return NULL; - psrc = (__be32 *)skb_put(skb, sizeof(__be32)); - *psrc = psf->sf_inaddr; - scount++; stotal++; - if ((type == IGMPV3_ALLOW_NEW_SOURCES || - type == IGMPV3_BLOCK_OLD_SOURCES) && psf->sf_crcount) { -decrease_sf_crcount: - psf->sf_crcount--; - if ((sdeleted || gdeleted) && psf->sf_crcount == 0) { - if (psf_prev) - psf_prev->sf_next = psf->sf_next; - else - *psf_list = psf->sf_next; - kfree(psf); - continue; - } - } - psf_prev = psf; - } - -empty_source: - if (!stotal) { - if (type == IGMPV3_ALLOW_NEW_SOURCES || - type == IGMPV3_BLOCK_OLD_SOURCES) - return skb; - if (pmc->crcount || isquery) { - /* make sure we have room for group header */ - if (skb && AVAILABLE(skb) < sizeof(struct igmpv3_grec)) { - igmpv3_sendpack(skb); - skb = NULL; /* add_grhead will get a new one */ - } - skb = add_grhead(skb, pmc, type, &pgr); - } - } - if (pgr) - pgr->grec_nsrcs = htons(scount); - - if (isquery) - pmc->gsquery = 0; /* clear query state on report */ - return skb; -} - -static int igmpv3_send_report(struct in_device *in_dev, struct ip_mc_list *pmc) -{ - struct sk_buff *skb = NULL; - struct net *net = dev_net(in_dev->dev); - int type; - - if (!pmc) { - rcu_read_lock(); - for_each_pmc_rcu(in_dev, pmc) { - if (pmc->multiaddr == IGMP_ALL_HOSTS) - continue; - if (ipv4_is_local_multicast(pmc->multiaddr) && - !net->ipv4.sysctl_igmp_llm_reports) - continue; - spin_lock_bh(&pmc->lock); - if (pmc->sfcount[MCAST_EXCLUDE]) - type = IGMPV3_MODE_IS_EXCLUDE; - else - type = IGMPV3_MODE_IS_INCLUDE; - skb = add_grec(skb, pmc, type, 0, 0); - spin_unlock_bh(&pmc->lock); - } - rcu_read_unlock(); - } else { - spin_lock_bh(&pmc->lock); - if (pmc->sfcount[MCAST_EXCLUDE]) - type = IGMPV3_MODE_IS_EXCLUDE; - else - type = IGMPV3_MODE_IS_INCLUDE; - skb = add_grec(skb, pmc, type, 0, 0); - spin_unlock_bh(&pmc->lock); - } - if (!skb) - return 0; - return igmpv3_sendpack(skb); -} - -/* - * remove zero-count source records from a source filter list - */ -static void igmpv3_clear_zeros(struct ip_sf_list **ppsf) -{ - struct ip_sf_list *psf_prev, *psf_next, *psf; - - psf_prev = NULL; - for (psf = *ppsf; psf; psf = psf_next) { - psf_next = psf->sf_next; - if (psf->sf_crcount == 0) { - if (psf_prev) - psf_prev->sf_next = psf->sf_next; - else - *ppsf = psf->sf_next; - kfree(psf); - } else - psf_prev = psf; - } -} - -static void igmpv3_send_cr(struct in_device *in_dev) -{ - struct ip_mc_list *pmc, *pmc_prev, *pmc_next; - struct sk_buff *skb = NULL; - int type, dtype; - - rcu_read_lock(); - spin_lock_bh(&in_dev->mc_tomb_lock); - - /* deleted MCA's */ - pmc_prev = NULL; - for (pmc = in_dev->mc_tomb; pmc; pmc = pmc_next) { - pmc_next = pmc->next; - if (pmc->sfmode == MCAST_INCLUDE) { - type = IGMPV3_BLOCK_OLD_SOURCES; - dtype = IGMPV3_BLOCK_OLD_SOURCES; - skb = add_grec(skb, pmc, type, 1, 0); - skb = add_grec(skb, pmc, dtype, 1, 1); - } - if (pmc->crcount) { - if (pmc->sfmode == MCAST_EXCLUDE) { - type = IGMPV3_CHANGE_TO_INCLUDE; - skb = add_grec(skb, pmc, type, 1, 0); - } - pmc->crcount--; - if (pmc->crcount == 0) { - igmpv3_clear_zeros(&pmc->tomb); - igmpv3_clear_zeros(&pmc->sources); - } - } - if (pmc->crcount == 0 && !pmc->tomb && !pmc->sources) { - if (pmc_prev) - pmc_prev->next = pmc_next; - else - in_dev->mc_tomb = pmc_next; - in_dev_put(pmc->interface); - kfree(pmc); - } else - pmc_prev = pmc; - } - spin_unlock_bh(&in_dev->mc_tomb_lock); - - /* change recs */ - for_each_pmc_rcu(in_dev, pmc) { - spin_lock_bh(&pmc->lock); - if (pmc->sfcount[MCAST_EXCLUDE]) { - type = IGMPV3_BLOCK_OLD_SOURCES; - dtype = IGMPV3_ALLOW_NEW_SOURCES; - } else { - type = IGMPV3_ALLOW_NEW_SOURCES; - dtype = IGMPV3_BLOCK_OLD_SOURCES; - } - skb = add_grec(skb, pmc, type, 0, 0); - skb = add_grec(skb, pmc, dtype, 0, 1); /* deleted sources */ - - /* filter mode changes */ - if (pmc->crcount) { - if (pmc->sfmode == MCAST_EXCLUDE) - type = IGMPV3_CHANGE_TO_EXCLUDE; - else - type = IGMPV3_CHANGE_TO_INCLUDE; - skb = add_grec(skb, pmc, type, 0, 0); - pmc->crcount--; - } - spin_unlock_bh(&pmc->lock); - } - rcu_read_unlock(); - - if (!skb) - return; - (void) igmpv3_sendpack(skb); -} - -static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, - int type) -{ - struct sk_buff *skb; - struct iphdr *iph; - struct igmphdr *ih; - struct rtable *rt; - struct net_device *dev = in_dev->dev; - struct net *net = dev_net(dev); - __be32 group = pmc ? pmc->multiaddr : 0; - struct flowi4 fl4; - __be32 dst; - int hlen, tlen; - - if (type == IGMPV3_HOST_MEMBERSHIP_REPORT) - return igmpv3_send_report(in_dev, pmc); - - if (ipv4_is_local_multicast(group) && !net->ipv4.sysctl_igmp_llm_reports) - return 0; - - if (type == IGMP_HOST_LEAVE_MESSAGE) - dst = IGMP_ALL_ROUTER; - else - dst = group; - - rt = ip_route_output_ports(net, &fl4, NULL, dst, 0, - 0, 0, - IPPROTO_IGMP, 0, dev->ifindex); - if (IS_ERR(rt)) - return -1; - - hlen = LL_RESERVED_SPACE(dev); - tlen = dev->needed_tailroom; - skb = alloc_skb(IGMP_SIZE + hlen + tlen, GFP_ATOMIC); - if (!skb) { - ip_rt_put(rt); - return -1; - } - skb->priority = TC_PRIO_CONTROL; - - skb_dst_set(skb, &rt->dst); - - skb_reserve(skb, hlen); - - skb_reset_network_header(skb); - iph = ip_hdr(skb); - skb_put(skb, sizeof(struct iphdr) + 4); - - iph->version = 4; - iph->ihl = (sizeof(struct iphdr)+4)>>2; - iph->tos = 0xc0; - iph->frag_off = htons(IP_DF); - iph->ttl = 1; - iph->daddr = dst; - iph->saddr = fl4.saddr; - iph->protocol = IPPROTO_IGMP; - ip_select_ident(net, skb, NULL); - ((u8 *)&iph[1])[0] = IPOPT_RA; - ((u8 *)&iph[1])[1] = 4; - ((u8 *)&iph[1])[2] = 0; - ((u8 *)&iph[1])[3] = 0; - - ih = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr)); - ih->type = type; - ih->code = 0; - ih->csum = 0; - ih->group = group; - ih->csum = ip_compute_csum((void *)ih, sizeof(struct igmphdr)); - - return ip_local_out(net, skb->sk, skb); -} - -static void igmp_gq_timer_expire(unsigned long data) -{ - struct in_device *in_dev = (struct in_device *)data; - - in_dev->mr_gq_running = 0; - igmpv3_send_report(in_dev, NULL); - in_dev_put(in_dev); -} - -static void igmp_ifc_timer_expire(unsigned long data) -{ - struct in_device *in_dev = (struct in_device *)data; - - igmpv3_send_cr(in_dev); - if (in_dev->mr_ifc_count) { - in_dev->mr_ifc_count--; - igmp_ifc_start_timer(in_dev, - unsolicited_report_interval(in_dev)); - } - in_dev_put(in_dev); -} - -static void igmp_ifc_event(struct in_device *in_dev) -{ - struct net *net = dev_net(in_dev->dev); - if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) - return; - in_dev->mr_ifc_count = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv; - igmp_ifc_start_timer(in_dev, 1); -} - - -static void igmp_timer_expire(unsigned long data) -{ - struct ip_mc_list *im = (struct ip_mc_list *)data; - struct in_device *in_dev = im->interface; - - spin_lock(&im->lock); - im->tm_running = 0; - - if (im->unsolicit_count) { - im->unsolicit_count--; - igmp_start_timer(im, unsolicited_report_interval(in_dev)); - } - im->reporter = 1; - spin_unlock(&im->lock); - - if (IGMP_V1_SEEN(in_dev)) - igmp_send_report(in_dev, im, IGMP_HOST_MEMBERSHIP_REPORT); - else if (IGMP_V2_SEEN(in_dev)) - igmp_send_report(in_dev, im, IGMPV2_HOST_MEMBERSHIP_REPORT); - else - igmp_send_report(in_dev, im, IGMPV3_HOST_MEMBERSHIP_REPORT); - - ip_ma_put(im); -} - -/* mark EXCLUDE-mode sources */ -static int igmp_xmarksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs) -{ - struct ip_sf_list *psf; - int i, scount; - - scount = 0; - for (psf = pmc->sources; psf; psf = psf->sf_next) { - if (scount == nsrcs) - break; - for (i = 0; i < nsrcs; i++) { - /* skip inactive filters */ - if (psf->sf_count[MCAST_INCLUDE] || - pmc->sfcount[MCAST_EXCLUDE] != - psf->sf_count[MCAST_EXCLUDE]) - break; - if (srcs[i] == psf->sf_inaddr) { - scount++; - break; - } - } - } - pmc->gsquery = 0; - if (scount == nsrcs) /* all sources excluded */ - return 0; - return 1; -} - -static int igmp_marksources(struct ip_mc_list *pmc, int nsrcs, __be32 *srcs) -{ - struct ip_sf_list *psf; - int i, scount; - - if (pmc->sfmode == MCAST_EXCLUDE) - return igmp_xmarksources(pmc, nsrcs, srcs); - - /* mark INCLUDE-mode sources */ - scount = 0; - for (psf = pmc->sources; psf; psf = psf->sf_next) { - if (scount == nsrcs) - break; - for (i = 0; i < nsrcs; i++) - if (srcs[i] == psf->sf_inaddr) { - psf->sf_gsresp = 1; - scount++; - break; - } - } - if (!scount) { - pmc->gsquery = 0; - return 0; - } - pmc->gsquery = 1; - return 1; -} - -/* return true if packet was dropped */ -static bool igmp_heard_report(struct in_device *in_dev, __be32 group) -{ - struct ip_mc_list *im; - struct net *net = dev_net(in_dev->dev); - - /* Timers are only set for non-local groups */ - - if (group == IGMP_ALL_HOSTS) - return false; - if (ipv4_is_local_multicast(group) && !net->ipv4.sysctl_igmp_llm_reports) - return false; - - rcu_read_lock(); - for_each_pmc_rcu(in_dev, im) { - if (im->multiaddr == group) { - igmp_stop_timer(im); - break; - } - } - rcu_read_unlock(); - return false; -} - -/* return true if packet was dropped */ -static bool igmp_heard_query(struct in_device *in_dev, struct sk_buff *skb, - int len) -{ - struct igmphdr *ih = igmp_hdr(skb); - struct igmpv3_query *ih3 = igmpv3_query_hdr(skb); - struct ip_mc_list *im; - __be32 group = ih->group; - int max_delay; - int mark = 0; - struct net *net = dev_net(in_dev->dev); - - - if (len == 8) { - if (ih->code == 0) { - /* Alas, old v1 router presents here. */ - - max_delay = IGMP_QUERY_RESPONSE_INTERVAL; - in_dev->mr_v1_seen = jiffies + - IGMP_V1_ROUTER_PRESENT_TIMEOUT; - group = 0; - } else { - /* v2 router present */ - max_delay = ih->code*(HZ/IGMP_TIMER_SCALE); - in_dev->mr_v2_seen = jiffies + - IGMP_V2_ROUTER_PRESENT_TIMEOUT; - } - /* cancel the interface change timer */ - in_dev->mr_ifc_count = 0; - if (del_timer(&in_dev->mr_ifc_timer)) - __in_dev_put(in_dev); - /* clear deleted report items */ - igmpv3_clear_delrec(in_dev); - } else if (len < 12) { - return true; /* ignore bogus packet; freed by caller */ - } else if (IGMP_V1_SEEN(in_dev)) { - /* This is a v3 query with v1 queriers present */ - max_delay = IGMP_QUERY_RESPONSE_INTERVAL; - group = 0; - } else if (IGMP_V2_SEEN(in_dev)) { - /* this is a v3 query with v2 queriers present; - * Interpretation of the max_delay code is problematic here. - * A real v2 host would use ih_code directly, while v3 has a - * different encoding. We use the v3 encoding as more likely - * to be intended in a v3 query. - */ - max_delay = IGMPV3_MRC(ih3->code)*(HZ/IGMP_TIMER_SCALE); - if (!max_delay) - max_delay = 1; /* can't mod w/ 0 */ - } else { /* v3 */ - if (!pskb_may_pull(skb, sizeof(struct igmpv3_query))) - return true; - - ih3 = igmpv3_query_hdr(skb); - if (ih3->nsrcs) { - if (!pskb_may_pull(skb, sizeof(struct igmpv3_query) - + ntohs(ih3->nsrcs)*sizeof(__be32))) - return true; - ih3 = igmpv3_query_hdr(skb); - } - - max_delay = IGMPV3_MRC(ih3->code)*(HZ/IGMP_TIMER_SCALE); - if (!max_delay) - max_delay = 1; /* can't mod w/ 0 */ - in_dev->mr_maxdelay = max_delay; - if (ih3->qrv) - in_dev->mr_qrv = ih3->qrv; - if (!group) { /* general query */ - if (ih3->nsrcs) - return true; /* no sources allowed */ - igmp_gq_start_timer(in_dev); - return false; - } - /* mark sources to include, if group & source-specific */ - mark = ih3->nsrcs != 0; - } - - /* - * - Start the timers in all of our membership records - * that the query applies to for the interface on - * which the query arrived excl. those that belong - * to a "local" group (224.0.0.X) - * - For timers already running check if they need to - * be reset. - * - Use the igmp->igmp_code field as the maximum - * delay possible - */ - rcu_read_lock(); - for_each_pmc_rcu(in_dev, im) { - int changed; - - if (group && group != im->multiaddr) - continue; - if (im->multiaddr == IGMP_ALL_HOSTS) - continue; - if (ipv4_is_local_multicast(im->multiaddr) && - !net->ipv4.sysctl_igmp_llm_reports) - continue; - spin_lock_bh(&im->lock); - if (im->tm_running) - im->gsquery = im->gsquery && mark; - else - im->gsquery = mark; - changed = !im->gsquery || - igmp_marksources(im, ntohs(ih3->nsrcs), ih3->srcs); - spin_unlock_bh(&im->lock); - if (changed) - igmp_mod_timer(im, max_delay); - } - rcu_read_unlock(); - return false; -} - -/* called in rcu_read_lock() section */ -int igmp_rcv(struct sk_buff *skb) -{ - /* This basically follows the spec line by line -- see RFC1112 */ - struct igmphdr *ih; - struct in_device *in_dev = __in_dev_get_rcu(skb->dev); - int len = skb->len; - bool dropped = true; - - if (!in_dev) - goto drop; - - if (!pskb_may_pull(skb, sizeof(struct igmphdr))) - goto drop; - - if (skb_checksum_simple_validate(skb)) - goto drop; - - ih = igmp_hdr(skb); - switch (ih->type) { - case IGMP_HOST_MEMBERSHIP_QUERY: - dropped = igmp_heard_query(in_dev, skb, len); - break; - case IGMP_HOST_MEMBERSHIP_REPORT: - case IGMPV2_HOST_MEMBERSHIP_REPORT: - /* Is it our report looped back? */ - if (rt_is_output_route(skb_rtable(skb))) - break; - /* don't rely on MC router hearing unicast reports */ - if (skb->pkt_type == PACKET_MULTICAST || - skb->pkt_type == PACKET_BROADCAST) - dropped = igmp_heard_report(in_dev, ih->group); - break; - case IGMP_PIM: -#ifdef CONFIG_IP_PIMSM_V1 - return pim_rcv_v1(skb); -#endif - case IGMPV3_HOST_MEMBERSHIP_REPORT: - case IGMP_DVMRP: - case IGMP_TRACE: - case IGMP_HOST_LEAVE_MESSAGE: - case IGMP_MTRACE: - case IGMP_MTRACE_RESP: - break; - default: - break; - } - -drop: - if (dropped) - kfree_skb(skb); - else - consume_skb(skb); - return 0; -} - -#endif - - -/* - * Add a filter to a device - */ - -static void ip_mc_filter_add(struct in_device *in_dev, __be32 addr) -{ - char buf[MAX_ADDR_LEN]; - struct net_device *dev = in_dev->dev; - - /* Checking for IFF_MULTICAST here is WRONG-WRONG-WRONG. - We will get multicast token leakage, when IFF_MULTICAST - is changed. This check should be done in ndo_set_rx_mode - routine. Something sort of: - if (dev->mc_list && dev->flags&IFF_MULTICAST) { do it; } - --ANK - */ - if (arp_mc_map(addr, buf, dev, 0) == 0) - dev_mc_add(dev, buf); -} - -/* - * Remove a filter from a device - */ - -static void ip_mc_filter_del(struct in_device *in_dev, __be32 addr) -{ - char buf[MAX_ADDR_LEN]; - struct net_device *dev = in_dev->dev; - - if (arp_mc_map(addr, buf, dev, 0) == 0) - dev_mc_del(dev, buf); -} - -#ifdef CONFIG_IP_MULTICAST -/* - * deleted ip_mc_list manipulation - */ -static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im) -{ - struct ip_mc_list *pmc; - struct net *net = dev_net(in_dev->dev); - - /* this is an "ip_mc_list" for convenience; only the fields below - * are actually used. In particular, the refcnt and users are not - * used for management of the delete list. Using the same structure - * for deleted items allows change reports to use common code with - * non-deleted or query-response MCA's. - */ - pmc = kzalloc(sizeof(*pmc), GFP_KERNEL); - if (!pmc) - return; - spin_lock_bh(&im->lock); - pmc->interface = im->interface; - in_dev_hold(in_dev); - pmc->multiaddr = im->multiaddr; - pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv; - pmc->sfmode = im->sfmode; - if (pmc->sfmode == MCAST_INCLUDE) { - struct ip_sf_list *psf; - - pmc->tomb = im->tomb; - pmc->sources = im->sources; - im->tomb = im->sources = NULL; - for (psf = pmc->sources; psf; psf = psf->sf_next) - psf->sf_crcount = pmc->crcount; - } - spin_unlock_bh(&im->lock); - - spin_lock_bh(&in_dev->mc_tomb_lock); - pmc->next = in_dev->mc_tomb; - in_dev->mc_tomb = pmc; - spin_unlock_bh(&in_dev->mc_tomb_lock); -} - -/* - * restore ip_mc_list deleted records - */ -static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im) -{ - struct ip_mc_list *pmc, *pmc_prev; - struct ip_sf_list *psf; - struct net *net = dev_net(in_dev->dev); - __be32 multiaddr = im->multiaddr; - - spin_lock_bh(&in_dev->mc_tomb_lock); - pmc_prev = NULL; - for (pmc = in_dev->mc_tomb; pmc; pmc = pmc->next) { - if (pmc->multiaddr == multiaddr) - break; - pmc_prev = pmc; - } - if (pmc) { - if (pmc_prev) - pmc_prev->next = pmc->next; - else - in_dev->mc_tomb = pmc->next; - } - spin_unlock_bh(&in_dev->mc_tomb_lock); - - spin_lock_bh(&im->lock); - if (pmc) { - im->interface = pmc->interface; - im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv; - im->sfmode = pmc->sfmode; - if (pmc->sfmode == MCAST_INCLUDE) { - im->tomb = pmc->tomb; - im->sources = pmc->sources; - for (psf = im->sources; psf; psf = psf->sf_next) - psf->sf_crcount = im->crcount; - } - in_dev_put(pmc->interface); - } - spin_unlock_bh(&im->lock); -} - -/* - * flush ip_mc_list deleted records - */ -static void igmpv3_clear_delrec(struct in_device *in_dev) -{ - struct ip_mc_list *pmc, *nextpmc; - - spin_lock_bh(&in_dev->mc_tomb_lock); - pmc = in_dev->mc_tomb; - in_dev->mc_tomb = NULL; - spin_unlock_bh(&in_dev->mc_tomb_lock); - - for (; pmc; pmc = nextpmc) { - nextpmc = pmc->next; - ip_mc_clear_src(pmc); - in_dev_put(pmc->interface); - kfree(pmc); - } - /* clear dead sources, too */ - rcu_read_lock(); - for_each_pmc_rcu(in_dev, pmc) { - struct ip_sf_list *psf, *psf_next; - - spin_lock_bh(&pmc->lock); - psf = pmc->tomb; - pmc->tomb = NULL; - spin_unlock_bh(&pmc->lock); - for (; psf; psf = psf_next) { - psf_next = psf->sf_next; - kfree(psf); - } - } - rcu_read_unlock(); -} -#endif - -static void igmp_group_dropped(struct ip_mc_list *im) -{ - struct in_device *in_dev = im->interface; -#ifdef CONFIG_IP_MULTICAST - struct net *net = dev_net(in_dev->dev); - int reporter; -#endif - - if (im->loaded) { - im->loaded = 0; - ip_mc_filter_del(in_dev, im->multiaddr); - } - -#ifdef CONFIG_IP_MULTICAST - if (im->multiaddr == IGMP_ALL_HOSTS) - return; - if (ipv4_is_local_multicast(im->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports) - return; - - reporter = im->reporter; - igmp_stop_timer(im); - - if (!in_dev->dead) { - if (IGMP_V1_SEEN(in_dev)) - return; - if (IGMP_V2_SEEN(in_dev)) { - if (reporter) - igmp_send_report(in_dev, im, IGMP_HOST_LEAVE_MESSAGE); - return; - } - /* IGMPv3 */ - igmpv3_add_delrec(in_dev, im); - - igmp_ifc_event(in_dev); - } -#endif -} - -static void igmp_group_added(struct ip_mc_list *im) -{ - struct in_device *in_dev = im->interface; -#ifdef CONFIG_IP_MULTICAST - struct net *net = dev_net(in_dev->dev); -#endif - - if (im->loaded == 0) { - im->loaded = 1; - ip_mc_filter_add(in_dev, im->multiaddr); - } - -#ifdef CONFIG_IP_MULTICAST - if (im->multiaddr == IGMP_ALL_HOSTS) - return; - if (ipv4_is_local_multicast(im->multiaddr) && !net->ipv4.sysctl_igmp_llm_reports) - return; - - if (in_dev->dead) - return; - if (IGMP_V1_SEEN(in_dev) || IGMP_V2_SEEN(in_dev)) { - spin_lock_bh(&im->lock); - igmp_start_timer(im, IGMP_INITIAL_REPORT_DELAY); - spin_unlock_bh(&im->lock); - return; - } - /* else, v3 */ - - im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv; - igmp_ifc_event(in_dev); -#endif -} - - -/* - * Multicast list managers - */ - -static u32 ip_mc_hash(const struct ip_mc_list *im) -{ - return hash_32((__force u32)im->multiaddr, MC_HASH_SZ_LOG); -} - -static void ip_mc_hash_add(struct in_device *in_dev, - struct ip_mc_list *im) -{ - struct ip_mc_list __rcu **mc_hash; - u32 hash; - - mc_hash = rtnl_dereference(in_dev->mc_hash); - if (mc_hash) { - hash = ip_mc_hash(im); - im->next_hash = mc_hash[hash]; - rcu_assign_pointer(mc_hash[hash], im); - return; - } - - /* do not use a hash table for small number of items */ - if (in_dev->mc_count < 4) - return; - - mc_hash = kzalloc(sizeof(struct ip_mc_list *) << MC_HASH_SZ_LOG, - GFP_KERNEL); - if (!mc_hash) - return; - - for_each_pmc_rtnl(in_dev, im) { - hash = ip_mc_hash(im); - im->next_hash = mc_hash[hash]; - RCU_INIT_POINTER(mc_hash[hash], im); - } - - rcu_assign_pointer(in_dev->mc_hash, mc_hash); -} - -static void ip_mc_hash_remove(struct in_device *in_dev, - struct ip_mc_list *im) -{ - struct ip_mc_list __rcu **mc_hash = rtnl_dereference(in_dev->mc_hash); - struct ip_mc_list *aux; - - if (!mc_hash) - return; - mc_hash += ip_mc_hash(im); - while ((aux = rtnl_dereference(*mc_hash)) != im) - mc_hash = &aux->next_hash; - *mc_hash = im->next_hash; -} - - -/* - * A socket has joined a multicast group on device dev. - */ - -void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) -{ - struct ip_mc_list *im; -#ifdef CONFIG_IP_MULTICAST - struct net *net = dev_net(in_dev->dev); -#endif - - ASSERT_RTNL(); - - for_each_pmc_rtnl(in_dev, im) { - if (im->multiaddr == addr) { - im->users++; - ip_mc_add_src(in_dev, &addr, MCAST_EXCLUDE, 0, NULL, 0); - goto out; - } - } - - im = kzalloc(sizeof(*im), GFP_KERNEL); - if (!im) - goto out; - - im->users = 1; - im->interface = in_dev; - in_dev_hold(in_dev); - im->multiaddr = addr; - /* initial mode is (EX, empty) */ - im->sfmode = MCAST_EXCLUDE; - im->sfcount[MCAST_EXCLUDE] = 1; - atomic_set(&im->refcnt, 1); - spin_lock_init(&im->lock); -#ifdef CONFIG_IP_MULTICAST - setup_timer(&im->timer, igmp_timer_expire, (unsigned long)im); - im->unsolicit_count = net->ipv4.sysctl_igmp_qrv; -#endif - - im->next_rcu = in_dev->mc_list; - in_dev->mc_count++; - rcu_assign_pointer(in_dev->mc_list, im); - - ip_mc_hash_add(in_dev, im); - -#ifdef CONFIG_IP_MULTICAST - igmpv3_del_delrec(in_dev, im); -#endif - igmp_group_added(im); - if (!in_dev->dead) - ip_rt_multicast_event(in_dev); -out: - return; -} -EXPORT_SYMBOL(ip_mc_inc_group); - -static int ip_mc_check_iphdr(struct sk_buff *skb) -{ - const struct iphdr *iph; - unsigned int len; - unsigned int offset = skb_network_offset(skb) + sizeof(*iph); - - if (!pskb_may_pull(skb, offset)) - return -EINVAL; - - iph = ip_hdr(skb); - - if (iph->version != 4 || ip_hdrlen(skb) < sizeof(*iph)) - return -EINVAL; - - offset += ip_hdrlen(skb) - sizeof(*iph); - - if (!pskb_may_pull(skb, offset)) - return -EINVAL; - - iph = ip_hdr(skb); - - if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl))) - return -EINVAL; - - len = skb_network_offset(skb) + ntohs(iph->tot_len); - if (skb->len < len || len < offset) - return -EINVAL; - - skb_set_transport_header(skb, offset); - - return 0; -} - -static int ip_mc_check_igmp_reportv3(struct sk_buff *skb) -{ - unsigned int len = skb_transport_offset(skb); - - len += sizeof(struct igmpv3_report); - - return pskb_may_pull(skb, len) ? 0 : -EINVAL; -} - -static int ip_mc_check_igmp_query(struct sk_buff *skb) -{ - unsigned int len = skb_transport_offset(skb); - - len += sizeof(struct igmphdr); - if (skb->len < len) - return -EINVAL; - - /* IGMPv{1,2}? */ - if (skb->len != len) { - /* or IGMPv3? */ - len += sizeof(struct igmpv3_query) - sizeof(struct igmphdr); - if (skb->len < len || !pskb_may_pull(skb, len)) - return -EINVAL; - } - - /* RFC2236+RFC3376 (IGMPv2+IGMPv3) require the multicast link layer - * all-systems destination addresses (224.0.0.1) for general queries - */ - if (!igmp_hdr(skb)->group && - ip_hdr(skb)->daddr != htonl(INADDR_ALLHOSTS_GROUP)) - return -EINVAL; - - return 0; -} - -static int ip_mc_check_igmp_msg(struct sk_buff *skb) -{ - switch (igmp_hdr(skb)->type) { - case IGMP_HOST_LEAVE_MESSAGE: - case IGMP_HOST_MEMBERSHIP_REPORT: - case IGMPV2_HOST_MEMBERSHIP_REPORT: - /* fall through */ - return 0; - case IGMPV3_HOST_MEMBERSHIP_REPORT: - return ip_mc_check_igmp_reportv3(skb); - case IGMP_HOST_MEMBERSHIP_QUERY: - return ip_mc_check_igmp_query(skb); - default: - return -ENOMSG; - } -} - -static inline __sum16 ip_mc_validate_checksum(struct sk_buff *skb) -{ - return skb_checksum_simple_validate(skb); -} - -static int __ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed) - -{ - struct sk_buff *skb_chk; - unsigned int transport_len; - unsigned int len = skb_transport_offset(skb) + sizeof(struct igmphdr); - int ret = -EINVAL; - - transport_len = ntohs(ip_hdr(skb)->tot_len) - ip_hdrlen(skb); - - skb_chk = skb_checksum_trimmed(skb, transport_len, - ip_mc_validate_checksum); - if (!skb_chk) - goto err; - - if (!pskb_may_pull(skb_chk, len)) - goto err; - - ret = ip_mc_check_igmp_msg(skb_chk); - if (ret) - goto err; - - if (skb_trimmed) - *skb_trimmed = skb_chk; - /* free now unneeded clone */ - else if (skb_chk != skb) - kfree_skb(skb_chk); - - ret = 0; - -err: - if (ret && skb_chk && skb_chk != skb) - kfree_skb(skb_chk); - - return ret; -} - -/** - * ip_mc_check_igmp - checks whether this is a sane IGMP packet - * @skb: the skb to validate - * @skb_trimmed: to store an skb pointer trimmed to IPv4 packet tail (optional) - * - * Checks whether an IPv4 packet is a valid IGMP packet. If so sets - * skb transport header accordingly and returns zero. - * - * -EINVAL: A broken packet was detected, i.e. it violates some internet - * standard - * -ENOMSG: IP header validation succeeded but it is not an IGMP packet. - * -ENOMEM: A memory allocation failure happened. - * - * Optionally, an skb pointer might be provided via skb_trimmed (or set it - * to NULL): After parsing an IGMP packet successfully it will point to - * an skb which has its tail aligned to the IP packet end. This might - * either be the originally provided skb or a trimmed, cloned version if - * the skb frame had data beyond the IP packet. A cloned skb allows us - * to leave the original skb and its full frame unchanged (which might be - * desirable for layer 2 frame jugglers). - * - * Caller needs to set the skb network header and free any returned skb if it - * differs from the provided skb. - */ -int ip_mc_check_igmp(struct sk_buff *skb, struct sk_buff **skb_trimmed) -{ - int ret = ip_mc_check_iphdr(skb); - - if (ret < 0) - return ret; - - if (ip_hdr(skb)->protocol != IPPROTO_IGMP) - return -ENOMSG; - - return __ip_mc_check_igmp(skb, skb_trimmed); -} -EXPORT_SYMBOL(ip_mc_check_igmp); - -/* - * Resend IGMP JOIN report; used by netdev notifier. - */ -static void ip_mc_rejoin_groups(struct in_device *in_dev) -{ -#ifdef CONFIG_IP_MULTICAST - struct ip_mc_list *im; - int type; - struct net *net = dev_net(in_dev->dev); - - ASSERT_RTNL(); - - for_each_pmc_rtnl(in_dev, im) { - if (im->multiaddr == IGMP_ALL_HOSTS) - continue; - if (ipv4_is_local_multicast(im->multiaddr) && - !net->ipv4.sysctl_igmp_llm_reports) - continue; - - /* a failover is happening and switches - * must be notified immediately - */ - if (IGMP_V1_SEEN(in_dev)) - type = IGMP_HOST_MEMBERSHIP_REPORT; - else if (IGMP_V2_SEEN(in_dev)) - type = IGMPV2_HOST_MEMBERSHIP_REPORT; - else - type = IGMPV3_HOST_MEMBERSHIP_REPORT; - igmp_send_report(in_dev, im, type); - } -#endif -} - -/* - * A socket has left a multicast group on device dev - */ - -void ip_mc_dec_group(struct in_device *in_dev, __be32 addr) -{ - struct ip_mc_list *i; - struct ip_mc_list __rcu **ip; - - ASSERT_RTNL(); - - for (ip = &in_dev->mc_list; - (i = rtnl_dereference(*ip)) != NULL; - ip = &i->next_rcu) { - if (i->multiaddr == addr) { - if (--i->users == 0) { - ip_mc_hash_remove(in_dev, i); - *ip = i->next_rcu; - in_dev->mc_count--; - igmp_group_dropped(i); - ip_mc_clear_src(i); - - if (!in_dev->dead) - ip_rt_multicast_event(in_dev); - - ip_ma_put(i); - return; - } - break; - } - } -} -EXPORT_SYMBOL(ip_mc_dec_group); - -/* Device changing type */ - -void ip_mc_unmap(struct in_device *in_dev) -{ - struct ip_mc_list *pmc; - - ASSERT_RTNL(); - - for_each_pmc_rtnl(in_dev, pmc) - igmp_group_dropped(pmc); -} - -void ip_mc_remap(struct in_device *in_dev) -{ - struct ip_mc_list *pmc; - - ASSERT_RTNL(); - - for_each_pmc_rtnl(in_dev, pmc) { -#ifdef CONFIG_IP_MULTICAST - igmpv3_del_delrec(in_dev, pmc); -#endif - igmp_group_added(pmc); - } -} - -/* Device going down */ - -void ip_mc_down(struct in_device *in_dev) -{ - struct ip_mc_list *pmc; - - ASSERT_RTNL(); - - for_each_pmc_rtnl(in_dev, pmc) - igmp_group_dropped(pmc); - -#ifdef CONFIG_IP_MULTICAST - in_dev->mr_ifc_count = 0; - if (del_timer(&in_dev->mr_ifc_timer)) - __in_dev_put(in_dev); - in_dev->mr_gq_running = 0; - if (del_timer(&in_dev->mr_gq_timer)) - __in_dev_put(in_dev); -#endif - - ip_mc_dec_group(in_dev, IGMP_ALL_HOSTS); -} - -void ip_mc_init_dev(struct in_device *in_dev) -{ -#ifdef CONFIG_IP_MULTICAST - struct net *net = dev_net(in_dev->dev); -#endif - ASSERT_RTNL(); - -#ifdef CONFIG_IP_MULTICAST - setup_timer(&in_dev->mr_gq_timer, igmp_gq_timer_expire, - (unsigned long)in_dev); - setup_timer(&in_dev->mr_ifc_timer, igmp_ifc_timer_expire, - (unsigned long)in_dev); - in_dev->mr_qrv = net->ipv4.sysctl_igmp_qrv; -#endif - - spin_lock_init(&in_dev->mc_tomb_lock); -} - -/* Device going up */ - -void ip_mc_up(struct in_device *in_dev) -{ - struct ip_mc_list *pmc; -#ifdef CONFIG_IP_MULTICAST - struct net *net = dev_net(in_dev->dev); -#endif - - ASSERT_RTNL(); - -#ifdef CONFIG_IP_MULTICAST - in_dev->mr_qrv = net->ipv4.sysctl_igmp_qrv; -#endif - ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS); - - for_each_pmc_rtnl(in_dev, pmc) { -#ifdef CONFIG_IP_MULTICAST - igmpv3_del_delrec(in_dev, pmc); -#endif - igmp_group_added(pmc); - } -} - -/* - * Device is about to be destroyed: clean up. - */ - -void ip_mc_destroy_dev(struct in_device *in_dev) -{ - struct ip_mc_list *i; - - ASSERT_RTNL(); - - /* Deactivate timers */ - ip_mc_down(in_dev); -#ifdef CONFIG_IP_MULTICAST - igmpv3_clear_delrec(in_dev); -#endif - - while ((i = rtnl_dereference(in_dev->mc_list)) != NULL) { - in_dev->mc_list = i->next_rcu; - in_dev->mc_count--; - ip_ma_put(i); - } -} - -/* RTNL is locked */ -static struct in_device *ip_mc_find_dev(struct net *net, struct ip_mreqn *imr) -{ - struct net_device *dev = NULL; - struct in_device *idev = NULL; - - if (imr->imr_ifindex) { - idev = inetdev_by_index(net, imr->imr_ifindex); - return idev; - } - if (imr->imr_address.s_addr) { - dev = __ip_dev_find(net, imr->imr_address.s_addr, false); - if (!dev) - return NULL; - } - - if (!dev) { - struct rtable *rt = ip_route_output(net, - imr->imr_multiaddr.s_addr, - 0, 0, 0); - if (!IS_ERR(rt)) { - dev = rt->dst.dev; - ip_rt_put(rt); - } - } - if (dev) { - imr->imr_ifindex = dev->ifindex; - idev = __in_dev_get_rtnl(dev); - } - return idev; -} - -/* - * Join a socket to a group - */ - -static int ip_mc_del1_src(struct ip_mc_list *pmc, int sfmode, - __be32 *psfsrc) -{ - struct ip_sf_list *psf, *psf_prev; - int rv = 0; - - psf_prev = NULL; - for (psf = pmc->sources; psf; psf = psf->sf_next) { - if (psf->sf_inaddr == *psfsrc) - break; - psf_prev = psf; - } - if (!psf || psf->sf_count[sfmode] == 0) { - /* source filter not found, or count wrong => bug */ - return -ESRCH; - } - psf->sf_count[sfmode]--; - if (psf->sf_count[sfmode] == 0) { - ip_rt_multicast_event(pmc->interface); - } - if (!psf->sf_count[MCAST_INCLUDE] && !psf->sf_count[MCAST_EXCLUDE]) { -#ifdef CONFIG_IP_MULTICAST - struct in_device *in_dev = pmc->interface; - struct net *net = dev_net(in_dev->dev); -#endif - - /* no more filters for this source */ - if (psf_prev) - psf_prev->sf_next = psf->sf_next; - else - pmc->sources = psf->sf_next; -#ifdef CONFIG_IP_MULTICAST - if (psf->sf_oldin && - !IGMP_V1_SEEN(in_dev) && !IGMP_V2_SEEN(in_dev)) { - psf->sf_crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv; - psf->sf_next = pmc->tomb; - pmc->tomb = psf; - rv = 1; - } else -#endif - kfree(psf); - } - return rv; -} - -#ifndef CONFIG_IP_MULTICAST -#define igmp_ifc_event(x) do { } while (0) -#endif - -static int ip_mc_del_src(struct in_device *in_dev, __be32 *pmca, int sfmode, - int sfcount, __be32 *psfsrc, int delta) -{ - struct ip_mc_list *pmc; - int changerec = 0; - int i, err; - - if (!in_dev) - return -ENODEV; - rcu_read_lock(); - for_each_pmc_rcu(in_dev, pmc) { - if (*pmca == pmc->multiaddr) - break; - } - if (!pmc) { - /* MCA not found?? bug */ - rcu_read_unlock(); - return -ESRCH; - } - spin_lock_bh(&pmc->lock); - rcu_read_unlock(); -#ifdef CONFIG_IP_MULTICAST - sf_markstate(pmc); -#endif - if (!delta) { - err = -EINVAL; - if (!pmc->sfcount[sfmode]) - goto out_unlock; - pmc->sfcount[sfmode]--; - } - err = 0; - for (i = 0; i < sfcount; i++) { - int rv = ip_mc_del1_src(pmc, sfmode, &psfsrc[i]); - - changerec |= rv > 0; - if (!err && rv < 0) - err = rv; - } - if (pmc->sfmode == MCAST_EXCLUDE && - pmc->sfcount[MCAST_EXCLUDE] == 0 && - pmc->sfcount[MCAST_INCLUDE]) { -#ifdef CONFIG_IP_MULTICAST - struct ip_sf_list *psf; - struct net *net = dev_net(in_dev->dev); -#endif - - /* filter mode change */ - pmc->sfmode = MCAST_INCLUDE; -#ifdef CONFIG_IP_MULTICAST - pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv; - in_dev->mr_ifc_count = pmc->crcount; - for (psf = pmc->sources; psf; psf = psf->sf_next) - psf->sf_crcount = 0; - igmp_ifc_event(pmc->interface); - } else if (sf_setstate(pmc) || changerec) { - igmp_ifc_event(pmc->interface); -#endif - } -out_unlock: - spin_unlock_bh(&pmc->lock); - return err; -} - -/* - * Add multicast single-source filter to the interface list - */ -static int ip_mc_add1_src(struct ip_mc_list *pmc, int sfmode, - __be32 *psfsrc) -{ - struct ip_sf_list *psf, *psf_prev; - - psf_prev = NULL; - for (psf = pmc->sources; psf; psf = psf->sf_next) { - if (psf->sf_inaddr == *psfsrc) - break; - psf_prev = psf; - } - if (!psf) { - psf = kzalloc(sizeof(*psf), GFP_ATOMIC); - if (!psf) - return -ENOBUFS; - psf->sf_inaddr = *psfsrc; - if (psf_prev) { - psf_prev->sf_next = psf; - } else - pmc->sources = psf; - } - psf->sf_count[sfmode]++; - if (psf->sf_count[sfmode] == 1) { - ip_rt_multicast_event(pmc->interface); - } - return 0; -} - -#ifdef CONFIG_IP_MULTICAST -static void sf_markstate(struct ip_mc_list *pmc) -{ - struct ip_sf_list *psf; - int mca_xcount = pmc->sfcount[MCAST_EXCLUDE]; - - for (psf = pmc->sources; psf; psf = psf->sf_next) - if (pmc->sfcount[MCAST_EXCLUDE]) { - psf->sf_oldin = mca_xcount == - psf->sf_count[MCAST_EXCLUDE] && - !psf->sf_count[MCAST_INCLUDE]; - } else - psf->sf_oldin = psf->sf_count[MCAST_INCLUDE] != 0; -} - -static int sf_setstate(struct ip_mc_list *pmc) -{ - struct ip_sf_list *psf, *dpsf; - int mca_xcount = pmc->sfcount[MCAST_EXCLUDE]; - int qrv = pmc->interface->mr_qrv; - int new_in, rv; - - rv = 0; - for (psf = pmc->sources; psf; psf = psf->sf_next) { - if (pmc->sfcount[MCAST_EXCLUDE]) { - new_in = mca_xcount == psf->sf_count[MCAST_EXCLUDE] && - !psf->sf_count[MCAST_INCLUDE]; - } else - new_in = psf->sf_count[MCAST_INCLUDE] != 0; - if (new_in) { - if (!psf->sf_oldin) { - struct ip_sf_list *prev = NULL; - - for (dpsf = pmc->tomb; dpsf; dpsf = dpsf->sf_next) { - if (dpsf->sf_inaddr == psf->sf_inaddr) - break; - prev = dpsf; - } - if (dpsf) { - if (prev) - prev->sf_next = dpsf->sf_next; - else - pmc->tomb = dpsf->sf_next; - kfree(dpsf); - } - psf->sf_crcount = qrv; - rv++; - } - } else if (psf->sf_oldin) { - - psf->sf_crcount = 0; - /* - * add or update "delete" records if an active filter - * is now inactive - */ - for (dpsf = pmc->tomb; dpsf; dpsf = dpsf->sf_next) - if (dpsf->sf_inaddr == psf->sf_inaddr) - break; - if (!dpsf) { - dpsf = kmalloc(sizeof(*dpsf), GFP_ATOMIC); - if (!dpsf) - continue; - *dpsf = *psf; - /* pmc->lock held by callers */ - dpsf->sf_next = pmc->tomb; - pmc->tomb = dpsf; - } - dpsf->sf_crcount = qrv; - rv++; - } - } - return rv; -} -#endif - -/* - * Add multicast source filter list to the interface list - */ -static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode, - int sfcount, __be32 *psfsrc, int delta) -{ - struct ip_mc_list *pmc; - int isexclude; - int i, err; - - if (!in_dev) - return -ENODEV; - rcu_read_lock(); - for_each_pmc_rcu(in_dev, pmc) { - if (*pmca == pmc->multiaddr) - break; - } - if (!pmc) { - /* MCA not found?? bug */ - rcu_read_unlock(); - return -ESRCH; - } - spin_lock_bh(&pmc->lock); - rcu_read_unlock(); - -#ifdef CONFIG_IP_MULTICAST - sf_markstate(pmc); -#endif - isexclude = pmc->sfmode == MCAST_EXCLUDE; - if (!delta) - pmc->sfcount[sfmode]++; - err = 0; - for (i = 0; i < sfcount; i++) { - err = ip_mc_add1_src(pmc, sfmode, &psfsrc[i]); - if (err) - break; - } - if (err) { - int j; - - if (!delta) - pmc->sfcount[sfmode]--; - for (j = 0; j < i; j++) - (void) ip_mc_del1_src(pmc, sfmode, &psfsrc[j]); - } else if (isexclude != (pmc->sfcount[MCAST_EXCLUDE] != 0)) { -#ifdef CONFIG_IP_MULTICAST - struct ip_sf_list *psf; - struct net *net = dev_net(pmc->interface->dev); - in_dev = pmc->interface; -#endif - - /* filter mode change */ - if (pmc->sfcount[MCAST_EXCLUDE]) - pmc->sfmode = MCAST_EXCLUDE; - else if (pmc->sfcount[MCAST_INCLUDE]) - pmc->sfmode = MCAST_INCLUDE; -#ifdef CONFIG_IP_MULTICAST - /* else no filters; keep old mode for reports */ - - pmc->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv; - in_dev->mr_ifc_count = pmc->crcount; - for (psf = pmc->sources; psf; psf = psf->sf_next) - psf->sf_crcount = 0; - igmp_ifc_event(in_dev); - } else if (sf_setstate(pmc)) { - igmp_ifc_event(in_dev); -#endif - } - spin_unlock_bh(&pmc->lock); - return err; -} - -static void ip_mc_clear_src(struct ip_mc_list *pmc) -{ - struct ip_sf_list *psf, *nextpsf; - - for (psf = pmc->tomb; psf; psf = nextpsf) { - nextpsf = psf->sf_next; - kfree(psf); - } - pmc->tomb = NULL; - for (psf = pmc->sources; psf; psf = nextpsf) { - nextpsf = psf->sf_next; - kfree(psf); - } - pmc->sources = NULL; - pmc->sfmode = MCAST_EXCLUDE; - pmc->sfcount[MCAST_INCLUDE] = 0; - pmc->sfcount[MCAST_EXCLUDE] = 1; -} - -/* Join a multicast group - */ - -int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr) -{ - __be32 addr = imr->imr_multiaddr.s_addr; - struct ip_mc_socklist *iml, *i; - struct in_device *in_dev; - struct inet_sock *inet = inet_sk(sk); - struct net *net = sock_net(sk); - int ifindex; - int count = 0; - int err; - - ASSERT_RTNL(); - - if (!ipv4_is_multicast(addr)) - return -EINVAL; - - in_dev = ip_mc_find_dev(net, imr); - - if (!in_dev) { - err = -ENODEV; - goto done; - } - - err = -EADDRINUSE; - ifindex = imr->imr_ifindex; - for_each_pmc_rtnl(inet, i) { - if (i->multi.imr_multiaddr.s_addr == addr && - i->multi.imr_ifindex == ifindex) - goto done; - count++; - } - err = -ENOBUFS; - if (count >= net->ipv4.sysctl_igmp_max_memberships) - goto done; - iml = sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL); - if (!iml) - goto done; - - memcpy(&iml->multi, imr, sizeof(*imr)); - iml->next_rcu = inet->mc_list; - iml->sflist = NULL; - iml->sfmode = MCAST_EXCLUDE; - rcu_assign_pointer(inet->mc_list, iml); - ip_mc_inc_group(in_dev, addr); - err = 0; -done: - return err; -} -EXPORT_SYMBOL(ip_mc_join_group); - -static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, - struct in_device *in_dev) -{ - struct ip_sf_socklist *psf = rtnl_dereference(iml->sflist); - int err; - - if (!psf) { - /* any-source empty exclude case */ - return ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr, - iml->sfmode, 0, NULL, 0); - } - err = ip_mc_del_src(in_dev, &iml->multi.imr_multiaddr.s_addr, - iml->sfmode, psf->sl_count, psf->sl_addr, 0); - RCU_INIT_POINTER(iml->sflist, NULL); - /* decrease mem now to avoid the memleak warning */ - atomic_sub(IP_SFLSIZE(psf->sl_max), &sk->sk_omem_alloc); - kfree_rcu(psf, rcu); - return err; -} - -int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr) -{ - struct inet_sock *inet = inet_sk(sk); - struct ip_mc_socklist *iml; - struct ip_mc_socklist __rcu **imlp; - struct in_device *in_dev; - struct net *net = sock_net(sk); - __be32 group = imr->imr_multiaddr.s_addr; - u32 ifindex; - int ret = -EADDRNOTAVAIL; - - ASSERT_RTNL(); - - in_dev = ip_mc_find_dev(net, imr); - if (!imr->imr_ifindex && !imr->imr_address.s_addr && !in_dev) { - ret = -ENODEV; - goto out; - } - ifindex = imr->imr_ifindex; - for (imlp = &inet->mc_list; - (iml = rtnl_dereference(*imlp)) != NULL; - imlp = &iml->next_rcu) { - if (iml->multi.imr_multiaddr.s_addr != group) - continue; - if (ifindex) { - if (iml->multi.imr_ifindex != ifindex) - continue; - } else if (imr->imr_address.s_addr && imr->imr_address.s_addr != - iml->multi.imr_address.s_addr) - continue; - - (void) ip_mc_leave_src(sk, iml, in_dev); - - *imlp = iml->next_rcu; - - if (in_dev) - ip_mc_dec_group(in_dev, group); - - /* decrease mem now to avoid the memleak warning */ - atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); - kfree_rcu(iml, rcu); - return 0; - } -out: - return ret; -} -EXPORT_SYMBOL(ip_mc_leave_group); - -int ip_mc_source(int add, int omode, struct sock *sk, struct - ip_mreq_source *mreqs, int ifindex) -{ - int err; - struct ip_mreqn imr; - __be32 addr = mreqs->imr_multiaddr; - struct ip_mc_socklist *pmc; - struct in_device *in_dev = NULL; - struct inet_sock *inet = inet_sk(sk); - struct ip_sf_socklist *psl; - struct net *net = sock_net(sk); - int leavegroup = 0; - int i, j, rv; - - if (!ipv4_is_multicast(addr)) - return -EINVAL; - - ASSERT_RTNL(); - - imr.imr_multiaddr.s_addr = mreqs->imr_multiaddr; - imr.imr_address.s_addr = mreqs->imr_interface; - imr.imr_ifindex = ifindex; - in_dev = ip_mc_find_dev(net, &imr); - - if (!in_dev) { - err = -ENODEV; - goto done; - } - err = -EADDRNOTAVAIL; - - for_each_pmc_rtnl(inet, pmc) { - if ((pmc->multi.imr_multiaddr.s_addr == - imr.imr_multiaddr.s_addr) && - (pmc->multi.imr_ifindex == imr.imr_ifindex)) - break; - } - if (!pmc) { /* must have a prior join */ - err = -EINVAL; - goto done; - } - /* if a source filter was set, must be the same mode as before */ - if (pmc->sflist) { - if (pmc->sfmode != omode) { - err = -EINVAL; - goto done; - } - } else if (pmc->sfmode != omode) { - /* allow mode switches for empty-set filters */ - ip_mc_add_src(in_dev, &mreqs->imr_multiaddr, omode, 0, NULL, 0); - ip_mc_del_src(in_dev, &mreqs->imr_multiaddr, pmc->sfmode, 0, - NULL, 0); - pmc->sfmode = omode; - } - - psl = rtnl_dereference(pmc->sflist); - if (!add) { - if (!psl) - goto done; /* err = -EADDRNOTAVAIL */ - rv = !0; - for (i = 0; i < psl->sl_count; i++) { - rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr, - sizeof(__be32)); - if (rv == 0) - break; - } - if (rv) /* source not found */ - goto done; /* err = -EADDRNOTAVAIL */ - - /* special case - (INCLUDE, empty) == LEAVE_GROUP */ - if (psl->sl_count == 1 && omode == MCAST_INCLUDE) { - leavegroup = 1; - goto done; - } - - /* update the interface filter */ - ip_mc_del_src(in_dev, &mreqs->imr_multiaddr, omode, 1, - &mreqs->imr_sourceaddr, 1); - - for (j = i+1; j < psl->sl_count; j++) - psl->sl_addr[j-1] = psl->sl_addr[j]; - psl->sl_count--; - err = 0; - goto done; - } - /* else, add a new source to the filter */ - - if (psl && psl->sl_count >= net->ipv4.sysctl_igmp_max_msf) { - err = -ENOBUFS; - goto done; - } - if (!psl || psl->sl_count == psl->sl_max) { - struct ip_sf_socklist *newpsl; - int count = IP_SFBLOCK; - - if (psl) - count += psl->sl_max; - newpsl = sock_kmalloc(sk, IP_SFLSIZE(count), GFP_KERNEL); - if (!newpsl) { - err = -ENOBUFS; - goto done; - } - newpsl->sl_max = count; - newpsl->sl_count = count - IP_SFBLOCK; - if (psl) { - for (i = 0; i < psl->sl_count; i++) - newpsl->sl_addr[i] = psl->sl_addr[i]; - /* decrease mem now to avoid the memleak warning */ - atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); - kfree_rcu(psl, rcu); - } - rcu_assign_pointer(pmc->sflist, newpsl); - psl = newpsl; - } - rv = 1; /* > 0 for insert logic below if sl_count is 0 */ - for (i = 0; i < psl->sl_count; i++) { - rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr, - sizeof(__be32)); - if (rv == 0) - break; - } - if (rv == 0) /* address already there is an error */ - goto done; - for (j = psl->sl_count-1; j >= i; j--) - psl->sl_addr[j+1] = psl->sl_addr[j]; - psl->sl_addr[i] = mreqs->imr_sourceaddr; - psl->sl_count++; - err = 0; - /* update the interface list */ - ip_mc_add_src(in_dev, &mreqs->imr_multiaddr, omode, 1, - &mreqs->imr_sourceaddr, 1); -done: - if (leavegroup) - err = ip_mc_leave_group(sk, &imr); - return err; -} - -int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex) -{ - int err = 0; - struct ip_mreqn imr; - __be32 addr = msf->imsf_multiaddr; - struct ip_mc_socklist *pmc; - struct in_device *in_dev; - struct inet_sock *inet = inet_sk(sk); - struct ip_sf_socklist *newpsl, *psl; - struct net *net = sock_net(sk); - int leavegroup = 0; - - if (!ipv4_is_multicast(addr)) - return -EINVAL; - if (msf->imsf_fmode != MCAST_INCLUDE && - msf->imsf_fmode != MCAST_EXCLUDE) - return -EINVAL; - - ASSERT_RTNL(); - - imr.imr_multiaddr.s_addr = msf->imsf_multiaddr; - imr.imr_address.s_addr = msf->imsf_interface; - imr.imr_ifindex = ifindex; - in_dev = ip_mc_find_dev(net, &imr); - - if (!in_dev) { - err = -ENODEV; - goto done; - } - - /* special case - (INCLUDE, empty) == LEAVE_GROUP */ - if (msf->imsf_fmode == MCAST_INCLUDE && msf->imsf_numsrc == 0) { - leavegroup = 1; - goto done; - } - - for_each_pmc_rtnl(inet, pmc) { - if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr && - pmc->multi.imr_ifindex == imr.imr_ifindex) - break; - } - if (!pmc) { /* must have a prior join */ - err = -EINVAL; - goto done; - } - if (msf->imsf_numsrc) { - newpsl = sock_kmalloc(sk, IP_SFLSIZE(msf->imsf_numsrc), - GFP_KERNEL); - if (!newpsl) { - err = -ENOBUFS; - goto done; - } - newpsl->sl_max = newpsl->sl_count = msf->imsf_numsrc; - memcpy(newpsl->sl_addr, msf->imsf_slist, - msf->imsf_numsrc * sizeof(msf->imsf_slist[0])); - err = ip_mc_add_src(in_dev, &msf->imsf_multiaddr, - msf->imsf_fmode, newpsl->sl_count, newpsl->sl_addr, 0); - if (err) { - sock_kfree_s(sk, newpsl, IP_SFLSIZE(newpsl->sl_max)); - goto done; - } - } else { - newpsl = NULL; - (void) ip_mc_add_src(in_dev, &msf->imsf_multiaddr, - msf->imsf_fmode, 0, NULL, 0); - } - psl = rtnl_dereference(pmc->sflist); - if (psl) { - (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, - psl->sl_count, psl->sl_addr, 0); - /* decrease mem now to avoid the memleak warning */ - atomic_sub(IP_SFLSIZE(psl->sl_max), &sk->sk_omem_alloc); - kfree_rcu(psl, rcu); - } else - (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, - 0, NULL, 0); - rcu_assign_pointer(pmc->sflist, newpsl); - pmc->sfmode = msf->imsf_fmode; - err = 0; -done: - if (leavegroup) - err = ip_mc_leave_group(sk, &imr); - return err; -} - -int ip_mc_msfget(struct sock *sk, struct ip_msfilter *msf, - struct ip_msfilter __user *optval, int __user *optlen) -{ - int err, len, count, copycount; - struct ip_mreqn imr; - __be32 addr = msf->imsf_multiaddr; - struct ip_mc_socklist *pmc; - struct in_device *in_dev; - struct inet_sock *inet = inet_sk(sk); - struct ip_sf_socklist *psl; - struct net *net = sock_net(sk); - - ASSERT_RTNL(); - - if (!ipv4_is_multicast(addr)) - return -EINVAL; - - imr.imr_multiaddr.s_addr = msf->imsf_multiaddr; - imr.imr_address.s_addr = msf->imsf_interface; - imr.imr_ifindex = 0; - in_dev = ip_mc_find_dev(net, &imr); - - if (!in_dev) { - err = -ENODEV; - goto done; - } - err = -EADDRNOTAVAIL; - - for_each_pmc_rtnl(inet, pmc) { - if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr && - pmc->multi.imr_ifindex == imr.imr_ifindex) - break; - } - if (!pmc) /* must have a prior join */ - goto done; - msf->imsf_fmode = pmc->sfmode; - psl = rtnl_dereference(pmc->sflist); - if (!psl) { - len = 0; - count = 0; - } else { - count = psl->sl_count; - } - copycount = count < msf->imsf_numsrc ? count : msf->imsf_numsrc; - len = copycount * sizeof(psl->sl_addr[0]); - msf->imsf_numsrc = count; - if (put_user(IP_MSFILTER_SIZE(copycount), optlen) || - copy_to_user(optval, msf, IP_MSFILTER_SIZE(0))) { - return -EFAULT; - } - if (len && - copy_to_user(&optval->imsf_slist[0], psl->sl_addr, len)) - return -EFAULT; - return 0; -done: - return err; -} - -int ip_mc_gsfget(struct sock *sk, struct group_filter *gsf, - struct group_filter __user *optval, int __user *optlen) -{ - int err, i, count, copycount; - struct sockaddr_in *psin; - __be32 addr; - struct ip_mc_socklist *pmc; - struct inet_sock *inet = inet_sk(sk); - struct ip_sf_socklist *psl; - - ASSERT_RTNL(); - - psin = (struct sockaddr_in *)&gsf->gf_group; - if (psin->sin_family != AF_INET) - return -EINVAL; - addr = psin->sin_addr.s_addr; - if (!ipv4_is_multicast(addr)) - return -EINVAL; - - err = -EADDRNOTAVAIL; - - for_each_pmc_rtnl(inet, pmc) { - if (pmc->multi.imr_multiaddr.s_addr == addr && - pmc->multi.imr_ifindex == gsf->gf_interface) - break; - } - if (!pmc) /* must have a prior join */ - goto done; - gsf->gf_fmode = pmc->sfmode; - psl = rtnl_dereference(pmc->sflist); - count = psl ? psl->sl_count : 0; - copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc; - gsf->gf_numsrc = count; - if (put_user(GROUP_FILTER_SIZE(copycount), optlen) || - copy_to_user(optval, gsf, GROUP_FILTER_SIZE(0))) { - return -EFAULT; - } - for (i = 0; i < copycount; i++) { - struct sockaddr_storage ss; - - psin = (struct sockaddr_in *)&ss; - memset(&ss, 0, sizeof(ss)); - psin->sin_family = AF_INET; - psin->sin_addr.s_addr = psl->sl_addr[i]; - if (copy_to_user(&optval->gf_slist[i], &ss, sizeof(ss))) - return -EFAULT; - } - return 0; -done: - return err; -} - -/* - * check if a multicast source filter allows delivery for a given - */ -int ip_mc_sf_allow(struct sock *sk, __be32 loc_addr, __be32 rmt_addr, int dif) -{ - struct inet_sock *inet = inet_sk(sk); - struct ip_mc_socklist *pmc; - struct ip_sf_socklist *psl; - int i; - int ret; - - ret = 1; - if (!ipv4_is_multicast(loc_addr)) - goto out; - - rcu_read_lock(); - for_each_pmc_rcu(inet, pmc) { - if (pmc->multi.imr_multiaddr.s_addr == loc_addr && - pmc->multi.imr_ifindex == dif) - break; - } - ret = inet->mc_all; - if (!pmc) - goto unlock; - psl = rcu_dereference(pmc->sflist); - ret = (pmc->sfmode == MCAST_EXCLUDE); - if (!psl) - goto unlock; - - for (i = 0; i < psl->sl_count; i++) { - if (psl->sl_addr[i] == rmt_addr) - break; - } - ret = 0; - if (pmc->sfmode == MCAST_INCLUDE && i >= psl->sl_count) - goto unlock; - if (pmc->sfmode == MCAST_EXCLUDE && i < psl->sl_count) - goto unlock; - ret = 1; -unlock: - rcu_read_unlock(); -out: - return ret; -} - -/* - * A socket is closing. - */ - -void ip_mc_drop_socket(struct sock *sk) -{ - struct inet_sock *inet = inet_sk(sk); - struct ip_mc_socklist *iml; - struct net *net = sock_net(sk); - - if (!inet->mc_list) - return; - - rtnl_lock(); - while ((iml = rtnl_dereference(inet->mc_list)) != NULL) { - struct in_device *in_dev; - - inet->mc_list = iml->next_rcu; - in_dev = inetdev_by_index(net, iml->multi.imr_ifindex); - (void) ip_mc_leave_src(sk, iml, in_dev); - if (in_dev) - ip_mc_dec_group(in_dev, iml->multi.imr_multiaddr.s_addr); - /* decrease mem now to avoid the memleak warning */ - atomic_sub(sizeof(*iml), &sk->sk_omem_alloc); - kfree_rcu(iml, rcu); - } - rtnl_unlock(); -} - -/* called with rcu_read_lock() */ -int ip_check_mc_rcu(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u8 proto) -{ - struct ip_mc_list *im; - struct ip_mc_list __rcu **mc_hash; - struct ip_sf_list *psf; - int rv = 0; - - mc_hash = rcu_dereference(in_dev->mc_hash); - if (mc_hash) { - u32 hash = hash_32((__force u32)mc_addr, MC_HASH_SZ_LOG); - - for (im = rcu_dereference(mc_hash[hash]); - im != NULL; - im = rcu_dereference(im->next_hash)) { - if (im->multiaddr == mc_addr) - break; - } - } else { - for_each_pmc_rcu(in_dev, im) { - if (im->multiaddr == mc_addr) - break; - } - } - if (im && proto == IPPROTO_IGMP) { - rv = 1; - } else if (im) { - if (src_addr) { - for (psf = im->sources; psf; psf = psf->sf_next) { - if (psf->sf_inaddr == src_addr) - break; - } - if (psf) - rv = psf->sf_count[MCAST_INCLUDE] || - psf->sf_count[MCAST_EXCLUDE] != - im->sfcount[MCAST_EXCLUDE]; - else - rv = im->sfcount[MCAST_EXCLUDE] != 0; - } else - rv = 1; /* unspecified source; tentatively allow */ - } - return rv; -} - -#if defined(CONFIG_PROC_FS) -struct igmp_mc_iter_state { - struct seq_net_private p; - struct net_device *dev; - struct in_device *in_dev; -}; - -#define igmp_mc_seq_private(seq) ((struct igmp_mc_iter_state *)(seq)->private) - -static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq) -{ - struct net *net = seq_file_net(seq); - struct ip_mc_list *im = NULL; - struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); - - state->in_dev = NULL; - for_each_netdev_rcu(net, state->dev) { - struct in_device *in_dev; - - in_dev = __in_dev_get_rcu(state->dev); - if (!in_dev) - continue; - im = rcu_dereference(in_dev->mc_list); - if (im) { - state->in_dev = in_dev; - break; - } - } - return im; -} - -static struct ip_mc_list *igmp_mc_get_next(struct seq_file *seq, struct ip_mc_list *im) -{ - struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); - - im = rcu_dereference(im->next_rcu); - while (!im) { - state->dev = next_net_device_rcu(state->dev); - if (!state->dev) { - state->in_dev = NULL; - break; - } - state->in_dev = __in_dev_get_rcu(state->dev); - if (!state->in_dev) - continue; - im = rcu_dereference(state->in_dev->mc_list); - } - return im; -} - -static struct ip_mc_list *igmp_mc_get_idx(struct seq_file *seq, loff_t pos) -{ - struct ip_mc_list *im = igmp_mc_get_first(seq); - if (im) - while (pos && (im = igmp_mc_get_next(seq, im)) != NULL) - --pos; - return pos ? NULL : im; -} - -static void *igmp_mc_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(rcu) -{ - rcu_read_lock(); - return *pos ? igmp_mc_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; -} - -static void *igmp_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct ip_mc_list *im; - if (v == SEQ_START_TOKEN) - im = igmp_mc_get_first(seq); - else - im = igmp_mc_get_next(seq, v); - ++*pos; - return im; -} - -static void igmp_mc_seq_stop(struct seq_file *seq, void *v) - __releases(rcu) -{ - struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); - - state->in_dev = NULL; - state->dev = NULL; - rcu_read_unlock(); -} - -static int igmp_mc_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) - seq_puts(seq, - "Idx\tDevice : Count Querier\tGroup Users Timer\tReporter\n"); - else { - struct ip_mc_list *im = (struct ip_mc_list *)v; - struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); - char *querier; - long delta; - -#ifdef CONFIG_IP_MULTICAST - querier = IGMP_V1_SEEN(state->in_dev) ? "V1" : - IGMP_V2_SEEN(state->in_dev) ? "V2" : - "V3"; -#else - querier = "NONE"; -#endif - - if (rcu_access_pointer(state->in_dev->mc_list) == im) { - seq_printf(seq, "%d\t%-10s: %5d %7s\n", - state->dev->ifindex, state->dev->name, state->in_dev->mc_count, querier); - } - - delta = im->timer.expires - jiffies; - seq_printf(seq, - "\t\t\t\t%08X %5d %d:%08lX\t\t%d\n", - im->multiaddr, im->users, - im->tm_running, - im->tm_running ? jiffies_delta_to_clock_t(delta) : 0, - im->reporter); - } - return 0; -} - -static const struct seq_operations igmp_mc_seq_ops = { - .start = igmp_mc_seq_start, - .next = igmp_mc_seq_next, - .stop = igmp_mc_seq_stop, - .show = igmp_mc_seq_show, -}; - -static int igmp_mc_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &igmp_mc_seq_ops, - sizeof(struct igmp_mc_iter_state)); -} - -static const struct file_operations igmp_mc_seq_fops = { - .owner = THIS_MODULE, - .open = igmp_mc_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -struct igmp_mcf_iter_state { - struct seq_net_private p; - struct net_device *dev; - struct in_device *idev; - struct ip_mc_list *im; -}; - -#define igmp_mcf_seq_private(seq) ((struct igmp_mcf_iter_state *)(seq)->private) - -static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) -{ - struct net *net = seq_file_net(seq); - struct ip_sf_list *psf = NULL; - struct ip_mc_list *im = NULL; - struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq); - - state->idev = NULL; - state->im = NULL; - for_each_netdev_rcu(net, state->dev) { - struct in_device *idev; - idev = __in_dev_get_rcu(state->dev); - if (unlikely(!idev)) - continue; - im = rcu_dereference(idev->mc_list); - if (likely(im)) { - spin_lock_bh(&im->lock); - psf = im->sources; - if (likely(psf)) { - state->im = im; - state->idev = idev; - break; - } - spin_unlock_bh(&im->lock); - } - } - return psf; -} - -static struct ip_sf_list *igmp_mcf_get_next(struct seq_file *seq, struct ip_sf_list *psf) -{ - struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq); - - psf = psf->sf_next; - while (!psf) { - spin_unlock_bh(&state->im->lock); - state->im = state->im->next; - while (!state->im) { - state->dev = next_net_device_rcu(state->dev); - if (!state->dev) { - state->idev = NULL; - goto out; - } - state->idev = __in_dev_get_rcu(state->dev); - if (!state->idev) - continue; - state->im = rcu_dereference(state->idev->mc_list); - } - if (!state->im) - break; - spin_lock_bh(&state->im->lock); - psf = state->im->sources; - } -out: - return psf; -} - -static struct ip_sf_list *igmp_mcf_get_idx(struct seq_file *seq, loff_t pos) -{ - struct ip_sf_list *psf = igmp_mcf_get_first(seq); - if (psf) - while (pos && (psf = igmp_mcf_get_next(seq, psf)) != NULL) - --pos; - return pos ? NULL : psf; -} - -static void *igmp_mcf_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(rcu) -{ - rcu_read_lock(); - return *pos ? igmp_mcf_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; -} - -static void *igmp_mcf_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct ip_sf_list *psf; - if (v == SEQ_START_TOKEN) - psf = igmp_mcf_get_first(seq); - else - psf = igmp_mcf_get_next(seq, v); - ++*pos; - return psf; -} - -static void igmp_mcf_seq_stop(struct seq_file *seq, void *v) - __releases(rcu) -{ - struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq); - if (likely(state->im)) { - spin_unlock_bh(&state->im->lock); - state->im = NULL; - } - state->idev = NULL; - state->dev = NULL; - rcu_read_unlock(); -} - -static int igmp_mcf_seq_show(struct seq_file *seq, void *v) -{ - struct ip_sf_list *psf = (struct ip_sf_list *)v; - struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq); - - if (v == SEQ_START_TOKEN) { - seq_puts(seq, "Idx Device MCA SRC INC EXC\n"); - } else { - seq_printf(seq, - "%3d %6.6s 0x%08x " - "0x%08x %6lu %6lu\n", - state->dev->ifindex, state->dev->name, - ntohl(state->im->multiaddr), - ntohl(psf->sf_inaddr), - psf->sf_count[MCAST_INCLUDE], - psf->sf_count[MCAST_EXCLUDE]); - } - return 0; -} - -static const struct seq_operations igmp_mcf_seq_ops = { - .start = igmp_mcf_seq_start, - .next = igmp_mcf_seq_next, - .stop = igmp_mcf_seq_stop, - .show = igmp_mcf_seq_show, -}; - -static int igmp_mcf_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &igmp_mcf_seq_ops, - sizeof(struct igmp_mcf_iter_state)); -} - -static const struct file_operations igmp_mcf_seq_fops = { - .owner = THIS_MODULE, - .open = igmp_mcf_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -static int __net_init igmp_net_init(struct net *net) -{ - struct proc_dir_entry *pde; - int err; - - pde = proc_create("igmp", S_IRUGO, net->proc_net, &igmp_mc_seq_fops); - if (!pde) - goto out_igmp; - pde = proc_create("mcfilter", S_IRUGO, net->proc_net, - &igmp_mcf_seq_fops); - if (!pde) - goto out_mcfilter; - err = inet_ctl_sock_create(&net->ipv4.mc_autojoin_sk, AF_INET, - SOCK_DGRAM, 0, net); - if (err < 0) { - pr_err("Failed to initialize the IGMP autojoin socket (err %d)\n", - err); - goto out_sock; - } - - /* Sysctl initialization */ - net->ipv4.sysctl_igmp_max_memberships = 20; - net->ipv4.sysctl_igmp_max_msf = 10; - /* IGMP reports for link-local multicast groups are enabled by default */ - net->ipv4.sysctl_igmp_llm_reports = 1; - net->ipv4.sysctl_igmp_qrv = 2; - return 0; - -out_sock: - remove_proc_entry("mcfilter", net->proc_net); -out_mcfilter: - remove_proc_entry("igmp", net->proc_net); -out_igmp: - return -ENOMEM; -} - -static void __net_exit igmp_net_exit(struct net *net) -{ - remove_proc_entry("mcfilter", net->proc_net); - remove_proc_entry("igmp", net->proc_net); - inet_ctl_sock_destroy(net->ipv4.mc_autojoin_sk); -} - -static struct pernet_operations igmp_net_ops = { - .init = igmp_net_init, - .exit = igmp_net_exit, -}; -#endif - -static int igmp_netdev_event(struct notifier_block *this, - unsigned long event, void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct in_device *in_dev; - - switch (event) { - case NETDEV_RESEND_IGMP: - in_dev = __in_dev_get_rtnl(dev); - if (in_dev) - ip_mc_rejoin_groups(in_dev); - break; - default: - break; - } - return NOTIFY_DONE; -} - -static struct notifier_block igmp_notifier = { - .notifier_call = igmp_netdev_event, -}; - -int __init igmp_mc_init(void) -{ -#if defined(CONFIG_PROC_FS) - int err; - - err = register_pernet_subsys(&igmp_net_ops); - if (err) - return err; - err = register_netdevice_notifier(&igmp_notifier); - if (err) - goto reg_notif_fail; - return 0; - -reg_notif_fail: - unregister_pernet_subsys(&igmp_net_ops); - return err; -#else - return register_netdevice_notifier(&igmp_notifier); -#endif -} diff --git a/src/linux/net/ipv4/inet_connection_sock.c b/src/linux/net/ipv4/inet_connection_sock.c deleted file mode 100644 index 61a9dee..0000000 --- a/src/linux/net/ipv4/inet_connection_sock.c +++ /dev/null @@ -1,965 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Support for INET connection oriented protocols. - * - * Authors: See the TCP sources - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or(at your option) any later version. - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef INET_CSK_DEBUG -const char inet_csk_timer_bug_msg[] = "inet_csk BUG: unknown timer value\n"; -EXPORT_SYMBOL(inet_csk_timer_bug_msg); -#endif - -void inet_get_local_port_range(struct net *net, int *low, int *high) -{ - unsigned int seq; - - do { - seq = read_seqbegin(&net->ipv4.ip_local_ports.lock); - - *low = net->ipv4.ip_local_ports.range[0]; - *high = net->ipv4.ip_local_ports.range[1]; - } while (read_seqretry(&net->ipv4.ip_local_ports.lock, seq)); -} -EXPORT_SYMBOL(inet_get_local_port_range); - -int inet_csk_bind_conflict(const struct sock *sk, - const struct inet_bind_bucket *tb, bool relax) -{ - struct sock *sk2; - int reuse = sk->sk_reuse; - int reuseport = sk->sk_reuseport; - kuid_t uid = sock_i_uid((struct sock *)sk); - - /* - * Unlike other sk lookup places we do not check - * for sk_net here, since _all_ the socks listed - * in tb->owners list belong to the same net - the - * one this bucket belongs to. - */ - - sk_for_each_bound(sk2, &tb->owners) { - if (sk != sk2 && - !inet_v6_ipv6only(sk2) && - (!sk->sk_bound_dev_if || - !sk2->sk_bound_dev_if || - sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { - if ((!reuse || !sk2->sk_reuse || - sk2->sk_state == TCP_LISTEN) && - (!reuseport || !sk2->sk_reuseport || - rcu_access_pointer(sk->sk_reuseport_cb) || - (sk2->sk_state != TCP_TIME_WAIT && - !uid_eq(uid, sock_i_uid(sk2))))) { - - if (!sk2->sk_rcv_saddr || !sk->sk_rcv_saddr || - sk2->sk_rcv_saddr == sk->sk_rcv_saddr) - break; - } - if (!relax && reuse && sk2->sk_reuse && - sk2->sk_state != TCP_LISTEN) { - - if (!sk2->sk_rcv_saddr || !sk->sk_rcv_saddr || - sk2->sk_rcv_saddr == sk->sk_rcv_saddr) - break; - } - } - } - return sk2 != NULL; -} -EXPORT_SYMBOL_GPL(inet_csk_bind_conflict); - -/* Obtain a reference to a local port for the given sock, - * if snum is zero it means select any available local port. - * We try to allocate an odd port (and leave even ports for connect()) - */ -int inet_csk_get_port(struct sock *sk, unsigned short snum) -{ - bool reuse = sk->sk_reuse && sk->sk_state != TCP_LISTEN; - struct inet_hashinfo *hinfo = sk->sk_prot->h.hashinfo; - int ret = 1, attempts = 5, port = snum; - int smallest_size = -1, smallest_port; - struct inet_bind_hashbucket *head; - struct net *net = sock_net(sk); - int i, low, high, attempt_half; - struct inet_bind_bucket *tb; - kuid_t uid = sock_i_uid(sk); - u32 remaining, offset; - - if (port) { -have_port: - head = &hinfo->bhash[inet_bhashfn(net, port, - hinfo->bhash_size)]; - spin_lock_bh(&head->lock); - inet_bind_bucket_for_each(tb, &head->chain) - if (net_eq(ib_net(tb), net) && tb->port == port) - goto tb_found; - - goto tb_not_found; - } -again: - attempt_half = (sk->sk_reuse == SK_CAN_REUSE) ? 1 : 0; -other_half_scan: - inet_get_local_port_range(net, &low, &high); - high++; /* [32768, 60999] -> [32768, 61000[ */ - if (high - low < 4) - attempt_half = 0; - if (attempt_half) { - int half = low + (((high - low) >> 2) << 1); - - if (attempt_half == 1) - high = half; - else - low = half; - } - remaining = high - low; - if (likely(remaining > 1)) - remaining &= ~1U; - - offset = prandom_u32() % remaining; - /* __inet_hash_connect() favors ports having @low parity - * We do the opposite to not pollute connect() users. - */ - offset |= 1U; - smallest_size = -1; - smallest_port = low; /* avoid compiler warning */ - -other_parity_scan: - port = low + offset; - for (i = 0; i < remaining; i += 2, port += 2) { - if (unlikely(port >= high)) - port -= remaining; - if (inet_is_local_reserved_port(net, port)) - continue; - head = &hinfo->bhash[inet_bhashfn(net, port, - hinfo->bhash_size)]; - spin_lock_bh(&head->lock); - inet_bind_bucket_for_each(tb, &head->chain) - if (net_eq(ib_net(tb), net) && tb->port == port) { - if (((tb->fastreuse > 0 && reuse) || - (tb->fastreuseport > 0 && - sk->sk_reuseport && - !rcu_access_pointer(sk->sk_reuseport_cb) && - uid_eq(tb->fastuid, uid))) && - (tb->num_owners < smallest_size || smallest_size == -1)) { - smallest_size = tb->num_owners; - smallest_port = port; - } - if (!inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb, false)) - goto tb_found; - goto next_port; - } - goto tb_not_found; -next_port: - spin_unlock_bh(&head->lock); - cond_resched(); - } - - if (smallest_size != -1) { - port = smallest_port; - goto have_port; - } - offset--; - if (!(offset & 1)) - goto other_parity_scan; - - if (attempt_half == 1) { - /* OK we now try the upper half of the range */ - attempt_half = 2; - goto other_half_scan; - } - return ret; - -tb_not_found: - tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep, - net, head, port); - if (!tb) - goto fail_unlock; -tb_found: - if (!hlist_empty(&tb->owners)) { - if (sk->sk_reuse == SK_FORCE_REUSE) - goto success; - - if (((tb->fastreuse > 0 && reuse) || - (tb->fastreuseport > 0 && - !rcu_access_pointer(sk->sk_reuseport_cb) && - sk->sk_reuseport && uid_eq(tb->fastuid, uid))) && - smallest_size == -1) - goto success; - if (inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb, true)) { - if ((reuse || - (tb->fastreuseport > 0 && - sk->sk_reuseport && - !rcu_access_pointer(sk->sk_reuseport_cb) && - uid_eq(tb->fastuid, uid))) && - smallest_size != -1 && --attempts >= 0) { - spin_unlock_bh(&head->lock); - goto again; - } - goto fail_unlock; - } - if (!reuse) - tb->fastreuse = 0; - if (!sk->sk_reuseport || !uid_eq(tb->fastuid, uid)) - tb->fastreuseport = 0; - } else { - tb->fastreuse = reuse; - if (sk->sk_reuseport) { - tb->fastreuseport = 1; - tb->fastuid = uid; - } else { - tb->fastreuseport = 0; - } - } -success: - if (!inet_csk(sk)->icsk_bind_hash) - inet_bind_hash(sk, tb, port); - WARN_ON(inet_csk(sk)->icsk_bind_hash != tb); - ret = 0; - -fail_unlock: - spin_unlock_bh(&head->lock); - return ret; -} -EXPORT_SYMBOL_GPL(inet_csk_get_port); - -/* - * Wait for an incoming connection, avoid race conditions. This must be called - * with the socket locked. - */ -static int inet_csk_wait_for_connect(struct sock *sk, long timeo) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - DEFINE_WAIT(wait); - int err; - - /* - * True wake-one mechanism for incoming connections: only - * one process gets woken up, not the 'whole herd'. - * Since we do not 'race & poll' for established sockets - * anymore, the common case will execute the loop only once. - * - * Subtle issue: "add_wait_queue_exclusive()" will be added - * after any current non-exclusive waiters, and we know that - * it will always _stay_ after any new non-exclusive waiters - * because all non-exclusive waiters are added at the - * beginning of the wait-queue. As such, it's ok to "drop" - * our exclusiveness temporarily when we get woken up without - * having to remove and re-insert us on the wait queue. - */ - for (;;) { - prepare_to_wait_exclusive(sk_sleep(sk), &wait, - TASK_INTERRUPTIBLE); - release_sock(sk); - if (reqsk_queue_empty(&icsk->icsk_accept_queue)) - timeo = schedule_timeout(timeo); - sched_annotate_sleep(); - lock_sock(sk); - err = 0; - if (!reqsk_queue_empty(&icsk->icsk_accept_queue)) - break; - err = -EINVAL; - if (sk->sk_state != TCP_LISTEN) - break; - err = sock_intr_errno(timeo); - if (signal_pending(current)) - break; - err = -EAGAIN; - if (!timeo) - break; - } - finish_wait(sk_sleep(sk), &wait); - return err; -} - -/* - * This will accept the next outstanding connection. - */ -struct sock *inet_csk_accept(struct sock *sk, int flags, int *err) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - struct request_sock_queue *queue = &icsk->icsk_accept_queue; - struct request_sock *req; - struct sock *newsk; - int error; - - lock_sock(sk); - - /* We need to make sure that this socket is listening, - * and that it has something pending. - */ - error = -EINVAL; - if (sk->sk_state != TCP_LISTEN) - goto out_err; - - /* Find already established connection */ - if (reqsk_queue_empty(queue)) { - long timeo = sock_rcvtimeo(sk, flags & O_NONBLOCK); - - /* If this is a non blocking socket don't sleep */ - error = -EAGAIN; - if (!timeo) - goto out_err; - - error = inet_csk_wait_for_connect(sk, timeo); - if (error) - goto out_err; - } - req = reqsk_queue_remove(queue, sk); - newsk = req->sk; - - if (sk->sk_protocol == IPPROTO_TCP && - tcp_rsk(req)->tfo_listener) { - spin_lock_bh(&queue->fastopenq.lock); - if (tcp_rsk(req)->tfo_listener) { - /* We are still waiting for the final ACK from 3WHS - * so can't free req now. Instead, we set req->sk to - * NULL to signify that the child socket is taken - * so reqsk_fastopen_remove() will free the req - * when 3WHS finishes (or is aborted). - */ - req->sk = NULL; - req = NULL; - } - spin_unlock_bh(&queue->fastopenq.lock); - } -out: - release_sock(sk); - if (req) - reqsk_put(req); - return newsk; -out_err: - newsk = NULL; - req = NULL; - *err = error; - goto out; -} -EXPORT_SYMBOL(inet_csk_accept); - -/* - * Using different timers for retransmit, delayed acks and probes - * We may wish use just one timer maintaining a list of expire jiffies - * to optimize. - */ -void inet_csk_init_xmit_timers(struct sock *sk, - void (*retransmit_handler)(unsigned long), - void (*delack_handler)(unsigned long), - void (*keepalive_handler)(unsigned long)) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - - setup_timer(&icsk->icsk_retransmit_timer, retransmit_handler, - (unsigned long)sk); - setup_timer(&icsk->icsk_delack_timer, delack_handler, - (unsigned long)sk); - setup_timer(&sk->sk_timer, keepalive_handler, (unsigned long)sk); - icsk->icsk_pending = icsk->icsk_ack.pending = 0; -} -EXPORT_SYMBOL(inet_csk_init_xmit_timers); - -void inet_csk_clear_xmit_timers(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - - icsk->icsk_pending = icsk->icsk_ack.pending = icsk->icsk_ack.blocked = 0; - - sk_stop_timer(sk, &icsk->icsk_retransmit_timer); - sk_stop_timer(sk, &icsk->icsk_delack_timer); - sk_stop_timer(sk, &sk->sk_timer); -} -EXPORT_SYMBOL(inet_csk_clear_xmit_timers); - -void inet_csk_delete_keepalive_timer(struct sock *sk) -{ - sk_stop_timer(sk, &sk->sk_timer); -} -EXPORT_SYMBOL(inet_csk_delete_keepalive_timer); - -void inet_csk_reset_keepalive_timer(struct sock *sk, unsigned long len) -{ - sk_reset_timer(sk, &sk->sk_timer, jiffies + len); -} -EXPORT_SYMBOL(inet_csk_reset_keepalive_timer); - -struct dst_entry *inet_csk_route_req(const struct sock *sk, - struct flowi4 *fl4, - const struct request_sock *req) -{ - const struct inet_request_sock *ireq = inet_rsk(req); - struct net *net = read_pnet(&ireq->ireq_net); - struct ip_options_rcu *opt = ireq->opt; - struct rtable *rt; - - flowi4_init_output(fl4, ireq->ir_iif, ireq->ir_mark, - RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, - sk->sk_protocol, inet_sk_flowi_flags(sk), - (opt && opt->opt.srr) ? opt->opt.faddr : ireq->ir_rmt_addr, - ireq->ir_loc_addr, ireq->ir_rmt_port, - htons(ireq->ir_num)); - security_req_classify_flow(req, flowi4_to_flowi(fl4)); - rt = ip_route_output_flow(net, fl4, sk); - if (IS_ERR(rt)) - goto no_route; - if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway) - goto route_err; - return &rt->dst; - -route_err: - ip_rt_put(rt); -no_route: - __IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); - return NULL; -} -EXPORT_SYMBOL_GPL(inet_csk_route_req); - -struct dst_entry *inet_csk_route_child_sock(const struct sock *sk, - struct sock *newsk, - const struct request_sock *req) -{ - const struct inet_request_sock *ireq = inet_rsk(req); - struct net *net = read_pnet(&ireq->ireq_net); - struct inet_sock *newinet = inet_sk(newsk); - struct ip_options_rcu *opt; - struct flowi4 *fl4; - struct rtable *rt; - - fl4 = &newinet->cork.fl.u.ip4; - - rcu_read_lock(); - opt = rcu_dereference(newinet->inet_opt); - flowi4_init_output(fl4, ireq->ir_iif, ireq->ir_mark, - RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, - sk->sk_protocol, inet_sk_flowi_flags(sk), - (opt && opt->opt.srr) ? opt->opt.faddr : ireq->ir_rmt_addr, - ireq->ir_loc_addr, ireq->ir_rmt_port, - htons(ireq->ir_num)); - security_req_classify_flow(req, flowi4_to_flowi(fl4)); - rt = ip_route_output_flow(net, fl4, sk); - if (IS_ERR(rt)) - goto no_route; - if (opt && opt->opt.is_strictroute && rt->rt_uses_gateway) - goto route_err; - rcu_read_unlock(); - return &rt->dst; - -route_err: - ip_rt_put(rt); -no_route: - rcu_read_unlock(); - __IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); - return NULL; -} -EXPORT_SYMBOL_GPL(inet_csk_route_child_sock); - -#if IS_ENABLED(CONFIG_IPV6) -#define AF_INET_FAMILY(fam) ((fam) == AF_INET) -#else -#define AF_INET_FAMILY(fam) true -#endif - -/* Decide when to expire the request and when to resend SYN-ACK */ -static inline void syn_ack_recalc(struct request_sock *req, const int thresh, - const int max_retries, - const u8 rskq_defer_accept, - int *expire, int *resend) -{ - if (!rskq_defer_accept) { - *expire = req->num_timeout >= thresh; - *resend = 1; - return; - } - *expire = req->num_timeout >= thresh && - (!inet_rsk(req)->acked || req->num_timeout >= max_retries); - /* - * Do not resend while waiting for data after ACK, - * start to resend on end of deferring period to give - * last chance for data or ACK to create established socket. - */ - *resend = !inet_rsk(req)->acked || - req->num_timeout >= rskq_defer_accept - 1; -} - -int inet_rtx_syn_ack(const struct sock *parent, struct request_sock *req) -{ - int err = req->rsk_ops->rtx_syn_ack(parent, req); - - if (!err) - req->num_retrans++; - return err; -} -EXPORT_SYMBOL(inet_rtx_syn_ack); - -/* return true if req was found in the ehash table */ -static bool reqsk_queue_unlink(struct request_sock_queue *queue, - struct request_sock *req) -{ - struct inet_hashinfo *hashinfo = req_to_sk(req)->sk_prot->h.hashinfo; - bool found = false; - - if (sk_hashed(req_to_sk(req))) { - spinlock_t *lock = inet_ehash_lockp(hashinfo, req->rsk_hash); - - spin_lock(lock); - found = __sk_nulls_del_node_init_rcu(req_to_sk(req)); - spin_unlock(lock); - } - if (timer_pending(&req->rsk_timer) && del_timer_sync(&req->rsk_timer)) - reqsk_put(req); - return found; -} - -void inet_csk_reqsk_queue_drop(struct sock *sk, struct request_sock *req) -{ - if (reqsk_queue_unlink(&inet_csk(sk)->icsk_accept_queue, req)) { - reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req); - reqsk_put(req); - } -} -EXPORT_SYMBOL(inet_csk_reqsk_queue_drop); - -void inet_csk_reqsk_queue_drop_and_put(struct sock *sk, struct request_sock *req) -{ - inet_csk_reqsk_queue_drop(sk, req); - reqsk_put(req); -} -EXPORT_SYMBOL(inet_csk_reqsk_queue_drop_and_put); - -static void reqsk_timer_handler(unsigned long data) -{ - struct request_sock *req = (struct request_sock *)data; - struct sock *sk_listener = req->rsk_listener; - struct net *net = sock_net(sk_listener); - struct inet_connection_sock *icsk = inet_csk(sk_listener); - struct request_sock_queue *queue = &icsk->icsk_accept_queue; - int qlen, expire = 0, resend = 0; - int max_retries, thresh; - u8 defer_accept; - - if (sk_state_load(sk_listener) != TCP_LISTEN) - goto drop; - - max_retries = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_synack_retries; - thresh = max_retries; - /* Normally all the openreqs are young and become mature - * (i.e. converted to established socket) for first timeout. - * If synack was not acknowledged for 1 second, it means - * one of the following things: synack was lost, ack was lost, - * rtt is high or nobody planned to ack (i.e. synflood). - * When server is a bit loaded, queue is populated with old - * open requests, reducing effective size of queue. - * When server is well loaded, queue size reduces to zero - * after several minutes of work. It is not synflood, - * it is normal operation. The solution is pruning - * too old entries overriding normal timeout, when - * situation becomes dangerous. - * - * Essentially, we reserve half of room for young - * embrions; and abort old ones without pity, if old - * ones are about to clog our table. - */ - qlen = reqsk_queue_len(queue); - if ((qlen << 1) > max(8U, sk_listener->sk_max_ack_backlog)) { - int young = reqsk_queue_len_young(queue) << 1; - - while (thresh > 2) { - if (qlen < young) - break; - thresh--; - young <<= 1; - } - } - defer_accept = READ_ONCE(queue->rskq_defer_accept); - if (defer_accept) - max_retries = defer_accept; - syn_ack_recalc(req, thresh, max_retries, defer_accept, - &expire, &resend); - req->rsk_ops->syn_ack_timeout(req); - if (!expire && - (!resend || - !inet_rtx_syn_ack(sk_listener, req) || - inet_rsk(req)->acked)) { - unsigned long timeo; - - if (req->num_timeout++ == 0) - atomic_dec(&queue->young); - timeo = min(TCP_TIMEOUT_INIT << req->num_timeout, TCP_RTO_MAX); - mod_timer(&req->rsk_timer, jiffies + timeo); - return; - } -drop: - inet_csk_reqsk_queue_drop_and_put(sk_listener, req); -} - -static void reqsk_queue_hash_req(struct request_sock *req, - unsigned long timeout) -{ - req->num_retrans = 0; - req->num_timeout = 0; - req->sk = NULL; - - setup_pinned_timer(&req->rsk_timer, reqsk_timer_handler, - (unsigned long)req); - mod_timer(&req->rsk_timer, jiffies + timeout); - - inet_ehash_insert(req_to_sk(req), NULL); - /* before letting lookups find us, make sure all req fields - * are committed to memory and refcnt initialized. - */ - smp_wmb(); - atomic_set(&req->rsk_refcnt, 2 + 1); -} - -void inet_csk_reqsk_queue_hash_add(struct sock *sk, struct request_sock *req, - unsigned long timeout) -{ - reqsk_queue_hash_req(req, timeout); - inet_csk_reqsk_queue_added(sk); -} -EXPORT_SYMBOL_GPL(inet_csk_reqsk_queue_hash_add); - -/** - * inet_csk_clone_lock - clone an inet socket, and lock its clone - * @sk: the socket to clone - * @req: request_sock - * @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc) - * - * Caller must unlock socket even in error path (bh_unlock_sock(newsk)) - */ -struct sock *inet_csk_clone_lock(const struct sock *sk, - const struct request_sock *req, - const gfp_t priority) -{ - struct sock *newsk = sk_clone_lock(sk, priority); - - if (newsk) { - struct inet_connection_sock *newicsk = inet_csk(newsk); - - newsk->sk_state = TCP_SYN_RECV; - newicsk->icsk_bind_hash = NULL; - - inet_sk(newsk)->inet_dport = inet_rsk(req)->ir_rmt_port; - inet_sk(newsk)->inet_num = inet_rsk(req)->ir_num; - inet_sk(newsk)->inet_sport = htons(inet_rsk(req)->ir_num); - newsk->sk_write_space = sk_stream_write_space; - - /* listeners have SOCK_RCU_FREE, not the children */ - sock_reset_flag(newsk, SOCK_RCU_FREE); - - newsk->sk_mark = inet_rsk(req)->ir_mark; - atomic64_set(&newsk->sk_cookie, - atomic64_read(&inet_rsk(req)->ir_cookie)); - - newicsk->icsk_retransmits = 0; - newicsk->icsk_backoff = 0; - newicsk->icsk_probes_out = 0; - - /* Deinitialize accept_queue to trap illegal accesses. */ - memset(&newicsk->icsk_accept_queue, 0, sizeof(newicsk->icsk_accept_queue)); - - security_inet_csk_clone(newsk, req); - } - return newsk; -} -EXPORT_SYMBOL_GPL(inet_csk_clone_lock); - -/* - * At this point, there should be no process reference to this - * socket, and thus no user references at all. Therefore we - * can assume the socket waitqueue is inactive and nobody will - * try to jump onto it. - */ -void inet_csk_destroy_sock(struct sock *sk) -{ - WARN_ON(sk->sk_state != TCP_CLOSE); - WARN_ON(!sock_flag(sk, SOCK_DEAD)); - - /* It cannot be in hash table! */ - WARN_ON(!sk_unhashed(sk)); - - /* If it has not 0 inet_sk(sk)->inet_num, it must be bound */ - WARN_ON(inet_sk(sk)->inet_num && !inet_csk(sk)->icsk_bind_hash); - - sk->sk_prot->destroy(sk); - - sk_stream_kill_queues(sk); - - xfrm_sk_free_policy(sk); - - sk_refcnt_debug_release(sk); - - local_bh_disable(); - percpu_counter_dec(sk->sk_prot->orphan_count); - local_bh_enable(); - sock_put(sk); -} -EXPORT_SYMBOL(inet_csk_destroy_sock); - -/* This function allows to force a closure of a socket after the call to - * tcp/dccp_create_openreq_child(). - */ -void inet_csk_prepare_forced_close(struct sock *sk) - __releases(&sk->sk_lock.slock) -{ - /* sk_clone_lock locked the socket and set refcnt to 2 */ - bh_unlock_sock(sk); - sock_put(sk); - - /* The below has to be done to allow calling inet_csk_destroy_sock */ - sock_set_flag(sk, SOCK_DEAD); - percpu_counter_inc(sk->sk_prot->orphan_count); - inet_sk(sk)->inet_num = 0; -} -EXPORT_SYMBOL(inet_csk_prepare_forced_close); - -int inet_csk_listen_start(struct sock *sk, int backlog) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - struct inet_sock *inet = inet_sk(sk); - int err = -EADDRINUSE; - - reqsk_queue_alloc(&icsk->icsk_accept_queue); - - sk->sk_max_ack_backlog = backlog; - sk->sk_ack_backlog = 0; - inet_csk_delack_init(sk); - - /* There is race window here: we announce ourselves listening, - * but this transition is still not validated by get_port(). - * It is OK, because this socket enters to hash table only - * after validation is complete. - */ - sk_state_store(sk, TCP_LISTEN); - if (!sk->sk_prot->get_port(sk, inet->inet_num)) { - inet->inet_sport = htons(inet->inet_num); - - sk_dst_reset(sk); - err = sk->sk_prot->hash(sk); - - if (likely(!err)) - return 0; - } - - sk->sk_state = TCP_CLOSE; - return err; -} -EXPORT_SYMBOL_GPL(inet_csk_listen_start); - -static void inet_child_forget(struct sock *sk, struct request_sock *req, - struct sock *child) -{ - sk->sk_prot->disconnect(child, O_NONBLOCK); - - sock_orphan(child); - - percpu_counter_inc(sk->sk_prot->orphan_count); - - if (sk->sk_protocol == IPPROTO_TCP && tcp_rsk(req)->tfo_listener) { - BUG_ON(tcp_sk(child)->fastopen_rsk != req); - BUG_ON(sk != req->rsk_listener); - - /* Paranoid, to prevent race condition if - * an inbound pkt destined for child is - * blocked by sock lock in tcp_v4_rcv(). - * Also to satisfy an assertion in - * tcp_v4_destroy_sock(). - */ - tcp_sk(child)->fastopen_rsk = NULL; - } - inet_csk_destroy_sock(child); - reqsk_put(req); -} - -struct sock *inet_csk_reqsk_queue_add(struct sock *sk, - struct request_sock *req, - struct sock *child) -{ - struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue; - - spin_lock(&queue->rskq_lock); - if (unlikely(sk->sk_state != TCP_LISTEN)) { - inet_child_forget(sk, req, child); - child = NULL; - } else { - req->sk = child; - req->dl_next = NULL; - if (queue->rskq_accept_head == NULL) - queue->rskq_accept_head = req; - else - queue->rskq_accept_tail->dl_next = req; - queue->rskq_accept_tail = req; - sk_acceptq_added(sk); - } - spin_unlock(&queue->rskq_lock); - return child; -} -EXPORT_SYMBOL(inet_csk_reqsk_queue_add); - -struct sock *inet_csk_complete_hashdance(struct sock *sk, struct sock *child, - struct request_sock *req, bool own_req) -{ - if (own_req) { - inet_csk_reqsk_queue_drop(sk, req); - reqsk_queue_removed(&inet_csk(sk)->icsk_accept_queue, req); - if (inet_csk_reqsk_queue_add(sk, req, child)) - return child; - } - /* Too bad, another child took ownership of the request, undo. */ - bh_unlock_sock(child); - sock_put(child); - return NULL; -} -EXPORT_SYMBOL(inet_csk_complete_hashdance); - -/* - * This routine closes sockets which have been at least partially - * opened, but not yet accepted. - */ -void inet_csk_listen_stop(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - struct request_sock_queue *queue = &icsk->icsk_accept_queue; - struct request_sock *next, *req; - - /* Following specs, it would be better either to send FIN - * (and enter FIN-WAIT-1, it is normal close) - * or to send active reset (abort). - * Certainly, it is pretty dangerous while synflood, but it is - * bad justification for our negligence 8) - * To be honest, we are not able to make either - * of the variants now. --ANK - */ - while ((req = reqsk_queue_remove(queue, sk)) != NULL) { - struct sock *child = req->sk; - - local_bh_disable(); - bh_lock_sock(child); - WARN_ON(sock_owned_by_user(child)); - sock_hold(child); - - inet_child_forget(sk, req, child); - bh_unlock_sock(child); - local_bh_enable(); - sock_put(child); - - cond_resched(); - } - if (queue->fastopenq.rskq_rst_head) { - /* Free all the reqs queued in rskq_rst_head. */ - spin_lock_bh(&queue->fastopenq.lock); - req = queue->fastopenq.rskq_rst_head; - queue->fastopenq.rskq_rst_head = NULL; - spin_unlock_bh(&queue->fastopenq.lock); - while (req != NULL) { - next = req->dl_next; - reqsk_put(req); - req = next; - } - } - WARN_ON_ONCE(sk->sk_ack_backlog); -} -EXPORT_SYMBOL_GPL(inet_csk_listen_stop); - -void inet_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr) -{ - struct sockaddr_in *sin = (struct sockaddr_in *)uaddr; - const struct inet_sock *inet = inet_sk(sk); - - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = inet->inet_daddr; - sin->sin_port = inet->inet_dport; -} -EXPORT_SYMBOL_GPL(inet_csk_addr2sockaddr); - -#ifdef CONFIG_COMPAT -int inet_csk_compat_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - - if (icsk->icsk_af_ops->compat_getsockopt) - return icsk->icsk_af_ops->compat_getsockopt(sk, level, optname, - optval, optlen); - return icsk->icsk_af_ops->getsockopt(sk, level, optname, - optval, optlen); -} -EXPORT_SYMBOL_GPL(inet_csk_compat_getsockopt); - -int inet_csk_compat_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - - if (icsk->icsk_af_ops->compat_setsockopt) - return icsk->icsk_af_ops->compat_setsockopt(sk, level, optname, - optval, optlen); - return icsk->icsk_af_ops->setsockopt(sk, level, optname, - optval, optlen); -} -EXPORT_SYMBOL_GPL(inet_csk_compat_setsockopt); -#endif - -static struct dst_entry *inet_csk_rebuild_route(struct sock *sk, struct flowi *fl) -{ - const struct inet_sock *inet = inet_sk(sk); - const struct ip_options_rcu *inet_opt; - __be32 daddr = inet->inet_daddr; - struct flowi4 *fl4; - struct rtable *rt; - - rcu_read_lock(); - inet_opt = rcu_dereference(inet->inet_opt); - if (inet_opt && inet_opt->opt.srr) - daddr = inet_opt->opt.faddr; - fl4 = &fl->u.ip4; - rt = ip_route_output_ports(sock_net(sk), fl4, sk, daddr, - inet->inet_saddr, inet->inet_dport, - inet->inet_sport, sk->sk_protocol, - RT_CONN_FLAGS(sk), sk->sk_bound_dev_if); - if (IS_ERR(rt)) - rt = NULL; - if (rt) - sk_setup_caps(sk, &rt->dst); - rcu_read_unlock(); - - return &rt->dst; -} - -struct dst_entry *inet_csk_update_pmtu(struct sock *sk, u32 mtu) -{ - struct dst_entry *dst = __sk_dst_check(sk, 0); - struct inet_sock *inet = inet_sk(sk); - - if (!dst) { - dst = inet_csk_rebuild_route(sk, &inet->cork.fl); - if (!dst) - goto out; - } - dst->ops->update_pmtu(dst, sk, NULL, mtu); - - dst = __sk_dst_check(sk, 0); - if (!dst) - dst = inet_csk_rebuild_route(sk, &inet->cork.fl); -out: - return dst; -} -EXPORT_SYMBOL_GPL(inet_csk_update_pmtu); diff --git a/src/linux/net/ipv4/inet_diag.c b/src/linux/net/ipv4/inet_diag.c deleted file mode 100644 index e4d16fc..0000000 --- a/src/linux/net/ipv4/inet_diag.c +++ /dev/null @@ -1,1262 +0,0 @@ -/* - * inet_diag.c Module for monitoring INET transport protocols sockets. - * - * Authors: Alexey Kuznetsov, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -static const struct inet_diag_handler **inet_diag_table; - -struct inet_diag_entry { - const __be32 *saddr; - const __be32 *daddr; - u16 sport; - u16 dport; - u16 family; - u16 userlocks; - u32 ifindex; - u32 mark; -}; - -static DEFINE_MUTEX(inet_diag_table_mutex); - -static const struct inet_diag_handler *inet_diag_lock_handler(int proto) -{ - if (!inet_diag_table[proto]) - request_module("net-pf-%d-proto-%d-type-%d-%d", PF_NETLINK, - NETLINK_SOCK_DIAG, AF_INET, proto); - - mutex_lock(&inet_diag_table_mutex); - if (!inet_diag_table[proto]) - return ERR_PTR(-ENOENT); - - return inet_diag_table[proto]; -} - -static void inet_diag_unlock_handler(const struct inet_diag_handler *handler) -{ - mutex_unlock(&inet_diag_table_mutex); -} - -void inet_diag_msg_common_fill(struct inet_diag_msg *r, struct sock *sk) -{ - r->idiag_family = sk->sk_family; - - r->id.idiag_sport = htons(sk->sk_num); - r->id.idiag_dport = sk->sk_dport; - r->id.idiag_if = sk->sk_bound_dev_if; - sock_diag_save_cookie(sk, r->id.idiag_cookie); - -#if IS_ENABLED(CONFIG_IPV6) - if (sk->sk_family == AF_INET6) { - *(struct in6_addr *)r->id.idiag_src = sk->sk_v6_rcv_saddr; - *(struct in6_addr *)r->id.idiag_dst = sk->sk_v6_daddr; - } else -#endif - { - memset(&r->id.idiag_src, 0, sizeof(r->id.idiag_src)); - memset(&r->id.idiag_dst, 0, sizeof(r->id.idiag_dst)); - - r->id.idiag_src[0] = sk->sk_rcv_saddr; - r->id.idiag_dst[0] = sk->sk_daddr; - } -} -EXPORT_SYMBOL_GPL(inet_diag_msg_common_fill); - -static size_t inet_sk_attr_size(void) -{ - return nla_total_size(sizeof(struct tcp_info)) - + nla_total_size(1) /* INET_DIAG_SHUTDOWN */ - + nla_total_size(1) /* INET_DIAG_TOS */ - + nla_total_size(1) /* INET_DIAG_TCLASS */ - + nla_total_size(4) /* INET_DIAG_MARK */ - + nla_total_size(sizeof(struct inet_diag_meminfo)) - + nla_total_size(sizeof(struct inet_diag_msg)) - + nla_total_size(SK_MEMINFO_VARS * sizeof(u32)) - + nla_total_size(TCP_CA_NAME_MAX) - + nla_total_size(sizeof(struct tcpvegas_info)) - + 64; -} - -int inet_diag_msg_attrs_fill(struct sock *sk, struct sk_buff *skb, - struct inet_diag_msg *r, int ext, - struct user_namespace *user_ns, - bool net_admin) -{ - const struct inet_sock *inet = inet_sk(sk); - - if (nla_put_u8(skb, INET_DIAG_SHUTDOWN, sk->sk_shutdown)) - goto errout; - - /* IPv6 dual-stack sockets use inet->tos for IPv4 connections, - * hence this needs to be included regardless of socket family. - */ - if (ext & (1 << (INET_DIAG_TOS - 1))) - if (nla_put_u8(skb, INET_DIAG_TOS, inet->tos) < 0) - goto errout; - -#if IS_ENABLED(CONFIG_IPV6) - if (r->idiag_family == AF_INET6) { - if (ext & (1 << (INET_DIAG_TCLASS - 1))) - if (nla_put_u8(skb, INET_DIAG_TCLASS, - inet6_sk(sk)->tclass) < 0) - goto errout; - - if (((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) && - nla_put_u8(skb, INET_DIAG_SKV6ONLY, ipv6_only_sock(sk))) - goto errout; - } -#endif - - if (net_admin && nla_put_u32(skb, INET_DIAG_MARK, sk->sk_mark)) - goto errout; - - r->idiag_uid = from_kuid_munged(user_ns, sock_i_uid(sk)); - r->idiag_inode = sock_i_ino(sk); - - return 0; -errout: - return 1; -} -EXPORT_SYMBOL_GPL(inet_diag_msg_attrs_fill); - -int inet_sk_diag_fill(struct sock *sk, struct inet_connection_sock *icsk, - struct sk_buff *skb, const struct inet_diag_req_v2 *req, - struct user_namespace *user_ns, - u32 portid, u32 seq, u16 nlmsg_flags, - const struct nlmsghdr *unlh, - bool net_admin) -{ - const struct tcp_congestion_ops *ca_ops; - const struct inet_diag_handler *handler; - int ext = req->idiag_ext; - struct inet_diag_msg *r; - struct nlmsghdr *nlh; - struct nlattr *attr; - void *info = NULL; - - handler = inet_diag_table[req->sdiag_protocol]; - BUG_ON(!handler); - - nlh = nlmsg_put(skb, portid, seq, unlh->nlmsg_type, sizeof(*r), - nlmsg_flags); - if (!nlh) - return -EMSGSIZE; - - r = nlmsg_data(nlh); - BUG_ON(!sk_fullsock(sk)); - - inet_diag_msg_common_fill(r, sk); - r->idiag_state = sk->sk_state; - r->idiag_timer = 0; - r->idiag_retrans = 0; - - if (inet_diag_msg_attrs_fill(sk, skb, r, ext, user_ns, net_admin)) - goto errout; - - if (ext & (1 << (INET_DIAG_MEMINFO - 1))) { - struct inet_diag_meminfo minfo = { - .idiag_rmem = sk_rmem_alloc_get(sk), - .idiag_wmem = sk->sk_wmem_queued, - .idiag_fmem = sk->sk_forward_alloc, - .idiag_tmem = sk_wmem_alloc_get(sk), - }; - - if (nla_put(skb, INET_DIAG_MEMINFO, sizeof(minfo), &minfo) < 0) - goto errout; - } - - if (ext & (1 << (INET_DIAG_SKMEMINFO - 1))) - if (sock_diag_put_meminfo(sk, skb, INET_DIAG_SKMEMINFO)) - goto errout; - - if (!icsk) { - handler->idiag_get_info(sk, r, NULL); - goto out; - } - - if (icsk->icsk_pending == ICSK_TIME_RETRANS || - icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS || - icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) { - r->idiag_timer = 1; - r->idiag_retrans = icsk->icsk_retransmits; - r->idiag_expires = - jiffies_to_msecs(icsk->icsk_timeout - jiffies); - } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) { - r->idiag_timer = 4; - r->idiag_retrans = icsk->icsk_probes_out; - r->idiag_expires = - jiffies_to_msecs(icsk->icsk_timeout - jiffies); - } else if (timer_pending(&sk->sk_timer)) { - r->idiag_timer = 2; - r->idiag_retrans = icsk->icsk_probes_out; - r->idiag_expires = - jiffies_to_msecs(sk->sk_timer.expires - jiffies); - } else { - r->idiag_timer = 0; - r->idiag_expires = 0; - } - - if ((ext & (1 << (INET_DIAG_INFO - 1))) && handler->idiag_info_size) { - attr = nla_reserve_64bit(skb, INET_DIAG_INFO, - handler->idiag_info_size, - INET_DIAG_PAD); - if (!attr) - goto errout; - - info = nla_data(attr); - } - - if (ext & (1 << (INET_DIAG_CONG - 1))) { - int err = 0; - - rcu_read_lock(); - ca_ops = READ_ONCE(icsk->icsk_ca_ops); - if (ca_ops) - err = nla_put_string(skb, INET_DIAG_CONG, ca_ops->name); - rcu_read_unlock(); - if (err < 0) - goto errout; - } - - handler->idiag_get_info(sk, r, info); - - if (sk->sk_state < TCP_TIME_WAIT) { - union tcp_cc_info info; - size_t sz = 0; - int attr; - - rcu_read_lock(); - ca_ops = READ_ONCE(icsk->icsk_ca_ops); - if (ca_ops && ca_ops->get_info) - sz = ca_ops->get_info(sk, ext, &attr, &info); - rcu_read_unlock(); - if (sz && nla_put(skb, attr, sz, &info) < 0) - goto errout; - } - -out: - nlmsg_end(skb, nlh); - return 0; - -errout: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} -EXPORT_SYMBOL_GPL(inet_sk_diag_fill); - -static int inet_csk_diag_fill(struct sock *sk, - struct sk_buff *skb, - const struct inet_diag_req_v2 *req, - struct user_namespace *user_ns, - u32 portid, u32 seq, u16 nlmsg_flags, - const struct nlmsghdr *unlh, - bool net_admin) -{ - return inet_sk_diag_fill(sk, inet_csk(sk), skb, req, user_ns, - portid, seq, nlmsg_flags, unlh, net_admin); -} - -static int inet_twsk_diag_fill(struct sock *sk, - struct sk_buff *skb, - u32 portid, u32 seq, u16 nlmsg_flags, - const struct nlmsghdr *unlh) -{ - struct inet_timewait_sock *tw = inet_twsk(sk); - struct inet_diag_msg *r; - struct nlmsghdr *nlh; - long tmo; - - nlh = nlmsg_put(skb, portid, seq, unlh->nlmsg_type, sizeof(*r), - nlmsg_flags); - if (!nlh) - return -EMSGSIZE; - - r = nlmsg_data(nlh); - BUG_ON(tw->tw_state != TCP_TIME_WAIT); - - tmo = tw->tw_timer.expires - jiffies; - if (tmo < 0) - tmo = 0; - - inet_diag_msg_common_fill(r, sk); - r->idiag_retrans = 0; - - r->idiag_state = tw->tw_substate; - r->idiag_timer = 3; - r->idiag_expires = jiffies_to_msecs(tmo); - r->idiag_rqueue = 0; - r->idiag_wqueue = 0; - r->idiag_uid = 0; - r->idiag_inode = 0; - - nlmsg_end(skb, nlh); - return 0; -} - -static int inet_req_diag_fill(struct sock *sk, struct sk_buff *skb, - u32 portid, u32 seq, u16 nlmsg_flags, - const struct nlmsghdr *unlh, bool net_admin) -{ - struct request_sock *reqsk = inet_reqsk(sk); - struct inet_diag_msg *r; - struct nlmsghdr *nlh; - long tmo; - - nlh = nlmsg_put(skb, portid, seq, unlh->nlmsg_type, sizeof(*r), - nlmsg_flags); - if (!nlh) - return -EMSGSIZE; - - r = nlmsg_data(nlh); - inet_diag_msg_common_fill(r, sk); - r->idiag_state = TCP_SYN_RECV; - r->idiag_timer = 1; - r->idiag_retrans = reqsk->num_retrans; - - BUILD_BUG_ON(offsetof(struct inet_request_sock, ir_cookie) != - offsetof(struct sock, sk_cookie)); - - tmo = inet_reqsk(sk)->rsk_timer.expires - jiffies; - r->idiag_expires = (tmo >= 0) ? jiffies_to_msecs(tmo) : 0; - r->idiag_rqueue = 0; - r->idiag_wqueue = 0; - r->idiag_uid = 0; - r->idiag_inode = 0; - - if (net_admin && nla_put_u32(skb, INET_DIAG_MARK, - inet_rsk(reqsk)->ir_mark)) - return -EMSGSIZE; - - nlmsg_end(skb, nlh); - return 0; -} - -static int sk_diag_fill(struct sock *sk, struct sk_buff *skb, - const struct inet_diag_req_v2 *r, - struct user_namespace *user_ns, - u32 portid, u32 seq, u16 nlmsg_flags, - const struct nlmsghdr *unlh, bool net_admin) -{ - if (sk->sk_state == TCP_TIME_WAIT) - return inet_twsk_diag_fill(sk, skb, portid, seq, - nlmsg_flags, unlh); - - if (sk->sk_state == TCP_NEW_SYN_RECV) - return inet_req_diag_fill(sk, skb, portid, seq, - nlmsg_flags, unlh, net_admin); - - return inet_csk_diag_fill(sk, skb, r, user_ns, portid, seq, - nlmsg_flags, unlh, net_admin); -} - -struct sock *inet_diag_find_one_icsk(struct net *net, - struct inet_hashinfo *hashinfo, - const struct inet_diag_req_v2 *req) -{ - struct sock *sk; - - rcu_read_lock(); - if (req->sdiag_family == AF_INET) - sk = inet_lookup(net, hashinfo, NULL, 0, req->id.idiag_dst[0], - req->id.idiag_dport, req->id.idiag_src[0], - req->id.idiag_sport, req->id.idiag_if); -#if IS_ENABLED(CONFIG_IPV6) - else if (req->sdiag_family == AF_INET6) { - if (ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_dst) && - ipv6_addr_v4mapped((struct in6_addr *)req->id.idiag_src)) - sk = inet_lookup(net, hashinfo, NULL, 0, req->id.idiag_dst[3], - req->id.idiag_dport, req->id.idiag_src[3], - req->id.idiag_sport, req->id.idiag_if); - else - sk = inet6_lookup(net, hashinfo, NULL, 0, - (struct in6_addr *)req->id.idiag_dst, - req->id.idiag_dport, - (struct in6_addr *)req->id.idiag_src, - req->id.idiag_sport, - req->id.idiag_if); - } -#endif - else { - rcu_read_unlock(); - return ERR_PTR(-EINVAL); - } - rcu_read_unlock(); - if (!sk) - return ERR_PTR(-ENOENT); - - if (sock_diag_check_cookie(sk, req->id.idiag_cookie)) { - sock_gen_put(sk); - return ERR_PTR(-ENOENT); - } - - return sk; -} -EXPORT_SYMBOL_GPL(inet_diag_find_one_icsk); - -int inet_diag_dump_one_icsk(struct inet_hashinfo *hashinfo, - struct sk_buff *in_skb, - const struct nlmsghdr *nlh, - const struct inet_diag_req_v2 *req) -{ - struct net *net = sock_net(in_skb->sk); - struct sk_buff *rep; - struct sock *sk; - int err; - - sk = inet_diag_find_one_icsk(net, hashinfo, req); - if (IS_ERR(sk)) - return PTR_ERR(sk); - - rep = nlmsg_new(inet_sk_attr_size(), GFP_KERNEL); - if (!rep) { - err = -ENOMEM; - goto out; - } - - err = sk_diag_fill(sk, rep, req, - sk_user_ns(NETLINK_CB(in_skb).sk), - NETLINK_CB(in_skb).portid, - nlh->nlmsg_seq, 0, nlh, - netlink_net_capable(in_skb, CAP_NET_ADMIN)); - if (err < 0) { - WARN_ON(err == -EMSGSIZE); - nlmsg_free(rep); - goto out; - } - err = netlink_unicast(net->diag_nlsk, rep, NETLINK_CB(in_skb).portid, - MSG_DONTWAIT); - if (err > 0) - err = 0; - -out: - if (sk) - sock_gen_put(sk); - - return err; -} -EXPORT_SYMBOL_GPL(inet_diag_dump_one_icsk); - -static int inet_diag_cmd_exact(int cmd, struct sk_buff *in_skb, - const struct nlmsghdr *nlh, - const struct inet_diag_req_v2 *req) -{ - const struct inet_diag_handler *handler; - int err; - - handler = inet_diag_lock_handler(req->sdiag_protocol); - if (IS_ERR(handler)) - err = PTR_ERR(handler); - else if (cmd == SOCK_DIAG_BY_FAMILY) - err = handler->dump_one(in_skb, nlh, req); - else if (cmd == SOCK_DESTROY && handler->destroy) - err = handler->destroy(in_skb, req); - else - err = -EOPNOTSUPP; - inet_diag_unlock_handler(handler); - - return err; -} - -static int bitstring_match(const __be32 *a1, const __be32 *a2, int bits) -{ - int words = bits >> 5; - - bits &= 0x1f; - - if (words) { - if (memcmp(a1, a2, words << 2)) - return 0; - } - if (bits) { - __be32 w1, w2; - __be32 mask; - - w1 = a1[words]; - w2 = a2[words]; - - mask = htonl((0xffffffff) << (32 - bits)); - - if ((w1 ^ w2) & mask) - return 0; - } - - return 1; -} - -static int inet_diag_bc_run(const struct nlattr *_bc, - const struct inet_diag_entry *entry) -{ - const void *bc = nla_data(_bc); - int len = nla_len(_bc); - - while (len > 0) { - int yes = 1; - const struct inet_diag_bc_op *op = bc; - - switch (op->code) { - case INET_DIAG_BC_NOP: - break; - case INET_DIAG_BC_JMP: - yes = 0; - break; - case INET_DIAG_BC_S_GE: - yes = entry->sport >= op[1].no; - break; - case INET_DIAG_BC_S_LE: - yes = entry->sport <= op[1].no; - break; - case INET_DIAG_BC_D_GE: - yes = entry->dport >= op[1].no; - break; - case INET_DIAG_BC_D_LE: - yes = entry->dport <= op[1].no; - break; - case INET_DIAG_BC_AUTO: - yes = !(entry->userlocks & SOCK_BINDPORT_LOCK); - break; - case INET_DIAG_BC_S_COND: - case INET_DIAG_BC_D_COND: { - const struct inet_diag_hostcond *cond; - const __be32 *addr; - - cond = (const struct inet_diag_hostcond *)(op + 1); - if (cond->port != -1 && - cond->port != (op->code == INET_DIAG_BC_S_COND ? - entry->sport : entry->dport)) { - yes = 0; - break; - } - - if (op->code == INET_DIAG_BC_S_COND) - addr = entry->saddr; - else - addr = entry->daddr; - - if (cond->family != AF_UNSPEC && - cond->family != entry->family) { - if (entry->family == AF_INET6 && - cond->family == AF_INET) { - if (addr[0] == 0 && addr[1] == 0 && - addr[2] == htonl(0xffff) && - bitstring_match(addr + 3, - cond->addr, - cond->prefix_len)) - break; - } - yes = 0; - break; - } - - if (cond->prefix_len == 0) - break; - if (bitstring_match(addr, cond->addr, - cond->prefix_len)) - break; - yes = 0; - break; - } - case INET_DIAG_BC_DEV_COND: { - u32 ifindex; - - ifindex = *((const u32 *)(op + 1)); - if (ifindex != entry->ifindex) - yes = 0; - break; - } - case INET_DIAG_BC_MARK_COND: { - struct inet_diag_markcond *cond; - - cond = (struct inet_diag_markcond *)(op + 1); - if ((entry->mark & cond->mask) != cond->mark) - yes = 0; - break; - } - } - - if (yes) { - len -= op->yes; - bc += op->yes; - } else { - len -= op->no; - bc += op->no; - } - } - return len == 0; -} - -/* This helper is available for all sockets (ESTABLISH, TIMEWAIT, SYN_RECV) - */ -static void entry_fill_addrs(struct inet_diag_entry *entry, - const struct sock *sk) -{ -#if IS_ENABLED(CONFIG_IPV6) - if (sk->sk_family == AF_INET6) { - entry->saddr = sk->sk_v6_rcv_saddr.s6_addr32; - entry->daddr = sk->sk_v6_daddr.s6_addr32; - } else -#endif - { - entry->saddr = &sk->sk_rcv_saddr; - entry->daddr = &sk->sk_daddr; - } -} - -int inet_diag_bc_sk(const struct nlattr *bc, struct sock *sk) -{ - struct inet_sock *inet = inet_sk(sk); - struct inet_diag_entry entry; - - if (!bc) - return 1; - - entry.family = sk->sk_family; - entry_fill_addrs(&entry, sk); - entry.sport = inet->inet_num; - entry.dport = ntohs(inet->inet_dport); - entry.ifindex = sk->sk_bound_dev_if; - entry.userlocks = sk_fullsock(sk) ? sk->sk_userlocks : 0; - if (sk_fullsock(sk)) - entry.mark = sk->sk_mark; - else if (sk->sk_state == TCP_NEW_SYN_RECV) - entry.mark = inet_rsk(inet_reqsk(sk))->ir_mark; - else - entry.mark = 0; - - return inet_diag_bc_run(bc, &entry); -} -EXPORT_SYMBOL_GPL(inet_diag_bc_sk); - -static int valid_cc(const void *bc, int len, int cc) -{ - while (len >= 0) { - const struct inet_diag_bc_op *op = bc; - - if (cc > len) - return 0; - if (cc == len) - return 1; - if (op->yes < 4 || op->yes & 3) - return 0; - len -= op->yes; - bc += op->yes; - } - return 0; -} - -/* data is u32 ifindex */ -static bool valid_devcond(const struct inet_diag_bc_op *op, int len, - int *min_len) -{ - /* Check ifindex space. */ - *min_len += sizeof(u32); - if (len < *min_len) - return false; - - return true; -} -/* Validate an inet_diag_hostcond. */ -static bool valid_hostcond(const struct inet_diag_bc_op *op, int len, - int *min_len) -{ - struct inet_diag_hostcond *cond; - int addr_len; - - /* Check hostcond space. */ - *min_len += sizeof(struct inet_diag_hostcond); - if (len < *min_len) - return false; - cond = (struct inet_diag_hostcond *)(op + 1); - - /* Check address family and address length. */ - switch (cond->family) { - case AF_UNSPEC: - addr_len = 0; - break; - case AF_INET: - addr_len = sizeof(struct in_addr); - break; - case AF_INET6: - addr_len = sizeof(struct in6_addr); - break; - default: - return false; - } - *min_len += addr_len; - if (len < *min_len) - return false; - - /* Check prefix length (in bits) vs address length (in bytes). */ - if (cond->prefix_len > 8 * addr_len) - return false; - - return true; -} - -/* Validate a port comparison operator. */ -static bool valid_port_comparison(const struct inet_diag_bc_op *op, - int len, int *min_len) -{ - /* Port comparisons put the port in a follow-on inet_diag_bc_op. */ - *min_len += sizeof(struct inet_diag_bc_op); - if (len < *min_len) - return false; - return true; -} - -static bool valid_markcond(const struct inet_diag_bc_op *op, int len, - int *min_len) -{ - *min_len += sizeof(struct inet_diag_markcond); - return len >= *min_len; -} - -static int inet_diag_bc_audit(const struct nlattr *attr, - const struct sk_buff *skb) -{ - bool net_admin = netlink_net_capable(skb, CAP_NET_ADMIN); - const void *bytecode, *bc; - int bytecode_len, len; - - if (!attr || nla_len(attr) < sizeof(struct inet_diag_bc_op)) - return -EINVAL; - - bytecode = bc = nla_data(attr); - len = bytecode_len = nla_len(attr); - - while (len > 0) { - int min_len = sizeof(struct inet_diag_bc_op); - const struct inet_diag_bc_op *op = bc; - - switch (op->code) { - case INET_DIAG_BC_S_COND: - case INET_DIAG_BC_D_COND: - if (!valid_hostcond(bc, len, &min_len)) - return -EINVAL; - break; - case INET_DIAG_BC_DEV_COND: - if (!valid_devcond(bc, len, &min_len)) - return -EINVAL; - break; - case INET_DIAG_BC_S_GE: - case INET_DIAG_BC_S_LE: - case INET_DIAG_BC_D_GE: - case INET_DIAG_BC_D_LE: - if (!valid_port_comparison(bc, len, &min_len)) - return -EINVAL; - break; - case INET_DIAG_BC_MARK_COND: - if (!net_admin) - return -EPERM; - if (!valid_markcond(bc, len, &min_len)) - return -EINVAL; - break; - case INET_DIAG_BC_AUTO: - case INET_DIAG_BC_JMP: - case INET_DIAG_BC_NOP: - break; - default: - return -EINVAL; - } - - if (op->code != INET_DIAG_BC_NOP) { - if (op->no < min_len || op->no > len + 4 || op->no & 3) - return -EINVAL; - if (op->no < len && - !valid_cc(bytecode, bytecode_len, len - op->no)) - return -EINVAL; - } - - if (op->yes < min_len || op->yes > len + 4 || op->yes & 3) - return -EINVAL; - bc += op->yes; - len -= op->yes; - } - return len == 0 ? 0 : -EINVAL; -} - -static int inet_csk_diag_dump(struct sock *sk, - struct sk_buff *skb, - struct netlink_callback *cb, - const struct inet_diag_req_v2 *r, - const struct nlattr *bc, - bool net_admin) -{ - if (!inet_diag_bc_sk(bc, sk)) - return 0; - - return inet_csk_diag_fill(sk, skb, r, - sk_user_ns(NETLINK_CB(cb->skb).sk), - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh, - net_admin); -} - -static void twsk_build_assert(void) -{ - BUILD_BUG_ON(offsetof(struct inet_timewait_sock, tw_family) != - offsetof(struct sock, sk_family)); - - BUILD_BUG_ON(offsetof(struct inet_timewait_sock, tw_num) != - offsetof(struct inet_sock, inet_num)); - - BUILD_BUG_ON(offsetof(struct inet_timewait_sock, tw_dport) != - offsetof(struct inet_sock, inet_dport)); - - BUILD_BUG_ON(offsetof(struct inet_timewait_sock, tw_rcv_saddr) != - offsetof(struct inet_sock, inet_rcv_saddr)); - - BUILD_BUG_ON(offsetof(struct inet_timewait_sock, tw_daddr) != - offsetof(struct inet_sock, inet_daddr)); - -#if IS_ENABLED(CONFIG_IPV6) - BUILD_BUG_ON(offsetof(struct inet_timewait_sock, tw_v6_rcv_saddr) != - offsetof(struct sock, sk_v6_rcv_saddr)); - - BUILD_BUG_ON(offsetof(struct inet_timewait_sock, tw_v6_daddr) != - offsetof(struct sock, sk_v6_daddr)); -#endif -} - -void inet_diag_dump_icsk(struct inet_hashinfo *hashinfo, struct sk_buff *skb, - struct netlink_callback *cb, - const struct inet_diag_req_v2 *r, struct nlattr *bc) -{ - struct net *net = sock_net(skb->sk); - int i, num, s_i, s_num; - u32 idiag_states = r->idiag_states; - bool net_admin = netlink_net_capable(cb->skb, CAP_NET_ADMIN); - - if (idiag_states & TCPF_SYN_RECV) - idiag_states |= TCPF_NEW_SYN_RECV; - s_i = cb->args[1]; - s_num = num = cb->args[2]; - - if (cb->args[0] == 0) { - if (!(idiag_states & TCPF_LISTEN)) - goto skip_listen_ht; - - for (i = s_i; i < INET_LHTABLE_SIZE; i++) { - struct inet_listen_hashbucket *ilb; - struct sock *sk; - - num = 0; - ilb = &hashinfo->listening_hash[i]; - spin_lock_bh(&ilb->lock); - sk_for_each(sk, &ilb->head) { - struct inet_sock *inet = inet_sk(sk); - - if (!net_eq(sock_net(sk), net)) - continue; - - if (num < s_num) { - num++; - continue; - } - - if (r->sdiag_family != AF_UNSPEC && - sk->sk_family != r->sdiag_family) - goto next_listen; - - if (r->id.idiag_sport != inet->inet_sport && - r->id.idiag_sport) - goto next_listen; - - if (r->id.idiag_dport || - cb->args[3] > 0) - goto next_listen; - - if (inet_csk_diag_dump(sk, skb, cb, r, - bc, net_admin) < 0) { - spin_unlock_bh(&ilb->lock); - goto done; - } - -next_listen: - cb->args[3] = 0; - cb->args[4] = 0; - ++num; - } - spin_unlock_bh(&ilb->lock); - - s_num = 0; - cb->args[3] = 0; - cb->args[4] = 0; - } -skip_listen_ht: - cb->args[0] = 1; - s_i = num = s_num = 0; - } - - if (!(idiag_states & ~TCPF_LISTEN)) - goto out; - - for (i = s_i; i <= hashinfo->ehash_mask; i++) { - struct inet_ehash_bucket *head = &hashinfo->ehash[i]; - spinlock_t *lock = inet_ehash_lockp(hashinfo, i); - struct hlist_nulls_node *node; - struct sock *sk; - - num = 0; - - if (hlist_nulls_empty(&head->chain)) - continue; - - if (i > s_i) - s_num = 0; - - spin_lock_bh(lock); - sk_nulls_for_each(sk, node, &head->chain) { - int state, res; - - if (!net_eq(sock_net(sk), net)) - continue; - if (num < s_num) - goto next_normal; - state = (sk->sk_state == TCP_TIME_WAIT) ? - inet_twsk(sk)->tw_substate : sk->sk_state; - if (!(idiag_states & (1 << state))) - goto next_normal; - if (r->sdiag_family != AF_UNSPEC && - sk->sk_family != r->sdiag_family) - goto next_normal; - if (r->id.idiag_sport != htons(sk->sk_num) && - r->id.idiag_sport) - goto next_normal; - if (r->id.idiag_dport != sk->sk_dport && - r->id.idiag_dport) - goto next_normal; - twsk_build_assert(); - - if (!inet_diag_bc_sk(bc, sk)) - goto next_normal; - - res = sk_diag_fill(sk, skb, r, - sk_user_ns(NETLINK_CB(cb->skb).sk), - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, NLM_F_MULTI, - cb->nlh, net_admin); - if (res < 0) { - spin_unlock_bh(lock); - goto done; - } -next_normal: - ++num; - } - - spin_unlock_bh(lock); - cond_resched(); - } - -done: - cb->args[1] = i; - cb->args[2] = num; -out: - ; -} -EXPORT_SYMBOL_GPL(inet_diag_dump_icsk); - -static int __inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, - const struct inet_diag_req_v2 *r, - struct nlattr *bc) -{ - const struct inet_diag_handler *handler; - int err = 0; - - handler = inet_diag_lock_handler(r->sdiag_protocol); - if (!IS_ERR(handler)) - handler->dump(skb, cb, r, bc); - else - err = PTR_ERR(handler); - inet_diag_unlock_handler(handler); - - return err ? : skb->len; -} - -static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) -{ - int hdrlen = sizeof(struct inet_diag_req_v2); - struct nlattr *bc = NULL; - - if (nlmsg_attrlen(cb->nlh, hdrlen)) - bc = nlmsg_find_attr(cb->nlh, hdrlen, INET_DIAG_REQ_BYTECODE); - - return __inet_diag_dump(skb, cb, nlmsg_data(cb->nlh), bc); -} - -static int inet_diag_type2proto(int type) -{ - switch (type) { - case TCPDIAG_GETSOCK: - return IPPROTO_TCP; - case DCCPDIAG_GETSOCK: - return IPPROTO_DCCP; - default: - return 0; - } -} - -static int inet_diag_dump_compat(struct sk_buff *skb, - struct netlink_callback *cb) -{ - struct inet_diag_req *rc = nlmsg_data(cb->nlh); - int hdrlen = sizeof(struct inet_diag_req); - struct inet_diag_req_v2 req; - struct nlattr *bc = NULL; - - req.sdiag_family = AF_UNSPEC; /* compatibility */ - req.sdiag_protocol = inet_diag_type2proto(cb->nlh->nlmsg_type); - req.idiag_ext = rc->idiag_ext; - req.idiag_states = rc->idiag_states; - req.id = rc->id; - - if (nlmsg_attrlen(cb->nlh, hdrlen)) - bc = nlmsg_find_attr(cb->nlh, hdrlen, INET_DIAG_REQ_BYTECODE); - - return __inet_diag_dump(skb, cb, &req, bc); -} - -static int inet_diag_get_exact_compat(struct sk_buff *in_skb, - const struct nlmsghdr *nlh) -{ - struct inet_diag_req *rc = nlmsg_data(nlh); - struct inet_diag_req_v2 req; - - req.sdiag_family = rc->idiag_family; - req.sdiag_protocol = inet_diag_type2proto(nlh->nlmsg_type); - req.idiag_ext = rc->idiag_ext; - req.idiag_states = rc->idiag_states; - req.id = rc->id; - - return inet_diag_cmd_exact(SOCK_DIAG_BY_FAMILY, in_skb, nlh, &req); -} - -static int inet_diag_rcv_msg_compat(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - int hdrlen = sizeof(struct inet_diag_req); - struct net *net = sock_net(skb->sk); - - if (nlh->nlmsg_type >= INET_DIAG_GETSOCK_MAX || - nlmsg_len(nlh) < hdrlen) - return -EINVAL; - - if (nlh->nlmsg_flags & NLM_F_DUMP) { - if (nlmsg_attrlen(nlh, hdrlen)) { - struct nlattr *attr; - int err; - - attr = nlmsg_find_attr(nlh, hdrlen, - INET_DIAG_REQ_BYTECODE); - err = inet_diag_bc_audit(attr, skb); - if (err) - return err; - } - { - struct netlink_dump_control c = { - .dump = inet_diag_dump_compat, - }; - return netlink_dump_start(net->diag_nlsk, skb, nlh, &c); - } - } - - return inet_diag_get_exact_compat(skb, nlh); -} - -static int inet_diag_handler_cmd(struct sk_buff *skb, struct nlmsghdr *h) -{ - int hdrlen = sizeof(struct inet_diag_req_v2); - struct net *net = sock_net(skb->sk); - - if (nlmsg_len(h) < hdrlen) - return -EINVAL; - - if (h->nlmsg_type == SOCK_DIAG_BY_FAMILY && - h->nlmsg_flags & NLM_F_DUMP) { - if (nlmsg_attrlen(h, hdrlen)) { - struct nlattr *attr; - int err; - - attr = nlmsg_find_attr(h, hdrlen, - INET_DIAG_REQ_BYTECODE); - err = inet_diag_bc_audit(attr, skb); - if (err) - return err; - } - { - struct netlink_dump_control c = { - .dump = inet_diag_dump, - }; - return netlink_dump_start(net->diag_nlsk, skb, h, &c); - } - } - - return inet_diag_cmd_exact(h->nlmsg_type, skb, h, nlmsg_data(h)); -} - -static -int inet_diag_handler_get_info(struct sk_buff *skb, struct sock *sk) -{ - const struct inet_diag_handler *handler; - struct nlmsghdr *nlh; - struct nlattr *attr; - struct inet_diag_msg *r; - void *info = NULL; - int err = 0; - - nlh = nlmsg_put(skb, 0, 0, SOCK_DIAG_BY_FAMILY, sizeof(*r), 0); - if (!nlh) - return -ENOMEM; - - r = nlmsg_data(nlh); - memset(r, 0, sizeof(*r)); - inet_diag_msg_common_fill(r, sk); - if (sk->sk_type == SOCK_DGRAM || sk->sk_type == SOCK_STREAM) - r->id.idiag_sport = inet_sk(sk)->inet_sport; - r->idiag_state = sk->sk_state; - - if ((err = nla_put_u8(skb, INET_DIAG_PROTOCOL, sk->sk_protocol))) { - nlmsg_cancel(skb, nlh); - return err; - } - - handler = inet_diag_lock_handler(sk->sk_protocol); - if (IS_ERR(handler)) { - inet_diag_unlock_handler(handler); - nlmsg_cancel(skb, nlh); - return PTR_ERR(handler); - } - - attr = handler->idiag_info_size - ? nla_reserve_64bit(skb, INET_DIAG_INFO, - handler->idiag_info_size, - INET_DIAG_PAD) - : NULL; - if (attr) - info = nla_data(attr); - - handler->idiag_get_info(sk, r, info); - inet_diag_unlock_handler(handler); - - nlmsg_end(skb, nlh); - return 0; -} - -static const struct sock_diag_handler inet_diag_handler = { - .family = AF_INET, - .dump = inet_diag_handler_cmd, - .get_info = inet_diag_handler_get_info, - .destroy = inet_diag_handler_cmd, -}; - -static const struct sock_diag_handler inet6_diag_handler = { - .family = AF_INET6, - .dump = inet_diag_handler_cmd, - .get_info = inet_diag_handler_get_info, - .destroy = inet_diag_handler_cmd, -}; - -int inet_diag_register(const struct inet_diag_handler *h) -{ - const __u16 type = h->idiag_type; - int err = -EINVAL; - - if (type >= IPPROTO_MAX) - goto out; - - mutex_lock(&inet_diag_table_mutex); - err = -EEXIST; - if (!inet_diag_table[type]) { - inet_diag_table[type] = h; - err = 0; - } - mutex_unlock(&inet_diag_table_mutex); -out: - return err; -} -EXPORT_SYMBOL_GPL(inet_diag_register); - -void inet_diag_unregister(const struct inet_diag_handler *h) -{ - const __u16 type = h->idiag_type; - - if (type >= IPPROTO_MAX) - return; - - mutex_lock(&inet_diag_table_mutex); - inet_diag_table[type] = NULL; - mutex_unlock(&inet_diag_table_mutex); -} -EXPORT_SYMBOL_GPL(inet_diag_unregister); - -static int __init inet_diag_init(void) -{ - const int inet_diag_table_size = (IPPROTO_MAX * - sizeof(struct inet_diag_handler *)); - int err = -ENOMEM; - - inet_diag_table = kzalloc(inet_diag_table_size, GFP_KERNEL); - if (!inet_diag_table) - goto out; - - err = sock_diag_register(&inet_diag_handler); - if (err) - goto out_free_nl; - - err = sock_diag_register(&inet6_diag_handler); - if (err) - goto out_free_inet; - - sock_diag_register_inet_compat(inet_diag_rcv_msg_compat); -out: - return err; - -out_free_inet: - sock_diag_unregister(&inet_diag_handler); -out_free_nl: - kfree(inet_diag_table); - goto out; -} - -static void __exit inet_diag_exit(void) -{ - sock_diag_unregister(&inet6_diag_handler); - sock_diag_unregister(&inet_diag_handler); - sock_diag_unregister_inet_compat(inet_diag_rcv_msg_compat); - kfree(inet_diag_table); -} - -module_init(inet_diag_init); -module_exit(inet_diag_exit); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2 /* AF_INET */); -MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 10 /* AF_INET6 */); diff --git a/src/linux/net/ipv4/inet_fragment.c b/src/linux/net/ipv4/inet_fragment.c deleted file mode 100644 index b5e9317..0000000 --- a/src/linux/net/ipv4/inet_fragment.c +++ /dev/null @@ -1,439 +0,0 @@ -/* - * inet fragments management - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Pavel Emelyanov - * Started as consolidation of ipv4/ip_fragment.c, - * ipv6/reassembly. and ipv6 nf conntrack reassembly - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#define INETFRAGS_EVICT_BUCKETS 128 -#define INETFRAGS_EVICT_MAX 512 - -/* don't rebuild inetfrag table with new secret more often than this */ -#define INETFRAGS_MIN_REBUILD_INTERVAL (5 * HZ) - -/* Given the OR values of all fragments, apply RFC 3168 5.3 requirements - * Value : 0xff if frame should be dropped. - * 0 or INET_ECN_CE value, to be ORed in to final iph->tos field - */ -const u8 ip_frag_ecn_table[16] = { - /* at least one fragment had CE, and others ECT_0 or ECT_1 */ - [IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0] = INET_ECN_CE, - [IPFRAG_ECN_CE | IPFRAG_ECN_ECT_1] = INET_ECN_CE, - [IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1] = INET_ECN_CE, - - /* invalid combinations : drop frame */ - [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE] = 0xff, - [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_ECT_0] = 0xff, - [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_ECT_1] = 0xff, - [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1] = 0xff, - [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0] = 0xff, - [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE | IPFRAG_ECN_ECT_1] = 0xff, - [IPFRAG_ECN_NOT_ECT | IPFRAG_ECN_CE | IPFRAG_ECN_ECT_0 | IPFRAG_ECN_ECT_1] = 0xff, -}; -EXPORT_SYMBOL(ip_frag_ecn_table); - -static unsigned int -inet_frag_hashfn(const struct inet_frags *f, const struct inet_frag_queue *q) -{ - return f->hashfn(q) & (INETFRAGS_HASHSZ - 1); -} - -static bool inet_frag_may_rebuild(struct inet_frags *f) -{ - return time_after(jiffies, - f->last_rebuild_jiffies + INETFRAGS_MIN_REBUILD_INTERVAL); -} - -static void inet_frag_secret_rebuild(struct inet_frags *f) -{ - int i; - - write_seqlock_bh(&f->rnd_seqlock); - - if (!inet_frag_may_rebuild(f)) - goto out; - - get_random_bytes(&f->rnd, sizeof(u32)); - - for (i = 0; i < INETFRAGS_HASHSZ; i++) { - struct inet_frag_bucket *hb; - struct inet_frag_queue *q; - struct hlist_node *n; - - hb = &f->hash[i]; - spin_lock(&hb->chain_lock); - - hlist_for_each_entry_safe(q, n, &hb->chain, list) { - unsigned int hval = inet_frag_hashfn(f, q); - - if (hval != i) { - struct inet_frag_bucket *hb_dest; - - hlist_del(&q->list); - - /* Relink to new hash chain. */ - hb_dest = &f->hash[hval]; - - /* This is the only place where we take - * another chain_lock while already holding - * one. As this will not run concurrently, - * we cannot deadlock on hb_dest lock below, if its - * already locked it will be released soon since - * other caller cannot be waiting for hb lock - * that we've taken above. - */ - spin_lock_nested(&hb_dest->chain_lock, - SINGLE_DEPTH_NESTING); - hlist_add_head(&q->list, &hb_dest->chain); - spin_unlock(&hb_dest->chain_lock); - } - } - spin_unlock(&hb->chain_lock); - } - - f->rebuild = false; - f->last_rebuild_jiffies = jiffies; -out: - write_sequnlock_bh(&f->rnd_seqlock); -} - -static bool inet_fragq_should_evict(const struct inet_frag_queue *q) -{ - return q->net->low_thresh == 0 || - frag_mem_limit(q->net) >= q->net->low_thresh; -} - -static unsigned int -inet_evict_bucket(struct inet_frags *f, struct inet_frag_bucket *hb) -{ - struct inet_frag_queue *fq; - struct hlist_node *n; - unsigned int evicted = 0; - HLIST_HEAD(expired); - - spin_lock(&hb->chain_lock); - - hlist_for_each_entry_safe(fq, n, &hb->chain, list) { - if (!inet_fragq_should_evict(fq)) - continue; - - if (!del_timer(&fq->timer)) - continue; - - hlist_add_head(&fq->list_evictor, &expired); - ++evicted; - } - - spin_unlock(&hb->chain_lock); - - hlist_for_each_entry_safe(fq, n, &expired, list_evictor) - f->frag_expire((unsigned long) fq); - - return evicted; -} - -static void inet_frag_worker(struct work_struct *work) -{ - unsigned int budget = INETFRAGS_EVICT_BUCKETS; - unsigned int i, evicted = 0; - struct inet_frags *f; - - f = container_of(work, struct inet_frags, frags_work); - - BUILD_BUG_ON(INETFRAGS_EVICT_BUCKETS >= INETFRAGS_HASHSZ); - - local_bh_disable(); - - for (i = ACCESS_ONCE(f->next_bucket); budget; --budget) { - evicted += inet_evict_bucket(f, &f->hash[i]); - i = (i + 1) & (INETFRAGS_HASHSZ - 1); - if (evicted > INETFRAGS_EVICT_MAX) - break; - } - - f->next_bucket = i; - - local_bh_enable(); - - if (f->rebuild && inet_frag_may_rebuild(f)) - inet_frag_secret_rebuild(f); -} - -static void inet_frag_schedule_worker(struct inet_frags *f) -{ - if (unlikely(!work_pending(&f->frags_work))) - schedule_work(&f->frags_work); -} - -int inet_frags_init(struct inet_frags *f) -{ - int i; - - INIT_WORK(&f->frags_work, inet_frag_worker); - - for (i = 0; i < INETFRAGS_HASHSZ; i++) { - struct inet_frag_bucket *hb = &f->hash[i]; - - spin_lock_init(&hb->chain_lock); - INIT_HLIST_HEAD(&hb->chain); - } - - seqlock_init(&f->rnd_seqlock); - f->last_rebuild_jiffies = 0; - f->frags_cachep = kmem_cache_create(f->frags_cache_name, f->qsize, 0, 0, - NULL); - if (!f->frags_cachep) - return -ENOMEM; - - return 0; -} -EXPORT_SYMBOL(inet_frags_init); - -void inet_frags_fini(struct inet_frags *f) -{ - cancel_work_sync(&f->frags_work); - kmem_cache_destroy(f->frags_cachep); -} -EXPORT_SYMBOL(inet_frags_fini); - -void inet_frags_exit_net(struct netns_frags *nf, struct inet_frags *f) -{ - unsigned int seq; - int i; - - nf->low_thresh = 0; - -evict_again: - local_bh_disable(); - seq = read_seqbegin(&f->rnd_seqlock); - - for (i = 0; i < INETFRAGS_HASHSZ ; i++) - inet_evict_bucket(f, &f->hash[i]); - - local_bh_enable(); - cond_resched(); - - if (read_seqretry(&f->rnd_seqlock, seq) || - percpu_counter_sum(&nf->mem)) - goto evict_again; - - percpu_counter_destroy(&nf->mem); -} -EXPORT_SYMBOL(inet_frags_exit_net); - -static struct inet_frag_bucket * -get_frag_bucket_locked(struct inet_frag_queue *fq, struct inet_frags *f) -__acquires(hb->chain_lock) -{ - struct inet_frag_bucket *hb; - unsigned int seq, hash; - - restart: - seq = read_seqbegin(&f->rnd_seqlock); - - hash = inet_frag_hashfn(f, fq); - hb = &f->hash[hash]; - - spin_lock(&hb->chain_lock); - if (read_seqretry(&f->rnd_seqlock, seq)) { - spin_unlock(&hb->chain_lock); - goto restart; - } - - return hb; -} - -static inline void fq_unlink(struct inet_frag_queue *fq, struct inet_frags *f) -{ - struct inet_frag_bucket *hb; - - hb = get_frag_bucket_locked(fq, f); - hlist_del(&fq->list); - fq->flags |= INET_FRAG_COMPLETE; - spin_unlock(&hb->chain_lock); -} - -void inet_frag_kill(struct inet_frag_queue *fq, struct inet_frags *f) -{ - if (del_timer(&fq->timer)) - atomic_dec(&fq->refcnt); - - if (!(fq->flags & INET_FRAG_COMPLETE)) { - fq_unlink(fq, f); - atomic_dec(&fq->refcnt); - } -} -EXPORT_SYMBOL(inet_frag_kill); - -void inet_frag_destroy(struct inet_frag_queue *q, struct inet_frags *f) -{ - struct sk_buff *fp; - struct netns_frags *nf; - unsigned int sum, sum_truesize = 0; - - WARN_ON(!(q->flags & INET_FRAG_COMPLETE)); - WARN_ON(del_timer(&q->timer) != 0); - - /* Release all fragment data. */ - fp = q->fragments; - nf = q->net; - while (fp) { - struct sk_buff *xp = fp->next; - - sum_truesize += fp->truesize; - kfree_skb(fp); - fp = xp; - } - sum = sum_truesize + f->qsize; - - if (f->destructor) - f->destructor(q); - kmem_cache_free(f->frags_cachep, q); - - sub_frag_mem_limit(nf, sum); -} -EXPORT_SYMBOL(inet_frag_destroy); - -static struct inet_frag_queue *inet_frag_intern(struct netns_frags *nf, - struct inet_frag_queue *qp_in, - struct inet_frags *f, - void *arg) -{ - struct inet_frag_bucket *hb = get_frag_bucket_locked(qp_in, f); - struct inet_frag_queue *qp; - -#ifdef CONFIG_SMP - /* With SMP race we have to recheck hash table, because - * such entry could have been created on other cpu before - * we acquired hash bucket lock. - */ - hlist_for_each_entry(qp, &hb->chain, list) { - if (qp->net == nf && f->match(qp, arg)) { - atomic_inc(&qp->refcnt); - spin_unlock(&hb->chain_lock); - qp_in->flags |= INET_FRAG_COMPLETE; - inet_frag_put(qp_in, f); - return qp; - } - } -#endif - qp = qp_in; - if (!mod_timer(&qp->timer, jiffies + nf->timeout)) - atomic_inc(&qp->refcnt); - - atomic_inc(&qp->refcnt); - hlist_add_head(&qp->list, &hb->chain); - - spin_unlock(&hb->chain_lock); - - return qp; -} - -static struct inet_frag_queue *inet_frag_alloc(struct netns_frags *nf, - struct inet_frags *f, - void *arg) -{ - struct inet_frag_queue *q; - - if (!nf->high_thresh || frag_mem_limit(nf) > nf->high_thresh) { - inet_frag_schedule_worker(f); - return NULL; - } - - q = kmem_cache_zalloc(f->frags_cachep, GFP_ATOMIC); - if (!q) - return NULL; - - q->net = nf; - f->constructor(q, arg); - add_frag_mem_limit(nf, f->qsize); - - setup_timer(&q->timer, f->frag_expire, (unsigned long)q); - spin_lock_init(&q->lock); - atomic_set(&q->refcnt, 1); - - return q; -} - -static struct inet_frag_queue *inet_frag_create(struct netns_frags *nf, - struct inet_frags *f, - void *arg) -{ - struct inet_frag_queue *q; - - q = inet_frag_alloc(nf, f, arg); - if (!q) - return NULL; - - return inet_frag_intern(nf, q, f, arg); -} - -struct inet_frag_queue *inet_frag_find(struct netns_frags *nf, - struct inet_frags *f, void *key, - unsigned int hash) -{ - struct inet_frag_bucket *hb; - struct inet_frag_queue *q; - int depth = 0; - - if (frag_mem_limit(nf) > nf->low_thresh) - inet_frag_schedule_worker(f); - - hash &= (INETFRAGS_HASHSZ - 1); - hb = &f->hash[hash]; - - spin_lock(&hb->chain_lock); - hlist_for_each_entry(q, &hb->chain, list) { - if (q->net == nf && f->match(q, key)) { - atomic_inc(&q->refcnt); - spin_unlock(&hb->chain_lock); - return q; - } - depth++; - } - spin_unlock(&hb->chain_lock); - - if (depth <= INETFRAGS_MAXDEPTH) - return inet_frag_create(nf, f, key); - - if (inet_frag_may_rebuild(f)) { - if (!f->rebuild) - f->rebuild = true; - inet_frag_schedule_worker(f); - } - - return ERR_PTR(-ENOBUFS); -} -EXPORT_SYMBOL(inet_frag_find); - -void inet_frag_maybe_warn_overflow(struct inet_frag_queue *q, - const char *prefix) -{ - static const char msg[] = "inet_frag_find: Fragment hash bucket" - " list length grew over limit " __stringify(INETFRAGS_MAXDEPTH) - ". Dropping fragment.\n"; - - if (PTR_ERR(q) == -ENOBUFS) - net_dbg_ratelimited("%s%s", prefix, msg); -} -EXPORT_SYMBOL(inet_frag_maybe_warn_overflow); diff --git a/src/linux/net/ipv4/inet_hashtables.c b/src/linux/net/ipv4/inet_hashtables.c deleted file mode 100644 index ca97835..0000000 --- a/src/linux/net/ipv4/inet_hashtables.c +++ /dev/null @@ -1,704 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Generic INET transport hashtables - * - * Authors: Lotsa people, from code originally in tcp - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -static u32 inet_ehashfn(const struct net *net, const __be32 laddr, - const __u16 lport, const __be32 faddr, - const __be16 fport) -{ - static u32 inet_ehash_secret __read_mostly; - - net_get_random_once(&inet_ehash_secret, sizeof(inet_ehash_secret)); - - return __inet_ehashfn(laddr, lport, faddr, fport, - inet_ehash_secret + net_hash_mix(net)); -} - -/* This function handles inet_sock, but also timewait and request sockets - * for IPv4/IPv6. - */ -u32 sk_ehashfn(const struct sock *sk) -{ -#if IS_ENABLED(CONFIG_IPV6) - if (sk->sk_family == AF_INET6 && - !ipv6_addr_v4mapped(&sk->sk_v6_daddr)) - return inet6_ehashfn(sock_net(sk), - &sk->sk_v6_rcv_saddr, sk->sk_num, - &sk->sk_v6_daddr, sk->sk_dport); -#endif - return inet_ehashfn(sock_net(sk), - sk->sk_rcv_saddr, sk->sk_num, - sk->sk_daddr, sk->sk_dport); -} - -/* - * Allocate and initialize a new local port bind bucket. - * The bindhash mutex for snum's hash chain must be held here. - */ -struct inet_bind_bucket *inet_bind_bucket_create(struct kmem_cache *cachep, - struct net *net, - struct inet_bind_hashbucket *head, - const unsigned short snum) -{ - struct inet_bind_bucket *tb = kmem_cache_alloc(cachep, GFP_ATOMIC); - - if (tb) { - write_pnet(&tb->ib_net, net); - tb->port = snum; - tb->fastreuse = 0; - tb->fastreuseport = 0; - tb->num_owners = 0; - INIT_HLIST_HEAD(&tb->owners); - hlist_add_head(&tb->node, &head->chain); - } - return tb; -} - -/* - * Caller must hold hashbucket lock for this tb with local BH disabled - */ -void inet_bind_bucket_destroy(struct kmem_cache *cachep, struct inet_bind_bucket *tb) -{ - if (hlist_empty(&tb->owners)) { - __hlist_del(&tb->node); - kmem_cache_free(cachep, tb); - } -} - -void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb, - const unsigned short snum) -{ - inet_sk(sk)->inet_num = snum; - sk_add_bind_node(sk, &tb->owners); - tb->num_owners++; - inet_csk(sk)->icsk_bind_hash = tb; -} - -/* - * Get rid of any references to a local port held by the given sock. - */ -static void __inet_put_port(struct sock *sk) -{ - struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; - const int bhash = inet_bhashfn(sock_net(sk), inet_sk(sk)->inet_num, - hashinfo->bhash_size); - struct inet_bind_hashbucket *head = &hashinfo->bhash[bhash]; - struct inet_bind_bucket *tb; - - spin_lock(&head->lock); - tb = inet_csk(sk)->icsk_bind_hash; - __sk_del_bind_node(sk); - tb->num_owners--; - inet_csk(sk)->icsk_bind_hash = NULL; - inet_sk(sk)->inet_num = 0; - inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb); - spin_unlock(&head->lock); -} - -void inet_put_port(struct sock *sk) -{ - local_bh_disable(); - __inet_put_port(sk); - local_bh_enable(); -} -EXPORT_SYMBOL(inet_put_port); - -int __inet_inherit_port(const struct sock *sk, struct sock *child) -{ - struct inet_hashinfo *table = sk->sk_prot->h.hashinfo; - unsigned short port = inet_sk(child)->inet_num; - const int bhash = inet_bhashfn(sock_net(sk), port, - table->bhash_size); - struct inet_bind_hashbucket *head = &table->bhash[bhash]; - struct inet_bind_bucket *tb; - - spin_lock(&head->lock); - tb = inet_csk(sk)->icsk_bind_hash; - if (unlikely(!tb)) { - spin_unlock(&head->lock); - return -ENOENT; - } - if (tb->port != port) { - /* NOTE: using tproxy and redirecting skbs to a proxy - * on a different listener port breaks the assumption - * that the listener socket's icsk_bind_hash is the same - * as that of the child socket. We have to look up or - * create a new bind bucket for the child here. */ - inet_bind_bucket_for_each(tb, &head->chain) { - if (net_eq(ib_net(tb), sock_net(sk)) && - tb->port == port) - break; - } - if (!tb) { - tb = inet_bind_bucket_create(table->bind_bucket_cachep, - sock_net(sk), head, port); - if (!tb) { - spin_unlock(&head->lock); - return -ENOMEM; - } - } - } - inet_bind_hash(child, tb, port); - spin_unlock(&head->lock); - - return 0; -} -EXPORT_SYMBOL_GPL(__inet_inherit_port); - -static inline int compute_score(struct sock *sk, struct net *net, - const unsigned short hnum, const __be32 daddr, - const int dif, bool exact_dif) -{ - int score = -1; - struct inet_sock *inet = inet_sk(sk); - - if (net_eq(sock_net(sk), net) && inet->inet_num == hnum && - !ipv6_only_sock(sk)) { - __be32 rcv_saddr = inet->inet_rcv_saddr; - score = sk->sk_family == PF_INET ? 2 : 1; - if (rcv_saddr) { - if (rcv_saddr != daddr) - return -1; - score += 4; - } - if (sk->sk_bound_dev_if || exact_dif) { - if (sk->sk_bound_dev_if != dif) - return -1; - score += 4; - } - if (sk->sk_incoming_cpu == raw_smp_processor_id()) - score++; - } - return score; -} - -/* - * Here are some nice properties to exploit here. The BSD API - * does not allow a listening sock to specify the remote port nor the - * remote address for the connection. So always assume those are both - * wildcarded during the search since they can never be otherwise. - */ - -/* called with rcu_read_lock() : No refcount taken on the socket */ -struct sock *__inet_lookup_listener(struct net *net, - struct inet_hashinfo *hashinfo, - struct sk_buff *skb, int doff, - const __be32 saddr, __be16 sport, - const __be32 daddr, const unsigned short hnum, - const int dif) -{ - unsigned int hash = inet_lhashfn(net, hnum); - struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash]; - int score, hiscore = 0, matches = 0, reuseport = 0; - bool exact_dif = inet_exact_dif_match(net, skb); - struct sock *sk, *result = NULL; - u32 phash = 0; - - sk_for_each_rcu(sk, &ilb->head) { - score = compute_score(sk, net, hnum, daddr, dif, exact_dif); - if (score > hiscore) { - reuseport = sk->sk_reuseport; - if (reuseport) { - phash = inet_ehashfn(net, daddr, hnum, - saddr, sport); - result = reuseport_select_sock(sk, phash, - skb, doff); - if (result) - return result; - matches = 1; - } - result = sk; - hiscore = score; - } else if (score == hiscore && reuseport) { - matches++; - if (reciprocal_scale(phash, matches) == 0) - result = sk; - phash = next_pseudo_random32(phash); - } - } - return result; -} -EXPORT_SYMBOL_GPL(__inet_lookup_listener); - -/* All sockets share common refcount, but have different destructors */ -void sock_gen_put(struct sock *sk) -{ - if (!atomic_dec_and_test(&sk->sk_refcnt)) - return; - - if (sk->sk_state == TCP_TIME_WAIT) - inet_twsk_free(inet_twsk(sk)); - else if (sk->sk_state == TCP_NEW_SYN_RECV) - reqsk_free(inet_reqsk(sk)); - else - sk_free(sk); -} -EXPORT_SYMBOL_GPL(sock_gen_put); - -void sock_edemux(struct sk_buff *skb) -{ - sock_gen_put(skb->sk); -} -EXPORT_SYMBOL(sock_edemux); - -struct sock *__inet_lookup_established(struct net *net, - struct inet_hashinfo *hashinfo, - const __be32 saddr, const __be16 sport, - const __be32 daddr, const u16 hnum, - const int dif) -{ - INET_ADDR_COOKIE(acookie, saddr, daddr); - const __portpair ports = INET_COMBINED_PORTS(sport, hnum); - struct sock *sk; - const struct hlist_nulls_node *node; - /* Optimize here for direct hit, only listening connections can - * have wildcards anyways. - */ - unsigned int hash = inet_ehashfn(net, daddr, hnum, saddr, sport); - unsigned int slot = hash & hashinfo->ehash_mask; - struct inet_ehash_bucket *head = &hashinfo->ehash[slot]; - -begin: - sk_nulls_for_each_rcu(sk, node, &head->chain) { - if (sk->sk_hash != hash) - continue; - if (likely(INET_MATCH(sk, net, acookie, - saddr, daddr, ports, dif))) { - if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) - goto out; - if (unlikely(!INET_MATCH(sk, net, acookie, - saddr, daddr, ports, dif))) { - sock_gen_put(sk); - goto begin; - } - goto found; - } - } - /* - * if the nulls value we got at the end of this lookup is - * not the expected one, we must restart lookup. - * We probably met an item that was moved to another chain. - */ - if (get_nulls_value(node) != slot) - goto begin; -out: - sk = NULL; -found: - return sk; -} -EXPORT_SYMBOL_GPL(__inet_lookup_established); - -/* called with local bh disabled */ -static int __inet_check_established(struct inet_timewait_death_row *death_row, - struct sock *sk, __u16 lport, - struct inet_timewait_sock **twp) -{ - struct inet_hashinfo *hinfo = death_row->hashinfo; - struct inet_sock *inet = inet_sk(sk); - __be32 daddr = inet->inet_rcv_saddr; - __be32 saddr = inet->inet_daddr; - int dif = sk->sk_bound_dev_if; - INET_ADDR_COOKIE(acookie, saddr, daddr); - const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport); - struct net *net = sock_net(sk); - unsigned int hash = inet_ehashfn(net, daddr, lport, - saddr, inet->inet_dport); - struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); - spinlock_t *lock = inet_ehash_lockp(hinfo, hash); - struct sock *sk2; - const struct hlist_nulls_node *node; - struct inet_timewait_sock *tw = NULL; - - spin_lock(lock); - - sk_nulls_for_each(sk2, node, &head->chain) { - if (sk2->sk_hash != hash) - continue; - - if (likely(INET_MATCH(sk2, net, acookie, - saddr, daddr, ports, dif))) { - if (sk2->sk_state == TCP_TIME_WAIT) { - tw = inet_twsk(sk2); - if (twsk_unique(sk, sk2, twp)) - break; - } - goto not_unique; - } - } - - /* Must record num and sport now. Otherwise we will see - * in hash table socket with a funny identity. - */ - inet->inet_num = lport; - inet->inet_sport = htons(lport); - sk->sk_hash = hash; - WARN_ON(!sk_unhashed(sk)); - __sk_nulls_add_node_rcu(sk, &head->chain); - if (tw) { - sk_nulls_del_node_init_rcu((struct sock *)tw); - __NET_INC_STATS(net, LINUX_MIB_TIMEWAITRECYCLED); - } - spin_unlock(lock); - sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); - - if (twp) { - *twp = tw; - } else if (tw) { - /* Silly. Should hash-dance instead... */ - inet_twsk_deschedule_put(tw); - } - return 0; - -not_unique: - spin_unlock(lock); - return -EADDRNOTAVAIL; -} - -static u32 inet_sk_port_offset(const struct sock *sk) -{ - const struct inet_sock *inet = inet_sk(sk); - - return secure_ipv4_port_ephemeral(inet->inet_rcv_saddr, - inet->inet_daddr, - inet->inet_dport); -} - -/* insert a socket into ehash, and eventually remove another one - * (The another one can be a SYN_RECV or TIMEWAIT - */ -bool inet_ehash_insert(struct sock *sk, struct sock *osk) -{ - struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; - struct hlist_nulls_head *list; - struct inet_ehash_bucket *head; - spinlock_t *lock; - bool ret = true; - - WARN_ON_ONCE(!sk_unhashed(sk)); - - sk->sk_hash = sk_ehashfn(sk); - head = inet_ehash_bucket(hashinfo, sk->sk_hash); - list = &head->chain; - lock = inet_ehash_lockp(hashinfo, sk->sk_hash); - - spin_lock(lock); - if (osk) { - WARN_ON_ONCE(sk->sk_hash != osk->sk_hash); - ret = sk_nulls_del_node_init_rcu(osk); - } - if (ret) - __sk_nulls_add_node_rcu(sk, list); - spin_unlock(lock); - return ret; -} - -bool inet_ehash_nolisten(struct sock *sk, struct sock *osk) -{ - bool ok = inet_ehash_insert(sk, osk); - - if (ok) { - sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); - } else { - percpu_counter_inc(sk->sk_prot->orphan_count); - sk->sk_state = TCP_CLOSE; - sock_set_flag(sk, SOCK_DEAD); - inet_csk_destroy_sock(sk); - } - return ok; -} -EXPORT_SYMBOL_GPL(inet_ehash_nolisten); - -static int inet_reuseport_add_sock(struct sock *sk, - struct inet_listen_hashbucket *ilb, - int (*saddr_same)(const struct sock *sk1, - const struct sock *sk2, - bool match_wildcard)) -{ - struct inet_bind_bucket *tb = inet_csk(sk)->icsk_bind_hash; - struct sock *sk2; - kuid_t uid = sock_i_uid(sk); - - sk_for_each_rcu(sk2, &ilb->head) { - if (sk2 != sk && - sk2->sk_family == sk->sk_family && - ipv6_only_sock(sk2) == ipv6_only_sock(sk) && - sk2->sk_bound_dev_if == sk->sk_bound_dev_if && - inet_csk(sk2)->icsk_bind_hash == tb && - sk2->sk_reuseport && uid_eq(uid, sock_i_uid(sk2)) && - saddr_same(sk, sk2, false)) - return reuseport_add_sock(sk, sk2); - } - - /* Initial allocation may have already happened via setsockopt */ - if (!rcu_access_pointer(sk->sk_reuseport_cb)) - return reuseport_alloc(sk); - return 0; -} - -int __inet_hash(struct sock *sk, struct sock *osk, - int (*saddr_same)(const struct sock *sk1, - const struct sock *sk2, - bool match_wildcard)) -{ - struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; - struct inet_listen_hashbucket *ilb; - int err = 0; - - if (sk->sk_state != TCP_LISTEN) { - inet_ehash_nolisten(sk, osk); - return 0; - } - WARN_ON(!sk_unhashed(sk)); - ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)]; - - spin_lock(&ilb->lock); - if (sk->sk_reuseport) { - err = inet_reuseport_add_sock(sk, ilb, saddr_same); - if (err) - goto unlock; - } - if (IS_ENABLED(CONFIG_IPV6) && sk->sk_reuseport && - sk->sk_family == AF_INET6) - hlist_add_tail_rcu(&sk->sk_node, &ilb->head); - else - hlist_add_head_rcu(&sk->sk_node, &ilb->head); - sock_set_flag(sk, SOCK_RCU_FREE); - sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); -unlock: - spin_unlock(&ilb->lock); - - return err; -} -EXPORT_SYMBOL(__inet_hash); - -int inet_hash(struct sock *sk) -{ - int err = 0; - - if (sk->sk_state != TCP_CLOSE) { - local_bh_disable(); - err = __inet_hash(sk, NULL, ipv4_rcv_saddr_equal); - local_bh_enable(); - } - - return err; -} -EXPORT_SYMBOL_GPL(inet_hash); - -void inet_unhash(struct sock *sk) -{ - struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; - spinlock_t *lock; - bool listener = false; - int done; - - if (sk_unhashed(sk)) - return; - - if (sk->sk_state == TCP_LISTEN) { - lock = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)].lock; - listener = true; - } else { - lock = inet_ehash_lockp(hashinfo, sk->sk_hash); - } - spin_lock_bh(lock); - if (rcu_access_pointer(sk->sk_reuseport_cb)) - reuseport_detach_sock(sk); - if (listener) - done = __sk_del_node_init(sk); - else - done = __sk_nulls_del_node_init_rcu(sk); - if (done) - sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); - spin_unlock_bh(lock); -} -EXPORT_SYMBOL_GPL(inet_unhash); - -int __inet_hash_connect(struct inet_timewait_death_row *death_row, - struct sock *sk, u32 port_offset, - int (*check_established)(struct inet_timewait_death_row *, - struct sock *, __u16, struct inet_timewait_sock **)) -{ - struct inet_hashinfo *hinfo = death_row->hashinfo; - struct inet_timewait_sock *tw = NULL; - struct inet_bind_hashbucket *head; - int port = inet_sk(sk)->inet_num; - struct net *net = sock_net(sk); - struct inet_bind_bucket *tb; - u32 remaining, offset; - int ret, i, low, high; - static u32 hint; - - if (port) { - head = &hinfo->bhash[inet_bhashfn(net, port, - hinfo->bhash_size)]; - tb = inet_csk(sk)->icsk_bind_hash; - spin_lock_bh(&head->lock); - if (sk_head(&tb->owners) == sk && !sk->sk_bind_node.next) { - inet_ehash_nolisten(sk, NULL); - spin_unlock_bh(&head->lock); - return 0; - } - spin_unlock(&head->lock); - /* No definite answer... Walk to established hash table */ - ret = check_established(death_row, sk, port, NULL); - local_bh_enable(); - return ret; - } - - inet_get_local_port_range(net, &low, &high); - high++; /* [32768, 60999] -> [32768, 61000[ */ - remaining = high - low; - if (likely(remaining > 1)) - remaining &= ~1U; - - offset = (hint + port_offset) % remaining; - /* In first pass we try ports of @low parity. - * inet_csk_get_port() does the opposite choice. - */ - offset &= ~1U; -other_parity_scan: - port = low + offset; - for (i = 0; i < remaining; i += 2, port += 2) { - if (unlikely(port >= high)) - port -= remaining; - if (inet_is_local_reserved_port(net, port)) - continue; - head = &hinfo->bhash[inet_bhashfn(net, port, - hinfo->bhash_size)]; - spin_lock_bh(&head->lock); - - /* Does not bother with rcv_saddr checks, because - * the established check is already unique enough. - */ - inet_bind_bucket_for_each(tb, &head->chain) { - if (net_eq(ib_net(tb), net) && tb->port == port) { - if (tb->fastreuse >= 0 || - tb->fastreuseport >= 0) - goto next_port; - WARN_ON(hlist_empty(&tb->owners)); - if (!check_established(death_row, sk, - port, &tw)) - goto ok; - goto next_port; - } - } - - tb = inet_bind_bucket_create(hinfo->bind_bucket_cachep, - net, head, port); - if (!tb) { - spin_unlock_bh(&head->lock); - return -ENOMEM; - } - tb->fastreuse = -1; - tb->fastreuseport = -1; - goto ok; -next_port: - spin_unlock_bh(&head->lock); - cond_resched(); - } - - offset++; - if ((offset & 1) && remaining > 1) - goto other_parity_scan; - - return -EADDRNOTAVAIL; - -ok: - hint += i + 2; - - /* Head lock still held and bh's disabled */ - inet_bind_hash(sk, tb, port); - if (sk_unhashed(sk)) { - inet_sk(sk)->inet_sport = htons(port); - inet_ehash_nolisten(sk, (struct sock *)tw); - } - if (tw) - inet_twsk_bind_unhash(tw, hinfo); - spin_unlock(&head->lock); - if (tw) - inet_twsk_deschedule_put(tw); - local_bh_enable(); - return 0; -} - -/* - * Bind a port for a connect operation and hash it. - */ -int inet_hash_connect(struct inet_timewait_death_row *death_row, - struct sock *sk) -{ - u32 port_offset = 0; - - if (!inet_sk(sk)->inet_num) - port_offset = inet_sk_port_offset(sk); - return __inet_hash_connect(death_row, sk, port_offset, - __inet_check_established); -} -EXPORT_SYMBOL_GPL(inet_hash_connect); - -void inet_hashinfo_init(struct inet_hashinfo *h) -{ - int i; - - for (i = 0; i < INET_LHTABLE_SIZE; i++) { - spin_lock_init(&h->listening_hash[i].lock); - INIT_HLIST_HEAD(&h->listening_hash[i].head); - } -} -EXPORT_SYMBOL_GPL(inet_hashinfo_init); - -int inet_ehash_locks_alloc(struct inet_hashinfo *hashinfo) -{ - unsigned int locksz = sizeof(spinlock_t); - unsigned int i, nblocks = 1; - - if (locksz != 0) { - /* allocate 2 cache lines or at least one spinlock per cpu */ - nblocks = max(2U * L1_CACHE_BYTES / locksz, 1U); - nblocks = roundup_pow_of_two(nblocks * num_possible_cpus()); - - /* no more locks than number of hash buckets */ - nblocks = min(nblocks, hashinfo->ehash_mask + 1); - - hashinfo->ehash_locks = kmalloc_array(nblocks, locksz, - GFP_KERNEL | __GFP_NOWARN); - if (!hashinfo->ehash_locks) - hashinfo->ehash_locks = vmalloc(nblocks * locksz); - - if (!hashinfo->ehash_locks) - return -ENOMEM; - - for (i = 0; i < nblocks; i++) - spin_lock_init(&hashinfo->ehash_locks[i]); - } - hashinfo->ehash_locks_mask = nblocks - 1; - return 0; -} -EXPORT_SYMBOL_GPL(inet_ehash_locks_alloc); diff --git a/src/linux/net/ipv4/inet_timewait_sock.c b/src/linux/net/ipv4/inet_timewait_sock.c deleted file mode 100644 index ddcd56c..0000000 --- a/src/linux/net/ipv4/inet_timewait_sock.c +++ /dev/null @@ -1,306 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Generic TIME_WAIT sockets functions - * - * From code orinally in TCP - */ - -#include -#include -#include -#include -#include -#include -#include - - -/** - * inet_twsk_bind_unhash - unhash a timewait socket from bind hash - * @tw: timewait socket - * @hashinfo: hashinfo pointer - * - * unhash a timewait socket from bind hash, if hashed. - * bind hash lock must be held by caller. - * Returns 1 if caller should call inet_twsk_put() after lock release. - */ -void inet_twsk_bind_unhash(struct inet_timewait_sock *tw, - struct inet_hashinfo *hashinfo) -{ - struct inet_bind_bucket *tb = tw->tw_tb; - - if (!tb) - return; - - __hlist_del(&tw->tw_bind_node); - tw->tw_tb = NULL; - inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb); - __sock_put((struct sock *)tw); -} - -/* Must be called with locally disabled BHs. */ -static void inet_twsk_kill(struct inet_timewait_sock *tw) -{ - struct inet_hashinfo *hashinfo = tw->tw_dr->hashinfo; - spinlock_t *lock = inet_ehash_lockp(hashinfo, tw->tw_hash); - struct inet_bind_hashbucket *bhead; - - spin_lock(lock); - sk_nulls_del_node_init_rcu((struct sock *)tw); - spin_unlock(lock); - - /* Disassociate with bind bucket. */ - bhead = &hashinfo->bhash[inet_bhashfn(twsk_net(tw), tw->tw_num, - hashinfo->bhash_size)]; - - spin_lock(&bhead->lock); - inet_twsk_bind_unhash(tw, hashinfo); - spin_unlock(&bhead->lock); - - atomic_dec(&tw->tw_dr->tw_count); - inet_twsk_put(tw); -} - -void inet_twsk_free(struct inet_timewait_sock *tw) -{ - struct module *owner = tw->tw_prot->owner; - twsk_destructor((struct sock *)tw); -#ifdef SOCK_REFCNT_DEBUG - pr_debug("%s timewait_sock %p released\n", tw->tw_prot->name, tw); -#endif - kmem_cache_free(tw->tw_prot->twsk_prot->twsk_slab, tw); - module_put(owner); -} - -void inet_twsk_put(struct inet_timewait_sock *tw) -{ - if (atomic_dec_and_test(&tw->tw_refcnt)) - inet_twsk_free(tw); -} -EXPORT_SYMBOL_GPL(inet_twsk_put); - -static void inet_twsk_add_node_rcu(struct inet_timewait_sock *tw, - struct hlist_nulls_head *list) -{ - hlist_nulls_add_head_rcu(&tw->tw_node, list); -} - -static void inet_twsk_add_bind_node(struct inet_timewait_sock *tw, - struct hlist_head *list) -{ - hlist_add_head(&tw->tw_bind_node, list); -} - -/* - * Enter the time wait state. - * Essentially we whip up a timewait bucket, copy the relevant info into it - * from the SK, and mess with hash chains and list linkage. - */ -void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, - struct inet_hashinfo *hashinfo) -{ - const struct inet_sock *inet = inet_sk(sk); - const struct inet_connection_sock *icsk = inet_csk(sk); - struct inet_ehash_bucket *ehead = inet_ehash_bucket(hashinfo, sk->sk_hash); - spinlock_t *lock = inet_ehash_lockp(hashinfo, sk->sk_hash); - struct inet_bind_hashbucket *bhead; - /* Step 1: Put TW into bind hash. Original socket stays there too. - Note, that any socket with inet->num != 0 MUST be bound in - binding cache, even if it is closed. - */ - bhead = &hashinfo->bhash[inet_bhashfn(twsk_net(tw), inet->inet_num, - hashinfo->bhash_size)]; - spin_lock_bh(&bhead->lock); - tw->tw_tb = icsk->icsk_bind_hash; - WARN_ON(!icsk->icsk_bind_hash); - inet_twsk_add_bind_node(tw, &tw->tw_tb->owners); - spin_unlock(&bhead->lock); - - spin_lock(lock); - - /* - * Step 2: Hash TW into tcp ehash chain. - * Notes : - * - tw_refcnt is set to 4 because : - * - We have one reference from bhash chain. - * - We have one reference from ehash chain. - * - We have one reference from timer. - * - One reference for ourself (our caller will release it). - * We can use atomic_set() because prior spin_lock()/spin_unlock() - * committed into memory all tw fields. - */ - atomic_set(&tw->tw_refcnt, 4); - inet_twsk_add_node_rcu(tw, &ehead->chain); - - /* Step 3: Remove SK from hash chain */ - if (__sk_nulls_del_node_init_rcu(sk)) - sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); - - spin_unlock_bh(lock); -} -EXPORT_SYMBOL_GPL(__inet_twsk_hashdance); - -static void tw_timer_handler(unsigned long data) -{ - struct inet_timewait_sock *tw = (struct inet_timewait_sock *)data; - - if (tw->tw_kill) - __NET_INC_STATS(twsk_net(tw), LINUX_MIB_TIMEWAITKILLED); - else - __NET_INC_STATS(twsk_net(tw), LINUX_MIB_TIMEWAITED); - inet_twsk_kill(tw); -} - -struct inet_timewait_sock *inet_twsk_alloc(const struct sock *sk, - struct inet_timewait_death_row *dr, - const int state) -{ - struct inet_timewait_sock *tw; - - if (atomic_read(&dr->tw_count) >= dr->sysctl_max_tw_buckets) - return NULL; - - tw = kmem_cache_alloc(sk->sk_prot_creator->twsk_prot->twsk_slab, - GFP_ATOMIC); - if (tw) { - const struct inet_sock *inet = inet_sk(sk); - - kmemcheck_annotate_bitfield(tw, flags); - - tw->tw_dr = dr; - /* Give us an identity. */ - tw->tw_daddr = inet->inet_daddr; - tw->tw_rcv_saddr = inet->inet_rcv_saddr; - tw->tw_bound_dev_if = sk->sk_bound_dev_if; - tw->tw_tos = inet->tos; - tw->tw_num = inet->inet_num; - tw->tw_state = TCP_TIME_WAIT; - tw->tw_substate = state; - tw->tw_sport = inet->inet_sport; - tw->tw_dport = inet->inet_dport; - tw->tw_family = sk->sk_family; - tw->tw_reuse = sk->sk_reuse; - tw->tw_hash = sk->sk_hash; - tw->tw_ipv6only = 0; - tw->tw_transparent = inet->transparent; - tw->tw_prot = sk->sk_prot_creator; - atomic64_set(&tw->tw_cookie, atomic64_read(&sk->sk_cookie)); - twsk_net_set(tw, sock_net(sk)); - setup_pinned_timer(&tw->tw_timer, tw_timer_handler, - (unsigned long)tw); - /* - * Because we use RCU lookups, we should not set tw_refcnt - * to a non null value before everything is setup for this - * timewait socket. - */ - atomic_set(&tw->tw_refcnt, 0); - - __module_get(tw->tw_prot->owner); - } - - return tw; -} -EXPORT_SYMBOL_GPL(inet_twsk_alloc); - -/* These are always called from BH context. See callers in - * tcp_input.c to verify this. - */ - -/* This is for handling early-kills of TIME_WAIT sockets. - * Warning : consume reference. - * Caller should not access tw anymore. - */ -void inet_twsk_deschedule_put(struct inet_timewait_sock *tw) -{ - if (del_timer_sync(&tw->tw_timer)) - inet_twsk_kill(tw); - inet_twsk_put(tw); -} -EXPORT_SYMBOL(inet_twsk_deschedule_put); - -void __inet_twsk_schedule(struct inet_timewait_sock *tw, int timeo, bool rearm) -{ - /* timeout := RTO * 3.5 - * - * 3.5 = 1+2+0.5 to wait for two retransmits. - * - * RATIONALE: if FIN arrived and we entered TIME-WAIT state, - * our ACK acking that FIN can be lost. If N subsequent retransmitted - * FINs (or previous seqments) are lost (probability of such event - * is p^(N+1), where p is probability to lose single packet and - * time to detect the loss is about RTO*(2^N - 1) with exponential - * backoff). Normal timewait length is calculated so, that we - * waited at least for one retransmitted FIN (maximal RTO is 120sec). - * [ BTW Linux. following BSD, violates this requirement waiting - * only for 60sec, we should wait at least for 240 secs. - * Well, 240 consumes too much of resources 8) - * ] - * This interval is not reduced to catch old duplicate and - * responces to our wandering segments living for two MSLs. - * However, if we use PAWS to detect - * old duplicates, we can reduce the interval to bounds required - * by RTO, rather than MSL. So, if peer understands PAWS, we - * kill tw bucket after 3.5*RTO (it is important that this number - * is greater than TS tick!) and detect old duplicates with help - * of PAWS. - */ - - tw->tw_kill = timeo <= 4*HZ; - if (!rearm) { - BUG_ON(mod_timer(&tw->tw_timer, jiffies + timeo)); - atomic_inc(&tw->tw_dr->tw_count); - } else { - mod_timer_pending(&tw->tw_timer, jiffies + timeo); - } -} -EXPORT_SYMBOL_GPL(__inet_twsk_schedule); - -void inet_twsk_purge(struct inet_hashinfo *hashinfo, - struct inet_timewait_death_row *twdr, int family) -{ - struct inet_timewait_sock *tw; - struct sock *sk; - struct hlist_nulls_node *node; - unsigned int slot; - - for (slot = 0; slot <= hashinfo->ehash_mask; slot++) { - struct inet_ehash_bucket *head = &hashinfo->ehash[slot]; -restart_rcu: - cond_resched(); - rcu_read_lock(); -restart: - sk_nulls_for_each_rcu(sk, node, &head->chain) { - if (sk->sk_state != TCP_TIME_WAIT) - continue; - tw = inet_twsk(sk); - if ((tw->tw_family != family) || - atomic_read(&twsk_net(tw)->count)) - continue; - - if (unlikely(!atomic_inc_not_zero(&tw->tw_refcnt))) - continue; - - if (unlikely((tw->tw_family != family) || - atomic_read(&twsk_net(tw)->count))) { - inet_twsk_put(tw); - goto restart; - } - - rcu_read_unlock(); - local_bh_disable(); - inet_twsk_deschedule_put(tw); - local_bh_enable(); - goto restart_rcu; - } - /* If the nulls value we got at the end of this lookup is - * not the expected one, we must restart lookup. - * We probably met an item that was moved to another chain. - */ - if (get_nulls_value(node) != slot) - goto restart; - rcu_read_unlock(); - } -} -EXPORT_SYMBOL_GPL(inet_twsk_purge); diff --git a/src/linux/net/ipv4/inetpeer.c b/src/linux/net/ipv4/inetpeer.c deleted file mode 100644 index 86fa458..0000000 --- a/src/linux/net/ipv4/inetpeer.c +++ /dev/null @@ -1,542 +0,0 @@ -/* - * INETPEER - A storage for permanent information about peers - * - * This source is covered by the GNU GPL, the same as all kernel sources. - * - * Authors: Andrey V. Savochkin - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Theory of operations. - * We keep one entry for each peer IP address. The nodes contains long-living - * information about the peer which doesn't depend on routes. - * - * Nodes are removed only when reference counter goes to 0. - * When it's happened the node may be removed when a sufficient amount of - * time has been passed since its last use. The less-recently-used entry can - * also be removed if the pool is overloaded i.e. if the total amount of - * entries is greater-or-equal than the threshold. - * - * Node pool is organised as an AVL tree. - * Such an implementation has been chosen not just for fun. It's a way to - * prevent easy and efficient DoS attacks by creating hash collisions. A huge - * amount of long living nodes in a single hash slot would significantly delay - * lookups performed with disabled BHs. - * - * Serialisation issues. - * 1. Nodes may appear in the tree only with the pool lock held. - * 2. Nodes may disappear from the tree only with the pool lock held - * AND reference count being 0. - * 3. Global variable peer_total is modified under the pool lock. - * 4. struct inet_peer fields modification: - * avl_left, avl_right, avl_parent, avl_height: pool lock - * refcnt: atomically against modifications on other CPU; - * usually under some other lock to prevent node disappearing - * daddr: unchangeable - */ - -static struct kmem_cache *peer_cachep __read_mostly; - -static LIST_HEAD(gc_list); -static const int gc_delay = 60 * HZ; -static struct delayed_work gc_work; -static DEFINE_SPINLOCK(gc_lock); - -#define node_height(x) x->avl_height - -#define peer_avl_empty ((struct inet_peer *)&peer_fake_node) -#define peer_avl_empty_rcu ((struct inet_peer __rcu __force *)&peer_fake_node) -static const struct inet_peer peer_fake_node = { - .avl_left = peer_avl_empty_rcu, - .avl_right = peer_avl_empty_rcu, - .avl_height = 0 -}; - -void inet_peer_base_init(struct inet_peer_base *bp) -{ - bp->root = peer_avl_empty_rcu; - seqlock_init(&bp->lock); - bp->total = 0; -} -EXPORT_SYMBOL_GPL(inet_peer_base_init); - -#define PEER_MAXDEPTH 40 /* sufficient for about 2^27 nodes */ - -/* Exported for sysctl_net_ipv4. */ -int inet_peer_threshold __read_mostly = 65536 + 128; /* start to throw entries more - * aggressively at this stage */ -int inet_peer_minttl __read_mostly = 120 * HZ; /* TTL under high load: 120 sec */ -int inet_peer_maxttl __read_mostly = 10 * 60 * HZ; /* usual time to live: 10 min */ - -static void inetpeer_gc_worker(struct work_struct *work) -{ - struct inet_peer *p, *n, *c; - struct list_head list; - - spin_lock_bh(&gc_lock); - list_replace_init(&gc_list, &list); - spin_unlock_bh(&gc_lock); - - if (list_empty(&list)) - return; - - list_for_each_entry_safe(p, n, &list, gc_list) { - - if (need_resched()) - cond_resched(); - - c = rcu_dereference_protected(p->avl_left, 1); - if (c != peer_avl_empty) { - list_add_tail(&c->gc_list, &list); - p->avl_left = peer_avl_empty_rcu; - } - - c = rcu_dereference_protected(p->avl_right, 1); - if (c != peer_avl_empty) { - list_add_tail(&c->gc_list, &list); - p->avl_right = peer_avl_empty_rcu; - } - - n = list_entry(p->gc_list.next, struct inet_peer, gc_list); - - if (!atomic_read(&p->refcnt)) { - list_del(&p->gc_list); - kmem_cache_free(peer_cachep, p); - } - } - - if (list_empty(&list)) - return; - - spin_lock_bh(&gc_lock); - list_splice(&list, &gc_list); - spin_unlock_bh(&gc_lock); - - schedule_delayed_work(&gc_work, gc_delay); -} - -/* Called from ip_output.c:ip_init */ -void __init inet_initpeers(void) -{ - struct sysinfo si; - - /* Use the straight interface to information about memory. */ - si_meminfo(&si); - /* The values below were suggested by Alexey Kuznetsov - * . I don't have any opinion about the values - * myself. --SAW - */ - if (si.totalram <= (32768*1024)/PAGE_SIZE) - inet_peer_threshold >>= 1; /* max pool size about 1MB on IA32 */ - if (si.totalram <= (16384*1024)/PAGE_SIZE) - inet_peer_threshold >>= 1; /* about 512KB */ - if (si.totalram <= (8192*1024)/PAGE_SIZE) - inet_peer_threshold >>= 2; /* about 128KB */ - - peer_cachep = kmem_cache_create("inet_peer_cache", - sizeof(struct inet_peer), - 0, SLAB_HWCACHE_ALIGN | SLAB_PANIC, - NULL); - - INIT_DEFERRABLE_WORK(&gc_work, inetpeer_gc_worker); -} - -#define rcu_deref_locked(X, BASE) \ - rcu_dereference_protected(X, lockdep_is_held(&(BASE)->lock.lock)) - -/* - * Called with local BH disabled and the pool lock held. - */ -#define lookup(_daddr, _stack, _base) \ -({ \ - struct inet_peer *u; \ - struct inet_peer __rcu **v; \ - \ - stackptr = _stack; \ - *stackptr++ = &_base->root; \ - for (u = rcu_deref_locked(_base->root, _base); \ - u != peer_avl_empty;) { \ - int cmp = inetpeer_addr_cmp(_daddr, &u->daddr); \ - if (cmp == 0) \ - break; \ - if (cmp == -1) \ - v = &u->avl_left; \ - else \ - v = &u->avl_right; \ - *stackptr++ = v; \ - u = rcu_deref_locked(*v, _base); \ - } \ - u; \ -}) - -/* - * Called with rcu_read_lock() - * Because we hold no lock against a writer, its quite possible we fall - * in an endless loop. - * But every pointer we follow is guaranteed to be valid thanks to RCU. - * We exit from this function if number of links exceeds PEER_MAXDEPTH - */ -static struct inet_peer *lookup_rcu(const struct inetpeer_addr *daddr, - struct inet_peer_base *base) -{ - struct inet_peer *u = rcu_dereference(base->root); - int count = 0; - - while (u != peer_avl_empty) { - int cmp = inetpeer_addr_cmp(daddr, &u->daddr); - if (cmp == 0) { - /* Before taking a reference, check if this entry was - * deleted (refcnt=-1) - */ - if (!atomic_add_unless(&u->refcnt, 1, -1)) - u = NULL; - return u; - } - if (cmp == -1) - u = rcu_dereference(u->avl_left); - else - u = rcu_dereference(u->avl_right); - if (unlikely(++count == PEER_MAXDEPTH)) - break; - } - return NULL; -} - -/* Called with local BH disabled and the pool lock held. */ -#define lookup_rightempty(start, base) \ -({ \ - struct inet_peer *u; \ - struct inet_peer __rcu **v; \ - *stackptr++ = &start->avl_left; \ - v = &start->avl_left; \ - for (u = rcu_deref_locked(*v, base); \ - u->avl_right != peer_avl_empty_rcu;) { \ - v = &u->avl_right; \ - *stackptr++ = v; \ - u = rcu_deref_locked(*v, base); \ - } \ - u; \ -}) - -/* Called with local BH disabled and the pool lock held. - * Variable names are the proof of operation correctness. - * Look into mm/map_avl.c for more detail description of the ideas. - */ -static void peer_avl_rebalance(struct inet_peer __rcu **stack[], - struct inet_peer __rcu ***stackend, - struct inet_peer_base *base) -{ - struct inet_peer __rcu **nodep; - struct inet_peer *node, *l, *r; - int lh, rh; - - while (stackend > stack) { - nodep = *--stackend; - node = rcu_deref_locked(*nodep, base); - l = rcu_deref_locked(node->avl_left, base); - r = rcu_deref_locked(node->avl_right, base); - lh = node_height(l); - rh = node_height(r); - if (lh > rh + 1) { /* l: RH+2 */ - struct inet_peer *ll, *lr, *lrl, *lrr; - int lrh; - ll = rcu_deref_locked(l->avl_left, base); - lr = rcu_deref_locked(l->avl_right, base); - lrh = node_height(lr); - if (lrh <= node_height(ll)) { /* ll: RH+1 */ - RCU_INIT_POINTER(node->avl_left, lr); /* lr: RH or RH+1 */ - RCU_INIT_POINTER(node->avl_right, r); /* r: RH */ - node->avl_height = lrh + 1; /* RH+1 or RH+2 */ - RCU_INIT_POINTER(l->avl_left, ll); /* ll: RH+1 */ - RCU_INIT_POINTER(l->avl_right, node); /* node: RH+1 or RH+2 */ - l->avl_height = node->avl_height + 1; - RCU_INIT_POINTER(*nodep, l); - } else { /* ll: RH, lr: RH+1 */ - lrl = rcu_deref_locked(lr->avl_left, base);/* lrl: RH or RH-1 */ - lrr = rcu_deref_locked(lr->avl_right, base);/* lrr: RH or RH-1 */ - RCU_INIT_POINTER(node->avl_left, lrr); /* lrr: RH or RH-1 */ - RCU_INIT_POINTER(node->avl_right, r); /* r: RH */ - node->avl_height = rh + 1; /* node: RH+1 */ - RCU_INIT_POINTER(l->avl_left, ll); /* ll: RH */ - RCU_INIT_POINTER(l->avl_right, lrl); /* lrl: RH or RH-1 */ - l->avl_height = rh + 1; /* l: RH+1 */ - RCU_INIT_POINTER(lr->avl_left, l); /* l: RH+1 */ - RCU_INIT_POINTER(lr->avl_right, node); /* node: RH+1 */ - lr->avl_height = rh + 2; - RCU_INIT_POINTER(*nodep, lr); - } - } else if (rh > lh + 1) { /* r: LH+2 */ - struct inet_peer *rr, *rl, *rlr, *rll; - int rlh; - rr = rcu_deref_locked(r->avl_right, base); - rl = rcu_deref_locked(r->avl_left, base); - rlh = node_height(rl); - if (rlh <= node_height(rr)) { /* rr: LH+1 */ - RCU_INIT_POINTER(node->avl_right, rl); /* rl: LH or LH+1 */ - RCU_INIT_POINTER(node->avl_left, l); /* l: LH */ - node->avl_height = rlh + 1; /* LH+1 or LH+2 */ - RCU_INIT_POINTER(r->avl_right, rr); /* rr: LH+1 */ - RCU_INIT_POINTER(r->avl_left, node); /* node: LH+1 or LH+2 */ - r->avl_height = node->avl_height + 1; - RCU_INIT_POINTER(*nodep, r); - } else { /* rr: RH, rl: RH+1 */ - rlr = rcu_deref_locked(rl->avl_right, base);/* rlr: LH or LH-1 */ - rll = rcu_deref_locked(rl->avl_left, base);/* rll: LH or LH-1 */ - RCU_INIT_POINTER(node->avl_right, rll); /* rll: LH or LH-1 */ - RCU_INIT_POINTER(node->avl_left, l); /* l: LH */ - node->avl_height = lh + 1; /* node: LH+1 */ - RCU_INIT_POINTER(r->avl_right, rr); /* rr: LH */ - RCU_INIT_POINTER(r->avl_left, rlr); /* rlr: LH or LH-1 */ - r->avl_height = lh + 1; /* r: LH+1 */ - RCU_INIT_POINTER(rl->avl_right, r); /* r: LH+1 */ - RCU_INIT_POINTER(rl->avl_left, node); /* node: LH+1 */ - rl->avl_height = lh + 2; - RCU_INIT_POINTER(*nodep, rl); - } - } else { - node->avl_height = (lh > rh ? lh : rh) + 1; - } - } -} - -/* Called with local BH disabled and the pool lock held. */ -#define link_to_pool(n, base) \ -do { \ - n->avl_height = 1; \ - n->avl_left = peer_avl_empty_rcu; \ - n->avl_right = peer_avl_empty_rcu; \ - /* lockless readers can catch us now */ \ - rcu_assign_pointer(**--stackptr, n); \ - peer_avl_rebalance(stack, stackptr, base); \ -} while (0) - -static void inetpeer_free_rcu(struct rcu_head *head) -{ - kmem_cache_free(peer_cachep, container_of(head, struct inet_peer, rcu)); -} - -static void unlink_from_pool(struct inet_peer *p, struct inet_peer_base *base, - struct inet_peer __rcu **stack[PEER_MAXDEPTH]) -{ - struct inet_peer __rcu ***stackptr, ***delp; - - if (lookup(&p->daddr, stack, base) != p) - BUG(); - delp = stackptr - 1; /* *delp[0] == p */ - if (p->avl_left == peer_avl_empty_rcu) { - *delp[0] = p->avl_right; - --stackptr; - } else { - /* look for a node to insert instead of p */ - struct inet_peer *t; - t = lookup_rightempty(p, base); - BUG_ON(rcu_deref_locked(*stackptr[-1], base) != t); - **--stackptr = t->avl_left; - /* t is removed, t->daddr > x->daddr for any - * x in p->avl_left subtree. - * Put t in the old place of p. */ - RCU_INIT_POINTER(*delp[0], t); - t->avl_left = p->avl_left; - t->avl_right = p->avl_right; - t->avl_height = p->avl_height; - BUG_ON(delp[1] != &p->avl_left); - delp[1] = &t->avl_left; /* was &p->avl_left */ - } - peer_avl_rebalance(stack, stackptr, base); - base->total--; - call_rcu(&p->rcu, inetpeer_free_rcu); -} - -/* perform garbage collect on all items stacked during a lookup */ -static int inet_peer_gc(struct inet_peer_base *base, - struct inet_peer __rcu **stack[PEER_MAXDEPTH], - struct inet_peer __rcu ***stackptr) -{ - struct inet_peer *p, *gchead = NULL; - __u32 delta, ttl; - int cnt = 0; - - if (base->total >= inet_peer_threshold) - ttl = 0; /* be aggressive */ - else - ttl = inet_peer_maxttl - - (inet_peer_maxttl - inet_peer_minttl) / HZ * - base->total / inet_peer_threshold * HZ; - stackptr--; /* last stack slot is peer_avl_empty */ - while (stackptr > stack) { - stackptr--; - p = rcu_deref_locked(**stackptr, base); - if (atomic_read(&p->refcnt) == 0) { - smp_rmb(); - delta = (__u32)jiffies - p->dtime; - if (delta >= ttl && - atomic_cmpxchg(&p->refcnt, 0, -1) == 0) { - p->gc_next = gchead; - gchead = p; - } - } - } - while ((p = gchead) != NULL) { - gchead = p->gc_next; - cnt++; - unlink_from_pool(p, base, stack); - } - return cnt; -} - -struct inet_peer *inet_getpeer(struct inet_peer_base *base, - const struct inetpeer_addr *daddr, - int create) -{ - struct inet_peer __rcu **stack[PEER_MAXDEPTH], ***stackptr; - struct inet_peer *p; - unsigned int sequence; - int invalidated, gccnt = 0; - - /* Attempt a lockless lookup first. - * Because of a concurrent writer, we might not find an existing entry. - */ - rcu_read_lock(); - sequence = read_seqbegin(&base->lock); - p = lookup_rcu(daddr, base); - invalidated = read_seqretry(&base->lock, sequence); - rcu_read_unlock(); - - if (p) - return p; - - /* If no writer did a change during our lookup, we can return early. */ - if (!create && !invalidated) - return NULL; - - /* retry an exact lookup, taking the lock before. - * At least, nodes should be hot in our cache. - */ - write_seqlock_bh(&base->lock); -relookup: - p = lookup(daddr, stack, base); - if (p != peer_avl_empty) { - atomic_inc(&p->refcnt); - write_sequnlock_bh(&base->lock); - return p; - } - if (!gccnt) { - gccnt = inet_peer_gc(base, stack, stackptr); - if (gccnt && create) - goto relookup; - } - p = create ? kmem_cache_alloc(peer_cachep, GFP_ATOMIC) : NULL; - if (p) { - p->daddr = *daddr; - atomic_set(&p->refcnt, 1); - atomic_set(&p->rid, 0); - p->metrics[RTAX_LOCK-1] = INETPEER_METRICS_NEW; - p->rate_tokens = 0; - /* 60*HZ is arbitrary, but chosen enough high so that the first - * calculation of tokens is at its maximum. - */ - p->rate_last = jiffies - 60*HZ; - INIT_LIST_HEAD(&p->gc_list); - - /* Link the node. */ - link_to_pool(p, base); - base->total++; - } - write_sequnlock_bh(&base->lock); - - return p; -} -EXPORT_SYMBOL_GPL(inet_getpeer); - -void inet_putpeer(struct inet_peer *p) -{ - p->dtime = (__u32)jiffies; - smp_mb__before_atomic(); - atomic_dec(&p->refcnt); -} -EXPORT_SYMBOL_GPL(inet_putpeer); - -/* - * Check transmit rate limitation for given message. - * The rate information is held in the inet_peer entries now. - * This function is generic and could be used for other purposes - * too. It uses a Token bucket filter as suggested by Alexey Kuznetsov. - * - * Note that the same inet_peer fields are modified by functions in - * route.c too, but these work for packet destinations while xrlim_allow - * works for icmp destinations. This means the rate limiting information - * for one "ip object" is shared - and these ICMPs are twice limited: - * by source and by destination. - * - * RFC 1812: 4.3.2.8 SHOULD be able to limit error message rate - * SHOULD allow setting of rate limits - * - * Shared between ICMPv4 and ICMPv6. - */ -#define XRLIM_BURST_FACTOR 6 -bool inet_peer_xrlim_allow(struct inet_peer *peer, int timeout) -{ - unsigned long now, token; - bool rc = false; - - if (!peer) - return true; - - token = peer->rate_tokens; - now = jiffies; - token += now - peer->rate_last; - peer->rate_last = now; - if (token > XRLIM_BURST_FACTOR * timeout) - token = XRLIM_BURST_FACTOR * timeout; - if (token >= timeout) { - token -= timeout; - rc = true; - } - peer->rate_tokens = token; - return rc; -} -EXPORT_SYMBOL(inet_peer_xrlim_allow); - -static void inetpeer_inval_rcu(struct rcu_head *head) -{ - struct inet_peer *p = container_of(head, struct inet_peer, gc_rcu); - - spin_lock_bh(&gc_lock); - list_add_tail(&p->gc_list, &gc_list); - spin_unlock_bh(&gc_lock); - - schedule_delayed_work(&gc_work, gc_delay); -} - -void inetpeer_invalidate_tree(struct inet_peer_base *base) -{ - struct inet_peer *root; - - write_seqlock_bh(&base->lock); - - root = rcu_deref_locked(base->root, base); - if (root != peer_avl_empty) { - base->root = peer_avl_empty_rcu; - base->total = 0; - call_rcu(&root->gc_rcu, inetpeer_inval_rcu); - } - - write_sequnlock_bh(&base->lock); -} -EXPORT_SYMBOL(inetpeer_invalidate_tree); diff --git a/src/linux/net/ipv4/ip_forward.c b/src/linux/net/ipv4/ip_forward.c deleted file mode 100644 index 9f0a7b9..0000000 --- a/src/linux/net/ipv4/ip_forward.c +++ /dev/null @@ -1,165 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * The IP forwarding functionality. - * - * Authors: see ip.c - * - * Fixes: - * Many : Split from ip.c , see ip_input.c for - * history. - * Dave Gregorich : NULL ip_rt_put fix for multicast - * routing. - * Jos Vos : Add call_out_firewall before sending, - * use output device for accounting. - * Jos Vos : Call forward firewall after routing - * (always use output device). - * Mike McLagan : Routing by source - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static bool ip_exceeds_mtu(const struct sk_buff *skb, unsigned int mtu) -{ - if (skb->len <= mtu) - return false; - - if (unlikely((ip_hdr(skb)->frag_off & htons(IP_DF)) == 0)) - return false; - - /* original fragment exceeds mtu and DF is set */ - if (unlikely(IPCB(skb)->frag_max_size > mtu)) - return true; - - if (skb->ignore_df) - return false; - - if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) - return false; - - return true; -} - - -static int ip_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - struct ip_options *opt = &(IPCB(skb)->opt); - - __IP_INC_STATS(net, IPSTATS_MIB_OUTFORWDATAGRAMS); - __IP_ADD_STATS(net, IPSTATS_MIB_OUTOCTETS, skb->len); - - if (unlikely(opt->optlen)) - ip_forward_options(skb); - - return dst_output(net, sk, skb); -} - -int ip_forward(struct sk_buff *skb) -{ - u32 mtu; - struct iphdr *iph; /* Our header */ - struct rtable *rt; /* Route we use */ - struct ip_options *opt = &(IPCB(skb)->opt); - struct net *net; - - /* that should never happen */ - if (skb->pkt_type != PACKET_HOST) - goto drop; - - if (unlikely(skb->sk)) - goto drop; - - if (skb_warn_if_lro(skb)) - goto drop; - - if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb)) - goto drop; - - if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb)) - return NET_RX_SUCCESS; - - skb_forward_csum(skb); - net = dev_net(skb->dev); - - /* - * According to the RFC, we must first decrease the TTL field. If - * that reaches zero, we must reply an ICMP control message telling - * that the packet's lifetime expired. - */ - if (ip_hdr(skb)->ttl <= 1) - goto too_many_hops; - - if (!xfrm4_route_forward(skb)) - goto drop; - - rt = skb_rtable(skb); - - if (opt->is_strictroute && rt->rt_uses_gateway) - goto sr_failed; - - IPCB(skb)->flags |= IPSKB_FORWARDED; - mtu = ip_dst_mtu_maybe_forward(&rt->dst, true); - if (ip_exceeds_mtu(skb, mtu)) { - IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS); - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, - htonl(mtu)); - goto drop; - } - - /* We are about to mangle packet. Copy it! */ - if (skb_cow(skb, LL_RESERVED_SPACE(rt->dst.dev)+rt->dst.header_len)) - goto drop; - iph = ip_hdr(skb); - - /* Decrease ttl after skb cow done */ - ip_decrease_ttl(iph); - - /* - * We now generate an ICMP HOST REDIRECT giving the route - * we calculated. - */ - if (IPCB(skb)->flags & IPSKB_DOREDIRECT && !opt->srr && - !skb_sec_path(skb)) - ip_rt_send_redirect(skb); - - skb->priority = rt_tos2priority(iph->tos); - - return NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, - net, NULL, skb, skb->dev, rt->dst.dev, - ip_forward_finish); - -sr_failed: - /* - * Strict routing permits no gatewaying - */ - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_SR_FAILED, 0); - goto drop; - -too_many_hops: - /* Tell the sender its packet died... */ - __IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS); - icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0); -drop: - kfree_skb(skb); - return NET_RX_DROP; -} diff --git a/src/linux/net/ipv4/ip_fragment.c b/src/linux/net/ipv4/ip_fragment.c deleted file mode 100644 index bbe7f72..0000000 --- a/src/linux/net/ipv4/ip_fragment.c +++ /dev/null @@ -1,898 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * The IP fragmentation functionality. - * - * Authors: Fred N. van Kempen - * Alan Cox - * - * Fixes: - * Alan Cox : Split from ip.c , see ip_input.c for history. - * David S. Miller : Begin massive cleanup... - * Andi Kleen : Add sysctls. - * xxxx : Overlapfrag bug. - * Ultima : ip_expire() kernel panic. - * Bill Hawes : Frag accounting and evictor fixes. - * John McDonald : 0 length frag bug. - * Alexey Kuznetsov: SMP races, threading, cleanup. - * Patrick McHardy : LRU queue of frag heads for evictor. - */ - -#define pr_fmt(fmt) "IPv4: " fmt - -#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 - -/* NOTE. Logic of IP defragmentation is parallel to corresponding IPv6 - * code now. If you change something here, _PLEASE_ update ipv6/reassembly.c - * as well. Or notify me, at least. --ANK - */ -static const char ip_frag_cache_name[] = "ip4-frags"; - -struct ipfrag_skb_cb -{ - struct inet_skb_parm h; - int offset; -}; - -#define FRAG_CB(skb) ((struct ipfrag_skb_cb *)((skb)->cb)) - -/* Describe an entry in the "incomplete datagrams" queue. */ -struct ipq { - struct inet_frag_queue q; - - u32 user; - __be32 saddr; - __be32 daddr; - __be16 id; - u8 protocol; - u8 ecn; /* RFC3168 support */ - u16 max_df_size; /* largest frag with DF set seen */ - int iif; - int vif; /* L3 master device index */ - unsigned int rid; - struct inet_peer *peer; -}; - -static u8 ip4_frag_ecn(u8 tos) -{ - return 1 << (tos & INET_ECN_MASK); -} - -static struct inet_frags ip4_frags; - -int ip_frag_mem(struct net *net) -{ - return sum_frag_mem_limit(&net->ipv4.frags); -} - -static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, - struct net_device *dev); - -struct ip4_create_arg { - struct iphdr *iph; - u32 user; - int vif; -}; - -static unsigned int ipqhashfn(__be16 id, __be32 saddr, __be32 daddr, u8 prot) -{ - net_get_random_once(&ip4_frags.rnd, sizeof(ip4_frags.rnd)); - return jhash_3words((__force u32)id << 16 | prot, - (__force u32)saddr, (__force u32)daddr, - ip4_frags.rnd); -} - -static unsigned int ip4_hashfn(const struct inet_frag_queue *q) -{ - const struct ipq *ipq; - - ipq = container_of(q, struct ipq, q); - return ipqhashfn(ipq->id, ipq->saddr, ipq->daddr, ipq->protocol); -} - -static bool ip4_frag_match(const struct inet_frag_queue *q, const void *a) -{ - const struct ipq *qp; - const struct ip4_create_arg *arg = a; - - qp = container_of(q, struct ipq, q); - return qp->id == arg->iph->id && - qp->saddr == arg->iph->saddr && - qp->daddr == arg->iph->daddr && - qp->protocol == arg->iph->protocol && - qp->user == arg->user && - qp->vif == arg->vif; -} - -static void ip4_frag_init(struct inet_frag_queue *q, const void *a) -{ - struct ipq *qp = container_of(q, struct ipq, q); - struct netns_ipv4 *ipv4 = container_of(q->net, struct netns_ipv4, - frags); - struct net *net = container_of(ipv4, struct net, ipv4); - - const struct ip4_create_arg *arg = a; - - qp->protocol = arg->iph->protocol; - qp->id = arg->iph->id; - qp->ecn = ip4_frag_ecn(arg->iph->tos); - qp->saddr = arg->iph->saddr; - qp->daddr = arg->iph->daddr; - qp->vif = arg->vif; - qp->user = arg->user; - qp->peer = q->net->max_dist ? - inet_getpeer_v4(net->ipv4.peers, arg->iph->saddr, arg->vif, 1) : - NULL; -} - -static void ip4_frag_free(struct inet_frag_queue *q) -{ - struct ipq *qp; - - qp = container_of(q, struct ipq, q); - if (qp->peer) - inet_putpeer(qp->peer); -} - - -/* Destruction primitives. */ - -static void ipq_put(struct ipq *ipq) -{ - inet_frag_put(&ipq->q, &ip4_frags); -} - -/* Kill ipq entry. It is not destroyed immediately, - * because caller (and someone more) holds reference count. - */ -static void ipq_kill(struct ipq *ipq) -{ - inet_frag_kill(&ipq->q, &ip4_frags); -} - -static bool frag_expire_skip_icmp(u32 user) -{ - return user == IP_DEFRAG_AF_PACKET || - ip_defrag_user_in_between(user, IP_DEFRAG_CONNTRACK_IN, - __IP_DEFRAG_CONNTRACK_IN_END) || - ip_defrag_user_in_between(user, IP_DEFRAG_CONNTRACK_BRIDGE_IN, - __IP_DEFRAG_CONNTRACK_BRIDGE_IN); -} - -/* - * Oops, a fragment queue timed out. Kill it and send an ICMP reply. - */ -static void ip_expire(unsigned long arg) -{ - struct ipq *qp; - struct net *net; - - qp = container_of((struct inet_frag_queue *) arg, struct ipq, q); - net = container_of(qp->q.net, struct net, ipv4.frags); - - spin_lock(&qp->q.lock); - - if (qp->q.flags & INET_FRAG_COMPLETE) - goto out; - - ipq_kill(qp); - __IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS); - - if (!inet_frag_evicting(&qp->q)) { - struct sk_buff *head = qp->q.fragments; - const struct iphdr *iph; - int err; - - __IP_INC_STATS(net, IPSTATS_MIB_REASMTIMEOUT); - - if (!(qp->q.flags & INET_FRAG_FIRST_IN) || !qp->q.fragments) - goto out; - - rcu_read_lock(); - head->dev = dev_get_by_index_rcu(net, qp->iif); - if (!head->dev) - goto out_rcu_unlock; - - /* skb has no dst, perform route lookup again */ - iph = ip_hdr(head); - err = ip_route_input_noref(head, iph->daddr, iph->saddr, - iph->tos, head->dev); - if (err) - goto out_rcu_unlock; - - /* Only an end host needs to send an ICMP - * "Fragment Reassembly Timeout" message, per RFC792. - */ - if (frag_expire_skip_icmp(qp->user) && - (skb_rtable(head)->rt_type != RTN_LOCAL)) - goto out_rcu_unlock; - - /* Send an ICMP "Fragment Reassembly Timeout" message. */ - icmp_send(head, ICMP_TIME_EXCEEDED, ICMP_EXC_FRAGTIME, 0); -out_rcu_unlock: - rcu_read_unlock(); - } -out: - spin_unlock(&qp->q.lock); - ipq_put(qp); -} - -/* Find the correct entry in the "incomplete datagrams" queue for - * this IP datagram, and create new one, if nothing is found. - */ -static struct ipq *ip_find(struct net *net, struct iphdr *iph, - u32 user, int vif) -{ - struct inet_frag_queue *q; - struct ip4_create_arg arg; - unsigned int hash; - - arg.iph = iph; - arg.user = user; - arg.vif = vif; - - hash = ipqhashfn(iph->id, iph->saddr, iph->daddr, iph->protocol); - - q = inet_frag_find(&net->ipv4.frags, &ip4_frags, &arg, hash); - if (IS_ERR_OR_NULL(q)) { - inet_frag_maybe_warn_overflow(q, pr_fmt()); - return NULL; - } - return container_of(q, struct ipq, q); -} - -/* Is the fragment too far ahead to be part of ipq? */ -static int ip_frag_too_far(struct ipq *qp) -{ - struct inet_peer *peer = qp->peer; - unsigned int max = qp->q.net->max_dist; - unsigned int start, end; - - int rc; - - if (!peer || !max) - return 0; - - start = qp->rid; - end = atomic_inc_return(&peer->rid); - qp->rid = end; - - rc = qp->q.fragments && (end - start) > max; - - if (rc) { - struct net *net; - - net = container_of(qp->q.net, struct net, ipv4.frags); - __IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS); - } - - return rc; -} - -static int ip_frag_reinit(struct ipq *qp) -{ - struct sk_buff *fp; - unsigned int sum_truesize = 0; - - if (!mod_timer(&qp->q.timer, jiffies + qp->q.net->timeout)) { - atomic_inc(&qp->q.refcnt); - return -ETIMEDOUT; - } - - fp = qp->q.fragments; - do { - struct sk_buff *xp = fp->next; - - sum_truesize += fp->truesize; - kfree_skb(fp); - fp = xp; - } while (fp); - sub_frag_mem_limit(qp->q.net, sum_truesize); - - qp->q.flags = 0; - qp->q.len = 0; - qp->q.meat = 0; - qp->q.fragments = NULL; - qp->q.fragments_tail = NULL; - qp->iif = 0; - qp->ecn = 0; - - return 0; -} - -/* Add new segment to existing queue. */ -static int ip_frag_queue(struct ipq *qp, struct sk_buff *skb) -{ - struct sk_buff *prev, *next; - struct net_device *dev; - unsigned int fragsize; - int flags, offset; - int ihl, end; - int err = -ENOENT; - u8 ecn; - - if (qp->q.flags & INET_FRAG_COMPLETE) - goto err; - - if (!(IPCB(skb)->flags & IPSKB_FRAG_COMPLETE) && - unlikely(ip_frag_too_far(qp)) && - unlikely(err = ip_frag_reinit(qp))) { - ipq_kill(qp); - goto err; - } - - ecn = ip4_frag_ecn(ip_hdr(skb)->tos); - offset = ntohs(ip_hdr(skb)->frag_off); - flags = offset & ~IP_OFFSET; - offset &= IP_OFFSET; - offset <<= 3; /* offset is in 8-byte chunks */ - ihl = ip_hdrlen(skb); - - /* Determine the position of this fragment. */ - end = offset + skb->len - skb_network_offset(skb) - ihl; - err = -EINVAL; - - /* Is this the final fragment? */ - if ((flags & IP_MF) == 0) { - /* If we already have some bits beyond end - * or have different end, the segment is corrupted. - */ - if (end < qp->q.len || - ((qp->q.flags & INET_FRAG_LAST_IN) && end != qp->q.len)) - goto err; - qp->q.flags |= INET_FRAG_LAST_IN; - qp->q.len = end; - } else { - if (end&7) { - end &= ~7; - if (skb->ip_summed != CHECKSUM_UNNECESSARY) - skb->ip_summed = CHECKSUM_NONE; - } - if (end > qp->q.len) { - /* Some bits beyond end -> corruption. */ - if (qp->q.flags & INET_FRAG_LAST_IN) - goto err; - qp->q.len = end; - } - } - if (end == offset) - goto err; - - err = -ENOMEM; - if (!pskb_pull(skb, skb_network_offset(skb) + ihl)) - goto err; - - err = pskb_trim_rcsum(skb, end - offset); - if (err) - goto err; - - /* Find out which fragments are in front and at the back of us - * in the chain of fragments so far. We must know where to put - * this fragment, right? - */ - prev = qp->q.fragments_tail; - if (!prev || FRAG_CB(prev)->offset < offset) { - next = NULL; - goto found; - } - prev = NULL; - for (next = qp->q.fragments; next != NULL; next = next->next) { - if (FRAG_CB(next)->offset >= offset) - break; /* bingo! */ - prev = next; - } - -found: - /* We found where to put this one. Check for overlap with - * preceding fragment, and, if needed, align things so that - * any overlaps are eliminated. - */ - if (prev) { - int i = (FRAG_CB(prev)->offset + prev->len) - offset; - - if (i > 0) { - offset += i; - err = -EINVAL; - if (end <= offset) - goto err; - err = -ENOMEM; - if (!pskb_pull(skb, i)) - goto err; - if (skb->ip_summed != CHECKSUM_UNNECESSARY) - skb->ip_summed = CHECKSUM_NONE; - } - } - - err = -ENOMEM; - - while (next && FRAG_CB(next)->offset < end) { - int i = end - FRAG_CB(next)->offset; /* overlap is 'i' bytes */ - - if (i < next->len) { - /* Eat head of the next overlapped fragment - * and leave the loop. The next ones cannot overlap. - */ - if (!pskb_pull(next, i)) - goto err; - FRAG_CB(next)->offset += i; - qp->q.meat -= i; - if (next->ip_summed != CHECKSUM_UNNECESSARY) - next->ip_summed = CHECKSUM_NONE; - break; - } else { - struct sk_buff *free_it = next; - - /* Old fragment is completely overridden with - * new one drop it. - */ - next = next->next; - - if (prev) - prev->next = next; - else - qp->q.fragments = next; - - qp->q.meat -= free_it->len; - sub_frag_mem_limit(qp->q.net, free_it->truesize); - kfree_skb(free_it); - } - } - - FRAG_CB(skb)->offset = offset; - - /* Insert this fragment in the chain of fragments. */ - skb->next = next; - if (!next) - qp->q.fragments_tail = skb; - if (prev) - prev->next = skb; - else - qp->q.fragments = skb; - - dev = skb->dev; - if (dev) { - qp->iif = dev->ifindex; - skb->dev = NULL; - } - qp->q.stamp = skb->tstamp; - qp->q.meat += skb->len; - qp->ecn |= ecn; - add_frag_mem_limit(qp->q.net, skb->truesize); - if (offset == 0) - qp->q.flags |= INET_FRAG_FIRST_IN; - - fragsize = skb->len + ihl; - - if (fragsize > qp->q.max_size) - qp->q.max_size = fragsize; - - if (ip_hdr(skb)->frag_off & htons(IP_DF) && - fragsize > qp->max_df_size) - qp->max_df_size = fragsize; - - if (qp->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && - qp->q.meat == qp->q.len) { - unsigned long orefdst = skb->_skb_refdst; - - skb->_skb_refdst = 0UL; - err = ip_frag_reasm(qp, prev, dev); - skb->_skb_refdst = orefdst; - return err; - } - - skb_dst_drop(skb); - return -EINPROGRESS; - -err: - kfree_skb(skb); - return err; -} - - -/* Build a new IP datagram from all its fragments. */ - -static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev, - struct net_device *dev) -{ - struct net *net = container_of(qp->q.net, struct net, ipv4.frags); - struct iphdr *iph; - struct sk_buff *fp, *head = qp->q.fragments; - int len; - int ihlen; - int err; - u8 ecn; - - ipq_kill(qp); - - ecn = ip_frag_ecn_table[qp->ecn]; - if (unlikely(ecn == 0xff)) { - err = -EINVAL; - goto out_fail; - } - /* Make the one we just received the head. */ - if (prev) { - head = prev->next; - fp = skb_clone(head, GFP_ATOMIC); - if (!fp) - goto out_nomem; - - fp->next = head->next; - if (!fp->next) - qp->q.fragments_tail = fp; - prev->next = fp; - - skb_morph(head, qp->q.fragments); - head->next = qp->q.fragments->next; - - consume_skb(qp->q.fragments); - qp->q.fragments = head; - } - - WARN_ON(!head); - WARN_ON(FRAG_CB(head)->offset != 0); - - /* Allocate a new buffer for the datagram. */ - ihlen = ip_hdrlen(head); - len = ihlen + qp->q.len; - - err = -E2BIG; - if (len > 65535) - goto out_oversize; - - /* Head of list must not be cloned. */ - if (skb_unclone(head, GFP_ATOMIC)) - goto out_nomem; - - /* If the first fragment is fragmented itself, we split - * it to two chunks: the first with data and paged part - * and the second, holding only fragments. */ - if (skb_has_frag_list(head)) { - struct sk_buff *clone; - int i, plen = 0; - - clone = alloc_skb(0, GFP_ATOMIC); - if (!clone) - goto out_nomem; - clone->next = head->next; - head->next = clone; - skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; - skb_frag_list_init(head); - for (i = 0; i < skb_shinfo(head)->nr_frags; i++) - plen += skb_frag_size(&skb_shinfo(head)->frags[i]); - clone->len = clone->data_len = head->data_len - plen; - head->data_len -= clone->len; - head->len -= clone->len; - clone->csum = 0; - clone->ip_summed = head->ip_summed; - add_frag_mem_limit(qp->q.net, clone->truesize); - } - - skb_shinfo(head)->frag_list = head->next; - skb_push(head, head->data - skb_network_header(head)); - - for (fp=head->next; fp; fp = fp->next) { - head->data_len += fp->len; - head->len += fp->len; - if (head->ip_summed != fp->ip_summed) - head->ip_summed = CHECKSUM_NONE; - else if (head->ip_summed == CHECKSUM_COMPLETE) - head->csum = csum_add(head->csum, fp->csum); - head->truesize += fp->truesize; - } - sub_frag_mem_limit(qp->q.net, head->truesize); - - head->next = NULL; - head->dev = dev; - head->tstamp = qp->q.stamp; - IPCB(head)->frag_max_size = max(qp->max_df_size, qp->q.max_size); - - iph = ip_hdr(head); - iph->tot_len = htons(len); - iph->tos |= ecn; - - /* When we set IP_DF on a refragmented skb we must also force a - * call to ip_fragment to avoid forwarding a DF-skb of size s while - * original sender only sent fragments of size f (where f < s). - * - * We only set DF/IPSKB_FRAG_PMTU if such DF fragment was the largest - * frag seen to avoid sending tiny DF-fragments in case skb was built - * from one very small df-fragment and one large non-df frag. - */ - if (qp->max_df_size == qp->q.max_size) { - IPCB(head)->flags |= IPSKB_FRAG_PMTU; - iph->frag_off = htons(IP_DF); - } else { - iph->frag_off = 0; - } - - ip_send_check(iph); - - __IP_INC_STATS(net, IPSTATS_MIB_REASMOKS); - qp->q.fragments = NULL; - qp->q.fragments_tail = NULL; - return 0; - -out_nomem: - net_dbg_ratelimited("queue_glue: no memory for gluing queue %p\n", qp); - err = -ENOMEM; - goto out_fail; -out_oversize: - net_info_ratelimited("Oversized IP packet from %pI4\n", &qp->saddr); -out_fail: - __IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS); - return err; -} - -/* Process an incoming IP datagram fragment. */ -int ip_defrag(struct net *net, struct sk_buff *skb, u32 user) -{ - struct net_device *dev = skb->dev ? : skb_dst(skb)->dev; - int vif = l3mdev_master_ifindex_rcu(dev); - struct ipq *qp; - - __IP_INC_STATS(net, IPSTATS_MIB_REASMREQDS); - skb_orphan(skb); - - /* Lookup (or create) queue header */ - qp = ip_find(net, ip_hdr(skb), user, vif); - if (qp) { - int ret; - - spin_lock(&qp->q.lock); - - ret = ip_frag_queue(qp, skb); - - spin_unlock(&qp->q.lock); - ipq_put(qp); - return ret; - } - - __IP_INC_STATS(net, IPSTATS_MIB_REASMFAILS); - kfree_skb(skb); - return -ENOMEM; -} -EXPORT_SYMBOL(ip_defrag); - -struct sk_buff *ip_check_defrag(struct net *net, struct sk_buff *skb, u32 user) -{ - struct iphdr iph; - int netoff; - u32 len; - - if (skb->protocol != htons(ETH_P_IP)) - return skb; - - netoff = skb_network_offset(skb); - - if (skb_copy_bits(skb, netoff, &iph, sizeof(iph)) < 0) - return skb; - - if (iph.ihl < 5 || iph.version != 4) - return skb; - - len = ntohs(iph.tot_len); - if (skb->len < netoff + len || len < (iph.ihl * 4)) - return skb; - - if (ip_is_fragment(&iph)) { - skb = skb_share_check(skb, GFP_ATOMIC); - if (skb) { - if (!pskb_may_pull(skb, netoff + iph.ihl * 4)) - return skb; - if (pskb_trim_rcsum(skb, netoff + len)) - return skb; - memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); - if (ip_defrag(net, skb, user)) - return NULL; - skb_clear_hash(skb); - } - } - return skb; -} -EXPORT_SYMBOL(ip_check_defrag); - -#ifdef CONFIG_SYSCTL -static int zero; - -static struct ctl_table ip4_frags_ns_ctl_table[] = { - { - .procname = "ipfrag_high_thresh", - .data = &init_net.ipv4.frags.high_thresh, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &init_net.ipv4.frags.low_thresh - }, - { - .procname = "ipfrag_low_thresh", - .data = &init_net.ipv4.frags.low_thresh, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &init_net.ipv4.frags.high_thresh - }, - { - .procname = "ipfrag_time", - .data = &init_net.ipv4.frags.timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "ipfrag_max_dist", - .data = &init_net.ipv4.frags.max_dist, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero - }, - { } -}; - -/* secret interval has been deprecated */ -static int ip4_frags_secret_interval_unused; -static struct ctl_table ip4_frags_ctl_table[] = { - { - .procname = "ipfrag_secret_interval", - .data = &ip4_frags_secret_interval_unused, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { } -}; - -static int __net_init ip4_frags_ns_ctl_register(struct net *net) -{ - struct ctl_table *table; - struct ctl_table_header *hdr; - - table = ip4_frags_ns_ctl_table; - if (!net_eq(net, &init_net)) { - table = kmemdup(table, sizeof(ip4_frags_ns_ctl_table), GFP_KERNEL); - if (!table) - goto err_alloc; - - table[0].data = &net->ipv4.frags.high_thresh; - table[0].extra1 = &net->ipv4.frags.low_thresh; - table[0].extra2 = &init_net.ipv4.frags.high_thresh; - table[1].data = &net->ipv4.frags.low_thresh; - table[1].extra2 = &net->ipv4.frags.high_thresh; - table[2].data = &net->ipv4.frags.timeout; - table[3].data = &net->ipv4.frags.max_dist; - } - - hdr = register_net_sysctl(net, "net/ipv4", table); - if (!hdr) - goto err_reg; - - net->ipv4.frags_hdr = hdr; - return 0; - -err_reg: - if (!net_eq(net, &init_net)) - kfree(table); -err_alloc: - return -ENOMEM; -} - -static void __net_exit ip4_frags_ns_ctl_unregister(struct net *net) -{ - struct ctl_table *table; - - table = net->ipv4.frags_hdr->ctl_table_arg; - unregister_net_sysctl_table(net->ipv4.frags_hdr); - kfree(table); -} - -static void __init ip4_frags_ctl_register(void) -{ - register_net_sysctl(&init_net, "net/ipv4", ip4_frags_ctl_table); -} -#else -static int ip4_frags_ns_ctl_register(struct net *net) -{ - return 0; -} - -static void ip4_frags_ns_ctl_unregister(struct net *net) -{ -} - -static void __init ip4_frags_ctl_register(void) -{ -} -#endif - -static int __net_init ipv4_frags_init_net(struct net *net) -{ - int res; - - /* Fragment cache limits. - * - * The fragment memory accounting code, (tries to) account for - * the real memory usage, by measuring both the size of frag - * queue struct (inet_frag_queue (ipv4:ipq/ipv6:frag_queue)) - * and the SKB's truesize. - * - * A 64K fragment consumes 129736 bytes (44*2944)+200 - * (1500 truesize == 2944, sizeof(struct ipq) == 200) - * - * We will commit 4MB at one time. Should we cross that limit - * we will prune down to 3MB, making room for approx 8 big 64K - * fragments 8x128k. - */ - net->ipv4.frags.high_thresh = 4 * 1024 * 1024; - net->ipv4.frags.low_thresh = 3 * 1024 * 1024; - /* - * Important NOTE! Fragment queue must be destroyed before MSL expires. - * RFC791 is wrong proposing to prolongate timer each fragment arrival - * by TTL. - */ - net->ipv4.frags.timeout = IP_FRAG_TIME; - - net->ipv4.frags.max_dist = 64; - - res = inet_frags_init_net(&net->ipv4.frags); - if (res) - return res; - res = ip4_frags_ns_ctl_register(net); - if (res) - inet_frags_uninit_net(&net->ipv4.frags); - return res; -} - -static void __net_exit ipv4_frags_exit_net(struct net *net) -{ - ip4_frags_ns_ctl_unregister(net); - inet_frags_exit_net(&net->ipv4.frags, &ip4_frags); -} - -static struct pernet_operations ip4_frags_ops = { - .init = ipv4_frags_init_net, - .exit = ipv4_frags_exit_net, -}; - -void __init ipfrag_init(void) -{ - ip4_frags_ctl_register(); - register_pernet_subsys(&ip4_frags_ops); - ip4_frags.hashfn = ip4_hashfn; - ip4_frags.constructor = ip4_frag_init; - ip4_frags.destructor = ip4_frag_free; - ip4_frags.qsize = sizeof(struct ipq); - ip4_frags.match = ip4_frag_match; - ip4_frags.frag_expire = ip_expire; - ip4_frags.frags_cache_name = ip_frag_cache_name; - if (inet_frags_init(&ip4_frags)) - panic("IP: failed to allocate ip4_frags cache\n"); -} diff --git a/src/linux/net/ipv4/ip_input.c b/src/linux/net/ipv4/ip_input.c deleted file mode 100644 index d6feabb..0000000 --- a/src/linux/net/ipv4/ip_input.c +++ /dev/null @@ -1,499 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * The Internet Protocol (IP) module. - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Donald Becker, - * Alan Cox, - * Richard Underwood - * Stefan Becker, - * Jorge Cwik, - * Arnt Gulbrandsen, - * - * - * Fixes: - * Alan Cox : Commented a couple of minor bits of surplus code - * Alan Cox : Undefining IP_FORWARD doesn't include the code - * (just stops a compiler warning). - * Alan Cox : Frames with >=MAX_ROUTE record routes, strict routes or loose routes - * are junked rather than corrupting things. - * Alan Cox : Frames to bad broadcast subnets are dumped - * We used to process them non broadcast and - * boy could that cause havoc. - * Alan Cox : ip_forward sets the free flag on the - * new frame it queues. Still crap because - * it copies the frame but at least it - * doesn't eat memory too. - * Alan Cox : Generic queue code and memory fixes. - * Fred Van Kempen : IP fragment support (borrowed from NET2E) - * Gerhard Koerting: Forward fragmented frames correctly. - * Gerhard Koerting: Fixes to my fix of the above 8-). - * Gerhard Koerting: IP interface addressing fix. - * Linus Torvalds : More robustness checks - * Alan Cox : Even more checks: Still not as robust as it ought to be - * Alan Cox : Save IP header pointer for later - * Alan Cox : ip option setting - * Alan Cox : Use ip_tos/ip_ttl settings - * Alan Cox : Fragmentation bogosity removed - * (Thanks to Mark.Bush@prg.ox.ac.uk) - * Dmitry Gorodchanin : Send of a raw packet crash fix. - * Alan Cox : Silly ip bug when an overlength - * fragment turns up. Now frees the - * queue. - * Linus Torvalds/ : Memory leakage on fragmentation - * Alan Cox : handling. - * Gerhard Koerting: Forwarding uses IP priority hints - * Teemu Rantanen : Fragment problems. - * Alan Cox : General cleanup, comments and reformat - * Alan Cox : SNMP statistics - * Alan Cox : BSD address rule semantics. Also see - * UDP as there is a nasty checksum issue - * if you do things the wrong way. - * Alan Cox : Always defrag, moved IP_FORWARD to the config.in file - * Alan Cox : IP options adjust sk->priority. - * Pedro Roque : Fix mtu/length error in ip_forward. - * Alan Cox : Avoid ip_chk_addr when possible. - * Richard Underwood : IP multicasting. - * Alan Cox : Cleaned up multicast handlers. - * Alan Cox : RAW sockets demultiplex in the BSD style. - * Gunther Mayer : Fix the SNMP reporting typo - * Alan Cox : Always in group 224.0.0.1 - * Pauline Middelink : Fast ip_checksum update when forwarding - * Masquerading support. - * Alan Cox : Multicast loopback error for 224.0.0.1 - * Alan Cox : IP_MULTICAST_LOOP option. - * Alan Cox : Use notifiers. - * Bjorn Ekwall : Removed ip_csum (from slhc.c too) - * Bjorn Ekwall : Moved ip_fast_csum to ip.h (inline!) - * Stefan Becker : Send out ICMP HOST REDIRECT - * Arnt Gulbrandsen : ip_build_xmit - * Alan Cox : Per socket routing cache - * Alan Cox : Fixed routing cache, added header cache. - * Alan Cox : Loopback didn't work right in original ip_build_xmit - fixed it. - * Alan Cox : Only send ICMP_REDIRECT if src/dest are the same net. - * Alan Cox : Incoming IP option handling. - * Alan Cox : Set saddr on raw output frames as per BSD. - * Alan Cox : Stopped broadcast source route explosions. - * Alan Cox : Can disable source routing - * Takeshi Sone : Masquerading didn't work. - * Dave Bonn,Alan Cox : Faster IP forwarding whenever possible. - * Alan Cox : Memory leaks, tramples, misc debugging. - * Alan Cox : Fixed multicast (by popular demand 8)) - * Alan Cox : Fixed forwarding (by even more popular demand 8)) - * Alan Cox : Fixed SNMP statistics [I think] - * Gerhard Koerting : IP fragmentation forwarding fix - * Alan Cox : Device lock against page fault. - * Alan Cox : IP_HDRINCL facility. - * Werner Almesberger : Zero fragment bug - * Alan Cox : RAW IP frame length bug - * Alan Cox : Outgoing firewall on build_xmit - * A.N.Kuznetsov : IP_OPTIONS support throughout the kernel - * Alan Cox : Multicast routing hooks - * Jos Vos : Do accounting *before* call_in_firewall - * Willy Konynenberg : Transparent proxying support - * - * - * - * To Fix: - * IP fragmentation wants rewriting cleanly. The RFC815 algorithm is much more efficient - * and could be made very efficient with the addition of some virtual memory hacks to permit - * the allocation of a buffer that can then be 'grown' by twiddling page tables. - * Output fragmentation wants updating along with the buffer management to use a single - * interleaved copy algorithm so that fragmenting has a one copy overhead. Actual packet - * output should probably do its own fragmentation at the UDP/RAW layer. TCP shouldn't cause - * fragmentation anyway. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#define pr_fmt(fmt) "IPv4: " fmt - -#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 -#include -#include - -/* - * Process Router Attention IP option (RFC 2113) - */ -bool ip_call_ra_chain(struct sk_buff *skb) -{ - struct ip_ra_chain *ra; - u8 protocol = ip_hdr(skb)->protocol; - struct sock *last = NULL; - struct net_device *dev = skb->dev; - struct net *net = dev_net(dev); - - for (ra = rcu_dereference(ip_ra_chain); ra; ra = rcu_dereference(ra->next)) { - struct sock *sk = ra->sk; - - /* If socket is bound to an interface, only report - * the packet if it came from that interface. - */ - if (sk && inet_sk(sk)->inet_num == protocol && - (!sk->sk_bound_dev_if || - sk->sk_bound_dev_if == dev->ifindex) && - net_eq(sock_net(sk), net)) { - if (ip_is_fragment(ip_hdr(skb))) { - if (ip_defrag(net, skb, IP_DEFRAG_CALL_RA_CHAIN)) - return true; - } - if (last) { - struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2) - raw_rcv(last, skb2); - } - last = sk; - } - } - - if (last) { - raw_rcv(last, skb); - return true; - } - return false; -} - -static int ip_local_deliver_finish(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - __skb_pull(skb, skb_network_header_len(skb)); - - rcu_read_lock(); - { - int protocol = ip_hdr(skb)->protocol; - const struct net_protocol *ipprot; - int raw; - - resubmit: - raw = raw_local_deliver(skb, protocol); - - ipprot = rcu_dereference(inet_protos[protocol]); - if (ipprot) { - int ret; - - if (!ipprot->no_policy) { - if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { - kfree_skb(skb); - goto out; - } - nf_reset(skb); - } - ret = ipprot->handler(skb); - if (ret < 0) { - protocol = -ret; - goto resubmit; - } - __IP_INC_STATS(net, IPSTATS_MIB_INDELIVERS); - } else { - if (!raw) { - if (xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { - __IP_INC_STATS(net, IPSTATS_MIB_INUNKNOWNPROTOS); - icmp_send(skb, ICMP_DEST_UNREACH, - ICMP_PROT_UNREACH, 0); - } - kfree_skb(skb); - } else { - __IP_INC_STATS(net, IPSTATS_MIB_INDELIVERS); - consume_skb(skb); - } - } - } - out: - rcu_read_unlock(); - - return 0; -} - -/* - * Deliver IP Packets to the higher protocol layers. - */ -int ip_local_deliver(struct sk_buff *skb) -{ - /* - * Reassemble IP fragments. - */ - struct net *net = dev_net(skb->dev); - - if (ip_is_fragment(ip_hdr(skb))) { - if (ip_defrag(net, skb, IP_DEFRAG_LOCAL_DELIVER)) - return 0; - } - - return NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN, - net, NULL, skb, skb->dev, NULL, - ip_local_deliver_finish); -} - -static inline bool ip_rcv_options(struct sk_buff *skb) -{ - struct ip_options *opt; - const struct iphdr *iph; - struct net_device *dev = skb->dev; - - /* It looks as overkill, because not all - IP options require packet mangling. - But it is the easiest for now, especially taking - into account that combination of IP options - and running sniffer is extremely rare condition. - --ANK (980813) - */ - if (skb_cow(skb, skb_headroom(skb))) { - __IP_INC_STATS(dev_net(dev), IPSTATS_MIB_INDISCARDS); - goto drop; - } - - iph = ip_hdr(skb); - opt = &(IPCB(skb)->opt); - opt->optlen = iph->ihl*4 - sizeof(struct iphdr); - - if (ip_options_compile(dev_net(dev), opt, skb)) { - __IP_INC_STATS(dev_net(dev), IPSTATS_MIB_INHDRERRORS); - goto drop; - } - - if (unlikely(opt->srr)) { - struct in_device *in_dev = __in_dev_get_rcu(dev); - - if (in_dev) { - if (!IN_DEV_SOURCE_ROUTE(in_dev)) { - if (IN_DEV_LOG_MARTIANS(in_dev)) - net_info_ratelimited("source route option %pI4 -> %pI4\n", - &iph->saddr, - &iph->daddr); - goto drop; - } - } - - if (ip_options_rcv_srr(skb)) - goto drop; - } - - return false; -drop: - return true; -} - -static int ip_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - const struct iphdr *iph = ip_hdr(skb); - struct rtable *rt; - struct net_device *dev = skb->dev; - - /* if ingress device is enslaved to an L3 master device pass the - * skb to its handler for processing - */ - skb = l3mdev_ip_rcv(skb); - if (!skb) - return NET_RX_SUCCESS; - - if (net->ipv4.sysctl_ip_early_demux && - !skb_dst(skb) && - !skb->sk && - !ip_is_fragment(iph)) { - const struct net_protocol *ipprot; - int protocol = iph->protocol; - - ipprot = rcu_dereference(inet_protos[protocol]); - if (ipprot && ipprot->early_demux) { - ipprot->early_demux(skb); - /* must reload iph, skb->head might have changed */ - iph = ip_hdr(skb); - } - } - - /* - * Initialise the virtual path cache for the packet. It describes - * how the packet travels inside Linux networking. - */ - if (!skb_valid_dst(skb)) { - int err = ip_route_input_noref(skb, iph->daddr, iph->saddr, - iph->tos, dev); - if (unlikely(err)) { - if (err == -EXDEV) - __NET_INC_STATS(net, LINUX_MIB_IPRPFILTER); - goto drop; - } - } - -#ifdef CONFIG_IP_ROUTE_CLASSID - if (unlikely(skb_dst(skb)->tclassid)) { - struct ip_rt_acct *st = this_cpu_ptr(ip_rt_acct); - u32 idx = skb_dst(skb)->tclassid; - st[idx&0xFF].o_packets++; - st[idx&0xFF].o_bytes += skb->len; - st[(idx>>16)&0xFF].i_packets++; - st[(idx>>16)&0xFF].i_bytes += skb->len; - } -#endif - - if (iph->ihl > 5 && ip_rcv_options(skb)) - goto drop; - - rt = skb_rtable(skb); - if (rt->rt_type == RTN_MULTICAST) { - __IP_UPD_PO_STATS(net, IPSTATS_MIB_INMCAST, skb->len); - } else if (rt->rt_type == RTN_BROADCAST) { - __IP_UPD_PO_STATS(net, IPSTATS_MIB_INBCAST, skb->len); - } else if (skb->pkt_type == PACKET_BROADCAST || - skb->pkt_type == PACKET_MULTICAST) { - struct in_device *in_dev = __in_dev_get_rcu(dev); - - /* RFC 1122 3.3.6: - * - * When a host sends a datagram to a link-layer broadcast - * address, the IP destination address MUST be a legal IP - * broadcast or IP multicast address. - * - * A host SHOULD silently discard a datagram that is received - * via a link-layer broadcast (see Section 2.4) but does not - * specify an IP multicast or broadcast destination address. - * - * This doesn't explicitly say L2 *broadcast*, but broadcast is - * in a way a form of multicast and the most common use case for - * this is 802.11 protecting against cross-station spoofing (the - * so-called "hole-196" attack) so do it for both. - */ - if (in_dev && - IN_DEV_ORCONF(in_dev, DROP_UNICAST_IN_L2_MULTICAST)) - goto drop; - } - - return dst_input(skb); - -drop: - kfree_skb(skb); - return NET_RX_DROP; -} - -/* - * Main IP Receive routine. - */ -int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) -{ - const struct iphdr *iph; - struct net *net; - u32 len; - - /* When the interface is in promisc. mode, drop all the crap - * that it receives, do not try to analyse it. - */ - if (skb->pkt_type == PACKET_OTHERHOST) - goto drop; - - - net = dev_net(dev); - __IP_UPD_PO_STATS(net, IPSTATS_MIB_IN, skb->len); - - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) { - __IP_INC_STATS(net, IPSTATS_MIB_INDISCARDS); - goto out; - } - - if (!pskb_may_pull(skb, sizeof(struct iphdr))) - goto inhdr_error; - - iph = ip_hdr(skb); - - /* - * RFC1122: 3.2.1.2 MUST silently discard any IP frame that fails the checksum. - * - * Is the datagram acceptable? - * - * 1. Length at least the size of an ip header - * 2. Version of 4 - * 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums] - * 4. Doesn't have a bogus length - */ - - if (iph->ihl < 5 || iph->version != 4) - goto inhdr_error; - - BUILD_BUG_ON(IPSTATS_MIB_ECT1PKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_ECT_1); - BUILD_BUG_ON(IPSTATS_MIB_ECT0PKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_ECT_0); - BUILD_BUG_ON(IPSTATS_MIB_CEPKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_CE); - __IP_ADD_STATS(net, - IPSTATS_MIB_NOECTPKTS + (iph->tos & INET_ECN_MASK), - max_t(unsigned short, 1, skb_shinfo(skb)->gso_segs)); - - if (!pskb_may_pull(skb, iph->ihl*4)) - goto inhdr_error; - - iph = ip_hdr(skb); - - if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl))) - goto csum_error; - - len = ntohs(iph->tot_len); - if (skb->len < len) { - __IP_INC_STATS(net, IPSTATS_MIB_INTRUNCATEDPKTS); - goto drop; - } else if (len < (iph->ihl*4)) - goto inhdr_error; - - /* Our transport medium may have padded the buffer out. Now we know it - * is IP we can trim to the true length of the frame. - * Note this now means skb->len holds ntohs(iph->tot_len). - */ - if (pskb_trim_rcsum(skb, len)) { - __IP_INC_STATS(net, IPSTATS_MIB_INDISCARDS); - goto drop; - } - - skb->transport_header = skb->network_header + iph->ihl*4; - - /* Remove any debris in the socket control block */ - memset(IPCB(skb), 0, sizeof(struct inet_skb_parm)); - IPCB(skb)->iif = skb->skb_iif; - - /* Must drop socket now because of tproxy. */ - skb_orphan(skb); - - return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, - net, NULL, skb, dev, NULL, - ip_rcv_finish); - -csum_error: - __IP_INC_STATS(net, IPSTATS_MIB_CSUMERRORS); -inhdr_error: - __IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS); -drop: - kfree_skb(skb); -out: - return NET_RX_DROP; -} diff --git a/src/linux/net/ipv4/ip_options.c b/src/linux/net/ipv4/ip_options.c deleted file mode 100644 index 4d158ff..0000000 --- a/src/linux/net/ipv4/ip_options.c +++ /dev/null @@ -1,661 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * The options processing module for ip.c - * - * Authors: A.N.Kuznetsov - * - */ - -#define pr_fmt(fmt) "IPv4: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * Write options to IP header, record destination address to - * source route option, address of outgoing interface - * (we should already know it, so that this function is allowed be - * called only after routing decision) and timestamp, - * if we originate this datagram. - * - * daddr is real destination address, next hop is recorded in IP header. - * saddr is address of outgoing interface. - */ - -void ip_options_build(struct sk_buff *skb, struct ip_options *opt, - __be32 daddr, struct rtable *rt, int is_frag) -{ - unsigned char *iph = skb_network_header(skb); - - memcpy(&(IPCB(skb)->opt), opt, sizeof(struct ip_options)); - memcpy(iph+sizeof(struct iphdr), opt->__data, opt->optlen); - opt = &(IPCB(skb)->opt); - - if (opt->srr) - memcpy(iph+opt->srr+iph[opt->srr+1]-4, &daddr, 4); - - if (!is_frag) { - if (opt->rr_needaddr) - ip_rt_get_source(iph+opt->rr+iph[opt->rr+2]-5, skb, rt); - if (opt->ts_needaddr) - ip_rt_get_source(iph+opt->ts+iph[opt->ts+2]-9, skb, rt); - if (opt->ts_needtime) { - __be32 midtime; - - midtime = inet_current_timestamp(); - memcpy(iph+opt->ts+iph[opt->ts+2]-5, &midtime, 4); - } - return; - } - if (opt->rr) { - memset(iph+opt->rr, IPOPT_NOP, iph[opt->rr+1]); - opt->rr = 0; - opt->rr_needaddr = 0; - } - if (opt->ts) { - memset(iph+opt->ts, IPOPT_NOP, iph[opt->ts+1]); - opt->ts = 0; - opt->ts_needaddr = opt->ts_needtime = 0; - } -} - -/* - * Provided (sopt, skb) points to received options, - * build in dopt compiled option set appropriate for answering. - * i.e. invert SRR option, copy anothers, - * and grab room in RR/TS options. - * - * NOTE: dopt cannot point to skb. - */ - -int __ip_options_echo(struct ip_options *dopt, struct sk_buff *skb, - const struct ip_options *sopt) -{ - unsigned char *sptr, *dptr; - int soffset, doffset; - int optlen; - - memset(dopt, 0, sizeof(struct ip_options)); - - if (sopt->optlen == 0) - return 0; - - sptr = skb_network_header(skb); - dptr = dopt->__data; - - if (sopt->rr) { - optlen = sptr[sopt->rr+1]; - soffset = sptr[sopt->rr+2]; - dopt->rr = dopt->optlen + sizeof(struct iphdr); - memcpy(dptr, sptr+sopt->rr, optlen); - if (sopt->rr_needaddr && soffset <= optlen) { - if (soffset + 3 > optlen) - return -EINVAL; - dptr[2] = soffset + 4; - dopt->rr_needaddr = 1; - } - dptr += optlen; - dopt->optlen += optlen; - } - if (sopt->ts) { - optlen = sptr[sopt->ts+1]; - soffset = sptr[sopt->ts+2]; - dopt->ts = dopt->optlen + sizeof(struct iphdr); - memcpy(dptr, sptr+sopt->ts, optlen); - if (soffset <= optlen) { - if (sopt->ts_needaddr) { - if (soffset + 3 > optlen) - return -EINVAL; - dopt->ts_needaddr = 1; - soffset += 4; - } - if (sopt->ts_needtime) { - if (soffset + 3 > optlen) - return -EINVAL; - if ((dptr[3]&0xF) != IPOPT_TS_PRESPEC) { - dopt->ts_needtime = 1; - soffset += 4; - } else { - dopt->ts_needtime = 0; - - if (soffset + 7 <= optlen) { - __be32 addr; - - memcpy(&addr, dptr+soffset-1, 4); - if (inet_addr_type(dev_net(skb_dst(skb)->dev), addr) != RTN_UNICAST) { - dopt->ts_needtime = 1; - soffset += 8; - } - } - } - } - dptr[2] = soffset; - } - dptr += optlen; - dopt->optlen += optlen; - } - if (sopt->srr) { - unsigned char *start = sptr+sopt->srr; - __be32 faddr; - - optlen = start[1]; - soffset = start[2]; - doffset = 0; - if (soffset > optlen) - soffset = optlen + 1; - soffset -= 4; - if (soffset > 3) { - memcpy(&faddr, &start[soffset-1], 4); - for (soffset -= 4, doffset = 4; soffset > 3; soffset -= 4, doffset += 4) - memcpy(&dptr[doffset-1], &start[soffset-1], 4); - /* - * RFC1812 requires to fix illegal source routes. - */ - if (memcmp(&ip_hdr(skb)->saddr, - &start[soffset + 3], 4) == 0) - doffset -= 4; - } - if (doffset > 3) { - __be32 daddr = fib_compute_spec_dst(skb); - - memcpy(&start[doffset-1], &daddr, 4); - dopt->faddr = faddr; - dptr[0] = start[0]; - dptr[1] = doffset+3; - dptr[2] = 4; - dptr += doffset+3; - dopt->srr = dopt->optlen + sizeof(struct iphdr); - dopt->optlen += doffset+3; - dopt->is_strictroute = sopt->is_strictroute; - } - } - if (sopt->cipso) { - optlen = sptr[sopt->cipso+1]; - dopt->cipso = dopt->optlen+sizeof(struct iphdr); - memcpy(dptr, sptr+sopt->cipso, optlen); - dptr += optlen; - dopt->optlen += optlen; - } - while (dopt->optlen & 3) { - *dptr++ = IPOPT_END; - dopt->optlen++; - } - return 0; -} - -/* - * Options "fragmenting", just fill options not - * allowed in fragments with NOOPs. - * Simple and stupid 8), but the most efficient way. - */ - -void ip_options_fragment(struct sk_buff *skb) -{ - unsigned char *optptr = skb_network_header(skb) + sizeof(struct iphdr); - struct ip_options *opt = &(IPCB(skb)->opt); - int l = opt->optlen; - int optlen; - - while (l > 0) { - switch (*optptr) { - case IPOPT_END: - return; - case IPOPT_NOOP: - l--; - optptr++; - continue; - } - optlen = optptr[1]; - if (optlen < 2 || optlen > l) - return; - if (!IPOPT_COPIED(*optptr)) - memset(optptr, IPOPT_NOOP, optlen); - l -= optlen; - optptr += optlen; - } - opt->ts = 0; - opt->rr = 0; - opt->rr_needaddr = 0; - opt->ts_needaddr = 0; - opt->ts_needtime = 0; -} - -/* helper used by ip_options_compile() to call fib_compute_spec_dst() - * at most one time. - */ -static void spec_dst_fill(__be32 *spec_dst, struct sk_buff *skb) -{ - if (*spec_dst == htonl(INADDR_ANY)) - *spec_dst = fib_compute_spec_dst(skb); -} - -/* - * Verify options and fill pointers in struct options. - * Caller should clear *opt, and set opt->data. - * If opt == NULL, then skb->data should point to IP header. - */ - -int ip_options_compile(struct net *net, - struct ip_options *opt, struct sk_buff *skb) -{ - __be32 spec_dst = htonl(INADDR_ANY); - unsigned char *pp_ptr = NULL; - struct rtable *rt = NULL; - unsigned char *optptr; - unsigned char *iph; - int optlen, l; - - if (skb) { - rt = skb_rtable(skb); - optptr = (unsigned char *)&(ip_hdr(skb)[1]); - } else - optptr = opt->__data; - iph = optptr - sizeof(struct iphdr); - - for (l = opt->optlen; l > 0; ) { - switch (*optptr) { - case IPOPT_END: - for (optptr++, l--; l > 0; optptr++, l--) { - if (*optptr != IPOPT_END) { - *optptr = IPOPT_END; - opt->is_changed = 1; - } - } - goto eol; - case IPOPT_NOOP: - l--; - optptr++; - continue; - } - if (unlikely(l < 2)) { - pp_ptr = optptr; - goto error; - } - optlen = optptr[1]; - if (optlen < 2 || optlen > l) { - pp_ptr = optptr; - goto error; - } - switch (*optptr) { - case IPOPT_SSRR: - case IPOPT_LSRR: - if (optlen < 3) { - pp_ptr = optptr + 1; - goto error; - } - if (optptr[2] < 4) { - pp_ptr = optptr + 2; - goto error; - } - /* NB: cf RFC-1812 5.2.4.1 */ - if (opt->srr) { - pp_ptr = optptr; - goto error; - } - if (!skb) { - if (optptr[2] != 4 || optlen < 7 || ((optlen-3) & 3)) { - pp_ptr = optptr + 1; - goto error; - } - memcpy(&opt->faddr, &optptr[3], 4); - if (optlen > 7) - memmove(&optptr[3], &optptr[7], optlen-7); - } - opt->is_strictroute = (optptr[0] == IPOPT_SSRR); - opt->srr = optptr - iph; - break; - case IPOPT_RR: - if (opt->rr) { - pp_ptr = optptr; - goto error; - } - if (optlen < 3) { - pp_ptr = optptr + 1; - goto error; - } - if (optptr[2] < 4) { - pp_ptr = optptr + 2; - goto error; - } - if (optptr[2] <= optlen) { - if (optptr[2]+3 > optlen) { - pp_ptr = optptr + 2; - goto error; - } - if (rt) { - spec_dst_fill(&spec_dst, skb); - memcpy(&optptr[optptr[2]-1], &spec_dst, 4); - opt->is_changed = 1; - } - optptr[2] += 4; - opt->rr_needaddr = 1; - } - opt->rr = optptr - iph; - break; - case IPOPT_TIMESTAMP: - if (opt->ts) { - pp_ptr = optptr; - goto error; - } - if (optlen < 4) { - pp_ptr = optptr + 1; - goto error; - } - if (optptr[2] < 5) { - pp_ptr = optptr + 2; - goto error; - } - if (optptr[2] <= optlen) { - unsigned char *timeptr = NULL; - if (optptr[2]+3 > optlen) { - pp_ptr = optptr + 2; - goto error; - } - switch (optptr[3]&0xF) { - case IPOPT_TS_TSONLY: - if (skb) - timeptr = &optptr[optptr[2]-1]; - opt->ts_needtime = 1; - optptr[2] += 4; - break; - case IPOPT_TS_TSANDADDR: - if (optptr[2]+7 > optlen) { - pp_ptr = optptr + 2; - goto error; - } - if (rt) { - spec_dst_fill(&spec_dst, skb); - memcpy(&optptr[optptr[2]-1], &spec_dst, 4); - timeptr = &optptr[optptr[2]+3]; - } - opt->ts_needaddr = 1; - opt->ts_needtime = 1; - optptr[2] += 8; - break; - case IPOPT_TS_PRESPEC: - if (optptr[2]+7 > optlen) { - pp_ptr = optptr + 2; - goto error; - } - { - __be32 addr; - memcpy(&addr, &optptr[optptr[2]-1], 4); - if (inet_addr_type(net, addr) == RTN_UNICAST) - break; - if (skb) - timeptr = &optptr[optptr[2]+3]; - } - opt->ts_needtime = 1; - optptr[2] += 8; - break; - default: - if (!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) { - pp_ptr = optptr + 3; - goto error; - } - break; - } - if (timeptr) { - __be32 midtime; - - midtime = inet_current_timestamp(); - memcpy(timeptr, &midtime, 4); - opt->is_changed = 1; - } - } else if ((optptr[3]&0xF) != IPOPT_TS_PRESPEC) { - unsigned int overflow = optptr[3]>>4; - if (overflow == 15) { - pp_ptr = optptr + 3; - goto error; - } - if (skb) { - optptr[3] = (optptr[3]&0xF)|((overflow+1)<<4); - opt->is_changed = 1; - } - } - opt->ts = optptr - iph; - break; - case IPOPT_RA: - if (optlen < 4) { - pp_ptr = optptr + 1; - goto error; - } - if (optptr[2] == 0 && optptr[3] == 0) - opt->router_alert = optptr - iph; - break; - case IPOPT_CIPSO: - if ((!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) || opt->cipso) { - pp_ptr = optptr; - goto error; - } - opt->cipso = optptr - iph; - if (cipso_v4_validate(skb, &optptr)) { - pp_ptr = optptr; - goto error; - } - break; - case IPOPT_SEC: - case IPOPT_SID: - default: - if (!skb && !ns_capable(net->user_ns, CAP_NET_RAW)) { - pp_ptr = optptr; - goto error; - } - break; - } - l -= optlen; - optptr += optlen; - } - -eol: - if (!pp_ptr) - return 0; - -error: - if (skb) { - icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((pp_ptr-iph)<<24)); - } - return -EINVAL; -} -EXPORT_SYMBOL(ip_options_compile); - -/* - * Undo all the changes done by ip_options_compile(). - */ - -void ip_options_undo(struct ip_options *opt) -{ - if (opt->srr) { - unsigned char *optptr = opt->__data+opt->srr-sizeof(struct iphdr); - memmove(optptr+7, optptr+3, optptr[1]-7); - memcpy(optptr+3, &opt->faddr, 4); - } - if (opt->rr_needaddr) { - unsigned char *optptr = opt->__data+opt->rr-sizeof(struct iphdr); - optptr[2] -= 4; - memset(&optptr[optptr[2]-1], 0, 4); - } - if (opt->ts) { - unsigned char *optptr = opt->__data+opt->ts-sizeof(struct iphdr); - if (opt->ts_needtime) { - optptr[2] -= 4; - memset(&optptr[optptr[2]-1], 0, 4); - if ((optptr[3]&0xF) == IPOPT_TS_PRESPEC) - optptr[2] -= 4; - } - if (opt->ts_needaddr) { - optptr[2] -= 4; - memset(&optptr[optptr[2]-1], 0, 4); - } - } -} - -static struct ip_options_rcu *ip_options_get_alloc(const int optlen) -{ - return kzalloc(sizeof(struct ip_options_rcu) + ((optlen + 3) & ~3), - GFP_KERNEL); -} - -static int ip_options_get_finish(struct net *net, struct ip_options_rcu **optp, - struct ip_options_rcu *opt, int optlen) -{ - while (optlen & 3) - opt->opt.__data[optlen++] = IPOPT_END; - opt->opt.optlen = optlen; - if (optlen && ip_options_compile(net, &opt->opt, NULL)) { - kfree(opt); - return -EINVAL; - } - kfree(*optp); - *optp = opt; - return 0; -} - -int ip_options_get_from_user(struct net *net, struct ip_options_rcu **optp, - unsigned char __user *data, int optlen) -{ - struct ip_options_rcu *opt = ip_options_get_alloc(optlen); - - if (!opt) - return -ENOMEM; - if (optlen && copy_from_user(opt->opt.__data, data, optlen)) { - kfree(opt); - return -EFAULT; - } - return ip_options_get_finish(net, optp, opt, optlen); -} - -int ip_options_get(struct net *net, struct ip_options_rcu **optp, - unsigned char *data, int optlen) -{ - struct ip_options_rcu *opt = ip_options_get_alloc(optlen); - - if (!opt) - return -ENOMEM; - if (optlen) - memcpy(opt->opt.__data, data, optlen); - return ip_options_get_finish(net, optp, opt, optlen); -} - -void ip_forward_options(struct sk_buff *skb) -{ - struct ip_options *opt = &(IPCB(skb)->opt); - unsigned char *optptr; - struct rtable *rt = skb_rtable(skb); - unsigned char *raw = skb_network_header(skb); - - if (opt->rr_needaddr) { - optptr = (unsigned char *)raw + opt->rr; - ip_rt_get_source(&optptr[optptr[2]-5], skb, rt); - opt->is_changed = 1; - } - if (opt->srr_is_hit) { - int srrptr, srrspace; - - optptr = raw + opt->srr; - - for ( srrptr = optptr[2], srrspace = optptr[1]; - srrptr <= srrspace; - srrptr += 4 - ) { - if (srrptr + 3 > srrspace) - break; - if (memcmp(&opt->nexthop, &optptr[srrptr-1], 4) == 0) - break; - } - if (srrptr + 3 <= srrspace) { - opt->is_changed = 1; - ip_hdr(skb)->daddr = opt->nexthop; - ip_rt_get_source(&optptr[srrptr-1], skb, rt); - optptr[2] = srrptr+4; - } else { - net_crit_ratelimited("%s(): Argh! Destination lost!\n", - __func__); - } - if (opt->ts_needaddr) { - optptr = raw + opt->ts; - ip_rt_get_source(&optptr[optptr[2]-9], skb, rt); - opt->is_changed = 1; - } - } - if (opt->is_changed) { - opt->is_changed = 0; - ip_send_check(ip_hdr(skb)); - } -} - -int ip_options_rcv_srr(struct sk_buff *skb) -{ - struct ip_options *opt = &(IPCB(skb)->opt); - int srrspace, srrptr; - __be32 nexthop; - struct iphdr *iph = ip_hdr(skb); - unsigned char *optptr = skb_network_header(skb) + opt->srr; - struct rtable *rt = skb_rtable(skb); - struct rtable *rt2; - unsigned long orefdst; - int err; - - if (!rt) - return 0; - - if (skb->pkt_type != PACKET_HOST) - return -EINVAL; - if (rt->rt_type == RTN_UNICAST) { - if (!opt->is_strictroute) - return 0; - icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl(16<<24)); - return -EINVAL; - } - if (rt->rt_type != RTN_LOCAL) - return -EINVAL; - - for (srrptr = optptr[2], srrspace = optptr[1]; srrptr <= srrspace; srrptr += 4) { - if (srrptr + 3 > srrspace) { - icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((opt->srr+2)<<24)); - return -EINVAL; - } - memcpy(&nexthop, &optptr[srrptr-1], 4); - - orefdst = skb->_skb_refdst; - skb_dst_set(skb, NULL); - err = ip_route_input(skb, nexthop, iph->saddr, iph->tos, skb->dev); - rt2 = skb_rtable(skb); - if (err || (rt2->rt_type != RTN_UNICAST && rt2->rt_type != RTN_LOCAL)) { - skb_dst_drop(skb); - skb->_skb_refdst = orefdst; - return -EINVAL; - } - refdst_drop(orefdst); - if (rt2->rt_type != RTN_LOCAL) - break; - /* Superfast 8) loopback forward */ - iph->daddr = nexthop; - opt->is_changed = 1; - } - if (srrptr <= srrspace) { - opt->srr_is_hit = 1; - opt->nexthop = nexthop; - opt->is_changed = 1; - } - return 0; -} -EXPORT_SYMBOL(ip_options_rcv_srr); diff --git a/src/linux/net/ipv4/ip_output.c b/src/linux/net/ipv4/ip_output.c deleted file mode 100644 index 877bdb0..0000000 --- a/src/linux/net/ipv4/ip_output.c +++ /dev/null @@ -1,1637 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * The Internet Protocol (IP) output module. - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Donald Becker, - * Alan Cox, - * Richard Underwood - * Stefan Becker, - * Jorge Cwik, - * Arnt Gulbrandsen, - * Hirokazu Takahashi, - * - * See ip_input.c for original log - * - * Fixes: - * Alan Cox : Missing nonblock feature in ip_build_xmit. - * Mike Kilburn : htons() missing in ip_build_xmit. - * Bradford Johnson: Fix faulty handling of some frames when - * no route is found. - * Alexander Demenshin: Missing sk/skb free in ip_queue_xmit - * (in case if packet not accepted by - * output firewall rules) - * Mike McLagan : Routing by source - * Alexey Kuznetsov: use new route cache - * Andi Kleen: Fix broken PMTU recovery and remove - * some redundant tests. - * Vitaly E. Lavrov : Transparent proxy revived after year coma. - * Andi Kleen : Replace ip_reply with ip_send_reply. - * Andi Kleen : Split fast and slow ip_build_xmit path - * for decreased register pressure on x86 - * and more readibility. - * Marc Boucher : When call_out_firewall returns FW_QUEUE, - * silently drop skb instead of failing with -EPERM. - * Detlev Wengorz : Copy protocol for fragments. - * Hirokazu Takahashi: HW checksumming for outgoing UDP - * datagrams. - * Hirokazu Takahashi: sendfile() on UDP works now. - */ - -#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 -#include -#include -#include -#include -#include -#include -#include - -static int -ip_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, - unsigned int mtu, - int (*output)(struct net *, struct sock *, struct sk_buff *)); - -/* Generate a checksum for an outgoing IP datagram. */ -void ip_send_check(struct iphdr *iph) -{ - iph->check = 0; - iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); -} -EXPORT_SYMBOL(ip_send_check); - -int __ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - struct iphdr *iph = ip_hdr(skb); - - iph->tot_len = htons(skb->len); - ip_send_check(iph); - - /* if egress device is enslaved to an L3 master device pass the - * skb to its handler for processing - */ - skb = l3mdev_ip_out(sk, skb); - if (unlikely(!skb)) - return 0; - - skb->protocol = htons(ETH_P_IP); - - return nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, - net, sk, skb, NULL, skb_dst(skb)->dev, - dst_output); -} - -int ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - int err; - - err = __ip_local_out(net, sk, skb); - if (likely(err == 1)) - err = dst_output(net, sk, skb); - - return err; -} -EXPORT_SYMBOL_GPL(ip_local_out); - -static inline int ip_select_ttl(struct inet_sock *inet, struct dst_entry *dst) -{ - int ttl = inet->uc_ttl; - - if (ttl < 0) - ttl = ip4_dst_hoplimit(dst); - return ttl; -} - -/* - * Add an ip header to a skbuff and send it out. - * - */ -int ip_build_and_send_pkt(struct sk_buff *skb, const struct sock *sk, - __be32 saddr, __be32 daddr, struct ip_options_rcu *opt) -{ - struct inet_sock *inet = inet_sk(sk); - struct rtable *rt = skb_rtable(skb); - struct net *net = sock_net(sk); - struct iphdr *iph; - - /* Build the IP header. */ - skb_push(skb, sizeof(struct iphdr) + (opt ? opt->opt.optlen : 0)); - skb_reset_network_header(skb); - iph = ip_hdr(skb); - iph->version = 4; - iph->ihl = 5; - iph->tos = inet->tos; - iph->ttl = ip_select_ttl(inet, &rt->dst); - iph->daddr = (opt && opt->opt.srr ? opt->opt.faddr : daddr); - iph->saddr = saddr; - iph->protocol = sk->sk_protocol; - if (ip_dont_fragment(sk, &rt->dst)) { - iph->frag_off = htons(IP_DF); - iph->id = 0; - } else { - iph->frag_off = 0; - __ip_select_ident(net, iph, 1); - } - - if (opt && opt->opt.optlen) { - iph->ihl += opt->opt.optlen>>2; - ip_options_build(skb, &opt->opt, daddr, rt, 0); - } - - skb->priority = sk->sk_priority; - skb->mark = sk->sk_mark; - - /* Send it out. */ - return ip_local_out(net, skb->sk, skb); -} -EXPORT_SYMBOL_GPL(ip_build_and_send_pkt); - -static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - struct dst_entry *dst = skb_dst(skb); - struct rtable *rt = (struct rtable *)dst; - struct net_device *dev = dst->dev; - unsigned int hh_len = LL_RESERVED_SPACE(dev); - struct neighbour *neigh; - u32 nexthop; - - if (rt->rt_type == RTN_MULTICAST) { - IP_UPD_PO_STATS(net, IPSTATS_MIB_OUTMCAST, skb->len); - } else if (rt->rt_type == RTN_BROADCAST) - IP_UPD_PO_STATS(net, IPSTATS_MIB_OUTBCAST, skb->len); - - /* Be paranoid, rather than too clever. */ - if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) { - struct sk_buff *skb2; - - skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev)); - if (!skb2) { - kfree_skb(skb); - return -ENOMEM; - } - if (skb->sk) - skb_set_owner_w(skb2, skb->sk); - consume_skb(skb); - skb = skb2; - } - - if (lwtunnel_xmit_redirect(dst->lwtstate)) { - int res = lwtunnel_xmit(skb); - - if (res < 0 || res == LWTUNNEL_XMIT_DONE) - return res; - } - - rcu_read_lock_bh(); - nexthop = (__force u32) rt_nexthop(rt, ip_hdr(skb)->daddr); - neigh = __ipv4_neigh_lookup_noref(dev, nexthop); - if (unlikely(!neigh)) - neigh = __neigh_create(&arp_tbl, &nexthop, dev, false); - if (!IS_ERR(neigh)) { - int res = dst_neigh_output(dst, neigh, skb); - - rcu_read_unlock_bh(); - return res; - } - rcu_read_unlock_bh(); - - net_dbg_ratelimited("%s: No header cache and no neighbour!\n", - __func__); - kfree_skb(skb); - return -EINVAL; -} - -static int ip_finish_output_gso(struct net *net, struct sock *sk, - struct sk_buff *skb, unsigned int mtu) -{ - netdev_features_t features; - struct sk_buff *segs; - int ret = 0; - - /* common case: seglen is <= mtu - */ - if (skb_gso_validate_mtu(skb, mtu)) - return ip_finish_output2(net, sk, skb); - - /* Slowpath - GSO segment length exceeds the egress MTU. - * - * This can happen in several cases: - * - Forwarding of a TCP GRO skb, when DF flag is not set. - * - Forwarding of an skb that arrived on a virtualization interface - * (virtio-net/vhost/tap) with TSO/GSO size set by other network - * stack. - * - Local GSO skb transmitted on an NETIF_F_TSO tunnel stacked over an - * interface with a smaller MTU. - * - Arriving GRO skb (or GSO skb in a virtualized environment) that is - * bridged to a NETIF_F_TSO tunnel stacked over an interface with an - * insufficent MTU. - */ - features = netif_skb_features(skb); - BUILD_BUG_ON(sizeof(*IPCB(skb)) > SKB_SGO_CB_OFFSET); - segs = skb_gso_segment(skb, features & ~NETIF_F_GSO_MASK); - if (IS_ERR_OR_NULL(segs)) { - kfree_skb(skb); - return -ENOMEM; - } - - consume_skb(skb); - - do { - struct sk_buff *nskb = segs->next; - int err; - - segs->next = NULL; - err = ip_fragment(net, sk, segs, mtu, ip_finish_output2); - - if (err && ret == 0) - ret = err; - segs = nskb; - } while (segs); - - return ret; -} - -static int ip_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - unsigned int mtu; - -#if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM) - /* Policy lookup after SNAT yielded a new policy */ - if (skb_dst(skb)->xfrm) { - IPCB(skb)->flags |= IPSKB_REROUTED; - return dst_output(net, sk, skb); - } -#endif - mtu = ip_skb_dst_mtu(sk, skb); - if (skb_is_gso(skb)) - return ip_finish_output_gso(net, sk, skb, mtu); - - if (skb->len > mtu || (IPCB(skb)->flags & IPSKB_FRAG_PMTU)) - return ip_fragment(net, sk, skb, mtu, ip_finish_output2); - - return ip_finish_output2(net, sk, skb); -} - -int ip_mc_output(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - struct rtable *rt = skb_rtable(skb); - struct net_device *dev = rt->dst.dev; - - /* - * If the indicated interface is up and running, send the packet. - */ - IP_UPD_PO_STATS(net, IPSTATS_MIB_OUT, skb->len); - - skb->dev = dev; - skb->protocol = htons(ETH_P_IP); - - /* - * Multicasts are looped back for other local users - */ - - if (rt->rt_flags&RTCF_MULTICAST) { - if (sk_mc_loop(sk) -#ifdef CONFIG_IP_MROUTE - /* Small optimization: do not loopback not local frames, - which returned after forwarding; they will be dropped - by ip_mr_input in any case. - Note, that local frames are looped back to be delivered - to local recipients. - - This check is duplicated in ip_mr_input at the moment. - */ - && - ((rt->rt_flags & RTCF_LOCAL) || - !(IPCB(skb)->flags & IPSKB_FORWARDED)) -#endif - ) { - struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); - if (newskb) - NF_HOOK(NFPROTO_IPV4, NF_INET_POST_ROUTING, - net, sk, newskb, NULL, newskb->dev, - dev_loopback_xmit); - } - - /* Multicasts with ttl 0 must not go beyond the host */ - - if (ip_hdr(skb)->ttl == 0) { - kfree_skb(skb); - return 0; - } - } - - if (rt->rt_flags&RTCF_BROADCAST) { - struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); - if (newskb) - NF_HOOK(NFPROTO_IPV4, NF_INET_POST_ROUTING, - net, sk, newskb, NULL, newskb->dev, - dev_loopback_xmit); - } - - return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, - net, sk, skb, NULL, skb->dev, - ip_finish_output, - !(IPCB(skb)->flags & IPSKB_REROUTED)); -} - -int ip_output(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - struct net_device *dev = skb_dst(skb)->dev; - - IP_UPD_PO_STATS(net, IPSTATS_MIB_OUT, skb->len); - - skb->dev = dev; - skb->protocol = htons(ETH_P_IP); - - return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, - net, sk, skb, NULL, dev, - ip_finish_output, - !(IPCB(skb)->flags & IPSKB_REROUTED)); -} - -/* - * copy saddr and daddr, possibly using 64bit load/stores - * Equivalent to : - * iph->saddr = fl4->saddr; - * iph->daddr = fl4->daddr; - */ -static void ip_copy_addrs(struct iphdr *iph, const struct flowi4 *fl4) -{ - BUILD_BUG_ON(offsetof(typeof(*fl4), daddr) != - offsetof(typeof(*fl4), saddr) + sizeof(fl4->saddr)); - memcpy(&iph->saddr, &fl4->saddr, - sizeof(fl4->saddr) + sizeof(fl4->daddr)); -} - -/* Note: skb->sk can be different from sk, in case of tunnels */ -int ip_queue_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl) -{ - struct inet_sock *inet = inet_sk(sk); - struct net *net = sock_net(sk); - struct ip_options_rcu *inet_opt; - struct flowi4 *fl4; - struct rtable *rt; - struct iphdr *iph; - int res; - - /* Skip all of this if the packet is already routed, - * f.e. by something like SCTP. - */ - rcu_read_lock(); - inet_opt = rcu_dereference(inet->inet_opt); - fl4 = &fl->u.ip4; - rt = skb_rtable(skb); - if (rt) - goto packet_routed; - - /* Make sure we can route this packet. */ - rt = (struct rtable *)__sk_dst_check(sk, 0); - if (!rt) { - __be32 daddr; - - /* Use correct destination address if we have options. */ - daddr = inet->inet_daddr; - if (inet_opt && inet_opt->opt.srr) - daddr = inet_opt->opt.faddr; - - /* If this fails, retransmit mechanism of transport layer will - * keep trying until route appears or the connection times - * itself out. - */ - rt = ip_route_output_ports(net, fl4, sk, - daddr, inet->inet_saddr, - inet->inet_dport, - inet->inet_sport, - sk->sk_protocol, - RT_CONN_FLAGS(sk), - sk->sk_bound_dev_if); - if (IS_ERR(rt)) - goto no_route; - sk_setup_caps(sk, &rt->dst); - } - skb_dst_set_noref(skb, &rt->dst); - -packet_routed: - if (inet_opt && inet_opt->opt.is_strictroute && rt->rt_uses_gateway) - goto no_route; - - /* OK, we know where to send it, allocate and build IP header. */ - skb_push(skb, sizeof(struct iphdr) + (inet_opt ? inet_opt->opt.optlen : 0)); - skb_reset_network_header(skb); - iph = ip_hdr(skb); - *((__be16 *)iph) = htons((4 << 12) | (5 << 8) | (inet->tos & 0xff)); - if (ip_dont_fragment(sk, &rt->dst) && !skb->ignore_df) - iph->frag_off = htons(IP_DF); - else - iph->frag_off = 0; - iph->ttl = ip_select_ttl(inet, &rt->dst); - iph->protocol = sk->sk_protocol; - ip_copy_addrs(iph, fl4); - - /* Transport layer set skb->h.foo itself. */ - - if (inet_opt && inet_opt->opt.optlen) { - iph->ihl += inet_opt->opt.optlen >> 2; - ip_options_build(skb, &inet_opt->opt, inet->inet_daddr, rt, 0); - } - - ip_select_ident_segs(net, skb, sk, - skb_shinfo(skb)->gso_segs ?: 1); - - /* TODO : should we use skb->sk here instead of sk ? */ - skb->priority = sk->sk_priority; - skb->mark = sk->sk_mark; - - res = ip_local_out(net, sk, skb); - rcu_read_unlock(); - return res; - -no_route: - rcu_read_unlock(); - IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); - kfree_skb(skb); - return -EHOSTUNREACH; -} -EXPORT_SYMBOL(ip_queue_xmit); - -static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) -{ - to->pkt_type = from->pkt_type; - to->priority = from->priority; - to->protocol = from->protocol; - skb_dst_drop(to); - skb_dst_copy(to, from); - to->dev = from->dev; - to->mark = from->mark; - - /* Copy the flags to each fragment. */ - IPCB(to)->flags = IPCB(from)->flags; - -#ifdef CONFIG_NET_SCHED - to->tc_index = from->tc_index; -#endif - nf_copy(to, from); -#if IS_ENABLED(CONFIG_IP_VS) - to->ipvs_property = from->ipvs_property; -#endif - skb_copy_secmark(to, from); -} - -static int ip_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, - unsigned int mtu, - int (*output)(struct net *, struct sock *, struct sk_buff *)) -{ - struct iphdr *iph = ip_hdr(skb); - - if ((iph->frag_off & htons(IP_DF)) == 0) - return ip_do_fragment(net, sk, skb, output); - - if (unlikely(!skb->ignore_df || - (IPCB(skb)->frag_max_size && - IPCB(skb)->frag_max_size > mtu))) { - IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS); - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, - htonl(mtu)); - kfree_skb(skb); - return -EMSGSIZE; - } - - return ip_do_fragment(net, sk, skb, output); -} - -/* - * This IP datagram is too large to be sent in one piece. Break it up into - * smaller pieces (each of size equal to IP header plus - * a block of the data of the original IP data part) that will yet fit in a - * single device frame, and queue such a frame for sending. - */ - -int ip_do_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, - int (*output)(struct net *, struct sock *, struct sk_buff *)) -{ - struct iphdr *iph; - int ptr; - struct sk_buff *skb2; - unsigned int mtu, hlen, left, len, ll_rs; - int offset; - __be16 not_last_frag; - struct rtable *rt = skb_rtable(skb); - int err = 0; - - /* for offloaded checksums cleanup checksum before fragmentation */ - if (skb->ip_summed == CHECKSUM_PARTIAL && - (err = skb_checksum_help(skb))) - goto fail; - - /* - * Point into the IP datagram header. - */ - - iph = ip_hdr(skb); - - mtu = ip_skb_dst_mtu(sk, skb); - if (IPCB(skb)->frag_max_size && IPCB(skb)->frag_max_size < mtu) - mtu = IPCB(skb)->frag_max_size; - - /* - * Setup starting values. - */ - - hlen = iph->ihl * 4; - mtu = mtu - hlen; /* Size of data space */ - IPCB(skb)->flags |= IPSKB_FRAG_COMPLETE; - - /* When frag_list is given, use it. First, check its validity: - * some transformers could create wrong frag_list or break existing - * one, it is not prohibited. In this case fall back to copying. - * - * LATER: this step can be merged to real generation of fragments, - * we can switch to copy when see the first bad fragment. - */ - if (skb_has_frag_list(skb)) { - struct sk_buff *frag, *frag2; - int first_len = skb_pagelen(skb); - - if (first_len - hlen > mtu || - ((first_len - hlen) & 7) || - ip_is_fragment(iph) || - skb_cloned(skb)) - goto slow_path; - - skb_walk_frags(skb, frag) { - /* Correct geometry. */ - if (frag->len > mtu || - ((frag->len & 7) && frag->next) || - skb_headroom(frag) < hlen) - goto slow_path_clean; - - /* Partially cloned skb? */ - if (skb_shared(frag)) - goto slow_path_clean; - - BUG_ON(frag->sk); - if (skb->sk) { - frag->sk = skb->sk; - frag->destructor = sock_wfree; - } - skb->truesize -= frag->truesize; - } - - /* Everything is OK. Generate! */ - - err = 0; - offset = 0; - frag = skb_shinfo(skb)->frag_list; - skb_frag_list_init(skb); - skb->data_len = first_len - skb_headlen(skb); - skb->len = first_len; - iph->tot_len = htons(first_len); - iph->frag_off = htons(IP_MF); - ip_send_check(iph); - - for (;;) { - /* Prepare header of the next frame, - * before previous one went down. */ - if (frag) { - frag->ip_summed = CHECKSUM_NONE; - skb_reset_transport_header(frag); - __skb_push(frag, hlen); - skb_reset_network_header(frag); - memcpy(skb_network_header(frag), iph, hlen); - iph = ip_hdr(frag); - iph->tot_len = htons(frag->len); - ip_copy_metadata(frag, skb); - if (offset == 0) - ip_options_fragment(frag); - offset += skb->len - hlen; - iph->frag_off = htons(offset>>3); - if (frag->next) - iph->frag_off |= htons(IP_MF); - /* Ready, complete checksum */ - ip_send_check(iph); - } - - err = output(net, sk, skb); - - if (!err) - IP_INC_STATS(net, IPSTATS_MIB_FRAGCREATES); - if (err || !frag) - break; - - skb = frag; - frag = skb->next; - skb->next = NULL; - } - - if (err == 0) { - IP_INC_STATS(net, IPSTATS_MIB_FRAGOKS); - return 0; - } - - while (frag) { - skb = frag->next; - kfree_skb(frag); - frag = skb; - } - IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS); - return err; - -slow_path_clean: - skb_walk_frags(skb, frag2) { - if (frag2 == frag) - break; - frag2->sk = NULL; - frag2->destructor = NULL; - skb->truesize += frag2->truesize; - } - } - -slow_path: - iph = ip_hdr(skb); - - left = skb->len - hlen; /* Space per frame */ - ptr = hlen; /* Where to start from */ - - ll_rs = LL_RESERVED_SPACE(rt->dst.dev); - - /* - * Fragment the datagram. - */ - - offset = (ntohs(iph->frag_off) & IP_OFFSET) << 3; - not_last_frag = iph->frag_off & htons(IP_MF); - - /* - * Keep copying data until we run out. - */ - - while (left > 0) { - len = left; - /* IF: it doesn't fit, use 'mtu' - the data space left */ - if (len > mtu) - len = mtu; - /* IF: we are not sending up to and including the packet end - then align the next start on an eight byte boundary */ - if (len < left) { - len &= ~7; - } - - /* Allocate buffer */ - skb2 = alloc_skb(len + hlen + ll_rs, GFP_ATOMIC); - if (!skb2) { - err = -ENOMEM; - goto fail; - } - - /* - * Set up data on packet - */ - - ip_copy_metadata(skb2, skb); - skb_reserve(skb2, ll_rs); - skb_put(skb2, len + hlen); - skb_reset_network_header(skb2); - skb2->transport_header = skb2->network_header + hlen; - - /* - * Charge the memory for the fragment to any owner - * it might possess - */ - - if (skb->sk) - skb_set_owner_w(skb2, skb->sk); - - /* - * Copy the packet header into the new buffer. - */ - - skb_copy_from_linear_data(skb, skb_network_header(skb2), hlen); - - /* - * Copy a block of the IP datagram. - */ - if (skb_copy_bits(skb, ptr, skb_transport_header(skb2), len)) - BUG(); - left -= len; - - /* - * Fill in the new header fields. - */ - iph = ip_hdr(skb2); - iph->frag_off = htons((offset >> 3)); - - if (IPCB(skb)->flags & IPSKB_FRAG_PMTU) - iph->frag_off |= htons(IP_DF); - - /* ANK: dirty, but effective trick. Upgrade options only if - * the segment to be fragmented was THE FIRST (otherwise, - * options are already fixed) and make it ONCE - * on the initial skb, so that all the following fragments - * will inherit fixed options. - */ - if (offset == 0) - ip_options_fragment(skb); - - /* - * Added AC : If we are fragmenting a fragment that's not the - * last fragment then keep MF on each bit - */ - if (left > 0 || not_last_frag) - iph->frag_off |= htons(IP_MF); - ptr += len; - offset += len; - - /* - * Put this fragment into the sending queue. - */ - iph->tot_len = htons(len + hlen); - - ip_send_check(iph); - - err = output(net, sk, skb2); - if (err) - goto fail; - - IP_INC_STATS(net, IPSTATS_MIB_FRAGCREATES); - } - consume_skb(skb); - IP_INC_STATS(net, IPSTATS_MIB_FRAGOKS); - return err; - -fail: - kfree_skb(skb); - IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS); - return err; -} -EXPORT_SYMBOL(ip_do_fragment); - -int -ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb) -{ - struct msghdr *msg = from; - - if (skb->ip_summed == CHECKSUM_PARTIAL) { - if (copy_from_iter(to, len, &msg->msg_iter) != len) - return -EFAULT; - } else { - __wsum csum = 0; - if (csum_and_copy_from_iter(to, len, &csum, &msg->msg_iter) != len) - return -EFAULT; - skb->csum = csum_block_add(skb->csum, csum, odd); - } - return 0; -} -EXPORT_SYMBOL(ip_generic_getfrag); - -static inline __wsum -csum_page(struct page *page, int offset, int copy) -{ - char *kaddr; - __wsum csum; - kaddr = kmap(page); - csum = csum_partial(kaddr + offset, copy, 0); - kunmap(page); - return csum; -} - -static inline int ip_ufo_append_data(struct sock *sk, - struct sk_buff_head *queue, - int getfrag(void *from, char *to, int offset, int len, - int odd, struct sk_buff *skb), - void *from, int length, int hh_len, int fragheaderlen, - int transhdrlen, int maxfraglen, unsigned int flags) -{ - struct sk_buff *skb; - int err; - - /* There is support for UDP fragmentation offload by network - * device, so create one single skb packet containing complete - * udp datagram - */ - skb = skb_peek_tail(queue); - if (!skb) { - skb = sock_alloc_send_skb(sk, - hh_len + fragheaderlen + transhdrlen + 20, - (flags & MSG_DONTWAIT), &err); - - if (!skb) - return err; - - /* reserve space for Hardware header */ - skb_reserve(skb, hh_len); - - /* create space for UDP/IP header */ - skb_put(skb, fragheaderlen + transhdrlen); - - /* initialize network header pointer */ - skb_reset_network_header(skb); - - /* initialize protocol header pointer */ - skb->transport_header = skb->network_header + fragheaderlen; - - skb->csum = 0; - - __skb_queue_tail(queue, skb); - } else if (skb_is_gso(skb)) { - goto append; - } - - skb->ip_summed = CHECKSUM_PARTIAL; - /* specify the length of each IP datagram fragment */ - skb_shinfo(skb)->gso_size = maxfraglen - fragheaderlen; - skb_shinfo(skb)->gso_type = SKB_GSO_UDP; - -append: - return skb_append_datato_frags(sk, skb, getfrag, from, - (length - transhdrlen)); -} - -static int __ip_append_data(struct sock *sk, - struct flowi4 *fl4, - struct sk_buff_head *queue, - struct inet_cork *cork, - struct page_frag *pfrag, - int getfrag(void *from, char *to, int offset, - int len, int odd, struct sk_buff *skb), - void *from, int length, int transhdrlen, - unsigned int flags) -{ - struct inet_sock *inet = inet_sk(sk); - struct sk_buff *skb; - - struct ip_options *opt = cork->opt; - int hh_len; - int exthdrlen; - int mtu; - int copy; - int err; - int offset = 0; - unsigned int maxfraglen, fragheaderlen, maxnonfragsize; - int csummode = CHECKSUM_NONE; - struct rtable *rt = (struct rtable *)cork->dst; - u32 tskey = 0; - - skb = skb_peek_tail(queue); - - exthdrlen = !skb ? rt->dst.header_len : 0; - mtu = cork->fragsize; - if (cork->tx_flags & SKBTX_ANY_SW_TSTAMP && - sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) - tskey = sk->sk_tskey++; - - hh_len = LL_RESERVED_SPACE(rt->dst.dev); - - fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0); - maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen; - maxnonfragsize = ip_sk_ignore_df(sk) ? 0xFFFF : mtu; - - if (cork->length + length > maxnonfragsize - fragheaderlen) { - ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport, - mtu - (opt ? opt->optlen : 0)); - return -EMSGSIZE; - } - - /* - * transhdrlen > 0 means that this is the first fragment and we wish - * it won't be fragmented in the future. - */ - if (transhdrlen && - length + fragheaderlen <= mtu && - rt->dst.dev->features & (NETIF_F_HW_CSUM | NETIF_F_IP_CSUM) && - !(flags & MSG_MORE) && - !exthdrlen) - csummode = CHECKSUM_PARTIAL; - - cork->length += length; - if (((length > mtu) || (skb && skb_is_gso(skb))) && - (sk->sk_protocol == IPPROTO_UDP) && - (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len && - (sk->sk_type == SOCK_DGRAM) && !sk->sk_no_check_tx) { - err = ip_ufo_append_data(sk, queue, getfrag, from, length, - hh_len, fragheaderlen, transhdrlen, - maxfraglen, flags); - if (err) - goto error; - return 0; - } - - /* So, what's going on in the loop below? - * - * We use calculated fragment length to generate chained skb, - * each of segments is IP fragment ready for sending to network after - * adding appropriate IP header. - */ - - if (!skb) - goto alloc_new_skb; - - while (length > 0) { - /* Check if the remaining data fits into current packet. */ - copy = mtu - skb->len; - if (copy < length) - copy = maxfraglen - skb->len; - if (copy <= 0) { - char *data; - unsigned int datalen; - unsigned int fraglen; - unsigned int fraggap; - unsigned int alloclen; - struct sk_buff *skb_prev; -alloc_new_skb: - skb_prev = skb; - if (skb_prev) - fraggap = skb_prev->len - maxfraglen; - else - fraggap = 0; - - /* - * If remaining data exceeds the mtu, - * we know we need more fragment(s). - */ - datalen = length + fraggap; - if (datalen > mtu - fragheaderlen) - datalen = maxfraglen - fragheaderlen; - fraglen = datalen + fragheaderlen; - - if ((flags & MSG_MORE) && - !(rt->dst.dev->features&NETIF_F_SG)) - alloclen = mtu; - else - alloclen = fraglen; - - alloclen += exthdrlen; - - /* The last fragment gets additional space at tail. - * Note, with MSG_MORE we overallocate on fragments, - * because we have no idea what fragment will be - * the last. - */ - if (datalen == length + fraggap) - alloclen += rt->dst.trailer_len; - - if (transhdrlen) { - skb = sock_alloc_send_skb(sk, - alloclen + hh_len + 15, - (flags & MSG_DONTWAIT), &err); - } else { - skb = NULL; - if (atomic_read(&sk->sk_wmem_alloc) <= - 2 * sk->sk_sndbuf) - skb = sock_wmalloc(sk, - alloclen + hh_len + 15, 1, - sk->sk_allocation); - if (unlikely(!skb)) - err = -ENOBUFS; - } - if (!skb) - goto error; - - /* - * Fill in the control structures - */ - skb->ip_summed = csummode; - skb->csum = 0; - skb_reserve(skb, hh_len); - - /* only the initial fragment is time stamped */ - skb_shinfo(skb)->tx_flags = cork->tx_flags; - cork->tx_flags = 0; - skb_shinfo(skb)->tskey = tskey; - tskey = 0; - - /* - * Find where to start putting bytes. - */ - data = skb_put(skb, fraglen + exthdrlen); - skb_set_network_header(skb, exthdrlen); - skb->transport_header = (skb->network_header + - fragheaderlen); - data += fragheaderlen + exthdrlen; - - if (fraggap) { - skb->csum = skb_copy_and_csum_bits( - skb_prev, maxfraglen, - data + transhdrlen, fraggap, 0); - skb_prev->csum = csum_sub(skb_prev->csum, - skb->csum); - data += fraggap; - pskb_trim_unique(skb_prev, maxfraglen); - } - - copy = datalen - transhdrlen - fraggap; - if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) { - err = -EFAULT; - kfree_skb(skb); - goto error; - } - - offset += copy; - length -= datalen - fraggap; - transhdrlen = 0; - exthdrlen = 0; - csummode = CHECKSUM_NONE; - - /* - * Put the packet on the pending queue. - */ - __skb_queue_tail(queue, skb); - continue; - } - - if (copy > length) - copy = length; - - if (!(rt->dst.dev->features&NETIF_F_SG)) { - unsigned int off; - - off = skb->len; - if (getfrag(from, skb_put(skb, copy), - offset, copy, off, skb) < 0) { - __skb_trim(skb, off); - err = -EFAULT; - goto error; - } - } else { - int i = skb_shinfo(skb)->nr_frags; - - err = -ENOMEM; - if (!sk_page_frag_refill(sk, pfrag)) - goto error; - - if (!skb_can_coalesce(skb, i, pfrag->page, - pfrag->offset)) { - err = -EMSGSIZE; - if (i == MAX_SKB_FRAGS) - goto error; - - __skb_fill_page_desc(skb, i, pfrag->page, - pfrag->offset, 0); - skb_shinfo(skb)->nr_frags = ++i; - get_page(pfrag->page); - } - copy = min_t(int, copy, pfrag->size - pfrag->offset); - if (getfrag(from, - page_address(pfrag->page) + pfrag->offset, - offset, copy, skb->len, skb) < 0) - goto error_efault; - - pfrag->offset += copy; - skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy); - skb->len += copy; - skb->data_len += copy; - skb->truesize += copy; - atomic_add(copy, &sk->sk_wmem_alloc); - } - offset += copy; - length -= copy; - } - - return 0; - -error_efault: - err = -EFAULT; -error: - cork->length -= length; - IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS); - return err; -} - -static int ip_setup_cork(struct sock *sk, struct inet_cork *cork, - struct ipcm_cookie *ipc, struct rtable **rtp) -{ - struct ip_options_rcu *opt; - struct rtable *rt; - - /* - * setup for corking. - */ - opt = ipc->opt; - if (opt) { - if (!cork->opt) { - cork->opt = kmalloc(sizeof(struct ip_options) + 40, - sk->sk_allocation); - if (unlikely(!cork->opt)) - return -ENOBUFS; - } - memcpy(cork->opt, &opt->opt, sizeof(struct ip_options) + opt->opt.optlen); - cork->flags |= IPCORK_OPT; - cork->addr = ipc->addr; - } - rt = *rtp; - if (unlikely(!rt)) - return -EFAULT; - /* - * We steal reference to this route, caller should not release it - */ - *rtp = NULL; - cork->fragsize = ip_sk_use_pmtu(sk) ? - dst_mtu(&rt->dst) : rt->dst.dev->mtu; - cork->dst = &rt->dst; - cork->length = 0; - cork->ttl = ipc->ttl; - cork->tos = ipc->tos; - cork->priority = ipc->priority; - cork->tx_flags = ipc->tx_flags; - - return 0; -} - -/* - * ip_append_data() and ip_append_page() can make one large IP datagram - * from many pieces of data. Each pieces will be holded on the socket - * until ip_push_pending_frames() is called. Each piece can be a page - * or non-page data. - * - * Not only UDP, other transport protocols - e.g. raw sockets - can use - * this interface potentially. - * - * LATER: length must be adjusted by pad at tail, when it is required. - */ -int ip_append_data(struct sock *sk, struct flowi4 *fl4, - int getfrag(void *from, char *to, int offset, int len, - int odd, struct sk_buff *skb), - void *from, int length, int transhdrlen, - struct ipcm_cookie *ipc, struct rtable **rtp, - unsigned int flags) -{ - struct inet_sock *inet = inet_sk(sk); - int err; - - if (flags&MSG_PROBE) - return 0; - - if (skb_queue_empty(&sk->sk_write_queue)) { - err = ip_setup_cork(sk, &inet->cork.base, ipc, rtp); - if (err) - return err; - } else { - transhdrlen = 0; - } - - return __ip_append_data(sk, fl4, &sk->sk_write_queue, &inet->cork.base, - sk_page_frag(sk), getfrag, - from, length, transhdrlen, flags); -} - -ssize_t ip_append_page(struct sock *sk, struct flowi4 *fl4, struct page *page, - int offset, size_t size, int flags) -{ - struct inet_sock *inet = inet_sk(sk); - struct sk_buff *skb; - struct rtable *rt; - struct ip_options *opt = NULL; - struct inet_cork *cork; - int hh_len; - int mtu; - int len; - int err; - unsigned int maxfraglen, fragheaderlen, fraggap, maxnonfragsize; - - if (inet->hdrincl) - return -EPERM; - - if (flags&MSG_PROBE) - return 0; - - if (skb_queue_empty(&sk->sk_write_queue)) - return -EINVAL; - - cork = &inet->cork.base; - rt = (struct rtable *)cork->dst; - if (cork->flags & IPCORK_OPT) - opt = cork->opt; - - if (!(rt->dst.dev->features&NETIF_F_SG)) - return -EOPNOTSUPP; - - hh_len = LL_RESERVED_SPACE(rt->dst.dev); - mtu = cork->fragsize; - - fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0); - maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen; - maxnonfragsize = ip_sk_ignore_df(sk) ? 0xFFFF : mtu; - - if (cork->length + size > maxnonfragsize - fragheaderlen) { - ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport, - mtu - (opt ? opt->optlen : 0)); - return -EMSGSIZE; - } - - skb = skb_peek_tail(&sk->sk_write_queue); - if (!skb) - return -EINVAL; - - if ((size + skb->len > mtu) && - (sk->sk_protocol == IPPROTO_UDP) && - (rt->dst.dev->features & NETIF_F_UFO)) { - if (skb->ip_summed != CHECKSUM_PARTIAL) - return -EOPNOTSUPP; - - skb_shinfo(skb)->gso_size = mtu - fragheaderlen; - skb_shinfo(skb)->gso_type = SKB_GSO_UDP; - } - cork->length += size; - - while (size > 0) { - if (skb_is_gso(skb)) { - len = size; - } else { - - /* Check if the remaining data fits into current packet. */ - len = mtu - skb->len; - if (len < size) - len = maxfraglen - skb->len; - } - if (len <= 0) { - struct sk_buff *skb_prev; - int alloclen; - - skb_prev = skb; - fraggap = skb_prev->len - maxfraglen; - - alloclen = fragheaderlen + hh_len + fraggap + 15; - skb = sock_wmalloc(sk, alloclen, 1, sk->sk_allocation); - if (unlikely(!skb)) { - err = -ENOBUFS; - goto error; - } - - /* - * Fill in the control structures - */ - skb->ip_summed = CHECKSUM_NONE; - skb->csum = 0; - skb_reserve(skb, hh_len); - - /* - * Find where to start putting bytes. - */ - skb_put(skb, fragheaderlen + fraggap); - skb_reset_network_header(skb); - skb->transport_header = (skb->network_header + - fragheaderlen); - if (fraggap) { - skb->csum = skb_copy_and_csum_bits(skb_prev, - maxfraglen, - skb_transport_header(skb), - fraggap, 0); - skb_prev->csum = csum_sub(skb_prev->csum, - skb->csum); - pskb_trim_unique(skb_prev, maxfraglen); - } - - /* - * Put the packet on the pending queue. - */ - __skb_queue_tail(&sk->sk_write_queue, skb); - continue; - } - - if (len > size) - len = size; - - if (skb_append_pagefrags(skb, page, offset, len)) { - err = -EMSGSIZE; - goto error; - } - - if (skb->ip_summed == CHECKSUM_NONE) { - __wsum csum; - csum = csum_page(page, offset, len); - skb->csum = csum_block_add(skb->csum, csum, skb->len); - } - - skb->len += len; - skb->data_len += len; - skb->truesize += len; - atomic_add(len, &sk->sk_wmem_alloc); - offset += len; - size -= len; - } - return 0; - -error: - cork->length -= size; - IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTDISCARDS); - return err; -} - -static void ip_cork_release(struct inet_cork *cork) -{ - cork->flags &= ~IPCORK_OPT; - kfree(cork->opt); - cork->opt = NULL; - dst_release(cork->dst); - cork->dst = NULL; -} - -/* - * Combined all pending IP fragments on the socket as one IP datagram - * and push them out. - */ -struct sk_buff *__ip_make_skb(struct sock *sk, - struct flowi4 *fl4, - struct sk_buff_head *queue, - struct inet_cork *cork) -{ - struct sk_buff *skb, *tmp_skb; - struct sk_buff **tail_skb; - struct inet_sock *inet = inet_sk(sk); - struct net *net = sock_net(sk); - struct ip_options *opt = NULL; - struct rtable *rt = (struct rtable *)cork->dst; - struct iphdr *iph; - __be16 df = 0; - __u8 ttl; - - skb = __skb_dequeue(queue); - if (!skb) - goto out; - tail_skb = &(skb_shinfo(skb)->frag_list); - - /* move skb->data to ip header from ext header */ - if (skb->data < skb_network_header(skb)) - __skb_pull(skb, skb_network_offset(skb)); - while ((tmp_skb = __skb_dequeue(queue)) != NULL) { - __skb_pull(tmp_skb, skb_network_header_len(skb)); - *tail_skb = tmp_skb; - tail_skb = &(tmp_skb->next); - skb->len += tmp_skb->len; - skb->data_len += tmp_skb->len; - skb->truesize += tmp_skb->truesize; - tmp_skb->destructor = NULL; - tmp_skb->sk = NULL; - } - - /* Unless user demanded real pmtu discovery (IP_PMTUDISC_DO), we allow - * to fragment the frame generated here. No matter, what transforms - * how transforms change size of the packet, it will come out. - */ - skb->ignore_df = ip_sk_ignore_df(sk); - - /* DF bit is set when we want to see DF on outgoing frames. - * If ignore_df is set too, we still allow to fragment this frame - * locally. */ - if (inet->pmtudisc == IP_PMTUDISC_DO || - inet->pmtudisc == IP_PMTUDISC_PROBE || - (skb->len <= dst_mtu(&rt->dst) && - ip_dont_fragment(sk, &rt->dst))) - df = htons(IP_DF); - - if (cork->flags & IPCORK_OPT) - opt = cork->opt; - - if (cork->ttl != 0) - ttl = cork->ttl; - else if (rt->rt_type == RTN_MULTICAST) - ttl = inet->mc_ttl; - else - ttl = ip_select_ttl(inet, &rt->dst); - - iph = ip_hdr(skb); - iph->version = 4; - iph->ihl = 5; - iph->tos = (cork->tos != -1) ? cork->tos : inet->tos; - iph->frag_off = df; - iph->ttl = ttl; - iph->protocol = sk->sk_protocol; - ip_copy_addrs(iph, fl4); - ip_select_ident(net, skb, sk); - - if (opt) { - iph->ihl += opt->optlen>>2; - ip_options_build(skb, opt, cork->addr, rt, 0); - } - - skb->priority = (cork->tos != -1) ? cork->priority: sk->sk_priority; - skb->mark = sk->sk_mark; - /* - * Steal rt from cork.dst to avoid a pair of atomic_inc/atomic_dec - * on dst refcount - */ - cork->dst = NULL; - skb_dst_set(skb, &rt->dst); - - if (iph->protocol == IPPROTO_ICMP) - icmp_out_count(net, ((struct icmphdr *) - skb_transport_header(skb))->type); - - ip_cork_release(cork); -out: - return skb; -} - -int ip_send_skb(struct net *net, struct sk_buff *skb) -{ - int err; - - err = ip_local_out(net, skb->sk, skb); - if (err) { - if (err > 0) - err = net_xmit_errno(err); - if (err) - IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS); - } - - return err; -} - -int ip_push_pending_frames(struct sock *sk, struct flowi4 *fl4) -{ - struct sk_buff *skb; - - skb = ip_finish_skb(sk, fl4); - if (!skb) - return 0; - - /* Netfilter gets whole the not fragmented skb. */ - return ip_send_skb(sock_net(sk), skb); -} - -/* - * Throw away all pending data on the socket. - */ -static void __ip_flush_pending_frames(struct sock *sk, - struct sk_buff_head *queue, - struct inet_cork *cork) -{ - struct sk_buff *skb; - - while ((skb = __skb_dequeue_tail(queue)) != NULL) - kfree_skb(skb); - - ip_cork_release(cork); -} - -void ip_flush_pending_frames(struct sock *sk) -{ - __ip_flush_pending_frames(sk, &sk->sk_write_queue, &inet_sk(sk)->cork.base); -} - -struct sk_buff *ip_make_skb(struct sock *sk, - struct flowi4 *fl4, - int getfrag(void *from, char *to, int offset, - int len, int odd, struct sk_buff *skb), - void *from, int length, int transhdrlen, - struct ipcm_cookie *ipc, struct rtable **rtp, - unsigned int flags) -{ - struct inet_cork cork; - struct sk_buff_head queue; - int err; - - if (flags & MSG_PROBE) - return NULL; - - __skb_queue_head_init(&queue); - - cork.flags = 0; - cork.addr = 0; - cork.opt = NULL; - err = ip_setup_cork(sk, &cork, ipc, rtp); - if (err) - return ERR_PTR(err); - - err = __ip_append_data(sk, fl4, &queue, &cork, - ¤t->task_frag, getfrag, - from, length, transhdrlen, flags); - if (err) { - __ip_flush_pending_frames(sk, &queue, &cork); - return ERR_PTR(err); - } - - return __ip_make_skb(sk, fl4, &queue, &cork); -} - -/* - * Fetch data from kernel space and fill in checksum if needed. - */ -static int ip_reply_glue_bits(void *dptr, char *to, int offset, - int len, int odd, struct sk_buff *skb) -{ - __wsum csum; - - csum = csum_partial_copy_nocheck(dptr+offset, to, len, 0); - skb->csum = csum_block_add(skb->csum, csum, odd); - return 0; -} - -/* - * Generic function to send a packet as reply to another packet. - * Used to send some TCP resets/acks so far. - */ -void ip_send_unicast_reply(struct sock *sk, struct sk_buff *skb, - const struct ip_options *sopt, - __be32 daddr, __be32 saddr, - const struct ip_reply_arg *arg, - unsigned int len) -{ - struct ip_options_data replyopts; - struct ipcm_cookie ipc; - struct flowi4 fl4; - struct rtable *rt = skb_rtable(skb); - struct net *net = sock_net(sk); - struct sk_buff *nskb; - int err; - int oif; - - if (__ip_options_echo(&replyopts.opt.opt, skb, sopt)) - return; - - ipc.addr = daddr; - ipc.opt = NULL; - ipc.tx_flags = 0; - ipc.ttl = 0; - ipc.tos = -1; - - if (replyopts.opt.opt.optlen) { - ipc.opt = &replyopts.opt; - - if (replyopts.opt.opt.srr) - daddr = replyopts.opt.opt.faddr; - } - - oif = arg->bound_dev_if; - if (!oif && netif_index_is_l3_master(net, skb->skb_iif)) - oif = skb->skb_iif; - - flowi4_init_output(&fl4, oif, - IP4_REPLY_MARK(net, skb->mark), - RT_TOS(arg->tos), - RT_SCOPE_UNIVERSE, ip_hdr(skb)->protocol, - ip_reply_arg_flowi_flags(arg), - daddr, saddr, - tcp_hdr(skb)->source, tcp_hdr(skb)->dest); - security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); - rt = ip_route_output_key(net, &fl4); - if (IS_ERR(rt)) - return; - - inet_sk(sk)->tos = arg->tos; - - sk->sk_priority = skb->priority; - sk->sk_protocol = ip_hdr(skb)->protocol; - sk->sk_bound_dev_if = arg->bound_dev_if; - sk->sk_sndbuf = sysctl_wmem_default; - err = ip_append_data(sk, &fl4, ip_reply_glue_bits, arg->iov->iov_base, - len, 0, &ipc, &rt, MSG_DONTWAIT); - if (unlikely(err)) { - ip_flush_pending_frames(sk); - goto out; - } - - nskb = skb_peek(&sk->sk_write_queue); - if (nskb) { - if (arg->csumoffset >= 0) - *((__sum16 *)skb_transport_header(nskb) + - arg->csumoffset) = csum_fold(csum_add(nskb->csum, - arg->csum)); - nskb->ip_summed = CHECKSUM_NONE; - ip_push_pending_frames(sk, &fl4); - } -out: - ip_rt_put(rt); -} - -void __init ip_init(void) -{ - ip_rt_init(); - inet_initpeers(); - -#if defined(CONFIG_IP_MULTICAST) - igmp_mc_init(); -#endif -} diff --git a/src/linux/net/ipv4/ip_sockglue.c b/src/linux/net/ipv4/ip_sockglue.c deleted file mode 100644 index b8a2d63..0000000 --- a/src/linux/net/ipv4/ip_sockglue.c +++ /dev/null @@ -1,1590 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * The IP to API glue. - * - * Authors: see ip.c - * - * Fixes: - * Many : Split from ip.c , see ip.c for history. - * Martin Mares : TOS setting fixed. - * Alan Cox : Fixed a couple of oopses in Martin's - * TOS tweaks. - * Mike McLagan : Routing by source - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if IS_ENABLED(CONFIG_IPV6) -#include -#endif -#include - -#include -#include - -/* - * SOL_IP control messages. - */ - -static void ip_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) -{ - struct in_pktinfo info = *PKTINFO_SKB_CB(skb); - - info.ipi_addr.s_addr = ip_hdr(skb)->daddr; - - put_cmsg(msg, SOL_IP, IP_PKTINFO, sizeof(info), &info); -} - -static void ip_cmsg_recv_ttl(struct msghdr *msg, struct sk_buff *skb) -{ - int ttl = ip_hdr(skb)->ttl; - put_cmsg(msg, SOL_IP, IP_TTL, sizeof(int), &ttl); -} - -static void ip_cmsg_recv_tos(struct msghdr *msg, struct sk_buff *skb) -{ - put_cmsg(msg, SOL_IP, IP_TOS, 1, &ip_hdr(skb)->tos); -} - -static void ip_cmsg_recv_opts(struct msghdr *msg, struct sk_buff *skb) -{ - if (IPCB(skb)->opt.optlen == 0) - return; - - put_cmsg(msg, SOL_IP, IP_RECVOPTS, IPCB(skb)->opt.optlen, - ip_hdr(skb) + 1); -} - - -static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb) -{ - unsigned char optbuf[sizeof(struct ip_options) + 40]; - struct ip_options *opt = (struct ip_options *)optbuf; - - if (IPCB(skb)->opt.optlen == 0) - return; - - if (ip_options_echo(opt, skb)) { - msg->msg_flags |= MSG_CTRUNC; - return; - } - ip_options_undo(opt); - - put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data); -} - -static void ip_cmsg_recv_checksum(struct msghdr *msg, struct sk_buff *skb, - int tlen, int offset) -{ - __wsum csum = skb->csum; - - if (skb->ip_summed != CHECKSUM_COMPLETE) - return; - - if (offset != 0) - csum = csum_sub(csum, - csum_partial(skb_transport_header(skb) + tlen, - offset, 0)); - - put_cmsg(msg, SOL_IP, IP_CHECKSUM, sizeof(__wsum), &csum); -} - -static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb) -{ - char *secdata; - u32 seclen, secid; - int err; - - err = security_socket_getpeersec_dgram(NULL, skb, &secid); - if (err) - return; - - err = security_secid_to_secctx(secid, &secdata, &seclen); - if (err) - return; - - put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata); - security_release_secctx(secdata, seclen); -} - -static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb) -{ - struct sockaddr_in sin; - const struct iphdr *iph = ip_hdr(skb); - __be16 *ports = (__be16 *)skb_transport_header(skb); - - if (skb_transport_offset(skb) + 4 > skb->len) - return; - - /* All current transport protocols have the port numbers in the - * first four bytes of the transport header and this function is - * written with this assumption in mind. - */ - - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = iph->daddr; - sin.sin_port = ports[1]; - memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); - - put_cmsg(msg, SOL_IP, IP_ORIGDSTADDR, sizeof(sin), &sin); -} - -void ip_cmsg_recv_offset(struct msghdr *msg, struct sk_buff *skb, - int tlen, int offset) -{ - struct inet_sock *inet = inet_sk(skb->sk); - unsigned int flags = inet->cmsg_flags; - - /* Ordered by supposed usage frequency */ - if (flags & IP_CMSG_PKTINFO) { - ip_cmsg_recv_pktinfo(msg, skb); - - flags &= ~IP_CMSG_PKTINFO; - if (!flags) - return; - } - - if (flags & IP_CMSG_TTL) { - ip_cmsg_recv_ttl(msg, skb); - - flags &= ~IP_CMSG_TTL; - if (!flags) - return; - } - - if (flags & IP_CMSG_TOS) { - ip_cmsg_recv_tos(msg, skb); - - flags &= ~IP_CMSG_TOS; - if (!flags) - return; - } - - if (flags & IP_CMSG_RECVOPTS) { - ip_cmsg_recv_opts(msg, skb); - - flags &= ~IP_CMSG_RECVOPTS; - if (!flags) - return; - } - - if (flags & IP_CMSG_RETOPTS) { - ip_cmsg_recv_retopts(msg, skb); - - flags &= ~IP_CMSG_RETOPTS; - if (!flags) - return; - } - - if (flags & IP_CMSG_PASSSEC) { - ip_cmsg_recv_security(msg, skb); - - flags &= ~IP_CMSG_PASSSEC; - if (!flags) - return; - } - - if (flags & IP_CMSG_ORIGDSTADDR) { - ip_cmsg_recv_dstaddr(msg, skb); - - flags &= ~IP_CMSG_ORIGDSTADDR; - if (!flags) - return; - } - - if (flags & IP_CMSG_CHECKSUM) - ip_cmsg_recv_checksum(msg, skb, tlen, offset); -} -EXPORT_SYMBOL(ip_cmsg_recv_offset); - -int ip_cmsg_send(struct sock *sk, struct msghdr *msg, struct ipcm_cookie *ipc, - bool allow_ipv6) -{ - int err, val; - struct cmsghdr *cmsg; - struct net *net = sock_net(sk); - - for_each_cmsghdr(cmsg, msg) { - if (!CMSG_OK(msg, cmsg)) - return -EINVAL; -#if IS_ENABLED(CONFIG_IPV6) - if (allow_ipv6 && - cmsg->cmsg_level == SOL_IPV6 && - cmsg->cmsg_type == IPV6_PKTINFO) { - struct in6_pktinfo *src_info; - - if (cmsg->cmsg_len < CMSG_LEN(sizeof(*src_info))) - return -EINVAL; - src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg); - if (!ipv6_addr_v4mapped(&src_info->ipi6_addr)) - return -EINVAL; - ipc->oif = src_info->ipi6_ifindex; - ipc->addr = src_info->ipi6_addr.s6_addr32[3]; - continue; - } -#endif - if (cmsg->cmsg_level == SOL_SOCKET) { - err = __sock_cmsg_send(sk, msg, cmsg, &ipc->sockc); - if (err) - return err; - continue; - } - - if (cmsg->cmsg_level != SOL_IP) - continue; - switch (cmsg->cmsg_type) { - case IP_RETOPTS: - err = cmsg->cmsg_len - CMSG_ALIGN(sizeof(struct cmsghdr)); - - /* Our caller is responsible for freeing ipc->opt */ - err = ip_options_get(net, &ipc->opt, CMSG_DATA(cmsg), - err < 40 ? err : 40); - if (err) - return err; - break; - case IP_PKTINFO: - { - struct in_pktinfo *info; - if (cmsg->cmsg_len != CMSG_LEN(sizeof(struct in_pktinfo))) - return -EINVAL; - info = (struct in_pktinfo *)CMSG_DATA(cmsg); - ipc->oif = info->ipi_ifindex; - ipc->addr = info->ipi_spec_dst.s_addr; - break; - } - case IP_TTL: - if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) - return -EINVAL; - val = *(int *)CMSG_DATA(cmsg); - if (val < 1 || val > 255) - return -EINVAL; - ipc->ttl = val; - break; - case IP_TOS: - if (cmsg->cmsg_len == CMSG_LEN(sizeof(int))) - val = *(int *)CMSG_DATA(cmsg); - else if (cmsg->cmsg_len == CMSG_LEN(sizeof(u8))) - val = *(u8 *)CMSG_DATA(cmsg); - else - return -EINVAL; - if (val < 0 || val > 255) - return -EINVAL; - ipc->tos = val; - ipc->priority = rt_tos2priority(ipc->tos); - break; - - default: - return -EINVAL; - } - } - return 0; -} - - -/* Special input handler for packets caught by router alert option. - They are selected only by protocol field, and then processed likely - local ones; but only if someone wants them! Otherwise, router - not running rsvpd will kill RSVP. - - It is user level problem, what it will make with them. - I have no idea, how it will masquearde or NAT them (it is joke, joke :-)), - but receiver should be enough clever f.e. to forward mtrace requests, - sent to multicast group to reach destination designated router. - */ -struct ip_ra_chain __rcu *ip_ra_chain; -static DEFINE_SPINLOCK(ip_ra_lock); - - -static void ip_ra_destroy_rcu(struct rcu_head *head) -{ - struct ip_ra_chain *ra = container_of(head, struct ip_ra_chain, rcu); - - sock_put(ra->saved_sk); - kfree(ra); -} - -int ip_ra_control(struct sock *sk, unsigned char on, - void (*destructor)(struct sock *)) -{ - struct ip_ra_chain *ra, *new_ra; - struct ip_ra_chain __rcu **rap; - - if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num == IPPROTO_RAW) - return -EINVAL; - - new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; - - spin_lock_bh(&ip_ra_lock); - for (rap = &ip_ra_chain; - (ra = rcu_dereference_protected(*rap, - lockdep_is_held(&ip_ra_lock))) != NULL; - rap = &ra->next) { - if (ra->sk == sk) { - if (on) { - spin_unlock_bh(&ip_ra_lock); - kfree(new_ra); - return -EADDRINUSE; - } - /* dont let ip_call_ra_chain() use sk again */ - ra->sk = NULL; - RCU_INIT_POINTER(*rap, ra->next); - spin_unlock_bh(&ip_ra_lock); - - if (ra->destructor) - ra->destructor(sk); - /* - * Delay sock_put(sk) and kfree(ra) after one rcu grace - * period. This guarantee ip_call_ra_chain() dont need - * to mess with socket refcounts. - */ - ra->saved_sk = sk; - call_rcu(&ra->rcu, ip_ra_destroy_rcu); - return 0; - } - } - if (!new_ra) { - spin_unlock_bh(&ip_ra_lock); - return -ENOBUFS; - } - new_ra->sk = sk; - new_ra->destructor = destructor; - - RCU_INIT_POINTER(new_ra->next, ra); - rcu_assign_pointer(*rap, new_ra); - sock_hold(sk); - spin_unlock_bh(&ip_ra_lock); - - return 0; -} - -void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err, - __be16 port, u32 info, u8 *payload) -{ - struct sock_exterr_skb *serr; - - skb = skb_clone(skb, GFP_ATOMIC); - if (!skb) - return; - - serr = SKB_EXT_ERR(skb); - serr->ee.ee_errno = err; - serr->ee.ee_origin = SO_EE_ORIGIN_ICMP; - serr->ee.ee_type = icmp_hdr(skb)->type; - serr->ee.ee_code = icmp_hdr(skb)->code; - serr->ee.ee_pad = 0; - serr->ee.ee_info = info; - serr->ee.ee_data = 0; - serr->addr_offset = (u8 *)&(((struct iphdr *)(icmp_hdr(skb) + 1))->daddr) - - skb_network_header(skb); - serr->port = port; - - if (skb_pull(skb, payload - skb->data)) { - skb_reset_transport_header(skb); - if (sock_queue_err_skb(sk, skb) == 0) - return; - } - kfree_skb(skb); -} - -void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 info) -{ - struct inet_sock *inet = inet_sk(sk); - struct sock_exterr_skb *serr; - struct iphdr *iph; - struct sk_buff *skb; - - if (!inet->recverr) - return; - - skb = alloc_skb(sizeof(struct iphdr), GFP_ATOMIC); - if (!skb) - return; - - skb_put(skb, sizeof(struct iphdr)); - skb_reset_network_header(skb); - iph = ip_hdr(skb); - iph->daddr = daddr; - - serr = SKB_EXT_ERR(skb); - serr->ee.ee_errno = err; - serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL; - serr->ee.ee_type = 0; - serr->ee.ee_code = 0; - serr->ee.ee_pad = 0; - serr->ee.ee_info = info; - serr->ee.ee_data = 0; - serr->addr_offset = (u8 *)&iph->daddr - skb_network_header(skb); - serr->port = port; - - __skb_pull(skb, skb_tail_pointer(skb) - skb->data); - skb_reset_transport_header(skb); - - if (sock_queue_err_skb(sk, skb)) - kfree_skb(skb); -} - -/* For some errors we have valid addr_offset even with zero payload and - * zero port. Also, addr_offset should be supported if port is set. - */ -static inline bool ipv4_datagram_support_addr(struct sock_exterr_skb *serr) -{ - return serr->ee.ee_origin == SO_EE_ORIGIN_ICMP || - serr->ee.ee_origin == SO_EE_ORIGIN_LOCAL || serr->port; -} - -/* IPv4 supports cmsg on all imcp errors and some timestamps - * - * Timestamp code paths do not initialize the fields expected by cmsg: - * the PKTINFO fields in skb->cb[]. Fill those in here. - */ -static bool ipv4_datagram_support_cmsg(const struct sock *sk, - struct sk_buff *skb, - int ee_origin) -{ - struct in_pktinfo *info; - - if (ee_origin == SO_EE_ORIGIN_ICMP) - return true; - - if (ee_origin == SO_EE_ORIGIN_LOCAL) - return false; - - /* Support IP_PKTINFO on tstamp packets if requested, to correlate - * timestamp with egress dev. Not possible for packets without dev - * or without payload (SOF_TIMESTAMPING_OPT_TSONLY). - */ - if ((!(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_CMSG)) || - (!skb->dev)) - return false; - - info = PKTINFO_SKB_CB(skb); - info->ipi_spec_dst.s_addr = ip_hdr(skb)->saddr; - info->ipi_ifindex = skb->dev->ifindex; - return true; -} - -/* - * Handle MSG_ERRQUEUE - */ -int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) -{ - struct sock_exterr_skb *serr; - struct sk_buff *skb; - DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name); - struct { - struct sock_extended_err ee; - struct sockaddr_in offender; - } errhdr; - int err; - int copied; - - WARN_ON_ONCE(sk->sk_family == AF_INET6); - - err = -EAGAIN; - skb = sock_dequeue_err_skb(sk); - if (!skb) - goto out; - - copied = skb->len; - if (copied > len) { - msg->msg_flags |= MSG_TRUNC; - copied = len; - } - err = skb_copy_datagram_msg(skb, 0, msg, copied); - if (unlikely(err)) { - kfree_skb(skb); - return err; - } - sock_recv_timestamp(msg, sk, skb); - - serr = SKB_EXT_ERR(skb); - - if (sin && ipv4_datagram_support_addr(serr)) { - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = *(__be32 *)(skb_network_header(skb) + - serr->addr_offset); - sin->sin_port = serr->port; - memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); - *addr_len = sizeof(*sin); - } - - memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); - sin = &errhdr.offender; - memset(sin, 0, sizeof(*sin)); - - if (ipv4_datagram_support_cmsg(sk, skb, serr->ee.ee_origin)) { - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = ip_hdr(skb)->saddr; - if (inet_sk(sk)->cmsg_flags) - ip_cmsg_recv(msg, skb); - } - - put_cmsg(msg, SOL_IP, IP_RECVERR, sizeof(errhdr), &errhdr); - - /* Now we could try to dump offended packet options */ - - msg->msg_flags |= MSG_ERRQUEUE; - err = copied; - - consume_skb(skb); -out: - return err; -} - - -/* - * Socket option code for IP. This is the end of the line after any - * TCP,UDP etc options on an IP socket. - */ -static bool setsockopt_needs_rtnl(int optname) -{ - switch (optname) { - case IP_ADD_MEMBERSHIP: - case IP_ADD_SOURCE_MEMBERSHIP: - case IP_BLOCK_SOURCE: - case IP_DROP_MEMBERSHIP: - case IP_DROP_SOURCE_MEMBERSHIP: - case IP_MSFILTER: - case IP_UNBLOCK_SOURCE: - case MCAST_BLOCK_SOURCE: - case MCAST_MSFILTER: - case MCAST_JOIN_GROUP: - case MCAST_JOIN_SOURCE_GROUP: - case MCAST_LEAVE_GROUP: - case MCAST_LEAVE_SOURCE_GROUP: - case MCAST_UNBLOCK_SOURCE: - return true; - } - return false; -} - -static int do_ip_setsockopt(struct sock *sk, int level, - int optname, char __user *optval, unsigned int optlen) -{ - struct inet_sock *inet = inet_sk(sk); - struct net *net = sock_net(sk); - int val = 0, err; - bool needs_rtnl = setsockopt_needs_rtnl(optname); - - switch (optname) { - case IP_PKTINFO: - case IP_RECVTTL: - case IP_RECVOPTS: - case IP_RECVTOS: - case IP_RETOPTS: - case IP_TOS: - case IP_TTL: - case IP_HDRINCL: - case IP_MTU_DISCOVER: - case IP_RECVERR: - case IP_ROUTER_ALERT: - case IP_FREEBIND: - case IP_PASSSEC: - case IP_TRANSPARENT: - case IP_MINTTL: - case IP_NODEFRAG: - case IP_BIND_ADDRESS_NO_PORT: - case IP_UNICAST_IF: - case IP_MULTICAST_TTL: - case IP_MULTICAST_ALL: - case IP_MULTICAST_LOOP: - case IP_RECVORIGDSTADDR: - case IP_CHECKSUM: - if (optlen >= sizeof(int)) { - if (get_user(val, (int __user *) optval)) - return -EFAULT; - } else if (optlen >= sizeof(char)) { - unsigned char ucval; - - if (get_user(ucval, (unsigned char __user *) optval)) - return -EFAULT; - val = (int) ucval; - } - } - - /* If optlen==0, it is equivalent to val == 0 */ - - if (ip_mroute_opt(optname)) - return ip_mroute_setsockopt(sk, optname, optval, optlen); - - err = 0; - if (needs_rtnl) - rtnl_lock(); - lock_sock(sk); - - switch (optname) { - case IP_OPTIONS: - { - struct ip_options_rcu *old, *opt = NULL; - - if (optlen > 40) - goto e_inval; - err = ip_options_get_from_user(sock_net(sk), &opt, - optval, optlen); - if (err) - break; - old = rcu_dereference_protected(inet->inet_opt, - lockdep_sock_is_held(sk)); - if (inet->is_icsk) { - struct inet_connection_sock *icsk = inet_csk(sk); -#if IS_ENABLED(CONFIG_IPV6) - if (sk->sk_family == PF_INET || - (!((1 << sk->sk_state) & - (TCPF_LISTEN | TCPF_CLOSE)) && - inet->inet_daddr != LOOPBACK4_IPV6)) { -#endif - if (old) - icsk->icsk_ext_hdr_len -= old->opt.optlen; - if (opt) - icsk->icsk_ext_hdr_len += opt->opt.optlen; - icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie); -#if IS_ENABLED(CONFIG_IPV6) - } -#endif - } - rcu_assign_pointer(inet->inet_opt, opt); - if (old) - kfree_rcu(old, rcu); - break; - } - case IP_PKTINFO: - if (val) - inet->cmsg_flags |= IP_CMSG_PKTINFO; - else - inet->cmsg_flags &= ~IP_CMSG_PKTINFO; - break; - case IP_RECVTTL: - if (val) - inet->cmsg_flags |= IP_CMSG_TTL; - else - inet->cmsg_flags &= ~IP_CMSG_TTL; - break; - case IP_RECVTOS: - if (val) - inet->cmsg_flags |= IP_CMSG_TOS; - else - inet->cmsg_flags &= ~IP_CMSG_TOS; - break; - case IP_RECVOPTS: - if (val) - inet->cmsg_flags |= IP_CMSG_RECVOPTS; - else - inet->cmsg_flags &= ~IP_CMSG_RECVOPTS; - break; - case IP_RETOPTS: - if (val) - inet->cmsg_flags |= IP_CMSG_RETOPTS; - else - inet->cmsg_flags &= ~IP_CMSG_RETOPTS; - break; - case IP_PASSSEC: - if (val) - inet->cmsg_flags |= IP_CMSG_PASSSEC; - else - inet->cmsg_flags &= ~IP_CMSG_PASSSEC; - break; - case IP_RECVORIGDSTADDR: - if (val) - inet->cmsg_flags |= IP_CMSG_ORIGDSTADDR; - else - inet->cmsg_flags &= ~IP_CMSG_ORIGDSTADDR; - break; - case IP_CHECKSUM: - if (val) { - if (!(inet->cmsg_flags & IP_CMSG_CHECKSUM)) { - inet_inc_convert_csum(sk); - inet->cmsg_flags |= IP_CMSG_CHECKSUM; - } - } else { - if (inet->cmsg_flags & IP_CMSG_CHECKSUM) { - inet_dec_convert_csum(sk); - inet->cmsg_flags &= ~IP_CMSG_CHECKSUM; - } - } - break; - case IP_TOS: /* This sets both TOS and Precedence */ - if (sk->sk_type == SOCK_STREAM) { - val &= ~INET_ECN_MASK; - val |= inet->tos & INET_ECN_MASK; - } - if (inet->tos != val) { - inet->tos = val; - sk->sk_priority = rt_tos2priority(val); - sk_dst_reset(sk); - } - break; - case IP_TTL: - if (optlen < 1) - goto e_inval; - if (val != -1 && (val < 1 || val > 255)) - goto e_inval; - inet->uc_ttl = val; - break; - case IP_HDRINCL: - if (sk->sk_type != SOCK_RAW) { - err = -ENOPROTOOPT; - break; - } - inet->hdrincl = val ? 1 : 0; - break; - case IP_NODEFRAG: - if (sk->sk_type != SOCK_RAW) { - err = -ENOPROTOOPT; - break; - } - inet->nodefrag = val ? 1 : 0; - break; - case IP_BIND_ADDRESS_NO_PORT: - inet->bind_address_no_port = val ? 1 : 0; - break; - case IP_MTU_DISCOVER: - if (val < IP_PMTUDISC_DONT || val > IP_PMTUDISC_OMIT) - goto e_inval; - inet->pmtudisc = val; - break; - case IP_RECVERR: - inet->recverr = !!val; - if (!val) - skb_queue_purge(&sk->sk_error_queue); - break; - case IP_MULTICAST_TTL: - if (sk->sk_type == SOCK_STREAM) - goto e_inval; - if (optlen < 1) - goto e_inval; - if (val == -1) - val = 1; - if (val < 0 || val > 255) - goto e_inval; - inet->mc_ttl = val; - break; - case IP_MULTICAST_LOOP: - if (optlen < 1) - goto e_inval; - inet->mc_loop = !!val; - break; - case IP_UNICAST_IF: - { - struct net_device *dev = NULL; - int ifindex; - - if (optlen != sizeof(int)) - goto e_inval; - - ifindex = (__force int)ntohl((__force __be32)val); - if (ifindex == 0) { - inet->uc_index = 0; - err = 0; - break; - } - - dev = dev_get_by_index(sock_net(sk), ifindex); - err = -EADDRNOTAVAIL; - if (!dev) - break; - dev_put(dev); - - err = -EINVAL; - if (sk->sk_bound_dev_if) - break; - - inet->uc_index = ifindex; - err = 0; - break; - } - case IP_MULTICAST_IF: - { - struct ip_mreqn mreq; - struct net_device *dev = NULL; - - if (sk->sk_type == SOCK_STREAM) - goto e_inval; - /* - * Check the arguments are allowable - */ - - if (optlen < sizeof(struct in_addr)) - goto e_inval; - - err = -EFAULT; - if (optlen >= sizeof(struct ip_mreqn)) { - if (copy_from_user(&mreq, optval, sizeof(mreq))) - break; - } else { - memset(&mreq, 0, sizeof(mreq)); - if (optlen >= sizeof(struct ip_mreq)) { - if (copy_from_user(&mreq, optval, - sizeof(struct ip_mreq))) - break; - } else if (optlen >= sizeof(struct in_addr)) { - if (copy_from_user(&mreq.imr_address, optval, - sizeof(struct in_addr))) - break; - } - } - - if (!mreq.imr_ifindex) { - if (mreq.imr_address.s_addr == htonl(INADDR_ANY)) { - inet->mc_index = 0; - inet->mc_addr = 0; - err = 0; - break; - } - dev = ip_dev_find(sock_net(sk), mreq.imr_address.s_addr); - if (dev) - mreq.imr_ifindex = dev->ifindex; - } else - dev = dev_get_by_index(sock_net(sk), mreq.imr_ifindex); - - - err = -EADDRNOTAVAIL; - if (!dev) - break; - dev_put(dev); - - err = -EINVAL; - if (sk->sk_bound_dev_if && - mreq.imr_ifindex != sk->sk_bound_dev_if) - break; - - inet->mc_index = mreq.imr_ifindex; - inet->mc_addr = mreq.imr_address.s_addr; - err = 0; - break; - } - - case IP_ADD_MEMBERSHIP: - case IP_DROP_MEMBERSHIP: - { - struct ip_mreqn mreq; - - err = -EPROTO; - if (inet_sk(sk)->is_icsk) - break; - - if (optlen < sizeof(struct ip_mreq)) - goto e_inval; - err = -EFAULT; - if (optlen >= sizeof(struct ip_mreqn)) { - if (copy_from_user(&mreq, optval, sizeof(mreq))) - break; - } else { - memset(&mreq, 0, sizeof(mreq)); - if (copy_from_user(&mreq, optval, sizeof(struct ip_mreq))) - break; - } - - if (optname == IP_ADD_MEMBERSHIP) - err = ip_mc_join_group(sk, &mreq); - else - err = ip_mc_leave_group(sk, &mreq); - break; - } - case IP_MSFILTER: - { - struct ip_msfilter *msf; - - if (optlen < IP_MSFILTER_SIZE(0)) - goto e_inval; - if (optlen > sysctl_optmem_max) { - err = -ENOBUFS; - break; - } - msf = kmalloc(optlen, GFP_KERNEL); - if (!msf) { - err = -ENOBUFS; - break; - } - err = -EFAULT; - if (copy_from_user(msf, optval, optlen)) { - kfree(msf); - break; - } - /* numsrc >= (1G-4) overflow in 32 bits */ - if (msf->imsf_numsrc >= 0x3ffffffcU || - msf->imsf_numsrc > net->ipv4.sysctl_igmp_max_msf) { - kfree(msf); - err = -ENOBUFS; - break; - } - if (IP_MSFILTER_SIZE(msf->imsf_numsrc) > optlen) { - kfree(msf); - err = -EINVAL; - break; - } - err = ip_mc_msfilter(sk, msf, 0); - kfree(msf); - break; - } - case IP_BLOCK_SOURCE: - case IP_UNBLOCK_SOURCE: - case IP_ADD_SOURCE_MEMBERSHIP: - case IP_DROP_SOURCE_MEMBERSHIP: - { - struct ip_mreq_source mreqs; - int omode, add; - - if (optlen != sizeof(struct ip_mreq_source)) - goto e_inval; - if (copy_from_user(&mreqs, optval, sizeof(mreqs))) { - err = -EFAULT; - break; - } - if (optname == IP_BLOCK_SOURCE) { - omode = MCAST_EXCLUDE; - add = 1; - } else if (optname == IP_UNBLOCK_SOURCE) { - omode = MCAST_EXCLUDE; - add = 0; - } else if (optname == IP_ADD_SOURCE_MEMBERSHIP) { - struct ip_mreqn mreq; - - mreq.imr_multiaddr.s_addr = mreqs.imr_multiaddr; - mreq.imr_address.s_addr = mreqs.imr_interface; - mreq.imr_ifindex = 0; - err = ip_mc_join_group(sk, &mreq); - if (err && err != -EADDRINUSE) - break; - omode = MCAST_INCLUDE; - add = 1; - } else /* IP_DROP_SOURCE_MEMBERSHIP */ { - omode = MCAST_INCLUDE; - add = 0; - } - err = ip_mc_source(add, omode, sk, &mreqs, 0); - break; - } - case MCAST_JOIN_GROUP: - case MCAST_LEAVE_GROUP: - { - struct group_req greq; - struct sockaddr_in *psin; - struct ip_mreqn mreq; - - if (optlen < sizeof(struct group_req)) - goto e_inval; - err = -EFAULT; - if (copy_from_user(&greq, optval, sizeof(greq))) - break; - psin = (struct sockaddr_in *)&greq.gr_group; - if (psin->sin_family != AF_INET) - goto e_inval; - memset(&mreq, 0, sizeof(mreq)); - mreq.imr_multiaddr = psin->sin_addr; - mreq.imr_ifindex = greq.gr_interface; - - if (optname == MCAST_JOIN_GROUP) - err = ip_mc_join_group(sk, &mreq); - else - err = ip_mc_leave_group(sk, &mreq); - break; - } - case MCAST_JOIN_SOURCE_GROUP: - case MCAST_LEAVE_SOURCE_GROUP: - case MCAST_BLOCK_SOURCE: - case MCAST_UNBLOCK_SOURCE: - { - struct group_source_req greqs; - struct ip_mreq_source mreqs; - struct sockaddr_in *psin; - int omode, add; - - if (optlen != sizeof(struct group_source_req)) - goto e_inval; - if (copy_from_user(&greqs, optval, sizeof(greqs))) { - err = -EFAULT; - break; - } - if (greqs.gsr_group.ss_family != AF_INET || - greqs.gsr_source.ss_family != AF_INET) { - err = -EADDRNOTAVAIL; - break; - } - psin = (struct sockaddr_in *)&greqs.gsr_group; - mreqs.imr_multiaddr = psin->sin_addr.s_addr; - psin = (struct sockaddr_in *)&greqs.gsr_source; - mreqs.imr_sourceaddr = psin->sin_addr.s_addr; - mreqs.imr_interface = 0; /* use index for mc_source */ - - if (optname == MCAST_BLOCK_SOURCE) { - omode = MCAST_EXCLUDE; - add = 1; - } else if (optname == MCAST_UNBLOCK_SOURCE) { - omode = MCAST_EXCLUDE; - add = 0; - } else if (optname == MCAST_JOIN_SOURCE_GROUP) { - struct ip_mreqn mreq; - - psin = (struct sockaddr_in *)&greqs.gsr_group; - mreq.imr_multiaddr = psin->sin_addr; - mreq.imr_address.s_addr = 0; - mreq.imr_ifindex = greqs.gsr_interface; - err = ip_mc_join_group(sk, &mreq); - if (err && err != -EADDRINUSE) - break; - greqs.gsr_interface = mreq.imr_ifindex; - omode = MCAST_INCLUDE; - add = 1; - } else /* MCAST_LEAVE_SOURCE_GROUP */ { - omode = MCAST_INCLUDE; - add = 0; - } - err = ip_mc_source(add, omode, sk, &mreqs, - greqs.gsr_interface); - break; - } - case MCAST_MSFILTER: - { - struct sockaddr_in *psin; - struct ip_msfilter *msf = NULL; - struct group_filter *gsf = NULL; - int msize, i, ifindex; - - if (optlen < GROUP_FILTER_SIZE(0)) - goto e_inval; - if (optlen > sysctl_optmem_max) { - err = -ENOBUFS; - break; - } - gsf = kmalloc(optlen, GFP_KERNEL); - if (!gsf) { - err = -ENOBUFS; - break; - } - err = -EFAULT; - if (copy_from_user(gsf, optval, optlen)) - goto mc_msf_out; - - /* numsrc >= (4G-140)/128 overflow in 32 bits */ - if (gsf->gf_numsrc >= 0x1ffffff || - gsf->gf_numsrc > net->ipv4.sysctl_igmp_max_msf) { - err = -ENOBUFS; - goto mc_msf_out; - } - if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) { - err = -EINVAL; - goto mc_msf_out; - } - msize = IP_MSFILTER_SIZE(gsf->gf_numsrc); - msf = kmalloc(msize, GFP_KERNEL); - if (!msf) { - err = -ENOBUFS; - goto mc_msf_out; - } - ifindex = gsf->gf_interface; - psin = (struct sockaddr_in *)&gsf->gf_group; - if (psin->sin_family != AF_INET) { - err = -EADDRNOTAVAIL; - goto mc_msf_out; - } - msf->imsf_multiaddr = psin->sin_addr.s_addr; - msf->imsf_interface = 0; - msf->imsf_fmode = gsf->gf_fmode; - msf->imsf_numsrc = gsf->gf_numsrc; - err = -EADDRNOTAVAIL; - for (i = 0; i < gsf->gf_numsrc; ++i) { - psin = (struct sockaddr_in *)&gsf->gf_slist[i]; - - if (psin->sin_family != AF_INET) - goto mc_msf_out; - msf->imsf_slist[i] = psin->sin_addr.s_addr; - } - kfree(gsf); - gsf = NULL; - - err = ip_mc_msfilter(sk, msf, ifindex); -mc_msf_out: - kfree(msf); - kfree(gsf); - break; - } - case IP_MULTICAST_ALL: - if (optlen < 1) - goto e_inval; - if (val != 0 && val != 1) - goto e_inval; - inet->mc_all = val; - break; - case IP_ROUTER_ALERT: - err = ip_ra_control(sk, val ? 1 : 0, NULL); - break; - - case IP_FREEBIND: - if (optlen < 1) - goto e_inval; - inet->freebind = !!val; - break; - - case IP_IPSEC_POLICY: - case IP_XFRM_POLICY: - err = -EPERM; - if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) - break; - err = xfrm_user_policy(sk, optname, optval, optlen); - break; - - case IP_TRANSPARENT: - if (!!val && !ns_capable(sock_net(sk)->user_ns, CAP_NET_RAW) && - !ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN)) { - err = -EPERM; - break; - } - if (optlen < 1) - goto e_inval; - inet->transparent = !!val; - break; - - case IP_MINTTL: - if (optlen < 1) - goto e_inval; - if (val < 0 || val > 255) - goto e_inval; - inet->min_ttl = val; - break; - - default: - err = -ENOPROTOOPT; - break; - } - release_sock(sk); - if (needs_rtnl) - rtnl_unlock(); - return err; - -e_inval: - release_sock(sk); - if (needs_rtnl) - rtnl_unlock(); - return -EINVAL; -} - -/** - * ipv4_pktinfo_prepare - transfer some info from rtable to skb - * @sk: socket - * @skb: buffer - * - * To support IP_CMSG_PKTINFO option, we store rt_iif and specific - * destination in skb->cb[] before dst drop. - * This way, receiver doesn't make cache line misses to read rtable. - */ -void ipv4_pktinfo_prepare(const struct sock *sk, struct sk_buff *skb) -{ - struct in_pktinfo *pktinfo = PKTINFO_SKB_CB(skb); - bool prepare = (inet_sk(sk)->cmsg_flags & IP_CMSG_PKTINFO) || - ipv6_sk_rxinfo(sk); - - if (prepare && skb_rtable(skb)) { - /* skb->cb is overloaded: prior to this point it is IP{6}CB - * which has interface index (iif) as the first member of the - * underlying inet{6}_skb_parm struct. This code then overlays - * PKTINFO_SKB_CB and in_pktinfo also has iif as the first - * element so the iif is picked up from the prior IPCB - */ - pktinfo->ipi_spec_dst.s_addr = fib_compute_spec_dst(skb); - } else { - pktinfo->ipi_ifindex = 0; - pktinfo->ipi_spec_dst.s_addr = 0; - } - skb_dst_drop(skb); -} - -int ip_setsockopt(struct sock *sk, int level, - int optname, char __user *optval, unsigned int optlen) -{ - int err; - - if (level != SOL_IP) - return -ENOPROTOOPT; - - err = do_ip_setsockopt(sk, level, optname, optval, optlen); -#ifdef CONFIG_NETFILTER - /* we need to exclude all possible ENOPROTOOPTs except default case */ - if (err == -ENOPROTOOPT && optname != IP_HDRINCL && - optname != IP_IPSEC_POLICY && - optname != IP_XFRM_POLICY && - !ip_mroute_opt(optname)) { - lock_sock(sk); - err = nf_setsockopt(sk, PF_INET, optname, optval, optlen); - release_sock(sk); - } -#endif - return err; -} -EXPORT_SYMBOL(ip_setsockopt); - -#ifdef CONFIG_COMPAT -int compat_ip_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen) -{ - int err; - - if (level != SOL_IP) - return -ENOPROTOOPT; - - if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER) - return compat_mc_setsockopt(sk, level, optname, optval, optlen, - ip_setsockopt); - - err = do_ip_setsockopt(sk, level, optname, optval, optlen); -#ifdef CONFIG_NETFILTER - /* we need to exclude all possible ENOPROTOOPTs except default case */ - if (err == -ENOPROTOOPT && optname != IP_HDRINCL && - optname != IP_IPSEC_POLICY && - optname != IP_XFRM_POLICY && - !ip_mroute_opt(optname)) { - lock_sock(sk); - err = compat_nf_setsockopt(sk, PF_INET, optname, - optval, optlen); - release_sock(sk); - } -#endif - return err; -} -EXPORT_SYMBOL(compat_ip_setsockopt); -#endif - -/* - * Get the options. Note for future reference. The GET of IP options gets - * the _received_ ones. The set sets the _sent_ ones. - */ - -static bool getsockopt_needs_rtnl(int optname) -{ - switch (optname) { - case IP_MSFILTER: - case MCAST_MSFILTER: - return true; - } - return false; -} - -static int do_ip_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen, unsigned int flags) -{ - struct inet_sock *inet = inet_sk(sk); - bool needs_rtnl = getsockopt_needs_rtnl(optname); - int val, err = 0; - int len; - - if (level != SOL_IP) - return -EOPNOTSUPP; - - if (ip_mroute_opt(optname)) - return ip_mroute_getsockopt(sk, optname, optval, optlen); - - if (get_user(len, optlen)) - return -EFAULT; - if (len < 0) - return -EINVAL; - - if (needs_rtnl) - rtnl_lock(); - lock_sock(sk); - - switch (optname) { - case IP_OPTIONS: - { - unsigned char optbuf[sizeof(struct ip_options)+40]; - struct ip_options *opt = (struct ip_options *)optbuf; - struct ip_options_rcu *inet_opt; - - inet_opt = rcu_dereference_protected(inet->inet_opt, - lockdep_sock_is_held(sk)); - opt->optlen = 0; - if (inet_opt) - memcpy(optbuf, &inet_opt->opt, - sizeof(struct ip_options) + - inet_opt->opt.optlen); - release_sock(sk); - - if (opt->optlen == 0) - return put_user(0, optlen); - - ip_options_undo(opt); - - len = min_t(unsigned int, len, opt->optlen); - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(optval, opt->__data, len)) - return -EFAULT; - return 0; - } - case IP_PKTINFO: - val = (inet->cmsg_flags & IP_CMSG_PKTINFO) != 0; - break; - case IP_RECVTTL: - val = (inet->cmsg_flags & IP_CMSG_TTL) != 0; - break; - case IP_RECVTOS: - val = (inet->cmsg_flags & IP_CMSG_TOS) != 0; - break; - case IP_RECVOPTS: - val = (inet->cmsg_flags & IP_CMSG_RECVOPTS) != 0; - break; - case IP_RETOPTS: - val = (inet->cmsg_flags & IP_CMSG_RETOPTS) != 0; - break; - case IP_PASSSEC: - val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0; - break; - case IP_RECVORIGDSTADDR: - val = (inet->cmsg_flags & IP_CMSG_ORIGDSTADDR) != 0; - break; - case IP_CHECKSUM: - val = (inet->cmsg_flags & IP_CMSG_CHECKSUM) != 0; - break; - case IP_TOS: - val = inet->tos; - break; - case IP_TTL: - { - struct net *net = sock_net(sk); - val = (inet->uc_ttl == -1 ? - net->ipv4.sysctl_ip_default_ttl : - inet->uc_ttl); - break; - } - case IP_HDRINCL: - val = inet->hdrincl; - break; - case IP_NODEFRAG: - val = inet->nodefrag; - break; - case IP_BIND_ADDRESS_NO_PORT: - val = inet->bind_address_no_port; - break; - case IP_MTU_DISCOVER: - val = inet->pmtudisc; - break; - case IP_MTU: - { - struct dst_entry *dst; - val = 0; - dst = sk_dst_get(sk); - if (dst) { - val = dst_mtu(dst); - dst_release(dst); - } - if (!val) { - release_sock(sk); - return -ENOTCONN; - } - break; - } - case IP_RECVERR: - val = inet->recverr; - break; - case IP_MULTICAST_TTL: - val = inet->mc_ttl; - break; - case IP_MULTICAST_LOOP: - val = inet->mc_loop; - break; - case IP_UNICAST_IF: - val = (__force int)htonl((__u32) inet->uc_index); - break; - case IP_MULTICAST_IF: - { - struct in_addr addr; - len = min_t(unsigned int, len, sizeof(struct in_addr)); - addr.s_addr = inet->mc_addr; - release_sock(sk); - - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(optval, &addr, len)) - return -EFAULT; - return 0; - } - case IP_MSFILTER: - { - struct ip_msfilter msf; - - if (len < IP_MSFILTER_SIZE(0)) { - err = -EINVAL; - goto out; - } - if (copy_from_user(&msf, optval, IP_MSFILTER_SIZE(0))) { - err = -EFAULT; - goto out; - } - err = ip_mc_msfget(sk, &msf, - (struct ip_msfilter __user *)optval, optlen); - goto out; - } - case MCAST_MSFILTER: - { - struct group_filter gsf; - - if (len < GROUP_FILTER_SIZE(0)) { - err = -EINVAL; - goto out; - } - if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0))) { - err = -EFAULT; - goto out; - } - err = ip_mc_gsfget(sk, &gsf, - (struct group_filter __user *)optval, - optlen); - goto out; - } - case IP_MULTICAST_ALL: - val = inet->mc_all; - break; - case IP_PKTOPTIONS: - { - struct msghdr msg; - - release_sock(sk); - - if (sk->sk_type != SOCK_STREAM) - return -ENOPROTOOPT; - - msg.msg_control = (__force void *) optval; - msg.msg_controllen = len; - msg.msg_flags = flags; - - if (inet->cmsg_flags & IP_CMSG_PKTINFO) { - struct in_pktinfo info; - - info.ipi_addr.s_addr = inet->inet_rcv_saddr; - info.ipi_spec_dst.s_addr = inet->inet_rcv_saddr; - info.ipi_ifindex = inet->mc_index; - put_cmsg(&msg, SOL_IP, IP_PKTINFO, sizeof(info), &info); - } - if (inet->cmsg_flags & IP_CMSG_TTL) { - int hlim = inet->mc_ttl; - put_cmsg(&msg, SOL_IP, IP_TTL, sizeof(hlim), &hlim); - } - if (inet->cmsg_flags & IP_CMSG_TOS) { - int tos = inet->rcv_tos; - put_cmsg(&msg, SOL_IP, IP_TOS, sizeof(tos), &tos); - } - len -= msg.msg_controllen; - return put_user(len, optlen); - } - case IP_FREEBIND: - val = inet->freebind; - break; - case IP_TRANSPARENT: - val = inet->transparent; - break; - case IP_MINTTL: - val = inet->min_ttl; - break; - default: - release_sock(sk); - return -ENOPROTOOPT; - } - release_sock(sk); - - if (len < sizeof(int) && len > 0 && val >= 0 && val <= 255) { - unsigned char ucval = (unsigned char)val; - len = 1; - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(optval, &ucval, 1)) - return -EFAULT; - } else { - len = min_t(unsigned int, sizeof(int), len); - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(optval, &val, len)) - return -EFAULT; - } - return 0; - -out: - release_sock(sk); - if (needs_rtnl) - rtnl_unlock(); - return err; -} - -int ip_getsockopt(struct sock *sk, int level, - int optname, char __user *optval, int __user *optlen) -{ - int err; - - err = do_ip_getsockopt(sk, level, optname, optval, optlen, 0); -#ifdef CONFIG_NETFILTER - /* we need to exclude all possible ENOPROTOOPTs except default case */ - if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS && - !ip_mroute_opt(optname)) { - int len; - - if (get_user(len, optlen)) - return -EFAULT; - - lock_sock(sk); - err = nf_getsockopt(sk, PF_INET, optname, optval, - &len); - release_sock(sk); - if (err >= 0) - err = put_user(len, optlen); - return err; - } -#endif - return err; -} -EXPORT_SYMBOL(ip_getsockopt); - -#ifdef CONFIG_COMPAT -int compat_ip_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - int err; - - if (optname == MCAST_MSFILTER) - return compat_mc_getsockopt(sk, level, optname, optval, optlen, - ip_getsockopt); - - err = do_ip_getsockopt(sk, level, optname, optval, optlen, - MSG_CMSG_COMPAT); - -#ifdef CONFIG_NETFILTER - /* we need to exclude all possible ENOPROTOOPTs except default case */ - if (err == -ENOPROTOOPT && optname != IP_PKTOPTIONS && - !ip_mroute_opt(optname)) { - int len; - - if (get_user(len, optlen)) - return -EFAULT; - - lock_sock(sk); - err = compat_nf_getsockopt(sk, PF_INET, optname, optval, &len); - release_sock(sk); - if (err >= 0) - err = put_user(len, optlen); - return err; - } -#endif - return err; -} -EXPORT_SYMBOL(compat_ip_getsockopt); -#endif diff --git a/src/linux/net/ipv4/ip_tunnel.c b/src/linux/net/ipv4/ip_tunnel.c deleted file mode 100644 index 5719d6b..0000000 --- a/src/linux/net/ipv4/ip_tunnel.c +++ /dev/null @@ -1,1202 +0,0 @@ -/* - * Copyright (c) 2013 Nicira, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if IS_ENABLED(CONFIG_IPV6) -#include -#include -#include -#endif - -static unsigned int ip_tunnel_hash(__be32 key, __be32 remote) -{ - return hash_32((__force u32)key ^ (__force u32)remote, - IP_TNL_HASH_BITS); -} - -static bool ip_tunnel_key_match(const struct ip_tunnel_parm *p, - __be16 flags, __be32 key) -{ - if (p->i_flags & TUNNEL_KEY) { - if (flags & TUNNEL_KEY) - return key == p->i_key; - else - /* key expected, none present */ - return false; - } else - return !(flags & TUNNEL_KEY); -} - -/* Fallback tunnel: no source, no destination, no key, no options - - Tunnel hash table: - We require exact key match i.e. if a key is present in packet - it will match only tunnel with the same key; if it is not present, - it will match only keyless tunnel. - - All keysless packets, if not matched configured keyless tunnels - will match fallback tunnel. - Given src, dst and key, find appropriate for input tunnel. -*/ -struct ip_tunnel *ip_tunnel_lookup(struct ip_tunnel_net *itn, - int link, __be16 flags, - __be32 remote, __be32 local, - __be32 key) -{ - unsigned int hash; - struct ip_tunnel *t, *cand = NULL; - struct hlist_head *head; - - hash = ip_tunnel_hash(key, remote); - head = &itn->tunnels[hash]; - - hlist_for_each_entry_rcu(t, head, hash_node) { - if (local != t->parms.iph.saddr || - remote != t->parms.iph.daddr || - !(t->dev->flags & IFF_UP)) - continue; - - if (!ip_tunnel_key_match(&t->parms, flags, key)) - continue; - - if (t->parms.link == link) - return t; - else - cand = t; - } - - hlist_for_each_entry_rcu(t, head, hash_node) { - if (remote != t->parms.iph.daddr || - t->parms.iph.saddr != 0 || - !(t->dev->flags & IFF_UP)) - continue; - - if (!ip_tunnel_key_match(&t->parms, flags, key)) - continue; - - if (t->parms.link == link) - return t; - else if (!cand) - cand = t; - } - - hash = ip_tunnel_hash(key, 0); - head = &itn->tunnels[hash]; - - hlist_for_each_entry_rcu(t, head, hash_node) { - if ((local != t->parms.iph.saddr || t->parms.iph.daddr != 0) && - (local != t->parms.iph.daddr || !ipv4_is_multicast(local))) - continue; - - if (!(t->dev->flags & IFF_UP)) - continue; - - if (!ip_tunnel_key_match(&t->parms, flags, key)) - continue; - - if (t->parms.link == link) - return t; - else if (!cand) - cand = t; - } - - if (flags & TUNNEL_NO_KEY) - goto skip_key_lookup; - - hlist_for_each_entry_rcu(t, head, hash_node) { - if (t->parms.i_key != key || - t->parms.iph.saddr != 0 || - t->parms.iph.daddr != 0 || - !(t->dev->flags & IFF_UP)) - continue; - - if (t->parms.link == link) - return t; - else if (!cand) - cand = t; - } - -skip_key_lookup: - if (cand) - return cand; - - t = rcu_dereference(itn->collect_md_tun); - if (t) - return t; - - if (itn->fb_tunnel_dev && itn->fb_tunnel_dev->flags & IFF_UP) - return netdev_priv(itn->fb_tunnel_dev); - - return NULL; -} -EXPORT_SYMBOL_GPL(ip_tunnel_lookup); - -static struct hlist_head *ip_bucket(struct ip_tunnel_net *itn, - struct ip_tunnel_parm *parms) -{ - unsigned int h; - __be32 remote; - __be32 i_key = parms->i_key; - - if (parms->iph.daddr && !ipv4_is_multicast(parms->iph.daddr)) - remote = parms->iph.daddr; - else - remote = 0; - - if (!(parms->i_flags & TUNNEL_KEY) && (parms->i_flags & VTI_ISVTI)) - i_key = 0; - - h = ip_tunnel_hash(i_key, remote); - return &itn->tunnels[h]; -} - -static void ip_tunnel_add(struct ip_tunnel_net *itn, struct ip_tunnel *t) -{ - struct hlist_head *head = ip_bucket(itn, &t->parms); - - if (t->collect_md) - rcu_assign_pointer(itn->collect_md_tun, t); - hlist_add_head_rcu(&t->hash_node, head); -} - -static void ip_tunnel_del(struct ip_tunnel_net *itn, struct ip_tunnel *t) -{ - if (t->collect_md) - rcu_assign_pointer(itn->collect_md_tun, NULL); - hlist_del_init_rcu(&t->hash_node); -} - -static struct ip_tunnel *ip_tunnel_find(struct ip_tunnel_net *itn, - struct ip_tunnel_parm *parms, - int type) -{ - __be32 remote = parms->iph.daddr; - __be32 local = parms->iph.saddr; - __be32 key = parms->i_key; - __be16 flags = parms->i_flags; - int link = parms->link; - struct ip_tunnel *t = NULL; - struct hlist_head *head = ip_bucket(itn, parms); - - hlist_for_each_entry_rcu(t, head, hash_node) { - if (local == t->parms.iph.saddr && - remote == t->parms.iph.daddr && - link == t->parms.link && - type == t->dev->type && - ip_tunnel_key_match(&t->parms, flags, key)) - break; - } - return t; -} - -static struct net_device *__ip_tunnel_create(struct net *net, - const struct rtnl_link_ops *ops, - struct ip_tunnel_parm *parms) -{ - int err; - struct ip_tunnel *tunnel; - struct net_device *dev; - char name[IFNAMSIZ]; - - if (parms->name[0]) - strlcpy(name, parms->name, IFNAMSIZ); - else { - if (strlen(ops->kind) > (IFNAMSIZ - 3)) { - err = -E2BIG; - goto failed; - } - strlcpy(name, ops->kind, IFNAMSIZ); - strncat(name, "%d", 2); - } - - ASSERT_RTNL(); - dev = alloc_netdev(ops->priv_size, name, NET_NAME_UNKNOWN, ops->setup); - if (!dev) { - err = -ENOMEM; - goto failed; - } - dev_net_set(dev, net); - - dev->rtnl_link_ops = ops; - - tunnel = netdev_priv(dev); - tunnel->parms = *parms; - tunnel->net = net; - - err = register_netdevice(dev); - if (err) - goto failed_free; - - return dev; - -failed_free: - free_netdev(dev); -failed: - return ERR_PTR(err); -} - -static inline void init_tunnel_flow(struct flowi4 *fl4, - int proto, - __be32 daddr, __be32 saddr, - __be32 key, __u8 tos, int oif) -{ - memset(fl4, 0, sizeof(*fl4)); - fl4->flowi4_oif = oif; - fl4->daddr = daddr; - fl4->saddr = saddr; - fl4->flowi4_tos = tos; - fl4->flowi4_proto = proto; - fl4->fl4_gre_key = key; -} - -static int ip_tunnel_bind_dev(struct net_device *dev) -{ - struct net_device *tdev = NULL; - struct ip_tunnel *tunnel = netdev_priv(dev); - const struct iphdr *iph; - int hlen = LL_MAX_HEADER; - int mtu = ETH_DATA_LEN; - int t_hlen = tunnel->hlen + sizeof(struct iphdr); - - iph = &tunnel->parms.iph; - - /* Guess output device to choose reasonable mtu and needed_headroom */ - if (iph->daddr) { - struct flowi4 fl4; - struct rtable *rt; - - init_tunnel_flow(&fl4, iph->protocol, iph->daddr, - iph->saddr, tunnel->parms.o_key, - RT_TOS(iph->tos), tunnel->parms.link); - rt = ip_route_output_key(tunnel->net, &fl4); - - if (!IS_ERR(rt)) { - tdev = rt->dst.dev; - ip_rt_put(rt); - } - if (dev->type != ARPHRD_ETHER) - dev->flags |= IFF_POINTOPOINT; - - dst_cache_reset(&tunnel->dst_cache); - } - - if (!tdev && tunnel->parms.link) - tdev = __dev_get_by_index(tunnel->net, tunnel->parms.link); - - if (tdev) { - hlen = tdev->hard_header_len + tdev->needed_headroom; - mtu = tdev->mtu; - } - - dev->needed_headroom = t_hlen + hlen; - mtu -= (dev->hard_header_len + t_hlen); - - if (mtu < 68) - mtu = 68; - - return mtu; -} - -static struct ip_tunnel *ip_tunnel_create(struct net *net, - struct ip_tunnel_net *itn, - struct ip_tunnel_parm *parms) -{ - struct ip_tunnel *nt; - struct net_device *dev; - - BUG_ON(!itn->fb_tunnel_dev); - dev = __ip_tunnel_create(net, itn->fb_tunnel_dev->rtnl_link_ops, parms); - if (IS_ERR(dev)) - return ERR_CAST(dev); - - dev->mtu = ip_tunnel_bind_dev(dev); - - nt = netdev_priv(dev); - ip_tunnel_add(itn, nt); - return nt; -} - -int ip_tunnel_rcv(struct ip_tunnel *tunnel, struct sk_buff *skb, - const struct tnl_ptk_info *tpi, struct metadata_dst *tun_dst, - bool log_ecn_error) -{ - struct pcpu_sw_netstats *tstats; - const struct iphdr *iph = ip_hdr(skb); - int err; - -#ifdef CONFIG_NET_IPGRE_BROADCAST - if (ipv4_is_multicast(iph->daddr)) { - tunnel->dev->stats.multicast++; - skb->pkt_type = PACKET_BROADCAST; - } -#endif - - if ((!(tpi->flags&TUNNEL_CSUM) && (tunnel->parms.i_flags&TUNNEL_CSUM)) || - ((tpi->flags&TUNNEL_CSUM) && !(tunnel->parms.i_flags&TUNNEL_CSUM))) { - tunnel->dev->stats.rx_crc_errors++; - tunnel->dev->stats.rx_errors++; - goto drop; - } - - if (tunnel->parms.i_flags&TUNNEL_SEQ) { - if (!(tpi->flags&TUNNEL_SEQ) || - (tunnel->i_seqno && (s32)(ntohl(tpi->seq) - tunnel->i_seqno) < 0)) { - tunnel->dev->stats.rx_fifo_errors++; - tunnel->dev->stats.rx_errors++; - goto drop; - } - tunnel->i_seqno = ntohl(tpi->seq) + 1; - } - - skb_reset_network_header(skb); - - err = IP_ECN_decapsulate(iph, skb); - if (unlikely(err)) { - if (log_ecn_error) - net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n", - &iph->saddr, iph->tos); - if (err > 1) { - ++tunnel->dev->stats.rx_frame_errors; - ++tunnel->dev->stats.rx_errors; - goto drop; - } - } - - tstats = this_cpu_ptr(tunnel->dev->tstats); - u64_stats_update_begin(&tstats->syncp); - tstats->rx_packets++; - tstats->rx_bytes += skb->len; - u64_stats_update_end(&tstats->syncp); - - skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(tunnel->dev))); - - if (tunnel->dev->type == ARPHRD_ETHER) { - skb->protocol = eth_type_trans(skb, tunnel->dev); - skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); - } else { - skb->dev = tunnel->dev; - } - - if (tun_dst) - skb_dst_set(skb, (struct dst_entry *)tun_dst); - - gro_cells_receive(&tunnel->gro_cells, skb); - return 0; - -drop: - kfree_skb(skb); - return 0; -} -EXPORT_SYMBOL_GPL(ip_tunnel_rcv); - -int ip_tunnel_encap_add_ops(const struct ip_tunnel_encap_ops *ops, - unsigned int num) -{ - if (num >= MAX_IPTUN_ENCAP_OPS) - return -ERANGE; - - return !cmpxchg((const struct ip_tunnel_encap_ops **) - &iptun_encaps[num], - NULL, ops) ? 0 : -1; -} -EXPORT_SYMBOL(ip_tunnel_encap_add_ops); - -int ip_tunnel_encap_del_ops(const struct ip_tunnel_encap_ops *ops, - unsigned int num) -{ - int ret; - - if (num >= MAX_IPTUN_ENCAP_OPS) - return -ERANGE; - - ret = (cmpxchg((const struct ip_tunnel_encap_ops **) - &iptun_encaps[num], - ops, NULL) == ops) ? 0 : -1; - - synchronize_net(); - - return ret; -} -EXPORT_SYMBOL(ip_tunnel_encap_del_ops); - -int ip_tunnel_encap_setup(struct ip_tunnel *t, - struct ip_tunnel_encap *ipencap) -{ - int hlen; - - memset(&t->encap, 0, sizeof(t->encap)); - - hlen = ip_encap_hlen(ipencap); - if (hlen < 0) - return hlen; - - t->encap.type = ipencap->type; - t->encap.sport = ipencap->sport; - t->encap.dport = ipencap->dport; - t->encap.flags = ipencap->flags; - - t->encap_hlen = hlen; - t->hlen = t->encap_hlen + t->tun_hlen; - - return 0; -} -EXPORT_SYMBOL_GPL(ip_tunnel_encap_setup); - -static int tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb, - struct rtable *rt, __be16 df, - const struct iphdr *inner_iph) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - int pkt_size = skb->len - tunnel->hlen - dev->hard_header_len; - int mtu; - - if (df) - mtu = dst_mtu(&rt->dst) - dev->hard_header_len - - sizeof(struct iphdr) - tunnel->hlen; - else - mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; - - if (skb_dst(skb)) - skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); - - if (skb->protocol == htons(ETH_P_IP)) { - if (!skb_is_gso(skb) && - (inner_iph->frag_off & htons(IP_DF)) && - mtu < pkt_size) { - memset(IPCB(skb), 0, sizeof(*IPCB(skb))); - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); - return -E2BIG; - } - } -#if IS_ENABLED(CONFIG_IPV6) - else if (skb->protocol == htons(ETH_P_IPV6)) { - struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb); - - if (rt6 && mtu < dst_mtu(skb_dst(skb)) && - mtu >= IPV6_MIN_MTU) { - if ((tunnel->parms.iph.daddr && - !ipv4_is_multicast(tunnel->parms.iph.daddr)) || - rt6->rt6i_dst.plen == 128) { - rt6->rt6i_flags |= RTF_MODIFIED; - dst_metric_set(skb_dst(skb), RTAX_MTU, mtu); - } - } - - if (!skb_is_gso(skb) && mtu >= IPV6_MIN_MTU && - mtu < pkt_size) { - icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); - return -E2BIG; - } - } -#endif - return 0; -} - -void ip_md_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, u8 proto) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - u32 headroom = sizeof(struct iphdr); - struct ip_tunnel_info *tun_info; - const struct ip_tunnel_key *key; - const struct iphdr *inner_iph; - struct rtable *rt; - struct flowi4 fl4; - __be16 df = 0; - u8 tos, ttl; - - tun_info = skb_tunnel_info(skb); - if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) || - ip_tunnel_info_af(tun_info) != AF_INET)) - goto tx_error; - key = &tun_info->key; - memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); - inner_iph = (const struct iphdr *)skb_inner_network_header(skb); - tos = key->tos; - if (tos == 1) { - if (skb->protocol == htons(ETH_P_IP)) - tos = inner_iph->tos; - else if (skb->protocol == htons(ETH_P_IPV6)) - tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph); - } - init_tunnel_flow(&fl4, proto, key->u.ipv4.dst, key->u.ipv4.src, 0, - RT_TOS(tos), tunnel->parms.link); - if (tunnel->encap.type != TUNNEL_ENCAP_NONE) - goto tx_error; - rt = ip_route_output_key(tunnel->net, &fl4); - if (IS_ERR(rt)) { - dev->stats.tx_carrier_errors++; - goto tx_error; - } - if (rt->dst.dev == dev) { - ip_rt_put(rt); - dev->stats.collisions++; - goto tx_error; - } - tos = ip_tunnel_ecn_encap(tos, inner_iph, skb); - ttl = key->ttl; - if (ttl == 0) { - if (skb->protocol == htons(ETH_P_IP)) - ttl = inner_iph->ttl; - else if (skb->protocol == htons(ETH_P_IPV6)) - ttl = ((const struct ipv6hdr *)inner_iph)->hop_limit; - else - ttl = ip4_dst_hoplimit(&rt->dst); - } - if (key->tun_flags & TUNNEL_DONT_FRAGMENT) - df = htons(IP_DF); - else if (skb->protocol == htons(ETH_P_IP)) - df = inner_iph->frag_off & htons(IP_DF); - headroom += LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len; - if (headroom > dev->needed_headroom) - dev->needed_headroom = headroom; - - if (skb_cow_head(skb, dev->needed_headroom)) { - ip_rt_put(rt); - goto tx_dropped; - } - iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, proto, key->tos, - key->ttl, df, !net_eq(tunnel->net, dev_net(dev))); - return; -tx_error: - dev->stats.tx_errors++; - goto kfree; -tx_dropped: - dev->stats.tx_dropped++; -kfree: - kfree_skb(skb); -} -EXPORT_SYMBOL_GPL(ip_md_tunnel_xmit); - -void ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, - const struct iphdr *tnl_params, u8 protocol) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - const struct iphdr *inner_iph; - struct flowi4 fl4; - u8 tos, ttl; - __be16 df; - struct rtable *rt; /* Route to the other host */ - unsigned int max_headroom; /* The extra header space needed */ - __be32 dst; - bool connected; - - inner_iph = (const struct iphdr *)skb_inner_network_header(skb); - connected = (tunnel->parms.iph.daddr != 0); - - memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); - - dst = tnl_params->daddr; - if (dst == 0) { - /* NBMA tunnel */ - - if (!skb_dst(skb)) { - dev->stats.tx_fifo_errors++; - goto tx_error; - } - - if (skb->protocol == htons(ETH_P_IP)) { - rt = skb_rtable(skb); - dst = rt_nexthop(rt, inner_iph->daddr); - } -#if IS_ENABLED(CONFIG_IPV6) - else if (skb->protocol == htons(ETH_P_IPV6)) { - const struct in6_addr *addr6; - struct neighbour *neigh; - bool do_tx_error_icmp; - int addr_type; - - neigh = dst_neigh_lookup(skb_dst(skb), - &ipv6_hdr(skb)->daddr); - if (!neigh) - goto tx_error; - - addr6 = (const struct in6_addr *)&neigh->primary_key; - addr_type = ipv6_addr_type(addr6); - - if (addr_type == IPV6_ADDR_ANY) { - addr6 = &ipv6_hdr(skb)->daddr; - addr_type = ipv6_addr_type(addr6); - } - - if ((addr_type & IPV6_ADDR_COMPATv4) == 0) - do_tx_error_icmp = true; - else { - do_tx_error_icmp = false; - dst = addr6->s6_addr32[3]; - } - neigh_release(neigh); - if (do_tx_error_icmp) - goto tx_error_icmp; - } -#endif - else - goto tx_error; - - connected = false; - } - - tos = tnl_params->tos; - if (tos & 0x1) { - tos &= ~0x1; - if (skb->protocol == htons(ETH_P_IP)) { - tos = inner_iph->tos; - connected = false; - } else if (skb->protocol == htons(ETH_P_IPV6)) { - tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph); - connected = false; - } - } - - init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, - tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link); - - if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0) - goto tx_error; - - rt = connected ? dst_cache_get_ip4(&tunnel->dst_cache, &fl4.saddr) : - NULL; - - if (!rt) { - rt = ip_route_output_key(tunnel->net, &fl4); - - if (IS_ERR(rt)) { - dev->stats.tx_carrier_errors++; - goto tx_error; - } - if (connected) - dst_cache_set_ip4(&tunnel->dst_cache, &rt->dst, - fl4.saddr); - } - - if (rt->dst.dev == dev) { - ip_rt_put(rt); - dev->stats.collisions++; - goto tx_error; - } - - if (tnl_update_pmtu(dev, skb, rt, tnl_params->frag_off, inner_iph)) { - ip_rt_put(rt); - goto tx_error; - } - - if (tunnel->err_count > 0) { - if (time_before(jiffies, - tunnel->err_time + IPTUNNEL_ERR_TIMEO)) { - tunnel->err_count--; - - dst_link_failure(skb); - } else - tunnel->err_count = 0; - } - - tos = ip_tunnel_ecn_encap(tos, inner_iph, skb); - ttl = tnl_params->ttl; - if (ttl == 0) { - if (skb->protocol == htons(ETH_P_IP)) - ttl = inner_iph->ttl; -#if IS_ENABLED(CONFIG_IPV6) - else if (skb->protocol == htons(ETH_P_IPV6)) - ttl = ((const struct ipv6hdr *)inner_iph)->hop_limit; -#endif - else - ttl = ip4_dst_hoplimit(&rt->dst); - } - - df = tnl_params->frag_off; - if (skb->protocol == htons(ETH_P_IP) && !tunnel->ignore_df) - df |= (inner_iph->frag_off&htons(IP_DF)); - - max_headroom = LL_RESERVED_SPACE(rt->dst.dev) + sizeof(struct iphdr) - + rt->dst.header_len + ip_encap_hlen(&tunnel->encap); - if (max_headroom > dev->needed_headroom) - dev->needed_headroom = max_headroom; - - if (skb_cow_head(skb, dev->needed_headroom)) { - ip_rt_put(rt); - dev->stats.tx_dropped++; - kfree_skb(skb); - return; - } - - iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, protocol, tos, ttl, - df, !net_eq(tunnel->net, dev_net(dev))); - return; - -#if IS_ENABLED(CONFIG_IPV6) -tx_error_icmp: - dst_link_failure(skb); -#endif -tx_error: - dev->stats.tx_errors++; - kfree_skb(skb); -} -EXPORT_SYMBOL_GPL(ip_tunnel_xmit); - -static void ip_tunnel_update(struct ip_tunnel_net *itn, - struct ip_tunnel *t, - struct net_device *dev, - struct ip_tunnel_parm *p, - bool set_mtu) -{ - ip_tunnel_del(itn, t); - t->parms.iph.saddr = p->iph.saddr; - t->parms.iph.daddr = p->iph.daddr; - t->parms.i_key = p->i_key; - t->parms.o_key = p->o_key; - if (dev->type != ARPHRD_ETHER) { - memcpy(dev->dev_addr, &p->iph.saddr, 4); - memcpy(dev->broadcast, &p->iph.daddr, 4); - } - ip_tunnel_add(itn, t); - - t->parms.iph.ttl = p->iph.ttl; - t->parms.iph.tos = p->iph.tos; - t->parms.iph.frag_off = p->iph.frag_off; - - if (t->parms.link != p->link) { - int mtu; - - t->parms.link = p->link; - mtu = ip_tunnel_bind_dev(dev); - if (set_mtu) - dev->mtu = mtu; - } - dst_cache_reset(&t->dst_cache); - netdev_state_change(dev); -} - -int ip_tunnel_ioctl(struct net_device *dev, struct ip_tunnel_parm *p, int cmd) -{ - int err = 0; - struct ip_tunnel *t = netdev_priv(dev); - struct net *net = t->net; - struct ip_tunnel_net *itn = net_generic(net, t->ip_tnl_net_id); - - BUG_ON(!itn->fb_tunnel_dev); - switch (cmd) { - case SIOCGETTUNNEL: - if (dev == itn->fb_tunnel_dev) { - t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type); - if (!t) - t = netdev_priv(dev); - } - memcpy(p, &t->parms, sizeof(*p)); - break; - - case SIOCADDTUNNEL: - case SIOCCHGTUNNEL: - err = -EPERM; - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - goto done; - if (p->iph.ttl) - p->iph.frag_off |= htons(IP_DF); - if (!(p->i_flags & VTI_ISVTI)) { - if (!(p->i_flags & TUNNEL_KEY)) - p->i_key = 0; - if (!(p->o_flags & TUNNEL_KEY)) - p->o_key = 0; - } - - t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type); - - if (cmd == SIOCADDTUNNEL) { - if (!t) { - t = ip_tunnel_create(net, itn, p); - err = PTR_ERR_OR_ZERO(t); - break; - } - - err = -EEXIST; - break; - } - if (dev != itn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { - if (t) { - if (t->dev != dev) { - err = -EEXIST; - break; - } - } else { - unsigned int nflags = 0; - - if (ipv4_is_multicast(p->iph.daddr)) - nflags = IFF_BROADCAST; - else if (p->iph.daddr) - nflags = IFF_POINTOPOINT; - - if ((dev->flags^nflags)&(IFF_POINTOPOINT|IFF_BROADCAST)) { - err = -EINVAL; - break; - } - - t = netdev_priv(dev); - } - } - - if (t) { - err = 0; - ip_tunnel_update(itn, t, dev, p, true); - } else { - err = -ENOENT; - } - break; - - case SIOCDELTUNNEL: - err = -EPERM; - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - goto done; - - if (dev == itn->fb_tunnel_dev) { - err = -ENOENT; - t = ip_tunnel_find(itn, p, itn->fb_tunnel_dev->type); - if (!t) - goto done; - err = -EPERM; - if (t == netdev_priv(itn->fb_tunnel_dev)) - goto done; - dev = t->dev; - } - unregister_netdevice(dev); - err = 0; - break; - - default: - err = -EINVAL; - } - -done: - return err; -} -EXPORT_SYMBOL_GPL(ip_tunnel_ioctl); - -int __ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - int t_hlen = tunnel->hlen + sizeof(struct iphdr); - int max_mtu = 0xFFF8 - dev->hard_header_len - t_hlen; - - if (new_mtu < 68) - return -EINVAL; - - if (new_mtu > max_mtu) { - if (strict) - return -EINVAL; - - new_mtu = max_mtu; - } - - dev->mtu = new_mtu; - return 0; -} -EXPORT_SYMBOL_GPL(__ip_tunnel_change_mtu); - -int ip_tunnel_change_mtu(struct net_device *dev, int new_mtu) -{ - return __ip_tunnel_change_mtu(dev, new_mtu, true); -} -EXPORT_SYMBOL_GPL(ip_tunnel_change_mtu); - -static void ip_tunnel_dev_free(struct net_device *dev) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - - gro_cells_destroy(&tunnel->gro_cells); - dst_cache_destroy(&tunnel->dst_cache); - free_percpu(dev->tstats); - free_netdev(dev); -} - -void ip_tunnel_dellink(struct net_device *dev, struct list_head *head) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - struct ip_tunnel_net *itn; - - itn = net_generic(tunnel->net, tunnel->ip_tnl_net_id); - - if (itn->fb_tunnel_dev != dev) { - ip_tunnel_del(itn, netdev_priv(dev)); - unregister_netdevice_queue(dev, head); - } -} -EXPORT_SYMBOL_GPL(ip_tunnel_dellink); - -struct net *ip_tunnel_get_link_net(const struct net_device *dev) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - - return tunnel->net; -} -EXPORT_SYMBOL(ip_tunnel_get_link_net); - -int ip_tunnel_get_iflink(const struct net_device *dev) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - - return tunnel->parms.link; -} -EXPORT_SYMBOL(ip_tunnel_get_iflink); - -int ip_tunnel_init_net(struct net *net, int ip_tnl_net_id, - struct rtnl_link_ops *ops, char *devname) -{ - struct ip_tunnel_net *itn = net_generic(net, ip_tnl_net_id); - struct ip_tunnel_parm parms; - unsigned int i; - - for (i = 0; i < IP_TNL_HASH_SIZE; i++) - INIT_HLIST_HEAD(&itn->tunnels[i]); - - if (!ops) { - itn->fb_tunnel_dev = NULL; - return 0; - } - - memset(&parms, 0, sizeof(parms)); - if (devname) - strlcpy(parms.name, devname, IFNAMSIZ); - - rtnl_lock(); - itn->fb_tunnel_dev = __ip_tunnel_create(net, ops, &parms); - /* FB netdevice is special: we have one, and only one per netns. - * Allowing to move it to another netns is clearly unsafe. - */ - if (!IS_ERR(itn->fb_tunnel_dev)) { - itn->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL; - itn->fb_tunnel_dev->mtu = ip_tunnel_bind_dev(itn->fb_tunnel_dev); - ip_tunnel_add(itn, netdev_priv(itn->fb_tunnel_dev)); - } - rtnl_unlock(); - - return PTR_ERR_OR_ZERO(itn->fb_tunnel_dev); -} -EXPORT_SYMBOL_GPL(ip_tunnel_init_net); - -static void ip_tunnel_destroy(struct ip_tunnel_net *itn, struct list_head *head, - struct rtnl_link_ops *ops) -{ - struct net *net = dev_net(itn->fb_tunnel_dev); - struct net_device *dev, *aux; - int h; - - for_each_netdev_safe(net, dev, aux) - if (dev->rtnl_link_ops == ops) - unregister_netdevice_queue(dev, head); - - for (h = 0; h < IP_TNL_HASH_SIZE; h++) { - struct ip_tunnel *t; - struct hlist_node *n; - struct hlist_head *thead = &itn->tunnels[h]; - - hlist_for_each_entry_safe(t, n, thead, hash_node) - /* If dev is in the same netns, it has already - * been added to the list by the previous loop. - */ - if (!net_eq(dev_net(t->dev), net)) - unregister_netdevice_queue(t->dev, head); - } -} - -void ip_tunnel_delete_net(struct ip_tunnel_net *itn, struct rtnl_link_ops *ops) -{ - LIST_HEAD(list); - - rtnl_lock(); - ip_tunnel_destroy(itn, &list, ops); - unregister_netdevice_many(&list); - rtnl_unlock(); -} -EXPORT_SYMBOL_GPL(ip_tunnel_delete_net); - -int ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[], - struct ip_tunnel_parm *p) -{ - struct ip_tunnel *nt; - struct net *net = dev_net(dev); - struct ip_tunnel_net *itn; - int mtu; - int err; - - nt = netdev_priv(dev); - itn = net_generic(net, nt->ip_tnl_net_id); - - if (nt->collect_md) { - if (rtnl_dereference(itn->collect_md_tun)) - return -EEXIST; - } else { - if (ip_tunnel_find(itn, p, dev->type)) - return -EEXIST; - } - - nt->net = net; - nt->parms = *p; - err = register_netdevice(dev); - if (err) - goto out; - - if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS]) - eth_hw_addr_random(dev); - - mtu = ip_tunnel_bind_dev(dev); - if (!tb[IFLA_MTU]) - dev->mtu = mtu; - - ip_tunnel_add(itn, nt); -out: - return err; -} -EXPORT_SYMBOL_GPL(ip_tunnel_newlink); - -int ip_tunnel_changelink(struct net_device *dev, struct nlattr *tb[], - struct ip_tunnel_parm *p) -{ - struct ip_tunnel *t; - struct ip_tunnel *tunnel = netdev_priv(dev); - struct net *net = tunnel->net; - struct ip_tunnel_net *itn = net_generic(net, tunnel->ip_tnl_net_id); - - if (dev == itn->fb_tunnel_dev) - return -EINVAL; - - t = ip_tunnel_find(itn, p, dev->type); - - if (t) { - if (t->dev != dev) - return -EEXIST; - } else { - t = tunnel; - - if (dev->type != ARPHRD_ETHER) { - unsigned int nflags = 0; - - if (ipv4_is_multicast(p->iph.daddr)) - nflags = IFF_BROADCAST; - else if (p->iph.daddr) - nflags = IFF_POINTOPOINT; - - if ((dev->flags ^ nflags) & - (IFF_POINTOPOINT | IFF_BROADCAST)) - return -EINVAL; - } - } - - ip_tunnel_update(itn, t, dev, p, !tb[IFLA_MTU]); - return 0; -} -EXPORT_SYMBOL_GPL(ip_tunnel_changelink); - -int ip_tunnel_init(struct net_device *dev) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - struct iphdr *iph = &tunnel->parms.iph; - int err; - - dev->destructor = ip_tunnel_dev_free; - dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); - if (!dev->tstats) - return -ENOMEM; - - err = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL); - if (err) { - free_percpu(dev->tstats); - return err; - } - - err = gro_cells_init(&tunnel->gro_cells, dev); - if (err) { - dst_cache_destroy(&tunnel->dst_cache); - free_percpu(dev->tstats); - return err; - } - - tunnel->dev = dev; - tunnel->net = dev_net(dev); - strcpy(tunnel->parms.name, dev->name); - iph->version = 4; - iph->ihl = 5; - - if (tunnel->collect_md) { - dev->features |= NETIF_F_NETNS_LOCAL; - netif_keep_dst(dev); - } - return 0; -} -EXPORT_SYMBOL_GPL(ip_tunnel_init); - -void ip_tunnel_uninit(struct net_device *dev) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - struct net *net = tunnel->net; - struct ip_tunnel_net *itn; - - itn = net_generic(net, tunnel->ip_tnl_net_id); - /* fb_tunnel_dev will be unregisted in net-exit call. */ - if (itn->fb_tunnel_dev != dev) - ip_tunnel_del(itn, netdev_priv(dev)); - - dst_cache_reset(&tunnel->dst_cache); -} -EXPORT_SYMBOL_GPL(ip_tunnel_uninit); - -/* Do least required initialization, rest of init is done in tunnel_init call */ -void ip_tunnel_setup(struct net_device *dev, int net_id) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - tunnel->ip_tnl_net_id = net_id; -} -EXPORT_SYMBOL_GPL(ip_tunnel_setup); - -MODULE_LICENSE("GPL"); diff --git a/src/linux/net/ipv4/ip_tunnel_core.c b/src/linux/net/ipv4/ip_tunnel_core.c deleted file mode 100644 index fed3d29..0000000 --- a/src/linux/net/ipv4/ip_tunnel_core.c +++ /dev/null @@ -1,433 +0,0 @@ -/* - * Copyright (c) 2013 Nicira, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#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 - -const struct ip_tunnel_encap_ops __rcu * - iptun_encaps[MAX_IPTUN_ENCAP_OPS] __read_mostly; -EXPORT_SYMBOL(iptun_encaps); - -const struct ip6_tnl_encap_ops __rcu * - ip6tun_encaps[MAX_IPTUN_ENCAP_OPS] __read_mostly; -EXPORT_SYMBOL(ip6tun_encaps); - -void iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb, - __be32 src, __be32 dst, __u8 proto, - __u8 tos, __u8 ttl, __be16 df, bool xnet) -{ - int pkt_len = skb->len - skb_inner_network_offset(skb); - struct net *net = dev_net(rt->dst.dev); - struct net_device *dev = skb->dev; - struct iphdr *iph; - int err; - - skb_scrub_packet(skb, xnet); - - skb_clear_hash_if_not_l4(skb); - skb_dst_set(skb, &rt->dst); - memset(IPCB(skb), 0, sizeof(*IPCB(skb))); - - /* Push down and install the IP header. */ - skb_push(skb, sizeof(struct iphdr)); - skb_reset_network_header(skb); - - iph = ip_hdr(skb); - - iph->version = 4; - iph->ihl = sizeof(struct iphdr) >> 2; - iph->frag_off = df; - iph->protocol = proto; - iph->tos = tos; - iph->daddr = dst; - iph->saddr = src; - iph->ttl = ttl; - __ip_select_ident(net, iph, skb_shinfo(skb)->gso_segs ?: 1); - - err = ip_local_out(net, sk, skb); - if (unlikely(net_xmit_eval(err))) - pkt_len = 0; - iptunnel_xmit_stats(dev, pkt_len); -} -EXPORT_SYMBOL_GPL(iptunnel_xmit); - -int __iptunnel_pull_header(struct sk_buff *skb, int hdr_len, - __be16 inner_proto, bool raw_proto, bool xnet) -{ - if (unlikely(!pskb_may_pull(skb, hdr_len))) - return -ENOMEM; - - skb_pull_rcsum(skb, hdr_len); - - if (!raw_proto && inner_proto == htons(ETH_P_TEB)) { - struct ethhdr *eh; - - if (unlikely(!pskb_may_pull(skb, ETH_HLEN))) - return -ENOMEM; - - eh = (struct ethhdr *)skb->data; - if (likely(eth_proto_is_802_3(eh->h_proto))) - skb->protocol = eh->h_proto; - else - skb->protocol = htons(ETH_P_802_2); - - } else { - skb->protocol = inner_proto; - } - - skb_clear_hash_if_not_l4(skb); - skb->vlan_tci = 0; - skb_set_queue_mapping(skb, 0); - skb_scrub_packet(skb, xnet); - - return iptunnel_pull_offloads(skb); -} -EXPORT_SYMBOL_GPL(__iptunnel_pull_header); - -struct metadata_dst *iptunnel_metadata_reply(struct metadata_dst *md, - gfp_t flags) -{ - struct metadata_dst *res; - struct ip_tunnel_info *dst, *src; - - if (!md || md->u.tun_info.mode & IP_TUNNEL_INFO_TX) - return NULL; - - res = metadata_dst_alloc(0, flags); - if (!res) - return NULL; - - dst = &res->u.tun_info; - src = &md->u.tun_info; - dst->key.tun_id = src->key.tun_id; - if (src->mode & IP_TUNNEL_INFO_IPV6) - memcpy(&dst->key.u.ipv6.dst, &src->key.u.ipv6.src, - sizeof(struct in6_addr)); - else - dst->key.u.ipv4.dst = src->key.u.ipv4.src; - dst->mode = src->mode | IP_TUNNEL_INFO_TX; - - return res; -} -EXPORT_SYMBOL_GPL(iptunnel_metadata_reply); - -int iptunnel_handle_offloads(struct sk_buff *skb, - int gso_type_mask) -{ - int err; - - if (likely(!skb->encapsulation)) { - skb_reset_inner_headers(skb); - skb->encapsulation = 1; - } - - if (skb_is_gso(skb)) { - err = skb_header_unclone(skb, GFP_ATOMIC); - if (unlikely(err)) - return err; - skb_shinfo(skb)->gso_type |= gso_type_mask; - return 0; - } - - if (skb->ip_summed != CHECKSUM_PARTIAL) { - skb->ip_summed = CHECKSUM_NONE; - /* We clear encapsulation here to prevent badly-written - * drivers potentially deciding to offload an inner checksum - * if we set CHECKSUM_PARTIAL on the outer header. - * This should go away when the drivers are all fixed. - */ - skb->encapsulation = 0; - } - - return 0; -} -EXPORT_SYMBOL_GPL(iptunnel_handle_offloads); - -/* Often modified stats are per cpu, other are shared (netdev->stats) */ -struct rtnl_link_stats64 *ip_tunnel_get_stats64(struct net_device *dev, - struct rtnl_link_stats64 *tot) -{ - int i; - - netdev_stats_to_stats64(tot, &dev->stats); - - for_each_possible_cpu(i) { - const struct pcpu_sw_netstats *tstats = - per_cpu_ptr(dev->tstats, i); - u64 rx_packets, rx_bytes, tx_packets, tx_bytes; - unsigned int start; - - do { - start = u64_stats_fetch_begin_irq(&tstats->syncp); - rx_packets = tstats->rx_packets; - tx_packets = tstats->tx_packets; - rx_bytes = tstats->rx_bytes; - tx_bytes = tstats->tx_bytes; - } while (u64_stats_fetch_retry_irq(&tstats->syncp, start)); - - tot->rx_packets += rx_packets; - tot->tx_packets += tx_packets; - tot->rx_bytes += rx_bytes; - tot->tx_bytes += tx_bytes; - } - - return tot; -} -EXPORT_SYMBOL_GPL(ip_tunnel_get_stats64); - -static const struct nla_policy ip_tun_policy[LWTUNNEL_IP_MAX + 1] = { - [LWTUNNEL_IP_ID] = { .type = NLA_U64 }, - [LWTUNNEL_IP_DST] = { .type = NLA_U32 }, - [LWTUNNEL_IP_SRC] = { .type = NLA_U32 }, - [LWTUNNEL_IP_TTL] = { .type = NLA_U8 }, - [LWTUNNEL_IP_TOS] = { .type = NLA_U8 }, - [LWTUNNEL_IP_FLAGS] = { .type = NLA_U16 }, -}; - -static int ip_tun_build_state(struct net_device *dev, struct nlattr *attr, - unsigned int family, const void *cfg, - struct lwtunnel_state **ts) -{ - struct ip_tunnel_info *tun_info; - struct lwtunnel_state *new_state; - struct nlattr *tb[LWTUNNEL_IP_MAX + 1]; - int err; - - err = nla_parse_nested(tb, LWTUNNEL_IP_MAX, attr, ip_tun_policy); - if (err < 0) - return err; - - new_state = lwtunnel_state_alloc(sizeof(*tun_info)); - if (!new_state) - return -ENOMEM; - - new_state->type = LWTUNNEL_ENCAP_IP; - - tun_info = lwt_tun_info(new_state); - - if (tb[LWTUNNEL_IP_ID]) - tun_info->key.tun_id = nla_get_be64(tb[LWTUNNEL_IP_ID]); - - if (tb[LWTUNNEL_IP_DST]) - tun_info->key.u.ipv4.dst = nla_get_in_addr(tb[LWTUNNEL_IP_DST]); - - if (tb[LWTUNNEL_IP_SRC]) - tun_info->key.u.ipv4.src = nla_get_in_addr(tb[LWTUNNEL_IP_SRC]); - - if (tb[LWTUNNEL_IP_TTL]) - tun_info->key.ttl = nla_get_u8(tb[LWTUNNEL_IP_TTL]); - - if (tb[LWTUNNEL_IP_TOS]) - tun_info->key.tos = nla_get_u8(tb[LWTUNNEL_IP_TOS]); - - if (tb[LWTUNNEL_IP_FLAGS]) - tun_info->key.tun_flags = nla_get_be16(tb[LWTUNNEL_IP_FLAGS]); - - tun_info->mode = IP_TUNNEL_INFO_TX; - tun_info->options_len = 0; - - *ts = new_state; - - return 0; -} - -static int ip_tun_fill_encap_info(struct sk_buff *skb, - struct lwtunnel_state *lwtstate) -{ - struct ip_tunnel_info *tun_info = lwt_tun_info(lwtstate); - - if (nla_put_be64(skb, LWTUNNEL_IP_ID, tun_info->key.tun_id, - LWTUNNEL_IP_PAD) || - nla_put_in_addr(skb, LWTUNNEL_IP_DST, tun_info->key.u.ipv4.dst) || - nla_put_in_addr(skb, LWTUNNEL_IP_SRC, tun_info->key.u.ipv4.src) || - nla_put_u8(skb, LWTUNNEL_IP_TOS, tun_info->key.tos) || - nla_put_u8(skb, LWTUNNEL_IP_TTL, tun_info->key.ttl) || - nla_put_be16(skb, LWTUNNEL_IP_FLAGS, tun_info->key.tun_flags)) - return -ENOMEM; - - return 0; -} - -static int ip_tun_encap_nlsize(struct lwtunnel_state *lwtstate) -{ - return nla_total_size_64bit(8) /* LWTUNNEL_IP_ID */ - + nla_total_size(4) /* LWTUNNEL_IP_DST */ - + nla_total_size(4) /* LWTUNNEL_IP_SRC */ - + nla_total_size(1) /* LWTUNNEL_IP_TOS */ - + nla_total_size(1) /* LWTUNNEL_IP_TTL */ - + nla_total_size(2); /* LWTUNNEL_IP_FLAGS */ -} - -static int ip_tun_cmp_encap(struct lwtunnel_state *a, struct lwtunnel_state *b) -{ - return memcmp(lwt_tun_info(a), lwt_tun_info(b), - sizeof(struct ip_tunnel_info)); -} - -static const struct lwtunnel_encap_ops ip_tun_lwt_ops = { - .build_state = ip_tun_build_state, - .fill_encap = ip_tun_fill_encap_info, - .get_encap_size = ip_tun_encap_nlsize, - .cmp_encap = ip_tun_cmp_encap, -}; - -static const struct nla_policy ip6_tun_policy[LWTUNNEL_IP6_MAX + 1] = { - [LWTUNNEL_IP6_ID] = { .type = NLA_U64 }, - [LWTUNNEL_IP6_DST] = { .len = sizeof(struct in6_addr) }, - [LWTUNNEL_IP6_SRC] = { .len = sizeof(struct in6_addr) }, - [LWTUNNEL_IP6_HOPLIMIT] = { .type = NLA_U8 }, - [LWTUNNEL_IP6_TC] = { .type = NLA_U8 }, - [LWTUNNEL_IP6_FLAGS] = { .type = NLA_U16 }, -}; - -static int ip6_tun_build_state(struct net_device *dev, struct nlattr *attr, - unsigned int family, const void *cfg, - struct lwtunnel_state **ts) -{ - struct ip_tunnel_info *tun_info; - struct lwtunnel_state *new_state; - struct nlattr *tb[LWTUNNEL_IP6_MAX + 1]; - int err; - - err = nla_parse_nested(tb, LWTUNNEL_IP6_MAX, attr, ip6_tun_policy); - if (err < 0) - return err; - - new_state = lwtunnel_state_alloc(sizeof(*tun_info)); - if (!new_state) - return -ENOMEM; - - new_state->type = LWTUNNEL_ENCAP_IP6; - - tun_info = lwt_tun_info(new_state); - - if (tb[LWTUNNEL_IP6_ID]) - tun_info->key.tun_id = nla_get_be64(tb[LWTUNNEL_IP6_ID]); - - if (tb[LWTUNNEL_IP6_DST]) - tun_info->key.u.ipv6.dst = nla_get_in6_addr(tb[LWTUNNEL_IP6_DST]); - - if (tb[LWTUNNEL_IP6_SRC]) - tun_info->key.u.ipv6.src = nla_get_in6_addr(tb[LWTUNNEL_IP6_SRC]); - - if (tb[LWTUNNEL_IP6_HOPLIMIT]) - tun_info->key.ttl = nla_get_u8(tb[LWTUNNEL_IP6_HOPLIMIT]); - - if (tb[LWTUNNEL_IP6_TC]) - tun_info->key.tos = nla_get_u8(tb[LWTUNNEL_IP6_TC]); - - if (tb[LWTUNNEL_IP6_FLAGS]) - tun_info->key.tun_flags = nla_get_be16(tb[LWTUNNEL_IP6_FLAGS]); - - tun_info->mode = IP_TUNNEL_INFO_TX | IP_TUNNEL_INFO_IPV6; - tun_info->options_len = 0; - - *ts = new_state; - - return 0; -} - -static int ip6_tun_fill_encap_info(struct sk_buff *skb, - struct lwtunnel_state *lwtstate) -{ - struct ip_tunnel_info *tun_info = lwt_tun_info(lwtstate); - - if (nla_put_be64(skb, LWTUNNEL_IP6_ID, tun_info->key.tun_id, - LWTUNNEL_IP6_PAD) || - nla_put_in6_addr(skb, LWTUNNEL_IP6_DST, &tun_info->key.u.ipv6.dst) || - nla_put_in6_addr(skb, LWTUNNEL_IP6_SRC, &tun_info->key.u.ipv6.src) || - nla_put_u8(skb, LWTUNNEL_IP6_TC, tun_info->key.tos) || - nla_put_u8(skb, LWTUNNEL_IP6_HOPLIMIT, tun_info->key.ttl) || - nla_put_be16(skb, LWTUNNEL_IP6_FLAGS, tun_info->key.tun_flags)) - return -ENOMEM; - - return 0; -} - -static int ip6_tun_encap_nlsize(struct lwtunnel_state *lwtstate) -{ - return nla_total_size_64bit(8) /* LWTUNNEL_IP6_ID */ - + nla_total_size(16) /* LWTUNNEL_IP6_DST */ - + nla_total_size(16) /* LWTUNNEL_IP6_SRC */ - + nla_total_size(1) /* LWTUNNEL_IP6_HOPLIMIT */ - + nla_total_size(1) /* LWTUNNEL_IP6_TC */ - + nla_total_size(2); /* LWTUNNEL_IP6_FLAGS */ -} - -static const struct lwtunnel_encap_ops ip6_tun_lwt_ops = { - .build_state = ip6_tun_build_state, - .fill_encap = ip6_tun_fill_encap_info, - .get_encap_size = ip6_tun_encap_nlsize, - .cmp_encap = ip_tun_cmp_encap, -}; - -void __init ip_tunnel_core_init(void) -{ - /* If you land here, make sure whether increasing ip_tunnel_info's - * options_len is a reasonable choice with its usage in front ends - * (f.e., it's part of flow keys, etc). - */ - BUILD_BUG_ON(IP_TUNNEL_OPTS_MAX != 255); - - lwtunnel_encap_add_ops(&ip_tun_lwt_ops, LWTUNNEL_ENCAP_IP); - lwtunnel_encap_add_ops(&ip6_tun_lwt_ops, LWTUNNEL_ENCAP_IP6); -} - -struct static_key ip_tunnel_metadata_cnt = STATIC_KEY_INIT_FALSE; -EXPORT_SYMBOL(ip_tunnel_metadata_cnt); - -void ip_tunnel_need_metadata(void) -{ - static_key_slow_inc(&ip_tunnel_metadata_cnt); -} -EXPORT_SYMBOL_GPL(ip_tunnel_need_metadata); - -void ip_tunnel_unneed_metadata(void) -{ - static_key_slow_dec(&ip_tunnel_metadata_cnt); -} -EXPORT_SYMBOL_GPL(ip_tunnel_unneed_metadata); diff --git a/src/linux/net/ipv4/ipconfig.c b/src/linux/net/ipv4/ipconfig.c deleted file mode 100644 index 071a785..0000000 --- a/src/linux/net/ipv4/ipconfig.c +++ /dev/null @@ -1,1708 +0,0 @@ -/* - * Automatic Configuration of IP -- use DHCP, BOOTP, RARP, or - * user-supplied information to configure own IP address and routes. - * - * Copyright (C) 1996-1998 Martin Mares - * - * Derived from network configuration code in fs/nfs/nfsroot.c, - * originally Copyright (C) 1995, 1996 Gero Kuhlmann and me. - * - * BOOTP rewritten to construct and analyse packets itself instead - * of misusing the IP layer. num_bugs_causing_wrong_arp_replies--; - * -- MJ, December 1998 - * - * Fixed ip_auto_config_setup calling at startup in the new "Linker Magic" - * initialization scheme. - * - Arnaldo Carvalho de Melo , 08/11/1999 - * - * DHCP support added. To users this looks like a whole separate - * protocol, but we know it's just a bag on the side of BOOTP. - * -- Chip Salzenberg , May 2000 - * - * Ported DHCP support from 2.2.16 to 2.4.0-test4 - * -- Eric Biederman , 30 Aug 2000 - * - * Merged changes from 2.2.19 into 2.4.3 - * -- Eric Biederman , 22 April Aug 2001 - * - * Multiple Nameservers in /proc/net/pnp - * -- Josef Siemes , Aug 2002 - */ - -#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 -#include -#include -#include - -#include -#include -#include - -#if defined(CONFIG_IP_PNP_DHCP) -#define IPCONFIG_DHCP -#endif -#if defined(CONFIG_IP_PNP_BOOTP) || defined(CONFIG_IP_PNP_DHCP) -#define IPCONFIG_BOOTP -#endif -#if defined(CONFIG_IP_PNP_RARP) -#define IPCONFIG_RARP -#endif -#if defined(IPCONFIG_BOOTP) || defined(IPCONFIG_RARP) -#define IPCONFIG_DYNAMIC -#endif - -/* Define the friendly delay before and after opening net devices */ -#define CONF_POST_OPEN 10 /* After opening: 10 msecs */ -#define CONF_CARRIER_TIMEOUT 120000 /* Wait for carrier timeout */ - -/* Define the timeout for waiting for a DHCP/BOOTP/RARP reply */ -#define CONF_OPEN_RETRIES 2 /* (Re)open devices twice */ -#define CONF_SEND_RETRIES 6 /* Send six requests per open */ -#define CONF_BASE_TIMEOUT (HZ*2) /* Initial timeout: 2 seconds */ -#define CONF_TIMEOUT_RANDOM (HZ) /* Maximum amount of randomization */ -#define CONF_TIMEOUT_MULT *7/4 /* Rate of timeout growth */ -#define CONF_TIMEOUT_MAX (HZ*30) /* Maximum allowed timeout */ -#define CONF_NAMESERVERS_MAX 3 /* Maximum number of nameservers - - '3' from resolv.h */ - -#define NONE cpu_to_be32(INADDR_NONE) -#define ANY cpu_to_be32(INADDR_ANY) - -/* - * Public IP configuration - */ - -/* This is used by platforms which might be able to set the ipconfig - * variables using firmware environment vars. If this is set, it will - * ignore such firmware variables. - */ -int ic_set_manually __initdata = 0; /* IPconfig parameters set manually */ - -static int ic_enable __initdata; /* IP config enabled? */ - -/* Protocol choice */ -int ic_proto_enabled __initdata = 0 -#ifdef IPCONFIG_BOOTP - | IC_BOOTP -#endif -#ifdef CONFIG_IP_PNP_DHCP - | IC_USE_DHCP -#endif -#ifdef IPCONFIG_RARP - | IC_RARP -#endif - ; - -static int ic_host_name_set __initdata; /* Host name set by us? */ - -__be32 ic_myaddr = NONE; /* My IP address */ -static __be32 ic_netmask = NONE; /* Netmask for local subnet */ -__be32 ic_gateway = NONE; /* Gateway IP address */ - -#ifdef IPCONFIG_DYNAMIC -static __be32 ic_addrservaddr = NONE; /* IP Address of the IP addresses'server */ -#endif - -__be32 ic_servaddr = NONE; /* Boot server IP address */ - -__be32 root_server_addr = NONE; /* Address of NFS server */ -u8 root_server_path[256] = { 0, }; /* Path to mount as root */ - -/* vendor class identifier */ -static char vendor_class_identifier[253] __initdata; - -#if defined(CONFIG_IP_PNP_DHCP) -static char dhcp_client_identifier[253] __initdata; -#endif - -/* Persistent data: */ - -#ifdef IPCONFIG_DYNAMIC -static int ic_proto_used; /* Protocol used, if any */ -#else -#define ic_proto_used 0 -#endif -static __be32 ic_nameservers[CONF_NAMESERVERS_MAX]; /* DNS Server IP addresses */ -static u8 ic_domain[64]; /* DNS (not NIS) domain name */ - -/* - * Private state. - */ - -/* Name of user-selected boot device */ -static char user_dev_name[IFNAMSIZ] __initdata = { 0, }; - -/* Protocols supported by available interfaces */ -static int ic_proto_have_if __initdata; - -/* MTU for boot device */ -static int ic_dev_mtu __initdata; - -#ifdef IPCONFIG_DYNAMIC -static DEFINE_SPINLOCK(ic_recv_lock); -static volatile int ic_got_reply __initdata; /* Proto(s) that replied */ -#endif -#ifdef IPCONFIG_DHCP -static int ic_dhcp_msgtype __initdata; /* DHCP msg type received */ -#endif - - -/* - * Network devices - */ - -struct ic_device { - struct ic_device *next; - struct net_device *dev; - unsigned short flags; - short able; - __be32 xid; -}; - -static struct ic_device *ic_first_dev __initdata; /* List of open device */ -static struct ic_device *ic_dev __initdata; /* Selected device */ - -static bool __init ic_is_init_dev(struct net_device *dev) -{ - if (dev->flags & IFF_LOOPBACK) - return false; - return user_dev_name[0] ? !strcmp(dev->name, user_dev_name) : - (!(dev->flags & IFF_LOOPBACK) && - (dev->flags & (IFF_POINTOPOINT|IFF_BROADCAST)) && - strncmp(dev->name, "dummy", 5)); -} - -static int __init ic_open_devs(void) -{ - struct ic_device *d, **last; - struct net_device *dev; - unsigned short oflags; - unsigned long start, next_msg; - - last = &ic_first_dev; - rtnl_lock(); - - /* bring loopback and DSA master network devices up first */ - for_each_netdev(&init_net, dev) { - if (!(dev->flags & IFF_LOOPBACK) && !netdev_uses_dsa(dev)) - continue; - if (dev_change_flags(dev, dev->flags | IFF_UP) < 0) - pr_err("IP-Config: Failed to open %s\n", dev->name); - } - - for_each_netdev(&init_net, dev) { - if (ic_is_init_dev(dev)) { - int able = 0; - if (dev->mtu >= 364) - able |= IC_BOOTP; - else - pr_warn("DHCP/BOOTP: Ignoring device %s, MTU %d too small\n", - dev->name, dev->mtu); - if (!(dev->flags & IFF_NOARP)) - able |= IC_RARP; - able &= ic_proto_enabled; - if (ic_proto_enabled && !able) - continue; - oflags = dev->flags; - if (dev_change_flags(dev, oflags | IFF_UP) < 0) { - pr_err("IP-Config: Failed to open %s\n", - dev->name); - continue; - } - if (!(d = kmalloc(sizeof(struct ic_device), GFP_KERNEL))) { - rtnl_unlock(); - return -ENOMEM; - } - d->dev = dev; - *last = d; - last = &d->next; - d->flags = oflags; - d->able = able; - if (able & IC_BOOTP) - get_random_bytes(&d->xid, sizeof(__be32)); - else - d->xid = 0; - ic_proto_have_if |= able; - pr_debug("IP-Config: %s UP (able=%d, xid=%08x)\n", - dev->name, able, d->xid); - } - } - - /* no point in waiting if we could not bring up at least one device */ - if (!ic_first_dev) - goto have_carrier; - - /* wait for a carrier on at least one device */ - start = jiffies; - next_msg = start + msecs_to_jiffies(CONF_CARRIER_TIMEOUT/12); - while (time_before(jiffies, start + - msecs_to_jiffies(CONF_CARRIER_TIMEOUT))) { - int wait, elapsed; - - for_each_netdev(&init_net, dev) - if (ic_is_init_dev(dev) && netif_carrier_ok(dev)) - goto have_carrier; - - msleep(1); - - if (time_before(jiffies, next_msg)) - continue; - - elapsed = jiffies_to_msecs(jiffies - start); - wait = (CONF_CARRIER_TIMEOUT - elapsed + 500)/1000; - pr_info("Waiting up to %d more seconds for network.\n", wait); - next_msg = jiffies + msecs_to_jiffies(CONF_CARRIER_TIMEOUT/12); - } -have_carrier: - rtnl_unlock(); - - *last = NULL; - - if (!ic_first_dev) { - if (user_dev_name[0]) - pr_err("IP-Config: Device `%s' not found\n", - user_dev_name); - else - pr_err("IP-Config: No network devices available\n"); - return -ENODEV; - } - return 0; -} - -static void __init ic_close_devs(void) -{ - struct ic_device *d, *next; - struct net_device *dev; - - rtnl_lock(); - next = ic_first_dev; - while ((d = next)) { - next = d->next; - dev = d->dev; - if ((!ic_dev || dev != ic_dev->dev) && !netdev_uses_dsa(dev)) { - pr_debug("IP-Config: Downing %s\n", dev->name); - dev_change_flags(dev, d->flags); - } - kfree(d); - } - rtnl_unlock(); -} - -/* - * Interface to various network functions. - */ - -static inline void -set_sockaddr(struct sockaddr_in *sin, __be32 addr, __be16 port) -{ - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = addr; - sin->sin_port = port; -} - -static int __init ic_devinet_ioctl(unsigned int cmd, struct ifreq *arg) -{ - int res; - - mm_segment_t oldfs = get_fs(); - set_fs(get_ds()); - res = devinet_ioctl(&init_net, cmd, (struct ifreq __user *) arg); - set_fs(oldfs); - return res; -} - -static int __init ic_dev_ioctl(unsigned int cmd, struct ifreq *arg) -{ - int res; - - mm_segment_t oldfs = get_fs(); - set_fs(get_ds()); - res = dev_ioctl(&init_net, cmd, (struct ifreq __user *) arg); - set_fs(oldfs); - return res; -} - -static int __init ic_route_ioctl(unsigned int cmd, struct rtentry *arg) -{ - int res; - - mm_segment_t oldfs = get_fs(); - set_fs(get_ds()); - res = ip_rt_ioctl(&init_net, cmd, (void __user *) arg); - set_fs(oldfs); - return res; -} - -/* - * Set up interface addresses and routes. - */ - -static int __init ic_setup_if(void) -{ - struct ifreq ir; - struct sockaddr_in *sin = (void *) &ir.ifr_ifru.ifru_addr; - int err; - - memset(&ir, 0, sizeof(ir)); - strcpy(ir.ifr_ifrn.ifrn_name, ic_dev->dev->name); - set_sockaddr(sin, ic_myaddr, 0); - if ((err = ic_devinet_ioctl(SIOCSIFADDR, &ir)) < 0) { - pr_err("IP-Config: Unable to set interface address (%d)\n", - err); - return -1; - } - set_sockaddr(sin, ic_netmask, 0); - if ((err = ic_devinet_ioctl(SIOCSIFNETMASK, &ir)) < 0) { - pr_err("IP-Config: Unable to set interface netmask (%d)\n", - err); - return -1; - } - set_sockaddr(sin, ic_myaddr | ~ic_netmask, 0); - if ((err = ic_devinet_ioctl(SIOCSIFBRDADDR, &ir)) < 0) { - pr_err("IP-Config: Unable to set interface broadcast address (%d)\n", - err); - return -1; - } - /* Handle the case where we need non-standard MTU on the boot link (a network - * using jumbo frames, for instance). If we can't set the mtu, don't error - * out, we'll try to muddle along. - */ - if (ic_dev_mtu != 0) { - strcpy(ir.ifr_name, ic_dev->dev->name); - ir.ifr_mtu = ic_dev_mtu; - if ((err = ic_dev_ioctl(SIOCSIFMTU, &ir)) < 0) - pr_err("IP-Config: Unable to set interface mtu to %d (%d)\n", - ic_dev_mtu, err); - } - return 0; -} - -static int __init ic_setup_routes(void) -{ - /* No need to setup device routes, only the default route... */ - - if (ic_gateway != NONE) { - struct rtentry rm; - int err; - - memset(&rm, 0, sizeof(rm)); - if ((ic_gateway ^ ic_myaddr) & ic_netmask) { - pr_err("IP-Config: Gateway not on directly connected network\n"); - return -1; - } - set_sockaddr((struct sockaddr_in *) &rm.rt_dst, 0, 0); - set_sockaddr((struct sockaddr_in *) &rm.rt_genmask, 0, 0); - set_sockaddr((struct sockaddr_in *) &rm.rt_gateway, ic_gateway, 0); - rm.rt_flags = RTF_UP | RTF_GATEWAY; - if ((err = ic_route_ioctl(SIOCADDRT, &rm)) < 0) { - pr_err("IP-Config: Cannot add default route (%d)\n", - err); - return -1; - } - } - - return 0; -} - -/* - * Fill in default values for all missing parameters. - */ - -static int __init ic_defaults(void) -{ - /* - * At this point we have no userspace running so need not - * claim locks on system_utsname - */ - - if (!ic_host_name_set) - sprintf(init_utsname()->nodename, "%pI4", &ic_myaddr); - - if (root_server_addr == NONE) - root_server_addr = ic_servaddr; - - if (ic_netmask == NONE) { - if (IN_CLASSA(ntohl(ic_myaddr))) - ic_netmask = htonl(IN_CLASSA_NET); - else if (IN_CLASSB(ntohl(ic_myaddr))) - ic_netmask = htonl(IN_CLASSB_NET); - else if (IN_CLASSC(ntohl(ic_myaddr))) - ic_netmask = htonl(IN_CLASSC_NET); - else { - pr_err("IP-Config: Unable to guess netmask for address %pI4\n", - &ic_myaddr); - return -1; - } - pr_notice("IP-Config: Guessing netmask %pI4\n", - &ic_netmask); - } - - return 0; -} - -/* - * RARP support. - */ - -#ifdef IPCONFIG_RARP - -static int ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev); - -static struct packet_type rarp_packet_type __initdata = { - .type = cpu_to_be16(ETH_P_RARP), - .func = ic_rarp_recv, -}; - -static inline void __init ic_rarp_init(void) -{ - dev_add_pack(&rarp_packet_type); -} - -static inline void __init ic_rarp_cleanup(void) -{ - dev_remove_pack(&rarp_packet_type); -} - -/* - * Process received RARP packet. - */ -static int __init -ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) -{ - struct arphdr *rarp; - unsigned char *rarp_ptr; - __be32 sip, tip; - unsigned char *tha; /* t for "target" */ - struct ic_device *d; - - if (!net_eq(dev_net(dev), &init_net)) - goto drop; - - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) - return NET_RX_DROP; - - if (!pskb_may_pull(skb, sizeof(struct arphdr))) - goto drop; - - /* Basic sanity checks can be done without the lock. */ - rarp = (struct arphdr *)skb_transport_header(skb); - - /* If this test doesn't pass, it's not IP, or we should - * ignore it anyway. - */ - if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)) - goto drop; - - /* If it's not a RARP reply, delete it. */ - if (rarp->ar_op != htons(ARPOP_RREPLY)) - goto drop; - - /* If it's not Ethernet, delete it. */ - if (rarp->ar_pro != htons(ETH_P_IP)) - goto drop; - - if (!pskb_may_pull(skb, arp_hdr_len(dev))) - goto drop; - - /* OK, it is all there and looks valid, process... */ - rarp = (struct arphdr *)skb_transport_header(skb); - rarp_ptr = (unsigned char *) (rarp + 1); - - /* One reply at a time, please. */ - spin_lock(&ic_recv_lock); - - /* If we already have a reply, just drop the packet */ - if (ic_got_reply) - goto drop_unlock; - - /* Find the ic_device that the packet arrived on */ - d = ic_first_dev; - while (d && d->dev != dev) - d = d->next; - if (!d) - goto drop_unlock; /* should never happen */ - - /* Extract variable-width fields */ - rarp_ptr += dev->addr_len; - memcpy(&sip, rarp_ptr, 4); - rarp_ptr += 4; - tha = rarp_ptr; - rarp_ptr += dev->addr_len; - memcpy(&tip, rarp_ptr, 4); - - /* Discard packets which are not meant for us. */ - if (memcmp(tha, dev->dev_addr, dev->addr_len)) - goto drop_unlock; - - /* Discard packets which are not from specified server. */ - if (ic_servaddr != NONE && ic_servaddr != sip) - goto drop_unlock; - - /* We have a winner! */ - ic_dev = d; - if (ic_myaddr == NONE) - ic_myaddr = tip; - ic_servaddr = sip; - ic_addrservaddr = sip; - ic_got_reply = IC_RARP; - -drop_unlock: - /* Show's over. Nothing to see here. */ - spin_unlock(&ic_recv_lock); - -drop: - /* Throw the packet out. */ - kfree_skb(skb); - return 0; -} - - -/* - * Send RARP request packet over a single interface. - */ -static void __init ic_rarp_send_if(struct ic_device *d) -{ - struct net_device *dev = d->dev; - arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL, - dev->dev_addr, dev->dev_addr); -} -#endif - -/* - * Predefine Nameservers - */ -static inline void __init ic_nameservers_predef(void) -{ - int i; - - for (i = 0; i < CONF_NAMESERVERS_MAX; i++) - ic_nameservers[i] = NONE; -} - -/* - * DHCP/BOOTP support. - */ - -#ifdef IPCONFIG_BOOTP - -struct bootp_pkt { /* BOOTP packet format */ - struct iphdr iph; /* IP header */ - struct udphdr udph; /* UDP header */ - u8 op; /* 1=request, 2=reply */ - u8 htype; /* HW address type */ - u8 hlen; /* HW address length */ - u8 hops; /* Used only by gateways */ - __be32 xid; /* Transaction ID */ - __be16 secs; /* Seconds since we started */ - __be16 flags; /* Just what it says */ - __be32 client_ip; /* Client's IP address if known */ - __be32 your_ip; /* Assigned IP address */ - __be32 server_ip; /* (Next, e.g. NFS) Server's IP address */ - __be32 relay_ip; /* IP address of BOOTP relay */ - u8 hw_addr[16]; /* Client's HW address */ - u8 serv_name[64]; /* Server host name */ - u8 boot_file[128]; /* Name of boot file */ - u8 exten[312]; /* DHCP options / BOOTP vendor extensions */ -}; - -/* packet ops */ -#define BOOTP_REQUEST 1 -#define BOOTP_REPLY 2 - -/* DHCP message types */ -#define DHCPDISCOVER 1 -#define DHCPOFFER 2 -#define DHCPREQUEST 3 -#define DHCPDECLINE 4 -#define DHCPACK 5 -#define DHCPNAK 6 -#define DHCPRELEASE 7 -#define DHCPINFORM 8 - -static int ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev); - -static struct packet_type bootp_packet_type __initdata = { - .type = cpu_to_be16(ETH_P_IP), - .func = ic_bootp_recv, -}; - -/* - * Initialize DHCP/BOOTP extension fields in the request. - */ - -static const u8 ic_bootp_cookie[4] = { 99, 130, 83, 99 }; - -#ifdef IPCONFIG_DHCP - -static void __init -ic_dhcp_init_options(u8 *options, struct ic_device *d) -{ - u8 mt = ((ic_servaddr == NONE) - ? DHCPDISCOVER : DHCPREQUEST); - u8 *e = options; - int len; - - pr_debug("DHCP: Sending message type %d (%s)\n", mt, d->dev->name); - - memcpy(e, ic_bootp_cookie, 4); /* RFC1048 Magic Cookie */ - e += 4; - - *e++ = 53; /* DHCP message type */ - *e++ = 1; - *e++ = mt; - - if (mt == DHCPREQUEST) { - *e++ = 54; /* Server ID (IP address) */ - *e++ = 4; - memcpy(e, &ic_servaddr, 4); - e += 4; - - *e++ = 50; /* Requested IP address */ - *e++ = 4; - memcpy(e, &ic_myaddr, 4); - e += 4; - } - - /* always? */ - { - static const u8 ic_req_params[] = { - 1, /* Subnet mask */ - 3, /* Default gateway */ - 6, /* DNS server */ - 12, /* Host name */ - 15, /* Domain name */ - 17, /* Boot path */ - 26, /* MTU */ - 40, /* NIS domain name */ - }; - - *e++ = 55; /* Parameter request list */ - *e++ = sizeof(ic_req_params); - memcpy(e, ic_req_params, sizeof(ic_req_params)); - e += sizeof(ic_req_params); - - if (ic_host_name_set) { - *e++ = 12; /* host-name */ - len = strlen(utsname()->nodename); - *e++ = len; - memcpy(e, utsname()->nodename, len); - e += len; - } - if (*vendor_class_identifier) { - pr_info("DHCP: sending class identifier \"%s\"\n", - vendor_class_identifier); - *e++ = 60; /* Class-identifier */ - len = strlen(vendor_class_identifier); - *e++ = len; - memcpy(e, vendor_class_identifier, len); - e += len; - } - len = strlen(dhcp_client_identifier + 1); - /* the minimum length of identifier is 2, include 1 byte type, - * and can not be larger than the length of options - */ - if (len >= 1 && len < 312 - (e - options) - 1) { - *e++ = 61; - *e++ = len + 1; - memcpy(e, dhcp_client_identifier, len + 1); - e += len + 1; - } - } - - *e++ = 255; /* End of the list */ -} - -#endif /* IPCONFIG_DHCP */ - -static void __init ic_bootp_init_ext(u8 *e) -{ - memcpy(e, ic_bootp_cookie, 4); /* RFC1048 Magic Cookie */ - e += 4; - *e++ = 1; /* Subnet mask request */ - *e++ = 4; - e += 4; - *e++ = 3; /* Default gateway request */ - *e++ = 4; - e += 4; - *e++ = 5; /* Name server request */ - *e++ = 8; - e += 8; - *e++ = 12; /* Host name request */ - *e++ = 32; - e += 32; - *e++ = 40; /* NIS Domain name request */ - *e++ = 32; - e += 32; - *e++ = 17; /* Boot path */ - *e++ = 40; - e += 40; - - *e++ = 57; /* set extension buffer size for reply */ - *e++ = 2; - *e++ = 1; /* 128+236+8+20+14, see dhcpd sources */ - *e++ = 150; - - *e++ = 255; /* End of the list */ -} - - -/* - * Initialize the DHCP/BOOTP mechanism. - */ -static inline void __init ic_bootp_init(void) -{ - ic_nameservers_predef(); - - dev_add_pack(&bootp_packet_type); -} - - -/* - * DHCP/BOOTP cleanup. - */ -static inline void __init ic_bootp_cleanup(void) -{ - dev_remove_pack(&bootp_packet_type); -} - - -/* - * Send DHCP/BOOTP request to single interface. - */ -static void __init ic_bootp_send_if(struct ic_device *d, unsigned long jiffies_diff) -{ - struct net_device *dev = d->dev; - struct sk_buff *skb; - struct bootp_pkt *b; - struct iphdr *h; - int hlen = LL_RESERVED_SPACE(dev); - int tlen = dev->needed_tailroom; - - /* Allocate packet */ - skb = alloc_skb(sizeof(struct bootp_pkt) + hlen + tlen + 15, - GFP_KERNEL); - if (!skb) - return; - skb_reserve(skb, hlen); - b = (struct bootp_pkt *) skb_put(skb, sizeof(struct bootp_pkt)); - memset(b, 0, sizeof(struct bootp_pkt)); - - /* Construct IP header */ - skb_reset_network_header(skb); - h = ip_hdr(skb); - h->version = 4; - h->ihl = 5; - h->tot_len = htons(sizeof(struct bootp_pkt)); - h->frag_off = htons(IP_DF); - h->ttl = 64; - h->protocol = IPPROTO_UDP; - h->daddr = htonl(INADDR_BROADCAST); - h->check = ip_fast_csum((unsigned char *) h, h->ihl); - - /* Construct UDP header */ - b->udph.source = htons(68); - b->udph.dest = htons(67); - b->udph.len = htons(sizeof(struct bootp_pkt) - sizeof(struct iphdr)); - /* UDP checksum not calculated -- explicitly allowed in BOOTP RFC */ - - /* Construct DHCP/BOOTP header */ - b->op = BOOTP_REQUEST; - if (dev->type < 256) /* check for false types */ - b->htype = dev->type; - else if (dev->type == ARPHRD_FDDI) - b->htype = ARPHRD_ETHER; - else { - pr_warn("Unknown ARP type 0x%04x for device %s\n", dev->type, - dev->name); - b->htype = dev->type; /* can cause undefined behavior */ - } - - /* server_ip and your_ip address are both already zero per RFC2131 */ - b->hlen = dev->addr_len; - memcpy(b->hw_addr, dev->dev_addr, dev->addr_len); - b->secs = htons(jiffies_diff / HZ); - b->xid = d->xid; - - /* add DHCP options or BOOTP extensions */ -#ifdef IPCONFIG_DHCP - if (ic_proto_enabled & IC_USE_DHCP) - ic_dhcp_init_options(b->exten, d); - else -#endif - ic_bootp_init_ext(b->exten); - - /* Chain packet down the line... */ - skb->dev = dev; - skb->protocol = htons(ETH_P_IP); - if (dev_hard_header(skb, dev, ntohs(skb->protocol), - dev->broadcast, dev->dev_addr, skb->len) < 0) { - kfree_skb(skb); - printk("E"); - return; - } - - if (dev_queue_xmit(skb) < 0) - printk("E"); -} - - -/* - * Copy BOOTP-supplied string if not already set. - */ -static int __init ic_bootp_string(char *dest, char *src, int len, int max) -{ - if (!len) - return 0; - if (len > max-1) - len = max-1; - memcpy(dest, src, len); - dest[len] = '\0'; - return 1; -} - - -/* - * Process BOOTP extensions. - */ -static void __init ic_do_bootp_ext(u8 *ext) -{ - u8 servers; - int i; - __be16 mtu; - - u8 *c; - - pr_debug("DHCP/BOOTP: Got extension %d:", *ext); - for (c=ext+2; c CONF_NAMESERVERS_MAX) - servers = CONF_NAMESERVERS_MAX; - for (i = 0; i < servers; i++) { - if (ic_nameservers[i] == NONE) - memcpy(&ic_nameservers[i], ext+1+4*i, 4); - } - break; - case 12: /* Host name */ - ic_bootp_string(utsname()->nodename, ext+1, *ext, - __NEW_UTS_LEN); - ic_host_name_set = 1; - break; - case 15: /* Domain name (DNS) */ - ic_bootp_string(ic_domain, ext+1, *ext, sizeof(ic_domain)); - break; - case 17: /* Root path */ - if (!root_server_path[0]) - ic_bootp_string(root_server_path, ext+1, *ext, - sizeof(root_server_path)); - break; - case 26: /* Interface MTU */ - memcpy(&mtu, ext+1, sizeof(mtu)); - ic_dev_mtu = ntohs(mtu); - break; - case 40: /* NIS Domain name (_not_ DNS) */ - ic_bootp_string(utsname()->domainname, ext+1, *ext, - __NEW_UTS_LEN); - break; - } -} - - -/* - * Receive BOOTP reply. - */ -static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) -{ - struct bootp_pkt *b; - struct iphdr *h; - struct ic_device *d; - int len, ext_len; - - if (!net_eq(dev_net(dev), &init_net)) - goto drop; - - /* Perform verifications before taking the lock. */ - if (skb->pkt_type == PACKET_OTHERHOST) - goto drop; - - skb = skb_share_check(skb, GFP_ATOMIC); - if (!skb) - return NET_RX_DROP; - - if (!pskb_may_pull(skb, - sizeof(struct iphdr) + - sizeof(struct udphdr))) - goto drop; - - b = (struct bootp_pkt *)skb_network_header(skb); - h = &b->iph; - - if (h->ihl != 5 || h->version != 4 || h->protocol != IPPROTO_UDP) - goto drop; - - /* Fragments are not supported */ - if (ip_is_fragment(h)) { - net_err_ratelimited("DHCP/BOOTP: Ignoring fragmented reply\n"); - goto drop; - } - - if (skb->len < ntohs(h->tot_len)) - goto drop; - - if (ip_fast_csum((char *) h, h->ihl)) - goto drop; - - if (b->udph.source != htons(67) || b->udph.dest != htons(68)) - goto drop; - - if (ntohs(h->tot_len) < ntohs(b->udph.len) + sizeof(struct iphdr)) - goto drop; - - len = ntohs(b->udph.len) - sizeof(struct udphdr); - ext_len = len - (sizeof(*b) - - sizeof(struct iphdr) - - sizeof(struct udphdr) - - sizeof(b->exten)); - if (ext_len < 0) - goto drop; - - /* Ok the front looks good, make sure we can get at the rest. */ - if (!pskb_may_pull(skb, skb->len)) - goto drop; - - b = (struct bootp_pkt *)skb_network_header(skb); - h = &b->iph; - - /* One reply at a time, please. */ - spin_lock(&ic_recv_lock); - - /* If we already have a reply, just drop the packet */ - if (ic_got_reply) - goto drop_unlock; - - /* Find the ic_device that the packet arrived on */ - d = ic_first_dev; - while (d && d->dev != dev) - d = d->next; - if (!d) - goto drop_unlock; /* should never happen */ - - /* Is it a reply to our BOOTP request? */ - if (b->op != BOOTP_REPLY || - b->xid != d->xid) { - net_err_ratelimited("DHCP/BOOTP: Reply not for us on %s, op[%x] xid[%x]\n", - d->dev->name, b->op, b->xid); - goto drop_unlock; - } - - /* Parse extensions */ - if (ext_len >= 4 && - !memcmp(b->exten, ic_bootp_cookie, 4)) { /* Check magic cookie */ - u8 *end = (u8 *) b + ntohs(b->iph.tot_len); - u8 *ext; - -#ifdef IPCONFIG_DHCP - if (ic_proto_enabled & IC_USE_DHCP) { - __be32 server_id = NONE; - int mt = 0; - - ext = &b->exten[4]; - while (ext < end && *ext != 0xff) { - u8 *opt = ext++; - if (*opt == 0) /* Padding */ - continue; - ext += *ext + 1; - if (ext >= end) - break; - switch (*opt) { - case 53: /* Message type */ - if (opt[1]) - mt = opt[2]; - break; - case 54: /* Server ID (IP address) */ - if (opt[1] >= 4) - memcpy(&server_id, opt + 2, 4); - break; - } - } - - pr_debug("DHCP: Got message type %d (%s)\n", mt, d->dev->name); - - switch (mt) { - case DHCPOFFER: - /* While in the process of accepting one offer, - * ignore all others. - */ - if (ic_myaddr != NONE) - goto drop_unlock; - - /* Let's accept that offer. */ - ic_myaddr = b->your_ip; - ic_servaddr = server_id; - pr_debug("DHCP: Offered address %pI4 by server %pI4\n", - &ic_myaddr, &b->iph.saddr); - /* The DHCP indicated server address takes - * precedence over the bootp header one if - * they are different. - */ - if ((server_id != NONE) && - (b->server_ip != server_id)) - b->server_ip = ic_servaddr; - break; - - case DHCPACK: - if (memcmp(dev->dev_addr, b->hw_addr, dev->addr_len) != 0) - goto drop_unlock; - - /* Yeah! */ - break; - - default: - /* Urque. Forget it*/ - ic_myaddr = NONE; - ic_servaddr = NONE; - goto drop_unlock; - } - - ic_dhcp_msgtype = mt; - - } -#endif /* IPCONFIG_DHCP */ - - ext = &b->exten[4]; - while (ext < end && *ext != 0xff) { - u8 *opt = ext++; - if (*opt == 0) /* Padding */ - continue; - ext += *ext + 1; - if (ext < end) - ic_do_bootp_ext(opt); - } - } - - /* We have a winner! */ - ic_dev = d; - ic_myaddr = b->your_ip; - ic_servaddr = b->server_ip; - ic_addrservaddr = b->iph.saddr; - if (ic_gateway == NONE && b->relay_ip) - ic_gateway = b->relay_ip; - if (ic_nameservers[0] == NONE) - ic_nameservers[0] = ic_servaddr; - ic_got_reply = IC_BOOTP; - -drop_unlock: - /* Show's over. Nothing to see here. */ - spin_unlock(&ic_recv_lock); - -drop: - /* Throw the packet out. */ - kfree_skb(skb); - - return 0; -} - - -#endif - - -/* - * Dynamic IP configuration -- DHCP, BOOTP, RARP. - */ - -#ifdef IPCONFIG_DYNAMIC - -static int __init ic_dynamic(void) -{ - int retries; - struct ic_device *d; - unsigned long start_jiffies, timeout, jiff; - int do_bootp = ic_proto_have_if & IC_BOOTP; - int do_rarp = ic_proto_have_if & IC_RARP; - - /* - * If none of DHCP/BOOTP/RARP was selected, return with an error. - * This routine gets only called when some pieces of information - * are missing, and without DHCP/BOOTP/RARP we are unable to get it. - */ - if (!ic_proto_enabled) { - pr_err("IP-Config: Incomplete network configuration information\n"); - return -1; - } - -#ifdef IPCONFIG_BOOTP - if ((ic_proto_enabled ^ ic_proto_have_if) & IC_BOOTP) - pr_err("DHCP/BOOTP: No suitable device found\n"); -#endif -#ifdef IPCONFIG_RARP - if ((ic_proto_enabled ^ ic_proto_have_if) & IC_RARP) - pr_err("RARP: No suitable device found\n"); -#endif - - if (!ic_proto_have_if) - /* Error message already printed */ - return -1; - - /* - * Setup protocols - */ -#ifdef IPCONFIG_BOOTP - if (do_bootp) - ic_bootp_init(); -#endif -#ifdef IPCONFIG_RARP - if (do_rarp) - ic_rarp_init(); -#endif - - /* - * Send requests and wait, until we get an answer. This loop - * seems to be a terrible waste of CPU time, but actually there is - * only one process running at all, so we don't need to use any - * scheduler functions. - * [Actually we could now, but the nothing else running note still - * applies.. - AC] - */ - pr_notice("Sending %s%s%s requests .", - do_bootp - ? ((ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP") : "", - (do_bootp && do_rarp) ? " and " : "", - do_rarp ? "RARP" : ""); - - start_jiffies = jiffies; - d = ic_first_dev; - retries = CONF_SEND_RETRIES; - get_random_bytes(&timeout, sizeof(timeout)); - timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned int) CONF_TIMEOUT_RANDOM); - for (;;) { -#ifdef IPCONFIG_BOOTP - if (do_bootp && (d->able & IC_BOOTP)) - ic_bootp_send_if(d, jiffies - start_jiffies); -#endif -#ifdef IPCONFIG_RARP - if (do_rarp && (d->able & IC_RARP)) - ic_rarp_send_if(d); -#endif - - if (!d->next) { - jiff = jiffies + timeout; - while (time_before(jiffies, jiff) && !ic_got_reply) - schedule_timeout_uninterruptible(1); - } -#ifdef IPCONFIG_DHCP - /* DHCP isn't done until we get a DHCPACK. */ - if ((ic_got_reply & IC_BOOTP) && - (ic_proto_enabled & IC_USE_DHCP) && - ic_dhcp_msgtype != DHCPACK) { - ic_got_reply = 0; - /* continue on device that got the reply */ - d = ic_dev; - pr_cont(","); - continue; - } -#endif /* IPCONFIG_DHCP */ - - if (ic_got_reply) { - pr_cont(" OK\n"); - break; - } - - if ((d = d->next)) - continue; - - if (! --retries) { - pr_cont(" timed out!\n"); - break; - } - - d = ic_first_dev; - - timeout = timeout CONF_TIMEOUT_MULT; - if (timeout > CONF_TIMEOUT_MAX) - timeout = CONF_TIMEOUT_MAX; - - pr_cont("."); - } - -#ifdef IPCONFIG_BOOTP - if (do_bootp) - ic_bootp_cleanup(); -#endif -#ifdef IPCONFIG_RARP - if (do_rarp) - ic_rarp_cleanup(); -#endif - - if (!ic_got_reply) { - ic_myaddr = NONE; - return -1; - } - - pr_info("IP-Config: Got %s answer from %pI4, my address is %pI4\n", - ((ic_got_reply & IC_RARP) ? "RARP" - : (ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP"), - &ic_addrservaddr, &ic_myaddr); - - return 0; -} - -#endif /* IPCONFIG_DYNAMIC */ - -#ifdef CONFIG_PROC_FS - -static int pnp_seq_show(struct seq_file *seq, void *v) -{ - int i; - - if (ic_proto_used & IC_PROTO) - seq_printf(seq, "#PROTO: %s\n", - (ic_proto_used & IC_RARP) ? "RARP" - : (ic_proto_used & IC_USE_DHCP) ? "DHCP" : "BOOTP"); - else - seq_puts(seq, "#MANUAL\n"); - - if (ic_domain[0]) - seq_printf(seq, - "domain %s\n", ic_domain); - for (i = 0; i < CONF_NAMESERVERS_MAX; i++) { - if (ic_nameservers[i] != NONE) - seq_printf(seq, "nameserver %pI4\n", - &ic_nameservers[i]); - } - if (ic_servaddr != NONE) - seq_printf(seq, "bootserver %pI4\n", - &ic_servaddr); - return 0; -} - -static int pnp_seq_open(struct inode *indoe, struct file *file) -{ - return single_open(file, pnp_seq_show, NULL); -} - -static const struct file_operations pnp_seq_fops = { - .owner = THIS_MODULE, - .open = pnp_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -#endif /* CONFIG_PROC_FS */ - -/* - * Extract IP address from the parameter string if needed. Note that we - * need to have root_server_addr set _before_ IPConfig gets called as it - * can override it. - */ -__be32 __init root_nfs_parse_addr(char *name) -{ - __be32 addr; - int octets = 0; - char *cp, *cq; - - cp = cq = name; - while (octets < 4) { - while (*cp >= '0' && *cp <= '9') - cp++; - if (cp == cq || cp - cq > 3) - break; - if (*cp == '.' || octets == 3) - octets++; - if (octets < 4) - cp++; - cq = cp; - } - if (octets == 4 && (*cp == ':' || *cp == '\0')) { - if (*cp == ':') - *cp++ = '\0'; - addr = in_aton(name); - memmove(name, cp, strlen(cp) + 1); - } else - addr = NONE; - - return addr; -} - -#define DEVICE_WAIT_MAX 12 /* 12 seconds */ - -static int __init wait_for_devices(void) -{ - int i; - - for (i = 0; i < DEVICE_WAIT_MAX; i++) { - struct net_device *dev; - int found = 0; - - rtnl_lock(); - for_each_netdev(&init_net, dev) { - if (ic_is_init_dev(dev)) { - found = 1; - break; - } - } - rtnl_unlock(); - if (found) - return 0; - ssleep(1); - } - return -ENODEV; -} - -/* - * IP Autoconfig dispatcher. - */ - -static int __init ip_auto_config(void) -{ - __be32 addr; -#ifdef IPCONFIG_DYNAMIC - int retries = CONF_OPEN_RETRIES; -#endif - int err; - unsigned int i; - -#ifdef CONFIG_PROC_FS - proc_create("pnp", S_IRUGO, init_net.proc_net, &pnp_seq_fops); -#endif /* CONFIG_PROC_FS */ - - if (!ic_enable) - return 0; - - pr_debug("IP-Config: Entered.\n"); -#ifdef IPCONFIG_DYNAMIC - try_try_again: -#endif - /* Wait for devices to appear */ - err = wait_for_devices(); - if (err) - return err; - - /* Setup all network devices */ - err = ic_open_devs(); - if (err) - return err; - - /* Give drivers a chance to settle */ - msleep(CONF_POST_OPEN); - - /* - * If the config information is insufficient (e.g., our IP address or - * IP address of the boot server is missing or we have multiple network - * interfaces and no default was set), use BOOTP or RARP to get the - * missing values. - */ - if (ic_myaddr == NONE || -#ifdef CONFIG_ROOT_NFS - (root_server_addr == NONE && - ic_servaddr == NONE && - ROOT_DEV == Root_NFS) || -#endif - ic_first_dev->next) { -#ifdef IPCONFIG_DYNAMIC - if (ic_dynamic() < 0) { - ic_close_devs(); - - /* - * I don't know why, but sometimes the - * eepro100 driver (at least) gets upset and - * doesn't work the first time it's opened. - * But then if you close it and reopen it, it - * works just fine. So we need to try that at - * least once before giving up. - * - * Also, if the root will be NFS-mounted, we - * have nowhere to go if DHCP fails. So we - * just have to keep trying forever. - * - * -- Chip - */ -#ifdef CONFIG_ROOT_NFS - if (ROOT_DEV == Root_NFS) { - pr_err("IP-Config: Retrying forever (NFS root)...\n"); - goto try_try_again; - } -#endif - - if (--retries) { - pr_err("IP-Config: Reopening network devices...\n"); - goto try_try_again; - } - - /* Oh, well. At least we tried. */ - pr_err("IP-Config: Auto-configuration of network failed\n"); - return -1; - } -#else /* !DYNAMIC */ - pr_err("IP-Config: Incomplete network configuration information\n"); - ic_close_devs(); - return -1; -#endif /* IPCONFIG_DYNAMIC */ - } else { - /* Device selected manually or only one device -> use it */ - ic_dev = ic_first_dev; - } - - addr = root_nfs_parse_addr(root_server_path); - if (root_server_addr == NONE) - root_server_addr = addr; - - /* - * Use defaults wherever applicable. - */ - if (ic_defaults() < 0) - return -1; - - /* - * Record which protocol was actually used. - */ -#ifdef IPCONFIG_DYNAMIC - ic_proto_used = ic_got_reply | (ic_proto_enabled & IC_USE_DHCP); -#endif - -#ifndef IPCONFIG_SILENT - /* - * Clue in the operator. - */ - pr_info("IP-Config: Complete:\n"); - - pr_info(" device=%s, hwaddr=%*phC, ipaddr=%pI4, mask=%pI4, gw=%pI4\n", - ic_dev->dev->name, ic_dev->dev->addr_len, ic_dev->dev->dev_addr, - &ic_myaddr, &ic_netmask, &ic_gateway); - pr_info(" host=%s, domain=%s, nis-domain=%s\n", - utsname()->nodename, ic_domain, utsname()->domainname); - pr_info(" bootserver=%pI4, rootserver=%pI4, rootpath=%s", - &ic_servaddr, &root_server_addr, root_server_path); - if (ic_dev_mtu) - pr_cont(", mtu=%d", ic_dev_mtu); - for (i = 0; i < CONF_NAMESERVERS_MAX; i++) - if (ic_nameservers[i] != NONE) { - pr_cont(" nameserver%u=%pI4", - i, &ic_nameservers[i]); - break; - } - for (i++; i < CONF_NAMESERVERS_MAX; i++) - if (ic_nameservers[i] != NONE) - pr_cont(", nameserver%u=%pI4", i, &ic_nameservers[i]); - pr_cont("\n"); -#endif /* !SILENT */ - - /* - * Close all network devices except the device we've - * autoconfigured and set up routes. - */ - if (ic_setup_if() < 0 || ic_setup_routes() < 0) - err = -1; - else - err = 0; - - ic_close_devs(); - - return err; -} - -late_initcall(ip_auto_config); - - -/* - * Decode any IP configuration options in the "ip=" or "nfsaddrs=" kernel - * command line parameter. See Documentation/filesystems/nfs/nfsroot.txt. - */ -static int __init ic_proto_name(char *name) -{ - if (!strcmp(name, "on") || !strcmp(name, "any")) { - return 1; - } - if (!strcmp(name, "off") || !strcmp(name, "none")) { - return 0; - } -#ifdef CONFIG_IP_PNP_DHCP - else if (!strncmp(name, "dhcp", 4)) { - char *client_id; - - ic_proto_enabled &= ~IC_RARP; - client_id = strstr(name, "dhcp,"); - if (client_id) { - char *v; - - client_id = client_id + 5; - v = strchr(client_id, ','); - if (!v) - return 1; - *v = 0; - if (kstrtou8(client_id, 0, dhcp_client_identifier)) - pr_debug("DHCP: Invalid client identifier type\n"); - strncpy(dhcp_client_identifier + 1, v + 1, 251); - *v = ','; - } - return 1; - } -#endif -#ifdef CONFIG_IP_PNP_BOOTP - else if (!strcmp(name, "bootp")) { - ic_proto_enabled &= ~(IC_RARP | IC_USE_DHCP); - return 1; - } -#endif -#ifdef CONFIG_IP_PNP_RARP - else if (!strcmp(name, "rarp")) { - ic_proto_enabled &= ~(IC_BOOTP | IC_USE_DHCP); - return 1; - } -#endif -#ifdef IPCONFIG_DYNAMIC - else if (!strcmp(name, "both")) { - ic_proto_enabled &= ~IC_USE_DHCP; /* backward compat :-( */ - return 1; - } -#endif - return 0; -} - -static int __init ip_auto_config_setup(char *addrs) -{ - char *cp, *ip, *dp; - int num = 0; - - ic_set_manually = 1; - ic_enable = 1; - - /* - * If any dhcp, bootp etc options are set, leave autoconfig on - * and skip the below static IP processing. - */ - if (ic_proto_name(addrs)) - return 1; - - /* If no static IP is given, turn off autoconfig and bail. */ - if (*addrs == 0 || - strcmp(addrs, "off") == 0 || - strcmp(addrs, "none") == 0) { - ic_enable = 0; - return 1; - } - - ic_nameservers_predef(); - - /* Parse string for static IP assignment. */ - ip = addrs; - while (ip && *ip) { - if ((cp = strchr(ip, ':'))) - *cp++ = '\0'; - if (strlen(ip) > 0) { - pr_debug("IP-Config: Parameter #%d: `%s'\n", num, ip); - switch (num) { - case 0: - if ((ic_myaddr = in_aton(ip)) == ANY) - ic_myaddr = NONE; - break; - case 1: - if ((ic_servaddr = in_aton(ip)) == ANY) - ic_servaddr = NONE; - break; - case 2: - if ((ic_gateway = in_aton(ip)) == ANY) - ic_gateway = NONE; - break; - case 3: - if ((ic_netmask = in_aton(ip)) == ANY) - ic_netmask = NONE; - break; - case 4: - if ((dp = strchr(ip, '.'))) { - *dp++ = '\0'; - strlcpy(utsname()->domainname, dp, - sizeof(utsname()->domainname)); - } - strlcpy(utsname()->nodename, ip, - sizeof(utsname()->nodename)); - ic_host_name_set = 1; - break; - case 5: - strlcpy(user_dev_name, ip, sizeof(user_dev_name)); - break; - case 6: - if (ic_proto_name(ip) == 0 && - ic_myaddr == NONE) { - ic_enable = 0; - } - break; - case 7: - if (CONF_NAMESERVERS_MAX >= 1) { - ic_nameservers[0] = in_aton(ip); - if (ic_nameservers[0] == ANY) - ic_nameservers[0] = NONE; - } - break; - case 8: - if (CONF_NAMESERVERS_MAX >= 2) { - ic_nameservers[1] = in_aton(ip); - if (ic_nameservers[1] == ANY) - ic_nameservers[1] = NONE; - } - break; - } - } - ip = cp; - num++; - } - - return 1; -} -__setup("ip=", ip_auto_config_setup); - -static int __init nfsaddrs_config_setup(char *addrs) -{ - return ip_auto_config_setup(addrs); -} -__setup("nfsaddrs=", nfsaddrs_config_setup); - -static int __init vendor_class_identifier_setup(char *addrs) -{ - if (strlcpy(vendor_class_identifier, addrs, - sizeof(vendor_class_identifier)) - >= sizeof(vendor_class_identifier)) - pr_warn("DHCP: vendorclass too long, truncated to \"%s\"\n", - vendor_class_identifier); - return 1; -} -__setup("dhcpclass=", vendor_class_identifier_setup); diff --git a/src/linux/net/ipv4/netfilter/Kconfig b/src/linux/net/ipv4/netfilter/Kconfig deleted file mode 100644 index d613309..0000000 --- a/src/linux/net/ipv4/netfilter/Kconfig +++ /dev/null @@ -1,410 +0,0 @@ -# -# IP netfilter configuration -# - -menu "IP: Netfilter Configuration" - depends on INET && NETFILTER - -config NF_DEFRAG_IPV4 - tristate - default n - -config NF_CONNTRACK_IPV4 - tristate "IPv4 connection tracking support (required for NAT)" - depends on NF_CONNTRACK - default m if NETFILTER_ADVANCED=n - select NF_DEFRAG_IPV4 - ---help--- - Connection tracking keeps a record of what packets have passed - through your machine, in order to figure out how they are related - into connections. - - This is IPv4 support on Layer 3 independent connection tracking. - Layer 3 independent connection tracking is experimental scheme - which generalize ip_conntrack to support other layer 3 protocols. - - To compile it as a module, choose M here. If unsure, say N. - -if NF_TABLES - -config NF_TABLES_IPV4 - tristate "IPv4 nf_tables support" - help - This option enables the IPv4 support for nf_tables. - -if NF_TABLES_IPV4 - -config NFT_CHAIN_ROUTE_IPV4 - tristate "IPv4 nf_tables route chain support" - help - This option enables the "route" chain for IPv4 in nf_tables. This - chain type is used to force packet re-routing after mangling header - fields such as the source, destination, type of service and - the packet mark. - -config NFT_REJECT_IPV4 - select NF_REJECT_IPV4 - default NFT_REJECT - tristate - -config NFT_DUP_IPV4 - tristate "IPv4 nf_tables packet duplication support" - depends on !NF_CONNTRACK || NF_CONNTRACK - select NF_DUP_IPV4 - help - This module enables IPv4 packet duplication support for nf_tables. - -endif # NF_TABLES_IPV4 - -config NF_TABLES_ARP - tristate "ARP nf_tables support" - help - This option enables the ARP support for nf_tables. - -endif # NF_TABLES - -config NF_DUP_IPV4 - tristate "Netfilter IPv4 packet duplication to alternate destination" - depends on !NF_CONNTRACK || NF_CONNTRACK - help - This option enables the nf_dup_ipv4 core, which duplicates an IPv4 - packet to be rerouted to another destination. - -config NF_LOG_ARP - tristate "ARP packet logging" - default m if NETFILTER_ADVANCED=n - select NF_LOG_COMMON - -config NF_LOG_IPV4 - tristate "IPv4 packet logging" - default m if NETFILTER_ADVANCED=n - select NF_LOG_COMMON - -config NF_REJECT_IPV4 - tristate "IPv4 packet rejection" - default m if NETFILTER_ADVANCED=n - -config NF_NAT_IPV4 - tristate "IPv4 NAT" - depends on NF_CONNTRACK_IPV4 - default m if NETFILTER_ADVANCED=n - select NF_NAT - help - The IPv4 NAT option allows masquerading, port forwarding and other - forms of full Network Address Port Translation. This can be - controlled by iptables or nft. - -if NF_NAT_IPV4 - -config NFT_CHAIN_NAT_IPV4 - depends on NF_TABLES_IPV4 - tristate "IPv4 nf_tables nat chain support" - help - This option enables the "nat" chain for IPv4 in nf_tables. This - chain type is used to perform Network Address Translation (NAT) - packet transformations such as the source, destination address and - source and destination ports. - -config NF_NAT_MASQUERADE_IPV4 - tristate "IPv4 masquerade support" - help - This is the kernel functionality to provide NAT in the masquerade - flavour (automatic source address selection). - -config NFT_MASQ_IPV4 - tristate "IPv4 masquerading support for nf_tables" - depends on NF_TABLES_IPV4 - depends on NFT_MASQ - select NF_NAT_MASQUERADE_IPV4 - help - This is the expression that provides IPv4 masquerading support for - nf_tables. - -config NFT_REDIR_IPV4 - tristate "IPv4 redirect support for nf_tables" - depends on NF_TABLES_IPV4 - depends on NFT_REDIR - select NF_NAT_REDIRECT - help - This is the expression that provides IPv4 redirect support for - nf_tables. - -config NF_NAT_SNMP_BASIC - tristate "Basic SNMP-ALG support" - depends on NF_CONNTRACK_SNMP - depends on NETFILTER_ADVANCED - default NF_NAT && NF_CONNTRACK_SNMP - ---help--- - - This module implements an Application Layer Gateway (ALG) for - SNMP payloads. In conjunction with NAT, it allows a network - management system to access multiple private networks with - conflicting addresses. It works by modifying IP addresses - inside SNMP payloads to match IP-layer NAT mapping. - - This is the "basic" form of SNMP-ALG, as described in RFC 2962 - - To compile it as a module, choose M here. If unsure, say N. - -config NF_NAT_PROTO_GRE - tristate - depends on NF_CT_PROTO_GRE - -config NF_NAT_PPTP - tristate - depends on NF_CONNTRACK - default NF_CONNTRACK_PPTP - select NF_NAT_PROTO_GRE - -config NF_NAT_H323 - tristate - depends on NF_CONNTRACK - default NF_CONNTRACK_H323 - -endif # NF_NAT_IPV4 - -config IP_NF_IPTABLES - tristate "IP tables support (required for filtering/masq/NAT)" - default m if NETFILTER_ADVANCED=n - select NETFILTER_XTABLES - help - iptables is a general, extensible packet identification framework. - The packet filtering and full NAT (masquerading, port forwarding, - etc) subsystems now use this: say `Y' or `M' here if you want to use - either of those. - - To compile it as a module, choose M here. If unsure, say N. - -if IP_NF_IPTABLES - -# The matches. -config IP_NF_MATCH_AH - tristate '"ah" match support' - depends on NETFILTER_ADVANCED - help - This match extension allows you to match a range of SPIs - inside AH header of IPSec packets. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_NF_MATCH_ECN - tristate '"ecn" match support' - depends on NETFILTER_ADVANCED - select NETFILTER_XT_MATCH_ECN - ---help--- - This is a backwards-compat option for the user's convenience - (e.g. when running oldconfig). It selects - CONFIG_NETFILTER_XT_MATCH_ECN. - -config IP_NF_MATCH_RPFILTER - tristate '"rpfilter" reverse path filter match support' - depends on NETFILTER_ADVANCED - depends on IP_NF_MANGLE || IP_NF_RAW - ---help--- - This option allows you to match packets whose replies would - go out via the interface the packet came in. - - To compile it as a module, choose M here. If unsure, say N. - The module will be called ipt_rpfilter. - -config IP_NF_MATCH_TTL - tristate '"ttl" match support' - depends on NETFILTER_ADVANCED - select NETFILTER_XT_MATCH_HL - ---help--- - This is a backwards-compat option for the user's convenience - (e.g. when running oldconfig). It selects - CONFIG_NETFILTER_XT_MATCH_HL. - -# `filter', generic and specific targets -config IP_NF_FILTER - tristate "Packet filtering" - default m if NETFILTER_ADVANCED=n - help - Packet filtering defines a table `filter', which has a series of - rules for simple packet filtering at local input, forwarding and - local output. See the man page for iptables(8). - - To compile it as a module, choose M here. If unsure, say N. - -config IP_NF_TARGET_REJECT - tristate "REJECT target support" - depends on IP_NF_FILTER - select NF_REJECT_IPV4 - default m if NETFILTER_ADVANCED=n - help - The REJECT target allows a filtering rule to specify that an ICMP - error should be issued in response to an incoming packet, rather - than silently being dropped. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_NF_TARGET_SYNPROXY - tristate "SYNPROXY target support" - depends on NF_CONNTRACK && NETFILTER_ADVANCED - select NETFILTER_SYNPROXY - select SYN_COOKIES - help - The SYNPROXY target allows you to intercept TCP connections and - establish them using syncookies before they are passed on to the - server. This allows to avoid conntrack and server resource usage - during SYN-flood attacks. - - To compile it as a module, choose M here. If unsure, say N. - -# NAT + specific targets: nf_conntrack -config IP_NF_NAT - tristate "iptables NAT support" - depends on NF_CONNTRACK_IPV4 - default m if NETFILTER_ADVANCED=n - select NF_NAT - select NF_NAT_IPV4 - select NETFILTER_XT_NAT - help - This enables the `nat' table in iptables. This allows masquerading, - port forwarding and other forms of full Network Address Port - Translation. - - To compile it as a module, choose M here. If unsure, say N. - -if IP_NF_NAT - -config IP_NF_TARGET_MASQUERADE - tristate "MASQUERADE target support" - select NF_NAT_MASQUERADE_IPV4 - default m if NETFILTER_ADVANCED=n - help - Masquerading is a special case of NAT: all outgoing connections are - changed to seem to come from a particular interface's address, and - if the interface goes down, those connections are lost. This is - only useful for dialup accounts with dynamic IP address (ie. your IP - address will be different on next dialup). - - To compile it as a module, choose M here. If unsure, say N. - -config IP_NF_TARGET_NETMAP - tristate "NETMAP target support" - depends on NETFILTER_ADVANCED - select NETFILTER_XT_TARGET_NETMAP - ---help--- - This is a backwards-compat option for the user's convenience - (e.g. when running oldconfig). It selects - CONFIG_NETFILTER_XT_TARGET_NETMAP. - -config IP_NF_TARGET_REDIRECT - tristate "REDIRECT target support" - depends on NETFILTER_ADVANCED - select NETFILTER_XT_TARGET_REDIRECT - ---help--- - This is a backwards-compat option for the user's convenience - (e.g. when running oldconfig). It selects - CONFIG_NETFILTER_XT_TARGET_REDIRECT. - -endif # IP_NF_NAT - -# mangle + specific targets -config IP_NF_MANGLE - tristate "Packet mangling" - default m if NETFILTER_ADVANCED=n - help - This option adds a `mangle' table to iptables: see the man page for - iptables(8). This table is used for various packet alterations - which can effect how the packet is routed. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_NF_TARGET_CLUSTERIP - tristate "CLUSTERIP target support" - depends on IP_NF_MANGLE - depends on NF_CONNTRACK_IPV4 - depends on NETFILTER_ADVANCED - select NF_CONNTRACK_MARK - help - The CLUSTERIP target allows you to build load-balancing clusters of - network servers without having a dedicated load-balancing - router/server/switch. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_NF_TARGET_ECN - tristate "ECN target support" - depends on IP_NF_MANGLE - depends on NETFILTER_ADVANCED - ---help--- - This option adds a `ECN' target, which can be used in the iptables mangle - table. - - You can use this target to remove the ECN bits from the IPv4 header of - an IP packet. This is particularly useful, if you need to work around - existing ECN blackholes on the internet, but don't want to disable - ECN support in general. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_NF_TARGET_TTL - tristate '"TTL" target support' - depends on NETFILTER_ADVANCED && IP_NF_MANGLE - select NETFILTER_XT_TARGET_HL - ---help--- - This is a backwards-compatible option for the user's convenience - (e.g. when running oldconfig). It selects - CONFIG_NETFILTER_XT_TARGET_HL. - -# raw + specific targets -config IP_NF_RAW - tristate 'raw table support (required for NOTRACK/TRACE)' - help - This option adds a `raw' table to iptables. This table is the very - first in the netfilter framework and hooks in at the PREROUTING - and OUTPUT chains. - - If you want to compile it as a module, say M here and read - . If unsure, say `N'. - -# security table for MAC policy -config IP_NF_SECURITY - tristate "Security table" - depends on SECURITY - depends on NETFILTER_ADVANCED - help - This option adds a `security' table to iptables, for use - with Mandatory Access Control (MAC) policy. - - If unsure, say N. - -endif # IP_NF_IPTABLES - -# ARP tables -config IP_NF_ARPTABLES - tristate "ARP tables support" - select NETFILTER_XTABLES - depends on NETFILTER_ADVANCED - help - arptables is a general, extensible packet identification framework. - The ARP packet filtering and mangling (manipulation)subsystems - use this: say Y or M here if you want to use either of those. - - To compile it as a module, choose M here. If unsure, say N. - -if IP_NF_ARPTABLES - -config IP_NF_ARPFILTER - tristate "ARP packet filtering" - help - ARP packet filtering defines a table `filter', which has a series of - rules for simple ARP packet filtering at local input and - local output. On a bridge, you can also specify filtering rules - for forwarded ARP packets. See the man page for arptables(8). - - To compile it as a module, choose M here. If unsure, say N. - -config IP_NF_ARP_MANGLE - tristate "ARP payload mangling" - help - Allows altering the ARP packet payload: source and destination - hardware and network addresses. - -endif # IP_NF_ARPTABLES - -endmenu - diff --git a/src/linux/net/ipv4/ping.c b/src/linux/net/ipv4/ping.c deleted file mode 100644 index 96b8e2b..0000000 --- a/src/linux/net/ipv4/ping.c +++ /dev/null @@ -1,1223 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * "Ping" sockets - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Based on ipv4/udp.c code. - * - * Authors: Vasiliy Kulikov / Openwall (for Linux 2.6), - * Pavel Kankovsky (for Linux 2.4.32) - * - * Pavel gave all rights to bugs to Vasiliy, - * none of the bugs are Pavel's now. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if IS_ENABLED(CONFIG_IPV6) -#include -#include -#include -#include -#include -#endif - -struct ping_table { - struct hlist_nulls_head hash[PING_HTABLE_SIZE]; - rwlock_t lock; -}; - -static struct ping_table ping_table; -struct pingv6_ops pingv6_ops; -EXPORT_SYMBOL_GPL(pingv6_ops); - -static u16 ping_port_rover; - -static inline u32 ping_hashfn(const struct net *net, u32 num, u32 mask) -{ - u32 res = (num + net_hash_mix(net)) & mask; - - pr_debug("hash(%u) = %u\n", num, res); - return res; -} -EXPORT_SYMBOL_GPL(ping_hash); - -static inline struct hlist_nulls_head *ping_hashslot(struct ping_table *table, - struct net *net, unsigned int num) -{ - return &table->hash[ping_hashfn(net, num, PING_HTABLE_MASK)]; -} - -int ping_get_port(struct sock *sk, unsigned short ident) -{ - struct hlist_nulls_node *node; - struct hlist_nulls_head *hlist; - struct inet_sock *isk, *isk2; - struct sock *sk2 = NULL; - - isk = inet_sk(sk); - write_lock_bh(&ping_table.lock); - if (ident == 0) { - u32 i; - u16 result = ping_port_rover + 1; - - for (i = 0; i < (1L << 16); i++, result++) { - if (!result) - result++; /* avoid zero */ - hlist = ping_hashslot(&ping_table, sock_net(sk), - result); - ping_portaddr_for_each_entry(sk2, node, hlist) { - isk2 = inet_sk(sk2); - - if (isk2->inet_num == result) - goto next_port; - } - - /* found */ - ping_port_rover = ident = result; - break; -next_port: - ; - } - if (i >= (1L << 16)) - goto fail; - } else { - hlist = ping_hashslot(&ping_table, sock_net(sk), ident); - ping_portaddr_for_each_entry(sk2, node, hlist) { - isk2 = inet_sk(sk2); - - /* BUG? Why is this reuse and not reuseaddr? ping.c - * doesn't turn off SO_REUSEADDR, and it doesn't expect - * that other ping processes can steal its packets. - */ - if ((isk2->inet_num == ident) && - (sk2 != sk) && - (!sk2->sk_reuse || !sk->sk_reuse)) - goto fail; - } - } - - pr_debug("found port/ident = %d\n", ident); - isk->inet_num = ident; - if (sk_unhashed(sk)) { - pr_debug("was not hashed\n"); - sock_hold(sk); - hlist_nulls_add_head(&sk->sk_nulls_node, hlist); - sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); - } - write_unlock_bh(&ping_table.lock); - return 0; - -fail: - write_unlock_bh(&ping_table.lock); - return 1; -} -EXPORT_SYMBOL_GPL(ping_get_port); - -int ping_hash(struct sock *sk) -{ - pr_debug("ping_hash(sk->port=%u)\n", inet_sk(sk)->inet_num); - BUG(); /* "Please do not press this button again." */ - - return 0; -} - -void ping_unhash(struct sock *sk) -{ - struct inet_sock *isk = inet_sk(sk); - pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num); - if (sk_hashed(sk)) { - write_lock_bh(&ping_table.lock); - hlist_nulls_del(&sk->sk_nulls_node); - sk_nulls_node_init(&sk->sk_nulls_node); - sock_put(sk); - isk->inet_num = 0; - isk->inet_sport = 0; - sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); - write_unlock_bh(&ping_table.lock); - } -} -EXPORT_SYMBOL_GPL(ping_unhash); - -static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident) -{ - struct hlist_nulls_head *hslot = ping_hashslot(&ping_table, net, ident); - struct sock *sk = NULL; - struct inet_sock *isk; - struct hlist_nulls_node *hnode; - int dif = skb->dev->ifindex; - - if (skb->protocol == htons(ETH_P_IP)) { - pr_debug("try to find: num = %d, daddr = %pI4, dif = %d\n", - (int)ident, &ip_hdr(skb)->daddr, dif); -#if IS_ENABLED(CONFIG_IPV6) - } else if (skb->protocol == htons(ETH_P_IPV6)) { - pr_debug("try to find: num = %d, daddr = %pI6c, dif = %d\n", - (int)ident, &ipv6_hdr(skb)->daddr, dif); -#endif - } - - read_lock_bh(&ping_table.lock); - - ping_portaddr_for_each_entry(sk, hnode, hslot) { - isk = inet_sk(sk); - - pr_debug("iterate\n"); - if (isk->inet_num != ident) - continue; - - if (skb->protocol == htons(ETH_P_IP) && - sk->sk_family == AF_INET) { - pr_debug("found: %p: num=%d, daddr=%pI4, dif=%d\n", sk, - (int) isk->inet_num, &isk->inet_rcv_saddr, - sk->sk_bound_dev_if); - - if (isk->inet_rcv_saddr && - isk->inet_rcv_saddr != ip_hdr(skb)->daddr) - continue; -#if IS_ENABLED(CONFIG_IPV6) - } else if (skb->protocol == htons(ETH_P_IPV6) && - sk->sk_family == AF_INET6) { - - pr_debug("found: %p: num=%d, daddr=%pI6c, dif=%d\n", sk, - (int) isk->inet_num, - &sk->sk_v6_rcv_saddr, - sk->sk_bound_dev_if); - - if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr) && - !ipv6_addr_equal(&sk->sk_v6_rcv_saddr, - &ipv6_hdr(skb)->daddr)) - continue; -#endif - } else { - continue; - } - - if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif) - continue; - - sock_hold(sk); - goto exit; - } - - sk = NULL; -exit: - read_unlock_bh(&ping_table.lock); - - return sk; -} - -static void inet_get_ping_group_range_net(struct net *net, kgid_t *low, - kgid_t *high) -{ - kgid_t *data = net->ipv4.ping_group_range.range; - unsigned int seq; - - do { - seq = read_seqbegin(&net->ipv4.ping_group_range.lock); - - *low = data[0]; - *high = data[1]; - } while (read_seqretry(&net->ipv4.ping_group_range.lock, seq)); -} - - -int ping_init_sock(struct sock *sk) -{ - struct net *net = sock_net(sk); - kgid_t group = current_egid(); - struct group_info *group_info; - int i; - kgid_t low, high; - int ret = 0; - - if (sk->sk_family == AF_INET6) - sk->sk_ipv6only = 1; - - inet_get_ping_group_range_net(net, &low, &high); - if (gid_lte(low, group) && gid_lte(group, high)) - return 0; - - group_info = get_current_groups(); - for (i = 0; i < group_info->ngroups; i++) { - kgid_t gid = group_info->gid[i]; - - if (gid_lte(low, gid) && gid_lte(gid, high)) - goto out_release_group; - } - - ret = -EACCES; - -out_release_group: - put_group_info(group_info); - return ret; -} -EXPORT_SYMBOL_GPL(ping_init_sock); - -void ping_close(struct sock *sk, long timeout) -{ - pr_debug("ping_close(sk=%p,sk->num=%u)\n", - inet_sk(sk), inet_sk(sk)->inet_num); - pr_debug("isk->refcnt = %d\n", sk->sk_refcnt.counter); - - sk_common_release(sk); -} -EXPORT_SYMBOL_GPL(ping_close); - -/* Checks the bind address and possibly modifies sk->sk_bound_dev_if. */ -static int ping_check_bind_addr(struct sock *sk, struct inet_sock *isk, - struct sockaddr *uaddr, int addr_len) { - struct net *net = sock_net(sk); - if (sk->sk_family == AF_INET) { - struct sockaddr_in *addr = (struct sockaddr_in *) uaddr; - int chk_addr_ret; - - if (addr_len < sizeof(*addr)) - return -EINVAL; - - if (addr->sin_family != AF_INET && - !(addr->sin_family == AF_UNSPEC && - addr->sin_addr.s_addr == htonl(INADDR_ANY))) - return -EAFNOSUPPORT; - - pr_debug("ping_check_bind_addr(sk=%p,addr=%pI4,port=%d)\n", - sk, &addr->sin_addr.s_addr, ntohs(addr->sin_port)); - - chk_addr_ret = inet_addr_type(net, addr->sin_addr.s_addr); - - if (addr->sin_addr.s_addr == htonl(INADDR_ANY)) - chk_addr_ret = RTN_LOCAL; - - if ((net->ipv4.sysctl_ip_nonlocal_bind == 0 && - isk->freebind == 0 && isk->transparent == 0 && - chk_addr_ret != RTN_LOCAL) || - chk_addr_ret == RTN_MULTICAST || - chk_addr_ret == RTN_BROADCAST) - return -EADDRNOTAVAIL; - -#if IS_ENABLED(CONFIG_IPV6) - } else if (sk->sk_family == AF_INET6) { - struct sockaddr_in6 *addr = (struct sockaddr_in6 *) uaddr; - int addr_type, scoped, has_addr; - struct net_device *dev = NULL; - - if (addr_len < sizeof(*addr)) - return -EINVAL; - - if (addr->sin6_family != AF_INET6) - return -EAFNOSUPPORT; - - pr_debug("ping_check_bind_addr(sk=%p,addr=%pI6c,port=%d)\n", - sk, addr->sin6_addr.s6_addr, ntohs(addr->sin6_port)); - - addr_type = ipv6_addr_type(&addr->sin6_addr); - scoped = __ipv6_addr_needs_scope_id(addr_type); - if ((addr_type != IPV6_ADDR_ANY && - !(addr_type & IPV6_ADDR_UNICAST)) || - (scoped && !addr->sin6_scope_id)) - return -EINVAL; - - rcu_read_lock(); - if (addr->sin6_scope_id) { - dev = dev_get_by_index_rcu(net, addr->sin6_scope_id); - if (!dev) { - rcu_read_unlock(); - return -ENODEV; - } - } - has_addr = pingv6_ops.ipv6_chk_addr(net, &addr->sin6_addr, dev, - scoped); - rcu_read_unlock(); - - if (!(net->ipv6.sysctl.ip_nonlocal_bind || - isk->freebind || isk->transparent || has_addr || - addr_type == IPV6_ADDR_ANY)) - return -EADDRNOTAVAIL; - - if (scoped) - sk->sk_bound_dev_if = addr->sin6_scope_id; -#endif - } else { - return -EAFNOSUPPORT; - } - return 0; -} - -static void ping_set_saddr(struct sock *sk, struct sockaddr *saddr) -{ - if (saddr->sa_family == AF_INET) { - struct inet_sock *isk = inet_sk(sk); - struct sockaddr_in *addr = (struct sockaddr_in *) saddr; - isk->inet_rcv_saddr = isk->inet_saddr = addr->sin_addr.s_addr; -#if IS_ENABLED(CONFIG_IPV6) - } else if (saddr->sa_family == AF_INET6) { - struct sockaddr_in6 *addr = (struct sockaddr_in6 *) saddr; - struct ipv6_pinfo *np = inet6_sk(sk); - sk->sk_v6_rcv_saddr = np->saddr = addr->sin6_addr; -#endif - } -} - -static void ping_clear_saddr(struct sock *sk, int dif) -{ - sk->sk_bound_dev_if = dif; - if (sk->sk_family == AF_INET) { - struct inet_sock *isk = inet_sk(sk); - isk->inet_rcv_saddr = isk->inet_saddr = 0; -#if IS_ENABLED(CONFIG_IPV6) - } else if (sk->sk_family == AF_INET6) { - struct ipv6_pinfo *np = inet6_sk(sk); - memset(&sk->sk_v6_rcv_saddr, 0, sizeof(sk->sk_v6_rcv_saddr)); - memset(&np->saddr, 0, sizeof(np->saddr)); -#endif - } -} -/* - * We need our own bind because there are no privileged id's == local ports. - * Moreover, we don't allow binding to multi- and broadcast addresses. - */ - -int ping_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) -{ - struct inet_sock *isk = inet_sk(sk); - unsigned short snum; - int err; - int dif = sk->sk_bound_dev_if; - - err = ping_check_bind_addr(sk, isk, uaddr, addr_len); - if (err) - return err; - - lock_sock(sk); - - err = -EINVAL; - if (isk->inet_num != 0) - goto out; - - err = -EADDRINUSE; - ping_set_saddr(sk, uaddr); - snum = ntohs(((struct sockaddr_in *)uaddr)->sin_port); - if (ping_get_port(sk, snum) != 0) { - ping_clear_saddr(sk, dif); - goto out; - } - - pr_debug("after bind(): num = %d, dif = %d\n", - (int)isk->inet_num, - (int)sk->sk_bound_dev_if); - - err = 0; - if (sk->sk_family == AF_INET && isk->inet_rcv_saddr) - sk->sk_userlocks |= SOCK_BINDADDR_LOCK; -#if IS_ENABLED(CONFIG_IPV6) - if (sk->sk_family == AF_INET6 && !ipv6_addr_any(&sk->sk_v6_rcv_saddr)) - sk->sk_userlocks |= SOCK_BINDADDR_LOCK; -#endif - - if (snum) - sk->sk_userlocks |= SOCK_BINDPORT_LOCK; - isk->inet_sport = htons(isk->inet_num); - isk->inet_daddr = 0; - isk->inet_dport = 0; - -#if IS_ENABLED(CONFIG_IPV6) - if (sk->sk_family == AF_INET6) - memset(&sk->sk_v6_daddr, 0, sizeof(sk->sk_v6_daddr)); -#endif - - sk_dst_reset(sk); -out: - release_sock(sk); - pr_debug("ping_v4_bind -> %d\n", err); - return err; -} -EXPORT_SYMBOL_GPL(ping_bind); - -/* - * Is this a supported type of ICMP message? - */ - -static inline int ping_supported(int family, int type, int code) -{ - return (family == AF_INET && type == ICMP_ECHO && code == 0) || - (family == AF_INET6 && type == ICMPV6_ECHO_REQUEST && code == 0); -} - -/* - * This routine is called by the ICMP module when it gets some - * sort of error condition. - */ - -void ping_err(struct sk_buff *skb, int offset, u32 info) -{ - int family; - struct icmphdr *icmph; - struct inet_sock *inet_sock; - int type; - int code; - struct net *net = dev_net(skb->dev); - struct sock *sk; - int harderr; - int err; - - if (skb->protocol == htons(ETH_P_IP)) { - family = AF_INET; - type = icmp_hdr(skb)->type; - code = icmp_hdr(skb)->code; - icmph = (struct icmphdr *)(skb->data + offset); - } else if (skb->protocol == htons(ETH_P_IPV6)) { - family = AF_INET6; - type = icmp6_hdr(skb)->icmp6_type; - code = icmp6_hdr(skb)->icmp6_code; - icmph = (struct icmphdr *) (skb->data + offset); - } else { - BUG(); - } - - /* We assume the packet has already been checked by icmp_unreach */ - - if (!ping_supported(family, icmph->type, icmph->code)) - return; - - pr_debug("ping_err(proto=0x%x,type=%d,code=%d,id=%04x,seq=%04x)\n", - skb->protocol, type, code, ntohs(icmph->un.echo.id), - ntohs(icmph->un.echo.sequence)); - - sk = ping_lookup(net, skb, ntohs(icmph->un.echo.id)); - if (!sk) { - pr_debug("no socket, dropping\n"); - return; /* No socket for error */ - } - pr_debug("err on socket %p\n", sk); - - err = 0; - harderr = 0; - inet_sock = inet_sk(sk); - - if (skb->protocol == htons(ETH_P_IP)) { - switch (type) { - default: - case ICMP_TIME_EXCEEDED: - err = EHOSTUNREACH; - break; - case ICMP_SOURCE_QUENCH: - /* This is not a real error but ping wants to see it. - * Report it with some fake errno. - */ - err = EREMOTEIO; - break; - case ICMP_PARAMETERPROB: - err = EPROTO; - harderr = 1; - break; - case ICMP_DEST_UNREACH: - if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ - ipv4_sk_update_pmtu(skb, sk, info); - if (inet_sock->pmtudisc != IP_PMTUDISC_DONT) { - err = EMSGSIZE; - harderr = 1; - break; - } - goto out; - } - err = EHOSTUNREACH; - if (code <= NR_ICMP_UNREACH) { - harderr = icmp_err_convert[code].fatal; - err = icmp_err_convert[code].errno; - } - break; - case ICMP_REDIRECT: - /* See ICMP_SOURCE_QUENCH */ - ipv4_sk_redirect(skb, sk); - err = EREMOTEIO; - break; - } -#if IS_ENABLED(CONFIG_IPV6) - } else if (skb->protocol == htons(ETH_P_IPV6)) { - harderr = pingv6_ops.icmpv6_err_convert(type, code, &err); -#endif - } - - /* - * RFC1122: OK. Passes ICMP errors back to application, as per - * 4.1.3.3. - */ - if ((family == AF_INET && !inet_sock->recverr) || - (family == AF_INET6 && !inet6_sk(sk)->recverr)) { - if (!harderr || sk->sk_state != TCP_ESTABLISHED) - goto out; - } else { - if (family == AF_INET) { - ip_icmp_error(sk, skb, err, 0 /* no remote port */, - info, (u8 *)icmph); -#if IS_ENABLED(CONFIG_IPV6) - } else if (family == AF_INET6) { - pingv6_ops.ipv6_icmp_error(sk, skb, err, 0, - info, (u8 *)icmph); -#endif - } - } - sk->sk_err = err; - sk->sk_error_report(sk); -out: - sock_put(sk); -} -EXPORT_SYMBOL_GPL(ping_err); - -/* - * Copy and checksum an ICMP Echo packet from user space into a buffer - * starting from the payload. - */ - -int ping_getfrag(void *from, char *to, - int offset, int fraglen, int odd, struct sk_buff *skb) -{ - struct pingfakehdr *pfh = (struct pingfakehdr *)from; - - if (offset == 0) { - fraglen -= sizeof(struct icmphdr); - if (fraglen < 0) - BUG(); - if (csum_and_copy_from_iter(to + sizeof(struct icmphdr), - fraglen, &pfh->wcheck, - &pfh->msg->msg_iter) != fraglen) - return -EFAULT; - } else if (offset < sizeof(struct icmphdr)) { - BUG(); - } else { - if (csum_and_copy_from_iter(to, fraglen, &pfh->wcheck, - &pfh->msg->msg_iter) != fraglen) - return -EFAULT; - } - -#if IS_ENABLED(CONFIG_IPV6) - /* For IPv6, checksum each skb as we go along, as expected by - * icmpv6_push_pending_frames. For IPv4, accumulate the checksum in - * wcheck, it will be finalized in ping_v4_push_pending_frames. - */ - if (pfh->family == AF_INET6) { - skb->csum = pfh->wcheck; - skb->ip_summed = CHECKSUM_NONE; - pfh->wcheck = 0; - } -#endif - - return 0; -} -EXPORT_SYMBOL_GPL(ping_getfrag); - -static int ping_v4_push_pending_frames(struct sock *sk, struct pingfakehdr *pfh, - struct flowi4 *fl4) -{ - struct sk_buff *skb = skb_peek(&sk->sk_write_queue); - - pfh->wcheck = csum_partial((char *)&pfh->icmph, - sizeof(struct icmphdr), pfh->wcheck); - pfh->icmph.checksum = csum_fold(pfh->wcheck); - memcpy(icmp_hdr(skb), &pfh->icmph, sizeof(struct icmphdr)); - skb->ip_summed = CHECKSUM_NONE; - return ip_push_pending_frames(sk, fl4); -} - -int ping_common_sendmsg(int family, struct msghdr *msg, size_t len, - void *user_icmph, size_t icmph_len) { - u8 type, code; - - if (len > 0xFFFF) - return -EMSGSIZE; - - /* Must have at least a full ICMP header. */ - if (len < icmph_len) - return -EINVAL; - - /* - * Check the flags. - */ - - /* Mirror BSD error message compatibility */ - if (msg->msg_flags & MSG_OOB) - return -EOPNOTSUPP; - - /* - * Fetch the ICMP header provided by the userland. - * iovec is modified! The ICMP header is consumed. - */ - if (memcpy_from_msg(user_icmph, msg, icmph_len)) - return -EFAULT; - - if (family == AF_INET) { - type = ((struct icmphdr *) user_icmph)->type; - code = ((struct icmphdr *) user_icmph)->code; -#if IS_ENABLED(CONFIG_IPV6) - } else if (family == AF_INET6) { - type = ((struct icmp6hdr *) user_icmph)->icmp6_type; - code = ((struct icmp6hdr *) user_icmph)->icmp6_code; -#endif - } else { - BUG(); - } - - if (!ping_supported(family, type, code)) - return -EINVAL; - - return 0; -} -EXPORT_SYMBOL_GPL(ping_common_sendmsg); - -static int ping_v4_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) -{ - struct net *net = sock_net(sk); - struct flowi4 fl4; - struct inet_sock *inet = inet_sk(sk); - struct ipcm_cookie ipc; - struct icmphdr user_icmph; - struct pingfakehdr pfh; - struct rtable *rt = NULL; - struct ip_options_data opt_copy; - int free = 0; - __be32 saddr, daddr, faddr; - u8 tos; - int err; - - pr_debug("ping_v4_sendmsg(sk=%p,sk->num=%u)\n", inet, inet->inet_num); - - err = ping_common_sendmsg(AF_INET, msg, len, &user_icmph, - sizeof(user_icmph)); - if (err) - return err; - - /* - * Get and verify the address. - */ - - if (msg->msg_name) { - DECLARE_SOCKADDR(struct sockaddr_in *, usin, msg->msg_name); - if (msg->msg_namelen < sizeof(*usin)) - return -EINVAL; - if (usin->sin_family != AF_INET) - return -EAFNOSUPPORT; - daddr = usin->sin_addr.s_addr; - /* no remote port */ - } else { - if (sk->sk_state != TCP_ESTABLISHED) - return -EDESTADDRREQ; - daddr = inet->inet_daddr; - /* no remote port */ - } - - ipc.sockc.tsflags = sk->sk_tsflags; - ipc.addr = inet->inet_saddr; - ipc.opt = NULL; - ipc.oif = sk->sk_bound_dev_if; - ipc.tx_flags = 0; - ipc.ttl = 0; - ipc.tos = -1; - - if (msg->msg_controllen) { - err = ip_cmsg_send(sk, msg, &ipc, false); - if (unlikely(err)) { - kfree(ipc.opt); - return err; - } - if (ipc.opt) - free = 1; - } - if (!ipc.opt) { - struct ip_options_rcu *inet_opt; - - rcu_read_lock(); - inet_opt = rcu_dereference(inet->inet_opt); - if (inet_opt) { - memcpy(&opt_copy, inet_opt, - sizeof(*inet_opt) + inet_opt->opt.optlen); - ipc.opt = &opt_copy.opt; - } - rcu_read_unlock(); - } - - sock_tx_timestamp(sk, ipc.sockc.tsflags, &ipc.tx_flags); - - saddr = ipc.addr; - ipc.addr = faddr = daddr; - - if (ipc.opt && ipc.opt->opt.srr) { - if (!daddr) - return -EINVAL; - faddr = ipc.opt->opt.faddr; - } - tos = get_rttos(&ipc, inet); - if (sock_flag(sk, SOCK_LOCALROUTE) || - (msg->msg_flags & MSG_DONTROUTE) || - (ipc.opt && ipc.opt->opt.is_strictroute)) { - tos |= RTO_ONLINK; - } - - if (ipv4_is_multicast(daddr)) { - if (!ipc.oif) - ipc.oif = inet->mc_index; - if (!saddr) - saddr = inet->mc_addr; - } else if (!ipc.oif) - ipc.oif = inet->uc_index; - - flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, - RT_SCOPE_UNIVERSE, sk->sk_protocol, - inet_sk_flowi_flags(sk), faddr, saddr, 0, 0); - - security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); - rt = ip_route_output_flow(net, &fl4, sk); - if (IS_ERR(rt)) { - err = PTR_ERR(rt); - rt = NULL; - if (err == -ENETUNREACH) - IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); - goto out; - } - - err = -EACCES; - if ((rt->rt_flags & RTCF_BROADCAST) && - !sock_flag(sk, SOCK_BROADCAST)) - goto out; - - if (msg->msg_flags & MSG_CONFIRM) - goto do_confirm; -back_from_confirm: - - if (!ipc.addr) - ipc.addr = fl4.daddr; - - lock_sock(sk); - - pfh.icmph.type = user_icmph.type; /* already checked */ - pfh.icmph.code = user_icmph.code; /* ditto */ - pfh.icmph.checksum = 0; - pfh.icmph.un.echo.id = inet->inet_sport; - pfh.icmph.un.echo.sequence = user_icmph.un.echo.sequence; - pfh.msg = msg; - pfh.wcheck = 0; - pfh.family = AF_INET; - - err = ip_append_data(sk, &fl4, ping_getfrag, &pfh, len, - 0, &ipc, &rt, msg->msg_flags); - if (err) - ip_flush_pending_frames(sk); - else - err = ping_v4_push_pending_frames(sk, &pfh, &fl4); - release_sock(sk); - -out: - ip_rt_put(rt); - if (free) - kfree(ipc.opt); - if (!err) { - icmp_out_count(sock_net(sk), user_icmph.type); - return len; - } - return err; - -do_confirm: - dst_confirm(&rt->dst); - if (!(msg->msg_flags & MSG_PROBE) || len) - goto back_from_confirm; - err = 0; - goto out; -} - -int ping_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock, - int flags, int *addr_len) -{ - struct inet_sock *isk = inet_sk(sk); - int family = sk->sk_family; - struct sk_buff *skb; - int copied, err; - - pr_debug("ping_recvmsg(sk=%p,sk->num=%u)\n", isk, isk->inet_num); - - err = -EOPNOTSUPP; - if (flags & MSG_OOB) - goto out; - - if (flags & MSG_ERRQUEUE) - return inet_recv_error(sk, msg, len, addr_len); - - skb = skb_recv_datagram(sk, flags, noblock, &err); - if (!skb) - goto out; - - copied = skb->len; - if (copied > len) { - msg->msg_flags |= MSG_TRUNC; - copied = len; - } - - /* Don't bother checking the checksum */ - err = skb_copy_datagram_msg(skb, 0, msg, copied); - if (err) - goto done; - - sock_recv_timestamp(msg, sk, skb); - - /* Copy the address and add cmsg data. */ - if (family == AF_INET) { - DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name); - - if (sin) { - sin->sin_family = AF_INET; - sin->sin_port = 0 /* skb->h.uh->source */; - sin->sin_addr.s_addr = ip_hdr(skb)->saddr; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - *addr_len = sizeof(*sin); - } - - if (isk->cmsg_flags) - ip_cmsg_recv(msg, skb); - -#if IS_ENABLED(CONFIG_IPV6) - } else if (family == AF_INET6) { - struct ipv6_pinfo *np = inet6_sk(sk); - struct ipv6hdr *ip6 = ipv6_hdr(skb); - DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name); - - if (sin6) { - sin6->sin6_family = AF_INET6; - sin6->sin6_port = 0; - sin6->sin6_addr = ip6->saddr; - sin6->sin6_flowinfo = 0; - if (np->sndflow) - sin6->sin6_flowinfo = ip6_flowinfo(ip6); - sin6->sin6_scope_id = - ipv6_iface_scope_id(&sin6->sin6_addr, - inet6_iif(skb)); - *addr_len = sizeof(*sin6); - } - - if (inet6_sk(sk)->rxopt.all) - pingv6_ops.ip6_datagram_recv_common_ctl(sk, msg, skb); - if (skb->protocol == htons(ETH_P_IPV6) && - inet6_sk(sk)->rxopt.all) - pingv6_ops.ip6_datagram_recv_specific_ctl(sk, msg, skb); - else if (skb->protocol == htons(ETH_P_IP) && isk->cmsg_flags) - ip_cmsg_recv(msg, skb); -#endif - } else { - BUG(); - } - - err = copied; - -done: - skb_free_datagram(sk, skb); -out: - pr_debug("ping_recvmsg -> %d\n", err); - return err; -} -EXPORT_SYMBOL_GPL(ping_recvmsg); - -int ping_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) -{ - pr_debug("ping_queue_rcv_skb(sk=%p,sk->num=%d,skb=%p)\n", - inet_sk(sk), inet_sk(sk)->inet_num, skb); - if (sock_queue_rcv_skb(sk, skb) < 0) { - kfree_skb(skb); - pr_debug("ping_queue_rcv_skb -> failed\n"); - return -1; - } - return 0; -} -EXPORT_SYMBOL_GPL(ping_queue_rcv_skb); - - -/* - * All we need to do is get the socket. - */ - -bool ping_rcv(struct sk_buff *skb) -{ - struct sock *sk; - struct net *net = dev_net(skb->dev); - struct icmphdr *icmph = icmp_hdr(skb); - - /* We assume the packet has already been checked by icmp_rcv */ - - pr_debug("ping_rcv(skb=%p,id=%04x,seq=%04x)\n", - skb, ntohs(icmph->un.echo.id), ntohs(icmph->un.echo.sequence)); - - /* Push ICMP header back */ - skb_push(skb, skb->data - (u8 *)icmph); - - sk = ping_lookup(net, skb, ntohs(icmph->un.echo.id)); - if (sk) { - struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); - - pr_debug("rcv on socket %p\n", sk); - if (skb2) - ping_queue_rcv_skb(sk, skb2); - sock_put(sk); - return true; - } - pr_debug("no socket, dropping\n"); - - return false; -} -EXPORT_SYMBOL_GPL(ping_rcv); - -struct proto ping_prot = { - .name = "PING", - .owner = THIS_MODULE, - .init = ping_init_sock, - .close = ping_close, - .connect = ip4_datagram_connect, - .disconnect = __udp_disconnect, - .setsockopt = ip_setsockopt, - .getsockopt = ip_getsockopt, - .sendmsg = ping_v4_sendmsg, - .recvmsg = ping_recvmsg, - .bind = ping_bind, - .backlog_rcv = ping_queue_rcv_skb, - .release_cb = ip4_datagram_release_cb, - .hash = ping_hash, - .unhash = ping_unhash, - .get_port = ping_get_port, - .obj_size = sizeof(struct inet_sock), -}; -EXPORT_SYMBOL(ping_prot); - -#ifdef CONFIG_PROC_FS - -static struct sock *ping_get_first(struct seq_file *seq, int start) -{ - struct sock *sk; - struct ping_iter_state *state = seq->private; - struct net *net = seq_file_net(seq); - - for (state->bucket = start; state->bucket < PING_HTABLE_SIZE; - ++state->bucket) { - struct hlist_nulls_node *node; - struct hlist_nulls_head *hslot; - - hslot = &ping_table.hash[state->bucket]; - - if (hlist_nulls_empty(hslot)) - continue; - - sk_nulls_for_each(sk, node, hslot) { - if (net_eq(sock_net(sk), net) && - sk->sk_family == state->family) - goto found; - } - } - sk = NULL; -found: - return sk; -} - -static struct sock *ping_get_next(struct seq_file *seq, struct sock *sk) -{ - struct ping_iter_state *state = seq->private; - struct net *net = seq_file_net(seq); - - do { - sk = sk_nulls_next(sk); - } while (sk && (!net_eq(sock_net(sk), net))); - - if (!sk) - return ping_get_first(seq, state->bucket + 1); - return sk; -} - -static struct sock *ping_get_idx(struct seq_file *seq, loff_t pos) -{ - struct sock *sk = ping_get_first(seq, 0); - - if (sk) - while (pos && (sk = ping_get_next(seq, sk)) != NULL) - --pos; - return pos ? NULL : sk; -} - -void *ping_seq_start(struct seq_file *seq, loff_t *pos, sa_family_t family) - __acquires(ping_table.lock) -{ - struct ping_iter_state *state = seq->private; - state->bucket = 0; - state->family = family; - - read_lock_bh(&ping_table.lock); - - return *pos ? ping_get_idx(seq, *pos-1) : SEQ_START_TOKEN; -} -EXPORT_SYMBOL_GPL(ping_seq_start); - -static void *ping_v4_seq_start(struct seq_file *seq, loff_t *pos) -{ - return ping_seq_start(seq, pos, AF_INET); -} - -void *ping_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct sock *sk; - - if (v == SEQ_START_TOKEN) - sk = ping_get_idx(seq, 0); - else - sk = ping_get_next(seq, v); - - ++*pos; - return sk; -} -EXPORT_SYMBOL_GPL(ping_seq_next); - -void ping_seq_stop(struct seq_file *seq, void *v) - __releases(ping_table.lock) -{ - read_unlock_bh(&ping_table.lock); -} -EXPORT_SYMBOL_GPL(ping_seq_stop); - -static void ping_v4_format_sock(struct sock *sp, struct seq_file *f, - int bucket) -{ - struct inet_sock *inet = inet_sk(sp); - __be32 dest = inet->inet_daddr; - __be32 src = inet->inet_rcv_saddr; - __u16 destp = ntohs(inet->inet_dport); - __u16 srcp = ntohs(inet->inet_sport); - - seq_printf(f, "%5d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d", - bucket, src, srcp, dest, destp, sp->sk_state, - sk_wmem_alloc_get(sp), - sk_rmem_alloc_get(sp), - 0, 0L, 0, - from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)), - 0, sock_i_ino(sp), - atomic_read(&sp->sk_refcnt), sp, - atomic_read(&sp->sk_drops)); -} - -static int ping_v4_seq_show(struct seq_file *seq, void *v) -{ - seq_setwidth(seq, 127); - if (v == SEQ_START_TOKEN) - seq_puts(seq, " sl local_address rem_address st tx_queue " - "rx_queue tr tm->when retrnsmt uid timeout " - "inode ref pointer drops"); - else { - struct ping_iter_state *state = seq->private; - - ping_v4_format_sock(v, seq, state->bucket); - } - seq_pad(seq, '\n'); - return 0; -} - -static int ping_seq_open(struct inode *inode, struct file *file) -{ - struct ping_seq_afinfo *afinfo = PDE_DATA(inode); - return seq_open_net(inode, file, &afinfo->seq_ops, - sizeof(struct ping_iter_state)); -} - -const struct file_operations ping_seq_fops = { - .open = ping_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; -EXPORT_SYMBOL_GPL(ping_seq_fops); - -static struct ping_seq_afinfo ping_v4_seq_afinfo = { - .name = "icmp", - .family = AF_INET, - .seq_fops = &ping_seq_fops, - .seq_ops = { - .start = ping_v4_seq_start, - .show = ping_v4_seq_show, - .next = ping_seq_next, - .stop = ping_seq_stop, - }, -}; - -int ping_proc_register(struct net *net, struct ping_seq_afinfo *afinfo) -{ - struct proc_dir_entry *p; - p = proc_create_data(afinfo->name, S_IRUGO, net->proc_net, - afinfo->seq_fops, afinfo); - if (!p) - return -ENOMEM; - return 0; -} -EXPORT_SYMBOL_GPL(ping_proc_register); - -void ping_proc_unregister(struct net *net, struct ping_seq_afinfo *afinfo) -{ - remove_proc_entry(afinfo->name, net->proc_net); -} -EXPORT_SYMBOL_GPL(ping_proc_unregister); - -static int __net_init ping_v4_proc_init_net(struct net *net) -{ - return ping_proc_register(net, &ping_v4_seq_afinfo); -} - -static void __net_exit ping_v4_proc_exit_net(struct net *net) -{ - ping_proc_unregister(net, &ping_v4_seq_afinfo); -} - -static struct pernet_operations ping_v4_net_ops = { - .init = ping_v4_proc_init_net, - .exit = ping_v4_proc_exit_net, -}; - -int __init ping_proc_init(void) -{ - return register_pernet_subsys(&ping_v4_net_ops); -} - -void ping_proc_exit(void) -{ - unregister_pernet_subsys(&ping_v4_net_ops); -} - -#endif - -void __init ping_init(void) -{ - int i; - - for (i = 0; i < PING_HTABLE_SIZE; i++) - INIT_HLIST_NULLS_HEAD(&ping_table.hash[i], i); - rwlock_init(&ping_table.lock); -} diff --git a/src/linux/net/ipv4/proc.c b/src/linux/net/ipv4/proc.c deleted file mode 100644 index 7143ca1..0000000 --- a/src/linux/net/ipv4/proc.c +++ /dev/null @@ -1,569 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * This file implements the various access functions for the - * PROC file system. It is mainly used for debugging and - * statistics. - * - * Authors: Fred N. van Kempen, - * Gerald J. Heim, - * Fred Baumgarten, - * Erik Schoenfelder, - * - * Fixes: - * Alan Cox : UDP sockets show the rxqueue/txqueue - * using hint flag for the netinfo. - * Pauline Middelink : identd support - * Alan Cox : Make /proc safer. - * Erik Schoenfelder : /proc/net/snmp - * Alan Cox : Handle dead sockets properly. - * Gerhard Koerting : Show both timers - * Alan Cox : Allow inode to be NULL (kernel socket) - * Andi Kleen : Add support for open_requests and - * split functions for more readibility. - * Andi Kleen : Add support for /proc/net/netstat - * Arnaldo C. Melo : Convert to seq_file - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define TCPUDP_MIB_MAX max_t(u32, UDP_MIB_MAX, TCP_MIB_MAX) - -/* - * Report socket allocation statistics [mea@utu.fi] - */ -static int sockstat_seq_show(struct seq_file *seq, void *v) -{ - struct net *net = seq->private; - unsigned int frag_mem; - int orphans, sockets; - - local_bh_disable(); - orphans = percpu_counter_sum_positive(&tcp_orphan_count); - sockets = proto_sockets_allocated_sum_positive(&tcp_prot); - local_bh_enable(); - - socket_seq_show(seq); - seq_printf(seq, "TCP: inuse %d orphan %d tw %d alloc %d mem %ld\n", - sock_prot_inuse_get(net, &tcp_prot), orphans, - atomic_read(&tcp_death_row.tw_count), sockets, - proto_memory_allocated(&tcp_prot)); - seq_printf(seq, "UDP: inuse %d mem %ld\n", - sock_prot_inuse_get(net, &udp_prot), - proto_memory_allocated(&udp_prot)); - seq_printf(seq, "UDPLITE: inuse %d\n", - sock_prot_inuse_get(net, &udplite_prot)); - seq_printf(seq, "RAW: inuse %d\n", - sock_prot_inuse_get(net, &raw_prot)); - frag_mem = ip_frag_mem(net); - seq_printf(seq, "FRAG: inuse %u memory %u\n", !!frag_mem, frag_mem); - return 0; -} - -static int sockstat_seq_open(struct inode *inode, struct file *file) -{ - return single_open_net(inode, file, sockstat_seq_show); -} - -static const struct file_operations sockstat_seq_fops = { - .owner = THIS_MODULE, - .open = sockstat_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release_net, -}; - -/* snmp items */ -static const struct snmp_mib snmp4_ipstats_list[] = { - SNMP_MIB_ITEM("InReceives", IPSTATS_MIB_INPKTS), - SNMP_MIB_ITEM("InHdrErrors", IPSTATS_MIB_INHDRERRORS), - SNMP_MIB_ITEM("InAddrErrors", IPSTATS_MIB_INADDRERRORS), - SNMP_MIB_ITEM("ForwDatagrams", IPSTATS_MIB_OUTFORWDATAGRAMS), - SNMP_MIB_ITEM("InUnknownProtos", IPSTATS_MIB_INUNKNOWNPROTOS), - SNMP_MIB_ITEM("InDiscards", IPSTATS_MIB_INDISCARDS), - SNMP_MIB_ITEM("InDelivers", IPSTATS_MIB_INDELIVERS), - SNMP_MIB_ITEM("OutRequests", IPSTATS_MIB_OUTPKTS), - SNMP_MIB_ITEM("OutDiscards", IPSTATS_MIB_OUTDISCARDS), - SNMP_MIB_ITEM("OutNoRoutes", IPSTATS_MIB_OUTNOROUTES), - SNMP_MIB_ITEM("ReasmTimeout", IPSTATS_MIB_REASMTIMEOUT), - SNMP_MIB_ITEM("ReasmReqds", IPSTATS_MIB_REASMREQDS), - SNMP_MIB_ITEM("ReasmOKs", IPSTATS_MIB_REASMOKS), - SNMP_MIB_ITEM("ReasmFails", IPSTATS_MIB_REASMFAILS), - SNMP_MIB_ITEM("FragOKs", IPSTATS_MIB_FRAGOKS), - SNMP_MIB_ITEM("FragFails", IPSTATS_MIB_FRAGFAILS), - SNMP_MIB_ITEM("FragCreates", IPSTATS_MIB_FRAGCREATES), - SNMP_MIB_SENTINEL -}; - -/* Following items are displayed in /proc/net/netstat */ -static const struct snmp_mib snmp4_ipextstats_list[] = { - SNMP_MIB_ITEM("InNoRoutes", IPSTATS_MIB_INNOROUTES), - SNMP_MIB_ITEM("InTruncatedPkts", IPSTATS_MIB_INTRUNCATEDPKTS), - SNMP_MIB_ITEM("InMcastPkts", IPSTATS_MIB_INMCASTPKTS), - SNMP_MIB_ITEM("OutMcastPkts", IPSTATS_MIB_OUTMCASTPKTS), - SNMP_MIB_ITEM("InBcastPkts", IPSTATS_MIB_INBCASTPKTS), - SNMP_MIB_ITEM("OutBcastPkts", IPSTATS_MIB_OUTBCASTPKTS), - SNMP_MIB_ITEM("InOctets", IPSTATS_MIB_INOCTETS), - SNMP_MIB_ITEM("OutOctets", IPSTATS_MIB_OUTOCTETS), - SNMP_MIB_ITEM("InMcastOctets", IPSTATS_MIB_INMCASTOCTETS), - SNMP_MIB_ITEM("OutMcastOctets", IPSTATS_MIB_OUTMCASTOCTETS), - SNMP_MIB_ITEM("InBcastOctets", IPSTATS_MIB_INBCASTOCTETS), - SNMP_MIB_ITEM("OutBcastOctets", IPSTATS_MIB_OUTBCASTOCTETS), - /* Non RFC4293 fields */ - SNMP_MIB_ITEM("InCsumErrors", IPSTATS_MIB_CSUMERRORS), - SNMP_MIB_ITEM("InNoECTPkts", IPSTATS_MIB_NOECTPKTS), - SNMP_MIB_ITEM("InECT1Pkts", IPSTATS_MIB_ECT1PKTS), - SNMP_MIB_ITEM("InECT0Pkts", IPSTATS_MIB_ECT0PKTS), - SNMP_MIB_ITEM("InCEPkts", IPSTATS_MIB_CEPKTS), - SNMP_MIB_SENTINEL -}; - -static const struct { - const char *name; - int index; -} icmpmibmap[] = { - { "DestUnreachs", ICMP_DEST_UNREACH }, - { "TimeExcds", ICMP_TIME_EXCEEDED }, - { "ParmProbs", ICMP_PARAMETERPROB }, - { "SrcQuenchs", ICMP_SOURCE_QUENCH }, - { "Redirects", ICMP_REDIRECT }, - { "Echos", ICMP_ECHO }, - { "EchoReps", ICMP_ECHOREPLY }, - { "Timestamps", ICMP_TIMESTAMP }, - { "TimestampReps", ICMP_TIMESTAMPREPLY }, - { "AddrMasks", ICMP_ADDRESS }, - { "AddrMaskReps", ICMP_ADDRESSREPLY }, - { NULL, 0 } -}; - - -static const struct snmp_mib snmp4_tcp_list[] = { - SNMP_MIB_ITEM("RtoAlgorithm", TCP_MIB_RTOALGORITHM), - SNMP_MIB_ITEM("RtoMin", TCP_MIB_RTOMIN), - SNMP_MIB_ITEM("RtoMax", TCP_MIB_RTOMAX), - SNMP_MIB_ITEM("MaxConn", TCP_MIB_MAXCONN), - SNMP_MIB_ITEM("ActiveOpens", TCP_MIB_ACTIVEOPENS), - SNMP_MIB_ITEM("PassiveOpens", TCP_MIB_PASSIVEOPENS), - SNMP_MIB_ITEM("AttemptFails", TCP_MIB_ATTEMPTFAILS), - SNMP_MIB_ITEM("EstabResets", TCP_MIB_ESTABRESETS), - SNMP_MIB_ITEM("CurrEstab", TCP_MIB_CURRESTAB), - SNMP_MIB_ITEM("InSegs", TCP_MIB_INSEGS), - SNMP_MIB_ITEM("OutSegs", TCP_MIB_OUTSEGS), - SNMP_MIB_ITEM("RetransSegs", TCP_MIB_RETRANSSEGS), - SNMP_MIB_ITEM("InErrs", TCP_MIB_INERRS), - SNMP_MIB_ITEM("OutRsts", TCP_MIB_OUTRSTS), - SNMP_MIB_ITEM("InCsumErrors", TCP_MIB_CSUMERRORS), - SNMP_MIB_SENTINEL -}; - -static const struct snmp_mib snmp4_udp_list[] = { - SNMP_MIB_ITEM("InDatagrams", UDP_MIB_INDATAGRAMS), - SNMP_MIB_ITEM("NoPorts", UDP_MIB_NOPORTS), - SNMP_MIB_ITEM("InErrors", UDP_MIB_INERRORS), - SNMP_MIB_ITEM("OutDatagrams", UDP_MIB_OUTDATAGRAMS), - SNMP_MIB_ITEM("RcvbufErrors", UDP_MIB_RCVBUFERRORS), - SNMP_MIB_ITEM("SndbufErrors", UDP_MIB_SNDBUFERRORS), - SNMP_MIB_ITEM("InCsumErrors", UDP_MIB_CSUMERRORS), - SNMP_MIB_ITEM("IgnoredMulti", UDP_MIB_IGNOREDMULTI), - SNMP_MIB_SENTINEL -}; - -static const struct snmp_mib snmp4_net_list[] = { - SNMP_MIB_ITEM("SyncookiesSent", LINUX_MIB_SYNCOOKIESSENT), - SNMP_MIB_ITEM("SyncookiesRecv", LINUX_MIB_SYNCOOKIESRECV), - SNMP_MIB_ITEM("SyncookiesFailed", LINUX_MIB_SYNCOOKIESFAILED), - SNMP_MIB_ITEM("EmbryonicRsts", LINUX_MIB_EMBRYONICRSTS), - SNMP_MIB_ITEM("PruneCalled", LINUX_MIB_PRUNECALLED), - SNMP_MIB_ITEM("RcvPruned", LINUX_MIB_RCVPRUNED), - SNMP_MIB_ITEM("OfoPruned", LINUX_MIB_OFOPRUNED), - SNMP_MIB_ITEM("OutOfWindowIcmps", LINUX_MIB_OUTOFWINDOWICMPS), - SNMP_MIB_ITEM("LockDroppedIcmps", LINUX_MIB_LOCKDROPPEDICMPS), - SNMP_MIB_ITEM("ArpFilter", LINUX_MIB_ARPFILTER), - SNMP_MIB_ITEM("TW", LINUX_MIB_TIMEWAITED), - SNMP_MIB_ITEM("TWRecycled", LINUX_MIB_TIMEWAITRECYCLED), - SNMP_MIB_ITEM("TWKilled", LINUX_MIB_TIMEWAITKILLED), - SNMP_MIB_ITEM("PAWSPassive", LINUX_MIB_PAWSPASSIVEREJECTED), - SNMP_MIB_ITEM("PAWSActive", LINUX_MIB_PAWSACTIVEREJECTED), - SNMP_MIB_ITEM("PAWSEstab", LINUX_MIB_PAWSESTABREJECTED), - SNMP_MIB_ITEM("DelayedACKs", LINUX_MIB_DELAYEDACKS), - SNMP_MIB_ITEM("DelayedACKLocked", LINUX_MIB_DELAYEDACKLOCKED), - SNMP_MIB_ITEM("DelayedACKLost", LINUX_MIB_DELAYEDACKLOST), - SNMP_MIB_ITEM("ListenOverflows", LINUX_MIB_LISTENOVERFLOWS), - SNMP_MIB_ITEM("ListenDrops", LINUX_MIB_LISTENDROPS), - SNMP_MIB_ITEM("TCPPrequeued", LINUX_MIB_TCPPREQUEUED), - SNMP_MIB_ITEM("TCPDirectCopyFromBacklog", LINUX_MIB_TCPDIRECTCOPYFROMBACKLOG), - SNMP_MIB_ITEM("TCPDirectCopyFromPrequeue", LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE), - SNMP_MIB_ITEM("TCPPrequeueDropped", LINUX_MIB_TCPPREQUEUEDROPPED), - SNMP_MIB_ITEM("TCPHPHits", LINUX_MIB_TCPHPHITS), - SNMP_MIB_ITEM("TCPHPHitsToUser", LINUX_MIB_TCPHPHITSTOUSER), - SNMP_MIB_ITEM("TCPPureAcks", LINUX_MIB_TCPPUREACKS), - SNMP_MIB_ITEM("TCPHPAcks", LINUX_MIB_TCPHPACKS), - SNMP_MIB_ITEM("TCPRenoRecovery", LINUX_MIB_TCPRENORECOVERY), - SNMP_MIB_ITEM("TCPSackRecovery", LINUX_MIB_TCPSACKRECOVERY), - SNMP_MIB_ITEM("TCPSACKReneging", LINUX_MIB_TCPSACKRENEGING), - SNMP_MIB_ITEM("TCPFACKReorder", LINUX_MIB_TCPFACKREORDER), - SNMP_MIB_ITEM("TCPSACKReorder", LINUX_MIB_TCPSACKREORDER), - SNMP_MIB_ITEM("TCPRenoReorder", LINUX_MIB_TCPRENOREORDER), - SNMP_MIB_ITEM("TCPTSReorder", LINUX_MIB_TCPTSREORDER), - SNMP_MIB_ITEM("TCPFullUndo", LINUX_MIB_TCPFULLUNDO), - SNMP_MIB_ITEM("TCPPartialUndo", LINUX_MIB_TCPPARTIALUNDO), - SNMP_MIB_ITEM("TCPDSACKUndo", LINUX_MIB_TCPDSACKUNDO), - SNMP_MIB_ITEM("TCPLossUndo", LINUX_MIB_TCPLOSSUNDO), - SNMP_MIB_ITEM("TCPLostRetransmit", LINUX_MIB_TCPLOSTRETRANSMIT), - SNMP_MIB_ITEM("TCPRenoFailures", LINUX_MIB_TCPRENOFAILURES), - SNMP_MIB_ITEM("TCPSackFailures", LINUX_MIB_TCPSACKFAILURES), - SNMP_MIB_ITEM("TCPLossFailures", LINUX_MIB_TCPLOSSFAILURES), - SNMP_MIB_ITEM("TCPFastRetrans", LINUX_MIB_TCPFASTRETRANS), - SNMP_MIB_ITEM("TCPForwardRetrans", LINUX_MIB_TCPFORWARDRETRANS), - SNMP_MIB_ITEM("TCPSlowStartRetrans", LINUX_MIB_TCPSLOWSTARTRETRANS), - SNMP_MIB_ITEM("TCPTimeouts", LINUX_MIB_TCPTIMEOUTS), - SNMP_MIB_ITEM("TCPLossProbes", LINUX_MIB_TCPLOSSPROBES), - SNMP_MIB_ITEM("TCPLossProbeRecovery", LINUX_MIB_TCPLOSSPROBERECOVERY), - SNMP_MIB_ITEM("TCPRenoRecoveryFail", LINUX_MIB_TCPRENORECOVERYFAIL), - SNMP_MIB_ITEM("TCPSackRecoveryFail", LINUX_MIB_TCPSACKRECOVERYFAIL), - SNMP_MIB_ITEM("TCPSchedulerFailed", LINUX_MIB_TCPSCHEDULERFAILED), - SNMP_MIB_ITEM("TCPRcvCollapsed", LINUX_MIB_TCPRCVCOLLAPSED), - SNMP_MIB_ITEM("TCPDSACKOldSent", LINUX_MIB_TCPDSACKOLDSENT), - SNMP_MIB_ITEM("TCPDSACKOfoSent", LINUX_MIB_TCPDSACKOFOSENT), - SNMP_MIB_ITEM("TCPDSACKRecv", LINUX_MIB_TCPDSACKRECV), - SNMP_MIB_ITEM("TCPDSACKOfoRecv", LINUX_MIB_TCPDSACKOFORECV), - SNMP_MIB_ITEM("TCPAbortOnData", LINUX_MIB_TCPABORTONDATA), - SNMP_MIB_ITEM("TCPAbortOnClose", LINUX_MIB_TCPABORTONCLOSE), - SNMP_MIB_ITEM("TCPAbortOnMemory", LINUX_MIB_TCPABORTONMEMORY), - SNMP_MIB_ITEM("TCPAbortOnTimeout", LINUX_MIB_TCPABORTONTIMEOUT), - SNMP_MIB_ITEM("TCPAbortOnLinger", LINUX_MIB_TCPABORTONLINGER), - SNMP_MIB_ITEM("TCPAbortFailed", LINUX_MIB_TCPABORTFAILED), - SNMP_MIB_ITEM("TCPMemoryPressures", LINUX_MIB_TCPMEMORYPRESSURES), - SNMP_MIB_ITEM("TCPSACKDiscard", LINUX_MIB_TCPSACKDISCARD), - SNMP_MIB_ITEM("TCPDSACKIgnoredOld", LINUX_MIB_TCPDSACKIGNOREDOLD), - SNMP_MIB_ITEM("TCPDSACKIgnoredNoUndo", LINUX_MIB_TCPDSACKIGNOREDNOUNDO), - SNMP_MIB_ITEM("TCPSpuriousRTOs", LINUX_MIB_TCPSPURIOUSRTOS), - SNMP_MIB_ITEM("TCPMD5NotFound", LINUX_MIB_TCPMD5NOTFOUND), - SNMP_MIB_ITEM("TCPMD5Unexpected", LINUX_MIB_TCPMD5UNEXPECTED), - SNMP_MIB_ITEM("TCPMD5Failure", LINUX_MIB_TCPMD5FAILURE), - SNMP_MIB_ITEM("TCPSackShifted", LINUX_MIB_SACKSHIFTED), - SNMP_MIB_ITEM("TCPSackMerged", LINUX_MIB_SACKMERGED), - SNMP_MIB_ITEM("TCPSackShiftFallback", LINUX_MIB_SACKSHIFTFALLBACK), - SNMP_MIB_ITEM("TCPBacklogDrop", LINUX_MIB_TCPBACKLOGDROP), - SNMP_MIB_ITEM("TCPMinTTLDrop", LINUX_MIB_TCPMINTTLDROP), - SNMP_MIB_ITEM("TCPDeferAcceptDrop", LINUX_MIB_TCPDEFERACCEPTDROP), - SNMP_MIB_ITEM("IPReversePathFilter", LINUX_MIB_IPRPFILTER), - SNMP_MIB_ITEM("TCPTimeWaitOverflow", LINUX_MIB_TCPTIMEWAITOVERFLOW), - SNMP_MIB_ITEM("TCPReqQFullDoCookies", LINUX_MIB_TCPREQQFULLDOCOOKIES), - SNMP_MIB_ITEM("TCPReqQFullDrop", LINUX_MIB_TCPREQQFULLDROP), - SNMP_MIB_ITEM("TCPRetransFail", LINUX_MIB_TCPRETRANSFAIL), - SNMP_MIB_ITEM("TCPRcvCoalesce", LINUX_MIB_TCPRCVCOALESCE), - SNMP_MIB_ITEM("TCPOFOQueue", LINUX_MIB_TCPOFOQUEUE), - SNMP_MIB_ITEM("TCPOFODrop", LINUX_MIB_TCPOFODROP), - SNMP_MIB_ITEM("TCPOFOMerge", LINUX_MIB_TCPOFOMERGE), - SNMP_MIB_ITEM("TCPChallengeACK", LINUX_MIB_TCPCHALLENGEACK), - SNMP_MIB_ITEM("TCPSYNChallenge", LINUX_MIB_TCPSYNCHALLENGE), - SNMP_MIB_ITEM("TCPFastOpenActive", LINUX_MIB_TCPFASTOPENACTIVE), - SNMP_MIB_ITEM("TCPFastOpenActiveFail", LINUX_MIB_TCPFASTOPENACTIVEFAIL), - SNMP_MIB_ITEM("TCPFastOpenPassive", LINUX_MIB_TCPFASTOPENPASSIVE), - SNMP_MIB_ITEM("TCPFastOpenPassiveFail", LINUX_MIB_TCPFASTOPENPASSIVEFAIL), - SNMP_MIB_ITEM("TCPFastOpenListenOverflow", LINUX_MIB_TCPFASTOPENLISTENOVERFLOW), - SNMP_MIB_ITEM("TCPFastOpenCookieReqd", LINUX_MIB_TCPFASTOPENCOOKIEREQD), - SNMP_MIB_ITEM("TCPSpuriousRtxHostQueues", LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES), - SNMP_MIB_ITEM("BusyPollRxPackets", LINUX_MIB_BUSYPOLLRXPACKETS), - SNMP_MIB_ITEM("TCPAutoCorking", LINUX_MIB_TCPAUTOCORKING), - SNMP_MIB_ITEM("TCPFromZeroWindowAdv", LINUX_MIB_TCPFROMZEROWINDOWADV), - SNMP_MIB_ITEM("TCPToZeroWindowAdv", LINUX_MIB_TCPTOZEROWINDOWADV), - SNMP_MIB_ITEM("TCPWantZeroWindowAdv", LINUX_MIB_TCPWANTZEROWINDOWADV), - SNMP_MIB_ITEM("TCPSynRetrans", LINUX_MIB_TCPSYNRETRANS), - SNMP_MIB_ITEM("TCPOrigDataSent", LINUX_MIB_TCPORIGDATASENT), - SNMP_MIB_ITEM("TCPHystartTrainDetect", LINUX_MIB_TCPHYSTARTTRAINDETECT), - SNMP_MIB_ITEM("TCPHystartTrainCwnd", LINUX_MIB_TCPHYSTARTTRAINCWND), - SNMP_MIB_ITEM("TCPHystartDelayDetect", LINUX_MIB_TCPHYSTARTDELAYDETECT), - SNMP_MIB_ITEM("TCPHystartDelayCwnd", LINUX_MIB_TCPHYSTARTDELAYCWND), - SNMP_MIB_ITEM("TCPACKSkippedSynRecv", LINUX_MIB_TCPACKSKIPPEDSYNRECV), - SNMP_MIB_ITEM("TCPACKSkippedPAWS", LINUX_MIB_TCPACKSKIPPEDPAWS), - SNMP_MIB_ITEM("TCPACKSkippedSeq", LINUX_MIB_TCPACKSKIPPEDSEQ), - SNMP_MIB_ITEM("TCPACKSkippedFinWait2", LINUX_MIB_TCPACKSKIPPEDFINWAIT2), - SNMP_MIB_ITEM("TCPACKSkippedTimeWait", LINUX_MIB_TCPACKSKIPPEDTIMEWAIT), - SNMP_MIB_ITEM("TCPACKSkippedChallenge", LINUX_MIB_TCPACKSKIPPEDCHALLENGE), - SNMP_MIB_ITEM("TCPWinProbe", LINUX_MIB_TCPWINPROBE), - SNMP_MIB_ITEM("TCPKeepAlive", LINUX_MIB_TCPKEEPALIVE), - SNMP_MIB_ITEM("TCPMTUPFail", LINUX_MIB_TCPMTUPFAIL), - SNMP_MIB_ITEM("TCPMTUPSuccess", LINUX_MIB_TCPMTUPSUCCESS), - SNMP_MIB_SENTINEL -}; - -static void icmpmsg_put_line(struct seq_file *seq, unsigned long *vals, - unsigned short *type, int count) -{ - int j; - - if (count) { - seq_puts(seq, "\nIcmpMsg:"); - for (j = 0; j < count; ++j) - seq_printf(seq, " %sType%u", - type[j] & 0x100 ? "Out" : "In", - type[j] & 0xff); - seq_puts(seq, "\nIcmpMsg:"); - for (j = 0; j < count; ++j) - seq_printf(seq, " %lu", vals[j]); - } -} - -static void icmpmsg_put(struct seq_file *seq) -{ -#define PERLINE 16 - - int i, count; - unsigned short type[PERLINE]; - unsigned long vals[PERLINE], val; - struct net *net = seq->private; - - count = 0; - for (i = 0; i < ICMPMSG_MIB_MAX; i++) { - val = atomic_long_read(&net->mib.icmpmsg_statistics->mibs[i]); - if (val) { - type[count] = i; - vals[count++] = val; - } - if (count == PERLINE) { - icmpmsg_put_line(seq, vals, type, count); - count = 0; - } - } - icmpmsg_put_line(seq, vals, type, count); - -#undef PERLINE -} - -static void icmp_put(struct seq_file *seq) -{ - int i; - struct net *net = seq->private; - atomic_long_t *ptr = net->mib.icmpmsg_statistics->mibs; - - seq_puts(seq, "\nIcmp: InMsgs InErrors InCsumErrors"); - for (i = 0; icmpmibmap[i].name; i++) - seq_printf(seq, " In%s", icmpmibmap[i].name); - seq_puts(seq, " OutMsgs OutErrors"); - for (i = 0; icmpmibmap[i].name; i++) - seq_printf(seq, " Out%s", icmpmibmap[i].name); - seq_printf(seq, "\nIcmp: %lu %lu %lu", - snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_INMSGS), - snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_INERRORS), - snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_CSUMERRORS)); - for (i = 0; icmpmibmap[i].name; i++) - seq_printf(seq, " %lu", - atomic_long_read(ptr + icmpmibmap[i].index)); - seq_printf(seq, " %lu %lu", - snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_OUTMSGS), - snmp_fold_field(net->mib.icmp_statistics, ICMP_MIB_OUTERRORS)); - for (i = 0; icmpmibmap[i].name; i++) - seq_printf(seq, " %lu", - atomic_long_read(ptr + (icmpmibmap[i].index | 0x100))); -} - -/* - * Called from the PROCfs module. This outputs /proc/net/snmp. - */ -static int snmp_seq_show_ipstats(struct seq_file *seq, void *v) -{ - struct net *net = seq->private; - u64 buff64[IPSTATS_MIB_MAX]; - int i; - - memset(buff64, 0, IPSTATS_MIB_MAX * sizeof(u64)); - - seq_puts(seq, "Ip: Forwarding DefaultTTL"); - for (i = 0; snmp4_ipstats_list[i].name; i++) - seq_printf(seq, " %s", snmp4_ipstats_list[i].name); - - seq_printf(seq, "\nIp: %d %d", - IPV4_DEVCONF_ALL(net, FORWARDING) ? 1 : 2, - net->ipv4.sysctl_ip_default_ttl); - - BUILD_BUG_ON(offsetof(struct ipstats_mib, mibs) != 0); - snmp_get_cpu_field64_batch(buff64, snmp4_ipstats_list, - net->mib.ip_statistics, - offsetof(struct ipstats_mib, syncp)); - for (i = 0; snmp4_ipstats_list[i].name; i++) - seq_printf(seq, " %llu", buff64[i]); - - return 0; -} - -static int snmp_seq_show_tcp_udp(struct seq_file *seq, void *v) -{ - unsigned long buff[TCPUDP_MIB_MAX]; - struct net *net = seq->private; - int i; - - memset(buff, 0, TCPUDP_MIB_MAX * sizeof(unsigned long)); - - seq_puts(seq, "\nTcp:"); - for (i = 0; snmp4_tcp_list[i].name; i++) - seq_printf(seq, " %s", snmp4_tcp_list[i].name); - - seq_puts(seq, "\nTcp:"); - snmp_get_cpu_field_batch(buff, snmp4_tcp_list, - net->mib.tcp_statistics); - for (i = 0; snmp4_tcp_list[i].name; i++) { - /* MaxConn field is signed, RFC 2012 */ - if (snmp4_tcp_list[i].entry == TCP_MIB_MAXCONN) - seq_printf(seq, " %ld", buff[i]); - else - seq_printf(seq, " %lu", buff[i]); - } - - memset(buff, 0, TCPUDP_MIB_MAX * sizeof(unsigned long)); - - snmp_get_cpu_field_batch(buff, snmp4_udp_list, - net->mib.udp_statistics); - seq_puts(seq, "\nUdp:"); - for (i = 0; snmp4_udp_list[i].name; i++) - seq_printf(seq, " %s", snmp4_udp_list[i].name); - seq_puts(seq, "\nUdp:"); - for (i = 0; snmp4_udp_list[i].name; i++) - seq_printf(seq, " %lu", buff[i]); - - memset(buff, 0, TCPUDP_MIB_MAX * sizeof(unsigned long)); - - /* the UDP and UDP-Lite MIBs are the same */ - seq_puts(seq, "\nUdpLite:"); - snmp_get_cpu_field_batch(buff, snmp4_udp_list, - net->mib.udplite_statistics); - for (i = 0; snmp4_udp_list[i].name; i++) - seq_printf(seq, " %s", snmp4_udp_list[i].name); - seq_puts(seq, "\nUdpLite:"); - for (i = 0; snmp4_udp_list[i].name; i++) - seq_printf(seq, " %lu", buff[i]); - - seq_putc(seq, '\n'); - return 0; -} - -static int snmp_seq_show(struct seq_file *seq, void *v) -{ - snmp_seq_show_ipstats(seq, v); - - icmp_put(seq); /* RFC 2011 compatibility */ - icmpmsg_put(seq); - - snmp_seq_show_tcp_udp(seq, v); - - return 0; -} - -static int snmp_seq_open(struct inode *inode, struct file *file) -{ - return single_open_net(inode, file, snmp_seq_show); -} - -static const struct file_operations snmp_seq_fops = { - .owner = THIS_MODULE, - .open = snmp_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release_net, -}; - - - -/* - * Output /proc/net/netstat - */ -static int netstat_seq_show(struct seq_file *seq, void *v) -{ - int i; - struct net *net = seq->private; - - seq_puts(seq, "TcpExt:"); - for (i = 0; snmp4_net_list[i].name; i++) - seq_printf(seq, " %s", snmp4_net_list[i].name); - - seq_puts(seq, "\nTcpExt:"); - for (i = 0; snmp4_net_list[i].name; i++) - seq_printf(seq, " %lu", - snmp_fold_field(net->mib.net_statistics, - snmp4_net_list[i].entry)); - - seq_puts(seq, "\nIpExt:"); - for (i = 0; snmp4_ipextstats_list[i].name; i++) - seq_printf(seq, " %s", snmp4_ipextstats_list[i].name); - - seq_puts(seq, "\nIpExt:"); - for (i = 0; snmp4_ipextstats_list[i].name; i++) - seq_printf(seq, " %llu", - snmp_fold_field64(net->mib.ip_statistics, - snmp4_ipextstats_list[i].entry, - offsetof(struct ipstats_mib, syncp))); - - seq_putc(seq, '\n'); - return 0; -} - -static int netstat_seq_open(struct inode *inode, struct file *file) -{ - return single_open_net(inode, file, netstat_seq_show); -} - -static const struct file_operations netstat_seq_fops = { - .owner = THIS_MODULE, - .open = netstat_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release_net, -}; - -static __net_init int ip_proc_init_net(struct net *net) -{ - if (!proc_create("sockstat", S_IRUGO, net->proc_net, - &sockstat_seq_fops)) - goto out_sockstat; - if (!proc_create("netstat", S_IRUGO, net->proc_net, &netstat_seq_fops)) - goto out_netstat; - if (!proc_create("snmp", S_IRUGO, net->proc_net, &snmp_seq_fops)) - goto out_snmp; - - return 0; - -out_snmp: - remove_proc_entry("netstat", net->proc_net); -out_netstat: - remove_proc_entry("sockstat", net->proc_net); -out_sockstat: - return -ENOMEM; -} - -static __net_exit void ip_proc_exit_net(struct net *net) -{ - remove_proc_entry("snmp", net->proc_net); - remove_proc_entry("netstat", net->proc_net); - remove_proc_entry("sockstat", net->proc_net); -} - -static __net_initdata struct pernet_operations ip_proc_ops = { - .init = ip_proc_init_net, - .exit = ip_proc_exit_net, -}; - -int __init ip_misc_proc_init(void) -{ - return register_pernet_subsys(&ip_proc_ops); -} - diff --git a/src/linux/net/ipv4/protocol.c b/src/linux/net/ipv4/protocol.c deleted file mode 100644 index 4b7c0ec..0000000 --- a/src/linux/net/ipv4/protocol.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * INET protocol dispatch tables. - * - * Authors: Ross Biro - * Fred N. van Kempen, - * - * Fixes: - * Alan Cox : Ahah! udp icmp errors don't work because - * udp_err is never called! - * Alan Cox : Added new fields for init and ready for - * proper fragmentation (_NO_ 4K limits!) - * Richard Colella : Hang on hash collision - * Vince Laviano : Modified inet_del_protocol() to correctly - * maintain copy bit. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include -#include -#include - -const struct net_protocol __rcu *inet_protos[MAX_INET_PROTOS] __read_mostly; -const struct net_offload __rcu *inet_offloads[MAX_INET_PROTOS] __read_mostly; -EXPORT_SYMBOL(inet_offloads); - -int inet_add_protocol(const struct net_protocol *prot, unsigned char protocol) -{ - if (!prot->netns_ok) { - pr_err("Protocol %u is not namespace aware, cannot register.\n", - protocol); - return -EINVAL; - } - - return !cmpxchg((const struct net_protocol **)&inet_protos[protocol], - NULL, prot) ? 0 : -1; -} -EXPORT_SYMBOL(inet_add_protocol); - -int inet_add_offload(const struct net_offload *prot, unsigned char protocol) -{ - return !cmpxchg((const struct net_offload **)&inet_offloads[protocol], - NULL, prot) ? 0 : -1; -} -EXPORT_SYMBOL(inet_add_offload); - -int inet_del_protocol(const struct net_protocol *prot, unsigned char protocol) -{ - int ret; - - ret = (cmpxchg((const struct net_protocol **)&inet_protos[protocol], - prot, NULL) == prot) ? 0 : -1; - - synchronize_net(); - - return ret; -} -EXPORT_SYMBOL(inet_del_protocol); - -int inet_del_offload(const struct net_offload *prot, unsigned char protocol) -{ - int ret; - - ret = (cmpxchg((const struct net_offload **)&inet_offloads[protocol], - prot, NULL) == prot) ? 0 : -1; - - synchronize_net(); - - return ret; -} -EXPORT_SYMBOL(inet_del_offload); diff --git a/src/linux/net/ipv4/raw.c b/src/linux/net/ipv4/raw.c deleted file mode 100644 index ecbe5a7..0000000 --- a/src/linux/net/ipv4/raw.c +++ /dev/null @@ -1,1109 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * RAW - implementation of IP "raw" sockets. - * - * Authors: Ross Biro - * Fred N. van Kempen, - * - * Fixes: - * Alan Cox : verify_area() fixed up - * Alan Cox : ICMP error handling - * Alan Cox : EMSGSIZE if you send too big a packet - * Alan Cox : Now uses generic datagrams and shared - * skbuff library. No more peek crashes, - * no more backlogs - * Alan Cox : Checks sk->broadcast. - * Alan Cox : Uses skb_free_datagram/skb_copy_datagram - * Alan Cox : Raw passes ip options too - * Alan Cox : Setsocketopt added - * Alan Cox : Fixed error return for broadcasts - * Alan Cox : Removed wake_up calls - * Alan Cox : Use ttl/tos - * Alan Cox : Cleaned up old debugging - * Alan Cox : Use new kernel side addresses - * Arnt Gulbrandsen : Fixed MSG_DONTROUTE in raw sockets. - * Alan Cox : BSD style RAW socket demultiplexing. - * Alan Cox : Beginnings of mrouted support. - * Alan Cox : Added IP_HDRINCL option. - * Alan Cox : Skip broadcast check if BSDism set. - * David S. Miller : New socket lookup architecture. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct raw_frag_vec { - struct msghdr *msg; - union { - struct icmphdr icmph; - char c[1]; - } hdr; - int hlen; -}; - -static struct raw_hashinfo raw_v4_hashinfo = { - .lock = __RW_LOCK_UNLOCKED(raw_v4_hashinfo.lock), -}; - -int raw_hash_sk(struct sock *sk) -{ - struct raw_hashinfo *h = sk->sk_prot->h.raw_hash; - struct hlist_head *head; - - head = &h->ht[inet_sk(sk)->inet_num & (RAW_HTABLE_SIZE - 1)]; - - write_lock_bh(&h->lock); - sk_add_node(sk, head); - sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); - write_unlock_bh(&h->lock); - - return 0; -} -EXPORT_SYMBOL_GPL(raw_hash_sk); - -void raw_unhash_sk(struct sock *sk) -{ - struct raw_hashinfo *h = sk->sk_prot->h.raw_hash; - - write_lock_bh(&h->lock); - if (sk_del_node_init(sk)) - sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); - write_unlock_bh(&h->lock); -} -EXPORT_SYMBOL_GPL(raw_unhash_sk); - -static struct sock *__raw_v4_lookup(struct net *net, struct sock *sk, - unsigned short num, __be32 raddr, __be32 laddr, int dif) -{ - sk_for_each_from(sk) { - struct inet_sock *inet = inet_sk(sk); - - if (net_eq(sock_net(sk), net) && inet->inet_num == num && - !(inet->inet_daddr && inet->inet_daddr != raddr) && - !(inet->inet_rcv_saddr && inet->inet_rcv_saddr != laddr) && - !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)) - goto found; /* gotcha */ - } - sk = NULL; -found: - return sk; -} - -/* - * 0 - deliver - * 1 - block - */ -static int icmp_filter(const struct sock *sk, const struct sk_buff *skb) -{ - struct icmphdr _hdr; - const struct icmphdr *hdr; - - hdr = skb_header_pointer(skb, skb_transport_offset(skb), - sizeof(_hdr), &_hdr); - if (!hdr) - return 1; - - if (hdr->type < 32) { - __u32 data = raw_sk(sk)->filter.data; - - return ((1U << hdr->type) & data) != 0; - } - - /* Do not block unknown ICMP types */ - return 0; -} - -/* IP input processing comes here for RAW socket delivery. - * Caller owns SKB, so we must make clones. - * - * RFC 1122: SHOULD pass TOS value up to the transport layer. - * -> It does. And not only TOS, but all IP header. - */ -static int raw_v4_input(struct sk_buff *skb, const struct iphdr *iph, int hash) -{ - struct sock *sk; - struct hlist_head *head; - int delivered = 0; - struct net *net; - - read_lock(&raw_v4_hashinfo.lock); - head = &raw_v4_hashinfo.ht[hash]; - if (hlist_empty(head)) - goto out; - - net = dev_net(skb->dev); - sk = __raw_v4_lookup(net, __sk_head(head), iph->protocol, - iph->saddr, iph->daddr, - skb->dev->ifindex); - - while (sk) { - delivered = 1; - if ((iph->protocol != IPPROTO_ICMP || !icmp_filter(sk, skb)) && - ip_mc_sf_allow(sk, iph->daddr, iph->saddr, - skb->dev->ifindex)) { - struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); - - /* Not releasing hash table! */ - if (clone) - raw_rcv(sk, clone); - } - sk = __raw_v4_lookup(net, sk_next(sk), iph->protocol, - iph->saddr, iph->daddr, - skb->dev->ifindex); - } -out: - read_unlock(&raw_v4_hashinfo.lock); - return delivered; -} - -int raw_local_deliver(struct sk_buff *skb, int protocol) -{ - int hash; - struct sock *raw_sk; - - hash = protocol & (RAW_HTABLE_SIZE - 1); - raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]); - - /* If there maybe a raw socket we must check - if not we - * don't care less - */ - if (raw_sk && !raw_v4_input(skb, ip_hdr(skb), hash)) - raw_sk = NULL; - - return raw_sk != NULL; - -} - -static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info) -{ - struct inet_sock *inet = inet_sk(sk); - const int type = icmp_hdr(skb)->type; - const int code = icmp_hdr(skb)->code; - int err = 0; - int harderr = 0; - - if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) - ipv4_sk_update_pmtu(skb, sk, info); - else if (type == ICMP_REDIRECT) { - ipv4_sk_redirect(skb, sk); - return; - } - - /* Report error on raw socket, if: - 1. User requested ip_recverr. - 2. Socket is connected (otherwise the error indication - is useless without ip_recverr and error is hard. - */ - if (!inet->recverr && sk->sk_state != TCP_ESTABLISHED) - return; - - switch (type) { - default: - case ICMP_TIME_EXCEEDED: - err = EHOSTUNREACH; - break; - case ICMP_SOURCE_QUENCH: - return; - case ICMP_PARAMETERPROB: - err = EPROTO; - harderr = 1; - break; - case ICMP_DEST_UNREACH: - err = EHOSTUNREACH; - if (code > NR_ICMP_UNREACH) - break; - err = icmp_err_convert[code].errno; - harderr = icmp_err_convert[code].fatal; - if (code == ICMP_FRAG_NEEDED) { - harderr = inet->pmtudisc != IP_PMTUDISC_DONT; - err = EMSGSIZE; - } - } - - if (inet->recverr) { - const struct iphdr *iph = (const struct iphdr *)skb->data; - u8 *payload = skb->data + (iph->ihl << 2); - - if (inet->hdrincl) - payload = skb->data; - ip_icmp_error(sk, skb, err, 0, info, payload); - } - - if (inet->recverr || harderr) { - sk->sk_err = err; - sk->sk_error_report(sk); - } -} - -void raw_icmp_error(struct sk_buff *skb, int protocol, u32 info) -{ - int hash; - struct sock *raw_sk; - const struct iphdr *iph; - struct net *net; - - hash = protocol & (RAW_HTABLE_SIZE - 1); - - read_lock(&raw_v4_hashinfo.lock); - raw_sk = sk_head(&raw_v4_hashinfo.ht[hash]); - if (raw_sk) { - iph = (const struct iphdr *)skb->data; - net = dev_net(skb->dev); - - while ((raw_sk = __raw_v4_lookup(net, raw_sk, protocol, - iph->daddr, iph->saddr, - skb->dev->ifindex)) != NULL) { - raw_err(raw_sk, skb, info); - raw_sk = sk_next(raw_sk); - iph = (const struct iphdr *)skb->data; - } - } - read_unlock(&raw_v4_hashinfo.lock); -} - -static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb) -{ - /* Charge it to the socket. */ - - ipv4_pktinfo_prepare(sk, skb); - if (sock_queue_rcv_skb(sk, skb) < 0) { - kfree_skb(skb); - return NET_RX_DROP; - } - - return NET_RX_SUCCESS; -} - -int raw_rcv(struct sock *sk, struct sk_buff *skb) -{ - if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) { - atomic_inc(&sk->sk_drops); - kfree_skb(skb); - return NET_RX_DROP; - } - nf_reset(skb); - - skb_push(skb, skb->data - skb_network_header(skb)); - - raw_rcv_skb(sk, skb); - return 0; -} - -static int raw_send_hdrinc(struct sock *sk, struct flowi4 *fl4, - struct msghdr *msg, size_t length, - struct rtable **rtp, unsigned int flags, - const struct sockcm_cookie *sockc) -{ - struct inet_sock *inet = inet_sk(sk); - struct net *net = sock_net(sk); - struct iphdr *iph; - struct sk_buff *skb; - unsigned int iphlen; - int err; - struct rtable *rt = *rtp; - int hlen, tlen; - - if (length > rt->dst.dev->mtu) { - ip_local_error(sk, EMSGSIZE, fl4->daddr, inet->inet_dport, - rt->dst.dev->mtu); - return -EMSGSIZE; - } - if (flags&MSG_PROBE) - goto out; - - hlen = LL_RESERVED_SPACE(rt->dst.dev); - tlen = rt->dst.dev->needed_tailroom; - skb = sock_alloc_send_skb(sk, - length + hlen + tlen + 15, - flags & MSG_DONTWAIT, &err); - if (!skb) - goto error; - skb_reserve(skb, hlen); - - skb->priority = sk->sk_priority; - skb->mark = sk->sk_mark; - skb_dst_set(skb, &rt->dst); - *rtp = NULL; - - skb_reset_network_header(skb); - iph = ip_hdr(skb); - skb_put(skb, length); - - skb->ip_summed = CHECKSUM_NONE; - - sock_tx_timestamp(sk, sockc->tsflags, &skb_shinfo(skb)->tx_flags); - - skb->transport_header = skb->network_header; - err = -EFAULT; - if (memcpy_from_msg(iph, msg, length)) - goto error_free; - - iphlen = iph->ihl * 4; - - /* - * We don't want to modify the ip header, but we do need to - * be sure that it won't cause problems later along the network - * stack. Specifically we want to make sure that iph->ihl is a - * sane value. If ihl points beyond the length of the buffer passed - * in, reject the frame as invalid - */ - err = -EINVAL; - if (iphlen > length) - goto error_free; - - if (iphlen >= sizeof(*iph)) { - if (!iph->saddr) - iph->saddr = fl4->saddr; - iph->check = 0; - iph->tot_len = htons(length); - if (!iph->id) - ip_select_ident(net, skb, NULL); - - iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); - skb->transport_header += iphlen; - if (iph->protocol == IPPROTO_ICMP && - length >= iphlen + sizeof(struct icmphdr)) - icmp_out_count(net, ((struct icmphdr *) - skb_transport_header(skb))->type); - } - - err = NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_OUT, - net, sk, skb, NULL, rt->dst.dev, - dst_output); - if (err > 0) - err = net_xmit_errno(err); - if (err) - goto error; -out: - return 0; - -error_free: - kfree_skb(skb); -error: - IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS); - if (err == -ENOBUFS && !inet->recverr) - err = 0; - return err; -} - -static int raw_probe_proto_opt(struct raw_frag_vec *rfv, struct flowi4 *fl4) -{ - int err; - - if (fl4->flowi4_proto != IPPROTO_ICMP) - return 0; - - /* We only need the first two bytes. */ - rfv->hlen = 2; - - err = memcpy_from_msg(rfv->hdr.c, rfv->msg, rfv->hlen); - if (err) - return err; - - fl4->fl4_icmp_type = rfv->hdr.icmph.type; - fl4->fl4_icmp_code = rfv->hdr.icmph.code; - - return 0; -} - -static int raw_getfrag(void *from, char *to, int offset, int len, int odd, - struct sk_buff *skb) -{ - struct raw_frag_vec *rfv = from; - - if (offset < rfv->hlen) { - int copy = min(rfv->hlen - offset, len); - - if (skb->ip_summed == CHECKSUM_PARTIAL) - memcpy(to, rfv->hdr.c + offset, copy); - else - skb->csum = csum_block_add( - skb->csum, - csum_partial_copy_nocheck(rfv->hdr.c + offset, - to, copy, 0), - odd); - - odd = 0; - offset += copy; - to += copy; - len -= copy; - - if (!len) - return 0; - } - - offset -= rfv->hlen; - - return ip_generic_getfrag(rfv->msg, to, offset, len, odd, skb); -} - -static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) -{ - struct inet_sock *inet = inet_sk(sk); - struct net *net = sock_net(sk); - struct ipcm_cookie ipc; - struct rtable *rt = NULL; - struct flowi4 fl4; - int free = 0; - __be32 daddr; - __be32 saddr; - u8 tos; - int err; - struct ip_options_data opt_copy; - struct raw_frag_vec rfv; - - err = -EMSGSIZE; - if (len > 0xFFFF) - goto out; - - /* - * Check the flags. - */ - - err = -EOPNOTSUPP; - if (msg->msg_flags & MSG_OOB) /* Mirror BSD error message */ - goto out; /* compatibility */ - - /* - * Get and verify the address. - */ - - if (msg->msg_namelen) { - DECLARE_SOCKADDR(struct sockaddr_in *, usin, msg->msg_name); - err = -EINVAL; - if (msg->msg_namelen < sizeof(*usin)) - goto out; - if (usin->sin_family != AF_INET) { - pr_info_once("%s: %s forgot to set AF_INET. Fix it!\n", - __func__, current->comm); - err = -EAFNOSUPPORT; - if (usin->sin_family) - goto out; - } - daddr = usin->sin_addr.s_addr; - /* ANK: I did not forget to get protocol from port field. - * I just do not know, who uses this weirdness. - * IP_HDRINCL is much more convenient. - */ - } else { - err = -EDESTADDRREQ; - if (sk->sk_state != TCP_ESTABLISHED) - goto out; - daddr = inet->inet_daddr; - } - - ipc.sockc.tsflags = sk->sk_tsflags; - ipc.addr = inet->inet_saddr; - ipc.opt = NULL; - ipc.tx_flags = 0; - ipc.ttl = 0; - ipc.tos = -1; - ipc.oif = sk->sk_bound_dev_if; - - if (msg->msg_controllen) { - err = ip_cmsg_send(sk, msg, &ipc, false); - if (unlikely(err)) { - kfree(ipc.opt); - goto out; - } - if (ipc.opt) - free = 1; - } - - saddr = ipc.addr; - ipc.addr = daddr; - - if (!ipc.opt) { - struct ip_options_rcu *inet_opt; - - rcu_read_lock(); - inet_opt = rcu_dereference(inet->inet_opt); - if (inet_opt) { - memcpy(&opt_copy, inet_opt, - sizeof(*inet_opt) + inet_opt->opt.optlen); - ipc.opt = &opt_copy.opt; - } - rcu_read_unlock(); - } - - if (ipc.opt) { - err = -EINVAL; - /* Linux does not mangle headers on raw sockets, - * so that IP options + IP_HDRINCL is non-sense. - */ - if (inet->hdrincl) - goto done; - if (ipc.opt->opt.srr) { - if (!daddr) - goto done; - daddr = ipc.opt->opt.faddr; - } - } - tos = get_rtconn_flags(&ipc, sk); - if (msg->msg_flags & MSG_DONTROUTE) - tos |= RTO_ONLINK; - - if (ipv4_is_multicast(daddr)) { - if (!ipc.oif) - ipc.oif = inet->mc_index; - if (!saddr) - saddr = inet->mc_addr; - } else if (!ipc.oif) - ipc.oif = inet->uc_index; - - flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, - RT_SCOPE_UNIVERSE, - inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, - inet_sk_flowi_flags(sk) | - (inet->hdrincl ? FLOWI_FLAG_KNOWN_NH : 0), - daddr, saddr, 0, 0); - - if (!inet->hdrincl) { - rfv.msg = msg; - rfv.hlen = 0; - - err = raw_probe_proto_opt(&rfv, &fl4); - if (err) - goto done; - } - - security_sk_classify_flow(sk, flowi4_to_flowi(&fl4)); - rt = ip_route_output_flow(net, &fl4, sk); - if (IS_ERR(rt)) { - err = PTR_ERR(rt); - rt = NULL; - goto done; - } - - err = -EACCES; - if (rt->rt_flags & RTCF_BROADCAST && !sock_flag(sk, SOCK_BROADCAST)) - goto done; - - if (msg->msg_flags & MSG_CONFIRM) - goto do_confirm; -back_from_confirm: - - if (inet->hdrincl) - err = raw_send_hdrinc(sk, &fl4, msg, len, - &rt, msg->msg_flags, &ipc.sockc); - - else { - sock_tx_timestamp(sk, ipc.sockc.tsflags, &ipc.tx_flags); - - if (!ipc.addr) - ipc.addr = fl4.daddr; - lock_sock(sk); - err = ip_append_data(sk, &fl4, raw_getfrag, - &rfv, len, 0, - &ipc, &rt, msg->msg_flags); - if (err) - ip_flush_pending_frames(sk); - else if (!(msg->msg_flags & MSG_MORE)) { - err = ip_push_pending_frames(sk, &fl4); - if (err == -ENOBUFS && !inet->recverr) - err = 0; - } - release_sock(sk); - } -done: - if (free) - kfree(ipc.opt); - ip_rt_put(rt); - -out: - if (err < 0) - return err; - return len; - -do_confirm: - dst_confirm(&rt->dst); - if (!(msg->msg_flags & MSG_PROBE) || len) - goto back_from_confirm; - err = 0; - goto done; -} - -static void raw_close(struct sock *sk, long timeout) -{ - /* - * Raw sockets may have direct kernel references. Kill them. - */ - ip_ra_control(sk, 0, NULL); - - sk_common_release(sk); -} - -static void raw_destroy(struct sock *sk) -{ - lock_sock(sk); - ip_flush_pending_frames(sk); - release_sock(sk); -} - -/* This gets rid of all the nasties in af_inet. -DaveM */ -static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) -{ - struct inet_sock *inet = inet_sk(sk); - struct sockaddr_in *addr = (struct sockaddr_in *) uaddr; - int ret = -EINVAL; - int chk_addr_ret; - - if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in)) - goto out; - chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr); - ret = -EADDRNOTAVAIL; - if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL && - chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) - goto out; - inet->inet_rcv_saddr = inet->inet_saddr = addr->sin_addr.s_addr; - if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) - inet->inet_saddr = 0; /* Use device */ - sk_dst_reset(sk); - ret = 0; -out: return ret; -} - -/* - * This should be easy, if there is something there - * we return it, otherwise we block. - */ - -static int raw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, - int noblock, int flags, int *addr_len) -{ - struct inet_sock *inet = inet_sk(sk); - size_t copied = 0; - int err = -EOPNOTSUPP; - DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name); - struct sk_buff *skb; - - if (flags & MSG_OOB) - goto out; - - if (flags & MSG_ERRQUEUE) { - err = ip_recv_error(sk, msg, len, addr_len); - goto out; - } - - skb = skb_recv_datagram(sk, flags, noblock, &err); - if (!skb) - goto out; - - copied = skb->len; - if (len < copied) { - msg->msg_flags |= MSG_TRUNC; - copied = len; - } - - err = skb_copy_datagram_msg(skb, 0, msg, copied); - if (err) - goto done; - - sock_recv_ts_and_drops(msg, sk, skb); - - /* Copy the address. */ - if (sin) { - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = ip_hdr(skb)->saddr; - sin->sin_port = 0; - memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); - *addr_len = sizeof(*sin); - } - if (inet->cmsg_flags) - ip_cmsg_recv(msg, skb); - if (flags & MSG_TRUNC) - copied = skb->len; -done: - skb_free_datagram(sk, skb); -out: - if (err) - return err; - return copied; -} - -static int raw_init(struct sock *sk) -{ - struct raw_sock *rp = raw_sk(sk); - - if (inet_sk(sk)->inet_num == IPPROTO_ICMP) - memset(&rp->filter, 0, sizeof(rp->filter)); - return 0; -} - -static int raw_seticmpfilter(struct sock *sk, char __user *optval, int optlen) -{ - if (optlen > sizeof(struct icmp_filter)) - optlen = sizeof(struct icmp_filter); - if (copy_from_user(&raw_sk(sk)->filter, optval, optlen)) - return -EFAULT; - return 0; -} - -static int raw_geticmpfilter(struct sock *sk, char __user *optval, int __user *optlen) -{ - int len, ret = -EFAULT; - - if (get_user(len, optlen)) - goto out; - ret = -EINVAL; - if (len < 0) - goto out; - if (len > sizeof(struct icmp_filter)) - len = sizeof(struct icmp_filter); - ret = -EFAULT; - if (put_user(len, optlen) || - copy_to_user(optval, &raw_sk(sk)->filter, len)) - goto out; - ret = 0; -out: return ret; -} - -static int do_raw_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen) -{ - if (optname == ICMP_FILTER) { - if (inet_sk(sk)->inet_num != IPPROTO_ICMP) - return -EOPNOTSUPP; - else - return raw_seticmpfilter(sk, optval, optlen); - } - return -ENOPROTOOPT; -} - -static int raw_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen) -{ - if (level != SOL_RAW) - return ip_setsockopt(sk, level, optname, optval, optlen); - return do_raw_setsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -static int compat_raw_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen) -{ - if (level != SOL_RAW) - return compat_ip_setsockopt(sk, level, optname, optval, optlen); - return do_raw_setsockopt(sk, level, optname, optval, optlen); -} -#endif - -static int do_raw_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (optname == ICMP_FILTER) { - if (inet_sk(sk)->inet_num != IPPROTO_ICMP) - return -EOPNOTSUPP; - else - return raw_geticmpfilter(sk, optval, optlen); - } - return -ENOPROTOOPT; -} - -static int raw_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (level != SOL_RAW) - return ip_getsockopt(sk, level, optname, optval, optlen); - return do_raw_getsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -static int compat_raw_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (level != SOL_RAW) - return compat_ip_getsockopt(sk, level, optname, optval, optlen); - return do_raw_getsockopt(sk, level, optname, optval, optlen); -} -#endif - -static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg) -{ - switch (cmd) { - case SIOCOUTQ: { - int amount = sk_wmem_alloc_get(sk); - - return put_user(amount, (int __user *)arg); - } - case SIOCINQ: { - struct sk_buff *skb; - int amount = 0; - - spin_lock_bh(&sk->sk_receive_queue.lock); - skb = skb_peek(&sk->sk_receive_queue); - if (skb) - amount = skb->len; - spin_unlock_bh(&sk->sk_receive_queue.lock); - return put_user(amount, (int __user *)arg); - } - - default: -#ifdef CONFIG_IP_MROUTE - return ipmr_ioctl(sk, cmd, (void __user *)arg); -#else - return -ENOIOCTLCMD; -#endif - } -} - -#ifdef CONFIG_COMPAT -static int compat_raw_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case SIOCOUTQ: - case SIOCINQ: - return -ENOIOCTLCMD; - default: -#ifdef CONFIG_IP_MROUTE - return ipmr_compat_ioctl(sk, cmd, compat_ptr(arg)); -#else - return -ENOIOCTLCMD; -#endif - } -} -#endif - -struct proto raw_prot = { - .name = "RAW", - .owner = THIS_MODULE, - .close = raw_close, - .destroy = raw_destroy, - .connect = ip4_datagram_connect, - .disconnect = __udp_disconnect, - .ioctl = raw_ioctl, - .init = raw_init, - .setsockopt = raw_setsockopt, - .getsockopt = raw_getsockopt, - .sendmsg = raw_sendmsg, - .recvmsg = raw_recvmsg, - .bind = raw_bind, - .backlog_rcv = raw_rcv_skb, - .release_cb = ip4_datagram_release_cb, - .hash = raw_hash_sk, - .unhash = raw_unhash_sk, - .obj_size = sizeof(struct raw_sock), - .h.raw_hash = &raw_v4_hashinfo, -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_raw_setsockopt, - .compat_getsockopt = compat_raw_getsockopt, - .compat_ioctl = compat_raw_ioctl, -#endif -}; - -#ifdef CONFIG_PROC_FS -static struct sock *raw_get_first(struct seq_file *seq) -{ - struct sock *sk; - struct raw_iter_state *state = raw_seq_private(seq); - - for (state->bucket = 0; state->bucket < RAW_HTABLE_SIZE; - ++state->bucket) { - sk_for_each(sk, &state->h->ht[state->bucket]) - if (sock_net(sk) == seq_file_net(seq)) - goto found; - } - sk = NULL; -found: - return sk; -} - -static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk) -{ - struct raw_iter_state *state = raw_seq_private(seq); - - do { - sk = sk_next(sk); -try_again: - ; - } while (sk && sock_net(sk) != seq_file_net(seq)); - - if (!sk && ++state->bucket < RAW_HTABLE_SIZE) { - sk = sk_head(&state->h->ht[state->bucket]); - goto try_again; - } - return sk; -} - -static struct sock *raw_get_idx(struct seq_file *seq, loff_t pos) -{ - struct sock *sk = raw_get_first(seq); - - if (sk) - while (pos && (sk = raw_get_next(seq, sk)) != NULL) - --pos; - return pos ? NULL : sk; -} - -void *raw_seq_start(struct seq_file *seq, loff_t *pos) -{ - struct raw_iter_state *state = raw_seq_private(seq); - - read_lock(&state->h->lock); - return *pos ? raw_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; -} -EXPORT_SYMBOL_GPL(raw_seq_start); - -void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct sock *sk; - - if (v == SEQ_START_TOKEN) - sk = raw_get_first(seq); - else - sk = raw_get_next(seq, v); - ++*pos; - return sk; -} -EXPORT_SYMBOL_GPL(raw_seq_next); - -void raw_seq_stop(struct seq_file *seq, void *v) -{ - struct raw_iter_state *state = raw_seq_private(seq); - - read_unlock(&state->h->lock); -} -EXPORT_SYMBOL_GPL(raw_seq_stop); - -static void raw_sock_seq_show(struct seq_file *seq, struct sock *sp, int i) -{ - struct inet_sock *inet = inet_sk(sp); - __be32 dest = inet->inet_daddr, - src = inet->inet_rcv_saddr; - __u16 destp = 0, - srcp = inet->inet_num; - - seq_printf(seq, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d\n", - i, src, srcp, dest, destp, sp->sk_state, - sk_wmem_alloc_get(sp), - sk_rmem_alloc_get(sp), - 0, 0L, 0, - from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)), - 0, sock_i_ino(sp), - atomic_read(&sp->sk_refcnt), sp, atomic_read(&sp->sk_drops)); -} - -static int raw_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) - seq_printf(seq, " sl local_address rem_address st tx_queue " - "rx_queue tr tm->when retrnsmt uid timeout " - "inode ref pointer drops\n"); - else - raw_sock_seq_show(seq, v, raw_seq_private(seq)->bucket); - return 0; -} - -static const struct seq_operations raw_seq_ops = { - .start = raw_seq_start, - .next = raw_seq_next, - .stop = raw_seq_stop, - .show = raw_seq_show, -}; - -int raw_seq_open(struct inode *ino, struct file *file, - struct raw_hashinfo *h, const struct seq_operations *ops) -{ - int err; - struct raw_iter_state *i; - - err = seq_open_net(ino, file, ops, sizeof(struct raw_iter_state)); - if (err < 0) - return err; - - i = raw_seq_private((struct seq_file *)file->private_data); - i->h = h; - return 0; -} -EXPORT_SYMBOL_GPL(raw_seq_open); - -static int raw_v4_seq_open(struct inode *inode, struct file *file) -{ - return raw_seq_open(inode, file, &raw_v4_hashinfo, &raw_seq_ops); -} - -static const struct file_operations raw_seq_fops = { - .owner = THIS_MODULE, - .open = raw_v4_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -static __net_init int raw_init_net(struct net *net) -{ - if (!proc_create("raw", S_IRUGO, net->proc_net, &raw_seq_fops)) - return -ENOMEM; - - return 0; -} - -static __net_exit void raw_exit_net(struct net *net) -{ - remove_proc_entry("raw", net->proc_net); -} - -static __net_initdata struct pernet_operations raw_net_ops = { - .init = raw_init_net, - .exit = raw_exit_net, -}; - -int __init raw_proc_init(void) -{ - return register_pernet_subsys(&raw_net_ops); -} - -void __init raw_proc_exit(void) -{ - unregister_pernet_subsys(&raw_net_ops); -} -#endif /* CONFIG_PROC_FS */ diff --git a/src/linux/net/ipv4/route.c b/src/linux/net/ipv4/route.c deleted file mode 100644 index 2a57566..0000000 --- a/src/linux/net/ipv4/route.c +++ /dev/null @@ -1,2939 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * ROUTE - implementation of the IP router. - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Alan Cox, - * Linus Torvalds, - * Alexey Kuznetsov, - * - * Fixes: - * Alan Cox : Verify area fixes. - * Alan Cox : cli() protects routing changes - * Rui Oliveira : ICMP routing table updates - * (rco@di.uminho.pt) Routing table insertion and update - * Linus Torvalds : Rewrote bits to be sensible - * Alan Cox : Added BSD route gw semantics - * Alan Cox : Super /proc >4K - * Alan Cox : MTU in route table - * Alan Cox : MSS actually. Also added the window - * clamper. - * Sam Lantinga : Fixed route matching in rt_del() - * Alan Cox : Routing cache support. - * Alan Cox : Removed compatibility cruft. - * Alan Cox : RTF_REJECT support. - * Alan Cox : TCP irtt support. - * Jonathan Naylor : Added Metric support. - * Miquel van Smoorenburg : BSD API fixes. - * Miquel van Smoorenburg : Metrics. - * Alan Cox : Use __u32 properly - * Alan Cox : Aligned routing errors more closely with BSD - * our system is still very different. - * Alan Cox : Faster /proc handling - * Alexey Kuznetsov : Massive rework to support tree based routing, - * routing caches and better behaviour. - * - * Olaf Erb : irtt wasn't being copied right. - * Bjorn Ekwall : Kerneld route support. - * Alan Cox : Multicast fixed (I hope) - * Pavel Krauz : Limited broadcast fixed - * Mike McLagan : Routing by source - * Alexey Kuznetsov : End of old history. Split to fib.c and - * route.c and rewritten from scratch. - * Andi Kleen : Load-limit warning messages. - * Vitaly E. Lavrov : Transparent proxy revived after year coma. - * Vitaly E. Lavrov : Race condition in ip_route_input_slow. - * Tobias Ringstrom : Uninitialized res.type in ip_route_output_slow. - * Vladimir V. Ivanov : IP rule info (flowid) is really useful. - * Marc Boucher : routing by fwmark - * Robert Olsson : Added rt_cache statistics - * Arnaldo C. Melo : Convert proc stuff to seq_file - * Eric Dumazet : hashed spinlocks and rt_check_expire() fixes. - * Ilia Sotnikov : Ignore TOS on PMTUD and Redirect - * Ilia Sotnikov : Removed TOS from hash calculations - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#define pr_fmt(fmt) "IPv4: " fmt - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_SYSCTL -#include -#include -#endif -#include -#include -#include - -#define RT_FL_TOS(oldflp4) \ - ((oldflp4)->flowi4_tos & (IPTOS_RT_MASK | RTO_ONLINK)) - -#define RT_GC_TIMEOUT (300*HZ) - -static int ip_rt_max_size; -static int ip_rt_redirect_number __read_mostly = 9; -static int ip_rt_redirect_load __read_mostly = HZ / 50; -static int ip_rt_redirect_silence __read_mostly = ((HZ / 50) << (9 + 1)); -static int ip_rt_error_cost __read_mostly = HZ; -static int ip_rt_error_burst __read_mostly = 5 * HZ; -static int ip_rt_mtu_expires __read_mostly = 10 * 60 * HZ; -static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; -static int ip_rt_min_advmss __read_mostly = 256; - -static int ip_rt_gc_timeout __read_mostly = RT_GC_TIMEOUT; -/* - * Interface to generic destination cache. - */ - -static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie); -static unsigned int ipv4_default_advmss(const struct dst_entry *dst); -static unsigned int ipv4_mtu(const struct dst_entry *dst); -static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); -static void ipv4_link_failure(struct sk_buff *skb); -static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, - struct sk_buff *skb, u32 mtu); -static void ip_do_redirect(struct dst_entry *dst, struct sock *sk, - struct sk_buff *skb); -static void ipv4_dst_destroy(struct dst_entry *dst); - -static u32 *ipv4_cow_metrics(struct dst_entry *dst, unsigned long old) -{ - WARN_ON(1); - return NULL; -} - -static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst, - struct sk_buff *skb, - const void *daddr); - -static struct dst_ops ipv4_dst_ops = { - .family = AF_INET, - .check = ipv4_dst_check, - .default_advmss = ipv4_default_advmss, - .mtu = ipv4_mtu, - .cow_metrics = ipv4_cow_metrics, - .destroy = ipv4_dst_destroy, - .negative_advice = ipv4_negative_advice, - .link_failure = ipv4_link_failure, - .update_pmtu = ip_rt_update_pmtu, - .redirect = ip_do_redirect, - .local_out = __ip_local_out, - .neigh_lookup = ipv4_neigh_lookup, -}; - -#define ECN_OR_COST(class) TC_PRIO_##class - -const __u8 ip_tos2prio[16] = { - TC_PRIO_BESTEFFORT, - ECN_OR_COST(BESTEFFORT), - TC_PRIO_BESTEFFORT, - ECN_OR_COST(BESTEFFORT), - TC_PRIO_BULK, - ECN_OR_COST(BULK), - TC_PRIO_BULK, - ECN_OR_COST(BULK), - TC_PRIO_INTERACTIVE, - ECN_OR_COST(INTERACTIVE), - TC_PRIO_INTERACTIVE, - ECN_OR_COST(INTERACTIVE), - TC_PRIO_INTERACTIVE_BULK, - ECN_OR_COST(INTERACTIVE_BULK), - TC_PRIO_INTERACTIVE_BULK, - ECN_OR_COST(INTERACTIVE_BULK) -}; -EXPORT_SYMBOL(ip_tos2prio); - -static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat); -#define RT_CACHE_STAT_INC(field) raw_cpu_inc(rt_cache_stat.field) - -#ifdef CONFIG_PROC_FS -static void *rt_cache_seq_start(struct seq_file *seq, loff_t *pos) -{ - if (*pos) - return NULL; - return SEQ_START_TOKEN; -} - -static void *rt_cache_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - ++*pos; - return NULL; -} - -static void rt_cache_seq_stop(struct seq_file *seq, void *v) -{ -} - -static int rt_cache_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) - seq_printf(seq, "%-127s\n", - "Iface\tDestination\tGateway \tFlags\t\tRefCnt\tUse\t" - "Metric\tSource\t\tMTU\tWindow\tIRTT\tTOS\tHHRef\t" - "HHUptod\tSpecDst"); - return 0; -} - -static const struct seq_operations rt_cache_seq_ops = { - .start = rt_cache_seq_start, - .next = rt_cache_seq_next, - .stop = rt_cache_seq_stop, - .show = rt_cache_seq_show, -}; - -static int rt_cache_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &rt_cache_seq_ops); -} - -static const struct file_operations rt_cache_seq_fops = { - .owner = THIS_MODULE, - .open = rt_cache_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - - -static void *rt_cpu_seq_start(struct seq_file *seq, loff_t *pos) -{ - int cpu; - - if (*pos == 0) - return SEQ_START_TOKEN; - - for (cpu = *pos-1; cpu < nr_cpu_ids; ++cpu) { - if (!cpu_possible(cpu)) - continue; - *pos = cpu+1; - return &per_cpu(rt_cache_stat, cpu); - } - return NULL; -} - -static void *rt_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - int cpu; - - for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) { - if (!cpu_possible(cpu)) - continue; - *pos = cpu+1; - return &per_cpu(rt_cache_stat, cpu); - } - return NULL; - -} - -static void rt_cpu_seq_stop(struct seq_file *seq, void *v) -{ - -} - -static int rt_cpu_seq_show(struct seq_file *seq, void *v) -{ - struct rt_cache_stat *st = v; - - if (v == SEQ_START_TOKEN) { - seq_printf(seq, "entries in_hit in_slow_tot in_slow_mc in_no_route in_brd in_martian_dst in_martian_src out_hit out_slow_tot out_slow_mc gc_total gc_ignored gc_goal_miss gc_dst_overflow in_hlist_search out_hlist_search\n"); - return 0; - } - - seq_printf(seq,"%08x %08x %08x %08x %08x %08x %08x %08x " - " %08x %08x %08x %08x %08x %08x %08x %08x %08x \n", - dst_entries_get_slow(&ipv4_dst_ops), - 0, /* st->in_hit */ - st->in_slow_tot, - st->in_slow_mc, - st->in_no_route, - st->in_brd, - st->in_martian_dst, - st->in_martian_src, - - 0, /* st->out_hit */ - st->out_slow_tot, - st->out_slow_mc, - - 0, /* st->gc_total */ - 0, /* st->gc_ignored */ - 0, /* st->gc_goal_miss */ - 0, /* st->gc_dst_overflow */ - 0, /* st->in_hlist_search */ - 0 /* st->out_hlist_search */ - ); - return 0; -} - -static const struct seq_operations rt_cpu_seq_ops = { - .start = rt_cpu_seq_start, - .next = rt_cpu_seq_next, - .stop = rt_cpu_seq_stop, - .show = rt_cpu_seq_show, -}; - - -static int rt_cpu_seq_open(struct inode *inode, struct file *file) -{ - return seq_open(file, &rt_cpu_seq_ops); -} - -static const struct file_operations rt_cpu_seq_fops = { - .owner = THIS_MODULE, - .open = rt_cpu_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release, -}; - -#ifdef CONFIG_IP_ROUTE_CLASSID -static int rt_acct_proc_show(struct seq_file *m, void *v) -{ - struct ip_rt_acct *dst, *src; - unsigned int i, j; - - dst = kcalloc(256, sizeof(struct ip_rt_acct), GFP_KERNEL); - if (!dst) - return -ENOMEM; - - for_each_possible_cpu(i) { - src = (struct ip_rt_acct *)per_cpu_ptr(ip_rt_acct, i); - for (j = 0; j < 256; j++) { - dst[j].o_bytes += src[j].o_bytes; - dst[j].o_packets += src[j].o_packets; - dst[j].i_bytes += src[j].i_bytes; - dst[j].i_packets += src[j].i_packets; - } - } - - seq_write(m, dst, 256 * sizeof(struct ip_rt_acct)); - kfree(dst); - return 0; -} - -static int rt_acct_proc_open(struct inode *inode, struct file *file) -{ - return single_open(file, rt_acct_proc_show, NULL); -} - -static const struct file_operations rt_acct_proc_fops = { - .owner = THIS_MODULE, - .open = rt_acct_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -#endif - -static int __net_init ip_rt_do_proc_init(struct net *net) -{ - struct proc_dir_entry *pde; - - pde = proc_create("rt_cache", S_IRUGO, net->proc_net, - &rt_cache_seq_fops); - if (!pde) - goto err1; - - pde = proc_create("rt_cache", S_IRUGO, - net->proc_net_stat, &rt_cpu_seq_fops); - if (!pde) - goto err2; - -#ifdef CONFIG_IP_ROUTE_CLASSID - pde = proc_create("rt_acct", 0, net->proc_net, &rt_acct_proc_fops); - if (!pde) - goto err3; -#endif - return 0; - -#ifdef CONFIG_IP_ROUTE_CLASSID -err3: - remove_proc_entry("rt_cache", net->proc_net_stat); -#endif -err2: - remove_proc_entry("rt_cache", net->proc_net); -err1: - return -ENOMEM; -} - -static void __net_exit ip_rt_do_proc_exit(struct net *net) -{ - remove_proc_entry("rt_cache", net->proc_net_stat); - remove_proc_entry("rt_cache", net->proc_net); -#ifdef CONFIG_IP_ROUTE_CLASSID - remove_proc_entry("rt_acct", net->proc_net); -#endif -} - -static struct pernet_operations ip_rt_proc_ops __net_initdata = { - .init = ip_rt_do_proc_init, - .exit = ip_rt_do_proc_exit, -}; - -static int __init ip_rt_proc_init(void) -{ - return register_pernet_subsys(&ip_rt_proc_ops); -} - -#else -static inline int ip_rt_proc_init(void) -{ - return 0; -} -#endif /* CONFIG_PROC_FS */ - -static inline bool rt_is_expired(const struct rtable *rth) -{ - return rth->rt_genid != rt_genid_ipv4(dev_net(rth->dst.dev)); -} - -void rt_cache_flush(struct net *net) -{ - rt_genid_bump_ipv4(net); -} - -static struct neighbour *ipv4_neigh_lookup(const struct dst_entry *dst, - struct sk_buff *skb, - const void *daddr) -{ - struct net_device *dev = dst->dev; - const __be32 *pkey = daddr; - const struct rtable *rt; - struct neighbour *n; - - rt = (const struct rtable *) dst; - if (rt->rt_gateway) - pkey = (const __be32 *) &rt->rt_gateway; - else if (skb) - pkey = &ip_hdr(skb)->daddr; - - n = __ipv4_neigh_lookup(dev, *(__force u32 *)pkey); - if (n) - return n; - return neigh_create(&arp_tbl, pkey, dev); -} - -#define IP_IDENTS_SZ 2048u - -static atomic_t *ip_idents __read_mostly; -static u32 *ip_tstamps __read_mostly; - -/* In order to protect privacy, we add a perturbation to identifiers - * if one generator is seldom used. This makes hard for an attacker - * to infer how many packets were sent between two points in time. - */ -u32 ip_idents_reserve(u32 hash, int segs) -{ - u32 *p_tstamp = ip_tstamps + hash % IP_IDENTS_SZ; - atomic_t *p_id = ip_idents + hash % IP_IDENTS_SZ; - u32 old = ACCESS_ONCE(*p_tstamp); - u32 now = (u32)jiffies; - u32 new, delta = 0; - - if (old != now && cmpxchg(p_tstamp, old, now) == old) - delta = prandom_u32_max(now - old); - - /* Do not use atomic_add_return() as it makes UBSAN unhappy */ - do { - old = (u32)atomic_read(p_id); - new = old + delta + segs; - } while (atomic_cmpxchg(p_id, old, new) != old); - - return new - segs; -} -EXPORT_SYMBOL(ip_idents_reserve); - -void __ip_select_ident(struct net *net, struct iphdr *iph, int segs) -{ - static u32 ip_idents_hashrnd __read_mostly; - u32 hash, id; - - net_get_random_once(&ip_idents_hashrnd, sizeof(ip_idents_hashrnd)); - - hash = jhash_3words((__force u32)iph->daddr, - (__force u32)iph->saddr, - iph->protocol ^ net_hash_mix(net), - ip_idents_hashrnd); - id = ip_idents_reserve(hash, segs); - iph->id = htons(id); -} -EXPORT_SYMBOL(__ip_select_ident); - -static void __build_flow_key(struct flowi4 *fl4, const struct sock *sk, - const struct iphdr *iph, - int oif, u8 tos, - u8 prot, u32 mark, int flow_flags) -{ - if (sk) { - const struct inet_sock *inet = inet_sk(sk); - - oif = sk->sk_bound_dev_if; - mark = sk->sk_mark; - tos = RT_CONN_FLAGS(sk); - prot = inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol; - } - flowi4_init_output(fl4, oif, mark, tos, - RT_SCOPE_UNIVERSE, prot, - flow_flags, - iph->daddr, iph->saddr, 0, 0); -} - -static void build_skb_flow_key(struct flowi4 *fl4, const struct sk_buff *skb, - const struct sock *sk) -{ - const struct iphdr *iph = ip_hdr(skb); - int oif = skb->dev->ifindex; - u8 tos = RT_TOS(iph->tos); - u8 prot = iph->protocol; - u32 mark = skb->mark; - - __build_flow_key(fl4, sk, iph, oif, tos, prot, mark, 0); -} - -static void build_sk_flow_key(struct flowi4 *fl4, const struct sock *sk) -{ - const struct inet_sock *inet = inet_sk(sk); - const struct ip_options_rcu *inet_opt; - __be32 daddr = inet->inet_daddr; - - rcu_read_lock(); - inet_opt = rcu_dereference(inet->inet_opt); - if (inet_opt && inet_opt->opt.srr) - daddr = inet_opt->opt.faddr; - flowi4_init_output(fl4, sk->sk_bound_dev_if, sk->sk_mark, - RT_CONN_FLAGS(sk), RT_SCOPE_UNIVERSE, - inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, - inet_sk_flowi_flags(sk), - daddr, inet->inet_saddr, 0, 0); - rcu_read_unlock(); -} - -static void ip_rt_build_flow_key(struct flowi4 *fl4, const struct sock *sk, - const struct sk_buff *skb) -{ - if (skb) - build_skb_flow_key(fl4, skb, sk); - else - build_sk_flow_key(fl4, sk); -} - -static inline void rt_free(struct rtable *rt) -{ - call_rcu(&rt->dst.rcu_head, dst_rcu_free); -} - -static DEFINE_SPINLOCK(fnhe_lock); - -static void fnhe_flush_routes(struct fib_nh_exception *fnhe) -{ - struct rtable *rt; - - rt = rcu_dereference(fnhe->fnhe_rth_input); - if (rt) { - RCU_INIT_POINTER(fnhe->fnhe_rth_input, NULL); - rt_free(rt); - } - rt = rcu_dereference(fnhe->fnhe_rth_output); - if (rt) { - RCU_INIT_POINTER(fnhe->fnhe_rth_output, NULL); - rt_free(rt); - } -} - -static struct fib_nh_exception *fnhe_oldest(struct fnhe_hash_bucket *hash) -{ - struct fib_nh_exception *fnhe, *oldest; - - oldest = rcu_dereference(hash->chain); - for (fnhe = rcu_dereference(oldest->fnhe_next); fnhe; - fnhe = rcu_dereference(fnhe->fnhe_next)) { - if (time_before(fnhe->fnhe_stamp, oldest->fnhe_stamp)) - oldest = fnhe; - } - fnhe_flush_routes(oldest); - return oldest; -} - -static inline u32 fnhe_hashfun(__be32 daddr) -{ - static u32 fnhe_hashrnd __read_mostly; - u32 hval; - - net_get_random_once(&fnhe_hashrnd, sizeof(fnhe_hashrnd)); - hval = jhash_1word((__force u32) daddr, fnhe_hashrnd); - return hash_32(hval, FNHE_HASH_SHIFT); -} - -static void fill_route_from_fnhe(struct rtable *rt, struct fib_nh_exception *fnhe) -{ - rt->rt_pmtu = fnhe->fnhe_pmtu; - rt->dst.expires = fnhe->fnhe_expires; - - if (fnhe->fnhe_gw) { - rt->rt_flags |= RTCF_REDIRECTED; - rt->rt_gateway = fnhe->fnhe_gw; - rt->rt_uses_gateway = 1; - } -} - -static void update_or_create_fnhe(struct fib_nh *nh, __be32 daddr, __be32 gw, - u32 pmtu, unsigned long expires) -{ - struct fnhe_hash_bucket *hash; - struct fib_nh_exception *fnhe; - struct rtable *rt; - unsigned int i; - int depth; - u32 hval = fnhe_hashfun(daddr); - - spin_lock_bh(&fnhe_lock); - - hash = rcu_dereference(nh->nh_exceptions); - if (!hash) { - hash = kzalloc(FNHE_HASH_SIZE * sizeof(*hash), GFP_ATOMIC); - if (!hash) - goto out_unlock; - rcu_assign_pointer(nh->nh_exceptions, hash); - } - - hash += hval; - - depth = 0; - for (fnhe = rcu_dereference(hash->chain); fnhe; - fnhe = rcu_dereference(fnhe->fnhe_next)) { - if (fnhe->fnhe_daddr == daddr) - break; - depth++; - } - - if (fnhe) { - if (gw) - fnhe->fnhe_gw = gw; - if (pmtu) { - fnhe->fnhe_pmtu = pmtu; - fnhe->fnhe_expires = max(1UL, expires); - } - /* Update all cached dsts too */ - rt = rcu_dereference(fnhe->fnhe_rth_input); - if (rt) - fill_route_from_fnhe(rt, fnhe); - rt = rcu_dereference(fnhe->fnhe_rth_output); - if (rt) - fill_route_from_fnhe(rt, fnhe); - } else { - if (depth > FNHE_RECLAIM_DEPTH) - fnhe = fnhe_oldest(hash); - else { - fnhe = kzalloc(sizeof(*fnhe), GFP_ATOMIC); - if (!fnhe) - goto out_unlock; - - fnhe->fnhe_next = hash->chain; - rcu_assign_pointer(hash->chain, fnhe); - } - fnhe->fnhe_genid = fnhe_genid(dev_net(nh->nh_dev)); - fnhe->fnhe_daddr = daddr; - fnhe->fnhe_gw = gw; - fnhe->fnhe_pmtu = pmtu; - fnhe->fnhe_expires = expires; - - /* Exception created; mark the cached routes for the nexthop - * stale, so anyone caching it rechecks if this exception - * applies to them. - */ - rt = rcu_dereference(nh->nh_rth_input); - if (rt) - rt->dst.obsolete = DST_OBSOLETE_KILL; - - for_each_possible_cpu(i) { - struct rtable __rcu **prt; - prt = per_cpu_ptr(nh->nh_pcpu_rth_output, i); - rt = rcu_dereference(*prt); - if (rt) - rt->dst.obsolete = DST_OBSOLETE_KILL; - } - } - - fnhe->fnhe_stamp = jiffies; - -out_unlock: - spin_unlock_bh(&fnhe_lock); -} - -static void __ip_do_redirect(struct rtable *rt, struct sk_buff *skb, struct flowi4 *fl4, - bool kill_route) -{ - __be32 new_gw = icmp_hdr(skb)->un.gateway; - __be32 old_gw = ip_hdr(skb)->saddr; - struct net_device *dev = skb->dev; - struct in_device *in_dev; - struct fib_result res; - struct neighbour *n; - struct net *net; - - switch (icmp_hdr(skb)->code & 7) { - case ICMP_REDIR_NET: - case ICMP_REDIR_NETTOS: - case ICMP_REDIR_HOST: - case ICMP_REDIR_HOSTTOS: - break; - - default: - return; - } - - if (rt->rt_gateway != old_gw) - return; - - in_dev = __in_dev_get_rcu(dev); - if (!in_dev) - return; - - net = dev_net(dev); - if (new_gw == old_gw || !IN_DEV_RX_REDIRECTS(in_dev) || - ipv4_is_multicast(new_gw) || ipv4_is_lbcast(new_gw) || - ipv4_is_zeronet(new_gw)) - goto reject_redirect; - - if (!IN_DEV_SHARED_MEDIA(in_dev)) { - if (!inet_addr_onlink(in_dev, new_gw, old_gw)) - goto reject_redirect; - if (IN_DEV_SEC_REDIRECTS(in_dev) && ip_fib_check_default(new_gw, dev)) - goto reject_redirect; - } else { - if (inet_addr_type(net, new_gw) != RTN_UNICAST) - goto reject_redirect; - } - - n = __ipv4_neigh_lookup(rt->dst.dev, new_gw); - if (!n) - n = neigh_create(&arp_tbl, &new_gw, rt->dst.dev); - if (!IS_ERR(n)) { - if (!(n->nud_state & NUD_VALID)) { - neigh_event_send(n, NULL); - } else { - if (fib_lookup(net, fl4, &res, 0) == 0) { - struct fib_nh *nh = &FIB_RES_NH(res); - - update_or_create_fnhe(nh, fl4->daddr, new_gw, - 0, jiffies + ip_rt_gc_timeout); - } - if (kill_route) - rt->dst.obsolete = DST_OBSOLETE_KILL; - call_netevent_notifiers(NETEVENT_NEIGH_UPDATE, n); - } - neigh_release(n); - } - return; - -reject_redirect: -#ifdef CONFIG_IP_ROUTE_VERBOSE - if (IN_DEV_LOG_MARTIANS(in_dev)) { - const struct iphdr *iph = (const struct iphdr *) skb->data; - __be32 daddr = iph->daddr; - __be32 saddr = iph->saddr; - - net_info_ratelimited("Redirect from %pI4 on %s about %pI4 ignored\n" - " Advised path = %pI4 -> %pI4\n", - &old_gw, dev->name, &new_gw, - &saddr, &daddr); - } -#endif - ; -} - -static void ip_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb) -{ - struct rtable *rt; - struct flowi4 fl4; - const struct iphdr *iph = (const struct iphdr *) skb->data; - int oif = skb->dev->ifindex; - u8 tos = RT_TOS(iph->tos); - u8 prot = iph->protocol; - u32 mark = skb->mark; - - rt = (struct rtable *) dst; - - __build_flow_key(&fl4, sk, iph, oif, tos, prot, mark, 0); - __ip_do_redirect(rt, skb, &fl4, true); -} - -static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) -{ - struct rtable *rt = (struct rtable *)dst; - struct dst_entry *ret = dst; - - if (rt) { - if (dst->obsolete > 0) { - ip_rt_put(rt); - ret = NULL; - } else if ((rt->rt_flags & RTCF_REDIRECTED) || - rt->dst.expires) { - ip_rt_put(rt); - ret = NULL; - } - } - return ret; -} - -/* - * Algorithm: - * 1. The first ip_rt_redirect_number redirects are sent - * with exponential backoff, then we stop sending them at all, - * assuming that the host ignores our redirects. - * 2. If we did not see packets requiring redirects - * during ip_rt_redirect_silence, we assume that the host - * forgot redirected route and start to send redirects again. - * - * This algorithm is much cheaper and more intelligent than dumb load limiting - * in icmp.c. - * - * NOTE. Do not forget to inhibit load limiting for redirects (redundant) - * and "frag. need" (breaks PMTU discovery) in icmp.c. - */ - -void ip_rt_send_redirect(struct sk_buff *skb) -{ - struct rtable *rt = skb_rtable(skb); - struct in_device *in_dev; - struct inet_peer *peer; - struct net *net; - int log_martians; - int vif; - - rcu_read_lock(); - in_dev = __in_dev_get_rcu(rt->dst.dev); - if (!in_dev || !IN_DEV_TX_REDIRECTS(in_dev)) { - rcu_read_unlock(); - return; - } - log_martians = IN_DEV_LOG_MARTIANS(in_dev); - vif = l3mdev_master_ifindex_rcu(rt->dst.dev); - rcu_read_unlock(); - - net = dev_net(rt->dst.dev); - peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr, vif, 1); - if (!peer) { - icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, - rt_nexthop(rt, ip_hdr(skb)->daddr)); - return; - } - - /* No redirected packets during ip_rt_redirect_silence; - * reset the algorithm. - */ - if (time_after(jiffies, peer->rate_last + ip_rt_redirect_silence)) - peer->rate_tokens = 0; - - /* Too many ignored redirects; do not send anything - * set dst.rate_last to the last seen redirected packet. - */ - if (peer->rate_tokens >= ip_rt_redirect_number) { - peer->rate_last = jiffies; - goto out_put_peer; - } - - /* Check for load limit; set rate_last to the latest sent - * redirect. - */ - if (peer->rate_tokens == 0 || - time_after(jiffies, - (peer->rate_last + - (ip_rt_redirect_load << peer->rate_tokens)))) { - __be32 gw = rt_nexthop(rt, ip_hdr(skb)->daddr); - - icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, gw); - peer->rate_last = jiffies; - ++peer->rate_tokens; -#ifdef CONFIG_IP_ROUTE_VERBOSE - if (log_martians && - peer->rate_tokens == ip_rt_redirect_number) - net_warn_ratelimited("host %pI4/if%d ignores redirects for %pI4 to %pI4\n", - &ip_hdr(skb)->saddr, inet_iif(skb), - &ip_hdr(skb)->daddr, &gw); -#endif - } -out_put_peer: - inet_putpeer(peer); -} - -static int ip_error(struct sk_buff *skb) -{ - struct in_device *in_dev = __in_dev_get_rcu(skb->dev); - struct rtable *rt = skb_rtable(skb); - struct inet_peer *peer; - unsigned long now; - struct net *net; - bool send; - int code; - - /* IP on this device is disabled. */ - if (!in_dev) - goto out; - - net = dev_net(rt->dst.dev); - if (!IN_DEV_FORWARD(in_dev)) { - switch (rt->dst.error) { - case EHOSTUNREACH: - __IP_INC_STATS(net, IPSTATS_MIB_INADDRERRORS); - break; - - case ENETUNREACH: - __IP_INC_STATS(net, IPSTATS_MIB_INNOROUTES); - break; - } - goto out; - } - - switch (rt->dst.error) { - case EINVAL: - default: - goto out; - case EHOSTUNREACH: - code = ICMP_HOST_UNREACH; - break; - case ENETUNREACH: - code = ICMP_NET_UNREACH; - __IP_INC_STATS(net, IPSTATS_MIB_INNOROUTES); - break; - case EACCES: - code = ICMP_PKT_FILTERED; - break; - } - - peer = inet_getpeer_v4(net->ipv4.peers, ip_hdr(skb)->saddr, - l3mdev_master_ifindex(skb->dev), 1); - - send = true; - if (peer) { - now = jiffies; - peer->rate_tokens += now - peer->rate_last; - if (peer->rate_tokens > ip_rt_error_burst) - peer->rate_tokens = ip_rt_error_burst; - peer->rate_last = now; - if (peer->rate_tokens >= ip_rt_error_cost) - peer->rate_tokens -= ip_rt_error_cost; - else - send = false; - inet_putpeer(peer); - } - if (send) - icmp_send(skb, ICMP_DEST_UNREACH, code, 0); - -out: kfree_skb(skb); - return 0; -} - -static void __ip_rt_update_pmtu(struct rtable *rt, struct flowi4 *fl4, u32 mtu) -{ - struct dst_entry *dst = &rt->dst; - struct fib_result res; - - if (dst_metric_locked(dst, RTAX_MTU)) - return; - - if (ipv4_mtu(dst) < mtu) - return; - - if (mtu < ip_rt_min_pmtu) - mtu = ip_rt_min_pmtu; - - if (rt->rt_pmtu == mtu && - time_before(jiffies, dst->expires - ip_rt_mtu_expires / 2)) - return; - - rcu_read_lock(); - if (fib_lookup(dev_net(dst->dev), fl4, &res, 0) == 0) { - struct fib_nh *nh = &FIB_RES_NH(res); - - update_or_create_fnhe(nh, fl4->daddr, 0, mtu, - jiffies + ip_rt_mtu_expires); - } - rcu_read_unlock(); -} - -static void ip_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, - struct sk_buff *skb, u32 mtu) -{ - struct rtable *rt = (struct rtable *) dst; - struct flowi4 fl4; - - ip_rt_build_flow_key(&fl4, sk, skb); - __ip_rt_update_pmtu(rt, &fl4, mtu); -} - -void ipv4_update_pmtu(struct sk_buff *skb, struct net *net, u32 mtu, - int oif, u32 mark, u8 protocol, int flow_flags) -{ - const struct iphdr *iph = (const struct iphdr *) skb->data; - struct flowi4 fl4; - struct rtable *rt; - - if (!mark) - mark = IP4_REPLY_MARK(net, skb->mark); - - __build_flow_key(&fl4, NULL, iph, oif, - RT_TOS(iph->tos), protocol, mark, flow_flags); - rt = __ip_route_output_key(net, &fl4); - if (!IS_ERR(rt)) { - __ip_rt_update_pmtu(rt, &fl4, mtu); - ip_rt_put(rt); - } -} -EXPORT_SYMBOL_GPL(ipv4_update_pmtu); - -static void __ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) -{ - const struct iphdr *iph = (const struct iphdr *) skb->data; - struct flowi4 fl4; - struct rtable *rt; - - __build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0); - - if (!fl4.flowi4_mark) - fl4.flowi4_mark = IP4_REPLY_MARK(sock_net(sk), skb->mark); - - rt = __ip_route_output_key(sock_net(sk), &fl4); - if (!IS_ERR(rt)) { - __ip_rt_update_pmtu(rt, &fl4, mtu); - ip_rt_put(rt); - } -} - -void ipv4_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, u32 mtu) -{ - const struct iphdr *iph = (const struct iphdr *) skb->data; - struct flowi4 fl4; - struct rtable *rt; - struct dst_entry *odst = NULL; - bool new = false; - - bh_lock_sock(sk); - - if (!ip_sk_accept_pmtu(sk)) - goto out; - - odst = sk_dst_get(sk); - - if (sock_owned_by_user(sk) || !odst) { - __ipv4_sk_update_pmtu(skb, sk, mtu); - goto out; - } - - __build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0); - - rt = (struct rtable *)odst; - if (odst->obsolete && !odst->ops->check(odst, 0)) { - rt = ip_route_output_flow(sock_net(sk), &fl4, sk); - if (IS_ERR(rt)) - goto out; - - new = true; - } - - __ip_rt_update_pmtu((struct rtable *) rt->dst.path, &fl4, mtu); - - if (!dst_check(&rt->dst, 0)) { - if (new) - dst_release(&rt->dst); - - rt = ip_route_output_flow(sock_net(sk), &fl4, sk); - if (IS_ERR(rt)) - goto out; - - new = true; - } - - if (new) - sk_dst_set(sk, &rt->dst); - -out: - bh_unlock_sock(sk); - dst_release(odst); -} -EXPORT_SYMBOL_GPL(ipv4_sk_update_pmtu); - -void ipv4_redirect(struct sk_buff *skb, struct net *net, - int oif, u32 mark, u8 protocol, int flow_flags) -{ - const struct iphdr *iph = (const struct iphdr *) skb->data; - struct flowi4 fl4; - struct rtable *rt; - - __build_flow_key(&fl4, NULL, iph, oif, - RT_TOS(iph->tos), protocol, mark, flow_flags); - rt = __ip_route_output_key(net, &fl4); - if (!IS_ERR(rt)) { - __ip_do_redirect(rt, skb, &fl4, false); - ip_rt_put(rt); - } -} -EXPORT_SYMBOL_GPL(ipv4_redirect); - -void ipv4_sk_redirect(struct sk_buff *skb, struct sock *sk) -{ - const struct iphdr *iph = (const struct iphdr *) skb->data; - struct flowi4 fl4; - struct rtable *rt; - - __build_flow_key(&fl4, sk, iph, 0, 0, 0, 0, 0); - rt = __ip_route_output_key(sock_net(sk), &fl4); - if (!IS_ERR(rt)) { - __ip_do_redirect(rt, skb, &fl4, false); - ip_rt_put(rt); - } -} -EXPORT_SYMBOL_GPL(ipv4_sk_redirect); - -static struct dst_entry *ipv4_dst_check(struct dst_entry *dst, u32 cookie) -{ - struct rtable *rt = (struct rtable *) dst; - - /* All IPV4 dsts are created with ->obsolete set to the value - * DST_OBSOLETE_FORCE_CHK which forces validation calls down - * into this function always. - * - * When a PMTU/redirect information update invalidates a route, - * this is indicated by setting obsolete to DST_OBSOLETE_KILL or - * DST_OBSOLETE_DEAD by dst_free(). - */ - if (dst->obsolete != DST_OBSOLETE_FORCE_CHK || rt_is_expired(rt)) - return NULL; - return dst; -} - -static void ipv4_link_failure(struct sk_buff *skb) -{ - struct rtable *rt; - - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, 0); - - rt = skb_rtable(skb); - if (rt) - dst_set_expires(&rt->dst, 0); -} - -static int ip_rt_bug(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - pr_debug("%s: %pI4 -> %pI4, %s\n", - __func__, &ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr, - skb->dev ? skb->dev->name : "?"); - kfree_skb(skb); - WARN_ON(1); - return 0; -} - -/* - We do not cache source address of outgoing interface, - because it is used only by IP RR, TS and SRR options, - so that it out of fast path. - - BTW remember: "addr" is allowed to be not aligned - in IP options! - */ - -void ip_rt_get_source(u8 *addr, struct sk_buff *skb, struct rtable *rt) -{ - __be32 src; - - if (rt_is_output_route(rt)) - src = ip_hdr(skb)->saddr; - else { - struct fib_result res; - struct flowi4 fl4; - struct iphdr *iph; - - iph = ip_hdr(skb); - - memset(&fl4, 0, sizeof(fl4)); - fl4.daddr = iph->daddr; - fl4.saddr = iph->saddr; - fl4.flowi4_tos = RT_TOS(iph->tos); - fl4.flowi4_oif = rt->dst.dev->ifindex; - fl4.flowi4_iif = skb->dev->ifindex; - fl4.flowi4_mark = skb->mark; - - rcu_read_lock(); - if (fib_lookup(dev_net(rt->dst.dev), &fl4, &res, 0) == 0) - src = FIB_RES_PREFSRC(dev_net(rt->dst.dev), res); - else - src = inet_select_addr(rt->dst.dev, - rt_nexthop(rt, iph->daddr), - RT_SCOPE_UNIVERSE); - rcu_read_unlock(); - } - memcpy(addr, &src, 4); -} - -#ifdef CONFIG_IP_ROUTE_CLASSID -static void set_class_tag(struct rtable *rt, u32 tag) -{ - if (!(rt->dst.tclassid & 0xFFFF)) - rt->dst.tclassid |= tag & 0xFFFF; - if (!(rt->dst.tclassid & 0xFFFF0000)) - rt->dst.tclassid |= tag & 0xFFFF0000; -} -#endif - -static unsigned int ipv4_default_advmss(const struct dst_entry *dst) -{ - unsigned int advmss = dst_metric_raw(dst, RTAX_ADVMSS); - - if (advmss == 0) { - advmss = max_t(unsigned int, dst->dev->mtu - 40, - ip_rt_min_advmss); - if (advmss > 65535 - 40) - advmss = 65535 - 40; - } - return advmss; -} - -static unsigned int ipv4_mtu(const struct dst_entry *dst) -{ - const struct rtable *rt = (const struct rtable *) dst; - unsigned int mtu = rt->rt_pmtu; - - if (!mtu || time_after_eq(jiffies, rt->dst.expires)) - mtu = dst_metric_raw(dst, RTAX_MTU); - - if (mtu) - return mtu; - - mtu = dst->dev->mtu; - - if (unlikely(dst_metric_locked(dst, RTAX_MTU))) { - if (rt->rt_uses_gateway && mtu > 576) - mtu = 576; - } - - mtu = min_t(unsigned int, mtu, IP_MAX_MTU); - - return mtu - lwtunnel_headroom(dst->lwtstate, mtu); -} - -static struct fib_nh_exception *find_exception(struct fib_nh *nh, __be32 daddr) -{ - struct fnhe_hash_bucket *hash = rcu_dereference(nh->nh_exceptions); - struct fib_nh_exception *fnhe; - u32 hval; - - if (!hash) - return NULL; - - hval = fnhe_hashfun(daddr); - - for (fnhe = rcu_dereference(hash[hval].chain); fnhe; - fnhe = rcu_dereference(fnhe->fnhe_next)) { - if (fnhe->fnhe_daddr == daddr) - return fnhe; - } - return NULL; -} - -static bool rt_bind_exception(struct rtable *rt, struct fib_nh_exception *fnhe, - __be32 daddr) -{ - bool ret = false; - - spin_lock_bh(&fnhe_lock); - - if (daddr == fnhe->fnhe_daddr) { - struct rtable __rcu **porig; - struct rtable *orig; - int genid = fnhe_genid(dev_net(rt->dst.dev)); - - if (rt_is_input_route(rt)) - porig = &fnhe->fnhe_rth_input; - else - porig = &fnhe->fnhe_rth_output; - orig = rcu_dereference(*porig); - - if (fnhe->fnhe_genid != genid) { - fnhe->fnhe_genid = genid; - fnhe->fnhe_gw = 0; - fnhe->fnhe_pmtu = 0; - fnhe->fnhe_expires = 0; - fnhe_flush_routes(fnhe); - orig = NULL; - } - fill_route_from_fnhe(rt, fnhe); - if (!rt->rt_gateway) - rt->rt_gateway = daddr; - - if (!(rt->dst.flags & DST_NOCACHE)) { - rcu_assign_pointer(*porig, rt); - if (orig) - rt_free(orig); - ret = true; - } - - fnhe->fnhe_stamp = jiffies; - } - spin_unlock_bh(&fnhe_lock); - - return ret; -} - -static bool rt_cache_route(struct fib_nh *nh, struct rtable *rt) -{ - struct rtable *orig, *prev, **p; - bool ret = true; - - if (rt_is_input_route(rt)) { - p = (struct rtable **)&nh->nh_rth_input; - } else { - p = (struct rtable **)raw_cpu_ptr(nh->nh_pcpu_rth_output); - } - orig = *p; - - prev = cmpxchg(p, orig, rt); - if (prev == orig) { - if (orig) - rt_free(orig); - } else - ret = false; - - return ret; -} - -struct uncached_list { - spinlock_t lock; - struct list_head head; -}; - -static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt_uncached_list); - -static void rt_add_uncached_list(struct rtable *rt) -{ - struct uncached_list *ul = raw_cpu_ptr(&rt_uncached_list); - - rt->rt_uncached_list = ul; - - spin_lock_bh(&ul->lock); - list_add_tail(&rt->rt_uncached, &ul->head); - spin_unlock_bh(&ul->lock); -} - -static void ipv4_dst_destroy(struct dst_entry *dst) -{ - struct rtable *rt = (struct rtable *) dst; - - if (!list_empty(&rt->rt_uncached)) { - struct uncached_list *ul = rt->rt_uncached_list; - - spin_lock_bh(&ul->lock); - list_del(&rt->rt_uncached); - spin_unlock_bh(&ul->lock); - } -} - -void rt_flush_dev(struct net_device *dev) -{ - struct net *net = dev_net(dev); - struct rtable *rt; - int cpu; - - for_each_possible_cpu(cpu) { - struct uncached_list *ul = &per_cpu(rt_uncached_list, cpu); - - spin_lock_bh(&ul->lock); - list_for_each_entry(rt, &ul->head, rt_uncached) { - if (rt->dst.dev != dev) - continue; - rt->dst.dev = net->loopback_dev; - dev_hold(rt->dst.dev); - dev_put(dev); - } - spin_unlock_bh(&ul->lock); - } -} - -static bool rt_cache_valid(const struct rtable *rt) -{ - return rt && - rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK && - !rt_is_expired(rt); -} - -static void rt_set_nexthop(struct rtable *rt, __be32 daddr, - const struct fib_result *res, - struct fib_nh_exception *fnhe, - struct fib_info *fi, u16 type, u32 itag) -{ - bool cached = false; - - if (fi) { - struct fib_nh *nh = &FIB_RES_NH(*res); - - if (nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK) { - rt->rt_gateway = nh->nh_gw; - rt->rt_uses_gateway = 1; - } - dst_init_metrics(&rt->dst, fi->fib_metrics, true); -#ifdef CONFIG_IP_ROUTE_CLASSID - rt->dst.tclassid = nh->nh_tclassid; -#endif - rt->dst.lwtstate = lwtstate_get(nh->nh_lwtstate); - if (unlikely(fnhe)) - cached = rt_bind_exception(rt, fnhe, daddr); - else if (!(rt->dst.flags & DST_NOCACHE)) - cached = rt_cache_route(nh, rt); - if (unlikely(!cached)) { - /* Routes we intend to cache in nexthop exception or - * FIB nexthop have the DST_NOCACHE bit clear. - * However, if we are unsuccessful at storing this - * route into the cache we really need to set it. - */ - rt->dst.flags |= DST_NOCACHE; - if (!rt->rt_gateway) - rt->rt_gateway = daddr; - rt_add_uncached_list(rt); - } - } else - rt_add_uncached_list(rt); - -#ifdef CONFIG_IP_ROUTE_CLASSID -#ifdef CONFIG_IP_MULTIPLE_TABLES - set_class_tag(rt, res->tclassid); -#endif - set_class_tag(rt, itag); -#endif -} - -struct rtable *rt_dst_alloc(struct net_device *dev, - unsigned int flags, u16 type, - bool nopolicy, bool noxfrm, bool will_cache) -{ - struct rtable *rt; - - rt = dst_alloc(&ipv4_dst_ops, dev, 1, DST_OBSOLETE_FORCE_CHK, - (will_cache ? 0 : (DST_HOST | DST_NOCACHE)) | - (nopolicy ? DST_NOPOLICY : 0) | - (noxfrm ? DST_NOXFRM : 0)); - - if (rt) { - rt->rt_genid = rt_genid_ipv4(dev_net(dev)); - rt->rt_flags = flags; - rt->rt_type = type; - rt->rt_is_input = 0; - rt->rt_iif = 0; - rt->rt_pmtu = 0; - rt->rt_gateway = 0; - rt->rt_uses_gateway = 0; - rt->rt_table_id = 0; - INIT_LIST_HEAD(&rt->rt_uncached); - - rt->dst.output = ip_output; - if (flags & RTCF_LOCAL) - rt->dst.input = ip_local_deliver; - } - - return rt; -} -EXPORT_SYMBOL(rt_dst_alloc); - -/* called in rcu_read_lock() section */ -static int ip_route_input_mc(struct sk_buff *skb, __be32 daddr, __be32 saddr, - u8 tos, struct net_device *dev, int our) -{ - struct rtable *rth; - struct in_device *in_dev = __in_dev_get_rcu(dev); - unsigned int flags = RTCF_MULTICAST; - u32 itag = 0; - int err; - - /* Primary sanity checks. */ - - if (!in_dev) - return -EINVAL; - - if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr) || - skb->protocol != htons(ETH_P_IP)) - goto e_inval; - - if (ipv4_is_loopback(saddr) && !IN_DEV_ROUTE_LOCALNET(in_dev)) - goto e_inval; - - if (ipv4_is_zeronet(saddr)) { - if (!ipv4_is_local_multicast(daddr)) - goto e_inval; - } else { - err = fib_validate_source(skb, saddr, 0, tos, 0, dev, - in_dev, &itag); - if (err < 0) - goto e_err; - } - if (our) - flags |= RTCF_LOCAL; - - rth = rt_dst_alloc(dev_net(dev)->loopback_dev, flags, RTN_MULTICAST, - IN_DEV_CONF_GET(in_dev, NOPOLICY), false, false); - if (!rth) - goto e_nobufs; - -#ifdef CONFIG_IP_ROUTE_CLASSID - rth->dst.tclassid = itag; -#endif - rth->dst.output = ip_rt_bug; - rth->rt_is_input= 1; - -#ifdef CONFIG_IP_MROUTE - if (!ipv4_is_local_multicast(daddr) && IN_DEV_MFORWARD(in_dev)) - rth->dst.input = ip_mr_input; -#endif - RT_CACHE_STAT_INC(in_slow_mc); - - skb_dst_set(skb, &rth->dst); - return 0; - -e_nobufs: - return -ENOBUFS; -e_inval: - return -EINVAL; -e_err: - return err; -} - - -static void ip_handle_martian_source(struct net_device *dev, - struct in_device *in_dev, - struct sk_buff *skb, - __be32 daddr, - __be32 saddr) -{ - RT_CACHE_STAT_INC(in_martian_src); -#ifdef CONFIG_IP_ROUTE_VERBOSE - if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) { - /* - * RFC1812 recommendation, if source is martian, - * the only hint is MAC header. - */ - pr_warn("martian source %pI4 from %pI4, on dev %s\n", - &daddr, &saddr, dev->name); - if (dev->hard_header_len && skb_mac_header_was_set(skb)) { - print_hex_dump(KERN_WARNING, "ll header: ", - DUMP_PREFIX_OFFSET, 16, 1, - skb_mac_header(skb), - dev->hard_header_len, true); - } - } -#endif -} - -static void ip_del_fnhe(struct fib_nh *nh, __be32 daddr) -{ - struct fnhe_hash_bucket *hash; - struct fib_nh_exception *fnhe, __rcu **fnhe_p; - u32 hval = fnhe_hashfun(daddr); - - spin_lock_bh(&fnhe_lock); - - hash = rcu_dereference_protected(nh->nh_exceptions, - lockdep_is_held(&fnhe_lock)); - hash += hval; - - fnhe_p = &hash->chain; - fnhe = rcu_dereference_protected(*fnhe_p, lockdep_is_held(&fnhe_lock)); - while (fnhe) { - if (fnhe->fnhe_daddr == daddr) { - rcu_assign_pointer(*fnhe_p, rcu_dereference_protected( - fnhe->fnhe_next, lockdep_is_held(&fnhe_lock))); - fnhe_flush_routes(fnhe); - kfree_rcu(fnhe, rcu); - break; - } - fnhe_p = &fnhe->fnhe_next; - fnhe = rcu_dereference_protected(fnhe->fnhe_next, - lockdep_is_held(&fnhe_lock)); - } - - spin_unlock_bh(&fnhe_lock); -} - -/* called in rcu_read_lock() section */ -static int __mkroute_input(struct sk_buff *skb, - const struct fib_result *res, - struct in_device *in_dev, - __be32 daddr, __be32 saddr, u32 tos) -{ - struct fib_nh_exception *fnhe; - struct rtable *rth; - int err; - struct in_device *out_dev; - bool do_cache; - u32 itag = 0; - - /* get a working reference to the output device */ - out_dev = __in_dev_get_rcu(FIB_RES_DEV(*res)); - if (!out_dev) { - net_crit_ratelimited("Bug in ip_route_input_slow(). Please report.\n"); - return -EINVAL; - } - - err = fib_validate_source(skb, saddr, daddr, tos, FIB_RES_OIF(*res), - in_dev->dev, in_dev, &itag); - if (err < 0) { - ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr, - saddr); - - goto cleanup; - } - - do_cache = res->fi && !itag; - if (out_dev == in_dev && err && IN_DEV_TX_REDIRECTS(out_dev) && - skb->protocol == htons(ETH_P_IP) && - (IN_DEV_SHARED_MEDIA(out_dev) || - inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res)))) - IPCB(skb)->flags |= IPSKB_DOREDIRECT; - - if (skb->protocol != htons(ETH_P_IP)) { - /* Not IP (i.e. ARP). Do not create route, if it is - * invalid for proxy arp. DNAT routes are always valid. - * - * Proxy arp feature have been extended to allow, ARP - * replies back to the same interface, to support - * Private VLAN switch technologies. See arp.c. - */ - if (out_dev == in_dev && - IN_DEV_PROXY_ARP_PVLAN(in_dev) == 0) { - err = -EINVAL; - goto cleanup; - } - } - - fnhe = find_exception(&FIB_RES_NH(*res), daddr); - if (do_cache) { - if (fnhe) { - rth = rcu_dereference(fnhe->fnhe_rth_input); - if (rth && rth->dst.expires && - time_after(jiffies, rth->dst.expires)) { - ip_del_fnhe(&FIB_RES_NH(*res), daddr); - fnhe = NULL; - } else { - goto rt_cache; - } - } - - rth = rcu_dereference(FIB_RES_NH(*res).nh_rth_input); - -rt_cache: - if (rt_cache_valid(rth)) { - skb_dst_set_noref(skb, &rth->dst); - goto out; - } - } - - rth = rt_dst_alloc(out_dev->dev, 0, res->type, - IN_DEV_CONF_GET(in_dev, NOPOLICY), - IN_DEV_CONF_GET(out_dev, NOXFRM), do_cache); - if (!rth) { - err = -ENOBUFS; - goto cleanup; - } - - rth->rt_is_input = 1; - if (res->table) - rth->rt_table_id = res->table->tb_id; - RT_CACHE_STAT_INC(in_slow_tot); - - rth->dst.input = ip_forward; - - rt_set_nexthop(rth, daddr, res, fnhe, res->fi, res->type, itag); - if (lwtunnel_output_redirect(rth->dst.lwtstate)) { - rth->dst.lwtstate->orig_output = rth->dst.output; - rth->dst.output = lwtunnel_output; - } - if (lwtunnel_input_redirect(rth->dst.lwtstate)) { - rth->dst.lwtstate->orig_input = rth->dst.input; - rth->dst.input = lwtunnel_input; - } - skb_dst_set(skb, &rth->dst); -out: - err = 0; - cleanup: - return err; -} - -#ifdef CONFIG_IP_ROUTE_MULTIPATH - -/* To make ICMP packets follow the right flow, the multipath hash is - * calculated from the inner IP addresses in reverse order. - */ -static int ip_multipath_icmp_hash(struct sk_buff *skb) -{ - const struct iphdr *outer_iph = ip_hdr(skb); - struct icmphdr _icmph; - const struct icmphdr *icmph; - struct iphdr _inner_iph; - const struct iphdr *inner_iph; - - if (unlikely((outer_iph->frag_off & htons(IP_OFFSET)) != 0)) - goto standard_hash; - - icmph = skb_header_pointer(skb, outer_iph->ihl * 4, sizeof(_icmph), - &_icmph); - if (!icmph) - goto standard_hash; - - if (icmph->type != ICMP_DEST_UNREACH && - icmph->type != ICMP_REDIRECT && - icmph->type != ICMP_TIME_EXCEEDED && - icmph->type != ICMP_PARAMETERPROB) { - goto standard_hash; - } - - inner_iph = skb_header_pointer(skb, - outer_iph->ihl * 4 + sizeof(_icmph), - sizeof(_inner_iph), &_inner_iph); - if (!inner_iph) - goto standard_hash; - - return fib_multipath_hash(inner_iph->daddr, inner_iph->saddr); - -standard_hash: - return fib_multipath_hash(outer_iph->saddr, outer_iph->daddr); -} - -#endif /* CONFIG_IP_ROUTE_MULTIPATH */ - -static int ip_mkroute_input(struct sk_buff *skb, - struct fib_result *res, - const struct flowi4 *fl4, - struct in_device *in_dev, - __be32 daddr, __be32 saddr, u32 tos) -{ -#ifdef CONFIG_IP_ROUTE_MULTIPATH - if (res->fi && res->fi->fib_nhs > 1) { - int h; - - if (unlikely(ip_hdr(skb)->protocol == IPPROTO_ICMP)) - h = ip_multipath_icmp_hash(skb); - else - h = fib_multipath_hash(saddr, daddr); - fib_select_multipath(res, h); - } -#endif - - /* create a routing cache entry */ - return __mkroute_input(skb, res, in_dev, daddr, saddr, tos); -} - -/* - * NOTE. We drop all the packets that has local source - * addresses, because every properly looped back packet - * must have correct destination already attached by output routine. - * - * Such approach solves two big problems: - * 1. Not simplex devices are handled properly. - * 2. IP spoofing attempts are filtered with 100% of guarantee. - * called with rcu_read_lock() - */ - -static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, - u8 tos, struct net_device *dev) -{ - struct fib_result res; - struct in_device *in_dev = __in_dev_get_rcu(dev); - struct ip_tunnel_info *tun_info; - struct flowi4 fl4; - unsigned int flags = 0; - u32 itag = 0; - struct rtable *rth; - int err = -EINVAL; - struct net *net = dev_net(dev); - bool do_cache; - - /* IP on this device is disabled. */ - - if (!in_dev) - goto out; - - /* Check for the most weird martians, which can be not detected - by fib_lookup. - */ - - tun_info = skb_tunnel_info(skb); - if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX)) - fl4.flowi4_tun_key.tun_id = tun_info->key.tun_id; - else - fl4.flowi4_tun_key.tun_id = 0; - skb_dst_drop(skb); - - if (ipv4_is_multicast(saddr) || ipv4_is_lbcast(saddr)) - goto martian_source; - - res.fi = NULL; - res.table = NULL; - if (ipv4_is_lbcast(daddr) || (saddr == 0 && daddr == 0)) - goto brd_input; - - /* Accept zero addresses only to limited broadcast; - * I even do not know to fix it or not. Waiting for complains :-) - */ - if (ipv4_is_zeronet(saddr)) - goto martian_source; - - if (ipv4_is_zeronet(daddr)) - goto martian_destination; - - /* Following code try to avoid calling IN_DEV_NET_ROUTE_LOCALNET(), - * and call it once if daddr or/and saddr are loopback addresses - */ - if (ipv4_is_loopback(daddr)) { - if (!IN_DEV_NET_ROUTE_LOCALNET(in_dev, net)) - goto martian_destination; - } else if (ipv4_is_loopback(saddr)) { - if (!IN_DEV_NET_ROUTE_LOCALNET(in_dev, net)) - goto martian_source; - } - - /* - * Now we are ready to route packet. - */ - fl4.flowi4_oif = 0; - fl4.flowi4_iif = dev->ifindex; - fl4.flowi4_mark = skb->mark; - fl4.flowi4_tos = tos; - fl4.flowi4_scope = RT_SCOPE_UNIVERSE; - fl4.flowi4_flags = 0; - fl4.daddr = daddr; - fl4.saddr = saddr; - err = fib_lookup(net, &fl4, &res, 0); - if (err != 0) { - if (!IN_DEV_FORWARD(in_dev)) - err = -EHOSTUNREACH; - goto no_route; - } - - if (res.type == RTN_BROADCAST) - goto brd_input; - - if (res.type == RTN_LOCAL) { - err = fib_validate_source(skb, saddr, daddr, tos, - 0, dev, in_dev, &itag); - if (err < 0) - goto martian_source; - goto local_input; - } - - if (!IN_DEV_FORWARD(in_dev)) { - err = -EHOSTUNREACH; - goto no_route; - } - if (res.type != RTN_UNICAST) - goto martian_destination; - - err = ip_mkroute_input(skb, &res, &fl4, in_dev, daddr, saddr, tos); -out: return err; - -brd_input: - if (skb->protocol != htons(ETH_P_IP)) - goto e_inval; - - if (!ipv4_is_zeronet(saddr)) { - err = fib_validate_source(skb, saddr, 0, tos, 0, dev, - in_dev, &itag); - if (err < 0) - goto martian_source; - } - flags |= RTCF_BROADCAST; - res.type = RTN_BROADCAST; - RT_CACHE_STAT_INC(in_brd); - -local_input: - do_cache = false; - if (res.fi) { - if (!itag) { - rth = rcu_dereference(FIB_RES_NH(res).nh_rth_input); - if (rt_cache_valid(rth)) { - skb_dst_set_noref(skb, &rth->dst); - err = 0; - goto out; - } - do_cache = true; - } - } - - rth = rt_dst_alloc(net->loopback_dev, flags | RTCF_LOCAL, res.type, - IN_DEV_CONF_GET(in_dev, NOPOLICY), false, do_cache); - if (!rth) - goto e_nobufs; - - rth->dst.output= ip_rt_bug; -#ifdef CONFIG_IP_ROUTE_CLASSID - rth->dst.tclassid = itag; -#endif - rth->rt_is_input = 1; - if (res.table) - rth->rt_table_id = res.table->tb_id; - - RT_CACHE_STAT_INC(in_slow_tot); - if (res.type == RTN_UNREACHABLE) { - rth->dst.input= ip_error; - rth->dst.error= -err; - rth->rt_flags &= ~RTCF_LOCAL; - } - if (do_cache) { - if (unlikely(!rt_cache_route(&FIB_RES_NH(res), rth))) { - rth->dst.flags |= DST_NOCACHE; - rt_add_uncached_list(rth); - } - } - skb_dst_set(skb, &rth->dst); - err = 0; - goto out; - -no_route: - RT_CACHE_STAT_INC(in_no_route); - res.type = RTN_UNREACHABLE; - res.fi = NULL; - res.table = NULL; - goto local_input; - - /* - * Do not cache martian addresses: they should be logged (RFC1812) - */ -martian_destination: - RT_CACHE_STAT_INC(in_martian_dst); -#ifdef CONFIG_IP_ROUTE_VERBOSE - if (IN_DEV_LOG_MARTIANS(in_dev)) - net_warn_ratelimited("martian destination %pI4 from %pI4, dev %s\n", - &daddr, &saddr, dev->name); -#endif - -e_inval: - err = -EINVAL; - goto out; - -e_nobufs: - err = -ENOBUFS; - goto out; - -martian_source: - ip_handle_martian_source(dev, in_dev, skb, daddr, saddr); - goto out; -} - -int ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr, - u8 tos, struct net_device *dev) -{ - int res; - - rcu_read_lock(); - - /* Multicast recognition logic is moved from route cache to here. - The problem was that too many Ethernet cards have broken/missing - hardware multicast filters :-( As result the host on multicasting - network acquires a lot of useless route cache entries, sort of - SDR messages from all the world. Now we try to get rid of them. - Really, provided software IP multicast filter is organized - reasonably (at least, hashed), it does not result in a slowdown - comparing with route cache reject entries. - Note, that multicast routers are not affected, because - route cache entry is created eventually. - */ - if (ipv4_is_multicast(daddr)) { - struct in_device *in_dev = __in_dev_get_rcu(dev); - - if (in_dev) { - int our = ip_check_mc_rcu(in_dev, daddr, saddr, - ip_hdr(skb)->protocol); - if (our -#ifdef CONFIG_IP_MROUTE - || - (!ipv4_is_local_multicast(daddr) && - IN_DEV_MFORWARD(in_dev)) -#endif - ) { - int res = ip_route_input_mc(skb, daddr, saddr, - tos, dev, our); - rcu_read_unlock(); - return res; - } - } - rcu_read_unlock(); - return -EINVAL; - } - res = ip_route_input_slow(skb, daddr, saddr, tos, dev); - rcu_read_unlock(); - return res; -} -EXPORT_SYMBOL(ip_route_input_noref); - -/* called with rcu_read_lock() */ -static struct rtable *__mkroute_output(const struct fib_result *res, - const struct flowi4 *fl4, int orig_oif, - struct net_device *dev_out, - unsigned int flags) -{ - struct fib_info *fi = res->fi; - struct fib_nh_exception *fnhe; - struct in_device *in_dev; - u16 type = res->type; - struct rtable *rth; - bool do_cache; - - in_dev = __in_dev_get_rcu(dev_out); - if (!in_dev) - return ERR_PTR(-EINVAL); - - if (likely(!IN_DEV_ROUTE_LOCALNET(in_dev))) - if (ipv4_is_loopback(fl4->saddr) && - !(dev_out->flags & IFF_LOOPBACK) && - !netif_is_l3_master(dev_out)) - return ERR_PTR(-EINVAL); - - if (ipv4_is_lbcast(fl4->daddr)) - type = RTN_BROADCAST; - else if (ipv4_is_multicast(fl4->daddr)) - type = RTN_MULTICAST; - else if (ipv4_is_zeronet(fl4->daddr)) - return ERR_PTR(-EINVAL); - - if (dev_out->flags & IFF_LOOPBACK) - flags |= RTCF_LOCAL; - - do_cache = true; - if (type == RTN_BROADCAST) { - flags |= RTCF_BROADCAST | RTCF_LOCAL; - fi = NULL; - } else if (type == RTN_MULTICAST) { - flags |= RTCF_MULTICAST | RTCF_LOCAL; - if (!ip_check_mc_rcu(in_dev, fl4->daddr, fl4->saddr, - fl4->flowi4_proto)) - flags &= ~RTCF_LOCAL; - else - do_cache = false; - /* If multicast route do not exist use - * default one, but do not gateway in this case. - * Yes, it is hack. - */ - if (fi && res->prefixlen < 4) - fi = NULL; - } else if ((type == RTN_LOCAL) && (orig_oif != 0) && - (orig_oif != dev_out->ifindex)) { - /* For local routes that require a particular output interface - * we do not want to cache the result. Caching the result - * causes incorrect behaviour when there are multiple source - * addresses on the interface, the end result being that if the - * intended recipient is waiting on that interface for the - * packet he won't receive it because it will be delivered on - * the loopback interface and the IP_PKTINFO ipi_ifindex will - * be set to the loopback interface as well. - */ - fi = NULL; - } - - fnhe = NULL; - do_cache &= fi != NULL; - if (do_cache) { - struct rtable __rcu **prth; - struct fib_nh *nh = &FIB_RES_NH(*res); - - fnhe = find_exception(nh, fl4->daddr); - if (fnhe) { - prth = &fnhe->fnhe_rth_output; - rth = rcu_dereference(*prth); - if (rth && rth->dst.expires && - time_after(jiffies, rth->dst.expires)) { - ip_del_fnhe(nh, fl4->daddr); - fnhe = NULL; - } else { - goto rt_cache; - } - } - - if (unlikely(fl4->flowi4_flags & - FLOWI_FLAG_KNOWN_NH && - !(nh->nh_gw && - nh->nh_scope == RT_SCOPE_LINK))) { - do_cache = false; - goto add; - } - prth = raw_cpu_ptr(nh->nh_pcpu_rth_output); - rth = rcu_dereference(*prth); - -rt_cache: - if (rt_cache_valid(rth)) { - dst_hold(&rth->dst); - return rth; - } - } - -add: - rth = rt_dst_alloc(dev_out, flags, type, - IN_DEV_CONF_GET(in_dev, NOPOLICY), - IN_DEV_CONF_GET(in_dev, NOXFRM), - do_cache); - if (!rth) - return ERR_PTR(-ENOBUFS); - - rth->rt_iif = orig_oif ? : 0; - if (res->table) - rth->rt_table_id = res->table->tb_id; - - RT_CACHE_STAT_INC(out_slow_tot); - - if (flags & (RTCF_BROADCAST | RTCF_MULTICAST)) { - if (flags & RTCF_LOCAL && - !(dev_out->flags & IFF_LOOPBACK)) { - rth->dst.output = ip_mc_output; - RT_CACHE_STAT_INC(out_slow_mc); - } -#ifdef CONFIG_IP_MROUTE - if (type == RTN_MULTICAST) { - if (IN_DEV_MFORWARD(in_dev) && - !ipv4_is_local_multicast(fl4->daddr)) { - rth->dst.input = ip_mr_input; - rth->dst.output = ip_mc_output; - } - } -#endif - } - - rt_set_nexthop(rth, fl4->daddr, res, fnhe, fi, type, 0); - if (lwtunnel_output_redirect(rth->dst.lwtstate)) - rth->dst.output = lwtunnel_output; - - return rth; -} - -/* - * Major route resolver routine. - */ - -struct rtable *__ip_route_output_key_hash(struct net *net, struct flowi4 *fl4, - int mp_hash) -{ - struct net_device *dev_out = NULL; - __u8 tos = RT_FL_TOS(fl4); - unsigned int flags = 0; - struct fib_result res; - struct rtable *rth; - int orig_oif; - int err = -ENETUNREACH; - - res.tclassid = 0; - res.fi = NULL; - res.table = NULL; - - orig_oif = fl4->flowi4_oif; - - fl4->flowi4_iif = LOOPBACK_IFINDEX; - fl4->flowi4_tos = tos & IPTOS_RT_MASK; - fl4->flowi4_scope = ((tos & RTO_ONLINK) ? - RT_SCOPE_LINK : RT_SCOPE_UNIVERSE); - - rcu_read_lock(); - if (fl4->saddr) { - rth = ERR_PTR(-EINVAL); - if (ipv4_is_multicast(fl4->saddr) || - ipv4_is_lbcast(fl4->saddr) || - ipv4_is_zeronet(fl4->saddr)) - goto out; - - /* I removed check for oif == dev_out->oif here. - It was wrong for two reasons: - 1. ip_dev_find(net, saddr) can return wrong iface, if saddr - is assigned to multiple interfaces. - 2. Moreover, we are allowed to send packets with saddr - of another iface. --ANK - */ - - if (fl4->flowi4_oif == 0 && - (ipv4_is_multicast(fl4->daddr) || - ipv4_is_lbcast(fl4->daddr))) { - /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ - dev_out = __ip_dev_find(net, fl4->saddr, false); - if (!dev_out) - goto out; - - /* Special hack: user can direct multicasts - and limited broadcast via necessary interface - without fiddling with IP_MULTICAST_IF or IP_PKTINFO. - This hack is not just for fun, it allows - vic,vat and friends to work. - They bind socket to loopback, set ttl to zero - and expect that it will work. - From the viewpoint of routing cache they are broken, - because we are not allowed to build multicast path - with loopback source addr (look, routing cache - cannot know, that ttl is zero, so that packet - will not leave this host and route is valid). - Luckily, this hack is good workaround. - */ - - fl4->flowi4_oif = dev_out->ifindex; - goto make_route; - } - - if (!(fl4->flowi4_flags & FLOWI_FLAG_ANYSRC)) { - /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ - if (!__ip_dev_find(net, fl4->saddr, false)) - goto out; - } - } - - - if (fl4->flowi4_oif) { - dev_out = dev_get_by_index_rcu(net, fl4->flowi4_oif); - rth = ERR_PTR(-ENODEV); - if (!dev_out) - goto out; - - /* RACE: Check return value of inet_select_addr instead. */ - if (!(dev_out->flags & IFF_UP) || !__in_dev_get_rcu(dev_out)) { - rth = ERR_PTR(-ENETUNREACH); - goto out; - } - if (ipv4_is_local_multicast(fl4->daddr) || - ipv4_is_lbcast(fl4->daddr) || - fl4->flowi4_proto == IPPROTO_IGMP) { - if (!fl4->saddr) - fl4->saddr = inet_select_addr(dev_out, 0, - RT_SCOPE_LINK); - goto make_route; - } - if (!fl4->saddr) { - if (ipv4_is_multicast(fl4->daddr)) - fl4->saddr = inet_select_addr(dev_out, 0, - fl4->flowi4_scope); - else if (!fl4->daddr) - fl4->saddr = inet_select_addr(dev_out, 0, - RT_SCOPE_HOST); - } - } - - if (!fl4->daddr) { - fl4->daddr = fl4->saddr; - if (!fl4->daddr) - fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK); - dev_out = net->loopback_dev; - fl4->flowi4_oif = LOOPBACK_IFINDEX; - res.type = RTN_LOCAL; - flags |= RTCF_LOCAL; - goto make_route; - } - - err = fib_lookup(net, fl4, &res, 0); - if (err) { - res.fi = NULL; - res.table = NULL; - if (fl4->flowi4_oif && - !netif_index_is_l3_master(net, fl4->flowi4_oif)) { - /* Apparently, routing tables are wrong. Assume, - that the destination is on link. - - WHY? DW. - Because we are allowed to send to iface - even if it has NO routes and NO assigned - addresses. When oif is specified, routing - tables are looked up with only one purpose: - to catch if destination is gatewayed, rather than - direct. Moreover, if MSG_DONTROUTE is set, - we send packet, ignoring both routing tables - and ifaddr state. --ANK - - - We could make it even if oif is unknown, - likely IPv6, but we do not. - */ - - if (fl4->saddr == 0) - fl4->saddr = inet_select_addr(dev_out, 0, - RT_SCOPE_LINK); - res.type = RTN_UNICAST; - goto make_route; - } - rth = ERR_PTR(err); - goto out; - } - - if (res.type == RTN_LOCAL) { - if (!fl4->saddr) { - if (res.fi->fib_prefsrc) - fl4->saddr = res.fi->fib_prefsrc; - else - fl4->saddr = fl4->daddr; - } - - /* L3 master device is the loopback for that domain */ - dev_out = l3mdev_master_dev_rcu(dev_out) ? : net->loopback_dev; - fl4->flowi4_oif = dev_out->ifindex; - flags |= RTCF_LOCAL; - goto make_route; - } - - fib_select_path(net, &res, fl4, mp_hash); - - dev_out = FIB_RES_DEV(res); - fl4->flowi4_oif = dev_out->ifindex; - - -make_route: - rth = __mkroute_output(&res, fl4, orig_oif, dev_out, flags); - -out: - rcu_read_unlock(); - return rth; -} -EXPORT_SYMBOL_GPL(__ip_route_output_key_hash); - -static struct dst_entry *ipv4_blackhole_dst_check(struct dst_entry *dst, u32 cookie) -{ - return NULL; -} - -static unsigned int ipv4_blackhole_mtu(const struct dst_entry *dst) -{ - unsigned int mtu = dst_metric_raw(dst, RTAX_MTU); - - return mtu ? : dst->dev->mtu; -} - -static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk, - struct sk_buff *skb, u32 mtu) -{ -} - -static void ipv4_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk, - struct sk_buff *skb) -{ -} - -static u32 *ipv4_rt_blackhole_cow_metrics(struct dst_entry *dst, - unsigned long old) -{ - return NULL; -} - -static struct dst_ops ipv4_dst_blackhole_ops = { - .family = AF_INET, - .check = ipv4_blackhole_dst_check, - .mtu = ipv4_blackhole_mtu, - .default_advmss = ipv4_default_advmss, - .update_pmtu = ipv4_rt_blackhole_update_pmtu, - .redirect = ipv4_rt_blackhole_redirect, - .cow_metrics = ipv4_rt_blackhole_cow_metrics, - .neigh_lookup = ipv4_neigh_lookup, -}; - -struct dst_entry *ipv4_blackhole_route(struct net *net, struct dst_entry *dst_orig) -{ - struct rtable *ort = (struct rtable *) dst_orig; - struct rtable *rt; - - rt = dst_alloc(&ipv4_dst_blackhole_ops, NULL, 1, DST_OBSOLETE_NONE, 0); - if (rt) { - struct dst_entry *new = &rt->dst; - - new->__use = 1; - new->input = dst_discard; - new->output = dst_discard_out; - - new->dev = ort->dst.dev; - if (new->dev) - dev_hold(new->dev); - - rt->rt_is_input = ort->rt_is_input; - rt->rt_iif = ort->rt_iif; - rt->rt_pmtu = ort->rt_pmtu; - - rt->rt_genid = rt_genid_ipv4(net); - rt->rt_flags = ort->rt_flags; - rt->rt_type = ort->rt_type; - rt->rt_gateway = ort->rt_gateway; - rt->rt_uses_gateway = ort->rt_uses_gateway; - - INIT_LIST_HEAD(&rt->rt_uncached); - dst_free(new); - } - - dst_release(dst_orig); - - return rt ? &rt->dst : ERR_PTR(-ENOMEM); -} - -struct rtable *ip_route_output_flow(struct net *net, struct flowi4 *flp4, - const struct sock *sk) -{ - struct rtable *rt = __ip_route_output_key(net, flp4); - - if (IS_ERR(rt)) - return rt; - - if (flp4->flowi4_proto) - rt = (struct rtable *)xfrm_lookup_route(net, &rt->dst, - flowi4_to_flowi(flp4), - sk, 0); - - return rt; -} -EXPORT_SYMBOL_GPL(ip_route_output_flow); - -static int rt_fill_info(struct net *net, __be32 dst, __be32 src, u32 table_id, - struct flowi4 *fl4, struct sk_buff *skb, u32 portid, - u32 seq, int event, int nowait, unsigned int flags) -{ - struct rtable *rt = skb_rtable(skb); - struct rtmsg *r; - struct nlmsghdr *nlh; - unsigned long expires = 0; - u32 error; - u32 metrics[RTAX_MAX]; - - nlh = nlmsg_put(skb, portid, seq, event, sizeof(*r), flags); - if (!nlh) - return -EMSGSIZE; - - r = nlmsg_data(nlh); - r->rtm_family = AF_INET; - r->rtm_dst_len = 32; - r->rtm_src_len = 0; - r->rtm_tos = fl4->flowi4_tos; - r->rtm_table = table_id; - if (nla_put_u32(skb, RTA_TABLE, table_id)) - goto nla_put_failure; - r->rtm_type = rt->rt_type; - r->rtm_scope = RT_SCOPE_UNIVERSE; - r->rtm_protocol = RTPROT_UNSPEC; - r->rtm_flags = (rt->rt_flags & ~0xFFFF) | RTM_F_CLONED; - if (rt->rt_flags & RTCF_NOTIFY) - r->rtm_flags |= RTM_F_NOTIFY; - if (IPCB(skb)->flags & IPSKB_DOREDIRECT) - r->rtm_flags |= RTCF_DOREDIRECT; - - if (nla_put_in_addr(skb, RTA_DST, dst)) - goto nla_put_failure; - if (src) { - r->rtm_src_len = 32; - if (nla_put_in_addr(skb, RTA_SRC, src)) - goto nla_put_failure; - } - if (rt->dst.dev && - nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex)) - goto nla_put_failure; -#ifdef CONFIG_IP_ROUTE_CLASSID - if (rt->dst.tclassid && - nla_put_u32(skb, RTA_FLOW, rt->dst.tclassid)) - goto nla_put_failure; -#endif - if (!rt_is_input_route(rt) && - fl4->saddr != src) { - if (nla_put_in_addr(skb, RTA_PREFSRC, fl4->saddr)) - goto nla_put_failure; - } - if (rt->rt_uses_gateway && - nla_put_in_addr(skb, RTA_GATEWAY, rt->rt_gateway)) - goto nla_put_failure; - - expires = rt->dst.expires; - if (expires) { - unsigned long now = jiffies; - - if (time_before(now, expires)) - expires -= now; - else - expires = 0; - } - - memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics)); - if (rt->rt_pmtu && expires) - metrics[RTAX_MTU - 1] = rt->rt_pmtu; - if (rtnetlink_put_metrics(skb, metrics) < 0) - goto nla_put_failure; - - if (fl4->flowi4_mark && - nla_put_u32(skb, RTA_MARK, fl4->flowi4_mark)) - goto nla_put_failure; - - error = rt->dst.error; - - if (rt_is_input_route(rt)) { -#ifdef CONFIG_IP_MROUTE - if (ipv4_is_multicast(dst) && !ipv4_is_local_multicast(dst) && - IPV4_DEVCONF_ALL(net, MC_FORWARDING)) { - int err = ipmr_get_route(net, skb, - fl4->saddr, fl4->daddr, - r, nowait, portid); - - if (err <= 0) { - if (!nowait) { - if (err == 0) - return 0; - goto nla_put_failure; - } else { - if (err == -EMSGSIZE) - goto nla_put_failure; - error = err; - } - } - } else -#endif - if (nla_put_u32(skb, RTA_IIF, skb->dev->ifindex)) - goto nla_put_failure; - } - - if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, error) < 0) - goto nla_put_failure; - - nlmsg_end(skb, nlh); - return 0; - -nla_put_failure: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -static int inet_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(in_skb->sk); - struct rtmsg *rtm; - struct nlattr *tb[RTA_MAX+1]; - struct rtable *rt = NULL; - struct flowi4 fl4; - __be32 dst = 0; - __be32 src = 0; - u32 iif; - int err; - int mark; - struct sk_buff *skb; - u32 table_id = RT_TABLE_MAIN; - - err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv4_policy); - if (err < 0) - goto errout; - - rtm = nlmsg_data(nlh); - - skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); - if (!skb) { - err = -ENOBUFS; - goto errout; - } - - /* Reserve room for dummy headers, this skb can pass - through good chunk of routing engine. - */ - skb_reset_mac_header(skb); - skb_reset_network_header(skb); - - /* Bugfix: need to give ip_route_input enough of an IP header to not gag. */ - ip_hdr(skb)->protocol = IPPROTO_ICMP; - skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr)); - - src = tb[RTA_SRC] ? nla_get_in_addr(tb[RTA_SRC]) : 0; - dst = tb[RTA_DST] ? nla_get_in_addr(tb[RTA_DST]) : 0; - iif = tb[RTA_IIF] ? nla_get_u32(tb[RTA_IIF]) : 0; - mark = tb[RTA_MARK] ? nla_get_u32(tb[RTA_MARK]) : 0; - - memset(&fl4, 0, sizeof(fl4)); - fl4.daddr = dst; - fl4.saddr = src; - fl4.flowi4_tos = rtm->rtm_tos; - fl4.flowi4_oif = tb[RTA_OIF] ? nla_get_u32(tb[RTA_OIF]) : 0; - fl4.flowi4_mark = mark; - - if (iif) { - struct net_device *dev; - - dev = __dev_get_by_index(net, iif); - if (!dev) { - err = -ENODEV; - goto errout_free; - } - - skb->protocol = htons(ETH_P_IP); - skb->dev = dev; - skb->mark = mark; - local_bh_disable(); - err = ip_route_input(skb, dst, src, rtm->rtm_tos, dev); - local_bh_enable(); - - rt = skb_rtable(skb); - if (err == 0 && rt->dst.error) - err = -rt->dst.error; - } else { - rt = ip_route_output_key(net, &fl4); - - err = 0; - if (IS_ERR(rt)) - err = PTR_ERR(rt); - } - - if (err) - goto errout_free; - - skb_dst_set(skb, &rt->dst); - if (rtm->rtm_flags & RTM_F_NOTIFY) - rt->rt_flags |= RTCF_NOTIFY; - - if (rtm->rtm_flags & RTM_F_LOOKUP_TABLE) - table_id = rt->rt_table_id; - - err = rt_fill_info(net, dst, src, table_id, &fl4, skb, - NETLINK_CB(in_skb).portid, nlh->nlmsg_seq, - RTM_NEWROUTE, 0, 0); - if (err < 0) - goto errout_free; - - err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); -errout: - return err; - -errout_free: - kfree_skb(skb); - goto errout; -} - -void ip_rt_multicast_event(struct in_device *in_dev) -{ - rt_cache_flush(dev_net(in_dev->dev)); -} - -#ifdef CONFIG_SYSCTL -static int ip_rt_gc_interval __read_mostly = 60 * HZ; -static int ip_rt_gc_min_interval __read_mostly = HZ / 2; -static int ip_rt_gc_elasticity __read_mostly = 8; - -static int ipv4_sysctl_rtcache_flush(struct ctl_table *__ctl, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - struct net *net = (struct net *)__ctl->extra1; - - if (write) { - rt_cache_flush(net); - fnhe_genid_bump(net); - return 0; - } - - return -EINVAL; -} - -static struct ctl_table ipv4_route_table[] = { - { - .procname = "gc_thresh", - .data = &ipv4_dst_ops.gc_thresh, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "max_size", - .data = &ip_rt_max_size, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - /* Deprecated. Use gc_min_interval_ms */ - - .procname = "gc_min_interval", - .data = &ip_rt_gc_min_interval, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "gc_min_interval_ms", - .data = &ip_rt_gc_min_interval, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_ms_jiffies, - }, - { - .procname = "gc_timeout", - .data = &ip_rt_gc_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "gc_interval", - .data = &ip_rt_gc_interval, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "redirect_load", - .data = &ip_rt_redirect_load, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "redirect_number", - .data = &ip_rt_redirect_number, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "redirect_silence", - .data = &ip_rt_redirect_silence, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "error_cost", - .data = &ip_rt_error_cost, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "error_burst", - .data = &ip_rt_error_burst, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "gc_elasticity", - .data = &ip_rt_gc_elasticity, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "mtu_expires", - .data = &ip_rt_mtu_expires, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "min_pmtu", - .data = &ip_rt_min_pmtu, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "min_adv_mss", - .data = &ip_rt_min_advmss, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { } -}; - -static struct ctl_table ipv4_route_flush_table[] = { - { - .procname = "flush", - .maxlen = sizeof(int), - .mode = 0200, - .proc_handler = ipv4_sysctl_rtcache_flush, - }, - { }, -}; - -static __net_init int sysctl_route_net_init(struct net *net) -{ - struct ctl_table *tbl; - - tbl = ipv4_route_flush_table; - if (!net_eq(net, &init_net)) { - tbl = kmemdup(tbl, sizeof(ipv4_route_flush_table), GFP_KERNEL); - if (!tbl) - goto err_dup; - - /* Don't export sysctls to unprivileged users */ - if (net->user_ns != &init_user_ns) - tbl[0].procname = NULL; - } - tbl[0].extra1 = net; - - net->ipv4.route_hdr = register_net_sysctl(net, "net/ipv4/route", tbl); - if (!net->ipv4.route_hdr) - goto err_reg; - return 0; - -err_reg: - if (tbl != ipv4_route_flush_table) - kfree(tbl); -err_dup: - return -ENOMEM; -} - -static __net_exit void sysctl_route_net_exit(struct net *net) -{ - struct ctl_table *tbl; - - tbl = net->ipv4.route_hdr->ctl_table_arg; - unregister_net_sysctl_table(net->ipv4.route_hdr); - BUG_ON(tbl == ipv4_route_flush_table); - kfree(tbl); -} - -static __net_initdata struct pernet_operations sysctl_route_ops = { - .init = sysctl_route_net_init, - .exit = sysctl_route_net_exit, -}; -#endif - -static __net_init int rt_genid_init(struct net *net) -{ - atomic_set(&net->ipv4.rt_genid, 0); - atomic_set(&net->fnhe_genid, 0); - get_random_bytes(&net->ipv4.dev_addr_genid, - sizeof(net->ipv4.dev_addr_genid)); - return 0; -} - -static __net_initdata struct pernet_operations rt_genid_ops = { - .init = rt_genid_init, -}; - -static int __net_init ipv4_inetpeer_init(struct net *net) -{ - struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL); - - if (!bp) - return -ENOMEM; - inet_peer_base_init(bp); - net->ipv4.peers = bp; - return 0; -} - -static void __net_exit ipv4_inetpeer_exit(struct net *net) -{ - struct inet_peer_base *bp = net->ipv4.peers; - - net->ipv4.peers = NULL; - inetpeer_invalidate_tree(bp); - kfree(bp); -} - -static __net_initdata struct pernet_operations ipv4_inetpeer_ops = { - .init = ipv4_inetpeer_init, - .exit = ipv4_inetpeer_exit, -}; - -#ifdef CONFIG_IP_ROUTE_CLASSID -struct ip_rt_acct __percpu *ip_rt_acct __read_mostly; -#endif /* CONFIG_IP_ROUTE_CLASSID */ - -int __init ip_rt_init(void) -{ - int rc = 0; - int cpu; - - ip_idents = kmalloc(IP_IDENTS_SZ * sizeof(*ip_idents), GFP_KERNEL); - if (!ip_idents) - panic("IP: failed to allocate ip_idents\n"); - - prandom_bytes(ip_idents, IP_IDENTS_SZ * sizeof(*ip_idents)); - - ip_tstamps = kcalloc(IP_IDENTS_SZ, sizeof(*ip_tstamps), GFP_KERNEL); - if (!ip_tstamps) - panic("IP: failed to allocate ip_tstamps\n"); - - for_each_possible_cpu(cpu) { - struct uncached_list *ul = &per_cpu(rt_uncached_list, cpu); - - INIT_LIST_HEAD(&ul->head); - spin_lock_init(&ul->lock); - } -#ifdef CONFIG_IP_ROUTE_CLASSID - ip_rt_acct = __alloc_percpu(256 * sizeof(struct ip_rt_acct), __alignof__(struct ip_rt_acct)); - if (!ip_rt_acct) - panic("IP: failed to allocate ip_rt_acct\n"); -#endif - - ipv4_dst_ops.kmem_cachep = - kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); - - ipv4_dst_blackhole_ops.kmem_cachep = ipv4_dst_ops.kmem_cachep; - - if (dst_entries_init(&ipv4_dst_ops) < 0) - panic("IP: failed to allocate ipv4_dst_ops counter\n"); - - if (dst_entries_init(&ipv4_dst_blackhole_ops) < 0) - panic("IP: failed to allocate ipv4_dst_blackhole_ops counter\n"); - - ipv4_dst_ops.gc_thresh = ~0; - ip_rt_max_size = INT_MAX; - - devinet_init(); - ip_fib_init(); - - if (ip_rt_proc_init()) - pr_err("Unable to create route proc files\n"); -#ifdef CONFIG_XFRM - xfrm_init(); - xfrm4_init(); -#endif - rtnl_register(PF_INET, RTM_GETROUTE, inet_rtm_getroute, NULL, NULL); - -#ifdef CONFIG_SYSCTL - register_pernet_subsys(&sysctl_route_ops); -#endif - register_pernet_subsys(&rt_genid_ops); - register_pernet_subsys(&ipv4_inetpeer_ops); - return rc; -} - -#ifdef CONFIG_SYSCTL -/* - * We really need to sanitize the damn ipv4 init order, then all - * this nonsense will go away. - */ -void __init ip_static_sysctl_init(void) -{ - register_net_sysctl(&init_net, "net/ipv4/route", ipv4_route_table); -} -#endif diff --git a/src/linux/net/ipv4/sysctl_net_ipv4.c b/src/linux/net/ipv4/sysctl_net_ipv4.c deleted file mode 100644 index 80bc36b..0000000 --- a/src/linux/net/ipv4/sysctl_net_ipv4.c +++ /dev/null @@ -1,1044 +0,0 @@ -/* - * sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem. - * - * Begun April 1, 1996, Mike Shaver. - * Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS] - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int zero; -static int one = 1; -static int four = 4; -static int thousand = 1000; -static int gso_max_segs = GSO_MAX_SEGS; -static int tcp_retr1_max = 255; -static int ip_local_port_range_min[] = { 1, 1 }; -static int ip_local_port_range_max[] = { 65535, 65535 }; -static int tcp_adv_win_scale_min = -31; -static int tcp_adv_win_scale_max = 31; -static int ip_ttl_min = 1; -static int ip_ttl_max = 255; -static int tcp_syn_retries_min = 1; -static int tcp_syn_retries_max = MAX_TCP_SYNCNT; -static int ip_ping_group_range_min[] = { 0, 0 }; -static int ip_ping_group_range_max[] = { GID_T_MAX, GID_T_MAX }; - -/* Update system visible IP port range */ -static void set_local_port_range(struct net *net, int range[2]) -{ - bool same_parity = !((range[0] ^ range[1]) & 1); - - write_seqlock_bh(&net->ipv4.ip_local_ports.lock); - if (same_parity && !net->ipv4.ip_local_ports.warned) { - net->ipv4.ip_local_ports.warned = true; - pr_err_ratelimited("ip_local_port_range: prefer different parity for start/end values.\n"); - } - net->ipv4.ip_local_ports.range[0] = range[0]; - net->ipv4.ip_local_ports.range[1] = range[1]; - write_sequnlock_bh(&net->ipv4.ip_local_ports.lock); -} - -/* Validate changes from /proc interface. */ -static int ipv4_local_port_range(struct ctl_table *table, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - struct net *net = - container_of(table->data, struct net, ipv4.ip_local_ports.range); - int ret; - int range[2]; - struct ctl_table tmp = { - .data = &range, - .maxlen = sizeof(range), - .mode = table->mode, - .extra1 = &ip_local_port_range_min, - .extra2 = &ip_local_port_range_max, - }; - - inet_get_local_port_range(net, &range[0], &range[1]); - - ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); - - if (write && ret == 0) { - if (range[1] < range[0]) - ret = -EINVAL; - else - set_local_port_range(net, range); - } - - return ret; -} - - -static void inet_get_ping_group_range_table(struct ctl_table *table, kgid_t *low, kgid_t *high) -{ - kgid_t *data = table->data; - struct net *net = - container_of(table->data, struct net, ipv4.ping_group_range.range); - unsigned int seq; - do { - seq = read_seqbegin(&net->ipv4.ping_group_range.lock); - - *low = data[0]; - *high = data[1]; - } while (read_seqretry(&net->ipv4.ping_group_range.lock, seq)); -} - -/* Update system visible IP port range */ -static void set_ping_group_range(struct ctl_table *table, kgid_t low, kgid_t high) -{ - kgid_t *data = table->data; - struct net *net = - container_of(table->data, struct net, ipv4.ping_group_range.range); - write_seqlock(&net->ipv4.ping_group_range.lock); - data[0] = low; - data[1] = high; - write_sequnlock(&net->ipv4.ping_group_range.lock); -} - -/* Validate changes from /proc interface. */ -static int ipv4_ping_group_range(struct ctl_table *table, int write, - void __user *buffer, - size_t *lenp, loff_t *ppos) -{ - struct user_namespace *user_ns = current_user_ns(); - int ret; - gid_t urange[2]; - kgid_t low, high; - struct ctl_table tmp = { - .data = &urange, - .maxlen = sizeof(urange), - .mode = table->mode, - .extra1 = &ip_ping_group_range_min, - .extra2 = &ip_ping_group_range_max, - }; - - inet_get_ping_group_range_table(table, &low, &high); - urange[0] = from_kgid_munged(user_ns, low); - urange[1] = from_kgid_munged(user_ns, high); - ret = proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); - - if (write && ret == 0) { - low = make_kgid(user_ns, urange[0]); - high = make_kgid(user_ns, urange[1]); - if (!gid_valid(low) || !gid_valid(high) || - (urange[1] < urange[0]) || gid_lt(high, low)) { - low = make_kgid(&init_user_ns, 1); - high = make_kgid(&init_user_ns, 0); - } - set_ping_group_range(table, low, high); - } - - return ret; -} - -static int proc_tcp_congestion_control(struct ctl_table *ctl, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - char val[TCP_CA_NAME_MAX]; - struct ctl_table tbl = { - .data = val, - .maxlen = TCP_CA_NAME_MAX, - }; - int ret; - - tcp_get_default_congestion_control(val); - - ret = proc_dostring(&tbl, write, buffer, lenp, ppos); - if (write && ret == 0) - ret = tcp_set_default_congestion_control(val); - return ret; -} - -static int proc_tcp_available_congestion_control(struct ctl_table *ctl, - int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - struct ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX, }; - int ret; - - tbl.data = kmalloc(tbl.maxlen, GFP_USER); - if (!tbl.data) - return -ENOMEM; - tcp_get_available_congestion_control(tbl.data, TCP_CA_BUF_MAX); - ret = proc_dostring(&tbl, write, buffer, lenp, ppos); - kfree(tbl.data); - return ret; -} - -static int proc_allowed_congestion_control(struct ctl_table *ctl, - int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - struct ctl_table tbl = { .maxlen = TCP_CA_BUF_MAX }; - int ret; - - tbl.data = kmalloc(tbl.maxlen, GFP_USER); - if (!tbl.data) - return -ENOMEM; - - tcp_get_allowed_congestion_control(tbl.data, tbl.maxlen); - ret = proc_dostring(&tbl, write, buffer, lenp, ppos); - if (write && ret == 0) - ret = tcp_set_allowed_congestion_control(tbl.data); - kfree(tbl.data); - return ret; -} - -static int proc_tcp_fastopen_key(struct ctl_table *ctl, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - struct ctl_table tbl = { .maxlen = (TCP_FASTOPEN_KEY_LENGTH * 2 + 10) }; - struct tcp_fastopen_context *ctxt; - int ret; - u32 user_key[4]; /* 16 bytes, matching TCP_FASTOPEN_KEY_LENGTH */ - - tbl.data = kmalloc(tbl.maxlen, GFP_KERNEL); - if (!tbl.data) - return -ENOMEM; - - rcu_read_lock(); - ctxt = rcu_dereference(tcp_fastopen_ctx); - if (ctxt) - memcpy(user_key, ctxt->key, TCP_FASTOPEN_KEY_LENGTH); - else - memset(user_key, 0, sizeof(user_key)); - rcu_read_unlock(); - - snprintf(tbl.data, tbl.maxlen, "%08x-%08x-%08x-%08x", - user_key[0], user_key[1], user_key[2], user_key[3]); - ret = proc_dostring(&tbl, write, buffer, lenp, ppos); - - if (write && ret == 0) { - if (sscanf(tbl.data, "%x-%x-%x-%x", user_key, user_key + 1, - user_key + 2, user_key + 3) != 4) { - ret = -EINVAL; - goto bad_key; - } - /* Generate a dummy secret but don't publish it. This - * is needed so we don't regenerate a new key on the - * first invocation of tcp_fastopen_cookie_gen - */ - tcp_fastopen_init_key_once(false); - tcp_fastopen_reset_cipher(user_key, TCP_FASTOPEN_KEY_LENGTH); - } - -bad_key: - pr_debug("proc FO key set 0x%x-%x-%x-%x <- 0x%s: %u\n", - user_key[0], user_key[1], user_key[2], user_key[3], - (char *)tbl.data, ret); - kfree(tbl.data); - return ret; -} - -static struct ctl_table ipv4_table[] = { - { - .procname = "tcp_timestamps", - .data = &sysctl_tcp_timestamps, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_window_scaling", - .data = &sysctl_tcp_window_scaling, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_sack", - .data = &sysctl_tcp_sack, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_retrans_collapse", - .data = &sysctl_tcp_retrans_collapse, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_max_orphans", - .data = &sysctl_tcp_max_orphans, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_max_tw_buckets", - .data = &tcp_death_row.sysctl_max_tw_buckets, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_fastopen", - .data = &sysctl_tcp_fastopen, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "tcp_fastopen_key", - .mode = 0600, - .maxlen = ((TCP_FASTOPEN_KEY_LENGTH * 2) + 10), - .proc_handler = proc_tcp_fastopen_key, - }, - { - .procname = "tcp_tw_recycle", - .data = &tcp_death_row.sysctl_tw_recycle, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_abort_on_overflow", - .data = &sysctl_tcp_abort_on_overflow, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_stdurg", - .data = &sysctl_tcp_stdurg, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_rfc1337", - .data = &sysctl_tcp_rfc1337, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_max_syn_backlog", - .data = &sysctl_max_syn_backlog, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "inet_peer_threshold", - .data = &inet_peer_threshold, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "inet_peer_minttl", - .data = &inet_peer_minttl, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "inet_peer_maxttl", - .data = &inet_peer_maxttl, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "tcp_fack", - .data = &sysctl_tcp_fack, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_recovery", - .data = &sysctl_tcp_recovery, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "tcp_max_reordering", - .data = &sysctl_tcp_max_reordering, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_dsack", - .data = &sysctl_tcp_dsack, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_mem", - .maxlen = sizeof(sysctl_tcp_mem), - .data = &sysctl_tcp_mem, - .mode = 0644, - .proc_handler = proc_doulongvec_minmax, - }, - { - .procname = "tcp_wmem", - .data = &sysctl_tcp_wmem, - .maxlen = sizeof(sysctl_tcp_wmem), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &one, - }, - { - .procname = "tcp_rmem", - .data = &sysctl_tcp_rmem, - .maxlen = sizeof(sysctl_tcp_rmem), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &one, - }, - { - .procname = "tcp_app_win", - .data = &sysctl_tcp_app_win, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_adv_win_scale", - .data = &sysctl_tcp_adv_win_scale, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &tcp_adv_win_scale_min, - .extra2 = &tcp_adv_win_scale_max, - }, - { - .procname = "tcp_tw_reuse", - .data = &sysctl_tcp_tw_reuse, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_frto", - .data = &sysctl_tcp_frto, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_min_rtt_wlen", - .data = &sysctl_tcp_min_rtt_wlen, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_low_latency", - .data = &sysctl_tcp_low_latency, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_no_metrics_save", - .data = &sysctl_tcp_nometrics_save, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "tcp_moderate_rcvbuf", - .data = &sysctl_tcp_moderate_rcvbuf, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "tcp_tso_win_divisor", - .data = &sysctl_tcp_tso_win_divisor, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "tcp_congestion_control", - .mode = 0644, - .maxlen = TCP_CA_NAME_MAX, - .proc_handler = proc_tcp_congestion_control, - }, - { - .procname = "tcp_workaround_signed_windows", - .data = &sysctl_tcp_workaround_signed_windows, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_limit_output_bytes", - .data = &sysctl_tcp_limit_output_bytes, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_challenge_ack_limit", - .data = &sysctl_tcp_challenge_ack_limit, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_slow_start_after_idle", - .data = &sysctl_tcp_slow_start_after_idle, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, -#ifdef CONFIG_NETLABEL - { - .procname = "cipso_cache_enable", - .data = &cipso_v4_cache_enabled, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "cipso_cache_bucket_size", - .data = &cipso_v4_cache_bucketsize, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "cipso_rbm_optfmt", - .data = &cipso_v4_rbm_optfmt, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "cipso_rbm_strictvalid", - .data = &cipso_v4_rbm_strictvalid, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif /* CONFIG_NETLABEL */ - { - .procname = "tcp_available_congestion_control", - .maxlen = TCP_CA_BUF_MAX, - .mode = 0444, - .proc_handler = proc_tcp_available_congestion_control, - }, - { - .procname = "tcp_allowed_congestion_control", - .maxlen = TCP_CA_BUF_MAX, - .mode = 0644, - .proc_handler = proc_allowed_congestion_control, - }, - { - .procname = "tcp_thin_linear_timeouts", - .data = &sysctl_tcp_thin_linear_timeouts, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_thin_dupack", - .data = &sysctl_tcp_thin_dupack, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_early_retrans", - .data = &sysctl_tcp_early_retrans, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &four, - }, - { - .procname = "tcp_min_tso_segs", - .data = &sysctl_tcp_min_tso_segs, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &one, - .extra2 = &gso_max_segs, - }, - { - .procname = "tcp_pacing_ss_ratio", - .data = &sysctl_tcp_pacing_ss_ratio, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &thousand, - }, - { - .procname = "tcp_pacing_ca_ratio", - .data = &sysctl_tcp_pacing_ca_ratio, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &thousand, - }, - { - .procname = "tcp_autocorking", - .data = &sysctl_tcp_autocorking, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, - { - .procname = "tcp_invalid_ratelimit", - .data = &sysctl_tcp_invalid_ratelimit, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_ms_jiffies, - }, - { - .procname = "icmp_msgs_per_sec", - .data = &sysctl_icmp_msgs_per_sec, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - }, - { - .procname = "icmp_msgs_burst", - .data = &sysctl_icmp_msgs_burst, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - }, - { - .procname = "udp_mem", - .data = &sysctl_udp_mem, - .maxlen = sizeof(sysctl_udp_mem), - .mode = 0644, - .proc_handler = proc_doulongvec_minmax, - }, - { - .procname = "udp_rmem_min", - .data = &sysctl_udp_rmem_min, - .maxlen = sizeof(sysctl_udp_rmem_min), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &one - }, - { - .procname = "udp_wmem_min", - .data = &sysctl_udp_wmem_min, - .maxlen = sizeof(sysctl_udp_wmem_min), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &one - }, - { } -}; - -static struct ctl_table ipv4_net_table[] = { - { - .procname = "icmp_echo_ignore_all", - .data = &init_net.ipv4.sysctl_icmp_echo_ignore_all, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "icmp_echo_ignore_broadcasts", - .data = &init_net.ipv4.sysctl_icmp_echo_ignore_broadcasts, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "icmp_ignore_bogus_error_responses", - .data = &init_net.ipv4.sysctl_icmp_ignore_bogus_error_responses, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "icmp_errors_use_inbound_ifaddr", - .data = &init_net.ipv4.sysctl_icmp_errors_use_inbound_ifaddr, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "icmp_ratelimit", - .data = &init_net.ipv4.sysctl_icmp_ratelimit, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_ms_jiffies, - }, - { - .procname = "icmp_ratemask", - .data = &init_net.ipv4.sysctl_icmp_ratemask, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "ping_group_range", - .data = &init_net.ipv4.ping_group_range.range, - .maxlen = sizeof(gid_t)*2, - .mode = 0644, - .proc_handler = ipv4_ping_group_range, - }, - { - .procname = "tcp_ecn", - .data = &init_net.ipv4.sysctl_tcp_ecn, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_ecn_fallback", - .data = &init_net.ipv4.sysctl_tcp_ecn_fallback, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "ip_dynaddr", - .data = &init_net.ipv4.sysctl_ip_dynaddr, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "ip_early_demux", - .data = &init_net.ipv4.sysctl_ip_early_demux, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "ip_default_ttl", - .data = &init_net.ipv4.sysctl_ip_default_ttl, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &ip_ttl_min, - .extra2 = &ip_ttl_max, - }, - { - .procname = "ip_local_port_range", - .maxlen = sizeof(init_net.ipv4.ip_local_ports.range), - .data = &init_net.ipv4.ip_local_ports.range, - .mode = 0644, - .proc_handler = ipv4_local_port_range, - }, - { - .procname = "ip_local_reserved_ports", - .data = &init_net.ipv4.sysctl_local_reserved_ports, - .maxlen = 65536, - .mode = 0644, - .proc_handler = proc_do_large_bitmap, - }, - { - .procname = "ip_no_pmtu_disc", - .data = &init_net.ipv4.sysctl_ip_no_pmtu_disc, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "ip_forward_use_pmtu", - .data = &init_net.ipv4.sysctl_ip_fwd_use_pmtu, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "ip_nonlocal_bind", - .data = &init_net.ipv4.sysctl_ip_nonlocal_bind, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "fwmark_reflect", - .data = &init_net.ipv4.sysctl_fwmark_reflect, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "tcp_fwmark_accept", - .data = &init_net.ipv4.sysctl_tcp_fwmark_accept, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#ifdef CONFIG_NET_L3_MASTER_DEV - { - .procname = "tcp_l3mdev_accept", - .data = &init_net.ipv4.sysctl_tcp_l3mdev_accept, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, -#endif - { - .procname = "tcp_mtu_probing", - .data = &init_net.ipv4.sysctl_tcp_mtu_probing, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "tcp_base_mss", - .data = &init_net.ipv4.sysctl_tcp_base_mss, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "tcp_probe_threshold", - .data = &init_net.ipv4.sysctl_tcp_probe_threshold, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "tcp_probe_interval", - .data = &init_net.ipv4.sysctl_tcp_probe_interval, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "igmp_link_local_mcast_reports", - .data = &init_net.ipv4.sysctl_igmp_llm_reports, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "igmp_max_memberships", - .data = &init_net.ipv4.sysctl_igmp_max_memberships, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "igmp_max_msf", - .data = &init_net.ipv4.sysctl_igmp_max_msf, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, -#ifdef CONFIG_IP_MULTICAST - { - .procname = "igmp_qrv", - .data = &init_net.ipv4.sysctl_igmp_qrv, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &one - }, -#endif - { - .procname = "tcp_keepalive_time", - .data = &init_net.ipv4.sysctl_tcp_keepalive_time, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "tcp_keepalive_probes", - .data = &init_net.ipv4.sysctl_tcp_keepalive_probes, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_keepalive_intvl", - .data = &init_net.ipv4.sysctl_tcp_keepalive_intvl, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "tcp_syn_retries", - .data = &init_net.ipv4.sysctl_tcp_syn_retries, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &tcp_syn_retries_min, - .extra2 = &tcp_syn_retries_max - }, - { - .procname = "tcp_synack_retries", - .data = &init_net.ipv4.sysctl_tcp_synack_retries, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, -#ifdef CONFIG_SYN_COOKIES - { - .procname = "tcp_syncookies", - .data = &init_net.ipv4.sysctl_tcp_syncookies, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, -#endif - { - .procname = "tcp_reordering", - .data = &init_net.ipv4.sysctl_tcp_reordering, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_retries1", - .data = &init_net.ipv4.sysctl_tcp_retries1, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra2 = &tcp_retr1_max - }, - { - .procname = "tcp_retries2", - .data = &init_net.ipv4.sysctl_tcp_retries2, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_orphan_retries", - .data = &init_net.ipv4.sysctl_tcp_orphan_retries, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "tcp_fin_timeout", - .data = &init_net.ipv4.sysctl_tcp_fin_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "tcp_notsent_lowat", - .data = &init_net.ipv4.sysctl_tcp_notsent_lowat, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#ifdef CONFIG_IP_ROUTE_MULTIPATH - { - .procname = "fib_multipath_use_neigh", - .data = &init_net.ipv4.sysctl_fib_multipath_use_neigh, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &one, - }, -#endif - { } -}; - -static __net_init int ipv4_sysctl_init_net(struct net *net) -{ - struct ctl_table *table; - - table = ipv4_net_table; - if (!net_eq(net, &init_net)) { - int i; - - table = kmemdup(table, sizeof(ipv4_net_table), GFP_KERNEL); - if (!table) - goto err_alloc; - - /* Update the variables to point into the current struct net */ - for (i = 0; i < ARRAY_SIZE(ipv4_net_table) - 1; i++) - table[i].data += (void *)net - (void *)&init_net; - } - - net->ipv4.ipv4_hdr = register_net_sysctl(net, "net/ipv4", table); - if (!net->ipv4.ipv4_hdr) - goto err_reg; - - net->ipv4.sysctl_local_reserved_ports = kzalloc(65536 / 8, GFP_KERNEL); - if (!net->ipv4.sysctl_local_reserved_ports) - goto err_ports; - - return 0; - -err_ports: - unregister_net_sysctl_table(net->ipv4.ipv4_hdr); -err_reg: - if (!net_eq(net, &init_net)) - kfree(table); -err_alloc: - return -ENOMEM; -} - -static __net_exit void ipv4_sysctl_exit_net(struct net *net) -{ - struct ctl_table *table; - - kfree(net->ipv4.sysctl_local_reserved_ports); - table = net->ipv4.ipv4_hdr->ctl_table_arg; - unregister_net_sysctl_table(net->ipv4.ipv4_hdr); - kfree(table); -} - -static __net_initdata struct pernet_operations ipv4_sysctl_ops = { - .init = ipv4_sysctl_init_net, - .exit = ipv4_sysctl_exit_net, -}; - -static __init int sysctl_ipv4_init(void) -{ - struct ctl_table_header *hdr; - - hdr = register_net_sysctl(&init_net, "net/ipv4", ipv4_table); - if (!hdr) - return -ENOMEM; - - if (register_pernet_subsys(&ipv4_sysctl_ops)) { - unregister_net_sysctl_table(hdr); - return -ENOMEM; - } - - return 0; -} - -__initcall(sysctl_ipv4_init); diff --git a/src/linux/net/ipv4/tcp.c b/src/linux/net/ipv4/tcp.c deleted file mode 100644 index 814af89..0000000 --- a/src/linux/net/ipv4/tcp.c +++ /dev/null @@ -1,3355 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Implementation of the Transmission Control Protocol(TCP). - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Mark Evans, - * Corey Minyard - * Florian La Roche, - * Charles Hedrick, - * Linus Torvalds, - * Alan Cox, - * Matthew Dillon, - * Arnt Gulbrandsen, - * Jorge Cwik, - * - * Fixes: - * Alan Cox : Numerous verify_area() calls - * Alan Cox : Set the ACK bit on a reset - * Alan Cox : Stopped it crashing if it closed while - * sk->inuse=1 and was trying to connect - * (tcp_err()). - * Alan Cox : All icmp error handling was broken - * pointers passed where wrong and the - * socket was looked up backwards. Nobody - * tested any icmp error code obviously. - * Alan Cox : tcp_err() now handled properly. It - * wakes people on errors. poll - * behaves and the icmp error race - * has gone by moving it into sock.c - * Alan Cox : tcp_send_reset() fixed to work for - * everything not just packets for - * unknown sockets. - * Alan Cox : tcp option processing. - * Alan Cox : Reset tweaked (still not 100%) [Had - * syn rule wrong] - * Herp Rosmanith : More reset fixes - * Alan Cox : No longer acks invalid rst frames. - * Acking any kind of RST is right out. - * Alan Cox : Sets an ignore me flag on an rst - * receive otherwise odd bits of prattle - * escape still - * Alan Cox : Fixed another acking RST frame bug. - * Should stop LAN workplace lockups. - * Alan Cox : Some tidyups using the new skb list - * facilities - * Alan Cox : sk->keepopen now seems to work - * Alan Cox : Pulls options out correctly on accepts - * Alan Cox : Fixed assorted sk->rqueue->next errors - * Alan Cox : PSH doesn't end a TCP read. Switched a - * bit to skb ops. - * Alan Cox : Tidied tcp_data to avoid a potential - * nasty. - * Alan Cox : Added some better commenting, as the - * tcp is hard to follow - * Alan Cox : Removed incorrect check for 20 * psh - * Michael O'Reilly : ack < copied bug fix. - * Johannes Stille : Misc tcp fixes (not all in yet). - * Alan Cox : FIN with no memory -> CRASH - * Alan Cox : Added socket option proto entries. - * Also added awareness of them to accept. - * Alan Cox : Added TCP options (SOL_TCP) - * Alan Cox : Switched wakeup calls to callbacks, - * so the kernel can layer network - * sockets. - * Alan Cox : Use ip_tos/ip_ttl settings. - * Alan Cox : Handle FIN (more) properly (we hope). - * Alan Cox : RST frames sent on unsynchronised - * state ack error. - * Alan Cox : Put in missing check for SYN bit. - * Alan Cox : Added tcp_select_window() aka NET2E - * window non shrink trick. - * Alan Cox : Added a couple of small NET2E timer - * fixes - * Charles Hedrick : TCP fixes - * Toomas Tamm : TCP window fixes - * Alan Cox : Small URG fix to rlogin ^C ack fight - * Charles Hedrick : Rewrote most of it to actually work - * Linus : Rewrote tcp_read() and URG handling - * completely - * Gerhard Koerting: Fixed some missing timer handling - * Matthew Dillon : Reworked TCP machine states as per RFC - * Gerhard Koerting: PC/TCP workarounds - * Adam Caldwell : Assorted timer/timing errors - * Matthew Dillon : Fixed another RST bug - * Alan Cox : Move to kernel side addressing changes. - * Alan Cox : Beginning work on TCP fastpathing - * (not yet usable) - * Arnt Gulbrandsen: Turbocharged tcp_check() routine. - * Alan Cox : TCP fast path debugging - * Alan Cox : Window clamping - * Michael Riepe : Bug in tcp_check() - * Matt Dillon : More TCP improvements and RST bug fixes - * Matt Dillon : Yet more small nasties remove from the - * TCP code (Be very nice to this man if - * tcp finally works 100%) 8) - * Alan Cox : BSD accept semantics. - * Alan Cox : Reset on closedown bug. - * Peter De Schrijver : ENOTCONN check missing in tcp_sendto(). - * Michael Pall : Handle poll() after URG properly in - * all cases. - * Michael Pall : Undo the last fix in tcp_read_urg() - * (multi URG PUSH broke rlogin). - * Michael Pall : Fix the multi URG PUSH problem in - * tcp_readable(), poll() after URG - * works now. - * Michael Pall : recv(...,MSG_OOB) never blocks in the - * BSD api. - * Alan Cox : Changed the semantics of sk->socket to - * fix a race and a signal problem with - * accept() and async I/O. - * Alan Cox : Relaxed the rules on tcp_sendto(). - * Yury Shevchuk : Really fixed accept() blocking problem. - * Craig I. Hagan : Allow for BSD compatible TIME_WAIT for - * clients/servers which listen in on - * fixed ports. - * Alan Cox : Cleaned the above up and shrank it to - * a sensible code size. - * Alan Cox : Self connect lockup fix. - * Alan Cox : No connect to multicast. - * Ross Biro : Close unaccepted children on master - * socket close. - * Alan Cox : Reset tracing code. - * Alan Cox : Spurious resets on shutdown. - * Alan Cox : Giant 15 minute/60 second timer error - * Alan Cox : Small whoops in polling before an - * accept. - * Alan Cox : Kept the state trace facility since - * it's handy for debugging. - * Alan Cox : More reset handler fixes. - * Alan Cox : Started rewriting the code based on - * the RFC's for other useful protocol - * references see: Comer, KA9Q NOS, and - * for a reference on the difference - * between specifications and how BSD - * works see the 4.4lite source. - * A.N.Kuznetsov : Don't time wait on completion of tidy - * close. - * Linus Torvalds : Fin/Shutdown & copied_seq changes. - * Linus Torvalds : Fixed BSD port reuse to work first syn - * Alan Cox : Reimplemented timers as per the RFC - * and using multiple timers for sanity. - * Alan Cox : Small bug fixes, and a lot of new - * comments. - * Alan Cox : Fixed dual reader crash by locking - * the buffers (much like datagram.c) - * Alan Cox : Fixed stuck sockets in probe. A probe - * now gets fed up of retrying without - * (even a no space) answer. - * Alan Cox : Extracted closing code better - * Alan Cox : Fixed the closing state machine to - * resemble the RFC. - * Alan Cox : More 'per spec' fixes. - * Jorge Cwik : Even faster checksumming. - * Alan Cox : tcp_data() doesn't ack illegal PSH - * only frames. At least one pc tcp stack - * generates them. - * Alan Cox : Cache last socket. - * Alan Cox : Per route irtt. - * Matt Day : poll()->select() match BSD precisely on error - * Alan Cox : New buffers - * Marc Tamsky : Various sk->prot->retransmits and - * sk->retransmits misupdating fixed. - * Fixed tcp_write_timeout: stuck close, - * and TCP syn retries gets used now. - * Mark Yarvis : In tcp_read_wakeup(), don't send an - * ack if state is TCP_CLOSED. - * Alan Cox : Look up device on a retransmit - routes may - * change. Doesn't yet cope with MSS shrink right - * but it's a start! - * Marc Tamsky : Closing in closing fixes. - * Mike Shaver : RFC1122 verifications. - * Alan Cox : rcv_saddr errors. - * Alan Cox : Block double connect(). - * Alan Cox : Small hooks for enSKIP. - * Alexey Kuznetsov: Path MTU discovery. - * Alan Cox : Support soft errors. - * Alan Cox : Fix MTU discovery pathological case - * when the remote claims no mtu! - * Marc Tamsky : TCP_CLOSE fix. - * Colin (G3TNE) : Send a reset on syn ack replies in - * window but wrong (fixes NT lpd problems) - * Pedro Roque : Better TCP window handling, delayed ack. - * Joerg Reuter : No modification of locked buffers in - * tcp_do_retransmit() - * Eric Schenk : Changed receiver side silly window - * avoidance algorithm to BSD style - * algorithm. This doubles throughput - * against machines running Solaris, - * and seems to result in general - * improvement. - * Stefan Magdalinski : adjusted tcp_readable() to fix FIONREAD - * Willy Konynenberg : Transparent proxying support. - * Mike McLagan : Routing by source - * Keith Owens : Do proper merging with partial SKB's in - * tcp_do_sendmsg to avoid burstiness. - * Eric Schenk : Fix fast close down bug with - * shutdown() followed by close(). - * Andi Kleen : Make poll agree with SIGIO - * Salvatore Sanfilippo : Support SO_LINGER with linger == 1 and - * lingertime == 0 (RFC 793 ABORT Call) - * Hirokazu Takahashi : Use copy_from_user() instead of - * csum_and_copy_from_user() if possible. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or(at your option) any later version. - * - * Description of States: - * - * TCP_SYN_SENT sent a connection request, waiting for ack - * - * TCP_SYN_RECV received a connection request, sent ack, - * waiting for final ack in three-way handshake. - * - * TCP_ESTABLISHED connection established - * - * TCP_FIN_WAIT1 our side has shutdown, waiting to complete - * transmission of remaining buffered data - * - * TCP_FIN_WAIT2 all buffered data sent, waiting for remote - * to shutdown - * - * TCP_CLOSING both sides have shutdown but we still have - * data we have to finish sending - * - * TCP_TIME_WAIT timeout to catch resent junk before entering - * closed, can only be entered from FIN_WAIT2 - * or CLOSING. Required because the other end - * may not have gotten our last ACK causing it - * to retransmit the data packet (which we ignore) - * - * TCP_CLOSE_WAIT remote side has shutdown and is waiting for - * us to finish writing our data and to shutdown - * (we have to close() to move on to LAST_ACK) - * - * TCP_LAST_ACK out side has shutdown after remote has - * shutdown. There may still be data in our - * buffer that we have to finish sending - * - * TCP_CLOSE socket is finished - */ - -#define pr_fmt(fmt) "TCP: " fmt - -#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 - -#include -#include -#include -#include - -int sysctl_tcp_min_tso_segs __read_mostly = 2; - -int sysctl_tcp_autocorking __read_mostly = 1; - -struct percpu_counter tcp_orphan_count; -EXPORT_SYMBOL_GPL(tcp_orphan_count); - -long sysctl_tcp_mem[3] __read_mostly; -int sysctl_tcp_wmem[3] __read_mostly; -int sysctl_tcp_rmem[3] __read_mostly; - -EXPORT_SYMBOL(sysctl_tcp_mem); -EXPORT_SYMBOL(sysctl_tcp_rmem); -EXPORT_SYMBOL(sysctl_tcp_wmem); - -atomic_long_t tcp_memory_allocated; /* Current allocated memory. */ -EXPORT_SYMBOL(tcp_memory_allocated); - -/* - * Current number of TCP sockets. - */ -struct percpu_counter tcp_sockets_allocated; -EXPORT_SYMBOL(tcp_sockets_allocated); - -/* - * TCP splice context - */ -struct tcp_splice_state { - struct pipe_inode_info *pipe; - size_t len; - unsigned int flags; -}; - -/* - * Pressure flag: try to collapse. - * Technical note: it is used by multiple contexts non atomically. - * All the __sk_mem_schedule() is of this nature: accounting - * is strict, actions are advisory and have some latency. - */ -int tcp_memory_pressure __read_mostly; -EXPORT_SYMBOL(tcp_memory_pressure); - -void tcp_enter_memory_pressure(struct sock *sk) -{ - if (!tcp_memory_pressure) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMEMORYPRESSURES); - tcp_memory_pressure = 1; - } -} -EXPORT_SYMBOL(tcp_enter_memory_pressure); - -/* Convert seconds to retransmits based on initial and max timeout */ -static u8 secs_to_retrans(int seconds, int timeout, int rto_max) -{ - u8 res = 0; - - if (seconds > 0) { - int period = timeout; - - res = 1; - while (seconds > period && res < 255) { - res++; - timeout <<= 1; - if (timeout > rto_max) - timeout = rto_max; - period += timeout; - } - } - return res; -} - -/* Convert retransmits to seconds based on initial and max timeout */ -static int retrans_to_secs(u8 retrans, int timeout, int rto_max) -{ - int period = 0; - - if (retrans > 0) { - period = timeout; - while (--retrans) { - timeout <<= 1; - if (timeout > rto_max) - timeout = rto_max; - period += timeout; - } - } - return period; -} - -/* Address-family independent initialization for a tcp_sock. - * - * NOTE: A lot of things set to zero explicitly by call to - * sk_alloc() so need not be done here. - */ -void tcp_init_sock(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - - tp->out_of_order_queue = RB_ROOT; - tcp_init_xmit_timers(sk); - tcp_prequeue_init(tp); - INIT_LIST_HEAD(&tp->tsq_node); - - icsk->icsk_rto = TCP_TIMEOUT_INIT; - tp->mdev_us = jiffies_to_usecs(TCP_TIMEOUT_INIT); - minmax_reset(&tp->rtt_min, tcp_time_stamp, ~0U); - - /* So many TCP implementations out there (incorrectly) count the - * initial SYN frame in their delayed-ACK and congestion control - * algorithms that we must have the following bandaid to talk - * efficiently to them. -DaveM - */ - tp->snd_cwnd = TCP_INIT_CWND; - - /* There's a bubble in the pipe until at least the first ACK. */ - tp->app_limited = ~0U; - - /* See draft-stevens-tcpca-spec-01 for discussion of the - * initialization of these values. - */ - tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; - tp->snd_cwnd_clamp = ~0; - tp->mss_cache = TCP_MSS_DEFAULT; - u64_stats_init(&tp->syncp); - - tp->reordering = sock_net(sk)->ipv4.sysctl_tcp_reordering; - tcp_enable_early_retrans(tp); - tcp_assign_congestion_control(sk); - - tp->tsoffset = 0; - - sk->sk_state = TCP_CLOSE; - - sk->sk_write_space = sk_stream_write_space; - sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); - - icsk->icsk_sync_mss = tcp_sync_mss; - - sk->sk_sndbuf = sysctl_tcp_wmem[1]; - sk->sk_rcvbuf = sysctl_tcp_rmem[1]; - - local_bh_disable(); - sk_sockets_allocated_inc(sk); - local_bh_enable(); -} -EXPORT_SYMBOL(tcp_init_sock); - -static void tcp_tx_timestamp(struct sock *sk, u16 tsflags, struct sk_buff *skb) -{ - if (tsflags) { - struct skb_shared_info *shinfo = skb_shinfo(skb); - struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); - - sock_tx_timestamp(sk, tsflags, &shinfo->tx_flags); - if (tsflags & SOF_TIMESTAMPING_TX_ACK) - tcb->txstamp_ack = 1; - if (tsflags & SOF_TIMESTAMPING_TX_RECORD_MASK) - shinfo->tskey = TCP_SKB_CB(skb)->seq + skb->len - 1; - } -} - -/* - * Wait for a TCP event. - * - * Note that we don't need to lock the socket, as the upper poll layers - * take care of normal races (between the test and the event) and we don't - * go look at any of the socket buffers directly. - */ -unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait) -{ - unsigned int mask; - struct sock *sk = sock->sk; - const struct tcp_sock *tp = tcp_sk(sk); - int state; - - sock_rps_record_flow(sk); - - sock_poll_wait(file, sk_sleep(sk), wait); - - state = sk_state_load(sk); - if (state == TCP_LISTEN) - return inet_csk_listen_poll(sk); - - /* Socket is not locked. We are protected from async events - * by poll logic and correct handling of state changes - * made by other threads is impossible in any case. - */ - - mask = 0; - - /* - * POLLHUP is certainly not done right. But poll() doesn't - * have a notion of HUP in just one direction, and for a - * socket the read side is more interesting. - * - * Some poll() documentation says that POLLHUP is incompatible - * with the POLLOUT/POLLWR flags, so somebody should check this - * all. But careful, it tends to be safer to return too many - * bits than too few, and you can easily break real applications - * if you don't tell them that something has hung up! - * - * Check-me. - * - * Check number 1. POLLHUP is _UNMASKABLE_ event (see UNIX98 and - * our fs/select.c). It means that after we received EOF, - * poll always returns immediately, making impossible poll() on write() - * in state CLOSE_WAIT. One solution is evident --- to set POLLHUP - * if and only if shutdown has been made in both directions. - * Actually, it is interesting to look how Solaris and DUX - * solve this dilemma. I would prefer, if POLLHUP were maskable, - * then we could set it on SND_SHUTDOWN. BTW examples given - * in Stevens' books assume exactly this behaviour, it explains - * why POLLHUP is incompatible with POLLOUT. --ANK - * - * NOTE. Check for TCP_CLOSE is added. The goal is to prevent - * blocking on fresh not-connected or disconnected socket. --ANK - */ - if (sk->sk_shutdown == SHUTDOWN_MASK || state == TCP_CLOSE) - mask |= POLLHUP; - if (sk->sk_shutdown & RCV_SHUTDOWN) - mask |= POLLIN | POLLRDNORM | POLLRDHUP; - - /* Connected or passive Fast Open socket? */ - if (state != TCP_SYN_SENT && - (state != TCP_SYN_RECV || tp->fastopen_rsk)) { - int target = sock_rcvlowat(sk, 0, INT_MAX); - - if (tp->urg_seq == tp->copied_seq && - !sock_flag(sk, SOCK_URGINLINE) && - tp->urg_data) - target++; - - if (tp->rcv_nxt - tp->copied_seq >= target) - mask |= POLLIN | POLLRDNORM; - - if (!(sk->sk_shutdown & SEND_SHUTDOWN)) { - if (sk_stream_is_writeable(sk)) { - mask |= POLLOUT | POLLWRNORM; - } else { /* send SIGIO later */ - sk_set_bit(SOCKWQ_ASYNC_NOSPACE, sk); - set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); - - /* Race breaker. If space is freed after - * wspace test but before the flags are set, - * IO signal will be lost. Memory barrier - * pairs with the input side. - */ - smp_mb__after_atomic(); - if (sk_stream_is_writeable(sk)) - mask |= POLLOUT | POLLWRNORM; - } - } else - mask |= POLLOUT | POLLWRNORM; - - if (tp->urg_data & TCP_URG_VALID) - mask |= POLLPRI; - } - /* This barrier is coupled with smp_wmb() in tcp_reset() */ - smp_rmb(); - if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) - mask |= POLLERR; - - return mask; -} -EXPORT_SYMBOL(tcp_poll); - -int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg) -{ - struct tcp_sock *tp = tcp_sk(sk); - int answ; - bool slow; - - switch (cmd) { - case SIOCINQ: - if (sk->sk_state == TCP_LISTEN) - return -EINVAL; - - slow = lock_sock_fast(sk); - answ = tcp_inq(sk); - unlock_sock_fast(sk, slow); - break; - case SIOCATMARK: - answ = tp->urg_data && tp->urg_seq == tp->copied_seq; - break; - case SIOCOUTQ: - if (sk->sk_state == TCP_LISTEN) - return -EINVAL; - - if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) - answ = 0; - else - answ = tp->write_seq - tp->snd_una; - break; - case SIOCOUTQNSD: - if (sk->sk_state == TCP_LISTEN) - return -EINVAL; - - if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) - answ = 0; - else - answ = tp->write_seq - tp->snd_nxt; - break; - default: - return -ENOIOCTLCMD; - } - - return put_user(answ, (int __user *)arg); -} -EXPORT_SYMBOL(tcp_ioctl); - -static inline void tcp_mark_push(struct tcp_sock *tp, struct sk_buff *skb) -{ - TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_PSH; - tp->pushed_seq = tp->write_seq; -} - -static inline bool forced_push(const struct tcp_sock *tp) -{ - return after(tp->write_seq, tp->pushed_seq + (tp->max_window >> 1)); -} - -static void skb_entail(struct sock *sk, struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); - - skb->csum = 0; - tcb->seq = tcb->end_seq = tp->write_seq; - tcb->tcp_flags = TCPHDR_ACK; - tcb->sacked = 0; - __skb_header_release(skb); - tcp_add_write_queue_tail(sk, skb); - sk->sk_wmem_queued += skb->truesize; - sk_mem_charge(sk, skb->truesize); - if (tp->nonagle & TCP_NAGLE_PUSH) - tp->nonagle &= ~TCP_NAGLE_PUSH; - - tcp_slow_start_after_idle_check(sk); -} - -static inline void tcp_mark_urg(struct tcp_sock *tp, int flags) -{ - if (flags & MSG_OOB) - tp->snd_up = tp->write_seq; -} - -/* If a not yet filled skb is pushed, do not send it if - * we have data packets in Qdisc or NIC queues : - * Because TX completion will happen shortly, it gives a chance - * to coalesce future sendmsg() payload into this skb, without - * need for a timer, and with no latency trade off. - * As packets containing data payload have a bigger truesize - * than pure acks (dataless) packets, the last checks prevent - * autocorking if we only have an ACK in Qdisc/NIC queues, - * or if TX completion was delayed after we processed ACK packet. - */ -static bool tcp_should_autocork(struct sock *sk, struct sk_buff *skb, - int size_goal) -{ - return skb->len < size_goal && - sysctl_tcp_autocorking && - skb != tcp_write_queue_head(sk) && - atomic_read(&sk->sk_wmem_alloc) > skb->truesize; -} - -static void tcp_push(struct sock *sk, int flags, int mss_now, - int nonagle, int size_goal) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *skb; - - if (!tcp_send_head(sk)) - return; - - skb = tcp_write_queue_tail(sk); - if (!(flags & MSG_MORE) || forced_push(tp)) - tcp_mark_push(tp, skb); - - tcp_mark_urg(tp, flags); - - if (tcp_should_autocork(sk, skb, size_goal)) { - - /* avoid atomic op if TSQ_THROTTLED bit is already set */ - if (!test_bit(TSQ_THROTTLED, &tp->tsq_flags)) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAUTOCORKING); - set_bit(TSQ_THROTTLED, &tp->tsq_flags); - } - /* It is possible TX completion already happened - * before we set TSQ_THROTTLED. - */ - if (atomic_read(&sk->sk_wmem_alloc) > skb->truesize) - return; - } - - if (flags & MSG_MORE) - nonagle = TCP_NAGLE_CORK; - - __tcp_push_pending_frames(sk, mss_now, nonagle); -} - -static int tcp_splice_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, - unsigned int offset, size_t len) -{ - struct tcp_splice_state *tss = rd_desc->arg.data; - int ret; - - ret = skb_splice_bits(skb, skb->sk, offset, tss->pipe, - min(rd_desc->count, len), tss->flags); - if (ret > 0) - rd_desc->count -= ret; - return ret; -} - -static int __tcp_splice_read(struct sock *sk, struct tcp_splice_state *tss) -{ - /* Store TCP splice context information in read_descriptor_t. */ - read_descriptor_t rd_desc = { - .arg.data = tss, - .count = tss->len, - }; - - return tcp_read_sock(sk, &rd_desc, tcp_splice_data_recv); -} - -/** - * tcp_splice_read - splice data from TCP socket to a pipe - * @sock: socket to splice from - * @ppos: position (not valid) - * @pipe: pipe to splice to - * @len: number of bytes to splice - * @flags: splice modifier flags - * - * Description: - * Will read pages from given socket and fill them into a pipe. - * - **/ -ssize_t tcp_splice_read(struct socket *sock, loff_t *ppos, - struct pipe_inode_info *pipe, size_t len, - unsigned int flags) -{ - struct sock *sk = sock->sk; - struct tcp_splice_state tss = { - .pipe = pipe, - .len = len, - .flags = flags, - }; - long timeo; - ssize_t spliced; - int ret; - - sock_rps_record_flow(sk); - /* - * We can't seek on a socket input - */ - if (unlikely(*ppos)) - return -ESPIPE; - - ret = spliced = 0; - - lock_sock(sk); - - timeo = sock_rcvtimeo(sk, sock->file->f_flags & O_NONBLOCK); - while (tss.len) { - ret = __tcp_splice_read(sk, &tss); - if (ret < 0) - break; - else if (!ret) { - if (spliced) - break; - if (sock_flag(sk, SOCK_DONE)) - break; - if (sk->sk_err) { - ret = sock_error(sk); - break; - } - if (sk->sk_shutdown & RCV_SHUTDOWN) - break; - if (sk->sk_state == TCP_CLOSE) { - /* - * This occurs when user tries to read - * from never connected socket. - */ - if (!sock_flag(sk, SOCK_DONE)) - ret = -ENOTCONN; - break; - } - if (!timeo) { - ret = -EAGAIN; - break; - } - sk_wait_data(sk, &timeo, NULL); - if (signal_pending(current)) { - ret = sock_intr_errno(timeo); - break; - } - continue; - } - tss.len -= ret; - spliced += ret; - - if (!timeo) - break; - release_sock(sk); - lock_sock(sk); - - if (sk->sk_err || sk->sk_state == TCP_CLOSE || - (sk->sk_shutdown & RCV_SHUTDOWN) || - signal_pending(current)) - break; - } - - release_sock(sk); - - if (spliced) - return spliced; - - return ret; -} -EXPORT_SYMBOL(tcp_splice_read); - -struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp, - bool force_schedule) -{ - struct sk_buff *skb; - - /* The TCP header must be at least 32-bit aligned. */ - size = ALIGN(size, 4); - - if (unlikely(tcp_under_memory_pressure(sk))) - sk_mem_reclaim_partial(sk); - - skb = alloc_skb_fclone(size + sk->sk_prot->max_header, gfp); - if (likely(skb)) { - bool mem_scheduled; - - if (force_schedule) { - mem_scheduled = true; - sk_forced_mem_schedule(sk, skb->truesize); - } else { - mem_scheduled = sk_wmem_schedule(sk, skb->truesize); - } - if (likely(mem_scheduled)) { - skb_reserve(skb, sk->sk_prot->max_header); - /* - * Make sure that we have exactly size bytes - * available to the caller, no more, no less. - */ - skb->reserved_tailroom = skb->end - skb->tail - size; - return skb; - } - __kfree_skb(skb); - } else { - sk->sk_prot->enter_memory_pressure(sk); - sk_stream_moderate_sndbuf(sk); - } - return NULL; -} - -static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now, - int large_allowed) -{ - struct tcp_sock *tp = tcp_sk(sk); - u32 new_size_goal, size_goal; - - if (!large_allowed || !sk_can_gso(sk)) - return mss_now; - - /* Note : tcp_tso_autosize() will eventually split this later */ - new_size_goal = sk->sk_gso_max_size - 1 - MAX_TCP_HEADER; - new_size_goal = tcp_bound_to_half_wnd(tp, new_size_goal); - - /* We try hard to avoid divides here */ - size_goal = tp->gso_segs * mss_now; - if (unlikely(new_size_goal < size_goal || - new_size_goal >= size_goal + mss_now)) { - tp->gso_segs = min_t(u16, new_size_goal / mss_now, - sk->sk_gso_max_segs); - size_goal = tp->gso_segs * mss_now; - } - - return max(size_goal, mss_now); -} - -static int tcp_send_mss(struct sock *sk, int *size_goal, int flags) -{ - int mss_now; - - mss_now = tcp_current_mss(sk); - *size_goal = tcp_xmit_size_goal(sk, mss_now, !(flags & MSG_OOB)); - - return mss_now; -} - -static ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset, - size_t size, int flags) -{ - struct tcp_sock *tp = tcp_sk(sk); - int mss_now, size_goal; - int err; - ssize_t copied; - long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); - - /* Wait for a connection to finish. One exception is TCP Fast Open - * (passive side) where data is allowed to be sent before a connection - * is fully established. - */ - if (((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) && - !tcp_passive_fastopen(sk)) { - err = sk_stream_wait_connect(sk, &timeo); - if (err != 0) - goto out_err; - } - - sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); - - mss_now = tcp_send_mss(sk, &size_goal, flags); - copied = 0; - - err = -EPIPE; - if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) - goto out_err; - - while (size > 0) { - struct sk_buff *skb = tcp_write_queue_tail(sk); - int copy, i; - bool can_coalesce; - - if (!tcp_send_head(sk) || (copy = size_goal - skb->len) <= 0 || - !tcp_skb_can_collapse_to(skb)) { -new_segment: - if (!sk_stream_memory_free(sk)) - goto wait_for_sndbuf; - - skb = sk_stream_alloc_skb(sk, 0, sk->sk_allocation, - skb_queue_empty(&sk->sk_write_queue)); - if (!skb) - goto wait_for_memory; - - skb_entail(sk, skb); - copy = size_goal; - } - - if (copy > size) - copy = size; - - i = skb_shinfo(skb)->nr_frags; - can_coalesce = skb_can_coalesce(skb, i, page, offset); - if (!can_coalesce && i >= sysctl_max_skb_frags) { - tcp_mark_push(tp, skb); - goto new_segment; - } - if (!sk_wmem_schedule(sk, copy)) - goto wait_for_memory; - - if (can_coalesce) { - skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy); - } else { - get_page(page); - skb_fill_page_desc(skb, i, page, offset, copy); - } - skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG; - - skb->len += copy; - skb->data_len += copy; - skb->truesize += copy; - sk->sk_wmem_queued += copy; - sk_mem_charge(sk, copy); - skb->ip_summed = CHECKSUM_PARTIAL; - tp->write_seq += copy; - TCP_SKB_CB(skb)->end_seq += copy; - tcp_skb_pcount_set(skb, 0); - - if (!copied) - TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH; - - copied += copy; - offset += copy; - size -= copy; - if (!size) { - tcp_tx_timestamp(sk, sk->sk_tsflags, skb); - goto out; - } - - if (skb->len < size_goal || (flags & MSG_OOB)) - continue; - - if (forced_push(tp)) { - tcp_mark_push(tp, skb); - __tcp_push_pending_frames(sk, mss_now, TCP_NAGLE_PUSH); - } else if (skb == tcp_send_head(sk)) - tcp_push_one(sk, mss_now); - continue; - -wait_for_sndbuf: - set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); -wait_for_memory: - tcp_push(sk, flags & ~MSG_MORE, mss_now, - TCP_NAGLE_PUSH, size_goal); - - err = sk_stream_wait_memory(sk, &timeo); - if (err != 0) - goto do_error; - - mss_now = tcp_send_mss(sk, &size_goal, flags); - } - -out: - if (copied && !(flags & MSG_SENDPAGE_NOTLAST)) - tcp_push(sk, flags, mss_now, tp->nonagle, size_goal); - return copied; - -do_error: - if (copied) - goto out; -out_err: - /* make sure we wake any epoll edge trigger waiter */ - if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && err == -EAGAIN)) - sk->sk_write_space(sk); - return sk_stream_error(sk, flags, err); -} - -int tcp_sendpage(struct sock *sk, struct page *page, int offset, - size_t size, int flags) -{ - ssize_t res; - - if (!(sk->sk_route_caps & NETIF_F_SG) || - !sk_check_csum_caps(sk)) - return sock_no_sendpage(sk->sk_socket, page, offset, size, - flags); - - lock_sock(sk); - - tcp_rate_check_app_limited(sk); /* is sending application-limited? */ - - res = do_tcp_sendpages(sk, page, offset, size, flags); - release_sock(sk); - return res; -} -EXPORT_SYMBOL(tcp_sendpage); - -/* Do not bother using a page frag for very small frames. - * But use this heuristic only for the first skb in write queue. - * - * Having no payload in skb->head allows better SACK shifting - * in tcp_shift_skb_data(), reducing sack/rack overhead, because - * write queue has less skbs. - * Each skb can hold up to MAX_SKB_FRAGS * 32Kbytes, or ~0.5 MB. - * This also speeds up tso_fragment(), since it wont fallback - * to tcp_fragment(). - */ -static int linear_payload_sz(bool first_skb) -{ - if (first_skb) - return SKB_WITH_OVERHEAD(2048 - MAX_TCP_HEADER); - return 0; -} - -static int select_size(const struct sock *sk, bool sg, bool first_skb) -{ - const struct tcp_sock *tp = tcp_sk(sk); - int tmp = tp->mss_cache; - - if (sg) { - if (sk_can_gso(sk)) { - tmp = linear_payload_sz(first_skb); - } else { - int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER); - - if (tmp >= pgbreak && - tmp <= pgbreak + (MAX_SKB_FRAGS - 1) * PAGE_SIZE) - tmp = pgbreak; - } - } - - return tmp; -} - -void tcp_free_fastopen_req(struct tcp_sock *tp) -{ - if (tp->fastopen_req) { - kfree(tp->fastopen_req); - tp->fastopen_req = NULL; - } -} - -static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, - int *copied, size_t size) -{ - struct tcp_sock *tp = tcp_sk(sk); - int err, flags; - - if (!(sysctl_tcp_fastopen & TFO_CLIENT_ENABLE)) - return -EOPNOTSUPP; - if (tp->fastopen_req) - return -EALREADY; /* Another Fast Open is in progress */ - - tp->fastopen_req = kzalloc(sizeof(struct tcp_fastopen_request), - sk->sk_allocation); - if (unlikely(!tp->fastopen_req)) - return -ENOBUFS; - tp->fastopen_req->data = msg; - tp->fastopen_req->size = size; - - flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0; - err = __inet_stream_connect(sk->sk_socket, msg->msg_name, - msg->msg_namelen, flags); - *copied = tp->fastopen_req->copied; - tcp_free_fastopen_req(tp); - return err; -} - -int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *skb; - struct sockcm_cookie sockc; - int flags, err, copied = 0; - int mss_now = 0, size_goal, copied_syn = 0; - bool process_backlog = false; - bool sg; - long timeo; - - lock_sock(sk); - - flags = msg->msg_flags; - if (flags & MSG_FASTOPEN) { - err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size); - if (err == -EINPROGRESS && copied_syn > 0) - goto out; - else if (err) - goto out_err; - } - - timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); - - tcp_rate_check_app_limited(sk); /* is sending application-limited? */ - - /* Wait for a connection to finish. One exception is TCP Fast Open - * (passive side) where data is allowed to be sent before a connection - * is fully established. - */ - if (((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) && - !tcp_passive_fastopen(sk)) { - err = sk_stream_wait_connect(sk, &timeo); - if (err != 0) - goto do_error; - } - - if (unlikely(tp->repair)) { - if (tp->repair_queue == TCP_RECV_QUEUE) { - copied = tcp_send_rcvq(sk, msg, size); - goto out_nopush; - } - - err = -EINVAL; - if (tp->repair_queue == TCP_NO_QUEUE) - goto out_err; - - /* 'common' sending to sendq */ - } - - sockc.tsflags = sk->sk_tsflags; - if (msg->msg_controllen) { - err = sock_cmsg_send(sk, msg, &sockc); - if (unlikely(err)) { - err = -EINVAL; - goto out_err; - } - } - - /* This should be in poll */ - sk_clear_bit(SOCKWQ_ASYNC_NOSPACE, sk); - - /* Ok commence sending. */ - copied = 0; - -restart: - mss_now = tcp_send_mss(sk, &size_goal, flags); - - err = -EPIPE; - if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) - goto do_error; - - sg = !!(sk->sk_route_caps & NETIF_F_SG); - - while (msg_data_left(msg)) { - int copy = 0; - int max = size_goal; - - skb = tcp_write_queue_tail(sk); - if (tcp_send_head(sk)) { - if (skb->ip_summed == CHECKSUM_NONE) - max = mss_now; - copy = max - skb->len; - } - - if (copy <= 0 || !tcp_skb_can_collapse_to(skb)) { - bool first_skb; - -new_segment: - /* Allocate new segment. If the interface is SG, - * allocate skb fitting to single page. - */ - if (!sk_stream_memory_free(sk)) - goto wait_for_sndbuf; - - if (process_backlog && sk_flush_backlog(sk)) { - process_backlog = false; - goto restart; - } - first_skb = skb_queue_empty(&sk->sk_write_queue); - skb = sk_stream_alloc_skb(sk, - select_size(sk, sg, first_skb), - sk->sk_allocation, - first_skb); - if (!skb) - goto wait_for_memory; - - process_backlog = true; - /* - * Check whether we can use HW checksum. - */ - if (sk_check_csum_caps(sk)) - skb->ip_summed = CHECKSUM_PARTIAL; - - skb_entail(sk, skb); - copy = size_goal; - max = size_goal; - - /* All packets are restored as if they have - * already been sent. skb_mstamp isn't set to - * avoid wrong rtt estimation. - */ - if (tp->repair) - TCP_SKB_CB(skb)->sacked |= TCPCB_REPAIRED; - } - - /* Try to append data to the end of skb. */ - if (copy > msg_data_left(msg)) - copy = msg_data_left(msg); - - /* Where to copy to? */ - if (skb_availroom(skb) > 0) { - /* We have some space in skb head. Superb! */ - copy = min_t(int, copy, skb_availroom(skb)); - err = skb_add_data_nocache(sk, skb, &msg->msg_iter, copy); - if (err) - goto do_fault; - } else { - bool merge = true; - int i = skb_shinfo(skb)->nr_frags; - struct page_frag *pfrag = sk_page_frag(sk); - - if (!sk_page_frag_refill(sk, pfrag)) - goto wait_for_memory; - - if (!skb_can_coalesce(skb, i, pfrag->page, - pfrag->offset)) { - if (i >= sysctl_max_skb_frags || !sg) { - tcp_mark_push(tp, skb); - goto new_segment; - } - merge = false; - } - - copy = min_t(int, copy, pfrag->size - pfrag->offset); - - if (!sk_wmem_schedule(sk, copy)) - goto wait_for_memory; - - err = skb_copy_to_page_nocache(sk, &msg->msg_iter, skb, - pfrag->page, - pfrag->offset, - copy); - if (err) - goto do_error; - - /* Update the skb. */ - if (merge) { - skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy); - } else { - skb_fill_page_desc(skb, i, pfrag->page, - pfrag->offset, copy); - get_page(pfrag->page); - } - pfrag->offset += copy; - } - - if (!copied) - TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_PSH; - - tp->write_seq += copy; - TCP_SKB_CB(skb)->end_seq += copy; - tcp_skb_pcount_set(skb, 0); - - copied += copy; - if (!msg_data_left(msg)) { - tcp_tx_timestamp(sk, sockc.tsflags, skb); - if (unlikely(flags & MSG_EOR)) - TCP_SKB_CB(skb)->eor = 1; - goto out; - } - - if (skb->len < max || (flags & MSG_OOB) || unlikely(tp->repair)) - continue; - - if (forced_push(tp)) { - tcp_mark_push(tp, skb); - __tcp_push_pending_frames(sk, mss_now, TCP_NAGLE_PUSH); - } else if (skb == tcp_send_head(sk)) - tcp_push_one(sk, mss_now); - continue; - -wait_for_sndbuf: - set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); -wait_for_memory: - if (copied) - tcp_push(sk, flags & ~MSG_MORE, mss_now, - TCP_NAGLE_PUSH, size_goal); - - err = sk_stream_wait_memory(sk, &timeo); - if (err != 0) - goto do_error; - - mss_now = tcp_send_mss(sk, &size_goal, flags); - } - -out: - if (copied) - tcp_push(sk, flags, mss_now, tp->nonagle, size_goal); -out_nopush: - release_sock(sk); - return copied + copied_syn; - -do_fault: - if (!skb->len) { - tcp_unlink_write_queue(skb, sk); - /* It is the one place in all of TCP, except connection - * reset, where we can be unlinking the send_head. - */ - tcp_check_send_head(sk, skb); - sk_wmem_free_skb(sk, skb); - } - -do_error: - if (copied + copied_syn) - goto out; -out_err: - err = sk_stream_error(sk, flags, err); - /* make sure we wake any epoll edge trigger waiter */ - if (unlikely(skb_queue_len(&sk->sk_write_queue) == 0 && err == -EAGAIN)) - sk->sk_write_space(sk); - release_sock(sk); - return err; -} -EXPORT_SYMBOL(tcp_sendmsg); - -/* - * Handle reading urgent data. BSD has very simple semantics for - * this, no blocking and very strange errors 8) - */ - -static int tcp_recv_urg(struct sock *sk, struct msghdr *msg, int len, int flags) -{ - struct tcp_sock *tp = tcp_sk(sk); - - /* No URG data to read. */ - if (sock_flag(sk, SOCK_URGINLINE) || !tp->urg_data || - tp->urg_data == TCP_URG_READ) - return -EINVAL; /* Yes this is right ! */ - - if (sk->sk_state == TCP_CLOSE && !sock_flag(sk, SOCK_DONE)) - return -ENOTCONN; - - if (tp->urg_data & TCP_URG_VALID) { - int err = 0; - char c = tp->urg_data; - - if (!(flags & MSG_PEEK)) - tp->urg_data = TCP_URG_READ; - - /* Read urgent data. */ - msg->msg_flags |= MSG_OOB; - - if (len > 0) { - if (!(flags & MSG_TRUNC)) - err = memcpy_to_msg(msg, &c, 1); - len = 1; - } else - msg->msg_flags |= MSG_TRUNC; - - return err ? -EFAULT : len; - } - - if (sk->sk_state == TCP_CLOSE || (sk->sk_shutdown & RCV_SHUTDOWN)) - return 0; - - /* Fixed the recv(..., MSG_OOB) behaviour. BSD docs and - * the available implementations agree in this case: - * this call should never block, independent of the - * blocking state of the socket. - * Mike - */ - return -EAGAIN; -} - -static int tcp_peek_sndq(struct sock *sk, struct msghdr *msg, int len) -{ - struct sk_buff *skb; - int copied = 0, err = 0; - - /* XXX -- need to support SO_PEEK_OFF */ - - skb_queue_walk(&sk->sk_write_queue, skb) { - err = skb_copy_datagram_msg(skb, 0, msg, skb->len); - if (err) - break; - - copied += skb->len; - } - - return err ?: copied; -} - -/* Clean up the receive buffer for full frames taken by the user, - * then send an ACK if necessary. COPIED is the number of bytes - * tcp_recvmsg has given to the user so far, it speeds up the - * calculation of whether or not we must ACK for the sake of - * a window update. - */ -static void tcp_cleanup_rbuf(struct sock *sk, int copied) -{ - struct tcp_sock *tp = tcp_sk(sk); - bool time_to_ack = false; - - struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); - - WARN(skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq), - "cleanup rbuf bug: copied %X seq %X rcvnxt %X\n", - tp->copied_seq, TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt); - - if (inet_csk_ack_scheduled(sk)) { - const struct inet_connection_sock *icsk = inet_csk(sk); - /* Delayed ACKs frequently hit locked sockets during bulk - * receive. */ - if (icsk->icsk_ack.blocked || - /* Once-per-two-segments ACK was not sent by tcp_input.c */ - tp->rcv_nxt - tp->rcv_wup > icsk->icsk_ack.rcv_mss || - /* - * If this read emptied read buffer, we send ACK, if - * connection is not bidirectional, user drained - * receive buffer and there was a small segment - * in queue. - */ - (copied > 0 && - ((icsk->icsk_ack.pending & ICSK_ACK_PUSHED2) || - ((icsk->icsk_ack.pending & ICSK_ACK_PUSHED) && - !icsk->icsk_ack.pingpong)) && - !atomic_read(&sk->sk_rmem_alloc))) - time_to_ack = true; - } - - /* We send an ACK if we can now advertise a non-zero window - * which has been raised "significantly". - * - * Even if window raised up to infinity, do not send window open ACK - * in states, where we will not receive more. It is useless. - */ - if (copied > 0 && !time_to_ack && !(sk->sk_shutdown & RCV_SHUTDOWN)) { - __u32 rcv_window_now = tcp_receive_window(tp); - - /* Optimize, __tcp_select_window() is not cheap. */ - if (2*rcv_window_now <= tp->window_clamp) { - __u32 new_window = __tcp_select_window(sk); - - /* Send ACK now, if this read freed lots of space - * in our buffer. Certainly, new_window is new window. - * We can advertise it now, if it is not less than current one. - * "Lots" means "at least twice" here. - */ - if (new_window && new_window >= 2 * rcv_window_now) - time_to_ack = true; - } - } - if (time_to_ack) - tcp_send_ack(sk); -} - -static void tcp_prequeue_process(struct sock *sk) -{ - struct sk_buff *skb; - struct tcp_sock *tp = tcp_sk(sk); - - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPPREQUEUED); - - while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) - sk_backlog_rcv(sk, skb); - - /* Clear memory counter. */ - tp->ucopy.memory = 0; -} - -static struct sk_buff *tcp_recv_skb(struct sock *sk, u32 seq, u32 *off) -{ - struct sk_buff *skb; - u32 offset; - - while ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) { - offset = seq - TCP_SKB_CB(skb)->seq; - if (unlikely(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)) { - pr_err_once("%s: found a SYN, please report !\n", __func__); - offset--; - } - if (offset < skb->len || (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)) { - *off = offset; - return skb; - } - /* This looks weird, but this can happen if TCP collapsing - * splitted a fat GRO packet, while we released socket lock - * in skb_splice_bits() - */ - sk_eat_skb(sk, skb); - } - return NULL; -} - -/* - * This routine provides an alternative to tcp_recvmsg() for routines - * that would like to handle copying from skbuffs directly in 'sendfile' - * fashion. - * Note: - * - It is assumed that the socket was locked by the caller. - * - The routine does not block. - * - At present, there is no support for reading OOB data - * or for 'peeking' the socket using this routine - * (although both would be easy to implement). - */ -int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, - sk_read_actor_t recv_actor) -{ - struct sk_buff *skb; - struct tcp_sock *tp = tcp_sk(sk); - u32 seq = tp->copied_seq; - u32 offset; - int copied = 0; - - if (sk->sk_state == TCP_LISTEN) - return -ENOTCONN; - while ((skb = tcp_recv_skb(sk, seq, &offset)) != NULL) { - if (offset < skb->len) { - int used; - size_t len; - - len = skb->len - offset; - /* Stop reading if we hit a patch of urgent data */ - if (tp->urg_data) { - u32 urg_offset = tp->urg_seq - seq; - if (urg_offset < len) - len = urg_offset; - if (!len) - break; - } - used = recv_actor(desc, skb, offset, len); - if (used <= 0) { - if (!copied) - copied = used; - break; - } else if (used <= len) { - seq += used; - copied += used; - offset += used; - } - /* If recv_actor drops the lock (e.g. TCP splice - * receive) the skb pointer might be invalid when - * getting here: tcp_collapse might have deleted it - * while aggregating skbs from the socket queue. - */ - skb = tcp_recv_skb(sk, seq - 1, &offset); - if (!skb) - break; - /* TCP coalescing might have appended data to the skb. - * Try to splice more frags - */ - if (offset + 1 != skb->len) - continue; - } - if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) { - sk_eat_skb(sk, skb); - ++seq; - break; - } - sk_eat_skb(sk, skb); - if (!desc->count) - break; - tp->copied_seq = seq; - } - tp->copied_seq = seq; - - tcp_rcv_space_adjust(sk); - - /* Clean up data we have read: This will do ACK frames. */ - if (copied > 0) { - tcp_recv_skb(sk, seq, &offset); - tcp_cleanup_rbuf(sk, copied); - } - return copied; -} -EXPORT_SYMBOL(tcp_read_sock); - -int tcp_peek_len(struct socket *sock) -{ - return tcp_inq(sock->sk); -} -EXPORT_SYMBOL(tcp_peek_len); - -/* - * This routine copies from a sock struct into the user buffer. - * - * Technical note: in 2.3 we work on _locked_ socket, so that - * tricks with *seq access order and skb->users are not required. - * Probably, code can be easily improved even more. - */ - -int tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int nonblock, - int flags, int *addr_len) -{ - struct tcp_sock *tp = tcp_sk(sk); - int copied = 0; - u32 peek_seq; - u32 *seq; - unsigned long used; - int err; - int target; /* Read at least this many bytes */ - long timeo; - struct task_struct *user_recv = NULL; - struct sk_buff *skb, *last; - u32 urg_hole = 0; - - if (unlikely(flags & MSG_ERRQUEUE)) - return inet_recv_error(sk, msg, len, addr_len); - - if (sk_can_busy_loop(sk) && skb_queue_empty(&sk->sk_receive_queue) && - (sk->sk_state == TCP_ESTABLISHED)) - sk_busy_loop(sk, nonblock); - - lock_sock(sk); - - err = -ENOTCONN; - if (sk->sk_state == TCP_LISTEN) - goto out; - - timeo = sock_rcvtimeo(sk, nonblock); - - /* Urgent data needs to be handled specially. */ - if (flags & MSG_OOB) - goto recv_urg; - - if (unlikely(tp->repair)) { - err = -EPERM; - if (!(flags & MSG_PEEK)) - goto out; - - if (tp->repair_queue == TCP_SEND_QUEUE) - goto recv_sndq; - - err = -EINVAL; - if (tp->repair_queue == TCP_NO_QUEUE) - goto out; - - /* 'common' recv queue MSG_PEEK-ing */ - } - - seq = &tp->copied_seq; - if (flags & MSG_PEEK) { - peek_seq = tp->copied_seq; - seq = &peek_seq; - } - - target = sock_rcvlowat(sk, flags & MSG_WAITALL, len); - - do { - u32 offset; - - /* Are we at urgent data? Stop if we have read anything or have SIGURG pending. */ - if (tp->urg_data && tp->urg_seq == *seq) { - if (copied) - break; - if (signal_pending(current)) { - copied = timeo ? sock_intr_errno(timeo) : -EAGAIN; - break; - } - } - - /* Next get a buffer. */ - - last = skb_peek_tail(&sk->sk_receive_queue); - skb_queue_walk(&sk->sk_receive_queue, skb) { - last = skb; - /* Now that we have two receive queues this - * shouldn't happen. - */ - if (WARN(before(*seq, TCP_SKB_CB(skb)->seq), - "recvmsg bug: copied %X seq %X rcvnxt %X fl %X\n", - *seq, TCP_SKB_CB(skb)->seq, tp->rcv_nxt, - flags)) - break; - - offset = *seq - TCP_SKB_CB(skb)->seq; - if (unlikely(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)) { - pr_err_once("%s: found a SYN, please report !\n", __func__); - offset--; - } - if (offset < skb->len) - goto found_ok_skb; - if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) - goto found_fin_ok; - WARN(!(flags & MSG_PEEK), - "recvmsg bug 2: copied %X seq %X rcvnxt %X fl %X\n", - *seq, TCP_SKB_CB(skb)->seq, tp->rcv_nxt, flags); - } - - /* Well, if we have backlog, try to process it now yet. */ - - if (copied >= target && !sk->sk_backlog.tail) - break; - - if (copied) { - if (sk->sk_err || - sk->sk_state == TCP_CLOSE || - (sk->sk_shutdown & RCV_SHUTDOWN) || - !timeo || - signal_pending(current)) - break; - } else { - if (sock_flag(sk, SOCK_DONE)) - break; - - if (sk->sk_err) { - copied = sock_error(sk); - break; - } - - if (sk->sk_shutdown & RCV_SHUTDOWN) - break; - - if (sk->sk_state == TCP_CLOSE) { - if (!sock_flag(sk, SOCK_DONE)) { - /* This occurs when user tries to read - * from never connected socket. - */ - copied = -ENOTCONN; - break; - } - break; - } - - if (!timeo) { - copied = -EAGAIN; - break; - } - - if (signal_pending(current)) { - copied = sock_intr_errno(timeo); - break; - } - } - - tcp_cleanup_rbuf(sk, copied); - - if (!sysctl_tcp_low_latency && tp->ucopy.task == user_recv) { - /* Install new reader */ - if (!user_recv && !(flags & (MSG_TRUNC | MSG_PEEK))) { - user_recv = current; - tp->ucopy.task = user_recv; - tp->ucopy.msg = msg; - } - - tp->ucopy.len = len; - - WARN_ON(tp->copied_seq != tp->rcv_nxt && - !(flags & (MSG_PEEK | MSG_TRUNC))); - - /* Ugly... If prequeue is not empty, we have to - * process it before releasing socket, otherwise - * order will be broken at second iteration. - * More elegant solution is required!!! - * - * Look: we have the following (pseudo)queues: - * - * 1. packets in flight - * 2. backlog - * 3. prequeue - * 4. receive_queue - * - * Each queue can be processed only if the next ones - * are empty. At this point we have empty receive_queue. - * But prequeue _can_ be not empty after 2nd iteration, - * when we jumped to start of loop because backlog - * processing added something to receive_queue. - * We cannot release_sock(), because backlog contains - * packets arrived _after_ prequeued ones. - * - * Shortly, algorithm is clear --- to process all - * the queues in order. We could make it more directly, - * requeueing packets from backlog to prequeue, if - * is not empty. It is more elegant, but eats cycles, - * unfortunately. - */ - if (!skb_queue_empty(&tp->ucopy.prequeue)) - goto do_prequeue; - - /* __ Set realtime policy in scheduler __ */ - } - - if (copied >= target) { - /* Do not sleep, just process backlog. */ - release_sock(sk); - lock_sock(sk); - } else { - sk_wait_data(sk, &timeo, last); - } - - if (user_recv) { - int chunk; - - /* __ Restore normal policy in scheduler __ */ - - chunk = len - tp->ucopy.len; - if (chunk != 0) { - NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPDIRECTCOPYFROMBACKLOG, chunk); - len -= chunk; - copied += chunk; - } - - if (tp->rcv_nxt == tp->copied_seq && - !skb_queue_empty(&tp->ucopy.prequeue)) { -do_prequeue: - tcp_prequeue_process(sk); - - chunk = len - tp->ucopy.len; - if (chunk != 0) { - NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE, chunk); - len -= chunk; - copied += chunk; - } - } - } - if ((flags & MSG_PEEK) && - (peek_seq - copied - urg_hole != tp->copied_seq)) { - net_dbg_ratelimited("TCP(%s:%d): Application bug, race in MSG_PEEK\n", - current->comm, - task_pid_nr(current)); - peek_seq = tp->copied_seq; - } - continue; - - found_ok_skb: - /* Ok so how much can we use? */ - used = skb->len - offset; - if (len < used) - used = len; - - /* Do we have urgent data here? */ - if (tp->urg_data) { - u32 urg_offset = tp->urg_seq - *seq; - if (urg_offset < used) { - if (!urg_offset) { - if (!sock_flag(sk, SOCK_URGINLINE)) { - ++*seq; - urg_hole++; - offset++; - used--; - if (!used) - goto skip_copy; - } - } else - used = urg_offset; - } - } - - if (!(flags & MSG_TRUNC)) { - err = skb_copy_datagram_msg(skb, offset, msg, used); - if (err) { - /* Exception. Bailout! */ - if (!copied) - copied = -EFAULT; - break; - } - } - - *seq += used; - copied += used; - len -= used; - - tcp_rcv_space_adjust(sk); - -skip_copy: - if (tp->urg_data && after(tp->copied_seq, tp->urg_seq)) { - tp->urg_data = 0; - tcp_fast_path_check(sk); - } - if (used + offset < skb->len) - continue; - - if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) - goto found_fin_ok; - if (!(flags & MSG_PEEK)) - sk_eat_skb(sk, skb); - continue; - - found_fin_ok: - /* Process the FIN. */ - ++*seq; - if (!(flags & MSG_PEEK)) - sk_eat_skb(sk, skb); - break; - } while (len > 0); - - if (user_recv) { - if (!skb_queue_empty(&tp->ucopy.prequeue)) { - int chunk; - - tp->ucopy.len = copied > 0 ? len : 0; - - tcp_prequeue_process(sk); - - if (copied > 0 && (chunk = len - tp->ucopy.len) != 0) { - NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPDIRECTCOPYFROMPREQUEUE, chunk); - len -= chunk; - copied += chunk; - } - } - - tp->ucopy.task = NULL; - tp->ucopy.len = 0; - } - - /* According to UNIX98, msg_name/msg_namelen are ignored - * on connected socket. I was just happy when found this 8) --ANK - */ - - /* Clean up data we have read: This will do ACK frames. */ - tcp_cleanup_rbuf(sk, copied); - - release_sock(sk); - return copied; - -out: - release_sock(sk); - return err; - -recv_urg: - err = tcp_recv_urg(sk, msg, len, flags); - goto out; - -recv_sndq: - err = tcp_peek_sndq(sk, msg, len); - goto out; -} -EXPORT_SYMBOL(tcp_recvmsg); - -void tcp_set_state(struct sock *sk, int state) -{ - int oldstate = sk->sk_state; - - switch (state) { - case TCP_ESTABLISHED: - if (oldstate != TCP_ESTABLISHED) - TCP_INC_STATS(sock_net(sk), TCP_MIB_CURRESTAB); - break; - - case TCP_CLOSE: - if (oldstate == TCP_CLOSE_WAIT || oldstate == TCP_ESTABLISHED) - TCP_INC_STATS(sock_net(sk), TCP_MIB_ESTABRESETS); - - sk->sk_prot->unhash(sk); - if (inet_csk(sk)->icsk_bind_hash && - !(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) - inet_put_port(sk); - /* fall through */ - default: - if (oldstate == TCP_ESTABLISHED) - TCP_DEC_STATS(sock_net(sk), TCP_MIB_CURRESTAB); - } - - /* Change state AFTER socket is unhashed to avoid closed - * socket sitting in hash tables. - */ - sk_state_store(sk, state); - -#ifdef STATE_TRACE - SOCK_DEBUG(sk, "TCP sk=%p, State %s -> %s\n", sk, statename[oldstate], statename[state]); -#endif -} -EXPORT_SYMBOL_GPL(tcp_set_state); - -/* - * State processing on a close. This implements the state shift for - * sending our FIN frame. Note that we only send a FIN for some - * states. A shutdown() may have already sent the FIN, or we may be - * closed. - */ - -static const unsigned char new_state[16] = { - /* current state: new state: action: */ - [0 /* (Invalid) */] = TCP_CLOSE, - [TCP_ESTABLISHED] = TCP_FIN_WAIT1 | TCP_ACTION_FIN, - [TCP_SYN_SENT] = TCP_CLOSE, - [TCP_SYN_RECV] = TCP_FIN_WAIT1 | TCP_ACTION_FIN, - [TCP_FIN_WAIT1] = TCP_FIN_WAIT1, - [TCP_FIN_WAIT2] = TCP_FIN_WAIT2, - [TCP_TIME_WAIT] = TCP_CLOSE, - [TCP_CLOSE] = TCP_CLOSE, - [TCP_CLOSE_WAIT] = TCP_LAST_ACK | TCP_ACTION_FIN, - [TCP_LAST_ACK] = TCP_LAST_ACK, - [TCP_LISTEN] = TCP_CLOSE, - [TCP_CLOSING] = TCP_CLOSING, - [TCP_NEW_SYN_RECV] = TCP_CLOSE, /* should not happen ! */ -}; - -static int tcp_close_state(struct sock *sk) -{ - int next = (int)new_state[sk->sk_state]; - int ns = next & TCP_STATE_MASK; - - tcp_set_state(sk, ns); - - return next & TCP_ACTION_FIN; -} - -/* - * Shutdown the sending side of a connection. Much like close except - * that we don't receive shut down or sock_set_flag(sk, SOCK_DEAD). - */ - -void tcp_shutdown(struct sock *sk, int how) -{ - /* We need to grab some memory, and put together a FIN, - * and then put it into the queue to be sent. - * Tim MacKenzie(tym@dibbler.cs.monash.edu.au) 4 Dec '92. - */ - if (!(how & SEND_SHUTDOWN)) - return; - - /* If we've already sent a FIN, or it's a closed state, skip this. */ - if ((1 << sk->sk_state) & - (TCPF_ESTABLISHED | TCPF_SYN_SENT | - TCPF_SYN_RECV | TCPF_CLOSE_WAIT)) { - /* Clear out any half completed packets. FIN if needed. */ - if (tcp_close_state(sk)) - tcp_send_fin(sk); - } -} -EXPORT_SYMBOL(tcp_shutdown); - -bool tcp_check_oom(struct sock *sk, int shift) -{ - bool too_many_orphans, out_of_socket_memory; - - too_many_orphans = tcp_too_many_orphans(sk, shift); - out_of_socket_memory = tcp_out_of_memory(sk); - - if (too_many_orphans) - net_info_ratelimited("too many orphaned sockets\n"); - if (out_of_socket_memory) - net_info_ratelimited("out of memory -- consider tuning tcp_mem\n"); - return too_many_orphans || out_of_socket_memory; -} - -void tcp_close(struct sock *sk, long timeout) -{ - struct sk_buff *skb; - int data_was_unread = 0; - int state; - - lock_sock(sk); - sk->sk_shutdown = SHUTDOWN_MASK; - - if (sk->sk_state == TCP_LISTEN) { - tcp_set_state(sk, TCP_CLOSE); - - /* Special case. */ - inet_csk_listen_stop(sk); - - goto adjudge_to_death; - } - - /* We need to flush the recv. buffs. We do this only on the - * descriptor close, not protocol-sourced closes, because the - * reader process may not have drained the data yet! - */ - while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) { - u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq; - - if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) - len--; - data_was_unread += len; - __kfree_skb(skb); - } - - sk_mem_reclaim(sk); - - /* If socket has been already reset (e.g. in tcp_reset()) - kill it. */ - if (sk->sk_state == TCP_CLOSE) - goto adjudge_to_death; - - /* As outlined in RFC 2525, section 2.17, we send a RST here because - * data was lost. To witness the awful effects of the old behavior of - * always doing a FIN, run an older 2.1.x kernel or 2.0.x, start a bulk - * GET in an FTP client, suspend the process, wait for the client to - * advertise a zero window, then kill -9 the FTP client, wheee... - * Note: timeout is always zero in such a case. - */ - if (unlikely(tcp_sk(sk)->repair)) { - sk->sk_prot->disconnect(sk, 0); - } else if (data_was_unread) { - /* Unread data was tossed, zap the connection. */ - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONCLOSE); - tcp_set_state(sk, TCP_CLOSE); - tcp_send_active_reset(sk, sk->sk_allocation); - } else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) { - /* Check zero linger _after_ checking for unread data. */ - sk->sk_prot->disconnect(sk, 0); - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONDATA); - } else if (tcp_close_state(sk)) { - /* We FIN if the application ate all the data before - * zapping the connection. - */ - - /* RED-PEN. Formally speaking, we have broken TCP state - * machine. State transitions: - * - * TCP_ESTABLISHED -> TCP_FIN_WAIT1 - * TCP_SYN_RECV -> TCP_FIN_WAIT1 (forget it, it's impossible) - * TCP_CLOSE_WAIT -> TCP_LAST_ACK - * - * are legal only when FIN has been sent (i.e. in window), - * rather than queued out of window. Purists blame. - * - * F.e. "RFC state" is ESTABLISHED, - * if Linux state is FIN-WAIT-1, but FIN is still not sent. - * - * The visible declinations are that sometimes - * we enter time-wait state, when it is not required really - * (harmless), do not send active resets, when they are - * required by specs (TCP_ESTABLISHED, TCP_CLOSE_WAIT, when - * they look as CLOSING or LAST_ACK for Linux) - * Probably, I missed some more holelets. - * --ANK - * XXX (TFO) - To start off we don't support SYN+ACK+FIN - * in a single packet! (May consider it later but will - * probably need API support or TCP_CORK SYN-ACK until - * data is written and socket is closed.) - */ - tcp_send_fin(sk); - } - - sk_stream_wait_close(sk, timeout); - -adjudge_to_death: - state = sk->sk_state; - sock_hold(sk); - sock_orphan(sk); - - /* It is the last release_sock in its life. It will remove backlog. */ - release_sock(sk); - - - /* Now socket is owned by kernel and we acquire BH lock - to finish close. No need to check for user refs. - */ - local_bh_disable(); - bh_lock_sock(sk); - WARN_ON(sock_owned_by_user(sk)); - - percpu_counter_inc(sk->sk_prot->orphan_count); - - /* Have we already been destroyed by a softirq or backlog? */ - if (state != TCP_CLOSE && sk->sk_state == TCP_CLOSE) - goto out; - - /* This is a (useful) BSD violating of the RFC. There is a - * problem with TCP as specified in that the other end could - * keep a socket open forever with no application left this end. - * We use a 1 minute timeout (about the same as BSD) then kill - * our end. If they send after that then tough - BUT: long enough - * that we won't make the old 4*rto = almost no time - whoops - * reset mistake. - * - * Nope, it was not mistake. It is really desired behaviour - * f.e. on http servers, when such sockets are useless, but - * consume significant resources. Let's do it with special - * linger2 option. --ANK - */ - - if (sk->sk_state == TCP_FIN_WAIT2) { - struct tcp_sock *tp = tcp_sk(sk); - if (tp->linger2 < 0) { - tcp_set_state(sk, TCP_CLOSE); - tcp_send_active_reset(sk, GFP_ATOMIC); - __NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPABORTONLINGER); - } else { - const int tmo = tcp_fin_time(sk); - - if (tmo > TCP_TIMEWAIT_LEN) { - inet_csk_reset_keepalive_timer(sk, - tmo - TCP_TIMEWAIT_LEN); - } else { - tcp_time_wait(sk, TCP_FIN_WAIT2, tmo); - goto out; - } - } - } - if (sk->sk_state != TCP_CLOSE) { - sk_mem_reclaim(sk); - if (tcp_check_oom(sk, 0)) { - tcp_set_state(sk, TCP_CLOSE); - tcp_send_active_reset(sk, GFP_ATOMIC); - __NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPABORTONMEMORY); - } - } - - if (sk->sk_state == TCP_CLOSE) { - struct request_sock *req = tcp_sk(sk)->fastopen_rsk; - /* We could get here with a non-NULL req if the socket is - * aborted (e.g., closed with unread data) before 3WHS - * finishes. - */ - if (req) - reqsk_fastopen_remove(sk, req, false); - inet_csk_destroy_sock(sk); - } - /* Otherwise, socket is reprieved until protocol close. */ - -out: - bh_unlock_sock(sk); - local_bh_enable(); - sock_put(sk); -} -EXPORT_SYMBOL(tcp_close); - -/* These states need RST on ABORT according to RFC793 */ - -static inline bool tcp_need_reset(int state) -{ - return (1 << state) & - (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_FIN_WAIT1 | - TCPF_FIN_WAIT2 | TCPF_SYN_RECV); -} - -int tcp_disconnect(struct sock *sk, int flags) -{ - struct inet_sock *inet = inet_sk(sk); - struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - int err = 0; - int old_state = sk->sk_state; - - if (old_state != TCP_CLOSE) - tcp_set_state(sk, TCP_CLOSE); - - /* ABORT function of RFC793 */ - if (old_state == TCP_LISTEN) { - inet_csk_listen_stop(sk); - } else if (unlikely(tp->repair)) { - sk->sk_err = ECONNABORTED; - } else if (tcp_need_reset(old_state) || - (tp->snd_nxt != tp->write_seq && - (1 << old_state) & (TCPF_CLOSING | TCPF_LAST_ACK))) { - /* The last check adjusts for discrepancy of Linux wrt. RFC - * states - */ - tcp_send_active_reset(sk, gfp_any()); - sk->sk_err = ECONNRESET; - } else if (old_state == TCP_SYN_SENT) - sk->sk_err = ECONNRESET; - - tcp_clear_xmit_timers(sk); - __skb_queue_purge(&sk->sk_receive_queue); - tcp_write_queue_purge(sk); - skb_rbtree_purge(&tp->out_of_order_queue); - - inet->inet_dport = 0; - - if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) - inet_reset_saddr(sk); - - sk->sk_shutdown = 0; - sock_reset_flag(sk, SOCK_DONE); - tp->srtt_us = 0; - tp->write_seq += tp->max_window + 2; - if (tp->write_seq == 0) - tp->write_seq = 1; - icsk->icsk_backoff = 0; - tp->snd_cwnd = 2; - icsk->icsk_probes_out = 0; - tp->packets_out = 0; - tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; - tp->snd_cwnd_cnt = 0; - tp->window_clamp = 0; - tcp_set_ca_state(sk, TCP_CA_Open); - tcp_clear_retrans(tp); - inet_csk_delack_init(sk); - tcp_init_send_head(sk); - memset(&tp->rx_opt, 0, sizeof(tp->rx_opt)); - __sk_dst_reset(sk); - - WARN_ON(inet->inet_num && !icsk->icsk_bind_hash); - - sk->sk_error_report(sk); - return err; -} -EXPORT_SYMBOL(tcp_disconnect); - -static inline bool tcp_can_repair_sock(const struct sock *sk) -{ - return ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN) && - ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_ESTABLISHED)); -} - -static int tcp_repair_set_window(struct tcp_sock *tp, char __user *optbuf, int len) -{ - struct tcp_repair_window opt; - - if (!tp->repair) - return -EPERM; - - if (len != sizeof(opt)) - return -EINVAL; - - if (copy_from_user(&opt, optbuf, sizeof(opt))) - return -EFAULT; - - if (opt.max_window < opt.snd_wnd) - return -EINVAL; - - if (after(opt.snd_wl1, tp->rcv_nxt + opt.rcv_wnd)) - return -EINVAL; - - if (after(opt.rcv_wup, tp->rcv_nxt)) - return -EINVAL; - - tp->snd_wl1 = opt.snd_wl1; - tp->snd_wnd = opt.snd_wnd; - tp->max_window = opt.max_window; - - tp->rcv_wnd = opt.rcv_wnd; - tp->rcv_wup = opt.rcv_wup; - - return 0; -} - -static int tcp_repair_options_est(struct tcp_sock *tp, - struct tcp_repair_opt __user *optbuf, unsigned int len) -{ - struct tcp_repair_opt opt; - - while (len >= sizeof(opt)) { - if (copy_from_user(&opt, optbuf, sizeof(opt))) - return -EFAULT; - - optbuf++; - len -= sizeof(opt); - - switch (opt.opt_code) { - case TCPOPT_MSS: - tp->rx_opt.mss_clamp = opt.opt_val; - break; - case TCPOPT_WINDOW: - { - u16 snd_wscale = opt.opt_val & 0xFFFF; - u16 rcv_wscale = opt.opt_val >> 16; - - if (snd_wscale > 14 || rcv_wscale > 14) - return -EFBIG; - - tp->rx_opt.snd_wscale = snd_wscale; - tp->rx_opt.rcv_wscale = rcv_wscale; - tp->rx_opt.wscale_ok = 1; - } - break; - case TCPOPT_SACK_PERM: - if (opt.opt_val != 0) - return -EINVAL; - - tp->rx_opt.sack_ok |= TCP_SACK_SEEN; - if (sysctl_tcp_fack) - tcp_enable_fack(tp); - break; - case TCPOPT_TIMESTAMP: - if (opt.opt_val != 0) - return -EINVAL; - - tp->rx_opt.tstamp_ok = 1; - break; - } - } - - return 0; -} - -/* - * Socket option code for TCP. - */ -static int do_tcp_setsockopt(struct sock *sk, int level, - int optname, char __user *optval, unsigned int optlen) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct inet_connection_sock *icsk = inet_csk(sk); - struct net *net = sock_net(sk); - int val; - int err = 0; - - /* These are data/string values, all the others are ints */ - switch (optname) { - case TCP_CONGESTION: { - char name[TCP_CA_NAME_MAX]; - - if (optlen < 1) - return -EINVAL; - - val = strncpy_from_user(name, optval, - min_t(long, TCP_CA_NAME_MAX-1, optlen)); - if (val < 0) - return -EFAULT; - name[val] = 0; - - lock_sock(sk); - err = tcp_set_congestion_control(sk, name); - release_sock(sk); - return err; - } - default: - /* fallthru */ - break; - } - - if (optlen < sizeof(int)) - return -EINVAL; - - if (get_user(val, (int __user *)optval)) - return -EFAULT; - - lock_sock(sk); - - switch (optname) { - case TCP_MAXSEG: - /* Values greater than interface MTU won't take effect. However - * at the point when this call is done we typically don't yet - * know which interface is going to be used */ - if (val < TCP_MIN_MSS || val > MAX_TCP_WINDOW) { - err = -EINVAL; - break; - } - tp->rx_opt.user_mss = val; - break; - - case TCP_NODELAY: - if (val) { - /* TCP_NODELAY is weaker than TCP_CORK, so that - * this option on corked socket is remembered, but - * it is not activated until cork is cleared. - * - * However, when TCP_NODELAY is set we make - * an explicit push, which overrides even TCP_CORK - * for currently queued segments. - */ - tp->nonagle |= TCP_NAGLE_OFF|TCP_NAGLE_PUSH; - tcp_push_pending_frames(sk); - } else { - tp->nonagle &= ~TCP_NAGLE_OFF; - } - break; - - case TCP_THIN_LINEAR_TIMEOUTS: - if (val < 0 || val > 1) - err = -EINVAL; - else - tp->thin_lto = val; - break; - - case TCP_THIN_DUPACK: - if (val < 0 || val > 1) - err = -EINVAL; - else { - tp->thin_dupack = val; - if (tp->thin_dupack) - tcp_disable_early_retrans(tp); - } - break; - - case TCP_REPAIR: - if (!tcp_can_repair_sock(sk)) - err = -EPERM; - else if (val == 1) { - tp->repair = 1; - sk->sk_reuse = SK_FORCE_REUSE; - tp->repair_queue = TCP_NO_QUEUE; - } else if (val == 0) { - tp->repair = 0; - sk->sk_reuse = SK_NO_REUSE; - tcp_send_window_probe(sk); - } else - err = -EINVAL; - - break; - - case TCP_REPAIR_QUEUE: - if (!tp->repair) - err = -EPERM; - else if (val < TCP_QUEUES_NR) - tp->repair_queue = val; - else - err = -EINVAL; - break; - - case TCP_QUEUE_SEQ: - if (sk->sk_state != TCP_CLOSE) - err = -EPERM; - else if (tp->repair_queue == TCP_SEND_QUEUE) - tp->write_seq = val; - else if (tp->repair_queue == TCP_RECV_QUEUE) - tp->rcv_nxt = val; - else - err = -EINVAL; - break; - - case TCP_REPAIR_OPTIONS: - if (!tp->repair) - err = -EINVAL; - else if (sk->sk_state == TCP_ESTABLISHED) - err = tcp_repair_options_est(tp, - (struct tcp_repair_opt __user *)optval, - optlen); - else - err = -EPERM; - break; - - case TCP_CORK: - /* When set indicates to always queue non-full frames. - * Later the user clears this option and we transmit - * any pending partial frames in the queue. This is - * meant to be used alongside sendfile() to get properly - * filled frames when the user (for example) must write - * out headers with a write() call first and then use - * sendfile to send out the data parts. - * - * TCP_CORK can be set together with TCP_NODELAY and it is - * stronger than TCP_NODELAY. - */ - if (val) { - tp->nonagle |= TCP_NAGLE_CORK; - } else { - tp->nonagle &= ~TCP_NAGLE_CORK; - if (tp->nonagle&TCP_NAGLE_OFF) - tp->nonagle |= TCP_NAGLE_PUSH; - tcp_push_pending_frames(sk); - } - break; - - case TCP_KEEPIDLE: - if (val < 1 || val > MAX_TCP_KEEPIDLE) - err = -EINVAL; - else { - tp->keepalive_time = val * HZ; - if (sock_flag(sk, SOCK_KEEPOPEN) && - !((1 << sk->sk_state) & - (TCPF_CLOSE | TCPF_LISTEN))) { - u32 elapsed = keepalive_time_elapsed(tp); - if (tp->keepalive_time > elapsed) - elapsed = tp->keepalive_time - elapsed; - else - elapsed = 0; - inet_csk_reset_keepalive_timer(sk, elapsed); - } - } - break; - case TCP_KEEPINTVL: - if (val < 1 || val > MAX_TCP_KEEPINTVL) - err = -EINVAL; - else - tp->keepalive_intvl = val * HZ; - break; - case TCP_KEEPCNT: - if (val < 1 || val > MAX_TCP_KEEPCNT) - err = -EINVAL; - else - tp->keepalive_probes = val; - break; - case TCP_SYNCNT: - if (val < 1 || val > MAX_TCP_SYNCNT) - err = -EINVAL; - else - icsk->icsk_syn_retries = val; - break; - - case TCP_SAVE_SYN: - if (val < 0 || val > 1) - err = -EINVAL; - else - tp->save_syn = val; - break; - - case TCP_LINGER2: - if (val < 0) - tp->linger2 = -1; - else if (val > net->ipv4.sysctl_tcp_fin_timeout / HZ) - tp->linger2 = 0; - else - tp->linger2 = val * HZ; - break; - - case TCP_DEFER_ACCEPT: - /* Translate value in seconds to number of retransmits */ - icsk->icsk_accept_queue.rskq_defer_accept = - secs_to_retrans(val, TCP_TIMEOUT_INIT / HZ, - TCP_RTO_MAX / HZ); - break; - - case TCP_WINDOW_CLAMP: - if (!val) { - if (sk->sk_state != TCP_CLOSE) { - err = -EINVAL; - break; - } - tp->window_clamp = 0; - } else - tp->window_clamp = val < SOCK_MIN_RCVBUF / 2 ? - SOCK_MIN_RCVBUF / 2 : val; - break; - - case TCP_QUICKACK: - if (!val) { - icsk->icsk_ack.pingpong = 1; - } else { - icsk->icsk_ack.pingpong = 0; - if ((1 << sk->sk_state) & - (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT) && - inet_csk_ack_scheduled(sk)) { - icsk->icsk_ack.pending |= ICSK_ACK_PUSHED; - tcp_cleanup_rbuf(sk, 1); - if (!(val & 1)) - icsk->icsk_ack.pingpong = 1; - } - } - break; - -#ifdef CONFIG_TCP_MD5SIG - case TCP_MD5SIG: - /* Read the IP->Key mappings from userspace */ - err = tp->af_specific->md5_parse(sk, optval, optlen); - break; -#endif - case TCP_USER_TIMEOUT: - /* Cap the max time in ms TCP will retry or probe the window - * before giving up and aborting (ETIMEDOUT) a connection. - */ - if (val < 0) - err = -EINVAL; - else - icsk->icsk_user_timeout = msecs_to_jiffies(val); - break; - - case TCP_FASTOPEN: - if (val >= 0 && ((1 << sk->sk_state) & (TCPF_CLOSE | - TCPF_LISTEN))) { - tcp_fastopen_init_key_once(true); - - fastopen_queue_tune(sk, val); - } else { - err = -EINVAL; - } - break; - case TCP_TIMESTAMP: - if (!tp->repair) - err = -EPERM; - else - tp->tsoffset = val - tcp_time_stamp; - break; - case TCP_REPAIR_WINDOW: - err = tcp_repair_set_window(tp, optval, optlen); - break; - case TCP_NOTSENT_LOWAT: - tp->notsent_lowat = val; - sk->sk_write_space(sk); - break; - default: - err = -ENOPROTOOPT; - break; - } - - release_sock(sk); - return err; -} - -int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval, - unsigned int optlen) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - - if (level != SOL_TCP) - return icsk->icsk_af_ops->setsockopt(sk, level, optname, - optval, optlen); - return do_tcp_setsockopt(sk, level, optname, optval, optlen); -} -EXPORT_SYMBOL(tcp_setsockopt); - -#ifdef CONFIG_COMPAT -int compat_tcp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen) -{ - if (level != SOL_TCP) - return inet_csk_compat_setsockopt(sk, level, optname, - optval, optlen); - return do_tcp_setsockopt(sk, level, optname, optval, optlen); -} -EXPORT_SYMBOL(compat_tcp_setsockopt); -#endif - -/* Return information about state of tcp endpoint in API format. */ -void tcp_get_info(struct sock *sk, struct tcp_info *info) -{ - const struct tcp_sock *tp = tcp_sk(sk); /* iff sk_type == SOCK_STREAM */ - const struct inet_connection_sock *icsk = inet_csk(sk); - u32 now = tcp_time_stamp, intv; - unsigned int start; - int notsent_bytes; - u64 rate64; - u32 rate; - - memset(info, 0, sizeof(*info)); - if (sk->sk_type != SOCK_STREAM) - return; - - info->tcpi_state = sk_state_load(sk); - - info->tcpi_ca_state = icsk->icsk_ca_state; - info->tcpi_retransmits = icsk->icsk_retransmits; - info->tcpi_probes = icsk->icsk_probes_out; - info->tcpi_backoff = icsk->icsk_backoff; - - if (tp->rx_opt.tstamp_ok) - info->tcpi_options |= TCPI_OPT_TIMESTAMPS; - if (tcp_is_sack(tp)) - info->tcpi_options |= TCPI_OPT_SACK; - if (tp->rx_opt.wscale_ok) { - info->tcpi_options |= TCPI_OPT_WSCALE; - info->tcpi_snd_wscale = tp->rx_opt.snd_wscale; - info->tcpi_rcv_wscale = tp->rx_opt.rcv_wscale; - } - - if (tp->ecn_flags & TCP_ECN_OK) - info->tcpi_options |= TCPI_OPT_ECN; - if (tp->ecn_flags & TCP_ECN_SEEN) - info->tcpi_options |= TCPI_OPT_ECN_SEEN; - if (tp->syn_data_acked) - info->tcpi_options |= TCPI_OPT_SYN_DATA; - - info->tcpi_rto = jiffies_to_usecs(icsk->icsk_rto); - info->tcpi_ato = jiffies_to_usecs(icsk->icsk_ack.ato); - info->tcpi_snd_mss = tp->mss_cache; - info->tcpi_rcv_mss = icsk->icsk_ack.rcv_mss; - - if (info->tcpi_state == TCP_LISTEN) { - info->tcpi_unacked = sk->sk_ack_backlog; - info->tcpi_sacked = sk->sk_max_ack_backlog; - } else { - info->tcpi_unacked = tp->packets_out; - info->tcpi_sacked = tp->sacked_out; - } - info->tcpi_lost = tp->lost_out; - info->tcpi_retrans = tp->retrans_out; - info->tcpi_fackets = tp->fackets_out; - - info->tcpi_last_data_sent = jiffies_to_msecs(now - tp->lsndtime); - info->tcpi_last_data_recv = jiffies_to_msecs(now - icsk->icsk_ack.lrcvtime); - info->tcpi_last_ack_recv = jiffies_to_msecs(now - tp->rcv_tstamp); - - info->tcpi_pmtu = icsk->icsk_pmtu_cookie; - info->tcpi_rcv_ssthresh = tp->rcv_ssthresh; - info->tcpi_rtt = tp->srtt_us >> 3; - info->tcpi_rttvar = tp->mdev_us >> 2; - info->tcpi_snd_ssthresh = tp->snd_ssthresh; - info->tcpi_snd_cwnd = tp->snd_cwnd; - info->tcpi_advmss = tp->advmss; - info->tcpi_reordering = tp->reordering; - - info->tcpi_rcv_rtt = jiffies_to_usecs(tp->rcv_rtt_est.rtt)>>3; - info->tcpi_rcv_space = tp->rcvq_space.space; - - info->tcpi_total_retrans = tp->total_retrans; - - rate = READ_ONCE(sk->sk_pacing_rate); - rate64 = rate != ~0U ? rate : ~0ULL; - put_unaligned(rate64, &info->tcpi_pacing_rate); - - rate = READ_ONCE(sk->sk_max_pacing_rate); - rate64 = rate != ~0U ? rate : ~0ULL; - put_unaligned(rate64, &info->tcpi_max_pacing_rate); - - do { - start = u64_stats_fetch_begin_irq(&tp->syncp); - put_unaligned(tp->bytes_acked, &info->tcpi_bytes_acked); - put_unaligned(tp->bytes_received, &info->tcpi_bytes_received); - } while (u64_stats_fetch_retry_irq(&tp->syncp, start)); - info->tcpi_segs_out = tp->segs_out; - info->tcpi_segs_in = tp->segs_in; - - notsent_bytes = READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_nxt); - info->tcpi_notsent_bytes = max(0, notsent_bytes); - - info->tcpi_min_rtt = tcp_min_rtt(tp); - info->tcpi_data_segs_in = tp->data_segs_in; - info->tcpi_data_segs_out = tp->data_segs_out; - - info->tcpi_delivery_rate_app_limited = tp->rate_app_limited ? 1 : 0; - rate = READ_ONCE(tp->rate_delivered); - intv = READ_ONCE(tp->rate_interval_us); - if (rate && intv) { - rate64 = (u64)rate * tp->mss_cache * USEC_PER_SEC; - do_div(rate64, intv); - put_unaligned(rate64, &info->tcpi_delivery_rate); - } -} -EXPORT_SYMBOL_GPL(tcp_get_info); - -static int do_tcp_getsockopt(struct sock *sk, int level, - int optname, char __user *optval, int __user *optlen) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - struct net *net = sock_net(sk); - int val, len; - - if (get_user(len, optlen)) - return -EFAULT; - - len = min_t(unsigned int, len, sizeof(int)); - - if (len < 0) - return -EINVAL; - - switch (optname) { - case TCP_MAXSEG: - val = tp->mss_cache; - if (!val && ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) - val = tp->rx_opt.user_mss; - if (tp->repair) - val = tp->rx_opt.mss_clamp; - break; - case TCP_NODELAY: - val = !!(tp->nonagle&TCP_NAGLE_OFF); - break; - case TCP_CORK: - val = !!(tp->nonagle&TCP_NAGLE_CORK); - break; - case TCP_KEEPIDLE: - val = keepalive_time_when(tp) / HZ; - break; - case TCP_KEEPINTVL: - val = keepalive_intvl_when(tp) / HZ; - break; - case TCP_KEEPCNT: - val = keepalive_probes(tp); - break; - case TCP_SYNCNT: - val = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_syn_retries; - break; - case TCP_LINGER2: - val = tp->linger2; - if (val >= 0) - val = (val ? : net->ipv4.sysctl_tcp_fin_timeout) / HZ; - break; - case TCP_DEFER_ACCEPT: - val = retrans_to_secs(icsk->icsk_accept_queue.rskq_defer_accept, - TCP_TIMEOUT_INIT / HZ, TCP_RTO_MAX / HZ); - break; - case TCP_WINDOW_CLAMP: - val = tp->window_clamp; - break; - case TCP_INFO: { - struct tcp_info info; - - if (get_user(len, optlen)) - return -EFAULT; - - tcp_get_info(sk, &info); - - len = min_t(unsigned int, len, sizeof(info)); - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(optval, &info, len)) - return -EFAULT; - return 0; - } - case TCP_CC_INFO: { - const struct tcp_congestion_ops *ca_ops; - union tcp_cc_info info; - size_t sz = 0; - int attr; - - if (get_user(len, optlen)) - return -EFAULT; - - ca_ops = icsk->icsk_ca_ops; - if (ca_ops && ca_ops->get_info) - sz = ca_ops->get_info(sk, ~0U, &attr, &info); - - len = min_t(unsigned int, len, sz); - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(optval, &info, len)) - return -EFAULT; - return 0; - } - case TCP_QUICKACK: - val = !icsk->icsk_ack.pingpong; - break; - - case TCP_CONGESTION: - if (get_user(len, optlen)) - return -EFAULT; - len = min_t(unsigned int, len, TCP_CA_NAME_MAX); - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(optval, icsk->icsk_ca_ops->name, len)) - return -EFAULT; - return 0; - - case TCP_THIN_LINEAR_TIMEOUTS: - val = tp->thin_lto; - break; - case TCP_THIN_DUPACK: - val = tp->thin_dupack; - break; - - case TCP_REPAIR: - val = tp->repair; - break; - - case TCP_REPAIR_QUEUE: - if (tp->repair) - val = tp->repair_queue; - else - return -EINVAL; - break; - - case TCP_REPAIR_WINDOW: { - struct tcp_repair_window opt; - - if (get_user(len, optlen)) - return -EFAULT; - - if (len != sizeof(opt)) - return -EINVAL; - - if (!tp->repair) - return -EPERM; - - opt.snd_wl1 = tp->snd_wl1; - opt.snd_wnd = tp->snd_wnd; - opt.max_window = tp->max_window; - opt.rcv_wnd = tp->rcv_wnd; - opt.rcv_wup = tp->rcv_wup; - - if (copy_to_user(optval, &opt, len)) - return -EFAULT; - return 0; - } - case TCP_QUEUE_SEQ: - if (tp->repair_queue == TCP_SEND_QUEUE) - val = tp->write_seq; - else if (tp->repair_queue == TCP_RECV_QUEUE) - val = tp->rcv_nxt; - else - return -EINVAL; - break; - - case TCP_USER_TIMEOUT: - val = jiffies_to_msecs(icsk->icsk_user_timeout); - break; - - case TCP_FASTOPEN: - val = icsk->icsk_accept_queue.fastopenq.max_qlen; - break; - - case TCP_TIMESTAMP: - val = tcp_time_stamp + tp->tsoffset; - break; - case TCP_NOTSENT_LOWAT: - val = tp->notsent_lowat; - break; - case TCP_SAVE_SYN: - val = tp->save_syn; - break; - case TCP_SAVED_SYN: { - if (get_user(len, optlen)) - return -EFAULT; - - lock_sock(sk); - if (tp->saved_syn) { - if (len < tp->saved_syn[0]) { - if (put_user(tp->saved_syn[0], optlen)) { - release_sock(sk); - return -EFAULT; - } - release_sock(sk); - return -EINVAL; - } - len = tp->saved_syn[0]; - if (put_user(len, optlen)) { - release_sock(sk); - return -EFAULT; - } - if (copy_to_user(optval, tp->saved_syn + 1, len)) { - release_sock(sk); - return -EFAULT; - } - tcp_saved_syn_free(tp); - release_sock(sk); - } else { - release_sock(sk); - len = 0; - if (put_user(len, optlen)) - return -EFAULT; - } - return 0; - } - default: - return -ENOPROTOOPT; - } - - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(optval, &val, len)) - return -EFAULT; - return 0; -} - -int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, - int __user *optlen) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - - if (level != SOL_TCP) - return icsk->icsk_af_ops->getsockopt(sk, level, optname, - optval, optlen); - return do_tcp_getsockopt(sk, level, optname, optval, optlen); -} -EXPORT_SYMBOL(tcp_getsockopt); - -#ifdef CONFIG_COMPAT -int compat_tcp_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (level != SOL_TCP) - return inet_csk_compat_getsockopt(sk, level, optname, - optval, optlen); - return do_tcp_getsockopt(sk, level, optname, optval, optlen); -} -EXPORT_SYMBOL(compat_tcp_getsockopt); -#endif - -#ifdef CONFIG_TCP_MD5SIG -static DEFINE_PER_CPU(struct tcp_md5sig_pool, tcp_md5sig_pool); -static DEFINE_MUTEX(tcp_md5sig_mutex); -static bool tcp_md5sig_pool_populated = false; - -static void __tcp_alloc_md5sig_pool(void) -{ - struct crypto_ahash *hash; - int cpu; - - hash = crypto_alloc_ahash("md5", 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(hash)) - return; - - for_each_possible_cpu(cpu) { - void *scratch = per_cpu(tcp_md5sig_pool, cpu).scratch; - struct ahash_request *req; - - if (!scratch) { - scratch = kmalloc_node(sizeof(union tcp_md5sum_block) + - sizeof(struct tcphdr), - GFP_KERNEL, - cpu_to_node(cpu)); - if (!scratch) - return; - per_cpu(tcp_md5sig_pool, cpu).scratch = scratch; - } - if (per_cpu(tcp_md5sig_pool, cpu).md5_req) - continue; - - req = ahash_request_alloc(hash, GFP_KERNEL); - if (!req) - return; - - ahash_request_set_callback(req, 0, NULL, NULL); - - per_cpu(tcp_md5sig_pool, cpu).md5_req = req; - } - /* before setting tcp_md5sig_pool_populated, we must commit all writes - * to memory. See smp_rmb() in tcp_get_md5sig_pool() - */ - smp_wmb(); - tcp_md5sig_pool_populated = true; -} - -bool tcp_alloc_md5sig_pool(void) -{ - if (unlikely(!tcp_md5sig_pool_populated)) { - mutex_lock(&tcp_md5sig_mutex); - - if (!tcp_md5sig_pool_populated) - __tcp_alloc_md5sig_pool(); - - mutex_unlock(&tcp_md5sig_mutex); - } - return tcp_md5sig_pool_populated; -} -EXPORT_SYMBOL(tcp_alloc_md5sig_pool); - - -/** - * tcp_get_md5sig_pool - get md5sig_pool for this user - * - * We use percpu structure, so if we succeed, we exit with preemption - * and BH disabled, to make sure another thread or softirq handling - * wont try to get same context. - */ -struct tcp_md5sig_pool *tcp_get_md5sig_pool(void) -{ - local_bh_disable(); - - if (tcp_md5sig_pool_populated) { - /* coupled with smp_wmb() in __tcp_alloc_md5sig_pool() */ - smp_rmb(); - return this_cpu_ptr(&tcp_md5sig_pool); - } - local_bh_enable(); - return NULL; -} -EXPORT_SYMBOL(tcp_get_md5sig_pool); - -int tcp_md5_hash_skb_data(struct tcp_md5sig_pool *hp, - const struct sk_buff *skb, unsigned int header_len) -{ - struct scatterlist sg; - const struct tcphdr *tp = tcp_hdr(skb); - struct ahash_request *req = hp->md5_req; - unsigned int i; - const unsigned int head_data_len = skb_headlen(skb) > header_len ? - skb_headlen(skb) - header_len : 0; - const struct skb_shared_info *shi = skb_shinfo(skb); - struct sk_buff *frag_iter; - - sg_init_table(&sg, 1); - - sg_set_buf(&sg, ((u8 *) tp) + header_len, head_data_len); - ahash_request_set_crypt(req, &sg, NULL, head_data_len); - if (crypto_ahash_update(req)) - return 1; - - for (i = 0; i < shi->nr_frags; ++i) { - const struct skb_frag_struct *f = &shi->frags[i]; - unsigned int offset = f->page_offset; - struct page *page = skb_frag_page(f) + (offset >> PAGE_SHIFT); - - sg_set_page(&sg, page, skb_frag_size(f), - offset_in_page(offset)); - ahash_request_set_crypt(req, &sg, NULL, skb_frag_size(f)); - if (crypto_ahash_update(req)) - return 1; - } - - skb_walk_frags(skb, frag_iter) - if (tcp_md5_hash_skb_data(hp, frag_iter, 0)) - return 1; - - return 0; -} -EXPORT_SYMBOL(tcp_md5_hash_skb_data); - -int tcp_md5_hash_key(struct tcp_md5sig_pool *hp, const struct tcp_md5sig_key *key) -{ - struct scatterlist sg; - - sg_init_one(&sg, key->key, key->keylen); - ahash_request_set_crypt(hp->md5_req, &sg, NULL, key->keylen); - return crypto_ahash_update(hp->md5_req); -} -EXPORT_SYMBOL(tcp_md5_hash_key); - -#endif - -void tcp_done(struct sock *sk) -{ - struct request_sock *req = tcp_sk(sk)->fastopen_rsk; - - if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV) - TCP_INC_STATS(sock_net(sk), TCP_MIB_ATTEMPTFAILS); - - tcp_set_state(sk, TCP_CLOSE); - tcp_clear_xmit_timers(sk); - if (req) - reqsk_fastopen_remove(sk, req, false); - - sk->sk_shutdown = SHUTDOWN_MASK; - - if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_state_change(sk); - else - inet_csk_destroy_sock(sk); -} -EXPORT_SYMBOL_GPL(tcp_done); - -int tcp_abort(struct sock *sk, int err) -{ - if (!sk_fullsock(sk)) { - if (sk->sk_state == TCP_NEW_SYN_RECV) { - struct request_sock *req = inet_reqsk(sk); - - local_bh_disable(); - inet_csk_reqsk_queue_drop_and_put(req->rsk_listener, - req); - local_bh_enable(); - return 0; - } - return -EOPNOTSUPP; - } - - /* Don't race with userspace socket closes such as tcp_close. */ - lock_sock(sk); - - if (sk->sk_state == TCP_LISTEN) { - tcp_set_state(sk, TCP_CLOSE); - inet_csk_listen_stop(sk); - } - - /* Don't race with BH socket closes such as inet_csk_listen_stop. */ - local_bh_disable(); - bh_lock_sock(sk); - - if (!sock_flag(sk, SOCK_DEAD)) { - sk->sk_err = err; - /* This barrier is coupled with smp_rmb() in tcp_poll() */ - smp_wmb(); - sk->sk_error_report(sk); - if (tcp_need_reset(sk->sk_state)) - tcp_send_active_reset(sk, GFP_ATOMIC); - tcp_done(sk); - } - - bh_unlock_sock(sk); - local_bh_enable(); - release_sock(sk); - return 0; -} -EXPORT_SYMBOL_GPL(tcp_abort); - -extern struct tcp_congestion_ops tcp_reno; - -static __initdata unsigned long thash_entries; -static int __init set_thash_entries(char *str) -{ - ssize_t ret; - - if (!str) - return 0; - - ret = kstrtoul(str, 0, &thash_entries); - if (ret) - return 0; - - return 1; -} -__setup("thash_entries=", set_thash_entries); - -static void __init tcp_init_mem(void) -{ - unsigned long limit = nr_free_buffer_pages() / 16; - - limit = max(limit, 128UL); - sysctl_tcp_mem[0] = limit / 4 * 3; /* 4.68 % */ - sysctl_tcp_mem[1] = limit; /* 6.25 % */ - sysctl_tcp_mem[2] = sysctl_tcp_mem[0] * 2; /* 9.37 % */ -} - -void __init tcp_init(void) -{ - int max_rshare, max_wshare, cnt; - unsigned long limit; - unsigned int i; - - BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > - FIELD_SIZEOF(struct sk_buff, cb)); - - percpu_counter_init(&tcp_sockets_allocated, 0, GFP_KERNEL); - percpu_counter_init(&tcp_orphan_count, 0, GFP_KERNEL); - tcp_hashinfo.bind_bucket_cachep = - kmem_cache_create("tcp_bind_bucket", - sizeof(struct inet_bind_bucket), 0, - SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); - - /* Size and allocate the main established and bind bucket - * hash tables. - * - * The methodology is similar to that of the buffer cache. - */ - tcp_hashinfo.ehash = - alloc_large_system_hash("TCP established", - sizeof(struct inet_ehash_bucket), - thash_entries, - 17, /* one slot per 128 KB of memory */ - 0, - NULL, - &tcp_hashinfo.ehash_mask, - 0, - thash_entries ? 0 : 512 * 1024); - for (i = 0; i <= tcp_hashinfo.ehash_mask; i++) - INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].chain, i); - - if (inet_ehash_locks_alloc(&tcp_hashinfo)) - panic("TCP: failed to alloc ehash_locks"); - tcp_hashinfo.bhash = - alloc_large_system_hash("TCP bind", - sizeof(struct inet_bind_hashbucket), - tcp_hashinfo.ehash_mask + 1, - 17, /* one slot per 128 KB of memory */ - 0, - &tcp_hashinfo.bhash_size, - NULL, - 0, - 64 * 1024); - tcp_hashinfo.bhash_size = 1U << tcp_hashinfo.bhash_size; - for (i = 0; i < tcp_hashinfo.bhash_size; i++) { - spin_lock_init(&tcp_hashinfo.bhash[i].lock); - INIT_HLIST_HEAD(&tcp_hashinfo.bhash[i].chain); - } - - - cnt = tcp_hashinfo.ehash_mask + 1; - - tcp_death_row.sysctl_max_tw_buckets = cnt / 2; - sysctl_tcp_max_orphans = cnt / 2; - sysctl_max_syn_backlog = max(128, cnt / 256); - - tcp_init_mem(); - /* Set per-socket limits to no more than 1/128 the pressure threshold */ - limit = nr_free_buffer_pages() << (PAGE_SHIFT - 7); - max_wshare = min(4UL*1024*1024, limit); - max_rshare = min(6UL*1024*1024, limit); - - sysctl_tcp_wmem[0] = SK_MEM_QUANTUM; - sysctl_tcp_wmem[1] = 16*1024; - sysctl_tcp_wmem[2] = max(64*1024, max_wshare); - - sysctl_tcp_rmem[0] = SK_MEM_QUANTUM; - sysctl_tcp_rmem[1] = 87380; - sysctl_tcp_rmem[2] = max(87380, max_rshare); - - pr_info("Hash tables configured (established %u bind %u)\n", - tcp_hashinfo.ehash_mask + 1, tcp_hashinfo.bhash_size); - - tcp_metrics_init(); - BUG_ON(tcp_register_congestion_control(&tcp_reno) != 0); - tcp_tasklet_init(); -} diff --git a/src/linux/net/ipv4/tcp_cong.c b/src/linux/net/ipv4/tcp_cong.c deleted file mode 100644 index f9038d6..0000000 --- a/src/linux/net/ipv4/tcp_cong.c +++ /dev/null @@ -1,452 +0,0 @@ -/* - * Pluggable TCP congestion control support and newReno - * congestion control. - * Based on ideas from I/O scheduler support and Web100. - * - * Copyright (C) 2005 Stephen Hemminger - */ - -#define pr_fmt(fmt) "TCP: " fmt - -#include -#include -#include -#include -#include -#include -#include - -static DEFINE_SPINLOCK(tcp_cong_list_lock); -static LIST_HEAD(tcp_cong_list); - -/* Simple linear search, don't expect many entries! */ -static struct tcp_congestion_ops *tcp_ca_find(const char *name) -{ - struct tcp_congestion_ops *e; - - list_for_each_entry_rcu(e, &tcp_cong_list, list) { - if (strcmp(e->name, name) == 0) - return e; - } - - return NULL; -} - -/* Must be called with rcu lock held */ -static const struct tcp_congestion_ops *__tcp_ca_find_autoload(const char *name) -{ - const struct tcp_congestion_ops *ca = tcp_ca_find(name); -#ifdef CONFIG_MODULES - if (!ca && capable(CAP_NET_ADMIN)) { - rcu_read_unlock(); - request_module("tcp_%s", name); - rcu_read_lock(); - ca = tcp_ca_find(name); - } -#endif - return ca; -} - -/* Simple linear search, not much in here. */ -struct tcp_congestion_ops *tcp_ca_find_key(u32 key) -{ - struct tcp_congestion_ops *e; - - list_for_each_entry_rcu(e, &tcp_cong_list, list) { - if (e->key == key) - return e; - } - - return NULL; -} - -/* - * Attach new congestion control algorithm to the list - * of available options. - */ -int tcp_register_congestion_control(struct tcp_congestion_ops *ca) -{ - int ret = 0; - - /* all algorithms must implement ssthresh and cong_avoid ops */ - if (!ca->ssthresh || !(ca->cong_avoid || ca->cong_control)) { - pr_err("%s does not implement required ops\n", ca->name); - return -EINVAL; - } - - ca->key = jhash(ca->name, sizeof(ca->name), strlen(ca->name)); - - spin_lock(&tcp_cong_list_lock); - if (ca->key == TCP_CA_UNSPEC || tcp_ca_find_key(ca->key)) { - pr_notice("%s already registered or non-unique key\n", - ca->name); - ret = -EEXIST; - } else { - list_add_tail_rcu(&ca->list, &tcp_cong_list); - pr_debug("%s registered\n", ca->name); - } - spin_unlock(&tcp_cong_list_lock); - - return ret; -} -EXPORT_SYMBOL_GPL(tcp_register_congestion_control); - -/* - * Remove congestion control algorithm, called from - * the module's remove function. Module ref counts are used - * to ensure that this can't be done till all sockets using - * that method are closed. - */ -void tcp_unregister_congestion_control(struct tcp_congestion_ops *ca) -{ - spin_lock(&tcp_cong_list_lock); - list_del_rcu(&ca->list); - spin_unlock(&tcp_cong_list_lock); - - /* Wait for outstanding readers to complete before the - * module gets removed entirely. - * - * A try_module_get() should fail by now as our module is - * in "going" state since no refs are held anymore and - * module_exit() handler being called. - */ - synchronize_rcu(); -} -EXPORT_SYMBOL_GPL(tcp_unregister_congestion_control); - -u32 tcp_ca_get_key_by_name(const char *name, bool *ecn_ca) -{ - const struct tcp_congestion_ops *ca; - u32 key = TCP_CA_UNSPEC; - - might_sleep(); - - rcu_read_lock(); - ca = __tcp_ca_find_autoload(name); - if (ca) { - key = ca->key; - *ecn_ca = ca->flags & TCP_CONG_NEEDS_ECN; - } - rcu_read_unlock(); - - return key; -} -EXPORT_SYMBOL_GPL(tcp_ca_get_key_by_name); - -char *tcp_ca_get_name_by_key(u32 key, char *buffer) -{ - const struct tcp_congestion_ops *ca; - char *ret = NULL; - - rcu_read_lock(); - ca = tcp_ca_find_key(key); - if (ca) - ret = strncpy(buffer, ca->name, - TCP_CA_NAME_MAX); - rcu_read_unlock(); - - return ret; -} -EXPORT_SYMBOL_GPL(tcp_ca_get_name_by_key); - -/* Assign choice of congestion control. */ -void tcp_assign_congestion_control(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_congestion_ops *ca; - - rcu_read_lock(); - list_for_each_entry_rcu(ca, &tcp_cong_list, list) { - if (likely(try_module_get(ca->owner))) { - icsk->icsk_ca_ops = ca; - goto out; - } - /* Fallback to next available. The last really - * guaranteed fallback is Reno from this list. - */ - } -out: - rcu_read_unlock(); - - /* Clear out private data before diag gets it and - * the ca has not been initialized. - */ - if (ca->get_info) - memset(icsk->icsk_ca_priv, 0, sizeof(icsk->icsk_ca_priv)); - if (ca->flags & TCP_CONG_NEEDS_ECN) - INET_ECN_xmit(sk); - else - INET_ECN_dontxmit(sk); -} - -void tcp_init_congestion_control(struct sock *sk) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - - if (icsk->icsk_ca_ops->init) - icsk->icsk_ca_ops->init(sk); - if (tcp_ca_needs_ecn(sk)) - INET_ECN_xmit(sk); - else - INET_ECN_dontxmit(sk); -} - -static void tcp_reinit_congestion_control(struct sock *sk, - const struct tcp_congestion_ops *ca) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - - tcp_cleanup_congestion_control(sk); - icsk->icsk_ca_ops = ca; - icsk->icsk_ca_setsockopt = 1; - - if (sk->sk_state != TCP_CLOSE) { - memset(icsk->icsk_ca_priv, 0, sizeof(icsk->icsk_ca_priv)); - tcp_init_congestion_control(sk); - } -} - -/* Manage refcounts on socket close. */ -void tcp_cleanup_congestion_control(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - - if (icsk->icsk_ca_ops->release) - icsk->icsk_ca_ops->release(sk); - module_put(icsk->icsk_ca_ops->owner); -} - -/* Used by sysctl to change default congestion control */ -int tcp_set_default_congestion_control(const char *name) -{ - struct tcp_congestion_ops *ca; - int ret = -ENOENT; - - spin_lock(&tcp_cong_list_lock); - ca = tcp_ca_find(name); -#ifdef CONFIG_MODULES - if (!ca && capable(CAP_NET_ADMIN)) { - spin_unlock(&tcp_cong_list_lock); - - request_module("tcp_%s", name); - spin_lock(&tcp_cong_list_lock); - ca = tcp_ca_find(name); - } -#endif - - if (ca) { - ca->flags |= TCP_CONG_NON_RESTRICTED; /* default is always allowed */ - list_move(&ca->list, &tcp_cong_list); - ret = 0; - } - spin_unlock(&tcp_cong_list_lock); - - return ret; -} - -/* Set default value from kernel configuration at bootup */ -static int __init tcp_congestion_default(void) -{ - return tcp_set_default_congestion_control(CONFIG_DEFAULT_TCP_CONG); -} -late_initcall(tcp_congestion_default); - -/* Build string with list of available congestion control values */ -void tcp_get_available_congestion_control(char *buf, size_t maxlen) -{ - struct tcp_congestion_ops *ca; - size_t offs = 0; - - rcu_read_lock(); - list_for_each_entry_rcu(ca, &tcp_cong_list, list) { - offs += snprintf(buf + offs, maxlen - offs, - "%s%s", - offs == 0 ? "" : " ", ca->name); - } - rcu_read_unlock(); -} - -/* Get current default congestion control */ -void tcp_get_default_congestion_control(char *name) -{ - struct tcp_congestion_ops *ca; - /* We will always have reno... */ - BUG_ON(list_empty(&tcp_cong_list)); - - rcu_read_lock(); - ca = list_entry(tcp_cong_list.next, struct tcp_congestion_ops, list); - strncpy(name, ca->name, TCP_CA_NAME_MAX); - rcu_read_unlock(); -} - -/* Built list of non-restricted congestion control values */ -void tcp_get_allowed_congestion_control(char *buf, size_t maxlen) -{ - struct tcp_congestion_ops *ca; - size_t offs = 0; - - *buf = '\0'; - rcu_read_lock(); - list_for_each_entry_rcu(ca, &tcp_cong_list, list) { - if (!(ca->flags & TCP_CONG_NON_RESTRICTED)) - continue; - offs += snprintf(buf + offs, maxlen - offs, - "%s%s", - offs == 0 ? "" : " ", ca->name); - } - rcu_read_unlock(); -} - -/* Change list of non-restricted congestion control */ -int tcp_set_allowed_congestion_control(char *val) -{ - struct tcp_congestion_ops *ca; - char *saved_clone, *clone, *name; - int ret = 0; - - saved_clone = clone = kstrdup(val, GFP_USER); - if (!clone) - return -ENOMEM; - - spin_lock(&tcp_cong_list_lock); - /* pass 1 check for bad entries */ - while ((name = strsep(&clone, " ")) && *name) { - ca = tcp_ca_find(name); - if (!ca) { - ret = -ENOENT; - goto out; - } - } - - /* pass 2 clear old values */ - list_for_each_entry_rcu(ca, &tcp_cong_list, list) - ca->flags &= ~TCP_CONG_NON_RESTRICTED; - - /* pass 3 mark as allowed */ - while ((name = strsep(&val, " ")) && *name) { - ca = tcp_ca_find(name); - WARN_ON(!ca); - if (ca) - ca->flags |= TCP_CONG_NON_RESTRICTED; - } -out: - spin_unlock(&tcp_cong_list_lock); - kfree(saved_clone); - - return ret; -} - -/* Change congestion control for socket */ -int tcp_set_congestion_control(struct sock *sk, const char *name) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - const struct tcp_congestion_ops *ca; - int err = 0; - - if (icsk->icsk_ca_dst_locked) - return -EPERM; - - rcu_read_lock(); - ca = __tcp_ca_find_autoload(name); - /* No change asking for existing value */ - if (ca == icsk->icsk_ca_ops) { - icsk->icsk_ca_setsockopt = 1; - goto out; - } - if (!ca) - err = -ENOENT; - else if (!((ca->flags & TCP_CONG_NON_RESTRICTED) || - ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))) - err = -EPERM; - else if (!try_module_get(ca->owner)) - err = -EBUSY; - else - tcp_reinit_congestion_control(sk, ca); - out: - rcu_read_unlock(); - return err; -} - -/* Slow start is used when congestion window is no greater than the slow start - * threshold. We base on RFC2581 and also handle stretch ACKs properly. - * We do not implement RFC3465 Appropriate Byte Counting (ABC) per se but - * something better;) a packet is only considered (s)acked in its entirety to - * defend the ACK attacks described in the RFC. Slow start processes a stretch - * ACK of degree N as if N acks of degree 1 are received back to back except - * ABC caps N to 2. Slow start exits when cwnd grows over ssthresh and - * returns the leftover acks to adjust cwnd in congestion avoidance mode. - */ -u32 tcp_slow_start(struct tcp_sock *tp, u32 acked) -{ - u32 cwnd = min(tp->snd_cwnd + acked, tp->snd_ssthresh); - - acked -= cwnd - tp->snd_cwnd; - tp->snd_cwnd = min(cwnd, tp->snd_cwnd_clamp); - - return acked; -} -EXPORT_SYMBOL_GPL(tcp_slow_start); - -/* In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd (or alternative w), - * for every packet that was ACKed. - */ -void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w, u32 acked) -{ - /* If credits accumulated at a higher w, apply them gently now. */ - if (tp->snd_cwnd_cnt >= w) { - tp->snd_cwnd_cnt = 0; - tp->snd_cwnd++; - } - - tp->snd_cwnd_cnt += acked; - if (tp->snd_cwnd_cnt >= w) { - u32 delta = tp->snd_cwnd_cnt / w; - - tp->snd_cwnd_cnt -= delta * w; - tp->snd_cwnd += delta; - } - tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_cwnd_clamp); -} -EXPORT_SYMBOL_GPL(tcp_cong_avoid_ai); - -/* - * TCP Reno congestion control - * This is special case used for fallback as well. - */ -/* This is Jacobson's slow start and congestion avoidance. - * SIGCOMM '88, p. 328. - */ -void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 acked) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (!tcp_is_cwnd_limited(sk)) - return; - - /* In "safe" area, increase. */ - if (tcp_in_slow_start(tp)) { - acked = tcp_slow_start(tp, acked); - if (!acked) - return; - } - /* In dangerous area, increase slowly. */ - tcp_cong_avoid_ai(tp, tp->snd_cwnd, acked); -} -EXPORT_SYMBOL_GPL(tcp_reno_cong_avoid); - -/* Slow start threshold is half the congestion window (min 2) */ -u32 tcp_reno_ssthresh(struct sock *sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - - return max(tp->snd_cwnd >> 1U, 2U); -} -EXPORT_SYMBOL_GPL(tcp_reno_ssthresh); - -struct tcp_congestion_ops tcp_reno = { - .flags = TCP_CONG_NON_RESTRICTED, - .name = "reno", - .owner = THIS_MODULE, - .ssthresh = tcp_reno_ssthresh, - .cong_avoid = tcp_reno_cong_avoid, -}; diff --git a/src/linux/net/ipv4/tcp_cubic.c b/src/linux/net/ipv4/tcp_cubic.c deleted file mode 100644 index c99230e..0000000 --- a/src/linux/net/ipv4/tcp_cubic.c +++ /dev/null @@ -1,526 +0,0 @@ -/* - * TCP CUBIC: Binary Increase Congestion control for TCP v2.3 - * Home page: - * http://netsrv.csc.ncsu.edu/twiki/bin/view/Main/BIC - * This is from the implementation of CUBIC TCP in - * Sangtae Ha, Injong Rhee and Lisong Xu, - * "CUBIC: A New TCP-Friendly High-Speed TCP Variant" - * in ACM SIGOPS Operating System Review, July 2008. - * Available from: - * http://netsrv.csc.ncsu.edu/export/cubic_a_new_tcp_2008.pdf - * - * CUBIC integrates a new slow start algorithm, called HyStart. - * The details of HyStart are presented in - * Sangtae Ha and Injong Rhee, - * "Taming the Elephants: New TCP Slow Start", NCSU TechReport 2008. - * Available from: - * http://netsrv.csc.ncsu.edu/export/hystart_techreport_2008.pdf - * - * All testing results are available from: - * http://netsrv.csc.ncsu.edu/wiki/index.php/TCP_Testing - * - * Unless CUBIC is enabled and congestion window is large - * this behaves the same as the original Reno. - */ - -#include -#include -#include -#include - -#define BICTCP_BETA_SCALE 1024 /* Scale factor beta calculation - * max_cwnd = snd_cwnd * beta - */ -#define BICTCP_HZ 10 /* BIC HZ 2^10 = 1024 */ - -/* Two methods of hybrid slow start */ -#define HYSTART_ACK_TRAIN 0x1 -#define HYSTART_DELAY 0x2 - -/* Number of delay samples for detecting the increase of delay */ -#define HYSTART_MIN_SAMPLES 8 -#define HYSTART_DELAY_MIN (4U<<3) -#define HYSTART_DELAY_MAX (16U<<3) -#define HYSTART_DELAY_THRESH(x) clamp(x, HYSTART_DELAY_MIN, HYSTART_DELAY_MAX) - -static int fast_convergence __read_mostly = 1; -static int beta __read_mostly = 717; /* = 717/1024 (BICTCP_BETA_SCALE) */ -static int initial_ssthresh __read_mostly; -static int bic_scale __read_mostly = 41; -static int tcp_friendliness __read_mostly = 1; - -static int hystart __read_mostly = 1; -static int hystart_detect __read_mostly = HYSTART_ACK_TRAIN | HYSTART_DELAY; -static int hystart_low_window __read_mostly = 16; -static int hystart_ack_delta __read_mostly = 2; - -static u32 cube_rtt_scale __read_mostly; -static u32 beta_scale __read_mostly; -static u64 cube_factor __read_mostly; - -/* Note parameters that are used for precomputing scale factors are read-only */ -module_param(fast_convergence, int, 0644); -MODULE_PARM_DESC(fast_convergence, "turn on/off fast convergence"); -module_param(beta, int, 0644); -MODULE_PARM_DESC(beta, "beta for multiplicative increase"); -module_param(initial_ssthresh, int, 0644); -MODULE_PARM_DESC(initial_ssthresh, "initial value of slow start threshold"); -module_param(bic_scale, int, 0444); -MODULE_PARM_DESC(bic_scale, "scale (scaled by 1024) value for bic function (bic_scale/1024)"); -module_param(tcp_friendliness, int, 0644); -MODULE_PARM_DESC(tcp_friendliness, "turn on/off tcp friendliness"); -module_param(hystart, int, 0644); -MODULE_PARM_DESC(hystart, "turn on/off hybrid slow start algorithm"); -module_param(hystart_detect, int, 0644); -MODULE_PARM_DESC(hystart_detect, "hyrbrid slow start detection mechanisms" - " 1: packet-train 2: delay 3: both packet-train and delay"); -module_param(hystart_low_window, int, 0644); -MODULE_PARM_DESC(hystart_low_window, "lower bound cwnd for hybrid slow start"); -module_param(hystart_ack_delta, int, 0644); -MODULE_PARM_DESC(hystart_ack_delta, "spacing between ack's indicating train (msecs)"); - -/* BIC TCP Parameters */ -struct bictcp { - u32 cnt; /* increase cwnd by 1 after ACKs */ - u32 last_max_cwnd; /* last maximum snd_cwnd */ - u32 loss_cwnd; /* congestion window at last loss */ - u32 last_cwnd; /* the last snd_cwnd */ - u32 last_time; /* time when updated last_cwnd */ - u32 bic_origin_point;/* origin point of bic function */ - u32 bic_K; /* time to origin point - from the beginning of the current epoch */ - u32 delay_min; /* min delay (msec << 3) */ - u32 epoch_start; /* beginning of an epoch */ - u32 ack_cnt; /* number of acks */ - u32 tcp_cwnd; /* estimated tcp cwnd */ - u16 unused; - u8 sample_cnt; /* number of samples to decide curr_rtt */ - u8 found; /* the exit point is found? */ - u32 round_start; /* beginning of each round */ - u32 end_seq; /* end_seq of the round */ - u32 last_ack; /* last time when the ACK spacing is close */ - u32 curr_rtt; /* the minimum rtt of current round */ -}; - -static inline void bictcp_reset(struct bictcp *ca) -{ - ca->cnt = 0; - ca->last_max_cwnd = 0; - ca->last_cwnd = 0; - ca->last_time = 0; - ca->bic_origin_point = 0; - ca->bic_K = 0; - ca->delay_min = 0; - ca->epoch_start = 0; - ca->ack_cnt = 0; - ca->tcp_cwnd = 0; - ca->found = 0; -} - -static inline u32 bictcp_clock(void) -{ -#if HZ < 1000 - return ktime_to_ms(ktime_get_real()); -#else - return jiffies_to_msecs(jiffies); -#endif -} - -static inline void bictcp_hystart_reset(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct bictcp *ca = inet_csk_ca(sk); - - ca->round_start = ca->last_ack = bictcp_clock(); - ca->end_seq = tp->snd_nxt; - ca->curr_rtt = 0; - ca->sample_cnt = 0; -} - -static void bictcp_init(struct sock *sk) -{ - struct bictcp *ca = inet_csk_ca(sk); - - bictcp_reset(ca); - ca->loss_cwnd = 0; - - if (hystart) - bictcp_hystart_reset(sk); - - if (!hystart && initial_ssthresh) - tcp_sk(sk)->snd_ssthresh = initial_ssthresh; -} - -static void bictcp_cwnd_event(struct sock *sk, enum tcp_ca_event event) -{ - if (event == CA_EVENT_TX_START) { - struct bictcp *ca = inet_csk_ca(sk); - u32 now = tcp_time_stamp; - s32 delta; - - delta = now - tcp_sk(sk)->lsndtime; - - /* We were application limited (idle) for a while. - * Shift epoch_start to keep cwnd growth to cubic curve. - */ - if (ca->epoch_start && delta > 0) { - ca->epoch_start += delta; - if (after(ca->epoch_start, now)) - ca->epoch_start = now; - } - return; - } -} - -/* calculate the cubic root of x using a table lookup followed by one - * Newton-Raphson iteration. - * Avg err ~= 0.195% - */ -static u32 cubic_root(u64 a) -{ - u32 x, b, shift; - /* - * cbrt(x) MSB values for x MSB values in [0..63]. - * Precomputed then refined by hand - Willy Tarreau - * - * For x in [0..63], - * v = cbrt(x << 18) - 1 - * cbrt(x) = (v[x] + 10) >> 6 - */ - static const u8 v[] = { - /* 0x00 */ 0, 54, 54, 54, 118, 118, 118, 118, - /* 0x08 */ 123, 129, 134, 138, 143, 147, 151, 156, - /* 0x10 */ 157, 161, 164, 168, 170, 173, 176, 179, - /* 0x18 */ 181, 185, 187, 190, 192, 194, 197, 199, - /* 0x20 */ 200, 202, 204, 206, 209, 211, 213, 215, - /* 0x28 */ 217, 219, 221, 222, 224, 225, 227, 229, - /* 0x30 */ 231, 232, 234, 236, 237, 239, 240, 242, - /* 0x38 */ 244, 245, 246, 248, 250, 251, 252, 254, - }; - - b = fls64(a); - if (b < 7) { - /* a in [0..63] */ - return ((u32)v[(u32)a] + 35) >> 6; - } - - b = ((b * 84) >> 8) - 1; - shift = (a >> (b * 3)); - - x = ((u32)(((u32)v[shift] + 10) << b)) >> 6; - - /* - * Newton-Raphson iteration - * 2 - * x = ( 2 * x + a / x ) / 3 - * k+1 k k - */ - x = (2 * x + (u32)div64_u64(a, (u64)x * (u64)(x - 1))); - x = ((x * 341) >> 10); - return x; -} - -/* - * Compute congestion window to use. - */ -static inline void bictcp_update(struct bictcp *ca, u32 cwnd, u32 acked) -{ - u32 delta, bic_target, max_cnt; - u64 offs, t; - - ca->ack_cnt += acked; /* count the number of ACKed packets */ - - if (ca->last_cwnd == cwnd && - (s32)(tcp_time_stamp - ca->last_time) <= HZ / 32) - return; - - /* The CUBIC function can update ca->cnt at most once per jiffy. - * On all cwnd reduction events, ca->epoch_start is set to 0, - * which will force a recalculation of ca->cnt. - */ - if (ca->epoch_start && tcp_time_stamp == ca->last_time) - goto tcp_friendliness; - - ca->last_cwnd = cwnd; - ca->last_time = tcp_time_stamp; - - if (ca->epoch_start == 0) { - ca->epoch_start = tcp_time_stamp; /* record beginning */ - ca->ack_cnt = acked; /* start counting */ - ca->tcp_cwnd = cwnd; /* syn with cubic */ - - if (ca->last_max_cwnd <= cwnd) { - ca->bic_K = 0; - ca->bic_origin_point = cwnd; - } else { - /* Compute new K based on - * (wmax-cwnd) * (srtt>>3 / HZ) / c * 2^(3*bictcp_HZ) - */ - ca->bic_K = cubic_root(cube_factor - * (ca->last_max_cwnd - cwnd)); - ca->bic_origin_point = ca->last_max_cwnd; - } - } - - /* cubic function - calc*/ - /* calculate c * time^3 / rtt, - * while considering overflow in calculation of time^3 - * (so time^3 is done by using 64 bit) - * and without the support of division of 64bit numbers - * (so all divisions are done by using 32 bit) - * also NOTE the unit of those veriables - * time = (t - K) / 2^bictcp_HZ - * c = bic_scale >> 10 - * rtt = (srtt >> 3) / HZ - * !!! The following code does not have overflow problems, - * if the cwnd < 1 million packets !!! - */ - - t = (s32)(tcp_time_stamp - ca->epoch_start); - t += msecs_to_jiffies(ca->delay_min >> 3); - /* change the unit from HZ to bictcp_HZ */ - t <<= BICTCP_HZ; - do_div(t, HZ); - - if (t < ca->bic_K) /* t - K */ - offs = ca->bic_K - t; - else - offs = t - ca->bic_K; - - /* c/rtt * (t-K)^3 */ - delta = (cube_rtt_scale * offs * offs * offs) >> (10+3*BICTCP_HZ); - if (t < ca->bic_K) /* below origin*/ - bic_target = ca->bic_origin_point - delta; - else /* above origin*/ - bic_target = ca->bic_origin_point + delta; - - /* cubic function - calc bictcp_cnt*/ - if (bic_target > cwnd) { - ca->cnt = cwnd / (bic_target - cwnd); - } else { - ca->cnt = 100 * cwnd; /* very small increment*/ - } - - /* - * The initial growth of cubic function may be too conservative - * when the available bandwidth is still unknown. - */ - if (ca->last_max_cwnd == 0 && ca->cnt > 20) - ca->cnt = 20; /* increase cwnd 5% per RTT */ - -tcp_friendliness: - /* TCP Friendly */ - if (tcp_friendliness) { - u32 scale = beta_scale; - - delta = (cwnd * scale) >> 3; - while (ca->ack_cnt > delta) { /* update tcp cwnd */ - ca->ack_cnt -= delta; - ca->tcp_cwnd++; - } - - if (ca->tcp_cwnd > cwnd) { /* if bic is slower than tcp */ - delta = ca->tcp_cwnd - cwnd; - max_cnt = cwnd / delta; - if (ca->cnt > max_cnt) - ca->cnt = max_cnt; - } - } - - /* The maximum rate of cwnd increase CUBIC allows is 1 packet per - * 2 packets ACKed, meaning cwnd grows at 1.5x per RTT. - */ - ca->cnt = max(ca->cnt, 2U); -} - -static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 acked) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct bictcp *ca = inet_csk_ca(sk); - - if (!tcp_is_cwnd_limited(sk)) - return; - - if (tcp_in_slow_start(tp)) { - if (hystart && after(ack, ca->end_seq)) - bictcp_hystart_reset(sk); - acked = tcp_slow_start(tp, acked); - if (!acked) - return; - } - bictcp_update(ca, tp->snd_cwnd, acked); - tcp_cong_avoid_ai(tp, ca->cnt, acked); -} - -static u32 bictcp_recalc_ssthresh(struct sock *sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - struct bictcp *ca = inet_csk_ca(sk); - - ca->epoch_start = 0; /* end of epoch */ - - /* Wmax and fast convergence */ - if (tp->snd_cwnd < ca->last_max_cwnd && fast_convergence) - ca->last_max_cwnd = (tp->snd_cwnd * (BICTCP_BETA_SCALE + beta)) - / (2 * BICTCP_BETA_SCALE); - else - ca->last_max_cwnd = tp->snd_cwnd; - - ca->loss_cwnd = tp->snd_cwnd; - - return max((tp->snd_cwnd * beta) / BICTCP_BETA_SCALE, 2U); -} - -static u32 bictcp_undo_cwnd(struct sock *sk) -{ - struct bictcp *ca = inet_csk_ca(sk); - - return max(tcp_sk(sk)->snd_cwnd, ca->loss_cwnd); -} - -static void bictcp_state(struct sock *sk, u8 new_state) -{ - if (new_state == TCP_CA_Loss) { - bictcp_reset(inet_csk_ca(sk)); - bictcp_hystart_reset(sk); - } -} - -static void hystart_update(struct sock *sk, u32 delay) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct bictcp *ca = inet_csk_ca(sk); - - if (ca->found & hystart_detect) - return; - - if (hystart_detect & HYSTART_ACK_TRAIN) { - u32 now = bictcp_clock(); - - /* first detection parameter - ack-train detection */ - if ((s32)(now - ca->last_ack) <= hystart_ack_delta) { - ca->last_ack = now; - if ((s32)(now - ca->round_start) > ca->delay_min >> 4) { - ca->found |= HYSTART_ACK_TRAIN; - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPHYSTARTTRAINDETECT); - NET_ADD_STATS(sock_net(sk), - LINUX_MIB_TCPHYSTARTTRAINCWND, - tp->snd_cwnd); - tp->snd_ssthresh = tp->snd_cwnd; - } - } - } - - if (hystart_detect & HYSTART_DELAY) { - /* obtain the minimum delay of more than sampling packets */ - if (ca->sample_cnt < HYSTART_MIN_SAMPLES) { - if (ca->curr_rtt == 0 || ca->curr_rtt > delay) - ca->curr_rtt = delay; - - ca->sample_cnt++; - } else { - if (ca->curr_rtt > ca->delay_min + - HYSTART_DELAY_THRESH(ca->delay_min >> 3)) { - ca->found |= HYSTART_DELAY; - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPHYSTARTDELAYDETECT); - NET_ADD_STATS(sock_net(sk), - LINUX_MIB_TCPHYSTARTDELAYCWND, - tp->snd_cwnd); - tp->snd_ssthresh = tp->snd_cwnd; - } - } - } -} - -/* Track delayed acknowledgment ratio using sliding window - * ratio = (15*ratio + sample) / 16 - */ -static void bictcp_acked(struct sock *sk, const struct ack_sample *sample) -{ - const struct tcp_sock *tp = tcp_sk(sk); - struct bictcp *ca = inet_csk_ca(sk); - u32 delay; - - /* Some calls are for duplicates without timetamps */ - if (sample->rtt_us < 0) - return; - - /* Discard delay samples right after fast recovery */ - if (ca->epoch_start && (s32)(tcp_time_stamp - ca->epoch_start) < HZ) - return; - - delay = (sample->rtt_us << 3) / USEC_PER_MSEC; - if (delay == 0) - delay = 1; - - /* first time call or link delay decreases */ - if (ca->delay_min == 0 || ca->delay_min > delay) - ca->delay_min = delay; - - /* hystart triggers when cwnd is larger than some threshold */ - if (hystart && tcp_in_slow_start(tp) && - tp->snd_cwnd >= hystart_low_window) - hystart_update(sk, delay); -} - -static struct tcp_congestion_ops cubictcp __read_mostly = { - .init = bictcp_init, - .ssthresh = bictcp_recalc_ssthresh, - .cong_avoid = bictcp_cong_avoid, - .set_state = bictcp_state, - .undo_cwnd = bictcp_undo_cwnd, - .cwnd_event = bictcp_cwnd_event, - .pkts_acked = bictcp_acked, - .owner = THIS_MODULE, - .name = "cubic", -}; - -static int __init cubictcp_register(void) -{ - BUILD_BUG_ON(sizeof(struct bictcp) > ICSK_CA_PRIV_SIZE); - - /* Precompute a bunch of the scaling factors that are used per-packet - * based on SRTT of 100ms - */ - - beta_scale = 8*(BICTCP_BETA_SCALE+beta) / 3 - / (BICTCP_BETA_SCALE - beta); - - cube_rtt_scale = (bic_scale * 10); /* 1024*c/rtt */ - - /* calculate the "K" for (wmax-cwnd) = c/rtt * K^3 - * so K = cubic_root( (wmax-cwnd)*rtt/c ) - * the unit of K is bictcp_HZ=2^10, not HZ - * - * c = bic_scale >> 10 - * rtt = 100ms - * - * the following code has been designed and tested for - * cwnd < 1 million packets - * RTT < 100 seconds - * HZ < 1,000,00 (corresponding to 10 nano-second) - */ - - /* 1/c * 2^2*bictcp_HZ * srtt */ - cube_factor = 1ull << (10+3*BICTCP_HZ); /* 2^40 */ - - /* divide by bic_scale and by constant Srtt (100ms) */ - do_div(cube_factor, bic_scale * 10); - - return tcp_register_congestion_control(&cubictcp); -} - -static void __exit cubictcp_unregister(void) -{ - tcp_unregister_congestion_control(&cubictcp); -} - -module_init(cubictcp_register); -module_exit(cubictcp_unregister); - -MODULE_AUTHOR("Sangtae Ha, Stephen Hemminger"); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("CUBIC TCP"); -MODULE_VERSION("2.3"); diff --git a/src/linux/net/ipv4/tcp_diag.c b/src/linux/net/ipv4/tcp_diag.c deleted file mode 100644 index a748c74..0000000 --- a/src/linux/net/ipv4/tcp_diag.c +++ /dev/null @@ -1,94 +0,0 @@ -/* - * tcp_diag.c Module for monitoring TCP transport protocols sockets. - * - * Authors: Alexey Kuznetsov, - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include - -#include - -#include - -static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, - void *_info) -{ - struct tcp_info *info = _info; - - if (sk_state_load(sk) == TCP_LISTEN) { - r->idiag_rqueue = sk->sk_ack_backlog; - r->idiag_wqueue = sk->sk_max_ack_backlog; - } else if (sk->sk_type == SOCK_STREAM) { - const struct tcp_sock *tp = tcp_sk(sk); - - r->idiag_rqueue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0); - r->idiag_wqueue = tp->write_seq - tp->snd_una; - } - if (info) - tcp_get_info(sk, info); -} - -static void tcp_diag_dump(struct sk_buff *skb, struct netlink_callback *cb, - const struct inet_diag_req_v2 *r, struct nlattr *bc) -{ - inet_diag_dump_icsk(&tcp_hashinfo, skb, cb, r, bc); -} - -static int tcp_diag_dump_one(struct sk_buff *in_skb, const struct nlmsghdr *nlh, - const struct inet_diag_req_v2 *req) -{ - return inet_diag_dump_one_icsk(&tcp_hashinfo, in_skb, nlh, req); -} - -#ifdef CONFIG_INET_DIAG_DESTROY -static int tcp_diag_destroy(struct sk_buff *in_skb, - const struct inet_diag_req_v2 *req) -{ - struct net *net = sock_net(in_skb->sk); - struct sock *sk = inet_diag_find_one_icsk(net, &tcp_hashinfo, req); - int err; - - if (IS_ERR(sk)) - return PTR_ERR(sk); - - err = sock_diag_destroy(sk, ECONNABORTED); - - sock_gen_put(sk); - - return err; -} -#endif - -static const struct inet_diag_handler tcp_diag_handler = { - .dump = tcp_diag_dump, - .dump_one = tcp_diag_dump_one, - .idiag_get_info = tcp_diag_get_info, - .idiag_type = IPPROTO_TCP, - .idiag_info_size = sizeof(struct tcp_info), -#ifdef CONFIG_INET_DIAG_DESTROY - .destroy = tcp_diag_destroy, -#endif -}; - -static int __init tcp_diag_init(void) -{ - return inet_diag_register(&tcp_diag_handler); -} - -static void __exit tcp_diag_exit(void) -{ - inet_diag_unregister(&tcp_diag_handler); -} - -module_init(tcp_diag_init); -module_exit(tcp_diag_exit); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_NETLINK, NETLINK_SOCK_DIAG, 2-6 /* AF_INET - IPPROTO_TCP */); diff --git a/src/linux/net/ipv4/tcp_fastopen.c b/src/linux/net/ipv4/tcp_fastopen.c deleted file mode 100644 index 4e777a3..0000000 --- a/src/linux/net/ipv4/tcp_fastopen.c +++ /dev/null @@ -1,327 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int sysctl_tcp_fastopen __read_mostly = TFO_CLIENT_ENABLE; - -struct tcp_fastopen_context __rcu *tcp_fastopen_ctx; - -static DEFINE_SPINLOCK(tcp_fastopen_ctx_lock); - -void tcp_fastopen_init_key_once(bool publish) -{ - static u8 key[TCP_FASTOPEN_KEY_LENGTH]; - - /* tcp_fastopen_reset_cipher publishes the new context - * atomically, so we allow this race happening here. - * - * All call sites of tcp_fastopen_cookie_gen also check - * for a valid cookie, so this is an acceptable risk. - */ - if (net_get_random_once(key, sizeof(key)) && publish) - tcp_fastopen_reset_cipher(key, sizeof(key)); -} - -static void tcp_fastopen_ctx_free(struct rcu_head *head) -{ - struct tcp_fastopen_context *ctx = - container_of(head, struct tcp_fastopen_context, rcu); - crypto_free_cipher(ctx->tfm); - kfree(ctx); -} - -int tcp_fastopen_reset_cipher(void *key, unsigned int len) -{ - int err; - struct tcp_fastopen_context *ctx, *octx; - - ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); - if (!ctx) - return -ENOMEM; - ctx->tfm = crypto_alloc_cipher("aes", 0, 0); - - if (IS_ERR(ctx->tfm)) { - err = PTR_ERR(ctx->tfm); -error: kfree(ctx); - pr_err("TCP: TFO aes cipher alloc error: %d\n", err); - return err; - } - err = crypto_cipher_setkey(ctx->tfm, key, len); - if (err) { - pr_err("TCP: TFO cipher key error: %d\n", err); - crypto_free_cipher(ctx->tfm); - goto error; - } - memcpy(ctx->key, key, len); - - spin_lock(&tcp_fastopen_ctx_lock); - - octx = rcu_dereference_protected(tcp_fastopen_ctx, - lockdep_is_held(&tcp_fastopen_ctx_lock)); - rcu_assign_pointer(tcp_fastopen_ctx, ctx); - spin_unlock(&tcp_fastopen_ctx_lock); - - if (octx) - call_rcu(&octx->rcu, tcp_fastopen_ctx_free); - return err; -} - -static bool __tcp_fastopen_cookie_gen(const void *path, - struct tcp_fastopen_cookie *foc) -{ - struct tcp_fastopen_context *ctx; - bool ok = false; - - rcu_read_lock(); - ctx = rcu_dereference(tcp_fastopen_ctx); - if (ctx) { - crypto_cipher_encrypt_one(ctx->tfm, foc->val, path); - foc->len = TCP_FASTOPEN_COOKIE_SIZE; - ok = true; - } - rcu_read_unlock(); - return ok; -} - -/* Generate the fastopen cookie by doing aes128 encryption on both - * the source and destination addresses. Pad 0s for IPv4 or IPv4-mapped-IPv6 - * addresses. For the longer IPv6 addresses use CBC-MAC. - * - * XXX (TFO) - refactor when TCP_FASTOPEN_COOKIE_SIZE != AES_BLOCK_SIZE. - */ -static bool tcp_fastopen_cookie_gen(struct request_sock *req, - struct sk_buff *syn, - struct tcp_fastopen_cookie *foc) -{ - if (req->rsk_ops->family == AF_INET) { - const struct iphdr *iph = ip_hdr(syn); - - __be32 path[4] = { iph->saddr, iph->daddr, 0, 0 }; - return __tcp_fastopen_cookie_gen(path, foc); - } - -#if IS_ENABLED(CONFIG_IPV6) - if (req->rsk_ops->family == AF_INET6) { - const struct ipv6hdr *ip6h = ipv6_hdr(syn); - struct tcp_fastopen_cookie tmp; - - if (__tcp_fastopen_cookie_gen(&ip6h->saddr, &tmp)) { - struct in6_addr *buf = (struct in6_addr *) tmp.val; - int i; - - for (i = 0; i < 4; i++) - buf->s6_addr32[i] ^= ip6h->daddr.s6_addr32[i]; - return __tcp_fastopen_cookie_gen(buf, foc); - } - } -#endif - return false; -} - - -/* If an incoming SYN or SYNACK frame contains a payload and/or FIN, - * queue this additional data / FIN. - */ -void tcp_fastopen_add_skb(struct sock *sk, struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (TCP_SKB_CB(skb)->end_seq == tp->rcv_nxt) - return; - - skb = skb_clone(skb, GFP_ATOMIC); - if (!skb) - return; - - skb_dst_drop(skb); - /* segs_in has been initialized to 1 in tcp_create_openreq_child(). - * Hence, reset segs_in to 0 before calling tcp_segs_in() - * to avoid double counting. Also, tcp_segs_in() expects - * skb->len to include the tcp_hdrlen. Hence, it should - * be called before __skb_pull(). - */ - tp->segs_in = 0; - tcp_segs_in(tp, skb); - __skb_pull(skb, tcp_hdrlen(skb)); - sk_forced_mem_schedule(sk, skb->truesize); - skb_set_owner_r(skb, sk); - - TCP_SKB_CB(skb)->seq++; - TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_SYN; - - tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; - __skb_queue_tail(&sk->sk_receive_queue, skb); - tp->syn_data_acked = 1; - - /* u64_stats_update_begin(&tp->syncp) not needed here, - * as we certainly are not changing upper 32bit value (0) - */ - tp->bytes_received = skb->len; - - if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) - tcp_fin(sk); -} - -static struct sock *tcp_fastopen_create_child(struct sock *sk, - struct sk_buff *skb, - struct dst_entry *dst, - struct request_sock *req) -{ - struct tcp_sock *tp; - struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue; - struct sock *child; - bool own_req; - - req->num_retrans = 0; - req->num_timeout = 0; - req->sk = NULL; - - child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL, - NULL, &own_req); - if (!child) - return NULL; - - spin_lock(&queue->fastopenq.lock); - queue->fastopenq.qlen++; - spin_unlock(&queue->fastopenq.lock); - - /* Initialize the child socket. Have to fix some values to take - * into account the child is a Fast Open socket and is created - * only out of the bits carried in the SYN packet. - */ - tp = tcp_sk(child); - - tp->fastopen_rsk = req; - tcp_rsk(req)->tfo_listener = true; - - /* RFC1323: The window in SYN & SYN/ACK segments is never - * scaled. So correct it appropriately. - */ - tp->snd_wnd = ntohs(tcp_hdr(skb)->window); - - /* Activate the retrans timer so that SYNACK can be retransmitted. - * The request socket is not added to the ehash - * because it's been added to the accept queue directly. - */ - inet_csk_reset_xmit_timer(child, ICSK_TIME_RETRANS, - TCP_TIMEOUT_INIT, TCP_RTO_MAX); - - atomic_set(&req->rsk_refcnt, 2); - - /* Now finish processing the fastopen child socket. */ - inet_csk(child)->icsk_af_ops->rebuild_header(child); - tcp_init_congestion_control(child); - tcp_mtup_init(child); - tcp_init_metrics(child); - tcp_init_buffer_space(child); - - tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; - - tcp_fastopen_add_skb(child, skb); - - tcp_rsk(req)->rcv_nxt = tp->rcv_nxt; - tp->rcv_wup = tp->rcv_nxt; - /* tcp_conn_request() is sending the SYNACK, - * and queues the child into listener accept queue. - */ - return child; -} - -static bool tcp_fastopen_queue_check(struct sock *sk) -{ - struct fastopen_queue *fastopenq; - - /* Make sure the listener has enabled fastopen, and we don't - * exceed the max # of pending TFO requests allowed before trying - * to validating the cookie in order to avoid burning CPU cycles - * unnecessarily. - * - * XXX (TFO) - The implication of checking the max_qlen before - * processing a cookie request is that clients can't differentiate - * between qlen overflow causing Fast Open to be disabled - * temporarily vs a server not supporting Fast Open at all. - */ - fastopenq = &inet_csk(sk)->icsk_accept_queue.fastopenq; - if (fastopenq->max_qlen == 0) - return false; - - if (fastopenq->qlen >= fastopenq->max_qlen) { - struct request_sock *req1; - spin_lock(&fastopenq->lock); - req1 = fastopenq->rskq_rst_head; - if (!req1 || time_after(req1->rsk_timer.expires, jiffies)) { - __NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPFASTOPENLISTENOVERFLOW); - spin_unlock(&fastopenq->lock); - return false; - } - fastopenq->rskq_rst_head = req1->dl_next; - fastopenq->qlen--; - spin_unlock(&fastopenq->lock); - reqsk_put(req1); - } - return true; -} - -/* Returns true if we should perform Fast Open on the SYN. The cookie (foc) - * may be updated and return the client in the SYN-ACK later. E.g., Fast Open - * cookie request (foc->len == 0). - */ -struct sock *tcp_try_fastopen(struct sock *sk, struct sk_buff *skb, - struct request_sock *req, - struct tcp_fastopen_cookie *foc, - struct dst_entry *dst) -{ - struct tcp_fastopen_cookie valid_foc = { .len = -1 }; - bool syn_data = TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq + 1; - struct sock *child; - - if (foc->len == 0) /* Client requests a cookie */ - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPFASTOPENCOOKIEREQD); - - if (!((sysctl_tcp_fastopen & TFO_SERVER_ENABLE) && - (syn_data || foc->len >= 0) && - tcp_fastopen_queue_check(sk))) { - foc->len = -1; - return NULL; - } - - if (syn_data && (sysctl_tcp_fastopen & TFO_SERVER_COOKIE_NOT_REQD)) - goto fastopen; - - if (foc->len >= 0 && /* Client presents or requests a cookie */ - tcp_fastopen_cookie_gen(req, skb, &valid_foc) && - foc->len == TCP_FASTOPEN_COOKIE_SIZE && - foc->len == valid_foc.len && - !memcmp(foc->val, valid_foc.val, foc->len)) { - /* Cookie is valid. Create a (full) child socket to accept - * the data in SYN before returning a SYN-ACK to ack the - * data. If we fail to create the socket, fall back and - * ack the ISN only but includes the same cookie. - * - * Note: Data-less SYN with valid cookie is allowed to send - * data in SYN_RECV state. - */ -fastopen: - child = tcp_fastopen_create_child(sk, skb, dst, req); - if (child) { - foc->len = -1; - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPFASTOPENPASSIVE); - return child; - } - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPFASTOPENPASSIVEFAIL); - } else if (foc->len > 0) /* Client presents an invalid cookie */ - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPFASTOPENPASSIVEFAIL); - - valid_foc.exp = foc->exp; - *foc = valid_foc; - return NULL; -} diff --git a/src/linux/net/ipv4/tcp_input.c b/src/linux/net/ipv4/tcp_input.c deleted file mode 100644 index c71d49c..0000000 --- a/src/linux/net/ipv4/tcp_input.c +++ /dev/null @@ -1,6453 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Implementation of the Transmission Control Protocol(TCP). - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Mark Evans, - * Corey Minyard - * Florian La Roche, - * Charles Hedrick, - * Linus Torvalds, - * Alan Cox, - * Matthew Dillon, - * Arnt Gulbrandsen, - * Jorge Cwik, - */ - -/* - * Changes: - * Pedro Roque : Fast Retransmit/Recovery. - * Two receive queues. - * Retransmit queue handled by TCP. - * Better retransmit timer handling. - * New congestion avoidance. - * Header prediction. - * Variable renaming. - * - * Eric : Fast Retransmit. - * Randy Scott : MSS option defines. - * Eric Schenk : Fixes to slow start algorithm. - * Eric Schenk : Yet another double ACK bug. - * Eric Schenk : Delayed ACK bug fixes. - * Eric Schenk : Floyd style fast retrans war avoidance. - * David S. Miller : Don't allow zero congestion window. - * Eric Schenk : Fix retransmitter so that it sends - * next packet on ack of previous packet. - * Andi Kleen : Moved open_request checking here - * and process RSTs for open_requests. - * Andi Kleen : Better prune_queue, and other fixes. - * Andrey Savochkin: Fix RTT measurements in the presence of - * timestamps. - * Andrey Savochkin: Check sequence numbers correctly when - * removing SACKs due to in sequence incoming - * data segments. - * Andi Kleen: Make sure we never ack data there is not - * enough room for. Also make this condition - * a fatal error if it might still happen. - * Andi Kleen: Add tcp_measure_rcv_mss to make - * connections with MSS -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int sysctl_tcp_timestamps __read_mostly = 1; -int sysctl_tcp_window_scaling __read_mostly = 1; -int sysctl_tcp_sack __read_mostly = 1; -int sysctl_tcp_fack __read_mostly = 1; -int sysctl_tcp_max_reordering __read_mostly = 300; -int sysctl_tcp_dsack __read_mostly = 1; -int sysctl_tcp_app_win __read_mostly = 31; -int sysctl_tcp_adv_win_scale __read_mostly = 1; -EXPORT_SYMBOL(sysctl_tcp_adv_win_scale); - -/* rfc5961 challenge ack rate limiting */ -int sysctl_tcp_challenge_ack_limit = 1000; - -int sysctl_tcp_stdurg __read_mostly; -int sysctl_tcp_rfc1337 __read_mostly; -int sysctl_tcp_max_orphans __read_mostly = NR_FILE; -int sysctl_tcp_frto __read_mostly = 2; -int sysctl_tcp_min_rtt_wlen __read_mostly = 300; - -int sysctl_tcp_thin_dupack __read_mostly; - -int sysctl_tcp_moderate_rcvbuf __read_mostly = 1; -int sysctl_tcp_early_retrans __read_mostly = 3; -int sysctl_tcp_invalid_ratelimit __read_mostly = HZ/2; - -#define FLAG_DATA 0x01 /* Incoming frame contained data. */ -#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */ -#define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */ -#define FLAG_RETRANS_DATA_ACKED 0x08 /* "" "" some of which was retransmitted. */ -#define FLAG_SYN_ACKED 0x10 /* This ACK acknowledged SYN. */ -#define FLAG_DATA_SACKED 0x20 /* New SACK. */ -#define FLAG_ECE 0x40 /* ECE in this ACK */ -#define FLAG_LOST_RETRANS 0x80 /* This ACK marks some retransmission lost */ -#define FLAG_SLOWPATH 0x100 /* Do not skip RFC checks for window update.*/ -#define FLAG_ORIG_SACK_ACKED 0x200 /* Never retransmitted data are (s)acked */ -#define FLAG_SND_UNA_ADVANCED 0x400 /* Snd_una was changed (!= FLAG_DATA_ACKED) */ -#define FLAG_DSACKING_ACK 0x800 /* SACK blocks contained D-SACK info */ -#define FLAG_SACK_RENEGING 0x2000 /* snd_una advanced to a sacked seq */ -#define FLAG_UPDATE_TS_RECENT 0x4000 /* tcp_replace_ts_recent() */ - -#define FLAG_ACKED (FLAG_DATA_ACKED|FLAG_SYN_ACKED) -#define FLAG_NOT_DUP (FLAG_DATA|FLAG_WIN_UPDATE|FLAG_ACKED) -#define FLAG_CA_ALERT (FLAG_DATA_SACKED|FLAG_ECE) -#define FLAG_FORWARD_PROGRESS (FLAG_ACKED|FLAG_DATA_SACKED) - -#define TCP_REMNANT (TCP_FLAG_FIN|TCP_FLAG_URG|TCP_FLAG_SYN|TCP_FLAG_PSH) -#define TCP_HP_BITS (~(TCP_RESERVED_BITS|TCP_FLAG_PSH)) - -#define REXMIT_NONE 0 /* no loss recovery to do */ -#define REXMIT_LOST 1 /* retransmit packets marked lost */ -#define REXMIT_NEW 2 /* FRTO-style transmit of unsent/new packets */ - -static void tcp_gro_dev_warn(struct sock *sk, const struct sk_buff *skb) -{ - static bool __once __read_mostly; - - if (!__once) { - struct net_device *dev; - - __once = true; - - rcu_read_lock(); - dev = dev_get_by_index_rcu(sock_net(sk), skb->skb_iif); - pr_warn("%s: Driver has suspect GRO implementation, TCP performance may be compromised.\n", - dev ? dev->name : "Unknown driver"); - rcu_read_unlock(); - } -} - -/* Adapt the MSS value used to make delayed ack decision to the - * real world. - */ -static void tcp_measure_rcv_mss(struct sock *sk, const struct sk_buff *skb) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - const unsigned int lss = icsk->icsk_ack.last_seg_size; - unsigned int len; - - icsk->icsk_ack.last_seg_size = 0; - - /* skb->len may jitter because of SACKs, even if peer - * sends good full-sized frames. - */ - len = skb_shinfo(skb)->gso_size ? : skb->len; - if (len >= icsk->icsk_ack.rcv_mss) { - icsk->icsk_ack.rcv_mss = min_t(unsigned int, len, - tcp_sk(sk)->advmss); - if (unlikely(icsk->icsk_ack.rcv_mss != len)) - tcp_gro_dev_warn(sk, skb); - } else { - /* Otherwise, we make more careful check taking into account, - * that SACKs block is variable. - * - * "len" is invariant segment length, including TCP header. - */ - len += skb->data - skb_transport_header(skb); - if (len >= TCP_MSS_DEFAULT + sizeof(struct tcphdr) || - /* If PSH is not set, packet should be - * full sized, provided peer TCP is not badly broken. - * This observation (if it is correct 8)) allows - * to handle super-low mtu links fairly. - */ - (len >= TCP_MIN_MSS + sizeof(struct tcphdr) && - !(tcp_flag_word(tcp_hdr(skb)) & TCP_REMNANT))) { - /* Subtract also invariant (if peer is RFC compliant), - * tcp header plus fixed timestamp option length. - * Resulting "len" is MSS free of SACK jitter. - */ - len -= tcp_sk(sk)->tcp_header_len; - icsk->icsk_ack.last_seg_size = len; - if (len == lss) { - icsk->icsk_ack.rcv_mss = len; - return; - } - } - if (icsk->icsk_ack.pending & ICSK_ACK_PUSHED) - icsk->icsk_ack.pending |= ICSK_ACK_PUSHED2; - icsk->icsk_ack.pending |= ICSK_ACK_PUSHED; - } -} - -static void tcp_incr_quickack(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - unsigned int quickacks = tcp_sk(sk)->rcv_wnd / (2 * icsk->icsk_ack.rcv_mss); - - if (quickacks == 0) - quickacks = 2; - if (quickacks > icsk->icsk_ack.quick) - icsk->icsk_ack.quick = min(quickacks, TCP_MAX_QUICKACKS); -} - -static void tcp_enter_quickack_mode(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - tcp_incr_quickack(sk); - icsk->icsk_ack.pingpong = 0; - icsk->icsk_ack.ato = TCP_ATO_MIN; -} - -/* Send ACKs quickly, if "quick" count is not exhausted - * and the session is not interactive. - */ - -static bool tcp_in_quickack_mode(struct sock *sk) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - const struct dst_entry *dst = __sk_dst_get(sk); - - return (dst && dst_metric(dst, RTAX_QUICKACK)) || - (icsk->icsk_ack.quick && !icsk->icsk_ack.pingpong); -} - -static void tcp_ecn_queue_cwr(struct tcp_sock *tp) -{ - if (tp->ecn_flags & TCP_ECN_OK) - tp->ecn_flags |= TCP_ECN_QUEUE_CWR; -} - -static void tcp_ecn_accept_cwr(struct tcp_sock *tp, const struct sk_buff *skb) -{ - if (tcp_hdr(skb)->cwr) - tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; -} - -static void tcp_ecn_withdraw_cwr(struct tcp_sock *tp) -{ - tp->ecn_flags &= ~TCP_ECN_DEMAND_CWR; -} - -static void __tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) -{ - switch (TCP_SKB_CB(skb)->ip_dsfield & INET_ECN_MASK) { - case INET_ECN_NOT_ECT: - /* Funny extension: if ECT is not set on a segment, - * and we already seen ECT on a previous segment, - * it is probably a retransmit. - */ - if (tp->ecn_flags & TCP_ECN_SEEN) - tcp_enter_quickack_mode((struct sock *)tp); - break; - case INET_ECN_CE: - if (tcp_ca_needs_ecn((struct sock *)tp)) - tcp_ca_event((struct sock *)tp, CA_EVENT_ECN_IS_CE); - - if (!(tp->ecn_flags & TCP_ECN_DEMAND_CWR)) { - /* Better not delay acks, sender can have a very low cwnd */ - tcp_enter_quickack_mode((struct sock *)tp); - tp->ecn_flags |= TCP_ECN_DEMAND_CWR; - } - tp->ecn_flags |= TCP_ECN_SEEN; - break; - default: - if (tcp_ca_needs_ecn((struct sock *)tp)) - tcp_ca_event((struct sock *)tp, CA_EVENT_ECN_NO_CE); - tp->ecn_flags |= TCP_ECN_SEEN; - break; - } -} - -static void tcp_ecn_check_ce(struct tcp_sock *tp, const struct sk_buff *skb) -{ - if (tp->ecn_flags & TCP_ECN_OK) - __tcp_ecn_check_ce(tp, skb); -} - -static void tcp_ecn_rcv_synack(struct tcp_sock *tp, const struct tcphdr *th) -{ - if ((tp->ecn_flags & TCP_ECN_OK) && (!th->ece || th->cwr)) - tp->ecn_flags &= ~TCP_ECN_OK; -} - -static void tcp_ecn_rcv_syn(struct tcp_sock *tp, const struct tcphdr *th) -{ - if ((tp->ecn_flags & TCP_ECN_OK) && (!th->ece || !th->cwr)) - tp->ecn_flags &= ~TCP_ECN_OK; -} - -static bool tcp_ecn_rcv_ecn_echo(const struct tcp_sock *tp, const struct tcphdr *th) -{ - if (th->ece && !th->syn && (tp->ecn_flags & TCP_ECN_OK)) - return true; - return false; -} - -/* Buffer size and advertised window tuning. - * - * 1. Tuning sk->sk_sndbuf, when connection enters established state. - */ - -static void tcp_sndbuf_expand(struct sock *sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; - int sndmem, per_mss; - u32 nr_segs; - - /* Worst case is non GSO/TSO : each frame consumes one skb - * and skb->head is kmalloced using power of two area of memory - */ - per_mss = max_t(u32, tp->rx_opt.mss_clamp, tp->mss_cache) + - MAX_TCP_HEADER + - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); - - per_mss = roundup_pow_of_two(per_mss) + - SKB_DATA_ALIGN(sizeof(struct sk_buff)); - - nr_segs = max_t(u32, TCP_INIT_CWND, tp->snd_cwnd); - nr_segs = max_t(u32, nr_segs, tp->reordering + 1); - - /* Fast Recovery (RFC 5681 3.2) : - * Cubic needs 1.7 factor, rounded to 2 to include - * extra cushion (application might react slowly to POLLOUT) - */ - sndmem = ca_ops->sndbuf_expand ? ca_ops->sndbuf_expand(sk) : 2; - sndmem *= nr_segs * per_mss; - - if (sk->sk_sndbuf < sndmem) - sk->sk_sndbuf = min(sndmem, sysctl_tcp_wmem[2]); -} - -/* 2. Tuning advertised window (window_clamp, rcv_ssthresh) - * - * All tcp_full_space() is split to two parts: "network" buffer, allocated - * forward and advertised in receiver window (tp->rcv_wnd) and - * "application buffer", required to isolate scheduling/application - * latencies from network. - * window_clamp is maximal advertised window. It can be less than - * tcp_full_space(), in this case tcp_full_space() - window_clamp - * is reserved for "application" buffer. The less window_clamp is - * the smoother our behaviour from viewpoint of network, but the lower - * throughput and the higher sensitivity of the connection to losses. 8) - * - * rcv_ssthresh is more strict window_clamp used at "slow start" - * phase to predict further behaviour of this connection. - * It is used for two goals: - * - to enforce header prediction at sender, even when application - * requires some significant "application buffer". It is check #1. - * - to prevent pruning of receive queue because of misprediction - * of receiver window. Check #2. - * - * The scheme does not work when sender sends good segments opening - * window and then starts to feed us spaghetti. But it should work - * in common situations. Otherwise, we have to rely on queue collapsing. - */ - -/* Slow part of check#2. */ -static int __tcp_grow_window(const struct sock *sk, const struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - /* Optimize this! */ - int truesize = tcp_win_from_space(skb->truesize) >> 1; - int window = tcp_win_from_space(sysctl_tcp_rmem[2]) >> 1; - - while (tp->rcv_ssthresh <= window) { - if (truesize <= skb->len) - return 2 * inet_csk(sk)->icsk_ack.rcv_mss; - - truesize >>= 1; - window >>= 1; - } - return 0; -} - -static void tcp_grow_window(struct sock *sk, const struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - - /* Check #1 */ - if (tp->rcv_ssthresh < tp->window_clamp && - (int)tp->rcv_ssthresh < tcp_space(sk) && - !tcp_under_memory_pressure(sk)) { - int incr; - - /* Check #2. Increase window, if skb with such overhead - * will fit to rcvbuf in future. - */ - if (tcp_win_from_space(skb->truesize) <= skb->len) - incr = 2 * tp->advmss; - else - incr = __tcp_grow_window(sk, skb); - - if (incr) { - incr = max_t(int, incr, 2 * skb->len); - tp->rcv_ssthresh = min(tp->rcv_ssthresh + incr, - tp->window_clamp); - inet_csk(sk)->icsk_ack.quick |= 1; - } - } -} - -/* 3. Tuning rcvbuf, when connection enters established state. */ -static void tcp_fixup_rcvbuf(struct sock *sk) -{ - u32 mss = tcp_sk(sk)->advmss; - int rcvmem; - - rcvmem = 2 * SKB_TRUESIZE(mss + MAX_TCP_HEADER) * - tcp_default_init_rwnd(mss); - - /* Dynamic Right Sizing (DRS) has 2 to 3 RTT latency - * Allow enough cushion so that sender is not limited by our window - */ - if (sysctl_tcp_moderate_rcvbuf) - rcvmem <<= 2; - - if (sk->sk_rcvbuf < rcvmem) - sk->sk_rcvbuf = min(rcvmem, sysctl_tcp_rmem[2]); -} - -/* 4. Try to fixup all. It is made immediately after connection enters - * established state. - */ -void tcp_init_buffer_space(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - int maxwin; - - if (!(sk->sk_userlocks & SOCK_RCVBUF_LOCK)) - tcp_fixup_rcvbuf(sk); - if (!(sk->sk_userlocks & SOCK_SNDBUF_LOCK)) - tcp_sndbuf_expand(sk); - - tp->rcvq_space.space = tp->rcv_wnd; - tp->rcvq_space.time = tcp_time_stamp; - tp->rcvq_space.seq = tp->copied_seq; - - maxwin = tcp_full_space(sk); - - if (tp->window_clamp >= maxwin) { - tp->window_clamp = maxwin; - - if (sysctl_tcp_app_win && maxwin > 4 * tp->advmss) - tp->window_clamp = max(maxwin - - (maxwin >> sysctl_tcp_app_win), - 4 * tp->advmss); - } - - /* Force reservation of one segment. */ - if (sysctl_tcp_app_win && - tp->window_clamp > 2 * tp->advmss && - tp->window_clamp + tp->advmss > maxwin) - tp->window_clamp = max(2 * tp->advmss, maxwin - tp->advmss); - - tp->rcv_ssthresh = min(tp->rcv_ssthresh, tp->window_clamp); - tp->snd_cwnd_stamp = tcp_time_stamp; -} - -/* 5. Recalculate window clamp after socket hit its memory bounds. */ -static void tcp_clamp_window(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct inet_connection_sock *icsk = inet_csk(sk); - - icsk->icsk_ack.quick = 0; - - if (sk->sk_rcvbuf < sysctl_tcp_rmem[2] && - !(sk->sk_userlocks & SOCK_RCVBUF_LOCK) && - !tcp_under_memory_pressure(sk) && - sk_memory_allocated(sk) < sk_prot_mem_limits(sk, 0)) { - sk->sk_rcvbuf = min(atomic_read(&sk->sk_rmem_alloc), - sysctl_tcp_rmem[2]); - } - if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf) - tp->rcv_ssthresh = min(tp->window_clamp, 2U * tp->advmss); -} - -/* Initialize RCV_MSS value. - * RCV_MSS is an our guess about MSS used by the peer. - * We haven't any direct information about the MSS. - * It's better to underestimate the RCV_MSS rather than overestimate. - * Overestimations make us ACKing less frequently than needed. - * Underestimations are more easy to detect and fix by tcp_measure_rcv_mss(). - */ -void tcp_initialize_rcv_mss(struct sock *sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - unsigned int hint = min_t(unsigned int, tp->advmss, tp->mss_cache); - - hint = min(hint, tp->rcv_wnd / 2); - hint = min(hint, TCP_MSS_DEFAULT); - hint = max(hint, TCP_MIN_MSS); - - inet_csk(sk)->icsk_ack.rcv_mss = hint; -} -EXPORT_SYMBOL(tcp_initialize_rcv_mss); - -/* Receiver "autotuning" code. - * - * The algorithm for RTT estimation w/o timestamps is based on - * Dynamic Right-Sizing (DRS) by Wu Feng and Mike Fisk of LANL. - * - * - * More detail on this code can be found at - * , - * though this reference is out of date. A new paper - * is pending. - */ -static void tcp_rcv_rtt_update(struct tcp_sock *tp, u32 sample, int win_dep) -{ - u32 new_sample = tp->rcv_rtt_est.rtt; - long m = sample; - - if (m == 0) - m = 1; - - if (new_sample != 0) { - /* If we sample in larger samples in the non-timestamp - * case, we could grossly overestimate the RTT especially - * with chatty applications or bulk transfer apps which - * are stalled on filesystem I/O. - * - * Also, since we are only going for a minimum in the - * non-timestamp case, we do not smooth things out - * else with timestamps disabled convergence takes too - * long. - */ - if (!win_dep) { - m -= (new_sample >> 3); - new_sample += m; - } else { - m <<= 3; - if (m < new_sample) - new_sample = m; - } - } else { - /* No previous measure. */ - new_sample = m << 3; - } - - if (tp->rcv_rtt_est.rtt != new_sample) - tp->rcv_rtt_est.rtt = new_sample; -} - -static inline void tcp_rcv_rtt_measure(struct tcp_sock *tp) -{ - if (tp->rcv_rtt_est.time == 0) - goto new_measure; - if (before(tp->rcv_nxt, tp->rcv_rtt_est.seq)) - return; - tcp_rcv_rtt_update(tp, tcp_time_stamp - tp->rcv_rtt_est.time, 1); - -new_measure: - tp->rcv_rtt_est.seq = tp->rcv_nxt + tp->rcv_wnd; - tp->rcv_rtt_est.time = tcp_time_stamp; -} - -static inline void tcp_rcv_rtt_measure_ts(struct sock *sk, - const struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - if (tp->rx_opt.rcv_tsecr && - (TCP_SKB_CB(skb)->end_seq - - TCP_SKB_CB(skb)->seq >= inet_csk(sk)->icsk_ack.rcv_mss)) - tcp_rcv_rtt_update(tp, tcp_time_stamp - tp->rx_opt.rcv_tsecr, 0); -} - -/* - * This function should be called every time data is copied to user space. - * It calculates the appropriate TCP receive buffer space. - */ -void tcp_rcv_space_adjust(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - int time; - int copied; - - time = tcp_time_stamp - tp->rcvq_space.time; - if (time < (tp->rcv_rtt_est.rtt >> 3) || tp->rcv_rtt_est.rtt == 0) - return; - - /* Number of bytes copied to user in last RTT */ - copied = tp->copied_seq - tp->rcvq_space.seq; - if (copied <= tp->rcvq_space.space) - goto new_measure; - - /* A bit of theory : - * copied = bytes received in previous RTT, our base window - * To cope with packet losses, we need a 2x factor - * To cope with slow start, and sender growing its cwin by 100 % - * every RTT, we need a 4x factor, because the ACK we are sending - * now is for the next RTT, not the current one : - * - */ - - if (sysctl_tcp_moderate_rcvbuf && - !(sk->sk_userlocks & SOCK_RCVBUF_LOCK)) { - int rcvwin, rcvmem, rcvbuf; - - /* minimal window to cope with packet losses, assuming - * steady state. Add some cushion because of small variations. - */ - rcvwin = (copied << 1) + 16 * tp->advmss; - - /* If rate increased by 25%, - * assume slow start, rcvwin = 3 * copied - * If rate increased by 50%, - * assume sender can use 2x growth, rcvwin = 4 * copied - */ - if (copied >= - tp->rcvq_space.space + (tp->rcvq_space.space >> 2)) { - if (copied >= - tp->rcvq_space.space + (tp->rcvq_space.space >> 1)) - rcvwin <<= 1; - else - rcvwin += (rcvwin >> 1); - } - - rcvmem = SKB_TRUESIZE(tp->advmss + MAX_TCP_HEADER); - while (tcp_win_from_space(rcvmem) < tp->advmss) - rcvmem += 128; - - rcvbuf = min(rcvwin / tp->advmss * rcvmem, sysctl_tcp_rmem[2]); - if (rcvbuf > sk->sk_rcvbuf) { - sk->sk_rcvbuf = rcvbuf; - - /* Make the window clamp follow along. */ - tp->window_clamp = rcvwin; - } - } - tp->rcvq_space.space = copied; - -new_measure: - tp->rcvq_space.seq = tp->copied_seq; - tp->rcvq_space.time = tcp_time_stamp; -} - -/* There is something which you must keep in mind when you analyze the - * behavior of the tp->ato delayed ack timeout interval. When a - * connection starts up, we want to ack as quickly as possible. The - * problem is that "good" TCP's do slow start at the beginning of data - * transmission. The means that until we send the first few ACK's the - * sender will sit on his end and only queue most of his data, because - * he can only send snd_cwnd unacked packets at any given time. For - * each ACK we send, he increments snd_cwnd and transmits more of his - * queue. -DaveM - */ -static void tcp_event_data_recv(struct sock *sk, struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct inet_connection_sock *icsk = inet_csk(sk); - u32 now; - - inet_csk_schedule_ack(sk); - - tcp_measure_rcv_mss(sk, skb); - - tcp_rcv_rtt_measure(tp); - - now = tcp_time_stamp; - - if (!icsk->icsk_ack.ato) { - /* The _first_ data packet received, initialize - * delayed ACK engine. - */ - tcp_incr_quickack(sk); - icsk->icsk_ack.ato = TCP_ATO_MIN; - } else { - int m = now - icsk->icsk_ack.lrcvtime; - - if (m <= TCP_ATO_MIN / 2) { - /* The fastest case is the first. */ - icsk->icsk_ack.ato = (icsk->icsk_ack.ato >> 1) + TCP_ATO_MIN / 2; - } else if (m < icsk->icsk_ack.ato) { - icsk->icsk_ack.ato = (icsk->icsk_ack.ato >> 1) + m; - if (icsk->icsk_ack.ato > icsk->icsk_rto) - icsk->icsk_ack.ato = icsk->icsk_rto; - } else if (m > icsk->icsk_rto) { - /* Too long gap. Apparently sender failed to - * restart window, so that we send ACKs quickly. - */ - tcp_incr_quickack(sk); - sk_mem_reclaim(sk); - } - } - icsk->icsk_ack.lrcvtime = now; - - tcp_ecn_check_ce(tp, skb); - - if (skb->len >= 128) - tcp_grow_window(sk, skb); -} - -/* Called to compute a smoothed rtt estimate. The data fed to this - * routine either comes from timestamps, or from segments that were - * known _not_ to have been retransmitted [see Karn/Partridge - * Proceedings SIGCOMM 87]. The algorithm is from the SIGCOMM 88 - * piece by Van Jacobson. - * NOTE: the next three routines used to be one big routine. - * To save cycles in the RFC 1323 implementation it was better to break - * it up into three procedures. -- erics - */ -static void tcp_rtt_estimator(struct sock *sk, long mrtt_us) -{ - struct tcp_sock *tp = tcp_sk(sk); - long m = mrtt_us; /* RTT */ - u32 srtt = tp->srtt_us; - - /* The following amusing code comes from Jacobson's - * article in SIGCOMM '88. Note that rtt and mdev - * are scaled versions of rtt and mean deviation. - * This is designed to be as fast as possible - * m stands for "measurement". - * - * On a 1990 paper the rto value is changed to: - * RTO = rtt + 4 * mdev - * - * Funny. This algorithm seems to be very broken. - * These formulae increase RTO, when it should be decreased, increase - * too slowly, when it should be increased quickly, decrease too quickly - * etc. I guess in BSD RTO takes ONE value, so that it is absolutely - * does not matter how to _calculate_ it. Seems, it was trap - * that VJ failed to avoid. 8) - */ - if (srtt != 0) { - m -= (srtt >> 3); /* m is now error in rtt est */ - srtt += m; /* rtt = 7/8 rtt + 1/8 new */ - if (m < 0) { - m = -m; /* m is now abs(error) */ - m -= (tp->mdev_us >> 2); /* similar update on mdev */ - /* This is similar to one of Eifel findings. - * Eifel blocks mdev updates when rtt decreases. - * This solution is a bit different: we use finer gain - * for mdev in this case (alpha*beta). - * Like Eifel it also prevents growth of rto, - * but also it limits too fast rto decreases, - * happening in pure Eifel. - */ - if (m > 0) - m >>= 3; - } else { - m -= (tp->mdev_us >> 2); /* similar update on mdev */ - } - tp->mdev_us += m; /* mdev = 3/4 mdev + 1/4 new */ - if (tp->mdev_us > tp->mdev_max_us) { - tp->mdev_max_us = tp->mdev_us; - if (tp->mdev_max_us > tp->rttvar_us) - tp->rttvar_us = tp->mdev_max_us; - } - if (after(tp->snd_una, tp->rtt_seq)) { - if (tp->mdev_max_us < tp->rttvar_us) - tp->rttvar_us -= (tp->rttvar_us - tp->mdev_max_us) >> 2; - tp->rtt_seq = tp->snd_nxt; - tp->mdev_max_us = tcp_rto_min_us(sk); - } - } else { - /* no previous measure. */ - srtt = m << 3; /* take the measured time to be rtt */ - tp->mdev_us = m << 1; /* make sure rto = 3*rtt */ - tp->rttvar_us = max(tp->mdev_us, tcp_rto_min_us(sk)); - tp->mdev_max_us = tp->rttvar_us; - tp->rtt_seq = tp->snd_nxt; - } - tp->srtt_us = max(1U, srtt); -} - -/* Set the sk_pacing_rate to allow proper sizing of TSO packets. - * Note: TCP stack does not yet implement pacing. - * FQ packet scheduler can be used to implement cheap but effective - * TCP pacing, to smooth the burst on large writes when packets - * in flight is significantly lower than cwnd (or rwin) - */ -int sysctl_tcp_pacing_ss_ratio __read_mostly = 200; -int sysctl_tcp_pacing_ca_ratio __read_mostly = 120; - -static void tcp_update_pacing_rate(struct sock *sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - u64 rate; - - /* set sk_pacing_rate to 200 % of current rate (mss * cwnd / srtt) */ - rate = (u64)tp->mss_cache * ((USEC_PER_SEC / 100) << 3); - - /* current rate is (cwnd * mss) / srtt - * In Slow Start [1], set sk_pacing_rate to 200 % the current rate. - * In Congestion Avoidance phase, set it to 120 % the current rate. - * - * [1] : Normal Slow Start condition is (tp->snd_cwnd < tp->snd_ssthresh) - * If snd_cwnd >= (tp->snd_ssthresh / 2), we are approaching - * end of slow start and should slow down. - */ - if (tp->snd_cwnd < tp->snd_ssthresh / 2) - rate *= sysctl_tcp_pacing_ss_ratio; - else - rate *= sysctl_tcp_pacing_ca_ratio; - - rate *= max(tp->snd_cwnd, tp->packets_out); - - if (likely(tp->srtt_us)) - do_div(rate, tp->srtt_us); - - /* ACCESS_ONCE() is needed because sch_fq fetches sk_pacing_rate - * without any lock. We want to make sure compiler wont store - * intermediate values in this location. - */ - ACCESS_ONCE(sk->sk_pacing_rate) = min_t(u64, rate, - sk->sk_max_pacing_rate); -} - -/* Calculate rto without backoff. This is the second half of Van Jacobson's - * routine referred to above. - */ -static void tcp_set_rto(struct sock *sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - /* Old crap is replaced with new one. 8) - * - * More seriously: - * 1. If rtt variance happened to be less 50msec, it is hallucination. - * It cannot be less due to utterly erratic ACK generation made - * at least by solaris and freebsd. "Erratic ACKs" has _nothing_ - * to do with delayed acks, because at cwnd>2 true delack timeout - * is invisible. Actually, Linux-2.4 also generates erratic - * ACKs in some circumstances. - */ - inet_csk(sk)->icsk_rto = __tcp_set_rto(tp); - - /* 2. Fixups made earlier cannot be right. - * If we do not estimate RTO correctly without them, - * all the algo is pure shit and should be replaced - * with correct one. It is exactly, which we pretend to do. - */ - - /* NOTE: clamping at TCP_RTO_MIN is not required, current algo - * guarantees that rto is higher. - */ - tcp_bound_rto(sk); -} - -__u32 tcp_init_cwnd(const struct tcp_sock *tp, const struct dst_entry *dst) -{ - __u32 cwnd = (dst ? dst_metric(dst, RTAX_INITCWND) : 0); - - if (!cwnd) - cwnd = TCP_INIT_CWND; - return min_t(__u32, cwnd, tp->snd_cwnd_clamp); -} - -/* - * Packet counting of FACK is based on in-order assumptions, therefore TCP - * disables it when reordering is detected - */ -void tcp_disable_fack(struct tcp_sock *tp) -{ - /* RFC3517 uses different metric in lost marker => reset on change */ - if (tcp_is_fack(tp)) - tp->lost_skb_hint = NULL; - tp->rx_opt.sack_ok &= ~TCP_FACK_ENABLED; -} - -/* Take a notice that peer is sending D-SACKs */ -static void tcp_dsack_seen(struct tcp_sock *tp) -{ - tp->rx_opt.sack_ok |= TCP_DSACK_SEEN; -} - -static void tcp_update_reordering(struct sock *sk, const int metric, - const int ts) -{ - struct tcp_sock *tp = tcp_sk(sk); - if (metric > tp->reordering) { - int mib_idx; - - tp->reordering = min(sysctl_tcp_max_reordering, metric); - - /* This exciting event is worth to be remembered. 8) */ - if (ts) - mib_idx = LINUX_MIB_TCPTSREORDER; - else if (tcp_is_reno(tp)) - mib_idx = LINUX_MIB_TCPRENOREORDER; - else if (tcp_is_fack(tp)) - mib_idx = LINUX_MIB_TCPFACKREORDER; - else - mib_idx = LINUX_MIB_TCPSACKREORDER; - - NET_INC_STATS(sock_net(sk), mib_idx); -#if FASTRETRANS_DEBUG > 1 - pr_debug("Disorder%d %d %u f%u s%u rr%d\n", - tp->rx_opt.sack_ok, inet_csk(sk)->icsk_ca_state, - tp->reordering, - tp->fackets_out, - tp->sacked_out, - tp->undo_marker ? tp->undo_retrans : 0); -#endif - tcp_disable_fack(tp); - } - - if (metric > 0) - tcp_disable_early_retrans(tp); - tp->rack.reord = 1; -} - -/* This must be called before lost_out is incremented */ -static void tcp_verify_retransmit_hint(struct tcp_sock *tp, struct sk_buff *skb) -{ - if (!tp->retransmit_skb_hint || - before(TCP_SKB_CB(skb)->seq, - TCP_SKB_CB(tp->retransmit_skb_hint)->seq)) - tp->retransmit_skb_hint = skb; - - if (!tp->lost_out || - after(TCP_SKB_CB(skb)->end_seq, tp->retransmit_high)) - tp->retransmit_high = TCP_SKB_CB(skb)->end_seq; -} - -/* Sum the number of packets on the wire we have marked as lost. - * There are two cases we care about here: - * a) Packet hasn't been marked lost (nor retransmitted), - * and this is the first loss. - * b) Packet has been marked both lost and retransmitted, - * and this means we think it was lost again. - */ -static void tcp_sum_lost(struct tcp_sock *tp, struct sk_buff *skb) -{ - __u8 sacked = TCP_SKB_CB(skb)->sacked; - - if (!(sacked & TCPCB_LOST) || - ((sacked & TCPCB_LOST) && (sacked & TCPCB_SACKED_RETRANS))) - tp->lost += tcp_skb_pcount(skb); -} - -static void tcp_skb_mark_lost(struct tcp_sock *tp, struct sk_buff *skb) -{ - if (!(TCP_SKB_CB(skb)->sacked & (TCPCB_LOST|TCPCB_SACKED_ACKED))) { - tcp_verify_retransmit_hint(tp, skb); - - tp->lost_out += tcp_skb_pcount(skb); - tcp_sum_lost(tp, skb); - TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; - } -} - -void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp, struct sk_buff *skb) -{ - tcp_verify_retransmit_hint(tp, skb); - - tcp_sum_lost(tp, skb); - if (!(TCP_SKB_CB(skb)->sacked & (TCPCB_LOST|TCPCB_SACKED_ACKED))) { - tp->lost_out += tcp_skb_pcount(skb); - TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; - } -} - -/* This procedure tags the retransmission queue when SACKs arrive. - * - * We have three tag bits: SACKED(S), RETRANS(R) and LOST(L). - * Packets in queue with these bits set are counted in variables - * sacked_out, retrans_out and lost_out, correspondingly. - * - * Valid combinations are: - * Tag InFlight Description - * 0 1 - orig segment is in flight. - * S 0 - nothing flies, orig reached receiver. - * L 0 - nothing flies, orig lost by net. - * R 2 - both orig and retransmit are in flight. - * L|R 1 - orig is lost, retransmit is in flight. - * S|R 1 - orig reached receiver, retrans is still in flight. - * (L|S|R is logically valid, it could occur when L|R is sacked, - * but it is equivalent to plain S and code short-curcuits it to S. - * L|S is logically invalid, it would mean -1 packet in flight 8)) - * - * These 6 states form finite state machine, controlled by the following events: - * 1. New ACK (+SACK) arrives. (tcp_sacktag_write_queue()) - * 2. Retransmission. (tcp_retransmit_skb(), tcp_xmit_retransmit_queue()) - * 3. Loss detection event of two flavors: - * A. Scoreboard estimator decided the packet is lost. - * A'. Reno "three dupacks" marks head of queue lost. - * A''. Its FACK modification, head until snd.fack is lost. - * B. SACK arrives sacking SND.NXT at the moment, when the - * segment was retransmitted. - * 4. D-SACK added new rule: D-SACK changes any tag to S. - * - * It is pleasant to note, that state diagram turns out to be commutative, - * so that we are allowed not to be bothered by order of our actions, - * when multiple events arrive simultaneously. (see the function below). - * - * Reordering detection. - * -------------------- - * Reordering metric is maximal distance, which a packet can be displaced - * in packet stream. With SACKs we can estimate it: - * - * 1. SACK fills old hole and the corresponding segment was not - * ever retransmitted -> reordering. Alas, we cannot use it - * when segment was retransmitted. - * 2. The last flaw is solved with D-SACK. D-SACK arrives - * for retransmitted and already SACKed segment -> reordering.. - * Both of these heuristics are not used in Loss state, when we cannot - * account for retransmits accurately. - * - * SACK block validation. - * ---------------------- - * - * SACK block range validation checks that the received SACK block fits to - * the expected sequence limits, i.e., it is between SND.UNA and SND.NXT. - * Note that SND.UNA is not included to the range though being valid because - * it means that the receiver is rather inconsistent with itself reporting - * SACK reneging when it should advance SND.UNA. Such SACK block this is - * perfectly valid, however, in light of RFC2018 which explicitly states - * that "SACK block MUST reflect the newest segment. Even if the newest - * segment is going to be discarded ...", not that it looks very clever - * in case of head skb. Due to potentional receiver driven attacks, we - * choose to avoid immediate execution of a walk in write queue due to - * reneging and defer head skb's loss recovery to standard loss recovery - * procedure that will eventually trigger (nothing forbids us doing this). - * - * Implements also blockage to start_seq wrap-around. Problem lies in the - * fact that though start_seq (s) is before end_seq (i.e., not reversed), - * there's no guarantee that it will be before snd_nxt (n). The problem - * happens when start_seq resides between end_seq wrap (e_w) and snd_nxt - * wrap (s_w): - * - * <- outs wnd -> <- wrapzone -> - * u e n u_w e_w s n_w - * | | | | | | | - * |<------------+------+----- TCP seqno space --------------+---------->| - * ...-- <2^31 ->| |<--------... - * ...---- >2^31 ------>| |<--------... - * - * Current code wouldn't be vulnerable but it's better still to discard such - * crazy SACK blocks. Doing this check for start_seq alone closes somewhat - * similar case (end_seq after snd_nxt wrap) as earlier reversed check in - * snd_nxt wrap -> snd_una region will then become "well defined", i.e., - * equal to the ideal case (infinite seqno space without wrap caused issues). - * - * With D-SACK the lower bound is extended to cover sequence space below - * SND.UNA down to undo_marker, which is the last point of interest. Yet - * again, D-SACK block must not to go across snd_una (for the same reason as - * for the normal SACK blocks, explained above). But there all simplicity - * ends, TCP might receive valid D-SACKs below that. As long as they reside - * fully below undo_marker they do not affect behavior in anyway and can - * therefore be safely ignored. In rare cases (which are more or less - * theoretical ones), the D-SACK will nicely cross that boundary due to skb - * fragmentation and packet reordering past skb's retransmission. To consider - * them correctly, the acceptable range must be extended even more though - * the exact amount is rather hard to quantify. However, tp->max_window can - * be used as an exaggerated estimate. - */ -static bool tcp_is_sackblock_valid(struct tcp_sock *tp, bool is_dsack, - u32 start_seq, u32 end_seq) -{ - /* Too far in future, or reversed (interpretation is ambiguous) */ - if (after(end_seq, tp->snd_nxt) || !before(start_seq, end_seq)) - return false; - - /* Nasty start_seq wrap-around check (see comments above) */ - if (!before(start_seq, tp->snd_nxt)) - return false; - - /* In outstanding window? ...This is valid exit for D-SACKs too. - * start_seq == snd_una is non-sensical (see comments above) - */ - if (after(start_seq, tp->snd_una)) - return true; - - if (!is_dsack || !tp->undo_marker) - return false; - - /* ...Then it's D-SACK, and must reside below snd_una completely */ - if (after(end_seq, tp->snd_una)) - return false; - - if (!before(start_seq, tp->undo_marker)) - return true; - - /* Too old */ - if (!after(end_seq, tp->undo_marker)) - return false; - - /* Undo_marker boundary crossing (overestimates a lot). Known already: - * start_seq < undo_marker and end_seq >= undo_marker. - */ - return !before(start_seq, end_seq - tp->max_window); -} - -static bool tcp_check_dsack(struct sock *sk, const struct sk_buff *ack_skb, - struct tcp_sack_block_wire *sp, int num_sacks, - u32 prior_snd_una) -{ - struct tcp_sock *tp = tcp_sk(sk); - u32 start_seq_0 = get_unaligned_be32(&sp[0].start_seq); - u32 end_seq_0 = get_unaligned_be32(&sp[0].end_seq); - bool dup_sack = false; - - if (before(start_seq_0, TCP_SKB_CB(ack_skb)->ack_seq)) { - dup_sack = true; - tcp_dsack_seen(tp); - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPDSACKRECV); - } else if (num_sacks > 1) { - u32 end_seq_1 = get_unaligned_be32(&sp[1].end_seq); - u32 start_seq_1 = get_unaligned_be32(&sp[1].start_seq); - - if (!after(end_seq_0, end_seq_1) && - !before(start_seq_0, start_seq_1)) { - dup_sack = true; - tcp_dsack_seen(tp); - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPDSACKOFORECV); - } - } - - /* D-SACK for already forgotten data... Do dumb counting. */ - if (dup_sack && tp->undo_marker && tp->undo_retrans > 0 && - !after(end_seq_0, prior_snd_una) && - after(end_seq_0, tp->undo_marker)) - tp->undo_retrans--; - - return dup_sack; -} - -struct tcp_sacktag_state { - int reord; - int fack_count; - /* Timestamps for earliest and latest never-retransmitted segment - * that was SACKed. RTO needs the earliest RTT to stay conservative, - * but congestion control should still get an accurate delay signal. - */ - struct skb_mstamp first_sackt; - struct skb_mstamp last_sackt; - struct rate_sample *rate; - int flag; -}; - -/* Check if skb is fully within the SACK block. In presence of GSO skbs, - * the incoming SACK may not exactly match but we can find smaller MSS - * aligned portion of it that matches. Therefore we might need to fragment - * which may fail and creates some hassle (caller must handle error case - * returns). - * - * FIXME: this could be merged to shift decision code - */ -static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb, - u32 start_seq, u32 end_seq) -{ - int err; - bool in_sack; - unsigned int pkt_len; - unsigned int mss; - - in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) && - !before(end_seq, TCP_SKB_CB(skb)->end_seq); - - if (tcp_skb_pcount(skb) > 1 && !in_sack && - after(TCP_SKB_CB(skb)->end_seq, start_seq)) { - mss = tcp_skb_mss(skb); - in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq); - - if (!in_sack) { - pkt_len = start_seq - TCP_SKB_CB(skb)->seq; - if (pkt_len < mss) - pkt_len = mss; - } else { - pkt_len = end_seq - TCP_SKB_CB(skb)->seq; - if (pkt_len < mss) - return -EINVAL; - } - - /* Round if necessary so that SACKs cover only full MSSes - * and/or the remaining small portion (if present) - */ - if (pkt_len > mss) { - unsigned int new_len = (pkt_len / mss) * mss; - if (!in_sack && new_len < pkt_len) { - new_len += mss; - if (new_len >= skb->len) - return 0; - } - pkt_len = new_len; - } - err = tcp_fragment(sk, skb, pkt_len, mss, GFP_ATOMIC); - if (err < 0) - return err; - } - - return in_sack; -} - -/* Mark the given newly-SACKed range as such, adjusting counters and hints. */ -static u8 tcp_sacktag_one(struct sock *sk, - struct tcp_sacktag_state *state, u8 sacked, - u32 start_seq, u32 end_seq, - int dup_sack, int pcount, - const struct skb_mstamp *xmit_time) -{ - struct tcp_sock *tp = tcp_sk(sk); - int fack_count = state->fack_count; - - /* Account D-SACK for retransmitted packet. */ - if (dup_sack && (sacked & TCPCB_RETRANS)) { - if (tp->undo_marker && tp->undo_retrans > 0 && - after(end_seq, tp->undo_marker)) - tp->undo_retrans--; - if (sacked & TCPCB_SACKED_ACKED) - state->reord = min(fack_count, state->reord); - } - - /* Nothing to do; acked frame is about to be dropped (was ACKed). */ - if (!after(end_seq, tp->snd_una)) - return sacked; - - if (!(sacked & TCPCB_SACKED_ACKED)) { - tcp_rack_advance(tp, xmit_time, sacked); - - if (sacked & TCPCB_SACKED_RETRANS) { - /* If the segment is not tagged as lost, - * we do not clear RETRANS, believing - * that retransmission is still in flight. - */ - if (sacked & TCPCB_LOST) { - sacked &= ~(TCPCB_LOST|TCPCB_SACKED_RETRANS); - tp->lost_out -= pcount; - tp->retrans_out -= pcount; - } - } else { - if (!(sacked & TCPCB_RETRANS)) { - /* New sack for not retransmitted frame, - * which was in hole. It is reordering. - */ - if (before(start_seq, - tcp_highest_sack_seq(tp))) - state->reord = min(fack_count, - state->reord); - if (!after(end_seq, tp->high_seq)) - state->flag |= FLAG_ORIG_SACK_ACKED; - if (state->first_sackt.v64 == 0) - state->first_sackt = *xmit_time; - state->last_sackt = *xmit_time; - } - - if (sacked & TCPCB_LOST) { - sacked &= ~TCPCB_LOST; - tp->lost_out -= pcount; - } - } - - sacked |= TCPCB_SACKED_ACKED; - state->flag |= FLAG_DATA_SACKED; - tp->sacked_out += pcount; - tp->delivered += pcount; /* Out-of-order packets delivered */ - - fack_count += pcount; - - /* Lost marker hint past SACKed? Tweak RFC3517 cnt */ - if (!tcp_is_fack(tp) && tp->lost_skb_hint && - before(start_seq, TCP_SKB_CB(tp->lost_skb_hint)->seq)) - tp->lost_cnt_hint += pcount; - - if (fack_count > tp->fackets_out) - tp->fackets_out = fack_count; - } - - /* D-SACK. We can detect redundant retransmission in S|R and plain R - * frames and clear it. undo_retrans is decreased above, L|R frames - * are accounted above as well. - */ - if (dup_sack && (sacked & TCPCB_SACKED_RETRANS)) { - sacked &= ~TCPCB_SACKED_RETRANS; - tp->retrans_out -= pcount; - } - - return sacked; -} - -/* Shift newly-SACKed bytes from this skb to the immediately previous - * already-SACKed sk_buff. Mark the newly-SACKed bytes as such. - */ -static bool tcp_shifted_skb(struct sock *sk, struct sk_buff *skb, - struct tcp_sacktag_state *state, - unsigned int pcount, int shifted, int mss, - bool dup_sack) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *prev = tcp_write_queue_prev(sk, skb); - u32 start_seq = TCP_SKB_CB(skb)->seq; /* start of newly-SACKed */ - u32 end_seq = start_seq + shifted; /* end of newly-SACKed */ - - BUG_ON(!pcount); - - /* Adjust counters and hints for the newly sacked sequence - * range but discard the return value since prev is already - * marked. We must tag the range first because the seq - * advancement below implicitly advances - * tcp_highest_sack_seq() when skb is highest_sack. - */ - tcp_sacktag_one(sk, state, TCP_SKB_CB(skb)->sacked, - start_seq, end_seq, dup_sack, pcount, - &skb->skb_mstamp); - tcp_rate_skb_delivered(sk, skb, state->rate); - - if (skb == tp->lost_skb_hint) - tp->lost_cnt_hint += pcount; - - TCP_SKB_CB(prev)->end_seq += shifted; - TCP_SKB_CB(skb)->seq += shifted; - - tcp_skb_pcount_add(prev, pcount); - BUG_ON(tcp_skb_pcount(skb) < pcount); - tcp_skb_pcount_add(skb, -pcount); - - /* When we're adding to gso_segs == 1, gso_size will be zero, - * in theory this shouldn't be necessary but as long as DSACK - * code can come after this skb later on it's better to keep - * setting gso_size to something. - */ - if (!TCP_SKB_CB(prev)->tcp_gso_size) - TCP_SKB_CB(prev)->tcp_gso_size = mss; - - /* CHECKME: To clear or not to clear? Mimics normal skb currently */ - if (tcp_skb_pcount(skb) <= 1) - TCP_SKB_CB(skb)->tcp_gso_size = 0; - - /* Difference in this won't matter, both ACKed by the same cumul. ACK */ - TCP_SKB_CB(prev)->sacked |= (TCP_SKB_CB(skb)->sacked & TCPCB_EVER_RETRANS); - - if (skb->len > 0) { - BUG_ON(!tcp_skb_pcount(skb)); - NET_INC_STATS(sock_net(sk), LINUX_MIB_SACKSHIFTED); - return false; - } - - /* Whole SKB was eaten :-) */ - - if (skb == tp->retransmit_skb_hint) - tp->retransmit_skb_hint = prev; - if (skb == tp->lost_skb_hint) { - tp->lost_skb_hint = prev; - tp->lost_cnt_hint -= tcp_skb_pcount(prev); - } - - TCP_SKB_CB(prev)->tcp_flags |= TCP_SKB_CB(skb)->tcp_flags; - TCP_SKB_CB(prev)->eor = TCP_SKB_CB(skb)->eor; - if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) - TCP_SKB_CB(prev)->end_seq++; - - if (skb == tcp_highest_sack(sk)) - tcp_advance_highest_sack(sk, skb); - - tcp_skb_collapse_tstamp(prev, skb); - if (unlikely(TCP_SKB_CB(prev)->tx.delivered_mstamp.v64)) - TCP_SKB_CB(prev)->tx.delivered_mstamp.v64 = 0; - - tcp_unlink_write_queue(skb, sk); - sk_wmem_free_skb(sk, skb); - - NET_INC_STATS(sock_net(sk), LINUX_MIB_SACKMERGED); - - return true; -} - -/* I wish gso_size would have a bit more sane initialization than - * something-or-zero which complicates things - */ -static int tcp_skb_seglen(const struct sk_buff *skb) -{ - return tcp_skb_pcount(skb) == 1 ? skb->len : tcp_skb_mss(skb); -} - -/* Shifting pages past head area doesn't work */ -static int skb_can_shift(const struct sk_buff *skb) -{ - return !skb_headlen(skb) && skb_is_nonlinear(skb); -} - -/* Try collapsing SACK blocks spanning across multiple skbs to a single - * skb. - */ -static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb, - struct tcp_sacktag_state *state, - u32 start_seq, u32 end_seq, - bool dup_sack) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *prev; - int mss; - int pcount = 0; - int len; - int in_sack; - - if (!sk_can_gso(sk)) - goto fallback; - - /* Normally R but no L won't result in plain S */ - if (!dup_sack && - (TCP_SKB_CB(skb)->sacked & (TCPCB_LOST|TCPCB_SACKED_RETRANS)) == TCPCB_SACKED_RETRANS) - goto fallback; - if (!skb_can_shift(skb)) - goto fallback; - /* This frame is about to be dropped (was ACKed). */ - if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) - goto fallback; - - /* Can only happen with delayed DSACK + discard craziness */ - if (unlikely(skb == tcp_write_queue_head(sk))) - goto fallback; - prev = tcp_write_queue_prev(sk, skb); - - if ((TCP_SKB_CB(prev)->sacked & TCPCB_TAGBITS) != TCPCB_SACKED_ACKED) - goto fallback; - - if (!tcp_skb_can_collapse_to(prev)) - goto fallback; - - in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) && - !before(end_seq, TCP_SKB_CB(skb)->end_seq); - - if (in_sack) { - len = skb->len; - pcount = tcp_skb_pcount(skb); - mss = tcp_skb_seglen(skb); - - /* TODO: Fix DSACKs to not fragment already SACKed and we can - * drop this restriction as unnecessary - */ - if (mss != tcp_skb_seglen(prev)) - goto fallback; - } else { - if (!after(TCP_SKB_CB(skb)->end_seq, start_seq)) - goto noop; - /* CHECKME: This is non-MSS split case only?, this will - * cause skipped skbs due to advancing loop btw, original - * has that feature too - */ - if (tcp_skb_pcount(skb) <= 1) - goto noop; - - in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq); - if (!in_sack) { - /* TODO: head merge to next could be attempted here - * if (!after(TCP_SKB_CB(skb)->end_seq, end_seq)), - * though it might not be worth of the additional hassle - * - * ...we can probably just fallback to what was done - * previously. We could try merging non-SACKed ones - * as well but it probably isn't going to buy off - * because later SACKs might again split them, and - * it would make skb timestamp tracking considerably - * harder problem. - */ - goto fallback; - } - - len = end_seq - TCP_SKB_CB(skb)->seq; - BUG_ON(len < 0); - BUG_ON(len > skb->len); - - /* MSS boundaries should be honoured or else pcount will - * severely break even though it makes things bit trickier. - * Optimize common case to avoid most of the divides - */ - mss = tcp_skb_mss(skb); - - /* TODO: Fix DSACKs to not fragment already SACKed and we can - * drop this restriction as unnecessary - */ - if (mss != tcp_skb_seglen(prev)) - goto fallback; - - if (len == mss) { - pcount = 1; - } else if (len < mss) { - goto noop; - } else { - pcount = len / mss; - len = pcount * mss; - } - } - - /* tcp_sacktag_one() won't SACK-tag ranges below snd_una */ - if (!after(TCP_SKB_CB(skb)->seq + len, tp->snd_una)) - goto fallback; - - if (!skb_shift(prev, skb, len)) - goto fallback; - if (!tcp_shifted_skb(sk, skb, state, pcount, len, mss, dup_sack)) - goto out; - - /* Hole filled allows collapsing with the next as well, this is very - * useful when hole on every nth skb pattern happens - */ - if (prev == tcp_write_queue_tail(sk)) - goto out; - skb = tcp_write_queue_next(sk, prev); - - if (!skb_can_shift(skb) || - (skb == tcp_send_head(sk)) || - ((TCP_SKB_CB(skb)->sacked & TCPCB_TAGBITS) != TCPCB_SACKED_ACKED) || - (mss != tcp_skb_seglen(skb))) - goto out; - - len = skb->len; - if (skb_shift(prev, skb, len)) { - pcount += tcp_skb_pcount(skb); - tcp_shifted_skb(sk, skb, state, tcp_skb_pcount(skb), len, mss, 0); - } - -out: - state->fack_count += pcount; - return prev; - -noop: - return skb; - -fallback: - NET_INC_STATS(sock_net(sk), LINUX_MIB_SACKSHIFTFALLBACK); - return NULL; -} - -static struct sk_buff *tcp_sacktag_walk(struct sk_buff *skb, struct sock *sk, - struct tcp_sack_block *next_dup, - struct tcp_sacktag_state *state, - u32 start_seq, u32 end_seq, - bool dup_sack_in) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *tmp; - - tcp_for_write_queue_from(skb, sk) { - int in_sack = 0; - bool dup_sack = dup_sack_in; - - if (skb == tcp_send_head(sk)) - break; - - /* queue is in-order => we can short-circuit the walk early */ - if (!before(TCP_SKB_CB(skb)->seq, end_seq)) - break; - - if (next_dup && - before(TCP_SKB_CB(skb)->seq, next_dup->end_seq)) { - in_sack = tcp_match_skb_to_sack(sk, skb, - next_dup->start_seq, - next_dup->end_seq); - if (in_sack > 0) - dup_sack = true; - } - - /* skb reference here is a bit tricky to get right, since - * shifting can eat and free both this skb and the next, - * so not even _safe variant of the loop is enough. - */ - if (in_sack <= 0) { - tmp = tcp_shift_skb_data(sk, skb, state, - start_seq, end_seq, dup_sack); - if (tmp) { - if (tmp != skb) { - skb = tmp; - continue; - } - - in_sack = 0; - } else { - in_sack = tcp_match_skb_to_sack(sk, skb, - start_seq, - end_seq); - } - } - - if (unlikely(in_sack < 0)) - break; - - if (in_sack) { - TCP_SKB_CB(skb)->sacked = - tcp_sacktag_one(sk, - state, - TCP_SKB_CB(skb)->sacked, - TCP_SKB_CB(skb)->seq, - TCP_SKB_CB(skb)->end_seq, - dup_sack, - tcp_skb_pcount(skb), - &skb->skb_mstamp); - tcp_rate_skb_delivered(sk, skb, state->rate); - - if (!before(TCP_SKB_CB(skb)->seq, - tcp_highest_sack_seq(tp))) - tcp_advance_highest_sack(sk, skb); - } - - state->fack_count += tcp_skb_pcount(skb); - } - return skb; -} - -/* Avoid all extra work that is being done by sacktag while walking in - * a normal way - */ -static struct sk_buff *tcp_sacktag_skip(struct sk_buff *skb, struct sock *sk, - struct tcp_sacktag_state *state, - u32 skip_to_seq) -{ - tcp_for_write_queue_from(skb, sk) { - if (skb == tcp_send_head(sk)) - break; - - if (after(TCP_SKB_CB(skb)->end_seq, skip_to_seq)) - break; - - state->fack_count += tcp_skb_pcount(skb); - } - return skb; -} - -static struct sk_buff *tcp_maybe_skipping_dsack(struct sk_buff *skb, - struct sock *sk, - struct tcp_sack_block *next_dup, - struct tcp_sacktag_state *state, - u32 skip_to_seq) -{ - if (!next_dup) - return skb; - - if (before(next_dup->start_seq, skip_to_seq)) { - skb = tcp_sacktag_skip(skb, sk, state, next_dup->start_seq); - skb = tcp_sacktag_walk(skb, sk, NULL, state, - next_dup->start_seq, next_dup->end_seq, - 1); - } - - return skb; -} - -static int tcp_sack_cache_ok(const struct tcp_sock *tp, const struct tcp_sack_block *cache) -{ - return cache < tp->recv_sack_cache + ARRAY_SIZE(tp->recv_sack_cache); -} - -static int -tcp_sacktag_write_queue(struct sock *sk, const struct sk_buff *ack_skb, - u32 prior_snd_una, struct tcp_sacktag_state *state) -{ - struct tcp_sock *tp = tcp_sk(sk); - const unsigned char *ptr = (skb_transport_header(ack_skb) + - TCP_SKB_CB(ack_skb)->sacked); - struct tcp_sack_block_wire *sp_wire = (struct tcp_sack_block_wire *)(ptr+2); - struct tcp_sack_block sp[TCP_NUM_SACKS]; - struct tcp_sack_block *cache; - struct sk_buff *skb; - int num_sacks = min(TCP_NUM_SACKS, (ptr[1] - TCPOLEN_SACK_BASE) >> 3); - int used_sacks; - bool found_dup_sack = false; - int i, j; - int first_sack_index; - - state->flag = 0; - state->reord = tp->packets_out; - - if (!tp->sacked_out) { - if (WARN_ON(tp->fackets_out)) - tp->fackets_out = 0; - tcp_highest_sack_reset(sk); - } - - found_dup_sack = tcp_check_dsack(sk, ack_skb, sp_wire, - num_sacks, prior_snd_una); - if (found_dup_sack) { - state->flag |= FLAG_DSACKING_ACK; - tp->delivered++; /* A spurious retransmission is delivered */ - } - - /* Eliminate too old ACKs, but take into - * account more or less fresh ones, they can - * contain valid SACK info. - */ - if (before(TCP_SKB_CB(ack_skb)->ack_seq, prior_snd_una - tp->max_window)) - return 0; - - if (!tp->packets_out) - goto out; - - used_sacks = 0; - first_sack_index = 0; - for (i = 0; i < num_sacks; i++) { - bool dup_sack = !i && found_dup_sack; - - sp[used_sacks].start_seq = get_unaligned_be32(&sp_wire[i].start_seq); - sp[used_sacks].end_seq = get_unaligned_be32(&sp_wire[i].end_seq); - - if (!tcp_is_sackblock_valid(tp, dup_sack, - sp[used_sacks].start_seq, - sp[used_sacks].end_seq)) { - int mib_idx; - - if (dup_sack) { - if (!tp->undo_marker) - mib_idx = LINUX_MIB_TCPDSACKIGNOREDNOUNDO; - else - mib_idx = LINUX_MIB_TCPDSACKIGNOREDOLD; - } else { - /* Don't count olds caused by ACK reordering */ - if ((TCP_SKB_CB(ack_skb)->ack_seq != tp->snd_una) && - !after(sp[used_sacks].end_seq, tp->snd_una)) - continue; - mib_idx = LINUX_MIB_TCPSACKDISCARD; - } - - NET_INC_STATS(sock_net(sk), mib_idx); - if (i == 0) - first_sack_index = -1; - continue; - } - - /* Ignore very old stuff early */ - if (!after(sp[used_sacks].end_seq, prior_snd_una)) - continue; - - used_sacks++; - } - - /* order SACK blocks to allow in order walk of the retrans queue */ - for (i = used_sacks - 1; i > 0; i--) { - for (j = 0; j < i; j++) { - if (after(sp[j].start_seq, sp[j + 1].start_seq)) { - swap(sp[j], sp[j + 1]); - - /* Track where the first SACK block goes to */ - if (j == first_sack_index) - first_sack_index = j + 1; - } - } - } - - skb = tcp_write_queue_head(sk); - state->fack_count = 0; - i = 0; - - if (!tp->sacked_out) { - /* It's already past, so skip checking against it */ - cache = tp->recv_sack_cache + ARRAY_SIZE(tp->recv_sack_cache); - } else { - cache = tp->recv_sack_cache; - /* Skip empty blocks in at head of the cache */ - while (tcp_sack_cache_ok(tp, cache) && !cache->start_seq && - !cache->end_seq) - cache++; - } - - while (i < used_sacks) { - u32 start_seq = sp[i].start_seq; - u32 end_seq = sp[i].end_seq; - bool dup_sack = (found_dup_sack && (i == first_sack_index)); - struct tcp_sack_block *next_dup = NULL; - - if (found_dup_sack && ((i + 1) == first_sack_index)) - next_dup = &sp[i + 1]; - - /* Skip too early cached blocks */ - while (tcp_sack_cache_ok(tp, cache) && - !before(start_seq, cache->end_seq)) - cache++; - - /* Can skip some work by looking recv_sack_cache? */ - if (tcp_sack_cache_ok(tp, cache) && !dup_sack && - after(end_seq, cache->start_seq)) { - - /* Head todo? */ - if (before(start_seq, cache->start_seq)) { - skb = tcp_sacktag_skip(skb, sk, state, - start_seq); - skb = tcp_sacktag_walk(skb, sk, next_dup, - state, - start_seq, - cache->start_seq, - dup_sack); - } - - /* Rest of the block already fully processed? */ - if (!after(end_seq, cache->end_seq)) - goto advance_sp; - - skb = tcp_maybe_skipping_dsack(skb, sk, next_dup, - state, - cache->end_seq); - - /* ...tail remains todo... */ - if (tcp_highest_sack_seq(tp) == cache->end_seq) { - /* ...but better entrypoint exists! */ - skb = tcp_highest_sack(sk); - if (!skb) - break; - state->fack_count = tp->fackets_out; - cache++; - goto walk; - } - - skb = tcp_sacktag_skip(skb, sk, state, cache->end_seq); - /* Check overlap against next cached too (past this one already) */ - cache++; - continue; - } - - if (!before(start_seq, tcp_highest_sack_seq(tp))) { - skb = tcp_highest_sack(sk); - if (!skb) - break; - state->fack_count = tp->fackets_out; - } - skb = tcp_sacktag_skip(skb, sk, state, start_seq); - -walk: - skb = tcp_sacktag_walk(skb, sk, next_dup, state, - start_seq, end_seq, dup_sack); - -advance_sp: - i++; - } - - /* Clear the head of the cache sack blocks so we can skip it next time */ - for (i = 0; i < ARRAY_SIZE(tp->recv_sack_cache) - used_sacks; i++) { - tp->recv_sack_cache[i].start_seq = 0; - tp->recv_sack_cache[i].end_seq = 0; - } - for (j = 0; j < used_sacks; j++) - tp->recv_sack_cache[i++] = sp[j]; - - if ((state->reord < tp->fackets_out) && - ((inet_csk(sk)->icsk_ca_state != TCP_CA_Loss) || tp->undo_marker)) - tcp_update_reordering(sk, tp->fackets_out - state->reord, 0); - - tcp_verify_left_out(tp); -out: - -#if FASTRETRANS_DEBUG > 0 - WARN_ON((int)tp->sacked_out < 0); - WARN_ON((int)tp->lost_out < 0); - WARN_ON((int)tp->retrans_out < 0); - WARN_ON((int)tcp_packets_in_flight(tp) < 0); -#endif - return state->flag; -} - -/* Limits sacked_out so that sum with lost_out isn't ever larger than - * packets_out. Returns false if sacked_out adjustement wasn't necessary. - */ -static bool tcp_limit_reno_sacked(struct tcp_sock *tp) -{ - u32 holes; - - holes = max(tp->lost_out, 1U); - holes = min(holes, tp->packets_out); - - if ((tp->sacked_out + holes) > tp->packets_out) { - tp->sacked_out = tp->packets_out - holes; - return true; - } - return false; -} - -/* If we receive more dupacks than we expected counting segments - * in assumption of absent reordering, interpret this as reordering. - * The only another reason could be bug in receiver TCP. - */ -static void tcp_check_reno_reordering(struct sock *sk, const int addend) -{ - struct tcp_sock *tp = tcp_sk(sk); - if (tcp_limit_reno_sacked(tp)) - tcp_update_reordering(sk, tp->packets_out + addend, 0); -} - -/* Emulate SACKs for SACKless connection: account for a new dupack. */ - -static void tcp_add_reno_sack(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - u32 prior_sacked = tp->sacked_out; - - tp->sacked_out++; - tcp_check_reno_reordering(sk, 0); - if (tp->sacked_out > prior_sacked) - tp->delivered++; /* Some out-of-order packet is delivered */ - tcp_verify_left_out(tp); -} - -/* Account for ACK, ACKing some data in Reno Recovery phase. */ - -static void tcp_remove_reno_sacks(struct sock *sk, int acked) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (acked > 0) { - /* One ACK acked hole. The rest eat duplicate ACKs. */ - tp->delivered += max_t(int, acked - tp->sacked_out, 1); - if (acked - 1 >= tp->sacked_out) - tp->sacked_out = 0; - else - tp->sacked_out -= acked - 1; - } - tcp_check_reno_reordering(sk, acked); - tcp_verify_left_out(tp); -} - -static inline void tcp_reset_reno_sack(struct tcp_sock *tp) -{ - tp->sacked_out = 0; -} - -void tcp_clear_retrans(struct tcp_sock *tp) -{ - tp->retrans_out = 0; - tp->lost_out = 0; - tp->undo_marker = 0; - tp->undo_retrans = -1; - tp->fackets_out = 0; - tp->sacked_out = 0; -} - -static inline void tcp_init_undo(struct tcp_sock *tp) -{ - tp->undo_marker = tp->snd_una; - /* Retransmission still in flight may cause DSACKs later. */ - tp->undo_retrans = tp->retrans_out ? : -1; -} - -/* Enter Loss state. If we detect SACK reneging, forget all SACK information - * and reset tags completely, otherwise preserve SACKs. If receiver - * dropped its ofo queue, we will know this due to reneging detection. - */ -void tcp_enter_loss(struct sock *sk) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - struct net *net = sock_net(sk); - struct sk_buff *skb; - bool new_recovery = icsk->icsk_ca_state < TCP_CA_Recovery; - bool is_reneg; /* is receiver reneging on SACKs? */ - bool mark_lost; - - /* Reduce ssthresh if it has not yet been made inside this window. */ - if (icsk->icsk_ca_state <= TCP_CA_Disorder || - !after(tp->high_seq, tp->snd_una) || - (icsk->icsk_ca_state == TCP_CA_Loss && !icsk->icsk_retransmits)) { - tp->prior_ssthresh = tcp_current_ssthresh(sk); - tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh(sk); - tcp_ca_event(sk, CA_EVENT_LOSS); - tcp_init_undo(tp); - } - tp->snd_cwnd = 1; - tp->snd_cwnd_cnt = 0; - tp->snd_cwnd_stamp = tcp_time_stamp; - - tp->retrans_out = 0; - tp->lost_out = 0; - - if (tcp_is_reno(tp)) - tcp_reset_reno_sack(tp); - - skb = tcp_write_queue_head(sk); - is_reneg = skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED); - if (is_reneg) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSACKRENEGING); - tp->sacked_out = 0; - tp->fackets_out = 0; - } - tcp_clear_all_retrans_hints(tp); - - tcp_for_write_queue(skb, sk) { - if (skb == tcp_send_head(sk)) - break; - - mark_lost = (!(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED) || - is_reneg); - if (mark_lost) - tcp_sum_lost(tp, skb); - TCP_SKB_CB(skb)->sacked &= (~TCPCB_TAGBITS)|TCPCB_SACKED_ACKED; - if (mark_lost) { - TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_ACKED; - TCP_SKB_CB(skb)->sacked |= TCPCB_LOST; - tp->lost_out += tcp_skb_pcount(skb); - tp->retransmit_high = TCP_SKB_CB(skb)->end_seq; - } - } - tcp_verify_left_out(tp); - - /* Timeout in disordered state after receiving substantial DUPACKs - * suggests that the degree of reordering is over-estimated. - */ - if (icsk->icsk_ca_state <= TCP_CA_Disorder && - tp->sacked_out >= net->ipv4.sysctl_tcp_reordering) - tp->reordering = min_t(unsigned int, tp->reordering, - net->ipv4.sysctl_tcp_reordering); - tcp_set_ca_state(sk, TCP_CA_Loss); - tp->high_seq = tp->snd_nxt; - tcp_ecn_queue_cwr(tp); - - /* F-RTO RFC5682 sec 3.1 step 1: retransmit SND.UNA if no previous - * loss recovery is underway except recurring timeout(s) on - * the same SND.UNA (sec 3.2). Disable F-RTO on path MTU probing - */ - tp->frto = sysctl_tcp_frto && - (new_recovery || icsk->icsk_retransmits) && - !inet_csk(sk)->icsk_mtup.probe_size; -} - -/* If ACK arrived pointing to a remembered SACK, it means that our - * remembered SACKs do not reflect real state of receiver i.e. - * receiver _host_ is heavily congested (or buggy). - * - * To avoid big spurious retransmission bursts due to transient SACK - * scoreboard oddities that look like reneging, we give the receiver a - * little time (max(RTT/2, 10ms)) to send us some more ACKs that will - * restore sanity to the SACK scoreboard. If the apparent reneging - * persists until this RTO then we'll clear the SACK scoreboard. - */ -static bool tcp_check_sack_reneging(struct sock *sk, int flag) -{ - if (flag & FLAG_SACK_RENEGING) { - struct tcp_sock *tp = tcp_sk(sk); - unsigned long delay = max(usecs_to_jiffies(tp->srtt_us >> 4), - msecs_to_jiffies(10)); - - inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, - delay, TCP_RTO_MAX); - return true; - } - return false; -} - -static inline int tcp_fackets_out(const struct tcp_sock *tp) -{ - return tcp_is_reno(tp) ? tp->sacked_out + 1 : tp->fackets_out; -} - -/* Heurestics to calculate number of duplicate ACKs. There's no dupACKs - * counter when SACK is enabled (without SACK, sacked_out is used for - * that purpose). - * - * Instead, with FACK TCP uses fackets_out that includes both SACKed - * segments up to the highest received SACK block so far and holes in - * between them. - * - * With reordering, holes may still be in flight, so RFC3517 recovery - * uses pure sacked_out (total number of SACKed segments) even though - * it violates the RFC that uses duplicate ACKs, often these are equal - * but when e.g. out-of-window ACKs or packet duplication occurs, - * they differ. Since neither occurs due to loss, TCP should really - * ignore them. - */ -static inline int tcp_dupack_heuristics(const struct tcp_sock *tp) -{ - return tcp_is_fack(tp) ? tp->fackets_out : tp->sacked_out + 1; -} - -static bool tcp_pause_early_retransmit(struct sock *sk, int flag) -{ - struct tcp_sock *tp = tcp_sk(sk); - unsigned long delay; - - /* Delay early retransmit and entering fast recovery for - * max(RTT/4, 2msec) unless ack has ECE mark, no RTT samples - * available, or RTO is scheduled to fire first. - */ - if (sysctl_tcp_early_retrans < 2 || sysctl_tcp_early_retrans > 3 || - (flag & FLAG_ECE) || !tp->srtt_us) - return false; - - delay = max(usecs_to_jiffies(tp->srtt_us >> 5), - msecs_to_jiffies(2)); - - if (!time_after(inet_csk(sk)->icsk_timeout, (jiffies + delay))) - return false; - - inet_csk_reset_xmit_timer(sk, ICSK_TIME_EARLY_RETRANS, delay, - TCP_RTO_MAX); - return true; -} - -/* Linux NewReno/SACK/FACK/ECN state machine. - * -------------------------------------- - * - * "Open" Normal state, no dubious events, fast path. - * "Disorder" In all the respects it is "Open", - * but requires a bit more attention. It is entered when - * we see some SACKs or dupacks. It is split of "Open" - * mainly to move some processing from fast path to slow one. - * "CWR" CWND was reduced due to some Congestion Notification event. - * It can be ECN, ICMP source quench, local device congestion. - * "Recovery" CWND was reduced, we are fast-retransmitting. - * "Loss" CWND was reduced due to RTO timeout or SACK reneging. - * - * tcp_fastretrans_alert() is entered: - * - each incoming ACK, if state is not "Open" - * - when arrived ACK is unusual, namely: - * * SACK - * * Duplicate ACK. - * * ECN ECE. - * - * Counting packets in flight is pretty simple. - * - * in_flight = packets_out - left_out + retrans_out - * - * packets_out is SND.NXT-SND.UNA counted in packets. - * - * retrans_out is number of retransmitted segments. - * - * left_out is number of segments left network, but not ACKed yet. - * - * left_out = sacked_out + lost_out - * - * sacked_out: Packets, which arrived to receiver out of order - * and hence not ACKed. With SACKs this number is simply - * amount of SACKed data. Even without SACKs - * it is easy to give pretty reliable estimate of this number, - * counting duplicate ACKs. - * - * lost_out: Packets lost by network. TCP has no explicit - * "loss notification" feedback from network (for now). - * It means that this number can be only _guessed_. - * Actually, it is the heuristics to predict lossage that - * distinguishes different algorithms. - * - * F.e. after RTO, when all the queue is considered as lost, - * lost_out = packets_out and in_flight = retrans_out. - * - * Essentially, we have now two algorithms counting - * lost packets. - * - * FACK: It is the simplest heuristics. As soon as we decided - * that something is lost, we decide that _all_ not SACKed - * packets until the most forward SACK are lost. I.e. - * lost_out = fackets_out - sacked_out and left_out = fackets_out. - * It is absolutely correct estimate, if network does not reorder - * packets. And it loses any connection to reality when reordering - * takes place. We use FACK by default until reordering - * is suspected on the path to this destination. - * - * NewReno: when Recovery is entered, we assume that one segment - * is lost (classic Reno). While we are in Recovery and - * a partial ACK arrives, we assume that one more packet - * is lost (NewReno). This heuristics are the same in NewReno - * and SACK. - * - * Imagine, that's all! Forget about all this shamanism about CWND inflation - * deflation etc. CWND is real congestion window, never inflated, changes - * only according to classic VJ rules. - * - * Really tricky (and requiring careful tuning) part of algorithm - * is hidden in functions tcp_time_to_recover() and tcp_xmit_retransmit_queue(). - * The first determines the moment _when_ we should reduce CWND and, - * hence, slow down forward transmission. In fact, it determines the moment - * when we decide that hole is caused by loss, rather than by a reorder. - * - * tcp_xmit_retransmit_queue() decides, _what_ we should retransmit to fill - * holes, caused by lost packets. - * - * And the most logically complicated part of algorithm is undo - * heuristics. We detect false retransmits due to both too early - * fast retransmit (reordering) and underestimated RTO, analyzing - * timestamps and D-SACKs. When we detect that some segments were - * retransmitted by mistake and CWND reduction was wrong, we undo - * window reduction and abort recovery phase. This logic is hidden - * inside several functions named tcp_try_undo_. - */ - -/* This function decides, when we should leave Disordered state - * and enter Recovery phase, reducing congestion window. - * - * Main question: may we further continue forward transmission - * with the same cwnd? - */ -static bool tcp_time_to_recover(struct sock *sk, int flag) -{ - struct tcp_sock *tp = tcp_sk(sk); - __u32 packets_out; - int tcp_reordering = sock_net(sk)->ipv4.sysctl_tcp_reordering; - - /* Trick#1: The loss is proven. */ - if (tp->lost_out) - return true; - - /* Not-A-Trick#2 : Classic rule... */ - if (tcp_dupack_heuristics(tp) > tp->reordering) - return true; - - /* Trick#4: It is still not OK... But will it be useful to delay - * recovery more? - */ - packets_out = tp->packets_out; - if (packets_out <= tp->reordering && - tp->sacked_out >= max_t(__u32, packets_out/2, tcp_reordering) && - !tcp_may_send_now(sk)) { - /* We have nothing to send. This connection is limited - * either by receiver window or by application. - */ - return true; - } - - /* If a thin stream is detected, retransmit after first - * received dupack. Employ only if SACK is supported in order - * to avoid possible corner-case series of spurious retransmissions - * Use only if there are no unsent data. - */ - if ((tp->thin_dupack || sysctl_tcp_thin_dupack) && - tcp_stream_is_thin(tp) && tcp_dupack_heuristics(tp) > 1 && - tcp_is_sack(tp) && !tcp_send_head(sk)) - return true; - - /* Trick#6: TCP early retransmit, per RFC5827. To avoid spurious - * retransmissions due to small network reorderings, we implement - * Mitigation A.3 in the RFC and delay the retransmission for a short - * interval if appropriate. - */ - if (tp->do_early_retrans && !tp->retrans_out && tp->sacked_out && - (tp->packets_out >= (tp->sacked_out + 1) && tp->packets_out < 4) && - !tcp_may_send_now(sk)) - return !tcp_pause_early_retransmit(sk, flag); - - return false; -} - -/* Detect loss in event "A" above by marking head of queue up as lost. - * For FACK or non-SACK(Reno) senders, the first "packets" number of segments - * are considered lost. For RFC3517 SACK, a segment is considered lost if it - * has at least tp->reordering SACKed seqments above it; "packets" refers to - * the maximum SACKed segments to pass before reaching this limit. - */ -static void tcp_mark_head_lost(struct sock *sk, int packets, int mark_head) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *skb; - int cnt, oldcnt, lost; - unsigned int mss; - /* Use SACK to deduce losses of new sequences sent during recovery */ - const u32 loss_high = tcp_is_sack(tp) ? tp->snd_nxt : tp->high_seq; - - WARN_ON(packets > tp->packets_out); - if (tp->lost_skb_hint) { - skb = tp->lost_skb_hint; - cnt = tp->lost_cnt_hint; - /* Head already handled? */ - if (mark_head && skb != tcp_write_queue_head(sk)) - return; - } else { - skb = tcp_write_queue_head(sk); - cnt = 0; - } - - tcp_for_write_queue_from(skb, sk) { - if (skb == tcp_send_head(sk)) - break; - /* TODO: do this better */ - /* this is not the most efficient way to do this... */ - tp->lost_skb_hint = skb; - tp->lost_cnt_hint = cnt; - - if (after(TCP_SKB_CB(skb)->end_seq, loss_high)) - break; - - oldcnt = cnt; - if (tcp_is_fack(tp) || tcp_is_reno(tp) || - (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) - cnt += tcp_skb_pcount(skb); - - if (cnt > packets) { - if ((tcp_is_sack(tp) && !tcp_is_fack(tp)) || - (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED) || - (oldcnt >= packets)) - break; - - mss = tcp_skb_mss(skb); - /* If needed, chop off the prefix to mark as lost. */ - lost = (packets - oldcnt) * mss; - if (lost < skb->len && - tcp_fragment(sk, skb, lost, mss, GFP_ATOMIC) < 0) - break; - cnt = packets; - } - - tcp_skb_mark_lost(tp, skb); - - if (mark_head) - break; - } - tcp_verify_left_out(tp); -} - -/* Account newly detected lost packet(s) */ - -static void tcp_update_scoreboard(struct sock *sk, int fast_rexmit) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (tcp_is_reno(tp)) { - tcp_mark_head_lost(sk, 1, 1); - } else if (tcp_is_fack(tp)) { - int lost = tp->fackets_out - tp->reordering; - if (lost <= 0) - lost = 1; - tcp_mark_head_lost(sk, lost, 0); - } else { - int sacked_upto = tp->sacked_out - tp->reordering; - if (sacked_upto >= 0) - tcp_mark_head_lost(sk, sacked_upto, 0); - else if (fast_rexmit) - tcp_mark_head_lost(sk, 1, 1); - } -} - -static bool tcp_tsopt_ecr_before(const struct tcp_sock *tp, u32 when) -{ - return tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr && - before(tp->rx_opt.rcv_tsecr, when); -} - -/* skb is spurious retransmitted if the returned timestamp echo - * reply is prior to the skb transmission time - */ -static bool tcp_skb_spurious_retrans(const struct tcp_sock *tp, - const struct sk_buff *skb) -{ - return (TCP_SKB_CB(skb)->sacked & TCPCB_RETRANS) && - tcp_tsopt_ecr_before(tp, tcp_skb_timestamp(skb)); -} - -/* Nothing was retransmitted or returned timestamp is less - * than timestamp of the first retransmission. - */ -static inline bool tcp_packet_delayed(const struct tcp_sock *tp) -{ - return !tp->retrans_stamp || - tcp_tsopt_ecr_before(tp, tp->retrans_stamp); -} - -/* Undo procedures. */ - -/* We can clear retrans_stamp when there are no retransmissions in the - * window. It would seem that it is trivially available for us in - * tp->retrans_out, however, that kind of assumptions doesn't consider - * what will happen if errors occur when sending retransmission for the - * second time. ...It could the that such segment has only - * TCPCB_EVER_RETRANS set at the present time. It seems that checking - * the head skb is enough except for some reneging corner cases that - * are not worth the effort. - * - * Main reason for all this complexity is the fact that connection dying - * time now depends on the validity of the retrans_stamp, in particular, - * that successive retransmissions of a segment must not advance - * retrans_stamp under any conditions. - */ -static bool tcp_any_retrans_done(const struct sock *sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *skb; - - if (tp->retrans_out) - return true; - - skb = tcp_write_queue_head(sk); - if (unlikely(skb && TCP_SKB_CB(skb)->sacked & TCPCB_EVER_RETRANS)) - return true; - - return false; -} - -#if FASTRETRANS_DEBUG > 1 -static void DBGUNDO(struct sock *sk, const char *msg) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct inet_sock *inet = inet_sk(sk); - - if (sk->sk_family == AF_INET) { - pr_debug("Undo %s %pI4/%u c%u l%u ss%u/%u p%u\n", - msg, - &inet->inet_daddr, ntohs(inet->inet_dport), - tp->snd_cwnd, tcp_left_out(tp), - tp->snd_ssthresh, tp->prior_ssthresh, - tp->packets_out); - } -#if IS_ENABLED(CONFIG_IPV6) - else if (sk->sk_family == AF_INET6) { - pr_debug("Undo %s %pI6/%u c%u l%u ss%u/%u p%u\n", - msg, - &sk->sk_v6_daddr, ntohs(inet->inet_dport), - tp->snd_cwnd, tcp_left_out(tp), - tp->snd_ssthresh, tp->prior_ssthresh, - tp->packets_out); - } -#endif -} -#else -#define DBGUNDO(x...) do { } while (0) -#endif - -static void tcp_undo_cwnd_reduction(struct sock *sk, bool unmark_loss) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (unmark_loss) { - struct sk_buff *skb; - - tcp_for_write_queue(skb, sk) { - if (skb == tcp_send_head(sk)) - break; - TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST; - } - tp->lost_out = 0; - tcp_clear_all_retrans_hints(tp); - } - - if (tp->prior_ssthresh) { - const struct inet_connection_sock *icsk = inet_csk(sk); - - if (icsk->icsk_ca_ops->undo_cwnd) - tp->snd_cwnd = icsk->icsk_ca_ops->undo_cwnd(sk); - else - tp->snd_cwnd = max(tp->snd_cwnd, tp->snd_ssthresh << 1); - - if (tp->prior_ssthresh > tp->snd_ssthresh) { - tp->snd_ssthresh = tp->prior_ssthresh; - tcp_ecn_withdraw_cwr(tp); - } - } - tp->snd_cwnd_stamp = tcp_time_stamp; - tp->undo_marker = 0; -} - -static inline bool tcp_may_undo(const struct tcp_sock *tp) -{ - return tp->undo_marker && (!tp->undo_retrans || tcp_packet_delayed(tp)); -} - -/* People celebrate: "We love our President!" */ -static bool tcp_try_undo_recovery(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (tcp_may_undo(tp)) { - int mib_idx; - - /* Happy end! We did not retransmit anything - * or our original transmission succeeded. - */ - DBGUNDO(sk, inet_csk(sk)->icsk_ca_state == TCP_CA_Loss ? "loss" : "retrans"); - tcp_undo_cwnd_reduction(sk, false); - if (inet_csk(sk)->icsk_ca_state == TCP_CA_Loss) - mib_idx = LINUX_MIB_TCPLOSSUNDO; - else - mib_idx = LINUX_MIB_TCPFULLUNDO; - - NET_INC_STATS(sock_net(sk), mib_idx); - } - if (tp->snd_una == tp->high_seq && tcp_is_reno(tp)) { - /* Hold old state until something *above* high_seq - * is ACKed. For Reno it is MUST to prevent false - * fast retransmits (RFC2582). SACK TCP is safe. */ - if (!tcp_any_retrans_done(sk)) - tp->retrans_stamp = 0; - return true; - } - tcp_set_ca_state(sk, TCP_CA_Open); - return false; -} - -/* Try to undo cwnd reduction, because D-SACKs acked all retransmitted data */ -static bool tcp_try_undo_dsack(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (tp->undo_marker && !tp->undo_retrans) { - DBGUNDO(sk, "D-SACK"); - tcp_undo_cwnd_reduction(sk, false); - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPDSACKUNDO); - return true; - } - return false; -} - -/* Undo during loss recovery after partial ACK or using F-RTO. */ -static bool tcp_try_undo_loss(struct sock *sk, bool frto_undo) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (frto_undo || tcp_may_undo(tp)) { - tcp_undo_cwnd_reduction(sk, true); - - DBGUNDO(sk, "partial loss"); - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPLOSSUNDO); - if (frto_undo) - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPSPURIOUSRTOS); - inet_csk(sk)->icsk_retransmits = 0; - if (frto_undo || tcp_is_sack(tp)) - tcp_set_ca_state(sk, TCP_CA_Open); - return true; - } - return false; -} - -/* The cwnd reduction in CWR and Recovery uses the PRR algorithm in RFC 6937. - * It computes the number of packets to send (sndcnt) based on packets newly - * delivered: - * 1) If the packets in flight is larger than ssthresh, PRR spreads the - * cwnd reductions across a full RTT. - * 2) Otherwise PRR uses packet conservation to send as much as delivered. - * But when the retransmits are acked without further losses, PRR - * slow starts cwnd up to ssthresh to speed up the recovery. - */ -static void tcp_init_cwnd_reduction(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - - tp->high_seq = tp->snd_nxt; - tp->tlp_high_seq = 0; - tp->snd_cwnd_cnt = 0; - tp->prior_cwnd = tp->snd_cwnd; - tp->prr_delivered = 0; - tp->prr_out = 0; - tp->snd_ssthresh = inet_csk(sk)->icsk_ca_ops->ssthresh(sk); - tcp_ecn_queue_cwr(tp); -} - -static void tcp_cwnd_reduction(struct sock *sk, int newly_acked_sacked, - int flag) -{ - struct tcp_sock *tp = tcp_sk(sk); - int sndcnt = 0; - int delta = tp->snd_ssthresh - tcp_packets_in_flight(tp); - - if (newly_acked_sacked <= 0 || WARN_ON_ONCE(!tp->prior_cwnd)) - return; - - tp->prr_delivered += newly_acked_sacked; - if (delta < 0) { - u64 dividend = (u64)tp->snd_ssthresh * tp->prr_delivered + - tp->prior_cwnd - 1; - sndcnt = div_u64(dividend, tp->prior_cwnd) - tp->prr_out; - } else if ((flag & FLAG_RETRANS_DATA_ACKED) && - !(flag & FLAG_LOST_RETRANS)) { - sndcnt = min_t(int, delta, - max_t(int, tp->prr_delivered - tp->prr_out, - newly_acked_sacked) + 1); - } else { - sndcnt = min(delta, newly_acked_sacked); - } - /* Force a fast retransmit upon entering fast recovery */ - sndcnt = max(sndcnt, (tp->prr_out ? 0 : 1)); - tp->snd_cwnd = tcp_packets_in_flight(tp) + sndcnt; -} - -static inline void tcp_end_cwnd_reduction(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (inet_csk(sk)->icsk_ca_ops->cong_control) - return; - - /* Reset cwnd to ssthresh in CWR or Recovery (unless it's undone) */ - if (inet_csk(sk)->icsk_ca_state == TCP_CA_CWR || - (tp->undo_marker && tp->snd_ssthresh < TCP_INFINITE_SSTHRESH)) { - tp->snd_cwnd = tp->snd_ssthresh; - tp->snd_cwnd_stamp = tcp_time_stamp; - } - tcp_ca_event(sk, CA_EVENT_COMPLETE_CWR); -} - -/* Enter CWR state. Disable cwnd undo since congestion is proven with ECN */ -void tcp_enter_cwr(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - - tp->prior_ssthresh = 0; - if (inet_csk(sk)->icsk_ca_state < TCP_CA_CWR) { - tp->undo_marker = 0; - tcp_init_cwnd_reduction(sk); - tcp_set_ca_state(sk, TCP_CA_CWR); - } -} -EXPORT_SYMBOL(tcp_enter_cwr); - -static void tcp_try_keep_open(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - int state = TCP_CA_Open; - - if (tcp_left_out(tp) || tcp_any_retrans_done(sk)) - state = TCP_CA_Disorder; - - if (inet_csk(sk)->icsk_ca_state != state) { - tcp_set_ca_state(sk, state); - tp->high_seq = tp->snd_nxt; - } -} - -static void tcp_try_to_open(struct sock *sk, int flag) -{ - struct tcp_sock *tp = tcp_sk(sk); - - tcp_verify_left_out(tp); - - if (!tcp_any_retrans_done(sk)) - tp->retrans_stamp = 0; - - if (flag & FLAG_ECE) - tcp_enter_cwr(sk); - - if (inet_csk(sk)->icsk_ca_state != TCP_CA_CWR) { - tcp_try_keep_open(sk); - } -} - -static void tcp_mtup_probe_failed(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - - icsk->icsk_mtup.search_high = icsk->icsk_mtup.probe_size - 1; - icsk->icsk_mtup.probe_size = 0; - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMTUPFAIL); -} - -static void tcp_mtup_probe_success(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct inet_connection_sock *icsk = inet_csk(sk); - - /* FIXME: breaks with very large cwnd */ - tp->prior_ssthresh = tcp_current_ssthresh(sk); - tp->snd_cwnd = tp->snd_cwnd * - tcp_mss_to_mtu(sk, tp->mss_cache) / - icsk->icsk_mtup.probe_size; - tp->snd_cwnd_cnt = 0; - tp->snd_cwnd_stamp = tcp_time_stamp; - tp->snd_ssthresh = tcp_current_ssthresh(sk); - - icsk->icsk_mtup.search_low = icsk->icsk_mtup.probe_size; - icsk->icsk_mtup.probe_size = 0; - tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMTUPSUCCESS); -} - -/* Do a simple retransmit without using the backoff mechanisms in - * tcp_timer. This is used for path mtu discovery. - * The socket is already locked here. - */ -void tcp_simple_retransmit(struct sock *sk) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *skb; - unsigned int mss = tcp_current_mss(sk); - u32 prior_lost = tp->lost_out; - - tcp_for_write_queue(skb, sk) { - if (skb == tcp_send_head(sk)) - break; - if (tcp_skb_seglen(skb) > mss && - !(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) { - if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) { - TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; - tp->retrans_out -= tcp_skb_pcount(skb); - } - tcp_skb_mark_lost_uncond_verify(tp, skb); - } - } - - tcp_clear_retrans_hints_partial(tp); - - if (prior_lost == tp->lost_out) - return; - - if (tcp_is_reno(tp)) - tcp_limit_reno_sacked(tp); - - tcp_verify_left_out(tp); - - /* Don't muck with the congestion window here. - * Reason is that we do not increase amount of _data_ - * in network, but units changed and effective - * cwnd/ssthresh really reduced now. - */ - if (icsk->icsk_ca_state != TCP_CA_Loss) { - tp->high_seq = tp->snd_nxt; - tp->snd_ssthresh = tcp_current_ssthresh(sk); - tp->prior_ssthresh = 0; - tp->undo_marker = 0; - tcp_set_ca_state(sk, TCP_CA_Loss); - } - tcp_xmit_retransmit_queue(sk); -} -EXPORT_SYMBOL(tcp_simple_retransmit); - -static void tcp_enter_recovery(struct sock *sk, bool ece_ack) -{ - struct tcp_sock *tp = tcp_sk(sk); - int mib_idx; - - if (tcp_is_reno(tp)) - mib_idx = LINUX_MIB_TCPRENORECOVERY; - else - mib_idx = LINUX_MIB_TCPSACKRECOVERY; - - NET_INC_STATS(sock_net(sk), mib_idx); - - tp->prior_ssthresh = 0; - tcp_init_undo(tp); - - if (!tcp_in_cwnd_reduction(sk)) { - if (!ece_ack) - tp->prior_ssthresh = tcp_current_ssthresh(sk); - tcp_init_cwnd_reduction(sk); - } - tcp_set_ca_state(sk, TCP_CA_Recovery); -} - -/* Process an ACK in CA_Loss state. Move to CA_Open if lost data are - * recovered or spurious. Otherwise retransmits more on partial ACKs. - */ -static void tcp_process_loss(struct sock *sk, int flag, bool is_dupack, - int *rexmit) -{ - struct tcp_sock *tp = tcp_sk(sk); - bool recovered = !before(tp->snd_una, tp->high_seq); - - if ((flag & FLAG_SND_UNA_ADVANCED) && - tcp_try_undo_loss(sk, false)) - return; - - if (tp->frto) { /* F-RTO RFC5682 sec 3.1 (sack enhanced version). */ - /* Step 3.b. A timeout is spurious if not all data are - * lost, i.e., never-retransmitted data are (s)acked. - */ - if ((flag & FLAG_ORIG_SACK_ACKED) && - tcp_try_undo_loss(sk, true)) - return; - - if (after(tp->snd_nxt, tp->high_seq)) { - if (flag & FLAG_DATA_SACKED || is_dupack) - tp->frto = 0; /* Step 3.a. loss was real */ - } else if (flag & FLAG_SND_UNA_ADVANCED && !recovered) { - tp->high_seq = tp->snd_nxt; - /* Step 2.b. Try send new data (but deferred until cwnd - * is updated in tcp_ack()). Otherwise fall back to - * the conventional recovery. - */ - if (tcp_send_head(sk) && - after(tcp_wnd_end(tp), tp->snd_nxt)) { - *rexmit = REXMIT_NEW; - return; - } - tp->frto = 0; - } - } - - if (recovered) { - /* F-RTO RFC5682 sec 3.1 step 2.a and 1st part of step 3.a */ - tcp_try_undo_recovery(sk); - return; - } - if (tcp_is_reno(tp)) { - /* A Reno DUPACK means new data in F-RTO step 2.b above are - * delivered. Lower inflight to clock out (re)tranmissions. - */ - if (after(tp->snd_nxt, tp->high_seq) && is_dupack) - tcp_add_reno_sack(sk); - else if (flag & FLAG_SND_UNA_ADVANCED) - tcp_reset_reno_sack(tp); - } - *rexmit = REXMIT_LOST; -} - -/* Undo during fast recovery after partial ACK. */ -static bool tcp_try_undo_partial(struct sock *sk, const int acked) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (tp->undo_marker && tcp_packet_delayed(tp)) { - /* Plain luck! Hole if filled with delayed - * packet, rather than with a retransmit. - */ - tcp_update_reordering(sk, tcp_fackets_out(tp) + acked, 1); - - /* We are getting evidence that the reordering degree is higher - * than we realized. If there are no retransmits out then we - * can undo. Otherwise we clock out new packets but do not - * mark more packets lost or retransmit more. - */ - if (tp->retrans_out) - return true; - - if (!tcp_any_retrans_done(sk)) - tp->retrans_stamp = 0; - - DBGUNDO(sk, "partial recovery"); - tcp_undo_cwnd_reduction(sk, true); - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPPARTIALUNDO); - tcp_try_keep_open(sk); - return true; - } - return false; -} - -/* Process an event, which can update packets-in-flight not trivially. - * Main goal of this function is to calculate new estimate for left_out, - * taking into account both packets sitting in receiver's buffer and - * packets lost by network. - * - * Besides that it updates the congestion state when packet loss or ECN - * is detected. But it does not reduce the cwnd, it is done by the - * congestion control later. - * - * It does _not_ decide what to send, it is made in function - * tcp_xmit_retransmit_queue(). - */ -static void tcp_fastretrans_alert(struct sock *sk, const int acked, - bool is_dupack, int *ack_flag, int *rexmit) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - int fast_rexmit = 0, flag = *ack_flag; - bool do_lost = is_dupack || ((flag & FLAG_DATA_SACKED) && - (tcp_fackets_out(tp) > tp->reordering)); - - if (WARN_ON(!tp->packets_out && tp->sacked_out)) - tp->sacked_out = 0; - if (WARN_ON(!tp->sacked_out && tp->fackets_out)) - tp->fackets_out = 0; - - /* Now state machine starts. - * A. ECE, hence prohibit cwnd undoing, the reduction is required. */ - if (flag & FLAG_ECE) - tp->prior_ssthresh = 0; - - /* B. In all the states check for reneging SACKs. */ - if (tcp_check_sack_reneging(sk, flag)) - return; - - /* C. Check consistency of the current state. */ - tcp_verify_left_out(tp); - - /* D. Check state exit conditions. State can be terminated - * when high_seq is ACKed. */ - if (icsk->icsk_ca_state == TCP_CA_Open) { - WARN_ON(tp->retrans_out != 0); - tp->retrans_stamp = 0; - } else if (!before(tp->snd_una, tp->high_seq)) { - switch (icsk->icsk_ca_state) { - case TCP_CA_CWR: - /* CWR is to be held something *above* high_seq - * is ACKed for CWR bit to reach receiver. */ - if (tp->snd_una != tp->high_seq) { - tcp_end_cwnd_reduction(sk); - tcp_set_ca_state(sk, TCP_CA_Open); - } - break; - - case TCP_CA_Recovery: - if (tcp_is_reno(tp)) - tcp_reset_reno_sack(tp); - if (tcp_try_undo_recovery(sk)) - return; - tcp_end_cwnd_reduction(sk); - break; - } - } - - /* Use RACK to detect loss */ - if (sysctl_tcp_recovery & TCP_RACK_LOST_RETRANS && - tcp_rack_mark_lost(sk)) { - flag |= FLAG_LOST_RETRANS; - *ack_flag |= FLAG_LOST_RETRANS; - } - - /* E. Process state. */ - switch (icsk->icsk_ca_state) { - case TCP_CA_Recovery: - if (!(flag & FLAG_SND_UNA_ADVANCED)) { - if (tcp_is_reno(tp) && is_dupack) - tcp_add_reno_sack(sk); - } else { - if (tcp_try_undo_partial(sk, acked)) - return; - /* Partial ACK arrived. Force fast retransmit. */ - do_lost = tcp_is_reno(tp) || - tcp_fackets_out(tp) > tp->reordering; - } - if (tcp_try_undo_dsack(sk)) { - tcp_try_keep_open(sk); - return; - } - break; - case TCP_CA_Loss: - tcp_process_loss(sk, flag, is_dupack, rexmit); - if (icsk->icsk_ca_state != TCP_CA_Open && - !(flag & FLAG_LOST_RETRANS)) - return; - /* Change state if cwnd is undone or retransmits are lost */ - default: - if (tcp_is_reno(tp)) { - if (flag & FLAG_SND_UNA_ADVANCED) - tcp_reset_reno_sack(tp); - if (is_dupack) - tcp_add_reno_sack(sk); - } - - if (icsk->icsk_ca_state <= TCP_CA_Disorder) - tcp_try_undo_dsack(sk); - - if (!tcp_time_to_recover(sk, flag)) { - tcp_try_to_open(sk, flag); - return; - } - - /* MTU probe failure: don't reduce cwnd */ - if (icsk->icsk_ca_state < TCP_CA_CWR && - icsk->icsk_mtup.probe_size && - tp->snd_una == tp->mtu_probe.probe_seq_start) { - tcp_mtup_probe_failed(sk); - /* Restores the reduction we did in tcp_mtup_probe() */ - tp->snd_cwnd++; - tcp_simple_retransmit(sk); - return; - } - - /* Otherwise enter Recovery state */ - tcp_enter_recovery(sk, (flag & FLAG_ECE)); - fast_rexmit = 1; - } - - if (do_lost) - tcp_update_scoreboard(sk, fast_rexmit); - *rexmit = REXMIT_LOST; -} - -static void tcp_update_rtt_min(struct sock *sk, u32 rtt_us) -{ - struct tcp_sock *tp = tcp_sk(sk); - u32 wlen = sysctl_tcp_min_rtt_wlen * HZ; - - minmax_running_min(&tp->rtt_min, wlen, tcp_time_stamp, - rtt_us ? : jiffies_to_usecs(1)); -} - -static inline bool tcp_ack_update_rtt(struct sock *sk, const int flag, - long seq_rtt_us, long sack_rtt_us, - long ca_rtt_us) -{ - const struct tcp_sock *tp = tcp_sk(sk); - - /* Prefer RTT measured from ACK's timing to TS-ECR. This is because - * broken middle-boxes or peers may corrupt TS-ECR fields. But - * Karn's algorithm forbids taking RTT if some retransmitted data - * is acked (RFC6298). - */ - if (seq_rtt_us < 0) - seq_rtt_us = sack_rtt_us; - - /* RTTM Rule: A TSecr value received in a segment is used to - * update the averaged RTT measurement only if the segment - * acknowledges some new data, i.e., only if it advances the - * left edge of the send window. - * See draft-ietf-tcplw-high-performance-00, section 3.3. - */ - if (seq_rtt_us < 0 && tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr && - flag & FLAG_ACKED) - seq_rtt_us = ca_rtt_us = jiffies_to_usecs(tcp_time_stamp - - tp->rx_opt.rcv_tsecr); - if (seq_rtt_us < 0) - return false; - - /* ca_rtt_us >= 0 is counting on the invariant that ca_rtt_us is - * always taken together with ACK, SACK, or TS-opts. Any negative - * values will be skipped with the seq_rtt_us < 0 check above. - */ - tcp_update_rtt_min(sk, ca_rtt_us); - tcp_rtt_estimator(sk, seq_rtt_us); - tcp_set_rto(sk); - - /* RFC6298: only reset backoff on valid RTT measurement. */ - inet_csk(sk)->icsk_backoff = 0; - return true; -} - -/* Compute time elapsed between (last) SYNACK and the ACK completing 3WHS. */ -void tcp_synack_rtt_meas(struct sock *sk, struct request_sock *req) -{ - long rtt_us = -1L; - - if (req && !req->num_retrans && tcp_rsk(req)->snt_synack.v64) { - struct skb_mstamp now; - - skb_mstamp_get(&now); - rtt_us = skb_mstamp_us_delta(&now, &tcp_rsk(req)->snt_synack); - } - - tcp_ack_update_rtt(sk, FLAG_SYN_ACKED, rtt_us, -1L, rtt_us); -} - - -static void tcp_cong_avoid(struct sock *sk, u32 ack, u32 acked) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - - icsk->icsk_ca_ops->cong_avoid(sk, ack, acked); - tcp_sk(sk)->snd_cwnd_stamp = tcp_time_stamp; -} - -/* Restart timer after forward progress on connection. - * RFC2988 recommends to restart timer to now+rto. - */ -void tcp_rearm_rto(struct sock *sk) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - - /* If the retrans timer is currently being used by Fast Open - * for SYN-ACK retrans purpose, stay put. - */ - if (tp->fastopen_rsk) - return; - - if (!tp->packets_out) { - inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS); - } else { - u32 rto = inet_csk(sk)->icsk_rto; - /* Offset the time elapsed after installing regular RTO */ - if (icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS || - icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) { - struct sk_buff *skb = tcp_write_queue_head(sk); - const u32 rto_time_stamp = - tcp_skb_timestamp(skb) + rto; - s32 delta = (s32)(rto_time_stamp - tcp_time_stamp); - /* delta may not be positive if the socket is locked - * when the retrans timer fires and is rescheduled. - */ - if (delta > 0) - rto = delta; - } - inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, rto, - TCP_RTO_MAX); - } -} - -/* This function is called when the delayed ER timer fires. TCP enters - * fast recovery and performs fast-retransmit. - */ -void tcp_resume_early_retransmit(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - - tcp_rearm_rto(sk); - - /* Stop if ER is disabled after the delayed ER timer is scheduled */ - if (!tp->do_early_retrans) - return; - - tcp_enter_recovery(sk, false); - tcp_update_scoreboard(sk, 1); - tcp_xmit_retransmit_queue(sk); -} - -/* If we get here, the whole TSO packet has not been acked. */ -static u32 tcp_tso_acked(struct sock *sk, struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - u32 packets_acked; - - BUG_ON(!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)); - - packets_acked = tcp_skb_pcount(skb); - if (tcp_trim_head(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq)) - return 0; - packets_acked -= tcp_skb_pcount(skb); - - if (packets_acked) { - BUG_ON(tcp_skb_pcount(skb) == 0); - BUG_ON(!before(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)); - } - - return packets_acked; -} - -static void tcp_ack_tstamp(struct sock *sk, struct sk_buff *skb, - u32 prior_snd_una) -{ - const struct skb_shared_info *shinfo; - - /* Avoid cache line misses to get skb_shinfo() and shinfo->tx_flags */ - if (likely(!TCP_SKB_CB(skb)->txstamp_ack)) - return; - - shinfo = skb_shinfo(skb); - if (!before(shinfo->tskey, prior_snd_una) && - before(shinfo->tskey, tcp_sk(sk)->snd_una)) - __skb_tstamp_tx(skb, NULL, sk, SCM_TSTAMP_ACK); -} - -/* Remove acknowledged frames from the retransmission queue. If our packet - * is before the ack sequence we can discard it as it's confirmed to have - * arrived at the other end. - */ -static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets, - u32 prior_snd_una, int *acked, - struct tcp_sacktag_state *sack, - struct skb_mstamp *now) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - struct skb_mstamp first_ackt, last_ackt; - struct tcp_sock *tp = tcp_sk(sk); - u32 prior_sacked = tp->sacked_out; - u32 reord = tp->packets_out; - bool fully_acked = true; - long sack_rtt_us = -1L; - long seq_rtt_us = -1L; - long ca_rtt_us = -1L; - struct sk_buff *skb; - u32 pkts_acked = 0; - u32 last_in_flight = 0; - bool rtt_update; - int flag = 0; - - first_ackt.v64 = 0; - - while ((skb = tcp_write_queue_head(sk)) && skb != tcp_send_head(sk)) { - struct tcp_skb_cb *scb = TCP_SKB_CB(skb); - u8 sacked = scb->sacked; - u32 acked_pcount; - - tcp_ack_tstamp(sk, skb, prior_snd_una); - - /* Determine how many packets and what bytes were acked, tso and else */ - if (after(scb->end_seq, tp->snd_una)) { - if (tcp_skb_pcount(skb) == 1 || - !after(tp->snd_una, scb->seq)) - break; - - acked_pcount = tcp_tso_acked(sk, skb); - if (!acked_pcount) - break; - fully_acked = false; - } else { - /* Speedup tcp_unlink_write_queue() and next loop */ - prefetchw(skb->next); - acked_pcount = tcp_skb_pcount(skb); - } - - if (unlikely(sacked & TCPCB_RETRANS)) { - if (sacked & TCPCB_SACKED_RETRANS) - tp->retrans_out -= acked_pcount; - flag |= FLAG_RETRANS_DATA_ACKED; - } else if (!(sacked & TCPCB_SACKED_ACKED)) { - last_ackt = skb->skb_mstamp; - WARN_ON_ONCE(last_ackt.v64 == 0); - if (!first_ackt.v64) - first_ackt = last_ackt; - - last_in_flight = TCP_SKB_CB(skb)->tx.in_flight; - reord = min(pkts_acked, reord); - if (!after(scb->end_seq, tp->high_seq)) - flag |= FLAG_ORIG_SACK_ACKED; - } - - if (sacked & TCPCB_SACKED_ACKED) { - tp->sacked_out -= acked_pcount; - } else if (tcp_is_sack(tp)) { - tp->delivered += acked_pcount; - if (!tcp_skb_spurious_retrans(tp, skb)) - tcp_rack_advance(tp, &skb->skb_mstamp, sacked); - } - if (sacked & TCPCB_LOST) - tp->lost_out -= acked_pcount; - - tp->packets_out -= acked_pcount; - pkts_acked += acked_pcount; - tcp_rate_skb_delivered(sk, skb, sack->rate); - - /* Initial outgoing SYN's get put onto the write_queue - * just like anything else we transmit. It is not - * true data, and if we misinform our callers that - * this ACK acks real data, we will erroneously exit - * connection startup slow start one packet too - * quickly. This is severely frowned upon behavior. - */ - if (likely(!(scb->tcp_flags & TCPHDR_SYN))) { - flag |= FLAG_DATA_ACKED; - } else { - flag |= FLAG_SYN_ACKED; - tp->retrans_stamp = 0; - } - - if (!fully_acked) - break; - - tcp_unlink_write_queue(skb, sk); - sk_wmem_free_skb(sk, skb); - if (unlikely(skb == tp->retransmit_skb_hint)) - tp->retransmit_skb_hint = NULL; - if (unlikely(skb == tp->lost_skb_hint)) - tp->lost_skb_hint = NULL; - } - - if (likely(between(tp->snd_up, prior_snd_una, tp->snd_una))) - tp->snd_up = tp->snd_una; - - if (skb && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) - flag |= FLAG_SACK_RENEGING; - - if (likely(first_ackt.v64) && !(flag & FLAG_RETRANS_DATA_ACKED)) { - seq_rtt_us = skb_mstamp_us_delta(now, &first_ackt); - ca_rtt_us = skb_mstamp_us_delta(now, &last_ackt); - } - if (sack->first_sackt.v64) { - sack_rtt_us = skb_mstamp_us_delta(now, &sack->first_sackt); - ca_rtt_us = skb_mstamp_us_delta(now, &sack->last_sackt); - } - sack->rate->rtt_us = ca_rtt_us; /* RTT of last (S)ACKed packet, or -1 */ - rtt_update = tcp_ack_update_rtt(sk, flag, seq_rtt_us, sack_rtt_us, - ca_rtt_us); - - if (flag & FLAG_ACKED) { - tcp_rearm_rto(sk); - if (unlikely(icsk->icsk_mtup.probe_size && - !after(tp->mtu_probe.probe_seq_end, tp->snd_una))) { - tcp_mtup_probe_success(sk); - } - - if (tcp_is_reno(tp)) { - tcp_remove_reno_sacks(sk, pkts_acked); - } else { - int delta; - - /* Non-retransmitted hole got filled? That's reordering */ - if (reord < prior_fackets) - tcp_update_reordering(sk, tp->fackets_out - reord, 0); - - delta = tcp_is_fack(tp) ? pkts_acked : - prior_sacked - tp->sacked_out; - tp->lost_cnt_hint -= min(tp->lost_cnt_hint, delta); - } - - tp->fackets_out -= min(pkts_acked, tp->fackets_out); - - } else if (skb && rtt_update && sack_rtt_us >= 0 && - sack_rtt_us > skb_mstamp_us_delta(now, &skb->skb_mstamp)) { - /* Do not re-arm RTO if the sack RTT is measured from data sent - * after when the head was last (re)transmitted. Otherwise the - * timeout may continue to extend in loss recovery. - */ - tcp_rearm_rto(sk); - } - - if (icsk->icsk_ca_ops->pkts_acked) { - struct ack_sample sample = { .pkts_acked = pkts_acked, - .rtt_us = ca_rtt_us, - .in_flight = last_in_flight }; - - icsk->icsk_ca_ops->pkts_acked(sk, &sample); - } - -#if FASTRETRANS_DEBUG > 0 - WARN_ON((int)tp->sacked_out < 0); - WARN_ON((int)tp->lost_out < 0); - WARN_ON((int)tp->retrans_out < 0); - if (!tp->packets_out && tcp_is_sack(tp)) { - icsk = inet_csk(sk); - if (tp->lost_out) { - pr_debug("Leak l=%u %d\n", - tp->lost_out, icsk->icsk_ca_state); - tp->lost_out = 0; - } - if (tp->sacked_out) { - pr_debug("Leak s=%u %d\n", - tp->sacked_out, icsk->icsk_ca_state); - tp->sacked_out = 0; - } - if (tp->retrans_out) { - pr_debug("Leak r=%u %d\n", - tp->retrans_out, icsk->icsk_ca_state); - tp->retrans_out = 0; - } - } -#endif - *acked = pkts_acked; - return flag; -} - -static void tcp_ack_probe(struct sock *sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - struct inet_connection_sock *icsk = inet_csk(sk); - - /* Was it a usable window open? */ - - if (!after(TCP_SKB_CB(tcp_send_head(sk))->end_seq, tcp_wnd_end(tp))) { - icsk->icsk_backoff = 0; - inet_csk_clear_xmit_timer(sk, ICSK_TIME_PROBE0); - /* Socket must be waked up by subsequent tcp_data_snd_check(). - * This function is not for random using! - */ - } else { - unsigned long when = tcp_probe0_when(sk, TCP_RTO_MAX); - - inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0, - when, TCP_RTO_MAX); - } -} - -static inline bool tcp_ack_is_dubious(const struct sock *sk, const int flag) -{ - return !(flag & FLAG_NOT_DUP) || (flag & FLAG_CA_ALERT) || - inet_csk(sk)->icsk_ca_state != TCP_CA_Open; -} - -/* Decide wheather to run the increase function of congestion control. */ -static inline bool tcp_may_raise_cwnd(const struct sock *sk, const int flag) -{ - /* If reordering is high then always grow cwnd whenever data is - * delivered regardless of its ordering. Otherwise stay conservative - * and only grow cwnd on in-order delivery (RFC5681). A stretched ACK w/ - * new SACK or ECE mark may first advance cwnd here and later reduce - * cwnd in tcp_fastretrans_alert() based on more states. - */ - if (tcp_sk(sk)->reordering > sock_net(sk)->ipv4.sysctl_tcp_reordering) - return flag & FLAG_FORWARD_PROGRESS; - - return flag & FLAG_DATA_ACKED; -} - -/* The "ultimate" congestion control function that aims to replace the rigid - * cwnd increase and decrease control (tcp_cong_avoid,tcp_*cwnd_reduction). - * It's called toward the end of processing an ACK with precise rate - * information. All transmission or retransmission are delayed afterwards. - */ -static void tcp_cong_control(struct sock *sk, u32 ack, u32 acked_sacked, - int flag, const struct rate_sample *rs) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - - if (icsk->icsk_ca_ops->cong_control) { - icsk->icsk_ca_ops->cong_control(sk, rs); - return; - } - - if (tcp_in_cwnd_reduction(sk)) { - /* Reduce cwnd if state mandates */ - tcp_cwnd_reduction(sk, acked_sacked, flag); - } else if (tcp_may_raise_cwnd(sk, flag)) { - /* Advance cwnd if state allows */ - tcp_cong_avoid(sk, ack, acked_sacked); - } - tcp_update_pacing_rate(sk); -} - -/* Check that window update is acceptable. - * The function assumes that snd_una<=ack<=snd_next. - */ -static inline bool tcp_may_update_window(const struct tcp_sock *tp, - const u32 ack, const u32 ack_seq, - const u32 nwin) -{ - return after(ack, tp->snd_una) || - after(ack_seq, tp->snd_wl1) || - (ack_seq == tp->snd_wl1 && nwin > tp->snd_wnd); -} - -/* If we update tp->snd_una, also update tp->bytes_acked */ -static void tcp_snd_una_update(struct tcp_sock *tp, u32 ack) -{ - u32 delta = ack - tp->snd_una; - - sock_owned_by_me((struct sock *)tp); - u64_stats_update_begin_raw(&tp->syncp); - tp->bytes_acked += delta; - u64_stats_update_end_raw(&tp->syncp); - tp->snd_una = ack; -} - -/* If we update tp->rcv_nxt, also update tp->bytes_received */ -static void tcp_rcv_nxt_update(struct tcp_sock *tp, u32 seq) -{ - u32 delta = seq - tp->rcv_nxt; - - sock_owned_by_me((struct sock *)tp); - u64_stats_update_begin_raw(&tp->syncp); - tp->bytes_received += delta; - u64_stats_update_end_raw(&tp->syncp); - tp->rcv_nxt = seq; -} - -/* Update our send window. - * - * Window update algorithm, described in RFC793/RFC1122 (used in linux-2.2 - * and in FreeBSD. NetBSD's one is even worse.) is wrong. - */ -static int tcp_ack_update_window(struct sock *sk, const struct sk_buff *skb, u32 ack, - u32 ack_seq) -{ - struct tcp_sock *tp = tcp_sk(sk); - int flag = 0; - u32 nwin = ntohs(tcp_hdr(skb)->window); - - if (likely(!tcp_hdr(skb)->syn)) - nwin <<= tp->rx_opt.snd_wscale; - - if (tcp_may_update_window(tp, ack, ack_seq, nwin)) { - flag |= FLAG_WIN_UPDATE; - tcp_update_wl(tp, ack_seq); - - if (tp->snd_wnd != nwin) { - tp->snd_wnd = nwin; - - /* Note, it is the only place, where - * fast path is recovered for sending TCP. - */ - tp->pred_flags = 0; - tcp_fast_path_check(sk); - - if (tcp_send_head(sk)) - tcp_slow_start_after_idle_check(sk); - - if (nwin > tp->max_window) { - tp->max_window = nwin; - tcp_sync_mss(sk, inet_csk(sk)->icsk_pmtu_cookie); - } - } - } - - tcp_snd_una_update(tp, ack); - - return flag; -} - -static bool __tcp_oow_rate_limited(struct net *net, int mib_idx, - u32 *last_oow_ack_time) -{ - if (*last_oow_ack_time) { - s32 elapsed = (s32)(tcp_time_stamp - *last_oow_ack_time); - - if (0 <= elapsed && elapsed < sysctl_tcp_invalid_ratelimit) { - NET_INC_STATS(net, mib_idx); - return true; /* rate-limited: don't send yet! */ - } - } - - *last_oow_ack_time = tcp_time_stamp; - - return false; /* not rate-limited: go ahead, send dupack now! */ -} - -/* Return true if we're currently rate-limiting out-of-window ACKs and - * thus shouldn't send a dupack right now. We rate-limit dupacks in - * response to out-of-window SYNs or ACKs to mitigate ACK loops or DoS - * attacks that send repeated SYNs or ACKs for the same connection. To - * do this, we do not send a duplicate SYNACK or ACK if the remote - * endpoint is sending out-of-window SYNs or pure ACKs at a high rate. - */ -bool tcp_oow_rate_limited(struct net *net, const struct sk_buff *skb, - int mib_idx, u32 *last_oow_ack_time) -{ - /* Data packets without SYNs are not likely part of an ACK loop. */ - if ((TCP_SKB_CB(skb)->seq != TCP_SKB_CB(skb)->end_seq) && - !tcp_hdr(skb)->syn) - return false; - - return __tcp_oow_rate_limited(net, mib_idx, last_oow_ack_time); -} - -/* RFC 5961 7 [ACK Throttling] */ -static void tcp_send_challenge_ack(struct sock *sk, const struct sk_buff *skb) -{ - /* unprotected vars, we dont care of overwrites */ - static u32 challenge_timestamp; - static unsigned int challenge_count; - struct tcp_sock *tp = tcp_sk(sk); - u32 count, now; - - /* First check our per-socket dupack rate limit. */ - if (__tcp_oow_rate_limited(sock_net(sk), - LINUX_MIB_TCPACKSKIPPEDCHALLENGE, - &tp->last_oow_ack_time)) - return; - - /* Then check host-wide RFC 5961 rate limit. */ - now = jiffies / HZ; - if (now != challenge_timestamp) { - u32 half = (sysctl_tcp_challenge_ack_limit + 1) >> 1; - - challenge_timestamp = now; - WRITE_ONCE(challenge_count, half + - prandom_u32_max(sysctl_tcp_challenge_ack_limit)); - } - count = READ_ONCE(challenge_count); - if (count > 0) { - WRITE_ONCE(challenge_count, count - 1); - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK); - tcp_send_ack(sk); - } -} - -static void tcp_store_ts_recent(struct tcp_sock *tp) -{ - tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval; - tp->rx_opt.ts_recent_stamp = get_seconds(); -} - -static void tcp_replace_ts_recent(struct tcp_sock *tp, u32 seq) -{ - if (tp->rx_opt.saw_tstamp && !after(seq, tp->rcv_wup)) { - /* PAWS bug workaround wrt. ACK frames, the PAWS discard - * extra check below makes sure this can only happen - * for pure ACK frames. -DaveM - * - * Not only, also it occurs for expired timestamps. - */ - - if (tcp_paws_check(&tp->rx_opt, 0)) - tcp_store_ts_recent(tp); - } -} - -/* This routine deals with acks during a TLP episode. - * We mark the end of a TLP episode on receiving TLP dupack or when - * ack is after tlp_high_seq. - * Ref: loss detection algorithm in draft-dukkipati-tcpm-tcp-loss-probe. - */ -static void tcp_process_tlp_ack(struct sock *sk, u32 ack, int flag) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (before(ack, tp->tlp_high_seq)) - return; - - if (flag & FLAG_DSACKING_ACK) { - /* This DSACK means original and TLP probe arrived; no loss */ - tp->tlp_high_seq = 0; - } else if (after(ack, tp->tlp_high_seq)) { - /* ACK advances: there was a loss, so reduce cwnd. Reset - * tlp_high_seq in tcp_init_cwnd_reduction() - */ - tcp_init_cwnd_reduction(sk); - tcp_set_ca_state(sk, TCP_CA_CWR); - tcp_end_cwnd_reduction(sk); - tcp_try_keep_open(sk); - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPLOSSPROBERECOVERY); - } else if (!(flag & (FLAG_SND_UNA_ADVANCED | - FLAG_NOT_DUP | FLAG_DATA_SACKED))) { - /* Pure dupack: original and TLP probe arrived; no loss */ - tp->tlp_high_seq = 0; - } -} - -static inline void tcp_in_ack_event(struct sock *sk, u32 flags) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - - if (icsk->icsk_ca_ops->in_ack_event) - icsk->icsk_ca_ops->in_ack_event(sk, flags); -} - -/* Congestion control has updated the cwnd already. So if we're in - * loss recovery then now we do any new sends (for FRTO) or - * retransmits (for CA_Loss or CA_recovery) that make sense. - */ -static void tcp_xmit_recovery(struct sock *sk, int rexmit) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (rexmit == REXMIT_NONE) - return; - - if (unlikely(rexmit == 2)) { - __tcp_push_pending_frames(sk, tcp_current_mss(sk), - TCP_NAGLE_OFF); - if (after(tp->snd_nxt, tp->high_seq)) - return; - tp->frto = 0; - } - tcp_xmit_retransmit_queue(sk); -} - -/* This routine deals with incoming acks, but not outgoing ones. */ -static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - struct tcp_sacktag_state sack_state; - struct rate_sample rs = { .prior_delivered = 0 }; - u32 prior_snd_una = tp->snd_una; - u32 ack_seq = TCP_SKB_CB(skb)->seq; - u32 ack = TCP_SKB_CB(skb)->ack_seq; - bool is_dupack = false; - u32 prior_fackets; - int prior_packets = tp->packets_out; - u32 delivered = tp->delivered; - u32 lost = tp->lost; - int acked = 0; /* Number of packets newly acked */ - int rexmit = REXMIT_NONE; /* Flag to (re)transmit to recover losses */ - struct skb_mstamp now; - - sack_state.first_sackt.v64 = 0; - sack_state.rate = &rs; - - /* We very likely will need to access write queue head. */ - prefetchw(sk->sk_write_queue.next); - - /* If the ack is older than previous acks - * then we can probably ignore it. - */ - if (before(ack, prior_snd_una)) { - /* RFC 5961 5.2 [Blind Data Injection Attack].[Mitigation] */ - if (before(ack, prior_snd_una - tp->max_window)) { - tcp_send_challenge_ack(sk, skb); - return -1; - } - goto old_ack; - } - - /* If the ack includes data we haven't sent yet, discard - * this segment (RFC793 Section 3.9). - */ - if (after(ack, tp->snd_nxt)) - goto invalid_ack; - - skb_mstamp_get(&now); - - if (icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS || - icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) - tcp_rearm_rto(sk); - - if (after(ack, prior_snd_una)) { - flag |= FLAG_SND_UNA_ADVANCED; - icsk->icsk_retransmits = 0; - } - - prior_fackets = tp->fackets_out; - rs.prior_in_flight = tcp_packets_in_flight(tp); - - /* ts_recent update must be made after we are sure that the packet - * is in window. - */ - if (flag & FLAG_UPDATE_TS_RECENT) - tcp_replace_ts_recent(tp, TCP_SKB_CB(skb)->seq); - - if (!(flag & FLAG_SLOWPATH) && after(ack, prior_snd_una)) { - /* Window is constant, pure forward advance. - * No more checks are required. - * Note, we use the fact that SND.UNA>=SND.WL2. - */ - tcp_update_wl(tp, ack_seq); - tcp_snd_una_update(tp, ack); - flag |= FLAG_WIN_UPDATE; - - tcp_in_ack_event(sk, CA_ACK_WIN_UPDATE); - - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPHPACKS); - } else { - u32 ack_ev_flags = CA_ACK_SLOWPATH; - - if (ack_seq != TCP_SKB_CB(skb)->end_seq) - flag |= FLAG_DATA; - else - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPPUREACKS); - - flag |= tcp_ack_update_window(sk, skb, ack, ack_seq); - - if (TCP_SKB_CB(skb)->sacked) - flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una, - &sack_state); - - if (tcp_ecn_rcv_ecn_echo(tp, tcp_hdr(skb))) { - flag |= FLAG_ECE; - ack_ev_flags |= CA_ACK_ECE; - } - - if (flag & FLAG_WIN_UPDATE) - ack_ev_flags |= CA_ACK_WIN_UPDATE; - - tcp_in_ack_event(sk, ack_ev_flags); - } - - /* We passed data and got it acked, remove any soft error - * log. Something worked... - */ - sk->sk_err_soft = 0; - icsk->icsk_probes_out = 0; - tp->rcv_tstamp = tcp_time_stamp; - if (!prior_packets) - goto no_queue; - - /* See if we can take anything off of the retransmit queue. */ - flag |= tcp_clean_rtx_queue(sk, prior_fackets, prior_snd_una, &acked, - &sack_state, &now); - - if (tcp_ack_is_dubious(sk, flag)) { - is_dupack = !(flag & (FLAG_SND_UNA_ADVANCED | FLAG_NOT_DUP)); - tcp_fastretrans_alert(sk, acked, is_dupack, &flag, &rexmit); - } - if (tp->tlp_high_seq) - tcp_process_tlp_ack(sk, ack, flag); - - if ((flag & FLAG_FORWARD_PROGRESS) || !(flag & FLAG_NOT_DUP)) { - struct dst_entry *dst = __sk_dst_get(sk); - if (dst) - dst_confirm(dst); - } - - if (icsk->icsk_pending == ICSK_TIME_RETRANS) - tcp_schedule_loss_probe(sk); - delivered = tp->delivered - delivered; /* freshly ACKed or SACKed */ - lost = tp->lost - lost; /* freshly marked lost */ - tcp_rate_gen(sk, delivered, lost, &now, &rs); - tcp_cong_control(sk, ack, delivered, flag, &rs); - tcp_xmit_recovery(sk, rexmit); - return 1; - -no_queue: - /* If data was DSACKed, see if we can undo a cwnd reduction. */ - if (flag & FLAG_DSACKING_ACK) - tcp_fastretrans_alert(sk, acked, is_dupack, &flag, &rexmit); - /* If this ack opens up a zero window, clear backoff. It was - * being used to time the probes, and is probably far higher than - * it needs to be for normal retransmission. - */ - if (tcp_send_head(sk)) - tcp_ack_probe(sk); - - if (tp->tlp_high_seq) - tcp_process_tlp_ack(sk, ack, flag); - return 1; - -invalid_ack: - SOCK_DEBUG(sk, "Ack %u after %u:%u\n", ack, tp->snd_una, tp->snd_nxt); - return -1; - -old_ack: - /* If data was SACKed, tag it and see if we should send more data. - * If data was DSACKed, see if we can undo a cwnd reduction. - */ - if (TCP_SKB_CB(skb)->sacked) { - flag |= tcp_sacktag_write_queue(sk, skb, prior_snd_una, - &sack_state); - tcp_fastretrans_alert(sk, acked, is_dupack, &flag, &rexmit); - tcp_xmit_recovery(sk, rexmit); - } - - SOCK_DEBUG(sk, "Ack %u before %u:%u\n", ack, tp->snd_una, tp->snd_nxt); - return 0; -} - -static void tcp_parse_fastopen_option(int len, const unsigned char *cookie, - bool syn, struct tcp_fastopen_cookie *foc, - bool exp_opt) -{ - /* Valid only in SYN or SYN-ACK with an even length. */ - if (!foc || !syn || len < 0 || (len & 1)) - return; - - if (len >= TCP_FASTOPEN_COOKIE_MIN && - len <= TCP_FASTOPEN_COOKIE_MAX) - memcpy(foc->val, cookie, len); - else if (len != 0) - len = -1; - foc->len = len; - foc->exp = exp_opt; -} - -/* Look for tcp options. Normally only called on SYN and SYNACK packets. - * But, this can also be called on packets in the established flow when - * the fast version below fails. - */ -void tcp_parse_options(const struct sk_buff *skb, - struct tcp_options_received *opt_rx, int estab, - struct tcp_fastopen_cookie *foc) -{ - const unsigned char *ptr; - const struct tcphdr *th = tcp_hdr(skb); - int length = (th->doff * 4) - sizeof(struct tcphdr); - - ptr = (const unsigned char *)(th + 1); - opt_rx->saw_tstamp = 0; - - while (length > 0) { - int opcode = *ptr++; - int opsize; - - switch (opcode) { - case TCPOPT_EOL: - return; - case TCPOPT_NOP: /* Ref: RFC 793 section 3.1 */ - length--; - continue; - default: - opsize = *ptr++; - if (opsize < 2) /* "silly options" */ - return; - if (opsize > length) - return; /* don't parse partial options */ - switch (opcode) { - case TCPOPT_MSS: - if (opsize == TCPOLEN_MSS && th->syn && !estab) { - u16 in_mss = get_unaligned_be16(ptr); - if (in_mss) { - if (opt_rx->user_mss && - opt_rx->user_mss < in_mss) - in_mss = opt_rx->user_mss; - opt_rx->mss_clamp = in_mss; - } - } - break; - case TCPOPT_WINDOW: - if (opsize == TCPOLEN_WINDOW && th->syn && - !estab && sysctl_tcp_window_scaling) { - __u8 snd_wscale = *(__u8 *)ptr; - opt_rx->wscale_ok = 1; - if (snd_wscale > 14) { - net_info_ratelimited("%s: Illegal window scaling value %d >14 received\n", - __func__, - snd_wscale); - snd_wscale = 14; - } - opt_rx->snd_wscale = snd_wscale; - } - break; - case TCPOPT_TIMESTAMP: - if ((opsize == TCPOLEN_TIMESTAMP) && - ((estab && opt_rx->tstamp_ok) || - (!estab && sysctl_tcp_timestamps))) { - opt_rx->saw_tstamp = 1; - opt_rx->rcv_tsval = get_unaligned_be32(ptr); - opt_rx->rcv_tsecr = get_unaligned_be32(ptr + 4); - } - break; - case TCPOPT_SACK_PERM: - if (opsize == TCPOLEN_SACK_PERM && th->syn && - !estab && sysctl_tcp_sack) { - opt_rx->sack_ok = TCP_SACK_SEEN; - tcp_sack_reset(opt_rx); - } - break; - - case TCPOPT_SACK: - if ((opsize >= (TCPOLEN_SACK_BASE + TCPOLEN_SACK_PERBLOCK)) && - !((opsize - TCPOLEN_SACK_BASE) % TCPOLEN_SACK_PERBLOCK) && - opt_rx->sack_ok) { - TCP_SKB_CB(skb)->sacked = (ptr - 2) - (unsigned char *)th; - } - break; -#ifdef CONFIG_TCP_MD5SIG - case TCPOPT_MD5SIG: - /* - * The MD5 Hash has already been - * checked (see tcp_v{4,6}_do_rcv()). - */ - break; -#endif - case TCPOPT_FASTOPEN: - tcp_parse_fastopen_option( - opsize - TCPOLEN_FASTOPEN_BASE, - ptr, th->syn, foc, false); - break; - - case TCPOPT_EXP: - /* Fast Open option shares code 254 using a - * 16 bits magic number. - */ - if (opsize >= TCPOLEN_EXP_FASTOPEN_BASE && - get_unaligned_be16(ptr) == - TCPOPT_FASTOPEN_MAGIC) - tcp_parse_fastopen_option(opsize - - TCPOLEN_EXP_FASTOPEN_BASE, - ptr + 2, th->syn, foc, true); - break; - - } - ptr += opsize-2; - length -= opsize; - } - } -} -EXPORT_SYMBOL(tcp_parse_options); - -static bool tcp_parse_aligned_timestamp(struct tcp_sock *tp, const struct tcphdr *th) -{ - const __be32 *ptr = (const __be32 *)(th + 1); - - if (*ptr == htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) - | (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP)) { - tp->rx_opt.saw_tstamp = 1; - ++ptr; - tp->rx_opt.rcv_tsval = ntohl(*ptr); - ++ptr; - if (*ptr) - tp->rx_opt.rcv_tsecr = ntohl(*ptr) - tp->tsoffset; - else - tp->rx_opt.rcv_tsecr = 0; - return true; - } - return false; -} - -/* Fast parse options. This hopes to only see timestamps. - * If it is wrong it falls back on tcp_parse_options(). - */ -static bool tcp_fast_parse_options(const struct sk_buff *skb, - const struct tcphdr *th, struct tcp_sock *tp) -{ - /* In the spirit of fast parsing, compare doff directly to constant - * values. Because equality is used, short doff can be ignored here. - */ - if (th->doff == (sizeof(*th) / 4)) { - tp->rx_opt.saw_tstamp = 0; - return false; - } else if (tp->rx_opt.tstamp_ok && - th->doff == ((sizeof(*th) + TCPOLEN_TSTAMP_ALIGNED) / 4)) { - if (tcp_parse_aligned_timestamp(tp, th)) - return true; - } - - tcp_parse_options(skb, &tp->rx_opt, 1, NULL); - if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr) - tp->rx_opt.rcv_tsecr -= tp->tsoffset; - - return true; -} - -#ifdef CONFIG_TCP_MD5SIG -/* - * Parse MD5 Signature option - */ -const u8 *tcp_parse_md5sig_option(const struct tcphdr *th) -{ - int length = (th->doff << 2) - sizeof(*th); - const u8 *ptr = (const u8 *)(th + 1); - - /* If the TCP option is too short, we can short cut */ - if (length < TCPOLEN_MD5SIG) - return NULL; - - while (length > 0) { - int opcode = *ptr++; - int opsize; - - switch (opcode) { - case TCPOPT_EOL: - return NULL; - case TCPOPT_NOP: - length--; - continue; - default: - opsize = *ptr++; - if (opsize < 2 || opsize > length) - return NULL; - if (opcode == TCPOPT_MD5SIG) - return opsize == TCPOLEN_MD5SIG ? ptr : NULL; - } - ptr += opsize - 2; - length -= opsize; - } - return NULL; -} -EXPORT_SYMBOL(tcp_parse_md5sig_option); -#endif - -/* Sorry, PAWS as specified is broken wrt. pure-ACKs -DaveM - * - * It is not fatal. If this ACK does _not_ change critical state (seqs, window) - * it can pass through stack. So, the following predicate verifies that - * this segment is not used for anything but congestion avoidance or - * fast retransmit. Moreover, we even are able to eliminate most of such - * second order effects, if we apply some small "replay" window (~RTO) - * to timestamp space. - * - * All these measures still do not guarantee that we reject wrapped ACKs - * on networks with high bandwidth, when sequence space is recycled fastly, - * but it guarantees that such events will be very rare and do not affect - * connection seriously. This doesn't look nice, but alas, PAWS is really - * buggy extension. - * - * [ Later note. Even worse! It is buggy for segments _with_ data. RFC - * states that events when retransmit arrives after original data are rare. - * It is a blatant lie. VJ forgot about fast retransmit! 8)8) It is - * the biggest problem on large power networks even with minor reordering. - * OK, let's give it small replay window. If peer clock is even 1hz, it is safe - * up to bandwidth of 18Gigabit/sec. 8) ] - */ - -static int tcp_disordered_ack(const struct sock *sk, const struct sk_buff *skb) -{ - const struct tcp_sock *tp = tcp_sk(sk); - const struct tcphdr *th = tcp_hdr(skb); - u32 seq = TCP_SKB_CB(skb)->seq; - u32 ack = TCP_SKB_CB(skb)->ack_seq; - - return (/* 1. Pure ACK with correct sequence number. */ - (th->ack && seq == TCP_SKB_CB(skb)->end_seq && seq == tp->rcv_nxt) && - - /* 2. ... and duplicate ACK. */ - ack == tp->snd_una && - - /* 3. ... and does not update window. */ - !tcp_may_update_window(tp, ack, seq, ntohs(th->window) << tp->rx_opt.snd_wscale) && - - /* 4. ... and sits in replay window. */ - (s32)(tp->rx_opt.ts_recent - tp->rx_opt.rcv_tsval) <= (inet_csk(sk)->icsk_rto * 1024) / HZ); -} - -static inline bool tcp_paws_discard(const struct sock *sk, - const struct sk_buff *skb) -{ - const struct tcp_sock *tp = tcp_sk(sk); - - return !tcp_paws_check(&tp->rx_opt, TCP_PAWS_WINDOW) && - !tcp_disordered_ack(sk, skb); -} - -/* Check segment sequence number for validity. - * - * Segment controls are considered valid, if the segment - * fits to the window after truncation to the window. Acceptability - * of data (and SYN, FIN, of course) is checked separately. - * See tcp_data_queue(), for example. - * - * Also, controls (RST is main one) are accepted using RCV.WUP instead - * of RCV.NXT. Peer still did not advance his SND.UNA when we - * delayed ACK, so that hisSND.UNA<=ourRCV.WUP. - * (borrowed from freebsd) - */ - -static inline bool tcp_sequence(const struct tcp_sock *tp, u32 seq, u32 end_seq) -{ - return !before(end_seq, tp->rcv_wup) && - !after(seq, tp->rcv_nxt + tcp_receive_window(tp)); -} - -/* When we get a reset we do this. */ -void tcp_reset(struct sock *sk) -{ - /* We want the right error as BSD sees it (and indeed as we do). */ - switch (sk->sk_state) { - case TCP_SYN_SENT: - sk->sk_err = ECONNREFUSED; - break; - case TCP_CLOSE_WAIT: - sk->sk_err = EPIPE; - break; - case TCP_CLOSE: - return; - default: - sk->sk_err = ECONNRESET; - } - /* This barrier is coupled with smp_rmb() in tcp_poll() */ - smp_wmb(); - - if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_error_report(sk); - - tcp_done(sk); -} - -/* - * Process the FIN bit. This now behaves as it is supposed to work - * and the FIN takes effect when it is validly part of sequence - * space. Not before when we get holes. - * - * If we are ESTABLISHED, a received fin moves us to CLOSE-WAIT - * (and thence onto LAST-ACK and finally, CLOSE, we never enter - * TIME-WAIT) - * - * If we are in FINWAIT-1, a received FIN indicates simultaneous - * close and we go into CLOSING (and later onto TIME-WAIT) - * - * If we are in FINWAIT-2, a received FIN moves us to TIME-WAIT. - */ -void tcp_fin(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - - inet_csk_schedule_ack(sk); - - sk->sk_shutdown |= RCV_SHUTDOWN; - sock_set_flag(sk, SOCK_DONE); - - switch (sk->sk_state) { - case TCP_SYN_RECV: - case TCP_ESTABLISHED: - /* Move to CLOSE_WAIT */ - tcp_set_state(sk, TCP_CLOSE_WAIT); - inet_csk(sk)->icsk_ack.pingpong = 1; - break; - - case TCP_CLOSE_WAIT: - case TCP_CLOSING: - /* Received a retransmission of the FIN, do - * nothing. - */ - break; - case TCP_LAST_ACK: - /* RFC793: Remain in the LAST-ACK state. */ - break; - - case TCP_FIN_WAIT1: - /* This case occurs when a simultaneous close - * happens, we must ack the received FIN and - * enter the CLOSING state. - */ - tcp_send_ack(sk); - tcp_set_state(sk, TCP_CLOSING); - break; - case TCP_FIN_WAIT2: - /* Received a FIN -- send ACK and enter TIME_WAIT. */ - tcp_send_ack(sk); - tcp_time_wait(sk, TCP_TIME_WAIT, 0); - break; - default: - /* Only TCP_LISTEN and TCP_CLOSE are left, in these - * cases we should never reach this piece of code. - */ - pr_err("%s: Impossible, sk->sk_state=%d\n", - __func__, sk->sk_state); - break; - } - - /* It _is_ possible, that we have something out-of-order _after_ FIN. - * Probably, we should reset in this case. For now drop them. - */ - skb_rbtree_purge(&tp->out_of_order_queue); - if (tcp_is_sack(tp)) - tcp_sack_reset(&tp->rx_opt); - sk_mem_reclaim(sk); - - if (!sock_flag(sk, SOCK_DEAD)) { - sk->sk_state_change(sk); - - /* Do not send POLL_HUP for half duplex close. */ - if (sk->sk_shutdown == SHUTDOWN_MASK || - sk->sk_state == TCP_CLOSE) - sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_HUP); - else - sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_IN); - } -} - -static inline bool tcp_sack_extend(struct tcp_sack_block *sp, u32 seq, - u32 end_seq) -{ - if (!after(seq, sp->end_seq) && !after(sp->start_seq, end_seq)) { - if (before(seq, sp->start_seq)) - sp->start_seq = seq; - if (after(end_seq, sp->end_seq)) - sp->end_seq = end_seq; - return true; - } - return false; -} - -static void tcp_dsack_set(struct sock *sk, u32 seq, u32 end_seq) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (tcp_is_sack(tp) && sysctl_tcp_dsack) { - int mib_idx; - - if (before(seq, tp->rcv_nxt)) - mib_idx = LINUX_MIB_TCPDSACKOLDSENT; - else - mib_idx = LINUX_MIB_TCPDSACKOFOSENT; - - NET_INC_STATS(sock_net(sk), mib_idx); - - tp->rx_opt.dsack = 1; - tp->duplicate_sack[0].start_seq = seq; - tp->duplicate_sack[0].end_seq = end_seq; - } -} - -static void tcp_dsack_extend(struct sock *sk, u32 seq, u32 end_seq) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (!tp->rx_opt.dsack) - tcp_dsack_set(sk, seq, end_seq); - else - tcp_sack_extend(tp->duplicate_sack, seq, end_seq); -} - -static void tcp_send_dupack(struct sock *sk, const struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && - before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOST); - tcp_enter_quickack_mode(sk); - - if (tcp_is_sack(tp) && sysctl_tcp_dsack) { - u32 end_seq = TCP_SKB_CB(skb)->end_seq; - - if (after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) - end_seq = tp->rcv_nxt; - tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, end_seq); - } - } - - tcp_send_ack(sk); -} - -/* These routines update the SACK block as out-of-order packets arrive or - * in-order packets close up the sequence space. - */ -static void tcp_sack_maybe_coalesce(struct tcp_sock *tp) -{ - int this_sack; - struct tcp_sack_block *sp = &tp->selective_acks[0]; - struct tcp_sack_block *swalk = sp + 1; - - /* See if the recent change to the first SACK eats into - * or hits the sequence space of other SACK blocks, if so coalesce. - */ - for (this_sack = 1; this_sack < tp->rx_opt.num_sacks;) { - if (tcp_sack_extend(sp, swalk->start_seq, swalk->end_seq)) { - int i; - - /* Zap SWALK, by moving every further SACK up by one slot. - * Decrease num_sacks. - */ - tp->rx_opt.num_sacks--; - for (i = this_sack; i < tp->rx_opt.num_sacks; i++) - sp[i] = sp[i + 1]; - continue; - } - this_sack++, swalk++; - } -} - -static void tcp_sack_new_ofo_skb(struct sock *sk, u32 seq, u32 end_seq) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct tcp_sack_block *sp = &tp->selective_acks[0]; - int cur_sacks = tp->rx_opt.num_sacks; - int this_sack; - - if (!cur_sacks) - goto new_sack; - - for (this_sack = 0; this_sack < cur_sacks; this_sack++, sp++) { - if (tcp_sack_extend(sp, seq, end_seq)) { - /* Rotate this_sack to the first one. */ - for (; this_sack > 0; this_sack--, sp--) - swap(*sp, *(sp - 1)); - if (cur_sacks > 1) - tcp_sack_maybe_coalesce(tp); - return; - } - } - - /* Could not find an adjacent existing SACK, build a new one, - * put it at the front, and shift everyone else down. We - * always know there is at least one SACK present already here. - * - * If the sack array is full, forget about the last one. - */ - if (this_sack >= TCP_NUM_SACKS) { - this_sack--; - tp->rx_opt.num_sacks--; - sp--; - } - for (; this_sack > 0; this_sack--, sp--) - *sp = *(sp - 1); - -new_sack: - /* Build the new head SACK, and we're done. */ - sp->start_seq = seq; - sp->end_seq = end_seq; - tp->rx_opt.num_sacks++; -} - -/* RCV.NXT advances, some SACKs should be eaten. */ - -static void tcp_sack_remove(struct tcp_sock *tp) -{ - struct tcp_sack_block *sp = &tp->selective_acks[0]; - int num_sacks = tp->rx_opt.num_sacks; - int this_sack; - - /* Empty ofo queue, hence, all the SACKs are eaten. Clear. */ - if (RB_EMPTY_ROOT(&tp->out_of_order_queue)) { - tp->rx_opt.num_sacks = 0; - return; - } - - for (this_sack = 0; this_sack < num_sacks;) { - /* Check if the start of the sack is covered by RCV.NXT. */ - if (!before(tp->rcv_nxt, sp->start_seq)) { - int i; - - /* RCV.NXT must cover all the block! */ - WARN_ON(before(tp->rcv_nxt, sp->end_seq)); - - /* Zap this SACK, by moving forward any other SACKS. */ - for (i = this_sack+1; i < num_sacks; i++) - tp->selective_acks[i-1] = tp->selective_acks[i]; - num_sacks--; - continue; - } - this_sack++; - sp++; - } - tp->rx_opt.num_sacks = num_sacks; -} - -/** - * tcp_try_coalesce - try to merge skb to prior one - * @sk: socket - * @to: prior buffer - * @from: buffer to add in queue - * @fragstolen: pointer to boolean - * - * Before queueing skb @from after @to, try to merge them - * to reduce overall memory use and queue lengths, if cost is small. - * Packets in ofo or receive queues can stay a long time. - * Better try to coalesce them right now to avoid future collapses. - * Returns true if caller should free @from instead of queueing it - */ -static bool tcp_try_coalesce(struct sock *sk, - struct sk_buff *to, - struct sk_buff *from, - bool *fragstolen) -{ - int delta; - - *fragstolen = false; - - /* Its possible this segment overlaps with prior segment in queue */ - if (TCP_SKB_CB(from)->seq != TCP_SKB_CB(to)->end_seq) - return false; - - if (!skb_try_coalesce(to, from, fragstolen, &delta)) - return false; - - atomic_add(delta, &sk->sk_rmem_alloc); - sk_mem_charge(sk, delta); - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRCVCOALESCE); - TCP_SKB_CB(to)->end_seq = TCP_SKB_CB(from)->end_seq; - TCP_SKB_CB(to)->ack_seq = TCP_SKB_CB(from)->ack_seq; - TCP_SKB_CB(to)->tcp_flags |= TCP_SKB_CB(from)->tcp_flags; - return true; -} - -static void tcp_drop(struct sock *sk, struct sk_buff *skb) -{ - sk_drops_add(sk, skb); - __kfree_skb(skb); -} - -/* This one checks to see if we can put data from the - * out_of_order queue into the receive_queue. - */ -static void tcp_ofo_queue(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - __u32 dsack_high = tp->rcv_nxt; - bool fin, fragstolen, eaten; - struct sk_buff *skb, *tail; - struct rb_node *p; - - p = rb_first(&tp->out_of_order_queue); - while (p) { - skb = rb_entry(p, struct sk_buff, rbnode); - if (after(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) - break; - - if (before(TCP_SKB_CB(skb)->seq, dsack_high)) { - __u32 dsack = dsack_high; - if (before(TCP_SKB_CB(skb)->end_seq, dsack_high)) - dsack_high = TCP_SKB_CB(skb)->end_seq; - tcp_dsack_extend(sk, TCP_SKB_CB(skb)->seq, dsack); - } - p = rb_next(p); - rb_erase(&skb->rbnode, &tp->out_of_order_queue); - - if (unlikely(!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt))) { - SOCK_DEBUG(sk, "ofo packet was already received\n"); - tcp_drop(sk, skb); - continue; - } - SOCK_DEBUG(sk, "ofo requeuing : rcv_next %X seq %X - %X\n", - tp->rcv_nxt, TCP_SKB_CB(skb)->seq, - TCP_SKB_CB(skb)->end_seq); - - tail = skb_peek_tail(&sk->sk_receive_queue); - eaten = tail && tcp_try_coalesce(sk, tail, skb, &fragstolen); - tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq); - fin = TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN; - if (!eaten) - __skb_queue_tail(&sk->sk_receive_queue, skb); - else - kfree_skb_partial(skb, fragstolen); - - if (unlikely(fin)) { - tcp_fin(sk); - /* tcp_fin() purges tp->out_of_order_queue, - * so we must end this loop right now. - */ - break; - } - } -} - -static bool tcp_prune_ofo_queue(struct sock *sk); -static int tcp_prune_queue(struct sock *sk); - -static int tcp_try_rmem_schedule(struct sock *sk, struct sk_buff *skb, - unsigned int size) -{ - if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || - !sk_rmem_schedule(sk, skb, size)) { - - if (tcp_prune_queue(sk) < 0) - return -1; - - while (!sk_rmem_schedule(sk, skb, size)) { - if (!tcp_prune_ofo_queue(sk)) - return -1; - } - } - return 0; -} - -static void tcp_data_queue_ofo(struct sock *sk, struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct rb_node **p, *q, *parent; - struct sk_buff *skb1; - u32 seq, end_seq; - bool fragstolen; - - tcp_ecn_check_ce(tp, skb); - - if (unlikely(tcp_try_rmem_schedule(sk, skb, skb->truesize))) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPOFODROP); - tcp_drop(sk, skb); - return; - } - - /* Disable header prediction. */ - tp->pred_flags = 0; - inet_csk_schedule_ack(sk); - - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPOFOQUEUE); - seq = TCP_SKB_CB(skb)->seq; - end_seq = TCP_SKB_CB(skb)->end_seq; - SOCK_DEBUG(sk, "out of order segment: rcv_next %X seq %X - %X\n", - tp->rcv_nxt, seq, end_seq); - - p = &tp->out_of_order_queue.rb_node; - if (RB_EMPTY_ROOT(&tp->out_of_order_queue)) { - /* Initial out of order segment, build 1 SACK. */ - if (tcp_is_sack(tp)) { - tp->rx_opt.num_sacks = 1; - tp->selective_acks[0].start_seq = seq; - tp->selective_acks[0].end_seq = end_seq; - } - rb_link_node(&skb->rbnode, NULL, p); - rb_insert_color(&skb->rbnode, &tp->out_of_order_queue); - tp->ooo_last_skb = skb; - goto end; - } - - /* In the typical case, we are adding an skb to the end of the list. - * Use of ooo_last_skb avoids the O(Log(N)) rbtree lookup. - */ - if (tcp_try_coalesce(sk, tp->ooo_last_skb, skb, &fragstolen)) { -coalesce_done: - tcp_grow_window(sk, skb); - kfree_skb_partial(skb, fragstolen); - skb = NULL; - goto add_sack; - } - /* Can avoid an rbtree lookup if we are adding skb after ooo_last_skb */ - if (!before(seq, TCP_SKB_CB(tp->ooo_last_skb)->end_seq)) { - parent = &tp->ooo_last_skb->rbnode; - p = &parent->rb_right; - goto insert; - } - - /* Find place to insert this segment. Handle overlaps on the way. */ - parent = NULL; - while (*p) { - parent = *p; - skb1 = rb_entry(parent, struct sk_buff, rbnode); - if (before(seq, TCP_SKB_CB(skb1)->seq)) { - p = &parent->rb_left; - continue; - } - if (before(seq, TCP_SKB_CB(skb1)->end_seq)) { - if (!after(end_seq, TCP_SKB_CB(skb1)->end_seq)) { - /* All the bits are present. Drop. */ - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPOFOMERGE); - __kfree_skb(skb); - skb = NULL; - tcp_dsack_set(sk, seq, end_seq); - goto add_sack; - } - if (after(seq, TCP_SKB_CB(skb1)->seq)) { - /* Partial overlap. */ - tcp_dsack_set(sk, seq, TCP_SKB_CB(skb1)->end_seq); - } else { - /* skb's seq == skb1's seq and skb covers skb1. - * Replace skb1 with skb. - */ - rb_replace_node(&skb1->rbnode, &skb->rbnode, - &tp->out_of_order_queue); - tcp_dsack_extend(sk, - TCP_SKB_CB(skb1)->seq, - TCP_SKB_CB(skb1)->end_seq); - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPOFOMERGE); - __kfree_skb(skb1); - goto merge_right; - } - } else if (tcp_try_coalesce(sk, skb1, skb, &fragstolen)) { - goto coalesce_done; - } - p = &parent->rb_right; - } -insert: - /* Insert segment into RB tree. */ - rb_link_node(&skb->rbnode, parent, p); - rb_insert_color(&skb->rbnode, &tp->out_of_order_queue); - -merge_right: - /* Remove other segments covered by skb. */ - while ((q = rb_next(&skb->rbnode)) != NULL) { - skb1 = rb_entry(q, struct sk_buff, rbnode); - - if (!after(end_seq, TCP_SKB_CB(skb1)->seq)) - break; - if (before(end_seq, TCP_SKB_CB(skb1)->end_seq)) { - tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq, - end_seq); - break; - } - rb_erase(&skb1->rbnode, &tp->out_of_order_queue); - tcp_dsack_extend(sk, TCP_SKB_CB(skb1)->seq, - TCP_SKB_CB(skb1)->end_seq); - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPOFOMERGE); - tcp_drop(sk, skb1); - } - /* If there is no skb after us, we are the last_skb ! */ - if (!q) - tp->ooo_last_skb = skb; - -add_sack: - if (tcp_is_sack(tp)) - tcp_sack_new_ofo_skb(sk, seq, end_seq); -end: - if (skb) { - tcp_grow_window(sk, skb); - skb_set_owner_r(skb, sk); - } -} - -static int __must_check tcp_queue_rcv(struct sock *sk, struct sk_buff *skb, int hdrlen, - bool *fragstolen) -{ - int eaten; - struct sk_buff *tail = skb_peek_tail(&sk->sk_receive_queue); - - __skb_pull(skb, hdrlen); - eaten = (tail && - tcp_try_coalesce(sk, tail, skb, fragstolen)) ? 1 : 0; - tcp_rcv_nxt_update(tcp_sk(sk), TCP_SKB_CB(skb)->end_seq); - if (!eaten) { - __skb_queue_tail(&sk->sk_receive_queue, skb); - skb_set_owner_r(skb, sk); - } - return eaten; -} - -int tcp_send_rcvq(struct sock *sk, struct msghdr *msg, size_t size) -{ - struct sk_buff *skb; - int err = -ENOMEM; - int data_len = 0; - bool fragstolen; - - if (size == 0) - return 0; - - if (size > PAGE_SIZE) { - int npages = min_t(size_t, size >> PAGE_SHIFT, MAX_SKB_FRAGS); - - data_len = npages << PAGE_SHIFT; - size = data_len + (size & ~PAGE_MASK); - } - skb = alloc_skb_with_frags(size - data_len, data_len, - PAGE_ALLOC_COSTLY_ORDER, - &err, sk->sk_allocation); - if (!skb) - goto err; - - skb_put(skb, size - data_len); - skb->data_len = data_len; - skb->len = size; - - if (tcp_try_rmem_schedule(sk, skb, skb->truesize)) - goto err_free; - - err = skb_copy_datagram_from_iter(skb, 0, &msg->msg_iter, size); - if (err) - goto err_free; - - TCP_SKB_CB(skb)->seq = tcp_sk(sk)->rcv_nxt; - TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + size; - TCP_SKB_CB(skb)->ack_seq = tcp_sk(sk)->snd_una - 1; - - if (tcp_queue_rcv(sk, skb, 0, &fragstolen)) { - WARN_ON_ONCE(fragstolen); /* should not happen */ - __kfree_skb(skb); - } - return size; - -err_free: - kfree_skb(skb); -err: - return err; - -} - -static void tcp_data_queue(struct sock *sk, struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - bool fragstolen = false; - int eaten = -1; - - if (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq) { - __kfree_skb(skb); - return; - } - skb_dst_drop(skb); - __skb_pull(skb, tcp_hdr(skb)->doff * 4); - - tcp_ecn_accept_cwr(tp, skb); - - tp->rx_opt.dsack = 0; - - /* Queue data for delivery to the user. - * Packets in sequence go to the receive queue. - * Out of sequence packets to the out_of_order_queue. - */ - if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt) { - if (tcp_receive_window(tp) == 0) - goto out_of_window; - - /* Ok. In sequence. In window. */ - if (tp->ucopy.task == current && - tp->copied_seq == tp->rcv_nxt && tp->ucopy.len && - sock_owned_by_user(sk) && !tp->urg_data) { - int chunk = min_t(unsigned int, skb->len, - tp->ucopy.len); - - __set_current_state(TASK_RUNNING); - - if (!skb_copy_datagram_msg(skb, 0, tp->ucopy.msg, chunk)) { - tp->ucopy.len -= chunk; - tp->copied_seq += chunk; - eaten = (chunk == skb->len); - tcp_rcv_space_adjust(sk); - } - } - - if (eaten <= 0) { -queue_and_out: - if (eaten < 0) { - if (skb_queue_len(&sk->sk_receive_queue) == 0) - sk_forced_mem_schedule(sk, skb->truesize); - else if (tcp_try_rmem_schedule(sk, skb, skb->truesize)) - goto drop; - } - eaten = tcp_queue_rcv(sk, skb, 0, &fragstolen); - } - tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq); - if (skb->len) - tcp_event_data_recv(sk, skb); - if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) - tcp_fin(sk); - - if (!RB_EMPTY_ROOT(&tp->out_of_order_queue)) { - tcp_ofo_queue(sk); - - /* RFC2581. 4.2. SHOULD send immediate ACK, when - * gap in queue is filled. - */ - if (RB_EMPTY_ROOT(&tp->out_of_order_queue)) - inet_csk(sk)->icsk_ack.pingpong = 0; - } - - if (tp->rx_opt.num_sacks) - tcp_sack_remove(tp); - - tcp_fast_path_check(sk); - - if (eaten > 0) - kfree_skb_partial(skb, fragstolen); - if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_data_ready(sk); - return; - } - - if (!after(TCP_SKB_CB(skb)->end_seq, tp->rcv_nxt)) { - /* A retransmit, 2nd most common case. Force an immediate ack. */ - NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOST); - tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq); - -out_of_window: - tcp_enter_quickack_mode(sk); - inet_csk_schedule_ack(sk); -drop: - tcp_drop(sk, skb); - return; - } - - /* Out of window. F.e. zero window probe. */ - if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt + tcp_receive_window(tp))) - goto out_of_window; - - tcp_enter_quickack_mode(sk); - - if (before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { - /* Partial packet, seq < rcv_next < end_seq */ - SOCK_DEBUG(sk, "partial packet: rcv_next %X seq %X - %X\n", - tp->rcv_nxt, TCP_SKB_CB(skb)->seq, - TCP_SKB_CB(skb)->end_seq); - - tcp_dsack_set(sk, TCP_SKB_CB(skb)->seq, tp->rcv_nxt); - - /* If window is closed, drop tail of packet. But after - * remembering D-SACK for its head made in previous line. - */ - if (!tcp_receive_window(tp)) - goto out_of_window; - goto queue_and_out; - } - - tcp_data_queue_ofo(sk, skb); -} - -static struct sk_buff *tcp_skb_next(struct sk_buff *skb, struct sk_buff_head *list) -{ - if (list) - return !skb_queue_is_last(list, skb) ? skb->next : NULL; - - return rb_entry_safe(rb_next(&skb->rbnode), struct sk_buff, rbnode); -} - -static struct sk_buff *tcp_collapse_one(struct sock *sk, struct sk_buff *skb, - struct sk_buff_head *list, - struct rb_root *root) -{ - struct sk_buff *next = tcp_skb_next(skb, list); - - if (list) - __skb_unlink(skb, list); - else - rb_erase(&skb->rbnode, root); - - __kfree_skb(skb); - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRCVCOLLAPSED); - - return next; -} - -/* Insert skb into rb tree, ordered by TCP_SKB_CB(skb)->seq */ -static void tcp_rbtree_insert(struct rb_root *root, struct sk_buff *skb) -{ - struct rb_node **p = &root->rb_node; - struct rb_node *parent = NULL; - struct sk_buff *skb1; - - while (*p) { - parent = *p; - skb1 = rb_entry(parent, struct sk_buff, rbnode); - if (before(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb1)->seq)) - p = &parent->rb_left; - else - p = &parent->rb_right; - } - rb_link_node(&skb->rbnode, parent, p); - rb_insert_color(&skb->rbnode, root); -} - -/* Collapse contiguous sequence of skbs head..tail with - * sequence numbers start..end. - * - * If tail is NULL, this means until the end of the queue. - * - * Segments with FIN/SYN are not collapsed (only because this - * simplifies code) - */ -static void -tcp_collapse(struct sock *sk, struct sk_buff_head *list, struct rb_root *root, - struct sk_buff *head, struct sk_buff *tail, u32 start, u32 end) -{ - struct sk_buff *skb = head, *n; - struct sk_buff_head tmp; - bool end_of_skbs; - - /* First, check that queue is collapsible and find - * the point where collapsing can be useful. - */ -restart: - for (end_of_skbs = true; skb != NULL && skb != tail; skb = n) { - n = tcp_skb_next(skb, list); - - /* No new bits? It is possible on ofo queue. */ - if (!before(start, TCP_SKB_CB(skb)->end_seq)) { - skb = tcp_collapse_one(sk, skb, list, root); - if (!skb) - break; - goto restart; - } - - /* The first skb to collapse is: - * - not SYN/FIN and - * - bloated or contains data before "start" or - * overlaps to the next one. - */ - if (!(TCP_SKB_CB(skb)->tcp_flags & (TCPHDR_SYN | TCPHDR_FIN)) && - (tcp_win_from_space(skb->truesize) > skb->len || - before(TCP_SKB_CB(skb)->seq, start))) { - end_of_skbs = false; - break; - } - - if (n && n != tail && - TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(n)->seq) { - end_of_skbs = false; - break; - } - - /* Decided to skip this, advance start seq. */ - start = TCP_SKB_CB(skb)->end_seq; - } - if (end_of_skbs || - (TCP_SKB_CB(skb)->tcp_flags & (TCPHDR_SYN | TCPHDR_FIN))) - return; - - __skb_queue_head_init(&tmp); - - while (before(start, end)) { - int copy = min_t(int, SKB_MAX_ORDER(0, 0), end - start); - struct sk_buff *nskb; - - nskb = alloc_skb(copy, GFP_ATOMIC); - if (!nskb) - break; - - memcpy(nskb->cb, skb->cb, sizeof(skb->cb)); - TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(nskb)->end_seq = start; - if (list) - __skb_queue_before(list, skb, nskb); - else - __skb_queue_tail(&tmp, nskb); /* defer rbtree insertion */ - skb_set_owner_r(nskb, sk); - - /* Copy data, releasing collapsed skbs. */ - while (copy > 0) { - int offset = start - TCP_SKB_CB(skb)->seq; - int size = TCP_SKB_CB(skb)->end_seq - start; - - BUG_ON(offset < 0); - if (size > 0) { - size = min(copy, size); - if (skb_copy_bits(skb, offset, skb_put(nskb, size), size)) - BUG(); - TCP_SKB_CB(nskb)->end_seq += size; - copy -= size; - start += size; - } - if (!before(start, TCP_SKB_CB(skb)->end_seq)) { - skb = tcp_collapse_one(sk, skb, list, root); - if (!skb || - skb == tail || - (TCP_SKB_CB(skb)->tcp_flags & (TCPHDR_SYN | TCPHDR_FIN))) - goto end; - } - } - } -end: - skb_queue_walk_safe(&tmp, skb, n) - tcp_rbtree_insert(root, skb); -} - -/* Collapse ofo queue. Algorithm: select contiguous sequence of skbs - * and tcp_collapse() them until all the queue is collapsed. - */ -static void tcp_collapse_ofo_queue(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *skb, *head; - struct rb_node *p; - u32 start, end; - - p = rb_first(&tp->out_of_order_queue); - skb = rb_entry_safe(p, struct sk_buff, rbnode); -new_range: - if (!skb) { - p = rb_last(&tp->out_of_order_queue); - /* Note: This is possible p is NULL here. We do not - * use rb_entry_safe(), as ooo_last_skb is valid only - * if rbtree is not empty. - */ - tp->ooo_last_skb = rb_entry(p, struct sk_buff, rbnode); - return; - } - start = TCP_SKB_CB(skb)->seq; - end = TCP_SKB_CB(skb)->end_seq; - - for (head = skb;;) { - skb = tcp_skb_next(skb, NULL); - - /* Range is terminated when we see a gap or when - * we are at the queue end. - */ - if (!skb || - after(TCP_SKB_CB(skb)->seq, end) || - before(TCP_SKB_CB(skb)->end_seq, start)) { - tcp_collapse(sk, NULL, &tp->out_of_order_queue, - head, skb, start, end); - goto new_range; - } - - if (unlikely(before(TCP_SKB_CB(skb)->seq, start))) - start = TCP_SKB_CB(skb)->seq; - if (after(TCP_SKB_CB(skb)->end_seq, end)) - end = TCP_SKB_CB(skb)->end_seq; - } -} - -/* - * Clean the out-of-order queue to make room. - * We drop high sequences packets to : - * 1) Let a chance for holes to be filled. - * 2) not add too big latencies if thousands of packets sit there. - * (But if application shrinks SO_RCVBUF, we could still end up - * freeing whole queue here) - * - * Return true if queue has shrunk. - */ -static bool tcp_prune_ofo_queue(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct rb_node *node, *prev; - - if (RB_EMPTY_ROOT(&tp->out_of_order_queue)) - return false; - - NET_INC_STATS(sock_net(sk), LINUX_MIB_OFOPRUNED); - node = &tp->ooo_last_skb->rbnode; - do { - prev = rb_prev(node); - rb_erase(node, &tp->out_of_order_queue); - tcp_drop(sk, rb_entry(node, struct sk_buff, rbnode)); - sk_mem_reclaim(sk); - if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf && - !tcp_under_memory_pressure(sk)) - break; - node = prev; - } while (node); - tp->ooo_last_skb = rb_entry(prev, struct sk_buff, rbnode); - - /* Reset SACK state. A conforming SACK implementation will - * do the same at a timeout based retransmit. When a connection - * is in a sad state like this, we care only about integrity - * of the connection not performance. - */ - if (tp->rx_opt.sack_ok) - tcp_sack_reset(&tp->rx_opt); - return true; -} - -/* Reduce allocated memory if we can, trying to get - * the socket within its memory limits again. - * - * Return less than zero if we should start dropping frames - * until the socket owning process reads some of the data - * to stabilize the situation. - */ -static int tcp_prune_queue(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - - SOCK_DEBUG(sk, "prune_queue: c=%x\n", tp->copied_seq); - - NET_INC_STATS(sock_net(sk), LINUX_MIB_PRUNECALLED); - - if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) - tcp_clamp_window(sk); - else if (tcp_under_memory_pressure(sk)) - tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss); - - tcp_collapse_ofo_queue(sk); - if (!skb_queue_empty(&sk->sk_receive_queue)) - tcp_collapse(sk, &sk->sk_receive_queue, NULL, - skb_peek(&sk->sk_receive_queue), - NULL, - tp->copied_seq, tp->rcv_nxt); - sk_mem_reclaim(sk); - - if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) - return 0; - - /* Collapsing did not help, destructive actions follow. - * This must not ever occur. */ - - tcp_prune_ofo_queue(sk); - - if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) - return 0; - - /* If we are really being abused, tell the caller to silently - * drop receive data on the floor. It will get retransmitted - * and hopefully then we'll have sufficient space. - */ - NET_INC_STATS(sock_net(sk), LINUX_MIB_RCVPRUNED); - - /* Massive buffer overcommit. */ - tp->pred_flags = 0; - return -1; -} - -static bool tcp_should_expand_sndbuf(const struct sock *sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - - /* If the user specified a specific send buffer setting, do - * not modify it. - */ - if (sk->sk_userlocks & SOCK_SNDBUF_LOCK) - return false; - - /* If we are under global TCP memory pressure, do not expand. */ - if (tcp_under_memory_pressure(sk)) - return false; - - /* If we are under soft global TCP memory pressure, do not expand. */ - if (sk_memory_allocated(sk) >= sk_prot_mem_limits(sk, 0)) - return false; - - /* If we filled the congestion window, do not expand. */ - if (tcp_packets_in_flight(tp) >= tp->snd_cwnd) - return false; - - return true; -} - -/* When incoming ACK allowed to free some skb from write_queue, - * we remember this event in flag SOCK_QUEUE_SHRUNK and wake up socket - * on the exit from tcp input handler. - * - * PROBLEM: sndbuf expansion does not work well with largesend. - */ -static void tcp_new_space(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (tcp_should_expand_sndbuf(sk)) { - tcp_sndbuf_expand(sk); - tp->snd_cwnd_stamp = tcp_time_stamp; - } - - sk->sk_write_space(sk); -} - -static void tcp_check_space(struct sock *sk) -{ - if (sock_flag(sk, SOCK_QUEUE_SHRUNK)) { - sock_reset_flag(sk, SOCK_QUEUE_SHRUNK); - /* pairs with tcp_poll() */ - smp_mb__after_atomic(); - if (sk->sk_socket && - test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) - tcp_new_space(sk); - } -} - -static inline void tcp_data_snd_check(struct sock *sk) -{ - tcp_push_pending_frames(sk); - tcp_check_space(sk); -} - -/* - * Check if sending an ack is needed. - */ -static void __tcp_ack_snd_check(struct sock *sk, int ofo_possible) -{ - struct tcp_sock *tp = tcp_sk(sk); - - /* More than one full frame received... */ - if (((tp->rcv_nxt - tp->rcv_wup) > inet_csk(sk)->icsk_ack.rcv_mss && - /* ... and right edge of window advances far enough. - * (tcp_recvmsg() will send ACK otherwise). Or... - */ - __tcp_select_window(sk) >= tp->rcv_wnd) || - /* We ACK each frame or... */ - tcp_in_quickack_mode(sk) || - /* We have out of order data. */ - (ofo_possible && !RB_EMPTY_ROOT(&tp->out_of_order_queue))) { - /* Then ack it now */ - tcp_send_ack(sk); - } else { - /* Else, send delayed ack. */ - tcp_send_delayed_ack(sk); - } -} - -static inline void tcp_ack_snd_check(struct sock *sk) -{ - if (!inet_csk_ack_scheduled(sk)) { - /* We sent a data segment already. */ - return; - } - __tcp_ack_snd_check(sk, 1); -} - -/* - * This routine is only called when we have urgent data - * signaled. Its the 'slow' part of tcp_urg. It could be - * moved inline now as tcp_urg is only called from one - * place. We handle URGent data wrong. We have to - as - * BSD still doesn't use the correction from RFC961. - * For 1003.1g we should support a new option TCP_STDURG to permit - * either form (or just set the sysctl tcp_stdurg). - */ - -static void tcp_check_urg(struct sock *sk, const struct tcphdr *th) -{ - struct tcp_sock *tp = tcp_sk(sk); - u32 ptr = ntohs(th->urg_ptr); - - if (ptr && !sysctl_tcp_stdurg) - ptr--; - ptr += ntohl(th->seq); - - /* Ignore urgent data that we've already seen and read. */ - if (after(tp->copied_seq, ptr)) - return; - - /* Do not replay urg ptr. - * - * NOTE: interesting situation not covered by specs. - * Misbehaving sender may send urg ptr, pointing to segment, - * which we already have in ofo queue. We are not able to fetch - * such data and will stay in TCP_URG_NOTYET until will be eaten - * by recvmsg(). Seems, we are not obliged to handle such wicked - * situations. But it is worth to think about possibility of some - * DoSes using some hypothetical application level deadlock. - */ - if (before(ptr, tp->rcv_nxt)) - return; - - /* Do we already have a newer (or duplicate) urgent pointer? */ - if (tp->urg_data && !after(ptr, tp->urg_seq)) - return; - - /* Tell the world about our new urgent pointer. */ - sk_send_sigurg(sk); - - /* We may be adding urgent data when the last byte read was - * urgent. To do this requires some care. We cannot just ignore - * tp->copied_seq since we would read the last urgent byte again - * as data, nor can we alter copied_seq until this data arrives - * or we break the semantics of SIOCATMARK (and thus sockatmark()) - * - * NOTE. Double Dutch. Rendering to plain English: author of comment - * above did something sort of send("A", MSG_OOB); send("B", MSG_OOB); - * and expect that both A and B disappear from stream. This is _wrong_. - * Though this happens in BSD with high probability, this is occasional. - * Any application relying on this is buggy. Note also, that fix "works" - * only in this artificial test. Insert some normal data between A and B and we will - * decline of BSD again. Verdict: it is better to remove to trap - * buggy users. - */ - if (tp->urg_seq == tp->copied_seq && tp->urg_data && - !sock_flag(sk, SOCK_URGINLINE) && tp->copied_seq != tp->rcv_nxt) { - struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); - tp->copied_seq++; - if (skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq)) { - __skb_unlink(skb, &sk->sk_receive_queue); - __kfree_skb(skb); - } - } - - tp->urg_data = TCP_URG_NOTYET; - tp->urg_seq = ptr; - - /* Disable header prediction. */ - tp->pred_flags = 0; -} - -/* This is the 'fast' part of urgent handling. */ -static void tcp_urg(struct sock *sk, struct sk_buff *skb, const struct tcphdr *th) -{ - struct tcp_sock *tp = tcp_sk(sk); - - /* Check if we get a new urgent pointer - normally not. */ - if (th->urg) - tcp_check_urg(sk, th); - - /* Do we wait for any urgent data? - normally not... */ - if (tp->urg_data == TCP_URG_NOTYET) { - u32 ptr = tp->urg_seq - ntohl(th->seq) + (th->doff * 4) - - th->syn; - - /* Is the urgent pointer pointing into this packet? */ - if (ptr < skb->len) { - u8 tmp; - if (skb_copy_bits(skb, ptr, &tmp, 1)) - BUG(); - tp->urg_data = TCP_URG_VALID | tmp; - if (!sock_flag(sk, SOCK_DEAD)) - sk->sk_data_ready(sk); - } - } -} - -static int tcp_copy_to_iovec(struct sock *sk, struct sk_buff *skb, int hlen) -{ - struct tcp_sock *tp = tcp_sk(sk); - int chunk = skb->len - hlen; - int err; - - if (skb_csum_unnecessary(skb)) - err = skb_copy_datagram_msg(skb, hlen, tp->ucopy.msg, chunk); - else - err = skb_copy_and_csum_datagram_msg(skb, hlen, tp->ucopy.msg); - - if (!err) { - tp->ucopy.len -= chunk; - tp->copied_seq += chunk; - tcp_rcv_space_adjust(sk); - } - - return err; -} - -/* Does PAWS and seqno based validation of an incoming segment, flags will - * play significant role here. - */ -static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, - const struct tcphdr *th, int syn_inerr) -{ - struct tcp_sock *tp = tcp_sk(sk); - bool rst_seq_match = false; - - /* RFC1323: H1. Apply PAWS check first. */ - if (tcp_fast_parse_options(skb, th, tp) && tp->rx_opt.saw_tstamp && - tcp_paws_discard(sk, skb)) { - if (!th->rst) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED); - if (!tcp_oow_rate_limited(sock_net(sk), skb, - LINUX_MIB_TCPACKSKIPPEDPAWS, - &tp->last_oow_ack_time)) - tcp_send_dupack(sk, skb); - goto discard; - } - /* Reset is accepted even if it did not pass PAWS. */ - } - - /* Step 1: check sequence number */ - if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) { - /* RFC793, page 37: "In all states except SYN-SENT, all reset - * (RST) segments are validated by checking their SEQ-fields." - * And page 69: "If an incoming segment is not acceptable, - * an acknowledgment should be sent in reply (unless the RST - * bit is set, if so drop the segment and return)". - */ - if (!th->rst) { - if (th->syn) - goto syn_challenge; - if (!tcp_oow_rate_limited(sock_net(sk), skb, - LINUX_MIB_TCPACKSKIPPEDSEQ, - &tp->last_oow_ack_time)) - tcp_send_dupack(sk, skb); - } - goto discard; - } - - /* Step 2: check RST bit */ - if (th->rst) { - /* RFC 5961 3.2 (extend to match against SACK too if available): - * If seq num matches RCV.NXT or the right-most SACK block, - * then - * RESET the connection - * else - * Send a challenge ACK - */ - if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt) { - rst_seq_match = true; - } else if (tcp_is_sack(tp) && tp->rx_opt.num_sacks > 0) { - struct tcp_sack_block *sp = &tp->selective_acks[0]; - int max_sack = sp[0].end_seq; - int this_sack; - - for (this_sack = 1; this_sack < tp->rx_opt.num_sacks; - ++this_sack) { - max_sack = after(sp[this_sack].end_seq, - max_sack) ? - sp[this_sack].end_seq : max_sack; - } - - if (TCP_SKB_CB(skb)->seq == max_sack) - rst_seq_match = true; - } - - if (rst_seq_match) - tcp_reset(sk); - else - tcp_send_challenge_ack(sk, skb); - goto discard; - } - - /* step 3: check security and precedence [ignored] */ - - /* step 4: Check for a SYN - * RFC 5961 4.2 : Send a challenge ack - */ - if (th->syn) { -syn_challenge: - if (syn_inerr) - TCP_INC_STATS(sock_net(sk), TCP_MIB_INERRS); - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNCHALLENGE); - tcp_send_challenge_ack(sk, skb); - goto discard; - } - - return true; - -discard: - tcp_drop(sk, skb); - return false; -} - -/* - * TCP receive function for the ESTABLISHED state. - * - * It is split into a fast path and a slow path. The fast path is - * disabled when: - * - A zero window was announced from us - zero window probing - * is only handled properly in the slow path. - * - Out of order segments arrived. - * - Urgent data is expected. - * - There is no buffer space left - * - Unexpected TCP flags/window values/header lengths are received - * (detected by checking the TCP header against pred_flags) - * - Data is sent in both directions. Fast path only supports pure senders - * or pure receivers (this means either the sequence number or the ack - * value must stay constant) - * - Unexpected TCP option. - * - * When these conditions are not satisfied it drops into a standard - * receive procedure patterned after RFC793 to handle all cases. - * The first three cases are guaranteed by proper pred_flags setting, - * the rest is checked inline. Fast processing is turned on in - * tcp_data_queue when everything is OK. - */ -void tcp_rcv_established(struct sock *sk, struct sk_buff *skb, - const struct tcphdr *th, unsigned int len) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (unlikely(!sk->sk_rx_dst)) - inet_csk(sk)->icsk_af_ops->sk_rx_dst_set(sk, skb); - /* - * Header prediction. - * The code loosely follows the one in the famous - * "30 instruction TCP receive" Van Jacobson mail. - * - * Van's trick is to deposit buffers into socket queue - * on a device interrupt, to call tcp_recv function - * on the receive process context and checksum and copy - * the buffer to user space. smart... - * - * Our current scheme is not silly either but we take the - * extra cost of the net_bh soft interrupt processing... - * We do checksum and copy also but from device to kernel. - */ - - tp->rx_opt.saw_tstamp = 0; - - /* pred_flags is 0xS?10 << 16 + snd_wnd - * if header_prediction is to be made - * 'S' will always be tp->tcp_header_len >> 2 - * '?' will be 0 for the fast path, otherwise pred_flags is 0 to - * turn it off (when there are holes in the receive - * space for instance) - * PSH flag is ignored. - */ - - if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags && - TCP_SKB_CB(skb)->seq == tp->rcv_nxt && - !after(TCP_SKB_CB(skb)->ack_seq, tp->snd_nxt)) { - int tcp_header_len = tp->tcp_header_len; - - /* Timestamp header prediction: tcp_header_len - * is automatically equal to th->doff*4 due to pred_flags - * match. - */ - - /* Check timestamp */ - if (tcp_header_len == sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) { - /* No? Slow path! */ - if (!tcp_parse_aligned_timestamp(tp, th)) - goto slow_path; - - /* If PAWS failed, check it more carefully in slow path */ - if ((s32)(tp->rx_opt.rcv_tsval - tp->rx_opt.ts_recent) < 0) - goto slow_path; - - /* DO NOT update ts_recent here, if checksum fails - * and timestamp was corrupted part, it will result - * in a hung connection since we will drop all - * future packets due to the PAWS test. - */ - } - - if (len <= tcp_header_len) { - /* Bulk data transfer: sender */ - if (len == tcp_header_len) { - /* Predicted packet is in window by definition. - * seq == rcv_nxt and rcv_wup <= rcv_nxt. - * Hence, check seq<=rcv_wup reduces to: - */ - if (tcp_header_len == - (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) && - tp->rcv_nxt == tp->rcv_wup) - tcp_store_ts_recent(tp); - - /* We know that such packets are checksummed - * on entry. - */ - tcp_ack(sk, skb, 0); - __kfree_skb(skb); - tcp_data_snd_check(sk); - return; - } else { /* Header too small */ - TCP_INC_STATS(sock_net(sk), TCP_MIB_INERRS); - goto discard; - } - } else { - int eaten = 0; - bool fragstolen = false; - - if (tp->ucopy.task == current && - tp->copied_seq == tp->rcv_nxt && - len - tcp_header_len <= tp->ucopy.len && - sock_owned_by_user(sk)) { - __set_current_state(TASK_RUNNING); - - if (!tcp_copy_to_iovec(sk, skb, tcp_header_len)) { - /* Predicted packet is in window by definition. - * seq == rcv_nxt and rcv_wup <= rcv_nxt. - * Hence, check seq<=rcv_wup reduces to: - */ - if (tcp_header_len == - (sizeof(struct tcphdr) + - TCPOLEN_TSTAMP_ALIGNED) && - tp->rcv_nxt == tp->rcv_wup) - tcp_store_ts_recent(tp); - - tcp_rcv_rtt_measure_ts(sk, skb); - - __skb_pull(skb, tcp_header_len); - tcp_rcv_nxt_update(tp, TCP_SKB_CB(skb)->end_seq); - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPHPHITSTOUSER); - eaten = 1; - } - } - if (!eaten) { - if (tcp_checksum_complete(skb)) - goto csum_error; - - if ((int)skb->truesize > sk->sk_forward_alloc) - goto step5; - - /* Predicted packet is in window by definition. - * seq == rcv_nxt and rcv_wup <= rcv_nxt. - * Hence, check seq<=rcv_wup reduces to: - */ - if (tcp_header_len == - (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) && - tp->rcv_nxt == tp->rcv_wup) - tcp_store_ts_recent(tp); - - tcp_rcv_rtt_measure_ts(sk, skb); - - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPHPHITS); - - /* Bulk data transfer: receiver */ - eaten = tcp_queue_rcv(sk, skb, tcp_header_len, - &fragstolen); - } - - tcp_event_data_recv(sk, skb); - - if (TCP_SKB_CB(skb)->ack_seq != tp->snd_una) { - /* Well, only one small jumplet in fast path... */ - tcp_ack(sk, skb, FLAG_DATA); - tcp_data_snd_check(sk); - if (!inet_csk_ack_scheduled(sk)) - goto no_ack; - } - - __tcp_ack_snd_check(sk, 0); -no_ack: - if (eaten) - kfree_skb_partial(skb, fragstolen); - sk->sk_data_ready(sk); - return; - } - } - -slow_path: - if (len < (th->doff << 2) || tcp_checksum_complete(skb)) - goto csum_error; - - if (!th->ack && !th->rst && !th->syn) - goto discard; - - /* - * Standard slow path. - */ - - if (!tcp_validate_incoming(sk, skb, th, 1)) - return; - -step5: - if (tcp_ack(sk, skb, FLAG_SLOWPATH | FLAG_UPDATE_TS_RECENT) < 0) - goto discard; - - tcp_rcv_rtt_measure_ts(sk, skb); - - /* Process urgent data. */ - tcp_urg(sk, skb, th); - - /* step 7: process the segment text */ - tcp_data_queue(sk, skb); - - tcp_data_snd_check(sk); - tcp_ack_snd_check(sk); - return; - -csum_error: - TCP_INC_STATS(sock_net(sk), TCP_MIB_CSUMERRORS); - TCP_INC_STATS(sock_net(sk), TCP_MIB_INERRS); - -discard: - tcp_drop(sk, skb); -} -EXPORT_SYMBOL(tcp_rcv_established); - -void tcp_finish_connect(struct sock *sk, struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct inet_connection_sock *icsk = inet_csk(sk); - - tcp_set_state(sk, TCP_ESTABLISHED); - - if (skb) { - icsk->icsk_af_ops->sk_rx_dst_set(sk, skb); - security_inet_conn_established(sk, skb); - } - - /* Make sure socket is routed, for correct metrics. */ - icsk->icsk_af_ops->rebuild_header(sk); - - tcp_init_metrics(sk); - - tcp_init_congestion_control(sk); - - /* Prevent spurious tcp_cwnd_restart() on first data - * packet. - */ - tp->lsndtime = tcp_time_stamp; - - tcp_init_buffer_space(sk); - - if (sock_flag(sk, SOCK_KEEPOPEN)) - inet_csk_reset_keepalive_timer(sk, keepalive_time_when(tp)); - - if (!tp->rx_opt.snd_wscale) - __tcp_fast_path_on(tp, tp->snd_wnd); - else - tp->pred_flags = 0; - - if (!sock_flag(sk, SOCK_DEAD)) { - sk->sk_state_change(sk); - sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT); - } -} - -static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack, - struct tcp_fastopen_cookie *cookie) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *data = tp->syn_data ? tcp_write_queue_head(sk) : NULL; - u16 mss = tp->rx_opt.mss_clamp, try_exp = 0; - bool syn_drop = false; - - if (mss == tp->rx_opt.user_mss) { - struct tcp_options_received opt; - - /* Get original SYNACK MSS value if user MSS sets mss_clamp */ - tcp_clear_options(&opt); - opt.user_mss = opt.mss_clamp = 0; - tcp_parse_options(synack, &opt, 0, NULL); - mss = opt.mss_clamp; - } - - if (!tp->syn_fastopen) { - /* Ignore an unsolicited cookie */ - cookie->len = -1; - } else if (tp->total_retrans) { - /* SYN timed out and the SYN-ACK neither has a cookie nor - * acknowledges data. Presumably the remote received only - * the retransmitted (regular) SYNs: either the original - * SYN-data or the corresponding SYN-ACK was dropped. - */ - syn_drop = (cookie->len < 0 && data); - } else if (cookie->len < 0 && !tp->syn_data) { - /* We requested a cookie but didn't get it. If we did not use - * the (old) exp opt format then try so next time (try_exp=1). - * Otherwise we go back to use the RFC7413 opt (try_exp=2). - */ - try_exp = tp->syn_fastopen_exp ? 2 : 1; - } - - tcp_fastopen_cache_set(sk, mss, cookie, syn_drop, try_exp); - - if (data) { /* Retransmit unacked data in SYN */ - tcp_for_write_queue_from(data, sk) { - if (data == tcp_send_head(sk) || - __tcp_retransmit_skb(sk, data, 1)) - break; - } - tcp_rearm_rto(sk); - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPFASTOPENACTIVEFAIL); - return true; - } - tp->syn_data_acked = tp->syn_data; - if (tp->syn_data_acked) - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPFASTOPENACTIVE); - - tcp_fastopen_add_skb(sk, synack); - - return false; -} - -static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, - const struct tcphdr *th) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - struct tcp_fastopen_cookie foc = { .len = -1 }; - int saved_clamp = tp->rx_opt.mss_clamp; - - tcp_parse_options(skb, &tp->rx_opt, 0, &foc); - if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr) - tp->rx_opt.rcv_tsecr -= tp->tsoffset; - - if (th->ack) { - /* rfc793: - * "If the state is SYN-SENT then - * first check the ACK bit - * If the ACK bit is set - * If SEG.ACK =< ISS, or SEG.ACK > SND.NXT, send - * a reset (unless the RST bit is set, if so drop - * the segment and return)" - */ - if (!after(TCP_SKB_CB(skb)->ack_seq, tp->snd_una) || - after(TCP_SKB_CB(skb)->ack_seq, tp->snd_nxt)) - goto reset_and_undo; - - if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr && - !between(tp->rx_opt.rcv_tsecr, tp->retrans_stamp, - tcp_time_stamp)) { - NET_INC_STATS(sock_net(sk), - LINUX_MIB_PAWSACTIVEREJECTED); - goto reset_and_undo; - } - - /* Now ACK is acceptable. - * - * "If the RST bit is set - * If the ACK was acceptable then signal the user "error: - * connection reset", drop the segment, enter CLOSED state, - * delete TCB, and return." - */ - - if (th->rst) { - tcp_reset(sk); - goto discard; - } - - /* rfc793: - * "fifth, if neither of the SYN or RST bits is set then - * drop the segment and return." - * - * See note below! - * --ANK(990513) - */ - if (!th->syn) - goto discard_and_undo; - - /* rfc793: - * "If the SYN bit is on ... - * are acceptable then ... - * (our SYN has been ACKed), change the connection - * state to ESTABLISHED..." - */ - - tcp_ecn_rcv_synack(tp, th); - - tcp_init_wl(tp, TCP_SKB_CB(skb)->seq); - tcp_ack(sk, skb, FLAG_SLOWPATH); - - /* Ok.. it's good. Set up sequence numbers and - * move to established. - */ - tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; - tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1; - - /* RFC1323: The window in SYN & SYN/ACK segments is - * never scaled. - */ - tp->snd_wnd = ntohs(th->window); - - if (!tp->rx_opt.wscale_ok) { - tp->rx_opt.snd_wscale = tp->rx_opt.rcv_wscale = 0; - tp->window_clamp = min(tp->window_clamp, 65535U); - } - - if (tp->rx_opt.saw_tstamp) { - tp->rx_opt.tstamp_ok = 1; - tp->tcp_header_len = - sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED; - tp->advmss -= TCPOLEN_TSTAMP_ALIGNED; - tcp_store_ts_recent(tp); - } else { - tp->tcp_header_len = sizeof(struct tcphdr); - } - - if (tcp_is_sack(tp) && sysctl_tcp_fack) - tcp_enable_fack(tp); - - tcp_mtup_init(sk); - tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); - tcp_initialize_rcv_mss(sk); - - /* Remember, tcp_poll() does not lock socket! - * Change state from SYN-SENT only after copied_seq - * is initialized. */ - tp->copied_seq = tp->rcv_nxt; - - smp_mb(); - - tcp_finish_connect(sk, skb); - - if ((tp->syn_fastopen || tp->syn_data) && - tcp_rcv_fastopen_synack(sk, skb, &foc)) - return -1; - - if (sk->sk_write_pending || - icsk->icsk_accept_queue.rskq_defer_accept || - icsk->icsk_ack.pingpong) { - /* Save one ACK. Data will be ready after - * several ticks, if write_pending is set. - * - * It may be deleted, but with this feature tcpdumps - * look so _wonderfully_ clever, that I was not able - * to stand against the temptation 8) --ANK - */ - inet_csk_schedule_ack(sk); - icsk->icsk_ack.lrcvtime = tcp_time_stamp; - tcp_enter_quickack_mode(sk); - inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, - TCP_DELACK_MAX, TCP_RTO_MAX); - -discard: - tcp_drop(sk, skb); - return 0; - } else { - tcp_send_ack(sk); - } - return -1; - } - - /* No ACK in the segment */ - - if (th->rst) { - /* rfc793: - * "If the RST bit is set - * - * Otherwise (no ACK) drop the segment and return." - */ - - goto discard_and_undo; - } - - /* PAWS check. */ - if (tp->rx_opt.ts_recent_stamp && tp->rx_opt.saw_tstamp && - tcp_paws_reject(&tp->rx_opt, 0)) - goto discard_and_undo; - - if (th->syn) { - /* We see SYN without ACK. It is attempt of - * simultaneous connect with crossed SYNs. - * Particularly, it can be connect to self. - */ - tcp_set_state(sk, TCP_SYN_RECV); - - if (tp->rx_opt.saw_tstamp) { - tp->rx_opt.tstamp_ok = 1; - tcp_store_ts_recent(tp); - tp->tcp_header_len = - sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED; - } else { - tp->tcp_header_len = sizeof(struct tcphdr); - } - - tp->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; - tp->copied_seq = tp->rcv_nxt; - tp->rcv_wup = TCP_SKB_CB(skb)->seq + 1; - - /* RFC1323: The window in SYN & SYN/ACK segments is - * never scaled. - */ - tp->snd_wnd = ntohs(th->window); - tp->snd_wl1 = TCP_SKB_CB(skb)->seq; - tp->max_window = tp->snd_wnd; - - tcp_ecn_rcv_syn(tp, th); - - tcp_mtup_init(sk); - tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); - tcp_initialize_rcv_mss(sk); - - tcp_send_synack(sk); -#if 0 - /* Note, we could accept data and URG from this segment. - * There are no obstacles to make this (except that we must - * either change tcp_recvmsg() to prevent it from returning data - * before 3WHS completes per RFC793, or employ TCP Fast Open). - * - * However, if we ignore data in ACKless segments sometimes, - * we have no reasons to accept it sometimes. - * Also, seems the code doing it in step6 of tcp_rcv_state_process - * is not flawless. So, discard packet for sanity. - * Uncomment this return to process the data. - */ - return -1; -#else - goto discard; -#endif - } - /* "fifth, if neither of the SYN or RST bits is set then - * drop the segment and return." - */ - -discard_and_undo: - tcp_clear_options(&tp->rx_opt); - tp->rx_opt.mss_clamp = saved_clamp; - goto discard; - -reset_and_undo: - tcp_clear_options(&tp->rx_opt); - tp->rx_opt.mss_clamp = saved_clamp; - return 1; -} - -/* - * This function implements the receiving procedure of RFC 793 for - * all states except ESTABLISHED and TIME_WAIT. - * It's called from both tcp_v4_rcv and tcp_v6_rcv and should be - * address independent. - */ - -int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct inet_connection_sock *icsk = inet_csk(sk); - const struct tcphdr *th = tcp_hdr(skb); - struct request_sock *req; - int queued = 0; - bool acceptable; - - switch (sk->sk_state) { - case TCP_CLOSE: - goto discard; - - case TCP_LISTEN: - if (th->ack) - return 1; - - if (th->rst) - goto discard; - - if (th->syn) { - if (th->fin) - goto discard; - if (icsk->icsk_af_ops->conn_request(sk, skb) < 0) - return 1; - - consume_skb(skb); - return 0; - } - goto discard; - - case TCP_SYN_SENT: - tp->rx_opt.saw_tstamp = 0; - queued = tcp_rcv_synsent_state_process(sk, skb, th); - if (queued >= 0) - return queued; - - /* Do step6 onward by hand. */ - tcp_urg(sk, skb, th); - __kfree_skb(skb); - tcp_data_snd_check(sk); - return 0; - } - - tp->rx_opt.saw_tstamp = 0; - req = tp->fastopen_rsk; - if (req) { - WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV && - sk->sk_state != TCP_FIN_WAIT1); - - if (!tcp_check_req(sk, skb, req, true)) - goto discard; - } - - if (!th->ack && !th->rst && !th->syn) - goto discard; - - if (!tcp_validate_incoming(sk, skb, th, 0)) - return 0; - - /* step 5: check the ACK field */ - acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH | - FLAG_UPDATE_TS_RECENT) > 0; - - switch (sk->sk_state) { - case TCP_SYN_RECV: - if (!acceptable) - return 1; - - if (!tp->srtt_us) - tcp_synack_rtt_meas(sk, req); - - /* Once we leave TCP_SYN_RECV, we no longer need req - * so release it. - */ - if (req) { - inet_csk(sk)->icsk_retransmits = 0; - reqsk_fastopen_remove(sk, req, false); - } else { - /* Make sure socket is routed, for correct metrics. */ - icsk->icsk_af_ops->rebuild_header(sk); - tcp_init_congestion_control(sk); - - tcp_mtup_init(sk); - tp->copied_seq = tp->rcv_nxt; - tcp_init_buffer_space(sk); - } - smp_mb(); - tcp_set_state(sk, TCP_ESTABLISHED); - sk->sk_state_change(sk); - - /* Note, that this wakeup is only for marginal crossed SYN case. - * Passively open sockets are not waked up, because - * sk->sk_sleep == NULL and sk->sk_socket == NULL. - */ - if (sk->sk_socket) - sk_wake_async(sk, SOCK_WAKE_IO, POLL_OUT); - - tp->snd_una = TCP_SKB_CB(skb)->ack_seq; - tp->snd_wnd = ntohs(th->window) << tp->rx_opt.snd_wscale; - tcp_init_wl(tp, TCP_SKB_CB(skb)->seq); - - if (tp->rx_opt.tstamp_ok) - tp->advmss -= TCPOLEN_TSTAMP_ALIGNED; - - if (req) { - /* Re-arm the timer because data may have been sent out. - * This is similar to the regular data transmission case - * when new data has just been ack'ed. - * - * (TFO) - we could try to be more aggressive and - * retransmitting any data sooner based on when they - * are sent out. - */ - tcp_rearm_rto(sk); - } else - tcp_init_metrics(sk); - - if (!inet_csk(sk)->icsk_ca_ops->cong_control) - tcp_update_pacing_rate(sk); - - /* Prevent spurious tcp_cwnd_restart() on first data packet */ - tp->lsndtime = tcp_time_stamp; - - tcp_initialize_rcv_mss(sk); - tcp_fast_path_on(tp); - break; - - case TCP_FIN_WAIT1: { - struct dst_entry *dst; - int tmo; - - /* If we enter the TCP_FIN_WAIT1 state and we are a - * Fast Open socket and this is the first acceptable - * ACK we have received, this would have acknowledged - * our SYNACK so stop the SYNACK timer. - */ - if (req) { - /* Return RST if ack_seq is invalid. - * Note that RFC793 only says to generate a - * DUPACK for it but for TCP Fast Open it seems - * better to treat this case like TCP_SYN_RECV - * above. - */ - if (!acceptable) - return 1; - /* We no longer need the request sock. */ - reqsk_fastopen_remove(sk, req, false); - tcp_rearm_rto(sk); - } - if (tp->snd_una != tp->write_seq) - break; - - tcp_set_state(sk, TCP_FIN_WAIT2); - sk->sk_shutdown |= SEND_SHUTDOWN; - - dst = __sk_dst_get(sk); - if (dst) - dst_confirm(dst); - - if (!sock_flag(sk, SOCK_DEAD)) { - /* Wake up lingering close() */ - sk->sk_state_change(sk); - break; - } - - if (tp->linger2 < 0 || - (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && - after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt))) { - tcp_done(sk); - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONDATA); - return 1; - } - - tmo = tcp_fin_time(sk); - if (tmo > TCP_TIMEWAIT_LEN) { - inet_csk_reset_keepalive_timer(sk, tmo - TCP_TIMEWAIT_LEN); - } else if (th->fin || sock_owned_by_user(sk)) { - /* Bad case. We could lose such FIN otherwise. - * It is not a big problem, but it looks confusing - * and not so rare event. We still can lose it now, - * if it spins in bh_lock_sock(), but it is really - * marginal case. - */ - inet_csk_reset_keepalive_timer(sk, tmo); - } else { - tcp_time_wait(sk, TCP_FIN_WAIT2, tmo); - goto discard; - } - break; - } - - case TCP_CLOSING: - if (tp->snd_una == tp->write_seq) { - tcp_time_wait(sk, TCP_TIME_WAIT, 0); - goto discard; - } - break; - - case TCP_LAST_ACK: - if (tp->snd_una == tp->write_seq) { - tcp_update_metrics(sk); - tcp_done(sk); - goto discard; - } - break; - } - - /* step 6: check the URG bit */ - tcp_urg(sk, skb, th); - - /* step 7: process the segment text */ - switch (sk->sk_state) { - case TCP_CLOSE_WAIT: - case TCP_CLOSING: - case TCP_LAST_ACK: - if (!before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) - break; - case TCP_FIN_WAIT1: - case TCP_FIN_WAIT2: - /* RFC 793 says to queue data in these states, - * RFC 1122 says we MUST send a reset. - * BSD 4.4 also does reset. - */ - if (sk->sk_shutdown & RCV_SHUTDOWN) { - if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && - after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONDATA); - tcp_reset(sk); - return 1; - } - } - /* Fall through */ - case TCP_ESTABLISHED: - tcp_data_queue(sk, skb); - queued = 1; - break; - } - - /* tcp_data could move socket to TIME-WAIT */ - if (sk->sk_state != TCP_CLOSE) { - tcp_data_snd_check(sk); - tcp_ack_snd_check(sk); - } - - if (!queued) { -discard: - tcp_drop(sk, skb); - } - return 0; -} -EXPORT_SYMBOL(tcp_rcv_state_process); - -static inline void pr_drop_req(struct request_sock *req, __u16 port, int family) -{ - struct inet_request_sock *ireq = inet_rsk(req); - - if (family == AF_INET) - net_dbg_ratelimited("drop open request from %pI4/%u\n", - &ireq->ir_rmt_addr, port); -#if IS_ENABLED(CONFIG_IPV6) - else if (family == AF_INET6) - net_dbg_ratelimited("drop open request from %pI6/%u\n", - &ireq->ir_v6_rmt_addr, port); -#endif -} - -/* RFC3168 : 6.1.1 SYN packets must not have ECT/ECN bits set - * - * If we receive a SYN packet with these bits set, it means a - * network is playing bad games with TOS bits. In order to - * avoid possible false congestion notifications, we disable - * TCP ECN negotiation. - * - * Exception: tcp_ca wants ECN. This is required for DCTCP - * congestion control: Linux DCTCP asserts ECT on all packets, - * including SYN, which is most optimal solution; however, - * others, such as FreeBSD do not. - */ -static void tcp_ecn_create_request(struct request_sock *req, - const struct sk_buff *skb, - const struct sock *listen_sk, - const struct dst_entry *dst) -{ - const struct tcphdr *th = tcp_hdr(skb); - const struct net *net = sock_net(listen_sk); - bool th_ecn = th->ece && th->cwr; - bool ect, ecn_ok; - u32 ecn_ok_dst; - - if (!th_ecn) - return; - - ect = !INET_ECN_is_not_ect(TCP_SKB_CB(skb)->ip_dsfield); - ecn_ok_dst = dst_feature(dst, DST_FEATURE_ECN_MASK); - ecn_ok = net->ipv4.sysctl_tcp_ecn || ecn_ok_dst; - - if ((!ect && ecn_ok) || tcp_ca_needs_ecn(listen_sk) || - (ecn_ok_dst & DST_FEATURE_ECN_CA)) - inet_rsk(req)->ecn_ok = 1; -} - -static void tcp_openreq_init(struct request_sock *req, - const struct tcp_options_received *rx_opt, - struct sk_buff *skb, const struct sock *sk) -{ - struct inet_request_sock *ireq = inet_rsk(req); - - req->rsk_rcv_wnd = 0; /* So that tcp_send_synack() knows! */ - req->cookie_ts = 0; - tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq; - tcp_rsk(req)->rcv_nxt = TCP_SKB_CB(skb)->seq + 1; - skb_mstamp_get(&tcp_rsk(req)->snt_synack); - tcp_rsk(req)->last_oow_ack_time = 0; - req->mss = rx_opt->mss_clamp; - req->ts_recent = rx_opt->saw_tstamp ? rx_opt->rcv_tsval : 0; - ireq->tstamp_ok = rx_opt->tstamp_ok; - ireq->sack_ok = rx_opt->sack_ok; - ireq->snd_wscale = rx_opt->snd_wscale; - ireq->wscale_ok = rx_opt->wscale_ok; - ireq->acked = 0; - ireq->ecn_ok = 0; - ireq->ir_rmt_port = tcp_hdr(skb)->source; - ireq->ir_num = ntohs(tcp_hdr(skb)->dest); - ireq->ir_mark = inet_request_mark(sk, skb); -} - -struct request_sock *inet_reqsk_alloc(const struct request_sock_ops *ops, - struct sock *sk_listener, - bool attach_listener) -{ - struct request_sock *req = reqsk_alloc(ops, sk_listener, - attach_listener); - - if (req) { - struct inet_request_sock *ireq = inet_rsk(req); - - kmemcheck_annotate_bitfield(ireq, flags); - ireq->opt = NULL; -#if IS_ENABLED(CONFIG_IPV6) - ireq->pktopts = NULL; -#endif - atomic64_set(&ireq->ir_cookie, 0); - ireq->ireq_state = TCP_NEW_SYN_RECV; - write_pnet(&ireq->ireq_net, sock_net(sk_listener)); - ireq->ireq_family = sk_listener->sk_family; - } - - return req; -} -EXPORT_SYMBOL(inet_reqsk_alloc); - -/* - * Return true if a syncookie should be sent - */ -static bool tcp_syn_flood_action(const struct sock *sk, - const struct sk_buff *skb, - const char *proto) -{ - struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue; - const char *msg = "Dropping request"; - bool want_cookie = false; - struct net *net = sock_net(sk); - -#ifdef CONFIG_SYN_COOKIES - if (net->ipv4.sysctl_tcp_syncookies) { - msg = "Sending cookies"; - want_cookie = true; - __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPREQQFULLDOCOOKIES); - } else -#endif - __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPREQQFULLDROP); - - if (!queue->synflood_warned && - net->ipv4.sysctl_tcp_syncookies != 2 && - xchg(&queue->synflood_warned, 1) == 0) - pr_info("%s: Possible SYN flooding on port %d. %s. Check SNMP counters.\n", - proto, ntohs(tcp_hdr(skb)->dest), msg); - - return want_cookie; -} - -static void tcp_reqsk_record_syn(const struct sock *sk, - struct request_sock *req, - const struct sk_buff *skb) -{ - if (tcp_sk(sk)->save_syn) { - u32 len = skb_network_header_len(skb) + tcp_hdrlen(skb); - u32 *copy; - - copy = kmalloc(len + sizeof(u32), GFP_ATOMIC); - if (copy) { - copy[0] = len; - memcpy(©[1], skb_network_header(skb), len); - req->saved_syn = copy; - } - } -} - -int tcp_conn_request(struct request_sock_ops *rsk_ops, - const struct tcp_request_sock_ops *af_ops, - struct sock *sk, struct sk_buff *skb) -{ - struct tcp_fastopen_cookie foc = { .len = -1 }; - __u32 isn = TCP_SKB_CB(skb)->tcp_tw_isn; - struct tcp_options_received tmp_opt; - struct tcp_sock *tp = tcp_sk(sk); - struct net *net = sock_net(sk); - struct sock *fastopen_sk = NULL; - struct dst_entry *dst = NULL; - struct request_sock *req; - bool want_cookie = false; - struct flowi fl; - - /* TW buckets are converted to open requests without - * limitations, they conserve resources and peer is - * evidently real one. - */ - if ((net->ipv4.sysctl_tcp_syncookies == 2 || - inet_csk_reqsk_queue_is_full(sk)) && !isn) { - want_cookie = tcp_syn_flood_action(sk, skb, rsk_ops->slab_name); - if (!want_cookie) - goto drop; - } - - - /* Accept backlog is full. If we have already queued enough - * of warm entries in syn queue, drop request. It is better than - * clogging syn queue with openreqs with exponentially increasing - * timeout. - */ - if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); - goto drop; - } - - req = inet_reqsk_alloc(rsk_ops, sk, !want_cookie); - if (!req) - goto drop; - - tcp_rsk(req)->af_specific = af_ops; - - tcp_clear_options(&tmp_opt); - tmp_opt.mss_clamp = af_ops->mss_clamp; - tmp_opt.user_mss = tp->rx_opt.user_mss; - tcp_parse_options(skb, &tmp_opt, 0, want_cookie ? NULL : &foc); - - if (want_cookie && !tmp_opt.saw_tstamp) - tcp_clear_options(&tmp_opt); - - tmp_opt.tstamp_ok = tmp_opt.saw_tstamp; - tcp_openreq_init(req, &tmp_opt, skb, sk); - inet_rsk(req)->no_srccheck = inet_sk(sk)->transparent; - - /* Note: tcp_v6_init_req() might override ir_iif for link locals */ - inet_rsk(req)->ir_iif = inet_request_bound_dev_if(sk, skb); - - af_ops->init_req(req, sk, skb); - - if (security_inet_conn_request(sk, skb, req)) - goto drop_and_free; - - if (!want_cookie && !isn) { - /* VJ's idea. We save last timestamp seen - * from the destination in peer table, when entering - * state TIME-WAIT, and check against it before - * accepting new connection request. - * - * If "isn" is not zero, this request hit alive - * timewait bucket, so that all the necessary checks - * are made in the function processing timewait state. - */ - if (tcp_death_row.sysctl_tw_recycle) { - bool strict; - - dst = af_ops->route_req(sk, &fl, req, &strict); - - if (dst && strict && - !tcp_peer_is_proven(req, dst, true, - tmp_opt.saw_tstamp)) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED); - goto drop_and_release; - } - } - /* Kill the following clause, if you dislike this way. */ - else if (!net->ipv4.sysctl_tcp_syncookies && - (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) < - (sysctl_max_syn_backlog >> 2)) && - !tcp_peer_is_proven(req, dst, false, - tmp_opt.saw_tstamp)) { - /* Without syncookies last quarter of - * backlog is filled with destinations, - * proven to be alive. - * It means that we continue to communicate - * to destinations, already remembered - * to the moment of synflood. - */ - pr_drop_req(req, ntohs(tcp_hdr(skb)->source), - rsk_ops->family); - goto drop_and_release; - } - - isn = af_ops->init_seq(skb); - } - if (!dst) { - dst = af_ops->route_req(sk, &fl, req, NULL); - if (!dst) - goto drop_and_free; - } - - tcp_ecn_create_request(req, skb, sk, dst); - - if (want_cookie) { - isn = cookie_init_sequence(af_ops, sk, skb, &req->mss); - req->cookie_ts = tmp_opt.tstamp_ok; - if (!tmp_opt.tstamp_ok) - inet_rsk(req)->ecn_ok = 0; - } - - tcp_rsk(req)->snt_isn = isn; - tcp_rsk(req)->txhash = net_tx_rndhash(); - tcp_openreq_init_rwin(req, sk, dst); - if (!want_cookie) { - tcp_reqsk_record_syn(sk, req, skb); - fastopen_sk = tcp_try_fastopen(sk, skb, req, &foc, dst); - } - if (fastopen_sk) { - af_ops->send_synack(fastopen_sk, dst, &fl, req, - &foc, TCP_SYNACK_FASTOPEN); - /* Add the child socket directly into the accept queue */ - inet_csk_reqsk_queue_add(sk, req, fastopen_sk); - sk->sk_data_ready(sk); - bh_unlock_sock(fastopen_sk); - sock_put(fastopen_sk); - } else { - tcp_rsk(req)->tfo_listener = false; - if (!want_cookie) - inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT); - af_ops->send_synack(sk, dst, &fl, req, &foc, - !want_cookie ? TCP_SYNACK_NORMAL : - TCP_SYNACK_COOKIE); - if (want_cookie) { - reqsk_free(req); - return 0; - } - } - reqsk_put(req); - return 0; - -drop_and_release: - dst_release(dst); -drop_and_free: - reqsk_free(req); -drop: - tcp_listendrop(sk); - return 0; -} -EXPORT_SYMBOL(tcp_conn_request); diff --git a/src/linux/net/ipv4/tcp_ipv4.c b/src/linux/net/ipv4/tcp_ipv4.c deleted file mode 100644 index 2259114..0000000 --- a/src/linux/net/ipv4/tcp_ipv4.c +++ /dev/null @@ -1,2479 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Implementation of the Transmission Control Protocol(TCP). - * - * IPv4 specific functions - * - * - * code split from: - * linux/ipv4/tcp.c - * linux/ipv4/tcp_input.c - * linux/ipv4/tcp_output.c - * - * See tcp.c for author information - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -/* - * Changes: - * David S. Miller : New socket lookup architecture. - * This code is dedicated to John Dyson. - * David S. Miller : Change semantics of established hash, - * half is devoted to TIME_WAIT sockets - * and the rest go in the other half. - * Andi Kleen : Add support for syncookies and fixed - * some bugs: ip options weren't passed to - * the TCP layer, missed a check for an - * ACK bit. - * Andi Kleen : Implemented fast path mtu discovery. - * Fixed many serious bugs in the - * request_sock handling and moved - * most of it into the af independent code. - * Added tail drop and some other bugfixes. - * Added new listen semantics. - * Mike McLagan : Routing by source - * Juan Jose Ciarlante: ip_dynaddr bits - * Andi Kleen: various fixes. - * Vitaly E. Lavrov : Transparent proxy revived after year - * coma. - * Andi Kleen : Fix new listen. - * Andi Kleen : Fix accept error reporting. - * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which - * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind - * a single port at the same time. - */ - -#define pr_fmt(fmt) "TCP: " fmt - -#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 - -int sysctl_tcp_tw_reuse __read_mostly; -int sysctl_tcp_low_latency __read_mostly; - -#ifdef CONFIG_TCP_MD5SIG -static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, - __be32 daddr, __be32 saddr, const struct tcphdr *th); -#endif - -struct inet_hashinfo tcp_hashinfo; -EXPORT_SYMBOL(tcp_hashinfo); - -static __u32 tcp_v4_init_sequence(const struct sk_buff *skb) -{ - return secure_tcp_sequence_number(ip_hdr(skb)->daddr, - ip_hdr(skb)->saddr, - tcp_hdr(skb)->dest, - tcp_hdr(skb)->source); -} - -int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp) -{ - const struct tcp_timewait_sock *tcptw = tcp_twsk(sktw); - struct tcp_sock *tp = tcp_sk(sk); - - /* With PAWS, it is safe from the viewpoint - of data integrity. Even without PAWS it is safe provided sequence - spaces do not overlap i.e. at data rates <= 80Mbit/sec. - - Actually, the idea is close to VJ's one, only timestamp cache is - held not per host, but per port pair and TW bucket is used as state - holder. - - If TW bucket has been already destroyed we fall back to VJ's scheme - and use initial timestamp retrieved from peer table. - */ - if (tcptw->tw_ts_recent_stamp && - (!twp || (sysctl_tcp_tw_reuse && - get_seconds() - tcptw->tw_ts_recent_stamp > 1))) { - tp->write_seq = tcptw->tw_snd_nxt + 65535 + 2; - if (tp->write_seq == 0) - tp->write_seq = 1; - tp->rx_opt.ts_recent = tcptw->tw_ts_recent; - tp->rx_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp; - sock_hold(sktw); - return 1; - } - - return 0; -} -EXPORT_SYMBOL_GPL(tcp_twsk_unique); - -/* This will initiate an outgoing connection. */ -int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) -{ - struct sockaddr_in *usin = (struct sockaddr_in *)uaddr; - struct inet_sock *inet = inet_sk(sk); - struct tcp_sock *tp = tcp_sk(sk); - __be16 orig_sport, orig_dport; - __be32 daddr, nexthop; - struct flowi4 *fl4; - struct rtable *rt; - int err; - struct ip_options_rcu *inet_opt; - - if (addr_len < sizeof(struct sockaddr_in)) - return -EINVAL; - - if (usin->sin_family != AF_INET) - return -EAFNOSUPPORT; - - nexthop = daddr = usin->sin_addr.s_addr; - inet_opt = rcu_dereference_protected(inet->inet_opt, - lockdep_sock_is_held(sk)); - if (inet_opt && inet_opt->opt.srr) { - if (!daddr) - return -EINVAL; - nexthop = inet_opt->opt.faddr; - } - - orig_sport = inet->inet_sport; - orig_dport = usin->sin_port; - fl4 = &inet->cork.fl.u.ip4; - rt = ip_route_connect(fl4, nexthop, inet->inet_saddr, - RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, - IPPROTO_TCP, - orig_sport, orig_dport, sk); - if (IS_ERR(rt)) { - err = PTR_ERR(rt); - if (err == -ENETUNREACH) - IP_INC_STATS(sock_net(sk), IPSTATS_MIB_OUTNOROUTES); - return err; - } - - if (rt->rt_flags & (RTCF_MULTICAST | RTCF_BROADCAST)) { - ip_rt_put(rt); - return -ENETUNREACH; - } - - if (!inet_opt || !inet_opt->opt.srr) - daddr = fl4->daddr; - - if (!inet->inet_saddr) - inet->inet_saddr = fl4->saddr; - sk_rcv_saddr_set(sk, inet->inet_saddr); - - if (tp->rx_opt.ts_recent_stamp && inet->inet_daddr != daddr) { - /* Reset inherited state */ - tp->rx_opt.ts_recent = 0; - tp->rx_opt.ts_recent_stamp = 0; - if (likely(!tp->repair)) - tp->write_seq = 0; - } - - if (tcp_death_row.sysctl_tw_recycle && - !tp->rx_opt.ts_recent_stamp && fl4->daddr == daddr) - tcp_fetch_timewait_stamp(sk, &rt->dst); - - inet->inet_dport = usin->sin_port; - sk_daddr_set(sk, daddr); - - inet_csk(sk)->icsk_ext_hdr_len = 0; - if (inet_opt) - inet_csk(sk)->icsk_ext_hdr_len = inet_opt->opt.optlen; - - tp->rx_opt.mss_clamp = TCP_MSS_DEFAULT; - - /* Socket identity is still unknown (sport may be zero). - * However we set state to SYN-SENT and not releasing socket - * lock select source port, enter ourselves into the hash tables and - * complete initialization after this. - */ - tcp_set_state(sk, TCP_SYN_SENT); - err = inet_hash_connect(&tcp_death_row, sk); - if (err) - goto failure; - - sk_set_txhash(sk); - - rt = ip_route_newports(fl4, rt, orig_sport, orig_dport, - inet->inet_sport, inet->inet_dport, sk); - if (IS_ERR(rt)) { - err = PTR_ERR(rt); - rt = NULL; - goto failure; - } - /* OK, now commit destination to socket. */ - sk->sk_gso_type = SKB_GSO_TCPV4; - sk_setup_caps(sk, &rt->dst); - - if (!tp->write_seq && likely(!tp->repair)) - tp->write_seq = secure_tcp_sequence_number(inet->inet_saddr, - inet->inet_daddr, - inet->inet_sport, - usin->sin_port); - - inet->inet_id = tp->write_seq ^ jiffies; - - err = tcp_connect(sk); - - rt = NULL; - if (err) - goto failure; - - return 0; - -failure: - /* - * This unhashes the socket and releases the local port, - * if necessary. - */ - tcp_set_state(sk, TCP_CLOSE); - ip_rt_put(rt); - sk->sk_route_caps = 0; - inet->inet_dport = 0; - return err; -} -EXPORT_SYMBOL(tcp_v4_connect); - -/* - * This routine reacts to ICMP_FRAG_NEEDED mtu indications as defined in RFC1191. - * It can be called through tcp_release_cb() if socket was owned by user - * at the time tcp_v4_err() was called to handle ICMP message. - */ -void tcp_v4_mtu_reduced(struct sock *sk) -{ - struct dst_entry *dst; - struct inet_sock *inet = inet_sk(sk); - u32 mtu = tcp_sk(sk)->mtu_info; - - dst = inet_csk_update_pmtu(sk, mtu); - if (!dst) - return; - - /* Something is about to be wrong... Remember soft error - * for the case, if this connection will not able to recover. - */ - if (mtu < dst_mtu(dst) && ip_dont_fragment(sk, dst)) - sk->sk_err_soft = EMSGSIZE; - - mtu = dst_mtu(dst); - - if (inet->pmtudisc != IP_PMTUDISC_DONT && - ip_sk_accept_pmtu(sk) && - inet_csk(sk)->icsk_pmtu_cookie > mtu) { - tcp_sync_mss(sk, mtu); - - /* Resend the TCP packet because it's - * clear that the old packet has been - * dropped. This is the new "fast" path mtu - * discovery. - */ - tcp_simple_retransmit(sk); - } /* else let the usual retransmit timer handle it */ -} -EXPORT_SYMBOL(tcp_v4_mtu_reduced); - -static void do_redirect(struct sk_buff *skb, struct sock *sk) -{ - struct dst_entry *dst = __sk_dst_check(sk, 0); - - if (dst) - dst->ops->redirect(dst, sk, skb); -} - - -/* handle ICMP messages on TCP_NEW_SYN_RECV request sockets */ -void tcp_req_err(struct sock *sk, u32 seq, bool abort) -{ - struct request_sock *req = inet_reqsk(sk); - struct net *net = sock_net(sk); - - /* ICMPs are not backlogged, hence we cannot get - * an established socket here. - */ - if (seq != tcp_rsk(req)->snt_isn) { - __NET_INC_STATS(net, LINUX_MIB_OUTOFWINDOWICMPS); - } else if (abort) { - /* - * Still in SYN_RECV, just remove it silently. - * There is no good way to pass the error to the newly - * created socket, and POSIX does not want network - * errors returned from accept(). - */ - inet_csk_reqsk_queue_drop(req->rsk_listener, req); - tcp_listendrop(req->rsk_listener); - } - reqsk_put(req); -} -EXPORT_SYMBOL(tcp_req_err); - -/* - * This routine is called by the ICMP module when it gets some - * sort of error condition. If err < 0 then the socket should - * be closed and the error returned to the user. If err > 0 - * it's just the icmp type << 8 | icmp code. After adjustment - * header points to the first 8 bytes of the tcp header. We need - * to find the appropriate port. - * - * The locking strategy used here is very "optimistic". When - * someone else accesses the socket the ICMP is just dropped - * and for some paths there is no check at all. - * A more general error queue to queue errors for later handling - * is probably better. - * - */ - -void tcp_v4_err(struct sk_buff *icmp_skb, u32 info) -{ - const struct iphdr *iph = (const struct iphdr *)icmp_skb->data; - struct tcphdr *th = (struct tcphdr *)(icmp_skb->data + (iph->ihl << 2)); - struct inet_connection_sock *icsk; - struct tcp_sock *tp; - struct inet_sock *inet; - const int type = icmp_hdr(icmp_skb)->type; - const int code = icmp_hdr(icmp_skb)->code; - struct sock *sk; - struct sk_buff *skb; - struct request_sock *fastopen; - __u32 seq, snd_una; - __u32 remaining; - int err; - struct net *net = dev_net(icmp_skb->dev); - - sk = __inet_lookup_established(net, &tcp_hashinfo, iph->daddr, - th->dest, iph->saddr, ntohs(th->source), - inet_iif(icmp_skb)); - if (!sk) { - __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); - return; - } - if (sk->sk_state == TCP_TIME_WAIT) { - inet_twsk_put(inet_twsk(sk)); - return; - } - seq = ntohl(th->seq); - if (sk->sk_state == TCP_NEW_SYN_RECV) - return tcp_req_err(sk, seq, - type == ICMP_PARAMETERPROB || - type == ICMP_TIME_EXCEEDED || - (type == ICMP_DEST_UNREACH && - (code == ICMP_NET_UNREACH || - code == ICMP_HOST_UNREACH))); - - bh_lock_sock(sk); - /* If too many ICMPs get dropped on busy - * servers this needs to be solved differently. - * We do take care of PMTU discovery (RFC1191) special case : - * we can receive locally generated ICMP messages while socket is held. - */ - if (sock_owned_by_user(sk)) { - if (!(type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)) - __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS); - } - if (sk->sk_state == TCP_CLOSE) - goto out; - - if (unlikely(iph->ttl < inet_sk(sk)->min_ttl)) { - __NET_INC_STATS(net, LINUX_MIB_TCPMINTTLDROP); - goto out; - } - - icsk = inet_csk(sk); - tp = tcp_sk(sk); - /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ - fastopen = tp->fastopen_rsk; - snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; - if (sk->sk_state != TCP_LISTEN && - !between(seq, snd_una, tp->snd_nxt)) { - __NET_INC_STATS(net, LINUX_MIB_OUTOFWINDOWICMPS); - goto out; - } - - switch (type) { - case ICMP_REDIRECT: - do_redirect(icmp_skb, sk); - goto out; - case ICMP_SOURCE_QUENCH: - /* Just silently ignore these. */ - goto out; - case ICMP_PARAMETERPROB: - err = EPROTO; - break; - case ICMP_DEST_UNREACH: - if (code > NR_ICMP_UNREACH) - goto out; - - if (code == ICMP_FRAG_NEEDED) { /* PMTU discovery (RFC1191) */ - /* We are not interested in TCP_LISTEN and open_requests - * (SYN-ACKs send out by Linux are always <576bytes so - * they should go through unfragmented). - */ - if (sk->sk_state == TCP_LISTEN) - goto out; - - tp->mtu_info = info; - if (!sock_owned_by_user(sk)) { - tcp_v4_mtu_reduced(sk); - } else { - if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, &tp->tsq_flags)) - sock_hold(sk); - } - goto out; - } - - err = icmp_err_convert[code].errno; - /* check if icmp_skb allows revert of backoff - * (see draft-zimmermann-tcp-lcd) */ - if (code != ICMP_NET_UNREACH && code != ICMP_HOST_UNREACH) - break; - if (seq != tp->snd_una || !icsk->icsk_retransmits || - !icsk->icsk_backoff || fastopen) - break; - - if (sock_owned_by_user(sk)) - break; - - icsk->icsk_backoff--; - icsk->icsk_rto = tp->srtt_us ? __tcp_set_rto(tp) : - TCP_TIMEOUT_INIT; - icsk->icsk_rto = inet_csk_rto_backoff(icsk, TCP_RTO_MAX); - - skb = tcp_write_queue_head(sk); - BUG_ON(!skb); - - remaining = icsk->icsk_rto - - min(icsk->icsk_rto, - tcp_time_stamp - tcp_skb_timestamp(skb)); - - if (remaining) { - inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, - remaining, TCP_RTO_MAX); - } else { - /* RTO revert clocked out retransmission. - * Will retransmit now */ - tcp_retransmit_timer(sk); - } - - break; - case ICMP_TIME_EXCEEDED: - err = EHOSTUNREACH; - break; - default: - goto out; - } - - switch (sk->sk_state) { - case TCP_SYN_SENT: - case TCP_SYN_RECV: - /* Only in fast or simultaneous open. If a fast open socket is - * is already accepted it is treated as a connected one below. - */ - if (fastopen && !fastopen->sk) - break; - - if (!sock_owned_by_user(sk)) { - sk->sk_err = err; - - sk->sk_error_report(sk); - - tcp_done(sk); - } else { - sk->sk_err_soft = err; - } - goto out; - } - - /* If we've already connected we will keep trying - * until we time out, or the user gives up. - * - * rfc1122 4.2.3.9 allows to consider as hard errors - * only PROTO_UNREACH and PORT_UNREACH (well, FRAG_FAILED too, - * but it is obsoleted by pmtu discovery). - * - * Note, that in modern internet, where routing is unreliable - * and in each dark corner broken firewalls sit, sending random - * errors ordered by their masters even this two messages finally lose - * their original sense (even Linux sends invalid PORT_UNREACHs) - * - * Now we are in compliance with RFCs. - * --ANK (980905) - */ - - inet = inet_sk(sk); - if (!sock_owned_by_user(sk) && inet->recverr) { - sk->sk_err = err; - sk->sk_error_report(sk); - } else { /* Only an error on timeout */ - sk->sk_err_soft = err; - } - -out: - bh_unlock_sock(sk); - sock_put(sk); -} - -void __tcp_v4_send_check(struct sk_buff *skb, __be32 saddr, __be32 daddr) -{ - struct tcphdr *th = tcp_hdr(skb); - - if (skb->ip_summed == CHECKSUM_PARTIAL) { - th->check = ~tcp_v4_check(skb->len, saddr, daddr, 0); - skb->csum_start = skb_transport_header(skb) - skb->head; - skb->csum_offset = offsetof(struct tcphdr, check); - } else { - th->check = tcp_v4_check(skb->len, saddr, daddr, - csum_partial(th, - th->doff << 2, - skb->csum)); - } -} - -/* This routine computes an IPv4 TCP checksum. */ -void tcp_v4_send_check(struct sock *sk, struct sk_buff *skb) -{ - const struct inet_sock *inet = inet_sk(sk); - - __tcp_v4_send_check(skb, inet->inet_saddr, inet->inet_daddr); -} -EXPORT_SYMBOL(tcp_v4_send_check); - -/* - * This routine will send an RST to the other tcp. - * - * Someone asks: why I NEVER use socket parameters (TOS, TTL etc.) - * for reset. - * Answer: if a packet caused RST, it is not for a socket - * existing in our system, if it is matched to a socket, - * it is just duplicate segment or bug in other side's TCP. - * So that we build reply only basing on parameters - * arrived with segment. - * Exception: precedence violation. We do not implement it in any case. - */ - -static void tcp_v4_send_reset(const struct sock *sk, struct sk_buff *skb) -{ - const struct tcphdr *th = tcp_hdr(skb); - struct { - struct tcphdr th; -#ifdef CONFIG_TCP_MD5SIG - __be32 opt[(TCPOLEN_MD5SIG_ALIGNED >> 2)]; -#endif - } rep; - struct ip_reply_arg arg; -#ifdef CONFIG_TCP_MD5SIG - struct tcp_md5sig_key *key = NULL; - const __u8 *hash_location = NULL; - unsigned char newhash[16]; - int genhash; - struct sock *sk1 = NULL; -#endif - struct net *net; - - /* Never send a reset in response to a reset. */ - if (th->rst) - return; - - /* If sk not NULL, it means we did a successful lookup and incoming - * route had to be correct. prequeue might have dropped our dst. - */ - if (!sk && skb_rtable(skb)->rt_type != RTN_LOCAL) - return; - - /* Swap the send and the receive. */ - memset(&rep, 0, sizeof(rep)); - rep.th.dest = th->source; - rep.th.source = th->dest; - rep.th.doff = sizeof(struct tcphdr) / 4; - rep.th.rst = 1; - - if (th->ack) { - rep.th.seq = th->ack_seq; - } else { - rep.th.ack = 1; - rep.th.ack_seq = htonl(ntohl(th->seq) + th->syn + th->fin + - skb->len - (th->doff << 2)); - } - - memset(&arg, 0, sizeof(arg)); - arg.iov[0].iov_base = (unsigned char *)&rep; - arg.iov[0].iov_len = sizeof(rep.th); - - net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev); -#ifdef CONFIG_TCP_MD5SIG - rcu_read_lock(); - hash_location = tcp_parse_md5sig_option(th); - if (sk && sk_fullsock(sk)) { - key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *) - &ip_hdr(skb)->saddr, AF_INET); - } else if (hash_location) { - /* - * active side is lost. Try to find listening socket through - * source port, and then find md5 key through listening socket. - * we are not loose security here: - * Incoming packet is checked with md5 hash with finding key, - * no RST generated if md5 hash doesn't match. - */ - sk1 = __inet_lookup_listener(net, &tcp_hashinfo, NULL, 0, - ip_hdr(skb)->saddr, - th->source, ip_hdr(skb)->daddr, - ntohs(th->source), inet_iif(skb)); - /* don't send rst if it can't find key */ - if (!sk1) - goto out; - - key = tcp_md5_do_lookup(sk1, (union tcp_md5_addr *) - &ip_hdr(skb)->saddr, AF_INET); - if (!key) - goto out; - - - genhash = tcp_v4_md5_hash_skb(newhash, key, NULL, skb); - if (genhash || memcmp(hash_location, newhash, 16) != 0) - goto out; - - } - - if (key) { - rep.opt[0] = htonl((TCPOPT_NOP << 24) | - (TCPOPT_NOP << 16) | - (TCPOPT_MD5SIG << 8) | - TCPOLEN_MD5SIG); - /* Update length and the length the header thinks exists */ - arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; - rep.th.doff = arg.iov[0].iov_len / 4; - - tcp_v4_md5_hash_hdr((__u8 *) &rep.opt[1], - key, ip_hdr(skb)->saddr, - ip_hdr(skb)->daddr, &rep.th); - } -#endif - arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, - ip_hdr(skb)->saddr, /* XXX */ - arg.iov[0].iov_len, IPPROTO_TCP, 0); - arg.csumoffset = offsetof(struct tcphdr, check) / 2; - arg.flags = (sk && inet_sk_transparent(sk)) ? IP_REPLY_ARG_NOSRCCHECK : 0; - - /* When socket is gone, all binding information is lost. - * routing might fail in this case. No choice here, if we choose to force - * input interface, we will misroute in case of asymmetric route. - */ - if (sk) - arg.bound_dev_if = sk->sk_bound_dev_if; - - BUILD_BUG_ON(offsetof(struct sock, sk_bound_dev_if) != - offsetof(struct inet_timewait_sock, tw_bound_dev_if)); - - arg.tos = ip_hdr(skb)->tos; - local_bh_disable(); - ip_send_unicast_reply(*this_cpu_ptr(net->ipv4.tcp_sk), - skb, &TCP_SKB_CB(skb)->header.h4.opt, - ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, - &arg, arg.iov[0].iov_len); - - __TCP_INC_STATS(net, TCP_MIB_OUTSEGS); - __TCP_INC_STATS(net, TCP_MIB_OUTRSTS); - local_bh_enable(); - -#ifdef CONFIG_TCP_MD5SIG -out: - rcu_read_unlock(); -#endif -} - -/* The code following below sending ACKs in SYN-RECV and TIME-WAIT states - outside socket context is ugly, certainly. What can I do? - */ - -static void tcp_v4_send_ack(struct net *net, - struct sk_buff *skb, u32 seq, u32 ack, - u32 win, u32 tsval, u32 tsecr, int oif, - struct tcp_md5sig_key *key, - int reply_flags, u8 tos) -{ - const struct tcphdr *th = tcp_hdr(skb); - struct { - struct tcphdr th; - __be32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2) -#ifdef CONFIG_TCP_MD5SIG - + (TCPOLEN_MD5SIG_ALIGNED >> 2) -#endif - ]; - } rep; - struct ip_reply_arg arg; - - memset(&rep.th, 0, sizeof(struct tcphdr)); - memset(&arg, 0, sizeof(arg)); - - arg.iov[0].iov_base = (unsigned char *)&rep; - arg.iov[0].iov_len = sizeof(rep.th); - if (tsecr) { - rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | - (TCPOPT_TIMESTAMP << 8) | - TCPOLEN_TIMESTAMP); - rep.opt[1] = htonl(tsval); - rep.opt[2] = htonl(tsecr); - arg.iov[0].iov_len += TCPOLEN_TSTAMP_ALIGNED; - } - - /* Swap the send and the receive. */ - rep.th.dest = th->source; - rep.th.source = th->dest; - rep.th.doff = arg.iov[0].iov_len / 4; - rep.th.seq = htonl(seq); - rep.th.ack_seq = htonl(ack); - rep.th.ack = 1; - rep.th.window = htons(win); - -#ifdef CONFIG_TCP_MD5SIG - if (key) { - int offset = (tsecr) ? 3 : 0; - - rep.opt[offset++] = htonl((TCPOPT_NOP << 24) | - (TCPOPT_NOP << 16) | - (TCPOPT_MD5SIG << 8) | - TCPOLEN_MD5SIG); - arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED; - rep.th.doff = arg.iov[0].iov_len/4; - - tcp_v4_md5_hash_hdr((__u8 *) &rep.opt[offset], - key, ip_hdr(skb)->saddr, - ip_hdr(skb)->daddr, &rep.th); - } -#endif - arg.flags = reply_flags; - arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, - ip_hdr(skb)->saddr, /* XXX */ - arg.iov[0].iov_len, IPPROTO_TCP, 0); - arg.csumoffset = offsetof(struct tcphdr, check) / 2; - if (oif) - arg.bound_dev_if = oif; - arg.tos = tos; - local_bh_disable(); - ip_send_unicast_reply(*this_cpu_ptr(net->ipv4.tcp_sk), - skb, &TCP_SKB_CB(skb)->header.h4.opt, - ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, - &arg, arg.iov[0].iov_len); - - __TCP_INC_STATS(net, TCP_MIB_OUTSEGS); - local_bh_enable(); -} - -static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) -{ - struct inet_timewait_sock *tw = inet_twsk(sk); - struct tcp_timewait_sock *tcptw = tcp_twsk(sk); - - tcp_v4_send_ack(sock_net(sk), skb, - tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, - tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, - tcp_time_stamp + tcptw->tw_ts_offset, - tcptw->tw_ts_recent, - tw->tw_bound_dev_if, - tcp_twsk_md5_key(tcptw), - tw->tw_transparent ? IP_REPLY_ARG_NOSRCCHECK : 0, - tw->tw_tos - ); - - inet_twsk_put(tw); -} - -static void tcp_v4_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, - struct request_sock *req) -{ - /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV - * sk->sk_state == TCP_SYN_RECV -> for Fast Open. - */ - u32 seq = (sk->sk_state == TCP_LISTEN) ? tcp_rsk(req)->snt_isn + 1 : - tcp_sk(sk)->snd_nxt; - - /* RFC 7323 2.3 - * The window field (SEG.WND) of every outgoing segment, with the - * exception of segments, MUST be right-shifted by - * Rcv.Wind.Shift bits: - */ - tcp_v4_send_ack(sock_net(sk), skb, seq, - tcp_rsk(req)->rcv_nxt, - req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, - tcp_time_stamp, - req->ts_recent, - 0, - tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&ip_hdr(skb)->daddr, - AF_INET), - inet_rsk(req)->no_srccheck ? IP_REPLY_ARG_NOSRCCHECK : 0, - ip_hdr(skb)->tos); -} - -/* - * Send a SYN-ACK after having received a SYN. - * This still operates on a request_sock only, not on a big - * socket. - */ -static int tcp_v4_send_synack(const struct sock *sk, struct dst_entry *dst, - struct flowi *fl, - struct request_sock *req, - struct tcp_fastopen_cookie *foc, - enum tcp_synack_type synack_type) -{ - const struct inet_request_sock *ireq = inet_rsk(req); - struct flowi4 fl4; - int err = -1; - struct sk_buff *skb; - - /* First, grab a route. */ - if (!dst && (dst = inet_csk_route_req(sk, &fl4, req)) == NULL) - return -1; - - skb = tcp_make_synack(sk, dst, req, foc, synack_type); - - if (skb) { - __tcp_v4_send_check(skb, ireq->ir_loc_addr, ireq->ir_rmt_addr); - - err = ip_build_and_send_pkt(skb, sk, ireq->ir_loc_addr, - ireq->ir_rmt_addr, - ireq->opt); - err = net_xmit_eval(err); - } - - return err; -} - -/* - * IPv4 request_sock destructor. - */ -static void tcp_v4_reqsk_destructor(struct request_sock *req) -{ - kfree(inet_rsk(req)->opt); -} - -#ifdef CONFIG_TCP_MD5SIG -/* - * RFC2385 MD5 checksumming requires a mapping of - * IP address->MD5 Key. - * We need to maintain these in the sk structure. - */ - -/* Find the Key structure for an address. */ -struct tcp_md5sig_key *tcp_md5_do_lookup(const struct sock *sk, - const union tcp_md5_addr *addr, - int family) -{ - const struct tcp_sock *tp = tcp_sk(sk); - struct tcp_md5sig_key *key; - unsigned int size = sizeof(struct in_addr); - const struct tcp_md5sig_info *md5sig; - - /* caller either holds rcu_read_lock() or socket lock */ - md5sig = rcu_dereference_check(tp->md5sig_info, - lockdep_sock_is_held(sk)); - if (!md5sig) - return NULL; -#if IS_ENABLED(CONFIG_IPV6) - if (family == AF_INET6) - size = sizeof(struct in6_addr); -#endif - hlist_for_each_entry_rcu(key, &md5sig->head, node) { - if (key->family != family) - continue; - if (!memcmp(&key->addr, addr, size)) - return key; - } - return NULL; -} -EXPORT_SYMBOL(tcp_md5_do_lookup); - -struct tcp_md5sig_key *tcp_v4_md5_lookup(const struct sock *sk, - const struct sock *addr_sk) -{ - const union tcp_md5_addr *addr; - - addr = (const union tcp_md5_addr *)&addr_sk->sk_daddr; - return tcp_md5_do_lookup(sk, addr, AF_INET); -} -EXPORT_SYMBOL(tcp_v4_md5_lookup); - -/* This can be called on a newly created socket, from other files */ -int tcp_md5_do_add(struct sock *sk, const union tcp_md5_addr *addr, - int family, const u8 *newkey, u8 newkeylen, gfp_t gfp) -{ - /* Add Key to the list */ - struct tcp_md5sig_key *key; - struct tcp_sock *tp = tcp_sk(sk); - struct tcp_md5sig_info *md5sig; - - key = tcp_md5_do_lookup(sk, addr, family); - if (key) { - /* Pre-existing entry - just update that one. */ - memcpy(key->key, newkey, newkeylen); - key->keylen = newkeylen; - return 0; - } - - md5sig = rcu_dereference_protected(tp->md5sig_info, - lockdep_sock_is_held(sk)); - if (!md5sig) { - md5sig = kmalloc(sizeof(*md5sig), gfp); - if (!md5sig) - return -ENOMEM; - - sk_nocaps_add(sk, NETIF_F_GSO_MASK); - INIT_HLIST_HEAD(&md5sig->head); - rcu_assign_pointer(tp->md5sig_info, md5sig); - } - - key = sock_kmalloc(sk, sizeof(*key), gfp); - if (!key) - return -ENOMEM; - if (!tcp_alloc_md5sig_pool()) { - sock_kfree_s(sk, key, sizeof(*key)); - return -ENOMEM; - } - - memcpy(key->key, newkey, newkeylen); - key->keylen = newkeylen; - key->family = family; - memcpy(&key->addr, addr, - (family == AF_INET6) ? sizeof(struct in6_addr) : - sizeof(struct in_addr)); - hlist_add_head_rcu(&key->node, &md5sig->head); - return 0; -} -EXPORT_SYMBOL(tcp_md5_do_add); - -int tcp_md5_do_del(struct sock *sk, const union tcp_md5_addr *addr, int family) -{ - struct tcp_md5sig_key *key; - - key = tcp_md5_do_lookup(sk, addr, family); - if (!key) - return -ENOENT; - hlist_del_rcu(&key->node); - atomic_sub(sizeof(*key), &sk->sk_omem_alloc); - kfree_rcu(key, rcu); - return 0; -} -EXPORT_SYMBOL(tcp_md5_do_del); - -static void tcp_clear_md5_list(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct tcp_md5sig_key *key; - struct hlist_node *n; - struct tcp_md5sig_info *md5sig; - - md5sig = rcu_dereference_protected(tp->md5sig_info, 1); - - hlist_for_each_entry_safe(key, n, &md5sig->head, node) { - hlist_del_rcu(&key->node); - atomic_sub(sizeof(*key), &sk->sk_omem_alloc); - kfree_rcu(key, rcu); - } -} - -static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, - int optlen) -{ - struct tcp_md5sig cmd; - struct sockaddr_in *sin = (struct sockaddr_in *)&cmd.tcpm_addr; - - if (optlen < sizeof(cmd)) - return -EINVAL; - - if (copy_from_user(&cmd, optval, sizeof(cmd))) - return -EFAULT; - - if (sin->sin_family != AF_INET) - return -EINVAL; - - if (!cmd.tcpm_keylen) - return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr, - AF_INET); - - if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) - return -EINVAL; - - return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin->sin_addr.s_addr, - AF_INET, cmd.tcpm_key, cmd.tcpm_keylen, - GFP_KERNEL); -} - -static int tcp_v4_md5_hash_headers(struct tcp_md5sig_pool *hp, - __be32 daddr, __be32 saddr, - const struct tcphdr *th, int nbytes) -{ - struct tcp4_pseudohdr *bp; - struct scatterlist sg; - struct tcphdr *_th; - - bp = hp->scratch; - bp->saddr = saddr; - bp->daddr = daddr; - bp->pad = 0; - bp->protocol = IPPROTO_TCP; - bp->len = cpu_to_be16(nbytes); - - _th = (struct tcphdr *)(bp + 1); - memcpy(_th, th, sizeof(*th)); - _th->check = 0; - - sg_init_one(&sg, bp, sizeof(*bp) + sizeof(*th)); - ahash_request_set_crypt(hp->md5_req, &sg, NULL, - sizeof(*bp) + sizeof(*th)); - return crypto_ahash_update(hp->md5_req); -} - -static int tcp_v4_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, - __be32 daddr, __be32 saddr, const struct tcphdr *th) -{ - struct tcp_md5sig_pool *hp; - struct ahash_request *req; - - hp = tcp_get_md5sig_pool(); - if (!hp) - goto clear_hash_noput; - req = hp->md5_req; - - if (crypto_ahash_init(req)) - goto clear_hash; - if (tcp_v4_md5_hash_headers(hp, daddr, saddr, th, th->doff << 2)) - goto clear_hash; - if (tcp_md5_hash_key(hp, key)) - goto clear_hash; - ahash_request_set_crypt(req, NULL, md5_hash, 0); - if (crypto_ahash_final(req)) - goto clear_hash; - - tcp_put_md5sig_pool(); - return 0; - -clear_hash: - tcp_put_md5sig_pool(); -clear_hash_noput: - memset(md5_hash, 0, 16); - return 1; -} - -int tcp_v4_md5_hash_skb(char *md5_hash, const struct tcp_md5sig_key *key, - const struct sock *sk, - const struct sk_buff *skb) -{ - struct tcp_md5sig_pool *hp; - struct ahash_request *req; - const struct tcphdr *th = tcp_hdr(skb); - __be32 saddr, daddr; - - if (sk) { /* valid for establish/request sockets */ - saddr = sk->sk_rcv_saddr; - daddr = sk->sk_daddr; - } else { - const struct iphdr *iph = ip_hdr(skb); - saddr = iph->saddr; - daddr = iph->daddr; - } - - hp = tcp_get_md5sig_pool(); - if (!hp) - goto clear_hash_noput; - req = hp->md5_req; - - if (crypto_ahash_init(req)) - goto clear_hash; - - if (tcp_v4_md5_hash_headers(hp, daddr, saddr, th, skb->len)) - goto clear_hash; - if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2)) - goto clear_hash; - if (tcp_md5_hash_key(hp, key)) - goto clear_hash; - ahash_request_set_crypt(req, NULL, md5_hash, 0); - if (crypto_ahash_final(req)) - goto clear_hash; - - tcp_put_md5sig_pool(); - return 0; - -clear_hash: - tcp_put_md5sig_pool(); -clear_hash_noput: - memset(md5_hash, 0, 16); - return 1; -} -EXPORT_SYMBOL(tcp_v4_md5_hash_skb); - -#endif - -/* Called with rcu_read_lock() */ -static bool tcp_v4_inbound_md5_hash(const struct sock *sk, - const struct sk_buff *skb) -{ -#ifdef CONFIG_TCP_MD5SIG - /* - * This gets called for each TCP segment that arrives - * so we want to be efficient. - * We have 3 drop cases: - * o No MD5 hash and one expected. - * o MD5 hash and we're not expecting one. - * o MD5 hash and its wrong. - */ - const __u8 *hash_location = NULL; - struct tcp_md5sig_key *hash_expected; - const struct iphdr *iph = ip_hdr(skb); - const struct tcphdr *th = tcp_hdr(skb); - int genhash; - unsigned char newhash[16]; - - hash_expected = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&iph->saddr, - AF_INET); - hash_location = tcp_parse_md5sig_option(th); - - /* We've parsed the options - do we have a hash? */ - if (!hash_expected && !hash_location) - return false; - - if (hash_expected && !hash_location) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5NOTFOUND); - return true; - } - - if (!hash_expected && hash_location) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5UNEXPECTED); - return true; - } - - /* Okay, so this is hash_expected and hash_location - - * so we need to calculate the checksum. - */ - genhash = tcp_v4_md5_hash_skb(newhash, - hash_expected, - NULL, skb); - - if (genhash || memcmp(hash_location, newhash, 16) != 0) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5FAILURE); - net_info_ratelimited("MD5 Hash failed for (%pI4, %d)->(%pI4, %d)%s\n", - &iph->saddr, ntohs(th->source), - &iph->daddr, ntohs(th->dest), - genhash ? " tcp_v4_calc_md5_hash failed" - : ""); - return true; - } - return false; -#endif - return false; -} - -static void tcp_v4_init_req(struct request_sock *req, - const struct sock *sk_listener, - struct sk_buff *skb) -{ - struct inet_request_sock *ireq = inet_rsk(req); - - sk_rcv_saddr_set(req_to_sk(req), ip_hdr(skb)->daddr); - sk_daddr_set(req_to_sk(req), ip_hdr(skb)->saddr); - ireq->opt = tcp_v4_save_options(skb); -} - -static struct dst_entry *tcp_v4_route_req(const struct sock *sk, - struct flowi *fl, - const struct request_sock *req, - bool *strict) -{ - struct dst_entry *dst = inet_csk_route_req(sk, &fl->u.ip4, req); - - if (strict) { - if (fl->u.ip4.daddr == inet_rsk(req)->ir_rmt_addr) - *strict = true; - else - *strict = false; - } - - return dst; -} - -struct request_sock_ops tcp_request_sock_ops __read_mostly = { - .family = PF_INET, - .obj_size = sizeof(struct tcp_request_sock), - .rtx_syn_ack = tcp_rtx_synack, - .send_ack = tcp_v4_reqsk_send_ack, - .destructor = tcp_v4_reqsk_destructor, - .send_reset = tcp_v4_send_reset, - .syn_ack_timeout = tcp_syn_ack_timeout, -}; - -static const struct tcp_request_sock_ops tcp_request_sock_ipv4_ops = { - .mss_clamp = TCP_MSS_DEFAULT, -#ifdef CONFIG_TCP_MD5SIG - .req_md5_lookup = tcp_v4_md5_lookup, - .calc_md5_hash = tcp_v4_md5_hash_skb, -#endif - .init_req = tcp_v4_init_req, -#ifdef CONFIG_SYN_COOKIES - .cookie_init_seq = cookie_v4_init_sequence, -#endif - .route_req = tcp_v4_route_req, - .init_seq = tcp_v4_init_sequence, - .send_synack = tcp_v4_send_synack, -}; - -int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) -{ - /* Never answer to SYNs send to broadcast or multicast */ - if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) - goto drop; - - return tcp_conn_request(&tcp_request_sock_ops, - &tcp_request_sock_ipv4_ops, sk, skb); - -drop: - tcp_listendrop(sk); - return 0; -} -EXPORT_SYMBOL(tcp_v4_conn_request); - - -/* - * The three way handshake has completed - we got a valid synack - - * now create the new socket. - */ -struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, - struct request_sock *req, - struct dst_entry *dst, - struct request_sock *req_unhash, - bool *own_req) -{ - struct inet_request_sock *ireq; - struct inet_sock *newinet; - struct tcp_sock *newtp; - struct sock *newsk; -#ifdef CONFIG_TCP_MD5SIG - struct tcp_md5sig_key *key; -#endif - struct ip_options_rcu *inet_opt; - - if (sk_acceptq_is_full(sk)) - goto exit_overflow; - - newsk = tcp_create_openreq_child(sk, req, skb); - if (!newsk) - goto exit_nonewsk; - - newsk->sk_gso_type = SKB_GSO_TCPV4; - inet_sk_rx_dst_set(newsk, skb); - - newtp = tcp_sk(newsk); - newinet = inet_sk(newsk); - ireq = inet_rsk(req); - sk_daddr_set(newsk, ireq->ir_rmt_addr); - sk_rcv_saddr_set(newsk, ireq->ir_loc_addr); - newsk->sk_bound_dev_if = ireq->ir_iif; - newinet->inet_saddr = ireq->ir_loc_addr; - inet_opt = ireq->opt; - rcu_assign_pointer(newinet->inet_opt, inet_opt); - ireq->opt = NULL; - newinet->mc_index = inet_iif(skb); - newinet->mc_ttl = ip_hdr(skb)->ttl; - newinet->rcv_tos = ip_hdr(skb)->tos; - inet_csk(newsk)->icsk_ext_hdr_len = 0; - if (inet_opt) - inet_csk(newsk)->icsk_ext_hdr_len = inet_opt->opt.optlen; - newinet->inet_id = newtp->write_seq ^ jiffies; - - if (!dst) { - dst = inet_csk_route_child_sock(sk, newsk, req); - if (!dst) - goto put_and_exit; - } else { - /* syncookie case : see end of cookie_v4_check() */ - } - sk_setup_caps(newsk, dst); - - tcp_ca_openreq_child(newsk, dst); - - tcp_sync_mss(newsk, dst_mtu(dst)); - newtp->advmss = dst_metric_advmss(dst); - if (tcp_sk(sk)->rx_opt.user_mss && - tcp_sk(sk)->rx_opt.user_mss < newtp->advmss) - newtp->advmss = tcp_sk(sk)->rx_opt.user_mss; - - tcp_initialize_rcv_mss(newsk); - -#ifdef CONFIG_TCP_MD5SIG - /* Copy over the MD5 key from the original socket */ - key = tcp_md5_do_lookup(sk, (union tcp_md5_addr *)&newinet->inet_daddr, - AF_INET); - if (key) { - /* - * We're using one, so create a matching key - * on the newsk structure. If we fail to get - * memory, then we end up not copying the key - * across. Shucks. - */ - tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newinet->inet_daddr, - AF_INET, key->key, key->keylen, GFP_ATOMIC); - sk_nocaps_add(newsk, NETIF_F_GSO_MASK); - } -#endif - - if (__inet_inherit_port(sk, newsk) < 0) - goto put_and_exit; - *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash)); - if (*own_req) - tcp_move_syn(newtp, req); - - return newsk; - -exit_overflow: - NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); -exit_nonewsk: - dst_release(dst); -exit: - tcp_listendrop(sk); - return NULL; -put_and_exit: - inet_csk_prepare_forced_close(newsk); - tcp_done(newsk); - goto exit; -} -EXPORT_SYMBOL(tcp_v4_syn_recv_sock); - -static struct sock *tcp_v4_cookie_check(struct sock *sk, struct sk_buff *skb) -{ -#ifdef CONFIG_SYN_COOKIES - const struct tcphdr *th = tcp_hdr(skb); - - if (!th->syn) - sk = cookie_v4_check(sk, skb); -#endif - return sk; -} - -/* The socket must have it's spinlock held when we get - * here, unless it is a TCP_LISTEN socket. - * - * We have a potential double-lock case here, so even when - * doing backlog processing we use the BH locking scheme. - * This is because we cannot sleep with the original spinlock - * held. - */ -int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) -{ - struct sock *rsk; - - if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ - struct dst_entry *dst = sk->sk_rx_dst; - - sock_rps_save_rxhash(sk, skb); - sk_mark_napi_id(sk, skb); - if (dst) { - if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif || - !dst->ops->check(dst, 0)) { - dst_release(dst); - sk->sk_rx_dst = NULL; - } - } - tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len); - return 0; - } - - if (tcp_checksum_complete(skb)) - goto csum_err; - - if (sk->sk_state == TCP_LISTEN) { - struct sock *nsk = tcp_v4_cookie_check(sk, skb); - - if (!nsk) - goto discard; - if (nsk != sk) { - sock_rps_save_rxhash(nsk, skb); - sk_mark_napi_id(nsk, skb); - if (tcp_child_process(sk, nsk, skb)) { - rsk = nsk; - goto reset; - } - return 0; - } - } else - sock_rps_save_rxhash(sk, skb); - - if (tcp_rcv_state_process(sk, skb)) { - rsk = sk; - goto reset; - } - return 0; - -reset: - tcp_v4_send_reset(rsk, skb); -discard: - kfree_skb(skb); - /* Be careful here. If this function gets more complicated and - * gcc suffers from register pressure on the x86, sk (in %ebx) - * might be destroyed here. This current version compiles correctly, - * but you have been warned. - */ - return 0; - -csum_err: - TCP_INC_STATS(sock_net(sk), TCP_MIB_CSUMERRORS); - TCP_INC_STATS(sock_net(sk), TCP_MIB_INERRS); - goto discard; -} -EXPORT_SYMBOL(tcp_v4_do_rcv); - -void tcp_v4_early_demux(struct sk_buff *skb) -{ - const struct iphdr *iph; - const struct tcphdr *th; - struct sock *sk; - - if (skb->pkt_type != PACKET_HOST) - return; - - if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct tcphdr))) - return; - - iph = ip_hdr(skb); - th = tcp_hdr(skb); - - if (th->doff < sizeof(struct tcphdr) / 4) - return; - - sk = __inet_lookup_established(dev_net(skb->dev), &tcp_hashinfo, - iph->saddr, th->source, - iph->daddr, ntohs(th->dest), - skb->skb_iif); - if (sk) { - skb->sk = sk; - skb->destructor = sock_edemux; - if (sk_fullsock(sk)) { - struct dst_entry *dst = READ_ONCE(sk->sk_rx_dst); - - if (dst) - dst = dst_check(dst, 0); - if (dst && - inet_sk(sk)->rx_dst_ifindex == skb->skb_iif) - skb_dst_set_noref(skb, dst); - } - } -} - -/* Packet is added to VJ-style prequeue for processing in process - * context, if a reader task is waiting. Apparently, this exciting - * idea (VJ's mail "Re: query about TCP header on tcp-ip" of 07 Sep 93) - * failed somewhere. Latency? Burstiness? Well, at least now we will - * see, why it failed. 8)8) --ANK - * - */ -bool tcp_prequeue(struct sock *sk, struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (sysctl_tcp_low_latency || !tp->ucopy.task) - return false; - - if (skb->len <= tcp_hdrlen(skb) && - skb_queue_len(&tp->ucopy.prequeue) == 0) - return false; - - /* Before escaping RCU protected region, we need to take care of skb - * dst. Prequeue is only enabled for established sockets. - * For such sockets, we might need the skb dst only to set sk->sk_rx_dst - * Instead of doing full sk_rx_dst validity here, let's perform - * an optimistic check. - */ - if (likely(sk->sk_rx_dst)) - skb_dst_drop(skb); - else - skb_dst_force_safe(skb); - - __skb_queue_tail(&tp->ucopy.prequeue, skb); - tp->ucopy.memory += skb->truesize; - if (skb_queue_len(&tp->ucopy.prequeue) >= 32 || - tp->ucopy.memory + atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf) { - struct sk_buff *skb1; - - BUG_ON(sock_owned_by_user(sk)); - __NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPPREQUEUEDROPPED, - skb_queue_len(&tp->ucopy.prequeue)); - - while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) - sk_backlog_rcv(sk, skb1); - - tp->ucopy.memory = 0; - } else if (skb_queue_len(&tp->ucopy.prequeue) == 1) { - wake_up_interruptible_sync_poll(sk_sleep(sk), - POLLIN | POLLRDNORM | POLLRDBAND); - if (!inet_csk_ack_scheduled(sk)) - inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, - (3 * tcp_rto_min(sk)) / 4, - TCP_RTO_MAX); - } - return true; -} -EXPORT_SYMBOL(tcp_prequeue); - -bool tcp_add_backlog(struct sock *sk, struct sk_buff *skb) -{ - u32 limit = sk->sk_rcvbuf + sk->sk_sndbuf; - - /* Only socket owner can try to collapse/prune rx queues - * to reduce memory overhead, so add a little headroom here. - * Few sockets backlog are possibly concurrently non empty. - */ - limit += 64*1024; - - /* In case all data was pulled from skb frags (in __pskb_pull_tail()), - * we can fix skb->truesize to its real value to avoid future drops. - * This is valid because skb is not yet charged to the socket. - * It has been noticed pure SACK packets were sometimes dropped - * (if cooked by drivers without copybreak feature). - */ - if (!skb->data_len) - skb->truesize = SKB_TRUESIZE(skb_end_offset(skb)); - - if (unlikely(sk_add_backlog(sk, skb, limit))) { - bh_unlock_sock(sk); - __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPBACKLOGDROP); - return true; - } - return false; -} -EXPORT_SYMBOL(tcp_add_backlog); - -int tcp_filter(struct sock *sk, struct sk_buff *skb) -{ - struct tcphdr *th = (struct tcphdr *)skb->data; - unsigned int eaten = skb->len; - int err; - - err = sk_filter_trim_cap(sk, skb, th->doff * 4); - if (!err) { - eaten -= skb->len; - TCP_SKB_CB(skb)->end_seq -= eaten; - } - return err; -} -EXPORT_SYMBOL(tcp_filter); - -/* - * From tcp_input.c - */ - -int tcp_v4_rcv(struct sk_buff *skb) -{ - struct net *net = dev_net(skb->dev); - const struct iphdr *iph; - const struct tcphdr *th; - bool refcounted; - struct sock *sk; - int ret; - - if (skb->pkt_type != PACKET_HOST) - goto discard_it; - - /* Count it even if it's bad */ - __TCP_INC_STATS(net, TCP_MIB_INSEGS); - - if (!pskb_may_pull(skb, sizeof(struct tcphdr))) - goto discard_it; - - th = (const struct tcphdr *)skb->data; - - if (unlikely(th->doff < sizeof(struct tcphdr) / 4)) - goto bad_packet; - if (!pskb_may_pull(skb, th->doff * 4)) - goto discard_it; - - /* An explanation is required here, I think. - * Packet length and doff are validated by header prediction, - * provided case of th->doff==0 is eliminated. - * So, we defer the checks. */ - - if (skb_checksum_init(skb, IPPROTO_TCP, inet_compute_pseudo)) - goto csum_error; - - th = (const struct tcphdr *)skb->data; - iph = ip_hdr(skb); - /* This is tricky : We move IPCB at its correct location into TCP_SKB_CB() - * barrier() makes sure compiler wont play fool^Waliasing games. - */ - memmove(&TCP_SKB_CB(skb)->header.h4, IPCB(skb), - sizeof(struct inet_skb_parm)); - barrier(); - - TCP_SKB_CB(skb)->seq = ntohl(th->seq); - TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + - skb->len - th->doff * 4); - TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); - TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); - TCP_SKB_CB(skb)->tcp_tw_isn = 0; - TCP_SKB_CB(skb)->ip_dsfield = ipv4_get_dsfield(iph); - TCP_SKB_CB(skb)->sacked = 0; - -lookup: - sk = __inet_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), th->source, - th->dest, &refcounted); - if (!sk) - goto no_tcp_socket; - -process: - if (sk->sk_state == TCP_TIME_WAIT) - goto do_time_wait; - - if (sk->sk_state == TCP_NEW_SYN_RECV) { - struct request_sock *req = inet_reqsk(sk); - struct sock *nsk; - - sk = req->rsk_listener; - if (unlikely(tcp_v4_inbound_md5_hash(sk, skb))) { - sk_drops_add(sk, skb); - reqsk_put(req); - goto discard_it; - } - if (unlikely(sk->sk_state != TCP_LISTEN)) { - inet_csk_reqsk_queue_drop_and_put(sk, req); - goto lookup; - } - /* We own a reference on the listener, increase it again - * as we might lose it too soon. - */ - sock_hold(sk); - refcounted = true; - nsk = tcp_check_req(sk, skb, req, false); - if (!nsk) { - reqsk_put(req); - goto discard_and_relse; - } - if (nsk == sk) { - reqsk_put(req); - } else if (tcp_child_process(sk, nsk, skb)) { - tcp_v4_send_reset(nsk, skb); - goto discard_and_relse; - } else { - sock_put(sk); - return 0; - } - } - if (unlikely(iph->ttl < inet_sk(sk)->min_ttl)) { - __NET_INC_STATS(net, LINUX_MIB_TCPMINTTLDROP); - goto discard_and_relse; - } - - if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) - goto discard_and_relse; - - if (tcp_v4_inbound_md5_hash(sk, skb)) - goto discard_and_relse; - - nf_reset(skb); - - if (tcp_filter(sk, skb)) - goto discard_and_relse; - th = (const struct tcphdr *)skb->data; - iph = ip_hdr(skb); - - skb->dev = NULL; - - if (sk->sk_state == TCP_LISTEN) { - ret = tcp_v4_do_rcv(sk, skb); - goto put_and_return; - } - - sk_incoming_cpu_update(sk); - - bh_lock_sock_nested(sk); - tcp_segs_in(tcp_sk(sk), skb); - ret = 0; - if (!sock_owned_by_user(sk)) { - if (!tcp_prequeue(sk, skb)) - ret = tcp_v4_do_rcv(sk, skb); - } else if (tcp_add_backlog(sk, skb)) { - goto discard_and_relse; - } - bh_unlock_sock(sk); - -put_and_return: - if (refcounted) - sock_put(sk); - - return ret; - -no_tcp_socket: - if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) - goto discard_it; - - if (tcp_checksum_complete(skb)) { -csum_error: - __TCP_INC_STATS(net, TCP_MIB_CSUMERRORS); -bad_packet: - __TCP_INC_STATS(net, TCP_MIB_INERRS); - } else { - tcp_v4_send_reset(NULL, skb); - } - -discard_it: - /* Discard frame. */ - kfree_skb(skb); - return 0; - -discard_and_relse: - sk_drops_add(sk, skb); - if (refcounted) - sock_put(sk); - goto discard_it; - -do_time_wait: - if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { - inet_twsk_put(inet_twsk(sk)); - goto discard_it; - } - - if (tcp_checksum_complete(skb)) { - inet_twsk_put(inet_twsk(sk)); - goto csum_error; - } - switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) { - case TCP_TW_SYN: { - struct sock *sk2 = inet_lookup_listener(dev_net(skb->dev), - &tcp_hashinfo, skb, - __tcp_hdrlen(th), - iph->saddr, th->source, - iph->daddr, th->dest, - inet_iif(skb)); - if (sk2) { - inet_twsk_deschedule_put(inet_twsk(sk)); - sk = sk2; - refcounted = false; - goto process; - } - /* Fall through to ACK */ - } - case TCP_TW_ACK: - tcp_v4_timewait_ack(sk, skb); - break; - case TCP_TW_RST: - tcp_v4_send_reset(sk, skb); - inet_twsk_deschedule_put(inet_twsk(sk)); - goto discard_it; - case TCP_TW_SUCCESS:; - } - goto discard_it; -} - -static struct timewait_sock_ops tcp_timewait_sock_ops = { - .twsk_obj_size = sizeof(struct tcp_timewait_sock), - .twsk_unique = tcp_twsk_unique, - .twsk_destructor= tcp_twsk_destructor, -}; - -void inet_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) -{ - struct dst_entry *dst = skb_dst(skb); - - if (dst && dst_hold_safe(dst)) { - sk->sk_rx_dst = dst; - inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; - } -} -EXPORT_SYMBOL(inet_sk_rx_dst_set); - -const struct inet_connection_sock_af_ops ipv4_specific = { - .queue_xmit = ip_queue_xmit, - .send_check = tcp_v4_send_check, - .rebuild_header = inet_sk_rebuild_header, - .sk_rx_dst_set = inet_sk_rx_dst_set, - .conn_request = tcp_v4_conn_request, - .syn_recv_sock = tcp_v4_syn_recv_sock, - .net_header_len = sizeof(struct iphdr), - .setsockopt = ip_setsockopt, - .getsockopt = ip_getsockopt, - .addr2sockaddr = inet_csk_addr2sockaddr, - .sockaddr_len = sizeof(struct sockaddr_in), - .bind_conflict = inet_csk_bind_conflict, -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_ip_setsockopt, - .compat_getsockopt = compat_ip_getsockopt, -#endif - .mtu_reduced = tcp_v4_mtu_reduced, -}; -EXPORT_SYMBOL(ipv4_specific); - -#ifdef CONFIG_TCP_MD5SIG -static const struct tcp_sock_af_ops tcp_sock_ipv4_specific = { - .md5_lookup = tcp_v4_md5_lookup, - .calc_md5_hash = tcp_v4_md5_hash_skb, - .md5_parse = tcp_v4_parse_md5_keys, -}; -#endif - -/* NOTE: A lot of things set to zero explicitly by call to - * sk_alloc() so need not be done here. - */ -static int tcp_v4_init_sock(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - - tcp_init_sock(sk); - - icsk->icsk_af_ops = &ipv4_specific; - -#ifdef CONFIG_TCP_MD5SIG - tcp_sk(sk)->af_specific = &tcp_sock_ipv4_specific; -#endif - - return 0; -} - -void tcp_v4_destroy_sock(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - - tcp_clear_xmit_timers(sk); - - tcp_cleanup_congestion_control(sk); - - /* Cleanup up the write buffer. */ - tcp_write_queue_purge(sk); - - /* Cleans up our, hopefully empty, out_of_order_queue. */ - skb_rbtree_purge(&tp->out_of_order_queue); - -#ifdef CONFIG_TCP_MD5SIG - /* Clean up the MD5 key list, if any */ - if (tp->md5sig_info) { - tcp_clear_md5_list(sk); - kfree_rcu(tp->md5sig_info, rcu); - tp->md5sig_info = NULL; - } -#endif - - /* Clean prequeue, it must be empty really */ - __skb_queue_purge(&tp->ucopy.prequeue); - - /* Clean up a referenced TCP bind bucket. */ - if (inet_csk(sk)->icsk_bind_hash) - inet_put_port(sk); - - BUG_ON(tp->fastopen_rsk); - - /* If socket is aborted during connect operation */ - tcp_free_fastopen_req(tp); - tcp_saved_syn_free(tp); - - local_bh_disable(); - sk_sockets_allocated_dec(sk); - local_bh_enable(); -} -EXPORT_SYMBOL(tcp_v4_destroy_sock); - -#ifdef CONFIG_PROC_FS -/* Proc filesystem TCP sock list dumping. */ - -/* - * Get next listener socket follow cur. If cur is NULL, get first socket - * starting from bucket given in st->bucket; when st->bucket is zero the - * very first socket in the hash table is returned. - */ -static void *listening_get_next(struct seq_file *seq, void *cur) -{ - struct tcp_iter_state *st = seq->private; - struct net *net = seq_file_net(seq); - struct inet_listen_hashbucket *ilb; - struct sock *sk = cur; - - if (!sk) { -get_head: - ilb = &tcp_hashinfo.listening_hash[st->bucket]; - spin_lock_bh(&ilb->lock); - sk = sk_head(&ilb->head); - st->offset = 0; - goto get_sk; - } - ilb = &tcp_hashinfo.listening_hash[st->bucket]; - ++st->num; - ++st->offset; - - sk = sk_next(sk); -get_sk: - sk_for_each_from(sk) { - if (!net_eq(sock_net(sk), net)) - continue; - if (sk->sk_family == st->family) - return sk; - } - spin_unlock_bh(&ilb->lock); - st->offset = 0; - if (++st->bucket < INET_LHTABLE_SIZE) - goto get_head; - return NULL; -} - -static void *listening_get_idx(struct seq_file *seq, loff_t *pos) -{ - struct tcp_iter_state *st = seq->private; - void *rc; - - st->bucket = 0; - st->offset = 0; - rc = listening_get_next(seq, NULL); - - while (rc && *pos) { - rc = listening_get_next(seq, rc); - --*pos; - } - return rc; -} - -static inline bool empty_bucket(const struct tcp_iter_state *st) -{ - return hlist_nulls_empty(&tcp_hashinfo.ehash[st->bucket].chain); -} - -/* - * Get first established socket starting from bucket given in st->bucket. - * If st->bucket is zero, the very first socket in the hash is returned. - */ -static void *established_get_first(struct seq_file *seq) -{ - struct tcp_iter_state *st = seq->private; - struct net *net = seq_file_net(seq); - void *rc = NULL; - - st->offset = 0; - for (; st->bucket <= tcp_hashinfo.ehash_mask; ++st->bucket) { - struct sock *sk; - struct hlist_nulls_node *node; - spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, st->bucket); - - /* Lockless fast path for the common case of empty buckets */ - if (empty_bucket(st)) - continue; - - spin_lock_bh(lock); - sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) { - if (sk->sk_family != st->family || - !net_eq(sock_net(sk), net)) { - continue; - } - rc = sk; - goto out; - } - spin_unlock_bh(lock); - } -out: - return rc; -} - -static void *established_get_next(struct seq_file *seq, void *cur) -{ - struct sock *sk = cur; - struct hlist_nulls_node *node; - struct tcp_iter_state *st = seq->private; - struct net *net = seq_file_net(seq); - - ++st->num; - ++st->offset; - - sk = sk_nulls_next(sk); - - sk_nulls_for_each_from(sk, node) { - if (sk->sk_family == st->family && net_eq(sock_net(sk), net)) - return sk; - } - - spin_unlock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket)); - ++st->bucket; - return established_get_first(seq); -} - -static void *established_get_idx(struct seq_file *seq, loff_t pos) -{ - struct tcp_iter_state *st = seq->private; - void *rc; - - st->bucket = 0; - rc = established_get_first(seq); - - while (rc && pos) { - rc = established_get_next(seq, rc); - --pos; - } - return rc; -} - -static void *tcp_get_idx(struct seq_file *seq, loff_t pos) -{ - void *rc; - struct tcp_iter_state *st = seq->private; - - st->state = TCP_SEQ_STATE_LISTENING; - rc = listening_get_idx(seq, &pos); - - if (!rc) { - st->state = TCP_SEQ_STATE_ESTABLISHED; - rc = established_get_idx(seq, pos); - } - - return rc; -} - -static void *tcp_seek_last_pos(struct seq_file *seq) -{ - struct tcp_iter_state *st = seq->private; - int offset = st->offset; - int orig_num = st->num; - void *rc = NULL; - - switch (st->state) { - case TCP_SEQ_STATE_LISTENING: - if (st->bucket >= INET_LHTABLE_SIZE) - break; - st->state = TCP_SEQ_STATE_LISTENING; - rc = listening_get_next(seq, NULL); - while (offset-- && rc) - rc = listening_get_next(seq, rc); - if (rc) - break; - st->bucket = 0; - st->state = TCP_SEQ_STATE_ESTABLISHED; - /* Fallthrough */ - case TCP_SEQ_STATE_ESTABLISHED: - if (st->bucket > tcp_hashinfo.ehash_mask) - break; - rc = established_get_first(seq); - while (offset-- && rc) - rc = established_get_next(seq, rc); - } - - st->num = orig_num; - - return rc; -} - -static void *tcp_seq_start(struct seq_file *seq, loff_t *pos) -{ - struct tcp_iter_state *st = seq->private; - void *rc; - - if (*pos && *pos == st->last_pos) { - rc = tcp_seek_last_pos(seq); - if (rc) - goto out; - } - - st->state = TCP_SEQ_STATE_LISTENING; - st->num = 0; - st->bucket = 0; - st->offset = 0; - rc = *pos ? tcp_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; - -out: - st->last_pos = *pos; - return rc; -} - -static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct tcp_iter_state *st = seq->private; - void *rc = NULL; - - if (v == SEQ_START_TOKEN) { - rc = tcp_get_idx(seq, 0); - goto out; - } - - switch (st->state) { - case TCP_SEQ_STATE_LISTENING: - rc = listening_get_next(seq, v); - if (!rc) { - st->state = TCP_SEQ_STATE_ESTABLISHED; - st->bucket = 0; - st->offset = 0; - rc = established_get_first(seq); - } - break; - case TCP_SEQ_STATE_ESTABLISHED: - rc = established_get_next(seq, v); - break; - } -out: - ++*pos; - st->last_pos = *pos; - return rc; -} - -static void tcp_seq_stop(struct seq_file *seq, void *v) -{ - struct tcp_iter_state *st = seq->private; - - switch (st->state) { - case TCP_SEQ_STATE_LISTENING: - if (v != SEQ_START_TOKEN) - spin_unlock_bh(&tcp_hashinfo.listening_hash[st->bucket].lock); - break; - case TCP_SEQ_STATE_ESTABLISHED: - if (v) - spin_unlock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket)); - break; - } -} - -int tcp_seq_open(struct inode *inode, struct file *file) -{ - struct tcp_seq_afinfo *afinfo = PDE_DATA(inode); - struct tcp_iter_state *s; - int err; - - err = seq_open_net(inode, file, &afinfo->seq_ops, - sizeof(struct tcp_iter_state)); - if (err < 0) - return err; - - s = ((struct seq_file *)file->private_data)->private; - s->family = afinfo->family; - s->last_pos = 0; - return 0; -} -EXPORT_SYMBOL(tcp_seq_open); - -int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo) -{ - int rc = 0; - struct proc_dir_entry *p; - - afinfo->seq_ops.start = tcp_seq_start; - afinfo->seq_ops.next = tcp_seq_next; - afinfo->seq_ops.stop = tcp_seq_stop; - - p = proc_create_data(afinfo->name, S_IRUGO, net->proc_net, - afinfo->seq_fops, afinfo); - if (!p) - rc = -ENOMEM; - return rc; -} -EXPORT_SYMBOL(tcp_proc_register); - -void tcp_proc_unregister(struct net *net, struct tcp_seq_afinfo *afinfo) -{ - remove_proc_entry(afinfo->name, net->proc_net); -} -EXPORT_SYMBOL(tcp_proc_unregister); - -static void get_openreq4(const struct request_sock *req, - struct seq_file *f, int i) -{ - const struct inet_request_sock *ireq = inet_rsk(req); - long delta = req->rsk_timer.expires - jiffies; - - seq_printf(f, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5u %8d %u %d %pK", - i, - ireq->ir_loc_addr, - ireq->ir_num, - ireq->ir_rmt_addr, - ntohs(ireq->ir_rmt_port), - TCP_SYN_RECV, - 0, 0, /* could print option size, but that is af dependent. */ - 1, /* timers active (only the expire timer) */ - jiffies_delta_to_clock_t(delta), - req->num_timeout, - from_kuid_munged(seq_user_ns(f), - sock_i_uid(req->rsk_listener)), - 0, /* non standard timer */ - 0, /* open_requests have no inode */ - 0, - req); -} - -static void get_tcp4_sock(struct sock *sk, struct seq_file *f, int i) -{ - int timer_active; - unsigned long timer_expires; - const struct tcp_sock *tp = tcp_sk(sk); - const struct inet_connection_sock *icsk = inet_csk(sk); - const struct inet_sock *inet = inet_sk(sk); - const struct fastopen_queue *fastopenq = &icsk->icsk_accept_queue.fastopenq; - __be32 dest = inet->inet_daddr; - __be32 src = inet->inet_rcv_saddr; - __u16 destp = ntohs(inet->inet_dport); - __u16 srcp = ntohs(inet->inet_sport); - int rx_queue; - int state; - - if (icsk->icsk_pending == ICSK_TIME_RETRANS || - icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS || - icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) { - timer_active = 1; - timer_expires = icsk->icsk_timeout; - } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) { - timer_active = 4; - timer_expires = icsk->icsk_timeout; - } else if (timer_pending(&sk->sk_timer)) { - timer_active = 2; - timer_expires = sk->sk_timer.expires; - } else { - timer_active = 0; - timer_expires = jiffies; - } - - state = sk_state_load(sk); - if (state == TCP_LISTEN) - rx_queue = sk->sk_ack_backlog; - else - /* Because we don't lock the socket, - * we might find a transient negative value. - */ - rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0); - - seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX " - "%08X %5u %8d %lu %d %pK %lu %lu %u %u %d", - i, src, srcp, dest, destp, state, - tp->write_seq - tp->snd_una, - rx_queue, - timer_active, - jiffies_delta_to_clock_t(timer_expires - jiffies), - icsk->icsk_retransmits, - from_kuid_munged(seq_user_ns(f), sock_i_uid(sk)), - icsk->icsk_probes_out, - sock_i_ino(sk), - atomic_read(&sk->sk_refcnt), sk, - jiffies_to_clock_t(icsk->icsk_rto), - jiffies_to_clock_t(icsk->icsk_ack.ato), - (icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong, - tp->snd_cwnd, - state == TCP_LISTEN ? - fastopenq->max_qlen : - (tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh)); -} - -static void get_timewait4_sock(const struct inet_timewait_sock *tw, - struct seq_file *f, int i) -{ - long delta = tw->tw_timer.expires - jiffies; - __be32 dest, src; - __u16 destp, srcp; - - dest = tw->tw_daddr; - src = tw->tw_rcv_saddr; - destp = ntohs(tw->tw_dport); - srcp = ntohs(tw->tw_sport); - - seq_printf(f, "%4d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK", - i, src, srcp, dest, destp, tw->tw_substate, 0, 0, - 3, jiffies_delta_to_clock_t(delta), 0, 0, 0, 0, - atomic_read(&tw->tw_refcnt), tw); -} - -#define TMPSZ 150 - -static int tcp4_seq_show(struct seq_file *seq, void *v) -{ - struct tcp_iter_state *st; - struct sock *sk = v; - - seq_setwidth(seq, TMPSZ - 1); - if (v == SEQ_START_TOKEN) { - seq_puts(seq, " sl local_address rem_address st tx_queue " - "rx_queue tr tm->when retrnsmt uid timeout " - "inode"); - goto out; - } - st = seq->private; - - if (sk->sk_state == TCP_TIME_WAIT) - get_timewait4_sock(v, seq, st->num); - else if (sk->sk_state == TCP_NEW_SYN_RECV) - get_openreq4(v, seq, st->num); - else - get_tcp4_sock(v, seq, st->num); -out: - seq_pad(seq, '\n'); - return 0; -} - -static const struct file_operations tcp_afinfo_seq_fops = { - .owner = THIS_MODULE, - .open = tcp_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net -}; - -static struct tcp_seq_afinfo tcp4_seq_afinfo = { - .name = "tcp", - .family = AF_INET, - .seq_fops = &tcp_afinfo_seq_fops, - .seq_ops = { - .show = tcp4_seq_show, - }, -}; - -static int __net_init tcp4_proc_init_net(struct net *net) -{ - return tcp_proc_register(net, &tcp4_seq_afinfo); -} - -static void __net_exit tcp4_proc_exit_net(struct net *net) -{ - tcp_proc_unregister(net, &tcp4_seq_afinfo); -} - -static struct pernet_operations tcp4_net_ops = { - .init = tcp4_proc_init_net, - .exit = tcp4_proc_exit_net, -}; - -int __init tcp4_proc_init(void) -{ - return register_pernet_subsys(&tcp4_net_ops); -} - -void tcp4_proc_exit(void) -{ - unregister_pernet_subsys(&tcp4_net_ops); -} -#endif /* CONFIG_PROC_FS */ - -struct proto tcp_prot = { - .name = "TCP", - .owner = THIS_MODULE, - .close = tcp_close, - .connect = tcp_v4_connect, - .disconnect = tcp_disconnect, - .accept = inet_csk_accept, - .ioctl = tcp_ioctl, - .init = tcp_v4_init_sock, - .destroy = tcp_v4_destroy_sock, - .shutdown = tcp_shutdown, - .setsockopt = tcp_setsockopt, - .getsockopt = tcp_getsockopt, - .recvmsg = tcp_recvmsg, - .sendmsg = tcp_sendmsg, - .sendpage = tcp_sendpage, - .backlog_rcv = tcp_v4_do_rcv, - .release_cb = tcp_release_cb, - .hash = inet_hash, - .unhash = inet_unhash, - .get_port = inet_csk_get_port, - .enter_memory_pressure = tcp_enter_memory_pressure, - .stream_memory_free = tcp_stream_memory_free, - .sockets_allocated = &tcp_sockets_allocated, - .orphan_count = &tcp_orphan_count, - .memory_allocated = &tcp_memory_allocated, - .memory_pressure = &tcp_memory_pressure, - .sysctl_mem = sysctl_tcp_mem, - .sysctl_wmem = sysctl_tcp_wmem, - .sysctl_rmem = sysctl_tcp_rmem, - .max_header = MAX_TCP_HEADER, - .obj_size = sizeof(struct tcp_sock), - .slab_flags = SLAB_DESTROY_BY_RCU, - .twsk_prot = &tcp_timewait_sock_ops, - .rsk_prot = &tcp_request_sock_ops, - .h.hashinfo = &tcp_hashinfo, - .no_autobind = true, -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_tcp_setsockopt, - .compat_getsockopt = compat_tcp_getsockopt, -#endif - .diag_destroy = tcp_abort, -}; -EXPORT_SYMBOL(tcp_prot); - -static void __net_exit tcp_sk_exit(struct net *net) -{ - int cpu; - - for_each_possible_cpu(cpu) - inet_ctl_sock_destroy(*per_cpu_ptr(net->ipv4.tcp_sk, cpu)); - free_percpu(net->ipv4.tcp_sk); -} - -static int __net_init tcp_sk_init(struct net *net) -{ - int res, cpu; - - net->ipv4.tcp_sk = alloc_percpu(struct sock *); - if (!net->ipv4.tcp_sk) - return -ENOMEM; - - for_each_possible_cpu(cpu) { - struct sock *sk; - - res = inet_ctl_sock_create(&sk, PF_INET, SOCK_RAW, - IPPROTO_TCP, net); - if (res) - goto fail; - sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); - *per_cpu_ptr(net->ipv4.tcp_sk, cpu) = sk; - } - - net->ipv4.sysctl_tcp_ecn = 2; - net->ipv4.sysctl_tcp_ecn_fallback = 1; - - net->ipv4.sysctl_tcp_base_mss = TCP_BASE_MSS; - net->ipv4.sysctl_tcp_probe_threshold = TCP_PROBE_THRESHOLD; - net->ipv4.sysctl_tcp_probe_interval = TCP_PROBE_INTERVAL; - - net->ipv4.sysctl_tcp_keepalive_time = TCP_KEEPALIVE_TIME; - net->ipv4.sysctl_tcp_keepalive_probes = TCP_KEEPALIVE_PROBES; - net->ipv4.sysctl_tcp_keepalive_intvl = TCP_KEEPALIVE_INTVL; - - net->ipv4.sysctl_tcp_syn_retries = TCP_SYN_RETRIES; - net->ipv4.sysctl_tcp_synack_retries = TCP_SYNACK_RETRIES; - net->ipv4.sysctl_tcp_syncookies = 1; - net->ipv4.sysctl_tcp_reordering = TCP_FASTRETRANS_THRESH; - net->ipv4.sysctl_tcp_retries1 = TCP_RETR1; - net->ipv4.sysctl_tcp_retries2 = TCP_RETR2; - net->ipv4.sysctl_tcp_orphan_retries = 0; - net->ipv4.sysctl_tcp_fin_timeout = TCP_FIN_TIMEOUT; - net->ipv4.sysctl_tcp_notsent_lowat = UINT_MAX; - - return 0; -fail: - tcp_sk_exit(net); - - return res; -} - -static void __net_exit tcp_sk_exit_batch(struct list_head *net_exit_list) -{ - inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET); -} - -static struct pernet_operations __net_initdata tcp_sk_ops = { - .init = tcp_sk_init, - .exit = tcp_sk_exit, - .exit_batch = tcp_sk_exit_batch, -}; - -void __init tcp_v4_init(void) -{ - inet_hashinfo_init(&tcp_hashinfo); - if (register_pernet_subsys(&tcp_sk_ops)) - panic("Failed to create the TCP control socket.\n"); -} diff --git a/src/linux/net/ipv4/tcp_metrics.c b/src/linux/net/ipv4/tcp_metrics.c deleted file mode 100644 index bf1f3b2..0000000 --- a/src/linux/net/ipv4/tcp_metrics.c +++ /dev/null @@ -1,1186 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int sysctl_tcp_nometrics_save __read_mostly; - -static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *saddr, - const struct inetpeer_addr *daddr, - struct net *net, unsigned int hash); - -struct tcp_fastopen_metrics { - u16 mss; - u16 syn_loss:10, /* Recurring Fast Open SYN losses */ - try_exp:2; /* Request w/ exp. option (once) */ - unsigned long last_syn_loss; /* Last Fast Open SYN loss */ - struct tcp_fastopen_cookie cookie; -}; - -/* TCP_METRIC_MAX includes 2 extra fields for userspace compatibility - * Kernel only stores RTT and RTTVAR in usec resolution - */ -#define TCP_METRIC_MAX_KERNEL (TCP_METRIC_MAX - 2) - -struct tcp_metrics_block { - struct tcp_metrics_block __rcu *tcpm_next; - possible_net_t tcpm_net; - struct inetpeer_addr tcpm_saddr; - struct inetpeer_addr tcpm_daddr; - unsigned long tcpm_stamp; - u32 tcpm_ts; - u32 tcpm_ts_stamp; - u32 tcpm_lock; - u32 tcpm_vals[TCP_METRIC_MAX_KERNEL + 1]; - struct tcp_fastopen_metrics tcpm_fastopen; - - struct rcu_head rcu_head; -}; - -static inline struct net *tm_net(struct tcp_metrics_block *tm) -{ - return read_pnet(&tm->tcpm_net); -} - -static bool tcp_metric_locked(struct tcp_metrics_block *tm, - enum tcp_metric_index idx) -{ - return tm->tcpm_lock & (1 << idx); -} - -static u32 tcp_metric_get(struct tcp_metrics_block *tm, - enum tcp_metric_index idx) -{ - return tm->tcpm_vals[idx]; -} - -static void tcp_metric_set(struct tcp_metrics_block *tm, - enum tcp_metric_index idx, - u32 val) -{ - tm->tcpm_vals[idx] = val; -} - -static bool addr_same(const struct inetpeer_addr *a, - const struct inetpeer_addr *b) -{ - return inetpeer_addr_cmp(a, b) == 0; -} - -struct tcpm_hash_bucket { - struct tcp_metrics_block __rcu *chain; -}; - -static struct tcpm_hash_bucket *tcp_metrics_hash __read_mostly; -static unsigned int tcp_metrics_hash_log __read_mostly; - -static DEFINE_SPINLOCK(tcp_metrics_lock); - -static void tcpm_suck_dst(struct tcp_metrics_block *tm, - const struct dst_entry *dst, - bool fastopen_clear) -{ - u32 msval; - u32 val; - - tm->tcpm_stamp = jiffies; - - val = 0; - if (dst_metric_locked(dst, RTAX_RTT)) - val |= 1 << TCP_METRIC_RTT; - if (dst_metric_locked(dst, RTAX_RTTVAR)) - val |= 1 << TCP_METRIC_RTTVAR; - if (dst_metric_locked(dst, RTAX_SSTHRESH)) - val |= 1 << TCP_METRIC_SSTHRESH; - if (dst_metric_locked(dst, RTAX_CWND)) - val |= 1 << TCP_METRIC_CWND; - if (dst_metric_locked(dst, RTAX_REORDERING)) - val |= 1 << TCP_METRIC_REORDERING; - tm->tcpm_lock = val; - - msval = dst_metric_raw(dst, RTAX_RTT); - tm->tcpm_vals[TCP_METRIC_RTT] = msval * USEC_PER_MSEC; - - msval = dst_metric_raw(dst, RTAX_RTTVAR); - tm->tcpm_vals[TCP_METRIC_RTTVAR] = msval * USEC_PER_MSEC; - tm->tcpm_vals[TCP_METRIC_SSTHRESH] = dst_metric_raw(dst, RTAX_SSTHRESH); - tm->tcpm_vals[TCP_METRIC_CWND] = dst_metric_raw(dst, RTAX_CWND); - tm->tcpm_vals[TCP_METRIC_REORDERING] = dst_metric_raw(dst, RTAX_REORDERING); - tm->tcpm_ts = 0; - tm->tcpm_ts_stamp = 0; - if (fastopen_clear) { - tm->tcpm_fastopen.mss = 0; - tm->tcpm_fastopen.syn_loss = 0; - tm->tcpm_fastopen.try_exp = 0; - tm->tcpm_fastopen.cookie.exp = false; - tm->tcpm_fastopen.cookie.len = 0; - } -} - -#define TCP_METRICS_TIMEOUT (60 * 60 * HZ) - -static void tcpm_check_stamp(struct tcp_metrics_block *tm, struct dst_entry *dst) -{ - if (tm && unlikely(time_after(jiffies, tm->tcpm_stamp + TCP_METRICS_TIMEOUT))) - tcpm_suck_dst(tm, dst, false); -} - -#define TCP_METRICS_RECLAIM_DEPTH 5 -#define TCP_METRICS_RECLAIM_PTR (struct tcp_metrics_block *) 0x1UL - -#define deref_locked(p) \ - rcu_dereference_protected(p, lockdep_is_held(&tcp_metrics_lock)) - -static struct tcp_metrics_block *tcpm_new(struct dst_entry *dst, - struct inetpeer_addr *saddr, - struct inetpeer_addr *daddr, - unsigned int hash) -{ - struct tcp_metrics_block *tm; - struct net *net; - bool reclaim = false; - - spin_lock_bh(&tcp_metrics_lock); - net = dev_net(dst->dev); - - /* While waiting for the spin-lock the cache might have been populated - * with this entry and so we have to check again. - */ - tm = __tcp_get_metrics(saddr, daddr, net, hash); - if (tm == TCP_METRICS_RECLAIM_PTR) { - reclaim = true; - tm = NULL; - } - if (tm) { - tcpm_check_stamp(tm, dst); - goto out_unlock; - } - - if (unlikely(reclaim)) { - struct tcp_metrics_block *oldest; - - oldest = deref_locked(tcp_metrics_hash[hash].chain); - for (tm = deref_locked(oldest->tcpm_next); tm; - tm = deref_locked(tm->tcpm_next)) { - if (time_before(tm->tcpm_stamp, oldest->tcpm_stamp)) - oldest = tm; - } - tm = oldest; - } else { - tm = kmalloc(sizeof(*tm), GFP_ATOMIC); - if (!tm) - goto out_unlock; - } - write_pnet(&tm->tcpm_net, net); - tm->tcpm_saddr = *saddr; - tm->tcpm_daddr = *daddr; - - tcpm_suck_dst(tm, dst, true); - - if (likely(!reclaim)) { - tm->tcpm_next = tcp_metrics_hash[hash].chain; - rcu_assign_pointer(tcp_metrics_hash[hash].chain, tm); - } - -out_unlock: - spin_unlock_bh(&tcp_metrics_lock); - return tm; -} - -static struct tcp_metrics_block *tcp_get_encode(struct tcp_metrics_block *tm, int depth) -{ - if (tm) - return tm; - if (depth > TCP_METRICS_RECLAIM_DEPTH) - return TCP_METRICS_RECLAIM_PTR; - return NULL; -} - -static struct tcp_metrics_block *__tcp_get_metrics(const struct inetpeer_addr *saddr, - const struct inetpeer_addr *daddr, - struct net *net, unsigned int hash) -{ - struct tcp_metrics_block *tm; - int depth = 0; - - for (tm = rcu_dereference(tcp_metrics_hash[hash].chain); tm; - tm = rcu_dereference(tm->tcpm_next)) { - if (addr_same(&tm->tcpm_saddr, saddr) && - addr_same(&tm->tcpm_daddr, daddr) && - net_eq(tm_net(tm), net)) - break; - depth++; - } - return tcp_get_encode(tm, depth); -} - -static struct tcp_metrics_block *__tcp_get_metrics_req(struct request_sock *req, - struct dst_entry *dst) -{ - struct tcp_metrics_block *tm; - struct inetpeer_addr saddr, daddr; - unsigned int hash; - struct net *net; - - saddr.family = req->rsk_ops->family; - daddr.family = req->rsk_ops->family; - switch (daddr.family) { - case AF_INET: - inetpeer_set_addr_v4(&saddr, inet_rsk(req)->ir_loc_addr); - inetpeer_set_addr_v4(&daddr, inet_rsk(req)->ir_rmt_addr); - hash = ipv4_addr_hash(inet_rsk(req)->ir_rmt_addr); - break; -#if IS_ENABLED(CONFIG_IPV6) - case AF_INET6: - inetpeer_set_addr_v6(&saddr, &inet_rsk(req)->ir_v6_loc_addr); - inetpeer_set_addr_v6(&daddr, &inet_rsk(req)->ir_v6_rmt_addr); - hash = ipv6_addr_hash(&inet_rsk(req)->ir_v6_rmt_addr); - break; -#endif - default: - return NULL; - } - - net = dev_net(dst->dev); - hash ^= net_hash_mix(net); - hash = hash_32(hash, tcp_metrics_hash_log); - - for (tm = rcu_dereference(tcp_metrics_hash[hash].chain); tm; - tm = rcu_dereference(tm->tcpm_next)) { - if (addr_same(&tm->tcpm_saddr, &saddr) && - addr_same(&tm->tcpm_daddr, &daddr) && - net_eq(tm_net(tm), net)) - break; - } - tcpm_check_stamp(tm, dst); - return tm; -} - -static struct tcp_metrics_block *__tcp_get_metrics_tw(struct inet_timewait_sock *tw) -{ - struct tcp_metrics_block *tm; - struct inetpeer_addr saddr, daddr; - unsigned int hash; - struct net *net; - - if (tw->tw_family == AF_INET) { - inetpeer_set_addr_v4(&saddr, tw->tw_rcv_saddr); - inetpeer_set_addr_v4(&daddr, tw->tw_daddr); - hash = ipv4_addr_hash(tw->tw_daddr); - } -#if IS_ENABLED(CONFIG_IPV6) - else if (tw->tw_family == AF_INET6) { - if (ipv6_addr_v4mapped(&tw->tw_v6_daddr)) { - inetpeer_set_addr_v4(&saddr, tw->tw_rcv_saddr); - inetpeer_set_addr_v4(&daddr, tw->tw_daddr); - hash = ipv4_addr_hash(tw->tw_daddr); - } else { - inetpeer_set_addr_v6(&saddr, &tw->tw_v6_rcv_saddr); - inetpeer_set_addr_v6(&daddr, &tw->tw_v6_daddr); - hash = ipv6_addr_hash(&tw->tw_v6_daddr); - } - } -#endif - else - return NULL; - - net = twsk_net(tw); - hash ^= net_hash_mix(net); - hash = hash_32(hash, tcp_metrics_hash_log); - - for (tm = rcu_dereference(tcp_metrics_hash[hash].chain); tm; - tm = rcu_dereference(tm->tcpm_next)) { - if (addr_same(&tm->tcpm_saddr, &saddr) && - addr_same(&tm->tcpm_daddr, &daddr) && - net_eq(tm_net(tm), net)) - break; - } - return tm; -} - -static struct tcp_metrics_block *tcp_get_metrics(struct sock *sk, - struct dst_entry *dst, - bool create) -{ - struct tcp_metrics_block *tm; - struct inetpeer_addr saddr, daddr; - unsigned int hash; - struct net *net; - - if (sk->sk_family == AF_INET) { - inetpeer_set_addr_v4(&saddr, inet_sk(sk)->inet_saddr); - inetpeer_set_addr_v4(&daddr, inet_sk(sk)->inet_daddr); - hash = ipv4_addr_hash(inet_sk(sk)->inet_daddr); - } -#if IS_ENABLED(CONFIG_IPV6) - else if (sk->sk_family == AF_INET6) { - if (ipv6_addr_v4mapped(&sk->sk_v6_daddr)) { - inetpeer_set_addr_v4(&saddr, inet_sk(sk)->inet_saddr); - inetpeer_set_addr_v4(&daddr, inet_sk(sk)->inet_daddr); - hash = ipv4_addr_hash(inet_sk(sk)->inet_daddr); - } else { - inetpeer_set_addr_v6(&saddr, &sk->sk_v6_rcv_saddr); - inetpeer_set_addr_v6(&daddr, &sk->sk_v6_daddr); - hash = ipv6_addr_hash(&sk->sk_v6_daddr); - } - } -#endif - else - return NULL; - - net = dev_net(dst->dev); - hash ^= net_hash_mix(net); - hash = hash_32(hash, tcp_metrics_hash_log); - - tm = __tcp_get_metrics(&saddr, &daddr, net, hash); - if (tm == TCP_METRICS_RECLAIM_PTR) - tm = NULL; - if (!tm && create) - tm = tcpm_new(dst, &saddr, &daddr, hash); - else - tcpm_check_stamp(tm, dst); - - return tm; -} - -/* Save metrics learned by this TCP session. This function is called - * only, when TCP finishes successfully i.e. when it enters TIME-WAIT - * or goes from LAST-ACK to CLOSE. - */ -void tcp_update_metrics(struct sock *sk) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - struct dst_entry *dst = __sk_dst_get(sk); - struct tcp_sock *tp = tcp_sk(sk); - struct net *net = sock_net(sk); - struct tcp_metrics_block *tm; - unsigned long rtt; - u32 val; - int m; - - if (sysctl_tcp_nometrics_save || !dst) - return; - - if (dst->flags & DST_HOST) - dst_confirm(dst); - - rcu_read_lock(); - if (icsk->icsk_backoff || !tp->srtt_us) { - /* This session failed to estimate rtt. Why? - * Probably, no packets returned in time. Reset our - * results. - */ - tm = tcp_get_metrics(sk, dst, false); - if (tm && !tcp_metric_locked(tm, TCP_METRIC_RTT)) - tcp_metric_set(tm, TCP_METRIC_RTT, 0); - goto out_unlock; - } else - tm = tcp_get_metrics(sk, dst, true); - - if (!tm) - goto out_unlock; - - rtt = tcp_metric_get(tm, TCP_METRIC_RTT); - m = rtt - tp->srtt_us; - - /* If newly calculated rtt larger than stored one, store new - * one. Otherwise, use EWMA. Remember, rtt overestimation is - * always better than underestimation. - */ - if (!tcp_metric_locked(tm, TCP_METRIC_RTT)) { - if (m <= 0) - rtt = tp->srtt_us; - else - rtt -= (m >> 3); - tcp_metric_set(tm, TCP_METRIC_RTT, rtt); - } - - if (!tcp_metric_locked(tm, TCP_METRIC_RTTVAR)) { - unsigned long var; - - if (m < 0) - m = -m; - - /* Scale deviation to rttvar fixed point */ - m >>= 1; - if (m < tp->mdev_us) - m = tp->mdev_us; - - var = tcp_metric_get(tm, TCP_METRIC_RTTVAR); - if (m >= var) - var = m; - else - var -= (var - m) >> 2; - - tcp_metric_set(tm, TCP_METRIC_RTTVAR, var); - } - - if (tcp_in_initial_slowstart(tp)) { - /* Slow start still did not finish. */ - if (!tcp_metric_locked(tm, TCP_METRIC_SSTHRESH)) { - val = tcp_metric_get(tm, TCP_METRIC_SSTHRESH); - if (val && (tp->snd_cwnd >> 1) > val) - tcp_metric_set(tm, TCP_METRIC_SSTHRESH, - tp->snd_cwnd >> 1); - } - if (!tcp_metric_locked(tm, TCP_METRIC_CWND)) { - val = tcp_metric_get(tm, TCP_METRIC_CWND); - if (tp->snd_cwnd > val) - tcp_metric_set(tm, TCP_METRIC_CWND, - tp->snd_cwnd); - } - } else if (!tcp_in_slow_start(tp) && - icsk->icsk_ca_state == TCP_CA_Open) { - /* Cong. avoidance phase, cwnd is reliable. */ - if (!tcp_metric_locked(tm, TCP_METRIC_SSTHRESH)) - tcp_metric_set(tm, TCP_METRIC_SSTHRESH, - max(tp->snd_cwnd >> 1, tp->snd_ssthresh)); - if (!tcp_metric_locked(tm, TCP_METRIC_CWND)) { - val = tcp_metric_get(tm, TCP_METRIC_CWND); - tcp_metric_set(tm, TCP_METRIC_CWND, (val + tp->snd_cwnd) >> 1); - } - } else { - /* Else slow start did not finish, cwnd is non-sense, - * ssthresh may be also invalid. - */ - if (!tcp_metric_locked(tm, TCP_METRIC_CWND)) { - val = tcp_metric_get(tm, TCP_METRIC_CWND); - tcp_metric_set(tm, TCP_METRIC_CWND, - (val + tp->snd_ssthresh) >> 1); - } - if (!tcp_metric_locked(tm, TCP_METRIC_SSTHRESH)) { - val = tcp_metric_get(tm, TCP_METRIC_SSTHRESH); - if (val && tp->snd_ssthresh > val) - tcp_metric_set(tm, TCP_METRIC_SSTHRESH, - tp->snd_ssthresh); - } - if (!tcp_metric_locked(tm, TCP_METRIC_REORDERING)) { - val = tcp_metric_get(tm, TCP_METRIC_REORDERING); - if (val < tp->reordering && - tp->reordering != net->ipv4.sysctl_tcp_reordering) - tcp_metric_set(tm, TCP_METRIC_REORDERING, - tp->reordering); - } - } - tm->tcpm_stamp = jiffies; -out_unlock: - rcu_read_unlock(); -} - -/* Initialize metrics on socket. */ - -void tcp_init_metrics(struct sock *sk) -{ - struct dst_entry *dst = __sk_dst_get(sk); - struct tcp_sock *tp = tcp_sk(sk); - struct tcp_metrics_block *tm; - u32 val, crtt = 0; /* cached RTT scaled by 8 */ - - if (!dst) - goto reset; - - dst_confirm(dst); - - rcu_read_lock(); - tm = tcp_get_metrics(sk, dst, true); - if (!tm) { - rcu_read_unlock(); - goto reset; - } - - if (tcp_metric_locked(tm, TCP_METRIC_CWND)) - tp->snd_cwnd_clamp = tcp_metric_get(tm, TCP_METRIC_CWND); - - val = tcp_metric_get(tm, TCP_METRIC_SSTHRESH); - if (val) { - tp->snd_ssthresh = val; - if (tp->snd_ssthresh > tp->snd_cwnd_clamp) - tp->snd_ssthresh = tp->snd_cwnd_clamp; - } else { - /* ssthresh may have been reduced unnecessarily during. - * 3WHS. Restore it back to its initial default. - */ - tp->snd_ssthresh = TCP_INFINITE_SSTHRESH; - } - val = tcp_metric_get(tm, TCP_METRIC_REORDERING); - if (val && tp->reordering != val) { - tcp_disable_fack(tp); - tcp_disable_early_retrans(tp); - tp->reordering = val; - } - - crtt = tcp_metric_get(tm, TCP_METRIC_RTT); - rcu_read_unlock(); -reset: - /* The initial RTT measurement from the SYN/SYN-ACK is not ideal - * to seed the RTO for later data packets because SYN packets are - * small. Use the per-dst cached values to seed the RTO but keep - * the RTT estimator variables intact (e.g., srtt, mdev, rttvar). - * Later the RTO will be updated immediately upon obtaining the first - * data RTT sample (tcp_rtt_estimator()). Hence the cached RTT only - * influences the first RTO but not later RTT estimation. - * - * But if RTT is not available from the SYN (due to retransmits or - * syn cookies) or the cache, force a conservative 3secs timeout. - * - * A bit of theory. RTT is time passed after "normal" sized packet - * is sent until it is ACKed. In normal circumstances sending small - * packets force peer to delay ACKs and calculation is correct too. - * The algorithm is adaptive and, provided we follow specs, it - * NEVER underestimate RTT. BUT! If peer tries to make some clever - * tricks sort of "quick acks" for time long enough to decrease RTT - * to low value, and then abruptly stops to do it and starts to delay - * ACKs, wait for troubles. - */ - if (crtt > tp->srtt_us) { - /* Set RTO like tcp_rtt_estimator(), but from cached RTT. */ - crtt /= 8 * USEC_PER_SEC / HZ; - inet_csk(sk)->icsk_rto = crtt + max(2 * crtt, tcp_rto_min(sk)); - } else if (tp->srtt_us == 0) { - /* RFC6298: 5.7 We've failed to get a valid RTT sample from - * 3WHS. This is most likely due to retransmission, - * including spurious one. Reset the RTO back to 3secs - * from the more aggressive 1sec to avoid more spurious - * retransmission. - */ - tp->rttvar_us = jiffies_to_usecs(TCP_TIMEOUT_FALLBACK); - tp->mdev_us = tp->mdev_max_us = tp->rttvar_us; - - inet_csk(sk)->icsk_rto = TCP_TIMEOUT_FALLBACK; - } - /* Cut cwnd down to 1 per RFC5681 if SYN or SYN-ACK has been - * retransmitted. In light of RFC6298 more aggressive 1sec - * initRTO, we only reset cwnd when more than 1 SYN/SYN-ACK - * retransmission has occurred. - */ - if (tp->total_retrans > 1) - tp->snd_cwnd = 1; - else - tp->snd_cwnd = tcp_init_cwnd(tp, dst); - tp->snd_cwnd_stamp = tcp_time_stamp; -} - -bool tcp_peer_is_proven(struct request_sock *req, struct dst_entry *dst, - bool paws_check, bool timestamps) -{ - struct tcp_metrics_block *tm; - bool ret; - - if (!dst) - return false; - - rcu_read_lock(); - tm = __tcp_get_metrics_req(req, dst); - if (paws_check) { - if (tm && - (u32)get_seconds() - tm->tcpm_ts_stamp < TCP_PAWS_MSL && - ((s32)(tm->tcpm_ts - req->ts_recent) > TCP_PAWS_WINDOW || - !timestamps)) - ret = false; - else - ret = true; - } else { - if (tm && tcp_metric_get(tm, TCP_METRIC_RTT) && tm->tcpm_ts_stamp) - ret = true; - else - ret = false; - } - rcu_read_unlock(); - - return ret; -} -EXPORT_SYMBOL_GPL(tcp_peer_is_proven); - -void tcp_fetch_timewait_stamp(struct sock *sk, struct dst_entry *dst) -{ - struct tcp_metrics_block *tm; - - rcu_read_lock(); - tm = tcp_get_metrics(sk, dst, true); - if (tm) { - struct tcp_sock *tp = tcp_sk(sk); - - if ((u32)get_seconds() - tm->tcpm_ts_stamp <= TCP_PAWS_MSL) { - tp->rx_opt.ts_recent_stamp = tm->tcpm_ts_stamp; - tp->rx_opt.ts_recent = tm->tcpm_ts; - } - } - rcu_read_unlock(); -} -EXPORT_SYMBOL_GPL(tcp_fetch_timewait_stamp); - -/* VJ's idea. Save last timestamp seen from this destination and hold - * it at least for normal timewait interval to use for duplicate - * segment detection in subsequent connections, before they enter - * synchronized state. - */ -bool tcp_remember_stamp(struct sock *sk) -{ - struct dst_entry *dst = __sk_dst_get(sk); - bool ret = false; - - if (dst) { - struct tcp_metrics_block *tm; - - rcu_read_lock(); - tm = tcp_get_metrics(sk, dst, true); - if (tm) { - struct tcp_sock *tp = tcp_sk(sk); - - if ((s32)(tm->tcpm_ts - tp->rx_opt.ts_recent) <= 0 || - ((u32)get_seconds() - tm->tcpm_ts_stamp > TCP_PAWS_MSL && - tm->tcpm_ts_stamp <= (u32)tp->rx_opt.ts_recent_stamp)) { - tm->tcpm_ts_stamp = (u32)tp->rx_opt.ts_recent_stamp; - tm->tcpm_ts = tp->rx_opt.ts_recent; - } - ret = true; - } - rcu_read_unlock(); - } - return ret; -} - -bool tcp_tw_remember_stamp(struct inet_timewait_sock *tw) -{ - struct tcp_metrics_block *tm; - bool ret = false; - - rcu_read_lock(); - tm = __tcp_get_metrics_tw(tw); - if (tm) { - const struct tcp_timewait_sock *tcptw; - struct sock *sk = (struct sock *) tw; - - tcptw = tcp_twsk(sk); - if ((s32)(tm->tcpm_ts - tcptw->tw_ts_recent) <= 0 || - ((u32)get_seconds() - tm->tcpm_ts_stamp > TCP_PAWS_MSL && - tm->tcpm_ts_stamp <= (u32)tcptw->tw_ts_recent_stamp)) { - tm->tcpm_ts_stamp = (u32)tcptw->tw_ts_recent_stamp; - tm->tcpm_ts = tcptw->tw_ts_recent; - } - ret = true; - } - rcu_read_unlock(); - - return ret; -} - -static DEFINE_SEQLOCK(fastopen_seqlock); - -void tcp_fastopen_cache_get(struct sock *sk, u16 *mss, - struct tcp_fastopen_cookie *cookie, - int *syn_loss, unsigned long *last_syn_loss) -{ - struct tcp_metrics_block *tm; - - rcu_read_lock(); - tm = tcp_get_metrics(sk, __sk_dst_get(sk), false); - if (tm) { - struct tcp_fastopen_metrics *tfom = &tm->tcpm_fastopen; - unsigned int seq; - - do { - seq = read_seqbegin(&fastopen_seqlock); - if (tfom->mss) - *mss = tfom->mss; - *cookie = tfom->cookie; - if (cookie->len <= 0 && tfom->try_exp == 1) - cookie->exp = true; - *syn_loss = tfom->syn_loss; - *last_syn_loss = *syn_loss ? tfom->last_syn_loss : 0; - } while (read_seqretry(&fastopen_seqlock, seq)); - } - rcu_read_unlock(); -} - -void tcp_fastopen_cache_set(struct sock *sk, u16 mss, - struct tcp_fastopen_cookie *cookie, bool syn_lost, - u16 try_exp) -{ - struct dst_entry *dst = __sk_dst_get(sk); - struct tcp_metrics_block *tm; - - if (!dst) - return; - rcu_read_lock(); - tm = tcp_get_metrics(sk, dst, true); - if (tm) { - struct tcp_fastopen_metrics *tfom = &tm->tcpm_fastopen; - - write_seqlock_bh(&fastopen_seqlock); - if (mss) - tfom->mss = mss; - if (cookie && cookie->len > 0) - tfom->cookie = *cookie; - else if (try_exp > tfom->try_exp && - tfom->cookie.len <= 0 && !tfom->cookie.exp) - tfom->try_exp = try_exp; - if (syn_lost) { - ++tfom->syn_loss; - tfom->last_syn_loss = jiffies; - } else - tfom->syn_loss = 0; - write_sequnlock_bh(&fastopen_seqlock); - } - rcu_read_unlock(); -} - -static struct genl_family tcp_metrics_nl_family = { - .id = GENL_ID_GENERATE, - .hdrsize = 0, - .name = TCP_METRICS_GENL_NAME, - .version = TCP_METRICS_GENL_VERSION, - .maxattr = TCP_METRICS_ATTR_MAX, - .netnsok = true, -}; - -static const struct nla_policy tcp_metrics_nl_policy[TCP_METRICS_ATTR_MAX + 1] = { - [TCP_METRICS_ATTR_ADDR_IPV4] = { .type = NLA_U32, }, - [TCP_METRICS_ATTR_ADDR_IPV6] = { .type = NLA_BINARY, - .len = sizeof(struct in6_addr), }, - /* Following attributes are not received for GET/DEL, - * we keep them for reference - */ -#if 0 - [TCP_METRICS_ATTR_AGE] = { .type = NLA_MSECS, }, - [TCP_METRICS_ATTR_TW_TSVAL] = { .type = NLA_U32, }, - [TCP_METRICS_ATTR_TW_TS_STAMP] = { .type = NLA_S32, }, - [TCP_METRICS_ATTR_VALS] = { .type = NLA_NESTED, }, - [TCP_METRICS_ATTR_FOPEN_MSS] = { .type = NLA_U16, }, - [TCP_METRICS_ATTR_FOPEN_SYN_DROPS] = { .type = NLA_U16, }, - [TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS] = { .type = NLA_MSECS, }, - [TCP_METRICS_ATTR_FOPEN_COOKIE] = { .type = NLA_BINARY, - .len = TCP_FASTOPEN_COOKIE_MAX, }, -#endif -}; - -/* Add attributes, caller cancels its header on failure */ -static int tcp_metrics_fill_info(struct sk_buff *msg, - struct tcp_metrics_block *tm) -{ - struct nlattr *nest; - int i; - - switch (tm->tcpm_daddr.family) { - case AF_INET: - if (nla_put_in_addr(msg, TCP_METRICS_ATTR_ADDR_IPV4, - inetpeer_get_addr_v4(&tm->tcpm_daddr)) < 0) - goto nla_put_failure; - if (nla_put_in_addr(msg, TCP_METRICS_ATTR_SADDR_IPV4, - inetpeer_get_addr_v4(&tm->tcpm_saddr)) < 0) - goto nla_put_failure; - break; - case AF_INET6: - if (nla_put_in6_addr(msg, TCP_METRICS_ATTR_ADDR_IPV6, - inetpeer_get_addr_v6(&tm->tcpm_daddr)) < 0) - goto nla_put_failure; - if (nla_put_in6_addr(msg, TCP_METRICS_ATTR_SADDR_IPV6, - inetpeer_get_addr_v6(&tm->tcpm_saddr)) < 0) - goto nla_put_failure; - break; - default: - return -EAFNOSUPPORT; - } - - if (nla_put_msecs(msg, TCP_METRICS_ATTR_AGE, - jiffies - tm->tcpm_stamp, - TCP_METRICS_ATTR_PAD) < 0) - goto nla_put_failure; - if (tm->tcpm_ts_stamp) { - if (nla_put_s32(msg, TCP_METRICS_ATTR_TW_TS_STAMP, - (s32) (get_seconds() - tm->tcpm_ts_stamp)) < 0) - goto nla_put_failure; - if (nla_put_u32(msg, TCP_METRICS_ATTR_TW_TSVAL, - tm->tcpm_ts) < 0) - goto nla_put_failure; - } - - { - int n = 0; - - nest = nla_nest_start(msg, TCP_METRICS_ATTR_VALS); - if (!nest) - goto nla_put_failure; - for (i = 0; i < TCP_METRIC_MAX_KERNEL + 1; i++) { - u32 val = tm->tcpm_vals[i]; - - if (!val) - continue; - if (i == TCP_METRIC_RTT) { - if (nla_put_u32(msg, TCP_METRIC_RTT_US + 1, - val) < 0) - goto nla_put_failure; - n++; - val = max(val / 1000, 1U); - } - if (i == TCP_METRIC_RTTVAR) { - if (nla_put_u32(msg, TCP_METRIC_RTTVAR_US + 1, - val) < 0) - goto nla_put_failure; - n++; - val = max(val / 1000, 1U); - } - if (nla_put_u32(msg, i + 1, val) < 0) - goto nla_put_failure; - n++; - } - if (n) - nla_nest_end(msg, nest); - else - nla_nest_cancel(msg, nest); - } - - { - struct tcp_fastopen_metrics tfom_copy[1], *tfom; - unsigned int seq; - - do { - seq = read_seqbegin(&fastopen_seqlock); - tfom_copy[0] = tm->tcpm_fastopen; - } while (read_seqretry(&fastopen_seqlock, seq)); - - tfom = tfom_copy; - if (tfom->mss && - nla_put_u16(msg, TCP_METRICS_ATTR_FOPEN_MSS, - tfom->mss) < 0) - goto nla_put_failure; - if (tfom->syn_loss && - (nla_put_u16(msg, TCP_METRICS_ATTR_FOPEN_SYN_DROPS, - tfom->syn_loss) < 0 || - nla_put_msecs(msg, TCP_METRICS_ATTR_FOPEN_SYN_DROP_TS, - jiffies - tfom->last_syn_loss, - TCP_METRICS_ATTR_PAD) < 0)) - goto nla_put_failure; - if (tfom->cookie.len > 0 && - nla_put(msg, TCP_METRICS_ATTR_FOPEN_COOKIE, - tfom->cookie.len, tfom->cookie.val) < 0) - goto nla_put_failure; - } - - return 0; - -nla_put_failure: - return -EMSGSIZE; -} - -static int tcp_metrics_dump_info(struct sk_buff *skb, - struct netlink_callback *cb, - struct tcp_metrics_block *tm) -{ - void *hdr; - - hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid, cb->nlh->nlmsg_seq, - &tcp_metrics_nl_family, NLM_F_MULTI, - TCP_METRICS_CMD_GET); - if (!hdr) - return -EMSGSIZE; - - if (tcp_metrics_fill_info(skb, tm) < 0) - goto nla_put_failure; - - genlmsg_end(skb, hdr); - return 0; - -nla_put_failure: - genlmsg_cancel(skb, hdr); - return -EMSGSIZE; -} - -static int tcp_metrics_nl_dump(struct sk_buff *skb, - struct netlink_callback *cb) -{ - struct net *net = sock_net(skb->sk); - unsigned int max_rows = 1U << tcp_metrics_hash_log; - unsigned int row, s_row = cb->args[0]; - int s_col = cb->args[1], col = s_col; - - for (row = s_row; row < max_rows; row++, s_col = 0) { - struct tcp_metrics_block *tm; - struct tcpm_hash_bucket *hb = tcp_metrics_hash + row; - - rcu_read_lock(); - for (col = 0, tm = rcu_dereference(hb->chain); tm; - tm = rcu_dereference(tm->tcpm_next), col++) { - if (!net_eq(tm_net(tm), net)) - continue; - if (col < s_col) - continue; - if (tcp_metrics_dump_info(skb, cb, tm) < 0) { - rcu_read_unlock(); - goto done; - } - } - rcu_read_unlock(); - } - -done: - cb->args[0] = row; - cb->args[1] = col; - return skb->len; -} - -static int __parse_nl_addr(struct genl_info *info, struct inetpeer_addr *addr, - unsigned int *hash, int optional, int v4, int v6) -{ - struct nlattr *a; - - a = info->attrs[v4]; - if (a) { - inetpeer_set_addr_v4(addr, nla_get_in_addr(a)); - if (hash) - *hash = ipv4_addr_hash(inetpeer_get_addr_v4(addr)); - return 0; - } - a = info->attrs[v6]; - if (a) { - struct in6_addr in6; - - if (nla_len(a) != sizeof(struct in6_addr)) - return -EINVAL; - in6 = nla_get_in6_addr(a); - inetpeer_set_addr_v6(addr, &in6); - if (hash) - *hash = ipv6_addr_hash(inetpeer_get_addr_v6(addr)); - return 0; - } - return optional ? 1 : -EAFNOSUPPORT; -} - -static int parse_nl_addr(struct genl_info *info, struct inetpeer_addr *addr, - unsigned int *hash, int optional) -{ - return __parse_nl_addr(info, addr, hash, optional, - TCP_METRICS_ATTR_ADDR_IPV4, - TCP_METRICS_ATTR_ADDR_IPV6); -} - -static int parse_nl_saddr(struct genl_info *info, struct inetpeer_addr *addr) -{ - return __parse_nl_addr(info, addr, NULL, 0, - TCP_METRICS_ATTR_SADDR_IPV4, - TCP_METRICS_ATTR_SADDR_IPV6); -} - -static int tcp_metrics_nl_cmd_get(struct sk_buff *skb, struct genl_info *info) -{ - struct tcp_metrics_block *tm; - struct inetpeer_addr saddr, daddr; - unsigned int hash; - struct sk_buff *msg; - struct net *net = genl_info_net(info); - void *reply; - int ret; - bool src = true; - - ret = parse_nl_addr(info, &daddr, &hash, 0); - if (ret < 0) - return ret; - - ret = parse_nl_saddr(info, &saddr); - if (ret < 0) - src = false; - - msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (!msg) - return -ENOMEM; - - reply = genlmsg_put_reply(msg, info, &tcp_metrics_nl_family, 0, - info->genlhdr->cmd); - if (!reply) - goto nla_put_failure; - - hash ^= net_hash_mix(net); - hash = hash_32(hash, tcp_metrics_hash_log); - ret = -ESRCH; - rcu_read_lock(); - for (tm = rcu_dereference(tcp_metrics_hash[hash].chain); tm; - tm = rcu_dereference(tm->tcpm_next)) { - if (addr_same(&tm->tcpm_daddr, &daddr) && - (!src || addr_same(&tm->tcpm_saddr, &saddr)) && - net_eq(tm_net(tm), net)) { - ret = tcp_metrics_fill_info(msg, tm); - break; - } - } - rcu_read_unlock(); - if (ret < 0) - goto out_free; - - genlmsg_end(msg, reply); - return genlmsg_reply(msg, info); - -nla_put_failure: - ret = -EMSGSIZE; - -out_free: - nlmsg_free(msg); - return ret; -} - -static void tcp_metrics_flush_all(struct net *net) -{ - unsigned int max_rows = 1U << tcp_metrics_hash_log; - struct tcpm_hash_bucket *hb = tcp_metrics_hash; - struct tcp_metrics_block *tm; - unsigned int row; - - for (row = 0; row < max_rows; row++, hb++) { - struct tcp_metrics_block __rcu **pp; - spin_lock_bh(&tcp_metrics_lock); - pp = &hb->chain; - for (tm = deref_locked(*pp); tm; tm = deref_locked(*pp)) { - if (net_eq(tm_net(tm), net)) { - *pp = tm->tcpm_next; - kfree_rcu(tm, rcu_head); - } else { - pp = &tm->tcpm_next; - } - } - spin_unlock_bh(&tcp_metrics_lock); - } -} - -static int tcp_metrics_nl_cmd_del(struct sk_buff *skb, struct genl_info *info) -{ - struct tcpm_hash_bucket *hb; - struct tcp_metrics_block *tm; - struct tcp_metrics_block __rcu **pp; - struct inetpeer_addr saddr, daddr; - unsigned int hash; - struct net *net = genl_info_net(info); - int ret; - bool src = true, found = false; - - ret = parse_nl_addr(info, &daddr, &hash, 1); - if (ret < 0) - return ret; - if (ret > 0) { - tcp_metrics_flush_all(net); - return 0; - } - ret = parse_nl_saddr(info, &saddr); - if (ret < 0) - src = false; - - hash ^= net_hash_mix(net); - hash = hash_32(hash, tcp_metrics_hash_log); - hb = tcp_metrics_hash + hash; - pp = &hb->chain; - spin_lock_bh(&tcp_metrics_lock); - for (tm = deref_locked(*pp); tm; tm = deref_locked(*pp)) { - if (addr_same(&tm->tcpm_daddr, &daddr) && - (!src || addr_same(&tm->tcpm_saddr, &saddr)) && - net_eq(tm_net(tm), net)) { - *pp = tm->tcpm_next; - kfree_rcu(tm, rcu_head); - found = true; - } else { - pp = &tm->tcpm_next; - } - } - spin_unlock_bh(&tcp_metrics_lock); - if (!found) - return -ESRCH; - return 0; -} - -static const struct genl_ops tcp_metrics_nl_ops[] = { - { - .cmd = TCP_METRICS_CMD_GET, - .doit = tcp_metrics_nl_cmd_get, - .dumpit = tcp_metrics_nl_dump, - .policy = tcp_metrics_nl_policy, - }, - { - .cmd = TCP_METRICS_CMD_DEL, - .doit = tcp_metrics_nl_cmd_del, - .policy = tcp_metrics_nl_policy, - .flags = GENL_ADMIN_PERM, - }, -}; - -static unsigned int tcpmhash_entries; -static int __init set_tcpmhash_entries(char *str) -{ - ssize_t ret; - - if (!str) - return 0; - - ret = kstrtouint(str, 0, &tcpmhash_entries); - if (ret) - return 0; - - return 1; -} -__setup("tcpmhash_entries=", set_tcpmhash_entries); - -static int __net_init tcp_net_metrics_init(struct net *net) -{ - size_t size; - unsigned int slots; - - if (!net_eq(net, &init_net)) - return 0; - - slots = tcpmhash_entries; - if (!slots) { - if (totalram_pages >= 128 * 1024) - slots = 16 * 1024; - else - slots = 8 * 1024; - } - - tcp_metrics_hash_log = order_base_2(slots); - size = sizeof(struct tcpm_hash_bucket) << tcp_metrics_hash_log; - - tcp_metrics_hash = kzalloc(size, GFP_KERNEL | __GFP_NOWARN); - if (!tcp_metrics_hash) - tcp_metrics_hash = vzalloc(size); - - if (!tcp_metrics_hash) - return -ENOMEM; - - return 0; -} - -static void __net_exit tcp_net_metrics_exit(struct net *net) -{ - tcp_metrics_flush_all(net); -} - -static __net_initdata struct pernet_operations tcp_net_metrics_ops = { - .init = tcp_net_metrics_init, - .exit = tcp_net_metrics_exit, -}; - -void __init tcp_metrics_init(void) -{ - int ret; - - ret = register_pernet_subsys(&tcp_net_metrics_ops); - if (ret < 0) - panic("Could not allocate the tcp_metrics hash table\n"); - - ret = genl_register_family_with_ops(&tcp_metrics_nl_family, - tcp_metrics_nl_ops); - if (ret < 0) - panic("Could not register tcp_metrics generic netlink\n"); -} diff --git a/src/linux/net/ipv4/tcp_minisocks.c b/src/linux/net/ipv4/tcp_minisocks.c deleted file mode 100644 index 6234eba..0000000 --- a/src/linux/net/ipv4/tcp_minisocks.c +++ /dev/null @@ -1,838 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Implementation of the Transmission Control Protocol(TCP). - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Mark Evans, - * Corey Minyard - * Florian La Roche, - * Charles Hedrick, - * Linus Torvalds, - * Alan Cox, - * Matthew Dillon, - * Arnt Gulbrandsen, - * Jorge Cwik, - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -int sysctl_tcp_abort_on_overflow __read_mostly; - -struct inet_timewait_death_row tcp_death_row = { - .sysctl_max_tw_buckets = NR_FILE * 2, - .hashinfo = &tcp_hashinfo, -}; -EXPORT_SYMBOL_GPL(tcp_death_row); - -static bool tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win) -{ - if (seq == s_win) - return true; - if (after(end_seq, s_win) && before(seq, e_win)) - return true; - return seq == e_win && seq == end_seq; -} - -static enum tcp_tw_status -tcp_timewait_check_oow_rate_limit(struct inet_timewait_sock *tw, - const struct sk_buff *skb, int mib_idx) -{ - struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); - - if (!tcp_oow_rate_limited(twsk_net(tw), skb, mib_idx, - &tcptw->tw_last_oow_ack_time)) { - /* Send ACK. Note, we do not put the bucket, - * it will be released by caller. - */ - return TCP_TW_ACK; - } - - /* We are rate-limiting, so just release the tw sock and drop skb. */ - inet_twsk_put(tw); - return TCP_TW_SUCCESS; -} - -/* - * * Main purpose of TIME-WAIT state is to close connection gracefully, - * when one of ends sits in LAST-ACK or CLOSING retransmitting FIN - * (and, probably, tail of data) and one or more our ACKs are lost. - * * What is TIME-WAIT timeout? It is associated with maximal packet - * lifetime in the internet, which results in wrong conclusion, that - * it is set to catch "old duplicate segments" wandering out of their path. - * It is not quite correct. This timeout is calculated so that it exceeds - * maximal retransmission timeout enough to allow to lose one (or more) - * segments sent by peer and our ACKs. This time may be calculated from RTO. - * * When TIME-WAIT socket receives RST, it means that another end - * finally closed and we are allowed to kill TIME-WAIT too. - * * Second purpose of TIME-WAIT is catching old duplicate segments. - * Well, certainly it is pure paranoia, but if we load TIME-WAIT - * with this semantics, we MUST NOT kill TIME-WAIT state with RSTs. - * * If we invented some more clever way to catch duplicates - * (f.e. based on PAWS), we could truncate TIME-WAIT to several RTOs. - * - * The algorithm below is based on FORMAL INTERPRETATION of RFCs. - * When you compare it to RFCs, please, read section SEGMENT ARRIVES - * from the very beginning. - * - * NOTE. With recycling (and later with fin-wait-2) TW bucket - * is _not_ stateless. It means, that strictly speaking we must - * spinlock it. I do not want! Well, probability of misbehaviour - * is ridiculously low and, seems, we could use some mb() tricks - * to avoid misread sequence numbers, states etc. --ANK - * - * We don't need to initialize tmp_out.sack_ok as we don't use the results - */ -enum tcp_tw_status -tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb, - const struct tcphdr *th) -{ - struct tcp_options_received tmp_opt; - struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); - bool paws_reject = false; - - tmp_opt.saw_tstamp = 0; - if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) { - tcp_parse_options(skb, &tmp_opt, 0, NULL); - - if (tmp_opt.saw_tstamp) { - tmp_opt.rcv_tsecr -= tcptw->tw_ts_offset; - tmp_opt.ts_recent = tcptw->tw_ts_recent; - tmp_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp; - paws_reject = tcp_paws_reject(&tmp_opt, th->rst); - } - } - - if (tw->tw_substate == TCP_FIN_WAIT2) { - /* Just repeat all the checks of tcp_rcv_state_process() */ - - /* Out of window, send ACK */ - if (paws_reject || - !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, - tcptw->tw_rcv_nxt, - tcptw->tw_rcv_nxt + tcptw->tw_rcv_wnd)) - return tcp_timewait_check_oow_rate_limit( - tw, skb, LINUX_MIB_TCPACKSKIPPEDFINWAIT2); - - if (th->rst) - goto kill; - - if (th->syn && !before(TCP_SKB_CB(skb)->seq, tcptw->tw_rcv_nxt)) - return TCP_TW_RST; - - /* Dup ACK? */ - if (!th->ack || - !after(TCP_SKB_CB(skb)->end_seq, tcptw->tw_rcv_nxt) || - TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq) { - inet_twsk_put(tw); - return TCP_TW_SUCCESS; - } - - /* New data or FIN. If new data arrive after half-duplex close, - * reset. - */ - if (!th->fin || - TCP_SKB_CB(skb)->end_seq != tcptw->tw_rcv_nxt + 1) - return TCP_TW_RST; - - /* FIN arrived, enter true time-wait state. */ - tw->tw_substate = TCP_TIME_WAIT; - tcptw->tw_rcv_nxt = TCP_SKB_CB(skb)->end_seq; - if (tmp_opt.saw_tstamp) { - tcptw->tw_ts_recent_stamp = get_seconds(); - tcptw->tw_ts_recent = tmp_opt.rcv_tsval; - } - - if (tcp_death_row.sysctl_tw_recycle && - tcptw->tw_ts_recent_stamp && - tcp_tw_remember_stamp(tw)) - inet_twsk_reschedule(tw, tw->tw_timeout); - else - inet_twsk_reschedule(tw, TCP_TIMEWAIT_LEN); - return TCP_TW_ACK; - } - - /* - * Now real TIME-WAIT state. - * - * RFC 1122: - * "When a connection is [...] on TIME-WAIT state [...] - * [a TCP] MAY accept a new SYN from the remote TCP to - * reopen the connection directly, if it: - * - * (1) assigns its initial sequence number for the new - * connection to be larger than the largest sequence - * number it used on the previous connection incarnation, - * and - * - * (2) returns to TIME-WAIT state if the SYN turns out - * to be an old duplicate". - */ - - if (!paws_reject && - (TCP_SKB_CB(skb)->seq == tcptw->tw_rcv_nxt && - (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq || th->rst))) { - /* In window segment, it may be only reset or bare ack. */ - - if (th->rst) { - /* This is TIME_WAIT assassination, in two flavors. - * Oh well... nobody has a sufficient solution to this - * protocol bug yet. - */ - if (sysctl_tcp_rfc1337 == 0) { -kill: - inet_twsk_deschedule_put(tw); - return TCP_TW_SUCCESS; - } - } - inet_twsk_reschedule(tw, TCP_TIMEWAIT_LEN); - - if (tmp_opt.saw_tstamp) { - tcptw->tw_ts_recent = tmp_opt.rcv_tsval; - tcptw->tw_ts_recent_stamp = get_seconds(); - } - - inet_twsk_put(tw); - return TCP_TW_SUCCESS; - } - - /* Out of window segment. - - All the segments are ACKed immediately. - - The only exception is new SYN. We accept it, if it is - not old duplicate and we are not in danger to be killed - by delayed old duplicates. RFC check is that it has - newer sequence number works at rates <40Mbit/sec. - However, if paws works, it is reliable AND even more, - we even may relax silly seq space cutoff. - - RED-PEN: we violate main RFC requirement, if this SYN will appear - old duplicate (i.e. we receive RST in reply to SYN-ACK), - we must return socket to time-wait state. It is not good, - but not fatal yet. - */ - - if (th->syn && !th->rst && !th->ack && !paws_reject && - (after(TCP_SKB_CB(skb)->seq, tcptw->tw_rcv_nxt) || - (tmp_opt.saw_tstamp && - (s32)(tcptw->tw_ts_recent - tmp_opt.rcv_tsval) < 0))) { - u32 isn = tcptw->tw_snd_nxt + 65535 + 2; - if (isn == 0) - isn++; - TCP_SKB_CB(skb)->tcp_tw_isn = isn; - return TCP_TW_SYN; - } - - if (paws_reject) - __NET_INC_STATS(twsk_net(tw), LINUX_MIB_PAWSESTABREJECTED); - - if (!th->rst) { - /* In this case we must reset the TIMEWAIT timer. - * - * If it is ACKless SYN it may be both old duplicate - * and new good SYN with random sequence number ack) - inet_twsk_reschedule(tw, TCP_TIMEWAIT_LEN); - - return tcp_timewait_check_oow_rate_limit( - tw, skb, LINUX_MIB_TCPACKSKIPPEDTIMEWAIT); - } - inet_twsk_put(tw); - return TCP_TW_SUCCESS; -} -EXPORT_SYMBOL(tcp_timewait_state_process); - -/* - * Move a socket to time-wait or dead fin-wait-2 state. - */ -void tcp_time_wait(struct sock *sk, int state, int timeo) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - const struct tcp_sock *tp = tcp_sk(sk); - struct inet_timewait_sock *tw; - bool recycle_ok = false; - - if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp) - recycle_ok = tcp_remember_stamp(sk); - - tw = inet_twsk_alloc(sk, &tcp_death_row, state); - - if (tw) { - struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw); - const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1); - struct inet_sock *inet = inet_sk(sk); - - tw->tw_transparent = inet->transparent; - tw->tw_rcv_wscale = tp->rx_opt.rcv_wscale; - tcptw->tw_rcv_nxt = tp->rcv_nxt; - tcptw->tw_snd_nxt = tp->snd_nxt; - tcptw->tw_rcv_wnd = tcp_receive_window(tp); - tcptw->tw_ts_recent = tp->rx_opt.ts_recent; - tcptw->tw_ts_recent_stamp = tp->rx_opt.ts_recent_stamp; - tcptw->tw_ts_offset = tp->tsoffset; - tcptw->tw_last_oow_ack_time = 0; - -#if IS_ENABLED(CONFIG_IPV6) - if (tw->tw_family == PF_INET6) { - struct ipv6_pinfo *np = inet6_sk(sk); - - tw->tw_v6_daddr = sk->sk_v6_daddr; - tw->tw_v6_rcv_saddr = sk->sk_v6_rcv_saddr; - tw->tw_tclass = np->tclass; - tw->tw_flowlabel = be32_to_cpu(np->flow_label & IPV6_FLOWLABEL_MASK); - tw->tw_ipv6only = sk->sk_ipv6only; - } -#endif - -#ifdef CONFIG_TCP_MD5SIG - /* - * The timewait bucket does not have the key DB from the - * sock structure. We just make a quick copy of the - * md5 key being used (if indeed we are using one) - * so the timewait ack generating code has the key. - */ - do { - struct tcp_md5sig_key *key; - tcptw->tw_md5_key = NULL; - key = tp->af_specific->md5_lookup(sk, sk); - if (key) { - tcptw->tw_md5_key = kmemdup(key, sizeof(*key), GFP_ATOMIC); - if (tcptw->tw_md5_key && !tcp_alloc_md5sig_pool()) - BUG(); - } - } while (0); -#endif - - /* Get the TIME_WAIT timeout firing. */ - if (timeo < rto) - timeo = rto; - - if (recycle_ok) { - tw->tw_timeout = rto; - } else { - tw->tw_timeout = TCP_TIMEWAIT_LEN; - if (state == TCP_TIME_WAIT) - timeo = TCP_TIMEWAIT_LEN; - } - - inet_twsk_schedule(tw, timeo); - /* Linkage updates. */ - __inet_twsk_hashdance(tw, sk, &tcp_hashinfo); - inet_twsk_put(tw); - } else { - /* Sorry, if we're out of memory, just CLOSE this - * socket up. We've got bigger problems than - * non-graceful socket closings. - */ - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPTIMEWAITOVERFLOW); - } - - tcp_update_metrics(sk); - tcp_done(sk); -} - -void tcp_twsk_destructor(struct sock *sk) -{ -#ifdef CONFIG_TCP_MD5SIG - struct tcp_timewait_sock *twsk = tcp_twsk(sk); - - if (twsk->tw_md5_key) - kfree_rcu(twsk->tw_md5_key, rcu); -#endif -} -EXPORT_SYMBOL_GPL(tcp_twsk_destructor); - -/* Warning : This function is called without sk_listener being locked. - * Be sure to read socket fields once, as their value could change under us. - */ -void tcp_openreq_init_rwin(struct request_sock *req, - const struct sock *sk_listener, - const struct dst_entry *dst) -{ - struct inet_request_sock *ireq = inet_rsk(req); - const struct tcp_sock *tp = tcp_sk(sk_listener); - u16 user_mss = READ_ONCE(tp->rx_opt.user_mss); - int full_space = tcp_full_space(sk_listener); - int mss = dst_metric_advmss(dst); - u32 window_clamp; - __u8 rcv_wscale; - - if (user_mss && user_mss < mss) - mss = user_mss; - - window_clamp = READ_ONCE(tp->window_clamp); - /* Set this up on the first call only */ - req->rsk_window_clamp = window_clamp ? : dst_metric(dst, RTAX_WINDOW); - - /* limit the window selection if the user enforce a smaller rx buffer */ - if (sk_listener->sk_userlocks & SOCK_RCVBUF_LOCK && - (req->rsk_window_clamp > full_space || req->rsk_window_clamp == 0)) - req->rsk_window_clamp = full_space; - - /* tcp_full_space because it is guaranteed to be the first packet */ - tcp_select_initial_window(full_space, - mss - (ireq->tstamp_ok ? TCPOLEN_TSTAMP_ALIGNED : 0), - &req->rsk_rcv_wnd, - &req->rsk_window_clamp, - ireq->wscale_ok, - &rcv_wscale, - dst_metric(dst, RTAX_INITRWND)); - ireq->rcv_wscale = rcv_wscale; -} -EXPORT_SYMBOL(tcp_openreq_init_rwin); - -static void tcp_ecn_openreq_child(struct tcp_sock *tp, - const struct request_sock *req) -{ - tp->ecn_flags = inet_rsk(req)->ecn_ok ? TCP_ECN_OK : 0; -} - -void tcp_ca_openreq_child(struct sock *sk, const struct dst_entry *dst) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - u32 ca_key = dst_metric(dst, RTAX_CC_ALGO); - bool ca_got_dst = false; - - if (ca_key != TCP_CA_UNSPEC) { - const struct tcp_congestion_ops *ca; - - rcu_read_lock(); - ca = tcp_ca_find_key(ca_key); - if (likely(ca && try_module_get(ca->owner))) { - icsk->icsk_ca_dst_locked = tcp_ca_dst_locked(dst); - icsk->icsk_ca_ops = ca; - ca_got_dst = true; - } - rcu_read_unlock(); - } - - /* If no valid choice made yet, assign current system default ca. */ - if (!ca_got_dst && - (!icsk->icsk_ca_setsockopt || - !try_module_get(icsk->icsk_ca_ops->owner))) - tcp_assign_congestion_control(sk); - - tcp_set_ca_state(sk, TCP_CA_Open); -} -EXPORT_SYMBOL_GPL(tcp_ca_openreq_child); - -/* This is not only more efficient than what we used to do, it eliminates - * a lot of code duplication between IPv4/IPv6 SYN recv processing. -DaveM - * - * Actually, we could lots of memory writes here. tp of listening - * socket contains all necessary default parameters. - */ -struct sock *tcp_create_openreq_child(const struct sock *sk, - struct request_sock *req, - struct sk_buff *skb) -{ - struct sock *newsk = inet_csk_clone_lock(sk, req, GFP_ATOMIC); - - if (newsk) { - const struct inet_request_sock *ireq = inet_rsk(req); - struct tcp_request_sock *treq = tcp_rsk(req); - struct inet_connection_sock *newicsk = inet_csk(newsk); - struct tcp_sock *newtp = tcp_sk(newsk); - - /* Now setup tcp_sock */ - newtp->pred_flags = 0; - - newtp->rcv_wup = newtp->copied_seq = - newtp->rcv_nxt = treq->rcv_isn + 1; - newtp->segs_in = 1; - - newtp->snd_sml = newtp->snd_una = - newtp->snd_nxt = newtp->snd_up = treq->snt_isn + 1; - - tcp_prequeue_init(newtp); - INIT_LIST_HEAD(&newtp->tsq_node); - - tcp_init_wl(newtp, treq->rcv_isn); - - newtp->srtt_us = 0; - newtp->mdev_us = jiffies_to_usecs(TCP_TIMEOUT_INIT); - minmax_reset(&newtp->rtt_min, tcp_time_stamp, ~0U); - newicsk->icsk_rto = TCP_TIMEOUT_INIT; - - newtp->packets_out = 0; - newtp->retrans_out = 0; - newtp->sacked_out = 0; - newtp->fackets_out = 0; - newtp->snd_ssthresh = TCP_INFINITE_SSTHRESH; - tcp_enable_early_retrans(newtp); - newtp->tlp_high_seq = 0; - newtp->lsndtime = treq->snt_synack.stamp_jiffies; - newsk->sk_txhash = treq->txhash; - newtp->last_oow_ack_time = 0; - newtp->total_retrans = req->num_retrans; - - /* So many TCP implementations out there (incorrectly) count the - * initial SYN frame in their delayed-ACK and congestion control - * algorithms that we must have the following bandaid to talk - * efficiently to them. -DaveM - */ - newtp->snd_cwnd = TCP_INIT_CWND; - newtp->snd_cwnd_cnt = 0; - - /* There's a bubble in the pipe until at least the first ACK. */ - newtp->app_limited = ~0U; - - tcp_init_xmit_timers(newsk); - newtp->write_seq = newtp->pushed_seq = treq->snt_isn + 1; - - newtp->rx_opt.saw_tstamp = 0; - - newtp->rx_opt.dsack = 0; - newtp->rx_opt.num_sacks = 0; - - newtp->urg_data = 0; - - if (sock_flag(newsk, SOCK_KEEPOPEN)) - inet_csk_reset_keepalive_timer(newsk, - keepalive_time_when(newtp)); - - newtp->rx_opt.tstamp_ok = ireq->tstamp_ok; - if ((newtp->rx_opt.sack_ok = ireq->sack_ok) != 0) { - if (sysctl_tcp_fack) - tcp_enable_fack(newtp); - } - newtp->window_clamp = req->rsk_window_clamp; - newtp->rcv_ssthresh = req->rsk_rcv_wnd; - newtp->rcv_wnd = req->rsk_rcv_wnd; - newtp->rx_opt.wscale_ok = ireq->wscale_ok; - if (newtp->rx_opt.wscale_ok) { - newtp->rx_opt.snd_wscale = ireq->snd_wscale; - newtp->rx_opt.rcv_wscale = ireq->rcv_wscale; - } else { - newtp->rx_opt.snd_wscale = newtp->rx_opt.rcv_wscale = 0; - newtp->window_clamp = min(newtp->window_clamp, 65535U); - } - newtp->snd_wnd = (ntohs(tcp_hdr(skb)->window) << - newtp->rx_opt.snd_wscale); - newtp->max_window = newtp->snd_wnd; - - if (newtp->rx_opt.tstamp_ok) { - newtp->rx_opt.ts_recent = req->ts_recent; - newtp->rx_opt.ts_recent_stamp = get_seconds(); - newtp->tcp_header_len = sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED; - } else { - newtp->rx_opt.ts_recent_stamp = 0; - newtp->tcp_header_len = sizeof(struct tcphdr); - } - newtp->tsoffset = 0; -#ifdef CONFIG_TCP_MD5SIG - newtp->md5sig_info = NULL; /*XXX*/ - if (newtp->af_specific->md5_lookup(sk, newsk)) - newtp->tcp_header_len += TCPOLEN_MD5SIG_ALIGNED; -#endif - if (skb->len >= TCP_MSS_DEFAULT + newtp->tcp_header_len) - newicsk->icsk_ack.last_seg_size = skb->len - newtp->tcp_header_len; - newtp->rx_opt.mss_clamp = req->mss; - tcp_ecn_openreq_child(newtp, req); - newtp->fastopen_rsk = NULL; - newtp->syn_data_acked = 0; - newtp->rack.mstamp.v64 = 0; - newtp->rack.advanced = 0; - - __TCP_INC_STATS(sock_net(sk), TCP_MIB_PASSIVEOPENS); - } - return newsk; -} -EXPORT_SYMBOL(tcp_create_openreq_child); - -/* - * Process an incoming packet for SYN_RECV sockets represented as a - * request_sock. Normally sk is the listener socket but for TFO it - * points to the child socket. - * - * XXX (TFO) - The current impl contains a special check for ack - * validation and inside tcp_v4_reqsk_send_ack(). Can we do better? - * - * We don't need to initialize tmp_opt.sack_ok as we don't use the results - */ - -struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, - struct request_sock *req, - bool fastopen) -{ - struct tcp_options_received tmp_opt; - struct sock *child; - const struct tcphdr *th = tcp_hdr(skb); - __be32 flg = tcp_flag_word(th) & (TCP_FLAG_RST|TCP_FLAG_SYN|TCP_FLAG_ACK); - bool paws_reject = false; - bool own_req; - - tmp_opt.saw_tstamp = 0; - if (th->doff > (sizeof(struct tcphdr)>>2)) { - tcp_parse_options(skb, &tmp_opt, 0, NULL); - - if (tmp_opt.saw_tstamp) { - tmp_opt.ts_recent = req->ts_recent; - /* We do not store true stamp, but it is not required, - * it can be estimated (approximately) - * from another data. - */ - tmp_opt.ts_recent_stamp = get_seconds() - ((TCP_TIMEOUT_INIT/HZ)<num_timeout); - paws_reject = tcp_paws_reject(&tmp_opt, th->rst); - } - } - - /* Check for pure retransmitted SYN. */ - if (TCP_SKB_CB(skb)->seq == tcp_rsk(req)->rcv_isn && - flg == TCP_FLAG_SYN && - !paws_reject) { - /* - * RFC793 draws (Incorrectly! It was fixed in RFC1122) - * this case on figure 6 and figure 8, but formal - * protocol description says NOTHING. - * To be more exact, it says that we should send ACK, - * because this segment (at least, if it has no data) - * is out of window. - * - * CONCLUSION: RFC793 (even with RFC1122) DOES NOT - * describe SYN-RECV state. All the description - * is wrong, we cannot believe to it and should - * rely only on common sense and implementation - * experience. - * - * Enforce "SYN-ACK" according to figure 8, figure 6 - * of RFC793, fixed by RFC1122. - * - * Note that even if there is new data in the SYN packet - * they will be thrown away too. - * - * Reset timer after retransmitting SYNACK, similar to - * the idea of fast retransmit in recovery. - */ - if (!tcp_oow_rate_limited(sock_net(sk), skb, - LINUX_MIB_TCPACKSKIPPEDSYNRECV, - &tcp_rsk(req)->last_oow_ack_time) && - - !inet_rtx_syn_ack(sk, req)) { - unsigned long expires = jiffies; - - expires += min(TCP_TIMEOUT_INIT << req->num_timeout, - TCP_RTO_MAX); - if (!fastopen) - mod_timer_pending(&req->rsk_timer, expires); - else - req->rsk_timer.expires = expires; - } - return NULL; - } - - /* Further reproduces section "SEGMENT ARRIVES" - for state SYN-RECEIVED of RFC793. - It is broken, however, it does not work only - when SYNs are crossed. - - You would think that SYN crossing is impossible here, since - we should have a SYN_SENT socket (from connect()) on our end, - but this is not true if the crossed SYNs were sent to both - ends by a malicious third party. We must defend against this, - and to do that we first verify the ACK (as per RFC793, page - 36) and reset if it is invalid. Is this a true full defense? - To convince ourselves, let us consider a way in which the ACK - test can still pass in this 'malicious crossed SYNs' case. - Malicious sender sends identical SYNs (and thus identical sequence - numbers) to both A and B: - - A: gets SYN, seq=7 - B: gets SYN, seq=7 - - By our good fortune, both A and B select the same initial - send sequence number of seven :-) - - A: sends SYN|ACK, seq=7, ack_seq=8 - B: sends SYN|ACK, seq=7, ack_seq=8 - - So we are now A eating this SYN|ACK, ACK test passes. So - does sequence test, SYN is truncated, and thus we consider - it a bare ACK. - - If icsk->icsk_accept_queue.rskq_defer_accept, we silently drop this - bare ACK. Otherwise, we create an established connection. Both - ends (listening sockets) accept the new incoming connection and try - to talk to each other. 8-) - - Note: This case is both harmless, and rare. Possibility is about the - same as us discovering intelligent life on another plant tomorrow. - - But generally, we should (RFC lies!) to accept ACK - from SYNACK both here and in tcp_rcv_state_process(). - tcp_rcv_state_process() does not, hence, we do not too. - - Note that the case is absolutely generic: - we cannot optimize anything here without - violating protocol. All the checks must be made - before attempt to create socket. - */ - - /* RFC793 page 36: "If the connection is in any non-synchronized state ... - * and the incoming segment acknowledges something not yet - * sent (the segment carries an unacceptable ACK) ... - * a reset is sent." - * - * Invalid ACK: reset will be sent by listening socket. - * Note that the ACK validity check for a Fast Open socket is done - * elsewhere and is checked directly against the child socket rather - * than req because user data may have been sent out. - */ - if ((flg & TCP_FLAG_ACK) && !fastopen && - (TCP_SKB_CB(skb)->ack_seq != - tcp_rsk(req)->snt_isn + 1)) - return sk; - - /* Also, it would be not so bad idea to check rcv_tsecr, which - * is essentially ACK extension and too early or too late values - * should cause reset in unsynchronized states. - */ - - /* RFC793: "first check sequence number". */ - - if (paws_reject || !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, - tcp_rsk(req)->rcv_nxt, tcp_rsk(req)->rcv_nxt + req->rsk_rcv_wnd)) { - /* Out of window: send ACK and drop. */ - if (!(flg & TCP_FLAG_RST) && - !tcp_oow_rate_limited(sock_net(sk), skb, - LINUX_MIB_TCPACKSKIPPEDSYNRECV, - &tcp_rsk(req)->last_oow_ack_time)) - req->rsk_ops->send_ack(sk, skb, req); - if (paws_reject) - __NET_INC_STATS(sock_net(sk), LINUX_MIB_PAWSESTABREJECTED); - return NULL; - } - - /* In sequence, PAWS is OK. */ - - if (tmp_opt.saw_tstamp && !after(TCP_SKB_CB(skb)->seq, tcp_rsk(req)->rcv_nxt)) - req->ts_recent = tmp_opt.rcv_tsval; - - if (TCP_SKB_CB(skb)->seq == tcp_rsk(req)->rcv_isn) { - /* Truncate SYN, it is out of window starting - at tcp_rsk(req)->rcv_isn + 1. */ - flg &= ~TCP_FLAG_SYN; - } - - /* RFC793: "second check the RST bit" and - * "fourth, check the SYN bit" - */ - if (flg & (TCP_FLAG_RST|TCP_FLAG_SYN)) { - __TCP_INC_STATS(sock_net(sk), TCP_MIB_ATTEMPTFAILS); - goto embryonic_reset; - } - - /* ACK sequence verified above, just make sure ACK is - * set. If ACK not set, just silently drop the packet. - * - * XXX (TFO) - if we ever allow "data after SYN", the - * following check needs to be removed. - */ - if (!(flg & TCP_FLAG_ACK)) - return NULL; - - /* For Fast Open no more processing is needed (sk is the - * child socket). - */ - if (fastopen) - return sk; - - /* While TCP_DEFER_ACCEPT is active, drop bare ACK. */ - if (req->num_timeout < inet_csk(sk)->icsk_accept_queue.rskq_defer_accept && - TCP_SKB_CB(skb)->end_seq == tcp_rsk(req)->rcv_isn + 1) { - inet_rsk(req)->acked = 1; - __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPDEFERACCEPTDROP); - return NULL; - } - - /* OK, ACK is valid, create big socket and - * feed this segment to it. It will repeat all - * the tests. THIS SEGMENT MUST MOVE SOCKET TO - * ESTABLISHED STATE. If it will be dropped after - * socket is created, wait for troubles. - */ - child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL, - req, &own_req); - if (!child) - goto listen_overflow; - - sock_rps_save_rxhash(child, skb); - tcp_synack_rtt_meas(child, req); - return inet_csk_complete_hashdance(sk, child, req, own_req); - -listen_overflow: - if (!sysctl_tcp_abort_on_overflow) { - inet_rsk(req)->acked = 1; - return NULL; - } - -embryonic_reset: - if (!(flg & TCP_FLAG_RST)) { - /* Received a bad SYN pkt - for TFO We try not to reset - * the local connection unless it's really necessary to - * avoid becoming vulnerable to outside attack aiming at - * resetting legit local connections. - */ - req->rsk_ops->send_reset(sk, skb); - } else if (fastopen) { /* received a valid RST pkt */ - reqsk_fastopen_remove(sk, req, true); - tcp_reset(sk); - } - if (!fastopen) { - inet_csk_reqsk_queue_drop(sk, req); - __NET_INC_STATS(sock_net(sk), LINUX_MIB_EMBRYONICRSTS); - } - return NULL; -} -EXPORT_SYMBOL(tcp_check_req); - -/* - * Queue segment on the new socket if the new socket is active, - * otherwise we just shortcircuit this and continue with - * the new socket. - * - * For the vast majority of cases child->sk_state will be TCP_SYN_RECV - * when entering. But other states are possible due to a race condition - * where after __inet_lookup_established() fails but before the listener - * locked is obtained, other packets cause the same connection to - * be created. - */ - -int tcp_child_process(struct sock *parent, struct sock *child, - struct sk_buff *skb) -{ - int ret = 0; - int state = child->sk_state; - - tcp_segs_in(tcp_sk(child), skb); - if (!sock_owned_by_user(child)) { - ret = tcp_rcv_state_process(child, skb); - /* Wakeup parent, send SIGIO */ - if (state == TCP_SYN_RECV && child->sk_state != state) - parent->sk_data_ready(parent); - } else { - /* Alas, it is possible again, because we do lookup - * in main socket hash table and lock on listening - * socket does not protect us more. - */ - __sk_add_backlog(child, skb); - } - - bh_unlock_sock(child); - sock_put(child); - return ret; -} -EXPORT_SYMBOL(tcp_child_process); diff --git a/src/linux/net/ipv4/tcp_offload.c b/src/linux/net/ipv4/tcp_offload.c deleted file mode 100644 index bc68da3..0000000 --- a/src/linux/net/ipv4/tcp_offload.c +++ /dev/null @@ -1,335 +0,0 @@ -/* - * IPV4 GSO/GRO offload support - * Linux INET implementation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * TCPv4 GSO/GRO support - */ - -#include -#include -#include - -static void tcp_gso_tstamp(struct sk_buff *skb, unsigned int ts_seq, - unsigned int seq, unsigned int mss) -{ - while (skb) { - if (before(ts_seq, seq + mss)) { - skb_shinfo(skb)->tx_flags |= SKBTX_SW_TSTAMP; - skb_shinfo(skb)->tskey = ts_seq; - return; - } - - skb = skb->next; - seq += mss; - } -} - -static struct sk_buff *tcp4_gso_segment(struct sk_buff *skb, - netdev_features_t features) -{ - if (!pskb_may_pull(skb, sizeof(struct tcphdr))) - return ERR_PTR(-EINVAL); - - if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) { - const struct iphdr *iph = ip_hdr(skb); - struct tcphdr *th = tcp_hdr(skb); - - /* Set up checksum pseudo header, usually expect stack to - * have done this already. - */ - - th->check = 0; - skb->ip_summed = CHECKSUM_PARTIAL; - __tcp_v4_send_check(skb, iph->saddr, iph->daddr); - } - - return tcp_gso_segment(skb, features); -} - -struct sk_buff *tcp_gso_segment(struct sk_buff *skb, - netdev_features_t features) -{ - struct sk_buff *segs = ERR_PTR(-EINVAL); - unsigned int sum_truesize = 0; - struct tcphdr *th; - unsigned int thlen; - unsigned int seq; - __be32 delta; - unsigned int oldlen; - unsigned int mss; - struct sk_buff *gso_skb = skb; - __sum16 newcheck; - bool ooo_okay, copy_destructor; - - th = tcp_hdr(skb); - thlen = th->doff * 4; - if (thlen < sizeof(*th)) - goto out; - - if (!pskb_may_pull(skb, thlen)) - goto out; - - oldlen = (u16)~skb->len; - __skb_pull(skb, thlen); - - mss = skb_shinfo(skb)->gso_size; - if (unlikely(skb->len <= mss)) - goto out; - - if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { - /* Packet is from an untrusted source, reset gso_segs. */ - - skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); - - segs = NULL; - goto out; - } - - copy_destructor = gso_skb->destructor == tcp_wfree; - ooo_okay = gso_skb->ooo_okay; - /* All segments but the first should have ooo_okay cleared */ - skb->ooo_okay = 0; - - segs = skb_segment(skb, features); - if (IS_ERR(segs)) - goto out; - - /* Only first segment might have ooo_okay set */ - segs->ooo_okay = ooo_okay; - - /* GSO partial and frag_list segmentation only requires splitting - * the frame into an MSS multiple and possibly a remainder, both - * cases return a GSO skb. So update the mss now. - */ - if (skb_is_gso(segs)) - mss *= skb_shinfo(segs)->gso_segs; - - delta = htonl(oldlen + (thlen + mss)); - - skb = segs; - th = tcp_hdr(skb); - seq = ntohl(th->seq); - - if (unlikely(skb_shinfo(gso_skb)->tx_flags & SKBTX_SW_TSTAMP)) - tcp_gso_tstamp(segs, skb_shinfo(gso_skb)->tskey, seq, mss); - - newcheck = ~csum_fold((__force __wsum)((__force u32)th->check + - (__force u32)delta)); - - while (skb->next) { - th->fin = th->psh = 0; - th->check = newcheck; - - if (skb->ip_summed == CHECKSUM_PARTIAL) - gso_reset_checksum(skb, ~th->check); - else - th->check = gso_make_checksum(skb, ~th->check); - - seq += mss; - if (copy_destructor) { - skb->destructor = gso_skb->destructor; - skb->sk = gso_skb->sk; - sum_truesize += skb->truesize; - } - skb = skb->next; - th = tcp_hdr(skb); - - th->seq = htonl(seq); - th->cwr = 0; - } - - /* Following permits TCP Small Queues to work well with GSO : - * The callback to TCP stack will be called at the time last frag - * is freed at TX completion, and not right now when gso_skb - * is freed by GSO engine - */ - if (copy_destructor) { - swap(gso_skb->sk, skb->sk); - swap(gso_skb->destructor, skb->destructor); - sum_truesize += skb->truesize; - atomic_add(sum_truesize - gso_skb->truesize, - &skb->sk->sk_wmem_alloc); - } - - delta = htonl(oldlen + (skb_tail_pointer(skb) - - skb_transport_header(skb)) + - skb->data_len); - th->check = ~csum_fold((__force __wsum)((__force u32)th->check + - (__force u32)delta)); - if (skb->ip_summed == CHECKSUM_PARTIAL) - gso_reset_checksum(skb, ~th->check); - else - th->check = gso_make_checksum(skb, ~th->check); -out: - return segs; -} - -struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb) -{ - struct sk_buff **pp = NULL; - struct sk_buff *p; - struct tcphdr *th; - struct tcphdr *th2; - unsigned int len; - unsigned int thlen; - __be32 flags; - unsigned int mss = 1; - unsigned int hlen; - unsigned int off; - int flush = 1; - int i; - - off = skb_gro_offset(skb); - hlen = off + sizeof(*th); - th = skb_gro_header_fast(skb, off); - if (skb_gro_header_hard(skb, hlen)) { - th = skb_gro_header_slow(skb, hlen, off); - if (unlikely(!th)) - goto out; - } - - thlen = th->doff * 4; - if (thlen < sizeof(*th)) - goto out; - - hlen = off + thlen; - if (skb_gro_header_hard(skb, hlen)) { - th = skb_gro_header_slow(skb, hlen, off); - if (unlikely(!th)) - goto out; - } - - skb_gro_pull(skb, thlen); - - len = skb_gro_len(skb); - flags = tcp_flag_word(th); - - for (; (p = *head); head = &p->next) { - if (!NAPI_GRO_CB(p)->same_flow) - continue; - - th2 = tcp_hdr(p); - - if (*(u32 *)&th->source ^ *(u32 *)&th2->source) { - NAPI_GRO_CB(p)->same_flow = 0; - continue; - } - - goto found; - } - - goto out_check_final; - -found: - /* Include the IP ID check below from the inner most IP hdr */ - flush = NAPI_GRO_CB(p)->flush; - flush |= (__force int)(flags & TCP_FLAG_CWR); - flush |= (__force int)((flags ^ tcp_flag_word(th2)) & - ~(TCP_FLAG_CWR | TCP_FLAG_FIN | TCP_FLAG_PSH)); - flush |= (__force int)(th->ack_seq ^ th2->ack_seq); - for (i = sizeof(*th); i < thlen; i += 4) - flush |= *(u32 *)((u8 *)th + i) ^ - *(u32 *)((u8 *)th2 + i); - - /* When we receive our second frame we can made a decision on if we - * continue this flow as an atomic flow with a fixed ID or if we use - * an incrementing ID. - */ - if (NAPI_GRO_CB(p)->flush_id != 1 || - NAPI_GRO_CB(p)->count != 1 || - !NAPI_GRO_CB(p)->is_atomic) - flush |= NAPI_GRO_CB(p)->flush_id; - else - NAPI_GRO_CB(p)->is_atomic = false; - - mss = skb_shinfo(p)->gso_size; - - flush |= (len - 1) >= mss; - flush |= (ntohl(th2->seq) + skb_gro_len(p)) ^ ntohl(th->seq); - - if (flush || skb_gro_receive(head, skb)) { - mss = 1; - goto out_check_final; - } - - p = *head; - th2 = tcp_hdr(p); - tcp_flag_word(th2) |= flags & (TCP_FLAG_FIN | TCP_FLAG_PSH); - -out_check_final: - flush = len < mss; - flush |= (__force int)(flags & (TCP_FLAG_URG | TCP_FLAG_PSH | - TCP_FLAG_RST | TCP_FLAG_SYN | - TCP_FLAG_FIN)); - - if (p && (!NAPI_GRO_CB(skb)->same_flow || flush)) - pp = head; - -out: - NAPI_GRO_CB(skb)->flush |= (flush != 0); - - return pp; -} - -int tcp_gro_complete(struct sk_buff *skb) -{ - struct tcphdr *th = tcp_hdr(skb); - - skb->csum_start = (unsigned char *)th - skb->head; - skb->csum_offset = offsetof(struct tcphdr, check); - skb->ip_summed = CHECKSUM_PARTIAL; - - skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count; - - if (th->cwr) - skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN; - - return 0; -} -EXPORT_SYMBOL(tcp_gro_complete); - -static struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb) -{ - /* Don't bother verifying checksum if we're going to flush anyway. */ - if (!NAPI_GRO_CB(skb)->flush && - skb_gro_checksum_validate(skb, IPPROTO_TCP, - inet_gro_compute_pseudo)) { - NAPI_GRO_CB(skb)->flush = 1; - return NULL; - } - - return tcp_gro_receive(head, skb); -} - -static int tcp4_gro_complete(struct sk_buff *skb, int thoff) -{ - const struct iphdr *iph = ip_hdr(skb); - struct tcphdr *th = tcp_hdr(skb); - - th->check = ~tcp_v4_check(skb->len - thoff, iph->saddr, - iph->daddr, 0); - skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV4; - - if (NAPI_GRO_CB(skb)->is_atomic) - skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_FIXEDID; - - return tcp_gro_complete(skb); -} - -static const struct net_offload tcpv4_offload = { - .callbacks = { - .gso_segment = tcp4_gso_segment, - .gro_receive = tcp4_gro_receive, - .gro_complete = tcp4_gro_complete, - }, -}; - -int __init tcpv4_offload_init(void) -{ - return inet_add_offload(&tcpv4_offload, IPPROTO_TCP); -} diff --git a/src/linux/net/ipv4/tcp_output.c b/src/linux/net/ipv4/tcp_output.c deleted file mode 100644 index 896e9df..0000000 --- a/src/linux/net/ipv4/tcp_output.c +++ /dev/null @@ -1,3620 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Implementation of the Transmission Control Protocol(TCP). - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Mark Evans, - * Corey Minyard - * Florian La Roche, - * Charles Hedrick, - * Linus Torvalds, - * Alan Cox, - * Matthew Dillon, - * Arnt Gulbrandsen, - * Jorge Cwik, - */ - -/* - * Changes: Pedro Roque : Retransmit queue handled by TCP. - * : Fragmentation on mtu decrease - * : Segment collapse on retransmit - * : AF independence - * - * Linus Torvalds : send_delayed_ack - * David S. Miller : Charge memory using the right skb - * during syn/ack processing. - * David S. Miller : Output engine completely rewritten. - * Andrea Arcangeli: SYNACK carry ts_recent in tsecr. - * Cacophonix Gaul : draft-minshall-nagle-01 - * J Hadi Salim : ECN support - * - */ - -#define pr_fmt(fmt) "TCP: " fmt - -#include - -#include -#include -#include - -/* People can turn this off for buggy TCP's found in printers etc. */ -int sysctl_tcp_retrans_collapse __read_mostly = 1; - -/* People can turn this on to work with those rare, broken TCPs that - * interpret the window field as a signed quantity. - */ -int sysctl_tcp_workaround_signed_windows __read_mostly = 0; - -/* Default TSQ limit of four TSO segments */ -int sysctl_tcp_limit_output_bytes __read_mostly = 262144; - -/* This limits the percentage of the congestion window which we - * will allow a single TSO frame to consume. Building TSO frames - * which are too large can cause TCP streams to be bursty. - */ -int sysctl_tcp_tso_win_divisor __read_mostly = 3; - -/* By default, RFC2861 behavior. */ -int sysctl_tcp_slow_start_after_idle __read_mostly = 1; - -static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, - int push_one, gfp_t gfp); - -/* Account for new data that has been sent to the network. */ -static void tcp_event_new_data_sent(struct sock *sk, const struct sk_buff *skb) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - unsigned int prior_packets = tp->packets_out; - - tcp_advance_send_head(sk, skb); - tp->snd_nxt = TCP_SKB_CB(skb)->end_seq; - - tp->packets_out += tcp_skb_pcount(skb); - if (!prior_packets || icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS || - icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) { - tcp_rearm_rto(sk); - } - - NET_ADD_STATS(sock_net(sk), LINUX_MIB_TCPORIGDATASENT, - tcp_skb_pcount(skb)); -} - -/* SND.NXT, if window was not shrunk. - * If window has been shrunk, what should we make? It is not clear at all. - * Using SND.UNA we will fail to open window, SND.NXT is out of window. :-( - * Anything in between SND.UNA...SND.UNA+SND.WND also can be already - * invalid. OK, let's make this for now: - */ -static inline __u32 tcp_acceptable_seq(const struct sock *sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - - if (!before(tcp_wnd_end(tp), tp->snd_nxt)) - return tp->snd_nxt; - else - return tcp_wnd_end(tp); -} - -/* Calculate mss to advertise in SYN segment. - * RFC1122, RFC1063, draft-ietf-tcpimpl-pmtud-01 state that: - * - * 1. It is independent of path mtu. - * 2. Ideally, it is maximal possible segment size i.e. 65535-40. - * 3. For IPv4 it is reasonable to calculate it from maximal MTU of - * attached devices, because some buggy hosts are confused by - * large MSS. - * 4. We do not make 3, we advertise MSS, calculated from first - * hop device mtu, but allow to raise it to ip_rt_min_advmss. - * This may be overridden via information stored in routing table. - * 5. Value 65535 for MSS is valid in IPv6 and means "as large as possible, - * probably even Jumbo". - */ -static __u16 tcp_advertise_mss(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - const struct dst_entry *dst = __sk_dst_get(sk); - int mss = tp->advmss; - - if (dst) { - unsigned int metric = dst_metric_advmss(dst); - - if (metric < mss) { - mss = metric; - tp->advmss = mss; - } - } - - return (__u16)mss; -} - -/* RFC2861. Reset CWND after idle period longer RTO to "restart window". - * This is the first part of cwnd validation mechanism. - */ -void tcp_cwnd_restart(struct sock *sk, s32 delta) -{ - struct tcp_sock *tp = tcp_sk(sk); - u32 restart_cwnd = tcp_init_cwnd(tp, __sk_dst_get(sk)); - u32 cwnd = tp->snd_cwnd; - - tcp_ca_event(sk, CA_EVENT_CWND_RESTART); - - tp->snd_ssthresh = tcp_current_ssthresh(sk); - restart_cwnd = min(restart_cwnd, cwnd); - - while ((delta -= inet_csk(sk)->icsk_rto) > 0 && cwnd > restart_cwnd) - cwnd >>= 1; - tp->snd_cwnd = max(cwnd, restart_cwnd); - tp->snd_cwnd_stamp = tcp_time_stamp; - tp->snd_cwnd_used = 0; -} - -/* Congestion state accounting after a packet has been sent. */ -static void tcp_event_data_sent(struct tcp_sock *tp, - struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - const u32 now = tcp_time_stamp; - - if (tcp_packets_in_flight(tp) == 0) - tcp_ca_event(sk, CA_EVENT_TX_START); - - tp->lsndtime = now; - - /* If it is a reply for ato after last received - * packet, enter pingpong mode. - */ - if ((u32)(now - icsk->icsk_ack.lrcvtime) < icsk->icsk_ack.ato) - icsk->icsk_ack.pingpong = 1; -} - -/* Account for an ACK we sent. */ -static inline void tcp_event_ack_sent(struct sock *sk, unsigned int pkts) -{ - tcp_dec_quickack_mode(sk, pkts); - inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK); -} - - -u32 tcp_default_init_rwnd(u32 mss) -{ - /* Initial receive window should be twice of TCP_INIT_CWND to - * enable proper sending of new unsent data during fast recovery - * (RFC 3517, Section 4, NextSeg() rule (2)). Further place a - * limit when mss is larger than 1460. - */ - u32 init_rwnd = TCP_INIT_CWND * 2; - - if (mss > 1460) - init_rwnd = max((1460 * init_rwnd) / mss, 2U); - return init_rwnd; -} - -/* Determine a window scaling and initial window to offer. - * Based on the assumption that the given amount of space - * will be offered. Store the results in the tp structure. - * NOTE: for smooth operation initial space offering should - * be a multiple of mss if possible. We assume here that mss >= 1. - * This MUST be enforced by all callers. - */ -void tcp_select_initial_window(int __space, __u32 mss, - __u32 *rcv_wnd, __u32 *window_clamp, - int wscale_ok, __u8 *rcv_wscale, - __u32 init_rcv_wnd) -{ - unsigned int space = (__space < 0 ? 0 : __space); - - /* If no clamp set the clamp to the max possible scaled window */ - if (*window_clamp == 0) - (*window_clamp) = (65535 << 14); - space = min(*window_clamp, space); - - /* Quantize space offering to a multiple of mss if possible. */ - if (space > mss) - space = (space / mss) * mss; - - /* NOTE: offering an initial window larger than 32767 - * will break some buggy TCP stacks. If the admin tells us - * it is likely we could be speaking with such a buggy stack - * we will truncate our initial window offering to 32K-1 - * unless the remote has sent us a window scaling option, - * which we interpret as a sign the remote TCP is not - * misinterpreting the window field as a signed quantity. - */ - if (sysctl_tcp_workaround_signed_windows) - (*rcv_wnd) = min(space, MAX_TCP_WINDOW); - else - (*rcv_wnd) = space; - - (*rcv_wscale) = 0; - if (wscale_ok) { - /* Set window scaling on max possible window - * See RFC1323 for an explanation of the limit to 14 - */ - space = max_t(u32, space, sysctl_tcp_rmem[2]); - space = max_t(u32, space, sysctl_rmem_max); - space = min_t(u32, space, *window_clamp); - while (space > 65535 && (*rcv_wscale) < 14) { - space >>= 1; - (*rcv_wscale)++; - } - } - - if (mss > (1 << *rcv_wscale)) { - if (!init_rcv_wnd) /* Use default unless specified otherwise */ - init_rcv_wnd = tcp_default_init_rwnd(mss); - *rcv_wnd = min(*rcv_wnd, init_rcv_wnd * mss); - } - - /* Set the clamp no higher than max representable value */ - (*window_clamp) = min(65535U << (*rcv_wscale), *window_clamp); -} -EXPORT_SYMBOL(tcp_select_initial_window); - -/* Chose a new window to advertise, update state in tcp_sock for the - * socket, and return result with RFC1323 scaling applied. The return - * value can be stuffed directly into th->window for an outgoing - * frame. - */ -static u16 tcp_select_window(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - u32 old_win = tp->rcv_wnd; - u32 cur_win = tcp_receive_window(tp); - u32 new_win = __tcp_select_window(sk); - - /* Never shrink the offered window */ - if (new_win < cur_win) { - /* Danger Will Robinson! - * Don't update rcv_wup/rcv_wnd here or else - * we will not be able to advertise a zero - * window in time. --DaveM - * - * Relax Will Robinson. - */ - if (new_win == 0) - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPWANTZEROWINDOWADV); - new_win = ALIGN(cur_win, 1 << tp->rx_opt.rcv_wscale); - } - tp->rcv_wnd = new_win; - tp->rcv_wup = tp->rcv_nxt; - - /* Make sure we do not exceed the maximum possible - * scaled window. - */ - if (!tp->rx_opt.rcv_wscale && sysctl_tcp_workaround_signed_windows) - new_win = min(new_win, MAX_TCP_WINDOW); - else - new_win = min(new_win, (65535U << tp->rx_opt.rcv_wscale)); - - /* RFC1323 scaling applied */ - new_win >>= tp->rx_opt.rcv_wscale; - - /* If we advertise zero window, disable fast path. */ - if (new_win == 0) { - tp->pred_flags = 0; - if (old_win) - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPTOZEROWINDOWADV); - } else if (old_win == 0) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPFROMZEROWINDOWADV); - } - - return new_win; -} - -/* Packet ECN state for a SYN-ACK */ -static void tcp_ecn_send_synack(struct sock *sk, struct sk_buff *skb) -{ - const struct tcp_sock *tp = tcp_sk(sk); - - TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_CWR; - if (!(tp->ecn_flags & TCP_ECN_OK)) - TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_ECE; - else if (tcp_ca_needs_ecn(sk)) - INET_ECN_xmit(sk); -} - -/* Packet ECN state for a SYN. */ -static void tcp_ecn_send_syn(struct sock *sk, struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - bool use_ecn = sock_net(sk)->ipv4.sysctl_tcp_ecn == 1 || - tcp_ca_needs_ecn(sk); - - if (!use_ecn) { - const struct dst_entry *dst = __sk_dst_get(sk); - - if (dst && dst_feature(dst, RTAX_FEATURE_ECN)) - use_ecn = true; - } - - tp->ecn_flags = 0; - - if (use_ecn) { - TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_ECE | TCPHDR_CWR; - tp->ecn_flags = TCP_ECN_OK; - if (tcp_ca_needs_ecn(sk)) - INET_ECN_xmit(sk); - } -} - -static void tcp_ecn_clear_syn(struct sock *sk, struct sk_buff *skb) -{ - if (sock_net(sk)->ipv4.sysctl_tcp_ecn_fallback) - /* tp->ecn_flags are cleared at a later point in time when - * SYN ACK is ultimatively being received. - */ - TCP_SKB_CB(skb)->tcp_flags &= ~(TCPHDR_ECE | TCPHDR_CWR); -} - -static void -tcp_ecn_make_synack(const struct request_sock *req, struct tcphdr *th) -{ - if (inet_rsk(req)->ecn_ok) - th->ece = 1; -} - -/* Set up ECN state for a packet on a ESTABLISHED socket that is about to - * be sent. - */ -static void tcp_ecn_send(struct sock *sk, struct sk_buff *skb, - struct tcphdr *th, int tcp_header_len) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (tp->ecn_flags & TCP_ECN_OK) { - /* Not-retransmitted data segment: set ECT and inject CWR. */ - if (skb->len != tcp_header_len && - !before(TCP_SKB_CB(skb)->seq, tp->snd_nxt)) { - INET_ECN_xmit(sk); - if (tp->ecn_flags & TCP_ECN_QUEUE_CWR) { - tp->ecn_flags &= ~TCP_ECN_QUEUE_CWR; - th->cwr = 1; - skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN; - } - } else if (!tcp_ca_needs_ecn(sk)) { - /* ACK or retransmitted segment: clear ECT|CE */ - INET_ECN_dontxmit(sk); - } - if (tp->ecn_flags & TCP_ECN_DEMAND_CWR) - th->ece = 1; - } -} - -/* Constructs common control bits of non-data skb. If SYN/FIN is present, - * auto increment end seqno. - */ -static void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags) -{ - skb->ip_summed = CHECKSUM_PARTIAL; - skb->csum = 0; - - TCP_SKB_CB(skb)->tcp_flags = flags; - TCP_SKB_CB(skb)->sacked = 0; - - tcp_skb_pcount_set(skb, 1); - - TCP_SKB_CB(skb)->seq = seq; - if (flags & (TCPHDR_SYN | TCPHDR_FIN)) - seq++; - TCP_SKB_CB(skb)->end_seq = seq; -} - -static inline bool tcp_urg_mode(const struct tcp_sock *tp) -{ - return tp->snd_una != tp->snd_up; -} - -#define OPTION_SACK_ADVERTISE (1 << 0) -#define OPTION_TS (1 << 1) -#define OPTION_MD5 (1 << 2) -#define OPTION_WSCALE (1 << 3) -#define OPTION_FAST_OPEN_COOKIE (1 << 8) - -struct tcp_out_options { - u16 options; /* bit field of OPTION_* */ - u16 mss; /* 0 to disable */ - u8 ws; /* window scale, 0 to disable */ - u8 num_sack_blocks; /* number of SACK blocks to include */ - u8 hash_size; /* bytes in hash_location */ - __u8 *hash_location; /* temporary pointer, overloaded */ - __u32 tsval, tsecr; /* need to include OPTION_TS */ - struct tcp_fastopen_cookie *fastopen_cookie; /* Fast open cookie */ -}; - -/* Write previously computed TCP options to the packet. - * - * Beware: Something in the Internet is very sensitive to the ordering of - * TCP options, we learned this through the hard way, so be careful here. - * Luckily we can at least blame others for their non-compliance but from - * inter-operability perspective it seems that we're somewhat stuck with - * the ordering which we have been using if we want to keep working with - * those broken things (not that it currently hurts anybody as there isn't - * particular reason why the ordering would need to be changed). - * - * At least SACK_PERM as the first option is known to lead to a disaster - * (but it may well be that other scenarios fail similarly). - */ -static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp, - struct tcp_out_options *opts) -{ - u16 options = opts->options; /* mungable copy */ - - if (unlikely(OPTION_MD5 & options)) { - *ptr++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | - (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG); - /* overload cookie hash location */ - opts->hash_location = (__u8 *)ptr; - ptr += 4; - } - - if (unlikely(opts->mss)) { - *ptr++ = htonl((TCPOPT_MSS << 24) | - (TCPOLEN_MSS << 16) | - opts->mss); - } - - if (likely(OPTION_TS & options)) { - if (unlikely(OPTION_SACK_ADVERTISE & options)) { - *ptr++ = htonl((TCPOPT_SACK_PERM << 24) | - (TCPOLEN_SACK_PERM << 16) | - (TCPOPT_TIMESTAMP << 8) | - TCPOLEN_TIMESTAMP); - options &= ~OPTION_SACK_ADVERTISE; - } else { - *ptr++ = htonl((TCPOPT_NOP << 24) | - (TCPOPT_NOP << 16) | - (TCPOPT_TIMESTAMP << 8) | - TCPOLEN_TIMESTAMP); - } - *ptr++ = htonl(opts->tsval); - *ptr++ = htonl(opts->tsecr); - } - - if (unlikely(OPTION_SACK_ADVERTISE & options)) { - *ptr++ = htonl((TCPOPT_NOP << 24) | - (TCPOPT_NOP << 16) | - (TCPOPT_SACK_PERM << 8) | - TCPOLEN_SACK_PERM); - } - - if (unlikely(OPTION_WSCALE & options)) { - *ptr++ = htonl((TCPOPT_NOP << 24) | - (TCPOPT_WINDOW << 16) | - (TCPOLEN_WINDOW << 8) | - opts->ws); - } - - if (unlikely(opts->num_sack_blocks)) { - struct tcp_sack_block *sp = tp->rx_opt.dsack ? - tp->duplicate_sack : tp->selective_acks; - int this_sack; - - *ptr++ = htonl((TCPOPT_NOP << 24) | - (TCPOPT_NOP << 16) | - (TCPOPT_SACK << 8) | - (TCPOLEN_SACK_BASE + (opts->num_sack_blocks * - TCPOLEN_SACK_PERBLOCK))); - - for (this_sack = 0; this_sack < opts->num_sack_blocks; - ++this_sack) { - *ptr++ = htonl(sp[this_sack].start_seq); - *ptr++ = htonl(sp[this_sack].end_seq); - } - - tp->rx_opt.dsack = 0; - } - - if (unlikely(OPTION_FAST_OPEN_COOKIE & options)) { - struct tcp_fastopen_cookie *foc = opts->fastopen_cookie; - u8 *p = (u8 *)ptr; - u32 len; /* Fast Open option length */ - - if (foc->exp) { - len = TCPOLEN_EXP_FASTOPEN_BASE + foc->len; - *ptr = htonl((TCPOPT_EXP << 24) | (len << 16) | - TCPOPT_FASTOPEN_MAGIC); - p += TCPOLEN_EXP_FASTOPEN_BASE; - } else { - len = TCPOLEN_FASTOPEN_BASE + foc->len; - *p++ = TCPOPT_FASTOPEN; - *p++ = len; - } - - memcpy(p, foc->val, foc->len); - if ((len & 3) == 2) { - p[foc->len] = TCPOPT_NOP; - p[foc->len + 1] = TCPOPT_NOP; - } - ptr += (len + 3) >> 2; - } -} - -/* Compute TCP options for SYN packets. This is not the final - * network wire format yet. - */ -static unsigned int tcp_syn_options(struct sock *sk, struct sk_buff *skb, - struct tcp_out_options *opts, - struct tcp_md5sig_key **md5) -{ - struct tcp_sock *tp = tcp_sk(sk); - unsigned int remaining = MAX_TCP_OPTION_SPACE; - struct tcp_fastopen_request *fastopen = tp->fastopen_req; - -#ifdef CONFIG_TCP_MD5SIG - *md5 = tp->af_specific->md5_lookup(sk, sk); - if (*md5) { - opts->options |= OPTION_MD5; - remaining -= TCPOLEN_MD5SIG_ALIGNED; - } -#else - *md5 = NULL; -#endif - - /* We always get an MSS option. The option bytes which will be seen in - * normal data packets should timestamps be used, must be in the MSS - * advertised. But we subtract them from tp->mss_cache so that - * calculations in tcp_sendmsg are simpler etc. So account for this - * fact here if necessary. If we don't do this correctly, as a - * receiver we won't recognize data packets as being full sized when we - * should, and thus we won't abide by the delayed ACK rules correctly. - * SACKs don't matter, we never delay an ACK when we have any of those - * going out. */ - opts->mss = tcp_advertise_mss(sk); - remaining -= TCPOLEN_MSS_ALIGNED; - - if (likely(sysctl_tcp_timestamps && !*md5)) { - opts->options |= OPTION_TS; - opts->tsval = tcp_skb_timestamp(skb) + tp->tsoffset; - opts->tsecr = tp->rx_opt.ts_recent; - remaining -= TCPOLEN_TSTAMP_ALIGNED; - } - if (likely(sysctl_tcp_window_scaling)) { - opts->ws = tp->rx_opt.rcv_wscale; - opts->options |= OPTION_WSCALE; - remaining -= TCPOLEN_WSCALE_ALIGNED; - } - if (likely(sysctl_tcp_sack)) { - opts->options |= OPTION_SACK_ADVERTISE; - if (unlikely(!(OPTION_TS & opts->options))) - remaining -= TCPOLEN_SACKPERM_ALIGNED; - } - - if (fastopen && fastopen->cookie.len >= 0) { - u32 need = fastopen->cookie.len; - - need += fastopen->cookie.exp ? TCPOLEN_EXP_FASTOPEN_BASE : - TCPOLEN_FASTOPEN_BASE; - need = (need + 3) & ~3U; /* Align to 32 bits */ - if (remaining >= need) { - opts->options |= OPTION_FAST_OPEN_COOKIE; - opts->fastopen_cookie = &fastopen->cookie; - remaining -= need; - tp->syn_fastopen = 1; - tp->syn_fastopen_exp = fastopen->cookie.exp ? 1 : 0; - } - } - - return MAX_TCP_OPTION_SPACE - remaining; -} - -/* Set up TCP options for SYN-ACKs. */ -static unsigned int tcp_synack_options(struct request_sock *req, - unsigned int mss, struct sk_buff *skb, - struct tcp_out_options *opts, - const struct tcp_md5sig_key *md5, - struct tcp_fastopen_cookie *foc) -{ - struct inet_request_sock *ireq = inet_rsk(req); - unsigned int remaining = MAX_TCP_OPTION_SPACE; - -#ifdef CONFIG_TCP_MD5SIG - if (md5) { - opts->options |= OPTION_MD5; - remaining -= TCPOLEN_MD5SIG_ALIGNED; - - /* We can't fit any SACK blocks in a packet with MD5 + TS - * options. There was discussion about disabling SACK - * rather than TS in order to fit in better with old, - * buggy kernels, but that was deemed to be unnecessary. - */ - ireq->tstamp_ok &= !ireq->sack_ok; - } -#endif - - /* We always send an MSS option. */ - opts->mss = mss; - remaining -= TCPOLEN_MSS_ALIGNED; - - if (likely(ireq->wscale_ok)) { - opts->ws = ireq->rcv_wscale; - opts->options |= OPTION_WSCALE; - remaining -= TCPOLEN_WSCALE_ALIGNED; - } - if (likely(ireq->tstamp_ok)) { - opts->options |= OPTION_TS; - opts->tsval = tcp_skb_timestamp(skb); - opts->tsecr = req->ts_recent; - remaining -= TCPOLEN_TSTAMP_ALIGNED; - } - if (likely(ireq->sack_ok)) { - opts->options |= OPTION_SACK_ADVERTISE; - if (unlikely(!ireq->tstamp_ok)) - remaining -= TCPOLEN_SACKPERM_ALIGNED; - } - if (foc != NULL && foc->len >= 0) { - u32 need = foc->len; - - need += foc->exp ? TCPOLEN_EXP_FASTOPEN_BASE : - TCPOLEN_FASTOPEN_BASE; - need = (need + 3) & ~3U; /* Align to 32 bits */ - if (remaining >= need) { - opts->options |= OPTION_FAST_OPEN_COOKIE; - opts->fastopen_cookie = foc; - remaining -= need; - } - } - - return MAX_TCP_OPTION_SPACE - remaining; -} - -/* Compute TCP options for ESTABLISHED sockets. This is not the - * final wire format yet. - */ -static unsigned int tcp_established_options(struct sock *sk, struct sk_buff *skb, - struct tcp_out_options *opts, - struct tcp_md5sig_key **md5) -{ - struct tcp_sock *tp = tcp_sk(sk); - unsigned int size = 0; - unsigned int eff_sacks; - - opts->options = 0; - -#ifdef CONFIG_TCP_MD5SIG - *md5 = tp->af_specific->md5_lookup(sk, sk); - if (unlikely(*md5)) { - opts->options |= OPTION_MD5; - size += TCPOLEN_MD5SIG_ALIGNED; - } -#else - *md5 = NULL; -#endif - - if (likely(tp->rx_opt.tstamp_ok)) { - opts->options |= OPTION_TS; - opts->tsval = skb ? tcp_skb_timestamp(skb) + tp->tsoffset : 0; - opts->tsecr = tp->rx_opt.ts_recent; - size += TCPOLEN_TSTAMP_ALIGNED; - } - - eff_sacks = tp->rx_opt.num_sacks + tp->rx_opt.dsack; - if (unlikely(eff_sacks)) { - const unsigned int remaining = MAX_TCP_OPTION_SPACE - size; - opts->num_sack_blocks = - min_t(unsigned int, eff_sacks, - (remaining - TCPOLEN_SACK_BASE_ALIGNED) / - TCPOLEN_SACK_PERBLOCK); - size += TCPOLEN_SACK_BASE_ALIGNED + - opts->num_sack_blocks * TCPOLEN_SACK_PERBLOCK; - } - - return size; -} - - -/* TCP SMALL QUEUES (TSQ) - * - * TSQ goal is to keep small amount of skbs per tcp flow in tx queues (qdisc+dev) - * to reduce RTT and bufferbloat. - * We do this using a special skb destructor (tcp_wfree). - * - * Its important tcp_wfree() can be replaced by sock_wfree() in the event skb - * needs to be reallocated in a driver. - * The invariant being skb->truesize subtracted from sk->sk_wmem_alloc - * - * Since transmit from skb destructor is forbidden, we use a tasklet - * to process all sockets that eventually need to send more skbs. - * We use one tasklet per cpu, with its own queue of sockets. - */ -struct tsq_tasklet { - struct tasklet_struct tasklet; - struct list_head head; /* queue of tcp sockets */ -}; -static DEFINE_PER_CPU(struct tsq_tasklet, tsq_tasklet); - -static void tcp_tsq_handler(struct sock *sk) -{ - if ((1 << sk->sk_state) & - (TCPF_ESTABLISHED | TCPF_FIN_WAIT1 | TCPF_CLOSING | - TCPF_CLOSE_WAIT | TCPF_LAST_ACK)) { - struct tcp_sock *tp = tcp_sk(sk); - - if (tp->lost_out > tp->retrans_out && - tp->snd_cwnd > tcp_packets_in_flight(tp)) - tcp_xmit_retransmit_queue(sk); - - tcp_write_xmit(sk, tcp_current_mss(sk), tp->nonagle, - 0, GFP_ATOMIC); - } -} -/* - * One tasklet per cpu tries to send more skbs. - * We run in tasklet context but need to disable irqs when - * transferring tsq->head because tcp_wfree() might - * interrupt us (non NAPI drivers) - */ -static void tcp_tasklet_func(unsigned long data) -{ - struct tsq_tasklet *tsq = (struct tsq_tasklet *)data; - LIST_HEAD(list); - unsigned long flags; - struct list_head *q, *n; - struct tcp_sock *tp; - struct sock *sk; - - local_irq_save(flags); - list_splice_init(&tsq->head, &list); - local_irq_restore(flags); - - list_for_each_safe(q, n, &list) { - tp = list_entry(q, struct tcp_sock, tsq_node); - list_del(&tp->tsq_node); - - sk = (struct sock *)tp; - bh_lock_sock(sk); - - if (!sock_owned_by_user(sk)) { - tcp_tsq_handler(sk); - } else { - /* defer the work to tcp_release_cb() */ - set_bit(TCP_TSQ_DEFERRED, &tp->tsq_flags); - } - bh_unlock_sock(sk); - - clear_bit(TSQ_QUEUED, &tp->tsq_flags); - sk_free(sk); - } -} - -#define TCP_DEFERRED_ALL ((1UL << TCP_TSQ_DEFERRED) | \ - (1UL << TCP_WRITE_TIMER_DEFERRED) | \ - (1UL << TCP_DELACK_TIMER_DEFERRED) | \ - (1UL << TCP_MTU_REDUCED_DEFERRED)) -/** - * tcp_release_cb - tcp release_sock() callback - * @sk: socket - * - * called from release_sock() to perform protocol dependent - * actions before socket release. - */ -void tcp_release_cb(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - unsigned long flags, nflags; - - /* perform an atomic operation only if at least one flag is set */ - do { - flags = tp->tsq_flags; - if (!(flags & TCP_DEFERRED_ALL)) - return; - nflags = flags & ~TCP_DEFERRED_ALL; - } while (cmpxchg(&tp->tsq_flags, flags, nflags) != flags); - - if (flags & (1UL << TCP_TSQ_DEFERRED)) - tcp_tsq_handler(sk); - - /* Here begins the tricky part : - * We are called from release_sock() with : - * 1) BH disabled - * 2) sk_lock.slock spinlock held - * 3) socket owned by us (sk->sk_lock.owned == 1) - * - * But following code is meant to be called from BH handlers, - * so we should keep BH disabled, but early release socket ownership - */ - sock_release_ownership(sk); - - if (flags & (1UL << TCP_WRITE_TIMER_DEFERRED)) { - tcp_write_timer_handler(sk); - __sock_put(sk); - } - if (flags & (1UL << TCP_DELACK_TIMER_DEFERRED)) { - tcp_delack_timer_handler(sk); - __sock_put(sk); - } - if (flags & (1UL << TCP_MTU_REDUCED_DEFERRED)) { - inet_csk(sk)->icsk_af_ops->mtu_reduced(sk); - __sock_put(sk); - } -} -EXPORT_SYMBOL(tcp_release_cb); - -void __init tcp_tasklet_init(void) -{ - int i; - - for_each_possible_cpu(i) { - struct tsq_tasklet *tsq = &per_cpu(tsq_tasklet, i); - - INIT_LIST_HEAD(&tsq->head); - tasklet_init(&tsq->tasklet, - tcp_tasklet_func, - (unsigned long)tsq); - } -} - -/* - * Write buffer destructor automatically called from kfree_skb. - * We can't xmit new skbs from this context, as we might already - * hold qdisc lock. - */ -void tcp_wfree(struct sk_buff *skb) -{ - struct sock *sk = skb->sk; - struct tcp_sock *tp = tcp_sk(sk); - int wmem; - - /* Keep one reference on sk_wmem_alloc. - * Will be released by sk_free() from here or tcp_tasklet_func() - */ - wmem = atomic_sub_return(skb->truesize - 1, &sk->sk_wmem_alloc); - - /* If this softirq is serviced by ksoftirqd, we are likely under stress. - * Wait until our queues (qdisc + devices) are drained. - * This gives : - * - less callbacks to tcp_write_xmit(), reducing stress (batches) - * - chance for incoming ACK (processed by another cpu maybe) - * to migrate this flow (skb->ooo_okay will be eventually set) - */ - if (wmem >= SKB_TRUESIZE(1) && this_cpu_ksoftirqd() == current) - goto out; - - if (test_and_clear_bit(TSQ_THROTTLED, &tp->tsq_flags) && - !test_and_set_bit(TSQ_QUEUED, &tp->tsq_flags)) { - unsigned long flags; - struct tsq_tasklet *tsq; - - /* queue this socket to tasklet queue */ - local_irq_save(flags); - tsq = this_cpu_ptr(&tsq_tasklet); - list_add(&tp->tsq_node, &tsq->head); - tasklet_schedule(&tsq->tasklet); - local_irq_restore(flags); - return; - } -out: - sk_free(sk); -} - -/* This routine actually transmits TCP packets queued in by - * tcp_do_sendmsg(). This is used by both the initial - * transmission and possible later retransmissions. - * All SKB's seen here are completely headerless. It is our - * job to build the TCP header, and pass the packet down to - * IP so it can do the same plus pass the packet off to the - * device. - * - * We are working here with either a clone of the original - * SKB, or a fresh unique copy made by the retransmit engine. - */ -static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, - gfp_t gfp_mask) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - struct inet_sock *inet; - struct tcp_sock *tp; - struct tcp_skb_cb *tcb; - struct tcp_out_options opts; - unsigned int tcp_options_size, tcp_header_size; - struct tcp_md5sig_key *md5; - struct tcphdr *th; - int err; - - BUG_ON(!skb || !tcp_skb_pcount(skb)); - tp = tcp_sk(sk); - - if (clone_it) { - skb_mstamp_get(&skb->skb_mstamp); - TCP_SKB_CB(skb)->tx.in_flight = TCP_SKB_CB(skb)->end_seq - - tp->snd_una; - tcp_rate_skb_sent(sk, skb); - - if (unlikely(skb_cloned(skb))) - skb = pskb_copy(skb, gfp_mask); - else - skb = skb_clone(skb, gfp_mask); - if (unlikely(!skb)) - return -ENOBUFS; - } - - inet = inet_sk(sk); - tcb = TCP_SKB_CB(skb); - memset(&opts, 0, sizeof(opts)); - - if (unlikely(tcb->tcp_flags & TCPHDR_SYN)) - tcp_options_size = tcp_syn_options(sk, skb, &opts, &md5); - else - tcp_options_size = tcp_established_options(sk, skb, &opts, - &md5); - tcp_header_size = tcp_options_size + sizeof(struct tcphdr); - - /* if no packet is in qdisc/device queue, then allow XPS to select - * another queue. We can be called from tcp_tsq_handler() - * which holds one reference to sk_wmem_alloc. - * - * TODO: Ideally, in-flight pure ACK packets should not matter here. - * One way to get this would be to set skb->truesize = 2 on them. - */ - skb->ooo_okay = sk_wmem_alloc_get(sk) < SKB_TRUESIZE(1); - - skb_push(skb, tcp_header_size); - skb_reset_transport_header(skb); - - skb_orphan(skb); - skb->sk = sk; - skb->destructor = skb_is_tcp_pure_ack(skb) ? __sock_wfree : tcp_wfree; - skb_set_hash_from_sk(skb, sk); - atomic_add(skb->truesize, &sk->sk_wmem_alloc); - - /* Build TCP header and checksum it. */ - th = (struct tcphdr *)skb->data; - th->source = inet->inet_sport; - th->dest = inet->inet_dport; - th->seq = htonl(tcb->seq); - th->ack_seq = htonl(tp->rcv_nxt); - *(((__be16 *)th) + 6) = htons(((tcp_header_size >> 2) << 12) | - tcb->tcp_flags); - - th->check = 0; - th->urg_ptr = 0; - - /* The urg_mode check is necessary during a below snd_una win probe */ - if (unlikely(tcp_urg_mode(tp) && before(tcb->seq, tp->snd_up))) { - if (before(tp->snd_up, tcb->seq + 0x10000)) { - th->urg_ptr = htons(tp->snd_up - tcb->seq); - th->urg = 1; - } else if (after(tcb->seq + 0xFFFF, tp->snd_nxt)) { - th->urg_ptr = htons(0xFFFF); - th->urg = 1; - } - } - - tcp_options_write((__be32 *)(th + 1), tp, &opts); - skb_shinfo(skb)->gso_type = sk->sk_gso_type; - if (likely(!(tcb->tcp_flags & TCPHDR_SYN))) { - th->window = htons(tcp_select_window(sk)); - tcp_ecn_send(sk, skb, th, tcp_header_size); - } else { - /* RFC1323: The window in SYN & SYN/ACK segments - * is never scaled. - */ - th->window = htons(min(tp->rcv_wnd, 65535U)); - } -#ifdef CONFIG_TCP_MD5SIG - /* Calculate the MD5 hash, as we have all we need now */ - if (md5) { - sk_nocaps_add(sk, NETIF_F_GSO_MASK); - tp->af_specific->calc_md5_hash(opts.hash_location, - md5, sk, skb); - } -#endif - - icsk->icsk_af_ops->send_check(sk, skb); - - if (likely(tcb->tcp_flags & TCPHDR_ACK)) - tcp_event_ack_sent(sk, tcp_skb_pcount(skb)); - - if (skb->len != tcp_header_size) { - tcp_event_data_sent(tp, sk); - tp->data_segs_out += tcp_skb_pcount(skb); - } - - if (after(tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq) - TCP_ADD_STATS(sock_net(sk), TCP_MIB_OUTSEGS, - tcp_skb_pcount(skb)); - - tp->segs_out += tcp_skb_pcount(skb); - /* OK, its time to fill skb_shinfo(skb)->gso_{segs|size} */ - skb_shinfo(skb)->gso_segs = tcp_skb_pcount(skb); - skb_shinfo(skb)->gso_size = tcp_skb_mss(skb); - - /* Our usage of tstamp should remain private */ - skb->tstamp.tv64 = 0; - - /* Cleanup our debris for IP stacks */ - memset(skb->cb, 0, max(sizeof(struct inet_skb_parm), - sizeof(struct inet6_skb_parm))); - - err = icsk->icsk_af_ops->queue_xmit(sk, skb, &inet->cork.fl); - - if (likely(err <= 0)) - return err; - - tcp_enter_cwr(sk); - - return net_xmit_eval(err); -} - -/* This routine just queues the buffer for sending. - * - * NOTE: probe0 timer is not checked, do not forget tcp_push_pending_frames, - * otherwise socket can stall. - */ -static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - - /* Advance write_seq and place onto the write_queue. */ - tp->write_seq = TCP_SKB_CB(skb)->end_seq; - __skb_header_release(skb); - tcp_add_write_queue_tail(sk, skb); - sk->sk_wmem_queued += skb->truesize; - sk_mem_charge(sk, skb->truesize); -} - -/* Initialize TSO segments for a packet. */ -static void tcp_set_skb_tso_segs(struct sk_buff *skb, unsigned int mss_now) -{ - if (skb->len <= mss_now || skb->ip_summed == CHECKSUM_NONE) { - /* Avoid the costly divide in the normal - * non-TSO case. - */ - tcp_skb_pcount_set(skb, 1); - TCP_SKB_CB(skb)->tcp_gso_size = 0; - } else { - tcp_skb_pcount_set(skb, DIV_ROUND_UP(skb->len, mss_now)); - TCP_SKB_CB(skb)->tcp_gso_size = mss_now; - } -} - -/* When a modification to fackets out becomes necessary, we need to check - * skb is counted to fackets_out or not. - */ -static void tcp_adjust_fackets_out(struct sock *sk, const struct sk_buff *skb, - int decr) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (!tp->sacked_out || tcp_is_reno(tp)) - return; - - if (after(tcp_highest_sack_seq(tp), TCP_SKB_CB(skb)->seq)) - tp->fackets_out -= decr; -} - -/* Pcount in the middle of the write queue got changed, we need to do various - * tweaks to fix counters - */ -static void tcp_adjust_pcount(struct sock *sk, const struct sk_buff *skb, int decr) -{ - struct tcp_sock *tp = tcp_sk(sk); - - tp->packets_out -= decr; - - if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED) - tp->sacked_out -= decr; - if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) - tp->retrans_out -= decr; - if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) - tp->lost_out -= decr; - - /* Reno case is special. Sigh... */ - if (tcp_is_reno(tp) && decr > 0) - tp->sacked_out -= min_t(u32, tp->sacked_out, decr); - - tcp_adjust_fackets_out(sk, skb, decr); - - if (tp->lost_skb_hint && - before(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(tp->lost_skb_hint)->seq) && - (tcp_is_fack(tp) || (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED))) - tp->lost_cnt_hint -= decr; - - tcp_verify_left_out(tp); -} - -static bool tcp_has_tx_tstamp(const struct sk_buff *skb) -{ - return TCP_SKB_CB(skb)->txstamp_ack || - (skb_shinfo(skb)->tx_flags & SKBTX_ANY_TSTAMP); -} - -static void tcp_fragment_tstamp(struct sk_buff *skb, struct sk_buff *skb2) -{ - struct skb_shared_info *shinfo = skb_shinfo(skb); - - if (unlikely(tcp_has_tx_tstamp(skb)) && - !before(shinfo->tskey, TCP_SKB_CB(skb2)->seq)) { - struct skb_shared_info *shinfo2 = skb_shinfo(skb2); - u8 tsflags = shinfo->tx_flags & SKBTX_ANY_TSTAMP; - - shinfo->tx_flags &= ~tsflags; - shinfo2->tx_flags |= tsflags; - swap(shinfo->tskey, shinfo2->tskey); - TCP_SKB_CB(skb2)->txstamp_ack = TCP_SKB_CB(skb)->txstamp_ack; - TCP_SKB_CB(skb)->txstamp_ack = 0; - } -} - -static void tcp_skb_fragment_eor(struct sk_buff *skb, struct sk_buff *skb2) -{ - TCP_SKB_CB(skb2)->eor = TCP_SKB_CB(skb)->eor; - TCP_SKB_CB(skb)->eor = 0; -} - -/* Function to create two new TCP segments. Shrinks the given segment - * to the specified size and appends a new segment with the rest of the - * packet to the list. This won't be called frequently, I hope. - * Remember, these are still headerless SKBs at this point. - */ -int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, - unsigned int mss_now, gfp_t gfp) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *buff; - int nsize, old_factor; - int nlen; - u8 flags; - - if (WARN_ON(len > skb->len)) - return -EINVAL; - - nsize = skb_headlen(skb) - len; - if (nsize < 0) - nsize = 0; - - if (skb_unclone(skb, gfp)) - return -ENOMEM; - - /* Get a new skb... force flag on. */ - buff = sk_stream_alloc_skb(sk, nsize, gfp, true); - if (!buff) - return -ENOMEM; /* We'll just try again later. */ - - sk->sk_wmem_queued += buff->truesize; - sk_mem_charge(sk, buff->truesize); - nlen = skb->len - len - nsize; - buff->truesize += nlen; - skb->truesize -= nlen; - - /* Correct the sequence numbers. */ - TCP_SKB_CB(buff)->seq = TCP_SKB_CB(skb)->seq + len; - TCP_SKB_CB(buff)->end_seq = TCP_SKB_CB(skb)->end_seq; - TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq; - - /* PSH and FIN should only be set in the second packet. */ - flags = TCP_SKB_CB(skb)->tcp_flags; - TCP_SKB_CB(skb)->tcp_flags = flags & ~(TCPHDR_FIN | TCPHDR_PSH); - TCP_SKB_CB(buff)->tcp_flags = flags; - TCP_SKB_CB(buff)->sacked = TCP_SKB_CB(skb)->sacked; - tcp_skb_fragment_eor(skb, buff); - - if (!skb_shinfo(skb)->nr_frags && skb->ip_summed != CHECKSUM_PARTIAL) { - /* Copy and checksum data tail into the new buffer. */ - buff->csum = csum_partial_copy_nocheck(skb->data + len, - skb_put(buff, nsize), - nsize, 0); - - skb_trim(skb, len); - - skb->csum = csum_block_sub(skb->csum, buff->csum, len); - } else { - skb->ip_summed = CHECKSUM_PARTIAL; - skb_split(skb, buff, len); - } - - buff->ip_summed = skb->ip_summed; - - buff->tstamp = skb->tstamp; - tcp_fragment_tstamp(skb, buff); - - old_factor = tcp_skb_pcount(skb); - - /* Fix up tso_factor for both original and new SKB. */ - tcp_set_skb_tso_segs(skb, mss_now); - tcp_set_skb_tso_segs(buff, mss_now); - - /* Update delivered info for the new segment */ - TCP_SKB_CB(buff)->tx = TCP_SKB_CB(skb)->tx; - - /* If this packet has been sent out already, we must - * adjust the various packet counters. - */ - if (!before(tp->snd_nxt, TCP_SKB_CB(buff)->end_seq)) { - int diff = old_factor - tcp_skb_pcount(skb) - - tcp_skb_pcount(buff); - - if (diff) - tcp_adjust_pcount(sk, skb, diff); - } - - /* Link BUFF into the send queue. */ - __skb_header_release(buff); - tcp_insert_write_queue_after(skb, buff, sk); - - return 0; -} - -/* This is similar to __pskb_pull_head() (it will go to core/skbuff.c - * eventually). The difference is that pulled data not copied, but - * immediately discarded. - */ -static void __pskb_trim_head(struct sk_buff *skb, int len) -{ - struct skb_shared_info *shinfo; - int i, k, eat; - - eat = min_t(int, len, skb_headlen(skb)); - if (eat) { - __skb_pull(skb, eat); - len -= eat; - if (!len) - return; - } - eat = len; - k = 0; - shinfo = skb_shinfo(skb); - for (i = 0; i < shinfo->nr_frags; i++) { - int size = skb_frag_size(&shinfo->frags[i]); - - if (size <= eat) { - skb_frag_unref(skb, i); - eat -= size; - } else { - shinfo->frags[k] = shinfo->frags[i]; - if (eat) { - shinfo->frags[k].page_offset += eat; - skb_frag_size_sub(&shinfo->frags[k], eat); - eat = 0; - } - k++; - } - } - shinfo->nr_frags = k; - - skb_reset_tail_pointer(skb); - skb->data_len -= len; - skb->len = skb->data_len; -} - -/* Remove acked data from a packet in the transmit queue. */ -int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) -{ - if (skb_unclone(skb, GFP_ATOMIC)) - return -ENOMEM; - - __pskb_trim_head(skb, len); - - TCP_SKB_CB(skb)->seq += len; - skb->ip_summed = CHECKSUM_PARTIAL; - - skb->truesize -= len; - sk->sk_wmem_queued -= len; - sk_mem_uncharge(sk, len); - sock_set_flag(sk, SOCK_QUEUE_SHRUNK); - - /* Any change of skb->len requires recalculation of tso factor. */ - if (tcp_skb_pcount(skb) > 1) - tcp_set_skb_tso_segs(skb, tcp_skb_mss(skb)); - - return 0; -} - -/* Calculate MSS not accounting any TCP options. */ -static inline int __tcp_mtu_to_mss(struct sock *sk, int pmtu) -{ - const struct tcp_sock *tp = tcp_sk(sk); - const struct inet_connection_sock *icsk = inet_csk(sk); - int mss_now; - - /* Calculate base mss without TCP options: - It is MMS_S - sizeof(tcphdr) of rfc1122 - */ - mss_now = pmtu - icsk->icsk_af_ops->net_header_len - sizeof(struct tcphdr); - - /* IPv6 adds a frag_hdr in case RTAX_FEATURE_ALLFRAG is set */ - if (icsk->icsk_af_ops->net_frag_header_len) { - const struct dst_entry *dst = __sk_dst_get(sk); - - if (dst && dst_allfrag(dst)) - mss_now -= icsk->icsk_af_ops->net_frag_header_len; - } - - /* Clamp it (mss_clamp does not include tcp options) */ - if (mss_now > tp->rx_opt.mss_clamp) - mss_now = tp->rx_opt.mss_clamp; - - /* Now subtract optional transport overhead */ - mss_now -= icsk->icsk_ext_hdr_len; - - /* Then reserve room for full set of TCP options and 8 bytes of data */ - if (mss_now < 48) - mss_now = 48; - return mss_now; -} - -/* Calculate MSS. Not accounting for SACKs here. */ -int tcp_mtu_to_mss(struct sock *sk, int pmtu) -{ - /* Subtract TCP options size, not including SACKs */ - return __tcp_mtu_to_mss(sk, pmtu) - - (tcp_sk(sk)->tcp_header_len - sizeof(struct tcphdr)); -} - -/* Inverse of above */ -int tcp_mss_to_mtu(struct sock *sk, int mss) -{ - const struct tcp_sock *tp = tcp_sk(sk); - const struct inet_connection_sock *icsk = inet_csk(sk); - int mtu; - - mtu = mss + - tp->tcp_header_len + - icsk->icsk_ext_hdr_len + - icsk->icsk_af_ops->net_header_len; - - /* IPv6 adds a frag_hdr in case RTAX_FEATURE_ALLFRAG is set */ - if (icsk->icsk_af_ops->net_frag_header_len) { - const struct dst_entry *dst = __sk_dst_get(sk); - - if (dst && dst_allfrag(dst)) - mtu += icsk->icsk_af_ops->net_frag_header_len; - } - return mtu; -} -EXPORT_SYMBOL(tcp_mss_to_mtu); - -/* MTU probing init per socket */ -void tcp_mtup_init(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct inet_connection_sock *icsk = inet_csk(sk); - struct net *net = sock_net(sk); - - icsk->icsk_mtup.enabled = net->ipv4.sysctl_tcp_mtu_probing > 1; - icsk->icsk_mtup.search_high = tp->rx_opt.mss_clamp + sizeof(struct tcphdr) + - icsk->icsk_af_ops->net_header_len; - icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, net->ipv4.sysctl_tcp_base_mss); - icsk->icsk_mtup.probe_size = 0; - if (icsk->icsk_mtup.enabled) - icsk->icsk_mtup.probe_timestamp = tcp_time_stamp; -} -EXPORT_SYMBOL(tcp_mtup_init); - -/* This function synchronize snd mss to current pmtu/exthdr set. - - tp->rx_opt.user_mss is mss set by user by TCP_MAXSEG. It does NOT counts - for TCP options, but includes only bare TCP header. - - tp->rx_opt.mss_clamp is mss negotiated at connection setup. - It is minimum of user_mss and mss received with SYN. - It also does not include TCP options. - - inet_csk(sk)->icsk_pmtu_cookie is last pmtu, seen by this function. - - tp->mss_cache is current effective sending mss, including - all tcp options except for SACKs. It is evaluated, - taking into account current pmtu, but never exceeds - tp->rx_opt.mss_clamp. - - NOTE1. rfc1122 clearly states that advertised MSS - DOES NOT include either tcp or ip options. - - NOTE2. inet_csk(sk)->icsk_pmtu_cookie and tp->mss_cache - are READ ONLY outside this function. --ANK (980731) - */ -unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct inet_connection_sock *icsk = inet_csk(sk); - int mss_now; - - if (icsk->icsk_mtup.search_high > pmtu) - icsk->icsk_mtup.search_high = pmtu; - - mss_now = tcp_mtu_to_mss(sk, pmtu); - mss_now = tcp_bound_to_half_wnd(tp, mss_now); - - /* And store cached results */ - icsk->icsk_pmtu_cookie = pmtu; - if (icsk->icsk_mtup.enabled) - mss_now = min(mss_now, tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_low)); - tp->mss_cache = mss_now; - - return mss_now; -} -EXPORT_SYMBOL(tcp_sync_mss); - -/* Compute the current effective MSS, taking SACKs and IP options, - * and even PMTU discovery events into account. - */ -unsigned int tcp_current_mss(struct sock *sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - const struct dst_entry *dst = __sk_dst_get(sk); - u32 mss_now; - unsigned int header_len; - struct tcp_out_options opts; - struct tcp_md5sig_key *md5; - - mss_now = tp->mss_cache; - - if (dst) { - u32 mtu = dst_mtu(dst); - if (mtu != inet_csk(sk)->icsk_pmtu_cookie) - mss_now = tcp_sync_mss(sk, mtu); - } - - header_len = tcp_established_options(sk, NULL, &opts, &md5) + - sizeof(struct tcphdr); - /* The mss_cache is sized based on tp->tcp_header_len, which assumes - * some common options. If this is an odd packet (because we have SACK - * blocks etc) then our calculated header_len will be different, and - * we have to adjust mss_now correspondingly */ - if (header_len != tp->tcp_header_len) { - int delta = (int) header_len - tp->tcp_header_len; - mss_now -= delta; - } - - return mss_now; -} - -/* RFC2861, slow part. Adjust cwnd, after it was not full during one rto. - * As additional protections, we do not touch cwnd in retransmission phases, - * and if application hit its sndbuf limit recently. - */ -static void tcp_cwnd_application_limited(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (inet_csk(sk)->icsk_ca_state == TCP_CA_Open && - sk->sk_socket && !test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { - /* Limited by application or receiver window. */ - u32 init_win = tcp_init_cwnd(tp, __sk_dst_get(sk)); - u32 win_used = max(tp->snd_cwnd_used, init_win); - if (win_used < tp->snd_cwnd) { - tp->snd_ssthresh = tcp_current_ssthresh(sk); - tp->snd_cwnd = (tp->snd_cwnd + win_used) >> 1; - } - tp->snd_cwnd_used = 0; - } - tp->snd_cwnd_stamp = tcp_time_stamp; -} - -static void tcp_cwnd_validate(struct sock *sk, bool is_cwnd_limited) -{ - struct tcp_sock *tp = tcp_sk(sk); - - /* Track the maximum number of outstanding packets in each - * window, and remember whether we were cwnd-limited then. - */ - if (!before(tp->snd_una, tp->max_packets_seq) || - tp->packets_out > tp->max_packets_out) { - tp->max_packets_out = tp->packets_out; - tp->max_packets_seq = tp->snd_nxt; - tp->is_cwnd_limited = is_cwnd_limited; - } - - if (tcp_is_cwnd_limited(sk)) { - /* Network is feed fully. */ - tp->snd_cwnd_used = 0; - tp->snd_cwnd_stamp = tcp_time_stamp; - } else { - /* Network starves. */ - if (tp->packets_out > tp->snd_cwnd_used) - tp->snd_cwnd_used = tp->packets_out; - - if (sysctl_tcp_slow_start_after_idle && - (s32)(tcp_time_stamp - tp->snd_cwnd_stamp) >= inet_csk(sk)->icsk_rto) - tcp_cwnd_application_limited(sk); - } -} - -/* Minshall's variant of the Nagle send check. */ -static bool tcp_minshall_check(const struct tcp_sock *tp) -{ - return after(tp->snd_sml, tp->snd_una) && - !after(tp->snd_sml, tp->snd_nxt); -} - -/* Update snd_sml if this skb is under mss - * Note that a TSO packet might end with a sub-mss segment - * The test is really : - * if ((skb->len % mss) != 0) - * tp->snd_sml = TCP_SKB_CB(skb)->end_seq; - * But we can avoid doing the divide again given we already have - * skb_pcount = skb->len / mss_now - */ -static void tcp_minshall_update(struct tcp_sock *tp, unsigned int mss_now, - const struct sk_buff *skb) -{ - if (skb->len < tcp_skb_pcount(skb) * mss_now) - tp->snd_sml = TCP_SKB_CB(skb)->end_seq; -} - -/* Return false, if packet can be sent now without violation Nagle's rules: - * 1. It is full sized. (provided by caller in %partial bool) - * 2. Or it contains FIN. (already checked by caller) - * 3. Or TCP_CORK is not set, and TCP_NODELAY is set. - * 4. Or TCP_CORK is not set, and all sent packets are ACKed. - * With Minshall's modification: all sent small packets are ACKed. - */ -static bool tcp_nagle_check(bool partial, const struct tcp_sock *tp, - int nonagle) -{ - return partial && - ((nonagle & TCP_NAGLE_CORK) || - (!nonagle && tp->packets_out && tcp_minshall_check(tp))); -} - -/* Return how many segs we'd like on a TSO packet, - * to send one TSO packet per ms - */ -u32 tcp_tso_autosize(const struct sock *sk, unsigned int mss_now, - int min_tso_segs) -{ - u32 bytes, segs; - - bytes = min(sk->sk_pacing_rate >> 10, - sk->sk_gso_max_size - 1 - MAX_TCP_HEADER); - - /* Goal is to send at least one packet per ms, - * not one big TSO packet every 100 ms. - * This preserves ACK clocking and is consistent - * with tcp_tso_should_defer() heuristic. - */ - segs = max_t(u32, bytes / mss_now, min_tso_segs); - - return min_t(u32, segs, sk->sk_gso_max_segs); -} -EXPORT_SYMBOL(tcp_tso_autosize); - -/* Return the number of segments we want in the skb we are transmitting. - * See if congestion control module wants to decide; otherwise, autosize. - */ -static u32 tcp_tso_segs(struct sock *sk, unsigned int mss_now) -{ - const struct tcp_congestion_ops *ca_ops = inet_csk(sk)->icsk_ca_ops; - u32 tso_segs = ca_ops->tso_segs_goal ? ca_ops->tso_segs_goal(sk) : 0; - - return tso_segs ? : - tcp_tso_autosize(sk, mss_now, sysctl_tcp_min_tso_segs); -} - -/* Returns the portion of skb which can be sent right away */ -static unsigned int tcp_mss_split_point(const struct sock *sk, - const struct sk_buff *skb, - unsigned int mss_now, - unsigned int max_segs, - int nonagle) -{ - const struct tcp_sock *tp = tcp_sk(sk); - u32 partial, needed, window, max_len; - - window = tcp_wnd_end(tp) - TCP_SKB_CB(skb)->seq; - max_len = mss_now * max_segs; - - if (likely(max_len <= window && skb != tcp_write_queue_tail(sk))) - return max_len; - - needed = min(skb->len, window); - - if (max_len <= needed) - return max_len; - - partial = needed % mss_now; - /* If last segment is not a full MSS, check if Nagle rules allow us - * to include this last segment in this skb. - * Otherwise, we'll split the skb at last MSS boundary - */ - if (tcp_nagle_check(partial != 0, tp, nonagle)) - return needed - partial; - - return needed; -} - -/* Can at least one segment of SKB be sent right now, according to the - * congestion window rules? If so, return how many segments are allowed. - */ -static inline unsigned int tcp_cwnd_test(const struct tcp_sock *tp, - const struct sk_buff *skb) -{ - u32 in_flight, cwnd, halfcwnd; - - /* Don't be strict about the congestion window for the final FIN. */ - if ((TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) && - tcp_skb_pcount(skb) == 1) - return 1; - - in_flight = tcp_packets_in_flight(tp); - cwnd = tp->snd_cwnd; - if (in_flight >= cwnd) - return 0; - - /* For better scheduling, ensure we have at least - * 2 GSO packets in flight. - */ - halfcwnd = max(cwnd >> 1, 1U); - return min(halfcwnd, cwnd - in_flight); -} - -/* Initialize TSO state of a skb. - * This must be invoked the first time we consider transmitting - * SKB onto the wire. - */ -static int tcp_init_tso_segs(struct sk_buff *skb, unsigned int mss_now) -{ - int tso_segs = tcp_skb_pcount(skb); - - if (!tso_segs || (tso_segs > 1 && tcp_skb_mss(skb) != mss_now)) { - tcp_set_skb_tso_segs(skb, mss_now); - tso_segs = tcp_skb_pcount(skb); - } - return tso_segs; -} - - -/* Return true if the Nagle test allows this packet to be - * sent now. - */ -static inline bool tcp_nagle_test(const struct tcp_sock *tp, const struct sk_buff *skb, - unsigned int cur_mss, int nonagle) -{ - /* Nagle rule does not apply to frames, which sit in the middle of the - * write_queue (they have no chances to get new data). - * - * This is implemented in the callers, where they modify the 'nonagle' - * argument based upon the location of SKB in the send queue. - */ - if (nonagle & TCP_NAGLE_PUSH) - return true; - - /* Don't use the nagle rule for urgent data (or for the final FIN). */ - if (tcp_urg_mode(tp) || (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN)) - return true; - - if (!tcp_nagle_check(skb->len < cur_mss, tp, nonagle)) - return true; - - return false; -} - -/* Does at least the first segment of SKB fit into the send window? */ -static bool tcp_snd_wnd_test(const struct tcp_sock *tp, - const struct sk_buff *skb, - unsigned int cur_mss) -{ - u32 end_seq = TCP_SKB_CB(skb)->end_seq; - - if (skb->len > cur_mss) - end_seq = TCP_SKB_CB(skb)->seq + cur_mss; - - return !after(end_seq, tcp_wnd_end(tp)); -} - -/* This checks if the data bearing packet SKB (usually tcp_send_head(sk)) - * should be put on the wire right now. If so, it returns the number of - * packets allowed by the congestion window. - */ -static unsigned int tcp_snd_test(const struct sock *sk, struct sk_buff *skb, - unsigned int cur_mss, int nonagle) -{ - const struct tcp_sock *tp = tcp_sk(sk); - unsigned int cwnd_quota; - - tcp_init_tso_segs(skb, cur_mss); - - if (!tcp_nagle_test(tp, skb, cur_mss, nonagle)) - return 0; - - cwnd_quota = tcp_cwnd_test(tp, skb); - if (cwnd_quota && !tcp_snd_wnd_test(tp, skb, cur_mss)) - cwnd_quota = 0; - - return cwnd_quota; -} - -/* Test if sending is allowed right now. */ -bool tcp_may_send_now(struct sock *sk) -{ - const struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *skb = tcp_send_head(sk); - - return skb && - tcp_snd_test(sk, skb, tcp_current_mss(sk), - (tcp_skb_is_last(sk, skb) ? - tp->nonagle : TCP_NAGLE_PUSH)); -} - -/* Trim TSO SKB to LEN bytes, put the remaining data into a new packet - * which is put after SKB on the list. It is very much like - * tcp_fragment() except that it may make several kinds of assumptions - * in order to speed up the splitting operation. In particular, we - * know that all the data is in scatter-gather pages, and that the - * packet has never been sent out before (and thus is not cloned). - */ -static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len, - unsigned int mss_now, gfp_t gfp) -{ - struct sk_buff *buff; - int nlen = skb->len - len; - u8 flags; - - /* All of a TSO frame must be composed of paged data. */ - if (skb->len != skb->data_len) - return tcp_fragment(sk, skb, len, mss_now, gfp); - - buff = sk_stream_alloc_skb(sk, 0, gfp, true); - if (unlikely(!buff)) - return -ENOMEM; - - sk->sk_wmem_queued += buff->truesize; - sk_mem_charge(sk, buff->truesize); - buff->truesize += nlen; - skb->truesize -= nlen; - - /* Correct the sequence numbers. */ - TCP_SKB_CB(buff)->seq = TCP_SKB_CB(skb)->seq + len; - TCP_SKB_CB(buff)->end_seq = TCP_SKB_CB(skb)->end_seq; - TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq; - - /* PSH and FIN should only be set in the second packet. */ - flags = TCP_SKB_CB(skb)->tcp_flags; - TCP_SKB_CB(skb)->tcp_flags = flags & ~(TCPHDR_FIN | TCPHDR_PSH); - TCP_SKB_CB(buff)->tcp_flags = flags; - - /* This packet was never sent out yet, so no SACK bits. */ - TCP_SKB_CB(buff)->sacked = 0; - - tcp_skb_fragment_eor(skb, buff); - - buff->ip_summed = skb->ip_summed = CHECKSUM_PARTIAL; - skb_split(skb, buff, len); - tcp_fragment_tstamp(skb, buff); - - /* Fix up tso_factor for both original and new SKB. */ - tcp_set_skb_tso_segs(skb, mss_now); - tcp_set_skb_tso_segs(buff, mss_now); - - /* Link BUFF into the send queue. */ - __skb_header_release(buff); - tcp_insert_write_queue_after(skb, buff, sk); - - return 0; -} - -/* Try to defer sending, if possible, in order to minimize the amount - * of TSO splitting we do. View it as a kind of TSO Nagle test. - * - * This algorithm is from John Heffner. - */ -static bool tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb, - bool *is_cwnd_limited, u32 max_segs) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - u32 age, send_win, cong_win, limit, in_flight; - struct tcp_sock *tp = tcp_sk(sk); - struct skb_mstamp now; - struct sk_buff *head; - int win_divisor; - - if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) - goto send_now; - - if (icsk->icsk_ca_state >= TCP_CA_Recovery) - goto send_now; - - /* Avoid bursty behavior by allowing defer - * only if the last write was recent. - */ - if ((s32)(tcp_time_stamp - tp->lsndtime) > 0) - goto send_now; - - in_flight = tcp_packets_in_flight(tp); - - BUG_ON(tcp_skb_pcount(skb) <= 1 || (tp->snd_cwnd <= in_flight)); - - send_win = tcp_wnd_end(tp) - TCP_SKB_CB(skb)->seq; - - /* From in_flight test above, we know that cwnd > in_flight. */ - cong_win = (tp->snd_cwnd - in_flight) * tp->mss_cache; - - limit = min(send_win, cong_win); - - /* If a full-sized TSO skb can be sent, do it. */ - if (limit >= max_segs * tp->mss_cache) - goto send_now; - - /* Middle in queue won't get any more data, full sendable already? */ - if ((skb != tcp_write_queue_tail(sk)) && (limit >= skb->len)) - goto send_now; - - win_divisor = ACCESS_ONCE(sysctl_tcp_tso_win_divisor); - if (win_divisor) { - u32 chunk = min(tp->snd_wnd, tp->snd_cwnd * tp->mss_cache); - - /* If at least some fraction of a window is available, - * just use it. - */ - chunk /= win_divisor; - if (limit >= chunk) - goto send_now; - } else { - /* Different approach, try not to defer past a single - * ACK. Receiver should ACK every other full sized - * frame, so if we have space for more than 3 frames - * then send now. - */ - if (limit > tcp_max_tso_deferred_mss(tp) * tp->mss_cache) - goto send_now; - } - - head = tcp_write_queue_head(sk); - skb_mstamp_get(&now); - age = skb_mstamp_us_delta(&now, &head->skb_mstamp); - /* If next ACK is likely to come too late (half srtt), do not defer */ - if (age < (tp->srtt_us >> 4)) - goto send_now; - - /* Ok, it looks like it is advisable to defer. */ - - if (cong_win < send_win && cong_win <= skb->len) - *is_cwnd_limited = true; - - return true; - -send_now: - return false; -} - -static inline void tcp_mtu_check_reprobe(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - struct net *net = sock_net(sk); - u32 interval; - s32 delta; - - interval = net->ipv4.sysctl_tcp_probe_interval; - delta = tcp_time_stamp - icsk->icsk_mtup.probe_timestamp; - if (unlikely(delta >= interval * HZ)) { - int mss = tcp_current_mss(sk); - - /* Update current search range */ - icsk->icsk_mtup.probe_size = 0; - icsk->icsk_mtup.search_high = tp->rx_opt.mss_clamp + - sizeof(struct tcphdr) + - icsk->icsk_af_ops->net_header_len; - icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, mss); - - /* Update probe time stamp */ - icsk->icsk_mtup.probe_timestamp = tcp_time_stamp; - } -} - -/* Create a new MTU probe if we are ready. - * MTU probe is regularly attempting to increase the path MTU by - * deliberately sending larger packets. This discovers routing - * changes resulting in larger path MTUs. - * - * Returns 0 if we should wait to probe (no cwnd available), - * 1 if a probe was sent, - * -1 otherwise - */ -static int tcp_mtu_probe(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct inet_connection_sock *icsk = inet_csk(sk); - struct sk_buff *skb, *nskb, *next; - struct net *net = sock_net(sk); - int len; - int probe_size; - int size_needed; - int copy; - int mss_now; - int interval; - - /* Not currently probing/verifying, - * not in recovery, - * have enough cwnd, and - * not SACKing (the variable headers throw things off) */ - if (!icsk->icsk_mtup.enabled || - icsk->icsk_mtup.probe_size || - inet_csk(sk)->icsk_ca_state != TCP_CA_Open || - tp->snd_cwnd < 11 || - tp->rx_opt.num_sacks || tp->rx_opt.dsack) - return -1; - - /* Use binary search for probe_size between tcp_mss_base, - * and current mss_clamp. if (search_high - search_low) - * smaller than a threshold, backoff from probing. - */ - mss_now = tcp_current_mss(sk); - probe_size = tcp_mtu_to_mss(sk, (icsk->icsk_mtup.search_high + - icsk->icsk_mtup.search_low) >> 1); - size_needed = probe_size + (tp->reordering + 1) * tp->mss_cache; - interval = icsk->icsk_mtup.search_high - icsk->icsk_mtup.search_low; - /* When misfortune happens, we are reprobing actively, - * and then reprobe timer has expired. We stick with current - * probing process by not resetting search range to its orignal. - */ - if (probe_size > tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_high) || - interval < net->ipv4.sysctl_tcp_probe_threshold) { - /* Check whether enough time has elaplased for - * another round of probing. - */ - tcp_mtu_check_reprobe(sk); - return -1; - } - - /* Have enough data in the send queue to probe? */ - if (tp->write_seq - tp->snd_nxt < size_needed) - return -1; - - if (tp->snd_wnd < size_needed) - return -1; - if (after(tp->snd_nxt + size_needed, tcp_wnd_end(tp))) - return 0; - - /* Do we need to wait to drain cwnd? With none in flight, don't stall */ - if (tcp_packets_in_flight(tp) + 2 > tp->snd_cwnd) { - if (!tcp_packets_in_flight(tp)) - return -1; - else - return 0; - } - - /* We're allowed to probe. Build it now. */ - nskb = sk_stream_alloc_skb(sk, probe_size, GFP_ATOMIC, false); - if (!nskb) - return -1; - sk->sk_wmem_queued += nskb->truesize; - sk_mem_charge(sk, nskb->truesize); - - skb = tcp_send_head(sk); - - TCP_SKB_CB(nskb)->seq = TCP_SKB_CB(skb)->seq; - TCP_SKB_CB(nskb)->end_seq = TCP_SKB_CB(skb)->seq + probe_size; - TCP_SKB_CB(nskb)->tcp_flags = TCPHDR_ACK; - TCP_SKB_CB(nskb)->sacked = 0; - nskb->csum = 0; - nskb->ip_summed = skb->ip_summed; - - tcp_insert_write_queue_before(nskb, skb, sk); - - len = 0; - tcp_for_write_queue_from_safe(skb, next, sk) { - copy = min_t(int, skb->len, probe_size - len); - if (nskb->ip_summed) { - skb_copy_bits(skb, 0, skb_put(nskb, copy), copy); - } else { - __wsum csum = skb_copy_and_csum_bits(skb, 0, - skb_put(nskb, copy), - copy, 0); - nskb->csum = csum_block_add(nskb->csum, csum, len); - } - - if (skb->len <= copy) { - /* We've eaten all the data from this skb. - * Throw it away. */ - TCP_SKB_CB(nskb)->tcp_flags |= TCP_SKB_CB(skb)->tcp_flags; - tcp_unlink_write_queue(skb, sk); - sk_wmem_free_skb(sk, skb); - } else { - TCP_SKB_CB(nskb)->tcp_flags |= TCP_SKB_CB(skb)->tcp_flags & - ~(TCPHDR_FIN|TCPHDR_PSH); - if (!skb_shinfo(skb)->nr_frags) { - skb_pull(skb, copy); - if (skb->ip_summed != CHECKSUM_PARTIAL) - skb->csum = csum_partial(skb->data, - skb->len, 0); - } else { - __pskb_trim_head(skb, copy); - tcp_set_skb_tso_segs(skb, mss_now); - } - TCP_SKB_CB(skb)->seq += copy; - } - - len += copy; - - if (len >= probe_size) - break; - } - tcp_init_tso_segs(nskb, nskb->len); - - /* We're ready to send. If this fails, the probe will - * be resegmented into mss-sized pieces by tcp_write_xmit(). - */ - if (!tcp_transmit_skb(sk, nskb, 1, GFP_ATOMIC)) { - /* Decrement cwnd here because we are sending - * effectively two packets. */ - tp->snd_cwnd--; - tcp_event_new_data_sent(sk, nskb); - - icsk->icsk_mtup.probe_size = tcp_mss_to_mtu(sk, nskb->len); - tp->mtu_probe.probe_seq_start = TCP_SKB_CB(nskb)->seq; - tp->mtu_probe.probe_seq_end = TCP_SKB_CB(nskb)->end_seq; - - return 1; - } - - return -1; -} - -/* TCP Small Queues : - * Control number of packets in qdisc/devices to two packets / or ~1 ms. - * (These limits are doubled for retransmits) - * This allows for : - * - better RTT estimation and ACK scheduling - * - faster recovery - * - high rates - * Alas, some drivers / subsystems require a fair amount - * of queued bytes to ensure line rate. - * One example is wifi aggregation (802.11 AMPDU) - */ -static bool tcp_small_queue_check(struct sock *sk, const struct sk_buff *skb, - unsigned int factor) -{ - unsigned int limit; - - limit = max(2 * skb->truesize, sk->sk_pacing_rate >> 10); - limit = min_t(u32, limit, sysctl_tcp_limit_output_bytes); - limit <<= factor; - - if (atomic_read(&sk->sk_wmem_alloc) > limit) { - set_bit(TSQ_THROTTLED, &tcp_sk(sk)->tsq_flags); - /* It is possible TX completion already happened - * before we set TSQ_THROTTLED, so we must - * test again the condition. - */ - smp_mb__after_atomic(); - if (atomic_read(&sk->sk_wmem_alloc) > limit) - return true; - } - return false; -} - -/* This routine writes packets to the network. It advances the - * send_head. This happens as incoming acks open up the remote - * window for us. - * - * LARGESEND note: !tcp_urg_mode is overkill, only frames between - * snd_up-64k-mss .. snd_up cannot be large. However, taking into - * account rare use of URG, this is not a big flaw. - * - * Send at most one packet when push_one > 0. Temporarily ignore - * cwnd limit to force at most one packet out when push_one == 2. - - * Returns true, if no segments are in flight and we have queued segments, - * but cannot send anything now because of SWS or another problem. - */ -static bool tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, - int push_one, gfp_t gfp) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *skb; - unsigned int tso_segs, sent_pkts; - int cwnd_quota; - int result; - bool is_cwnd_limited = false; - u32 max_segs; - - sent_pkts = 0; - - if (!push_one) { - /* Do MTU probing. */ - result = tcp_mtu_probe(sk); - if (!result) { - return false; - } else if (result > 0) { - sent_pkts = 1; - } - } - - max_segs = tcp_tso_segs(sk, mss_now); - while ((skb = tcp_send_head(sk))) { - unsigned int limit; - - tso_segs = tcp_init_tso_segs(skb, mss_now); - BUG_ON(!tso_segs); - - if (unlikely(tp->repair) && tp->repair_queue == TCP_SEND_QUEUE) { - /* "skb_mstamp" is used as a start point for the retransmit timer */ - skb_mstamp_get(&skb->skb_mstamp); - goto repair; /* Skip network transmission */ - } - - cwnd_quota = tcp_cwnd_test(tp, skb); - if (!cwnd_quota) { - if (push_one == 2) - /* Force out a loss probe pkt. */ - cwnd_quota = 1; - else - break; - } - - if (unlikely(!tcp_snd_wnd_test(tp, skb, mss_now))) - break; - - if (tso_segs == 1) { - if (unlikely(!tcp_nagle_test(tp, skb, mss_now, - (tcp_skb_is_last(sk, skb) ? - nonagle : TCP_NAGLE_PUSH)))) - break; - } else { - if (!push_one && - tcp_tso_should_defer(sk, skb, &is_cwnd_limited, - max_segs)) - break; - } - - limit = mss_now; - if (tso_segs > 1 && !tcp_urg_mode(tp)) - limit = tcp_mss_split_point(sk, skb, mss_now, - min_t(unsigned int, - cwnd_quota, - max_segs), - nonagle); - - if (skb->len > limit && - unlikely(tso_fragment(sk, skb, limit, mss_now, gfp))) - break; - - if (tcp_small_queue_check(sk, skb, 0)) - break; - - if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp))) - break; - -repair: - /* Advance the send_head. This one is sent out. - * This call will increment packets_out. - */ - tcp_event_new_data_sent(sk, skb); - - tcp_minshall_update(tp, mss_now, skb); - sent_pkts += tcp_skb_pcount(skb); - - if (push_one) - break; - } - - if (likely(sent_pkts)) { - if (tcp_in_cwnd_reduction(sk)) - tp->prr_out += sent_pkts; - - /* Send one loss probe per tail loss episode. */ - if (push_one != 2) - tcp_schedule_loss_probe(sk); - is_cwnd_limited |= (tcp_packets_in_flight(tp) >= tp->snd_cwnd); - tcp_cwnd_validate(sk, is_cwnd_limited); - return false; - } - return !tp->packets_out && tcp_send_head(sk); -} - -bool tcp_schedule_loss_probe(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - u32 timeout, tlp_time_stamp, rto_time_stamp; - u32 rtt = usecs_to_jiffies(tp->srtt_us >> 3); - - if (WARN_ON(icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS)) - return false; - /* No consecutive loss probes. */ - if (WARN_ON(icsk->icsk_pending == ICSK_TIME_LOSS_PROBE)) { - tcp_rearm_rto(sk); - return false; - } - /* Don't do any loss probe on a Fast Open connection before 3WHS - * finishes. - */ - if (tp->fastopen_rsk) - return false; - - /* TLP is only scheduled when next timer event is RTO. */ - if (icsk->icsk_pending != ICSK_TIME_RETRANS) - return false; - - /* Schedule a loss probe in 2*RTT for SACK capable connections - * in Open state, that are either limited by cwnd or application. - */ - if (sysctl_tcp_early_retrans < 3 || !tp->packets_out || - !tcp_is_sack(tp) || inet_csk(sk)->icsk_ca_state != TCP_CA_Open) - return false; - - if ((tp->snd_cwnd > tcp_packets_in_flight(tp)) && - tcp_send_head(sk)) - return false; - - /* Probe timeout is at least 1.5*rtt + TCP_DELACK_MAX to account - * for delayed ack when there's one outstanding packet. If no RTT - * sample is available then probe after TCP_TIMEOUT_INIT. - */ - timeout = rtt << 1 ? : TCP_TIMEOUT_INIT; - if (tp->packets_out == 1) - timeout = max_t(u32, timeout, - (rtt + (rtt >> 1) + TCP_DELACK_MAX)); - timeout = max_t(u32, timeout, msecs_to_jiffies(10)); - - /* If RTO is shorter, just schedule TLP in its place. */ - tlp_time_stamp = tcp_time_stamp + timeout; - rto_time_stamp = (u32)inet_csk(sk)->icsk_timeout; - if ((s32)(tlp_time_stamp - rto_time_stamp) > 0) { - s32 delta = rto_time_stamp - tcp_time_stamp; - if (delta > 0) - timeout = delta; - } - - inet_csk_reset_xmit_timer(sk, ICSK_TIME_LOSS_PROBE, timeout, - TCP_RTO_MAX); - return true; -} - -/* Thanks to skb fast clones, we can detect if a prior transmit of - * a packet is still in a qdisc or driver queue. - * In this case, there is very little point doing a retransmit ! - */ -static bool skb_still_in_host_queue(const struct sock *sk, - const struct sk_buff *skb) -{ - if (unlikely(skb_fclone_busy(sk, skb))) { - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPSPURIOUS_RTX_HOSTQUEUES); - return true; - } - return false; -} - -/* When probe timeout (PTO) fires, try send a new segment if possible, else - * retransmit the last segment. - */ -void tcp_send_loss_probe(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *skb; - int pcount; - int mss = tcp_current_mss(sk); - - skb = tcp_send_head(sk); - if (skb) { - if (tcp_snd_wnd_test(tp, skb, mss)) { - pcount = tp->packets_out; - tcp_write_xmit(sk, mss, TCP_NAGLE_OFF, 2, GFP_ATOMIC); - if (tp->packets_out > pcount) - goto probe_sent; - goto rearm_timer; - } - skb = tcp_write_queue_prev(sk, skb); - } else { - skb = tcp_write_queue_tail(sk); - } - - /* At most one outstanding TLP retransmission. */ - if (tp->tlp_high_seq) - goto rearm_timer; - - /* Retransmit last segment. */ - if (WARN_ON(!skb)) - goto rearm_timer; - - if (skb_still_in_host_queue(sk, skb)) - goto rearm_timer; - - pcount = tcp_skb_pcount(skb); - if (WARN_ON(!pcount)) - goto rearm_timer; - - if ((pcount > 1) && (skb->len > (pcount - 1) * mss)) { - if (unlikely(tcp_fragment(sk, skb, (pcount - 1) * mss, mss, - GFP_ATOMIC))) - goto rearm_timer; - skb = tcp_write_queue_next(sk, skb); - } - - if (WARN_ON(!skb || !tcp_skb_pcount(skb))) - goto rearm_timer; - - if (__tcp_retransmit_skb(sk, skb, 1)) - goto rearm_timer; - - /* Record snd_nxt for loss detection. */ - tp->tlp_high_seq = tp->snd_nxt; - -probe_sent: - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPLOSSPROBES); - /* Reset s.t. tcp_rearm_rto will restart timer from now */ - inet_csk(sk)->icsk_pending = 0; -rearm_timer: - tcp_rearm_rto(sk); -} - -/* Push out any pending frames which were held back due to - * TCP_CORK or attempt at coalescing tiny packets. - * The socket must be locked by the caller. - */ -void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss, - int nonagle) -{ - /* If we are closed, the bytes will have to remain here. - * In time closedown will finish, we empty the write queue and - * all will be happy. - */ - if (unlikely(sk->sk_state == TCP_CLOSE)) - return; - - if (tcp_write_xmit(sk, cur_mss, nonagle, 0, - sk_gfp_mask(sk, GFP_ATOMIC))) - tcp_check_probe_timer(sk); -} - -/* Send _single_ skb sitting at the send head. This function requires - * true push pending frames to setup probe timer etc. - */ -void tcp_push_one(struct sock *sk, unsigned int mss_now) -{ - struct sk_buff *skb = tcp_send_head(sk); - - BUG_ON(!skb || skb->len < mss_now); - - tcp_write_xmit(sk, mss_now, TCP_NAGLE_PUSH, 1, sk->sk_allocation); -} - -/* This function returns the amount that we can raise the - * usable window based on the following constraints - * - * 1. The window can never be shrunk once it is offered (RFC 793) - * 2. We limit memory per socket - * - * RFC 1122: - * "the suggested [SWS] avoidance algorithm for the receiver is to keep - * RECV.NEXT + RCV.WIN fixed until: - * RCV.BUFF - RCV.USER - RCV.WINDOW >= min(1/2 RCV.BUFF, MSS)" - * - * i.e. don't raise the right edge of the window until you can raise - * it at least MSS bytes. - * - * Unfortunately, the recommended algorithm breaks header prediction, - * since header prediction assumes th->window stays fixed. - * - * Strictly speaking, keeping th->window fixed violates the receiver - * side SWS prevention criteria. The problem is that under this rule - * a stream of single byte packets will cause the right side of the - * window to always advance by a single byte. - * - * Of course, if the sender implements sender side SWS prevention - * then this will not be a problem. - * - * BSD seems to make the following compromise: - * - * If the free space is less than the 1/4 of the maximum - * space available and the free space is less than 1/2 mss, - * then set the window to 0. - * [ Actually, bsd uses MSS and 1/4 of maximal _window_ ] - * Otherwise, just prevent the window from shrinking - * and from being larger than the largest representable value. - * - * This prevents incremental opening of the window in the regime - * where TCP is limited by the speed of the reader side taking - * data out of the TCP receive queue. It does nothing about - * those cases where the window is constrained on the sender side - * because the pipeline is full. - * - * BSD also seems to "accidentally" limit itself to windows that are a - * multiple of MSS, at least until the free space gets quite small. - * This would appear to be a side effect of the mbuf implementation. - * Combining these two algorithms results in the observed behavior - * of having a fixed window size at almost all times. - * - * Below we obtain similar behavior by forcing the offered window to - * a multiple of the mss when it is feasible to do so. - * - * Note, we don't "adjust" for TIMESTAMP or SACK option bytes. - * Regular options like TIMESTAMP are taken into account. - */ -u32 __tcp_select_window(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - /* MSS for the peer's data. Previous versions used mss_clamp - * here. I don't know if the value based on our guesses - * of peer's MSS is better for the performance. It's more correct - * but may be worse for the performance because of rcv_mss - * fluctuations. --SAW 1998/11/1 - */ - int mss = icsk->icsk_ack.rcv_mss; - int free_space = tcp_space(sk); - int allowed_space = tcp_full_space(sk); - int full_space = min_t(int, tp->window_clamp, allowed_space); - int window; - - if (mss > full_space) - mss = full_space; - - if (free_space < (full_space >> 1)) { - icsk->icsk_ack.quick = 0; - - if (tcp_under_memory_pressure(sk)) - tp->rcv_ssthresh = min(tp->rcv_ssthresh, - 4U * tp->advmss); - - /* free_space might become our new window, make sure we don't - * increase it due to wscale. - */ - free_space = round_down(free_space, 1 << tp->rx_opt.rcv_wscale); - - /* if free space is less than mss estimate, or is below 1/16th - * of the maximum allowed, try to move to zero-window, else - * tcp_clamp_window() will grow rcv buf up to tcp_rmem[2], and - * new incoming data is dropped due to memory limits. - * With large window, mss test triggers way too late in order - * to announce zero window in time before rmem limit kicks in. - */ - if (free_space < (allowed_space >> 4) || free_space < mss) - return 0; - } - - if (free_space > tp->rcv_ssthresh) - free_space = tp->rcv_ssthresh; - - /* Don't do rounding if we are using window scaling, since the - * scaled window will not line up with the MSS boundary anyway. - */ - window = tp->rcv_wnd; - if (tp->rx_opt.rcv_wscale) { - window = free_space; - - /* Advertise enough space so that it won't get scaled away. - * Import case: prevent zero window announcement if - * 1< mss. - */ - if (((window >> tp->rx_opt.rcv_wscale) << tp->rx_opt.rcv_wscale) != window) - window = (((window >> tp->rx_opt.rcv_wscale) + 1) - << tp->rx_opt.rcv_wscale); - } else { - /* Get the largest window that is a nice multiple of mss. - * Window clamp already applied above. - * If our current window offering is within 1 mss of the - * free space we just keep it. This prevents the divide - * and multiply from happening most of the time. - * We also don't do any window rounding when the free space - * is too small. - */ - if (window <= free_space - mss || window > free_space) - window = (free_space / mss) * mss; - else if (mss == full_space && - free_space > window + (full_space >> 1)) - window = free_space; - } - - return window; -} - -void tcp_skb_collapse_tstamp(struct sk_buff *skb, - const struct sk_buff *next_skb) -{ - if (unlikely(tcp_has_tx_tstamp(next_skb))) { - const struct skb_shared_info *next_shinfo = - skb_shinfo(next_skb); - struct skb_shared_info *shinfo = skb_shinfo(skb); - - shinfo->tx_flags |= next_shinfo->tx_flags & SKBTX_ANY_TSTAMP; - shinfo->tskey = next_shinfo->tskey; - TCP_SKB_CB(skb)->txstamp_ack |= - TCP_SKB_CB(next_skb)->txstamp_ack; - } -} - -/* Collapses two adjacent SKB's during retransmission. */ -static void tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *next_skb = tcp_write_queue_next(sk, skb); - int skb_size, next_skb_size; - - skb_size = skb->len; - next_skb_size = next_skb->len; - - BUG_ON(tcp_skb_pcount(skb) != 1 || tcp_skb_pcount(next_skb) != 1); - - tcp_highest_sack_combine(sk, next_skb, skb); - - tcp_unlink_write_queue(next_skb, sk); - - skb_copy_from_linear_data(next_skb, skb_put(skb, next_skb_size), - next_skb_size); - - if (next_skb->ip_summed == CHECKSUM_PARTIAL) - skb->ip_summed = CHECKSUM_PARTIAL; - - if (skb->ip_summed != CHECKSUM_PARTIAL) - skb->csum = csum_block_add(skb->csum, next_skb->csum, skb_size); - - /* Update sequence range on original skb. */ - TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(next_skb)->end_seq; - - /* Merge over control information. This moves PSH/FIN etc. over */ - TCP_SKB_CB(skb)->tcp_flags |= TCP_SKB_CB(next_skb)->tcp_flags; - - /* All done, get rid of second SKB and account for it so - * packet counting does not break. - */ - TCP_SKB_CB(skb)->sacked |= TCP_SKB_CB(next_skb)->sacked & TCPCB_EVER_RETRANS; - TCP_SKB_CB(skb)->eor = TCP_SKB_CB(next_skb)->eor; - - /* changed transmit queue under us so clear hints */ - tcp_clear_retrans_hints_partial(tp); - if (next_skb == tp->retransmit_skb_hint) - tp->retransmit_skb_hint = skb; - - tcp_adjust_pcount(sk, next_skb, tcp_skb_pcount(next_skb)); - - tcp_skb_collapse_tstamp(skb, next_skb); - - sk_wmem_free_skb(sk, next_skb); -} - -/* Check if coalescing SKBs is legal. */ -static bool tcp_can_collapse(const struct sock *sk, const struct sk_buff *skb) -{ - if (tcp_skb_pcount(skb) > 1) - return false; - /* TODO: SACK collapsing could be used to remove this condition */ - if (skb_shinfo(skb)->nr_frags != 0) - return false; - if (skb_cloned(skb)) - return false; - if (skb == tcp_send_head(sk)) - return false; - /* Some heurestics for collapsing over SACK'd could be invented */ - if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED) - return false; - - return true; -} - -/* Collapse packets in the retransmit queue to make to create - * less packets on the wire. This is only done on retransmission. - */ -static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to, - int space) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *skb = to, *tmp; - bool first = true; - - if (!sysctl_tcp_retrans_collapse) - return; - if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN) - return; - - tcp_for_write_queue_from_safe(skb, tmp, sk) { - if (!tcp_can_collapse(sk, skb)) - break; - - if (!tcp_skb_can_collapse_to(to)) - break; - - space -= skb->len; - - if (first) { - first = false; - continue; - } - - if (space < 0) - break; - /* Punt if not enough space exists in the first SKB for - * the data in the second - */ - if (skb->len > skb_availroom(to)) - break; - - if (after(TCP_SKB_CB(skb)->end_seq, tcp_wnd_end(tp))) - break; - - tcp_collapse_retrans(sk, to); - } -} - -/* This retransmits one SKB. Policy decisions and retransmit queue - * state updates are done by the caller. Returns non-zero if an - * error occurred which prevented the send. - */ -int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - unsigned int cur_mss; - int diff, len, err; - - - /* Inconclusive MTU probe */ - if (icsk->icsk_mtup.probe_size) - icsk->icsk_mtup.probe_size = 0; - - /* Do not sent more than we queued. 1/4 is reserved for possible - * copying overhead: fragmentation, tunneling, mangling etc. - */ - if (atomic_read(&sk->sk_wmem_alloc) > - min_t(u32, sk->sk_wmem_queued + (sk->sk_wmem_queued >> 2), - sk->sk_sndbuf)) - return -EAGAIN; - - if (skb_still_in_host_queue(sk, skb)) - return -EBUSY; - - if (before(TCP_SKB_CB(skb)->seq, tp->snd_una)) { - if (before(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) - BUG(); - if (tcp_trim_head(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq)) - return -ENOMEM; - } - - if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk)) - return -EHOSTUNREACH; /* Routing failure or similar. */ - - cur_mss = tcp_current_mss(sk); - - /* If receiver has shrunk his window, and skb is out of - * new window, do not retransmit it. The exception is the - * case, when window is shrunk to zero. In this case - * our retransmit serves as a zero window probe. - */ - if (!before(TCP_SKB_CB(skb)->seq, tcp_wnd_end(tp)) && - TCP_SKB_CB(skb)->seq != tp->snd_una) - return -EAGAIN; - - len = cur_mss * segs; - if (skb->len > len) { - if (tcp_fragment(sk, skb, len, cur_mss, GFP_ATOMIC)) - return -ENOMEM; /* We'll try again later. */ - } else { - if (skb_unclone(skb, GFP_ATOMIC)) - return -ENOMEM; - - diff = tcp_skb_pcount(skb); - tcp_set_skb_tso_segs(skb, cur_mss); - diff -= tcp_skb_pcount(skb); - if (diff) - tcp_adjust_pcount(sk, skb, diff); - if (skb->len < cur_mss) - tcp_retrans_try_collapse(sk, skb, cur_mss); - } - - /* RFC3168, section 6.1.1.1. ECN fallback */ - if ((TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN_ECN) == TCPHDR_SYN_ECN) - tcp_ecn_clear_syn(sk, skb); - - /* make sure skb->data is aligned on arches that require it - * and check if ack-trimming & collapsing extended the headroom - * beyond what csum_start can cover. - */ - if (unlikely((NET_IP_ALIGN && ((unsigned long)skb->data & 3)) || - skb_headroom(skb) >= 0xFFFF)) { - struct sk_buff *nskb; - - skb_mstamp_get(&skb->skb_mstamp); - nskb = __pskb_copy(skb, MAX_TCP_HEADER, GFP_ATOMIC); - err = nskb ? tcp_transmit_skb(sk, nskb, 0, GFP_ATOMIC) : - -ENOBUFS; - } else { - err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC); - } - - if (likely(!err)) { - segs = tcp_skb_pcount(skb); - - TCP_SKB_CB(skb)->sacked |= TCPCB_EVER_RETRANS; - /* Update global TCP statistics. */ - TCP_ADD_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS, segs); - if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN) - __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); - tp->total_retrans += segs; - } - return err; -} - -int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs) -{ - struct tcp_sock *tp = tcp_sk(sk); - int err = __tcp_retransmit_skb(sk, skb, segs); - - if (err == 0) { -#if FASTRETRANS_DEBUG > 0 - if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) { - net_dbg_ratelimited("retrans_out leaked\n"); - } -#endif - TCP_SKB_CB(skb)->sacked |= TCPCB_RETRANS; - tp->retrans_out += tcp_skb_pcount(skb); - - /* Save stamp of the first retransmit. */ - if (!tp->retrans_stamp) - tp->retrans_stamp = tcp_skb_timestamp(skb); - - } else if (err != -EBUSY) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPRETRANSFAIL); - } - - if (tp->undo_retrans < 0) - tp->undo_retrans = 0; - tp->undo_retrans += tcp_skb_pcount(skb); - return err; -} - -/* Check if we forward retransmits are possible in the current - * window/congestion state. - */ -static bool tcp_can_forward_retransmit(struct sock *sk) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - const struct tcp_sock *tp = tcp_sk(sk); - - /* Forward retransmissions are possible only during Recovery. */ - if (icsk->icsk_ca_state != TCP_CA_Recovery) - return false; - - /* No forward retransmissions in Reno are possible. */ - if (tcp_is_reno(tp)) - return false; - - /* Yeah, we have to make difficult choice between forward transmission - * and retransmission... Both ways have their merits... - * - * For now we do not retransmit anything, while we have some new - * segments to send. In the other cases, follow rule 3 for - * NextSeg() specified in RFC3517. - */ - - if (tcp_may_send_now(sk)) - return false; - - return true; -} - -/* This gets called after a retransmit timeout, and the initially - * retransmitted data is acknowledged. It tries to continue - * resending the rest of the retransmit queue, until either - * we've sent it all or the congestion window limit is reached. - * If doing SACK, the first ACK which comes back for a timeout - * based retransmit packet might feed us FACK information again. - * If so, we use it to avoid unnecessarily retransmissions. - */ -void tcp_xmit_retransmit_queue(struct sock *sk) -{ - const struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *skb; - struct sk_buff *hole = NULL; - u32 max_segs, last_lost; - int mib_idx; - int fwd_rexmitting = 0; - - if (!tp->packets_out) - return; - - if (!tp->lost_out) - tp->retransmit_high = tp->snd_una; - - if (tp->retransmit_skb_hint) { - skb = tp->retransmit_skb_hint; - last_lost = TCP_SKB_CB(skb)->end_seq; - if (after(last_lost, tp->retransmit_high)) - last_lost = tp->retransmit_high; - } else { - skb = tcp_write_queue_head(sk); - last_lost = tp->snd_una; - } - - max_segs = tcp_tso_segs(sk, tcp_current_mss(sk)); - tcp_for_write_queue_from(skb, sk) { - __u8 sacked; - int segs; - - if (skb == tcp_send_head(sk)) - break; - /* we could do better than to assign each time */ - if (!hole) - tp->retransmit_skb_hint = skb; - - segs = tp->snd_cwnd - tcp_packets_in_flight(tp); - if (segs <= 0) - return; - sacked = TCP_SKB_CB(skb)->sacked; - /* In case tcp_shift_skb_data() have aggregated large skbs, - * we need to make sure not sending too bigs TSO packets - */ - segs = min_t(int, segs, max_segs); - - if (fwd_rexmitting) { -begin_fwd: - if (!before(TCP_SKB_CB(skb)->seq, tcp_highest_sack_seq(tp))) - break; - mib_idx = LINUX_MIB_TCPFORWARDRETRANS; - - } else if (!before(TCP_SKB_CB(skb)->seq, tp->retransmit_high)) { - tp->retransmit_high = last_lost; - if (!tcp_can_forward_retransmit(sk)) - break; - /* Backtrack if necessary to non-L'ed skb */ - if (hole) { - skb = hole; - hole = NULL; - } - fwd_rexmitting = 1; - goto begin_fwd; - - } else if (!(sacked & TCPCB_LOST)) { - if (!hole && !(sacked & (TCPCB_SACKED_RETRANS|TCPCB_SACKED_ACKED))) - hole = skb; - continue; - - } else { - last_lost = TCP_SKB_CB(skb)->end_seq; - if (icsk->icsk_ca_state != TCP_CA_Loss) - mib_idx = LINUX_MIB_TCPFASTRETRANS; - else - mib_idx = LINUX_MIB_TCPSLOWSTARTRETRANS; - } - - if (sacked & (TCPCB_SACKED_ACKED|TCPCB_SACKED_RETRANS)) - continue; - - if (tcp_small_queue_check(sk, skb, 1)) - return; - - if (tcp_retransmit_skb(sk, skb, segs)) - return; - - NET_ADD_STATS(sock_net(sk), mib_idx, tcp_skb_pcount(skb)); - - if (tcp_in_cwnd_reduction(sk)) - tp->prr_out += tcp_skb_pcount(skb); - - if (skb == tcp_write_queue_head(sk)) - inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, - inet_csk(sk)->icsk_rto, - TCP_RTO_MAX); - } -} - -/* We allow to exceed memory limits for FIN packets to expedite - * connection tear down and (memory) recovery. - * Otherwise tcp_send_fin() could be tempted to either delay FIN - * or even be forced to close flow without any FIN. - * In general, we want to allow one skb per socket to avoid hangs - * with edge trigger epoll() - */ -void sk_forced_mem_schedule(struct sock *sk, int size) -{ - int amt; - - if (size <= sk->sk_forward_alloc) - return; - amt = sk_mem_pages(size); - sk->sk_forward_alloc += amt * SK_MEM_QUANTUM; - sk_memory_allocated_add(sk, amt); - - if (mem_cgroup_sockets_enabled && sk->sk_memcg) - mem_cgroup_charge_skmem(sk->sk_memcg, amt); -} - -/* Send a FIN. The caller locks the socket for us. - * We should try to send a FIN packet really hard, but eventually give up. - */ -void tcp_send_fin(struct sock *sk) -{ - struct sk_buff *skb, *tskb = tcp_write_queue_tail(sk); - struct tcp_sock *tp = tcp_sk(sk); - - /* Optimization, tack on the FIN if we have one skb in write queue and - * this skb was not yet sent, or we are under memory pressure. - * Note: in the latter case, FIN packet will be sent after a timeout, - * as TCP stack thinks it has already been transmitted. - */ - if (tskb && (tcp_send_head(sk) || tcp_under_memory_pressure(sk))) { -coalesce: - TCP_SKB_CB(tskb)->tcp_flags |= TCPHDR_FIN; - TCP_SKB_CB(tskb)->end_seq++; - tp->write_seq++; - if (!tcp_send_head(sk)) { - /* This means tskb was already sent. - * Pretend we included the FIN on previous transmit. - * We need to set tp->snd_nxt to the value it would have - * if FIN had been sent. This is because retransmit path - * does not change tp->snd_nxt. - */ - tp->snd_nxt++; - return; - } - } else { - skb = alloc_skb_fclone(MAX_TCP_HEADER, sk->sk_allocation); - if (unlikely(!skb)) { - if (tskb) - goto coalesce; - return; - } - skb_reserve(skb, MAX_TCP_HEADER); - sk_forced_mem_schedule(sk, skb->truesize); - /* FIN eats a sequence byte, write_seq advanced by tcp_queue_skb(). */ - tcp_init_nondata_skb(skb, tp->write_seq, - TCPHDR_ACK | TCPHDR_FIN); - tcp_queue_skb(sk, skb); - } - __tcp_push_pending_frames(sk, tcp_current_mss(sk), TCP_NAGLE_OFF); -} - -/* We get here when a process closes a file descriptor (either due to - * an explicit close() or as a byproduct of exit()'ing) and there - * was unread data in the receive queue. This behavior is recommended - * by RFC 2525, section 2.17. -DaveM - */ -void tcp_send_active_reset(struct sock *sk, gfp_t priority) -{ - struct sk_buff *skb; - - /* NOTE: No TCP options attached and we never retransmit this. */ - skb = alloc_skb(MAX_TCP_HEADER, priority); - if (!skb) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTFAILED); - return; - } - - /* Reserve space for headers and prepare control bits. */ - skb_reserve(skb, MAX_TCP_HEADER); - tcp_init_nondata_skb(skb, tcp_acceptable_seq(sk), - TCPHDR_ACK | TCPHDR_RST); - skb_mstamp_get(&skb->skb_mstamp); - /* Send it off. */ - if (tcp_transmit_skb(sk, skb, 0, priority)) - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTFAILED); - - TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTRSTS); -} - -/* Send a crossed SYN-ACK during socket establishment. - * WARNING: This routine must only be called when we have already sent - * a SYN packet that crossed the incoming SYN that caused this routine - * to get called. If this assumption fails then the initial rcv_wnd - * and rcv_wscale values will not be correct. - */ -int tcp_send_synack(struct sock *sk) -{ - struct sk_buff *skb; - - skb = tcp_write_queue_head(sk); - if (!skb || !(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_SYN)) { - pr_debug("%s: wrong queue state\n", __func__); - return -EFAULT; - } - if (!(TCP_SKB_CB(skb)->tcp_flags & TCPHDR_ACK)) { - if (skb_cloned(skb)) { - struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); - if (!nskb) - return -ENOMEM; - tcp_unlink_write_queue(skb, sk); - __skb_header_release(nskb); - __tcp_add_write_queue_head(sk, nskb); - sk_wmem_free_skb(sk, skb); - sk->sk_wmem_queued += nskb->truesize; - sk_mem_charge(sk, nskb->truesize); - skb = nskb; - } - - TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_ACK; - tcp_ecn_send_synack(sk, skb); - } - return tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC); -} - -/** - * tcp_make_synack - Prepare a SYN-ACK. - * sk: listener socket - * dst: dst entry attached to the SYNACK - * req: request_sock pointer - * - * Allocate one skb and build a SYNACK packet. - * @dst is consumed : Caller should not use it again. - */ -struct sk_buff *tcp_make_synack(const struct sock *sk, struct dst_entry *dst, - struct request_sock *req, - struct tcp_fastopen_cookie *foc, - enum tcp_synack_type synack_type) -{ - struct inet_request_sock *ireq = inet_rsk(req); - const struct tcp_sock *tp = tcp_sk(sk); - struct tcp_md5sig_key *md5 = NULL; - struct tcp_out_options opts; - struct sk_buff *skb; - int tcp_header_size; - struct tcphdr *th; - u16 user_mss; - int mss; - - skb = alloc_skb(MAX_TCP_HEADER, GFP_ATOMIC); - if (unlikely(!skb)) { - dst_release(dst); - return NULL; - } - /* Reserve space for headers. */ - skb_reserve(skb, MAX_TCP_HEADER); - - switch (synack_type) { - case TCP_SYNACK_NORMAL: - skb_set_owner_w(skb, req_to_sk(req)); - break; - case TCP_SYNACK_COOKIE: - /* Under synflood, we do not attach skb to a socket, - * to avoid false sharing. - */ - break; - case TCP_SYNACK_FASTOPEN: - /* sk is a const pointer, because we want to express multiple - * cpu might call us concurrently. - * sk->sk_wmem_alloc in an atomic, we can promote to rw. - */ - skb_set_owner_w(skb, (struct sock *)sk); - break; - } - skb_dst_set(skb, dst); - - mss = dst_metric_advmss(dst); - user_mss = READ_ONCE(tp->rx_opt.user_mss); - if (user_mss && user_mss < mss) - mss = user_mss; - - memset(&opts, 0, sizeof(opts)); -#ifdef CONFIG_SYN_COOKIES - if (unlikely(req->cookie_ts)) - skb->skb_mstamp.stamp_jiffies = cookie_init_timestamp(req); - else -#endif - skb_mstamp_get(&skb->skb_mstamp); - -#ifdef CONFIG_TCP_MD5SIG - rcu_read_lock(); - md5 = tcp_rsk(req)->af_specific->req_md5_lookup(sk, req_to_sk(req)); -#endif - skb_set_hash(skb, tcp_rsk(req)->txhash, PKT_HASH_TYPE_L4); - tcp_header_size = tcp_synack_options(req, mss, skb, &opts, md5, foc) + - sizeof(*th); - - skb_push(skb, tcp_header_size); - skb_reset_transport_header(skb); - - th = (struct tcphdr *)skb->data; - memset(th, 0, sizeof(struct tcphdr)); - th->syn = 1; - th->ack = 1; - tcp_ecn_make_synack(req, th); - th->source = htons(ireq->ir_num); - th->dest = ireq->ir_rmt_port; - /* Setting of flags are superfluous here for callers (and ECE is - * not even correctly set) - */ - tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn, - TCPHDR_SYN | TCPHDR_ACK); - - th->seq = htonl(TCP_SKB_CB(skb)->seq); - /* XXX data is queued and acked as is. No buffer/window check */ - th->ack_seq = htonl(tcp_rsk(req)->rcv_nxt); - - /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ - th->window = htons(min(req->rsk_rcv_wnd, 65535U)); - tcp_options_write((__be32 *)(th + 1), NULL, &opts); - th->doff = (tcp_header_size >> 2); - __TCP_INC_STATS(sock_net(sk), TCP_MIB_OUTSEGS); - -#ifdef CONFIG_TCP_MD5SIG - /* Okay, we have all we need - do the md5 hash if needed */ - if (md5) - tcp_rsk(req)->af_specific->calc_md5_hash(opts.hash_location, - md5, req_to_sk(req), skb); - rcu_read_unlock(); -#endif - - /* Do not fool tcpdump (if any), clean our debris */ - skb->tstamp.tv64 = 0; - return skb; -} -EXPORT_SYMBOL(tcp_make_synack); - -static void tcp_ca_dst_init(struct sock *sk, const struct dst_entry *dst) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - const struct tcp_congestion_ops *ca; - u32 ca_key = dst_metric(dst, RTAX_CC_ALGO); - - if (ca_key == TCP_CA_UNSPEC) - return; - - rcu_read_lock(); - ca = tcp_ca_find_key(ca_key); - if (likely(ca && try_module_get(ca->owner))) { - module_put(icsk->icsk_ca_ops->owner); - icsk->icsk_ca_dst_locked = tcp_ca_dst_locked(dst); - icsk->icsk_ca_ops = ca; - } - rcu_read_unlock(); -} - -/* Do all connect socket setups that can be done AF independent. */ -static void tcp_connect_init(struct sock *sk) -{ - const struct dst_entry *dst = __sk_dst_get(sk); - struct tcp_sock *tp = tcp_sk(sk); - __u8 rcv_wscale; - - /* We'll fix this up when we get a response from the other end. - * See tcp_input.c:tcp_rcv_state_process case TCP_SYN_SENT. - */ - tp->tcp_header_len = sizeof(struct tcphdr) + - (sysctl_tcp_timestamps ? TCPOLEN_TSTAMP_ALIGNED : 0); - -#ifdef CONFIG_TCP_MD5SIG - if (tp->af_specific->md5_lookup(sk, sk)) - tp->tcp_header_len += TCPOLEN_MD5SIG_ALIGNED; -#endif - - /* If user gave his TCP_MAXSEG, record it to clamp */ - if (tp->rx_opt.user_mss) - tp->rx_opt.mss_clamp = tp->rx_opt.user_mss; - tp->max_window = 0; - tcp_mtup_init(sk); - tcp_sync_mss(sk, dst_mtu(dst)); - - tcp_ca_dst_init(sk, dst); - - if (!tp->window_clamp) - tp->window_clamp = dst_metric(dst, RTAX_WINDOW); - tp->advmss = dst_metric_advmss(dst); - if (tp->rx_opt.user_mss && tp->rx_opt.user_mss < tp->advmss) - tp->advmss = tp->rx_opt.user_mss; - - tcp_initialize_rcv_mss(sk); - - /* limit the window selection if the user enforce a smaller rx buffer */ - if (sk->sk_userlocks & SOCK_RCVBUF_LOCK && - (tp->window_clamp > tcp_full_space(sk) || tp->window_clamp == 0)) - tp->window_clamp = tcp_full_space(sk); - - tcp_select_initial_window(tcp_full_space(sk), - tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0), - &tp->rcv_wnd, - &tp->window_clamp, - sysctl_tcp_window_scaling, - &rcv_wscale, - dst_metric(dst, RTAX_INITRWND)); - - tp->rx_opt.rcv_wscale = rcv_wscale; - tp->rcv_ssthresh = tp->rcv_wnd; - - sk->sk_err = 0; - sock_reset_flag(sk, SOCK_DONE); - tp->snd_wnd = 0; - tcp_init_wl(tp, 0); - tp->snd_una = tp->write_seq; - tp->snd_sml = tp->write_seq; - tp->snd_up = tp->write_seq; - tp->snd_nxt = tp->write_seq; - - if (likely(!tp->repair)) - tp->rcv_nxt = 0; - else - tp->rcv_tstamp = tcp_time_stamp; - tp->rcv_wup = tp->rcv_nxt; - tp->copied_seq = tp->rcv_nxt; - - inet_csk(sk)->icsk_rto = TCP_TIMEOUT_INIT; - inet_csk(sk)->icsk_retransmits = 0; - tcp_clear_retrans(tp); -} - -static void tcp_connect_queue_skb(struct sock *sk, struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct tcp_skb_cb *tcb = TCP_SKB_CB(skb); - - tcb->end_seq += skb->len; - __skb_header_release(skb); - __tcp_add_write_queue_tail(sk, skb); - sk->sk_wmem_queued += skb->truesize; - sk_mem_charge(sk, skb->truesize); - tp->write_seq = tcb->end_seq; - tp->packets_out += tcp_skb_pcount(skb); -} - -/* Build and send a SYN with data and (cached) Fast Open cookie. However, - * queue a data-only packet after the regular SYN, such that regular SYNs - * are retransmitted on timeouts. Also if the remote SYN-ACK acknowledges - * only the SYN sequence, the data are retransmitted in the first ACK. - * If cookie is not cached or other error occurs, falls back to send a - * regular SYN with Fast Open cookie request option. - */ -static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct tcp_fastopen_request *fo = tp->fastopen_req; - int syn_loss = 0, space, err = 0; - unsigned long last_syn_loss = 0; - struct sk_buff *syn_data; - - tp->rx_opt.mss_clamp = tp->advmss; /* If MSS is not cached */ - tcp_fastopen_cache_get(sk, &tp->rx_opt.mss_clamp, &fo->cookie, - &syn_loss, &last_syn_loss); - /* Recurring FO SYN losses: revert to regular handshake temporarily */ - if (syn_loss > 1 && - time_before(jiffies, last_syn_loss + (60*HZ << syn_loss))) { - fo->cookie.len = -1; - goto fallback; - } - - if (sysctl_tcp_fastopen & TFO_CLIENT_NO_COOKIE) - fo->cookie.len = -1; - else if (fo->cookie.len <= 0) - goto fallback; - - /* MSS for SYN-data is based on cached MSS and bounded by PMTU and - * user-MSS. Reserve maximum option space for middleboxes that add - * private TCP options. The cost is reduced data space in SYN :( - */ - if (tp->rx_opt.user_mss && tp->rx_opt.user_mss < tp->rx_opt.mss_clamp) - tp->rx_opt.mss_clamp = tp->rx_opt.user_mss; - space = __tcp_mtu_to_mss(sk, inet_csk(sk)->icsk_pmtu_cookie) - - MAX_TCP_OPTION_SPACE; - - space = min_t(size_t, space, fo->size); - - /* limit to order-0 allocations */ - space = min_t(size_t, space, SKB_MAX_HEAD(MAX_TCP_HEADER)); - - syn_data = sk_stream_alloc_skb(sk, space, sk->sk_allocation, false); - if (!syn_data) - goto fallback; - syn_data->ip_summed = CHECKSUM_PARTIAL; - memcpy(syn_data->cb, syn->cb, sizeof(syn->cb)); - if (space) { - int copied = copy_from_iter(skb_put(syn_data, space), space, - &fo->data->msg_iter); - if (unlikely(!copied)) { - kfree_skb(syn_data); - goto fallback; - } - if (copied != space) { - skb_trim(syn_data, copied); - space = copied; - } - } - /* No more data pending in inet_wait_for_connect() */ - if (space == fo->size) - fo->data = NULL; - fo->copied = space; - - tcp_connect_queue_skb(sk, syn_data); - - err = tcp_transmit_skb(sk, syn_data, 1, sk->sk_allocation); - - syn->skb_mstamp = syn_data->skb_mstamp; - - /* Now full SYN+DATA was cloned and sent (or not), - * remove the SYN from the original skb (syn_data) - * we keep in write queue in case of a retransmit, as we - * also have the SYN packet (with no data) in the same queue. - */ - TCP_SKB_CB(syn_data)->seq++; - TCP_SKB_CB(syn_data)->tcp_flags = TCPHDR_ACK | TCPHDR_PSH; - if (!err) { - tp->syn_data = (fo->copied > 0); - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPORIGDATASENT); - goto done; - } - -fallback: - /* Send a regular SYN with Fast Open cookie request option */ - if (fo->cookie.len > 0) - fo->cookie.len = 0; - err = tcp_transmit_skb(sk, syn, 1, sk->sk_allocation); - if (err) - tp->syn_fastopen = 0; -done: - fo->cookie.len = -1; /* Exclude Fast Open option for SYN retries */ - return err; -} - -/* Build a SYN and send it off. */ -int tcp_connect(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *buff; - int err; - - tcp_connect_init(sk); - - if (unlikely(tp->repair)) { - tcp_finish_connect(sk, NULL); - return 0; - } - - buff = sk_stream_alloc_skb(sk, 0, sk->sk_allocation, true); - if (unlikely(!buff)) - return -ENOBUFS; - - tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN); - tp->retrans_stamp = tcp_time_stamp; - tcp_connect_queue_skb(sk, buff); - tcp_ecn_send_syn(sk, buff); - - /* Send off SYN; include data in Fast Open. */ - err = tp->fastopen_req ? tcp_send_syn_data(sk, buff) : - tcp_transmit_skb(sk, buff, 1, sk->sk_allocation); - if (err == -ECONNREFUSED) - return err; - - /* We change tp->snd_nxt after the tcp_transmit_skb() call - * in order to make this packet get counted in tcpOutSegs. - */ - tp->snd_nxt = tp->write_seq; - tp->pushed_seq = tp->write_seq; - TCP_INC_STATS(sock_net(sk), TCP_MIB_ACTIVEOPENS); - - /* Timer for repeating the SYN until an answer. */ - inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, - inet_csk(sk)->icsk_rto, TCP_RTO_MAX); - return 0; -} -EXPORT_SYMBOL(tcp_connect); - -/* Send out a delayed ack, the caller does the policy checking - * to see if we should even be here. See tcp_input.c:tcp_ack_snd_check() - * for details. - */ -void tcp_send_delayed_ack(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - int ato = icsk->icsk_ack.ato; - unsigned long timeout; - - tcp_ca_event(sk, CA_EVENT_DELAYED_ACK); - - if (ato > TCP_DELACK_MIN) { - const struct tcp_sock *tp = tcp_sk(sk); - int max_ato = HZ / 2; - - if (icsk->icsk_ack.pingpong || - (icsk->icsk_ack.pending & ICSK_ACK_PUSHED)) - max_ato = TCP_DELACK_MAX; - - /* Slow path, intersegment interval is "high". */ - - /* If some rtt estimate is known, use it to bound delayed ack. - * Do not use inet_csk(sk)->icsk_rto here, use results of rtt measurements - * directly. - */ - if (tp->srtt_us) { - int rtt = max_t(int, usecs_to_jiffies(tp->srtt_us >> 3), - TCP_DELACK_MIN); - - if (rtt < max_ato) - max_ato = rtt; - } - - ato = min(ato, max_ato); - } - - /* Stay within the limit we were given */ - timeout = jiffies + ato; - - /* Use new timeout only if there wasn't a older one earlier. */ - if (icsk->icsk_ack.pending & ICSK_ACK_TIMER) { - /* If delack timer was blocked or is about to expire, - * send ACK now. - */ - if (icsk->icsk_ack.blocked || - time_before_eq(icsk->icsk_ack.timeout, jiffies + (ato >> 2))) { - tcp_send_ack(sk); - return; - } - - if (!time_before(timeout, icsk->icsk_ack.timeout)) - timeout = icsk->icsk_ack.timeout; - } - icsk->icsk_ack.pending |= ICSK_ACK_SCHED | ICSK_ACK_TIMER; - icsk->icsk_ack.timeout = timeout; - sk_reset_timer(sk, &icsk->icsk_delack_timer, timeout); -} - -/* This routine sends an ack and also updates the window. */ -void tcp_send_ack(struct sock *sk) -{ - struct sk_buff *buff; - - /* If we have been reset, we may not send again. */ - if (sk->sk_state == TCP_CLOSE) - return; - - tcp_ca_event(sk, CA_EVENT_NON_DELAYED_ACK); - - /* We are not putting this on the write queue, so - * tcp_transmit_skb() will set the ownership to this - * sock. - */ - buff = alloc_skb(MAX_TCP_HEADER, - sk_gfp_mask(sk, GFP_ATOMIC | __GFP_NOWARN)); - if (unlikely(!buff)) { - inet_csk_schedule_ack(sk); - inet_csk(sk)->icsk_ack.ato = TCP_ATO_MIN; - inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, - TCP_DELACK_MAX, TCP_RTO_MAX); - return; - } - - /* Reserve space for headers and prepare control bits. */ - skb_reserve(buff, MAX_TCP_HEADER); - tcp_init_nondata_skb(buff, tcp_acceptable_seq(sk), TCPHDR_ACK); - - /* We do not want pure acks influencing TCP Small Queues or fq/pacing - * too much. - * SKB_TRUESIZE(max(1 .. 66, MAX_TCP_HEADER)) is unfortunately ~784 - * We also avoid tcp_wfree() overhead (cache line miss accessing - * tp->tsq_flags) by using regular sock_wfree() - */ - skb_set_tcp_pure_ack(buff); - - /* Send it off, this clears delayed acks for us. */ - skb_mstamp_get(&buff->skb_mstamp); - tcp_transmit_skb(sk, buff, 0, (__force gfp_t)0); -} -EXPORT_SYMBOL_GPL(tcp_send_ack); - -/* This routine sends a packet with an out of date sequence - * number. It assumes the other end will try to ack it. - * - * Question: what should we make while urgent mode? - * 4.4BSD forces sending single byte of data. We cannot send - * out of window data, because we have SND.NXT==SND.MAX... - * - * Current solution: to send TWO zero-length segments in urgent mode: - * one is with SEG.SEQ=SND.UNA to deliver urgent pointer, another is - * out-of-date with SND.UNA-1 to probe window. - */ -static int tcp_xmit_probe_skb(struct sock *sk, int urgent, int mib) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *skb; - - /* We don't queue it, tcp_transmit_skb() sets ownership. */ - skb = alloc_skb(MAX_TCP_HEADER, - sk_gfp_mask(sk, GFP_ATOMIC | __GFP_NOWARN)); - if (!skb) - return -1; - - /* Reserve space for headers and set control bits. */ - skb_reserve(skb, MAX_TCP_HEADER); - /* Use a previous sequence. This should cause the other - * end to send an ack. Don't queue or clone SKB, just - * send it. - */ - tcp_init_nondata_skb(skb, tp->snd_una - !urgent, TCPHDR_ACK); - skb_mstamp_get(&skb->skb_mstamp); - NET_INC_STATS(sock_net(sk), mib); - return tcp_transmit_skb(sk, skb, 0, (__force gfp_t)0); -} - -void tcp_send_window_probe(struct sock *sk) -{ - if (sk->sk_state == TCP_ESTABLISHED) { - tcp_sk(sk)->snd_wl1 = tcp_sk(sk)->rcv_nxt - 1; - tcp_xmit_probe_skb(sk, 0, LINUX_MIB_TCPWINPROBE); - } -} - -/* Initiate keepalive or window probe from timer. */ -int tcp_write_wakeup(struct sock *sk, int mib) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *skb; - - if (sk->sk_state == TCP_CLOSE) - return -1; - - skb = tcp_send_head(sk); - if (skb && before(TCP_SKB_CB(skb)->seq, tcp_wnd_end(tp))) { - int err; - unsigned int mss = tcp_current_mss(sk); - unsigned int seg_size = tcp_wnd_end(tp) - TCP_SKB_CB(skb)->seq; - - if (before(tp->pushed_seq, TCP_SKB_CB(skb)->end_seq)) - tp->pushed_seq = TCP_SKB_CB(skb)->end_seq; - - /* We are probing the opening of a window - * but the window size is != 0 - * must have been a result SWS avoidance ( sender ) - */ - if (seg_size < TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq || - skb->len > mss) { - seg_size = min(seg_size, mss); - TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_PSH; - if (tcp_fragment(sk, skb, seg_size, mss, GFP_ATOMIC)) - return -1; - } else if (!tcp_skb_pcount(skb)) - tcp_set_skb_tso_segs(skb, mss); - - TCP_SKB_CB(skb)->tcp_flags |= TCPHDR_PSH; - err = tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC); - if (!err) - tcp_event_new_data_sent(sk, skb); - return err; - } else { - if (between(tp->snd_up, tp->snd_una + 1, tp->snd_una + 0xFFFF)) - tcp_xmit_probe_skb(sk, 1, mib); - return tcp_xmit_probe_skb(sk, 0, mib); - } -} - -/* A window probe timeout has occurred. If window is not closed send - * a partial packet else a zero probe. - */ -void tcp_send_probe0(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - struct net *net = sock_net(sk); - unsigned long probe_max; - int err; - - err = tcp_write_wakeup(sk, LINUX_MIB_TCPWINPROBE); - - if (tp->packets_out || !tcp_send_head(sk)) { - /* Cancel probe timer, if it is not required. */ - icsk->icsk_probes_out = 0; - icsk->icsk_backoff = 0; - return; - } - - if (err <= 0) { - if (icsk->icsk_backoff < net->ipv4.sysctl_tcp_retries2) - icsk->icsk_backoff++; - icsk->icsk_probes_out++; - probe_max = TCP_RTO_MAX; - } else { - /* If packet was not sent due to local congestion, - * do not backoff and do not remember icsk_probes_out. - * Let local senders to fight for local resources. - * - * Use accumulated backoff yet. - */ - if (!icsk->icsk_probes_out) - icsk->icsk_probes_out = 1; - probe_max = TCP_RESOURCE_PROBE_INTERVAL; - } - inet_csk_reset_xmit_timer(sk, ICSK_TIME_PROBE0, - tcp_probe0_when(sk, probe_max), - TCP_RTO_MAX); -} - -int tcp_rtx_synack(const struct sock *sk, struct request_sock *req) -{ - const struct tcp_request_sock_ops *af_ops = tcp_rsk(req)->af_specific; - struct flowi fl; - int res; - - tcp_rsk(req)->txhash = net_tx_rndhash(); - res = af_ops->send_synack(sk, NULL, &fl, req, NULL, TCP_SYNACK_NORMAL); - if (!res) { - __TCP_INC_STATS(sock_net(sk), TCP_MIB_RETRANSSEGS); - __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSYNRETRANS); - if (unlikely(tcp_passive_fastopen(sk))) - tcp_sk(sk)->total_retrans++; - } - return res; -} -EXPORT_SYMBOL(tcp_rtx_synack); diff --git a/src/linux/net/ipv4/tcp_rate.c b/src/linux/net/ipv4/tcp_rate.c deleted file mode 100644 index 9be1581..0000000 --- a/src/linux/net/ipv4/tcp_rate.c +++ /dev/null @@ -1,186 +0,0 @@ -#include - -/* The bandwidth estimator estimates the rate at which the network - * can currently deliver outbound data packets for this flow. At a high - * level, it operates by taking a delivery rate sample for each ACK. - * - * A rate sample records the rate at which the network delivered packets - * for this flow, calculated over the time interval between the transmission - * of a data packet and the acknowledgment of that packet. - * - * Specifically, over the interval between each transmit and corresponding ACK, - * the estimator generates a delivery rate sample. Typically it uses the rate - * at which packets were acknowledged. However, the approach of using only the - * acknowledgment rate faces a challenge under the prevalent ACK decimation or - * compression: packets can temporarily appear to be delivered much quicker - * than the bottleneck rate. Since it is physically impossible to do that in a - * sustained fashion, when the estimator notices that the ACK rate is faster - * than the transmit rate, it uses the latter: - * - * send_rate = #pkts_delivered/(last_snd_time - first_snd_time) - * ack_rate = #pkts_delivered/(last_ack_time - first_ack_time) - * bw = min(send_rate, ack_rate) - * - * Notice the estimator essentially estimates the goodput, not always the - * network bottleneck link rate when the sending or receiving is limited by - * other factors like applications or receiver window limits. The estimator - * deliberately avoids using the inter-packet spacing approach because that - * approach requires a large number of samples and sophisticated filtering. - * - * TCP flows can often be application-limited in request/response workloads. - * The estimator marks a bandwidth sample as application-limited if there - * was some moment during the sampled window of packets when there was no data - * ready to send in the write queue. - */ - -/* Snapshot the current delivery information in the skb, to generate - * a rate sample later when the skb is (s)acked in tcp_rate_skb_delivered(). - */ -void tcp_rate_skb_sent(struct sock *sk, struct sk_buff *skb) -{ - struct tcp_sock *tp = tcp_sk(sk); - - /* In general we need to start delivery rate samples from the - * time we received the most recent ACK, to ensure we include - * the full time the network needs to deliver all in-flight - * packets. If there are no packets in flight yet, then we - * know that any ACKs after now indicate that the network was - * able to deliver those packets completely in the sampling - * interval between now and the next ACK. - * - * Note that we use packets_out instead of tcp_packets_in_flight(tp) - * because the latter is a guess based on RTO and loss-marking - * heuristics. We don't want spurious RTOs or loss markings to cause - * a spuriously small time interval, causing a spuriously high - * bandwidth estimate. - */ - if (!tp->packets_out) { - tp->first_tx_mstamp = skb->skb_mstamp; - tp->delivered_mstamp = skb->skb_mstamp; - } - - TCP_SKB_CB(skb)->tx.first_tx_mstamp = tp->first_tx_mstamp; - TCP_SKB_CB(skb)->tx.delivered_mstamp = tp->delivered_mstamp; - TCP_SKB_CB(skb)->tx.delivered = tp->delivered; - TCP_SKB_CB(skb)->tx.is_app_limited = tp->app_limited ? 1 : 0; -} - -/* When an skb is sacked or acked, we fill in the rate sample with the (prior) - * delivery information when the skb was last transmitted. - * - * If an ACK (s)acks multiple skbs (e.g., stretched-acks), this function is - * called multiple times. We favor the information from the most recently - * sent skb, i.e., the skb with the highest prior_delivered count. - */ -void tcp_rate_skb_delivered(struct sock *sk, struct sk_buff *skb, - struct rate_sample *rs) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct tcp_skb_cb *scb = TCP_SKB_CB(skb); - - if (!scb->tx.delivered_mstamp.v64) - return; - - if (!rs->prior_delivered || - after(scb->tx.delivered, rs->prior_delivered)) { - rs->prior_delivered = scb->tx.delivered; - rs->prior_mstamp = scb->tx.delivered_mstamp; - rs->is_app_limited = scb->tx.is_app_limited; - rs->is_retrans = scb->sacked & TCPCB_RETRANS; - - /* Find the duration of the "send phase" of this window: */ - rs->interval_us = skb_mstamp_us_delta( - &skb->skb_mstamp, - &scb->tx.first_tx_mstamp); - - /* Record send time of most recently ACKed packet: */ - tp->first_tx_mstamp = skb->skb_mstamp; - } - /* Mark off the skb delivered once it's sacked to avoid being - * used again when it's cumulatively acked. For acked packets - * we don't need to reset since it'll be freed soon. - */ - if (scb->sacked & TCPCB_SACKED_ACKED) - scb->tx.delivered_mstamp.v64 = 0; -} - -/* Update the connection delivery information and generate a rate sample. */ -void tcp_rate_gen(struct sock *sk, u32 delivered, u32 lost, - struct skb_mstamp *now, struct rate_sample *rs) -{ - struct tcp_sock *tp = tcp_sk(sk); - u32 snd_us, ack_us; - - /* Clear app limited if bubble is acked and gone. */ - if (tp->app_limited && after(tp->delivered, tp->app_limited)) - tp->app_limited = 0; - - /* TODO: there are multiple places throughout tcp_ack() to get - * current time. Refactor the code using a new "tcp_acktag_state" - * to carry current time, flags, stats like "tcp_sacktag_state". - */ - if (delivered) - tp->delivered_mstamp = *now; - - rs->acked_sacked = delivered; /* freshly ACKed or SACKed */ - rs->losses = lost; /* freshly marked lost */ - /* Return an invalid sample if no timing information is available. */ - if (!rs->prior_mstamp.v64) { - rs->delivered = -1; - rs->interval_us = -1; - return; - } - rs->delivered = tp->delivered - rs->prior_delivered; - - /* Model sending data and receiving ACKs as separate pipeline phases - * for a window. Usually the ACK phase is longer, but with ACK - * compression the send phase can be longer. To be safe we use the - * longer phase. - */ - snd_us = rs->interval_us; /* send phase */ - ack_us = skb_mstamp_us_delta(now, &rs->prior_mstamp); /* ack phase */ - rs->interval_us = max(snd_us, ack_us); - - /* Normally we expect interval_us >= min-rtt. - * Note that rate may still be over-estimated when a spuriously - * retransmistted skb was first (s)acked because "interval_us" - * is under-estimated (up to an RTT). However continuously - * measuring the delivery rate during loss recovery is crucial - * for connections suffer heavy or prolonged losses. - */ - if (unlikely(rs->interval_us < tcp_min_rtt(tp))) { - if (!rs->is_retrans) - pr_debug("tcp rate: %ld %d %u %u %u\n", - rs->interval_us, rs->delivered, - inet_csk(sk)->icsk_ca_state, - tp->rx_opt.sack_ok, tcp_min_rtt(tp)); - rs->interval_us = -1; - return; - } - - /* Record the last non-app-limited or the highest app-limited bw */ - if (!rs->is_app_limited || - ((u64)rs->delivered * tp->rate_interval_us >= - (u64)tp->rate_delivered * rs->interval_us)) { - tp->rate_delivered = rs->delivered; - tp->rate_interval_us = rs->interval_us; - tp->rate_app_limited = rs->is_app_limited; - } -} - -/* If a gap is detected between sends, mark the socket application-limited. */ -void tcp_rate_check_app_limited(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - - if (/* We have less than one packet to send. */ - tp->write_seq - tp->snd_nxt < tp->mss_cache && - /* Nothing in sending host's qdisc queues or NIC tx queue. */ - sk_wmem_alloc_get(sk) < SKB_TRUESIZE(1) && - /* We are not limited by CWND. */ - tcp_packets_in_flight(tp) < tp->snd_cwnd && - /* All lost packets have been retransmitted. */ - tp->lost_out <= tp->retrans_out) - tp->app_limited = - (tp->delivered + tcp_packets_in_flight(tp)) ? : 1; -} diff --git a/src/linux/net/ipv4/tcp_recovery.c b/src/linux/net/ipv4/tcp_recovery.c deleted file mode 100644 index e36df4f..0000000 --- a/src/linux/net/ipv4/tcp_recovery.c +++ /dev/null @@ -1,109 +0,0 @@ -#include -#include - -int sysctl_tcp_recovery __read_mostly = TCP_RACK_LOST_RETRANS; - -/* Marks a packet lost, if some packet sent later has been (s)acked. - * The underlying idea is similar to the traditional dupthresh and FACK - * but they look at different metrics: - * - * dupthresh: 3 OOO packets delivered (packet count) - * FACK: sequence delta to highest sacked sequence (sequence space) - * RACK: sent time delta to the latest delivered packet (time domain) - * - * The advantage of RACK is it applies to both original and retransmitted - * packet and therefore is robust against tail losses. Another advantage - * is being more resilient to reordering by simply allowing some - * "settling delay", instead of tweaking the dupthresh. - * - * The current version is only used after recovery starts but can be - * easily extended to detect the first loss. - */ -int tcp_rack_mark_lost(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *skb; - u32 reo_wnd, prior_retrans = tp->retrans_out; - - if (inet_csk(sk)->icsk_ca_state < TCP_CA_Recovery || !tp->rack.advanced) - return 0; - - /* Reset the advanced flag to avoid unnecessary queue scanning */ - tp->rack.advanced = 0; - - /* To be more reordering resilient, allow min_rtt/4 settling delay - * (lower-bounded to 1000uS). We use min_rtt instead of the smoothed - * RTT because reordering is often a path property and less related - * to queuing or delayed ACKs. - * - * TODO: measure and adapt to the observed reordering delay, and - * use a timer to retransmit like the delayed early retransmit. - */ - reo_wnd = 1000; - if (tp->rack.reord && tcp_min_rtt(tp) != ~0U) - reo_wnd = max(tcp_min_rtt(tp) >> 2, reo_wnd); - - tcp_for_write_queue(skb, sk) { - struct tcp_skb_cb *scb = TCP_SKB_CB(skb); - - if (skb == tcp_send_head(sk)) - break; - - /* Skip ones already (s)acked */ - if (!after(scb->end_seq, tp->snd_una) || - scb->sacked & TCPCB_SACKED_ACKED) - continue; - - if (skb_mstamp_after(&tp->rack.mstamp, &skb->skb_mstamp)) { - - if (skb_mstamp_us_delta(&tp->rack.mstamp, - &skb->skb_mstamp) <= reo_wnd) - continue; - - /* skb is lost if packet sent later is sacked */ - tcp_skb_mark_lost_uncond_verify(tp, skb); - if (scb->sacked & TCPCB_SACKED_RETRANS) { - scb->sacked &= ~TCPCB_SACKED_RETRANS; - tp->retrans_out -= tcp_skb_pcount(skb); - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPLOSTRETRANSMIT); - } - } else if (!(scb->sacked & TCPCB_RETRANS)) { - /* Original data are sent sequentially so stop early - * b/c the rest are all sent after rack_sent - */ - break; - } - } - return prior_retrans - tp->retrans_out; -} - -/* Record the most recently (re)sent time among the (s)acked packets */ -void tcp_rack_advance(struct tcp_sock *tp, - const struct skb_mstamp *xmit_time, u8 sacked) -{ - if (tp->rack.mstamp.v64 && - !skb_mstamp_after(xmit_time, &tp->rack.mstamp)) - return; - - if (sacked & TCPCB_RETRANS) { - struct skb_mstamp now; - - /* If the sacked packet was retransmitted, it's ambiguous - * whether the retransmission or the original (or the prior - * retransmission) was sacked. - * - * If the original is lost, there is no ambiguity. Otherwise - * we assume the original can be delayed up to aRTT + min_rtt. - * the aRTT term is bounded by the fast recovery or timeout, - * so it's at least one RTT (i.e., retransmission is at least - * an RTT later). - */ - skb_mstamp_get(&now); - if (skb_mstamp_us_delta(&now, xmit_time) < tcp_min_rtt(tp)) - return; - } - - tp->rack.mstamp = *xmit_time; - tp->rack.advanced = 1; -} diff --git a/src/linux/net/ipv4/tcp_timer.c b/src/linux/net/ipv4/tcp_timer.c deleted file mode 100644 index 3ea1cf8..0000000 --- a/src/linux/net/ipv4/tcp_timer.c +++ /dev/null @@ -1,711 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Implementation of the Transmission Control Protocol(TCP). - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Mark Evans, - * Corey Minyard - * Florian La Roche, - * Charles Hedrick, - * Linus Torvalds, - * Alan Cox, - * Matthew Dillon, - * Arnt Gulbrandsen, - * Jorge Cwik, - */ - -#include -#include -#include - -int sysctl_tcp_thin_linear_timeouts __read_mostly; - -/** - * tcp_write_err() - close socket and save error info - * @sk: The socket the error has appeared on. - * - * Returns: Nothing (void) - */ - -static void tcp_write_err(struct sock *sk) -{ - sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT; - sk->sk_error_report(sk); - - tcp_done(sk); - __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONTIMEOUT); -} - -/** - * tcp_out_of_resources() - Close socket if out of resources - * @sk: pointer to current socket - * @do_reset: send a last packet with reset flag - * - * Do not allow orphaned sockets to eat all our resources. - * This is direct violation of TCP specs, but it is required - * to prevent DoS attacks. It is called when a retransmission timeout - * or zero probe timeout occurs on orphaned socket. - * - * Criteria is still not confirmed experimentally and may change. - * We kill the socket, if: - * 1. If number of orphaned sockets exceeds an administratively configured - * limit. - * 2. If we have strong memory pressure. - */ -static int tcp_out_of_resources(struct sock *sk, bool do_reset) -{ - struct tcp_sock *tp = tcp_sk(sk); - int shift = 0; - - /* If peer does not open window for long time, or did not transmit - * anything for long time, penalize it. */ - if ((s32)(tcp_time_stamp - tp->lsndtime) > 2*TCP_RTO_MAX || !do_reset) - shift++; - - /* If some dubious ICMP arrived, penalize even more. */ - if (sk->sk_err_soft) - shift++; - - if (tcp_check_oom(sk, shift)) { - /* Catch exceptional cases, when connection requires reset. - * 1. Last segment was sent recently. */ - if ((s32)(tcp_time_stamp - tp->lsndtime) <= TCP_TIMEWAIT_LEN || - /* 2. Window is closed. */ - (!tp->snd_wnd && !tp->packets_out)) - do_reset = true; - if (do_reset) - tcp_send_active_reset(sk, GFP_ATOMIC); - tcp_done(sk); - __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPABORTONMEMORY); - return 1; - } - return 0; -} - -/** - * tcp_orphan_retries() - Returns maximal number of retries on an orphaned socket - * @sk: Pointer to the current socket. - * @alive: bool, socket alive state - */ -static int tcp_orphan_retries(struct sock *sk, bool alive) -{ - int retries = sock_net(sk)->ipv4.sysctl_tcp_orphan_retries; /* May be zero. */ - - /* We know from an ICMP that something is wrong. */ - if (sk->sk_err_soft && !alive) - retries = 0; - - /* However, if socket sent something recently, select some safe - * number of retries. 8 corresponds to >100 seconds with minimal - * RTO of 200msec. */ - if (retries == 0 && alive) - retries = 8; - return retries; -} - -static void tcp_mtu_probing(struct inet_connection_sock *icsk, struct sock *sk) -{ - struct net *net = sock_net(sk); - - /* Black hole detection */ - if (net->ipv4.sysctl_tcp_mtu_probing) { - if (!icsk->icsk_mtup.enabled) { - icsk->icsk_mtup.enabled = 1; - icsk->icsk_mtup.probe_timestamp = tcp_time_stamp; - tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); - } else { - struct net *net = sock_net(sk); - struct tcp_sock *tp = tcp_sk(sk); - int mss; - - mss = tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_low) >> 1; - mss = min(net->ipv4.sysctl_tcp_base_mss, mss); - mss = max(mss, 68 - tp->tcp_header_len); - icsk->icsk_mtup.search_low = tcp_mss_to_mtu(sk, mss); - tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); - } - } -} - - -/** - * retransmits_timed_out() - returns true if this connection has timed out - * @sk: The current socket - * @boundary: max number of retransmissions - * @timeout: A custom timeout value. - * If set to 0 the default timeout is calculated and used. - * Using TCP_RTO_MIN and the number of unsuccessful retransmits. - * @syn_set: true if the SYN Bit was set. - * - * The default "timeout" value this function can calculate and use - * is equivalent to the timeout of a TCP Connection - * after "boundary" unsuccessful, exponentially backed-off - * retransmissions with an initial RTO of TCP_RTO_MIN or TCP_TIMEOUT_INIT if - * syn_set flag is set. - * - */ -static bool retransmits_timed_out(struct sock *sk, - unsigned int boundary, - unsigned int timeout, - bool syn_set) -{ - unsigned int linear_backoff_thresh, start_ts; - unsigned int rto_base = syn_set ? TCP_TIMEOUT_INIT : TCP_RTO_MIN; - - if (!inet_csk(sk)->icsk_retransmits) - return false; - - start_ts = tcp_sk(sk)->retrans_stamp; - if (unlikely(!start_ts)) - start_ts = tcp_skb_timestamp(tcp_write_queue_head(sk)); - - if (likely(timeout == 0)) { - linear_backoff_thresh = ilog2(TCP_RTO_MAX/rto_base); - - if (boundary <= linear_backoff_thresh) - timeout = ((2 << boundary) - 1) * rto_base; - else - timeout = ((2 << linear_backoff_thresh) - 1) * rto_base + - (boundary - linear_backoff_thresh) * TCP_RTO_MAX; - } - return (tcp_time_stamp - start_ts) >= timeout; -} - -/* A write timeout has occurred. Process the after effects. */ -static int tcp_write_timeout(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - struct net *net = sock_net(sk); - int retry_until; - bool do_reset, syn_set = false; - - if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { - if (icsk->icsk_retransmits) { - dst_negative_advice(sk); - if (tp->syn_fastopen || tp->syn_data) - tcp_fastopen_cache_set(sk, 0, NULL, true, 0); - if (tp->syn_data && icsk->icsk_retransmits == 1) - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPFASTOPENACTIVEFAIL); - } else if (!tp->syn_data && !tp->syn_fastopen) { - sk_rethink_txhash(sk); - } - retry_until = icsk->icsk_syn_retries ? : net->ipv4.sysctl_tcp_syn_retries; - syn_set = true; - } else { - if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1, 0, 0)) { - /* Some middle-boxes may black-hole Fast Open _after_ - * the handshake. Therefore we conservatively disable - * Fast Open on this path on recurring timeouts with - * few or zero bytes acked after Fast Open. - */ - if (tp->syn_data_acked && - tp->bytes_acked <= tp->rx_opt.mss_clamp) { - tcp_fastopen_cache_set(sk, 0, NULL, true, 0); - if (icsk->icsk_retransmits == net->ipv4.sysctl_tcp_retries1) - NET_INC_STATS(sock_net(sk), - LINUX_MIB_TCPFASTOPENACTIVEFAIL); - } - /* Black hole detection */ - tcp_mtu_probing(icsk, sk); - - dst_negative_advice(sk); - } else { - sk_rethink_txhash(sk); - } - - retry_until = net->ipv4.sysctl_tcp_retries2; - if (sock_flag(sk, SOCK_DEAD)) { - const bool alive = icsk->icsk_rto < TCP_RTO_MAX; - - retry_until = tcp_orphan_retries(sk, alive); - do_reset = alive || - !retransmits_timed_out(sk, retry_until, 0, 0); - - if (tcp_out_of_resources(sk, do_reset)) - return 1; - } - } - - if (retransmits_timed_out(sk, retry_until, - syn_set ? 0 : icsk->icsk_user_timeout, syn_set)) { - /* Has it gone just too far? */ - tcp_write_err(sk); - return 1; - } - return 0; -} - -/* Called with BH disabled */ -void tcp_delack_timer_handler(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct inet_connection_sock *icsk = inet_csk(sk); - - sk_mem_reclaim_partial(sk); - - if (sk->sk_state == TCP_CLOSE || !(icsk->icsk_ack.pending & ICSK_ACK_TIMER)) - goto out; - - if (time_after(icsk->icsk_ack.timeout, jiffies)) { - sk_reset_timer(sk, &icsk->icsk_delack_timer, icsk->icsk_ack.timeout); - goto out; - } - icsk->icsk_ack.pending &= ~ICSK_ACK_TIMER; - - if (!skb_queue_empty(&tp->ucopy.prequeue)) { - struct sk_buff *skb; - - __NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPSCHEDULERFAILED); - - while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) - sk_backlog_rcv(sk, skb); - - tp->ucopy.memory = 0; - } - - if (inet_csk_ack_scheduled(sk)) { - if (!icsk->icsk_ack.pingpong) { - /* Delayed ACK missed: inflate ATO. */ - icsk->icsk_ack.ato = min(icsk->icsk_ack.ato << 1, icsk->icsk_rto); - } else { - /* Delayed ACK missed: leave pingpong mode and - * deflate ATO. - */ - icsk->icsk_ack.pingpong = 0; - icsk->icsk_ack.ato = TCP_ATO_MIN; - } - tcp_send_ack(sk); - __NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKS); - } - -out: - if (tcp_under_memory_pressure(sk)) - sk_mem_reclaim(sk); -} - - -/** - * tcp_delack_timer() - The TCP delayed ACK timeout handler - * @data: Pointer to the current socket. (gets casted to struct sock *) - * - * This function gets (indirectly) called when the kernel timer for a TCP packet - * of this socket expires. Calls tcp_delack_timer_handler() to do the actual work. - * - * Returns: Nothing (void) - */ -static void tcp_delack_timer(unsigned long data) -{ - struct sock *sk = (struct sock *)data; - - bh_lock_sock(sk); - if (!sock_owned_by_user(sk)) { - tcp_delack_timer_handler(sk); - } else { - inet_csk(sk)->icsk_ack.blocked = 1; - __NET_INC_STATS(sock_net(sk), LINUX_MIB_DELAYEDACKLOCKED); - /* deleguate our work to tcp_release_cb() */ - if (!test_and_set_bit(TCP_DELACK_TIMER_DEFERRED, &tcp_sk(sk)->tsq_flags)) - sock_hold(sk); - } - bh_unlock_sock(sk); - sock_put(sk); -} - -static void tcp_probe_timer(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - int max_probes; - u32 start_ts; - - if (tp->packets_out || !tcp_send_head(sk)) { - icsk->icsk_probes_out = 0; - return; - } - - /* RFC 1122 4.2.2.17 requires the sender to stay open indefinitely as - * long as the receiver continues to respond probes. We support this by - * default and reset icsk_probes_out with incoming ACKs. But if the - * socket is orphaned or the user specifies TCP_USER_TIMEOUT, we - * kill the socket when the retry count and the time exceeds the - * corresponding system limit. We also implement similar policy when - * we use RTO to probe window in tcp_retransmit_timer(). - */ - start_ts = tcp_skb_timestamp(tcp_send_head(sk)); - if (!start_ts) - skb_mstamp_get(&tcp_send_head(sk)->skb_mstamp); - else if (icsk->icsk_user_timeout && - (s32)(tcp_time_stamp - start_ts) > icsk->icsk_user_timeout) - goto abort; - - max_probes = sock_net(sk)->ipv4.sysctl_tcp_retries2; - if (sock_flag(sk, SOCK_DEAD)) { - const bool alive = inet_csk_rto_backoff(icsk, TCP_RTO_MAX) < TCP_RTO_MAX; - - max_probes = tcp_orphan_retries(sk, alive); - if (!alive && icsk->icsk_backoff >= max_probes) - goto abort; - if (tcp_out_of_resources(sk, true)) - return; - } - - if (icsk->icsk_probes_out > max_probes) { -abort: tcp_write_err(sk); - } else { - /* Only send another probe if we didn't close things up. */ - tcp_send_probe0(sk); - } -} - -/* - * Timer for Fast Open socket to retransmit SYNACK. Note that the - * sk here is the child socket, not the parent (listener) socket. - */ -static void tcp_fastopen_synack_timer(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - int max_retries = icsk->icsk_syn_retries ? : - sock_net(sk)->ipv4.sysctl_tcp_synack_retries + 1; /* add one more retry for fastopen */ - struct request_sock *req; - - req = tcp_sk(sk)->fastopen_rsk; - req->rsk_ops->syn_ack_timeout(req); - - if (req->num_timeout >= max_retries) { - tcp_write_err(sk); - return; - } - /* XXX (TFO) - Unlike regular SYN-ACK retransmit, we ignore error - * returned from rtx_syn_ack() to make it more persistent like - * regular retransmit because if the child socket has been accepted - * it's not good to give up too easily. - */ - inet_rtx_syn_ack(sk, req); - req->num_timeout++; - icsk->icsk_retransmits++; - inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, - TCP_TIMEOUT_INIT << req->num_timeout, TCP_RTO_MAX); -} - - -/** - * tcp_retransmit_timer() - The TCP retransmit timeout handler - * @sk: Pointer to the current socket. - * - * This function gets called when the kernel timer for a TCP packet - * of this socket expires. - * - * It handles retransmission, timer adjustment and other necesarry measures. - * - * Returns: Nothing (void) - */ -void tcp_retransmit_timer(struct sock *sk) -{ - struct tcp_sock *tp = tcp_sk(sk); - struct net *net = sock_net(sk); - struct inet_connection_sock *icsk = inet_csk(sk); - - if (tp->fastopen_rsk) { - WARN_ON_ONCE(sk->sk_state != TCP_SYN_RECV && - sk->sk_state != TCP_FIN_WAIT1); - tcp_fastopen_synack_timer(sk); - /* Before we receive ACK to our SYN-ACK don't retransmit - * anything else (e.g., data or FIN segments). - */ - return; - } - if (!tp->packets_out) - goto out; - - WARN_ON(tcp_write_queue_empty(sk)); - - tp->tlp_high_seq = 0; - - if (!tp->snd_wnd && !sock_flag(sk, SOCK_DEAD) && - !((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))) { - /* Receiver dastardly shrinks window. Our retransmits - * become zero probes, but we should not timeout this - * connection. If the socket is an orphan, time it out, - * we cannot allow such beasts to hang infinitely. - */ - struct inet_sock *inet = inet_sk(sk); - if (sk->sk_family == AF_INET) { - net_dbg_ratelimited("Peer %pI4:%u/%u unexpectedly shrunk window %u:%u (repaired)\n", - &inet->inet_daddr, - ntohs(inet->inet_dport), - inet->inet_num, - tp->snd_una, tp->snd_nxt); - } -#if IS_ENABLED(CONFIG_IPV6) - else if (sk->sk_family == AF_INET6) { - net_dbg_ratelimited("Peer %pI6:%u/%u unexpectedly shrunk window %u:%u (repaired)\n", - &sk->sk_v6_daddr, - ntohs(inet->inet_dport), - inet->inet_num, - tp->snd_una, tp->snd_nxt); - } -#endif - if (tcp_time_stamp - tp->rcv_tstamp > TCP_RTO_MAX) { - tcp_write_err(sk); - goto out; - } - tcp_enter_loss(sk); - tcp_retransmit_skb(sk, tcp_write_queue_head(sk), 1); - __sk_dst_reset(sk); - goto out_reset_timer; - } - - if (tcp_write_timeout(sk)) - goto out; - - if (icsk->icsk_retransmits == 0) { - int mib_idx; - - if (icsk->icsk_ca_state == TCP_CA_Recovery) { - if (tcp_is_sack(tp)) - mib_idx = LINUX_MIB_TCPSACKRECOVERYFAIL; - else - mib_idx = LINUX_MIB_TCPRENORECOVERYFAIL; - } else if (icsk->icsk_ca_state == TCP_CA_Loss) { - mib_idx = LINUX_MIB_TCPLOSSFAILURES; - } else if ((icsk->icsk_ca_state == TCP_CA_Disorder) || - tp->sacked_out) { - if (tcp_is_sack(tp)) - mib_idx = LINUX_MIB_TCPSACKFAILURES; - else - mib_idx = LINUX_MIB_TCPRENOFAILURES; - } else { - mib_idx = LINUX_MIB_TCPTIMEOUTS; - } - __NET_INC_STATS(sock_net(sk), mib_idx); - } - - tcp_enter_loss(sk); - - if (tcp_retransmit_skb(sk, tcp_write_queue_head(sk), 1) > 0) { - /* Retransmission failed because of local congestion, - * do not backoff. - */ - if (!icsk->icsk_retransmits) - icsk->icsk_retransmits = 1; - inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, - min(icsk->icsk_rto, TCP_RESOURCE_PROBE_INTERVAL), - TCP_RTO_MAX); - goto out; - } - - /* Increase the timeout each time we retransmit. Note that - * we do not increase the rtt estimate. rto is initialized - * from rtt, but increases here. Jacobson (SIGCOMM 88) suggests - * that doubling rto each time is the least we can get away with. - * In KA9Q, Karn uses this for the first few times, and then - * goes to quadratic. netBSD doubles, but only goes up to *64, - * and clamps at 1 to 64 sec afterwards. Note that 120 sec is - * defined in the protocol as the maximum possible RTT. I guess - * we'll have to use something other than TCP to talk to the - * University of Mars. - * - * PAWS allows us longer timeouts and large windows, so once - * implemented ftp to mars will work nicely. We will have to fix - * the 120 second clamps though! - */ - icsk->icsk_backoff++; - icsk->icsk_retransmits++; - -out_reset_timer: - /* If stream is thin, use linear timeouts. Since 'icsk_backoff' is - * used to reset timer, set to 0. Recalculate 'icsk_rto' as this - * might be increased if the stream oscillates between thin and thick, - * thus the old value might already be too high compared to the value - * set by 'tcp_set_rto' in tcp_input.c which resets the rto without - * backoff. Limit to TCP_THIN_LINEAR_RETRIES before initiating - * exponential backoff behaviour to avoid continue hammering - * linear-timeout retransmissions into a black hole - */ - if (sk->sk_state == TCP_ESTABLISHED && - (tp->thin_lto || sysctl_tcp_thin_linear_timeouts) && - tcp_stream_is_thin(tp) && - icsk->icsk_retransmits <= TCP_THIN_LINEAR_RETRIES) { - icsk->icsk_backoff = 0; - icsk->icsk_rto = min(__tcp_set_rto(tp), TCP_RTO_MAX); - } else { - /* Use normal (exponential) backoff */ - icsk->icsk_rto = min(icsk->icsk_rto << 1, TCP_RTO_MAX); - } - inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto, TCP_RTO_MAX); - if (retransmits_timed_out(sk, net->ipv4.sysctl_tcp_retries1 + 1, 0, 0)) - __sk_dst_reset(sk); - -out:; -} - -/* Called with bottom-half processing disabled. - Called by tcp_write_timer() */ -void tcp_write_timer_handler(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - int event; - - if (sk->sk_state == TCP_CLOSE || !icsk->icsk_pending) - goto out; - - if (time_after(icsk->icsk_timeout, jiffies)) { - sk_reset_timer(sk, &icsk->icsk_retransmit_timer, icsk->icsk_timeout); - goto out; - } - - event = icsk->icsk_pending; - - switch (event) { - case ICSK_TIME_EARLY_RETRANS: - tcp_resume_early_retransmit(sk); - break; - case ICSK_TIME_LOSS_PROBE: - tcp_send_loss_probe(sk); - break; - case ICSK_TIME_RETRANS: - icsk->icsk_pending = 0; - tcp_retransmit_timer(sk); - break; - case ICSK_TIME_PROBE0: - icsk->icsk_pending = 0; - tcp_probe_timer(sk); - break; - } - -out: - sk_mem_reclaim(sk); -} - -static void tcp_write_timer(unsigned long data) -{ - struct sock *sk = (struct sock *)data; - - bh_lock_sock(sk); - if (!sock_owned_by_user(sk)) { - tcp_write_timer_handler(sk); - } else { - /* delegate our work to tcp_release_cb() */ - if (!test_and_set_bit(TCP_WRITE_TIMER_DEFERRED, &tcp_sk(sk)->tsq_flags)) - sock_hold(sk); - } - bh_unlock_sock(sk); - sock_put(sk); -} - -void tcp_syn_ack_timeout(const struct request_sock *req) -{ - struct net *net = read_pnet(&inet_rsk(req)->ireq_net); - - __NET_INC_STATS(net, LINUX_MIB_TCPTIMEOUTS); -} -EXPORT_SYMBOL(tcp_syn_ack_timeout); - -void tcp_set_keepalive(struct sock *sk, int val) -{ - if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) - return; - - if (val && !sock_flag(sk, SOCK_KEEPOPEN)) - inet_csk_reset_keepalive_timer(sk, keepalive_time_when(tcp_sk(sk))); - else if (!val) - inet_csk_delete_keepalive_timer(sk); -} - - -static void tcp_keepalive_timer (unsigned long data) -{ - struct sock *sk = (struct sock *) data; - struct inet_connection_sock *icsk = inet_csk(sk); - struct tcp_sock *tp = tcp_sk(sk); - u32 elapsed; - - /* Only process if socket is not in use. */ - bh_lock_sock(sk); - if (sock_owned_by_user(sk)) { - /* Try again later. */ - inet_csk_reset_keepalive_timer (sk, HZ/20); - goto out; - } - - if (sk->sk_state == TCP_LISTEN) { - pr_err("Hmm... keepalive on a LISTEN ???\n"); - goto out; - } - - if (sk->sk_state == TCP_FIN_WAIT2 && sock_flag(sk, SOCK_DEAD)) { - if (tp->linger2 >= 0) { - const int tmo = tcp_fin_time(sk) - TCP_TIMEWAIT_LEN; - - if (tmo > 0) { - tcp_time_wait(sk, TCP_FIN_WAIT2, tmo); - goto out; - } - } - tcp_send_active_reset(sk, GFP_ATOMIC); - goto death; - } - - if (!sock_flag(sk, SOCK_KEEPOPEN) || sk->sk_state == TCP_CLOSE) - goto out; - - elapsed = keepalive_time_when(tp); - - /* It is alive without keepalive 8) */ - if (tp->packets_out || tcp_send_head(sk)) - goto resched; - - elapsed = keepalive_time_elapsed(tp); - - if (elapsed >= keepalive_time_when(tp)) { - /* If the TCP_USER_TIMEOUT option is enabled, use that - * to determine when to timeout instead. - */ - if ((icsk->icsk_user_timeout != 0 && - elapsed >= icsk->icsk_user_timeout && - icsk->icsk_probes_out > 0) || - (icsk->icsk_user_timeout == 0 && - icsk->icsk_probes_out >= keepalive_probes(tp))) { - tcp_send_active_reset(sk, GFP_ATOMIC); - tcp_write_err(sk); - goto out; - } - if (tcp_write_wakeup(sk, LINUX_MIB_TCPKEEPALIVE) <= 0) { - icsk->icsk_probes_out++; - elapsed = keepalive_intvl_when(tp); - } else { - /* If keepalive was lost due to local congestion, - * try harder. - */ - elapsed = TCP_RESOURCE_PROBE_INTERVAL; - } - } else { - /* It is tp->rcv_tstamp + keepalive_time_when(tp) */ - elapsed = keepalive_time_when(tp) - elapsed; - } - - sk_mem_reclaim(sk); - -resched: - inet_csk_reset_keepalive_timer (sk, elapsed); - goto out; - -death: - tcp_done(sk); - -out: - bh_unlock_sock(sk); - sock_put(sk); -} - -void tcp_init_xmit_timers(struct sock *sk) -{ - inet_csk_init_xmit_timers(sk, &tcp_write_timer, &tcp_delack_timer, - &tcp_keepalive_timer); -} diff --git a/src/linux/net/ipv4/tunnel4.c b/src/linux/net/ipv4/tunnel4.c deleted file mode 100644 index ec35eaa..0000000 --- a/src/linux/net/ipv4/tunnel4.c +++ /dev/null @@ -1,250 +0,0 @@ -/* tunnel4.c: Generic IP tunnel transformer. - * - * Copyright (C) 2003 David S. Miller (davem@redhat.com) - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct xfrm_tunnel __rcu *tunnel4_handlers __read_mostly; -static struct xfrm_tunnel __rcu *tunnel64_handlers __read_mostly; -static struct xfrm_tunnel __rcu *tunnelmpls4_handlers __read_mostly; -static DEFINE_MUTEX(tunnel4_mutex); - -static inline struct xfrm_tunnel __rcu **fam_handlers(unsigned short family) -{ - return (family == AF_INET) ? &tunnel4_handlers : - (family == AF_INET6) ? &tunnel64_handlers : - &tunnelmpls4_handlers; -} - -int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family) -{ - struct xfrm_tunnel __rcu **pprev; - struct xfrm_tunnel *t; - - int ret = -EEXIST; - int priority = handler->priority; - - mutex_lock(&tunnel4_mutex); - - for (pprev = fam_handlers(family); - (t = rcu_dereference_protected(*pprev, - lockdep_is_held(&tunnel4_mutex))) != NULL; - pprev = &t->next) { - if (t->priority > priority) - break; - if (t->priority == priority) - goto err; - } - - handler->next = *pprev; - rcu_assign_pointer(*pprev, handler); - - ret = 0; - -err: - mutex_unlock(&tunnel4_mutex); - - return ret; -} -EXPORT_SYMBOL(xfrm4_tunnel_register); - -int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family) -{ - struct xfrm_tunnel __rcu **pprev; - struct xfrm_tunnel *t; - int ret = -ENOENT; - - mutex_lock(&tunnel4_mutex); - - for (pprev = fam_handlers(family); - (t = rcu_dereference_protected(*pprev, - lockdep_is_held(&tunnel4_mutex))) != NULL; - pprev = &t->next) { - if (t == handler) { - *pprev = handler->next; - ret = 0; - break; - } - } - - mutex_unlock(&tunnel4_mutex); - - synchronize_net(); - - return ret; -} -EXPORT_SYMBOL(xfrm4_tunnel_deregister); - -#define for_each_tunnel_rcu(head, handler) \ - for (handler = rcu_dereference(head); \ - handler != NULL; \ - handler = rcu_dereference(handler->next)) \ - -static int tunnel4_rcv(struct sk_buff *skb) -{ - struct xfrm_tunnel *handler; - - if (!pskb_may_pull(skb, sizeof(struct iphdr))) - goto drop; - - for_each_tunnel_rcu(tunnel4_handlers, handler) - if (!handler->handler(skb)) - return 0; - - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); - -drop: - kfree_skb(skb); - return 0; -} - -#if IS_ENABLED(CONFIG_IPV6) -static int tunnel64_rcv(struct sk_buff *skb) -{ - struct xfrm_tunnel *handler; - - if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) - goto drop; - - for_each_tunnel_rcu(tunnel64_handlers, handler) - if (!handler->handler(skb)) - return 0; - - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); - -drop: - kfree_skb(skb); - return 0; -} -#endif - -#if IS_ENABLED(CONFIG_MPLS) -static int tunnelmpls4_rcv(struct sk_buff *skb) -{ - struct xfrm_tunnel *handler; - - if (!pskb_may_pull(skb, sizeof(struct mpls_label))) - goto drop; - - for_each_tunnel_rcu(tunnelmpls4_handlers, handler) - if (!handler->handler(skb)) - return 0; - - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); - -drop: - kfree_skb(skb); - return 0; -} -#endif - -static void tunnel4_err(struct sk_buff *skb, u32 info) -{ - struct xfrm_tunnel *handler; - - for_each_tunnel_rcu(tunnel4_handlers, handler) - if (!handler->err_handler(skb, info)) - break; -} - -#if IS_ENABLED(CONFIG_IPV6) -static void tunnel64_err(struct sk_buff *skb, u32 info) -{ - struct xfrm_tunnel *handler; - - for_each_tunnel_rcu(tunnel64_handlers, handler) - if (!handler->err_handler(skb, info)) - break; -} -#endif - -#if IS_ENABLED(CONFIG_MPLS) -static void tunnelmpls4_err(struct sk_buff *skb, u32 info) -{ - struct xfrm_tunnel *handler; - - for_each_tunnel_rcu(tunnelmpls4_handlers, handler) - if (!handler->err_handler(skb, info)) - break; -} -#endif - -static const struct net_protocol tunnel4_protocol = { - .handler = tunnel4_rcv, - .err_handler = tunnel4_err, - .no_policy = 1, - .netns_ok = 1, -}; - -#if IS_ENABLED(CONFIG_IPV6) -static const struct net_protocol tunnel64_protocol = { - .handler = tunnel64_rcv, - .err_handler = tunnel64_err, - .no_policy = 1, - .netns_ok = 1, -}; -#endif - -#if IS_ENABLED(CONFIG_MPLS) -static const struct net_protocol tunnelmpls4_protocol = { - .handler = tunnelmpls4_rcv, - .err_handler = tunnelmpls4_err, - .no_policy = 1, - .netns_ok = 1, -}; -#endif - -static int __init tunnel4_init(void) -{ - if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) - goto err; -#if IS_ENABLED(CONFIG_IPV6) - if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) { - inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); - goto err; - } -#endif -#if IS_ENABLED(CONFIG_MPLS) - if (inet_add_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS)) { - inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); -#if IS_ENABLED(CONFIG_IPV6) - inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6); -#endif - goto err; - } -#endif - return 0; - -err: - pr_err("%s: can't add protocol\n", __func__); - return -EAGAIN; -} - -static void __exit tunnel4_fini(void) -{ -#if IS_ENABLED(CONFIG_MPLS) - if (inet_del_protocol(&tunnelmpls4_protocol, IPPROTO_MPLS)) - pr_err("tunnelmpls4 close: can't remove protocol\n"); -#endif -#if IS_ENABLED(CONFIG_IPV6) - if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6)) - pr_err("tunnel64 close: can't remove protocol\n"); -#endif - if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP)) - pr_err("tunnel4 close: can't remove protocol\n"); -} - -module_init(tunnel4_init); -module_exit(tunnel4_fini); -MODULE_LICENSE("GPL"); diff --git a/src/linux/net/ipv4/udp.c b/src/linux/net/ipv4/udp.c deleted file mode 100644 index 5bab6c3..0000000 --- a/src/linux/net/ipv4/udp.c +++ /dev/null @@ -1,2525 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * The User Datagram Protocol (UDP). - * - * Authors: Ross Biro - * Fred N. van Kempen, - * Arnt Gulbrandsen, - * Alan Cox, - * Hirokazu Takahashi, - * - * Fixes: - * Alan Cox : verify_area() calls - * Alan Cox : stopped close while in use off icmp - * messages. Not a fix but a botch that - * for udp at least is 'valid'. - * Alan Cox : Fixed icmp handling properly - * Alan Cox : Correct error for oversized datagrams - * Alan Cox : Tidied select() semantics. - * Alan Cox : udp_err() fixed properly, also now - * select and read wake correctly on errors - * Alan Cox : udp_send verify_area moved to avoid mem leak - * Alan Cox : UDP can count its memory - * Alan Cox : send to an unknown connection causes - * an ECONNREFUSED off the icmp, but - * does NOT close. - * Alan Cox : Switched to new sk_buff handlers. No more backlog! - * Alan Cox : Using generic datagram code. Even smaller and the PEEK - * bug no longer crashes it. - * Fred Van Kempen : Net2e support for sk->broadcast. - * Alan Cox : Uses skb_free_datagram - * Alan Cox : Added get/set sockopt support. - * Alan Cox : Broadcasting without option set returns EACCES. - * Alan Cox : No wakeup calls. Instead we now use the callbacks. - * Alan Cox : Use ip_tos and ip_ttl - * Alan Cox : SNMP Mibs - * Alan Cox : MSG_DONTROUTE, and 0.0.0.0 support. - * Matt Dillon : UDP length checks. - * Alan Cox : Smarter af_inet used properly. - * Alan Cox : Use new kernel side addressing. - * Alan Cox : Incorrect return on truncated datagram receive. - * Arnt Gulbrandsen : New udp_send and stuff - * Alan Cox : Cache last socket - * Alan Cox : Route cache - * Jon Peatfield : Minor efficiency fix to sendto(). - * Mike Shaver : RFC1122 checks. - * Alan Cox : Nonblocking error fix. - * Willy Konynenberg : Transparent proxying support. - * Mike McLagan : Routing by source - * David S. Miller : New socket lookup architecture. - * Last socket cache retained as it - * does have a high hit rate. - * Olaf Kirch : Don't linearise iovec on sendmsg. - * Andi Kleen : Some cleanups, cache destination entry - * for connect. - * Vitaly E. Lavrov : Transparent proxy revived after year coma. - * Melvin Smith : Check msg_name not msg_namelen in sendto(), - * return ENOTCONN for unconnected sockets (POSIX) - * Janos Farkas : don't deliver multi/broadcasts to a different - * bound-to-device socket - * Hirokazu Takahashi : HW checksumming for outgoing UDP - * datagrams. - * Hirokazu Takahashi : sendfile() on UDP works now. - * Arnaldo C. Melo : convert /proc/net/udp to seq_file - * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which - * Alexey Kuznetsov: allow both IPv4 and IPv6 sockets to bind - * a single port at the same time. - * Derek Atkins : Add Encapulation Support - * James Chapman : Add L2TP encapsulation type. - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#define pr_fmt(fmt) "UDP: " fmt - -#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 -#include -#include -#include -#include -#include -#include "udp_impl.h" -#include -#include - -struct udp_table udp_table __read_mostly; -EXPORT_SYMBOL(udp_table); - -long sysctl_udp_mem[3] __read_mostly; -EXPORT_SYMBOL(sysctl_udp_mem); - -int sysctl_udp_rmem_min __read_mostly; -EXPORT_SYMBOL(sysctl_udp_rmem_min); - -int sysctl_udp_wmem_min __read_mostly; -EXPORT_SYMBOL(sysctl_udp_wmem_min); - -atomic_long_t udp_memory_allocated; -EXPORT_SYMBOL(udp_memory_allocated); - -#define MAX_UDP_PORTS 65536 -#define PORTS_PER_CHAIN (MAX_UDP_PORTS / UDP_HTABLE_SIZE_MIN) - -static int udp_lib_lport_inuse(struct net *net, __u16 num, - const struct udp_hslot *hslot, - unsigned long *bitmap, - struct sock *sk, - int (*saddr_comp)(const struct sock *sk1, - const struct sock *sk2, - bool match_wildcard), - unsigned int log) -{ - struct sock *sk2; - kuid_t uid = sock_i_uid(sk); - - sk_for_each(sk2, &hslot->head) { - if (net_eq(sock_net(sk2), net) && - sk2 != sk && - (bitmap || udp_sk(sk2)->udp_port_hash == num) && - (!sk2->sk_reuse || !sk->sk_reuse) && - (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || - sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && - (!sk2->sk_reuseport || !sk->sk_reuseport || - rcu_access_pointer(sk->sk_reuseport_cb) || - !uid_eq(uid, sock_i_uid(sk2))) && - saddr_comp(sk, sk2, true)) { - if (!bitmap) - return 1; - __set_bit(udp_sk(sk2)->udp_port_hash >> log, bitmap); - } - } - return 0; -} - -/* - * Note: we still hold spinlock of primary hash chain, so no other writer - * can insert/delete a socket with local_port == num - */ -static int udp_lib_lport_inuse2(struct net *net, __u16 num, - struct udp_hslot *hslot2, - struct sock *sk, - int (*saddr_comp)(const struct sock *sk1, - const struct sock *sk2, - bool match_wildcard)) -{ - struct sock *sk2; - kuid_t uid = sock_i_uid(sk); - int res = 0; - - spin_lock(&hslot2->lock); - udp_portaddr_for_each_entry(sk2, &hslot2->head) { - if (net_eq(sock_net(sk2), net) && - sk2 != sk && - (udp_sk(sk2)->udp_port_hash == num) && - (!sk2->sk_reuse || !sk->sk_reuse) && - (!sk2->sk_bound_dev_if || !sk->sk_bound_dev_if || - sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && - (!sk2->sk_reuseport || !sk->sk_reuseport || - rcu_access_pointer(sk->sk_reuseport_cb) || - !uid_eq(uid, sock_i_uid(sk2))) && - saddr_comp(sk, sk2, true)) { - res = 1; - break; - } - } - spin_unlock(&hslot2->lock); - return res; -} - -static int udp_reuseport_add_sock(struct sock *sk, struct udp_hslot *hslot, - int (*saddr_same)(const struct sock *sk1, - const struct sock *sk2, - bool match_wildcard)) -{ - struct net *net = sock_net(sk); - kuid_t uid = sock_i_uid(sk); - struct sock *sk2; - - sk_for_each(sk2, &hslot->head) { - if (net_eq(sock_net(sk2), net) && - sk2 != sk && - sk2->sk_family == sk->sk_family && - ipv6_only_sock(sk2) == ipv6_only_sock(sk) && - (udp_sk(sk2)->udp_port_hash == udp_sk(sk)->udp_port_hash) && - (sk2->sk_bound_dev_if == sk->sk_bound_dev_if) && - sk2->sk_reuseport && uid_eq(uid, sock_i_uid(sk2)) && - (*saddr_same)(sk, sk2, false)) { - return reuseport_add_sock(sk, sk2); - } - } - - /* Initial allocation may have already happened via setsockopt */ - if (!rcu_access_pointer(sk->sk_reuseport_cb)) - return reuseport_alloc(sk); - return 0; -} - -/** - * udp_lib_get_port - UDP/-Lite port lookup for IPv4 and IPv6 - * - * @sk: socket struct in question - * @snum: port number to look up - * @saddr_comp: AF-dependent comparison of bound local IP addresses - * @hash2_nulladdr: AF-dependent hash value in secondary hash chains, - * with NULL address - */ -int udp_lib_get_port(struct sock *sk, unsigned short snum, - int (*saddr_comp)(const struct sock *sk1, - const struct sock *sk2, - bool match_wildcard), - unsigned int hash2_nulladdr) -{ - struct udp_hslot *hslot, *hslot2; - struct udp_table *udptable = sk->sk_prot->h.udp_table; - int error = 1; - struct net *net = sock_net(sk); - - if (!snum) { - int low, high, remaining; - unsigned int rand; - unsigned short first, last; - DECLARE_BITMAP(bitmap, PORTS_PER_CHAIN); - - inet_get_local_port_range(net, &low, &high); - remaining = (high - low) + 1; - - rand = prandom_u32(); - first = reciprocal_scale(rand, remaining) + low; - /* - * force rand to be an odd multiple of UDP_HTABLE_SIZE - */ - rand = (rand | 1) * (udptable->mask + 1); - last = first + udptable->mask + 1; - do { - hslot = udp_hashslot(udptable, net, first); - bitmap_zero(bitmap, PORTS_PER_CHAIN); - spin_lock_bh(&hslot->lock); - udp_lib_lport_inuse(net, snum, hslot, bitmap, sk, - saddr_comp, udptable->log); - - snum = first; - /* - * Iterate on all possible values of snum for this hash. - * Using steps of an odd multiple of UDP_HTABLE_SIZE - * give us randomization and full range coverage. - */ - do { - if (low <= snum && snum <= high && - !test_bit(snum >> udptable->log, bitmap) && - !inet_is_local_reserved_port(net, snum)) - goto found; - snum += rand; - } while (snum != first); - spin_unlock_bh(&hslot->lock); - } while (++first != last); - goto fail; - } else { - hslot = udp_hashslot(udptable, net, snum); - spin_lock_bh(&hslot->lock); - if (hslot->count > 10) { - int exist; - unsigned int slot2 = udp_sk(sk)->udp_portaddr_hash ^ snum; - - slot2 &= udptable->mask; - hash2_nulladdr &= udptable->mask; - - hslot2 = udp_hashslot2(udptable, slot2); - if (hslot->count < hslot2->count) - goto scan_primary_hash; - - exist = udp_lib_lport_inuse2(net, snum, hslot2, - sk, saddr_comp); - if (!exist && (hash2_nulladdr != slot2)) { - hslot2 = udp_hashslot2(udptable, hash2_nulladdr); - exist = udp_lib_lport_inuse2(net, snum, hslot2, - sk, saddr_comp); - } - if (exist) - goto fail_unlock; - else - goto found; - } -scan_primary_hash: - if (udp_lib_lport_inuse(net, snum, hslot, NULL, sk, - saddr_comp, 0)) - goto fail_unlock; - } -found: - inet_sk(sk)->inet_num = snum; - udp_sk(sk)->udp_port_hash = snum; - udp_sk(sk)->udp_portaddr_hash ^= snum; - if (sk_unhashed(sk)) { - if (sk->sk_reuseport && - udp_reuseport_add_sock(sk, hslot, saddr_comp)) { - inet_sk(sk)->inet_num = 0; - udp_sk(sk)->udp_port_hash = 0; - udp_sk(sk)->udp_portaddr_hash ^= snum; - goto fail_unlock; - } - - sk_add_node_rcu(sk, &hslot->head); - hslot->count++; - sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); - - hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash); - spin_lock(&hslot2->lock); - if (IS_ENABLED(CONFIG_IPV6) && sk->sk_reuseport && - sk->sk_family == AF_INET6) - hlist_add_tail_rcu(&udp_sk(sk)->udp_portaddr_node, - &hslot2->head); - else - hlist_add_head_rcu(&udp_sk(sk)->udp_portaddr_node, - &hslot2->head); - hslot2->count++; - spin_unlock(&hslot2->lock); - } - sock_set_flag(sk, SOCK_RCU_FREE); - error = 0; -fail_unlock: - spin_unlock_bh(&hslot->lock); -fail: - return error; -} -EXPORT_SYMBOL(udp_lib_get_port); - -/* match_wildcard == true: 0.0.0.0 equals to any IPv4 addresses - * match_wildcard == false: addresses must be exactly the same, i.e. - * 0.0.0.0 only equals to 0.0.0.0 - */ -int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2, - bool match_wildcard) -{ - struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); - - if (!ipv6_only_sock(sk2)) { - if (inet1->inet_rcv_saddr == inet2->inet_rcv_saddr) - return 1; - if (!inet1->inet_rcv_saddr || !inet2->inet_rcv_saddr) - return match_wildcard; - } - return 0; -} - -static u32 udp4_portaddr_hash(const struct net *net, __be32 saddr, - unsigned int port) -{ - return jhash_1word((__force u32)saddr, net_hash_mix(net)) ^ port; -} - -int udp_v4_get_port(struct sock *sk, unsigned short snum) -{ - unsigned int hash2_nulladdr = - udp4_portaddr_hash(sock_net(sk), htonl(INADDR_ANY), snum); - unsigned int hash2_partial = - udp4_portaddr_hash(sock_net(sk), inet_sk(sk)->inet_rcv_saddr, 0); - - /* precompute partial secondary hash */ - udp_sk(sk)->udp_portaddr_hash = hash2_partial; - return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal, hash2_nulladdr); -} - -static int compute_score(struct sock *sk, struct net *net, - __be32 saddr, __be16 sport, - __be32 daddr, unsigned short hnum, int dif) -{ - int score; - struct inet_sock *inet; - - if (!net_eq(sock_net(sk), net) || - udp_sk(sk)->udp_port_hash != hnum || - ipv6_only_sock(sk)) - return -1; - - score = (sk->sk_family == PF_INET) ? 2 : 1; - inet = inet_sk(sk); - - if (inet->inet_rcv_saddr) { - if (inet->inet_rcv_saddr != daddr) - return -1; - score += 4; - } - - if (inet->inet_daddr) { - if (inet->inet_daddr != saddr) - return -1; - score += 4; - } - - if (inet->inet_dport) { - if (inet->inet_dport != sport) - return -1; - score += 4; - } - - if (sk->sk_bound_dev_if) { - if (sk->sk_bound_dev_if != dif) - return -1; - score += 4; - } - if (sk->sk_incoming_cpu == raw_smp_processor_id()) - score++; - return score; -} - -static u32 udp_ehashfn(const struct net *net, const __be32 laddr, - const __u16 lport, const __be32 faddr, - const __be16 fport) -{ - static u32 udp_ehash_secret __read_mostly; - - net_get_random_once(&udp_ehash_secret, sizeof(udp_ehash_secret)); - - return __inet_ehashfn(laddr, lport, faddr, fport, - udp_ehash_secret + net_hash_mix(net)); -} - -/* called with rcu_read_lock() */ -static struct sock *udp4_lib_lookup2(struct net *net, - __be32 saddr, __be16 sport, - __be32 daddr, unsigned int hnum, int dif, - struct udp_hslot *hslot2, - struct sk_buff *skb) -{ - struct sock *sk, *result; - int score, badness, matches = 0, reuseport = 0; - u32 hash = 0; - - result = NULL; - badness = 0; - udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { - score = compute_score(sk, net, saddr, sport, - daddr, hnum, dif); - if (score > badness) { - reuseport = sk->sk_reuseport; - if (reuseport) { - hash = udp_ehashfn(net, daddr, hnum, - saddr, sport); - result = reuseport_select_sock(sk, hash, skb, - sizeof(struct udphdr)); - if (result) - return result; - matches = 1; - } - badness = score; - result = sk; - } else if (score == badness && reuseport) { - matches++; - if (reciprocal_scale(hash, matches) == 0) - result = sk; - hash = next_pseudo_random32(hash); - } - } - return result; -} - -/* UDP is nearly always wildcards out the wazoo, it makes no sense to try - * harder than this. -DaveM - */ -struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, - __be16 sport, __be32 daddr, __be16 dport, - int dif, struct udp_table *udptable, struct sk_buff *skb) -{ - struct sock *sk, *result; - unsigned short hnum = ntohs(dport); - unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask); - struct udp_hslot *hslot2, *hslot = &udptable->hash[slot]; - int score, badness, matches = 0, reuseport = 0; - u32 hash = 0; - - if (hslot->count > 10) { - hash2 = udp4_portaddr_hash(net, daddr, hnum); - slot2 = hash2 & udptable->mask; - hslot2 = &udptable->hash2[slot2]; - if (hslot->count < hslot2->count) - goto begin; - - result = udp4_lib_lookup2(net, saddr, sport, - daddr, hnum, dif, - hslot2, skb); - if (!result) { - unsigned int old_slot2 = slot2; - hash2 = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum); - slot2 = hash2 & udptable->mask; - /* avoid searching the same slot again. */ - if (unlikely(slot2 == old_slot2)) - return result; - - hslot2 = &udptable->hash2[slot2]; - if (hslot->count < hslot2->count) - goto begin; - - result = udp4_lib_lookup2(net, saddr, sport, - daddr, hnum, dif, - hslot2, skb); - } - return result; - } -begin: - result = NULL; - badness = 0; - sk_for_each_rcu(sk, &hslot->head) { - score = compute_score(sk, net, saddr, sport, - daddr, hnum, dif); - if (score > badness) { - reuseport = sk->sk_reuseport; - if (reuseport) { - hash = udp_ehashfn(net, daddr, hnum, - saddr, sport); - result = reuseport_select_sock(sk, hash, skb, - sizeof(struct udphdr)); - if (result) - return result; - matches = 1; - } - result = sk; - badness = score; - } else if (score == badness && reuseport) { - matches++; - if (reciprocal_scale(hash, matches) == 0) - result = sk; - hash = next_pseudo_random32(hash); - } - } - return result; -} -EXPORT_SYMBOL_GPL(__udp4_lib_lookup); - -static inline struct sock *__udp4_lib_lookup_skb(struct sk_buff *skb, - __be16 sport, __be16 dport, - struct udp_table *udptable) -{ - const struct iphdr *iph = ip_hdr(skb); - - return __udp4_lib_lookup(dev_net(skb->dev), iph->saddr, sport, - iph->daddr, dport, inet_iif(skb), - udptable, skb); -} - -struct sock *udp4_lib_lookup_skb(struct sk_buff *skb, - __be16 sport, __be16 dport) -{ - return __udp4_lib_lookup_skb(skb, sport, dport, &udp_table); -} -EXPORT_SYMBOL_GPL(udp4_lib_lookup_skb); - -/* Must be called under rcu_read_lock(). - * Does increment socket refcount. - */ -#if IS_ENABLED(CONFIG_NETFILTER_XT_MATCH_SOCKET) || \ - IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TPROXY) -struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport, - __be32 daddr, __be16 dport, int dif) -{ - struct sock *sk; - - sk = __udp4_lib_lookup(net, saddr, sport, daddr, dport, - dif, &udp_table, NULL); - if (sk && !atomic_inc_not_zero(&sk->sk_refcnt)) - sk = NULL; - return sk; -} -EXPORT_SYMBOL_GPL(udp4_lib_lookup); -#endif - -static inline bool __udp_is_mcast_sock(struct net *net, struct sock *sk, - __be16 loc_port, __be32 loc_addr, - __be16 rmt_port, __be32 rmt_addr, - int dif, unsigned short hnum) -{ - struct inet_sock *inet = inet_sk(sk); - - if (!net_eq(sock_net(sk), net) || - udp_sk(sk)->udp_port_hash != hnum || - (inet->inet_daddr && inet->inet_daddr != rmt_addr) || - (inet->inet_dport != rmt_port && inet->inet_dport) || - (inet->inet_rcv_saddr && inet->inet_rcv_saddr != loc_addr) || - ipv6_only_sock(sk) || - (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)) - return false; - if (!ip_mc_sf_allow(sk, loc_addr, rmt_addr, dif)) - return false; - return true; -} - -/* - * This routine is called by the ICMP module when it gets some - * sort of error condition. If err < 0 then the socket should - * be closed and the error returned to the user. If err > 0 - * it's just the icmp type << 8 | icmp code. - * Header points to the ip header of the error packet. We move - * on past this. Then (as it used to claim before adjustment) - * header points to the first 8 bytes of the udp header. We need - * to find the appropriate port. - */ - -void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable) -{ - struct inet_sock *inet; - const struct iphdr *iph = (const struct iphdr *)skb->data; - struct udphdr *uh = (struct udphdr *)(skb->data+(iph->ihl<<2)); - const int type = icmp_hdr(skb)->type; - const int code = icmp_hdr(skb)->code; - struct sock *sk; - int harderr; - int err; - struct net *net = dev_net(skb->dev); - - sk = __udp4_lib_lookup(net, iph->daddr, uh->dest, - iph->saddr, uh->source, skb->dev->ifindex, udptable, - NULL); - if (!sk) { - __ICMP_INC_STATS(net, ICMP_MIB_INERRORS); - return; /* No socket for error */ - } - - err = 0; - harderr = 0; - inet = inet_sk(sk); - - switch (type) { - default: - case ICMP_TIME_EXCEEDED: - err = EHOSTUNREACH; - break; - case ICMP_SOURCE_QUENCH: - goto out; - case ICMP_PARAMETERPROB: - err = EPROTO; - harderr = 1; - break; - case ICMP_DEST_UNREACH: - if (code == ICMP_FRAG_NEEDED) { /* Path MTU discovery */ - ipv4_sk_update_pmtu(skb, sk, info); - if (inet->pmtudisc != IP_PMTUDISC_DONT) { - err = EMSGSIZE; - harderr = 1; - break; - } - goto out; - } - err = EHOSTUNREACH; - if (code <= NR_ICMP_UNREACH) { - harderr = icmp_err_convert[code].fatal; - err = icmp_err_convert[code].errno; - } - break; - case ICMP_REDIRECT: - ipv4_sk_redirect(skb, sk); - goto out; - } - - /* - * RFC1122: OK. Passes ICMP errors back to application, as per - * 4.1.3.3. - */ - if (!inet->recverr) { - if (!harderr || sk->sk_state != TCP_ESTABLISHED) - goto out; - } else - ip_icmp_error(sk, skb, err, uh->dest, info, (u8 *)(uh+1)); - - sk->sk_err = err; - sk->sk_error_report(sk); -out: - return; -} - -void udp_err(struct sk_buff *skb, u32 info) -{ - __udp4_lib_err(skb, info, &udp_table); -} - -/* - * Throw away all pending data and cancel the corking. Socket is locked. - */ -void udp_flush_pending_frames(struct sock *sk) -{ - struct udp_sock *up = udp_sk(sk); - - if (up->pending) { - up->len = 0; - up->pending = 0; - ip_flush_pending_frames(sk); - } -} -EXPORT_SYMBOL(udp_flush_pending_frames); - -/** - * udp4_hwcsum - handle outgoing HW checksumming - * @skb: sk_buff containing the filled-in UDP header - * (checksum field must be zeroed out) - * @src: source IP address - * @dst: destination IP address - */ -void udp4_hwcsum(struct sk_buff *skb, __be32 src, __be32 dst) -{ - struct udphdr *uh = udp_hdr(skb); - int offset = skb_transport_offset(skb); - int len = skb->len - offset; - int hlen = len; - __wsum csum = 0; - - if (!skb_has_frag_list(skb)) { - /* - * Only one fragment on the socket. - */ - skb->csum_start = skb_transport_header(skb) - skb->head; - skb->csum_offset = offsetof(struct udphdr, check); - uh->check = ~csum_tcpudp_magic(src, dst, len, - IPPROTO_UDP, 0); - } else { - struct sk_buff *frags; - - /* - * HW-checksum won't work as there are two or more - * fragments on the socket so that all csums of sk_buffs - * should be together - */ - skb_walk_frags(skb, frags) { - csum = csum_add(csum, frags->csum); - hlen -= frags->len; - } - - csum = skb_checksum(skb, offset, hlen, csum); - skb->ip_summed = CHECKSUM_NONE; - - uh->check = csum_tcpudp_magic(src, dst, len, IPPROTO_UDP, csum); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - } -} -EXPORT_SYMBOL_GPL(udp4_hwcsum); - -/* Function to set UDP checksum for an IPv4 UDP packet. This is intended - * for the simple case like when setting the checksum for a UDP tunnel. - */ -void udp_set_csum(bool nocheck, struct sk_buff *skb, - __be32 saddr, __be32 daddr, int len) -{ - struct udphdr *uh = udp_hdr(skb); - - if (nocheck) { - uh->check = 0; - } else if (skb_is_gso(skb)) { - uh->check = ~udp_v4_check(len, saddr, daddr, 0); - } else if (skb->ip_summed == CHECKSUM_PARTIAL) { - uh->check = 0; - uh->check = udp_v4_check(len, saddr, daddr, lco_csum(skb)); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - } else { - skb->ip_summed = CHECKSUM_PARTIAL; - skb->csum_start = skb_transport_header(skb) - skb->head; - skb->csum_offset = offsetof(struct udphdr, check); - uh->check = ~udp_v4_check(len, saddr, daddr, 0); - } -} -EXPORT_SYMBOL(udp_set_csum); - -static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4) -{ - struct sock *sk = skb->sk; - struct inet_sock *inet = inet_sk(sk); - struct udphdr *uh; - int err = 0; - int is_udplite = IS_UDPLITE(sk); - int offset = skb_transport_offset(skb); - int len = skb->len - offset; - __wsum csum = 0; - - /* - * Create a UDP header - */ - uh = udp_hdr(skb); - uh->source = inet->inet_sport; - uh->dest = fl4->fl4_dport; - uh->len = htons(len); - uh->check = 0; - - if (is_udplite) /* UDP-Lite */ - csum = udplite_csum(skb); - - else if (sk->sk_no_check_tx) { /* UDP csum disabled */ - - skb->ip_summed = CHECKSUM_NONE; - goto send; - - } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ - - udp4_hwcsum(skb, fl4->saddr, fl4->daddr); - goto send; - - } else - csum = udp_csum(skb); - - /* add protocol-dependent pseudo-header */ - uh->check = csum_tcpudp_magic(fl4->saddr, fl4->daddr, len, - sk->sk_protocol, csum); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - -send: - err = ip_send_skb(sock_net(sk), skb); - if (err) { - if (err == -ENOBUFS && !inet->recverr) { - UDP_INC_STATS(sock_net(sk), - UDP_MIB_SNDBUFERRORS, is_udplite); - err = 0; - } - } else - UDP_INC_STATS(sock_net(sk), - UDP_MIB_OUTDATAGRAMS, is_udplite); - return err; -} - -/* - * Push out all pending data as one UDP datagram. Socket is locked. - */ -int udp_push_pending_frames(struct sock *sk) -{ - struct udp_sock *up = udp_sk(sk); - struct inet_sock *inet = inet_sk(sk); - struct flowi4 *fl4 = &inet->cork.fl.u.ip4; - struct sk_buff *skb; - int err = 0; - - skb = ip_finish_skb(sk, fl4); - if (!skb) - goto out; - - err = udp_send_skb(skb, fl4); - -out: - up->len = 0; - up->pending = 0; - return err; -} -EXPORT_SYMBOL(udp_push_pending_frames); - -int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) -{ - struct inet_sock *inet = inet_sk(sk); - struct udp_sock *up = udp_sk(sk); - struct flowi4 fl4_stack; - struct flowi4 *fl4; - int ulen = len; - struct ipcm_cookie ipc; - struct rtable *rt = NULL; - int free = 0; - int connected = 0; - __be32 daddr, faddr, saddr; - __be16 dport; - u8 tos; - int err, is_udplite = IS_UDPLITE(sk); - int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; - int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); - struct sk_buff *skb; - struct ip_options_data opt_copy; - - if (len > 0xFFFF) - return -EMSGSIZE; - - /* - * Check the flags. - */ - - if (msg->msg_flags & MSG_OOB) /* Mirror BSD error message compatibility */ - return -EOPNOTSUPP; - - ipc.opt = NULL; - ipc.tx_flags = 0; - ipc.ttl = 0; - ipc.tos = -1; - - getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; - - fl4 = &inet->cork.fl.u.ip4; - if (up->pending) { - /* - * There are pending frames. - * The socket lock must be held while it's corked. - */ - lock_sock(sk); - if (likely(up->pending)) { - if (unlikely(up->pending != AF_INET)) { - release_sock(sk); - return -EINVAL; - } - goto do_append_data; - } - release_sock(sk); - } - ulen += sizeof(struct udphdr); - - /* - * Get and verify the address. - */ - if (msg->msg_name) { - DECLARE_SOCKADDR(struct sockaddr_in *, usin, msg->msg_name); - if (msg->msg_namelen < sizeof(*usin)) - return -EINVAL; - if (usin->sin_family != AF_INET) { - if (usin->sin_family != AF_UNSPEC) - return -EAFNOSUPPORT; - } - - daddr = usin->sin_addr.s_addr; - dport = usin->sin_port; - if (dport == 0) - return -EINVAL; - } else { - if (sk->sk_state != TCP_ESTABLISHED) - return -EDESTADDRREQ; - daddr = inet->inet_daddr; - dport = inet->inet_dport; - /* Open fast path for connected socket. - Route will not be used, if at least one option is set. - */ - connected = 1; - } - - ipc.sockc.tsflags = sk->sk_tsflags; - ipc.addr = inet->inet_saddr; - ipc.oif = sk->sk_bound_dev_if; - - if (msg->msg_controllen) { - err = ip_cmsg_send(sk, msg, &ipc, sk->sk_family == AF_INET6); - if (unlikely(err)) { - kfree(ipc.opt); - return err; - } - if (ipc.opt) - free = 1; - connected = 0; - } - if (!ipc.opt) { - struct ip_options_rcu *inet_opt; - - rcu_read_lock(); - inet_opt = rcu_dereference(inet->inet_opt); - if (inet_opt) { - memcpy(&opt_copy, inet_opt, - sizeof(*inet_opt) + inet_opt->opt.optlen); - ipc.opt = &opt_copy.opt; - } - rcu_read_unlock(); - } - - saddr = ipc.addr; - ipc.addr = faddr = daddr; - - sock_tx_timestamp(sk, ipc.sockc.tsflags, &ipc.tx_flags); - - if (ipc.opt && ipc.opt->opt.srr) { - if (!daddr) - return -EINVAL; - faddr = ipc.opt->opt.faddr; - connected = 0; - } - tos = get_rttos(&ipc, inet); - if (sock_flag(sk, SOCK_LOCALROUTE) || - (msg->msg_flags & MSG_DONTROUTE) || - (ipc.opt && ipc.opt->opt.is_strictroute)) { - tos |= RTO_ONLINK; - connected = 0; - } - - if (ipv4_is_multicast(daddr)) { - if (!ipc.oif) - ipc.oif = inet->mc_index; - if (!saddr) - saddr = inet->mc_addr; - connected = 0; - } else if (!ipc.oif) - ipc.oif = inet->uc_index; - - if (connected) - rt = (struct rtable *)sk_dst_check(sk, 0); - - if (!rt) { - struct net *net = sock_net(sk); - __u8 flow_flags = inet_sk_flowi_flags(sk); - - fl4 = &fl4_stack; - - flowi4_init_output(fl4, ipc.oif, sk->sk_mark, tos, - RT_SCOPE_UNIVERSE, sk->sk_protocol, - flow_flags, - faddr, saddr, dport, inet->inet_sport); - - security_sk_classify_flow(sk, flowi4_to_flowi(fl4)); - rt = ip_route_output_flow(net, fl4, sk); - if (IS_ERR(rt)) { - err = PTR_ERR(rt); - rt = NULL; - if (err == -ENETUNREACH) - IP_INC_STATS(net, IPSTATS_MIB_OUTNOROUTES); - goto out; - } - - err = -EACCES; - if ((rt->rt_flags & RTCF_BROADCAST) && - !sock_flag(sk, SOCK_BROADCAST)) - goto out; - if (connected) - sk_dst_set(sk, dst_clone(&rt->dst)); - } - - if (msg->msg_flags&MSG_CONFIRM) - goto do_confirm; -back_from_confirm: - - saddr = fl4->saddr; - if (!ipc.addr) - daddr = ipc.addr = fl4->daddr; - - /* Lockless fast path for the non-corking case. */ - if (!corkreq) { - skb = ip_make_skb(sk, fl4, getfrag, msg, ulen, - sizeof(struct udphdr), &ipc, &rt, - msg->msg_flags); - err = PTR_ERR(skb); - if (!IS_ERR_OR_NULL(skb)) - err = udp_send_skb(skb, fl4); - goto out; - } - - lock_sock(sk); - if (unlikely(up->pending)) { - /* The socket is already corked while preparing it. */ - /* ... which is an evident application bug. --ANK */ - release_sock(sk); - - net_dbg_ratelimited("cork app bug 2\n"); - err = -EINVAL; - goto out; - } - /* - * Now cork the socket to pend data. - */ - fl4 = &inet->cork.fl.u.ip4; - fl4->daddr = daddr; - fl4->saddr = saddr; - fl4->fl4_dport = dport; - fl4->fl4_sport = inet->inet_sport; - up->pending = AF_INET; - -do_append_data: - up->len += ulen; - err = ip_append_data(sk, fl4, getfrag, msg, ulen, - sizeof(struct udphdr), &ipc, &rt, - corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); - if (err) - udp_flush_pending_frames(sk); - else if (!corkreq) - err = udp_push_pending_frames(sk); - else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) - up->pending = 0; - release_sock(sk); - -out: - ip_rt_put(rt); - if (free) - kfree(ipc.opt); - if (!err) - return len; - /* - * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting - * ENOBUFS might not be good (it's not tunable per se), but otherwise - * we don't have a good statistic (IpOutDiscards but it can be too many - * things). We could add another new stat but at least for now that - * seems like overkill. - */ - if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { - UDP_INC_STATS(sock_net(sk), - UDP_MIB_SNDBUFERRORS, is_udplite); - } - return err; - -do_confirm: - dst_confirm(&rt->dst); - if (!(msg->msg_flags&MSG_PROBE) || len) - goto back_from_confirm; - err = 0; - goto out; -} -EXPORT_SYMBOL(udp_sendmsg); - -int udp_sendpage(struct sock *sk, struct page *page, int offset, - size_t size, int flags) -{ - struct inet_sock *inet = inet_sk(sk); - struct udp_sock *up = udp_sk(sk); - int ret; - - if (flags & MSG_SENDPAGE_NOTLAST) - flags |= MSG_MORE; - - if (!up->pending) { - struct msghdr msg = { .msg_flags = flags|MSG_MORE }; - - /* Call udp_sendmsg to specify destination address which - * sendpage interface can't pass. - * This will succeed only when the socket is connected. - */ - ret = udp_sendmsg(sk, &msg, 0); - if (ret < 0) - return ret; - } - - lock_sock(sk); - - if (unlikely(!up->pending)) { - release_sock(sk); - - net_dbg_ratelimited("udp cork app bug 3\n"); - return -EINVAL; - } - - ret = ip_append_page(sk, &inet->cork.fl.u.ip4, - page, offset, size, flags); - if (ret == -EOPNOTSUPP) { - release_sock(sk); - return sock_no_sendpage(sk->sk_socket, page, offset, - size, flags); - } - if (ret < 0) { - udp_flush_pending_frames(sk); - goto out; - } - - up->len += size; - if (!(up->corkflag || (flags&MSG_MORE))) - ret = udp_push_pending_frames(sk); - if (!ret) - ret = size; -out: - release_sock(sk); - return ret; -} - -/** - * first_packet_length - return length of first packet in receive queue - * @sk: socket - * - * Drops all bad checksum frames, until a valid one is found. - * Returns the length of found skb, or -1 if none is found. - */ -static int first_packet_length(struct sock *sk) -{ - struct sk_buff_head list_kill, *rcvq = &sk->sk_receive_queue; - struct sk_buff *skb; - int res; - - __skb_queue_head_init(&list_kill); - - spin_lock_bh(&rcvq->lock); - while ((skb = skb_peek(rcvq)) != NULL && - udp_lib_checksum_complete(skb)) { - __UDP_INC_STATS(sock_net(sk), UDP_MIB_CSUMERRORS, - IS_UDPLITE(sk)); - __UDP_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, - IS_UDPLITE(sk)); - atomic_inc(&sk->sk_drops); - __skb_unlink(skb, rcvq); - __skb_queue_tail(&list_kill, skb); - } - res = skb ? skb->len : -1; - spin_unlock_bh(&rcvq->lock); - - if (!skb_queue_empty(&list_kill)) { - bool slow = lock_sock_fast(sk); - - __skb_queue_purge(&list_kill); - sk_mem_reclaim_partial(sk); - unlock_sock_fast(sk, slow); - } - return res; -} - -/* - * IOCTL requests applicable to the UDP protocol - */ - -int udp_ioctl(struct sock *sk, int cmd, unsigned long arg) -{ - switch (cmd) { - case SIOCOUTQ: - { - int amount = sk_wmem_alloc_get(sk); - - return put_user(amount, (int __user *)arg); - } - - case SIOCINQ: - { - int amount = max_t(int, 0, first_packet_length(sk)); - - return put_user(amount, (int __user *)arg); - } - - default: - return -ENOIOCTLCMD; - } - - return 0; -} -EXPORT_SYMBOL(udp_ioctl); - -/* - * This should be easy, if there is something there we - * return it, otherwise we block. - */ - -int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock, - int flags, int *addr_len) -{ - struct inet_sock *inet = inet_sk(sk); - DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name); - struct sk_buff *skb; - unsigned int ulen, copied; - int peeked, peeking, off; - int err; - int is_udplite = IS_UDPLITE(sk); - bool checksum_valid = false; - bool slow; - - if (flags & MSG_ERRQUEUE) - return ip_recv_error(sk, msg, len, addr_len); - -try_again: - peeking = off = sk_peek_offset(sk, flags); - skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), - &peeked, &off, &err); - if (!skb) - return err; - - ulen = skb->len; - copied = len; - if (copied > ulen - off) - copied = ulen - off; - else if (copied < ulen) - msg->msg_flags |= MSG_TRUNC; - - /* - * If checksum is needed at all, try to do it while copying the - * data. If the data is truncated, or if we only want a partial - * coverage checksum (UDP-Lite), do it before the copy. - */ - - if (copied < ulen || UDP_SKB_CB(skb)->partial_cov || peeking) { - checksum_valid = !udp_lib_checksum_complete(skb); - if (!checksum_valid) - goto csum_copy_err; - } - - if (checksum_valid || skb_csum_unnecessary(skb)) - err = skb_copy_datagram_msg(skb, off, msg, copied); - else { - err = skb_copy_and_csum_datagram_msg(skb, off, msg); - - if (err == -EINVAL) - goto csum_copy_err; - } - - if (unlikely(err)) { - trace_kfree_skb(skb, udp_recvmsg); - if (!peeked) { - atomic_inc(&sk->sk_drops); - UDP_INC_STATS(sock_net(sk), - UDP_MIB_INERRORS, is_udplite); - } - skb_free_datagram_locked(sk, skb); - return err; - } - - if (!peeked) - UDP_INC_STATS(sock_net(sk), - UDP_MIB_INDATAGRAMS, is_udplite); - - sock_recv_ts_and_drops(msg, sk, skb); - - /* Copy the address. */ - if (sin) { - sin->sin_family = AF_INET; - sin->sin_port = udp_hdr(skb)->source; - sin->sin_addr.s_addr = ip_hdr(skb)->saddr; - memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); - *addr_len = sizeof(*sin); - } - if (inet->cmsg_flags) - ip_cmsg_recv_offset(msg, skb, sizeof(struct udphdr), off); - - err = copied; - if (flags & MSG_TRUNC) - err = ulen; - - __skb_free_datagram_locked(sk, skb, peeking ? -err : err); - return err; - -csum_copy_err: - slow = lock_sock_fast(sk); - if (!skb_kill_datagram(sk, skb, flags)) { - UDP_INC_STATS(sock_net(sk), UDP_MIB_CSUMERRORS, is_udplite); - UDP_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, is_udplite); - } - unlock_sock_fast(sk, slow); - - /* starting over for a new packet, but check if we need to yield */ - cond_resched(); - msg->msg_flags &= ~MSG_TRUNC; - goto try_again; -} - -int __udp_disconnect(struct sock *sk, int flags) -{ - struct inet_sock *inet = inet_sk(sk); - /* - * 1003.1g - break association. - */ - - sk->sk_state = TCP_CLOSE; - inet->inet_daddr = 0; - inet->inet_dport = 0; - sock_rps_reset_rxhash(sk); - sk->sk_bound_dev_if = 0; - if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) - inet_reset_saddr(sk); - - if (!(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) { - sk->sk_prot->unhash(sk); - inet->inet_sport = 0; - } - sk_dst_reset(sk); - return 0; -} -EXPORT_SYMBOL(__udp_disconnect); - -int udp_disconnect(struct sock *sk, int flags) -{ - lock_sock(sk); - __udp_disconnect(sk, flags); - release_sock(sk); - return 0; -} -EXPORT_SYMBOL(udp_disconnect); - -void udp_lib_unhash(struct sock *sk) -{ - if (sk_hashed(sk)) { - struct udp_table *udptable = sk->sk_prot->h.udp_table; - struct udp_hslot *hslot, *hslot2; - - hslot = udp_hashslot(udptable, sock_net(sk), - udp_sk(sk)->udp_port_hash); - hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash); - - spin_lock_bh(&hslot->lock); - if (rcu_access_pointer(sk->sk_reuseport_cb)) - reuseport_detach_sock(sk); - if (sk_del_node_init_rcu(sk)) { - hslot->count--; - inet_sk(sk)->inet_num = 0; - sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); - - spin_lock(&hslot2->lock); - hlist_del_init_rcu(&udp_sk(sk)->udp_portaddr_node); - hslot2->count--; - spin_unlock(&hslot2->lock); - } - spin_unlock_bh(&hslot->lock); - } -} -EXPORT_SYMBOL(udp_lib_unhash); - -/* - * inet_rcv_saddr was changed, we must rehash secondary hash - */ -void udp_lib_rehash(struct sock *sk, u16 newhash) -{ - if (sk_hashed(sk)) { - struct udp_table *udptable = sk->sk_prot->h.udp_table; - struct udp_hslot *hslot, *hslot2, *nhslot2; - - hslot2 = udp_hashslot2(udptable, udp_sk(sk)->udp_portaddr_hash); - nhslot2 = udp_hashslot2(udptable, newhash); - udp_sk(sk)->udp_portaddr_hash = newhash; - - if (hslot2 != nhslot2 || - rcu_access_pointer(sk->sk_reuseport_cb)) { - hslot = udp_hashslot(udptable, sock_net(sk), - udp_sk(sk)->udp_port_hash); - /* we must lock primary chain too */ - spin_lock_bh(&hslot->lock); - if (rcu_access_pointer(sk->sk_reuseport_cb)) - reuseport_detach_sock(sk); - - if (hslot2 != nhslot2) { - spin_lock(&hslot2->lock); - hlist_del_init_rcu(&udp_sk(sk)->udp_portaddr_node); - hslot2->count--; - spin_unlock(&hslot2->lock); - - spin_lock(&nhslot2->lock); - hlist_add_head_rcu(&udp_sk(sk)->udp_portaddr_node, - &nhslot2->head); - nhslot2->count++; - spin_unlock(&nhslot2->lock); - } - - spin_unlock_bh(&hslot->lock); - } - } -} -EXPORT_SYMBOL(udp_lib_rehash); - -static void udp_v4_rehash(struct sock *sk) -{ - u16 new_hash = udp4_portaddr_hash(sock_net(sk), - inet_sk(sk)->inet_rcv_saddr, - inet_sk(sk)->inet_num); - udp_lib_rehash(sk, new_hash); -} - -int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) -{ - int rc; - - if (inet_sk(sk)->inet_daddr) { - sock_rps_save_rxhash(sk, skb); - sk_mark_napi_id(sk, skb); - sk_incoming_cpu_update(sk); - } - - rc = __sock_queue_rcv_skb(sk, skb); - if (rc < 0) { - int is_udplite = IS_UDPLITE(sk); - - /* Note that an ENOMEM error is charged twice */ - if (rc == -ENOMEM) - UDP_INC_STATS(sock_net(sk), UDP_MIB_RCVBUFERRORS, - is_udplite); - UDP_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, is_udplite); - kfree_skb(skb); - trace_udp_fail_queue_rcv_skb(rc, sk); - return -1; - } - - return 0; - -} - -static struct static_key udp_encap_needed __read_mostly; -void udp_encap_enable(void) -{ - if (!static_key_enabled(&udp_encap_needed)) - static_key_slow_inc(&udp_encap_needed); -} -EXPORT_SYMBOL(udp_encap_enable); - -/* returns: - * -1: error - * 0: success - * >0: "udp encap" protocol resubmission - * - * Note that in the success and error cases, the skb is assumed to - * have either been requeued or freed. - */ -int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) -{ - struct udp_sock *up = udp_sk(sk); - int rc; - int is_udplite = IS_UDPLITE(sk); - - /* - * Charge it to the socket, dropping if the queue is full. - */ - if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) - goto drop; - nf_reset(skb); - - if (static_key_false(&udp_encap_needed) && up->encap_type) { - int (*encap_rcv)(struct sock *sk, struct sk_buff *skb); - - /* - * This is an encapsulation socket so pass the skb to - * the socket's udp_encap_rcv() hook. Otherwise, just - * fall through and pass this up the UDP socket. - * up->encap_rcv() returns the following value: - * =0 if skb was successfully passed to the encap - * handler or was discarded by it. - * >0 if skb should be passed on to UDP. - * <0 if skb should be resubmitted as proto -N - */ - - /* if we're overly short, let UDP handle it */ - encap_rcv = ACCESS_ONCE(up->encap_rcv); - if (encap_rcv) { - int ret; - - /* Verify checksum before giving to encap */ - if (udp_lib_checksum_complete(skb)) - goto csum_error; - - ret = encap_rcv(sk, skb); - if (ret <= 0) { - __UDP_INC_STATS(sock_net(sk), - UDP_MIB_INDATAGRAMS, - is_udplite); - return -ret; - } - } - - /* FALLTHROUGH -- it's a UDP Packet */ - } - - /* - * UDP-Lite specific tests, ignored on UDP sockets - */ - if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { - - /* - * MIB statistics other than incrementing the error count are - * disabled for the following two types of errors: these depend - * on the application settings, not on the functioning of the - * protocol stack as such. - * - * RFC 3828 here recommends (sec 3.3): "There should also be a - * way ... to ... at least let the receiving application block - * delivery of packets with coverage values less than a value - * provided by the application." - */ - if (up->pcrlen == 0) { /* full coverage was set */ - net_dbg_ratelimited("UDPLite: partial coverage %d while full coverage %d requested\n", - UDP_SKB_CB(skb)->cscov, skb->len); - goto drop; - } - /* The next case involves violating the min. coverage requested - * by the receiver. This is subtle: if receiver wants x and x is - * greater than the buffersize/MTU then receiver will complain - * that it wants x while sender emits packets of smaller size y. - * Therefore the above ...()->partial_cov statement is essential. - */ - if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { - net_dbg_ratelimited("UDPLite: coverage %d too small, need min %d\n", - UDP_SKB_CB(skb)->cscov, up->pcrlen); - goto drop; - } - } - - if (rcu_access_pointer(sk->sk_filter) && - udp_lib_checksum_complete(skb)) - goto csum_error; - - if (sk_filter_trim_cap(sk, skb, sizeof(struct udphdr))) - goto drop; - - udp_csum_pull_header(skb); - if (sk_rcvqueues_full(sk, sk->sk_rcvbuf)) { - __UDP_INC_STATS(sock_net(sk), UDP_MIB_RCVBUFERRORS, - is_udplite); - goto drop; - } - - rc = 0; - - ipv4_pktinfo_prepare(sk, skb); - bh_lock_sock(sk); - if (!sock_owned_by_user(sk)) - rc = __udp_queue_rcv_skb(sk, skb); - else if (sk_add_backlog(sk, skb, sk->sk_rcvbuf)) { - bh_unlock_sock(sk); - goto drop; - } - bh_unlock_sock(sk); - - return rc; - -csum_error: - __UDP_INC_STATS(sock_net(sk), UDP_MIB_CSUMERRORS, is_udplite); -drop: - __UDP_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, is_udplite); - atomic_inc(&sk->sk_drops); - kfree_skb(skb); - return -1; -} - -/* For TCP sockets, sk_rx_dst is protected by socket lock - * For UDP, we use xchg() to guard against concurrent changes. - */ -static void udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst) -{ - struct dst_entry *old; - - dst_hold(dst); - old = xchg(&sk->sk_rx_dst, dst); - dst_release(old); -} - -/* - * Multicasts and broadcasts go to each listener. - * - * Note: called only from the BH handler context. - */ -static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb, - struct udphdr *uh, - __be32 saddr, __be32 daddr, - struct udp_table *udptable, - int proto) -{ - struct sock *sk, *first = NULL; - unsigned short hnum = ntohs(uh->dest); - struct udp_hslot *hslot = udp_hashslot(udptable, net, hnum); - unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10); - unsigned int offset = offsetof(typeof(*sk), sk_node); - int dif = skb->dev->ifindex; - struct hlist_node *node; - struct sk_buff *nskb; - - if (use_hash2) { - hash2_any = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum) & - udptable->mask; - hash2 = udp4_portaddr_hash(net, daddr, hnum) & udptable->mask; -start_lookup: - hslot = &udptable->hash2[hash2]; - offset = offsetof(typeof(*sk), __sk_common.skc_portaddr_node); - } - - sk_for_each_entry_offset_rcu(sk, node, &hslot->head, offset) { - if (!__udp_is_mcast_sock(net, sk, uh->dest, daddr, - uh->source, saddr, dif, hnum)) - continue; - - if (!first) { - first = sk; - continue; - } - nskb = skb_clone(skb, GFP_ATOMIC); - - if (unlikely(!nskb)) { - atomic_inc(&sk->sk_drops); - __UDP_INC_STATS(net, UDP_MIB_RCVBUFERRORS, - IS_UDPLITE(sk)); - __UDP_INC_STATS(net, UDP_MIB_INERRORS, - IS_UDPLITE(sk)); - continue; - } - if (udp_queue_rcv_skb(sk, nskb) > 0) - consume_skb(nskb); - } - - /* Also lookup *:port if we are using hash2 and haven't done so yet. */ - if (use_hash2 && hash2 != hash2_any) { - hash2 = hash2_any; - goto start_lookup; - } - - if (first) { - if (udp_queue_rcv_skb(first, skb) > 0) - consume_skb(skb); - } else { - kfree_skb(skb); - __UDP_INC_STATS(net, UDP_MIB_IGNOREDMULTI, - proto == IPPROTO_UDPLITE); - } - return 0; -} - -/* Initialize UDP checksum. If exited with zero value (success), - * CHECKSUM_UNNECESSARY means, that no more checks are required. - * Otherwise, csum completion requires chacksumming packet body, - * including udp header and folding it to skb->csum. - */ -static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, - int proto) -{ - int err; - - UDP_SKB_CB(skb)->partial_cov = 0; - UDP_SKB_CB(skb)->cscov = skb->len; - - if (proto == IPPROTO_UDPLITE) { - err = udplite_checksum_init(skb, uh); - if (err) - return err; - } - - /* Note, we are only interested in != 0 or == 0, thus the - * force to int. - */ - return (__force int)skb_checksum_init_zero_check(skb, proto, uh->check, - inet_compute_pseudo); -} - -/* - * All we need to do is get the socket, and then do a checksum. - */ - -int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, - int proto) -{ - struct sock *sk; - struct udphdr *uh; - unsigned short ulen; - struct rtable *rt = skb_rtable(skb); - __be32 saddr, daddr; - struct net *net = dev_net(skb->dev); - - /* - * Validate the packet. - */ - if (!pskb_may_pull(skb, sizeof(struct udphdr))) - goto drop; /* No space for header. */ - - uh = udp_hdr(skb); - ulen = ntohs(uh->len); - saddr = ip_hdr(skb)->saddr; - daddr = ip_hdr(skb)->daddr; - - if (ulen > skb->len) - goto short_packet; - - if (proto == IPPROTO_UDP) { - /* UDP validates ulen. */ - if (ulen < sizeof(*uh) || pskb_trim_rcsum(skb, ulen)) - goto short_packet; - uh = udp_hdr(skb); - } - - if (udp4_csum_init(skb, uh, proto)) - goto csum_error; - - sk = skb_steal_sock(skb); - if (sk) { - struct dst_entry *dst = skb_dst(skb); - int ret; - - if (unlikely(sk->sk_rx_dst != dst)) - udp_sk_rx_dst_set(sk, dst); - - ret = udp_queue_rcv_skb(sk, skb); - sock_put(sk); - /* a return value > 0 means to resubmit the input, but - * it wants the return to be -protocol, or 0 - */ - if (ret > 0) - return -ret; - return 0; - } - - if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST)) - return __udp4_lib_mcast_deliver(net, skb, uh, - saddr, daddr, udptable, proto); - - sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable); - if (sk) { - int ret; - - if (inet_get_convert_csum(sk) && uh->check && !IS_UDPLITE(sk)) - skb_checksum_try_convert(skb, IPPROTO_UDP, uh->check, - inet_compute_pseudo); - - ret = udp_queue_rcv_skb(sk, skb); - - /* a return value > 0 means to resubmit the input, but - * it wants the return to be -protocol, or 0 - */ - if (ret > 0) - return -ret; - return 0; - } - - if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) - goto drop; - nf_reset(skb); - - /* No socket. Drop packet silently, if checksum is wrong */ - if (udp_lib_checksum_complete(skb)) - goto csum_error; - - __UDP_INC_STATS(net, UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); - - /* - * Hmm. We got an UDP packet to a port to which we - * don't wanna listen. Ignore it. - */ - kfree_skb(skb); - return 0; - -short_packet: - net_dbg_ratelimited("UDP%s: short packet: From %pI4:%u %d/%d to %pI4:%u\n", - proto == IPPROTO_UDPLITE ? "Lite" : "", - &saddr, ntohs(uh->source), - ulen, skb->len, - &daddr, ntohs(uh->dest)); - goto drop; - -csum_error: - /* - * RFC1122: OK. Discards the bad packet silently (as far as - * the network is concerned, anyway) as per 4.1.3.4 (MUST). - */ - net_dbg_ratelimited("UDP%s: bad checksum. From %pI4:%u to %pI4:%u ulen %d\n", - proto == IPPROTO_UDPLITE ? "Lite" : "", - &saddr, ntohs(uh->source), &daddr, ntohs(uh->dest), - ulen); - __UDP_INC_STATS(net, UDP_MIB_CSUMERRORS, proto == IPPROTO_UDPLITE); -drop: - __UDP_INC_STATS(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); - kfree_skb(skb); - return 0; -} - -/* We can only early demux multicast if there is a single matching socket. - * If more than one socket found returns NULL - */ -static struct sock *__udp4_lib_mcast_demux_lookup(struct net *net, - __be16 loc_port, __be32 loc_addr, - __be16 rmt_port, __be32 rmt_addr, - int dif) -{ - struct sock *sk, *result; - unsigned short hnum = ntohs(loc_port); - unsigned int slot = udp_hashfn(net, hnum, udp_table.mask); - struct udp_hslot *hslot = &udp_table.hash[slot]; - - /* Do not bother scanning a too big list */ - if (hslot->count > 10) - return NULL; - - result = NULL; - sk_for_each_rcu(sk, &hslot->head) { - if (__udp_is_mcast_sock(net, sk, loc_port, loc_addr, - rmt_port, rmt_addr, dif, hnum)) { - if (result) - return NULL; - result = sk; - } - } - - return result; -} - -/* For unicast we should only early demux connected sockets or we can - * break forwarding setups. The chains here can be long so only check - * if the first socket is an exact match and if not move on. - */ -static struct sock *__udp4_lib_demux_lookup(struct net *net, - __be16 loc_port, __be32 loc_addr, - __be16 rmt_port, __be32 rmt_addr, - int dif) -{ - unsigned short hnum = ntohs(loc_port); - unsigned int hash2 = udp4_portaddr_hash(net, loc_addr, hnum); - unsigned int slot2 = hash2 & udp_table.mask; - struct udp_hslot *hslot2 = &udp_table.hash2[slot2]; - INET_ADDR_COOKIE(acookie, rmt_addr, loc_addr); - const __portpair ports = INET_COMBINED_PORTS(rmt_port, hnum); - struct sock *sk; - - udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { - if (INET_MATCH(sk, net, acookie, rmt_addr, - loc_addr, ports, dif)) - return sk; - /* Only check first socket in chain */ - break; - } - return NULL; -} - -void udp_v4_early_demux(struct sk_buff *skb) -{ - struct net *net = dev_net(skb->dev); - const struct iphdr *iph; - const struct udphdr *uh; - struct sock *sk = NULL; - struct dst_entry *dst; - int dif = skb->dev->ifindex; - int ours; - - /* validate the packet */ - if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct udphdr))) - return; - - iph = ip_hdr(skb); - uh = udp_hdr(skb); - - if (skb->pkt_type == PACKET_BROADCAST || - skb->pkt_type == PACKET_MULTICAST) { - struct in_device *in_dev = __in_dev_get_rcu(skb->dev); - - if (!in_dev) - return; - - /* we are supposed to accept bcast packets */ - if (skb->pkt_type == PACKET_MULTICAST) { - ours = ip_check_mc_rcu(in_dev, iph->daddr, iph->saddr, - iph->protocol); - if (!ours) - return; - } - - sk = __udp4_lib_mcast_demux_lookup(net, uh->dest, iph->daddr, - uh->source, iph->saddr, dif); - } else if (skb->pkt_type == PACKET_HOST) { - sk = __udp4_lib_demux_lookup(net, uh->dest, iph->daddr, - uh->source, iph->saddr, dif); - } - - if (!sk || !atomic_inc_not_zero_hint(&sk->sk_refcnt, 2)) - return; - - skb->sk = sk; - skb->destructor = sock_efree; - dst = READ_ONCE(sk->sk_rx_dst); - - if (dst) - dst = dst_check(dst, 0); - if (dst) { - /* DST_NOCACHE can not be used without taking a reference */ - if (dst->flags & DST_NOCACHE) { - if (likely(atomic_inc_not_zero(&dst->__refcnt))) - skb_dst_set(skb, dst); - } else { - skb_dst_set_noref(skb, dst); - } - } -} - -int udp_rcv(struct sk_buff *skb) -{ - return __udp4_lib_rcv(skb, &udp_table, IPPROTO_UDP); -} - -void udp_destroy_sock(struct sock *sk) -{ - struct udp_sock *up = udp_sk(sk); - bool slow = lock_sock_fast(sk); - udp_flush_pending_frames(sk); - unlock_sock_fast(sk, slow); - if (static_key_false(&udp_encap_needed) && up->encap_type) { - void (*encap_destroy)(struct sock *sk); - encap_destroy = ACCESS_ONCE(up->encap_destroy); - if (encap_destroy) - encap_destroy(sk); - } -} - -/* - * Socket option code for UDP - */ -int udp_lib_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen, - int (*push_pending_frames)(struct sock *)) -{ - struct udp_sock *up = udp_sk(sk); - int val, valbool; - int err = 0; - int is_udplite = IS_UDPLITE(sk); - - if (optlen < sizeof(int)) - return -EINVAL; - - if (get_user(val, (int __user *)optval)) - return -EFAULT; - - valbool = val ? 1 : 0; - - switch (optname) { - case UDP_CORK: - if (val != 0) { - up->corkflag = 1; - } else { - up->corkflag = 0; - lock_sock(sk); - push_pending_frames(sk); - release_sock(sk); - } - break; - - case UDP_ENCAP: - switch (val) { - case 0: - case UDP_ENCAP_ESPINUDP: - case UDP_ENCAP_ESPINUDP_NON_IKE: - up->encap_rcv = xfrm4_udp_encap_rcv; - /* FALLTHROUGH */ - case UDP_ENCAP_L2TPINUDP: - up->encap_type = val; - udp_encap_enable(); - break; - default: - err = -ENOPROTOOPT; - break; - } - break; - - case UDP_NO_CHECK6_TX: - up->no_check6_tx = valbool; - break; - - case UDP_NO_CHECK6_RX: - up->no_check6_rx = valbool; - break; - - /* - * UDP-Lite's partial checksum coverage (RFC 3828). - */ - /* The sender sets actual checksum coverage length via this option. - * The case coverage > packet length is handled by send module. */ - case UDPLITE_SEND_CSCOV: - if (!is_udplite) /* Disable the option on UDP sockets */ - return -ENOPROTOOPT; - if (val != 0 && val < 8) /* Illegal coverage: use default (8) */ - val = 8; - else if (val > USHRT_MAX) - val = USHRT_MAX; - up->pcslen = val; - up->pcflag |= UDPLITE_SEND_CC; - break; - - /* The receiver specifies a minimum checksum coverage value. To make - * sense, this should be set to at least 8 (as done below). If zero is - * used, this again means full checksum coverage. */ - case UDPLITE_RECV_CSCOV: - if (!is_udplite) /* Disable the option on UDP sockets */ - return -ENOPROTOOPT; - if (val != 0 && val < 8) /* Avoid silly minimal values. */ - val = 8; - else if (val > USHRT_MAX) - val = USHRT_MAX; - up->pcrlen = val; - up->pcflag |= UDPLITE_RECV_CC; - break; - - default: - err = -ENOPROTOOPT; - break; - } - - return err; -} -EXPORT_SYMBOL(udp_lib_setsockopt); - -int udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen) -{ - if (level == SOL_UDP || level == SOL_UDPLITE) - return udp_lib_setsockopt(sk, level, optname, optval, optlen, - udp_push_pending_frames); - return ip_setsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -int compat_udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen) -{ - if (level == SOL_UDP || level == SOL_UDPLITE) - return udp_lib_setsockopt(sk, level, optname, optval, optlen, - udp_push_pending_frames); - return compat_ip_setsockopt(sk, level, optname, optval, optlen); -} -#endif - -int udp_lib_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - struct udp_sock *up = udp_sk(sk); - int val, len; - - if (get_user(len, optlen)) - return -EFAULT; - - len = min_t(unsigned int, len, sizeof(int)); - - if (len < 0) - return -EINVAL; - - switch (optname) { - case UDP_CORK: - val = up->corkflag; - break; - - case UDP_ENCAP: - val = up->encap_type; - break; - - case UDP_NO_CHECK6_TX: - val = up->no_check6_tx; - break; - - case UDP_NO_CHECK6_RX: - val = up->no_check6_rx; - break; - - /* The following two cannot be changed on UDP sockets, the return is - * always 0 (which corresponds to the full checksum coverage of UDP). */ - case UDPLITE_SEND_CSCOV: - val = up->pcslen; - break; - - case UDPLITE_RECV_CSCOV: - val = up->pcrlen; - break; - - default: - return -ENOPROTOOPT; - } - - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(optval, &val, len)) - return -EFAULT; - return 0; -} -EXPORT_SYMBOL(udp_lib_getsockopt); - -int udp_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (level == SOL_UDP || level == SOL_UDPLITE) - return udp_lib_getsockopt(sk, level, optname, optval, optlen); - return ip_getsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -int compat_udp_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (level == SOL_UDP || level == SOL_UDPLITE) - return udp_lib_getsockopt(sk, level, optname, optval, optlen); - return compat_ip_getsockopt(sk, level, optname, optval, optlen); -} -#endif -/** - * udp_poll - wait for a UDP event. - * @file - file struct - * @sock - socket - * @wait - poll table - * - * This is same as datagram poll, except for the special case of - * blocking sockets. If application is using a blocking fd - * and a packet with checksum error is in the queue; - * then it could get return from select indicating data available - * but then block when reading it. Add special case code - * to work around these arguably broken applications. - */ -unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait) -{ - unsigned int mask = datagram_poll(file, sock, wait); - struct sock *sk = sock->sk; - - sock_rps_record_flow(sk); - - /* Check for false positives due to checksum errors */ - if ((mask & POLLRDNORM) && !(file->f_flags & O_NONBLOCK) && - !(sk->sk_shutdown & RCV_SHUTDOWN) && first_packet_length(sk) == -1) - mask &= ~(POLLIN | POLLRDNORM); - - return mask; - -} -EXPORT_SYMBOL(udp_poll); - -int udp_abort(struct sock *sk, int err) -{ - lock_sock(sk); - - sk->sk_err = err; - sk->sk_error_report(sk); - __udp_disconnect(sk, 0); - - release_sock(sk); - - return 0; -} -EXPORT_SYMBOL_GPL(udp_abort); - -struct proto udp_prot = { - .name = "UDP", - .owner = THIS_MODULE, - .close = udp_lib_close, - .connect = ip4_datagram_connect, - .disconnect = udp_disconnect, - .ioctl = udp_ioctl, - .destroy = udp_destroy_sock, - .setsockopt = udp_setsockopt, - .getsockopt = udp_getsockopt, - .sendmsg = udp_sendmsg, - .recvmsg = udp_recvmsg, - .sendpage = udp_sendpage, - .backlog_rcv = __udp_queue_rcv_skb, - .release_cb = ip4_datagram_release_cb, - .hash = udp_lib_hash, - .unhash = udp_lib_unhash, - .rehash = udp_v4_rehash, - .get_port = udp_v4_get_port, - .memory_allocated = &udp_memory_allocated, - .sysctl_mem = sysctl_udp_mem, - .sysctl_wmem = &sysctl_udp_wmem_min, - .sysctl_rmem = &sysctl_udp_rmem_min, - .obj_size = sizeof(struct udp_sock), - .h.udp_table = &udp_table, -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_udp_setsockopt, - .compat_getsockopt = compat_udp_getsockopt, -#endif - .diag_destroy = udp_abort, -}; -EXPORT_SYMBOL(udp_prot); - -/* ------------------------------------------------------------------------ */ -#ifdef CONFIG_PROC_FS - -static struct sock *udp_get_first(struct seq_file *seq, int start) -{ - struct sock *sk; - struct udp_iter_state *state = seq->private; - struct net *net = seq_file_net(seq); - - for (state->bucket = start; state->bucket <= state->udp_table->mask; - ++state->bucket) { - struct udp_hslot *hslot = &state->udp_table->hash[state->bucket]; - - if (hlist_empty(&hslot->head)) - continue; - - spin_lock_bh(&hslot->lock); - sk_for_each(sk, &hslot->head) { - if (!net_eq(sock_net(sk), net)) - continue; - if (sk->sk_family == state->family) - goto found; - } - spin_unlock_bh(&hslot->lock); - } - sk = NULL; -found: - return sk; -} - -static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk) -{ - struct udp_iter_state *state = seq->private; - struct net *net = seq_file_net(seq); - - do { - sk = sk_next(sk); - } while (sk && (!net_eq(sock_net(sk), net) || sk->sk_family != state->family)); - - if (!sk) { - if (state->bucket <= state->udp_table->mask) - spin_unlock_bh(&state->udp_table->hash[state->bucket].lock); - return udp_get_first(seq, state->bucket + 1); - } - return sk; -} - -static struct sock *udp_get_idx(struct seq_file *seq, loff_t pos) -{ - struct sock *sk = udp_get_first(seq, 0); - - if (sk) - while (pos && (sk = udp_get_next(seq, sk)) != NULL) - --pos; - return pos ? NULL : sk; -} - -static void *udp_seq_start(struct seq_file *seq, loff_t *pos) -{ - struct udp_iter_state *state = seq->private; - state->bucket = MAX_UDP_PORTS; - - return *pos ? udp_get_idx(seq, *pos-1) : SEQ_START_TOKEN; -} - -static void *udp_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct sock *sk; - - if (v == SEQ_START_TOKEN) - sk = udp_get_idx(seq, 0); - else - sk = udp_get_next(seq, v); - - ++*pos; - return sk; -} - -static void udp_seq_stop(struct seq_file *seq, void *v) -{ - struct udp_iter_state *state = seq->private; - - if (state->bucket <= state->udp_table->mask) - spin_unlock_bh(&state->udp_table->hash[state->bucket].lock); -} - -int udp_seq_open(struct inode *inode, struct file *file) -{ - struct udp_seq_afinfo *afinfo = PDE_DATA(inode); - struct udp_iter_state *s; - int err; - - err = seq_open_net(inode, file, &afinfo->seq_ops, - sizeof(struct udp_iter_state)); - if (err < 0) - return err; - - s = ((struct seq_file *)file->private_data)->private; - s->family = afinfo->family; - s->udp_table = afinfo->udp_table; - return err; -} -EXPORT_SYMBOL(udp_seq_open); - -/* ------------------------------------------------------------------------ */ -int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo) -{ - struct proc_dir_entry *p; - int rc = 0; - - afinfo->seq_ops.start = udp_seq_start; - afinfo->seq_ops.next = udp_seq_next; - afinfo->seq_ops.stop = udp_seq_stop; - - p = proc_create_data(afinfo->name, S_IRUGO, net->proc_net, - afinfo->seq_fops, afinfo); - if (!p) - rc = -ENOMEM; - return rc; -} -EXPORT_SYMBOL(udp_proc_register); - -void udp_proc_unregister(struct net *net, struct udp_seq_afinfo *afinfo) -{ - remove_proc_entry(afinfo->name, net->proc_net); -} -EXPORT_SYMBOL(udp_proc_unregister); - -/* ------------------------------------------------------------------------ */ -static void udp4_format_sock(struct sock *sp, struct seq_file *f, - int bucket) -{ - struct inet_sock *inet = inet_sk(sp); - __be32 dest = inet->inet_daddr; - __be32 src = inet->inet_rcv_saddr; - __u16 destp = ntohs(inet->inet_dport); - __u16 srcp = ntohs(inet->inet_sport); - - seq_printf(f, "%5d: %08X:%04X %08X:%04X" - " %02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d", - bucket, src, srcp, dest, destp, sp->sk_state, - sk_wmem_alloc_get(sp), - sk_rmem_alloc_get(sp), - 0, 0L, 0, - from_kuid_munged(seq_user_ns(f), sock_i_uid(sp)), - 0, sock_i_ino(sp), - atomic_read(&sp->sk_refcnt), sp, - atomic_read(&sp->sk_drops)); -} - -int udp4_seq_show(struct seq_file *seq, void *v) -{ - seq_setwidth(seq, 127); - if (v == SEQ_START_TOKEN) - seq_puts(seq, " sl local_address rem_address st tx_queue " - "rx_queue tr tm->when retrnsmt uid timeout " - "inode ref pointer drops"); - else { - struct udp_iter_state *state = seq->private; - - udp4_format_sock(v, seq, state->bucket); - } - seq_pad(seq, '\n'); - return 0; -} - -static const struct file_operations udp_afinfo_seq_fops = { - .owner = THIS_MODULE, - .open = udp_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net -}; - -/* ------------------------------------------------------------------------ */ -static struct udp_seq_afinfo udp4_seq_afinfo = { - .name = "udp", - .family = AF_INET, - .udp_table = &udp_table, - .seq_fops = &udp_afinfo_seq_fops, - .seq_ops = { - .show = udp4_seq_show, - }, -}; - -static int __net_init udp4_proc_init_net(struct net *net) -{ - return udp_proc_register(net, &udp4_seq_afinfo); -} - -static void __net_exit udp4_proc_exit_net(struct net *net) -{ - udp_proc_unregister(net, &udp4_seq_afinfo); -} - -static struct pernet_operations udp4_net_ops = { - .init = udp4_proc_init_net, - .exit = udp4_proc_exit_net, -}; - -int __init udp4_proc_init(void) -{ - return register_pernet_subsys(&udp4_net_ops); -} - -void udp4_proc_exit(void) -{ - unregister_pernet_subsys(&udp4_net_ops); -} -#endif /* CONFIG_PROC_FS */ - -static __initdata unsigned long uhash_entries; -static int __init set_uhash_entries(char *str) -{ - ssize_t ret; - - if (!str) - return 0; - - ret = kstrtoul(str, 0, &uhash_entries); - if (ret) - return 0; - - if (uhash_entries && uhash_entries < UDP_HTABLE_SIZE_MIN) - uhash_entries = UDP_HTABLE_SIZE_MIN; - return 1; -} -__setup("uhash_entries=", set_uhash_entries); - -void __init udp_table_init(struct udp_table *table, const char *name) -{ - unsigned int i; - - table->hash = alloc_large_system_hash(name, - 2 * sizeof(struct udp_hslot), - uhash_entries, - 21, /* one slot per 2 MB */ - 0, - &table->log, - &table->mask, - UDP_HTABLE_SIZE_MIN, - 64 * 1024); - - table->hash2 = table->hash + (table->mask + 1); - for (i = 0; i <= table->mask; i++) { - INIT_HLIST_HEAD(&table->hash[i].head); - table->hash[i].count = 0; - spin_lock_init(&table->hash[i].lock); - } - for (i = 0; i <= table->mask; i++) { - INIT_HLIST_HEAD(&table->hash2[i].head); - table->hash2[i].count = 0; - spin_lock_init(&table->hash2[i].lock); - } -} - -u32 udp_flow_hashrnd(void) -{ - static u32 hashrnd __read_mostly; - - net_get_random_once(&hashrnd, sizeof(hashrnd)); - - return hashrnd; -} -EXPORT_SYMBOL(udp_flow_hashrnd); - -void __init udp_init(void) -{ - unsigned long limit; - - udp_table_init(&udp_table, "UDP"); - limit = nr_free_buffer_pages() / 8; - limit = max(limit, 128UL); - sysctl_udp_mem[0] = limit / 4 * 3; - sysctl_udp_mem[1] = limit; - sysctl_udp_mem[2] = sysctl_udp_mem[0] * 2; - - sysctl_udp_rmem_min = SK_MEM_QUANTUM; - sysctl_udp_wmem_min = SK_MEM_QUANTUM; -} diff --git a/src/linux/net/ipv4/udp_impl.h b/src/linux/net/ipv4/udp_impl.h deleted file mode 100644 index feb50a1..0000000 --- a/src/linux/net/ipv4/udp_impl.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef _UDP4_IMPL_H -#define _UDP4_IMPL_H -#include -#include -#include -#include - -int __udp4_lib_rcv(struct sk_buff *, struct udp_table *, int); -void __udp4_lib_err(struct sk_buff *, u32, struct udp_table *); - -int udp_v4_get_port(struct sock *sk, unsigned short snum); - -int udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen); -int udp_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen); - -#ifdef CONFIG_COMPAT -int compat_udp_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen); -int compat_udp_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen); -#endif -int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock, - int flags, int *addr_len); -int udp_sendpage(struct sock *sk, struct page *page, int offset, size_t size, - int flags); -int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); -void udp_destroy_sock(struct sock *sk); - -#ifdef CONFIG_PROC_FS -int udp4_seq_show(struct seq_file *seq, void *v); -#endif -#endif /* _UDP4_IMPL_H */ diff --git a/src/linux/net/ipv4/udp_offload.c b/src/linux/net/ipv4/udp_offload.c deleted file mode 100644 index b2be1d9..0000000 --- a/src/linux/net/ipv4/udp_offload.c +++ /dev/null @@ -1,391 +0,0 @@ -/* - * IPV4 GSO/GRO offload support - * Linux INET implementation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * UDPv4 GSO support - */ - -#include -#include -#include - -static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb, - netdev_features_t features, - struct sk_buff *(*gso_inner_segment)(struct sk_buff *skb, - netdev_features_t features), - __be16 new_protocol, bool is_ipv6) -{ - int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb); - bool remcsum, need_csum, offload_csum, ufo, gso_partial; - struct sk_buff *segs = ERR_PTR(-EINVAL); - struct udphdr *uh = udp_hdr(skb); - u16 mac_offset = skb->mac_header; - __be16 protocol = skb->protocol; - u16 mac_len = skb->mac_len; - int udp_offset, outer_hlen; - __wsum partial; - - if (unlikely(!pskb_may_pull(skb, tnl_hlen))) - goto out; - - /* Adjust partial header checksum to negate old length. - * We cannot rely on the value contained in uh->len as it is - * possible that the actual value exceeds the boundaries of the - * 16 bit length field due to the header being added outside of an - * IP or IPv6 frame that was already limited to 64K - 1. - */ - if (skb_shinfo(skb)->gso_type & SKB_GSO_PARTIAL) - partial = (__force __wsum)uh->len; - else - partial = (__force __wsum)htonl(skb->len); - partial = csum_sub(csum_unfold(uh->check), partial); - - /* setup inner skb. */ - skb->encapsulation = 0; - SKB_GSO_CB(skb)->encap_level = 0; - __skb_pull(skb, tnl_hlen); - skb_reset_mac_header(skb); - skb_set_network_header(skb, skb_inner_network_offset(skb)); - skb->mac_len = skb_inner_network_offset(skb); - skb->protocol = new_protocol; - - need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM); - skb->encap_hdr_csum = need_csum; - - remcsum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_TUNNEL_REMCSUM); - skb->remcsum_offload = remcsum; - - ufo = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP); - - /* Try to offload checksum if possible */ - offload_csum = !!(need_csum && - (skb->dev->features & - (is_ipv6 ? (NETIF_F_HW_CSUM | NETIF_F_IPV6_CSUM) : - (NETIF_F_HW_CSUM | NETIF_F_IP_CSUM)))); - - features &= skb->dev->hw_enc_features; - - /* The only checksum offload we care about from here on out is the - * outer one so strip the existing checksum feature flags and - * instead set the flag based on our outer checksum offload value. - */ - if (remcsum || ufo) { - features &= ~NETIF_F_CSUM_MASK; - if (!need_csum || offload_csum) - features |= NETIF_F_HW_CSUM; - } - - /* segment inner packet. */ - segs = gso_inner_segment(skb, features); - if (IS_ERR_OR_NULL(segs)) { - skb_gso_error_unwind(skb, protocol, tnl_hlen, mac_offset, - mac_len); - goto out; - } - - gso_partial = !!(skb_shinfo(segs)->gso_type & SKB_GSO_PARTIAL); - - outer_hlen = skb_tnl_header_len(skb); - udp_offset = outer_hlen - tnl_hlen; - skb = segs; - do { - unsigned int len; - - if (remcsum) - skb->ip_summed = CHECKSUM_NONE; - - /* Set up inner headers if we are offloading inner checksum */ - if (skb->ip_summed == CHECKSUM_PARTIAL) { - skb_reset_inner_headers(skb); - skb->encapsulation = 1; - } - - skb->mac_len = mac_len; - skb->protocol = protocol; - - __skb_push(skb, outer_hlen); - skb_reset_mac_header(skb); - skb_set_network_header(skb, mac_len); - skb_set_transport_header(skb, udp_offset); - len = skb->len - udp_offset; - uh = udp_hdr(skb); - - /* If we are only performing partial GSO the inner header - * will be using a length value equal to only one MSS sized - * segment instead of the entire frame. - */ - if (gso_partial) { - uh->len = htons(skb_shinfo(skb)->gso_size + - SKB_GSO_CB(skb)->data_offset + - skb->head - (unsigned char *)uh); - } else { - uh->len = htons(len); - } - - if (!need_csum) - continue; - - uh->check = ~csum_fold(csum_add(partial, - (__force __wsum)htonl(len))); - - if (skb->encapsulation || !offload_csum) { - uh->check = gso_make_checksum(skb, ~uh->check); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - } else { - skb->ip_summed = CHECKSUM_PARTIAL; - skb->csum_start = skb_transport_header(skb) - skb->head; - skb->csum_offset = offsetof(struct udphdr, check); - } - } while ((skb = skb->next)); -out: - return segs; -} - -struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb, - netdev_features_t features, - bool is_ipv6) -{ - __be16 protocol = skb->protocol; - const struct net_offload **offloads; - const struct net_offload *ops; - struct sk_buff *segs = ERR_PTR(-EINVAL); - struct sk_buff *(*gso_inner_segment)(struct sk_buff *skb, - netdev_features_t features); - - rcu_read_lock(); - - switch (skb->inner_protocol_type) { - case ENCAP_TYPE_ETHER: - protocol = skb->inner_protocol; - gso_inner_segment = skb_mac_gso_segment; - break; - case ENCAP_TYPE_IPPROTO: - offloads = is_ipv6 ? inet6_offloads : inet_offloads; - ops = rcu_dereference(offloads[skb->inner_ipproto]); - if (!ops || !ops->callbacks.gso_segment) - goto out_unlock; - gso_inner_segment = ops->callbacks.gso_segment; - break; - default: - goto out_unlock; - } - - segs = __skb_udp_tunnel_segment(skb, features, gso_inner_segment, - protocol, is_ipv6); - -out_unlock: - rcu_read_unlock(); - - return segs; -} -EXPORT_SYMBOL(skb_udp_tunnel_segment); - -static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb, - netdev_features_t features) -{ - struct sk_buff *segs = ERR_PTR(-EINVAL); - unsigned int mss; - __wsum csum; - struct udphdr *uh; - struct iphdr *iph; - - if (skb->encapsulation && - (skb_shinfo(skb)->gso_type & - (SKB_GSO_UDP_TUNNEL|SKB_GSO_UDP_TUNNEL_CSUM))) { - segs = skb_udp_tunnel_segment(skb, features, false); - goto out; - } - - if (!pskb_may_pull(skb, sizeof(struct udphdr))) - goto out; - - mss = skb_shinfo(skb)->gso_size; - if (unlikely(skb->len <= mss)) - goto out; - - if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { - /* Packet is from an untrusted source, reset gso_segs. */ - - skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); - - segs = NULL; - goto out; - } - - /* Do software UFO. Complete and fill in the UDP checksum as - * HW cannot do checksum of UDP packets sent as multiple - * IP fragments. - */ - - uh = udp_hdr(skb); - iph = ip_hdr(skb); - - uh->check = 0; - csum = skb_checksum(skb, 0, skb->len, 0); - uh->check = udp_v4_check(skb->len, iph->saddr, iph->daddr, csum); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - - skb->ip_summed = CHECKSUM_NONE; - - /* If there is no outer header we can fake a checksum offload - * due to the fact that we have already done the checksum in - * software prior to segmenting the frame. - */ - if (!skb->encap_hdr_csum) - features |= NETIF_F_HW_CSUM; - - /* Fragment the skb. IP headers of the fragments are updated in - * inet_gso_segment() - */ - segs = skb_segment(skb, features); -out: - return segs; -} - -struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb, - struct udphdr *uh, udp_lookup_t lookup) -{ - struct sk_buff *p, **pp = NULL; - struct udphdr *uh2; - unsigned int off = skb_gro_offset(skb); - int flush = 1; - struct sock *sk; - - if (NAPI_GRO_CB(skb)->encap_mark || - (skb->ip_summed != CHECKSUM_PARTIAL && - NAPI_GRO_CB(skb)->csum_cnt == 0 && - !NAPI_GRO_CB(skb)->csum_valid)) - goto out; - - /* mark that this skb passed once through the tunnel gro layer */ - NAPI_GRO_CB(skb)->encap_mark = 1; - - rcu_read_lock(); - sk = (*lookup)(skb, uh->source, uh->dest); - - if (sk && udp_sk(sk)->gro_receive) - goto unflush; - goto out_unlock; - -unflush: - flush = 0; - - for (p = *head; p; p = p->next) { - if (!NAPI_GRO_CB(p)->same_flow) - continue; - - uh2 = (struct udphdr *)(p->data + off); - - /* Match ports and either checksums are either both zero - * or nonzero. - */ - if ((*(u32 *)&uh->source != *(u32 *)&uh2->source) || - (!uh->check ^ !uh2->check)) { - NAPI_GRO_CB(p)->same_flow = 0; - continue; - } - } - - skb_gro_pull(skb, sizeof(struct udphdr)); /* pull encapsulating udp header */ - skb_gro_postpull_rcsum(skb, uh, sizeof(struct udphdr)); - pp = call_gro_receive_sk(udp_sk(sk)->gro_receive, sk, head, skb); - -out_unlock: - rcu_read_unlock(); -out: - NAPI_GRO_CB(skb)->flush |= flush; - return pp; -} -EXPORT_SYMBOL(udp_gro_receive); - -static struct sk_buff **udp4_gro_receive(struct sk_buff **head, - struct sk_buff *skb) -{ - struct udphdr *uh = udp_gro_udphdr(skb); - - if (unlikely(!uh)) - goto flush; - - /* Don't bother verifying checksum if we're going to flush anyway. */ - if (NAPI_GRO_CB(skb)->flush) - goto skip; - - if (skb_gro_checksum_validate_zero_check(skb, IPPROTO_UDP, uh->check, - inet_gro_compute_pseudo)) - goto flush; - else if (uh->check) - skb_gro_checksum_try_convert(skb, IPPROTO_UDP, uh->check, - inet_gro_compute_pseudo); -skip: - NAPI_GRO_CB(skb)->is_ipv6 = 0; - return udp_gro_receive(head, skb, uh, udp4_lib_lookup_skb); - -flush: - NAPI_GRO_CB(skb)->flush = 1; - return NULL; -} - -int udp_gro_complete(struct sk_buff *skb, int nhoff, - udp_lookup_t lookup) -{ - __be16 newlen = htons(skb->len - nhoff); - struct udphdr *uh = (struct udphdr *)(skb->data + nhoff); - int err = -ENOSYS; - struct sock *sk; - - uh->len = newlen; - - /* Set encapsulation before calling into inner gro_complete() functions - * to make them set up the inner offsets. - */ - skb->encapsulation = 1; - - rcu_read_lock(); - sk = (*lookup)(skb, uh->source, uh->dest); - if (sk && udp_sk(sk)->gro_complete) - err = udp_sk(sk)->gro_complete(sk, skb, - nhoff + sizeof(struct udphdr)); - rcu_read_unlock(); - - if (skb->remcsum_offload) - skb_shinfo(skb)->gso_type |= SKB_GSO_TUNNEL_REMCSUM; - - return err; -} -EXPORT_SYMBOL(udp_gro_complete); - -static int udp4_gro_complete(struct sk_buff *skb, int nhoff) -{ - const struct iphdr *iph = ip_hdr(skb); - struct udphdr *uh = (struct udphdr *)(skb->data + nhoff); - - if (uh->check) { - skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL_CSUM; - uh->check = ~udp_v4_check(skb->len - nhoff, iph->saddr, - iph->daddr, 0); - } else { - skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL; - } - - return udp_gro_complete(skb, nhoff, udp4_lib_lookup_skb); -} - -static const struct net_offload udpv4_offload = { - .callbacks = { - .gso_segment = udp4_ufo_fragment, - .gro_receive = udp4_gro_receive, - .gro_complete = udp4_gro_complete, - }, -}; - -int __init udpv4_offload_init(void) -{ - return inet_add_offload(&udpv4_offload, IPPROTO_UDP); -} diff --git a/src/linux/net/ipv4/udplite.c b/src/linux/net/ipv4/udplite.c deleted file mode 100644 index ff450c2..0000000 --- a/src/linux/net/ipv4/udplite.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * UDPLITE An implementation of the UDP-Lite protocol (RFC 3828). - * - * Authors: Gerrit Renker - * - * Changes: - * Fixes: - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#define pr_fmt(fmt) "UDPLite: " fmt - -#include -#include "udp_impl.h" - -struct udp_table udplite_table __read_mostly; -EXPORT_SYMBOL(udplite_table); - -static int udplite_rcv(struct sk_buff *skb) -{ - return __udp4_lib_rcv(skb, &udplite_table, IPPROTO_UDPLITE); -} - -static void udplite_err(struct sk_buff *skb, u32 info) -{ - __udp4_lib_err(skb, info, &udplite_table); -} - -static const struct net_protocol udplite_protocol = { - .handler = udplite_rcv, - .err_handler = udplite_err, - .no_policy = 1, - .netns_ok = 1, -}; - -struct proto udplite_prot = { - .name = "UDP-Lite", - .owner = THIS_MODULE, - .close = udp_lib_close, - .connect = ip4_datagram_connect, - .disconnect = udp_disconnect, - .ioctl = udp_ioctl, - .init = udplite_sk_init, - .destroy = udp_destroy_sock, - .setsockopt = udp_setsockopt, - .getsockopt = udp_getsockopt, - .sendmsg = udp_sendmsg, - .recvmsg = udp_recvmsg, - .sendpage = udp_sendpage, - .backlog_rcv = __udp_queue_rcv_skb, - .hash = udp_lib_hash, - .unhash = udp_lib_unhash, - .get_port = udp_v4_get_port, - .obj_size = sizeof(struct udp_sock), - .h.udp_table = &udplite_table, -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_udp_setsockopt, - .compat_getsockopt = compat_udp_getsockopt, -#endif -}; -EXPORT_SYMBOL(udplite_prot); - -static struct inet_protosw udplite4_protosw = { - .type = SOCK_DGRAM, - .protocol = IPPROTO_UDPLITE, - .prot = &udplite_prot, - .ops = &inet_dgram_ops, - .flags = INET_PROTOSW_PERMANENT, -}; - -#ifdef CONFIG_PROC_FS - -static const struct file_operations udplite_afinfo_seq_fops = { - .owner = THIS_MODULE, - .open = udp_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net -}; - -static struct udp_seq_afinfo udplite4_seq_afinfo = { - .name = "udplite", - .family = AF_INET, - .udp_table = &udplite_table, - .seq_fops = &udplite_afinfo_seq_fops, - .seq_ops = { - .show = udp4_seq_show, - }, -}; - -static int __net_init udplite4_proc_init_net(struct net *net) -{ - return udp_proc_register(net, &udplite4_seq_afinfo); -} - -static void __net_exit udplite4_proc_exit_net(struct net *net) -{ - udp_proc_unregister(net, &udplite4_seq_afinfo); -} - -static struct pernet_operations udplite4_net_ops = { - .init = udplite4_proc_init_net, - .exit = udplite4_proc_exit_net, -}; - -static __init int udplite4_proc_init(void) -{ - return register_pernet_subsys(&udplite4_net_ops); -} -#else -static inline int udplite4_proc_init(void) -{ - return 0; -} -#endif - -void __init udplite4_register(void) -{ - udp_table_init(&udplite_table, "UDP-Lite"); - if (proto_register(&udplite_prot, 1)) - goto out_register_err; - - if (inet_add_protocol(&udplite_protocol, IPPROTO_UDPLITE) < 0) - goto out_unregister_proto; - - inet_register_protosw(&udplite4_protosw); - - if (udplite4_proc_init()) - pr_err("%s: Cannot register /proc!\n", __func__); - return; - -out_unregister_proto: - proto_unregister(&udplite_prot); -out_register_err: - pr_crit("%s: Cannot add UDP-Lite protocol\n", __func__); -} diff --git a/src/linux/net/ipv4/xfrm4_input.c b/src/linux/net/ipv4/xfrm4_input.c deleted file mode 100644 index 62e1e72..0000000 --- a/src/linux/net/ipv4/xfrm4_input.c +++ /dev/null @@ -1,159 +0,0 @@ -/* - * xfrm4_input.c - * - * Changes: - * YOSHIFUJI Hideaki @USAGI - * Split up af-specific portion - * Derek Atkins - * Add Encapsulation support - * - */ - -#include -#include -#include -#include -#include -#include -#include - -int xfrm4_extract_input(struct xfrm_state *x, struct sk_buff *skb) -{ - return xfrm4_extract_header(skb); -} - -static inline int xfrm4_rcv_encap_finish(struct net *net, struct sock *sk, - struct sk_buff *skb) -{ - if (!skb_dst(skb)) { - const struct iphdr *iph = ip_hdr(skb); - - if (ip_route_input_noref(skb, iph->daddr, iph->saddr, - iph->tos, skb->dev)) - goto drop; - } - return dst_input(skb); -drop: - kfree_skb(skb); - return NET_RX_DROP; -} - -int xfrm4_transport_finish(struct sk_buff *skb, int async) -{ - struct iphdr *iph = ip_hdr(skb); - - iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol; - -#ifndef CONFIG_NETFILTER - if (!async) - return -iph->protocol; -#endif - - __skb_push(skb, skb->data - skb_network_header(skb)); - iph->tot_len = htons(skb->len); - ip_send_check(iph); - - NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, - dev_net(skb->dev), NULL, skb, skb->dev, NULL, - xfrm4_rcv_encap_finish); - return 0; -} - -/* If it's a keepalive packet, then just eat it. - * If it's an encapsulated packet, then pass it to the - * IPsec xfrm input. - * Returns 0 if skb passed to xfrm or was dropped. - * Returns >0 if skb should be passed to UDP. - * Returns <0 if skb should be resubmitted (-ret is protocol) - */ -int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb) -{ - struct udp_sock *up = udp_sk(sk); - struct udphdr *uh; - struct iphdr *iph; - int iphlen, len; - - __u8 *udpdata; - __be32 *udpdata32; - __u16 encap_type = up->encap_type; - - /* if this is not encapsulated socket, then just return now */ - if (!encap_type) - return 1; - - /* If this is a paged skb, make sure we pull up - * whatever data we need to look at. */ - len = skb->len - sizeof(struct udphdr); - if (!pskb_may_pull(skb, sizeof(struct udphdr) + min(len, 8))) - return 1; - - /* Now we can get the pointers */ - uh = udp_hdr(skb); - udpdata = (__u8 *)uh + sizeof(struct udphdr); - udpdata32 = (__be32 *)udpdata; - - switch (encap_type) { - default: - case UDP_ENCAP_ESPINUDP: - /* Check if this is a keepalive packet. If so, eat it. */ - if (len == 1 && udpdata[0] == 0xff) { - goto drop; - } else if (len > sizeof(struct ip_esp_hdr) && udpdata32[0] != 0) { - /* ESP Packet without Non-ESP header */ - len = sizeof(struct udphdr); - } else - /* Must be an IKE packet.. pass it through */ - return 1; - break; - case UDP_ENCAP_ESPINUDP_NON_IKE: - /* Check if this is a keepalive packet. If so, eat it. */ - if (len == 1 && udpdata[0] == 0xff) { - goto drop; - } else if (len > 2 * sizeof(u32) + sizeof(struct ip_esp_hdr) && - udpdata32[0] == 0 && udpdata32[1] == 0) { - - /* ESP Packet with Non-IKE marker */ - len = sizeof(struct udphdr) + 2 * sizeof(u32); - } else - /* Must be an IKE packet.. pass it through */ - return 1; - break; - } - - /* At this point we are sure that this is an ESPinUDP packet, - * so we need to remove 'len' bytes from the packet (the UDP - * header and optional ESP marker bytes) and then modify the - * protocol to ESP, and then call into the transform receiver. - */ - if (skb_unclone(skb, GFP_ATOMIC)) - goto drop; - - /* Now we can update and verify the packet length... */ - iph = ip_hdr(skb); - iphlen = iph->ihl << 2; - iph->tot_len = htons(ntohs(iph->tot_len) - len); - if (skb->len < iphlen + len) { - /* packet is too small!?! */ - goto drop; - } - - /* pull the data buffer up to the ESP header and set the - * transport header to point to ESP. Keep UDP on the stack - * for later. - */ - __skb_pull(skb, len); - skb_reset_transport_header(skb); - - /* process ESP */ - return xfrm4_rcv_encap(skb, IPPROTO_ESP, 0, encap_type); - -drop: - kfree_skb(skb); - return 0; -} - -int xfrm4_rcv(struct sk_buff *skb) -{ - return xfrm4_rcv_spi(skb, ip_hdr(skb)->protocol, 0); -} -EXPORT_SYMBOL(xfrm4_rcv); diff --git a/src/linux/net/ipv4/xfrm4_mode_beet.c b/src/linux/net/ipv4/xfrm4_mode_beet.c deleted file mode 100644 index 71acd00..0000000 --- a/src/linux/net/ipv4/xfrm4_mode_beet.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * xfrm4_mode_beet.c - BEET mode encapsulation for IPv4. - * - * Copyright (c) 2006 Diego Beltrami - * Miika Komu - * Herbert Xu - * Abhinav Pathak - * Jeff Ahrenholz - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static void xfrm4_beet_make_header(struct sk_buff *skb) -{ - struct iphdr *iph = ip_hdr(skb); - - iph->ihl = 5; - iph->version = 4; - - iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol; - iph->tos = XFRM_MODE_SKB_CB(skb)->tos; - - iph->id = XFRM_MODE_SKB_CB(skb)->id; - iph->frag_off = XFRM_MODE_SKB_CB(skb)->frag_off; - iph->ttl = XFRM_MODE_SKB_CB(skb)->ttl; -} - -/* Add encapsulation header. - * - * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. - */ -static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb) -{ - struct ip_beet_phdr *ph; - struct iphdr *top_iph; - int hdrlen, optlen; - - hdrlen = 0; - optlen = XFRM_MODE_SKB_CB(skb)->optlen; - if (unlikely(optlen)) - hdrlen += IPV4_BEET_PHMAXLEN - (optlen & 4); - - skb_set_network_header(skb, -x->props.header_len - - hdrlen + (XFRM_MODE_SKB_CB(skb)->ihl - sizeof(*top_iph))); - if (x->sel.family != AF_INET6) - skb->network_header += IPV4_BEET_PHMAXLEN; - skb->mac_header = skb->network_header + - offsetof(struct iphdr, protocol); - skb->transport_header = skb->network_header + sizeof(*top_iph); - - xfrm4_beet_make_header(skb); - - ph = (struct ip_beet_phdr *) - __skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl - hdrlen); - - top_iph = ip_hdr(skb); - - if (unlikely(optlen)) { - BUG_ON(optlen < 0); - - ph->padlen = 4 - (optlen & 4); - ph->hdrlen = optlen / 8; - ph->nexthdr = top_iph->protocol; - if (ph->padlen) - memset(ph + 1, IPOPT_NOP, ph->padlen); - - top_iph->protocol = IPPROTO_BEETPH; - top_iph->ihl = sizeof(struct iphdr) / 4; - } - - top_iph->saddr = x->props.saddr.a4; - top_iph->daddr = x->id.daddr.a4; - - return 0; -} - -static int xfrm4_beet_input(struct xfrm_state *x, struct sk_buff *skb) -{ - struct iphdr *iph; - int optlen = 0; - int err = -EINVAL; - - if (unlikely(XFRM_MODE_SKB_CB(skb)->protocol == IPPROTO_BEETPH)) { - struct ip_beet_phdr *ph; - int phlen; - - if (!pskb_may_pull(skb, sizeof(*ph))) - goto out; - - ph = (struct ip_beet_phdr *)skb->data; - - phlen = sizeof(*ph) + ph->padlen; - optlen = ph->hdrlen * 8 + (IPV4_BEET_PHMAXLEN - phlen); - if (optlen < 0 || optlen & 3 || optlen > 250) - goto out; - - XFRM_MODE_SKB_CB(skb)->protocol = ph->nexthdr; - - if (!pskb_may_pull(skb, phlen)) - goto out; - __skb_pull(skb, phlen); - } - - skb_push(skb, sizeof(*iph)); - skb_reset_network_header(skb); - skb_mac_header_rebuild(skb); - - xfrm4_beet_make_header(skb); - - iph = ip_hdr(skb); - - iph->ihl += optlen / 4; - iph->tot_len = htons(skb->len); - iph->daddr = x->sel.daddr.a4; - iph->saddr = x->sel.saddr.a4; - iph->check = 0; - iph->check = ip_fast_csum(skb_network_header(skb), iph->ihl); - err = 0; -out: - return err; -} - -static struct xfrm_mode xfrm4_beet_mode = { - .input2 = xfrm4_beet_input, - .input = xfrm_prepare_input, - .output2 = xfrm4_beet_output, - .output = xfrm4_prepare_output, - .owner = THIS_MODULE, - .encap = XFRM_MODE_BEET, - .flags = XFRM_MODE_FLAG_TUNNEL, -}; - -static int __init xfrm4_beet_init(void) -{ - return xfrm_register_mode(&xfrm4_beet_mode, AF_INET); -} - -static void __exit xfrm4_beet_exit(void) -{ - int err; - - err = xfrm_unregister_mode(&xfrm4_beet_mode, AF_INET); - BUG_ON(err); -} - -module_init(xfrm4_beet_init); -module_exit(xfrm4_beet_exit); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_BEET); diff --git a/src/linux/net/ipv4/xfrm4_mode_transport.c b/src/linux/net/ipv4/xfrm4_mode_transport.c deleted file mode 100644 index fd840c7..0000000 --- a/src/linux/net/ipv4/xfrm4_mode_transport.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * xfrm4_mode_transport.c - Transport mode encapsulation for IPv4. - * - * Copyright (c) 2004-2006 Herbert Xu - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* Add encapsulation header. - * - * The IP header will be moved forward to make space for the encapsulation - * header. - */ -static int xfrm4_transport_output(struct xfrm_state *x, struct sk_buff *skb) -{ - struct iphdr *iph = ip_hdr(skb); - int ihl = iph->ihl * 4; - - skb_set_network_header(skb, -x->props.header_len); - skb->mac_header = skb->network_header + - offsetof(struct iphdr, protocol); - skb->transport_header = skb->network_header + ihl; - __skb_pull(skb, ihl); - memmove(skb_network_header(skb), iph, ihl); - return 0; -} - -/* Remove encapsulation header. - * - * The IP header will be moved over the top of the encapsulation header. - * - * On entry, skb->h shall point to where the IP header should be and skb->nh - * shall be set to where the IP header currently is. skb->data shall point - * to the start of the payload. - */ -static int xfrm4_transport_input(struct xfrm_state *x, struct sk_buff *skb) -{ - int ihl = skb->data - skb_transport_header(skb); - - if (skb->transport_header != skb->network_header) { - memmove(skb_transport_header(skb), - skb_network_header(skb), ihl); - skb->network_header = skb->transport_header; - } - ip_hdr(skb)->tot_len = htons(skb->len + ihl); - skb_reset_transport_header(skb); - return 0; -} - -static struct xfrm_mode xfrm4_transport_mode = { - .input = xfrm4_transport_input, - .output = xfrm4_transport_output, - .owner = THIS_MODULE, - .encap = XFRM_MODE_TRANSPORT, -}; - -static int __init xfrm4_transport_init(void) -{ - return xfrm_register_mode(&xfrm4_transport_mode, AF_INET); -} - -static void __exit xfrm4_transport_exit(void) -{ - int err; - - err = xfrm_unregister_mode(&xfrm4_transport_mode, AF_INET); - BUG_ON(err); -} - -module_init(xfrm4_transport_init); -module_exit(xfrm4_transport_exit); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_TRANSPORT); diff --git a/src/linux/net/ipv4/xfrm4_mode_tunnel.c b/src/linux/net/ipv4/xfrm4_mode_tunnel.c deleted file mode 100644 index 35feda6..0000000 --- a/src/linux/net/ipv4/xfrm4_mode_tunnel.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * xfrm4_mode_tunnel.c - Tunnel mode encapsulation for IPv4. - * - * Copyright (c) 2004-2006 Herbert Xu - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static inline void ipip_ecn_decapsulate(struct sk_buff *skb) -{ - struct iphdr *inner_iph = ipip_hdr(skb); - - if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos)) - IP_ECN_set_ce(inner_iph); -} - -/* Add encapsulation header. - * - * The top IP header will be constructed per RFC 2401. - */ -static int xfrm4_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) -{ - struct dst_entry *dst = skb_dst(skb); - struct iphdr *top_iph; - int flags; - - skb_set_network_header(skb, -x->props.header_len); - skb->mac_header = skb->network_header + - offsetof(struct iphdr, protocol); - skb->transport_header = skb->network_header + sizeof(*top_iph); - top_iph = ip_hdr(skb); - - top_iph->ihl = 5; - top_iph->version = 4; - - top_iph->protocol = xfrm_af2proto(skb_dst(skb)->ops->family); - - /* DS disclosing depends on XFRM_SA_XFLAG_DONT_ENCAP_DSCP */ - if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP) - top_iph->tos = 0; - else - top_iph->tos = XFRM_MODE_SKB_CB(skb)->tos; - top_iph->tos = INET_ECN_encapsulate(top_iph->tos, - XFRM_MODE_SKB_CB(skb)->tos); - - flags = x->props.flags; - if (flags & XFRM_STATE_NOECN) - IP_ECN_clear(top_iph); - - top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? - 0 : (XFRM_MODE_SKB_CB(skb)->frag_off & htons(IP_DF)); - - top_iph->ttl = ip4_dst_hoplimit(dst->child); - - top_iph->saddr = x->props.saddr.a4; - top_iph->daddr = x->id.daddr.a4; - ip_select_ident(dev_net(dst->dev), skb, NULL); - - return 0; -} - -static int xfrm4_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) -{ - int err = -EINVAL; - - if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPIP) - goto out; - - if (!pskb_may_pull(skb, sizeof(struct iphdr))) - goto out; - - err = skb_unclone(skb, GFP_ATOMIC); - if (err) - goto out; - - if (x->props.flags & XFRM_STATE_DECAP_DSCP) - ipv4_copy_dscp(XFRM_MODE_SKB_CB(skb)->tos, ipip_hdr(skb)); - if (!(x->props.flags & XFRM_STATE_NOECN)) - ipip_ecn_decapsulate(skb); - - skb_reset_network_header(skb); - skb_mac_header_rebuild(skb); - - err = 0; - -out: - return err; -} - -static struct xfrm_mode xfrm4_tunnel_mode = { - .input2 = xfrm4_mode_tunnel_input, - .input = xfrm_prepare_input, - .output2 = xfrm4_mode_tunnel_output, - .output = xfrm4_prepare_output, - .owner = THIS_MODULE, - .encap = XFRM_MODE_TUNNEL, - .flags = XFRM_MODE_FLAG_TUNNEL, -}; - -static int __init xfrm4_mode_tunnel_init(void) -{ - return xfrm_register_mode(&xfrm4_tunnel_mode, AF_INET); -} - -static void __exit xfrm4_mode_tunnel_exit(void) -{ - int err; - - err = xfrm_unregister_mode(&xfrm4_tunnel_mode, AF_INET); - BUG_ON(err); -} - -module_init(xfrm4_mode_tunnel_init); -module_exit(xfrm4_mode_tunnel_exit); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_TUNNEL); diff --git a/src/linux/net/ipv4/xfrm4_output.c b/src/linux/net/ipv4/xfrm4_output.c deleted file mode 100644 index 7ee6518..0000000 --- a/src/linux/net/ipv4/xfrm4_output.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * xfrm4_output.c - Common IPsec encapsulation code for IPv4. - * Copyright (c) 2004 Herbert Xu - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int xfrm4_tunnel_check_size(struct sk_buff *skb) -{ - int mtu, ret = 0; - - if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE) - goto out; - - if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->ignore_df) - goto out; - - mtu = dst_mtu(skb_dst(skb)); - if (skb->len > mtu) { - skb->protocol = htons(ETH_P_IP); - - if (skb->sk) - xfrm_local_error(skb, mtu); - else - icmp_send(skb, ICMP_DEST_UNREACH, - ICMP_FRAG_NEEDED, htonl(mtu)); - ret = -EMSGSIZE; - } -out: - return ret; -} - -int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb) -{ - int err; - - err = xfrm4_tunnel_check_size(skb); - if (err) - return err; - - XFRM_MODE_SKB_CB(skb)->protocol = ip_hdr(skb)->protocol; - - return xfrm4_extract_header(skb); -} - -int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb) -{ - int err; - - err = xfrm_inner_extract_output(x, skb); - if (err) - return err; - - IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE; - skb->protocol = htons(ETH_P_IP); - - return x->outer_mode->output2(x, skb); -} -EXPORT_SYMBOL(xfrm4_prepare_output); - -int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb) -{ - memset(IPCB(skb), 0, sizeof(*IPCB(skb))); - -#ifdef CONFIG_NETFILTER - IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED; -#endif - - return xfrm_output(sk, skb); -} - -static int __xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - struct xfrm_state *x = skb_dst(skb)->xfrm; - -#ifdef CONFIG_NETFILTER - if (!x) { - IPCB(skb)->flags |= IPSKB_REROUTED; - return dst_output(net, sk, skb); - } -#endif - - return x->outer_mode->afinfo->output_finish(sk, skb); -} - -int xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, - net, sk, skb, NULL, skb_dst(skb)->dev, - __xfrm4_output, - !(IPCB(skb)->flags & IPSKB_REROUTED)); -} - -void xfrm4_local_error(struct sk_buff *skb, u32 mtu) -{ - struct iphdr *hdr; - - hdr = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb); - ip_local_error(skb->sk, EMSGSIZE, hdr->daddr, - inet_sk(skb->sk)->inet_dport, mtu); -} diff --git a/src/linux/net/ipv4/xfrm4_policy.c b/src/linux/net/ipv4/xfrm4_policy.c deleted file mode 100644 index 6a7ff69..0000000 --- a/src/linux/net/ipv4/xfrm4_policy.c +++ /dev/null @@ -1,389 +0,0 @@ -/* - * xfrm4_policy.c - * - * Changes: - * Kazunori MIYAZAWA @USAGI - * YOSHIFUJI Hideaki @USAGI - * Split up af-specific portion - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static struct xfrm_policy_afinfo xfrm4_policy_afinfo; - -static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4, - int tos, int oif, - const xfrm_address_t *saddr, - const xfrm_address_t *daddr) -{ - struct rtable *rt; - - memset(fl4, 0, sizeof(*fl4)); - fl4->daddr = daddr->a4; - fl4->flowi4_tos = tos; - fl4->flowi4_oif = l3mdev_master_ifindex_by_index(net, oif); - if (saddr) - fl4->saddr = saddr->a4; - - fl4->flowi4_flags = FLOWI_FLAG_SKIP_NH_OIF; - - rt = __ip_route_output_key(net, fl4); - if (!IS_ERR(rt)) - return &rt->dst; - - return ERR_CAST(rt); -} - -static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, int oif, - const xfrm_address_t *saddr, - const xfrm_address_t *daddr) -{ - struct flowi4 fl4; - - return __xfrm4_dst_lookup(net, &fl4, tos, oif, saddr, daddr); -} - -static int xfrm4_get_saddr(struct net *net, int oif, - xfrm_address_t *saddr, xfrm_address_t *daddr) -{ - struct dst_entry *dst; - struct flowi4 fl4; - - dst = __xfrm4_dst_lookup(net, &fl4, 0, oif, NULL, daddr); - if (IS_ERR(dst)) - return -EHOSTUNREACH; - - saddr->a4 = fl4.saddr; - dst_release(dst); - return 0; -} - -static int xfrm4_get_tos(const struct flowi *fl) -{ - return IPTOS_RT_MASK & fl->u.ip4.flowi4_tos; /* Strip ECN bits */ -} - -static int xfrm4_init_path(struct xfrm_dst *path, struct dst_entry *dst, - int nfheader_len) -{ - return 0; -} - -static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, - const struct flowi *fl) -{ - struct rtable *rt = (struct rtable *)xdst->route; - const struct flowi4 *fl4 = &fl->u.ip4; - - xdst->u.rt.rt_iif = fl4->flowi4_iif; - - xdst->u.dst.dev = dev; - dev_hold(dev); - - /* Sheit... I remember I did this right. Apparently, - * it was magically lost, so this code needs audit */ - xdst->u.rt.rt_is_input = rt->rt_is_input; - xdst->u.rt.rt_flags = rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST | - RTCF_LOCAL); - xdst->u.rt.rt_type = rt->rt_type; - xdst->u.rt.rt_gateway = rt->rt_gateway; - xdst->u.rt.rt_uses_gateway = rt->rt_uses_gateway; - xdst->u.rt.rt_pmtu = rt->rt_pmtu; - xdst->u.rt.rt_table_id = rt->rt_table_id; - INIT_LIST_HEAD(&xdst->u.rt.rt_uncached); - - return 0; -} - -static void -_decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) -{ - const struct iphdr *iph = ip_hdr(skb); - u8 *xprth = skb_network_header(skb) + iph->ihl * 4; - struct flowi4 *fl4 = &fl->u.ip4; - int oif = 0; - - if (skb_dst(skb)) - oif = skb_dst(skb)->dev->ifindex; - - memset(fl4, 0, sizeof(struct flowi4)); - fl4->flowi4_mark = skb->mark; - fl4->flowi4_oif = reverse ? skb->skb_iif : oif; - - if (!ip_is_fragment(iph)) { - switch (iph->protocol) { - case IPPROTO_UDP: - case IPPROTO_UDPLITE: - case IPPROTO_TCP: - case IPPROTO_SCTP: - case IPPROTO_DCCP: - if (xprth + 4 < skb->data || - pskb_may_pull(skb, xprth + 4 - skb->data)) { - __be16 *ports; - - xprth = skb_network_header(skb) + iph->ihl * 4; - ports = (__be16 *)xprth; - - fl4->fl4_sport = ports[!!reverse]; - fl4->fl4_dport = ports[!reverse]; - } - break; - - case IPPROTO_ICMP: - if (xprth + 2 < skb->data || - pskb_may_pull(skb, xprth + 2 - skb->data)) { - u8 *icmp; - - xprth = skb_network_header(skb) + iph->ihl * 4; - icmp = xprth; - - fl4->fl4_icmp_type = icmp[0]; - fl4->fl4_icmp_code = icmp[1]; - } - break; - - case IPPROTO_ESP: - if (xprth + 4 < skb->data || - pskb_may_pull(skb, xprth + 4 - skb->data)) { - __be32 *ehdr; - - xprth = skb_network_header(skb) + iph->ihl * 4; - ehdr = (__be32 *)xprth; - - fl4->fl4_ipsec_spi = ehdr[0]; - } - break; - - case IPPROTO_AH: - if (xprth + 8 < skb->data || - pskb_may_pull(skb, xprth + 8 - skb->data)) { - __be32 *ah_hdr; - - xprth = skb_network_header(skb) + iph->ihl * 4; - ah_hdr = (__be32 *)xprth; - - fl4->fl4_ipsec_spi = ah_hdr[1]; - } - break; - - case IPPROTO_COMP: - if (xprth + 4 < skb->data || - pskb_may_pull(skb, xprth + 4 - skb->data)) { - __be16 *ipcomp_hdr; - - xprth = skb_network_header(skb) + iph->ihl * 4; - ipcomp_hdr = (__be16 *)xprth; - - fl4->fl4_ipsec_spi = htonl(ntohs(ipcomp_hdr[1])); - } - break; - - case IPPROTO_GRE: - if (xprth + 12 < skb->data || - pskb_may_pull(skb, xprth + 12 - skb->data)) { - __be16 *greflags; - __be32 *gre_hdr; - - xprth = skb_network_header(skb) + iph->ihl * 4; - greflags = (__be16 *)xprth; - gre_hdr = (__be32 *)xprth; - - if (greflags[0] & GRE_KEY) { - if (greflags[0] & GRE_CSUM) - gre_hdr++; - fl4->fl4_gre_key = gre_hdr[1]; - } - } - break; - - default: - fl4->fl4_ipsec_spi = 0; - break; - } - } - fl4->flowi4_proto = iph->protocol; - fl4->daddr = reverse ? iph->saddr : iph->daddr; - fl4->saddr = reverse ? iph->daddr : iph->saddr; - fl4->flowi4_tos = iph->tos; -} - -static inline int xfrm4_garbage_collect(struct dst_ops *ops) -{ - struct net *net = container_of(ops, struct net, xfrm.xfrm4_dst_ops); - - xfrm4_policy_afinfo.garbage_collect(net); - return (dst_entries_get_slow(ops) > ops->gc_thresh * 2); -} - -static void xfrm4_update_pmtu(struct dst_entry *dst, struct sock *sk, - struct sk_buff *skb, u32 mtu) -{ - struct xfrm_dst *xdst = (struct xfrm_dst *)dst; - struct dst_entry *path = xdst->route; - - path->ops->update_pmtu(path, sk, skb, mtu); -} - -static void xfrm4_redirect(struct dst_entry *dst, struct sock *sk, - struct sk_buff *skb) -{ - struct xfrm_dst *xdst = (struct xfrm_dst *)dst; - struct dst_entry *path = xdst->route; - - path->ops->redirect(path, sk, skb); -} - -static void xfrm4_dst_destroy(struct dst_entry *dst) -{ - struct xfrm_dst *xdst = (struct xfrm_dst *)dst; - - dst_destroy_metrics_generic(dst); - - xfrm_dst_destroy(xdst); -} - -static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, - int unregister) -{ - if (!unregister) - return; - - xfrm_dst_ifdown(dst, dev); -} - -static struct dst_ops xfrm4_dst_ops_template = { - .family = AF_INET, - .gc = xfrm4_garbage_collect, - .update_pmtu = xfrm4_update_pmtu, - .redirect = xfrm4_redirect, - .cow_metrics = dst_cow_metrics_generic, - .destroy = xfrm4_dst_destroy, - .ifdown = xfrm4_dst_ifdown, - .local_out = __ip_local_out, - .gc_thresh = INT_MAX, -}; - -static struct xfrm_policy_afinfo xfrm4_policy_afinfo = { - .family = AF_INET, - .dst_ops = &xfrm4_dst_ops_template, - .dst_lookup = xfrm4_dst_lookup, - .get_saddr = xfrm4_get_saddr, - .decode_session = _decode_session4, - .get_tos = xfrm4_get_tos, - .init_path = xfrm4_init_path, - .fill_dst = xfrm4_fill_dst, - .blackhole_route = ipv4_blackhole_route, -}; - -#ifdef CONFIG_SYSCTL -static struct ctl_table xfrm4_policy_table[] = { - { - .procname = "xfrm4_gc_thresh", - .data = &init_net.xfrm.xfrm4_dst_ops.gc_thresh, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { } -}; - -static __net_init int xfrm4_net_sysctl_init(struct net *net) -{ - struct ctl_table *table; - struct ctl_table_header *hdr; - - table = xfrm4_policy_table; - if (!net_eq(net, &init_net)) { - table = kmemdup(table, sizeof(xfrm4_policy_table), GFP_KERNEL); - if (!table) - goto err_alloc; - - table[0].data = &net->xfrm.xfrm4_dst_ops.gc_thresh; - } - - hdr = register_net_sysctl(net, "net/ipv4", table); - if (!hdr) - goto err_reg; - - net->ipv4.xfrm4_hdr = hdr; - return 0; - -err_reg: - if (!net_eq(net, &init_net)) - kfree(table); -err_alloc: - return -ENOMEM; -} - -static __net_exit void xfrm4_net_sysctl_exit(struct net *net) -{ - struct ctl_table *table; - - if (!net->ipv4.xfrm4_hdr) - return; - - table = net->ipv4.xfrm4_hdr->ctl_table_arg; - unregister_net_sysctl_table(net->ipv4.xfrm4_hdr); - if (!net_eq(net, &init_net)) - kfree(table); -} -#else /* CONFIG_SYSCTL */ -static inline int xfrm4_net_sysctl_init(struct net *net) -{ - return 0; -} - -static inline void xfrm4_net_sysctl_exit(struct net *net) -{ -} -#endif - -static int __net_init xfrm4_net_init(struct net *net) -{ - int ret; - - memcpy(&net->xfrm.xfrm4_dst_ops, &xfrm4_dst_ops_template, - sizeof(xfrm4_dst_ops_template)); - ret = dst_entries_init(&net->xfrm.xfrm4_dst_ops); - if (ret) - return ret; - - ret = xfrm4_net_sysctl_init(net); - if (ret) - dst_entries_destroy(&net->xfrm.xfrm4_dst_ops); - - return ret; -} - -static void __net_exit xfrm4_net_exit(struct net *net) -{ - xfrm4_net_sysctl_exit(net); - dst_entries_destroy(&net->xfrm.xfrm4_dst_ops); -} - -static struct pernet_operations __net_initdata xfrm4_net_ops = { - .init = xfrm4_net_init, - .exit = xfrm4_net_exit, -}; - -static void __init xfrm4_policy_init(void) -{ - xfrm_policy_register_afinfo(&xfrm4_policy_afinfo); -} - -void __init xfrm4_init(void) -{ - xfrm4_state_init(); - xfrm4_policy_init(); - xfrm4_protocol_init(); - register_pernet_subsys(&xfrm4_net_ops); -} - diff --git a/src/linux/net/ipv4/xfrm4_protocol.c b/src/linux/net/ipv4/xfrm4_protocol.c deleted file mode 100644 index dccefa9..0000000 --- a/src/linux/net/ipv4/xfrm4_protocol.c +++ /dev/null @@ -1,301 +0,0 @@ -/* xfrm4_protocol.c - Generic xfrm protocol multiplexer. - * - * Copyright (C) 2013 secunet Security Networks AG - * - * Author: - * Steffen Klassert - * - * Based on: - * net/ipv4/tunnel4.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include - -static struct xfrm4_protocol __rcu *esp4_handlers __read_mostly; -static struct xfrm4_protocol __rcu *ah4_handlers __read_mostly; -static struct xfrm4_protocol __rcu *ipcomp4_handlers __read_mostly; -static DEFINE_MUTEX(xfrm4_protocol_mutex); - -static inline struct xfrm4_protocol __rcu **proto_handlers(u8 protocol) -{ - switch (protocol) { - case IPPROTO_ESP: - return &esp4_handlers; - case IPPROTO_AH: - return &ah4_handlers; - case IPPROTO_COMP: - return &ipcomp4_handlers; - } - - return NULL; -} - -#define for_each_protocol_rcu(head, handler) \ - for (handler = rcu_dereference(head); \ - handler != NULL; \ - handler = rcu_dereference(handler->next)) \ - -int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err) -{ - int ret; - struct xfrm4_protocol *handler; - struct xfrm4_protocol __rcu **head = proto_handlers(protocol); - - if (!head) - return 0; - - for_each_protocol_rcu(*head, handler) - if ((ret = handler->cb_handler(skb, err)) <= 0) - return ret; - - return 0; -} -EXPORT_SYMBOL(xfrm4_rcv_cb); - -int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, - int encap_type) -{ - int ret; - struct xfrm4_protocol *handler; - struct xfrm4_protocol __rcu **head = proto_handlers(nexthdr); - - XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; - XFRM_SPI_SKB_CB(skb)->family = AF_INET; - XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); - - if (!head) - goto out; - - for_each_protocol_rcu(*head, handler) - if ((ret = handler->input_handler(skb, nexthdr, spi, encap_type)) != -EINVAL) - return ret; - -out: - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); - - kfree_skb(skb); - return 0; -} -EXPORT_SYMBOL(xfrm4_rcv_encap); - -static int xfrm4_esp_rcv(struct sk_buff *skb) -{ - int ret; - struct xfrm4_protocol *handler; - - XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; - - for_each_protocol_rcu(esp4_handlers, handler) - if ((ret = handler->handler(skb)) != -EINVAL) - return ret; - - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); - - kfree_skb(skb); - return 0; -} - -static void xfrm4_esp_err(struct sk_buff *skb, u32 info) -{ - struct xfrm4_protocol *handler; - - for_each_protocol_rcu(esp4_handlers, handler) - if (!handler->err_handler(skb, info)) - break; -} - -static int xfrm4_ah_rcv(struct sk_buff *skb) -{ - int ret; - struct xfrm4_protocol *handler; - - XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; - - for_each_protocol_rcu(ah4_handlers, handler) - if ((ret = handler->handler(skb)) != -EINVAL) - return ret; - - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); - - kfree_skb(skb); - return 0; -} - -static void xfrm4_ah_err(struct sk_buff *skb, u32 info) -{ - struct xfrm4_protocol *handler; - - for_each_protocol_rcu(ah4_handlers, handler) - if (!handler->err_handler(skb, info)) - break; -} - -static int xfrm4_ipcomp_rcv(struct sk_buff *skb) -{ - int ret; - struct xfrm4_protocol *handler; - - XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; - - for_each_protocol_rcu(ipcomp4_handlers, handler) - if ((ret = handler->handler(skb)) != -EINVAL) - return ret; - - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); - - kfree_skb(skb); - return 0; -} - -static void xfrm4_ipcomp_err(struct sk_buff *skb, u32 info) -{ - struct xfrm4_protocol *handler; - - for_each_protocol_rcu(ipcomp4_handlers, handler) - if (!handler->err_handler(skb, info)) - break; -} - -static const struct net_protocol esp4_protocol = { - .handler = xfrm4_esp_rcv, - .err_handler = xfrm4_esp_err, - .no_policy = 1, - .netns_ok = 1, -}; - -static const struct net_protocol ah4_protocol = { - .handler = xfrm4_ah_rcv, - .err_handler = xfrm4_ah_err, - .no_policy = 1, - .netns_ok = 1, -}; - -static const struct net_protocol ipcomp4_protocol = { - .handler = xfrm4_ipcomp_rcv, - .err_handler = xfrm4_ipcomp_err, - .no_policy = 1, - .netns_ok = 1, -}; - -static struct xfrm_input_afinfo xfrm4_input_afinfo = { - .family = AF_INET, - .owner = THIS_MODULE, - .callback = xfrm4_rcv_cb, -}; - -static inline const struct net_protocol *netproto(unsigned char protocol) -{ - switch (protocol) { - case IPPROTO_ESP: - return &esp4_protocol; - case IPPROTO_AH: - return &ah4_protocol; - case IPPROTO_COMP: - return &ipcomp4_protocol; - } - - return NULL; -} - -int xfrm4_protocol_register(struct xfrm4_protocol *handler, - unsigned char protocol) -{ - struct xfrm4_protocol __rcu **pprev; - struct xfrm4_protocol *t; - bool add_netproto = false; - int ret = -EEXIST; - int priority = handler->priority; - - if (!proto_handlers(protocol) || !netproto(protocol)) - return -EINVAL; - - mutex_lock(&xfrm4_protocol_mutex); - - if (!rcu_dereference_protected(*proto_handlers(protocol), - lockdep_is_held(&xfrm4_protocol_mutex))) - add_netproto = true; - - for (pprev = proto_handlers(protocol); - (t = rcu_dereference_protected(*pprev, - lockdep_is_held(&xfrm4_protocol_mutex))) != NULL; - pprev = &t->next) { - if (t->priority < priority) - break; - if (t->priority == priority) - goto err; - } - - handler->next = *pprev; - rcu_assign_pointer(*pprev, handler); - - ret = 0; - -err: - mutex_unlock(&xfrm4_protocol_mutex); - - if (add_netproto) { - if (inet_add_protocol(netproto(protocol), protocol)) { - pr_err("%s: can't add protocol\n", __func__); - ret = -EAGAIN; - } - } - - return ret; -} -EXPORT_SYMBOL(xfrm4_protocol_register); - -int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, - unsigned char protocol) -{ - struct xfrm4_protocol __rcu **pprev; - struct xfrm4_protocol *t; - int ret = -ENOENT; - - if (!proto_handlers(protocol) || !netproto(protocol)) - return -EINVAL; - - mutex_lock(&xfrm4_protocol_mutex); - - for (pprev = proto_handlers(protocol); - (t = rcu_dereference_protected(*pprev, - lockdep_is_held(&xfrm4_protocol_mutex))) != NULL; - pprev = &t->next) { - if (t == handler) { - *pprev = handler->next; - ret = 0; - break; - } - } - - if (!rcu_dereference_protected(*proto_handlers(protocol), - lockdep_is_held(&xfrm4_protocol_mutex))) { - if (inet_del_protocol(netproto(protocol), protocol) < 0) { - pr_err("%s: can't remove protocol\n", __func__); - ret = -EAGAIN; - } - } - - mutex_unlock(&xfrm4_protocol_mutex); - - synchronize_net(); - - return ret; -} -EXPORT_SYMBOL(xfrm4_protocol_deregister); - -void __init xfrm4_protocol_init(void) -{ - xfrm_input_register_afinfo(&xfrm4_input_afinfo); -} -EXPORT_SYMBOL(xfrm4_protocol_init); diff --git a/src/linux/net/ipv4/xfrm4_state.c b/src/linux/net/ipv4/xfrm4_state.c deleted file mode 100644 index 542074c..0000000 --- a/src/linux/net/ipv4/xfrm4_state.c +++ /dev/null @@ -1,100 +0,0 @@ -/* - * xfrm4_state.c - * - * Changes: - * YOSHIFUJI Hideaki @USAGI - * Split up af-specific portion - * - */ - -#include -#include -#include -#include -#include -#include - -static int xfrm4_init_flags(struct xfrm_state *x) -{ - if (xs_net(x)->ipv4.sysctl_ip_no_pmtu_disc) - x->props.flags |= XFRM_STATE_NOPMTUDISC; - return 0; -} - -static void -__xfrm4_init_tempsel(struct xfrm_selector *sel, const struct flowi *fl) -{ - const struct flowi4 *fl4 = &fl->u.ip4; - - sel->daddr.a4 = fl4->daddr; - sel->saddr.a4 = fl4->saddr; - sel->dport = xfrm_flowi_dport(fl, &fl4->uli); - sel->dport_mask = htons(0xffff); - sel->sport = xfrm_flowi_sport(fl, &fl4->uli); - sel->sport_mask = htons(0xffff); - sel->family = AF_INET; - sel->prefixlen_d = 32; - sel->prefixlen_s = 32; - sel->proto = fl4->flowi4_proto; - sel->ifindex = fl4->flowi4_oif; -} - -static void -xfrm4_init_temprop(struct xfrm_state *x, const struct xfrm_tmpl *tmpl, - const xfrm_address_t *daddr, const xfrm_address_t *saddr) -{ - x->id = tmpl->id; - if (x->id.daddr.a4 == 0) - x->id.daddr.a4 = daddr->a4; - x->props.saddr = tmpl->saddr; - if (x->props.saddr.a4 == 0) - x->props.saddr.a4 = saddr->a4; - x->props.mode = tmpl->mode; - x->props.reqid = tmpl->reqid; - x->props.family = AF_INET; -} - -int xfrm4_extract_header(struct sk_buff *skb) -{ - const struct iphdr *iph = ip_hdr(skb); - - XFRM_MODE_SKB_CB(skb)->ihl = sizeof(*iph); - XFRM_MODE_SKB_CB(skb)->id = iph->id; - XFRM_MODE_SKB_CB(skb)->frag_off = iph->frag_off; - XFRM_MODE_SKB_CB(skb)->tos = iph->tos; - XFRM_MODE_SKB_CB(skb)->ttl = iph->ttl; - XFRM_MODE_SKB_CB(skb)->optlen = iph->ihl * 4 - sizeof(*iph); - memset(XFRM_MODE_SKB_CB(skb)->flow_lbl, 0, - sizeof(XFRM_MODE_SKB_CB(skb)->flow_lbl)); - - return 0; -} - -static struct xfrm_state_afinfo xfrm4_state_afinfo = { - .family = AF_INET, - .proto = IPPROTO_IPIP, - .eth_proto = htons(ETH_P_IP), - .owner = THIS_MODULE, - .init_flags = xfrm4_init_flags, - .init_tempsel = __xfrm4_init_tempsel, - .init_temprop = xfrm4_init_temprop, - .output = xfrm4_output, - .output_finish = xfrm4_output_finish, - .extract_input = xfrm4_extract_input, - .extract_output = xfrm4_extract_output, - .transport_finish = xfrm4_transport_finish, - .local_error = xfrm4_local_error, -}; - -void __init xfrm4_state_init(void) -{ - xfrm_state_register_afinfo(&xfrm4_state_afinfo); -} - -#if 0 -void __exit xfrm4_state_fini(void) -{ - xfrm_state_unregister_afinfo(&xfrm4_state_afinfo); -} -#endif /* 0 */ - diff --git a/src/linux/net/ipv6/Kconfig b/src/linux/net/ipv6/Kconfig deleted file mode 100644 index 2343e4f..0000000 --- a/src/linux/net/ipv6/Kconfig +++ /dev/null @@ -1,292 +0,0 @@ -# -# IPv6 configuration -# - -# IPv6 as module will cause a CRASH if you try to unload it -menuconfig IPV6 - tristate "The IPv6 protocol" - default y - ---help--- - Support for IP version 6 (IPv6). - - For general information about IPv6, see - . - For specific information about IPv6 under Linux, see - Documentation/networking/ipv6.txt and read the HOWTO at - - - To compile this protocol support as a module, choose M here: the - module will be called ipv6. - -if IPV6 - -config IPV6_ROUTER_PREF - bool "IPv6: Router Preference (RFC 4191) support" - ---help--- - Router Preference is an optional extension to the Router - Advertisement message which improves the ability of hosts - to pick an appropriate router, especially when the hosts - are placed in a multi-homed network. - - If unsure, say N. - -config IPV6_ROUTE_INFO - bool "IPv6: Route Information (RFC 4191) support" - depends on IPV6_ROUTER_PREF - ---help--- - This is experimental support of Route Information. - - If unsure, say N. - -config IPV6_OPTIMISTIC_DAD - bool "IPv6: Enable RFC 4429 Optimistic DAD" - ---help--- - This is experimental support for optimistic Duplicate - Address Detection. It allows for autoconfigured addresses - to be used more quickly. - - If unsure, say N. - -config INET6_AH - tristate "IPv6: AH transformation" - select XFRM_ALGO - select CRYPTO - select CRYPTO_HMAC - select CRYPTO_MD5 - select CRYPTO_SHA1 - ---help--- - Support for IPsec AH. - - If unsure, say Y. - -config INET6_ESP - tristate "IPv6: ESP transformation" - select XFRM_ALGO - select CRYPTO - select CRYPTO_AUTHENC - select CRYPTO_HMAC - select CRYPTO_MD5 - select CRYPTO_CBC - select CRYPTO_SHA1 - select CRYPTO_DES - select CRYPTO_ECHAINIV - ---help--- - Support for IPsec ESP. - - If unsure, say Y. - -config INET6_IPCOMP - tristate "IPv6: IPComp transformation" - select INET6_XFRM_TUNNEL - select XFRM_IPCOMP - ---help--- - Support for IP Payload Compression Protocol (IPComp) (RFC3173), - typically needed for IPsec. - - If unsure, say Y. - -config IPV6_MIP6 - tristate "IPv6: Mobility" - select XFRM - ---help--- - Support for IPv6 Mobility described in RFC 3775. - - If unsure, say N. - -config IPV6_ILA - tristate "IPv6: Identifier Locator Addressing (ILA)" - depends on NETFILTER - select LWTUNNEL - ---help--- - Support for IPv6 Identifier Locator Addressing (ILA). - - ILA is a mechanism to do network virtualization without - encapsulation. The basic concept of ILA is that we split an - IPv6 address into a 64 bit locator and 64 bit identifier. The - identifier is the identity of an entity in communication - ("who") and the locator expresses the location of the - entity ("where"). - - ILA can be configured using the "encap ila" option with - "ip -6 route" command. ILA is described in - https://tools.ietf.org/html/draft-herbert-nvo3-ila-00. - - If unsure, say N. - -config INET6_XFRM_TUNNEL - tristate - select INET6_TUNNEL - default n - -config INET6_TUNNEL - tristate - default n - -config INET6_XFRM_MODE_TRANSPORT - tristate "IPv6: IPsec transport mode" - default IPV6 - select XFRM - ---help--- - Support for IPsec transport mode. - - If unsure, say Y. - -config INET6_XFRM_MODE_TUNNEL - tristate "IPv6: IPsec tunnel mode" - default IPV6 - select XFRM - ---help--- - Support for IPsec tunnel mode. - - If unsure, say Y. - -config INET6_XFRM_MODE_BEET - tristate "IPv6: IPsec BEET mode" - default IPV6 - select XFRM - ---help--- - Support for IPsec BEET mode. - - If unsure, say Y. - -config INET6_XFRM_MODE_ROUTEOPTIMIZATION - tristate "IPv6: MIPv6 route optimization mode" - select XFRM - ---help--- - Support for MIPv6 route optimization mode. - -config IPV6_VTI -tristate "Virtual (secure) IPv6: tunneling" - select IPV6_TUNNEL - select NET_IP_TUNNEL - depends on INET6_XFRM_MODE_TUNNEL - ---help--- - Tunneling means encapsulating data of one protocol type within - another protocol and sending it over a channel that understands the - encapsulating protocol. This can be used with xfrm mode tunnel to give - the notion of a secure tunnel for IPSEC and then use routing protocol - on top. - -config IPV6_SIT - tristate "IPv6: IPv6-in-IPv4 tunnel (SIT driver)" - select INET_TUNNEL - select NET_IP_TUNNEL - select IPV6_NDISC_NODETYPE - default y - ---help--- - Tunneling means encapsulating data of one protocol type within - another protocol and sending it over a channel that understands the - encapsulating protocol. This driver implements encapsulation of IPv6 - into IPv4 packets. This is useful if you want to connect two IPv6 - networks over an IPv4-only path. - - Saying M here will produce a module called sit. If unsure, say Y. - -config IPV6_SIT_6RD - bool "IPv6: IPv6 Rapid Deployment (6RD)" - depends on IPV6_SIT - default n - ---help--- - IPv6 Rapid Deployment (6rd; draft-ietf-softwire-ipv6-6rd) builds upon - mechanisms of 6to4 (RFC3056) to enable a service provider to rapidly - deploy IPv6 unicast service to IPv4 sites to which it provides - customer premise equipment. Like 6to4, it utilizes stateless IPv6 in - IPv4 encapsulation in order to transit IPv4-only network - infrastructure. Unlike 6to4, a 6rd service provider uses an IPv6 - prefix of its own in place of the fixed 6to4 prefix. - - With this option enabled, the SIT driver offers 6rd functionality by - providing additional ioctl API to configure the IPv6 Prefix for in - stead of static 2002::/16 for 6to4. - - If unsure, say N. - -config IPV6_NDISC_NODETYPE - bool - -config IPV6_TUNNEL - tristate "IPv6: IP-in-IPv6 tunnel (RFC2473)" - select INET6_TUNNEL - select DST_CACHE - ---help--- - Support for IPv6-in-IPv6 and IPv4-in-IPv6 tunnels described in - RFC 2473. - - If unsure, say N. - -config IPV6_GRE - tristate "IPv6: GRE tunnel" - select IPV6_TUNNEL - select NET_IP_TUNNEL - depends on NET_IPGRE_DEMUX - ---help--- - Tunneling means encapsulating data of one protocol type within - another protocol and sending it over a channel that understands the - encapsulating protocol. This particular tunneling driver implements - GRE (Generic Routing Encapsulation) and at this time allows - encapsulating of IPv4 or IPv6 over existing IPv6 infrastructure. - This driver is useful if the other endpoint is a Cisco router: Cisco - likes GRE much better than the other Linux tunneling driver ("IP - tunneling" above). In addition, GRE allows multicast redistribution - through the tunnel. - - Saying M here will produce a module called ip6_gre. If unsure, say N. - -config IPV6_FOU - tristate - default NET_FOU && IPV6 - -config IPV6_FOU_TUNNEL - tristate - default NET_FOU_IP_TUNNELS && IPV6_FOU - select IPV6_TUNNEL - -config IPV6_MULTIPLE_TABLES - bool "IPv6: Multiple Routing Tables" - select FIB_RULES - ---help--- - Support multiple routing tables. - -config IPV6_SUBTREES - bool "IPv6: source address based routing" - depends on IPV6_MULTIPLE_TABLES - ---help--- - Enable routing by source address or prefix. - - The destination address is still the primary routing key, so mixing - normal and source prefix specific routes in the same routing table - may sometimes lead to unintended routing behavior. This can be - avoided by defining different routing tables for the normal and - source prefix specific routes. - - If unsure, say N. - -config IPV6_MROUTE - bool "IPv6: multicast routing" - depends on IPV6 - ---help--- - Experimental support for IPv6 multicast forwarding. - If unsure, say N. - -config IPV6_MROUTE_MULTIPLE_TABLES - bool "IPv6: multicast policy routing" - depends on IPV6_MROUTE - select FIB_RULES - help - Normally, a multicast router runs a userspace daemon and decides - what to do with a multicast packet based on the source and - destination addresses. If you say Y here, the multicast router - will also be able to take interfaces and packet marks into - account and run multiple instances of userspace daemons - simultaneously, each one handling a single table. - - If unsure, say N. - -config IPV6_PIMSM_V2 - bool "IPv6: PIM-SM version 2 support" - depends on IPV6_MROUTE - ---help--- - Support for IPv6 PIM multicast routing protocol PIM-SMv2. - If unsure, say N. - -endif # IPV6 diff --git a/src/linux/net/ipv6/Makefile b/src/linux/net/ipv6/Makefile deleted file mode 100644 index c174ccb..0000000 --- a/src/linux/net/ipv6/Makefile +++ /dev/null @@ -1,56 +0,0 @@ -# -# Makefile for the Linux TCP/IP (INET6) layer. -# - -obj-$(CONFIG_IPV6) += ipv6.o - -ipv6-objs := af_inet6.o anycast.o ip6_output.o ip6_input.o addrconf.o \ - addrlabel.o \ - route.o ip6_fib.o ipv6_sockglue.o ndisc.o udp.o udplite.o \ - raw.o icmp.o mcast.o reassembly.o tcp_ipv6.o ping.o \ - exthdrs.o datagram.o ip6_flowlabel.o inet6_connection_sock.o \ - udp_offload.o - -ipv6-offload := ip6_offload.o tcpv6_offload.o exthdrs_offload.o - -ipv6-$(CONFIG_SYSCTL) = sysctl_net_ipv6.o -ipv6-$(CONFIG_IPV6_MROUTE) += ip6mr.o - -ipv6-$(CONFIG_XFRM) += xfrm6_policy.o xfrm6_state.o xfrm6_input.o \ - xfrm6_output.o xfrm6_protocol.o -ipv6-$(CONFIG_NETFILTER) += netfilter.o -ipv6-$(CONFIG_IPV6_MULTIPLE_TABLES) += fib6_rules.o -ipv6-$(CONFIG_PROC_FS) += proc.o -ipv6-$(CONFIG_SYN_COOKIES) += syncookies.o -ipv6-$(CONFIG_NETLABEL) += calipso.o - -ipv6-objs += $(ipv6-y) - -obj-$(CONFIG_INET6_AH) += ah6.o -obj-$(CONFIG_INET6_ESP) += esp6.o -obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o -obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o -obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o -obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o -obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o -obj-$(CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION) += xfrm6_mode_ro.o -obj-$(CONFIG_INET6_XFRM_MODE_BEET) += xfrm6_mode_beet.o -obj-$(CONFIG_IPV6_MIP6) += mip6.o -obj-$(CONFIG_IPV6_ILA) += ila/ -obj-$(CONFIG_NETFILTER) += netfilter/ - -obj-$(CONFIG_IPV6_VTI) += ip6_vti.o -obj-$(CONFIG_IPV6_SIT) += sit.o -obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o -obj-$(CONFIG_IPV6_GRE) += ip6_gre.o -obj-$(CONFIG_IPV6_FOU) += fou6.o - -obj-y += addrconf_core.o exthdrs_core.o ip6_checksum.o ip6_icmp.o -obj-$(CONFIG_INET) += output_core.o protocol.o $(ipv6-offload) - -obj-$(subst m,y,$(CONFIG_IPV6)) += inet6_hashtables.o - -ifneq ($(CONFIG_IPV6),) -obj-$(CONFIG_NET_UDP_TUNNEL) += ip6_udp_tunnel.o -obj-y += mcast_snoop.o -endif diff --git a/src/linux/net/ipv6/addrconf.c b/src/linux/net/ipv6/addrconf.c deleted file mode 100644 index 4bc5ba3..0000000 --- a/src/linux/net/ipv6/addrconf.c +++ /dev/null @@ -1,6329 +0,0 @@ -/* - * IPv6 Address [auto]configuration - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * Alexey Kuznetsov - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -/* - * Changes: - * - * Janos Farkas : delete timer on ifdown - * - * Andi Kleen : kill double kfree on module - * unload. - * Maciej W. Rozycki : FDDI support - * sekiya@USAGI : Don't send too many RS - * packets. - * yoshfuji@USAGI : Fixed interval between DAD - * packets. - * YOSHIFUJI Hideaki @USAGI : improved accuracy of - * address validation timer. - * YOSHIFUJI Hideaki @USAGI : Privacy Extensions (RFC3041) - * support. - * Yuji SEKIYA @USAGI : Don't assign a same IPv6 - * address on a same interface. - * YOSHIFUJI Hideaki @USAGI : ARCnet support - * YOSHIFUJI Hideaki @USAGI : convert /proc/net/if_inet6 to - * seq_file. - * YOSHIFUJI Hideaki @USAGI : improved source address - * selection; consider scope, - * status etc. - */ - -#define pr_fmt(fmt) "IPv6: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_SYSCTL -#include -#endif -#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 -#include - -/* Set to 3 to get tracing... */ -#define ACONF_DEBUG 2 - -#if ACONF_DEBUG >= 3 -#define ADBG(fmt, ...) printk(fmt, ##__VA_ARGS__) -#else -#define ADBG(fmt, ...) do { if (0) printk(fmt, ##__VA_ARGS__); } while (0) -#endif - -#define INFINITY_LIFE_TIME 0xFFFFFFFF - -#define IPV6_MAX_STRLEN \ - sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255") - -static inline u32 cstamp_delta(unsigned long cstamp) -{ - return (cstamp - INITIAL_JIFFIES) * 100UL / HZ; -} - -static inline s32 rfc3315_s14_backoff_init(s32 irt) -{ - /* multiply 'initial retransmission time' by 0.9 .. 1.1 */ - u64 tmp = (900000 + prandom_u32() % 200001) * (u64)irt; - do_div(tmp, 1000000); - return (s32)tmp; -} - -static inline s32 rfc3315_s14_backoff_update(s32 rt, s32 mrt) -{ - /* multiply 'retransmission timeout' by 1.9 .. 2.1 */ - u64 tmp = (1900000 + prandom_u32() % 200001) * (u64)rt; - do_div(tmp, 1000000); - if ((s32)tmp > mrt) { - /* multiply 'maximum retransmission time' by 0.9 .. 1.1 */ - tmp = (900000 + prandom_u32() % 200001) * (u64)mrt; - do_div(tmp, 1000000); - } - return (s32)tmp; -} - -#ifdef CONFIG_SYSCTL -static int addrconf_sysctl_register(struct inet6_dev *idev); -static void addrconf_sysctl_unregister(struct inet6_dev *idev); -#else -static inline int addrconf_sysctl_register(struct inet6_dev *idev) -{ - return 0; -} - -static inline void addrconf_sysctl_unregister(struct inet6_dev *idev) -{ -} -#endif - -static void ipv6_regen_rndid(struct inet6_dev *idev); -static void ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr); - -static int ipv6_generate_eui64(u8 *eui, struct net_device *dev); -static int ipv6_count_addresses(struct inet6_dev *idev); -static int ipv6_generate_stable_address(struct in6_addr *addr, - u8 dad_count, - const struct inet6_dev *idev); - -/* - * Configured unicast address hash table - */ -static struct hlist_head inet6_addr_lst[IN6_ADDR_HSIZE]; -static DEFINE_SPINLOCK(addrconf_hash_lock); - -static void addrconf_verify(void); -static void addrconf_verify_rtnl(void); -static void addrconf_verify_work(struct work_struct *); - -static struct workqueue_struct *addrconf_wq; -static DECLARE_DELAYED_WORK(addr_chk_work, addrconf_verify_work); - -static void addrconf_join_anycast(struct inet6_ifaddr *ifp); -static void addrconf_leave_anycast(struct inet6_ifaddr *ifp); - -static void addrconf_type_change(struct net_device *dev, - unsigned long event); -static int addrconf_ifdown(struct net_device *dev, int how); - -static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, - int plen, - const struct net_device *dev, - u32 flags, u32 noflags); - -static void addrconf_dad_start(struct inet6_ifaddr *ifp); -static void addrconf_dad_work(struct work_struct *w); -static void addrconf_dad_completed(struct inet6_ifaddr *ifp, bool bump_id); -static void addrconf_dad_run(struct inet6_dev *idev); -static void addrconf_rs_timer(unsigned long data); -static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); -static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa); - -static void inet6_prefix_notify(int event, struct inet6_dev *idev, - struct prefix_info *pinfo); -static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, - struct net_device *dev); - -static struct ipv6_devconf ipv6_devconf __read_mostly = { - .forwarding = 0, - .hop_limit = IPV6_DEFAULT_HOPLIMIT, - .mtu6 = IPV6_MIN_MTU, - .accept_ra = 1, - .accept_redirects = 1, - .autoconf = 1, - .force_mld_version = 0, - .mldv1_unsolicited_report_interval = 10 * HZ, - .mldv2_unsolicited_report_interval = HZ, - .dad_transmits = 1, - .rtr_solicits = MAX_RTR_SOLICITATIONS, - .rtr_solicit_interval = RTR_SOLICITATION_INTERVAL, - .rtr_solicit_max_interval = RTR_SOLICITATION_MAX_INTERVAL, - .rtr_solicit_delay = MAX_RTR_SOLICITATION_DELAY, - .use_tempaddr = 0, - .temp_valid_lft = TEMP_VALID_LIFETIME, - .temp_prefered_lft = TEMP_PREFERRED_LIFETIME, - .regen_max_retry = REGEN_MAX_RETRY, - .max_desync_factor = MAX_DESYNC_FACTOR, - .max_addresses = IPV6_MAX_ADDRESSES, - .accept_ra_defrtr = 1, - .accept_ra_from_local = 0, - .accept_ra_min_hop_limit= 1, - .accept_ra_pinfo = 1, -#ifdef CONFIG_IPV6_ROUTER_PREF - .accept_ra_rtr_pref = 1, - .rtr_probe_interval = 60 * HZ, -#ifdef CONFIG_IPV6_ROUTE_INFO - .accept_ra_rt_info_max_plen = 0, -#endif -#endif - .proxy_ndp = 0, - .accept_source_route = 0, /* we do not accept RH0 by default. */ - .disable_ipv6 = 0, - .accept_dad = 1, - .suppress_frag_ndisc = 1, - .accept_ra_mtu = 1, - .stable_secret = { - .initialized = false, - }, - .use_oif_addrs_only = 0, - .ignore_routes_with_linkdown = 0, - .keep_addr_on_down = 0, -}; - -static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = { - .forwarding = 0, - .hop_limit = IPV6_DEFAULT_HOPLIMIT, - .mtu6 = IPV6_MIN_MTU, - .accept_ra = 1, - .accept_redirects = 1, - .autoconf = 1, - .force_mld_version = 0, - .mldv1_unsolicited_report_interval = 10 * HZ, - .mldv2_unsolicited_report_interval = HZ, - .dad_transmits = 1, - .rtr_solicits = MAX_RTR_SOLICITATIONS, - .rtr_solicit_interval = RTR_SOLICITATION_INTERVAL, - .rtr_solicit_max_interval = RTR_SOLICITATION_MAX_INTERVAL, - .rtr_solicit_delay = MAX_RTR_SOLICITATION_DELAY, - .use_tempaddr = 0, - .temp_valid_lft = TEMP_VALID_LIFETIME, - .temp_prefered_lft = TEMP_PREFERRED_LIFETIME, - .regen_max_retry = REGEN_MAX_RETRY, - .max_desync_factor = MAX_DESYNC_FACTOR, - .max_addresses = IPV6_MAX_ADDRESSES, - .accept_ra_defrtr = 1, - .accept_ra_from_local = 0, - .accept_ra_min_hop_limit= 1, - .accept_ra_pinfo = 1, -#ifdef CONFIG_IPV6_ROUTER_PREF - .accept_ra_rtr_pref = 1, - .rtr_probe_interval = 60 * HZ, -#ifdef CONFIG_IPV6_ROUTE_INFO - .accept_ra_rt_info_max_plen = 0, -#endif -#endif - .proxy_ndp = 0, - .accept_source_route = 0, /* we do not accept RH0 by default. */ - .disable_ipv6 = 0, - .accept_dad = 1, - .suppress_frag_ndisc = 1, - .accept_ra_mtu = 1, - .stable_secret = { - .initialized = false, - }, - .use_oif_addrs_only = 0, - .ignore_routes_with_linkdown = 0, - .keep_addr_on_down = 0, -}; - -/* Check if a valid qdisc is available */ -static inline bool addrconf_qdisc_ok(const struct net_device *dev) -{ - return !qdisc_tx_is_noop(dev); -} - -static void addrconf_del_rs_timer(struct inet6_dev *idev) -{ - if (del_timer(&idev->rs_timer)) - __in6_dev_put(idev); -} - -static void addrconf_del_dad_work(struct inet6_ifaddr *ifp) -{ - if (cancel_delayed_work(&ifp->dad_work)) - __in6_ifa_put(ifp); -} - -static void addrconf_mod_rs_timer(struct inet6_dev *idev, - unsigned long when) -{ - if (!timer_pending(&idev->rs_timer)) - in6_dev_hold(idev); - mod_timer(&idev->rs_timer, jiffies + when); -} - -static void addrconf_mod_dad_work(struct inet6_ifaddr *ifp, - unsigned long delay) -{ - if (!delayed_work_pending(&ifp->dad_work)) - in6_ifa_hold(ifp); - mod_delayed_work(addrconf_wq, &ifp->dad_work, delay); -} - -static int snmp6_alloc_dev(struct inet6_dev *idev) -{ - int i; - - idev->stats.ipv6 = alloc_percpu(struct ipstats_mib); - if (!idev->stats.ipv6) - goto err_ip; - - for_each_possible_cpu(i) { - struct ipstats_mib *addrconf_stats; - addrconf_stats = per_cpu_ptr(idev->stats.ipv6, i); - u64_stats_init(&addrconf_stats->syncp); - } - - - idev->stats.icmpv6dev = kzalloc(sizeof(struct icmpv6_mib_device), - GFP_KERNEL); - if (!idev->stats.icmpv6dev) - goto err_icmp; - idev->stats.icmpv6msgdev = kzalloc(sizeof(struct icmpv6msg_mib_device), - GFP_KERNEL); - if (!idev->stats.icmpv6msgdev) - goto err_icmpmsg; - - return 0; - -err_icmpmsg: - kfree(idev->stats.icmpv6dev); -err_icmp: - free_percpu(idev->stats.ipv6); -err_ip: - return -ENOMEM; -} - -static struct inet6_dev *ipv6_add_dev(struct net_device *dev) -{ - struct inet6_dev *ndev; - int err = -ENOMEM; - - ASSERT_RTNL(); - - if (dev->mtu < IPV6_MIN_MTU) - return ERR_PTR(-EINVAL); - - ndev = kzalloc(sizeof(struct inet6_dev), GFP_KERNEL); - if (!ndev) - return ERR_PTR(err); - - rwlock_init(&ndev->lock); - ndev->dev = dev; - INIT_LIST_HEAD(&ndev->addr_list); - setup_timer(&ndev->rs_timer, addrconf_rs_timer, - (unsigned long)ndev); - memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf)); - - if (ndev->cnf.stable_secret.initialized) - ndev->addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY; - else - ndev->addr_gen_mode = IN6_ADDR_GEN_MODE_EUI64; - - ndev->cnf.mtu6 = dev->mtu; - ndev->nd_parms = neigh_parms_alloc(dev, &nd_tbl); - if (!ndev->nd_parms) { - kfree(ndev); - return ERR_PTR(err); - } - if (ndev->cnf.forwarding) - dev_disable_lro(dev); - /* We refer to the device */ - dev_hold(dev); - - if (snmp6_alloc_dev(ndev) < 0) { - ADBG(KERN_WARNING - "%s: cannot allocate memory for statistics; dev=%s.\n", - __func__, dev->name); - neigh_parms_release(&nd_tbl, ndev->nd_parms); - dev_put(dev); - kfree(ndev); - return ERR_PTR(err); - } - - if (snmp6_register_dev(ndev) < 0) { - ADBG(KERN_WARNING - "%s: cannot create /proc/net/dev_snmp6/%s\n", - __func__, dev->name); - goto err_release; - } - - /* One reference from device. */ - in6_dev_hold(ndev); - - if (dev->flags & (IFF_NOARP | IFF_LOOPBACK)) - ndev->cnf.accept_dad = -1; - -#if IS_ENABLED(CONFIG_IPV6_SIT) - if (dev->type == ARPHRD_SIT && (dev->priv_flags & IFF_ISATAP)) { - pr_info("%s: Disabled Multicast RS\n", dev->name); - ndev->cnf.rtr_solicits = 0; - } -#endif - - INIT_LIST_HEAD(&ndev->tempaddr_list); - ndev->desync_factor = U32_MAX; - if ((dev->flags&IFF_LOOPBACK) || - dev->type == ARPHRD_TUNNEL || - dev->type == ARPHRD_TUNNEL6 || - dev->type == ARPHRD_SIT || - dev->type == ARPHRD_NONE) { - ndev->cnf.use_tempaddr = -1; - } else - ipv6_regen_rndid(ndev); - - ndev->token = in6addr_any; - - if (netif_running(dev) && addrconf_qdisc_ok(dev)) - ndev->if_flags |= IF_READY; - - ipv6_mc_init_dev(ndev); - ndev->tstamp = jiffies; - err = addrconf_sysctl_register(ndev); - if (err) { - ipv6_mc_destroy_dev(ndev); - snmp6_unregister_dev(ndev); - goto err_release; - } - /* protected by rtnl_lock */ - rcu_assign_pointer(dev->ip6_ptr, ndev); - - /* Join interface-local all-node multicast group */ - ipv6_dev_mc_inc(dev, &in6addr_interfacelocal_allnodes); - - /* Join all-node multicast group */ - ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes); - - /* Join all-router multicast group if forwarding is set */ - if (ndev->cnf.forwarding && (dev->flags & IFF_MULTICAST)) - ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); - - return ndev; - -err_release: - neigh_parms_release(&nd_tbl, ndev->nd_parms); - ndev->dead = 1; - in6_dev_finish_destroy(ndev); - return ERR_PTR(err); -} - -static struct inet6_dev *ipv6_find_idev(struct net_device *dev) -{ - struct inet6_dev *idev; - - ASSERT_RTNL(); - - idev = __in6_dev_get(dev); - if (!idev) { - idev = ipv6_add_dev(dev); - if (IS_ERR(idev)) - return NULL; - } - - if (dev->flags&IFF_UP) - ipv6_mc_up(idev); - return idev; -} - -static int inet6_netconf_msgsize_devconf(int type) -{ - int size = NLMSG_ALIGN(sizeof(struct netconfmsg)) - + nla_total_size(4); /* NETCONFA_IFINDEX */ - bool all = false; - - if (type == NETCONFA_ALL) - all = true; - - if (all || type == NETCONFA_FORWARDING) - size += nla_total_size(4); -#ifdef CONFIG_IPV6_MROUTE - if (all || type == NETCONFA_MC_FORWARDING) - size += nla_total_size(4); -#endif - if (all || type == NETCONFA_PROXY_NEIGH) - size += nla_total_size(4); - - if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) - size += nla_total_size(4); - - return size; -} - -static int inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex, - struct ipv6_devconf *devconf, u32 portid, - u32 seq, int event, unsigned int flags, - int type) -{ - struct nlmsghdr *nlh; - struct netconfmsg *ncm; - bool all = false; - - nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct netconfmsg), - flags); - if (!nlh) - return -EMSGSIZE; - - if (type == NETCONFA_ALL) - all = true; - - ncm = nlmsg_data(nlh); - ncm->ncm_family = AF_INET6; - - if (nla_put_s32(skb, NETCONFA_IFINDEX, ifindex) < 0) - goto nla_put_failure; - - if ((all || type == NETCONFA_FORWARDING) && - nla_put_s32(skb, NETCONFA_FORWARDING, devconf->forwarding) < 0) - goto nla_put_failure; -#ifdef CONFIG_IPV6_MROUTE - if ((all || type == NETCONFA_MC_FORWARDING) && - nla_put_s32(skb, NETCONFA_MC_FORWARDING, - devconf->mc_forwarding) < 0) - goto nla_put_failure; -#endif - if ((all || type == NETCONFA_PROXY_NEIGH) && - nla_put_s32(skb, NETCONFA_PROXY_NEIGH, devconf->proxy_ndp) < 0) - goto nla_put_failure; - - if ((all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN) && - nla_put_s32(skb, NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, - devconf->ignore_routes_with_linkdown) < 0) - goto nla_put_failure; - - nlmsg_end(skb, nlh); - return 0; - -nla_put_failure: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -void inet6_netconf_notify_devconf(struct net *net, int type, int ifindex, - struct ipv6_devconf *devconf) -{ - struct sk_buff *skb; - int err = -ENOBUFS; - - skb = nlmsg_new(inet6_netconf_msgsize_devconf(type), GFP_KERNEL); - if (!skb) - goto errout; - - err = inet6_netconf_fill_devconf(skb, ifindex, devconf, 0, 0, - RTM_NEWNETCONF, 0, type); - if (err < 0) { - /* -EMSGSIZE implies BUG in inet6_netconf_msgsize_devconf() */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - goto errout; - } - rtnl_notify(skb, net, 0, RTNLGRP_IPV6_NETCONF, NULL, GFP_KERNEL); - return; -errout: - rtnl_set_sk_err(net, RTNLGRP_IPV6_NETCONF, err); -} - -static const struct nla_policy devconf_ipv6_policy[NETCONFA_MAX+1] = { - [NETCONFA_IFINDEX] = { .len = sizeof(int) }, - [NETCONFA_FORWARDING] = { .len = sizeof(int) }, - [NETCONFA_PROXY_NEIGH] = { .len = sizeof(int) }, - [NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN] = { .len = sizeof(int) }, -}; - -static int inet6_netconf_get_devconf(struct sk_buff *in_skb, - struct nlmsghdr *nlh) -{ - struct net *net = sock_net(in_skb->sk); - struct nlattr *tb[NETCONFA_MAX+1]; - struct netconfmsg *ncm; - struct sk_buff *skb; - struct ipv6_devconf *devconf; - struct inet6_dev *in6_dev; - struct net_device *dev; - int ifindex; - int err; - - err = nlmsg_parse(nlh, sizeof(*ncm), tb, NETCONFA_MAX, - devconf_ipv6_policy); - if (err < 0) - goto errout; - - err = -EINVAL; - if (!tb[NETCONFA_IFINDEX]) - goto errout; - - ifindex = nla_get_s32(tb[NETCONFA_IFINDEX]); - switch (ifindex) { - case NETCONFA_IFINDEX_ALL: - devconf = net->ipv6.devconf_all; - break; - case NETCONFA_IFINDEX_DEFAULT: - devconf = net->ipv6.devconf_dflt; - break; - default: - dev = __dev_get_by_index(net, ifindex); - if (!dev) - goto errout; - in6_dev = __in6_dev_get(dev); - if (!in6_dev) - goto errout; - devconf = &in6_dev->cnf; - break; - } - - err = -ENOBUFS; - skb = nlmsg_new(inet6_netconf_msgsize_devconf(NETCONFA_ALL), GFP_ATOMIC); - if (!skb) - goto errout; - - err = inet6_netconf_fill_devconf(skb, ifindex, devconf, - NETLINK_CB(in_skb).portid, - nlh->nlmsg_seq, RTM_NEWNETCONF, 0, - NETCONFA_ALL); - if (err < 0) { - /* -EMSGSIZE implies BUG in inet6_netconf_msgsize_devconf() */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - goto errout; - } - err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); -errout: - return err; -} - -static int inet6_netconf_dump_devconf(struct sk_buff *skb, - struct netlink_callback *cb) -{ - struct net *net = sock_net(skb->sk); - int h, s_h; - int idx, s_idx; - struct net_device *dev; - struct inet6_dev *idev; - struct hlist_head *head; - - s_h = cb->args[0]; - s_idx = idx = cb->args[1]; - - for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { - idx = 0; - head = &net->dev_index_head[h]; - rcu_read_lock(); - cb->seq = atomic_read(&net->ipv6.dev_addr_genid) ^ - net->dev_base_seq; - hlist_for_each_entry_rcu(dev, head, index_hlist) { - if (idx < s_idx) - goto cont; - idev = __in6_dev_get(dev); - if (!idev) - goto cont; - - if (inet6_netconf_fill_devconf(skb, dev->ifindex, - &idev->cnf, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWNETCONF, - NLM_F_MULTI, - NETCONFA_ALL) < 0) { - rcu_read_unlock(); - goto done; - } - nl_dump_check_consistent(cb, nlmsg_hdr(skb)); -cont: - idx++; - } - rcu_read_unlock(); - } - if (h == NETDEV_HASHENTRIES) { - if (inet6_netconf_fill_devconf(skb, NETCONFA_IFINDEX_ALL, - net->ipv6.devconf_all, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWNETCONF, NLM_F_MULTI, - NETCONFA_ALL) < 0) - goto done; - else - h++; - } - if (h == NETDEV_HASHENTRIES + 1) { - if (inet6_netconf_fill_devconf(skb, NETCONFA_IFINDEX_DEFAULT, - net->ipv6.devconf_dflt, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWNETCONF, NLM_F_MULTI, - NETCONFA_ALL) < 0) - goto done; - else - h++; - } -done: - cb->args[0] = h; - cb->args[1] = idx; - - return skb->len; -} - -#ifdef CONFIG_SYSCTL -static void dev_forward_change(struct inet6_dev *idev) -{ - struct net_device *dev; - struct inet6_ifaddr *ifa; - - if (!idev) - return; - dev = idev->dev; - if (idev->cnf.forwarding) - dev_disable_lro(dev); - if (dev->flags & IFF_MULTICAST) { - if (idev->cnf.forwarding) { - ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters); - ipv6_dev_mc_inc(dev, &in6addr_interfacelocal_allrouters); - ipv6_dev_mc_inc(dev, &in6addr_sitelocal_allrouters); - } else { - ipv6_dev_mc_dec(dev, &in6addr_linklocal_allrouters); - ipv6_dev_mc_dec(dev, &in6addr_interfacelocal_allrouters); - ipv6_dev_mc_dec(dev, &in6addr_sitelocal_allrouters); - } - } - - list_for_each_entry(ifa, &idev->addr_list, if_list) { - if (ifa->flags&IFA_F_TENTATIVE) - continue; - if (idev->cnf.forwarding) - addrconf_join_anycast(ifa); - else - addrconf_leave_anycast(ifa); - } - inet6_netconf_notify_devconf(dev_net(dev), NETCONFA_FORWARDING, - dev->ifindex, &idev->cnf); -} - - -static void addrconf_forward_change(struct net *net, __s32 newf) -{ - struct net_device *dev; - struct inet6_dev *idev; - - for_each_netdev(net, dev) { - idev = __in6_dev_get(dev); - if (idev) { - int changed = (!idev->cnf.forwarding) ^ (!newf); - idev->cnf.forwarding = newf; - if (changed) - dev_forward_change(idev); - } - } -} - -static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf) -{ - struct net *net; - int old; - - if (!rtnl_trylock()) - return restart_syscall(); - - net = (struct net *)table->extra2; - old = *p; - *p = newf; - - if (p == &net->ipv6.devconf_dflt->forwarding) { - if ((!newf) ^ (!old)) - inet6_netconf_notify_devconf(net, NETCONFA_FORWARDING, - NETCONFA_IFINDEX_DEFAULT, - net->ipv6.devconf_dflt); - rtnl_unlock(); - return 0; - } - - if (p == &net->ipv6.devconf_all->forwarding) { - int old_dflt = net->ipv6.devconf_dflt->forwarding; - - net->ipv6.devconf_dflt->forwarding = newf; - if ((!newf) ^ (!old_dflt)) - inet6_netconf_notify_devconf(net, NETCONFA_FORWARDING, - NETCONFA_IFINDEX_DEFAULT, - net->ipv6.devconf_dflt); - - addrconf_forward_change(net, newf); - if ((!newf) ^ (!old)) - inet6_netconf_notify_devconf(net, NETCONFA_FORWARDING, - NETCONFA_IFINDEX_ALL, - net->ipv6.devconf_all); - } else if ((!newf) ^ (!old)) - dev_forward_change((struct inet6_dev *)table->extra1); - rtnl_unlock(); - - if (newf) - rt6_purge_dflt_routers(net); - return 1; -} - -static void addrconf_linkdown_change(struct net *net, __s32 newf) -{ - struct net_device *dev; - struct inet6_dev *idev; - - for_each_netdev(net, dev) { - idev = __in6_dev_get(dev); - if (idev) { - int changed = (!idev->cnf.ignore_routes_with_linkdown) ^ (!newf); - - idev->cnf.ignore_routes_with_linkdown = newf; - if (changed) - inet6_netconf_notify_devconf(dev_net(dev), - NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, - dev->ifindex, - &idev->cnf); - } - } -} - -static int addrconf_fixup_linkdown(struct ctl_table *table, int *p, int newf) -{ - struct net *net; - int old; - - if (!rtnl_trylock()) - return restart_syscall(); - - net = (struct net *)table->extra2; - old = *p; - *p = newf; - - if (p == &net->ipv6.devconf_dflt->ignore_routes_with_linkdown) { - if ((!newf) ^ (!old)) - inet6_netconf_notify_devconf(net, - NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, - NETCONFA_IFINDEX_DEFAULT, - net->ipv6.devconf_dflt); - rtnl_unlock(); - return 0; - } - - if (p == &net->ipv6.devconf_all->ignore_routes_with_linkdown) { - net->ipv6.devconf_dflt->ignore_routes_with_linkdown = newf; - addrconf_linkdown_change(net, newf); - if ((!newf) ^ (!old)) - inet6_netconf_notify_devconf(net, - NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN, - NETCONFA_IFINDEX_ALL, - net->ipv6.devconf_all); - } - rtnl_unlock(); - - return 1; -} - -#endif - -/* Nobody refers to this ifaddr, destroy it */ -void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp) -{ - WARN_ON(!hlist_unhashed(&ifp->addr_lst)); - -#ifdef NET_REFCNT_DEBUG - pr_debug("%s\n", __func__); -#endif - - in6_dev_put(ifp->idev); - - if (cancel_delayed_work(&ifp->dad_work)) - pr_notice("delayed DAD work was pending while freeing ifa=%p\n", - ifp); - - if (ifp->state != INET6_IFADDR_STATE_DEAD) { - pr_warn("Freeing alive inet6 address %p\n", ifp); - return; - } - ip6_rt_put(ifp->rt); - - kfree_rcu(ifp, rcu); -} - -static void -ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp) -{ - struct list_head *p; - int ifp_scope = ipv6_addr_src_scope(&ifp->addr); - - /* - * Each device address list is sorted in order of scope - - * global before linklocal. - */ - list_for_each(p, &idev->addr_list) { - struct inet6_ifaddr *ifa - = list_entry(p, struct inet6_ifaddr, if_list); - if (ifp_scope >= ipv6_addr_src_scope(&ifa->addr)) - break; - } - - list_add_tail(&ifp->if_list, p); -} - -static u32 inet6_addr_hash(const struct in6_addr *addr) -{ - return hash_32(ipv6_addr_hash(addr), IN6_ADDR_HSIZE_SHIFT); -} - -/* On success it returns ifp with increased reference count */ - -static struct inet6_ifaddr * -ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, - const struct in6_addr *peer_addr, int pfxlen, - int scope, u32 flags, u32 valid_lft, u32 prefered_lft) -{ - struct inet6_ifaddr *ifa = NULL; - struct rt6_info *rt; - unsigned int hash; - int err = 0; - int addr_type = ipv6_addr_type(addr); - - if (addr_type == IPV6_ADDR_ANY || - addr_type & IPV6_ADDR_MULTICAST || - (!(idev->dev->flags & IFF_LOOPBACK) && - addr_type & IPV6_ADDR_LOOPBACK)) - return ERR_PTR(-EADDRNOTAVAIL); - - rcu_read_lock_bh(); - if (idev->dead) { - err = -ENODEV; /*XXX*/ - goto out2; - } - - if (idev->cnf.disable_ipv6) { - err = -EACCES; - goto out2; - } - - spin_lock(&addrconf_hash_lock); - - /* Ignore adding duplicate addresses on an interface */ - if (ipv6_chk_same_addr(dev_net(idev->dev), addr, idev->dev)) { - ADBG("ipv6_add_addr: already assigned\n"); - err = -EEXIST; - goto out; - } - - ifa = kzalloc(sizeof(struct inet6_ifaddr), GFP_ATOMIC); - - if (!ifa) { - ADBG("ipv6_add_addr: malloc failed\n"); - err = -ENOBUFS; - goto out; - } - - rt = addrconf_dst_alloc(idev, addr, false); - if (IS_ERR(rt)) { - err = PTR_ERR(rt); - goto out; - } - - neigh_parms_data_state_setall(idev->nd_parms); - - ifa->addr = *addr; - if (peer_addr) - ifa->peer_addr = *peer_addr; - - spin_lock_init(&ifa->lock); - INIT_DELAYED_WORK(&ifa->dad_work, addrconf_dad_work); - INIT_HLIST_NODE(&ifa->addr_lst); - ifa->scope = scope; - ifa->prefix_len = pfxlen; - ifa->flags = flags | IFA_F_TENTATIVE; - ifa->valid_lft = valid_lft; - ifa->prefered_lft = prefered_lft; - ifa->cstamp = ifa->tstamp = jiffies; - ifa->tokenized = false; - - ifa->rt = rt; - - ifa->idev = idev; - in6_dev_hold(idev); - /* For caller */ - in6_ifa_hold(ifa); - - /* Add to big hash table */ - hash = inet6_addr_hash(addr); - - hlist_add_head_rcu(&ifa->addr_lst, &inet6_addr_lst[hash]); - spin_unlock(&addrconf_hash_lock); - - write_lock(&idev->lock); - /* Add to inet6_dev unicast addr list. */ - ipv6_link_dev_addr(idev, ifa); - - if (ifa->flags&IFA_F_TEMPORARY) { - list_add(&ifa->tmp_list, &idev->tempaddr_list); - in6_ifa_hold(ifa); - } - - in6_ifa_hold(ifa); - write_unlock(&idev->lock); -out2: - rcu_read_unlock_bh(); - - if (likely(err == 0)) - inet6addr_notifier_call_chain(NETDEV_UP, ifa); - else { - kfree(ifa); - ifa = ERR_PTR(err); - } - - return ifa; -out: - spin_unlock(&addrconf_hash_lock); - goto out2; -} - -enum cleanup_prefix_rt_t { - CLEANUP_PREFIX_RT_NOP, /* no cleanup action for prefix route */ - CLEANUP_PREFIX_RT_DEL, /* delete the prefix route */ - CLEANUP_PREFIX_RT_EXPIRE, /* update the lifetime of the prefix route */ -}; - -/* - * Check, whether the prefix for ifp would still need a prefix route - * after deleting ifp. The function returns one of the CLEANUP_PREFIX_RT_* - * constants. - * - * 1) we don't purge prefix if address was not permanent. - * prefix is managed by its own lifetime. - * 2) we also don't purge, if the address was IFA_F_NOPREFIXROUTE. - * 3) if there are no addresses, delete prefix. - * 4) if there are still other permanent address(es), - * corresponding prefix is still permanent. - * 5) if there are still other addresses with IFA_F_NOPREFIXROUTE, - * don't purge the prefix, assume user space is managing it. - * 6) otherwise, update prefix lifetime to the - * longest valid lifetime among the corresponding - * addresses on the device. - * Note: subsequent RA will update lifetime. - **/ -static enum cleanup_prefix_rt_t -check_cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long *expires) -{ - struct inet6_ifaddr *ifa; - struct inet6_dev *idev = ifp->idev; - unsigned long lifetime; - enum cleanup_prefix_rt_t action = CLEANUP_PREFIX_RT_DEL; - - *expires = jiffies; - - list_for_each_entry(ifa, &idev->addr_list, if_list) { - if (ifa == ifp) - continue; - if (!ipv6_prefix_equal(&ifa->addr, &ifp->addr, - ifp->prefix_len)) - continue; - if (ifa->flags & (IFA_F_PERMANENT | IFA_F_NOPREFIXROUTE)) - return CLEANUP_PREFIX_RT_NOP; - - action = CLEANUP_PREFIX_RT_EXPIRE; - - spin_lock(&ifa->lock); - - lifetime = addrconf_timeout_fixup(ifa->valid_lft, HZ); - /* - * Note: Because this address is - * not permanent, lifetime < - * LONG_MAX / HZ here. - */ - if (time_before(*expires, ifa->tstamp + lifetime * HZ)) - *expires = ifa->tstamp + lifetime * HZ; - spin_unlock(&ifa->lock); - } - - return action; -} - -static void -cleanup_prefix_route(struct inet6_ifaddr *ifp, unsigned long expires, bool del_rt) -{ - struct rt6_info *rt; - - rt = addrconf_get_prefix_route(&ifp->addr, - ifp->prefix_len, - ifp->idev->dev, - 0, RTF_GATEWAY | RTF_DEFAULT); - if (rt) { - if (del_rt) - ip6_del_rt(rt); - else { - if (!(rt->rt6i_flags & RTF_EXPIRES)) - rt6_set_expires(rt, expires); - ip6_rt_put(rt); - } - } -} - - -/* This function wants to get referenced ifp and releases it before return */ - -static void ipv6_del_addr(struct inet6_ifaddr *ifp) -{ - int state; - enum cleanup_prefix_rt_t action = CLEANUP_PREFIX_RT_NOP; - unsigned long expires; - - ASSERT_RTNL(); - - spin_lock_bh(&ifp->lock); - state = ifp->state; - ifp->state = INET6_IFADDR_STATE_DEAD; - spin_unlock_bh(&ifp->lock); - - if (state == INET6_IFADDR_STATE_DEAD) - goto out; - - spin_lock_bh(&addrconf_hash_lock); - hlist_del_init_rcu(&ifp->addr_lst); - spin_unlock_bh(&addrconf_hash_lock); - - write_lock_bh(&ifp->idev->lock); - - if (ifp->flags&IFA_F_TEMPORARY) { - list_del(&ifp->tmp_list); - if (ifp->ifpub) { - in6_ifa_put(ifp->ifpub); - ifp->ifpub = NULL; - } - __in6_ifa_put(ifp); - } - - if (ifp->flags & IFA_F_PERMANENT && !(ifp->flags & IFA_F_NOPREFIXROUTE)) - action = check_cleanup_prefix_route(ifp, &expires); - - list_del_init(&ifp->if_list); - __in6_ifa_put(ifp); - - write_unlock_bh(&ifp->idev->lock); - - addrconf_del_dad_work(ifp); - - ipv6_ifa_notify(RTM_DELADDR, ifp); - - inet6addr_notifier_call_chain(NETDEV_DOWN, ifp); - - if (action != CLEANUP_PREFIX_RT_NOP) { - cleanup_prefix_route(ifp, expires, - action == CLEANUP_PREFIX_RT_DEL); - } - - /* clean up prefsrc entries */ - rt6_remove_prefsrc(ifp); -out: - in6_ifa_put(ifp); -} - -static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *ift) -{ - struct inet6_dev *idev = ifp->idev; - struct in6_addr addr, *tmpaddr; - unsigned long tmp_prefered_lft, tmp_valid_lft, tmp_tstamp, age; - unsigned long regen_advance; - int tmp_plen; - int ret = 0; - u32 addr_flags; - unsigned long now = jiffies; - long max_desync_factor; - s32 cnf_temp_preferred_lft; - - write_lock_bh(&idev->lock); - if (ift) { - spin_lock_bh(&ift->lock); - memcpy(&addr.s6_addr[8], &ift->addr.s6_addr[8], 8); - spin_unlock_bh(&ift->lock); - tmpaddr = &addr; - } else { - tmpaddr = NULL; - } -retry: - in6_dev_hold(idev); - if (idev->cnf.use_tempaddr <= 0) { - write_unlock_bh(&idev->lock); - pr_info("%s: use_tempaddr is disabled\n", __func__); - in6_dev_put(idev); - ret = -1; - goto out; - } - spin_lock_bh(&ifp->lock); - if (ifp->regen_count++ >= idev->cnf.regen_max_retry) { - idev->cnf.use_tempaddr = -1; /*XXX*/ - spin_unlock_bh(&ifp->lock); - write_unlock_bh(&idev->lock); - pr_warn("%s: regeneration time exceeded - disabled temporary address support\n", - __func__); - in6_dev_put(idev); - ret = -1; - goto out; - } - in6_ifa_hold(ifp); - memcpy(addr.s6_addr, ifp->addr.s6_addr, 8); - ipv6_try_regen_rndid(idev, tmpaddr); - memcpy(&addr.s6_addr[8], idev->rndid, 8); - age = (now - ifp->tstamp) / HZ; - - regen_advance = idev->cnf.regen_max_retry * - idev->cnf.dad_transmits * - NEIGH_VAR(idev->nd_parms, RETRANS_TIME) / HZ; - - /* recalculate max_desync_factor each time and update - * idev->desync_factor if it's larger - */ - cnf_temp_preferred_lft = READ_ONCE(idev->cnf.temp_prefered_lft); - max_desync_factor = min_t(__u32, - idev->cnf.max_desync_factor, - cnf_temp_preferred_lft - regen_advance); - - if (unlikely(idev->desync_factor > max_desync_factor)) { - if (max_desync_factor > 0) { - get_random_bytes(&idev->desync_factor, - sizeof(idev->desync_factor)); - idev->desync_factor %= max_desync_factor; - } else { - idev->desync_factor = 0; - } - } - - tmp_valid_lft = min_t(__u32, - ifp->valid_lft, - idev->cnf.temp_valid_lft + age); - tmp_prefered_lft = cnf_temp_preferred_lft + age - - idev->desync_factor; - tmp_prefered_lft = min_t(__u32, ifp->prefered_lft, tmp_prefered_lft); - tmp_plen = ifp->prefix_len; - tmp_tstamp = ifp->tstamp; - spin_unlock_bh(&ifp->lock); - - write_unlock_bh(&idev->lock); - - /* A temporary address is created only if this calculated Preferred - * Lifetime is greater than REGEN_ADVANCE time units. In particular, - * an implementation must not create a temporary address with a zero - * Preferred Lifetime. - * Use age calculation as in addrconf_verify to avoid unnecessary - * temporary addresses being generated. - */ - age = (now - tmp_tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ; - if (tmp_prefered_lft <= regen_advance + age) { - in6_ifa_put(ifp); - in6_dev_put(idev); - ret = -1; - goto out; - } - - addr_flags = IFA_F_TEMPORARY; - /* set in addrconf_prefix_rcv() */ - if (ifp->flags & IFA_F_OPTIMISTIC) - addr_flags |= IFA_F_OPTIMISTIC; - - ift = ipv6_add_addr(idev, &addr, NULL, tmp_plen, - ipv6_addr_scope(&addr), addr_flags, - tmp_valid_lft, tmp_prefered_lft); - if (IS_ERR(ift)) { - in6_ifa_put(ifp); - in6_dev_put(idev); - pr_info("%s: retry temporary address regeneration\n", __func__); - tmpaddr = &addr; - write_lock_bh(&idev->lock); - goto retry; - } - - spin_lock_bh(&ift->lock); - ift->ifpub = ifp; - ift->cstamp = now; - ift->tstamp = tmp_tstamp; - spin_unlock_bh(&ift->lock); - - addrconf_dad_start(ift); - in6_ifa_put(ift); - in6_dev_put(idev); -out: - return ret; -} - -/* - * Choose an appropriate source address (RFC3484) - */ -enum { - IPV6_SADDR_RULE_INIT = 0, - IPV6_SADDR_RULE_LOCAL, - IPV6_SADDR_RULE_SCOPE, - IPV6_SADDR_RULE_PREFERRED, -#ifdef CONFIG_IPV6_MIP6 - IPV6_SADDR_RULE_HOA, -#endif - IPV6_SADDR_RULE_OIF, - IPV6_SADDR_RULE_LABEL, - IPV6_SADDR_RULE_PRIVACY, - IPV6_SADDR_RULE_ORCHID, - IPV6_SADDR_RULE_PREFIX, -#ifdef CONFIG_IPV6_OPTIMISTIC_DAD - IPV6_SADDR_RULE_NOT_OPTIMISTIC, -#endif - IPV6_SADDR_RULE_MAX -}; - -struct ipv6_saddr_score { - int rule; - int addr_type; - struct inet6_ifaddr *ifa; - DECLARE_BITMAP(scorebits, IPV6_SADDR_RULE_MAX); - int scopedist; - int matchlen; -}; - -struct ipv6_saddr_dst { - const struct in6_addr *addr; - int ifindex; - int scope; - int label; - unsigned int prefs; -}; - -static inline int ipv6_saddr_preferred(int type) -{ - if (type & (IPV6_ADDR_MAPPED|IPV6_ADDR_COMPATv4|IPV6_ADDR_LOOPBACK)) - return 1; - return 0; -} - -static inline bool ipv6_use_optimistic_addr(struct inet6_dev *idev) -{ -#ifdef CONFIG_IPV6_OPTIMISTIC_DAD - return idev && idev->cnf.optimistic_dad && idev->cnf.use_optimistic; -#else - return false; -#endif -} - -static int ipv6_get_saddr_eval(struct net *net, - struct ipv6_saddr_score *score, - struct ipv6_saddr_dst *dst, - int i) -{ - int ret; - - if (i <= score->rule) { - switch (i) { - case IPV6_SADDR_RULE_SCOPE: - ret = score->scopedist; - break; - case IPV6_SADDR_RULE_PREFIX: - ret = score->matchlen; - break; - default: - ret = !!test_bit(i, score->scorebits); - } - goto out; - } - - switch (i) { - case IPV6_SADDR_RULE_INIT: - /* Rule 0: remember if hiscore is not ready yet */ - ret = !!score->ifa; - break; - case IPV6_SADDR_RULE_LOCAL: - /* Rule 1: Prefer same address */ - ret = ipv6_addr_equal(&score->ifa->addr, dst->addr); - break; - case IPV6_SADDR_RULE_SCOPE: - /* Rule 2: Prefer appropriate scope - * - * ret - * ^ - * -1 | d 15 - * ---+--+-+---> scope - * | - * | d is scope of the destination. - * B-d | \ - * | \ <- smaller scope is better if - * B-15 | \ if scope is enough for destination. - * | ret = B - scope (-1 <= scope >= d <= 15). - * d-C-1 | / - * |/ <- greater is better - * -C / if scope is not enough for destination. - * /| ret = scope - C (-1 <= d < scope <= 15). - * - * d - C - 1 < B -15 (for all -1 <= d <= 15). - * C > d + 14 - B >= 15 + 14 - B = 29 - B. - * Assume B = 0 and we get C > 29. - */ - ret = __ipv6_addr_src_scope(score->addr_type); - if (ret >= dst->scope) - ret = -ret; - else - ret -= 128; /* 30 is enough */ - score->scopedist = ret; - break; - case IPV6_SADDR_RULE_PREFERRED: - { - /* Rule 3: Avoid deprecated and optimistic addresses */ - u8 avoid = IFA_F_DEPRECATED; - - if (!ipv6_use_optimistic_addr(score->ifa->idev)) - avoid |= IFA_F_OPTIMISTIC; - ret = ipv6_saddr_preferred(score->addr_type) || - !(score->ifa->flags & avoid); - break; - } -#ifdef CONFIG_IPV6_MIP6 - case IPV6_SADDR_RULE_HOA: - { - /* Rule 4: Prefer home address */ - int prefhome = !(dst->prefs & IPV6_PREFER_SRC_COA); - ret = !(score->ifa->flags & IFA_F_HOMEADDRESS) ^ prefhome; - break; - } -#endif - case IPV6_SADDR_RULE_OIF: - /* Rule 5: Prefer outgoing interface */ - ret = (!dst->ifindex || - dst->ifindex == score->ifa->idev->dev->ifindex); - break; - case IPV6_SADDR_RULE_LABEL: - /* Rule 6: Prefer matching label */ - ret = ipv6_addr_label(net, - &score->ifa->addr, score->addr_type, - score->ifa->idev->dev->ifindex) == dst->label; - break; - case IPV6_SADDR_RULE_PRIVACY: - { - /* Rule 7: Prefer public address - * Note: prefer temporary address if use_tempaddr >= 2 - */ - int preftmp = dst->prefs & (IPV6_PREFER_SRC_PUBLIC|IPV6_PREFER_SRC_TMP) ? - !!(dst->prefs & IPV6_PREFER_SRC_TMP) : - score->ifa->idev->cnf.use_tempaddr >= 2; - ret = (!(score->ifa->flags & IFA_F_TEMPORARY)) ^ preftmp; - break; - } - case IPV6_SADDR_RULE_ORCHID: - /* Rule 8-: Prefer ORCHID vs ORCHID or - * non-ORCHID vs non-ORCHID - */ - ret = !(ipv6_addr_orchid(&score->ifa->addr) ^ - ipv6_addr_orchid(dst->addr)); - break; - case IPV6_SADDR_RULE_PREFIX: - /* Rule 8: Use longest matching prefix */ - ret = ipv6_addr_diff(&score->ifa->addr, dst->addr); - if (ret > score->ifa->prefix_len) - ret = score->ifa->prefix_len; - score->matchlen = ret; - break; -#ifdef CONFIG_IPV6_OPTIMISTIC_DAD - case IPV6_SADDR_RULE_NOT_OPTIMISTIC: - /* Optimistic addresses still have lower precedence than other - * preferred addresses. - */ - ret = !(score->ifa->flags & IFA_F_OPTIMISTIC); - break; -#endif - default: - ret = 0; - } - - if (ret) - __set_bit(i, score->scorebits); - score->rule = i; -out: - return ret; -} - -static int __ipv6_dev_get_saddr(struct net *net, - struct ipv6_saddr_dst *dst, - struct inet6_dev *idev, - struct ipv6_saddr_score *scores, - int hiscore_idx) -{ - struct ipv6_saddr_score *score = &scores[1 - hiscore_idx], *hiscore = &scores[hiscore_idx]; - - read_lock_bh(&idev->lock); - list_for_each_entry(score->ifa, &idev->addr_list, if_list) { - int i; - - /* - * - Tentative Address (RFC2462 section 5.4) - * - A tentative address is not considered - * "assigned to an interface" in the traditional - * sense, unless it is also flagged as optimistic. - * - Candidate Source Address (section 4) - * - In any case, anycast addresses, multicast - * addresses, and the unspecified address MUST - * NOT be included in a candidate set. - */ - if ((score->ifa->flags & IFA_F_TENTATIVE) && - (!(score->ifa->flags & IFA_F_OPTIMISTIC))) - continue; - - score->addr_type = __ipv6_addr_type(&score->ifa->addr); - - if (unlikely(score->addr_type == IPV6_ADDR_ANY || - score->addr_type & IPV6_ADDR_MULTICAST)) { - net_dbg_ratelimited("ADDRCONF: unspecified / multicast address assigned as unicast address on %s", - idev->dev->name); - continue; - } - - score->rule = -1; - bitmap_zero(score->scorebits, IPV6_SADDR_RULE_MAX); - - for (i = 0; i < IPV6_SADDR_RULE_MAX; i++) { - int minihiscore, miniscore; - - minihiscore = ipv6_get_saddr_eval(net, hiscore, dst, i); - miniscore = ipv6_get_saddr_eval(net, score, dst, i); - - if (minihiscore > miniscore) { - if (i == IPV6_SADDR_RULE_SCOPE && - score->scopedist > 0) { - /* - * special case: - * each remaining entry - * has too small (not enough) - * scope, because ifa entries - * are sorted by their scope - * values. - */ - goto out; - } - break; - } else if (minihiscore < miniscore) { - if (hiscore->ifa) - in6_ifa_put(hiscore->ifa); - - in6_ifa_hold(score->ifa); - - swap(hiscore, score); - hiscore_idx = 1 - hiscore_idx; - - /* restore our iterator */ - score->ifa = hiscore->ifa; - - break; - } - } - } -out: - read_unlock_bh(&idev->lock); - return hiscore_idx; -} - -static int ipv6_get_saddr_master(struct net *net, - const struct net_device *dst_dev, - const struct net_device *master, - struct ipv6_saddr_dst *dst, - struct ipv6_saddr_score *scores, - int hiscore_idx) -{ - struct inet6_dev *idev; - - idev = __in6_dev_get(dst_dev); - if (idev) - hiscore_idx = __ipv6_dev_get_saddr(net, dst, idev, - scores, hiscore_idx); - - idev = __in6_dev_get(master); - if (idev) - hiscore_idx = __ipv6_dev_get_saddr(net, dst, idev, - scores, hiscore_idx); - - return hiscore_idx; -} - -int ipv6_dev_get_saddr(struct net *net, const struct net_device *dst_dev, - const struct in6_addr *daddr, unsigned int prefs, - struct in6_addr *saddr) -{ - struct ipv6_saddr_score scores[2], *hiscore; - struct ipv6_saddr_dst dst; - struct inet6_dev *idev; - struct net_device *dev; - int dst_type; - bool use_oif_addr = false; - int hiscore_idx = 0; - - dst_type = __ipv6_addr_type(daddr); - dst.addr = daddr; - dst.ifindex = dst_dev ? dst_dev->ifindex : 0; - dst.scope = __ipv6_addr_src_scope(dst_type); - dst.label = ipv6_addr_label(net, daddr, dst_type, dst.ifindex); - dst.prefs = prefs; - - scores[hiscore_idx].rule = -1; - scores[hiscore_idx].ifa = NULL; - - rcu_read_lock(); - - /* Candidate Source Address (section 4) - * - multicast and link-local destination address, - * the set of candidate source address MUST only - * include addresses assigned to interfaces - * belonging to the same link as the outgoing - * interface. - * (- For site-local destination addresses, the - * set of candidate source addresses MUST only - * include addresses assigned to interfaces - * belonging to the same site as the outgoing - * interface.) - * - "It is RECOMMENDED that the candidate source addresses - * be the set of unicast addresses assigned to the - * interface that will be used to send to the destination - * (the 'outgoing' interface)." (RFC 6724) - */ - if (dst_dev) { - idev = __in6_dev_get(dst_dev); - if ((dst_type & IPV6_ADDR_MULTICAST) || - dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL || - (idev && idev->cnf.use_oif_addrs_only)) { - use_oif_addr = true; - } - } - - if (use_oif_addr) { - if (idev) - hiscore_idx = __ipv6_dev_get_saddr(net, &dst, idev, scores, hiscore_idx); - } else { - const struct net_device *master; - int master_idx = 0; - - /* if dst_dev exists and is enslaved to an L3 device, then - * prefer addresses from dst_dev and then the master over - * any other enslaved devices in the L3 domain. - */ - master = l3mdev_master_dev_rcu(dst_dev); - if (master) { - master_idx = master->ifindex; - - hiscore_idx = ipv6_get_saddr_master(net, dst_dev, - master, &dst, - scores, hiscore_idx); - - if (scores[hiscore_idx].ifa) - goto out; - } - - for_each_netdev_rcu(net, dev) { - /* only consider addresses on devices in the - * same L3 domain - */ - if (l3mdev_master_ifindex_rcu(dev) != master_idx) - continue; - idev = __in6_dev_get(dev); - if (!idev) - continue; - hiscore_idx = __ipv6_dev_get_saddr(net, &dst, idev, scores, hiscore_idx); - } - } - -out: - rcu_read_unlock(); - - hiscore = &scores[hiscore_idx]; - if (!hiscore->ifa) - return -EADDRNOTAVAIL; - - *saddr = hiscore->ifa->addr; - in6_ifa_put(hiscore->ifa); - return 0; -} -EXPORT_SYMBOL(ipv6_dev_get_saddr); - -int __ipv6_get_lladdr(struct inet6_dev *idev, struct in6_addr *addr, - u32 banned_flags) -{ - struct inet6_ifaddr *ifp; - int err = -EADDRNOTAVAIL; - - list_for_each_entry_reverse(ifp, &idev->addr_list, if_list) { - if (ifp->scope > IFA_LINK) - break; - if (ifp->scope == IFA_LINK && - !(ifp->flags & banned_flags)) { - *addr = ifp->addr; - err = 0; - break; - } - } - return err; -} - -int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, - u32 banned_flags) -{ - struct inet6_dev *idev; - int err = -EADDRNOTAVAIL; - - rcu_read_lock(); - idev = __in6_dev_get(dev); - if (idev) { - read_lock_bh(&idev->lock); - err = __ipv6_get_lladdr(idev, addr, banned_flags); - read_unlock_bh(&idev->lock); - } - rcu_read_unlock(); - return err; -} - -static int ipv6_count_addresses(struct inet6_dev *idev) -{ - int cnt = 0; - struct inet6_ifaddr *ifp; - - read_lock_bh(&idev->lock); - list_for_each_entry(ifp, &idev->addr_list, if_list) - cnt++; - read_unlock_bh(&idev->lock); - return cnt; -} - -int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, - const struct net_device *dev, int strict) -{ - return ipv6_chk_addr_and_flags(net, addr, dev, strict, IFA_F_TENTATIVE); -} -EXPORT_SYMBOL(ipv6_chk_addr); - -int ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr, - const struct net_device *dev, int strict, - u32 banned_flags) -{ - struct inet6_ifaddr *ifp; - unsigned int hash = inet6_addr_hash(addr); - u32 ifp_flags; - - rcu_read_lock_bh(); - hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) { - if (!net_eq(dev_net(ifp->idev->dev), net)) - continue; - /* Decouple optimistic from tentative for evaluation here. - * Ban optimistic addresses explicitly, when required. - */ - ifp_flags = (ifp->flags&IFA_F_OPTIMISTIC) - ? (ifp->flags&~IFA_F_TENTATIVE) - : ifp->flags; - if (ipv6_addr_equal(&ifp->addr, addr) && - !(ifp_flags&banned_flags) && - (!dev || ifp->idev->dev == dev || - !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) { - rcu_read_unlock_bh(); - return 1; - } - } - - rcu_read_unlock_bh(); - return 0; -} -EXPORT_SYMBOL(ipv6_chk_addr_and_flags); - -static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, - struct net_device *dev) -{ - unsigned int hash = inet6_addr_hash(addr); - struct inet6_ifaddr *ifp; - - hlist_for_each_entry(ifp, &inet6_addr_lst[hash], addr_lst) { - if (!net_eq(dev_net(ifp->idev->dev), net)) - continue; - if (ipv6_addr_equal(&ifp->addr, addr)) { - if (!dev || ifp->idev->dev == dev) - return true; - } - } - return false; -} - -/* Compares an address/prefix_len with addresses on device @dev. - * If one is found it returns true. - */ -bool ipv6_chk_custom_prefix(const struct in6_addr *addr, - const unsigned int prefix_len, struct net_device *dev) -{ - struct inet6_dev *idev; - struct inet6_ifaddr *ifa; - bool ret = false; - - rcu_read_lock(); - idev = __in6_dev_get(dev); - if (idev) { - read_lock_bh(&idev->lock); - list_for_each_entry(ifa, &idev->addr_list, if_list) { - ret = ipv6_prefix_equal(addr, &ifa->addr, prefix_len); - if (ret) - break; - } - read_unlock_bh(&idev->lock); - } - rcu_read_unlock(); - - return ret; -} -EXPORT_SYMBOL(ipv6_chk_custom_prefix); - -int ipv6_chk_prefix(const struct in6_addr *addr, struct net_device *dev) -{ - struct inet6_dev *idev; - struct inet6_ifaddr *ifa; - int onlink; - - onlink = 0; - rcu_read_lock(); - idev = __in6_dev_get(dev); - if (idev) { - read_lock_bh(&idev->lock); - list_for_each_entry(ifa, &idev->addr_list, if_list) { - onlink = ipv6_prefix_equal(addr, &ifa->addr, - ifa->prefix_len); - if (onlink) - break; - } - read_unlock_bh(&idev->lock); - } - rcu_read_unlock(); - return onlink; -} -EXPORT_SYMBOL(ipv6_chk_prefix); - -struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *addr, - struct net_device *dev, int strict) -{ - struct inet6_ifaddr *ifp, *result = NULL; - unsigned int hash = inet6_addr_hash(addr); - - rcu_read_lock_bh(); - hlist_for_each_entry_rcu_bh(ifp, &inet6_addr_lst[hash], addr_lst) { - if (!net_eq(dev_net(ifp->idev->dev), net)) - continue; - if (ipv6_addr_equal(&ifp->addr, addr)) { - if (!dev || ifp->idev->dev == dev || - !(ifp->scope&(IFA_LINK|IFA_HOST) || strict)) { - result = ifp; - in6_ifa_hold(ifp); - break; - } - } - } - rcu_read_unlock_bh(); - - return result; -} - -/* Gets referenced address, destroys ifaddr */ - -static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed) -{ - if (dad_failed) - ifp->flags |= IFA_F_DADFAILED; - - if (ifp->flags&IFA_F_PERMANENT) { - spin_lock_bh(&ifp->lock); - addrconf_del_dad_work(ifp); - ifp->flags |= IFA_F_TENTATIVE; - spin_unlock_bh(&ifp->lock); - if (dad_failed) - ipv6_ifa_notify(0, ifp); - in6_ifa_put(ifp); - } else if (ifp->flags&IFA_F_TEMPORARY) { - struct inet6_ifaddr *ifpub; - spin_lock_bh(&ifp->lock); - ifpub = ifp->ifpub; - if (ifpub) { - in6_ifa_hold(ifpub); - spin_unlock_bh(&ifp->lock); - ipv6_create_tempaddr(ifpub, ifp); - in6_ifa_put(ifpub); - } else { - spin_unlock_bh(&ifp->lock); - } - ipv6_del_addr(ifp); - } else { - ipv6_del_addr(ifp); - } -} - -static int addrconf_dad_end(struct inet6_ifaddr *ifp) -{ - int err = -ENOENT; - - spin_lock_bh(&ifp->lock); - if (ifp->state == INET6_IFADDR_STATE_DAD) { - ifp->state = INET6_IFADDR_STATE_POSTDAD; - err = 0; - } - spin_unlock_bh(&ifp->lock); - - return err; -} - -void addrconf_dad_failure(struct inet6_ifaddr *ifp) -{ - struct inet6_dev *idev = ifp->idev; - struct net *net = dev_net(ifp->idev->dev); - - if (addrconf_dad_end(ifp)) { - in6_ifa_put(ifp); - return; - } - - net_info_ratelimited("%s: IPv6 duplicate address %pI6c detected!\n", - ifp->idev->dev->name, &ifp->addr); - - spin_lock_bh(&ifp->lock); - - if (ifp->flags & IFA_F_STABLE_PRIVACY) { - int scope = ifp->scope; - u32 flags = ifp->flags; - struct in6_addr new_addr; - struct inet6_ifaddr *ifp2; - u32 valid_lft, preferred_lft; - int pfxlen = ifp->prefix_len; - int retries = ifp->stable_privacy_retry + 1; - - if (retries > net->ipv6.sysctl.idgen_retries) { - net_info_ratelimited("%s: privacy stable address generation failed because of DAD conflicts!\n", - ifp->idev->dev->name); - goto errdad; - } - - new_addr = ifp->addr; - if (ipv6_generate_stable_address(&new_addr, retries, - idev)) - goto errdad; - - valid_lft = ifp->valid_lft; - preferred_lft = ifp->prefered_lft; - - spin_unlock_bh(&ifp->lock); - - if (idev->cnf.max_addresses && - ipv6_count_addresses(idev) >= - idev->cnf.max_addresses) - goto lock_errdad; - - net_info_ratelimited("%s: generating new stable privacy address because of DAD conflict\n", - ifp->idev->dev->name); - - ifp2 = ipv6_add_addr(idev, &new_addr, NULL, pfxlen, - scope, flags, valid_lft, - preferred_lft); - if (IS_ERR(ifp2)) - goto lock_errdad; - - spin_lock_bh(&ifp2->lock); - ifp2->stable_privacy_retry = retries; - ifp2->state = INET6_IFADDR_STATE_PREDAD; - spin_unlock_bh(&ifp2->lock); - - addrconf_mod_dad_work(ifp2, net->ipv6.sysctl.idgen_delay); - in6_ifa_put(ifp2); -lock_errdad: - spin_lock_bh(&ifp->lock); - } - -errdad: - /* transition from _POSTDAD to _ERRDAD */ - ifp->state = INET6_IFADDR_STATE_ERRDAD; - spin_unlock_bh(&ifp->lock); - - addrconf_mod_dad_work(ifp, 0); - in6_ifa_put(ifp); -} - -/* Join to solicited addr multicast group. - * caller must hold RTNL */ -void addrconf_join_solict(struct net_device *dev, const struct in6_addr *addr) -{ - struct in6_addr maddr; - - if (dev->flags&(IFF_LOOPBACK|IFF_NOARP)) - return; - - addrconf_addr_solict_mult(addr, &maddr); - ipv6_dev_mc_inc(dev, &maddr); -} - -/* caller must hold RTNL */ -void addrconf_leave_solict(struct inet6_dev *idev, const struct in6_addr *addr) -{ - struct in6_addr maddr; - - if (idev->dev->flags&(IFF_LOOPBACK|IFF_NOARP)) - return; - - addrconf_addr_solict_mult(addr, &maddr); - __ipv6_dev_mc_dec(idev, &maddr); -} - -/* caller must hold RTNL */ -static void addrconf_join_anycast(struct inet6_ifaddr *ifp) -{ - struct in6_addr addr; - - if (ifp->prefix_len >= 127) /* RFC 6164 */ - return; - ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len); - if (ipv6_addr_any(&addr)) - return; - __ipv6_dev_ac_inc(ifp->idev, &addr); -} - -/* caller must hold RTNL */ -static void addrconf_leave_anycast(struct inet6_ifaddr *ifp) -{ - struct in6_addr addr; - - if (ifp->prefix_len >= 127) /* RFC 6164 */ - return; - ipv6_addr_prefix(&addr, &ifp->addr, ifp->prefix_len); - if (ipv6_addr_any(&addr)) - return; - __ipv6_dev_ac_dec(ifp->idev, &addr); -} - -static int addrconf_ifid_eui64(u8 *eui, struct net_device *dev) -{ - if (dev->addr_len != EUI64_ADDR_LEN) - return -1; - memcpy(eui, dev->dev_addr, EUI64_ADDR_LEN); - eui[0] ^= 2; - return 0; -} - -static int addrconf_ifid_ieee1394(u8 *eui, struct net_device *dev) -{ - union fwnet_hwaddr *ha; - - if (dev->addr_len != FWNET_ALEN) - return -1; - - ha = (union fwnet_hwaddr *)dev->dev_addr; - - memcpy(eui, &ha->uc.uniq_id, sizeof(ha->uc.uniq_id)); - eui[0] ^= 2; - return 0; -} - -static int addrconf_ifid_arcnet(u8 *eui, struct net_device *dev) -{ - /* XXX: inherit EUI-64 from other interface -- yoshfuji */ - if (dev->addr_len != ARCNET_ALEN) - return -1; - memset(eui, 0, 7); - eui[7] = *(u8 *)dev->dev_addr; - return 0; -} - -static int addrconf_ifid_infiniband(u8 *eui, struct net_device *dev) -{ - if (dev->addr_len != INFINIBAND_ALEN) - return -1; - memcpy(eui, dev->dev_addr + 12, 8); - eui[0] |= 2; - return 0; -} - -static int __ipv6_isatap_ifid(u8 *eui, __be32 addr) -{ - if (addr == 0) - return -1; - eui[0] = (ipv4_is_zeronet(addr) || ipv4_is_private_10(addr) || - ipv4_is_loopback(addr) || ipv4_is_linklocal_169(addr) || - ipv4_is_private_172(addr) || ipv4_is_test_192(addr) || - ipv4_is_anycast_6to4(addr) || ipv4_is_private_192(addr) || - ipv4_is_test_198(addr) || ipv4_is_multicast(addr) || - ipv4_is_lbcast(addr)) ? 0x00 : 0x02; - eui[1] = 0; - eui[2] = 0x5E; - eui[3] = 0xFE; - memcpy(eui + 4, &addr, 4); - return 0; -} - -static int addrconf_ifid_sit(u8 *eui, struct net_device *dev) -{ - if (dev->priv_flags & IFF_ISATAP) - return __ipv6_isatap_ifid(eui, *(__be32 *)dev->dev_addr); - return -1; -} - -static int addrconf_ifid_gre(u8 *eui, struct net_device *dev) -{ - return __ipv6_isatap_ifid(eui, *(__be32 *)dev->dev_addr); -} - -static int addrconf_ifid_ip6tnl(u8 *eui, struct net_device *dev) -{ - memcpy(eui, dev->perm_addr, 3); - memcpy(eui + 5, dev->perm_addr + 3, 3); - eui[3] = 0xFF; - eui[4] = 0xFE; - eui[0] ^= 2; - return 0; -} - -static int ipv6_generate_eui64(u8 *eui, struct net_device *dev) -{ - switch (dev->type) { - case ARPHRD_ETHER: - case ARPHRD_FDDI: - return addrconf_ifid_eui48(eui, dev); - case ARPHRD_ARCNET: - return addrconf_ifid_arcnet(eui, dev); - case ARPHRD_INFINIBAND: - return addrconf_ifid_infiniband(eui, dev); - case ARPHRD_SIT: - return addrconf_ifid_sit(eui, dev); - case ARPHRD_IPGRE: - return addrconf_ifid_gre(eui, dev); - case ARPHRD_6LOWPAN: - return addrconf_ifid_eui64(eui, dev); - case ARPHRD_IEEE1394: - return addrconf_ifid_ieee1394(eui, dev); - case ARPHRD_TUNNEL6: - return addrconf_ifid_ip6tnl(eui, dev); - } - return -1; -} - -static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev) -{ - int err = -1; - struct inet6_ifaddr *ifp; - - read_lock_bh(&idev->lock); - list_for_each_entry_reverse(ifp, &idev->addr_list, if_list) { - if (ifp->scope > IFA_LINK) - break; - if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) { - memcpy(eui, ifp->addr.s6_addr+8, 8); - err = 0; - break; - } - } - read_unlock_bh(&idev->lock); - return err; -} - -/* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */ -static void ipv6_regen_rndid(struct inet6_dev *idev) -{ -regen: - get_random_bytes(idev->rndid, sizeof(idev->rndid)); - idev->rndid[0] &= ~0x02; - - /* - * : - * check if generated address is not inappropriate - * - * - Reserved subnet anycast (RFC 2526) - * 11111101 11....11 1xxxxxxx - * - ISATAP (RFC4214) 6.1 - * 00-00-5E-FE-xx-xx-xx-xx - * - value 0 - * - XXX: already assigned to an address on the device - */ - if (idev->rndid[0] == 0xfd && - (idev->rndid[1]&idev->rndid[2]&idev->rndid[3]&idev->rndid[4]&idev->rndid[5]&idev->rndid[6]) == 0xff && - (idev->rndid[7]&0x80)) - goto regen; - if ((idev->rndid[0]|idev->rndid[1]) == 0) { - if (idev->rndid[2] == 0x5e && idev->rndid[3] == 0xfe) - goto regen; - if ((idev->rndid[2]|idev->rndid[3]|idev->rndid[4]|idev->rndid[5]|idev->rndid[6]|idev->rndid[7]) == 0x00) - goto regen; - } -} - -static void ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr) -{ - if (tmpaddr && memcmp(idev->rndid, &tmpaddr->s6_addr[8], 8) == 0) - ipv6_regen_rndid(idev); -} - -/* - * Add prefix route. - */ - -static void -addrconf_prefix_route(struct in6_addr *pfx, int plen, struct net_device *dev, - unsigned long expires, u32 flags) -{ - struct fib6_config cfg = { - .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_PREFIX, - .fc_metric = IP6_RT_PRIO_ADDRCONF, - .fc_ifindex = dev->ifindex, - .fc_expires = expires, - .fc_dst_len = plen, - .fc_flags = RTF_UP | flags, - .fc_nlinfo.nl_net = dev_net(dev), - .fc_protocol = RTPROT_KERNEL, - }; - - cfg.fc_dst = *pfx; - - /* Prevent useless cloning on PtP SIT. - This thing is done here expecting that the whole - class of non-broadcast devices need not cloning. - */ -#if IS_ENABLED(CONFIG_IPV6_SIT) - if (dev->type == ARPHRD_SIT && (dev->flags & IFF_POINTOPOINT)) - cfg.fc_flags |= RTF_NONEXTHOP; -#endif - - ip6_route_add(&cfg); -} - - -static struct rt6_info *addrconf_get_prefix_route(const struct in6_addr *pfx, - int plen, - const struct net_device *dev, - u32 flags, u32 noflags) -{ - struct fib6_node *fn; - struct rt6_info *rt = NULL; - struct fib6_table *table; - u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_PREFIX; - - table = fib6_get_table(dev_net(dev), tb_id); - if (!table) - return NULL; - - read_lock_bh(&table->tb6_lock); - fn = fib6_locate(&table->tb6_root, pfx, plen, NULL, 0); - if (!fn) - goto out; - - noflags |= RTF_CACHE; - for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) { - if (rt->dst.dev->ifindex != dev->ifindex) - continue; - if ((rt->rt6i_flags & flags) != flags) - continue; - if ((rt->rt6i_flags & noflags) != 0) - continue; - dst_hold(&rt->dst); - break; - } -out: - read_unlock_bh(&table->tb6_lock); - return rt; -} - - -/* Create "default" multicast route to the interface */ - -static void addrconf_add_mroute(struct net_device *dev) -{ - struct fib6_config cfg = { - .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_LOCAL, - .fc_metric = IP6_RT_PRIO_ADDRCONF, - .fc_ifindex = dev->ifindex, - .fc_dst_len = 8, - .fc_flags = RTF_UP, - .fc_nlinfo.nl_net = dev_net(dev), - }; - - ipv6_addr_set(&cfg.fc_dst, htonl(0xFF000000), 0, 0, 0); - - ip6_route_add(&cfg); -} - -static struct inet6_dev *addrconf_add_dev(struct net_device *dev) -{ - struct inet6_dev *idev; - - ASSERT_RTNL(); - - idev = ipv6_find_idev(dev); - if (!idev) - return ERR_PTR(-ENOBUFS); - - if (idev->cnf.disable_ipv6) - return ERR_PTR(-EACCES); - - /* Add default multicast route */ - if (!(dev->flags & IFF_LOOPBACK) && !netif_is_l3_master(dev)) - addrconf_add_mroute(dev); - - return idev; -} - -static void manage_tempaddrs(struct inet6_dev *idev, - struct inet6_ifaddr *ifp, - __u32 valid_lft, __u32 prefered_lft, - bool create, unsigned long now) -{ - u32 flags; - struct inet6_ifaddr *ift; - - read_lock_bh(&idev->lock); - /* update all temporary addresses in the list */ - list_for_each_entry(ift, &idev->tempaddr_list, tmp_list) { - int age, max_valid, max_prefered; - - if (ifp != ift->ifpub) - continue; - - /* RFC 4941 section 3.3: - * If a received option will extend the lifetime of a public - * address, the lifetimes of temporary addresses should - * be extended, subject to the overall constraint that no - * temporary addresses should ever remain "valid" or "preferred" - * for a time longer than (TEMP_VALID_LIFETIME) or - * (TEMP_PREFERRED_LIFETIME - DESYNC_FACTOR), respectively. - */ - age = (now - ift->cstamp) / HZ; - max_valid = idev->cnf.temp_valid_lft - age; - if (max_valid < 0) - max_valid = 0; - - max_prefered = idev->cnf.temp_prefered_lft - - idev->desync_factor - age; - if (max_prefered < 0) - max_prefered = 0; - - if (valid_lft > max_valid) - valid_lft = max_valid; - - if (prefered_lft > max_prefered) - prefered_lft = max_prefered; - - spin_lock(&ift->lock); - flags = ift->flags; - ift->valid_lft = valid_lft; - ift->prefered_lft = prefered_lft; - ift->tstamp = now; - if (prefered_lft > 0) - ift->flags &= ~IFA_F_DEPRECATED; - - spin_unlock(&ift->lock); - if (!(flags&IFA_F_TENTATIVE)) - ipv6_ifa_notify(0, ift); - } - - if ((create || list_empty(&idev->tempaddr_list)) && - idev->cnf.use_tempaddr > 0) { - /* When a new public address is created as described - * in [ADDRCONF], also create a new temporary address. - * Also create a temporary address if it's enabled but - * no temporary address currently exists. - */ - read_unlock_bh(&idev->lock); - ipv6_create_tempaddr(ifp, NULL); - } else { - read_unlock_bh(&idev->lock); - } -} - -static bool is_addr_mode_generate_stable(struct inet6_dev *idev) -{ - return idev->addr_gen_mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY || - idev->addr_gen_mode == IN6_ADDR_GEN_MODE_RANDOM; -} - -int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev, - const struct prefix_info *pinfo, - struct inet6_dev *in6_dev, - const struct in6_addr *addr, int addr_type, - u32 addr_flags, bool sllao, bool tokenized, - __u32 valid_lft, u32 prefered_lft) -{ - struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1); - int create = 0, update_lft = 0; - - if (!ifp && valid_lft) { - int max_addresses = in6_dev->cnf.max_addresses; - -#ifdef CONFIG_IPV6_OPTIMISTIC_DAD - if (in6_dev->cnf.optimistic_dad && - !net->ipv6.devconf_all->forwarding && sllao) - addr_flags |= IFA_F_OPTIMISTIC; -#endif - - /* Do not allow to create too much of autoconfigured - * addresses; this would be too easy way to crash kernel. - */ - if (!max_addresses || - ipv6_count_addresses(in6_dev) < max_addresses) - ifp = ipv6_add_addr(in6_dev, addr, NULL, - pinfo->prefix_len, - addr_type&IPV6_ADDR_SCOPE_MASK, - addr_flags, valid_lft, - prefered_lft); - - if (IS_ERR_OR_NULL(ifp)) - return -1; - - update_lft = 0; - create = 1; - spin_lock_bh(&ifp->lock); - ifp->flags |= IFA_F_MANAGETEMPADDR; - ifp->cstamp = jiffies; - ifp->tokenized = tokenized; - spin_unlock_bh(&ifp->lock); - addrconf_dad_start(ifp); - } - - if (ifp) { - u32 flags; - unsigned long now; - u32 stored_lft; - - /* update lifetime (RFC2462 5.5.3 e) */ - spin_lock_bh(&ifp->lock); - now = jiffies; - if (ifp->valid_lft > (now - ifp->tstamp) / HZ) - stored_lft = ifp->valid_lft - (now - ifp->tstamp) / HZ; - else - stored_lft = 0; - if (!update_lft && !create && stored_lft) { - const u32 minimum_lft = min_t(u32, - stored_lft, MIN_VALID_LIFETIME); - valid_lft = max(valid_lft, minimum_lft); - - /* RFC4862 Section 5.5.3e: - * "Note that the preferred lifetime of the - * corresponding address is always reset to - * the Preferred Lifetime in the received - * Prefix Information option, regardless of - * whether the valid lifetime is also reset or - * ignored." - * - * So we should always update prefered_lft here. - */ - update_lft = 1; - } - - if (update_lft) { - ifp->valid_lft = valid_lft; - ifp->prefered_lft = prefered_lft; - ifp->tstamp = now; - flags = ifp->flags; - ifp->flags &= ~IFA_F_DEPRECATED; - spin_unlock_bh(&ifp->lock); - - if (!(flags&IFA_F_TENTATIVE)) - ipv6_ifa_notify(0, ifp); - } else - spin_unlock_bh(&ifp->lock); - - manage_tempaddrs(in6_dev, ifp, valid_lft, prefered_lft, - create, now); - - in6_ifa_put(ifp); - addrconf_verify(); - } - - return 0; -} -EXPORT_SYMBOL_GPL(addrconf_prefix_rcv_add_addr); - -void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len, bool sllao) -{ - struct prefix_info *pinfo; - __u32 valid_lft; - __u32 prefered_lft; - int addr_type, err; - u32 addr_flags = 0; - struct inet6_dev *in6_dev; - struct net *net = dev_net(dev); - - pinfo = (struct prefix_info *) opt; - - if (len < sizeof(struct prefix_info)) { - ADBG("addrconf: prefix option too short\n"); - return; - } - - /* - * Validation checks ([ADDRCONF], page 19) - */ - - addr_type = ipv6_addr_type(&pinfo->prefix); - - if (addr_type & (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL)) - return; - - valid_lft = ntohl(pinfo->valid); - prefered_lft = ntohl(pinfo->prefered); - - if (prefered_lft > valid_lft) { - net_warn_ratelimited("addrconf: prefix option has invalid lifetime\n"); - return; - } - - in6_dev = in6_dev_get(dev); - - if (!in6_dev) { - net_dbg_ratelimited("addrconf: device %s not configured\n", - dev->name); - return; - } - - /* - * Two things going on here: - * 1) Add routes for on-link prefixes - * 2) Configure prefixes with the auto flag set - */ - - if (pinfo->onlink) { - struct rt6_info *rt; - unsigned long rt_expires; - - /* Avoid arithmetic overflow. Really, we could - * save rt_expires in seconds, likely valid_lft, - * but it would require division in fib gc, that it - * not good. - */ - if (HZ > USER_HZ) - rt_expires = addrconf_timeout_fixup(valid_lft, HZ); - else - rt_expires = addrconf_timeout_fixup(valid_lft, USER_HZ); - - if (addrconf_finite_timeout(rt_expires)) - rt_expires *= HZ; - - rt = addrconf_get_prefix_route(&pinfo->prefix, - pinfo->prefix_len, - dev, - RTF_ADDRCONF | RTF_PREFIX_RT, - RTF_GATEWAY | RTF_DEFAULT); - - if (rt) { - /* Autoconf prefix route */ - if (valid_lft == 0) { - ip6_del_rt(rt); - rt = NULL; - } else if (addrconf_finite_timeout(rt_expires)) { - /* not infinity */ - rt6_set_expires(rt, jiffies + rt_expires); - } else { - rt6_clean_expires(rt); - } - } else if (valid_lft) { - clock_t expires = 0; - int flags = RTF_ADDRCONF | RTF_PREFIX_RT; - if (addrconf_finite_timeout(rt_expires)) { - /* not infinity */ - flags |= RTF_EXPIRES; - expires = jiffies_to_clock_t(rt_expires); - } - addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len, - dev, expires, flags); - } - ip6_rt_put(rt); - } - - /* Try to figure out our local address for this prefix */ - - if (pinfo->autoconf && in6_dev->cnf.autoconf) { - struct in6_addr addr; - bool tokenized = false, dev_addr_generated = false; - - if (pinfo->prefix_len == 64) { - memcpy(&addr, &pinfo->prefix, 8); - - if (!ipv6_addr_any(&in6_dev->token)) { - read_lock_bh(&in6_dev->lock); - memcpy(addr.s6_addr + 8, - in6_dev->token.s6_addr + 8, 8); - read_unlock_bh(&in6_dev->lock); - tokenized = true; - } else if (is_addr_mode_generate_stable(in6_dev) && - !ipv6_generate_stable_address(&addr, 0, - in6_dev)) { - addr_flags |= IFA_F_STABLE_PRIVACY; - goto ok; - } else if (ipv6_generate_eui64(addr.s6_addr + 8, dev) && - ipv6_inherit_eui64(addr.s6_addr + 8, in6_dev)) { - goto put; - } else { - dev_addr_generated = true; - } - goto ok; - } - net_dbg_ratelimited("IPv6 addrconf: prefix with wrong length %d\n", - pinfo->prefix_len); - goto put; - -ok: - err = addrconf_prefix_rcv_add_addr(net, dev, pinfo, in6_dev, - &addr, addr_type, - addr_flags, sllao, - tokenized, valid_lft, - prefered_lft); - if (err) - goto put; - - /* Ignore error case here because previous prefix add addr was - * successful which will be notified. - */ - ndisc_ops_prefix_rcv_add_addr(net, dev, pinfo, in6_dev, &addr, - addr_type, addr_flags, sllao, - tokenized, valid_lft, - prefered_lft, - dev_addr_generated); - } - inet6_prefix_notify(RTM_NEWPREFIX, in6_dev, pinfo); -put: - in6_dev_put(in6_dev); -} - -/* - * Set destination address. - * Special case for SIT interfaces where we create a new "virtual" - * device. - */ -int addrconf_set_dstaddr(struct net *net, void __user *arg) -{ - struct in6_ifreq ireq; - struct net_device *dev; - int err = -EINVAL; - - rtnl_lock(); - - err = -EFAULT; - if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) - goto err_exit; - - dev = __dev_get_by_index(net, ireq.ifr6_ifindex); - - err = -ENODEV; - if (!dev) - goto err_exit; - -#if IS_ENABLED(CONFIG_IPV6_SIT) - if (dev->type == ARPHRD_SIT) { - const struct net_device_ops *ops = dev->netdev_ops; - struct ifreq ifr; - struct ip_tunnel_parm p; - - err = -EADDRNOTAVAIL; - if (!(ipv6_addr_type(&ireq.ifr6_addr) & IPV6_ADDR_COMPATv4)) - goto err_exit; - - memset(&p, 0, sizeof(p)); - p.iph.daddr = ireq.ifr6_addr.s6_addr32[3]; - p.iph.saddr = 0; - p.iph.version = 4; - p.iph.ihl = 5; - p.iph.protocol = IPPROTO_IPV6; - p.iph.ttl = 64; - ifr.ifr_ifru.ifru_data = (__force void __user *)&p; - - if (ops->ndo_do_ioctl) { - mm_segment_t oldfs = get_fs(); - - set_fs(KERNEL_DS); - err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL); - set_fs(oldfs); - } else - err = -EOPNOTSUPP; - - if (err == 0) { - err = -ENOBUFS; - dev = __dev_get_by_name(net, p.name); - if (!dev) - goto err_exit; - err = dev_open(dev); - } - } -#endif - -err_exit: - rtnl_unlock(); - return err; -} - -static int ipv6_mc_config(struct sock *sk, bool join, - const struct in6_addr *addr, int ifindex) -{ - int ret; - - ASSERT_RTNL(); - - lock_sock(sk); - if (join) - ret = ipv6_sock_mc_join(sk, ifindex, addr); - else - ret = ipv6_sock_mc_drop(sk, ifindex, addr); - release_sock(sk); - - return ret; -} - -/* - * Manual configuration of address on an interface - */ -static int inet6_addr_add(struct net *net, int ifindex, - const struct in6_addr *pfx, - const struct in6_addr *peer_pfx, - unsigned int plen, __u32 ifa_flags, - __u32 prefered_lft, __u32 valid_lft) -{ - struct inet6_ifaddr *ifp; - struct inet6_dev *idev; - struct net_device *dev; - unsigned long timeout; - clock_t expires; - int scope; - u32 flags; - - ASSERT_RTNL(); - - if (plen > 128) - return -EINVAL; - - /* check the lifetime */ - if (!valid_lft || prefered_lft > valid_lft) - return -EINVAL; - - if (ifa_flags & IFA_F_MANAGETEMPADDR && plen != 64) - return -EINVAL; - - dev = __dev_get_by_index(net, ifindex); - if (!dev) - return -ENODEV; - - idev = addrconf_add_dev(dev); - if (IS_ERR(idev)) - return PTR_ERR(idev); - - if (ifa_flags & IFA_F_MCAUTOJOIN) { - int ret = ipv6_mc_config(net->ipv6.mc_autojoin_sk, - true, pfx, ifindex); - - if (ret < 0) - return ret; - } - - scope = ipv6_addr_scope(pfx); - - timeout = addrconf_timeout_fixup(valid_lft, HZ); - if (addrconf_finite_timeout(timeout)) { - expires = jiffies_to_clock_t(timeout * HZ); - valid_lft = timeout; - flags = RTF_EXPIRES; - } else { - expires = 0; - flags = 0; - ifa_flags |= IFA_F_PERMANENT; - } - - timeout = addrconf_timeout_fixup(prefered_lft, HZ); - if (addrconf_finite_timeout(timeout)) { - if (timeout == 0) - ifa_flags |= IFA_F_DEPRECATED; - prefered_lft = timeout; - } - - ifp = ipv6_add_addr(idev, pfx, peer_pfx, plen, scope, ifa_flags, - valid_lft, prefered_lft); - - if (!IS_ERR(ifp)) { - if (!(ifa_flags & IFA_F_NOPREFIXROUTE)) { - addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, - expires, flags); - } - - /* - * Note that section 3.1 of RFC 4429 indicates - * that the Optimistic flag should not be set for - * manually configured addresses - */ - addrconf_dad_start(ifp); - if (ifa_flags & IFA_F_MANAGETEMPADDR) - manage_tempaddrs(idev, ifp, valid_lft, prefered_lft, - true, jiffies); - in6_ifa_put(ifp); - addrconf_verify_rtnl(); - return 0; - } else if (ifa_flags & IFA_F_MCAUTOJOIN) { - ipv6_mc_config(net->ipv6.mc_autojoin_sk, - false, pfx, ifindex); - } - - return PTR_ERR(ifp); -} - -static int inet6_addr_del(struct net *net, int ifindex, u32 ifa_flags, - const struct in6_addr *pfx, unsigned int plen) -{ - struct inet6_ifaddr *ifp; - struct inet6_dev *idev; - struct net_device *dev; - - if (plen > 128) - return -EINVAL; - - dev = __dev_get_by_index(net, ifindex); - if (!dev) - return -ENODEV; - - idev = __in6_dev_get(dev); - if (!idev) - return -ENXIO; - - read_lock_bh(&idev->lock); - list_for_each_entry(ifp, &idev->addr_list, if_list) { - if (ifp->prefix_len == plen && - ipv6_addr_equal(pfx, &ifp->addr)) { - in6_ifa_hold(ifp); - read_unlock_bh(&idev->lock); - - if (!(ifp->flags & IFA_F_TEMPORARY) && - (ifa_flags & IFA_F_MANAGETEMPADDR)) - manage_tempaddrs(idev, ifp, 0, 0, false, - jiffies); - ipv6_del_addr(ifp); - addrconf_verify_rtnl(); - if (ipv6_addr_is_multicast(pfx)) { - ipv6_mc_config(net->ipv6.mc_autojoin_sk, - false, pfx, dev->ifindex); - } - return 0; - } - } - read_unlock_bh(&idev->lock); - return -EADDRNOTAVAIL; -} - - -int addrconf_add_ifaddr(struct net *net, void __user *arg) -{ - struct in6_ifreq ireq; - int err; - - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - return -EPERM; - - if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) - return -EFAULT; - - rtnl_lock(); - err = inet6_addr_add(net, ireq.ifr6_ifindex, &ireq.ifr6_addr, NULL, - ireq.ifr6_prefixlen, IFA_F_PERMANENT, - INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); - rtnl_unlock(); - return err; -} - -int addrconf_del_ifaddr(struct net *net, void __user *arg) -{ - struct in6_ifreq ireq; - int err; - - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - return -EPERM; - - if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq))) - return -EFAULT; - - rtnl_lock(); - err = inet6_addr_del(net, ireq.ifr6_ifindex, 0, &ireq.ifr6_addr, - ireq.ifr6_prefixlen); - rtnl_unlock(); - return err; -} - -static void add_addr(struct inet6_dev *idev, const struct in6_addr *addr, - int plen, int scope) -{ - struct inet6_ifaddr *ifp; - - ifp = ipv6_add_addr(idev, addr, NULL, plen, - scope, IFA_F_PERMANENT, - INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); - if (!IS_ERR(ifp)) { - spin_lock_bh(&ifp->lock); - ifp->flags &= ~IFA_F_TENTATIVE; - spin_unlock_bh(&ifp->lock); - rt_genid_bump_ipv6(dev_net(idev->dev)); - ipv6_ifa_notify(RTM_NEWADDR, ifp); - in6_ifa_put(ifp); - } -} - -#if IS_ENABLED(CONFIG_IPV6_SIT) -static void sit_add_v4_addrs(struct inet6_dev *idev) -{ - struct in6_addr addr; - struct net_device *dev; - struct net *net = dev_net(idev->dev); - int scope, plen; - u32 pflags = 0; - - ASSERT_RTNL(); - - memset(&addr, 0, sizeof(struct in6_addr)); - memcpy(&addr.s6_addr32[3], idev->dev->dev_addr, 4); - - if (idev->dev->flags&IFF_POINTOPOINT) { - addr.s6_addr32[0] = htonl(0xfe800000); - scope = IFA_LINK; - plen = 64; - } else { - scope = IPV6_ADDR_COMPATv4; - plen = 96; - pflags |= RTF_NONEXTHOP; - } - - if (addr.s6_addr32[3]) { - add_addr(idev, &addr, plen, scope); - addrconf_prefix_route(&addr, plen, idev->dev, 0, pflags); - return; - } - - for_each_netdev(net, dev) { - struct in_device *in_dev = __in_dev_get_rtnl(dev); - if (in_dev && (dev->flags & IFF_UP)) { - struct in_ifaddr *ifa; - - int flag = scope; - - for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { - - addr.s6_addr32[3] = ifa->ifa_local; - - if (ifa->ifa_scope == RT_SCOPE_LINK) - continue; - if (ifa->ifa_scope >= RT_SCOPE_HOST) { - if (idev->dev->flags&IFF_POINTOPOINT) - continue; - flag |= IFA_HOST; - } - - add_addr(idev, &addr, plen, flag); - addrconf_prefix_route(&addr, plen, idev->dev, 0, - pflags); - } - } - } -} -#endif - -static void init_loopback(struct net_device *dev) -{ - struct inet6_dev *idev; - struct net_device *sp_dev; - struct inet6_ifaddr *sp_ifa; - struct rt6_info *sp_rt; - - /* ::1 */ - - ASSERT_RTNL(); - - idev = ipv6_find_idev(dev); - if (!idev) { - pr_debug("%s: add_dev failed\n", __func__); - return; - } - - add_addr(idev, &in6addr_loopback, 128, IFA_HOST); - - /* Add routes to other interface's IPv6 addresses */ - for_each_netdev(dev_net(dev), sp_dev) { - if (!strcmp(sp_dev->name, dev->name)) - continue; - - idev = __in6_dev_get(sp_dev); - if (!idev) - continue; - - read_lock_bh(&idev->lock); - list_for_each_entry(sp_ifa, &idev->addr_list, if_list) { - - if (sp_ifa->flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE)) - continue; - - if (sp_ifa->rt) { - /* This dst has been added to garbage list when - * lo device down, release this obsolete dst and - * reallocate a new router for ifa. - */ - if (!atomic_read(&sp_ifa->rt->rt6i_ref)) { - ip6_rt_put(sp_ifa->rt); - sp_ifa->rt = NULL; - } else { - continue; - } - } - - sp_rt = addrconf_dst_alloc(idev, &sp_ifa->addr, false); - - /* Failure cases are ignored */ - if (!IS_ERR(sp_rt)) { - sp_ifa->rt = sp_rt; - ip6_ins_rt(sp_rt); - } - } - read_unlock_bh(&idev->lock); - } -} - -void addrconf_add_linklocal(struct inet6_dev *idev, - const struct in6_addr *addr, u32 flags) -{ - struct inet6_ifaddr *ifp; - u32 addr_flags = flags | IFA_F_PERMANENT; - -#ifdef CONFIG_IPV6_OPTIMISTIC_DAD - if (idev->cnf.optimistic_dad && - !dev_net(idev->dev)->ipv6.devconf_all->forwarding) - addr_flags |= IFA_F_OPTIMISTIC; -#endif - - ifp = ipv6_add_addr(idev, addr, NULL, 64, IFA_LINK, addr_flags, - INFINITY_LIFE_TIME, INFINITY_LIFE_TIME); - if (!IS_ERR(ifp)) { - addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0); - addrconf_dad_start(ifp); - in6_ifa_put(ifp); - } -} -EXPORT_SYMBOL_GPL(addrconf_add_linklocal); - -static bool ipv6_reserved_interfaceid(struct in6_addr address) -{ - if ((address.s6_addr32[2] | address.s6_addr32[3]) == 0) - return true; - - if (address.s6_addr32[2] == htonl(0x02005eff) && - ((address.s6_addr32[3] & htonl(0xfe000000)) == htonl(0xfe000000))) - return true; - - if (address.s6_addr32[2] == htonl(0xfdffffff) && - ((address.s6_addr32[3] & htonl(0xffffff80)) == htonl(0xffffff80))) - return true; - - return false; -} - -static int ipv6_generate_stable_address(struct in6_addr *address, - u8 dad_count, - const struct inet6_dev *idev) -{ - static DEFINE_SPINLOCK(lock); - static __u32 digest[SHA_DIGEST_WORDS]; - static __u32 workspace[SHA_WORKSPACE_WORDS]; - - static union { - char __data[SHA_MESSAGE_BYTES]; - struct { - struct in6_addr secret; - __be32 prefix[2]; - unsigned char hwaddr[MAX_ADDR_LEN]; - u8 dad_count; - } __packed; - } data; - - struct in6_addr secret; - struct in6_addr temp; - struct net *net = dev_net(idev->dev); - - BUILD_BUG_ON(sizeof(data.__data) != sizeof(data)); - - if (idev->cnf.stable_secret.initialized) - secret = idev->cnf.stable_secret.secret; - else if (net->ipv6.devconf_dflt->stable_secret.initialized) - secret = net->ipv6.devconf_dflt->stable_secret.secret; - else - return -1; - -retry: - spin_lock_bh(&lock); - - sha_init(digest); - memset(&data, 0, sizeof(data)); - memset(workspace, 0, sizeof(workspace)); - memcpy(data.hwaddr, idev->dev->perm_addr, idev->dev->addr_len); - data.prefix[0] = address->s6_addr32[0]; - data.prefix[1] = address->s6_addr32[1]; - data.secret = secret; - data.dad_count = dad_count; - - sha_transform(digest, data.__data, workspace); - - temp = *address; - temp.s6_addr32[2] = (__force __be32)digest[0]; - temp.s6_addr32[3] = (__force __be32)digest[1]; - - spin_unlock_bh(&lock); - - if (ipv6_reserved_interfaceid(temp)) { - dad_count++; - if (dad_count > dev_net(idev->dev)->ipv6.sysctl.idgen_retries) - return -1; - goto retry; - } - - *address = temp; - return 0; -} - -static void ipv6_gen_mode_random_init(struct inet6_dev *idev) -{ - struct ipv6_stable_secret *s = &idev->cnf.stable_secret; - - if (s->initialized) - return; - s = &idev->cnf.stable_secret; - get_random_bytes(&s->secret, sizeof(s->secret)); - s->initialized = true; -} - -static void addrconf_addr_gen(struct inet6_dev *idev, bool prefix_route) -{ - struct in6_addr addr; - - /* no link local addresses on L3 master devices */ - if (netif_is_l3_master(idev->dev)) - return; - - ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); - - switch (idev->addr_gen_mode) { - case IN6_ADDR_GEN_MODE_RANDOM: - ipv6_gen_mode_random_init(idev); - /* fallthrough */ - case IN6_ADDR_GEN_MODE_STABLE_PRIVACY: - if (!ipv6_generate_stable_address(&addr, 0, idev)) - addrconf_add_linklocal(idev, &addr, - IFA_F_STABLE_PRIVACY); - else if (prefix_route) - addrconf_prefix_route(&addr, 64, idev->dev, 0, 0); - break; - case IN6_ADDR_GEN_MODE_EUI64: - /* addrconf_add_linklocal also adds a prefix_route and we - * only need to care about prefix routes if ipv6_generate_eui64 - * couldn't generate one. - */ - if (ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) == 0) - addrconf_add_linklocal(idev, &addr, 0); - else if (prefix_route) - addrconf_prefix_route(&addr, 64, idev->dev, 0, 0); - break; - case IN6_ADDR_GEN_MODE_NONE: - default: - /* will not add any link local address */ - break; - } -} - -static void addrconf_dev_config(struct net_device *dev) -{ - struct inet6_dev *idev; - - ASSERT_RTNL(); - - if ((dev->type != ARPHRD_ETHER) && - (dev->type != ARPHRD_FDDI) && - (dev->type != ARPHRD_ARCNET) && - (dev->type != ARPHRD_INFINIBAND) && - (dev->type != ARPHRD_IEEE1394) && - (dev->type != ARPHRD_TUNNEL6) && - (dev->type != ARPHRD_6LOWPAN) && - (dev->type != ARPHRD_NONE)) { - /* Alas, we support only Ethernet autoconfiguration. */ - return; - } - - idev = addrconf_add_dev(dev); - if (IS_ERR(idev)) - return; - - /* this device type has no EUI support */ - if (dev->type == ARPHRD_NONE && - idev->addr_gen_mode == IN6_ADDR_GEN_MODE_EUI64) - idev->addr_gen_mode = IN6_ADDR_GEN_MODE_RANDOM; - - addrconf_addr_gen(idev, false); -} - -#if IS_ENABLED(CONFIG_IPV6_SIT) -static void addrconf_sit_config(struct net_device *dev) -{ - struct inet6_dev *idev; - - ASSERT_RTNL(); - - /* - * Configure the tunnel with one of our IPv4 - * addresses... we should configure all of - * our v4 addrs in the tunnel - */ - - idev = ipv6_find_idev(dev); - if (!idev) { - pr_debug("%s: add_dev failed\n", __func__); - return; - } - - if (dev->priv_flags & IFF_ISATAP) { - addrconf_addr_gen(idev, false); - return; - } - - sit_add_v4_addrs(idev); - - if (dev->flags&IFF_POINTOPOINT) - addrconf_add_mroute(dev); -} -#endif - -#if IS_ENABLED(CONFIG_NET_IPGRE) -static void addrconf_gre_config(struct net_device *dev) -{ - struct inet6_dev *idev; - - ASSERT_RTNL(); - - idev = ipv6_find_idev(dev); - if (!idev) { - pr_debug("%s: add_dev failed\n", __func__); - return; - } - - addrconf_addr_gen(idev, true); - if (dev->flags & IFF_POINTOPOINT) - addrconf_add_mroute(dev); -} -#endif - -static int fixup_permanent_addr(struct inet6_dev *idev, - struct inet6_ifaddr *ifp) -{ - if (!ifp->rt) { - struct rt6_info *rt; - - rt = addrconf_dst_alloc(idev, &ifp->addr, false); - if (unlikely(IS_ERR(rt))) - return PTR_ERR(rt); - - ifp->rt = rt; - } - - if (!(ifp->flags & IFA_F_NOPREFIXROUTE)) { - addrconf_prefix_route(&ifp->addr, ifp->prefix_len, - idev->dev, 0, 0); - } - - addrconf_dad_start(ifp); - - return 0; -} - -static void addrconf_permanent_addr(struct net_device *dev) -{ - struct inet6_ifaddr *ifp, *tmp; - struct inet6_dev *idev; - - idev = __in6_dev_get(dev); - if (!idev) - return; - - write_lock_bh(&idev->lock); - - list_for_each_entry_safe(ifp, tmp, &idev->addr_list, if_list) { - if ((ifp->flags & IFA_F_PERMANENT) && - fixup_permanent_addr(idev, ifp) < 0) { - write_unlock_bh(&idev->lock); - ipv6_del_addr(ifp); - write_lock_bh(&idev->lock); - - net_info_ratelimited("%s: Failed to add prefix route for address %pI6c; dropping\n", - idev->dev->name, &ifp->addr); - } - } - - write_unlock_bh(&idev->lock); -} - -static int addrconf_notify(struct notifier_block *this, unsigned long event, - void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct netdev_notifier_changeupper_info *info; - struct inet6_dev *idev = __in6_dev_get(dev); - int run_pending = 0; - int err; - - switch (event) { - case NETDEV_REGISTER: - if (!idev && dev->mtu >= IPV6_MIN_MTU) { - idev = ipv6_add_dev(dev); - if (IS_ERR(idev)) - return notifier_from_errno(PTR_ERR(idev)); - } - break; - - case NETDEV_CHANGEMTU: - /* if MTU under IPV6_MIN_MTU stop IPv6 on this interface. */ - if (dev->mtu < IPV6_MIN_MTU) { - addrconf_ifdown(dev, 1); - break; - } - - if (idev) { - rt6_mtu_change(dev, dev->mtu); - idev->cnf.mtu6 = dev->mtu; - break; - } - - /* allocate new idev */ - idev = ipv6_add_dev(dev); - if (IS_ERR(idev)) - break; - - /* device is still not ready */ - if (!(idev->if_flags & IF_READY)) - break; - - run_pending = 1; - - /* fall through */ - - case NETDEV_UP: - case NETDEV_CHANGE: - if (dev->flags & IFF_SLAVE) - break; - - if (idev && idev->cnf.disable_ipv6) - break; - - if (event == NETDEV_UP) { - /* restore routes for permanent addresses */ - addrconf_permanent_addr(dev); - - if (!addrconf_qdisc_ok(dev)) { - /* device is not ready yet. */ - pr_info("ADDRCONF(NETDEV_UP): %s: link is not ready\n", - dev->name); - break; - } - - if (!idev && dev->mtu >= IPV6_MIN_MTU) - idev = ipv6_add_dev(dev); - - if (!IS_ERR_OR_NULL(idev)) { - idev->if_flags |= IF_READY; - run_pending = 1; - } - } else if (event == NETDEV_CHANGE) { - if (!addrconf_qdisc_ok(dev)) { - /* device is still not ready. */ - break; - } - - if (idev) { - if (idev->if_flags & IF_READY) - /* device is already configured. */ - break; - idev->if_flags |= IF_READY; - } - - pr_info("ADDRCONF(NETDEV_CHANGE): %s: link becomes ready\n", - dev->name); - - run_pending = 1; - } - - switch (dev->type) { -#if IS_ENABLED(CONFIG_IPV6_SIT) - case ARPHRD_SIT: - addrconf_sit_config(dev); - break; -#endif -#if IS_ENABLED(CONFIG_NET_IPGRE) - case ARPHRD_IPGRE: - addrconf_gre_config(dev); - break; -#endif - case ARPHRD_LOOPBACK: - init_loopback(dev); - break; - - default: - addrconf_dev_config(dev); - break; - } - - if (!IS_ERR_OR_NULL(idev)) { - if (run_pending) - addrconf_dad_run(idev); - - /* - * If the MTU changed during the interface down, - * when the interface up, the changed MTU must be - * reflected in the idev as well as routers. - */ - if (idev->cnf.mtu6 != dev->mtu && - dev->mtu >= IPV6_MIN_MTU) { - rt6_mtu_change(dev, dev->mtu); - idev->cnf.mtu6 = dev->mtu; - } - idev->tstamp = jiffies; - inet6_ifinfo_notify(RTM_NEWLINK, idev); - - /* - * If the changed mtu during down is lower than - * IPV6_MIN_MTU stop IPv6 on this interface. - */ - if (dev->mtu < IPV6_MIN_MTU) - addrconf_ifdown(dev, 1); - } - break; - - case NETDEV_DOWN: - case NETDEV_UNREGISTER: - /* - * Remove all addresses from this interface. - */ - addrconf_ifdown(dev, event != NETDEV_DOWN); - break; - - case NETDEV_CHANGENAME: - if (idev) { - snmp6_unregister_dev(idev); - addrconf_sysctl_unregister(idev); - err = addrconf_sysctl_register(idev); - if (err) - return notifier_from_errno(err); - err = snmp6_register_dev(idev); - if (err) { - addrconf_sysctl_unregister(idev); - return notifier_from_errno(err); - } - } - break; - - case NETDEV_PRE_TYPE_CHANGE: - case NETDEV_POST_TYPE_CHANGE: - if (idev) - addrconf_type_change(dev, event); - break; - - case NETDEV_CHANGEUPPER: - info = ptr; - - /* flush all routes if dev is linked to or unlinked from - * an L3 master device (e.g., VRF) - */ - if (info->upper_dev && netif_is_l3_master(info->upper_dev)) - addrconf_ifdown(dev, 0); - } - - return NOTIFY_OK; -} - -/* - * addrconf module should be notified of a device going up - */ -static struct notifier_block ipv6_dev_notf = { - .notifier_call = addrconf_notify, -}; - -static void addrconf_type_change(struct net_device *dev, unsigned long event) -{ - struct inet6_dev *idev; - ASSERT_RTNL(); - - idev = __in6_dev_get(dev); - - if (event == NETDEV_POST_TYPE_CHANGE) - ipv6_mc_remap(idev); - else if (event == NETDEV_PRE_TYPE_CHANGE) - ipv6_mc_unmap(idev); -} - -static bool addr_is_local(const struct in6_addr *addr) -{ - return ipv6_addr_type(addr) & - (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK); -} - -static int addrconf_ifdown(struct net_device *dev, int how) -{ - struct net *net = dev_net(dev); - struct inet6_dev *idev; - struct inet6_ifaddr *ifa, *tmp; - struct list_head del_list; - int _keep_addr; - bool keep_addr; - int state, i; - - ASSERT_RTNL(); - - rt6_ifdown(net, dev); - neigh_ifdown(&nd_tbl, dev); - - idev = __in6_dev_get(dev); - if (!idev) - return -ENODEV; - - /* - * Step 1: remove reference to ipv6 device from parent device. - * Do not dev_put! - */ - if (how) { - idev->dead = 1; - - /* protected by rtnl_lock */ - RCU_INIT_POINTER(dev->ip6_ptr, NULL); - - /* Step 1.5: remove snmp6 entry */ - snmp6_unregister_dev(idev); - - } - - /* aggregate the system setting and interface setting */ - _keep_addr = net->ipv6.devconf_all->keep_addr_on_down; - if (!_keep_addr) - _keep_addr = idev->cnf.keep_addr_on_down; - - /* combine the user config with event to determine if permanent - * addresses are to be removed from address hash table - */ - keep_addr = !(how || _keep_addr <= 0 || idev->cnf.disable_ipv6); - - /* Step 2: clear hash table */ - for (i = 0; i < IN6_ADDR_HSIZE; i++) { - struct hlist_head *h = &inet6_addr_lst[i]; - - spin_lock_bh(&addrconf_hash_lock); -restart: - hlist_for_each_entry_rcu(ifa, h, addr_lst) { - if (ifa->idev == idev) { - addrconf_del_dad_work(ifa); - /* combined flag + permanent flag decide if - * address is retained on a down event - */ - if (!keep_addr || - !(ifa->flags & IFA_F_PERMANENT) || - addr_is_local(&ifa->addr)) { - hlist_del_init_rcu(&ifa->addr_lst); - goto restart; - } - } - } - spin_unlock_bh(&addrconf_hash_lock); - } - - write_lock_bh(&idev->lock); - - addrconf_del_rs_timer(idev); - - /* Step 2: clear flags for stateless addrconf */ - if (!how) - idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY); - - /* Step 3: clear tempaddr list */ - while (!list_empty(&idev->tempaddr_list)) { - ifa = list_first_entry(&idev->tempaddr_list, - struct inet6_ifaddr, tmp_list); - list_del(&ifa->tmp_list); - write_unlock_bh(&idev->lock); - spin_lock_bh(&ifa->lock); - - if (ifa->ifpub) { - in6_ifa_put(ifa->ifpub); - ifa->ifpub = NULL; - } - spin_unlock_bh(&ifa->lock); - in6_ifa_put(ifa); - write_lock_bh(&idev->lock); - } - - /* re-combine the user config with event to determine if permanent - * addresses are to be removed from the interface list - */ - keep_addr = (!how && _keep_addr > 0 && !idev->cnf.disable_ipv6); - - INIT_LIST_HEAD(&del_list); - list_for_each_entry_safe(ifa, tmp, &idev->addr_list, if_list) { - struct rt6_info *rt = NULL; - - addrconf_del_dad_work(ifa); - - write_unlock_bh(&idev->lock); - spin_lock_bh(&ifa->lock); - - if (keep_addr && (ifa->flags & IFA_F_PERMANENT) && - !addr_is_local(&ifa->addr)) { - /* set state to skip the notifier below */ - state = INET6_IFADDR_STATE_DEAD; - ifa->state = 0; - if (!(ifa->flags & IFA_F_NODAD)) - ifa->flags |= IFA_F_TENTATIVE; - - rt = ifa->rt; - ifa->rt = NULL; - } else { - state = ifa->state; - ifa->state = INET6_IFADDR_STATE_DEAD; - - list_move(&ifa->if_list, &del_list); - } - - spin_unlock_bh(&ifa->lock); - - if (rt) - ip6_del_rt(rt); - - if (state != INET6_IFADDR_STATE_DEAD) { - __ipv6_ifa_notify(RTM_DELADDR, ifa); - inet6addr_notifier_call_chain(NETDEV_DOWN, ifa); - } else { - if (idev->cnf.forwarding) - addrconf_leave_anycast(ifa); - addrconf_leave_solict(ifa->idev, &ifa->addr); - } - - write_lock_bh(&idev->lock); - } - - write_unlock_bh(&idev->lock); - - /* now clean up addresses to be removed */ - while (!list_empty(&del_list)) { - ifa = list_first_entry(&del_list, - struct inet6_ifaddr, if_list); - list_del(&ifa->if_list); - - in6_ifa_put(ifa); - } - - /* Step 5: Discard anycast and multicast list */ - if (how) { - ipv6_ac_destroy_dev(idev); - ipv6_mc_destroy_dev(idev); - } else { - ipv6_mc_down(idev); - } - - idev->tstamp = jiffies; - - /* Last: Shot the device (if unregistered) */ - if (how) { - addrconf_sysctl_unregister(idev); - neigh_parms_release(&nd_tbl, idev->nd_parms); - neigh_ifdown(&nd_tbl, dev); - in6_dev_put(idev); - } - return 0; -} - -static void addrconf_rs_timer(unsigned long data) -{ - struct inet6_dev *idev = (struct inet6_dev *)data; - struct net_device *dev = idev->dev; - struct in6_addr lladdr; - - write_lock(&idev->lock); - if (idev->dead || !(idev->if_flags & IF_READY)) - goto out; - - if (!ipv6_accept_ra(idev)) - goto out; - - /* Announcement received after solicitation was sent */ - if (idev->if_flags & IF_RA_RCVD) - goto out; - - if (idev->rs_probes++ < idev->cnf.rtr_solicits || idev->cnf.rtr_solicits < 0) { - write_unlock(&idev->lock); - if (!ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE)) - ndisc_send_rs(dev, &lladdr, - &in6addr_linklocal_allrouters); - else - goto put; - - write_lock(&idev->lock); - idev->rs_interval = rfc3315_s14_backoff_update( - idev->rs_interval, idev->cnf.rtr_solicit_max_interval); - /* The wait after the last probe can be shorter */ - addrconf_mod_rs_timer(idev, (idev->rs_probes == - idev->cnf.rtr_solicits) ? - idev->cnf.rtr_solicit_delay : - idev->rs_interval); - } else { - /* - * Note: we do not support deprecated "all on-link" - * assumption any longer. - */ - pr_debug("%s: no IPv6 routers present\n", idev->dev->name); - } - -out: - write_unlock(&idev->lock); -put: - in6_dev_put(idev); -} - -/* - * Duplicate Address Detection - */ -static void addrconf_dad_kick(struct inet6_ifaddr *ifp) -{ - unsigned long rand_num; - struct inet6_dev *idev = ifp->idev; - - if (ifp->flags & IFA_F_OPTIMISTIC) - rand_num = 0; - else - rand_num = prandom_u32() % (idev->cnf.rtr_solicit_delay ? : 1); - - ifp->dad_probes = idev->cnf.dad_transmits; - addrconf_mod_dad_work(ifp, rand_num); -} - -static void addrconf_dad_begin(struct inet6_ifaddr *ifp) -{ - struct inet6_dev *idev = ifp->idev; - struct net_device *dev = idev->dev; - bool bump_id, notify = false; - - addrconf_join_solict(dev, &ifp->addr); - - prandom_seed((__force u32) ifp->addr.s6_addr32[3]); - - read_lock_bh(&idev->lock); - spin_lock(&ifp->lock); - if (ifp->state == INET6_IFADDR_STATE_DEAD) - goto out; - - if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) || - idev->cnf.accept_dad < 1 || - !(ifp->flags&IFA_F_TENTATIVE) || - ifp->flags & IFA_F_NODAD) { - bump_id = ifp->flags & IFA_F_TENTATIVE; - ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); - spin_unlock(&ifp->lock); - read_unlock_bh(&idev->lock); - - addrconf_dad_completed(ifp, bump_id); - return; - } - - if (!(idev->if_flags & IF_READY)) { - spin_unlock(&ifp->lock); - read_unlock_bh(&idev->lock); - /* - * If the device is not ready: - * - keep it tentative if it is a permanent address. - * - otherwise, kill it. - */ - in6_ifa_hold(ifp); - addrconf_dad_stop(ifp, 0); - return; - } - - /* - * Optimistic nodes can start receiving - * Frames right away - */ - if (ifp->flags & IFA_F_OPTIMISTIC) { - ip6_ins_rt(ifp->rt); - if (ipv6_use_optimistic_addr(idev)) { - /* Because optimistic nodes can use this address, - * notify listeners. If DAD fails, RTM_DELADDR is sent. - */ - notify = true; - } - } - - addrconf_dad_kick(ifp); -out: - spin_unlock(&ifp->lock); - read_unlock_bh(&idev->lock); - if (notify) - ipv6_ifa_notify(RTM_NEWADDR, ifp); -} - -static void addrconf_dad_start(struct inet6_ifaddr *ifp) -{ - bool begin_dad = false; - - spin_lock_bh(&ifp->lock); - if (ifp->state != INET6_IFADDR_STATE_DEAD) { - ifp->state = INET6_IFADDR_STATE_PREDAD; - begin_dad = true; - } - spin_unlock_bh(&ifp->lock); - - if (begin_dad) - addrconf_mod_dad_work(ifp, 0); -} - -static void addrconf_dad_work(struct work_struct *w) -{ - struct inet6_ifaddr *ifp = container_of(to_delayed_work(w), - struct inet6_ifaddr, - dad_work); - struct inet6_dev *idev = ifp->idev; - bool bump_id, disable_ipv6 = false; - struct in6_addr mcaddr; - - enum { - DAD_PROCESS, - DAD_BEGIN, - DAD_ABORT, - } action = DAD_PROCESS; - - rtnl_lock(); - - spin_lock_bh(&ifp->lock); - if (ifp->state == INET6_IFADDR_STATE_PREDAD) { - action = DAD_BEGIN; - ifp->state = INET6_IFADDR_STATE_DAD; - } else if (ifp->state == INET6_IFADDR_STATE_ERRDAD) { - action = DAD_ABORT; - ifp->state = INET6_IFADDR_STATE_POSTDAD; - - if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6 && - !(ifp->flags & IFA_F_STABLE_PRIVACY)) { - struct in6_addr addr; - - addr.s6_addr32[0] = htonl(0xfe800000); - addr.s6_addr32[1] = 0; - - if (!ipv6_generate_eui64(addr.s6_addr + 8, idev->dev) && - ipv6_addr_equal(&ifp->addr, &addr)) { - /* DAD failed for link-local based on MAC */ - idev->cnf.disable_ipv6 = 1; - - pr_info("%s: IPv6 being disabled!\n", - ifp->idev->dev->name); - disable_ipv6 = true; - } - } - } - spin_unlock_bh(&ifp->lock); - - if (action == DAD_BEGIN) { - addrconf_dad_begin(ifp); - goto out; - } else if (action == DAD_ABORT) { - in6_ifa_hold(ifp); - addrconf_dad_stop(ifp, 1); - if (disable_ipv6) - addrconf_ifdown(idev->dev, 0); - goto out; - } - - if (!ifp->dad_probes && addrconf_dad_end(ifp)) - goto out; - - write_lock_bh(&idev->lock); - if (idev->dead || !(idev->if_flags & IF_READY)) { - write_unlock_bh(&idev->lock); - goto out; - } - - spin_lock(&ifp->lock); - if (ifp->state == INET6_IFADDR_STATE_DEAD) { - spin_unlock(&ifp->lock); - write_unlock_bh(&idev->lock); - goto out; - } - - if (ifp->dad_probes == 0) { - /* - * DAD was successful - */ - - bump_id = ifp->flags & IFA_F_TENTATIVE; - ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED); - spin_unlock(&ifp->lock); - write_unlock_bh(&idev->lock); - - addrconf_dad_completed(ifp, bump_id); - - goto out; - } - - ifp->dad_probes--; - addrconf_mod_dad_work(ifp, - NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME)); - spin_unlock(&ifp->lock); - write_unlock_bh(&idev->lock); - - /* send a neighbour solicitation for our addr */ - addrconf_addr_solict_mult(&ifp->addr, &mcaddr); - ndisc_send_ns(ifp->idev->dev, &ifp->addr, &mcaddr, &in6addr_any); -out: - in6_ifa_put(ifp); - rtnl_unlock(); -} - -/* ifp->idev must be at least read locked */ -static bool ipv6_lonely_lladdr(struct inet6_ifaddr *ifp) -{ - struct inet6_ifaddr *ifpiter; - struct inet6_dev *idev = ifp->idev; - - list_for_each_entry_reverse(ifpiter, &idev->addr_list, if_list) { - if (ifpiter->scope > IFA_LINK) - break; - if (ifp != ifpiter && ifpiter->scope == IFA_LINK && - (ifpiter->flags & (IFA_F_PERMANENT|IFA_F_TENTATIVE| - IFA_F_OPTIMISTIC|IFA_F_DADFAILED)) == - IFA_F_PERMANENT) - return false; - } - return true; -} - -static void addrconf_dad_completed(struct inet6_ifaddr *ifp, bool bump_id) -{ - struct net_device *dev = ifp->idev->dev; - struct in6_addr lladdr; - bool send_rs, send_mld; - - addrconf_del_dad_work(ifp); - - /* - * Configure the address for reception. Now it is valid. - */ - - ipv6_ifa_notify(RTM_NEWADDR, ifp); - - /* If added prefix is link local and we are prepared to process - router advertisements, start sending router solicitations. - */ - - read_lock_bh(&ifp->idev->lock); - send_mld = ifp->scope == IFA_LINK && ipv6_lonely_lladdr(ifp); - send_rs = send_mld && - ipv6_accept_ra(ifp->idev) && - ifp->idev->cnf.rtr_solicits != 0 && - (dev->flags&IFF_LOOPBACK) == 0; - read_unlock_bh(&ifp->idev->lock); - - /* While dad is in progress mld report's source address is in6_addrany. - * Resend with proper ll now. - */ - if (send_mld) - ipv6_mc_dad_complete(ifp->idev); - - if (send_rs) { - /* - * If a host as already performed a random delay - * [...] as part of DAD [...] there is no need - * to delay again before sending the first RS - */ - if (ipv6_get_lladdr(dev, &lladdr, IFA_F_TENTATIVE)) - return; - ndisc_send_rs(dev, &lladdr, &in6addr_linklocal_allrouters); - - write_lock_bh(&ifp->idev->lock); - spin_lock(&ifp->lock); - ifp->idev->rs_interval = rfc3315_s14_backoff_init( - ifp->idev->cnf.rtr_solicit_interval); - ifp->idev->rs_probes = 1; - ifp->idev->if_flags |= IF_RS_SENT; - addrconf_mod_rs_timer(ifp->idev, ifp->idev->rs_interval); - spin_unlock(&ifp->lock); - write_unlock_bh(&ifp->idev->lock); - } - - if (bump_id) - rt_genid_bump_ipv6(dev_net(dev)); -} - -static void addrconf_dad_run(struct inet6_dev *idev) -{ - struct inet6_ifaddr *ifp; - - read_lock_bh(&idev->lock); - list_for_each_entry(ifp, &idev->addr_list, if_list) { - spin_lock(&ifp->lock); - if (ifp->flags & IFA_F_TENTATIVE && - ifp->state == INET6_IFADDR_STATE_DAD) - addrconf_dad_kick(ifp); - spin_unlock(&ifp->lock); - } - read_unlock_bh(&idev->lock); -} - -#ifdef CONFIG_PROC_FS -struct if6_iter_state { - struct seq_net_private p; - int bucket; - int offset; -}; - -static struct inet6_ifaddr *if6_get_first(struct seq_file *seq, loff_t pos) -{ - struct inet6_ifaddr *ifa = NULL; - struct if6_iter_state *state = seq->private; - struct net *net = seq_file_net(seq); - int p = 0; - - /* initial bucket if pos is 0 */ - if (pos == 0) { - state->bucket = 0; - state->offset = 0; - } - - for (; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { - hlist_for_each_entry_rcu_bh(ifa, &inet6_addr_lst[state->bucket], - addr_lst) { - if (!net_eq(dev_net(ifa->idev->dev), net)) - continue; - /* sync with offset */ - if (p < state->offset) { - p++; - continue; - } - state->offset++; - return ifa; - } - - /* prepare for next bucket */ - state->offset = 0; - p = 0; - } - return NULL; -} - -static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, - struct inet6_ifaddr *ifa) -{ - struct if6_iter_state *state = seq->private; - struct net *net = seq_file_net(seq); - - hlist_for_each_entry_continue_rcu_bh(ifa, addr_lst) { - if (!net_eq(dev_net(ifa->idev->dev), net)) - continue; - state->offset++; - return ifa; - } - - while (++state->bucket < IN6_ADDR_HSIZE) { - state->offset = 0; - hlist_for_each_entry_rcu_bh(ifa, - &inet6_addr_lst[state->bucket], addr_lst) { - if (!net_eq(dev_net(ifa->idev->dev), net)) - continue; - state->offset++; - return ifa; - } - } - - return NULL; -} - -static void *if6_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(rcu_bh) -{ - rcu_read_lock_bh(); - return if6_get_first(seq, *pos); -} - -static void *if6_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct inet6_ifaddr *ifa; - - ifa = if6_get_next(seq, v); - ++*pos; - return ifa; -} - -static void if6_seq_stop(struct seq_file *seq, void *v) - __releases(rcu_bh) -{ - rcu_read_unlock_bh(); -} - -static int if6_seq_show(struct seq_file *seq, void *v) -{ - struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v; - seq_printf(seq, "%pi6 %02x %02x %02x %02x %8s\n", - &ifp->addr, - ifp->idev->dev->ifindex, - ifp->prefix_len, - ifp->scope, - (u8) ifp->flags, - ifp->idev->dev->name); - return 0; -} - -static const struct seq_operations if6_seq_ops = { - .start = if6_seq_start, - .next = if6_seq_next, - .show = if6_seq_show, - .stop = if6_seq_stop, -}; - -static int if6_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &if6_seq_ops, - sizeof(struct if6_iter_state)); -} - -static const struct file_operations if6_fops = { - .owner = THIS_MODULE, - .open = if6_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -static int __net_init if6_proc_net_init(struct net *net) -{ - if (!proc_create("if_inet6", S_IRUGO, net->proc_net, &if6_fops)) - return -ENOMEM; - return 0; -} - -static void __net_exit if6_proc_net_exit(struct net *net) -{ - remove_proc_entry("if_inet6", net->proc_net); -} - -static struct pernet_operations if6_proc_net_ops = { - .init = if6_proc_net_init, - .exit = if6_proc_net_exit, -}; - -int __init if6_proc_init(void) -{ - return register_pernet_subsys(&if6_proc_net_ops); -} - -void if6_proc_exit(void) -{ - unregister_pernet_subsys(&if6_proc_net_ops); -} -#endif /* CONFIG_PROC_FS */ - -#if IS_ENABLED(CONFIG_IPV6_MIP6) -/* Check if address is a home address configured on any interface. */ -int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr) -{ - int ret = 0; - struct inet6_ifaddr *ifp = NULL; - unsigned int hash = inet6_addr_hash(addr); - - rcu_read_lock_bh(); - hlist_for_each_entry_rcu_bh(ifp, &inet6_addr_lst[hash], addr_lst) { - if (!net_eq(dev_net(ifp->idev->dev), net)) - continue; - if (ipv6_addr_equal(&ifp->addr, addr) && - (ifp->flags & IFA_F_HOMEADDRESS)) { - ret = 1; - break; - } - } - rcu_read_unlock_bh(); - return ret; -} -#endif - -/* - * Periodic address status verification - */ - -static void addrconf_verify_rtnl(void) -{ - unsigned long now, next, next_sec, next_sched; - struct inet6_ifaddr *ifp; - int i; - - ASSERT_RTNL(); - - rcu_read_lock_bh(); - now = jiffies; - next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY); - - cancel_delayed_work(&addr_chk_work); - - for (i = 0; i < IN6_ADDR_HSIZE; i++) { -restart: - hlist_for_each_entry_rcu_bh(ifp, &inet6_addr_lst[i], addr_lst) { - unsigned long age; - - /* When setting preferred_lft to a value not zero or - * infinity, while valid_lft is infinity - * IFA_F_PERMANENT has a non-infinity life time. - */ - if ((ifp->flags & IFA_F_PERMANENT) && - (ifp->prefered_lft == INFINITY_LIFE_TIME)) - continue; - - spin_lock(&ifp->lock); - /* We try to batch several events at once. */ - age = (now - ifp->tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ; - - if (ifp->valid_lft != INFINITY_LIFE_TIME && - age >= ifp->valid_lft) { - spin_unlock(&ifp->lock); - in6_ifa_hold(ifp); - ipv6_del_addr(ifp); - goto restart; - } else if (ifp->prefered_lft == INFINITY_LIFE_TIME) { - spin_unlock(&ifp->lock); - continue; - } else if (age >= ifp->prefered_lft) { - /* jiffies - ifp->tstamp > age >= ifp->prefered_lft */ - int deprecate = 0; - - if (!(ifp->flags&IFA_F_DEPRECATED)) { - deprecate = 1; - ifp->flags |= IFA_F_DEPRECATED; - } - - if ((ifp->valid_lft != INFINITY_LIFE_TIME) && - (time_before(ifp->tstamp + ifp->valid_lft * HZ, next))) - next = ifp->tstamp + ifp->valid_lft * HZ; - - spin_unlock(&ifp->lock); - - if (deprecate) { - in6_ifa_hold(ifp); - - ipv6_ifa_notify(0, ifp); - in6_ifa_put(ifp); - goto restart; - } - } else if ((ifp->flags&IFA_F_TEMPORARY) && - !(ifp->flags&IFA_F_TENTATIVE)) { - unsigned long regen_advance = ifp->idev->cnf.regen_max_retry * - ifp->idev->cnf.dad_transmits * - NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME) / HZ; - - if (age >= ifp->prefered_lft - regen_advance) { - struct inet6_ifaddr *ifpub = ifp->ifpub; - if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next)) - next = ifp->tstamp + ifp->prefered_lft * HZ; - if (!ifp->regen_count && ifpub) { - ifp->regen_count++; - in6_ifa_hold(ifp); - in6_ifa_hold(ifpub); - spin_unlock(&ifp->lock); - - spin_lock(&ifpub->lock); - ifpub->regen_count = 0; - spin_unlock(&ifpub->lock); - ipv6_create_tempaddr(ifpub, ifp); - in6_ifa_put(ifpub); - in6_ifa_put(ifp); - goto restart; - } - } else if (time_before(ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ, next)) - next = ifp->tstamp + ifp->prefered_lft * HZ - regen_advance * HZ; - spin_unlock(&ifp->lock); - } else { - /* ifp->prefered_lft <= ifp->valid_lft */ - if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next)) - next = ifp->tstamp + ifp->prefered_lft * HZ; - spin_unlock(&ifp->lock); - } - } - } - - next_sec = round_jiffies_up(next); - next_sched = next; - - /* If rounded timeout is accurate enough, accept it. */ - if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ)) - next_sched = next_sec; - - /* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */ - if (time_before(next_sched, jiffies + ADDRCONF_TIMER_FUZZ_MAX)) - next_sched = jiffies + ADDRCONF_TIMER_FUZZ_MAX; - - ADBG(KERN_DEBUG "now = %lu, schedule = %lu, rounded schedule = %lu => %lu\n", - now, next, next_sec, next_sched); - mod_delayed_work(addrconf_wq, &addr_chk_work, next_sched - now); - rcu_read_unlock_bh(); -} - -static void addrconf_verify_work(struct work_struct *w) -{ - rtnl_lock(); - addrconf_verify_rtnl(); - rtnl_unlock(); -} - -static void addrconf_verify(void) -{ - mod_delayed_work(addrconf_wq, &addr_chk_work, 0); -} - -static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local, - struct in6_addr **peer_pfx) -{ - struct in6_addr *pfx = NULL; - - *peer_pfx = NULL; - - if (addr) - pfx = nla_data(addr); - - if (local) { - if (pfx && nla_memcmp(local, pfx, sizeof(*pfx))) - *peer_pfx = pfx; - pfx = nla_data(local); - } - - return pfx; -} - -static const struct nla_policy ifa_ipv6_policy[IFA_MAX+1] = { - [IFA_ADDRESS] = { .len = sizeof(struct in6_addr) }, - [IFA_LOCAL] = { .len = sizeof(struct in6_addr) }, - [IFA_CACHEINFO] = { .len = sizeof(struct ifa_cacheinfo) }, - [IFA_FLAGS] = { .len = sizeof(u32) }, -}; - -static int -inet6_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct ifaddrmsg *ifm; - struct nlattr *tb[IFA_MAX+1]; - struct in6_addr *pfx, *peer_pfx; - u32 ifa_flags; - int err; - - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); - if (err < 0) - return err; - - ifm = nlmsg_data(nlh); - pfx = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL], &peer_pfx); - if (!pfx) - return -EINVAL; - - ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : ifm->ifa_flags; - - /* We ignore other flags so far. */ - ifa_flags &= IFA_F_MANAGETEMPADDR; - - return inet6_addr_del(net, ifm->ifa_index, ifa_flags, pfx, - ifm->ifa_prefixlen); -} - -static int inet6_addr_modify(struct inet6_ifaddr *ifp, u32 ifa_flags, - u32 prefered_lft, u32 valid_lft) -{ - u32 flags; - clock_t expires; - unsigned long timeout; - bool was_managetempaddr; - bool had_prefixroute; - - ASSERT_RTNL(); - - if (!valid_lft || (prefered_lft > valid_lft)) - return -EINVAL; - - if (ifa_flags & IFA_F_MANAGETEMPADDR && - (ifp->flags & IFA_F_TEMPORARY || ifp->prefix_len != 64)) - return -EINVAL; - - timeout = addrconf_timeout_fixup(valid_lft, HZ); - if (addrconf_finite_timeout(timeout)) { - expires = jiffies_to_clock_t(timeout * HZ); - valid_lft = timeout; - flags = RTF_EXPIRES; - } else { - expires = 0; - flags = 0; - ifa_flags |= IFA_F_PERMANENT; - } - - timeout = addrconf_timeout_fixup(prefered_lft, HZ); - if (addrconf_finite_timeout(timeout)) { - if (timeout == 0) - ifa_flags |= IFA_F_DEPRECATED; - prefered_lft = timeout; - } - - spin_lock_bh(&ifp->lock); - was_managetempaddr = ifp->flags & IFA_F_MANAGETEMPADDR; - had_prefixroute = ifp->flags & IFA_F_PERMANENT && - !(ifp->flags & IFA_F_NOPREFIXROUTE); - ifp->flags &= ~(IFA_F_DEPRECATED | IFA_F_PERMANENT | IFA_F_NODAD | - IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR | - IFA_F_NOPREFIXROUTE); - ifp->flags |= ifa_flags; - ifp->tstamp = jiffies; - ifp->valid_lft = valid_lft; - ifp->prefered_lft = prefered_lft; - - spin_unlock_bh(&ifp->lock); - if (!(ifp->flags&IFA_F_TENTATIVE)) - ipv6_ifa_notify(0, ifp); - - if (!(ifa_flags & IFA_F_NOPREFIXROUTE)) { - addrconf_prefix_route(&ifp->addr, ifp->prefix_len, ifp->idev->dev, - expires, flags); - } else if (had_prefixroute) { - enum cleanup_prefix_rt_t action; - unsigned long rt_expires; - - write_lock_bh(&ifp->idev->lock); - action = check_cleanup_prefix_route(ifp, &rt_expires); - write_unlock_bh(&ifp->idev->lock); - - if (action != CLEANUP_PREFIX_RT_NOP) { - cleanup_prefix_route(ifp, rt_expires, - action == CLEANUP_PREFIX_RT_DEL); - } - } - - if (was_managetempaddr || ifp->flags & IFA_F_MANAGETEMPADDR) { - if (was_managetempaddr && !(ifp->flags & IFA_F_MANAGETEMPADDR)) - valid_lft = prefered_lft = 0; - manage_tempaddrs(ifp->idev, ifp, valid_lft, prefered_lft, - !was_managetempaddr, jiffies); - } - - addrconf_verify_rtnl(); - - return 0; -} - -static int -inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct ifaddrmsg *ifm; - struct nlattr *tb[IFA_MAX+1]; - struct in6_addr *pfx, *peer_pfx; - struct inet6_ifaddr *ifa; - struct net_device *dev; - u32 valid_lft = INFINITY_LIFE_TIME, preferred_lft = INFINITY_LIFE_TIME; - u32 ifa_flags; - int err; - - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); - if (err < 0) - return err; - - ifm = nlmsg_data(nlh); - pfx = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL], &peer_pfx); - if (!pfx) - return -EINVAL; - - if (tb[IFA_CACHEINFO]) { - struct ifa_cacheinfo *ci; - - ci = nla_data(tb[IFA_CACHEINFO]); - valid_lft = ci->ifa_valid; - preferred_lft = ci->ifa_prefered; - } else { - preferred_lft = INFINITY_LIFE_TIME; - valid_lft = INFINITY_LIFE_TIME; - } - - dev = __dev_get_by_index(net, ifm->ifa_index); - if (!dev) - return -ENODEV; - - ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : ifm->ifa_flags; - - /* We ignore other flags so far. */ - ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS | IFA_F_MANAGETEMPADDR | - IFA_F_NOPREFIXROUTE | IFA_F_MCAUTOJOIN; - - ifa = ipv6_get_ifaddr(net, pfx, dev, 1); - if (!ifa) { - /* - * It would be best to check for !NLM_F_CREATE here but - * userspace already relies on not having to provide this. - */ - return inet6_addr_add(net, ifm->ifa_index, pfx, peer_pfx, - ifm->ifa_prefixlen, ifa_flags, - preferred_lft, valid_lft); - } - - if (nlh->nlmsg_flags & NLM_F_EXCL || - !(nlh->nlmsg_flags & NLM_F_REPLACE)) - err = -EEXIST; - else - err = inet6_addr_modify(ifa, ifa_flags, preferred_lft, valid_lft); - - in6_ifa_put(ifa); - - return err; -} - -static void put_ifaddrmsg(struct nlmsghdr *nlh, u8 prefixlen, u32 flags, - u8 scope, int ifindex) -{ - struct ifaddrmsg *ifm; - - ifm = nlmsg_data(nlh); - ifm->ifa_family = AF_INET6; - ifm->ifa_prefixlen = prefixlen; - ifm->ifa_flags = flags; - ifm->ifa_scope = scope; - ifm->ifa_index = ifindex; -} - -static int put_cacheinfo(struct sk_buff *skb, unsigned long cstamp, - unsigned long tstamp, u32 preferred, u32 valid) -{ - struct ifa_cacheinfo ci; - - ci.cstamp = cstamp_delta(cstamp); - ci.tstamp = cstamp_delta(tstamp); - ci.ifa_prefered = preferred; - ci.ifa_valid = valid; - - return nla_put(skb, IFA_CACHEINFO, sizeof(ci), &ci); -} - -static inline int rt_scope(int ifa_scope) -{ - if (ifa_scope & IFA_HOST) - return RT_SCOPE_HOST; - else if (ifa_scope & IFA_LINK) - return RT_SCOPE_LINK; - else if (ifa_scope & IFA_SITE) - return RT_SCOPE_SITE; - else - return RT_SCOPE_UNIVERSE; -} - -static inline int inet6_ifaddr_msgsize(void) -{ - return NLMSG_ALIGN(sizeof(struct ifaddrmsg)) - + nla_total_size(16) /* IFA_LOCAL */ - + nla_total_size(16) /* IFA_ADDRESS */ - + nla_total_size(sizeof(struct ifa_cacheinfo)) - + nla_total_size(4) /* IFA_FLAGS */; -} - -static int inet6_fill_ifaddr(struct sk_buff *skb, struct inet6_ifaddr *ifa, - u32 portid, u32 seq, int event, unsigned int flags) -{ - struct nlmsghdr *nlh; - u32 preferred, valid; - - nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct ifaddrmsg), flags); - if (!nlh) - return -EMSGSIZE; - - put_ifaddrmsg(nlh, ifa->prefix_len, ifa->flags, rt_scope(ifa->scope), - ifa->idev->dev->ifindex); - - if (!((ifa->flags&IFA_F_PERMANENT) && - (ifa->prefered_lft == INFINITY_LIFE_TIME))) { - preferred = ifa->prefered_lft; - valid = ifa->valid_lft; - if (preferred != INFINITY_LIFE_TIME) { - long tval = (jiffies - ifa->tstamp)/HZ; - if (preferred > tval) - preferred -= tval; - else - preferred = 0; - if (valid != INFINITY_LIFE_TIME) { - if (valid > tval) - valid -= tval; - else - valid = 0; - } - } - } else { - preferred = INFINITY_LIFE_TIME; - valid = INFINITY_LIFE_TIME; - } - - if (!ipv6_addr_any(&ifa->peer_addr)) { - if (nla_put_in6_addr(skb, IFA_LOCAL, &ifa->addr) < 0 || - nla_put_in6_addr(skb, IFA_ADDRESS, &ifa->peer_addr) < 0) - goto error; - } else - if (nla_put_in6_addr(skb, IFA_ADDRESS, &ifa->addr) < 0) - goto error; - - if (put_cacheinfo(skb, ifa->cstamp, ifa->tstamp, preferred, valid) < 0) - goto error; - - if (nla_put_u32(skb, IFA_FLAGS, ifa->flags) < 0) - goto error; - - nlmsg_end(skb, nlh); - return 0; - -error: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -static int inet6_fill_ifmcaddr(struct sk_buff *skb, struct ifmcaddr6 *ifmca, - u32 portid, u32 seq, int event, u16 flags) -{ - struct nlmsghdr *nlh; - u8 scope = RT_SCOPE_UNIVERSE; - int ifindex = ifmca->idev->dev->ifindex; - - if (ipv6_addr_scope(&ifmca->mca_addr) & IFA_SITE) - scope = RT_SCOPE_SITE; - - nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct ifaddrmsg), flags); - if (!nlh) - return -EMSGSIZE; - - put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex); - if (nla_put_in6_addr(skb, IFA_MULTICAST, &ifmca->mca_addr) < 0 || - put_cacheinfo(skb, ifmca->mca_cstamp, ifmca->mca_tstamp, - INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0) { - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; - } - - nlmsg_end(skb, nlh); - return 0; -} - -static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca, - u32 portid, u32 seq, int event, unsigned int flags) -{ - struct nlmsghdr *nlh; - u8 scope = RT_SCOPE_UNIVERSE; - int ifindex = ifaca->aca_idev->dev->ifindex; - - if (ipv6_addr_scope(&ifaca->aca_addr) & IFA_SITE) - scope = RT_SCOPE_SITE; - - nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct ifaddrmsg), flags); - if (!nlh) - return -EMSGSIZE; - - put_ifaddrmsg(nlh, 128, IFA_F_PERMANENT, scope, ifindex); - if (nla_put_in6_addr(skb, IFA_ANYCAST, &ifaca->aca_addr) < 0 || - put_cacheinfo(skb, ifaca->aca_cstamp, ifaca->aca_tstamp, - INFINITY_LIFE_TIME, INFINITY_LIFE_TIME) < 0) { - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; - } - - nlmsg_end(skb, nlh); - return 0; -} - -enum addr_type_t { - UNICAST_ADDR, - MULTICAST_ADDR, - ANYCAST_ADDR, -}; - -/* called with rcu_read_lock() */ -static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb, - struct netlink_callback *cb, enum addr_type_t type, - int s_ip_idx, int *p_ip_idx) -{ - struct ifmcaddr6 *ifmca; - struct ifacaddr6 *ifaca; - int err = 1; - int ip_idx = *p_ip_idx; - - read_lock_bh(&idev->lock); - switch (type) { - case UNICAST_ADDR: { - struct inet6_ifaddr *ifa; - - /* unicast address incl. temp addr */ - list_for_each_entry(ifa, &idev->addr_list, if_list) { - if (++ip_idx < s_ip_idx) - continue; - err = inet6_fill_ifaddr(skb, ifa, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWADDR, - NLM_F_MULTI); - if (err < 0) - break; - nl_dump_check_consistent(cb, nlmsg_hdr(skb)); - } - break; - } - case MULTICAST_ADDR: - /* multicast address */ - for (ifmca = idev->mc_list; ifmca; - ifmca = ifmca->next, ip_idx++) { - if (ip_idx < s_ip_idx) - continue; - err = inet6_fill_ifmcaddr(skb, ifmca, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_GETMULTICAST, - NLM_F_MULTI); - if (err < 0) - break; - } - break; - case ANYCAST_ADDR: - /* anycast address */ - for (ifaca = idev->ac_list; ifaca; - ifaca = ifaca->aca_next, ip_idx++) { - if (ip_idx < s_ip_idx) - continue; - err = inet6_fill_ifacaddr(skb, ifaca, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_GETANYCAST, - NLM_F_MULTI); - if (err < 0) - break; - } - break; - default: - break; - } - read_unlock_bh(&idev->lock); - *p_ip_idx = ip_idx; - return err; -} - -static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, - enum addr_type_t type) -{ - struct net *net = sock_net(skb->sk); - int h, s_h; - int idx, ip_idx; - int s_idx, s_ip_idx; - struct net_device *dev; - struct inet6_dev *idev; - struct hlist_head *head; - - s_h = cb->args[0]; - s_idx = idx = cb->args[1]; - s_ip_idx = ip_idx = cb->args[2]; - - rcu_read_lock(); - cb->seq = atomic_read(&net->ipv6.dev_addr_genid) ^ net->dev_base_seq; - for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { - idx = 0; - head = &net->dev_index_head[h]; - hlist_for_each_entry_rcu(dev, head, index_hlist) { - if (idx < s_idx) - goto cont; - if (h > s_h || idx > s_idx) - s_ip_idx = 0; - ip_idx = 0; - idev = __in6_dev_get(dev); - if (!idev) - goto cont; - - if (in6_dump_addrs(idev, skb, cb, type, - s_ip_idx, &ip_idx) < 0) - goto done; -cont: - idx++; - } - } -done: - rcu_read_unlock(); - cb->args[0] = h; - cb->args[1] = idx; - cb->args[2] = ip_idx; - - return skb->len; -} - -static int inet6_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb) -{ - enum addr_type_t type = UNICAST_ADDR; - - return inet6_dump_addr(skb, cb, type); -} - -static int inet6_dump_ifmcaddr(struct sk_buff *skb, struct netlink_callback *cb) -{ - enum addr_type_t type = MULTICAST_ADDR; - - return inet6_dump_addr(skb, cb, type); -} - - -static int inet6_dump_ifacaddr(struct sk_buff *skb, struct netlink_callback *cb) -{ - enum addr_type_t type = ANYCAST_ADDR; - - return inet6_dump_addr(skb, cb, type); -} - -static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(in_skb->sk); - struct ifaddrmsg *ifm; - struct nlattr *tb[IFA_MAX+1]; - struct in6_addr *addr = NULL, *peer; - struct net_device *dev = NULL; - struct inet6_ifaddr *ifa; - struct sk_buff *skb; - int err; - - err = nlmsg_parse(nlh, sizeof(*ifm), tb, IFA_MAX, ifa_ipv6_policy); - if (err < 0) - goto errout; - - addr = extract_addr(tb[IFA_ADDRESS], tb[IFA_LOCAL], &peer); - if (!addr) { - err = -EINVAL; - goto errout; - } - - ifm = nlmsg_data(nlh); - if (ifm->ifa_index) - dev = __dev_get_by_index(net, ifm->ifa_index); - - ifa = ipv6_get_ifaddr(net, addr, dev, 1); - if (!ifa) { - err = -EADDRNOTAVAIL; - goto errout; - } - - skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_KERNEL); - if (!skb) { - err = -ENOBUFS; - goto errout_ifa; - } - - err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(in_skb).portid, - nlh->nlmsg_seq, RTM_NEWADDR, 0); - if (err < 0) { - /* -EMSGSIZE implies BUG in inet6_ifaddr_msgsize() */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - goto errout_ifa; - } - err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); -errout_ifa: - in6_ifa_put(ifa); -errout: - return err; -} - -static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa) -{ - struct sk_buff *skb; - struct net *net = dev_net(ifa->idev->dev); - int err = -ENOBUFS; - - skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_ATOMIC); - if (!skb) - goto errout; - - err = inet6_fill_ifaddr(skb, ifa, 0, 0, event, 0); - if (err < 0) { - /* -EMSGSIZE implies BUG in inet6_ifaddr_msgsize() */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - goto errout; - } - rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC); - return; -errout: - if (err < 0) - rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err); -} - -static inline void ipv6_store_devconf(struct ipv6_devconf *cnf, - __s32 *array, int bytes) -{ - BUG_ON(bytes < (DEVCONF_MAX * 4)); - - memset(array, 0, bytes); - array[DEVCONF_FORWARDING] = cnf->forwarding; - array[DEVCONF_HOPLIMIT] = cnf->hop_limit; - array[DEVCONF_MTU6] = cnf->mtu6; - array[DEVCONF_ACCEPT_RA] = cnf->accept_ra; - array[DEVCONF_ACCEPT_REDIRECTS] = cnf->accept_redirects; - array[DEVCONF_AUTOCONF] = cnf->autoconf; - array[DEVCONF_DAD_TRANSMITS] = cnf->dad_transmits; - array[DEVCONF_RTR_SOLICITS] = cnf->rtr_solicits; - array[DEVCONF_RTR_SOLICIT_INTERVAL] = - jiffies_to_msecs(cnf->rtr_solicit_interval); - array[DEVCONF_RTR_SOLICIT_MAX_INTERVAL] = - jiffies_to_msecs(cnf->rtr_solicit_max_interval); - array[DEVCONF_RTR_SOLICIT_DELAY] = - jiffies_to_msecs(cnf->rtr_solicit_delay); - array[DEVCONF_FORCE_MLD_VERSION] = cnf->force_mld_version; - array[DEVCONF_MLDV1_UNSOLICITED_REPORT_INTERVAL] = - jiffies_to_msecs(cnf->mldv1_unsolicited_report_interval); - array[DEVCONF_MLDV2_UNSOLICITED_REPORT_INTERVAL] = - jiffies_to_msecs(cnf->mldv2_unsolicited_report_interval); - array[DEVCONF_USE_TEMPADDR] = cnf->use_tempaddr; - array[DEVCONF_TEMP_VALID_LFT] = cnf->temp_valid_lft; - array[DEVCONF_TEMP_PREFERED_LFT] = cnf->temp_prefered_lft; - array[DEVCONF_REGEN_MAX_RETRY] = cnf->regen_max_retry; - array[DEVCONF_MAX_DESYNC_FACTOR] = cnf->max_desync_factor; - array[DEVCONF_MAX_ADDRESSES] = cnf->max_addresses; - array[DEVCONF_ACCEPT_RA_DEFRTR] = cnf->accept_ra_defrtr; - array[DEVCONF_ACCEPT_RA_MIN_HOP_LIMIT] = cnf->accept_ra_min_hop_limit; - array[DEVCONF_ACCEPT_RA_PINFO] = cnf->accept_ra_pinfo; -#ifdef CONFIG_IPV6_ROUTER_PREF - array[DEVCONF_ACCEPT_RA_RTR_PREF] = cnf->accept_ra_rtr_pref; - array[DEVCONF_RTR_PROBE_INTERVAL] = - jiffies_to_msecs(cnf->rtr_probe_interval); -#ifdef CONFIG_IPV6_ROUTE_INFO - array[DEVCONF_ACCEPT_RA_RT_INFO_MAX_PLEN] = cnf->accept_ra_rt_info_max_plen; -#endif -#endif - array[DEVCONF_PROXY_NDP] = cnf->proxy_ndp; - array[DEVCONF_ACCEPT_SOURCE_ROUTE] = cnf->accept_source_route; -#ifdef CONFIG_IPV6_OPTIMISTIC_DAD - array[DEVCONF_OPTIMISTIC_DAD] = cnf->optimistic_dad; - array[DEVCONF_USE_OPTIMISTIC] = cnf->use_optimistic; -#endif -#ifdef CONFIG_IPV6_MROUTE - array[DEVCONF_MC_FORWARDING] = cnf->mc_forwarding; -#endif - array[DEVCONF_DISABLE_IPV6] = cnf->disable_ipv6; - array[DEVCONF_ACCEPT_DAD] = cnf->accept_dad; - array[DEVCONF_FORCE_TLLAO] = cnf->force_tllao; - array[DEVCONF_NDISC_NOTIFY] = cnf->ndisc_notify; - array[DEVCONF_SUPPRESS_FRAG_NDISC] = cnf->suppress_frag_ndisc; - array[DEVCONF_ACCEPT_RA_FROM_LOCAL] = cnf->accept_ra_from_local; - array[DEVCONF_ACCEPT_RA_MTU] = cnf->accept_ra_mtu; - array[DEVCONF_IGNORE_ROUTES_WITH_LINKDOWN] = cnf->ignore_routes_with_linkdown; - /* we omit DEVCONF_STABLE_SECRET for now */ - array[DEVCONF_USE_OIF_ADDRS_ONLY] = cnf->use_oif_addrs_only; - array[DEVCONF_DROP_UNICAST_IN_L2_MULTICAST] = cnf->drop_unicast_in_l2_multicast; - array[DEVCONF_DROP_UNSOLICITED_NA] = cnf->drop_unsolicited_na; - array[DEVCONF_KEEP_ADDR_ON_DOWN] = cnf->keep_addr_on_down; -} - -static inline size_t inet6_ifla6_size(void) -{ - return nla_total_size(4) /* IFLA_INET6_FLAGS */ - + nla_total_size(sizeof(struct ifla_cacheinfo)) - + nla_total_size(DEVCONF_MAX * 4) /* IFLA_INET6_CONF */ - + nla_total_size(IPSTATS_MIB_MAX * 8) /* IFLA_INET6_STATS */ - + nla_total_size(ICMP6_MIB_MAX * 8) /* IFLA_INET6_ICMP6STATS */ - + nla_total_size(sizeof(struct in6_addr)); /* IFLA_INET6_TOKEN */ -} - -static inline size_t inet6_if_nlmsg_size(void) -{ - return NLMSG_ALIGN(sizeof(struct ifinfomsg)) - + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */ - + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */ - + nla_total_size(4) /* IFLA_MTU */ - + nla_total_size(4) /* IFLA_LINK */ - + nla_total_size(1) /* IFLA_OPERSTATE */ - + nla_total_size(inet6_ifla6_size()); /* IFLA_PROTINFO */ -} - -static inline void __snmp6_fill_statsdev(u64 *stats, atomic_long_t *mib, - int bytes) -{ - int i; - int pad = bytes - sizeof(u64) * ICMP6_MIB_MAX; - BUG_ON(pad < 0); - - /* Use put_unaligned() because stats may not be aligned for u64. */ - put_unaligned(ICMP6_MIB_MAX, &stats[0]); - for (i = 1; i < ICMP6_MIB_MAX; i++) - put_unaligned(atomic_long_read(&mib[i]), &stats[i]); - - memset(&stats[ICMP6_MIB_MAX], 0, pad); -} - -static inline void __snmp6_fill_stats64(u64 *stats, void __percpu *mib, - int bytes, size_t syncpoff) -{ - int i, c; - u64 buff[IPSTATS_MIB_MAX]; - int pad = bytes - sizeof(u64) * IPSTATS_MIB_MAX; - - BUG_ON(pad < 0); - - memset(buff, 0, sizeof(buff)); - buff[0] = IPSTATS_MIB_MAX; - - for_each_possible_cpu(c) { - for (i = 1; i < IPSTATS_MIB_MAX; i++) - buff[i] += snmp_get_cpu_field64(mib, c, i, syncpoff); - } - - memcpy(stats, buff, IPSTATS_MIB_MAX * sizeof(u64)); - memset(&stats[IPSTATS_MIB_MAX], 0, pad); -} - -static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype, - int bytes) -{ - switch (attrtype) { - case IFLA_INET6_STATS: - __snmp6_fill_stats64(stats, idev->stats.ipv6, bytes, - offsetof(struct ipstats_mib, syncp)); - break; - case IFLA_INET6_ICMP6STATS: - __snmp6_fill_statsdev(stats, idev->stats.icmpv6dev->mibs, bytes); - break; - } -} - -static int inet6_fill_ifla6_attrs(struct sk_buff *skb, struct inet6_dev *idev, - u32 ext_filter_mask) -{ - struct nlattr *nla; - struct ifla_cacheinfo ci; - - if (nla_put_u32(skb, IFLA_INET6_FLAGS, idev->if_flags)) - goto nla_put_failure; - ci.max_reasm_len = IPV6_MAXPLEN; - ci.tstamp = cstamp_delta(idev->tstamp); - ci.reachable_time = jiffies_to_msecs(idev->nd_parms->reachable_time); - ci.retrans_time = jiffies_to_msecs(NEIGH_VAR(idev->nd_parms, RETRANS_TIME)); - if (nla_put(skb, IFLA_INET6_CACHEINFO, sizeof(ci), &ci)) - goto nla_put_failure; - nla = nla_reserve(skb, IFLA_INET6_CONF, DEVCONF_MAX * sizeof(s32)); - if (!nla) - goto nla_put_failure; - ipv6_store_devconf(&idev->cnf, nla_data(nla), nla_len(nla)); - - /* XXX - MC not implemented */ - - if (ext_filter_mask & RTEXT_FILTER_SKIP_STATS) - return 0; - - nla = nla_reserve(skb, IFLA_INET6_STATS, IPSTATS_MIB_MAX * sizeof(u64)); - if (!nla) - goto nla_put_failure; - snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_STATS, nla_len(nla)); - - nla = nla_reserve(skb, IFLA_INET6_ICMP6STATS, ICMP6_MIB_MAX * sizeof(u64)); - if (!nla) - goto nla_put_failure; - snmp6_fill_stats(nla_data(nla), idev, IFLA_INET6_ICMP6STATS, nla_len(nla)); - - nla = nla_reserve(skb, IFLA_INET6_TOKEN, sizeof(struct in6_addr)); - if (!nla) - goto nla_put_failure; - - if (nla_put_u8(skb, IFLA_INET6_ADDR_GEN_MODE, idev->addr_gen_mode)) - goto nla_put_failure; - - read_lock_bh(&idev->lock); - memcpy(nla_data(nla), idev->token.s6_addr, nla_len(nla)); - read_unlock_bh(&idev->lock); - - return 0; - -nla_put_failure: - return -EMSGSIZE; -} - -static size_t inet6_get_link_af_size(const struct net_device *dev, - u32 ext_filter_mask) -{ - if (!__in6_dev_get(dev)) - return 0; - - return inet6_ifla6_size(); -} - -static int inet6_fill_link_af(struct sk_buff *skb, const struct net_device *dev, - u32 ext_filter_mask) -{ - struct inet6_dev *idev = __in6_dev_get(dev); - - if (!idev) - return -ENODATA; - - if (inet6_fill_ifla6_attrs(skb, idev, ext_filter_mask) < 0) - return -EMSGSIZE; - - return 0; -} - -static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token) -{ - struct inet6_ifaddr *ifp; - struct net_device *dev = idev->dev; - bool clear_token, update_rs = false; - struct in6_addr ll_addr; - - ASSERT_RTNL(); - - if (!token) - return -EINVAL; - if (dev->flags & (IFF_LOOPBACK | IFF_NOARP)) - return -EINVAL; - if (!ipv6_accept_ra(idev)) - return -EINVAL; - if (idev->cnf.rtr_solicits == 0) - return -EINVAL; - - write_lock_bh(&idev->lock); - - BUILD_BUG_ON(sizeof(token->s6_addr) != 16); - memcpy(idev->token.s6_addr + 8, token->s6_addr + 8, 8); - - write_unlock_bh(&idev->lock); - - clear_token = ipv6_addr_any(token); - if (clear_token) - goto update_lft; - - if (!idev->dead && (idev->if_flags & IF_READY) && - !ipv6_get_lladdr(dev, &ll_addr, IFA_F_TENTATIVE | - IFA_F_OPTIMISTIC)) { - /* If we're not ready, then normal ifup will take care - * of this. Otherwise, we need to request our rs here. - */ - ndisc_send_rs(dev, &ll_addr, &in6addr_linklocal_allrouters); - update_rs = true; - } - -update_lft: - write_lock_bh(&idev->lock); - - if (update_rs) { - idev->if_flags |= IF_RS_SENT; - idev->rs_interval = rfc3315_s14_backoff_init( - idev->cnf.rtr_solicit_interval); - idev->rs_probes = 1; - addrconf_mod_rs_timer(idev, idev->rs_interval); - } - - /* Well, that's kinda nasty ... */ - list_for_each_entry(ifp, &idev->addr_list, if_list) { - spin_lock(&ifp->lock); - if (ifp->tokenized) { - ifp->valid_lft = 0; - ifp->prefered_lft = 0; - } - spin_unlock(&ifp->lock); - } - - write_unlock_bh(&idev->lock); - inet6_ifinfo_notify(RTM_NEWLINK, idev); - addrconf_verify_rtnl(); - return 0; -} - -static const struct nla_policy inet6_af_policy[IFLA_INET6_MAX + 1] = { - [IFLA_INET6_ADDR_GEN_MODE] = { .type = NLA_U8 }, - [IFLA_INET6_TOKEN] = { .len = sizeof(struct in6_addr) }, -}; - -static int inet6_validate_link_af(const struct net_device *dev, - const struct nlattr *nla) -{ - struct nlattr *tb[IFLA_INET6_MAX + 1]; - - if (dev && !__in6_dev_get(dev)) - return -EAFNOSUPPORT; - - return nla_parse_nested(tb, IFLA_INET6_MAX, nla, inet6_af_policy); -} - -static int inet6_set_link_af(struct net_device *dev, const struct nlattr *nla) -{ - int err = -EINVAL; - struct inet6_dev *idev = __in6_dev_get(dev); - struct nlattr *tb[IFLA_INET6_MAX + 1]; - - if (!idev) - return -EAFNOSUPPORT; - - if (nla_parse_nested(tb, IFLA_INET6_MAX, nla, NULL) < 0) - BUG(); - - if (tb[IFLA_INET6_TOKEN]) { - err = inet6_set_iftoken(idev, nla_data(tb[IFLA_INET6_TOKEN])); - if (err) - return err; - } - - if (tb[IFLA_INET6_ADDR_GEN_MODE]) { - u8 mode = nla_get_u8(tb[IFLA_INET6_ADDR_GEN_MODE]); - - if (mode != IN6_ADDR_GEN_MODE_EUI64 && - mode != IN6_ADDR_GEN_MODE_NONE && - mode != IN6_ADDR_GEN_MODE_STABLE_PRIVACY && - mode != IN6_ADDR_GEN_MODE_RANDOM) - return -EINVAL; - - if (mode == IN6_ADDR_GEN_MODE_STABLE_PRIVACY && - !idev->cnf.stable_secret.initialized && - !dev_net(dev)->ipv6.devconf_dflt->stable_secret.initialized) - return -EINVAL; - - idev->addr_gen_mode = mode; - err = 0; - } - - return err; -} - -static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev, - u32 portid, u32 seq, int event, unsigned int flags) -{ - struct net_device *dev = idev->dev; - struct ifinfomsg *hdr; - struct nlmsghdr *nlh; - void *protoinfo; - - nlh = nlmsg_put(skb, portid, seq, event, sizeof(*hdr), flags); - if (!nlh) - return -EMSGSIZE; - - hdr = nlmsg_data(nlh); - hdr->ifi_family = AF_INET6; - hdr->__ifi_pad = 0; - hdr->ifi_type = dev->type; - hdr->ifi_index = dev->ifindex; - hdr->ifi_flags = dev_get_flags(dev); - hdr->ifi_change = 0; - - if (nla_put_string(skb, IFLA_IFNAME, dev->name) || - (dev->addr_len && - nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) || - nla_put_u32(skb, IFLA_MTU, dev->mtu) || - (dev->ifindex != dev_get_iflink(dev) && - nla_put_u32(skb, IFLA_LINK, dev_get_iflink(dev))) || - nla_put_u8(skb, IFLA_OPERSTATE, - netif_running(dev) ? dev->operstate : IF_OPER_DOWN)) - goto nla_put_failure; - protoinfo = nla_nest_start(skb, IFLA_PROTINFO); - if (!protoinfo) - goto nla_put_failure; - - if (inet6_fill_ifla6_attrs(skb, idev, 0) < 0) - goto nla_put_failure; - - nla_nest_end(skb, protoinfo); - nlmsg_end(skb, nlh); - return 0; - -nla_put_failure: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) -{ - struct net *net = sock_net(skb->sk); - int h, s_h; - int idx = 0, s_idx; - struct net_device *dev; - struct inet6_dev *idev; - struct hlist_head *head; - - s_h = cb->args[0]; - s_idx = cb->args[1]; - - rcu_read_lock(); - for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { - idx = 0; - head = &net->dev_index_head[h]; - hlist_for_each_entry_rcu(dev, head, index_hlist) { - if (idx < s_idx) - goto cont; - idev = __in6_dev_get(dev); - if (!idev) - goto cont; - if (inet6_fill_ifinfo(skb, idev, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWLINK, NLM_F_MULTI) < 0) - goto out; -cont: - idx++; - } - } -out: - rcu_read_unlock(); - cb->args[1] = idx; - cb->args[0] = h; - - return skb->len; -} - -void inet6_ifinfo_notify(int event, struct inet6_dev *idev) -{ - struct sk_buff *skb; - struct net *net = dev_net(idev->dev); - int err = -ENOBUFS; - - skb = nlmsg_new(inet6_if_nlmsg_size(), GFP_ATOMIC); - if (!skb) - goto errout; - - err = inet6_fill_ifinfo(skb, idev, 0, 0, event, 0); - if (err < 0) { - /* -EMSGSIZE implies BUG in inet6_if_nlmsg_size() */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - goto errout; - } - rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFINFO, NULL, GFP_ATOMIC); - return; -errout: - if (err < 0) - rtnl_set_sk_err(net, RTNLGRP_IPV6_IFINFO, err); -} - -static inline size_t inet6_prefix_nlmsg_size(void) -{ - return NLMSG_ALIGN(sizeof(struct prefixmsg)) - + nla_total_size(sizeof(struct in6_addr)) - + nla_total_size(sizeof(struct prefix_cacheinfo)); -} - -static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev, - struct prefix_info *pinfo, u32 portid, u32 seq, - int event, unsigned int flags) -{ - struct prefixmsg *pmsg; - struct nlmsghdr *nlh; - struct prefix_cacheinfo ci; - - nlh = nlmsg_put(skb, portid, seq, event, sizeof(*pmsg), flags); - if (!nlh) - return -EMSGSIZE; - - pmsg = nlmsg_data(nlh); - pmsg->prefix_family = AF_INET6; - pmsg->prefix_pad1 = 0; - pmsg->prefix_pad2 = 0; - pmsg->prefix_ifindex = idev->dev->ifindex; - pmsg->prefix_len = pinfo->prefix_len; - pmsg->prefix_type = pinfo->type; - pmsg->prefix_pad3 = 0; - pmsg->prefix_flags = 0; - if (pinfo->onlink) - pmsg->prefix_flags |= IF_PREFIX_ONLINK; - if (pinfo->autoconf) - pmsg->prefix_flags |= IF_PREFIX_AUTOCONF; - - if (nla_put(skb, PREFIX_ADDRESS, sizeof(pinfo->prefix), &pinfo->prefix)) - goto nla_put_failure; - ci.preferred_time = ntohl(pinfo->prefered); - ci.valid_time = ntohl(pinfo->valid); - if (nla_put(skb, PREFIX_CACHEINFO, sizeof(ci), &ci)) - goto nla_put_failure; - nlmsg_end(skb, nlh); - return 0; - -nla_put_failure: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -static void inet6_prefix_notify(int event, struct inet6_dev *idev, - struct prefix_info *pinfo) -{ - struct sk_buff *skb; - struct net *net = dev_net(idev->dev); - int err = -ENOBUFS; - - skb = nlmsg_new(inet6_prefix_nlmsg_size(), GFP_ATOMIC); - if (!skb) - goto errout; - - err = inet6_fill_prefix(skb, idev, pinfo, 0, 0, event, 0); - if (err < 0) { - /* -EMSGSIZE implies BUG in inet6_prefix_nlmsg_size() */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - goto errout; - } - rtnl_notify(skb, net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC); - return; -errout: - if (err < 0) - rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err); -} - -static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) -{ - struct net *net = dev_net(ifp->idev->dev); - - if (event) - ASSERT_RTNL(); - - inet6_ifa_notify(event ? : RTM_NEWADDR, ifp); - - switch (event) { - case RTM_NEWADDR: - /* - * If the address was optimistic - * we inserted the route at the start of - * our DAD process, so we don't need - * to do it again - */ - if (!(ifp->rt->rt6i_node)) - ip6_ins_rt(ifp->rt); - if (ifp->idev->cnf.forwarding) - addrconf_join_anycast(ifp); - if (!ipv6_addr_any(&ifp->peer_addr)) - addrconf_prefix_route(&ifp->peer_addr, 128, - ifp->idev->dev, 0, 0); - break; - case RTM_DELADDR: - if (ifp->idev->cnf.forwarding) - addrconf_leave_anycast(ifp); - addrconf_leave_solict(ifp->idev, &ifp->addr); - if (!ipv6_addr_any(&ifp->peer_addr)) { - struct rt6_info *rt; - - rt = addrconf_get_prefix_route(&ifp->peer_addr, 128, - ifp->idev->dev, 0, 0); - if (rt) - ip6_del_rt(rt); - } - if (ifp->rt) { - dst_hold(&ifp->rt->dst); - ip6_del_rt(ifp->rt); - } - rt_genid_bump_ipv6(net); - break; - } - atomic_inc(&net->ipv6.dev_addr_genid); -} - -static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp) -{ - rcu_read_lock_bh(); - if (likely(ifp->idev->dead == 0)) - __ipv6_ifa_notify(event, ifp); - rcu_read_unlock_bh(); -} - -#ifdef CONFIG_SYSCTL - -static -int addrconf_sysctl_forward(struct ctl_table *ctl, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - int *valp = ctl->data; - int val = *valp; - loff_t pos = *ppos; - struct ctl_table lctl; - int ret; - - /* - * ctl->data points to idev->cnf.forwarding, we should - * not modify it until we get the rtnl lock. - */ - lctl = *ctl; - lctl.data = &val; - - ret = proc_dointvec(&lctl, write, buffer, lenp, ppos); - - if (write) - ret = addrconf_fixup_forwarding(ctl, valp, val); - if (ret) - *ppos = pos; - return ret; -} - -static -int addrconf_sysctl_mtu(struct ctl_table *ctl, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - struct inet6_dev *idev = ctl->extra1; - int min_mtu = IPV6_MIN_MTU; - struct ctl_table lctl; - - lctl = *ctl; - lctl.extra1 = &min_mtu; - lctl.extra2 = idev ? &idev->dev->mtu : NULL; - - return proc_dointvec_minmax(&lctl, write, buffer, lenp, ppos); -} - -static void dev_disable_change(struct inet6_dev *idev) -{ - struct netdev_notifier_info info; - - if (!idev || !idev->dev) - return; - - netdev_notifier_info_init(&info, idev->dev); - if (idev->cnf.disable_ipv6) - addrconf_notify(NULL, NETDEV_DOWN, &info); - else - addrconf_notify(NULL, NETDEV_UP, &info); -} - -static void addrconf_disable_change(struct net *net, __s32 newf) -{ - struct net_device *dev; - struct inet6_dev *idev; - - rcu_read_lock(); - for_each_netdev_rcu(net, dev) { - idev = __in6_dev_get(dev); - if (idev) { - int changed = (!idev->cnf.disable_ipv6) ^ (!newf); - idev->cnf.disable_ipv6 = newf; - if (changed) - dev_disable_change(idev); - } - } - rcu_read_unlock(); -} - -static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int newf) -{ - struct net *net; - int old; - - if (!rtnl_trylock()) - return restart_syscall(); - - net = (struct net *)table->extra2; - old = *p; - *p = newf; - - if (p == &net->ipv6.devconf_dflt->disable_ipv6) { - rtnl_unlock(); - return 0; - } - - if (p == &net->ipv6.devconf_all->disable_ipv6) { - net->ipv6.devconf_dflt->disable_ipv6 = newf; - addrconf_disable_change(net, newf); - } else if ((!newf) ^ (!old)) - dev_disable_change((struct inet6_dev *)table->extra1); - - rtnl_unlock(); - return 0; -} - -static -int addrconf_sysctl_disable(struct ctl_table *ctl, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - int *valp = ctl->data; - int val = *valp; - loff_t pos = *ppos; - struct ctl_table lctl; - int ret; - - /* - * ctl->data points to idev->cnf.disable_ipv6, we should - * not modify it until we get the rtnl lock. - */ - lctl = *ctl; - lctl.data = &val; - - ret = proc_dointvec(&lctl, write, buffer, lenp, ppos); - - if (write) - ret = addrconf_disable_ipv6(ctl, valp, val); - if (ret) - *ppos = pos; - return ret; -} - -static -int addrconf_sysctl_proxy_ndp(struct ctl_table *ctl, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - int *valp = ctl->data; - int ret; - int old, new; - - old = *valp; - ret = proc_dointvec(ctl, write, buffer, lenp, ppos); - new = *valp; - - if (write && old != new) { - struct net *net = ctl->extra2; - - if (!rtnl_trylock()) - return restart_syscall(); - - if (valp == &net->ipv6.devconf_dflt->proxy_ndp) - inet6_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH, - NETCONFA_IFINDEX_DEFAULT, - net->ipv6.devconf_dflt); - else if (valp == &net->ipv6.devconf_all->proxy_ndp) - inet6_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH, - NETCONFA_IFINDEX_ALL, - net->ipv6.devconf_all); - else { - struct inet6_dev *idev = ctl->extra1; - - inet6_netconf_notify_devconf(net, NETCONFA_PROXY_NEIGH, - idev->dev->ifindex, - &idev->cnf); - } - rtnl_unlock(); - } - - return ret; -} - -static int addrconf_sysctl_stable_secret(struct ctl_table *ctl, int write, - void __user *buffer, size_t *lenp, - loff_t *ppos) -{ - int err; - struct in6_addr addr; - char str[IPV6_MAX_STRLEN]; - struct ctl_table lctl = *ctl; - struct net *net = ctl->extra2; - struct ipv6_stable_secret *secret = ctl->data; - - if (&net->ipv6.devconf_all->stable_secret == ctl->data) - return -EIO; - - lctl.maxlen = IPV6_MAX_STRLEN; - lctl.data = str; - - if (!rtnl_trylock()) - return restart_syscall(); - - if (!write && !secret->initialized) { - err = -EIO; - goto out; - } - - err = snprintf(str, sizeof(str), "%pI6", &secret->secret); - if (err >= sizeof(str)) { - err = -EIO; - goto out; - } - - err = proc_dostring(&lctl, write, buffer, lenp, ppos); - if (err || !write) - goto out; - - if (in6_pton(str, -1, addr.in6_u.u6_addr8, -1, NULL) != 1) { - err = -EIO; - goto out; - } - - secret->initialized = true; - secret->secret = addr; - - if (&net->ipv6.devconf_dflt->stable_secret == ctl->data) { - struct net_device *dev; - - for_each_netdev(net, dev) { - struct inet6_dev *idev = __in6_dev_get(dev); - - if (idev) { - idev->addr_gen_mode = - IN6_ADDR_GEN_MODE_STABLE_PRIVACY; - } - } - } else { - struct inet6_dev *idev = ctl->extra1; - - idev->addr_gen_mode = IN6_ADDR_GEN_MODE_STABLE_PRIVACY; - } - -out: - rtnl_unlock(); - - return err; -} - -static -int addrconf_sysctl_ignore_routes_with_linkdown(struct ctl_table *ctl, - int write, - void __user *buffer, - size_t *lenp, - loff_t *ppos) -{ - int *valp = ctl->data; - int val = *valp; - loff_t pos = *ppos; - struct ctl_table lctl; - int ret; - - /* ctl->data points to idev->cnf.ignore_routes_when_linkdown - * we should not modify it until we get the rtnl lock. - */ - lctl = *ctl; - lctl.data = &val; - - ret = proc_dointvec(&lctl, write, buffer, lenp, ppos); - - if (write) - ret = addrconf_fixup_linkdown(ctl, valp, val); - if (ret) - *ppos = pos; - return ret; -} - -static int minus_one = -1; -static const int one = 1; -static const int two_five_five = 255; - -static const struct ctl_table addrconf_sysctl[] = { - { - .procname = "forwarding", - .data = &ipv6_devconf.forwarding, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = addrconf_sysctl_forward, - }, - { - .procname = "hop_limit", - .data = &ipv6_devconf.hop_limit, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = (void *)&one, - .extra2 = (void *)&two_five_five, - }, - { - .procname = "mtu", - .data = &ipv6_devconf.mtu6, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = addrconf_sysctl_mtu, - }, - { - .procname = "accept_ra", - .data = &ipv6_devconf.accept_ra, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "accept_redirects", - .data = &ipv6_devconf.accept_redirects, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "autoconf", - .data = &ipv6_devconf.autoconf, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "dad_transmits", - .data = &ipv6_devconf.dad_transmits, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "router_solicitations", - .data = &ipv6_devconf.rtr_solicits, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &minus_one, - }, - { - .procname = "router_solicitation_interval", - .data = &ipv6_devconf.rtr_solicit_interval, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "router_solicitation_max_interval", - .data = &ipv6_devconf.rtr_solicit_max_interval, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "router_solicitation_delay", - .data = &ipv6_devconf.rtr_solicit_delay, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "force_mld_version", - .data = &ipv6_devconf.force_mld_version, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "mldv1_unsolicited_report_interval", - .data = - &ipv6_devconf.mldv1_unsolicited_report_interval, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_ms_jiffies, - }, - { - .procname = "mldv2_unsolicited_report_interval", - .data = - &ipv6_devconf.mldv2_unsolicited_report_interval, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_ms_jiffies, - }, - { - .procname = "use_tempaddr", - .data = &ipv6_devconf.use_tempaddr, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "temp_valid_lft", - .data = &ipv6_devconf.temp_valid_lft, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "temp_prefered_lft", - .data = &ipv6_devconf.temp_prefered_lft, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "regen_max_retry", - .data = &ipv6_devconf.regen_max_retry, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "max_desync_factor", - .data = &ipv6_devconf.max_desync_factor, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "max_addresses", - .data = &ipv6_devconf.max_addresses, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "accept_ra_defrtr", - .data = &ipv6_devconf.accept_ra_defrtr, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "accept_ra_min_hop_limit", - .data = &ipv6_devconf.accept_ra_min_hop_limit, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "accept_ra_pinfo", - .data = &ipv6_devconf.accept_ra_pinfo, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#ifdef CONFIG_IPV6_ROUTER_PREF - { - .procname = "accept_ra_rtr_pref", - .data = &ipv6_devconf.accept_ra_rtr_pref, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "router_probe_interval", - .data = &ipv6_devconf.rtr_probe_interval, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, -#ifdef CONFIG_IPV6_ROUTE_INFO - { - .procname = "accept_ra_rt_info_max_plen", - .data = &ipv6_devconf.accept_ra_rt_info_max_plen, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif -#endif - { - .procname = "proxy_ndp", - .data = &ipv6_devconf.proxy_ndp, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = addrconf_sysctl_proxy_ndp, - }, - { - .procname = "accept_source_route", - .data = &ipv6_devconf.accept_source_route, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#ifdef CONFIG_IPV6_OPTIMISTIC_DAD - { - .procname = "optimistic_dad", - .data = &ipv6_devconf.optimistic_dad, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "use_optimistic", - .data = &ipv6_devconf.use_optimistic, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif -#ifdef CONFIG_IPV6_MROUTE - { - .procname = "mc_forwarding", - .data = &ipv6_devconf.mc_forwarding, - .maxlen = sizeof(int), - .mode = 0444, - .proc_handler = proc_dointvec, - }, -#endif - { - .procname = "disable_ipv6", - .data = &ipv6_devconf.disable_ipv6, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = addrconf_sysctl_disable, - }, - { - .procname = "accept_dad", - .data = &ipv6_devconf.accept_dad, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "force_tllao", - .data = &ipv6_devconf.force_tllao, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "ndisc_notify", - .data = &ipv6_devconf.ndisc_notify, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "suppress_frag_ndisc", - .data = &ipv6_devconf.suppress_frag_ndisc, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "accept_ra_from_local", - .data = &ipv6_devconf.accept_ra_from_local, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "accept_ra_mtu", - .data = &ipv6_devconf.accept_ra_mtu, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "stable_secret", - .data = &ipv6_devconf.stable_secret, - .maxlen = IPV6_MAX_STRLEN, - .mode = 0600, - .proc_handler = addrconf_sysctl_stable_secret, - }, - { - .procname = "use_oif_addrs_only", - .data = &ipv6_devconf.use_oif_addrs_only, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "ignore_routes_with_linkdown", - .data = &ipv6_devconf.ignore_routes_with_linkdown, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = addrconf_sysctl_ignore_routes_with_linkdown, - }, - { - .procname = "drop_unicast_in_l2_multicast", - .data = &ipv6_devconf.drop_unicast_in_l2_multicast, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "drop_unsolicited_na", - .data = &ipv6_devconf.drop_unsolicited_na, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "keep_addr_on_down", - .data = &ipv6_devconf.keep_addr_on_down, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - - }, - { - /* sentinel */ - } -}; - -static int __addrconf_sysctl_register(struct net *net, char *dev_name, - struct inet6_dev *idev, struct ipv6_devconf *p) -{ - int i, ifindex; - struct ctl_table *table; - char path[sizeof("net/ipv6/conf/") + IFNAMSIZ]; - - table = kmemdup(addrconf_sysctl, sizeof(addrconf_sysctl), GFP_KERNEL); - if (!table) - goto out; - - for (i = 0; table[i].data; i++) { - table[i].data += (char *)p - (char *)&ipv6_devconf; - /* If one of these is already set, then it is not safe to - * overwrite either of them: this makes proc_dointvec_minmax - * usable. - */ - if (!table[i].extra1 && !table[i].extra2) { - table[i].extra1 = idev; /* embedded; no ref */ - table[i].extra2 = net; - } - } - - snprintf(path, sizeof(path), "net/ipv6/conf/%s", dev_name); - - p->sysctl_header = register_net_sysctl(net, path, table); - if (!p->sysctl_header) - goto free; - - if (!strcmp(dev_name, "all")) - ifindex = NETCONFA_IFINDEX_ALL; - else if (!strcmp(dev_name, "default")) - ifindex = NETCONFA_IFINDEX_DEFAULT; - else - ifindex = idev->dev->ifindex; - inet6_netconf_notify_devconf(net, NETCONFA_ALL, ifindex, p); - return 0; - -free: - kfree(table); -out: - return -ENOBUFS; -} - -static void __addrconf_sysctl_unregister(struct ipv6_devconf *p) -{ - struct ctl_table *table; - - if (!p->sysctl_header) - return; - - table = p->sysctl_header->ctl_table_arg; - unregister_net_sysctl_table(p->sysctl_header); - p->sysctl_header = NULL; - kfree(table); -} - -static int addrconf_sysctl_register(struct inet6_dev *idev) -{ - int err; - - if (!sysctl_dev_name_is_allowed(idev->dev->name)) - return -EINVAL; - - err = neigh_sysctl_register(idev->dev, idev->nd_parms, - &ndisc_ifinfo_sysctl_change); - if (err) - return err; - err = __addrconf_sysctl_register(dev_net(idev->dev), idev->dev->name, - idev, &idev->cnf); - if (err) - neigh_sysctl_unregister(idev->nd_parms); - - return err; -} - -static void addrconf_sysctl_unregister(struct inet6_dev *idev) -{ - __addrconf_sysctl_unregister(&idev->cnf); - neigh_sysctl_unregister(idev->nd_parms); -} - - -#endif - -static int __net_init addrconf_init_net(struct net *net) -{ - int err = -ENOMEM; - struct ipv6_devconf *all, *dflt; - - all = kmemdup(&ipv6_devconf, sizeof(ipv6_devconf), GFP_KERNEL); - if (!all) - goto err_alloc_all; - - dflt = kmemdup(&ipv6_devconf_dflt, sizeof(ipv6_devconf_dflt), GFP_KERNEL); - if (!dflt) - goto err_alloc_dflt; - - /* these will be inherited by all namespaces */ - dflt->autoconf = ipv6_defaults.autoconf; - dflt->disable_ipv6 = ipv6_defaults.disable_ipv6; - - dflt->stable_secret.initialized = false; - all->stable_secret.initialized = false; - - net->ipv6.devconf_all = all; - net->ipv6.devconf_dflt = dflt; - -#ifdef CONFIG_SYSCTL - err = __addrconf_sysctl_register(net, "all", NULL, all); - if (err < 0) - goto err_reg_all; - - err = __addrconf_sysctl_register(net, "default", NULL, dflt); - if (err < 0) - goto err_reg_dflt; -#endif - return 0; - -#ifdef CONFIG_SYSCTL -err_reg_dflt: - __addrconf_sysctl_unregister(all); -err_reg_all: - kfree(dflt); -#endif -err_alloc_dflt: - kfree(all); -err_alloc_all: - return err; -} - -static void __net_exit addrconf_exit_net(struct net *net) -{ -#ifdef CONFIG_SYSCTL - __addrconf_sysctl_unregister(net->ipv6.devconf_dflt); - __addrconf_sysctl_unregister(net->ipv6.devconf_all); -#endif - kfree(net->ipv6.devconf_dflt); - kfree(net->ipv6.devconf_all); -} - -static struct pernet_operations addrconf_ops = { - .init = addrconf_init_net, - .exit = addrconf_exit_net, -}; - -static struct rtnl_af_ops inet6_ops __read_mostly = { - .family = AF_INET6, - .fill_link_af = inet6_fill_link_af, - .get_link_af_size = inet6_get_link_af_size, - .validate_link_af = inet6_validate_link_af, - .set_link_af = inet6_set_link_af, -}; - -/* - * Init / cleanup code - */ - -int __init addrconf_init(void) -{ - struct inet6_dev *idev; - int i, err; - - err = ipv6_addr_label_init(); - if (err < 0) { - pr_crit("%s: cannot initialize default policy table: %d\n", - __func__, err); - goto out; - } - - err = register_pernet_subsys(&addrconf_ops); - if (err < 0) - goto out_addrlabel; - - addrconf_wq = create_workqueue("ipv6_addrconf"); - if (!addrconf_wq) { - err = -ENOMEM; - goto out_nowq; - } - - /* The addrconf netdev notifier requires that loopback_dev - * has it's ipv6 private information allocated and setup - * before it can bring up and give link-local addresses - * to other devices which are up. - * - * Unfortunately, loopback_dev is not necessarily the first - * entry in the global dev_base list of net devices. In fact, - * it is likely to be the very last entry on that list. - * So this causes the notifier registry below to try and - * give link-local addresses to all devices besides loopback_dev - * first, then loopback_dev, which cases all the non-loopback_dev - * devices to fail to get a link-local address. - * - * So, as a temporary fix, allocate the ipv6 structure for - * loopback_dev first by hand. - * Longer term, all of the dependencies ipv6 has upon the loopback - * device and it being up should be removed. - */ - rtnl_lock(); - idev = ipv6_add_dev(init_net.loopback_dev); - rtnl_unlock(); - if (IS_ERR(idev)) { - err = PTR_ERR(idev); - goto errlo; - } - - for (i = 0; i < IN6_ADDR_HSIZE; i++) - INIT_HLIST_HEAD(&inet6_addr_lst[i]); - - register_netdevice_notifier(&ipv6_dev_notf); - - addrconf_verify(); - - rtnl_af_register(&inet6_ops); - - err = __rtnl_register(PF_INET6, RTM_GETLINK, NULL, inet6_dump_ifinfo, - NULL); - if (err < 0) - goto errout; - - /* Only the first call to __rtnl_register can fail */ - __rtnl_register(PF_INET6, RTM_NEWADDR, inet6_rtm_newaddr, NULL, NULL); - __rtnl_register(PF_INET6, RTM_DELADDR, inet6_rtm_deladdr, NULL, NULL); - __rtnl_register(PF_INET6, RTM_GETADDR, inet6_rtm_getaddr, - inet6_dump_ifaddr, NULL); - __rtnl_register(PF_INET6, RTM_GETMULTICAST, NULL, - inet6_dump_ifmcaddr, NULL); - __rtnl_register(PF_INET6, RTM_GETANYCAST, NULL, - inet6_dump_ifacaddr, NULL); - __rtnl_register(PF_INET6, RTM_GETNETCONF, inet6_netconf_get_devconf, - inet6_netconf_dump_devconf, NULL); - - ipv6_addr_label_rtnl_register(); - - return 0; -errout: - rtnl_af_unregister(&inet6_ops); - unregister_netdevice_notifier(&ipv6_dev_notf); -errlo: - destroy_workqueue(addrconf_wq); -out_nowq: - unregister_pernet_subsys(&addrconf_ops); -out_addrlabel: - ipv6_addr_label_cleanup(); -out: - return err; -} - -void addrconf_cleanup(void) -{ - struct net_device *dev; - int i; - - unregister_netdevice_notifier(&ipv6_dev_notf); - unregister_pernet_subsys(&addrconf_ops); - ipv6_addr_label_cleanup(); - - rtnl_lock(); - - __rtnl_af_unregister(&inet6_ops); - - /* clean dev list */ - for_each_netdev(&init_net, dev) { - if (__in6_dev_get(dev) == NULL) - continue; - addrconf_ifdown(dev, 1); - } - addrconf_ifdown(init_net.loopback_dev, 2); - - /* - * Check hash table. - */ - spin_lock_bh(&addrconf_hash_lock); - for (i = 0; i < IN6_ADDR_HSIZE; i++) - WARN_ON(!hlist_empty(&inet6_addr_lst[i])); - spin_unlock_bh(&addrconf_hash_lock); - cancel_delayed_work(&addr_chk_work); - rtnl_unlock(); - - destroy_workqueue(addrconf_wq); -} diff --git a/src/linux/net/ipv6/addrconf_core.c b/src/linux/net/ipv6/addrconf_core.c deleted file mode 100644 index bfa941f..0000000 --- a/src/linux/net/ipv6/addrconf_core.c +++ /dev/null @@ -1,173 +0,0 @@ -/* - * IPv6 library code, needed by static components when full IPv6 support is - * not configured or static. - */ - -#include -#include -#include -#include - -/* if ipv6 module registers this function is used by xfrm to force all - * sockets to relookup their nodes - this is fairly expensive, be - * careful - */ -void (*__fib6_flush_trees)(struct net *); -EXPORT_SYMBOL(__fib6_flush_trees); - -#define IPV6_ADDR_SCOPE_TYPE(scope) ((scope) << 16) - -static inline unsigned int ipv6_addr_scope2type(unsigned int scope) -{ - switch (scope) { - case IPV6_ADDR_SCOPE_NODELOCAL: - return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_NODELOCAL) | - IPV6_ADDR_LOOPBACK); - case IPV6_ADDR_SCOPE_LINKLOCAL: - return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL) | - IPV6_ADDR_LINKLOCAL); - case IPV6_ADDR_SCOPE_SITELOCAL: - return (IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL) | - IPV6_ADDR_SITELOCAL); - } - return IPV6_ADDR_SCOPE_TYPE(scope); -} - -int __ipv6_addr_type(const struct in6_addr *addr) -{ - __be32 st; - - st = addr->s6_addr32[0]; - - /* Consider all addresses with the first three bits different of - 000 and 111 as unicasts. - */ - if ((st & htonl(0xE0000000)) != htonl(0x00000000) && - (st & htonl(0xE0000000)) != htonl(0xE0000000)) - return (IPV6_ADDR_UNICAST | - IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); - - if ((st & htonl(0xFF000000)) == htonl(0xFF000000)) { - /* multicast */ - /* addr-select 3.1 */ - return (IPV6_ADDR_MULTICAST | - ipv6_addr_scope2type(IPV6_ADDR_MC_SCOPE(addr))); - } - - if ((st & htonl(0xFFC00000)) == htonl(0xFE800000)) - return (IPV6_ADDR_LINKLOCAL | IPV6_ADDR_UNICAST | - IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL)); /* addr-select 3.1 */ - if ((st & htonl(0xFFC00000)) == htonl(0xFEC00000)) - return (IPV6_ADDR_SITELOCAL | IPV6_ADDR_UNICAST | - IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_SITELOCAL)); /* addr-select 3.1 */ - if ((st & htonl(0xFE000000)) == htonl(0xFC000000)) - return (IPV6_ADDR_UNICAST | - IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* RFC 4193 */ - - if ((addr->s6_addr32[0] | addr->s6_addr32[1]) == 0) { - if (addr->s6_addr32[2] == 0) { - if (addr->s6_addr32[3] == 0) - return IPV6_ADDR_ANY; - - if (addr->s6_addr32[3] == htonl(0x00000001)) - return (IPV6_ADDR_LOOPBACK | IPV6_ADDR_UNICAST | - IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_LINKLOCAL)); /* addr-select 3.4 */ - - return (IPV6_ADDR_COMPATv4 | IPV6_ADDR_UNICAST | - IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */ - } - - if (addr->s6_addr32[2] == htonl(0x0000ffff)) - return (IPV6_ADDR_MAPPED | - IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.3 */ - } - - return (IPV6_ADDR_UNICAST | - IPV6_ADDR_SCOPE_TYPE(IPV6_ADDR_SCOPE_GLOBAL)); /* addr-select 3.4 */ -} -EXPORT_SYMBOL(__ipv6_addr_type); - -static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); - -int register_inet6addr_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&inet6addr_chain, nb); -} -EXPORT_SYMBOL(register_inet6addr_notifier); - -int unregister_inet6addr_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&inet6addr_chain, nb); -} -EXPORT_SYMBOL(unregister_inet6addr_notifier); - -int inet6addr_notifier_call_chain(unsigned long val, void *v) -{ - return atomic_notifier_call_chain(&inet6addr_chain, val, v); -} -EXPORT_SYMBOL(inet6addr_notifier_call_chain); - -static int eafnosupport_ipv6_dst_lookup(struct net *net, struct sock *u1, - struct dst_entry **u2, - struct flowi6 *u3) -{ - return -EAFNOSUPPORT; -} - -const struct ipv6_stub *ipv6_stub __read_mostly = &(struct ipv6_stub) { - .ipv6_dst_lookup = eafnosupport_ipv6_dst_lookup, -}; -EXPORT_SYMBOL_GPL(ipv6_stub); - -/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ -const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; -EXPORT_SYMBOL(in6addr_loopback); -const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; -EXPORT_SYMBOL(in6addr_any); -const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT; -EXPORT_SYMBOL(in6addr_linklocal_allnodes); -const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; -EXPORT_SYMBOL(in6addr_linklocal_allrouters); -const struct in6_addr in6addr_interfacelocal_allnodes = IN6ADDR_INTERFACELOCAL_ALLNODES_INIT; -EXPORT_SYMBOL(in6addr_interfacelocal_allnodes); -const struct in6_addr in6addr_interfacelocal_allrouters = IN6ADDR_INTERFACELOCAL_ALLROUTERS_INIT; -EXPORT_SYMBOL(in6addr_interfacelocal_allrouters); -const struct in6_addr in6addr_sitelocal_allrouters = IN6ADDR_SITELOCAL_ALLROUTERS_INIT; -EXPORT_SYMBOL(in6addr_sitelocal_allrouters); - -static void snmp6_free_dev(struct inet6_dev *idev) -{ - kfree(idev->stats.icmpv6msgdev); - kfree(idev->stats.icmpv6dev); - free_percpu(idev->stats.ipv6); -} - -static void in6_dev_finish_destroy_rcu(struct rcu_head *head) -{ - struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu); - - snmp6_free_dev(idev); - kfree(idev); -} - -/* Nobody refers to this device, we may destroy it. */ - -void in6_dev_finish_destroy(struct inet6_dev *idev) -{ - struct net_device *dev = idev->dev; - - WARN_ON(!list_empty(&idev->addr_list)); - WARN_ON(idev->mc_list); - WARN_ON(timer_pending(&idev->rs_timer)); - -#ifdef NET_REFCNT_DEBUG - pr_debug("%s: %s\n", __func__, dev ? dev->name : "NIL"); -#endif - dev_put(dev); - if (!idev->dead) { - pr_warn("Freeing alive inet6 device %p\n", idev); - return; - } - call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu); -} -EXPORT_SYMBOL(in6_dev_finish_destroy); diff --git a/src/linux/net/ipv6/addrlabel.c b/src/linux/net/ipv6/addrlabel.c deleted file mode 100644 index a8f6986..0000000 --- a/src/linux/net/ipv6/addrlabel.c +++ /dev/null @@ -1,597 +0,0 @@ -/* - * IPv6 Address Label subsystem - * for the IPv6 "Default" Source Address Selection - * - * Copyright (C)2007 USAGI/WIDE Project - */ -/* - * Author: - * YOSHIFUJI Hideaki @ USAGI/WIDE Project - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if 0 -#define ADDRLABEL(x...) printk(x) -#else -#define ADDRLABEL(x...) do { ; } while (0) -#endif - -/* - * Policy Table - */ -struct ip6addrlbl_entry { - possible_net_t lbl_net; - struct in6_addr prefix; - int prefixlen; - int ifindex; - int addrtype; - u32 label; - struct hlist_node list; - atomic_t refcnt; - struct rcu_head rcu; -}; - -static struct ip6addrlbl_table -{ - struct hlist_head head; - spinlock_t lock; - u32 seq; -} ip6addrlbl_table; - -static inline -struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl) -{ - return read_pnet(&lbl->lbl_net); -} - -/* - * Default policy table (RFC6724 + extensions) - * - * prefix addr_type label - * ------------------------------------------------------------------------- - * ::1/128 LOOPBACK 0 - * ::/0 N/A 1 - * 2002::/16 N/A 2 - * ::/96 COMPATv4 3 - * ::ffff:0:0/96 V4MAPPED 4 - * fc00::/7 N/A 5 ULA (RFC 4193) - * 2001::/32 N/A 6 Teredo (RFC 4380) - * 2001:10::/28 N/A 7 ORCHID (RFC 4843) - * fec0::/10 N/A 11 Site-local - * (deprecated by RFC3879) - * 3ffe::/16 N/A 12 6bone - * - * Note: 0xffffffff is used if we do not have any policies. - * Note: Labels for ULA and 6to4 are different from labels listed in RFC6724. - */ - -#define IPV6_ADDR_LABEL_DEFAULT 0xffffffffUL - -static const __net_initconst struct ip6addrlbl_init_table -{ - const struct in6_addr *prefix; - int prefixlen; - u32 label; -} ip6addrlbl_init_table[] = { - { /* ::/0 */ - .prefix = &in6addr_any, - .label = 1, - }, { /* fc00::/7 */ - .prefix = &(struct in6_addr){ { { 0xfc } } } , - .prefixlen = 7, - .label = 5, - }, { /* fec0::/10 */ - .prefix = &(struct in6_addr){ { { 0xfe, 0xc0 } } }, - .prefixlen = 10, - .label = 11, - }, { /* 2002::/16 */ - .prefix = &(struct in6_addr){ { { 0x20, 0x02 } } }, - .prefixlen = 16, - .label = 2, - }, { /* 3ffe::/16 */ - .prefix = &(struct in6_addr){ { { 0x3f, 0xfe } } }, - .prefixlen = 16, - .label = 12, - }, { /* 2001::/32 */ - .prefix = &(struct in6_addr){ { { 0x20, 0x01 } } }, - .prefixlen = 32, - .label = 6, - }, { /* 2001:10::/28 */ - .prefix = &(struct in6_addr){ { { 0x20, 0x01, 0x00, 0x10 } } }, - .prefixlen = 28, - .label = 7, - }, { /* ::ffff:0:0 */ - .prefix = &(struct in6_addr){ { { [10] = 0xff, [11] = 0xff } } }, - .prefixlen = 96, - .label = 4, - }, { /* ::/96 */ - .prefix = &in6addr_any, - .prefixlen = 96, - .label = 3, - }, { /* ::1/128 */ - .prefix = &in6addr_loopback, - .prefixlen = 128, - .label = 0, - } -}; - -/* Object management */ -static inline void ip6addrlbl_free(struct ip6addrlbl_entry *p) -{ - kfree(p); -} - -static void ip6addrlbl_free_rcu(struct rcu_head *h) -{ - ip6addrlbl_free(container_of(h, struct ip6addrlbl_entry, rcu)); -} - -static bool ip6addrlbl_hold(struct ip6addrlbl_entry *p) -{ - return atomic_inc_not_zero(&p->refcnt); -} - -static inline void ip6addrlbl_put(struct ip6addrlbl_entry *p) -{ - if (atomic_dec_and_test(&p->refcnt)) - call_rcu(&p->rcu, ip6addrlbl_free_rcu); -} - -/* Find label */ -static bool __ip6addrlbl_match(struct net *net, - const struct ip6addrlbl_entry *p, - const struct in6_addr *addr, - int addrtype, int ifindex) -{ - if (!net_eq(ip6addrlbl_net(p), net)) - return false; - if (p->ifindex && p->ifindex != ifindex) - return false; - if (p->addrtype && p->addrtype != addrtype) - return false; - if (!ipv6_prefix_equal(addr, &p->prefix, p->prefixlen)) - return false; - return true; -} - -static struct ip6addrlbl_entry *__ipv6_addr_label(struct net *net, - const struct in6_addr *addr, - int type, int ifindex) -{ - struct ip6addrlbl_entry *p; - hlist_for_each_entry_rcu(p, &ip6addrlbl_table.head, list) { - if (__ip6addrlbl_match(net, p, addr, type, ifindex)) - return p; - } - return NULL; -} - -u32 ipv6_addr_label(struct net *net, - const struct in6_addr *addr, int type, int ifindex) -{ - u32 label; - struct ip6addrlbl_entry *p; - - type &= IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK; - - rcu_read_lock(); - p = __ipv6_addr_label(net, addr, type, ifindex); - label = p ? p->label : IPV6_ADDR_LABEL_DEFAULT; - rcu_read_unlock(); - - ADDRLABEL(KERN_DEBUG "%s(addr=%pI6, type=%d, ifindex=%d) => %08x\n", - __func__, addr, type, ifindex, label); - - return label; -} - -/* allocate one entry */ -static struct ip6addrlbl_entry *ip6addrlbl_alloc(struct net *net, - const struct in6_addr *prefix, - int prefixlen, int ifindex, - u32 label) -{ - struct ip6addrlbl_entry *newp; - int addrtype; - - ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d, label=%u)\n", - __func__, prefix, prefixlen, ifindex, (unsigned int)label); - - addrtype = ipv6_addr_type(prefix) & (IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK); - - switch (addrtype) { - case IPV6_ADDR_MAPPED: - if (prefixlen > 96) - return ERR_PTR(-EINVAL); - if (prefixlen < 96) - addrtype = 0; - break; - case IPV6_ADDR_COMPATv4: - if (prefixlen != 96) - addrtype = 0; - break; - case IPV6_ADDR_LOOPBACK: - if (prefixlen != 128) - addrtype = 0; - break; - } - - newp = kmalloc(sizeof(*newp), GFP_KERNEL); - if (!newp) - return ERR_PTR(-ENOMEM); - - ipv6_addr_prefix(&newp->prefix, prefix, prefixlen); - newp->prefixlen = prefixlen; - newp->ifindex = ifindex; - newp->addrtype = addrtype; - newp->label = label; - INIT_HLIST_NODE(&newp->list); - write_pnet(&newp->lbl_net, net); - atomic_set(&newp->refcnt, 1); - return newp; -} - -/* add a label */ -static int __ip6addrlbl_add(struct ip6addrlbl_entry *newp, int replace) -{ - struct hlist_node *n; - struct ip6addrlbl_entry *last = NULL, *p = NULL; - int ret = 0; - - ADDRLABEL(KERN_DEBUG "%s(newp=%p, replace=%d)\n", __func__, newp, - replace); - - hlist_for_each_entry_safe(p, n, &ip6addrlbl_table.head, list) { - if (p->prefixlen == newp->prefixlen && - net_eq(ip6addrlbl_net(p), ip6addrlbl_net(newp)) && - p->ifindex == newp->ifindex && - ipv6_addr_equal(&p->prefix, &newp->prefix)) { - if (!replace) { - ret = -EEXIST; - goto out; - } - hlist_replace_rcu(&p->list, &newp->list); - ip6addrlbl_put(p); - goto out; - } else if ((p->prefixlen == newp->prefixlen && !p->ifindex) || - (p->prefixlen < newp->prefixlen)) { - hlist_add_before_rcu(&newp->list, &p->list); - goto out; - } - last = p; - } - if (last) - hlist_add_behind_rcu(&newp->list, &last->list); - else - hlist_add_head_rcu(&newp->list, &ip6addrlbl_table.head); -out: - if (!ret) - ip6addrlbl_table.seq++; - return ret; -} - -/* add a label */ -static int ip6addrlbl_add(struct net *net, - const struct in6_addr *prefix, int prefixlen, - int ifindex, u32 label, int replace) -{ - struct ip6addrlbl_entry *newp; - int ret = 0; - - ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d, label=%u, replace=%d)\n", - __func__, prefix, prefixlen, ifindex, (unsigned int)label, - replace); - - newp = ip6addrlbl_alloc(net, prefix, prefixlen, ifindex, label); - if (IS_ERR(newp)) - return PTR_ERR(newp); - spin_lock(&ip6addrlbl_table.lock); - ret = __ip6addrlbl_add(newp, replace); - spin_unlock(&ip6addrlbl_table.lock); - if (ret) - ip6addrlbl_free(newp); - return ret; -} - -/* remove a label */ -static int __ip6addrlbl_del(struct net *net, - const struct in6_addr *prefix, int prefixlen, - int ifindex) -{ - struct ip6addrlbl_entry *p = NULL; - struct hlist_node *n; - int ret = -ESRCH; - - ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)\n", - __func__, prefix, prefixlen, ifindex); - - hlist_for_each_entry_safe(p, n, &ip6addrlbl_table.head, list) { - if (p->prefixlen == prefixlen && - net_eq(ip6addrlbl_net(p), net) && - p->ifindex == ifindex && - ipv6_addr_equal(&p->prefix, prefix)) { - hlist_del_rcu(&p->list); - ip6addrlbl_put(p); - ret = 0; - break; - } - } - return ret; -} - -static int ip6addrlbl_del(struct net *net, - const struct in6_addr *prefix, int prefixlen, - int ifindex) -{ - struct in6_addr prefix_buf; - int ret; - - ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)\n", - __func__, prefix, prefixlen, ifindex); - - ipv6_addr_prefix(&prefix_buf, prefix, prefixlen); - spin_lock(&ip6addrlbl_table.lock); - ret = __ip6addrlbl_del(net, &prefix_buf, prefixlen, ifindex); - spin_unlock(&ip6addrlbl_table.lock); - return ret; -} - -/* add default label */ -static int __net_init ip6addrlbl_net_init(struct net *net) -{ - int err = 0; - int i; - - ADDRLABEL(KERN_DEBUG "%s\n", __func__); - - for (i = 0; i < ARRAY_SIZE(ip6addrlbl_init_table); i++) { - int ret = ip6addrlbl_add(net, - ip6addrlbl_init_table[i].prefix, - ip6addrlbl_init_table[i].prefixlen, - 0, - ip6addrlbl_init_table[i].label, 0); - /* XXX: should we free all rules when we catch an error? */ - if (ret && (!err || err != -ENOMEM)) - err = ret; - } - return err; -} - -static void __net_exit ip6addrlbl_net_exit(struct net *net) -{ - struct ip6addrlbl_entry *p = NULL; - struct hlist_node *n; - - /* Remove all labels belonging to the exiting net */ - spin_lock(&ip6addrlbl_table.lock); - hlist_for_each_entry_safe(p, n, &ip6addrlbl_table.head, list) { - if (net_eq(ip6addrlbl_net(p), net)) { - hlist_del_rcu(&p->list); - ip6addrlbl_put(p); - } - } - spin_unlock(&ip6addrlbl_table.lock); -} - -static struct pernet_operations ipv6_addr_label_ops = { - .init = ip6addrlbl_net_init, - .exit = ip6addrlbl_net_exit, -}; - -int __init ipv6_addr_label_init(void) -{ - spin_lock_init(&ip6addrlbl_table.lock); - - return register_pernet_subsys(&ipv6_addr_label_ops); -} - -void ipv6_addr_label_cleanup(void) -{ - unregister_pernet_subsys(&ipv6_addr_label_ops); -} - -static const struct nla_policy ifal_policy[IFAL_MAX+1] = { - [IFAL_ADDRESS] = { .len = sizeof(struct in6_addr), }, - [IFAL_LABEL] = { .len = sizeof(u32), }, -}; - -static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(skb->sk); - struct ifaddrlblmsg *ifal; - struct nlattr *tb[IFAL_MAX+1]; - struct in6_addr *pfx; - u32 label; - int err = 0; - - err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy); - if (err < 0) - return err; - - ifal = nlmsg_data(nlh); - - if (ifal->ifal_family != AF_INET6 || - ifal->ifal_prefixlen > 128) - return -EINVAL; - - if (!tb[IFAL_ADDRESS]) - return -EINVAL; - pfx = nla_data(tb[IFAL_ADDRESS]); - - if (!tb[IFAL_LABEL]) - return -EINVAL; - label = nla_get_u32(tb[IFAL_LABEL]); - if (label == IPV6_ADDR_LABEL_DEFAULT) - return -EINVAL; - - switch (nlh->nlmsg_type) { - case RTM_NEWADDRLABEL: - if (ifal->ifal_index && - !__dev_get_by_index(net, ifal->ifal_index)) - return -EINVAL; - - err = ip6addrlbl_add(net, pfx, ifal->ifal_prefixlen, - ifal->ifal_index, label, - nlh->nlmsg_flags & NLM_F_REPLACE); - break; - case RTM_DELADDRLABEL: - err = ip6addrlbl_del(net, pfx, ifal->ifal_prefixlen, - ifal->ifal_index); - break; - default: - err = -EOPNOTSUPP; - } - return err; -} - -static void ip6addrlbl_putmsg(struct nlmsghdr *nlh, - int prefixlen, int ifindex, u32 lseq) -{ - struct ifaddrlblmsg *ifal = nlmsg_data(nlh); - ifal->ifal_family = AF_INET6; - ifal->ifal_prefixlen = prefixlen; - ifal->ifal_flags = 0; - ifal->ifal_index = ifindex; - ifal->ifal_seq = lseq; -}; - -static int ip6addrlbl_fill(struct sk_buff *skb, - struct ip6addrlbl_entry *p, - u32 lseq, - u32 portid, u32 seq, int event, - unsigned int flags) -{ - struct nlmsghdr *nlh = nlmsg_put(skb, portid, seq, event, - sizeof(struct ifaddrlblmsg), flags); - if (!nlh) - return -EMSGSIZE; - - ip6addrlbl_putmsg(nlh, p->prefixlen, p->ifindex, lseq); - - if (nla_put_in6_addr(skb, IFAL_ADDRESS, &p->prefix) < 0 || - nla_put_u32(skb, IFAL_LABEL, p->label) < 0) { - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; - } - - nlmsg_end(skb, nlh); - return 0; -} - -static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb) -{ - struct net *net = sock_net(skb->sk); - struct ip6addrlbl_entry *p; - int idx = 0, s_idx = cb->args[0]; - int err; - - rcu_read_lock(); - hlist_for_each_entry_rcu(p, &ip6addrlbl_table.head, list) { - if (idx >= s_idx && - net_eq(ip6addrlbl_net(p), net)) { - err = ip6addrlbl_fill(skb, p, - ip6addrlbl_table.seq, - NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, - RTM_NEWADDRLABEL, - NLM_F_MULTI); - if (err < 0) - break; - } - idx++; - } - rcu_read_unlock(); - cb->args[0] = idx; - return skb->len; -} - -static inline int ip6addrlbl_msgsize(void) -{ - return NLMSG_ALIGN(sizeof(struct ifaddrlblmsg)) - + nla_total_size(16) /* IFAL_ADDRESS */ - + nla_total_size(4); /* IFAL_LABEL */ -} - -static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(in_skb->sk); - struct ifaddrlblmsg *ifal; - struct nlattr *tb[IFAL_MAX+1]; - struct in6_addr *addr; - u32 lseq; - int err = 0; - struct ip6addrlbl_entry *p; - struct sk_buff *skb; - - err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy); - if (err < 0) - return err; - - ifal = nlmsg_data(nlh); - - if (ifal->ifal_family != AF_INET6 || - ifal->ifal_prefixlen != 128) - return -EINVAL; - - if (ifal->ifal_index && - !__dev_get_by_index(net, ifal->ifal_index)) - return -EINVAL; - - if (!tb[IFAL_ADDRESS]) - return -EINVAL; - addr = nla_data(tb[IFAL_ADDRESS]); - - rcu_read_lock(); - p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index); - if (p && !ip6addrlbl_hold(p)) - p = NULL; - lseq = ip6addrlbl_table.seq; - rcu_read_unlock(); - - if (!p) { - err = -ESRCH; - goto out; - } - - skb = nlmsg_new(ip6addrlbl_msgsize(), GFP_KERNEL); - if (!skb) { - ip6addrlbl_put(p); - return -ENOBUFS; - } - - err = ip6addrlbl_fill(skb, p, lseq, - NETLINK_CB(in_skb).portid, nlh->nlmsg_seq, - RTM_NEWADDRLABEL, 0); - - ip6addrlbl_put(p); - - if (err < 0) { - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - goto out; - } - - err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); -out: - return err; -} - -void __init ipv6_addr_label_rtnl_register(void) -{ - __rtnl_register(PF_INET6, RTM_NEWADDRLABEL, ip6addrlbl_newdel, - NULL, NULL); - __rtnl_register(PF_INET6, RTM_DELADDRLABEL, ip6addrlbl_newdel, - NULL, NULL); - __rtnl_register(PF_INET6, RTM_GETADDRLABEL, ip6addrlbl_get, - ip6addrlbl_dump, NULL); -} - diff --git a/src/linux/net/ipv6/af_inet6.c b/src/linux/net/ipv6/af_inet6.c deleted file mode 100644 index 46ad699..0000000 --- a/src/linux/net/ipv6/af_inet6.c +++ /dev/null @@ -1,1070 +0,0 @@ -/* - * PF_INET6 socket protocol family - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * Adapted from linux/net/ipv4/af_inet.c - * - * Fixes: - * piggy, Karl Knutson : Socket protocol table - * Hideaki YOSHIFUJI : sin6_scope_id support - * Arnaldo Melo : check proc_net_create return, cleanups - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#define pr_fmt(fmt) "IPv6: " fmt - -#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 -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_IPV6_TUNNEL -#include -#endif -#include - -#include -#include - -#include "ip6_offload.h" - -MODULE_AUTHOR("Cast of dozens"); -MODULE_DESCRIPTION("IPv6 protocol stack for Linux"); -MODULE_LICENSE("GPL"); - -/* The inetsw6 table contains everything that inet6_create needs to - * build a new socket. - */ -static struct list_head inetsw6[SOCK_MAX]; -static DEFINE_SPINLOCK(inetsw6_lock); - -struct ipv6_params ipv6_defaults = { - .disable_ipv6 = 0, - .autoconf = 1, -}; - -static int disable_ipv6_mod; - -module_param_named(disable, disable_ipv6_mod, int, 0444); -MODULE_PARM_DESC(disable, "Disable IPv6 module such that it is non-functional"); - -module_param_named(disable_ipv6, ipv6_defaults.disable_ipv6, int, 0444); -MODULE_PARM_DESC(disable_ipv6, "Disable IPv6 on all interfaces"); - -module_param_named(autoconf, ipv6_defaults.autoconf, int, 0444); -MODULE_PARM_DESC(autoconf, "Enable IPv6 address autoconfiguration on all interfaces"); - -bool ipv6_mod_enabled(void) -{ - return disable_ipv6_mod == 0; -} -EXPORT_SYMBOL_GPL(ipv6_mod_enabled); - -static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk) -{ - const int offset = sk->sk_prot->obj_size - sizeof(struct ipv6_pinfo); - - return (struct ipv6_pinfo *)(((u8 *)sk) + offset); -} - -static int inet6_create(struct net *net, struct socket *sock, int protocol, - int kern) -{ - struct inet_sock *inet; - struct ipv6_pinfo *np; - struct sock *sk; - struct inet_protosw *answer; - struct proto *answer_prot; - unsigned char answer_flags; - int try_loading_module = 0; - int err; - - if (protocol < 0 || protocol >= IPPROTO_MAX) - return -EINVAL; - - /* Look for the requested type/protocol pair. */ -lookup_protocol: - err = -ESOCKTNOSUPPORT; - rcu_read_lock(); - list_for_each_entry_rcu(answer, &inetsw6[sock->type], list) { - - err = 0; - /* Check the non-wild match. */ - if (protocol == answer->protocol) { - if (protocol != IPPROTO_IP) - break; - } else { - /* Check for the two wild cases. */ - if (IPPROTO_IP == protocol) { - protocol = answer->protocol; - break; - } - if (IPPROTO_IP == answer->protocol) - break; - } - err = -EPROTONOSUPPORT; - } - - if (err) { - if (try_loading_module < 2) { - rcu_read_unlock(); - /* - * Be more specific, e.g. net-pf-10-proto-132-type-1 - * (net-pf-PF_INET6-proto-IPPROTO_SCTP-type-SOCK_STREAM) - */ - if (++try_loading_module == 1) - request_module("net-pf-%d-proto-%d-type-%d", - PF_INET6, protocol, sock->type); - /* - * Fall back to generic, e.g. net-pf-10-proto-132 - * (net-pf-PF_INET6-proto-IPPROTO_SCTP) - */ - else - request_module("net-pf-%d-proto-%d", - PF_INET6, protocol); - goto lookup_protocol; - } else - goto out_rcu_unlock; - } - - err = -EPERM; - if (sock->type == SOCK_RAW && !kern && - !ns_capable(net->user_ns, CAP_NET_RAW)) - goto out_rcu_unlock; - - sock->ops = answer->ops; - answer_prot = answer->prot; - answer_flags = answer->flags; - rcu_read_unlock(); - - WARN_ON(!answer_prot->slab); - - err = -ENOBUFS; - sk = sk_alloc(net, PF_INET6, GFP_KERNEL, answer_prot, kern); - if (!sk) - goto out; - - sock_init_data(sock, sk); - - err = 0; - if (INET_PROTOSW_REUSE & answer_flags) - sk->sk_reuse = SK_CAN_REUSE; - - inet = inet_sk(sk); - inet->is_icsk = (INET_PROTOSW_ICSK & answer_flags) != 0; - - if (SOCK_RAW == sock->type) { - inet->inet_num = protocol; - if (IPPROTO_RAW == protocol) - inet->hdrincl = 1; - } - - sk->sk_destruct = inet_sock_destruct; - sk->sk_family = PF_INET6; - sk->sk_protocol = protocol; - - sk->sk_backlog_rcv = answer->prot->backlog_rcv; - - inet_sk(sk)->pinet6 = np = inet6_sk_generic(sk); - np->hop_limit = -1; - np->mcast_hops = IPV6_DEFAULT_MCASTHOPS; - np->mc_loop = 1; - np->pmtudisc = IPV6_PMTUDISC_WANT; - np->autoflowlabel = ip6_default_np_autolabel(sock_net(sk)); - sk->sk_ipv6only = net->ipv6.sysctl.bindv6only; - - /* Init the ipv4 part of the socket since we can have sockets - * using v6 API for ipv4. - */ - inet->uc_ttl = -1; - - inet->mc_loop = 1; - inet->mc_ttl = 1; - inet->mc_index = 0; - inet->mc_list = NULL; - inet->rcv_tos = 0; - - if (net->ipv4.sysctl_ip_no_pmtu_disc) - inet->pmtudisc = IP_PMTUDISC_DONT; - else - inet->pmtudisc = IP_PMTUDISC_WANT; - /* - * Increment only the relevant sk_prot->socks debug field, this changes - * the previous behaviour of incrementing both the equivalent to - * answer->prot->socks (inet6_sock_nr) and inet_sock_nr. - * - * This allows better debug granularity as we'll know exactly how many - * UDPv6, TCPv6, etc socks were allocated, not the sum of all IPv6 - * transport protocol socks. -acme - */ - sk_refcnt_debug_inc(sk); - - if (inet->inet_num) { - /* It assumes that any protocol which allows - * the user to assign a number at socket - * creation time automatically shares. - */ - inet->inet_sport = htons(inet->inet_num); - err = sk->sk_prot->hash(sk); - if (err) { - sk_common_release(sk); - goto out; - } - } - if (sk->sk_prot->init) { - err = sk->sk_prot->init(sk); - if (err) { - sk_common_release(sk); - goto out; - } - } -out: - return err; -out_rcu_unlock: - rcu_read_unlock(); - goto out; -} - - -/* bind for INET6 API */ -int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) -{ - struct sockaddr_in6 *addr = (struct sockaddr_in6 *)uaddr; - struct sock *sk = sock->sk; - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *np = inet6_sk(sk); - struct net *net = sock_net(sk); - __be32 v4addr = 0; - unsigned short snum; - int addr_type = 0; - int err = 0; - - /* If the socket has its own bind function then use it. */ - if (sk->sk_prot->bind) - return sk->sk_prot->bind(sk, uaddr, addr_len); - - if (addr_len < SIN6_LEN_RFC2133) - return -EINVAL; - - if (addr->sin6_family != AF_INET6) - return -EAFNOSUPPORT; - - addr_type = ipv6_addr_type(&addr->sin6_addr); - if ((addr_type & IPV6_ADDR_MULTICAST) && sock->type == SOCK_STREAM) - return -EINVAL; - - snum = ntohs(addr->sin6_port); - if (snum && snum < PROT_SOCK && !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) - return -EACCES; - - lock_sock(sk); - - /* Check these errors (active socket, double bind). */ - if (sk->sk_state != TCP_CLOSE || inet->inet_num) { - err = -EINVAL; - goto out; - } - - /* Check if the address belongs to the host. */ - if (addr_type == IPV6_ADDR_MAPPED) { - int chk_addr_ret; - - /* Binding to v4-mapped address on a v6-only socket - * makes no sense - */ - if (sk->sk_ipv6only) { - err = -EINVAL; - goto out; - } - - /* Reproduce AF_INET checks to make the bindings consistent */ - v4addr = addr->sin6_addr.s6_addr32[3]; - chk_addr_ret = inet_addr_type(net, v4addr); - if (!net->ipv4.sysctl_ip_nonlocal_bind && - !(inet->freebind || inet->transparent) && - v4addr != htonl(INADDR_ANY) && - chk_addr_ret != RTN_LOCAL && - chk_addr_ret != RTN_MULTICAST && - chk_addr_ret != RTN_BROADCAST) { - err = -EADDRNOTAVAIL; - goto out; - } - } else { - if (addr_type != IPV6_ADDR_ANY) { - struct net_device *dev = NULL; - - rcu_read_lock(); - if (__ipv6_addr_needs_scope_id(addr_type)) { - if (addr_len >= sizeof(struct sockaddr_in6) && - addr->sin6_scope_id) { - /* Override any existing binding, if another one - * is supplied by user. - */ - sk->sk_bound_dev_if = addr->sin6_scope_id; - } - - /* Binding to link-local address requires an interface */ - if (!sk->sk_bound_dev_if) { - err = -EINVAL; - goto out_unlock; - } - dev = dev_get_by_index_rcu(net, sk->sk_bound_dev_if); - if (!dev) { - err = -ENODEV; - goto out_unlock; - } - } - - /* ipv4 addr of the socket is invalid. Only the - * unspecified and mapped address have a v4 equivalent. - */ - v4addr = LOOPBACK4_IPV6; - if (!(addr_type & IPV6_ADDR_MULTICAST)) { - if (!net->ipv6.sysctl.ip_nonlocal_bind && - !(inet->freebind || inet->transparent) && - !ipv6_chk_addr(net, &addr->sin6_addr, - dev, 0)) { - err = -EADDRNOTAVAIL; - goto out_unlock; - } - } - rcu_read_unlock(); - } - } - - inet->inet_rcv_saddr = v4addr; - inet->inet_saddr = v4addr; - - sk->sk_v6_rcv_saddr = addr->sin6_addr; - - if (!(addr_type & IPV6_ADDR_MULTICAST)) - np->saddr = addr->sin6_addr; - - /* Make sure we are allowed to bind here. */ - if ((snum || !inet->bind_address_no_port) && - sk->sk_prot->get_port(sk, snum)) { - inet_reset_saddr(sk); - err = -EADDRINUSE; - goto out; - } - - if (addr_type != IPV6_ADDR_ANY) { - sk->sk_userlocks |= SOCK_BINDADDR_LOCK; - if (addr_type != IPV6_ADDR_MAPPED) - sk->sk_ipv6only = 1; - } - if (snum) - sk->sk_userlocks |= SOCK_BINDPORT_LOCK; - inet->inet_sport = htons(inet->inet_num); - inet->inet_dport = 0; - inet->inet_daddr = 0; -out: - release_sock(sk); - return err; -out_unlock: - rcu_read_unlock(); - goto out; -} -EXPORT_SYMBOL(inet6_bind); - -int inet6_release(struct socket *sock) -{ - struct sock *sk = sock->sk; - - if (!sk) - return -EINVAL; - - /* Free mc lists */ - ipv6_sock_mc_close(sk); - - /* Free ac lists */ - ipv6_sock_ac_close(sk); - - return inet_release(sock); -} -EXPORT_SYMBOL(inet6_release); - -void inet6_destroy_sock(struct sock *sk) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct sk_buff *skb; - struct ipv6_txoptions *opt; - - /* Release rx options */ - - skb = xchg(&np->pktoptions, NULL); - if (skb) - kfree_skb(skb); - - skb = xchg(&np->rxpmtu, NULL); - if (skb) - kfree_skb(skb); - - /* Free flowlabels */ - fl6_free_socklist(sk); - - /* Free tx options */ - - opt = xchg((__force struct ipv6_txoptions **)&np->opt, NULL); - if (opt) { - atomic_sub(opt->tot_len, &sk->sk_omem_alloc); - txopt_put(opt); - } -} -EXPORT_SYMBOL_GPL(inet6_destroy_sock); - -/* - * This does both peername and sockname. - */ - -int inet6_getname(struct socket *sock, struct sockaddr *uaddr, - int *uaddr_len, int peer) -{ - struct sockaddr_in6 *sin = (struct sockaddr_in6 *)uaddr; - struct sock *sk = sock->sk; - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *np = inet6_sk(sk); - - sin->sin6_family = AF_INET6; - sin->sin6_flowinfo = 0; - sin->sin6_scope_id = 0; - if (peer) { - if (!inet->inet_dport) - return -ENOTCONN; - if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) && - peer == 1) - return -ENOTCONN; - sin->sin6_port = inet->inet_dport; - sin->sin6_addr = sk->sk_v6_daddr; - if (np->sndflow) - sin->sin6_flowinfo = np->flow_label; - } else { - if (ipv6_addr_any(&sk->sk_v6_rcv_saddr)) - sin->sin6_addr = np->saddr; - else - sin->sin6_addr = sk->sk_v6_rcv_saddr; - - sin->sin6_port = inet->inet_sport; - } - sin->sin6_scope_id = ipv6_iface_scope_id(&sin->sin6_addr, - sk->sk_bound_dev_if); - *uaddr_len = sizeof(*sin); - return 0; -} -EXPORT_SYMBOL(inet6_getname); - -int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) -{ - struct sock *sk = sock->sk; - struct net *net = sock_net(sk); - - switch (cmd) { - case SIOCGSTAMP: - return sock_get_timestamp(sk, (struct timeval __user *)arg); - - case SIOCGSTAMPNS: - return sock_get_timestampns(sk, (struct timespec __user *)arg); - - case SIOCADDRT: - case SIOCDELRT: - - return ipv6_route_ioctl(net, cmd, (void __user *)arg); - - case SIOCSIFADDR: - return addrconf_add_ifaddr(net, (void __user *) arg); - case SIOCDIFADDR: - return addrconf_del_ifaddr(net, (void __user *) arg); - case SIOCSIFDSTADDR: - return addrconf_set_dstaddr(net, (void __user *) arg); - default: - if (!sk->sk_prot->ioctl) - return -ENOIOCTLCMD; - return sk->sk_prot->ioctl(sk, cmd, arg); - } - /*NOTREACHED*/ - return 0; -} -EXPORT_SYMBOL(inet6_ioctl); - -const struct proto_ops inet6_stream_ops = { - .family = PF_INET6, - .owner = THIS_MODULE, - .release = inet6_release, - .bind = inet6_bind, - .connect = inet_stream_connect, /* ok */ - .socketpair = sock_no_socketpair, /* a do nothing */ - .accept = inet_accept, /* ok */ - .getname = inet6_getname, - .poll = tcp_poll, /* ok */ - .ioctl = inet6_ioctl, /* must change */ - .listen = inet_listen, /* ok */ - .shutdown = inet_shutdown, /* ok */ - .setsockopt = sock_common_setsockopt, /* ok */ - .getsockopt = sock_common_getsockopt, /* ok */ - .sendmsg = inet_sendmsg, /* ok */ - .recvmsg = inet_recvmsg, /* ok */ - .mmap = sock_no_mmap, - .sendpage = inet_sendpage, - .splice_read = tcp_splice_read, - .read_sock = tcp_read_sock, - .peek_len = tcp_peek_len, -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_sock_common_setsockopt, - .compat_getsockopt = compat_sock_common_getsockopt, -#endif -}; - -const struct proto_ops inet6_dgram_ops = { - .family = PF_INET6, - .owner = THIS_MODULE, - .release = inet6_release, - .bind = inet6_bind, - .connect = inet_dgram_connect, /* ok */ - .socketpair = sock_no_socketpair, /* a do nothing */ - .accept = sock_no_accept, /* a do nothing */ - .getname = inet6_getname, - .poll = udp_poll, /* ok */ - .ioctl = inet6_ioctl, /* must change */ - .listen = sock_no_listen, /* ok */ - .shutdown = inet_shutdown, /* ok */ - .setsockopt = sock_common_setsockopt, /* ok */ - .getsockopt = sock_common_getsockopt, /* ok */ - .sendmsg = inet_sendmsg, /* ok */ - .recvmsg = inet_recvmsg, /* ok */ - .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, - .set_peek_off = sk_set_peek_off, -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_sock_common_setsockopt, - .compat_getsockopt = compat_sock_common_getsockopt, -#endif -}; - -static const struct net_proto_family inet6_family_ops = { - .family = PF_INET6, - .create = inet6_create, - .owner = THIS_MODULE, -}; - -int inet6_register_protosw(struct inet_protosw *p) -{ - struct list_head *lh; - struct inet_protosw *answer; - struct list_head *last_perm; - int protocol = p->protocol; - int ret; - - spin_lock_bh(&inetsw6_lock); - - ret = -EINVAL; - if (p->type >= SOCK_MAX) - goto out_illegal; - - /* If we are trying to override a permanent protocol, bail. */ - answer = NULL; - ret = -EPERM; - last_perm = &inetsw6[p->type]; - list_for_each(lh, &inetsw6[p->type]) { - answer = list_entry(lh, struct inet_protosw, list); - - /* Check only the non-wild match. */ - if (INET_PROTOSW_PERMANENT & answer->flags) { - if (protocol == answer->protocol) - break; - last_perm = lh; - } - - answer = NULL; - } - if (answer) - goto out_permanent; - - /* Add the new entry after the last permanent entry if any, so that - * the new entry does not override a permanent entry when matched with - * a wild-card protocol. But it is allowed to override any existing - * non-permanent entry. This means that when we remove this entry, the - * system automatically returns to the old behavior. - */ - list_add_rcu(&p->list, last_perm); - ret = 0; -out: - spin_unlock_bh(&inetsw6_lock); - return ret; - -out_permanent: - pr_err("Attempt to override permanent protocol %d\n", protocol); - goto out; - -out_illegal: - pr_err("Ignoring attempt to register invalid socket type %d\n", - p->type); - goto out; -} -EXPORT_SYMBOL(inet6_register_protosw); - -void -inet6_unregister_protosw(struct inet_protosw *p) -{ - if (INET_PROTOSW_PERMANENT & p->flags) { - pr_err("Attempt to unregister permanent protocol %d\n", - p->protocol); - } else { - spin_lock_bh(&inetsw6_lock); - list_del_rcu(&p->list); - spin_unlock_bh(&inetsw6_lock); - - synchronize_net(); - } -} -EXPORT_SYMBOL(inet6_unregister_protosw); - -int inet6_sk_rebuild_header(struct sock *sk) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct dst_entry *dst; - - dst = __sk_dst_check(sk, np->dst_cookie); - - if (!dst) { - struct inet_sock *inet = inet_sk(sk); - struct in6_addr *final_p, final; - struct flowi6 fl6; - - memset(&fl6, 0, sizeof(fl6)); - fl6.flowi6_proto = sk->sk_protocol; - fl6.daddr = sk->sk_v6_daddr; - fl6.saddr = np->saddr; - fl6.flowlabel = np->flow_label; - fl6.flowi6_oif = sk->sk_bound_dev_if; - fl6.flowi6_mark = sk->sk_mark; - fl6.fl6_dport = inet->inet_dport; - fl6.fl6_sport = inet->inet_sport; - security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); - - rcu_read_lock(); - final_p = fl6_update_dst(&fl6, rcu_dereference(np->opt), - &final); - rcu_read_unlock(); - - dst = ip6_dst_lookup_flow(sk, &fl6, final_p); - if (IS_ERR(dst)) { - sk->sk_route_caps = 0; - sk->sk_err_soft = -PTR_ERR(dst); - return PTR_ERR(dst); - } - - ip6_dst_store(sk, dst, NULL, NULL); - } - - return 0; -} -EXPORT_SYMBOL_GPL(inet6_sk_rebuild_header); - -bool ipv6_opt_accepted(const struct sock *sk, const struct sk_buff *skb, - const struct inet6_skb_parm *opt) -{ - const struct ipv6_pinfo *np = inet6_sk(sk); - - if (np->rxopt.all) { - if (((opt->flags & IP6SKB_HOPBYHOP) && - (np->rxopt.bits.hopopts || np->rxopt.bits.ohopopts)) || - (ip6_flowinfo((struct ipv6hdr *) skb_network_header(skb)) && - np->rxopt.bits.rxflow) || - (opt->srcrt && (np->rxopt.bits.srcrt || - np->rxopt.bits.osrcrt)) || - ((opt->dst1 || opt->dst0) && - (np->rxopt.bits.dstopts || np->rxopt.bits.odstopts))) - return true; - } - return false; -} -EXPORT_SYMBOL_GPL(ipv6_opt_accepted); - -static struct packet_type ipv6_packet_type __read_mostly = { - .type = cpu_to_be16(ETH_P_IPV6), - .func = ipv6_rcv, -}; - -static int __init ipv6_packet_init(void) -{ - dev_add_pack(&ipv6_packet_type); - return 0; -} - -static void ipv6_packet_cleanup(void) -{ - dev_remove_pack(&ipv6_packet_type); -} - -static int __net_init ipv6_init_mibs(struct net *net) -{ - int i; - - net->mib.udp_stats_in6 = alloc_percpu(struct udp_mib); - if (!net->mib.udp_stats_in6) - return -ENOMEM; - net->mib.udplite_stats_in6 = alloc_percpu(struct udp_mib); - if (!net->mib.udplite_stats_in6) - goto err_udplite_mib; - net->mib.ipv6_statistics = alloc_percpu(struct ipstats_mib); - if (!net->mib.ipv6_statistics) - goto err_ip_mib; - - for_each_possible_cpu(i) { - struct ipstats_mib *af_inet6_stats; - af_inet6_stats = per_cpu_ptr(net->mib.ipv6_statistics, i); - u64_stats_init(&af_inet6_stats->syncp); - } - - - net->mib.icmpv6_statistics = alloc_percpu(struct icmpv6_mib); - if (!net->mib.icmpv6_statistics) - goto err_icmp_mib; - net->mib.icmpv6msg_statistics = kzalloc(sizeof(struct icmpv6msg_mib), - GFP_KERNEL); - if (!net->mib.icmpv6msg_statistics) - goto err_icmpmsg_mib; - return 0; - -err_icmpmsg_mib: - free_percpu(net->mib.icmpv6_statistics); -err_icmp_mib: - free_percpu(net->mib.ipv6_statistics); -err_ip_mib: - free_percpu(net->mib.udplite_stats_in6); -err_udplite_mib: - free_percpu(net->mib.udp_stats_in6); - return -ENOMEM; -} - -static void ipv6_cleanup_mibs(struct net *net) -{ - free_percpu(net->mib.udp_stats_in6); - free_percpu(net->mib.udplite_stats_in6); - free_percpu(net->mib.ipv6_statistics); - free_percpu(net->mib.icmpv6_statistics); - kfree(net->mib.icmpv6msg_statistics); -} - -static int __net_init inet6_net_init(struct net *net) -{ - int err = 0; - - net->ipv6.sysctl.bindv6only = 0; - net->ipv6.sysctl.icmpv6_time = 1*HZ; - net->ipv6.sysctl.flowlabel_consistency = 1; - net->ipv6.sysctl.auto_flowlabels = IP6_DEFAULT_AUTO_FLOW_LABELS; - net->ipv6.sysctl.idgen_retries = 3; - net->ipv6.sysctl.idgen_delay = 1 * HZ; - net->ipv6.sysctl.flowlabel_state_ranges = 0; - atomic_set(&net->ipv6.fib6_sernum, 1); - - err = ipv6_init_mibs(net); - if (err) - return err; -#ifdef CONFIG_PROC_FS - err = udp6_proc_init(net); - if (err) - goto out; - err = tcp6_proc_init(net); - if (err) - goto proc_tcp6_fail; - err = ac6_proc_init(net); - if (err) - goto proc_ac6_fail; -#endif - return err; - -#ifdef CONFIG_PROC_FS -proc_ac6_fail: - tcp6_proc_exit(net); -proc_tcp6_fail: - udp6_proc_exit(net); -out: - ipv6_cleanup_mibs(net); - return err; -#endif -} - -static void __net_exit inet6_net_exit(struct net *net) -{ -#ifdef CONFIG_PROC_FS - udp6_proc_exit(net); - tcp6_proc_exit(net); - ac6_proc_exit(net); -#endif - ipv6_cleanup_mibs(net); -} - -static struct pernet_operations inet6_net_ops = { - .init = inet6_net_init, - .exit = inet6_net_exit, -}; - -static const struct ipv6_stub ipv6_stub_impl = { - .ipv6_sock_mc_join = ipv6_sock_mc_join, - .ipv6_sock_mc_drop = ipv6_sock_mc_drop, - .ipv6_dst_lookup = ip6_dst_lookup, - .udpv6_encap_enable = udpv6_encap_enable, - .ndisc_send_na = ndisc_send_na, - .nd_tbl = &nd_tbl, -}; - -static int __init inet6_init(void) -{ - struct list_head *r; - int err = 0; - - sock_skb_cb_check_size(sizeof(struct inet6_skb_parm)); - - /* Register the socket-side information for inet6_create. */ - for (r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r) - INIT_LIST_HEAD(r); - - if (disable_ipv6_mod) { - pr_info("Loaded, but administratively disabled, reboot required to enable\n"); - goto out; - } - - err = proto_register(&tcpv6_prot, 1); - if (err) - goto out; - - err = proto_register(&udpv6_prot, 1); - if (err) - goto out_unregister_tcp_proto; - - err = proto_register(&udplitev6_prot, 1); - if (err) - goto out_unregister_udp_proto; - - err = proto_register(&rawv6_prot, 1); - if (err) - goto out_unregister_udplite_proto; - - err = proto_register(&pingv6_prot, 1); - if (err) - goto out_unregister_ping_proto; - - /* We MUST register RAW sockets before we create the ICMP6, - * IGMP6, or NDISC control sockets. - */ - err = rawv6_init(); - if (err) - goto out_unregister_raw_proto; - - /* Register the family here so that the init calls below will - * be able to create sockets. (?? is this dangerous ??) - */ - err = sock_register(&inet6_family_ops); - if (err) - goto out_sock_register_fail; - - /* - * ipngwg API draft makes clear that the correct semantics - * for TCP and UDP is to consider one TCP and UDP instance - * in a host available by both INET and INET6 APIs and - * able to communicate via both network protocols. - */ - - err = register_pernet_subsys(&inet6_net_ops); - if (err) - goto register_pernet_fail; - err = icmpv6_init(); - if (err) - goto icmp_fail; - err = ip6_mr_init(); - if (err) - goto ipmr_fail; - err = ndisc_init(); - if (err) - goto ndisc_fail; - err = igmp6_init(); - if (err) - goto igmp_fail; - - ipv6_stub = &ipv6_stub_impl; - - err = ipv6_netfilter_init(); - if (err) - goto netfilter_fail; - /* Create /proc/foo6 entries. */ -#ifdef CONFIG_PROC_FS - err = -ENOMEM; - if (raw6_proc_init()) - goto proc_raw6_fail; - if (udplite6_proc_init()) - goto proc_udplite6_fail; - if (ipv6_misc_proc_init()) - goto proc_misc6_fail; - if (if6_proc_init()) - goto proc_if6_fail; -#endif - err = ip6_route_init(); - if (err) - goto ip6_route_fail; - err = ndisc_late_init(); - if (err) - goto ndisc_late_fail; - err = ip6_flowlabel_init(); - if (err) - goto ip6_flowlabel_fail; - err = addrconf_init(); - if (err) - goto addrconf_fail; - - /* Init v6 extension headers. */ - err = ipv6_exthdrs_init(); - if (err) - goto ipv6_exthdrs_fail; - - err = ipv6_frag_init(); - if (err) - goto ipv6_frag_fail; - - /* Init v6 transport protocols. */ - err = udpv6_init(); - if (err) - goto udpv6_fail; - - err = udplitev6_init(); - if (err) - goto udplitev6_fail; - - err = udpv6_offload_init(); - if (err) - goto udpv6_offload_fail; - - err = tcpv6_init(); - if (err) - goto tcpv6_fail; - - err = ipv6_packet_init(); - if (err) - goto ipv6_packet_fail; - - err = pingv6_init(); - if (err) - goto pingv6_fail; - - err = calipso_init(); - if (err) - goto calipso_fail; - -#ifdef CONFIG_SYSCTL - err = ipv6_sysctl_register(); - if (err) - goto sysctl_fail; -#endif -out: - return err; - -#ifdef CONFIG_SYSCTL -sysctl_fail: - calipso_exit(); -#endif -calipso_fail: - pingv6_exit(); -pingv6_fail: - ipv6_packet_cleanup(); -ipv6_packet_fail: - tcpv6_exit(); -tcpv6_fail: - udpv6_offload_exit(); -udpv6_offload_fail: - udplitev6_exit(); -udplitev6_fail: - udpv6_exit(); -udpv6_fail: - ipv6_frag_exit(); -ipv6_frag_fail: - ipv6_exthdrs_exit(); -ipv6_exthdrs_fail: - addrconf_cleanup(); -addrconf_fail: - ip6_flowlabel_cleanup(); -ip6_flowlabel_fail: - ndisc_late_cleanup(); -ndisc_late_fail: - ip6_route_cleanup(); -ip6_route_fail: -#ifdef CONFIG_PROC_FS - if6_proc_exit(); -proc_if6_fail: - ipv6_misc_proc_exit(); -proc_misc6_fail: - udplite6_proc_exit(); -proc_udplite6_fail: - raw6_proc_exit(); -proc_raw6_fail: -#endif - ipv6_netfilter_fini(); -netfilter_fail: - igmp6_cleanup(); -igmp_fail: - ndisc_cleanup(); -ndisc_fail: - ip6_mr_cleanup(); -ipmr_fail: - icmpv6_cleanup(); -icmp_fail: - unregister_pernet_subsys(&inet6_net_ops); -register_pernet_fail: - sock_unregister(PF_INET6); - rtnl_unregister_all(PF_INET6); -out_sock_register_fail: - rawv6_exit(); -out_unregister_ping_proto: - proto_unregister(&pingv6_prot); -out_unregister_raw_proto: - proto_unregister(&rawv6_prot); -out_unregister_udplite_proto: - proto_unregister(&udplitev6_prot); -out_unregister_udp_proto: - proto_unregister(&udpv6_prot); -out_unregister_tcp_proto: - proto_unregister(&tcpv6_prot); - goto out; -} -module_init(inet6_init); - -MODULE_ALIAS_NETPROTO(PF_INET6); diff --git a/src/linux/net/ipv6/anycast.c b/src/linux/net/ipv6/anycast.c deleted file mode 100644 index 514ac25..0000000 --- a/src/linux/net/ipv6/anycast.c +++ /dev/null @@ -1,556 +0,0 @@ -/* - * Anycast support for IPv6 - * Linux INET6 implementation - * - * Authors: - * David L Stevens (dlstevens@us.ibm.com) - * - * based heavily on net/ipv6/mcast.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#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 - -static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr); - -/* - * socket join an anycast group - */ - -int ipv6_sock_ac_join(struct sock *sk, int ifindex, const struct in6_addr *addr) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct net_device *dev = NULL; - struct inet6_dev *idev; - struct ipv6_ac_socklist *pac; - struct net *net = sock_net(sk); - int ishost = !net->ipv6.devconf_all->forwarding; - int err = 0; - - ASSERT_RTNL(); - - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - return -EPERM; - if (ipv6_addr_is_multicast(addr)) - return -EINVAL; - if (ipv6_chk_addr(net, addr, NULL, 0)) - return -EINVAL; - - pac = sock_kmalloc(sk, sizeof(struct ipv6_ac_socklist), GFP_KERNEL); - if (!pac) - return -ENOMEM; - pac->acl_next = NULL; - pac->acl_addr = *addr; - - if (ifindex == 0) { - struct rt6_info *rt; - - rt = rt6_lookup(net, addr, NULL, 0, 0); - if (rt) { - dev = rt->dst.dev; - ip6_rt_put(rt); - } else if (ishost) { - err = -EADDRNOTAVAIL; - goto error; - } else { - /* router, no matching interface: just pick one */ - dev = __dev_get_by_flags(net, IFF_UP, - IFF_UP | IFF_LOOPBACK); - } - } else - dev = __dev_get_by_index(net, ifindex); - - if (!dev) { - err = -ENODEV; - goto error; - } - - idev = __in6_dev_get(dev); - if (!idev) { - if (ifindex) - err = -ENODEV; - else - err = -EADDRNOTAVAIL; - goto error; - } - /* reset ishost, now that we have a specific device */ - ishost = !idev->cnf.forwarding; - - pac->acl_ifindex = dev->ifindex; - - /* XXX - * For hosts, allow link-local or matching prefix anycasts. - * This obviates the need for propagating anycast routes while - * still allowing some non-router anycast participation. - */ - if (!ipv6_chk_prefix(addr, dev)) { - if (ishost) - err = -EADDRNOTAVAIL; - if (err) - goto error; - } - - err = __ipv6_dev_ac_inc(idev, addr); - if (!err) { - pac->acl_next = np->ipv6_ac_list; - np->ipv6_ac_list = pac; - pac = NULL; - } - -error: - if (pac) - sock_kfree_s(sk, pac, sizeof(*pac)); - return err; -} - -/* - * socket leave an anycast group - */ -int ipv6_sock_ac_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct net_device *dev; - struct ipv6_ac_socklist *pac, *prev_pac; - struct net *net = sock_net(sk); - - ASSERT_RTNL(); - - prev_pac = NULL; - for (pac = np->ipv6_ac_list; pac; pac = pac->acl_next) { - if ((ifindex == 0 || pac->acl_ifindex == ifindex) && - ipv6_addr_equal(&pac->acl_addr, addr)) - break; - prev_pac = pac; - } - if (!pac) - return -ENOENT; - if (prev_pac) - prev_pac->acl_next = pac->acl_next; - else - np->ipv6_ac_list = pac->acl_next; - - dev = __dev_get_by_index(net, pac->acl_ifindex); - if (dev) - ipv6_dev_ac_dec(dev, &pac->acl_addr); - - sock_kfree_s(sk, pac, sizeof(*pac)); - return 0; -} - -void ipv6_sock_ac_close(struct sock *sk) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct net_device *dev = NULL; - struct ipv6_ac_socklist *pac; - struct net *net = sock_net(sk); - int prev_index; - - if (!np->ipv6_ac_list) - return; - - rtnl_lock(); - pac = np->ipv6_ac_list; - np->ipv6_ac_list = NULL; - - prev_index = 0; - while (pac) { - struct ipv6_ac_socklist *next = pac->acl_next; - - if (pac->acl_ifindex != prev_index) { - dev = __dev_get_by_index(net, pac->acl_ifindex); - prev_index = pac->acl_ifindex; - } - if (dev) - ipv6_dev_ac_dec(dev, &pac->acl_addr); - sock_kfree_s(sk, pac, sizeof(*pac)); - pac = next; - } - rtnl_unlock(); -} - -static void aca_get(struct ifacaddr6 *aca) -{ - atomic_inc(&aca->aca_refcnt); -} - -static void aca_put(struct ifacaddr6 *ac) -{ - if (atomic_dec_and_test(&ac->aca_refcnt)) { - in6_dev_put(ac->aca_idev); - dst_release(&ac->aca_rt->dst); - kfree(ac); - } -} - -static struct ifacaddr6 *aca_alloc(struct rt6_info *rt, - const struct in6_addr *addr) -{ - struct inet6_dev *idev = rt->rt6i_idev; - struct ifacaddr6 *aca; - - aca = kzalloc(sizeof(*aca), GFP_ATOMIC); - if (!aca) - return NULL; - - aca->aca_addr = *addr; - in6_dev_hold(idev); - aca->aca_idev = idev; - aca->aca_rt = rt; - aca->aca_users = 1; - /* aca_tstamp should be updated upon changes */ - aca->aca_cstamp = aca->aca_tstamp = jiffies; - atomic_set(&aca->aca_refcnt, 1); - - return aca; -} - -/* - * device anycast group inc (add if not found) - */ -int __ipv6_dev_ac_inc(struct inet6_dev *idev, const struct in6_addr *addr) -{ - struct ifacaddr6 *aca; - struct rt6_info *rt; - int err; - - ASSERT_RTNL(); - - write_lock_bh(&idev->lock); - if (idev->dead) { - err = -ENODEV; - goto out; - } - - for (aca = idev->ac_list; aca; aca = aca->aca_next) { - if (ipv6_addr_equal(&aca->aca_addr, addr)) { - aca->aca_users++; - err = 0; - goto out; - } - } - - rt = addrconf_dst_alloc(idev, addr, true); - if (IS_ERR(rt)) { - err = PTR_ERR(rt); - goto out; - } - aca = aca_alloc(rt, addr); - if (!aca) { - ip6_rt_put(rt); - err = -ENOMEM; - goto out; - } - - aca->aca_next = idev->ac_list; - idev->ac_list = aca; - - /* Hold this for addrconf_join_solict() below before we unlock, - * it is already exposed via idev->ac_list. - */ - aca_get(aca); - write_unlock_bh(&idev->lock); - - ip6_ins_rt(rt); - - addrconf_join_solict(idev->dev, &aca->aca_addr); - - aca_put(aca); - return 0; -out: - write_unlock_bh(&idev->lock); - return err; -} - -/* - * device anycast group decrement - */ -int __ipv6_dev_ac_dec(struct inet6_dev *idev, const struct in6_addr *addr) -{ - struct ifacaddr6 *aca, *prev_aca; - - ASSERT_RTNL(); - - write_lock_bh(&idev->lock); - prev_aca = NULL; - for (aca = idev->ac_list; aca; aca = aca->aca_next) { - if (ipv6_addr_equal(&aca->aca_addr, addr)) - break; - prev_aca = aca; - } - if (!aca) { - write_unlock_bh(&idev->lock); - return -ENOENT; - } - if (--aca->aca_users > 0) { - write_unlock_bh(&idev->lock); - return 0; - } - if (prev_aca) - prev_aca->aca_next = aca->aca_next; - else - idev->ac_list = aca->aca_next; - write_unlock_bh(&idev->lock); - addrconf_leave_solict(idev, &aca->aca_addr); - - dst_hold(&aca->aca_rt->dst); - ip6_del_rt(aca->aca_rt); - - aca_put(aca); - return 0; -} - -/* called with rtnl_lock() */ -static int ipv6_dev_ac_dec(struct net_device *dev, const struct in6_addr *addr) -{ - struct inet6_dev *idev = __in6_dev_get(dev); - - if (!idev) - return -ENODEV; - return __ipv6_dev_ac_dec(idev, addr); -} - -void ipv6_ac_destroy_dev(struct inet6_dev *idev) -{ - struct ifacaddr6 *aca; - - write_lock_bh(&idev->lock); - while ((aca = idev->ac_list) != NULL) { - idev->ac_list = aca->aca_next; - write_unlock_bh(&idev->lock); - - addrconf_leave_solict(idev, &aca->aca_addr); - - dst_hold(&aca->aca_rt->dst); - ip6_del_rt(aca->aca_rt); - - aca_put(aca); - - write_lock_bh(&idev->lock); - } - write_unlock_bh(&idev->lock); -} - -/* - * check if the interface has this anycast address - * called with rcu_read_lock() - */ -static bool ipv6_chk_acast_dev(struct net_device *dev, const struct in6_addr *addr) -{ - struct inet6_dev *idev; - struct ifacaddr6 *aca; - - idev = __in6_dev_get(dev); - if (idev) { - read_lock_bh(&idev->lock); - for (aca = idev->ac_list; aca; aca = aca->aca_next) - if (ipv6_addr_equal(&aca->aca_addr, addr)) - break; - read_unlock_bh(&idev->lock); - return aca != NULL; - } - return false; -} - -/* - * check if given interface (or any, if dev==0) has this anycast address - */ -bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev, - const struct in6_addr *addr) -{ - bool found = false; - - rcu_read_lock(); - if (dev) - found = ipv6_chk_acast_dev(dev, addr); - else - for_each_netdev_rcu(net, dev) - if (ipv6_chk_acast_dev(dev, addr)) { - found = true; - break; - } - rcu_read_unlock(); - return found; -} - -/* check if this anycast address is link-local on given interface or - * is global - */ -bool ipv6_chk_acast_addr_src(struct net *net, struct net_device *dev, - const struct in6_addr *addr) -{ - return ipv6_chk_acast_addr(net, - (ipv6_addr_type(addr) & IPV6_ADDR_LINKLOCAL ? - dev : NULL), - addr); -} - -#ifdef CONFIG_PROC_FS -struct ac6_iter_state { - struct seq_net_private p; - struct net_device *dev; - struct inet6_dev *idev; -}; - -#define ac6_seq_private(seq) ((struct ac6_iter_state *)(seq)->private) - -static inline struct ifacaddr6 *ac6_get_first(struct seq_file *seq) -{ - struct ifacaddr6 *im = NULL; - struct ac6_iter_state *state = ac6_seq_private(seq); - struct net *net = seq_file_net(seq); - - state->idev = NULL; - for_each_netdev_rcu(net, state->dev) { - struct inet6_dev *idev; - idev = __in6_dev_get(state->dev); - if (!idev) - continue; - read_lock_bh(&idev->lock); - im = idev->ac_list; - if (im) { - state->idev = idev; - break; - } - read_unlock_bh(&idev->lock); - } - return im; -} - -static struct ifacaddr6 *ac6_get_next(struct seq_file *seq, struct ifacaddr6 *im) -{ - struct ac6_iter_state *state = ac6_seq_private(seq); - - im = im->aca_next; - while (!im) { - if (likely(state->idev != NULL)) - read_unlock_bh(&state->idev->lock); - - state->dev = next_net_device_rcu(state->dev); - if (!state->dev) { - state->idev = NULL; - break; - } - state->idev = __in6_dev_get(state->dev); - if (!state->idev) - continue; - read_lock_bh(&state->idev->lock); - im = state->idev->ac_list; - } - return im; -} - -static struct ifacaddr6 *ac6_get_idx(struct seq_file *seq, loff_t pos) -{ - struct ifacaddr6 *im = ac6_get_first(seq); - if (im) - while (pos && (im = ac6_get_next(seq, im)) != NULL) - --pos; - return pos ? NULL : im; -} - -static void *ac6_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(RCU) -{ - rcu_read_lock(); - return ac6_get_idx(seq, *pos); -} - -static void *ac6_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct ifacaddr6 *im = ac6_get_next(seq, v); - - ++*pos; - return im; -} - -static void ac6_seq_stop(struct seq_file *seq, void *v) - __releases(RCU) -{ - struct ac6_iter_state *state = ac6_seq_private(seq); - - if (likely(state->idev != NULL)) { - read_unlock_bh(&state->idev->lock); - state->idev = NULL; - } - rcu_read_unlock(); -} - -static int ac6_seq_show(struct seq_file *seq, void *v) -{ - struct ifacaddr6 *im = (struct ifacaddr6 *)v; - struct ac6_iter_state *state = ac6_seq_private(seq); - - seq_printf(seq, "%-4d %-15s %pi6 %5d\n", - state->dev->ifindex, state->dev->name, - &im->aca_addr, im->aca_users); - return 0; -} - -static const struct seq_operations ac6_seq_ops = { - .start = ac6_seq_start, - .next = ac6_seq_next, - .stop = ac6_seq_stop, - .show = ac6_seq_show, -}; - -static int ac6_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &ac6_seq_ops, - sizeof(struct ac6_iter_state)); -} - -static const struct file_operations ac6_seq_fops = { - .owner = THIS_MODULE, - .open = ac6_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -int __net_init ac6_proc_init(struct net *net) -{ - if (!proc_create("anycast6", S_IRUGO, net->proc_net, &ac6_seq_fops)) - return -ENOMEM; - - return 0; -} - -void ac6_proc_exit(struct net *net) -{ - remove_proc_entry("anycast6", net->proc_net); -} -#endif - diff --git a/src/linux/net/ipv6/datagram.c b/src/linux/net/ipv6/datagram.c deleted file mode 100644 index ccf4055..0000000 --- a/src/linux/net/ipv6/datagram.c +++ /dev/null @@ -1,1038 +0,0 @@ -/* - * common UDP/RAW code - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -static bool ipv6_mapped_addr_any(const struct in6_addr *a) -{ - return ipv6_addr_v4mapped(a) && (a->s6_addr32[3] == 0); -} - -static void ip6_datagram_flow_key_init(struct flowi6 *fl6, struct sock *sk) -{ - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *np = inet6_sk(sk); - - memset(fl6, 0, sizeof(*fl6)); - fl6->flowi6_proto = sk->sk_protocol; - fl6->daddr = sk->sk_v6_daddr; - fl6->saddr = np->saddr; - fl6->flowi6_oif = sk->sk_bound_dev_if; - fl6->flowi6_mark = sk->sk_mark; - fl6->fl6_dport = inet->inet_dport; - fl6->fl6_sport = inet->inet_sport; - fl6->flowlabel = np->flow_label; - - if (!fl6->flowi6_oif) - fl6->flowi6_oif = np->sticky_pktinfo.ipi6_ifindex; - - if (!fl6->flowi6_oif && ipv6_addr_is_multicast(&fl6->daddr)) - fl6->flowi6_oif = np->mcast_oif; - - security_sk_classify_flow(sk, flowi6_to_flowi(fl6)); -} - -int ip6_datagram_dst_update(struct sock *sk, bool fix_sk_saddr) -{ - struct ip6_flowlabel *flowlabel = NULL; - struct in6_addr *final_p, final; - struct ipv6_txoptions *opt; - struct dst_entry *dst; - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *np = inet6_sk(sk); - struct flowi6 fl6; - int err = 0; - - if (np->sndflow && (np->flow_label & IPV6_FLOWLABEL_MASK)) { - flowlabel = fl6_sock_lookup(sk, np->flow_label); - if (!flowlabel) - return -EINVAL; - } - ip6_datagram_flow_key_init(&fl6, sk); - - rcu_read_lock(); - opt = flowlabel ? flowlabel->opt : rcu_dereference(np->opt); - final_p = fl6_update_dst(&fl6, opt, &final); - rcu_read_unlock(); - - dst = ip6_dst_lookup_flow(sk, &fl6, final_p); - if (IS_ERR(dst)) { - err = PTR_ERR(dst); - goto out; - } - - if (fix_sk_saddr) { - if (ipv6_addr_any(&np->saddr)) - np->saddr = fl6.saddr; - - if (ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { - sk->sk_v6_rcv_saddr = fl6.saddr; - inet->inet_rcv_saddr = LOOPBACK4_IPV6; - if (sk->sk_prot->rehash) - sk->sk_prot->rehash(sk); - } - } - - ip6_dst_store(sk, dst, - ipv6_addr_equal(&fl6.daddr, &sk->sk_v6_daddr) ? - &sk->sk_v6_daddr : NULL, -#ifdef CONFIG_IPV6_SUBTREES - ipv6_addr_equal(&fl6.saddr, &np->saddr) ? - &np->saddr : -#endif - NULL); - -out: - fl6_sock_release(flowlabel); - return err; -} - -void ip6_datagram_release_cb(struct sock *sk) -{ - struct dst_entry *dst; - - if (ipv6_addr_v4mapped(&sk->sk_v6_daddr)) - return; - - rcu_read_lock(); - dst = __sk_dst_get(sk); - if (!dst || !dst->obsolete || - dst->ops->check(dst, inet6_sk(sk)->dst_cookie)) { - rcu_read_unlock(); - return; - } - rcu_read_unlock(); - - ip6_datagram_dst_update(sk, false); -} -EXPORT_SYMBOL_GPL(ip6_datagram_release_cb); - -int __ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, - int addr_len) -{ - struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *np = inet6_sk(sk); - struct in6_addr *daddr; - int addr_type; - int err; - __be32 fl6_flowlabel = 0; - - if (usin->sin6_family == AF_INET) { - if (__ipv6_only_sock(sk)) - return -EAFNOSUPPORT; - err = __ip4_datagram_connect(sk, uaddr, addr_len); - goto ipv4_connected; - } - - if (addr_len < SIN6_LEN_RFC2133) - return -EINVAL; - - if (usin->sin6_family != AF_INET6) - return -EAFNOSUPPORT; - - if (np->sndflow) - fl6_flowlabel = usin->sin6_flowinfo & IPV6_FLOWINFO_MASK; - - addr_type = ipv6_addr_type(&usin->sin6_addr); - - if (addr_type == IPV6_ADDR_ANY) { - /* - * connect to self - */ - usin->sin6_addr.s6_addr[15] = 0x01; - } - - daddr = &usin->sin6_addr; - - if (addr_type == IPV6_ADDR_MAPPED) { - struct sockaddr_in sin; - - if (__ipv6_only_sock(sk)) { - err = -ENETUNREACH; - goto out; - } - sin.sin_family = AF_INET; - sin.sin_addr.s_addr = daddr->s6_addr32[3]; - sin.sin_port = usin->sin6_port; - - err = __ip4_datagram_connect(sk, - (struct sockaddr *) &sin, - sizeof(sin)); - -ipv4_connected: - if (err) - goto out; - - ipv6_addr_set_v4mapped(inet->inet_daddr, &sk->sk_v6_daddr); - - if (ipv6_addr_any(&np->saddr) || - ipv6_mapped_addr_any(&np->saddr)) - ipv6_addr_set_v4mapped(inet->inet_saddr, &np->saddr); - - if (ipv6_addr_any(&sk->sk_v6_rcv_saddr) || - ipv6_mapped_addr_any(&sk->sk_v6_rcv_saddr)) { - ipv6_addr_set_v4mapped(inet->inet_rcv_saddr, - &sk->sk_v6_rcv_saddr); - if (sk->sk_prot->rehash) - sk->sk_prot->rehash(sk); - } - - goto out; - } - - if (__ipv6_addr_needs_scope_id(addr_type)) { - if (addr_len >= sizeof(struct sockaddr_in6) && - usin->sin6_scope_id) { - if (sk->sk_bound_dev_if && - sk->sk_bound_dev_if != usin->sin6_scope_id) { - err = -EINVAL; - goto out; - } - sk->sk_bound_dev_if = usin->sin6_scope_id; - } - - if (!sk->sk_bound_dev_if && (addr_type & IPV6_ADDR_MULTICAST)) - sk->sk_bound_dev_if = np->mcast_oif; - - /* Connect to link-local address requires an interface */ - if (!sk->sk_bound_dev_if) { - err = -EINVAL; - goto out; - } - } - - sk->sk_v6_daddr = *daddr; - np->flow_label = fl6_flowlabel; - - inet->inet_dport = usin->sin6_port; - - /* - * Check for a route to destination an obtain the - * destination cache for it. - */ - - err = ip6_datagram_dst_update(sk, true); - if (err) - goto out; - - sk->sk_state = TCP_ESTABLISHED; - sk_set_txhash(sk); -out: - return err; -} -EXPORT_SYMBOL_GPL(__ip6_datagram_connect); - -int ip6_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) -{ - int res; - - lock_sock(sk); - res = __ip6_datagram_connect(sk, uaddr, addr_len); - release_sock(sk); - return res; -} -EXPORT_SYMBOL_GPL(ip6_datagram_connect); - -int ip6_datagram_connect_v6_only(struct sock *sk, struct sockaddr *uaddr, - int addr_len) -{ - DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, uaddr); - if (sin6->sin6_family != AF_INET6) - return -EAFNOSUPPORT; - return ip6_datagram_connect(sk, uaddr, addr_len); -} -EXPORT_SYMBOL_GPL(ip6_datagram_connect_v6_only); - -void ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, - __be16 port, u32 info, u8 *payload) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct icmp6hdr *icmph = icmp6_hdr(skb); - struct sock_exterr_skb *serr; - - if (!np->recverr) - return; - - skb = skb_clone(skb, GFP_ATOMIC); - if (!skb) - return; - - skb->protocol = htons(ETH_P_IPV6); - - serr = SKB_EXT_ERR(skb); - serr->ee.ee_errno = err; - serr->ee.ee_origin = SO_EE_ORIGIN_ICMP6; - serr->ee.ee_type = icmph->icmp6_type; - serr->ee.ee_code = icmph->icmp6_code; - serr->ee.ee_pad = 0; - serr->ee.ee_info = info; - serr->ee.ee_data = 0; - serr->addr_offset = (u8 *)&(((struct ipv6hdr *)(icmph + 1))->daddr) - - skb_network_header(skb); - serr->port = port; - - __skb_pull(skb, payload - skb->data); - skb_reset_transport_header(skb); - - if (sock_queue_err_skb(sk, skb)) - kfree_skb(skb); -} - -void ipv6_local_error(struct sock *sk, int err, struct flowi6 *fl6, u32 info) -{ - const struct ipv6_pinfo *np = inet6_sk(sk); - struct sock_exterr_skb *serr; - struct ipv6hdr *iph; - struct sk_buff *skb; - - if (!np->recverr) - return; - - skb = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC); - if (!skb) - return; - - skb->protocol = htons(ETH_P_IPV6); - - skb_put(skb, sizeof(struct ipv6hdr)); - skb_reset_network_header(skb); - iph = ipv6_hdr(skb); - iph->daddr = fl6->daddr; - - serr = SKB_EXT_ERR(skb); - serr->ee.ee_errno = err; - serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL; - serr->ee.ee_type = 0; - serr->ee.ee_code = 0; - serr->ee.ee_pad = 0; - serr->ee.ee_info = info; - serr->ee.ee_data = 0; - serr->addr_offset = (u8 *)&iph->daddr - skb_network_header(skb); - serr->port = fl6->fl6_dport; - - __skb_pull(skb, skb_tail_pointer(skb) - skb->data); - skb_reset_transport_header(skb); - - if (sock_queue_err_skb(sk, skb)) - kfree_skb(skb); -} - -void ipv6_local_rxpmtu(struct sock *sk, struct flowi6 *fl6, u32 mtu) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct ipv6hdr *iph; - struct sk_buff *skb; - struct ip6_mtuinfo *mtu_info; - - if (!np->rxopt.bits.rxpmtu) - return; - - skb = alloc_skb(sizeof(struct ipv6hdr), GFP_ATOMIC); - if (!skb) - return; - - skb_put(skb, sizeof(struct ipv6hdr)); - skb_reset_network_header(skb); - iph = ipv6_hdr(skb); - iph->daddr = fl6->daddr; - - mtu_info = IP6CBMTU(skb); - - mtu_info->ip6m_mtu = mtu; - mtu_info->ip6m_addr.sin6_family = AF_INET6; - mtu_info->ip6m_addr.sin6_port = 0; - mtu_info->ip6m_addr.sin6_flowinfo = 0; - mtu_info->ip6m_addr.sin6_scope_id = fl6->flowi6_oif; - mtu_info->ip6m_addr.sin6_addr = ipv6_hdr(skb)->daddr; - - __skb_pull(skb, skb_tail_pointer(skb) - skb->data); - skb_reset_transport_header(skb); - - skb = xchg(&np->rxpmtu, skb); - kfree_skb(skb); -} - -/* For some errors we have valid addr_offset even with zero payload and - * zero port. Also, addr_offset should be supported if port is set. - */ -static inline bool ipv6_datagram_support_addr(struct sock_exterr_skb *serr) -{ - return serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6 || - serr->ee.ee_origin == SO_EE_ORIGIN_ICMP || - serr->ee.ee_origin == SO_EE_ORIGIN_LOCAL || serr->port; -} - -/* IPv6 supports cmsg on all origins aside from SO_EE_ORIGIN_LOCAL. - * - * At one point, excluding local errors was a quick test to identify icmp/icmp6 - * errors. This is no longer true, but the test remained, so the v6 stack, - * unlike v4, also honors cmsg requests on all wifi and timestamp errors. - * - * Timestamp code paths do not initialize the fields expected by cmsg: - * the PKTINFO fields in skb->cb[]. Fill those in here. - */ -static bool ip6_datagram_support_cmsg(struct sk_buff *skb, - struct sock_exterr_skb *serr) -{ - if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP || - serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) - return true; - - if (serr->ee.ee_origin == SO_EE_ORIGIN_LOCAL) - return false; - - if (!skb->dev) - return false; - - if (skb->protocol == htons(ETH_P_IPV6)) - IP6CB(skb)->iif = skb->dev->ifindex; - else - PKTINFO_SKB_CB(skb)->ipi_ifindex = skb->dev->ifindex; - - return true; -} - -/* - * Handle MSG_ERRQUEUE - */ -int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct sock_exterr_skb *serr; - struct sk_buff *skb; - DECLARE_SOCKADDR(struct sockaddr_in6 *, sin, msg->msg_name); - struct { - struct sock_extended_err ee; - struct sockaddr_in6 offender; - } errhdr; - int err; - int copied; - - err = -EAGAIN; - skb = sock_dequeue_err_skb(sk); - if (!skb) - goto out; - - copied = skb->len; - if (copied > len) { - msg->msg_flags |= MSG_TRUNC; - copied = len; - } - err = skb_copy_datagram_msg(skb, 0, msg, copied); - if (unlikely(err)) { - kfree_skb(skb); - return err; - } - sock_recv_timestamp(msg, sk, skb); - - serr = SKB_EXT_ERR(skb); - - if (sin && ipv6_datagram_support_addr(serr)) { - const unsigned char *nh = skb_network_header(skb); - sin->sin6_family = AF_INET6; - sin->sin6_flowinfo = 0; - sin->sin6_port = serr->port; - if (skb->protocol == htons(ETH_P_IPV6)) { - const struct ipv6hdr *ip6h = container_of((struct in6_addr *)(nh + serr->addr_offset), - struct ipv6hdr, daddr); - sin->sin6_addr = ip6h->daddr; - if (np->sndflow) - sin->sin6_flowinfo = ip6_flowinfo(ip6h); - sin->sin6_scope_id = - ipv6_iface_scope_id(&sin->sin6_addr, - IP6CB(skb)->iif); - } else { - ipv6_addr_set_v4mapped(*(__be32 *)(nh + serr->addr_offset), - &sin->sin6_addr); - sin->sin6_scope_id = 0; - } - *addr_len = sizeof(*sin); - } - - memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err)); - sin = &errhdr.offender; - memset(sin, 0, sizeof(*sin)); - - if (ip6_datagram_support_cmsg(skb, serr)) { - sin->sin6_family = AF_INET6; - if (np->rxopt.all) - ip6_datagram_recv_common_ctl(sk, msg, skb); - if (skb->protocol == htons(ETH_P_IPV6)) { - sin->sin6_addr = ipv6_hdr(skb)->saddr; - if (np->rxopt.all) - ip6_datagram_recv_specific_ctl(sk, msg, skb); - sin->sin6_scope_id = - ipv6_iface_scope_id(&sin->sin6_addr, - IP6CB(skb)->iif); - } else { - ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, - &sin->sin6_addr); - if (inet_sk(sk)->cmsg_flags) - ip_cmsg_recv(msg, skb); - } - } - - put_cmsg(msg, SOL_IPV6, IPV6_RECVERR, sizeof(errhdr), &errhdr); - - /* Now we could try to dump offended packet options */ - - msg->msg_flags |= MSG_ERRQUEUE; - err = copied; - - consume_skb(skb); -out: - return err; -} -EXPORT_SYMBOL_GPL(ipv6_recv_error); - -/* - * Handle IPV6_RECVPATHMTU - */ -int ipv6_recv_rxpmtu(struct sock *sk, struct msghdr *msg, int len, - int *addr_len) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct sk_buff *skb; - struct ip6_mtuinfo mtu_info; - DECLARE_SOCKADDR(struct sockaddr_in6 *, sin, msg->msg_name); - int err; - int copied; - - err = -EAGAIN; - skb = xchg(&np->rxpmtu, NULL); - if (!skb) - goto out; - - copied = skb->len; - if (copied > len) { - msg->msg_flags |= MSG_TRUNC; - copied = len; - } - err = skb_copy_datagram_msg(skb, 0, msg, copied); - if (err) - goto out_free_skb; - - sock_recv_timestamp(msg, sk, skb); - - memcpy(&mtu_info, IP6CBMTU(skb), sizeof(mtu_info)); - - if (sin) { - sin->sin6_family = AF_INET6; - sin->sin6_flowinfo = 0; - sin->sin6_port = 0; - sin->sin6_scope_id = mtu_info.ip6m_addr.sin6_scope_id; - sin->sin6_addr = mtu_info.ip6m_addr.sin6_addr; - *addr_len = sizeof(*sin); - } - - put_cmsg(msg, SOL_IPV6, IPV6_PATHMTU, sizeof(mtu_info), &mtu_info); - - err = copied; - -out_free_skb: - kfree_skb(skb); -out: - return err; -} - - -void ip6_datagram_recv_common_ctl(struct sock *sk, struct msghdr *msg, - struct sk_buff *skb) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - bool is_ipv6 = skb->protocol == htons(ETH_P_IPV6); - - if (np->rxopt.bits.rxinfo) { - struct in6_pktinfo src_info; - - if (is_ipv6) { - src_info.ipi6_ifindex = IP6CB(skb)->iif; - src_info.ipi6_addr = ipv6_hdr(skb)->daddr; - } else { - src_info.ipi6_ifindex = - PKTINFO_SKB_CB(skb)->ipi_ifindex; - ipv6_addr_set_v4mapped(ip_hdr(skb)->daddr, - &src_info.ipi6_addr); - } - - if (src_info.ipi6_ifindex >= 0) - put_cmsg(msg, SOL_IPV6, IPV6_PKTINFO, - sizeof(src_info), &src_info); - } -} - -void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg, - struct sk_buff *skb) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct inet6_skb_parm *opt = IP6CB(skb); - unsigned char *nh = skb_network_header(skb); - - if (np->rxopt.bits.rxhlim) { - int hlim = ipv6_hdr(skb)->hop_limit; - put_cmsg(msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); - } - - if (np->rxopt.bits.rxtclass) { - int tclass = ipv6_get_dsfield(ipv6_hdr(skb)); - put_cmsg(msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); - } - - if (np->rxopt.bits.rxflow) { - __be32 flowinfo = ip6_flowinfo((struct ipv6hdr *)nh); - if (flowinfo) - put_cmsg(msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo); - } - - /* HbH is allowed only once */ - if (np->rxopt.bits.hopopts && (opt->flags & IP6SKB_HOPBYHOP)) { - u8 *ptr = nh + sizeof(struct ipv6hdr); - put_cmsg(msg, SOL_IPV6, IPV6_HOPOPTS, (ptr[1]+1)<<3, ptr); - } - - if (opt->lastopt && - (np->rxopt.bits.dstopts || np->rxopt.bits.srcrt)) { - /* - * Silly enough, but we need to reparse in order to - * report extension headers (except for HbH) - * in order. - * - * Also note that IPV6_RECVRTHDRDSTOPTS is NOT - * (and WILL NOT be) defined because - * IPV6_RECVDSTOPTS is more generic. --yoshfuji - */ - unsigned int off = sizeof(struct ipv6hdr); - u8 nexthdr = ipv6_hdr(skb)->nexthdr; - - while (off <= opt->lastopt) { - unsigned int len; - u8 *ptr = nh + off; - - switch (nexthdr) { - case IPPROTO_DSTOPTS: - nexthdr = ptr[0]; - len = (ptr[1] + 1) << 3; - if (np->rxopt.bits.dstopts) - put_cmsg(msg, SOL_IPV6, IPV6_DSTOPTS, len, ptr); - break; - case IPPROTO_ROUTING: - nexthdr = ptr[0]; - len = (ptr[1] + 1) << 3; - if (np->rxopt.bits.srcrt) - put_cmsg(msg, SOL_IPV6, IPV6_RTHDR, len, ptr); - break; - case IPPROTO_AH: - nexthdr = ptr[0]; - len = (ptr[1] + 2) << 2; - break; - default: - nexthdr = ptr[0]; - len = (ptr[1] + 1) << 3; - break; - } - - off += len; - } - } - - /* socket options in old style */ - if (np->rxopt.bits.rxoinfo) { - struct in6_pktinfo src_info; - - src_info.ipi6_ifindex = opt->iif; - src_info.ipi6_addr = ipv6_hdr(skb)->daddr; - put_cmsg(msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info); - } - if (np->rxopt.bits.rxohlim) { - int hlim = ipv6_hdr(skb)->hop_limit; - put_cmsg(msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim); - } - if (np->rxopt.bits.ohopopts && (opt->flags & IP6SKB_HOPBYHOP)) { - u8 *ptr = nh + sizeof(struct ipv6hdr); - put_cmsg(msg, SOL_IPV6, IPV6_2292HOPOPTS, (ptr[1]+1)<<3, ptr); - } - if (np->rxopt.bits.odstopts && opt->dst0) { - u8 *ptr = nh + opt->dst0; - put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr); - } - if (np->rxopt.bits.osrcrt && opt->srcrt) { - struct ipv6_rt_hdr *rthdr = (struct ipv6_rt_hdr *)(nh + opt->srcrt); - put_cmsg(msg, SOL_IPV6, IPV6_2292RTHDR, (rthdr->hdrlen+1) << 3, rthdr); - } - if (np->rxopt.bits.odstopts && opt->dst1) { - u8 *ptr = nh + opt->dst1; - put_cmsg(msg, SOL_IPV6, IPV6_2292DSTOPTS, (ptr[1]+1)<<3, ptr); - } - if (np->rxopt.bits.rxorigdstaddr) { - struct sockaddr_in6 sin6; - __be16 *ports = (__be16 *) skb_transport_header(skb); - - if (skb_transport_offset(skb) + 4 <= skb->len) { - /* All current transport protocols have the port numbers in the - * first four bytes of the transport header and this function is - * written with this assumption in mind. - */ - - sin6.sin6_family = AF_INET6; - sin6.sin6_addr = ipv6_hdr(skb)->daddr; - sin6.sin6_port = ports[1]; - sin6.sin6_flowinfo = 0; - sin6.sin6_scope_id = - ipv6_iface_scope_id(&ipv6_hdr(skb)->daddr, - opt->iif); - - put_cmsg(msg, SOL_IPV6, IPV6_ORIGDSTADDR, sizeof(sin6), &sin6); - } - } -} - -void ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, - struct sk_buff *skb) -{ - ip6_datagram_recv_common_ctl(sk, msg, skb); - ip6_datagram_recv_specific_ctl(sk, msg, skb); -} -EXPORT_SYMBOL_GPL(ip6_datagram_recv_ctl); - -int ip6_datagram_send_ctl(struct net *net, struct sock *sk, - struct msghdr *msg, struct flowi6 *fl6, - struct ipcm6_cookie *ipc6, struct sockcm_cookie *sockc) -{ - struct in6_pktinfo *src_info; - struct cmsghdr *cmsg; - struct ipv6_rt_hdr *rthdr; - struct ipv6_opt_hdr *hdr; - struct ipv6_txoptions *opt = ipc6->opt; - int len; - int err = 0; - - for_each_cmsghdr(cmsg, msg) { - int addr_type; - - if (!CMSG_OK(msg, cmsg)) { - err = -EINVAL; - goto exit_f; - } - - if (cmsg->cmsg_level == SOL_SOCKET) { - err = __sock_cmsg_send(sk, msg, cmsg, sockc); - if (err) - return err; - continue; - } - - if (cmsg->cmsg_level != SOL_IPV6) - continue; - - switch (cmsg->cmsg_type) { - case IPV6_PKTINFO: - case IPV6_2292PKTINFO: - { - struct net_device *dev = NULL; - - if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct in6_pktinfo))) { - err = -EINVAL; - goto exit_f; - } - - src_info = (struct in6_pktinfo *)CMSG_DATA(cmsg); - - if (src_info->ipi6_ifindex) { - if (fl6->flowi6_oif && - src_info->ipi6_ifindex != fl6->flowi6_oif) - return -EINVAL; - fl6->flowi6_oif = src_info->ipi6_ifindex; - } - - addr_type = __ipv6_addr_type(&src_info->ipi6_addr); - - rcu_read_lock(); - if (fl6->flowi6_oif) { - dev = dev_get_by_index_rcu(net, fl6->flowi6_oif); - if (!dev) { - rcu_read_unlock(); - return -ENODEV; - } - } else if (addr_type & IPV6_ADDR_LINKLOCAL) { - rcu_read_unlock(); - return -EINVAL; - } - - if (addr_type != IPV6_ADDR_ANY) { - int strict = __ipv6_addr_src_scope(addr_type) <= IPV6_ADDR_SCOPE_LINKLOCAL; - if (!(inet_sk(sk)->freebind || inet_sk(sk)->transparent) && - !ipv6_chk_addr(net, &src_info->ipi6_addr, - strict ? dev : NULL, 0) && - !ipv6_chk_acast_addr_src(net, dev, - &src_info->ipi6_addr)) - err = -EINVAL; - else - fl6->saddr = src_info->ipi6_addr; - } - - rcu_read_unlock(); - - if (err) - goto exit_f; - - break; - } - - case IPV6_FLOWINFO: - if (cmsg->cmsg_len < CMSG_LEN(4)) { - err = -EINVAL; - goto exit_f; - } - - if (fl6->flowlabel&IPV6_FLOWINFO_MASK) { - if ((fl6->flowlabel^*(__be32 *)CMSG_DATA(cmsg))&~IPV6_FLOWINFO_MASK) { - err = -EINVAL; - goto exit_f; - } - } - fl6->flowlabel = IPV6_FLOWINFO_MASK & *(__be32 *)CMSG_DATA(cmsg); - break; - - case IPV6_2292HOPOPTS: - case IPV6_HOPOPTS: - if (opt->hopopt || cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) { - err = -EINVAL; - goto exit_f; - } - - hdr = (struct ipv6_opt_hdr *)CMSG_DATA(cmsg); - len = ((hdr->hdrlen + 1) << 3); - if (cmsg->cmsg_len < CMSG_LEN(len)) { - err = -EINVAL; - goto exit_f; - } - if (!ns_capable(net->user_ns, CAP_NET_RAW)) { - err = -EPERM; - goto exit_f; - } - opt->opt_nflen += len; - opt->hopopt = hdr; - break; - - case IPV6_2292DSTOPTS: - if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) { - err = -EINVAL; - goto exit_f; - } - - hdr = (struct ipv6_opt_hdr *)CMSG_DATA(cmsg); - len = ((hdr->hdrlen + 1) << 3); - if (cmsg->cmsg_len < CMSG_LEN(len)) { - err = -EINVAL; - goto exit_f; - } - if (!ns_capable(net->user_ns, CAP_NET_RAW)) { - err = -EPERM; - goto exit_f; - } - if (opt->dst1opt) { - err = -EINVAL; - goto exit_f; - } - opt->opt_flen += len; - opt->dst1opt = hdr; - break; - - case IPV6_DSTOPTS: - case IPV6_RTHDRDSTOPTS: - if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_opt_hdr))) { - err = -EINVAL; - goto exit_f; - } - - hdr = (struct ipv6_opt_hdr *)CMSG_DATA(cmsg); - len = ((hdr->hdrlen + 1) << 3); - if (cmsg->cmsg_len < CMSG_LEN(len)) { - err = -EINVAL; - goto exit_f; - } - if (!ns_capable(net->user_ns, CAP_NET_RAW)) { - err = -EPERM; - goto exit_f; - } - if (cmsg->cmsg_type == IPV6_DSTOPTS) { - opt->opt_flen += len; - opt->dst1opt = hdr; - } else { - opt->opt_nflen += len; - opt->dst0opt = hdr; - } - break; - - case IPV6_2292RTHDR: - case IPV6_RTHDR: - if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct ipv6_rt_hdr))) { - err = -EINVAL; - goto exit_f; - } - - rthdr = (struct ipv6_rt_hdr *)CMSG_DATA(cmsg); - - switch (rthdr->type) { -#if IS_ENABLED(CONFIG_IPV6_MIP6) - case IPV6_SRCRT_TYPE_2: - if (rthdr->hdrlen != 2 || - rthdr->segments_left != 1) { - err = -EINVAL; - goto exit_f; - } - break; -#endif - default: - err = -EINVAL; - goto exit_f; - } - - len = ((rthdr->hdrlen + 1) << 3); - - if (cmsg->cmsg_len < CMSG_LEN(len)) { - err = -EINVAL; - goto exit_f; - } - - /* segments left must also match */ - if ((rthdr->hdrlen >> 1) != rthdr->segments_left) { - err = -EINVAL; - goto exit_f; - } - - opt->opt_nflen += len; - opt->srcrt = rthdr; - - if (cmsg->cmsg_type == IPV6_2292RTHDR && opt->dst1opt) { - int dsthdrlen = ((opt->dst1opt->hdrlen+1)<<3); - - opt->opt_nflen += dsthdrlen; - opt->dst0opt = opt->dst1opt; - opt->dst1opt = NULL; - opt->opt_flen -= dsthdrlen; - } - - break; - - case IPV6_2292HOPLIMIT: - case IPV6_HOPLIMIT: - if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) { - err = -EINVAL; - goto exit_f; - } - - ipc6->hlimit = *(int *)CMSG_DATA(cmsg); - if (ipc6->hlimit < -1 || ipc6->hlimit > 0xff) { - err = -EINVAL; - goto exit_f; - } - - break; - - case IPV6_TCLASS: - { - int tc; - - err = -EINVAL; - if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) - goto exit_f; - - tc = *(int *)CMSG_DATA(cmsg); - if (tc < -1 || tc > 0xff) - goto exit_f; - - err = 0; - ipc6->tclass = tc; - - break; - } - - case IPV6_DONTFRAG: - { - int df; - - err = -EINVAL; - if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) - goto exit_f; - - df = *(int *)CMSG_DATA(cmsg); - if (df < 0 || df > 1) - goto exit_f; - - err = 0; - ipc6->dontfrag = df; - - break; - } - default: - net_dbg_ratelimited("invalid cmsg type: %d\n", - cmsg->cmsg_type); - err = -EINVAL; - goto exit_f; - } - } - -exit_f: - return err; -} -EXPORT_SYMBOL_GPL(ip6_datagram_send_ctl); - -void ip6_dgram_sock_seq_show(struct seq_file *seq, struct sock *sp, - __u16 srcp, __u16 destp, int bucket) -{ - const struct in6_addr *dest, *src; - - dest = &sp->sk_v6_daddr; - src = &sp->sk_v6_rcv_saddr; - seq_printf(seq, - "%5d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " - "%02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %d\n", - bucket, - src->s6_addr32[0], src->s6_addr32[1], - src->s6_addr32[2], src->s6_addr32[3], srcp, - dest->s6_addr32[0], dest->s6_addr32[1], - dest->s6_addr32[2], dest->s6_addr32[3], destp, - sp->sk_state, - sk_wmem_alloc_get(sp), - sk_rmem_alloc_get(sp), - 0, 0L, 0, - from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)), - 0, - sock_i_ino(sp), - atomic_read(&sp->sk_refcnt), sp, - atomic_read(&sp->sk_drops)); -} diff --git a/src/linux/net/ipv6/exthdrs.c b/src/linux/net/ipv6/exthdrs.c deleted file mode 100644 index 139ceb6..0000000 --- a/src/linux/net/ipv6/exthdrs.c +++ /dev/null @@ -1,951 +0,0 @@ -/* - * Extension Header handling for IPv6 - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * Andi Kleen - * Alexey Kuznetsov - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -/* Changes: - * yoshfuji : ensure not to overrun while parsing - * tlv options. - * Mitsuru KANDA @USAGI and: Remove ipv6_parse_exthdrs(). - * YOSHIFUJI Hideaki @USAGI Register inbound extension header - * handlers as inet6_protocol{}. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#if IS_ENABLED(CONFIG_IPV6_MIP6) -#include -#endif - -#include - -/* - * Parsing tlv encoded headers. - * - * Parsing function "func" returns true, if parsing succeed - * and false, if it failed. - * It MUST NOT touch skb->h. - */ - -struct tlvtype_proc { - int type; - bool (*func)(struct sk_buff *skb, int offset); -}; - -/********************* - Generic functions - *********************/ - -/* An unknown option is detected, decide what to do */ - -static bool ip6_tlvopt_unknown(struct sk_buff *skb, int optoff) -{ - switch ((skb_network_header(skb)[optoff] & 0xC0) >> 6) { - case 0: /* ignore */ - return true; - - case 1: /* drop packet */ - break; - - case 3: /* Send ICMP if not a multicast address and drop packet */ - /* Actually, it is redundant check. icmp_send - will recheck in any case. - */ - if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) - break; - case 2: /* send ICMP PARM PROB regardless and drop packet */ - icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff); - return false; - } - - kfree_skb(skb); - return false; -} - -/* Parse tlv encoded option header (hop-by-hop or destination) */ - -static bool ip6_parse_tlv(const struct tlvtype_proc *procs, struct sk_buff *skb) -{ - const struct tlvtype_proc *curr; - const unsigned char *nh = skb_network_header(skb); - int off = skb_network_header_len(skb); - int len = (skb_transport_header(skb)[1] + 1) << 3; - int padlen = 0; - - if (skb_transport_offset(skb) + len > skb_headlen(skb)) - goto bad; - - off += 2; - len -= 2; - - while (len > 0) { - int optlen = nh[off + 1] + 2; - int i; - - switch (nh[off]) { - case IPV6_TLV_PAD1: - optlen = 1; - padlen++; - if (padlen > 7) - goto bad; - break; - - case IPV6_TLV_PADN: - /* RFC 2460 states that the purpose of PadN is - * to align the containing header to multiples - * of 8. 7 is therefore the highest valid value. - * See also RFC 4942, Section 2.1.9.5. - */ - padlen += optlen; - if (padlen > 7) - goto bad; - /* RFC 4942 recommends receiving hosts to - * actively check PadN payload to contain - * only zeroes. - */ - for (i = 2; i < optlen; i++) { - if (nh[off + i] != 0) - goto bad; - } - break; - - default: /* Other TLV code so scan list */ - if (optlen > len) - goto bad; - for (curr = procs; curr->type >= 0; curr++) { - if (curr->type == nh[off]) { - /* type specific length/alignment - checks will be performed in the - func(). */ - if (curr->func(skb, off) == false) - return false; - break; - } - } - if (curr->type < 0) { - if (ip6_tlvopt_unknown(skb, off) == 0) - return false; - } - padlen = 0; - break; - } - off += optlen; - len -= optlen; - } - - if (len == 0) - return true; -bad: - kfree_skb(skb); - return false; -} - -/***************************** - Destination options header. - *****************************/ - -#if IS_ENABLED(CONFIG_IPV6_MIP6) -static bool ipv6_dest_hao(struct sk_buff *skb, int optoff) -{ - struct ipv6_destopt_hao *hao; - struct inet6_skb_parm *opt = IP6CB(skb); - struct ipv6hdr *ipv6h = ipv6_hdr(skb); - struct in6_addr tmp_addr; - int ret; - - if (opt->dsthao) { - net_dbg_ratelimited("hao duplicated\n"); - goto discard; - } - opt->dsthao = opt->dst1; - opt->dst1 = 0; - - hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) + optoff); - - if (hao->length != 16) { - net_dbg_ratelimited("hao invalid option length = %d\n", - hao->length); - goto discard; - } - - if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) { - net_dbg_ratelimited("hao is not an unicast addr: %pI6\n", - &hao->addr); - goto discard; - } - - ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr, - (xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS); - if (unlikely(ret < 0)) - goto discard; - - if (skb_cloned(skb)) { - if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) - goto discard; - - /* update all variable using below by copied skbuff */ - hao = (struct ipv6_destopt_hao *)(skb_network_header(skb) + - optoff); - ipv6h = ipv6_hdr(skb); - } - - if (skb->ip_summed == CHECKSUM_COMPLETE) - skb->ip_summed = CHECKSUM_NONE; - - tmp_addr = ipv6h->saddr; - ipv6h->saddr = hao->addr; - hao->addr = tmp_addr; - - if (skb->tstamp.tv64 == 0) - __net_timestamp(skb); - - return true; - - discard: - kfree_skb(skb); - return false; -} -#endif - -static const struct tlvtype_proc tlvprocdestopt_lst[] = { -#if IS_ENABLED(CONFIG_IPV6_MIP6) - { - .type = IPV6_TLV_HAO, - .func = ipv6_dest_hao, - }, -#endif - {-1, NULL} -}; - -static int ipv6_destopt_rcv(struct sk_buff *skb) -{ - struct inet6_skb_parm *opt = IP6CB(skb); -#if IS_ENABLED(CONFIG_IPV6_MIP6) - __u16 dstbuf; -#endif - struct dst_entry *dst = skb_dst(skb); - - if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) || - !pskb_may_pull(skb, (skb_transport_offset(skb) + - ((skb_transport_header(skb)[1] + 1) << 3)))) { - __IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst), - IPSTATS_MIB_INHDRERRORS); - kfree_skb(skb); - return -1; - } - - opt->lastopt = opt->dst1 = skb_network_header_len(skb); -#if IS_ENABLED(CONFIG_IPV6_MIP6) - dstbuf = opt->dst1; -#endif - - if (ip6_parse_tlv(tlvprocdestopt_lst, skb)) { - skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3; - opt = IP6CB(skb); -#if IS_ENABLED(CONFIG_IPV6_MIP6) - opt->nhoff = dstbuf; -#else - opt->nhoff = opt->dst1; -#endif - return 1; - } - - __IP6_INC_STATS(dev_net(dst->dev), - ip6_dst_idev(dst), IPSTATS_MIB_INHDRERRORS); - return -1; -} - -/******************************** - Routing header. - ********************************/ - -/* called with rcu_read_lock() */ -static int ipv6_rthdr_rcv(struct sk_buff *skb) -{ - struct inet6_skb_parm *opt = IP6CB(skb); - struct in6_addr *addr = NULL; - struct in6_addr daddr; - struct inet6_dev *idev; - int n, i; - struct ipv6_rt_hdr *hdr; - struct rt0_hdr *rthdr; - struct net *net = dev_net(skb->dev); - int accept_source_route = net->ipv6.devconf_all->accept_source_route; - - idev = __in6_dev_get(skb->dev); - if (idev && accept_source_route > idev->cnf.accept_source_route) - accept_source_route = idev->cnf.accept_source_route; - - if (!pskb_may_pull(skb, skb_transport_offset(skb) + 8) || - !pskb_may_pull(skb, (skb_transport_offset(skb) + - ((skb_transport_header(skb)[1] + 1) << 3)))) { - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_INHDRERRORS); - kfree_skb(skb); - return -1; - } - - hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb); - - if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr) || - skb->pkt_type != PACKET_HOST) { - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_INADDRERRORS); - kfree_skb(skb); - return -1; - } - -looped_back: - if (hdr->segments_left == 0) { - switch (hdr->type) { -#if IS_ENABLED(CONFIG_IPV6_MIP6) - case IPV6_SRCRT_TYPE_2: - /* Silently discard type 2 header unless it was - * processed by own - */ - if (!addr) { - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_INADDRERRORS); - kfree_skb(skb); - return -1; - } - break; -#endif - default: - break; - } - - opt->lastopt = opt->srcrt = skb_network_header_len(skb); - skb->transport_header += (hdr->hdrlen + 1) << 3; - opt->dst0 = opt->dst1; - opt->dst1 = 0; - opt->nhoff = (&hdr->nexthdr) - skb_network_header(skb); - return 1; - } - - switch (hdr->type) { -#if IS_ENABLED(CONFIG_IPV6_MIP6) - case IPV6_SRCRT_TYPE_2: - if (accept_source_route < 0) - goto unknown_rh; - /* Silently discard invalid RTH type 2 */ - if (hdr->hdrlen != 2 || hdr->segments_left != 1) { - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_INHDRERRORS); - kfree_skb(skb); - return -1; - } - break; -#endif - default: - goto unknown_rh; - } - - /* - * This is the routing header forwarding algorithm from - * RFC 2460, page 16. - */ - - n = hdr->hdrlen >> 1; - - if (hdr->segments_left > n) { - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_INHDRERRORS); - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, - ((&hdr->segments_left) - - skb_network_header(skb))); - return -1; - } - - /* We are about to mangle packet header. Be careful! - Do not damage packets queued somewhere. - */ - if (skb_cloned(skb)) { - /* the copy is a forwarded packet */ - if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_OUTDISCARDS); - kfree_skb(skb); - return -1; - } - hdr = (struct ipv6_rt_hdr *)skb_transport_header(skb); - } - - if (skb->ip_summed == CHECKSUM_COMPLETE) - skb->ip_summed = CHECKSUM_NONE; - - i = n - --hdr->segments_left; - - rthdr = (struct rt0_hdr *) hdr; - addr = rthdr->addr; - addr += i - 1; - - switch (hdr->type) { -#if IS_ENABLED(CONFIG_IPV6_MIP6) - case IPV6_SRCRT_TYPE_2: - if (xfrm6_input_addr(skb, (xfrm_address_t *)addr, - (xfrm_address_t *)&ipv6_hdr(skb)->saddr, - IPPROTO_ROUTING) < 0) { - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_INADDRERRORS); - kfree_skb(skb); - return -1; - } - if (!ipv6_chk_home_addr(dev_net(skb_dst(skb)->dev), addr)) { - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_INADDRERRORS); - kfree_skb(skb); - return -1; - } - break; -#endif - default: - break; - } - - if (ipv6_addr_is_multicast(addr)) { - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_INADDRERRORS); - kfree_skb(skb); - return -1; - } - - daddr = *addr; - *addr = ipv6_hdr(skb)->daddr; - ipv6_hdr(skb)->daddr = daddr; - - skb_dst_drop(skb); - ip6_route_input(skb); - if (skb_dst(skb)->error) { - skb_push(skb, skb->data - skb_network_header(skb)); - dst_input(skb); - return -1; - } - - if (skb_dst(skb)->dev->flags&IFF_LOOPBACK) { - if (ipv6_hdr(skb)->hop_limit <= 1) { - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_INHDRERRORS); - icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, - 0); - kfree_skb(skb); - return -1; - } - ipv6_hdr(skb)->hop_limit--; - goto looped_back; - } - - skb_push(skb, skb->data - skb_network_header(skb)); - dst_input(skb); - return -1; - -unknown_rh: - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INHDRERRORS); - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, - (&hdr->type) - skb_network_header(skb)); - return -1; -} - -static const struct inet6_protocol rthdr_protocol = { - .handler = ipv6_rthdr_rcv, - .flags = INET6_PROTO_NOPOLICY, -}; - -static const struct inet6_protocol destopt_protocol = { - .handler = ipv6_destopt_rcv, - .flags = INET6_PROTO_NOPOLICY, -}; - -static const struct inet6_protocol nodata_protocol = { - .handler = dst_discard, - .flags = INET6_PROTO_NOPOLICY, -}; - -int __init ipv6_exthdrs_init(void) -{ - int ret; - - ret = inet6_add_protocol(&rthdr_protocol, IPPROTO_ROUTING); - if (ret) - goto out; - - ret = inet6_add_protocol(&destopt_protocol, IPPROTO_DSTOPTS); - if (ret) - goto out_rthdr; - - ret = inet6_add_protocol(&nodata_protocol, IPPROTO_NONE); - if (ret) - goto out_destopt; - -out: - return ret; -out_destopt: - inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS); -out_rthdr: - inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING); - goto out; -}; - -void ipv6_exthdrs_exit(void) -{ - inet6_del_protocol(&nodata_protocol, IPPROTO_NONE); - inet6_del_protocol(&destopt_protocol, IPPROTO_DSTOPTS); - inet6_del_protocol(&rthdr_protocol, IPPROTO_ROUTING); -} - -/********************************** - Hop-by-hop options. - **********************************/ - -/* - * Note: we cannot rely on skb_dst(skb) before we assign it in ip6_route_input(). - */ -static inline struct inet6_dev *ipv6_skb_idev(struct sk_buff *skb) -{ - return skb_dst(skb) ? ip6_dst_idev(skb_dst(skb)) : __in6_dev_get(skb->dev); -} - -static inline struct net *ipv6_skb_net(struct sk_buff *skb) -{ - return skb_dst(skb) ? dev_net(skb_dst(skb)->dev) : dev_net(skb->dev); -} - -/* Router Alert as of RFC 2711 */ - -static bool ipv6_hop_ra(struct sk_buff *skb, int optoff) -{ - const unsigned char *nh = skb_network_header(skb); - - if (nh[optoff + 1] == 2) { - IP6CB(skb)->flags |= IP6SKB_ROUTERALERT; - memcpy(&IP6CB(skb)->ra, nh + optoff + 2, sizeof(IP6CB(skb)->ra)); - return true; - } - net_dbg_ratelimited("ipv6_hop_ra: wrong RA length %d\n", - nh[optoff + 1]); - kfree_skb(skb); - return false; -} - -/* Jumbo payload */ - -static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff) -{ - const unsigned char *nh = skb_network_header(skb); - struct net *net = ipv6_skb_net(skb); - u32 pkt_len; - - if (nh[optoff + 1] != 4 || (optoff & 3) != 2) { - net_dbg_ratelimited("ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n", - nh[optoff+1]); - __IP6_INC_STATS(net, ipv6_skb_idev(skb), - IPSTATS_MIB_INHDRERRORS); - goto drop; - } - - pkt_len = ntohl(*(__be32 *)(nh + optoff + 2)); - if (pkt_len <= IPV6_MAXPLEN) { - __IP6_INC_STATS(net, ipv6_skb_idev(skb), - IPSTATS_MIB_INHDRERRORS); - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2); - return false; - } - if (ipv6_hdr(skb)->payload_len) { - __IP6_INC_STATS(net, ipv6_skb_idev(skb), - IPSTATS_MIB_INHDRERRORS); - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff); - return false; - } - - if (pkt_len > skb->len - sizeof(struct ipv6hdr)) { - __IP6_INC_STATS(net, ipv6_skb_idev(skb), - IPSTATS_MIB_INTRUNCATEDPKTS); - goto drop; - } - - if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) - goto drop; - - return true; - -drop: - kfree_skb(skb); - return false; -} - -/* CALIPSO RFC 5570 */ - -static bool ipv6_hop_calipso(struct sk_buff *skb, int optoff) -{ - const unsigned char *nh = skb_network_header(skb); - - if (nh[optoff + 1] < 8) - goto drop; - - if (nh[optoff + 6] * 4 + 8 > nh[optoff + 1]) - goto drop; - - if (!calipso_validate(skb, nh + optoff)) - goto drop; - - return true; - -drop: - kfree_skb(skb); - return false; -} - -static const struct tlvtype_proc tlvprochopopt_lst[] = { - { - .type = IPV6_TLV_ROUTERALERT, - .func = ipv6_hop_ra, - }, - { - .type = IPV6_TLV_JUMBO, - .func = ipv6_hop_jumbo, - }, - { - .type = IPV6_TLV_CALIPSO, - .func = ipv6_hop_calipso, - }, - { -1, } -}; - -int ipv6_parse_hopopts(struct sk_buff *skb) -{ - struct inet6_skb_parm *opt = IP6CB(skb); - - /* - * skb_network_header(skb) is equal to skb->data, and - * skb_network_header_len(skb) is always equal to - * sizeof(struct ipv6hdr) by definition of - * hop-by-hop options. - */ - if (!pskb_may_pull(skb, sizeof(struct ipv6hdr) + 8) || - !pskb_may_pull(skb, (sizeof(struct ipv6hdr) + - ((skb_transport_header(skb)[1] + 1) << 3)))) { - kfree_skb(skb); - return -1; - } - - opt->flags |= IP6SKB_HOPBYHOP; - if (ip6_parse_tlv(tlvprochopopt_lst, skb)) { - skb->transport_header += (skb_transport_header(skb)[1] + 1) << 3; - opt = IP6CB(skb); - opt->nhoff = sizeof(struct ipv6hdr); - return 1; - } - return -1; -} - -/* - * Creating outbound headers. - * - * "build" functions work when skb is filled from head to tail (datagram) - * "push" functions work when headers are added from tail to head (tcp) - * - * In both cases we assume, that caller reserved enough room - * for headers. - */ - -static void ipv6_push_rthdr(struct sk_buff *skb, u8 *proto, - struct ipv6_rt_hdr *opt, - struct in6_addr **addr_p) -{ - struct rt0_hdr *phdr, *ihdr; - int hops; - - ihdr = (struct rt0_hdr *) opt; - - phdr = (struct rt0_hdr *) skb_push(skb, (ihdr->rt_hdr.hdrlen + 1) << 3); - memcpy(phdr, ihdr, sizeof(struct rt0_hdr)); - - hops = ihdr->rt_hdr.hdrlen >> 1; - - if (hops > 1) - memcpy(phdr->addr, ihdr->addr + 1, - (hops - 1) * sizeof(struct in6_addr)); - - phdr->addr[hops - 1] = **addr_p; - *addr_p = ihdr->addr; - - phdr->rt_hdr.nexthdr = *proto; - *proto = NEXTHDR_ROUTING; -} - -static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, u8 type, struct ipv6_opt_hdr *opt) -{ - struct ipv6_opt_hdr *h = (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt)); - - memcpy(h, opt, ipv6_optlen(opt)); - h->nexthdr = *proto; - *proto = type; -} - -void ipv6_push_nfrag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, - u8 *proto, - struct in6_addr **daddr) -{ - if (opt->srcrt) { - ipv6_push_rthdr(skb, proto, opt->srcrt, daddr); - /* - * IPV6_RTHDRDSTOPTS is ignored - * unless IPV6_RTHDR is set (RFC3542). - */ - if (opt->dst0opt) - ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst0opt); - } - if (opt->hopopt) - ipv6_push_exthdr(skb, proto, NEXTHDR_HOP, opt->hopopt); -} -EXPORT_SYMBOL(ipv6_push_nfrag_opts); - -void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, u8 *proto) -{ - if (opt->dst1opt) - ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt); -} - -struct ipv6_txoptions * -ipv6_dup_options(struct sock *sk, struct ipv6_txoptions *opt) -{ - struct ipv6_txoptions *opt2; - - opt2 = sock_kmalloc(sk, opt->tot_len, GFP_ATOMIC); - if (opt2) { - long dif = (char *)opt2 - (char *)opt; - memcpy(opt2, opt, opt->tot_len); - if (opt2->hopopt) - *((char **)&opt2->hopopt) += dif; - if (opt2->dst0opt) - *((char **)&opt2->dst0opt) += dif; - if (opt2->dst1opt) - *((char **)&opt2->dst1opt) += dif; - if (opt2->srcrt) - *((char **)&opt2->srcrt) += dif; - atomic_set(&opt2->refcnt, 1); - } - return opt2; -} -EXPORT_SYMBOL_GPL(ipv6_dup_options); - -static int ipv6_renew_option(void *ohdr, - struct ipv6_opt_hdr __user *newopt, int newoptlen, - int inherit, - struct ipv6_opt_hdr **hdr, - char **p) -{ - if (inherit) { - if (ohdr) { - memcpy(*p, ohdr, ipv6_optlen((struct ipv6_opt_hdr *)ohdr)); - *hdr = (struct ipv6_opt_hdr *)*p; - *p += CMSG_ALIGN(ipv6_optlen(*hdr)); - } - } else { - if (newopt) { - if (copy_from_user(*p, newopt, newoptlen)) - return -EFAULT; - *hdr = (struct ipv6_opt_hdr *)*p; - if (ipv6_optlen(*hdr) > newoptlen) - return -EINVAL; - *p += CMSG_ALIGN(newoptlen); - } - } - return 0; -} - -/** - * ipv6_renew_options - replace a specific ext hdr with a new one. - * - * @sk: sock from which to allocate memory - * @opt: original options - * @newtype: option type to replace in @opt - * @newopt: new option of type @newtype to replace (user-mem) - * @newoptlen: length of @newopt - * - * Returns a new set of options which is a copy of @opt with the - * option type @newtype replaced with @newopt. - * - * @opt may be NULL, in which case a new set of options is returned - * containing just @newopt. - * - * @newopt may be NULL, in which case the specified option type is - * not copied into the new set of options. - * - * The new set of options is allocated from the socket option memory - * buffer of @sk. - */ -struct ipv6_txoptions * -ipv6_renew_options(struct sock *sk, struct ipv6_txoptions *opt, - int newtype, - struct ipv6_opt_hdr __user *newopt, int newoptlen) -{ - int tot_len = 0; - char *p; - struct ipv6_txoptions *opt2; - int err; - - if (opt) { - if (newtype != IPV6_HOPOPTS && opt->hopopt) - tot_len += CMSG_ALIGN(ipv6_optlen(opt->hopopt)); - if (newtype != IPV6_RTHDRDSTOPTS && opt->dst0opt) - tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst0opt)); - if (newtype != IPV6_RTHDR && opt->srcrt) - tot_len += CMSG_ALIGN(ipv6_optlen(opt->srcrt)); - if (newtype != IPV6_DSTOPTS && opt->dst1opt) - tot_len += CMSG_ALIGN(ipv6_optlen(opt->dst1opt)); - } - - if (newopt && newoptlen) - tot_len += CMSG_ALIGN(newoptlen); - - if (!tot_len) - return NULL; - - tot_len += sizeof(*opt2); - opt2 = sock_kmalloc(sk, tot_len, GFP_ATOMIC); - if (!opt2) - return ERR_PTR(-ENOBUFS); - - memset(opt2, 0, tot_len); - atomic_set(&opt2->refcnt, 1); - opt2->tot_len = tot_len; - p = (char *)(opt2 + 1); - - err = ipv6_renew_option(opt ? opt->hopopt : NULL, newopt, newoptlen, - newtype != IPV6_HOPOPTS, - &opt2->hopopt, &p); - if (err) - goto out; - - err = ipv6_renew_option(opt ? opt->dst0opt : NULL, newopt, newoptlen, - newtype != IPV6_RTHDRDSTOPTS, - &opt2->dst0opt, &p); - if (err) - goto out; - - err = ipv6_renew_option(opt ? opt->srcrt : NULL, newopt, newoptlen, - newtype != IPV6_RTHDR, - (struct ipv6_opt_hdr **)&opt2->srcrt, &p); - if (err) - goto out; - - err = ipv6_renew_option(opt ? opt->dst1opt : NULL, newopt, newoptlen, - newtype != IPV6_DSTOPTS, - &opt2->dst1opt, &p); - if (err) - goto out; - - opt2->opt_nflen = (opt2->hopopt ? ipv6_optlen(opt2->hopopt) : 0) + - (opt2->dst0opt ? ipv6_optlen(opt2->dst0opt) : 0) + - (opt2->srcrt ? ipv6_optlen(opt2->srcrt) : 0); - opt2->opt_flen = (opt2->dst1opt ? ipv6_optlen(opt2->dst1opt) : 0); - - return opt2; -out: - sock_kfree_s(sk, opt2, opt2->tot_len); - return ERR_PTR(err); -} - -/** - * ipv6_renew_options_kern - replace a specific ext hdr with a new one. - * - * @sk: sock from which to allocate memory - * @opt: original options - * @newtype: option type to replace in @opt - * @newopt: new option of type @newtype to replace (kernel-mem) - * @newoptlen: length of @newopt - * - * See ipv6_renew_options(). The difference is that @newopt is - * kernel memory, rather than user memory. - */ -struct ipv6_txoptions * -ipv6_renew_options_kern(struct sock *sk, struct ipv6_txoptions *opt, - int newtype, struct ipv6_opt_hdr *newopt, - int newoptlen) -{ - struct ipv6_txoptions *ret_val; - const mm_segment_t old_fs = get_fs(); - - set_fs(KERNEL_DS); - ret_val = ipv6_renew_options(sk, opt, newtype, - (struct ipv6_opt_hdr __user *)newopt, - newoptlen); - set_fs(old_fs); - return ret_val; -} - -struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space, - struct ipv6_txoptions *opt) -{ - /* - * ignore the dest before srcrt unless srcrt is being included. - * --yoshfuji - */ - if (opt && opt->dst0opt && !opt->srcrt) { - if (opt_space != opt) { - memcpy(opt_space, opt, sizeof(*opt_space)); - opt = opt_space; - } - opt->opt_nflen -= ipv6_optlen(opt->dst0opt); - opt->dst0opt = NULL; - } - - return opt; -} -EXPORT_SYMBOL_GPL(ipv6_fixup_options); - -/** - * fl6_update_dst - update flowi destination address with info given - * by srcrt option, if any. - * - * @fl6: flowi6 for which daddr is to be updated - * @opt: struct ipv6_txoptions in which to look for srcrt opt - * @orig: copy of original daddr address if modified - * - * Returns NULL if no txoptions or no srcrt, otherwise returns orig - * and initial value of fl6->daddr set in orig - */ -struct in6_addr *fl6_update_dst(struct flowi6 *fl6, - const struct ipv6_txoptions *opt, - struct in6_addr *orig) -{ - if (!opt || !opt->srcrt) - return NULL; - - *orig = fl6->daddr; - fl6->daddr = *((struct rt0_hdr *)opt->srcrt)->addr; - return orig; -} -EXPORT_SYMBOL_GPL(fl6_update_dst); diff --git a/src/linux/net/ipv6/exthdrs_core.c b/src/linux/net/ipv6/exthdrs_core.c deleted file mode 100644 index 305e2ed..0000000 --- a/src/linux/net/ipv6/exthdrs_core.c +++ /dev/null @@ -1,285 +0,0 @@ -/* - * IPv6 library code, needed by static components when full IPv6 support is - * not configured or static. - */ -#include -#include - -/* - * find out if nexthdr is a well-known extension header or a protocol - */ - -bool ipv6_ext_hdr(u8 nexthdr) -{ - /* - * find out if nexthdr is an extension header or a protocol - */ - return (nexthdr == NEXTHDR_HOP) || - (nexthdr == NEXTHDR_ROUTING) || - (nexthdr == NEXTHDR_FRAGMENT) || - (nexthdr == NEXTHDR_AUTH) || - (nexthdr == NEXTHDR_NONE) || - (nexthdr == NEXTHDR_DEST); -} -EXPORT_SYMBOL(ipv6_ext_hdr); - -/* - * Skip any extension headers. This is used by the ICMP module. - * - * Note that strictly speaking this conflicts with RFC 2460 4.0: - * ...The contents and semantics of each extension header determine whether - * or not to proceed to the next header. Therefore, extension headers must - * be processed strictly in the order they appear in the packet; a - * receiver must not, for example, scan through a packet looking for a - * particular kind of extension header and process that header prior to - * processing all preceding ones. - * - * We do exactly this. This is a protocol bug. We can't decide after a - * seeing an unknown discard-with-error flavour TLV option if it's a - * ICMP error message or not (errors should never be send in reply to - * ICMP error messages). - * - * But I see no other way to do this. This might need to be reexamined - * when Linux implements ESP (and maybe AUTH) headers. - * --AK - * - * This function parses (probably truncated) exthdr set "hdr". - * "nexthdrp" initially points to some place, - * where type of the first header can be found. - * - * It skips all well-known exthdrs, and returns pointer to the start - * of unparsable area i.e. the first header with unknown type. - * If it is not NULL *nexthdr is updated by type/protocol of this header. - * - * NOTES: - if packet terminated with NEXTHDR_NONE it returns NULL. - * - it may return pointer pointing beyond end of packet, - * if the last recognized header is truncated in the middle. - * - if packet is truncated, so that all parsed headers are skipped, - * it returns NULL. - * - First fragment header is skipped, not-first ones - * are considered as unparsable. - * - Reports the offset field of the final fragment header so it is - * possible to tell whether this is a first fragment, later fragment, - * or not fragmented. - * - ESP is unparsable for now and considered like - * normal payload protocol. - * - Note also special handling of AUTH header. Thanks to IPsec wizards. - * - * --ANK (980726) - */ - -int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp, - __be16 *frag_offp) -{ - u8 nexthdr = *nexthdrp; - - *frag_offp = 0; - - while (ipv6_ext_hdr(nexthdr)) { - struct ipv6_opt_hdr _hdr, *hp; - int hdrlen; - - if (nexthdr == NEXTHDR_NONE) - return -1; - hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); - if (!hp) - return -1; - if (nexthdr == NEXTHDR_FRAGMENT) { - __be16 _frag_off, *fp; - fp = skb_header_pointer(skb, - start+offsetof(struct frag_hdr, - frag_off), - sizeof(_frag_off), - &_frag_off); - if (!fp) - return -1; - - *frag_offp = *fp; - if (ntohs(*frag_offp) & ~0x7) - break; - hdrlen = 8; - } else if (nexthdr == NEXTHDR_AUTH) - hdrlen = (hp->hdrlen+2)<<2; - else - hdrlen = ipv6_optlen(hp); - - nexthdr = hp->nexthdr; - start += hdrlen; - } - - *nexthdrp = nexthdr; - return start; -} -EXPORT_SYMBOL(ipv6_skip_exthdr); - -int ipv6_find_tlv(const struct sk_buff *skb, int offset, int type) -{ - const unsigned char *nh = skb_network_header(skb); - int packet_len = skb_tail_pointer(skb) - skb_network_header(skb); - struct ipv6_opt_hdr *hdr; - int len; - - if (offset + 2 > packet_len) - goto bad; - hdr = (struct ipv6_opt_hdr *)(nh + offset); - len = ((hdr->hdrlen + 1) << 3); - - if (offset + len > packet_len) - goto bad; - - offset += 2; - len -= 2; - - while (len > 0) { - int opttype = nh[offset]; - int optlen; - - if (opttype == type) - return offset; - - switch (opttype) { - case IPV6_TLV_PAD1: - optlen = 1; - break; - default: - optlen = nh[offset + 1] + 2; - if (optlen > len) - goto bad; - break; - } - offset += optlen; - len -= optlen; - } - /* not_found */ - bad: - return -1; -} -EXPORT_SYMBOL_GPL(ipv6_find_tlv); - -/* - * find the offset to specified header or the protocol number of last header - * if target < 0. "last header" is transport protocol header, ESP, or - * "No next header". - * - * Note that *offset is used as input/output parameter. an if it is not zero, - * then it must be a valid offset to an inner IPv6 header. This can be used - * to explore inner IPv6 header, eg. ICMPv6 error messages. - * - * If target header is found, its offset is set in *offset and return protocol - * number. Otherwise, return -1. - * - * If the first fragment doesn't contain the final protocol header or - * NEXTHDR_NONE it is considered invalid. - * - * Note that non-1st fragment is special case that "the protocol number - * of last header" is "next header" field in Fragment header. In this case, - * *offset is meaningless and fragment offset is stored in *fragoff if fragoff - * isn't NULL. - * - * if flags is not NULL and it's a fragment, then the frag flag - * IP6_FH_F_FRAG will be set. If it's an AH header, the - * IP6_FH_F_AUTH flag is set and target < 0, then this function will - * stop at the AH header. If IP6_FH_F_SKIP_RH flag was passed, then this - * function will skip all those routing headers, where segements_left was 0. - */ -int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, - int target, unsigned short *fragoff, int *flags) -{ - unsigned int start = skb_network_offset(skb) + sizeof(struct ipv6hdr); - u8 nexthdr = ipv6_hdr(skb)->nexthdr; - unsigned int len; - bool found; - - if (fragoff) - *fragoff = 0; - - if (*offset) { - struct ipv6hdr _ip6, *ip6; - - ip6 = skb_header_pointer(skb, *offset, sizeof(_ip6), &_ip6); - if (!ip6 || (ip6->version != 6)) { - printk(KERN_ERR "IPv6 header not found\n"); - return -EBADMSG; - } - start = *offset + sizeof(struct ipv6hdr); - nexthdr = ip6->nexthdr; - } - len = skb->len - start; - - do { - struct ipv6_opt_hdr _hdr, *hp; - unsigned int hdrlen; - found = (nexthdr == target); - - if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE) { - if (target < 0 || found) - break; - return -ENOENT; - } - - hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr); - if (!hp) - return -EBADMSG; - - if (nexthdr == NEXTHDR_ROUTING) { - struct ipv6_rt_hdr _rh, *rh; - - rh = skb_header_pointer(skb, start, sizeof(_rh), - &_rh); - if (!rh) - return -EBADMSG; - - if (flags && (*flags & IP6_FH_F_SKIP_RH) && - rh->segments_left == 0) - found = false; - } - - if (nexthdr == NEXTHDR_FRAGMENT) { - unsigned short _frag_off; - __be16 *fp; - - if (flags) /* Indicate that this is a fragment */ - *flags |= IP6_FH_F_FRAG; - fp = skb_header_pointer(skb, - start+offsetof(struct frag_hdr, - frag_off), - sizeof(_frag_off), - &_frag_off); - if (!fp) - return -EBADMSG; - - _frag_off = ntohs(*fp) & ~0x7; - if (_frag_off) { - if (target < 0 && - ((!ipv6_ext_hdr(hp->nexthdr)) || - hp->nexthdr == NEXTHDR_NONE)) { - if (fragoff) - *fragoff = _frag_off; - return hp->nexthdr; - } - if (!found) - return -ENOENT; - if (fragoff) - *fragoff = _frag_off; - break; - } - hdrlen = 8; - } else if (nexthdr == NEXTHDR_AUTH) { - if (flags && (*flags & IP6_FH_F_AUTH) && (target < 0)) - break; - hdrlen = (hp->hdrlen + 2) << 2; - } else - hdrlen = ipv6_optlen(hp); - - if (!found) { - nexthdr = hp->nexthdr; - len -= hdrlen; - start += hdrlen; - } - } while (!found); - - *offset = start; - return nexthdr; -} -EXPORT_SYMBOL(ipv6_find_hdr); - diff --git a/src/linux/net/ipv6/exthdrs_offload.c b/src/linux/net/ipv6/exthdrs_offload.c deleted file mode 100644 index f5e2ba1..0000000 --- a/src/linux/net/ipv6/exthdrs_offload.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * IPV6 GSO/GRO offload support - * Linux INET6 implementation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * IPV6 Extension Header GSO/GRO support - */ -#include -#include "ip6_offload.h" - -static const struct net_offload rthdr_offload = { - .flags = INET6_PROTO_GSO_EXTHDR, -}; - -static const struct net_offload dstopt_offload = { - .flags = INET6_PROTO_GSO_EXTHDR, -}; - -int __init ipv6_exthdrs_offload_init(void) -{ - int ret; - - ret = inet6_add_offload(&rthdr_offload, IPPROTO_ROUTING); - if (ret) - goto out; - - ret = inet6_add_offload(&dstopt_offload, IPPROTO_DSTOPTS); - if (ret) - goto out_rt; - -out: - return ret; - -out_rt: - inet6_del_offload(&rthdr_offload, IPPROTO_ROUTING); - goto out; -} diff --git a/src/linux/net/ipv6/icmp.c b/src/linux/net/ipv6/icmp.c deleted file mode 100644 index 2772004..0000000 --- a/src/linux/net/ipv6/icmp.c +++ /dev/null @@ -1,1089 +0,0 @@ -/* - * Internet Control Message Protocol (ICMPv6) - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * Based on net/ipv4/icmp.c - * - * RFC 1885 - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -/* - * Changes: - * - * Andi Kleen : exception handling - * Andi Kleen add rate limits. never reply to a icmp. - * add more length checks and other fixes. - * yoshfuji : ensure to sent parameter problem for - * fragments. - * YOSHIFUJI Hideaki @USAGI: added sysctl for icmp rate limit. - * Randy Dunlap and - * YOSHIFUJI Hideaki @USAGI: Per-interface statistics support - * Kazunori MIYAZAWA @USAGI: change output process to use ip6_append_data - */ - -#define pr_fmt(fmt) "IPv6: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_SYSCTL -#include -#endif - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * The ICMP socket(s). This is the most convenient way to flow control - * our ICMP output as well as maintain a clean interface throughout - * all layers. All Socketless IP sends will soon be gone. - * - * On SMP we have one ICMP socket per-cpu. - */ -static inline struct sock *icmpv6_sk(struct net *net) -{ - return net->ipv6.icmp_sk[smp_processor_id()]; -} - -static void icmpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - u8 type, u8 code, int offset, __be32 info) -{ - /* icmpv6_notify checks 8 bytes can be pulled, icmp6hdr is 8 bytes */ - struct icmp6hdr *icmp6 = (struct icmp6hdr *) (skb->data + offset); - struct net *net = dev_net(skb->dev); - - if (type == ICMPV6_PKT_TOOBIG) - ip6_update_pmtu(skb, net, info, 0, 0); - else if (type == NDISC_REDIRECT) - ip6_redirect(skb, net, skb->dev->ifindex, 0); - - if (!(type & ICMPV6_INFOMSG_MASK)) - if (icmp6->icmp6_type == ICMPV6_ECHO_REQUEST) - ping_err(skb, offset, ntohl(info)); -} - -static int icmpv6_rcv(struct sk_buff *skb); - -static const struct inet6_protocol icmpv6_protocol = { - .handler = icmpv6_rcv, - .err_handler = icmpv6_err, - .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, -}; - -static __inline__ struct sock *icmpv6_xmit_lock(struct net *net) -{ - struct sock *sk; - - local_bh_disable(); - - sk = icmpv6_sk(net); - if (unlikely(!spin_trylock(&sk->sk_lock.slock))) { - /* This can happen if the output path (f.e. SIT or - * ip6ip6 tunnel) signals dst_link_failure() for an - * outgoing ICMP6 packet. - */ - local_bh_enable(); - return NULL; - } - return sk; -} - -static __inline__ void icmpv6_xmit_unlock(struct sock *sk) -{ - spin_unlock_bh(&sk->sk_lock.slock); -} - -/* - * Figure out, may we reply to this packet with icmp error. - * - * We do not reply, if: - * - it was icmp error message. - * - it is truncated, so that it is known, that protocol is ICMPV6 - * (i.e. in the middle of some exthdr) - * - * --ANK (980726) - */ - -static bool is_ineligible(const struct sk_buff *skb) -{ - int ptr = (u8 *)(ipv6_hdr(skb) + 1) - skb->data; - int len = skb->len - ptr; - __u8 nexthdr = ipv6_hdr(skb)->nexthdr; - __be16 frag_off; - - if (len < 0) - return true; - - ptr = ipv6_skip_exthdr(skb, ptr, &nexthdr, &frag_off); - if (ptr < 0) - return false; - if (nexthdr == IPPROTO_ICMPV6) { - u8 _type, *tp; - tp = skb_header_pointer(skb, - ptr+offsetof(struct icmp6hdr, icmp6_type), - sizeof(_type), &_type); - if (!tp || !(*tp & ICMPV6_INFOMSG_MASK)) - return true; - } - return false; -} - -/* - * Check the ICMP output rate limit - */ -static bool icmpv6_xrlim_allow(struct sock *sk, u8 type, - struct flowi6 *fl6) -{ - struct net *net = sock_net(sk); - struct dst_entry *dst; - bool res = false; - - /* Informational messages are not limited. */ - if (type & ICMPV6_INFOMSG_MASK) - return true; - - /* Do not limit pmtu discovery, it would break it. */ - if (type == ICMPV6_PKT_TOOBIG) - return true; - - /* - * Look up the output route. - * XXX: perhaps the expire for routing entries cloned by - * this lookup should be more aggressive (not longer than timeout). - */ - dst = ip6_route_output(net, sk, fl6); - if (dst->error) { - IP6_INC_STATS(net, ip6_dst_idev(dst), - IPSTATS_MIB_OUTNOROUTES); - } else if (dst->dev && (dst->dev->flags&IFF_LOOPBACK)) { - res = true; - } else { - struct rt6_info *rt = (struct rt6_info *)dst; - int tmo = net->ipv6.sysctl.icmpv6_time; - - /* Give more bandwidth to wider prefixes. */ - if (rt->rt6i_dst.plen < 128) - tmo >>= ((128 - rt->rt6i_dst.plen)>>5); - - if (icmp_global_allow()) { - struct inet_peer *peer; - - peer = inet_getpeer_v6(net->ipv6.peers, - &fl6->daddr, 1); - res = inet_peer_xrlim_allow(peer, tmo); - if (peer) - inet_putpeer(peer); - } - } - dst_release(dst); - return res; -} - -/* - * an inline helper for the "simple" if statement below - * checks if parameter problem report is caused by an - * unrecognized IPv6 option that has the Option Type - * highest-order two bits set to 10 - */ - -static bool opt_unrec(struct sk_buff *skb, __u32 offset) -{ - u8 _optval, *op; - - offset += skb_network_offset(skb); - op = skb_header_pointer(skb, offset, sizeof(_optval), &_optval); - if (!op) - return true; - return (*op & 0xC0) == 0x80; -} - -int icmpv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, - struct icmp6hdr *thdr, int len) -{ - struct sk_buff *skb; - struct icmp6hdr *icmp6h; - int err = 0; - - skb = skb_peek(&sk->sk_write_queue); - if (!skb) - goto out; - - icmp6h = icmp6_hdr(skb); - memcpy(icmp6h, thdr, sizeof(struct icmp6hdr)); - icmp6h->icmp6_cksum = 0; - - if (skb_queue_len(&sk->sk_write_queue) == 1) { - skb->csum = csum_partial(icmp6h, - sizeof(struct icmp6hdr), skb->csum); - icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr, - &fl6->daddr, - len, fl6->flowi6_proto, - skb->csum); - } else { - __wsum tmp_csum = 0; - - skb_queue_walk(&sk->sk_write_queue, skb) { - tmp_csum = csum_add(tmp_csum, skb->csum); - } - - tmp_csum = csum_partial(icmp6h, - sizeof(struct icmp6hdr), tmp_csum); - icmp6h->icmp6_cksum = csum_ipv6_magic(&fl6->saddr, - &fl6->daddr, - len, fl6->flowi6_proto, - tmp_csum); - } - ip6_push_pending_frames(sk); -out: - return err; -} - -struct icmpv6_msg { - struct sk_buff *skb; - int offset; - uint8_t type; -}; - -static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb) -{ - struct icmpv6_msg *msg = (struct icmpv6_msg *) from; - struct sk_buff *org_skb = msg->skb; - __wsum csum = 0; - - csum = skb_copy_and_csum_bits(org_skb, msg->offset + offset, - to, len, csum); - skb->csum = csum_block_add(skb->csum, csum, odd); - if (!(msg->type & ICMPV6_INFOMSG_MASK)) - nf_ct_attach(skb, org_skb); - return 0; -} - -#if IS_ENABLED(CONFIG_IPV6_MIP6) -static void mip6_addr_swap(struct sk_buff *skb) -{ - struct ipv6hdr *iph = ipv6_hdr(skb); - struct inet6_skb_parm *opt = IP6CB(skb); - struct ipv6_destopt_hao *hao; - struct in6_addr tmp; - int off; - - if (opt->dsthao) { - off = ipv6_find_tlv(skb, opt->dsthao, IPV6_TLV_HAO); - if (likely(off >= 0)) { - hao = (struct ipv6_destopt_hao *) - (skb_network_header(skb) + off); - tmp = iph->saddr; - iph->saddr = hao->addr; - hao->addr = tmp; - } - } -} -#else -static inline void mip6_addr_swap(struct sk_buff *skb) {} -#endif - -static struct dst_entry *icmpv6_route_lookup(struct net *net, - struct sk_buff *skb, - struct sock *sk, - struct flowi6 *fl6) -{ - struct dst_entry *dst, *dst2; - struct flowi6 fl2; - int err; - - err = ip6_dst_lookup(net, sk, &dst, fl6); - if (err) - return ERR_PTR(err); - - /* - * We won't send icmp if the destination is known - * anycast. - */ - if (ipv6_anycast_destination(dst, &fl6->daddr)) { - net_dbg_ratelimited("icmp6_send: acast source\n"); - dst_release(dst); - return ERR_PTR(-EINVAL); - } - - /* No need to clone since we're just using its address. */ - dst2 = dst; - - dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), sk, 0); - if (!IS_ERR(dst)) { - if (dst != dst2) - return dst; - } else { - if (PTR_ERR(dst) == -EPERM) - dst = NULL; - else - return dst; - } - - err = xfrm_decode_session_reverse(skb, flowi6_to_flowi(&fl2), AF_INET6); - if (err) - goto relookup_failed; - - err = ip6_dst_lookup(net, sk, &dst2, &fl2); - if (err) - goto relookup_failed; - - dst2 = xfrm_lookup(net, dst2, flowi6_to_flowi(&fl2), sk, XFRM_LOOKUP_ICMP); - if (!IS_ERR(dst2)) { - dst_release(dst); - dst = dst2; - } else { - err = PTR_ERR(dst2); - if (err == -EPERM) { - dst_release(dst); - return dst2; - } else - goto relookup_failed; - } - -relookup_failed: - if (dst) - return dst; - return ERR_PTR(err); -} - -/* - * Send an ICMP message in response to a packet in error - */ -static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info, - const struct in6_addr *force_saddr) -{ - struct net *net = dev_net(skb->dev); - struct inet6_dev *idev = NULL; - struct ipv6hdr *hdr = ipv6_hdr(skb); - struct sock *sk; - struct ipv6_pinfo *np; - const struct in6_addr *saddr = NULL; - struct dst_entry *dst; - struct icmp6hdr tmp_hdr; - struct flowi6 fl6; - struct icmpv6_msg msg; - struct sockcm_cookie sockc_unused = {0}; - struct ipcm6_cookie ipc6; - int iif = 0; - int addr_type = 0; - int len; - int err = 0; - u32 mark = IP6_REPLY_MARK(net, skb->mark); - - if ((u8 *)hdr < skb->head || - (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb)) - return; - - /* - * Make sure we respect the rules - * i.e. RFC 1885 2.4(e) - * Rule (e.1) is enforced by not using icmp6_send - * in any code that processes icmp errors. - */ - addr_type = ipv6_addr_type(&hdr->daddr); - - if (ipv6_chk_addr(net, &hdr->daddr, skb->dev, 0) || - ipv6_chk_acast_addr_src(net, skb->dev, &hdr->daddr)) - saddr = &hdr->daddr; - - /* - * Dest addr check - */ - - if (addr_type & IPV6_ADDR_MULTICAST || skb->pkt_type != PACKET_HOST) { - if (type != ICMPV6_PKT_TOOBIG && - !(type == ICMPV6_PARAMPROB && - code == ICMPV6_UNK_OPTION && - (opt_unrec(skb, info)))) - return; - - saddr = NULL; - } - - addr_type = ipv6_addr_type(&hdr->saddr); - - /* - * Source addr check - */ - - if (__ipv6_addr_needs_scope_id(addr_type)) - iif = skb->dev->ifindex; - else { - dst = skb_dst(skb); - iif = l3mdev_master_ifindex(dst ? dst->dev : skb->dev); - } - - /* - * Must not send error if the source does not uniquely - * identify a single node (RFC2463 Section 2.4). - * We check unspecified / multicast addresses here, - * and anycast addresses will be checked later. - */ - if ((addr_type == IPV6_ADDR_ANY) || (addr_type & IPV6_ADDR_MULTICAST)) { - net_dbg_ratelimited("icmp6_send: addr_any/mcast source [%pI6c > %pI6c]\n", - &hdr->saddr, &hdr->daddr); - return; - } - - /* - * Never answer to a ICMP packet. - */ - if (is_ineligible(skb)) { - net_dbg_ratelimited("icmp6_send: no reply to icmp error [%pI6c > %pI6c]\n", - &hdr->saddr, &hdr->daddr); - return; - } - - mip6_addr_swap(skb); - - memset(&fl6, 0, sizeof(fl6)); - fl6.flowi6_proto = IPPROTO_ICMPV6; - fl6.daddr = hdr->saddr; - if (force_saddr) - saddr = force_saddr; - if (saddr) - fl6.saddr = *saddr; - fl6.flowi6_mark = mark; - fl6.flowi6_oif = iif; - fl6.fl6_icmp_type = type; - fl6.fl6_icmp_code = code; - security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); - - sk = icmpv6_xmit_lock(net); - if (!sk) - return; - sk->sk_mark = mark; - np = inet6_sk(sk); - - if (!icmpv6_xrlim_allow(sk, type, &fl6)) - goto out; - - tmp_hdr.icmp6_type = type; - tmp_hdr.icmp6_code = code; - tmp_hdr.icmp6_cksum = 0; - tmp_hdr.icmp6_pointer = htonl(info); - - if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) - fl6.flowi6_oif = np->mcast_oif; - else if (!fl6.flowi6_oif) - fl6.flowi6_oif = np->ucast_oif; - - ipc6.tclass = np->tclass; - fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel); - - dst = icmpv6_route_lookup(net, skb, sk, &fl6); - if (IS_ERR(dst)) - goto out; - - ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); - ipc6.dontfrag = np->dontfrag; - ipc6.opt = NULL; - - msg.skb = skb; - msg.offset = skb_network_offset(skb); - msg.type = type; - - len = skb->len - msg.offset; - len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(struct icmp6hdr)); - if (len < 0) { - net_dbg_ratelimited("icmp: len problem [%pI6c > %pI6c]\n", - &hdr->saddr, &hdr->daddr); - goto out_dst_release; - } - - rcu_read_lock(); - idev = __in6_dev_get(skb->dev); - - err = ip6_append_data(sk, icmpv6_getfrag, &msg, - len + sizeof(struct icmp6hdr), - sizeof(struct icmp6hdr), - &ipc6, &fl6, (struct rt6_info *)dst, - MSG_DONTWAIT, &sockc_unused); - if (err) { - ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS); - ip6_flush_pending_frames(sk); - } else { - err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr, - len + sizeof(struct icmp6hdr)); - } - rcu_read_unlock(); -out_dst_release: - dst_release(dst); -out: - icmpv6_xmit_unlock(sk); -} - -/* Slightly more convenient version of icmp6_send. - */ -void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos) -{ - icmp6_send(skb, ICMPV6_PARAMPROB, code, pos, NULL); - kfree_skb(skb); -} - -/* Generate icmpv6 with type/code ICMPV6_DEST_UNREACH/ICMPV6_ADDR_UNREACH - * if sufficient data bytes are available - * @nhs is the size of the tunnel header(s) : - * Either an IPv4 header for SIT encap - * an IPv4 header + GRE header for GRE encap - */ -int ip6_err_gen_icmpv6_unreach(struct sk_buff *skb, int nhs, int type, - unsigned int data_len) -{ - struct in6_addr temp_saddr; - struct rt6_info *rt; - struct sk_buff *skb2; - u32 info = 0; - - if (!pskb_may_pull(skb, nhs + sizeof(struct ipv6hdr) + 8)) - return 1; - - /* RFC 4884 (partial) support for ICMP extensions */ - if (data_len < 128 || (data_len & 7) || skb->len < data_len) - data_len = 0; - - skb2 = data_len ? skb_copy(skb, GFP_ATOMIC) : skb_clone(skb, GFP_ATOMIC); - - if (!skb2) - return 1; - - skb_dst_drop(skb2); - skb_pull(skb2, nhs); - skb_reset_network_header(skb2); - - rt = rt6_lookup(dev_net(skb->dev), &ipv6_hdr(skb2)->saddr, NULL, 0, 0); - - if (rt && rt->dst.dev) - skb2->dev = rt->dst.dev; - - ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, &temp_saddr); - - if (data_len) { - /* RFC 4884 (partial) support : - * insert 0 padding at the end, before the extensions - */ - __skb_push(skb2, nhs); - skb_reset_network_header(skb2); - memmove(skb2->data, skb2->data + nhs, data_len - nhs); - memset(skb2->data + data_len - nhs, 0, nhs); - /* RFC 4884 4.5 : Length is measured in 64-bit words, - * and stored in reserved[0] - */ - info = (data_len/8) << 24; - } - if (type == ICMP_TIME_EXCEEDED) - icmp6_send(skb2, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, - info, &temp_saddr); - else - icmp6_send(skb2, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, - info, &temp_saddr); - if (rt) - ip6_rt_put(rt); - - kfree_skb(skb2); - - return 0; -} -EXPORT_SYMBOL(ip6_err_gen_icmpv6_unreach); - -static void icmpv6_echo_reply(struct sk_buff *skb) -{ - struct net *net = dev_net(skb->dev); - struct sock *sk; - struct inet6_dev *idev; - struct ipv6_pinfo *np; - const struct in6_addr *saddr = NULL; - struct icmp6hdr *icmph = icmp6_hdr(skb); - struct icmp6hdr tmp_hdr; - struct flowi6 fl6; - struct icmpv6_msg msg; - struct dst_entry *dst; - struct ipcm6_cookie ipc6; - int err = 0; - u32 mark = IP6_REPLY_MARK(net, skb->mark); - struct sockcm_cookie sockc_unused = {0}; - - saddr = &ipv6_hdr(skb)->daddr; - - if (!ipv6_unicast_destination(skb) && - !(net->ipv6.sysctl.anycast_src_echo_reply && - ipv6_anycast_destination(skb_dst(skb), saddr))) - saddr = NULL; - - memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr)); - tmp_hdr.icmp6_type = ICMPV6_ECHO_REPLY; - - memset(&fl6, 0, sizeof(fl6)); - fl6.flowi6_proto = IPPROTO_ICMPV6; - fl6.daddr = ipv6_hdr(skb)->saddr; - if (saddr) - fl6.saddr = *saddr; - fl6.flowi6_oif = skb->dev->ifindex; - fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY; - fl6.flowi6_mark = mark; - security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); - - sk = icmpv6_xmit_lock(net); - if (!sk) - return; - sk->sk_mark = mark; - np = inet6_sk(sk); - - if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) - fl6.flowi6_oif = np->mcast_oif; - else if (!fl6.flowi6_oif) - fl6.flowi6_oif = np->ucast_oif; - - err = ip6_dst_lookup(net, sk, &dst, &fl6); - if (err) - goto out; - dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), sk, 0); - if (IS_ERR(dst)) - goto out; - - idev = __in6_dev_get(skb->dev); - - msg.skb = skb; - msg.offset = 0; - msg.type = ICMPV6_ECHO_REPLY; - - ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); - ipc6.tclass = ipv6_get_dsfield(ipv6_hdr(skb)); - ipc6.dontfrag = np->dontfrag; - ipc6.opt = NULL; - - err = ip6_append_data(sk, icmpv6_getfrag, &msg, skb->len + sizeof(struct icmp6hdr), - sizeof(struct icmp6hdr), &ipc6, &fl6, - (struct rt6_info *)dst, MSG_DONTWAIT, - &sockc_unused); - - if (err) { - __ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTERRORS); - ip6_flush_pending_frames(sk); - } else { - err = icmpv6_push_pending_frames(sk, &fl6, &tmp_hdr, - skb->len + sizeof(struct icmp6hdr)); - } - dst_release(dst); -out: - icmpv6_xmit_unlock(sk); -} - -void icmpv6_notify(struct sk_buff *skb, u8 type, u8 code, __be32 info) -{ - const struct inet6_protocol *ipprot; - int inner_offset; - __be16 frag_off; - u8 nexthdr; - struct net *net = dev_net(skb->dev); - - if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) - goto out; - - nexthdr = ((struct ipv6hdr *)skb->data)->nexthdr; - if (ipv6_ext_hdr(nexthdr)) { - /* now skip over extension headers */ - inner_offset = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), - &nexthdr, &frag_off); - if (inner_offset < 0) - goto out; - } else { - inner_offset = sizeof(struct ipv6hdr); - } - - /* Checkin header including 8 bytes of inner protocol header. */ - if (!pskb_may_pull(skb, inner_offset+8)) - goto out; - - /* BUGGG_FUTURE: we should try to parse exthdrs in this packet. - Without this we will not able f.e. to make source routed - pmtu discovery. - Corresponding argument (opt) to notifiers is already added. - --ANK (980726) - */ - - ipprot = rcu_dereference(inet6_protos[nexthdr]); - if (ipprot && ipprot->err_handler) - ipprot->err_handler(skb, NULL, type, code, inner_offset, info); - - raw6_icmp_error(skb, nexthdr, type, code, inner_offset, info); - return; - -out: - __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), ICMP6_MIB_INERRORS); -} - -/* - * Handle icmp messages - */ - -static int icmpv6_rcv(struct sk_buff *skb) -{ - struct net_device *dev = skb->dev; - struct inet6_dev *idev = __in6_dev_get(dev); - const struct in6_addr *saddr, *daddr; - struct icmp6hdr *hdr; - u8 type; - bool success = false; - - if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { - struct sec_path *sp = skb_sec_path(skb); - int nh; - - if (!(sp && sp->xvec[sp->len - 1]->props.flags & - XFRM_STATE_ICMP)) - goto drop_no_count; - - if (!pskb_may_pull(skb, sizeof(*hdr) + sizeof(struct ipv6hdr))) - goto drop_no_count; - - nh = skb_network_offset(skb); - skb_set_network_header(skb, sizeof(*hdr)); - - if (!xfrm6_policy_check_reverse(NULL, XFRM_POLICY_IN, skb)) - goto drop_no_count; - - skb_set_network_header(skb, nh); - } - - __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INMSGS); - - saddr = &ipv6_hdr(skb)->saddr; - daddr = &ipv6_hdr(skb)->daddr; - - if (skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo)) { - net_dbg_ratelimited("ICMPv6 checksum failed [%pI6c > %pI6c]\n", - saddr, daddr); - goto csum_error; - } - - if (!pskb_pull(skb, sizeof(*hdr))) - goto discard_it; - - hdr = icmp6_hdr(skb); - - type = hdr->icmp6_type; - - ICMP6MSGIN_INC_STATS(dev_net(dev), idev, type); - - switch (type) { - case ICMPV6_ECHO_REQUEST: - icmpv6_echo_reply(skb); - break; - - case ICMPV6_ECHO_REPLY: - success = ping_rcv(skb); - break; - - case ICMPV6_PKT_TOOBIG: - /* BUGGG_FUTURE: if packet contains rthdr, we cannot update - standard destination cache. Seems, only "advanced" - destination cache will allow to solve this problem - --ANK (980726) - */ - if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) - goto discard_it; - hdr = icmp6_hdr(skb); - - /* - * Drop through to notify - */ - - case ICMPV6_DEST_UNREACH: - case ICMPV6_TIME_EXCEED: - case ICMPV6_PARAMPROB: - icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu); - break; - - case NDISC_ROUTER_SOLICITATION: - case NDISC_ROUTER_ADVERTISEMENT: - case NDISC_NEIGHBOUR_SOLICITATION: - case NDISC_NEIGHBOUR_ADVERTISEMENT: - case NDISC_REDIRECT: - ndisc_rcv(skb); - break; - - case ICMPV6_MGM_QUERY: - igmp6_event_query(skb); - break; - - case ICMPV6_MGM_REPORT: - igmp6_event_report(skb); - break; - - case ICMPV6_MGM_REDUCTION: - case ICMPV6_NI_QUERY: - case ICMPV6_NI_REPLY: - case ICMPV6_MLD2_REPORT: - case ICMPV6_DHAAD_REQUEST: - case ICMPV6_DHAAD_REPLY: - case ICMPV6_MOBILE_PREFIX_SOL: - case ICMPV6_MOBILE_PREFIX_ADV: - break; - - default: - /* informational */ - if (type & ICMPV6_INFOMSG_MASK) - break; - - net_dbg_ratelimited("icmpv6: msg of unknown type [%pI6c > %pI6c]\n", - saddr, daddr); - - /* - * error of unknown type. - * must pass to upper level - */ - - icmpv6_notify(skb, type, hdr->icmp6_code, hdr->icmp6_mtu); - } - - /* until the v6 path can be better sorted assume failure and - * preserve the status quo behaviour for the rest of the paths to here - */ - if (success) - consume_skb(skb); - else - kfree_skb(skb); - - return 0; - -csum_error: - __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_CSUMERRORS); -discard_it: - __ICMP6_INC_STATS(dev_net(dev), idev, ICMP6_MIB_INERRORS); -drop_no_count: - kfree_skb(skb); - return 0; -} - -void icmpv6_flow_init(struct sock *sk, struct flowi6 *fl6, - u8 type, - const struct in6_addr *saddr, - const struct in6_addr *daddr, - int oif) -{ - memset(fl6, 0, sizeof(*fl6)); - fl6->saddr = *saddr; - fl6->daddr = *daddr; - fl6->flowi6_proto = IPPROTO_ICMPV6; - fl6->fl6_icmp_type = type; - fl6->fl6_icmp_code = 0; - fl6->flowi6_oif = oif; - security_sk_classify_flow(sk, flowi6_to_flowi(fl6)); -} - -static int __net_init icmpv6_sk_init(struct net *net) -{ - struct sock *sk; - int err, i, j; - - net->ipv6.icmp_sk = - kzalloc(nr_cpu_ids * sizeof(struct sock *), GFP_KERNEL); - if (!net->ipv6.icmp_sk) - return -ENOMEM; - - for_each_possible_cpu(i) { - err = inet_ctl_sock_create(&sk, PF_INET6, - SOCK_RAW, IPPROTO_ICMPV6, net); - if (err < 0) { - pr_err("Failed to initialize the ICMP6 control socket (err %d)\n", - err); - goto fail; - } - - net->ipv6.icmp_sk[i] = sk; - - /* Enough space for 2 64K ICMP packets, including - * sk_buff struct overhead. - */ - sk->sk_sndbuf = 2 * SKB_TRUESIZE(64 * 1024); - } - return 0; - - fail: - for (j = 0; j < i; j++) - inet_ctl_sock_destroy(net->ipv6.icmp_sk[j]); - kfree(net->ipv6.icmp_sk); - return err; -} - -static void __net_exit icmpv6_sk_exit(struct net *net) -{ - int i; - - for_each_possible_cpu(i) { - inet_ctl_sock_destroy(net->ipv6.icmp_sk[i]); - } - kfree(net->ipv6.icmp_sk); -} - -static struct pernet_operations icmpv6_sk_ops = { - .init = icmpv6_sk_init, - .exit = icmpv6_sk_exit, -}; - -int __init icmpv6_init(void) -{ - int err; - - err = register_pernet_subsys(&icmpv6_sk_ops); - if (err < 0) - return err; - - err = -EAGAIN; - if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0) - goto fail; - - err = inet6_register_icmp_sender(icmp6_send); - if (err) - goto sender_reg_err; - return 0; - -sender_reg_err: - inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6); -fail: - pr_err("Failed to register ICMP6 protocol\n"); - unregister_pernet_subsys(&icmpv6_sk_ops); - return err; -} - -void icmpv6_cleanup(void) -{ - inet6_unregister_icmp_sender(icmp6_send); - unregister_pernet_subsys(&icmpv6_sk_ops); - inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6); -} - - -static const struct icmp6_err { - int err; - int fatal; -} tab_unreach[] = { - { /* NOROUTE */ - .err = ENETUNREACH, - .fatal = 0, - }, - { /* ADM_PROHIBITED */ - .err = EACCES, - .fatal = 1, - }, - { /* Was NOT_NEIGHBOUR, now reserved */ - .err = EHOSTUNREACH, - .fatal = 0, - }, - { /* ADDR_UNREACH */ - .err = EHOSTUNREACH, - .fatal = 0, - }, - { /* PORT_UNREACH */ - .err = ECONNREFUSED, - .fatal = 1, - }, - { /* POLICY_FAIL */ - .err = EACCES, - .fatal = 1, - }, - { /* REJECT_ROUTE */ - .err = EACCES, - .fatal = 1, - }, -}; - -int icmpv6_err_convert(u8 type, u8 code, int *err) -{ - int fatal = 0; - - *err = EPROTO; - - switch (type) { - case ICMPV6_DEST_UNREACH: - fatal = 1; - if (code < ARRAY_SIZE(tab_unreach)) { - *err = tab_unreach[code].err; - fatal = tab_unreach[code].fatal; - } - break; - - case ICMPV6_PKT_TOOBIG: - *err = EMSGSIZE; - break; - - case ICMPV6_PARAMPROB: - *err = EPROTO; - fatal = 1; - break; - - case ICMPV6_TIME_EXCEED: - *err = EHOSTUNREACH; - break; - } - - return fatal; -} -EXPORT_SYMBOL(icmpv6_err_convert); - -#ifdef CONFIG_SYSCTL -static struct ctl_table ipv6_icmp_table_template[] = { - { - .procname = "ratelimit", - .data = &init_net.ipv6.sysctl.icmpv6_time, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_ms_jiffies, - }, - { }, -}; - -struct ctl_table * __net_init ipv6_icmp_sysctl_init(struct net *net) -{ - struct ctl_table *table; - - table = kmemdup(ipv6_icmp_table_template, - sizeof(ipv6_icmp_table_template), - GFP_KERNEL); - - if (table) - table[0].data = &net->ipv6.sysctl.icmpv6_time; - - return table; -} -#endif diff --git a/src/linux/net/ipv6/inet6_connection_sock.c b/src/linux/net/ipv6/inet6_connection_sock.c deleted file mode 100644 index 532c3ef..0000000 --- a/src/linux/net/ipv6/inet6_connection_sock.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Support for INET6 connection oriented protocols. - * - * Authors: See the TCPv6 sources - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or(at your option) any later version. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -int inet6_csk_bind_conflict(const struct sock *sk, - const struct inet_bind_bucket *tb, bool relax) -{ - const struct sock *sk2; - int reuse = sk->sk_reuse; - int reuseport = sk->sk_reuseport; - kuid_t uid = sock_i_uid((struct sock *)sk); - - /* We must walk the whole port owner list in this case. -DaveM */ - /* - * See comment in inet_csk_bind_conflict about sock lookup - * vs net namespaces issues. - */ - sk_for_each_bound(sk2, &tb->owners) { - if (sk != sk2 && - (!sk->sk_bound_dev_if || - !sk2->sk_bound_dev_if || - sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { - if ((!reuse || !sk2->sk_reuse || - sk2->sk_state == TCP_LISTEN) && - (!reuseport || !sk2->sk_reuseport || - rcu_access_pointer(sk->sk_reuseport_cb) || - (sk2->sk_state != TCP_TIME_WAIT && - !uid_eq(uid, - sock_i_uid((struct sock *)sk2))))) { - if (ipv6_rcv_saddr_equal(sk, sk2, true)) - break; - } - if (!relax && reuse && sk2->sk_reuse && - sk2->sk_state != TCP_LISTEN && - ipv6_rcv_saddr_equal(sk, sk2, true)) - break; - } - } - - return sk2 != NULL; -} -EXPORT_SYMBOL_GPL(inet6_csk_bind_conflict); - -struct dst_entry *inet6_csk_route_req(const struct sock *sk, - struct flowi6 *fl6, - const struct request_sock *req, - u8 proto) -{ - struct inet_request_sock *ireq = inet_rsk(req); - const struct ipv6_pinfo *np = inet6_sk(sk); - struct in6_addr *final_p, final; - struct dst_entry *dst; - - memset(fl6, 0, sizeof(*fl6)); - fl6->flowi6_proto = proto; - fl6->daddr = ireq->ir_v6_rmt_addr; - rcu_read_lock(); - final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final); - rcu_read_unlock(); - fl6->saddr = ireq->ir_v6_loc_addr; - fl6->flowi6_oif = ireq->ir_iif; - fl6->flowi6_mark = ireq->ir_mark; - fl6->fl6_dport = ireq->ir_rmt_port; - fl6->fl6_sport = htons(ireq->ir_num); - security_req_classify_flow(req, flowi6_to_flowi(fl6)); - - dst = ip6_dst_lookup_flow(sk, fl6, final_p); - if (IS_ERR(dst)) - return NULL; - - return dst; -} -EXPORT_SYMBOL(inet6_csk_route_req); - -void inet6_csk_addr2sockaddr(struct sock *sk, struct sockaddr *uaddr) -{ - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) uaddr; - - sin6->sin6_family = AF_INET6; - sin6->sin6_addr = sk->sk_v6_daddr; - sin6->sin6_port = inet_sk(sk)->inet_dport; - /* We do not store received flowlabel for TCP */ - sin6->sin6_flowinfo = 0; - sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr, - sk->sk_bound_dev_if); -} -EXPORT_SYMBOL_GPL(inet6_csk_addr2sockaddr); - -static inline -struct dst_entry *__inet6_csk_dst_check(struct sock *sk, u32 cookie) -{ - return __sk_dst_check(sk, cookie); -} - -static struct dst_entry *inet6_csk_route_socket(struct sock *sk, - struct flowi6 *fl6) -{ - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *np = inet6_sk(sk); - struct in6_addr *final_p, final; - struct dst_entry *dst; - - memset(fl6, 0, sizeof(*fl6)); - fl6->flowi6_proto = sk->sk_protocol; - fl6->daddr = sk->sk_v6_daddr; - fl6->saddr = np->saddr; - fl6->flowlabel = np->flow_label; - IP6_ECN_flow_xmit(sk, fl6->flowlabel); - fl6->flowi6_oif = sk->sk_bound_dev_if; - fl6->flowi6_mark = sk->sk_mark; - fl6->fl6_sport = inet->inet_sport; - fl6->fl6_dport = inet->inet_dport; - security_sk_classify_flow(sk, flowi6_to_flowi(fl6)); - - rcu_read_lock(); - final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final); - rcu_read_unlock(); - - dst = __inet6_csk_dst_check(sk, np->dst_cookie); - if (!dst) { - dst = ip6_dst_lookup_flow(sk, fl6, final_p); - - if (!IS_ERR(dst)) - ip6_dst_store(sk, dst, NULL, NULL); - } - return dst; -} - -int inet6_csk_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl_unused) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct flowi6 fl6; - struct dst_entry *dst; - int res; - - dst = inet6_csk_route_socket(sk, &fl6); - if (IS_ERR(dst)) { - sk->sk_err_soft = -PTR_ERR(dst); - sk->sk_route_caps = 0; - kfree_skb(skb); - return PTR_ERR(dst); - } - - rcu_read_lock(); - skb_dst_set_noref(skb, dst); - - /* Restore final destination back after routing done */ - fl6.daddr = sk->sk_v6_daddr; - - res = ip6_xmit(sk, skb, &fl6, rcu_dereference(np->opt), - np->tclass); - rcu_read_unlock(); - return res; -} -EXPORT_SYMBOL_GPL(inet6_csk_xmit); - -struct dst_entry *inet6_csk_update_pmtu(struct sock *sk, u32 mtu) -{ - struct flowi6 fl6; - struct dst_entry *dst = inet6_csk_route_socket(sk, &fl6); - - if (IS_ERR(dst)) - return NULL; - dst->ops->update_pmtu(dst, sk, NULL, mtu); - - dst = inet6_csk_route_socket(sk, &fl6); - return IS_ERR(dst) ? NULL : dst; -} -EXPORT_SYMBOL_GPL(inet6_csk_update_pmtu); diff --git a/src/linux/net/ipv6/inet6_hashtables.c b/src/linux/net/ipv6/inet6_hashtables.c deleted file mode 100644 index 02761c9..0000000 --- a/src/linux/net/ipv6/inet6_hashtables.c +++ /dev/null @@ -1,321 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * Generic INET6 transport hashtables - * - * Authors: Lotsa people, from code originally in tcp, generalised here - * by Arnaldo Carvalho de Melo - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -u32 inet6_ehashfn(const struct net *net, - const struct in6_addr *laddr, const u16 lport, - const struct in6_addr *faddr, const __be16 fport) -{ - static u32 inet6_ehash_secret __read_mostly; - static u32 ipv6_hash_secret __read_mostly; - - u32 lhash, fhash; - - net_get_random_once(&inet6_ehash_secret, sizeof(inet6_ehash_secret)); - net_get_random_once(&ipv6_hash_secret, sizeof(ipv6_hash_secret)); - - lhash = (__force u32)laddr->s6_addr32[3]; - fhash = __ipv6_addr_jhash(faddr, ipv6_hash_secret); - - return __inet6_ehashfn(lhash, lport, fhash, fport, - inet6_ehash_secret + net_hash_mix(net)); -} - -/* - * Sockets in TCP_CLOSE state are _always_ taken out of the hash, so - * we need not check it for TCP lookups anymore, thanks Alexey. -DaveM - * - * The sockhash lock must be held as a reader here. - */ -struct sock *__inet6_lookup_established(struct net *net, - struct inet_hashinfo *hashinfo, - const struct in6_addr *saddr, - const __be16 sport, - const struct in6_addr *daddr, - const u16 hnum, - const int dif) -{ - struct sock *sk; - const struct hlist_nulls_node *node; - const __portpair ports = INET_COMBINED_PORTS(sport, hnum); - /* Optimize here for direct hit, only listening connections can - * have wildcards anyways. - */ - unsigned int hash = inet6_ehashfn(net, daddr, hnum, saddr, sport); - unsigned int slot = hash & hashinfo->ehash_mask; - struct inet_ehash_bucket *head = &hashinfo->ehash[slot]; - - -begin: - sk_nulls_for_each_rcu(sk, node, &head->chain) { - if (sk->sk_hash != hash) - continue; - if (!INET6_MATCH(sk, net, saddr, daddr, ports, dif)) - continue; - if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) - goto out; - - if (unlikely(!INET6_MATCH(sk, net, saddr, daddr, ports, dif))) { - sock_gen_put(sk); - goto begin; - } - goto found; - } - if (get_nulls_value(node) != slot) - goto begin; -out: - sk = NULL; -found: - return sk; -} -EXPORT_SYMBOL(__inet6_lookup_established); - -static inline int compute_score(struct sock *sk, struct net *net, - const unsigned short hnum, - const struct in6_addr *daddr, - const int dif, bool exact_dif) -{ - int score = -1; - - if (net_eq(sock_net(sk), net) && inet_sk(sk)->inet_num == hnum && - sk->sk_family == PF_INET6) { - - score = 1; - if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { - if (!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, daddr)) - return -1; - score++; - } - if (sk->sk_bound_dev_if || exact_dif) { - if (sk->sk_bound_dev_if != dif) - return -1; - score++; - } - if (sk->sk_incoming_cpu == raw_smp_processor_id()) - score++; - } - return score; -} - -/* called with rcu_read_lock() */ -struct sock *inet6_lookup_listener(struct net *net, - struct inet_hashinfo *hashinfo, - struct sk_buff *skb, int doff, - const struct in6_addr *saddr, - const __be16 sport, const struct in6_addr *daddr, - const unsigned short hnum, const int dif) -{ - unsigned int hash = inet_lhashfn(net, hnum); - struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash]; - int score, hiscore = 0, matches = 0, reuseport = 0; - bool exact_dif = inet6_exact_dif_match(net, skb); - struct sock *sk, *result = NULL; - u32 phash = 0; - - sk_for_each(sk, &ilb->head) { - score = compute_score(sk, net, hnum, daddr, dif, exact_dif); - if (score > hiscore) { - reuseport = sk->sk_reuseport; - if (reuseport) { - phash = inet6_ehashfn(net, daddr, hnum, - saddr, sport); - result = reuseport_select_sock(sk, phash, - skb, doff); - if (result) - return result; - matches = 1; - } - result = sk; - hiscore = score; - } else if (score == hiscore && reuseport) { - matches++; - if (reciprocal_scale(phash, matches) == 0) - result = sk; - phash = next_pseudo_random32(phash); - } - } - return result; -} -EXPORT_SYMBOL_GPL(inet6_lookup_listener); - -struct sock *inet6_lookup(struct net *net, struct inet_hashinfo *hashinfo, - struct sk_buff *skb, int doff, - const struct in6_addr *saddr, const __be16 sport, - const struct in6_addr *daddr, const __be16 dport, - const int dif) -{ - struct sock *sk; - bool refcounted; - - sk = __inet6_lookup(net, hashinfo, skb, doff, saddr, sport, daddr, - ntohs(dport), dif, &refcounted); - if (sk && !refcounted && !atomic_inc_not_zero(&sk->sk_refcnt)) - sk = NULL; - return sk; -} -EXPORT_SYMBOL_GPL(inet6_lookup); - -static int __inet6_check_established(struct inet_timewait_death_row *death_row, - struct sock *sk, const __u16 lport, - struct inet_timewait_sock **twp) -{ - struct inet_hashinfo *hinfo = death_row->hashinfo; - struct inet_sock *inet = inet_sk(sk); - const struct in6_addr *daddr = &sk->sk_v6_rcv_saddr; - const struct in6_addr *saddr = &sk->sk_v6_daddr; - const int dif = sk->sk_bound_dev_if; - const __portpair ports = INET_COMBINED_PORTS(inet->inet_dport, lport); - struct net *net = sock_net(sk); - const unsigned int hash = inet6_ehashfn(net, daddr, lport, saddr, - inet->inet_dport); - struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); - spinlock_t *lock = inet_ehash_lockp(hinfo, hash); - struct sock *sk2; - const struct hlist_nulls_node *node; - struct inet_timewait_sock *tw = NULL; - - spin_lock(lock); - - sk_nulls_for_each(sk2, node, &head->chain) { - if (sk2->sk_hash != hash) - continue; - - if (likely(INET6_MATCH(sk2, net, saddr, daddr, ports, dif))) { - if (sk2->sk_state == TCP_TIME_WAIT) { - tw = inet_twsk(sk2); - if (twsk_unique(sk, sk2, twp)) - break; - } - goto not_unique; - } - } - - /* Must record num and sport now. Otherwise we will see - * in hash table socket with a funny identity. - */ - inet->inet_num = lport; - inet->inet_sport = htons(lport); - sk->sk_hash = hash; - WARN_ON(!sk_unhashed(sk)); - __sk_nulls_add_node_rcu(sk, &head->chain); - if (tw) { - sk_nulls_del_node_init_rcu((struct sock *)tw); - __NET_INC_STATS(net, LINUX_MIB_TIMEWAITRECYCLED); - } - spin_unlock(lock); - sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); - - if (twp) { - *twp = tw; - } else if (tw) { - /* Silly. Should hash-dance instead... */ - inet_twsk_deschedule_put(tw); - } - return 0; - -not_unique: - spin_unlock(lock); - return -EADDRNOTAVAIL; -} - -static u32 inet6_sk_port_offset(const struct sock *sk) -{ - const struct inet_sock *inet = inet_sk(sk); - - return secure_ipv6_port_ephemeral(sk->sk_v6_rcv_saddr.s6_addr32, - sk->sk_v6_daddr.s6_addr32, - inet->inet_dport); -} - -int inet6_hash_connect(struct inet_timewait_death_row *death_row, - struct sock *sk) -{ - u32 port_offset = 0; - - if (!inet_sk(sk)->inet_num) - port_offset = inet6_sk_port_offset(sk); - return __inet_hash_connect(death_row, sk, port_offset, - __inet6_check_established); -} -EXPORT_SYMBOL_GPL(inet6_hash_connect); - -int inet6_hash(struct sock *sk) -{ - int err = 0; - - if (sk->sk_state != TCP_CLOSE) { - local_bh_disable(); - err = __inet_hash(sk, NULL, ipv6_rcv_saddr_equal); - local_bh_enable(); - } - - return err; -} -EXPORT_SYMBOL_GPL(inet6_hash); - -/* match_wildcard == true: IPV6_ADDR_ANY equals to any IPv6 addresses if IPv6 - * only, and any IPv4 addresses if not IPv6 only - * match_wildcard == false: addresses must be exactly the same, i.e. - * IPV6_ADDR_ANY only equals to IPV6_ADDR_ANY, - * and 0.0.0.0 equals to 0.0.0.0 only - */ -int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2, - bool match_wildcard) -{ - const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); - int sk2_ipv6only = inet_v6_ipv6only(sk2); - int addr_type = ipv6_addr_type(&sk->sk_v6_rcv_saddr); - int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED; - - /* if both are mapped, treat as IPv4 */ - if (addr_type == IPV6_ADDR_MAPPED && addr_type2 == IPV6_ADDR_MAPPED) { - if (!sk2_ipv6only) { - if (sk->sk_rcv_saddr == sk2->sk_rcv_saddr) - return 1; - if (!sk->sk_rcv_saddr || !sk2->sk_rcv_saddr) - return match_wildcard; - } - return 0; - } - - if (addr_type == IPV6_ADDR_ANY && addr_type2 == IPV6_ADDR_ANY) - return 1; - - if (addr_type2 == IPV6_ADDR_ANY && match_wildcard && - !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) - return 1; - - if (addr_type == IPV6_ADDR_ANY && match_wildcard && - !(ipv6_only_sock(sk) && addr_type2 == IPV6_ADDR_MAPPED)) - return 1; - - if (sk2_rcv_saddr6 && - ipv6_addr_equal(&sk->sk_v6_rcv_saddr, sk2_rcv_saddr6)) - return 1; - - return 0; -} -EXPORT_SYMBOL_GPL(ipv6_rcv_saddr_equal); diff --git a/src/linux/net/ipv6/ip6_checksum.c b/src/linux/net/ipv6/ip6_checksum.c deleted file mode 100644 index c0cbcb2..0000000 --- a/src/linux/net/ipv6/ip6_checksum.c +++ /dev/null @@ -1,115 +0,0 @@ -#include -#include -#include -#include - -#ifndef _HAVE_ARCH_IPV6_CSUM -__sum16 csum_ipv6_magic(const struct in6_addr *saddr, - const struct in6_addr *daddr, - __u32 len, __u8 proto, __wsum csum) -{ - - int carry; - __u32 ulen; - __u32 uproto; - __u32 sum = (__force u32)csum; - - sum += (__force u32)saddr->s6_addr32[0]; - carry = (sum < (__force u32)saddr->s6_addr32[0]); - sum += carry; - - sum += (__force u32)saddr->s6_addr32[1]; - carry = (sum < (__force u32)saddr->s6_addr32[1]); - sum += carry; - - sum += (__force u32)saddr->s6_addr32[2]; - carry = (sum < (__force u32)saddr->s6_addr32[2]); - sum += carry; - - sum += (__force u32)saddr->s6_addr32[3]; - carry = (sum < (__force u32)saddr->s6_addr32[3]); - sum += carry; - - sum += (__force u32)daddr->s6_addr32[0]; - carry = (sum < (__force u32)daddr->s6_addr32[0]); - sum += carry; - - sum += (__force u32)daddr->s6_addr32[1]; - carry = (sum < (__force u32)daddr->s6_addr32[1]); - sum += carry; - - sum += (__force u32)daddr->s6_addr32[2]; - carry = (sum < (__force u32)daddr->s6_addr32[2]); - sum += carry; - - sum += (__force u32)daddr->s6_addr32[3]; - carry = (sum < (__force u32)daddr->s6_addr32[3]); - sum += carry; - - ulen = (__force u32)htonl((__u32) len); - sum += ulen; - carry = (sum < ulen); - sum += carry; - - uproto = (__force u32)htonl(proto); - sum += uproto; - carry = (sum < uproto); - sum += carry; - - return csum_fold((__force __wsum)sum); -} -EXPORT_SYMBOL(csum_ipv6_magic); -#endif - -int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, int proto) -{ - int err; - - UDP_SKB_CB(skb)->partial_cov = 0; - UDP_SKB_CB(skb)->cscov = skb->len; - - if (proto == IPPROTO_UDPLITE) { - err = udplite_checksum_init(skb, uh); - if (err) - return err; - } - - /* To support RFC 6936 (allow zero checksum in UDP/IPV6 for tunnels) - * we accept a checksum of zero here. When we find the socket - * for the UDP packet we'll check if that socket allows zero checksum - * for IPv6 (set by socket option). - * - * Note, we are only interested in != 0 or == 0, thus the - * force to int. - */ - return (__force int)skb_checksum_init_zero_check(skb, proto, uh->check, - ip6_compute_pseudo); -} -EXPORT_SYMBOL(udp6_csum_init); - -/* Function to set UDP checksum for an IPv6 UDP packet. This is intended - * for the simple case like when setting the checksum for a UDP tunnel. - */ -void udp6_set_csum(bool nocheck, struct sk_buff *skb, - const struct in6_addr *saddr, - const struct in6_addr *daddr, int len) -{ - struct udphdr *uh = udp_hdr(skb); - - if (nocheck) - uh->check = 0; - else if (skb_is_gso(skb)) - uh->check = ~udp_v6_check(len, saddr, daddr, 0); - else if (skb->ip_summed == CHECKSUM_PARTIAL) { - uh->check = 0; - uh->check = udp_v6_check(len, saddr, daddr, lco_csum(skb)); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - } else { - skb->ip_summed = CHECKSUM_PARTIAL; - skb->csum_start = skb_transport_header(skb) - skb->head; - skb->csum_offset = offsetof(struct udphdr, check); - uh->check = ~udp_v6_check(len, saddr, daddr, 0); - } -} -EXPORT_SYMBOL(udp6_set_csum); diff --git a/src/linux/net/ipv6/ip6_fib.c b/src/linux/net/ipv6/ip6_fib.c deleted file mode 100644 index ef54852..0000000 --- a/src/linux/net/ipv6/ip6_fib.c +++ /dev/null @@ -1,2120 +0,0 @@ -/* - * Linux INET6 implementation - * Forwarding Information Database - * - * Authors: - * Pedro Roque - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Changes: - * Yuji SEKIYA @USAGI: Support default route on router node; - * remove ip6_null_entry from the top of - * routing table. - * Ville Nuorvala: Fixed routing subtrees. - */ - -#define pr_fmt(fmt) "IPv6: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include - -#define RT6_DEBUG 2 - -#if RT6_DEBUG >= 3 -#define RT6_TRACE(x...) pr_debug(x) -#else -#define RT6_TRACE(x...) do { ; } while (0) -#endif - -static struct kmem_cache *fib6_node_kmem __read_mostly; - -struct fib6_cleaner { - struct fib6_walker w; - struct net *net; - int (*func)(struct rt6_info *, void *arg); - int sernum; - void *arg; -}; - -#ifdef CONFIG_IPV6_SUBTREES -#define FWS_INIT FWS_S -#else -#define FWS_INIT FWS_L -#endif - -static void fib6_prune_clones(struct net *net, struct fib6_node *fn); -static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn); -static struct fib6_node *fib6_repair_tree(struct net *net, struct fib6_node *fn); -static int fib6_walk(struct net *net, struct fib6_walker *w); -static int fib6_walk_continue(struct fib6_walker *w); - -/* - * A routing update causes an increase of the serial number on the - * affected subtree. This allows for cached routes to be asynchronously - * tested when modifications are made to the destination cache as a - * result of redirects, path MTU changes, etc. - */ - -static void fib6_gc_timer_cb(unsigned long arg); - -#define FOR_WALKERS(net, w) \ - list_for_each_entry(w, &(net)->ipv6.fib6_walkers, lh) - -static void fib6_walker_link(struct net *net, struct fib6_walker *w) -{ - write_lock_bh(&net->ipv6.fib6_walker_lock); - list_add(&w->lh, &net->ipv6.fib6_walkers); - write_unlock_bh(&net->ipv6.fib6_walker_lock); -} - -static void fib6_walker_unlink(struct net *net, struct fib6_walker *w) -{ - write_lock_bh(&net->ipv6.fib6_walker_lock); - list_del(&w->lh); - write_unlock_bh(&net->ipv6.fib6_walker_lock); -} - -static int fib6_new_sernum(struct net *net) -{ - int new, old; - - do { - old = atomic_read(&net->ipv6.fib6_sernum); - new = old < INT_MAX ? old + 1 : 1; - } while (atomic_cmpxchg(&net->ipv6.fib6_sernum, - old, new) != old); - return new; -} - -enum { - FIB6_NO_SERNUM_CHANGE = 0, -}; - -/* - * Auxiliary address test functions for the radix tree. - * - * These assume a 32bit processor (although it will work on - * 64bit processors) - */ - -/* - * test bit - */ -#if defined(__LITTLE_ENDIAN) -# define BITOP_BE32_SWIZZLE (0x1F & ~7) -#else -# define BITOP_BE32_SWIZZLE 0 -#endif - -static __be32 addr_bit_set(const void *token, int fn_bit) -{ - const __be32 *addr = token; - /* - * Here, - * 1 << ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f) - * is optimized version of - * htonl(1 << ((~fn_bit)&0x1F)) - * See include/asm-generic/bitops/le.h. - */ - return (__force __be32)(1 << ((~fn_bit ^ BITOP_BE32_SWIZZLE) & 0x1f)) & - addr[fn_bit >> 5]; -} - -static struct fib6_node *node_alloc(void) -{ - struct fib6_node *fn; - - fn = kmem_cache_zalloc(fib6_node_kmem, GFP_ATOMIC); - - return fn; -} - -static void node_free(struct fib6_node *fn) -{ - kmem_cache_free(fib6_node_kmem, fn); -} - -static void rt6_rcu_free(struct rt6_info *rt) -{ - call_rcu(&rt->dst.rcu_head, dst_rcu_free); -} - -static void rt6_free_pcpu(struct rt6_info *non_pcpu_rt) -{ - int cpu; - - if (!non_pcpu_rt->rt6i_pcpu) - return; - - for_each_possible_cpu(cpu) { - struct rt6_info **ppcpu_rt; - struct rt6_info *pcpu_rt; - - ppcpu_rt = per_cpu_ptr(non_pcpu_rt->rt6i_pcpu, cpu); - pcpu_rt = *ppcpu_rt; - if (pcpu_rt) { - rt6_rcu_free(pcpu_rt); - *ppcpu_rt = NULL; - } - } - - free_percpu(non_pcpu_rt->rt6i_pcpu); - non_pcpu_rt->rt6i_pcpu = NULL; -} - -static void rt6_release(struct rt6_info *rt) -{ - if (atomic_dec_and_test(&rt->rt6i_ref)) { - rt6_free_pcpu(rt); - rt6_rcu_free(rt); - } -} - -static void fib6_link_table(struct net *net, struct fib6_table *tb) -{ - unsigned int h; - - /* - * Initialize table lock at a single place to give lockdep a key, - * tables aren't visible prior to being linked to the list. - */ - rwlock_init(&tb->tb6_lock); - - h = tb->tb6_id & (FIB6_TABLE_HASHSZ - 1); - - /* - * No protection necessary, this is the only list mutatation - * operation, tables never disappear once they exist. - */ - hlist_add_head_rcu(&tb->tb6_hlist, &net->ipv6.fib_table_hash[h]); -} - -#ifdef CONFIG_IPV6_MULTIPLE_TABLES - -static struct fib6_table *fib6_alloc_table(struct net *net, u32 id) -{ - struct fib6_table *table; - - table = kzalloc(sizeof(*table), GFP_ATOMIC); - if (table) { - table->tb6_id = id; - table->tb6_root.leaf = net->ipv6.ip6_null_entry; - table->tb6_root.fn_flags = RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; - inet_peer_base_init(&table->tb6_peers); - } - - return table; -} - -struct fib6_table *fib6_new_table(struct net *net, u32 id) -{ - struct fib6_table *tb; - - if (id == 0) - id = RT6_TABLE_MAIN; - tb = fib6_get_table(net, id); - if (tb) - return tb; - - tb = fib6_alloc_table(net, id); - if (tb) - fib6_link_table(net, tb); - - return tb; -} -EXPORT_SYMBOL_GPL(fib6_new_table); - -struct fib6_table *fib6_get_table(struct net *net, u32 id) -{ - struct fib6_table *tb; - struct hlist_head *head; - unsigned int h; - - if (id == 0) - id = RT6_TABLE_MAIN; - h = id & (FIB6_TABLE_HASHSZ - 1); - rcu_read_lock(); - head = &net->ipv6.fib_table_hash[h]; - hlist_for_each_entry_rcu(tb, head, tb6_hlist) { - if (tb->tb6_id == id) { - rcu_read_unlock(); - return tb; - } - } - rcu_read_unlock(); - - return NULL; -} -EXPORT_SYMBOL_GPL(fib6_get_table); - -static void __net_init fib6_tables_init(struct net *net) -{ - fib6_link_table(net, net->ipv6.fib6_main_tbl); - fib6_link_table(net, net->ipv6.fib6_local_tbl); -} -#else - -struct fib6_table *fib6_new_table(struct net *net, u32 id) -{ - return fib6_get_table(net, id); -} - -struct fib6_table *fib6_get_table(struct net *net, u32 id) -{ - return net->ipv6.fib6_main_tbl; -} - -struct dst_entry *fib6_rule_lookup(struct net *net, struct flowi6 *fl6, - int flags, pol_lookup_t lookup) -{ - struct rt6_info *rt; - - rt = lookup(net, net->ipv6.fib6_main_tbl, fl6, flags); - if (rt->rt6i_flags & RTF_REJECT && - rt->dst.error == -EAGAIN) { - ip6_rt_put(rt); - rt = net->ipv6.ip6_null_entry; - dst_hold(&rt->dst); - } - - return &rt->dst; -} - -static void __net_init fib6_tables_init(struct net *net) -{ - fib6_link_table(net, net->ipv6.fib6_main_tbl); -} - -#endif - -static int fib6_dump_node(struct fib6_walker *w) -{ - int res; - struct rt6_info *rt; - - for (rt = w->leaf; rt; rt = rt->dst.rt6_next) { - res = rt6_dump_route(rt, w->args); - if (res < 0) { - /* Frame is full, suspend walking */ - w->leaf = rt; - return 1; - } - } - w->leaf = NULL; - return 0; -} - -static void fib6_dump_end(struct netlink_callback *cb) -{ - struct net *net = sock_net(cb->skb->sk); - struct fib6_walker *w = (void *)cb->args[2]; - - if (w) { - if (cb->args[4]) { - cb->args[4] = 0; - fib6_walker_unlink(net, w); - } - cb->args[2] = 0; - kfree(w); - } - cb->done = (void *)cb->args[3]; - cb->args[1] = 3; -} - -static int fib6_dump_done(struct netlink_callback *cb) -{ - fib6_dump_end(cb); - return cb->done ? cb->done(cb) : 0; -} - -static int fib6_dump_table(struct fib6_table *table, struct sk_buff *skb, - struct netlink_callback *cb) -{ - struct net *net = sock_net(skb->sk); - struct fib6_walker *w; - int res; - - w = (void *)cb->args[2]; - w->root = &table->tb6_root; - - if (cb->args[4] == 0) { - w->count = 0; - w->skip = 0; - - read_lock_bh(&table->tb6_lock); - res = fib6_walk(net, w); - read_unlock_bh(&table->tb6_lock); - if (res > 0) { - cb->args[4] = 1; - cb->args[5] = w->root->fn_sernum; - } - } else { - if (cb->args[5] != w->root->fn_sernum) { - /* Begin at the root if the tree changed */ - cb->args[5] = w->root->fn_sernum; - w->state = FWS_INIT; - w->node = w->root; - w->skip = w->count; - } else - w->skip = 0; - - read_lock_bh(&table->tb6_lock); - res = fib6_walk_continue(w); - read_unlock_bh(&table->tb6_lock); - if (res <= 0) { - fib6_walker_unlink(net, w); - cb->args[4] = 0; - } - } - - return res; -} - -static int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) -{ - struct net *net = sock_net(skb->sk); - unsigned int h, s_h; - unsigned int e = 0, s_e; - struct rt6_rtnl_dump_arg arg; - struct fib6_walker *w; - struct fib6_table *tb; - struct hlist_head *head; - int res = 0; - - s_h = cb->args[0]; - s_e = cb->args[1]; - - w = (void *)cb->args[2]; - if (!w) { - /* New dump: - * - * 1. hook callback destructor. - */ - cb->args[3] = (long)cb->done; - cb->done = fib6_dump_done; - - /* - * 2. allocate and initialize walker. - */ - w = kzalloc(sizeof(*w), GFP_ATOMIC); - if (!w) - return -ENOMEM; - w->func = fib6_dump_node; - cb->args[2] = (long)w; - } - - arg.skb = skb; - arg.cb = cb; - arg.net = net; - w->args = &arg; - - rcu_read_lock(); - for (h = s_h; h < FIB6_TABLE_HASHSZ; h++, s_e = 0) { - e = 0; - head = &net->ipv6.fib_table_hash[h]; - hlist_for_each_entry_rcu(tb, head, tb6_hlist) { - if (e < s_e) - goto next; - res = fib6_dump_table(tb, skb, cb); - if (res != 0) - goto out; -next: - e++; - } - } -out: - rcu_read_unlock(); - cb->args[1] = e; - cb->args[0] = h; - - res = res < 0 ? res : skb->len; - if (res <= 0) - fib6_dump_end(cb); - return res; -} - -/* - * Routing Table - * - * return the appropriate node for a routing tree "add" operation - * by either creating and inserting or by returning an existing - * node. - */ - -static struct fib6_node *fib6_add_1(struct fib6_node *root, - struct in6_addr *addr, int plen, - int offset, int allow_create, - int replace_required, int sernum) -{ - struct fib6_node *fn, *in, *ln; - struct fib6_node *pn = NULL; - struct rt6key *key; - int bit; - __be32 dir = 0; - - RT6_TRACE("fib6_add_1\n"); - - /* insert node in tree */ - - fn = root; - - do { - key = (struct rt6key *)((u8 *)fn->leaf + offset); - - /* - * Prefix match - */ - if (plen < fn->fn_bit || - !ipv6_prefix_equal(&key->addr, addr, fn->fn_bit)) { - if (!allow_create) { - if (replace_required) { - pr_warn("Can't replace route, no match found\n"); - return ERR_PTR(-ENOENT); - } - pr_warn("NLM_F_CREATE should be set when creating new route\n"); - } - goto insert_above; - } - - /* - * Exact match ? - */ - - if (plen == fn->fn_bit) { - /* clean up an intermediate node */ - if (!(fn->fn_flags & RTN_RTINFO)) { - rt6_release(fn->leaf); - fn->leaf = NULL; - } - - fn->fn_sernum = sernum; - - return fn; - } - - /* - * We have more bits to go - */ - - /* Try to walk down on tree. */ - fn->fn_sernum = sernum; - dir = addr_bit_set(addr, fn->fn_bit); - pn = fn; - fn = dir ? fn->right : fn->left; - } while (fn); - - if (!allow_create) { - /* We should not create new node because - * NLM_F_REPLACE was specified without NLM_F_CREATE - * I assume it is safe to require NLM_F_CREATE when - * REPLACE flag is used! Later we may want to remove the - * check for replace_required, because according - * to netlink specification, NLM_F_CREATE - * MUST be specified if new route is created. - * That would keep IPv6 consistent with IPv4 - */ - if (replace_required) { - pr_warn("Can't replace route, no match found\n"); - return ERR_PTR(-ENOENT); - } - pr_warn("NLM_F_CREATE should be set when creating new route\n"); - } - /* - * We walked to the bottom of tree. - * Create new leaf node without children. - */ - - ln = node_alloc(); - - if (!ln) - return ERR_PTR(-ENOMEM); - ln->fn_bit = plen; - - ln->parent = pn; - ln->fn_sernum = sernum; - - if (dir) - pn->right = ln; - else - pn->left = ln; - - return ln; - - -insert_above: - /* - * split since we don't have a common prefix anymore or - * we have a less significant route. - * we've to insert an intermediate node on the list - * this new node will point to the one we need to create - * and the current - */ - - pn = fn->parent; - - /* find 1st bit in difference between the 2 addrs. - - See comment in __ipv6_addr_diff: bit may be an invalid value, - but if it is >= plen, the value is ignored in any case. - */ - - bit = __ipv6_addr_diff(addr, &key->addr, sizeof(*addr)); - - /* - * (intermediate)[in] - * / \ - * (new leaf node)[ln] (old node)[fn] - */ - if (plen > bit) { - in = node_alloc(); - ln = node_alloc(); - - if (!in || !ln) { - if (in) - node_free(in); - if (ln) - node_free(ln); - return ERR_PTR(-ENOMEM); - } - - /* - * new intermediate node. - * RTN_RTINFO will - * be off since that an address that chooses one of - * the branches would not match less specific routes - * in the other branch - */ - - in->fn_bit = bit; - - in->parent = pn; - in->leaf = fn->leaf; - atomic_inc(&in->leaf->rt6i_ref); - - in->fn_sernum = sernum; - - /* update parent pointer */ - if (dir) - pn->right = in; - else - pn->left = in; - - ln->fn_bit = plen; - - ln->parent = in; - fn->parent = in; - - ln->fn_sernum = sernum; - - if (addr_bit_set(addr, bit)) { - in->right = ln; - in->left = fn; - } else { - in->left = ln; - in->right = fn; - } - } else { /* plen <= bit */ - - /* - * (new leaf node)[ln] - * / \ - * (old node)[fn] NULL - */ - - ln = node_alloc(); - - if (!ln) - return ERR_PTR(-ENOMEM); - - ln->fn_bit = plen; - - ln->parent = pn; - - ln->fn_sernum = sernum; - - if (dir) - pn->right = ln; - else - pn->left = ln; - - if (addr_bit_set(&key->addr, plen)) - ln->right = fn; - else - ln->left = fn; - - fn->parent = ln; - } - return ln; -} - -static bool rt6_qualify_for_ecmp(struct rt6_info *rt) -{ - return (rt->rt6i_flags & (RTF_GATEWAY|RTF_ADDRCONF|RTF_DYNAMIC)) == - RTF_GATEWAY; -} - -static void fib6_copy_metrics(u32 *mp, const struct mx6_config *mxc) -{ - int i; - - for (i = 0; i < RTAX_MAX; i++) { - if (test_bit(i, mxc->mx_valid)) - mp[i] = mxc->mx[i]; - } -} - -static int fib6_commit_metrics(struct dst_entry *dst, struct mx6_config *mxc) -{ - if (!mxc->mx) - return 0; - - if (dst->flags & DST_HOST) { - u32 *mp = dst_metrics_write_ptr(dst); - - if (unlikely(!mp)) - return -ENOMEM; - - fib6_copy_metrics(mp, mxc); - } else { - dst_init_metrics(dst, mxc->mx, false); - - /* We've stolen mx now. */ - mxc->mx = NULL; - } - - return 0; -} - -static void fib6_purge_rt(struct rt6_info *rt, struct fib6_node *fn, - struct net *net) -{ - if (atomic_read(&rt->rt6i_ref) != 1) { - /* This route is used as dummy address holder in some split - * nodes. It is not leaked, but it still holds other resources, - * which must be released in time. So, scan ascendant nodes - * and replace dummy references to this route with references - * to still alive ones. - */ - while (fn) { - if (!(fn->fn_flags & RTN_RTINFO) && fn->leaf == rt) { - fn->leaf = fib6_find_prefix(net, fn); - atomic_inc(&fn->leaf->rt6i_ref); - rt6_release(rt); - } - fn = fn->parent; - } - /* No more references are possible at this point. */ - BUG_ON(atomic_read(&rt->rt6i_ref) != 1); - } -} - -/* - * Insert routing information in a node. - */ - -static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, - struct nl_info *info, struct mx6_config *mxc) -{ - struct rt6_info *iter = NULL; - struct rt6_info **ins; - struct rt6_info **fallback_ins = NULL; - int replace = (info->nlh && - (info->nlh->nlmsg_flags & NLM_F_REPLACE)); - int add = (!info->nlh || - (info->nlh->nlmsg_flags & NLM_F_CREATE)); - int found = 0; - bool rt_can_ecmp = rt6_qualify_for_ecmp(rt); - u16 nlflags = NLM_F_EXCL; - int err; - - ins = &fn->leaf; - - for (iter = fn->leaf; iter; iter = iter->dst.rt6_next) { - /* - * Search for duplicates - */ - - if (iter->rt6i_metric == rt->rt6i_metric) { - /* - * Same priority level - */ - if (info->nlh && - (info->nlh->nlmsg_flags & NLM_F_EXCL)) - return -EEXIST; - - nlflags &= ~NLM_F_EXCL; - if (replace) { - if (rt_can_ecmp == rt6_qualify_for_ecmp(iter)) { - found++; - break; - } - if (rt_can_ecmp) - fallback_ins = fallback_ins ?: ins; - goto next_iter; - } - - if (iter->dst.dev == rt->dst.dev && - iter->rt6i_idev == rt->rt6i_idev && - ipv6_addr_equal(&iter->rt6i_gateway, - &rt->rt6i_gateway)) { - if (rt->rt6i_nsiblings) - rt->rt6i_nsiblings = 0; - if (!(iter->rt6i_flags & RTF_EXPIRES)) - return -EEXIST; - if (!(rt->rt6i_flags & RTF_EXPIRES)) - rt6_clean_expires(iter); - else - rt6_set_expires(iter, rt->dst.expires); - iter->rt6i_pmtu = rt->rt6i_pmtu; - return -EEXIST; - } - /* If we have the same destination and the same metric, - * but not the same gateway, then the route we try to - * add is sibling to this route, increment our counter - * of siblings, and later we will add our route to the - * list. - * Only static routes (which don't have flag - * RTF_EXPIRES) are used for ECMPv6. - * - * To avoid long list, we only had siblings if the - * route have a gateway. - */ - if (rt_can_ecmp && - rt6_qualify_for_ecmp(iter)) - rt->rt6i_nsiblings++; - } - - if (iter->rt6i_metric > rt->rt6i_metric) - break; - -next_iter: - ins = &iter->dst.rt6_next; - } - - if (fallback_ins && !found) { - /* No ECMP-able route found, replace first non-ECMP one */ - ins = fallback_ins; - iter = *ins; - found++; - } - - /* Reset round-robin state, if necessary */ - if (ins == &fn->leaf) - fn->rr_ptr = NULL; - - /* Link this route to others same route. */ - if (rt->rt6i_nsiblings) { - unsigned int rt6i_nsiblings; - struct rt6_info *sibling, *temp_sibling; - - /* Find the first route that have the same metric */ - sibling = fn->leaf; - while (sibling) { - if (sibling->rt6i_metric == rt->rt6i_metric && - rt6_qualify_for_ecmp(sibling)) { - list_add_tail(&rt->rt6i_siblings, - &sibling->rt6i_siblings); - break; - } - sibling = sibling->dst.rt6_next; - } - /* For each sibling in the list, increment the counter of - * siblings. BUG() if counters does not match, list of siblings - * is broken! - */ - rt6i_nsiblings = 0; - list_for_each_entry_safe(sibling, temp_sibling, - &rt->rt6i_siblings, rt6i_siblings) { - sibling->rt6i_nsiblings++; - BUG_ON(sibling->rt6i_nsiblings != rt->rt6i_nsiblings); - rt6i_nsiblings++; - } - BUG_ON(rt6i_nsiblings != rt->rt6i_nsiblings); - } - - /* - * insert node - */ - if (!replace) { - if (!add) - pr_warn("NLM_F_CREATE should be set when creating new route\n"); - -add: - nlflags |= NLM_F_CREATE; - err = fib6_commit_metrics(&rt->dst, mxc); - if (err) - return err; - - rt->dst.rt6_next = iter; - *ins = rt; - rt->rt6i_node = fn; - atomic_inc(&rt->rt6i_ref); - inet6_rt_notify(RTM_NEWROUTE, rt, info, nlflags); - info->nl_net->ipv6.rt6_stats->fib_rt_entries++; - - if (!(fn->fn_flags & RTN_RTINFO)) { - info->nl_net->ipv6.rt6_stats->fib_route_nodes++; - fn->fn_flags |= RTN_RTINFO; - } - - } else { - int nsiblings; - - if (!found) { - if (add) - goto add; - pr_warn("NLM_F_REPLACE set, but no existing node found!\n"); - return -ENOENT; - } - - err = fib6_commit_metrics(&rt->dst, mxc); - if (err) - return err; - - *ins = rt; - rt->rt6i_node = fn; - rt->dst.rt6_next = iter->dst.rt6_next; - atomic_inc(&rt->rt6i_ref); - inet6_rt_notify(RTM_NEWROUTE, rt, info, NLM_F_REPLACE); - if (!(fn->fn_flags & RTN_RTINFO)) { - info->nl_net->ipv6.rt6_stats->fib_route_nodes++; - fn->fn_flags |= RTN_RTINFO; - } - nsiblings = iter->rt6i_nsiblings; - fib6_purge_rt(iter, fn, info->nl_net); - rt6_release(iter); - - if (nsiblings) { - /* Replacing an ECMP route, remove all siblings */ - ins = &rt->dst.rt6_next; - iter = *ins; - while (iter) { - if (rt6_qualify_for_ecmp(iter)) { - *ins = iter->dst.rt6_next; - fib6_purge_rt(iter, fn, info->nl_net); - rt6_release(iter); - nsiblings--; - } else { - ins = &iter->dst.rt6_next; - } - iter = *ins; - } - WARN_ON(nsiblings != 0); - } - } - - return 0; -} - -static void fib6_start_gc(struct net *net, struct rt6_info *rt) -{ - if (!timer_pending(&net->ipv6.ip6_fib_timer) && - (rt->rt6i_flags & (RTF_EXPIRES | RTF_CACHE))) - mod_timer(&net->ipv6.ip6_fib_timer, - jiffies + net->ipv6.sysctl.ip6_rt_gc_interval); -} - -void fib6_force_start_gc(struct net *net) -{ - if (!timer_pending(&net->ipv6.ip6_fib_timer)) - mod_timer(&net->ipv6.ip6_fib_timer, - jiffies + net->ipv6.sysctl.ip6_rt_gc_interval); -} - -/* - * Add routing information to the routing tree. - * / - * with source addr info in sub-trees - */ - -int fib6_add(struct fib6_node *root, struct rt6_info *rt, - struct nl_info *info, struct mx6_config *mxc) -{ - struct fib6_node *fn, *pn = NULL; - int err = -ENOMEM; - int allow_create = 1; - int replace_required = 0; - int sernum = fib6_new_sernum(info->nl_net); - - if (WARN_ON_ONCE((rt->dst.flags & DST_NOCACHE) && - !atomic_read(&rt->dst.__refcnt))) - return -EINVAL; - - if (info->nlh) { - if (!(info->nlh->nlmsg_flags & NLM_F_CREATE)) - allow_create = 0; - if (info->nlh->nlmsg_flags & NLM_F_REPLACE) - replace_required = 1; - } - if (!allow_create && !replace_required) - pr_warn("RTM_NEWROUTE with no NLM_F_CREATE or NLM_F_REPLACE\n"); - - fn = fib6_add_1(root, &rt->rt6i_dst.addr, rt->rt6i_dst.plen, - offsetof(struct rt6_info, rt6i_dst), allow_create, - replace_required, sernum); - if (IS_ERR(fn)) { - err = PTR_ERR(fn); - fn = NULL; - goto out; - } - - pn = fn; - -#ifdef CONFIG_IPV6_SUBTREES - if (rt->rt6i_src.plen) { - struct fib6_node *sn; - - if (!fn->subtree) { - struct fib6_node *sfn; - - /* - * Create subtree. - * - * fn[main tree] - * | - * sfn[subtree root] - * \ - * sn[new leaf node] - */ - - /* Create subtree root node */ - sfn = node_alloc(); - if (!sfn) - goto st_failure; - - sfn->leaf = info->nl_net->ipv6.ip6_null_entry; - atomic_inc(&info->nl_net->ipv6.ip6_null_entry->rt6i_ref); - sfn->fn_flags = RTN_ROOT; - sfn->fn_sernum = sernum; - - /* Now add the first leaf node to new subtree */ - - sn = fib6_add_1(sfn, &rt->rt6i_src.addr, - rt->rt6i_src.plen, - offsetof(struct rt6_info, rt6i_src), - allow_create, replace_required, sernum); - - if (IS_ERR(sn)) { - /* If it is failed, discard just allocated - root, and then (in st_failure) stale node - in main tree. - */ - node_free(sfn); - err = PTR_ERR(sn); - goto st_failure; - } - - /* Now link new subtree to main tree */ - sfn->parent = fn; - fn->subtree = sfn; - } else { - sn = fib6_add_1(fn->subtree, &rt->rt6i_src.addr, - rt->rt6i_src.plen, - offsetof(struct rt6_info, rt6i_src), - allow_create, replace_required, sernum); - - if (IS_ERR(sn)) { - err = PTR_ERR(sn); - goto st_failure; - } - } - - if (!fn->leaf) { - fn->leaf = rt; - atomic_inc(&rt->rt6i_ref); - } - fn = sn; - } -#endif - - err = fib6_add_rt2node(fn, rt, info, mxc); - if (!err) { - fib6_start_gc(info->nl_net, rt); - if (!(rt->rt6i_flags & RTF_CACHE)) - fib6_prune_clones(info->nl_net, pn); - rt->dst.flags &= ~DST_NOCACHE; - } - -out: - if (err) { -#ifdef CONFIG_IPV6_SUBTREES - /* - * If fib6_add_1 has cleared the old leaf pointer in the - * super-tree leaf node we have to find a new one for it. - */ - if (pn != fn && pn->leaf == rt) { - pn->leaf = NULL; - atomic_dec(&rt->rt6i_ref); - } - if (pn != fn && !pn->leaf && !(pn->fn_flags & RTN_RTINFO)) { - pn->leaf = fib6_find_prefix(info->nl_net, pn); -#if RT6_DEBUG >= 2 - if (!pn->leaf) { - WARN_ON(pn->leaf == NULL); - pn->leaf = info->nl_net->ipv6.ip6_null_entry; - } -#endif - atomic_inc(&pn->leaf->rt6i_ref); - } -#endif - if (!(rt->dst.flags & DST_NOCACHE)) - dst_free(&rt->dst); - } - return err; - -#ifdef CONFIG_IPV6_SUBTREES - /* Subtree creation failed, probably main tree node - is orphan. If it is, shoot it. - */ -st_failure: - if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT))) - fib6_repair_tree(info->nl_net, fn); - if (!(rt->dst.flags & DST_NOCACHE)) - dst_free(&rt->dst); - return err; -#endif -} - -/* - * Routing tree lookup - * - */ - -struct lookup_args { - int offset; /* key offset on rt6_info */ - const struct in6_addr *addr; /* search key */ -}; - -static struct fib6_node *fib6_lookup_1(struct fib6_node *root, - struct lookup_args *args) -{ - struct fib6_node *fn; - __be32 dir; - - if (unlikely(args->offset == 0)) - return NULL; - - /* - * Descend on a tree - */ - - fn = root; - - for (;;) { - struct fib6_node *next; - - dir = addr_bit_set(args->addr, fn->fn_bit); - - next = dir ? fn->right : fn->left; - - if (next) { - fn = next; - continue; - } - break; - } - - while (fn) { - if (FIB6_SUBTREE(fn) || fn->fn_flags & RTN_RTINFO) { - struct rt6key *key; - - key = (struct rt6key *) ((u8 *) fn->leaf + - args->offset); - - if (ipv6_prefix_equal(&key->addr, args->addr, key->plen)) { -#ifdef CONFIG_IPV6_SUBTREES - if (fn->subtree) { - struct fib6_node *sfn; - sfn = fib6_lookup_1(fn->subtree, - args + 1); - if (!sfn) - goto backtrack; - fn = sfn; - } -#endif - if (fn->fn_flags & RTN_RTINFO) - return fn; - } - } -#ifdef CONFIG_IPV6_SUBTREES -backtrack: -#endif - if (fn->fn_flags & RTN_ROOT) - break; - - fn = fn->parent; - } - - return NULL; -} - -struct fib6_node *fib6_lookup(struct fib6_node *root, const struct in6_addr *daddr, - const struct in6_addr *saddr) -{ - struct fib6_node *fn; - struct lookup_args args[] = { - { - .offset = offsetof(struct rt6_info, rt6i_dst), - .addr = daddr, - }, -#ifdef CONFIG_IPV6_SUBTREES - { - .offset = offsetof(struct rt6_info, rt6i_src), - .addr = saddr, - }, -#endif - { - .offset = 0, /* sentinel */ - } - }; - - fn = fib6_lookup_1(root, daddr ? args : args + 1); - if (!fn || fn->fn_flags & RTN_TL_ROOT) - fn = root; - - return fn; -} - -/* - * Get node with specified destination prefix (and source prefix, - * if subtrees are used) - */ - - -static struct fib6_node *fib6_locate_1(struct fib6_node *root, - const struct in6_addr *addr, - int plen, int offset) -{ - struct fib6_node *fn; - - for (fn = root; fn ; ) { - struct rt6key *key = (struct rt6key *)((u8 *)fn->leaf + offset); - - /* - * Prefix match - */ - if (plen < fn->fn_bit || - !ipv6_prefix_equal(&key->addr, addr, fn->fn_bit)) - return NULL; - - if (plen == fn->fn_bit) - return fn; - - /* - * We have more bits to go - */ - if (addr_bit_set(addr, fn->fn_bit)) - fn = fn->right; - else - fn = fn->left; - } - return NULL; -} - -struct fib6_node *fib6_locate(struct fib6_node *root, - const struct in6_addr *daddr, int dst_len, - const struct in6_addr *saddr, int src_len) -{ - struct fib6_node *fn; - - fn = fib6_locate_1(root, daddr, dst_len, - offsetof(struct rt6_info, rt6i_dst)); - -#ifdef CONFIG_IPV6_SUBTREES - if (src_len) { - WARN_ON(saddr == NULL); - if (fn && fn->subtree) - fn = fib6_locate_1(fn->subtree, saddr, src_len, - offsetof(struct rt6_info, rt6i_src)); - } -#endif - - if (fn && fn->fn_flags & RTN_RTINFO) - return fn; - - return NULL; -} - - -/* - * Deletion - * - */ - -static struct rt6_info *fib6_find_prefix(struct net *net, struct fib6_node *fn) -{ - if (fn->fn_flags & RTN_ROOT) - return net->ipv6.ip6_null_entry; - - while (fn) { - if (fn->left) - return fn->left->leaf; - if (fn->right) - return fn->right->leaf; - - fn = FIB6_SUBTREE(fn); - } - return NULL; -} - -/* - * Called to trim the tree of intermediate nodes when possible. "fn" - * is the node we want to try and remove. - */ - -static struct fib6_node *fib6_repair_tree(struct net *net, - struct fib6_node *fn) -{ - int children; - int nstate; - struct fib6_node *child, *pn; - struct fib6_walker *w; - int iter = 0; - - for (;;) { - RT6_TRACE("fixing tree: plen=%d iter=%d\n", fn->fn_bit, iter); - iter++; - - WARN_ON(fn->fn_flags & RTN_RTINFO); - WARN_ON(fn->fn_flags & RTN_TL_ROOT); - WARN_ON(fn->leaf); - - children = 0; - child = NULL; - if (fn->right) - child = fn->right, children |= 1; - if (fn->left) - child = fn->left, children |= 2; - - if (children == 3 || FIB6_SUBTREE(fn) -#ifdef CONFIG_IPV6_SUBTREES - /* Subtree root (i.e. fn) may have one child */ - || (children && fn->fn_flags & RTN_ROOT) -#endif - ) { - fn->leaf = fib6_find_prefix(net, fn); -#if RT6_DEBUG >= 2 - if (!fn->leaf) { - WARN_ON(!fn->leaf); - fn->leaf = net->ipv6.ip6_null_entry; - } -#endif - atomic_inc(&fn->leaf->rt6i_ref); - return fn->parent; - } - - pn = fn->parent; -#ifdef CONFIG_IPV6_SUBTREES - if (FIB6_SUBTREE(pn) == fn) { - WARN_ON(!(fn->fn_flags & RTN_ROOT)); - FIB6_SUBTREE(pn) = NULL; - nstate = FWS_L; - } else { - WARN_ON(fn->fn_flags & RTN_ROOT); -#endif - if (pn->right == fn) - pn->right = child; - else if (pn->left == fn) - pn->left = child; -#if RT6_DEBUG >= 2 - else - WARN_ON(1); -#endif - if (child) - child->parent = pn; - nstate = FWS_R; -#ifdef CONFIG_IPV6_SUBTREES - } -#endif - - read_lock(&net->ipv6.fib6_walker_lock); - FOR_WALKERS(net, w) { - if (!child) { - if (w->root == fn) { - w->root = w->node = NULL; - RT6_TRACE("W %p adjusted by delroot 1\n", w); - } else if (w->node == fn) { - RT6_TRACE("W %p adjusted by delnode 1, s=%d/%d\n", w, w->state, nstate); - w->node = pn; - w->state = nstate; - } - } else { - if (w->root == fn) { - w->root = child; - RT6_TRACE("W %p adjusted by delroot 2\n", w); - } - if (w->node == fn) { - w->node = child; - if (children&2) { - RT6_TRACE("W %p adjusted by delnode 2, s=%d\n", w, w->state); - w->state = w->state >= FWS_R ? FWS_U : FWS_INIT; - } else { - RT6_TRACE("W %p adjusted by delnode 2, s=%d\n", w, w->state); - w->state = w->state >= FWS_C ? FWS_U : FWS_INIT; - } - } - } - } - read_unlock(&net->ipv6.fib6_walker_lock); - - node_free(fn); - if (pn->fn_flags & RTN_RTINFO || FIB6_SUBTREE(pn)) - return pn; - - rt6_release(pn->leaf); - pn->leaf = NULL; - fn = pn; - } -} - -static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, - struct nl_info *info) -{ - struct fib6_walker *w; - struct rt6_info *rt = *rtp; - struct net *net = info->nl_net; - - RT6_TRACE("fib6_del_route\n"); - - /* Unlink it */ - *rtp = rt->dst.rt6_next; - rt->rt6i_node = NULL; - net->ipv6.rt6_stats->fib_rt_entries--; - net->ipv6.rt6_stats->fib_discarded_routes++; - - /* Reset round-robin state, if necessary */ - if (fn->rr_ptr == rt) - fn->rr_ptr = NULL; - - /* Remove this entry from other siblings */ - if (rt->rt6i_nsiblings) { - struct rt6_info *sibling, *next_sibling; - - list_for_each_entry_safe(sibling, next_sibling, - &rt->rt6i_siblings, rt6i_siblings) - sibling->rt6i_nsiblings--; - rt->rt6i_nsiblings = 0; - list_del_init(&rt->rt6i_siblings); - } - - /* Adjust walkers */ - read_lock(&net->ipv6.fib6_walker_lock); - FOR_WALKERS(net, w) { - if (w->state == FWS_C && w->leaf == rt) { - RT6_TRACE("walker %p adjusted by delroute\n", w); - w->leaf = rt->dst.rt6_next; - if (!w->leaf) - w->state = FWS_U; - } - } - read_unlock(&net->ipv6.fib6_walker_lock); - - rt->dst.rt6_next = NULL; - - /* If it was last route, expunge its radix tree node */ - if (!fn->leaf) { - fn->fn_flags &= ~RTN_RTINFO; - net->ipv6.rt6_stats->fib_route_nodes--; - fn = fib6_repair_tree(net, fn); - } - - fib6_purge_rt(rt, fn, net); - - inet6_rt_notify(RTM_DELROUTE, rt, info, 0); - rt6_release(rt); -} - -int fib6_del(struct rt6_info *rt, struct nl_info *info) -{ - struct net *net = info->nl_net; - struct fib6_node *fn = rt->rt6i_node; - struct rt6_info **rtp; - -#if RT6_DEBUG >= 2 - if (rt->dst.obsolete > 0) { - WARN_ON(fn); - return -ENOENT; - } -#endif - if (!fn || rt == net->ipv6.ip6_null_entry) - return -ENOENT; - - WARN_ON(!(fn->fn_flags & RTN_RTINFO)); - - if (!(rt->rt6i_flags & RTF_CACHE)) { - struct fib6_node *pn = fn; -#ifdef CONFIG_IPV6_SUBTREES - /* clones of this route might be in another subtree */ - if (rt->rt6i_src.plen) { - while (!(pn->fn_flags & RTN_ROOT)) - pn = pn->parent; - pn = pn->parent; - } -#endif - fib6_prune_clones(info->nl_net, pn); - } - - /* - * Walk the leaf entries looking for ourself - */ - - for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->dst.rt6_next) { - if (*rtp == rt) { - fib6_del_route(fn, rtp, info); - return 0; - } - } - return -ENOENT; -} - -/* - * Tree traversal function. - * - * Certainly, it is not interrupt safe. - * However, it is internally reenterable wrt itself and fib6_add/fib6_del. - * It means, that we can modify tree during walking - * and use this function for garbage collection, clone pruning, - * cleaning tree when a device goes down etc. etc. - * - * It guarantees that every node will be traversed, - * and that it will be traversed only once. - * - * Callback function w->func may return: - * 0 -> continue walking. - * positive value -> walking is suspended (used by tree dumps, - * and probably by gc, if it will be split to several slices) - * negative value -> terminate walking. - * - * The function itself returns: - * 0 -> walk is complete. - * >0 -> walk is incomplete (i.e. suspended) - * <0 -> walk is terminated by an error. - */ - -static int fib6_walk_continue(struct fib6_walker *w) -{ - struct fib6_node *fn, *pn; - - for (;;) { - fn = w->node; - if (!fn) - return 0; - - if (w->prune && fn != w->root && - fn->fn_flags & RTN_RTINFO && w->state < FWS_C) { - w->state = FWS_C; - w->leaf = fn->leaf; - } - switch (w->state) { -#ifdef CONFIG_IPV6_SUBTREES - case FWS_S: - if (FIB6_SUBTREE(fn)) { - w->node = FIB6_SUBTREE(fn); - continue; - } - w->state = FWS_L; -#endif - case FWS_L: - if (fn->left) { - w->node = fn->left; - w->state = FWS_INIT; - continue; - } - w->state = FWS_R; - case FWS_R: - if (fn->right) { - w->node = fn->right; - w->state = FWS_INIT; - continue; - } - w->state = FWS_C; - w->leaf = fn->leaf; - case FWS_C: - if (w->leaf && fn->fn_flags & RTN_RTINFO) { - int err; - - if (w->skip) { - w->skip--; - goto skip; - } - - err = w->func(w); - if (err) - return err; - - w->count++; - continue; - } -skip: - w->state = FWS_U; - case FWS_U: - if (fn == w->root) - return 0; - pn = fn->parent; - w->node = pn; -#ifdef CONFIG_IPV6_SUBTREES - if (FIB6_SUBTREE(pn) == fn) { - WARN_ON(!(fn->fn_flags & RTN_ROOT)); - w->state = FWS_L; - continue; - } -#endif - if (pn->left == fn) { - w->state = FWS_R; - continue; - } - if (pn->right == fn) { - w->state = FWS_C; - w->leaf = w->node->leaf; - continue; - } -#if RT6_DEBUG >= 2 - WARN_ON(1); -#endif - } - } -} - -static int fib6_walk(struct net *net, struct fib6_walker *w) -{ - int res; - - w->state = FWS_INIT; - w->node = w->root; - - fib6_walker_link(net, w); - res = fib6_walk_continue(w); - if (res <= 0) - fib6_walker_unlink(net, w); - return res; -} - -static int fib6_clean_node(struct fib6_walker *w) -{ - int res; - struct rt6_info *rt; - struct fib6_cleaner *c = container_of(w, struct fib6_cleaner, w); - struct nl_info info = { - .nl_net = c->net, - }; - - if (c->sernum != FIB6_NO_SERNUM_CHANGE && - w->node->fn_sernum != c->sernum) - w->node->fn_sernum = c->sernum; - - if (!c->func) { - WARN_ON_ONCE(c->sernum == FIB6_NO_SERNUM_CHANGE); - w->leaf = NULL; - return 0; - } - - for (rt = w->leaf; rt; rt = rt->dst.rt6_next) { - res = c->func(rt, c->arg); - if (res < 0) { - w->leaf = rt; - res = fib6_del(rt, &info); - if (res) { -#if RT6_DEBUG >= 2 - pr_debug("%s: del failed: rt=%p@%p err=%d\n", - __func__, rt, rt->rt6i_node, res); -#endif - continue; - } - return 0; - } - WARN_ON(res != 0); - } - w->leaf = rt; - return 0; -} - -/* - * Convenient frontend to tree walker. - * - * func is called on each route. - * It may return -1 -> delete this route. - * 0 -> continue walking - * - * prune==1 -> only immediate children of node (certainly, - * ignoring pure split nodes) will be scanned. - */ - -static void fib6_clean_tree(struct net *net, struct fib6_node *root, - int (*func)(struct rt6_info *, void *arg), - bool prune, int sernum, void *arg) -{ - struct fib6_cleaner c; - - c.w.root = root; - c.w.func = fib6_clean_node; - c.w.prune = prune; - c.w.count = 0; - c.w.skip = 0; - c.func = func; - c.sernum = sernum; - c.arg = arg; - c.net = net; - - fib6_walk(net, &c.w); -} - -static void __fib6_clean_all(struct net *net, - int (*func)(struct rt6_info *, void *), - int sernum, void *arg) -{ - struct fib6_table *table; - struct hlist_head *head; - unsigned int h; - - rcu_read_lock(); - for (h = 0; h < FIB6_TABLE_HASHSZ; h++) { - head = &net->ipv6.fib_table_hash[h]; - hlist_for_each_entry_rcu(table, head, tb6_hlist) { - write_lock_bh(&table->tb6_lock); - fib6_clean_tree(net, &table->tb6_root, - func, false, sernum, arg); - write_unlock_bh(&table->tb6_lock); - } - } - rcu_read_unlock(); -} - -void fib6_clean_all(struct net *net, int (*func)(struct rt6_info *, void *), - void *arg) -{ - __fib6_clean_all(net, func, FIB6_NO_SERNUM_CHANGE, arg); -} - -static int fib6_prune_clone(struct rt6_info *rt, void *arg) -{ - if (rt->rt6i_flags & RTF_CACHE) { - RT6_TRACE("pruning clone %p\n", rt); - return -1; - } - - return 0; -} - -static void fib6_prune_clones(struct net *net, struct fib6_node *fn) -{ - fib6_clean_tree(net, fn, fib6_prune_clone, true, - FIB6_NO_SERNUM_CHANGE, NULL); -} - -static void fib6_flush_trees(struct net *net) -{ - int new_sernum = fib6_new_sernum(net); - - __fib6_clean_all(net, NULL, new_sernum, NULL); -} - -/* - * Garbage collection - */ - -struct fib6_gc_args -{ - int timeout; - int more; -}; - -static int fib6_age(struct rt6_info *rt, void *arg) -{ - struct fib6_gc_args *gc_args = arg; - unsigned long now = jiffies; - - /* - * check addrconf expiration here. - * Routes are expired even if they are in use. - * - * Also age clones. Note, that clones are aged out - * only if they are not in use now. - */ - - if (rt->rt6i_flags & RTF_EXPIRES && rt->dst.expires) { - if (time_after(now, rt->dst.expires)) { - RT6_TRACE("expiring %p\n", rt); - return -1; - } - gc_args->more++; - } else if (rt->rt6i_flags & RTF_CACHE) { - if (atomic_read(&rt->dst.__refcnt) == 0 && - time_after_eq(now, rt->dst.lastuse + gc_args->timeout)) { - RT6_TRACE("aging clone %p\n", rt); - return -1; - } else if (rt->rt6i_flags & RTF_GATEWAY) { - struct neighbour *neigh; - __u8 neigh_flags = 0; - - neigh = dst_neigh_lookup(&rt->dst, &rt->rt6i_gateway); - if (neigh) { - neigh_flags = neigh->flags; - neigh_release(neigh); - } - if (!(neigh_flags & NTF_ROUTER)) { - RT6_TRACE("purging route %p via non-router but gateway\n", - rt); - return -1; - } - } - gc_args->more++; - } - - return 0; -} - -void fib6_run_gc(unsigned long expires, struct net *net, bool force) -{ - struct fib6_gc_args gc_args; - unsigned long now; - - if (force) { - spin_lock_bh(&net->ipv6.fib6_gc_lock); - } else if (!spin_trylock_bh(&net->ipv6.fib6_gc_lock)) { - mod_timer(&net->ipv6.ip6_fib_timer, jiffies + HZ); - return; - } - gc_args.timeout = expires ? (int)expires : - net->ipv6.sysctl.ip6_rt_gc_interval; - - gc_args.more = icmp6_dst_gc(); - - fib6_clean_all(net, fib6_age, &gc_args); - now = jiffies; - net->ipv6.ip6_rt_last_gc = now; - - if (gc_args.more) - mod_timer(&net->ipv6.ip6_fib_timer, - round_jiffies(now - + net->ipv6.sysctl.ip6_rt_gc_interval)); - else - del_timer(&net->ipv6.ip6_fib_timer); - spin_unlock_bh(&net->ipv6.fib6_gc_lock); -} - -static void fib6_gc_timer_cb(unsigned long arg) -{ - fib6_run_gc(0, (struct net *)arg, true); -} - -static int __net_init fib6_net_init(struct net *net) -{ - size_t size = sizeof(struct hlist_head) * FIB6_TABLE_HASHSZ; - - spin_lock_init(&net->ipv6.fib6_gc_lock); - rwlock_init(&net->ipv6.fib6_walker_lock); - INIT_LIST_HEAD(&net->ipv6.fib6_walkers); - setup_timer(&net->ipv6.ip6_fib_timer, fib6_gc_timer_cb, (unsigned long)net); - - net->ipv6.rt6_stats = kzalloc(sizeof(*net->ipv6.rt6_stats), GFP_KERNEL); - if (!net->ipv6.rt6_stats) - goto out_timer; - - /* Avoid false sharing : Use at least a full cache line */ - size = max_t(size_t, size, L1_CACHE_BYTES); - - net->ipv6.fib_table_hash = kzalloc(size, GFP_KERNEL); - if (!net->ipv6.fib_table_hash) - goto out_rt6_stats; - - net->ipv6.fib6_main_tbl = kzalloc(sizeof(*net->ipv6.fib6_main_tbl), - GFP_KERNEL); - if (!net->ipv6.fib6_main_tbl) - goto out_fib_table_hash; - - net->ipv6.fib6_main_tbl->tb6_id = RT6_TABLE_MAIN; - net->ipv6.fib6_main_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry; - net->ipv6.fib6_main_tbl->tb6_root.fn_flags = - RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; - inet_peer_base_init(&net->ipv6.fib6_main_tbl->tb6_peers); - -#ifdef CONFIG_IPV6_MULTIPLE_TABLES - net->ipv6.fib6_local_tbl = kzalloc(sizeof(*net->ipv6.fib6_local_tbl), - GFP_KERNEL); - if (!net->ipv6.fib6_local_tbl) - goto out_fib6_main_tbl; - net->ipv6.fib6_local_tbl->tb6_id = RT6_TABLE_LOCAL; - net->ipv6.fib6_local_tbl->tb6_root.leaf = net->ipv6.ip6_null_entry; - net->ipv6.fib6_local_tbl->tb6_root.fn_flags = - RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO; - inet_peer_base_init(&net->ipv6.fib6_local_tbl->tb6_peers); -#endif - fib6_tables_init(net); - - return 0; - -#ifdef CONFIG_IPV6_MULTIPLE_TABLES -out_fib6_main_tbl: - kfree(net->ipv6.fib6_main_tbl); -#endif -out_fib_table_hash: - kfree(net->ipv6.fib_table_hash); -out_rt6_stats: - kfree(net->ipv6.rt6_stats); -out_timer: - return -ENOMEM; -} - -static void fib6_net_exit(struct net *net) -{ - rt6_ifdown(net, NULL); - del_timer_sync(&net->ipv6.ip6_fib_timer); - -#ifdef CONFIG_IPV6_MULTIPLE_TABLES - inetpeer_invalidate_tree(&net->ipv6.fib6_local_tbl->tb6_peers); - kfree(net->ipv6.fib6_local_tbl); -#endif - inetpeer_invalidate_tree(&net->ipv6.fib6_main_tbl->tb6_peers); - kfree(net->ipv6.fib6_main_tbl); - kfree(net->ipv6.fib_table_hash); - kfree(net->ipv6.rt6_stats); -} - -static struct pernet_operations fib6_net_ops = { - .init = fib6_net_init, - .exit = fib6_net_exit, -}; - -int __init fib6_init(void) -{ - int ret = -ENOMEM; - - fib6_node_kmem = kmem_cache_create("fib6_nodes", - sizeof(struct fib6_node), - 0, SLAB_HWCACHE_ALIGN, - NULL); - if (!fib6_node_kmem) - goto out; - - ret = register_pernet_subsys(&fib6_net_ops); - if (ret) - goto out_kmem_cache_create; - - ret = __rtnl_register(PF_INET6, RTM_GETROUTE, NULL, inet6_dump_fib, - NULL); - if (ret) - goto out_unregister_subsys; - - __fib6_flush_trees = fib6_flush_trees; -out: - return ret; - -out_unregister_subsys: - unregister_pernet_subsys(&fib6_net_ops); -out_kmem_cache_create: - kmem_cache_destroy(fib6_node_kmem); - goto out; -} - -void fib6_gc_cleanup(void) -{ - unregister_pernet_subsys(&fib6_net_ops); - kmem_cache_destroy(fib6_node_kmem); -} - -#ifdef CONFIG_PROC_FS - -struct ipv6_route_iter { - struct seq_net_private p; - struct fib6_walker w; - loff_t skip; - struct fib6_table *tbl; - int sernum; -}; - -static int ipv6_route_seq_show(struct seq_file *seq, void *v) -{ - struct rt6_info *rt = v; - struct ipv6_route_iter *iter = seq->private; - - seq_printf(seq, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen); - -#ifdef CONFIG_IPV6_SUBTREES - seq_printf(seq, "%pi6 %02x ", &rt->rt6i_src.addr, rt->rt6i_src.plen); -#else - seq_puts(seq, "00000000000000000000000000000000 00 "); -#endif - if (rt->rt6i_flags & RTF_GATEWAY) - seq_printf(seq, "%pi6", &rt->rt6i_gateway); - else - seq_puts(seq, "00000000000000000000000000000000"); - - seq_printf(seq, " %08x %08x %08x %08x %8s\n", - rt->rt6i_metric, atomic_read(&rt->dst.__refcnt), - rt->dst.__use, rt->rt6i_flags, - rt->dst.dev ? rt->dst.dev->name : ""); - iter->w.leaf = NULL; - return 0; -} - -static int ipv6_route_yield(struct fib6_walker *w) -{ - struct ipv6_route_iter *iter = w->args; - - if (!iter->skip) - return 1; - - do { - iter->w.leaf = iter->w.leaf->dst.rt6_next; - iter->skip--; - if (!iter->skip && iter->w.leaf) - return 1; - } while (iter->w.leaf); - - return 0; -} - -static void ipv6_route_seq_setup_walk(struct ipv6_route_iter *iter, - struct net *net) -{ - memset(&iter->w, 0, sizeof(iter->w)); - iter->w.func = ipv6_route_yield; - iter->w.root = &iter->tbl->tb6_root; - iter->w.state = FWS_INIT; - iter->w.node = iter->w.root; - iter->w.args = iter; - iter->sernum = iter->w.root->fn_sernum; - INIT_LIST_HEAD(&iter->w.lh); - fib6_walker_link(net, &iter->w); -} - -static struct fib6_table *ipv6_route_seq_next_table(struct fib6_table *tbl, - struct net *net) -{ - unsigned int h; - struct hlist_node *node; - - if (tbl) { - h = (tbl->tb6_id & (FIB6_TABLE_HASHSZ - 1)) + 1; - node = rcu_dereference_bh(hlist_next_rcu(&tbl->tb6_hlist)); - } else { - h = 0; - node = NULL; - } - - while (!node && h < FIB6_TABLE_HASHSZ) { - node = rcu_dereference_bh( - hlist_first_rcu(&net->ipv6.fib_table_hash[h++])); - } - return hlist_entry_safe(node, struct fib6_table, tb6_hlist); -} - -static void ipv6_route_check_sernum(struct ipv6_route_iter *iter) -{ - if (iter->sernum != iter->w.root->fn_sernum) { - iter->sernum = iter->w.root->fn_sernum; - iter->w.state = FWS_INIT; - iter->w.node = iter->w.root; - WARN_ON(iter->w.skip); - iter->w.skip = iter->w.count; - } -} - -static void *ipv6_route_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - int r; - struct rt6_info *n; - struct net *net = seq_file_net(seq); - struct ipv6_route_iter *iter = seq->private; - - if (!v) - goto iter_table; - - n = ((struct rt6_info *)v)->dst.rt6_next; - if (n) { - ++*pos; - return n; - } - -iter_table: - ipv6_route_check_sernum(iter); - read_lock(&iter->tbl->tb6_lock); - r = fib6_walk_continue(&iter->w); - read_unlock(&iter->tbl->tb6_lock); - if (r > 0) { - if (v) - ++*pos; - return iter->w.leaf; - } else if (r < 0) { - fib6_walker_unlink(net, &iter->w); - return NULL; - } - fib6_walker_unlink(net, &iter->w); - - iter->tbl = ipv6_route_seq_next_table(iter->tbl, net); - if (!iter->tbl) - return NULL; - - ipv6_route_seq_setup_walk(iter, net); - goto iter_table; -} - -static void *ipv6_route_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(RCU_BH) -{ - struct net *net = seq_file_net(seq); - struct ipv6_route_iter *iter = seq->private; - - rcu_read_lock_bh(); - iter->tbl = ipv6_route_seq_next_table(NULL, net); - iter->skip = *pos; - - if (iter->tbl) { - ipv6_route_seq_setup_walk(iter, net); - return ipv6_route_seq_next(seq, NULL, pos); - } else { - return NULL; - } -} - -static bool ipv6_route_iter_active(struct ipv6_route_iter *iter) -{ - struct fib6_walker *w = &iter->w; - return w->node && !(w->state == FWS_U && w->node == w->root); -} - -static void ipv6_route_seq_stop(struct seq_file *seq, void *v) - __releases(RCU_BH) -{ - struct net *net = seq_file_net(seq); - struct ipv6_route_iter *iter = seq->private; - - if (ipv6_route_iter_active(iter)) - fib6_walker_unlink(net, &iter->w); - - rcu_read_unlock_bh(); -} - -static const struct seq_operations ipv6_route_seq_ops = { - .start = ipv6_route_seq_start, - .next = ipv6_route_seq_next, - .stop = ipv6_route_seq_stop, - .show = ipv6_route_seq_show -}; - -int ipv6_route_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &ipv6_route_seq_ops, - sizeof(struct ipv6_route_iter)); -} - -#endif /* CONFIG_PROC_FS */ diff --git a/src/linux/net/ipv6/ip6_flowlabel.c b/src/linux/net/ipv6/ip6_flowlabel.c deleted file mode 100644 index b912f0d..0000000 --- a/src/linux/net/ipv6/ip6_flowlabel.c +++ /dev/null @@ -1,887 +0,0 @@ -/* - * ip6_flowlabel.c IPv6 flowlabel manager. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include - -#define FL_MIN_LINGER 6 /* Minimal linger. It is set to 6sec specified - in old IPv6 RFC. Well, it was reasonable value. - */ -#define FL_MAX_LINGER 150 /* Maximal linger timeout */ - -/* FL hash table */ - -#define FL_MAX_PER_SOCK 32 -#define FL_MAX_SIZE 4096 -#define FL_HASH_MASK 255 -#define FL_HASH(l) (ntohl(l)&FL_HASH_MASK) - -static atomic_t fl_size = ATOMIC_INIT(0); -static struct ip6_flowlabel __rcu *fl_ht[FL_HASH_MASK+1]; - -static void ip6_fl_gc(unsigned long dummy); -static DEFINE_TIMER(ip6_fl_gc_timer, ip6_fl_gc, 0, 0); - -/* FL hash table lock: it protects only of GC */ - -static DEFINE_SPINLOCK(ip6_fl_lock); - -/* Big socket sock */ - -static DEFINE_SPINLOCK(ip6_sk_fl_lock); - -#define for_each_fl_rcu(hash, fl) \ - for (fl = rcu_dereference_bh(fl_ht[(hash)]); \ - fl != NULL; \ - fl = rcu_dereference_bh(fl->next)) -#define for_each_fl_continue_rcu(fl) \ - for (fl = rcu_dereference_bh(fl->next); \ - fl != NULL; \ - fl = rcu_dereference_bh(fl->next)) - -#define for_each_sk_fl_rcu(np, sfl) \ - for (sfl = rcu_dereference_bh(np->ipv6_fl_list); \ - sfl != NULL; \ - sfl = rcu_dereference_bh(sfl->next)) - -static inline struct ip6_flowlabel *__fl_lookup(struct net *net, __be32 label) -{ - struct ip6_flowlabel *fl; - - for_each_fl_rcu(FL_HASH(label), fl) { - if (fl->label == label && net_eq(fl->fl_net, net)) - return fl; - } - return NULL; -} - -static struct ip6_flowlabel *fl_lookup(struct net *net, __be32 label) -{ - struct ip6_flowlabel *fl; - - rcu_read_lock_bh(); - fl = __fl_lookup(net, label); - if (fl && !atomic_inc_not_zero(&fl->users)) - fl = NULL; - rcu_read_unlock_bh(); - return fl; -} - - -static void fl_free(struct ip6_flowlabel *fl) -{ - if (fl) { - if (fl->share == IPV6_FL_S_PROCESS) - put_pid(fl->owner.pid); - kfree(fl->opt); - kfree_rcu(fl, rcu); - } -} - -static void fl_release(struct ip6_flowlabel *fl) -{ - spin_lock_bh(&ip6_fl_lock); - - fl->lastuse = jiffies; - if (atomic_dec_and_test(&fl->users)) { - unsigned long ttd = fl->lastuse + fl->linger; - if (time_after(ttd, fl->expires)) - fl->expires = ttd; - ttd = fl->expires; - if (fl->opt && fl->share == IPV6_FL_S_EXCL) { - struct ipv6_txoptions *opt = fl->opt; - fl->opt = NULL; - kfree(opt); - } - if (!timer_pending(&ip6_fl_gc_timer) || - time_after(ip6_fl_gc_timer.expires, ttd)) - mod_timer(&ip6_fl_gc_timer, ttd); - } - spin_unlock_bh(&ip6_fl_lock); -} - -static void ip6_fl_gc(unsigned long dummy) -{ - int i; - unsigned long now = jiffies; - unsigned long sched = 0; - - spin_lock(&ip6_fl_lock); - - for (i = 0; i <= FL_HASH_MASK; i++) { - struct ip6_flowlabel *fl; - struct ip6_flowlabel __rcu **flp; - - flp = &fl_ht[i]; - while ((fl = rcu_dereference_protected(*flp, - lockdep_is_held(&ip6_fl_lock))) != NULL) { - if (atomic_read(&fl->users) == 0) { - unsigned long ttd = fl->lastuse + fl->linger; - if (time_after(ttd, fl->expires)) - fl->expires = ttd; - ttd = fl->expires; - if (time_after_eq(now, ttd)) { - *flp = fl->next; - fl_free(fl); - atomic_dec(&fl_size); - continue; - } - if (!sched || time_before(ttd, sched)) - sched = ttd; - } - flp = &fl->next; - } - } - if (!sched && atomic_read(&fl_size)) - sched = now + FL_MAX_LINGER; - if (sched) { - mod_timer(&ip6_fl_gc_timer, sched); - } - spin_unlock(&ip6_fl_lock); -} - -static void __net_exit ip6_fl_purge(struct net *net) -{ - int i; - - spin_lock_bh(&ip6_fl_lock); - for (i = 0; i <= FL_HASH_MASK; i++) { - struct ip6_flowlabel *fl; - struct ip6_flowlabel __rcu **flp; - - flp = &fl_ht[i]; - while ((fl = rcu_dereference_protected(*flp, - lockdep_is_held(&ip6_fl_lock))) != NULL) { - if (net_eq(fl->fl_net, net) && - atomic_read(&fl->users) == 0) { - *flp = fl->next; - fl_free(fl); - atomic_dec(&fl_size); - continue; - } - flp = &fl->next; - } - } - spin_unlock_bh(&ip6_fl_lock); -} - -static struct ip6_flowlabel *fl_intern(struct net *net, - struct ip6_flowlabel *fl, __be32 label) -{ - struct ip6_flowlabel *lfl; - - fl->label = label & IPV6_FLOWLABEL_MASK; - - spin_lock_bh(&ip6_fl_lock); - if (label == 0) { - for (;;) { - fl->label = htonl(prandom_u32())&IPV6_FLOWLABEL_MASK; - if (fl->label) { - lfl = __fl_lookup(net, fl->label); - if (!lfl) - break; - } - } - } else { - /* - * we dropper the ip6_fl_lock, so this entry could reappear - * and we need to recheck with it. - * - * OTOH no need to search the active socket first, like it is - * done in ipv6_flowlabel_opt - sock is locked, so new entry - * with the same label can only appear on another sock - */ - lfl = __fl_lookup(net, fl->label); - if (lfl) { - atomic_inc(&lfl->users); - spin_unlock_bh(&ip6_fl_lock); - return lfl; - } - } - - fl->lastuse = jiffies; - fl->next = fl_ht[FL_HASH(fl->label)]; - rcu_assign_pointer(fl_ht[FL_HASH(fl->label)], fl); - atomic_inc(&fl_size); - spin_unlock_bh(&ip6_fl_lock); - return NULL; -} - - - -/* Socket flowlabel lists */ - -struct ip6_flowlabel *fl6_sock_lookup(struct sock *sk, __be32 label) -{ - struct ipv6_fl_socklist *sfl; - struct ipv6_pinfo *np = inet6_sk(sk); - - label &= IPV6_FLOWLABEL_MASK; - - rcu_read_lock_bh(); - for_each_sk_fl_rcu(np, sfl) { - struct ip6_flowlabel *fl = sfl->fl; - if (fl->label == label) { - fl->lastuse = jiffies; - atomic_inc(&fl->users); - rcu_read_unlock_bh(); - return fl; - } - } - rcu_read_unlock_bh(); - return NULL; -} -EXPORT_SYMBOL_GPL(fl6_sock_lookup); - -void fl6_free_socklist(struct sock *sk) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct ipv6_fl_socklist *sfl; - - if (!rcu_access_pointer(np->ipv6_fl_list)) - return; - - spin_lock_bh(&ip6_sk_fl_lock); - while ((sfl = rcu_dereference_protected(np->ipv6_fl_list, - lockdep_is_held(&ip6_sk_fl_lock))) != NULL) { - np->ipv6_fl_list = sfl->next; - spin_unlock_bh(&ip6_sk_fl_lock); - - fl_release(sfl->fl); - kfree_rcu(sfl, rcu); - - spin_lock_bh(&ip6_sk_fl_lock); - } - spin_unlock_bh(&ip6_sk_fl_lock); -} - -/* Service routines */ - - -/* - It is the only difficult place. flowlabel enforces equal headers - before and including routing header, however user may supply options - following rthdr. - */ - -struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions *opt_space, - struct ip6_flowlabel *fl, - struct ipv6_txoptions *fopt) -{ - struct ipv6_txoptions *fl_opt = fl->opt; - - if (!fopt || fopt->opt_flen == 0) - return fl_opt; - - if (fl_opt) { - opt_space->hopopt = fl_opt->hopopt; - opt_space->dst0opt = fl_opt->dst0opt; - opt_space->srcrt = fl_opt->srcrt; - opt_space->opt_nflen = fl_opt->opt_nflen; - } else { - if (fopt->opt_nflen == 0) - return fopt; - opt_space->hopopt = NULL; - opt_space->dst0opt = NULL; - opt_space->srcrt = NULL; - opt_space->opt_nflen = 0; - } - opt_space->dst1opt = fopt->dst1opt; - opt_space->opt_flen = fopt->opt_flen; - return opt_space; -} -EXPORT_SYMBOL_GPL(fl6_merge_options); - -static unsigned long check_linger(unsigned long ttl) -{ - if (ttl < FL_MIN_LINGER) - return FL_MIN_LINGER*HZ; - if (ttl > FL_MAX_LINGER && !capable(CAP_NET_ADMIN)) - return 0; - return ttl*HZ; -} - -static int fl6_renew(struct ip6_flowlabel *fl, unsigned long linger, unsigned long expires) -{ - linger = check_linger(linger); - if (!linger) - return -EPERM; - expires = check_linger(expires); - if (!expires) - return -EPERM; - - spin_lock_bh(&ip6_fl_lock); - fl->lastuse = jiffies; - if (time_before(fl->linger, linger)) - fl->linger = linger; - if (time_before(expires, fl->linger)) - expires = fl->linger; - if (time_before(fl->expires, fl->lastuse + expires)) - fl->expires = fl->lastuse + expires; - spin_unlock_bh(&ip6_fl_lock); - - return 0; -} - -static struct ip6_flowlabel * -fl_create(struct net *net, struct sock *sk, struct in6_flowlabel_req *freq, - char __user *optval, int optlen, int *err_p) -{ - struct ip6_flowlabel *fl = NULL; - int olen; - int addr_type; - int err; - - olen = optlen - CMSG_ALIGN(sizeof(*freq)); - err = -EINVAL; - if (olen > 64 * 1024) - goto done; - - err = -ENOMEM; - fl = kzalloc(sizeof(*fl), GFP_KERNEL); - if (!fl) - goto done; - - if (olen > 0) { - struct msghdr msg; - struct flowi6 flowi6; - struct sockcm_cookie sockc_junk; - struct ipcm6_cookie ipc6; - - err = -ENOMEM; - fl->opt = kmalloc(sizeof(*fl->opt) + olen, GFP_KERNEL); - if (!fl->opt) - goto done; - - memset(fl->opt, 0, sizeof(*fl->opt)); - fl->opt->tot_len = sizeof(*fl->opt) + olen; - err = -EFAULT; - if (copy_from_user(fl->opt+1, optval+CMSG_ALIGN(sizeof(*freq)), olen)) - goto done; - - msg.msg_controllen = olen; - msg.msg_control = (void *)(fl->opt+1); - memset(&flowi6, 0, sizeof(flowi6)); - - ipc6.opt = fl->opt; - err = ip6_datagram_send_ctl(net, sk, &msg, &flowi6, &ipc6, &sockc_junk); - if (err) - goto done; - err = -EINVAL; - if (fl->opt->opt_flen) - goto done; - if (fl->opt->opt_nflen == 0) { - kfree(fl->opt); - fl->opt = NULL; - } - } - - fl->fl_net = net; - fl->expires = jiffies; - err = fl6_renew(fl, freq->flr_linger, freq->flr_expires); - if (err) - goto done; - fl->share = freq->flr_share; - addr_type = ipv6_addr_type(&freq->flr_dst); - if ((addr_type & IPV6_ADDR_MAPPED) || - addr_type == IPV6_ADDR_ANY) { - err = -EINVAL; - goto done; - } - fl->dst = freq->flr_dst; - atomic_set(&fl->users, 1); - switch (fl->share) { - case IPV6_FL_S_EXCL: - case IPV6_FL_S_ANY: - break; - case IPV6_FL_S_PROCESS: - fl->owner.pid = get_task_pid(current, PIDTYPE_PID); - break; - case IPV6_FL_S_USER: - fl->owner.uid = current_euid(); - break; - default: - err = -EINVAL; - goto done; - } - return fl; - -done: - fl_free(fl); - *err_p = err; - return NULL; -} - -static int mem_check(struct sock *sk) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct ipv6_fl_socklist *sfl; - int room = FL_MAX_SIZE - atomic_read(&fl_size); - int count = 0; - - if (room > FL_MAX_SIZE - FL_MAX_PER_SOCK) - return 0; - - rcu_read_lock_bh(); - for_each_sk_fl_rcu(np, sfl) - count++; - rcu_read_unlock_bh(); - - if (room <= 0 || - ((count >= FL_MAX_PER_SOCK || - (count > 0 && room < FL_MAX_SIZE/2) || room < FL_MAX_SIZE/4) && - !capable(CAP_NET_ADMIN))) - return -ENOBUFS; - - return 0; -} - -static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl, - struct ip6_flowlabel *fl) -{ - spin_lock_bh(&ip6_sk_fl_lock); - sfl->fl = fl; - sfl->next = np->ipv6_fl_list; - rcu_assign_pointer(np->ipv6_fl_list, sfl); - spin_unlock_bh(&ip6_sk_fl_lock); -} - -int ipv6_flowlabel_opt_get(struct sock *sk, struct in6_flowlabel_req *freq, - int flags) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct ipv6_fl_socklist *sfl; - - if (flags & IPV6_FL_F_REMOTE) { - freq->flr_label = np->rcv_flowinfo & IPV6_FLOWLABEL_MASK; - return 0; - } - - if (np->repflow) { - freq->flr_label = np->flow_label; - return 0; - } - - rcu_read_lock_bh(); - - for_each_sk_fl_rcu(np, sfl) { - if (sfl->fl->label == (np->flow_label & IPV6_FLOWLABEL_MASK)) { - spin_lock_bh(&ip6_fl_lock); - freq->flr_label = sfl->fl->label; - freq->flr_dst = sfl->fl->dst; - freq->flr_share = sfl->fl->share; - freq->flr_expires = (sfl->fl->expires - jiffies) / HZ; - freq->flr_linger = sfl->fl->linger / HZ; - - spin_unlock_bh(&ip6_fl_lock); - rcu_read_unlock_bh(); - return 0; - } - } - rcu_read_unlock_bh(); - - return -ENOENT; -} - -int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) -{ - int uninitialized_var(err); - struct net *net = sock_net(sk); - struct ipv6_pinfo *np = inet6_sk(sk); - struct in6_flowlabel_req freq; - struct ipv6_fl_socklist *sfl1 = NULL; - struct ipv6_fl_socklist *sfl; - struct ipv6_fl_socklist __rcu **sflp; - struct ip6_flowlabel *fl, *fl1 = NULL; - - - if (optlen < sizeof(freq)) - return -EINVAL; - - if (copy_from_user(&freq, optval, sizeof(freq))) - return -EFAULT; - - switch (freq.flr_action) { - case IPV6_FL_A_PUT: - if (freq.flr_flags & IPV6_FL_F_REFLECT) { - if (sk->sk_protocol != IPPROTO_TCP) - return -ENOPROTOOPT; - if (!np->repflow) - return -ESRCH; - np->flow_label = 0; - np->repflow = 0; - return 0; - } - spin_lock_bh(&ip6_sk_fl_lock); - for (sflp = &np->ipv6_fl_list; - (sfl = rcu_dereference_protected(*sflp, - lockdep_is_held(&ip6_sk_fl_lock))) != NULL; - sflp = &sfl->next) { - if (sfl->fl->label == freq.flr_label) { - if (freq.flr_label == (np->flow_label&IPV6_FLOWLABEL_MASK)) - np->flow_label &= ~IPV6_FLOWLABEL_MASK; - *sflp = sfl->next; - spin_unlock_bh(&ip6_sk_fl_lock); - fl_release(sfl->fl); - kfree_rcu(sfl, rcu); - return 0; - } - } - spin_unlock_bh(&ip6_sk_fl_lock); - return -ESRCH; - - case IPV6_FL_A_RENEW: - rcu_read_lock_bh(); - for_each_sk_fl_rcu(np, sfl) { - if (sfl->fl->label == freq.flr_label) { - err = fl6_renew(sfl->fl, freq.flr_linger, freq.flr_expires); - rcu_read_unlock_bh(); - return err; - } - } - rcu_read_unlock_bh(); - - if (freq.flr_share == IPV6_FL_S_NONE && - ns_capable(net->user_ns, CAP_NET_ADMIN)) { - fl = fl_lookup(net, freq.flr_label); - if (fl) { - err = fl6_renew(fl, freq.flr_linger, freq.flr_expires); - fl_release(fl); - return err; - } - } - return -ESRCH; - - case IPV6_FL_A_GET: - if (freq.flr_flags & IPV6_FL_F_REFLECT) { - struct net *net = sock_net(sk); - if (net->ipv6.sysctl.flowlabel_consistency) { - net_info_ratelimited("Can not set IPV6_FL_F_REFLECT if flowlabel_consistency sysctl is enable\n"); - return -EPERM; - } - - if (sk->sk_protocol != IPPROTO_TCP) - return -ENOPROTOOPT; - - np->repflow = 1; - return 0; - } - - if (freq.flr_label & ~IPV6_FLOWLABEL_MASK) - return -EINVAL; - - if (net->ipv6.sysctl.flowlabel_state_ranges && - (freq.flr_label & IPV6_FLOWLABEL_STATELESS_FLAG)) - return -ERANGE; - - fl = fl_create(net, sk, &freq, optval, optlen, &err); - if (!fl) - return err; - sfl1 = kmalloc(sizeof(*sfl1), GFP_KERNEL); - - if (freq.flr_label) { - err = -EEXIST; - rcu_read_lock_bh(); - for_each_sk_fl_rcu(np, sfl) { - if (sfl->fl->label == freq.flr_label) { - if (freq.flr_flags&IPV6_FL_F_EXCL) { - rcu_read_unlock_bh(); - goto done; - } - fl1 = sfl->fl; - atomic_inc(&fl1->users); - break; - } - } - rcu_read_unlock_bh(); - - if (!fl1) - fl1 = fl_lookup(net, freq.flr_label); - if (fl1) { -recheck: - err = -EEXIST; - if (freq.flr_flags&IPV6_FL_F_EXCL) - goto release; - err = -EPERM; - if (fl1->share == IPV6_FL_S_EXCL || - fl1->share != fl->share || - ((fl1->share == IPV6_FL_S_PROCESS) && - (fl1->owner.pid == fl->owner.pid)) || - ((fl1->share == IPV6_FL_S_USER) && - uid_eq(fl1->owner.uid, fl->owner.uid))) - goto release; - - err = -ENOMEM; - if (!sfl1) - goto release; - if (fl->linger > fl1->linger) - fl1->linger = fl->linger; - if ((long)(fl->expires - fl1->expires) > 0) - fl1->expires = fl->expires; - fl_link(np, sfl1, fl1); - fl_free(fl); - return 0; - -release: - fl_release(fl1); - goto done; - } - } - err = -ENOENT; - if (!(freq.flr_flags&IPV6_FL_F_CREATE)) - goto done; - - err = -ENOMEM; - if (!sfl1) - goto done; - - err = mem_check(sk); - if (err != 0) - goto done; - - fl1 = fl_intern(net, fl, freq.flr_label); - if (fl1) - goto recheck; - - if (!freq.flr_label) { - if (copy_to_user(&((struct in6_flowlabel_req __user *) optval)->flr_label, - &fl->label, sizeof(fl->label))) { - /* Intentionally ignore fault. */ - } - } - - fl_link(np, sfl1, fl); - return 0; - - default: - return -EINVAL; - } - -done: - fl_free(fl); - kfree(sfl1); - return err; -} - -#ifdef CONFIG_PROC_FS - -struct ip6fl_iter_state { - struct seq_net_private p; - struct pid_namespace *pid_ns; - int bucket; -}; - -#define ip6fl_seq_private(seq) ((struct ip6fl_iter_state *)(seq)->private) - -static struct ip6_flowlabel *ip6fl_get_first(struct seq_file *seq) -{ - struct ip6_flowlabel *fl = NULL; - struct ip6fl_iter_state *state = ip6fl_seq_private(seq); - struct net *net = seq_file_net(seq); - - for (state->bucket = 0; state->bucket <= FL_HASH_MASK; ++state->bucket) { - for_each_fl_rcu(state->bucket, fl) { - if (net_eq(fl->fl_net, net)) - goto out; - } - } - fl = NULL; -out: - return fl; -} - -static struct ip6_flowlabel *ip6fl_get_next(struct seq_file *seq, struct ip6_flowlabel *fl) -{ - struct ip6fl_iter_state *state = ip6fl_seq_private(seq); - struct net *net = seq_file_net(seq); - - for_each_fl_continue_rcu(fl) { - if (net_eq(fl->fl_net, net)) - goto out; - } - -try_again: - if (++state->bucket <= FL_HASH_MASK) { - for_each_fl_rcu(state->bucket, fl) { - if (net_eq(fl->fl_net, net)) - goto out; - } - goto try_again; - } - fl = NULL; - -out: - return fl; -} - -static struct ip6_flowlabel *ip6fl_get_idx(struct seq_file *seq, loff_t pos) -{ - struct ip6_flowlabel *fl = ip6fl_get_first(seq); - if (fl) - while (pos && (fl = ip6fl_get_next(seq, fl)) != NULL) - --pos; - return pos ? NULL : fl; -} - -static void *ip6fl_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(RCU) -{ - rcu_read_lock_bh(); - return *pos ? ip6fl_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; -} - -static void *ip6fl_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct ip6_flowlabel *fl; - - if (v == SEQ_START_TOKEN) - fl = ip6fl_get_first(seq); - else - fl = ip6fl_get_next(seq, v); - ++*pos; - return fl; -} - -static void ip6fl_seq_stop(struct seq_file *seq, void *v) - __releases(RCU) -{ - rcu_read_unlock_bh(); -} - -static int ip6fl_seq_show(struct seq_file *seq, void *v) -{ - struct ip6fl_iter_state *state = ip6fl_seq_private(seq); - if (v == SEQ_START_TOKEN) { - seq_puts(seq, "Label S Owner Users Linger Expires Dst Opt\n"); - } else { - struct ip6_flowlabel *fl = v; - seq_printf(seq, - "%05X %-1d %-6d %-6d %-6ld %-8ld %pi6 %-4d\n", - (unsigned int)ntohl(fl->label), - fl->share, - ((fl->share == IPV6_FL_S_PROCESS) ? - pid_nr_ns(fl->owner.pid, state->pid_ns) : - ((fl->share == IPV6_FL_S_USER) ? - from_kuid_munged(seq_user_ns(seq), fl->owner.uid) : - 0)), - atomic_read(&fl->users), - fl->linger/HZ, - (long)(fl->expires - jiffies)/HZ, - &fl->dst, - fl->opt ? fl->opt->opt_nflen : 0); - } - return 0; -} - -static const struct seq_operations ip6fl_seq_ops = { - .start = ip6fl_seq_start, - .next = ip6fl_seq_next, - .stop = ip6fl_seq_stop, - .show = ip6fl_seq_show, -}; - -static int ip6fl_seq_open(struct inode *inode, struct file *file) -{ - struct seq_file *seq; - struct ip6fl_iter_state *state; - int err; - - err = seq_open_net(inode, file, &ip6fl_seq_ops, - sizeof(struct ip6fl_iter_state)); - - if (!err) { - seq = file->private_data; - state = ip6fl_seq_private(seq); - rcu_read_lock(); - state->pid_ns = get_pid_ns(task_active_pid_ns(current)); - rcu_read_unlock(); - } - return err; -} - -static int ip6fl_seq_release(struct inode *inode, struct file *file) -{ - struct seq_file *seq = file->private_data; - struct ip6fl_iter_state *state = ip6fl_seq_private(seq); - put_pid_ns(state->pid_ns); - return seq_release_net(inode, file); -} - -static const struct file_operations ip6fl_seq_fops = { - .owner = THIS_MODULE, - .open = ip6fl_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = ip6fl_seq_release, -}; - -static int __net_init ip6_flowlabel_proc_init(struct net *net) -{ - if (!proc_create("ip6_flowlabel", S_IRUGO, net->proc_net, - &ip6fl_seq_fops)) - return -ENOMEM; - return 0; -} - -static void __net_exit ip6_flowlabel_proc_fini(struct net *net) -{ - remove_proc_entry("ip6_flowlabel", net->proc_net); -} -#else -static inline int ip6_flowlabel_proc_init(struct net *net) -{ - return 0; -} -static inline void ip6_flowlabel_proc_fini(struct net *net) -{ -} -#endif - -static void __net_exit ip6_flowlabel_net_exit(struct net *net) -{ - ip6_fl_purge(net); - ip6_flowlabel_proc_fini(net); -} - -static struct pernet_operations ip6_flowlabel_net_ops = { - .init = ip6_flowlabel_proc_init, - .exit = ip6_flowlabel_net_exit, -}; - -int ip6_flowlabel_init(void) -{ - return register_pernet_subsys(&ip6_flowlabel_net_ops); -} - -void ip6_flowlabel_cleanup(void) -{ - del_timer(&ip6_fl_gc_timer); - unregister_pernet_subsys(&ip6_flowlabel_net_ops); -} diff --git a/src/linux/net/ipv6/ip6_icmp.c b/src/linux/net/ipv6/ip6_icmp.c deleted file mode 100644 index 713676f..0000000 --- a/src/linux/net/ipv6/ip6_icmp.c +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include -#include -#include -#include - -#include - -#if IS_ENABLED(CONFIG_IPV6) - -static ip6_icmp_send_t __rcu *ip6_icmp_send; - -int inet6_register_icmp_sender(ip6_icmp_send_t *fn) -{ - return (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, NULL, fn) == NULL) ? - 0 : -EBUSY; -} -EXPORT_SYMBOL(inet6_register_icmp_sender); - -int inet6_unregister_icmp_sender(ip6_icmp_send_t *fn) -{ - int ret; - - ret = (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, fn, NULL) == fn) ? - 0 : -EINVAL; - - synchronize_net(); - - return ret; -} -EXPORT_SYMBOL(inet6_unregister_icmp_sender); - -void icmpv6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) -{ - ip6_icmp_send_t *send; - - rcu_read_lock(); - send = rcu_dereference(ip6_icmp_send); - - if (!send) - goto out; - send(skb, type, code, info, NULL); -out: - rcu_read_unlock(); -} -EXPORT_SYMBOL(icmpv6_send); -#endif diff --git a/src/linux/net/ipv6/ip6_input.c b/src/linux/net/ipv6/ip6_input.c deleted file mode 100644 index aacfb4b..0000000 --- a/src/linux/net/ipv6/ip6_input.c +++ /dev/null @@ -1,406 +0,0 @@ -/* - * IPv6 input - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * Ian P. Morris - * - * Based in linux/net/ipv4/ip_input.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -/* Changes - * - * Mitsuru KANDA @USAGI and - * YOSHIFUJI Hideaki @USAGI: Remove ipv6_parse_exthdrs(). - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int ip6_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - /* if ingress device is enslaved to an L3 master device pass the - * skb to its handler for processing - */ - skb = l3mdev_ip6_rcv(skb); - if (!skb) - return NET_RX_SUCCESS; - - if (net->ipv4.sysctl_ip_early_demux && !skb_dst(skb) && skb->sk == NULL) { - const struct inet6_protocol *ipprot; - - ipprot = rcu_dereference(inet6_protos[ipv6_hdr(skb)->nexthdr]); - if (ipprot && ipprot->early_demux) - ipprot->early_demux(skb); - } - if (!skb_valid_dst(skb)) - ip6_route_input(skb); - - return dst_input(skb); -} - -int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) -{ - const struct ipv6hdr *hdr; - u32 pkt_len; - struct inet6_dev *idev; - struct net *net = dev_net(skb->dev); - - if (skb->pkt_type == PACKET_OTHERHOST) { - kfree_skb(skb); - return NET_RX_DROP; - } - - rcu_read_lock(); - - idev = __in6_dev_get(skb->dev); - - __IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_IN, skb->len); - - if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL || - !idev || unlikely(idev->cnf.disable_ipv6)) { - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); - goto drop; - } - - memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm)); - - /* - * Store incoming device index. When the packet will - * be queued, we cannot refer to skb->dev anymore. - * - * BTW, when we send a packet for our own local address on a - * non-loopback interface (e.g. ethX), it is being delivered - * via the loopback interface (lo) here; skb->dev = loopback_dev. - * It, however, should be considered as if it is being - * arrived via the sending interface (ethX), because of the - * nature of scoping architecture. --yoshfuji - */ - IP6CB(skb)->iif = skb_valid_dst(skb) ? ip6_dst_idev(skb_dst(skb))->dev->ifindex : dev->ifindex; - - if (unlikely(!pskb_may_pull(skb, sizeof(*hdr)))) - goto err; - - hdr = ipv6_hdr(skb); - - if (hdr->version != 6) - goto err; - - __IP6_ADD_STATS(net, idev, - IPSTATS_MIB_NOECTPKTS + - (ipv6_get_dsfield(hdr) & INET_ECN_MASK), - max_t(unsigned short, 1, skb_shinfo(skb)->gso_segs)); - /* - * RFC4291 2.5.3 - * A packet received on an interface with a destination address - * of loopback must be dropped. - */ - if (!(dev->flags & IFF_LOOPBACK) && - ipv6_addr_loopback(&hdr->daddr)) - goto err; - - /* RFC4291 Errata ID: 3480 - * Interface-Local scope spans only a single interface on a - * node and is useful only for loopback transmission of - * multicast. Packets with interface-local scope received - * from another node must be discarded. - */ - if (!(skb->pkt_type == PACKET_LOOPBACK || - dev->flags & IFF_LOOPBACK) && - ipv6_addr_is_multicast(&hdr->daddr) && - IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 1) - goto err; - - /* If enabled, drop unicast packets that were encapsulated in link-layer - * multicast or broadcast to protected against the so-called "hole-196" - * attack in 802.11 wireless. - */ - if (!ipv6_addr_is_multicast(&hdr->daddr) && - (skb->pkt_type == PACKET_BROADCAST || - skb->pkt_type == PACKET_MULTICAST) && - idev->cnf.drop_unicast_in_l2_multicast) - goto err; - - /* RFC4291 2.7 - * Nodes must not originate a packet to a multicast address whose scope - * field contains the reserved value 0; if such a packet is received, it - * must be silently dropped. - */ - if (ipv6_addr_is_multicast(&hdr->daddr) && - IPV6_ADDR_MC_SCOPE(&hdr->daddr) == 0) - goto err; - - /* - * RFC4291 2.7 - * Multicast addresses must not be used as source addresses in IPv6 - * packets or appear in any Routing header. - */ - if (ipv6_addr_is_multicast(&hdr->saddr)) - goto err; - - skb->transport_header = skb->network_header + sizeof(*hdr); - IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); - - pkt_len = ntohs(hdr->payload_len); - - /* pkt_len may be zero if Jumbo payload option is present */ - if (pkt_len || hdr->nexthdr != NEXTHDR_HOP) { - if (pkt_len + sizeof(struct ipv6hdr) > skb->len) { - __IP6_INC_STATS(net, - idev, IPSTATS_MIB_INTRUNCATEDPKTS); - goto drop; - } - if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) { - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); - goto drop; - } - hdr = ipv6_hdr(skb); - } - - if (hdr->nexthdr == NEXTHDR_HOP) { - if (ipv6_parse_hopopts(skb) < 0) { - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); - rcu_read_unlock(); - return NET_RX_DROP; - } - } - - rcu_read_unlock(); - - /* Must drop socket now because of tproxy. */ - skb_orphan(skb); - - return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, - net, NULL, skb, dev, NULL, - ip6_rcv_finish); -err: - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS); -drop: - rcu_read_unlock(); - kfree_skb(skb); - return NET_RX_DROP; -} - -/* - * Deliver the packet to the host - */ - - -static int ip6_input_finish(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - const struct inet6_protocol *ipprot; - struct inet6_dev *idev; - unsigned int nhoff; - int nexthdr; - bool raw; - bool have_final = false; - - /* - * Parse extension headers - */ - - rcu_read_lock(); -resubmit: - idev = ip6_dst_idev(skb_dst(skb)); - if (!pskb_pull(skb, skb_transport_offset(skb))) - goto discard; - nhoff = IP6CB(skb)->nhoff; - nexthdr = skb_network_header(skb)[nhoff]; - -resubmit_final: - raw = raw6_local_deliver(skb, nexthdr); - ipprot = rcu_dereference(inet6_protos[nexthdr]); - if (ipprot) { - int ret; - - if (have_final) { - if (!(ipprot->flags & INET6_PROTO_FINAL)) { - /* Once we've seen a final protocol don't - * allow encapsulation on any non-final - * ones. This allows foo in UDP encapsulation - * to work. - */ - goto discard; - } - } else if (ipprot->flags & INET6_PROTO_FINAL) { - const struct ipv6hdr *hdr; - - /* Only do this once for first final protocol */ - have_final = true; - - /* Free reference early: we don't need it any more, - and it may hold ip_conntrack module loaded - indefinitely. */ - nf_reset(skb); - - skb_postpull_rcsum(skb, skb_network_header(skb), - skb_network_header_len(skb)); - hdr = ipv6_hdr(skb); - if (ipv6_addr_is_multicast(&hdr->daddr) && - !ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, - &hdr->saddr) && - !ipv6_is_mld(skb, nexthdr, skb_network_header_len(skb))) - goto discard; - } - if (!(ipprot->flags & INET6_PROTO_NOPOLICY) && - !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) - goto discard; - - ret = ipprot->handler(skb); - if (ret > 0) { - if (ipprot->flags & INET6_PROTO_FINAL) { - /* Not an extension header, most likely UDP - * encapsulation. Use return value as nexthdr - * protocol not nhoff (which presumably is - * not set by handler). - */ - nexthdr = ret; - goto resubmit_final; - } else { - goto resubmit; - } - } else if (ret == 0) { - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDELIVERS); - } - } else { - if (!raw) { - if (xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { - __IP6_INC_STATS(net, idev, - IPSTATS_MIB_INUNKNOWNPROTOS); - icmpv6_send(skb, ICMPV6_PARAMPROB, - ICMPV6_UNK_NEXTHDR, nhoff); - } - kfree_skb(skb); - } else { - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDELIVERS); - consume_skb(skb); - } - } - rcu_read_unlock(); - return 0; - -discard: - __IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS); - rcu_read_unlock(); - kfree_skb(skb); - return 0; -} - - -int ip6_input(struct sk_buff *skb) -{ - return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_IN, - dev_net(skb->dev), NULL, skb, skb->dev, NULL, - ip6_input_finish); -} -EXPORT_SYMBOL_GPL(ip6_input); - -int ip6_mc_input(struct sk_buff *skb) -{ - const struct ipv6hdr *hdr; - bool deliver; - - __IP6_UPD_PO_STATS(dev_net(skb_dst(skb)->dev), - ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_INMCAST, - skb->len); - - hdr = ipv6_hdr(skb); - deliver = ipv6_chk_mcast_addr(skb->dev, &hdr->daddr, NULL); - -#ifdef CONFIG_IPV6_MROUTE - /* - * IPv6 multicast router mode is now supported ;) - */ - if (dev_net(skb->dev)->ipv6.devconf_all->mc_forwarding && - !(ipv6_addr_type(&hdr->daddr) & - (IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL)) && - likely(!(IP6CB(skb)->flags & IP6SKB_FORWARDED))) { - /* - * Okay, we try to forward - split and duplicate - * packets. - */ - struct sk_buff *skb2; - struct inet6_skb_parm *opt = IP6CB(skb); - - /* Check for MLD */ - if (unlikely(opt->flags & IP6SKB_ROUTERALERT)) { - /* Check if this is a mld message */ - u8 nexthdr = hdr->nexthdr; - __be16 frag_off; - int offset; - - /* Check if the value of Router Alert - * is for MLD (0x0000). - */ - if (opt->ra == htons(IPV6_OPT_ROUTERALERT_MLD)) { - deliver = false; - - if (!ipv6_ext_hdr(nexthdr)) { - /* BUG */ - goto out; - } - offset = ipv6_skip_exthdr(skb, sizeof(*hdr), - &nexthdr, &frag_off); - if (offset < 0) - goto out; - - if (ipv6_is_mld(skb, nexthdr, offset)) - deliver = true; - - goto out; - } - /* unknown RA - process it normally */ - } - - if (deliver) - skb2 = skb_clone(skb, GFP_ATOMIC); - else { - skb2 = skb; - skb = NULL; - } - - if (skb2) { - ip6_mr_input(skb2); - } - } -out: -#endif - if (likely(deliver)) - ip6_input(skb); - else { - /* discard */ - kfree_skb(skb); - } - - return 0; -} diff --git a/src/linux/net/ipv6/ip6_offload.c b/src/linux/net/ipv6/ip6_offload.c deleted file mode 100644 index 89c59e6..0000000 --- a/src/linux/net/ipv6/ip6_offload.c +++ /dev/null @@ -1,385 +0,0 @@ -/* - * IPV6 GSO/GRO offload support - * Linux INET6 implementation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "ip6_offload.h" - -static int ipv6_gso_pull_exthdrs(struct sk_buff *skb, int proto) -{ - const struct net_offload *ops = NULL; - - for (;;) { - struct ipv6_opt_hdr *opth; - int len; - - if (proto != NEXTHDR_HOP) { - ops = rcu_dereference(inet6_offloads[proto]); - - if (unlikely(!ops)) - break; - - if (!(ops->flags & INET6_PROTO_GSO_EXTHDR)) - break; - } - - if (unlikely(!pskb_may_pull(skb, 8))) - break; - - opth = (void *)skb->data; - len = ipv6_optlen(opth); - - if (unlikely(!pskb_may_pull(skb, len))) - break; - - opth = (void *)skb->data; - proto = opth->nexthdr; - __skb_pull(skb, len); - } - - return proto; -} - -static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb, - netdev_features_t features) -{ - struct sk_buff *segs = ERR_PTR(-EINVAL); - struct ipv6hdr *ipv6h; - const struct net_offload *ops; - int proto; - struct frag_hdr *fptr; - unsigned int unfrag_ip6hlen; - unsigned int payload_len; - u8 *prevhdr; - int offset = 0; - bool encap, udpfrag; - int nhoff; - bool gso_partial; - - skb_reset_network_header(skb); - nhoff = skb_network_header(skb) - skb_mac_header(skb); - if (unlikely(!pskb_may_pull(skb, sizeof(*ipv6h)))) - goto out; - - encap = SKB_GSO_CB(skb)->encap_level > 0; - if (encap) - features &= skb->dev->hw_enc_features; - SKB_GSO_CB(skb)->encap_level += sizeof(*ipv6h); - - ipv6h = ipv6_hdr(skb); - __skb_pull(skb, sizeof(*ipv6h)); - segs = ERR_PTR(-EPROTONOSUPPORT); - - proto = ipv6_gso_pull_exthdrs(skb, ipv6h->nexthdr); - - if (skb->encapsulation && - skb_shinfo(skb)->gso_type & (SKB_GSO_IPXIP4 | SKB_GSO_IPXIP6)) - udpfrag = proto == IPPROTO_UDP && encap; - else - udpfrag = proto == IPPROTO_UDP && !skb->encapsulation; - - ops = rcu_dereference(inet6_offloads[proto]); - if (likely(ops && ops->callbacks.gso_segment)) { - skb_reset_transport_header(skb); - segs = ops->callbacks.gso_segment(skb, features); - } - - if (IS_ERR_OR_NULL(segs)) - goto out; - - gso_partial = !!(skb_shinfo(segs)->gso_type & SKB_GSO_PARTIAL); - - for (skb = segs; skb; skb = skb->next) { - ipv6h = (struct ipv6hdr *)(skb_mac_header(skb) + nhoff); - if (gso_partial) - payload_len = skb_shinfo(skb)->gso_size + - SKB_GSO_CB(skb)->data_offset + - skb->head - (unsigned char *)(ipv6h + 1); - else - payload_len = skb->len - nhoff - sizeof(*ipv6h); - ipv6h->payload_len = htons(payload_len); - skb->network_header = (u8 *)ipv6h - skb->head; - - if (udpfrag) { - unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); - fptr = (struct frag_hdr *)((u8 *)ipv6h + unfrag_ip6hlen); - fptr->frag_off = htons(offset); - if (skb->next) - fptr->frag_off |= htons(IP6_MF); - offset += (ntohs(ipv6h->payload_len) - - sizeof(struct frag_hdr)); - } - if (encap) - skb_reset_inner_headers(skb); - } - -out: - return segs; -} - -/* Return the total length of all the extension hdrs, following the same - * logic in ipv6_gso_pull_exthdrs() when parsing ext-hdrs. - */ -static int ipv6_exthdrs_len(struct ipv6hdr *iph, - const struct net_offload **opps) -{ - struct ipv6_opt_hdr *opth = (void *)iph; - int len = 0, proto, optlen = sizeof(*iph); - - proto = iph->nexthdr; - for (;;) { - if (proto != NEXTHDR_HOP) { - *opps = rcu_dereference(inet6_offloads[proto]); - if (unlikely(!(*opps))) - break; - if (!((*opps)->flags & INET6_PROTO_GSO_EXTHDR)) - break; - } - opth = (void *)opth + optlen; - optlen = ipv6_optlen(opth); - len += optlen; - proto = opth->nexthdr; - } - return len; -} - -static struct sk_buff **ipv6_gro_receive(struct sk_buff **head, - struct sk_buff *skb) -{ - const struct net_offload *ops; - struct sk_buff **pp = NULL; - struct sk_buff *p; - struct ipv6hdr *iph; - unsigned int nlen; - unsigned int hlen; - unsigned int off; - u16 flush = 1; - int proto; - - off = skb_gro_offset(skb); - hlen = off + sizeof(*iph); - iph = skb_gro_header_fast(skb, off); - if (skb_gro_header_hard(skb, hlen)) { - iph = skb_gro_header_slow(skb, hlen, off); - if (unlikely(!iph)) - goto out; - } - - skb_set_network_header(skb, off); - skb_gro_pull(skb, sizeof(*iph)); - skb_set_transport_header(skb, skb_gro_offset(skb)); - - flush += ntohs(iph->payload_len) != skb_gro_len(skb); - - rcu_read_lock(); - proto = iph->nexthdr; - ops = rcu_dereference(inet6_offloads[proto]); - if (!ops || !ops->callbacks.gro_receive) { - __pskb_pull(skb, skb_gro_offset(skb)); - proto = ipv6_gso_pull_exthdrs(skb, proto); - skb_gro_pull(skb, -skb_transport_offset(skb)); - skb_reset_transport_header(skb); - __skb_push(skb, skb_gro_offset(skb)); - - ops = rcu_dereference(inet6_offloads[proto]); - if (!ops || !ops->callbacks.gro_receive) - goto out_unlock; - - iph = ipv6_hdr(skb); - } - - NAPI_GRO_CB(skb)->proto = proto; - - flush--; - nlen = skb_network_header_len(skb); - - for (p = *head; p; p = p->next) { - const struct ipv6hdr *iph2; - __be32 first_word; /* */ - - if (!NAPI_GRO_CB(p)->same_flow) - continue; - - iph2 = (struct ipv6hdr *)(p->data + off); - first_word = *(__be32 *)iph ^ *(__be32 *)iph2; - - /* All fields must match except length and Traffic Class. - * XXX skbs on the gro_list have all been parsed and pulled - * already so we don't need to compare nlen - * (nlen != (sizeof(*iph2) + ipv6_exthdrs_len(iph2, &ops))) - * memcmp() alone below is suffcient, right? - */ - if ((first_word & htonl(0xF00FFFFF)) || - memcmp(&iph->nexthdr, &iph2->nexthdr, - nlen - offsetof(struct ipv6hdr, nexthdr))) { - NAPI_GRO_CB(p)->same_flow = 0; - continue; - } - /* flush if Traffic Class fields are different */ - NAPI_GRO_CB(p)->flush |= !!(first_word & htonl(0x0FF00000)); - NAPI_GRO_CB(p)->flush |= flush; - - /* If the previous IP ID value was based on an atomic - * datagram we can overwrite the value and ignore it. - */ - if (NAPI_GRO_CB(skb)->is_atomic) - NAPI_GRO_CB(p)->flush_id = 0; - } - - NAPI_GRO_CB(skb)->is_atomic = true; - NAPI_GRO_CB(skb)->flush |= flush; - - skb_gro_postpull_rcsum(skb, iph, nlen); - - pp = call_gro_receive(ops->callbacks.gro_receive, head, skb); - -out_unlock: - rcu_read_unlock(); - -out: - NAPI_GRO_CB(skb)->flush |= flush; - - return pp; -} - -static struct sk_buff **sit_ip6ip6_gro_receive(struct sk_buff **head, - struct sk_buff *skb) -{ - /* Common GRO receive for SIT and IP6IP6 */ - - if (NAPI_GRO_CB(skb)->encap_mark) { - NAPI_GRO_CB(skb)->flush = 1; - return NULL; - } - - NAPI_GRO_CB(skb)->encap_mark = 1; - - return ipv6_gro_receive(head, skb); -} - -static struct sk_buff **ip4ip6_gro_receive(struct sk_buff **head, - struct sk_buff *skb) -{ - /* Common GRO receive for SIT and IP6IP6 */ - - if (NAPI_GRO_CB(skb)->encap_mark) { - NAPI_GRO_CB(skb)->flush = 1; - return NULL; - } - - NAPI_GRO_CB(skb)->encap_mark = 1; - - return inet_gro_receive(head, skb); -} - -static int ipv6_gro_complete(struct sk_buff *skb, int nhoff) -{ - const struct net_offload *ops; - struct ipv6hdr *iph = (struct ipv6hdr *)(skb->data + nhoff); - int err = -ENOSYS; - - if (skb->encapsulation) - skb_set_inner_network_header(skb, nhoff); - - iph->payload_len = htons(skb->len - nhoff - sizeof(*iph)); - - rcu_read_lock(); - - nhoff += sizeof(*iph) + ipv6_exthdrs_len(iph, &ops); - if (WARN_ON(!ops || !ops->callbacks.gro_complete)) - goto out_unlock; - - err = ops->callbacks.gro_complete(skb, nhoff); - -out_unlock: - rcu_read_unlock(); - - return err; -} - -static int sit_gro_complete(struct sk_buff *skb, int nhoff) -{ - skb->encapsulation = 1; - skb_shinfo(skb)->gso_type |= SKB_GSO_IPXIP4; - return ipv6_gro_complete(skb, nhoff); -} - -static int ip6ip6_gro_complete(struct sk_buff *skb, int nhoff) -{ - skb->encapsulation = 1; - skb_shinfo(skb)->gso_type |= SKB_GSO_IPXIP6; - return ipv6_gro_complete(skb, nhoff); -} - -static int ip4ip6_gro_complete(struct sk_buff *skb, int nhoff) -{ - skb->encapsulation = 1; - skb_shinfo(skb)->gso_type |= SKB_GSO_IPXIP6; - return inet_gro_complete(skb, nhoff); -} - -static struct packet_offload ipv6_packet_offload __read_mostly = { - .type = cpu_to_be16(ETH_P_IPV6), - .callbacks = { - .gso_segment = ipv6_gso_segment, - .gro_receive = ipv6_gro_receive, - .gro_complete = ipv6_gro_complete, - }, -}; - -static const struct net_offload sit_offload = { - .callbacks = { - .gso_segment = ipv6_gso_segment, - .gro_receive = sit_ip6ip6_gro_receive, - .gro_complete = sit_gro_complete, - }, -}; - -static const struct net_offload ip4ip6_offload = { - .callbacks = { - .gso_segment = inet_gso_segment, - .gro_receive = ip4ip6_gro_receive, - .gro_complete = ip4ip6_gro_complete, - }, -}; - -static const struct net_offload ip6ip6_offload = { - .callbacks = { - .gso_segment = ipv6_gso_segment, - .gro_receive = sit_ip6ip6_gro_receive, - .gro_complete = ip6ip6_gro_complete, - }, -}; -static int __init ipv6_offload_init(void) -{ - - if (tcpv6_offload_init() < 0) - pr_crit("%s: Cannot add TCP protocol offload\n", __func__); - if (ipv6_exthdrs_offload_init() < 0) - pr_crit("%s: Cannot add EXTHDRS protocol offload\n", __func__); - - dev_add_offload(&ipv6_packet_offload); - - inet_add_offload(&sit_offload, IPPROTO_IPV6); - inet6_add_offload(&ip6ip6_offload, IPPROTO_IPV6); - inet6_add_offload(&ip4ip6_offload, IPPROTO_IPIP); - - return 0; -} - -fs_initcall(ipv6_offload_init); diff --git a/src/linux/net/ipv6/ip6_offload.h b/src/linux/net/ipv6/ip6_offload.h deleted file mode 100644 index 96b40e4..0000000 --- a/src/linux/net/ipv6/ip6_offload.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * IPV6 GSO/GRO offload support - * Linux INET6 implementation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#ifndef __ip6_offload_h -#define __ip6_offload_h - -int ipv6_exthdrs_offload_init(void); -int udpv6_offload_init(void); -int udpv6_offload_exit(void); -int tcpv6_offload_init(void); - -#endif diff --git a/src/linux/net/ipv6/ip6_output.c b/src/linux/net/ipv6/ip6_output.c deleted file mode 100644 index 59eb4ed..0000000 --- a/src/linux/net/ipv6/ip6_output.c +++ /dev/null @@ -1,1800 +0,0 @@ -/* - * IPv6 output functions - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * Based on linux/net/ipv4/ip_output.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Changes: - * A.N.Kuznetsov : airthmetics in fragmentation. - * extension headers are implemented. - * route changes now work. - * ip6_forward does not confuse sniffers. - * etc. - * - * H. von Brand : Added missing #include - * Imran Patel : frag id should be in NBO - * Kazunori MIYAZAWA @USAGI - * : add ip6_append_data and related functions - * for datagram xmit - */ - -#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 - -static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - struct dst_entry *dst = skb_dst(skb); - struct net_device *dev = dst->dev; - struct neighbour *neigh; - struct in6_addr *nexthop; - int ret; - - skb->protocol = htons(ETH_P_IPV6); - skb->dev = dev; - - if (ipv6_addr_is_multicast(&ipv6_hdr(skb)->daddr)) { - struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); - - if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(sk) && - ((mroute6_socket(net, skb) && - !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) || - ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr, - &ipv6_hdr(skb)->saddr))) { - struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); - - /* Do not check for IFF_ALLMULTI; multicast routing - is not supported in any case. - */ - if (newskb) - NF_HOOK(NFPROTO_IPV6, NF_INET_POST_ROUTING, - net, sk, newskb, NULL, newskb->dev, - dev_loopback_xmit); - - if (ipv6_hdr(skb)->hop_limit == 0) { - IP6_INC_STATS(net, idev, - IPSTATS_MIB_OUTDISCARDS); - kfree_skb(skb); - return 0; - } - } - - IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUTMCAST, skb->len); - - if (IPV6_ADDR_MC_SCOPE(&ipv6_hdr(skb)->daddr) <= - IPV6_ADDR_SCOPE_NODELOCAL && - !(dev->flags & IFF_LOOPBACK)) { - kfree_skb(skb); - return 0; - } - } - - if (lwtunnel_xmit_redirect(dst->lwtstate)) { - int res = lwtunnel_xmit(skb); - - if (res < 0 || res == LWTUNNEL_XMIT_DONE) - return res; - } - - rcu_read_lock_bh(); - nexthop = rt6_nexthop((struct rt6_info *)dst, &ipv6_hdr(skb)->daddr); - neigh = __ipv6_neigh_lookup_noref(dst->dev, nexthop); - if (unlikely(!neigh)) - neigh = __neigh_create(&nd_tbl, nexthop, dst->dev, false); - if (!IS_ERR(neigh)) { - ret = dst_neigh_output(dst, neigh, skb); - rcu_read_unlock_bh(); - return ret; - } - rcu_read_unlock_bh(); - - IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); - kfree_skb(skb); - return -EINVAL; -} - -static int ip6_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - if ((skb->len > ip6_skb_dst_mtu(skb) && !skb_is_gso(skb)) || - dst_allfrag(skb_dst(skb)) || - (IP6CB(skb)->frag_max_size && skb->len > IP6CB(skb)->frag_max_size)) - return ip6_fragment(net, sk, skb, ip6_finish_output2); - else - return ip6_finish_output2(net, sk, skb); -} - -int ip6_output(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - struct net_device *dev = skb_dst(skb)->dev; - struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); - - if (unlikely(idev->cnf.disable_ipv6)) { - IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); - kfree_skb(skb); - return 0; - } - - return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, - net, sk, skb, NULL, dev, - ip6_finish_output, - !(IP6CB(skb)->flags & IP6SKB_REROUTED)); -} - -/* - * xmit an sk_buff (used by TCP, SCTP and DCCP) - * Note : socket lock is not held for SYNACK packets, but might be modified - * by calls to skb_set_owner_w() and ipv6_local_error(), - * which are using proper atomic operations or spinlocks. - */ -int ip6_xmit(const struct sock *sk, struct sk_buff *skb, struct flowi6 *fl6, - struct ipv6_txoptions *opt, int tclass) -{ - struct net *net = sock_net(sk); - const struct ipv6_pinfo *np = inet6_sk(sk); - struct in6_addr *first_hop = &fl6->daddr; - struct dst_entry *dst = skb_dst(skb); - struct ipv6hdr *hdr; - u8 proto = fl6->flowi6_proto; - int seg_len = skb->len; - int hlimit = -1; - u32 mtu; - - if (opt) { - unsigned int head_room; - - /* First: exthdrs may take lots of space (~8K for now) - MAX_HEADER is not enough. - */ - head_room = opt->opt_nflen + opt->opt_flen; - seg_len += head_room; - head_room += sizeof(struct ipv6hdr) + LL_RESERVED_SPACE(dst->dev); - - if (skb_headroom(skb) < head_room) { - struct sk_buff *skb2 = skb_realloc_headroom(skb, head_room); - if (!skb2) { - IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_OUTDISCARDS); - kfree_skb(skb); - return -ENOBUFS; - } - consume_skb(skb); - skb = skb2; - /* skb_set_owner_w() changes sk->sk_wmem_alloc atomically, - * it is safe to call in our context (socket lock not held) - */ - skb_set_owner_w(skb, (struct sock *)sk); - } - if (opt->opt_flen) - ipv6_push_frag_opts(skb, opt, &proto); - if (opt->opt_nflen) - ipv6_push_nfrag_opts(skb, opt, &proto, &first_hop); - } - - skb_push(skb, sizeof(struct ipv6hdr)); - skb_reset_network_header(skb); - hdr = ipv6_hdr(skb); - - /* - * Fill in the IPv6 header - */ - if (np) - hlimit = np->hop_limit; - if (hlimit < 0) - hlimit = ip6_dst_hoplimit(dst); - - ip6_flow_hdr(hdr, tclass, ip6_make_flowlabel(net, skb, fl6->flowlabel, - np->autoflowlabel, fl6)); - - hdr->payload_len = htons(seg_len); - hdr->nexthdr = proto; - hdr->hop_limit = hlimit; - - hdr->saddr = fl6->saddr; - hdr->daddr = *first_hop; - - skb->protocol = htons(ETH_P_IPV6); - skb->priority = sk->sk_priority; - skb->mark = sk->sk_mark; - - mtu = dst_mtu(dst); - if ((skb->len <= mtu) || skb->ignore_df || skb_is_gso(skb)) { - IP6_UPD_PO_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_OUT, skb->len); - - /* if egress device is enslaved to an L3 master device pass the - * skb to its handler for processing - */ - skb = l3mdev_ip6_out((struct sock *)sk, skb); - if (unlikely(!skb)) - return 0; - - /* hooks should never assume socket lock is held. - * we promote our socket to non const - */ - return NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, - net, (struct sock *)sk, skb, NULL, dst->dev, - dst_output); - } - - skb->dev = dst->dev; - /* ipv6_local_error() does not require socket lock, - * we promote our socket to non const - */ - ipv6_local_error((struct sock *)sk, EMSGSIZE, fl6, mtu); - - IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_FRAGFAILS); - kfree_skb(skb); - return -EMSGSIZE; -} -EXPORT_SYMBOL(ip6_xmit); - -static int ip6_call_ra_chain(struct sk_buff *skb, int sel) -{ - struct ip6_ra_chain *ra; - struct sock *last = NULL; - - read_lock(&ip6_ra_lock); - for (ra = ip6_ra_chain; ra; ra = ra->next) { - struct sock *sk = ra->sk; - if (sk && ra->sel == sel && - (!sk->sk_bound_dev_if || - sk->sk_bound_dev_if == skb->dev->ifindex)) { - if (last) { - struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); - if (skb2) - rawv6_rcv(last, skb2); - } - last = sk; - } - } - - if (last) { - rawv6_rcv(last, skb); - read_unlock(&ip6_ra_lock); - return 1; - } - read_unlock(&ip6_ra_lock); - return 0; -} - -static int ip6_forward_proxy_check(struct sk_buff *skb) -{ - struct ipv6hdr *hdr = ipv6_hdr(skb); - u8 nexthdr = hdr->nexthdr; - __be16 frag_off; - int offset; - - if (ipv6_ext_hdr(nexthdr)) { - offset = ipv6_skip_exthdr(skb, sizeof(*hdr), &nexthdr, &frag_off); - if (offset < 0) - return 0; - } else - offset = sizeof(struct ipv6hdr); - - if (nexthdr == IPPROTO_ICMPV6) { - struct icmp6hdr *icmp6; - - if (!pskb_may_pull(skb, (skb_network_header(skb) + - offset + 1 - skb->data))) - return 0; - - icmp6 = (struct icmp6hdr *)(skb_network_header(skb) + offset); - - switch (icmp6->icmp6_type) { - case NDISC_ROUTER_SOLICITATION: - case NDISC_ROUTER_ADVERTISEMENT: - case NDISC_NEIGHBOUR_SOLICITATION: - case NDISC_NEIGHBOUR_ADVERTISEMENT: - case NDISC_REDIRECT: - /* For reaction involving unicast neighbor discovery - * message destined to the proxied address, pass it to - * input function. - */ - return 1; - default: - break; - } - } - - /* - * The proxying router can't forward traffic sent to a link-local - * address, so signal the sender and discard the packet. This - * behavior is clarified by the MIPv6 specification. - */ - if (ipv6_addr_type(&hdr->daddr) & IPV6_ADDR_LINKLOCAL) { - dst_link_failure(skb); - return -1; - } - - return 0; -} - -static inline int ip6_forward_finish(struct net *net, struct sock *sk, - struct sk_buff *skb) -{ - return dst_output(net, sk, skb); -} - -static unsigned int ip6_dst_mtu_forward(const struct dst_entry *dst) -{ - unsigned int mtu; - struct inet6_dev *idev; - - if (dst_metric_locked(dst, RTAX_MTU)) { - mtu = dst_metric_raw(dst, RTAX_MTU); - if (mtu) - return mtu; - } - - mtu = IPV6_MIN_MTU; - rcu_read_lock(); - idev = __in6_dev_get(dst->dev); - if (idev) - mtu = idev->cnf.mtu6; - rcu_read_unlock(); - - return mtu; -} - -static bool ip6_pkt_too_big(const struct sk_buff *skb, unsigned int mtu) -{ - if (skb->len <= mtu) - return false; - - /* ipv6 conntrack defrag sets max_frag_size + ignore_df */ - if (IP6CB(skb)->frag_max_size && IP6CB(skb)->frag_max_size > mtu) - return true; - - if (skb->ignore_df) - return false; - - if (skb_is_gso(skb) && skb_gso_validate_mtu(skb, mtu)) - return false; - - return true; -} - -int ip6_forward(struct sk_buff *skb) -{ - struct dst_entry *dst = skb_dst(skb); - struct ipv6hdr *hdr = ipv6_hdr(skb); - struct inet6_skb_parm *opt = IP6CB(skb); - struct net *net = dev_net(dst->dev); - u32 mtu; - - if (net->ipv6.devconf_all->forwarding == 0) - goto error; - - if (skb->pkt_type != PACKET_HOST) - goto drop; - - if (unlikely(skb->sk)) - goto drop; - - if (skb_warn_if_lro(skb)) - goto drop; - - if (!xfrm6_policy_check(NULL, XFRM_POLICY_FWD, skb)) { - __IP6_INC_STATS(net, ip6_dst_idev(dst), - IPSTATS_MIB_INDISCARDS); - goto drop; - } - - skb_forward_csum(skb); - - /* - * We DO NOT make any processing on - * RA packets, pushing them to user level AS IS - * without ane WARRANTY that application will be able - * to interpret them. The reason is that we - * cannot make anything clever here. - * - * We are not end-node, so that if packet contains - * AH/ESP, we cannot make anything. - * Defragmentation also would be mistake, RA packets - * cannot be fragmented, because there is no warranty - * that different fragments will go along one path. --ANK - */ - if (unlikely(opt->flags & IP6SKB_ROUTERALERT)) { - if (ip6_call_ra_chain(skb, ntohs(opt->ra))) - return 0; - } - - /* - * check and decrement ttl - */ - if (hdr->hop_limit <= 1) { - /* Force OUTPUT device used as source address */ - skb->dev = dst->dev; - icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0); - __IP6_INC_STATS(net, ip6_dst_idev(dst), - IPSTATS_MIB_INHDRERRORS); - - kfree_skb(skb); - return -ETIMEDOUT; - } - - /* XXX: idev->cnf.proxy_ndp? */ - if (net->ipv6.devconf_all->proxy_ndp && - pneigh_lookup(&nd_tbl, net, &hdr->daddr, skb->dev, 0)) { - int proxied = ip6_forward_proxy_check(skb); - if (proxied > 0) - return ip6_input(skb); - else if (proxied < 0) { - __IP6_INC_STATS(net, ip6_dst_idev(dst), - IPSTATS_MIB_INDISCARDS); - goto drop; - } - } - - if (!xfrm6_route_forward(skb)) { - __IP6_INC_STATS(net, ip6_dst_idev(dst), - IPSTATS_MIB_INDISCARDS); - goto drop; - } - dst = skb_dst(skb); - - /* IPv6 specs say nothing about it, but it is clear that we cannot - send redirects to source routed frames. - We don't send redirects to frames decapsulated from IPsec. - */ - if (skb->dev == dst->dev && opt->srcrt == 0 && !skb_sec_path(skb)) { - struct in6_addr *target = NULL; - struct inet_peer *peer; - struct rt6_info *rt; - - /* - * incoming and outgoing devices are the same - * send a redirect. - */ - - rt = (struct rt6_info *) dst; - if (rt->rt6i_flags & RTF_GATEWAY) - target = &rt->rt6i_gateway; - else - target = &hdr->daddr; - - peer = inet_getpeer_v6(net->ipv6.peers, &hdr->daddr, 1); - - /* Limit redirects both by destination (here) - and by source (inside ndisc_send_redirect) - */ - if (inet_peer_xrlim_allow(peer, 1*HZ)) - ndisc_send_redirect(skb, target); - if (peer) - inet_putpeer(peer); - } else { - int addrtype = ipv6_addr_type(&hdr->saddr); - - /* This check is security critical. */ - if (addrtype == IPV6_ADDR_ANY || - addrtype & (IPV6_ADDR_MULTICAST | IPV6_ADDR_LOOPBACK)) - goto error; - if (addrtype & IPV6_ADDR_LINKLOCAL) { - icmpv6_send(skb, ICMPV6_DEST_UNREACH, - ICMPV6_NOT_NEIGHBOUR, 0); - goto error; - } - } - - mtu = ip6_dst_mtu_forward(dst); - if (mtu < IPV6_MIN_MTU) - mtu = IPV6_MIN_MTU; - - if (ip6_pkt_too_big(skb, mtu)) { - /* Again, force OUTPUT device used as source address */ - skb->dev = dst->dev; - icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); - __IP6_INC_STATS(net, ip6_dst_idev(dst), - IPSTATS_MIB_INTOOBIGERRORS); - __IP6_INC_STATS(net, ip6_dst_idev(dst), - IPSTATS_MIB_FRAGFAILS); - kfree_skb(skb); - return -EMSGSIZE; - } - - if (skb_cow(skb, dst->dev->hard_header_len)) { - __IP6_INC_STATS(net, ip6_dst_idev(dst), - IPSTATS_MIB_OUTDISCARDS); - goto drop; - } - - hdr = ipv6_hdr(skb); - - /* Mangling hops number delayed to point after skb COW */ - - hdr->hop_limit--; - - __IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTFORWDATAGRAMS); - __IP6_ADD_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_OUTOCTETS, skb->len); - return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, - net, NULL, skb, skb->dev, dst->dev, - ip6_forward_finish); - -error: - __IP6_INC_STATS(net, ip6_dst_idev(dst), IPSTATS_MIB_INADDRERRORS); -drop: - kfree_skb(skb); - return -EINVAL; -} - -static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from) -{ - to->pkt_type = from->pkt_type; - to->priority = from->priority; - to->protocol = from->protocol; - skb_dst_drop(to); - skb_dst_set(to, dst_clone(skb_dst(from))); - to->dev = from->dev; - to->mark = from->mark; - -#ifdef CONFIG_NET_SCHED - to->tc_index = from->tc_index; -#endif - nf_copy(to, from); - skb_copy_secmark(to, from); -} - -int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, - int (*output)(struct net *, struct sock *, struct sk_buff *)) -{ - struct sk_buff *frag; - struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); - struct ipv6_pinfo *np = skb->sk && !dev_recursion_level() ? - inet6_sk(skb->sk) : NULL; - struct ipv6hdr *tmp_hdr; - struct frag_hdr *fh; - unsigned int mtu, hlen, left, len; - int hroom, troom; - __be32 frag_id; - int ptr, offset = 0, err = 0; - u8 *prevhdr, nexthdr = 0; - - hlen = ip6_find_1stfragopt(skb, &prevhdr); - nexthdr = *prevhdr; - - mtu = ip6_skb_dst_mtu(skb); - - /* We must not fragment if the socket is set to force MTU discovery - * or if the skb it not generated by a local socket. - */ - if (unlikely(!skb->ignore_df && skb->len > mtu)) - goto fail_toobig; - - if (IP6CB(skb)->frag_max_size) { - if (IP6CB(skb)->frag_max_size > mtu) - goto fail_toobig; - - /* don't send fragments larger than what we received */ - mtu = IP6CB(skb)->frag_max_size; - if (mtu < IPV6_MIN_MTU) - mtu = IPV6_MIN_MTU; - } - - if (np && np->frag_size < mtu) { - if (np->frag_size) - mtu = np->frag_size; - } - if (mtu < hlen + sizeof(struct frag_hdr) + 8) - goto fail_toobig; - mtu -= hlen + sizeof(struct frag_hdr); - - frag_id = ipv6_select_ident(net, &ipv6_hdr(skb)->daddr, - &ipv6_hdr(skb)->saddr); - - if (skb->ip_summed == CHECKSUM_PARTIAL && - (err = skb_checksum_help(skb))) - goto fail; - - hroom = LL_RESERVED_SPACE(rt->dst.dev); - if (skb_has_frag_list(skb)) { - int first_len = skb_pagelen(skb); - struct sk_buff *frag2; - - if (first_len - hlen > mtu || - ((first_len - hlen) & 7) || - skb_cloned(skb) || - skb_headroom(skb) < (hroom + sizeof(struct frag_hdr))) - goto slow_path; - - skb_walk_frags(skb, frag) { - /* Correct geometry. */ - if (frag->len > mtu || - ((frag->len & 7) && frag->next) || - skb_headroom(frag) < (hlen + hroom + sizeof(struct frag_hdr))) - goto slow_path_clean; - - /* Partially cloned skb? */ - if (skb_shared(frag)) - goto slow_path_clean; - - BUG_ON(frag->sk); - if (skb->sk) { - frag->sk = skb->sk; - frag->destructor = sock_wfree; - } - skb->truesize -= frag->truesize; - } - - err = 0; - offset = 0; - /* BUILD HEADER */ - - *prevhdr = NEXTHDR_FRAGMENT; - tmp_hdr = kmemdup(skb_network_header(skb), hlen, GFP_ATOMIC); - if (!tmp_hdr) { - IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_FRAGFAILS); - err = -ENOMEM; - goto fail; - } - frag = skb_shinfo(skb)->frag_list; - skb_frag_list_init(skb); - - __skb_pull(skb, hlen); - fh = (struct frag_hdr *)__skb_push(skb, sizeof(struct frag_hdr)); - __skb_push(skb, hlen); - skb_reset_network_header(skb); - memcpy(skb_network_header(skb), tmp_hdr, hlen); - - fh->nexthdr = nexthdr; - fh->reserved = 0; - fh->frag_off = htons(IP6_MF); - fh->identification = frag_id; - - first_len = skb_pagelen(skb); - skb->data_len = first_len - skb_headlen(skb); - skb->len = first_len; - ipv6_hdr(skb)->payload_len = htons(first_len - - sizeof(struct ipv6hdr)); - - dst_hold(&rt->dst); - - for (;;) { - /* Prepare header of the next frame, - * before previous one went down. */ - if (frag) { - frag->ip_summed = CHECKSUM_NONE; - skb_reset_transport_header(frag); - fh = (struct frag_hdr *)__skb_push(frag, sizeof(struct frag_hdr)); - __skb_push(frag, hlen); - skb_reset_network_header(frag); - memcpy(skb_network_header(frag), tmp_hdr, - hlen); - offset += skb->len - hlen - sizeof(struct frag_hdr); - fh->nexthdr = nexthdr; - fh->reserved = 0; - fh->frag_off = htons(offset); - if (frag->next) - fh->frag_off |= htons(IP6_MF); - fh->identification = frag_id; - ipv6_hdr(frag)->payload_len = - htons(frag->len - - sizeof(struct ipv6hdr)); - ip6_copy_metadata(frag, skb); - } - - err = output(net, sk, skb); - if (!err) - IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), - IPSTATS_MIB_FRAGCREATES); - - if (err || !frag) - break; - - skb = frag; - frag = skb->next; - skb->next = NULL; - } - - kfree(tmp_hdr); - - if (err == 0) { - IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), - IPSTATS_MIB_FRAGOKS); - ip6_rt_put(rt); - return 0; - } - - kfree_skb_list(frag); - - IP6_INC_STATS(net, ip6_dst_idev(&rt->dst), - IPSTATS_MIB_FRAGFAILS); - ip6_rt_put(rt); - return err; - -slow_path_clean: - skb_walk_frags(skb, frag2) { - if (frag2 == frag) - break; - frag2->sk = NULL; - frag2->destructor = NULL; - skb->truesize += frag2->truesize; - } - } - -slow_path: - left = skb->len - hlen; /* Space per frame */ - ptr = hlen; /* Where to start from */ - - /* - * Fragment the datagram. - */ - - *prevhdr = NEXTHDR_FRAGMENT; - troom = rt->dst.dev->needed_tailroom; - - /* - * Keep copying data until we run out. - */ - while (left > 0) { - len = left; - /* IF: it doesn't fit, use 'mtu' - the data space left */ - if (len > mtu) - len = mtu; - /* IF: we are not sending up to and including the packet end - then align the next start on an eight byte boundary */ - if (len < left) { - len &= ~7; - } - - /* Allocate buffer */ - frag = alloc_skb(len + hlen + sizeof(struct frag_hdr) + - hroom + troom, GFP_ATOMIC); - if (!frag) { - IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_FRAGFAILS); - err = -ENOMEM; - goto fail; - } - - /* - * Set up data on packet - */ - - ip6_copy_metadata(frag, skb); - skb_reserve(frag, hroom); - skb_put(frag, len + hlen + sizeof(struct frag_hdr)); - skb_reset_network_header(frag); - fh = (struct frag_hdr *)(skb_network_header(frag) + hlen); - frag->transport_header = (frag->network_header + hlen + - sizeof(struct frag_hdr)); - - /* - * Charge the memory for the fragment to any owner - * it might possess - */ - if (skb->sk) - skb_set_owner_w(frag, skb->sk); - - /* - * Copy the packet header into the new buffer. - */ - skb_copy_from_linear_data(skb, skb_network_header(frag), hlen); - - /* - * Build fragment header. - */ - fh->nexthdr = nexthdr; - fh->reserved = 0; - fh->identification = frag_id; - - /* - * Copy a block of the IP datagram. - */ - BUG_ON(skb_copy_bits(skb, ptr, skb_transport_header(frag), - len)); - left -= len; - - fh->frag_off = htons(offset); - if (left > 0) - fh->frag_off |= htons(IP6_MF); - ipv6_hdr(frag)->payload_len = htons(frag->len - - sizeof(struct ipv6hdr)); - - ptr += len; - offset += len; - - /* - * Put this fragment into the sending queue. - */ - err = output(net, sk, frag); - if (err) - goto fail; - - IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_FRAGCREATES); - } - IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_FRAGOKS); - consume_skb(skb); - return err; - -fail_toobig: - if (skb->sk && dst_allfrag(skb_dst(skb))) - sk_nocaps_add(skb->sk, NETIF_F_GSO_MASK); - - skb->dev = skb_dst(skb)->dev; - icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); - err = -EMSGSIZE; - -fail: - IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_FRAGFAILS); - kfree_skb(skb); - return err; -} - -static inline int ip6_rt_check(const struct rt6key *rt_key, - const struct in6_addr *fl_addr, - const struct in6_addr *addr_cache) -{ - return (rt_key->plen != 128 || !ipv6_addr_equal(fl_addr, &rt_key->addr)) && - (!addr_cache || !ipv6_addr_equal(fl_addr, addr_cache)); -} - -static struct dst_entry *ip6_sk_dst_check(struct sock *sk, - struct dst_entry *dst, - const struct flowi6 *fl6) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct rt6_info *rt; - - if (!dst) - goto out; - - if (dst->ops->family != AF_INET6) { - dst_release(dst); - return NULL; - } - - rt = (struct rt6_info *)dst; - /* Yes, checking route validity in not connected - * case is not very simple. Take into account, - * that we do not support routing by source, TOS, - * and MSG_DONTROUTE --ANK (980726) - * - * 1. ip6_rt_check(): If route was host route, - * check that cached destination is current. - * If it is network route, we still may - * check its validity using saved pointer - * to the last used address: daddr_cache. - * We do not want to save whole address now, - * (because main consumer of this service - * is tcp, which has not this problem), - * so that the last trick works only on connected - * sockets. - * 2. oif also should be the same. - */ - if (ip6_rt_check(&rt->rt6i_dst, &fl6->daddr, np->daddr_cache) || -#ifdef CONFIG_IPV6_SUBTREES - ip6_rt_check(&rt->rt6i_src, &fl6->saddr, np->saddr_cache) || -#endif - (!(fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF) && - (fl6->flowi6_oif && fl6->flowi6_oif != dst->dev->ifindex))) { - dst_release(dst); - dst = NULL; - } - -out: - return dst; -} - -static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk, - struct dst_entry **dst, struct flowi6 *fl6) -{ -#ifdef CONFIG_IPV6_OPTIMISTIC_DAD - struct neighbour *n; - struct rt6_info *rt; -#endif - int err; - int flags = 0; - - /* The correct way to handle this would be to do - * ip6_route_get_saddr, and then ip6_route_output; however, - * the route-specific preferred source forces the - * ip6_route_output call _before_ ip6_route_get_saddr. - * - * In source specific routing (no src=any default route), - * ip6_route_output will fail given src=any saddr, though, so - * that's why we try it again later. - */ - if (ipv6_addr_any(&fl6->saddr) && (!*dst || !(*dst)->error)) { - struct rt6_info *rt; - bool had_dst = *dst != NULL; - - if (!had_dst) - *dst = ip6_route_output(net, sk, fl6); - rt = (*dst)->error ? NULL : (struct rt6_info *)*dst; - err = ip6_route_get_saddr(net, rt, &fl6->daddr, - sk ? inet6_sk(sk)->srcprefs : 0, - &fl6->saddr); - if (err) - goto out_err_release; - - /* If we had an erroneous initial result, pretend it - * never existed and let the SA-enabled version take - * over. - */ - if (!had_dst && (*dst)->error) { - dst_release(*dst); - *dst = NULL; - } - - if (fl6->flowi6_oif) - flags |= RT6_LOOKUP_F_IFACE; - } - - if (!*dst) - *dst = ip6_route_output_flags(net, sk, fl6, flags); - - err = (*dst)->error; - if (err) - goto out_err_release; - -#ifdef CONFIG_IPV6_OPTIMISTIC_DAD - /* - * Here if the dst entry we've looked up - * has a neighbour entry that is in the INCOMPLETE - * state and the src address from the flow is - * marked as OPTIMISTIC, we release the found - * dst entry and replace it instead with the - * dst entry of the nexthop router - */ - rt = (struct rt6_info *) *dst; - rcu_read_lock_bh(); - n = __ipv6_neigh_lookup_noref(rt->dst.dev, - rt6_nexthop(rt, &fl6->daddr)); - err = n && !(n->nud_state & NUD_VALID) ? -EINVAL : 0; - rcu_read_unlock_bh(); - - if (err) { - struct inet6_ifaddr *ifp; - struct flowi6 fl_gw6; - int redirect; - - ifp = ipv6_get_ifaddr(net, &fl6->saddr, - (*dst)->dev, 1); - - redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC); - if (ifp) - in6_ifa_put(ifp); - - if (redirect) { - /* - * We need to get the dst entry for the - * default router instead - */ - dst_release(*dst); - memcpy(&fl_gw6, fl6, sizeof(struct flowi6)); - memset(&fl_gw6.daddr, 0, sizeof(struct in6_addr)); - *dst = ip6_route_output(net, sk, &fl_gw6); - err = (*dst)->error; - if (err) - goto out_err_release; - } - } -#endif - - return 0; - -out_err_release: - dst_release(*dst); - *dst = NULL; - - if (err == -ENETUNREACH) - IP6_INC_STATS(net, NULL, IPSTATS_MIB_OUTNOROUTES); - return err; -} - -/** - * ip6_dst_lookup - perform route lookup on flow - * @sk: socket which provides route info - * @dst: pointer to dst_entry * for result - * @fl6: flow to lookup - * - * This function performs a route lookup on the given flow. - * - * It returns zero on success, or a standard errno code on error. - */ -int ip6_dst_lookup(struct net *net, struct sock *sk, struct dst_entry **dst, - struct flowi6 *fl6) -{ - *dst = NULL; - return ip6_dst_lookup_tail(net, sk, dst, fl6); -} -EXPORT_SYMBOL_GPL(ip6_dst_lookup); - -/** - * ip6_dst_lookup_flow - perform route lookup on flow with ipsec - * @sk: socket which provides route info - * @fl6: flow to lookup - * @final_dst: final destination address for ipsec lookup - * - * This function performs a route lookup on the given flow. - * - * It returns a valid dst pointer on success, or a pointer encoded - * error code. - */ -struct dst_entry *ip6_dst_lookup_flow(const struct sock *sk, struct flowi6 *fl6, - const struct in6_addr *final_dst) -{ - struct dst_entry *dst = NULL; - int err; - - err = ip6_dst_lookup_tail(sock_net(sk), sk, &dst, fl6); - if (err) - return ERR_PTR(err); - if (final_dst) - fl6->daddr = *final_dst; - - return xfrm_lookup_route(sock_net(sk), dst, flowi6_to_flowi(fl6), sk, 0); -} -EXPORT_SYMBOL_GPL(ip6_dst_lookup_flow); - -/** - * ip6_sk_dst_lookup_flow - perform socket cached route lookup on flow - * @sk: socket which provides the dst cache and route info - * @fl6: flow to lookup - * @final_dst: final destination address for ipsec lookup - * - * This function performs a route lookup on the given flow with the - * possibility of using the cached route in the socket if it is valid. - * It will take the socket dst lock when operating on the dst cache. - * As a result, this function can only be used in process context. - * - * It returns a valid dst pointer on success, or a pointer encoded - * error code. - */ -struct dst_entry *ip6_sk_dst_lookup_flow(struct sock *sk, struct flowi6 *fl6, - const struct in6_addr *final_dst) -{ - struct dst_entry *dst = sk_dst_check(sk, inet6_sk(sk)->dst_cookie); - - dst = ip6_sk_dst_check(sk, dst, fl6); - if (!dst) - dst = ip6_dst_lookup_flow(sk, fl6, final_dst); - - return dst; -} -EXPORT_SYMBOL_GPL(ip6_sk_dst_lookup_flow); - -static inline int ip6_ufo_append_data(struct sock *sk, - struct sk_buff_head *queue, - int getfrag(void *from, char *to, int offset, int len, - int odd, struct sk_buff *skb), - void *from, int length, int hh_len, int fragheaderlen, - int exthdrlen, int transhdrlen, int mtu, - unsigned int flags, const struct flowi6 *fl6) - -{ - struct sk_buff *skb; - int err; - - /* There is support for UDP large send offload by network - * device, so create one single skb packet containing complete - * udp datagram - */ - skb = skb_peek_tail(queue); - if (!skb) { - skb = sock_alloc_send_skb(sk, - hh_len + fragheaderlen + transhdrlen + 20, - (flags & MSG_DONTWAIT), &err); - if (!skb) - return err; - - /* reserve space for Hardware header */ - skb_reserve(skb, hh_len); - - /* create space for UDP/IP header */ - skb_put(skb, fragheaderlen + transhdrlen); - - /* initialize network header pointer */ - skb_set_network_header(skb, exthdrlen); - - /* initialize protocol header pointer */ - skb->transport_header = skb->network_header + fragheaderlen; - - skb->protocol = htons(ETH_P_IPV6); - skb->csum = 0; - - __skb_queue_tail(queue, skb); - } else if (skb_is_gso(skb)) { - goto append; - } - - skb->ip_summed = CHECKSUM_PARTIAL; - /* Specify the length of each IPv6 datagram fragment. - * It has to be a multiple of 8. - */ - skb_shinfo(skb)->gso_size = (mtu - fragheaderlen - - sizeof(struct frag_hdr)) & ~7; - skb_shinfo(skb)->gso_type = SKB_GSO_UDP; - skb_shinfo(skb)->ip6_frag_id = ipv6_select_ident(sock_net(sk), - &fl6->daddr, - &fl6->saddr); - -append: - return skb_append_datato_frags(sk, skb, getfrag, from, - (length - transhdrlen)); -} - -static inline struct ipv6_opt_hdr *ip6_opt_dup(struct ipv6_opt_hdr *src, - gfp_t gfp) -{ - return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL; -} - -static inline struct ipv6_rt_hdr *ip6_rthdr_dup(struct ipv6_rt_hdr *src, - gfp_t gfp) -{ - return src ? kmemdup(src, (src->hdrlen + 1) * 8, gfp) : NULL; -} - -static void ip6_append_data_mtu(unsigned int *mtu, - int *maxfraglen, - unsigned int fragheaderlen, - struct sk_buff *skb, - struct rt6_info *rt, - unsigned int orig_mtu) -{ - if (!(rt->dst.flags & DST_XFRM_TUNNEL)) { - if (!skb) { - /* first fragment, reserve header_len */ - *mtu = orig_mtu - rt->dst.header_len; - - } else { - /* - * this fragment is not first, the headers - * space is regarded as data space. - */ - *mtu = orig_mtu; - } - *maxfraglen = ((*mtu - fragheaderlen) & ~7) - + fragheaderlen - sizeof(struct frag_hdr); - } -} - -static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork, - struct inet6_cork *v6_cork, struct ipcm6_cookie *ipc6, - struct rt6_info *rt, struct flowi6 *fl6) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - unsigned int mtu; - struct ipv6_txoptions *opt = ipc6->opt; - - /* - * setup for corking - */ - if (opt) { - if (WARN_ON(v6_cork->opt)) - return -EINVAL; - - v6_cork->opt = kzalloc(opt->tot_len, sk->sk_allocation); - if (unlikely(!v6_cork->opt)) - return -ENOBUFS; - - v6_cork->opt->tot_len = opt->tot_len; - v6_cork->opt->opt_flen = opt->opt_flen; - v6_cork->opt->opt_nflen = opt->opt_nflen; - - v6_cork->opt->dst0opt = ip6_opt_dup(opt->dst0opt, - sk->sk_allocation); - if (opt->dst0opt && !v6_cork->opt->dst0opt) - return -ENOBUFS; - - v6_cork->opt->dst1opt = ip6_opt_dup(opt->dst1opt, - sk->sk_allocation); - if (opt->dst1opt && !v6_cork->opt->dst1opt) - return -ENOBUFS; - - v6_cork->opt->hopopt = ip6_opt_dup(opt->hopopt, - sk->sk_allocation); - if (opt->hopopt && !v6_cork->opt->hopopt) - return -ENOBUFS; - - v6_cork->opt->srcrt = ip6_rthdr_dup(opt->srcrt, - sk->sk_allocation); - if (opt->srcrt && !v6_cork->opt->srcrt) - return -ENOBUFS; - - /* need source address above miyazawa*/ - } - dst_hold(&rt->dst); - cork->base.dst = &rt->dst; - cork->fl.u.ip6 = *fl6; - v6_cork->hop_limit = ipc6->hlimit; - v6_cork->tclass = ipc6->tclass; - if (rt->dst.flags & DST_XFRM_TUNNEL) - mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? - rt->dst.dev->mtu : dst_mtu(&rt->dst); - else - mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? - rt->dst.dev->mtu : dst_mtu(rt->dst.path); - if (np->frag_size < mtu) { - if (np->frag_size) - mtu = np->frag_size; - } - cork->base.fragsize = mtu; - if (dst_allfrag(rt->dst.path)) - cork->base.flags |= IPCORK_ALLFRAG; - cork->base.length = 0; - - return 0; -} - -static int __ip6_append_data(struct sock *sk, - struct flowi6 *fl6, - struct sk_buff_head *queue, - struct inet_cork *cork, - struct inet6_cork *v6_cork, - struct page_frag *pfrag, - int getfrag(void *from, char *to, int offset, - int len, int odd, struct sk_buff *skb), - void *from, int length, int transhdrlen, - unsigned int flags, struct ipcm6_cookie *ipc6, - const struct sockcm_cookie *sockc) -{ - struct sk_buff *skb, *skb_prev = NULL; - unsigned int maxfraglen, fragheaderlen, mtu, orig_mtu; - int exthdrlen = 0; - int dst_exthdrlen = 0; - int hh_len; - int copy; - int err; - int offset = 0; - __u8 tx_flags = 0; - u32 tskey = 0; - struct rt6_info *rt = (struct rt6_info *)cork->dst; - struct ipv6_txoptions *opt = v6_cork->opt; - int csummode = CHECKSUM_NONE; - unsigned int maxnonfragsize, headersize; - - skb = skb_peek_tail(queue); - if (!skb) { - exthdrlen = opt ? opt->opt_flen : 0; - dst_exthdrlen = rt->dst.header_len - rt->rt6i_nfheader_len; - } - - mtu = cork->fragsize; - orig_mtu = mtu; - - hh_len = LL_RESERVED_SPACE(rt->dst.dev); - - fragheaderlen = sizeof(struct ipv6hdr) + rt->rt6i_nfheader_len + - (opt ? opt->opt_nflen : 0); - maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - - sizeof(struct frag_hdr); - - headersize = sizeof(struct ipv6hdr) + - (opt ? opt->opt_flen + opt->opt_nflen : 0) + - (dst_allfrag(&rt->dst) ? - sizeof(struct frag_hdr) : 0) + - rt->rt6i_nfheader_len; - - if (cork->length + length > mtu - headersize && ipc6->dontfrag && - (sk->sk_protocol == IPPROTO_UDP || - sk->sk_protocol == IPPROTO_RAW)) { - ipv6_local_rxpmtu(sk, fl6, mtu - headersize + - sizeof(struct ipv6hdr)); - goto emsgsize; - } - - if (ip6_sk_ignore_df(sk)) - maxnonfragsize = sizeof(struct ipv6hdr) + IPV6_MAXPLEN; - else - maxnonfragsize = mtu; - - if (cork->length + length > maxnonfragsize - headersize) { -emsgsize: - ipv6_local_error(sk, EMSGSIZE, fl6, - mtu - headersize + - sizeof(struct ipv6hdr)); - return -EMSGSIZE; - } - - /* CHECKSUM_PARTIAL only with no extension headers and when - * we are not going to fragment - */ - if (transhdrlen && sk->sk_protocol == IPPROTO_UDP && - headersize == sizeof(struct ipv6hdr) && - length < mtu - headersize && - !(flags & MSG_MORE) && - rt->dst.dev->features & (NETIF_F_IPV6_CSUM | NETIF_F_HW_CSUM)) - csummode = CHECKSUM_PARTIAL; - - if (sk->sk_type == SOCK_DGRAM || sk->sk_type == SOCK_RAW) { - sock_tx_timestamp(sk, sockc->tsflags, &tx_flags); - if (tx_flags & SKBTX_ANY_SW_TSTAMP && - sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID) - tskey = sk->sk_tskey++; - } - - /* - * Let's try using as much space as possible. - * Use MTU if total length of the message fits into the MTU. - * Otherwise, we need to reserve fragment header and - * fragment alignment (= 8-15 octects, in total). - * - * Note that we may need to "move" the data from the tail of - * of the buffer to the new fragment when we split - * the message. - * - * FIXME: It may be fragmented into multiple chunks - * at once if non-fragmentable extension headers - * are too large. - * --yoshfuji - */ - - cork->length += length; - if (((length > mtu) || - (skb && skb_is_gso(skb))) && - (sk->sk_protocol == IPPROTO_UDP) && - (rt->dst.dev->features & NETIF_F_UFO) && !rt->dst.header_len && - (sk->sk_type == SOCK_DGRAM) && !udp_get_no_check6_tx(sk)) { - err = ip6_ufo_append_data(sk, queue, getfrag, from, length, - hh_len, fragheaderlen, exthdrlen, - transhdrlen, mtu, flags, fl6); - if (err) - goto error; - return 0; - } - - if (!skb) - goto alloc_new_skb; - - while (length > 0) { - /* Check if the remaining data fits into current packet. */ - copy = (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - skb->len; - if (copy < length) - copy = maxfraglen - skb->len; - - if (copy <= 0) { - char *data; - unsigned int datalen; - unsigned int fraglen; - unsigned int fraggap; - unsigned int alloclen; -alloc_new_skb: - /* There's no room in the current skb */ - if (skb) - fraggap = skb->len - maxfraglen; - else - fraggap = 0; - /* update mtu and maxfraglen if necessary */ - if (!skb || !skb_prev) - ip6_append_data_mtu(&mtu, &maxfraglen, - fragheaderlen, skb, rt, - orig_mtu); - - skb_prev = skb; - - /* - * If remaining data exceeds the mtu, - * we know we need more fragment(s). - */ - datalen = length + fraggap; - - if (datalen > (cork->length <= mtu && !(cork->flags & IPCORK_ALLFRAG) ? mtu : maxfraglen) - fragheaderlen) - datalen = maxfraglen - fragheaderlen - rt->dst.trailer_len; - if ((flags & MSG_MORE) && - !(rt->dst.dev->features&NETIF_F_SG)) - alloclen = mtu; - else - alloclen = datalen + fragheaderlen; - - alloclen += dst_exthdrlen; - - if (datalen != length + fraggap) { - /* - * this is not the last fragment, the trailer - * space is regarded as data space. - */ - datalen += rt->dst.trailer_len; - } - - alloclen += rt->dst.trailer_len; - fraglen = datalen + fragheaderlen; - - /* - * We just reserve space for fragment header. - * Note: this may be overallocation if the message - * (without MSG_MORE) fits into the MTU. - */ - alloclen += sizeof(struct frag_hdr); - - if (transhdrlen) { - skb = sock_alloc_send_skb(sk, - alloclen + hh_len, - (flags & MSG_DONTWAIT), &err); - } else { - skb = NULL; - if (atomic_read(&sk->sk_wmem_alloc) <= - 2 * sk->sk_sndbuf) - skb = sock_wmalloc(sk, - alloclen + hh_len, 1, - sk->sk_allocation); - if (unlikely(!skb)) - err = -ENOBUFS; - } - if (!skb) - goto error; - /* - * Fill in the control structures - */ - skb->protocol = htons(ETH_P_IPV6); - skb->ip_summed = csummode; - skb->csum = 0; - /* reserve for fragmentation and ipsec header */ - skb_reserve(skb, hh_len + sizeof(struct frag_hdr) + - dst_exthdrlen); - - /* Only the initial fragment is time stamped */ - skb_shinfo(skb)->tx_flags = tx_flags; - tx_flags = 0; - skb_shinfo(skb)->tskey = tskey; - tskey = 0; - - /* - * Find where to start putting bytes - */ - data = skb_put(skb, fraglen); - skb_set_network_header(skb, exthdrlen); - data += fragheaderlen; - skb->transport_header = (skb->network_header + - fragheaderlen); - if (fraggap) { - skb->csum = skb_copy_and_csum_bits( - skb_prev, maxfraglen, - data + transhdrlen, fraggap, 0); - skb_prev->csum = csum_sub(skb_prev->csum, - skb->csum); - data += fraggap; - pskb_trim_unique(skb_prev, maxfraglen); - } - copy = datalen - transhdrlen - fraggap; - - if (copy < 0) { - err = -EINVAL; - kfree_skb(skb); - goto error; - } else if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) { - err = -EFAULT; - kfree_skb(skb); - goto error; - } - - offset += copy; - length -= datalen - fraggap; - transhdrlen = 0; - exthdrlen = 0; - dst_exthdrlen = 0; - - /* - * Put the packet on the pending queue - */ - __skb_queue_tail(queue, skb); - continue; - } - - if (copy > length) - copy = length; - - if (!(rt->dst.dev->features&NETIF_F_SG)) { - unsigned int off; - - off = skb->len; - if (getfrag(from, skb_put(skb, copy), - offset, copy, off, skb) < 0) { - __skb_trim(skb, off); - err = -EFAULT; - goto error; - } - } else { - int i = skb_shinfo(skb)->nr_frags; - - err = -ENOMEM; - if (!sk_page_frag_refill(sk, pfrag)) - goto error; - - if (!skb_can_coalesce(skb, i, pfrag->page, - pfrag->offset)) { - err = -EMSGSIZE; - if (i == MAX_SKB_FRAGS) - goto error; - - __skb_fill_page_desc(skb, i, pfrag->page, - pfrag->offset, 0); - skb_shinfo(skb)->nr_frags = ++i; - get_page(pfrag->page); - } - copy = min_t(int, copy, pfrag->size - pfrag->offset); - if (getfrag(from, - page_address(pfrag->page) + pfrag->offset, - offset, copy, skb->len, skb) < 0) - goto error_efault; - - pfrag->offset += copy; - skb_frag_size_add(&skb_shinfo(skb)->frags[i - 1], copy); - skb->len += copy; - skb->data_len += copy; - skb->truesize += copy; - atomic_add(copy, &sk->sk_wmem_alloc); - } - offset += copy; - length -= copy; - } - - return 0; - -error_efault: - err = -EFAULT; -error: - cork->length -= length; - IP6_INC_STATS(sock_net(sk), rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); - return err; -} - -int ip6_append_data(struct sock *sk, - int getfrag(void *from, char *to, int offset, int len, - int odd, struct sk_buff *skb), - void *from, int length, int transhdrlen, - struct ipcm6_cookie *ipc6, struct flowi6 *fl6, - struct rt6_info *rt, unsigned int flags, - const struct sockcm_cookie *sockc) -{ - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *np = inet6_sk(sk); - int exthdrlen; - int err; - - if (flags&MSG_PROBE) - return 0; - if (skb_queue_empty(&sk->sk_write_queue)) { - /* - * setup for corking - */ - err = ip6_setup_cork(sk, &inet->cork, &np->cork, - ipc6, rt, fl6); - if (err) - return err; - - exthdrlen = (ipc6->opt ? ipc6->opt->opt_flen : 0); - length += exthdrlen; - transhdrlen += exthdrlen; - } else { - fl6 = &inet->cork.fl.u.ip6; - transhdrlen = 0; - } - - return __ip6_append_data(sk, fl6, &sk->sk_write_queue, &inet->cork.base, - &np->cork, sk_page_frag(sk), getfrag, - from, length, transhdrlen, flags, ipc6, sockc); -} -EXPORT_SYMBOL_GPL(ip6_append_data); - -static void ip6_cork_release(struct inet_cork_full *cork, - struct inet6_cork *v6_cork) -{ - if (v6_cork->opt) { - kfree(v6_cork->opt->dst0opt); - kfree(v6_cork->opt->dst1opt); - kfree(v6_cork->opt->hopopt); - kfree(v6_cork->opt->srcrt); - kfree(v6_cork->opt); - v6_cork->opt = NULL; - } - - if (cork->base.dst) { - dst_release(cork->base.dst); - cork->base.dst = NULL; - cork->base.flags &= ~IPCORK_ALLFRAG; - } - memset(&cork->fl, 0, sizeof(cork->fl)); -} - -struct sk_buff *__ip6_make_skb(struct sock *sk, - struct sk_buff_head *queue, - struct inet_cork_full *cork, - struct inet6_cork *v6_cork) -{ - struct sk_buff *skb, *tmp_skb; - struct sk_buff **tail_skb; - struct in6_addr final_dst_buf, *final_dst = &final_dst_buf; - struct ipv6_pinfo *np = inet6_sk(sk); - struct net *net = sock_net(sk); - struct ipv6hdr *hdr; - struct ipv6_txoptions *opt = v6_cork->opt; - struct rt6_info *rt = (struct rt6_info *)cork->base.dst; - struct flowi6 *fl6 = &cork->fl.u.ip6; - unsigned char proto = fl6->flowi6_proto; - - skb = __skb_dequeue(queue); - if (!skb) - goto out; - tail_skb = &(skb_shinfo(skb)->frag_list); - - /* move skb->data to ip header from ext header */ - if (skb->data < skb_network_header(skb)) - __skb_pull(skb, skb_network_offset(skb)); - while ((tmp_skb = __skb_dequeue(queue)) != NULL) { - __skb_pull(tmp_skb, skb_network_header_len(skb)); - *tail_skb = tmp_skb; - tail_skb = &(tmp_skb->next); - skb->len += tmp_skb->len; - skb->data_len += tmp_skb->len; - skb->truesize += tmp_skb->truesize; - tmp_skb->destructor = NULL; - tmp_skb->sk = NULL; - } - - /* Allow local fragmentation. */ - skb->ignore_df = ip6_sk_ignore_df(sk); - - *final_dst = fl6->daddr; - __skb_pull(skb, skb_network_header_len(skb)); - if (opt && opt->opt_flen) - ipv6_push_frag_opts(skb, opt, &proto); - if (opt && opt->opt_nflen) - ipv6_push_nfrag_opts(skb, opt, &proto, &final_dst); - - skb_push(skb, sizeof(struct ipv6hdr)); - skb_reset_network_header(skb); - hdr = ipv6_hdr(skb); - - ip6_flow_hdr(hdr, v6_cork->tclass, - ip6_make_flowlabel(net, skb, fl6->flowlabel, - np->autoflowlabel, fl6)); - hdr->hop_limit = v6_cork->hop_limit; - hdr->nexthdr = proto; - hdr->saddr = fl6->saddr; - hdr->daddr = *final_dst; - - skb->priority = sk->sk_priority; - skb->mark = sk->sk_mark; - - skb_dst_set(skb, dst_clone(&rt->dst)); - IP6_UPD_PO_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len); - if (proto == IPPROTO_ICMPV6) { - struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb)); - - ICMP6MSGOUT_INC_STATS(net, idev, icmp6_hdr(skb)->icmp6_type); - ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); - } - - ip6_cork_release(cork, v6_cork); -out: - return skb; -} - -int ip6_send_skb(struct sk_buff *skb) -{ - struct net *net = sock_net(skb->sk); - struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); - int err; - - err = ip6_local_out(net, skb->sk, skb); - if (err) { - if (err > 0) - err = net_xmit_errno(err); - if (err) - IP6_INC_STATS(net, rt->rt6i_idev, - IPSTATS_MIB_OUTDISCARDS); - } - - return err; -} - -int ip6_push_pending_frames(struct sock *sk) -{ - struct sk_buff *skb; - - skb = ip6_finish_skb(sk); - if (!skb) - return 0; - - return ip6_send_skb(skb); -} -EXPORT_SYMBOL_GPL(ip6_push_pending_frames); - -static void __ip6_flush_pending_frames(struct sock *sk, - struct sk_buff_head *queue, - struct inet_cork_full *cork, - struct inet6_cork *v6_cork) -{ - struct sk_buff *skb; - - while ((skb = __skb_dequeue_tail(queue)) != NULL) { - if (skb_dst(skb)) - IP6_INC_STATS(sock_net(sk), ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_OUTDISCARDS); - kfree_skb(skb); - } - - ip6_cork_release(cork, v6_cork); -} - -void ip6_flush_pending_frames(struct sock *sk) -{ - __ip6_flush_pending_frames(sk, &sk->sk_write_queue, - &inet_sk(sk)->cork, &inet6_sk(sk)->cork); -} -EXPORT_SYMBOL_GPL(ip6_flush_pending_frames); - -struct sk_buff *ip6_make_skb(struct sock *sk, - int getfrag(void *from, char *to, int offset, - int len, int odd, struct sk_buff *skb), - void *from, int length, int transhdrlen, - struct ipcm6_cookie *ipc6, struct flowi6 *fl6, - struct rt6_info *rt, unsigned int flags, - const struct sockcm_cookie *sockc) -{ - struct inet_cork_full cork; - struct inet6_cork v6_cork; - struct sk_buff_head queue; - int exthdrlen = (ipc6->opt ? ipc6->opt->opt_flen : 0); - int err; - - if (flags & MSG_PROBE) - return NULL; - - __skb_queue_head_init(&queue); - - cork.base.flags = 0; - cork.base.addr = 0; - cork.base.opt = NULL; - v6_cork.opt = NULL; - err = ip6_setup_cork(sk, &cork, &v6_cork, ipc6, rt, fl6); - if (err) - return ERR_PTR(err); - - if (ipc6->dontfrag < 0) - ipc6->dontfrag = inet6_sk(sk)->dontfrag; - - err = __ip6_append_data(sk, fl6, &queue, &cork.base, &v6_cork, - ¤t->task_frag, getfrag, from, - length + exthdrlen, transhdrlen + exthdrlen, - flags, ipc6, sockc); - if (err) { - __ip6_flush_pending_frames(sk, &queue, &cork, &v6_cork); - return ERR_PTR(err); - } - - return __ip6_make_skb(sk, &queue, &cork, &v6_cork); -} diff --git a/src/linux/net/ipv6/ipv6_sockglue.c b/src/linux/net/ipv6/ipv6_sockglue.c deleted file mode 100644 index 636ec56..0000000 --- a/src/linux/net/ipv6/ipv6_sockglue.c +++ /dev/null @@ -1,1398 +0,0 @@ -/* - * IPv6 BSD socket options interface - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * Based on linux/net/ipv4/ip_sockglue.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * FIXME: Make the setsockopt code POSIX compliant: That is - * - * o Truncate getsockopt returns - * o Return an optlen of the truncated length if need be - * - * Changes: - * David L Stevens : - * - added multicast source filtering API for MLDv2 - */ - -#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 -#include - -#include - -struct ip6_ra_chain *ip6_ra_chain; -DEFINE_RWLOCK(ip6_ra_lock); - -int ip6_ra_control(struct sock *sk, int sel) -{ - struct ip6_ra_chain *ra, *new_ra, **rap; - - /* RA packet may be delivered ONLY to IPPROTO_RAW socket */ - if (sk->sk_type != SOCK_RAW || inet_sk(sk)->inet_num != IPPROTO_RAW) - return -ENOPROTOOPT; - - new_ra = (sel >= 0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; - - write_lock_bh(&ip6_ra_lock); - for (rap = &ip6_ra_chain; (ra = *rap) != NULL; rap = &ra->next) { - if (ra->sk == sk) { - if (sel >= 0) { - write_unlock_bh(&ip6_ra_lock); - kfree(new_ra); - return -EADDRINUSE; - } - - *rap = ra->next; - write_unlock_bh(&ip6_ra_lock); - - sock_put(sk); - kfree(ra); - return 0; - } - } - if (!new_ra) { - write_unlock_bh(&ip6_ra_lock); - return -ENOBUFS; - } - new_ra->sk = sk; - new_ra->sel = sel; - new_ra->next = ra; - *rap = new_ra; - sock_hold(sk); - write_unlock_bh(&ip6_ra_lock); - return 0; -} - -struct ipv6_txoptions *ipv6_update_options(struct sock *sk, - struct ipv6_txoptions *opt) -{ - if (inet_sk(sk)->is_icsk) { - if (opt && - !((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) && - inet_sk(sk)->inet_daddr != LOOPBACK4_IPV6) { - struct inet_connection_sock *icsk = inet_csk(sk); - icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen; - icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie); - } - } - opt = xchg((__force struct ipv6_txoptions **)&inet6_sk(sk)->opt, - opt); - sk_dst_reset(sk); - - return opt; -} - -static bool setsockopt_needs_rtnl(int optname) -{ - switch (optname) { - case IPV6_ADDRFORM: - case IPV6_ADD_MEMBERSHIP: - case IPV6_DROP_MEMBERSHIP: - case IPV6_JOIN_ANYCAST: - case IPV6_LEAVE_ANYCAST: - case MCAST_JOIN_GROUP: - case MCAST_LEAVE_GROUP: - case MCAST_JOIN_SOURCE_GROUP: - case MCAST_LEAVE_SOURCE_GROUP: - case MCAST_BLOCK_SOURCE: - case MCAST_UNBLOCK_SOURCE: - case MCAST_MSFILTER: - return true; - } - return false; -} - -static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct net *net = sock_net(sk); - int val, valbool; - int retv = -ENOPROTOOPT; - bool needs_rtnl = setsockopt_needs_rtnl(optname); - - if (!optval) - val = 0; - else { - if (optlen >= sizeof(int)) { - if (get_user(val, (int __user *) optval)) - return -EFAULT; - } else - val = 0; - } - - valbool = (val != 0); - - if (ip6_mroute_opt(optname)) - return ip6_mroute_setsockopt(sk, optname, optval, optlen); - - if (needs_rtnl) - rtnl_lock(); - lock_sock(sk); - - switch (optname) { - - case IPV6_ADDRFORM: - if (optlen < sizeof(int)) - goto e_inval; - if (val == PF_INET) { - struct ipv6_txoptions *opt; - struct sk_buff *pktopt; - - if (sk->sk_type == SOCK_RAW) - break; - - if (sk->sk_protocol == IPPROTO_UDP || - sk->sk_protocol == IPPROTO_UDPLITE) { - struct udp_sock *up = udp_sk(sk); - if (up->pending == AF_INET6) { - retv = -EBUSY; - break; - } - } else if (sk->sk_protocol != IPPROTO_TCP) - break; - - if (sk->sk_state != TCP_ESTABLISHED) { - retv = -ENOTCONN; - break; - } - - if (ipv6_only_sock(sk) || - !ipv6_addr_v4mapped(&sk->sk_v6_daddr)) { - retv = -EADDRNOTAVAIL; - break; - } - - fl6_free_socklist(sk); - __ipv6_sock_mc_close(sk); - - /* - * Sock is moving from IPv6 to IPv4 (sk_prot), so - * remove it from the refcnt debug socks count in the - * original family... - */ - sk_refcnt_debug_dec(sk); - - if (sk->sk_protocol == IPPROTO_TCP) { - struct inet_connection_sock *icsk = inet_csk(sk); - local_bh_disable(); - sock_prot_inuse_add(net, sk->sk_prot, -1); - sock_prot_inuse_add(net, &tcp_prot, 1); - local_bh_enable(); - sk->sk_prot = &tcp_prot; - icsk->icsk_af_ops = &ipv4_specific; - sk->sk_socket->ops = &inet_stream_ops; - sk->sk_family = PF_INET; - tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); - } else { - struct proto *prot = &udp_prot; - - if (sk->sk_protocol == IPPROTO_UDPLITE) - prot = &udplite_prot; - local_bh_disable(); - sock_prot_inuse_add(net, sk->sk_prot, -1); - sock_prot_inuse_add(net, prot, 1); - local_bh_enable(); - sk->sk_prot = prot; - sk->sk_socket->ops = &inet_dgram_ops; - sk->sk_family = PF_INET; - } - opt = xchg((__force struct ipv6_txoptions **)&np->opt, - NULL); - if (opt) { - atomic_sub(opt->tot_len, &sk->sk_omem_alloc); - txopt_put(opt); - } - pktopt = xchg(&np->pktoptions, NULL); - kfree_skb(pktopt); - - sk->sk_destruct = inet_sock_destruct; - /* - * ... and add it to the refcnt debug socks count - * in the new family. -acme - */ - sk_refcnt_debug_inc(sk); - module_put(THIS_MODULE); - retv = 0; - break; - } - goto e_inval; - - case IPV6_V6ONLY: - if (optlen < sizeof(int) || - inet_sk(sk)->inet_num) - goto e_inval; - sk->sk_ipv6only = valbool; - retv = 0; - break; - - case IPV6_RECVPKTINFO: - if (optlen < sizeof(int)) - goto e_inval; - np->rxopt.bits.rxinfo = valbool; - retv = 0; - break; - - case IPV6_2292PKTINFO: - if (optlen < sizeof(int)) - goto e_inval; - np->rxopt.bits.rxoinfo = valbool; - retv = 0; - break; - - case IPV6_RECVHOPLIMIT: - if (optlen < sizeof(int)) - goto e_inval; - np->rxopt.bits.rxhlim = valbool; - retv = 0; - break; - - case IPV6_2292HOPLIMIT: - if (optlen < sizeof(int)) - goto e_inval; - np->rxopt.bits.rxohlim = valbool; - retv = 0; - break; - - case IPV6_RECVRTHDR: - if (optlen < sizeof(int)) - goto e_inval; - np->rxopt.bits.srcrt = valbool; - retv = 0; - break; - - case IPV6_2292RTHDR: - if (optlen < sizeof(int)) - goto e_inval; - np->rxopt.bits.osrcrt = valbool; - retv = 0; - break; - - case IPV6_RECVHOPOPTS: - if (optlen < sizeof(int)) - goto e_inval; - np->rxopt.bits.hopopts = valbool; - retv = 0; - break; - - case IPV6_2292HOPOPTS: - if (optlen < sizeof(int)) - goto e_inval; - np->rxopt.bits.ohopopts = valbool; - retv = 0; - break; - - case IPV6_RECVDSTOPTS: - if (optlen < sizeof(int)) - goto e_inval; - np->rxopt.bits.dstopts = valbool; - retv = 0; - break; - - case IPV6_2292DSTOPTS: - if (optlen < sizeof(int)) - goto e_inval; - np->rxopt.bits.odstopts = valbool; - retv = 0; - break; - - case IPV6_TCLASS: - if (optlen < sizeof(int)) - goto e_inval; - if (val < -1 || val > 0xff) - goto e_inval; - /* RFC 3542, 6.5: default traffic class of 0x0 */ - if (val == -1) - val = 0; - np->tclass = val; - retv = 0; - break; - - case IPV6_RECVTCLASS: - if (optlen < sizeof(int)) - goto e_inval; - np->rxopt.bits.rxtclass = valbool; - retv = 0; - break; - - case IPV6_FLOWINFO: - if (optlen < sizeof(int)) - goto e_inval; - np->rxopt.bits.rxflow = valbool; - retv = 0; - break; - - case IPV6_RECVPATHMTU: - if (optlen < sizeof(int)) - goto e_inval; - np->rxopt.bits.rxpmtu = valbool; - retv = 0; - break; - - case IPV6_TRANSPARENT: - if (valbool && !ns_capable(net->user_ns, CAP_NET_ADMIN) && - !ns_capable(net->user_ns, CAP_NET_RAW)) { - retv = -EPERM; - break; - } - if (optlen < sizeof(int)) - goto e_inval; - /* we don't have a separate transparent bit for IPV6 we use the one in the IPv4 socket */ - inet_sk(sk)->transparent = valbool; - retv = 0; - break; - - case IPV6_RECVORIGDSTADDR: - if (optlen < sizeof(int)) - goto e_inval; - np->rxopt.bits.rxorigdstaddr = valbool; - retv = 0; - break; - - case IPV6_HOPOPTS: - case IPV6_RTHDRDSTOPTS: - case IPV6_RTHDR: - case IPV6_DSTOPTS: - { - struct ipv6_txoptions *opt; - - /* remove any sticky options header with a zero option - * length, per RFC3542. - */ - if (optlen == 0) - optval = NULL; - else if (!optval) - goto e_inval; - else if (optlen < sizeof(struct ipv6_opt_hdr) || - optlen & 0x7 || optlen > 8 * 255) - goto e_inval; - - /* hop-by-hop / destination options are privileged option */ - retv = -EPERM; - if (optname != IPV6_RTHDR && !ns_capable(net->user_ns, CAP_NET_RAW)) - break; - - opt = rcu_dereference_protected(np->opt, - lockdep_sock_is_held(sk)); - opt = ipv6_renew_options(sk, opt, optname, - (struct ipv6_opt_hdr __user *)optval, - optlen); - if (IS_ERR(opt)) { - retv = PTR_ERR(opt); - break; - } - - /* routing header option needs extra check */ - retv = -EINVAL; - if (optname == IPV6_RTHDR && opt && opt->srcrt) { - struct ipv6_rt_hdr *rthdr = opt->srcrt; - switch (rthdr->type) { -#if IS_ENABLED(CONFIG_IPV6_MIP6) - case IPV6_SRCRT_TYPE_2: - if (rthdr->hdrlen != 2 || - rthdr->segments_left != 1) - goto sticky_done; - - break; -#endif - default: - goto sticky_done; - } - } - - retv = 0; - opt = ipv6_update_options(sk, opt); -sticky_done: - if (opt) { - atomic_sub(opt->tot_len, &sk->sk_omem_alloc); - txopt_put(opt); - } - break; - } - - case IPV6_PKTINFO: - { - struct in6_pktinfo pkt; - - if (optlen == 0) - goto e_inval; - else if (optlen < sizeof(struct in6_pktinfo) || !optval) - goto e_inval; - - if (copy_from_user(&pkt, optval, sizeof(struct in6_pktinfo))) { - retv = -EFAULT; - break; - } - if (sk->sk_bound_dev_if && pkt.ipi6_ifindex != sk->sk_bound_dev_if) - goto e_inval; - - np->sticky_pktinfo.ipi6_ifindex = pkt.ipi6_ifindex; - np->sticky_pktinfo.ipi6_addr = pkt.ipi6_addr; - retv = 0; - break; - } - - case IPV6_2292PKTOPTIONS: - { - struct ipv6_txoptions *opt = NULL; - struct msghdr msg; - struct flowi6 fl6; - struct sockcm_cookie sockc_junk; - struct ipcm6_cookie ipc6; - - memset(&fl6, 0, sizeof(fl6)); - fl6.flowi6_oif = sk->sk_bound_dev_if; - fl6.flowi6_mark = sk->sk_mark; - - if (optlen == 0) - goto update; - - /* 1K is probably excessive - * 1K is surely not enough, 2K per standard header is 16K. - */ - retv = -EINVAL; - if (optlen > 64*1024) - break; - - opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL); - retv = -ENOBUFS; - if (!opt) - break; - - memset(opt, 0, sizeof(*opt)); - atomic_set(&opt->refcnt, 1); - opt->tot_len = sizeof(*opt) + optlen; - retv = -EFAULT; - if (copy_from_user(opt+1, optval, optlen)) - goto done; - - msg.msg_controllen = optlen; - msg.msg_control = (void *)(opt+1); - ipc6.opt = opt; - - retv = ip6_datagram_send_ctl(net, sk, &msg, &fl6, &ipc6, &sockc_junk); - if (retv) - goto done; -update: - retv = 0; - opt = ipv6_update_options(sk, opt); -done: - if (opt) { - atomic_sub(opt->tot_len, &sk->sk_omem_alloc); - txopt_put(opt); - } - break; - } - case IPV6_UNICAST_HOPS: - if (optlen < sizeof(int)) - goto e_inval; - if (val > 255 || val < -1) - goto e_inval; - np->hop_limit = val; - retv = 0; - break; - - case IPV6_MULTICAST_HOPS: - if (sk->sk_type == SOCK_STREAM) - break; - if (optlen < sizeof(int)) - goto e_inval; - if (val > 255 || val < -1) - goto e_inval; - np->mcast_hops = (val == -1 ? IPV6_DEFAULT_MCASTHOPS : val); - retv = 0; - break; - - case IPV6_MULTICAST_LOOP: - if (optlen < sizeof(int)) - goto e_inval; - if (val != valbool) - goto e_inval; - np->mc_loop = valbool; - retv = 0; - break; - - case IPV6_UNICAST_IF: - { - struct net_device *dev = NULL; - int ifindex; - - if (optlen != sizeof(int)) - goto e_inval; - - ifindex = (__force int)ntohl((__force __be32)val); - if (ifindex == 0) { - np->ucast_oif = 0; - retv = 0; - break; - } - - dev = dev_get_by_index(net, ifindex); - retv = -EADDRNOTAVAIL; - if (!dev) - break; - dev_put(dev); - - retv = -EINVAL; - if (sk->sk_bound_dev_if) - break; - - np->ucast_oif = ifindex; - retv = 0; - break; - } - - case IPV6_MULTICAST_IF: - if (sk->sk_type == SOCK_STREAM) - break; - if (optlen < sizeof(int)) - goto e_inval; - - if (val) { - struct net_device *dev; - - if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val) - goto e_inval; - - dev = dev_get_by_index(net, val); - if (!dev) { - retv = -ENODEV; - break; - } - dev_put(dev); - } - np->mcast_oif = val; - retv = 0; - break; - case IPV6_ADD_MEMBERSHIP: - case IPV6_DROP_MEMBERSHIP: - { - struct ipv6_mreq mreq; - - if (optlen < sizeof(struct ipv6_mreq)) - goto e_inval; - - retv = -EPROTO; - if (inet_sk(sk)->is_icsk) - break; - - retv = -EFAULT; - if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq))) - break; - - if (optname == IPV6_ADD_MEMBERSHIP) - retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr); - else - retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr); - break; - } - case IPV6_JOIN_ANYCAST: - case IPV6_LEAVE_ANYCAST: - { - struct ipv6_mreq mreq; - - if (optlen < sizeof(struct ipv6_mreq)) - goto e_inval; - - retv = -EFAULT; - if (copy_from_user(&mreq, optval, sizeof(struct ipv6_mreq))) - break; - - if (optname == IPV6_JOIN_ANYCAST) - retv = ipv6_sock_ac_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr); - else - retv = ipv6_sock_ac_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_acaddr); - break; - } - case MCAST_JOIN_GROUP: - case MCAST_LEAVE_GROUP: - { - struct group_req greq; - struct sockaddr_in6 *psin6; - - if (optlen < sizeof(struct group_req)) - goto e_inval; - - retv = -EFAULT; - if (copy_from_user(&greq, optval, sizeof(struct group_req))) - break; - if (greq.gr_group.ss_family != AF_INET6) { - retv = -EADDRNOTAVAIL; - break; - } - psin6 = (struct sockaddr_in6 *)&greq.gr_group; - if (optname == MCAST_JOIN_GROUP) - retv = ipv6_sock_mc_join(sk, greq.gr_interface, - &psin6->sin6_addr); - else - retv = ipv6_sock_mc_drop(sk, greq.gr_interface, - &psin6->sin6_addr); - break; - } - case MCAST_JOIN_SOURCE_GROUP: - case MCAST_LEAVE_SOURCE_GROUP: - case MCAST_BLOCK_SOURCE: - case MCAST_UNBLOCK_SOURCE: - { - struct group_source_req greqs; - int omode, add; - - if (optlen < sizeof(struct group_source_req)) - goto e_inval; - if (copy_from_user(&greqs, optval, sizeof(greqs))) { - retv = -EFAULT; - break; - } - if (greqs.gsr_group.ss_family != AF_INET6 || - greqs.gsr_source.ss_family != AF_INET6) { - retv = -EADDRNOTAVAIL; - break; - } - if (optname == MCAST_BLOCK_SOURCE) { - omode = MCAST_EXCLUDE; - add = 1; - } else if (optname == MCAST_UNBLOCK_SOURCE) { - omode = MCAST_EXCLUDE; - add = 0; - } else if (optname == MCAST_JOIN_SOURCE_GROUP) { - struct sockaddr_in6 *psin6; - - psin6 = (struct sockaddr_in6 *)&greqs.gsr_group; - retv = ipv6_sock_mc_join(sk, greqs.gsr_interface, - &psin6->sin6_addr); - /* prior join w/ different source is ok */ - if (retv && retv != -EADDRINUSE) - break; - omode = MCAST_INCLUDE; - add = 1; - } else /* MCAST_LEAVE_SOURCE_GROUP */ { - omode = MCAST_INCLUDE; - add = 0; - } - retv = ip6_mc_source(add, omode, sk, &greqs); - break; - } - case MCAST_MSFILTER: - { - struct group_filter *gsf; - - if (optlen < GROUP_FILTER_SIZE(0)) - goto e_inval; - if (optlen > sysctl_optmem_max) { - retv = -ENOBUFS; - break; - } - gsf = kmalloc(optlen, GFP_KERNEL); - if (!gsf) { - retv = -ENOBUFS; - break; - } - retv = -EFAULT; - if (copy_from_user(gsf, optval, optlen)) { - kfree(gsf); - break; - } - /* numsrc >= (4G-140)/128 overflow in 32 bits */ - if (gsf->gf_numsrc >= 0x1ffffffU || - gsf->gf_numsrc > sysctl_mld_max_msf) { - kfree(gsf); - retv = -ENOBUFS; - break; - } - if (GROUP_FILTER_SIZE(gsf->gf_numsrc) > optlen) { - kfree(gsf); - retv = -EINVAL; - break; - } - retv = ip6_mc_msfilter(sk, gsf); - kfree(gsf); - - break; - } - case IPV6_ROUTER_ALERT: - if (optlen < sizeof(int)) - goto e_inval; - retv = ip6_ra_control(sk, val); - break; - case IPV6_MTU_DISCOVER: - if (optlen < sizeof(int)) - goto e_inval; - if (val < IPV6_PMTUDISC_DONT || val > IPV6_PMTUDISC_OMIT) - goto e_inval; - np->pmtudisc = val; - retv = 0; - break; - case IPV6_MTU: - if (optlen < sizeof(int)) - goto e_inval; - if (val && val < IPV6_MIN_MTU) - goto e_inval; - np->frag_size = val; - retv = 0; - break; - case IPV6_RECVERR: - if (optlen < sizeof(int)) - goto e_inval; - np->recverr = valbool; - if (!val) - skb_queue_purge(&sk->sk_error_queue); - retv = 0; - break; - case IPV6_FLOWINFO_SEND: - if (optlen < sizeof(int)) - goto e_inval; - np->sndflow = valbool; - retv = 0; - break; - case IPV6_FLOWLABEL_MGR: - retv = ipv6_flowlabel_opt(sk, optval, optlen); - break; - case IPV6_IPSEC_POLICY: - case IPV6_XFRM_POLICY: - retv = -EPERM; - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - break; - retv = xfrm_user_policy(sk, optname, optval, optlen); - break; - - case IPV6_ADDR_PREFERENCES: - { - unsigned int pref = 0; - unsigned int prefmask = ~0; - - if (optlen < sizeof(int)) - goto e_inval; - - retv = -EINVAL; - - /* check PUBLIC/TMP/PUBTMP_DEFAULT conflicts */ - switch (val & (IPV6_PREFER_SRC_PUBLIC| - IPV6_PREFER_SRC_TMP| - IPV6_PREFER_SRC_PUBTMP_DEFAULT)) { - case IPV6_PREFER_SRC_PUBLIC: - pref |= IPV6_PREFER_SRC_PUBLIC; - break; - case IPV6_PREFER_SRC_TMP: - pref |= IPV6_PREFER_SRC_TMP; - break; - case IPV6_PREFER_SRC_PUBTMP_DEFAULT: - break; - case 0: - goto pref_skip_pubtmp; - default: - goto e_inval; - } - - prefmask &= ~(IPV6_PREFER_SRC_PUBLIC| - IPV6_PREFER_SRC_TMP); -pref_skip_pubtmp: - - /* check HOME/COA conflicts */ - switch (val & (IPV6_PREFER_SRC_HOME|IPV6_PREFER_SRC_COA)) { - case IPV6_PREFER_SRC_HOME: - break; - case IPV6_PREFER_SRC_COA: - pref |= IPV6_PREFER_SRC_COA; - case 0: - goto pref_skip_coa; - default: - goto e_inval; - } - - prefmask &= ~IPV6_PREFER_SRC_COA; -pref_skip_coa: - - /* check CGA/NONCGA conflicts */ - switch (val & (IPV6_PREFER_SRC_CGA|IPV6_PREFER_SRC_NONCGA)) { - case IPV6_PREFER_SRC_CGA: - case IPV6_PREFER_SRC_NONCGA: - case 0: - break; - default: - goto e_inval; - } - - np->srcprefs = (np->srcprefs & prefmask) | pref; - retv = 0; - - break; - } - case IPV6_MINHOPCOUNT: - if (optlen < sizeof(int)) - goto e_inval; - if (val < 0 || val > 255) - goto e_inval; - np->min_hopcount = val; - retv = 0; - break; - case IPV6_DONTFRAG: - np->dontfrag = valbool; - retv = 0; - break; - case IPV6_AUTOFLOWLABEL: - np->autoflowlabel = valbool; - retv = 0; - break; - } - - release_sock(sk); - if (needs_rtnl) - rtnl_unlock(); - - return retv; - -e_inval: - release_sock(sk); - if (needs_rtnl) - rtnl_unlock(); - return -EINVAL; -} - -int ipv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen) -{ - int err; - - if (level == SOL_IP && sk->sk_type != SOCK_RAW) - return udp_prot.setsockopt(sk, level, optname, optval, optlen); - - if (level != SOL_IPV6) - return -ENOPROTOOPT; - - err = do_ipv6_setsockopt(sk, level, optname, optval, optlen); -#ifdef CONFIG_NETFILTER - /* we need to exclude all possible ENOPROTOOPTs except default case */ - if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY && - optname != IPV6_XFRM_POLICY) { - lock_sock(sk); - err = nf_setsockopt(sk, PF_INET6, optname, optval, - optlen); - release_sock(sk); - } -#endif - return err; -} -EXPORT_SYMBOL(ipv6_setsockopt); - -#ifdef CONFIG_COMPAT -int compat_ipv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen) -{ - int err; - - if (level == SOL_IP && sk->sk_type != SOCK_RAW) { - if (udp_prot.compat_setsockopt != NULL) - return udp_prot.compat_setsockopt(sk, level, optname, - optval, optlen); - return udp_prot.setsockopt(sk, level, optname, optval, optlen); - } - - if (level != SOL_IPV6) - return -ENOPROTOOPT; - - if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER) - return compat_mc_setsockopt(sk, level, optname, optval, optlen, - ipv6_setsockopt); - - err = do_ipv6_setsockopt(sk, level, optname, optval, optlen); -#ifdef CONFIG_NETFILTER - /* we need to exclude all possible ENOPROTOOPTs except default case */ - if (err == -ENOPROTOOPT && optname != IPV6_IPSEC_POLICY && - optname != IPV6_XFRM_POLICY) { - lock_sock(sk); - err = compat_nf_setsockopt(sk, PF_INET6, optname, - optval, optlen); - release_sock(sk); - } -#endif - return err; -} -EXPORT_SYMBOL(compat_ipv6_setsockopt); -#endif - -static int ipv6_getsockopt_sticky(struct sock *sk, struct ipv6_txoptions *opt, - int optname, char __user *optval, int len) -{ - struct ipv6_opt_hdr *hdr; - - if (!opt) - return 0; - - switch (optname) { - case IPV6_HOPOPTS: - hdr = opt->hopopt; - break; - case IPV6_RTHDRDSTOPTS: - hdr = opt->dst0opt; - break; - case IPV6_RTHDR: - hdr = (struct ipv6_opt_hdr *)opt->srcrt; - break; - case IPV6_DSTOPTS: - hdr = opt->dst1opt; - break; - default: - return -EINVAL; /* should not happen */ - } - - if (!hdr) - return 0; - - len = min_t(unsigned int, len, ipv6_optlen(hdr)); - if (copy_to_user(optval, hdr, len)) - return -EFAULT; - return len; -} - -static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen, unsigned int flags) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - int len; - int val; - - if (ip6_mroute_opt(optname)) - return ip6_mroute_getsockopt(sk, optname, optval, optlen); - - if (get_user(len, optlen)) - return -EFAULT; - switch (optname) { - case IPV6_ADDRFORM: - if (sk->sk_protocol != IPPROTO_UDP && - sk->sk_protocol != IPPROTO_UDPLITE && - sk->sk_protocol != IPPROTO_TCP) - return -ENOPROTOOPT; - if (sk->sk_state != TCP_ESTABLISHED) - return -ENOTCONN; - val = sk->sk_family; - break; - case MCAST_MSFILTER: - { - struct group_filter gsf; - int err; - - if (len < GROUP_FILTER_SIZE(0)) - return -EINVAL; - if (copy_from_user(&gsf, optval, GROUP_FILTER_SIZE(0))) - return -EFAULT; - if (gsf.gf_group.ss_family != AF_INET6) - return -EADDRNOTAVAIL; - lock_sock(sk); - err = ip6_mc_msfget(sk, &gsf, - (struct group_filter __user *)optval, optlen); - release_sock(sk); - return err; - } - - case IPV6_2292PKTOPTIONS: - { - struct msghdr msg; - struct sk_buff *skb; - - if (sk->sk_type != SOCK_STREAM) - return -ENOPROTOOPT; - - msg.msg_control = optval; - msg.msg_controllen = len; - msg.msg_flags = flags; - - lock_sock(sk); - skb = np->pktoptions; - if (skb) - ip6_datagram_recv_ctl(sk, &msg, skb); - release_sock(sk); - if (!skb) { - if (np->rxopt.bits.rxinfo) { - struct in6_pktinfo src_info; - src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : - np->sticky_pktinfo.ipi6_ifindex; - src_info.ipi6_addr = np->mcast_oif ? sk->sk_v6_daddr : np->sticky_pktinfo.ipi6_addr; - put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info); - } - if (np->rxopt.bits.rxhlim) { - int hlim = np->mcast_hops; - put_cmsg(&msg, SOL_IPV6, IPV6_HOPLIMIT, sizeof(hlim), &hlim); - } - if (np->rxopt.bits.rxtclass) { - int tclass = (int)ip6_tclass(np->rcv_flowinfo); - - put_cmsg(&msg, SOL_IPV6, IPV6_TCLASS, sizeof(tclass), &tclass); - } - if (np->rxopt.bits.rxoinfo) { - struct in6_pktinfo src_info; - src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : - np->sticky_pktinfo.ipi6_ifindex; - src_info.ipi6_addr = np->mcast_oif ? sk->sk_v6_daddr : - np->sticky_pktinfo.ipi6_addr; - put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info); - } - if (np->rxopt.bits.rxohlim) { - int hlim = np->mcast_hops; - put_cmsg(&msg, SOL_IPV6, IPV6_2292HOPLIMIT, sizeof(hlim), &hlim); - } - if (np->rxopt.bits.rxflow) { - __be32 flowinfo = np->rcv_flowinfo; - - put_cmsg(&msg, SOL_IPV6, IPV6_FLOWINFO, sizeof(flowinfo), &flowinfo); - } - } - len -= msg.msg_controllen; - return put_user(len, optlen); - } - case IPV6_MTU: - { - struct dst_entry *dst; - - val = 0; - rcu_read_lock(); - dst = __sk_dst_get(sk); - if (dst) - val = dst_mtu(dst); - rcu_read_unlock(); - if (!val) - return -ENOTCONN; - break; - } - - case IPV6_V6ONLY: - val = sk->sk_ipv6only; - break; - - case IPV6_RECVPKTINFO: - val = np->rxopt.bits.rxinfo; - break; - - case IPV6_2292PKTINFO: - val = np->rxopt.bits.rxoinfo; - break; - - case IPV6_RECVHOPLIMIT: - val = np->rxopt.bits.rxhlim; - break; - - case IPV6_2292HOPLIMIT: - val = np->rxopt.bits.rxohlim; - break; - - case IPV6_RECVRTHDR: - val = np->rxopt.bits.srcrt; - break; - - case IPV6_2292RTHDR: - val = np->rxopt.bits.osrcrt; - break; - - case IPV6_HOPOPTS: - case IPV6_RTHDRDSTOPTS: - case IPV6_RTHDR: - case IPV6_DSTOPTS: - { - struct ipv6_txoptions *opt; - - lock_sock(sk); - opt = rcu_dereference_protected(np->opt, - lockdep_sock_is_held(sk)); - len = ipv6_getsockopt_sticky(sk, opt, optname, optval, len); - release_sock(sk); - /* check if ipv6_getsockopt_sticky() returns err code */ - if (len < 0) - return len; - return put_user(len, optlen); - } - - case IPV6_RECVHOPOPTS: - val = np->rxopt.bits.hopopts; - break; - - case IPV6_2292HOPOPTS: - val = np->rxopt.bits.ohopopts; - break; - - case IPV6_RECVDSTOPTS: - val = np->rxopt.bits.dstopts; - break; - - case IPV6_2292DSTOPTS: - val = np->rxopt.bits.odstopts; - break; - - case IPV6_TCLASS: - val = np->tclass; - break; - - case IPV6_RECVTCLASS: - val = np->rxopt.bits.rxtclass; - break; - - case IPV6_FLOWINFO: - val = np->rxopt.bits.rxflow; - break; - - case IPV6_RECVPATHMTU: - val = np->rxopt.bits.rxpmtu; - break; - - case IPV6_PATHMTU: - { - struct dst_entry *dst; - struct ip6_mtuinfo mtuinfo; - - if (len < sizeof(mtuinfo)) - return -EINVAL; - - len = sizeof(mtuinfo); - memset(&mtuinfo, 0, sizeof(mtuinfo)); - - rcu_read_lock(); - dst = __sk_dst_get(sk); - if (dst) - mtuinfo.ip6m_mtu = dst_mtu(dst); - rcu_read_unlock(); - if (!mtuinfo.ip6m_mtu) - return -ENOTCONN; - - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(optval, &mtuinfo, len)) - return -EFAULT; - - return 0; - } - - case IPV6_TRANSPARENT: - val = inet_sk(sk)->transparent; - break; - - case IPV6_RECVORIGDSTADDR: - val = np->rxopt.bits.rxorigdstaddr; - break; - - case IPV6_UNICAST_HOPS: - case IPV6_MULTICAST_HOPS: - { - struct dst_entry *dst; - - if (optname == IPV6_UNICAST_HOPS) - val = np->hop_limit; - else - val = np->mcast_hops; - - if (val < 0) { - rcu_read_lock(); - dst = __sk_dst_get(sk); - if (dst) - val = ip6_dst_hoplimit(dst); - rcu_read_unlock(); - } - - if (val < 0) - val = sock_net(sk)->ipv6.devconf_all->hop_limit; - break; - } - - case IPV6_MULTICAST_LOOP: - val = np->mc_loop; - break; - - case IPV6_MULTICAST_IF: - val = np->mcast_oif; - break; - - case IPV6_UNICAST_IF: - val = (__force int)htonl((__u32) np->ucast_oif); - break; - - case IPV6_MTU_DISCOVER: - val = np->pmtudisc; - break; - - case IPV6_RECVERR: - val = np->recverr; - break; - - case IPV6_FLOWINFO_SEND: - val = np->sndflow; - break; - - case IPV6_FLOWLABEL_MGR: - { - struct in6_flowlabel_req freq; - int flags; - - if (len < sizeof(freq)) - return -EINVAL; - - if (copy_from_user(&freq, optval, sizeof(freq))) - return -EFAULT; - - if (freq.flr_action != IPV6_FL_A_GET) - return -EINVAL; - - len = sizeof(freq); - flags = freq.flr_flags; - - memset(&freq, 0, sizeof(freq)); - - val = ipv6_flowlabel_opt_get(sk, &freq, flags); - if (val < 0) - return val; - - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(optval, &freq, len)) - return -EFAULT; - - return 0; - } - - case IPV6_ADDR_PREFERENCES: - val = 0; - - if (np->srcprefs & IPV6_PREFER_SRC_TMP) - val |= IPV6_PREFER_SRC_TMP; - else if (np->srcprefs & IPV6_PREFER_SRC_PUBLIC) - val |= IPV6_PREFER_SRC_PUBLIC; - else { - /* XXX: should we return system default? */ - val |= IPV6_PREFER_SRC_PUBTMP_DEFAULT; - } - - if (np->srcprefs & IPV6_PREFER_SRC_COA) - val |= IPV6_PREFER_SRC_COA; - else - val |= IPV6_PREFER_SRC_HOME; - break; - - case IPV6_MINHOPCOUNT: - val = np->min_hopcount; - break; - - case IPV6_DONTFRAG: - val = np->dontfrag; - break; - - case IPV6_AUTOFLOWLABEL: - val = np->autoflowlabel; - break; - - default: - return -ENOPROTOOPT; - } - len = min_t(unsigned int, sizeof(int), len); - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(optval, &val, len)) - return -EFAULT; - return 0; -} - -int ipv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - int err; - - if (level == SOL_IP && sk->sk_type != SOCK_RAW) - return udp_prot.getsockopt(sk, level, optname, optval, optlen); - - if (level != SOL_IPV6) - return -ENOPROTOOPT; - - err = do_ipv6_getsockopt(sk, level, optname, optval, optlen, 0); -#ifdef CONFIG_NETFILTER - /* we need to exclude all possible ENOPROTOOPTs except default case */ - if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) { - int len; - - if (get_user(len, optlen)) - return -EFAULT; - - lock_sock(sk); - err = nf_getsockopt(sk, PF_INET6, optname, optval, - &len); - release_sock(sk); - if (err >= 0) - err = put_user(len, optlen); - } -#endif - return err; -} -EXPORT_SYMBOL(ipv6_getsockopt); - -#ifdef CONFIG_COMPAT -int compat_ipv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - int err; - - if (level == SOL_IP && sk->sk_type != SOCK_RAW) { - if (udp_prot.compat_getsockopt != NULL) - return udp_prot.compat_getsockopt(sk, level, optname, - optval, optlen); - return udp_prot.getsockopt(sk, level, optname, optval, optlen); - } - - if (level != SOL_IPV6) - return -ENOPROTOOPT; - - if (optname == MCAST_MSFILTER) - return compat_mc_getsockopt(sk, level, optname, optval, optlen, - ipv6_getsockopt); - - err = do_ipv6_getsockopt(sk, level, optname, optval, optlen, - MSG_CMSG_COMPAT); -#ifdef CONFIG_NETFILTER - /* we need to exclude all possible ENOPROTOOPTs except default case */ - if (err == -ENOPROTOOPT && optname != IPV6_2292PKTOPTIONS) { - int len; - - if (get_user(len, optlen)) - return -EFAULT; - - lock_sock(sk); - err = compat_nf_getsockopt(sk, PF_INET6, - optname, optval, &len); - release_sock(sk); - if (err >= 0) - err = put_user(len, optlen); - } -#endif - return err; -} -EXPORT_SYMBOL(compat_ipv6_getsockopt); -#endif - diff --git a/src/linux/net/ipv6/mcast.c b/src/linux/net/ipv6/mcast.c deleted file mode 100644 index 14a3903..0000000 --- a/src/linux/net/ipv6/mcast.c +++ /dev/null @@ -1,2966 +0,0 @@ -/* - * Multicast support for IPv6 - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -/* Changes: - * - * yoshfuji : fix format of router-alert option - * YOSHIFUJI Hideaki @USAGI: - * Fixed source address for MLD message based on - * . - * YOSHIFUJI Hideaki @USAGI: - * - Ignore Queries for invalid addresses. - * - MLD for link-local addresses. - * David L Stevens : - * - MLDv2 support - */ - -#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 -#include -#include -#include -#include - -#include - -/* Ensure that we have struct in6_addr aligned on 32bit word. */ -static void *__mld2_query_bugs[] __attribute__((__unused__)) = { - BUILD_BUG_ON_NULL(offsetof(struct mld2_query, mld2q_srcs) % 4), - BUILD_BUG_ON_NULL(offsetof(struct mld2_report, mld2r_grec) % 4), - BUILD_BUG_ON_NULL(offsetof(struct mld2_grec, grec_mca) % 4) -}; - -static struct in6_addr mld2_all_mcr = MLD2_ALL_MCR_INIT; - -static void igmp6_join_group(struct ifmcaddr6 *ma); -static void igmp6_leave_group(struct ifmcaddr6 *ma); -static void igmp6_timer_handler(unsigned long data); - -static void mld_gq_timer_expire(unsigned long data); -static void mld_ifc_timer_expire(unsigned long data); -static void mld_ifc_event(struct inet6_dev *idev); -static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *pmc); -static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *addr); -static void mld_clear_delrec(struct inet6_dev *idev); -static bool mld_in_v1_mode(const struct inet6_dev *idev); -static int sf_setstate(struct ifmcaddr6 *pmc); -static void sf_markstate(struct ifmcaddr6 *pmc); -static void ip6_mc_clear_src(struct ifmcaddr6 *pmc); -static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca, - int sfmode, int sfcount, const struct in6_addr *psfsrc, - int delta); -static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca, - int sfmode, int sfcount, const struct in6_addr *psfsrc, - int delta); -static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, - struct inet6_dev *idev); - -#define MLD_QRV_DEFAULT 2 -/* RFC3810, 9.2. Query Interval */ -#define MLD_QI_DEFAULT (125 * HZ) -/* RFC3810, 9.3. Query Response Interval */ -#define MLD_QRI_DEFAULT (10 * HZ) - -/* RFC3810, 8.1 Query Version Distinctions */ -#define MLD_V1_QUERY_LEN 24 -#define MLD_V2_QUERY_LEN_MIN 28 - -#define IPV6_MLD_MAX_MSF 64 - -int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF; -int sysctl_mld_qrv __read_mostly = MLD_QRV_DEFAULT; - -/* - * socket join on multicast group - */ - -#define for_each_pmc_rcu(np, pmc) \ - for (pmc = rcu_dereference(np->ipv6_mc_list); \ - pmc != NULL; \ - pmc = rcu_dereference(pmc->next)) - -static int unsolicited_report_interval(struct inet6_dev *idev) -{ - int iv; - - if (mld_in_v1_mode(idev)) - iv = idev->cnf.mldv1_unsolicited_report_interval; - else - iv = idev->cnf.mldv2_unsolicited_report_interval; - - return iv > 0 ? iv : 1; -} - -int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) -{ - struct net_device *dev = NULL; - struct ipv6_mc_socklist *mc_lst; - struct ipv6_pinfo *np = inet6_sk(sk); - struct net *net = sock_net(sk); - int err; - - ASSERT_RTNL(); - - if (!ipv6_addr_is_multicast(addr)) - return -EINVAL; - - rcu_read_lock(); - for_each_pmc_rcu(np, mc_lst) { - if ((ifindex == 0 || mc_lst->ifindex == ifindex) && - ipv6_addr_equal(&mc_lst->addr, addr)) { - rcu_read_unlock(); - return -EADDRINUSE; - } - } - rcu_read_unlock(); - - mc_lst = sock_kmalloc(sk, sizeof(struct ipv6_mc_socklist), GFP_KERNEL); - - if (!mc_lst) - return -ENOMEM; - - mc_lst->next = NULL; - mc_lst->addr = *addr; - - if (ifindex == 0) { - struct rt6_info *rt; - rt = rt6_lookup(net, addr, NULL, 0, 0); - if (rt) { - dev = rt->dst.dev; - ip6_rt_put(rt); - } - } else - dev = __dev_get_by_index(net, ifindex); - - if (!dev) { - sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); - return -ENODEV; - } - - mc_lst->ifindex = dev->ifindex; - mc_lst->sfmode = MCAST_EXCLUDE; - rwlock_init(&mc_lst->sflock); - mc_lst->sflist = NULL; - - /* - * now add/increase the group membership on the device - */ - - err = ipv6_dev_mc_inc(dev, addr); - - if (err) { - sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); - return err; - } - - mc_lst->next = np->ipv6_mc_list; - rcu_assign_pointer(np->ipv6_mc_list, mc_lst); - - return 0; -} -EXPORT_SYMBOL(ipv6_sock_mc_join); - -/* - * socket leave on multicast group - */ -int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct ipv6_mc_socklist *mc_lst; - struct ipv6_mc_socklist __rcu **lnk; - struct net *net = sock_net(sk); - - ASSERT_RTNL(); - - if (!ipv6_addr_is_multicast(addr)) - return -EINVAL; - - for (lnk = &np->ipv6_mc_list; - (mc_lst = rtnl_dereference(*lnk)) != NULL; - lnk = &mc_lst->next) { - if ((ifindex == 0 || mc_lst->ifindex == ifindex) && - ipv6_addr_equal(&mc_lst->addr, addr)) { - struct net_device *dev; - - *lnk = mc_lst->next; - - dev = __dev_get_by_index(net, mc_lst->ifindex); - if (dev) { - struct inet6_dev *idev = __in6_dev_get(dev); - - (void) ip6_mc_leave_src(sk, mc_lst, idev); - if (idev) - __ipv6_dev_mc_dec(idev, &mc_lst->addr); - } else - (void) ip6_mc_leave_src(sk, mc_lst, NULL); - - atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc); - kfree_rcu(mc_lst, rcu); - return 0; - } - } - - return -EADDRNOTAVAIL; -} -EXPORT_SYMBOL(ipv6_sock_mc_drop); - -/* called with rcu_read_lock() */ -static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net, - const struct in6_addr *group, - int ifindex) -{ - struct net_device *dev = NULL; - struct inet6_dev *idev = NULL; - - if (ifindex == 0) { - struct rt6_info *rt = rt6_lookup(net, group, NULL, 0, 0); - - if (rt) { - dev = rt->dst.dev; - ip6_rt_put(rt); - } - } else - dev = dev_get_by_index_rcu(net, ifindex); - - if (!dev) - return NULL; - idev = __in6_dev_get(dev); - if (!idev) - return NULL; - read_lock_bh(&idev->lock); - if (idev->dead) { - read_unlock_bh(&idev->lock); - return NULL; - } - return idev; -} - -void __ipv6_sock_mc_close(struct sock *sk) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct ipv6_mc_socklist *mc_lst; - struct net *net = sock_net(sk); - - ASSERT_RTNL(); - - while ((mc_lst = rtnl_dereference(np->ipv6_mc_list)) != NULL) { - struct net_device *dev; - - np->ipv6_mc_list = mc_lst->next; - - dev = __dev_get_by_index(net, mc_lst->ifindex); - if (dev) { - struct inet6_dev *idev = __in6_dev_get(dev); - - (void) ip6_mc_leave_src(sk, mc_lst, idev); - if (idev) - __ipv6_dev_mc_dec(idev, &mc_lst->addr); - } else - (void) ip6_mc_leave_src(sk, mc_lst, NULL); - - atomic_sub(sizeof(*mc_lst), &sk->sk_omem_alloc); - kfree_rcu(mc_lst, rcu); - } -} - -void ipv6_sock_mc_close(struct sock *sk) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - - if (!rcu_access_pointer(np->ipv6_mc_list)) - return; - rtnl_lock(); - __ipv6_sock_mc_close(sk); - rtnl_unlock(); -} - -int ip6_mc_source(int add, int omode, struct sock *sk, - struct group_source_req *pgsr) -{ - struct in6_addr *source, *group; - struct ipv6_mc_socklist *pmc; - struct inet6_dev *idev; - struct ipv6_pinfo *inet6 = inet6_sk(sk); - struct ip6_sf_socklist *psl; - struct net *net = sock_net(sk); - int i, j, rv; - int leavegroup = 0; - int pmclocked = 0; - int err; - - source = &((struct sockaddr_in6 *)&pgsr->gsr_source)->sin6_addr; - group = &((struct sockaddr_in6 *)&pgsr->gsr_group)->sin6_addr; - - if (!ipv6_addr_is_multicast(group)) - return -EINVAL; - - rcu_read_lock(); - idev = ip6_mc_find_dev_rcu(net, group, pgsr->gsr_interface); - if (!idev) { - rcu_read_unlock(); - return -ENODEV; - } - - err = -EADDRNOTAVAIL; - - for_each_pmc_rcu(inet6, pmc) { - if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface) - continue; - if (ipv6_addr_equal(&pmc->addr, group)) - break; - } - if (!pmc) { /* must have a prior join */ - err = -EINVAL; - goto done; - } - /* if a source filter was set, must be the same mode as before */ - if (pmc->sflist) { - if (pmc->sfmode != omode) { - err = -EINVAL; - goto done; - } - } else if (pmc->sfmode != omode) { - /* allow mode switches for empty-set filters */ - ip6_mc_add_src(idev, group, omode, 0, NULL, 0); - ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0); - pmc->sfmode = omode; - } - - write_lock(&pmc->sflock); - pmclocked = 1; - - psl = pmc->sflist; - if (!add) { - if (!psl) - goto done; /* err = -EADDRNOTAVAIL */ - rv = !0; - for (i = 0; i < psl->sl_count; i++) { - rv = !ipv6_addr_equal(&psl->sl_addr[i], source); - if (rv == 0) - break; - } - if (rv) /* source not found */ - goto done; /* err = -EADDRNOTAVAIL */ - - /* special case - (INCLUDE, empty) == LEAVE_GROUP */ - if (psl->sl_count == 1 && omode == MCAST_INCLUDE) { - leavegroup = 1; - goto done; - } - - /* update the interface filter */ - ip6_mc_del_src(idev, group, omode, 1, source, 1); - - for (j = i+1; j < psl->sl_count; j++) - psl->sl_addr[j-1] = psl->sl_addr[j]; - psl->sl_count--; - err = 0; - goto done; - } - /* else, add a new source to the filter */ - - if (psl && psl->sl_count >= sysctl_mld_max_msf) { - err = -ENOBUFS; - goto done; - } - if (!psl || psl->sl_count == psl->sl_max) { - struct ip6_sf_socklist *newpsl; - int count = IP6_SFBLOCK; - - if (psl) - count += psl->sl_max; - newpsl = sock_kmalloc(sk, IP6_SFLSIZE(count), GFP_ATOMIC); - if (!newpsl) { - err = -ENOBUFS; - goto done; - } - newpsl->sl_max = count; - newpsl->sl_count = count - IP6_SFBLOCK; - if (psl) { - for (i = 0; i < psl->sl_count; i++) - newpsl->sl_addr[i] = psl->sl_addr[i]; - sock_kfree_s(sk, psl, IP6_SFLSIZE(psl->sl_max)); - } - pmc->sflist = psl = newpsl; - } - rv = 1; /* > 0 for insert logic below if sl_count is 0 */ - for (i = 0; i < psl->sl_count; i++) { - rv = !ipv6_addr_equal(&psl->sl_addr[i], source); - if (rv == 0) /* There is an error in the address. */ - goto done; - } - for (j = psl->sl_count-1; j >= i; j--) - psl->sl_addr[j+1] = psl->sl_addr[j]; - psl->sl_addr[i] = *source; - psl->sl_count++; - err = 0; - /* update the interface list */ - ip6_mc_add_src(idev, group, omode, 1, source, 1); -done: - if (pmclocked) - write_unlock(&pmc->sflock); - read_unlock_bh(&idev->lock); - rcu_read_unlock(); - if (leavegroup) - err = ipv6_sock_mc_drop(sk, pgsr->gsr_interface, group); - return err; -} - -int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) -{ - const struct in6_addr *group; - struct ipv6_mc_socklist *pmc; - struct inet6_dev *idev; - struct ipv6_pinfo *inet6 = inet6_sk(sk); - struct ip6_sf_socklist *newpsl, *psl; - struct net *net = sock_net(sk); - int leavegroup = 0; - int i, err; - - group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr; - - if (!ipv6_addr_is_multicast(group)) - return -EINVAL; - if (gsf->gf_fmode != MCAST_INCLUDE && - gsf->gf_fmode != MCAST_EXCLUDE) - return -EINVAL; - - rcu_read_lock(); - idev = ip6_mc_find_dev_rcu(net, group, gsf->gf_interface); - - if (!idev) { - rcu_read_unlock(); - return -ENODEV; - } - - err = 0; - - if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) { - leavegroup = 1; - goto done; - } - - for_each_pmc_rcu(inet6, pmc) { - if (pmc->ifindex != gsf->gf_interface) - continue; - if (ipv6_addr_equal(&pmc->addr, group)) - break; - } - if (!pmc) { /* must have a prior join */ - err = -EINVAL; - goto done; - } - if (gsf->gf_numsrc) { - newpsl = sock_kmalloc(sk, IP6_SFLSIZE(gsf->gf_numsrc), - GFP_ATOMIC); - if (!newpsl) { - err = -ENOBUFS; - goto done; - } - newpsl->sl_max = newpsl->sl_count = gsf->gf_numsrc; - for (i = 0; i < newpsl->sl_count; ++i) { - struct sockaddr_in6 *psin6; - - psin6 = (struct sockaddr_in6 *)&gsf->gf_slist[i]; - newpsl->sl_addr[i] = psin6->sin6_addr; - } - err = ip6_mc_add_src(idev, group, gsf->gf_fmode, - newpsl->sl_count, newpsl->sl_addr, 0); - if (err) { - sock_kfree_s(sk, newpsl, IP6_SFLSIZE(newpsl->sl_max)); - goto done; - } - } else { - newpsl = NULL; - (void) ip6_mc_add_src(idev, group, gsf->gf_fmode, 0, NULL, 0); - } - - write_lock(&pmc->sflock); - psl = pmc->sflist; - if (psl) { - (void) ip6_mc_del_src(idev, group, pmc->sfmode, - psl->sl_count, psl->sl_addr, 0); - sock_kfree_s(sk, psl, IP6_SFLSIZE(psl->sl_max)); - } else - (void) ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0); - pmc->sflist = newpsl; - pmc->sfmode = gsf->gf_fmode; - write_unlock(&pmc->sflock); - err = 0; -done: - read_unlock_bh(&idev->lock); - rcu_read_unlock(); - if (leavegroup) - err = ipv6_sock_mc_drop(sk, gsf->gf_interface, group); - return err; -} - -int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf, - struct group_filter __user *optval, int __user *optlen) -{ - int err, i, count, copycount; - const struct in6_addr *group; - struct ipv6_mc_socklist *pmc; - struct inet6_dev *idev; - struct ipv6_pinfo *inet6 = inet6_sk(sk); - struct ip6_sf_socklist *psl; - struct net *net = sock_net(sk); - - group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr; - - if (!ipv6_addr_is_multicast(group)) - return -EINVAL; - - rcu_read_lock(); - idev = ip6_mc_find_dev_rcu(net, group, gsf->gf_interface); - - if (!idev) { - rcu_read_unlock(); - return -ENODEV; - } - - err = -EADDRNOTAVAIL; - /* changes to the ipv6_mc_list require the socket lock and - * rtnl lock. We have the socket lock and rcu read lock, - * so reading the list is safe. - */ - - for_each_pmc_rcu(inet6, pmc) { - if (pmc->ifindex != gsf->gf_interface) - continue; - if (ipv6_addr_equal(group, &pmc->addr)) - break; - } - if (!pmc) /* must have a prior join */ - goto done; - gsf->gf_fmode = pmc->sfmode; - psl = pmc->sflist; - count = psl ? psl->sl_count : 0; - read_unlock_bh(&idev->lock); - rcu_read_unlock(); - - copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc; - gsf->gf_numsrc = count; - if (put_user(GROUP_FILTER_SIZE(copycount), optlen) || - copy_to_user(optval, gsf, GROUP_FILTER_SIZE(0))) { - return -EFAULT; - } - /* changes to psl require the socket lock, and a write lock - * on pmc->sflock. We have the socket lock so reading here is safe. - */ - for (i = 0; i < copycount; i++) { - struct sockaddr_in6 *psin6; - struct sockaddr_storage ss; - - psin6 = (struct sockaddr_in6 *)&ss; - memset(&ss, 0, sizeof(ss)); - psin6->sin6_family = AF_INET6; - psin6->sin6_addr = psl->sl_addr[i]; - if (copy_to_user(&optval->gf_slist[i], &ss, sizeof(ss))) - return -EFAULT; - } - return 0; -done: - read_unlock_bh(&idev->lock); - rcu_read_unlock(); - return err; -} - -bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr, - const struct in6_addr *src_addr) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct ipv6_mc_socklist *mc; - struct ip6_sf_socklist *psl; - bool rv = true; - - rcu_read_lock(); - for_each_pmc_rcu(np, mc) { - if (ipv6_addr_equal(&mc->addr, mc_addr)) - break; - } - if (!mc) { - rcu_read_unlock(); - return true; - } - read_lock(&mc->sflock); - psl = mc->sflist; - if (!psl) { - rv = mc->sfmode == MCAST_EXCLUDE; - } else { - int i; - - for (i = 0; i < psl->sl_count; i++) { - if (ipv6_addr_equal(&psl->sl_addr[i], src_addr)) - break; - } - if (mc->sfmode == MCAST_INCLUDE && i >= psl->sl_count) - rv = false; - if (mc->sfmode == MCAST_EXCLUDE && i < psl->sl_count) - rv = false; - } - read_unlock(&mc->sflock); - rcu_read_unlock(); - - return rv; -} - -static void igmp6_group_added(struct ifmcaddr6 *mc) -{ - struct net_device *dev = mc->idev->dev; - char buf[MAX_ADDR_LEN]; - - if (IPV6_ADDR_MC_SCOPE(&mc->mca_addr) < - IPV6_ADDR_SCOPE_LINKLOCAL) - return; - - spin_lock_bh(&mc->mca_lock); - if (!(mc->mca_flags&MAF_LOADED)) { - mc->mca_flags |= MAF_LOADED; - if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0) - dev_mc_add(dev, buf); - } - spin_unlock_bh(&mc->mca_lock); - - if (!(dev->flags & IFF_UP) || (mc->mca_flags & MAF_NOREPORT)) - return; - - if (mld_in_v1_mode(mc->idev)) { - igmp6_join_group(mc); - return; - } - /* else v2 */ - - mc->mca_crcount = mc->idev->mc_qrv; - mld_ifc_event(mc->idev); -} - -static void igmp6_group_dropped(struct ifmcaddr6 *mc) -{ - struct net_device *dev = mc->idev->dev; - char buf[MAX_ADDR_LEN]; - - if (IPV6_ADDR_MC_SCOPE(&mc->mca_addr) < - IPV6_ADDR_SCOPE_LINKLOCAL) - return; - - spin_lock_bh(&mc->mca_lock); - if (mc->mca_flags&MAF_LOADED) { - mc->mca_flags &= ~MAF_LOADED; - if (ndisc_mc_map(&mc->mca_addr, buf, dev, 0) == 0) - dev_mc_del(dev, buf); - } - - if (mc->mca_flags & MAF_NOREPORT) - goto done; - spin_unlock_bh(&mc->mca_lock); - - if (!mc->idev->dead) - igmp6_leave_group(mc); - - spin_lock_bh(&mc->mca_lock); - if (del_timer(&mc->mca_timer)) - atomic_dec(&mc->mca_refcnt); -done: - ip6_mc_clear_src(mc); - spin_unlock_bh(&mc->mca_lock); -} - -/* - * deleted ifmcaddr6 manipulation - */ -static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im) -{ - struct ifmcaddr6 *pmc; - - /* this is an "ifmcaddr6" for convenience; only the fields below - * are actually used. In particular, the refcnt and users are not - * used for management of the delete list. Using the same structure - * for deleted items allows change reports to use common code with - * non-deleted or query-response MCA's. - */ - pmc = kzalloc(sizeof(*pmc), GFP_ATOMIC); - if (!pmc) - return; - - spin_lock_bh(&im->mca_lock); - spin_lock_init(&pmc->mca_lock); - pmc->idev = im->idev; - in6_dev_hold(idev); - pmc->mca_addr = im->mca_addr; - pmc->mca_crcount = idev->mc_qrv; - pmc->mca_sfmode = im->mca_sfmode; - if (pmc->mca_sfmode == MCAST_INCLUDE) { - struct ip6_sf_list *psf; - - pmc->mca_tomb = im->mca_tomb; - pmc->mca_sources = im->mca_sources; - im->mca_tomb = im->mca_sources = NULL; - for (psf = pmc->mca_sources; psf; psf = psf->sf_next) - psf->sf_crcount = pmc->mca_crcount; - } - spin_unlock_bh(&im->mca_lock); - - spin_lock_bh(&idev->mc_lock); - pmc->next = idev->mc_tomb; - idev->mc_tomb = pmc; - spin_unlock_bh(&idev->mc_lock); -} - -static void mld_del_delrec(struct inet6_dev *idev, const struct in6_addr *pmca) -{ - struct ifmcaddr6 *pmc, *pmc_prev; - struct ip6_sf_list *psf, *psf_next; - - spin_lock_bh(&idev->mc_lock); - pmc_prev = NULL; - for (pmc = idev->mc_tomb; pmc; pmc = pmc->next) { - if (ipv6_addr_equal(&pmc->mca_addr, pmca)) - break; - pmc_prev = pmc; - } - if (pmc) { - if (pmc_prev) - pmc_prev->next = pmc->next; - else - idev->mc_tomb = pmc->next; - } - spin_unlock_bh(&idev->mc_lock); - - if (pmc) { - for (psf = pmc->mca_tomb; psf; psf = psf_next) { - psf_next = psf->sf_next; - kfree(psf); - } - in6_dev_put(pmc->idev); - kfree(pmc); - } -} - -static void mld_clear_delrec(struct inet6_dev *idev) -{ - struct ifmcaddr6 *pmc, *nextpmc; - - spin_lock_bh(&idev->mc_lock); - pmc = idev->mc_tomb; - idev->mc_tomb = NULL; - spin_unlock_bh(&idev->mc_lock); - - for (; pmc; pmc = nextpmc) { - nextpmc = pmc->next; - ip6_mc_clear_src(pmc); - in6_dev_put(pmc->idev); - kfree(pmc); - } - - /* clear dead sources, too */ - read_lock_bh(&idev->lock); - for (pmc = idev->mc_list; pmc; pmc = pmc->next) { - struct ip6_sf_list *psf, *psf_next; - - spin_lock_bh(&pmc->mca_lock); - psf = pmc->mca_tomb; - pmc->mca_tomb = NULL; - spin_unlock_bh(&pmc->mca_lock); - for (; psf; psf = psf_next) { - psf_next = psf->sf_next; - kfree(psf); - } - } - read_unlock_bh(&idev->lock); -} - -static void mca_get(struct ifmcaddr6 *mc) -{ - atomic_inc(&mc->mca_refcnt); -} - -static void ma_put(struct ifmcaddr6 *mc) -{ - if (atomic_dec_and_test(&mc->mca_refcnt)) { - in6_dev_put(mc->idev); - kfree(mc); - } -} - -static struct ifmcaddr6 *mca_alloc(struct inet6_dev *idev, - const struct in6_addr *addr) -{ - struct ifmcaddr6 *mc; - - mc = kzalloc(sizeof(*mc), GFP_ATOMIC); - if (!mc) - return NULL; - - setup_timer(&mc->mca_timer, igmp6_timer_handler, (unsigned long)mc); - - mc->mca_addr = *addr; - mc->idev = idev; /* reference taken by caller */ - mc->mca_users = 1; - /* mca_stamp should be updated upon changes */ - mc->mca_cstamp = mc->mca_tstamp = jiffies; - atomic_set(&mc->mca_refcnt, 1); - spin_lock_init(&mc->mca_lock); - - /* initial mode is (EX, empty) */ - mc->mca_sfmode = MCAST_EXCLUDE; - mc->mca_sfcount[MCAST_EXCLUDE] = 1; - - if (ipv6_addr_is_ll_all_nodes(&mc->mca_addr) || - IPV6_ADDR_MC_SCOPE(&mc->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL) - mc->mca_flags |= MAF_NOREPORT; - - return mc; -} - -/* - * device multicast group inc (add if not found) - */ -int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr) -{ - struct ifmcaddr6 *mc; - struct inet6_dev *idev; - - ASSERT_RTNL(); - - /* we need to take a reference on idev */ - idev = in6_dev_get(dev); - - if (!idev) - return -EINVAL; - - write_lock_bh(&idev->lock); - if (idev->dead) { - write_unlock_bh(&idev->lock); - in6_dev_put(idev); - return -ENODEV; - } - - for (mc = idev->mc_list; mc; mc = mc->next) { - if (ipv6_addr_equal(&mc->mca_addr, addr)) { - mc->mca_users++; - write_unlock_bh(&idev->lock); - ip6_mc_add_src(idev, &mc->mca_addr, MCAST_EXCLUDE, 0, - NULL, 0); - in6_dev_put(idev); - return 0; - } - } - - mc = mca_alloc(idev, addr); - if (!mc) { - write_unlock_bh(&idev->lock); - in6_dev_put(idev); - return -ENOMEM; - } - - mc->next = idev->mc_list; - idev->mc_list = mc; - - /* Hold this for the code below before we unlock, - * it is already exposed via idev->mc_list. - */ - mca_get(mc); - write_unlock_bh(&idev->lock); - - mld_del_delrec(idev, &mc->mca_addr); - igmp6_group_added(mc); - ma_put(mc); - return 0; -} - -/* - * device multicast group del - */ -int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr) -{ - struct ifmcaddr6 *ma, **map; - - ASSERT_RTNL(); - - write_lock_bh(&idev->lock); - for (map = &idev->mc_list; (ma = *map) != NULL; map = &ma->next) { - if (ipv6_addr_equal(&ma->mca_addr, addr)) { - if (--ma->mca_users == 0) { - *map = ma->next; - write_unlock_bh(&idev->lock); - - igmp6_group_dropped(ma); - - ma_put(ma); - return 0; - } - write_unlock_bh(&idev->lock); - return 0; - } - } - write_unlock_bh(&idev->lock); - - return -ENOENT; -} - -int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr) -{ - struct inet6_dev *idev; - int err; - - ASSERT_RTNL(); - - idev = __in6_dev_get(dev); - if (!idev) - err = -ENODEV; - else - err = __ipv6_dev_mc_dec(idev, addr); - - return err; -} - -/* - * check if the interface/address pair is valid - */ -bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group, - const struct in6_addr *src_addr) -{ - struct inet6_dev *idev; - struct ifmcaddr6 *mc; - bool rv = false; - - rcu_read_lock(); - idev = __in6_dev_get(dev); - if (idev) { - read_lock_bh(&idev->lock); - for (mc = idev->mc_list; mc; mc = mc->next) { - if (ipv6_addr_equal(&mc->mca_addr, group)) - break; - } - if (mc) { - if (src_addr && !ipv6_addr_any(src_addr)) { - struct ip6_sf_list *psf; - - spin_lock_bh(&mc->mca_lock); - for (psf = mc->mca_sources; psf; psf = psf->sf_next) { - if (ipv6_addr_equal(&psf->sf_addr, src_addr)) - break; - } - if (psf) - rv = psf->sf_count[MCAST_INCLUDE] || - psf->sf_count[MCAST_EXCLUDE] != - mc->mca_sfcount[MCAST_EXCLUDE]; - else - rv = mc->mca_sfcount[MCAST_EXCLUDE] != 0; - spin_unlock_bh(&mc->mca_lock); - } else - rv = true; /* don't filter unspecified source */ - } - read_unlock_bh(&idev->lock); - } - rcu_read_unlock(); - return rv; -} - -static void mld_gq_start_timer(struct inet6_dev *idev) -{ - unsigned long tv = prandom_u32() % idev->mc_maxdelay; - - idev->mc_gq_running = 1; - if (!mod_timer(&idev->mc_gq_timer, jiffies+tv+2)) - in6_dev_hold(idev); -} - -static void mld_gq_stop_timer(struct inet6_dev *idev) -{ - idev->mc_gq_running = 0; - if (del_timer(&idev->mc_gq_timer)) - __in6_dev_put(idev); -} - -static void mld_ifc_start_timer(struct inet6_dev *idev, unsigned long delay) -{ - unsigned long tv = prandom_u32() % delay; - - if (!mod_timer(&idev->mc_ifc_timer, jiffies+tv+2)) - in6_dev_hold(idev); -} - -static void mld_ifc_stop_timer(struct inet6_dev *idev) -{ - idev->mc_ifc_count = 0; - if (del_timer(&idev->mc_ifc_timer)) - __in6_dev_put(idev); -} - -static void mld_dad_start_timer(struct inet6_dev *idev, unsigned long delay) -{ - unsigned long tv = prandom_u32() % delay; - - if (!mod_timer(&idev->mc_dad_timer, jiffies+tv+2)) - in6_dev_hold(idev); -} - -static void mld_dad_stop_timer(struct inet6_dev *idev) -{ - if (del_timer(&idev->mc_dad_timer)) - __in6_dev_put(idev); -} - -/* - * IGMP handling (alias multicast ICMPv6 messages) - */ - -static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime) -{ - unsigned long delay = resptime; - - /* Do not start timer for these addresses */ - if (ipv6_addr_is_ll_all_nodes(&ma->mca_addr) || - IPV6_ADDR_MC_SCOPE(&ma->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL) - return; - - if (del_timer(&ma->mca_timer)) { - atomic_dec(&ma->mca_refcnt); - delay = ma->mca_timer.expires - jiffies; - } - - if (delay >= resptime) - delay = prandom_u32() % resptime; - - ma->mca_timer.expires = jiffies + delay; - if (!mod_timer(&ma->mca_timer, jiffies + delay)) - atomic_inc(&ma->mca_refcnt); - ma->mca_flags |= MAF_TIMER_RUNNING; -} - -/* mark EXCLUDE-mode sources */ -static bool mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs, - const struct in6_addr *srcs) -{ - struct ip6_sf_list *psf; - int i, scount; - - scount = 0; - for (psf = pmc->mca_sources; psf; psf = psf->sf_next) { - if (scount == nsrcs) - break; - for (i = 0; i < nsrcs; i++) { - /* skip inactive filters */ - if (psf->sf_count[MCAST_INCLUDE] || - pmc->mca_sfcount[MCAST_EXCLUDE] != - psf->sf_count[MCAST_EXCLUDE]) - break; - if (ipv6_addr_equal(&srcs[i], &psf->sf_addr)) { - scount++; - break; - } - } - } - pmc->mca_flags &= ~MAF_GSQUERY; - if (scount == nsrcs) /* all sources excluded */ - return false; - return true; -} - -static bool mld_marksources(struct ifmcaddr6 *pmc, int nsrcs, - const struct in6_addr *srcs) -{ - struct ip6_sf_list *psf; - int i, scount; - - if (pmc->mca_sfmode == MCAST_EXCLUDE) - return mld_xmarksources(pmc, nsrcs, srcs); - - /* mark INCLUDE-mode sources */ - - scount = 0; - for (psf = pmc->mca_sources; psf; psf = psf->sf_next) { - if (scount == nsrcs) - break; - for (i = 0; i < nsrcs; i++) { - if (ipv6_addr_equal(&srcs[i], &psf->sf_addr)) { - psf->sf_gsresp = 1; - scount++; - break; - } - } - } - if (!scount) { - pmc->mca_flags &= ~MAF_GSQUERY; - return false; - } - pmc->mca_flags |= MAF_GSQUERY; - return true; -} - -static int mld_force_mld_version(const struct inet6_dev *idev) -{ - /* Normally, both are 0 here. If enforcement to a particular is - * being used, individual device enforcement will have a lower - * precedence over 'all' device (.../conf/all/force_mld_version). - */ - - if (dev_net(idev->dev)->ipv6.devconf_all->force_mld_version != 0) - return dev_net(idev->dev)->ipv6.devconf_all->force_mld_version; - else - return idev->cnf.force_mld_version; -} - -static bool mld_in_v2_mode_only(const struct inet6_dev *idev) -{ - return mld_force_mld_version(idev) == 2; -} - -static bool mld_in_v1_mode_only(const struct inet6_dev *idev) -{ - return mld_force_mld_version(idev) == 1; -} - -static bool mld_in_v1_mode(const struct inet6_dev *idev) -{ - if (mld_in_v2_mode_only(idev)) - return false; - if (mld_in_v1_mode_only(idev)) - return true; - if (idev->mc_v1_seen && time_before(jiffies, idev->mc_v1_seen)) - return true; - - return false; -} - -static void mld_set_v1_mode(struct inet6_dev *idev) -{ - /* RFC3810, relevant sections: - * - 9.1. Robustness Variable - * - 9.2. Query Interval - * - 9.3. Query Response Interval - * - 9.12. Older Version Querier Present Timeout - */ - unsigned long switchback; - - switchback = (idev->mc_qrv * idev->mc_qi) + idev->mc_qri; - - idev->mc_v1_seen = jiffies + switchback; -} - -static void mld_update_qrv(struct inet6_dev *idev, - const struct mld2_query *mlh2) -{ - /* RFC3810, relevant sections: - * - 5.1.8. QRV (Querier's Robustness Variable) - * - 9.1. Robustness Variable - */ - - /* The value of the Robustness Variable MUST NOT be zero, - * and SHOULD NOT be one. Catch this here if we ever run - * into such a case in future. - */ - const int min_qrv = min(MLD_QRV_DEFAULT, sysctl_mld_qrv); - WARN_ON(idev->mc_qrv == 0); - - if (mlh2->mld2q_qrv > 0) - idev->mc_qrv = mlh2->mld2q_qrv; - - if (unlikely(idev->mc_qrv < min_qrv)) { - net_warn_ratelimited("IPv6: MLD: clamping QRV from %u to %u!\n", - idev->mc_qrv, min_qrv); - idev->mc_qrv = min_qrv; - } -} - -static void mld_update_qi(struct inet6_dev *idev, - const struct mld2_query *mlh2) -{ - /* RFC3810, relevant sections: - * - 5.1.9. QQIC (Querier's Query Interval Code) - * - 9.2. Query Interval - * - 9.12. Older Version Querier Present Timeout - * (the [Query Interval] in the last Query received) - */ - unsigned long mc_qqi; - - if (mlh2->mld2q_qqic < 128) { - mc_qqi = mlh2->mld2q_qqic; - } else { - unsigned long mc_man, mc_exp; - - mc_exp = MLDV2_QQIC_EXP(mlh2->mld2q_qqic); - mc_man = MLDV2_QQIC_MAN(mlh2->mld2q_qqic); - - mc_qqi = (mc_man | 0x10) << (mc_exp + 3); - } - - idev->mc_qi = mc_qqi * HZ; -} - -static void mld_update_qri(struct inet6_dev *idev, - const struct mld2_query *mlh2) -{ - /* RFC3810, relevant sections: - * - 5.1.3. Maximum Response Code - * - 9.3. Query Response Interval - */ - idev->mc_qri = msecs_to_jiffies(mldv2_mrc(mlh2)); -} - -static int mld_process_v1(struct inet6_dev *idev, struct mld_msg *mld, - unsigned long *max_delay, bool v1_query) -{ - unsigned long mldv1_md; - - /* Ignore v1 queries */ - if (mld_in_v2_mode_only(idev)) - return -EINVAL; - - mldv1_md = ntohs(mld->mld_maxdelay); - - /* When in MLDv1 fallback and a MLDv2 router start-up being - * unaware of current MLDv1 operation, the MRC == MRD mapping - * only works when the exponential algorithm is not being - * used (as MLDv1 is unaware of such things). - * - * According to the RFC author, the MLDv2 implementations - * he's aware of all use a MRC < 32768 on start up queries. - * - * Thus, should we *ever* encounter something else larger - * than that, just assume the maximum possible within our - * reach. - */ - if (!v1_query) - mldv1_md = min(mldv1_md, MLDV1_MRD_MAX_COMPAT); - - *max_delay = max(msecs_to_jiffies(mldv1_md), 1UL); - - /* MLDv1 router present: we need to go into v1 mode *only* - * when an MLDv1 query is received as per section 9.12. of - * RFC3810! And we know from RFC2710 section 3.7 that MLDv1 - * queries MUST be of exactly 24 octets. - */ - if (v1_query) - mld_set_v1_mode(idev); - - /* cancel MLDv2 report timer */ - mld_gq_stop_timer(idev); - /* cancel the interface change timer */ - mld_ifc_stop_timer(idev); - /* clear deleted report items */ - mld_clear_delrec(idev); - - return 0; -} - -static int mld_process_v2(struct inet6_dev *idev, struct mld2_query *mld, - unsigned long *max_delay) -{ - *max_delay = max(msecs_to_jiffies(mldv2_mrc(mld)), 1UL); - - mld_update_qrv(idev, mld); - mld_update_qi(idev, mld); - mld_update_qri(idev, mld); - - idev->mc_maxdelay = *max_delay; - - return 0; -} - -/* called with rcu_read_lock() */ -int igmp6_event_query(struct sk_buff *skb) -{ - struct mld2_query *mlh2 = NULL; - struct ifmcaddr6 *ma; - const struct in6_addr *group; - unsigned long max_delay; - struct inet6_dev *idev; - struct mld_msg *mld; - int group_type; - int mark = 0; - int len, err; - - if (!pskb_may_pull(skb, sizeof(struct in6_addr))) - return -EINVAL; - - /* compute payload length excluding extension headers */ - len = ntohs(ipv6_hdr(skb)->payload_len) + sizeof(struct ipv6hdr); - len -= skb_network_header_len(skb); - - /* RFC3810 6.2 - * Upon reception of an MLD message that contains a Query, the node - * checks if the source address of the message is a valid link-local - * address, if the Hop Limit is set to 1, and if the Router Alert - * option is present in the Hop-By-Hop Options header of the IPv6 - * packet. If any of these checks fails, the packet is dropped. - */ - if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL) || - ipv6_hdr(skb)->hop_limit != 1 || - !(IP6CB(skb)->flags & IP6SKB_ROUTERALERT) || - IP6CB(skb)->ra != htons(IPV6_OPT_ROUTERALERT_MLD)) - return -EINVAL; - - idev = __in6_dev_get(skb->dev); - if (!idev) - return 0; - - mld = (struct mld_msg *)icmp6_hdr(skb); - group = &mld->mld_mca; - group_type = ipv6_addr_type(group); - - if (group_type != IPV6_ADDR_ANY && - !(group_type&IPV6_ADDR_MULTICAST)) - return -EINVAL; - - if (len < MLD_V1_QUERY_LEN) { - return -EINVAL; - } else if (len == MLD_V1_QUERY_LEN || mld_in_v1_mode(idev)) { - err = mld_process_v1(idev, mld, &max_delay, - len == MLD_V1_QUERY_LEN); - if (err < 0) - return err; - } else if (len >= MLD_V2_QUERY_LEN_MIN) { - int srcs_offset = sizeof(struct mld2_query) - - sizeof(struct icmp6hdr); - - if (!pskb_may_pull(skb, srcs_offset)) - return -EINVAL; - - mlh2 = (struct mld2_query *)skb_transport_header(skb); - - err = mld_process_v2(idev, mlh2, &max_delay); - if (err < 0) - return err; - - if (group_type == IPV6_ADDR_ANY) { /* general query */ - if (mlh2->mld2q_nsrcs) - return -EINVAL; /* no sources allowed */ - - mld_gq_start_timer(idev); - return 0; - } - /* mark sources to include, if group & source-specific */ - if (mlh2->mld2q_nsrcs != 0) { - if (!pskb_may_pull(skb, srcs_offset + - ntohs(mlh2->mld2q_nsrcs) * sizeof(struct in6_addr))) - return -EINVAL; - - mlh2 = (struct mld2_query *)skb_transport_header(skb); - mark = 1; - } - } else { - return -EINVAL; - } - - read_lock_bh(&idev->lock); - if (group_type == IPV6_ADDR_ANY) { - for (ma = idev->mc_list; ma; ma = ma->next) { - spin_lock_bh(&ma->mca_lock); - igmp6_group_queried(ma, max_delay); - spin_unlock_bh(&ma->mca_lock); - } - } else { - for (ma = idev->mc_list; ma; ma = ma->next) { - if (!ipv6_addr_equal(group, &ma->mca_addr)) - continue; - spin_lock_bh(&ma->mca_lock); - if (ma->mca_flags & MAF_TIMER_RUNNING) { - /* gsquery <- gsquery && mark */ - if (!mark) - ma->mca_flags &= ~MAF_GSQUERY; - } else { - /* gsquery <- mark */ - if (mark) - ma->mca_flags |= MAF_GSQUERY; - else - ma->mca_flags &= ~MAF_GSQUERY; - } - if (!(ma->mca_flags & MAF_GSQUERY) || - mld_marksources(ma, ntohs(mlh2->mld2q_nsrcs), mlh2->mld2q_srcs)) - igmp6_group_queried(ma, max_delay); - spin_unlock_bh(&ma->mca_lock); - break; - } - } - read_unlock_bh(&idev->lock); - - return 0; -} - -/* called with rcu_read_lock() */ -int igmp6_event_report(struct sk_buff *skb) -{ - struct ifmcaddr6 *ma; - struct inet6_dev *idev; - struct mld_msg *mld; - int addr_type; - - /* Our own report looped back. Ignore it. */ - if (skb->pkt_type == PACKET_LOOPBACK) - return 0; - - /* send our report if the MC router may not have heard this report */ - if (skb->pkt_type != PACKET_MULTICAST && - skb->pkt_type != PACKET_BROADCAST) - return 0; - - if (!pskb_may_pull(skb, sizeof(*mld) - sizeof(struct icmp6hdr))) - return -EINVAL; - - mld = (struct mld_msg *)icmp6_hdr(skb); - - /* Drop reports with not link local source */ - addr_type = ipv6_addr_type(&ipv6_hdr(skb)->saddr); - if (addr_type != IPV6_ADDR_ANY && - !(addr_type&IPV6_ADDR_LINKLOCAL)) - return -EINVAL; - - idev = __in6_dev_get(skb->dev); - if (!idev) - return -ENODEV; - - /* - * Cancel the timer for this group - */ - - read_lock_bh(&idev->lock); - for (ma = idev->mc_list; ma; ma = ma->next) { - if (ipv6_addr_equal(&ma->mca_addr, &mld->mld_mca)) { - spin_lock(&ma->mca_lock); - if (del_timer(&ma->mca_timer)) - atomic_dec(&ma->mca_refcnt); - ma->mca_flags &= ~(MAF_LAST_REPORTER|MAF_TIMER_RUNNING); - spin_unlock(&ma->mca_lock); - break; - } - } - read_unlock_bh(&idev->lock); - return 0; -} - -static bool is_in(struct ifmcaddr6 *pmc, struct ip6_sf_list *psf, int type, - int gdeleted, int sdeleted) -{ - switch (type) { - case MLD2_MODE_IS_INCLUDE: - case MLD2_MODE_IS_EXCLUDE: - if (gdeleted || sdeleted) - return false; - if (!((pmc->mca_flags & MAF_GSQUERY) && !psf->sf_gsresp)) { - if (pmc->mca_sfmode == MCAST_INCLUDE) - return true; - /* don't include if this source is excluded - * in all filters - */ - if (psf->sf_count[MCAST_INCLUDE]) - return type == MLD2_MODE_IS_INCLUDE; - return pmc->mca_sfcount[MCAST_EXCLUDE] == - psf->sf_count[MCAST_EXCLUDE]; - } - return false; - case MLD2_CHANGE_TO_INCLUDE: - if (gdeleted || sdeleted) - return false; - return psf->sf_count[MCAST_INCLUDE] != 0; - case MLD2_CHANGE_TO_EXCLUDE: - if (gdeleted || sdeleted) - return false; - if (pmc->mca_sfcount[MCAST_EXCLUDE] == 0 || - psf->sf_count[MCAST_INCLUDE]) - return false; - return pmc->mca_sfcount[MCAST_EXCLUDE] == - psf->sf_count[MCAST_EXCLUDE]; - case MLD2_ALLOW_NEW_SOURCES: - if (gdeleted || !psf->sf_crcount) - return false; - return (pmc->mca_sfmode == MCAST_INCLUDE) ^ sdeleted; - case MLD2_BLOCK_OLD_SOURCES: - if (pmc->mca_sfmode == MCAST_INCLUDE) - return gdeleted || (psf->sf_crcount && sdeleted); - return psf->sf_crcount && !gdeleted && !sdeleted; - } - return false; -} - -static int -mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted) -{ - struct ip6_sf_list *psf; - int scount = 0; - - for (psf = pmc->mca_sources; psf; psf = psf->sf_next) { - if (!is_in(pmc, psf, type, gdeleted, sdeleted)) - continue; - scount++; - } - return scount; -} - -static void ip6_mc_hdr(struct sock *sk, struct sk_buff *skb, - struct net_device *dev, - const struct in6_addr *saddr, - const struct in6_addr *daddr, - int proto, int len) -{ - struct ipv6hdr *hdr; - - skb->protocol = htons(ETH_P_IPV6); - skb->dev = dev; - - skb_reset_network_header(skb); - skb_put(skb, sizeof(struct ipv6hdr)); - hdr = ipv6_hdr(skb); - - ip6_flow_hdr(hdr, 0, 0); - - hdr->payload_len = htons(len); - hdr->nexthdr = proto; - hdr->hop_limit = inet6_sk(sk)->hop_limit; - - hdr->saddr = *saddr; - hdr->daddr = *daddr; -} - -static struct sk_buff *mld_newpack(struct inet6_dev *idev, unsigned int mtu) -{ - struct net_device *dev = idev->dev; - struct net *net = dev_net(dev); - struct sock *sk = net->ipv6.igmp_sk; - struct sk_buff *skb; - struct mld2_report *pmr; - struct in6_addr addr_buf; - const struct in6_addr *saddr; - int hlen = LL_RESERVED_SPACE(dev); - int tlen = dev->needed_tailroom; - unsigned int size = mtu + hlen + tlen; - int err; - u8 ra[8] = { IPPROTO_ICMPV6, 0, - IPV6_TLV_ROUTERALERT, 2, 0, 0, - IPV6_TLV_PADN, 0 }; - - /* we assume size > sizeof(ra) here */ - /* limit our allocations to order-0 page */ - size = min_t(int, size, SKB_MAX_ORDER(0, 0)); - skb = sock_alloc_send_skb(sk, size, 1, &err); - - if (!skb) - return NULL; - - skb->priority = TC_PRIO_CONTROL; - skb_reserve(skb, hlen); - skb_tailroom_reserve(skb, mtu, tlen); - - if (__ipv6_get_lladdr(idev, &addr_buf, IFA_F_TENTATIVE)) { - /* : - * use unspecified address as the source address - * when a valid link-local address is not available. - */ - saddr = &in6addr_any; - } else - saddr = &addr_buf; - - ip6_mc_hdr(sk, skb, dev, saddr, &mld2_all_mcr, NEXTHDR_HOP, 0); - - memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); - - skb_set_transport_header(skb, skb_tail_pointer(skb) - skb->data); - skb_put(skb, sizeof(*pmr)); - pmr = (struct mld2_report *)skb_transport_header(skb); - pmr->mld2r_type = ICMPV6_MLD2_REPORT; - pmr->mld2r_resv1 = 0; - pmr->mld2r_cksum = 0; - pmr->mld2r_resv2 = 0; - pmr->mld2r_ngrec = 0; - return skb; -} - -static void mld_sendpack(struct sk_buff *skb) -{ - struct ipv6hdr *pip6 = ipv6_hdr(skb); - struct mld2_report *pmr = - (struct mld2_report *)skb_transport_header(skb); - int payload_len, mldlen; - struct inet6_dev *idev; - struct net *net = dev_net(skb->dev); - int err; - struct flowi6 fl6; - struct dst_entry *dst; - - rcu_read_lock(); - idev = __in6_dev_get(skb->dev); - IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); - - payload_len = (skb_tail_pointer(skb) - skb_network_header(skb)) - - sizeof(*pip6); - mldlen = skb_tail_pointer(skb) - skb_transport_header(skb); - pip6->payload_len = htons(payload_len); - - pmr->mld2r_cksum = csum_ipv6_magic(&pip6->saddr, &pip6->daddr, mldlen, - IPPROTO_ICMPV6, - csum_partial(skb_transport_header(skb), - mldlen, 0)); - - icmpv6_flow_init(net->ipv6.igmp_sk, &fl6, ICMPV6_MLD2_REPORT, - &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, - skb->dev->ifindex); - dst = icmp6_dst_alloc(skb->dev, &fl6); - - err = 0; - if (IS_ERR(dst)) { - err = PTR_ERR(dst); - dst = NULL; - } - skb_dst_set(skb, dst); - if (err) - goto err_out; - - payload_len = skb->len; - - err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, - net, net->ipv6.igmp_sk, skb, NULL, skb->dev, - dst_output); -out: - if (!err) { - ICMP6MSGOUT_INC_STATS(net, idev, ICMPV6_MLD2_REPORT); - ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); - } else { - IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); - } - - rcu_read_unlock(); - return; - -err_out: - kfree_skb(skb); - goto out; -} - -static int grec_size(struct ifmcaddr6 *pmc, int type, int gdel, int sdel) -{ - return sizeof(struct mld2_grec) + 16 * mld_scount(pmc,type,gdel,sdel); -} - -static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc, - int type, struct mld2_grec **ppgr) -{ - struct net_device *dev = pmc->idev->dev; - struct mld2_report *pmr; - struct mld2_grec *pgr; - - if (!skb) - skb = mld_newpack(pmc->idev, dev->mtu); - if (!skb) - return NULL; - pgr = (struct mld2_grec *)skb_put(skb, sizeof(struct mld2_grec)); - pgr->grec_type = type; - pgr->grec_auxwords = 0; - pgr->grec_nsrcs = 0; - pgr->grec_mca = pmc->mca_addr; /* structure copy */ - pmr = (struct mld2_report *)skb_transport_header(skb); - pmr->mld2r_ngrec = htons(ntohs(pmr->mld2r_ngrec)+1); - *ppgr = pgr; - return skb; -} - -#define AVAILABLE(skb) ((skb) ? skb_availroom(skb) : 0) - -static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, - int type, int gdeleted, int sdeleted, int crsend) -{ - struct inet6_dev *idev = pmc->idev; - struct net_device *dev = idev->dev; - struct mld2_report *pmr; - struct mld2_grec *pgr = NULL; - struct ip6_sf_list *psf, *psf_next, *psf_prev, **psf_list; - int scount, stotal, first, isquery, truncate; - - if (pmc->mca_flags & MAF_NOREPORT) - return skb; - - isquery = type == MLD2_MODE_IS_INCLUDE || - type == MLD2_MODE_IS_EXCLUDE; - truncate = type == MLD2_MODE_IS_EXCLUDE || - type == MLD2_CHANGE_TO_EXCLUDE; - - stotal = scount = 0; - - psf_list = sdeleted ? &pmc->mca_tomb : &pmc->mca_sources; - - if (!*psf_list) - goto empty_source; - - pmr = skb ? (struct mld2_report *)skb_transport_header(skb) : NULL; - - /* EX and TO_EX get a fresh packet, if needed */ - if (truncate) { - if (pmr && pmr->mld2r_ngrec && - AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) { - if (skb) - mld_sendpack(skb); - skb = mld_newpack(idev, dev->mtu); - } - } - first = 1; - psf_prev = NULL; - for (psf = *psf_list; psf; psf = psf_next) { - struct in6_addr *psrc; - - psf_next = psf->sf_next; - - if (!is_in(pmc, psf, type, gdeleted, sdeleted)) { - psf_prev = psf; - continue; - } - - /* Based on RFC3810 6.1. Should not send source-list change - * records when there is a filter mode change. - */ - if (((gdeleted && pmc->mca_sfmode == MCAST_EXCLUDE) || - (!gdeleted && pmc->mca_crcount)) && - (type == MLD2_ALLOW_NEW_SOURCES || - type == MLD2_BLOCK_OLD_SOURCES) && psf->sf_crcount) - goto decrease_sf_crcount; - - /* clear marks on query responses */ - if (isquery) - psf->sf_gsresp = 0; - - if (AVAILABLE(skb) < sizeof(*psrc) + - first*sizeof(struct mld2_grec)) { - if (truncate && !first) - break; /* truncate these */ - if (pgr) - pgr->grec_nsrcs = htons(scount); - if (skb) - mld_sendpack(skb); - skb = mld_newpack(idev, dev->mtu); - first = 1; - scount = 0; - } - if (first) { - skb = add_grhead(skb, pmc, type, &pgr); - first = 0; - } - if (!skb) - return NULL; - psrc = (struct in6_addr *)skb_put(skb, sizeof(*psrc)); - *psrc = psf->sf_addr; - scount++; stotal++; - if ((type == MLD2_ALLOW_NEW_SOURCES || - type == MLD2_BLOCK_OLD_SOURCES) && psf->sf_crcount) { -decrease_sf_crcount: - psf->sf_crcount--; - if ((sdeleted || gdeleted) && psf->sf_crcount == 0) { - if (psf_prev) - psf_prev->sf_next = psf->sf_next; - else - *psf_list = psf->sf_next; - kfree(psf); - continue; - } - } - psf_prev = psf; - } - -empty_source: - if (!stotal) { - if (type == MLD2_ALLOW_NEW_SOURCES || - type == MLD2_BLOCK_OLD_SOURCES) - return skb; - if (pmc->mca_crcount || isquery || crsend) { - /* make sure we have room for group header */ - if (skb && AVAILABLE(skb) < sizeof(struct mld2_grec)) { - mld_sendpack(skb); - skb = NULL; /* add_grhead will get a new one */ - } - skb = add_grhead(skb, pmc, type, &pgr); - } - } - if (pgr) - pgr->grec_nsrcs = htons(scount); - - if (isquery) - pmc->mca_flags &= ~MAF_GSQUERY; /* clear query state */ - return skb; -} - -static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc) -{ - struct sk_buff *skb = NULL; - int type; - - read_lock_bh(&idev->lock); - if (!pmc) { - for (pmc = idev->mc_list; pmc; pmc = pmc->next) { - if (pmc->mca_flags & MAF_NOREPORT) - continue; - spin_lock_bh(&pmc->mca_lock); - if (pmc->mca_sfcount[MCAST_EXCLUDE]) - type = MLD2_MODE_IS_EXCLUDE; - else - type = MLD2_MODE_IS_INCLUDE; - skb = add_grec(skb, pmc, type, 0, 0, 0); - spin_unlock_bh(&pmc->mca_lock); - } - } else { - spin_lock_bh(&pmc->mca_lock); - if (pmc->mca_sfcount[MCAST_EXCLUDE]) - type = MLD2_MODE_IS_EXCLUDE; - else - type = MLD2_MODE_IS_INCLUDE; - skb = add_grec(skb, pmc, type, 0, 0, 0); - spin_unlock_bh(&pmc->mca_lock); - } - read_unlock_bh(&idev->lock); - if (skb) - mld_sendpack(skb); -} - -/* - * remove zero-count source records from a source filter list - */ -static void mld_clear_zeros(struct ip6_sf_list **ppsf) -{ - struct ip6_sf_list *psf_prev, *psf_next, *psf; - - psf_prev = NULL; - for (psf = *ppsf; psf; psf = psf_next) { - psf_next = psf->sf_next; - if (psf->sf_crcount == 0) { - if (psf_prev) - psf_prev->sf_next = psf->sf_next; - else - *ppsf = psf->sf_next; - kfree(psf); - } else - psf_prev = psf; - } -} - -static void mld_send_cr(struct inet6_dev *idev) -{ - struct ifmcaddr6 *pmc, *pmc_prev, *pmc_next; - struct sk_buff *skb = NULL; - int type, dtype; - - read_lock_bh(&idev->lock); - spin_lock(&idev->mc_lock); - - /* deleted MCA's */ - pmc_prev = NULL; - for (pmc = idev->mc_tomb; pmc; pmc = pmc_next) { - pmc_next = pmc->next; - if (pmc->mca_sfmode == MCAST_INCLUDE) { - type = MLD2_BLOCK_OLD_SOURCES; - dtype = MLD2_BLOCK_OLD_SOURCES; - skb = add_grec(skb, pmc, type, 1, 0, 0); - skb = add_grec(skb, pmc, dtype, 1, 1, 0); - } - if (pmc->mca_crcount) { - if (pmc->mca_sfmode == MCAST_EXCLUDE) { - type = MLD2_CHANGE_TO_INCLUDE; - skb = add_grec(skb, pmc, type, 1, 0, 0); - } - pmc->mca_crcount--; - if (pmc->mca_crcount == 0) { - mld_clear_zeros(&pmc->mca_tomb); - mld_clear_zeros(&pmc->mca_sources); - } - } - if (pmc->mca_crcount == 0 && !pmc->mca_tomb && - !pmc->mca_sources) { - if (pmc_prev) - pmc_prev->next = pmc_next; - else - idev->mc_tomb = pmc_next; - in6_dev_put(pmc->idev); - kfree(pmc); - } else - pmc_prev = pmc; - } - spin_unlock(&idev->mc_lock); - - /* change recs */ - for (pmc = idev->mc_list; pmc; pmc = pmc->next) { - spin_lock_bh(&pmc->mca_lock); - if (pmc->mca_sfcount[MCAST_EXCLUDE]) { - type = MLD2_BLOCK_OLD_SOURCES; - dtype = MLD2_ALLOW_NEW_SOURCES; - } else { - type = MLD2_ALLOW_NEW_SOURCES; - dtype = MLD2_BLOCK_OLD_SOURCES; - } - skb = add_grec(skb, pmc, type, 0, 0, 0); - skb = add_grec(skb, pmc, dtype, 0, 1, 0); /* deleted sources */ - - /* filter mode changes */ - if (pmc->mca_crcount) { - if (pmc->mca_sfmode == MCAST_EXCLUDE) - type = MLD2_CHANGE_TO_EXCLUDE; - else - type = MLD2_CHANGE_TO_INCLUDE; - skb = add_grec(skb, pmc, type, 0, 0, 0); - pmc->mca_crcount--; - } - spin_unlock_bh(&pmc->mca_lock); - } - read_unlock_bh(&idev->lock); - if (!skb) - return; - (void) mld_sendpack(skb); -} - -static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) -{ - struct net *net = dev_net(dev); - struct sock *sk = net->ipv6.igmp_sk; - struct inet6_dev *idev; - struct sk_buff *skb; - struct mld_msg *hdr; - const struct in6_addr *snd_addr, *saddr; - struct in6_addr addr_buf; - int hlen = LL_RESERVED_SPACE(dev); - int tlen = dev->needed_tailroom; - int err, len, payload_len, full_len; - u8 ra[8] = { IPPROTO_ICMPV6, 0, - IPV6_TLV_ROUTERALERT, 2, 0, 0, - IPV6_TLV_PADN, 0 }; - struct flowi6 fl6; - struct dst_entry *dst; - - if (type == ICMPV6_MGM_REDUCTION) - snd_addr = &in6addr_linklocal_allrouters; - else - snd_addr = addr; - - len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr); - payload_len = len + sizeof(ra); - full_len = sizeof(struct ipv6hdr) + payload_len; - - rcu_read_lock(); - IP6_UPD_PO_STATS(net, __in6_dev_get(dev), - IPSTATS_MIB_OUT, full_len); - rcu_read_unlock(); - - skb = sock_alloc_send_skb(sk, hlen + tlen + full_len, 1, &err); - - if (!skb) { - rcu_read_lock(); - IP6_INC_STATS(net, __in6_dev_get(dev), - IPSTATS_MIB_OUTDISCARDS); - rcu_read_unlock(); - return; - } - skb->priority = TC_PRIO_CONTROL; - skb_reserve(skb, hlen); - - if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) { - /* : - * use unspecified address as the source address - * when a valid link-local address is not available. - */ - saddr = &in6addr_any; - } else - saddr = &addr_buf; - - ip6_mc_hdr(sk, skb, dev, saddr, snd_addr, NEXTHDR_HOP, payload_len); - - memcpy(skb_put(skb, sizeof(ra)), ra, sizeof(ra)); - - hdr = (struct mld_msg *) skb_put(skb, sizeof(struct mld_msg)); - memset(hdr, 0, sizeof(struct mld_msg)); - hdr->mld_type = type; - hdr->mld_mca = *addr; - - hdr->mld_cksum = csum_ipv6_magic(saddr, snd_addr, len, - IPPROTO_ICMPV6, - csum_partial(hdr, len, 0)); - - rcu_read_lock(); - idev = __in6_dev_get(skb->dev); - - icmpv6_flow_init(sk, &fl6, type, - &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, - skb->dev->ifindex); - dst = icmp6_dst_alloc(skb->dev, &fl6); - if (IS_ERR(dst)) { - err = PTR_ERR(dst); - goto err_out; - } - - skb_dst_set(skb, dst); - err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, - net, sk, skb, NULL, skb->dev, - dst_output); -out: - if (!err) { - ICMP6MSGOUT_INC_STATS(net, idev, type); - ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); - } else - IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS); - - rcu_read_unlock(); - return; - -err_out: - kfree_skb(skb); - goto out; -} - -static void mld_send_initial_cr(struct inet6_dev *idev) -{ - struct sk_buff *skb; - struct ifmcaddr6 *pmc; - int type; - - if (mld_in_v1_mode(idev)) - return; - - skb = NULL; - read_lock_bh(&idev->lock); - for (pmc = idev->mc_list; pmc; pmc = pmc->next) { - spin_lock_bh(&pmc->mca_lock); - if (pmc->mca_sfcount[MCAST_EXCLUDE]) - type = MLD2_CHANGE_TO_EXCLUDE; - else - type = MLD2_CHANGE_TO_INCLUDE; - skb = add_grec(skb, pmc, type, 0, 0, 1); - spin_unlock_bh(&pmc->mca_lock); - } - read_unlock_bh(&idev->lock); - if (skb) - mld_sendpack(skb); -} - -void ipv6_mc_dad_complete(struct inet6_dev *idev) -{ - idev->mc_dad_count = idev->mc_qrv; - if (idev->mc_dad_count) { - mld_send_initial_cr(idev); - idev->mc_dad_count--; - if (idev->mc_dad_count) - mld_dad_start_timer(idev, idev->mc_maxdelay); - } -} - -static void mld_dad_timer_expire(unsigned long data) -{ - struct inet6_dev *idev = (struct inet6_dev *)data; - - mld_send_initial_cr(idev); - if (idev->mc_dad_count) { - idev->mc_dad_count--; - if (idev->mc_dad_count) - mld_dad_start_timer(idev, idev->mc_maxdelay); - } - in6_dev_put(idev); -} - -static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode, - const struct in6_addr *psfsrc) -{ - struct ip6_sf_list *psf, *psf_prev; - int rv = 0; - - psf_prev = NULL; - for (psf = pmc->mca_sources; psf; psf = psf->sf_next) { - if (ipv6_addr_equal(&psf->sf_addr, psfsrc)) - break; - psf_prev = psf; - } - if (!psf || psf->sf_count[sfmode] == 0) { - /* source filter not found, or count wrong => bug */ - return -ESRCH; - } - psf->sf_count[sfmode]--; - if (!psf->sf_count[MCAST_INCLUDE] && !psf->sf_count[MCAST_EXCLUDE]) { - struct inet6_dev *idev = pmc->idev; - - /* no more filters for this source */ - if (psf_prev) - psf_prev->sf_next = psf->sf_next; - else - pmc->mca_sources = psf->sf_next; - if (psf->sf_oldin && !(pmc->mca_flags & MAF_NOREPORT) && - !mld_in_v1_mode(idev)) { - psf->sf_crcount = idev->mc_qrv; - psf->sf_next = pmc->mca_tomb; - pmc->mca_tomb = psf; - rv = 1; - } else - kfree(psf); - } - return rv; -} - -static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca, - int sfmode, int sfcount, const struct in6_addr *psfsrc, - int delta) -{ - struct ifmcaddr6 *pmc; - int changerec = 0; - int i, err; - - if (!idev) - return -ENODEV; - read_lock_bh(&idev->lock); - for (pmc = idev->mc_list; pmc; pmc = pmc->next) { - if (ipv6_addr_equal(pmca, &pmc->mca_addr)) - break; - } - if (!pmc) { - /* MCA not found?? bug */ - read_unlock_bh(&idev->lock); - return -ESRCH; - } - spin_lock_bh(&pmc->mca_lock); - sf_markstate(pmc); - if (!delta) { - if (!pmc->mca_sfcount[sfmode]) { - spin_unlock_bh(&pmc->mca_lock); - read_unlock_bh(&idev->lock); - return -EINVAL; - } - pmc->mca_sfcount[sfmode]--; - } - err = 0; - for (i = 0; i < sfcount; i++) { - int rv = ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]); - - changerec |= rv > 0; - if (!err && rv < 0) - err = rv; - } - if (pmc->mca_sfmode == MCAST_EXCLUDE && - pmc->mca_sfcount[MCAST_EXCLUDE] == 0 && - pmc->mca_sfcount[MCAST_INCLUDE]) { - struct ip6_sf_list *psf; - - /* filter mode change */ - pmc->mca_sfmode = MCAST_INCLUDE; - pmc->mca_crcount = idev->mc_qrv; - idev->mc_ifc_count = pmc->mca_crcount; - for (psf = pmc->mca_sources; psf; psf = psf->sf_next) - psf->sf_crcount = 0; - mld_ifc_event(pmc->idev); - } else if (sf_setstate(pmc) || changerec) - mld_ifc_event(pmc->idev); - spin_unlock_bh(&pmc->mca_lock); - read_unlock_bh(&idev->lock); - return err; -} - -/* - * Add multicast single-source filter to the interface list - */ -static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode, - const struct in6_addr *psfsrc) -{ - struct ip6_sf_list *psf, *psf_prev; - - psf_prev = NULL; - for (psf = pmc->mca_sources; psf; psf = psf->sf_next) { - if (ipv6_addr_equal(&psf->sf_addr, psfsrc)) - break; - psf_prev = psf; - } - if (!psf) { - psf = kzalloc(sizeof(*psf), GFP_ATOMIC); - if (!psf) - return -ENOBUFS; - - psf->sf_addr = *psfsrc; - if (psf_prev) { - psf_prev->sf_next = psf; - } else - pmc->mca_sources = psf; - } - psf->sf_count[sfmode]++; - return 0; -} - -static void sf_markstate(struct ifmcaddr6 *pmc) -{ - struct ip6_sf_list *psf; - int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE]; - - for (psf = pmc->mca_sources; psf; psf = psf->sf_next) - if (pmc->mca_sfcount[MCAST_EXCLUDE]) { - psf->sf_oldin = mca_xcount == - psf->sf_count[MCAST_EXCLUDE] && - !psf->sf_count[MCAST_INCLUDE]; - } else - psf->sf_oldin = psf->sf_count[MCAST_INCLUDE] != 0; -} - -static int sf_setstate(struct ifmcaddr6 *pmc) -{ - struct ip6_sf_list *psf, *dpsf; - int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE]; - int qrv = pmc->idev->mc_qrv; - int new_in, rv; - - rv = 0; - for (psf = pmc->mca_sources; psf; psf = psf->sf_next) { - if (pmc->mca_sfcount[MCAST_EXCLUDE]) { - new_in = mca_xcount == psf->sf_count[MCAST_EXCLUDE] && - !psf->sf_count[MCAST_INCLUDE]; - } else - new_in = psf->sf_count[MCAST_INCLUDE] != 0; - if (new_in) { - if (!psf->sf_oldin) { - struct ip6_sf_list *prev = NULL; - - for (dpsf = pmc->mca_tomb; dpsf; - dpsf = dpsf->sf_next) { - if (ipv6_addr_equal(&dpsf->sf_addr, - &psf->sf_addr)) - break; - prev = dpsf; - } - if (dpsf) { - if (prev) - prev->sf_next = dpsf->sf_next; - else - pmc->mca_tomb = dpsf->sf_next; - kfree(dpsf); - } - psf->sf_crcount = qrv; - rv++; - } - } else if (psf->sf_oldin) { - psf->sf_crcount = 0; - /* - * add or update "delete" records if an active filter - * is now inactive - */ - for (dpsf = pmc->mca_tomb; dpsf; dpsf = dpsf->sf_next) - if (ipv6_addr_equal(&dpsf->sf_addr, - &psf->sf_addr)) - break; - if (!dpsf) { - dpsf = kmalloc(sizeof(*dpsf), GFP_ATOMIC); - if (!dpsf) - continue; - *dpsf = *psf; - /* pmc->mca_lock held by callers */ - dpsf->sf_next = pmc->mca_tomb; - pmc->mca_tomb = dpsf; - } - dpsf->sf_crcount = qrv; - rv++; - } - } - return rv; -} - -/* - * Add multicast source filter list to the interface list - */ -static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca, - int sfmode, int sfcount, const struct in6_addr *psfsrc, - int delta) -{ - struct ifmcaddr6 *pmc; - int isexclude; - int i, err; - - if (!idev) - return -ENODEV; - read_lock_bh(&idev->lock); - for (pmc = idev->mc_list; pmc; pmc = pmc->next) { - if (ipv6_addr_equal(pmca, &pmc->mca_addr)) - break; - } - if (!pmc) { - /* MCA not found?? bug */ - read_unlock_bh(&idev->lock); - return -ESRCH; - } - spin_lock_bh(&pmc->mca_lock); - - sf_markstate(pmc); - isexclude = pmc->mca_sfmode == MCAST_EXCLUDE; - if (!delta) - pmc->mca_sfcount[sfmode]++; - err = 0; - for (i = 0; i < sfcount; i++) { - err = ip6_mc_add1_src(pmc, sfmode, &psfsrc[i]); - if (err) - break; - } - if (err) { - int j; - - if (!delta) - pmc->mca_sfcount[sfmode]--; - for (j = 0; j < i; j++) - ip6_mc_del1_src(pmc, sfmode, &psfsrc[j]); - } else if (isexclude != (pmc->mca_sfcount[MCAST_EXCLUDE] != 0)) { - struct ip6_sf_list *psf; - - /* filter mode change */ - if (pmc->mca_sfcount[MCAST_EXCLUDE]) - pmc->mca_sfmode = MCAST_EXCLUDE; - else if (pmc->mca_sfcount[MCAST_INCLUDE]) - pmc->mca_sfmode = MCAST_INCLUDE; - /* else no filters; keep old mode for reports */ - - pmc->mca_crcount = idev->mc_qrv; - idev->mc_ifc_count = pmc->mca_crcount; - for (psf = pmc->mca_sources; psf; psf = psf->sf_next) - psf->sf_crcount = 0; - mld_ifc_event(idev); - } else if (sf_setstate(pmc)) - mld_ifc_event(idev); - spin_unlock_bh(&pmc->mca_lock); - read_unlock_bh(&idev->lock); - return err; -} - -static void ip6_mc_clear_src(struct ifmcaddr6 *pmc) -{ - struct ip6_sf_list *psf, *nextpsf; - - for (psf = pmc->mca_tomb; psf; psf = nextpsf) { - nextpsf = psf->sf_next; - kfree(psf); - } - pmc->mca_tomb = NULL; - for (psf = pmc->mca_sources; psf; psf = nextpsf) { - nextpsf = psf->sf_next; - kfree(psf); - } - pmc->mca_sources = NULL; - pmc->mca_sfmode = MCAST_EXCLUDE; - pmc->mca_sfcount[MCAST_INCLUDE] = 0; - pmc->mca_sfcount[MCAST_EXCLUDE] = 1; -} - - -static void igmp6_join_group(struct ifmcaddr6 *ma) -{ - unsigned long delay; - - if (ma->mca_flags & MAF_NOREPORT) - return; - - igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT); - - delay = prandom_u32() % unsolicited_report_interval(ma->idev); - - spin_lock_bh(&ma->mca_lock); - if (del_timer(&ma->mca_timer)) { - atomic_dec(&ma->mca_refcnt); - delay = ma->mca_timer.expires - jiffies; - } - - if (!mod_timer(&ma->mca_timer, jiffies + delay)) - atomic_inc(&ma->mca_refcnt); - ma->mca_flags |= MAF_TIMER_RUNNING | MAF_LAST_REPORTER; - spin_unlock_bh(&ma->mca_lock); -} - -static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, - struct inet6_dev *idev) -{ - int err; - - /* callers have the socket lock and rtnl lock - * so no other readers or writers of iml or its sflist - */ - if (!iml->sflist) { - /* any-source empty exclude case */ - return ip6_mc_del_src(idev, &iml->addr, iml->sfmode, 0, NULL, 0); - } - err = ip6_mc_del_src(idev, &iml->addr, iml->sfmode, - iml->sflist->sl_count, iml->sflist->sl_addr, 0); - sock_kfree_s(sk, iml->sflist, IP6_SFLSIZE(iml->sflist->sl_max)); - iml->sflist = NULL; - return err; -} - -static void igmp6_leave_group(struct ifmcaddr6 *ma) -{ - if (mld_in_v1_mode(ma->idev)) { - if (ma->mca_flags & MAF_LAST_REPORTER) - igmp6_send(&ma->mca_addr, ma->idev->dev, - ICMPV6_MGM_REDUCTION); - } else { - mld_add_delrec(ma->idev, ma); - mld_ifc_event(ma->idev); - } -} - -static void mld_gq_timer_expire(unsigned long data) -{ - struct inet6_dev *idev = (struct inet6_dev *)data; - - idev->mc_gq_running = 0; - mld_send_report(idev, NULL); - in6_dev_put(idev); -} - -static void mld_ifc_timer_expire(unsigned long data) -{ - struct inet6_dev *idev = (struct inet6_dev *)data; - - mld_send_cr(idev); - if (idev->mc_ifc_count) { - idev->mc_ifc_count--; - if (idev->mc_ifc_count) - mld_ifc_start_timer(idev, idev->mc_maxdelay); - } - in6_dev_put(idev); -} - -static void mld_ifc_event(struct inet6_dev *idev) -{ - if (mld_in_v1_mode(idev)) - return; - idev->mc_ifc_count = idev->mc_qrv; - mld_ifc_start_timer(idev, 1); -} - - -static void igmp6_timer_handler(unsigned long data) -{ - struct ifmcaddr6 *ma = (struct ifmcaddr6 *) data; - - if (mld_in_v1_mode(ma->idev)) - igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT); - else - mld_send_report(ma->idev, ma); - - spin_lock(&ma->mca_lock); - ma->mca_flags |= MAF_LAST_REPORTER; - ma->mca_flags &= ~MAF_TIMER_RUNNING; - spin_unlock(&ma->mca_lock); - ma_put(ma); -} - -/* Device changing type */ - -void ipv6_mc_unmap(struct inet6_dev *idev) -{ - struct ifmcaddr6 *i; - - /* Install multicast list, except for all-nodes (already installed) */ - - read_lock_bh(&idev->lock); - for (i = idev->mc_list; i; i = i->next) - igmp6_group_dropped(i); - read_unlock_bh(&idev->lock); -} - -void ipv6_mc_remap(struct inet6_dev *idev) -{ - ipv6_mc_up(idev); -} - -/* Device going down */ - -void ipv6_mc_down(struct inet6_dev *idev) -{ - struct ifmcaddr6 *i; - - /* Withdraw multicast list */ - - read_lock_bh(&idev->lock); - mld_ifc_stop_timer(idev); - mld_gq_stop_timer(idev); - mld_dad_stop_timer(idev); - - for (i = idev->mc_list; i; i = i->next) - igmp6_group_dropped(i); - read_unlock_bh(&idev->lock); - - mld_clear_delrec(idev); -} - -static void ipv6_mc_reset(struct inet6_dev *idev) -{ - idev->mc_qrv = sysctl_mld_qrv; - idev->mc_qi = MLD_QI_DEFAULT; - idev->mc_qri = MLD_QRI_DEFAULT; - idev->mc_v1_seen = 0; - idev->mc_maxdelay = unsolicited_report_interval(idev); -} - -/* Device going up */ - -void ipv6_mc_up(struct inet6_dev *idev) -{ - struct ifmcaddr6 *i; - - /* Install multicast list, except for all-nodes (already installed) */ - - read_lock_bh(&idev->lock); - ipv6_mc_reset(idev); - for (i = idev->mc_list; i; i = i->next) - igmp6_group_added(i); - read_unlock_bh(&idev->lock); -} - -/* IPv6 device initialization. */ - -void ipv6_mc_init_dev(struct inet6_dev *idev) -{ - write_lock_bh(&idev->lock); - spin_lock_init(&idev->mc_lock); - idev->mc_gq_running = 0; - setup_timer(&idev->mc_gq_timer, mld_gq_timer_expire, - (unsigned long)idev); - idev->mc_tomb = NULL; - idev->mc_ifc_count = 0; - setup_timer(&idev->mc_ifc_timer, mld_ifc_timer_expire, - (unsigned long)idev); - setup_timer(&idev->mc_dad_timer, mld_dad_timer_expire, - (unsigned long)idev); - ipv6_mc_reset(idev); - write_unlock_bh(&idev->lock); -} - -/* - * Device is about to be destroyed: clean up. - */ - -void ipv6_mc_destroy_dev(struct inet6_dev *idev) -{ - struct ifmcaddr6 *i; - - /* Deactivate timers */ - ipv6_mc_down(idev); - - /* Delete all-nodes address. */ - /* We cannot call ipv6_dev_mc_dec() directly, our caller in - * addrconf.c has NULL'd out dev->ip6_ptr so in6_dev_get() will - * fail. - */ - __ipv6_dev_mc_dec(idev, &in6addr_linklocal_allnodes); - - if (idev->cnf.forwarding) - __ipv6_dev_mc_dec(idev, &in6addr_linklocal_allrouters); - - write_lock_bh(&idev->lock); - while ((i = idev->mc_list) != NULL) { - idev->mc_list = i->next; - write_unlock_bh(&idev->lock); - - igmp6_group_dropped(i); - ma_put(i); - - write_lock_bh(&idev->lock); - } - write_unlock_bh(&idev->lock); -} - -#ifdef CONFIG_PROC_FS -struct igmp6_mc_iter_state { - struct seq_net_private p; - struct net_device *dev; - struct inet6_dev *idev; -}; - -#define igmp6_mc_seq_private(seq) ((struct igmp6_mc_iter_state *)(seq)->private) - -static inline struct ifmcaddr6 *igmp6_mc_get_first(struct seq_file *seq) -{ - struct ifmcaddr6 *im = NULL; - struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); - struct net *net = seq_file_net(seq); - - state->idev = NULL; - for_each_netdev_rcu(net, state->dev) { - struct inet6_dev *idev; - idev = __in6_dev_get(state->dev); - if (!idev) - continue; - read_lock_bh(&idev->lock); - im = idev->mc_list; - if (im) { - state->idev = idev; - break; - } - read_unlock_bh(&idev->lock); - } - return im; -} - -static struct ifmcaddr6 *igmp6_mc_get_next(struct seq_file *seq, struct ifmcaddr6 *im) -{ - struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); - - im = im->next; - while (!im) { - if (likely(state->idev)) - read_unlock_bh(&state->idev->lock); - - state->dev = next_net_device_rcu(state->dev); - if (!state->dev) { - state->idev = NULL; - break; - } - state->idev = __in6_dev_get(state->dev); - if (!state->idev) - continue; - read_lock_bh(&state->idev->lock); - im = state->idev->mc_list; - } - return im; -} - -static struct ifmcaddr6 *igmp6_mc_get_idx(struct seq_file *seq, loff_t pos) -{ - struct ifmcaddr6 *im = igmp6_mc_get_first(seq); - if (im) - while (pos && (im = igmp6_mc_get_next(seq, im)) != NULL) - --pos; - return pos ? NULL : im; -} - -static void *igmp6_mc_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(RCU) -{ - rcu_read_lock(); - return igmp6_mc_get_idx(seq, *pos); -} - -static void *igmp6_mc_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct ifmcaddr6 *im = igmp6_mc_get_next(seq, v); - - ++*pos; - return im; -} - -static void igmp6_mc_seq_stop(struct seq_file *seq, void *v) - __releases(RCU) -{ - struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); - - if (likely(state->idev)) { - read_unlock_bh(&state->idev->lock); - state->idev = NULL; - } - state->dev = NULL; - rcu_read_unlock(); -} - -static int igmp6_mc_seq_show(struct seq_file *seq, void *v) -{ - struct ifmcaddr6 *im = (struct ifmcaddr6 *)v; - struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); - - seq_printf(seq, - "%-4d %-15s %pi6 %5d %08X %ld\n", - state->dev->ifindex, state->dev->name, - &im->mca_addr, - im->mca_users, im->mca_flags, - (im->mca_flags&MAF_TIMER_RUNNING) ? - jiffies_to_clock_t(im->mca_timer.expires-jiffies) : 0); - return 0; -} - -static const struct seq_operations igmp6_mc_seq_ops = { - .start = igmp6_mc_seq_start, - .next = igmp6_mc_seq_next, - .stop = igmp6_mc_seq_stop, - .show = igmp6_mc_seq_show, -}; - -static int igmp6_mc_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &igmp6_mc_seq_ops, - sizeof(struct igmp6_mc_iter_state)); -} - -static const struct file_operations igmp6_mc_seq_fops = { - .owner = THIS_MODULE, - .open = igmp6_mc_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -struct igmp6_mcf_iter_state { - struct seq_net_private p; - struct net_device *dev; - struct inet6_dev *idev; - struct ifmcaddr6 *im; -}; - -#define igmp6_mcf_seq_private(seq) ((struct igmp6_mcf_iter_state *)(seq)->private) - -static inline struct ip6_sf_list *igmp6_mcf_get_first(struct seq_file *seq) -{ - struct ip6_sf_list *psf = NULL; - struct ifmcaddr6 *im = NULL; - struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); - struct net *net = seq_file_net(seq); - - state->idev = NULL; - state->im = NULL; - for_each_netdev_rcu(net, state->dev) { - struct inet6_dev *idev; - idev = __in6_dev_get(state->dev); - if (unlikely(idev == NULL)) - continue; - read_lock_bh(&idev->lock); - im = idev->mc_list; - if (likely(im)) { - spin_lock_bh(&im->mca_lock); - psf = im->mca_sources; - if (likely(psf)) { - state->im = im; - state->idev = idev; - break; - } - spin_unlock_bh(&im->mca_lock); - } - read_unlock_bh(&idev->lock); - } - return psf; -} - -static struct ip6_sf_list *igmp6_mcf_get_next(struct seq_file *seq, struct ip6_sf_list *psf) -{ - struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); - - psf = psf->sf_next; - while (!psf) { - spin_unlock_bh(&state->im->mca_lock); - state->im = state->im->next; - while (!state->im) { - if (likely(state->idev)) - read_unlock_bh(&state->idev->lock); - - state->dev = next_net_device_rcu(state->dev); - if (!state->dev) { - state->idev = NULL; - goto out; - } - state->idev = __in6_dev_get(state->dev); - if (!state->idev) - continue; - read_lock_bh(&state->idev->lock); - state->im = state->idev->mc_list; - } - if (!state->im) - break; - spin_lock_bh(&state->im->mca_lock); - psf = state->im->mca_sources; - } -out: - return psf; -} - -static struct ip6_sf_list *igmp6_mcf_get_idx(struct seq_file *seq, loff_t pos) -{ - struct ip6_sf_list *psf = igmp6_mcf_get_first(seq); - if (psf) - while (pos && (psf = igmp6_mcf_get_next(seq, psf)) != NULL) - --pos; - return pos ? NULL : psf; -} - -static void *igmp6_mcf_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(RCU) -{ - rcu_read_lock(); - return *pos ? igmp6_mcf_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; -} - -static void *igmp6_mcf_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - struct ip6_sf_list *psf; - if (v == SEQ_START_TOKEN) - psf = igmp6_mcf_get_first(seq); - else - psf = igmp6_mcf_get_next(seq, v); - ++*pos; - return psf; -} - -static void igmp6_mcf_seq_stop(struct seq_file *seq, void *v) - __releases(RCU) -{ - struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); - if (likely(state->im)) { - spin_unlock_bh(&state->im->mca_lock); - state->im = NULL; - } - if (likely(state->idev)) { - read_unlock_bh(&state->idev->lock); - state->idev = NULL; - } - state->dev = NULL; - rcu_read_unlock(); -} - -static int igmp6_mcf_seq_show(struct seq_file *seq, void *v) -{ - struct ip6_sf_list *psf = (struct ip6_sf_list *)v; - struct igmp6_mcf_iter_state *state = igmp6_mcf_seq_private(seq); - - if (v == SEQ_START_TOKEN) { - seq_puts(seq, "Idx Device Multicast Address Source Address INC EXC\n"); - } else { - seq_printf(seq, - "%3d %6.6s %pi6 %pi6 %6lu %6lu\n", - state->dev->ifindex, state->dev->name, - &state->im->mca_addr, - &psf->sf_addr, - psf->sf_count[MCAST_INCLUDE], - psf->sf_count[MCAST_EXCLUDE]); - } - return 0; -} - -static const struct seq_operations igmp6_mcf_seq_ops = { - .start = igmp6_mcf_seq_start, - .next = igmp6_mcf_seq_next, - .stop = igmp6_mcf_seq_stop, - .show = igmp6_mcf_seq_show, -}; - -static int igmp6_mcf_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &igmp6_mcf_seq_ops, - sizeof(struct igmp6_mcf_iter_state)); -} - -static const struct file_operations igmp6_mcf_seq_fops = { - .owner = THIS_MODULE, - .open = igmp6_mcf_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -static int __net_init igmp6_proc_init(struct net *net) -{ - int err; - - err = -ENOMEM; - if (!proc_create("igmp6", S_IRUGO, net->proc_net, &igmp6_mc_seq_fops)) - goto out; - if (!proc_create("mcfilter6", S_IRUGO, net->proc_net, - &igmp6_mcf_seq_fops)) - goto out_proc_net_igmp6; - - err = 0; -out: - return err; - -out_proc_net_igmp6: - remove_proc_entry("igmp6", net->proc_net); - goto out; -} - -static void __net_exit igmp6_proc_exit(struct net *net) -{ - remove_proc_entry("mcfilter6", net->proc_net); - remove_proc_entry("igmp6", net->proc_net); -} -#else -static inline int igmp6_proc_init(struct net *net) -{ - return 0; -} -static inline void igmp6_proc_exit(struct net *net) -{ -} -#endif - -static int __net_init igmp6_net_init(struct net *net) -{ - int err; - - err = inet_ctl_sock_create(&net->ipv6.igmp_sk, PF_INET6, - SOCK_RAW, IPPROTO_ICMPV6, net); - if (err < 0) { - pr_err("Failed to initialize the IGMP6 control socket (err %d)\n", - err); - goto out; - } - - inet6_sk(net->ipv6.igmp_sk)->hop_limit = 1; - - err = inet_ctl_sock_create(&net->ipv6.mc_autojoin_sk, PF_INET6, - SOCK_RAW, IPPROTO_ICMPV6, net); - if (err < 0) { - pr_err("Failed to initialize the IGMP6 autojoin socket (err %d)\n", - err); - goto out_sock_create; - } - - err = igmp6_proc_init(net); - if (err) - goto out_sock_create_autojoin; - - return 0; - -out_sock_create_autojoin: - inet_ctl_sock_destroy(net->ipv6.mc_autojoin_sk); -out_sock_create: - inet_ctl_sock_destroy(net->ipv6.igmp_sk); -out: - return err; -} - -static void __net_exit igmp6_net_exit(struct net *net) -{ - inet_ctl_sock_destroy(net->ipv6.igmp_sk); - inet_ctl_sock_destroy(net->ipv6.mc_autojoin_sk); - igmp6_proc_exit(net); -} - -static struct pernet_operations igmp6_net_ops = { - .init = igmp6_net_init, - .exit = igmp6_net_exit, -}; - -int __init igmp6_init(void) -{ - return register_pernet_subsys(&igmp6_net_ops); -} - -void igmp6_cleanup(void) -{ - unregister_pernet_subsys(&igmp6_net_ops); -} diff --git a/src/linux/net/ipv6/mcast_snoop.c b/src/linux/net/ipv6/mcast_snoop.c deleted file mode 100644 index 9405b04..0000000 --- a/src/linux/net/ipv6/mcast_snoop.c +++ /dev/null @@ -1,216 +0,0 @@ -/* Copyright (C) 2010: YOSHIFUJI Hideaki - * Copyright (C) 2015: Linus Lüssing - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, see . - * - * - * Based on the MLD support added to br_multicast.c by YOSHIFUJI Hideaki. - */ - -#include -#include -#include -#include -#include - -static int ipv6_mc_check_ip6hdr(struct sk_buff *skb) -{ - const struct ipv6hdr *ip6h; - unsigned int len; - unsigned int offset = skb_network_offset(skb) + sizeof(*ip6h); - - if (!pskb_may_pull(skb, offset)) - return -EINVAL; - - ip6h = ipv6_hdr(skb); - - if (ip6h->version != 6) - return -EINVAL; - - len = offset + ntohs(ip6h->payload_len); - if (skb->len < len || len <= offset) - return -EINVAL; - - return 0; -} - -static int ipv6_mc_check_exthdrs(struct sk_buff *skb) -{ - const struct ipv6hdr *ip6h; - int offset; - u8 nexthdr; - __be16 frag_off; - - ip6h = ipv6_hdr(skb); - - if (ip6h->nexthdr != IPPROTO_HOPOPTS) - return -ENOMSG; - - nexthdr = ip6h->nexthdr; - offset = skb_network_offset(skb) + sizeof(*ip6h); - offset = ipv6_skip_exthdr(skb, offset, &nexthdr, &frag_off); - - if (offset < 0) - return -EINVAL; - - if (nexthdr != IPPROTO_ICMPV6) - return -ENOMSG; - - skb_set_transport_header(skb, offset); - - return 0; -} - -static int ipv6_mc_check_mld_reportv2(struct sk_buff *skb) -{ - unsigned int len = skb_transport_offset(skb); - - len += sizeof(struct mld2_report); - - return pskb_may_pull(skb, len) ? 0 : -EINVAL; -} - -static int ipv6_mc_check_mld_query(struct sk_buff *skb) -{ - struct mld_msg *mld; - unsigned int len = skb_transport_offset(skb); - - /* RFC2710+RFC3810 (MLDv1+MLDv2) require link-local source addresses */ - if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) - return -EINVAL; - - len += sizeof(struct mld_msg); - if (skb->len < len) - return -EINVAL; - - /* MLDv1? */ - if (skb->len != len) { - /* or MLDv2? */ - len += sizeof(struct mld2_query) - sizeof(struct mld_msg); - if (skb->len < len || !pskb_may_pull(skb, len)) - return -EINVAL; - } - - mld = (struct mld_msg *)skb_transport_header(skb); - - /* RFC2710+RFC3810 (MLDv1+MLDv2) require the multicast link layer - * all-nodes destination address (ff02::1) for general queries - */ - if (ipv6_addr_any(&mld->mld_mca) && - !ipv6_addr_is_ll_all_nodes(&ipv6_hdr(skb)->daddr)) - return -EINVAL; - - return 0; -} - -static int ipv6_mc_check_mld_msg(struct sk_buff *skb) -{ - struct mld_msg *mld = (struct mld_msg *)skb_transport_header(skb); - - switch (mld->mld_type) { - case ICMPV6_MGM_REDUCTION: - case ICMPV6_MGM_REPORT: - /* fall through */ - return 0; - case ICMPV6_MLD2_REPORT: - return ipv6_mc_check_mld_reportv2(skb); - case ICMPV6_MGM_QUERY: - return ipv6_mc_check_mld_query(skb); - default: - return -ENOMSG; - } -} - -static inline __sum16 ipv6_mc_validate_checksum(struct sk_buff *skb) -{ - return skb_checksum_validate(skb, IPPROTO_ICMPV6, ip6_compute_pseudo); -} - -static int __ipv6_mc_check_mld(struct sk_buff *skb, - struct sk_buff **skb_trimmed) - -{ - struct sk_buff *skb_chk = NULL; - unsigned int transport_len; - unsigned int len = skb_transport_offset(skb) + sizeof(struct mld_msg); - int ret = -EINVAL; - - transport_len = ntohs(ipv6_hdr(skb)->payload_len); - transport_len -= skb_transport_offset(skb) - sizeof(struct ipv6hdr); - - skb_chk = skb_checksum_trimmed(skb, transport_len, - ipv6_mc_validate_checksum); - if (!skb_chk) - goto err; - - if (!pskb_may_pull(skb_chk, len)) - goto err; - - ret = ipv6_mc_check_mld_msg(skb_chk); - if (ret) - goto err; - - if (skb_trimmed) - *skb_trimmed = skb_chk; - /* free now unneeded clone */ - else if (skb_chk != skb) - kfree_skb(skb_chk); - - ret = 0; - -err: - if (ret && skb_chk && skb_chk != skb) - kfree_skb(skb_chk); - - return ret; -} - -/** - * ipv6_mc_check_mld - checks whether this is a sane MLD packet - * @skb: the skb to validate - * @skb_trimmed: to store an skb pointer trimmed to IPv6 packet tail (optional) - * - * Checks whether an IPv6 packet is a valid MLD packet. If so sets - * skb transport header accordingly and returns zero. - * - * -EINVAL: A broken packet was detected, i.e. it violates some internet - * standard - * -ENOMSG: IP header validation succeeded but it is not an MLD packet. - * -ENOMEM: A memory allocation failure happened. - * - * Optionally, an skb pointer might be provided via skb_trimmed (or set it - * to NULL): After parsing an MLD packet successfully it will point to - * an skb which has its tail aligned to the IP packet end. This might - * either be the originally provided skb or a trimmed, cloned version if - * the skb frame had data beyond the IP packet. A cloned skb allows us - * to leave the original skb and its full frame unchanged (which might be - * desirable for layer 2 frame jugglers). - * - * Caller needs to set the skb network header and free any returned skb if it - * differs from the provided skb. - */ -int ipv6_mc_check_mld(struct sk_buff *skb, struct sk_buff **skb_trimmed) -{ - int ret; - - ret = ipv6_mc_check_ip6hdr(skb); - if (ret < 0) - return ret; - - ret = ipv6_mc_check_exthdrs(skb); - if (ret < 0) - return ret; - - return __ipv6_mc_check_mld(skb, skb_trimmed); -} -EXPORT_SYMBOL(ipv6_mc_check_mld); diff --git a/src/linux/net/ipv6/ndisc.c b/src/linux/net/ipv6/ndisc.c deleted file mode 100644 index d8e6714..0000000 --- a/src/linux/net/ipv6/ndisc.c +++ /dev/null @@ -1,1890 +0,0 @@ -/* - * Neighbour Discovery for IPv6 - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * Mike Shaver - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -/* - * Changes: - * - * Alexey I. Froloff : RFC6106 (DNSSL) support - * Pierre Ynard : export userland ND options - * through netlink (RDNSS support) - * Lars Fenneberg : fixed MTU setting on receipt - * of an RA. - * Janos Farkas : kmalloc failure checks - * Alexey Kuznetsov : state machine reworked - * and moved to net/core. - * Pekka Savola : RFC2461 validation - * YOSHIFUJI Hideaki @USAGI : Verify ND options properly - */ - -#define pr_fmt(fmt) "ICMPv6: " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_SYSCTL -#include -#endif - -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include - -static u32 ndisc_hash(const void *pkey, - const struct net_device *dev, - __u32 *hash_rnd); -static bool ndisc_key_eq(const struct neighbour *neigh, const void *pkey); -static int ndisc_constructor(struct neighbour *neigh); -static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); -static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb); -static int pndisc_constructor(struct pneigh_entry *n); -static void pndisc_destructor(struct pneigh_entry *n); -static void pndisc_redo(struct sk_buff *skb); - -static const struct neigh_ops ndisc_generic_ops = { - .family = AF_INET6, - .solicit = ndisc_solicit, - .error_report = ndisc_error_report, - .output = neigh_resolve_output, - .connected_output = neigh_connected_output, -}; - -static const struct neigh_ops ndisc_hh_ops = { - .family = AF_INET6, - .solicit = ndisc_solicit, - .error_report = ndisc_error_report, - .output = neigh_resolve_output, - .connected_output = neigh_resolve_output, -}; - - -static const struct neigh_ops ndisc_direct_ops = { - .family = AF_INET6, - .output = neigh_direct_output, - .connected_output = neigh_direct_output, -}; - -struct neigh_table nd_tbl = { - .family = AF_INET6, - .key_len = sizeof(struct in6_addr), - .protocol = cpu_to_be16(ETH_P_IPV6), - .hash = ndisc_hash, - .key_eq = ndisc_key_eq, - .constructor = ndisc_constructor, - .pconstructor = pndisc_constructor, - .pdestructor = pndisc_destructor, - .proxy_redo = pndisc_redo, - .id = "ndisc_cache", - .parms = { - .tbl = &nd_tbl, - .reachable_time = ND_REACHABLE_TIME, - .data = { - [NEIGH_VAR_MCAST_PROBES] = 3, - [NEIGH_VAR_UCAST_PROBES] = 3, - [NEIGH_VAR_RETRANS_TIME] = ND_RETRANS_TIMER, - [NEIGH_VAR_BASE_REACHABLE_TIME] = ND_REACHABLE_TIME, - [NEIGH_VAR_DELAY_PROBE_TIME] = 5 * HZ, - [NEIGH_VAR_GC_STALETIME] = 60 * HZ, - [NEIGH_VAR_QUEUE_LEN_BYTES] = 64 * 1024, - [NEIGH_VAR_PROXY_QLEN] = 64, - [NEIGH_VAR_ANYCAST_DELAY] = 1 * HZ, - [NEIGH_VAR_PROXY_DELAY] = (8 * HZ) / 10, - }, - }, - .gc_interval = 30 * HZ, - .gc_thresh1 = 128, - .gc_thresh2 = 512, - .gc_thresh3 = 1024, -}; -EXPORT_SYMBOL_GPL(nd_tbl); - -void __ndisc_fill_addr_option(struct sk_buff *skb, int type, void *data, - int data_len, int pad) -{ - int space = __ndisc_opt_addr_space(data_len, pad); - u8 *opt = skb_put(skb, space); - - opt[0] = type; - opt[1] = space>>3; - - memset(opt + 2, 0, pad); - opt += pad; - space -= pad; - - memcpy(opt+2, data, data_len); - data_len += 2; - opt += data_len; - space -= data_len; - if (space > 0) - memset(opt, 0, space); -} -EXPORT_SYMBOL_GPL(__ndisc_fill_addr_option); - -static inline void ndisc_fill_addr_option(struct sk_buff *skb, int type, - void *data, u8 icmp6_type) -{ - __ndisc_fill_addr_option(skb, type, data, skb->dev->addr_len, - ndisc_addr_option_pad(skb->dev->type)); - ndisc_ops_fill_addr_option(skb->dev, skb, icmp6_type); -} - -static inline void ndisc_fill_redirect_addr_option(struct sk_buff *skb, - void *ha, - const u8 *ops_data) -{ - ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, ha, NDISC_REDIRECT); - ndisc_ops_fill_redirect_addr_option(skb->dev, skb, ops_data); -} - -static struct nd_opt_hdr *ndisc_next_option(struct nd_opt_hdr *cur, - struct nd_opt_hdr *end) -{ - int type; - if (!cur || !end || cur >= end) - return NULL; - type = cur->nd_opt_type; - do { - cur = ((void *)cur) + (cur->nd_opt_len << 3); - } while (cur < end && cur->nd_opt_type != type); - return cur <= end && cur->nd_opt_type == type ? cur : NULL; -} - -static inline int ndisc_is_useropt(const struct net_device *dev, - struct nd_opt_hdr *opt) -{ - return opt->nd_opt_type == ND_OPT_RDNSS || - opt->nd_opt_type == ND_OPT_DNSSL || - ndisc_ops_is_useropt(dev, opt->nd_opt_type); -} - -static struct nd_opt_hdr *ndisc_next_useropt(const struct net_device *dev, - struct nd_opt_hdr *cur, - struct nd_opt_hdr *end) -{ - if (!cur || !end || cur >= end) - return NULL; - do { - cur = ((void *)cur) + (cur->nd_opt_len << 3); - } while (cur < end && !ndisc_is_useropt(dev, cur)); - return cur <= end && ndisc_is_useropt(dev, cur) ? cur : NULL; -} - -struct ndisc_options *ndisc_parse_options(const struct net_device *dev, - u8 *opt, int opt_len, - struct ndisc_options *ndopts) -{ - struct nd_opt_hdr *nd_opt = (struct nd_opt_hdr *)opt; - - if (!nd_opt || opt_len < 0 || !ndopts) - return NULL; - memset(ndopts, 0, sizeof(*ndopts)); - while (opt_len) { - int l; - if (opt_len < sizeof(struct nd_opt_hdr)) - return NULL; - l = nd_opt->nd_opt_len << 3; - if (opt_len < l || l == 0) - return NULL; - if (ndisc_ops_parse_options(dev, nd_opt, ndopts)) - goto next_opt; - switch (nd_opt->nd_opt_type) { - case ND_OPT_SOURCE_LL_ADDR: - case ND_OPT_TARGET_LL_ADDR: - case ND_OPT_MTU: - case ND_OPT_REDIRECT_HDR: - if (ndopts->nd_opt_array[nd_opt->nd_opt_type]) { - ND_PRINTK(2, warn, - "%s: duplicated ND6 option found: type=%d\n", - __func__, nd_opt->nd_opt_type); - } else { - ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; - } - break; - case ND_OPT_PREFIX_INFO: - ndopts->nd_opts_pi_end = nd_opt; - if (!ndopts->nd_opt_array[nd_opt->nd_opt_type]) - ndopts->nd_opt_array[nd_opt->nd_opt_type] = nd_opt; - break; -#ifdef CONFIG_IPV6_ROUTE_INFO - case ND_OPT_ROUTE_INFO: - ndopts->nd_opts_ri_end = nd_opt; - if (!ndopts->nd_opts_ri) - ndopts->nd_opts_ri = nd_opt; - break; -#endif - default: - if (ndisc_is_useropt(dev, nd_opt)) { - ndopts->nd_useropts_end = nd_opt; - if (!ndopts->nd_useropts) - ndopts->nd_useropts = nd_opt; - } else { - /* - * Unknown options must be silently ignored, - * to accommodate future extension to the - * protocol. - */ - ND_PRINTK(2, notice, - "%s: ignored unsupported option; type=%d, len=%d\n", - __func__, - nd_opt->nd_opt_type, - nd_opt->nd_opt_len); - } - } -next_opt: - opt_len -= l; - nd_opt = ((void *)nd_opt) + l; - } - return ndopts; -} - -int ndisc_mc_map(const struct in6_addr *addr, char *buf, struct net_device *dev, int dir) -{ - switch (dev->type) { - case ARPHRD_ETHER: - case ARPHRD_IEEE802: /* Not sure. Check it later. --ANK */ - case ARPHRD_FDDI: - ipv6_eth_mc_map(addr, buf); - return 0; - case ARPHRD_ARCNET: - ipv6_arcnet_mc_map(addr, buf); - return 0; - case ARPHRD_INFINIBAND: - ipv6_ib_mc_map(addr, dev->broadcast, buf); - return 0; - case ARPHRD_IPGRE: - return ipv6_ipgre_mc_map(addr, dev->broadcast, buf); - default: - if (dir) { - memcpy(buf, dev->broadcast, dev->addr_len); - return 0; - } - } - return -EINVAL; -} -EXPORT_SYMBOL(ndisc_mc_map); - -static u32 ndisc_hash(const void *pkey, - const struct net_device *dev, - __u32 *hash_rnd) -{ - return ndisc_hashfn(pkey, dev, hash_rnd); -} - -static bool ndisc_key_eq(const struct neighbour *n, const void *pkey) -{ - return neigh_key_eq128(n, pkey); -} - -static int ndisc_constructor(struct neighbour *neigh) -{ - struct in6_addr *addr = (struct in6_addr *)&neigh->primary_key; - struct net_device *dev = neigh->dev; - struct inet6_dev *in6_dev; - struct neigh_parms *parms; - bool is_multicast = ipv6_addr_is_multicast(addr); - - in6_dev = in6_dev_get(dev); - if (!in6_dev) { - return -EINVAL; - } - - parms = in6_dev->nd_parms; - __neigh_parms_put(neigh->parms); - neigh->parms = neigh_parms_clone(parms); - - neigh->type = is_multicast ? RTN_MULTICAST : RTN_UNICAST; - if (!dev->header_ops) { - neigh->nud_state = NUD_NOARP; - neigh->ops = &ndisc_direct_ops; - neigh->output = neigh_direct_output; - } else { - if (is_multicast) { - neigh->nud_state = NUD_NOARP; - ndisc_mc_map(addr, neigh->ha, dev, 1); - } else if (dev->flags&(IFF_NOARP|IFF_LOOPBACK)) { - neigh->nud_state = NUD_NOARP; - memcpy(neigh->ha, dev->dev_addr, dev->addr_len); - if (dev->flags&IFF_LOOPBACK) - neigh->type = RTN_LOCAL; - } else if (dev->flags&IFF_POINTOPOINT) { - neigh->nud_state = NUD_NOARP; - memcpy(neigh->ha, dev->broadcast, dev->addr_len); - } - if (dev->header_ops->cache) - neigh->ops = &ndisc_hh_ops; - else - neigh->ops = &ndisc_generic_ops; - if (neigh->nud_state&NUD_VALID) - neigh->output = neigh->ops->connected_output; - else - neigh->output = neigh->ops->output; - } - in6_dev_put(in6_dev); - return 0; -} - -static int pndisc_constructor(struct pneigh_entry *n) -{ - struct in6_addr *addr = (struct in6_addr *)&n->key; - struct in6_addr maddr; - struct net_device *dev = n->dev; - - if (!dev || !__in6_dev_get(dev)) - return -EINVAL; - addrconf_addr_solict_mult(addr, &maddr); - ipv6_dev_mc_inc(dev, &maddr); - return 0; -} - -static void pndisc_destructor(struct pneigh_entry *n) -{ - struct in6_addr *addr = (struct in6_addr *)&n->key; - struct in6_addr maddr; - struct net_device *dev = n->dev; - - if (!dev || !__in6_dev_get(dev)) - return; - addrconf_addr_solict_mult(addr, &maddr); - ipv6_dev_mc_dec(dev, &maddr); -} - -static struct sk_buff *ndisc_alloc_skb(struct net_device *dev, - int len) -{ - int hlen = LL_RESERVED_SPACE(dev); - int tlen = dev->needed_tailroom; - struct sock *sk = dev_net(dev)->ipv6.ndisc_sk; - struct sk_buff *skb; - - skb = alloc_skb(hlen + sizeof(struct ipv6hdr) + len + tlen, GFP_ATOMIC); - if (!skb) { - ND_PRINTK(0, err, "ndisc: %s failed to allocate an skb\n", - __func__); - return NULL; - } - - skb->protocol = htons(ETH_P_IPV6); - skb->dev = dev; - - skb_reserve(skb, hlen + sizeof(struct ipv6hdr)); - skb_reset_transport_header(skb); - - /* Manually assign socket ownership as we avoid calling - * sock_alloc_send_pskb() to bypass wmem buffer limits - */ - skb_set_owner_w(skb, sk); - - return skb; -} - -static void ip6_nd_hdr(struct sk_buff *skb, - const struct in6_addr *saddr, - const struct in6_addr *daddr, - int hop_limit, int len) -{ - struct ipv6hdr *hdr; - - skb_push(skb, sizeof(*hdr)); - skb_reset_network_header(skb); - hdr = ipv6_hdr(skb); - - ip6_flow_hdr(hdr, 0, 0); - - hdr->payload_len = htons(len); - hdr->nexthdr = IPPROTO_ICMPV6; - hdr->hop_limit = hop_limit; - - hdr->saddr = *saddr; - hdr->daddr = *daddr; -} - -static void ndisc_send_skb(struct sk_buff *skb, - const struct in6_addr *daddr, - const struct in6_addr *saddr) -{ - struct dst_entry *dst = skb_dst(skb); - struct net *net = dev_net(skb->dev); - struct sock *sk = net->ipv6.ndisc_sk; - struct inet6_dev *idev; - int err; - struct icmp6hdr *icmp6h = icmp6_hdr(skb); - u8 type; - - type = icmp6h->icmp6_type; - - if (!dst) { - struct flowi6 fl6; - int oif = skb->dev->ifindex; - - icmpv6_flow_init(sk, &fl6, type, saddr, daddr, oif); - dst = icmp6_dst_alloc(skb->dev, &fl6); - if (IS_ERR(dst)) { - kfree_skb(skb); - return; - } - - skb_dst_set(skb, dst); - } - - icmp6h->icmp6_cksum = csum_ipv6_magic(saddr, daddr, skb->len, - IPPROTO_ICMPV6, - csum_partial(icmp6h, - skb->len, 0)); - - ip6_nd_hdr(skb, saddr, daddr, inet6_sk(sk)->hop_limit, skb->len); - - rcu_read_lock(); - idev = __in6_dev_get(dst->dev); - IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len); - - err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, - net, sk, skb, NULL, dst->dev, - dst_output); - if (!err) { - ICMP6MSGOUT_INC_STATS(net, idev, type); - ICMP6_INC_STATS(net, idev, ICMP6_MIB_OUTMSGS); - } - - rcu_read_unlock(); -} - -void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr, - const struct in6_addr *solicited_addr, - bool router, bool solicited, bool override, bool inc_opt) -{ - struct sk_buff *skb; - struct in6_addr tmpaddr; - struct inet6_ifaddr *ifp; - const struct in6_addr *src_addr; - struct nd_msg *msg; - int optlen = 0; - - /* for anycast or proxy, solicited_addr != src_addr */ - ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1); - if (ifp) { - src_addr = solicited_addr; - if (ifp->flags & IFA_F_OPTIMISTIC) - override = false; - inc_opt |= ifp->idev->cnf.force_tllao; - in6_ifa_put(ifp); - } else { - if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr, - inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs, - &tmpaddr)) - return; - src_addr = &tmpaddr; - } - - if (!dev->addr_len) - inc_opt = 0; - if (inc_opt) - optlen += ndisc_opt_addr_space(dev, - NDISC_NEIGHBOUR_ADVERTISEMENT); - - skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); - if (!skb) - return; - - msg = (struct nd_msg *)skb_put(skb, sizeof(*msg)); - *msg = (struct nd_msg) { - .icmph = { - .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, - .icmp6_router = router, - .icmp6_solicited = solicited, - .icmp6_override = override, - }, - .target = *solicited_addr, - }; - - if (inc_opt) - ndisc_fill_addr_option(skb, ND_OPT_TARGET_LL_ADDR, - dev->dev_addr, - NDISC_NEIGHBOUR_ADVERTISEMENT); - - ndisc_send_skb(skb, daddr, src_addr); -} - -static void ndisc_send_unsol_na(struct net_device *dev) -{ - struct inet6_dev *idev; - struct inet6_ifaddr *ifa; - - idev = in6_dev_get(dev); - if (!idev) - return; - - read_lock_bh(&idev->lock); - list_for_each_entry(ifa, &idev->addr_list, if_list) { - ndisc_send_na(dev, &in6addr_linklocal_allnodes, &ifa->addr, - /*router=*/ !!idev->cnf.forwarding, - /*solicited=*/ false, /*override=*/ true, - /*inc_opt=*/ true); - } - read_unlock_bh(&idev->lock); - - in6_dev_put(idev); -} - -void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit, - const struct in6_addr *daddr, const struct in6_addr *saddr) -{ - struct sk_buff *skb; - struct in6_addr addr_buf; - int inc_opt = dev->addr_len; - int optlen = 0; - struct nd_msg *msg; - - if (!saddr) { - if (ipv6_get_lladdr(dev, &addr_buf, - (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC))) - return; - saddr = &addr_buf; - } - - if (ipv6_addr_any(saddr)) - inc_opt = false; - if (inc_opt) - optlen += ndisc_opt_addr_space(dev, - NDISC_NEIGHBOUR_SOLICITATION); - - skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); - if (!skb) - return; - - msg = (struct nd_msg *)skb_put(skb, sizeof(*msg)); - *msg = (struct nd_msg) { - .icmph = { - .icmp6_type = NDISC_NEIGHBOUR_SOLICITATION, - }, - .target = *solicit, - }; - - if (inc_opt) - ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR, - dev->dev_addr, - NDISC_NEIGHBOUR_SOLICITATION); - - ndisc_send_skb(skb, daddr, saddr); -} - -void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, - const struct in6_addr *daddr) -{ - struct sk_buff *skb; - struct rs_msg *msg; - int send_sllao = dev->addr_len; - int optlen = 0; - -#ifdef CONFIG_IPV6_OPTIMISTIC_DAD - /* - * According to section 2.2 of RFC 4429, we must not - * send router solicitations with a sllao from - * optimistic addresses, but we may send the solicitation - * if we don't include the sllao. So here we check - * if our address is optimistic, and if so, we - * suppress the inclusion of the sllao. - */ - if (send_sllao) { - struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr, - dev, 1); - if (ifp) { - if (ifp->flags & IFA_F_OPTIMISTIC) { - send_sllao = 0; - } - in6_ifa_put(ifp); - } else { - send_sllao = 0; - } - } -#endif - if (send_sllao) - optlen += ndisc_opt_addr_space(dev, NDISC_ROUTER_SOLICITATION); - - skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); - if (!skb) - return; - - msg = (struct rs_msg *)skb_put(skb, sizeof(*msg)); - *msg = (struct rs_msg) { - .icmph = { - .icmp6_type = NDISC_ROUTER_SOLICITATION, - }, - }; - - if (send_sllao) - ndisc_fill_addr_option(skb, ND_OPT_SOURCE_LL_ADDR, - dev->dev_addr, - NDISC_ROUTER_SOLICITATION); - - ndisc_send_skb(skb, daddr, saddr); -} - - -static void ndisc_error_report(struct neighbour *neigh, struct sk_buff *skb) -{ - /* - * "The sender MUST return an ICMP - * destination unreachable" - */ - dst_link_failure(skb); - kfree_skb(skb); -} - -/* Called with locked neigh: either read or both */ - -static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) -{ - struct in6_addr *saddr = NULL; - struct in6_addr mcaddr; - struct net_device *dev = neigh->dev; - struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; - int probes = atomic_read(&neigh->probes); - - if (skb && ipv6_chk_addr_and_flags(dev_net(dev), &ipv6_hdr(skb)->saddr, - dev, 1, - IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) - saddr = &ipv6_hdr(skb)->saddr; - probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES); - if (probes < 0) { - if (!(neigh->nud_state & NUD_VALID)) { - ND_PRINTK(1, dbg, - "%s: trying to ucast probe in NUD_INVALID: %pI6\n", - __func__, target); - } - ndisc_send_ns(dev, target, target, saddr); - } else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) { - neigh_app_ns(neigh); - } else { - addrconf_addr_solict_mult(target, &mcaddr); - ndisc_send_ns(dev, target, &mcaddr, saddr); - } -} - -static int pndisc_is_router(const void *pkey, - struct net_device *dev) -{ - struct pneigh_entry *n; - int ret = -1; - - read_lock_bh(&nd_tbl.lock); - n = __pneigh_lookup(&nd_tbl, dev_net(dev), pkey, dev); - if (n) - ret = !!(n->flags & NTF_ROUTER); - read_unlock_bh(&nd_tbl.lock); - - return ret; -} - -void ndisc_update(const struct net_device *dev, struct neighbour *neigh, - const u8 *lladdr, u8 new, u32 flags, u8 icmp6_type, - struct ndisc_options *ndopts) -{ - neigh_update(neigh, lladdr, new, flags); - /* report ndisc ops about neighbour update */ - ndisc_ops_update(dev, neigh, flags, icmp6_type, ndopts); -} - -static void ndisc_recv_ns(struct sk_buff *skb) -{ - struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); - const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; - const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; - u8 *lladdr = NULL; - u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) + - offsetof(struct nd_msg, opt)); - struct ndisc_options ndopts; - struct net_device *dev = skb->dev; - struct inet6_ifaddr *ifp; - struct inet6_dev *idev = NULL; - struct neighbour *neigh; - int dad = ipv6_addr_any(saddr); - bool inc; - int is_router = -1; - - if (skb->len < sizeof(struct nd_msg)) { - ND_PRINTK(2, warn, "NS: packet too short\n"); - return; - } - - if (ipv6_addr_is_multicast(&msg->target)) { - ND_PRINTK(2, warn, "NS: multicast target address\n"); - return; - } - - /* - * RFC2461 7.1.1: - * DAD has to be destined for solicited node multicast address. - */ - if (dad && !ipv6_addr_is_solict_mult(daddr)) { - ND_PRINTK(2, warn, "NS: bad DAD packet (wrong destination)\n"); - return; - } - - if (!ndisc_parse_options(dev, msg->opt, ndoptlen, &ndopts)) { - ND_PRINTK(2, warn, "NS: invalid ND options\n"); - return; - } - - if (ndopts.nd_opts_src_lladdr) { - lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, dev); - if (!lladdr) { - ND_PRINTK(2, warn, - "NS: invalid link-layer address length\n"); - return; - } - - /* RFC2461 7.1.1: - * If the IP source address is the unspecified address, - * there MUST NOT be source link-layer address option - * in the message. - */ - if (dad) { - ND_PRINTK(2, warn, - "NS: bad DAD packet (link-layer address option)\n"); - return; - } - } - - inc = ipv6_addr_is_multicast(daddr); - - ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); - if (ifp) { -have_ifp: - if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) { - if (dad) { - /* - * We are colliding with another node - * who is doing DAD - * so fail our DAD process - */ - addrconf_dad_failure(ifp); - return; - } else { - /* - * This is not a dad solicitation. - * If we are an optimistic node, - * we should respond. - * Otherwise, we should ignore it. - */ - if (!(ifp->flags & IFA_F_OPTIMISTIC)) - goto out; - } - } - - idev = ifp->idev; - } else { - struct net *net = dev_net(dev); - - /* perhaps an address on the master device */ - if (netif_is_l3_slave(dev)) { - struct net_device *mdev; - - mdev = netdev_master_upper_dev_get_rcu(dev); - if (mdev) { - ifp = ipv6_get_ifaddr(net, &msg->target, mdev, 1); - if (ifp) - goto have_ifp; - } - } - - idev = in6_dev_get(dev); - if (!idev) { - /* XXX: count this drop? */ - return; - } - - if (ipv6_chk_acast_addr(net, dev, &msg->target) || - (idev->cnf.forwarding && - (net->ipv6.devconf_all->proxy_ndp || idev->cnf.proxy_ndp) && - (is_router = pndisc_is_router(&msg->target, dev)) >= 0)) { - if (!(NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED) && - skb->pkt_type != PACKET_HOST && - inc && - NEIGH_VAR(idev->nd_parms, PROXY_DELAY) != 0) { - /* - * for anycast or proxy, - * sender should delay its response - * by a random time between 0 and - * MAX_ANYCAST_DELAY_TIME seconds. - * (RFC2461) -- yoshfuji - */ - struct sk_buff *n = skb_clone(skb, GFP_ATOMIC); - if (n) - pneigh_enqueue(&nd_tbl, idev->nd_parms, n); - goto out; - } - } else - goto out; - } - - if (is_router < 0) - is_router = idev->cnf.forwarding; - - if (dad) { - ndisc_send_na(dev, &in6addr_linklocal_allnodes, &msg->target, - !!is_router, false, (ifp != NULL), true); - goto out; - } - - if (inc) - NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast); - else - NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast); - - /* - * update / create cache entry - * for the source address - */ - neigh = __neigh_lookup(&nd_tbl, saddr, dev, - !inc || lladdr || !dev->addr_len); - if (neigh) - ndisc_update(dev, neigh, lladdr, NUD_STALE, - NEIGH_UPDATE_F_WEAK_OVERRIDE| - NEIGH_UPDATE_F_OVERRIDE, - NDISC_NEIGHBOUR_SOLICITATION, &ndopts); - if (neigh || !dev->header_ops) { - ndisc_send_na(dev, saddr, &msg->target, !!is_router, - true, (ifp != NULL && inc), inc); - if (neigh) - neigh_release(neigh); - } - -out: - if (ifp) - in6_ifa_put(ifp); - else - in6_dev_put(idev); -} - -static void ndisc_recv_na(struct sk_buff *skb) -{ - struct nd_msg *msg = (struct nd_msg *)skb_transport_header(skb); - struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; - const struct in6_addr *daddr = &ipv6_hdr(skb)->daddr; - u8 *lladdr = NULL; - u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) + - offsetof(struct nd_msg, opt)); - struct ndisc_options ndopts; - struct net_device *dev = skb->dev; - struct inet6_dev *idev = __in6_dev_get(dev); - struct inet6_ifaddr *ifp; - struct neighbour *neigh; - - if (skb->len < sizeof(struct nd_msg)) { - ND_PRINTK(2, warn, "NA: packet too short\n"); - return; - } - - if (ipv6_addr_is_multicast(&msg->target)) { - ND_PRINTK(2, warn, "NA: target address is multicast\n"); - return; - } - - if (ipv6_addr_is_multicast(daddr) && - msg->icmph.icmp6_solicited) { - ND_PRINTK(2, warn, "NA: solicited NA is multicasted\n"); - return; - } - - /* For some 802.11 wireless deployments (and possibly other networks), - * there will be a NA proxy and unsolicitd packets are attacks - * and thus should not be accepted. - */ - if (!msg->icmph.icmp6_solicited && idev && - idev->cnf.drop_unsolicited_na) - return; - - if (!ndisc_parse_options(dev, msg->opt, ndoptlen, &ndopts)) { - ND_PRINTK(2, warn, "NS: invalid ND option\n"); - return; - } - if (ndopts.nd_opts_tgt_lladdr) { - lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, dev); - if (!lladdr) { - ND_PRINTK(2, warn, - "NA: invalid link-layer address length\n"); - return; - } - } - ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1); - if (ifp) { - if (skb->pkt_type != PACKET_LOOPBACK - && (ifp->flags & IFA_F_TENTATIVE)) { - addrconf_dad_failure(ifp); - return; - } - /* What should we make now? The advertisement - is invalid, but ndisc specs say nothing - about it. It could be misconfiguration, or - an smart proxy agent tries to help us :-) - - We should not print the error if NA has been - received from loopback - it is just our own - unsolicited advertisement. - */ - if (skb->pkt_type != PACKET_LOOPBACK) - ND_PRINTK(1, warn, - "NA: someone advertises our address %pI6 on %s!\n", - &ifp->addr, ifp->idev->dev->name); - in6_ifa_put(ifp); - return; - } - neigh = neigh_lookup(&nd_tbl, &msg->target, dev); - - if (neigh) { - u8 old_flags = neigh->flags; - struct net *net = dev_net(dev); - - if (neigh->nud_state & NUD_FAILED) - goto out; - - /* - * Don't update the neighbor cache entry on a proxy NA from - * ourselves because either the proxied node is off link or it - * has already sent a NA to us. - */ - if (lladdr && !memcmp(lladdr, dev->dev_addr, dev->addr_len) && - net->ipv6.devconf_all->forwarding && net->ipv6.devconf_all->proxy_ndp && - pneigh_lookup(&nd_tbl, net, &msg->target, dev, 0)) { - /* XXX: idev->cnf.proxy_ndp */ - goto out; - } - - ndisc_update(dev, neigh, lladdr, - msg->icmph.icmp6_solicited ? NUD_REACHABLE : NUD_STALE, - NEIGH_UPDATE_F_WEAK_OVERRIDE| - (msg->icmph.icmp6_override ? NEIGH_UPDATE_F_OVERRIDE : 0)| - NEIGH_UPDATE_F_OVERRIDE_ISROUTER| - (msg->icmph.icmp6_router ? NEIGH_UPDATE_F_ISROUTER : 0), - NDISC_NEIGHBOUR_ADVERTISEMENT, &ndopts); - - if ((old_flags & ~neigh->flags) & NTF_ROUTER) { - /* - * Change: router to host - */ - rt6_clean_tohost(dev_net(dev), saddr); - } - -out: - neigh_release(neigh); - } -} - -static void ndisc_recv_rs(struct sk_buff *skb) -{ - struct rs_msg *rs_msg = (struct rs_msg *)skb_transport_header(skb); - unsigned long ndoptlen = skb->len - sizeof(*rs_msg); - struct neighbour *neigh; - struct inet6_dev *idev; - const struct in6_addr *saddr = &ipv6_hdr(skb)->saddr; - struct ndisc_options ndopts; - u8 *lladdr = NULL; - - if (skb->len < sizeof(*rs_msg)) - return; - - idev = __in6_dev_get(skb->dev); - if (!idev) { - ND_PRINTK(1, err, "RS: can't find in6 device\n"); - return; - } - - /* Don't accept RS if we're not in router mode */ - if (!idev->cnf.forwarding) - goto out; - - /* - * Don't update NCE if src = ::; - * this implies that the source node has no ip address assigned yet. - */ - if (ipv6_addr_any(saddr)) - goto out; - - /* Parse ND options */ - if (!ndisc_parse_options(skb->dev, rs_msg->opt, ndoptlen, &ndopts)) { - ND_PRINTK(2, notice, "NS: invalid ND option, ignored\n"); - goto out; - } - - if (ndopts.nd_opts_src_lladdr) { - lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, - skb->dev); - if (!lladdr) - goto out; - } - - neigh = __neigh_lookup(&nd_tbl, saddr, skb->dev, 1); - if (neigh) { - ndisc_update(skb->dev, neigh, lladdr, NUD_STALE, - NEIGH_UPDATE_F_WEAK_OVERRIDE| - NEIGH_UPDATE_F_OVERRIDE| - NEIGH_UPDATE_F_OVERRIDE_ISROUTER, - NDISC_ROUTER_SOLICITATION, &ndopts); - neigh_release(neigh); - } -out: - return; -} - -static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt) -{ - struct icmp6hdr *icmp6h = (struct icmp6hdr *)skb_transport_header(ra); - struct sk_buff *skb; - struct nlmsghdr *nlh; - struct nduseroptmsg *ndmsg; - struct net *net = dev_net(ra->dev); - int err; - int base_size = NLMSG_ALIGN(sizeof(struct nduseroptmsg) - + (opt->nd_opt_len << 3)); - size_t msg_size = base_size + nla_total_size(sizeof(struct in6_addr)); - - skb = nlmsg_new(msg_size, GFP_ATOMIC); - if (!skb) { - err = -ENOBUFS; - goto errout; - } - - nlh = nlmsg_put(skb, 0, 0, RTM_NEWNDUSEROPT, base_size, 0); - if (!nlh) { - goto nla_put_failure; - } - - ndmsg = nlmsg_data(nlh); - ndmsg->nduseropt_family = AF_INET6; - ndmsg->nduseropt_ifindex = ra->dev->ifindex; - ndmsg->nduseropt_icmp_type = icmp6h->icmp6_type; - ndmsg->nduseropt_icmp_code = icmp6h->icmp6_code; - ndmsg->nduseropt_opts_len = opt->nd_opt_len << 3; - - memcpy(ndmsg + 1, opt, opt->nd_opt_len << 3); - - if (nla_put_in6_addr(skb, NDUSEROPT_SRCADDR, &ipv6_hdr(ra)->saddr)) - goto nla_put_failure; - nlmsg_end(skb, nlh); - - rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC); - return; - -nla_put_failure: - nlmsg_free(skb); - err = -EMSGSIZE; -errout: - rtnl_set_sk_err(net, RTNLGRP_ND_USEROPT, err); -} - -static void ndisc_router_discovery(struct sk_buff *skb) -{ - struct ra_msg *ra_msg = (struct ra_msg *)skb_transport_header(skb); - struct neighbour *neigh = NULL; - struct inet6_dev *in6_dev; - struct rt6_info *rt = NULL; - int lifetime; - struct ndisc_options ndopts; - int optlen; - unsigned int pref = 0; - __u32 old_if_flags; - bool send_ifinfo_notify = false; - - __u8 *opt = (__u8 *)(ra_msg + 1); - - optlen = (skb_tail_pointer(skb) - skb_transport_header(skb)) - - sizeof(struct ra_msg); - - ND_PRINTK(2, info, - "RA: %s, dev: %s\n", - __func__, skb->dev->name); - if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) { - ND_PRINTK(2, warn, "RA: source address is not link-local\n"); - return; - } - if (optlen < 0) { - ND_PRINTK(2, warn, "RA: packet too short\n"); - return; - } - -#ifdef CONFIG_IPV6_NDISC_NODETYPE - if (skb->ndisc_nodetype == NDISC_NODETYPE_HOST) { - ND_PRINTK(2, warn, "RA: from host or unauthorized router\n"); - return; - } -#endif - - /* - * set the RA_RECV flag in the interface - */ - - in6_dev = __in6_dev_get(skb->dev); - if (!in6_dev) { - ND_PRINTK(0, err, "RA: can't find inet6 device for %s\n", - skb->dev->name); - return; - } - - if (!ndisc_parse_options(skb->dev, opt, optlen, &ndopts)) { - ND_PRINTK(2, warn, "RA: invalid ND options\n"); - return; - } - - if (!ipv6_accept_ra(in6_dev)) { - ND_PRINTK(2, info, - "RA: %s, did not accept ra for dev: %s\n", - __func__, skb->dev->name); - goto skip_linkparms; - } - -#ifdef CONFIG_IPV6_NDISC_NODETYPE - /* skip link-specific parameters from interior routers */ - if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) { - ND_PRINTK(2, info, - "RA: %s, nodetype is NODEFAULT, dev: %s\n", - __func__, skb->dev->name); - goto skip_linkparms; - } -#endif - - if (in6_dev->if_flags & IF_RS_SENT) { - /* - * flag that an RA was received after an RS was sent - * out on this interface. - */ - in6_dev->if_flags |= IF_RA_RCVD; - } - - /* - * Remember the managed/otherconf flags from most recently - * received RA message (RFC 2462) -- yoshfuji - */ - old_if_flags = in6_dev->if_flags; - in6_dev->if_flags = (in6_dev->if_flags & ~(IF_RA_MANAGED | - IF_RA_OTHERCONF)) | - (ra_msg->icmph.icmp6_addrconf_managed ? - IF_RA_MANAGED : 0) | - (ra_msg->icmph.icmp6_addrconf_other ? - IF_RA_OTHERCONF : 0); - - if (old_if_flags != in6_dev->if_flags) - send_ifinfo_notify = true; - - if (!in6_dev->cnf.accept_ra_defrtr) { - ND_PRINTK(2, info, - "RA: %s, defrtr is false for dev: %s\n", - __func__, skb->dev->name); - goto skip_defrtr; - } - - /* Do not accept RA with source-addr found on local machine unless - * accept_ra_from_local is set to true. - */ - if (!in6_dev->cnf.accept_ra_from_local && - ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, - in6_dev->dev, 0)) { - ND_PRINTK(2, info, - "RA from local address detected on dev: %s: default router ignored\n", - skb->dev->name); - goto skip_defrtr; - } - - lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime); - -#ifdef CONFIG_IPV6_ROUTER_PREF - pref = ra_msg->icmph.icmp6_router_pref; - /* 10b is handled as if it were 00b (medium) */ - if (pref == ICMPV6_ROUTER_PREF_INVALID || - !in6_dev->cnf.accept_ra_rtr_pref) - pref = ICMPV6_ROUTER_PREF_MEDIUM; -#endif - - rt = rt6_get_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev); - - if (rt) { - neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr); - if (!neigh) { - ND_PRINTK(0, err, - "RA: %s got default router without neighbour\n", - __func__); - ip6_rt_put(rt); - return; - } - } - if (rt && lifetime == 0) { - ip6_del_rt(rt); - rt = NULL; - } - - ND_PRINTK(3, info, "RA: rt: %p lifetime: %d, for dev: %s\n", - rt, lifetime, skb->dev->name); - if (!rt && lifetime) { - ND_PRINTK(3, info, "RA: adding default router\n"); - - rt = rt6_add_dflt_router(&ipv6_hdr(skb)->saddr, skb->dev, pref); - if (!rt) { - ND_PRINTK(0, err, - "RA: %s failed to add default route\n", - __func__); - return; - } - - neigh = dst_neigh_lookup(&rt->dst, &ipv6_hdr(skb)->saddr); - if (!neigh) { - ND_PRINTK(0, err, - "RA: %s got default router without neighbour\n", - __func__); - ip6_rt_put(rt); - return; - } - neigh->flags |= NTF_ROUTER; - } else if (rt) { - rt->rt6i_flags = (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); - } - - if (rt) - rt6_set_expires(rt, jiffies + (HZ * lifetime)); - if (in6_dev->cnf.accept_ra_min_hop_limit < 256 && - ra_msg->icmph.icmp6_hop_limit) { - if (in6_dev->cnf.accept_ra_min_hop_limit <= ra_msg->icmph.icmp6_hop_limit) { - in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit; - if (rt) - dst_metric_set(&rt->dst, RTAX_HOPLIMIT, - ra_msg->icmph.icmp6_hop_limit); - } else { - ND_PRINTK(2, warn, "RA: Got route advertisement with lower hop_limit than minimum\n"); - } - } - -skip_defrtr: - - /* - * Update Reachable Time and Retrans Timer - */ - - if (in6_dev->nd_parms) { - unsigned long rtime = ntohl(ra_msg->retrans_timer); - - if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/HZ) { - rtime = (rtime*HZ)/1000; - if (rtime < HZ/10) - rtime = HZ/10; - NEIGH_VAR_SET(in6_dev->nd_parms, RETRANS_TIME, rtime); - in6_dev->tstamp = jiffies; - send_ifinfo_notify = true; - } - - rtime = ntohl(ra_msg->reachable_time); - if (rtime && rtime/1000 < MAX_SCHEDULE_TIMEOUT/(3*HZ)) { - rtime = (rtime*HZ)/1000; - - if (rtime < HZ/10) - rtime = HZ/10; - - if (rtime != NEIGH_VAR(in6_dev->nd_parms, BASE_REACHABLE_TIME)) { - NEIGH_VAR_SET(in6_dev->nd_parms, - BASE_REACHABLE_TIME, rtime); - NEIGH_VAR_SET(in6_dev->nd_parms, - GC_STALETIME, 3 * rtime); - in6_dev->nd_parms->reachable_time = neigh_rand_reach_time(rtime); - in6_dev->tstamp = jiffies; - send_ifinfo_notify = true; - } - } - } - - /* - * Send a notify if RA changed managed/otherconf flags or timer settings - */ - if (send_ifinfo_notify) - inet6_ifinfo_notify(RTM_NEWLINK, in6_dev); - -skip_linkparms: - - /* - * Process options. - */ - - if (!neigh) - neigh = __neigh_lookup(&nd_tbl, &ipv6_hdr(skb)->saddr, - skb->dev, 1); - if (neigh) { - u8 *lladdr = NULL; - if (ndopts.nd_opts_src_lladdr) { - lladdr = ndisc_opt_addr_data(ndopts.nd_opts_src_lladdr, - skb->dev); - if (!lladdr) { - ND_PRINTK(2, warn, - "RA: invalid link-layer address length\n"); - goto out; - } - } - ndisc_update(skb->dev, neigh, lladdr, NUD_STALE, - NEIGH_UPDATE_F_WEAK_OVERRIDE| - NEIGH_UPDATE_F_OVERRIDE| - NEIGH_UPDATE_F_OVERRIDE_ISROUTER| - NEIGH_UPDATE_F_ISROUTER, - NDISC_ROUTER_ADVERTISEMENT, &ndopts); - } - - if (!ipv6_accept_ra(in6_dev)) { - ND_PRINTK(2, info, - "RA: %s, accept_ra is false for dev: %s\n", - __func__, skb->dev->name); - goto out; - } - -#ifdef CONFIG_IPV6_ROUTE_INFO - if (!in6_dev->cnf.accept_ra_from_local && - ipv6_chk_addr(dev_net(in6_dev->dev), &ipv6_hdr(skb)->saddr, - in6_dev->dev, 0)) { - ND_PRINTK(2, info, - "RA from local address detected on dev: %s: router info ignored.\n", - skb->dev->name); - goto skip_routeinfo; - } - - if (in6_dev->cnf.accept_ra_rtr_pref && ndopts.nd_opts_ri) { - struct nd_opt_hdr *p; - for (p = ndopts.nd_opts_ri; - p; - p = ndisc_next_option(p, ndopts.nd_opts_ri_end)) { - struct route_info *ri = (struct route_info *)p; -#ifdef CONFIG_IPV6_NDISC_NODETYPE - if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT && - ri->prefix_len == 0) - continue; -#endif - if (ri->prefix_len == 0 && - !in6_dev->cnf.accept_ra_defrtr) - continue; - if (ri->prefix_len > in6_dev->cnf.accept_ra_rt_info_max_plen) - continue; - rt6_route_rcv(skb->dev, (u8 *)p, (p->nd_opt_len) << 3, - &ipv6_hdr(skb)->saddr); - } - } - -skip_routeinfo: -#endif - -#ifdef CONFIG_IPV6_NDISC_NODETYPE - /* skip link-specific ndopts from interior routers */ - if (skb->ndisc_nodetype == NDISC_NODETYPE_NODEFAULT) { - ND_PRINTK(2, info, - "RA: %s, nodetype is NODEFAULT (interior routes), dev: %s\n", - __func__, skb->dev->name); - goto out; - } -#endif - - if (in6_dev->cnf.accept_ra_pinfo && ndopts.nd_opts_pi) { - struct nd_opt_hdr *p; - for (p = ndopts.nd_opts_pi; - p; - p = ndisc_next_option(p, ndopts.nd_opts_pi_end)) { - addrconf_prefix_rcv(skb->dev, (u8 *)p, - (p->nd_opt_len) << 3, - ndopts.nd_opts_src_lladdr != NULL); - } - } - - if (ndopts.nd_opts_mtu && in6_dev->cnf.accept_ra_mtu) { - __be32 n; - u32 mtu; - - memcpy(&n, ((u8 *)(ndopts.nd_opts_mtu+1))+2, sizeof(mtu)); - mtu = ntohl(n); - - if (mtu < IPV6_MIN_MTU || mtu > skb->dev->mtu) { - ND_PRINTK(2, warn, "RA: invalid mtu: %d\n", mtu); - } else if (in6_dev->cnf.mtu6 != mtu) { - in6_dev->cnf.mtu6 = mtu; - - if (rt) - dst_metric_set(&rt->dst, RTAX_MTU, mtu); - - rt6_mtu_change(skb->dev, mtu); - } - } - - if (ndopts.nd_useropts) { - struct nd_opt_hdr *p; - for (p = ndopts.nd_useropts; - p; - p = ndisc_next_useropt(skb->dev, p, - ndopts.nd_useropts_end)) { - ndisc_ra_useropt(skb, p); - } - } - - if (ndopts.nd_opts_tgt_lladdr || ndopts.nd_opts_rh) { - ND_PRINTK(2, warn, "RA: invalid RA options\n"); - } -out: - ip6_rt_put(rt); - if (neigh) - neigh_release(neigh); -} - -static void ndisc_redirect_rcv(struct sk_buff *skb) -{ - u8 *hdr; - struct ndisc_options ndopts; - struct rd_msg *msg = (struct rd_msg *)skb_transport_header(skb); - u32 ndoptlen = skb_tail_pointer(skb) - (skb_transport_header(skb) + - offsetof(struct rd_msg, opt)); - -#ifdef CONFIG_IPV6_NDISC_NODETYPE - switch (skb->ndisc_nodetype) { - case NDISC_NODETYPE_HOST: - case NDISC_NODETYPE_NODEFAULT: - ND_PRINTK(2, warn, - "Redirect: from host or unauthorized router\n"); - return; - } -#endif - - if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL)) { - ND_PRINTK(2, warn, - "Redirect: source address is not link-local\n"); - return; - } - - if (!ndisc_parse_options(skb->dev, msg->opt, ndoptlen, &ndopts)) - return; - - if (!ndopts.nd_opts_rh) { - ip6_redirect_no_header(skb, dev_net(skb->dev), - skb->dev->ifindex, 0); - return; - } - - hdr = (u8 *)ndopts.nd_opts_rh; - hdr += 8; - if (!pskb_pull(skb, hdr - skb_transport_header(skb))) - return; - - icmpv6_notify(skb, NDISC_REDIRECT, 0, 0); -} - -static void ndisc_fill_redirect_hdr_option(struct sk_buff *skb, - struct sk_buff *orig_skb, - int rd_len) -{ - u8 *opt = skb_put(skb, rd_len); - - memset(opt, 0, 8); - *(opt++) = ND_OPT_REDIRECT_HDR; - *(opt++) = (rd_len >> 3); - opt += 6; - - memcpy(opt, ipv6_hdr(orig_skb), rd_len - 8); -} - -void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target) -{ - struct net_device *dev = skb->dev; - struct net *net = dev_net(dev); - struct sock *sk = net->ipv6.ndisc_sk; - int optlen = 0; - struct inet_peer *peer; - struct sk_buff *buff; - struct rd_msg *msg; - struct in6_addr saddr_buf; - struct rt6_info *rt; - struct dst_entry *dst; - struct flowi6 fl6; - int rd_len; - u8 ha_buf[MAX_ADDR_LEN], *ha = NULL, - ops_data_buf[NDISC_OPS_REDIRECT_DATA_SPACE], *ops_data = NULL; - bool ret; - - if (ipv6_get_lladdr(dev, &saddr_buf, IFA_F_TENTATIVE)) { - ND_PRINTK(2, warn, "Redirect: no link-local address on %s\n", - dev->name); - return; - } - - if (!ipv6_addr_equal(&ipv6_hdr(skb)->daddr, target) && - ipv6_addr_type(target) != (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) { - ND_PRINTK(2, warn, - "Redirect: target address is not link-local unicast\n"); - return; - } - - icmpv6_flow_init(sk, &fl6, NDISC_REDIRECT, - &saddr_buf, &ipv6_hdr(skb)->saddr, dev->ifindex); - - dst = ip6_route_output(net, NULL, &fl6); - if (dst->error) { - dst_release(dst); - return; - } - dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); - if (IS_ERR(dst)) - return; - - rt = (struct rt6_info *) dst; - - if (rt->rt6i_flags & RTF_GATEWAY) { - ND_PRINTK(2, warn, - "Redirect: destination is not a neighbour\n"); - goto release; - } - peer = inet_getpeer_v6(net->ipv6.peers, &ipv6_hdr(skb)->saddr, 1); - ret = inet_peer_xrlim_allow(peer, 1*HZ); - if (peer) - inet_putpeer(peer); - if (!ret) - goto release; - - if (dev->addr_len) { - struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target); - if (!neigh) { - ND_PRINTK(2, warn, - "Redirect: no neigh for target address\n"); - goto release; - } - - read_lock_bh(&neigh->lock); - if (neigh->nud_state & NUD_VALID) { - memcpy(ha_buf, neigh->ha, dev->addr_len); - read_unlock_bh(&neigh->lock); - ha = ha_buf; - optlen += ndisc_redirect_opt_addr_space(dev, neigh, - ops_data_buf, - &ops_data); - } else - read_unlock_bh(&neigh->lock); - - neigh_release(neigh); - } - - rd_len = min_t(unsigned int, - IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen, - skb->len + 8); - rd_len &= ~0x7; - optlen += rd_len; - - buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen); - if (!buff) - goto release; - - msg = (struct rd_msg *)skb_put(buff, sizeof(*msg)); - *msg = (struct rd_msg) { - .icmph = { - .icmp6_type = NDISC_REDIRECT, - }, - .target = *target, - .dest = ipv6_hdr(skb)->daddr, - }; - - /* - * include target_address option - */ - - if (ha) - ndisc_fill_redirect_addr_option(buff, ha, ops_data); - - /* - * build redirect option and copy skb over to the new packet. - */ - - if (rd_len) - ndisc_fill_redirect_hdr_option(buff, skb, rd_len); - - skb_dst_set(buff, dst); - ndisc_send_skb(buff, &ipv6_hdr(skb)->saddr, &saddr_buf); - return; - -release: - dst_release(dst); -} - -static void pndisc_redo(struct sk_buff *skb) -{ - ndisc_recv_ns(skb); - kfree_skb(skb); -} - -static bool ndisc_suppress_frag_ndisc(struct sk_buff *skb) -{ - struct inet6_dev *idev = __in6_dev_get(skb->dev); - - if (!idev) - return true; - if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED && - idev->cnf.suppress_frag_ndisc) { - net_warn_ratelimited("Received fragmented ndisc packet. Carefully consider disabling suppress_frag_ndisc.\n"); - return true; - } - return false; -} - -int ndisc_rcv(struct sk_buff *skb) -{ - struct nd_msg *msg; - - if (ndisc_suppress_frag_ndisc(skb)) - return 0; - - if (skb_linearize(skb)) - return 0; - - msg = (struct nd_msg *)skb_transport_header(skb); - - __skb_push(skb, skb->data - skb_transport_header(skb)); - - if (ipv6_hdr(skb)->hop_limit != 255) { - ND_PRINTK(2, warn, "NDISC: invalid hop-limit: %d\n", - ipv6_hdr(skb)->hop_limit); - return 0; - } - - if (msg->icmph.icmp6_code != 0) { - ND_PRINTK(2, warn, "NDISC: invalid ICMPv6 code: %d\n", - msg->icmph.icmp6_code); - return 0; - } - - memset(NEIGH_CB(skb), 0, sizeof(struct neighbour_cb)); - - switch (msg->icmph.icmp6_type) { - case NDISC_NEIGHBOUR_SOLICITATION: - ndisc_recv_ns(skb); - break; - - case NDISC_NEIGHBOUR_ADVERTISEMENT: - ndisc_recv_na(skb); - break; - - case NDISC_ROUTER_SOLICITATION: - ndisc_recv_rs(skb); - break; - - case NDISC_ROUTER_ADVERTISEMENT: - ndisc_router_discovery(skb); - break; - - case NDISC_REDIRECT: - ndisc_redirect_rcv(skb); - break; - } - - return 0; -} - -static int ndisc_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct netdev_notifier_change_info *change_info; - struct net *net = dev_net(dev); - struct inet6_dev *idev; - - switch (event) { - case NETDEV_CHANGEADDR: - neigh_changeaddr(&nd_tbl, dev); - fib6_run_gc(0, net, false); - idev = in6_dev_get(dev); - if (!idev) - break; - if (idev->cnf.ndisc_notify) - ndisc_send_unsol_na(dev); - in6_dev_put(idev); - break; - case NETDEV_CHANGE: - change_info = ptr; - if (change_info->flags_changed & IFF_NOARP) - neigh_changeaddr(&nd_tbl, dev); - break; - case NETDEV_DOWN: - neigh_ifdown(&nd_tbl, dev); - fib6_run_gc(0, net, false); - break; - case NETDEV_NOTIFY_PEERS: - ndisc_send_unsol_na(dev); - break; - default: - break; - } - - return NOTIFY_DONE; -} - -static struct notifier_block ndisc_netdev_notifier = { - .notifier_call = ndisc_netdev_event, -}; - -#ifdef CONFIG_SYSCTL -static void ndisc_warn_deprecated_sysctl(struct ctl_table *ctl, - const char *func, const char *dev_name) -{ - static char warncomm[TASK_COMM_LEN]; - static int warned; - if (strcmp(warncomm, current->comm) && warned < 5) { - strcpy(warncomm, current->comm); - pr_warn("process `%s' is using deprecated sysctl (%s) net.ipv6.neigh.%s.%s - use net.ipv6.neigh.%s.%s_ms instead\n", - warncomm, func, - dev_name, ctl->procname, - dev_name, ctl->procname); - warned++; - } -} - -int ndisc_ifinfo_sysctl_change(struct ctl_table *ctl, int write, void __user *buffer, size_t *lenp, loff_t *ppos) -{ - struct net_device *dev = ctl->extra1; - struct inet6_dev *idev; - int ret; - - if ((strcmp(ctl->procname, "retrans_time") == 0) || - (strcmp(ctl->procname, "base_reachable_time") == 0)) - ndisc_warn_deprecated_sysctl(ctl, "syscall", dev ? dev->name : "default"); - - if (strcmp(ctl->procname, "retrans_time") == 0) - ret = neigh_proc_dointvec(ctl, write, buffer, lenp, ppos); - - else if (strcmp(ctl->procname, "base_reachable_time") == 0) - ret = neigh_proc_dointvec_jiffies(ctl, write, - buffer, lenp, ppos); - - else if ((strcmp(ctl->procname, "retrans_time_ms") == 0) || - (strcmp(ctl->procname, "base_reachable_time_ms") == 0)) - ret = neigh_proc_dointvec_ms_jiffies(ctl, write, - buffer, lenp, ppos); - else - ret = -1; - - if (write && ret == 0 && dev && (idev = in6_dev_get(dev)) != NULL) { - if (ctl->data == &NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME)) - idev->nd_parms->reachable_time = - neigh_rand_reach_time(NEIGH_VAR(idev->nd_parms, BASE_REACHABLE_TIME)); - idev->tstamp = jiffies; - inet6_ifinfo_notify(RTM_NEWLINK, idev); - in6_dev_put(idev); - } - return ret; -} - - -#endif - -static int __net_init ndisc_net_init(struct net *net) -{ - struct ipv6_pinfo *np; - struct sock *sk; - int err; - - err = inet_ctl_sock_create(&sk, PF_INET6, - SOCK_RAW, IPPROTO_ICMPV6, net); - if (err < 0) { - ND_PRINTK(0, err, - "NDISC: Failed to initialize the control socket (err %d)\n", - err); - return err; - } - - net->ipv6.ndisc_sk = sk; - - np = inet6_sk(sk); - np->hop_limit = 255; - /* Do not loopback ndisc messages */ - np->mc_loop = 0; - - return 0; -} - -static void __net_exit ndisc_net_exit(struct net *net) -{ - inet_ctl_sock_destroy(net->ipv6.ndisc_sk); -} - -static struct pernet_operations ndisc_net_ops = { - .init = ndisc_net_init, - .exit = ndisc_net_exit, -}; - -int __init ndisc_init(void) -{ - int err; - - err = register_pernet_subsys(&ndisc_net_ops); - if (err) - return err; - /* - * Initialize the neighbour table - */ - neigh_table_init(NEIGH_ND_TABLE, &nd_tbl); - -#ifdef CONFIG_SYSCTL - err = neigh_sysctl_register(NULL, &nd_tbl.parms, - ndisc_ifinfo_sysctl_change); - if (err) - goto out_unregister_pernet; -out: -#endif - return err; - -#ifdef CONFIG_SYSCTL -out_unregister_pernet: - unregister_pernet_subsys(&ndisc_net_ops); - goto out; -#endif -} - -int __init ndisc_late_init(void) -{ - return register_netdevice_notifier(&ndisc_netdev_notifier); -} - -void ndisc_late_cleanup(void) -{ - unregister_netdevice_notifier(&ndisc_netdev_notifier); -} - -void ndisc_cleanup(void) -{ -#ifdef CONFIG_SYSCTL - neigh_sysctl_unregister(&nd_tbl.parms); -#endif - neigh_table_clear(NEIGH_ND_TABLE, &nd_tbl); - unregister_pernet_subsys(&ndisc_net_ops); -} diff --git a/src/linux/net/ipv6/netfilter/Kconfig b/src/linux/net/ipv6/netfilter/Kconfig deleted file mode 100644 index e10a04c..0000000 --- a/src/linux/net/ipv6/netfilter/Kconfig +++ /dev/null @@ -1,338 +0,0 @@ -# -# IP netfilter configuration -# - -menu "IPv6: Netfilter Configuration" - depends on INET && IPV6 && NETFILTER - -config NF_DEFRAG_IPV6 - tristate - default n - -config NF_CONNTRACK_IPV6 - tristate "IPv6 connection tracking support" - depends on INET && IPV6 && NF_CONNTRACK - default m if NETFILTER_ADVANCED=n - select NF_DEFRAG_IPV6 - ---help--- - Connection tracking keeps a record of what packets have passed - through your machine, in order to figure out how they are related - into connections. - - This is IPv6 support on Layer 3 independent connection tracking. - Layer 3 independent connection tracking is experimental scheme - which generalize ip_conntrack to support other layer 3 protocols. - - To compile it as a module, choose M here. If unsure, say N. - -if NF_TABLES - -config NF_TABLES_IPV6 - tristate "IPv6 nf_tables support" - help - This option enables the IPv6 support for nf_tables. - -if NF_TABLES_IPV6 - -config NFT_CHAIN_ROUTE_IPV6 - tristate "IPv6 nf_tables route chain support" - help - This option enables the "route" chain for IPv6 in nf_tables. This - chain type is used to force packet re-routing after mangling header - fields such as the source, destination, flowlabel, hop-limit and - the packet mark. - -config NFT_REJECT_IPV6 - select NF_REJECT_IPV6 - default NFT_REJECT - tristate - -config NFT_DUP_IPV6 - tristate "IPv6 nf_tables packet duplication support" - depends on !NF_CONNTRACK || NF_CONNTRACK - select NF_DUP_IPV6 - help - This module enables IPv6 packet duplication support for nf_tables. - -endif # NF_TABLES_IPV6 -endif # NF_TABLES - -config NF_DUP_IPV6 - tristate "Netfilter IPv6 packet duplication to alternate destination" - depends on !NF_CONNTRACK || NF_CONNTRACK - help - This option enables the nf_dup_ipv6 core, which duplicates an IPv6 - packet to be rerouted to another destination. - -config NF_REJECT_IPV6 - tristate "IPv6 packet rejection" - default m if NETFILTER_ADVANCED=n - -config NF_LOG_IPV6 - tristate "IPv6 packet logging" - default m if NETFILTER_ADVANCED=n - select NF_LOG_COMMON - -config NF_NAT_IPV6 - tristate "IPv6 NAT" - depends on NF_CONNTRACK_IPV6 - depends on NETFILTER_ADVANCED - select NF_NAT - help - The IPv6 NAT option allows masquerading, port forwarding and other - forms of full Network Address Port Translation. This can be - controlled by iptables or nft. - -if NF_NAT_IPV6 - -config NFT_CHAIN_NAT_IPV6 - depends on NF_TABLES_IPV6 - tristate "IPv6 nf_tables nat chain support" - help - This option enables the "nat" chain for IPv6 in nf_tables. This - chain type is used to perform Network Address Translation (NAT) - packet transformations such as the source, destination address and - source and destination ports. - -config NF_NAT_MASQUERADE_IPV6 - tristate "IPv6 masquerade support" - help - This is the kernel functionality to provide NAT in the masquerade - flavour (automatic source address selection) for IPv6. - -config NFT_MASQ_IPV6 - tristate "IPv6 masquerade support for nf_tables" - depends on NF_TABLES_IPV6 - depends on NFT_MASQ - select NF_NAT_MASQUERADE_IPV6 - help - This is the expression that provides IPv4 masquerading support for - nf_tables. - -config NFT_REDIR_IPV6 - tristate "IPv6 redirect support for nf_tables" - depends on NF_TABLES_IPV6 - depends on NFT_REDIR - select NF_NAT_REDIRECT - help - This is the expression that provides IPv4 redirect support for - nf_tables. - -endif # NF_NAT_IPV6 - -config IP6_NF_IPTABLES - tristate "IP6 tables support (required for filtering)" - depends on INET && IPV6 - select NETFILTER_XTABLES - default m if NETFILTER_ADVANCED=n - help - ip6tables is a general, extensible packet identification framework. - Currently only the packet filtering and packet mangling subsystem - for IPv6 use this, but connection tracking is going to follow. - Say 'Y' or 'M' here if you want to use either of those. - - To compile it as a module, choose M here. If unsure, say N. - -if IP6_NF_IPTABLES - -# The simple matches. -config IP6_NF_MATCH_AH - tristate '"ah" match support' - depends on NETFILTER_ADVANCED - help - This module allows one to match AH packets. - - To compile it as a module, choose M here. If unsure, say N. - -config IP6_NF_MATCH_EUI64 - tristate '"eui64" address check' - depends on NETFILTER_ADVANCED - help - This module performs checking on the IPv6 source address - Compares the last 64 bits with the EUI64 (delivered - from the MAC address) address - - To compile it as a module, choose M here. If unsure, say N. - -config IP6_NF_MATCH_FRAG - tristate '"frag" Fragmentation header match support' - depends on NETFILTER_ADVANCED - help - frag matching allows you to match packets based on the fragmentation - header of the packet. - - To compile it as a module, choose M here. If unsure, say N. - -config IP6_NF_MATCH_OPTS - tristate '"hbh" hop-by-hop and "dst" opts header match support' - depends on NETFILTER_ADVANCED - help - This allows one to match packets based on the hop-by-hop - and destination options headers of a packet. - - To compile it as a module, choose M here. If unsure, say N. - -config IP6_NF_MATCH_HL - tristate '"hl" hoplimit match support' - depends on NETFILTER_ADVANCED - select NETFILTER_XT_MATCH_HL - ---help--- - This is a backwards-compat option for the user's convenience - (e.g. when running oldconfig). It selects - CONFIG_NETFILTER_XT_MATCH_HL. - -config IP6_NF_MATCH_IPV6HEADER - tristate '"ipv6header" IPv6 Extension Headers Match' - default m if NETFILTER_ADVANCED=n - help - This module allows one to match packets based upon - the ipv6 extension headers. - - To compile it as a module, choose M here. If unsure, say N. - -config IP6_NF_MATCH_MH - tristate '"mh" match support' - depends on NETFILTER_ADVANCED - help - This module allows one to match MH packets. - - To compile it as a module, choose M here. If unsure, say N. - -config IP6_NF_MATCH_RPFILTER - tristate '"rpfilter" reverse path filter match support' - depends on NETFILTER_ADVANCED - depends on IP6_NF_MANGLE || IP6_NF_RAW - ---help--- - This option allows you to match packets whose replies would - go out via the interface the packet came in. - - To compile it as a module, choose M here. If unsure, say N. - The module will be called ip6t_rpfilter. - -config IP6_NF_MATCH_RT - tristate '"rt" Routing header match support' - depends on NETFILTER_ADVANCED - help - rt matching allows you to match packets based on the routing - header of the packet. - - To compile it as a module, choose M here. If unsure, say N. - -# The targets -config IP6_NF_TARGET_HL - tristate '"HL" hoplimit target support' - depends on NETFILTER_ADVANCED && IP6_NF_MANGLE - select NETFILTER_XT_TARGET_HL - ---help--- - This is a backwards-compatible option for the user's convenience - (e.g. when running oldconfig). It selects - CONFIG_NETFILTER_XT_TARGET_HL. - -config IP6_NF_FILTER - tristate "Packet filtering" - default m if NETFILTER_ADVANCED=n - help - Packet filtering defines a table `filter', which has a series of - rules for simple packet filtering at local input, forwarding and - local output. See the man page for iptables(8). - - To compile it as a module, choose M here. If unsure, say N. - -config IP6_NF_TARGET_REJECT - tristate "REJECT target support" - depends on IP6_NF_FILTER - select NF_REJECT_IPV6 - default m if NETFILTER_ADVANCED=n - help - The REJECT target allows a filtering rule to specify that an ICMPv6 - error should be issued in response to an incoming packet, rather - than silently being dropped. - - To compile it as a module, choose M here. If unsure, say N. - -config IP6_NF_TARGET_SYNPROXY - tristate "SYNPROXY target support" - depends on NF_CONNTRACK && NETFILTER_ADVANCED - select NETFILTER_SYNPROXY - select SYN_COOKIES - help - The SYNPROXY target allows you to intercept TCP connections and - establish them using syncookies before they are passed on to the - server. This allows to avoid conntrack and server resource usage - during SYN-flood attacks. - - To compile it as a module, choose M here. If unsure, say N. - -config IP6_NF_MANGLE - tristate "Packet mangling" - default m if NETFILTER_ADVANCED=n - help - This option adds a `mangle' table to iptables: see the man page for - iptables(8). This table is used for various packet alterations - which can effect how the packet is routed. - - To compile it as a module, choose M here. If unsure, say N. - -config IP6_NF_RAW - tristate 'raw table support (required for TRACE)' - help - This option adds a `raw' table to ip6tables. This table is the very - first in the netfilter framework and hooks in at the PREROUTING - and OUTPUT chains. - - If you want to compile it as a module, say M here and read - . If unsure, say `N'. - -# security table for MAC policy -config IP6_NF_SECURITY - tristate "Security table" - depends on SECURITY - depends on NETFILTER_ADVANCED - help - This option adds a `security' table to iptables, for use - with Mandatory Access Control (MAC) policy. - - If unsure, say N. - -config IP6_NF_NAT - tristate "ip6tables NAT support" - depends on NF_CONNTRACK_IPV6 - depends on NETFILTER_ADVANCED - select NF_NAT - select NF_NAT_IPV6 - select NETFILTER_XT_NAT - help - This enables the `nat' table in ip6tables. This allows masquerading, - port forwarding and other forms of full Network Address Port - Translation. - - To compile it as a module, choose M here. If unsure, say N. - -if IP6_NF_NAT - -config IP6_NF_TARGET_MASQUERADE - tristate "MASQUERADE target support" - select NF_NAT_MASQUERADE_IPV6 - help - Masquerading is a special case of NAT: all outgoing connections are - changed to seem to come from a particular interface's address, and - if the interface goes down, those connections are lost. This is - only useful for dialup accounts with dynamic IP address (ie. your IP - address will be different on next dialup). - - To compile it as a module, choose M here. If unsure, say N. - -config IP6_NF_TARGET_NPT - tristate "NPT (Network Prefix translation) target support" - help - This option adds the `SNPT' and `DNPT' target, which perform - stateless IPv6-to-IPv6 Network Prefix Translation per RFC 6296. - - To compile it as a module, choose M here. If unsure, say N. - -endif # IP6_NF_NAT - -endif # IP6_NF_IPTABLES - -endmenu - diff --git a/src/linux/net/ipv6/output_core.c b/src/linux/net/ipv6/output_core.c deleted file mode 100644 index cd42523..0000000 --- a/src/linux/net/ipv6/output_core.c +++ /dev/null @@ -1,176 +0,0 @@ -/* - * IPv6 library code, needed by static components when full IPv6 support is - * not configured or static. These functions are needed by GSO/GRO implementation. - */ -#include -#include -#include -#include -#include -#include -#include - -static u32 __ipv6_select_ident(struct net *net, u32 hashrnd, - const struct in6_addr *dst, - const struct in6_addr *src) -{ - u32 hash, id; - - hash = __ipv6_addr_jhash(dst, hashrnd); - hash = __ipv6_addr_jhash(src, hash); - hash ^= net_hash_mix(net); - - /* Treat id of 0 as unset and if we get 0 back from ip_idents_reserve, - * set the hight order instead thus minimizing possible future - * collisions. - */ - id = ip_idents_reserve(hash, 1); - if (unlikely(!id)) - id = 1 << 31; - - return id; -} - -/* This function exists only for tap drivers that must support broken - * clients requesting UFO without specifying an IPv6 fragment ID. - * - * This is similar to ipv6_select_ident() but we use an independent hash - * seed to limit information leakage. - * - * The network header must be set before calling this. - */ -void ipv6_proxy_select_ident(struct net *net, struct sk_buff *skb) -{ - static u32 ip6_proxy_idents_hashrnd __read_mostly; - struct in6_addr buf[2]; - struct in6_addr *addrs; - u32 id; - - addrs = skb_header_pointer(skb, - skb_network_offset(skb) + - offsetof(struct ipv6hdr, saddr), - sizeof(buf), buf); - if (!addrs) - return; - - net_get_random_once(&ip6_proxy_idents_hashrnd, - sizeof(ip6_proxy_idents_hashrnd)); - - id = __ipv6_select_ident(net, ip6_proxy_idents_hashrnd, - &addrs[1], &addrs[0]); - skb_shinfo(skb)->ip6_frag_id = htonl(id); -} -EXPORT_SYMBOL_GPL(ipv6_proxy_select_ident); - -__be32 ipv6_select_ident(struct net *net, - const struct in6_addr *daddr, - const struct in6_addr *saddr) -{ - static u32 ip6_idents_hashrnd __read_mostly; - u32 id; - - net_get_random_once(&ip6_idents_hashrnd, sizeof(ip6_idents_hashrnd)); - - id = __ipv6_select_ident(net, ip6_idents_hashrnd, daddr, saddr); - return htonl(id); -} -EXPORT_SYMBOL(ipv6_select_ident); - -int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) -{ - u16 offset = sizeof(struct ipv6hdr); - struct ipv6_opt_hdr *exthdr = - (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1); - unsigned int packet_len = skb_tail_pointer(skb) - - skb_network_header(skb); - int found_rhdr = 0; - *nexthdr = &ipv6_hdr(skb)->nexthdr; - - while (offset + 1 <= packet_len) { - - switch (**nexthdr) { - - case NEXTHDR_HOP: - break; - case NEXTHDR_ROUTING: - found_rhdr = 1; - break; - case NEXTHDR_DEST: -#if IS_ENABLED(CONFIG_IPV6_MIP6) - if (ipv6_find_tlv(skb, offset, IPV6_TLV_HAO) >= 0) - break; -#endif - if (found_rhdr) - return offset; - break; - default: - return offset; - } - - offset += ipv6_optlen(exthdr); - *nexthdr = &exthdr->nexthdr; - exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) + - offset); - } - - return offset; -} -EXPORT_SYMBOL(ip6_find_1stfragopt); - -#if IS_ENABLED(CONFIG_IPV6) -int ip6_dst_hoplimit(struct dst_entry *dst) -{ - int hoplimit = dst_metric_raw(dst, RTAX_HOPLIMIT); - if (hoplimit == 0) { - struct net_device *dev = dst->dev; - struct inet6_dev *idev; - - rcu_read_lock(); - idev = __in6_dev_get(dev); - if (idev) - hoplimit = idev->cnf.hop_limit; - else - hoplimit = dev_net(dev)->ipv6.devconf_all->hop_limit; - rcu_read_unlock(); - } - return hoplimit; -} -EXPORT_SYMBOL(ip6_dst_hoplimit); -#endif - -int __ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - int len; - - len = skb->len - sizeof(struct ipv6hdr); - if (len > IPV6_MAXPLEN) - len = 0; - ipv6_hdr(skb)->payload_len = htons(len); - IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr); - - /* if egress device is enslaved to an L3 master device pass the - * skb to its handler for processing - */ - skb = l3mdev_ip6_out(sk, skb); - if (unlikely(!skb)) - return 0; - - skb->protocol = htons(ETH_P_IPV6); - - return nf_hook(NFPROTO_IPV6, NF_INET_LOCAL_OUT, - net, sk, skb, NULL, skb_dst(skb)->dev, - dst_output); -} -EXPORT_SYMBOL_GPL(__ip6_local_out); - -int ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - int err; - - err = __ip6_local_out(net, sk, skb); - if (likely(err == 1)) - err = dst_output(net, sk, skb); - - return err; -} -EXPORT_SYMBOL_GPL(ip6_local_out); diff --git a/src/linux/net/ipv6/ping.c b/src/linux/net/ipv6/ping.c deleted file mode 100644 index 66e2d9d..0000000 --- a/src/linux/net/ipv6/ping.c +++ /dev/null @@ -1,285 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * "Ping" sockets - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Based on ipv4/ping.c code. - * - * Authors: Lorenzo Colitti (IPv6 support) - * Vasiliy Kulikov / Openwall (IPv4 implementation, for Linux 2.6), - * Pavel Kankovsky (IPv4 implementation, for Linux 2.4.32) - * - */ - -#include -#include -#include -#include -#include -#include -#include - -/* Compatibility glue so we can support IPv6 when it's compiled as a module */ -static int dummy_ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, - int *addr_len) -{ - return -EAFNOSUPPORT; -} -static void dummy_ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg, - struct sk_buff *skb) -{ -} -static int dummy_icmpv6_err_convert(u8 type, u8 code, int *err) -{ - return -EAFNOSUPPORT; -} -static void dummy_ipv6_icmp_error(struct sock *sk, struct sk_buff *skb, int err, - __be16 port, u32 info, u8 *payload) {} -static int dummy_ipv6_chk_addr(struct net *net, const struct in6_addr *addr, - const struct net_device *dev, int strict) -{ - return 0; -} - -static int ping_v6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) -{ - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *np = inet6_sk(sk); - struct icmp6hdr user_icmph; - int addr_type; - struct in6_addr *daddr; - int oif = 0; - struct flowi6 fl6; - int err; - struct dst_entry *dst; - struct rt6_info *rt; - struct pingfakehdr pfh; - struct sockcm_cookie junk = {0}; - struct ipcm6_cookie ipc6; - - pr_debug("ping_v6_sendmsg(sk=%p,sk->num=%u)\n", inet, inet->inet_num); - - err = ping_common_sendmsg(AF_INET6, msg, len, &user_icmph, - sizeof(user_icmph)); - if (err) - return err; - - if (msg->msg_name) { - DECLARE_SOCKADDR(struct sockaddr_in6 *, u, msg->msg_name); - if (msg->msg_namelen < sizeof(*u)) - return -EINVAL; - if (u->sin6_family != AF_INET6) { - return -EAFNOSUPPORT; - } - daddr = &(u->sin6_addr); - if (__ipv6_addr_needs_scope_id(ipv6_addr_type(daddr))) - oif = u->sin6_scope_id; - } else { - if (sk->sk_state != TCP_ESTABLISHED) - return -EDESTADDRREQ; - daddr = &sk->sk_v6_daddr; - } - - if (!oif) - oif = sk->sk_bound_dev_if; - - if (!oif) - oif = np->sticky_pktinfo.ipi6_ifindex; - - if (!oif && ipv6_addr_is_multicast(daddr)) - oif = np->mcast_oif; - else if (!oif) - oif = np->ucast_oif; - - addr_type = ipv6_addr_type(daddr); - if ((__ipv6_addr_needs_scope_id(addr_type) && !oif) || - (addr_type & IPV6_ADDR_MAPPED) || - (oif && sk->sk_bound_dev_if && oif != sk->sk_bound_dev_if)) - return -EINVAL; - - /* TODO: use ip6_datagram_send_ctl to get options from cmsg */ - - memset(&fl6, 0, sizeof(fl6)); - - fl6.flowi6_proto = IPPROTO_ICMPV6; - fl6.saddr = np->saddr; - fl6.daddr = *daddr; - fl6.flowi6_oif = oif; - fl6.flowi6_mark = sk->sk_mark; - fl6.fl6_icmp_type = user_icmph.icmp6_type; - fl6.fl6_icmp_code = user_icmph.icmp6_code; - security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); - - ipc6.tclass = np->tclass; - fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel); - - dst = ip6_sk_dst_lookup_flow(sk, &fl6, daddr); - if (IS_ERR(dst)) - return PTR_ERR(dst); - rt = (struct rt6_info *) dst; - - np = inet6_sk(sk); - if (!np) { - err = -EBADF; - goto dst_err_out; - } - - if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) - fl6.flowi6_oif = np->mcast_oif; - else if (!fl6.flowi6_oif) - fl6.flowi6_oif = np->ucast_oif; - - pfh.icmph.type = user_icmph.icmp6_type; - pfh.icmph.code = user_icmph.icmp6_code; - pfh.icmph.checksum = 0; - pfh.icmph.un.echo.id = inet->inet_sport; - pfh.icmph.un.echo.sequence = user_icmph.icmp6_sequence; - pfh.msg = msg; - pfh.wcheck = 0; - pfh.family = AF_INET6; - - ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); - ipc6.dontfrag = np->dontfrag; - ipc6.opt = NULL; - - lock_sock(sk); - err = ip6_append_data(sk, ping_getfrag, &pfh, len, - 0, &ipc6, &fl6, rt, - MSG_DONTWAIT, &junk); - - if (err) { - ICMP6_INC_STATS(sock_net(sk), rt->rt6i_idev, - ICMP6_MIB_OUTERRORS); - ip6_flush_pending_frames(sk); - } else { - err = icmpv6_push_pending_frames(sk, &fl6, - (struct icmp6hdr *) &pfh.icmph, - len); - } - release_sock(sk); - -dst_err_out: - dst_release(dst); - - if (err) - return err; - - return len; -} - -struct proto pingv6_prot = { - .name = "PINGv6", - .owner = THIS_MODULE, - .init = ping_init_sock, - .close = ping_close, - .connect = ip6_datagram_connect_v6_only, - .disconnect = __udp_disconnect, - .setsockopt = ipv6_setsockopt, - .getsockopt = ipv6_getsockopt, - .sendmsg = ping_v6_sendmsg, - .recvmsg = ping_recvmsg, - .bind = ping_bind, - .backlog_rcv = ping_queue_rcv_skb, - .hash = ping_hash, - .unhash = ping_unhash, - .get_port = ping_get_port, - .obj_size = sizeof(struct raw6_sock), -}; -EXPORT_SYMBOL_GPL(pingv6_prot); - -static struct inet_protosw pingv6_protosw = { - .type = SOCK_DGRAM, - .protocol = IPPROTO_ICMPV6, - .prot = &pingv6_prot, - .ops = &inet6_dgram_ops, - .flags = INET_PROTOSW_REUSE, -}; - -#ifdef CONFIG_PROC_FS -static void *ping_v6_seq_start(struct seq_file *seq, loff_t *pos) -{ - return ping_seq_start(seq, pos, AF_INET6); -} - -static int ping_v6_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) { - seq_puts(seq, IPV6_SEQ_DGRAM_HEADER); - } else { - int bucket = ((struct ping_iter_state *) seq->private)->bucket; - struct inet_sock *inet = inet_sk(v); - __u16 srcp = ntohs(inet->inet_sport); - __u16 destp = ntohs(inet->inet_dport); - ip6_dgram_sock_seq_show(seq, v, srcp, destp, bucket); - } - return 0; -} - -static struct ping_seq_afinfo ping_v6_seq_afinfo = { - .name = "icmp6", - .family = AF_INET6, - .seq_fops = &ping_seq_fops, - .seq_ops = { - .start = ping_v6_seq_start, - .show = ping_v6_seq_show, - .next = ping_seq_next, - .stop = ping_seq_stop, - }, -}; - -static int __net_init ping_v6_proc_init_net(struct net *net) -{ - return ping_proc_register(net, &ping_v6_seq_afinfo); -} - -static void __net_init ping_v6_proc_exit_net(struct net *net) -{ - return ping_proc_unregister(net, &ping_v6_seq_afinfo); -} - -static struct pernet_operations ping_v6_net_ops = { - .init = ping_v6_proc_init_net, - .exit = ping_v6_proc_exit_net, -}; -#endif - -int __init pingv6_init(void) -{ -#ifdef CONFIG_PROC_FS - int ret = register_pernet_subsys(&ping_v6_net_ops); - if (ret) - return ret; -#endif - pingv6_ops.ipv6_recv_error = ipv6_recv_error; - pingv6_ops.ip6_datagram_recv_common_ctl = ip6_datagram_recv_common_ctl; - pingv6_ops.ip6_datagram_recv_specific_ctl = - ip6_datagram_recv_specific_ctl; - pingv6_ops.icmpv6_err_convert = icmpv6_err_convert; - pingv6_ops.ipv6_icmp_error = ipv6_icmp_error; - pingv6_ops.ipv6_chk_addr = ipv6_chk_addr; - return inet6_register_protosw(&pingv6_protosw); -} - -/* This never gets called because it's not possible to unload the ipv6 module, - * but just in case. - */ -void pingv6_exit(void) -{ - pingv6_ops.ipv6_recv_error = dummy_ipv6_recv_error; - pingv6_ops.ip6_datagram_recv_common_ctl = dummy_ip6_datagram_recv_ctl; - pingv6_ops.ip6_datagram_recv_specific_ctl = dummy_ip6_datagram_recv_ctl; - pingv6_ops.icmpv6_err_convert = dummy_icmpv6_err_convert; - pingv6_ops.ipv6_icmp_error = dummy_ipv6_icmp_error; - pingv6_ops.ipv6_chk_addr = dummy_ipv6_chk_addr; -#ifdef CONFIG_PROC_FS - unregister_pernet_subsys(&ping_v6_net_ops); -#endif - inet6_unregister_protosw(&pingv6_protosw); -} diff --git a/src/linux/net/ipv6/proc.c b/src/linux/net/ipv6/proc.c deleted file mode 100644 index cc8e3ae..0000000 --- a/src/linux/net/ipv6/proc.c +++ /dev/null @@ -1,360 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * This file implements the various access functions for the - * PROC file system. This is very similar to the IPv4 version, - * except it reports the sockets in the INET6 address family. - * - * Authors: David S. Miller (davem@caip.rutgers.edu) - * YOSHIFUJI Hideaki - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX4(a, b, c, d) \ - max_t(u32, max_t(u32, a, b), max_t(u32, c, d)) -#define SNMP_MIB_MAX MAX4(UDP_MIB_MAX, TCP_MIB_MAX, \ - IPSTATS_MIB_MAX, ICMP_MIB_MAX) - -static int sockstat6_seq_show(struct seq_file *seq, void *v) -{ - struct net *net = seq->private; - unsigned int frag_mem = ip6_frag_mem(net); - - seq_printf(seq, "TCP6: inuse %d\n", - sock_prot_inuse_get(net, &tcpv6_prot)); - seq_printf(seq, "UDP6: inuse %d\n", - sock_prot_inuse_get(net, &udpv6_prot)); - seq_printf(seq, "UDPLITE6: inuse %d\n", - sock_prot_inuse_get(net, &udplitev6_prot)); - seq_printf(seq, "RAW6: inuse %d\n", - sock_prot_inuse_get(net, &rawv6_prot)); - seq_printf(seq, "FRAG6: inuse %u memory %u\n", !!frag_mem, frag_mem); - return 0; -} - -static int sockstat6_seq_open(struct inode *inode, struct file *file) -{ - return single_open_net(inode, file, sockstat6_seq_show); -} - -static const struct file_operations sockstat6_seq_fops = { - .owner = THIS_MODULE, - .open = sockstat6_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release_net, -}; - -static const struct snmp_mib snmp6_ipstats_list[] = { -/* ipv6 mib according to RFC 2465 */ - SNMP_MIB_ITEM("Ip6InReceives", IPSTATS_MIB_INPKTS), - SNMP_MIB_ITEM("Ip6InHdrErrors", IPSTATS_MIB_INHDRERRORS), - SNMP_MIB_ITEM("Ip6InTooBigErrors", IPSTATS_MIB_INTOOBIGERRORS), - SNMP_MIB_ITEM("Ip6InNoRoutes", IPSTATS_MIB_INNOROUTES), - SNMP_MIB_ITEM("Ip6InAddrErrors", IPSTATS_MIB_INADDRERRORS), - SNMP_MIB_ITEM("Ip6InUnknownProtos", IPSTATS_MIB_INUNKNOWNPROTOS), - SNMP_MIB_ITEM("Ip6InTruncatedPkts", IPSTATS_MIB_INTRUNCATEDPKTS), - SNMP_MIB_ITEM("Ip6InDiscards", IPSTATS_MIB_INDISCARDS), - SNMP_MIB_ITEM("Ip6InDelivers", IPSTATS_MIB_INDELIVERS), - SNMP_MIB_ITEM("Ip6OutForwDatagrams", IPSTATS_MIB_OUTFORWDATAGRAMS), - SNMP_MIB_ITEM("Ip6OutRequests", IPSTATS_MIB_OUTPKTS), - SNMP_MIB_ITEM("Ip6OutDiscards", IPSTATS_MIB_OUTDISCARDS), - SNMP_MIB_ITEM("Ip6OutNoRoutes", IPSTATS_MIB_OUTNOROUTES), - SNMP_MIB_ITEM("Ip6ReasmTimeout", IPSTATS_MIB_REASMTIMEOUT), - SNMP_MIB_ITEM("Ip6ReasmReqds", IPSTATS_MIB_REASMREQDS), - SNMP_MIB_ITEM("Ip6ReasmOKs", IPSTATS_MIB_REASMOKS), - SNMP_MIB_ITEM("Ip6ReasmFails", IPSTATS_MIB_REASMFAILS), - SNMP_MIB_ITEM("Ip6FragOKs", IPSTATS_MIB_FRAGOKS), - SNMP_MIB_ITEM("Ip6FragFails", IPSTATS_MIB_FRAGFAILS), - SNMP_MIB_ITEM("Ip6FragCreates", IPSTATS_MIB_FRAGCREATES), - SNMP_MIB_ITEM("Ip6InMcastPkts", IPSTATS_MIB_INMCASTPKTS), - SNMP_MIB_ITEM("Ip6OutMcastPkts", IPSTATS_MIB_OUTMCASTPKTS), - SNMP_MIB_ITEM("Ip6InOctets", IPSTATS_MIB_INOCTETS), - SNMP_MIB_ITEM("Ip6OutOctets", IPSTATS_MIB_OUTOCTETS), - SNMP_MIB_ITEM("Ip6InMcastOctets", IPSTATS_MIB_INMCASTOCTETS), - SNMP_MIB_ITEM("Ip6OutMcastOctets", IPSTATS_MIB_OUTMCASTOCTETS), - SNMP_MIB_ITEM("Ip6InBcastOctets", IPSTATS_MIB_INBCASTOCTETS), - SNMP_MIB_ITEM("Ip6OutBcastOctets", IPSTATS_MIB_OUTBCASTOCTETS), - /* IPSTATS_MIB_CSUMERRORS is not relevant in IPv6 (no checksum) */ - SNMP_MIB_ITEM("Ip6InNoECTPkts", IPSTATS_MIB_NOECTPKTS), - SNMP_MIB_ITEM("Ip6InECT1Pkts", IPSTATS_MIB_ECT1PKTS), - SNMP_MIB_ITEM("Ip6InECT0Pkts", IPSTATS_MIB_ECT0PKTS), - SNMP_MIB_ITEM("Ip6InCEPkts", IPSTATS_MIB_CEPKTS), - SNMP_MIB_SENTINEL -}; - -static const struct snmp_mib snmp6_icmp6_list[] = { -/* icmpv6 mib according to RFC 2466 */ - SNMP_MIB_ITEM("Icmp6InMsgs", ICMP6_MIB_INMSGS), - SNMP_MIB_ITEM("Icmp6InErrors", ICMP6_MIB_INERRORS), - SNMP_MIB_ITEM("Icmp6OutMsgs", ICMP6_MIB_OUTMSGS), - SNMP_MIB_ITEM("Icmp6OutErrors", ICMP6_MIB_OUTERRORS), - SNMP_MIB_ITEM("Icmp6InCsumErrors", ICMP6_MIB_CSUMERRORS), - SNMP_MIB_SENTINEL -}; - -/* RFC 4293 v6 ICMPMsgStatsTable; named items for RFC 2466 compatibility */ -static const char *const icmp6type2name[256] = { - [ICMPV6_DEST_UNREACH] = "DestUnreachs", - [ICMPV6_PKT_TOOBIG] = "PktTooBigs", - [ICMPV6_TIME_EXCEED] = "TimeExcds", - [ICMPV6_PARAMPROB] = "ParmProblems", - [ICMPV6_ECHO_REQUEST] = "Echos", - [ICMPV6_ECHO_REPLY] = "EchoReplies", - [ICMPV6_MGM_QUERY] = "GroupMembQueries", - [ICMPV6_MGM_REPORT] = "GroupMembResponses", - [ICMPV6_MGM_REDUCTION] = "GroupMembReductions", - [ICMPV6_MLD2_REPORT] = "MLDv2Reports", - [NDISC_ROUTER_ADVERTISEMENT] = "RouterAdvertisements", - [NDISC_ROUTER_SOLICITATION] = "RouterSolicits", - [NDISC_NEIGHBOUR_ADVERTISEMENT] = "NeighborAdvertisements", - [NDISC_NEIGHBOUR_SOLICITATION] = "NeighborSolicits", - [NDISC_REDIRECT] = "Redirects", -}; - - -static const struct snmp_mib snmp6_udp6_list[] = { - SNMP_MIB_ITEM("Udp6InDatagrams", UDP_MIB_INDATAGRAMS), - SNMP_MIB_ITEM("Udp6NoPorts", UDP_MIB_NOPORTS), - SNMP_MIB_ITEM("Udp6InErrors", UDP_MIB_INERRORS), - SNMP_MIB_ITEM("Udp6OutDatagrams", UDP_MIB_OUTDATAGRAMS), - SNMP_MIB_ITEM("Udp6RcvbufErrors", UDP_MIB_RCVBUFERRORS), - SNMP_MIB_ITEM("Udp6SndbufErrors", UDP_MIB_SNDBUFERRORS), - SNMP_MIB_ITEM("Udp6InCsumErrors", UDP_MIB_CSUMERRORS), - SNMP_MIB_ITEM("Udp6IgnoredMulti", UDP_MIB_IGNOREDMULTI), - SNMP_MIB_SENTINEL -}; - -static const struct snmp_mib snmp6_udplite6_list[] = { - SNMP_MIB_ITEM("UdpLite6InDatagrams", UDP_MIB_INDATAGRAMS), - SNMP_MIB_ITEM("UdpLite6NoPorts", UDP_MIB_NOPORTS), - SNMP_MIB_ITEM("UdpLite6InErrors", UDP_MIB_INERRORS), - SNMP_MIB_ITEM("UdpLite6OutDatagrams", UDP_MIB_OUTDATAGRAMS), - SNMP_MIB_ITEM("UdpLite6RcvbufErrors", UDP_MIB_RCVBUFERRORS), - SNMP_MIB_ITEM("UdpLite6SndbufErrors", UDP_MIB_SNDBUFERRORS), - SNMP_MIB_ITEM("UdpLite6InCsumErrors", UDP_MIB_CSUMERRORS), - SNMP_MIB_SENTINEL -}; - -static void snmp6_seq_show_icmpv6msg(struct seq_file *seq, atomic_long_t *smib) -{ - char name[32]; - int i; - - /* print by name -- deprecated items */ - for (i = 0; i < ICMP6MSG_MIB_MAX; i++) { - int icmptype; - const char *p; - - icmptype = i & 0xff; - p = icmp6type2name[icmptype]; - if (!p) /* don't print un-named types here */ - continue; - snprintf(name, sizeof(name), "Icmp6%s%s", - i & 0x100 ? "Out" : "In", p); - seq_printf(seq, "%-32s\t%lu\n", name, - atomic_long_read(smib + i)); - } - - /* print by number (nonzero only) - ICMPMsgStat format */ - for (i = 0; i < ICMP6MSG_MIB_MAX; i++) { - unsigned long val; - - val = atomic_long_read(smib + i); - if (!val) - continue; - snprintf(name, sizeof(name), "Icmp6%sType%u", - i & 0x100 ? "Out" : "In", i & 0xff); - seq_printf(seq, "%-32s\t%lu\n", name, val); - } -} - -/* can be called either with percpu mib (pcpumib != NULL), - * or shared one (smib != NULL) - */ -static void snmp6_seq_show_item(struct seq_file *seq, void __percpu *pcpumib, - atomic_long_t *smib, - const struct snmp_mib *itemlist) -{ - unsigned long buff[SNMP_MIB_MAX]; - int i; - - if (pcpumib) { - memset(buff, 0, sizeof(unsigned long) * SNMP_MIB_MAX); - - snmp_get_cpu_field_batch(buff, itemlist, pcpumib); - for (i = 0; itemlist[i].name; i++) - seq_printf(seq, "%-32s\t%lu\n", - itemlist[i].name, buff[i]); - } else { - for (i = 0; itemlist[i].name; i++) - seq_printf(seq, "%-32s\t%lu\n", itemlist[i].name, - atomic_long_read(smib + itemlist[i].entry)); - } -} - -static void snmp6_seq_show_item64(struct seq_file *seq, void __percpu *mib, - const struct snmp_mib *itemlist, size_t syncpoff) -{ - u64 buff64[SNMP_MIB_MAX]; - int i; - - memset(buff64, 0, sizeof(unsigned long) * SNMP_MIB_MAX); - - snmp_get_cpu_field64_batch(buff64, itemlist, mib, syncpoff); - for (i = 0; itemlist[i].name; i++) - seq_printf(seq, "%-32s\t%llu\n", itemlist[i].name, buff64[i]); -} - -static int snmp6_seq_show(struct seq_file *seq, void *v) -{ - struct net *net = (struct net *)seq->private; - - snmp6_seq_show_item64(seq, net->mib.ipv6_statistics, - snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp)); - snmp6_seq_show_item(seq, net->mib.icmpv6_statistics, - NULL, snmp6_icmp6_list); - snmp6_seq_show_icmpv6msg(seq, net->mib.icmpv6msg_statistics->mibs); - snmp6_seq_show_item(seq, net->mib.udp_stats_in6, - NULL, snmp6_udp6_list); - snmp6_seq_show_item(seq, net->mib.udplite_stats_in6, - NULL, snmp6_udplite6_list); - return 0; -} - -static int snmp6_seq_open(struct inode *inode, struct file *file) -{ - return single_open_net(inode, file, snmp6_seq_show); -} - -static const struct file_operations snmp6_seq_fops = { - .owner = THIS_MODULE, - .open = snmp6_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release_net, -}; - -static int snmp6_dev_seq_show(struct seq_file *seq, void *v) -{ - struct inet6_dev *idev = (struct inet6_dev *)seq->private; - - seq_printf(seq, "%-32s\t%u\n", "ifIndex", idev->dev->ifindex); - snmp6_seq_show_item64(seq, idev->stats.ipv6, - snmp6_ipstats_list, offsetof(struct ipstats_mib, syncp)); - snmp6_seq_show_item(seq, NULL, idev->stats.icmpv6dev->mibs, - snmp6_icmp6_list); - snmp6_seq_show_icmpv6msg(seq, idev->stats.icmpv6msgdev->mibs); - return 0; -} - -static int snmp6_dev_seq_open(struct inode *inode, struct file *file) -{ - return single_open(file, snmp6_dev_seq_show, PDE_DATA(inode)); -} - -static const struct file_operations snmp6_dev_seq_fops = { - .owner = THIS_MODULE, - .open = snmp6_dev_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -int snmp6_register_dev(struct inet6_dev *idev) -{ - struct proc_dir_entry *p; - struct net *net; - - if (!idev || !idev->dev) - return -EINVAL; - - net = dev_net(idev->dev); - if (!net->mib.proc_net_devsnmp6) - return -ENOENT; - - p = proc_create_data(idev->dev->name, S_IRUGO, - net->mib.proc_net_devsnmp6, - &snmp6_dev_seq_fops, idev); - if (!p) - return -ENOMEM; - - idev->stats.proc_dir_entry = p; - return 0; -} - -int snmp6_unregister_dev(struct inet6_dev *idev) -{ - struct net *net = dev_net(idev->dev); - if (!net->mib.proc_net_devsnmp6) - return -ENOENT; - if (!idev->stats.proc_dir_entry) - return -EINVAL; - proc_remove(idev->stats.proc_dir_entry); - idev->stats.proc_dir_entry = NULL; - return 0; -} - -static int __net_init ipv6_proc_init_net(struct net *net) -{ - if (!proc_create("sockstat6", S_IRUGO, net->proc_net, - &sockstat6_seq_fops)) - return -ENOMEM; - - if (!proc_create("snmp6", S_IRUGO, net->proc_net, &snmp6_seq_fops)) - goto proc_snmp6_fail; - - net->mib.proc_net_devsnmp6 = proc_mkdir("dev_snmp6", net->proc_net); - if (!net->mib.proc_net_devsnmp6) - goto proc_dev_snmp6_fail; - return 0; - -proc_dev_snmp6_fail: - remove_proc_entry("snmp6", net->proc_net); -proc_snmp6_fail: - remove_proc_entry("sockstat6", net->proc_net); - return -ENOMEM; -} - -static void __net_exit ipv6_proc_exit_net(struct net *net) -{ - remove_proc_entry("sockstat6", net->proc_net); - remove_proc_entry("dev_snmp6", net->proc_net); - remove_proc_entry("snmp6", net->proc_net); -} - -static struct pernet_operations ipv6_proc_ops = { - .init = ipv6_proc_init_net, - .exit = ipv6_proc_exit_net, -}; - -int __init ipv6_misc_proc_init(void) -{ - return register_pernet_subsys(&ipv6_proc_ops); -} - -void ipv6_misc_proc_exit(void) -{ - unregister_pernet_subsys(&ipv6_proc_ops); -} - diff --git a/src/linux/net/ipv6/protocol.c b/src/linux/net/ipv6/protocol.c deleted file mode 100644 index e3770ab..0000000 --- a/src/linux/net/ipv6/protocol.c +++ /dev/null @@ -1,74 +0,0 @@ -/* - * INET An implementation of the TCP/IP protocol suite for the LINUX - * operating system. INET is implemented using the BSD Socket - * interface as the means of communication with the user level. - * - * PF_INET6 protocol dispatch tables. - * - * Authors: Pedro Roque - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -/* - * Changes: - * - * Vince Laviano (vince@cs.stanford.edu) 16 May 2001 - * - Removed unused variable 'inet6_protocol_base' - * - Modified inet6_del_protocol() to correctly maintain copy bit. - */ -#include -#include -#include -#include - -#if IS_ENABLED(CONFIG_IPV6) -const struct inet6_protocol __rcu *inet6_protos[MAX_INET_PROTOS] __read_mostly; -EXPORT_SYMBOL(inet6_protos); - -int inet6_add_protocol(const struct inet6_protocol *prot, unsigned char protocol) -{ - return !cmpxchg((const struct inet6_protocol **)&inet6_protos[protocol], - NULL, prot) ? 0 : -1; -} -EXPORT_SYMBOL(inet6_add_protocol); - -int inet6_del_protocol(const struct inet6_protocol *prot, unsigned char protocol) -{ - int ret; - - ret = (cmpxchg((const struct inet6_protocol **)&inet6_protos[protocol], - prot, NULL) == prot) ? 0 : -1; - - synchronize_net(); - - return ret; -} -EXPORT_SYMBOL(inet6_del_protocol); -#endif - -const struct net_offload __rcu *inet6_offloads[MAX_INET_PROTOS] __read_mostly; -EXPORT_SYMBOL(inet6_offloads); - -int inet6_add_offload(const struct net_offload *prot, unsigned char protocol) -{ - return !cmpxchg((const struct net_offload **)&inet6_offloads[protocol], - NULL, prot) ? 0 : -1; -} -EXPORT_SYMBOL(inet6_add_offload); - -int inet6_del_offload(const struct net_offload *prot, unsigned char protocol) -{ - int ret; - - ret = (cmpxchg((const struct net_offload **)&inet6_offloads[protocol], - prot, NULL) == prot) ? 0 : -1; - - synchronize_net(); - - return ret; -} -EXPORT_SYMBOL(inet6_del_offload); diff --git a/src/linux/net/ipv6/raw.c b/src/linux/net/ipv6/raw.c deleted file mode 100644 index 054a1d8..0000000 --- a/src/linux/net/ipv6/raw.c +++ /dev/null @@ -1,1369 +0,0 @@ -/* - * RAW sockets for IPv6 - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * Adapted from linux/net/ipv4/raw.c - * - * Fixes: - * Hideaki YOSHIFUJI : sin6_scope_id support - * YOSHIFUJI,H.@USAGI : raw checksum (RFC2292(bis) compliance) - * Kazunori MIYAZAWA @USAGI: change process style to use ip6_append_data - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#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 -#include -#include -#if IS_ENABLED(CONFIG_IPV6_MIP6) -#include -#endif -#include - -#include -#include -#include - -#include -#include -#include - -#define ICMPV6_HDRLEN 4 /* ICMPv6 header, RFC 4443 Section 2.1 */ - -static struct raw_hashinfo raw_v6_hashinfo = { - .lock = __RW_LOCK_UNLOCKED(raw_v6_hashinfo.lock), -}; - -static struct sock *__raw_v6_lookup(struct net *net, struct sock *sk, - unsigned short num, const struct in6_addr *loc_addr, - const struct in6_addr *rmt_addr, int dif) -{ - bool is_multicast = ipv6_addr_is_multicast(loc_addr); - - sk_for_each_from(sk) - if (inet_sk(sk)->inet_num == num) { - - if (!net_eq(sock_net(sk), net)) - continue; - - if (!ipv6_addr_any(&sk->sk_v6_daddr) && - !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) - continue; - - if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif) - continue; - - if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { - if (ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr)) - goto found; - if (is_multicast && - inet6_mc_check(sk, loc_addr, rmt_addr)) - goto found; - continue; - } - goto found; - } - sk = NULL; -found: - return sk; -} - -/* - * 0 - deliver - * 1 - block - */ -static int icmpv6_filter(const struct sock *sk, const struct sk_buff *skb) -{ - struct icmp6hdr _hdr; - const struct icmp6hdr *hdr; - - /* We require only the four bytes of the ICMPv6 header, not any - * additional bytes of message body in "struct icmp6hdr". - */ - hdr = skb_header_pointer(skb, skb_transport_offset(skb), - ICMPV6_HDRLEN, &_hdr); - if (hdr) { - const __u32 *data = &raw6_sk(sk)->filter.data[0]; - unsigned int type = hdr->icmp6_type; - - return (data[type >> 5] & (1U << (type & 31))) != 0; - } - return 1; -} - -#if IS_ENABLED(CONFIG_IPV6_MIP6) -typedef int mh_filter_t(struct sock *sock, struct sk_buff *skb); - -static mh_filter_t __rcu *mh_filter __read_mostly; - -int rawv6_mh_filter_register(mh_filter_t filter) -{ - rcu_assign_pointer(mh_filter, filter); - return 0; -} -EXPORT_SYMBOL(rawv6_mh_filter_register); - -int rawv6_mh_filter_unregister(mh_filter_t filter) -{ - RCU_INIT_POINTER(mh_filter, NULL); - synchronize_rcu(); - return 0; -} -EXPORT_SYMBOL(rawv6_mh_filter_unregister); - -#endif - -/* - * demultiplex raw sockets. - * (should consider queueing the skb in the sock receive_queue - * without calling rawv6.c) - * - * Caller owns SKB so we must make clones. - */ -static bool ipv6_raw_deliver(struct sk_buff *skb, int nexthdr) -{ - const struct in6_addr *saddr; - const struct in6_addr *daddr; - struct sock *sk; - bool delivered = false; - __u8 hash; - struct net *net; - - saddr = &ipv6_hdr(skb)->saddr; - daddr = saddr + 1; - - hash = nexthdr & (RAW_HTABLE_SIZE - 1); - - read_lock(&raw_v6_hashinfo.lock); - sk = sk_head(&raw_v6_hashinfo.ht[hash]); - - if (!sk) - goto out; - - net = dev_net(skb->dev); - sk = __raw_v6_lookup(net, sk, nexthdr, daddr, saddr, inet6_iif(skb)); - - while (sk) { - int filtered; - - delivered = true; - switch (nexthdr) { - case IPPROTO_ICMPV6: - filtered = icmpv6_filter(sk, skb); - break; - -#if IS_ENABLED(CONFIG_IPV6_MIP6) - case IPPROTO_MH: - { - /* XXX: To validate MH only once for each packet, - * this is placed here. It should be after checking - * xfrm policy, however it doesn't. The checking xfrm - * policy is placed in rawv6_rcv() because it is - * required for each socket. - */ - mh_filter_t *filter; - - filter = rcu_dereference(mh_filter); - filtered = filter ? (*filter)(sk, skb) : 0; - break; - } -#endif - default: - filtered = 0; - break; - } - - if (filtered < 0) - break; - if (filtered == 0) { - struct sk_buff *clone = skb_clone(skb, GFP_ATOMIC); - - /* Not releasing hash table! */ - if (clone) { - nf_reset(clone); - rawv6_rcv(sk, clone); - } - } - sk = __raw_v6_lookup(net, sk_next(sk), nexthdr, daddr, saddr, - inet6_iif(skb)); - } -out: - read_unlock(&raw_v6_hashinfo.lock); - return delivered; -} - -bool raw6_local_deliver(struct sk_buff *skb, int nexthdr) -{ - struct sock *raw_sk; - - raw_sk = sk_head(&raw_v6_hashinfo.ht[nexthdr & (RAW_HTABLE_SIZE - 1)]); - if (raw_sk && !ipv6_raw_deliver(skb, nexthdr)) - raw_sk = NULL; - - return raw_sk != NULL; -} - -/* This cleans up af_inet6 a bit. -DaveM */ -static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) -{ - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *np = inet6_sk(sk); - struct sockaddr_in6 *addr = (struct sockaddr_in6 *) uaddr; - __be32 v4addr = 0; - int addr_type; - int err; - - if (addr_len < SIN6_LEN_RFC2133) - return -EINVAL; - - if (addr->sin6_family != AF_INET6) - return -EINVAL; - - addr_type = ipv6_addr_type(&addr->sin6_addr); - - /* Raw sockets are IPv6 only */ - if (addr_type == IPV6_ADDR_MAPPED) - return -EADDRNOTAVAIL; - - lock_sock(sk); - - err = -EINVAL; - if (sk->sk_state != TCP_CLOSE) - goto out; - - rcu_read_lock(); - /* Check if the address belongs to the host. */ - if (addr_type != IPV6_ADDR_ANY) { - struct net_device *dev = NULL; - - if (__ipv6_addr_needs_scope_id(addr_type)) { - if (addr_len >= sizeof(struct sockaddr_in6) && - addr->sin6_scope_id) { - /* Override any existing binding, if another - * one is supplied by user. - */ - sk->sk_bound_dev_if = addr->sin6_scope_id; - } - - /* Binding to link-local address requires an interface */ - if (!sk->sk_bound_dev_if) - goto out_unlock; - - err = -ENODEV; - dev = dev_get_by_index_rcu(sock_net(sk), - sk->sk_bound_dev_if); - if (!dev) - goto out_unlock; - } - - /* ipv4 addr of the socket is invalid. Only the - * unspecified and mapped address have a v4 equivalent. - */ - v4addr = LOOPBACK4_IPV6; - if (!(addr_type & IPV6_ADDR_MULTICAST) && - !sock_net(sk)->ipv6.sysctl.ip_nonlocal_bind) { - err = -EADDRNOTAVAIL; - if (!ipv6_chk_addr(sock_net(sk), &addr->sin6_addr, - dev, 0)) { - goto out_unlock; - } - } - } - - inet->inet_rcv_saddr = inet->inet_saddr = v4addr; - sk->sk_v6_rcv_saddr = addr->sin6_addr; - if (!(addr_type & IPV6_ADDR_MULTICAST)) - np->saddr = addr->sin6_addr; - err = 0; -out_unlock: - rcu_read_unlock(); -out: - release_sock(sk); - return err; -} - -static void rawv6_err(struct sock *sk, struct sk_buff *skb, - struct inet6_skb_parm *opt, - u8 type, u8 code, int offset, __be32 info) -{ - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *np = inet6_sk(sk); - int err; - int harderr; - - /* Report error on raw socket, if: - 1. User requested recverr. - 2. Socket is connected (otherwise the error indication - is useless without recverr and error is hard. - */ - if (!np->recverr && sk->sk_state != TCP_ESTABLISHED) - return; - - harderr = icmpv6_err_convert(type, code, &err); - if (type == ICMPV6_PKT_TOOBIG) { - ip6_sk_update_pmtu(skb, sk, info); - harderr = (np->pmtudisc == IPV6_PMTUDISC_DO); - } - if (type == NDISC_REDIRECT) { - ip6_sk_redirect(skb, sk); - return; - } - if (np->recverr) { - u8 *payload = skb->data; - if (!inet->hdrincl) - payload += offset; - ipv6_icmp_error(sk, skb, err, 0, ntohl(info), payload); - } - - if (np->recverr || harderr) { - sk->sk_err = err; - sk->sk_error_report(sk); - } -} - -void raw6_icmp_error(struct sk_buff *skb, int nexthdr, - u8 type, u8 code, int inner_offset, __be32 info) -{ - struct sock *sk; - int hash; - const struct in6_addr *saddr, *daddr; - struct net *net; - - hash = nexthdr & (RAW_HTABLE_SIZE - 1); - - read_lock(&raw_v6_hashinfo.lock); - sk = sk_head(&raw_v6_hashinfo.ht[hash]); - if (sk) { - /* Note: ipv6_hdr(skb) != skb->data */ - const struct ipv6hdr *ip6h = (const struct ipv6hdr *)skb->data; - saddr = &ip6h->saddr; - daddr = &ip6h->daddr; - net = dev_net(skb->dev); - - while ((sk = __raw_v6_lookup(net, sk, nexthdr, saddr, daddr, - inet6_iif(skb)))) { - rawv6_err(sk, skb, NULL, type, code, - inner_offset, info); - sk = sk_next(sk); - } - } - read_unlock(&raw_v6_hashinfo.lock); -} - -static inline int rawv6_rcv_skb(struct sock *sk, struct sk_buff *skb) -{ - if ((raw6_sk(sk)->checksum || rcu_access_pointer(sk->sk_filter)) && - skb_checksum_complete(skb)) { - atomic_inc(&sk->sk_drops); - kfree_skb(skb); - return NET_RX_DROP; - } - - /* Charge it to the socket. */ - skb_dst_drop(skb); - if (sock_queue_rcv_skb(sk, skb) < 0) { - kfree_skb(skb); - return NET_RX_DROP; - } - - return 0; -} - -/* - * This is next to useless... - * if we demultiplex in network layer we don't need the extra call - * just to queue the skb... - * maybe we could have the network decide upon a hint if it - * should call raw_rcv for demultiplexing - */ -int rawv6_rcv(struct sock *sk, struct sk_buff *skb) -{ - struct inet_sock *inet = inet_sk(sk); - struct raw6_sock *rp = raw6_sk(sk); - - if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) { - atomic_inc(&sk->sk_drops); - kfree_skb(skb); - return NET_RX_DROP; - } - - if (!rp->checksum) - skb->ip_summed = CHECKSUM_UNNECESSARY; - - if (skb->ip_summed == CHECKSUM_COMPLETE) { - skb_postpull_rcsum(skb, skb_network_header(skb), - skb_network_header_len(skb)); - if (!csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - skb->len, inet->inet_num, skb->csum)) - skb->ip_summed = CHECKSUM_UNNECESSARY; - } - if (!skb_csum_unnecessary(skb)) - skb->csum = ~csum_unfold(csum_ipv6_magic(&ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, - skb->len, - inet->inet_num, 0)); - - if (inet->hdrincl) { - if (skb_checksum_complete(skb)) { - atomic_inc(&sk->sk_drops); - kfree_skb(skb); - return NET_RX_DROP; - } - } - - rawv6_rcv_skb(sk, skb); - return 0; -} - - -/* - * This should be easy, if there is something there - * we return it, otherwise we block. - */ - -static int rawv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, - int noblock, int flags, int *addr_len) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name); - struct sk_buff *skb; - size_t copied; - int err; - - if (flags & MSG_OOB) - return -EOPNOTSUPP; - - if (flags & MSG_ERRQUEUE) - return ipv6_recv_error(sk, msg, len, addr_len); - - if (np->rxpmtu && np->rxopt.bits.rxpmtu) - return ipv6_recv_rxpmtu(sk, msg, len, addr_len); - - skb = skb_recv_datagram(sk, flags, noblock, &err); - if (!skb) - goto out; - - copied = skb->len; - if (copied > len) { - copied = len; - msg->msg_flags |= MSG_TRUNC; - } - - if (skb_csum_unnecessary(skb)) { - err = skb_copy_datagram_msg(skb, 0, msg, copied); - } else if (msg->msg_flags&MSG_TRUNC) { - if (__skb_checksum_complete(skb)) - goto csum_copy_err; - err = skb_copy_datagram_msg(skb, 0, msg, copied); - } else { - err = skb_copy_and_csum_datagram_msg(skb, 0, msg); - if (err == -EINVAL) - goto csum_copy_err; - } - if (err) - goto out_free; - - /* Copy the address. */ - if (sin6) { - sin6->sin6_family = AF_INET6; - sin6->sin6_port = 0; - sin6->sin6_addr = ipv6_hdr(skb)->saddr; - sin6->sin6_flowinfo = 0; - sin6->sin6_scope_id = ipv6_iface_scope_id(&sin6->sin6_addr, - inet6_iif(skb)); - *addr_len = sizeof(*sin6); - } - - sock_recv_ts_and_drops(msg, sk, skb); - - if (np->rxopt.all) - ip6_datagram_recv_ctl(sk, msg, skb); - - err = copied; - if (flags & MSG_TRUNC) - err = skb->len; - -out_free: - skb_free_datagram(sk, skb); -out: - return err; - -csum_copy_err: - skb_kill_datagram(sk, skb, flags); - - /* Error for blocking case is chosen to masquerade - as some normal condition. - */ - err = (flags&MSG_DONTWAIT) ? -EAGAIN : -EHOSTUNREACH; - goto out; -} - -static int rawv6_push_pending_frames(struct sock *sk, struct flowi6 *fl6, - struct raw6_sock *rp) -{ - struct sk_buff *skb; - int err = 0; - int offset; - int len; - int total_len; - __wsum tmp_csum; - __sum16 csum; - - if (!rp->checksum) - goto send; - - skb = skb_peek(&sk->sk_write_queue); - if (!skb) - goto out; - - offset = rp->offset; - total_len = inet_sk(sk)->cork.base.length; - if (offset >= total_len - 1) { - err = -EINVAL; - ip6_flush_pending_frames(sk); - goto out; - } - - /* should be check HW csum miyazawa */ - if (skb_queue_len(&sk->sk_write_queue) == 1) { - /* - * Only one fragment on the socket. - */ - tmp_csum = skb->csum; - } else { - struct sk_buff *csum_skb = NULL; - tmp_csum = 0; - - skb_queue_walk(&sk->sk_write_queue, skb) { - tmp_csum = csum_add(tmp_csum, skb->csum); - - if (csum_skb) - continue; - - len = skb->len - skb_transport_offset(skb); - if (offset >= len) { - offset -= len; - continue; - } - - csum_skb = skb; - } - - skb = csum_skb; - } - - offset += skb_transport_offset(skb); - BUG_ON(skb_copy_bits(skb, offset, &csum, 2)); - - /* in case cksum was not initialized */ - if (unlikely(csum)) - tmp_csum = csum_sub(tmp_csum, csum_unfold(csum)); - - csum = csum_ipv6_magic(&fl6->saddr, &fl6->daddr, - total_len, fl6->flowi6_proto, tmp_csum); - - if (csum == 0 && fl6->flowi6_proto == IPPROTO_UDP) - csum = CSUM_MANGLED_0; - - BUG_ON(skb_store_bits(skb, offset, &csum, 2)); - -send: - err = ip6_push_pending_frames(sk); -out: - return err; -} - -static int rawv6_send_hdrinc(struct sock *sk, struct msghdr *msg, int length, - struct flowi6 *fl6, struct dst_entry **dstp, - unsigned int flags) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct net *net = sock_net(sk); - struct ipv6hdr *iph; - struct sk_buff *skb; - int err; - struct rt6_info *rt = (struct rt6_info *)*dstp; - int hlen = LL_RESERVED_SPACE(rt->dst.dev); - int tlen = rt->dst.dev->needed_tailroom; - - if (length > rt->dst.dev->mtu) { - ipv6_local_error(sk, EMSGSIZE, fl6, rt->dst.dev->mtu); - return -EMSGSIZE; - } - if (flags&MSG_PROBE) - goto out; - - skb = sock_alloc_send_skb(sk, - length + hlen + tlen + 15, - flags & MSG_DONTWAIT, &err); - if (!skb) - goto error; - skb_reserve(skb, hlen); - - skb->protocol = htons(ETH_P_IPV6); - skb->priority = sk->sk_priority; - skb->mark = sk->sk_mark; - skb_dst_set(skb, &rt->dst); - *dstp = NULL; - - skb_put(skb, length); - skb_reset_network_header(skb); - iph = ipv6_hdr(skb); - - skb->ip_summed = CHECKSUM_NONE; - - skb->transport_header = skb->network_header; - err = memcpy_from_msg(iph, msg, length); - if (err) - goto error_fault; - - /* if egress device is enslaved to an L3 master device pass the - * skb to its handler for processing - */ - skb = l3mdev_ip6_out(sk, skb); - if (unlikely(!skb)) - return 0; - - IP6_UPD_PO_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUT, skb->len); - err = NF_HOOK(NFPROTO_IPV6, NF_INET_LOCAL_OUT, net, sk, skb, - NULL, rt->dst.dev, dst_output); - if (err > 0) - err = net_xmit_errno(err); - if (err) - goto error; -out: - return 0; - -error_fault: - err = -EFAULT; - kfree_skb(skb); -error: - IP6_INC_STATS(net, rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); - if (err == -ENOBUFS && !np->recverr) - err = 0; - return err; -} - -struct raw6_frag_vec { - struct msghdr *msg; - int hlen; - char c[4]; -}; - -static int rawv6_probe_proto_opt(struct raw6_frag_vec *rfv, struct flowi6 *fl6) -{ - int err = 0; - switch (fl6->flowi6_proto) { - case IPPROTO_ICMPV6: - rfv->hlen = 2; - err = memcpy_from_msg(rfv->c, rfv->msg, rfv->hlen); - if (!err) { - fl6->fl6_icmp_type = rfv->c[0]; - fl6->fl6_icmp_code = rfv->c[1]; - } - break; - case IPPROTO_MH: - rfv->hlen = 4; - err = memcpy_from_msg(rfv->c, rfv->msg, rfv->hlen); - if (!err) - fl6->fl6_mh_type = rfv->c[2]; - } - return err; -} - -static int raw6_getfrag(void *from, char *to, int offset, int len, int odd, - struct sk_buff *skb) -{ - struct raw6_frag_vec *rfv = from; - - if (offset < rfv->hlen) { - int copy = min(rfv->hlen - offset, len); - - if (skb->ip_summed == CHECKSUM_PARTIAL) - memcpy(to, rfv->c + offset, copy); - else - skb->csum = csum_block_add( - skb->csum, - csum_partial_copy_nocheck(rfv->c + offset, - to, copy, 0), - odd); - - odd = 0; - offset += copy; - to += copy; - len -= copy; - - if (!len) - return 0; - } - - offset -= rfv->hlen; - - return ip_generic_getfrag(rfv->msg, to, offset, len, odd, skb); -} - -static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) -{ - struct ipv6_txoptions *opt_to_free = NULL; - struct ipv6_txoptions opt_space; - DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name); - struct in6_addr *daddr, *final_p, final; - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *np = inet6_sk(sk); - struct raw6_sock *rp = raw6_sk(sk); - struct ipv6_txoptions *opt = NULL; - struct ip6_flowlabel *flowlabel = NULL; - struct dst_entry *dst = NULL; - struct raw6_frag_vec rfv; - struct flowi6 fl6; - struct sockcm_cookie sockc; - struct ipcm6_cookie ipc6; - int addr_len = msg->msg_namelen; - u16 proto; - int err; - - /* Rough check on arithmetic overflow, - better check is made in ip6_append_data(). - */ - if (len > INT_MAX) - return -EMSGSIZE; - - /* Mirror BSD error message compatibility */ - if (msg->msg_flags & MSG_OOB) - return -EOPNOTSUPP; - - /* - * Get and verify the address. - */ - memset(&fl6, 0, sizeof(fl6)); - - fl6.flowi6_mark = sk->sk_mark; - - ipc6.hlimit = -1; - ipc6.tclass = -1; - ipc6.dontfrag = -1; - ipc6.opt = NULL; - - if (sin6) { - if (addr_len < SIN6_LEN_RFC2133) - return -EINVAL; - - if (sin6->sin6_family && sin6->sin6_family != AF_INET6) - return -EAFNOSUPPORT; - - /* port is the proto value [0..255] carried in nexthdr */ - proto = ntohs(sin6->sin6_port); - - if (!proto) - proto = inet->inet_num; - else if (proto != inet->inet_num) - return -EINVAL; - - if (proto > 255) - return -EINVAL; - - daddr = &sin6->sin6_addr; - if (np->sndflow) { - fl6.flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; - if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) { - flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); - if (!flowlabel) - return -EINVAL; - } - } - - /* - * Otherwise it will be difficult to maintain - * sk->sk_dst_cache. - */ - if (sk->sk_state == TCP_ESTABLISHED && - ipv6_addr_equal(daddr, &sk->sk_v6_daddr)) - daddr = &sk->sk_v6_daddr; - - if (addr_len >= sizeof(struct sockaddr_in6) && - sin6->sin6_scope_id && - __ipv6_addr_needs_scope_id(__ipv6_addr_type(daddr))) - fl6.flowi6_oif = sin6->sin6_scope_id; - } else { - if (sk->sk_state != TCP_ESTABLISHED) - return -EDESTADDRREQ; - - proto = inet->inet_num; - daddr = &sk->sk_v6_daddr; - fl6.flowlabel = np->flow_label; - } - - if (fl6.flowi6_oif == 0) - fl6.flowi6_oif = sk->sk_bound_dev_if; - - sockc.tsflags = sk->sk_tsflags; - if (msg->msg_controllen) { - opt = &opt_space; - memset(opt, 0, sizeof(struct ipv6_txoptions)); - opt->tot_len = sizeof(struct ipv6_txoptions); - ipc6.opt = opt; - - err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, &ipc6, &sockc); - if (err < 0) { - fl6_sock_release(flowlabel); - return err; - } - if ((fl6.flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { - flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); - if (!flowlabel) - return -EINVAL; - } - if (!(opt->opt_nflen|opt->opt_flen)) - opt = NULL; - } - if (!opt) { - opt = txopt_get(np); - opt_to_free = opt; - } - if (flowlabel) - opt = fl6_merge_options(&opt_space, flowlabel, opt); - opt = ipv6_fixup_options(&opt_space, opt); - - fl6.flowi6_proto = proto; - rfv.msg = msg; - rfv.hlen = 0; - err = rawv6_probe_proto_opt(&rfv, &fl6); - if (err) - goto out; - - if (!ipv6_addr_any(daddr)) - fl6.daddr = *daddr; - else - fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ - if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr)) - fl6.saddr = np->saddr; - - final_p = fl6_update_dst(&fl6, opt, &final); - - if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) - fl6.flowi6_oif = np->mcast_oif; - else if (!fl6.flowi6_oif) - fl6.flowi6_oif = np->ucast_oif; - security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); - - if (inet->hdrincl) - fl6.flowi6_flags |= FLOWI_FLAG_KNOWN_NH; - - if (ipc6.tclass < 0) - ipc6.tclass = np->tclass; - - fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel); - - dst = ip6_dst_lookup_flow(sk, &fl6, final_p); - if (IS_ERR(dst)) { - err = PTR_ERR(dst); - goto out; - } - if (ipc6.hlimit < 0) - ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); - - if (ipc6.dontfrag < 0) - ipc6.dontfrag = np->dontfrag; - - if (msg->msg_flags&MSG_CONFIRM) - goto do_confirm; - -back_from_confirm: - if (inet->hdrincl) - err = rawv6_send_hdrinc(sk, msg, len, &fl6, &dst, msg->msg_flags); - else { - ipc6.opt = opt; - lock_sock(sk); - err = ip6_append_data(sk, raw6_getfrag, &rfv, - len, 0, &ipc6, &fl6, (struct rt6_info *)dst, - msg->msg_flags, &sockc); - - if (err) - ip6_flush_pending_frames(sk); - else if (!(msg->msg_flags & MSG_MORE)) - err = rawv6_push_pending_frames(sk, &fl6, rp); - release_sock(sk); - } -done: - dst_release(dst); -out: - fl6_sock_release(flowlabel); - txopt_put(opt_to_free); - return err < 0 ? err : len; -do_confirm: - dst_confirm(dst); - if (!(msg->msg_flags & MSG_PROBE) || len) - goto back_from_confirm; - err = 0; - goto done; -} - -static int rawv6_seticmpfilter(struct sock *sk, int level, int optname, - char __user *optval, int optlen) -{ - switch (optname) { - case ICMPV6_FILTER: - if (optlen > sizeof(struct icmp6_filter)) - optlen = sizeof(struct icmp6_filter); - if (copy_from_user(&raw6_sk(sk)->filter, optval, optlen)) - return -EFAULT; - return 0; - default: - return -ENOPROTOOPT; - } - - return 0; -} - -static int rawv6_geticmpfilter(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - int len; - - switch (optname) { - case ICMPV6_FILTER: - if (get_user(len, optlen)) - return -EFAULT; - if (len < 0) - return -EINVAL; - if (len > sizeof(struct icmp6_filter)) - len = sizeof(struct icmp6_filter); - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(optval, &raw6_sk(sk)->filter, len)) - return -EFAULT; - return 0; - default: - return -ENOPROTOOPT; - } - - return 0; -} - - -static int do_rawv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen) -{ - struct raw6_sock *rp = raw6_sk(sk); - int val; - - if (get_user(val, (int __user *)optval)) - return -EFAULT; - - switch (optname) { - case IPV6_HDRINCL: - if (sk->sk_type != SOCK_RAW) - return -EINVAL; - inet_sk(sk)->hdrincl = !!val; - return 0; - case IPV6_CHECKSUM: - if (inet_sk(sk)->inet_num == IPPROTO_ICMPV6 && - level == IPPROTO_IPV6) { - /* - * RFC3542 tells that IPV6_CHECKSUM socket - * option in the IPPROTO_IPV6 level is not - * allowed on ICMPv6 sockets. - * If you want to set it, use IPPROTO_RAW - * level IPV6_CHECKSUM socket option - * (Linux extension). - */ - return -EINVAL; - } - - /* You may get strange result with a positive odd offset; - RFC2292bis agrees with me. */ - if (val > 0 && (val&1)) - return -EINVAL; - if (val < 0) { - rp->checksum = 0; - } else { - rp->checksum = 1; - rp->offset = val; - } - - return 0; - - default: - return -ENOPROTOOPT; - } -} - -static int rawv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen) -{ - switch (level) { - case SOL_RAW: - break; - - case SOL_ICMPV6: - if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6) - return -EOPNOTSUPP; - return rawv6_seticmpfilter(sk, level, optname, optval, optlen); - case SOL_IPV6: - if (optname == IPV6_CHECKSUM || - optname == IPV6_HDRINCL) - break; - default: - return ipv6_setsockopt(sk, level, optname, optval, optlen); - } - - return do_rawv6_setsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -static int compat_rawv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen) -{ - switch (level) { - case SOL_RAW: - break; - case SOL_ICMPV6: - if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6) - return -EOPNOTSUPP; - return rawv6_seticmpfilter(sk, level, optname, optval, optlen); - case SOL_IPV6: - if (optname == IPV6_CHECKSUM || - optname == IPV6_HDRINCL) - break; - default: - return compat_ipv6_setsockopt(sk, level, optname, - optval, optlen); - } - return do_rawv6_setsockopt(sk, level, optname, optval, optlen); -} -#endif - -static int do_rawv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - struct raw6_sock *rp = raw6_sk(sk); - int val, len; - - if (get_user(len, optlen)) - return -EFAULT; - - switch (optname) { - case IPV6_HDRINCL: - val = inet_sk(sk)->hdrincl; - break; - case IPV6_CHECKSUM: - /* - * We allow getsockopt() for IPPROTO_IPV6-level - * IPV6_CHECKSUM socket option on ICMPv6 sockets - * since RFC3542 is silent about it. - */ - if (rp->checksum == 0) - val = -1; - else - val = rp->offset; - break; - - default: - return -ENOPROTOOPT; - } - - len = min_t(unsigned int, sizeof(int), len); - - if (put_user(len, optlen)) - return -EFAULT; - if (copy_to_user(optval, &val, len)) - return -EFAULT; - return 0; -} - -static int rawv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - switch (level) { - case SOL_RAW: - break; - - case SOL_ICMPV6: - if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6) - return -EOPNOTSUPP; - return rawv6_geticmpfilter(sk, level, optname, optval, optlen); - case SOL_IPV6: - if (optname == IPV6_CHECKSUM || - optname == IPV6_HDRINCL) - break; - default: - return ipv6_getsockopt(sk, level, optname, optval, optlen); - } - - return do_rawv6_getsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -static int compat_rawv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - switch (level) { - case SOL_RAW: - break; - case SOL_ICMPV6: - if (inet_sk(sk)->inet_num != IPPROTO_ICMPV6) - return -EOPNOTSUPP; - return rawv6_geticmpfilter(sk, level, optname, optval, optlen); - case SOL_IPV6: - if (optname == IPV6_CHECKSUM || - optname == IPV6_HDRINCL) - break; - default: - return compat_ipv6_getsockopt(sk, level, optname, - optval, optlen); - } - return do_rawv6_getsockopt(sk, level, optname, optval, optlen); -} -#endif - -static int rawv6_ioctl(struct sock *sk, int cmd, unsigned long arg) -{ - switch (cmd) { - case SIOCOUTQ: { - int amount = sk_wmem_alloc_get(sk); - - return put_user(amount, (int __user *)arg); - } - case SIOCINQ: { - struct sk_buff *skb; - int amount = 0; - - spin_lock_bh(&sk->sk_receive_queue.lock); - skb = skb_peek(&sk->sk_receive_queue); - if (skb) - amount = skb_tail_pointer(skb) - - skb_transport_header(skb); - spin_unlock_bh(&sk->sk_receive_queue.lock); - return put_user(amount, (int __user *)arg); - } - - default: -#ifdef CONFIG_IPV6_MROUTE - return ip6mr_ioctl(sk, cmd, (void __user *)arg); -#else - return -ENOIOCTLCMD; -#endif - } -} - -#ifdef CONFIG_COMPAT -static int compat_rawv6_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg) -{ - switch (cmd) { - case SIOCOUTQ: - case SIOCINQ: - return -ENOIOCTLCMD; - default: -#ifdef CONFIG_IPV6_MROUTE - return ip6mr_compat_ioctl(sk, cmd, compat_ptr(arg)); -#else - return -ENOIOCTLCMD; -#endif - } -} -#endif - -static void rawv6_close(struct sock *sk, long timeout) -{ - if (inet_sk(sk)->inet_num == IPPROTO_RAW) - ip6_ra_control(sk, -1); - ip6mr_sk_done(sk); - sk_common_release(sk); -} - -static void raw6_destroy(struct sock *sk) -{ - lock_sock(sk); - ip6_flush_pending_frames(sk); - release_sock(sk); - - inet6_destroy_sock(sk); -} - -static int rawv6_init_sk(struct sock *sk) -{ - struct raw6_sock *rp = raw6_sk(sk); - - switch (inet_sk(sk)->inet_num) { - case IPPROTO_ICMPV6: - rp->checksum = 1; - rp->offset = 2; - break; - case IPPROTO_MH: - rp->checksum = 1; - rp->offset = 4; - break; - default: - break; - } - return 0; -} - -struct proto rawv6_prot = { - .name = "RAWv6", - .owner = THIS_MODULE, - .close = rawv6_close, - .destroy = raw6_destroy, - .connect = ip6_datagram_connect_v6_only, - .disconnect = __udp_disconnect, - .ioctl = rawv6_ioctl, - .init = rawv6_init_sk, - .setsockopt = rawv6_setsockopt, - .getsockopt = rawv6_getsockopt, - .sendmsg = rawv6_sendmsg, - .recvmsg = rawv6_recvmsg, - .bind = rawv6_bind, - .backlog_rcv = rawv6_rcv_skb, - .hash = raw_hash_sk, - .unhash = raw_unhash_sk, - .obj_size = sizeof(struct raw6_sock), - .h.raw_hash = &raw_v6_hashinfo, -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_rawv6_setsockopt, - .compat_getsockopt = compat_rawv6_getsockopt, - .compat_ioctl = compat_rawv6_ioctl, -#endif -}; - -#ifdef CONFIG_PROC_FS -static int raw6_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) { - seq_puts(seq, IPV6_SEQ_DGRAM_HEADER); - } else { - struct sock *sp = v; - __u16 srcp = inet_sk(sp)->inet_num; - ip6_dgram_sock_seq_show(seq, v, srcp, 0, - raw_seq_private(seq)->bucket); - } - return 0; -} - -static const struct seq_operations raw6_seq_ops = { - .start = raw_seq_start, - .next = raw_seq_next, - .stop = raw_seq_stop, - .show = raw6_seq_show, -}; - -static int raw6_seq_open(struct inode *inode, struct file *file) -{ - return raw_seq_open(inode, file, &raw_v6_hashinfo, &raw6_seq_ops); -} - -static const struct file_operations raw6_seq_fops = { - .owner = THIS_MODULE, - .open = raw6_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -static int __net_init raw6_init_net(struct net *net) -{ - if (!proc_create("raw6", S_IRUGO, net->proc_net, &raw6_seq_fops)) - return -ENOMEM; - - return 0; -} - -static void __net_exit raw6_exit_net(struct net *net) -{ - remove_proc_entry("raw6", net->proc_net); -} - -static struct pernet_operations raw6_net_ops = { - .init = raw6_init_net, - .exit = raw6_exit_net, -}; - -int __init raw6_proc_init(void) -{ - return register_pernet_subsys(&raw6_net_ops); -} - -void raw6_proc_exit(void) -{ - unregister_pernet_subsys(&raw6_net_ops); -} -#endif /* CONFIG_PROC_FS */ - -/* Same as inet6_dgram_ops, sans udp_poll. */ -static const struct proto_ops inet6_sockraw_ops = { - .family = PF_INET6, - .owner = THIS_MODULE, - .release = inet6_release, - .bind = inet6_bind, - .connect = inet_dgram_connect, /* ok */ - .socketpair = sock_no_socketpair, /* a do nothing */ - .accept = sock_no_accept, /* a do nothing */ - .getname = inet6_getname, - .poll = datagram_poll, /* ok */ - .ioctl = inet6_ioctl, /* must change */ - .listen = sock_no_listen, /* ok */ - .shutdown = inet_shutdown, /* ok */ - .setsockopt = sock_common_setsockopt, /* ok */ - .getsockopt = sock_common_getsockopt, /* ok */ - .sendmsg = inet_sendmsg, /* ok */ - .recvmsg = sock_common_recvmsg, /* ok */ - .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_sock_common_setsockopt, - .compat_getsockopt = compat_sock_common_getsockopt, -#endif -}; - -static struct inet_protosw rawv6_protosw = { - .type = SOCK_RAW, - .protocol = IPPROTO_IP, /* wild card */ - .prot = &rawv6_prot, - .ops = &inet6_sockraw_ops, - .flags = INET_PROTOSW_REUSE, -}; - -int __init rawv6_init(void) -{ - return inet6_register_protosw(&rawv6_protosw); -} - -void rawv6_exit(void) -{ - inet6_unregister_protosw(&rawv6_protosw); -} diff --git a/src/linux/net/ipv6/reassembly.c b/src/linux/net/ipv6/reassembly.c deleted file mode 100644 index 3815e85..0000000 --- a/src/linux/net/ipv6/reassembly.c +++ /dev/null @@ -1,780 +0,0 @@ -/* - * IPv6 fragment reassembly - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * Based on: net/ipv4/ip_fragment.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -/* - * Fixes: - * Andi Kleen Make it work with multiple hosts. - * More RFC compliance. - * - * Horst von Brand Add missing #include - * Alexey Kuznetsov SMP races, threading, cleanup. - * Patrick McHardy LRU queue of frag heads for evictor. - * Mitsuru KANDA @USAGI Register inet6_protocol{}. - * David Stevens and - * YOSHIFUJI,H. @USAGI Always remove fragment header to - * calculate ICV correctly. - */ - -#define pr_fmt(fmt) "IPv6: " fmt - -#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 - -static const char ip6_frag_cache_name[] = "ip6-frags"; - -struct ip6frag_skb_cb { - struct inet6_skb_parm h; - int offset; -}; - -#define FRAG6_CB(skb) ((struct ip6frag_skb_cb *)((skb)->cb)) - -static u8 ip6_frag_ecn(const struct ipv6hdr *ipv6h) -{ - return 1 << (ipv6_get_dsfield(ipv6h) & INET_ECN_MASK); -} - -static struct inet_frags ip6_frags; - -static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, - struct net_device *dev); - -/* - * callers should be careful not to use the hash value outside the ipfrag_lock - * as doing so could race with ipfrag_hash_rnd being recalculated. - */ -static unsigned int inet6_hash_frag(__be32 id, const struct in6_addr *saddr, - const struct in6_addr *daddr) -{ - net_get_random_once(&ip6_frags.rnd, sizeof(ip6_frags.rnd)); - return jhash_3words(ipv6_addr_hash(saddr), ipv6_addr_hash(daddr), - (__force u32)id, ip6_frags.rnd); -} - -static unsigned int ip6_hashfn(const struct inet_frag_queue *q) -{ - const struct frag_queue *fq; - - fq = container_of(q, struct frag_queue, q); - return inet6_hash_frag(fq->id, &fq->saddr, &fq->daddr); -} - -bool ip6_frag_match(const struct inet_frag_queue *q, const void *a) -{ - const struct frag_queue *fq; - const struct ip6_create_arg *arg = a; - - fq = container_of(q, struct frag_queue, q); - return fq->id == arg->id && - fq->user == arg->user && - ipv6_addr_equal(&fq->saddr, arg->src) && - ipv6_addr_equal(&fq->daddr, arg->dst) && - (arg->iif == fq->iif || - !(ipv6_addr_type(arg->dst) & (IPV6_ADDR_MULTICAST | - IPV6_ADDR_LINKLOCAL))); -} -EXPORT_SYMBOL(ip6_frag_match); - -void ip6_frag_init(struct inet_frag_queue *q, const void *a) -{ - struct frag_queue *fq = container_of(q, struct frag_queue, q); - const struct ip6_create_arg *arg = a; - - fq->id = arg->id; - fq->user = arg->user; - fq->saddr = *arg->src; - fq->daddr = *arg->dst; - fq->ecn = arg->ecn; -} -EXPORT_SYMBOL(ip6_frag_init); - -void ip6_expire_frag_queue(struct net *net, struct frag_queue *fq, - struct inet_frags *frags) -{ - struct net_device *dev = NULL; - - spin_lock(&fq->q.lock); - - if (fq->q.flags & INET_FRAG_COMPLETE) - goto out; - - inet_frag_kill(&fq->q, frags); - - rcu_read_lock(); - dev = dev_get_by_index_rcu(net, fq->iif); - if (!dev) - goto out_rcu_unlock; - - __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); - - if (inet_frag_evicting(&fq->q)) - goto out_rcu_unlock; - - __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMTIMEOUT); - - /* Don't send error if the first segment did not arrive. */ - if (!(fq->q.flags & INET_FRAG_FIRST_IN) || !fq->q.fragments) - goto out_rcu_unlock; - - /* But use as source device on which LAST ARRIVED - * segment was received. And do not use fq->dev - * pointer directly, device might already disappeared. - */ - fq->q.fragments->dev = dev; - icmpv6_send(fq->q.fragments, ICMPV6_TIME_EXCEED, ICMPV6_EXC_FRAGTIME, 0); -out_rcu_unlock: - rcu_read_unlock(); -out: - spin_unlock(&fq->q.lock); - inet_frag_put(&fq->q, frags); -} -EXPORT_SYMBOL(ip6_expire_frag_queue); - -static void ip6_frag_expire(unsigned long data) -{ - struct frag_queue *fq; - struct net *net; - - fq = container_of((struct inet_frag_queue *)data, struct frag_queue, q); - net = container_of(fq->q.net, struct net, ipv6.frags); - - ip6_expire_frag_queue(net, fq, &ip6_frags); -} - -static struct frag_queue * -fq_find(struct net *net, __be32 id, const struct in6_addr *src, - const struct in6_addr *dst, int iif, u8 ecn) -{ - struct inet_frag_queue *q; - struct ip6_create_arg arg; - unsigned int hash; - - arg.id = id; - arg.user = IP6_DEFRAG_LOCAL_DELIVER; - arg.src = src; - arg.dst = dst; - arg.iif = iif; - arg.ecn = ecn; - - hash = inet6_hash_frag(id, src, dst); - - q = inet_frag_find(&net->ipv6.frags, &ip6_frags, &arg, hash); - if (IS_ERR_OR_NULL(q)) { - inet_frag_maybe_warn_overflow(q, pr_fmt()); - return NULL; - } - return container_of(q, struct frag_queue, q); -} - -static int ip6_frag_queue(struct frag_queue *fq, struct sk_buff *skb, - struct frag_hdr *fhdr, int nhoff) -{ - struct sk_buff *prev, *next; - struct net_device *dev; - int offset, end; - struct net *net = dev_net(skb_dst(skb)->dev); - u8 ecn; - - if (fq->q.flags & INET_FRAG_COMPLETE) - goto err; - - offset = ntohs(fhdr->frag_off) & ~0x7; - end = offset + (ntohs(ipv6_hdr(skb)->payload_len) - - ((u8 *)(fhdr + 1) - (u8 *)(ipv6_hdr(skb) + 1))); - - if ((unsigned int)end > IPV6_MAXPLEN) { - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_INHDRERRORS); - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, - ((u8 *)&fhdr->frag_off - - skb_network_header(skb))); - return -1; - } - - ecn = ip6_frag_ecn(ipv6_hdr(skb)); - - if (skb->ip_summed == CHECKSUM_COMPLETE) { - const unsigned char *nh = skb_network_header(skb); - skb->csum = csum_sub(skb->csum, - csum_partial(nh, (u8 *)(fhdr + 1) - nh, - 0)); - } - - /* Is this the final fragment? */ - if (!(fhdr->frag_off & htons(IP6_MF))) { - /* If we already have some bits beyond end - * or have different end, the segment is corrupted. - */ - if (end < fq->q.len || - ((fq->q.flags & INET_FRAG_LAST_IN) && end != fq->q.len)) - goto err; - fq->q.flags |= INET_FRAG_LAST_IN; - fq->q.len = end; - } else { - /* Check if the fragment is rounded to 8 bytes. - * Required by the RFC. - */ - if (end & 0x7) { - /* RFC2460 says always send parameter problem in - * this case. -DaveM - */ - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_INHDRERRORS); - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, - offsetof(struct ipv6hdr, payload_len)); - return -1; - } - if (end > fq->q.len) { - /* Some bits beyond end -> corruption. */ - if (fq->q.flags & INET_FRAG_LAST_IN) - goto err; - fq->q.len = end; - } - } - - if (end == offset) - goto err; - - /* Point into the IP datagram 'data' part. */ - if (!pskb_pull(skb, (u8 *) (fhdr + 1) - skb->data)) - goto err; - - if (pskb_trim_rcsum(skb, end - offset)) - goto err; - - /* Find out which fragments are in front and at the back of us - * in the chain of fragments so far. We must know where to put - * this fragment, right? - */ - prev = fq->q.fragments_tail; - if (!prev || FRAG6_CB(prev)->offset < offset) { - next = NULL; - goto found; - } - prev = NULL; - for (next = fq->q.fragments; next != NULL; next = next->next) { - if (FRAG6_CB(next)->offset >= offset) - break; /* bingo! */ - prev = next; - } - -found: - /* RFC5722, Section 4, amended by Errata ID : 3089 - * When reassembling an IPv6 datagram, if - * one or more its constituent fragments is determined to be an - * overlapping fragment, the entire datagram (and any constituent - * fragments) MUST be silently discarded. - */ - - /* Check for overlap with preceding fragment. */ - if (prev && - (FRAG6_CB(prev)->offset + prev->len) > offset) - goto discard_fq; - - /* Look for overlap with succeeding segment. */ - if (next && FRAG6_CB(next)->offset < end) - goto discard_fq; - - FRAG6_CB(skb)->offset = offset; - - /* Insert this fragment in the chain of fragments. */ - skb->next = next; - if (!next) - fq->q.fragments_tail = skb; - if (prev) - prev->next = skb; - else - fq->q.fragments = skb; - - dev = skb->dev; - if (dev) { - fq->iif = dev->ifindex; - skb->dev = NULL; - } - fq->q.stamp = skb->tstamp; - fq->q.meat += skb->len; - fq->ecn |= ecn; - add_frag_mem_limit(fq->q.net, skb->truesize); - - /* The first fragment. - * nhoffset is obtained from the first fragment, of course. - */ - if (offset == 0) { - fq->nhoffset = nhoff; - fq->q.flags |= INET_FRAG_FIRST_IN; - } - - if (fq->q.flags == (INET_FRAG_FIRST_IN | INET_FRAG_LAST_IN) && - fq->q.meat == fq->q.len) { - int res; - unsigned long orefdst = skb->_skb_refdst; - - skb->_skb_refdst = 0UL; - res = ip6_frag_reasm(fq, prev, dev); - skb->_skb_refdst = orefdst; - return res; - } - - skb_dst_drop(skb); - return -1; - -discard_fq: - inet_frag_kill(&fq->q, &ip6_frags); -err: - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_REASMFAILS); - kfree_skb(skb); - return -1; -} - -/* - * Check if this packet is complete. - * Returns NULL on failure by any reason, and pointer - * to current nexthdr field in reassembled frame. - * - * It is called with locked fq, and caller must check that - * queue is eligible for reassembly i.e. it is not COMPLETE, - * the last and the first frames arrived and all the bits are here. - */ -static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev, - struct net_device *dev) -{ - struct net *net = container_of(fq->q.net, struct net, ipv6.frags); - struct sk_buff *fp, *head = fq->q.fragments; - int payload_len; - unsigned int nhoff; - int sum_truesize; - u8 ecn; - - inet_frag_kill(&fq->q, &ip6_frags); - - ecn = ip_frag_ecn_table[fq->ecn]; - if (unlikely(ecn == 0xff)) - goto out_fail; - - /* Make the one we just received the head. */ - if (prev) { - head = prev->next; - fp = skb_clone(head, GFP_ATOMIC); - - if (!fp) - goto out_oom; - - fp->next = head->next; - if (!fp->next) - fq->q.fragments_tail = fp; - prev->next = fp; - - skb_morph(head, fq->q.fragments); - head->next = fq->q.fragments->next; - - consume_skb(fq->q.fragments); - fq->q.fragments = head; - } - - WARN_ON(head == NULL); - WARN_ON(FRAG6_CB(head)->offset != 0); - - /* Unfragmented part is taken from the first segment. */ - payload_len = ((head->data - skb_network_header(head)) - - sizeof(struct ipv6hdr) + fq->q.len - - sizeof(struct frag_hdr)); - if (payload_len > IPV6_MAXPLEN) - goto out_oversize; - - /* Head of list must not be cloned. */ - if (skb_unclone(head, GFP_ATOMIC)) - goto out_oom; - - /* If the first fragment is fragmented itself, we split - * it to two chunks: the first with data and paged part - * and the second, holding only fragments. */ - if (skb_has_frag_list(head)) { - struct sk_buff *clone; - int i, plen = 0; - - clone = alloc_skb(0, GFP_ATOMIC); - if (!clone) - goto out_oom; - clone->next = head->next; - head->next = clone; - skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; - skb_frag_list_init(head); - for (i = 0; i < skb_shinfo(head)->nr_frags; i++) - plen += skb_frag_size(&skb_shinfo(head)->frags[i]); - clone->len = clone->data_len = head->data_len - plen; - head->data_len -= clone->len; - head->len -= clone->len; - clone->csum = 0; - clone->ip_summed = head->ip_summed; - add_frag_mem_limit(fq->q.net, clone->truesize); - } - - /* We have to remove fragment header from datagram and to relocate - * header in order to calculate ICV correctly. */ - nhoff = fq->nhoffset; - skb_network_header(head)[nhoff] = skb_transport_header(head)[0]; - memmove(head->head + sizeof(struct frag_hdr), head->head, - (head->data - head->head) - sizeof(struct frag_hdr)); - if (skb_mac_header_was_set(head)) - head->mac_header += sizeof(struct frag_hdr); - head->network_header += sizeof(struct frag_hdr); - - skb_reset_transport_header(head); - skb_push(head, head->data - skb_network_header(head)); - - sum_truesize = head->truesize; - for (fp = head->next; fp;) { - bool headstolen; - int delta; - struct sk_buff *next = fp->next; - - sum_truesize += fp->truesize; - if (head->ip_summed != fp->ip_summed) - head->ip_summed = CHECKSUM_NONE; - else if (head->ip_summed == CHECKSUM_COMPLETE) - head->csum = csum_add(head->csum, fp->csum); - - if (skb_try_coalesce(head, fp, &headstolen, &delta)) { - kfree_skb_partial(fp, headstolen); - } else { - if (!skb_shinfo(head)->frag_list) - skb_shinfo(head)->frag_list = fp; - head->data_len += fp->len; - head->len += fp->len; - head->truesize += fp->truesize; - } - fp = next; - } - sub_frag_mem_limit(fq->q.net, sum_truesize); - - head->next = NULL; - head->dev = dev; - head->tstamp = fq->q.stamp; - ipv6_hdr(head)->payload_len = htons(payload_len); - ipv6_change_dsfield(ipv6_hdr(head), 0xff, ecn); - IP6CB(head)->nhoff = nhoff; - IP6CB(head)->flags |= IP6SKB_FRAGMENTED; - - /* Yes, and fold redundant checksum back. 8) */ - skb_postpush_rcsum(head, skb_network_header(head), - skb_network_header_len(head)); - - rcu_read_lock(); - __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS); - rcu_read_unlock(); - fq->q.fragments = NULL; - fq->q.fragments_tail = NULL; - return 1; - -out_oversize: - net_dbg_ratelimited("ip6_frag_reasm: payload len = %d\n", payload_len); - goto out_fail; -out_oom: - net_dbg_ratelimited("ip6_frag_reasm: no memory for reassembly\n"); -out_fail: - rcu_read_lock(); - __IP6_INC_STATS(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS); - rcu_read_unlock(); - return -1; -} - -static int ipv6_frag_rcv(struct sk_buff *skb) -{ - struct frag_hdr *fhdr; - struct frag_queue *fq; - const struct ipv6hdr *hdr = ipv6_hdr(skb); - struct net *net = dev_net(skb_dst(skb)->dev); - - if (IP6CB(skb)->flags & IP6SKB_FRAGMENTED) - goto fail_hdr; - - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMREQDS); - - /* Jumbo payload inhibits frag. header */ - if (hdr->payload_len == 0) - goto fail_hdr; - - if (!pskb_may_pull(skb, (skb_transport_offset(skb) + - sizeof(struct frag_hdr)))) - goto fail_hdr; - - hdr = ipv6_hdr(skb); - fhdr = (struct frag_hdr *)skb_transport_header(skb); - - if (!(fhdr->frag_off & htons(0xFFF9))) { - /* It is not a fragmented frame */ - skb->transport_header += sizeof(struct frag_hdr); - __IP6_INC_STATS(net, - ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMOKS); - - IP6CB(skb)->nhoff = (u8 *)fhdr - skb_network_header(skb); - IP6CB(skb)->flags |= IP6SKB_FRAGMENTED; - return 1; - } - - fq = fq_find(net, fhdr->identification, &hdr->saddr, &hdr->daddr, - skb->dev ? skb->dev->ifindex : 0, ip6_frag_ecn(hdr)); - if (fq) { - int ret; - - spin_lock(&fq->q.lock); - - ret = ip6_frag_queue(fq, skb, fhdr, IP6CB(skb)->nhoff); - - spin_unlock(&fq->q.lock); - inet_frag_put(&fq->q, &ip6_frags); - return ret; - } - - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), IPSTATS_MIB_REASMFAILS); - kfree_skb(skb); - return -1; - -fail_hdr: - __IP6_INC_STATS(net, ip6_dst_idev(skb_dst(skb)), - IPSTATS_MIB_INHDRERRORS); - icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, skb_network_header_len(skb)); - return -1; -} - -static const struct inet6_protocol frag_protocol = { - .handler = ipv6_frag_rcv, - .flags = INET6_PROTO_NOPOLICY, -}; - -#ifdef CONFIG_SYSCTL -static int zero; - -static struct ctl_table ip6_frags_ns_ctl_table[] = { - { - .procname = "ip6frag_high_thresh", - .data = &init_net.ipv6.frags.high_thresh, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &init_net.ipv6.frags.low_thresh - }, - { - .procname = "ip6frag_low_thresh", - .data = &init_net.ipv6.frags.low_thresh, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &zero, - .extra2 = &init_net.ipv6.frags.high_thresh - }, - { - .procname = "ip6frag_time", - .data = &init_net.ipv6.frags.timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { } -}; - -/* secret interval has been deprecated */ -static int ip6_frags_secret_interval_unused; -static struct ctl_table ip6_frags_ctl_table[] = { - { - .procname = "ip6frag_secret_interval", - .data = &ip6_frags_secret_interval_unused, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { } -}; - -static int __net_init ip6_frags_ns_sysctl_register(struct net *net) -{ - struct ctl_table *table; - struct ctl_table_header *hdr; - - table = ip6_frags_ns_ctl_table; - if (!net_eq(net, &init_net)) { - table = kmemdup(table, sizeof(ip6_frags_ns_ctl_table), GFP_KERNEL); - if (!table) - goto err_alloc; - - table[0].data = &net->ipv6.frags.high_thresh; - table[0].extra1 = &net->ipv6.frags.low_thresh; - table[0].extra2 = &init_net.ipv6.frags.high_thresh; - table[1].data = &net->ipv6.frags.low_thresh; - table[1].extra2 = &net->ipv6.frags.high_thresh; - table[2].data = &net->ipv6.frags.timeout; - - /* Don't export sysctls to unprivileged users */ - if (net->user_ns != &init_user_ns) - table[0].procname = NULL; - } - - hdr = register_net_sysctl(net, "net/ipv6", table); - if (!hdr) - goto err_reg; - - net->ipv6.sysctl.frags_hdr = hdr; - return 0; - -err_reg: - if (!net_eq(net, &init_net)) - kfree(table); -err_alloc: - return -ENOMEM; -} - -static void __net_exit ip6_frags_ns_sysctl_unregister(struct net *net) -{ - struct ctl_table *table; - - table = net->ipv6.sysctl.frags_hdr->ctl_table_arg; - unregister_net_sysctl_table(net->ipv6.sysctl.frags_hdr); - if (!net_eq(net, &init_net)) - kfree(table); -} - -static struct ctl_table_header *ip6_ctl_header; - -static int ip6_frags_sysctl_register(void) -{ - ip6_ctl_header = register_net_sysctl(&init_net, "net/ipv6", - ip6_frags_ctl_table); - return ip6_ctl_header == NULL ? -ENOMEM : 0; -} - -static void ip6_frags_sysctl_unregister(void) -{ - unregister_net_sysctl_table(ip6_ctl_header); -} -#else -static int ip6_frags_ns_sysctl_register(struct net *net) -{ - return 0; -} - -static void ip6_frags_ns_sysctl_unregister(struct net *net) -{ -} - -static int ip6_frags_sysctl_register(void) -{ - return 0; -} - -static void ip6_frags_sysctl_unregister(void) -{ -} -#endif - -static int __net_init ipv6_frags_init_net(struct net *net) -{ - int res; - - net->ipv6.frags.high_thresh = IPV6_FRAG_HIGH_THRESH; - net->ipv6.frags.low_thresh = IPV6_FRAG_LOW_THRESH; - net->ipv6.frags.timeout = IPV6_FRAG_TIMEOUT; - - res = inet_frags_init_net(&net->ipv6.frags); - if (res) - return res; - res = ip6_frags_ns_sysctl_register(net); - if (res) - inet_frags_uninit_net(&net->ipv6.frags); - return res; -} - -static void __net_exit ipv6_frags_exit_net(struct net *net) -{ - ip6_frags_ns_sysctl_unregister(net); - inet_frags_exit_net(&net->ipv6.frags, &ip6_frags); -} - -static struct pernet_operations ip6_frags_ops = { - .init = ipv6_frags_init_net, - .exit = ipv6_frags_exit_net, -}; - -int __init ipv6_frag_init(void) -{ - int ret; - - ret = inet6_add_protocol(&frag_protocol, IPPROTO_FRAGMENT); - if (ret) - goto out; - - ret = ip6_frags_sysctl_register(); - if (ret) - goto err_sysctl; - - ret = register_pernet_subsys(&ip6_frags_ops); - if (ret) - goto err_pernet; - - ip6_frags.hashfn = ip6_hashfn; - ip6_frags.constructor = ip6_frag_init; - ip6_frags.destructor = NULL; - ip6_frags.qsize = sizeof(struct frag_queue); - ip6_frags.match = ip6_frag_match; - ip6_frags.frag_expire = ip6_frag_expire; - ip6_frags.frags_cache_name = ip6_frag_cache_name; - ret = inet_frags_init(&ip6_frags); - if (ret) - goto err_pernet; -out: - return ret; - -err_pernet: - ip6_frags_sysctl_unregister(); -err_sysctl: - inet6_del_protocol(&frag_protocol, IPPROTO_FRAGMENT); - goto out; -} - -void ipv6_frag_exit(void) -{ - inet_frags_fini(&ip6_frags); - ip6_frags_sysctl_unregister(); - unregister_pernet_subsys(&ip6_frags_ops); - inet6_del_protocol(&frag_protocol, IPPROTO_FRAGMENT); -} diff --git a/src/linux/net/ipv6/route.c b/src/linux/net/ipv6/route.c deleted file mode 100644 index 1b57e11..0000000 --- a/src/linux/net/ipv6/route.c +++ /dev/null @@ -1,3887 +0,0 @@ -/* - * Linux INET6 implementation - * FIB front-end. - * - * Authors: - * Pedro Roque - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -/* Changes: - * - * YOSHIFUJI Hideaki @USAGI - * reworked default router selection. - * - respect outgoing interface - * - select from (probably) reachable routers (i.e. - * routers in REACHABLE, STALE, DELAY or PROBE states). - * - always select the same router if it is (probably) - * reachable. otherwise, round-robin the list. - * Ville Nuorvala - * Fixed routing subtrees. - */ - -#define pr_fmt(fmt) "IPv6: " fmt - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#ifdef CONFIG_SYSCTL -#include -#endif - -enum rt6_nud_state { - RT6_NUD_FAIL_HARD = -3, - RT6_NUD_FAIL_PROBE = -2, - RT6_NUD_FAIL_DO_RR = -1, - RT6_NUD_SUCCEED = 1 -}; - -static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort); -static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie); -static unsigned int ip6_default_advmss(const struct dst_entry *dst); -static unsigned int ip6_mtu(const struct dst_entry *dst); -static struct dst_entry *ip6_negative_advice(struct dst_entry *); -static void ip6_dst_destroy(struct dst_entry *); -static void ip6_dst_ifdown(struct dst_entry *, - struct net_device *dev, int how); -static int ip6_dst_gc(struct dst_ops *ops); - -static int ip6_pkt_discard(struct sk_buff *skb); -static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb); -static int ip6_pkt_prohibit(struct sk_buff *skb); -static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb); -static void ip6_link_failure(struct sk_buff *skb); -static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, - struct sk_buff *skb, u32 mtu); -static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, - struct sk_buff *skb); -static void rt6_dst_from_metrics_check(struct rt6_info *rt); -static int rt6_score_route(struct rt6_info *rt, int oif, int strict); - -#ifdef CONFIG_IPV6_ROUTE_INFO -static struct rt6_info *rt6_add_route_info(struct net *net, - const struct in6_addr *prefix, int prefixlen, - const struct in6_addr *gwaddr, - struct net_device *dev, - unsigned int pref); -static struct rt6_info *rt6_get_route_info(struct net *net, - const struct in6_addr *prefix, int prefixlen, - const struct in6_addr *gwaddr, - struct net_device *dev); -#endif - -struct uncached_list { - spinlock_t lock; - struct list_head head; -}; - -static DEFINE_PER_CPU_ALIGNED(struct uncached_list, rt6_uncached_list); - -static void rt6_uncached_list_add(struct rt6_info *rt) -{ - struct uncached_list *ul = raw_cpu_ptr(&rt6_uncached_list); - - rt->dst.flags |= DST_NOCACHE; - rt->rt6i_uncached_list = ul; - - spin_lock_bh(&ul->lock); - list_add_tail(&rt->rt6i_uncached, &ul->head); - spin_unlock_bh(&ul->lock); -} - -static void rt6_uncached_list_del(struct rt6_info *rt) -{ - if (!list_empty(&rt->rt6i_uncached)) { - struct uncached_list *ul = rt->rt6i_uncached_list; - - spin_lock_bh(&ul->lock); - list_del(&rt->rt6i_uncached); - spin_unlock_bh(&ul->lock); - } -} - -static void rt6_uncached_list_flush_dev(struct net *net, struct net_device *dev) -{ - struct net_device *loopback_dev = net->loopback_dev; - int cpu; - - if (dev == loopback_dev) - return; - - for_each_possible_cpu(cpu) { - struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu); - struct rt6_info *rt; - - spin_lock_bh(&ul->lock); - list_for_each_entry(rt, &ul->head, rt6i_uncached) { - struct inet6_dev *rt_idev = rt->rt6i_idev; - struct net_device *rt_dev = rt->dst.dev; - - if (rt_idev->dev == dev) { - rt->rt6i_idev = in6_dev_get(loopback_dev); - in6_dev_put(rt_idev); - } - - if (rt_dev == dev) { - rt->dst.dev = loopback_dev; - dev_hold(rt->dst.dev); - dev_put(rt_dev); - } - } - spin_unlock_bh(&ul->lock); - } -} - -static u32 *rt6_pcpu_cow_metrics(struct rt6_info *rt) -{ - return dst_metrics_write_ptr(rt->dst.from); -} - -static u32 *ipv6_cow_metrics(struct dst_entry *dst, unsigned long old) -{ - struct rt6_info *rt = (struct rt6_info *)dst; - - if (rt->rt6i_flags & RTF_PCPU) - return rt6_pcpu_cow_metrics(rt); - else if (rt->rt6i_flags & RTF_CACHE) - return NULL; - else - return dst_cow_metrics_generic(dst, old); -} - -static inline const void *choose_neigh_daddr(struct rt6_info *rt, - struct sk_buff *skb, - const void *daddr) -{ - struct in6_addr *p = &rt->rt6i_gateway; - - if (!ipv6_addr_any(p)) - return (const void *) p; - else if (skb) - return &ipv6_hdr(skb)->daddr; - return daddr; -} - -static struct neighbour *ip6_neigh_lookup(const struct dst_entry *dst, - struct sk_buff *skb, - const void *daddr) -{ - struct rt6_info *rt = (struct rt6_info *) dst; - struct neighbour *n; - - daddr = choose_neigh_daddr(rt, skb, daddr); - n = __ipv6_neigh_lookup(dst->dev, daddr); - if (n) - return n; - return neigh_create(&nd_tbl, daddr, dst->dev); -} - -static struct dst_ops ip6_dst_ops_template = { - .family = AF_INET6, - .gc = ip6_dst_gc, - .gc_thresh = 1024, - .check = ip6_dst_check, - .default_advmss = ip6_default_advmss, - .mtu = ip6_mtu, - .cow_metrics = ipv6_cow_metrics, - .destroy = ip6_dst_destroy, - .ifdown = ip6_dst_ifdown, - .negative_advice = ip6_negative_advice, - .link_failure = ip6_link_failure, - .update_pmtu = ip6_rt_update_pmtu, - .redirect = rt6_do_redirect, - .local_out = __ip6_local_out, - .neigh_lookup = ip6_neigh_lookup, -}; - -static unsigned int ip6_blackhole_mtu(const struct dst_entry *dst) -{ - unsigned int mtu = dst_metric_raw(dst, RTAX_MTU); - - return mtu ? : dst->dev->mtu; -} - -static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk, - struct sk_buff *skb, u32 mtu) -{ -} - -static void ip6_rt_blackhole_redirect(struct dst_entry *dst, struct sock *sk, - struct sk_buff *skb) -{ -} - -static struct dst_ops ip6_dst_blackhole_ops = { - .family = AF_INET6, - .destroy = ip6_dst_destroy, - .check = ip6_dst_check, - .mtu = ip6_blackhole_mtu, - .default_advmss = ip6_default_advmss, - .update_pmtu = ip6_rt_blackhole_update_pmtu, - .redirect = ip6_rt_blackhole_redirect, - .cow_metrics = dst_cow_metrics_generic, - .neigh_lookup = ip6_neigh_lookup, -}; - -static const u32 ip6_template_metrics[RTAX_MAX] = { - [RTAX_HOPLIMIT - 1] = 0, -}; - -static const struct rt6_info ip6_null_entry_template = { - .dst = { - .__refcnt = ATOMIC_INIT(1), - .__use = 1, - .obsolete = DST_OBSOLETE_FORCE_CHK, - .error = -ENETUNREACH, - .input = ip6_pkt_discard, - .output = ip6_pkt_discard_out, - }, - .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), - .rt6i_protocol = RTPROT_KERNEL, - .rt6i_metric = ~(u32) 0, - .rt6i_ref = ATOMIC_INIT(1), -}; - -#ifdef CONFIG_IPV6_MULTIPLE_TABLES - -static const struct rt6_info ip6_prohibit_entry_template = { - .dst = { - .__refcnt = ATOMIC_INIT(1), - .__use = 1, - .obsolete = DST_OBSOLETE_FORCE_CHK, - .error = -EACCES, - .input = ip6_pkt_prohibit, - .output = ip6_pkt_prohibit_out, - }, - .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), - .rt6i_protocol = RTPROT_KERNEL, - .rt6i_metric = ~(u32) 0, - .rt6i_ref = ATOMIC_INIT(1), -}; - -static const struct rt6_info ip6_blk_hole_entry_template = { - .dst = { - .__refcnt = ATOMIC_INIT(1), - .__use = 1, - .obsolete = DST_OBSOLETE_FORCE_CHK, - .error = -EINVAL, - .input = dst_discard, - .output = dst_discard_out, - }, - .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), - .rt6i_protocol = RTPROT_KERNEL, - .rt6i_metric = ~(u32) 0, - .rt6i_ref = ATOMIC_INIT(1), -}; - -#endif - -static void rt6_info_init(struct rt6_info *rt) -{ - struct dst_entry *dst = &rt->dst; - - memset(dst + 1, 0, sizeof(*rt) - sizeof(*dst)); - INIT_LIST_HEAD(&rt->rt6i_siblings); - INIT_LIST_HEAD(&rt->rt6i_uncached); -} - -/* allocate dst with ip6_dst_ops */ -static struct rt6_info *__ip6_dst_alloc(struct net *net, - struct net_device *dev, - int flags) -{ - struct rt6_info *rt = dst_alloc(&net->ipv6.ip6_dst_ops, dev, - 0, DST_OBSOLETE_FORCE_CHK, flags); - - if (rt) - rt6_info_init(rt); - - return rt; -} - -struct rt6_info *ip6_dst_alloc(struct net *net, - struct net_device *dev, - int flags) -{ - struct rt6_info *rt = __ip6_dst_alloc(net, dev, flags); - - if (rt) { - rt->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_ATOMIC); - if (rt->rt6i_pcpu) { - int cpu; - - for_each_possible_cpu(cpu) { - struct rt6_info **p; - - p = per_cpu_ptr(rt->rt6i_pcpu, cpu); - /* no one shares rt */ - *p = NULL; - } - } else { - dst_destroy((struct dst_entry *)rt); - return NULL; - } - } - - return rt; -} -EXPORT_SYMBOL(ip6_dst_alloc); - -static void ip6_dst_destroy(struct dst_entry *dst) -{ - struct rt6_info *rt = (struct rt6_info *)dst; - struct dst_entry *from = dst->from; - struct inet6_dev *idev; - - dst_destroy_metrics_generic(dst); - free_percpu(rt->rt6i_pcpu); - rt6_uncached_list_del(rt); - - idev = rt->rt6i_idev; - if (idev) { - rt->rt6i_idev = NULL; - in6_dev_put(idev); - } - - dst->from = NULL; - dst_release(from); -} - -static void ip6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, - int how) -{ - struct rt6_info *rt = (struct rt6_info *)dst; - struct inet6_dev *idev = rt->rt6i_idev; - struct net_device *loopback_dev = - dev_net(dev)->loopback_dev; - - if (dev != loopback_dev) { - if (idev && idev->dev == dev) { - struct inet6_dev *loopback_idev = - in6_dev_get(loopback_dev); - if (loopback_idev) { - rt->rt6i_idev = loopback_idev; - in6_dev_put(idev); - } - } - } -} - -static bool __rt6_check_expired(const struct rt6_info *rt) -{ - if (rt->rt6i_flags & RTF_EXPIRES) - return time_after(jiffies, rt->dst.expires); - else - return false; -} - -static bool rt6_check_expired(const struct rt6_info *rt) -{ - if (rt->rt6i_flags & RTF_EXPIRES) { - if (time_after(jiffies, rt->dst.expires)) - return true; - } else if (rt->dst.from) { - return rt6_check_expired((struct rt6_info *) rt->dst.from); - } - return false; -} - -/* Multipath route selection: - * Hash based function using packet header and flowlabel. - * Adapted from fib_info_hashfn() - */ -static int rt6_info_hash_nhsfn(unsigned int candidate_count, - const struct flowi6 *fl6) -{ - return get_hash_from_flowi6(fl6) % candidate_count; -} - -static struct rt6_info *rt6_multipath_select(struct rt6_info *match, - struct flowi6 *fl6, int oif, - int strict) -{ - struct rt6_info *sibling, *next_sibling; - int route_choosen; - - route_choosen = rt6_info_hash_nhsfn(match->rt6i_nsiblings + 1, fl6); - /* Don't change the route, if route_choosen == 0 - * (siblings does not include ourself) - */ - if (route_choosen) - list_for_each_entry_safe(sibling, next_sibling, - &match->rt6i_siblings, rt6i_siblings) { - route_choosen--; - if (route_choosen == 0) { - if (rt6_score_route(sibling, oif, strict) < 0) - break; - match = sibling; - break; - } - } - return match; -} - -/* - * Route lookup. Any table->tb6_lock is implied. - */ - -static inline struct rt6_info *rt6_device_match(struct net *net, - struct rt6_info *rt, - const struct in6_addr *saddr, - int oif, - int flags) -{ - struct rt6_info *local = NULL; - struct rt6_info *sprt; - - if (!oif && ipv6_addr_any(saddr)) - goto out; - - for (sprt = rt; sprt; sprt = sprt->dst.rt6_next) { - struct net_device *dev = sprt->dst.dev; - - if (oif) { - if (dev->ifindex == oif) - return sprt; - if (dev->flags & IFF_LOOPBACK) { - if (!sprt->rt6i_idev || - sprt->rt6i_idev->dev->ifindex != oif) { - if (flags & RT6_LOOKUP_F_IFACE) - continue; - if (local && - local->rt6i_idev->dev->ifindex == oif) - continue; - } - local = sprt; - } - } else { - if (ipv6_chk_addr(net, saddr, dev, - flags & RT6_LOOKUP_F_IFACE)) - return sprt; - } - } - - if (oif) { - if (local) - return local; - - if (flags & RT6_LOOKUP_F_IFACE) - return net->ipv6.ip6_null_entry; - } -out: - return rt; -} - -#ifdef CONFIG_IPV6_ROUTER_PREF -struct __rt6_probe_work { - struct work_struct work; - struct in6_addr target; - struct net_device *dev; -}; - -static void rt6_probe_deferred(struct work_struct *w) -{ - struct in6_addr mcaddr; - struct __rt6_probe_work *work = - container_of(w, struct __rt6_probe_work, work); - - addrconf_addr_solict_mult(&work->target, &mcaddr); - ndisc_send_ns(work->dev, &work->target, &mcaddr, NULL); - dev_put(work->dev); - kfree(work); -} - -static void rt6_probe(struct rt6_info *rt) -{ - struct __rt6_probe_work *work; - struct neighbour *neigh; - /* - * Okay, this does not seem to be appropriate - * for now, however, we need to check if it - * is really so; aka Router Reachability Probing. - * - * Router Reachability Probe MUST be rate-limited - * to no more than one per minute. - */ - if (!rt || !(rt->rt6i_flags & RTF_GATEWAY)) - return; - rcu_read_lock_bh(); - neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway); - if (neigh) { - if (neigh->nud_state & NUD_VALID) - goto out; - - work = NULL; - write_lock(&neigh->lock); - if (!(neigh->nud_state & NUD_VALID) && - time_after(jiffies, - neigh->updated + - rt->rt6i_idev->cnf.rtr_probe_interval)) { - work = kmalloc(sizeof(*work), GFP_ATOMIC); - if (work) - __neigh_set_probe_once(neigh); - } - write_unlock(&neigh->lock); - } else { - work = kmalloc(sizeof(*work), GFP_ATOMIC); - } - - if (work) { - INIT_WORK(&work->work, rt6_probe_deferred); - work->target = rt->rt6i_gateway; - dev_hold(rt->dst.dev); - work->dev = rt->dst.dev; - schedule_work(&work->work); - } - -out: - rcu_read_unlock_bh(); -} -#else -static inline void rt6_probe(struct rt6_info *rt) -{ -} -#endif - -/* - * Default Router Selection (RFC 2461 6.3.6) - */ -static inline int rt6_check_dev(struct rt6_info *rt, int oif) -{ - struct net_device *dev = rt->dst.dev; - if (!oif || dev->ifindex == oif) - return 2; - if ((dev->flags & IFF_LOOPBACK) && - rt->rt6i_idev && rt->rt6i_idev->dev->ifindex == oif) - return 1; - return 0; -} - -static inline enum rt6_nud_state rt6_check_neigh(struct rt6_info *rt) -{ - struct neighbour *neigh; - enum rt6_nud_state ret = RT6_NUD_FAIL_HARD; - - if (rt->rt6i_flags & RTF_NONEXTHOP || - !(rt->rt6i_flags & RTF_GATEWAY)) - return RT6_NUD_SUCCEED; - - rcu_read_lock_bh(); - neigh = __ipv6_neigh_lookup_noref(rt->dst.dev, &rt->rt6i_gateway); - if (neigh) { - read_lock(&neigh->lock); - if (neigh->nud_state & NUD_VALID) - ret = RT6_NUD_SUCCEED; -#ifdef CONFIG_IPV6_ROUTER_PREF - else if (!(neigh->nud_state & NUD_FAILED)) - ret = RT6_NUD_SUCCEED; - else - ret = RT6_NUD_FAIL_PROBE; -#endif - read_unlock(&neigh->lock); - } else { - ret = IS_ENABLED(CONFIG_IPV6_ROUTER_PREF) ? - RT6_NUD_SUCCEED : RT6_NUD_FAIL_DO_RR; - } - rcu_read_unlock_bh(); - - return ret; -} - -static int rt6_score_route(struct rt6_info *rt, int oif, - int strict) -{ - int m; - - m = rt6_check_dev(rt, oif); - if (!m && (strict & RT6_LOOKUP_F_IFACE)) - return RT6_NUD_FAIL_HARD; -#ifdef CONFIG_IPV6_ROUTER_PREF - m |= IPV6_DECODE_PREF(IPV6_EXTRACT_PREF(rt->rt6i_flags)) << 2; -#endif - if (strict & RT6_LOOKUP_F_REACHABLE) { - int n = rt6_check_neigh(rt); - if (n < 0) - return n; - } - return m; -} - -static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict, - int *mpri, struct rt6_info *match, - bool *do_rr) -{ - int m; - bool match_do_rr = false; - struct inet6_dev *idev = rt->rt6i_idev; - struct net_device *dev = rt->dst.dev; - - if (dev && !netif_carrier_ok(dev) && - idev->cnf.ignore_routes_with_linkdown && - !(strict & RT6_LOOKUP_F_IGNORE_LINKSTATE)) - goto out; - - if (rt6_check_expired(rt)) - goto out; - - m = rt6_score_route(rt, oif, strict); - if (m == RT6_NUD_FAIL_DO_RR) { - match_do_rr = true; - m = 0; /* lowest valid score */ - } else if (m == RT6_NUD_FAIL_HARD) { - goto out; - } - - if (strict & RT6_LOOKUP_F_REACHABLE) - rt6_probe(rt); - - /* note that m can be RT6_NUD_FAIL_PROBE at this point */ - if (m > *mpri) { - *do_rr = match_do_rr; - *mpri = m; - match = rt; - } -out: - return match; -} - -static struct rt6_info *find_rr_leaf(struct fib6_node *fn, - struct rt6_info *rr_head, - u32 metric, int oif, int strict, - bool *do_rr) -{ - struct rt6_info *rt, *match, *cont; - int mpri = -1; - - match = NULL; - cont = NULL; - for (rt = rr_head; rt; rt = rt->dst.rt6_next) { - if (rt->rt6i_metric != metric) { - cont = rt; - break; - } - - match = find_match(rt, oif, strict, &mpri, match, do_rr); - } - - for (rt = fn->leaf; rt && rt != rr_head; rt = rt->dst.rt6_next) { - if (rt->rt6i_metric != metric) { - cont = rt; - break; - } - - match = find_match(rt, oif, strict, &mpri, match, do_rr); - } - - if (match || !cont) - return match; - - for (rt = cont; rt; rt = rt->dst.rt6_next) - match = find_match(rt, oif, strict, &mpri, match, do_rr); - - return match; -} - -static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict) -{ - struct rt6_info *match, *rt0; - struct net *net; - bool do_rr = false; - - rt0 = fn->rr_ptr; - if (!rt0) - fn->rr_ptr = rt0 = fn->leaf; - - match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict, - &do_rr); - - if (do_rr) { - struct rt6_info *next = rt0->dst.rt6_next; - - /* no entries matched; do round-robin */ - if (!next || next->rt6i_metric != rt0->rt6i_metric) - next = fn->leaf; - - if (next != rt0) - fn->rr_ptr = next; - } - - net = dev_net(rt0->dst.dev); - return match ? match : net->ipv6.ip6_null_entry; -} - -static bool rt6_is_gw_or_nonexthop(const struct rt6_info *rt) -{ - return (rt->rt6i_flags & (RTF_NONEXTHOP | RTF_GATEWAY)); -} - -#ifdef CONFIG_IPV6_ROUTE_INFO -int rt6_route_rcv(struct net_device *dev, u8 *opt, int len, - const struct in6_addr *gwaddr) -{ - struct net *net = dev_net(dev); - struct route_info *rinfo = (struct route_info *) opt; - struct in6_addr prefix_buf, *prefix; - unsigned int pref; - unsigned long lifetime; - struct rt6_info *rt; - - if (len < sizeof(struct route_info)) { - return -EINVAL; - } - - /* Sanity check for prefix_len and length */ - if (rinfo->length > 3) { - return -EINVAL; - } else if (rinfo->prefix_len > 128) { - return -EINVAL; - } else if (rinfo->prefix_len > 64) { - if (rinfo->length < 2) { - return -EINVAL; - } - } else if (rinfo->prefix_len > 0) { - if (rinfo->length < 1) { - return -EINVAL; - } - } - - pref = rinfo->route_pref; - if (pref == ICMPV6_ROUTER_PREF_INVALID) - return -EINVAL; - - lifetime = addrconf_timeout_fixup(ntohl(rinfo->lifetime), HZ); - - if (rinfo->length == 3) - prefix = (struct in6_addr *)rinfo->prefix; - else { - /* this function is safe */ - ipv6_addr_prefix(&prefix_buf, - (struct in6_addr *)rinfo->prefix, - rinfo->prefix_len); - prefix = &prefix_buf; - } - - if (rinfo->prefix_len == 0) - rt = rt6_get_dflt_router(gwaddr, dev); - else - rt = rt6_get_route_info(net, prefix, rinfo->prefix_len, - gwaddr, dev); - - if (rt && !lifetime) { - ip6_del_rt(rt); - rt = NULL; - } - - if (!rt && lifetime) - rt = rt6_add_route_info(net, prefix, rinfo->prefix_len, gwaddr, - dev, pref); - else if (rt) - rt->rt6i_flags = RTF_ROUTEINFO | - (rt->rt6i_flags & ~RTF_PREF_MASK) | RTF_PREF(pref); - - if (rt) { - if (!addrconf_finite_timeout(lifetime)) - rt6_clean_expires(rt); - else - rt6_set_expires(rt, jiffies + HZ * lifetime); - - ip6_rt_put(rt); - } - return 0; -} -#endif - -static struct fib6_node* fib6_backtrack(struct fib6_node *fn, - struct in6_addr *saddr) -{ - struct fib6_node *pn; - while (1) { - if (fn->fn_flags & RTN_TL_ROOT) - return NULL; - pn = fn->parent; - if (FIB6_SUBTREE(pn) && FIB6_SUBTREE(pn) != fn) - fn = fib6_lookup(FIB6_SUBTREE(pn), NULL, saddr); - else - fn = pn; - if (fn->fn_flags & RTN_RTINFO) - return fn; - } -} - -static struct rt6_info *ip6_pol_route_lookup(struct net *net, - struct fib6_table *table, - struct flowi6 *fl6, int flags) -{ - struct fib6_node *fn; - struct rt6_info *rt; - - read_lock_bh(&table->tb6_lock); - fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); -restart: - rt = fn->leaf; - rt = rt6_device_match(net, rt, &fl6->saddr, fl6->flowi6_oif, flags); - if (rt->rt6i_nsiblings && fl6->flowi6_oif == 0) - rt = rt6_multipath_select(rt, fl6, fl6->flowi6_oif, flags); - if (rt == net->ipv6.ip6_null_entry) { - fn = fib6_backtrack(fn, &fl6->saddr); - if (fn) - goto restart; - } - dst_use(&rt->dst, jiffies); - read_unlock_bh(&table->tb6_lock); - - trace_fib6_table_lookup(net, rt, table->tb6_id, fl6); - - return rt; - -} - -struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6, - int flags) -{ - return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_lookup); -} -EXPORT_SYMBOL_GPL(ip6_route_lookup); - -struct rt6_info *rt6_lookup(struct net *net, const struct in6_addr *daddr, - const struct in6_addr *saddr, int oif, int strict) -{ - struct flowi6 fl6 = { - .flowi6_oif = oif, - .daddr = *daddr, - }; - struct dst_entry *dst; - int flags = strict ? RT6_LOOKUP_F_IFACE : 0; - - if (saddr) { - memcpy(&fl6.saddr, saddr, sizeof(*saddr)); - flags |= RT6_LOOKUP_F_HAS_SADDR; - } - - dst = fib6_rule_lookup(net, &fl6, flags, ip6_pol_route_lookup); - if (dst->error == 0) - return (struct rt6_info *) dst; - - dst_release(dst); - - return NULL; -} -EXPORT_SYMBOL(rt6_lookup); - -/* ip6_ins_rt is called with FREE table->tb6_lock. - It takes new route entry, the addition fails by any reason the - route is freed. In any case, if caller does not hold it, it may - be destroyed. - */ - -static int __ip6_ins_rt(struct rt6_info *rt, struct nl_info *info, - struct mx6_config *mxc) -{ - int err; - struct fib6_table *table; - - table = rt->rt6i_table; - write_lock_bh(&table->tb6_lock); - err = fib6_add(&table->tb6_root, rt, info, mxc); - write_unlock_bh(&table->tb6_lock); - - return err; -} - -int ip6_ins_rt(struct rt6_info *rt) -{ - struct nl_info info = { .nl_net = dev_net(rt->dst.dev), }; - struct mx6_config mxc = { .mx = NULL, }; - - return __ip6_ins_rt(rt, &info, &mxc); -} - -static struct rt6_info *ip6_rt_cache_alloc(struct rt6_info *ort, - const struct in6_addr *daddr, - const struct in6_addr *saddr) -{ - struct rt6_info *rt; - - /* - * Clone the route. - */ - - if (ort->rt6i_flags & (RTF_CACHE | RTF_PCPU)) - ort = (struct rt6_info *)ort->dst.from; - - rt = __ip6_dst_alloc(dev_net(ort->dst.dev), ort->dst.dev, 0); - - if (!rt) - return NULL; - - ip6_rt_copy_init(rt, ort); - rt->rt6i_flags |= RTF_CACHE; - rt->rt6i_metric = 0; - rt->dst.flags |= DST_HOST; - rt->rt6i_dst.addr = *daddr; - rt->rt6i_dst.plen = 128; - - if (!rt6_is_gw_or_nonexthop(ort)) { - if (ort->rt6i_dst.plen != 128 && - ipv6_addr_equal(&ort->rt6i_dst.addr, daddr)) - rt->rt6i_flags |= RTF_ANYCAST; -#ifdef CONFIG_IPV6_SUBTREES - if (rt->rt6i_src.plen && saddr) { - rt->rt6i_src.addr = *saddr; - rt->rt6i_src.plen = 128; - } -#endif - } - - return rt; -} - -static struct rt6_info *ip6_rt_pcpu_alloc(struct rt6_info *rt) -{ - struct rt6_info *pcpu_rt; - - pcpu_rt = __ip6_dst_alloc(dev_net(rt->dst.dev), - rt->dst.dev, rt->dst.flags); - - if (!pcpu_rt) - return NULL; - ip6_rt_copy_init(pcpu_rt, rt); - pcpu_rt->rt6i_protocol = rt->rt6i_protocol; - pcpu_rt->rt6i_flags |= RTF_PCPU; - return pcpu_rt; -} - -/* It should be called with read_lock_bh(&tb6_lock) acquired */ -static struct rt6_info *rt6_get_pcpu_route(struct rt6_info *rt) -{ - struct rt6_info *pcpu_rt, **p; - - p = this_cpu_ptr(rt->rt6i_pcpu); - pcpu_rt = *p; - - if (pcpu_rt) { - dst_hold(&pcpu_rt->dst); - rt6_dst_from_metrics_check(pcpu_rt); - } - return pcpu_rt; -} - -static struct rt6_info *rt6_make_pcpu_route(struct rt6_info *rt) -{ - struct fib6_table *table = rt->rt6i_table; - struct rt6_info *pcpu_rt, *prev, **p; - - pcpu_rt = ip6_rt_pcpu_alloc(rt); - if (!pcpu_rt) { - struct net *net = dev_net(rt->dst.dev); - - dst_hold(&net->ipv6.ip6_null_entry->dst); - return net->ipv6.ip6_null_entry; - } - - read_lock_bh(&table->tb6_lock); - if (rt->rt6i_pcpu) { - p = this_cpu_ptr(rt->rt6i_pcpu); - prev = cmpxchg(p, NULL, pcpu_rt); - if (prev) { - /* If someone did it before us, return prev instead */ - dst_destroy(&pcpu_rt->dst); - pcpu_rt = prev; - } - } else { - /* rt has been removed from the fib6 tree - * before we have a chance to acquire the read_lock. - * In this case, don't brother to create a pcpu rt - * since rt is going away anyway. The next - * dst_check() will trigger a re-lookup. - */ - dst_destroy(&pcpu_rt->dst); - pcpu_rt = rt; - } - dst_hold(&pcpu_rt->dst); - rt6_dst_from_metrics_check(pcpu_rt); - read_unlock_bh(&table->tb6_lock); - return pcpu_rt; -} - -struct rt6_info *ip6_pol_route(struct net *net, struct fib6_table *table, - int oif, struct flowi6 *fl6, int flags) -{ - struct fib6_node *fn, *saved_fn; - struct rt6_info *rt; - int strict = 0; - - strict |= flags & RT6_LOOKUP_F_IFACE; - strict |= flags & RT6_LOOKUP_F_IGNORE_LINKSTATE; - if (net->ipv6.devconf_all->forwarding == 0) - strict |= RT6_LOOKUP_F_REACHABLE; - - read_lock_bh(&table->tb6_lock); - - fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); - saved_fn = fn; - - if (fl6->flowi6_flags & FLOWI_FLAG_SKIP_NH_OIF) - oif = 0; - -redo_rt6_select: - rt = rt6_select(fn, oif, strict); - if (rt->rt6i_nsiblings) - rt = rt6_multipath_select(rt, fl6, oif, strict); - if (rt == net->ipv6.ip6_null_entry) { - fn = fib6_backtrack(fn, &fl6->saddr); - if (fn) - goto redo_rt6_select; - else if (strict & RT6_LOOKUP_F_REACHABLE) { - /* also consider unreachable route */ - strict &= ~RT6_LOOKUP_F_REACHABLE; - fn = saved_fn; - goto redo_rt6_select; - } - } - - - if (rt == net->ipv6.ip6_null_entry || (rt->rt6i_flags & RTF_CACHE)) { - dst_use(&rt->dst, jiffies); - read_unlock_bh(&table->tb6_lock); - - rt6_dst_from_metrics_check(rt); - - trace_fib6_table_lookup(net, rt, table->tb6_id, fl6); - return rt; - } else if (unlikely((fl6->flowi6_flags & FLOWI_FLAG_KNOWN_NH) && - !(rt->rt6i_flags & RTF_GATEWAY))) { - /* Create a RTF_CACHE clone which will not be - * owned by the fib6 tree. It is for the special case where - * the daddr in the skb during the neighbor look-up is different - * from the fl6->daddr used to look-up route here. - */ - - struct rt6_info *uncached_rt; - - dst_use(&rt->dst, jiffies); - read_unlock_bh(&table->tb6_lock); - - uncached_rt = ip6_rt_cache_alloc(rt, &fl6->daddr, NULL); - dst_release(&rt->dst); - - if (uncached_rt) - rt6_uncached_list_add(uncached_rt); - else - uncached_rt = net->ipv6.ip6_null_entry; - - dst_hold(&uncached_rt->dst); - - trace_fib6_table_lookup(net, uncached_rt, table->tb6_id, fl6); - return uncached_rt; - - } else { - /* Get a percpu copy */ - - struct rt6_info *pcpu_rt; - - rt->dst.lastuse = jiffies; - rt->dst.__use++; - pcpu_rt = rt6_get_pcpu_route(rt); - - if (pcpu_rt) { - read_unlock_bh(&table->tb6_lock); - } else { - /* We have to do the read_unlock first - * because rt6_make_pcpu_route() may trigger - * ip6_dst_gc() which will take the write_lock. - */ - dst_hold(&rt->dst); - read_unlock_bh(&table->tb6_lock); - pcpu_rt = rt6_make_pcpu_route(rt); - dst_release(&rt->dst); - } - - trace_fib6_table_lookup(net, pcpu_rt, table->tb6_id, fl6); - return pcpu_rt; - - } -} -EXPORT_SYMBOL_GPL(ip6_pol_route); - -static struct rt6_info *ip6_pol_route_input(struct net *net, struct fib6_table *table, - struct flowi6 *fl6, int flags) -{ - return ip6_pol_route(net, table, fl6->flowi6_iif, fl6, flags); -} - -struct dst_entry *ip6_route_input_lookup(struct net *net, - struct net_device *dev, - struct flowi6 *fl6, int flags) -{ - if (rt6_need_strict(&fl6->daddr) && dev->type != ARPHRD_PIMREG) - flags |= RT6_LOOKUP_F_IFACE; - - return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_input); -} -EXPORT_SYMBOL_GPL(ip6_route_input_lookup); - -void ip6_route_input(struct sk_buff *skb) -{ - const struct ipv6hdr *iph = ipv6_hdr(skb); - struct net *net = dev_net(skb->dev); - int flags = RT6_LOOKUP_F_HAS_SADDR; - struct ip_tunnel_info *tun_info; - struct flowi6 fl6 = { - .flowi6_iif = skb->dev->ifindex, - .daddr = iph->daddr, - .saddr = iph->saddr, - .flowlabel = ip6_flowinfo(iph), - .flowi6_mark = skb->mark, - .flowi6_proto = iph->nexthdr, - }; - - tun_info = skb_tunnel_info(skb); - if (tun_info && !(tun_info->mode & IP_TUNNEL_INFO_TX)) - fl6.flowi6_tun_key.tun_id = tun_info->key.tun_id; - skb_dst_drop(skb); - skb_dst_set(skb, ip6_route_input_lookup(net, skb->dev, &fl6, flags)); -} - -static struct rt6_info *ip6_pol_route_output(struct net *net, struct fib6_table *table, - struct flowi6 *fl6, int flags) -{ - return ip6_pol_route(net, table, fl6->flowi6_oif, fl6, flags); -} - -struct dst_entry *ip6_route_output_flags(struct net *net, const struct sock *sk, - struct flowi6 *fl6, int flags) -{ - bool any_src; - - if (rt6_need_strict(&fl6->daddr)) { - struct dst_entry *dst; - - dst = l3mdev_link_scope_lookup(net, fl6); - if (dst) - return dst; - } - - fl6->flowi6_iif = LOOPBACK_IFINDEX; - - any_src = ipv6_addr_any(&fl6->saddr); - if ((sk && sk->sk_bound_dev_if) || rt6_need_strict(&fl6->daddr) || - (fl6->flowi6_oif && any_src)) - flags |= RT6_LOOKUP_F_IFACE; - - if (!any_src) - flags |= RT6_LOOKUP_F_HAS_SADDR; - else if (sk) - flags |= rt6_srcprefs2flags(inet6_sk(sk)->srcprefs); - - return fib6_rule_lookup(net, fl6, flags, ip6_pol_route_output); -} -EXPORT_SYMBOL_GPL(ip6_route_output_flags); - -struct dst_entry *ip6_blackhole_route(struct net *net, struct dst_entry *dst_orig) -{ - struct rt6_info *rt, *ort = (struct rt6_info *) dst_orig; - struct dst_entry *new = NULL; - - rt = dst_alloc(&ip6_dst_blackhole_ops, ort->dst.dev, 1, DST_OBSOLETE_NONE, 0); - if (rt) { - rt6_info_init(rt); - - new = &rt->dst; - new->__use = 1; - new->input = dst_discard; - new->output = dst_discard_out; - - dst_copy_metrics(new, &ort->dst); - rt->rt6i_idev = ort->rt6i_idev; - if (rt->rt6i_idev) - in6_dev_hold(rt->rt6i_idev); - - rt->rt6i_gateway = ort->rt6i_gateway; - rt->rt6i_flags = ort->rt6i_flags & ~RTF_PCPU; - rt->rt6i_metric = 0; - - memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key)); -#ifdef CONFIG_IPV6_SUBTREES - memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); -#endif - - dst_free(new); - } - - dst_release(dst_orig); - return new ? new : ERR_PTR(-ENOMEM); -} - -/* - * Destination cache support functions - */ - -static void rt6_dst_from_metrics_check(struct rt6_info *rt) -{ - if (rt->dst.from && - dst_metrics_ptr(&rt->dst) != dst_metrics_ptr(rt->dst.from)) - dst_init_metrics(&rt->dst, dst_metrics_ptr(rt->dst.from), true); -} - -static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie) -{ - if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie)) - return NULL; - - if (rt6_check_expired(rt)) - return NULL; - - return &rt->dst; -} - -static struct dst_entry *rt6_dst_from_check(struct rt6_info *rt, u32 cookie) -{ - if (!__rt6_check_expired(rt) && - rt->dst.obsolete == DST_OBSOLETE_FORCE_CHK && - rt6_check((struct rt6_info *)(rt->dst.from), cookie)) - return &rt->dst; - else - return NULL; -} - -static struct dst_entry *ip6_dst_check(struct dst_entry *dst, u32 cookie) -{ - struct rt6_info *rt; - - rt = (struct rt6_info *) dst; - - /* All IPV6 dsts are created with ->obsolete set to the value - * DST_OBSOLETE_FORCE_CHK which forces validation calls down - * into this function always. - */ - - rt6_dst_from_metrics_check(rt); - - if (rt->rt6i_flags & RTF_PCPU || - (unlikely(dst->flags & DST_NOCACHE) && rt->dst.from)) - return rt6_dst_from_check(rt, cookie); - else - return rt6_check(rt, cookie); -} - -static struct dst_entry *ip6_negative_advice(struct dst_entry *dst) -{ - struct rt6_info *rt = (struct rt6_info *) dst; - - if (rt) { - if (rt->rt6i_flags & RTF_CACHE) { - if (rt6_check_expired(rt)) { - ip6_del_rt(rt); - dst = NULL; - } - } else { - dst_release(dst); - dst = NULL; - } - } - return dst; -} - -static void ip6_link_failure(struct sk_buff *skb) -{ - struct rt6_info *rt; - - icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0); - - rt = (struct rt6_info *) skb_dst(skb); - if (rt) { - if (rt->rt6i_flags & RTF_CACHE) { - dst_hold(&rt->dst); - ip6_del_rt(rt); - } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) { - rt->rt6i_node->fn_sernum = -1; - } - } -} - -static void rt6_do_update_pmtu(struct rt6_info *rt, u32 mtu) -{ - struct net *net = dev_net(rt->dst.dev); - - rt->rt6i_flags |= RTF_MODIFIED; - rt->rt6i_pmtu = mtu; - rt6_update_expires(rt, net->ipv6.sysctl.ip6_rt_mtu_expires); -} - -static bool rt6_cache_allowed_for_pmtu(const struct rt6_info *rt) -{ - return !(rt->rt6i_flags & RTF_CACHE) && - (rt->rt6i_flags & RTF_PCPU || rt->rt6i_node); -} - -static void __ip6_rt_update_pmtu(struct dst_entry *dst, const struct sock *sk, - const struct ipv6hdr *iph, u32 mtu) -{ - struct rt6_info *rt6 = (struct rt6_info *)dst; - - if (rt6->rt6i_flags & RTF_LOCAL) - return; - - if (dst_metric_locked(dst, RTAX_MTU)) - return; - - dst_confirm(dst); - mtu = max_t(u32, mtu, IPV6_MIN_MTU); - if (mtu >= dst_mtu(dst)) - return; - - if (!rt6_cache_allowed_for_pmtu(rt6)) { - rt6_do_update_pmtu(rt6, mtu); - } else { - const struct in6_addr *daddr, *saddr; - struct rt6_info *nrt6; - - if (iph) { - daddr = &iph->daddr; - saddr = &iph->saddr; - } else if (sk) { - daddr = &sk->sk_v6_daddr; - saddr = &inet6_sk(sk)->saddr; - } else { - return; - } - nrt6 = ip6_rt_cache_alloc(rt6, daddr, saddr); - if (nrt6) { - rt6_do_update_pmtu(nrt6, mtu); - - /* ip6_ins_rt(nrt6) will bump the - * rt6->rt6i_node->fn_sernum - * which will fail the next rt6_check() and - * invalidate the sk->sk_dst_cache. - */ - ip6_ins_rt(nrt6); - } - } -} - -static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk, - struct sk_buff *skb, u32 mtu) -{ - __ip6_rt_update_pmtu(dst, sk, skb ? ipv6_hdr(skb) : NULL, mtu); -} - -void ip6_update_pmtu(struct sk_buff *skb, struct net *net, __be32 mtu, - int oif, u32 mark) -{ - const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data; - struct dst_entry *dst; - struct flowi6 fl6; - - memset(&fl6, 0, sizeof(fl6)); - fl6.flowi6_oif = oif; - fl6.flowi6_mark = mark ? mark : IP6_REPLY_MARK(net, skb->mark); - fl6.daddr = iph->daddr; - fl6.saddr = iph->saddr; - fl6.flowlabel = ip6_flowinfo(iph); - - dst = ip6_route_output(net, NULL, &fl6); - if (!dst->error) - __ip6_rt_update_pmtu(dst, NULL, iph, ntohl(mtu)); - dst_release(dst); -} -EXPORT_SYMBOL_GPL(ip6_update_pmtu); - -void ip6_sk_update_pmtu(struct sk_buff *skb, struct sock *sk, __be32 mtu) -{ - struct dst_entry *dst; - - ip6_update_pmtu(skb, sock_net(sk), mtu, - sk->sk_bound_dev_if, sk->sk_mark); - - dst = __sk_dst_get(sk); - if (!dst || !dst->obsolete || - dst->ops->check(dst, inet6_sk(sk)->dst_cookie)) - return; - - bh_lock_sock(sk); - if (!sock_owned_by_user(sk) && !ipv6_addr_v4mapped(&sk->sk_v6_daddr)) - ip6_datagram_dst_update(sk, false); - bh_unlock_sock(sk); -} -EXPORT_SYMBOL_GPL(ip6_sk_update_pmtu); - -/* Handle redirects */ -struct ip6rd_flowi { - struct flowi6 fl6; - struct in6_addr gateway; -}; - -static struct rt6_info *__ip6_route_redirect(struct net *net, - struct fib6_table *table, - struct flowi6 *fl6, - int flags) -{ - struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl6; - struct rt6_info *rt; - struct fib6_node *fn; - - /* Get the "current" route for this destination and - * check if the redirect has come from approriate router. - * - * RFC 4861 specifies that redirects should only be - * accepted if they come from the nexthop to the target. - * Due to the way the routes are chosen, this notion - * is a bit fuzzy and one might need to check all possible - * routes. - */ - - read_lock_bh(&table->tb6_lock); - fn = fib6_lookup(&table->tb6_root, &fl6->daddr, &fl6->saddr); -restart: - for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) { - if (rt6_check_expired(rt)) - continue; - if (rt->dst.error) - break; - if (!(rt->rt6i_flags & RTF_GATEWAY)) - continue; - if (fl6->flowi6_oif != rt->dst.dev->ifindex) - continue; - if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway)) - continue; - break; - } - - if (!rt) - rt = net->ipv6.ip6_null_entry; - else if (rt->dst.error) { - rt = net->ipv6.ip6_null_entry; - goto out; - } - - if (rt == net->ipv6.ip6_null_entry) { - fn = fib6_backtrack(fn, &fl6->saddr); - if (fn) - goto restart; - } - -out: - dst_hold(&rt->dst); - - read_unlock_bh(&table->tb6_lock); - - trace_fib6_table_lookup(net, rt, table->tb6_id, fl6); - return rt; -}; - -static struct dst_entry *ip6_route_redirect(struct net *net, - const struct flowi6 *fl6, - const struct in6_addr *gateway) -{ - int flags = RT6_LOOKUP_F_HAS_SADDR; - struct ip6rd_flowi rdfl; - - rdfl.fl6 = *fl6; - rdfl.gateway = *gateway; - - return fib6_rule_lookup(net, &rdfl.fl6, - flags, __ip6_route_redirect); -} - -void ip6_redirect(struct sk_buff *skb, struct net *net, int oif, u32 mark) -{ - const struct ipv6hdr *iph = (struct ipv6hdr *) skb->data; - struct dst_entry *dst; - struct flowi6 fl6; - - memset(&fl6, 0, sizeof(fl6)); - fl6.flowi6_iif = LOOPBACK_IFINDEX; - fl6.flowi6_oif = oif; - fl6.flowi6_mark = mark; - fl6.daddr = iph->daddr; - fl6.saddr = iph->saddr; - fl6.flowlabel = ip6_flowinfo(iph); - - dst = ip6_route_redirect(net, &fl6, &ipv6_hdr(skb)->saddr); - rt6_do_redirect(dst, NULL, skb); - dst_release(dst); -} -EXPORT_SYMBOL_GPL(ip6_redirect); - -void ip6_redirect_no_header(struct sk_buff *skb, struct net *net, int oif, - u32 mark) -{ - const struct ipv6hdr *iph = ipv6_hdr(skb); - const struct rd_msg *msg = (struct rd_msg *)icmp6_hdr(skb); - struct dst_entry *dst; - struct flowi6 fl6; - - memset(&fl6, 0, sizeof(fl6)); - fl6.flowi6_iif = LOOPBACK_IFINDEX; - fl6.flowi6_oif = oif; - fl6.flowi6_mark = mark; - fl6.daddr = msg->dest; - fl6.saddr = iph->daddr; - - dst = ip6_route_redirect(net, &fl6, &iph->saddr); - rt6_do_redirect(dst, NULL, skb); - dst_release(dst); -} - -void ip6_sk_redirect(struct sk_buff *skb, struct sock *sk) -{ - ip6_redirect(skb, sock_net(sk), sk->sk_bound_dev_if, sk->sk_mark); -} -EXPORT_SYMBOL_GPL(ip6_sk_redirect); - -static unsigned int ip6_default_advmss(const struct dst_entry *dst) -{ - struct net_device *dev = dst->dev; - unsigned int mtu = dst_mtu(dst); - struct net *net = dev_net(dev); - - mtu -= sizeof(struct ipv6hdr) + sizeof(struct tcphdr); - - if (mtu < net->ipv6.sysctl.ip6_rt_min_advmss) - mtu = net->ipv6.sysctl.ip6_rt_min_advmss; - - /* - * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and - * corresponding MSS is IPV6_MAXPLEN - tcp_header_size. - * IPV6_MAXPLEN is also valid and means: "any MSS, - * rely only on pmtu discovery" - */ - if (mtu > IPV6_MAXPLEN - sizeof(struct tcphdr)) - mtu = IPV6_MAXPLEN; - return mtu; -} - -static unsigned int ip6_mtu(const struct dst_entry *dst) -{ - const struct rt6_info *rt = (const struct rt6_info *)dst; - unsigned int mtu = rt->rt6i_pmtu; - struct inet6_dev *idev; - - if (mtu) - goto out; - - mtu = dst_metric_raw(dst, RTAX_MTU); - if (mtu) - goto out; - - mtu = IPV6_MIN_MTU; - - rcu_read_lock(); - idev = __in6_dev_get(dst->dev); - if (idev) - mtu = idev->cnf.mtu6; - rcu_read_unlock(); - -out: - mtu = min_t(unsigned int, mtu, IP6_MAX_MTU); - - return mtu - lwtunnel_headroom(dst->lwtstate, mtu); -} - -static struct dst_entry *icmp6_dst_gc_list; -static DEFINE_SPINLOCK(icmp6_dst_lock); - -struct dst_entry *icmp6_dst_alloc(struct net_device *dev, - struct flowi6 *fl6) -{ - struct dst_entry *dst; - struct rt6_info *rt; - struct inet6_dev *idev = in6_dev_get(dev); - struct net *net = dev_net(dev); - - if (unlikely(!idev)) - return ERR_PTR(-ENODEV); - - rt = ip6_dst_alloc(net, dev, 0); - if (unlikely(!rt)) { - in6_dev_put(idev); - dst = ERR_PTR(-ENOMEM); - goto out; - } - - rt->dst.flags |= DST_HOST; - rt->dst.output = ip6_output; - atomic_set(&rt->dst.__refcnt, 1); - rt->rt6i_gateway = fl6->daddr; - rt->rt6i_dst.addr = fl6->daddr; - rt->rt6i_dst.plen = 128; - rt->rt6i_idev = idev; - dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 0); - - spin_lock_bh(&icmp6_dst_lock); - rt->dst.next = icmp6_dst_gc_list; - icmp6_dst_gc_list = &rt->dst; - spin_unlock_bh(&icmp6_dst_lock); - - fib6_force_start_gc(net); - - dst = xfrm_lookup(net, &rt->dst, flowi6_to_flowi(fl6), NULL, 0); - -out: - return dst; -} - -int icmp6_dst_gc(void) -{ - struct dst_entry *dst, **pprev; - int more = 0; - - spin_lock_bh(&icmp6_dst_lock); - pprev = &icmp6_dst_gc_list; - - while ((dst = *pprev) != NULL) { - if (!atomic_read(&dst->__refcnt)) { - *pprev = dst->next; - dst_free(dst); - } else { - pprev = &dst->next; - ++more; - } - } - - spin_unlock_bh(&icmp6_dst_lock); - - return more; -} - -static void icmp6_clean_all(int (*func)(struct rt6_info *rt, void *arg), - void *arg) -{ - struct dst_entry *dst, **pprev; - - spin_lock_bh(&icmp6_dst_lock); - pprev = &icmp6_dst_gc_list; - while ((dst = *pprev) != NULL) { - struct rt6_info *rt = (struct rt6_info *) dst; - if (func(rt, arg)) { - *pprev = dst->next; - dst_free(dst); - } else { - pprev = &dst->next; - } - } - spin_unlock_bh(&icmp6_dst_lock); -} - -static int ip6_dst_gc(struct dst_ops *ops) -{ - struct net *net = container_of(ops, struct net, ipv6.ip6_dst_ops); - int rt_min_interval = net->ipv6.sysctl.ip6_rt_gc_min_interval; - int rt_max_size = net->ipv6.sysctl.ip6_rt_max_size; - int rt_elasticity = net->ipv6.sysctl.ip6_rt_gc_elasticity; - int rt_gc_timeout = net->ipv6.sysctl.ip6_rt_gc_timeout; - unsigned long rt_last_gc = net->ipv6.ip6_rt_last_gc; - int entries; - - entries = dst_entries_get_fast(ops); - if (time_after(rt_last_gc + rt_min_interval, jiffies) && - entries <= rt_max_size) - goto out; - - net->ipv6.ip6_rt_gc_expire++; - fib6_run_gc(net->ipv6.ip6_rt_gc_expire, net, true); - entries = dst_entries_get_slow(ops); - if (entries < ops->gc_thresh) - net->ipv6.ip6_rt_gc_expire = rt_gc_timeout>>1; -out: - net->ipv6.ip6_rt_gc_expire -= net->ipv6.ip6_rt_gc_expire>>rt_elasticity; - return entries > rt_max_size; -} - -static int ip6_convert_metrics(struct mx6_config *mxc, - const struct fib6_config *cfg) -{ - bool ecn_ca = false; - struct nlattr *nla; - int remaining; - u32 *mp; - - if (!cfg->fc_mx) - return 0; - - mp = kzalloc(sizeof(u32) * RTAX_MAX, GFP_KERNEL); - if (unlikely(!mp)) - return -ENOMEM; - - nla_for_each_attr(nla, cfg->fc_mx, cfg->fc_mx_len, remaining) { - int type = nla_type(nla); - u32 val; - - if (!type) - continue; - if (unlikely(type > RTAX_MAX)) - goto err; - - if (type == RTAX_CC_ALGO) { - char tmp[TCP_CA_NAME_MAX]; - - nla_strlcpy(tmp, nla, sizeof(tmp)); - val = tcp_ca_get_key_by_name(tmp, &ecn_ca); - if (val == TCP_CA_UNSPEC) - goto err; - } else { - val = nla_get_u32(nla); - } - if (type == RTAX_HOPLIMIT && val > 255) - val = 255; - if (type == RTAX_FEATURES && (val & ~RTAX_FEATURE_MASK)) - goto err; - - mp[type - 1] = val; - __set_bit(type - 1, mxc->mx_valid); - } - - if (ecn_ca) { - __set_bit(RTAX_FEATURES - 1, mxc->mx_valid); - mp[RTAX_FEATURES - 1] |= DST_FEATURE_ECN_CA; - } - - mxc->mx = mp; - return 0; - err: - kfree(mp); - return -EINVAL; -} - -static struct rt6_info *ip6_nh_lookup_table(struct net *net, - struct fib6_config *cfg, - const struct in6_addr *gw_addr) -{ - struct flowi6 fl6 = { - .flowi6_oif = cfg->fc_ifindex, - .daddr = *gw_addr, - .saddr = cfg->fc_prefsrc, - }; - struct fib6_table *table; - struct rt6_info *rt; - int flags = RT6_LOOKUP_F_IFACE | RT6_LOOKUP_F_IGNORE_LINKSTATE; - - table = fib6_get_table(net, cfg->fc_table); - if (!table) - return NULL; - - if (!ipv6_addr_any(&cfg->fc_prefsrc)) - flags |= RT6_LOOKUP_F_HAS_SADDR; - - rt = ip6_pol_route(net, table, cfg->fc_ifindex, &fl6, flags); - - /* if table lookup failed, fall back to full lookup */ - if (rt == net->ipv6.ip6_null_entry) { - ip6_rt_put(rt); - rt = NULL; - } - - return rt; -} - -static struct rt6_info *ip6_route_info_create(struct fib6_config *cfg) -{ - struct net *net = cfg->fc_nlinfo.nl_net; - struct rt6_info *rt = NULL; - struct net_device *dev = NULL; - struct inet6_dev *idev = NULL; - struct fib6_table *table; - int addr_type; - int err = -EINVAL; - - if (cfg->fc_dst_len > 128 || cfg->fc_src_len > 128) - goto out; -#ifndef CONFIG_IPV6_SUBTREES - if (cfg->fc_src_len) - goto out; -#endif - if (cfg->fc_ifindex) { - err = -ENODEV; - dev = dev_get_by_index(net, cfg->fc_ifindex); - if (!dev) - goto out; - idev = in6_dev_get(dev); - if (!idev) - goto out; - } - - if (cfg->fc_metric == 0) - cfg->fc_metric = IP6_RT_PRIO_USER; - - err = -ENOBUFS; - if (cfg->fc_nlinfo.nlh && - !(cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_CREATE)) { - table = fib6_get_table(net, cfg->fc_table); - if (!table) { - pr_warn("NLM_F_CREATE should be specified when creating new route\n"); - table = fib6_new_table(net, cfg->fc_table); - } - } else { - table = fib6_new_table(net, cfg->fc_table); - } - - if (!table) - goto out; - - rt = ip6_dst_alloc(net, NULL, - (cfg->fc_flags & RTF_ADDRCONF) ? 0 : DST_NOCOUNT); - - if (!rt) { - err = -ENOMEM; - goto out; - } - - if (cfg->fc_flags & RTF_EXPIRES) - rt6_set_expires(rt, jiffies + - clock_t_to_jiffies(cfg->fc_expires)); - else - rt6_clean_expires(rt); - - if (cfg->fc_protocol == RTPROT_UNSPEC) - cfg->fc_protocol = RTPROT_BOOT; - rt->rt6i_protocol = cfg->fc_protocol; - - addr_type = ipv6_addr_type(&cfg->fc_dst); - - if (addr_type & IPV6_ADDR_MULTICAST) - rt->dst.input = ip6_mc_input; - else if (cfg->fc_flags & RTF_LOCAL) - rt->dst.input = ip6_input; - else - rt->dst.input = ip6_forward; - - rt->dst.output = ip6_output; - - if (cfg->fc_encap) { - struct lwtunnel_state *lwtstate; - - err = lwtunnel_build_state(dev, cfg->fc_encap_type, - cfg->fc_encap, AF_INET6, cfg, - &lwtstate); - if (err) - goto out; - rt->dst.lwtstate = lwtstate_get(lwtstate); - if (lwtunnel_output_redirect(rt->dst.lwtstate)) { - rt->dst.lwtstate->orig_output = rt->dst.output; - rt->dst.output = lwtunnel_output; - } - if (lwtunnel_input_redirect(rt->dst.lwtstate)) { - rt->dst.lwtstate->orig_input = rt->dst.input; - rt->dst.input = lwtunnel_input; - } - } - - ipv6_addr_prefix(&rt->rt6i_dst.addr, &cfg->fc_dst, cfg->fc_dst_len); - rt->rt6i_dst.plen = cfg->fc_dst_len; - if (rt->rt6i_dst.plen == 128) - rt->dst.flags |= DST_HOST; - -#ifdef CONFIG_IPV6_SUBTREES - ipv6_addr_prefix(&rt->rt6i_src.addr, &cfg->fc_src, cfg->fc_src_len); - rt->rt6i_src.plen = cfg->fc_src_len; -#endif - - rt->rt6i_metric = cfg->fc_metric; - - /* We cannot add true routes via loopback here, - they would result in kernel looping; promote them to reject routes - */ - if ((cfg->fc_flags & RTF_REJECT) || - (dev && (dev->flags & IFF_LOOPBACK) && - !(addr_type & IPV6_ADDR_LOOPBACK) && - !(cfg->fc_flags & RTF_LOCAL))) { - /* hold loopback dev/idev if we haven't done so. */ - if (dev != net->loopback_dev) { - if (dev) { - dev_put(dev); - in6_dev_put(idev); - } - dev = net->loopback_dev; - dev_hold(dev); - idev = in6_dev_get(dev); - if (!idev) { - err = -ENODEV; - goto out; - } - } - rt->rt6i_flags = RTF_REJECT|RTF_NONEXTHOP; - switch (cfg->fc_type) { - case RTN_BLACKHOLE: - rt->dst.error = -EINVAL; - rt->dst.output = dst_discard_out; - rt->dst.input = dst_discard; - break; - case RTN_PROHIBIT: - rt->dst.error = -EACCES; - rt->dst.output = ip6_pkt_prohibit_out; - rt->dst.input = ip6_pkt_prohibit; - break; - case RTN_THROW: - case RTN_UNREACHABLE: - default: - rt->dst.error = (cfg->fc_type == RTN_THROW) ? -EAGAIN - : (cfg->fc_type == RTN_UNREACHABLE) - ? -EHOSTUNREACH : -ENETUNREACH; - rt->dst.output = ip6_pkt_discard_out; - rt->dst.input = ip6_pkt_discard; - break; - } - goto install_route; - } - - if (cfg->fc_flags & RTF_GATEWAY) { - const struct in6_addr *gw_addr; - int gwa_type; - - gw_addr = &cfg->fc_gateway; - gwa_type = ipv6_addr_type(gw_addr); - - /* if gw_addr is local we will fail to detect this in case - * address is still TENTATIVE (DAD in progress). rt6_lookup() - * will return already-added prefix route via interface that - * prefix route was assigned to, which might be non-loopback. - */ - err = -EINVAL; - if (ipv6_chk_addr_and_flags(net, gw_addr, - gwa_type & IPV6_ADDR_LINKLOCAL ? - dev : NULL, 0, 0)) - goto out; - - rt->rt6i_gateway = *gw_addr; - - if (gwa_type != (IPV6_ADDR_LINKLOCAL|IPV6_ADDR_UNICAST)) { - struct rt6_info *grt = NULL; - - /* IPv6 strictly inhibits using not link-local - addresses as nexthop address. - Otherwise, router will not able to send redirects. - It is very good, but in some (rare!) circumstances - (SIT, PtP, NBMA NOARP links) it is handy to allow - some exceptions. --ANK - */ - if (!(gwa_type & IPV6_ADDR_UNICAST)) - goto out; - - if (cfg->fc_table) { - grt = ip6_nh_lookup_table(net, cfg, gw_addr); - - if (grt) { - if (grt->rt6i_flags & RTF_GATEWAY || - (dev && dev != grt->dst.dev)) { - ip6_rt_put(grt); - grt = NULL; - } - } - } - - if (!grt) - grt = rt6_lookup(net, gw_addr, NULL, - cfg->fc_ifindex, 1); - - err = -EHOSTUNREACH; - if (!grt) - goto out; - if (dev) { - if (dev != grt->dst.dev) { - ip6_rt_put(grt); - goto out; - } - } else { - dev = grt->dst.dev; - idev = grt->rt6i_idev; - dev_hold(dev); - in6_dev_hold(grt->rt6i_idev); - } - if (!(grt->rt6i_flags & RTF_GATEWAY)) - err = 0; - ip6_rt_put(grt); - - if (err) - goto out; - } - err = -EINVAL; - if (!dev || (dev->flags & IFF_LOOPBACK)) - goto out; - } - - err = -ENODEV; - if (!dev) - goto out; - - if (!ipv6_addr_any(&cfg->fc_prefsrc)) { - if (!ipv6_chk_addr(net, &cfg->fc_prefsrc, dev, 0)) { - err = -EINVAL; - goto out; - } - rt->rt6i_prefsrc.addr = cfg->fc_prefsrc; - rt->rt6i_prefsrc.plen = 128; - } else - rt->rt6i_prefsrc.plen = 0; - - rt->rt6i_flags = cfg->fc_flags; - -install_route: - rt->dst.dev = dev; - rt->rt6i_idev = idev; - rt->rt6i_table = table; - - cfg->fc_nlinfo.nl_net = dev_net(dev); - - return rt; -out: - if (dev) - dev_put(dev); - if (idev) - in6_dev_put(idev); - if (rt) - dst_free(&rt->dst); - - return ERR_PTR(err); -} - -int ip6_route_add(struct fib6_config *cfg) -{ - struct mx6_config mxc = { .mx = NULL, }; - struct rt6_info *rt; - int err; - - rt = ip6_route_info_create(cfg); - if (IS_ERR(rt)) { - err = PTR_ERR(rt); - rt = NULL; - goto out; - } - - err = ip6_convert_metrics(&mxc, cfg); - if (err) - goto out; - - err = __ip6_ins_rt(rt, &cfg->fc_nlinfo, &mxc); - - kfree(mxc.mx); - - return err; -out: - if (rt) - dst_free(&rt->dst); - - return err; -} - -static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info) -{ - int err; - struct fib6_table *table; - struct net *net = dev_net(rt->dst.dev); - - if (rt == net->ipv6.ip6_null_entry || - rt->dst.flags & DST_NOCACHE) { - err = -ENOENT; - goto out; - } - - table = rt->rt6i_table; - write_lock_bh(&table->tb6_lock); - err = fib6_del(rt, info); - write_unlock_bh(&table->tb6_lock); - -out: - ip6_rt_put(rt); - return err; -} - -int ip6_del_rt(struct rt6_info *rt) -{ - struct nl_info info = { - .nl_net = dev_net(rt->dst.dev), - }; - return __ip6_del_rt(rt, &info); -} - -static int ip6_route_del(struct fib6_config *cfg) -{ - struct fib6_table *table; - struct fib6_node *fn; - struct rt6_info *rt; - int err = -ESRCH; - - table = fib6_get_table(cfg->fc_nlinfo.nl_net, cfg->fc_table); - if (!table) - return err; - - read_lock_bh(&table->tb6_lock); - - fn = fib6_locate(&table->tb6_root, - &cfg->fc_dst, cfg->fc_dst_len, - &cfg->fc_src, cfg->fc_src_len); - - if (fn) { - for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) { - if ((rt->rt6i_flags & RTF_CACHE) && - !(cfg->fc_flags & RTF_CACHE)) - continue; - if (cfg->fc_ifindex && - (!rt->dst.dev || - rt->dst.dev->ifindex != cfg->fc_ifindex)) - continue; - if (cfg->fc_flags & RTF_GATEWAY && - !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway)) - continue; - if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric) - continue; - dst_hold(&rt->dst); - read_unlock_bh(&table->tb6_lock); - - return __ip6_del_rt(rt, &cfg->fc_nlinfo); - } - } - read_unlock_bh(&table->tb6_lock); - - return err; -} - -static void rt6_do_redirect(struct dst_entry *dst, struct sock *sk, struct sk_buff *skb) -{ - struct netevent_redirect netevent; - struct rt6_info *rt, *nrt = NULL; - struct ndisc_options ndopts; - struct inet6_dev *in6_dev; - struct neighbour *neigh; - struct rd_msg *msg; - int optlen, on_link; - u8 *lladdr; - - optlen = skb_tail_pointer(skb) - skb_transport_header(skb); - optlen -= sizeof(*msg); - - if (optlen < 0) { - net_dbg_ratelimited("rt6_do_redirect: packet too short\n"); - return; - } - - msg = (struct rd_msg *)icmp6_hdr(skb); - - if (ipv6_addr_is_multicast(&msg->dest)) { - net_dbg_ratelimited("rt6_do_redirect: destination address is multicast\n"); - return; - } - - on_link = 0; - if (ipv6_addr_equal(&msg->dest, &msg->target)) { - on_link = 1; - } else if (ipv6_addr_type(&msg->target) != - (IPV6_ADDR_UNICAST|IPV6_ADDR_LINKLOCAL)) { - net_dbg_ratelimited("rt6_do_redirect: target address is not link-local unicast\n"); - return; - } - - in6_dev = __in6_dev_get(skb->dev); - if (!in6_dev) - return; - if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects) - return; - - /* RFC2461 8.1: - * The IP source address of the Redirect MUST be the same as the current - * first-hop router for the specified ICMP Destination Address. - */ - - if (!ndisc_parse_options(skb->dev, msg->opt, optlen, &ndopts)) { - net_dbg_ratelimited("rt6_redirect: invalid ND options\n"); - return; - } - - lladdr = NULL; - if (ndopts.nd_opts_tgt_lladdr) { - lladdr = ndisc_opt_addr_data(ndopts.nd_opts_tgt_lladdr, - skb->dev); - if (!lladdr) { - net_dbg_ratelimited("rt6_redirect: invalid link-layer address length\n"); - return; - } - } - - rt = (struct rt6_info *) dst; - if (rt->rt6i_flags & RTF_REJECT) { - net_dbg_ratelimited("rt6_redirect: source isn't a valid nexthop for redirect target\n"); - return; - } - - /* Redirect received -> path was valid. - * Look, redirects are sent only in response to data packets, - * so that this nexthop apparently is reachable. --ANK - */ - dst_confirm(&rt->dst); - - neigh = __neigh_lookup(&nd_tbl, &msg->target, skb->dev, 1); - if (!neigh) - return; - - /* - * We have finally decided to accept it. - */ - - ndisc_update(skb->dev, neigh, lladdr, NUD_STALE, - NEIGH_UPDATE_F_WEAK_OVERRIDE| - NEIGH_UPDATE_F_OVERRIDE| - (on_link ? 0 : (NEIGH_UPDATE_F_OVERRIDE_ISROUTER| - NEIGH_UPDATE_F_ISROUTER)), - NDISC_REDIRECT, &ndopts); - - nrt = ip6_rt_cache_alloc(rt, &msg->dest, NULL); - if (!nrt) - goto out; - - nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE; - if (on_link) - nrt->rt6i_flags &= ~RTF_GATEWAY; - - nrt->rt6i_gateway = *(struct in6_addr *)neigh->primary_key; - - if (ip6_ins_rt(nrt)) - goto out; - - netevent.old = &rt->dst; - netevent.new = &nrt->dst; - netevent.daddr = &msg->dest; - netevent.neigh = neigh; - call_netevent_notifiers(NETEVENT_REDIRECT, &netevent); - - if (rt->rt6i_flags & RTF_CACHE) { - rt = (struct rt6_info *) dst_clone(&rt->dst); - ip6_del_rt(rt); - } - -out: - neigh_release(neigh); -} - -/* - * Misc support functions - */ - -static void rt6_set_from(struct rt6_info *rt, struct rt6_info *from) -{ - BUG_ON(from->dst.from); - - rt->rt6i_flags &= ~RTF_EXPIRES; - dst_hold(&from->dst); - rt->dst.from = &from->dst; - dst_init_metrics(&rt->dst, dst_metrics_ptr(&from->dst), true); -} - -static void ip6_rt_copy_init(struct rt6_info *rt, struct rt6_info *ort) -{ - rt->dst.input = ort->dst.input; - rt->dst.output = ort->dst.output; - rt->rt6i_dst = ort->rt6i_dst; - rt->dst.error = ort->dst.error; - rt->rt6i_idev = ort->rt6i_idev; - if (rt->rt6i_idev) - in6_dev_hold(rt->rt6i_idev); - rt->dst.lastuse = jiffies; - rt->rt6i_gateway = ort->rt6i_gateway; - rt->rt6i_flags = ort->rt6i_flags; - rt6_set_from(rt, ort); - rt->rt6i_metric = ort->rt6i_metric; -#ifdef CONFIG_IPV6_SUBTREES - rt->rt6i_src = ort->rt6i_src; -#endif - rt->rt6i_prefsrc = ort->rt6i_prefsrc; - rt->rt6i_table = ort->rt6i_table; - rt->dst.lwtstate = lwtstate_get(ort->dst.lwtstate); -} - -#ifdef CONFIG_IPV6_ROUTE_INFO -static struct rt6_info *rt6_get_route_info(struct net *net, - const struct in6_addr *prefix, int prefixlen, - const struct in6_addr *gwaddr, - struct net_device *dev) -{ - u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO; - int ifindex = dev->ifindex; - struct fib6_node *fn; - struct rt6_info *rt = NULL; - struct fib6_table *table; - - table = fib6_get_table(net, tb_id); - if (!table) - return NULL; - - read_lock_bh(&table->tb6_lock); - fn = fib6_locate(&table->tb6_root, prefix, prefixlen, NULL, 0); - if (!fn) - goto out; - - for (rt = fn->leaf; rt; rt = rt->dst.rt6_next) { - if (rt->dst.dev->ifindex != ifindex) - continue; - if ((rt->rt6i_flags & (RTF_ROUTEINFO|RTF_GATEWAY)) != (RTF_ROUTEINFO|RTF_GATEWAY)) - continue; - if (!ipv6_addr_equal(&rt->rt6i_gateway, gwaddr)) - continue; - dst_hold(&rt->dst); - break; - } -out: - read_unlock_bh(&table->tb6_lock); - return rt; -} - -static struct rt6_info *rt6_add_route_info(struct net *net, - const struct in6_addr *prefix, int prefixlen, - const struct in6_addr *gwaddr, - struct net_device *dev, - unsigned int pref) -{ - struct fib6_config cfg = { - .fc_metric = IP6_RT_PRIO_USER, - .fc_ifindex = dev->ifindex, - .fc_dst_len = prefixlen, - .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_ROUTEINFO | - RTF_UP | RTF_PREF(pref), - .fc_nlinfo.portid = 0, - .fc_nlinfo.nlh = NULL, - .fc_nlinfo.nl_net = net, - }; - - cfg.fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_INFO, - cfg.fc_dst = *prefix; - cfg.fc_gateway = *gwaddr; - - /* We should treat it as a default route if prefix length is 0. */ - if (!prefixlen) - cfg.fc_flags |= RTF_DEFAULT; - - ip6_route_add(&cfg); - - return rt6_get_route_info(net, prefix, prefixlen, gwaddr, dev); -} -#endif - -struct rt6_info *rt6_get_dflt_router(const struct in6_addr *addr, struct net_device *dev) -{ - u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT; - struct rt6_info *rt; - struct fib6_table *table; - - table = fib6_get_table(dev_net(dev), tb_id); - if (!table) - return NULL; - - read_lock_bh(&table->tb6_lock); - for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) { - if (dev == rt->dst.dev && - ((rt->rt6i_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) && - ipv6_addr_equal(&rt->rt6i_gateway, addr)) - break; - } - if (rt) - dst_hold(&rt->dst); - read_unlock_bh(&table->tb6_lock); - return rt; -} - -struct rt6_info *rt6_add_dflt_router(const struct in6_addr *gwaddr, - struct net_device *dev, - unsigned int pref) -{ - struct fib6_config cfg = { - .fc_table = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT, - .fc_metric = IP6_RT_PRIO_USER, - .fc_ifindex = dev->ifindex, - .fc_flags = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT | - RTF_UP | RTF_EXPIRES | RTF_PREF(pref), - .fc_nlinfo.portid = 0, - .fc_nlinfo.nlh = NULL, - .fc_nlinfo.nl_net = dev_net(dev), - }; - - cfg.fc_gateway = *gwaddr; - - if (!ip6_route_add(&cfg)) { - struct fib6_table *table; - - table = fib6_get_table(dev_net(dev), cfg.fc_table); - if (table) - table->flags |= RT6_TABLE_HAS_DFLT_ROUTER; - } - - return rt6_get_dflt_router(gwaddr, dev); -} - -static void __rt6_purge_dflt_routers(struct fib6_table *table) -{ - struct rt6_info *rt; - -restart: - read_lock_bh(&table->tb6_lock); - for (rt = table->tb6_root.leaf; rt; rt = rt->dst.rt6_next) { - if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF) && - (!rt->rt6i_idev || rt->rt6i_idev->cnf.accept_ra != 2)) { - dst_hold(&rt->dst); - read_unlock_bh(&table->tb6_lock); - ip6_del_rt(rt); - goto restart; - } - } - read_unlock_bh(&table->tb6_lock); - - table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER; -} - -void rt6_purge_dflt_routers(struct net *net) -{ - struct fib6_table *table; - struct hlist_head *head; - unsigned int h; - - rcu_read_lock(); - - for (h = 0; h < FIB6_TABLE_HASHSZ; h++) { - head = &net->ipv6.fib_table_hash[h]; - hlist_for_each_entry_rcu(table, head, tb6_hlist) { - if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER) - __rt6_purge_dflt_routers(table); - } - } - - rcu_read_unlock(); -} - -static void rtmsg_to_fib6_config(struct net *net, - struct in6_rtmsg *rtmsg, - struct fib6_config *cfg) -{ - memset(cfg, 0, sizeof(*cfg)); - - cfg->fc_table = l3mdev_fib_table_by_index(net, rtmsg->rtmsg_ifindex) ? - : RT6_TABLE_MAIN; - cfg->fc_ifindex = rtmsg->rtmsg_ifindex; - cfg->fc_metric = rtmsg->rtmsg_metric; - cfg->fc_expires = rtmsg->rtmsg_info; - cfg->fc_dst_len = rtmsg->rtmsg_dst_len; - cfg->fc_src_len = rtmsg->rtmsg_src_len; - cfg->fc_flags = rtmsg->rtmsg_flags; - - cfg->fc_nlinfo.nl_net = net; - - cfg->fc_dst = rtmsg->rtmsg_dst; - cfg->fc_src = rtmsg->rtmsg_src; - cfg->fc_gateway = rtmsg->rtmsg_gateway; -} - -int ipv6_route_ioctl(struct net *net, unsigned int cmd, void __user *arg) -{ - struct fib6_config cfg; - struct in6_rtmsg rtmsg; - int err; - - switch (cmd) { - case SIOCADDRT: /* Add a route */ - case SIOCDELRT: /* Delete a route */ - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - return -EPERM; - err = copy_from_user(&rtmsg, arg, - sizeof(struct in6_rtmsg)); - if (err) - return -EFAULT; - - rtmsg_to_fib6_config(net, &rtmsg, &cfg); - - rtnl_lock(); - switch (cmd) { - case SIOCADDRT: - err = ip6_route_add(&cfg); - break; - case SIOCDELRT: - err = ip6_route_del(&cfg); - break; - default: - err = -EINVAL; - } - rtnl_unlock(); - - return err; - } - - return -EINVAL; -} - -/* - * Drop the packet on the floor - */ - -static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes) -{ - int type; - struct dst_entry *dst = skb_dst(skb); - switch (ipstats_mib_noroutes) { - case IPSTATS_MIB_INNOROUTES: - type = ipv6_addr_type(&ipv6_hdr(skb)->daddr); - if (type == IPV6_ADDR_ANY) { - IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst), - IPSTATS_MIB_INADDRERRORS); - break; - } - /* FALLTHROUGH */ - case IPSTATS_MIB_OUTNOROUTES: - IP6_INC_STATS(dev_net(dst->dev), ip6_dst_idev(dst), - ipstats_mib_noroutes); - break; - } - icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0); - kfree_skb(skb); - return 0; -} - -static int ip6_pkt_discard(struct sk_buff *skb) -{ - return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_INNOROUTES); -} - -static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - skb->dev = skb_dst(skb)->dev; - return ip6_pkt_drop(skb, ICMPV6_NOROUTE, IPSTATS_MIB_OUTNOROUTES); -} - -static int ip6_pkt_prohibit(struct sk_buff *skb) -{ - return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_INNOROUTES); -} - -static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - skb->dev = skb_dst(skb)->dev; - return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES); -} - -/* - * Allocate a dst for local (unicast / anycast) address. - */ - -struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev, - const struct in6_addr *addr, - bool anycast) -{ - u32 tb_id; - struct net *net = dev_net(idev->dev); - struct net_device *dev = net->loopback_dev; - struct rt6_info *rt; - - /* use L3 Master device as loopback for host routes if device - * is enslaved and address is not link local or multicast - */ - if (!rt6_need_strict(addr)) - dev = l3mdev_master_dev_rcu(idev->dev) ? : dev; - - rt = ip6_dst_alloc(net, dev, DST_NOCOUNT); - if (!rt) - return ERR_PTR(-ENOMEM); - - in6_dev_hold(idev); - - rt->dst.flags |= DST_HOST; - rt->dst.input = ip6_input; - rt->dst.output = ip6_output; - rt->rt6i_idev = idev; - - rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; - if (anycast) - rt->rt6i_flags |= RTF_ANYCAST; - else - rt->rt6i_flags |= RTF_LOCAL; - - rt->rt6i_gateway = *addr; - rt->rt6i_dst.addr = *addr; - rt->rt6i_dst.plen = 128; - tb_id = l3mdev_fib_table(idev->dev) ? : RT6_TABLE_LOCAL; - rt->rt6i_table = fib6_get_table(net, tb_id); - rt->dst.flags |= DST_NOCACHE; - - atomic_set(&rt->dst.__refcnt, 1); - - return rt; -} - -/* remove deleted ip from prefsrc entries */ -struct arg_dev_net_ip { - struct net_device *dev; - struct net *net; - struct in6_addr *addr; -}; - -static int fib6_remove_prefsrc(struct rt6_info *rt, void *arg) -{ - struct net_device *dev = ((struct arg_dev_net_ip *)arg)->dev; - struct net *net = ((struct arg_dev_net_ip *)arg)->net; - struct in6_addr *addr = ((struct arg_dev_net_ip *)arg)->addr; - - if (((void *)rt->dst.dev == dev || !dev) && - rt != net->ipv6.ip6_null_entry && - ipv6_addr_equal(addr, &rt->rt6i_prefsrc.addr)) { - /* remove prefsrc entry */ - rt->rt6i_prefsrc.plen = 0; - } - return 0; -} - -void rt6_remove_prefsrc(struct inet6_ifaddr *ifp) -{ - struct net *net = dev_net(ifp->idev->dev); - struct arg_dev_net_ip adni = { - .dev = ifp->idev->dev, - .net = net, - .addr = &ifp->addr, - }; - fib6_clean_all(net, fib6_remove_prefsrc, &adni); -} - -#define RTF_RA_ROUTER (RTF_ADDRCONF | RTF_DEFAULT | RTF_GATEWAY) -#define RTF_CACHE_GATEWAY (RTF_GATEWAY | RTF_CACHE) - -/* Remove routers and update dst entries when gateway turn into host. */ -static int fib6_clean_tohost(struct rt6_info *rt, void *arg) -{ - struct in6_addr *gateway = (struct in6_addr *)arg; - - if ((((rt->rt6i_flags & RTF_RA_ROUTER) == RTF_RA_ROUTER) || - ((rt->rt6i_flags & RTF_CACHE_GATEWAY) == RTF_CACHE_GATEWAY)) && - ipv6_addr_equal(gateway, &rt->rt6i_gateway)) { - return -1; - } - return 0; -} - -void rt6_clean_tohost(struct net *net, struct in6_addr *gateway) -{ - fib6_clean_all(net, fib6_clean_tohost, gateway); -} - -struct arg_dev_net { - struct net_device *dev; - struct net *net; -}; - -static int fib6_ifdown(struct rt6_info *rt, void *arg) -{ - const struct arg_dev_net *adn = arg; - const struct net_device *dev = adn->dev; - - if ((rt->dst.dev == dev || !dev) && - rt != adn->net->ipv6.ip6_null_entry) - return -1; - - return 0; -} - -void rt6_ifdown(struct net *net, struct net_device *dev) -{ - struct arg_dev_net adn = { - .dev = dev, - .net = net, - }; - - fib6_clean_all(net, fib6_ifdown, &adn); - icmp6_clean_all(fib6_ifdown, &adn); - if (dev) - rt6_uncached_list_flush_dev(net, dev); -} - -struct rt6_mtu_change_arg { - struct net_device *dev; - unsigned int mtu; -}; - -static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg) -{ - struct rt6_mtu_change_arg *arg = (struct rt6_mtu_change_arg *) p_arg; - struct inet6_dev *idev; - - /* In IPv6 pmtu discovery is not optional, - so that RTAX_MTU lock cannot disable it. - We still use this lock to block changes - caused by addrconf/ndisc. - */ - - idev = __in6_dev_get(arg->dev); - if (!idev) - return 0; - - /* For administrative MTU increase, there is no way to discover - IPv6 PMTU increase, so PMTU increase should be updated here. - Since RFC 1981 doesn't include administrative MTU increase - update PMTU increase is a MUST. (i.e. jumbo frame) - */ - /* - If new MTU is less than route PMTU, this new MTU will be the - lowest MTU in the path, update the route PMTU to reflect PMTU - decreases; if new MTU is greater than route PMTU, and the - old MTU is the lowest MTU in the path, update the route PMTU - to reflect the increase. In this case if the other nodes' MTU - also have the lowest MTU, TOO BIG MESSAGE will be lead to - PMTU discouvery. - */ - if (rt->dst.dev == arg->dev && - dst_metric_raw(&rt->dst, RTAX_MTU) && - !dst_metric_locked(&rt->dst, RTAX_MTU)) { - if (rt->rt6i_flags & RTF_CACHE) { - /* For RTF_CACHE with rt6i_pmtu == 0 - * (i.e. a redirected route), - * the metrics of its rt->dst.from has already - * been updated. - */ - if (rt->rt6i_pmtu && rt->rt6i_pmtu > arg->mtu) - rt->rt6i_pmtu = arg->mtu; - } else if (dst_mtu(&rt->dst) >= arg->mtu || - (dst_mtu(&rt->dst) < arg->mtu && - dst_mtu(&rt->dst) == idev->cnf.mtu6)) { - dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu); - } - } - return 0; -} - -void rt6_mtu_change(struct net_device *dev, unsigned int mtu) -{ - struct rt6_mtu_change_arg arg = { - .dev = dev, - .mtu = mtu, - }; - - fib6_clean_all(dev_net(dev), rt6_mtu_change_route, &arg); -} - -static const struct nla_policy rtm_ipv6_policy[RTA_MAX+1] = { - [RTA_GATEWAY] = { .len = sizeof(struct in6_addr) }, - [RTA_OIF] = { .type = NLA_U32 }, - [RTA_IIF] = { .type = NLA_U32 }, - [RTA_PRIORITY] = { .type = NLA_U32 }, - [RTA_METRICS] = { .type = NLA_NESTED }, - [RTA_MULTIPATH] = { .len = sizeof(struct rtnexthop) }, - [RTA_PREF] = { .type = NLA_U8 }, - [RTA_ENCAP_TYPE] = { .type = NLA_U16 }, - [RTA_ENCAP] = { .type = NLA_NESTED }, - [RTA_EXPIRES] = { .type = NLA_U32 }, -}; - -static int rtm_to_fib6_config(struct sk_buff *skb, struct nlmsghdr *nlh, - struct fib6_config *cfg) -{ - struct rtmsg *rtm; - struct nlattr *tb[RTA_MAX+1]; - unsigned int pref; - int err; - - err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy); - if (err < 0) - goto errout; - - err = -EINVAL; - rtm = nlmsg_data(nlh); - memset(cfg, 0, sizeof(*cfg)); - - cfg->fc_table = rtm->rtm_table; - cfg->fc_dst_len = rtm->rtm_dst_len; - cfg->fc_src_len = rtm->rtm_src_len; - cfg->fc_flags = RTF_UP; - cfg->fc_protocol = rtm->rtm_protocol; - cfg->fc_type = rtm->rtm_type; - - if (rtm->rtm_type == RTN_UNREACHABLE || - rtm->rtm_type == RTN_BLACKHOLE || - rtm->rtm_type == RTN_PROHIBIT || - rtm->rtm_type == RTN_THROW) - cfg->fc_flags |= RTF_REJECT; - - if (rtm->rtm_type == RTN_LOCAL) - cfg->fc_flags |= RTF_LOCAL; - - if (rtm->rtm_flags & RTM_F_CLONED) - cfg->fc_flags |= RTF_CACHE; - - cfg->fc_nlinfo.portid = NETLINK_CB(skb).portid; - cfg->fc_nlinfo.nlh = nlh; - cfg->fc_nlinfo.nl_net = sock_net(skb->sk); - - if (tb[RTA_GATEWAY]) { - cfg->fc_gateway = nla_get_in6_addr(tb[RTA_GATEWAY]); - cfg->fc_flags |= RTF_GATEWAY; - } - - if (tb[RTA_DST]) { - int plen = (rtm->rtm_dst_len + 7) >> 3; - - if (nla_len(tb[RTA_DST]) < plen) - goto errout; - - nla_memcpy(&cfg->fc_dst, tb[RTA_DST], plen); - } - - if (tb[RTA_SRC]) { - int plen = (rtm->rtm_src_len + 7) >> 3; - - if (nla_len(tb[RTA_SRC]) < plen) - goto errout; - - nla_memcpy(&cfg->fc_src, tb[RTA_SRC], plen); - } - - if (tb[RTA_PREFSRC]) - cfg->fc_prefsrc = nla_get_in6_addr(tb[RTA_PREFSRC]); - - if (tb[RTA_OIF]) - cfg->fc_ifindex = nla_get_u32(tb[RTA_OIF]); - - if (tb[RTA_PRIORITY]) - cfg->fc_metric = nla_get_u32(tb[RTA_PRIORITY]); - - if (tb[RTA_METRICS]) { - cfg->fc_mx = nla_data(tb[RTA_METRICS]); - cfg->fc_mx_len = nla_len(tb[RTA_METRICS]); - } - - if (tb[RTA_TABLE]) - cfg->fc_table = nla_get_u32(tb[RTA_TABLE]); - - if (tb[RTA_MULTIPATH]) { - cfg->fc_mp = nla_data(tb[RTA_MULTIPATH]); - cfg->fc_mp_len = nla_len(tb[RTA_MULTIPATH]); - } - - if (tb[RTA_PREF]) { - pref = nla_get_u8(tb[RTA_PREF]); - if (pref != ICMPV6_ROUTER_PREF_LOW && - pref != ICMPV6_ROUTER_PREF_HIGH) - pref = ICMPV6_ROUTER_PREF_MEDIUM; - cfg->fc_flags |= RTF_PREF(pref); - } - - if (tb[RTA_ENCAP]) - cfg->fc_encap = tb[RTA_ENCAP]; - - if (tb[RTA_ENCAP_TYPE]) - cfg->fc_encap_type = nla_get_u16(tb[RTA_ENCAP_TYPE]); - - if (tb[RTA_EXPIRES]) { - unsigned long timeout = addrconf_timeout_fixup(nla_get_u32(tb[RTA_EXPIRES]), HZ); - - if (addrconf_finite_timeout(timeout)) { - cfg->fc_expires = jiffies_to_clock_t(timeout * HZ); - cfg->fc_flags |= RTF_EXPIRES; - } - } - - err = 0; -errout: - return err; -} - -struct rt6_nh { - struct rt6_info *rt6_info; - struct fib6_config r_cfg; - struct mx6_config mxc; - struct list_head next; -}; - -static void ip6_print_replace_route_err(struct list_head *rt6_nh_list) -{ - struct rt6_nh *nh; - - list_for_each_entry(nh, rt6_nh_list, next) { - pr_warn("IPV6: multipath route replace failed (check consistency of installed routes): %pI6 nexthop %pI6 ifi %d\n", - &nh->r_cfg.fc_dst, &nh->r_cfg.fc_gateway, - nh->r_cfg.fc_ifindex); - } -} - -static int ip6_route_info_append(struct list_head *rt6_nh_list, - struct rt6_info *rt, struct fib6_config *r_cfg) -{ - struct rt6_nh *nh; - struct rt6_info *rtnh; - int err = -EEXIST; - - list_for_each_entry(nh, rt6_nh_list, next) { - /* check if rt6_info already exists */ - rtnh = nh->rt6_info; - - if (rtnh->dst.dev == rt->dst.dev && - rtnh->rt6i_idev == rt->rt6i_idev && - ipv6_addr_equal(&rtnh->rt6i_gateway, - &rt->rt6i_gateway)) - return err; - } - - nh = kzalloc(sizeof(*nh), GFP_KERNEL); - if (!nh) - return -ENOMEM; - nh->rt6_info = rt; - err = ip6_convert_metrics(&nh->mxc, r_cfg); - if (err) { - kfree(nh); - return err; - } - memcpy(&nh->r_cfg, r_cfg, sizeof(*r_cfg)); - list_add_tail(&nh->next, rt6_nh_list); - - return 0; -} - -static int ip6_route_multipath_add(struct fib6_config *cfg) -{ - struct fib6_config r_cfg; - struct rtnexthop *rtnh; - struct rt6_info *rt; - struct rt6_nh *err_nh; - struct rt6_nh *nh, *nh_safe; - int remaining; - int attrlen; - int err = 1; - int nhn = 0; - int replace = (cfg->fc_nlinfo.nlh && - (cfg->fc_nlinfo.nlh->nlmsg_flags & NLM_F_REPLACE)); - LIST_HEAD(rt6_nh_list); - - remaining = cfg->fc_mp_len; - rtnh = (struct rtnexthop *)cfg->fc_mp; - - /* Parse a Multipath Entry and build a list (rt6_nh_list) of - * rt6_info structs per nexthop - */ - while (rtnh_ok(rtnh, remaining)) { - memcpy(&r_cfg, cfg, sizeof(*cfg)); - if (rtnh->rtnh_ifindex) - r_cfg.fc_ifindex = rtnh->rtnh_ifindex; - - attrlen = rtnh_attrlen(rtnh); - if (attrlen > 0) { - struct nlattr *nla, *attrs = rtnh_attrs(rtnh); - - nla = nla_find(attrs, attrlen, RTA_GATEWAY); - if (nla) { - r_cfg.fc_gateway = nla_get_in6_addr(nla); - r_cfg.fc_flags |= RTF_GATEWAY; - } - r_cfg.fc_encap = nla_find(attrs, attrlen, RTA_ENCAP); - nla = nla_find(attrs, attrlen, RTA_ENCAP_TYPE); - if (nla) - r_cfg.fc_encap_type = nla_get_u16(nla); - } - - rt = ip6_route_info_create(&r_cfg); - if (IS_ERR(rt)) { - err = PTR_ERR(rt); - rt = NULL; - goto cleanup; - } - - err = ip6_route_info_append(&rt6_nh_list, rt, &r_cfg); - if (err) { - dst_free(&rt->dst); - goto cleanup; - } - - rtnh = rtnh_next(rtnh, &remaining); - } - - err_nh = NULL; - list_for_each_entry(nh, &rt6_nh_list, next) { - err = __ip6_ins_rt(nh->rt6_info, &cfg->fc_nlinfo, &nh->mxc); - /* nh->rt6_info is used or freed at this point, reset to NULL*/ - nh->rt6_info = NULL; - if (err) { - if (replace && nhn) - ip6_print_replace_route_err(&rt6_nh_list); - err_nh = nh; - goto add_errout; - } - - /* Because each route is added like a single route we remove - * these flags after the first nexthop: if there is a collision, - * we have already failed to add the first nexthop: - * fib6_add_rt2node() has rejected it; when replacing, old - * nexthops have been replaced by first new, the rest should - * be added to it. - */ - cfg->fc_nlinfo.nlh->nlmsg_flags &= ~(NLM_F_EXCL | - NLM_F_REPLACE); - nhn++; - } - - goto cleanup; - -add_errout: - /* Delete routes that were already added */ - list_for_each_entry(nh, &rt6_nh_list, next) { - if (err_nh == nh) - break; - ip6_route_del(&nh->r_cfg); - } - -cleanup: - list_for_each_entry_safe(nh, nh_safe, &rt6_nh_list, next) { - if (nh->rt6_info) - dst_free(&nh->rt6_info->dst); - kfree(nh->mxc.mx); - list_del(&nh->next); - kfree(nh); - } - - return err; -} - -static int ip6_route_multipath_del(struct fib6_config *cfg) -{ - struct fib6_config r_cfg; - struct rtnexthop *rtnh; - int remaining; - int attrlen; - int err = 1, last_err = 0; - - remaining = cfg->fc_mp_len; - rtnh = (struct rtnexthop *)cfg->fc_mp; - - /* Parse a Multipath Entry */ - while (rtnh_ok(rtnh, remaining)) { - memcpy(&r_cfg, cfg, sizeof(*cfg)); - if (rtnh->rtnh_ifindex) - r_cfg.fc_ifindex = rtnh->rtnh_ifindex; - - attrlen = rtnh_attrlen(rtnh); - if (attrlen > 0) { - struct nlattr *nla, *attrs = rtnh_attrs(rtnh); - - nla = nla_find(attrs, attrlen, RTA_GATEWAY); - if (nla) { - nla_memcpy(&r_cfg.fc_gateway, nla, 16); - r_cfg.fc_flags |= RTF_GATEWAY; - } - } - err = ip6_route_del(&r_cfg); - if (err) - last_err = err; - - rtnh = rtnh_next(rtnh, &remaining); - } - - return last_err; -} - -static int inet6_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct fib6_config cfg; - int err; - - err = rtm_to_fib6_config(skb, nlh, &cfg); - if (err < 0) - return err; - - if (cfg.fc_mp) - return ip6_route_multipath_del(&cfg); - else - return ip6_route_del(&cfg); -} - -static int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct fib6_config cfg; - int err; - - err = rtm_to_fib6_config(skb, nlh, &cfg); - if (err < 0) - return err; - - if (cfg.fc_mp) - return ip6_route_multipath_add(&cfg); - else - return ip6_route_add(&cfg); -} - -static inline size_t rt6_nlmsg_size(struct rt6_info *rt) -{ - return NLMSG_ALIGN(sizeof(struct rtmsg)) - + nla_total_size(16) /* RTA_SRC */ - + nla_total_size(16) /* RTA_DST */ - + nla_total_size(16) /* RTA_GATEWAY */ - + nla_total_size(16) /* RTA_PREFSRC */ - + nla_total_size(4) /* RTA_TABLE */ - + nla_total_size(4) /* RTA_IIF */ - + nla_total_size(4) /* RTA_OIF */ - + nla_total_size(4) /* RTA_PRIORITY */ - + RTAX_MAX * nla_total_size(4) /* RTA_METRICS */ - + nla_total_size(sizeof(struct rta_cacheinfo)) - + nla_total_size(TCP_CA_NAME_MAX) /* RTAX_CC_ALGO */ - + nla_total_size(1) /* RTA_PREF */ - + lwtunnel_get_encap_size(rt->dst.lwtstate); -} - -static int rt6_fill_node(struct net *net, - struct sk_buff *skb, struct rt6_info *rt, - struct in6_addr *dst, struct in6_addr *src, - int iif, int type, u32 portid, u32 seq, - int prefix, int nowait, unsigned int flags) -{ - u32 metrics[RTAX_MAX]; - struct rtmsg *rtm; - struct nlmsghdr *nlh; - long expires; - u32 table; - - if (prefix) { /* user wants prefix routes only */ - if (!(rt->rt6i_flags & RTF_PREFIX_RT)) { - /* success since this is not a prefix route */ - return 1; - } - } - - nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags); - if (!nlh) - return -EMSGSIZE; - - rtm = nlmsg_data(nlh); - rtm->rtm_family = AF_INET6; - rtm->rtm_dst_len = rt->rt6i_dst.plen; - rtm->rtm_src_len = rt->rt6i_src.plen; - rtm->rtm_tos = 0; - if (rt->rt6i_table) - table = rt->rt6i_table->tb6_id; - else - table = RT6_TABLE_UNSPEC; - rtm->rtm_table = table; - if (nla_put_u32(skb, RTA_TABLE, table)) - goto nla_put_failure; - if (rt->rt6i_flags & RTF_REJECT) { - switch (rt->dst.error) { - case -EINVAL: - rtm->rtm_type = RTN_BLACKHOLE; - break; - case -EACCES: - rtm->rtm_type = RTN_PROHIBIT; - break; - case -EAGAIN: - rtm->rtm_type = RTN_THROW; - break; - default: - rtm->rtm_type = RTN_UNREACHABLE; - break; - } - } - else if (rt->rt6i_flags & RTF_LOCAL) - rtm->rtm_type = RTN_LOCAL; - else if (rt->dst.dev && (rt->dst.dev->flags & IFF_LOOPBACK)) - rtm->rtm_type = RTN_LOCAL; - else - rtm->rtm_type = RTN_UNICAST; - rtm->rtm_flags = 0; - if (!netif_carrier_ok(rt->dst.dev)) { - rtm->rtm_flags |= RTNH_F_LINKDOWN; - if (rt->rt6i_idev->cnf.ignore_routes_with_linkdown) - rtm->rtm_flags |= RTNH_F_DEAD; - } - rtm->rtm_scope = RT_SCOPE_UNIVERSE; - rtm->rtm_protocol = rt->rt6i_protocol; - if (rt->rt6i_flags & RTF_DYNAMIC) - rtm->rtm_protocol = RTPROT_REDIRECT; - else if (rt->rt6i_flags & RTF_ADDRCONF) { - if (rt->rt6i_flags & (RTF_DEFAULT | RTF_ROUTEINFO)) - rtm->rtm_protocol = RTPROT_RA; - else - rtm->rtm_protocol = RTPROT_KERNEL; - } - - if (rt->rt6i_flags & RTF_CACHE) - rtm->rtm_flags |= RTM_F_CLONED; - - if (dst) { - if (nla_put_in6_addr(skb, RTA_DST, dst)) - goto nla_put_failure; - rtm->rtm_dst_len = 128; - } else if (rtm->rtm_dst_len) - if (nla_put_in6_addr(skb, RTA_DST, &rt->rt6i_dst.addr)) - goto nla_put_failure; -#ifdef CONFIG_IPV6_SUBTREES - if (src) { - if (nla_put_in6_addr(skb, RTA_SRC, src)) - goto nla_put_failure; - rtm->rtm_src_len = 128; - } else if (rtm->rtm_src_len && - nla_put_in6_addr(skb, RTA_SRC, &rt->rt6i_src.addr)) - goto nla_put_failure; -#endif - if (iif) { -#ifdef CONFIG_IPV6_MROUTE - if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) { - int err = ip6mr_get_route(net, skb, rtm, nowait, - portid); - - if (err <= 0) { - if (!nowait) { - if (err == 0) - return 0; - goto nla_put_failure; - } else { - if (err == -EMSGSIZE) - goto nla_put_failure; - } - } - } else -#endif - if (nla_put_u32(skb, RTA_IIF, iif)) - goto nla_put_failure; - } else if (dst) { - struct in6_addr saddr_buf; - if (ip6_route_get_saddr(net, rt, dst, 0, &saddr_buf) == 0 && - nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf)) - goto nla_put_failure; - } - - if (rt->rt6i_prefsrc.plen) { - struct in6_addr saddr_buf; - saddr_buf = rt->rt6i_prefsrc.addr; - if (nla_put_in6_addr(skb, RTA_PREFSRC, &saddr_buf)) - goto nla_put_failure; - } - - memcpy(metrics, dst_metrics_ptr(&rt->dst), sizeof(metrics)); - if (rt->rt6i_pmtu) - metrics[RTAX_MTU - 1] = rt->rt6i_pmtu; - if (rtnetlink_put_metrics(skb, metrics) < 0) - goto nla_put_failure; - - if (rt->rt6i_flags & RTF_GATEWAY) { - if (nla_put_in6_addr(skb, RTA_GATEWAY, &rt->rt6i_gateway) < 0) - goto nla_put_failure; - } - - if (rt->dst.dev && - nla_put_u32(skb, RTA_OIF, rt->dst.dev->ifindex)) - goto nla_put_failure; - if (nla_put_u32(skb, RTA_PRIORITY, rt->rt6i_metric)) - goto nla_put_failure; - - expires = (rt->rt6i_flags & RTF_EXPIRES) ? rt->dst.expires - jiffies : 0; - - if (rtnl_put_cacheinfo(skb, &rt->dst, 0, expires, rt->dst.error) < 0) - goto nla_put_failure; - - if (nla_put_u8(skb, RTA_PREF, IPV6_EXTRACT_PREF(rt->rt6i_flags))) - goto nla_put_failure; - - lwtunnel_fill_encap(skb, rt->dst.lwtstate); - - nlmsg_end(skb, nlh); - return 0; - -nla_put_failure: - nlmsg_cancel(skb, nlh); - return -EMSGSIZE; -} - -int rt6_dump_route(struct rt6_info *rt, void *p_arg) -{ - struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg; - int prefix; - - if (nlmsg_len(arg->cb->nlh) >= sizeof(struct rtmsg)) { - struct rtmsg *rtm = nlmsg_data(arg->cb->nlh); - prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0; - } else - prefix = 0; - - return rt6_fill_node(arg->net, - arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE, - NETLINK_CB(arg->cb->skb).portid, arg->cb->nlh->nlmsg_seq, - prefix, 0, NLM_F_MULTI); -} - -static int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr *nlh) -{ - struct net *net = sock_net(in_skb->sk); - struct nlattr *tb[RTA_MAX+1]; - struct rt6_info *rt; - struct sk_buff *skb; - struct rtmsg *rtm; - struct flowi6 fl6; - int err, iif = 0, oif = 0; - - err = nlmsg_parse(nlh, sizeof(*rtm), tb, RTA_MAX, rtm_ipv6_policy); - if (err < 0) - goto errout; - - err = -EINVAL; - memset(&fl6, 0, sizeof(fl6)); - rtm = nlmsg_data(nlh); - fl6.flowlabel = ip6_make_flowinfo(rtm->rtm_tos, 0); - - if (tb[RTA_SRC]) { - if (nla_len(tb[RTA_SRC]) < sizeof(struct in6_addr)) - goto errout; - - fl6.saddr = *(struct in6_addr *)nla_data(tb[RTA_SRC]); - } - - if (tb[RTA_DST]) { - if (nla_len(tb[RTA_DST]) < sizeof(struct in6_addr)) - goto errout; - - fl6.daddr = *(struct in6_addr *)nla_data(tb[RTA_DST]); - } - - if (tb[RTA_IIF]) - iif = nla_get_u32(tb[RTA_IIF]); - - if (tb[RTA_OIF]) - oif = nla_get_u32(tb[RTA_OIF]); - - if (tb[RTA_MARK]) - fl6.flowi6_mark = nla_get_u32(tb[RTA_MARK]); - - if (iif) { - struct net_device *dev; - int flags = 0; - - dev = __dev_get_by_index(net, iif); - if (!dev) { - err = -ENODEV; - goto errout; - } - - fl6.flowi6_iif = iif; - - if (!ipv6_addr_any(&fl6.saddr)) - flags |= RT6_LOOKUP_F_HAS_SADDR; - - rt = (struct rt6_info *)ip6_route_input_lookup(net, dev, &fl6, - flags); - } else { - fl6.flowi6_oif = oif; - - rt = (struct rt6_info *)ip6_route_output(net, NULL, &fl6); - } - - skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); - if (!skb) { - ip6_rt_put(rt); - err = -ENOBUFS; - goto errout; - } - - /* Reserve room for dummy headers, this skb can pass - through good chunk of routing engine. - */ - skb_reset_mac_header(skb); - skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); - - skb_dst_set(skb, &rt->dst); - - err = rt6_fill_node(net, skb, rt, &fl6.daddr, &fl6.saddr, iif, - RTM_NEWROUTE, NETLINK_CB(in_skb).portid, - nlh->nlmsg_seq, 0, 0, 0); - if (err < 0) { - kfree_skb(skb); - goto errout; - } - - err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).portid); -errout: - return err; -} - -void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info, - unsigned int nlm_flags) -{ - struct sk_buff *skb; - struct net *net = info->nl_net; - u32 seq; - int err; - - err = -ENOBUFS; - seq = info->nlh ? info->nlh->nlmsg_seq : 0; - - skb = nlmsg_new(rt6_nlmsg_size(rt), gfp_any()); - if (!skb) - goto errout; - - err = rt6_fill_node(net, skb, rt, NULL, NULL, 0, - event, info->portid, seq, 0, 0, nlm_flags); - if (err < 0) { - /* -EMSGSIZE implies BUG in rt6_nlmsg_size() */ - WARN_ON(err == -EMSGSIZE); - kfree_skb(skb); - goto errout; - } - rtnl_notify(skb, net, info->portid, RTNLGRP_IPV6_ROUTE, - info->nlh, gfp_any()); - return; -errout: - if (err < 0) - rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err); -} - -static int ip6_route_dev_notify(struct notifier_block *this, - unsigned long event, void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - struct net *net = dev_net(dev); - - if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) { - net->ipv6.ip6_null_entry->dst.dev = dev; - net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev); -#ifdef CONFIG_IPV6_MULTIPLE_TABLES - net->ipv6.ip6_prohibit_entry->dst.dev = dev; - net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev); - net->ipv6.ip6_blk_hole_entry->dst.dev = dev; - net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); -#endif - } - - return NOTIFY_OK; -} - -/* - * /proc - */ - -#ifdef CONFIG_PROC_FS - -static const struct file_operations ipv6_route_proc_fops = { - .owner = THIS_MODULE, - .open = ipv6_route_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -static int rt6_stats_seq_show(struct seq_file *seq, void *v) -{ - struct net *net = (struct net *)seq->private; - seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n", - net->ipv6.rt6_stats->fib_nodes, - net->ipv6.rt6_stats->fib_route_nodes, - net->ipv6.rt6_stats->fib_rt_alloc, - net->ipv6.rt6_stats->fib_rt_entries, - net->ipv6.rt6_stats->fib_rt_cache, - dst_entries_get_slow(&net->ipv6.ip6_dst_ops), - net->ipv6.rt6_stats->fib_discarded_routes); - - return 0; -} - -static int rt6_stats_seq_open(struct inode *inode, struct file *file) -{ - return single_open_net(inode, file, rt6_stats_seq_show); -} - -static const struct file_operations rt6_stats_seq_fops = { - .owner = THIS_MODULE, - .open = rt6_stats_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release_net, -}; -#endif /* CONFIG_PROC_FS */ - -#ifdef CONFIG_SYSCTL - -static -int ipv6_sysctl_rtcache_flush(struct ctl_table *ctl, int write, - void __user *buffer, size_t *lenp, loff_t *ppos) -{ - struct net *net; - int delay; - if (!write) - return -EINVAL; - - net = (struct net *)ctl->extra1; - delay = net->ipv6.sysctl.flush_delay; - proc_dointvec(ctl, write, buffer, lenp, ppos); - fib6_run_gc(delay <= 0 ? 0 : (unsigned long)delay, net, delay > 0); - return 0; -} - -struct ctl_table ipv6_route_table_template[] = { - { - .procname = "flush", - .data = &init_net.ipv6.sysctl.flush_delay, - .maxlen = sizeof(int), - .mode = 0200, - .proc_handler = ipv6_sysctl_rtcache_flush - }, - { - .procname = "gc_thresh", - .data = &ip6_dst_ops_template.gc_thresh, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "max_size", - .data = &init_net.ipv6.sysctl.ip6_rt_max_size, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "gc_min_interval", - .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "gc_timeout", - .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "gc_interval", - .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "gc_elasticity", - .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "mtu_expires", - .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "min_adv_mss", - .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "gc_min_interval_ms", - .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_ms_jiffies, - }, - { } -}; - -struct ctl_table * __net_init ipv6_route_sysctl_init(struct net *net) -{ - struct ctl_table *table; - - table = kmemdup(ipv6_route_table_template, - sizeof(ipv6_route_table_template), - GFP_KERNEL); - - if (table) { - table[0].data = &net->ipv6.sysctl.flush_delay; - table[0].extra1 = net; - table[1].data = &net->ipv6.ip6_dst_ops.gc_thresh; - table[2].data = &net->ipv6.sysctl.ip6_rt_max_size; - table[3].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; - table[4].data = &net->ipv6.sysctl.ip6_rt_gc_timeout; - table[5].data = &net->ipv6.sysctl.ip6_rt_gc_interval; - table[6].data = &net->ipv6.sysctl.ip6_rt_gc_elasticity; - table[7].data = &net->ipv6.sysctl.ip6_rt_mtu_expires; - table[8].data = &net->ipv6.sysctl.ip6_rt_min_advmss; - table[9].data = &net->ipv6.sysctl.ip6_rt_gc_min_interval; - - /* Don't export sysctls to unprivileged users */ - if (net->user_ns != &init_user_ns) - table[0].procname = NULL; - } - - return table; -} -#endif - -static int __net_init ip6_route_net_init(struct net *net) -{ - int ret = -ENOMEM; - - memcpy(&net->ipv6.ip6_dst_ops, &ip6_dst_ops_template, - sizeof(net->ipv6.ip6_dst_ops)); - - if (dst_entries_init(&net->ipv6.ip6_dst_ops) < 0) - goto out_ip6_dst_ops; - - net->ipv6.ip6_null_entry = kmemdup(&ip6_null_entry_template, - sizeof(*net->ipv6.ip6_null_entry), - GFP_KERNEL); - if (!net->ipv6.ip6_null_entry) - goto out_ip6_dst_entries; - net->ipv6.ip6_null_entry->dst.path = - (struct dst_entry *)net->ipv6.ip6_null_entry; - net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops; - dst_init_metrics(&net->ipv6.ip6_null_entry->dst, - ip6_template_metrics, true); - -#ifdef CONFIG_IPV6_MULTIPLE_TABLES - net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template, - sizeof(*net->ipv6.ip6_prohibit_entry), - GFP_KERNEL); - if (!net->ipv6.ip6_prohibit_entry) - goto out_ip6_null_entry; - net->ipv6.ip6_prohibit_entry->dst.path = - (struct dst_entry *)net->ipv6.ip6_prohibit_entry; - net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops; - dst_init_metrics(&net->ipv6.ip6_prohibit_entry->dst, - ip6_template_metrics, true); - - net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template, - sizeof(*net->ipv6.ip6_blk_hole_entry), - GFP_KERNEL); - if (!net->ipv6.ip6_blk_hole_entry) - goto out_ip6_prohibit_entry; - net->ipv6.ip6_blk_hole_entry->dst.path = - (struct dst_entry *)net->ipv6.ip6_blk_hole_entry; - net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops; - dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst, - ip6_template_metrics, true); -#endif - - net->ipv6.sysctl.flush_delay = 0; - net->ipv6.sysctl.ip6_rt_max_size = 4096; - net->ipv6.sysctl.ip6_rt_gc_min_interval = HZ / 2; - net->ipv6.sysctl.ip6_rt_gc_timeout = 60*HZ; - net->ipv6.sysctl.ip6_rt_gc_interval = 30*HZ; - net->ipv6.sysctl.ip6_rt_gc_elasticity = 9; - net->ipv6.sysctl.ip6_rt_mtu_expires = 10*60*HZ; - net->ipv6.sysctl.ip6_rt_min_advmss = IPV6_MIN_MTU - 20 - 40; - - net->ipv6.ip6_rt_gc_expire = 30*HZ; - - ret = 0; -out: - return ret; - -#ifdef CONFIG_IPV6_MULTIPLE_TABLES -out_ip6_prohibit_entry: - kfree(net->ipv6.ip6_prohibit_entry); -out_ip6_null_entry: - kfree(net->ipv6.ip6_null_entry); -#endif -out_ip6_dst_entries: - dst_entries_destroy(&net->ipv6.ip6_dst_ops); -out_ip6_dst_ops: - goto out; -} - -static void __net_exit ip6_route_net_exit(struct net *net) -{ - kfree(net->ipv6.ip6_null_entry); -#ifdef CONFIG_IPV6_MULTIPLE_TABLES - kfree(net->ipv6.ip6_prohibit_entry); - kfree(net->ipv6.ip6_blk_hole_entry); -#endif - dst_entries_destroy(&net->ipv6.ip6_dst_ops); -} - -static int __net_init ip6_route_net_init_late(struct net *net) -{ -#ifdef CONFIG_PROC_FS - proc_create("ipv6_route", 0, net->proc_net, &ipv6_route_proc_fops); - proc_create("rt6_stats", S_IRUGO, net->proc_net, &rt6_stats_seq_fops); -#endif - return 0; -} - -static void __net_exit ip6_route_net_exit_late(struct net *net) -{ -#ifdef CONFIG_PROC_FS - remove_proc_entry("ipv6_route", net->proc_net); - remove_proc_entry("rt6_stats", net->proc_net); -#endif -} - -static struct pernet_operations ip6_route_net_ops = { - .init = ip6_route_net_init, - .exit = ip6_route_net_exit, -}; - -static int __net_init ipv6_inetpeer_init(struct net *net) -{ - struct inet_peer_base *bp = kmalloc(sizeof(*bp), GFP_KERNEL); - - if (!bp) - return -ENOMEM; - inet_peer_base_init(bp); - net->ipv6.peers = bp; - return 0; -} - -static void __net_exit ipv6_inetpeer_exit(struct net *net) -{ - struct inet_peer_base *bp = net->ipv6.peers; - - net->ipv6.peers = NULL; - inetpeer_invalidate_tree(bp); - kfree(bp); -} - -static struct pernet_operations ipv6_inetpeer_ops = { - .init = ipv6_inetpeer_init, - .exit = ipv6_inetpeer_exit, -}; - -static struct pernet_operations ip6_route_net_late_ops = { - .init = ip6_route_net_init_late, - .exit = ip6_route_net_exit_late, -}; - -static struct notifier_block ip6_route_dev_notifier = { - .notifier_call = ip6_route_dev_notify, - .priority = 0, -}; - -int __init ip6_route_init(void) -{ - int ret; - int cpu; - - ret = -ENOMEM; - ip6_dst_ops_template.kmem_cachep = - kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0, - SLAB_HWCACHE_ALIGN, NULL); - if (!ip6_dst_ops_template.kmem_cachep) - goto out; - - ret = dst_entries_init(&ip6_dst_blackhole_ops); - if (ret) - goto out_kmem_cache; - - ret = register_pernet_subsys(&ipv6_inetpeer_ops); - if (ret) - goto out_dst_entries; - - ret = register_pernet_subsys(&ip6_route_net_ops); - if (ret) - goto out_register_inetpeer; - - ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep; - - /* Registering of the loopback is done before this portion of code, - * the loopback reference in rt6_info will not be taken, do it - * manually for init_net */ - init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev; - init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); - #ifdef CONFIG_IPV6_MULTIPLE_TABLES - init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev; - init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); - init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; - init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); - #endif - ret = fib6_init(); - if (ret) - goto out_register_subsys; - - ret = xfrm6_init(); - if (ret) - goto out_fib6_init; - - ret = fib6_rules_init(); - if (ret) - goto xfrm6_init; - - ret = register_pernet_subsys(&ip6_route_net_late_ops); - if (ret) - goto fib6_rules_init; - - ret = -ENOBUFS; - if (__rtnl_register(PF_INET6, RTM_NEWROUTE, inet6_rtm_newroute, NULL, NULL) || - __rtnl_register(PF_INET6, RTM_DELROUTE, inet6_rtm_delroute, NULL, NULL) || - __rtnl_register(PF_INET6, RTM_GETROUTE, inet6_rtm_getroute, NULL, NULL)) - goto out_register_late_subsys; - - ret = register_netdevice_notifier(&ip6_route_dev_notifier); - if (ret) - goto out_register_late_subsys; - - for_each_possible_cpu(cpu) { - struct uncached_list *ul = per_cpu_ptr(&rt6_uncached_list, cpu); - - INIT_LIST_HEAD(&ul->head); - spin_lock_init(&ul->lock); - } - -out: - return ret; - -out_register_late_subsys: - unregister_pernet_subsys(&ip6_route_net_late_ops); -fib6_rules_init: - fib6_rules_cleanup(); -xfrm6_init: - xfrm6_fini(); -out_fib6_init: - fib6_gc_cleanup(); -out_register_subsys: - unregister_pernet_subsys(&ip6_route_net_ops); -out_register_inetpeer: - unregister_pernet_subsys(&ipv6_inetpeer_ops); -out_dst_entries: - dst_entries_destroy(&ip6_dst_blackhole_ops); -out_kmem_cache: - kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep); - goto out; -} - -void ip6_route_cleanup(void) -{ - unregister_netdevice_notifier(&ip6_route_dev_notifier); - unregister_pernet_subsys(&ip6_route_net_late_ops); - fib6_rules_cleanup(); - xfrm6_fini(); - fib6_gc_cleanup(); - unregister_pernet_subsys(&ipv6_inetpeer_ops); - unregister_pernet_subsys(&ip6_route_net_ops); - dst_entries_destroy(&ip6_dst_blackhole_ops); - kmem_cache_destroy(ip6_dst_ops_template.kmem_cachep); -} diff --git a/src/linux/net/ipv6/sit.c b/src/linux/net/ipv6/sit.c deleted file mode 100644 index b1cdf80..0000000 --- a/src/linux/net/ipv6/sit.c +++ /dev/null @@ -1,1926 +0,0 @@ -/* - * IPv6 over IPv4 tunnel device - Simple Internet Transition (SIT) - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * Alexey Kuznetsov - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Changes: - * Roger Venning : 6to4 support - * Nate Thompson : 6to4 support - * Fred Templin : isatap support - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#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 -#include -#include -#include -#include -#include -#include - -/* - This version of net/ipv6/sit.c is cloned of net/ipv4/ip_gre.c - - For comments look at net/ipv4/ip_gre.c --ANK - */ - -#define IP6_SIT_HASH_SIZE 16 -#define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) - -static bool log_ecn_error = true; -module_param(log_ecn_error, bool, 0644); -MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN"); - -static int ipip6_tunnel_init(struct net_device *dev); -static void ipip6_tunnel_setup(struct net_device *dev); -static void ipip6_dev_free(struct net_device *dev); -static bool check_6rd(struct ip_tunnel *tunnel, const struct in6_addr *v6dst, - __be32 *v4dst); -static struct rtnl_link_ops sit_link_ops __read_mostly; - -static int sit_net_id __read_mostly; -struct sit_net { - struct ip_tunnel __rcu *tunnels_r_l[IP6_SIT_HASH_SIZE]; - struct ip_tunnel __rcu *tunnels_r[IP6_SIT_HASH_SIZE]; - struct ip_tunnel __rcu *tunnels_l[IP6_SIT_HASH_SIZE]; - struct ip_tunnel __rcu *tunnels_wc[1]; - struct ip_tunnel __rcu **tunnels[4]; - - struct net_device *fb_tunnel_dev; -}; - -/* - * Must be invoked with rcu_read_lock - */ -static struct ip_tunnel *ipip6_tunnel_lookup(struct net *net, - struct net_device *dev, __be32 remote, __be32 local) -{ - unsigned int h0 = HASH(remote); - unsigned int h1 = HASH(local); - struct ip_tunnel *t; - struct sit_net *sitn = net_generic(net, sit_net_id); - - for_each_ip_tunnel_rcu(t, sitn->tunnels_r_l[h0 ^ h1]) { - if (local == t->parms.iph.saddr && - remote == t->parms.iph.daddr && - (!dev || !t->parms.link || dev->ifindex == t->parms.link) && - (t->dev->flags & IFF_UP)) - return t; - } - for_each_ip_tunnel_rcu(t, sitn->tunnels_r[h0]) { - if (remote == t->parms.iph.daddr && - (!dev || !t->parms.link || dev->ifindex == t->parms.link) && - (t->dev->flags & IFF_UP)) - return t; - } - for_each_ip_tunnel_rcu(t, sitn->tunnels_l[h1]) { - if (local == t->parms.iph.saddr && - (!dev || !t->parms.link || dev->ifindex == t->parms.link) && - (t->dev->flags & IFF_UP)) - return t; - } - t = rcu_dereference(sitn->tunnels_wc[0]); - if (t && (t->dev->flags & IFF_UP)) - return t; - return NULL; -} - -static struct ip_tunnel __rcu **__ipip6_bucket(struct sit_net *sitn, - struct ip_tunnel_parm *parms) -{ - __be32 remote = parms->iph.daddr; - __be32 local = parms->iph.saddr; - unsigned int h = 0; - int prio = 0; - - if (remote) { - prio |= 2; - h ^= HASH(remote); - } - if (local) { - prio |= 1; - h ^= HASH(local); - } - return &sitn->tunnels[prio][h]; -} - -static inline struct ip_tunnel __rcu **ipip6_bucket(struct sit_net *sitn, - struct ip_tunnel *t) -{ - return __ipip6_bucket(sitn, &t->parms); -} - -static void ipip6_tunnel_unlink(struct sit_net *sitn, struct ip_tunnel *t) -{ - struct ip_tunnel __rcu **tp; - struct ip_tunnel *iter; - - for (tp = ipip6_bucket(sitn, t); - (iter = rtnl_dereference(*tp)) != NULL; - tp = &iter->next) { - if (t == iter) { - rcu_assign_pointer(*tp, t->next); - break; - } - } -} - -static void ipip6_tunnel_link(struct sit_net *sitn, struct ip_tunnel *t) -{ - struct ip_tunnel __rcu **tp = ipip6_bucket(sitn, t); - - rcu_assign_pointer(t->next, rtnl_dereference(*tp)); - rcu_assign_pointer(*tp, t); -} - -static void ipip6_tunnel_clone_6rd(struct net_device *dev, struct sit_net *sitn) -{ -#ifdef CONFIG_IPV6_SIT_6RD - struct ip_tunnel *t = netdev_priv(dev); - - if (t->dev == sitn->fb_tunnel_dev) { - ipv6_addr_set(&t->ip6rd.prefix, htonl(0x20020000), 0, 0, 0); - t->ip6rd.relay_prefix = 0; - t->ip6rd.prefixlen = 16; - t->ip6rd.relay_prefixlen = 0; - } else { - struct ip_tunnel *t0 = netdev_priv(sitn->fb_tunnel_dev); - memcpy(&t->ip6rd, &t0->ip6rd, sizeof(t->ip6rd)); - } -#endif -} - -static int ipip6_tunnel_create(struct net_device *dev) -{ - struct ip_tunnel *t = netdev_priv(dev); - struct net *net = dev_net(dev); - struct sit_net *sitn = net_generic(net, sit_net_id); - int err; - - memcpy(dev->dev_addr, &t->parms.iph.saddr, 4); - memcpy(dev->broadcast, &t->parms.iph.daddr, 4); - - if ((__force u16)t->parms.i_flags & SIT_ISATAP) - dev->priv_flags |= IFF_ISATAP; - - dev->rtnl_link_ops = &sit_link_ops; - - err = register_netdevice(dev); - if (err < 0) - goto out; - - ipip6_tunnel_clone_6rd(dev, sitn); - - dev_hold(dev); - - ipip6_tunnel_link(sitn, t); - return 0; - -out: - return err; -} - -static struct ip_tunnel *ipip6_tunnel_locate(struct net *net, - struct ip_tunnel_parm *parms, int create) -{ - __be32 remote = parms->iph.daddr; - __be32 local = parms->iph.saddr; - struct ip_tunnel *t, *nt; - struct ip_tunnel __rcu **tp; - struct net_device *dev; - char name[IFNAMSIZ]; - struct sit_net *sitn = net_generic(net, sit_net_id); - - for (tp = __ipip6_bucket(sitn, parms); - (t = rtnl_dereference(*tp)) != NULL; - tp = &t->next) { - if (local == t->parms.iph.saddr && - remote == t->parms.iph.daddr && - parms->link == t->parms.link) { - if (create) - return NULL; - else - return t; - } - } - if (!create) - goto failed; - - if (parms->name[0]) - strlcpy(name, parms->name, IFNAMSIZ); - else - strcpy(name, "sit%d"); - - dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, - ipip6_tunnel_setup); - if (!dev) - return NULL; - - dev_net_set(dev, net); - - nt = netdev_priv(dev); - - nt->parms = *parms; - if (ipip6_tunnel_create(dev) < 0) - goto failed_free; - - return nt; - -failed_free: - ipip6_dev_free(dev); -failed: - return NULL; -} - -#define for_each_prl_rcu(start) \ - for (prl = rcu_dereference(start); \ - prl; \ - prl = rcu_dereference(prl->next)) - -static struct ip_tunnel_prl_entry * -__ipip6_tunnel_locate_prl(struct ip_tunnel *t, __be32 addr) -{ - struct ip_tunnel_prl_entry *prl; - - for_each_prl_rcu(t->prl) - if (prl->addr == addr) - break; - return prl; - -} - -static int ipip6_tunnel_get_prl(struct ip_tunnel *t, - struct ip_tunnel_prl __user *a) -{ - struct ip_tunnel_prl kprl, *kp; - struct ip_tunnel_prl_entry *prl; - unsigned int cmax, c = 0, ca, len; - int ret = 0; - - if (copy_from_user(&kprl, a, sizeof(kprl))) - return -EFAULT; - cmax = kprl.datalen / sizeof(kprl); - if (cmax > 1 && kprl.addr != htonl(INADDR_ANY)) - cmax = 1; - - /* For simple GET or for root users, - * we try harder to allocate. - */ - kp = (cmax <= 1 || capable(CAP_NET_ADMIN)) ? - kcalloc(cmax, sizeof(*kp), GFP_KERNEL) : - NULL; - - rcu_read_lock(); - - ca = t->prl_count < cmax ? t->prl_count : cmax; - - if (!kp) { - /* We don't try hard to allocate much memory for - * non-root users. - * For root users, retry allocating enough memory for - * the answer. - */ - kp = kcalloc(ca, sizeof(*kp), GFP_ATOMIC); - if (!kp) { - ret = -ENOMEM; - goto out; - } - } - - c = 0; - for_each_prl_rcu(t->prl) { - if (c >= cmax) - break; - if (kprl.addr != htonl(INADDR_ANY) && prl->addr != kprl.addr) - continue; - kp[c].addr = prl->addr; - kp[c].flags = prl->flags; - c++; - if (kprl.addr != htonl(INADDR_ANY)) - break; - } -out: - rcu_read_unlock(); - - len = sizeof(*kp) * c; - ret = 0; - if ((len && copy_to_user(a + 1, kp, len)) || put_user(len, &a->datalen)) - ret = -EFAULT; - - kfree(kp); - - return ret; -} - -static int -ipip6_tunnel_add_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a, int chg) -{ - struct ip_tunnel_prl_entry *p; - int err = 0; - - if (a->addr == htonl(INADDR_ANY)) - return -EINVAL; - - ASSERT_RTNL(); - - for (p = rtnl_dereference(t->prl); p; p = rtnl_dereference(p->next)) { - if (p->addr == a->addr) { - if (chg) { - p->flags = a->flags; - goto out; - } - err = -EEXIST; - goto out; - } - } - - if (chg) { - err = -ENXIO; - goto out; - } - - p = kzalloc(sizeof(struct ip_tunnel_prl_entry), GFP_KERNEL); - if (!p) { - err = -ENOBUFS; - goto out; - } - - p->next = t->prl; - p->addr = a->addr; - p->flags = a->flags; - t->prl_count++; - rcu_assign_pointer(t->prl, p); -out: - return err; -} - -static void prl_list_destroy_rcu(struct rcu_head *head) -{ - struct ip_tunnel_prl_entry *p, *n; - - p = container_of(head, struct ip_tunnel_prl_entry, rcu_head); - do { - n = rcu_dereference_protected(p->next, 1); - kfree(p); - p = n; - } while (p); -} - -static int -ipip6_tunnel_del_prl(struct ip_tunnel *t, struct ip_tunnel_prl *a) -{ - struct ip_tunnel_prl_entry *x; - struct ip_tunnel_prl_entry __rcu **p; - int err = 0; - - ASSERT_RTNL(); - - if (a && a->addr != htonl(INADDR_ANY)) { - for (p = &t->prl; - (x = rtnl_dereference(*p)) != NULL; - p = &x->next) { - if (x->addr == a->addr) { - *p = x->next; - kfree_rcu(x, rcu_head); - t->prl_count--; - goto out; - } - } - err = -ENXIO; - } else { - x = rtnl_dereference(t->prl); - if (x) { - t->prl_count = 0; - call_rcu(&x->rcu_head, prl_list_destroy_rcu); - t->prl = NULL; - } - } -out: - return err; -} - -static int -isatap_chksrc(struct sk_buff *skb, const struct iphdr *iph, struct ip_tunnel *t) -{ - struct ip_tunnel_prl_entry *p; - int ok = 1; - - rcu_read_lock(); - p = __ipip6_tunnel_locate_prl(t, iph->saddr); - if (p) { - if (p->flags & PRL_DEFAULT) - skb->ndisc_nodetype = NDISC_NODETYPE_DEFAULT; - else - skb->ndisc_nodetype = NDISC_NODETYPE_NODEFAULT; - } else { - const struct in6_addr *addr6 = &ipv6_hdr(skb)->saddr; - - if (ipv6_addr_is_isatap(addr6) && - (addr6->s6_addr32[3] == iph->saddr) && - ipv6_chk_prefix(addr6, t->dev)) - skb->ndisc_nodetype = NDISC_NODETYPE_HOST; - else - ok = 0; - } - rcu_read_unlock(); - return ok; -} - -static void ipip6_tunnel_uninit(struct net_device *dev) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - struct sit_net *sitn = net_generic(tunnel->net, sit_net_id); - - if (dev == sitn->fb_tunnel_dev) { - RCU_INIT_POINTER(sitn->tunnels_wc[0], NULL); - } else { - ipip6_tunnel_unlink(sitn, tunnel); - ipip6_tunnel_del_prl(tunnel, NULL); - } - dst_cache_reset(&tunnel->dst_cache); - dev_put(dev); -} - -static int ipip6_err(struct sk_buff *skb, u32 info) -{ - const struct iphdr *iph = (const struct iphdr *)skb->data; - const int type = icmp_hdr(skb)->type; - const int code = icmp_hdr(skb)->code; - unsigned int data_len = 0; - struct ip_tunnel *t; - int err; - - switch (type) { - default: - case ICMP_PARAMETERPROB: - return 0; - - case ICMP_DEST_UNREACH: - switch (code) { - case ICMP_SR_FAILED: - /* Impossible event. */ - return 0; - default: - /* All others are translated to HOST_UNREACH. - rfc2003 contains "deep thoughts" about NET_UNREACH, - I believe they are just ether pollution. --ANK - */ - break; - } - break; - case ICMP_TIME_EXCEEDED: - if (code != ICMP_EXC_TTL) - return 0; - data_len = icmp_hdr(skb)->un.reserved[1] * 4; /* RFC 4884 4.1 */ - break; - case ICMP_REDIRECT: - break; - } - - err = -ENOENT; - - t = ipip6_tunnel_lookup(dev_net(skb->dev), - skb->dev, - iph->daddr, - iph->saddr); - if (!t) - goto out; - - if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { - ipv4_update_pmtu(skb, dev_net(skb->dev), info, - t->parms.link, 0, iph->protocol, 0); - err = 0; - goto out; - } - if (type == ICMP_REDIRECT) { - ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0, - iph->protocol, 0); - err = 0; - goto out; - } - - err = 0; - if (!ip6_err_gen_icmpv6_unreach(skb, iph->ihl * 4, type, data_len)) - goto out; - - if (t->parms.iph.daddr == 0) - goto out; - - if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) - goto out; - - if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO)) - t->err_count++; - else - t->err_count = 1; - t->err_time = jiffies; -out: - return err; -} - -static inline bool is_spoofed_6rd(struct ip_tunnel *tunnel, const __be32 v4addr, - const struct in6_addr *v6addr) -{ - __be32 v4embed = 0; - if (check_6rd(tunnel, v6addr, &v4embed) && v4addr != v4embed) - return true; - return false; -} - -/* Checks if an address matches an address on the tunnel interface. - * Used to detect the NAT of proto 41 packets and let them pass spoofing test. - * Long story: - * This function is called after we considered the packet as spoofed - * in is_spoofed_6rd. - * We may have a router that is doing NAT for proto 41 packets - * for an internal station. Destination a.a.a.a/PREFIX:bbbb:bbbb - * will be translated to n.n.n.n/PREFIX:bbbb:bbbb. And is_spoofed_6rd - * function will return true, dropping the packet. - * But, we can still check if is spoofed against the IP - * addresses associated with the interface. - */ -static bool only_dnatted(const struct ip_tunnel *tunnel, - const struct in6_addr *v6dst) -{ - int prefix_len; - -#ifdef CONFIG_IPV6_SIT_6RD - prefix_len = tunnel->ip6rd.prefixlen + 32 - - tunnel->ip6rd.relay_prefixlen; -#else - prefix_len = 48; -#endif - return ipv6_chk_custom_prefix(v6dst, prefix_len, tunnel->dev); -} - -/* Returns true if a packet is spoofed */ -static bool packet_is_spoofed(struct sk_buff *skb, - const struct iphdr *iph, - struct ip_tunnel *tunnel) -{ - const struct ipv6hdr *ipv6h; - - if (tunnel->dev->priv_flags & IFF_ISATAP) { - if (!isatap_chksrc(skb, iph, tunnel)) - return true; - - return false; - } - - if (tunnel->dev->flags & IFF_POINTOPOINT) - return false; - - ipv6h = ipv6_hdr(skb); - - if (unlikely(is_spoofed_6rd(tunnel, iph->saddr, &ipv6h->saddr))) { - net_warn_ratelimited("Src spoofed %pI4/%pI6c -> %pI4/%pI6c\n", - &iph->saddr, &ipv6h->saddr, - &iph->daddr, &ipv6h->daddr); - return true; - } - - if (likely(!is_spoofed_6rd(tunnel, iph->daddr, &ipv6h->daddr))) - return false; - - if (only_dnatted(tunnel, &ipv6h->daddr)) - return false; - - net_warn_ratelimited("Dst spoofed %pI4/%pI6c -> %pI4/%pI6c\n", - &iph->saddr, &ipv6h->saddr, - &iph->daddr, &ipv6h->daddr); - return true; -} - -static int ipip6_rcv(struct sk_buff *skb) -{ - const struct iphdr *iph = ip_hdr(skb); - struct ip_tunnel *tunnel; - int err; - - tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, - iph->saddr, iph->daddr); - if (tunnel) { - struct pcpu_sw_netstats *tstats; - - if (tunnel->parms.iph.protocol != IPPROTO_IPV6 && - tunnel->parms.iph.protocol != 0) - goto out; - - skb->mac_header = skb->network_header; - skb_reset_network_header(skb); - IPCB(skb)->flags = 0; - skb->dev = tunnel->dev; - - if (packet_is_spoofed(skb, iph, tunnel)) { - tunnel->dev->stats.rx_errors++; - goto out; - } - - if (iptunnel_pull_header(skb, 0, htons(ETH_P_IPV6), - !net_eq(tunnel->net, dev_net(tunnel->dev)))) - goto out; - - err = IP_ECN_decapsulate(iph, skb); - if (unlikely(err)) { - if (log_ecn_error) - net_info_ratelimited("non-ECT from %pI4 with TOS=%#x\n", - &iph->saddr, iph->tos); - if (err > 1) { - ++tunnel->dev->stats.rx_frame_errors; - ++tunnel->dev->stats.rx_errors; - goto out; - } - } - - tstats = this_cpu_ptr(tunnel->dev->tstats); - u64_stats_update_begin(&tstats->syncp); - tstats->rx_packets++; - tstats->rx_bytes += skb->len; - u64_stats_update_end(&tstats->syncp); - - netif_rx(skb); - - return 0; - } - - /* no tunnel matched, let upstream know, ipsec may handle it */ - return 1; -out: - kfree_skb(skb); - return 0; -} - -static const struct tnl_ptk_info ipip_tpi = { - /* no tunnel info required for ipip. */ - .proto = htons(ETH_P_IP), -}; - -#if IS_ENABLED(CONFIG_MPLS) -static const struct tnl_ptk_info mplsip_tpi = { - /* no tunnel info required for mplsip. */ - .proto = htons(ETH_P_MPLS_UC), -}; -#endif - -static int sit_tunnel_rcv(struct sk_buff *skb, u8 ipproto) -{ - const struct iphdr *iph; - struct ip_tunnel *tunnel; - - iph = ip_hdr(skb); - tunnel = ipip6_tunnel_lookup(dev_net(skb->dev), skb->dev, - iph->saddr, iph->daddr); - if (tunnel) { - const struct tnl_ptk_info *tpi; - - if (tunnel->parms.iph.protocol != ipproto && - tunnel->parms.iph.protocol != 0) - goto drop; - - if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) - goto drop; -#if IS_ENABLED(CONFIG_MPLS) - if (ipproto == IPPROTO_MPLS) - tpi = &mplsip_tpi; - else -#endif - tpi = &ipip_tpi; - if (iptunnel_pull_header(skb, 0, tpi->proto, false)) - goto drop; - return ip_tunnel_rcv(tunnel, skb, tpi, NULL, log_ecn_error); - } - - return 1; - -drop: - kfree_skb(skb); - return 0; -} - -static int ipip_rcv(struct sk_buff *skb) -{ - return sit_tunnel_rcv(skb, IPPROTO_IPIP); -} - -#if IS_ENABLED(CONFIG_MPLS) -static int mplsip_rcv(struct sk_buff *skb) -{ - return sit_tunnel_rcv(skb, IPPROTO_MPLS); -} -#endif - -/* - * If the IPv6 address comes from 6rd / 6to4 (RFC 3056) addr space this function - * stores the embedded IPv4 address in v4dst and returns true. - */ -static bool check_6rd(struct ip_tunnel *tunnel, const struct in6_addr *v6dst, - __be32 *v4dst) -{ -#ifdef CONFIG_IPV6_SIT_6RD - if (ipv6_prefix_equal(v6dst, &tunnel->ip6rd.prefix, - tunnel->ip6rd.prefixlen)) { - unsigned int pbw0, pbi0; - int pbi1; - u32 d; - - pbw0 = tunnel->ip6rd.prefixlen >> 5; - pbi0 = tunnel->ip6rd.prefixlen & 0x1f; - - d = (ntohl(v6dst->s6_addr32[pbw0]) << pbi0) >> - tunnel->ip6rd.relay_prefixlen; - - pbi1 = pbi0 - tunnel->ip6rd.relay_prefixlen; - if (pbi1 > 0) - d |= ntohl(v6dst->s6_addr32[pbw0 + 1]) >> - (32 - pbi1); - - *v4dst = tunnel->ip6rd.relay_prefix | htonl(d); - return true; - } -#else - if (v6dst->s6_addr16[0] == htons(0x2002)) { - /* 6to4 v6 addr has 16 bits prefix, 32 v4addr, 16 SLA, ... */ - memcpy(v4dst, &v6dst->s6_addr16[1], 4); - return true; - } -#endif - return false; -} - -static inline __be32 try_6rd(struct ip_tunnel *tunnel, - const struct in6_addr *v6dst) -{ - __be32 dst = 0; - check_6rd(tunnel, v6dst, &dst); - return dst; -} - -/* - * This function assumes it is being called from dev_queue_xmit() - * and that skb is filled properly by that function. - */ - -static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - const struct iphdr *tiph = &tunnel->parms.iph; - const struct ipv6hdr *iph6 = ipv6_hdr(skb); - u8 tos = tunnel->parms.iph.tos; - __be16 df = tiph->frag_off; - struct rtable *rt; /* Route to the other host */ - struct net_device *tdev; /* Device to other host */ - unsigned int max_headroom; /* The extra header space needed */ - __be32 dst = tiph->daddr; - struct flowi4 fl4; - int mtu; - const struct in6_addr *addr6; - int addr_type; - u8 ttl; - u8 protocol = IPPROTO_IPV6; - int t_hlen = tunnel->hlen + sizeof(struct iphdr); - - if (tos == 1) - tos = ipv6_get_dsfield(iph6); - - /* ISATAP (RFC4214) - must come before 6to4 */ - if (dev->priv_flags & IFF_ISATAP) { - struct neighbour *neigh = NULL; - bool do_tx_error = false; - - if (skb_dst(skb)) - neigh = dst_neigh_lookup(skb_dst(skb), &iph6->daddr); - - if (!neigh) { - net_dbg_ratelimited("nexthop == NULL\n"); - goto tx_error; - } - - addr6 = (const struct in6_addr *)&neigh->primary_key; - addr_type = ipv6_addr_type(addr6); - - if ((addr_type & IPV6_ADDR_UNICAST) && - ipv6_addr_is_isatap(addr6)) - dst = addr6->s6_addr32[3]; - else - do_tx_error = true; - - neigh_release(neigh); - if (do_tx_error) - goto tx_error; - } - - if (!dst) - dst = try_6rd(tunnel, &iph6->daddr); - - if (!dst) { - struct neighbour *neigh = NULL; - bool do_tx_error = false; - - if (skb_dst(skb)) - neigh = dst_neigh_lookup(skb_dst(skb), &iph6->daddr); - - if (!neigh) { - net_dbg_ratelimited("nexthop == NULL\n"); - goto tx_error; - } - - addr6 = (const struct in6_addr *)&neigh->primary_key; - addr_type = ipv6_addr_type(addr6); - - if (addr_type == IPV6_ADDR_ANY) { - addr6 = &ipv6_hdr(skb)->daddr; - addr_type = ipv6_addr_type(addr6); - } - - if ((addr_type & IPV6_ADDR_COMPATv4) != 0) - dst = addr6->s6_addr32[3]; - else - do_tx_error = true; - - neigh_release(neigh); - if (do_tx_error) - goto tx_error; - } - - rt = ip_route_output_ports(tunnel->net, &fl4, NULL, - dst, tiph->saddr, - 0, 0, - IPPROTO_IPV6, RT_TOS(tos), - tunnel->parms.link); - if (IS_ERR(rt)) { - dev->stats.tx_carrier_errors++; - goto tx_error_icmp; - } - if (rt->rt_type != RTN_UNICAST) { - ip_rt_put(rt); - dev->stats.tx_carrier_errors++; - goto tx_error_icmp; - } - tdev = rt->dst.dev; - - if (tdev == dev) { - ip_rt_put(rt); - dev->stats.collisions++; - goto tx_error; - } - - if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4)) { - ip_rt_put(rt); - goto tx_error; - } - - if (df) { - mtu = dst_mtu(&rt->dst) - t_hlen; - - if (mtu < 68) { - dev->stats.collisions++; - ip_rt_put(rt); - goto tx_error; - } - - if (mtu < IPV6_MIN_MTU) { - mtu = IPV6_MIN_MTU; - df = 0; - } - - if (tunnel->parms.iph.daddr && skb_dst(skb)) - skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); - - if (skb->len > mtu && !skb_is_gso(skb)) { - icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); - ip_rt_put(rt); - goto tx_error; - } - } - - if (tunnel->err_count > 0) { - if (time_before(jiffies, - tunnel->err_time + IPTUNNEL_ERR_TIMEO)) { - tunnel->err_count--; - dst_link_failure(skb); - } else - tunnel->err_count = 0; - } - - /* - * Okay, now see if we can stuff it in the buffer as-is. - */ - max_headroom = LL_RESERVED_SPACE(tdev) + t_hlen; - - if (skb_headroom(skb) < max_headroom || skb_shared(skb) || - (skb_cloned(skb) && !skb_clone_writable(skb, 0))) { - struct sk_buff *new_skb = skb_realloc_headroom(skb, max_headroom); - if (!new_skb) { - ip_rt_put(rt); - dev->stats.tx_dropped++; - kfree_skb(skb); - return NETDEV_TX_OK; - } - if (skb->sk) - skb_set_owner_w(new_skb, skb->sk); - dev_kfree_skb(skb); - skb = new_skb; - iph6 = ipv6_hdr(skb); - } - ttl = tiph->ttl; - if (ttl == 0) - ttl = iph6->hop_limit; - tos = INET_ECN_encapsulate(tos, ipv6_get_dsfield(iph6)); - - if (ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0) { - ip_rt_put(rt); - goto tx_error; - } - - skb_set_inner_ipproto(skb, IPPROTO_IPV6); - - iptunnel_xmit(NULL, rt, skb, fl4.saddr, fl4.daddr, protocol, tos, ttl, - df, !net_eq(tunnel->net, dev_net(dev))); - return NETDEV_TX_OK; - -tx_error_icmp: - dst_link_failure(skb); -tx_error: - kfree_skb(skb); - dev->stats.tx_errors++; - return NETDEV_TX_OK; -} - -static netdev_tx_t sit_tunnel_xmit__(struct sk_buff *skb, - struct net_device *dev, u8 ipproto) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - const struct iphdr *tiph = &tunnel->parms.iph; - - if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP4)) - goto tx_error; - - skb_set_inner_ipproto(skb, ipproto); - - ip_tunnel_xmit(skb, dev, tiph, ipproto); - return NETDEV_TX_OK; -tx_error: - kfree_skb(skb); - dev->stats.tx_errors++; - return NETDEV_TX_OK; -} - -static netdev_tx_t sit_tunnel_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - switch (skb->protocol) { - case htons(ETH_P_IP): - sit_tunnel_xmit__(skb, dev, IPPROTO_IPIP); - break; - case htons(ETH_P_IPV6): - ipip6_tunnel_xmit(skb, dev); - break; -#if IS_ENABLED(CONFIG_MPLS) - case htons(ETH_P_MPLS_UC): - sit_tunnel_xmit__(skb, dev, IPPROTO_MPLS); - break; -#endif - default: - goto tx_err; - } - - return NETDEV_TX_OK; - -tx_err: - dev->stats.tx_errors++; - kfree_skb(skb); - return NETDEV_TX_OK; - -} - -static void ipip6_tunnel_bind_dev(struct net_device *dev) -{ - struct net_device *tdev = NULL; - struct ip_tunnel *tunnel; - const struct iphdr *iph; - struct flowi4 fl4; - - tunnel = netdev_priv(dev); - iph = &tunnel->parms.iph; - - if (iph->daddr) { - struct rtable *rt = ip_route_output_ports(tunnel->net, &fl4, - NULL, - iph->daddr, iph->saddr, - 0, 0, - IPPROTO_IPV6, - RT_TOS(iph->tos), - tunnel->parms.link); - - if (!IS_ERR(rt)) { - tdev = rt->dst.dev; - ip_rt_put(rt); - } - dev->flags |= IFF_POINTOPOINT; - } - - if (!tdev && tunnel->parms.link) - tdev = __dev_get_by_index(tunnel->net, tunnel->parms.link); - - if (tdev) { - int t_hlen = tunnel->hlen + sizeof(struct iphdr); - - dev->hard_header_len = tdev->hard_header_len + sizeof(struct iphdr); - dev->mtu = tdev->mtu - t_hlen; - if (dev->mtu < IPV6_MIN_MTU) - dev->mtu = IPV6_MIN_MTU; - } -} - -static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p) -{ - struct net *net = t->net; - struct sit_net *sitn = net_generic(net, sit_net_id); - - ipip6_tunnel_unlink(sitn, t); - synchronize_net(); - t->parms.iph.saddr = p->iph.saddr; - t->parms.iph.daddr = p->iph.daddr; - memcpy(t->dev->dev_addr, &p->iph.saddr, 4); - memcpy(t->dev->broadcast, &p->iph.daddr, 4); - ipip6_tunnel_link(sitn, t); - t->parms.iph.ttl = p->iph.ttl; - t->parms.iph.tos = p->iph.tos; - if (t->parms.link != p->link) { - t->parms.link = p->link; - ipip6_tunnel_bind_dev(t->dev); - } - dst_cache_reset(&t->dst_cache); - netdev_state_change(t->dev); -} - -#ifdef CONFIG_IPV6_SIT_6RD -static int ipip6_tunnel_update_6rd(struct ip_tunnel *t, - struct ip_tunnel_6rd *ip6rd) -{ - struct in6_addr prefix; - __be32 relay_prefix; - - if (ip6rd->relay_prefixlen > 32 || - ip6rd->prefixlen + (32 - ip6rd->relay_prefixlen) > 64) - return -EINVAL; - - ipv6_addr_prefix(&prefix, &ip6rd->prefix, ip6rd->prefixlen); - if (!ipv6_addr_equal(&prefix, &ip6rd->prefix)) - return -EINVAL; - if (ip6rd->relay_prefixlen) - relay_prefix = ip6rd->relay_prefix & - htonl(0xffffffffUL << - (32 - ip6rd->relay_prefixlen)); - else - relay_prefix = 0; - if (relay_prefix != ip6rd->relay_prefix) - return -EINVAL; - - t->ip6rd.prefix = prefix; - t->ip6rd.relay_prefix = relay_prefix; - t->ip6rd.prefixlen = ip6rd->prefixlen; - t->ip6rd.relay_prefixlen = ip6rd->relay_prefixlen; - dst_cache_reset(&t->dst_cache); - netdev_state_change(t->dev); - return 0; -} -#endif - -static bool ipip6_valid_ip_proto(u8 ipproto) -{ - return ipproto == IPPROTO_IPV6 || - ipproto == IPPROTO_IPIP || -#if IS_ENABLED(CONFIG_MPLS) - ipproto == IPPROTO_MPLS || -#endif - ipproto == 0; -} - -static int -ipip6_tunnel_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - int err = 0; - struct ip_tunnel_parm p; - struct ip_tunnel_prl prl; - struct ip_tunnel *t = netdev_priv(dev); - struct net *net = t->net; - struct sit_net *sitn = net_generic(net, sit_net_id); -#ifdef CONFIG_IPV6_SIT_6RD - struct ip_tunnel_6rd ip6rd; -#endif - - switch (cmd) { - case SIOCGETTUNNEL: -#ifdef CONFIG_IPV6_SIT_6RD - case SIOCGET6RD: -#endif - if (dev == sitn->fb_tunnel_dev) { - if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { - err = -EFAULT; - break; - } - t = ipip6_tunnel_locate(net, &p, 0); - if (!t) - t = netdev_priv(dev); - } - - err = -EFAULT; - if (cmd == SIOCGETTUNNEL) { - memcpy(&p, &t->parms, sizeof(p)); - if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, - sizeof(p))) - goto done; -#ifdef CONFIG_IPV6_SIT_6RD - } else { - ip6rd.prefix = t->ip6rd.prefix; - ip6rd.relay_prefix = t->ip6rd.relay_prefix; - ip6rd.prefixlen = t->ip6rd.prefixlen; - ip6rd.relay_prefixlen = t->ip6rd.relay_prefixlen; - if (copy_to_user(ifr->ifr_ifru.ifru_data, &ip6rd, - sizeof(ip6rd))) - goto done; -#endif - } - err = 0; - break; - - case SIOCADDTUNNEL: - case SIOCCHGTUNNEL: - err = -EPERM; - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - goto done; - - err = -EFAULT; - if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) - goto done; - - err = -EINVAL; - if (!ipip6_valid_ip_proto(p.iph.protocol)) - goto done; - if (p.iph.version != 4 || - p.iph.ihl != 5 || (p.iph.frag_off&htons(~IP_DF))) - goto done; - if (p.iph.ttl) - p.iph.frag_off |= htons(IP_DF); - - t = ipip6_tunnel_locate(net, &p, cmd == SIOCADDTUNNEL); - - if (dev != sitn->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { - if (t) { - if (t->dev != dev) { - err = -EEXIST; - break; - } - } else { - if (((dev->flags&IFF_POINTOPOINT) && !p.iph.daddr) || - (!(dev->flags&IFF_POINTOPOINT) && p.iph.daddr)) { - err = -EINVAL; - break; - } - t = netdev_priv(dev); - } - - ipip6_tunnel_update(t, &p); - } - - if (t) { - err = 0; - if (copy_to_user(ifr->ifr_ifru.ifru_data, &t->parms, sizeof(p))) - err = -EFAULT; - } else - err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT); - break; - - case SIOCDELTUNNEL: - err = -EPERM; - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - goto done; - - if (dev == sitn->fb_tunnel_dev) { - err = -EFAULT; - if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) - goto done; - err = -ENOENT; - t = ipip6_tunnel_locate(net, &p, 0); - if (!t) - goto done; - err = -EPERM; - if (t == netdev_priv(sitn->fb_tunnel_dev)) - goto done; - dev = t->dev; - } - unregister_netdevice(dev); - err = 0; - break; - - case SIOCGETPRL: - err = -EINVAL; - if (dev == sitn->fb_tunnel_dev) - goto done; - err = ipip6_tunnel_get_prl(t, ifr->ifr_ifru.ifru_data); - break; - - case SIOCADDPRL: - case SIOCDELPRL: - case SIOCCHGPRL: - err = -EPERM; - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - goto done; - err = -EINVAL; - if (dev == sitn->fb_tunnel_dev) - goto done; - err = -EFAULT; - if (copy_from_user(&prl, ifr->ifr_ifru.ifru_data, sizeof(prl))) - goto done; - - switch (cmd) { - case SIOCDELPRL: - err = ipip6_tunnel_del_prl(t, &prl); - break; - case SIOCADDPRL: - case SIOCCHGPRL: - err = ipip6_tunnel_add_prl(t, &prl, cmd == SIOCCHGPRL); - break; - } - dst_cache_reset(&t->dst_cache); - netdev_state_change(dev); - break; - -#ifdef CONFIG_IPV6_SIT_6RD - case SIOCADD6RD: - case SIOCCHG6RD: - case SIOCDEL6RD: - err = -EPERM; - if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) - goto done; - - err = -EFAULT; - if (copy_from_user(&ip6rd, ifr->ifr_ifru.ifru_data, - sizeof(ip6rd))) - goto done; - - if (cmd != SIOCDEL6RD) { - err = ipip6_tunnel_update_6rd(t, &ip6rd); - if (err < 0) - goto done; - } else - ipip6_tunnel_clone_6rd(dev, sitn); - - err = 0; - break; -#endif - - default: - err = -EINVAL; - } - -done: - return err; -} - -static int ipip6_tunnel_change_mtu(struct net_device *dev, int new_mtu) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - int t_hlen = tunnel->hlen + sizeof(struct iphdr); - - if (new_mtu < IPV6_MIN_MTU || new_mtu > 0xFFF8 - t_hlen) - return -EINVAL; - dev->mtu = new_mtu; - return 0; -} - -static const struct net_device_ops ipip6_netdev_ops = { - .ndo_init = ipip6_tunnel_init, - .ndo_uninit = ipip6_tunnel_uninit, - .ndo_start_xmit = sit_tunnel_xmit, - .ndo_do_ioctl = ipip6_tunnel_ioctl, - .ndo_change_mtu = ipip6_tunnel_change_mtu, - .ndo_get_stats64 = ip_tunnel_get_stats64, - .ndo_get_iflink = ip_tunnel_get_iflink, -}; - -static void ipip6_dev_free(struct net_device *dev) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - - dst_cache_destroy(&tunnel->dst_cache); - free_percpu(dev->tstats); - free_netdev(dev); -} - -#define SIT_FEATURES (NETIF_F_SG | \ - NETIF_F_FRAGLIST | \ - NETIF_F_HIGHDMA | \ - NETIF_F_GSO_SOFTWARE | \ - NETIF_F_HW_CSUM) - -static void ipip6_tunnel_setup(struct net_device *dev) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - int t_hlen = tunnel->hlen + sizeof(struct iphdr); - - dev->netdev_ops = &ipip6_netdev_ops; - dev->destructor = ipip6_dev_free; - - dev->type = ARPHRD_SIT; - dev->hard_header_len = LL_MAX_HEADER + t_hlen; - dev->mtu = ETH_DATA_LEN - t_hlen; - dev->flags = IFF_NOARP; - netif_keep_dst(dev); - dev->addr_len = 4; - dev->features |= NETIF_F_LLTX; - dev->features |= SIT_FEATURES; - dev->hw_features |= SIT_FEATURES; -} - -static int ipip6_tunnel_init(struct net_device *dev) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - int err; - - tunnel->dev = dev; - tunnel->net = dev_net(dev); - strcpy(tunnel->parms.name, dev->name); - - ipip6_tunnel_bind_dev(dev); - dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); - if (!dev->tstats) - return -ENOMEM; - - err = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL); - if (err) { - free_percpu(dev->tstats); - return err; - } - - return 0; -} - -static void __net_init ipip6_fb_tunnel_init(struct net_device *dev) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - struct iphdr *iph = &tunnel->parms.iph; - struct net *net = dev_net(dev); - struct sit_net *sitn = net_generic(net, sit_net_id); - - iph->version = 4; - iph->protocol = IPPROTO_IPV6; - iph->ihl = 5; - iph->ttl = 64; - - dev_hold(dev); - rcu_assign_pointer(sitn->tunnels_wc[0], tunnel); -} - -static int ipip6_validate(struct nlattr *tb[], struct nlattr *data[]) -{ - u8 proto; - - if (!data || !data[IFLA_IPTUN_PROTO]) - return 0; - - proto = nla_get_u8(data[IFLA_IPTUN_PROTO]); - if (!ipip6_valid_ip_proto(proto)) - return -EINVAL; - - return 0; -} - -static void ipip6_netlink_parms(struct nlattr *data[], - struct ip_tunnel_parm *parms) -{ - memset(parms, 0, sizeof(*parms)); - - parms->iph.version = 4; - parms->iph.protocol = IPPROTO_IPV6; - parms->iph.ihl = 5; - parms->iph.ttl = 64; - - if (!data) - return; - - if (data[IFLA_IPTUN_LINK]) - parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]); - - if (data[IFLA_IPTUN_LOCAL]) - parms->iph.saddr = nla_get_be32(data[IFLA_IPTUN_LOCAL]); - - if (data[IFLA_IPTUN_REMOTE]) - parms->iph.daddr = nla_get_be32(data[IFLA_IPTUN_REMOTE]); - - if (data[IFLA_IPTUN_TTL]) { - parms->iph.ttl = nla_get_u8(data[IFLA_IPTUN_TTL]); - if (parms->iph.ttl) - parms->iph.frag_off = htons(IP_DF); - } - - if (data[IFLA_IPTUN_TOS]) - parms->iph.tos = nla_get_u8(data[IFLA_IPTUN_TOS]); - - if (!data[IFLA_IPTUN_PMTUDISC] || nla_get_u8(data[IFLA_IPTUN_PMTUDISC])) - parms->iph.frag_off = htons(IP_DF); - - if (data[IFLA_IPTUN_FLAGS]) - parms->i_flags = nla_get_be16(data[IFLA_IPTUN_FLAGS]); - - if (data[IFLA_IPTUN_PROTO]) - parms->iph.protocol = nla_get_u8(data[IFLA_IPTUN_PROTO]); - -} - -/* This function returns true when ENCAP attributes are present in the nl msg */ -static bool ipip6_netlink_encap_parms(struct nlattr *data[], - struct ip_tunnel_encap *ipencap) -{ - bool ret = false; - - memset(ipencap, 0, sizeof(*ipencap)); - - if (!data) - return ret; - - if (data[IFLA_IPTUN_ENCAP_TYPE]) { - ret = true; - ipencap->type = nla_get_u16(data[IFLA_IPTUN_ENCAP_TYPE]); - } - - if (data[IFLA_IPTUN_ENCAP_FLAGS]) { - ret = true; - ipencap->flags = nla_get_u16(data[IFLA_IPTUN_ENCAP_FLAGS]); - } - - if (data[IFLA_IPTUN_ENCAP_SPORT]) { - ret = true; - ipencap->sport = nla_get_be16(data[IFLA_IPTUN_ENCAP_SPORT]); - } - - if (data[IFLA_IPTUN_ENCAP_DPORT]) { - ret = true; - ipencap->dport = nla_get_be16(data[IFLA_IPTUN_ENCAP_DPORT]); - } - - return ret; -} - -#ifdef CONFIG_IPV6_SIT_6RD -/* This function returns true when 6RD attributes are present in the nl msg */ -static bool ipip6_netlink_6rd_parms(struct nlattr *data[], - struct ip_tunnel_6rd *ip6rd) -{ - bool ret = false; - memset(ip6rd, 0, sizeof(*ip6rd)); - - if (!data) - return ret; - - if (data[IFLA_IPTUN_6RD_PREFIX]) { - ret = true; - ip6rd->prefix = nla_get_in6_addr(data[IFLA_IPTUN_6RD_PREFIX]); - } - - if (data[IFLA_IPTUN_6RD_RELAY_PREFIX]) { - ret = true; - ip6rd->relay_prefix = - nla_get_be32(data[IFLA_IPTUN_6RD_RELAY_PREFIX]); - } - - if (data[IFLA_IPTUN_6RD_PREFIXLEN]) { - ret = true; - ip6rd->prefixlen = nla_get_u16(data[IFLA_IPTUN_6RD_PREFIXLEN]); - } - - if (data[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]) { - ret = true; - ip6rd->relay_prefixlen = - nla_get_u16(data[IFLA_IPTUN_6RD_RELAY_PREFIXLEN]); - } - - return ret; -} -#endif - -static int ipip6_newlink(struct net *src_net, struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) -{ - struct net *net = dev_net(dev); - struct ip_tunnel *nt; - struct ip_tunnel_encap ipencap; -#ifdef CONFIG_IPV6_SIT_6RD - struct ip_tunnel_6rd ip6rd; -#endif - int err; - - nt = netdev_priv(dev); - - if (ipip6_netlink_encap_parms(data, &ipencap)) { - err = ip_tunnel_encap_setup(nt, &ipencap); - if (err < 0) - return err; - } - - ipip6_netlink_parms(data, &nt->parms); - - if (ipip6_tunnel_locate(net, &nt->parms, 0)) - return -EEXIST; - - err = ipip6_tunnel_create(dev); - if (err < 0) - return err; - -#ifdef CONFIG_IPV6_SIT_6RD - if (ipip6_netlink_6rd_parms(data, &ip6rd)) - err = ipip6_tunnel_update_6rd(nt, &ip6rd); -#endif - - return err; -} - -static int ipip6_changelink(struct net_device *dev, struct nlattr *tb[], - struct nlattr *data[]) -{ - struct ip_tunnel *t = netdev_priv(dev); - struct ip_tunnel_parm p; - struct ip_tunnel_encap ipencap; - struct net *net = t->net; - struct sit_net *sitn = net_generic(net, sit_net_id); -#ifdef CONFIG_IPV6_SIT_6RD - struct ip_tunnel_6rd ip6rd; -#endif - int err; - - if (dev == sitn->fb_tunnel_dev) - return -EINVAL; - - if (ipip6_netlink_encap_parms(data, &ipencap)) { - err = ip_tunnel_encap_setup(t, &ipencap); - if (err < 0) - return err; - } - - ipip6_netlink_parms(data, &p); - - if (((dev->flags & IFF_POINTOPOINT) && !p.iph.daddr) || - (!(dev->flags & IFF_POINTOPOINT) && p.iph.daddr)) - return -EINVAL; - - t = ipip6_tunnel_locate(net, &p, 0); - - if (t) { - if (t->dev != dev) - return -EEXIST; - } else - t = netdev_priv(dev); - - ipip6_tunnel_update(t, &p); - -#ifdef CONFIG_IPV6_SIT_6RD - if (ipip6_netlink_6rd_parms(data, &ip6rd)) - return ipip6_tunnel_update_6rd(t, &ip6rd); -#endif - - return 0; -} - -static size_t ipip6_get_size(const struct net_device *dev) -{ - return - /* IFLA_IPTUN_LINK */ - nla_total_size(4) + - /* IFLA_IPTUN_LOCAL */ - nla_total_size(4) + - /* IFLA_IPTUN_REMOTE */ - nla_total_size(4) + - /* IFLA_IPTUN_TTL */ - nla_total_size(1) + - /* IFLA_IPTUN_TOS */ - nla_total_size(1) + - /* IFLA_IPTUN_PMTUDISC */ - nla_total_size(1) + - /* IFLA_IPTUN_FLAGS */ - nla_total_size(2) + - /* IFLA_IPTUN_PROTO */ - nla_total_size(1) + -#ifdef CONFIG_IPV6_SIT_6RD - /* IFLA_IPTUN_6RD_PREFIX */ - nla_total_size(sizeof(struct in6_addr)) + - /* IFLA_IPTUN_6RD_RELAY_PREFIX */ - nla_total_size(4) + - /* IFLA_IPTUN_6RD_PREFIXLEN */ - nla_total_size(2) + - /* IFLA_IPTUN_6RD_RELAY_PREFIXLEN */ - nla_total_size(2) + -#endif - /* IFLA_IPTUN_ENCAP_TYPE */ - nla_total_size(2) + - /* IFLA_IPTUN_ENCAP_FLAGS */ - nla_total_size(2) + - /* IFLA_IPTUN_ENCAP_SPORT */ - nla_total_size(2) + - /* IFLA_IPTUN_ENCAP_DPORT */ - nla_total_size(2) + - 0; -} - -static int ipip6_fill_info(struct sk_buff *skb, const struct net_device *dev) -{ - struct ip_tunnel *tunnel = netdev_priv(dev); - struct ip_tunnel_parm *parm = &tunnel->parms; - - if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || - nla_put_in_addr(skb, IFLA_IPTUN_LOCAL, parm->iph.saddr) || - nla_put_in_addr(skb, IFLA_IPTUN_REMOTE, parm->iph.daddr) || - nla_put_u8(skb, IFLA_IPTUN_TTL, parm->iph.ttl) || - nla_put_u8(skb, IFLA_IPTUN_TOS, parm->iph.tos) || - nla_put_u8(skb, IFLA_IPTUN_PMTUDISC, - !!(parm->iph.frag_off & htons(IP_DF))) || - nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->iph.protocol) || - nla_put_be16(skb, IFLA_IPTUN_FLAGS, parm->i_flags)) - goto nla_put_failure; - -#ifdef CONFIG_IPV6_SIT_6RD - if (nla_put_in6_addr(skb, IFLA_IPTUN_6RD_PREFIX, - &tunnel->ip6rd.prefix) || - nla_put_in_addr(skb, IFLA_IPTUN_6RD_RELAY_PREFIX, - tunnel->ip6rd.relay_prefix) || - nla_put_u16(skb, IFLA_IPTUN_6RD_PREFIXLEN, - tunnel->ip6rd.prefixlen) || - nla_put_u16(skb, IFLA_IPTUN_6RD_RELAY_PREFIXLEN, - tunnel->ip6rd.relay_prefixlen)) - goto nla_put_failure; -#endif - - if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, - tunnel->encap.type) || - nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, - tunnel->encap.sport) || - nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, - tunnel->encap.dport) || - nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS, - tunnel->encap.flags)) - goto nla_put_failure; - - return 0; - -nla_put_failure: - return -EMSGSIZE; -} - -static const struct nla_policy ipip6_policy[IFLA_IPTUN_MAX + 1] = { - [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, - [IFLA_IPTUN_LOCAL] = { .type = NLA_U32 }, - [IFLA_IPTUN_REMOTE] = { .type = NLA_U32 }, - [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, - [IFLA_IPTUN_TOS] = { .type = NLA_U8 }, - [IFLA_IPTUN_PMTUDISC] = { .type = NLA_U8 }, - [IFLA_IPTUN_FLAGS] = { .type = NLA_U16 }, - [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, -#ifdef CONFIG_IPV6_SIT_6RD - [IFLA_IPTUN_6RD_PREFIX] = { .len = sizeof(struct in6_addr) }, - [IFLA_IPTUN_6RD_RELAY_PREFIX] = { .type = NLA_U32 }, - [IFLA_IPTUN_6RD_PREFIXLEN] = { .type = NLA_U16 }, - [IFLA_IPTUN_6RD_RELAY_PREFIXLEN] = { .type = NLA_U16 }, -#endif - [IFLA_IPTUN_ENCAP_TYPE] = { .type = NLA_U16 }, - [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 }, - [IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 }, - [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, -}; - -static void ipip6_dellink(struct net_device *dev, struct list_head *head) -{ - struct net *net = dev_net(dev); - struct sit_net *sitn = net_generic(net, sit_net_id); - - if (dev != sitn->fb_tunnel_dev) - unregister_netdevice_queue(dev, head); -} - -static struct rtnl_link_ops sit_link_ops __read_mostly = { - .kind = "sit", - .maxtype = IFLA_IPTUN_MAX, - .policy = ipip6_policy, - .priv_size = sizeof(struct ip_tunnel), - .setup = ipip6_tunnel_setup, - .validate = ipip6_validate, - .newlink = ipip6_newlink, - .changelink = ipip6_changelink, - .get_size = ipip6_get_size, - .fill_info = ipip6_fill_info, - .dellink = ipip6_dellink, - .get_link_net = ip_tunnel_get_link_net, -}; - -static struct xfrm_tunnel sit_handler __read_mostly = { - .handler = ipip6_rcv, - .err_handler = ipip6_err, - .priority = 1, -}; - -static struct xfrm_tunnel ipip_handler __read_mostly = { - .handler = ipip_rcv, - .err_handler = ipip6_err, - .priority = 2, -}; - -#if IS_ENABLED(CONFIG_MPLS) -static struct xfrm_tunnel mplsip_handler __read_mostly = { - .handler = mplsip_rcv, - .err_handler = ipip6_err, - .priority = 2, -}; -#endif - -static void __net_exit sit_destroy_tunnels(struct net *net, - struct list_head *head) -{ - struct sit_net *sitn = net_generic(net, sit_net_id); - struct net_device *dev, *aux; - int prio; - - for_each_netdev_safe(net, dev, aux) - if (dev->rtnl_link_ops == &sit_link_ops) - unregister_netdevice_queue(dev, head); - - for (prio = 1; prio < 4; prio++) { - int h; - for (h = 0; h < IP6_SIT_HASH_SIZE; h++) { - struct ip_tunnel *t; - - t = rtnl_dereference(sitn->tunnels[prio][h]); - while (t) { - /* If dev is in the same netns, it has already - * been added to the list by the previous loop. - */ - if (!net_eq(dev_net(t->dev), net)) - unregister_netdevice_queue(t->dev, - head); - t = rtnl_dereference(t->next); - } - } - } -} - -static int __net_init sit_init_net(struct net *net) -{ - struct sit_net *sitn = net_generic(net, sit_net_id); - struct ip_tunnel *t; - int err; - - sitn->tunnels[0] = sitn->tunnels_wc; - sitn->tunnels[1] = sitn->tunnels_l; - sitn->tunnels[2] = sitn->tunnels_r; - sitn->tunnels[3] = sitn->tunnels_r_l; - - sitn->fb_tunnel_dev = alloc_netdev(sizeof(struct ip_tunnel), "sit0", - NET_NAME_UNKNOWN, - ipip6_tunnel_setup); - if (!sitn->fb_tunnel_dev) { - err = -ENOMEM; - goto err_alloc_dev; - } - dev_net_set(sitn->fb_tunnel_dev, net); - sitn->fb_tunnel_dev->rtnl_link_ops = &sit_link_ops; - /* FB netdevice is special: we have one, and only one per netns. - * Allowing to move it to another netns is clearly unsafe. - */ - sitn->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL; - - err = register_netdev(sitn->fb_tunnel_dev); - if (err) - goto err_reg_dev; - - ipip6_tunnel_clone_6rd(sitn->fb_tunnel_dev, sitn); - ipip6_fb_tunnel_init(sitn->fb_tunnel_dev); - - t = netdev_priv(sitn->fb_tunnel_dev); - - strcpy(t->parms.name, sitn->fb_tunnel_dev->name); - return 0; - -err_reg_dev: - ipip6_dev_free(sitn->fb_tunnel_dev); -err_alloc_dev: - return err; -} - -static void __net_exit sit_exit_net(struct net *net) -{ - LIST_HEAD(list); - - rtnl_lock(); - sit_destroy_tunnels(net, &list); - unregister_netdevice_many(&list); - rtnl_unlock(); -} - -static struct pernet_operations sit_net_ops = { - .init = sit_init_net, - .exit = sit_exit_net, - .id = &sit_net_id, - .size = sizeof(struct sit_net), -}; - -static void __exit sit_cleanup(void) -{ - rtnl_link_unregister(&sit_link_ops); - xfrm4_tunnel_deregister(&sit_handler, AF_INET6); - xfrm4_tunnel_deregister(&ipip_handler, AF_INET); -#if IS_ENABLED(CONFIG_MPLS) - xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS); -#endif - - unregister_pernet_device(&sit_net_ops); - rcu_barrier(); /* Wait for completion of call_rcu()'s */ -} - -static int __init sit_init(void) -{ - int err; - - pr_info("IPv6, IPv4 and MPLS over IPv4 tunneling driver\n"); - - err = register_pernet_device(&sit_net_ops); - if (err < 0) - return err; - err = xfrm4_tunnel_register(&sit_handler, AF_INET6); - if (err < 0) { - pr_info("%s: can't register ip6ip4\n", __func__); - goto xfrm_tunnel_failed; - } - err = xfrm4_tunnel_register(&ipip_handler, AF_INET); - if (err < 0) { - pr_info("%s: can't register ip4ip4\n", __func__); - goto xfrm_tunnel4_failed; - } -#if IS_ENABLED(CONFIG_MPLS) - err = xfrm4_tunnel_register(&mplsip_handler, AF_MPLS); - if (err < 0) { - pr_info("%s: can't register mplsip\n", __func__); - goto xfrm_tunnel_mpls_failed; - } -#endif - err = rtnl_link_register(&sit_link_ops); - if (err < 0) - goto rtnl_link_failed; - -out: - return err; - -rtnl_link_failed: -#if IS_ENABLED(CONFIG_MPLS) - xfrm4_tunnel_deregister(&mplsip_handler, AF_MPLS); -xfrm_tunnel_mpls_failed: -#endif - xfrm4_tunnel_deregister(&ipip_handler, AF_INET); -xfrm_tunnel4_failed: - xfrm4_tunnel_deregister(&sit_handler, AF_INET6); -xfrm_tunnel_failed: - unregister_pernet_device(&sit_net_ops); - goto out; -} - -module_init(sit_init); -module_exit(sit_cleanup); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_RTNL_LINK("sit"); -MODULE_ALIAS_NETDEV("sit0"); diff --git a/src/linux/net/ipv6/sysctl_net_ipv6.c b/src/linux/net/ipv6/sysctl_net_ipv6.c deleted file mode 100644 index 69c50e7..0000000 --- a/src/linux/net/ipv6/sysctl_net_ipv6.c +++ /dev/null @@ -1,240 +0,0 @@ -/* - * sysctl_net_ipv6.c: sysctl interface to net IPV6 subsystem. - * - * Changes: - * YOSHIFUJI Hideaki @USAGI: added icmp sysctl table. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_NETLABEL -#include -#endif - -static int one = 1; -static int auto_flowlabels_min; -static int auto_flowlabels_max = IP6_AUTO_FLOW_LABEL_MAX; - - -static struct ctl_table ipv6_table_template[] = { - { - .procname = "bindv6only", - .data = &init_net.ipv6.sysctl.bindv6only, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "anycast_src_echo_reply", - .data = &init_net.ipv6.sysctl.anycast_src_echo_reply, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "flowlabel_consistency", - .data = &init_net.ipv6.sysctl.flowlabel_consistency, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "auto_flowlabels", - .data = &init_net.ipv6.sysctl.auto_flowlabels, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &auto_flowlabels_min, - .extra2 = &auto_flowlabels_max - }, - { - .procname = "fwmark_reflect", - .data = &init_net.ipv6.sysctl.fwmark_reflect, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "idgen_retries", - .data = &init_net.ipv6.sysctl.idgen_retries, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "idgen_delay", - .data = &init_net.ipv6.sysctl.idgen_delay, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_jiffies, - }, - { - .procname = "flowlabel_state_ranges", - .data = &init_net.ipv6.sysctl.flowlabel_state_ranges, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "ip_nonlocal_bind", - .data = &init_net.ipv6.sysctl.ip_nonlocal_bind, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { } -}; - -static struct ctl_table ipv6_rotable[] = { - { - .procname = "mld_max_msf", - .data = &sysctl_mld_max_msf, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "mld_qrv", - .data = &sysctl_mld_qrv, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &one - }, -#ifdef CONFIG_NETLABEL - { - .procname = "calipso_cache_enable", - .data = &calipso_cache_enabled, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "calipso_cache_bucket_size", - .data = &calipso_cache_bucketsize, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, -#endif /* CONFIG_NETLABEL */ - { } -}; - -static int __net_init ipv6_sysctl_net_init(struct net *net) -{ - struct ctl_table *ipv6_table; - struct ctl_table *ipv6_route_table; - struct ctl_table *ipv6_icmp_table; - int err; - - err = -ENOMEM; - ipv6_table = kmemdup(ipv6_table_template, sizeof(ipv6_table_template), - GFP_KERNEL); - if (!ipv6_table) - goto out; - ipv6_table[0].data = &net->ipv6.sysctl.bindv6only; - ipv6_table[1].data = &net->ipv6.sysctl.anycast_src_echo_reply; - ipv6_table[2].data = &net->ipv6.sysctl.flowlabel_consistency; - ipv6_table[3].data = &net->ipv6.sysctl.auto_flowlabels; - ipv6_table[4].data = &net->ipv6.sysctl.fwmark_reflect; - ipv6_table[5].data = &net->ipv6.sysctl.idgen_retries; - ipv6_table[6].data = &net->ipv6.sysctl.idgen_delay; - ipv6_table[7].data = &net->ipv6.sysctl.flowlabel_state_ranges; - ipv6_table[8].data = &net->ipv6.sysctl.ip_nonlocal_bind; - - ipv6_route_table = ipv6_route_sysctl_init(net); - if (!ipv6_route_table) - goto out_ipv6_table; - - ipv6_icmp_table = ipv6_icmp_sysctl_init(net); - if (!ipv6_icmp_table) - goto out_ipv6_route_table; - - net->ipv6.sysctl.hdr = register_net_sysctl(net, "net/ipv6", ipv6_table); - if (!net->ipv6.sysctl.hdr) - goto out_ipv6_icmp_table; - - net->ipv6.sysctl.route_hdr = - register_net_sysctl(net, "net/ipv6/route", ipv6_route_table); - if (!net->ipv6.sysctl.route_hdr) - goto out_unregister_ipv6_table; - - net->ipv6.sysctl.icmp_hdr = - register_net_sysctl(net, "net/ipv6/icmp", ipv6_icmp_table); - if (!net->ipv6.sysctl.icmp_hdr) - goto out_unregister_route_table; - - err = 0; -out: - return err; -out_unregister_route_table: - unregister_net_sysctl_table(net->ipv6.sysctl.route_hdr); -out_unregister_ipv6_table: - unregister_net_sysctl_table(net->ipv6.sysctl.hdr); -out_ipv6_icmp_table: - kfree(ipv6_icmp_table); -out_ipv6_route_table: - kfree(ipv6_route_table); -out_ipv6_table: - kfree(ipv6_table); - goto out; -} - -static void __net_exit ipv6_sysctl_net_exit(struct net *net) -{ - struct ctl_table *ipv6_table; - struct ctl_table *ipv6_route_table; - struct ctl_table *ipv6_icmp_table; - - ipv6_table = net->ipv6.sysctl.hdr->ctl_table_arg; - ipv6_route_table = net->ipv6.sysctl.route_hdr->ctl_table_arg; - ipv6_icmp_table = net->ipv6.sysctl.icmp_hdr->ctl_table_arg; - - unregister_net_sysctl_table(net->ipv6.sysctl.icmp_hdr); - unregister_net_sysctl_table(net->ipv6.sysctl.route_hdr); - unregister_net_sysctl_table(net->ipv6.sysctl.hdr); - - kfree(ipv6_table); - kfree(ipv6_route_table); - kfree(ipv6_icmp_table); -} - -static struct pernet_operations ipv6_sysctl_net_ops = { - .init = ipv6_sysctl_net_init, - .exit = ipv6_sysctl_net_exit, -}; - -static struct ctl_table_header *ip6_header; - -int ipv6_sysctl_register(void) -{ - int err = -ENOMEM; - - ip6_header = register_net_sysctl(&init_net, "net/ipv6", ipv6_rotable); - if (!ip6_header) - goto out; - - err = register_pernet_subsys(&ipv6_sysctl_net_ops); - if (err) - goto err_pernet; -out: - return err; - -err_pernet: - unregister_net_sysctl_table(ip6_header); - goto out; -} - -void ipv6_sysctl_unregister(void) -{ - unregister_net_sysctl_table(ip6_header); - unregister_pernet_subsys(&ipv6_sysctl_net_ops); -} diff --git a/src/linux/net/ipv6/tcp_ipv6.c b/src/linux/net/ipv6/tcp_ipv6.c deleted file mode 100644 index b9f1fee..0000000 --- a/src/linux/net/ipv6/tcp_ipv6.c +++ /dev/null @@ -1,1987 +0,0 @@ -/* - * TCP over IPv6 - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * Based on: - * linux/net/ipv4/tcp.c - * linux/net/ipv4/tcp_input.c - * linux/net/ipv4/tcp_output.c - * - * Fixes: - * Hideaki YOSHIFUJI : sin6_scope_id support - * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which - * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind - * a single port at the same time. - * YOSHIFUJI Hideaki @USAGI: convert /proc/net/tcp6 to seq_file. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb); -static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, - struct request_sock *req); - -static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb); - -static const struct inet_connection_sock_af_ops ipv6_mapped; -static const struct inet_connection_sock_af_ops ipv6_specific; -#ifdef CONFIG_TCP_MD5SIG -static const struct tcp_sock_af_ops tcp_sock_ipv6_specific; -static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; -#else -static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(const struct sock *sk, - const struct in6_addr *addr) -{ - return NULL; -} -#endif - -static void inet6_sk_rx_dst_set(struct sock *sk, const struct sk_buff *skb) -{ - struct dst_entry *dst = skb_dst(skb); - - if (dst && dst_hold_safe(dst)) { - const struct rt6_info *rt = (const struct rt6_info *)dst; - - sk->sk_rx_dst = dst; - inet_sk(sk)->rx_dst_ifindex = skb->skb_iif; - inet6_sk(sk)->rx_dst_cookie = rt6_get_cookie(rt); - } -} - -static __u32 tcp_v6_init_sequence(const struct sk_buff *skb) -{ - return secure_tcpv6_sequence_number(ipv6_hdr(skb)->daddr.s6_addr32, - ipv6_hdr(skb)->saddr.s6_addr32, - tcp_hdr(skb)->dest, - tcp_hdr(skb)->source); -} - -static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, - int addr_len) -{ - struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; - struct inet_sock *inet = inet_sk(sk); - struct inet_connection_sock *icsk = inet_csk(sk); - struct ipv6_pinfo *np = inet6_sk(sk); - struct tcp_sock *tp = tcp_sk(sk); - struct in6_addr *saddr = NULL, *final_p, final; - struct ipv6_txoptions *opt; - struct flowi6 fl6; - struct dst_entry *dst; - int addr_type; - int err; - - if (addr_len < SIN6_LEN_RFC2133) - return -EINVAL; - - if (usin->sin6_family != AF_INET6) - return -EAFNOSUPPORT; - - memset(&fl6, 0, sizeof(fl6)); - - if (np->sndflow) { - fl6.flowlabel = usin->sin6_flowinfo&IPV6_FLOWINFO_MASK; - IP6_ECN_flow_init(fl6.flowlabel); - if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) { - struct ip6_flowlabel *flowlabel; - flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); - if (!flowlabel) - return -EINVAL; - fl6_sock_release(flowlabel); - } - } - - /* - * connect() to INADDR_ANY means loopback (BSD'ism). - */ - - if (ipv6_addr_any(&usin->sin6_addr)) - usin->sin6_addr.s6_addr[15] = 0x1; - - addr_type = ipv6_addr_type(&usin->sin6_addr); - - if (addr_type & IPV6_ADDR_MULTICAST) - return -ENETUNREACH; - - if (addr_type&IPV6_ADDR_LINKLOCAL) { - if (addr_len >= sizeof(struct sockaddr_in6) && - usin->sin6_scope_id) { - /* If interface is set while binding, indices - * must coincide. - */ - if (sk->sk_bound_dev_if && - sk->sk_bound_dev_if != usin->sin6_scope_id) - return -EINVAL; - - sk->sk_bound_dev_if = usin->sin6_scope_id; - } - - /* Connect to link-local address requires an interface */ - if (!sk->sk_bound_dev_if) - return -EINVAL; - } - - if (tp->rx_opt.ts_recent_stamp && - !ipv6_addr_equal(&sk->sk_v6_daddr, &usin->sin6_addr)) { - tp->rx_opt.ts_recent = 0; - tp->rx_opt.ts_recent_stamp = 0; - tp->write_seq = 0; - } - - sk->sk_v6_daddr = usin->sin6_addr; - np->flow_label = fl6.flowlabel; - - /* - * TCP over IPv4 - */ - - if (addr_type == IPV6_ADDR_MAPPED) { - u32 exthdrlen = icsk->icsk_ext_hdr_len; - struct sockaddr_in sin; - - SOCK_DEBUG(sk, "connect: ipv4 mapped\n"); - - if (__ipv6_only_sock(sk)) - return -ENETUNREACH; - - sin.sin_family = AF_INET; - sin.sin_port = usin->sin6_port; - sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3]; - - icsk->icsk_af_ops = &ipv6_mapped; - sk->sk_backlog_rcv = tcp_v4_do_rcv; -#ifdef CONFIG_TCP_MD5SIG - tp->af_specific = &tcp_sock_ipv6_mapped_specific; -#endif - - err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin)); - - if (err) { - icsk->icsk_ext_hdr_len = exthdrlen; - icsk->icsk_af_ops = &ipv6_specific; - sk->sk_backlog_rcv = tcp_v6_do_rcv; -#ifdef CONFIG_TCP_MD5SIG - tp->af_specific = &tcp_sock_ipv6_specific; -#endif - goto failure; - } - np->saddr = sk->sk_v6_rcv_saddr; - - return err; - } - - if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) - saddr = &sk->sk_v6_rcv_saddr; - - fl6.flowi6_proto = IPPROTO_TCP; - fl6.daddr = sk->sk_v6_daddr; - fl6.saddr = saddr ? *saddr : np->saddr; - fl6.flowi6_oif = sk->sk_bound_dev_if; - fl6.flowi6_mark = sk->sk_mark; - fl6.fl6_dport = usin->sin6_port; - fl6.fl6_sport = inet->inet_sport; - - opt = rcu_dereference_protected(np->opt, lockdep_sock_is_held(sk)); - final_p = fl6_update_dst(&fl6, opt, &final); - - security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); - - dst = ip6_dst_lookup_flow(sk, &fl6, final_p); - if (IS_ERR(dst)) { - err = PTR_ERR(dst); - goto failure; - } - - if (!saddr) { - saddr = &fl6.saddr; - sk->sk_v6_rcv_saddr = *saddr; - } - - /* set the source address */ - np->saddr = *saddr; - inet->inet_rcv_saddr = LOOPBACK4_IPV6; - - sk->sk_gso_type = SKB_GSO_TCPV6; - ip6_dst_store(sk, dst, NULL, NULL); - - if (tcp_death_row.sysctl_tw_recycle && - !tp->rx_opt.ts_recent_stamp && - ipv6_addr_equal(&fl6.daddr, &sk->sk_v6_daddr)) - tcp_fetch_timewait_stamp(sk, dst); - - icsk->icsk_ext_hdr_len = 0; - if (opt) - icsk->icsk_ext_hdr_len = opt->opt_flen + - opt->opt_nflen; - - tp->rx_opt.mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - sizeof(struct ipv6hdr); - - inet->inet_dport = usin->sin6_port; - - tcp_set_state(sk, TCP_SYN_SENT); - err = inet6_hash_connect(&tcp_death_row, sk); - if (err) - goto late_failure; - - sk_set_txhash(sk); - - if (!tp->write_seq && likely(!tp->repair)) - tp->write_seq = secure_tcpv6_sequence_number(np->saddr.s6_addr32, - sk->sk_v6_daddr.s6_addr32, - inet->inet_sport, - inet->inet_dport); - - err = tcp_connect(sk); - if (err) - goto late_failure; - - return 0; - -late_failure: - tcp_set_state(sk, TCP_CLOSE); - __sk_dst_reset(sk); -failure: - inet->inet_dport = 0; - sk->sk_route_caps = 0; - return err; -} - -static void tcp_v6_mtu_reduced(struct sock *sk) -{ - struct dst_entry *dst; - - if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) - return; - - dst = inet6_csk_update_pmtu(sk, tcp_sk(sk)->mtu_info); - if (!dst) - return; - - if (inet_csk(sk)->icsk_pmtu_cookie > dst_mtu(dst)) { - tcp_sync_mss(sk, dst_mtu(dst)); - tcp_simple_retransmit(sk); - } -} - -static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - u8 type, u8 code, int offset, __be32 info) -{ - const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data; - const struct tcphdr *th = (struct tcphdr *)(skb->data+offset); - struct net *net = dev_net(skb->dev); - struct request_sock *fastopen; - struct ipv6_pinfo *np; - struct tcp_sock *tp; - __u32 seq, snd_una; - struct sock *sk; - bool fatal; - int err; - - sk = __inet6_lookup_established(net, &tcp_hashinfo, - &hdr->daddr, th->dest, - &hdr->saddr, ntohs(th->source), - skb->dev->ifindex); - - if (!sk) { - __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), - ICMP6_MIB_INERRORS); - return; - } - - if (sk->sk_state == TCP_TIME_WAIT) { - inet_twsk_put(inet_twsk(sk)); - return; - } - seq = ntohl(th->seq); - fatal = icmpv6_err_convert(type, code, &err); - if (sk->sk_state == TCP_NEW_SYN_RECV) - return tcp_req_err(sk, seq, fatal); - - bh_lock_sock(sk); - if (sock_owned_by_user(sk) && type != ICMPV6_PKT_TOOBIG) - __NET_INC_STATS(net, LINUX_MIB_LOCKDROPPEDICMPS); - - if (sk->sk_state == TCP_CLOSE) - goto out; - - if (ipv6_hdr(skb)->hop_limit < inet6_sk(sk)->min_hopcount) { - __NET_INC_STATS(net, LINUX_MIB_TCPMINTTLDROP); - goto out; - } - - tp = tcp_sk(sk); - /* XXX (TFO) - tp->snd_una should be ISN (tcp_create_openreq_child() */ - fastopen = tp->fastopen_rsk; - snd_una = fastopen ? tcp_rsk(fastopen)->snt_isn : tp->snd_una; - if (sk->sk_state != TCP_LISTEN && - !between(seq, snd_una, tp->snd_nxt)) { - __NET_INC_STATS(net, LINUX_MIB_OUTOFWINDOWICMPS); - goto out; - } - - np = inet6_sk(sk); - - if (type == NDISC_REDIRECT) { - struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie); - - if (dst) - dst->ops->redirect(dst, sk, skb); - goto out; - } - - if (type == ICMPV6_PKT_TOOBIG) { - /* We are not interested in TCP_LISTEN and open_requests - * (SYN-ACKs send out by Linux are always <576bytes so - * they should go through unfragmented). - */ - if (sk->sk_state == TCP_LISTEN) - goto out; - - if (!ip6_sk_accept_pmtu(sk)) - goto out; - - tp->mtu_info = ntohl(info); - if (!sock_owned_by_user(sk)) - tcp_v6_mtu_reduced(sk); - else if (!test_and_set_bit(TCP_MTU_REDUCED_DEFERRED, - &tp->tsq_flags)) - sock_hold(sk); - goto out; - } - - - /* Might be for an request_sock */ - switch (sk->sk_state) { - case TCP_SYN_SENT: - case TCP_SYN_RECV: - /* Only in fast or simultaneous open. If a fast open socket is - * is already accepted it is treated as a connected one below. - */ - if (fastopen && !fastopen->sk) - break; - - if (!sock_owned_by_user(sk)) { - sk->sk_err = err; - sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ - - tcp_done(sk); - } else - sk->sk_err_soft = err; - goto out; - } - - if (!sock_owned_by_user(sk) && np->recverr) { - sk->sk_err = err; - sk->sk_error_report(sk); - } else - sk->sk_err_soft = err; - -out: - bh_unlock_sock(sk); - sock_put(sk); -} - - -static int tcp_v6_send_synack(const struct sock *sk, struct dst_entry *dst, - struct flowi *fl, - struct request_sock *req, - struct tcp_fastopen_cookie *foc, - enum tcp_synack_type synack_type) -{ - struct inet_request_sock *ireq = inet_rsk(req); - struct ipv6_pinfo *np = inet6_sk(sk); - struct ipv6_txoptions *opt; - struct flowi6 *fl6 = &fl->u.ip6; - struct sk_buff *skb; - int err = -ENOMEM; - - /* First, grab a route. */ - if (!dst && (dst = inet6_csk_route_req(sk, fl6, req, - IPPROTO_TCP)) == NULL) - goto done; - - skb = tcp_make_synack(sk, dst, req, foc, synack_type); - - if (skb) { - __tcp_v6_send_check(skb, &ireq->ir_v6_loc_addr, - &ireq->ir_v6_rmt_addr); - - fl6->daddr = ireq->ir_v6_rmt_addr; - if (np->repflow && ireq->pktopts) - fl6->flowlabel = ip6_flowlabel(ipv6_hdr(ireq->pktopts)); - - rcu_read_lock(); - opt = ireq->ipv6_opt; - if (!opt) - opt = rcu_dereference(np->opt); - err = ip6_xmit(sk, skb, fl6, opt, np->tclass); - rcu_read_unlock(); - err = net_xmit_eval(err); - } - -done: - return err; -} - - -static void tcp_v6_reqsk_destructor(struct request_sock *req) -{ - kfree(inet_rsk(req)->ipv6_opt); - kfree_skb(inet_rsk(req)->pktopts); -} - -#ifdef CONFIG_TCP_MD5SIG -static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(const struct sock *sk, - const struct in6_addr *addr) -{ - return tcp_md5_do_lookup(sk, (union tcp_md5_addr *)addr, AF_INET6); -} - -static struct tcp_md5sig_key *tcp_v6_md5_lookup(const struct sock *sk, - const struct sock *addr_sk) -{ - return tcp_v6_md5_do_lookup(sk, &addr_sk->sk_v6_daddr); -} - -static int tcp_v6_parse_md5_keys(struct sock *sk, char __user *optval, - int optlen) -{ - struct tcp_md5sig cmd; - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&cmd.tcpm_addr; - - if (optlen < sizeof(cmd)) - return -EINVAL; - - if (copy_from_user(&cmd, optval, sizeof(cmd))) - return -EFAULT; - - if (sin6->sin6_family != AF_INET6) - return -EINVAL; - - if (!cmd.tcpm_keylen) { - if (ipv6_addr_v4mapped(&sin6->sin6_addr)) - return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3], - AF_INET); - return tcp_md5_do_del(sk, (union tcp_md5_addr *)&sin6->sin6_addr, - AF_INET6); - } - - if (cmd.tcpm_keylen > TCP_MD5SIG_MAXKEYLEN) - return -EINVAL; - - if (ipv6_addr_v4mapped(&sin6->sin6_addr)) - return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr.s6_addr32[3], - AF_INET, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); - - return tcp_md5_do_add(sk, (union tcp_md5_addr *)&sin6->sin6_addr, - AF_INET6, cmd.tcpm_key, cmd.tcpm_keylen, GFP_KERNEL); -} - -static int tcp_v6_md5_hash_headers(struct tcp_md5sig_pool *hp, - const struct in6_addr *daddr, - const struct in6_addr *saddr, - const struct tcphdr *th, int nbytes) -{ - struct tcp6_pseudohdr *bp; - struct scatterlist sg; - struct tcphdr *_th; - - bp = hp->scratch; - /* 1. TCP pseudo-header (RFC2460) */ - bp->saddr = *saddr; - bp->daddr = *daddr; - bp->protocol = cpu_to_be32(IPPROTO_TCP); - bp->len = cpu_to_be32(nbytes); - - _th = (struct tcphdr *)(bp + 1); - memcpy(_th, th, sizeof(*th)); - _th->check = 0; - - sg_init_one(&sg, bp, sizeof(*bp) + sizeof(*th)); - ahash_request_set_crypt(hp->md5_req, &sg, NULL, - sizeof(*bp) + sizeof(*th)); - return crypto_ahash_update(hp->md5_req); -} - -static int tcp_v6_md5_hash_hdr(char *md5_hash, const struct tcp_md5sig_key *key, - const struct in6_addr *daddr, struct in6_addr *saddr, - const struct tcphdr *th) -{ - struct tcp_md5sig_pool *hp; - struct ahash_request *req; - - hp = tcp_get_md5sig_pool(); - if (!hp) - goto clear_hash_noput; - req = hp->md5_req; - - if (crypto_ahash_init(req)) - goto clear_hash; - if (tcp_v6_md5_hash_headers(hp, daddr, saddr, th, th->doff << 2)) - goto clear_hash; - if (tcp_md5_hash_key(hp, key)) - goto clear_hash; - ahash_request_set_crypt(req, NULL, md5_hash, 0); - if (crypto_ahash_final(req)) - goto clear_hash; - - tcp_put_md5sig_pool(); - return 0; - -clear_hash: - tcp_put_md5sig_pool(); -clear_hash_noput: - memset(md5_hash, 0, 16); - return 1; -} - -static int tcp_v6_md5_hash_skb(char *md5_hash, - const struct tcp_md5sig_key *key, - const struct sock *sk, - const struct sk_buff *skb) -{ - const struct in6_addr *saddr, *daddr; - struct tcp_md5sig_pool *hp; - struct ahash_request *req; - const struct tcphdr *th = tcp_hdr(skb); - - if (sk) { /* valid for establish/request sockets */ - saddr = &sk->sk_v6_rcv_saddr; - daddr = &sk->sk_v6_daddr; - } else { - const struct ipv6hdr *ip6h = ipv6_hdr(skb); - saddr = &ip6h->saddr; - daddr = &ip6h->daddr; - } - - hp = tcp_get_md5sig_pool(); - if (!hp) - goto clear_hash_noput; - req = hp->md5_req; - - if (crypto_ahash_init(req)) - goto clear_hash; - - if (tcp_v6_md5_hash_headers(hp, daddr, saddr, th, skb->len)) - goto clear_hash; - if (tcp_md5_hash_skb_data(hp, skb, th->doff << 2)) - goto clear_hash; - if (tcp_md5_hash_key(hp, key)) - goto clear_hash; - ahash_request_set_crypt(req, NULL, md5_hash, 0); - if (crypto_ahash_final(req)) - goto clear_hash; - - tcp_put_md5sig_pool(); - return 0; - -clear_hash: - tcp_put_md5sig_pool(); -clear_hash_noput: - memset(md5_hash, 0, 16); - return 1; -} - -#endif - -static bool tcp_v6_inbound_md5_hash(const struct sock *sk, - const struct sk_buff *skb) -{ -#ifdef CONFIG_TCP_MD5SIG - const __u8 *hash_location = NULL; - struct tcp_md5sig_key *hash_expected; - const struct ipv6hdr *ip6h = ipv6_hdr(skb); - const struct tcphdr *th = tcp_hdr(skb); - int genhash; - u8 newhash[16]; - - hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr); - hash_location = tcp_parse_md5sig_option(th); - - /* We've parsed the options - do we have a hash? */ - if (!hash_expected && !hash_location) - return false; - - if (hash_expected && !hash_location) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5NOTFOUND); - return true; - } - - if (!hash_expected && hash_location) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5UNEXPECTED); - return true; - } - - /* check the signature */ - genhash = tcp_v6_md5_hash_skb(newhash, - hash_expected, - NULL, skb); - - if (genhash || memcmp(hash_location, newhash, 16) != 0) { - NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5FAILURE); - net_info_ratelimited("MD5 Hash %s for [%pI6c]:%u->[%pI6c]:%u\n", - genhash ? "failed" : "mismatch", - &ip6h->saddr, ntohs(th->source), - &ip6h->daddr, ntohs(th->dest)); - return true; - } -#endif - return false; -} - -static void tcp_v6_init_req(struct request_sock *req, - const struct sock *sk_listener, - struct sk_buff *skb) -{ - struct inet_request_sock *ireq = inet_rsk(req); - const struct ipv6_pinfo *np = inet6_sk(sk_listener); - - ireq->ir_v6_rmt_addr = ipv6_hdr(skb)->saddr; - ireq->ir_v6_loc_addr = ipv6_hdr(skb)->daddr; - - /* So that link locals have meaning */ - if (!sk_listener->sk_bound_dev_if && - ipv6_addr_type(&ireq->ir_v6_rmt_addr) & IPV6_ADDR_LINKLOCAL) - ireq->ir_iif = tcp_v6_iif(skb); - - if (!TCP_SKB_CB(skb)->tcp_tw_isn && - (ipv6_opt_accepted(sk_listener, skb, &TCP_SKB_CB(skb)->header.h6) || - np->rxopt.bits.rxinfo || - np->rxopt.bits.rxoinfo || np->rxopt.bits.rxhlim || - np->rxopt.bits.rxohlim || np->repflow)) { - atomic_inc(&skb->users); - ireq->pktopts = skb; - } -} - -static struct dst_entry *tcp_v6_route_req(const struct sock *sk, - struct flowi *fl, - const struct request_sock *req, - bool *strict) -{ - if (strict) - *strict = true; - return inet6_csk_route_req(sk, &fl->u.ip6, req, IPPROTO_TCP); -} - -struct request_sock_ops tcp6_request_sock_ops __read_mostly = { - .family = AF_INET6, - .obj_size = sizeof(struct tcp6_request_sock), - .rtx_syn_ack = tcp_rtx_synack, - .send_ack = tcp_v6_reqsk_send_ack, - .destructor = tcp_v6_reqsk_destructor, - .send_reset = tcp_v6_send_reset, - .syn_ack_timeout = tcp_syn_ack_timeout, -}; - -static const struct tcp_request_sock_ops tcp_request_sock_ipv6_ops = { - .mss_clamp = IPV6_MIN_MTU - sizeof(struct tcphdr) - - sizeof(struct ipv6hdr), -#ifdef CONFIG_TCP_MD5SIG - .req_md5_lookup = tcp_v6_md5_lookup, - .calc_md5_hash = tcp_v6_md5_hash_skb, -#endif - .init_req = tcp_v6_init_req, -#ifdef CONFIG_SYN_COOKIES - .cookie_init_seq = cookie_v6_init_sequence, -#endif - .route_req = tcp_v6_route_req, - .init_seq = tcp_v6_init_sequence, - .send_synack = tcp_v6_send_synack, -}; - -static void tcp_v6_send_response(const struct sock *sk, struct sk_buff *skb, u32 seq, - u32 ack, u32 win, u32 tsval, u32 tsecr, - int oif, struct tcp_md5sig_key *key, int rst, - u8 tclass, __be32 label) -{ - const struct tcphdr *th = tcp_hdr(skb); - struct tcphdr *t1; - struct sk_buff *buff; - struct flowi6 fl6; - struct net *net = sk ? sock_net(sk) : dev_net(skb_dst(skb)->dev); - struct sock *ctl_sk = net->ipv6.tcp_sk; - unsigned int tot_len = sizeof(struct tcphdr); - struct dst_entry *dst; - __be32 *topt; - - if (tsecr) - tot_len += TCPOLEN_TSTAMP_ALIGNED; -#ifdef CONFIG_TCP_MD5SIG - if (key) - tot_len += TCPOLEN_MD5SIG_ALIGNED; -#endif - - buff = alloc_skb(MAX_HEADER + sizeof(struct ipv6hdr) + tot_len, - GFP_ATOMIC); - if (!buff) - return; - - skb_reserve(buff, MAX_HEADER + sizeof(struct ipv6hdr) + tot_len); - - t1 = (struct tcphdr *) skb_push(buff, tot_len); - skb_reset_transport_header(buff); - - /* Swap the send and the receive. */ - memset(t1, 0, sizeof(*t1)); - t1->dest = th->source; - t1->source = th->dest; - t1->doff = tot_len / 4; - t1->seq = htonl(seq); - t1->ack_seq = htonl(ack); - t1->ack = !rst || !th->ack; - t1->rst = rst; - t1->window = htons(win); - - topt = (__be32 *)(t1 + 1); - - if (tsecr) { - *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | - (TCPOPT_TIMESTAMP << 8) | TCPOLEN_TIMESTAMP); - *topt++ = htonl(tsval); - *topt++ = htonl(tsecr); - } - -#ifdef CONFIG_TCP_MD5SIG - if (key) { - *topt++ = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) | - (TCPOPT_MD5SIG << 8) | TCPOLEN_MD5SIG); - tcp_v6_md5_hash_hdr((__u8 *)topt, key, - &ipv6_hdr(skb)->saddr, - &ipv6_hdr(skb)->daddr, t1); - } -#endif - - memset(&fl6, 0, sizeof(fl6)); - fl6.daddr = ipv6_hdr(skb)->saddr; - fl6.saddr = ipv6_hdr(skb)->daddr; - fl6.flowlabel = label; - - buff->ip_summed = CHECKSUM_PARTIAL; - buff->csum = 0; - - __tcp_v6_send_check(buff, &fl6.saddr, &fl6.daddr); - - fl6.flowi6_proto = IPPROTO_TCP; - if (rt6_need_strict(&fl6.daddr) && !oif) - fl6.flowi6_oif = tcp_v6_iif(skb); - else { - if (!oif && netif_index_is_l3_master(net, skb->skb_iif)) - oif = skb->skb_iif; - - fl6.flowi6_oif = oif; - } - - fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark); - fl6.fl6_dport = t1->dest; - fl6.fl6_sport = t1->source; - security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); - - /* Pass a socket to ip6_dst_lookup either it is for RST - * Underlying function will use this to retrieve the network - * namespace - */ - dst = ip6_dst_lookup_flow(ctl_sk, &fl6, NULL); - if (!IS_ERR(dst)) { - skb_dst_set(buff, dst); - ip6_xmit(ctl_sk, buff, &fl6, NULL, tclass); - TCP_INC_STATS(net, TCP_MIB_OUTSEGS); - if (rst) - TCP_INC_STATS(net, TCP_MIB_OUTRSTS); - return; - } - - kfree_skb(buff); -} - -static void tcp_v6_send_reset(const struct sock *sk, struct sk_buff *skb) -{ - const struct tcphdr *th = tcp_hdr(skb); - u32 seq = 0, ack_seq = 0; - struct tcp_md5sig_key *key = NULL; -#ifdef CONFIG_TCP_MD5SIG - const __u8 *hash_location = NULL; - struct ipv6hdr *ipv6h = ipv6_hdr(skb); - unsigned char newhash[16]; - int genhash; - struct sock *sk1 = NULL; -#endif - int oif; - - if (th->rst) - return; - - /* If sk not NULL, it means we did a successful lookup and incoming - * route had to be correct. prequeue might have dropped our dst. - */ - if (!sk && !ipv6_unicast_destination(skb)) - return; - -#ifdef CONFIG_TCP_MD5SIG - rcu_read_lock(); - hash_location = tcp_parse_md5sig_option(th); - if (sk && sk_fullsock(sk)) { - key = tcp_v6_md5_do_lookup(sk, &ipv6h->saddr); - } else if (hash_location) { - /* - * active side is lost. Try to find listening socket through - * source port, and then find md5 key through listening socket. - * we are not loose security here: - * Incoming packet is checked with md5 hash with finding key, - * no RST generated if md5 hash doesn't match. - */ - sk1 = inet6_lookup_listener(dev_net(skb_dst(skb)->dev), - &tcp_hashinfo, NULL, 0, - &ipv6h->saddr, - th->source, &ipv6h->daddr, - ntohs(th->source), tcp_v6_iif(skb)); - if (!sk1) - goto out; - - key = tcp_v6_md5_do_lookup(sk1, &ipv6h->saddr); - if (!key) - goto out; - - genhash = tcp_v6_md5_hash_skb(newhash, key, NULL, skb); - if (genhash || memcmp(hash_location, newhash, 16) != 0) - goto out; - } -#endif - - if (th->ack) - seq = ntohl(th->ack_seq); - else - ack_seq = ntohl(th->seq) + th->syn + th->fin + skb->len - - (th->doff << 2); - - oif = sk ? sk->sk_bound_dev_if : 0; - tcp_v6_send_response(sk, skb, seq, ack_seq, 0, 0, 0, oif, key, 1, 0, 0); - -#ifdef CONFIG_TCP_MD5SIG -out: - rcu_read_unlock(); -#endif -} - -static void tcp_v6_send_ack(const struct sock *sk, struct sk_buff *skb, u32 seq, - u32 ack, u32 win, u32 tsval, u32 tsecr, int oif, - struct tcp_md5sig_key *key, u8 tclass, - __be32 label) -{ - tcp_v6_send_response(sk, skb, seq, ack, win, tsval, tsecr, oif, key, 0, - tclass, label); -} - -static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) -{ - struct inet_timewait_sock *tw = inet_twsk(sk); - struct tcp_timewait_sock *tcptw = tcp_twsk(sk); - - tcp_v6_send_ack(sk, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, - tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, - tcp_time_stamp + tcptw->tw_ts_offset, - tcptw->tw_ts_recent, tw->tw_bound_dev_if, tcp_twsk_md5_key(tcptw), - tw->tw_tclass, cpu_to_be32(tw->tw_flowlabel)); - - inet_twsk_put(tw); -} - -static void tcp_v6_reqsk_send_ack(const struct sock *sk, struct sk_buff *skb, - struct request_sock *req) -{ - /* sk->sk_state == TCP_LISTEN -> for regular TCP_SYN_RECV - * sk->sk_state == TCP_SYN_RECV -> for Fast Open. - */ - /* RFC 7323 2.3 - * The window field (SEG.WND) of every outgoing segment, with the - * exception of segments, MUST be right-shifted by - * Rcv.Wind.Shift bits: - */ - tcp_v6_send_ack(sk, skb, (sk->sk_state == TCP_LISTEN) ? - tcp_rsk(req)->snt_isn + 1 : tcp_sk(sk)->snd_nxt, - tcp_rsk(req)->rcv_nxt, - req->rsk_rcv_wnd >> inet_rsk(req)->rcv_wscale, - tcp_time_stamp, req->ts_recent, sk->sk_bound_dev_if, - tcp_v6_md5_do_lookup(sk, &ipv6_hdr(skb)->daddr), - 0, 0); -} - - -static struct sock *tcp_v6_cookie_check(struct sock *sk, struct sk_buff *skb) -{ -#ifdef CONFIG_SYN_COOKIES - const struct tcphdr *th = tcp_hdr(skb); - - if (!th->syn) - sk = cookie_v6_check(sk, skb); -#endif - return sk; -} - -static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) -{ - if (skb->protocol == htons(ETH_P_IP)) - return tcp_v4_conn_request(sk, skb); - - if (!ipv6_unicast_destination(skb)) - goto drop; - - return tcp_conn_request(&tcp6_request_sock_ops, - &tcp_request_sock_ipv6_ops, sk, skb); - -drop: - tcp_listendrop(sk); - return 0; /* don't send reset */ -} - -static struct sock *tcp_v6_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, - struct request_sock *req, - struct dst_entry *dst, - struct request_sock *req_unhash, - bool *own_req) -{ - struct inet_request_sock *ireq; - struct ipv6_pinfo *newnp; - const struct ipv6_pinfo *np = inet6_sk(sk); - struct ipv6_txoptions *opt; - struct tcp6_sock *newtcp6sk; - struct inet_sock *newinet; - struct tcp_sock *newtp; - struct sock *newsk; -#ifdef CONFIG_TCP_MD5SIG - struct tcp_md5sig_key *key; -#endif - struct flowi6 fl6; - - if (skb->protocol == htons(ETH_P_IP)) { - /* - * v6 mapped - */ - - newsk = tcp_v4_syn_recv_sock(sk, skb, req, dst, - req_unhash, own_req); - - if (!newsk) - return NULL; - - newtcp6sk = (struct tcp6_sock *)newsk; - inet_sk(newsk)->pinet6 = &newtcp6sk->inet6; - - newinet = inet_sk(newsk); - newnp = inet6_sk(newsk); - newtp = tcp_sk(newsk); - - memcpy(newnp, np, sizeof(struct ipv6_pinfo)); - - newnp->saddr = newsk->sk_v6_rcv_saddr; - - inet_csk(newsk)->icsk_af_ops = &ipv6_mapped; - newsk->sk_backlog_rcv = tcp_v4_do_rcv; -#ifdef CONFIG_TCP_MD5SIG - newtp->af_specific = &tcp_sock_ipv6_mapped_specific; -#endif - - newnp->ipv6_ac_list = NULL; - newnp->ipv6_fl_list = NULL; - newnp->pktoptions = NULL; - newnp->opt = NULL; - newnp->mcast_oif = tcp_v6_iif(skb); - newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; - newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb)); - if (np->repflow) - newnp->flow_label = ip6_flowlabel(ipv6_hdr(skb)); - - /* - * No need to charge this sock to the relevant IPv6 refcnt debug socks count - * here, tcp_create_openreq_child now does this for us, see the comment in - * that function for the gory details. -acme - */ - - /* It is tricky place. Until this moment IPv4 tcp - worked with IPv6 icsk.icsk_af_ops. - Sync it now. - */ - tcp_sync_mss(newsk, inet_csk(newsk)->icsk_pmtu_cookie); - - return newsk; - } - - ireq = inet_rsk(req); - - if (sk_acceptq_is_full(sk)) - goto out_overflow; - - if (!dst) { - dst = inet6_csk_route_req(sk, &fl6, req, IPPROTO_TCP); - if (!dst) - goto out; - } - - newsk = tcp_create_openreq_child(sk, req, skb); - if (!newsk) - goto out_nonewsk; - - /* - * No need to charge this sock to the relevant IPv6 refcnt debug socks - * count here, tcp_create_openreq_child now does this for us, see the - * comment in that function for the gory details. -acme - */ - - newsk->sk_gso_type = SKB_GSO_TCPV6; - ip6_dst_store(newsk, dst, NULL, NULL); - inet6_sk_rx_dst_set(newsk, skb); - - newtcp6sk = (struct tcp6_sock *)newsk; - inet_sk(newsk)->pinet6 = &newtcp6sk->inet6; - - newtp = tcp_sk(newsk); - newinet = inet_sk(newsk); - newnp = inet6_sk(newsk); - - memcpy(newnp, np, sizeof(struct ipv6_pinfo)); - - newsk->sk_v6_daddr = ireq->ir_v6_rmt_addr; - newnp->saddr = ireq->ir_v6_loc_addr; - newsk->sk_v6_rcv_saddr = ireq->ir_v6_loc_addr; - newsk->sk_bound_dev_if = ireq->ir_iif; - - /* Now IPv6 options... - - First: no IPv4 options. - */ - newinet->inet_opt = NULL; - newnp->ipv6_ac_list = NULL; - newnp->ipv6_fl_list = NULL; - - /* Clone RX bits */ - newnp->rxopt.all = np->rxopt.all; - - newnp->pktoptions = NULL; - newnp->opt = NULL; - newnp->mcast_oif = tcp_v6_iif(skb); - newnp->mcast_hops = ipv6_hdr(skb)->hop_limit; - newnp->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(skb)); - if (np->repflow) - newnp->flow_label = ip6_flowlabel(ipv6_hdr(skb)); - - /* Clone native IPv6 options from listening socket (if any) - - Yes, keeping reference count would be much more clever, - but we make one more one thing there: reattach optmem - to newsk. - */ - opt = ireq->ipv6_opt; - if (!opt) - opt = rcu_dereference(np->opt); - if (opt) { - opt = ipv6_dup_options(newsk, opt); - RCU_INIT_POINTER(newnp->opt, opt); - } - inet_csk(newsk)->icsk_ext_hdr_len = 0; - if (opt) - inet_csk(newsk)->icsk_ext_hdr_len = opt->opt_nflen + - opt->opt_flen; - - tcp_ca_openreq_child(newsk, dst); - - tcp_sync_mss(newsk, dst_mtu(dst)); - newtp->advmss = dst_metric_advmss(dst); - if (tcp_sk(sk)->rx_opt.user_mss && - tcp_sk(sk)->rx_opt.user_mss < newtp->advmss) - newtp->advmss = tcp_sk(sk)->rx_opt.user_mss; - - tcp_initialize_rcv_mss(newsk); - - newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6; - newinet->inet_rcv_saddr = LOOPBACK4_IPV6; - -#ifdef CONFIG_TCP_MD5SIG - /* Copy over the MD5 key from the original socket */ - key = tcp_v6_md5_do_lookup(sk, &newsk->sk_v6_daddr); - if (key) { - /* We're using one, so create a matching key - * on the newsk structure. If we fail to get - * memory, then we end up not copying the key - * across. Shucks. - */ - tcp_md5_do_add(newsk, (union tcp_md5_addr *)&newsk->sk_v6_daddr, - AF_INET6, key->key, key->keylen, - sk_gfp_mask(sk, GFP_ATOMIC)); - } -#endif - - if (__inet_inherit_port(sk, newsk) < 0) { - inet_csk_prepare_forced_close(newsk); - tcp_done(newsk); - goto out; - } - *own_req = inet_ehash_nolisten(newsk, req_to_sk(req_unhash)); - if (*own_req) { - tcp_move_syn(newtp, req); - - /* Clone pktoptions received with SYN, if we own the req */ - if (ireq->pktopts) { - newnp->pktoptions = skb_clone(ireq->pktopts, - sk_gfp_mask(sk, GFP_ATOMIC)); - consume_skb(ireq->pktopts); - ireq->pktopts = NULL; - if (newnp->pktoptions) - skb_set_owner_r(newnp->pktoptions, newsk); - } - } - - return newsk; - -out_overflow: - __NET_INC_STATS(sock_net(sk), LINUX_MIB_LISTENOVERFLOWS); -out_nonewsk: - dst_release(dst); -out: - tcp_listendrop(sk); - return NULL; -} - -static void tcp_v6_restore_cb(struct sk_buff *skb) -{ - /* We need to move header back to the beginning if xfrm6_policy_check() - * and tcp_v6_fill_cb() are going to be called again. - * ip6_datagram_recv_specific_ctl() also expects IP6CB to be there. - */ - memmove(IP6CB(skb), &TCP_SKB_CB(skb)->header.h6, - sizeof(struct inet6_skb_parm)); -} - -/* The socket must have it's spinlock held when we get - * here, unless it is a TCP_LISTEN socket. - * - * We have a potential double-lock case here, so even when - * doing backlog processing we use the BH locking scheme. - * This is because we cannot sleep with the original spinlock - * held. - */ -static int tcp_v6_do_rcv(struct sock *sk, struct sk_buff *skb) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct tcp_sock *tp; - struct sk_buff *opt_skb = NULL; - - /* Imagine: socket is IPv6. IPv4 packet arrives, - goes to IPv4 receive handler and backlogged. - From backlog it always goes here. Kerboom... - Fortunately, tcp_rcv_established and rcv_established - handle them correctly, but it is not case with - tcp_v6_hnd_req and tcp_v6_send_reset(). --ANK - */ - - if (skb->protocol == htons(ETH_P_IP)) - return tcp_v4_do_rcv(sk, skb); - - if (tcp_filter(sk, skb)) - goto discard; - - /* - * socket locking is here for SMP purposes as backlog rcv - * is currently called with bh processing disabled. - */ - - /* Do Stevens' IPV6_PKTOPTIONS. - - Yes, guys, it is the only place in our code, where we - may make it not affecting IPv4. - The rest of code is protocol independent, - and I do not like idea to uglify IPv4. - - Actually, all the idea behind IPV6_PKTOPTIONS - looks not very well thought. For now we latch - options, received in the last packet, enqueued - by tcp. Feel free to propose better solution. - --ANK (980728) - */ - if (np->rxopt.all) - opt_skb = skb_clone(skb, sk_gfp_mask(sk, GFP_ATOMIC)); - - if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ - struct dst_entry *dst = sk->sk_rx_dst; - - sock_rps_save_rxhash(sk, skb); - sk_mark_napi_id(sk, skb); - if (dst) { - if (inet_sk(sk)->rx_dst_ifindex != skb->skb_iif || - dst->ops->check(dst, np->rx_dst_cookie) == NULL) { - dst_release(dst); - sk->sk_rx_dst = NULL; - } - } - - tcp_rcv_established(sk, skb, tcp_hdr(skb), skb->len); - if (opt_skb) - goto ipv6_pktoptions; - return 0; - } - - if (tcp_checksum_complete(skb)) - goto csum_err; - - if (sk->sk_state == TCP_LISTEN) { - struct sock *nsk = tcp_v6_cookie_check(sk, skb); - - if (!nsk) - goto discard; - - if (nsk != sk) { - sock_rps_save_rxhash(nsk, skb); - sk_mark_napi_id(nsk, skb); - if (tcp_child_process(sk, nsk, skb)) - goto reset; - if (opt_skb) - __kfree_skb(opt_skb); - return 0; - } - } else - sock_rps_save_rxhash(sk, skb); - - if (tcp_rcv_state_process(sk, skb)) - goto reset; - if (opt_skb) - goto ipv6_pktoptions; - return 0; - -reset: - tcp_v6_send_reset(sk, skb); -discard: - if (opt_skb) - __kfree_skb(opt_skb); - kfree_skb(skb); - return 0; -csum_err: - TCP_INC_STATS(sock_net(sk), TCP_MIB_CSUMERRORS); - TCP_INC_STATS(sock_net(sk), TCP_MIB_INERRS); - goto discard; - - -ipv6_pktoptions: - /* Do you ask, what is it? - - 1. skb was enqueued by tcp. - 2. skb is added to tail of read queue, rather than out of order. - 3. socket is not in passive state. - 4. Finally, it really contains options, which user wants to receive. - */ - tp = tcp_sk(sk); - if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt && - !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) { - if (np->rxopt.bits.rxinfo || np->rxopt.bits.rxoinfo) - np->mcast_oif = tcp_v6_iif(opt_skb); - if (np->rxopt.bits.rxhlim || np->rxopt.bits.rxohlim) - np->mcast_hops = ipv6_hdr(opt_skb)->hop_limit; - if (np->rxopt.bits.rxflow || np->rxopt.bits.rxtclass) - np->rcv_flowinfo = ip6_flowinfo(ipv6_hdr(opt_skb)); - if (np->repflow) - np->flow_label = ip6_flowlabel(ipv6_hdr(opt_skb)); - if (ipv6_opt_accepted(sk, opt_skb, &TCP_SKB_CB(opt_skb)->header.h6)) { - skb_set_owner_r(opt_skb, sk); - tcp_v6_restore_cb(opt_skb); - opt_skb = xchg(&np->pktoptions, opt_skb); - } else { - __kfree_skb(opt_skb); - opt_skb = xchg(&np->pktoptions, NULL); - } - } - - kfree_skb(opt_skb); - return 0; -} - -static void tcp_v6_fill_cb(struct sk_buff *skb, const struct ipv6hdr *hdr, - const struct tcphdr *th) -{ - /* This is tricky: we move IP6CB at its correct location into - * TCP_SKB_CB(). It must be done after xfrm6_policy_check(), because - * _decode_session6() uses IP6CB(). - * barrier() makes sure compiler won't play aliasing games. - */ - memmove(&TCP_SKB_CB(skb)->header.h6, IP6CB(skb), - sizeof(struct inet6_skb_parm)); - barrier(); - - TCP_SKB_CB(skb)->seq = ntohl(th->seq); - TCP_SKB_CB(skb)->end_seq = (TCP_SKB_CB(skb)->seq + th->syn + th->fin + - skb->len - th->doff*4); - TCP_SKB_CB(skb)->ack_seq = ntohl(th->ack_seq); - TCP_SKB_CB(skb)->tcp_flags = tcp_flag_byte(th); - TCP_SKB_CB(skb)->tcp_tw_isn = 0; - TCP_SKB_CB(skb)->ip_dsfield = ipv6_get_dsfield(hdr); - TCP_SKB_CB(skb)->sacked = 0; -} - -static int tcp_v6_rcv(struct sk_buff *skb) -{ - const struct tcphdr *th; - const struct ipv6hdr *hdr; - bool refcounted; - struct sock *sk; - int ret; - struct net *net = dev_net(skb->dev); - - if (skb->pkt_type != PACKET_HOST) - goto discard_it; - - /* - * Count it even if it's bad. - */ - __TCP_INC_STATS(net, TCP_MIB_INSEGS); - - if (!pskb_may_pull(skb, sizeof(struct tcphdr))) - goto discard_it; - - th = (const struct tcphdr *)skb->data; - - if (unlikely(th->doff < sizeof(struct tcphdr)/4)) - goto bad_packet; - if (!pskb_may_pull(skb, th->doff*4)) - goto discard_it; - - if (skb_checksum_init(skb, IPPROTO_TCP, ip6_compute_pseudo)) - goto csum_error; - - th = (const struct tcphdr *)skb->data; - hdr = ipv6_hdr(skb); - -lookup: - sk = __inet6_lookup_skb(&tcp_hashinfo, skb, __tcp_hdrlen(th), - th->source, th->dest, inet6_iif(skb), - &refcounted); - if (!sk) - goto no_tcp_socket; - -process: - if (sk->sk_state == TCP_TIME_WAIT) - goto do_time_wait; - - if (sk->sk_state == TCP_NEW_SYN_RECV) { - struct request_sock *req = inet_reqsk(sk); - struct sock *nsk; - - sk = req->rsk_listener; - tcp_v6_fill_cb(skb, hdr, th); - if (tcp_v6_inbound_md5_hash(sk, skb)) { - sk_drops_add(sk, skb); - reqsk_put(req); - goto discard_it; - } - if (unlikely(sk->sk_state != TCP_LISTEN)) { - inet_csk_reqsk_queue_drop_and_put(sk, req); - goto lookup; - } - sock_hold(sk); - refcounted = true; - nsk = tcp_check_req(sk, skb, req, false); - if (!nsk) { - reqsk_put(req); - goto discard_and_relse; - } - if (nsk == sk) { - reqsk_put(req); - tcp_v6_restore_cb(skb); - } else if (tcp_child_process(sk, nsk, skb)) { - tcp_v6_send_reset(nsk, skb); - goto discard_and_relse; - } else { - sock_put(sk); - return 0; - } - } - if (hdr->hop_limit < inet6_sk(sk)->min_hopcount) { - __NET_INC_STATS(net, LINUX_MIB_TCPMINTTLDROP); - goto discard_and_relse; - } - - if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) - goto discard_and_relse; - - tcp_v6_fill_cb(skb, hdr, th); - - if (tcp_v6_inbound_md5_hash(sk, skb)) - goto discard_and_relse; - - if (tcp_filter(sk, skb)) - goto discard_and_relse; - th = (const struct tcphdr *)skb->data; - hdr = ipv6_hdr(skb); - - skb->dev = NULL; - - if (sk->sk_state == TCP_LISTEN) { - ret = tcp_v6_do_rcv(sk, skb); - goto put_and_return; - } - - sk_incoming_cpu_update(sk); - - bh_lock_sock_nested(sk); - tcp_segs_in(tcp_sk(sk), skb); - ret = 0; - if (!sock_owned_by_user(sk)) { - if (!tcp_prequeue(sk, skb)) - ret = tcp_v6_do_rcv(sk, skb); - } else if (tcp_add_backlog(sk, skb)) { - goto discard_and_relse; - } - bh_unlock_sock(sk); - -put_and_return: - if (refcounted) - sock_put(sk); - return ret ? -1 : 0; - -no_tcp_socket: - if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) - goto discard_it; - - tcp_v6_fill_cb(skb, hdr, th); - - if (tcp_checksum_complete(skb)) { -csum_error: - __TCP_INC_STATS(net, TCP_MIB_CSUMERRORS); -bad_packet: - __TCP_INC_STATS(net, TCP_MIB_INERRS); - } else { - tcp_v6_send_reset(NULL, skb); - } - -discard_it: - kfree_skb(skb); - return 0; - -discard_and_relse: - sk_drops_add(sk, skb); - if (refcounted) - sock_put(sk); - goto discard_it; - -do_time_wait: - if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { - inet_twsk_put(inet_twsk(sk)); - goto discard_it; - } - - tcp_v6_fill_cb(skb, hdr, th); - - if (tcp_checksum_complete(skb)) { - inet_twsk_put(inet_twsk(sk)); - goto csum_error; - } - - switch (tcp_timewait_state_process(inet_twsk(sk), skb, th)) { - case TCP_TW_SYN: - { - struct sock *sk2; - - sk2 = inet6_lookup_listener(dev_net(skb->dev), &tcp_hashinfo, - skb, __tcp_hdrlen(th), - &ipv6_hdr(skb)->saddr, th->source, - &ipv6_hdr(skb)->daddr, - ntohs(th->dest), tcp_v6_iif(skb)); - if (sk2) { - struct inet_timewait_sock *tw = inet_twsk(sk); - inet_twsk_deschedule_put(tw); - sk = sk2; - tcp_v6_restore_cb(skb); - refcounted = false; - goto process; - } - /* Fall through to ACK */ - } - case TCP_TW_ACK: - tcp_v6_timewait_ack(sk, skb); - break; - case TCP_TW_RST: - tcp_v6_restore_cb(skb); - tcp_v6_send_reset(sk, skb); - inet_twsk_deschedule_put(inet_twsk(sk)); - goto discard_it; - case TCP_TW_SUCCESS: - ; - } - goto discard_it; -} - -static void tcp_v6_early_demux(struct sk_buff *skb) -{ - const struct ipv6hdr *hdr; - const struct tcphdr *th; - struct sock *sk; - - if (skb->pkt_type != PACKET_HOST) - return; - - if (!pskb_may_pull(skb, skb_transport_offset(skb) + sizeof(struct tcphdr))) - return; - - hdr = ipv6_hdr(skb); - th = tcp_hdr(skb); - - if (th->doff < sizeof(struct tcphdr) / 4) - return; - - /* Note : We use inet6_iif() here, not tcp_v6_iif() */ - sk = __inet6_lookup_established(dev_net(skb->dev), &tcp_hashinfo, - &hdr->saddr, th->source, - &hdr->daddr, ntohs(th->dest), - inet6_iif(skb)); - if (sk) { - skb->sk = sk; - skb->destructor = sock_edemux; - if (sk_fullsock(sk)) { - struct dst_entry *dst = READ_ONCE(sk->sk_rx_dst); - - if (dst) - dst = dst_check(dst, inet6_sk(sk)->rx_dst_cookie); - if (dst && - inet_sk(sk)->rx_dst_ifindex == skb->skb_iif) - skb_dst_set_noref(skb, dst); - } - } -} - -static struct timewait_sock_ops tcp6_timewait_sock_ops = { - .twsk_obj_size = sizeof(struct tcp6_timewait_sock), - .twsk_unique = tcp_twsk_unique, - .twsk_destructor = tcp_twsk_destructor, -}; - -static const struct inet_connection_sock_af_ops ipv6_specific = { - .queue_xmit = inet6_csk_xmit, - .send_check = tcp_v6_send_check, - .rebuild_header = inet6_sk_rebuild_header, - .sk_rx_dst_set = inet6_sk_rx_dst_set, - .conn_request = tcp_v6_conn_request, - .syn_recv_sock = tcp_v6_syn_recv_sock, - .net_header_len = sizeof(struct ipv6hdr), - .net_frag_header_len = sizeof(struct frag_hdr), - .setsockopt = ipv6_setsockopt, - .getsockopt = ipv6_getsockopt, - .addr2sockaddr = inet6_csk_addr2sockaddr, - .sockaddr_len = sizeof(struct sockaddr_in6), - .bind_conflict = inet6_csk_bind_conflict, -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_ipv6_setsockopt, - .compat_getsockopt = compat_ipv6_getsockopt, -#endif - .mtu_reduced = tcp_v6_mtu_reduced, -}; - -#ifdef CONFIG_TCP_MD5SIG -static const struct tcp_sock_af_ops tcp_sock_ipv6_specific = { - .md5_lookup = tcp_v6_md5_lookup, - .calc_md5_hash = tcp_v6_md5_hash_skb, - .md5_parse = tcp_v6_parse_md5_keys, -}; -#endif - -/* - * TCP over IPv4 via INET6 API - */ -static const struct inet_connection_sock_af_ops ipv6_mapped = { - .queue_xmit = ip_queue_xmit, - .send_check = tcp_v4_send_check, - .rebuild_header = inet_sk_rebuild_header, - .sk_rx_dst_set = inet_sk_rx_dst_set, - .conn_request = tcp_v6_conn_request, - .syn_recv_sock = tcp_v6_syn_recv_sock, - .net_header_len = sizeof(struct iphdr), - .setsockopt = ipv6_setsockopt, - .getsockopt = ipv6_getsockopt, - .addr2sockaddr = inet6_csk_addr2sockaddr, - .sockaddr_len = sizeof(struct sockaddr_in6), - .bind_conflict = inet6_csk_bind_conflict, -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_ipv6_setsockopt, - .compat_getsockopt = compat_ipv6_getsockopt, -#endif - .mtu_reduced = tcp_v4_mtu_reduced, -}; - -#ifdef CONFIG_TCP_MD5SIG -static const struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific = { - .md5_lookup = tcp_v4_md5_lookup, - .calc_md5_hash = tcp_v4_md5_hash_skb, - .md5_parse = tcp_v6_parse_md5_keys, -}; -#endif - -/* NOTE: A lot of things set to zero explicitly by call to - * sk_alloc() so need not be done here. - */ -static int tcp_v6_init_sock(struct sock *sk) -{ - struct inet_connection_sock *icsk = inet_csk(sk); - - tcp_init_sock(sk); - - icsk->icsk_af_ops = &ipv6_specific; - -#ifdef CONFIG_TCP_MD5SIG - tcp_sk(sk)->af_specific = &tcp_sock_ipv6_specific; -#endif - - return 0; -} - -static void tcp_v6_destroy_sock(struct sock *sk) -{ - tcp_v4_destroy_sock(sk); - inet6_destroy_sock(sk); -} - -#ifdef CONFIG_PROC_FS -/* Proc filesystem TCPv6 sock list dumping. */ -static void get_openreq6(struct seq_file *seq, - const struct request_sock *req, int i) -{ - long ttd = req->rsk_timer.expires - jiffies; - const struct in6_addr *src = &inet_rsk(req)->ir_v6_loc_addr; - const struct in6_addr *dest = &inet_rsk(req)->ir_v6_rmt_addr; - - if (ttd < 0) - ttd = 0; - - seq_printf(seq, - "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " - "%02X %08X:%08X %02X:%08lX %08X %5u %8d %d %d %pK\n", - i, - src->s6_addr32[0], src->s6_addr32[1], - src->s6_addr32[2], src->s6_addr32[3], - inet_rsk(req)->ir_num, - dest->s6_addr32[0], dest->s6_addr32[1], - dest->s6_addr32[2], dest->s6_addr32[3], - ntohs(inet_rsk(req)->ir_rmt_port), - TCP_SYN_RECV, - 0, 0, /* could print option size, but that is af dependent. */ - 1, /* timers active (only the expire timer) */ - jiffies_to_clock_t(ttd), - req->num_timeout, - from_kuid_munged(seq_user_ns(seq), - sock_i_uid(req->rsk_listener)), - 0, /* non standard timer */ - 0, /* open_requests have no inode */ - 0, req); -} - -static void get_tcp6_sock(struct seq_file *seq, struct sock *sp, int i) -{ - const struct in6_addr *dest, *src; - __u16 destp, srcp; - int timer_active; - unsigned long timer_expires; - const struct inet_sock *inet = inet_sk(sp); - const struct tcp_sock *tp = tcp_sk(sp); - const struct inet_connection_sock *icsk = inet_csk(sp); - const struct fastopen_queue *fastopenq = &icsk->icsk_accept_queue.fastopenq; - int rx_queue; - int state; - - dest = &sp->sk_v6_daddr; - src = &sp->sk_v6_rcv_saddr; - destp = ntohs(inet->inet_dport); - srcp = ntohs(inet->inet_sport); - - if (icsk->icsk_pending == ICSK_TIME_RETRANS || - icsk->icsk_pending == ICSK_TIME_EARLY_RETRANS || - icsk->icsk_pending == ICSK_TIME_LOSS_PROBE) { - timer_active = 1; - timer_expires = icsk->icsk_timeout; - } else if (icsk->icsk_pending == ICSK_TIME_PROBE0) { - timer_active = 4; - timer_expires = icsk->icsk_timeout; - } else if (timer_pending(&sp->sk_timer)) { - timer_active = 2; - timer_expires = sp->sk_timer.expires; - } else { - timer_active = 0; - timer_expires = jiffies; - } - - state = sk_state_load(sp); - if (state == TCP_LISTEN) - rx_queue = sp->sk_ack_backlog; - else - /* Because we don't lock the socket, - * we might find a transient negative value. - */ - rx_queue = max_t(int, tp->rcv_nxt - tp->copied_seq, 0); - - seq_printf(seq, - "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " - "%02X %08X:%08X %02X:%08lX %08X %5u %8d %lu %d %pK %lu %lu %u %u %d\n", - i, - src->s6_addr32[0], src->s6_addr32[1], - src->s6_addr32[2], src->s6_addr32[3], srcp, - dest->s6_addr32[0], dest->s6_addr32[1], - dest->s6_addr32[2], dest->s6_addr32[3], destp, - state, - tp->write_seq - tp->snd_una, - rx_queue, - timer_active, - jiffies_delta_to_clock_t(timer_expires - jiffies), - icsk->icsk_retransmits, - from_kuid_munged(seq_user_ns(seq), sock_i_uid(sp)), - icsk->icsk_probes_out, - sock_i_ino(sp), - atomic_read(&sp->sk_refcnt), sp, - jiffies_to_clock_t(icsk->icsk_rto), - jiffies_to_clock_t(icsk->icsk_ack.ato), - (icsk->icsk_ack.quick << 1) | icsk->icsk_ack.pingpong, - tp->snd_cwnd, - state == TCP_LISTEN ? - fastopenq->max_qlen : - (tcp_in_initial_slowstart(tp) ? -1 : tp->snd_ssthresh) - ); -} - -static void get_timewait6_sock(struct seq_file *seq, - struct inet_timewait_sock *tw, int i) -{ - long delta = tw->tw_timer.expires - jiffies; - const struct in6_addr *dest, *src; - __u16 destp, srcp; - - dest = &tw->tw_v6_daddr; - src = &tw->tw_v6_rcv_saddr; - destp = ntohs(tw->tw_dport); - srcp = ntohs(tw->tw_sport); - - seq_printf(seq, - "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " - "%02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %pK\n", - i, - src->s6_addr32[0], src->s6_addr32[1], - src->s6_addr32[2], src->s6_addr32[3], srcp, - dest->s6_addr32[0], dest->s6_addr32[1], - dest->s6_addr32[2], dest->s6_addr32[3], destp, - tw->tw_substate, 0, 0, - 3, jiffies_delta_to_clock_t(delta), 0, 0, 0, 0, - atomic_read(&tw->tw_refcnt), tw); -} - -static int tcp6_seq_show(struct seq_file *seq, void *v) -{ - struct tcp_iter_state *st; - struct sock *sk = v; - - if (v == SEQ_START_TOKEN) { - seq_puts(seq, - " sl " - "local_address " - "remote_address " - "st tx_queue rx_queue tr tm->when retrnsmt" - " uid timeout inode\n"); - goto out; - } - st = seq->private; - - if (sk->sk_state == TCP_TIME_WAIT) - get_timewait6_sock(seq, v, st->num); - else if (sk->sk_state == TCP_NEW_SYN_RECV) - get_openreq6(seq, v, st->num); - else - get_tcp6_sock(seq, v, st->num); -out: - return 0; -} - -static const struct file_operations tcp6_afinfo_seq_fops = { - .owner = THIS_MODULE, - .open = tcp_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net -}; - -static struct tcp_seq_afinfo tcp6_seq_afinfo = { - .name = "tcp6", - .family = AF_INET6, - .seq_fops = &tcp6_afinfo_seq_fops, - .seq_ops = { - .show = tcp6_seq_show, - }, -}; - -int __net_init tcp6_proc_init(struct net *net) -{ - return tcp_proc_register(net, &tcp6_seq_afinfo); -} - -void tcp6_proc_exit(struct net *net) -{ - tcp_proc_unregister(net, &tcp6_seq_afinfo); -} -#endif - -struct proto tcpv6_prot = { - .name = "TCPv6", - .owner = THIS_MODULE, - .close = tcp_close, - .connect = tcp_v6_connect, - .disconnect = tcp_disconnect, - .accept = inet_csk_accept, - .ioctl = tcp_ioctl, - .init = tcp_v6_init_sock, - .destroy = tcp_v6_destroy_sock, - .shutdown = tcp_shutdown, - .setsockopt = tcp_setsockopt, - .getsockopt = tcp_getsockopt, - .recvmsg = tcp_recvmsg, - .sendmsg = tcp_sendmsg, - .sendpage = tcp_sendpage, - .backlog_rcv = tcp_v6_do_rcv, - .release_cb = tcp_release_cb, - .hash = inet6_hash, - .unhash = inet_unhash, - .get_port = inet_csk_get_port, - .enter_memory_pressure = tcp_enter_memory_pressure, - .stream_memory_free = tcp_stream_memory_free, - .sockets_allocated = &tcp_sockets_allocated, - .memory_allocated = &tcp_memory_allocated, - .memory_pressure = &tcp_memory_pressure, - .orphan_count = &tcp_orphan_count, - .sysctl_mem = sysctl_tcp_mem, - .sysctl_wmem = sysctl_tcp_wmem, - .sysctl_rmem = sysctl_tcp_rmem, - .max_header = MAX_TCP_HEADER, - .obj_size = sizeof(struct tcp6_sock), - .slab_flags = SLAB_DESTROY_BY_RCU, - .twsk_prot = &tcp6_timewait_sock_ops, - .rsk_prot = &tcp6_request_sock_ops, - .h.hashinfo = &tcp_hashinfo, - .no_autobind = true, -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_tcp_setsockopt, - .compat_getsockopt = compat_tcp_getsockopt, -#endif - .diag_destroy = tcp_abort, -}; - -static const struct inet6_protocol tcpv6_protocol = { - .early_demux = tcp_v6_early_demux, - .handler = tcp_v6_rcv, - .err_handler = tcp_v6_err, - .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, -}; - -static struct inet_protosw tcpv6_protosw = { - .type = SOCK_STREAM, - .protocol = IPPROTO_TCP, - .prot = &tcpv6_prot, - .ops = &inet6_stream_ops, - .flags = INET_PROTOSW_PERMANENT | - INET_PROTOSW_ICSK, -}; - -static int __net_init tcpv6_net_init(struct net *net) -{ - return inet_ctl_sock_create(&net->ipv6.tcp_sk, PF_INET6, - SOCK_RAW, IPPROTO_TCP, net); -} - -static void __net_exit tcpv6_net_exit(struct net *net) -{ - inet_ctl_sock_destroy(net->ipv6.tcp_sk); -} - -static void __net_exit tcpv6_net_exit_batch(struct list_head *net_exit_list) -{ - inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6); -} - -static struct pernet_operations tcpv6_net_ops = { - .init = tcpv6_net_init, - .exit = tcpv6_net_exit, - .exit_batch = tcpv6_net_exit_batch, -}; - -int __init tcpv6_init(void) -{ - int ret; - - ret = inet6_add_protocol(&tcpv6_protocol, IPPROTO_TCP); - if (ret) - goto out; - - /* register inet6 protocol */ - ret = inet6_register_protosw(&tcpv6_protosw); - if (ret) - goto out_tcpv6_protocol; - - ret = register_pernet_subsys(&tcpv6_net_ops); - if (ret) - goto out_tcpv6_protosw; -out: - return ret; - -out_tcpv6_protosw: - inet6_unregister_protosw(&tcpv6_protosw); -out_tcpv6_protocol: - inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP); - goto out; -} - -void tcpv6_exit(void) -{ - unregister_pernet_subsys(&tcpv6_net_ops); - inet6_unregister_protosw(&tcpv6_protosw); - inet6_del_protocol(&tcpv6_protocol, IPPROTO_TCP); -} diff --git a/src/linux/net/ipv6/tcpv6_offload.c b/src/linux/net/ipv6/tcpv6_offload.c deleted file mode 100644 index d883c92..0000000 --- a/src/linux/net/ipv6/tcpv6_offload.c +++ /dev/null @@ -1,78 +0,0 @@ -/* - * IPV6 GSO/GRO offload support - * Linux INET6 implementation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * TCPv6 GSO/GRO support - */ -#include -#include -#include -#include -#include "ip6_offload.h" - -static struct sk_buff **tcp6_gro_receive(struct sk_buff **head, - struct sk_buff *skb) -{ - /* Don't bother verifying checksum if we're going to flush anyway. */ - if (!NAPI_GRO_CB(skb)->flush && - skb_gro_checksum_validate(skb, IPPROTO_TCP, - ip6_gro_compute_pseudo)) { - NAPI_GRO_CB(skb)->flush = 1; - return NULL; - } - - return tcp_gro_receive(head, skb); -} - -static int tcp6_gro_complete(struct sk_buff *skb, int thoff) -{ - const struct ipv6hdr *iph = ipv6_hdr(skb); - struct tcphdr *th = tcp_hdr(skb); - - th->check = ~tcp_v6_check(skb->len - thoff, &iph->saddr, - &iph->daddr, 0); - skb_shinfo(skb)->gso_type |= SKB_GSO_TCPV6; - - return tcp_gro_complete(skb); -} - -static struct sk_buff *tcp6_gso_segment(struct sk_buff *skb, - netdev_features_t features) -{ - struct tcphdr *th; - - if (!pskb_may_pull(skb, sizeof(*th))) - return ERR_PTR(-EINVAL); - - if (unlikely(skb->ip_summed != CHECKSUM_PARTIAL)) { - const struct ipv6hdr *ipv6h = ipv6_hdr(skb); - struct tcphdr *th = tcp_hdr(skb); - - /* Set up pseudo header, usually expect stack to have done - * this. - */ - - th->check = 0; - skb->ip_summed = CHECKSUM_PARTIAL; - __tcp_v6_send_check(skb, &ipv6h->saddr, &ipv6h->daddr); - } - - return tcp_gso_segment(skb, features); -} -static const struct net_offload tcpv6_offload = { - .callbacks = { - .gso_segment = tcp6_gso_segment, - .gro_receive = tcp6_gro_receive, - .gro_complete = tcp6_gro_complete, - }, -}; - -int __init tcpv6_offload_init(void) -{ - return inet6_add_offload(&tcpv6_offload, IPPROTO_TCP); -} diff --git a/src/linux/net/ipv6/udp.c b/src/linux/net/ipv6/udp.c deleted file mode 100644 index e4a8000..0000000 --- a/src/linux/net/ipv6/udp.c +++ /dev/null @@ -1,1492 +0,0 @@ -/* - * UDP over IPv6 - * Linux INET6 implementation - * - * Authors: - * Pedro Roque - * - * Based on linux/ipv4/udp.c - * - * Fixes: - * Hideaki YOSHIFUJI : sin6_scope_id support - * YOSHIFUJI Hideaki @USAGI and: Support IPV6_V6ONLY socket option, which - * Alexey Kuznetsov allow both IPv4 and IPv6 sockets to bind - * a single port at the same time. - * Kazunori MIYAZAWA @USAGI: change process style to use ip6_append_data - * YOSHIFUJI Hideaki @USAGI: convert /proc/net/udp6 to seq_file. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#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 -#include -#include -#include "udp_impl.h" - -static u32 udp6_ehashfn(const struct net *net, - const struct in6_addr *laddr, - const u16 lport, - const struct in6_addr *faddr, - const __be16 fport) -{ - static u32 udp6_ehash_secret __read_mostly; - static u32 udp_ipv6_hash_secret __read_mostly; - - u32 lhash, fhash; - - net_get_random_once(&udp6_ehash_secret, - sizeof(udp6_ehash_secret)); - net_get_random_once(&udp_ipv6_hash_secret, - sizeof(udp_ipv6_hash_secret)); - - lhash = (__force u32)laddr->s6_addr32[3]; - fhash = __ipv6_addr_jhash(faddr, udp_ipv6_hash_secret); - - return __inet6_ehashfn(lhash, lport, fhash, fport, - udp_ipv6_hash_secret + net_hash_mix(net)); -} - -static u32 udp6_portaddr_hash(const struct net *net, - const struct in6_addr *addr6, - unsigned int port) -{ - unsigned int hash, mix = net_hash_mix(net); - - if (ipv6_addr_any(addr6)) - hash = jhash_1word(0, mix); - else if (ipv6_addr_v4mapped(addr6)) - hash = jhash_1word((__force u32)addr6->s6_addr32[3], mix); - else - hash = jhash2((__force u32 *)addr6->s6_addr32, 4, mix); - - return hash ^ port; -} - -int udp_v6_get_port(struct sock *sk, unsigned short snum) -{ - unsigned int hash2_nulladdr = - udp6_portaddr_hash(sock_net(sk), &in6addr_any, snum); - unsigned int hash2_partial = - udp6_portaddr_hash(sock_net(sk), &sk->sk_v6_rcv_saddr, 0); - - /* precompute partial secondary hash */ - udp_sk(sk)->udp_portaddr_hash = hash2_partial; - return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal, hash2_nulladdr); -} - -static void udp_v6_rehash(struct sock *sk) -{ - u16 new_hash = udp6_portaddr_hash(sock_net(sk), - &sk->sk_v6_rcv_saddr, - inet_sk(sk)->inet_num); - - udp_lib_rehash(sk, new_hash); -} - -static int compute_score(struct sock *sk, struct net *net, - const struct in6_addr *saddr, __be16 sport, - const struct in6_addr *daddr, unsigned short hnum, - int dif) -{ - int score; - struct inet_sock *inet; - - if (!net_eq(sock_net(sk), net) || - udp_sk(sk)->udp_port_hash != hnum || - sk->sk_family != PF_INET6) - return -1; - - score = 0; - inet = inet_sk(sk); - - if (inet->inet_dport) { - if (inet->inet_dport != sport) - return -1; - score++; - } - - if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr)) { - if (!ipv6_addr_equal(&sk->sk_v6_rcv_saddr, daddr)) - return -1; - score++; - } - - if (!ipv6_addr_any(&sk->sk_v6_daddr)) { - if (!ipv6_addr_equal(&sk->sk_v6_daddr, saddr)) - return -1; - score++; - } - - if (sk->sk_bound_dev_if) { - if (sk->sk_bound_dev_if != dif) - return -1; - score++; - } - - if (sk->sk_incoming_cpu == raw_smp_processor_id()) - score++; - - return score; -} - -/* called with rcu_read_lock() */ -static struct sock *udp6_lib_lookup2(struct net *net, - const struct in6_addr *saddr, __be16 sport, - const struct in6_addr *daddr, unsigned int hnum, int dif, - struct udp_hslot *hslot2, - struct sk_buff *skb) -{ - struct sock *sk, *result; - int score, badness, matches = 0, reuseport = 0; - u32 hash = 0; - - result = NULL; - badness = -1; - udp_portaddr_for_each_entry_rcu(sk, &hslot2->head) { - score = compute_score(sk, net, saddr, sport, - daddr, hnum, dif); - if (score > badness) { - reuseport = sk->sk_reuseport; - if (reuseport) { - hash = udp6_ehashfn(net, daddr, hnum, - saddr, sport); - - result = reuseport_select_sock(sk, hash, skb, - sizeof(struct udphdr)); - if (result) - return result; - matches = 1; - } - result = sk; - badness = score; - } else if (score == badness && reuseport) { - matches++; - if (reciprocal_scale(hash, matches) == 0) - result = sk; - hash = next_pseudo_random32(hash); - } - } - return result; -} - -/* rcu_read_lock() must be held */ -struct sock *__udp6_lib_lookup(struct net *net, - const struct in6_addr *saddr, __be16 sport, - const struct in6_addr *daddr, __be16 dport, - int dif, struct udp_table *udptable, - struct sk_buff *skb) -{ - struct sock *sk, *result; - unsigned short hnum = ntohs(dport); - unsigned int hash2, slot2, slot = udp_hashfn(net, hnum, udptable->mask); - struct udp_hslot *hslot2, *hslot = &udptable->hash[slot]; - int score, badness, matches = 0, reuseport = 0; - u32 hash = 0; - - if (hslot->count > 10) { - hash2 = udp6_portaddr_hash(net, daddr, hnum); - slot2 = hash2 & udptable->mask; - hslot2 = &udptable->hash2[slot2]; - if (hslot->count < hslot2->count) - goto begin; - - result = udp6_lib_lookup2(net, saddr, sport, - daddr, hnum, dif, - hslot2, skb); - if (!result) { - unsigned int old_slot2 = slot2; - hash2 = udp6_portaddr_hash(net, &in6addr_any, hnum); - slot2 = hash2 & udptable->mask; - /* avoid searching the same slot again. */ - if (unlikely(slot2 == old_slot2)) - return result; - - hslot2 = &udptable->hash2[slot2]; - if (hslot->count < hslot2->count) - goto begin; - - result = udp6_lib_lookup2(net, saddr, sport, - daddr, hnum, dif, - hslot2, skb); - } - return result; - } -begin: - result = NULL; - badness = -1; - sk_for_each_rcu(sk, &hslot->head) { - score = compute_score(sk, net, saddr, sport, daddr, hnum, dif); - if (score > badness) { - reuseport = sk->sk_reuseport; - if (reuseport) { - hash = udp6_ehashfn(net, daddr, hnum, - saddr, sport); - result = reuseport_select_sock(sk, hash, skb, - sizeof(struct udphdr)); - if (result) - return result; - matches = 1; - } - result = sk; - badness = score; - } else if (score == badness && reuseport) { - matches++; - if (reciprocal_scale(hash, matches) == 0) - result = sk; - hash = next_pseudo_random32(hash); - } - } - return result; -} -EXPORT_SYMBOL_GPL(__udp6_lib_lookup); - -static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb, - __be16 sport, __be16 dport, - struct udp_table *udptable) -{ - const struct ipv6hdr *iph = ipv6_hdr(skb); - struct sock *sk; - - sk = skb_steal_sock(skb); - if (unlikely(sk)) - return sk; - return __udp6_lib_lookup(dev_net(skb->dev), &iph->saddr, sport, - &iph->daddr, dport, inet6_iif(skb), - udptable, skb); -} - -struct sock *udp6_lib_lookup_skb(struct sk_buff *skb, - __be16 sport, __be16 dport) -{ - const struct ipv6hdr *iph = ipv6_hdr(skb); - - return __udp6_lib_lookup(dev_net(skb->dev), &iph->saddr, sport, - &iph->daddr, dport, inet6_iif(skb), - &udp_table, skb); -} -EXPORT_SYMBOL_GPL(udp6_lib_lookup_skb); - -/* Must be called under rcu_read_lock(). - * Does increment socket refcount. - */ -#if IS_ENABLED(CONFIG_NETFILTER_XT_MATCH_SOCKET) || \ - IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TPROXY) -struct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *saddr, __be16 sport, - const struct in6_addr *daddr, __be16 dport, int dif) -{ - struct sock *sk; - - sk = __udp6_lib_lookup(net, saddr, sport, daddr, dport, - dif, &udp_table, NULL); - if (sk && !atomic_inc_not_zero(&sk->sk_refcnt)) - sk = NULL; - return sk; -} -EXPORT_SYMBOL_GPL(udp6_lib_lookup); -#endif - -/* - * This should be easy, if there is something there we - * return it, otherwise we block. - */ - -int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, - int noblock, int flags, int *addr_len) -{ - struct ipv6_pinfo *np = inet6_sk(sk); - struct inet_sock *inet = inet_sk(sk); - struct sk_buff *skb; - unsigned int ulen, copied; - int peeked, peeking, off; - int err; - int is_udplite = IS_UDPLITE(sk); - bool checksum_valid = false; - int is_udp4; - bool slow; - - if (flags & MSG_ERRQUEUE) - return ipv6_recv_error(sk, msg, len, addr_len); - - if (np->rxpmtu && np->rxopt.bits.rxpmtu) - return ipv6_recv_rxpmtu(sk, msg, len, addr_len); - -try_again: - peeking = off = sk_peek_offset(sk, flags); - skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0), - &peeked, &off, &err); - if (!skb) - return err; - - ulen = skb->len; - copied = len; - if (copied > ulen - off) - copied = ulen - off; - else if (copied < ulen) - msg->msg_flags |= MSG_TRUNC; - - is_udp4 = (skb->protocol == htons(ETH_P_IP)); - - /* - * If checksum is needed at all, try to do it while copying the - * data. If the data is truncated, or if we only want a partial - * coverage checksum (UDP-Lite), do it before the copy. - */ - - if (copied < ulen || UDP_SKB_CB(skb)->partial_cov || peeking) { - checksum_valid = !udp_lib_checksum_complete(skb); - if (!checksum_valid) - goto csum_copy_err; - } - - if (checksum_valid || skb_csum_unnecessary(skb)) - err = skb_copy_datagram_msg(skb, off, msg, copied); - else { - err = skb_copy_and_csum_datagram_msg(skb, off, msg); - if (err == -EINVAL) - goto csum_copy_err; - } - if (unlikely(err)) { - trace_kfree_skb(skb, udpv6_recvmsg); - if (!peeked) { - atomic_inc(&sk->sk_drops); - if (is_udp4) - UDP_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, - is_udplite); - else - UDP6_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, - is_udplite); - } - skb_free_datagram_locked(sk, skb); - return err; - } - if (!peeked) { - if (is_udp4) - UDP_INC_STATS(sock_net(sk), UDP_MIB_INDATAGRAMS, - is_udplite); - else - UDP6_INC_STATS(sock_net(sk), UDP_MIB_INDATAGRAMS, - is_udplite); - } - - sock_recv_ts_and_drops(msg, sk, skb); - - /* Copy the address. */ - if (msg->msg_name) { - DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name); - sin6->sin6_family = AF_INET6; - sin6->sin6_port = udp_hdr(skb)->source; - sin6->sin6_flowinfo = 0; - - if (is_udp4) { - ipv6_addr_set_v4mapped(ip_hdr(skb)->saddr, - &sin6->sin6_addr); - sin6->sin6_scope_id = 0; - } else { - sin6->sin6_addr = ipv6_hdr(skb)->saddr; - sin6->sin6_scope_id = - ipv6_iface_scope_id(&sin6->sin6_addr, - inet6_iif(skb)); - } - *addr_len = sizeof(*sin6); - } - - if (np->rxopt.all) - ip6_datagram_recv_common_ctl(sk, msg, skb); - - if (is_udp4) { - if (inet->cmsg_flags) - ip_cmsg_recv_offset(msg, skb, - sizeof(struct udphdr), off); - } else { - if (np->rxopt.all) - ip6_datagram_recv_specific_ctl(sk, msg, skb); - } - - err = copied; - if (flags & MSG_TRUNC) - err = ulen; - - __skb_free_datagram_locked(sk, skb, peeking ? -err : err); - return err; - -csum_copy_err: - slow = lock_sock_fast(sk); - if (!skb_kill_datagram(sk, skb, flags)) { - if (is_udp4) { - UDP_INC_STATS(sock_net(sk), - UDP_MIB_CSUMERRORS, is_udplite); - UDP_INC_STATS(sock_net(sk), - UDP_MIB_INERRORS, is_udplite); - } else { - UDP6_INC_STATS(sock_net(sk), - UDP_MIB_CSUMERRORS, is_udplite); - UDP6_INC_STATS(sock_net(sk), - UDP_MIB_INERRORS, is_udplite); - } - } - unlock_sock_fast(sk, slow); - - /* starting over for a new packet, but check if we need to yield */ - cond_resched(); - msg->msg_flags &= ~MSG_TRUNC; - goto try_again; -} - -void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - u8 type, u8 code, int offset, __be32 info, - struct udp_table *udptable) -{ - struct ipv6_pinfo *np; - const struct ipv6hdr *hdr = (const struct ipv6hdr *)skb->data; - const struct in6_addr *saddr = &hdr->saddr; - const struct in6_addr *daddr = &hdr->daddr; - struct udphdr *uh = (struct udphdr *)(skb->data+offset); - struct sock *sk; - int harderr; - int err; - struct net *net = dev_net(skb->dev); - - sk = __udp6_lib_lookup(net, daddr, uh->dest, saddr, uh->source, - inet6_iif(skb), udptable, skb); - if (!sk) { - __ICMP6_INC_STATS(net, __in6_dev_get(skb->dev), - ICMP6_MIB_INERRORS); - return; - } - - harderr = icmpv6_err_convert(type, code, &err); - np = inet6_sk(sk); - - if (type == ICMPV6_PKT_TOOBIG) { - if (!ip6_sk_accept_pmtu(sk)) - goto out; - ip6_sk_update_pmtu(skb, sk, info); - if (np->pmtudisc != IPV6_PMTUDISC_DONT) - harderr = 1; - } - if (type == NDISC_REDIRECT) { - ip6_sk_redirect(skb, sk); - goto out; - } - - if (!np->recverr) { - if (!harderr || sk->sk_state != TCP_ESTABLISHED) - goto out; - } else { - ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1)); - } - - sk->sk_err = err; - sk->sk_error_report(sk); -out: - return; -} - -int __udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) -{ - int rc; - - if (!ipv6_addr_any(&sk->sk_v6_daddr)) { - sock_rps_save_rxhash(sk, skb); - sk_mark_napi_id(sk, skb); - sk_incoming_cpu_update(sk); - } - - rc = __sock_queue_rcv_skb(sk, skb); - if (rc < 0) { - int is_udplite = IS_UDPLITE(sk); - - /* Note that an ENOMEM error is charged twice */ - if (rc == -ENOMEM) - UDP6_INC_STATS(sock_net(sk), - UDP_MIB_RCVBUFERRORS, is_udplite); - UDP6_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, is_udplite); - kfree_skb(skb); - return -1; - } - return 0; -} - -static __inline__ void udpv6_err(struct sk_buff *skb, - struct inet6_skb_parm *opt, u8 type, - u8 code, int offset, __be32 info) -{ - __udp6_lib_err(skb, opt, type, code, offset, info, &udp_table); -} - -static struct static_key udpv6_encap_needed __read_mostly; -void udpv6_encap_enable(void) -{ - if (!static_key_enabled(&udpv6_encap_needed)) - static_key_slow_inc(&udpv6_encap_needed); -} -EXPORT_SYMBOL(udpv6_encap_enable); - -int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) -{ - struct udp_sock *up = udp_sk(sk); - int rc; - int is_udplite = IS_UDPLITE(sk); - - if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) - goto drop; - - if (static_key_false(&udpv6_encap_needed) && up->encap_type) { - int (*encap_rcv)(struct sock *sk, struct sk_buff *skb); - - /* - * This is an encapsulation socket so pass the skb to - * the socket's udp_encap_rcv() hook. Otherwise, just - * fall through and pass this up the UDP socket. - * up->encap_rcv() returns the following value: - * =0 if skb was successfully passed to the encap - * handler or was discarded by it. - * >0 if skb should be passed on to UDP. - * <0 if skb should be resubmitted as proto -N - */ - - /* if we're overly short, let UDP handle it */ - encap_rcv = ACCESS_ONCE(up->encap_rcv); - if (encap_rcv) { - int ret; - - /* Verify checksum before giving to encap */ - if (udp_lib_checksum_complete(skb)) - goto csum_error; - - ret = encap_rcv(sk, skb); - if (ret <= 0) { - __UDP_INC_STATS(sock_net(sk), - UDP_MIB_INDATAGRAMS, - is_udplite); - return -ret; - } - } - - /* FALLTHROUGH -- it's a UDP Packet */ - } - - /* - * UDP-Lite specific tests, ignored on UDP sockets (see net/ipv4/udp.c). - */ - if ((is_udplite & UDPLITE_RECV_CC) && UDP_SKB_CB(skb)->partial_cov) { - - if (up->pcrlen == 0) { /* full coverage was set */ - net_dbg_ratelimited("UDPLITE6: partial coverage %d while full coverage %d requested\n", - UDP_SKB_CB(skb)->cscov, skb->len); - goto drop; - } - if (UDP_SKB_CB(skb)->cscov < up->pcrlen) { - net_dbg_ratelimited("UDPLITE6: coverage %d too small, need min %d\n", - UDP_SKB_CB(skb)->cscov, up->pcrlen); - goto drop; - } - } - - if (rcu_access_pointer(sk->sk_filter) && - udp_lib_checksum_complete(skb)) - goto csum_error; - - if (sk_filter_trim_cap(sk, skb, sizeof(struct udphdr))) - goto drop; - - udp_csum_pull_header(skb); - if (sk_rcvqueues_full(sk, sk->sk_rcvbuf)) { - __UDP6_INC_STATS(sock_net(sk), - UDP_MIB_RCVBUFERRORS, is_udplite); - goto drop; - } - - skb_dst_drop(skb); - - bh_lock_sock(sk); - rc = 0; - if (!sock_owned_by_user(sk)) - rc = __udpv6_queue_rcv_skb(sk, skb); - else if (sk_add_backlog(sk, skb, sk->sk_rcvbuf)) { - bh_unlock_sock(sk); - goto drop; - } - bh_unlock_sock(sk); - - return rc; - -csum_error: - __UDP6_INC_STATS(sock_net(sk), UDP_MIB_CSUMERRORS, is_udplite); -drop: - __UDP6_INC_STATS(sock_net(sk), UDP_MIB_INERRORS, is_udplite); - atomic_inc(&sk->sk_drops); - kfree_skb(skb); - return -1; -} - -static bool __udp_v6_is_mcast_sock(struct net *net, struct sock *sk, - __be16 loc_port, const struct in6_addr *loc_addr, - __be16 rmt_port, const struct in6_addr *rmt_addr, - int dif, unsigned short hnum) -{ - struct inet_sock *inet = inet_sk(sk); - - if (!net_eq(sock_net(sk), net)) - return false; - - if (udp_sk(sk)->udp_port_hash != hnum || - sk->sk_family != PF_INET6 || - (inet->inet_dport && inet->inet_dport != rmt_port) || - (!ipv6_addr_any(&sk->sk_v6_daddr) && - !ipv6_addr_equal(&sk->sk_v6_daddr, rmt_addr)) || - (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif) || - (!ipv6_addr_any(&sk->sk_v6_rcv_saddr) && - !ipv6_addr_equal(&sk->sk_v6_rcv_saddr, loc_addr))) - return false; - if (!inet6_mc_check(sk, loc_addr, rmt_addr)) - return false; - return true; -} - -static void udp6_csum_zero_error(struct sk_buff *skb) -{ - /* RFC 2460 section 8.1 says that we SHOULD log - * this error. Well, it is reasonable. - */ - net_dbg_ratelimited("IPv6: udp checksum is 0 for [%pI6c]:%u->[%pI6c]:%u\n", - &ipv6_hdr(skb)->saddr, ntohs(udp_hdr(skb)->source), - &ipv6_hdr(skb)->daddr, ntohs(udp_hdr(skb)->dest)); -} - -/* - * Note: called only from the BH handler context, - * so we don't need to lock the hashes. - */ -static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, - const struct in6_addr *saddr, const struct in6_addr *daddr, - struct udp_table *udptable, int proto) -{ - struct sock *sk, *first = NULL; - const struct udphdr *uh = udp_hdr(skb); - unsigned short hnum = ntohs(uh->dest); - struct udp_hslot *hslot = udp_hashslot(udptable, net, hnum); - unsigned int offset = offsetof(typeof(*sk), sk_node); - unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10); - int dif = inet6_iif(skb); - struct hlist_node *node; - struct sk_buff *nskb; - - if (use_hash2) { - hash2_any = udp6_portaddr_hash(net, &in6addr_any, hnum) & - udptable->mask; - hash2 = udp6_portaddr_hash(net, daddr, hnum) & udptable->mask; -start_lookup: - hslot = &udptable->hash2[hash2]; - offset = offsetof(typeof(*sk), __sk_common.skc_portaddr_node); - } - - sk_for_each_entry_offset_rcu(sk, node, &hslot->head, offset) { - if (!__udp_v6_is_mcast_sock(net, sk, uh->dest, daddr, - uh->source, saddr, dif, hnum)) - continue; - /* If zero checksum and no_check is not on for - * the socket then skip it. - */ - if (!uh->check && !udp_sk(sk)->no_check6_rx) - continue; - if (!first) { - first = sk; - continue; - } - nskb = skb_clone(skb, GFP_ATOMIC); - if (unlikely(!nskb)) { - atomic_inc(&sk->sk_drops); - __UDP6_INC_STATS(net, UDP_MIB_RCVBUFERRORS, - IS_UDPLITE(sk)); - __UDP6_INC_STATS(net, UDP_MIB_INERRORS, - IS_UDPLITE(sk)); - continue; - } - - if (udpv6_queue_rcv_skb(sk, nskb) > 0) - consume_skb(nskb); - } - - /* Also lookup *:port if we are using hash2 and haven't done so yet. */ - if (use_hash2 && hash2 != hash2_any) { - hash2 = hash2_any; - goto start_lookup; - } - - if (first) { - if (udpv6_queue_rcv_skb(first, skb) > 0) - consume_skb(skb); - } else { - kfree_skb(skb); - __UDP6_INC_STATS(net, UDP_MIB_IGNOREDMULTI, - proto == IPPROTO_UDPLITE); - } - return 0; -} - -int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, - int proto) -{ - const struct in6_addr *saddr, *daddr; - struct net *net = dev_net(skb->dev); - struct udphdr *uh; - struct sock *sk; - u32 ulen = 0; - - if (!pskb_may_pull(skb, sizeof(struct udphdr))) - goto discard; - - saddr = &ipv6_hdr(skb)->saddr; - daddr = &ipv6_hdr(skb)->daddr; - uh = udp_hdr(skb); - - ulen = ntohs(uh->len); - if (ulen > skb->len) - goto short_packet; - - if (proto == IPPROTO_UDP) { - /* UDP validates ulen. */ - - /* Check for jumbo payload */ - if (ulen == 0) - ulen = skb->len; - - if (ulen < sizeof(*uh)) - goto short_packet; - - if (ulen < skb->len) { - if (pskb_trim_rcsum(skb, ulen)) - goto short_packet; - saddr = &ipv6_hdr(skb)->saddr; - daddr = &ipv6_hdr(skb)->daddr; - uh = udp_hdr(skb); - } - } - - if (udp6_csum_init(skb, uh, proto)) - goto csum_error; - - /* - * Multicast receive code - */ - if (ipv6_addr_is_multicast(daddr)) - return __udp6_lib_mcast_deliver(net, skb, - saddr, daddr, udptable, proto); - - /* Unicast */ - - /* - * check socket cache ... must talk to Alan about his plans - * for sock caches... i'll skip this for now. - */ - sk = __udp6_lib_lookup_skb(skb, uh->source, uh->dest, udptable); - if (sk) { - int ret; - - if (!uh->check && !udp_sk(sk)->no_check6_rx) { - udp6_csum_zero_error(skb); - goto csum_error; - } - - if (inet_get_convert_csum(sk) && uh->check && !IS_UDPLITE(sk)) - skb_checksum_try_convert(skb, IPPROTO_UDP, uh->check, - ip6_compute_pseudo); - - ret = udpv6_queue_rcv_skb(sk, skb); - - /* a return value > 0 means to resubmit the input */ - if (ret > 0) - return ret; - - return 0; - } - - if (!uh->check) { - udp6_csum_zero_error(skb); - goto csum_error; - } - - if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) - goto discard; - - if (udp_lib_checksum_complete(skb)) - goto csum_error; - - __UDP6_INC_STATS(net, UDP_MIB_NOPORTS, proto == IPPROTO_UDPLITE); - icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); - - kfree_skb(skb); - return 0; - -short_packet: - net_dbg_ratelimited("UDP%sv6: short packet: From [%pI6c]:%u %d/%d to [%pI6c]:%u\n", - proto == IPPROTO_UDPLITE ? "-Lite" : "", - saddr, ntohs(uh->source), - ulen, skb->len, - daddr, ntohs(uh->dest)); - goto discard; -csum_error: - __UDP6_INC_STATS(net, UDP_MIB_CSUMERRORS, proto == IPPROTO_UDPLITE); -discard: - __UDP6_INC_STATS(net, UDP_MIB_INERRORS, proto == IPPROTO_UDPLITE); - kfree_skb(skb); - return 0; -} - -static __inline__ int udpv6_rcv(struct sk_buff *skb) -{ - return __udp6_lib_rcv(skb, &udp_table, IPPROTO_UDP); -} - -/* - * Throw away all pending data and cancel the corking. Socket is locked. - */ -static void udp_v6_flush_pending_frames(struct sock *sk) -{ - struct udp_sock *up = udp_sk(sk); - - if (up->pending == AF_INET) - udp_flush_pending_frames(sk); - else if (up->pending) { - up->len = 0; - up->pending = 0; - ip6_flush_pending_frames(sk); - } -} - -/** - * udp6_hwcsum_outgoing - handle outgoing HW checksumming - * @sk: socket we are sending on - * @skb: sk_buff containing the filled-in UDP header - * (checksum field must be zeroed out) - */ -static void udp6_hwcsum_outgoing(struct sock *sk, struct sk_buff *skb, - const struct in6_addr *saddr, - const struct in6_addr *daddr, int len) -{ - unsigned int offset; - struct udphdr *uh = udp_hdr(skb); - struct sk_buff *frags = skb_shinfo(skb)->frag_list; - __wsum csum = 0; - - if (!frags) { - /* Only one fragment on the socket. */ - skb->csum_start = skb_transport_header(skb) - skb->head; - skb->csum_offset = offsetof(struct udphdr, check); - uh->check = ~csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, 0); - } else { - /* - * HW-checksum won't work as there are two or more - * fragments on the socket so that all csums of sk_buffs - * should be together - */ - offset = skb_transport_offset(skb); - skb->csum = skb_checksum(skb, offset, skb->len - offset, 0); - - skb->ip_summed = CHECKSUM_NONE; - - do { - csum = csum_add(csum, frags->csum); - } while ((frags = frags->next)); - - uh->check = csum_ipv6_magic(saddr, daddr, len, IPPROTO_UDP, - csum); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - } -} - -/* - * Sending - */ - -static int udp_v6_send_skb(struct sk_buff *skb, struct flowi6 *fl6) -{ - struct sock *sk = skb->sk; - struct udphdr *uh; - int err = 0; - int is_udplite = IS_UDPLITE(sk); - __wsum csum = 0; - int offset = skb_transport_offset(skb); - int len = skb->len - offset; - - /* - * Create a UDP header - */ - uh = udp_hdr(skb); - uh->source = fl6->fl6_sport; - uh->dest = fl6->fl6_dport; - uh->len = htons(len); - uh->check = 0; - - if (is_udplite) - csum = udplite_csum(skb); - else if (udp_sk(sk)->no_check6_tx) { /* UDP csum disabled */ - skb->ip_summed = CHECKSUM_NONE; - goto send; - } else if (skb->ip_summed == CHECKSUM_PARTIAL) { /* UDP hardware csum */ - udp6_hwcsum_outgoing(sk, skb, &fl6->saddr, &fl6->daddr, len); - goto send; - } else - csum = udp_csum(skb); - - /* add protocol-dependent pseudo-header */ - uh->check = csum_ipv6_magic(&fl6->saddr, &fl6->daddr, - len, fl6->flowi6_proto, csum); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - -send: - err = ip6_send_skb(skb); - if (err) { - if (err == -ENOBUFS && !inet6_sk(sk)->recverr) { - UDP6_INC_STATS(sock_net(sk), - UDP_MIB_SNDBUFERRORS, is_udplite); - err = 0; - } - } else { - UDP6_INC_STATS(sock_net(sk), - UDP_MIB_OUTDATAGRAMS, is_udplite); - } - return err; -} - -static int udp_v6_push_pending_frames(struct sock *sk) -{ - struct sk_buff *skb; - struct udp_sock *up = udp_sk(sk); - struct flowi6 fl6; - int err = 0; - - if (up->pending == AF_INET) - return udp_push_pending_frames(sk); - - /* ip6_finish_skb will release the cork, so make a copy of - * fl6 here. - */ - fl6 = inet_sk(sk)->cork.fl.u.ip6; - - skb = ip6_finish_skb(sk); - if (!skb) - goto out; - - err = udp_v6_send_skb(skb, &fl6); - -out: - up->len = 0; - up->pending = 0; - return err; -} - -int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len) -{ - struct ipv6_txoptions opt_space; - struct udp_sock *up = udp_sk(sk); - struct inet_sock *inet = inet_sk(sk); - struct ipv6_pinfo *np = inet6_sk(sk); - DECLARE_SOCKADDR(struct sockaddr_in6 *, sin6, msg->msg_name); - struct in6_addr *daddr, *final_p, final; - struct ipv6_txoptions *opt = NULL; - struct ipv6_txoptions *opt_to_free = NULL; - struct ip6_flowlabel *flowlabel = NULL; - struct flowi6 fl6; - struct dst_entry *dst; - struct ipcm6_cookie ipc6; - int addr_len = msg->msg_namelen; - int ulen = len; - int corkreq = up->corkflag || msg->msg_flags&MSG_MORE; - int err; - int connected = 0; - int is_udplite = IS_UDPLITE(sk); - int (*getfrag)(void *, char *, int, int, int, struct sk_buff *); - struct sockcm_cookie sockc; - - ipc6.hlimit = -1; - ipc6.tclass = -1; - ipc6.dontfrag = -1; - - /* destination address check */ - if (sin6) { - if (addr_len < offsetof(struct sockaddr, sa_data)) - return -EINVAL; - - switch (sin6->sin6_family) { - case AF_INET6: - if (addr_len < SIN6_LEN_RFC2133) - return -EINVAL; - daddr = &sin6->sin6_addr; - break; - case AF_INET: - goto do_udp_sendmsg; - case AF_UNSPEC: - msg->msg_name = sin6 = NULL; - msg->msg_namelen = addr_len = 0; - daddr = NULL; - break; - default: - return -EINVAL; - } - } else if (!up->pending) { - if (sk->sk_state != TCP_ESTABLISHED) - return -EDESTADDRREQ; - daddr = &sk->sk_v6_daddr; - } else - daddr = NULL; - - if (daddr) { - if (ipv6_addr_v4mapped(daddr)) { - struct sockaddr_in sin; - sin.sin_family = AF_INET; - sin.sin_port = sin6 ? sin6->sin6_port : inet->inet_dport; - sin.sin_addr.s_addr = daddr->s6_addr32[3]; - msg->msg_name = &sin; - msg->msg_namelen = sizeof(sin); -do_udp_sendmsg: - if (__ipv6_only_sock(sk)) - return -ENETUNREACH; - return udp_sendmsg(sk, msg, len); - } - } - - if (up->pending == AF_INET) - return udp_sendmsg(sk, msg, len); - - /* Rough check on arithmetic overflow, - better check is made in ip6_append_data(). - */ - if (len > INT_MAX - sizeof(struct udphdr)) - return -EMSGSIZE; - - getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; - if (up->pending) { - /* - * There are pending frames. - * The socket lock must be held while it's corked. - */ - lock_sock(sk); - if (likely(up->pending)) { - if (unlikely(up->pending != AF_INET6)) { - release_sock(sk); - return -EAFNOSUPPORT; - } - dst = NULL; - goto do_append_data; - } - release_sock(sk); - } - ulen += sizeof(struct udphdr); - - memset(&fl6, 0, sizeof(fl6)); - - if (sin6) { - if (sin6->sin6_port == 0) - return -EINVAL; - - fl6.fl6_dport = sin6->sin6_port; - daddr = &sin6->sin6_addr; - - if (np->sndflow) { - fl6.flowlabel = sin6->sin6_flowinfo&IPV6_FLOWINFO_MASK; - if (fl6.flowlabel&IPV6_FLOWLABEL_MASK) { - flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); - if (!flowlabel) - return -EINVAL; - } - } - - /* - * Otherwise it will be difficult to maintain - * sk->sk_dst_cache. - */ - if (sk->sk_state == TCP_ESTABLISHED && - ipv6_addr_equal(daddr, &sk->sk_v6_daddr)) - daddr = &sk->sk_v6_daddr; - - if (addr_len >= sizeof(struct sockaddr_in6) && - sin6->sin6_scope_id && - __ipv6_addr_needs_scope_id(__ipv6_addr_type(daddr))) - fl6.flowi6_oif = sin6->sin6_scope_id; - } else { - if (sk->sk_state != TCP_ESTABLISHED) - return -EDESTADDRREQ; - - fl6.fl6_dport = inet->inet_dport; - daddr = &sk->sk_v6_daddr; - fl6.flowlabel = np->flow_label; - connected = 1; - } - - if (!fl6.flowi6_oif) - fl6.flowi6_oif = sk->sk_bound_dev_if; - - if (!fl6.flowi6_oif) - fl6.flowi6_oif = np->sticky_pktinfo.ipi6_ifindex; - - fl6.flowi6_mark = sk->sk_mark; - sockc.tsflags = sk->sk_tsflags; - - if (msg->msg_controllen) { - opt = &opt_space; - memset(opt, 0, sizeof(struct ipv6_txoptions)); - opt->tot_len = sizeof(*opt); - ipc6.opt = opt; - - err = ip6_datagram_send_ctl(sock_net(sk), sk, msg, &fl6, &ipc6, &sockc); - if (err < 0) { - fl6_sock_release(flowlabel); - return err; - } - if ((fl6.flowlabel&IPV6_FLOWLABEL_MASK) && !flowlabel) { - flowlabel = fl6_sock_lookup(sk, fl6.flowlabel); - if (!flowlabel) - return -EINVAL; - } - if (!(opt->opt_nflen|opt->opt_flen)) - opt = NULL; - connected = 0; - } - if (!opt) { - opt = txopt_get(np); - opt_to_free = opt; - } - if (flowlabel) - opt = fl6_merge_options(&opt_space, flowlabel, opt); - opt = ipv6_fixup_options(&opt_space, opt); - ipc6.opt = opt; - - fl6.flowi6_proto = sk->sk_protocol; - if (!ipv6_addr_any(daddr)) - fl6.daddr = *daddr; - else - fl6.daddr.s6_addr[15] = 0x1; /* :: means loopback (BSD'ism) */ - if (ipv6_addr_any(&fl6.saddr) && !ipv6_addr_any(&np->saddr)) - fl6.saddr = np->saddr; - fl6.fl6_sport = inet->inet_sport; - - final_p = fl6_update_dst(&fl6, opt, &final); - if (final_p) - connected = 0; - - if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) { - fl6.flowi6_oif = np->mcast_oif; - connected = 0; - } else if (!fl6.flowi6_oif) - fl6.flowi6_oif = np->ucast_oif; - - security_sk_classify_flow(sk, flowi6_to_flowi(&fl6)); - - if (ipc6.tclass < 0) - ipc6.tclass = np->tclass; - - fl6.flowlabel = ip6_make_flowinfo(ipc6.tclass, fl6.flowlabel); - - dst = ip6_sk_dst_lookup_flow(sk, &fl6, final_p); - if (IS_ERR(dst)) { - err = PTR_ERR(dst); - dst = NULL; - goto out; - } - - if (ipc6.hlimit < 0) - ipc6.hlimit = ip6_sk_dst_hoplimit(np, &fl6, dst); - - if (msg->msg_flags&MSG_CONFIRM) - goto do_confirm; -back_from_confirm: - - /* Lockless fast path for the non-corking case */ - if (!corkreq) { - struct sk_buff *skb; - - skb = ip6_make_skb(sk, getfrag, msg, ulen, - sizeof(struct udphdr), &ipc6, - &fl6, (struct rt6_info *)dst, - msg->msg_flags, &sockc); - err = PTR_ERR(skb); - if (!IS_ERR_OR_NULL(skb)) - err = udp_v6_send_skb(skb, &fl6); - goto release_dst; - } - - lock_sock(sk); - if (unlikely(up->pending)) { - /* The socket is already corked while preparing it. */ - /* ... which is an evident application bug. --ANK */ - release_sock(sk); - - net_dbg_ratelimited("udp cork app bug 2\n"); - err = -EINVAL; - goto out; - } - - up->pending = AF_INET6; - -do_append_data: - if (ipc6.dontfrag < 0) - ipc6.dontfrag = np->dontfrag; - up->len += ulen; - err = ip6_append_data(sk, getfrag, msg, ulen, sizeof(struct udphdr), - &ipc6, &fl6, (struct rt6_info *)dst, - corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags, &sockc); - if (err) - udp_v6_flush_pending_frames(sk); - else if (!corkreq) - err = udp_v6_push_pending_frames(sk); - else if (unlikely(skb_queue_empty(&sk->sk_write_queue))) - up->pending = 0; - - if (err > 0) - err = np->recverr ? net_xmit_errno(err) : 0; - release_sock(sk); - -release_dst: - if (dst) { - if (connected) { - ip6_dst_store(sk, dst, - ipv6_addr_equal(&fl6.daddr, &sk->sk_v6_daddr) ? - &sk->sk_v6_daddr : NULL, -#ifdef CONFIG_IPV6_SUBTREES - ipv6_addr_equal(&fl6.saddr, &np->saddr) ? - &np->saddr : -#endif - NULL); - } else { - dst_release(dst); - } - dst = NULL; - } - -out: - dst_release(dst); - fl6_sock_release(flowlabel); - txopt_put(opt_to_free); - if (!err) - return len; - /* - * ENOBUFS = no kernel mem, SOCK_NOSPACE = no sndbuf space. Reporting - * ENOBUFS might not be good (it's not tunable per se), but otherwise - * we don't have a good statistic (IpOutDiscards but it can be too many - * things). We could add another new stat but at least for now that - * seems like overkill. - */ - if (err == -ENOBUFS || test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { - UDP6_INC_STATS(sock_net(sk), - UDP_MIB_SNDBUFERRORS, is_udplite); - } - return err; - -do_confirm: - dst_confirm(dst); - if (!(msg->msg_flags&MSG_PROBE) || len) - goto back_from_confirm; - err = 0; - goto out; -} - -void udpv6_destroy_sock(struct sock *sk) -{ - struct udp_sock *up = udp_sk(sk); - lock_sock(sk); - udp_v6_flush_pending_frames(sk); - release_sock(sk); - - if (static_key_false(&udpv6_encap_needed) && up->encap_type) { - void (*encap_destroy)(struct sock *sk); - encap_destroy = ACCESS_ONCE(up->encap_destroy); - if (encap_destroy) - encap_destroy(sk); - } - - inet6_destroy_sock(sk); -} - -/* - * Socket option code for UDP - */ -int udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen) -{ - if (level == SOL_UDP || level == SOL_UDPLITE) - return udp_lib_setsockopt(sk, level, optname, optval, optlen, - udp_v6_push_pending_frames); - return ipv6_setsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen) -{ - if (level == SOL_UDP || level == SOL_UDPLITE) - return udp_lib_setsockopt(sk, level, optname, optval, optlen, - udp_v6_push_pending_frames); - return compat_ipv6_setsockopt(sk, level, optname, optval, optlen); -} -#endif - -int udpv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (level == SOL_UDP || level == SOL_UDPLITE) - return udp_lib_getsockopt(sk, level, optname, optval, optlen); - return ipv6_getsockopt(sk, level, optname, optval, optlen); -} - -#ifdef CONFIG_COMPAT -int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen) -{ - if (level == SOL_UDP || level == SOL_UDPLITE) - return udp_lib_getsockopt(sk, level, optname, optval, optlen); - return compat_ipv6_getsockopt(sk, level, optname, optval, optlen); -} -#endif - -static const struct inet6_protocol udpv6_protocol = { - .handler = udpv6_rcv, - .err_handler = udpv6_err, - .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, -}; - -/* ------------------------------------------------------------------------ */ -#ifdef CONFIG_PROC_FS -int udp6_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) { - seq_puts(seq, IPV6_SEQ_DGRAM_HEADER); - } else { - int bucket = ((struct udp_iter_state *)seq->private)->bucket; - struct inet_sock *inet = inet_sk(v); - __u16 srcp = ntohs(inet->inet_sport); - __u16 destp = ntohs(inet->inet_dport); - ip6_dgram_sock_seq_show(seq, v, srcp, destp, bucket); - } - return 0; -} - -static const struct file_operations udp6_afinfo_seq_fops = { - .owner = THIS_MODULE, - .open = udp_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net -}; - -static struct udp_seq_afinfo udp6_seq_afinfo = { - .name = "udp6", - .family = AF_INET6, - .udp_table = &udp_table, - .seq_fops = &udp6_afinfo_seq_fops, - .seq_ops = { - .show = udp6_seq_show, - }, -}; - -int __net_init udp6_proc_init(struct net *net) -{ - return udp_proc_register(net, &udp6_seq_afinfo); -} - -void udp6_proc_exit(struct net *net) -{ - udp_proc_unregister(net, &udp6_seq_afinfo); -} -#endif /* CONFIG_PROC_FS */ - -/* ------------------------------------------------------------------------ */ - -struct proto udpv6_prot = { - .name = "UDPv6", - .owner = THIS_MODULE, - .close = udp_lib_close, - .connect = ip6_datagram_connect, - .disconnect = udp_disconnect, - .ioctl = udp_ioctl, - .destroy = udpv6_destroy_sock, - .setsockopt = udpv6_setsockopt, - .getsockopt = udpv6_getsockopt, - .sendmsg = udpv6_sendmsg, - .recvmsg = udpv6_recvmsg, - .backlog_rcv = __udpv6_queue_rcv_skb, - .release_cb = ip6_datagram_release_cb, - .hash = udp_lib_hash, - .unhash = udp_lib_unhash, - .rehash = udp_v6_rehash, - .get_port = udp_v6_get_port, - .memory_allocated = &udp_memory_allocated, - .sysctl_mem = sysctl_udp_mem, - .sysctl_wmem = &sysctl_udp_wmem_min, - .sysctl_rmem = &sysctl_udp_rmem_min, - .obj_size = sizeof(struct udp6_sock), - .h.udp_table = &udp_table, -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_udpv6_setsockopt, - .compat_getsockopt = compat_udpv6_getsockopt, -#endif - .diag_destroy = udp_abort, -}; - -static struct inet_protosw udpv6_protosw = { - .type = SOCK_DGRAM, - .protocol = IPPROTO_UDP, - .prot = &udpv6_prot, - .ops = &inet6_dgram_ops, - .flags = INET_PROTOSW_PERMANENT, -}; - -int __init udpv6_init(void) -{ - int ret; - - ret = inet6_add_protocol(&udpv6_protocol, IPPROTO_UDP); - if (ret) - goto out; - - ret = inet6_register_protosw(&udpv6_protosw); - if (ret) - goto out_udpv6_protocol; -out: - return ret; - -out_udpv6_protocol: - inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); - goto out; -} - -void udpv6_exit(void) -{ - inet6_unregister_protosw(&udpv6_protosw); - inet6_del_protocol(&udpv6_protocol, IPPROTO_UDP); -} diff --git a/src/linux/net/ipv6/udp_impl.h b/src/linux/net/ipv6/udp_impl.h deleted file mode 100644 index e78bdc7..0000000 --- a/src/linux/net/ipv6/udp_impl.h +++ /dev/null @@ -1,35 +0,0 @@ -#ifndef _UDP6_IMPL_H -#define _UDP6_IMPL_H -#include -#include -#include -#include -#include -#include - -int __udp6_lib_rcv(struct sk_buff *, struct udp_table *, int); -void __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, u8, u8, int, - __be32, struct udp_table *); - -int udp_v6_get_port(struct sock *sk, unsigned short snum); - -int udpv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen); -int udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen); -#ifdef CONFIG_COMPAT -int compat_udpv6_setsockopt(struct sock *sk, int level, int optname, - char __user *optval, unsigned int optlen); -int compat_udpv6_getsockopt(struct sock *sk, int level, int optname, - char __user *optval, int __user *optlen); -#endif -int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, size_t len); -int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock, - int flags, int *addr_len); -int __udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); -void udpv6_destroy_sock(struct sock *sk); - -#ifdef CONFIG_PROC_FS -int udp6_seq_show(struct seq_file *seq, void *v); -#endif -#endif /* _UDP6_IMPL_H */ diff --git a/src/linux/net/ipv6/udp_offload.c b/src/linux/net/ipv6/udp_offload.c deleted file mode 100644 index ac858c4..0000000 --- a/src/linux/net/ipv6/udp_offload.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * IPV6 GSO/GRO offload support - * Linux INET6 implementation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * UDPv6 GSO support - */ -#include -#include -#include -#include -#include -#include -#include "ip6_offload.h" - -static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb, - netdev_features_t features) -{ - struct sk_buff *segs = ERR_PTR(-EINVAL); - unsigned int mss; - unsigned int unfrag_ip6hlen, unfrag_len; - struct frag_hdr *fptr; - u8 *packet_start, *prevhdr; - u8 nexthdr; - u8 frag_hdr_sz = sizeof(struct frag_hdr); - __wsum csum; - int tnl_hlen; - - mss = skb_shinfo(skb)->gso_size; - if (unlikely(skb->len <= mss)) - goto out; - - if (skb_gso_ok(skb, features | NETIF_F_GSO_ROBUST)) { - /* Packet is from an untrusted source, reset gso_segs. */ - - skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len, mss); - - /* Set the IPv6 fragment id if not set yet */ - if (!skb_shinfo(skb)->ip6_frag_id) - ipv6_proxy_select_ident(dev_net(skb->dev), skb); - - segs = NULL; - goto out; - } - - if (skb->encapsulation && skb_shinfo(skb)->gso_type & - (SKB_GSO_UDP_TUNNEL|SKB_GSO_UDP_TUNNEL_CSUM)) - segs = skb_udp_tunnel_segment(skb, features, true); - else { - const struct ipv6hdr *ipv6h; - struct udphdr *uh; - - if (!pskb_may_pull(skb, sizeof(struct udphdr))) - goto out; - - /* Do software UFO. Complete and fill in the UDP checksum as HW cannot - * do checksum of UDP packets sent as multiple IP fragments. - */ - - uh = udp_hdr(skb); - ipv6h = ipv6_hdr(skb); - - uh->check = 0; - csum = skb_checksum(skb, 0, skb->len, 0); - uh->check = udp_v6_check(skb->len, &ipv6h->saddr, - &ipv6h->daddr, csum); - if (uh->check == 0) - uh->check = CSUM_MANGLED_0; - - skb->ip_summed = CHECKSUM_NONE; - - /* If there is no outer header we can fake a checksum offload - * due to the fact that we have already done the checksum in - * software prior to segmenting the frame. - */ - if (!skb->encap_hdr_csum) - features |= NETIF_F_HW_CSUM; - - /* Check if there is enough headroom to insert fragment header. */ - tnl_hlen = skb_tnl_header_len(skb); - if (skb->mac_header < (tnl_hlen + frag_hdr_sz)) { - if (gso_pskb_expand_head(skb, tnl_hlen + frag_hdr_sz)) - goto out; - } - - /* Find the unfragmentable header and shift it left by frag_hdr_sz - * bytes to insert fragment header. - */ - unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); - nexthdr = *prevhdr; - *prevhdr = NEXTHDR_FRAGMENT; - unfrag_len = (skb_network_header(skb) - skb_mac_header(skb)) + - unfrag_ip6hlen + tnl_hlen; - packet_start = (u8 *) skb->head + SKB_GSO_CB(skb)->mac_offset; - memmove(packet_start-frag_hdr_sz, packet_start, unfrag_len); - - SKB_GSO_CB(skb)->mac_offset -= frag_hdr_sz; - skb->mac_header -= frag_hdr_sz; - skb->network_header -= frag_hdr_sz; - - fptr = (struct frag_hdr *)(skb_network_header(skb) + unfrag_ip6hlen); - fptr->nexthdr = nexthdr; - fptr->reserved = 0; - if (!skb_shinfo(skb)->ip6_frag_id) - ipv6_proxy_select_ident(dev_net(skb->dev), skb); - fptr->identification = skb_shinfo(skb)->ip6_frag_id; - - /* Fragment the skb. ipv6 header and the remaining fields of the - * fragment header are updated in ipv6_gso_segment() - */ - segs = skb_segment(skb, features); - } - -out: - return segs; -} - -static struct sk_buff **udp6_gro_receive(struct sk_buff **head, - struct sk_buff *skb) -{ - struct udphdr *uh = udp_gro_udphdr(skb); - - if (unlikely(!uh)) - goto flush; - - /* Don't bother verifying checksum if we're going to flush anyway. */ - if (NAPI_GRO_CB(skb)->flush) - goto skip; - - if (skb_gro_checksum_validate_zero_check(skb, IPPROTO_UDP, uh->check, - ip6_gro_compute_pseudo)) - goto flush; - else if (uh->check) - skb_gro_checksum_try_convert(skb, IPPROTO_UDP, uh->check, - ip6_gro_compute_pseudo); - -skip: - NAPI_GRO_CB(skb)->is_ipv6 = 1; - return udp_gro_receive(head, skb, uh, udp6_lib_lookup_skb); - -flush: - NAPI_GRO_CB(skb)->flush = 1; - return NULL; -} - -static int udp6_gro_complete(struct sk_buff *skb, int nhoff) -{ - const struct ipv6hdr *ipv6h = ipv6_hdr(skb); - struct udphdr *uh = (struct udphdr *)(skb->data + nhoff); - - if (uh->check) { - skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL_CSUM; - uh->check = ~udp_v6_check(skb->len - nhoff, &ipv6h->saddr, - &ipv6h->daddr, 0); - } else { - skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL; - } - - return udp_gro_complete(skb, nhoff, udp6_lib_lookup_skb); -} - -static const struct net_offload udpv6_offload = { - .callbacks = { - .gso_segment = udp6_ufo_fragment, - .gro_receive = udp6_gro_receive, - .gro_complete = udp6_gro_complete, - }, -}; - -int udpv6_offload_init(void) -{ - return inet6_add_offload(&udpv6_offload, IPPROTO_UDP); -} - -int udpv6_offload_exit(void) -{ - return inet6_del_offload(&udpv6_offload, IPPROTO_UDP); -} diff --git a/src/linux/net/ipv6/udplite.c b/src/linux/net/ipv6/udplite.c deleted file mode 100644 index 2f5101a..0000000 --- a/src/linux/net/ipv6/udplite.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * UDPLITEv6 An implementation of the UDP-Lite protocol over IPv6. - * See also net/ipv4/udplite.c - * - * Authors: Gerrit Renker - * - * Changes: - * Fixes: - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ -#include -#include "udp_impl.h" - -static int udplitev6_rcv(struct sk_buff *skb) -{ - return __udp6_lib_rcv(skb, &udplite_table, IPPROTO_UDPLITE); -} - -static void udplitev6_err(struct sk_buff *skb, - struct inet6_skb_parm *opt, - u8 type, u8 code, int offset, __be32 info) -{ - __udp6_lib_err(skb, opt, type, code, offset, info, &udplite_table); -} - -static const struct inet6_protocol udplitev6_protocol = { - .handler = udplitev6_rcv, - .err_handler = udplitev6_err, - .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, -}; - -struct proto udplitev6_prot = { - .name = "UDPLITEv6", - .owner = THIS_MODULE, - .close = udp_lib_close, - .connect = ip6_datagram_connect, - .disconnect = udp_disconnect, - .ioctl = udp_ioctl, - .init = udplite_sk_init, - .destroy = udpv6_destroy_sock, - .setsockopt = udpv6_setsockopt, - .getsockopt = udpv6_getsockopt, - .sendmsg = udpv6_sendmsg, - .recvmsg = udpv6_recvmsg, - .backlog_rcv = __udpv6_queue_rcv_skb, - .hash = udp_lib_hash, - .unhash = udp_lib_unhash, - .get_port = udp_v6_get_port, - .obj_size = sizeof(struct udp6_sock), - .h.udp_table = &udplite_table, -#ifdef CONFIG_COMPAT - .compat_setsockopt = compat_udpv6_setsockopt, - .compat_getsockopt = compat_udpv6_getsockopt, -#endif -}; - -static struct inet_protosw udplite6_protosw = { - .type = SOCK_DGRAM, - .protocol = IPPROTO_UDPLITE, - .prot = &udplitev6_prot, - .ops = &inet6_dgram_ops, - .flags = INET_PROTOSW_PERMANENT, -}; - -int __init udplitev6_init(void) -{ - int ret; - - ret = inet6_add_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); - if (ret) - goto out; - - ret = inet6_register_protosw(&udplite6_protosw); - if (ret) - goto out_udplitev6_protocol; -out: - return ret; - -out_udplitev6_protocol: - inet6_del_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); - goto out; -} - -void udplitev6_exit(void) -{ - inet6_unregister_protosw(&udplite6_protosw); - inet6_del_protocol(&udplitev6_protocol, IPPROTO_UDPLITE); -} - -#ifdef CONFIG_PROC_FS - -static const struct file_operations udplite6_afinfo_seq_fops = { - .owner = THIS_MODULE, - .open = udp_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net -}; - -static struct udp_seq_afinfo udplite6_seq_afinfo = { - .name = "udplite6", - .family = AF_INET6, - .udp_table = &udplite_table, - .seq_fops = &udplite6_afinfo_seq_fops, - .seq_ops = { - .show = udp6_seq_show, - }, -}; - -static int __net_init udplite6_proc_init_net(struct net *net) -{ - return udp_proc_register(net, &udplite6_seq_afinfo); -} - -static void __net_exit udplite6_proc_exit_net(struct net *net) -{ - udp_proc_unregister(net, &udplite6_seq_afinfo); -} - -static struct pernet_operations udplite6_net_ops = { - .init = udplite6_proc_init_net, - .exit = udplite6_proc_exit_net, -}; - -int __init udplite6_proc_init(void) -{ - return register_pernet_subsys(&udplite6_net_ops); -} - -void udplite6_proc_exit(void) -{ - unregister_pernet_subsys(&udplite6_net_ops); -} -#endif diff --git a/src/linux/net/ipv6/xfrm6_input.c b/src/linux/net/ipv6/xfrm6_input.c deleted file mode 100644 index b578956..0000000 --- a/src/linux/net/ipv6/xfrm6_input.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * xfrm6_input.c: based on net/ipv4/xfrm4_input.c - * - * Authors: - * Mitsuru KANDA @USAGI - * Kazunori MIYAZAWA @USAGI - * Kunihiro Ishiguro - * YOSHIFUJI Hideaki @USAGI - * IPv6 support - */ - -#include -#include -#include -#include -#include -#include - -int xfrm6_extract_input(struct xfrm_state *x, struct sk_buff *skb) -{ - return xfrm6_extract_header(skb); -} - -int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi, - struct ip6_tnl *t) -{ - XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = t; - XFRM_SPI_SKB_CB(skb)->family = AF_INET6; - XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct ipv6hdr, daddr); - return xfrm_input(skb, nexthdr, spi, 0); -} -EXPORT_SYMBOL(xfrm6_rcv_spi); - -int xfrm6_transport_finish(struct sk_buff *skb, int async) -{ - skb_network_header(skb)[IP6CB(skb)->nhoff] = - XFRM_MODE_SKB_CB(skb)->protocol; - -#ifndef CONFIG_NETFILTER - if (!async) - return 1; -#endif - - ipv6_hdr(skb)->payload_len = htons(skb->len); - __skb_push(skb, skb->data - skb_network_header(skb)); - - NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, - dev_net(skb->dev), NULL, skb, skb->dev, NULL, - ip6_rcv_finish); - return -1; -} - -int xfrm6_rcv_tnl(struct sk_buff *skb, struct ip6_tnl *t) -{ - return xfrm6_rcv_spi(skb, skb_network_header(skb)[IP6CB(skb)->nhoff], - 0, t); -} -EXPORT_SYMBOL(xfrm6_rcv_tnl); - -int xfrm6_rcv(struct sk_buff *skb) -{ - return xfrm6_rcv_tnl(skb, NULL); -} -EXPORT_SYMBOL(xfrm6_rcv); -int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, - xfrm_address_t *saddr, u8 proto) -{ - struct net *net = dev_net(skb->dev); - struct xfrm_state *x = NULL; - int i = 0; - - /* Allocate new secpath or COW existing one. */ - if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { - struct sec_path *sp; - - sp = secpath_dup(skb->sp); - if (!sp) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR); - goto drop; - } - if (skb->sp) - secpath_put(skb->sp); - skb->sp = sp; - } - - if (1 + skb->sp->len == XFRM_MAX_DEPTH) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR); - goto drop; - } - - for (i = 0; i < 3; i++) { - xfrm_address_t *dst, *src; - - switch (i) { - case 0: - dst = daddr; - src = saddr; - break; - case 1: - /* lookup state with wild-card source address */ - dst = daddr; - src = (xfrm_address_t *)&in6addr_any; - break; - default: - /* lookup state with wild-card addresses */ - dst = (xfrm_address_t *)&in6addr_any; - src = (xfrm_address_t *)&in6addr_any; - break; - } - - x = xfrm_state_lookup_byaddr(net, skb->mark, dst, src, proto, AF_INET6); - if (!x) - continue; - - spin_lock(&x->lock); - - if ((!i || (x->props.flags & XFRM_STATE_WILDRECV)) && - likely(x->km.state == XFRM_STATE_VALID) && - !xfrm_state_check_expire(x)) { - spin_unlock(&x->lock); - if (x->type->input(x, skb) > 0) { - /* found a valid state */ - break; - } - } else - spin_unlock(&x->lock); - - xfrm_state_put(x); - x = NULL; - } - - if (!x) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES); - xfrm_audit_state_notfound_simple(skb, AF_INET6); - goto drop; - } - - skb->sp->xvec[skb->sp->len++] = x; - - spin_lock(&x->lock); - - x->curlft.bytes += skb->len; - x->curlft.packets++; - - spin_unlock(&x->lock); - - return 1; - -drop: - return -1; -} -EXPORT_SYMBOL(xfrm6_input_addr); diff --git a/src/linux/net/ipv6/xfrm6_mode_beet.c b/src/linux/net/ipv6/xfrm6_mode_beet.c deleted file mode 100644 index 1e205c3..0000000 --- a/src/linux/net/ipv6/xfrm6_mode_beet.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - * xfrm6_mode_beet.c - BEET mode encapsulation for IPv6. - * - * Copyright (c) 2006 Diego Beltrami - * Miika Komu - * Herbert Xu - * Abhinav Pathak - * Jeff Ahrenholz - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static void xfrm6_beet_make_header(struct sk_buff *skb) -{ - struct ipv6hdr *iph = ipv6_hdr(skb); - - iph->version = 6; - - memcpy(iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl, - sizeof(iph->flow_lbl)); - iph->nexthdr = XFRM_MODE_SKB_CB(skb)->protocol; - - ipv6_change_dsfield(iph, 0, XFRM_MODE_SKB_CB(skb)->tos); - iph->hop_limit = XFRM_MODE_SKB_CB(skb)->ttl; -} - -/* Add encapsulation header. - * - * The top IP header will be constructed per draft-nikander-esp-beet-mode-06.txt. - */ -static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) -{ - struct ipv6hdr *top_iph; - struct ip_beet_phdr *ph; - int optlen, hdr_len; - - hdr_len = 0; - optlen = XFRM_MODE_SKB_CB(skb)->optlen; - if (unlikely(optlen)) - hdr_len += IPV4_BEET_PHMAXLEN - (optlen & 4); - - skb_set_network_header(skb, -x->props.header_len - hdr_len); - if (x->sel.family != AF_INET6) - skb->network_header += IPV4_BEET_PHMAXLEN; - skb->mac_header = skb->network_header + - offsetof(struct ipv6hdr, nexthdr); - skb->transport_header = skb->network_header + sizeof(*top_iph); - ph = (struct ip_beet_phdr *)__skb_pull(skb, XFRM_MODE_SKB_CB(skb)->ihl-hdr_len); - - xfrm6_beet_make_header(skb); - - top_iph = ipv6_hdr(skb); - if (unlikely(optlen)) { - - BUG_ON(optlen < 0); - - ph->padlen = 4 - (optlen & 4); - ph->hdrlen = optlen / 8; - ph->nexthdr = top_iph->nexthdr; - if (ph->padlen) - memset(ph + 1, IPOPT_NOP, ph->padlen); - - top_iph->nexthdr = IPPROTO_BEETPH; - } - - top_iph->saddr = *(struct in6_addr *)&x->props.saddr; - top_iph->daddr = *(struct in6_addr *)&x->id.daddr; - return 0; -} - -static int xfrm6_beet_input(struct xfrm_state *x, struct sk_buff *skb) -{ - struct ipv6hdr *ip6h; - int size = sizeof(struct ipv6hdr); - int err; - - err = skb_cow_head(skb, size + skb->mac_len); - if (err) - goto out; - - __skb_push(skb, size); - skb_reset_network_header(skb); - skb_mac_header_rebuild(skb); - - xfrm6_beet_make_header(skb); - - ip6h = ipv6_hdr(skb); - ip6h->payload_len = htons(skb->len - size); - ip6h->daddr = x->sel.daddr.in6; - ip6h->saddr = x->sel.saddr.in6; - err = 0; -out: - return err; -} - -static struct xfrm_mode xfrm6_beet_mode = { - .input2 = xfrm6_beet_input, - .input = xfrm_prepare_input, - .output2 = xfrm6_beet_output, - .output = xfrm6_prepare_output, - .owner = THIS_MODULE, - .encap = XFRM_MODE_BEET, - .flags = XFRM_MODE_FLAG_TUNNEL, -}; - -static int __init xfrm6_beet_init(void) -{ - return xfrm_register_mode(&xfrm6_beet_mode, AF_INET6); -} - -static void __exit xfrm6_beet_exit(void) -{ - int err; - - err = xfrm_unregister_mode(&xfrm6_beet_mode, AF_INET6); - BUG_ON(err); -} - -module_init(xfrm6_beet_init); -module_exit(xfrm6_beet_exit); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_BEET); diff --git a/src/linux/net/ipv6/xfrm6_mode_transport.c b/src/linux/net/ipv6/xfrm6_mode_transport.c deleted file mode 100644 index 4e34410..0000000 --- a/src/linux/net/ipv6/xfrm6_mode_transport.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * xfrm6_mode_transport.c - Transport mode encapsulation for IPv6. - * - * Copyright (C) 2002 USAGI/WIDE Project - * Copyright (c) 2004-2006 Herbert Xu - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -/* Add encapsulation header. - * - * The IP header and mutable extension headers will be moved forward to make - * space for the encapsulation header. - */ -static int xfrm6_transport_output(struct xfrm_state *x, struct sk_buff *skb) -{ - struct ipv6hdr *iph; - u8 *prevhdr; - int hdr_len; - - iph = ipv6_hdr(skb); - - hdr_len = x->type->hdr_offset(x, skb, &prevhdr); - skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data); - skb_set_network_header(skb, -x->props.header_len); - skb->transport_header = skb->network_header + hdr_len; - __skb_pull(skb, hdr_len); - memmove(ipv6_hdr(skb), iph, hdr_len); - return 0; -} - -/* Remove encapsulation header. - * - * The IP header will be moved over the top of the encapsulation header. - * - * On entry, skb->h shall point to where the IP header should be and skb->nh - * shall be set to where the IP header currently is. skb->data shall point - * to the start of the payload. - */ -static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb) -{ - int ihl = skb->data - skb_transport_header(skb); - - if (skb->transport_header != skb->network_header) { - memmove(skb_transport_header(skb), - skb_network_header(skb), ihl); - skb->network_header = skb->transport_header; - } - ipv6_hdr(skb)->payload_len = htons(skb->len + ihl - - sizeof(struct ipv6hdr)); - skb_reset_transport_header(skb); - return 0; -} - -static struct xfrm_mode xfrm6_transport_mode = { - .input = xfrm6_transport_input, - .output = xfrm6_transport_output, - .owner = THIS_MODULE, - .encap = XFRM_MODE_TRANSPORT, -}; - -static int __init xfrm6_transport_init(void) -{ - return xfrm_register_mode(&xfrm6_transport_mode, AF_INET6); -} - -static void __exit xfrm6_transport_exit(void) -{ - int err; - - err = xfrm_unregister_mode(&xfrm6_transport_mode, AF_INET6); - BUG_ON(err); -} - -module_init(xfrm6_transport_init); -module_exit(xfrm6_transport_exit); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_TRANSPORT); diff --git a/src/linux/net/ipv6/xfrm6_mode_tunnel.c b/src/linux/net/ipv6/xfrm6_mode_tunnel.c deleted file mode 100644 index 372855e..0000000 --- a/src/linux/net/ipv6/xfrm6_mode_tunnel.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * xfrm6_mode_tunnel.c - Tunnel mode encapsulation for IPv6. - * - * Copyright (C) 2002 USAGI/WIDE Project - * Copyright (c) 2004-2006 Herbert Xu - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) -{ - struct ipv6hdr *inner_iph = ipipv6_hdr(skb); - - if (INET_ECN_is_ce(XFRM_MODE_SKB_CB(skb)->tos)) - IP6_ECN_set_ce(skb, inner_iph); -} - -/* Add encapsulation header. - * - * The top IP header will be constructed per RFC 2401. - */ -static int xfrm6_mode_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) -{ - struct dst_entry *dst = skb_dst(skb); - struct ipv6hdr *top_iph; - int dsfield; - - skb_set_network_header(skb, -x->props.header_len); - skb->mac_header = skb->network_header + - offsetof(struct ipv6hdr, nexthdr); - skb->transport_header = skb->network_header + sizeof(*top_iph); - top_iph = ipv6_hdr(skb); - - top_iph->version = 6; - - memcpy(top_iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl, - sizeof(top_iph->flow_lbl)); - top_iph->nexthdr = xfrm_af2proto(skb_dst(skb)->ops->family); - - if (x->props.extra_flags & XFRM_SA_XFLAG_DONT_ENCAP_DSCP) - dsfield = 0; - else - dsfield = XFRM_MODE_SKB_CB(skb)->tos; - dsfield = INET_ECN_encapsulate(dsfield, XFRM_MODE_SKB_CB(skb)->tos); - if (x->props.flags & XFRM_STATE_NOECN) - dsfield &= ~INET_ECN_MASK; - ipv6_change_dsfield(top_iph, 0, dsfield); - top_iph->hop_limit = ip6_dst_hoplimit(dst->child); - top_iph->saddr = *(struct in6_addr *)&x->props.saddr; - top_iph->daddr = *(struct in6_addr *)&x->id.daddr; - return 0; -} - -#define for_each_input_rcu(head, handler) \ - for (handler = rcu_dereference(head); \ - handler != NULL; \ - handler = rcu_dereference(handler->next)) - - -static int xfrm6_mode_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) -{ - int err = -EINVAL; - - if (XFRM_MODE_SKB_CB(skb)->protocol != IPPROTO_IPV6) - goto out; - if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) - goto out; - - err = skb_unclone(skb, GFP_ATOMIC); - if (err) - goto out; - - if (x->props.flags & XFRM_STATE_DECAP_DSCP) - ipv6_copy_dscp(ipv6_get_dsfield(ipv6_hdr(skb)), - ipipv6_hdr(skb)); - if (!(x->props.flags & XFRM_STATE_NOECN)) - ipip6_ecn_decapsulate(skb); - - skb_reset_network_header(skb); - skb_mac_header_rebuild(skb); - - err = 0; - -out: - return err; -} - -static struct xfrm_mode xfrm6_tunnel_mode = { - .input2 = xfrm6_mode_tunnel_input, - .input = xfrm_prepare_input, - .output2 = xfrm6_mode_tunnel_output, - .output = xfrm6_prepare_output, - .owner = THIS_MODULE, - .encap = XFRM_MODE_TUNNEL, - .flags = XFRM_MODE_FLAG_TUNNEL, -}; - -static int __init xfrm6_mode_tunnel_init(void) -{ - return xfrm_register_mode(&xfrm6_tunnel_mode, AF_INET6); -} - -static void __exit xfrm6_mode_tunnel_exit(void) -{ - int err; - - err = xfrm_unregister_mode(&xfrm6_tunnel_mode, AF_INET6); - BUG_ON(err); -} - -module_init(xfrm6_mode_tunnel_init); -module_exit(xfrm6_mode_tunnel_exit); -MODULE_LICENSE("GPL"); -MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_TUNNEL); diff --git a/src/linux/net/ipv6/xfrm6_output.c b/src/linux/net/ipv6/xfrm6_output.c deleted file mode 100644 index 4d09ce6..0000000 --- a/src/linux/net/ipv6/xfrm6_output.c +++ /dev/null @@ -1,188 +0,0 @@ -/* - * xfrm6_output.c - Common IPsec encapsulation code for IPv6. - * Copyright (C) 2002 USAGI/WIDE Project - * Copyright (c) 2004 Herbert Xu - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, - u8 **prevhdr) -{ - return ip6_find_1stfragopt(skb, prevhdr); -} -EXPORT_SYMBOL(xfrm6_find_1stfragopt); - -static int xfrm6_local_dontfrag(struct sk_buff *skb) -{ - int proto; - struct sock *sk = skb->sk; - - if (sk) { - if (sk->sk_family != AF_INET6) - return 0; - - proto = sk->sk_protocol; - if (proto == IPPROTO_UDP || proto == IPPROTO_RAW) - return inet6_sk(sk)->dontfrag; - } - - return 0; -} - -static void xfrm6_local_rxpmtu(struct sk_buff *skb, u32 mtu) -{ - struct flowi6 fl6; - struct sock *sk = skb->sk; - - fl6.flowi6_oif = sk->sk_bound_dev_if; - fl6.daddr = ipv6_hdr(skb)->daddr; - - ipv6_local_rxpmtu(sk, &fl6, mtu); -} - -void xfrm6_local_error(struct sk_buff *skb, u32 mtu) -{ - struct flowi6 fl6; - const struct ipv6hdr *hdr; - struct sock *sk = skb->sk; - - hdr = skb->encapsulation ? inner_ipv6_hdr(skb) : ipv6_hdr(skb); - fl6.fl6_dport = inet_sk(sk)->inet_dport; - fl6.daddr = hdr->daddr; - - ipv6_local_error(sk, EMSGSIZE, &fl6, mtu); -} - -static int xfrm6_tunnel_check_size(struct sk_buff *skb) -{ - int mtu, ret = 0; - struct dst_entry *dst = skb_dst(skb); - - mtu = dst_mtu(dst); - if (mtu < IPV6_MIN_MTU) - mtu = IPV6_MIN_MTU; - - if (!skb->ignore_df && skb->len > mtu) { - skb->dev = dst->dev; - skb->protocol = htons(ETH_P_IPV6); - - if (xfrm6_local_dontfrag(skb)) - xfrm6_local_rxpmtu(skb, mtu); - else if (skb->sk) - xfrm_local_error(skb, mtu); - else - icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); - ret = -EMSGSIZE; - } - - return ret; -} - -int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb) -{ - int err; - - err = xfrm6_tunnel_check_size(skb); - if (err) - return err; - - XFRM_MODE_SKB_CB(skb)->protocol = ipv6_hdr(skb)->nexthdr; - - return xfrm6_extract_header(skb); -} - -int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb) -{ - int err; - - err = xfrm_inner_extract_output(x, skb); - if (err) - return err; - - skb->ignore_df = 1; - skb->protocol = htons(ETH_P_IPV6); - - return x->outer_mode->output2(x, skb); -} -EXPORT_SYMBOL(xfrm6_prepare_output); - -int xfrm6_output_finish(struct sock *sk, struct sk_buff *skb) -{ - memset(IP6CB(skb), 0, sizeof(*IP6CB(skb))); - -#ifdef CONFIG_NETFILTER - IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED; -#endif - - return xfrm_output(sk, skb); -} - -static int __xfrm6_output_finish(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - struct xfrm_state *x = skb_dst(skb)->xfrm; - - return x->outer_mode->afinfo->output_finish(sk, skb); -} - -static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - struct dst_entry *dst = skb_dst(skb); - struct xfrm_state *x = dst->xfrm; - int mtu; - bool toobig; - -#ifdef CONFIG_NETFILTER - if (!x) { - IP6CB(skb)->flags |= IP6SKB_REROUTED; - return dst_output(net, sk, skb); - } -#endif - - if (x->props.mode != XFRM_MODE_TUNNEL) - goto skip_frag; - - if (skb->protocol == htons(ETH_P_IPV6)) - mtu = ip6_skb_dst_mtu(skb); - else - mtu = dst_mtu(skb_dst(skb)); - - toobig = skb->len > mtu && !skb_is_gso(skb); - - if (toobig && xfrm6_local_dontfrag(skb)) { - xfrm6_local_rxpmtu(skb, mtu); - return -EMSGSIZE; - } else if (!skb->ignore_df && toobig && skb->sk) { - xfrm_local_error(skb, mtu); - return -EMSGSIZE; - } - - if (toobig || dst_allfrag(skb_dst(skb))) - return ip6_fragment(net, sk, skb, - __xfrm6_output_finish); - -skip_frag: - return x->outer_mode->afinfo->output_finish(sk, skb); -} - -int xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - return NF_HOOK_COND(NFPROTO_IPV6, NF_INET_POST_ROUTING, - net, sk, skb, NULL, skb_dst(skb)->dev, - __xfrm6_output, - !(IP6CB(skb)->flags & IP6SKB_REROUTED)); -} diff --git a/src/linux/net/ipv6/xfrm6_policy.c b/src/linux/net/ipv6/xfrm6_policy.c deleted file mode 100644 index e0f71c0..0000000 --- a/src/linux/net/ipv6/xfrm6_policy.c +++ /dev/null @@ -1,438 +0,0 @@ -/* - * xfrm6_policy.c: based on xfrm4_policy.c - * - * Authors: - * Mitsuru KANDA @USAGI - * Kazunori MIYAZAWA @USAGI - * Kunihiro Ishiguro - * IPv6 support - * YOSHIFUJI Hideaki - * Split up af-specific portion - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if IS_ENABLED(CONFIG_IPV6_MIP6) -#include -#endif - -static struct xfrm_policy_afinfo xfrm6_policy_afinfo; - -static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, int oif, - const xfrm_address_t *saddr, - const xfrm_address_t *daddr) -{ - struct flowi6 fl6; - struct dst_entry *dst; - int err; - - memset(&fl6, 0, sizeof(fl6)); - fl6.flowi6_oif = l3mdev_master_ifindex_by_index(net, oif); - fl6.flowi6_flags = FLOWI_FLAG_SKIP_NH_OIF; - memcpy(&fl6.daddr, daddr, sizeof(fl6.daddr)); - if (saddr) - memcpy(&fl6.saddr, saddr, sizeof(fl6.saddr)); - - dst = ip6_route_output(net, NULL, &fl6); - - err = dst->error; - if (dst->error) { - dst_release(dst); - dst = ERR_PTR(err); - } - - return dst; -} - -static int xfrm6_get_saddr(struct net *net, int oif, - xfrm_address_t *saddr, xfrm_address_t *daddr) -{ - struct dst_entry *dst; - struct net_device *dev; - - dst = xfrm6_dst_lookup(net, 0, oif, NULL, daddr); - if (IS_ERR(dst)) - return -EHOSTUNREACH; - - dev = ip6_dst_idev(dst)->dev; - ipv6_dev_get_saddr(dev_net(dev), dev, &daddr->in6, 0, &saddr->in6); - dst_release(dst); - return 0; -} - -static int xfrm6_get_tos(const struct flowi *fl) -{ - return 0; -} - -static int xfrm6_init_path(struct xfrm_dst *path, struct dst_entry *dst, - int nfheader_len) -{ - if (dst->ops->family == AF_INET6) { - struct rt6_info *rt = (struct rt6_info *)dst; - path->path_cookie = rt6_get_cookie(rt); - } - - path->u.rt6.rt6i_nfheader_len = nfheader_len; - - return 0; -} - -static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, - const struct flowi *fl) -{ - struct rt6_info *rt = (struct rt6_info *)xdst->route; - - xdst->u.dst.dev = dev; - dev_hold(dev); - - xdst->u.rt6.rt6i_idev = in6_dev_get(dev); - if (!xdst->u.rt6.rt6i_idev) { - dev_put(dev); - return -ENODEV; - } - - /* Sheit... I remember I did this right. Apparently, - * it was magically lost, so this code needs audit */ - xdst->u.rt6.rt6i_flags = rt->rt6i_flags & (RTF_ANYCAST | - RTF_LOCAL); - xdst->u.rt6.rt6i_metric = rt->rt6i_metric; - xdst->u.rt6.rt6i_node = rt->rt6i_node; - xdst->route_cookie = rt6_get_cookie(rt); - xdst->u.rt6.rt6i_gateway = rt->rt6i_gateway; - xdst->u.rt6.rt6i_dst = rt->rt6i_dst; - xdst->u.rt6.rt6i_src = rt->rt6i_src; - - return 0; -} - -static inline void -_decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) -{ - struct flowi6 *fl6 = &fl->u.ip6; - int onlyproto = 0; - const struct ipv6hdr *hdr = ipv6_hdr(skb); - u16 offset = sizeof(*hdr); - struct ipv6_opt_hdr *exthdr; - const unsigned char *nh = skb_network_header(skb); - u16 nhoff = IP6CB(skb)->nhoff; - int oif = 0; - u8 nexthdr; - - if (!nhoff) - nhoff = offsetof(struct ipv6hdr, nexthdr); - - nexthdr = nh[nhoff]; - - if (skb_dst(skb)) - oif = skb_dst(skb)->dev->ifindex; - - memset(fl6, 0, sizeof(struct flowi6)); - fl6->flowi6_mark = skb->mark; - fl6->flowi6_oif = reverse ? skb->skb_iif : oif; - - fl6->daddr = reverse ? hdr->saddr : hdr->daddr; - fl6->saddr = reverse ? hdr->daddr : hdr->saddr; - - while (nh + offset + 1 < skb->data || - pskb_may_pull(skb, nh + offset + 1 - skb->data)) { - nh = skb_network_header(skb); - exthdr = (struct ipv6_opt_hdr *)(nh + offset); - - switch (nexthdr) { - case NEXTHDR_FRAGMENT: - onlyproto = 1; - case NEXTHDR_ROUTING: - case NEXTHDR_HOP: - case NEXTHDR_DEST: - offset += ipv6_optlen(exthdr); - nexthdr = exthdr->nexthdr; - exthdr = (struct ipv6_opt_hdr *)(nh + offset); - break; - - case IPPROTO_UDP: - case IPPROTO_UDPLITE: - case IPPROTO_TCP: - case IPPROTO_SCTP: - case IPPROTO_DCCP: - if (!onlyproto && (nh + offset + 4 < skb->data || - pskb_may_pull(skb, nh + offset + 4 - skb->data))) { - __be16 *ports; - - nh = skb_network_header(skb); - ports = (__be16 *)(nh + offset); - fl6->fl6_sport = ports[!!reverse]; - fl6->fl6_dport = ports[!reverse]; - } - fl6->flowi6_proto = nexthdr; - return; - - case IPPROTO_ICMPV6: - if (!onlyproto && (nh + offset + 2 < skb->data || - pskb_may_pull(skb, nh + offset + 2 - skb->data))) { - u8 *icmp; - - nh = skb_network_header(skb); - icmp = (u8 *)(nh + offset); - fl6->fl6_icmp_type = icmp[0]; - fl6->fl6_icmp_code = icmp[1]; - } - fl6->flowi6_proto = nexthdr; - return; - -#if IS_ENABLED(CONFIG_IPV6_MIP6) - case IPPROTO_MH: - offset += ipv6_optlen(exthdr); - if (!onlyproto && (nh + offset + 3 < skb->data || - pskb_may_pull(skb, nh + offset + 3 - skb->data))) { - struct ip6_mh *mh; - - nh = skb_network_header(skb); - mh = (struct ip6_mh *)(nh + offset); - fl6->fl6_mh_type = mh->ip6mh_type; - } - fl6->flowi6_proto = nexthdr; - return; -#endif - - /* XXX Why are there these headers? */ - case IPPROTO_AH: - case IPPROTO_ESP: - case IPPROTO_COMP: - default: - fl6->fl6_ipsec_spi = 0; - fl6->flowi6_proto = nexthdr; - return; - } - } -} - -static inline int xfrm6_garbage_collect(struct dst_ops *ops) -{ - struct net *net = container_of(ops, struct net, xfrm.xfrm6_dst_ops); - - xfrm6_policy_afinfo.garbage_collect(net); - return dst_entries_get_fast(ops) > ops->gc_thresh * 2; -} - -static void xfrm6_update_pmtu(struct dst_entry *dst, struct sock *sk, - struct sk_buff *skb, u32 mtu) -{ - struct xfrm_dst *xdst = (struct xfrm_dst *)dst; - struct dst_entry *path = xdst->route; - - path->ops->update_pmtu(path, sk, skb, mtu); -} - -static void xfrm6_redirect(struct dst_entry *dst, struct sock *sk, - struct sk_buff *skb) -{ - struct xfrm_dst *xdst = (struct xfrm_dst *)dst; - struct dst_entry *path = xdst->route; - - path->ops->redirect(path, sk, skb); -} - -static void xfrm6_dst_destroy(struct dst_entry *dst) -{ - struct xfrm_dst *xdst = (struct xfrm_dst *)dst; - - if (likely(xdst->u.rt6.rt6i_idev)) - in6_dev_put(xdst->u.rt6.rt6i_idev); - dst_destroy_metrics_generic(dst); - xfrm_dst_destroy(xdst); -} - -static void xfrm6_dst_ifdown(struct dst_entry *dst, struct net_device *dev, - int unregister) -{ - struct xfrm_dst *xdst; - - if (!unregister) - return; - - xdst = (struct xfrm_dst *)dst; - if (xdst->u.rt6.rt6i_idev->dev == dev) { - struct inet6_dev *loopback_idev = - in6_dev_get(dev_net(dev)->loopback_dev); - BUG_ON(!loopback_idev); - - do { - in6_dev_put(xdst->u.rt6.rt6i_idev); - xdst->u.rt6.rt6i_idev = loopback_idev; - in6_dev_hold(loopback_idev); - xdst = (struct xfrm_dst *)xdst->u.dst.child; - } while (xdst->u.dst.xfrm); - - __in6_dev_put(loopback_idev); - } - - xfrm_dst_ifdown(dst, dev); -} - -static struct dst_ops xfrm6_dst_ops_template = { - .family = AF_INET6, - .gc = xfrm6_garbage_collect, - .update_pmtu = xfrm6_update_pmtu, - .redirect = xfrm6_redirect, - .cow_metrics = dst_cow_metrics_generic, - .destroy = xfrm6_dst_destroy, - .ifdown = xfrm6_dst_ifdown, - .local_out = __ip6_local_out, - .gc_thresh = INT_MAX, -}; - -static struct xfrm_policy_afinfo xfrm6_policy_afinfo = { - .family = AF_INET6, - .dst_ops = &xfrm6_dst_ops_template, - .dst_lookup = xfrm6_dst_lookup, - .get_saddr = xfrm6_get_saddr, - .decode_session = _decode_session6, - .get_tos = xfrm6_get_tos, - .init_path = xfrm6_init_path, - .fill_dst = xfrm6_fill_dst, - .blackhole_route = ip6_blackhole_route, -}; - -static int __init xfrm6_policy_init(void) -{ - return xfrm_policy_register_afinfo(&xfrm6_policy_afinfo); -} - -static void xfrm6_policy_fini(void) -{ - xfrm_policy_unregister_afinfo(&xfrm6_policy_afinfo); -} - -#ifdef CONFIG_SYSCTL -static struct ctl_table xfrm6_policy_table[] = { - { - .procname = "xfrm6_gc_thresh", - .data = &init_net.xfrm.xfrm6_dst_ops.gc_thresh, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { } -}; - -static int __net_init xfrm6_net_sysctl_init(struct net *net) -{ - struct ctl_table *table; - struct ctl_table_header *hdr; - - table = xfrm6_policy_table; - if (!net_eq(net, &init_net)) { - table = kmemdup(table, sizeof(xfrm6_policy_table), GFP_KERNEL); - if (!table) - goto err_alloc; - - table[0].data = &net->xfrm.xfrm6_dst_ops.gc_thresh; - } - - hdr = register_net_sysctl(net, "net/ipv6", table); - if (!hdr) - goto err_reg; - - net->ipv6.sysctl.xfrm6_hdr = hdr; - return 0; - -err_reg: - if (!net_eq(net, &init_net)) - kfree(table); -err_alloc: - return -ENOMEM; -} - -static void __net_exit xfrm6_net_sysctl_exit(struct net *net) -{ - struct ctl_table *table; - - if (!net->ipv6.sysctl.xfrm6_hdr) - return; - - table = net->ipv6.sysctl.xfrm6_hdr->ctl_table_arg; - unregister_net_sysctl_table(net->ipv6.sysctl.xfrm6_hdr); - if (!net_eq(net, &init_net)) - kfree(table); -} -#else /* CONFIG_SYSCTL */ -static inline int xfrm6_net_sysctl_init(struct net *net) -{ - return 0; -} - -static inline void xfrm6_net_sysctl_exit(struct net *net) -{ -} -#endif - -static int __net_init xfrm6_net_init(struct net *net) -{ - int ret; - - memcpy(&net->xfrm.xfrm6_dst_ops, &xfrm6_dst_ops_template, - sizeof(xfrm6_dst_ops_template)); - ret = dst_entries_init(&net->xfrm.xfrm6_dst_ops); - if (ret) - return ret; - - ret = xfrm6_net_sysctl_init(net); - if (ret) - dst_entries_destroy(&net->xfrm.xfrm6_dst_ops); - - return ret; -} - -static void __net_exit xfrm6_net_exit(struct net *net) -{ - xfrm6_net_sysctl_exit(net); - dst_entries_destroy(&net->xfrm.xfrm6_dst_ops); -} - -static struct pernet_operations xfrm6_net_ops = { - .init = xfrm6_net_init, - .exit = xfrm6_net_exit, -}; - -int __init xfrm6_init(void) -{ - int ret; - - ret = xfrm6_policy_init(); - if (ret) - goto out; - ret = xfrm6_state_init(); - if (ret) - goto out_policy; - - ret = xfrm6_protocol_init(); - if (ret) - goto out_state; - - register_pernet_subsys(&xfrm6_net_ops); -out: - return ret; -out_state: - xfrm6_state_fini(); -out_policy: - xfrm6_policy_fini(); - goto out; -} - -void xfrm6_fini(void) -{ - unregister_pernet_subsys(&xfrm6_net_ops); - xfrm6_protocol_fini(); - xfrm6_policy_fini(); - xfrm6_state_fini(); -} diff --git a/src/linux/net/ipv6/xfrm6_protocol.c b/src/linux/net/ipv6/xfrm6_protocol.c deleted file mode 100644 index 54d13f8..0000000 --- a/src/linux/net/ipv6/xfrm6_protocol.c +++ /dev/null @@ -1,279 +0,0 @@ -/* xfrm6_protocol.c - Generic xfrm protocol multiplexer for ipv6. - * - * Copyright (C) 2013 secunet Security Networks AG - * - * Author: - * Steffen Klassert - * - * Based on: - * net/ipv4/xfrm4_protocol.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include - -static struct xfrm6_protocol __rcu *esp6_handlers __read_mostly; -static struct xfrm6_protocol __rcu *ah6_handlers __read_mostly; -static struct xfrm6_protocol __rcu *ipcomp6_handlers __read_mostly; -static DEFINE_MUTEX(xfrm6_protocol_mutex); - -static inline struct xfrm6_protocol __rcu **proto_handlers(u8 protocol) -{ - switch (protocol) { - case IPPROTO_ESP: - return &esp6_handlers; - case IPPROTO_AH: - return &ah6_handlers; - case IPPROTO_COMP: - return &ipcomp6_handlers; - } - - return NULL; -} - -#define for_each_protocol_rcu(head, handler) \ - for (handler = rcu_dereference(head); \ - handler != NULL; \ - handler = rcu_dereference(handler->next)) \ - -int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err) -{ - int ret; - struct xfrm6_protocol *handler; - struct xfrm6_protocol __rcu **head = proto_handlers(protocol); - - if (!head) - return 0; - - for_each_protocol_rcu(*proto_handlers(protocol), handler) - if ((ret = handler->cb_handler(skb, err)) <= 0) - return ret; - - return 0; -} -EXPORT_SYMBOL(xfrm6_rcv_cb); - -static int xfrm6_esp_rcv(struct sk_buff *skb) -{ - int ret; - struct xfrm6_protocol *handler; - - XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL; - - for_each_protocol_rcu(esp6_handlers, handler) - if ((ret = handler->handler(skb)) != -EINVAL) - return ret; - - icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); - - kfree_skb(skb); - return 0; -} - -static void xfrm6_esp_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - u8 type, u8 code, int offset, __be32 info) -{ - struct xfrm6_protocol *handler; - - for_each_protocol_rcu(esp6_handlers, handler) - if (!handler->err_handler(skb, opt, type, code, offset, info)) - break; -} - -static int xfrm6_ah_rcv(struct sk_buff *skb) -{ - int ret; - struct xfrm6_protocol *handler; - - XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL; - - for_each_protocol_rcu(ah6_handlers, handler) - if ((ret = handler->handler(skb)) != -EINVAL) - return ret; - - icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); - - kfree_skb(skb); - return 0; -} - -static void xfrm6_ah_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - u8 type, u8 code, int offset, __be32 info) -{ - struct xfrm6_protocol *handler; - - for_each_protocol_rcu(ah6_handlers, handler) - if (!handler->err_handler(skb, opt, type, code, offset, info)) - break; -} - -static int xfrm6_ipcomp_rcv(struct sk_buff *skb) -{ - int ret; - struct xfrm6_protocol *handler; - - XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL; - - for_each_protocol_rcu(ipcomp6_handlers, handler) - if ((ret = handler->handler(skb)) != -EINVAL) - return ret; - - icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); - - kfree_skb(skb); - return 0; -} - -static void xfrm6_ipcomp_err(struct sk_buff *skb, struct inet6_skb_parm *opt, - u8 type, u8 code, int offset, __be32 info) -{ - struct xfrm6_protocol *handler; - - for_each_protocol_rcu(ipcomp6_handlers, handler) - if (!handler->err_handler(skb, opt, type, code, offset, info)) - break; -} - -static const struct inet6_protocol esp6_protocol = { - .handler = xfrm6_esp_rcv, - .err_handler = xfrm6_esp_err, - .flags = INET6_PROTO_NOPOLICY, -}; - -static const struct inet6_protocol ah6_protocol = { - .handler = xfrm6_ah_rcv, - .err_handler = xfrm6_ah_err, - .flags = INET6_PROTO_NOPOLICY, -}; - -static const struct inet6_protocol ipcomp6_protocol = { - .handler = xfrm6_ipcomp_rcv, - .err_handler = xfrm6_ipcomp_err, - .flags = INET6_PROTO_NOPOLICY, -}; - -static struct xfrm_input_afinfo xfrm6_input_afinfo = { - .family = AF_INET6, - .owner = THIS_MODULE, - .callback = xfrm6_rcv_cb, -}; - -static inline const struct inet6_protocol *netproto(unsigned char protocol) -{ - switch (protocol) { - case IPPROTO_ESP: - return &esp6_protocol; - case IPPROTO_AH: - return &ah6_protocol; - case IPPROTO_COMP: - return &ipcomp6_protocol; - } - - return NULL; -} - -int xfrm6_protocol_register(struct xfrm6_protocol *handler, - unsigned char protocol) -{ - struct xfrm6_protocol __rcu **pprev; - struct xfrm6_protocol *t; - bool add_netproto = false; - int ret = -EEXIST; - int priority = handler->priority; - - if (!proto_handlers(protocol) || !netproto(protocol)) - return -EINVAL; - - mutex_lock(&xfrm6_protocol_mutex); - - if (!rcu_dereference_protected(*proto_handlers(protocol), - lockdep_is_held(&xfrm6_protocol_mutex))) - add_netproto = true; - - for (pprev = proto_handlers(protocol); - (t = rcu_dereference_protected(*pprev, - lockdep_is_held(&xfrm6_protocol_mutex))) != NULL; - pprev = &t->next) { - if (t->priority < priority) - break; - if (t->priority == priority) - goto err; - } - - handler->next = *pprev; - rcu_assign_pointer(*pprev, handler); - - ret = 0; - -err: - mutex_unlock(&xfrm6_protocol_mutex); - - if (add_netproto) { - if (inet6_add_protocol(netproto(protocol), protocol)) { - pr_err("%s: can't add protocol\n", __func__); - ret = -EAGAIN; - } - } - - return ret; -} -EXPORT_SYMBOL(xfrm6_protocol_register); - -int xfrm6_protocol_deregister(struct xfrm6_protocol *handler, - unsigned char protocol) -{ - struct xfrm6_protocol __rcu **pprev; - struct xfrm6_protocol *t; - int ret = -ENOENT; - - if (!proto_handlers(protocol) || !netproto(protocol)) - return -EINVAL; - - mutex_lock(&xfrm6_protocol_mutex); - - for (pprev = proto_handlers(protocol); - (t = rcu_dereference_protected(*pprev, - lockdep_is_held(&xfrm6_protocol_mutex))) != NULL; - pprev = &t->next) { - if (t == handler) { - *pprev = handler->next; - ret = 0; - break; - } - } - - if (!rcu_dereference_protected(*proto_handlers(protocol), - lockdep_is_held(&xfrm6_protocol_mutex))) { - if (inet6_del_protocol(netproto(protocol), protocol) < 0) { - pr_err("%s: can't remove protocol\n", __func__); - ret = -EAGAIN; - } - } - - mutex_unlock(&xfrm6_protocol_mutex); - - synchronize_net(); - - return ret; -} -EXPORT_SYMBOL(xfrm6_protocol_deregister); - -int __init xfrm6_protocol_init(void) -{ - return xfrm_input_register_afinfo(&xfrm6_input_afinfo); -} - -void xfrm6_protocol_fini(void) -{ - xfrm_input_unregister_afinfo(&xfrm6_input_afinfo); -} diff --git a/src/linux/net/ipv6/xfrm6_state.c b/src/linux/net/ipv6/xfrm6_state.c deleted file mode 100644 index 8a1f9c0..0000000 --- a/src/linux/net/ipv6/xfrm6_state.c +++ /dev/null @@ -1,198 +0,0 @@ -/* - * xfrm6_state.c: based on xfrm4_state.c - * - * Authors: - * Mitsuru KANDA @USAGI - * Kazunori MIYAZAWA @USAGI - * Kunihiro Ishiguro - * IPv6 support - * YOSHIFUJI Hideaki @USAGI - * Split up af-specific portion - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static void -__xfrm6_init_tempsel(struct xfrm_selector *sel, const struct flowi *fl) -{ - const struct flowi6 *fl6 = &fl->u.ip6; - - /* Initialize temporary selector matching only - * to current session. */ - *(struct in6_addr *)&sel->daddr = fl6->daddr; - *(struct in6_addr *)&sel->saddr = fl6->saddr; - sel->dport = xfrm_flowi_dport(fl, &fl6->uli); - sel->dport_mask = htons(0xffff); - sel->sport = xfrm_flowi_sport(fl, &fl6->uli); - sel->sport_mask = htons(0xffff); - sel->family = AF_INET6; - sel->prefixlen_d = 128; - sel->prefixlen_s = 128; - sel->proto = fl6->flowi6_proto; - sel->ifindex = fl6->flowi6_oif; -} - -static void -xfrm6_init_temprop(struct xfrm_state *x, const struct xfrm_tmpl *tmpl, - const xfrm_address_t *daddr, const xfrm_address_t *saddr) -{ - x->id = tmpl->id; - if (ipv6_addr_any((struct in6_addr *)&x->id.daddr)) - memcpy(&x->id.daddr, daddr, sizeof(x->sel.daddr)); - memcpy(&x->props.saddr, &tmpl->saddr, sizeof(x->props.saddr)); - if (ipv6_addr_any((struct in6_addr *)&x->props.saddr)) - memcpy(&x->props.saddr, saddr, sizeof(x->props.saddr)); - x->props.mode = tmpl->mode; - x->props.reqid = tmpl->reqid; - x->props.family = AF_INET6; -} - -/* distribution counting sort function for xfrm_state and xfrm_tmpl */ -static int -__xfrm6_sort(void **dst, void **src, int n, int (*cmp)(void *p), int maxclass) -{ - int i; - int class[XFRM_MAX_DEPTH]; - int count[maxclass]; - - memset(count, 0, sizeof(count)); - - for (i = 0; i < n; i++) { - int c; - class[i] = c = cmp(src[i]); - count[c]++; - } - - for (i = 2; i < maxclass; i++) - count[i] += count[i - 1]; - - for (i = 0; i < n; i++) { - dst[count[class[i] - 1]++] = src[i]; - src[i] = NULL; - } - - return 0; -} - -/* - * Rule for xfrm_state: - * - * rule 1: select IPsec transport except AH - * rule 2: select MIPv6 RO or inbound trigger - * rule 3: select IPsec transport AH - * rule 4: select IPsec tunnel - * rule 5: others - */ -static int __xfrm6_state_sort_cmp(void *p) -{ - struct xfrm_state *v = p; - - switch (v->props.mode) { - case XFRM_MODE_TRANSPORT: - if (v->id.proto != IPPROTO_AH) - return 1; - else - return 3; -#if IS_ENABLED(CONFIG_IPV6_MIP6) - case XFRM_MODE_ROUTEOPTIMIZATION: - case XFRM_MODE_IN_TRIGGER: - return 2; -#endif - case XFRM_MODE_TUNNEL: - case XFRM_MODE_BEET: - return 4; - } - return 5; -} - -static int -__xfrm6_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n) -{ - return __xfrm6_sort((void **)dst, (void **)src, n, - __xfrm6_state_sort_cmp, 6); -} - -/* - * Rule for xfrm_tmpl: - * - * rule 1: select IPsec transport - * rule 2: select MIPv6 RO or inbound trigger - * rule 3: select IPsec tunnel - * rule 4: others - */ -static int __xfrm6_tmpl_sort_cmp(void *p) -{ - struct xfrm_tmpl *v = p; - switch (v->mode) { - case XFRM_MODE_TRANSPORT: - return 1; -#if IS_ENABLED(CONFIG_IPV6_MIP6) - case XFRM_MODE_ROUTEOPTIMIZATION: - case XFRM_MODE_IN_TRIGGER: - return 2; -#endif - case XFRM_MODE_TUNNEL: - case XFRM_MODE_BEET: - return 3; - } - return 4; -} - -static int -__xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n) -{ - return __xfrm6_sort((void **)dst, (void **)src, n, - __xfrm6_tmpl_sort_cmp, 5); -} - -int xfrm6_extract_header(struct sk_buff *skb) -{ - struct ipv6hdr *iph = ipv6_hdr(skb); - - XFRM_MODE_SKB_CB(skb)->ihl = sizeof(*iph); - XFRM_MODE_SKB_CB(skb)->id = 0; - XFRM_MODE_SKB_CB(skb)->frag_off = htons(IP_DF); - XFRM_MODE_SKB_CB(skb)->tos = ipv6_get_dsfield(iph); - XFRM_MODE_SKB_CB(skb)->ttl = iph->hop_limit; - XFRM_MODE_SKB_CB(skb)->optlen = 0; - memcpy(XFRM_MODE_SKB_CB(skb)->flow_lbl, iph->flow_lbl, - sizeof(XFRM_MODE_SKB_CB(skb)->flow_lbl)); - - return 0; -} - -static struct xfrm_state_afinfo xfrm6_state_afinfo = { - .family = AF_INET6, - .proto = IPPROTO_IPV6, - .eth_proto = htons(ETH_P_IPV6), - .owner = THIS_MODULE, - .init_tempsel = __xfrm6_init_tempsel, - .init_temprop = xfrm6_init_temprop, - .tmpl_sort = __xfrm6_tmpl_sort, - .state_sort = __xfrm6_state_sort, - .output = xfrm6_output, - .output_finish = xfrm6_output_finish, - .extract_input = xfrm6_extract_input, - .extract_output = xfrm6_extract_output, - .transport_finish = xfrm6_transport_finish, - .local_error = xfrm6_local_error, -}; - -int __init xfrm6_state_init(void) -{ - return xfrm_state_register_afinfo(&xfrm6_state_afinfo); -} - -void xfrm6_state_fini(void) -{ - xfrm_state_unregister_afinfo(&xfrm6_state_afinfo); -} - diff --git a/src/linux/net/ipx/Kconfig b/src/linux/net/ipx/Kconfig deleted file mode 100644 index e9ad006..0000000 --- a/src/linux/net/ipx/Kconfig +++ /dev/null @@ -1,60 +0,0 @@ -# -# IPX configuration -# -config IPX - tristate "The IPX protocol" - select LLC - ---help--- - This is support for the Novell networking protocol, IPX, commonly - used for local networks of Windows machines. You need it if you - want to access Novell NetWare file or print servers using the Linux - Novell client ncpfs (available from - ) or from - within the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, - available from ). In order - to do the former, you'll also have to say Y to "NCP file system - support", below. - - IPX is similar in scope to IP, while SPX, which runs on top of IPX, - is similar to TCP. - - To turn your Linux box into a fully featured NetWare file server and - IPX router, say Y here and fetch either lwared from - or - mars_nwe from . For more - information, read the IPX-HOWTO available from - . - - The IPX driver would enlarge your kernel by about 16 KB. To compile - this driver as a module, choose M here: the module will be called ipx. - Unless you want to integrate your Linux box with a local Novell - network, say N. - -config IPX_INTERN - bool "IPX: Full internal IPX network" - depends on IPX - ---help--- - Every IPX network has an address that identifies it. Sometimes it is - useful to give an IPX "network" address to your Linux box as well - (for example if your box is acting as a file server for different - IPX networks: it will then be accessible from everywhere using the - same address). The way this is done is to create a virtual internal - "network" inside your box and to assign an IPX address to this - network. Say Y here if you want to do this; read the IPX-HOWTO at - for details. - - The full internal IPX network enables you to allocate sockets on - different virtual nodes of the internal network. This is done by - evaluating the field sipx_node of the socket address given to the - bind call. So applications should always initialize the node field - to 0 when binding a socket on the primary network. In this case the - socket is assigned the default node that has been given to the - kernel when the internal network was created. By enabling the full - internal IPX network the cross-forwarding of packets targeted at - 'special' sockets to sockets listening on the primary network is - disabled. This might break existing applications, especially RIP/SAP - daemons. A RIP/SAP daemon that works well with the full internal net - can be found on . - - If you don't know what you are doing, say N. - diff --git a/src/linux/net/irda/Kconfig b/src/linux/net/irda/Kconfig deleted file mode 100644 index c8671a7..0000000 --- a/src/linux/net/irda/Kconfig +++ /dev/null @@ -1,96 +0,0 @@ -# -# IrDA protocol configuration -# - -menuconfig IRDA - depends on NET && !S390 - tristate "IrDA (infrared) subsystem support" - select CRC_CCITT - ---help--- - Say Y here if you want to build support for the IrDA (TM) protocols. - The Infrared Data Associations (tm) specifies standards for wireless - infrared communication and is supported by most laptops and PDA's. - - To use Linux support for the IrDA (tm) protocols, you will also need - some user-space utilities like irattach. For more information, see - the file . You also want to - read the IR-HOWTO, available at - . - - If you want to exchange bits of data (vCal, vCard) with a PDA, you - will need to install some OBEX application, such as OpenObex : - - - To compile this support as a module, choose M here: the module will - be called irda. - -comment "IrDA protocols" - depends on IRDA - -source "net/irda/irlan/Kconfig" - -source "net/irda/irnet/Kconfig" - -source "net/irda/ircomm/Kconfig" - -config IRDA_ULTRA - bool "Ultra (connectionless) protocol" - depends on IRDA - help - Say Y here to support the connectionless Ultra IRDA protocol. - Ultra allows to exchange data over IrDA with really simple devices - (watch, beacon) without the overhead of the IrDA protocol (no handshaking, - no management frames, simple fixed header). - Ultra is available as a special socket : socket(AF_IRDA, SOCK_DGRAM, 1); - -comment "IrDA options" - depends on IRDA - -config IRDA_CACHE_LAST_LSAP - bool "Cache last LSAP" - depends on IRDA - help - Say Y here if you want IrLMP to cache the last LSAP used. This - makes sense since most frames will be sent/received on the same - connection. Enabling this option will save a hash-lookup per frame. - - If unsure, say Y. - -config IRDA_FAST_RR - bool "Fast RRs (low latency)" - depends on IRDA - ---help--- - Say Y here is you want IrLAP to send fast RR (Receive Ready) frames - when acting as a primary station. - Disabling this option will make latency over IrDA very bad. Enabling - this option will make the IrDA stack send more packet than strictly - necessary, thus reduce your battery life (but not that much). - - Fast RR will make IrLAP send out a RR frame immediately when - receiving a frame if its own transmit queue is currently empty. This - will give a lot of speed improvement when receiving much data since - the secondary station will not have to wait the max. turn around - time (usually 500ms) before it is allowed to transmit the next time. - If the transmit queue of the secondary is also empty, the primary will - start backing-off before sending another RR frame, waiting longer - each time until the back-off reaches the max. turn around time. - This back-off increase in controlled via - /proc/sys/net/irda/fast_poll_increase - - If unsure, say Y. - -config IRDA_DEBUG - bool "Debug information" - depends on IRDA - help - Say Y here if you want the IrDA subsystem to write debug information - to your syslog. You can change the debug level in - /proc/sys/net/irda/debug . - When this option is enabled, the IrDA also perform many extra internal - verifications which will usually prevent the kernel to crash in case of - bugs. - - If unsure, say Y (since it makes it easier to find the bugs). - -source "drivers/net/irda/Kconfig" - diff --git a/src/linux/net/irda/ircomm/Kconfig b/src/linux/net/irda/ircomm/Kconfig deleted file mode 100644 index 19492c1..0000000 --- a/src/linux/net/irda/ircomm/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config IRCOMM - tristate "IrCOMM protocol" - depends on IRDA && TTY - help - Say Y here if you want to build support for the IrCOMM protocol. - To compile it as modules, choose M here: the modules will be - called ircomm and ircomm_tty. - IrCOMM implements serial port emulation, and makes it possible to - use all existing applications that understands TTY's with an - infrared link. Thus you should be able to use application like PPP, - minicom and others. - diff --git a/src/linux/net/irda/irlan/Kconfig b/src/linux/net/irda/irlan/Kconfig deleted file mode 100644 index 951abc2..0000000 --- a/src/linux/net/irda/irlan/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config IRLAN - tristate "IrLAN protocol" - depends on IRDA - help - Say Y here if you want to build support for the IrLAN protocol. - To compile it as a module, choose M here: the module will be called - irlan. IrLAN emulates an Ethernet and makes it possible to put up - a wireless LAN using infrared beams. - - The IrLAN protocol can be used to talk with infrared access points - like the HP NetbeamIR, or the ESI JetEye NET. You can also connect - to another Linux machine running the IrLAN protocol for ad-hoc - networking! - diff --git a/src/linux/net/irda/irnet/Kconfig b/src/linux/net/irda/irnet/Kconfig deleted file mode 100644 index 28c557f..0000000 --- a/src/linux/net/irda/irnet/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -config IRNET - tristate "IrNET protocol" - depends on IRDA && PPP - help - Say Y here if you want to build support for the IrNET protocol. - To compile it as a module, choose M here: the module will be - called irnet. IrNET is a PPP driver, so you will also need a - working PPP subsystem (driver, daemon and config)... - - IrNET is an alternate way to transfer TCP/IP traffic over IrDA. It - uses synchronous PPP over a set of point to point IrDA sockets. You - can use it between Linux machine or with W2k. - diff --git a/src/linux/net/iucv/Kconfig b/src/linux/net/iucv/Kconfig deleted file mode 100644 index 497fbe7..0000000 --- a/src/linux/net/iucv/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -config IUCV - depends on S390 - def_tristate y if S390 - prompt "IUCV support (S390 - z/VM only)" - help - Select this option if you want to use inter-user communication - under VM or VIF. If you run on z/VM, say "Y" to enable a fast - communication link between VM guests. - -config AFIUCV - depends on S390 - def_tristate m if QETH_L3 || IUCV - prompt "AF_IUCV Socket support (S390 - z/VM and HiperSockets transport)" - help - Select this option if you want to use AF_IUCV socket applications - based on z/VM inter-user communication vehicle or based on - HiperSockets. diff --git a/src/linux/net/kcm/Kconfig b/src/linux/net/kcm/Kconfig deleted file mode 100644 index 87fca36..0000000 --- a/src/linux/net/kcm/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ - -config AF_KCM - tristate "KCM sockets" - depends on INET - select BPF_SYSCALL - select STREAM_PARSER - ---help--- - KCM (Kernel Connection Multiplexor) sockets provide a method - for multiplexing messages of a message based application - protocol over kernel connectons (e.g. TCP connections). - diff --git a/src/linux/net/l2tp/Kconfig b/src/linux/net/l2tp/Kconfig deleted file mode 100644 index 378c73b..0000000 --- a/src/linux/net/l2tp/Kconfig +++ /dev/null @@ -1,109 +0,0 @@ -# -# Layer Two Tunneling Protocol (L2TP) -# - -menuconfig L2TP - tristate "Layer Two Tunneling Protocol (L2TP)" - depends on (IPV6 || IPV6=n) - depends on INET - select NET_UDP_TUNNEL - ---help--- - Layer Two Tunneling Protocol - - From RFC 2661 . - - L2TP facilitates the tunneling of packets across an - intervening network in a way that is as transparent as - possible to both end-users and applications. - - L2TP is often used to tunnel PPP traffic over IP - tunnels. One IP tunnel may carry thousands of individual PPP - connections. L2TP is also used as a VPN protocol, popular - with home workers to connect to their offices. - - L2TPv3 allows other protocols as well as PPP to be carried - over L2TP tunnels. L2TPv3 is defined in RFC 3931 - . - - The kernel component handles only L2TP data packets: a - userland daemon handles L2TP the control protocol (tunnel - and session setup). One such daemon is OpenL2TP - (http://openl2tp.org/). - - If you don't need L2TP, say N. To compile all L2TP code as - modules, choose M here. - -config L2TP_DEBUGFS - tristate "L2TP debugfs support" - depends on L2TP && DEBUG_FS - help - Support for l2tp directory in debugfs filesystem. This may be - used to dump internal state of the l2tp drivers for problem - analysis. - - If unsure, say 'Y'. - - To compile this driver as a module, choose M here. The module - will be called l2tp_debugfs. - -config L2TP_V3 - bool "L2TPv3 support" - depends on L2TP - help - Layer Two Tunneling Protocol Version 3 - - From RFC 3931 . - - The Layer Two Tunneling Protocol (L2TP) provides a dynamic - mechanism for tunneling Layer 2 (L2) "circuits" across a - packet-oriented data network (e.g., over IP). L2TP, as - originally defined in RFC 2661, is a standard method for - tunneling Point-to-Point Protocol (PPP) [RFC1661] sessions. - L2TP has since been adopted for tunneling a number of other - L2 protocols, including ATM, Frame Relay, HDLC and even raw - ethernet frames. - - If you are connecting to L2TPv3 equipment, or you want to - tunnel raw ethernet frames using L2TP, say Y here. If - unsure, say N. - -config L2TP_IP - tristate "L2TP IP encapsulation for L2TPv3" - depends on L2TP_V3 - help - Support for L2TP-over-IP socket family. - - The L2TPv3 protocol defines two possible encapsulations for - L2TP frames, namely UDP and plain IP (without UDP). This - driver provides a new L2TPIP socket family with which - userspace L2TPv3 daemons may create L2TP/IP tunnel sockets - when UDP encapsulation is not required. When L2TP is carried - in IP packets, it used IP protocol number 115, so this port - must be enabled in firewalls. - - To compile this driver as a module, choose M here. The module - will be called l2tp_ip. - -config L2TP_ETH - tristate "L2TP ethernet pseudowire support for L2TPv3" - depends on L2TP_V3 - help - Support for carrying raw ethernet frames over L2TPv3. - - From RFC 4719 . - - The Layer 2 Tunneling Protocol, Version 3 (L2TPv3) can be - used as a control protocol and for data encapsulation to set - up Pseudowires for transporting layer 2 Packet Data Units - across an IP network [RFC3931]. - - This driver provides an ethernet virtual interface for each - L2TP ethernet pseudowire instance. Standard Linux tools may - be used to assign an IP address to the local virtual - interface, or add the interface to a bridge. - - If you are using L2TPv3, you will almost certainly want to - enable this option. - - To compile this driver as a module, choose M here. The module - will be called l2tp_eth. diff --git a/src/linux/net/l3mdev/Kconfig b/src/linux/net/l3mdev/Kconfig deleted file mode 100644 index 5d47325..0000000 --- a/src/linux/net/l3mdev/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -# -# Configuration for L3 master device support -# - -config NET_L3_MASTER_DEV - bool "L3 Master device support" - depends on INET || IPV6 - ---help--- - This module provides glue between core networking code and device - drivers to support L3 master devices like VRF. diff --git a/src/linux/net/lapb/Kconfig b/src/linux/net/lapb/Kconfig deleted file mode 100644 index 6481839..0000000 --- a/src/linux/net/lapb/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -# -# LAPB Data Link Drive -# - -config LAPB - tristate "LAPB Data Link Driver" - ---help--- - Link Access Procedure, Balanced (LAPB) is the data link layer (i.e. - the lower) part of the X.25 protocol. It offers a reliable - connection service to exchange data frames with one other host, and - it is used to transport higher level protocols (mostly X.25 Packet - Layer, the higher part of X.25, but others are possible as well). - Usually, LAPB is used with specialized X.21 network cards, but Linux - currently supports LAPB only over Ethernet connections. If you want - to use LAPB connections over Ethernet, say Y here and to "LAPB over - Ethernet driver" below. Read - for technical - details. - - To compile this driver as a module, choose M here: the - module will be called lapb. If unsure, say N. diff --git a/src/linux/net/llc/Kconfig b/src/linux/net/llc/Kconfig deleted file mode 100644 index b91c651..0000000 --- a/src/linux/net/llc/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -config LLC - tristate - depends on NET - -config LLC2 - tristate "ANSI/IEEE 802.2 LLC type 2 Support" - select LLC - help - This is a Logical Link Layer type 2, connection oriented support. - Select this if you want to have support for PF_LLC sockets. diff --git a/src/linux/net/mac80211/Kconfig b/src/linux/net/mac80211/Kconfig deleted file mode 100644 index 3891cbd..0000000 --- a/src/linux/net/mac80211/Kconfig +++ /dev/null @@ -1,320 +0,0 @@ -config MAC80211 - tristate "Generic IEEE 802.11 Networking Stack (mac80211)" - depends on CFG80211 - select CRYPTO - select CRYPTO_ARC4 - select CRYPTO_AES - select CRYPTO_CCM - select CRYPTO_GCM - select CRC32 - ---help--- - This option enables the hardware independent IEEE 802.11 - networking stack. - -comment "CFG80211 needs to be enabled for MAC80211" - depends on CFG80211=n - -if MAC80211 != n - -config MAC80211_HAS_RC - bool - -config MAC80211_RC_MINSTREL - bool "Minstrel" if EXPERT - select MAC80211_HAS_RC - default y - ---help--- - This option enables the 'minstrel' TX rate control algorithm - -config MAC80211_RC_MINSTREL_HT - bool "Minstrel 802.11n support" if EXPERT - depends on MAC80211_RC_MINSTREL - default y - ---help--- - This option enables the 'minstrel_ht' TX rate control algorithm - -config MAC80211_RC_MINSTREL_VHT - bool "Minstrel 802.11ac support" if EXPERT - depends on MAC80211_RC_MINSTREL_HT - default n - ---help--- - This option enables VHT in the 'minstrel_ht' TX rate control algorithm - -choice - prompt "Default rate control algorithm" - depends on MAC80211_HAS_RC - default MAC80211_RC_DEFAULT_MINSTREL - ---help--- - This option selects the default rate control algorithm - mac80211 will use. Note that this default can still be - overridden through the ieee80211_default_rc_algo module - parameter if different algorithms are available. - -config MAC80211_RC_DEFAULT_MINSTREL - bool "Minstrel" - depends on MAC80211_RC_MINSTREL - ---help--- - Select Minstrel as the default rate control algorithm. - - -endchoice - -config MAC80211_RC_DEFAULT - string - default "minstrel_ht" if MAC80211_RC_DEFAULT_MINSTREL && MAC80211_RC_MINSTREL_HT - default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL - default "" - -endif - -comment "Some wireless drivers require a rate control algorithm" - depends on MAC80211 && MAC80211_HAS_RC=n - -config MAC80211_MESH - bool "Enable mac80211 mesh networking (pre-802.11s) support" - depends on MAC80211 - ---help--- - This options enables support of Draft 802.11s mesh networking. - The implementation is based on Draft 2.08 of the Mesh Networking - amendment. However, no compliance with that draft is claimed or even - possible, as drafts leave a number of identifiers to be defined after - ratification. For more information visit http://o11s.org/. - -config MAC80211_LEDS - bool "Enable LED triggers" - depends on MAC80211 - depends on LEDS_CLASS - select LEDS_TRIGGERS - ---help--- - This option enables a few LED triggers for different - packet receive/transmit events. - -config MAC80211_DEBUGFS - bool "Export mac80211 internals in DebugFS" - depends on MAC80211 && DEBUG_FS - ---help--- - Select this to see extensive information about - the internal state of mac80211 in debugfs. - - Say N unless you know you need this. - -config MAC80211_MESSAGE_TRACING - bool "Trace all mac80211 debug messages" - depends on MAC80211 - ---help--- - Select this option to have mac80211 register the - mac80211_msg trace subsystem with tracepoints to - collect all debugging messages, independent of - printing them into the kernel log. - - The overhead in this option is that all the messages - need to be present in the binary and formatted at - runtime for tracing. - -menuconfig MAC80211_DEBUG_MENU - bool "Select mac80211 debugging features" - depends on MAC80211 - ---help--- - This option collects various mac80211 debug settings. - -config MAC80211_NOINLINE - bool "Do not inline TX/RX handlers" - depends on MAC80211_DEBUG_MENU - ---help--- - This option affects code generation in mac80211, when - selected some functions are marked "noinline" to allow - easier debugging of problems in the transmit and receive - paths. - - This option increases code size a bit and inserts a lot - of function calls in the code, but is otherwise safe to - enable. - - If unsure, say N unless you expect to be finding problems - in mac80211. - -config MAC80211_VERBOSE_DEBUG - bool "Verbose debugging output" - depends on MAC80211_DEBUG_MENU - ---help--- - Selecting this option causes mac80211 to print out - many debugging messages. It should not be selected - on production systems as some of the messages are - remotely triggerable. - - Do not select this option. - -config MAC80211_MLME_DEBUG - bool "Verbose managed MLME output" - depends on MAC80211_DEBUG_MENU - ---help--- - Selecting this option causes mac80211 to print out - debugging messages for the managed-mode MLME. It - should not be selected on production systems as some - of the messages are remotely triggerable. - - Do not select this option. - -config MAC80211_STA_DEBUG - bool "Verbose station debugging" - depends on MAC80211_DEBUG_MENU - ---help--- - Selecting this option causes mac80211 to print out - debugging messages for station addition/removal. - - Do not select this option. - -config MAC80211_HT_DEBUG - bool "Verbose HT debugging" - depends on MAC80211_DEBUG_MENU - ---help--- - This option enables 802.11n High Throughput features - debug tracing output. - - It should not be selected on production systems as some - of the messages are remotely triggerable. - - Do not select this option. - -config MAC80211_OCB_DEBUG - bool "Verbose OCB debugging" - depends on MAC80211_DEBUG_MENU - ---help--- - Selecting this option causes mac80211 to print out - very verbose OCB debugging messages. It should not - be selected on production systems as those messages - are remotely triggerable. - - Do not select this option. - -config MAC80211_IBSS_DEBUG - bool "Verbose IBSS debugging" - depends on MAC80211_DEBUG_MENU - ---help--- - Selecting this option causes mac80211 to print out - very verbose IBSS debugging messages. It should not - be selected on production systems as those messages - are remotely triggerable. - - Do not select this option. - -config MAC80211_PS_DEBUG - bool "Verbose powersave mode debugging" - depends on MAC80211_DEBUG_MENU - ---help--- - Selecting this option causes mac80211 to print out very - verbose power save mode debugging messages (when mac80211 - is an AP and has power saving stations.) - It should not be selected on production systems as those - messages are remotely triggerable. - - Do not select this option. - -config MAC80211_MPL_DEBUG - bool "Verbose mesh peer link debugging" - depends on MAC80211_DEBUG_MENU - depends on MAC80211_MESH - ---help--- - Selecting this option causes mac80211 to print out very - verbose mesh peer link debugging messages (when mac80211 - is taking part in a mesh network). - It should not be selected on production systems as those - messages are remotely triggerable. - - Do not select this option. - -config MAC80211_MPATH_DEBUG - bool "Verbose mesh path debugging" - depends on MAC80211_DEBUG_MENU - depends on MAC80211_MESH - ---help--- - Selecting this option causes mac80211 to print out very - verbose mesh path selection debugging messages (when mac80211 - is taking part in a mesh network). - It should not be selected on production systems as those - messages are remotely triggerable. - - Do not select this option. - -config MAC80211_MHWMP_DEBUG - bool "Verbose mesh HWMP routing debugging" - depends on MAC80211_DEBUG_MENU - depends on MAC80211_MESH - ---help--- - Selecting this option causes mac80211 to print out very - verbose mesh routing (HWMP) debugging messages (when mac80211 - is taking part in a mesh network). - It should not be selected on production systems as those - messages are remotely triggerable. - - Do not select this option. - -config MAC80211_MESH_SYNC_DEBUG - bool "Verbose mesh synchronization debugging" - depends on MAC80211_DEBUG_MENU - depends on MAC80211_MESH - ---help--- - Selecting this option causes mac80211 to print out very verbose mesh - synchronization debugging messages (when mac80211 is taking part in a - mesh network). - - Do not select this option. - -config MAC80211_MESH_CSA_DEBUG - bool "Verbose mesh channel switch debugging" - depends on MAC80211_DEBUG_MENU - depends on MAC80211_MESH - ---help--- - Selecting this option causes mac80211 to print out very verbose mesh - channel switch debugging messages (when mac80211 is taking part in a - mesh network). - - Do not select this option. - -config MAC80211_MESH_PS_DEBUG - bool "Verbose mesh powersave debugging" - depends on MAC80211_DEBUG_MENU - depends on MAC80211_MESH - ---help--- - Selecting this option causes mac80211 to print out very verbose mesh - powersave debugging messages (when mac80211 is taking part in a - mesh network). - - Do not select this option. - -config MAC80211_TDLS_DEBUG - bool "Verbose TDLS debugging" - depends on MAC80211_DEBUG_MENU - ---help--- - Selecting this option causes mac80211 to print out very - verbose TDLS selection debugging messages (when mac80211 - is a TDLS STA). - It should not be selected on production systems as those - messages are remotely triggerable. - - Do not select this option. - -config MAC80211_DEBUG_COUNTERS - bool "Extra statistics for TX/RX debugging" - depends on MAC80211_DEBUG_MENU - depends on MAC80211_DEBUGFS - ---help--- - Selecting this option causes mac80211 to keep additional - and very verbose statistics about TX and RX handler use - as well as a few selected dot11 counters. These will be - exposed in debugfs. - - Note that some of the counters are not concurrency safe - and may thus not always be accurate. - - If unsure, say N. - -config MAC80211_STA_HASH_MAX_SIZE - int "Station hash table maximum size" if MAC80211_DEBUG_MENU - default 0 - ---help--- - Setting this option to a low value (e.g. 4) allows testing the - hash table with collisions relatively deterministically (just - connect more stations than the number selected here.) - - If unsure, leave the default of 0. diff --git a/src/linux/net/mac802154/Kconfig b/src/linux/net/mac802154/Kconfig deleted file mode 100644 index fb45287..0000000 --- a/src/linux/net/mac802154/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -config MAC802154 - tristate "Generic IEEE 802.15.4 Soft Networking Stack (mac802154)" - depends on IEEE802154 - select CRC_CCITT - select CRYPTO - select CRYPTO_AUTHENC - select CRYPTO_CCM - select CRYPTO_CTR - select CRYPTO_AES - ---help--- - This option enables the hardware independent IEEE 802.15.4 - networking stack for SoftMAC devices (the ones implementing - only PHY level of IEEE 802.15.4 standard). - - Note: this implementation is neither certified, nor feature - complete! Compatibility with other implementations hasn't - been tested yet! - - If you plan to use HardMAC IEEE 802.15.4 devices, you can - say N here. Alternatively you can say M to compile it as - module. diff --git a/src/linux/net/mpls/Kconfig b/src/linux/net/mpls/Kconfig deleted file mode 100644 index 5c467ef..0000000 --- a/src/linux/net/mpls/Kconfig +++ /dev/null @@ -1,36 +0,0 @@ -# -# MPLS configuration -# - -menuconfig MPLS - bool "MultiProtocol Label Switching" - default n - ---help--- - MultiProtocol Label Switching routes packets through logical - circuits. Originally conceived as a way of routing packets at - hardware speeds (before hardware was capable of routing ipv4 packets), - MPLS remains a simple way of making tunnels. - - If you have not heard of MPLS you probably want to say N here. - -if MPLS - -config NET_MPLS_GSO - tristate "MPLS: GSO support" - help - This is helper module to allow segmentation of non-MPLS GSO packets - that have had MPLS stack entries pushed onto them and thus - become MPLS GSO packets. - -config MPLS_ROUTING - tristate "MPLS: routing support" - ---help--- - Add support for forwarding of mpls packets. - -config MPLS_IPTUNNEL - tristate "MPLS: IP over MPLS tunnel support" - depends on LWTUNNEL && MPLS_ROUTING - ---help--- - mpls ip tunnel support. - -endif # MPLS diff --git a/src/linux/net/ncsi/Kconfig b/src/linux/net/ncsi/Kconfig deleted file mode 100644 index 08a8a60..0000000 --- a/src/linux/net/ncsi/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -# -# Configuration for NCSI support -# - -config NET_NCSI - bool "NCSI interface support" - depends on INET - ---help--- - This module provides NCSI (Network Controller Sideband Interface) - support. Enable this only if your system connects to a network - device via NCSI and the ethernet driver you're using supports - the protocol explicitly. diff --git a/src/linux/net/netfilter/Kconfig b/src/linux/net/netfilter/Kconfig deleted file mode 100644 index e8d56d9..0000000 --- a/src/linux/net/netfilter/Kconfig +++ /dev/null @@ -1,1501 +0,0 @@ -menu "Core Netfilter Configuration" - depends on NET && INET && NETFILTER - -config NETFILTER_INGRESS - bool "Netfilter ingress support" - default y - select NET_INGRESS - help - This allows you to classify packets from ingress using the Netfilter - infrastructure. - -config NETFILTER_NETLINK - tristate - -config NETFILTER_NETLINK_ACCT -tristate "Netfilter NFACCT over NFNETLINK interface" - depends on NETFILTER_ADVANCED - select NETFILTER_NETLINK - help - If this option is enabled, the kernel will include support - for extended accounting via NFNETLINK. - -config NETFILTER_NETLINK_QUEUE - tristate "Netfilter NFQUEUE over NFNETLINK interface" - depends on NETFILTER_ADVANCED - select NETFILTER_NETLINK - help - If this option is enabled, the kernel will include support - for queueing packets via NFNETLINK. - -config NETFILTER_NETLINK_LOG - tristate "Netfilter LOG over NFNETLINK interface" - default m if NETFILTER_ADVANCED=n - select NETFILTER_NETLINK - help - If this option is enabled, the kernel will include support - for logging packets via NFNETLINK. - - This obsoletes the existing ipt_ULOG and ebg_ulog mechanisms, - and is also scheduled to replace the old syslog-based ipt_LOG - and ip6t_LOG modules. - -config NF_CONNTRACK - tristate "Netfilter connection tracking support" - default m if NETFILTER_ADVANCED=n - help - Connection tracking keeps a record of what packets have passed - through your machine, in order to figure out how they are related - into connections. - - This is required to do Masquerading or other kinds of Network - Address Translation. It can also be used to enhance packet - filtering (see `Connection state match support' below). - - To compile it as a module, choose M here. If unsure, say N. - -config NF_LOG_COMMON - tristate - -if NF_CONNTRACK - -config NF_CONNTRACK_MARK - bool 'Connection mark tracking support' - depends on NETFILTER_ADVANCED - help - This option enables support for connection marks, used by the - `CONNMARK' target and `connmark' match. Similar to the mark value - of packets, but this mark value is kept in the conntrack session - instead of the individual packets. - -config NF_CONNTRACK_SECMARK - bool 'Connection tracking security mark support' - depends on NETWORK_SECMARK - default m if NETFILTER_ADVANCED=n - help - This option enables security markings to be applied to - connections. Typically they are copied to connections from - packets using the CONNSECMARK target and copied back from - connections to packets with the same target, with the packets - being originally labeled via SECMARK. - - If unsure, say 'N'. - -config NF_CONNTRACK_ZONES - bool 'Connection tracking zones' - depends on NETFILTER_ADVANCED - depends on NETFILTER_XT_TARGET_CT - help - This option enables support for connection tracking zones. - Normally, each connection needs to have a unique system wide - identity. Connection tracking zones allow to have multiple - connections using the same identity, as long as they are - contained in different zones. - - If unsure, say `N'. - -config NF_CONNTRACK_PROCFS - bool "Supply CT list in procfs (OBSOLETE)" - default y - depends on PROC_FS - ---help--- - This option enables for the list of known conntrack entries - to be shown in procfs under net/netfilter/nf_conntrack. This - is considered obsolete in favor of using the conntrack(8) - tool which uses Netlink. - -config NF_CONNTRACK_EVENTS - bool "Connection tracking events" - depends on NETFILTER_ADVANCED - help - If this option is enabled, the connection tracking code will - provide a notifier chain that can be used by other kernel code - to get notified about changes in the connection tracking state. - - If unsure, say `N'. - -config NF_CONNTRACK_TIMEOUT - bool 'Connection tracking timeout' - depends on NETFILTER_ADVANCED - help - This option enables support for connection tracking timeout - extension. This allows you to attach timeout policies to flow - via the CT target. - - If unsure, say `N'. - -config NF_CONNTRACK_TIMESTAMP - bool 'Connection tracking timestamping' - depends on NETFILTER_ADVANCED - help - This option enables support for connection tracking timestamping. - This allows you to store the flow start-time and to obtain - the flow-stop time (once it has been destroyed) via Connection - tracking events. - - If unsure, say `N'. - -config NF_CONNTRACK_LABELS - bool - help - This option enables support for assigning user-defined flag bits - to connection tracking entries. It selected by the connlabel match. - -config NF_CT_PROTO_DCCP - tristate 'DCCP protocol connection tracking support' - depends on NETFILTER_ADVANCED - default IP_DCCP - help - With this option enabled, the layer 3 independent connection - tracking code will be able to do state tracking on DCCP connections. - - If unsure, say 'N'. - -config NF_CT_PROTO_GRE - tristate - -config NF_CT_PROTO_SCTP - tristate 'SCTP protocol connection tracking support' - depends on NETFILTER_ADVANCED - default IP_SCTP - help - With this option enabled, the layer 3 independent connection - tracking code will be able to do state tracking on SCTP connections. - - If you want to compile it as a module, say M here and read - . If unsure, say `N'. - -config NF_CT_PROTO_UDPLITE - tristate 'UDP-Lite protocol connection tracking support' - depends on NETFILTER_ADVANCED - help - With this option enabled, the layer 3 independent connection - tracking code will be able to do state tracking on UDP-Lite - connections. - - To compile it as a module, choose M here. If unsure, say N. - -config NF_CONNTRACK_AMANDA - tristate "Amanda backup protocol support" - depends on NETFILTER_ADVANCED - select TEXTSEARCH - select TEXTSEARCH_KMP - help - If you are running the Amanda backup package - on this machine or machines that will be MASQUERADED through this - machine, then you may want to enable this feature. This allows the - connection tracking and natting code to allow the sub-channels that - Amanda requires for communication of the backup data, messages and - index. - - To compile it as a module, choose M here. If unsure, say N. - -config NF_CONNTRACK_FTP - tristate "FTP protocol support" - default m if NETFILTER_ADVANCED=n - help - Tracking FTP connections is problematic: special helpers are - required for tracking them, and doing masquerading and other forms - of Network Address Translation on them. - - This is FTP support on Layer 3 independent connection tracking. - Layer 3 independent connection tracking is experimental scheme - which generalize ip_conntrack to support other layer 3 protocols. - - To compile it as a module, choose M here. If unsure, say N. - -config NF_CONNTRACK_H323 - tristate "H.323 protocol support" - depends on IPV6 || IPV6=n - depends on NETFILTER_ADVANCED - help - H.323 is a VoIP signalling protocol from ITU-T. As one of the most - important VoIP protocols, it is widely used by voice hardware and - software including voice gateways, IP phones, Netmeeting, OpenPhone, - Gnomemeeting, etc. - - With this module you can support H.323 on a connection tracking/NAT - firewall. - - This module supports RAS, Fast Start, H.245 Tunnelling, Call - Forwarding, RTP/RTCP and T.120 based audio, video, fax, chat, - whiteboard, file transfer, etc. For more information, please - visit http://nath323.sourceforge.net/. - - To compile it as a module, choose M here. If unsure, say N. - -config NF_CONNTRACK_IRC - tristate "IRC protocol support" - default m if NETFILTER_ADVANCED=n - help - There is a commonly-used extension to IRC called - Direct Client-to-Client Protocol (DCC). This enables users to send - files to each other, and also chat to each other without the need - of a server. DCC Sending is used anywhere you send files over IRC, - and DCC Chat is most commonly used by Eggdrop bots. If you are - using NAT, this extension will enable you to send files and initiate - chats. Note that you do NOT need this extension to get files or - have others initiate chats, or everything else in IRC. - - To compile it as a module, choose M here. If unsure, say N. - -config NF_CONNTRACK_BROADCAST - tristate - -config NF_CONNTRACK_NETBIOS_NS - tristate "NetBIOS name service protocol support" - select NF_CONNTRACK_BROADCAST - help - NetBIOS name service requests are sent as broadcast messages from an - unprivileged port and responded to with unicast messages to the - same port. This make them hard to firewall properly because connection - tracking doesn't deal with broadcasts. This helper tracks locally - originating NetBIOS name service requests and the corresponding - responses. It relies on correct IP address configuration, specifically - netmask and broadcast address. When properly configured, the output - of "ip address show" should look similar to this: - - $ ip -4 address show eth0 - 4: eth0: mtu 1500 qdisc pfifo_fast qlen 1000 - inet 172.16.2.252/24 brd 172.16.2.255 scope global eth0 - - To compile it as a module, choose M here. If unsure, say N. - -config NF_CONNTRACK_SNMP - tristate "SNMP service protocol support" - depends on NETFILTER_ADVANCED - select NF_CONNTRACK_BROADCAST - help - SNMP service requests are sent as broadcast messages from an - unprivileged port and responded to with unicast messages to the - same port. This make them hard to firewall properly because connection - tracking doesn't deal with broadcasts. This helper tracks locally - originating SNMP service requests and the corresponding - responses. It relies on correct IP address configuration, specifically - netmask and broadcast address. - - To compile it as a module, choose M here. If unsure, say N. - -config NF_CONNTRACK_PPTP - tristate "PPtP protocol support" - depends on NETFILTER_ADVANCED - select NF_CT_PROTO_GRE - help - This module adds support for PPTP (Point to Point Tunnelling - Protocol, RFC2637) connection tracking and NAT. - - If you are running PPTP sessions over a stateful firewall or NAT - box, you may want to enable this feature. - - Please note that not all PPTP modes of operation are supported yet. - Specifically these limitations exist: - - Blindly assumes that control connections are always established - in PNS->PAC direction. This is a violation of RFC2637. - - Only supports a single call within each session - - To compile it as a module, choose M here. If unsure, say N. - -config NF_CONNTRACK_SANE - tristate "SANE protocol support" - depends on NETFILTER_ADVANCED - help - SANE is a protocol for remote access to scanners as implemented - by the 'saned' daemon. Like FTP, it uses separate control and - data connections. - - With this module you can support SANE on a connection tracking - firewall. - - To compile it as a module, choose M here. If unsure, say N. - -config NF_CONNTRACK_SIP - tristate "SIP protocol support" - default m if NETFILTER_ADVANCED=n - help - SIP is an application-layer control protocol that can establish, - modify, and terminate multimedia sessions (conferences) such as - Internet telephony calls. With the ip_conntrack_sip and - the nf_nat_sip modules you can support the protocol on a connection - tracking/NATing firewall. - - To compile it as a module, choose M here. If unsure, say N. - -config NF_CONNTRACK_TFTP - tristate "TFTP protocol support" - depends on NETFILTER_ADVANCED - help - TFTP connection tracking helper, this is required depending - on how restrictive your ruleset is. - If you are using a tftp client behind -j SNAT or -j MASQUERADING - you will need this. - - To compile it as a module, choose M here. If unsure, say N. - -config NF_CT_NETLINK - tristate 'Connection tracking netlink interface' - select NETFILTER_NETLINK - default m if NETFILTER_ADVANCED=n - help - This option enables support for a netlink-based userspace interface - -config NF_CT_NETLINK_TIMEOUT - tristate 'Connection tracking timeout tuning via Netlink' - select NETFILTER_NETLINK - depends on NETFILTER_ADVANCED - help - This option enables support for connection tracking timeout - fine-grain tuning. This allows you to attach specific timeout - policies to flows, instead of using the global timeout policy. - - If unsure, say `N'. - -config NF_CT_NETLINK_HELPER - tristate 'Connection tracking helpers in user-space via Netlink' - select NETFILTER_NETLINK - depends on NF_CT_NETLINK - depends on NETFILTER_NETLINK_QUEUE - depends on NETFILTER_NETLINK_GLUE_CT - depends on NETFILTER_ADVANCED - help - This option enables the user-space connection tracking helpers - infrastructure. - - If unsure, say `N'. - -config NETFILTER_NETLINK_GLUE_CT - bool "NFQUEUE and NFLOG integration with Connection Tracking" - default n - depends on (NETFILTER_NETLINK_QUEUE || NETFILTER_NETLINK_LOG) && NF_CT_NETLINK - help - If this option is enabled, NFQUEUE and NFLOG can include - Connection Tracking information together with the packet is - the enqueued via NFNETLINK. - -config NF_NAT - tristate - -config NF_NAT_NEEDED - bool - depends on NF_NAT - default y - -config NF_NAT_PROTO_DCCP - tristate - depends on NF_NAT && NF_CT_PROTO_DCCP - default NF_NAT && NF_CT_PROTO_DCCP - -config NF_NAT_PROTO_UDPLITE - tristate - depends on NF_NAT && NF_CT_PROTO_UDPLITE - default NF_NAT && NF_CT_PROTO_UDPLITE - -config NF_NAT_PROTO_SCTP - tristate - default NF_NAT && NF_CT_PROTO_SCTP - depends on NF_NAT && NF_CT_PROTO_SCTP - select LIBCRC32C - -config NF_NAT_AMANDA - tristate - depends on NF_CONNTRACK && NF_NAT - default NF_NAT && NF_CONNTRACK_AMANDA - -config NF_NAT_FTP - tristate - depends on NF_CONNTRACK && NF_NAT - default NF_NAT && NF_CONNTRACK_FTP - -config NF_NAT_IRC - tristate - depends on NF_CONNTRACK && NF_NAT - default NF_NAT && NF_CONNTRACK_IRC - -config NF_NAT_SIP - tristate - depends on NF_CONNTRACK && NF_NAT - default NF_NAT && NF_CONNTRACK_SIP - -config NF_NAT_TFTP - tristate - depends on NF_CONNTRACK && NF_NAT - default NF_NAT && NF_CONNTRACK_TFTP - -config NF_NAT_REDIRECT - tristate "IPv4/IPv6 redirect support" - depends on NF_NAT - help - This is the kernel functionality to redirect packets to local - machine through NAT. - -config NETFILTER_SYNPROXY - tristate - -endif # NF_CONNTRACK - -config NF_TABLES - select NETFILTER_NETLINK - tristate "Netfilter nf_tables support" - help - nftables is the new packet classification framework that intends to - replace the existing {ip,ip6,arp,eb}_tables infrastructure. It - provides a pseudo-state machine with an extensible instruction-set - (also known as expressions) that the userspace 'nft' utility - (http://www.netfilter.org/projects/nftables) uses to build the - rule-set. It also comes with the generic set infrastructure that - allows you to construct mappings between matchings and actions - for performance lookups. - - To compile it as a module, choose M here. - -if NF_TABLES - -config NF_TABLES_INET - depends on IPV6 - select NF_TABLES_IPV4 - select NF_TABLES_IPV6 - tristate "Netfilter nf_tables mixed IPv4/IPv6 tables support" - help - This option enables support for a mixed IPv4/IPv6 "inet" table. - -config NF_TABLES_NETDEV - tristate "Netfilter nf_tables netdev tables support" - help - This option enables support for the "netdev" table. - -config NFT_EXTHDR - tristate "Netfilter nf_tables IPv6 exthdr module" - help - This option adds the "exthdr" expression that you can use to match - IPv6 extension headers. - -config NFT_META - tristate "Netfilter nf_tables meta module" - help - This option adds the "meta" expression that you can use to match and - to set packet metainformation such as the packet mark. - -config NFT_NUMGEN - tristate "Netfilter nf_tables number generator module" - help - This option adds the number generator expression used to perform - incremental counting and random numbers bound to a upper limit. - -config NFT_CT - depends on NF_CONNTRACK - tristate "Netfilter nf_tables conntrack module" - help - This option adds the "meta" expression that you can use to match - connection tracking information such as the flow state. - -config NFT_SET_RBTREE - tristate "Netfilter nf_tables rbtree set module" - help - This option adds the "rbtree" set type (Red Black tree) that is used - to build interval-based sets. - -config NFT_SET_HASH - tristate "Netfilter nf_tables hash set module" - help - This option adds the "hash" set type that is used to build one-way - mappings between matchings and actions. - -config NFT_COUNTER - tristate "Netfilter nf_tables counter module" - help - This option adds the "counter" expression that you can use to - include packet and byte counters in a rule. - -config NFT_LOG - tristate "Netfilter nf_tables log module" - help - This option adds the "log" expression that you can use to log - packets matching some criteria. - -config NFT_LIMIT - tristate "Netfilter nf_tables limit module" - help - This option adds the "limit" expression that you can use to - ratelimit rule matchings. - -config NFT_MASQ - depends on NF_CONNTRACK - depends on NF_NAT - tristate "Netfilter nf_tables masquerade support" - help - This option adds the "masquerade" expression that you can use - to perform NAT in the masquerade flavour. - -config NFT_REDIR - depends on NF_CONNTRACK - depends on NF_NAT - tristate "Netfilter nf_tables redirect support" - help - This options adds the "redirect" expression that you can use - to perform NAT in the redirect flavour. - -config NFT_NAT - depends on NF_CONNTRACK - select NF_NAT - tristate "Netfilter nf_tables nat module" - help - This option adds the "nat" expression that you can use to perform - typical Network Address Translation (NAT) packet transformations. - -config NFT_QUEUE - depends on NETFILTER_NETLINK_QUEUE - tristate "Netfilter nf_tables queue module" - help - This is required if you intend to use the userspace queueing - infrastructure (also known as NFQUEUE) from nftables. - -config NFT_QUOTA - tristate "Netfilter nf_tables quota module" - help - This option adds the "quota" expression that you can use to match - enforce bytes quotas. - -config NFT_REJECT - default m if NETFILTER_ADVANCED=n - tristate "Netfilter nf_tables reject support" - help - This option adds the "reject" expression that you can use to - explicitly deny and notify via TCP reset/ICMP informational errors - unallowed traffic. - -config NFT_REJECT_INET - depends on NF_TABLES_INET - default NFT_REJECT - tristate - -config NFT_COMPAT - depends on NETFILTER_XTABLES - tristate "Netfilter x_tables over nf_tables module" - help - This is required if you intend to use any of existing - x_tables match/target extensions over the nf_tables - framework. - -config NFT_HASH - tristate "Netfilter nf_tables hash module" - help - This option adds the "hash" expression that you can use to perform - a hash operation on registers. - -if NF_TABLES_NETDEV - -config NF_DUP_NETDEV - tristate "Netfilter packet duplication support" - help - This option enables the generic packet duplication infrastructure - for Netfilter. - -config NFT_DUP_NETDEV - tristate "Netfilter nf_tables netdev packet duplication support" - select NF_DUP_NETDEV - help - This option enables packet duplication for the "netdev" family. - -config NFT_FWD_NETDEV - tristate "Netfilter nf_tables netdev packet forwarding support" - select NF_DUP_NETDEV - help - This option enables packet forwarding for the "netdev" family. - -endif # NF_TABLES_NETDEV - -endif # NF_TABLES - -config NETFILTER_XTABLES - tristate "Netfilter Xtables support (required for ip_tables)" - default m if NETFILTER_ADVANCED=n - help - This is required if you intend to use any of ip_tables, - ip6_tables or arp_tables. - -if NETFILTER_XTABLES - -comment "Xtables combined modules" - -config NETFILTER_XT_MARK - tristate 'nfmark target and match support' - default m if NETFILTER_ADVANCED=n - ---help--- - This option adds the "MARK" target and "mark" match. - - Netfilter mark matching allows you to match packets based on the - "nfmark" value in the packet. - The target allows you to create rules in the "mangle" table which alter - the netfilter mark (nfmark) field associated with the packet. - - Prior to routing, the nfmark can influence the routing method and can - also be used by other subsystems to change their behavior. - -config NETFILTER_XT_CONNMARK - tristate 'ctmark target and match support' - depends on NF_CONNTRACK - depends on NETFILTER_ADVANCED - select NF_CONNTRACK_MARK - ---help--- - This option adds the "CONNMARK" target and "connmark" match. - - Netfilter allows you to store a mark value per connection (a.k.a. - ctmark), similarly to the packet mark (nfmark). Using this - target and match, you can set and match on this mark. - -config NETFILTER_XT_SET - tristate 'set target and match support' - depends on IP_SET - depends on NETFILTER_ADVANCED - help - This option adds the "SET" target and "set" match. - - Using this target and match, you can add/delete and match - elements in the sets created by ipset(8). - - To compile it as a module, choose M here. If unsure, say N. - -# alphabetically ordered list of targets - -comment "Xtables targets" - -config NETFILTER_XT_TARGET_AUDIT - tristate "AUDIT target support" - depends on AUDIT - depends on NETFILTER_ADVANCED - ---help--- - This option adds a 'AUDIT' target, which can be used to create - audit records for packets dropped/accepted. - - To compileit as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_TARGET_CHECKSUM - tristate "CHECKSUM target support" - depends on IP_NF_MANGLE || IP6_NF_MANGLE - depends on NETFILTER_ADVANCED - ---help--- - This option adds a `CHECKSUM' target, which can be used in the iptables mangle - table. - - You can use this target to compute and fill in the checksum in - a packet that lacks a checksum. This is particularly useful, - if you need to work around old applications such as dhcp clients, - that do not work well with checksum offloads, but don't want to disable - checksum offload in your device. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_TARGET_CLASSIFY - tristate '"CLASSIFY" target support' - depends on NETFILTER_ADVANCED - help - This option adds a `CLASSIFY' target, which enables the user to set - the priority of a packet. Some qdiscs can use this value for - classification, among these are: - - atm, cbq, dsmark, pfifo_fast, htb, prio - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_TARGET_CONNMARK - tristate '"CONNMARK" target support' - depends on NF_CONNTRACK - depends on NETFILTER_ADVANCED - select NETFILTER_XT_CONNMARK - ---help--- - This is a backwards-compat option for the user's convenience - (e.g. when running oldconfig). It selects - CONFIG_NETFILTER_XT_CONNMARK (combined connmark/CONNMARK module). - -config NETFILTER_XT_TARGET_CONNSECMARK - tristate '"CONNSECMARK" target support' - depends on NF_CONNTRACK && NF_CONNTRACK_SECMARK - default m if NETFILTER_ADVANCED=n - help - The CONNSECMARK target copies security markings from packets - to connections, and restores security markings from connections - to packets (if the packets are not already marked). This would - normally be used in conjunction with the SECMARK target. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_TARGET_CT - tristate '"CT" target support' - depends on NF_CONNTRACK - depends on IP_NF_RAW || IP6_NF_RAW - depends on NETFILTER_ADVANCED - help - This options adds a `CT' target, which allows to specify initial - connection tracking parameters like events to be delivered and - the helper to be used. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_TARGET_DSCP - tristate '"DSCP" and "TOS" target support' - depends on IP_NF_MANGLE || IP6_NF_MANGLE - depends on NETFILTER_ADVANCED - help - This option adds a `DSCP' target, which allows you to manipulate - the IPv4/IPv6 header DSCP field (differentiated services codepoint). - - The DSCP field can have any value between 0x0 and 0x3f inclusive. - - It also adds the "TOS" target, which allows you to create rules in - the "mangle" table which alter the Type Of Service field of an IPv4 - or the Priority field of an IPv6 packet, prior to routing. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_TARGET_HL - tristate '"HL" hoplimit target support' - depends on IP_NF_MANGLE || IP6_NF_MANGLE - depends on NETFILTER_ADVANCED - ---help--- - This option adds the "HL" (for IPv6) and "TTL" (for IPv4) - targets, which enable the user to change the - hoplimit/time-to-live value of the IP header. - - While it is safe to decrement the hoplimit/TTL value, the - modules also allow to increment and set the hoplimit value of - the header to arbitrary values. This is EXTREMELY DANGEROUS - since you can easily create immortal packets that loop - forever on the network. - -config NETFILTER_XT_TARGET_HMARK - tristate '"HMARK" target support' - depends on IP6_NF_IPTABLES || IP6_NF_IPTABLES=n - depends on NETFILTER_ADVANCED - ---help--- - This option adds the "HMARK" target. - - The target allows you to create rules in the "raw" and "mangle" tables - which set the skbuff mark by means of hash calculation within a given - range. The nfmark can influence the routing method and can also be used - by other subsystems to change their behaviour. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_TARGET_IDLETIMER - tristate "IDLETIMER target support" - depends on NETFILTER_ADVANCED - help - - This option adds the `IDLETIMER' target. Each matching packet - resets the timer associated with label specified when the rule is - added. When the timer expires, it triggers a sysfs notification. - The remaining time for expiration can be read via sysfs. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_TARGET_LED - tristate '"LED" target support' - depends on LEDS_CLASS && LEDS_TRIGGERS - depends on NETFILTER_ADVANCED - help - This option adds a `LED' target, which allows you to blink LEDs in - response to particular packets passing through your machine. - - This can be used to turn a spare LED into a network activity LED, - which only flashes in response to FTP transfers, for example. Or - you could have an LED which lights up for a minute or two every time - somebody connects to your machine via SSH. - - You will need support for the "led" class to make this work. - - To create an LED trigger for incoming SSH traffic: - iptables -A INPUT -p tcp --dport 22 -j LED --led-trigger-id ssh --led-delay 1000 - - Then attach the new trigger to an LED on your system: - echo netfilter-ssh > /sys/class/leds//trigger - - For more information on the LEDs available on your system, see - Documentation/leds/leds-class.txt - -config NETFILTER_XT_TARGET_LOG - tristate "LOG target support" - select NF_LOG_COMMON - select NF_LOG_IPV4 - select NF_LOG_IPV6 if IPV6 - default m if NETFILTER_ADVANCED=n - help - This option adds a `LOG' target, which allows you to create rules in - any iptables table which records the packet header to the syslog. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_TARGET_MARK - tristate '"MARK" target support' - depends on NETFILTER_ADVANCED - select NETFILTER_XT_MARK - ---help--- - This is a backwards-compat option for the user's convenience - (e.g. when running oldconfig). It selects - CONFIG_NETFILTER_XT_MARK (combined mark/MARK module). - -config NETFILTER_XT_NAT - tristate '"SNAT and DNAT" targets support' - depends on NF_NAT - ---help--- - This option enables the SNAT and DNAT targets. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_TARGET_NETMAP - tristate '"NETMAP" target support' - depends on NF_NAT - ---help--- - NETMAP is an implementation of static 1:1 NAT mapping of network - addresses. It maps the network address part, while keeping the host - address part intact. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_TARGET_NFLOG - tristate '"NFLOG" target support' - default m if NETFILTER_ADVANCED=n - select NETFILTER_NETLINK_LOG - help - This option enables the NFLOG target, which allows to LOG - messages through nfnetlink_log. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_TARGET_NFQUEUE - tristate '"NFQUEUE" target Support' - depends on NETFILTER_ADVANCED - select NETFILTER_NETLINK_QUEUE - help - This target replaced the old obsolete QUEUE target. - - As opposed to QUEUE, it supports 65535 different queues, - not just one. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_TARGET_NOTRACK - tristate '"NOTRACK" target support (DEPRECATED)' - depends on NF_CONNTRACK - depends on IP_NF_RAW || IP6_NF_RAW - depends on NETFILTER_ADVANCED - select NETFILTER_XT_TARGET_CT - -config NETFILTER_XT_TARGET_RATEEST - tristate '"RATEEST" target support' - depends on NETFILTER_ADVANCED - help - This option adds a `RATEEST' target, which allows to measure - rates similar to TC estimators. The `rateest' match can be - used to match on the measured rates. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_TARGET_REDIRECT - tristate "REDIRECT target support" - depends on NF_NAT - select NF_NAT_REDIRECT - ---help--- - REDIRECT is a special case of NAT: all incoming connections are - mapped onto the incoming interface's address, causing the packets to - come to the local machine instead of passing through. This is - useful for transparent proxies. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_TARGET_TEE - tristate '"TEE" - packet cloning to alternate destination' - depends on NETFILTER_ADVANCED - depends on IPV6 || IPV6=n - depends on !NF_CONNTRACK || NF_CONNTRACK - select NF_DUP_IPV4 - select NF_DUP_IPV6 if IPV6 - ---help--- - This option adds a "TEE" target with which a packet can be cloned and - this clone be rerouted to another nexthop. - -config NETFILTER_XT_TARGET_TPROXY - tristate '"TPROXY" target transparent proxying support' - depends on NETFILTER_XTABLES - depends on NETFILTER_ADVANCED - depends on IPV6 || IPV6=n - depends on IP6_NF_IPTABLES || IP6_NF_IPTABLES=n - depends on IP_NF_MANGLE - select NF_DEFRAG_IPV4 - select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES != n - help - This option adds a `TPROXY' target, which is somewhat similar to - REDIRECT. It can only be used in the mangle table and is useful - to redirect traffic to a transparent proxy. It does _not_ depend - on Netfilter connection tracking and NAT, unlike REDIRECT. - For it to work you will have to configure certain iptables rules - and use policy routing. For more information on how to set it up - see Documentation/networking/tproxy.txt. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_TARGET_TRACE - tristate '"TRACE" target support' - depends on IP_NF_RAW || IP6_NF_RAW - depends on NETFILTER_ADVANCED - help - The TRACE target allows you to mark packets so that the kernel - will log every rule which match the packets as those traverse - the tables, chains, rules. - - If you want to compile it as a module, say M here and read - . If unsure, say `N'. - -config NETFILTER_XT_TARGET_SECMARK - tristate '"SECMARK" target support' - depends on NETWORK_SECMARK - default m if NETFILTER_ADVANCED=n - help - The SECMARK target allows security marking of network - packets, for use with security subsystems. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_TARGET_TCPMSS - tristate '"TCPMSS" target support' - depends on IPV6 || IPV6=n - default m if NETFILTER_ADVANCED=n - ---help--- - This option adds a `TCPMSS' target, which allows you to alter the - MSS value of TCP SYN packets, to control the maximum size for that - connection (usually limiting it to your outgoing interface's MTU - minus 40). - - This is used to overcome criminally braindead ISPs or servers which - block ICMP Fragmentation Needed packets. The symptoms of this - problem are that everything works fine from your Linux - firewall/router, but machines behind it can never exchange large - packets: - 1) Web browsers connect, then hang with no data received. - 2) Small mail works fine, but large emails hang. - 3) ssh works fine, but scp hangs after initial handshaking. - - Workaround: activate this option and add a rule to your firewall - configuration like: - - iptables -A FORWARD -p tcp --tcp-flags SYN,RST SYN \ - -j TCPMSS --clamp-mss-to-pmtu - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_TARGET_TCPOPTSTRIP - tristate '"TCPOPTSTRIP" target support' - depends on IP_NF_MANGLE || IP6_NF_MANGLE - depends on NETFILTER_ADVANCED - help - This option adds a "TCPOPTSTRIP" target, which allows you to strip - TCP options from TCP packets. - -# alphabetically ordered list of matches - -comment "Xtables matches" - -config NETFILTER_XT_MATCH_ADDRTYPE - tristate '"addrtype" address type match support' - default m if NETFILTER_ADVANCED=n - ---help--- - This option allows you to match what routing thinks of an address, - eg. UNICAST, LOCAL, BROADCAST, ... - - If you want to compile it as a module, say M here and read - . If unsure, say `N'. - -config NETFILTER_XT_MATCH_BPF - tristate '"bpf" match support' - depends on NETFILTER_ADVANCED - help - BPF matching applies a linux socket filter to each packet and - accepts those for which the filter returns non-zero. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_CGROUP - tristate '"control group" match support' - depends on NETFILTER_ADVANCED - depends on CGROUPS - select CGROUP_NET_CLASSID - ---help--- - Socket/process control group matching allows you to match locally - generated packets based on which net_cls control group processes - belong to. - -config NETFILTER_XT_MATCH_CLUSTER - tristate '"cluster" match support' - depends on NF_CONNTRACK - depends on NETFILTER_ADVANCED - ---help--- - This option allows you to build work-load-sharing clusters of - network servers/stateful firewalls without having a dedicated - load-balancing router/server/switch. Basically, this match returns - true when the packet must be handled by this cluster node. Thus, - all nodes see all packets and this match decides which node handles - what packets. The work-load sharing algorithm is based on source - address hashing. - - If you say Y or M here, try `iptables -m cluster --help` for - more information. - -config NETFILTER_XT_MATCH_COMMENT - tristate '"comment" match support' - depends on NETFILTER_ADVANCED - help - This option adds a `comment' dummy-match, which allows you to put - comments in your iptables ruleset. - - If you want to compile it as a module, say M here and read - . If unsure, say `N'. - -config NETFILTER_XT_MATCH_CONNBYTES - tristate '"connbytes" per-connection counter match support' - depends on NF_CONNTRACK - depends on NETFILTER_ADVANCED - help - This option adds a `connbytes' match, which allows you to match the - number of bytes and/or packets for each direction within a connection. - - If you want to compile it as a module, say M here and read - . If unsure, say `N'. - -config NETFILTER_XT_MATCH_CONNLABEL - tristate '"connlabel" match support' - select NF_CONNTRACK_LABELS - depends on NF_CONNTRACK - depends on NETFILTER_ADVANCED - ---help--- - This match allows you to test and assign userspace-defined labels names - to a connection. The kernel only stores bit values - mapping - names to bits is done by userspace. - - Unlike connmark, more than 32 flag bits may be assigned to a - connection simultaneously. - -config NETFILTER_XT_MATCH_CONNLIMIT - tristate '"connlimit" match support' - depends on NF_CONNTRACK - depends on NETFILTER_ADVANCED - ---help--- - This match allows you to match against the number of parallel - connections to a server per client IP address (or address block). - -config NETFILTER_XT_MATCH_CONNMARK - tristate '"connmark" connection mark match support' - depends on NF_CONNTRACK - depends on NETFILTER_ADVANCED - select NETFILTER_XT_CONNMARK - ---help--- - This is a backwards-compat option for the user's convenience - (e.g. when running oldconfig). It selects - CONFIG_NETFILTER_XT_CONNMARK (combined connmark/CONNMARK module). - -config NETFILTER_XT_MATCH_CONNTRACK - tristate '"conntrack" connection tracking match support' - depends on NF_CONNTRACK - default m if NETFILTER_ADVANCED=n - help - This is a general conntrack match module, a superset of the state match. - - It allows matching on additional conntrack information, which is - useful in complex configurations, such as NAT gateways with multiple - internet links or tunnels. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_CPU - tristate '"cpu" match support' - depends on NETFILTER_ADVANCED - help - CPU matching allows you to match packets based on the CPU - currently handling the packet. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_DCCP - tristate '"dccp" protocol match support' - depends on NETFILTER_ADVANCED - default IP_DCCP - help - With this option enabled, you will be able to use the iptables - `dccp' match in order to match on DCCP source/destination ports - and DCCP flags. - - If you want to compile it as a module, say M here and read - . If unsure, say `N'. - -config NETFILTER_XT_MATCH_DEVGROUP - tristate '"devgroup" match support' - depends on NETFILTER_ADVANCED - help - This options adds a `devgroup' match, which allows to match on the - device group a network device is assigned to. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_DSCP - tristate '"dscp" and "tos" match support' - depends on NETFILTER_ADVANCED - help - This option adds a `DSCP' match, which allows you to match against - the IPv4/IPv6 header DSCP field (differentiated services codepoint). - - The DSCP field can have any value between 0x0 and 0x3f inclusive. - - It will also add a "tos" match, which allows you to match packets - based on the Type Of Service fields of the IPv4 packet (which share - the same bits as DSCP). - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_ECN - tristate '"ecn" match support' - depends on NETFILTER_ADVANCED - ---help--- - This option adds an "ECN" match, which allows you to match against - the IPv4 and TCP header ECN fields. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_ESP - tristate '"esp" match support' - depends on NETFILTER_ADVANCED - help - This match extension allows you to match a range of SPIs - inside ESP header of IPSec packets. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_HASHLIMIT - tristate '"hashlimit" match support' - depends on IP6_NF_IPTABLES || IP6_NF_IPTABLES=n - depends on NETFILTER_ADVANCED - help - This option adds a `hashlimit' match. - - As opposed to `limit', this match dynamically creates a hash table - of limit buckets, based on your selection of source/destination - addresses and/or ports. - - It enables you to express policies like `10kpps for any given - destination address' or `500pps from any given source address' - with a single rule. - -config NETFILTER_XT_MATCH_HELPER - tristate '"helper" match support' - depends on NF_CONNTRACK - depends on NETFILTER_ADVANCED - help - Helper matching allows you to match packets in dynamic connections - tracked by a conntrack-helper, ie. ip_conntrack_ftp - - To compile it as a module, choose M here. If unsure, say Y. - -config NETFILTER_XT_MATCH_HL - tristate '"hl" hoplimit/TTL match support' - depends on NETFILTER_ADVANCED - ---help--- - HL matching allows you to match packets based on the hoplimit - in the IPv6 header, or the time-to-live field in the IPv4 - header of the packet. - -config NETFILTER_XT_MATCH_IPCOMP - tristate '"ipcomp" match support' - depends on NETFILTER_ADVANCED - help - This match extension allows you to match a range of CPIs(16 bits) - inside IPComp header of IPSec packets. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_IPRANGE - tristate '"iprange" address range match support' - depends on NETFILTER_ADVANCED - ---help--- - This option adds a "iprange" match, which allows you to match based on - an IP address range. (Normal iptables only matches on single addresses - with an optional mask.) - - If unsure, say M. - -config NETFILTER_XT_MATCH_IPVS - tristate '"ipvs" match support' - depends on IP_VS - depends on NETFILTER_ADVANCED - depends on NF_CONNTRACK - help - This option allows you to match against IPVS properties of a packet. - - If unsure, say N. - -config NETFILTER_XT_MATCH_L2TP - tristate '"l2tp" match support' - depends on NETFILTER_ADVANCED - default L2TP - ---help--- - This option adds an "L2TP" match, which allows you to match against - L2TP protocol header fields. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_LENGTH - tristate '"length" match support' - depends on NETFILTER_ADVANCED - help - This option allows you to match the length of a packet against a - specific value or range of values. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_LIMIT - tristate '"limit" match support' - depends on NETFILTER_ADVANCED - help - limit matching allows you to control the rate at which a rule can be - matched: mainly useful in combination with the LOG target ("LOG - target support", below) and to avoid some Denial of Service attacks. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_MAC - tristate '"mac" address match support' - depends on NETFILTER_ADVANCED - help - MAC matching allows you to match packets based on the source - Ethernet address of the packet. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_MARK - tristate '"mark" match support' - depends on NETFILTER_ADVANCED - select NETFILTER_XT_MARK - ---help--- - This is a backwards-compat option for the user's convenience - (e.g. when running oldconfig). It selects - CONFIG_NETFILTER_XT_MARK (combined mark/MARK module). - -config NETFILTER_XT_MATCH_MULTIPORT - tristate '"multiport" Multiple port match support' - depends on NETFILTER_ADVANCED - help - Multiport matching allows you to match TCP or UDP packets based on - a series of source or destination ports: normally a rule can only - match a single range of ports. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_NFACCT - tristate '"nfacct" match support' - depends on NETFILTER_ADVANCED - select NETFILTER_NETLINK_ACCT - help - This option allows you to use the extended accounting through - nfnetlink_acct. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_OSF - tristate '"osf" Passive OS fingerprint match' - depends on NETFILTER_ADVANCED && NETFILTER_NETLINK - help - This option selects the Passive OS Fingerprinting match module - that allows to passively match the remote operating system by - analyzing incoming TCP SYN packets. - - Rules and loading software can be downloaded from - http://www.ioremap.net/projects/osf - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_OWNER - tristate '"owner" match support' - depends on NETFILTER_ADVANCED - ---help--- - Socket owner matching allows you to match locally-generated packets - based on who created the socket: the user or group. It is also - possible to check whether a socket actually exists. - -config NETFILTER_XT_MATCH_POLICY - tristate 'IPsec "policy" match support' - depends on XFRM - default m if NETFILTER_ADVANCED=n - help - Policy matching allows you to match packets based on the - IPsec policy that was used during decapsulation/will - be used during encapsulation. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_PHYSDEV - tristate '"physdev" match support' - depends on BRIDGE && BRIDGE_NETFILTER - depends on NETFILTER_ADVANCED - help - Physdev packet matching matches against the physical bridge ports - the IP packet arrived on or will leave by. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_PKTTYPE - tristate '"pkttype" packet type match support' - depends on NETFILTER_ADVANCED - help - Packet type matching allows you to match a packet by - its "class", eg. BROADCAST, MULTICAST, ... - - Typical usage: - iptables -A INPUT -m pkttype --pkt-type broadcast -j LOG - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_QUOTA - tristate '"quota" match support' - depends on NETFILTER_ADVANCED - help - This option adds a `quota' match, which allows to match on a - byte counter. - - If you want to compile it as a module, say M here and read - . If unsure, say `N'. - -config NETFILTER_XT_MATCH_RATEEST - tristate '"rateest" match support' - depends on NETFILTER_ADVANCED - select NETFILTER_XT_TARGET_RATEEST - help - This option adds a `rateest' match, which allows to match on the - rate estimated by the RATEEST target. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_REALM - tristate '"realm" match support' - depends on NETFILTER_ADVANCED - select IP_ROUTE_CLASSID - help - This option adds a `realm' match, which allows you to use the realm - key from the routing subsystem inside iptables. - - This match pretty much resembles the CONFIG_NET_CLS_ROUTE4 option - in tc world. - - If you want to compile it as a module, say M here and read - . If unsure, say `N'. - -config NETFILTER_XT_MATCH_RECENT - tristate '"recent" match support' - depends on NETFILTER_ADVANCED - ---help--- - This match is used for creating one or many lists of recently - used addresses and then matching against that/those list(s). - - Short options are available by using 'iptables -m recent -h' - Official Website: - -config NETFILTER_XT_MATCH_SCTP - tristate '"sctp" protocol match support' - depends on NETFILTER_ADVANCED - default IP_SCTP - help - With this option enabled, you will be able to use the - `sctp' match in order to match on SCTP source/destination ports - and SCTP chunk types. - - If you want to compile it as a module, say M here and read - . If unsure, say `N'. - -config NETFILTER_XT_MATCH_SOCKET - tristate '"socket" match support' - depends on NETFILTER_XTABLES - depends on NETFILTER_ADVANCED - depends on !NF_CONNTRACK || NF_CONNTRACK - depends on IPV6 || IPV6=n - depends on IP6_NF_IPTABLES || IP6_NF_IPTABLES=n - select NF_DEFRAG_IPV4 - select NF_DEFRAG_IPV6 if IP6_NF_IPTABLES != n - help - This option adds a `socket' match, which can be used to match - packets for which a TCP or UDP socket lookup finds a valid socket. - It can be used in combination with the MARK target and policy - routing to implement full featured non-locally bound sockets. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_STATE - tristate '"state" match support' - depends on NF_CONNTRACK - default m if NETFILTER_ADVANCED=n - help - Connection state matching allows you to match packets based on their - relationship to a tracked connection (ie. previous packets). This - is a powerful tool for packet classification. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_STATISTIC - tristate '"statistic" match support' - depends on NETFILTER_ADVANCED - help - This option adds a `statistic' match, which allows you to match - on packets periodically or randomly with a given percentage. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_STRING - tristate '"string" match support' - depends on NETFILTER_ADVANCED - select TEXTSEARCH - select TEXTSEARCH_KMP - select TEXTSEARCH_BM - select TEXTSEARCH_FSM - help - This option adds a `string' match, which allows you to look for - pattern matchings in packets. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_TCPMSS - tristate '"tcpmss" match support' - depends on NETFILTER_ADVANCED - help - This option adds a `tcpmss' match, which allows you to examine the - MSS value of TCP SYN packets, which control the maximum packet size - for that connection. - - To compile it as a module, choose M here. If unsure, say N. - -config NETFILTER_XT_MATCH_TIME - tristate '"time" match support' - depends on NETFILTER_ADVANCED - ---help--- - This option adds a "time" match, which allows you to match based on - the packet arrival time (at the machine which netfilter is running) - on) or departure time/date (for locally generated packets). - - If you say Y here, try `iptables -m time --help` for - more information. - - If you want to compile it as a module, say M here. - If unsure, say N. - -config NETFILTER_XT_MATCH_U32 - tristate '"u32" match support' - depends on NETFILTER_ADVANCED - ---help--- - u32 allows you to extract quantities of up to 4 bytes from a packet, - AND them with specified masks, shift them by specified amounts and - test whether the results are in any of a set of specified ranges. - The specification of what to extract is general enough to skip over - headers with lengths stored in the packet, as in IP or TCP header - lengths. - - Details and examples are in the kernel module source. - -endif # NETFILTER_XTABLES - -endmenu - -source "net/netfilter/ipset/Kconfig" - -source "net/netfilter/ipvs/Kconfig" diff --git a/src/linux/net/netfilter/ipset/Kconfig b/src/linux/net/netfilter/ipset/Kconfig deleted file mode 100644 index 234a8ec..0000000 --- a/src/linux/net/netfilter/ipset/Kconfig +++ /dev/null @@ -1,168 +0,0 @@ -menuconfig IP_SET - tristate "IP set support" - depends on INET && NETFILTER - select NETFILTER_NETLINK - help - This option adds IP set support to the kernel. - In order to define and use the sets, you need the userspace utility - ipset(8). You can use the sets in netfilter via the "set" match - and "SET" target. - - To compile it as a module, choose M here. If unsure, say N. - -if IP_SET - -config IP_SET_MAX - int "Maximum number of IP sets" - default 256 - range 2 65534 - depends on IP_SET - help - You can define here default value of the maximum number - of IP sets for the kernel. - - The value can be overridden by the 'max_sets' module - parameter of the 'ip_set' module. - -config IP_SET_BITMAP_IP - tristate "bitmap:ip set support" - depends on IP_SET - help - This option adds the bitmap:ip set type support, by which one - can store IPv4 addresses (or network addresse) from a range. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_SET_BITMAP_IPMAC - tristate "bitmap:ip,mac set support" - depends on IP_SET - help - This option adds the bitmap:ip,mac set type support, by which one - can store IPv4 address and (source) MAC address pairs from a range. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_SET_BITMAP_PORT - tristate "bitmap:port set support" - depends on IP_SET - help - This option adds the bitmap:port set type support, by which one - can store TCP/UDP port numbers from a range. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_SET_HASH_IP - tristate "hash:ip set support" - depends on IP_SET - help - This option adds the hash:ip set type support, by which one - can store arbitrary IPv4 or IPv6 addresses (or network addresses) - in a set. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_SET_HASH_IPMARK - tristate "hash:ip,mark set support" - depends on IP_SET - help - This option adds the hash:ip,mark set type support, by which one - can store IPv4/IPv6 address and mark pairs. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_SET_HASH_IPPORT - tristate "hash:ip,port set support" - depends on IP_SET - help - This option adds the hash:ip,port set type support, by which one - can store IPv4/IPv6 address and protocol/port pairs. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_SET_HASH_IPPORTIP - tristate "hash:ip,port,ip set support" - depends on IP_SET - help - This option adds the hash:ip,port,ip set type support, by which - one can store IPv4/IPv6 address, protocol/port, and IPv4/IPv6 - address triples in a set. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_SET_HASH_IPPORTNET - tristate "hash:ip,port,net set support" - depends on IP_SET - help - This option adds the hash:ip,port,net set type support, by which - one can store IPv4/IPv6 address, protocol/port, and IPv4/IPv6 - network address/prefix triples in a set. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_SET_HASH_MAC - tristate "hash:mac set support" - depends on IP_SET - help - This option adds the hash:mac set type support, by which - one can store MAC (ethernet address) elements in a set. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_SET_HASH_NETPORTNET - tristate "hash:net,port,net set support" - depends on IP_SET - help - This option adds the hash:net,port,net set type support, by which - one can store two IPv4/IPv6 subnets, and a protocol/port in a set. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_SET_HASH_NET - tristate "hash:net set support" - depends on IP_SET - help - This option adds the hash:net set type support, by which - one can store IPv4/IPv6 network address/prefix elements in a set. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_SET_HASH_NETNET - tristate "hash:net,net set support" - depends on IP_SET - help - This option adds the hash:net,net set type support, by which - one can store IPv4/IPv6 network address/prefix pairs in a set. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_SET_HASH_NETPORT - tristate "hash:net,port set support" - depends on IP_SET - help - This option adds the hash:net,port set type support, by which - one can store IPv4/IPv6 network address/prefix and - protocol/port pairs as elements in a set. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_SET_HASH_NETIFACE - tristate "hash:net,iface set support" - depends on IP_SET - help - This option adds the hash:net,iface set type support, by which - one can store IPv4/IPv6 network address/prefix and - interface name pairs as elements in a set. - - To compile it as a module, choose M here. If unsure, say N. - -config IP_SET_LIST_SET - tristate "list:set set support" - depends on IP_SET - help - This option adds the list:set set type support. In this - kind of set one can store the name of other sets and it forms - an ordered union of the member sets. - - To compile it as a module, choose M here. If unsure, say N. - -endif # IP_SET diff --git a/src/linux/net/netfilter/ipvs/Kconfig b/src/linux/net/netfilter/ipvs/Kconfig deleted file mode 100644 index b32fb0d..0000000 --- a/src/linux/net/netfilter/ipvs/Kconfig +++ /dev/null @@ -1,302 +0,0 @@ -# -# IP Virtual Server configuration -# -menuconfig IP_VS - tristate "IP virtual server support" - depends on NET && INET && NETFILTER - depends on (NF_CONNTRACK || NF_CONNTRACK=n) - ---help--- - IP Virtual Server support will let you build a high-performance - virtual server based on cluster of two or more real servers. This - option must be enabled for at least one of the clustered computers - that will take care of intercepting incoming connections to a - single IP address and scheduling them to real servers. - - Three request dispatching techniques are implemented, they are - virtual server via NAT, virtual server via tunneling and virtual - server via direct routing. The several scheduling algorithms can - be used to choose which server the connection is directed to, - thus load balancing can be achieved among the servers. For more - information and its administration program, please visit the - following URL: . - - If you want to compile it in kernel, say Y. To compile it as a - module, choose M here. If unsure, say N. - -if IP_VS - -config IP_VS_IPV6 - bool "IPv6 support for IPVS" - depends on IPV6 = y || IP_VS = IPV6 - select IP6_NF_IPTABLES - ---help--- - Add IPv6 support to IPVS. - - Say Y if unsure. - -config IP_VS_DEBUG - bool "IP virtual server debugging" - ---help--- - Say Y here if you want to get additional messages useful in - debugging the IP virtual server code. You can change the debug - level in /proc/sys/net/ipv4/vs/debug_level - -config IP_VS_TAB_BITS - int "IPVS connection table size (the Nth power of 2)" - range 8 20 - default 12 - ---help--- - The IPVS connection hash table uses the chaining scheme to handle - hash collisions. Using a big IPVS connection hash table will greatly - reduce conflicts when there are hundreds of thousands of connections - in the hash table. - - Note the table size must be power of 2. The table size will be the - value of 2 to the your input number power. The number to choose is - from 8 to 20, the default number is 12, which means the table size - is 4096. Don't input the number too small, otherwise you will lose - performance on it. You can adapt the table size yourself, according - to your virtual server application. It is good to set the table size - not far less than the number of connections per second multiplying - average lasting time of connection in the table. For example, your - virtual server gets 200 connections per second, the connection lasts - for 200 seconds in average in the connection table, the table size - should be not far less than 200x200, it is good to set the table - size 32768 (2**15). - - Another note that each connection occupies 128 bytes effectively and - each hash entry uses 8 bytes, so you can estimate how much memory is - needed for your box. - - You can overwrite this number setting conn_tab_bits module parameter - or by appending ip_vs.conn_tab_bits=? to the kernel command line - if IP VS was compiled built-in. - -comment "IPVS transport protocol load balancing support" - -config IP_VS_PROTO_TCP - bool "TCP load balancing support" - ---help--- - This option enables support for load balancing TCP transport - protocol. Say Y if unsure. - -config IP_VS_PROTO_UDP - bool "UDP load balancing support" - ---help--- - This option enables support for load balancing UDP transport - protocol. Say Y if unsure. - -config IP_VS_PROTO_AH_ESP - def_bool IP_VS_PROTO_ESP || IP_VS_PROTO_AH - -config IP_VS_PROTO_ESP - bool "ESP load balancing support" - ---help--- - This option enables support for load balancing ESP (Encapsulation - Security Payload) transport protocol. Say Y if unsure. - -config IP_VS_PROTO_AH - bool "AH load balancing support" - ---help--- - This option enables support for load balancing AH (Authentication - Header) transport protocol. Say Y if unsure. - -config IP_VS_PROTO_SCTP - bool "SCTP load balancing support" - select LIBCRC32C - ---help--- - This option enables support for load balancing SCTP transport - protocol. Say Y if unsure. - -comment "IPVS scheduler" - -config IP_VS_RR - tristate "round-robin scheduling" - ---help--- - The robin-robin scheduling algorithm simply directs network - connections to different real servers in a round-robin manner. - - If you want to compile it in kernel, say Y. To compile it as a - module, choose M here. If unsure, say N. - -config IP_VS_WRR - tristate "weighted round-robin scheduling" - ---help--- - The weighted robin-robin scheduling algorithm directs network - connections to different real servers based on server weights - in a round-robin manner. Servers with higher weights receive - new connections first than those with less weights, and servers - with higher weights get more connections than those with less - weights and servers with equal weights get equal connections. - - If you want to compile it in kernel, say Y. To compile it as a - module, choose M here. If unsure, say N. - -config IP_VS_LC - tristate "least-connection scheduling" - ---help--- - The least-connection scheduling algorithm directs network - connections to the server with the least number of active - connections. - - If you want to compile it in kernel, say Y. To compile it as a - module, choose M here. If unsure, say N. - -config IP_VS_WLC - tristate "weighted least-connection scheduling" - ---help--- - The weighted least-connection scheduling algorithm directs network - connections to the server with the least active connections - normalized by the server weight. - - If you want to compile it in kernel, say Y. To compile it as a - module, choose M here. If unsure, say N. - -config IP_VS_FO - tristate "weighted failover scheduling" - ---help--- - The weighted failover scheduling algorithm directs network - connections to the server with the highest weight that is - currently available. - - If you want to compile it in kernel, say Y. To compile it as a - module, choose M here. If unsure, say N. - -config IP_VS_OVF - tristate "weighted overflow scheduling" - ---help--- - The weighted overflow scheduling algorithm directs network - connections to the server with the highest weight that is - currently available and overflows to the next when active - connections exceed the node's weight. - - If you want to compile it in kernel, say Y. To compile it as a - module, choose M here. If unsure, say N. - -config IP_VS_LBLC - tristate "locality-based least-connection scheduling" - ---help--- - The locality-based least-connection scheduling algorithm is for - destination IP load balancing. It is usually used in cache cluster. - This algorithm usually directs packet destined for an IP address to - its server if the server is alive and under load. If the server is - overloaded (its active connection numbers is larger than its weight) - and there is a server in its half load, then allocate the weighted - least-connection server to this IP address. - - If you want to compile it in kernel, say Y. To compile it as a - module, choose M here. If unsure, say N. - -config IP_VS_LBLCR - tristate "locality-based least-connection with replication scheduling" - ---help--- - The locality-based least-connection with replication scheduling - algorithm is also for destination IP load balancing. It is - usually used in cache cluster. It differs from the LBLC scheduling - as follows: the load balancer maintains mappings from a target - to a set of server nodes that can serve the target. Requests for - a target are assigned to the least-connection node in the target's - server set. If all the node in the server set are over loaded, - it picks up a least-connection node in the cluster and adds it - in the sever set for the target. If the server set has not been - modified for the specified time, the most loaded node is removed - from the server set, in order to avoid high degree of replication. - - If you want to compile it in kernel, say Y. To compile it as a - module, choose M here. If unsure, say N. - -config IP_VS_DH - tristate "destination hashing scheduling" - ---help--- - The destination hashing scheduling algorithm assigns network - connections to the servers through looking up a statically assigned - hash table by their destination IP addresses. - - If you want to compile it in kernel, say Y. To compile it as a - module, choose M here. If unsure, say N. - -config IP_VS_SH - tristate "source hashing scheduling" - ---help--- - The source hashing scheduling algorithm assigns network - connections to the servers through looking up a statically assigned - hash table by their source IP addresses. - - If you want to compile it in kernel, say Y. To compile it as a - module, choose M here. If unsure, say N. - -config IP_VS_SED - tristate "shortest expected delay scheduling" - ---help--- - The shortest expected delay scheduling algorithm assigns network - connections to the server with the shortest expected delay. The - expected delay that the job will experience is (Ci + 1) / Ui if - sent to the ith server, in which Ci is the number of connections - on the ith server and Ui is the fixed service rate (weight) - of the ith server. - - If you want to compile it in kernel, say Y. To compile it as a - module, choose M here. If unsure, say N. - -config IP_VS_NQ - tristate "never queue scheduling" - ---help--- - The never queue scheduling algorithm adopts a two-speed model. - When there is an idle server available, the job will be sent to - the idle server, instead of waiting for a fast one. When there - is no idle server available, the job will be sent to the server - that minimize its expected delay (The Shortest Expected Delay - scheduling algorithm). - - If you want to compile it in kernel, say Y. To compile it as a - module, choose M here. If unsure, say N. - -comment 'IPVS SH scheduler' - -config IP_VS_SH_TAB_BITS - int "IPVS source hashing table size (the Nth power of 2)" - range 4 20 - default 8 - ---help--- - The source hashing scheduler maps source IPs to destinations - stored in a hash table. This table is tiled by each destination - until all slots in the table are filled. When using weights to - allow destinations to receive more connections, the table is - tiled an amount proportional to the weights specified. The table - needs to be large enough to effectively fit all the destinations - multiplied by their respective weights. - -comment 'IPVS application helper' - -config IP_VS_FTP - tristate "FTP protocol helper" - depends on IP_VS_PROTO_TCP && NF_CONNTRACK && NF_NAT && \ - NF_CONNTRACK_FTP - select IP_VS_NFCT - ---help--- - FTP is a protocol that transfers IP address and/or port number in - the payload. In the virtual server via Network Address Translation, - the IP address and port number of real servers cannot be sent to - clients in ftp connections directly, so FTP protocol helper is - required for tracking the connection and mangling it back to that of - virtual service. - - If you want to compile it in kernel, say Y. To compile it as a - module, choose M here. If unsure, say N. - -config IP_VS_NFCT - bool "Netfilter connection tracking" - depends on NF_CONNTRACK - ---help--- - The Netfilter connection tracking support allows the IPVS - connection state to be exported to the Netfilter framework - for filtering purposes. - -config IP_VS_PE_SIP - tristate "SIP persistence engine" - depends on IP_VS_PROTO_UDP - depends on NF_CONNTRACK_SIP - ---help--- - Allow persistence based on the SIP Call-ID - -endif # IP_VS diff --git a/src/linux/net/netlabel/Kconfig b/src/linux/net/netlabel/Kconfig deleted file mode 100644 index d9eaa30..0000000 --- a/src/linux/net/netlabel/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -# -# NetLabel configuration -# - -config NETLABEL - bool "NetLabel subsystem support" - depends on SECURITY - select CRC_CCITT if IPV6 - default n - ---help--- - NetLabel provides support for explicit network packet labeling - protocols such as CIPSO and RIPSO. For more information see - Documentation/netlabel as well as the NetLabel SourceForge project - for configuration tools and additional documentation. - - * http://netlabel.sf.net - - If you are unsure, say N. diff --git a/src/linux/net/netlink/Kconfig b/src/linux/net/netlink/Kconfig deleted file mode 100644 index 5d6e8c0..0000000 --- a/src/linux/net/netlink/Kconfig +++ /dev/null @@ -1,10 +0,0 @@ -# -# Netlink Sockets -# - -config NETLINK_DIAG - tristate "NETLINK: socket monitoring interface" - default n - ---help--- - Support for NETLINK socket monitoring interface used by the ss tool. - If unsure, say Y. diff --git a/src/linux/net/netlink/Makefile b/src/linux/net/netlink/Makefile deleted file mode 100644 index e837917..0000000 --- a/src/linux/net/netlink/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# -# Makefile for the netlink driver. -# - -obj-y := af_netlink.o genetlink.o - -obj-$(CONFIG_NETLINK_DIAG) += netlink_diag.o -netlink_diag-y := diag.o diff --git a/src/linux/net/netlink/af_netlink.c b/src/linux/net/netlink/af_netlink.c deleted file mode 100644 index 246f29d..0000000 --- a/src/linux/net/netlink/af_netlink.c +++ /dev/null @@ -1,2640 +0,0 @@ -/* - * NETLINK Kernel-user communication protocol. - * - * Authors: Alan Cox - * Alexey Kuznetsov - * Patrick McHardy - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Tue Jun 26 14:36:48 MEST 2001 Herbert "herp" Rosmanith - * added netlink_proto_exit - * Tue Jan 22 18:32:44 BRST 2002 Arnaldo C. de Melo - * use nlk_sk, as sk->protinfo is on a diet 8) - * Fri Jul 22 19:51:12 MEST 2005 Harald Welte - * - inc module use count of module that owns - * the kernel socket in case userspace opens - * socket of same protocol - * - remove all module support, since netlink is - * mandatory if CONFIG_NET=y these days - */ - -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "af_netlink.h" - -struct listeners { - struct rcu_head rcu; - unsigned long masks[0]; -}; - -/* state bits */ -#define NETLINK_S_CONGESTED 0x0 - -/* flags */ -#define NETLINK_F_KERNEL_SOCKET 0x1 -#define NETLINK_F_RECV_PKTINFO 0x2 -#define NETLINK_F_BROADCAST_SEND_ERROR 0x4 -#define NETLINK_F_RECV_NO_ENOBUFS 0x8 -#define NETLINK_F_LISTEN_ALL_NSID 0x10 -#define NETLINK_F_CAP_ACK 0x20 - -static inline int netlink_is_kernel(struct sock *sk) -{ - return nlk_sk(sk)->flags & NETLINK_F_KERNEL_SOCKET; -} - -struct netlink_table *nl_table __read_mostly; -EXPORT_SYMBOL_GPL(nl_table); - -static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait); - -static int netlink_dump(struct sock *sk); -static void netlink_skb_destructor(struct sk_buff *skb); - -/* nl_table locking explained: - * Lookup and traversal are protected with an RCU read-side lock. Insertion - * and removal are protected with per bucket lock while using RCU list - * modification primitives and may run in parallel to RCU protected lookups. - * Destruction of the Netlink socket may only occur *after* nl_table_lock has - * been acquired * either during or after the socket has been removed from - * the list and after an RCU grace period. - */ -DEFINE_RWLOCK(nl_table_lock); -EXPORT_SYMBOL_GPL(nl_table_lock); -static atomic_t nl_table_users = ATOMIC_INIT(0); - -#define nl_deref_protected(X) rcu_dereference_protected(X, lockdep_is_held(&nl_table_lock)); - -static ATOMIC_NOTIFIER_HEAD(netlink_chain); - -static DEFINE_SPINLOCK(netlink_tap_lock); -static struct list_head netlink_tap_all __read_mostly; - -static const struct rhashtable_params netlink_rhashtable_params; - -static inline u32 netlink_group_mask(u32 group) -{ - return group ? 1 << (group - 1) : 0; -} - -static struct sk_buff *netlink_to_full_skb(const struct sk_buff *skb, - gfp_t gfp_mask) -{ - unsigned int len = skb_end_offset(skb); - struct sk_buff *new; - - new = alloc_skb(len, gfp_mask); - if (new == NULL) - return NULL; - - NETLINK_CB(new).portid = NETLINK_CB(skb).portid; - NETLINK_CB(new).dst_group = NETLINK_CB(skb).dst_group; - NETLINK_CB(new).creds = NETLINK_CB(skb).creds; - - memcpy(skb_put(new, len), skb->data, len); - return new; -} - -int netlink_add_tap(struct netlink_tap *nt) -{ - if (unlikely(nt->dev->type != ARPHRD_NETLINK)) - return -EINVAL; - - spin_lock(&netlink_tap_lock); - list_add_rcu(&nt->list, &netlink_tap_all); - spin_unlock(&netlink_tap_lock); - - __module_get(nt->module); - - return 0; -} -EXPORT_SYMBOL_GPL(netlink_add_tap); - -static int __netlink_remove_tap(struct netlink_tap *nt) -{ - bool found = false; - struct netlink_tap *tmp; - - spin_lock(&netlink_tap_lock); - - list_for_each_entry(tmp, &netlink_tap_all, list) { - if (nt == tmp) { - list_del_rcu(&nt->list); - found = true; - goto out; - } - } - - pr_warn("__netlink_remove_tap: %p not found\n", nt); -out: - spin_unlock(&netlink_tap_lock); - - if (found) - module_put(nt->module); - - return found ? 0 : -ENODEV; -} - -int netlink_remove_tap(struct netlink_tap *nt) -{ - int ret; - - ret = __netlink_remove_tap(nt); - synchronize_net(); - - return ret; -} -EXPORT_SYMBOL_GPL(netlink_remove_tap); - -static bool netlink_filter_tap(const struct sk_buff *skb) -{ - struct sock *sk = skb->sk; - - /* We take the more conservative approach and - * whitelist socket protocols that may pass. - */ - switch (sk->sk_protocol) { - case NETLINK_ROUTE: - case NETLINK_USERSOCK: - case NETLINK_SOCK_DIAG: - case NETLINK_NFLOG: - case NETLINK_XFRM: - case NETLINK_FIB_LOOKUP: - case NETLINK_NETFILTER: - case NETLINK_GENERIC: - return true; - } - - return false; -} - -static int __netlink_deliver_tap_skb(struct sk_buff *skb, - struct net_device *dev) -{ - struct sk_buff *nskb; - struct sock *sk = skb->sk; - int ret = -ENOMEM; - - dev_hold(dev); - - if (is_vmalloc_addr(skb->head)) - nskb = netlink_to_full_skb(skb, GFP_ATOMIC); - else - nskb = skb_clone(skb, GFP_ATOMIC); - if (nskb) { - nskb->dev = dev; - nskb->protocol = htons((u16) sk->sk_protocol); - nskb->pkt_type = netlink_is_kernel(sk) ? - PACKET_KERNEL : PACKET_USER; - skb_reset_network_header(nskb); - ret = dev_queue_xmit(nskb); - if (unlikely(ret > 0)) - ret = net_xmit_errno(ret); - } - - dev_put(dev); - return ret; -} - -static void __netlink_deliver_tap(struct sk_buff *skb) -{ - int ret; - struct netlink_tap *tmp; - - if (!netlink_filter_tap(skb)) - return; - - list_for_each_entry_rcu(tmp, &netlink_tap_all, list) { - ret = __netlink_deliver_tap_skb(skb, tmp->dev); - if (unlikely(ret)) - break; - } -} - -static void netlink_deliver_tap(struct sk_buff *skb) -{ - rcu_read_lock(); - - if (unlikely(!list_empty(&netlink_tap_all))) - __netlink_deliver_tap(skb); - - rcu_read_unlock(); -} - -static void netlink_deliver_tap_kernel(struct sock *dst, struct sock *src, - struct sk_buff *skb) -{ - if (!(netlink_is_kernel(dst) && netlink_is_kernel(src))) - netlink_deliver_tap(skb); -} - -static void netlink_overrun(struct sock *sk) -{ - struct netlink_sock *nlk = nlk_sk(sk); - - if (!(nlk->flags & NETLINK_F_RECV_NO_ENOBUFS)) { - if (!test_and_set_bit(NETLINK_S_CONGESTED, - &nlk_sk(sk)->state)) { - sk->sk_err = ENOBUFS; - sk->sk_error_report(sk); - } - } - atomic_inc(&sk->sk_drops); -} - -static void netlink_rcv_wake(struct sock *sk) -{ - struct netlink_sock *nlk = nlk_sk(sk); - - if (skb_queue_empty(&sk->sk_receive_queue)) - clear_bit(NETLINK_S_CONGESTED, &nlk->state); - if (!test_bit(NETLINK_S_CONGESTED, &nlk->state)) - wake_up_interruptible(&nlk->wait); -} - -static void netlink_skb_destructor(struct sk_buff *skb) -{ - if (is_vmalloc_addr(skb->head)) { - if (!skb->cloned || - !atomic_dec_return(&(skb_shinfo(skb)->dataref))) - vfree(skb->head); - - skb->head = NULL; - } - if (skb->sk != NULL) - sock_rfree(skb); -} - -static void netlink_skb_set_owner_r(struct sk_buff *skb, struct sock *sk) -{ - WARN_ON(skb->sk != NULL); - skb->sk = sk; - skb->destructor = netlink_skb_destructor; - atomic_add(skb->truesize, &sk->sk_rmem_alloc); - sk_mem_charge(sk, skb->truesize); -} - -static void netlink_sock_destruct(struct sock *sk) -{ - struct netlink_sock *nlk = nlk_sk(sk); - - if (nlk->cb_running) { - if (nlk->cb.done) - nlk->cb.done(&nlk->cb); - module_put(nlk->cb.module); - kfree_skb(nlk->cb.skb); - } - - skb_queue_purge(&sk->sk_receive_queue); - - if (!sock_flag(sk, SOCK_DEAD)) { - printk(KERN_ERR "Freeing alive netlink socket %p\n", sk); - return; - } - - WARN_ON(atomic_read(&sk->sk_rmem_alloc)); - WARN_ON(atomic_read(&sk->sk_wmem_alloc)); - WARN_ON(nlk_sk(sk)->groups); -} - -static void netlink_sock_destruct_work(struct work_struct *work) -{ - struct netlink_sock *nlk = container_of(work, struct netlink_sock, - work); - - sk_free(&nlk->sk); -} - -/* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on - * SMP. Look, when several writers sleep and reader wakes them up, all but one - * immediately hit write lock and grab all the cpus. Exclusive sleep solves - * this, _but_ remember, it adds useless work on UP machines. - */ - -void netlink_table_grab(void) - __acquires(nl_table_lock) -{ - might_sleep(); - - write_lock_irq(&nl_table_lock); - - if (atomic_read(&nl_table_users)) { - DECLARE_WAITQUEUE(wait, current); - - add_wait_queue_exclusive(&nl_table_wait, &wait); - for (;;) { - set_current_state(TASK_UNINTERRUPTIBLE); - if (atomic_read(&nl_table_users) == 0) - break; - write_unlock_irq(&nl_table_lock); - schedule(); - write_lock_irq(&nl_table_lock); - } - - __set_current_state(TASK_RUNNING); - remove_wait_queue(&nl_table_wait, &wait); - } -} - -void netlink_table_ungrab(void) - __releases(nl_table_lock) -{ - write_unlock_irq(&nl_table_lock); - wake_up(&nl_table_wait); -} - -static inline void -netlink_lock_table(void) -{ - /* read_lock() synchronizes us to netlink_table_grab */ - - read_lock(&nl_table_lock); - atomic_inc(&nl_table_users); - read_unlock(&nl_table_lock); -} - -static inline void -netlink_unlock_table(void) -{ - if (atomic_dec_and_test(&nl_table_users)) - wake_up(&nl_table_wait); -} - -struct netlink_compare_arg -{ - possible_net_t pnet; - u32 portid; -}; - -/* Doing sizeof directly may yield 4 extra bytes on 64-bit. */ -#define netlink_compare_arg_len \ - (offsetof(struct netlink_compare_arg, portid) + sizeof(u32)) - -static inline int netlink_compare(struct rhashtable_compare_arg *arg, - const void *ptr) -{ - const struct netlink_compare_arg *x = arg->key; - const struct netlink_sock *nlk = ptr; - - return nlk->portid != x->portid || - !net_eq(sock_net(&nlk->sk), read_pnet(&x->pnet)); -} - -static void netlink_compare_arg_init(struct netlink_compare_arg *arg, - struct net *net, u32 portid) -{ - memset(arg, 0, sizeof(*arg)); - write_pnet(&arg->pnet, net); - arg->portid = portid; -} - -static struct sock *__netlink_lookup(struct netlink_table *table, u32 portid, - struct net *net) -{ - struct netlink_compare_arg arg; - - netlink_compare_arg_init(&arg, net, portid); - return rhashtable_lookup_fast(&table->hash, &arg, - netlink_rhashtable_params); -} - -static int __netlink_insert(struct netlink_table *table, struct sock *sk) -{ - struct netlink_compare_arg arg; - - netlink_compare_arg_init(&arg, sock_net(sk), nlk_sk(sk)->portid); - return rhashtable_lookup_insert_key(&table->hash, &arg, - &nlk_sk(sk)->node, - netlink_rhashtable_params); -} - -static struct sock *netlink_lookup(struct net *net, int protocol, u32 portid) -{ - struct netlink_table *table = &nl_table[protocol]; - struct sock *sk; - - rcu_read_lock(); - sk = __netlink_lookup(table, portid, net); - if (sk) - sock_hold(sk); - rcu_read_unlock(); - - return sk; -} - -static const struct proto_ops netlink_ops; - -static void -netlink_update_listeners(struct sock *sk) -{ - struct netlink_table *tbl = &nl_table[sk->sk_protocol]; - unsigned long mask; - unsigned int i; - struct listeners *listeners; - - listeners = nl_deref_protected(tbl->listeners); - if (!listeners) - return; - - for (i = 0; i < NLGRPLONGS(tbl->groups); i++) { - mask = 0; - sk_for_each_bound(sk, &tbl->mc_list) { - if (i < NLGRPLONGS(nlk_sk(sk)->ngroups)) - mask |= nlk_sk(sk)->groups[i]; - } - listeners->masks[i] = mask; - } - /* this function is only called with the netlink table "grabbed", which - * makes sure updates are visible before bind or setsockopt return. */ -} - -static int netlink_insert(struct sock *sk, u32 portid) -{ - struct netlink_table *table = &nl_table[sk->sk_protocol]; - int err; - - lock_sock(sk); - - err = nlk_sk(sk)->portid == portid ? 0 : -EBUSY; - if (nlk_sk(sk)->bound) - goto err; - - err = -ENOMEM; - if (BITS_PER_LONG > 32 && - unlikely(atomic_read(&table->hash.nelems) >= UINT_MAX)) - goto err; - - nlk_sk(sk)->portid = portid; - sock_hold(sk); - - err = __netlink_insert(table, sk); - if (err) { - /* In case the hashtable backend returns with -EBUSY - * from here, it must not escape to the caller. - */ - if (unlikely(err == -EBUSY)) - err = -EOVERFLOW; - if (err == -EEXIST) - err = -EADDRINUSE; - sock_put(sk); - goto err; - } - - /* We need to ensure that the socket is hashed and visible. */ - smp_wmb(); - nlk_sk(sk)->bound = portid; - -err: - release_sock(sk); - return err; -} - -static void netlink_remove(struct sock *sk) -{ - struct netlink_table *table; - - table = &nl_table[sk->sk_protocol]; - if (!rhashtable_remove_fast(&table->hash, &nlk_sk(sk)->node, - netlink_rhashtable_params)) { - WARN_ON(atomic_read(&sk->sk_refcnt) == 1); - __sock_put(sk); - } - - netlink_table_grab(); - if (nlk_sk(sk)->subscriptions) { - __sk_del_bind_node(sk); - netlink_update_listeners(sk); - } - if (sk->sk_protocol == NETLINK_GENERIC) - atomic_inc(&genl_sk_destructing_cnt); - netlink_table_ungrab(); -} - -static struct proto netlink_proto = { - .name = "NETLINK", - .owner = THIS_MODULE, - .obj_size = sizeof(struct netlink_sock), -}; - -static int __netlink_create(struct net *net, struct socket *sock, - struct mutex *cb_mutex, int protocol, - int kern) -{ - struct sock *sk; - struct netlink_sock *nlk; - - sock->ops = &netlink_ops; - - sk = sk_alloc(net, PF_NETLINK, GFP_KERNEL, &netlink_proto, kern); - if (!sk) - return -ENOMEM; - - sock_init_data(sock, sk); - - nlk = nlk_sk(sk); - if (cb_mutex) { - nlk->cb_mutex = cb_mutex; - } else { - nlk->cb_mutex = &nlk->cb_def_mutex; - mutex_init(nlk->cb_mutex); - } - init_waitqueue_head(&nlk->wait); - - sk->sk_destruct = netlink_sock_destruct; - sk->sk_protocol = protocol; - return 0; -} - -static int netlink_create(struct net *net, struct socket *sock, int protocol, - int kern) -{ - struct module *module = NULL; - struct mutex *cb_mutex; - struct netlink_sock *nlk; - int (*bind)(struct net *net, int group); - void (*unbind)(struct net *net, int group); - int err = 0; - - sock->state = SS_UNCONNECTED; - - if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) - return -ESOCKTNOSUPPORT; - - if (protocol < 0 || protocol >= MAX_LINKS) - return -EPROTONOSUPPORT; - - netlink_lock_table(); -#ifdef CONFIG_MODULES - if (!nl_table[protocol].registered) { - netlink_unlock_table(); - request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol); - netlink_lock_table(); - } -#endif - if (nl_table[protocol].registered && - try_module_get(nl_table[protocol].module)) - module = nl_table[protocol].module; - else - err = -EPROTONOSUPPORT; - cb_mutex = nl_table[protocol].cb_mutex; - bind = nl_table[protocol].bind; - unbind = nl_table[protocol].unbind; - netlink_unlock_table(); - - if (err < 0) - goto out; - - err = __netlink_create(net, sock, cb_mutex, protocol, kern); - if (err < 0) - goto out_module; - - local_bh_disable(); - sock_prot_inuse_add(net, &netlink_proto, 1); - local_bh_enable(); - - nlk = nlk_sk(sock->sk); - nlk->module = module; - nlk->netlink_bind = bind; - nlk->netlink_unbind = unbind; -out: - return err; - -out_module: - module_put(module); - goto out; -} - -static void deferred_put_nlk_sk(struct rcu_head *head) -{ - struct netlink_sock *nlk = container_of(head, struct netlink_sock, rcu); - struct sock *sk = &nlk->sk; - - if (!atomic_dec_and_test(&sk->sk_refcnt)) - return; - - if (nlk->cb_running && nlk->cb.done) { - INIT_WORK(&nlk->work, netlink_sock_destruct_work); - schedule_work(&nlk->work); - return; - } - - sk_free(sk); -} - -static int netlink_release(struct socket *sock) -{ - struct sock *sk = sock->sk; - struct netlink_sock *nlk; - - if (!sk) - return 0; - - netlink_remove(sk); - sock_orphan(sk); - nlk = nlk_sk(sk); - - /* - * OK. Socket is unlinked, any packets that arrive now - * will be purged. - */ - - /* must not acquire netlink_table_lock in any way again before unbind - * and notifying genetlink is done as otherwise it might deadlock - */ - if (nlk->netlink_unbind) { - int i; - - for (i = 0; i < nlk->ngroups; i++) - if (test_bit(i, nlk->groups)) - nlk->netlink_unbind(sock_net(sk), i + 1); - } - if (sk->sk_protocol == NETLINK_GENERIC && - atomic_dec_return(&genl_sk_destructing_cnt) == 0) - wake_up(&genl_sk_destructing_waitq); - - sock->sk = NULL; - wake_up_interruptible_all(&nlk->wait); - - skb_queue_purge(&sk->sk_write_queue); - - if (nlk->portid && nlk->bound) { - struct netlink_notify n = { - .net = sock_net(sk), - .protocol = sk->sk_protocol, - .portid = nlk->portid, - }; - atomic_notifier_call_chain(&netlink_chain, - NETLINK_URELEASE, &n); - } - - module_put(nlk->module); - - if (netlink_is_kernel(sk)) { - netlink_table_grab(); - BUG_ON(nl_table[sk->sk_protocol].registered == 0); - if (--nl_table[sk->sk_protocol].registered == 0) { - struct listeners *old; - - old = nl_deref_protected(nl_table[sk->sk_protocol].listeners); - RCU_INIT_POINTER(nl_table[sk->sk_protocol].listeners, NULL); - kfree_rcu(old, rcu); - nl_table[sk->sk_protocol].module = NULL; - nl_table[sk->sk_protocol].bind = NULL; - nl_table[sk->sk_protocol].unbind = NULL; - nl_table[sk->sk_protocol].flags = 0; - nl_table[sk->sk_protocol].registered = 0; - } - netlink_table_ungrab(); - } - - kfree(nlk->groups); - nlk->groups = NULL; - - local_bh_disable(); - sock_prot_inuse_add(sock_net(sk), &netlink_proto, -1); - local_bh_enable(); - call_rcu(&nlk->rcu, deferred_put_nlk_sk); - return 0; -} - -static int netlink_autobind(struct socket *sock) -{ - struct sock *sk = sock->sk; - struct net *net = sock_net(sk); - struct netlink_table *table = &nl_table[sk->sk_protocol]; - s32 portid = task_tgid_vnr(current); - int err; - s32 rover = -4096; - bool ok; - -retry: - cond_resched(); - rcu_read_lock(); - ok = !__netlink_lookup(table, portid, net); - rcu_read_unlock(); - if (!ok) { - /* Bind collision, search negative portid values. */ - if (rover == -4096) - /* rover will be in range [S32_MIN, -4097] */ - rover = S32_MIN + prandom_u32_max(-4096 - S32_MIN); - else if (rover >= -4096) - rover = -4097; - portid = rover--; - goto retry; - } - - err = netlink_insert(sk, portid); - if (err == -EADDRINUSE) - goto retry; - - /* If 2 threads race to autobind, that is fine. */ - if (err == -EBUSY) - err = 0; - - return err; -} - -/** - * __netlink_ns_capable - General netlink message capability test - * @nsp: NETLINK_CB of the socket buffer holding a netlink command from userspace. - * @user_ns: The user namespace of the capability to use - * @cap: The capability to use - * - * Test to see if the opener of the socket we received the message - * from had when the netlink socket was created and the sender of the - * message has has the capability @cap in the user namespace @user_ns. - */ -bool __netlink_ns_capable(const struct netlink_skb_parms *nsp, - struct user_namespace *user_ns, int cap) -{ - return ((nsp->flags & NETLINK_SKB_DST) || - file_ns_capable(nsp->sk->sk_socket->file, user_ns, cap)) && - ns_capable(user_ns, cap); -} -EXPORT_SYMBOL(__netlink_ns_capable); - -/** - * netlink_ns_capable - General netlink message capability test - * @skb: socket buffer holding a netlink command from userspace - * @user_ns: The user namespace of the capability to use - * @cap: The capability to use - * - * Test to see if the opener of the socket we received the message - * from had when the netlink socket was created and the sender of the - * message has has the capability @cap in the user namespace @user_ns. - */ -bool netlink_ns_capable(const struct sk_buff *skb, - struct user_namespace *user_ns, int cap) -{ - return __netlink_ns_capable(&NETLINK_CB(skb), user_ns, cap); -} -EXPORT_SYMBOL(netlink_ns_capable); - -/** - * netlink_capable - Netlink global message capability test - * @skb: socket buffer holding a netlink command from userspace - * @cap: The capability to use - * - * Test to see if the opener of the socket we received the message - * from had when the netlink socket was created and the sender of the - * message has has the capability @cap in all user namespaces. - */ -bool netlink_capable(const struct sk_buff *skb, int cap) -{ - return netlink_ns_capable(skb, &init_user_ns, cap); -} -EXPORT_SYMBOL(netlink_capable); - -/** - * netlink_net_capable - Netlink network namespace message capability test - * @skb: socket buffer holding a netlink command from userspace - * @cap: The capability to use - * - * Test to see if the opener of the socket we received the message - * from had when the netlink socket was created and the sender of the - * message has has the capability @cap over the network namespace of - * the socket we received the message from. - */ -bool netlink_net_capable(const struct sk_buff *skb, int cap) -{ - return netlink_ns_capable(skb, sock_net(skb->sk)->user_ns, cap); -} -EXPORT_SYMBOL(netlink_net_capable); - -static inline int netlink_allowed(const struct socket *sock, unsigned int flag) -{ - return (nl_table[sock->sk->sk_protocol].flags & flag) || - ns_capable(sock_net(sock->sk)->user_ns, CAP_NET_ADMIN); -} - -static void -netlink_update_subscriptions(struct sock *sk, unsigned int subscriptions) -{ - struct netlink_sock *nlk = nlk_sk(sk); - - if (nlk->subscriptions && !subscriptions) - __sk_del_bind_node(sk); - else if (!nlk->subscriptions && subscriptions) - sk_add_bind_node(sk, &nl_table[sk->sk_protocol].mc_list); - nlk->subscriptions = subscriptions; -} - -static int netlink_realloc_groups(struct sock *sk) -{ - struct netlink_sock *nlk = nlk_sk(sk); - unsigned int groups; - unsigned long *new_groups; - int err = 0; - - netlink_table_grab(); - - groups = nl_table[sk->sk_protocol].groups; - if (!nl_table[sk->sk_protocol].registered) { - err = -ENOENT; - goto out_unlock; - } - - if (nlk->ngroups >= groups) - goto out_unlock; - - new_groups = krealloc(nlk->groups, NLGRPSZ(groups), GFP_ATOMIC); - if (new_groups == NULL) { - err = -ENOMEM; - goto out_unlock; - } - memset((char *)new_groups + NLGRPSZ(nlk->ngroups), 0, - NLGRPSZ(groups) - NLGRPSZ(nlk->ngroups)); - - nlk->groups = new_groups; - nlk->ngroups = groups; - out_unlock: - netlink_table_ungrab(); - return err; -} - -static void netlink_undo_bind(int group, long unsigned int groups, - struct sock *sk) -{ - struct netlink_sock *nlk = nlk_sk(sk); - int undo; - - if (!nlk->netlink_unbind) - return; - - for (undo = 0; undo < group; undo++) - if (test_bit(undo, &groups)) - nlk->netlink_unbind(sock_net(sk), undo + 1); -} - -static int netlink_bind(struct socket *sock, struct sockaddr *addr, - int addr_len) -{ - struct sock *sk = sock->sk; - struct net *net = sock_net(sk); - struct netlink_sock *nlk = nlk_sk(sk); - struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; - int err; - long unsigned int groups = nladdr->nl_groups; - bool bound; - - if (addr_len < sizeof(struct sockaddr_nl)) - return -EINVAL; - - if (nladdr->nl_family != AF_NETLINK) - return -EINVAL; - - /* Only superuser is allowed to listen multicasts */ - if (groups) { - if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV)) - return -EPERM; - err = netlink_realloc_groups(sk); - if (err) - return err; - } - - bound = nlk->bound; - if (bound) { - /* Ensure nlk->portid is up-to-date. */ - smp_rmb(); - - if (nladdr->nl_pid != nlk->portid) - return -EINVAL; - } - - if (nlk->netlink_bind && groups) { - int group; - - for (group = 0; group < nlk->ngroups; group++) { - if (!test_bit(group, &groups)) - continue; - err = nlk->netlink_bind(net, group + 1); - if (!err) - continue; - netlink_undo_bind(group, groups, sk); - return err; - } - } - - /* No need for barriers here as we return to user-space without - * using any of the bound attributes. - */ - if (!bound) { - err = nladdr->nl_pid ? - netlink_insert(sk, nladdr->nl_pid) : - netlink_autobind(sock); - if (err) { - netlink_undo_bind(nlk->ngroups, groups, sk); - return err; - } - } - - if (!groups && (nlk->groups == NULL || !(u32)nlk->groups[0])) - return 0; - - netlink_table_grab(); - netlink_update_subscriptions(sk, nlk->subscriptions + - hweight32(groups) - - hweight32(nlk->groups[0])); - nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | groups; - netlink_update_listeners(sk); - netlink_table_ungrab(); - - return 0; -} - -static int netlink_connect(struct socket *sock, struct sockaddr *addr, - int alen, int flags) -{ - int err = 0; - struct sock *sk = sock->sk; - struct netlink_sock *nlk = nlk_sk(sk); - struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; - - if (alen < sizeof(addr->sa_family)) - return -EINVAL; - - if (addr->sa_family == AF_UNSPEC) { - sk->sk_state = NETLINK_UNCONNECTED; - nlk->dst_portid = 0; - nlk->dst_group = 0; - return 0; - } - if (addr->sa_family != AF_NETLINK) - return -EINVAL; - - if ((nladdr->nl_groups || nladdr->nl_pid) && - !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) - return -EPERM; - - /* No need for barriers here as we return to user-space without - * using any of the bound attributes. - */ - if (!nlk->bound) - err = netlink_autobind(sock); - - if (err == 0) { - sk->sk_state = NETLINK_CONNECTED; - nlk->dst_portid = nladdr->nl_pid; - nlk->dst_group = ffs(nladdr->nl_groups); - } - - return err; -} - -static int netlink_getname(struct socket *sock, struct sockaddr *addr, - int *addr_len, int peer) -{ - struct sock *sk = sock->sk; - struct netlink_sock *nlk = nlk_sk(sk); - DECLARE_SOCKADDR(struct sockaddr_nl *, nladdr, addr); - - nladdr->nl_family = AF_NETLINK; - nladdr->nl_pad = 0; - *addr_len = sizeof(*nladdr); - - if (peer) { - nladdr->nl_pid = nlk->dst_portid; - nladdr->nl_groups = netlink_group_mask(nlk->dst_group); - } else { - nladdr->nl_pid = nlk->portid; - nladdr->nl_groups = nlk->groups ? nlk->groups[0] : 0; - } - return 0; -} - -static int netlink_ioctl(struct socket *sock, unsigned int cmd, - unsigned long arg) -{ - /* try to hand this ioctl down to the NIC drivers. - */ - return -ENOIOCTLCMD; -} - -static struct sock *netlink_getsockbyportid(struct sock *ssk, u32 portid) -{ - struct sock *sock; - struct netlink_sock *nlk; - - sock = netlink_lookup(sock_net(ssk), ssk->sk_protocol, portid); - if (!sock) - return ERR_PTR(-ECONNREFUSED); - - /* Don't bother queuing skb if kernel socket has no input function */ - nlk = nlk_sk(sock); - if (sock->sk_state == NETLINK_CONNECTED && - nlk->dst_portid != nlk_sk(ssk)->portid) { - sock_put(sock); - return ERR_PTR(-ECONNREFUSED); - } - return sock; -} - -struct sock *netlink_getsockbyfilp(struct file *filp) -{ - struct inode *inode = file_inode(filp); - struct sock *sock; - - if (!S_ISSOCK(inode->i_mode)) - return ERR_PTR(-ENOTSOCK); - - sock = SOCKET_I(inode)->sk; - if (sock->sk_family != AF_NETLINK) - return ERR_PTR(-EINVAL); - - sock_hold(sock); - return sock; -} - -static struct sk_buff *netlink_alloc_large_skb(unsigned int size, - int broadcast) -{ - struct sk_buff *skb; - void *data; - - if (size <= NLMSG_GOODSIZE || broadcast) - return alloc_skb(size, GFP_KERNEL); - - size = SKB_DATA_ALIGN(size) + - SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); - - data = vmalloc(size); - if (data == NULL) - return NULL; - - skb = __build_skb(data, size); - if (skb == NULL) - vfree(data); - else - skb->destructor = netlink_skb_destructor; - - return skb; -} - -/* - * Attach a skb to a netlink socket. - * The caller must hold a reference to the destination socket. On error, the - * reference is dropped. The skb is not send to the destination, just all - * all error checks are performed and memory in the queue is reserved. - * Return values: - * < 0: error. skb freed, reference to sock dropped. - * 0: continue - * 1: repeat lookup - reference dropped while waiting for socket memory. - */ -int netlink_attachskb(struct sock *sk, struct sk_buff *skb, - long *timeo, struct sock *ssk) -{ - struct netlink_sock *nlk; - - nlk = nlk_sk(sk); - - if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || - test_bit(NETLINK_S_CONGESTED, &nlk->state))) { - DECLARE_WAITQUEUE(wait, current); - if (!*timeo) { - if (!ssk || netlink_is_kernel(ssk)) - netlink_overrun(sk); - sock_put(sk); - kfree_skb(skb); - return -EAGAIN; - } - - __set_current_state(TASK_INTERRUPTIBLE); - add_wait_queue(&nlk->wait, &wait); - - if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || - test_bit(NETLINK_S_CONGESTED, &nlk->state)) && - !sock_flag(sk, SOCK_DEAD)) - *timeo = schedule_timeout(*timeo); - - __set_current_state(TASK_RUNNING); - remove_wait_queue(&nlk->wait, &wait); - sock_put(sk); - - if (signal_pending(current)) { - kfree_skb(skb); - return sock_intr_errno(*timeo); - } - return 1; - } - netlink_skb_set_owner_r(skb, sk); - return 0; -} - -static int __netlink_sendskb(struct sock *sk, struct sk_buff *skb) -{ - int len = skb->len; - - netlink_deliver_tap(skb); - - skb_queue_tail(&sk->sk_receive_queue, skb); - sk->sk_data_ready(sk); - return len; -} - -int netlink_sendskb(struct sock *sk, struct sk_buff *skb) -{ - int len = __netlink_sendskb(sk, skb); - - sock_put(sk); - return len; -} - -void netlink_detachskb(struct sock *sk, struct sk_buff *skb) -{ - kfree_skb(skb); - sock_put(sk); -} - -static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation) -{ - int delta; - - WARN_ON(skb->sk != NULL); - delta = skb->end - skb->tail; - if (is_vmalloc_addr(skb->head) || delta * 2 < skb->truesize) - return skb; - - if (skb_shared(skb)) { - struct sk_buff *nskb = skb_clone(skb, allocation); - if (!nskb) - return skb; - consume_skb(skb); - skb = nskb; - } - - if (!pskb_expand_head(skb, 0, -delta, allocation)) - skb->truesize -= delta; - - return skb; -} - -static int netlink_unicast_kernel(struct sock *sk, struct sk_buff *skb, - struct sock *ssk) -{ - int ret; - struct netlink_sock *nlk = nlk_sk(sk); - - ret = -ECONNREFUSED; - if (nlk->netlink_rcv != NULL) { - ret = skb->len; - netlink_skb_set_owner_r(skb, sk); - NETLINK_CB(skb).sk = ssk; - netlink_deliver_tap_kernel(sk, ssk, skb); - nlk->netlink_rcv(skb); - consume_skb(skb); - } else { - kfree_skb(skb); - } - sock_put(sk); - return ret; -} - -int netlink_unicast(struct sock *ssk, struct sk_buff *skb, - u32 portid, int nonblock) -{ - struct sock *sk; - int err; - long timeo; - - skb = netlink_trim(skb, gfp_any()); - - timeo = sock_sndtimeo(ssk, nonblock); -retry: - sk = netlink_getsockbyportid(ssk, portid); - if (IS_ERR(sk)) { - kfree_skb(skb); - return PTR_ERR(sk); - } - if (netlink_is_kernel(sk)) - return netlink_unicast_kernel(sk, skb, ssk); - - if (sk_filter(sk, skb)) { - err = skb->len; - kfree_skb(skb); - sock_put(sk); - return err; - } - - err = netlink_attachskb(sk, skb, &timeo, ssk); - if (err == 1) - goto retry; - if (err) - return err; - - return netlink_sendskb(sk, skb); -} -EXPORT_SYMBOL(netlink_unicast); - -int netlink_has_listeners(struct sock *sk, unsigned int group) -{ - int res = 0; - struct listeners *listeners; - - BUG_ON(!netlink_is_kernel(sk)); - - rcu_read_lock(); - listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners); - - if (listeners && group - 1 < nl_table[sk->sk_protocol].groups) - res = test_bit(group - 1, listeners->masks); - - rcu_read_unlock(); - - return res; -} -EXPORT_SYMBOL_GPL(netlink_has_listeners); - -static int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb) -{ - struct netlink_sock *nlk = nlk_sk(sk); - - if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf && - !test_bit(NETLINK_S_CONGESTED, &nlk->state)) { - netlink_skb_set_owner_r(skb, sk); - __netlink_sendskb(sk, skb); - return atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf >> 1); - } - return -1; -} - -struct netlink_broadcast_data { - struct sock *exclude_sk; - struct net *net; - u32 portid; - u32 group; - int failure; - int delivery_failure; - int congested; - int delivered; - gfp_t allocation; - struct sk_buff *skb, *skb2; - int (*tx_filter)(struct sock *dsk, struct sk_buff *skb, void *data); - void *tx_data; -}; - -static void do_one_broadcast(struct sock *sk, - struct netlink_broadcast_data *p) -{ - struct netlink_sock *nlk = nlk_sk(sk); - int val; - - if (p->exclude_sk == sk) - return; - - if (nlk->portid == p->portid || p->group - 1 >= nlk->ngroups || - !test_bit(p->group - 1, nlk->groups)) - return; - - if (!net_eq(sock_net(sk), p->net)) { - if (!(nlk->flags & NETLINK_F_LISTEN_ALL_NSID)) - return; - - if (!peernet_has_id(sock_net(sk), p->net)) - return; - - if (!file_ns_capable(sk->sk_socket->file, p->net->user_ns, - CAP_NET_BROADCAST)) - return; - } - - if (p->failure) { - netlink_overrun(sk); - return; - } - - sock_hold(sk); - if (p->skb2 == NULL) { - if (skb_shared(p->skb)) { - p->skb2 = skb_clone(p->skb, p->allocation); - } else { - p->skb2 = skb_get(p->skb); - /* - * skb ownership may have been set when - * delivered to a previous socket. - */ - skb_orphan(p->skb2); - } - } - if (p->skb2 == NULL) { - netlink_overrun(sk); - /* Clone failed. Notify ALL listeners. */ - p->failure = 1; - if (nlk->flags & NETLINK_F_BROADCAST_SEND_ERROR) - p->delivery_failure = 1; - goto out; - } - if (p->tx_filter && p->tx_filter(sk, p->skb2, p->tx_data)) { - kfree_skb(p->skb2); - p->skb2 = NULL; - goto out; - } - if (sk_filter(sk, p->skb2)) { - kfree_skb(p->skb2); - p->skb2 = NULL; - goto out; - } - NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); - NETLINK_CB(p->skb2).nsid_is_set = true; - val = netlink_broadcast_deliver(sk, p->skb2); - if (val < 0) { - netlink_overrun(sk); - if (nlk->flags & NETLINK_F_BROADCAST_SEND_ERROR) - p->delivery_failure = 1; - } else { - p->congested |= val; - p->delivered = 1; - p->skb2 = NULL; - } -out: - sock_put(sk); -} - -int netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb, u32 portid, - u32 group, gfp_t allocation, - int (*filter)(struct sock *dsk, struct sk_buff *skb, void *data), - void *filter_data) -{ - struct net *net = sock_net(ssk); - struct netlink_broadcast_data info; - struct sock *sk; - - skb = netlink_trim(skb, allocation); - - info.exclude_sk = ssk; - info.net = net; - info.portid = portid; - info.group = group; - info.failure = 0; - info.delivery_failure = 0; - info.congested = 0; - info.delivered = 0; - info.allocation = allocation; - info.skb = skb; - info.skb2 = NULL; - info.tx_filter = filter; - info.tx_data = filter_data; - - /* While we sleep in clone, do not allow to change socket list */ - - netlink_lock_table(); - - sk_for_each_bound(sk, &nl_table[ssk->sk_protocol].mc_list) - do_one_broadcast(sk, &info); - - consume_skb(skb); - - netlink_unlock_table(); - - if (info.delivery_failure) { - kfree_skb(info.skb2); - return -ENOBUFS; - } - consume_skb(info.skb2); - - if (info.delivered) { - if (info.congested && gfpflags_allow_blocking(allocation)) - yield(); - return 0; - } - return -ESRCH; -} -EXPORT_SYMBOL(netlink_broadcast_filtered); - -int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 portid, - u32 group, gfp_t allocation) -{ - return netlink_broadcast_filtered(ssk, skb, portid, group, allocation, - NULL, NULL); -} -EXPORT_SYMBOL(netlink_broadcast); - -struct netlink_set_err_data { - struct sock *exclude_sk; - u32 portid; - u32 group; - int code; -}; - -static int do_one_set_err(struct sock *sk, struct netlink_set_err_data *p) -{ - struct netlink_sock *nlk = nlk_sk(sk); - int ret = 0; - - if (sk == p->exclude_sk) - goto out; - - if (!net_eq(sock_net(sk), sock_net(p->exclude_sk))) - goto out; - - if (nlk->portid == p->portid || p->group - 1 >= nlk->ngroups || - !test_bit(p->group - 1, nlk->groups)) - goto out; - - if (p->code == ENOBUFS && nlk->flags & NETLINK_F_RECV_NO_ENOBUFS) { - ret = 1; - goto out; - } - - sk->sk_err = p->code; - sk->sk_error_report(sk); -out: - return ret; -} - -/** - * netlink_set_err - report error to broadcast listeners - * @ssk: the kernel netlink socket, as returned by netlink_kernel_create() - * @portid: the PORTID of a process that we want to skip (if any) - * @group: the broadcast group that will notice the error - * @code: error code, must be negative (as usual in kernelspace) - * - * This function returns the number of broadcast listeners that have set the - * NETLINK_NO_ENOBUFS socket option. - */ -int netlink_set_err(struct sock *ssk, u32 portid, u32 group, int code) -{ - struct netlink_set_err_data info; - struct sock *sk; - int ret = 0; - - info.exclude_sk = ssk; - info.portid = portid; - info.group = group; - /* sk->sk_err wants a positive error value */ - info.code = -code; - - read_lock(&nl_table_lock); - - sk_for_each_bound(sk, &nl_table[ssk->sk_protocol].mc_list) - ret += do_one_set_err(sk, &info); - - read_unlock(&nl_table_lock); - return ret; -} -EXPORT_SYMBOL(netlink_set_err); - -/* must be called with netlink table grabbed */ -static void netlink_update_socket_mc(struct netlink_sock *nlk, - unsigned int group, - int is_new) -{ - int old, new = !!is_new, subscriptions; - - old = test_bit(group - 1, nlk->groups); - subscriptions = nlk->subscriptions - old + new; - if (new) - __set_bit(group - 1, nlk->groups); - else - __clear_bit(group - 1, nlk->groups); - netlink_update_subscriptions(&nlk->sk, subscriptions); - netlink_update_listeners(&nlk->sk); -} - -static int netlink_setsockopt(struct socket *sock, int level, int optname, - char __user *optval, unsigned int optlen) -{ - struct sock *sk = sock->sk; - struct netlink_sock *nlk = nlk_sk(sk); - unsigned int val = 0; - int err; - - if (level != SOL_NETLINK) - return -ENOPROTOOPT; - - if (optlen >= sizeof(int) && - get_user(val, (unsigned int __user *)optval)) - return -EFAULT; - - switch (optname) { - case NETLINK_PKTINFO: - if (val) - nlk->flags |= NETLINK_F_RECV_PKTINFO; - else - nlk->flags &= ~NETLINK_F_RECV_PKTINFO; - err = 0; - break; - case NETLINK_ADD_MEMBERSHIP: - case NETLINK_DROP_MEMBERSHIP: { - if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV)) - return -EPERM; - err = netlink_realloc_groups(sk); - if (err) - return err; - if (!val || val - 1 >= nlk->ngroups) - return -EINVAL; - if (optname == NETLINK_ADD_MEMBERSHIP && nlk->netlink_bind) { - err = nlk->netlink_bind(sock_net(sk), val); - if (err) - return err; - } - netlink_table_grab(); - netlink_update_socket_mc(nlk, val, - optname == NETLINK_ADD_MEMBERSHIP); - netlink_table_ungrab(); - if (optname == NETLINK_DROP_MEMBERSHIP && nlk->netlink_unbind) - nlk->netlink_unbind(sock_net(sk), val); - - err = 0; - break; - } - case NETLINK_BROADCAST_ERROR: - if (val) - nlk->flags |= NETLINK_F_BROADCAST_SEND_ERROR; - else - nlk->flags &= ~NETLINK_F_BROADCAST_SEND_ERROR; - err = 0; - break; - case NETLINK_NO_ENOBUFS: - if (val) { - nlk->flags |= NETLINK_F_RECV_NO_ENOBUFS; - clear_bit(NETLINK_S_CONGESTED, &nlk->state); - wake_up_interruptible(&nlk->wait); - } else { - nlk->flags &= ~NETLINK_F_RECV_NO_ENOBUFS; - } - err = 0; - break; - case NETLINK_LISTEN_ALL_NSID: - if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_BROADCAST)) - return -EPERM; - - if (val) - nlk->flags |= NETLINK_F_LISTEN_ALL_NSID; - else - nlk->flags &= ~NETLINK_F_LISTEN_ALL_NSID; - err = 0; - break; - case NETLINK_CAP_ACK: - if (val) - nlk->flags |= NETLINK_F_CAP_ACK; - else - nlk->flags &= ~NETLINK_F_CAP_ACK; - err = 0; - break; - default: - err = -ENOPROTOOPT; - } - return err; -} - -static int netlink_getsockopt(struct socket *sock, int level, int optname, - char __user *optval, int __user *optlen) -{ - struct sock *sk = sock->sk; - struct netlink_sock *nlk = nlk_sk(sk); - int len, val, err; - - if (level != SOL_NETLINK) - return -ENOPROTOOPT; - - if (get_user(len, optlen)) - return -EFAULT; - if (len < 0) - return -EINVAL; - - switch (optname) { - case NETLINK_PKTINFO: - if (len < sizeof(int)) - return -EINVAL; - len = sizeof(int); - val = nlk->flags & NETLINK_F_RECV_PKTINFO ? 1 : 0; - if (put_user(len, optlen) || - put_user(val, optval)) - return -EFAULT; - err = 0; - break; - case NETLINK_BROADCAST_ERROR: - if (len < sizeof(int)) - return -EINVAL; - len = sizeof(int); - val = nlk->flags & NETLINK_F_BROADCAST_SEND_ERROR ? 1 : 0; - if (put_user(len, optlen) || - put_user(val, optval)) - return -EFAULT; - err = 0; - break; - case NETLINK_NO_ENOBUFS: - if (len < sizeof(int)) - return -EINVAL; - len = sizeof(int); - val = nlk->flags & NETLINK_F_RECV_NO_ENOBUFS ? 1 : 0; - if (put_user(len, optlen) || - put_user(val, optval)) - return -EFAULT; - err = 0; - break; - case NETLINK_LIST_MEMBERSHIPS: { - int pos, idx, shift; - - err = 0; - netlink_lock_table(); - for (pos = 0; pos * 8 < nlk->ngroups; pos += sizeof(u32)) { - if (len - pos < sizeof(u32)) - break; - - idx = pos / sizeof(unsigned long); - shift = (pos % sizeof(unsigned long)) * 8; - if (put_user((u32)(nlk->groups[idx] >> shift), - (u32 __user *)(optval + pos))) { - err = -EFAULT; - break; - } - } - if (put_user(ALIGN(nlk->ngroups / 8, sizeof(u32)), optlen)) - err = -EFAULT; - netlink_unlock_table(); - break; - } - case NETLINK_CAP_ACK: - if (len < sizeof(int)) - return -EINVAL; - len = sizeof(int); - val = nlk->flags & NETLINK_F_CAP_ACK ? 1 : 0; - if (put_user(len, optlen) || - put_user(val, optval)) - return -EFAULT; - err = 0; - break; - default: - err = -ENOPROTOOPT; - } - return err; -} - -static void netlink_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) -{ - struct nl_pktinfo info; - - info.group = NETLINK_CB(skb).dst_group; - put_cmsg(msg, SOL_NETLINK, NETLINK_PKTINFO, sizeof(info), &info); -} - -static void netlink_cmsg_listen_all_nsid(struct sock *sk, struct msghdr *msg, - struct sk_buff *skb) -{ - if (!NETLINK_CB(skb).nsid_is_set) - return; - - put_cmsg(msg, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, sizeof(int), - &NETLINK_CB(skb).nsid); -} - -static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) -{ - struct sock *sk = sock->sk; - struct netlink_sock *nlk = nlk_sk(sk); - DECLARE_SOCKADDR(struct sockaddr_nl *, addr, msg->msg_name); - u32 dst_portid; - u32 dst_group; - struct sk_buff *skb; - int err; - struct scm_cookie scm; - u32 netlink_skb_flags = 0; - - if (msg->msg_flags&MSG_OOB) - return -EOPNOTSUPP; - - err = scm_send(sock, msg, &scm, true); - if (err < 0) - return err; - - if (msg->msg_namelen) { - err = -EINVAL; - if (addr->nl_family != AF_NETLINK) - goto out; - dst_portid = addr->nl_pid; - dst_group = ffs(addr->nl_groups); - err = -EPERM; - if ((dst_group || dst_portid) && - !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) - goto out; - netlink_skb_flags |= NETLINK_SKB_DST; - } else { - dst_portid = nlk->dst_portid; - dst_group = nlk->dst_group; - } - - if (!nlk->bound) { - err = netlink_autobind(sock); - if (err) - goto out; - } else { - /* Ensure nlk is hashed and visible. */ - smp_rmb(); - } - - err = -EMSGSIZE; - if (len > sk->sk_sndbuf - 32) - goto out; - err = -ENOBUFS; - skb = netlink_alloc_large_skb(len, dst_group); - if (skb == NULL) - goto out; - - NETLINK_CB(skb).portid = nlk->portid; - NETLINK_CB(skb).dst_group = dst_group; - NETLINK_CB(skb).creds = scm.creds; - NETLINK_CB(skb).flags = netlink_skb_flags; - - err = -EFAULT; - if (memcpy_from_msg(skb_put(skb, len), msg, len)) { - kfree_skb(skb); - goto out; - } - - err = security_netlink_send(sk, skb); - if (err) { - kfree_skb(skb); - goto out; - } - - if (dst_group) { - atomic_inc(&skb->users); - netlink_broadcast(sk, skb, dst_portid, dst_group, GFP_KERNEL); - } - err = netlink_unicast(sk, skb, dst_portid, msg->msg_flags&MSG_DONTWAIT); - -out: - scm_destroy(&scm); - return err; -} - -static int netlink_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, - int flags) -{ - struct scm_cookie scm; - struct sock *sk = sock->sk; - struct netlink_sock *nlk = nlk_sk(sk); - int noblock = flags&MSG_DONTWAIT; - size_t copied; - struct sk_buff *skb, *data_skb; - int err, ret; - - if (flags&MSG_OOB) - return -EOPNOTSUPP; - - copied = 0; - - skb = skb_recv_datagram(sk, flags, noblock, &err); - if (skb == NULL) - goto out; - - data_skb = skb; - -#ifdef CONFIG_COMPAT_NETLINK_MESSAGES - if (unlikely(skb_shinfo(skb)->frag_list)) { - /* - * If this skb has a frag_list, then here that means that we - * will have to use the frag_list skb's data for compat tasks - * and the regular skb's data for normal (non-compat) tasks. - * - * If we need to send the compat skb, assign it to the - * 'data_skb' variable so that it will be used below for data - * copying. We keep 'skb' for everything else, including - * freeing both later. - */ - if (flags & MSG_CMSG_COMPAT) - data_skb = skb_shinfo(skb)->frag_list; - } -#endif - - /* Record the max length of recvmsg() calls for future allocations */ - nlk->max_recvmsg_len = max(nlk->max_recvmsg_len, len); - nlk->max_recvmsg_len = min_t(size_t, nlk->max_recvmsg_len, - SKB_WITH_OVERHEAD(32768)); - - copied = data_skb->len; - if (len < copied) { - msg->msg_flags |= MSG_TRUNC; - copied = len; - } - - skb_reset_transport_header(data_skb); - err = skb_copy_datagram_msg(data_skb, 0, msg, copied); - - if (msg->msg_name) { - DECLARE_SOCKADDR(struct sockaddr_nl *, addr, msg->msg_name); - addr->nl_family = AF_NETLINK; - addr->nl_pad = 0; - addr->nl_pid = NETLINK_CB(skb).portid; - addr->nl_groups = netlink_group_mask(NETLINK_CB(skb).dst_group); - msg->msg_namelen = sizeof(*addr); - } - - if (nlk->flags & NETLINK_F_RECV_PKTINFO) - netlink_cmsg_recv_pktinfo(msg, skb); - if (nlk->flags & NETLINK_F_LISTEN_ALL_NSID) - netlink_cmsg_listen_all_nsid(sk, msg, skb); - - memset(&scm, 0, sizeof(scm)); - scm.creds = *NETLINK_CREDS(skb); - if (flags & MSG_TRUNC) - copied = data_skb->len; - - skb_free_datagram(sk, skb); - - if (nlk->cb_running && - atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) { - ret = netlink_dump(sk); - if (ret) { - sk->sk_err = -ret; - sk->sk_error_report(sk); - } - } - - scm_recv(sock, msg, &scm, flags); -out: - netlink_rcv_wake(sk); - return err ? : copied; -} - -static void netlink_data_ready(struct sock *sk) -{ - BUG(); -} - -/* - * We export these functions to other modules. They provide a - * complete set of kernel non-blocking support for message - * queueing. - */ - -struct sock * -__netlink_kernel_create(struct net *net, int unit, struct module *module, - struct netlink_kernel_cfg *cfg) -{ - struct socket *sock; - struct sock *sk; - struct netlink_sock *nlk; - struct listeners *listeners = NULL; - struct mutex *cb_mutex = cfg ? cfg->cb_mutex : NULL; - unsigned int groups; - - BUG_ON(!nl_table); - - if (unit < 0 || unit >= MAX_LINKS) - return NULL; - - if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) - return NULL; - - if (__netlink_create(net, sock, cb_mutex, unit, 1) < 0) - goto out_sock_release_nosk; - - sk = sock->sk; - - if (!cfg || cfg->groups < 32) - groups = 32; - else - groups = cfg->groups; - - listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL); - if (!listeners) - goto out_sock_release; - - sk->sk_data_ready = netlink_data_ready; - if (cfg && cfg->input) - nlk_sk(sk)->netlink_rcv = cfg->input; - - if (netlink_insert(sk, 0)) - goto out_sock_release; - - nlk = nlk_sk(sk); - nlk->flags |= NETLINK_F_KERNEL_SOCKET; - - netlink_table_grab(); - if (!nl_table[unit].registered) { - nl_table[unit].groups = groups; - rcu_assign_pointer(nl_table[unit].listeners, listeners); - nl_table[unit].cb_mutex = cb_mutex; - nl_table[unit].module = module; - if (cfg) { - nl_table[unit].bind = cfg->bind; - nl_table[unit].unbind = cfg->unbind; - nl_table[unit].flags = cfg->flags; - if (cfg->compare) - nl_table[unit].compare = cfg->compare; - } - nl_table[unit].registered = 1; - } else { - kfree(listeners); - nl_table[unit].registered++; - } - netlink_table_ungrab(); - return sk; - -out_sock_release: - kfree(listeners); - netlink_kernel_release(sk); - return NULL; - -out_sock_release_nosk: - sock_release(sock); - return NULL; -} -EXPORT_SYMBOL(__netlink_kernel_create); - -void -netlink_kernel_release(struct sock *sk) -{ - if (sk == NULL || sk->sk_socket == NULL) - return; - - sock_release(sk->sk_socket); -} -EXPORT_SYMBOL(netlink_kernel_release); - -int __netlink_change_ngroups(struct sock *sk, unsigned int groups) -{ - struct listeners *new, *old; - struct netlink_table *tbl = &nl_table[sk->sk_protocol]; - - if (groups < 32) - groups = 32; - - if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) { - new = kzalloc(sizeof(*new) + NLGRPSZ(groups), GFP_ATOMIC); - if (!new) - return -ENOMEM; - old = nl_deref_protected(tbl->listeners); - memcpy(new->masks, old->masks, NLGRPSZ(tbl->groups)); - rcu_assign_pointer(tbl->listeners, new); - - kfree_rcu(old, rcu); - } - tbl->groups = groups; - - return 0; -} - -/** - * netlink_change_ngroups - change number of multicast groups - * - * This changes the number of multicast groups that are available - * on a certain netlink family. Note that it is not possible to - * change the number of groups to below 32. Also note that it does - * not implicitly call netlink_clear_multicast_users() when the - * number of groups is reduced. - * - * @sk: The kernel netlink socket, as returned by netlink_kernel_create(). - * @groups: The new number of groups. - */ -int netlink_change_ngroups(struct sock *sk, unsigned int groups) -{ - int err; - - netlink_table_grab(); - err = __netlink_change_ngroups(sk, groups); - netlink_table_ungrab(); - - return err; -} - -void __netlink_clear_multicast_users(struct sock *ksk, unsigned int group) -{ - struct sock *sk; - struct netlink_table *tbl = &nl_table[ksk->sk_protocol]; - - sk_for_each_bound(sk, &tbl->mc_list) - netlink_update_socket_mc(nlk_sk(sk), group, 0); -} - -struct nlmsghdr * -__nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int len, int flags) -{ - struct nlmsghdr *nlh; - int size = nlmsg_msg_size(len); - - nlh = (struct nlmsghdr *)skb_put(skb, NLMSG_ALIGN(size)); - nlh->nlmsg_type = type; - nlh->nlmsg_len = size; - nlh->nlmsg_flags = flags; - nlh->nlmsg_pid = portid; - nlh->nlmsg_seq = seq; - if (!__builtin_constant_p(size) || NLMSG_ALIGN(size) - size != 0) - memset(nlmsg_data(nlh) + len, 0, NLMSG_ALIGN(size) - size); - return nlh; -} -EXPORT_SYMBOL(__nlmsg_put); - -/* - * It looks a bit ugly. - * It would be better to create kernel thread. - */ - -static int netlink_dump(struct sock *sk) -{ - struct netlink_sock *nlk = nlk_sk(sk); - struct netlink_callback *cb; - struct sk_buff *skb = NULL; - struct nlmsghdr *nlh; - struct module *module; - int len, err = -ENOBUFS; - int alloc_min_size; - int alloc_size; - - mutex_lock(nlk->cb_mutex); - if (!nlk->cb_running) { - err = -EINVAL; - goto errout_skb; - } - - if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) - goto errout_skb; - - /* NLMSG_GOODSIZE is small to avoid high order allocations being - * required, but it makes sense to _attempt_ a 16K bytes allocation - * to reduce number of system calls on dump operations, if user - * ever provided a big enough buffer. - */ - cb = &nlk->cb; - alloc_min_size = max_t(int, cb->min_dump_alloc, NLMSG_GOODSIZE); - - if (alloc_min_size < nlk->max_recvmsg_len) { - alloc_size = nlk->max_recvmsg_len; - skb = alloc_skb(alloc_size, - (GFP_KERNEL & ~__GFP_DIRECT_RECLAIM) | - __GFP_NOWARN | __GFP_NORETRY); - } - if (!skb) { - alloc_size = alloc_min_size; - skb = alloc_skb(alloc_size, GFP_KERNEL); - } - if (!skb) - goto errout_skb; - - /* Trim skb to allocated size. User is expected to provide buffer as - * large as max(min_dump_alloc, 16KiB (mac_recvmsg_len capped at - * netlink_recvmsg())). dump will pack as many smaller messages as - * could fit within the allocated skb. skb is typically allocated - * with larger space than required (could be as much as near 2x the - * requested size with align to next power of 2 approach). Allowing - * dump to use the excess space makes it difficult for a user to have a - * reasonable static buffer based on the expected largest dump of a - * single netdev. The outcome is MSG_TRUNC error. - */ - skb_reserve(skb, skb_tailroom(skb) - alloc_size); - netlink_skb_set_owner_r(skb, sk); - - len = cb->dump(skb, cb); - - if (len > 0) { - mutex_unlock(nlk->cb_mutex); - - if (sk_filter(sk, skb)) - kfree_skb(skb); - else - __netlink_sendskb(sk, skb); - return 0; - } - - nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, sizeof(len), NLM_F_MULTI); - if (!nlh) - goto errout_skb; - - nl_dump_check_consistent(cb, nlh); - - memcpy(nlmsg_data(nlh), &len, sizeof(len)); - - if (sk_filter(sk, skb)) - kfree_skb(skb); - else - __netlink_sendskb(sk, skb); - - if (cb->done) - cb->done(cb); - - nlk->cb_running = false; - module = cb->module; - skb = cb->skb; - mutex_unlock(nlk->cb_mutex); - module_put(module); - consume_skb(skb); - return 0; - -errout_skb: - mutex_unlock(nlk->cb_mutex); - kfree_skb(skb); - return err; -} - -int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, - const struct nlmsghdr *nlh, - struct netlink_dump_control *control) -{ - struct netlink_callback *cb; - struct sock *sk; - struct netlink_sock *nlk; - int ret; - - atomic_inc(&skb->users); - - sk = netlink_lookup(sock_net(ssk), ssk->sk_protocol, NETLINK_CB(skb).portid); - if (sk == NULL) { - ret = -ECONNREFUSED; - goto error_free; - } - - nlk = nlk_sk(sk); - mutex_lock(nlk->cb_mutex); - /* A dump is in progress... */ - if (nlk->cb_running) { - ret = -EBUSY; - goto error_unlock; - } - /* add reference of module which cb->dump belongs to */ - if (!try_module_get(control->module)) { - ret = -EPROTONOSUPPORT; - goto error_unlock; - } - - cb = &nlk->cb; - memset(cb, 0, sizeof(*cb)); - cb->start = control->start; - cb->dump = control->dump; - cb->done = control->done; - cb->nlh = nlh; - cb->data = control->data; - cb->module = control->module; - cb->min_dump_alloc = control->min_dump_alloc; - cb->skb = skb; - - nlk->cb_running = true; - - mutex_unlock(nlk->cb_mutex); - - if (cb->start) - cb->start(cb); - - ret = netlink_dump(sk); - sock_put(sk); - - if (ret) - return ret; - - /* We successfully started a dump, by returning -EINTR we - * signal not to send ACK even if it was requested. - */ - return -EINTR; - -error_unlock: - sock_put(sk); - mutex_unlock(nlk->cb_mutex); -error_free: - kfree_skb(skb); - return ret; -} -EXPORT_SYMBOL(__netlink_dump_start); - -void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) -{ - struct sk_buff *skb; - struct nlmsghdr *rep; - struct nlmsgerr *errmsg; - size_t payload = sizeof(*errmsg); - struct netlink_sock *nlk = nlk_sk(NETLINK_CB(in_skb).sk); - - /* Error messages get the original request appened, unless the user - * requests to cap the error message. - */ - if (!(nlk->flags & NETLINK_F_CAP_ACK) && err) - payload += nlmsg_len(nlh); - - skb = nlmsg_new(payload, GFP_KERNEL); - if (!skb) { - struct sock *sk; - - sk = netlink_lookup(sock_net(in_skb->sk), - in_skb->sk->sk_protocol, - NETLINK_CB(in_skb).portid); - if (sk) { - sk->sk_err = ENOBUFS; - sk->sk_error_report(sk); - sock_put(sk); - } - return; - } - - rep = __nlmsg_put(skb, NETLINK_CB(in_skb).portid, nlh->nlmsg_seq, - NLMSG_ERROR, payload, 0); - errmsg = nlmsg_data(rep); - errmsg->error = err; - memcpy(&errmsg->msg, nlh, payload > sizeof(*errmsg) ? nlh->nlmsg_len : sizeof(*nlh)); - netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid, MSG_DONTWAIT); -} -EXPORT_SYMBOL(netlink_ack); - -int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, - struct nlmsghdr *)) -{ - struct nlmsghdr *nlh; - int err; - - while (skb->len >= nlmsg_total_size(0)) { - int msglen; - - nlh = nlmsg_hdr(skb); - err = 0; - - if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len) - return 0; - - /* Only requests are handled by the kernel */ - if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) - goto ack; - - /* Skip control messages */ - if (nlh->nlmsg_type < NLMSG_MIN_TYPE) - goto ack; - - err = cb(skb, nlh); - if (err == -EINTR) - goto skip; - -ack: - if (nlh->nlmsg_flags & NLM_F_ACK || err) - netlink_ack(skb, nlh, err); - -skip: - msglen = NLMSG_ALIGN(nlh->nlmsg_len); - if (msglen > skb->len) - msglen = skb->len; - skb_pull(skb, msglen); - } - - return 0; -} -EXPORT_SYMBOL(netlink_rcv_skb); - -/** - * nlmsg_notify - send a notification netlink message - * @sk: netlink socket to use - * @skb: notification message - * @portid: destination netlink portid for reports or 0 - * @group: destination multicast group or 0 - * @report: 1 to report back, 0 to disable - * @flags: allocation flags - */ -int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 portid, - unsigned int group, int report, gfp_t flags) -{ - int err = 0; - - if (group) { - int exclude_portid = 0; - - if (report) { - atomic_inc(&skb->users); - exclude_portid = portid; - } - - /* errors reported via destination sk->sk_err, but propagate - * delivery errors if NETLINK_BROADCAST_ERROR flag is set */ - err = nlmsg_multicast(sk, skb, exclude_portid, group, flags); - } - - if (report) { - int err2; - - err2 = nlmsg_unicast(sk, skb, portid); - if (!err || err == -ESRCH) - err = err2; - } - - return err; -} -EXPORT_SYMBOL(nlmsg_notify); - -#ifdef CONFIG_PROC_FS -struct nl_seq_iter { - struct seq_net_private p; - struct rhashtable_iter hti; - int link; -}; - -static int netlink_walk_start(struct nl_seq_iter *iter) -{ - int err; - - err = rhashtable_walk_init(&nl_table[iter->link].hash, &iter->hti, - GFP_KERNEL); - if (err) { - iter->link = MAX_LINKS; - return err; - } - - err = rhashtable_walk_start(&iter->hti); - return err == -EAGAIN ? 0 : err; -} - -static void netlink_walk_stop(struct nl_seq_iter *iter) -{ - rhashtable_walk_stop(&iter->hti); - rhashtable_walk_exit(&iter->hti); -} - -static void *__netlink_seq_next(struct seq_file *seq) -{ - struct nl_seq_iter *iter = seq->private; - struct netlink_sock *nlk; - - do { - for (;;) { - int err; - - nlk = rhashtable_walk_next(&iter->hti); - - if (IS_ERR(nlk)) { - if (PTR_ERR(nlk) == -EAGAIN) - continue; - - return nlk; - } - - if (nlk) - break; - - netlink_walk_stop(iter); - if (++iter->link >= MAX_LINKS) - return NULL; - - err = netlink_walk_start(iter); - if (err) - return ERR_PTR(err); - } - } while (sock_net(&nlk->sk) != seq_file_net(seq)); - - return nlk; -} - -static void *netlink_seq_start(struct seq_file *seq, loff_t *posp) -{ - struct nl_seq_iter *iter = seq->private; - void *obj = SEQ_START_TOKEN; - loff_t pos; - int err; - - iter->link = 0; - - err = netlink_walk_start(iter); - if (err) - return ERR_PTR(err); - - for (pos = *posp; pos && obj && !IS_ERR(obj); pos--) - obj = __netlink_seq_next(seq); - - return obj; -} - -static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) -{ - ++*pos; - return __netlink_seq_next(seq); -} - -static void netlink_seq_stop(struct seq_file *seq, void *v) -{ - struct nl_seq_iter *iter = seq->private; - - if (iter->link >= MAX_LINKS) - return; - - netlink_walk_stop(iter); -} - - -static int netlink_seq_show(struct seq_file *seq, void *v) -{ - if (v == SEQ_START_TOKEN) { - seq_puts(seq, - "sk Eth Pid Groups " - "Rmem Wmem Dump Locks Drops Inode\n"); - } else { - struct sock *s = v; - struct netlink_sock *nlk = nlk_sk(s); - - seq_printf(seq, "%pK %-3d %-6u %08x %-8d %-8d %d %-8d %-8d %-8lu\n", - s, - s->sk_protocol, - nlk->portid, - nlk->groups ? (u32)nlk->groups[0] : 0, - sk_rmem_alloc_get(s), - sk_wmem_alloc_get(s), - nlk->cb_running, - atomic_read(&s->sk_refcnt), - atomic_read(&s->sk_drops), - sock_i_ino(s) - ); - - } - return 0; -} - -static const struct seq_operations netlink_seq_ops = { - .start = netlink_seq_start, - .next = netlink_seq_next, - .stop = netlink_seq_stop, - .show = netlink_seq_show, -}; - - -static int netlink_seq_open(struct inode *inode, struct file *file) -{ - return seq_open_net(inode, file, &netlink_seq_ops, - sizeof(struct nl_seq_iter)); -} - -static const struct file_operations netlink_seq_fops = { - .owner = THIS_MODULE, - .open = netlink_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = seq_release_net, -}; - -#endif - -int netlink_register_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_register(&netlink_chain, nb); -} -EXPORT_SYMBOL(netlink_register_notifier); - -int netlink_unregister_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&netlink_chain, nb); -} -EXPORT_SYMBOL(netlink_unregister_notifier); - -static const struct proto_ops netlink_ops = { - .family = PF_NETLINK, - .owner = THIS_MODULE, - .release = netlink_release, - .bind = netlink_bind, - .connect = netlink_connect, - .socketpair = sock_no_socketpair, - .accept = sock_no_accept, - .getname = netlink_getname, - .poll = datagram_poll, - .ioctl = netlink_ioctl, - .listen = sock_no_listen, - .shutdown = sock_no_shutdown, - .setsockopt = netlink_setsockopt, - .getsockopt = netlink_getsockopt, - .sendmsg = netlink_sendmsg, - .recvmsg = netlink_recvmsg, - .mmap = sock_no_mmap, - .sendpage = sock_no_sendpage, -}; - -static const struct net_proto_family netlink_family_ops = { - .family = PF_NETLINK, - .create = netlink_create, - .owner = THIS_MODULE, /* for consistency 8) */ -}; - -static int __net_init netlink_net_init(struct net *net) -{ -#ifdef CONFIG_PROC_FS - if (!proc_create("netlink", 0, net->proc_net, &netlink_seq_fops)) - return -ENOMEM; -#endif - return 0; -} - -static void __net_exit netlink_net_exit(struct net *net) -{ -#ifdef CONFIG_PROC_FS - remove_proc_entry("netlink", net->proc_net); -#endif -} - -static void __init netlink_add_usersock_entry(void) -{ - struct listeners *listeners; - int groups = 32; - - listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL); - if (!listeners) - panic("netlink_add_usersock_entry: Cannot allocate listeners\n"); - - netlink_table_grab(); - - nl_table[NETLINK_USERSOCK].groups = groups; - rcu_assign_pointer(nl_table[NETLINK_USERSOCK].listeners, listeners); - nl_table[NETLINK_USERSOCK].module = THIS_MODULE; - nl_table[NETLINK_USERSOCK].registered = 1; - nl_table[NETLINK_USERSOCK].flags = NL_CFG_F_NONROOT_SEND; - - netlink_table_ungrab(); -} - -static struct pernet_operations __net_initdata netlink_net_ops = { - .init = netlink_net_init, - .exit = netlink_net_exit, -}; - -static inline u32 netlink_hash(const void *data, u32 len, u32 seed) -{ - const struct netlink_sock *nlk = data; - struct netlink_compare_arg arg; - - netlink_compare_arg_init(&arg, sock_net(&nlk->sk), nlk->portid); - return jhash2((u32 *)&arg, netlink_compare_arg_len / sizeof(u32), seed); -} - -static const struct rhashtable_params netlink_rhashtable_params = { - .head_offset = offsetof(struct netlink_sock, node), - .key_len = netlink_compare_arg_len, - .obj_hashfn = netlink_hash, - .obj_cmpfn = netlink_compare, - .automatic_shrinking = true, -}; - -static int __init netlink_proto_init(void) -{ - int i; - int err = proto_register(&netlink_proto, 0); - - if (err != 0) - goto out; - - BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > FIELD_SIZEOF(struct sk_buff, cb)); - - nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL); - if (!nl_table) - goto panic; - - for (i = 0; i < MAX_LINKS; i++) { - if (rhashtable_init(&nl_table[i].hash, - &netlink_rhashtable_params) < 0) { - while (--i > 0) - rhashtable_destroy(&nl_table[i].hash); - kfree(nl_table); - goto panic; - } - } - - INIT_LIST_HEAD(&netlink_tap_all); - - netlink_add_usersock_entry(); - - sock_register(&netlink_family_ops); - register_pernet_subsys(&netlink_net_ops); - /* The netlink device handler may be needed early. */ - rtnetlink_init(); -out: - return err; -panic: - panic("netlink_init: Cannot allocate nl_table\n"); -} - -core_initcall(netlink_proto_init); diff --git a/src/linux/net/netlink/af_netlink.h b/src/linux/net/netlink/af_netlink.h deleted file mode 100644 index 4fdb383..0000000 --- a/src/linux/net/netlink/af_netlink.h +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef _AF_NETLINK_H -#define _AF_NETLINK_H - -#include -#include -#include -#include - -#define NLGRPSZ(x) (ALIGN(x, sizeof(unsigned long) * 8) / 8) -#define NLGRPLONGS(x) (NLGRPSZ(x)/sizeof(unsigned long)) - -struct netlink_sock { - /* struct sock has to be the first member of netlink_sock */ - struct sock sk; - u32 portid; - u32 dst_portid; - u32 dst_group; - u32 flags; - u32 subscriptions; - u32 ngroups; - unsigned long *groups; - unsigned long state; - size_t max_recvmsg_len; - wait_queue_head_t wait; - bool bound; - bool cb_running; - struct netlink_callback cb; - struct mutex *cb_mutex; - struct mutex cb_def_mutex; - void (*netlink_rcv)(struct sk_buff *skb); - int (*netlink_bind)(struct net *net, int group); - void (*netlink_unbind)(struct net *net, int group); - struct module *module; - - struct rhash_head node; - struct rcu_head rcu; - struct work_struct work; -}; - -static inline struct netlink_sock *nlk_sk(struct sock *sk) -{ - return container_of(sk, struct netlink_sock, sk); -} - -struct netlink_table { - struct rhashtable hash; - struct hlist_head mc_list; - struct listeners __rcu *listeners; - unsigned int flags; - unsigned int groups; - struct mutex *cb_mutex; - struct module *module; - int (*bind)(struct net *net, int group); - void (*unbind)(struct net *net, int group); - bool (*compare)(struct net *net, struct sock *sock); - int registered; -}; - -extern struct netlink_table *nl_table; -extern rwlock_t nl_table_lock; - -#endif diff --git a/src/linux/net/netlink/genetlink.c b/src/linux/net/netlink/genetlink.c deleted file mode 100644 index 49c28e8..0000000 --- a/src/linux/net/netlink/genetlink.c +++ /dev/null @@ -1,1155 +0,0 @@ -/* - * NETLINK Generic Netlink Family - * - * Authors: Jamal Hadi Salim - * Thomas Graf - * Johannes Berg - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static DEFINE_MUTEX(genl_mutex); /* serialization of message processing */ -static DECLARE_RWSEM(cb_lock); - -atomic_t genl_sk_destructing_cnt = ATOMIC_INIT(0); -DECLARE_WAIT_QUEUE_HEAD(genl_sk_destructing_waitq); - -void genl_lock(void) -{ - mutex_lock(&genl_mutex); -} -EXPORT_SYMBOL(genl_lock); - -void genl_unlock(void) -{ - mutex_unlock(&genl_mutex); -} -EXPORT_SYMBOL(genl_unlock); - -#ifdef CONFIG_LOCKDEP -bool lockdep_genl_is_held(void) -{ - return lockdep_is_held(&genl_mutex); -} -EXPORT_SYMBOL(lockdep_genl_is_held); -#endif - -static void genl_lock_all(void) -{ - down_write(&cb_lock); - genl_lock(); -} - -static void genl_unlock_all(void) -{ - genl_unlock(); - up_write(&cb_lock); -} - -#define GENL_FAM_TAB_SIZE 16 -#define GENL_FAM_TAB_MASK (GENL_FAM_TAB_SIZE - 1) - -static struct list_head family_ht[GENL_FAM_TAB_SIZE]; -/* - * Bitmap of multicast groups that are currently in use. - * - * To avoid an allocation at boot of just one unsigned long, - * declare it global instead. - * Bit 0 is marked as already used since group 0 is invalid. - * Bit 1 is marked as already used since the drop-monitor code - * abuses the API and thinks it can statically use group 1. - * That group will typically conflict with other groups that - * any proper users use. - * Bit 16 is marked as used since it's used for generic netlink - * and the code no longer marks pre-reserved IDs as used. - * Bit 17 is marked as already used since the VFS quota code - * also abused this API and relied on family == group ID, we - * cater to that by giving it a static family and group ID. - * Bit 18 is marked as already used since the PMCRAID driver - * did the same thing as the VFS quota code (maybe copied?) - */ -static unsigned long mc_group_start = 0x3 | BIT(GENL_ID_CTRL) | - BIT(GENL_ID_VFS_DQUOT) | - BIT(GENL_ID_PMCRAID); -static unsigned long *mc_groups = &mc_group_start; -static unsigned long mc_groups_longs = 1; - -static int genl_ctrl_event(int event, struct genl_family *family, - const struct genl_multicast_group *grp, - int grp_id); - -static inline unsigned int genl_family_hash(unsigned int id) -{ - return id & GENL_FAM_TAB_MASK; -} - -static inline struct list_head *genl_family_chain(unsigned int id) -{ - return &family_ht[genl_family_hash(id)]; -} - -static struct genl_family *genl_family_find_byid(unsigned int id) -{ - struct genl_family *f; - - list_for_each_entry(f, genl_family_chain(id), family_list) - if (f->id == id) - return f; - - return NULL; -} - -static struct genl_family *genl_family_find_byname(char *name) -{ - struct genl_family *f; - int i; - - for (i = 0; i < GENL_FAM_TAB_SIZE; i++) - list_for_each_entry(f, genl_family_chain(i), family_list) - if (strcmp(f->name, name) == 0) - return f; - - return NULL; -} - -static const struct genl_ops *genl_get_cmd(u8 cmd, struct genl_family *family) -{ - int i; - - for (i = 0; i < family->n_ops; i++) - if (family->ops[i].cmd == cmd) - return &family->ops[i]; - - return NULL; -} - -/* Of course we are going to have problems once we hit - * 2^16 alive types, but that can only happen by year 2K -*/ -static u16 genl_generate_id(void) -{ - static u16 id_gen_idx = GENL_MIN_ID; - int i; - - for (i = 0; i <= GENL_MAX_ID - GENL_MIN_ID; i++) { - if (id_gen_idx != GENL_ID_VFS_DQUOT && - id_gen_idx != GENL_ID_PMCRAID && - !genl_family_find_byid(id_gen_idx)) - return id_gen_idx; - if (++id_gen_idx > GENL_MAX_ID) - id_gen_idx = GENL_MIN_ID; - } - - return 0; -} - -static int genl_allocate_reserve_groups(int n_groups, int *first_id) -{ - unsigned long *new_groups; - int start = 0; - int i; - int id; - bool fits; - - do { - if (start == 0) - id = find_first_zero_bit(mc_groups, - mc_groups_longs * - BITS_PER_LONG); - else - id = find_next_zero_bit(mc_groups, - mc_groups_longs * BITS_PER_LONG, - start); - - fits = true; - for (i = id; - i < min_t(int, id + n_groups, - mc_groups_longs * BITS_PER_LONG); - i++) { - if (test_bit(i, mc_groups)) { - start = i; - fits = false; - break; - } - } - - if (id + n_groups > mc_groups_longs * BITS_PER_LONG) { - unsigned long new_longs = mc_groups_longs + - BITS_TO_LONGS(n_groups); - size_t nlen = new_longs * sizeof(unsigned long); - - if (mc_groups == &mc_group_start) { - new_groups = kzalloc(nlen, GFP_KERNEL); - if (!new_groups) - return -ENOMEM; - mc_groups = new_groups; - *mc_groups = mc_group_start; - } else { - new_groups = krealloc(mc_groups, nlen, - GFP_KERNEL); - if (!new_groups) - return -ENOMEM; - mc_groups = new_groups; - for (i = 0; i < BITS_TO_LONGS(n_groups); i++) - mc_groups[mc_groups_longs + i] = 0; - } - mc_groups_longs = new_longs; - } - } while (!fits); - - for (i = id; i < id + n_groups; i++) - set_bit(i, mc_groups); - *first_id = id; - return 0; -} - -static struct genl_family genl_ctrl; - -static int genl_validate_assign_mc_groups(struct genl_family *family) -{ - int first_id; - int n_groups = family->n_mcgrps; - int err = 0, i; - bool groups_allocated = false; - - if (!n_groups) - return 0; - - for (i = 0; i < n_groups; i++) { - const struct genl_multicast_group *grp = &family->mcgrps[i]; - - if (WARN_ON(grp->name[0] == '\0')) - return -EINVAL; - if (WARN_ON(memchr(grp->name, '\0', GENL_NAMSIZ) == NULL)) - return -EINVAL; - } - - /* special-case our own group and hacks */ - if (family == &genl_ctrl) { - first_id = GENL_ID_CTRL; - BUG_ON(n_groups != 1); - } else if (strcmp(family->name, "NET_DM") == 0) { - first_id = 1; - BUG_ON(n_groups != 1); - } else if (family->id == GENL_ID_VFS_DQUOT) { - first_id = GENL_ID_VFS_DQUOT; - BUG_ON(n_groups != 1); - } else if (family->id == GENL_ID_PMCRAID) { - first_id = GENL_ID_PMCRAID; - BUG_ON(n_groups != 1); - } else { - groups_allocated = true; - err = genl_allocate_reserve_groups(n_groups, &first_id); - if (err) - return err; - } - - family->mcgrp_offset = first_id; - - /* if still initializing, can't and don't need to to realloc bitmaps */ - if (!init_net.genl_sock) - return 0; - - if (family->netnsok) { - struct net *net; - - netlink_table_grab(); - rcu_read_lock(); - for_each_net_rcu(net) { - err = __netlink_change_ngroups(net->genl_sock, - mc_groups_longs * BITS_PER_LONG); - if (err) { - /* - * No need to roll back, can only fail if - * memory allocation fails and then the - * number of _possible_ groups has been - * increased on some sockets which is ok. - */ - break; - } - } - rcu_read_unlock(); - netlink_table_ungrab(); - } else { - err = netlink_change_ngroups(init_net.genl_sock, - mc_groups_longs * BITS_PER_LONG); - } - - if (groups_allocated && err) { - for (i = 0; i < family->n_mcgrps; i++) - clear_bit(family->mcgrp_offset + i, mc_groups); - } - - return err; -} - -static void genl_unregister_mc_groups(struct genl_family *family) -{ - struct net *net; - int i; - - netlink_table_grab(); - rcu_read_lock(); - for_each_net_rcu(net) { - for (i = 0; i < family->n_mcgrps; i++) - __netlink_clear_multicast_users( - net->genl_sock, family->mcgrp_offset + i); - } - rcu_read_unlock(); - netlink_table_ungrab(); - - for (i = 0; i < family->n_mcgrps; i++) { - int grp_id = family->mcgrp_offset + i; - - if (grp_id != 1) - clear_bit(grp_id, mc_groups); - genl_ctrl_event(CTRL_CMD_DELMCAST_GRP, family, - &family->mcgrps[i], grp_id); - } -} - -static int genl_validate_ops(const struct genl_family *family) -{ - const struct genl_ops *ops = family->ops; - unsigned int n_ops = family->n_ops; - int i, j; - - if (WARN_ON(n_ops && !ops)) - return -EINVAL; - - if (!n_ops) - return 0; - - for (i = 0; i < n_ops; i++) { - if (ops[i].dumpit == NULL && ops[i].doit == NULL) - return -EINVAL; - for (j = i + 1; j < n_ops; j++) - if (ops[i].cmd == ops[j].cmd) - return -EINVAL; - } - - return 0; -} - -/** - * __genl_register_family - register a generic netlink family - * @family: generic netlink family - * - * Registers the specified family after validating it first. Only one - * family may be registered with the same family name or identifier. - * The family id may equal GENL_ID_GENERATE causing an unique id to - * be automatically generated and assigned. - * - * The family's ops array must already be assigned, you can use the - * genl_register_family_with_ops() helper function. - * - * Return 0 on success or a negative error code. - */ -int __genl_register_family(struct genl_family *family) -{ - int err = -EINVAL, i; - - if (family->id && family->id < GENL_MIN_ID) - goto errout; - - if (family->id > GENL_MAX_ID) - goto errout; - - err = genl_validate_ops(family); - if (err) - return err; - - genl_lock_all(); - - if (genl_family_find_byname(family->name)) { - err = -EEXIST; - goto errout_locked; - } - - if (family->id == GENL_ID_GENERATE) { - u16 newid = genl_generate_id(); - - if (!newid) { - err = -ENOMEM; - goto errout_locked; - } - - family->id = newid; - } else if (genl_family_find_byid(family->id)) { - err = -EEXIST; - goto errout_locked; - } - - if (family->maxattr && !family->parallel_ops) { - family->attrbuf = kmalloc((family->maxattr+1) * - sizeof(struct nlattr *), GFP_KERNEL); - if (family->attrbuf == NULL) { - err = -ENOMEM; - goto errout_locked; - } - } else - family->attrbuf = NULL; - - err = genl_validate_assign_mc_groups(family); - if (err) - goto errout_free; - - list_add_tail(&family->family_list, genl_family_chain(family->id)); - genl_unlock_all(); - - /* send all events */ - genl_ctrl_event(CTRL_CMD_NEWFAMILY, family, NULL, 0); - for (i = 0; i < family->n_mcgrps; i++) - genl_ctrl_event(CTRL_CMD_NEWMCAST_GRP, family, - &family->mcgrps[i], family->mcgrp_offset + i); - - return 0; - -errout_free: - kfree(family->attrbuf); -errout_locked: - genl_unlock_all(); -errout: - return err; -} -EXPORT_SYMBOL(__genl_register_family); - -/** - * genl_unregister_family - unregister generic netlink family - * @family: generic netlink family - * - * Unregisters the specified family. - * - * Returns 0 on success or a negative error code. - */ -int genl_unregister_family(struct genl_family *family) -{ - struct genl_family *rc; - - genl_lock_all(); - - list_for_each_entry(rc, genl_family_chain(family->id), family_list) { - if (family->id != rc->id || strcmp(rc->name, family->name)) - continue; - - genl_unregister_mc_groups(family); - - list_del(&rc->family_list); - family->n_ops = 0; - up_write(&cb_lock); - wait_event(genl_sk_destructing_waitq, - atomic_read(&genl_sk_destructing_cnt) == 0); - genl_unlock(); - - kfree(family->attrbuf); - genl_ctrl_event(CTRL_CMD_DELFAMILY, family, NULL, 0); - return 0; - } - - genl_unlock_all(); - - return -ENOENT; -} -EXPORT_SYMBOL(genl_unregister_family); - -/** - * genlmsg_put - Add generic netlink header to netlink message - * @skb: socket buffer holding the message - * @portid: netlink portid the message is addressed to - * @seq: sequence number (usually the one of the sender) - * @family: generic netlink family - * @flags: netlink message flags - * @cmd: generic netlink command - * - * Returns pointer to user specific header - */ -void *genlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, - struct genl_family *family, int flags, u8 cmd) -{ - struct nlmsghdr *nlh; - struct genlmsghdr *hdr; - - nlh = nlmsg_put(skb, portid, seq, family->id, GENL_HDRLEN + - family->hdrsize, flags); - if (nlh == NULL) - return NULL; - - hdr = nlmsg_data(nlh); - hdr->cmd = cmd; - hdr->version = family->version; - hdr->reserved = 0; - - return (char *) hdr + GENL_HDRLEN; -} -EXPORT_SYMBOL(genlmsg_put); - -static int genl_lock_start(struct netlink_callback *cb) -{ - /* our ops are always const - netlink API doesn't propagate that */ - const struct genl_ops *ops = cb->data; - int rc = 0; - - if (ops->start) { - genl_lock(); - rc = ops->start(cb); - genl_unlock(); - } - return rc; -} - -static int genl_lock_dumpit(struct sk_buff *skb, struct netlink_callback *cb) -{ - /* our ops are always const - netlink API doesn't propagate that */ - const struct genl_ops *ops = cb->data; - int rc; - - genl_lock(); - rc = ops->dumpit(skb, cb); - genl_unlock(); - return rc; -} - -static int genl_lock_done(struct netlink_callback *cb) -{ - /* our ops are always const - netlink API doesn't propagate that */ - const struct genl_ops *ops = cb->data; - int rc = 0; - - if (ops->done) { - genl_lock(); - rc = ops->done(cb); - genl_unlock(); - } - return rc; -} - -static int genl_family_rcv_msg(struct genl_family *family, - struct sk_buff *skb, - struct nlmsghdr *nlh) -{ - const struct genl_ops *ops; - struct net *net = sock_net(skb->sk); - struct genl_info info; - struct genlmsghdr *hdr = nlmsg_data(nlh); - struct nlattr **attrbuf; - int hdrlen, err; - - /* this family doesn't exist in this netns */ - if (!family->netnsok && !net_eq(net, &init_net)) - return -ENOENT; - - hdrlen = GENL_HDRLEN + family->hdrsize; - if (nlh->nlmsg_len < nlmsg_msg_size(hdrlen)) - return -EINVAL; - - ops = genl_get_cmd(hdr->cmd, family); - if (ops == NULL) - return -EOPNOTSUPP; - - if ((ops->flags & GENL_ADMIN_PERM) && - !netlink_capable(skb, CAP_NET_ADMIN)) - return -EPERM; - - if ((ops->flags & GENL_UNS_ADMIN_PERM) && - !netlink_ns_capable(skb, net->user_ns, CAP_NET_ADMIN)) - return -EPERM; - - if ((nlh->nlmsg_flags & NLM_F_DUMP) == NLM_F_DUMP) { - int rc; - - if (ops->dumpit == NULL) - return -EOPNOTSUPP; - - if (!family->parallel_ops) { - struct netlink_dump_control c = { - .module = family->module, - /* we have const, but the netlink API doesn't */ - .data = (void *)ops, - .start = genl_lock_start, - .dump = genl_lock_dumpit, - .done = genl_lock_done, - }; - - genl_unlock(); - rc = __netlink_dump_start(net->genl_sock, skb, nlh, &c); - genl_lock(); - - } else { - struct netlink_dump_control c = { - .module = family->module, - .start = ops->start, - .dump = ops->dumpit, - .done = ops->done, - }; - - rc = __netlink_dump_start(net->genl_sock, skb, nlh, &c); - } - - return rc; - } - - if (ops->doit == NULL) - return -EOPNOTSUPP; - - if (family->maxattr && family->parallel_ops) { - attrbuf = kmalloc((family->maxattr+1) * - sizeof(struct nlattr *), GFP_KERNEL); - if (attrbuf == NULL) - return -ENOMEM; - } else - attrbuf = family->attrbuf; - - if (attrbuf) { - err = nlmsg_parse(nlh, hdrlen, attrbuf, family->maxattr, - ops->policy); - if (err < 0) - goto out; - } - - info.snd_seq = nlh->nlmsg_seq; - info.snd_portid = NETLINK_CB(skb).portid; - info.nlhdr = nlh; - info.genlhdr = nlmsg_data(nlh); - info.userhdr = nlmsg_data(nlh) + GENL_HDRLEN; - info.attrs = attrbuf; - genl_info_net_set(&info, net); - memset(&info.user_ptr, 0, sizeof(info.user_ptr)); - - if (family->pre_doit) { - err = family->pre_doit(ops, skb, &info); - if (err) - goto out; - } - - err = ops->doit(skb, &info); - - if (family->post_doit) - family->post_doit(ops, skb, &info); - -out: - if (family->parallel_ops) - kfree(attrbuf); - - return err; -} - -static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) -{ - struct genl_family *family; - int err; - - family = genl_family_find_byid(nlh->nlmsg_type); - if (family == NULL) - return -ENOENT; - - if (!family->parallel_ops) - genl_lock(); - - err = genl_family_rcv_msg(family, skb, nlh); - - if (!family->parallel_ops) - genl_unlock(); - - return err; -} - -static void genl_rcv(struct sk_buff *skb) -{ - down_read(&cb_lock); - netlink_rcv_skb(skb, &genl_rcv_msg); - up_read(&cb_lock); -} - -/************************************************************************** - * Controller - **************************************************************************/ - -static struct genl_family genl_ctrl = { - .id = GENL_ID_CTRL, - .name = "nlctrl", - .version = 0x2, - .maxattr = CTRL_ATTR_MAX, - .netnsok = true, -}; - -static int ctrl_fill_info(struct genl_family *family, u32 portid, u32 seq, - u32 flags, struct sk_buff *skb, u8 cmd) -{ - void *hdr; - - hdr = genlmsg_put(skb, portid, seq, &genl_ctrl, flags, cmd); - if (hdr == NULL) - return -1; - - if (nla_put_string(skb, CTRL_ATTR_FAMILY_NAME, family->name) || - nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, family->id) || - nla_put_u32(skb, CTRL_ATTR_VERSION, family->version) || - nla_put_u32(skb, CTRL_ATTR_HDRSIZE, family->hdrsize) || - nla_put_u32(skb, CTRL_ATTR_MAXATTR, family->maxattr)) - goto nla_put_failure; - - if (family->n_ops) { - struct nlattr *nla_ops; - int i; - - nla_ops = nla_nest_start(skb, CTRL_ATTR_OPS); - if (nla_ops == NULL) - goto nla_put_failure; - - for (i = 0; i < family->n_ops; i++) { - struct nlattr *nest; - const struct genl_ops *ops = &family->ops[i]; - u32 op_flags = ops->flags; - - if (ops->dumpit) - op_flags |= GENL_CMD_CAP_DUMP; - if (ops->doit) - op_flags |= GENL_CMD_CAP_DO; - if (ops->policy) - op_flags |= GENL_CMD_CAP_HASPOL; - - nest = nla_nest_start(skb, i + 1); - if (nest == NULL) - goto nla_put_failure; - - if (nla_put_u32(skb, CTRL_ATTR_OP_ID, ops->cmd) || - nla_put_u32(skb, CTRL_ATTR_OP_FLAGS, op_flags)) - goto nla_put_failure; - - nla_nest_end(skb, nest); - } - - nla_nest_end(skb, nla_ops); - } - - if (family->n_mcgrps) { - struct nlattr *nla_grps; - int i; - - nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS); - if (nla_grps == NULL) - goto nla_put_failure; - - for (i = 0; i < family->n_mcgrps; i++) { - struct nlattr *nest; - const struct genl_multicast_group *grp; - - grp = &family->mcgrps[i]; - - nest = nla_nest_start(skb, i + 1); - if (nest == NULL) - goto nla_put_failure; - - if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID, - family->mcgrp_offset + i) || - nla_put_string(skb, CTRL_ATTR_MCAST_GRP_NAME, - grp->name)) - goto nla_put_failure; - - nla_nest_end(skb, nest); - } - nla_nest_end(skb, nla_grps); - } - - genlmsg_end(skb, hdr); - return 0; - -nla_put_failure: - genlmsg_cancel(skb, hdr); - return -EMSGSIZE; -} - -static int ctrl_fill_mcgrp_info(struct genl_family *family, - const struct genl_multicast_group *grp, - int grp_id, u32 portid, u32 seq, u32 flags, - struct sk_buff *skb, u8 cmd) -{ - void *hdr; - struct nlattr *nla_grps; - struct nlattr *nest; - - hdr = genlmsg_put(skb, portid, seq, &genl_ctrl, flags, cmd); - if (hdr == NULL) - return -1; - - if (nla_put_string(skb, CTRL_ATTR_FAMILY_NAME, family->name) || - nla_put_u16(skb, CTRL_ATTR_FAMILY_ID, family->id)) - goto nla_put_failure; - - nla_grps = nla_nest_start(skb, CTRL_ATTR_MCAST_GROUPS); - if (nla_grps == NULL) - goto nla_put_failure; - - nest = nla_nest_start(skb, 1); - if (nest == NULL) - goto nla_put_failure; - - if (nla_put_u32(skb, CTRL_ATTR_MCAST_GRP_ID, grp_id) || - nla_put_string(skb, CTRL_ATTR_MCAST_GRP_NAME, - grp->name)) - goto nla_put_failure; - - nla_nest_end(skb, nest); - nla_nest_end(skb, nla_grps); - - genlmsg_end(skb, hdr); - return 0; - -nla_put_failure: - genlmsg_cancel(skb, hdr); - return -EMSGSIZE; -} - -static int ctrl_dumpfamily(struct sk_buff *skb, struct netlink_callback *cb) -{ - - int i, n = 0; - struct genl_family *rt; - struct net *net = sock_net(skb->sk); - int chains_to_skip = cb->args[0]; - int fams_to_skip = cb->args[1]; - - for (i = chains_to_skip; i < GENL_FAM_TAB_SIZE; i++) { - n = 0; - list_for_each_entry(rt, genl_family_chain(i), family_list) { - if (!rt->netnsok && !net_eq(net, &init_net)) - continue; - if (++n < fams_to_skip) - continue; - if (ctrl_fill_info(rt, NETLINK_CB(cb->skb).portid, - cb->nlh->nlmsg_seq, NLM_F_MULTI, - skb, CTRL_CMD_NEWFAMILY) < 0) - goto errout; - } - - fams_to_skip = 0; - } - -errout: - cb->args[0] = i; - cb->args[1] = n; - - return skb->len; -} - -static struct sk_buff *ctrl_build_family_msg(struct genl_family *family, - u32 portid, int seq, u8 cmd) -{ - struct sk_buff *skb; - int err; - - skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (skb == NULL) - return ERR_PTR(-ENOBUFS); - - err = ctrl_fill_info(family, portid, seq, 0, skb, cmd); - if (err < 0) { - nlmsg_free(skb); - return ERR_PTR(err); - } - - return skb; -} - -static struct sk_buff * -ctrl_build_mcgrp_msg(struct genl_family *family, - const struct genl_multicast_group *grp, - int grp_id, u32 portid, int seq, u8 cmd) -{ - struct sk_buff *skb; - int err; - - skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); - if (skb == NULL) - return ERR_PTR(-ENOBUFS); - - err = ctrl_fill_mcgrp_info(family, grp, grp_id, portid, - seq, 0, skb, cmd); - if (err < 0) { - nlmsg_free(skb); - return ERR_PTR(err); - } - - return skb; -} - -static const struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = { - [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 }, - [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_NUL_STRING, - .len = GENL_NAMSIZ - 1 }, -}; - -static int ctrl_getfamily(struct sk_buff *skb, struct genl_info *info) -{ - struct sk_buff *msg; - struct genl_family *res = NULL; - int err = -EINVAL; - - if (info->attrs[CTRL_ATTR_FAMILY_ID]) { - u16 id = nla_get_u16(info->attrs[CTRL_ATTR_FAMILY_ID]); - res = genl_family_find_byid(id); - err = -ENOENT; - } - - if (info->attrs[CTRL_ATTR_FAMILY_NAME]) { - char *name; - - name = nla_data(info->attrs[CTRL_ATTR_FAMILY_NAME]); - res = genl_family_find_byname(name); -#ifdef CONFIG_MODULES - if (res == NULL) { - genl_unlock(); - up_read(&cb_lock); - request_module("net-pf-%d-proto-%d-family-%s", - PF_NETLINK, NETLINK_GENERIC, name); - down_read(&cb_lock); - genl_lock(); - res = genl_family_find_byname(name); - } -#endif - err = -ENOENT; - } - - if (res == NULL) - return err; - - if (!res->netnsok && !net_eq(genl_info_net(info), &init_net)) { - /* family doesn't exist here */ - return -ENOENT; - } - - msg = ctrl_build_family_msg(res, info->snd_portid, info->snd_seq, - CTRL_CMD_NEWFAMILY); - if (IS_ERR(msg)) - return PTR_ERR(msg); - - return genlmsg_reply(msg, info); -} - -static int genl_ctrl_event(int event, struct genl_family *family, - const struct genl_multicast_group *grp, - int grp_id) -{ - struct sk_buff *msg; - - /* genl is still initialising */ - if (!init_net.genl_sock) - return 0; - - switch (event) { - case CTRL_CMD_NEWFAMILY: - case CTRL_CMD_DELFAMILY: - WARN_ON(grp); - msg = ctrl_build_family_msg(family, 0, 0, event); - break; - case CTRL_CMD_NEWMCAST_GRP: - case CTRL_CMD_DELMCAST_GRP: - BUG_ON(!grp); - msg = ctrl_build_mcgrp_msg(family, grp, grp_id, 0, 0, event); - break; - default: - return -EINVAL; - } - - if (IS_ERR(msg)) - return PTR_ERR(msg); - - if (!family->netnsok) { - genlmsg_multicast_netns(&genl_ctrl, &init_net, msg, 0, - 0, GFP_KERNEL); - } else { - rcu_read_lock(); - genlmsg_multicast_allns(&genl_ctrl, msg, 0, - 0, GFP_ATOMIC); - rcu_read_unlock(); - } - - return 0; -} - -static const struct genl_ops genl_ctrl_ops[] = { - { - .cmd = CTRL_CMD_GETFAMILY, - .doit = ctrl_getfamily, - .dumpit = ctrl_dumpfamily, - .policy = ctrl_policy, - }, -}; - -static const struct genl_multicast_group genl_ctrl_groups[] = { - { .name = "notify", }, -}; - -static int genl_bind(struct net *net, int group) -{ - int i, err = -ENOENT; - - down_read(&cb_lock); - for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { - struct genl_family *f; - - list_for_each_entry(f, genl_family_chain(i), family_list) { - if (group >= f->mcgrp_offset && - group < f->mcgrp_offset + f->n_mcgrps) { - int fam_grp = group - f->mcgrp_offset; - - if (!f->netnsok && net != &init_net) - err = -ENOENT; - else if (f->mcast_bind) - err = f->mcast_bind(net, fam_grp); - else - err = 0; - break; - } - } - } - up_read(&cb_lock); - - return err; -} - -static void genl_unbind(struct net *net, int group) -{ - int i; - - down_read(&cb_lock); - for (i = 0; i < GENL_FAM_TAB_SIZE; i++) { - struct genl_family *f; - - list_for_each_entry(f, genl_family_chain(i), family_list) { - if (group >= f->mcgrp_offset && - group < f->mcgrp_offset + f->n_mcgrps) { - int fam_grp = group - f->mcgrp_offset; - - if (f->mcast_unbind) - f->mcast_unbind(net, fam_grp); - break; - } - } - } - up_read(&cb_lock); -} - -static int __net_init genl_pernet_init(struct net *net) -{ - struct netlink_kernel_cfg cfg = { - .input = genl_rcv, - .flags = NL_CFG_F_NONROOT_RECV, - .bind = genl_bind, - .unbind = genl_unbind, - }; - - /* we'll bump the group number right afterwards */ - net->genl_sock = netlink_kernel_create(net, NETLINK_GENERIC, &cfg); - - if (!net->genl_sock && net_eq(net, &init_net)) - panic("GENL: Cannot initialize generic netlink\n"); - - if (!net->genl_sock) - return -ENOMEM; - - return 0; -} - -static void __net_exit genl_pernet_exit(struct net *net) -{ - netlink_kernel_release(net->genl_sock); - net->genl_sock = NULL; -} - -static struct pernet_operations genl_pernet_ops = { - .init = genl_pernet_init, - .exit = genl_pernet_exit, -}; - -static int __init genl_init(void) -{ - int i, err; - - for (i = 0; i < GENL_FAM_TAB_SIZE; i++) - INIT_LIST_HEAD(&family_ht[i]); - - err = genl_register_family_with_ops_groups(&genl_ctrl, genl_ctrl_ops, - genl_ctrl_groups); - if (err < 0) - goto problem; - - err = register_pernet_subsys(&genl_pernet_ops); - if (err) - goto problem; - - return 0; - -problem: - panic("GENL: Cannot register controller: %d\n", err); -} - -subsys_initcall(genl_init); - -static int genlmsg_mcast(struct sk_buff *skb, u32 portid, unsigned long group, - gfp_t flags) -{ - struct sk_buff *tmp; - struct net *net, *prev = NULL; - int err; - - for_each_net_rcu(net) { - if (prev) { - tmp = skb_clone(skb, flags); - if (!tmp) { - err = -ENOMEM; - goto error; - } - err = nlmsg_multicast(prev->genl_sock, tmp, - portid, group, flags); - if (err) - goto error; - } - - prev = net; - } - - return nlmsg_multicast(prev->genl_sock, skb, portid, group, flags); - error: - kfree_skb(skb); - return err; -} - -int genlmsg_multicast_allns(struct genl_family *family, struct sk_buff *skb, - u32 portid, unsigned int group, gfp_t flags) -{ - if (WARN_ON_ONCE(group >= family->n_mcgrps)) - return -EINVAL; - group = family->mcgrp_offset + group; - return genlmsg_mcast(skb, portid, group, flags); -} -EXPORT_SYMBOL(genlmsg_multicast_allns); - -void genl_notify(struct genl_family *family, struct sk_buff *skb, - struct genl_info *info, u32 group, gfp_t flags) -{ - struct net *net = genl_info_net(info); - struct sock *sk = net->genl_sock; - int report = 0; - - if (info->nlhdr) - report = nlmsg_report(info->nlhdr); - - if (WARN_ON_ONCE(group >= family->n_mcgrps)) - return; - group = family->mcgrp_offset + group; - nlmsg_notify(sk, skb, info->snd_portid, group, report, flags); -} -EXPORT_SYMBOL(genl_notify); diff --git a/src/linux/net/nfc/Kconfig b/src/linux/net/nfc/Kconfig deleted file mode 100644 index 6e0fa0c..0000000 --- a/src/linux/net/nfc/Kconfig +++ /dev/null @@ -1,34 +0,0 @@ -# -# NFC sybsystem configuration -# - -menuconfig NFC - depends on NET - depends on RFKILL || !RFKILL - tristate "NFC subsystem support" - default n - help - Say Y here if you want to build support for NFC (Near field - communication) devices. - - To compile this support as a module, choose M here: the module will - be called nfc. - -config NFC_DIGITAL - depends on NFC - select CRC_CCITT - select CRC_ITU_T - tristate "NFC Digital Protocol stack support" - default n - help - Say Y if you want to build NFC digital protocol stack support. - This is needed by NFC chipsets whose firmware only implement - the NFC analog layer. - - To compile this support as a module, choose M here: the module will - be called nfc_digital. - -source "net/nfc/nci/Kconfig" -source "net/nfc/hci/Kconfig" - -source "drivers/nfc/Kconfig" diff --git a/src/linux/net/nfc/hci/Kconfig b/src/linux/net/nfc/hci/Kconfig deleted file mode 100644 index fd67f51..0000000 --- a/src/linux/net/nfc/hci/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -config NFC_HCI - depends on NFC - tristate "NFC HCI implementation" - default n - help - Say Y here if you want to build support for a kernel NFC HCI - implementation. This is mostly needed for devices that only process - HCI frames, like for example the NXP pn544. - -config NFC_SHDLC - depends on NFC_HCI - select CRC_CCITT - bool "SHDLC link layer for HCI based NFC drivers" - default n - ---help--- - Say yes if you use an NFC HCI driver that requires SHDLC link layer. - If unsure, say N here. diff --git a/src/linux/net/nfc/nci/Kconfig b/src/linux/net/nfc/nci/Kconfig deleted file mode 100644 index 85d4819..0000000 --- a/src/linux/net/nfc/nci/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -config NFC_NCI - depends on NFC - tristate "NCI protocol support" - default n - help - NCI (NFC Controller Interface) is a communication protocol between - an NFC Controller (NFCC) and a Device Host (DH). - - Say Y here to compile NCI support into the kernel or say M to - compile it as module (nci). - -config NFC_NCI_SPI - depends on NFC_NCI && SPI - select CRC_CCITT - tristate "NCI over SPI protocol support" - default n - help - NCI (NFC Controller Interface) is a communication protocol between - an NFC Controller (NFCC) and a Device Host (DH). - - Say yes if you use an NCI driver that requires SPI link layer. - -config NFC_NCI_UART - depends on NFC_NCI && TTY - tristate "NCI over UART protocol support" - default n - help - Say yes if you use an NCI driver that requires UART link layer. diff --git a/src/linux/net/openvswitch/Kconfig b/src/linux/net/openvswitch/Kconfig deleted file mode 100644 index ce94729..0000000 --- a/src/linux/net/openvswitch/Kconfig +++ /dev/null @@ -1,73 +0,0 @@ -# -# Open vSwitch -# - -config OPENVSWITCH - tristate "Open vSwitch" - depends on INET - depends on !NF_CONNTRACK || \ - (NF_CONNTRACK && ((!NF_DEFRAG_IPV6 || NF_DEFRAG_IPV6) && \ - (!NF_NAT || NF_NAT) && \ - (!NF_NAT_IPV4 || NF_NAT_IPV4) && \ - (!NF_NAT_IPV6 || NF_NAT_IPV6))) - select LIBCRC32C - select MPLS - select NET_MPLS_GSO - select DST_CACHE - ---help--- - Open vSwitch is a multilayer Ethernet switch targeted at virtualized - environments. In addition to supporting a variety of features - expected in a traditional hardware switch, it enables fine-grained - programmatic extension and flow-based control of the network. This - control is useful in a wide variety of applications but is - particularly important in multi-server virtualization deployments, - which are often characterized by highly dynamic endpoints and the - need to maintain logical abstractions for multiple tenants. - - The Open vSwitch datapath provides an in-kernel fast path for packet - forwarding. It is complemented by a userspace daemon, ovs-vswitchd, - which is able to accept configuration from a variety of sources and - translate it into packet processing rules. - - See http://openvswitch.org for more information and userspace - utilities. - - To compile this code as a module, choose M here: the module will be - called openvswitch. - - If unsure, say N. - -config OPENVSWITCH_GRE - tristate "Open vSwitch GRE tunneling support" - depends on OPENVSWITCH - depends on NET_IPGRE - default OPENVSWITCH - ---help--- - If you say Y here, then the Open vSwitch will be able create GRE - vport. - - Say N to exclude this support and reduce the binary size. - - If unsure, say Y. - -config OPENVSWITCH_VXLAN - tristate "Open vSwitch VXLAN tunneling support" - depends on OPENVSWITCH - depends on VXLAN - default OPENVSWITCH - ---help--- - If you say Y here, then the Open vSwitch will be able create vxlan vport. - - Say N to exclude this support and reduce the binary size. - - If unsure, say Y. - -config OPENVSWITCH_GENEVE - tristate "Open vSwitch Geneve tunneling support" - depends on OPENVSWITCH - depends on GENEVE - default OPENVSWITCH - ---help--- - If you say Y here, then the Open vSwitch will be able create geneve vport. - - Say N to exclude this support and reduce the binary size. diff --git a/src/linux/net/packet/Kconfig b/src/linux/net/packet/Kconfig deleted file mode 100644 index cc55b35..0000000 --- a/src/linux/net/packet/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -# -# Packet configuration -# - -config PACKET - tristate "Packet socket" - ---help--- - The Packet protocol is used by applications which communicate - directly with network devices without an intermediate network - protocol implemented in the kernel, e.g. tcpdump. If you want them - to work, choose Y. - - To compile this driver as a module, choose M here: the module will - be called af_packet. - - If unsure, say Y. - -config PACKET_DIAG - tristate "Packet: sockets monitoring interface" - depends on PACKET - default n - ---help--- - Support for PF_PACKET sockets monitoring interface used by the ss tool. - If unsure, say Y. diff --git a/src/linux/net/phonet/Kconfig b/src/linux/net/phonet/Kconfig deleted file mode 100644 index 6ec7d55..0000000 --- a/src/linux/net/phonet/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# -# Phonet protocol -# - -config PHONET - tristate "Phonet protocols family" - help - The Phone Network protocol (PhoNet) is a packet-oriented - communication protocol developed by Nokia for use with its modems. - - This is required for Maemo to use cellular data connectivity (if - supported). It can also be used to control Nokia phones - from a Linux computer, although AT commands may be easier to use. - - To compile this driver as a module, choose M here: the module - will be called phonet. If unsure, say N. diff --git a/src/linux/net/qrtr/Kconfig b/src/linux/net/qrtr/Kconfig deleted file mode 100644 index b83c680..0000000 --- a/src/linux/net/qrtr/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -# Qualcomm IPC Router configuration -# - -config QRTR - tristate "Qualcomm IPC Router support" - depends on ARCH_QCOM || COMPILE_TEST - ---help--- - Say Y if you intend to use Qualcomm IPC router protocol. The - protocol is used to communicate with services provided by other - hardware blocks in the system. - - In order to do service lookups, a userspace daemon is required to - maintain a service listing. - -if QRTR - -config QRTR_SMD - tristate "SMD IPC Router channels" - depends on QCOM_SMD || (COMPILE_TEST && QCOM_SMD=n) - ---help--- - Say Y here to support SMD based ipcrouter channels. SMD is the - most common transport for IPC Router. - -endif # QRTR diff --git a/src/linux/net/rds/Kconfig b/src/linux/net/rds/Kconfig deleted file mode 100644 index bffde4b..0000000 --- a/src/linux/net/rds/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ - -config RDS - tristate "The RDS Protocol" - depends on INET - ---help--- - The RDS (Reliable Datagram Sockets) protocol provides reliable, - sequenced delivery of datagrams over Infiniband or TCP. - -config RDS_RDMA - tristate "RDS over Infiniband" - depends on RDS && INFINIBAND && INFINIBAND_ADDR_TRANS - ---help--- - Allow RDS to use Infiniband as a transport. - This transport supports RDMA operations. - -config RDS_TCP - tristate "RDS over TCP" - depends on RDS - ---help--- - Allow RDS to use TCP as a transport. - This transport does not support RDMA operations. - -config RDS_DEBUG - bool "RDS debugging messages" - depends on RDS - default n - diff --git a/src/linux/net/rfkill/Kconfig b/src/linux/net/rfkill/Kconfig deleted file mode 100644 index 868f1ad..0000000 --- a/src/linux/net/rfkill/Kconfig +++ /dev/null @@ -1,44 +0,0 @@ -# -# RF switch subsystem configuration -# -menuconfig RFKILL - tristate "RF switch subsystem support" - help - Say Y here if you want to have control over RF switches - found on many WiFi and Bluetooth cards. - - To compile this driver as a module, choose M here: the - module will be called rfkill. - -# LED trigger support -config RFKILL_LEDS - bool - depends on RFKILL - depends on LEDS_TRIGGERS = y || RFKILL = LEDS_TRIGGERS - default y - -config RFKILL_INPUT - bool "RF switch input support" if EXPERT - depends on RFKILL - depends on INPUT = y || RFKILL = INPUT - default y if !EXPERT - -config RFKILL_REGULATOR - tristate "Generic rfkill regulator driver" - depends on RFKILL || !RFKILL - depends on REGULATOR - help - This options enable controlling radio transmitters connected to - voltage regulator using the regulator framework. - - To compile this driver as a module, choose M here: the module will - be called rfkill-regulator. - -config RFKILL_GPIO - tristate "GPIO RFKILL driver" - depends on RFKILL - depends on GPIOLIB || COMPILE_TEST - default n - help - If you say yes here you get support of a generic gpio RFKILL - driver. diff --git a/src/linux/net/rxrpc/Kconfig b/src/linux/net/rxrpc/Kconfig deleted file mode 100644 index 86f8853..0000000 --- a/src/linux/net/rxrpc/Kconfig +++ /dev/null @@ -1,58 +0,0 @@ -# -# RxRPC session sockets -# - -config AF_RXRPC - tristate "RxRPC session sockets" - depends on INET - select CRYPTO - select KEYS - help - Say Y or M here to include support for RxRPC session sockets (just - the transport part, not the presentation part: (un)marshalling is - left to the application). - - These are used for AFS kernel filesystem and userspace utilities. - - This module at the moment only supports client operations and is - currently incomplete. - - See Documentation/networking/rxrpc.txt. - -config AF_RXRPC_IPV6 - bool "IPv6 support for RxRPC" - depends on (IPV6 = m && AF_RXRPC = m) || (IPV6 = y && AF_RXRPC) - help - Say Y here to allow AF_RXRPC to use IPV6 UDP as well as IPV4 UDP as - its network transport. - -config AF_RXRPC_INJECT_LOSS - bool "Inject packet loss into RxRPC packet stream" - depends on AF_RXRPC - help - Say Y here to inject packet loss by discarding some received and some - transmitted packets. - - -config AF_RXRPC_DEBUG - bool "RxRPC dynamic debugging" - depends on AF_RXRPC - help - Say Y here to make runtime controllable debugging messages appear. - - See Documentation/networking/rxrpc.txt. - - -config RXKAD - bool "RxRPC Kerberos security" - depends on AF_RXRPC - select CRYPTO - select CRYPTO_MANAGER - select CRYPTO_BLKCIPHER - select CRYPTO_PCBC - select CRYPTO_FCRYPT - help - Provide kerberos 4 and AFS kaserver security handling for AF_RXRPC - through the use of the key retention service. - - See Documentation/networking/rxrpc.txt. diff --git a/src/linux/net/sched/Kconfig b/src/linux/net/sched/Kconfig deleted file mode 100644 index 87956a7..0000000 --- a/src/linux/net/sched/Kconfig +++ /dev/null @@ -1,812 +0,0 @@ -# -# Traffic control configuration. -# - -menuconfig NET_SCHED - bool "QoS and/or fair queueing" - select NET_SCH_FIFO - ---help--- - When the kernel has several packets to send out over a network - device, it has to decide which ones to send first, which ones to - delay, and which ones to drop. This is the job of the queueing - disciplines, several different algorithms for how to do this - "fairly" have been proposed. - - If you say N here, you will get the standard packet scheduler, which - is a FIFO (first come, first served). If you say Y here, you will be - able to choose from among several alternative algorithms which can - then be attached to different network devices. This is useful for - example if some of your network devices are real time devices that - need a certain minimum data flow rate, or if you need to limit the - maximum data flow rate for traffic which matches specified criteria. - This code is considered to be experimental. - - To administer these schedulers, you'll need the user-level utilities - from the package iproute2+tc at - . That package - also contains some documentation; for more, check out - . - - This Quality of Service (QoS) support will enable you to use - Differentiated Services (diffserv) and Resource Reservation Protocol - (RSVP) on your Linux router if you also say Y to the corresponding - classifiers below. Documentation and software is at - . - - If you say Y here and to "/proc file system" below, you will be able - to read status information about packet schedulers from the file - /proc/net/psched. - - The available schedulers are listed in the following questions; you - can say Y to as many as you like. If unsure, say N now. - -if NET_SCHED - -comment "Queueing/Scheduling" - -config NET_SCH_CBQ - tristate "Class Based Queueing (CBQ)" - ---help--- - Say Y here if you want to use the Class-Based Queueing (CBQ) packet - scheduling algorithm. This algorithm classifies the waiting packets - into a tree-like hierarchy of classes; the leaves of this tree are - in turn scheduled by separate algorithms. - - See the top of for more details. - - CBQ is a commonly used scheduler, so if you're unsure, you should - say Y here. Then say Y to all the queueing algorithms below that you - want to use as leaf disciplines. - - To compile this code as a module, choose M here: the - module will be called sch_cbq. - -config NET_SCH_HTB - tristate "Hierarchical Token Bucket (HTB)" - ---help--- - Say Y here if you want to use the Hierarchical Token Buckets (HTB) - packet scheduling algorithm. See - for complete manual and - in-depth articles. - - HTB is very similar to CBQ regarding its goals however is has - different properties and different algorithm. - - To compile this code as a module, choose M here: the - module will be called sch_htb. - -config NET_SCH_HFSC - tristate "Hierarchical Fair Service Curve (HFSC)" - ---help--- - Say Y here if you want to use the Hierarchical Fair Service Curve - (HFSC) packet scheduling algorithm. - - To compile this code as a module, choose M here: the - module will be called sch_hfsc. - -config NET_SCH_ATM - tristate "ATM Virtual Circuits (ATM)" - depends on ATM - ---help--- - Say Y here if you want to use the ATM pseudo-scheduler. This - provides a framework for invoking classifiers, which in turn - select classes of this queuing discipline. Each class maps - the flow(s) it is handling to a given virtual circuit. - - See the top of for more details. - - To compile this code as a module, choose M here: the - module will be called sch_atm. - -config NET_SCH_PRIO - tristate "Multi Band Priority Queueing (PRIO)" - ---help--- - Say Y here if you want to use an n-band priority queue packet - scheduler. - - To compile this code as a module, choose M here: the - module will be called sch_prio. - -config NET_SCH_MULTIQ - tristate "Hardware Multiqueue-aware Multi Band Queuing (MULTIQ)" - ---help--- - Say Y here if you want to use an n-band queue packet scheduler - to support devices that have multiple hardware transmit queues. - - To compile this code as a module, choose M here: the - module will be called sch_multiq. - -config NET_SCH_RED - tristate "Random Early Detection (RED)" - ---help--- - Say Y here if you want to use the Random Early Detection (RED) - packet scheduling algorithm. - - See the top of for more details. - - To compile this code as a module, choose M here: the - module will be called sch_red. - -config NET_SCH_SFB - tristate "Stochastic Fair Blue (SFB)" - ---help--- - Say Y here if you want to use the Stochastic Fair Blue (SFB) - packet scheduling algorithm. - - See the top of for more details. - - To compile this code as a module, choose M here: the - module will be called sch_sfb. - -config NET_SCH_SFQ - tristate "Stochastic Fairness Queueing (SFQ)" - ---help--- - Say Y here if you want to use the Stochastic Fairness Queueing (SFQ) - packet scheduling algorithm. - - See the top of for more details. - - To compile this code as a module, choose M here: the - module will be called sch_sfq. - -config NET_SCH_TEQL - tristate "True Link Equalizer (TEQL)" - ---help--- - Say Y here if you want to use the True Link Equalizer (TLE) packet - scheduling algorithm. This queueing discipline allows the combination - of several physical devices into one virtual device. - - See the top of for more details. - - To compile this code as a module, choose M here: the - module will be called sch_teql. - -config NET_SCH_TBF - tristate "Token Bucket Filter (TBF)" - ---help--- - Say Y here if you want to use the Token Bucket Filter (TBF) packet - scheduling algorithm. - - See the top of for more details. - - To compile this code as a module, choose M here: the - module will be called sch_tbf. - -config NET_SCH_GRED - tristate "Generic Random Early Detection (GRED)" - ---help--- - Say Y here if you want to use the Generic Random Early Detection - (GRED) packet scheduling algorithm for some of your network devices - (see the top of for details and - references about the algorithm). - - To compile this code as a module, choose M here: the - module will be called sch_gred. - -config NET_SCH_DSMARK - tristate "Differentiated Services marker (DSMARK)" - ---help--- - Say Y if you want to schedule packets according to the - Differentiated Services architecture proposed in RFC 2475. - Technical information on this method, with pointers to associated - RFCs, is available at . - - To compile this code as a module, choose M here: the - module will be called sch_dsmark. - -config NET_SCH_NETEM - tristate "Network emulator (NETEM)" - ---help--- - Say Y if you want to emulate network delay, loss, and packet - re-ordering. This is often useful to simulate networks when - testing applications or protocols. - - To compile this driver as a module, choose M here: the module - will be called sch_netem. - - If unsure, say N. - -config NET_SCH_DRR - tristate "Deficit Round Robin scheduler (DRR)" - help - Say Y here if you want to use the Deficit Round Robin (DRR) packet - scheduling algorithm. - - To compile this driver as a module, choose M here: the module - will be called sch_drr. - - If unsure, say N. - -config NET_SCH_MQPRIO - tristate "Multi-queue priority scheduler (MQPRIO)" - help - Say Y here if you want to use the Multi-queue Priority scheduler. - This scheduler allows QOS to be offloaded on NICs that have support - for offloading QOS schedulers. - - To compile this driver as a module, choose M here: the module will - be called sch_mqprio. - - If unsure, say N. - -config NET_SCH_CHOKE - tristate "CHOose and Keep responsive flow scheduler (CHOKE)" - help - Say Y here if you want to use the CHOKe packet scheduler (CHOose - and Keep for responsive flows, CHOose and Kill for unresponsive - flows). This is a variation of RED which trys to penalize flows - that monopolize the queue. - - To compile this code as a module, choose M here: the - module will be called sch_choke. - -config NET_SCH_QFQ - tristate "Quick Fair Queueing scheduler (QFQ)" - help - Say Y here if you want to use the Quick Fair Queueing Scheduler (QFQ) - packet scheduling algorithm. - - To compile this driver as a module, choose M here: the module - will be called sch_qfq. - - If unsure, say N. - -config NET_SCH_CODEL - tristate "Controlled Delay AQM (CODEL)" - help - Say Y here if you want to use the Controlled Delay (CODEL) - packet scheduling algorithm. - - To compile this driver as a module, choose M here: the module - will be called sch_codel. - - If unsure, say N. - -config NET_SCH_FQ_CODEL - tristate "Fair Queue Controlled Delay AQM (FQ_CODEL)" - help - Say Y here if you want to use the FQ Controlled Delay (FQ_CODEL) - packet scheduling algorithm. - - To compile this driver as a module, choose M here: the module - will be called sch_fq_codel. - - If unsure, say N. - -config NET_SCH_FQ - tristate "Fair Queue" - help - Say Y here if you want to use the FQ packet scheduling algorithm. - - FQ does flow separation, and is able to respect pacing requirements - set by TCP stack into sk->sk_pacing_rate (for localy generated - traffic) - - To compile this driver as a module, choose M here: the module - will be called sch_fq. - - If unsure, say N. - -config NET_SCH_HHF - tristate "Heavy-Hitter Filter (HHF)" - help - Say Y here if you want to use the Heavy-Hitter Filter (HHF) - packet scheduling algorithm. - - To compile this driver as a module, choose M here: the module - will be called sch_hhf. - -config NET_SCH_PIE - tristate "Proportional Integral controller Enhanced (PIE) scheduler" - help - Say Y here if you want to use the Proportional Integral controller - Enhanced scheduler packet scheduling algorithm. - For more information, please see - http://tools.ietf.org/html/draft-pan-tsvwg-pie-00 - - To compile this driver as a module, choose M here: the module - will be called sch_pie. - - If unsure, say N. - -config NET_SCH_INGRESS - tristate "Ingress/classifier-action Qdisc" - depends on NET_CLS_ACT - select NET_INGRESS - select NET_EGRESS - ---help--- - Say Y here if you want to use classifiers for incoming and/or outgoing - packets. This qdisc doesn't do anything else besides running classifiers, - which can also have actions attached to them. In case of outgoing packets, - classifiers that this qdisc holds are executed in the transmit path - before real enqueuing to an egress qdisc happens. - - If unsure, say Y. - - To compile this code as a module, choose M here: the module will be - called sch_ingress with alias of sch_clsact. - -config NET_SCH_PLUG - tristate "Plug network traffic until release (PLUG)" - ---help--- - - This queuing discipline allows userspace to plug/unplug a network - output queue, using the netlink interface. When it receives an - enqueue command it inserts a plug into the outbound queue that - causes following packets to enqueue until a dequeue command arrives - over netlink, causing the plug to be removed and resuming the normal - packet flow. - - This module also provides a generic "network output buffering" - functionality (aka output commit), wherein upon arrival of a dequeue - command, only packets up to the first plug are released for delivery. - The Remus HA project uses this module to enable speculative execution - of virtual machines by allowing the generated network output to be rolled - back if needed. - - For more information, please refer to - - Say Y here if you are using this kernel for Xen dom0 and - want to protect Xen guests with Remus. - - To compile this code as a module, choose M here: the - module will be called sch_plug. - -comment "Classification" - -config NET_CLS - bool - -config NET_CLS_BASIC - tristate "Elementary classification (BASIC)" - select NET_CLS - ---help--- - Say Y here if you want to be able to classify packets using - only extended matches and actions. - - To compile this code as a module, choose M here: the - module will be called cls_basic. - -config NET_CLS_TCINDEX - tristate "Traffic-Control Index (TCINDEX)" - select NET_CLS - ---help--- - Say Y here if you want to be able to classify packets based on - traffic control indices. You will want this feature if you want - to implement Differentiated Services together with DSMARK. - - To compile this code as a module, choose M here: the - module will be called cls_tcindex. - -config NET_CLS_ROUTE4 - tristate "Routing decision (ROUTE)" - depends on INET - select IP_ROUTE_CLASSID - select NET_CLS - ---help--- - If you say Y here, you will be able to classify packets - according to the route table entry they matched. - - To compile this code as a module, choose M here: the - module will be called cls_route. - -config NET_CLS_FW - tristate "Netfilter mark (FW)" - select NET_CLS - ---help--- - If you say Y here, you will be able to classify packets - according to netfilter/firewall marks. - - To compile this code as a module, choose M here: the - module will be called cls_fw. - -config NET_CLS_U32 - tristate "Universal 32bit comparisons w/ hashing (U32)" - select NET_CLS - ---help--- - Say Y here to be able to classify packets using a universal - 32bit pieces based comparison scheme. - - To compile this code as a module, choose M here: the - module will be called cls_u32. - -config CLS_U32_PERF - bool "Performance counters support" - depends on NET_CLS_U32 - ---help--- - Say Y here to make u32 gather additional statistics useful for - fine tuning u32 classifiers. - -config CLS_U32_MARK - bool "Netfilter marks support" - depends on NET_CLS_U32 - ---help--- - Say Y here to be able to use netfilter marks as u32 key. - -config NET_CLS_RSVP - tristate "IPv4 Resource Reservation Protocol (RSVP)" - select NET_CLS - ---help--- - The Resource Reservation Protocol (RSVP) permits end systems to - request a minimum and maximum data flow rate for a connection; this - is important for real time data such as streaming sound or video. - - Say Y here if you want to be able to classify outgoing packets based - on their RSVP requests. - - To compile this code as a module, choose M here: the - module will be called cls_rsvp. - -config NET_CLS_RSVP6 - tristate "IPv6 Resource Reservation Protocol (RSVP6)" - select NET_CLS - ---help--- - The Resource Reservation Protocol (RSVP) permits end systems to - request a minimum and maximum data flow rate for a connection; this - is important for real time data such as streaming sound or video. - - Say Y here if you want to be able to classify outgoing packets based - on their RSVP requests and you are using the IPv6 protocol. - - To compile this code as a module, choose M here: the - module will be called cls_rsvp6. - -config NET_CLS_FLOW - tristate "Flow classifier" - select NET_CLS - ---help--- - If you say Y here, you will be able to classify packets based on - a configurable combination of packet keys. This is mostly useful - in combination with SFQ. - - To compile this code as a module, choose M here: the - module will be called cls_flow. - -config NET_CLS_CGROUP - tristate "Control Group Classifier" - select NET_CLS - select CGROUP_NET_CLASSID - depends on CGROUPS - ---help--- - Say Y here if you want to classify packets based on the control - cgroup of their process. - - To compile this code as a module, choose M here: the - module will be called cls_cgroup. - -config NET_CLS_BPF - tristate "BPF-based classifier" - select NET_CLS - ---help--- - If you say Y here, you will be able to classify packets based on - programmable BPF (JIT'ed) filters as an alternative to ematches. - - To compile this code as a module, choose M here: the module will - be called cls_bpf. - -config NET_CLS_FLOWER - tristate "Flower classifier" - select NET_CLS - ---help--- - If you say Y here, you will be able to classify packets based on - a configurable combination of packet keys and masks. - - To compile this code as a module, choose M here: the module will - be called cls_flower. - -config NET_CLS_MATCHALL - tristate "Match-all classifier" - select NET_CLS - ---help--- - If you say Y here, you will be able to classify packets based on - nothing. Every packet will match. - - To compile this code as a module, choose M here: the module will - be called cls_matchall. - -config NET_EMATCH - bool "Extended Matches" - select NET_CLS - ---help--- - Say Y here if you want to use extended matches on top of classifiers - and select the extended matches below. - - Extended matches are small classification helpers not worth writing - a separate classifier for. - - A recent version of the iproute2 package is required to use - extended matches. - -config NET_EMATCH_STACK - int "Stack size" - depends on NET_EMATCH - default "32" - ---help--- - Size of the local stack variable used while evaluating the tree of - ematches. Limits the depth of the tree, i.e. the number of - encapsulated precedences. Every level requires 4 bytes of additional - stack space. - -config NET_EMATCH_CMP - tristate "Simple packet data comparison" - depends on NET_EMATCH - ---help--- - Say Y here if you want to be able to classify packets based on - simple packet data comparisons for 8, 16, and 32bit values. - - To compile this code as a module, choose M here: the - module will be called em_cmp. - -config NET_EMATCH_NBYTE - tristate "Multi byte comparison" - depends on NET_EMATCH - ---help--- - Say Y here if you want to be able to classify packets based on - multiple byte comparisons mainly useful for IPv6 address comparisons. - - To compile this code as a module, choose M here: the - module will be called em_nbyte. - -config NET_EMATCH_U32 - tristate "U32 key" - depends on NET_EMATCH - ---help--- - Say Y here if you want to be able to classify packets using - the famous u32 key in combination with logic relations. - - To compile this code as a module, choose M here: the - module will be called em_u32. - -config NET_EMATCH_META - tristate "Metadata" - depends on NET_EMATCH - ---help--- - Say Y here if you want to be able to classify packets based on - metadata such as load average, netfilter attributes, socket - attributes and routing decisions. - - To compile this code as a module, choose M here: the - module will be called em_meta. - -config NET_EMATCH_TEXT - tristate "Textsearch" - depends on NET_EMATCH - select TEXTSEARCH - select TEXTSEARCH_KMP - select TEXTSEARCH_BM - select TEXTSEARCH_FSM - ---help--- - Say Y here if you want to be able to classify packets based on - textsearch comparisons. - - To compile this code as a module, choose M here: the - module will be called em_text. - -config NET_EMATCH_CANID - tristate "CAN Identifier" - depends on NET_EMATCH && (CAN=y || CAN=m) - ---help--- - Say Y here if you want to be able to classify CAN frames based - on CAN Identifier. - - To compile this code as a module, choose M here: the - module will be called em_canid. - -config NET_EMATCH_IPSET - tristate "IPset" - depends on NET_EMATCH && IP_SET - ---help--- - Say Y here if you want to be able to classify packets based on - ipset membership. - - To compile this code as a module, choose M here: the - module will be called em_ipset. - -config NET_CLS_ACT - bool "Actions" - ---help--- - Say Y here if you want to use traffic control actions. Actions - get attached to classifiers and are invoked after a successful - classification. They are used to overwrite the classification - result, instantly drop or redirect packets, etc. - - A recent version of the iproute2 package is required to use - extended matches. - -config NET_ACT_POLICE - tristate "Traffic Policing" - depends on NET_CLS_ACT - ---help--- - Say Y here if you want to do traffic policing, i.e. strict - bandwidth limiting. This action replaces the existing policing - module. - - To compile this code as a module, choose M here: the - module will be called act_police. - -config NET_ACT_GACT - tristate "Generic actions" - depends on NET_CLS_ACT - ---help--- - Say Y here to take generic actions such as dropping and - accepting packets. - - To compile this code as a module, choose M here: the - module will be called act_gact. - -config GACT_PROB - bool "Probability support" - depends on NET_ACT_GACT - ---help--- - Say Y here to use the generic action randomly or deterministically. - -config NET_ACT_MIRRED - tristate "Redirecting and Mirroring" - depends on NET_CLS_ACT - ---help--- - Say Y here to allow packets to be mirrored or redirected to - other devices. - - To compile this code as a module, choose M here: the - module will be called act_mirred. - -config NET_ACT_IPT - tristate "IPtables targets" - depends on NET_CLS_ACT && NETFILTER && IP_NF_IPTABLES - ---help--- - Say Y here to be able to invoke iptables targets after successful - classification. - - To compile this code as a module, choose M here: the - module will be called act_ipt. - -config NET_ACT_NAT - tristate "Stateless NAT" - depends on NET_CLS_ACT - ---help--- - Say Y here to do stateless NAT on IPv4 packets. You should use - netfilter for NAT unless you know what you are doing. - - To compile this code as a module, choose M here: the - module will be called act_nat. - -config NET_ACT_PEDIT - tristate "Packet Editing" - depends on NET_CLS_ACT - ---help--- - Say Y here if you want to mangle the content of packets. - - To compile this code as a module, choose M here: the - module will be called act_pedit. - -config NET_ACT_SIMP - tristate "Simple Example (Debug)" - depends on NET_CLS_ACT - ---help--- - Say Y here to add a simple action for demonstration purposes. - It is meant as an example and for debugging purposes. It will - print a configured policy string followed by the packet count - to the console for every packet that passes by. - - If unsure, say N. - - To compile this code as a module, choose M here: the - module will be called act_simple. - -config NET_ACT_SKBEDIT - tristate "SKB Editing" - depends on NET_CLS_ACT - ---help--- - Say Y here to change skb priority or queue_mapping settings. - - If unsure, say N. - - To compile this code as a module, choose M here: the - module will be called act_skbedit. - -config NET_ACT_CSUM - tristate "Checksum Updating" - depends on NET_CLS_ACT && INET - ---help--- - Say Y here to update some common checksum after some direct - packet alterations. - - To compile this code as a module, choose M here: the - module will be called act_csum. - -config NET_ACT_VLAN - tristate "Vlan manipulation" - depends on NET_CLS_ACT - ---help--- - Say Y here to push or pop vlan headers. - - If unsure, say N. - - To compile this code as a module, choose M here: the - module will be called act_vlan. - -config NET_ACT_BPF - tristate "BPF based action" - depends on NET_CLS_ACT - ---help--- - Say Y here to execute BPF code on packets. The BPF code will decide - if the packet should be dropped or not. - - If unsure, say N. - - To compile this code as a module, choose M here: the - module will be called act_bpf. - -config NET_ACT_CONNMARK - tristate "Netfilter Connection Mark Retriever" - depends on NET_CLS_ACT && NETFILTER && IP_NF_IPTABLES - depends on NF_CONNTRACK && NF_CONNTRACK_MARK - ---help--- - Say Y here to allow retrieving of conn mark - - If unsure, say N. - - To compile this code as a module, choose M here: the - module will be called act_connmark. - -config NET_ACT_SKBMOD - tristate "skb data modification action" - depends on NET_CLS_ACT - ---help--- - Say Y here to allow modification of skb data - - If unsure, say N. - - To compile this code as a module, choose M here: the - module will be called act_skbmod. - -config NET_ACT_IFE - tristate "Inter-FE action based on IETF ForCES InterFE LFB" - depends on NET_CLS_ACT - ---help--- - Say Y here to allow for sourcing and terminating metadata - For details refer to netdev01 paper: - "Distributing Linux Traffic Control Classifier-Action Subsystem" - Authors: Jamal Hadi Salim and Damascene M. Joachimpillai - - To compile this code as a module, choose M here: the - module will be called act_ife. - -config NET_ACT_TUNNEL_KEY - tristate "IP tunnel metadata manipulation" - depends on NET_CLS_ACT - ---help--- - Say Y here to set/release ip tunnel metadata. - - If unsure, say N. - - To compile this code as a module, choose M here: the - module will be called act_tunnel_key. - -config NET_IFE_SKBMARK - tristate "Support to encoding decoding skb mark on IFE action" - depends on NET_ACT_IFE - ---help--- - -config NET_IFE_SKBPRIO - tristate "Support to encoding decoding skb prio on IFE action" - depends on NET_ACT_IFE - ---help--- - -config NET_IFE_SKBTCINDEX - tristate "Support to encoding decoding skb tcindex on IFE action" - depends on NET_ACT_IFE - ---help--- - -config NET_CLS_IND - bool "Incoming device classification" - depends on NET_CLS_U32 || NET_CLS_FW - ---help--- - Say Y here to extend the u32 and fw classifier to support - classification based on the incoming device. This option is - likely to disappear in favour of the metadata ematch. - -endif # NET_SCHED - -config NET_SCH_FIFO - bool diff --git a/src/linux/net/sched/Makefile b/src/linux/net/sched/Makefile deleted file mode 100644 index 4bdda36..0000000 --- a/src/linux/net/sched/Makefile +++ /dev/null @@ -1,74 +0,0 @@ -# -# Makefile for the Linux Traffic Control Unit. -# - -obj-y := sch_generic.o sch_mq.o - -obj-$(CONFIG_NET_SCHED) += sch_api.o sch_blackhole.o -obj-$(CONFIG_NET_CLS) += cls_api.o -obj-$(CONFIG_NET_CLS_ACT) += act_api.o -obj-$(CONFIG_NET_ACT_POLICE) += act_police.o -obj-$(CONFIG_NET_ACT_GACT) += act_gact.o -obj-$(CONFIG_NET_ACT_MIRRED) += act_mirred.o -obj-$(CONFIG_NET_ACT_IPT) += act_ipt.o -obj-$(CONFIG_NET_ACT_NAT) += act_nat.o -obj-$(CONFIG_NET_ACT_PEDIT) += act_pedit.o -obj-$(CONFIG_NET_ACT_SIMP) += act_simple.o -obj-$(CONFIG_NET_ACT_SKBEDIT) += act_skbedit.o -obj-$(CONFIG_NET_ACT_CSUM) += act_csum.o -obj-$(CONFIG_NET_ACT_VLAN) += act_vlan.o -obj-$(CONFIG_NET_ACT_BPF) += act_bpf.o -obj-$(CONFIG_NET_ACT_CONNMARK) += act_connmark.o -obj-$(CONFIG_NET_ACT_SKBMOD) += act_skbmod.o -obj-$(CONFIG_NET_ACT_IFE) += act_ife.o -obj-$(CONFIG_NET_IFE_SKBMARK) += act_meta_mark.o -obj-$(CONFIG_NET_IFE_SKBPRIO) += act_meta_skbprio.o -obj-$(CONFIG_NET_IFE_SKBTCINDEX) += act_meta_skbtcindex.o -obj-$(CONFIG_NET_ACT_TUNNEL_KEY)+= act_tunnel_key.o -obj-$(CONFIG_NET_SCH_FIFO) += sch_fifo.o -obj-$(CONFIG_NET_SCH_CBQ) += sch_cbq.o -obj-$(CONFIG_NET_SCH_HTB) += sch_htb.o -obj-$(CONFIG_NET_SCH_HFSC) += sch_hfsc.o -obj-$(CONFIG_NET_SCH_RED) += sch_red.o -obj-$(CONFIG_NET_SCH_GRED) += sch_gred.o -obj-$(CONFIG_NET_SCH_INGRESS) += sch_ingress.o -obj-$(CONFIG_NET_SCH_DSMARK) += sch_dsmark.o -obj-$(CONFIG_NET_SCH_SFB) += sch_sfb.o -obj-$(CONFIG_NET_SCH_SFQ) += sch_sfq.o -obj-$(CONFIG_NET_SCH_TBF) += sch_tbf.o -obj-$(CONFIG_NET_SCH_TEQL) += sch_teql.o -obj-$(CONFIG_NET_SCH_PRIO) += sch_prio.o -obj-$(CONFIG_NET_SCH_MULTIQ) += sch_multiq.o -obj-$(CONFIG_NET_SCH_ATM) += sch_atm.o -obj-$(CONFIG_NET_SCH_NETEM) += sch_netem.o -obj-$(CONFIG_NET_SCH_DRR) += sch_drr.o -obj-$(CONFIG_NET_SCH_PLUG) += sch_plug.o -obj-$(CONFIG_NET_SCH_MQPRIO) += sch_mqprio.o -obj-$(CONFIG_NET_SCH_CHOKE) += sch_choke.o -obj-$(CONFIG_NET_SCH_QFQ) += sch_qfq.o -obj-$(CONFIG_NET_SCH_CODEL) += sch_codel.o -obj-$(CONFIG_NET_SCH_FQ_CODEL) += sch_fq_codel.o -obj-$(CONFIG_NET_SCH_FQ) += sch_fq.o -obj-$(CONFIG_NET_SCH_HHF) += sch_hhf.o -obj-$(CONFIG_NET_SCH_PIE) += sch_pie.o - -obj-$(CONFIG_NET_CLS_U32) += cls_u32.o -obj-$(CONFIG_NET_CLS_ROUTE4) += cls_route.o -obj-$(CONFIG_NET_CLS_FW) += cls_fw.o -obj-$(CONFIG_NET_CLS_RSVP) += cls_rsvp.o -obj-$(CONFIG_NET_CLS_TCINDEX) += cls_tcindex.o -obj-$(CONFIG_NET_CLS_RSVP6) += cls_rsvp6.o -obj-$(CONFIG_NET_CLS_BASIC) += cls_basic.o -obj-$(CONFIG_NET_CLS_FLOW) += cls_flow.o -obj-$(CONFIG_NET_CLS_CGROUP) += cls_cgroup.o -obj-$(CONFIG_NET_CLS_BPF) += cls_bpf.o -obj-$(CONFIG_NET_CLS_FLOWER) += cls_flower.o -obj-$(CONFIG_NET_CLS_MATCHALL) += cls_matchall.o -obj-$(CONFIG_NET_EMATCH) += ematch.o -obj-$(CONFIG_NET_EMATCH_CMP) += em_cmp.o -obj-$(CONFIG_NET_EMATCH_NBYTE) += em_nbyte.o -obj-$(CONFIG_NET_EMATCH_U32) += em_u32.o -obj-$(CONFIG_NET_EMATCH_META) += em_meta.o -obj-$(CONFIG_NET_EMATCH_TEXT) += em_text.o -obj-$(CONFIG_NET_EMATCH_CANID) += em_canid.o -obj-$(CONFIG_NET_EMATCH_IPSET) += em_ipset.o diff --git a/src/linux/net/sched/sch_generic.c b/src/linux/net/sched/sch_generic.c deleted file mode 100644 index 6cfb6e9..0000000 --- a/src/linux/net/sched/sch_generic.c +++ /dev/null @@ -1,1021 +0,0 @@ -/* - * net/sched/sch_generic.c Generic packet scheduler routines. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, - * Jamal Hadi Salim, 990601 - * - Ingress support - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* Qdisc to use by default */ -const struct Qdisc_ops *default_qdisc_ops = &pfifo_fast_ops; -EXPORT_SYMBOL(default_qdisc_ops); - -/* Main transmission queue. */ - -/* Modifications to data participating in scheduling must be protected with - * qdisc_lock(qdisc) spinlock. - * - * The idea is the following: - * - enqueue, dequeue are serialized via qdisc root lock - * - ingress filtering is also serialized via qdisc root lock - * - updates to tree and tree walking are only done under the rtnl mutex. - */ - -static inline int dev_requeue_skb(struct sk_buff *skb, struct Qdisc *q) -{ - q->gso_skb = skb; - q->qstats.requeues++; - qdisc_qstats_backlog_inc(q, skb); - q->q.qlen++; /* it's still part of the queue */ - __netif_schedule(q); - - return 0; -} - -static void try_bulk_dequeue_skb(struct Qdisc *q, - struct sk_buff *skb, - const struct netdev_queue *txq, - int *packets) -{ - int bytelimit = qdisc_avail_bulklimit(txq) - skb->len; - - while (bytelimit > 0) { - struct sk_buff *nskb = q->dequeue(q); - - if (!nskb) - break; - - bytelimit -= nskb->len; /* covers GSO len */ - skb->next = nskb; - skb = nskb; - (*packets)++; /* GSO counts as one pkt */ - } - skb->next = NULL; -} - -/* This variant of try_bulk_dequeue_skb() makes sure - * all skbs in the chain are for the same txq - */ -static void try_bulk_dequeue_skb_slow(struct Qdisc *q, - struct sk_buff *skb, - int *packets) -{ - int mapping = skb_get_queue_mapping(skb); - struct sk_buff *nskb; - int cnt = 0; - - do { - nskb = q->dequeue(q); - if (!nskb) - break; - if (unlikely(skb_get_queue_mapping(nskb) != mapping)) { - q->skb_bad_txq = nskb; - qdisc_qstats_backlog_inc(q, nskb); - q->q.qlen++; - break; - } - skb->next = nskb; - skb = nskb; - } while (++cnt < 8); - (*packets) += cnt; - skb->next = NULL; -} - -/* Note that dequeue_skb can possibly return a SKB list (via skb->next). - * A requeued skb (via q->gso_skb) can also be a SKB list. - */ -static struct sk_buff *dequeue_skb(struct Qdisc *q, bool *validate, - int *packets) -{ - struct sk_buff *skb = q->gso_skb; - const struct netdev_queue *txq = q->dev_queue; - - *packets = 1; - if (unlikely(skb)) { - /* skb in gso_skb were already validated */ - *validate = false; - /* check the reason of requeuing without tx lock first */ - txq = skb_get_tx_queue(txq->dev, skb); - if (!netif_xmit_frozen_or_stopped(txq)) { - q->gso_skb = NULL; - qdisc_qstats_backlog_dec(q, skb); - q->q.qlen--; - } else - skb = NULL; - return skb; - } - *validate = true; - skb = q->skb_bad_txq; - if (unlikely(skb)) { - /* check the reason of requeuing without tx lock first */ - txq = skb_get_tx_queue(txq->dev, skb); - if (!netif_xmit_frozen_or_stopped(txq)) { - q->skb_bad_txq = NULL; - qdisc_qstats_backlog_dec(q, skb); - q->q.qlen--; - goto bulk; - } - return NULL; - } - if (!(q->flags & TCQ_F_ONETXQUEUE) || - !netif_xmit_frozen_or_stopped(txq)) - skb = q->dequeue(q); - if (skb) { -bulk: - if (qdisc_may_bulk(q)) - try_bulk_dequeue_skb(q, skb, txq, packets); - else - try_bulk_dequeue_skb_slow(q, skb, packets); - } - return skb; -} - -/* - * Transmit possibly several skbs, and handle the return status as - * required. Owning running seqcount bit guarantees that - * only one CPU can execute this function. - * - * Returns to the caller: - * 0 - queue is empty or throttled. - * >0 - queue is not empty. - */ -int sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, - struct net_device *dev, struct netdev_queue *txq, - spinlock_t *root_lock, bool validate) -{ - int ret = NETDEV_TX_BUSY; - - /* And release qdisc */ - spin_unlock(root_lock); - - /* Note that we validate skb (GSO, checksum, ...) outside of locks */ - if (validate) - skb = validate_xmit_skb_list(skb, dev); - - if (likely(skb)) { - HARD_TX_LOCK(dev, txq, smp_processor_id()); - if (!netif_xmit_frozen_or_stopped(txq)) - skb = dev_hard_start_xmit(skb, dev, txq, &ret); - - HARD_TX_UNLOCK(dev, txq); - } else { - spin_lock(root_lock); - return qdisc_qlen(q); - } - spin_lock(root_lock); - - if (dev_xmit_complete(ret)) { - /* Driver sent out skb successfully or skb was consumed */ - ret = qdisc_qlen(q); - } else { - /* Driver returned NETDEV_TX_BUSY - requeue skb */ - if (unlikely(ret != NETDEV_TX_BUSY)) - net_warn_ratelimited("BUG %s code %d qlen %d\n", - dev->name, ret, q->q.qlen); - - ret = dev_requeue_skb(skb, q); - } - - if (ret && netif_xmit_frozen_or_stopped(txq)) - ret = 0; - - return ret; -} - -/* - * NOTE: Called under qdisc_lock(q) with locally disabled BH. - * - * running seqcount guarantees only one CPU can process - * this qdisc at a time. qdisc_lock(q) serializes queue accesses for - * this queue. - * - * netif_tx_lock serializes accesses to device driver. - * - * qdisc_lock(q) and netif_tx_lock are mutually exclusive, - * if one is grabbed, another must be free. - * - * Note, that this procedure can be called by a watchdog timer - * - * Returns to the caller: - * 0 - queue is empty or throttled. - * >0 - queue is not empty. - * - */ -static inline int qdisc_restart(struct Qdisc *q, int *packets) -{ - struct netdev_queue *txq; - struct net_device *dev; - spinlock_t *root_lock; - struct sk_buff *skb; - bool validate; - - /* Dequeue packet */ - skb = dequeue_skb(q, &validate, packets); - if (unlikely(!skb)) - return 0; - - root_lock = qdisc_lock(q); - dev = qdisc_dev(q); - txq = skb_get_tx_queue(dev, skb); - - return sch_direct_xmit(skb, q, dev, txq, root_lock, validate); -} - -void __qdisc_run(struct Qdisc *q) -{ - int quota = weight_p; - int packets; - - while (qdisc_restart(q, &packets)) { - /* - * Ordered by possible occurrence: Postpone processing if - * 1. we've exceeded packet quota - * 2. another process needs the CPU; - */ - quota -= packets; - if (quota <= 0 || need_resched()) { - __netif_schedule(q); - break; - } - } - - qdisc_run_end(q); -} - -unsigned long dev_trans_start(struct net_device *dev) -{ - unsigned long val, res; - unsigned int i; - - if (is_vlan_dev(dev)) - dev = vlan_dev_real_dev(dev); - res = netdev_get_tx_queue(dev, 0)->trans_start; - for (i = 1; i < dev->num_tx_queues; i++) { - val = netdev_get_tx_queue(dev, i)->trans_start; - if (val && time_after(val, res)) - res = val; - } - - return res; -} -EXPORT_SYMBOL(dev_trans_start); - -static void dev_watchdog(unsigned long arg) -{ - struct net_device *dev = (struct net_device *)arg; - - netif_tx_lock(dev); - if (!qdisc_tx_is_noop(dev)) { - if (netif_device_present(dev) && - netif_running(dev) && - netif_carrier_ok(dev)) { - int some_queue_timedout = 0; - unsigned int i; - unsigned long trans_start; - - for (i = 0; i < dev->num_tx_queues; i++) { - struct netdev_queue *txq; - - txq = netdev_get_tx_queue(dev, i); - trans_start = txq->trans_start; - if (netif_xmit_stopped(txq) && - time_after(jiffies, (trans_start + - dev->watchdog_timeo))) { - some_queue_timedout = 1; - txq->trans_timeout++; - break; - } - } - - if (some_queue_timedout) { - WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit queue %u timed out\n", - dev->name, netdev_drivername(dev), i); - dev->netdev_ops->ndo_tx_timeout(dev); - } - if (!mod_timer(&dev->watchdog_timer, - round_jiffies(jiffies + - dev->watchdog_timeo))) - dev_hold(dev); - } - } - netif_tx_unlock(dev); - - dev_put(dev); -} - -void __netdev_watchdog_up(struct net_device *dev) -{ - if (dev->netdev_ops->ndo_tx_timeout) { - if (dev->watchdog_timeo <= 0) - dev->watchdog_timeo = 5*HZ; - if (!mod_timer(&dev->watchdog_timer, - round_jiffies(jiffies + dev->watchdog_timeo))) - dev_hold(dev); - } -} - -static void dev_watchdog_up(struct net_device *dev) -{ - __netdev_watchdog_up(dev); -} - -static void dev_watchdog_down(struct net_device *dev) -{ - netif_tx_lock_bh(dev); - if (del_timer(&dev->watchdog_timer)) - dev_put(dev); - netif_tx_unlock_bh(dev); -} - -/** - * netif_carrier_on - set carrier - * @dev: network device - * - * Device has detected that carrier. - */ -void netif_carrier_on(struct net_device *dev) -{ - if (test_and_clear_bit(__LINK_STATE_NOCARRIER, &dev->state)) { - if (dev->reg_state == NETREG_UNINITIALIZED) - return; - atomic_inc(&dev->carrier_changes); - linkwatch_fire_event(dev); - if (netif_running(dev)) - __netdev_watchdog_up(dev); - } -} -EXPORT_SYMBOL(netif_carrier_on); - -/** - * netif_carrier_off - clear carrier - * @dev: network device - * - * Device has detected loss of carrier. - */ -void netif_carrier_off(struct net_device *dev) -{ - if (!test_and_set_bit(__LINK_STATE_NOCARRIER, &dev->state)) { - if (dev->reg_state == NETREG_UNINITIALIZED) - return; - atomic_inc(&dev->carrier_changes); - linkwatch_fire_event(dev); - } -} -EXPORT_SYMBOL(netif_carrier_off); - -/* "NOOP" scheduler: the best scheduler, recommended for all interfaces - under all circumstances. It is difficult to invent anything faster or - cheaper. - */ - -static int noop_enqueue(struct sk_buff *skb, struct Qdisc *qdisc, - struct sk_buff **to_free) -{ - __qdisc_drop(skb, to_free); - return NET_XMIT_CN; -} - -static struct sk_buff *noop_dequeue(struct Qdisc *qdisc) -{ - return NULL; -} - -struct Qdisc_ops noop_qdisc_ops __read_mostly = { - .id = "noop", - .priv_size = 0, - .enqueue = noop_enqueue, - .dequeue = noop_dequeue, - .peek = noop_dequeue, - .owner = THIS_MODULE, -}; - -static struct netdev_queue noop_netdev_queue = { - .qdisc = &noop_qdisc, - .qdisc_sleeping = &noop_qdisc, -}; - -struct Qdisc noop_qdisc = { - .enqueue = noop_enqueue, - .dequeue = noop_dequeue, - .flags = TCQ_F_BUILTIN, - .ops = &noop_qdisc_ops, - .q.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock), - .dev_queue = &noop_netdev_queue, - .running = SEQCNT_ZERO(noop_qdisc.running), - .busylock = __SPIN_LOCK_UNLOCKED(noop_qdisc.busylock), -}; -EXPORT_SYMBOL(noop_qdisc); - -static int noqueue_init(struct Qdisc *qdisc, struct nlattr *opt) -{ - /* register_qdisc() assigns a default of noop_enqueue if unset, - * but __dev_queue_xmit() treats noqueue only as such - * if this is NULL - so clear it here. */ - qdisc->enqueue = NULL; - return 0; -} - -struct Qdisc_ops noqueue_qdisc_ops __read_mostly = { - .id = "noqueue", - .priv_size = 0, - .init = noqueue_init, - .enqueue = noop_enqueue, - .dequeue = noop_dequeue, - .peek = noop_dequeue, - .owner = THIS_MODULE, -}; - -static const u8 prio2band[TC_PRIO_MAX + 1] = { - 1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1 -}; - -/* 3-band FIFO queue: old style, but should be a bit faster than - generic prio+fifo combination. - */ - -#define PFIFO_FAST_BANDS 3 - -/* - * Private data for a pfifo_fast scheduler containing: - * - queues for the three band - * - bitmap indicating which of the bands contain skbs - */ -struct pfifo_fast_priv { - u32 bitmap; - struct qdisc_skb_head q[PFIFO_FAST_BANDS]; -}; - -/* - * Convert a bitmap to the first band number where an skb is queued, where: - * bitmap=0 means there are no skbs on any band. - * bitmap=1 means there is an skb on band 0. - * bitmap=7 means there are skbs on all 3 bands, etc. - */ -static const int bitmap2band[] = {-1, 0, 1, 0, 2, 0, 1, 0}; - -static inline struct qdisc_skb_head *band2list(struct pfifo_fast_priv *priv, - int band) -{ - return priv->q + band; -} - -static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc, - struct sk_buff **to_free) -{ - if (qdisc->q.qlen < qdisc_dev(qdisc)->tx_queue_len) { - int band = prio2band[skb->priority & TC_PRIO_MAX]; - struct pfifo_fast_priv *priv = qdisc_priv(qdisc); - struct qdisc_skb_head *list = band2list(priv, band); - - priv->bitmap |= (1 << band); - qdisc->q.qlen++; - return __qdisc_enqueue_tail(skb, qdisc, list); - } - - return qdisc_drop(skb, qdisc, to_free); -} - -static struct sk_buff *pfifo_fast_dequeue(struct Qdisc *qdisc) -{ - struct pfifo_fast_priv *priv = qdisc_priv(qdisc); - int band = bitmap2band[priv->bitmap]; - - if (likely(band >= 0)) { - struct qdisc_skb_head *qh = band2list(priv, band); - struct sk_buff *skb = __qdisc_dequeue_head(qh); - - if (likely(skb != NULL)) { - qdisc_qstats_backlog_dec(qdisc, skb); - qdisc_bstats_update(qdisc, skb); - } - - qdisc->q.qlen--; - if (qh->qlen == 0) - priv->bitmap &= ~(1 << band); - - return skb; - } - - return NULL; -} - -static struct sk_buff *pfifo_fast_peek(struct Qdisc *qdisc) -{ - struct pfifo_fast_priv *priv = qdisc_priv(qdisc); - int band = bitmap2band[priv->bitmap]; - - if (band >= 0) { - struct qdisc_skb_head *qh = band2list(priv, band); - - return qh->head; - } - - return NULL; -} - -static void pfifo_fast_reset(struct Qdisc *qdisc) -{ - int prio; - struct pfifo_fast_priv *priv = qdisc_priv(qdisc); - - for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) - __qdisc_reset_queue(band2list(priv, prio)); - - priv->bitmap = 0; - qdisc->qstats.backlog = 0; - qdisc->q.qlen = 0; -} - -static int pfifo_fast_dump(struct Qdisc *qdisc, struct sk_buff *skb) -{ - struct tc_prio_qopt opt = { .bands = PFIFO_FAST_BANDS }; - - memcpy(&opt.priomap, prio2band, TC_PRIO_MAX + 1); - if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt)) - goto nla_put_failure; - return skb->len; - -nla_put_failure: - return -1; -} - -static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt) -{ - int prio; - struct pfifo_fast_priv *priv = qdisc_priv(qdisc); - - for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) - qdisc_skb_head_init(band2list(priv, prio)); - - /* Can by-pass the queue discipline */ - qdisc->flags |= TCQ_F_CAN_BYPASS; - return 0; -} - -struct Qdisc_ops pfifo_fast_ops __read_mostly = { - .id = "pfifo_fast", - .priv_size = sizeof(struct pfifo_fast_priv), - .enqueue = pfifo_fast_enqueue, - .dequeue = pfifo_fast_dequeue, - .peek = pfifo_fast_peek, - .init = pfifo_fast_init, - .reset = pfifo_fast_reset, - .dump = pfifo_fast_dump, - .owner = THIS_MODULE, -}; -EXPORT_SYMBOL(pfifo_fast_ops); - -static struct lock_class_key qdisc_tx_busylock; -static struct lock_class_key qdisc_running_key; - -struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, - const struct Qdisc_ops *ops) -{ - void *p; - struct Qdisc *sch; - unsigned int size = QDISC_ALIGN(sizeof(*sch)) + ops->priv_size; - int err = -ENOBUFS; - struct net_device *dev = dev_queue->dev; - - p = kzalloc_node(size, GFP_KERNEL, - netdev_queue_numa_node_read(dev_queue)); - - if (!p) - goto errout; - sch = (struct Qdisc *) QDISC_ALIGN((unsigned long) p); - /* if we got non aligned memory, ask more and do alignment ourself */ - if (sch != p) { - kfree(p); - p = kzalloc_node(size + QDISC_ALIGNTO - 1, GFP_KERNEL, - netdev_queue_numa_node_read(dev_queue)); - if (!p) - goto errout; - sch = (struct Qdisc *) QDISC_ALIGN((unsigned long) p); - sch->padded = (char *) sch - (char *) p; - } - qdisc_skb_head_init(&sch->q); - spin_lock_init(&sch->q.lock); - - spin_lock_init(&sch->busylock); - lockdep_set_class(&sch->busylock, - dev->qdisc_tx_busylock ?: &qdisc_tx_busylock); - - seqcount_init(&sch->running); - lockdep_set_class(&sch->running, - dev->qdisc_running_key ?: &qdisc_running_key); - - sch->ops = ops; - sch->enqueue = ops->enqueue; - sch->dequeue = ops->dequeue; - sch->dev_queue = dev_queue; - dev_hold(dev); - atomic_set(&sch->refcnt, 1); - - return sch; -errout: - return ERR_PTR(err); -} - -struct Qdisc *qdisc_create_dflt(struct netdev_queue *dev_queue, - const struct Qdisc_ops *ops, - unsigned int parentid) -{ - struct Qdisc *sch; - - if (!try_module_get(ops->owner)) - return NULL; - - sch = qdisc_alloc(dev_queue, ops); - if (IS_ERR(sch)) { - module_put(ops->owner); - return NULL; - } - sch->parent = parentid; - - if (!ops->init || ops->init(sch, NULL) == 0) - return sch; - - qdisc_destroy(sch); - return NULL; -} -EXPORT_SYMBOL(qdisc_create_dflt); - -/* Under qdisc_lock(qdisc) and BH! */ - -void qdisc_reset(struct Qdisc *qdisc) -{ - const struct Qdisc_ops *ops = qdisc->ops; - - if (ops->reset) - ops->reset(qdisc); - - kfree_skb(qdisc->skb_bad_txq); - qdisc->skb_bad_txq = NULL; - - if (qdisc->gso_skb) { - kfree_skb_list(qdisc->gso_skb); - qdisc->gso_skb = NULL; - } - qdisc->q.qlen = 0; -} -EXPORT_SYMBOL(qdisc_reset); - -static void qdisc_rcu_free(struct rcu_head *head) -{ - struct Qdisc *qdisc = container_of(head, struct Qdisc, rcu_head); - - if (qdisc_is_percpu_stats(qdisc)) { - free_percpu(qdisc->cpu_bstats); - free_percpu(qdisc->cpu_qstats); - } - - kfree((char *) qdisc - qdisc->padded); -} - -void qdisc_destroy(struct Qdisc *qdisc) -{ - const struct Qdisc_ops *ops = qdisc->ops; - - if (qdisc->flags & TCQ_F_BUILTIN || - !atomic_dec_and_test(&qdisc->refcnt)) - return; - -#ifdef CONFIG_NET_SCHED - qdisc_hash_del(qdisc); - - qdisc_put_stab(rtnl_dereference(qdisc->stab)); -#endif - gen_kill_estimator(&qdisc->bstats, &qdisc->rate_est); - if (ops->reset) - ops->reset(qdisc); - if (ops->destroy) - ops->destroy(qdisc); - - module_put(ops->owner); - dev_put(qdisc_dev(qdisc)); - - kfree_skb_list(qdisc->gso_skb); - kfree_skb(qdisc->skb_bad_txq); - /* - * gen_estimator est_timer() might access qdisc->q.lock, - * wait a RCU grace period before freeing qdisc. - */ - call_rcu(&qdisc->rcu_head, qdisc_rcu_free); -} -EXPORT_SYMBOL(qdisc_destroy); - -/* Attach toplevel qdisc to device queue. */ -struct Qdisc *dev_graft_qdisc(struct netdev_queue *dev_queue, - struct Qdisc *qdisc) -{ - struct Qdisc *oqdisc = dev_queue->qdisc_sleeping; - spinlock_t *root_lock; - - root_lock = qdisc_lock(oqdisc); - spin_lock_bh(root_lock); - - /* Prune old scheduler */ - if (oqdisc && atomic_read(&oqdisc->refcnt) <= 1) - qdisc_reset(oqdisc); - - /* ... and graft new one */ - if (qdisc == NULL) - qdisc = &noop_qdisc; - dev_queue->qdisc_sleeping = qdisc; - rcu_assign_pointer(dev_queue->qdisc, &noop_qdisc); - - spin_unlock_bh(root_lock); - - return oqdisc; -} -EXPORT_SYMBOL(dev_graft_qdisc); - -static void attach_one_default_qdisc(struct net_device *dev, - struct netdev_queue *dev_queue, - void *_unused) -{ - struct Qdisc *qdisc; - const struct Qdisc_ops *ops = default_qdisc_ops; - - if (dev->priv_flags & IFF_NO_QUEUE) - ops = &noqueue_qdisc_ops; - - qdisc = qdisc_create_dflt(dev_queue, ops, TC_H_ROOT); - if (!qdisc) { - netdev_info(dev, "activation failed\n"); - return; - } - if (!netif_is_multiqueue(dev)) - qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; - dev_queue->qdisc_sleeping = qdisc; -} - -static void attach_default_qdiscs(struct net_device *dev) -{ - struct netdev_queue *txq; - struct Qdisc *qdisc; - - txq = netdev_get_tx_queue(dev, 0); - - if (!netif_is_multiqueue(dev) || - dev->priv_flags & IFF_NO_QUEUE) { - netdev_for_each_tx_queue(dev, attach_one_default_qdisc, NULL); - dev->qdisc = txq->qdisc_sleeping; - atomic_inc(&dev->qdisc->refcnt); - } else { - qdisc = qdisc_create_dflt(txq, &mq_qdisc_ops, TC_H_ROOT); - if (qdisc) { - dev->qdisc = qdisc; - qdisc->ops->attach(qdisc); - } - } -#ifdef CONFIG_NET_SCHED - if (dev->qdisc) - qdisc_hash_add(dev->qdisc); -#endif -} - -static void transition_one_qdisc(struct net_device *dev, - struct netdev_queue *dev_queue, - void *_need_watchdog) -{ - struct Qdisc *new_qdisc = dev_queue->qdisc_sleeping; - int *need_watchdog_p = _need_watchdog; - - if (!(new_qdisc->flags & TCQ_F_BUILTIN)) - clear_bit(__QDISC_STATE_DEACTIVATED, &new_qdisc->state); - - rcu_assign_pointer(dev_queue->qdisc, new_qdisc); - if (need_watchdog_p) { - dev_queue->trans_start = 0; - *need_watchdog_p = 1; - } -} - -void dev_activate(struct net_device *dev) -{ - int need_watchdog; - - /* No queueing discipline is attached to device; - * create default one for devices, which need queueing - * and noqueue_qdisc for virtual interfaces - */ - - if (dev->qdisc == &noop_qdisc) - attach_default_qdiscs(dev); - - if (!netif_carrier_ok(dev)) - /* Delay activation until next carrier-on event */ - return; - - need_watchdog = 0; - netdev_for_each_tx_queue(dev, transition_one_qdisc, &need_watchdog); - if (dev_ingress_queue(dev)) - transition_one_qdisc(dev, dev_ingress_queue(dev), NULL); - - if (need_watchdog) { - netif_trans_update(dev); - dev_watchdog_up(dev); - } -} -EXPORT_SYMBOL(dev_activate); - -static void dev_deactivate_queue(struct net_device *dev, - struct netdev_queue *dev_queue, - void *_qdisc_default) -{ - struct Qdisc *qdisc_default = _qdisc_default; - struct Qdisc *qdisc; - - qdisc = rtnl_dereference(dev_queue->qdisc); - if (qdisc) { - spin_lock_bh(qdisc_lock(qdisc)); - - if (!(qdisc->flags & TCQ_F_BUILTIN)) - set_bit(__QDISC_STATE_DEACTIVATED, &qdisc->state); - - rcu_assign_pointer(dev_queue->qdisc, qdisc_default); - qdisc_reset(qdisc); - - spin_unlock_bh(qdisc_lock(qdisc)); - } -} - -static bool some_qdisc_is_busy(struct net_device *dev) -{ - unsigned int i; - - for (i = 0; i < dev->num_tx_queues; i++) { - struct netdev_queue *dev_queue; - spinlock_t *root_lock; - struct Qdisc *q; - int val; - - dev_queue = netdev_get_tx_queue(dev, i); - q = dev_queue->qdisc_sleeping; - root_lock = qdisc_lock(q); - - spin_lock_bh(root_lock); - - val = (qdisc_is_running(q) || - test_bit(__QDISC_STATE_SCHED, &q->state)); - - spin_unlock_bh(root_lock); - - if (val) - return true; - } - return false; -} - -/** - * dev_deactivate_many - deactivate transmissions on several devices - * @head: list of devices to deactivate - * - * This function returns only when all outstanding transmissions - * have completed, unless all devices are in dismantle phase. - */ -void dev_deactivate_many(struct list_head *head) -{ - struct net_device *dev; - bool sync_needed = false; - - list_for_each_entry(dev, head, close_list) { - netdev_for_each_tx_queue(dev, dev_deactivate_queue, - &noop_qdisc); - if (dev_ingress_queue(dev)) - dev_deactivate_queue(dev, dev_ingress_queue(dev), - &noop_qdisc); - - dev_watchdog_down(dev); - sync_needed |= !dev->dismantle; - } - - /* Wait for outstanding qdisc-less dev_queue_xmit calls. - * This is avoided if all devices are in dismantle phase : - * Caller will call synchronize_net() for us - */ - if (sync_needed) - synchronize_net(); - - /* Wait for outstanding qdisc_run calls. */ - list_for_each_entry(dev, head, close_list) - while (some_qdisc_is_busy(dev)) - yield(); -} - -void dev_deactivate(struct net_device *dev) -{ - LIST_HEAD(single); - - list_add(&dev->close_list, &single); - dev_deactivate_many(&single); - list_del(&single); -} -EXPORT_SYMBOL(dev_deactivate); - -static void dev_init_scheduler_queue(struct net_device *dev, - struct netdev_queue *dev_queue, - void *_qdisc) -{ - struct Qdisc *qdisc = _qdisc; - - rcu_assign_pointer(dev_queue->qdisc, qdisc); - dev_queue->qdisc_sleeping = qdisc; -} - -void dev_init_scheduler(struct net_device *dev) -{ - dev->qdisc = &noop_qdisc; - netdev_for_each_tx_queue(dev, dev_init_scheduler_queue, &noop_qdisc); - if (dev_ingress_queue(dev)) - dev_init_scheduler_queue(dev, dev_ingress_queue(dev), &noop_qdisc); - - setup_timer(&dev->watchdog_timer, dev_watchdog, (unsigned long)dev); -} - -static void shutdown_scheduler_queue(struct net_device *dev, - struct netdev_queue *dev_queue, - void *_qdisc_default) -{ - struct Qdisc *qdisc = dev_queue->qdisc_sleeping; - struct Qdisc *qdisc_default = _qdisc_default; - - if (qdisc) { - rcu_assign_pointer(dev_queue->qdisc, qdisc_default); - dev_queue->qdisc_sleeping = qdisc_default; - - qdisc_destroy(qdisc); - } -} - -void dev_shutdown(struct net_device *dev) -{ - netdev_for_each_tx_queue(dev, shutdown_scheduler_queue, &noop_qdisc); - if (dev_ingress_queue(dev)) - shutdown_scheduler_queue(dev, dev_ingress_queue(dev), &noop_qdisc); - qdisc_destroy(dev->qdisc); - dev->qdisc = &noop_qdisc; - - WARN_ON(timer_pending(&dev->watchdog_timer)); -} - -void psched_ratecfg_precompute(struct psched_ratecfg *r, - const struct tc_ratespec *conf, - u64 rate64) -{ - memset(r, 0, sizeof(*r)); - r->overhead = conf->overhead; - r->rate_bytes_ps = max_t(u64, conf->rate, rate64); - r->linklayer = (conf->linklayer & TC_LINKLAYER_MASK); - r->mult = 1; - /* - * The deal here is to replace a divide by a reciprocal one - * in fast path (a reciprocal divide is a multiply and a shift) - * - * Normal formula would be : - * time_in_ns = (NSEC_PER_SEC * len) / rate_bps - * - * We compute mult/shift to use instead : - * time_in_ns = (len * mult) >> shift; - * - * We try to get the highest possible mult value for accuracy, - * but have to make sure no overflows will ever happen. - */ - if (r->rate_bytes_ps > 0) { - u64 factor = NSEC_PER_SEC; - - for (;;) { - r->mult = div64_u64(factor, r->rate_bytes_ps); - if (r->mult & (1U << 31) || factor & (1ULL << 63)) - break; - factor <<= 1; - r->shift++; - } - } -} -EXPORT_SYMBOL(psched_ratecfg_precompute); diff --git a/src/linux/net/sched/sch_mq.c b/src/linux/net/sched/sch_mq.c deleted file mode 100644 index 2bc8d7f..0000000 --- a/src/linux/net/sched/sch_mq.c +++ /dev/null @@ -1,246 +0,0 @@ -/* - * net/sched/sch_mq.c Classful multiqueue dummy scheduler - * - * Copyright (c) 2009 Patrick McHardy - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -struct mq_sched { - struct Qdisc **qdiscs; -}; - -static void mq_destroy(struct Qdisc *sch) -{ - struct net_device *dev = qdisc_dev(sch); - struct mq_sched *priv = qdisc_priv(sch); - unsigned int ntx; - - if (!priv->qdiscs) - return; - for (ntx = 0; ntx < dev->num_tx_queues && priv->qdiscs[ntx]; ntx++) - qdisc_destroy(priv->qdiscs[ntx]); - kfree(priv->qdiscs); -} - -static int mq_init(struct Qdisc *sch, struct nlattr *opt) -{ - struct net_device *dev = qdisc_dev(sch); - struct mq_sched *priv = qdisc_priv(sch); - struct netdev_queue *dev_queue; - struct Qdisc *qdisc; - unsigned int ntx; - - if (sch->parent != TC_H_ROOT) - return -EOPNOTSUPP; - - if (!netif_is_multiqueue(dev)) - return -EOPNOTSUPP; - - /* pre-allocate qdiscs, attachment can't fail */ - priv->qdiscs = kcalloc(dev->num_tx_queues, sizeof(priv->qdiscs[0]), - GFP_KERNEL); - if (priv->qdiscs == NULL) - return -ENOMEM; - - for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { - dev_queue = netdev_get_tx_queue(dev, ntx); - qdisc = qdisc_create_dflt(dev_queue, get_default_qdisc_ops(dev, ntx), - TC_H_MAKE(TC_H_MAJ(sch->handle), - TC_H_MIN(ntx + 1))); - if (qdisc == NULL) - goto err; - priv->qdiscs[ntx] = qdisc; - qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; - } - - sch->flags |= TCQ_F_MQROOT; - return 0; - -err: - mq_destroy(sch); - return -ENOMEM; -} - -static void mq_attach(struct Qdisc *sch) -{ - struct net_device *dev = qdisc_dev(sch); - struct mq_sched *priv = qdisc_priv(sch); - struct Qdisc *qdisc, *old; - unsigned int ntx; - - for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { - qdisc = priv->qdiscs[ntx]; - old = dev_graft_qdisc(qdisc->dev_queue, qdisc); - if (old) - qdisc_destroy(old); -#ifdef CONFIG_NET_SCHED - if (ntx < dev->real_num_tx_queues) - qdisc_hash_add(qdisc); -#endif - - } - kfree(priv->qdiscs); - priv->qdiscs = NULL; -} - -static int mq_dump(struct Qdisc *sch, struct sk_buff *skb) -{ - struct net_device *dev = qdisc_dev(sch); - struct Qdisc *qdisc; - unsigned int ntx; - - sch->q.qlen = 0; - memset(&sch->bstats, 0, sizeof(sch->bstats)); - memset(&sch->qstats, 0, sizeof(sch->qstats)); - - for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { - qdisc = netdev_get_tx_queue(dev, ntx)->qdisc_sleeping; - spin_lock_bh(qdisc_lock(qdisc)); - sch->q.qlen += qdisc->q.qlen; - sch->bstats.bytes += qdisc->bstats.bytes; - sch->bstats.packets += qdisc->bstats.packets; - sch->qstats.backlog += qdisc->qstats.backlog; - sch->qstats.drops += qdisc->qstats.drops; - sch->qstats.requeues += qdisc->qstats.requeues; - sch->qstats.overlimits += qdisc->qstats.overlimits; - spin_unlock_bh(qdisc_lock(qdisc)); - } - return 0; -} - -static struct netdev_queue *mq_queue_get(struct Qdisc *sch, unsigned long cl) -{ - struct net_device *dev = qdisc_dev(sch); - unsigned long ntx = cl - 1; - - if (ntx >= dev->num_tx_queues) - return NULL; - return netdev_get_tx_queue(dev, ntx); -} - -static struct netdev_queue *mq_select_queue(struct Qdisc *sch, - struct tcmsg *tcm) -{ - unsigned int ntx = TC_H_MIN(tcm->tcm_parent); - struct netdev_queue *dev_queue = mq_queue_get(sch, ntx); - - if (!dev_queue) { - struct net_device *dev = qdisc_dev(sch); - - return netdev_get_tx_queue(dev, 0); - } - return dev_queue; -} - -static int mq_graft(struct Qdisc *sch, unsigned long cl, struct Qdisc *new, - struct Qdisc **old) -{ - struct netdev_queue *dev_queue = mq_queue_get(sch, cl); - struct net_device *dev = qdisc_dev(sch); - - if (dev->flags & IFF_UP) - dev_deactivate(dev); - - *old = dev_graft_qdisc(dev_queue, new); - if (new) - new->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; - if (dev->flags & IFF_UP) - dev_activate(dev); - return 0; -} - -static struct Qdisc *mq_leaf(struct Qdisc *sch, unsigned long cl) -{ - struct netdev_queue *dev_queue = mq_queue_get(sch, cl); - - return dev_queue->qdisc_sleeping; -} - -static unsigned long mq_get(struct Qdisc *sch, u32 classid) -{ - unsigned int ntx = TC_H_MIN(classid); - - if (!mq_queue_get(sch, ntx)) - return 0; - return ntx; -} - -static void mq_put(struct Qdisc *sch, unsigned long cl) -{ -} - -static int mq_dump_class(struct Qdisc *sch, unsigned long cl, - struct sk_buff *skb, struct tcmsg *tcm) -{ - struct netdev_queue *dev_queue = mq_queue_get(sch, cl); - - tcm->tcm_parent = TC_H_ROOT; - tcm->tcm_handle |= TC_H_MIN(cl); - tcm->tcm_info = dev_queue->qdisc_sleeping->handle; - return 0; -} - -static int mq_dump_class_stats(struct Qdisc *sch, unsigned long cl, - struct gnet_dump *d) -{ - struct netdev_queue *dev_queue = mq_queue_get(sch, cl); - - sch = dev_queue->qdisc_sleeping; - if (gnet_stats_copy_basic(&sch->running, d, NULL, &sch->bstats) < 0 || - gnet_stats_copy_queue(d, NULL, &sch->qstats, sch->q.qlen) < 0) - return -1; - return 0; -} - -static void mq_walk(struct Qdisc *sch, struct qdisc_walker *arg) -{ - struct net_device *dev = qdisc_dev(sch); - unsigned int ntx; - - if (arg->stop) - return; - - arg->count = arg->skip; - for (ntx = arg->skip; ntx < dev->num_tx_queues; ntx++) { - if (arg->fn(sch, ntx + 1, arg) < 0) { - arg->stop = 1; - break; - } - arg->count++; - } -} - -static const struct Qdisc_class_ops mq_class_ops = { - .select_queue = mq_select_queue, - .graft = mq_graft, - .leaf = mq_leaf, - .get = mq_get, - .put = mq_put, - .walk = mq_walk, - .dump = mq_dump_class, - .dump_stats = mq_dump_class_stats, -}; - -struct Qdisc_ops mq_qdisc_ops __read_mostly = { - .cl_ops = &mq_class_ops, - .id = "mq", - .priv_size = sizeof(struct mq_sched), - .init = mq_init, - .destroy = mq_destroy, - .attach = mq_attach, - .dump = mq_dump, - .owner = THIS_MODULE, -}; diff --git a/src/linux/net/sctp/Kconfig b/src/linux/net/sctp/Kconfig deleted file mode 100644 index d9c04dc..0000000 --- a/src/linux/net/sctp/Kconfig +++ /dev/null @@ -1,107 +0,0 @@ -# -# SCTP configuration -# - -menuconfig IP_SCTP - tristate "The SCTP Protocol" - depends on INET - depends on IPV6 || IPV6=n - select CRYPTO - select CRYPTO_HMAC - select CRYPTO_SHA1 - select LIBCRC32C - ---help--- - Stream Control Transmission Protocol - - From RFC 2960 . - - "SCTP is a reliable transport protocol operating on top of a - connectionless packet network such as IP. It offers the following - services to its users: - - -- acknowledged error-free non-duplicated transfer of user data, - -- data fragmentation to conform to discovered path MTU size, - -- sequenced delivery of user messages within multiple streams, - with an option for order-of-arrival delivery of individual user - messages, - -- optional bundling of multiple user messages into a single SCTP - packet, and - -- network-level fault tolerance through supporting of multi- - homing at either or both ends of an association." - - To compile this protocol support as a module, choose M here: the - module will be called sctp. Debug messages are handeled by the - kernel's dynamic debugging framework. - - If in doubt, say N. - -if IP_SCTP - -config NET_SCTPPROBE - tristate "SCTP: Association probing" - depends on PROC_FS && KPROBES - ---help--- - This module allows for capturing the changes to SCTP association - state in response to incoming packets. It is used for debugging - SCTP congestion control algorithms. If you don't understand - what was just said, you don't need it: say N. - - To compile this code as a module, choose M here: the - module will be called sctp_probe. - -config SCTP_DBG_OBJCNT - bool "SCTP: Debug object counts" - depends on PROC_FS - help - If you say Y, this will enable debugging support for counting the - type of objects that are currently allocated. This is useful for - identifying memory leaks. This debug information can be viewed by - 'cat /proc/net/sctp/sctp_dbg_objcnt' - - If unsure, say N -choice - prompt "Default SCTP cookie HMAC encoding" - default SCTP_DEFAULT_COOKIE_HMAC_MD5 - help - This option sets the default sctp cookie hmac algorithm - when in doubt select 'md5' - -config SCTP_DEFAULT_COOKIE_HMAC_MD5 - bool "Enable optional MD5 hmac cookie generation" - help - Enable optional MD5 hmac based SCTP cookie generation - select SCTP_COOKIE_HMAC_MD5 - -config SCTP_DEFAULT_COOKIE_HMAC_SHA1 - bool "Enable optional SHA1 hmac cookie generation" - help - Enable optional SHA1 hmac based SCTP cookie generation - select SCTP_COOKIE_HMAC_SHA1 - -config SCTP_DEFAULT_COOKIE_HMAC_NONE - bool "Use no hmac alg in SCTP cookie generation" - help - Use no hmac algorithm in SCTP cookie generation - -endchoice - -config SCTP_COOKIE_HMAC_MD5 - bool "Enable optional MD5 hmac cookie generation" - help - Enable optional MD5 hmac based SCTP cookie generation - select CRYPTO_HMAC if SCTP_COOKIE_HMAC_MD5 - select CRYPTO_MD5 if SCTP_COOKIE_HMAC_MD5 - -config SCTP_COOKIE_HMAC_SHA1 - bool "Enable optional SHA1 hmac cookie generation" - help - Enable optional SHA1 hmac based SCTP cookie generation - select CRYPTO_HMAC if SCTP_COOKIE_HMAC_SHA1 - select CRYPTO_SHA1 if SCTP_COOKIE_HMAC_SHA1 - -config INET_SCTP_DIAG - depends on INET_DIAG - def_tristate INET_DIAG - - -endif # IP_SCTP diff --git a/src/linux/net/socket.c b/src/linux/net/socket.c deleted file mode 100644 index 73dc69f..0000000 --- a/src/linux/net/socket.c +++ /dev/null @@ -1,3312 +0,0 @@ -/* - * NET An implementation of the SOCKET network access protocol. - * - * Version: @(#)socket.c 1.1.93 18/02/95 - * - * Authors: Orest Zborowski, - * Ross Biro - * Fred N. van Kempen, - * - * Fixes: - * Anonymous : NOTSOCK/BADF cleanup. Error fix in - * shutdown() - * Alan Cox : verify_area() fixes - * Alan Cox : Removed DDI - * Jonathan Kamens : SOCK_DGRAM reconnect bug - * Alan Cox : Moved a load of checks to the very - * top level. - * Alan Cox : Move address structures to/from user - * mode above the protocol layers. - * Rob Janssen : Allow 0 length sends. - * Alan Cox : Asynchronous I/O support (cribbed from the - * tty drivers). - * Niibe Yutaka : Asynchronous I/O for writes (4.4BSD style) - * Jeff Uphoff : Made max number of sockets command-line - * configurable. - * Matti Aarnio : Made the number of sockets dynamic, - * to be allocated when needed, and mr. - * Uphoff's max is used as max to be - * allowed to allocate. - * Linus : Argh. removed all the socket allocation - * altogether: it's in the inode now. - * Alan Cox : Made sock_alloc()/sock_release() public - * for NetROM and future kernel nfsd type - * stuff. - * Alan Cox : sendmsg/recvmsg basics. - * Tom Dyas : Export net symbols. - * Marcin Dalecki : Fixed problems with CONFIG_NET="n". - * Alan Cox : Added thread locking to sys_* calls - * for sockets. May have errors at the - * moment. - * Kevin Buhr : Fixed the dumb errors in the above. - * Andi Kleen : Some small cleanups, optimizations, - * and fixed a copy_from_user() bug. - * Tigran Aivazian : sys_send(args) calls sys_sendto(args, NULL, 0) - * Tigran Aivazian : Made listen(2) backlog sanity checks - * protocol-independent - * - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * - * This module is effectively the top level interface to the BSD socket - * paradigm. - * - * Based upon Swansea University Computer Society NET3.039 - */ - -#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 -#include -#include -#include - -#include -#include - -#include -#include -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_NET_RX_BUSY_POLL -unsigned int sysctl_net_busy_read __read_mostly; -unsigned int sysctl_net_busy_poll __read_mostly; -#endif - -static ssize_t sock_read_iter(struct kiocb *iocb, struct iov_iter *to); -static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from); -static int sock_mmap(struct file *file, struct vm_area_struct *vma); - -static int sock_close(struct inode *inode, struct file *file); -static unsigned int sock_poll(struct file *file, - struct poll_table_struct *wait); -static long sock_ioctl(struct file *file, unsigned int cmd, unsigned long arg); -#ifdef CONFIG_COMPAT -static long compat_sock_ioctl(struct file *file, - unsigned int cmd, unsigned long arg); -#endif -static int sock_fasync(int fd, struct file *filp, int on); -static ssize_t sock_sendpage(struct file *file, struct page *page, - int offset, size_t size, loff_t *ppos, int more); -static ssize_t sock_splice_read(struct file *file, loff_t *ppos, - struct pipe_inode_info *pipe, size_t len, - unsigned int flags); - -/* - * Socket files have a set of 'special' operations as well as the generic file ones. These don't appear - * in the operation structures but are done directly via the socketcall() multiplexor. - */ - -static const struct file_operations socket_file_ops = { - .owner = THIS_MODULE, - .llseek = no_llseek, - .read_iter = sock_read_iter, - .write_iter = sock_write_iter, - .poll = sock_poll, - .unlocked_ioctl = sock_ioctl, -#ifdef CONFIG_COMPAT - .compat_ioctl = compat_sock_ioctl, -#endif - .mmap = sock_mmap, - .release = sock_close, - .fasync = sock_fasync, - .sendpage = sock_sendpage, - .splice_write = generic_splice_sendpage, - .splice_read = sock_splice_read, -}; - -/* - * The protocol list. Each protocol is registered in here. - */ - -static DEFINE_SPINLOCK(net_family_lock); -static const struct net_proto_family __rcu *net_families[NPROTO] __read_mostly; - -/* - * Statistics counters of the socket lists - */ - -static DEFINE_PER_CPU(int, sockets_in_use); - -/* - * Support routines. - * Move socket addresses back and forth across the kernel/user - * divide and look after the messy bits. - */ - -/** - * move_addr_to_kernel - copy a socket address into kernel space - * @uaddr: Address in user space - * @kaddr: Address in kernel space - * @ulen: Length in user space - * - * The address is copied into kernel space. If the provided address is - * too long an error code of -EINVAL is returned. If the copy gives - * invalid addresses -EFAULT is returned. On a success 0 is returned. - */ - -int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr) -{ - if (ulen < 0 || ulen > sizeof(struct sockaddr_storage)) - return -EINVAL; - if (ulen == 0) - return 0; - if (copy_from_user(kaddr, uaddr, ulen)) - return -EFAULT; - return audit_sockaddr(ulen, kaddr); -} - -/** - * move_addr_to_user - copy an address to user space - * @kaddr: kernel space address - * @klen: length of address in kernel - * @uaddr: user space address - * @ulen: pointer to user length field - * - * The value pointed to by ulen on entry is the buffer length available. - * This is overwritten with the buffer space used. -EINVAL is returned - * if an overlong buffer is specified or a negative buffer size. -EFAULT - * is returned if either the buffer or the length field are not - * accessible. - * After copying the data up to the limit the user specifies, the true - * length of the data is written over the length limit the user - * specified. Zero is returned for a success. - */ - -static int move_addr_to_user(struct sockaddr_storage *kaddr, int klen, - void __user *uaddr, int __user *ulen) -{ - int err; - int len; - - BUG_ON(klen > sizeof(struct sockaddr_storage)); - err = get_user(len, ulen); - if (err) - return err; - if (len > klen) - len = klen; - if (len < 0) - return -EINVAL; - if (len) { - if (audit_sockaddr(klen, kaddr)) - return -ENOMEM; - if (copy_to_user(uaddr, kaddr, len)) - return -EFAULT; - } - /* - * "fromlen shall refer to the value before truncation.." - * 1003.1g - */ - return __put_user(klen, ulen); -} - -static struct kmem_cache *sock_inode_cachep __read_mostly; - -static struct inode *sock_alloc_inode(struct super_block *sb) -{ - struct socket_alloc *ei; - struct socket_wq *wq; - - ei = kmem_cache_alloc(sock_inode_cachep, GFP_KERNEL); - if (!ei) - return NULL; - wq = kmalloc(sizeof(*wq), GFP_KERNEL); - if (!wq) { - kmem_cache_free(sock_inode_cachep, ei); - return NULL; - } - init_waitqueue_head(&wq->wait); - wq->fasync_list = NULL; - wq->flags = 0; - RCU_INIT_POINTER(ei->socket.wq, wq); - - ei->socket.state = SS_UNCONNECTED; - ei->socket.flags = 0; - ei->socket.ops = NULL; - ei->socket.sk = NULL; - ei->socket.file = NULL; - - return &ei->vfs_inode; -} - -static void sock_destroy_inode(struct inode *inode) -{ - struct socket_alloc *ei; - struct socket_wq *wq; - - ei = container_of(inode, struct socket_alloc, vfs_inode); - wq = rcu_dereference_protected(ei->socket.wq, 1); - kfree_rcu(wq, rcu); - kmem_cache_free(sock_inode_cachep, ei); -} - -static void init_once(void *foo) -{ - struct socket_alloc *ei = (struct socket_alloc *)foo; - - inode_init_once(&ei->vfs_inode); -} - -static int init_inodecache(void) -{ - sock_inode_cachep = kmem_cache_create("sock_inode_cache", - sizeof(struct socket_alloc), - 0, - (SLAB_HWCACHE_ALIGN | - SLAB_RECLAIM_ACCOUNT | - SLAB_MEM_SPREAD | SLAB_ACCOUNT), - init_once); - if (sock_inode_cachep == NULL) - return -ENOMEM; - return 0; -} - -static const struct super_operations sockfs_ops = { - .alloc_inode = sock_alloc_inode, - .destroy_inode = sock_destroy_inode, - .statfs = simple_statfs, -}; - -/* - * sockfs_dname() is called from d_path(). - */ -static char *sockfs_dname(struct dentry *dentry, char *buffer, int buflen) -{ - return dynamic_dname(dentry, buffer, buflen, "socket:[%lu]", - d_inode(dentry)->i_ino); -} - -static const struct dentry_operations sockfs_dentry_operations = { - .d_dname = sockfs_dname, -}; - -static int sockfs_xattr_get(const struct xattr_handler *handler, - struct dentry *dentry, struct inode *inode, - const char *suffix, void *value, size_t size) -{ - if (value) { - if (dentry->d_name.len + 1 > size) - return -ERANGE; - memcpy(value, dentry->d_name.name, dentry->d_name.len + 1); - } - return dentry->d_name.len + 1; -} - -#define XATTR_SOCKPROTONAME_SUFFIX "sockprotoname" -#define XATTR_NAME_SOCKPROTONAME (XATTR_SYSTEM_PREFIX XATTR_SOCKPROTONAME_SUFFIX) -#define XATTR_NAME_SOCKPROTONAME_LEN (sizeof(XATTR_NAME_SOCKPROTONAME)-1) - -static const struct xattr_handler sockfs_xattr_handler = { - .name = XATTR_NAME_SOCKPROTONAME, - .get = sockfs_xattr_get, -}; - -static int sockfs_security_xattr_set(const struct xattr_handler *handler, - struct dentry *dentry, struct inode *inode, - const char *suffix, const void *value, - size_t size, int flags) -{ - /* Handled by LSM. */ - return -EAGAIN; -} - -static const struct xattr_handler sockfs_security_xattr_handler = { - .prefix = XATTR_SECURITY_PREFIX, - .set = sockfs_security_xattr_set, -}; - -static const struct xattr_handler *sockfs_xattr_handlers[] = { - &sockfs_xattr_handler, - &sockfs_security_xattr_handler, - NULL -}; - -static struct dentry *sockfs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_pseudo_xattr(fs_type, "socket:", &sockfs_ops, - sockfs_xattr_handlers, - &sockfs_dentry_operations, SOCKFS_MAGIC); -} - -static struct vfsmount *sock_mnt __read_mostly; - -static struct file_system_type sock_fs_type = { - .name = "sockfs", - .mount = sockfs_mount, - .kill_sb = kill_anon_super, -}; - -/* - * Obtains the first available file descriptor and sets it up for use. - * - * These functions create file structures and maps them to fd space - * of the current process. On success it returns file descriptor - * and file struct implicitly stored in sock->file. - * Note that another thread may close file descriptor before we return - * from this function. We use the fact that now we do not refer - * to socket after mapping. If one day we will need it, this - * function will increment ref. count on file by 1. - * - * In any case returned fd MAY BE not valid! - * This race condition is unavoidable - * with shared fd spaces, we cannot solve it inside kernel, - * but we take care of internal coherence yet. - */ - -struct file *sock_alloc_file(struct socket *sock, int flags, const char *dname) -{ - struct qstr name = { .name = "" }; - struct path path; - struct file *file; - - if (dname) { - name.name = dname; - name.len = strlen(name.name); - } else if (sock->sk) { - name.name = sock->sk->sk_prot_creator->name; - name.len = strlen(name.name); - } - path.dentry = d_alloc_pseudo(sock_mnt->mnt_sb, &name); - if (unlikely(!path.dentry)) - return ERR_PTR(-ENOMEM); - path.mnt = mntget(sock_mnt); - - d_instantiate(path.dentry, SOCK_INODE(sock)); - - file = alloc_file(&path, FMODE_READ | FMODE_WRITE, - &socket_file_ops); - if (IS_ERR(file)) { - /* drop dentry, keep inode */ - ihold(d_inode(path.dentry)); - path_put(&path); - return file; - } - - sock->file = file; - file->f_flags = O_RDWR | (flags & O_NONBLOCK); - file->private_data = sock; - return file; -} -EXPORT_SYMBOL(sock_alloc_file); - -static int sock_map_fd(struct socket *sock, int flags) -{ - struct file *newfile; - int fd = get_unused_fd_flags(flags); - if (unlikely(fd < 0)) - return fd; - - newfile = sock_alloc_file(sock, flags, NULL); - if (likely(!IS_ERR(newfile))) { - fd_install(fd, newfile); - return fd; - } - - put_unused_fd(fd); - return PTR_ERR(newfile); -} - -struct socket *sock_from_file(struct file *file, int *err) -{ - if (file->f_op == &socket_file_ops) - return file->private_data; /* set in sock_map_fd */ - - *err = -ENOTSOCK; - return NULL; -} -EXPORT_SYMBOL(sock_from_file); - -/** - * sockfd_lookup - Go from a file number to its socket slot - * @fd: file handle - * @err: pointer to an error code return - * - * The file handle passed in is locked and the socket it is bound - * too is returned. If an error occurs the err pointer is overwritten - * with a negative errno code and NULL is returned. The function checks - * for both invalid handles and passing a handle which is not a socket. - * - * On a success the socket object pointer is returned. - */ - -struct socket *sockfd_lookup(int fd, int *err) -{ - struct file *file; - struct socket *sock; - - file = fget(fd); - if (!file) { - *err = -EBADF; - return NULL; - } - - sock = sock_from_file(file, err); - if (!sock) - fput(file); - return sock; -} -EXPORT_SYMBOL(sockfd_lookup); - -static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed) -{ - struct fd f = fdget(fd); - struct socket *sock; - - *err = -EBADF; - if (f.file) { - sock = sock_from_file(f.file, err); - if (likely(sock)) { - *fput_needed = f.flags; - return sock; - } - fdput(f); - } - return NULL; -} - -static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer, - size_t size) -{ - ssize_t len; - ssize_t used = 0; - - len = security_inode_listsecurity(d_inode(dentry), buffer, size); - if (len < 0) - return len; - used += len; - if (buffer) { - if (size < used) - return -ERANGE; - buffer += len; - } - - len = (XATTR_NAME_SOCKPROTONAME_LEN + 1); - used += len; - if (buffer) { - if (size < used) - return -ERANGE; - memcpy(buffer, XATTR_NAME_SOCKPROTONAME, len); - buffer += len; - } - - return used; -} - -static const struct inode_operations sockfs_inode_ops = { - .listxattr = sockfs_listxattr, -}; - -/** - * sock_alloc - allocate a socket - * - * Allocate a new inode and socket object. The two are bound together - * and initialised. The socket is then returned. If we are out of inodes - * NULL is returned. - */ - -struct socket *sock_alloc(void) -{ - struct inode *inode; - struct socket *sock; - - inode = new_inode_pseudo(sock_mnt->mnt_sb); - if (!inode) - return NULL; - - sock = SOCKET_I(inode); - - kmemcheck_annotate_bitfield(sock, type); - inode->i_ino = get_next_ino(); - inode->i_mode = S_IFSOCK | S_IRWXUGO; - inode->i_uid = current_fsuid(); - inode->i_gid = current_fsgid(); - inode->i_op = &sockfs_inode_ops; - - this_cpu_add(sockets_in_use, 1); - return sock; -} -EXPORT_SYMBOL(sock_alloc); - -/** - * sock_release - close a socket - * @sock: socket to close - * - * The socket is released from the protocol stack if it has a release - * callback, and the inode is then released if the socket is bound to - * an inode not a file. - */ - -void sock_release(struct socket *sock) -{ - if (sock->ops) { - struct module *owner = sock->ops->owner; - - sock->ops->release(sock); - sock->ops = NULL; - module_put(owner); - } - - if (rcu_dereference_protected(sock->wq, 1)->fasync_list) - pr_err("%s: fasync list not empty!\n", __func__); - - this_cpu_sub(sockets_in_use, 1); - if (!sock->file) { - iput(SOCK_INODE(sock)); - return; - } - sock->file = NULL; -} -EXPORT_SYMBOL(sock_release); - -void __sock_tx_timestamp(__u16 tsflags, __u8 *tx_flags) -{ - u8 flags = *tx_flags; - - if (tsflags & SOF_TIMESTAMPING_TX_HARDWARE) - flags |= SKBTX_HW_TSTAMP; - - if (tsflags & SOF_TIMESTAMPING_TX_SOFTWARE) - flags |= SKBTX_SW_TSTAMP; - - if (tsflags & SOF_TIMESTAMPING_TX_SCHED) - flags |= SKBTX_SCHED_TSTAMP; - - *tx_flags = flags; -} -EXPORT_SYMBOL(__sock_tx_timestamp); - -static inline int sock_sendmsg_nosec(struct socket *sock, struct msghdr *msg) -{ - int ret = sock->ops->sendmsg(sock, msg, msg_data_left(msg)); - BUG_ON(ret == -EIOCBQUEUED); - return ret; -} - -int sock_sendmsg(struct socket *sock, struct msghdr *msg) -{ - int err = security_socket_sendmsg(sock, msg, - msg_data_left(msg)); - - return err ?: sock_sendmsg_nosec(sock, msg); -} -EXPORT_SYMBOL(sock_sendmsg); - -int kernel_sendmsg(struct socket *sock, struct msghdr *msg, - struct kvec *vec, size_t num, size_t size) -{ - iov_iter_kvec(&msg->msg_iter, WRITE | ITER_KVEC, vec, num, size); - return sock_sendmsg(sock, msg); -} -EXPORT_SYMBOL(kernel_sendmsg); - -/* - * called from sock_recv_timestamp() if sock_flag(sk, SOCK_RCVTSTAMP) - */ -void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk, - struct sk_buff *skb) -{ - int need_software_tstamp = sock_flag(sk, SOCK_RCVTSTAMP); - struct scm_timestamping tss; - int empty = 1; - struct skb_shared_hwtstamps *shhwtstamps = - skb_hwtstamps(skb); - - /* Race occurred between timestamp enabling and packet - receiving. Fill in the current time for now. */ - if (need_software_tstamp && skb->tstamp.tv64 == 0) - __net_timestamp(skb); - - if (need_software_tstamp) { - if (!sock_flag(sk, SOCK_RCVTSTAMPNS)) { - struct timeval tv; - skb_get_timestamp(skb, &tv); - put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMP, - sizeof(tv), &tv); - } else { - struct timespec ts; - skb_get_timestampns(skb, &ts); - put_cmsg(msg, SOL_SOCKET, SCM_TIMESTAMPNS, - sizeof(ts), &ts); - } - } - - memset(&tss, 0, sizeof(tss)); - if ((sk->sk_tsflags & SOF_TIMESTAMPING_SOFTWARE) && - ktime_to_timespec_cond(skb->tstamp, tss.ts + 0)) - empty = 0; - if (shhwtstamps && - (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE) && - ktime_to_timespec_cond(shhwtstamps->hwtstamp, tss.ts + 2)) - empty = 0; - if (!empty) - put_cmsg(msg, SOL_SOCKET, - SCM_TIMESTAMPING, sizeof(tss), &tss); -} -EXPORT_SYMBOL_GPL(__sock_recv_timestamp); - -void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk, - struct sk_buff *skb) -{ - int ack; - - if (!sock_flag(sk, SOCK_WIFI_STATUS)) - return; - if (!skb->wifi_acked_valid) - return; - - ack = skb->wifi_acked; - - put_cmsg(msg, SOL_SOCKET, SCM_WIFI_STATUS, sizeof(ack), &ack); -} -EXPORT_SYMBOL_GPL(__sock_recv_wifi_status); - -static inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, - struct sk_buff *skb) -{ - if (sock_flag(sk, SOCK_RXQ_OVFL) && skb && SOCK_SKB_CB(skb)->dropcount) - put_cmsg(msg, SOL_SOCKET, SO_RXQ_OVFL, - sizeof(__u32), &SOCK_SKB_CB(skb)->dropcount); -} - -void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk, - struct sk_buff *skb) -{ - sock_recv_timestamp(msg, sk, skb); - sock_recv_drops(msg, sk, skb); -} -EXPORT_SYMBOL_GPL(__sock_recv_ts_and_drops); - -static inline int sock_recvmsg_nosec(struct socket *sock, struct msghdr *msg, - int flags) -{ - return sock->ops->recvmsg(sock, msg, msg_data_left(msg), flags); -} - -int sock_recvmsg(struct socket *sock, struct msghdr *msg, int flags) -{ - int err = security_socket_recvmsg(sock, msg, msg_data_left(msg), flags); - - return err ?: sock_recvmsg_nosec(sock, msg, flags); -} -EXPORT_SYMBOL(sock_recvmsg); - -/** - * kernel_recvmsg - Receive a message from a socket (kernel space) - * @sock: The socket to receive the message from - * @msg: Received message - * @vec: Input s/g array for message data - * @num: Size of input s/g array - * @size: Number of bytes to read - * @flags: Message flags (MSG_DONTWAIT, etc...) - * - * On return the msg structure contains the scatter/gather array passed in the - * vec argument. The array is modified so that it consists of the unfilled - * portion of the original array. - * - * The returned value is the total number of bytes received, or an error. - */ -int kernel_recvmsg(struct socket *sock, struct msghdr *msg, - struct kvec *vec, size_t num, size_t size, int flags) -{ - mm_segment_t oldfs = get_fs(); - int result; - - iov_iter_kvec(&msg->msg_iter, READ | ITER_KVEC, vec, num, size); - set_fs(KERNEL_DS); - result = sock_recvmsg(sock, msg, flags); - set_fs(oldfs); - return result; -} -EXPORT_SYMBOL(kernel_recvmsg); - -static ssize_t sock_sendpage(struct file *file, struct page *page, - int offset, size_t size, loff_t *ppos, int more) -{ - struct socket *sock; - int flags; - - sock = file->private_data; - - flags = (file->f_flags & O_NONBLOCK) ? MSG_DONTWAIT : 0; - /* more is a combination of MSG_MORE and MSG_SENDPAGE_NOTLAST */ - flags |= more; - - return kernel_sendpage(sock, page, offset, size, flags); -} - -static ssize_t sock_splice_read(struct file *file, loff_t *ppos, - struct pipe_inode_info *pipe, size_t len, - unsigned int flags) -{ - struct socket *sock = file->private_data; - - if (unlikely(!sock->ops->splice_read)) - return -EINVAL; - - return sock->ops->splice_read(sock, ppos, pipe, len, flags); -} - -static ssize_t sock_read_iter(struct kiocb *iocb, struct iov_iter *to) -{ - struct file *file = iocb->ki_filp; - struct socket *sock = file->private_data; - struct msghdr msg = {.msg_iter = *to, - .msg_iocb = iocb}; - ssize_t res; - - if (file->f_flags & O_NONBLOCK) - msg.msg_flags = MSG_DONTWAIT; - - if (iocb->ki_pos != 0) - return -ESPIPE; - - if (!iov_iter_count(to)) /* Match SYS5 behaviour */ - return 0; - - res = sock_recvmsg(sock, &msg, msg.msg_flags); - *to = msg.msg_iter; - return res; -} - -static ssize_t sock_write_iter(struct kiocb *iocb, struct iov_iter *from) -{ - struct file *file = iocb->ki_filp; - struct socket *sock = file->private_data; - struct msghdr msg = {.msg_iter = *from, - .msg_iocb = iocb}; - ssize_t res; - - if (iocb->ki_pos != 0) - return -ESPIPE; - - if (file->f_flags & O_NONBLOCK) - msg.msg_flags = MSG_DONTWAIT; - - if (sock->type == SOCK_SEQPACKET) - msg.msg_flags |= MSG_EOR; - - res = sock_sendmsg(sock, &msg); - *from = msg.msg_iter; - return res; -} - -/* - * Atomic setting of ioctl hooks to avoid race - * with module unload. - */ - -static DEFINE_MUTEX(br_ioctl_mutex); -static int (*br_ioctl_hook) (struct net *, unsigned int cmd, void __user *arg); - -void brioctl_set(int (*hook) (struct net *, unsigned int, void __user *)) -{ - mutex_lock(&br_ioctl_mutex); - br_ioctl_hook = hook; - mutex_unlock(&br_ioctl_mutex); -} -EXPORT_SYMBOL(brioctl_set); - -static DEFINE_MUTEX(vlan_ioctl_mutex); -static int (*vlan_ioctl_hook) (struct net *, void __user *arg); - -void vlan_ioctl_set(int (*hook) (struct net *, void __user *)) -{ - mutex_lock(&vlan_ioctl_mutex); - vlan_ioctl_hook = hook; - mutex_unlock(&vlan_ioctl_mutex); -} -EXPORT_SYMBOL(vlan_ioctl_set); - -static DEFINE_MUTEX(dlci_ioctl_mutex); -static int (*dlci_ioctl_hook) (unsigned int, void __user *); - -void dlci_ioctl_set(int (*hook) (unsigned int, void __user *)) -{ - mutex_lock(&dlci_ioctl_mutex); - dlci_ioctl_hook = hook; - mutex_unlock(&dlci_ioctl_mutex); -} -EXPORT_SYMBOL(dlci_ioctl_set); - -static long sock_do_ioctl(struct net *net, struct socket *sock, - unsigned int cmd, unsigned long arg) -{ - int err; - void __user *argp = (void __user *)arg; - - err = sock->ops->ioctl(sock, cmd, arg); - - /* - * If this ioctl is unknown try to hand it down - * to the NIC driver. - */ - if (err == -ENOIOCTLCMD) - err = dev_ioctl(net, cmd, argp); - - return err; -} - -/* - * With an ioctl, arg may well be a user mode pointer, but we don't know - * what to do with it - that's up to the protocol still. - */ - -static long sock_ioctl(struct file *file, unsigned cmd, unsigned long arg) -{ - struct socket *sock; - struct sock *sk; - void __user *argp = (void __user *)arg; - int pid, err; - struct net *net; - - sock = file->private_data; - sk = sock->sk; - net = sock_net(sk); - if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) { - err = dev_ioctl(net, cmd, argp); - } else -#ifdef CONFIG_WEXT_CORE - if (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST) { - err = dev_ioctl(net, cmd, argp); - } else -#endif - switch (cmd) { - case FIOSETOWN: - case SIOCSPGRP: - err = -EFAULT; - if (get_user(pid, (int __user *)argp)) - break; - f_setown(sock->file, pid, 1); - err = 0; - break; - case FIOGETOWN: - case SIOCGPGRP: - err = put_user(f_getown(sock->file), - (int __user *)argp); - break; - case SIOCGIFBR: - case SIOCSIFBR: - case SIOCBRADDBR: - case SIOCBRDELBR: - err = -ENOPKG; - if (!br_ioctl_hook) - request_module("bridge"); - - mutex_lock(&br_ioctl_mutex); - if (br_ioctl_hook) - err = br_ioctl_hook(net, cmd, argp); - mutex_unlock(&br_ioctl_mutex); - break; - case SIOCGIFVLAN: - case SIOCSIFVLAN: - err = -ENOPKG; - if (!vlan_ioctl_hook) - request_module("8021q"); - - mutex_lock(&vlan_ioctl_mutex); - if (vlan_ioctl_hook) - err = vlan_ioctl_hook(net, argp); - mutex_unlock(&vlan_ioctl_mutex); - break; - case SIOCADDDLCI: - case SIOCDELDLCI: - err = -ENOPKG; - if (!dlci_ioctl_hook) - request_module("dlci"); - - mutex_lock(&dlci_ioctl_mutex); - if (dlci_ioctl_hook) - err = dlci_ioctl_hook(cmd, argp); - mutex_unlock(&dlci_ioctl_mutex); - break; - default: - err = sock_do_ioctl(net, sock, cmd, arg); - break; - } - return err; -} - -int sock_create_lite(int family, int type, int protocol, struct socket **res) -{ - int err; - struct socket *sock = NULL; - - err = security_socket_create(family, type, protocol, 1); - if (err) - goto out; - - sock = sock_alloc(); - if (!sock) { - err = -ENOMEM; - goto out; - } - - sock->type = type; - err = security_socket_post_create(sock, family, type, protocol, 1); - if (err) - goto out_release; - -out: - *res = sock; - return err; -out_release: - sock_release(sock); - sock = NULL; - goto out; -} -EXPORT_SYMBOL(sock_create_lite); - -/* No kernel lock held - perfect */ -static unsigned int sock_poll(struct file *file, poll_table *wait) -{ - unsigned int busy_flag = 0; - struct socket *sock; - - /* - * We can't return errors to poll, so it's either yes or no. - */ - sock = file->private_data; - - if (sk_can_busy_loop(sock->sk)) { - /* this socket can poll_ll so tell the system call */ - busy_flag = POLL_BUSY_LOOP; - - /* once, only if requested by syscall */ - if (wait && (wait->_key & POLL_BUSY_LOOP)) - sk_busy_loop(sock->sk, 1); - } - - return busy_flag | sock->ops->poll(file, sock, wait); -} - -static int sock_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct socket *sock = file->private_data; - - return sock->ops->mmap(file, sock, vma); -} - -static int sock_close(struct inode *inode, struct file *filp) -{ - sock_release(SOCKET_I(inode)); - return 0; -} - -/* - * Update the socket async list - * - * Fasync_list locking strategy. - * - * 1. fasync_list is modified only under process context socket lock - * i.e. under semaphore. - * 2. fasync_list is used under read_lock(&sk->sk_callback_lock) - * or under socket lock - */ - -static int sock_fasync(int fd, struct file *filp, int on) -{ - struct socket *sock = filp->private_data; - struct sock *sk = sock->sk; - struct socket_wq *wq; - - if (sk == NULL) - return -EINVAL; - - lock_sock(sk); - wq = rcu_dereference_protected(sock->wq, lockdep_sock_is_held(sk)); - fasync_helper(fd, filp, on, &wq->fasync_list); - - if (!wq->fasync_list) - sock_reset_flag(sk, SOCK_FASYNC); - else - sock_set_flag(sk, SOCK_FASYNC); - - release_sock(sk); - return 0; -} - -/* This function may be called only under rcu_lock */ - -int sock_wake_async(struct socket_wq *wq, int how, int band) -{ - if (!wq || !wq->fasync_list) - return -1; - - switch (how) { - case SOCK_WAKE_WAITD: - if (test_bit(SOCKWQ_ASYNC_WAITDATA, &wq->flags)) - break; - goto call_kill; - case SOCK_WAKE_SPACE: - if (!test_and_clear_bit(SOCKWQ_ASYNC_NOSPACE, &wq->flags)) - break; - /* fall through */ - case SOCK_WAKE_IO: -call_kill: - kill_fasync(&wq->fasync_list, SIGIO, band); - break; - case SOCK_WAKE_URG: - kill_fasync(&wq->fasync_list, SIGURG, band); - } - - return 0; -} -EXPORT_SYMBOL(sock_wake_async); - -int __sock_create(struct net *net, int family, int type, int protocol, - struct socket **res, int kern) -{ - int err; - struct socket *sock; - const struct net_proto_family *pf; - - /* - * Check protocol is in range - */ - if (family < 0 || family >= NPROTO) - return -EAFNOSUPPORT; - if (type < 0 || type >= SOCK_MAX) - return -EINVAL; - - /* Compatibility. - - This uglymoron is moved from INET layer to here to avoid - deadlock in module load. - */ - if (family == PF_INET && type == SOCK_PACKET) { - pr_info_once("%s uses obsolete (PF_INET,SOCK_PACKET)\n", - current->comm); - family = PF_PACKET; - } - - err = security_socket_create(family, type, protocol, kern); - if (err) - return err; - - /* - * Allocate the socket and allow the family to set things up. if - * the protocol is 0, the family is instructed to select an appropriate - * default. - */ - sock = sock_alloc(); - if (!sock) { - net_warn_ratelimited("socket: no more sockets\n"); - return -ENFILE; /* Not exactly a match, but its the - closest posix thing */ - } - - sock->type = type; - -#ifdef CONFIG_MODULES - /* Attempt to load a protocol module if the find failed. - * - * 12/09/1996 Marcin: But! this makes REALLY only sense, if the user - * requested real, full-featured networking support upon configuration. - * Otherwise module support will break! - */ - if (rcu_access_pointer(net_families[family]) == NULL) - request_module("net-pf-%d", family); -#endif - - rcu_read_lock(); - pf = rcu_dereference(net_families[family]); - err = -EAFNOSUPPORT; - if (!pf) - goto out_release; - - /* - * We will call the ->create function, that possibly is in a loadable - * module, so we have to bump that loadable module refcnt first. - */ - if (!try_module_get(pf->owner)) - goto out_release; - - /* Now protected by module ref count */ - rcu_read_unlock(); - - err = pf->create(net, sock, protocol, kern); - if (err < 0) - goto out_module_put; - - /* - * Now to bump the refcnt of the [loadable] module that owns this - * socket at sock_release time we decrement its refcnt. - */ - if (!try_module_get(sock->ops->owner)) - goto out_module_busy; - - /* - * Now that we're done with the ->create function, the [loadable] - * module can have its refcnt decremented - */ - module_put(pf->owner); - err = security_socket_post_create(sock, family, type, protocol, kern); - if (err) - goto out_sock_release; - *res = sock; - - return 0; - -out_module_busy: - err = -EAFNOSUPPORT; -out_module_put: - sock->ops = NULL; - module_put(pf->owner); -out_sock_release: - sock_release(sock); - return err; - -out_release: - rcu_read_unlock(); - goto out_sock_release; -} -EXPORT_SYMBOL(__sock_create); - -int sock_create(int family, int type, int protocol, struct socket **res) -{ - return __sock_create(current->nsproxy->net_ns, family, type, protocol, res, 0); -} -EXPORT_SYMBOL(sock_create); - -int sock_create_kern(struct net *net, int family, int type, int protocol, struct socket **res) -{ - return __sock_create(net, family, type, protocol, res, 1); -} -EXPORT_SYMBOL(sock_create_kern); - -SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol) -{ - int retval; - struct socket *sock; - int flags; - - /* Check the SOCK_* constants for consistency. */ - BUILD_BUG_ON(SOCK_CLOEXEC != O_CLOEXEC); - BUILD_BUG_ON((SOCK_MAX | SOCK_TYPE_MASK) != SOCK_TYPE_MASK); - BUILD_BUG_ON(SOCK_CLOEXEC & SOCK_TYPE_MASK); - BUILD_BUG_ON(SOCK_NONBLOCK & SOCK_TYPE_MASK); - - flags = type & ~SOCK_TYPE_MASK; - if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) - return -EINVAL; - type &= SOCK_TYPE_MASK; - - if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) - flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; - - retval = sock_create(family, type, protocol, &sock); - if (retval < 0) - goto out; - - retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK)); - if (retval < 0) - goto out_release; - -out: - /* It may be already another descriptor 8) Not kernel problem. */ - return retval; - -out_release: - sock_release(sock); - return retval; -} - -/* - * Create a pair of connected sockets. - */ - -SYSCALL_DEFINE4(socketpair, int, family, int, type, int, protocol, - int __user *, usockvec) -{ - struct socket *sock1, *sock2; - int fd1, fd2, err; - struct file *newfile1, *newfile2; - int flags; - - flags = type & ~SOCK_TYPE_MASK; - if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) - return -EINVAL; - type &= SOCK_TYPE_MASK; - - if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) - flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; - - /* - * Obtain the first socket and check if the underlying protocol - * supports the socketpair call. - */ - - err = sock_create(family, type, protocol, &sock1); - if (err < 0) - goto out; - - err = sock_create(family, type, protocol, &sock2); - if (err < 0) - goto out_release_1; - - err = sock1->ops->socketpair(sock1, sock2); - if (err < 0) - goto out_release_both; - - fd1 = get_unused_fd_flags(flags); - if (unlikely(fd1 < 0)) { - err = fd1; - goto out_release_both; - } - - fd2 = get_unused_fd_flags(flags); - if (unlikely(fd2 < 0)) { - err = fd2; - goto out_put_unused_1; - } - - newfile1 = sock_alloc_file(sock1, flags, NULL); - if (IS_ERR(newfile1)) { - err = PTR_ERR(newfile1); - goto out_put_unused_both; - } - - newfile2 = sock_alloc_file(sock2, flags, NULL); - if (IS_ERR(newfile2)) { - err = PTR_ERR(newfile2); - goto out_fput_1; - } - - err = put_user(fd1, &usockvec[0]); - if (err) - goto out_fput_both; - - err = put_user(fd2, &usockvec[1]); - if (err) - goto out_fput_both; - - audit_fd_pair(fd1, fd2); - - fd_install(fd1, newfile1); - fd_install(fd2, newfile2); - /* fd1 and fd2 may be already another descriptors. - * Not kernel problem. - */ - - return 0; - -out_fput_both: - fput(newfile2); - fput(newfile1); - put_unused_fd(fd2); - put_unused_fd(fd1); - goto out; - -out_fput_1: - fput(newfile1); - put_unused_fd(fd2); - put_unused_fd(fd1); - sock_release(sock2); - goto out; - -out_put_unused_both: - put_unused_fd(fd2); -out_put_unused_1: - put_unused_fd(fd1); -out_release_both: - sock_release(sock2); -out_release_1: - sock_release(sock1); -out: - return err; -} - -/* - * Bind a name to a socket. Nothing much to do here since it's - * the protocol's responsibility to handle the local address. - * - * We move the socket address to kernel space before we call - * the protocol layer (having also checked the address is ok). - */ - -SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen) -{ - struct socket *sock; - struct sockaddr_storage address; - int err, fput_needed; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (sock) { - err = move_addr_to_kernel(umyaddr, addrlen, &address); - if (err >= 0) { - err = security_socket_bind(sock, - (struct sockaddr *)&address, - addrlen); - if (!err) - err = sock->ops->bind(sock, - (struct sockaddr *) - &address, addrlen); - } - fput_light(sock->file, fput_needed); - } - return err; -} - -/* - * Perform a listen. Basically, we allow the protocol to do anything - * necessary for a listen, and if that works, we mark the socket as - * ready for listening. - */ - -SYSCALL_DEFINE2(listen, int, fd, int, backlog) -{ - struct socket *sock; - int err, fput_needed; - int somaxconn; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (sock) { - somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn; - if ((unsigned int)backlog > somaxconn) - backlog = somaxconn; - - err = security_socket_listen(sock, backlog); - if (!err) - err = sock->ops->listen(sock, backlog); - - fput_light(sock->file, fput_needed); - } - return err; -} - -/* - * For accept, we attempt to create a new socket, set up the link - * with the client, wake up the client, then return the new - * connected fd. We collect the address of the connector in kernel - * space and move it to user at the very end. This is unclean because - * we open the socket then return an error. - * - * 1003.1g adds the ability to recvmsg() to query connection pending - * status to recvmsg. We need to add that support in a way thats - * clean when we restucture accept also. - */ - -SYSCALL_DEFINE4(accept4, int, fd, struct sockaddr __user *, upeer_sockaddr, - int __user *, upeer_addrlen, int, flags) -{ - struct socket *sock, *newsock; - struct file *newfile; - int err, len, newfd, fput_needed; - struct sockaddr_storage address; - - if (flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK)) - return -EINVAL; - - if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) - flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - goto out; - - err = -ENFILE; - newsock = sock_alloc(); - if (!newsock) - goto out_put; - - newsock->type = sock->type; - newsock->ops = sock->ops; - - /* - * We don't need try_module_get here, as the listening socket (sock) - * has the protocol module (sock->ops->owner) held. - */ - __module_get(newsock->ops->owner); - - newfd = get_unused_fd_flags(flags); - if (unlikely(newfd < 0)) { - err = newfd; - sock_release(newsock); - goto out_put; - } - newfile = sock_alloc_file(newsock, flags, sock->sk->sk_prot_creator->name); - if (IS_ERR(newfile)) { - err = PTR_ERR(newfile); - put_unused_fd(newfd); - sock_release(newsock); - goto out_put; - } - - err = security_socket_accept(sock, newsock); - if (err) - goto out_fd; - - err = sock->ops->accept(sock, newsock, sock->file->f_flags); - if (err < 0) - goto out_fd; - - if (upeer_sockaddr) { - if (newsock->ops->getname(newsock, (struct sockaddr *)&address, - &len, 2) < 0) { - err = -ECONNABORTED; - goto out_fd; - } - err = move_addr_to_user(&address, - len, upeer_sockaddr, upeer_addrlen); - if (err < 0) - goto out_fd; - } - - /* File flags are not inherited via accept() unlike another OSes. */ - - fd_install(newfd, newfile); - err = newfd; - -out_put: - fput_light(sock->file, fput_needed); -out: - return err; -out_fd: - fput(newfile); - put_unused_fd(newfd); - goto out_put; -} - -SYSCALL_DEFINE3(accept, int, fd, struct sockaddr __user *, upeer_sockaddr, - int __user *, upeer_addrlen) -{ - return sys_accept4(fd, upeer_sockaddr, upeer_addrlen, 0); -} - -/* - * Attempt to connect to a socket with the server address. The address - * is in user space so we verify it is OK and move it to kernel space. - * - * For 1003.1g we need to add clean support for a bind to AF_UNSPEC to - * break bindings - * - * NOTE: 1003.1g draft 6.3 is broken with respect to AX.25/NetROM and - * other SEQPACKET protocols that take time to connect() as it doesn't - * include the -EINPROGRESS status for such sockets. - */ - -SYSCALL_DEFINE3(connect, int, fd, struct sockaddr __user *, uservaddr, - int, addrlen) -{ - struct socket *sock; - struct sockaddr_storage address; - int err, fput_needed; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - goto out; - err = move_addr_to_kernel(uservaddr, addrlen, &address); - if (err < 0) - goto out_put; - - err = - security_socket_connect(sock, (struct sockaddr *)&address, addrlen); - if (err) - goto out_put; - - err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen, - sock->file->f_flags); -out_put: - fput_light(sock->file, fput_needed); -out: - return err; -} - -/* - * Get the local address ('name') of a socket object. Move the obtained - * name to user space. - */ - -SYSCALL_DEFINE3(getsockname, int, fd, struct sockaddr __user *, usockaddr, - int __user *, usockaddr_len) -{ - struct socket *sock; - struct sockaddr_storage address; - int len, err, fput_needed; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - goto out; - - err = security_socket_getsockname(sock); - if (err) - goto out_put; - - err = sock->ops->getname(sock, (struct sockaddr *)&address, &len, 0); - if (err) - goto out_put; - err = move_addr_to_user(&address, len, usockaddr, usockaddr_len); - -out_put: - fput_light(sock->file, fput_needed); -out: - return err; -} - -/* - * Get the remote address ('name') of a socket object. Move the obtained - * name to user space. - */ - -SYSCALL_DEFINE3(getpeername, int, fd, struct sockaddr __user *, usockaddr, - int __user *, usockaddr_len) -{ - struct socket *sock; - struct sockaddr_storage address; - int len, err, fput_needed; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (sock != NULL) { - err = security_socket_getpeername(sock); - if (err) { - fput_light(sock->file, fput_needed); - return err; - } - - err = - sock->ops->getname(sock, (struct sockaddr *)&address, &len, - 1); - if (!err) - err = move_addr_to_user(&address, len, usockaddr, - usockaddr_len); - fput_light(sock->file, fput_needed); - } - return err; -} - -/* - * Send a datagram to a given address. We move the address into kernel - * space and check the user space data area is readable before invoking - * the protocol. - */ - -SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len, - unsigned int, flags, struct sockaddr __user *, addr, - int, addr_len) -{ - struct socket *sock; - struct sockaddr_storage address; - int err; - struct msghdr msg; - struct iovec iov; - int fput_needed; - - err = import_single_range(WRITE, buff, len, &iov, &msg.msg_iter); - if (unlikely(err)) - return err; - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - goto out; - - msg.msg_name = NULL; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_namelen = 0; - if (addr) { - err = move_addr_to_kernel(addr, addr_len, &address); - if (err < 0) - goto out_put; - msg.msg_name = (struct sockaddr *)&address; - msg.msg_namelen = addr_len; - } - if (sock->file->f_flags & O_NONBLOCK) - flags |= MSG_DONTWAIT; - msg.msg_flags = flags; - err = sock_sendmsg(sock, &msg); - -out_put: - fput_light(sock->file, fput_needed); -out: - return err; -} - -/* - * Send a datagram down a socket. - */ - -SYSCALL_DEFINE4(send, int, fd, void __user *, buff, size_t, len, - unsigned int, flags) -{ - return sys_sendto(fd, buff, len, flags, NULL, 0); -} - -/* - * Receive a frame from the socket and optionally record the address of the - * sender. We verify the buffers are writable and if needed move the - * sender address from kernel to user space. - */ - -SYSCALL_DEFINE6(recvfrom, int, fd, void __user *, ubuf, size_t, size, - unsigned int, flags, struct sockaddr __user *, addr, - int __user *, addr_len) -{ - struct socket *sock; - struct iovec iov; - struct msghdr msg; - struct sockaddr_storage address; - int err, err2; - int fput_needed; - - err = import_single_range(READ, ubuf, size, &iov, &msg.msg_iter); - if (unlikely(err)) - return err; - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - goto out; - - msg.msg_control = NULL; - msg.msg_controllen = 0; - /* Save some cycles and don't copy the address if not needed */ - msg.msg_name = addr ? (struct sockaddr *)&address : NULL; - /* We assume all kernel code knows the size of sockaddr_storage */ - msg.msg_namelen = 0; - msg.msg_iocb = NULL; - if (sock->file->f_flags & O_NONBLOCK) - flags |= MSG_DONTWAIT; - err = sock_recvmsg(sock, &msg, flags); - - if (err >= 0 && addr != NULL) { - err2 = move_addr_to_user(&address, - msg.msg_namelen, addr, addr_len); - if (err2 < 0) - err = err2; - } - - fput_light(sock->file, fput_needed); -out: - return err; -} - -/* - * Receive a datagram from a socket. - */ - -SYSCALL_DEFINE4(recv, int, fd, void __user *, ubuf, size_t, size, - unsigned int, flags) -{ - return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL); -} - -/* - * Set a socket option. Because we don't know the option lengths we have - * to pass the user mode parameter for the protocols to sort out. - */ - -SYSCALL_DEFINE5(setsockopt, int, fd, int, level, int, optname, - char __user *, optval, int, optlen) -{ - int err, fput_needed; - struct socket *sock; - - if (optlen < 0) - return -EINVAL; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (sock != NULL) { - err = security_socket_setsockopt(sock, level, optname); - if (err) - goto out_put; - - if (level == SOL_SOCKET) - err = - sock_setsockopt(sock, level, optname, optval, - optlen); - else - err = - sock->ops->setsockopt(sock, level, optname, optval, - optlen); -out_put: - fput_light(sock->file, fput_needed); - } - return err; -} - -/* - * Get a socket option. Because we don't know the option lengths we have - * to pass a user mode parameter for the protocols to sort out. - */ - -SYSCALL_DEFINE5(getsockopt, int, fd, int, level, int, optname, - char __user *, optval, int __user *, optlen) -{ - int err, fput_needed; - struct socket *sock; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (sock != NULL) { - err = security_socket_getsockopt(sock, level, optname); - if (err) - goto out_put; - - if (level == SOL_SOCKET) - err = - sock_getsockopt(sock, level, optname, optval, - optlen); - else - err = - sock->ops->getsockopt(sock, level, optname, optval, - optlen); -out_put: - fput_light(sock->file, fput_needed); - } - return err; -} - -/* - * Shutdown a socket. - */ - -SYSCALL_DEFINE2(shutdown, int, fd, int, how) -{ - int err, fput_needed; - struct socket *sock; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (sock != NULL) { - err = security_socket_shutdown(sock, how); - if (!err) - err = sock->ops->shutdown(sock, how); - fput_light(sock->file, fput_needed); - } - return err; -} - -/* A couple of helpful macros for getting the address of the 32/64 bit - * fields which are the same type (int / unsigned) on our platforms. - */ -#define COMPAT_MSG(msg, member) ((MSG_CMSG_COMPAT & flags) ? &msg##_compat->member : &msg->member) -#define COMPAT_NAMELEN(msg) COMPAT_MSG(msg, msg_namelen) -#define COMPAT_FLAGS(msg) COMPAT_MSG(msg, msg_flags) - -struct used_address { - struct sockaddr_storage name; - unsigned int name_len; -}; - -static int copy_msghdr_from_user(struct msghdr *kmsg, - struct user_msghdr __user *umsg, - struct sockaddr __user **save_addr, - struct iovec **iov) -{ - struct sockaddr __user *uaddr; - struct iovec __user *uiov; - size_t nr_segs; - ssize_t err; - - if (!access_ok(VERIFY_READ, umsg, sizeof(*umsg)) || - __get_user(uaddr, &umsg->msg_name) || - __get_user(kmsg->msg_namelen, &umsg->msg_namelen) || - __get_user(uiov, &umsg->msg_iov) || - __get_user(nr_segs, &umsg->msg_iovlen) || - __get_user(kmsg->msg_control, &umsg->msg_control) || - __get_user(kmsg->msg_controllen, &umsg->msg_controllen) || - __get_user(kmsg->msg_flags, &umsg->msg_flags)) - return -EFAULT; - - if (!uaddr) - kmsg->msg_namelen = 0; - - if (kmsg->msg_namelen < 0) - return -EINVAL; - - if (kmsg->msg_namelen > sizeof(struct sockaddr_storage)) - kmsg->msg_namelen = sizeof(struct sockaddr_storage); - - if (save_addr) - *save_addr = uaddr; - - if (uaddr && kmsg->msg_namelen) { - if (!save_addr) { - err = move_addr_to_kernel(uaddr, kmsg->msg_namelen, - kmsg->msg_name); - if (err < 0) - return err; - } - } else { - kmsg->msg_name = NULL; - kmsg->msg_namelen = 0; - } - - if (nr_segs > UIO_MAXIOV) - return -EMSGSIZE; - - kmsg->msg_iocb = NULL; - - return import_iovec(save_addr ? READ : WRITE, uiov, nr_segs, - UIO_FASTIOV, iov, &kmsg->msg_iter); -} - -static int ___sys_sendmsg(struct socket *sock, struct user_msghdr __user *msg, - struct msghdr *msg_sys, unsigned int flags, - struct used_address *used_address, - unsigned int allowed_msghdr_flags) -{ - struct compat_msghdr __user *msg_compat = - (struct compat_msghdr __user *)msg; - struct sockaddr_storage address; - struct iovec iovstack[UIO_FASTIOV], *iov = iovstack; - unsigned char ctl[sizeof(struct cmsghdr) + 20] - __attribute__ ((aligned(sizeof(__kernel_size_t)))); - /* 20 is size of ipv6_pktinfo */ - unsigned char *ctl_buf = ctl; - int ctl_len; - ssize_t err; - - msg_sys->msg_name = &address; - - if (MSG_CMSG_COMPAT & flags) - err = get_compat_msghdr(msg_sys, msg_compat, NULL, &iov); - else - err = copy_msghdr_from_user(msg_sys, msg, NULL, &iov); - if (err < 0) - return err; - - err = -ENOBUFS; - - if (msg_sys->msg_controllen > INT_MAX) - goto out_freeiov; - flags |= (msg_sys->msg_flags & allowed_msghdr_flags); - ctl_len = msg_sys->msg_controllen; - if ((MSG_CMSG_COMPAT & flags) && ctl_len) { - err = - cmsghdr_from_user_compat_to_kern(msg_sys, sock->sk, ctl, - sizeof(ctl)); - if (err) - goto out_freeiov; - ctl_buf = msg_sys->msg_control; - ctl_len = msg_sys->msg_controllen; - } else if (ctl_len) { - if (ctl_len > sizeof(ctl)) { - ctl_buf = sock_kmalloc(sock->sk, ctl_len, GFP_KERNEL); - if (ctl_buf == NULL) - goto out_freeiov; - } - err = -EFAULT; - /* - * Careful! Before this, msg_sys->msg_control contains a user pointer. - * Afterwards, it will be a kernel pointer. Thus the compiler-assisted - * checking falls down on this. - */ - if (copy_from_user(ctl_buf, - (void __user __force *)msg_sys->msg_control, - ctl_len)) - goto out_freectl; - msg_sys->msg_control = ctl_buf; - } - msg_sys->msg_flags = flags; - - if (sock->file->f_flags & O_NONBLOCK) - msg_sys->msg_flags |= MSG_DONTWAIT; - /* - * If this is sendmmsg() and current destination address is same as - * previously succeeded address, omit asking LSM's decision. - * used_address->name_len is initialized to UINT_MAX so that the first - * destination address never matches. - */ - if (used_address && msg_sys->msg_name && - used_address->name_len == msg_sys->msg_namelen && - !memcmp(&used_address->name, msg_sys->msg_name, - used_address->name_len)) { - err = sock_sendmsg_nosec(sock, msg_sys); - goto out_freectl; - } - err = sock_sendmsg(sock, msg_sys); - /* - * If this is sendmmsg() and sending to current destination address was - * successful, remember it. - */ - if (used_address && err >= 0) { - used_address->name_len = msg_sys->msg_namelen; - if (msg_sys->msg_name) - memcpy(&used_address->name, msg_sys->msg_name, - used_address->name_len); - } - -out_freectl: - if (ctl_buf != ctl) - sock_kfree_s(sock->sk, ctl_buf, ctl_len); -out_freeiov: - kfree(iov); - return err; -} - -/* - * BSD sendmsg interface - */ - -long __sys_sendmsg(int fd, struct user_msghdr __user *msg, unsigned flags) -{ - int fput_needed, err; - struct msghdr msg_sys; - struct socket *sock; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - goto out; - - err = ___sys_sendmsg(sock, msg, &msg_sys, flags, NULL, 0); - - fput_light(sock->file, fput_needed); -out: - return err; -} - -SYSCALL_DEFINE3(sendmsg, int, fd, struct user_msghdr __user *, msg, unsigned int, flags) -{ - if (flags & MSG_CMSG_COMPAT) - return -EINVAL; - return __sys_sendmsg(fd, msg, flags); -} - -/* - * Linux sendmmsg interface - */ - -int __sys_sendmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, - unsigned int flags) -{ - int fput_needed, err, datagrams; - struct socket *sock; - struct mmsghdr __user *entry; - struct compat_mmsghdr __user *compat_entry; - struct msghdr msg_sys; - struct used_address used_address; - unsigned int oflags = flags; - - if (vlen > UIO_MAXIOV) - vlen = UIO_MAXIOV; - - datagrams = 0; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - return err; - - used_address.name_len = UINT_MAX; - entry = mmsg; - compat_entry = (struct compat_mmsghdr __user *)mmsg; - err = 0; - flags |= MSG_BATCH; - - while (datagrams < vlen) { - if (datagrams == vlen - 1) - flags = oflags; - - if (MSG_CMSG_COMPAT & flags) { - err = ___sys_sendmsg(sock, (struct user_msghdr __user *)compat_entry, - &msg_sys, flags, &used_address, MSG_EOR); - if (err < 0) - break; - err = __put_user(err, &compat_entry->msg_len); - ++compat_entry; - } else { - err = ___sys_sendmsg(sock, - (struct user_msghdr __user *)entry, - &msg_sys, flags, &used_address, MSG_EOR); - if (err < 0) - break; - err = put_user(err, &entry->msg_len); - ++entry; - } - - if (err) - break; - ++datagrams; - if (msg_data_left(&msg_sys)) - break; - cond_resched(); - } - - fput_light(sock->file, fput_needed); - - /* We only return an error if no datagrams were able to be sent */ - if (datagrams != 0) - return datagrams; - - return err; -} - -SYSCALL_DEFINE4(sendmmsg, int, fd, struct mmsghdr __user *, mmsg, - unsigned int, vlen, unsigned int, flags) -{ - if (flags & MSG_CMSG_COMPAT) - return -EINVAL; - return __sys_sendmmsg(fd, mmsg, vlen, flags); -} - -static int ___sys_recvmsg(struct socket *sock, struct user_msghdr __user *msg, - struct msghdr *msg_sys, unsigned int flags, int nosec) -{ - struct compat_msghdr __user *msg_compat = - (struct compat_msghdr __user *)msg; - struct iovec iovstack[UIO_FASTIOV]; - struct iovec *iov = iovstack; - unsigned long cmsg_ptr; - int len; - ssize_t err; - - /* kernel mode address */ - struct sockaddr_storage addr; - - /* user mode address pointers */ - struct sockaddr __user *uaddr; - int __user *uaddr_len = COMPAT_NAMELEN(msg); - - msg_sys->msg_name = &addr; - - if (MSG_CMSG_COMPAT & flags) - err = get_compat_msghdr(msg_sys, msg_compat, &uaddr, &iov); - else - err = copy_msghdr_from_user(msg_sys, msg, &uaddr, &iov); - if (err < 0) - return err; - - cmsg_ptr = (unsigned long)msg_sys->msg_control; - msg_sys->msg_flags = flags & (MSG_CMSG_CLOEXEC|MSG_CMSG_COMPAT); - - /* We assume all kernel code knows the size of sockaddr_storage */ - msg_sys->msg_namelen = 0; - - if (sock->file->f_flags & O_NONBLOCK) - flags |= MSG_DONTWAIT; - err = (nosec ? sock_recvmsg_nosec : sock_recvmsg)(sock, msg_sys, flags); - if (err < 0) - goto out_freeiov; - len = err; - - if (uaddr != NULL) { - err = move_addr_to_user(&addr, - msg_sys->msg_namelen, uaddr, - uaddr_len); - if (err < 0) - goto out_freeiov; - } - err = __put_user((msg_sys->msg_flags & ~MSG_CMSG_COMPAT), - COMPAT_FLAGS(msg)); - if (err) - goto out_freeiov; - if (MSG_CMSG_COMPAT & flags) - err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr, - &msg_compat->msg_controllen); - else - err = __put_user((unsigned long)msg_sys->msg_control - cmsg_ptr, - &msg->msg_controllen); - if (err) - goto out_freeiov; - err = len; - -out_freeiov: - kfree(iov); - return err; -} - -/* - * BSD recvmsg interface - */ - -long __sys_recvmsg(int fd, struct user_msghdr __user *msg, unsigned flags) -{ - int fput_needed, err; - struct msghdr msg_sys; - struct socket *sock; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - goto out; - - err = ___sys_recvmsg(sock, msg, &msg_sys, flags, 0); - - fput_light(sock->file, fput_needed); -out: - return err; -} - -SYSCALL_DEFINE3(recvmsg, int, fd, struct user_msghdr __user *, msg, - unsigned int, flags) -{ - if (flags & MSG_CMSG_COMPAT) - return -EINVAL; - return __sys_recvmsg(fd, msg, flags); -} - -/* - * Linux recvmmsg interface - */ - -int __sys_recvmmsg(int fd, struct mmsghdr __user *mmsg, unsigned int vlen, - unsigned int flags, struct timespec *timeout) -{ - int fput_needed, err, datagrams; - struct socket *sock; - struct mmsghdr __user *entry; - struct compat_mmsghdr __user *compat_entry; - struct msghdr msg_sys; - struct timespec64 end_time; - struct timespec64 timeout64; - - if (timeout && - poll_select_set_timeout(&end_time, timeout->tv_sec, - timeout->tv_nsec)) - return -EINVAL; - - datagrams = 0; - - sock = sockfd_lookup_light(fd, &err, &fput_needed); - if (!sock) - return err; - - err = sock_error(sock->sk); - if (err) - goto out_put; - - entry = mmsg; - compat_entry = (struct compat_mmsghdr __user *)mmsg; - - while (datagrams < vlen) { - /* - * No need to ask LSM for more than the first datagram. - */ - if (MSG_CMSG_COMPAT & flags) { - err = ___sys_recvmsg(sock, (struct user_msghdr __user *)compat_entry, - &msg_sys, flags & ~MSG_WAITFORONE, - datagrams); - if (err < 0) - break; - err = __put_user(err, &compat_entry->msg_len); - ++compat_entry; - } else { - err = ___sys_recvmsg(sock, - (struct user_msghdr __user *)entry, - &msg_sys, flags & ~MSG_WAITFORONE, - datagrams); - if (err < 0) - break; - err = put_user(err, &entry->msg_len); - ++entry; - } - - if (err) - break; - ++datagrams; - - /* MSG_WAITFORONE turns on MSG_DONTWAIT after one packet */ - if (flags & MSG_WAITFORONE) - flags |= MSG_DONTWAIT; - - if (timeout) { - ktime_get_ts64(&timeout64); - *timeout = timespec64_to_timespec( - timespec64_sub(end_time, timeout64)); - if (timeout->tv_sec < 0) { - timeout->tv_sec = timeout->tv_nsec = 0; - break; - } - - /* Timeout, return less than vlen datagrams */ - if (timeout->tv_nsec == 0 && timeout->tv_sec == 0) - break; - } - - /* Out of band data, return right away */ - if (msg_sys.msg_flags & MSG_OOB) - break; - cond_resched(); - } - - if (err == 0) - goto out_put; - - if (datagrams == 0) { - datagrams = err; - goto out_put; - } - - /* - * We may return less entries than requested (vlen) if the - * sock is non block and there aren't enough datagrams... - */ - if (err != -EAGAIN) { - /* - * ... or if recvmsg returns an error after we - * received some datagrams, where we record the - * error to return on the next call or if the - * app asks about it using getsockopt(SO_ERROR). - */ - sock->sk->sk_err = -err; - } -out_put: - fput_light(sock->file, fput_needed); - - return datagrams; -} - -SYSCALL_DEFINE5(recvmmsg, int, fd, struct mmsghdr __user *, mmsg, - unsigned int, vlen, unsigned int, flags, - struct timespec __user *, timeout) -{ - int datagrams; - struct timespec timeout_sys; - - if (flags & MSG_CMSG_COMPAT) - return -EINVAL; - - if (!timeout) - return __sys_recvmmsg(fd, mmsg, vlen, flags, NULL); - - if (copy_from_user(&timeout_sys, timeout, sizeof(timeout_sys))) - return -EFAULT; - - datagrams = __sys_recvmmsg(fd, mmsg, vlen, flags, &timeout_sys); - - if (datagrams > 0 && - copy_to_user(timeout, &timeout_sys, sizeof(timeout_sys))) - datagrams = -EFAULT; - - return datagrams; -} - -#ifdef __ARCH_WANT_SYS_SOCKETCALL -/* Argument list sizes for sys_socketcall */ -#define AL(x) ((x) * sizeof(unsigned long)) -static const unsigned char nargs[21] = { - AL(0), AL(3), AL(3), AL(3), AL(2), AL(3), - AL(3), AL(3), AL(4), AL(4), AL(4), AL(6), - AL(6), AL(2), AL(5), AL(5), AL(3), AL(3), - AL(4), AL(5), AL(4) -}; - -#undef AL - -/* - * System call vectors. - * - * Argument checking cleaned up. Saved 20% in size. - * This function doesn't need to set the kernel lock because - * it is set by the callees. - */ - -SYSCALL_DEFINE2(socketcall, int, call, unsigned long __user *, args) -{ - unsigned long a[AUDITSC_ARGS]; - unsigned long a0, a1; - int err; - unsigned int len; - - if (call < 1 || call > SYS_SENDMMSG) - return -EINVAL; - - len = nargs[call]; - if (len > sizeof(a)) - return -EINVAL; - - /* copy_from_user should be SMP safe. */ - if (copy_from_user(a, args, len)) - return -EFAULT; - - err = audit_socketcall(nargs[call] / sizeof(unsigned long), a); - if (err) - return err; - - a0 = a[0]; - a1 = a[1]; - - switch (call) { - case SYS_SOCKET: - err = sys_socket(a0, a1, a[2]); - break; - case SYS_BIND: - err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]); - break; - case SYS_CONNECT: - err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]); - break; - case SYS_LISTEN: - err = sys_listen(a0, a1); - break; - case SYS_ACCEPT: - err = sys_accept4(a0, (struct sockaddr __user *)a1, - (int __user *)a[2], 0); - break; - case SYS_GETSOCKNAME: - err = - sys_getsockname(a0, (struct sockaddr __user *)a1, - (int __user *)a[2]); - break; - case SYS_GETPEERNAME: - err = - sys_getpeername(a0, (struct sockaddr __user *)a1, - (int __user *)a[2]); - break; - case SYS_SOCKETPAIR: - err = sys_socketpair(a0, a1, a[2], (int __user *)a[3]); - break; - case SYS_SEND: - err = sys_send(a0, (void __user *)a1, a[2], a[3]); - break; - case SYS_SENDTO: - err = sys_sendto(a0, (void __user *)a1, a[2], a[3], - (struct sockaddr __user *)a[4], a[5]); - break; - case SYS_RECV: - err = sys_recv(a0, (void __user *)a1, a[2], a[3]); - break; - case SYS_RECVFROM: - err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3], - (struct sockaddr __user *)a[4], - (int __user *)a[5]); - break; - case SYS_SHUTDOWN: - err = sys_shutdown(a0, a1); - break; - case SYS_SETSOCKOPT: - err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]); - break; - case SYS_GETSOCKOPT: - err = - sys_getsockopt(a0, a1, a[2], (char __user *)a[3], - (int __user *)a[4]); - break; - case SYS_SENDMSG: - err = sys_sendmsg(a0, (struct user_msghdr __user *)a1, a[2]); - break; - case SYS_SENDMMSG: - err = sys_sendmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3]); - break; - case SYS_RECVMSG: - err = sys_recvmsg(a0, (struct user_msghdr __user *)a1, a[2]); - break; - case SYS_RECVMMSG: - err = sys_recvmmsg(a0, (struct mmsghdr __user *)a1, a[2], a[3], - (struct timespec __user *)a[4]); - break; - case SYS_ACCEPT4: - err = sys_accept4(a0, (struct sockaddr __user *)a1, - (int __user *)a[2], a[3]); - break; - default: - err = -EINVAL; - break; - } - return err; -} - -#endif /* __ARCH_WANT_SYS_SOCKETCALL */ - -/** - * sock_register - add a socket protocol handler - * @ops: description of protocol - * - * This function is called by a protocol handler that wants to - * advertise its address family, and have it linked into the - * socket interface. The value ops->family corresponds to the - * socket system call protocol family. - */ -int sock_register(const struct net_proto_family *ops) -{ - int err; - - if (ops->family >= NPROTO) { - pr_crit("protocol %d >= NPROTO(%d)\n", ops->family, NPROTO); - return -ENOBUFS; - } - - spin_lock(&net_family_lock); - if (rcu_dereference_protected(net_families[ops->family], - lockdep_is_held(&net_family_lock))) - err = -EEXIST; - else { - rcu_assign_pointer(net_families[ops->family], ops); - err = 0; - } - spin_unlock(&net_family_lock); - - pr_info("NET: Registered protocol family %d\n", ops->family); - return err; -} -EXPORT_SYMBOL(sock_register); - -/** - * sock_unregister - remove a protocol handler - * @family: protocol family to remove - * - * This function is called by a protocol handler that wants to - * remove its address family, and have it unlinked from the - * new socket creation. - * - * If protocol handler is a module, then it can use module reference - * counts to protect against new references. If protocol handler is not - * a module then it needs to provide its own protection in - * the ops->create routine. - */ -void sock_unregister(int family) -{ - BUG_ON(family < 0 || family >= NPROTO); - - spin_lock(&net_family_lock); - RCU_INIT_POINTER(net_families[family], NULL); - spin_unlock(&net_family_lock); - - synchronize_rcu(); - - pr_info("NET: Unregistered protocol family %d\n", family); -} -EXPORT_SYMBOL(sock_unregister); - -static int __init sock_init(void) -{ - int err; - /* - * Initialize the network sysctl infrastructure. - */ - err = net_sysctl_init(); - if (err) - goto out; - - /* - * Initialize skbuff SLAB cache - */ - skb_init(); - - /* - * Initialize the protocols module. - */ - - init_inodecache(); - - err = register_filesystem(&sock_fs_type); - if (err) - goto out_fs; - sock_mnt = kern_mount(&sock_fs_type); - if (IS_ERR(sock_mnt)) { - err = PTR_ERR(sock_mnt); - goto out_mount; - } - - /* The real protocol initialization is performed in later initcalls. - */ - -#ifdef CONFIG_NETFILTER - err = netfilter_init(); - if (err) - goto out; -#endif - - ptp_classifier_init(); - -out: - return err; - -out_mount: - unregister_filesystem(&sock_fs_type); -out_fs: - goto out; -} - -core_initcall(sock_init); /* early initcall */ - -#ifdef CONFIG_PROC_FS -void socket_seq_show(struct seq_file *seq) -{ - int cpu; - int counter = 0; - - for_each_possible_cpu(cpu) - counter += per_cpu(sockets_in_use, cpu); - - /* It can be negative, by the way. 8) */ - if (counter < 0) - counter = 0; - - seq_printf(seq, "sockets: used %d\n", counter); -} -#endif /* CONFIG_PROC_FS */ - -#ifdef CONFIG_COMPAT -static int do_siocgstamp(struct net *net, struct socket *sock, - unsigned int cmd, void __user *up) -{ - mm_segment_t old_fs = get_fs(); - struct timeval ktv; - int err; - - set_fs(KERNEL_DS); - err = sock_do_ioctl(net, sock, cmd, (unsigned long)&ktv); - set_fs(old_fs); - if (!err) - err = compat_put_timeval(&ktv, up); - - return err; -} - -static int do_siocgstampns(struct net *net, struct socket *sock, - unsigned int cmd, void __user *up) -{ - mm_segment_t old_fs = get_fs(); - struct timespec kts; - int err; - - set_fs(KERNEL_DS); - err = sock_do_ioctl(net, sock, cmd, (unsigned long)&kts); - set_fs(old_fs); - if (!err) - err = compat_put_timespec(&kts, up); - - return err; -} - -static int dev_ifname32(struct net *net, struct compat_ifreq __user *uifr32) -{ - struct ifreq __user *uifr; - int err; - - uifr = compat_alloc_user_space(sizeof(struct ifreq)); - if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) - return -EFAULT; - - err = dev_ioctl(net, SIOCGIFNAME, uifr); - if (err) - return err; - - if (copy_in_user(uifr32, uifr, sizeof(struct compat_ifreq))) - return -EFAULT; - - return 0; -} - -static int dev_ifconf(struct net *net, struct compat_ifconf __user *uifc32) -{ - struct compat_ifconf ifc32; - struct ifconf ifc; - struct ifconf __user *uifc; - struct compat_ifreq __user *ifr32; - struct ifreq __user *ifr; - unsigned int i, j; - int err; - - if (copy_from_user(&ifc32, uifc32, sizeof(struct compat_ifconf))) - return -EFAULT; - - memset(&ifc, 0, sizeof(ifc)); - if (ifc32.ifcbuf == 0) { - ifc32.ifc_len = 0; - ifc.ifc_len = 0; - ifc.ifc_req = NULL; - uifc = compat_alloc_user_space(sizeof(struct ifconf)); - } else { - size_t len = ((ifc32.ifc_len / sizeof(struct compat_ifreq)) + 1) * - sizeof(struct ifreq); - uifc = compat_alloc_user_space(sizeof(struct ifconf) + len); - ifc.ifc_len = len; - ifr = ifc.ifc_req = (void __user *)(uifc + 1); - ifr32 = compat_ptr(ifc32.ifcbuf); - for (i = 0; i < ifc32.ifc_len; i += sizeof(struct compat_ifreq)) { - if (copy_in_user(ifr, ifr32, sizeof(struct compat_ifreq))) - return -EFAULT; - ifr++; - ifr32++; - } - } - if (copy_to_user(uifc, &ifc, sizeof(struct ifconf))) - return -EFAULT; - - err = dev_ioctl(net, SIOCGIFCONF, uifc); - if (err) - return err; - - if (copy_from_user(&ifc, uifc, sizeof(struct ifconf))) - return -EFAULT; - - ifr = ifc.ifc_req; - ifr32 = compat_ptr(ifc32.ifcbuf); - for (i = 0, j = 0; - i + sizeof(struct compat_ifreq) <= ifc32.ifc_len && j < ifc.ifc_len; - i += sizeof(struct compat_ifreq), j += sizeof(struct ifreq)) { - if (copy_in_user(ifr32, ifr, sizeof(struct compat_ifreq))) - return -EFAULT; - ifr32++; - ifr++; - } - - if (ifc32.ifcbuf == 0) { - /* Translate from 64-bit structure multiple to - * a 32-bit one. - */ - i = ifc.ifc_len; - i = ((i / sizeof(struct ifreq)) * sizeof(struct compat_ifreq)); - ifc32.ifc_len = i; - } else { - ifc32.ifc_len = i; - } - if (copy_to_user(uifc32, &ifc32, sizeof(struct compat_ifconf))) - return -EFAULT; - - return 0; -} - -static int ethtool_ioctl(struct net *net, struct compat_ifreq __user *ifr32) -{ - struct compat_ethtool_rxnfc __user *compat_rxnfc; - bool convert_in = false, convert_out = false; - size_t buf_size = ALIGN(sizeof(struct ifreq), 8); - struct ethtool_rxnfc __user *rxnfc; - struct ifreq __user *ifr; - u32 rule_cnt = 0, actual_rule_cnt; - u32 ethcmd; - u32 data; - int ret; - - if (get_user(data, &ifr32->ifr_ifru.ifru_data)) - return -EFAULT; - - compat_rxnfc = compat_ptr(data); - - if (get_user(ethcmd, &compat_rxnfc->cmd)) - return -EFAULT; - - /* Most ethtool structures are defined without padding. - * Unfortunately struct ethtool_rxnfc is an exception. - */ - switch (ethcmd) { - default: - break; - case ETHTOOL_GRXCLSRLALL: - /* Buffer size is variable */ - if (get_user(rule_cnt, &compat_rxnfc->rule_cnt)) - return -EFAULT; - if (rule_cnt > KMALLOC_MAX_SIZE / sizeof(u32)) - return -ENOMEM; - buf_size += rule_cnt * sizeof(u32); - /* fall through */ - case ETHTOOL_GRXRINGS: - case ETHTOOL_GRXCLSRLCNT: - case ETHTOOL_GRXCLSRULE: - case ETHTOOL_SRXCLSRLINS: - convert_out = true; - /* fall through */ - case ETHTOOL_SRXCLSRLDEL: - buf_size += sizeof(struct ethtool_rxnfc); - convert_in = true; - break; - } - - ifr = compat_alloc_user_space(buf_size); - rxnfc = (void __user *)ifr + ALIGN(sizeof(struct ifreq), 8); - - if (copy_in_user(&ifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) - return -EFAULT; - - if (put_user(convert_in ? rxnfc : compat_ptr(data), - &ifr->ifr_ifru.ifru_data)) - return -EFAULT; - - if (convert_in) { - /* We expect there to be holes between fs.m_ext and - * fs.ring_cookie and at the end of fs, but nowhere else. - */ - BUILD_BUG_ON(offsetof(struct compat_ethtool_rxnfc, fs.m_ext) + - sizeof(compat_rxnfc->fs.m_ext) != - offsetof(struct ethtool_rxnfc, fs.m_ext) + - sizeof(rxnfc->fs.m_ext)); - BUILD_BUG_ON( - offsetof(struct compat_ethtool_rxnfc, fs.location) - - offsetof(struct compat_ethtool_rxnfc, fs.ring_cookie) != - offsetof(struct ethtool_rxnfc, fs.location) - - offsetof(struct ethtool_rxnfc, fs.ring_cookie)); - - if (copy_in_user(rxnfc, compat_rxnfc, - (void __user *)(&rxnfc->fs.m_ext + 1) - - (void __user *)rxnfc) || - copy_in_user(&rxnfc->fs.ring_cookie, - &compat_rxnfc->fs.ring_cookie, - (void __user *)(&rxnfc->fs.location + 1) - - (void __user *)&rxnfc->fs.ring_cookie) || - copy_in_user(&rxnfc->rule_cnt, &compat_rxnfc->rule_cnt, - sizeof(rxnfc->rule_cnt))) - return -EFAULT; - } - - ret = dev_ioctl(net, SIOCETHTOOL, ifr); - if (ret) - return ret; - - if (convert_out) { - if (copy_in_user(compat_rxnfc, rxnfc, - (const void __user *)(&rxnfc->fs.m_ext + 1) - - (const void __user *)rxnfc) || - copy_in_user(&compat_rxnfc->fs.ring_cookie, - &rxnfc->fs.ring_cookie, - (const void __user *)(&rxnfc->fs.location + 1) - - (const void __user *)&rxnfc->fs.ring_cookie) || - copy_in_user(&compat_rxnfc->rule_cnt, &rxnfc->rule_cnt, - sizeof(rxnfc->rule_cnt))) - return -EFAULT; - - if (ethcmd == ETHTOOL_GRXCLSRLALL) { - /* As an optimisation, we only copy the actual - * number of rules that the underlying - * function returned. Since Mallory might - * change the rule count in user memory, we - * check that it is less than the rule count - * originally given (as the user buffer size), - * which has been range-checked. - */ - if (get_user(actual_rule_cnt, &rxnfc->rule_cnt)) - return -EFAULT; - if (actual_rule_cnt < rule_cnt) - rule_cnt = actual_rule_cnt; - if (copy_in_user(&compat_rxnfc->rule_locs[0], - &rxnfc->rule_locs[0], - rule_cnt * sizeof(u32))) - return -EFAULT; - } - } - - return 0; -} - -static int compat_siocwandev(struct net *net, struct compat_ifreq __user *uifr32) -{ - void __user *uptr; - compat_uptr_t uptr32; - struct ifreq __user *uifr; - - uifr = compat_alloc_user_space(sizeof(*uifr)); - if (copy_in_user(uifr, uifr32, sizeof(struct compat_ifreq))) - return -EFAULT; - - if (get_user(uptr32, &uifr32->ifr_settings.ifs_ifsu)) - return -EFAULT; - - uptr = compat_ptr(uptr32); - - if (put_user(uptr, &uifr->ifr_settings.ifs_ifsu.raw_hdlc)) - return -EFAULT; - - return dev_ioctl(net, SIOCWANDEV, uifr); -} - -static int bond_ioctl(struct net *net, unsigned int cmd, - struct compat_ifreq __user *ifr32) -{ - struct ifreq kifr; - mm_segment_t old_fs; - int err; - - switch (cmd) { - case SIOCBONDENSLAVE: - case SIOCBONDRELEASE: - case SIOCBONDSETHWADDR: - case SIOCBONDCHANGEACTIVE: - if (copy_from_user(&kifr, ifr32, sizeof(struct compat_ifreq))) - return -EFAULT; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = dev_ioctl(net, cmd, - (struct ifreq __user __force *) &kifr); - set_fs(old_fs); - - return err; - default: - return -ENOIOCTLCMD; - } -} - -/* Handle ioctls that use ifreq::ifr_data and just need struct ifreq converted */ -static int compat_ifr_data_ioctl(struct net *net, unsigned int cmd, - struct compat_ifreq __user *u_ifreq32) -{ - struct ifreq __user *u_ifreq64; - char tmp_buf[IFNAMSIZ]; - void __user *data64; - u32 data32; - - if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), - IFNAMSIZ)) - return -EFAULT; - if (get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) - return -EFAULT; - data64 = compat_ptr(data32); - - u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); - - if (copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], - IFNAMSIZ)) - return -EFAULT; - if (put_user(data64, &u_ifreq64->ifr_ifru.ifru_data)) - return -EFAULT; - - return dev_ioctl(net, cmd, u_ifreq64); -} - -static int dev_ifsioc(struct net *net, struct socket *sock, - unsigned int cmd, struct compat_ifreq __user *uifr32) -{ - struct ifreq __user *uifr; - int err; - - uifr = compat_alloc_user_space(sizeof(*uifr)); - if (copy_in_user(uifr, uifr32, sizeof(*uifr32))) - return -EFAULT; - - err = sock_do_ioctl(net, sock, cmd, (unsigned long)uifr); - - if (!err) { - switch (cmd) { - case SIOCGIFFLAGS: - case SIOCGIFMETRIC: - case SIOCGIFMTU: - case SIOCGIFMEM: - case SIOCGIFHWADDR: - case SIOCGIFINDEX: - case SIOCGIFADDR: - case SIOCGIFBRDADDR: - case SIOCGIFDSTADDR: - case SIOCGIFNETMASK: - case SIOCGIFPFLAGS: - case SIOCGIFTXQLEN: - case SIOCGMIIPHY: - case SIOCGMIIREG: - if (copy_in_user(uifr32, uifr, sizeof(*uifr32))) - err = -EFAULT; - break; - } - } - return err; -} - -static int compat_sioc_ifmap(struct net *net, unsigned int cmd, - struct compat_ifreq __user *uifr32) -{ - struct ifreq ifr; - struct compat_ifmap __user *uifmap32; - mm_segment_t old_fs; - int err; - - uifmap32 = &uifr32->ifr_ifru.ifru_map; - err = copy_from_user(&ifr, uifr32, sizeof(ifr.ifr_name)); - err |= get_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); - err |= get_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); - err |= get_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); - err |= get_user(ifr.ifr_map.irq, &uifmap32->irq); - err |= get_user(ifr.ifr_map.dma, &uifmap32->dma); - err |= get_user(ifr.ifr_map.port, &uifmap32->port); - if (err) - return -EFAULT; - - old_fs = get_fs(); - set_fs(KERNEL_DS); - err = dev_ioctl(net, cmd, (void __user __force *)&ifr); - set_fs(old_fs); - - if (cmd == SIOCGIFMAP && !err) { - err = copy_to_user(uifr32, &ifr, sizeof(ifr.ifr_name)); - err |= put_user(ifr.ifr_map.mem_start, &uifmap32->mem_start); - err |= put_user(ifr.ifr_map.mem_end, &uifmap32->mem_end); - err |= put_user(ifr.ifr_map.base_addr, &uifmap32->base_addr); - err |= put_user(ifr.ifr_map.irq, &uifmap32->irq); - err |= put_user(ifr.ifr_map.dma, &uifmap32->dma); - err |= put_user(ifr.ifr_map.port, &uifmap32->port); - if (err) - err = -EFAULT; - } - return err; -} - -struct rtentry32 { - u32 rt_pad1; - struct sockaddr rt_dst; /* target address */ - struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ - struct sockaddr rt_genmask; /* target network mask (IP) */ - unsigned short rt_flags; - short rt_pad2; - u32 rt_pad3; - unsigned char rt_tos; - unsigned char rt_class; - short rt_pad4; - short rt_metric; /* +1 for binary compatibility! */ - /* char * */ u32 rt_dev; /* forcing the device at add */ - u32 rt_mtu; /* per route MTU/Window */ - u32 rt_window; /* Window clamping */ - unsigned short rt_irtt; /* Initial RTT */ -}; - -struct in6_rtmsg32 { - struct in6_addr rtmsg_dst; - struct in6_addr rtmsg_src; - struct in6_addr rtmsg_gateway; - u32 rtmsg_type; - u16 rtmsg_dst_len; - u16 rtmsg_src_len; - u32 rtmsg_metric; - u32 rtmsg_info; - u32 rtmsg_flags; - s32 rtmsg_ifindex; -}; - -static int routing_ioctl(struct net *net, struct socket *sock, - unsigned int cmd, void __user *argp) -{ - int ret; - void *r = NULL; - struct in6_rtmsg r6; - struct rtentry r4; - char devname[16]; - u32 rtdev; - mm_segment_t old_fs = get_fs(); - - if (sock && sock->sk && sock->sk->sk_family == AF_INET6) { /* ipv6 */ - struct in6_rtmsg32 __user *ur6 = argp; - ret = copy_from_user(&r6.rtmsg_dst, &(ur6->rtmsg_dst), - 3 * sizeof(struct in6_addr)); - ret |= get_user(r6.rtmsg_type, &(ur6->rtmsg_type)); - ret |= get_user(r6.rtmsg_dst_len, &(ur6->rtmsg_dst_len)); - ret |= get_user(r6.rtmsg_src_len, &(ur6->rtmsg_src_len)); - ret |= get_user(r6.rtmsg_metric, &(ur6->rtmsg_metric)); - ret |= get_user(r6.rtmsg_info, &(ur6->rtmsg_info)); - ret |= get_user(r6.rtmsg_flags, &(ur6->rtmsg_flags)); - ret |= get_user(r6.rtmsg_ifindex, &(ur6->rtmsg_ifindex)); - - r = (void *) &r6; - } else { /* ipv4 */ - struct rtentry32 __user *ur4 = argp; - ret = copy_from_user(&r4.rt_dst, &(ur4->rt_dst), - 3 * sizeof(struct sockaddr)); - ret |= get_user(r4.rt_flags, &(ur4->rt_flags)); - ret |= get_user(r4.rt_metric, &(ur4->rt_metric)); - ret |= get_user(r4.rt_mtu, &(ur4->rt_mtu)); - ret |= get_user(r4.rt_window, &(ur4->rt_window)); - ret |= get_user(r4.rt_irtt, &(ur4->rt_irtt)); - ret |= get_user(rtdev, &(ur4->rt_dev)); - if (rtdev) { - ret |= copy_from_user(devname, compat_ptr(rtdev), 15); - r4.rt_dev = (char __user __force *)devname; - devname[15] = 0; - } else - r4.rt_dev = NULL; - - r = (void *) &r4; - } - - if (ret) { - ret = -EFAULT; - goto out; - } - - set_fs(KERNEL_DS); - ret = sock_do_ioctl(net, sock, cmd, (unsigned long) r); - set_fs(old_fs); - -out: - return ret; -} - -/* Since old style bridge ioctl's endup using SIOCDEVPRIVATE - * for some operations; this forces use of the newer bridge-utils that - * use compatible ioctls - */ -static int old_bridge_ioctl(compat_ulong_t __user *argp) -{ - compat_ulong_t tmp; - - if (get_user(tmp, argp)) - return -EFAULT; - if (tmp == BRCTL_GET_VERSION) - return BRCTL_VERSION + 1; - return -EINVAL; -} - -static int compat_sock_ioctl_trans(struct file *file, struct socket *sock, - unsigned int cmd, unsigned long arg) -{ - void __user *argp = compat_ptr(arg); - struct sock *sk = sock->sk; - struct net *net = sock_net(sk); - - if (cmd >= SIOCDEVPRIVATE && cmd <= (SIOCDEVPRIVATE + 15)) - return compat_ifr_data_ioctl(net, cmd, argp); - - switch (cmd) { - case SIOCSIFBR: - case SIOCGIFBR: - return old_bridge_ioctl(argp); - case SIOCGIFNAME: - return dev_ifname32(net, argp); - case SIOCGIFCONF: - return dev_ifconf(net, argp); - case SIOCETHTOOL: - return ethtool_ioctl(net, argp); - case SIOCWANDEV: - return compat_siocwandev(net, argp); - case SIOCGIFMAP: - case SIOCSIFMAP: - return compat_sioc_ifmap(net, cmd, argp); - case SIOCBONDENSLAVE: - case SIOCBONDRELEASE: - case SIOCBONDSETHWADDR: - case SIOCBONDCHANGEACTIVE: - return bond_ioctl(net, cmd, argp); - case SIOCADDRT: - case SIOCDELRT: - return routing_ioctl(net, sock, cmd, argp); - case SIOCGSTAMP: - return do_siocgstamp(net, sock, cmd, argp); - case SIOCGSTAMPNS: - return do_siocgstampns(net, sock, cmd, argp); - case SIOCBONDSLAVEINFOQUERY: - case SIOCBONDINFOQUERY: - case SIOCSHWTSTAMP: - case SIOCGHWTSTAMP: - return compat_ifr_data_ioctl(net, cmd, argp); - - case FIOSETOWN: - case SIOCSPGRP: - case FIOGETOWN: - case SIOCGPGRP: - case SIOCBRADDBR: - case SIOCBRDELBR: - case SIOCGIFVLAN: - case SIOCSIFVLAN: - case SIOCADDDLCI: - case SIOCDELDLCI: - return sock_ioctl(file, cmd, arg); - - case SIOCGIFFLAGS: - case SIOCSIFFLAGS: - case SIOCGIFMETRIC: - case SIOCSIFMETRIC: - case SIOCGIFMTU: - case SIOCSIFMTU: - case SIOCGIFMEM: - case SIOCSIFMEM: - case SIOCGIFHWADDR: - case SIOCSIFHWADDR: - case SIOCADDMULTI: - case SIOCDELMULTI: - case SIOCGIFINDEX: - case SIOCGIFADDR: - case SIOCSIFADDR: - case SIOCSIFHWBROADCAST: - case SIOCDIFADDR: - case SIOCGIFBRDADDR: - case SIOCSIFBRDADDR: - case SIOCGIFDSTADDR: - case SIOCSIFDSTADDR: - case SIOCGIFNETMASK: - case SIOCSIFNETMASK: - case SIOCSIFPFLAGS: - case SIOCGIFPFLAGS: - case SIOCGIFTXQLEN: - case SIOCSIFTXQLEN: - case SIOCBRADDIF: - case SIOCBRDELIF: - case SIOCSIFNAME: - case SIOCGMIIPHY: - case SIOCGMIIREG: - case SIOCSMIIREG: - return dev_ifsioc(net, sock, cmd, argp); - - case SIOCSARP: - case SIOCGARP: - case SIOCDARP: - case SIOCATMARK: - return sock_do_ioctl(net, sock, cmd, arg); - } - - return -ENOIOCTLCMD; -} - -static long compat_sock_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct socket *sock = file->private_data; - int ret = -ENOIOCTLCMD; - struct sock *sk; - struct net *net; - - sk = sock->sk; - net = sock_net(sk); - - if (sock->ops->compat_ioctl) - ret = sock->ops->compat_ioctl(sock, cmd, arg); - - if (ret == -ENOIOCTLCMD && - (cmd >= SIOCIWFIRST && cmd <= SIOCIWLAST)) - ret = compat_wext_handle_ioctl(net, cmd, arg); - - if (ret == -ENOIOCTLCMD) - ret = compat_sock_ioctl_trans(file, sock, cmd, arg); - - return ret; -} -#endif - -int kernel_bind(struct socket *sock, struct sockaddr *addr, int addrlen) -{ - return sock->ops->bind(sock, addr, addrlen); -} -EXPORT_SYMBOL(kernel_bind); - -int kernel_listen(struct socket *sock, int backlog) -{ - return sock->ops->listen(sock, backlog); -} -EXPORT_SYMBOL(kernel_listen); - -int kernel_accept(struct socket *sock, struct socket **newsock, int flags) -{ - struct sock *sk = sock->sk; - int err; - - err = sock_create_lite(sk->sk_family, sk->sk_type, sk->sk_protocol, - newsock); - if (err < 0) - goto done; - - err = sock->ops->accept(sock, *newsock, flags); - if (err < 0) { - sock_release(*newsock); - *newsock = NULL; - goto done; - } - - (*newsock)->ops = sock->ops; - __module_get((*newsock)->ops->owner); - -done: - return err; -} -EXPORT_SYMBOL(kernel_accept); - -int kernel_connect(struct socket *sock, struct sockaddr *addr, int addrlen, - int flags) -{ - return sock->ops->connect(sock, addr, addrlen, flags); -} -EXPORT_SYMBOL(kernel_connect); - -int kernel_getsockname(struct socket *sock, struct sockaddr *addr, - int *addrlen) -{ - return sock->ops->getname(sock, addr, addrlen, 0); -} -EXPORT_SYMBOL(kernel_getsockname); - -int kernel_getpeername(struct socket *sock, struct sockaddr *addr, - int *addrlen) -{ - return sock->ops->getname(sock, addr, addrlen, 1); -} -EXPORT_SYMBOL(kernel_getpeername); - -int kernel_getsockopt(struct socket *sock, int level, int optname, - char *optval, int *optlen) -{ - mm_segment_t oldfs = get_fs(); - char __user *uoptval; - int __user *uoptlen; - int err; - - uoptval = (char __user __force *) optval; - uoptlen = (int __user __force *) optlen; - - set_fs(KERNEL_DS); - if (level == SOL_SOCKET) - err = sock_getsockopt(sock, level, optname, uoptval, uoptlen); - else - err = sock->ops->getsockopt(sock, level, optname, uoptval, - uoptlen); - set_fs(oldfs); - return err; -} -EXPORT_SYMBOL(kernel_getsockopt); - -int kernel_setsockopt(struct socket *sock, int level, int optname, - char *optval, unsigned int optlen) -{ - mm_segment_t oldfs = get_fs(); - char __user *uoptval; - int err; - - uoptval = (char __user __force *) optval; - - set_fs(KERNEL_DS); - if (level == SOL_SOCKET) - err = sock_setsockopt(sock, level, optname, uoptval, optlen); - else - err = sock->ops->setsockopt(sock, level, optname, uoptval, - optlen); - set_fs(oldfs); - return err; -} -EXPORT_SYMBOL(kernel_setsockopt); - -int kernel_sendpage(struct socket *sock, struct page *page, int offset, - size_t size, int flags) -{ - if (sock->ops->sendpage) - return sock->ops->sendpage(sock, page, offset, size, flags); - - return sock_no_sendpage(sock, page, offset, size, flags); -} -EXPORT_SYMBOL(kernel_sendpage); - -int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg) -{ - mm_segment_t oldfs = get_fs(); - int err; - - set_fs(KERNEL_DS); - err = sock->ops->ioctl(sock, cmd, arg); - set_fs(oldfs); - - return err; -} -EXPORT_SYMBOL(kernel_sock_ioctl); - -int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how) -{ - return sock->ops->shutdown(sock, how); -} -EXPORT_SYMBOL(kernel_sock_shutdown); diff --git a/src/linux/net/strparser/Kconfig b/src/linux/net/strparser/Kconfig deleted file mode 100644 index 6cff3f6..0000000 --- a/src/linux/net/strparser/Kconfig +++ /dev/null @@ -1,4 +0,0 @@ - -config STREAM_PARSER - tristate - default n diff --git a/src/linux/net/sunrpc/Kconfig b/src/linux/net/sunrpc/Kconfig deleted file mode 100644 index 04ce2c0..0000000 --- a/src/linux/net/sunrpc/Kconfig +++ /dev/null @@ -1,63 +0,0 @@ -config SUNRPC - tristate - depends on MULTIUSER - -config SUNRPC_GSS - tristate - select OID_REGISTRY - depends on MULTIUSER - -config SUNRPC_BACKCHANNEL - bool - depends on SUNRPC - -config SUNRPC_SWAP - bool - depends on SUNRPC - -config RPCSEC_GSS_KRB5 - tristate "Secure RPC: Kerberos V mechanism" - depends on SUNRPC && CRYPTO - depends on CRYPTO_MD5 && CRYPTO_DES && CRYPTO_CBC && CRYPTO_CTS - depends on CRYPTO_ECB && CRYPTO_HMAC && CRYPTO_SHA1 && CRYPTO_AES - depends on CRYPTO_ARC4 - default y - select SUNRPC_GSS - help - Choose Y here to enable Secure RPC using the Kerberos version 5 - GSS-API mechanism (RFC 1964). - - Secure RPC calls with Kerberos require an auxiliary user-space - daemon which may be found in the Linux nfs-utils package - available from http://linux-nfs.org/. In addition, user-space - Kerberos support should be installed. - - If unsure, say Y. - -config SUNRPC_DEBUG - bool "RPC: Enable dprintk debugging" - depends on SUNRPC && SYSCTL - select DEBUG_FS - help - This option enables a sysctl-based debugging interface - that is be used by the 'rpcdebug' utility to turn on or off - logging of different aspects of the kernel RPC activity. - - Disabling this option will make your kernel slightly smaller, - but makes troubleshooting NFS issues significantly harder. - - If unsure, say Y. - -config SUNRPC_XPRT_RDMA - tristate "RPC-over-RDMA transport" - depends on SUNRPC && INFINIBAND && INFINIBAND_ADDR_TRANS - default SUNRPC && INFINIBAND - help - This option allows the NFS client and server to use RDMA - transports (InfiniBand, iWARP, or RoCE). - - To compile this support as a module, choose M. The module - will be called rpcrdma.ko. - - If unsure, or you know there is no RDMA capability on your - hardware platform, say N. diff --git a/src/linux/net/switchdev/Kconfig b/src/linux/net/switchdev/Kconfig deleted file mode 100644 index 651fa20..0000000 --- a/src/linux/net/switchdev/Kconfig +++ /dev/null @@ -1,13 +0,0 @@ -# -# Configuration for Switch device support -# - -config NET_SWITCHDEV - bool "Switch (and switch-ish) device support" - depends on INET - ---help--- - This module provides glue between core networking code and device - drivers in order to support hardware switch chips in very generic - meaning of the word "switch". This include devices supporting L2/L3 but - also various flow offloading chips, including switches embedded into - SR-IOV NICs. diff --git a/src/linux/net/sysctl_net.c b/src/linux/net/sysctl_net.c deleted file mode 100644 index 9199813..0000000 --- a/src/linux/net/sysctl_net.c +++ /dev/null @@ -1,129 +0,0 @@ -/* -*- linux-c -*- - * sysctl_net.c: sysctl interface to net subsystem. - * - * Begun April 1, 1996, Mike Shaver. - * Added /proc/sys/net directories for each protocol family. [MS] - * - * Revision 1.2 1996/05/08 20:24:40 shaver - * Added bits for NET_BRIDGE and the NET_IPV4_ARP stuff and - * NET_IPV4_IP_FORWARD. - * - * - */ - -#include -#include -#include -#include - -#include - -#ifdef CONFIG_INET -#include -#endif - -#ifdef CONFIG_NET -#include -#endif - -static struct ctl_table_set * -net_ctl_header_lookup(struct ctl_table_root *root) -{ - return ¤t->nsproxy->net_ns->sysctls; -} - -static int is_seen(struct ctl_table_set *set) -{ - return ¤t->nsproxy->net_ns->sysctls == set; -} - -/* Return standard mode bits for table entry. */ -static int net_ctl_permissions(struct ctl_table_header *head, - struct ctl_table *table) -{ - struct net *net = container_of(head->set, struct net, sysctls); - - /* Allow network administrator to have same access as root. */ - if (ns_capable_noaudit(net->user_ns, CAP_NET_ADMIN)) { - int mode = (table->mode >> 6) & 7; - return (mode << 6) | (mode << 3) | mode; - } - - return table->mode; -} - -static void net_ctl_set_ownership(struct ctl_table_header *head, - struct ctl_table *table, - kuid_t *uid, kgid_t *gid) -{ - struct net *net = container_of(head->set, struct net, sysctls); - kuid_t ns_root_uid; - kgid_t ns_root_gid; - - ns_root_uid = make_kuid(net->user_ns, 0); - if (uid_valid(ns_root_uid)) - *uid = ns_root_uid; - - ns_root_gid = make_kgid(net->user_ns, 0); - if (gid_valid(ns_root_gid)) - *gid = ns_root_gid; -} - -static struct ctl_table_root net_sysctl_root = { - .lookup = net_ctl_header_lookup, - .permissions = net_ctl_permissions, - .set_ownership = net_ctl_set_ownership, -}; - -static int __net_init sysctl_net_init(struct net *net) -{ - setup_sysctl_set(&net->sysctls, &net_sysctl_root, is_seen); - return 0; -} - -static void __net_exit sysctl_net_exit(struct net *net) -{ - retire_sysctl_set(&net->sysctls); -} - -static struct pernet_operations sysctl_pernet_ops = { - .init = sysctl_net_init, - .exit = sysctl_net_exit, -}; - -static struct ctl_table_header *net_header; -__init int net_sysctl_init(void) -{ - static struct ctl_table empty[1]; - int ret = -ENOMEM; - /* Avoid limitations in the sysctl implementation by - * registering "/proc/sys/net" as an empty directory not in a - * network namespace. - */ - net_header = register_sysctl("net", empty); - if (!net_header) - goto out; - ret = register_pernet_subsys(&sysctl_pernet_ops); - if (ret) - goto out1; - register_sysctl_root(&net_sysctl_root); -out: - return ret; -out1: - unregister_sysctl_table(net_header); - net_header = NULL; - goto out; -} - -struct ctl_table_header *register_net_sysctl(struct net *net, - const char *path, struct ctl_table *table) -{ - return __register_sysctl_table(&net->sysctls, path, table); -} -EXPORT_SYMBOL_GPL(register_net_sysctl); - -void unregister_net_sysctl_table(struct ctl_table_header *header) -{ - unregister_sysctl_table(header); -} -EXPORT_SYMBOL_GPL(unregister_net_sysctl_table); diff --git a/src/linux/net/tipc/Kconfig b/src/linux/net/tipc/Kconfig deleted file mode 100644 index c25a3a1..0000000 --- a/src/linux/net/tipc/Kconfig +++ /dev/null @@ -1,36 +0,0 @@ -# -# TIPC configuration -# - -menuconfig TIPC - tristate "The TIPC Protocol" - depends on INET - ---help--- - The Transparent Inter Process Communication (TIPC) protocol is - specially designed for intra cluster communication. This protocol - originates from Ericsson where it has been used in carrier grade - cluster applications for many years. - - For more information about TIPC, see http://tipc.sourceforge.net. - - This protocol support is also available as a module ( = code which - can be inserted in and removed from the running kernel whenever you - want). The module will be called tipc. If you want to compile it - as a module, say M here and read . - - If in doubt, say N. - -config TIPC_MEDIA_IB - bool "InfiniBand media type support" - depends on TIPC && INFINIBAND_IPOIB - help - Saying Y here will enable support for running TIPC on - IP-over-InfiniBand devices. -config TIPC_MEDIA_UDP - bool "IP/UDP media type support" - depends on TIPC - select NET_UDP_TUNNEL - help - Saying Y here will enable support for running TIPC over IP/UDP - bool - default y diff --git a/src/linux/net/unix/Kconfig b/src/linux/net/unix/Kconfig deleted file mode 100644 index 8b31ab8..0000000 --- a/src/linux/net/unix/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -# -# Unix Domain Sockets -# - -config UNIX - tristate "Unix domain sockets" - ---help--- - If you say Y here, you will include support for Unix domain sockets; - sockets are the standard Unix mechanism for establishing and - accessing network connections. Many commonly used programs such as - the X Window system and syslog use these sockets even if your - machine is not connected to any network. Unless you are working on - an embedded system or something similar, you therefore definitely - want to say Y here. - - To compile this driver as a module, choose M here: the module will be - called unix. Note that several important services won't work - correctly if you say M here and then neglect to load the module. - - Say Y unless you know what you are doing. - -config UNIX_DIAG - tristate "UNIX: socket monitoring interface" - depends on UNIX - default n - ---help--- - Support for UNIX socket monitoring interface used by the ss tool. - If unsure, say Y. diff --git a/src/linux/net/vmw_vsock/Kconfig b/src/linux/net/vmw_vsock/Kconfig deleted file mode 100644 index 8831e7c..0000000 --- a/src/linux/net/vmw_vsock/Kconfig +++ /dev/null @@ -1,48 +0,0 @@ -# -# Vsock protocol -# - -config VSOCKETS - tristate "Virtual Socket protocol" - help - Virtual Socket Protocol is a socket protocol similar to TCP/IP - allowing communication between Virtual Machines and hypervisor - or host. - - You should also select one or more hypervisor-specific transports - below. - - To compile this driver as a module, choose M here: the module - will be called vsock. If unsure, say N. - -config VMWARE_VMCI_VSOCKETS - tristate "VMware VMCI transport for Virtual Sockets" - depends on VSOCKETS && VMWARE_VMCI - help - This module implements a VMCI transport for Virtual Sockets. - - Enable this transport if your Virtual Machine runs on a VMware - hypervisor. - - To compile this driver as a module, choose M here: the module - will be called vmw_vsock_vmci_transport. If unsure, say N. - -config VIRTIO_VSOCKETS - tristate "virtio transport for Virtual Sockets" - depends on VSOCKETS && VIRTIO - select VIRTIO_VSOCKETS_COMMON - help - This module implements a virtio transport for Virtual Sockets. - - Enable this transport if your Virtual Machine host supports Virtual - Sockets over virtio. - - To compile this driver as a module, choose M here: the module will be - called vmw_vsock_virtio_transport. If unsure, say N. - -config VIRTIO_VSOCKETS_COMMON - tristate - help - This option is selected by any driver which needs to access - the virtio_vsock. The module will be called - vmw_vsock_virtio_transport_common. diff --git a/src/linux/net/wimax/Kconfig b/src/linux/net/wimax/Kconfig deleted file mode 100644 index e4d97ab..0000000 --- a/src/linux/net/wimax/Kconfig +++ /dev/null @@ -1,39 +0,0 @@ -# -# WiMAX LAN device configuration -# - -menuconfig WIMAX - tristate "WiMAX Wireless Broadband support" - depends on RFKILL || !RFKILL - help - - Select to configure support for devices that provide - wireless broadband connectivity using the WiMAX protocol - (IEEE 802.16). - - Please note that most of these devices require signing up - for a service plan with a provider. - - The different WiMAX drivers can be enabled in the menu entry - - Device Drivers > Network device support > WiMAX Wireless - Broadband devices - - If unsure, it is safe to select M (module). - -config WIMAX_DEBUG_LEVEL - int "WiMAX debug level" - depends on WIMAX - default 8 - help - - Select the maximum debug verbosity level to be compiled into - the WiMAX stack code. - - By default, debug messages are disabled at runtime and can - be selectively enabled for different parts of the code using - the sysfs debug-levels file. - - If set at zero, this will compile out all the debug code. - - It is recommended that it is left at 8. diff --git a/src/linux/net/wireless/.gitignore b/src/linux/net/wireless/.gitignore deleted file mode 100644 index c33451b..0000000 --- a/src/linux/net/wireless/.gitignore +++ /dev/null @@ -1 +0,0 @@ -regdb.c diff --git a/src/linux/net/wireless/Kconfig b/src/linux/net/wireless/Kconfig deleted file mode 100644 index 6c60612..0000000 --- a/src/linux/net/wireless/Kconfig +++ /dev/null @@ -1,216 +0,0 @@ -config WIRELESS_EXT - bool - -config WEXT_CORE - def_bool y - depends on CFG80211_WEXT || WIRELESS_EXT - -config WEXT_PROC - def_bool y - depends on PROC_FS - depends on WEXT_CORE - -config WEXT_SPY - bool - -config WEXT_PRIV - bool - -config CFG80211 - tristate "cfg80211 - wireless configuration API" - depends on RFKILL || !RFKILL - ---help--- - cfg80211 is the Linux wireless LAN (802.11) configuration API. - Enable this if you have a wireless device. - - For more information refer to documentation on the wireless wiki: - - http://wireless.kernel.org/en/developers/Documentation/cfg80211 - - When built as a module it will be called cfg80211. - -config NL80211_TESTMODE - bool "nl80211 testmode command" - depends on CFG80211 - help - The nl80211 testmode command helps implementing things like - factory calibration or validation tools for wireless chips. - - Select this option ONLY for kernels that are specifically - built for such purposes. - - Debugging tools that are supposed to end up in the hands of - users should better be implemented with debugfs. - - Say N. - -config CFG80211_DEVELOPER_WARNINGS - bool "enable developer warnings" - depends on CFG80211 - default n - help - This option enables some additional warnings that help - cfg80211 developers and driver developers, but beware that - they can also trigger due to races with userspace. - - For example, when a driver reports that it was disconnected - from the AP, but the user disconnects manually at the same - time, the warning might trigger spuriously due to races. - - Say Y only if you are developing cfg80211 or a driver based - on it (or mac80211). - - -config CFG80211_CERTIFICATION_ONUS - bool "cfg80211 certification onus" - depends on CFG80211 && EXPERT - default n - ---help--- - You should disable this option unless you are both capable - and willing to ensure your system will remain regulatory - compliant with the features available under this option. - Some options may still be under heavy development and - for whatever reason regulatory compliance has not or - cannot yet be verified. Regulatory verification may at - times only be possible until you have the final system - in place. - - This option should only be enabled by system integrators - or distributions that have done work necessary to ensure - regulatory certification on the system with the enabled - features. Alternatively you can enable this option if - you are a wireless researcher and are working in a controlled - and approved environment by your local regulatory agency. - -config CFG80211_REG_CELLULAR_HINTS - bool "cfg80211 regulatory support for cellular base station hints" - depends on CFG80211_CERTIFICATION_ONUS - ---help--- - This option enables support for parsing regulatory hints - from cellular base stations. If enabled and at least one driver - claims support for parsing cellular base station hints the - regulatory core will allow and parse these regulatory hints. - The regulatory core will only apply these regulatory hints on - drivers that support this feature. You should only enable this - feature if you have tested and validated this feature on your - systems. - -config CFG80211_REG_RELAX_NO_IR - bool "cfg80211 support for NO_IR relaxation" - depends on CFG80211_CERTIFICATION_ONUS - ---help--- - This option enables support for relaxation of the NO_IR flag for - situations that certain regulatory bodies have provided clarifications - on how relaxation can occur. This feature has an inherent dependency on - userspace features which must have been properly tested and as such is - not enabled by default. - - A relaxation feature example is allowing the operation of a P2P group - owner (GO) on channels marked with NO_IR if there is an additional BSS - interface which associated to an AP which userspace assumes or confirms - to be an authorized master, i.e., with radar detection support and DFS - capabilities. However, note that in order to not create daisy chain - scenarios, this relaxation is not allowed in cases where the BSS client - is associated to P2P GO and in addition the P2P GO instantiated on - a channel due to this relaxation should not allow connection from - non P2P clients. - - The regulatory core will apply these relaxations only for drivers that - support this feature by declaring the appropriate channel flags and - capabilities in their registration flow. - -config CFG80211_DEFAULT_PS - bool "enable powersave by default" - depends on CFG80211 - default y - help - This option enables powersave mode by default. - - If this causes your applications to misbehave you should fix your - applications instead -- they need to register their network - latency requirement, see Documentation/power/pm_qos_interface.txt. - -config CFG80211_DEBUGFS - bool "cfg80211 DebugFS entries" - depends on CFG80211 - depends on DEBUG_FS - ---help--- - You can enable this if you want debugfs entries for cfg80211. - - If unsure, say N. - -config CFG80211_INTERNAL_REGDB - bool "use statically compiled regulatory rules database" if EXPERT - default n - depends on CFG80211 - ---help--- - This option generates an internal data structure representing - the wireless regulatory rules described in net/wireless/db.txt - and includes code to query that database. This is an alternative - to using CRDA for defining regulatory rules for the kernel. - - Using this option requires some parsing of the db.txt at build time, - the parser will be upkept with the latest wireless-regdb updates but - older wireless-regdb formats will be ignored. The parser may later - be replaced to avoid issues with conflicts on versions of - wireless-regdb. - - For details see: - - http://wireless.kernel.org/en/developers/Regulatory - - Most distributions have a CRDA package. So if unsure, say N. - -config CFG80211_CRDA_SUPPORT - bool "support CRDA" if CFG80211_INTERNAL_REGDB - default y - depends on CFG80211 - help - You should enable this option unless you know for sure you have no - need for it, for example when using internal regdb (above.) - - If unsure, say Y. - -config CFG80211_WEXT - bool "cfg80211 wireless extensions compatibility" if !CFG80211_WEXT_EXPORT - depends on CFG80211 - select WEXT_CORE - default y if CFG80211_WEXT_EXPORT - help - Enable this option if you need old userspace for wireless - extensions with cfg80211-based drivers. - -config CFG80211_WEXT_EXPORT - bool - depends on CFG80211 - help - Drivers should select this option if they require cfg80211's - wext compatibility symbols to be exported. - -config LIB80211 - tristate - default n - help - This options enables a library of common routines used - by IEEE802.11 wireless LAN drivers. - - Drivers should select this themselves if needed. - -config LIB80211_CRYPT_WEP - tristate - -config LIB80211_CRYPT_CCMP - tristate - -config LIB80211_CRYPT_TKIP - tristate - -config LIB80211_DEBUG - bool "lib80211 debugging messages" - depends on LIB80211 - default n - ---help--- - You can enable this if you want verbose debugging messages - from lib80211. - - If unsure, say N. diff --git a/src/linux/net/x25/Kconfig b/src/linux/net/x25/Kconfig deleted file mode 100644 index e2fa133..0000000 --- a/src/linux/net/x25/Kconfig +++ /dev/null @@ -1,35 +0,0 @@ -# -# CCITT X.25 Packet Layer -# - -config X25 - tristate "CCITT X.25 Packet Layer" - ---help--- - X.25 is a set of standardized network protocols, similar in scope to - frame relay; the one physical line from your box to the X.25 network - entry point can carry several logical point-to-point connections - (called "virtual circuits") to other computers connected to the X.25 - network. Governments, banks, and other organizations tend to use it - to connect to each other or to form Wide Area Networks (WANs). Many - countries have public X.25 networks. X.25 consists of two - protocols: the higher level Packet Layer Protocol (PLP) (say Y here - if you want that) and the lower level data link layer protocol LAPB - (say Y to "LAPB Data Link Driver" below if you want that). - - You can read more about X.25 at and - . - Information about X.25 for Linux is contained in the files - and - . - - One connects to an X.25 network either with a dedicated network card - using the X.21 protocol (not yet supported by Linux) or one can do - X.25 over a standard telephone line using an ordinary modem (say Y - to "X.25 async driver" below) or over Ethernet using an ordinary - Ethernet card and the LAPB over Ethernet (say Y to "LAPB Data Link - Driver" and "LAPB over Ethernet driver" below). - - To compile this driver as a module, choose M here: the module - will be called x25. If unsure, say N. - - diff --git a/src/linux/net/xfrm/Kconfig b/src/linux/net/xfrm/Kconfig deleted file mode 100644 index bda1a13..0000000 --- a/src/linux/net/xfrm/Kconfig +++ /dev/null @@ -1,85 +0,0 @@ -# -# XFRM configuration -# -config XFRM - bool - depends on NET - -config XFRM_ALGO - tristate - select XFRM - select CRYPTO - -config XFRM_USER - tristate "Transformation user configuration interface" - depends on INET - select XFRM_ALGO - ---help--- - Support for Transformation(XFRM) user configuration interface - like IPsec used by native Linux tools. - - If unsure, say Y. - -config XFRM_SUB_POLICY - bool "Transformation sub policy support" - depends on XFRM - ---help--- - Support sub policy for developers. By using sub policy with main - one, two policies can be applied to the same packet at once. - Policy which lives shorter time in kernel should be a sub. - - If unsure, say N. - -config XFRM_MIGRATE - bool "Transformation migrate database" - depends on XFRM - ---help--- - A feature to update locator(s) of a given IPsec security - association dynamically. This feature is required, for - instance, in a Mobile IPv6 environment with IPsec configuration - where mobile nodes change their attachment point to the Internet. - - If unsure, say N. - -config XFRM_STATISTICS - bool "Transformation statistics" - depends on INET && XFRM && PROC_FS - ---help--- - This statistics is not a SNMP/MIB specification but shows - statistics about transformation error (or almost error) factor - at packet processing for developer. - - If unsure, say N. - -config XFRM_IPCOMP - tristate - select XFRM_ALGO - select CRYPTO - select CRYPTO_DEFLATE - -config NET_KEY - tristate "PF_KEY sockets" - select XFRM_ALGO - ---help--- - PF_KEYv2 socket family, compatible to KAME ones. - They are required if you are going to use IPsec tools ported - from KAME. - - Say Y unless you know what you are doing. - -config NET_KEY_MIGRATE - bool "PF_KEY MIGRATE" - depends on NET_KEY - select XFRM_MIGRATE - ---help--- - Add a PF_KEY MIGRATE message to PF_KEYv2 socket family. - The PF_KEY MIGRATE message is used to dynamically update - locator(s) of a given IPsec security association. - This feature is required, for instance, in a Mobile IPv6 - environment with IPsec configuration where mobile nodes - change their attachment point to the Internet. Detail - information can be found in the internet-draft - . - - If unsure, say N. - diff --git a/src/linux/net/xfrm/Makefile b/src/linux/net/xfrm/Makefile deleted file mode 100644 index c0e9619..0000000 --- a/src/linux/net/xfrm/Makefile +++ /dev/null @@ -1,11 +0,0 @@ -# -# Makefile for the XFRM subsystem. -# - -obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \ - xfrm_input.o xfrm_output.o \ - xfrm_sysctl.o xfrm_replay.o -obj-$(CONFIG_XFRM_STATISTICS) += xfrm_proc.o -obj-$(CONFIG_XFRM_ALGO) += xfrm_algo.o -obj-$(CONFIG_XFRM_USER) += xfrm_user.o -obj-$(CONFIG_XFRM_IPCOMP) += xfrm_ipcomp.o diff --git a/src/linux/net/xfrm/xfrm_hash.c b/src/linux/net/xfrm/xfrm_hash.c deleted file mode 100644 index 1e98bc0..0000000 --- a/src/linux/net/xfrm/xfrm_hash.c +++ /dev/null @@ -1,39 +0,0 @@ -/* xfrm_hash.c: Common hash table code. - * - * Copyright (C) 2006 David S. Miller (davem@davemloft.net) - */ - -#include -#include -#include -#include -#include -#include - -#include "xfrm_hash.h" - -struct hlist_head *xfrm_hash_alloc(unsigned int sz) -{ - struct hlist_head *n; - - if (sz <= PAGE_SIZE) - n = kzalloc(sz, GFP_KERNEL); - else if (hashdist) - n = vzalloc(sz); - else - n = (struct hlist_head *) - __get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO, - get_order(sz)); - - return n; -} - -void xfrm_hash_free(struct hlist_head *n, unsigned int sz) -{ - if (sz <= PAGE_SIZE) - kfree(n); - else if (hashdist) - vfree(n); - else - free_pages((unsigned long)n, get_order(sz)); -} diff --git a/src/linux/net/xfrm/xfrm_hash.h b/src/linux/net/xfrm/xfrm_hash.h deleted file mode 100644 index 666c5ff..0000000 --- a/src/linux/net/xfrm/xfrm_hash.h +++ /dev/null @@ -1,192 +0,0 @@ -#ifndef _XFRM_HASH_H -#define _XFRM_HASH_H - -#include -#include -#include - -static inline unsigned int __xfrm4_addr_hash(const xfrm_address_t *addr) -{ - return ntohl(addr->a4); -} - -static inline unsigned int __xfrm6_addr_hash(const xfrm_address_t *addr) -{ - return ntohl(addr->a6[2] ^ addr->a6[3]); -} - -static inline unsigned int __xfrm4_daddr_saddr_hash(const xfrm_address_t *daddr, - const xfrm_address_t *saddr) -{ - u32 sum = (__force u32)daddr->a4 + (__force u32)saddr->a4; - return ntohl((__force __be32)sum); -} - -static inline unsigned int __xfrm6_daddr_saddr_hash(const xfrm_address_t *daddr, - const xfrm_address_t *saddr) -{ - return ntohl(daddr->a6[2] ^ daddr->a6[3] ^ - saddr->a6[2] ^ saddr->a6[3]); -} - -static inline u32 __bits2mask32(__u8 bits) -{ - u32 mask32 = 0xffffffff; - - if (bits == 0) - mask32 = 0; - else if (bits < 32) - mask32 <<= (32 - bits); - - return mask32; -} - -static inline unsigned int __xfrm4_dpref_spref_hash(const xfrm_address_t *daddr, - const xfrm_address_t *saddr, - __u8 dbits, - __u8 sbits) -{ - return jhash_2words(ntohl(daddr->a4) & __bits2mask32(dbits), - ntohl(saddr->a4) & __bits2mask32(sbits), - 0); -} - -static inline unsigned int __xfrm6_pref_hash(const xfrm_address_t *addr, - __u8 prefixlen) -{ - int pdw; - int pbi; - u32 initval = 0; - - pdw = prefixlen >> 5; /* num of whole u32 in prefix */ - pbi = prefixlen & 0x1f; /* num of bits in incomplete u32 in prefix */ - - if (pbi) { - __be32 mask; - - mask = htonl((0xffffffff) << (32 - pbi)); - - initval = (__force u32)(addr->a6[pdw] & mask); - } - - return jhash2((__force u32 *)addr->a6, pdw, initval); -} - -static inline unsigned int __xfrm6_dpref_spref_hash(const xfrm_address_t *daddr, - const xfrm_address_t *saddr, - __u8 dbits, - __u8 sbits) -{ - return __xfrm6_pref_hash(daddr, dbits) ^ - __xfrm6_pref_hash(saddr, sbits); -} - -static inline unsigned int __xfrm_dst_hash(const xfrm_address_t *daddr, - const xfrm_address_t *saddr, - u32 reqid, unsigned short family, - unsigned int hmask) -{ - unsigned int h = family ^ reqid; - switch (family) { - case AF_INET: - h ^= __xfrm4_daddr_saddr_hash(daddr, saddr); - break; - case AF_INET6: - h ^= __xfrm6_daddr_saddr_hash(daddr, saddr); - break; - } - return (h ^ (h >> 16)) & hmask; -} - -static inline unsigned int __xfrm_src_hash(const xfrm_address_t *daddr, - const xfrm_address_t *saddr, - unsigned short family, - unsigned int hmask) -{ - unsigned int h = family; - switch (family) { - case AF_INET: - h ^= __xfrm4_daddr_saddr_hash(daddr, saddr); - break; - case AF_INET6: - h ^= __xfrm6_daddr_saddr_hash(daddr, saddr); - break; - } - return (h ^ (h >> 16)) & hmask; -} - -static inline unsigned int -__xfrm_spi_hash(const xfrm_address_t *daddr, __be32 spi, u8 proto, - unsigned short family, unsigned int hmask) -{ - unsigned int h = (__force u32)spi ^ proto; - switch (family) { - case AF_INET: - h ^= __xfrm4_addr_hash(daddr); - break; - case AF_INET6: - h ^= __xfrm6_addr_hash(daddr); - break; - } - return (h ^ (h >> 10) ^ (h >> 20)) & hmask; -} - -static inline unsigned int __idx_hash(u32 index, unsigned int hmask) -{ - return (index ^ (index >> 8)) & hmask; -} - -static inline unsigned int __sel_hash(const struct xfrm_selector *sel, - unsigned short family, unsigned int hmask, - u8 dbits, u8 sbits) -{ - const xfrm_address_t *daddr = &sel->daddr; - const xfrm_address_t *saddr = &sel->saddr; - unsigned int h = 0; - - switch (family) { - case AF_INET: - if (sel->prefixlen_d < dbits || - sel->prefixlen_s < sbits) - return hmask + 1; - - h = __xfrm4_dpref_spref_hash(daddr, saddr, dbits, sbits); - break; - - case AF_INET6: - if (sel->prefixlen_d < dbits || - sel->prefixlen_s < sbits) - return hmask + 1; - - h = __xfrm6_dpref_spref_hash(daddr, saddr, dbits, sbits); - break; - } - h ^= (h >> 16); - return h & hmask; -} - -static inline unsigned int __addr_hash(const xfrm_address_t *daddr, - const xfrm_address_t *saddr, - unsigned short family, - unsigned int hmask, - u8 dbits, u8 sbits) -{ - unsigned int h = 0; - - switch (family) { - case AF_INET: - h = __xfrm4_dpref_spref_hash(daddr, saddr, dbits, sbits); - break; - - case AF_INET6: - h = __xfrm6_dpref_spref_hash(daddr, saddr, dbits, sbits); - break; - } - h ^= (h >> 16); - return h & hmask; -} - -struct hlist_head *xfrm_hash_alloc(unsigned int sz); -void xfrm_hash_free(struct hlist_head *n, unsigned int sz); - -#endif /* _XFRM_HASH_H */ diff --git a/src/linux/net/xfrm/xfrm_input.c b/src/linux/net/xfrm/xfrm_input.c deleted file mode 100644 index 6e3f025..0000000 --- a/src/linux/net/xfrm/xfrm_input.c +++ /dev/null @@ -1,401 +0,0 @@ -/* - * xfrm_input.c - * - * Changes: - * YOSHIFUJI Hideaki @USAGI - * Split up af-specific portion - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -static struct kmem_cache *secpath_cachep __read_mostly; - -static DEFINE_SPINLOCK(xfrm_input_afinfo_lock); -static struct xfrm_input_afinfo __rcu *xfrm_input_afinfo[NPROTO]; - -int xfrm_input_register_afinfo(struct xfrm_input_afinfo *afinfo) -{ - int err = 0; - - if (unlikely(afinfo == NULL)) - return -EINVAL; - if (unlikely(afinfo->family >= NPROTO)) - return -EAFNOSUPPORT; - spin_lock_bh(&xfrm_input_afinfo_lock); - if (unlikely(xfrm_input_afinfo[afinfo->family] != NULL)) - err = -EEXIST; - else - rcu_assign_pointer(xfrm_input_afinfo[afinfo->family], afinfo); - spin_unlock_bh(&xfrm_input_afinfo_lock); - return err; -} -EXPORT_SYMBOL(xfrm_input_register_afinfo); - -int xfrm_input_unregister_afinfo(struct xfrm_input_afinfo *afinfo) -{ - int err = 0; - - if (unlikely(afinfo == NULL)) - return -EINVAL; - if (unlikely(afinfo->family >= NPROTO)) - return -EAFNOSUPPORT; - spin_lock_bh(&xfrm_input_afinfo_lock); - if (likely(xfrm_input_afinfo[afinfo->family] != NULL)) { - if (unlikely(xfrm_input_afinfo[afinfo->family] != afinfo)) - err = -EINVAL; - else - RCU_INIT_POINTER(xfrm_input_afinfo[afinfo->family], NULL); - } - spin_unlock_bh(&xfrm_input_afinfo_lock); - synchronize_rcu(); - return err; -} -EXPORT_SYMBOL(xfrm_input_unregister_afinfo); - -static struct xfrm_input_afinfo *xfrm_input_get_afinfo(unsigned int family) -{ - struct xfrm_input_afinfo *afinfo; - - if (unlikely(family >= NPROTO)) - return NULL; - rcu_read_lock(); - afinfo = rcu_dereference(xfrm_input_afinfo[family]); - if (unlikely(!afinfo)) - rcu_read_unlock(); - return afinfo; -} - -static void xfrm_input_put_afinfo(struct xfrm_input_afinfo *afinfo) -{ - rcu_read_unlock(); -} - -static int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family, u8 protocol, - int err) -{ - int ret; - struct xfrm_input_afinfo *afinfo = xfrm_input_get_afinfo(family); - - if (!afinfo) - return -EAFNOSUPPORT; - - ret = afinfo->callback(skb, protocol, err); - xfrm_input_put_afinfo(afinfo); - - return ret; -} - -void __secpath_destroy(struct sec_path *sp) -{ - int i; - for (i = 0; i < sp->len; i++) - xfrm_state_put(sp->xvec[i]); - kmem_cache_free(secpath_cachep, sp); -} -EXPORT_SYMBOL(__secpath_destroy); - -struct sec_path *secpath_dup(struct sec_path *src) -{ - struct sec_path *sp; - - sp = kmem_cache_alloc(secpath_cachep, GFP_ATOMIC); - if (!sp) - return NULL; - - sp->len = 0; - if (src) { - int i; - - memcpy(sp, src, sizeof(*sp)); - for (i = 0; i < sp->len; i++) - xfrm_state_hold(sp->xvec[i]); - } - atomic_set(&sp->refcnt, 1); - return sp; -} -EXPORT_SYMBOL(secpath_dup); - -/* Fetch spi and seq from ipsec header */ - -int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq) -{ - int offset, offset_seq; - int hlen; - - switch (nexthdr) { - case IPPROTO_AH: - hlen = sizeof(struct ip_auth_hdr); - offset = offsetof(struct ip_auth_hdr, spi); - offset_seq = offsetof(struct ip_auth_hdr, seq_no); - break; - case IPPROTO_ESP: - hlen = sizeof(struct ip_esp_hdr); - offset = offsetof(struct ip_esp_hdr, spi); - offset_seq = offsetof(struct ip_esp_hdr, seq_no); - break; - case IPPROTO_COMP: - if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr))) - return -EINVAL; - *spi = htonl(ntohs(*(__be16 *)(skb_transport_header(skb) + 2))); - *seq = 0; - return 0; - default: - return 1; - } - - if (!pskb_may_pull(skb, hlen)) - return -EINVAL; - - *spi = *(__be32 *)(skb_transport_header(skb) + offset); - *seq = *(__be32 *)(skb_transport_header(skb) + offset_seq); - return 0; -} - -int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb) -{ - struct xfrm_mode *inner_mode = x->inner_mode; - int err; - - err = x->outer_mode->afinfo->extract_input(x, skb); - if (err) - return err; - - if (x->sel.family == AF_UNSPEC) { - inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); - if (inner_mode == NULL) - return -EAFNOSUPPORT; - } - - skb->protocol = inner_mode->afinfo->eth_proto; - return inner_mode->input2(x, skb); -} -EXPORT_SYMBOL(xfrm_prepare_input); - -int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) -{ - struct net *net = dev_net(skb->dev); - int err; - __be32 seq; - __be32 seq_hi; - struct xfrm_state *x = NULL; - xfrm_address_t *daddr; - struct xfrm_mode *inner_mode; - u32 mark = skb->mark; - unsigned int family; - int decaps = 0; - int async = 0; - - /* A negative encap_type indicates async resumption. */ - if (encap_type < 0) { - async = 1; - x = xfrm_input_state(skb); - seq = XFRM_SKB_CB(skb)->seq.input.low; - family = x->outer_mode->afinfo->family; - goto resume; - } - - daddr = (xfrm_address_t *)(skb_network_header(skb) + - XFRM_SPI_SKB_CB(skb)->daddroff); - family = XFRM_SPI_SKB_CB(skb)->family; - - /* if tunnel is present override skb->mark value with tunnel i_key */ - switch (family) { - case AF_INET: - if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4) - mark = be32_to_cpu(XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4->parms.i_key); - break; - case AF_INET6: - if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6) - mark = be32_to_cpu(XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6->parms.i_key); - break; - } - - /* Allocate new secpath or COW existing one. */ - if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) { - struct sec_path *sp; - - sp = secpath_dup(skb->sp); - if (!sp) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR); - goto drop; - } - if (skb->sp) - secpath_put(skb->sp); - skb->sp = sp; - } - - seq = 0; - if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR); - goto drop; - } - - do { - if (skb->sp->len == XFRM_MAX_DEPTH) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR); - goto drop; - } - - x = xfrm_state_lookup(net, mark, daddr, spi, nexthdr, family); - if (x == NULL) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES); - xfrm_audit_state_notfound(skb, family, spi, seq); - goto drop; - } - - skb->sp->xvec[skb->sp->len++] = x; - - spin_lock(&x->lock); - - if (unlikely(x->km.state != XFRM_STATE_VALID)) { - if (x->km.state == XFRM_STATE_ACQ) - XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR); - else - XFRM_INC_STATS(net, - LINUX_MIB_XFRMINSTATEINVALID); - goto drop_unlock; - } - - if ((x->encap ? x->encap->encap_type : 0) != encap_type) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH); - goto drop_unlock; - } - - if (x->repl->check(x, skb, seq)) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR); - goto drop_unlock; - } - - if (xfrm_state_check_expire(x)) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEEXPIRED); - goto drop_unlock; - } - - spin_unlock(&x->lock); - - if (xfrm_tunnel_check(skb, x, family)) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR); - goto drop; - } - - seq_hi = htonl(xfrm_replay_seqhi(x, seq)); - - XFRM_SKB_CB(skb)->seq.input.low = seq; - XFRM_SKB_CB(skb)->seq.input.hi = seq_hi; - - skb_dst_force(skb); - dev_hold(skb->dev); - - nexthdr = x->type->input(x, skb); - - if (nexthdr == -EINPROGRESS) - return 0; -resume: - dev_put(skb->dev); - - spin_lock(&x->lock); - if (nexthdr <= 0) { - if (nexthdr == -EBADMSG) { - xfrm_audit_state_icvfail(x, skb, - x->type->proto); - x->stats.integrity_failed++; - } - XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR); - goto drop_unlock; - } - - /* only the first xfrm gets the encap type */ - encap_type = 0; - - if (async && x->repl->recheck(x, skb, seq)) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR); - goto drop_unlock; - } - - x->repl->advance(x, seq); - - x->curlft.bytes += skb->len; - x->curlft.packets++; - - spin_unlock(&x->lock); - - XFRM_MODE_SKB_CB(skb)->protocol = nexthdr; - - inner_mode = x->inner_mode; - - if (x->sel.family == AF_UNSPEC) { - inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); - if (inner_mode == NULL) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR); - goto drop; - } - } - - if (inner_mode->input(x, skb)) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR); - goto drop; - } - - if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { - decaps = 1; - break; - } - - /* - * We need the inner address. However, we only get here for - * transport mode so the outer address is identical. - */ - daddr = &x->id.daddr; - family = x->outer_mode->afinfo->family; - - err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); - if (err < 0) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR); - goto drop; - } - } while (!err); - - err = xfrm_rcv_cb(skb, family, x->type->proto, 0); - if (err) - goto drop; - - nf_reset(skb); - - if (decaps) { - skb_dst_drop(skb); - netif_rx(skb); - return 0; - } else { - return x->inner_mode->afinfo->transport_finish(skb, async); - } - -drop_unlock: - spin_unlock(&x->lock); -drop: - xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1); - kfree_skb(skb); - return 0; -} -EXPORT_SYMBOL(xfrm_input); - -int xfrm_input_resume(struct sk_buff *skb, int nexthdr) -{ - return xfrm_input(skb, nexthdr, 0, -1); -} -EXPORT_SYMBOL(xfrm_input_resume); - -void __init xfrm_input_init(void) -{ - secpath_cachep = kmem_cache_create("secpath_cache", - sizeof(struct sec_path), - 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, - NULL); -} diff --git a/src/linux/net/xfrm/xfrm_output.c b/src/linux/net/xfrm/xfrm_output.c deleted file mode 100644 index 637387b..0000000 --- a/src/linux/net/xfrm/xfrm_output.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * xfrm_output.c - Common IPsec encapsulation code. - * - * Copyright (c) 2007 Herbert Xu - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int xfrm_output2(struct net *net, struct sock *sk, struct sk_buff *skb); - -static int xfrm_skb_check_space(struct sk_buff *skb) -{ - struct dst_entry *dst = skb_dst(skb); - int nhead = dst->header_len + LL_RESERVED_SPACE(dst->dev) - - skb_headroom(skb); - int ntail = dst->dev->needed_tailroom - skb_tailroom(skb); - - if (nhead <= 0) { - if (ntail <= 0) - return 0; - nhead = 0; - } else if (ntail < 0) - ntail = 0; - - return pskb_expand_head(skb, nhead, ntail, GFP_ATOMIC); -} - -/* Children define the path of the packet through the - * Linux networking. Thus, destinations are stackable. - */ - -static struct dst_entry *skb_dst_pop(struct sk_buff *skb) -{ - struct dst_entry *child = dst_clone(skb_dst(skb)->child); - - skb_dst_drop(skb); - return child; -} - -static int xfrm_output_one(struct sk_buff *skb, int err) -{ - struct dst_entry *dst = skb_dst(skb); - struct xfrm_state *x = dst->xfrm; - struct net *net = xs_net(x); - - if (err <= 0) - goto resume; - - do { - err = xfrm_skb_check_space(skb); - if (err) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR); - goto error_nolock; - } - - err = x->outer_mode->output(x, skb); - if (err) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR); - goto error_nolock; - } - - spin_lock_bh(&x->lock); - - if (unlikely(x->km.state != XFRM_STATE_VALID)) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEINVALID); - err = -EINVAL; - goto error; - } - - err = xfrm_state_check_expire(x); - if (err) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEEXPIRED); - goto error; - } - - err = x->repl->overflow(x, skb); - if (err) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATESEQERROR); - goto error; - } - - x->curlft.bytes += skb->len; - x->curlft.packets++; - - spin_unlock_bh(&x->lock); - - skb_dst_force(skb); - - /* Inner headers are invalid now. */ - skb->encapsulation = 0; - - err = x->type->output(x, skb); - if (err == -EINPROGRESS) - goto out; - -resume: - if (err) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR); - goto error_nolock; - } - - dst = skb_dst_pop(skb); - if (!dst) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR); - err = -EHOSTUNREACH; - goto error_nolock; - } - skb_dst_set(skb, dst); - x = dst->xfrm; - } while (x && !(x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL)); - - return 0; - -error: - spin_unlock_bh(&x->lock); -error_nolock: - kfree_skb(skb); -out: - return err; -} - -int xfrm_output_resume(struct sk_buff *skb, int err) -{ - struct net *net = xs_net(skb_dst(skb)->xfrm); - - while (likely((err = xfrm_output_one(skb, err)) == 0)) { - nf_reset(skb); - - err = skb_dst(skb)->ops->local_out(net, skb->sk, skb); - if (unlikely(err != 1)) - goto out; - - if (!skb_dst(skb)->xfrm) - return dst_output(net, skb->sk, skb); - - err = nf_hook(skb_dst(skb)->ops->family, - NF_INET_POST_ROUTING, net, skb->sk, skb, - NULL, skb_dst(skb)->dev, xfrm_output2); - if (unlikely(err != 1)) - goto out; - } - - if (err == -EINPROGRESS) - err = 0; - -out: - return err; -} -EXPORT_SYMBOL_GPL(xfrm_output_resume); - -static int xfrm_output2(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - return xfrm_output_resume(skb, 1); -} - -static int xfrm_output_gso(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - struct sk_buff *segs; - - BUILD_BUG_ON(sizeof(*IPCB(skb)) > SKB_SGO_CB_OFFSET); - BUILD_BUG_ON(sizeof(*IP6CB(skb)) > SKB_SGO_CB_OFFSET); - segs = skb_gso_segment(skb, 0); - kfree_skb(skb); - if (IS_ERR(segs)) - return PTR_ERR(segs); - if (segs == NULL) - return -EINVAL; - - do { - struct sk_buff *nskb = segs->next; - int err; - - segs->next = NULL; - err = xfrm_output2(net, sk, segs); - - if (unlikely(err)) { - kfree_skb_list(nskb); - return err; - } - - segs = nskb; - } while (segs); - - return 0; -} - -int xfrm_output(struct sock *sk, struct sk_buff *skb) -{ - struct net *net = dev_net(skb_dst(skb)->dev); - int err; - - if (skb_is_gso(skb)) - return xfrm_output_gso(net, sk, skb); - - if (skb->ip_summed == CHECKSUM_PARTIAL) { - err = skb_checksum_help(skb); - if (err) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR); - kfree_skb(skb); - return err; - } - } - - return xfrm_output2(net, sk, skb); -} -EXPORT_SYMBOL_GPL(xfrm_output); - -int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb) -{ - struct xfrm_mode *inner_mode; - if (x->sel.family == AF_UNSPEC) - inner_mode = xfrm_ip2inner_mode(x, - xfrm_af2proto(skb_dst(skb)->ops->family)); - else - inner_mode = x->inner_mode; - - if (inner_mode == NULL) - return -EAFNOSUPPORT; - return inner_mode->afinfo->extract_output(x, skb); -} -EXPORT_SYMBOL_GPL(xfrm_inner_extract_output); - -void xfrm_local_error(struct sk_buff *skb, int mtu) -{ - unsigned int proto; - struct xfrm_state_afinfo *afinfo; - - if (skb->protocol == htons(ETH_P_IP)) - proto = AF_INET; - else if (skb->protocol == htons(ETH_P_IPV6)) - proto = AF_INET6; - else - return; - - afinfo = xfrm_state_get_afinfo(proto); - if (!afinfo) - return; - - afinfo->local_error(skb, mtu); - xfrm_state_put_afinfo(afinfo); -} -EXPORT_SYMBOL_GPL(xfrm_local_error); diff --git a/src/linux/net/xfrm/xfrm_policy.c b/src/linux/net/xfrm/xfrm_policy.c deleted file mode 100644 index 5bf7e1b..0000000 --- a/src/linux/net/xfrm/xfrm_policy.c +++ /dev/null @@ -1,3413 +0,0 @@ -/* - * xfrm_policy.c - * - * Changes: - * Mitsuru KANDA @USAGI - * Kazunori MIYAZAWA @USAGI - * Kunihiro Ishiguro - * IPv6 support - * Kazunori MIYAZAWA @USAGI - * YOSHIFUJI Hideaki - * Split up af-specific portion - * Derek Atkins Add the post_input processor - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef CONFIG_XFRM_STATISTICS -#include -#endif - -#include "xfrm_hash.h" - -#define XFRM_QUEUE_TMO_MIN ((unsigned)(HZ/10)) -#define XFRM_QUEUE_TMO_MAX ((unsigned)(60*HZ)) -#define XFRM_MAX_QUEUE_LEN 100 - -struct xfrm_flo { - struct dst_entry *dst_orig; - u8 flags; -}; - -static DEFINE_SPINLOCK(xfrm_policy_afinfo_lock); -static struct xfrm_policy_afinfo __rcu *xfrm_policy_afinfo[NPROTO] - __read_mostly; - -static struct kmem_cache *xfrm_dst_cache __read_mostly; -static __read_mostly seqcount_t xfrm_policy_hash_generation; - -static void xfrm_init_pmtu(struct dst_entry *dst); -static int stale_bundle(struct dst_entry *dst); -static int xfrm_bundle_ok(struct xfrm_dst *xdst); -static void xfrm_policy_queue_process(unsigned long arg); - -static void __xfrm_policy_link(struct xfrm_policy *pol, int dir); -static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, - int dir); - -static inline bool xfrm_pol_hold_rcu(struct xfrm_policy *policy) -{ - return atomic_inc_not_zero(&policy->refcnt); -} - -static inline bool -__xfrm4_selector_match(const struct xfrm_selector *sel, const struct flowi *fl) -{ - const struct flowi4 *fl4 = &fl->u.ip4; - - return addr4_match(fl4->daddr, sel->daddr.a4, sel->prefixlen_d) && - addr4_match(fl4->saddr, sel->saddr.a4, sel->prefixlen_s) && - !((xfrm_flowi_dport(fl, &fl4->uli) ^ sel->dport) & sel->dport_mask) && - !((xfrm_flowi_sport(fl, &fl4->uli) ^ sel->sport) & sel->sport_mask) && - (fl4->flowi4_proto == sel->proto || !sel->proto) && - (fl4->flowi4_oif == sel->ifindex || !sel->ifindex); -} - -static inline bool -__xfrm6_selector_match(const struct xfrm_selector *sel, const struct flowi *fl) -{ - const struct flowi6 *fl6 = &fl->u.ip6; - - return addr_match(&fl6->daddr, &sel->daddr, sel->prefixlen_d) && - addr_match(&fl6->saddr, &sel->saddr, sel->prefixlen_s) && - !((xfrm_flowi_dport(fl, &fl6->uli) ^ sel->dport) & sel->dport_mask) && - !((xfrm_flowi_sport(fl, &fl6->uli) ^ sel->sport) & sel->sport_mask) && - (fl6->flowi6_proto == sel->proto || !sel->proto) && - (fl6->flowi6_oif == sel->ifindex || !sel->ifindex); -} - -bool xfrm_selector_match(const struct xfrm_selector *sel, const struct flowi *fl, - unsigned short family) -{ - switch (family) { - case AF_INET: - return __xfrm4_selector_match(sel, fl); - case AF_INET6: - return __xfrm6_selector_match(sel, fl); - } - return false; -} - -static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family) -{ - struct xfrm_policy_afinfo *afinfo; - - if (unlikely(family >= NPROTO)) - return NULL; - rcu_read_lock(); - afinfo = rcu_dereference(xfrm_policy_afinfo[family]); - if (unlikely(!afinfo)) - rcu_read_unlock(); - return afinfo; -} - -static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo) -{ - rcu_read_unlock(); -} - -static inline struct dst_entry *__xfrm_dst_lookup(struct net *net, - int tos, int oif, - const xfrm_address_t *saddr, - const xfrm_address_t *daddr, - int family) -{ - struct xfrm_policy_afinfo *afinfo; - struct dst_entry *dst; - - afinfo = xfrm_policy_get_afinfo(family); - if (unlikely(afinfo == NULL)) - return ERR_PTR(-EAFNOSUPPORT); - - dst = afinfo->dst_lookup(net, tos, oif, saddr, daddr); - - xfrm_policy_put_afinfo(afinfo); - - return dst; -} - -static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, - int tos, int oif, - xfrm_address_t *prev_saddr, - xfrm_address_t *prev_daddr, - int family) -{ - struct net *net = xs_net(x); - xfrm_address_t *saddr = &x->props.saddr; - xfrm_address_t *daddr = &x->id.daddr; - struct dst_entry *dst; - - if (x->type->flags & XFRM_TYPE_LOCAL_COADDR) { - saddr = x->coaddr; - daddr = prev_daddr; - } - if (x->type->flags & XFRM_TYPE_REMOTE_COADDR) { - saddr = prev_saddr; - daddr = x->coaddr; - } - - dst = __xfrm_dst_lookup(net, tos, oif, saddr, daddr, family); - - if (!IS_ERR(dst)) { - if (prev_saddr != saddr) - memcpy(prev_saddr, saddr, sizeof(*prev_saddr)); - if (prev_daddr != daddr) - memcpy(prev_daddr, daddr, sizeof(*prev_daddr)); - } - - return dst; -} - -static inline unsigned long make_jiffies(long secs) -{ - if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) - return MAX_SCHEDULE_TIMEOUT-1; - else - return secs*HZ; -} - -static void xfrm_policy_timer(unsigned long data) -{ - struct xfrm_policy *xp = (struct xfrm_policy *)data; - unsigned long now = get_seconds(); - long next = LONG_MAX; - int warn = 0; - int dir; - - read_lock(&xp->lock); - - if (unlikely(xp->walk.dead)) - goto out; - - dir = xfrm_policy_id2dir(xp->index); - - if (xp->lft.hard_add_expires_seconds) { - long tmo = xp->lft.hard_add_expires_seconds + - xp->curlft.add_time - now; - if (tmo <= 0) - goto expired; - if (tmo < next) - next = tmo; - } - if (xp->lft.hard_use_expires_seconds) { - long tmo = xp->lft.hard_use_expires_seconds + - (xp->curlft.use_time ? : xp->curlft.add_time) - now; - if (tmo <= 0) - goto expired; - if (tmo < next) - next = tmo; - } - if (xp->lft.soft_add_expires_seconds) { - long tmo = xp->lft.soft_add_expires_seconds + - xp->curlft.add_time - now; - if (tmo <= 0) { - warn = 1; - tmo = XFRM_KM_TIMEOUT; - } - if (tmo < next) - next = tmo; - } - if (xp->lft.soft_use_expires_seconds) { - long tmo = xp->lft.soft_use_expires_seconds + - (xp->curlft.use_time ? : xp->curlft.add_time) - now; - if (tmo <= 0) { - warn = 1; - tmo = XFRM_KM_TIMEOUT; - } - if (tmo < next) - next = tmo; - } - - if (warn) - km_policy_expired(xp, dir, 0, 0); - if (next != LONG_MAX && - !mod_timer(&xp->timer, jiffies + make_jiffies(next))) - xfrm_pol_hold(xp); - -out: - read_unlock(&xp->lock); - xfrm_pol_put(xp); - return; - -expired: - read_unlock(&xp->lock); - if (!xfrm_policy_delete(xp, dir)) - km_policy_expired(xp, dir, 1, 0); - xfrm_pol_put(xp); -} - -static struct flow_cache_object *xfrm_policy_flo_get(struct flow_cache_object *flo) -{ - struct xfrm_policy *pol = container_of(flo, struct xfrm_policy, flo); - - if (unlikely(pol->walk.dead)) - flo = NULL; - else - xfrm_pol_hold(pol); - - return flo; -} - -static int xfrm_policy_flo_check(struct flow_cache_object *flo) -{ - struct xfrm_policy *pol = container_of(flo, struct xfrm_policy, flo); - - return !pol->walk.dead; -} - -static void xfrm_policy_flo_delete(struct flow_cache_object *flo) -{ - xfrm_pol_put(container_of(flo, struct xfrm_policy, flo)); -} - -static const struct flow_cache_ops xfrm_policy_fc_ops = { - .get = xfrm_policy_flo_get, - .check = xfrm_policy_flo_check, - .delete = xfrm_policy_flo_delete, -}; - -/* Allocate xfrm_policy. Not used here, it is supposed to be used by pfkeyv2 - * SPD calls. - */ - -struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp) -{ - struct xfrm_policy *policy; - - policy = kzalloc(sizeof(struct xfrm_policy), gfp); - - if (policy) { - write_pnet(&policy->xp_net, net); - INIT_LIST_HEAD(&policy->walk.all); - INIT_HLIST_NODE(&policy->bydst); - INIT_HLIST_NODE(&policy->byidx); - rwlock_init(&policy->lock); - atomic_set(&policy->refcnt, 1); - skb_queue_head_init(&policy->polq.hold_queue); - setup_timer(&policy->timer, xfrm_policy_timer, - (unsigned long)policy); - setup_timer(&policy->polq.hold_timer, xfrm_policy_queue_process, - (unsigned long)policy); - policy->flo.ops = &xfrm_policy_fc_ops; - } - return policy; -} -EXPORT_SYMBOL(xfrm_policy_alloc); - -static void xfrm_policy_destroy_rcu(struct rcu_head *head) -{ - struct xfrm_policy *policy = container_of(head, struct xfrm_policy, rcu); - - security_xfrm_policy_free(policy->security); - kfree(policy); -} - -/* Destroy xfrm_policy: descendant resources must be released to this moment. */ - -void xfrm_policy_destroy(struct xfrm_policy *policy) -{ - BUG_ON(!policy->walk.dead); - - if (del_timer(&policy->timer) || del_timer(&policy->polq.hold_timer)) - BUG(); - - call_rcu(&policy->rcu, xfrm_policy_destroy_rcu); -} -EXPORT_SYMBOL(xfrm_policy_destroy); - -/* Rule must be locked. Release descentant resources, announce - * entry dead. The rule must be unlinked from lists to the moment. - */ - -static void xfrm_policy_kill(struct xfrm_policy *policy) -{ - policy->walk.dead = 1; - - atomic_inc(&policy->genid); - - if (del_timer(&policy->polq.hold_timer)) - xfrm_pol_put(policy); - skb_queue_purge(&policy->polq.hold_queue); - - if (del_timer(&policy->timer)) - xfrm_pol_put(policy); - - xfrm_pol_put(policy); -} - -static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024; - -static inline unsigned int idx_hash(struct net *net, u32 index) -{ - return __idx_hash(index, net->xfrm.policy_idx_hmask); -} - -/* calculate policy hash thresholds */ -static void __get_hash_thresh(struct net *net, - unsigned short family, int dir, - u8 *dbits, u8 *sbits) -{ - switch (family) { - case AF_INET: - *dbits = net->xfrm.policy_bydst[dir].dbits4; - *sbits = net->xfrm.policy_bydst[dir].sbits4; - break; - - case AF_INET6: - *dbits = net->xfrm.policy_bydst[dir].dbits6; - *sbits = net->xfrm.policy_bydst[dir].sbits6; - break; - - default: - *dbits = 0; - *sbits = 0; - } -} - -static struct hlist_head *policy_hash_bysel(struct net *net, - const struct xfrm_selector *sel, - unsigned short family, int dir) -{ - unsigned int hmask = net->xfrm.policy_bydst[dir].hmask; - unsigned int hash; - u8 dbits; - u8 sbits; - - __get_hash_thresh(net, family, dir, &dbits, &sbits); - hash = __sel_hash(sel, family, hmask, dbits, sbits); - - if (hash == hmask + 1) - return &net->xfrm.policy_inexact[dir]; - - return rcu_dereference_check(net->xfrm.policy_bydst[dir].table, - lockdep_is_held(&net->xfrm.xfrm_policy_lock)) + hash; -} - -static struct hlist_head *policy_hash_direct(struct net *net, - const xfrm_address_t *daddr, - const xfrm_address_t *saddr, - unsigned short family, int dir) -{ - unsigned int hmask = net->xfrm.policy_bydst[dir].hmask; - unsigned int hash; - u8 dbits; - u8 sbits; - - __get_hash_thresh(net, family, dir, &dbits, &sbits); - hash = __addr_hash(daddr, saddr, family, hmask, dbits, sbits); - - return rcu_dereference_check(net->xfrm.policy_bydst[dir].table, - lockdep_is_held(&net->xfrm.xfrm_policy_lock)) + hash; -} - -static void xfrm_dst_hash_transfer(struct net *net, - struct hlist_head *list, - struct hlist_head *ndsttable, - unsigned int nhashmask, - int dir) -{ - struct hlist_node *tmp, *entry0 = NULL; - struct xfrm_policy *pol; - unsigned int h0 = 0; - u8 dbits; - u8 sbits; - -redo: - hlist_for_each_entry_safe(pol, tmp, list, bydst) { - unsigned int h; - - __get_hash_thresh(net, pol->family, dir, &dbits, &sbits); - h = __addr_hash(&pol->selector.daddr, &pol->selector.saddr, - pol->family, nhashmask, dbits, sbits); - if (!entry0) { - hlist_del_rcu(&pol->bydst); - hlist_add_head_rcu(&pol->bydst, ndsttable + h); - h0 = h; - } else { - if (h != h0) - continue; - hlist_del_rcu(&pol->bydst); - hlist_add_behind_rcu(&pol->bydst, entry0); - } - entry0 = &pol->bydst; - } - if (!hlist_empty(list)) { - entry0 = NULL; - goto redo; - } -} - -static void xfrm_idx_hash_transfer(struct hlist_head *list, - struct hlist_head *nidxtable, - unsigned int nhashmask) -{ - struct hlist_node *tmp; - struct xfrm_policy *pol; - - hlist_for_each_entry_safe(pol, tmp, list, byidx) { - unsigned int h; - - h = __idx_hash(pol->index, nhashmask); - hlist_add_head(&pol->byidx, nidxtable+h); - } -} - -static unsigned long xfrm_new_hash_mask(unsigned int old_hmask) -{ - return ((old_hmask + 1) << 1) - 1; -} - -static void xfrm_bydst_resize(struct net *net, int dir) -{ - unsigned int hmask = net->xfrm.policy_bydst[dir].hmask; - unsigned int nhashmask = xfrm_new_hash_mask(hmask); - unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); - struct hlist_head *ndst = xfrm_hash_alloc(nsize); - struct hlist_head *odst; - int i; - - if (!ndst) - return; - - spin_lock_bh(&net->xfrm.xfrm_policy_lock); - write_seqcount_begin(&xfrm_policy_hash_generation); - - odst = rcu_dereference_protected(net->xfrm.policy_bydst[dir].table, - lockdep_is_held(&net->xfrm.xfrm_policy_lock)); - - odst = rcu_dereference_protected(net->xfrm.policy_bydst[dir].table, - lockdep_is_held(&net->xfrm.xfrm_policy_lock)); - - for (i = hmask; i >= 0; i--) - xfrm_dst_hash_transfer(net, odst + i, ndst, nhashmask, dir); - - rcu_assign_pointer(net->xfrm.policy_bydst[dir].table, ndst); - net->xfrm.policy_bydst[dir].hmask = nhashmask; - - write_seqcount_end(&xfrm_policy_hash_generation); - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); - - synchronize_rcu(); - - xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head)); -} - -static void xfrm_byidx_resize(struct net *net, int total) -{ - unsigned int hmask = net->xfrm.policy_idx_hmask; - unsigned int nhashmask = xfrm_new_hash_mask(hmask); - unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); - struct hlist_head *oidx = net->xfrm.policy_byidx; - struct hlist_head *nidx = xfrm_hash_alloc(nsize); - int i; - - if (!nidx) - return; - - spin_lock_bh(&net->xfrm.xfrm_policy_lock); - - for (i = hmask; i >= 0; i--) - xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask); - - net->xfrm.policy_byidx = nidx; - net->xfrm.policy_idx_hmask = nhashmask; - - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); - - xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head)); -} - -static inline int xfrm_bydst_should_resize(struct net *net, int dir, int *total) -{ - unsigned int cnt = net->xfrm.policy_count[dir]; - unsigned int hmask = net->xfrm.policy_bydst[dir].hmask; - - if (total) - *total += cnt; - - if ((hmask + 1) < xfrm_policy_hashmax && - cnt > hmask) - return 1; - - return 0; -} - -static inline int xfrm_byidx_should_resize(struct net *net, int total) -{ - unsigned int hmask = net->xfrm.policy_idx_hmask; - - if ((hmask + 1) < xfrm_policy_hashmax && - total > hmask) - return 1; - - return 0; -} - -void xfrm_spd_getinfo(struct net *net, struct xfrmk_spdinfo *si) -{ - si->incnt = net->xfrm.policy_count[XFRM_POLICY_IN]; - si->outcnt = net->xfrm.policy_count[XFRM_POLICY_OUT]; - si->fwdcnt = net->xfrm.policy_count[XFRM_POLICY_FWD]; - si->inscnt = net->xfrm.policy_count[XFRM_POLICY_IN+XFRM_POLICY_MAX]; - si->outscnt = net->xfrm.policy_count[XFRM_POLICY_OUT+XFRM_POLICY_MAX]; - si->fwdscnt = net->xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX]; - si->spdhcnt = net->xfrm.policy_idx_hmask; - si->spdhmcnt = xfrm_policy_hashmax; -} -EXPORT_SYMBOL(xfrm_spd_getinfo); - -static DEFINE_MUTEX(hash_resize_mutex); -static void xfrm_hash_resize(struct work_struct *work) -{ - struct net *net = container_of(work, struct net, xfrm.policy_hash_work); - int dir, total; - - mutex_lock(&hash_resize_mutex); - - total = 0; - for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { - if (xfrm_bydst_should_resize(net, dir, &total)) - xfrm_bydst_resize(net, dir); - } - if (xfrm_byidx_should_resize(net, total)) - xfrm_byidx_resize(net, total); - - mutex_unlock(&hash_resize_mutex); -} - -static void xfrm_hash_rebuild(struct work_struct *work) -{ - struct net *net = container_of(work, struct net, - xfrm.policy_hthresh.work); - unsigned int hmask; - struct xfrm_policy *pol; - struct xfrm_policy *policy; - struct hlist_head *chain; - struct hlist_head *odst; - struct hlist_node *newpos; - int i; - int dir; - unsigned seq; - u8 lbits4, rbits4, lbits6, rbits6; - - mutex_lock(&hash_resize_mutex); - - /* read selector prefixlen thresholds */ - do { - seq = read_seqbegin(&net->xfrm.policy_hthresh.lock); - - lbits4 = net->xfrm.policy_hthresh.lbits4; - rbits4 = net->xfrm.policy_hthresh.rbits4; - lbits6 = net->xfrm.policy_hthresh.lbits6; - rbits6 = net->xfrm.policy_hthresh.rbits6; - } while (read_seqretry(&net->xfrm.policy_hthresh.lock, seq)); - - spin_lock_bh(&net->xfrm.xfrm_policy_lock); - - /* reset the bydst and inexact table in all directions */ - for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { - INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]); - hmask = net->xfrm.policy_bydst[dir].hmask; - odst = net->xfrm.policy_bydst[dir].table; - for (i = hmask; i >= 0; i--) - INIT_HLIST_HEAD(odst + i); - if ((dir & XFRM_POLICY_MASK) == XFRM_POLICY_OUT) { - /* dir out => dst = remote, src = local */ - net->xfrm.policy_bydst[dir].dbits4 = rbits4; - net->xfrm.policy_bydst[dir].sbits4 = lbits4; - net->xfrm.policy_bydst[dir].dbits6 = rbits6; - net->xfrm.policy_bydst[dir].sbits6 = lbits6; - } else { - /* dir in/fwd => dst = local, src = remote */ - net->xfrm.policy_bydst[dir].dbits4 = lbits4; - net->xfrm.policy_bydst[dir].sbits4 = rbits4; - net->xfrm.policy_bydst[dir].dbits6 = lbits6; - net->xfrm.policy_bydst[dir].sbits6 = rbits6; - } - } - - /* re-insert all policies by order of creation */ - list_for_each_entry_reverse(policy, &net->xfrm.policy_all, walk.all) { - if (xfrm_policy_id2dir(policy->index) >= XFRM_POLICY_MAX) { - /* skip socket policies */ - continue; - } - newpos = NULL; - chain = policy_hash_bysel(net, &policy->selector, - policy->family, - xfrm_policy_id2dir(policy->index)); - hlist_for_each_entry(pol, chain, bydst) { - if (policy->priority >= pol->priority) - newpos = &pol->bydst; - else - break; - } - if (newpos) - hlist_add_behind(&policy->bydst, newpos); - else - hlist_add_head(&policy->bydst, chain); - } - - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); - - mutex_unlock(&hash_resize_mutex); -} - -void xfrm_policy_hash_rebuild(struct net *net) -{ - schedule_work(&net->xfrm.policy_hthresh.work); -} -EXPORT_SYMBOL(xfrm_policy_hash_rebuild); - -/* Generate new index... KAME seems to generate them ordered by cost - * of an absolute inpredictability of ordering of rules. This will not pass. */ -static u32 xfrm_gen_index(struct net *net, int dir, u32 index) -{ - static u32 idx_generator; - - for (;;) { - struct hlist_head *list; - struct xfrm_policy *p; - u32 idx; - int found; - - if (!index) { - idx = (idx_generator | dir); - idx_generator += 8; - } else { - idx = index; - index = 0; - } - - if (idx == 0) - idx = 8; - list = net->xfrm.policy_byidx + idx_hash(net, idx); - found = 0; - hlist_for_each_entry(p, list, byidx) { - if (p->index == idx) { - found = 1; - break; - } - } - if (!found) - return idx; - } -} - -static inline int selector_cmp(struct xfrm_selector *s1, struct xfrm_selector *s2) -{ - u32 *p1 = (u32 *) s1; - u32 *p2 = (u32 *) s2; - int len = sizeof(struct xfrm_selector) / sizeof(u32); - int i; - - for (i = 0; i < len; i++) { - if (p1[i] != p2[i]) - return 1; - } - - return 0; -} - -static void xfrm_policy_requeue(struct xfrm_policy *old, - struct xfrm_policy *new) -{ - struct xfrm_policy_queue *pq = &old->polq; - struct sk_buff_head list; - - if (skb_queue_empty(&pq->hold_queue)) - return; - - __skb_queue_head_init(&list); - - spin_lock_bh(&pq->hold_queue.lock); - skb_queue_splice_init(&pq->hold_queue, &list); - if (del_timer(&pq->hold_timer)) - xfrm_pol_put(old); - spin_unlock_bh(&pq->hold_queue.lock); - - pq = &new->polq; - - spin_lock_bh(&pq->hold_queue.lock); - skb_queue_splice(&list, &pq->hold_queue); - pq->timeout = XFRM_QUEUE_TMO_MIN; - if (!mod_timer(&pq->hold_timer, jiffies)) - xfrm_pol_hold(new); - spin_unlock_bh(&pq->hold_queue.lock); -} - -static bool xfrm_policy_mark_match(struct xfrm_policy *policy, - struct xfrm_policy *pol) -{ - u32 mark = policy->mark.v & policy->mark.m; - - if (policy->mark.v == pol->mark.v && policy->mark.m == pol->mark.m) - return true; - - if ((mark & pol->mark.m) == pol->mark.v && - policy->priority == pol->priority) - return true; - - return false; -} - -int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) -{ - struct net *net = xp_net(policy); - struct xfrm_policy *pol; - struct xfrm_policy *delpol; - struct hlist_head *chain; - struct hlist_node *newpos; - - spin_lock_bh(&net->xfrm.xfrm_policy_lock); - chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); - delpol = NULL; - newpos = NULL; - hlist_for_each_entry(pol, chain, bydst) { - if (pol->type == policy->type && - !selector_cmp(&pol->selector, &policy->selector) && - xfrm_policy_mark_match(policy, pol) && - xfrm_sec_ctx_match(pol->security, policy->security) && - !WARN_ON(delpol)) { - if (excl) { - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); - return -EEXIST; - } - delpol = pol; - if (policy->priority > pol->priority) - continue; - } else if (policy->priority >= pol->priority) { - newpos = &pol->bydst; - continue; - } - if (delpol) - break; - } - if (newpos) - hlist_add_behind(&policy->bydst, newpos); - else - hlist_add_head(&policy->bydst, chain); - __xfrm_policy_link(policy, dir); - atomic_inc(&net->xfrm.flow_cache_genid); - - /* After previous checking, family can either be AF_INET or AF_INET6 */ - if (policy->family == AF_INET) - rt_genid_bump_ipv4(net); - else - rt_genid_bump_ipv6(net); - - if (delpol) { - xfrm_policy_requeue(delpol, policy); - __xfrm_policy_unlink(delpol, dir); - } - policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir, policy->index); - hlist_add_head(&policy->byidx, net->xfrm.policy_byidx+idx_hash(net, policy->index)); - policy->curlft.add_time = get_seconds(); - policy->curlft.use_time = 0; - if (!mod_timer(&policy->timer, jiffies + HZ)) - xfrm_pol_hold(policy); - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); - - if (delpol) - xfrm_policy_kill(delpol); - else if (xfrm_bydst_should_resize(net, dir, NULL)) - schedule_work(&net->xfrm.policy_hash_work); - - return 0; -} -EXPORT_SYMBOL(xfrm_policy_insert); - -struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, - int dir, struct xfrm_selector *sel, - struct xfrm_sec_ctx *ctx, int delete, - int *err) -{ - struct xfrm_policy *pol, *ret; - struct hlist_head *chain; - - *err = 0; - spin_lock_bh(&net->xfrm.xfrm_policy_lock); - chain = policy_hash_bysel(net, sel, sel->family, dir); - ret = NULL; - hlist_for_each_entry(pol, chain, bydst) { - if (pol->type == type && - (mark & pol->mark.m) == pol->mark.v && - !selector_cmp(sel, &pol->selector) && - xfrm_sec_ctx_match(ctx, pol->security)) { - xfrm_pol_hold(pol); - if (delete) { - *err = security_xfrm_policy_delete( - pol->security); - if (*err) { - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); - return pol; - } - __xfrm_policy_unlink(pol, dir); - } - ret = pol; - break; - } - } - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); - - if (ret && delete) - xfrm_policy_kill(ret); - return ret; -} -EXPORT_SYMBOL(xfrm_policy_bysel_ctx); - -struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8 type, - int dir, u32 id, int delete, int *err) -{ - struct xfrm_policy *pol, *ret; - struct hlist_head *chain; - - *err = -ENOENT; - if (xfrm_policy_id2dir(id) != dir) - return NULL; - - *err = 0; - spin_lock_bh(&net->xfrm.xfrm_policy_lock); - chain = net->xfrm.policy_byidx + idx_hash(net, id); - ret = NULL; - hlist_for_each_entry(pol, chain, byidx) { - if (pol->type == type && pol->index == id && - (mark & pol->mark.m) == pol->mark.v) { - xfrm_pol_hold(pol); - if (delete) { - *err = security_xfrm_policy_delete( - pol->security); - if (*err) { - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); - return pol; - } - __xfrm_policy_unlink(pol, dir); - } - ret = pol; - break; - } - } - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); - - if (ret && delete) - xfrm_policy_kill(ret); - return ret; -} -EXPORT_SYMBOL(xfrm_policy_byid); - -#ifdef CONFIG_SECURITY_NETWORK_XFRM -static inline int -xfrm_policy_flush_secctx_check(struct net *net, u8 type, bool task_valid) -{ - int dir, err = 0; - - for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { - struct xfrm_policy *pol; - int i; - - hlist_for_each_entry(pol, - &net->xfrm.policy_inexact[dir], bydst) { - if (pol->type != type) - continue; - err = security_xfrm_policy_delete(pol->security); - if (err) { - xfrm_audit_policy_delete(pol, 0, task_valid); - return err; - } - } - for (i = net->xfrm.policy_bydst[dir].hmask; i >= 0; i--) { - hlist_for_each_entry(pol, - net->xfrm.policy_bydst[dir].table + i, - bydst) { - if (pol->type != type) - continue; - err = security_xfrm_policy_delete( - pol->security); - if (err) { - xfrm_audit_policy_delete(pol, 0, - task_valid); - return err; - } - } - } - } - return err; -} -#else -static inline int -xfrm_policy_flush_secctx_check(struct net *net, u8 type, bool task_valid) -{ - return 0; -} -#endif - -int xfrm_policy_flush(struct net *net, u8 type, bool task_valid) -{ - int dir, err = 0, cnt = 0; - - spin_lock_bh(&net->xfrm.xfrm_policy_lock); - - err = xfrm_policy_flush_secctx_check(net, type, task_valid); - if (err) - goto out; - - for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { - struct xfrm_policy *pol; - int i; - - again1: - hlist_for_each_entry(pol, - &net->xfrm.policy_inexact[dir], bydst) { - if (pol->type != type) - continue; - __xfrm_policy_unlink(pol, dir); - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); - cnt++; - - xfrm_audit_policy_delete(pol, 1, task_valid); - - xfrm_policy_kill(pol); - - spin_lock_bh(&net->xfrm.xfrm_policy_lock); - goto again1; - } - - for (i = net->xfrm.policy_bydst[dir].hmask; i >= 0; i--) { - again2: - hlist_for_each_entry(pol, - net->xfrm.policy_bydst[dir].table + i, - bydst) { - if (pol->type != type) - continue; - __xfrm_policy_unlink(pol, dir); - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); - cnt++; - - xfrm_audit_policy_delete(pol, 1, task_valid); - xfrm_policy_kill(pol); - - spin_lock_bh(&net->xfrm.xfrm_policy_lock); - goto again2; - } - } - - } - if (!cnt) - err = -ESRCH; -out: - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); - return err; -} -EXPORT_SYMBOL(xfrm_policy_flush); - -int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, - int (*func)(struct xfrm_policy *, int, int, void*), - void *data) -{ - struct xfrm_policy *pol; - struct xfrm_policy_walk_entry *x; - int error = 0; - - if (walk->type >= XFRM_POLICY_TYPE_MAX && - walk->type != XFRM_POLICY_TYPE_ANY) - return -EINVAL; - - if (list_empty(&walk->walk.all) && walk->seq != 0) - return 0; - - spin_lock_bh(&net->xfrm.xfrm_policy_lock); - if (list_empty(&walk->walk.all)) - x = list_first_entry(&net->xfrm.policy_all, struct xfrm_policy_walk_entry, all); - else - x = list_first_entry(&walk->walk.all, - struct xfrm_policy_walk_entry, all); - - list_for_each_entry_from(x, &net->xfrm.policy_all, all) { - if (x->dead) - continue; - pol = container_of(x, struct xfrm_policy, walk); - if (walk->type != XFRM_POLICY_TYPE_ANY && - walk->type != pol->type) - continue; - error = func(pol, xfrm_policy_id2dir(pol->index), - walk->seq, data); - if (error) { - list_move_tail(&walk->walk.all, &x->all); - goto out; - } - walk->seq++; - } - if (walk->seq == 0) { - error = -ENOENT; - goto out; - } - list_del_init(&walk->walk.all); -out: - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); - return error; -} -EXPORT_SYMBOL(xfrm_policy_walk); - -void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type) -{ - INIT_LIST_HEAD(&walk->walk.all); - walk->walk.dead = 1; - walk->type = type; - walk->seq = 0; -} -EXPORT_SYMBOL(xfrm_policy_walk_init); - -void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net) -{ - if (list_empty(&walk->walk.all)) - return; - - spin_lock_bh(&net->xfrm.xfrm_policy_lock); /*FIXME where is net? */ - list_del(&walk->walk.all); - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); -} -EXPORT_SYMBOL(xfrm_policy_walk_done); - -/* - * Find policy to apply to this flow. - * - * Returns 0 if policy found, else an -errno. - */ -static int xfrm_policy_match(const struct xfrm_policy *pol, - const struct flowi *fl, - u8 type, u16 family, int dir) -{ - const struct xfrm_selector *sel = &pol->selector; - int ret = -ESRCH; - bool match; - - if (pol->family != family || - (fl->flowi_mark & pol->mark.m) != pol->mark.v || - pol->type != type) - return ret; - - match = xfrm_selector_match(sel, fl, family); - if (match) - ret = security_xfrm_policy_lookup(pol->security, fl->flowi_secid, - dir); - - return ret; -} - -static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type, - const struct flowi *fl, - u16 family, u8 dir) -{ - int err; - struct xfrm_policy *pol, *ret; - const xfrm_address_t *daddr, *saddr; - struct hlist_head *chain; - unsigned int sequence; - u32 priority; - - daddr = xfrm_flowi_daddr(fl, family); - saddr = xfrm_flowi_saddr(fl, family); - if (unlikely(!daddr || !saddr)) - return NULL; - - rcu_read_lock(); - retry: - do { - sequence = read_seqcount_begin(&xfrm_policy_hash_generation); - chain = policy_hash_direct(net, daddr, saddr, family, dir); - } while (read_seqcount_retry(&xfrm_policy_hash_generation, sequence)); - - priority = ~0U; - ret = NULL; - hlist_for_each_entry_rcu(pol, chain, bydst) { - err = xfrm_policy_match(pol, fl, type, family, dir); - if (err) { - if (err == -ESRCH) - continue; - else { - ret = ERR_PTR(err); - goto fail; - } - } else { - ret = pol; - priority = ret->priority; - break; - } - } - chain = &net->xfrm.policy_inexact[dir]; - hlist_for_each_entry_rcu(pol, chain, bydst) { - if ((pol->priority >= priority) && ret) - break; - - err = xfrm_policy_match(pol, fl, type, family, dir); - if (err) { - if (err == -ESRCH) - continue; - else { - ret = ERR_PTR(err); - goto fail; - } - } else { - ret = pol; - break; - } - } - - if (read_seqcount_retry(&xfrm_policy_hash_generation, sequence)) - goto retry; - - if (ret && !xfrm_pol_hold_rcu(ret)) - goto retry; -fail: - rcu_read_unlock(); - - return ret; -} - -static struct xfrm_policy * -__xfrm_policy_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir) -{ -#ifdef CONFIG_XFRM_SUB_POLICY - struct xfrm_policy *pol; - - pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family, dir); - if (pol != NULL) - return pol; -#endif - return xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir); -} - -static int flow_to_policy_dir(int dir) -{ - if (XFRM_POLICY_IN == FLOW_DIR_IN && - XFRM_POLICY_OUT == FLOW_DIR_OUT && - XFRM_POLICY_FWD == FLOW_DIR_FWD) - return dir; - - switch (dir) { - default: - case FLOW_DIR_IN: - return XFRM_POLICY_IN; - case FLOW_DIR_OUT: - return XFRM_POLICY_OUT; - case FLOW_DIR_FWD: - return XFRM_POLICY_FWD; - } -} - -static struct flow_cache_object * -xfrm_policy_lookup(struct net *net, const struct flowi *fl, u16 family, - u8 dir, struct flow_cache_object *old_obj, void *ctx) -{ - struct xfrm_policy *pol; - - if (old_obj) - xfrm_pol_put(container_of(old_obj, struct xfrm_policy, flo)); - - pol = __xfrm_policy_lookup(net, fl, family, flow_to_policy_dir(dir)); - if (IS_ERR_OR_NULL(pol)) - return ERR_CAST(pol); - - /* Resolver returns two references: - * one for cache and one for caller of flow_cache_lookup() */ - xfrm_pol_hold(pol); - - return &pol->flo; -} - -static inline int policy_to_flow_dir(int dir) -{ - if (XFRM_POLICY_IN == FLOW_DIR_IN && - XFRM_POLICY_OUT == FLOW_DIR_OUT && - XFRM_POLICY_FWD == FLOW_DIR_FWD) - return dir; - switch (dir) { - default: - case XFRM_POLICY_IN: - return FLOW_DIR_IN; - case XFRM_POLICY_OUT: - return FLOW_DIR_OUT; - case XFRM_POLICY_FWD: - return FLOW_DIR_FWD; - } -} - -static struct xfrm_policy *xfrm_sk_policy_lookup(const struct sock *sk, int dir, - const struct flowi *fl) -{ - struct xfrm_policy *pol; - - rcu_read_lock(); - again: - pol = rcu_dereference(sk->sk_policy[dir]); - if (pol != NULL) { - bool match = xfrm_selector_match(&pol->selector, fl, - sk->sk_family); - int err = 0; - - if (match) { - if ((sk->sk_mark & pol->mark.m) != pol->mark.v) { - pol = NULL; - goto out; - } - err = security_xfrm_policy_lookup(pol->security, - fl->flowi_secid, - policy_to_flow_dir(dir)); - if (!err) { - if (!xfrm_pol_hold_rcu(pol)) - goto again; - } else if (err == -ESRCH) { - pol = NULL; - } else { - pol = ERR_PTR(err); - } - } else - pol = NULL; - } -out: - rcu_read_unlock(); - return pol; -} - -static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) -{ - struct net *net = xp_net(pol); - - list_add(&pol->walk.all, &net->xfrm.policy_all); - net->xfrm.policy_count[dir]++; - xfrm_pol_hold(pol); -} - -static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, - int dir) -{ - struct net *net = xp_net(pol); - - if (list_empty(&pol->walk.all)) - return NULL; - - /* Socket policies are not hashed. */ - if (!hlist_unhashed(&pol->bydst)) { - hlist_del_rcu(&pol->bydst); - hlist_del(&pol->byidx); - } - - list_del_init(&pol->walk.all); - net->xfrm.policy_count[dir]--; - - return pol; -} - -static void xfrm_sk_policy_link(struct xfrm_policy *pol, int dir) -{ - __xfrm_policy_link(pol, XFRM_POLICY_MAX + dir); -} - -static void xfrm_sk_policy_unlink(struct xfrm_policy *pol, int dir) -{ - __xfrm_policy_unlink(pol, XFRM_POLICY_MAX + dir); -} - -int xfrm_policy_delete(struct xfrm_policy *pol, int dir) -{ - struct net *net = xp_net(pol); - - spin_lock_bh(&net->xfrm.xfrm_policy_lock); - pol = __xfrm_policy_unlink(pol, dir); - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); - if (pol) { - xfrm_policy_kill(pol); - return 0; - } - return -ENOENT; -} -EXPORT_SYMBOL(xfrm_policy_delete); - -int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) -{ - struct net *net = xp_net(pol); - struct xfrm_policy *old_pol; - -#ifdef CONFIG_XFRM_SUB_POLICY - if (pol && pol->type != XFRM_POLICY_TYPE_MAIN) - return -EINVAL; -#endif - - spin_lock_bh(&net->xfrm.xfrm_policy_lock); - old_pol = rcu_dereference_protected(sk->sk_policy[dir], - lockdep_is_held(&net->xfrm.xfrm_policy_lock)); - if (pol) { - pol->curlft.add_time = get_seconds(); - pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir, 0); - xfrm_sk_policy_link(pol, dir); - } - rcu_assign_pointer(sk->sk_policy[dir], pol); - if (old_pol) { - if (pol) - xfrm_policy_requeue(old_pol, pol); - - /* Unlinking succeeds always. This is the only function - * allowed to delete or replace socket policy. - */ - xfrm_sk_policy_unlink(old_pol, dir); - } - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); - - if (old_pol) { - xfrm_policy_kill(old_pol); - } - return 0; -} - -static struct xfrm_policy *clone_policy(const struct xfrm_policy *old, int dir) -{ - struct xfrm_policy *newp = xfrm_policy_alloc(xp_net(old), GFP_ATOMIC); - struct net *net = xp_net(old); - - if (newp) { - newp->selector = old->selector; - if (security_xfrm_policy_clone(old->security, - &newp->security)) { - kfree(newp); - return NULL; /* ENOMEM */ - } - newp->lft = old->lft; - newp->curlft = old->curlft; - newp->mark = old->mark; - newp->action = old->action; - newp->flags = old->flags; - newp->xfrm_nr = old->xfrm_nr; - newp->index = old->index; - newp->type = old->type; - memcpy(newp->xfrm_vec, old->xfrm_vec, - newp->xfrm_nr*sizeof(struct xfrm_tmpl)); - spin_lock_bh(&net->xfrm.xfrm_policy_lock); - xfrm_sk_policy_link(newp, dir); - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); - xfrm_pol_put(newp); - } - return newp; -} - -int __xfrm_sk_clone_policy(struct sock *sk, const struct sock *osk) -{ - const struct xfrm_policy *p; - struct xfrm_policy *np; - int i, ret = 0; - - rcu_read_lock(); - for (i = 0; i < 2; i++) { - p = rcu_dereference(osk->sk_policy[i]); - if (p) { - np = clone_policy(p, i); - if (unlikely(!np)) { - ret = -ENOMEM; - break; - } - rcu_assign_pointer(sk->sk_policy[i], np); - } - } - rcu_read_unlock(); - return ret; -} - -static int -xfrm_get_saddr(struct net *net, int oif, xfrm_address_t *local, - xfrm_address_t *remote, unsigned short family) -{ - int err; - struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); - - if (unlikely(afinfo == NULL)) - return -EINVAL; - err = afinfo->get_saddr(net, oif, local, remote); - xfrm_policy_put_afinfo(afinfo); - return err; -} - -/* Resolve list of templates for the flow, given policy. */ - -static int -xfrm_tmpl_resolve_one(struct xfrm_policy *policy, const struct flowi *fl, - struct xfrm_state **xfrm, unsigned short family) -{ - struct net *net = xp_net(policy); - int nx; - int i, error; - xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family); - xfrm_address_t *saddr = xfrm_flowi_saddr(fl, family); - xfrm_address_t tmp; - - for (nx = 0, i = 0; i < policy->xfrm_nr; i++) { - struct xfrm_state *x; - xfrm_address_t *remote = daddr; - xfrm_address_t *local = saddr; - struct xfrm_tmpl *tmpl = &policy->xfrm_vec[i]; - - if (tmpl->mode == XFRM_MODE_TUNNEL || - tmpl->mode == XFRM_MODE_BEET) { - remote = &tmpl->id.daddr; - local = &tmpl->saddr; - if (xfrm_addr_any(local, tmpl->encap_family)) { - error = xfrm_get_saddr(net, fl->flowi_oif, - &tmp, remote, - tmpl->encap_family); - if (error) - goto fail; - local = &tmp; - } - } - - x = xfrm_state_find(remote, local, fl, tmpl, policy, &error, family); - - if (x && x->km.state == XFRM_STATE_VALID) { - xfrm[nx++] = x; - daddr = remote; - saddr = local; - continue; - } - if (x) { - error = (x->km.state == XFRM_STATE_ERROR ? - -EINVAL : -EAGAIN); - xfrm_state_put(x); - } else if (error == -ESRCH) { - error = -EAGAIN; - } - - if (!tmpl->optional) - goto fail; - } - return nx; - -fail: - for (nx--; nx >= 0; nx--) - xfrm_state_put(xfrm[nx]); - return error; -} - -static int -xfrm_tmpl_resolve(struct xfrm_policy **pols, int npols, const struct flowi *fl, - struct xfrm_state **xfrm, unsigned short family) -{ - struct xfrm_state *tp[XFRM_MAX_DEPTH]; - struct xfrm_state **tpp = (npols > 1) ? tp : xfrm; - int cnx = 0; - int error; - int ret; - int i; - - for (i = 0; i < npols; i++) { - if (cnx + pols[i]->xfrm_nr >= XFRM_MAX_DEPTH) { - error = -ENOBUFS; - goto fail; - } - - ret = xfrm_tmpl_resolve_one(pols[i], fl, &tpp[cnx], family); - if (ret < 0) { - error = ret; - goto fail; - } else - cnx += ret; - } - - /* found states are sorted for outbound processing */ - if (npols > 1) - xfrm_state_sort(xfrm, tpp, cnx, family); - - return cnx; - - fail: - for (cnx--; cnx >= 0; cnx--) - xfrm_state_put(tpp[cnx]); - return error; - -} - -/* Check that the bundle accepts the flow and its components are - * still valid. - */ - -static inline int xfrm_get_tos(const struct flowi *fl, int family) -{ - struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); - int tos; - - if (!afinfo) - return -EINVAL; - - tos = afinfo->get_tos(fl); - - xfrm_policy_put_afinfo(afinfo); - - return tos; -} - -static struct flow_cache_object *xfrm_bundle_flo_get(struct flow_cache_object *flo) -{ - struct xfrm_dst *xdst = container_of(flo, struct xfrm_dst, flo); - struct dst_entry *dst = &xdst->u.dst; - - if (xdst->route == NULL) { - /* Dummy bundle - if it has xfrms we were not - * able to build bundle as template resolution failed. - * It means we need to try again resolving. */ - if (xdst->num_xfrms > 0) - return NULL; - } else if (dst->flags & DST_XFRM_QUEUE) { - return NULL; - } else { - /* Real bundle */ - if (stale_bundle(dst)) - return NULL; - } - - dst_hold(dst); - return flo; -} - -static int xfrm_bundle_flo_check(struct flow_cache_object *flo) -{ - struct xfrm_dst *xdst = container_of(flo, struct xfrm_dst, flo); - struct dst_entry *dst = &xdst->u.dst; - - if (!xdst->route) - return 0; - if (stale_bundle(dst)) - return 0; - - return 1; -} - -static void xfrm_bundle_flo_delete(struct flow_cache_object *flo) -{ - struct xfrm_dst *xdst = container_of(flo, struct xfrm_dst, flo); - struct dst_entry *dst = &xdst->u.dst; - - dst_free(dst); -} - -static const struct flow_cache_ops xfrm_bundle_fc_ops = { - .get = xfrm_bundle_flo_get, - .check = xfrm_bundle_flo_check, - .delete = xfrm_bundle_flo_delete, -}; - -static inline struct xfrm_dst *xfrm_alloc_dst(struct net *net, int family) -{ - struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); - struct dst_ops *dst_ops; - struct xfrm_dst *xdst; - - if (!afinfo) - return ERR_PTR(-EINVAL); - - switch (family) { - case AF_INET: - dst_ops = &net->xfrm.xfrm4_dst_ops; - break; -#if IS_ENABLED(CONFIG_IPV6) - case AF_INET6: - dst_ops = &net->xfrm.xfrm6_dst_ops; - break; -#endif - default: - BUG(); - } - xdst = dst_alloc(dst_ops, NULL, 0, DST_OBSOLETE_NONE, 0); - - if (likely(xdst)) { - struct dst_entry *dst = &xdst->u.dst; - - memset(dst + 1, 0, sizeof(*xdst) - sizeof(*dst)); - xdst->flo.ops = &xfrm_bundle_fc_ops; - } else - xdst = ERR_PTR(-ENOBUFS); - - xfrm_policy_put_afinfo(afinfo); - - return xdst; -} - -static inline int xfrm_init_path(struct xfrm_dst *path, struct dst_entry *dst, - int nfheader_len) -{ - struct xfrm_policy_afinfo *afinfo = - xfrm_policy_get_afinfo(dst->ops->family); - int err; - - if (!afinfo) - return -EINVAL; - - err = afinfo->init_path(path, dst, nfheader_len); - - xfrm_policy_put_afinfo(afinfo); - - return err; -} - -static inline int xfrm_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, - const struct flowi *fl) -{ - struct xfrm_policy_afinfo *afinfo = - xfrm_policy_get_afinfo(xdst->u.dst.ops->family); - int err; - - if (!afinfo) - return -EINVAL; - - err = afinfo->fill_dst(xdst, dev, fl); - - xfrm_policy_put_afinfo(afinfo); - - return err; -} - - -/* Allocate chain of dst_entry's, attach known xfrm's, calculate - * all the metrics... Shortly, bundle a bundle. - */ - -static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, - struct xfrm_state **xfrm, int nx, - const struct flowi *fl, - struct dst_entry *dst) -{ - struct net *net = xp_net(policy); - unsigned long now = jiffies; - struct net_device *dev; - struct xfrm_mode *inner_mode; - struct dst_entry *dst_prev = NULL; - struct dst_entry *dst0 = NULL; - int i = 0; - int err; - int header_len = 0; - int nfheader_len = 0; - int trailer_len = 0; - int tos; - int family = policy->selector.family; - xfrm_address_t saddr, daddr; - - xfrm_flowi_addr_get(fl, &saddr, &daddr, family); - - tos = xfrm_get_tos(fl, family); - err = tos; - if (tos < 0) - goto put_states; - - dst_hold(dst); - - for (; i < nx; i++) { - struct xfrm_dst *xdst = xfrm_alloc_dst(net, family); - struct dst_entry *dst1 = &xdst->u.dst; - - err = PTR_ERR(xdst); - if (IS_ERR(xdst)) { - dst_release(dst); - goto put_states; - } - - if (xfrm[i]->sel.family == AF_UNSPEC) { - inner_mode = xfrm_ip2inner_mode(xfrm[i], - xfrm_af2proto(family)); - if (!inner_mode) { - err = -EAFNOSUPPORT; - dst_release(dst); - goto put_states; - } - } else - inner_mode = xfrm[i]->inner_mode; - - if (!dst_prev) - dst0 = dst1; - else { - dst_prev->child = dst_clone(dst1); - dst1->flags |= DST_NOHASH; - } - - xdst->route = dst; - dst_copy_metrics(dst1, dst); - - if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) { - family = xfrm[i]->props.family; - dst = xfrm_dst_lookup(xfrm[i], tos, fl->flowi_oif, - &saddr, &daddr, family); - err = PTR_ERR(dst); - if (IS_ERR(dst)) - goto put_states; - } else - dst_hold(dst); - - dst1->xfrm = xfrm[i]; - xdst->xfrm_genid = xfrm[i]->genid; - - dst1->obsolete = DST_OBSOLETE_FORCE_CHK; - dst1->flags |= DST_HOST; - dst1->lastuse = now; - - dst1->input = dst_discard; - dst1->output = inner_mode->afinfo->output; - - dst1->next = dst_prev; - dst_prev = dst1; - - header_len += xfrm[i]->props.header_len; - if (xfrm[i]->type->flags & XFRM_TYPE_NON_FRAGMENT) - nfheader_len += xfrm[i]->props.header_len; - trailer_len += xfrm[i]->props.trailer_len; - } - - dst_prev->child = dst; - dst0->path = dst; - - err = -ENODEV; - dev = dst->dev; - if (!dev) - goto free_dst; - - xfrm_init_path((struct xfrm_dst *)dst0, dst, nfheader_len); - xfrm_init_pmtu(dst_prev); - - for (dst_prev = dst0; dst_prev != dst; dst_prev = dst_prev->child) { - struct xfrm_dst *xdst = (struct xfrm_dst *)dst_prev; - - err = xfrm_fill_dst(xdst, dev, fl); - if (err) - goto free_dst; - - dst_prev->header_len = header_len; - dst_prev->trailer_len = trailer_len; - header_len -= xdst->u.dst.xfrm->props.header_len; - trailer_len -= xdst->u.dst.xfrm->props.trailer_len; - } - -out: - return dst0; - -put_states: - for (; i < nx; i++) - xfrm_state_put(xfrm[i]); -free_dst: - if (dst0) - dst_free(dst0); - dst0 = ERR_PTR(err); - goto out; -} - -#ifdef CONFIG_XFRM_SUB_POLICY -static int xfrm_dst_alloc_copy(void **target, const void *src, int size) -{ - if (!*target) { - *target = kmalloc(size, GFP_ATOMIC); - if (!*target) - return -ENOMEM; - } - - memcpy(*target, src, size); - return 0; -} -#endif - -static int xfrm_dst_update_parent(struct dst_entry *dst, - const struct xfrm_selector *sel) -{ -#ifdef CONFIG_XFRM_SUB_POLICY - struct xfrm_dst *xdst = (struct xfrm_dst *)dst; - return xfrm_dst_alloc_copy((void **)&(xdst->partner), - sel, sizeof(*sel)); -#else - return 0; -#endif -} - -static int xfrm_dst_update_origin(struct dst_entry *dst, - const struct flowi *fl) -{ -#ifdef CONFIG_XFRM_SUB_POLICY - struct xfrm_dst *xdst = (struct xfrm_dst *)dst; - return xfrm_dst_alloc_copy((void **)&(xdst->origin), fl, sizeof(*fl)); -#else - return 0; -#endif -} - -static int xfrm_expand_policies(const struct flowi *fl, u16 family, - struct xfrm_policy **pols, - int *num_pols, int *num_xfrms) -{ - int i; - - if (*num_pols == 0 || !pols[0]) { - *num_pols = 0; - *num_xfrms = 0; - return 0; - } - if (IS_ERR(pols[0])) - return PTR_ERR(pols[0]); - - *num_xfrms = pols[0]->xfrm_nr; - -#ifdef CONFIG_XFRM_SUB_POLICY - if (pols[0] && pols[0]->action == XFRM_POLICY_ALLOW && - pols[0]->type != XFRM_POLICY_TYPE_MAIN) { - pols[1] = xfrm_policy_lookup_bytype(xp_net(pols[0]), - XFRM_POLICY_TYPE_MAIN, - fl, family, - XFRM_POLICY_OUT); - if (pols[1]) { - if (IS_ERR(pols[1])) { - xfrm_pols_put(pols, *num_pols); - return PTR_ERR(pols[1]); - } - (*num_pols)++; - (*num_xfrms) += pols[1]->xfrm_nr; - } - } -#endif - for (i = 0; i < *num_pols; i++) { - if (pols[i]->action != XFRM_POLICY_ALLOW) { - *num_xfrms = -1; - break; - } - } - - return 0; - -} - -static struct xfrm_dst * -xfrm_resolve_and_create_bundle(struct xfrm_policy **pols, int num_pols, - const struct flowi *fl, u16 family, - struct dst_entry *dst_orig) -{ - struct net *net = xp_net(pols[0]); - struct xfrm_state *xfrm[XFRM_MAX_DEPTH]; - struct dst_entry *dst; - struct xfrm_dst *xdst; - int err; - - /* Try to instantiate a bundle */ - err = xfrm_tmpl_resolve(pols, num_pols, fl, xfrm, family); - if (err <= 0) { - if (err != 0 && err != -EAGAIN) - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR); - return ERR_PTR(err); - } - - dst = xfrm_bundle_create(pols[0], xfrm, err, fl, dst_orig); - if (IS_ERR(dst)) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLEGENERROR); - return ERR_CAST(dst); - } - - xdst = (struct xfrm_dst *)dst; - xdst->num_xfrms = err; - if (num_pols > 1) - err = xfrm_dst_update_parent(dst, &pols[1]->selector); - else - err = xfrm_dst_update_origin(dst, fl); - if (unlikely(err)) { - dst_free(dst); - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR); - return ERR_PTR(err); - } - - xdst->num_pols = num_pols; - memcpy(xdst->pols, pols, sizeof(struct xfrm_policy *) * num_pols); - xdst->policy_genid = atomic_read(&pols[0]->genid); - - return xdst; -} - -static void xfrm_policy_queue_process(unsigned long arg) -{ - struct sk_buff *skb; - struct sock *sk; - struct dst_entry *dst; - struct xfrm_policy *pol = (struct xfrm_policy *)arg; - struct net *net = xp_net(pol); - struct xfrm_policy_queue *pq = &pol->polq; - struct flowi fl; - struct sk_buff_head list; - - spin_lock(&pq->hold_queue.lock); - skb = skb_peek(&pq->hold_queue); - if (!skb) { - spin_unlock(&pq->hold_queue.lock); - goto out; - } - dst = skb_dst(skb); - sk = skb->sk; - xfrm_decode_session(skb, &fl, dst->ops->family); - spin_unlock(&pq->hold_queue.lock); - - dst_hold(dst->path); - dst = xfrm_lookup(net, dst->path, &fl, sk, 0); - if (IS_ERR(dst)) - goto purge_queue; - - if (dst->flags & DST_XFRM_QUEUE) { - dst_release(dst); - - if (pq->timeout >= XFRM_QUEUE_TMO_MAX) - goto purge_queue; - - pq->timeout = pq->timeout << 1; - if (!mod_timer(&pq->hold_timer, jiffies + pq->timeout)) - xfrm_pol_hold(pol); - goto out; - } - - dst_release(dst); - - __skb_queue_head_init(&list); - - spin_lock(&pq->hold_queue.lock); - pq->timeout = 0; - skb_queue_splice_init(&pq->hold_queue, &list); - spin_unlock(&pq->hold_queue.lock); - - while (!skb_queue_empty(&list)) { - skb = __skb_dequeue(&list); - - xfrm_decode_session(skb, &fl, skb_dst(skb)->ops->family); - dst_hold(skb_dst(skb)->path); - dst = xfrm_lookup(net, skb_dst(skb)->path, &fl, skb->sk, 0); - if (IS_ERR(dst)) { - kfree_skb(skb); - continue; - } - - nf_reset(skb); - skb_dst_drop(skb); - skb_dst_set(skb, dst); - - dst_output(net, skb->sk, skb); - } - -out: - xfrm_pol_put(pol); - return; - -purge_queue: - pq->timeout = 0; - skb_queue_purge(&pq->hold_queue); - xfrm_pol_put(pol); -} - -static int xdst_queue_output(struct net *net, struct sock *sk, struct sk_buff *skb) -{ - unsigned long sched_next; - struct dst_entry *dst = skb_dst(skb); - struct xfrm_dst *xdst = (struct xfrm_dst *) dst; - struct xfrm_policy *pol = xdst->pols[0]; - struct xfrm_policy_queue *pq = &pol->polq; - - if (unlikely(skb_fclone_busy(sk, skb))) { - kfree_skb(skb); - return 0; - } - - if (pq->hold_queue.qlen > XFRM_MAX_QUEUE_LEN) { - kfree_skb(skb); - return -EAGAIN; - } - - skb_dst_force(skb); - - spin_lock_bh(&pq->hold_queue.lock); - - if (!pq->timeout) - pq->timeout = XFRM_QUEUE_TMO_MIN; - - sched_next = jiffies + pq->timeout; - - if (del_timer(&pq->hold_timer)) { - if (time_before(pq->hold_timer.expires, sched_next)) - sched_next = pq->hold_timer.expires; - xfrm_pol_put(pol); - } - - __skb_queue_tail(&pq->hold_queue, skb); - if (!mod_timer(&pq->hold_timer, sched_next)) - xfrm_pol_hold(pol); - - spin_unlock_bh(&pq->hold_queue.lock); - - return 0; -} - -static struct xfrm_dst *xfrm_create_dummy_bundle(struct net *net, - struct xfrm_flo *xflo, - const struct flowi *fl, - int num_xfrms, - u16 family) -{ - int err; - struct net_device *dev; - struct dst_entry *dst; - struct dst_entry *dst1; - struct xfrm_dst *xdst; - - xdst = xfrm_alloc_dst(net, family); - if (IS_ERR(xdst)) - return xdst; - - if (!(xflo->flags & XFRM_LOOKUP_QUEUE) || - net->xfrm.sysctl_larval_drop || - num_xfrms <= 0) - return xdst; - - dst = xflo->dst_orig; - dst1 = &xdst->u.dst; - dst_hold(dst); - xdst->route = dst; - - dst_copy_metrics(dst1, dst); - - dst1->obsolete = DST_OBSOLETE_FORCE_CHK; - dst1->flags |= DST_HOST | DST_XFRM_QUEUE; - dst1->lastuse = jiffies; - - dst1->input = dst_discard; - dst1->output = xdst_queue_output; - - dst_hold(dst); - dst1->child = dst; - dst1->path = dst; - - xfrm_init_path((struct xfrm_dst *)dst1, dst, 0); - - err = -ENODEV; - dev = dst->dev; - if (!dev) - goto free_dst; - - err = xfrm_fill_dst(xdst, dev, fl); - if (err) - goto free_dst; - -out: - return xdst; - -free_dst: - dst_release(dst1); - xdst = ERR_PTR(err); - goto out; -} - -static struct flow_cache_object * -xfrm_bundle_lookup(struct net *net, const struct flowi *fl, u16 family, u8 dir, - struct flow_cache_object *oldflo, void *ctx) -{ - struct xfrm_flo *xflo = (struct xfrm_flo *)ctx; - struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; - struct xfrm_dst *xdst, *new_xdst; - int num_pols = 0, num_xfrms = 0, i, err, pol_dead; - - /* Check if the policies from old bundle are usable */ - xdst = NULL; - if (oldflo) { - xdst = container_of(oldflo, struct xfrm_dst, flo); - num_pols = xdst->num_pols; - num_xfrms = xdst->num_xfrms; - pol_dead = 0; - for (i = 0; i < num_pols; i++) { - pols[i] = xdst->pols[i]; - pol_dead |= pols[i]->walk.dead; - } - if (pol_dead) { - dst_free(&xdst->u.dst); - xdst = NULL; - num_pols = 0; - num_xfrms = 0; - oldflo = NULL; - } - } - - /* Resolve policies to use if we couldn't get them from - * previous cache entry */ - if (xdst == NULL) { - num_pols = 1; - pols[0] = __xfrm_policy_lookup(net, fl, family, - flow_to_policy_dir(dir)); - err = xfrm_expand_policies(fl, family, pols, - &num_pols, &num_xfrms); - if (err < 0) - goto inc_error; - if (num_pols == 0) - return NULL; - if (num_xfrms <= 0) - goto make_dummy_bundle; - } - - new_xdst = xfrm_resolve_and_create_bundle(pols, num_pols, fl, family, - xflo->dst_orig); - if (IS_ERR(new_xdst)) { - err = PTR_ERR(new_xdst); - if (err != -EAGAIN) - goto error; - if (oldflo == NULL) - goto make_dummy_bundle; - dst_hold(&xdst->u.dst); - return oldflo; - } else if (new_xdst == NULL) { - num_xfrms = 0; - if (oldflo == NULL) - goto make_dummy_bundle; - xdst->num_xfrms = 0; - dst_hold(&xdst->u.dst); - return oldflo; - } - - /* Kill the previous bundle */ - if (xdst) { - /* The policies were stolen for newly generated bundle */ - xdst->num_pols = 0; - dst_free(&xdst->u.dst); - } - - /* Flow cache does not have reference, it dst_free()'s, - * but we do need to return one reference for original caller */ - dst_hold(&new_xdst->u.dst); - return &new_xdst->flo; - -make_dummy_bundle: - /* We found policies, but there's no bundles to instantiate: - * either because the policy blocks, has no transformations or - * we could not build template (no xfrm_states).*/ - xdst = xfrm_create_dummy_bundle(net, xflo, fl, num_xfrms, family); - if (IS_ERR(xdst)) { - xfrm_pols_put(pols, num_pols); - return ERR_CAST(xdst); - } - xdst->num_pols = num_pols; - xdst->num_xfrms = num_xfrms; - memcpy(xdst->pols, pols, sizeof(struct xfrm_policy *) * num_pols); - - dst_hold(&xdst->u.dst); - return &xdst->flo; - -inc_error: - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR); -error: - if (xdst != NULL) - dst_free(&xdst->u.dst); - else - xfrm_pols_put(pols, num_pols); - return ERR_PTR(err); -} - -static struct dst_entry *make_blackhole(struct net *net, u16 family, - struct dst_entry *dst_orig) -{ - struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); - struct dst_entry *ret; - - if (!afinfo) { - dst_release(dst_orig); - return ERR_PTR(-EINVAL); - } else { - ret = afinfo->blackhole_route(net, dst_orig); - } - xfrm_policy_put_afinfo(afinfo); - - return ret; -} - -/* Main function: finds/creates a bundle for given flow. - * - * At the moment we eat a raw IP route. Mostly to speed up lookups - * on interfaces with disabled IPsec. - */ -struct dst_entry *xfrm_lookup(struct net *net, struct dst_entry *dst_orig, - const struct flowi *fl, - const struct sock *sk, int flags) -{ - struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; - struct flow_cache_object *flo; - struct xfrm_dst *xdst; - struct dst_entry *dst, *route; - u16 family = dst_orig->ops->family; - u8 dir = policy_to_flow_dir(XFRM_POLICY_OUT); - int i, err, num_pols, num_xfrms = 0, drop_pols = 0; - - dst = NULL; - xdst = NULL; - route = NULL; - - sk = sk_const_to_full_sk(sk); - if (sk && sk->sk_policy[XFRM_POLICY_OUT]) { - num_pols = 1; - pols[0] = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); - err = xfrm_expand_policies(fl, family, pols, - &num_pols, &num_xfrms); - if (err < 0) - goto dropdst; - - if (num_pols) { - if (num_xfrms <= 0) { - drop_pols = num_pols; - goto no_transform; - } - - xdst = xfrm_resolve_and_create_bundle( - pols, num_pols, fl, - family, dst_orig); - if (IS_ERR(xdst)) { - xfrm_pols_put(pols, num_pols); - err = PTR_ERR(xdst); - goto dropdst; - } else if (xdst == NULL) { - num_xfrms = 0; - drop_pols = num_pols; - goto no_transform; - } - - dst_hold(&xdst->u.dst); - xdst->u.dst.flags |= DST_NOCACHE; - route = xdst->route; - } - } - - if (xdst == NULL) { - struct xfrm_flo xflo; - - xflo.dst_orig = dst_orig; - xflo.flags = flags; - - /* To accelerate a bit... */ - if ((dst_orig->flags & DST_NOXFRM) || - !net->xfrm.policy_count[XFRM_POLICY_OUT]) - goto nopol; - - flo = flow_cache_lookup(net, fl, family, dir, - xfrm_bundle_lookup, &xflo); - if (flo == NULL) - goto nopol; - if (IS_ERR(flo)) { - err = PTR_ERR(flo); - goto dropdst; - } - xdst = container_of(flo, struct xfrm_dst, flo); - - num_pols = xdst->num_pols; - num_xfrms = xdst->num_xfrms; - memcpy(pols, xdst->pols, sizeof(struct xfrm_policy *) * num_pols); - route = xdst->route; - } - - dst = &xdst->u.dst; - if (route == NULL && num_xfrms > 0) { - /* The only case when xfrm_bundle_lookup() returns a - * bundle with null route, is when the template could - * not be resolved. It means policies are there, but - * bundle could not be created, since we don't yet - * have the xfrm_state's. We need to wait for KM to - * negotiate new SA's or bail out with error.*/ - if (net->xfrm.sysctl_larval_drop) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); - err = -EREMOTE; - goto error; - } - - err = -EAGAIN; - - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); - goto error; - } - -no_transform: - if (num_pols == 0) - goto nopol; - - if ((flags & XFRM_LOOKUP_ICMP) && - !(pols[0]->flags & XFRM_POLICY_ICMP)) { - err = -ENOENT; - goto error; - } - - for (i = 0; i < num_pols; i++) - pols[i]->curlft.use_time = get_seconds(); - - if (num_xfrms < 0) { - /* Prohibit the flow */ - XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLBLOCK); - err = -EPERM; - goto error; - } else if (num_xfrms > 0) { - /* Flow transformed */ - dst_release(dst_orig); - } else { - /* Flow passes untransformed */ - dst_release(dst); - dst = dst_orig; - } -ok: - xfrm_pols_put(pols, drop_pols); - if (dst && dst->xfrm && - dst->xfrm->props.mode == XFRM_MODE_TUNNEL) - dst->flags |= DST_XFRM_TUNNEL; - return dst; - -nopol: - if (!(flags & XFRM_LOOKUP_ICMP)) { - dst = dst_orig; - goto ok; - } - err = -ENOENT; -error: - dst_release(dst); -dropdst: - if (!(flags & XFRM_LOOKUP_KEEP_DST_REF)) - dst_release(dst_orig); - xfrm_pols_put(pols, drop_pols); - return ERR_PTR(err); -} -EXPORT_SYMBOL(xfrm_lookup); - -/* Callers of xfrm_lookup_route() must ensure a call to dst_output(). - * Otherwise we may send out blackholed packets. - */ -struct dst_entry *xfrm_lookup_route(struct net *net, struct dst_entry *dst_orig, - const struct flowi *fl, - const struct sock *sk, int flags) -{ - struct dst_entry *dst = xfrm_lookup(net, dst_orig, fl, sk, - flags | XFRM_LOOKUP_QUEUE | - XFRM_LOOKUP_KEEP_DST_REF); - - if (IS_ERR(dst) && PTR_ERR(dst) == -EREMOTE) - return make_blackhole(net, dst_orig->ops->family, dst_orig); - - return dst; -} -EXPORT_SYMBOL(xfrm_lookup_route); - -static inline int -xfrm_secpath_reject(int idx, struct sk_buff *skb, const struct flowi *fl) -{ - struct xfrm_state *x; - - if (!skb->sp || idx < 0 || idx >= skb->sp->len) - return 0; - x = skb->sp->xvec[idx]; - if (!x->type->reject) - return 0; - return x->type->reject(x, skb, fl); -} - -/* When skb is transformed back to its "native" form, we have to - * check policy restrictions. At the moment we make this in maximally - * stupid way. Shame on me. :-) Of course, connected sockets must - * have policy cached at them. - */ - -static inline int -xfrm_state_ok(const struct xfrm_tmpl *tmpl, const struct xfrm_state *x, - unsigned short family) -{ - if (xfrm_state_kern(x)) - return tmpl->optional && !xfrm_state_addr_cmp(tmpl, x, tmpl->encap_family); - return x->id.proto == tmpl->id.proto && - (x->id.spi == tmpl->id.spi || !tmpl->id.spi) && - (x->props.reqid == tmpl->reqid || !tmpl->reqid) && - x->props.mode == tmpl->mode && - (tmpl->allalgs || (tmpl->aalgos & (1<props.aalgo)) || - !(xfrm_id_proto_match(tmpl->id.proto, IPSEC_PROTO_ANY))) && - !(x->props.mode != XFRM_MODE_TRANSPORT && - xfrm_state_addr_cmp(tmpl, x, family)); -} - -/* - * 0 or more than 0 is returned when validation is succeeded (either bypass - * because of optional transport mode, or next index of the mathced secpath - * state with the template. - * -1 is returned when no matching template is found. - * Otherwise "-2 - errored_index" is returned. - */ -static inline int -xfrm_policy_ok(const struct xfrm_tmpl *tmpl, const struct sec_path *sp, int start, - unsigned short family) -{ - int idx = start; - - if (tmpl->optional) { - if (tmpl->mode == XFRM_MODE_TRANSPORT) - return start; - } else - start = -1; - for (; idx < sp->len; idx++) { - if (xfrm_state_ok(tmpl, sp->xvec[idx], family)) - return ++idx; - if (sp->xvec[idx]->props.mode != XFRM_MODE_TRANSPORT) { - if (start == -1) - start = -2-idx; - break; - } - } - return start; -} - -int __xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, - unsigned int family, int reverse) -{ - struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); - int err; - - if (unlikely(afinfo == NULL)) - return -EAFNOSUPPORT; - - afinfo->decode_session(skb, fl, reverse); - err = security_xfrm_decode_session(skb, &fl->flowi_secid); - xfrm_policy_put_afinfo(afinfo); - return err; -} -EXPORT_SYMBOL(__xfrm_decode_session); - -static inline int secpath_has_nontransport(const struct sec_path *sp, int k, int *idxp) -{ - for (; k < sp->len; k++) { - if (sp->xvec[k]->props.mode != XFRM_MODE_TRANSPORT) { - *idxp = k; - return 1; - } - } - - return 0; -} - -int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, - unsigned short family) -{ - struct net *net = dev_net(skb->dev); - struct xfrm_policy *pol; - struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; - int npols = 0; - int xfrm_nr; - int pi; - int reverse; - struct flowi fl; - u8 fl_dir; - int xerr_idx = -1; - - reverse = dir & ~XFRM_POLICY_MASK; - dir &= XFRM_POLICY_MASK; - fl_dir = policy_to_flow_dir(dir); - - if (__xfrm_decode_session(skb, &fl, family, reverse) < 0) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR); - return 0; - } - - nf_nat_decode_session(skb, &fl, family); - - /* First, check used SA against their selectors. */ - if (skb->sp) { - int i; - - for (i = skb->sp->len-1; i >= 0; i--) { - struct xfrm_state *x = skb->sp->xvec[i]; - if (!xfrm_selector_match(&x->sel, &fl, family)) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH); - return 0; - } - } - } - - pol = NULL; - sk = sk_to_full_sk(sk); - if (sk && sk->sk_policy[dir]) { - pol = xfrm_sk_policy_lookup(sk, dir, &fl); - if (IS_ERR(pol)) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR); - return 0; - } - } - - if (!pol) { - struct flow_cache_object *flo; - - flo = flow_cache_lookup(net, &fl, family, fl_dir, - xfrm_policy_lookup, NULL); - if (IS_ERR_OR_NULL(flo)) - pol = ERR_CAST(flo); - else - pol = container_of(flo, struct xfrm_policy, flo); - } - - if (IS_ERR(pol)) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR); - return 0; - } - - if (!pol) { - if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) { - xfrm_secpath_reject(xerr_idx, skb, &fl); - XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOPOLS); - return 0; - } - return 1; - } - - pol->curlft.use_time = get_seconds(); - - pols[0] = pol; - npols++; -#ifdef CONFIG_XFRM_SUB_POLICY - if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) { - pols[1] = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, - &fl, family, - XFRM_POLICY_IN); - if (pols[1]) { - if (IS_ERR(pols[1])) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR); - return 0; - } - pols[1]->curlft.use_time = get_seconds(); - npols++; - } - } -#endif - - if (pol->action == XFRM_POLICY_ALLOW) { - struct sec_path *sp; - static struct sec_path dummy; - struct xfrm_tmpl *tp[XFRM_MAX_DEPTH]; - struct xfrm_tmpl *stp[XFRM_MAX_DEPTH]; - struct xfrm_tmpl **tpp = tp; - int ti = 0; - int i, k; - - if ((sp = skb->sp) == NULL) - sp = &dummy; - - for (pi = 0; pi < npols; pi++) { - if (pols[pi] != pol && - pols[pi]->action != XFRM_POLICY_ALLOW) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK); - goto reject; - } - if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR); - goto reject_error; - } - for (i = 0; i < pols[pi]->xfrm_nr; i++) - tpp[ti++] = &pols[pi]->xfrm_vec[i]; - } - xfrm_nr = ti; - if (npols > 1) { - xfrm_tmpl_sort(stp, tpp, xfrm_nr, family, net); - tpp = stp; - } - - /* For each tunnel xfrm, find the first matching tmpl. - * For each tmpl before that, find corresponding xfrm. - * Order is _important_. Later we will implement - * some barriers, but at the moment barriers - * are implied between each two transformations. - */ - for (i = xfrm_nr-1, k = 0; i >= 0; i--) { - k = xfrm_policy_ok(tpp[i], sp, k, family); - if (k < 0) { - if (k < -1) - /* "-2 - errored_index" returned */ - xerr_idx = -(2+k); - XFRM_INC_STATS(net, LINUX_MIB_XFRMINTMPLMISMATCH); - goto reject; - } - } - - if (secpath_has_nontransport(sp, k, &xerr_idx)) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMINTMPLMISMATCH); - goto reject; - } - - xfrm_pols_put(pols, npols); - return 1; - } - XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK); - -reject: - xfrm_secpath_reject(xerr_idx, skb, &fl); -reject_error: - xfrm_pols_put(pols, npols); - return 0; -} -EXPORT_SYMBOL(__xfrm_policy_check); - -int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) -{ - struct net *net = dev_net(skb->dev); - struct flowi fl; - struct dst_entry *dst; - int res = 1; - - if (xfrm_decode_session(skb, &fl, family) < 0) { - XFRM_INC_STATS(net, LINUX_MIB_XFRMFWDHDRERROR); - return 0; - } - - skb_dst_force(skb); - - dst = xfrm_lookup(net, skb_dst(skb), &fl, NULL, XFRM_LOOKUP_QUEUE); - if (IS_ERR(dst)) { - res = 0; - dst = NULL; - } - skb_dst_set(skb, dst); - return res; -} -EXPORT_SYMBOL(__xfrm_route_forward); - -/* Optimize later using cookies and generation ids. */ - -static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie) -{ - /* Code (such as __xfrm4_bundle_create()) sets dst->obsolete - * to DST_OBSOLETE_FORCE_CHK to force all XFRM destinations to - * get validated by dst_ops->check on every use. We do this - * because when a normal route referenced by an XFRM dst is - * obsoleted we do not go looking around for all parent - * referencing XFRM dsts so that we can invalidate them. It - * is just too much work. Instead we make the checks here on - * every use. For example: - * - * XFRM dst A --> IPv4 dst X - * - * X is the "xdst->route" of A (X is also the "dst->path" of A - * in this example). If X is marked obsolete, "A" will not - * notice. That's what we are validating here via the - * stale_bundle() check. - * - * When a policy's bundle is pruned, we dst_free() the XFRM - * dst which causes it's ->obsolete field to be set to - * DST_OBSOLETE_DEAD. If an XFRM dst has been pruned like - * this, we want to force a new route lookup. - */ - if (dst->obsolete < 0 && !stale_bundle(dst)) - return dst; - - return NULL; -} - -static int stale_bundle(struct dst_entry *dst) -{ - return !xfrm_bundle_ok((struct xfrm_dst *)dst); -} - -void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev) -{ - while ((dst = dst->child) && dst->xfrm && dst->dev == dev) { - dst->dev = dev_net(dev)->loopback_dev; - dev_hold(dst->dev); - dev_put(dev); - } -} -EXPORT_SYMBOL(xfrm_dst_ifdown); - -static void xfrm_link_failure(struct sk_buff *skb) -{ - /* Impossible. Such dst must be popped before reaches point of failure. */ -} - -static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst) -{ - if (dst) { - if (dst->obsolete) { - dst_release(dst); - dst = NULL; - } - } - return dst; -} - -void xfrm_garbage_collect(struct net *net) -{ - flow_cache_flush(net); -} -EXPORT_SYMBOL(xfrm_garbage_collect); - -static void xfrm_garbage_collect_deferred(struct net *net) -{ - flow_cache_flush_deferred(net); -} - -static void xfrm_init_pmtu(struct dst_entry *dst) -{ - do { - struct xfrm_dst *xdst = (struct xfrm_dst *)dst; - u32 pmtu, route_mtu_cached; - - pmtu = dst_mtu(dst->child); - xdst->child_mtu_cached = pmtu; - - pmtu = xfrm_state_mtu(dst->xfrm, pmtu); - - route_mtu_cached = dst_mtu(xdst->route); - xdst->route_mtu_cached = route_mtu_cached; - - if (pmtu > route_mtu_cached) - pmtu = route_mtu_cached; - - dst_metric_set(dst, RTAX_MTU, pmtu); - } while ((dst = dst->next)); -} - -/* Check that the bundle accepts the flow and its components are - * still valid. - */ - -static int xfrm_bundle_ok(struct xfrm_dst *first) -{ - struct dst_entry *dst = &first->u.dst; - struct xfrm_dst *last; - u32 mtu; - - if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) || - (dst->dev && !netif_running(dst->dev))) - return 0; - - if (dst->flags & DST_XFRM_QUEUE) - return 1; - - last = NULL; - - do { - struct xfrm_dst *xdst = (struct xfrm_dst *)dst; - - if (dst->xfrm->km.state != XFRM_STATE_VALID) - return 0; - if (xdst->xfrm_genid != dst->xfrm->genid) - return 0; - if (xdst->num_pols > 0 && - xdst->policy_genid != atomic_read(&xdst->pols[0]->genid)) - return 0; - - mtu = dst_mtu(dst->child); - if (xdst->child_mtu_cached != mtu) { - last = xdst; - xdst->child_mtu_cached = mtu; - } - - if (!dst_check(xdst->route, xdst->route_cookie)) - return 0; - mtu = dst_mtu(xdst->route); - if (xdst->route_mtu_cached != mtu) { - last = xdst; - xdst->route_mtu_cached = mtu; - } - - dst = dst->child; - } while (dst->xfrm); - - if (likely(!last)) - return 1; - - mtu = last->child_mtu_cached; - for (;;) { - dst = &last->u.dst; - - mtu = xfrm_state_mtu(dst->xfrm, mtu); - if (mtu > last->route_mtu_cached) - mtu = last->route_mtu_cached; - dst_metric_set(dst, RTAX_MTU, mtu); - - if (last == first) - break; - - last = (struct xfrm_dst *)last->u.dst.next; - last->child_mtu_cached = mtu; - } - - return 1; -} - -static unsigned int xfrm_default_advmss(const struct dst_entry *dst) -{ - return dst_metric_advmss(dst->path); -} - -static unsigned int xfrm_mtu(const struct dst_entry *dst) -{ - unsigned int mtu = dst_metric_raw(dst, RTAX_MTU); - - return mtu ? : dst_mtu(dst->path); -} - -static struct neighbour *xfrm_neigh_lookup(const struct dst_entry *dst, - struct sk_buff *skb, - const void *daddr) -{ - return dst->path->ops->neigh_lookup(dst, skb, daddr); -} - -int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo) -{ - int err = 0; - if (unlikely(afinfo == NULL)) - return -EINVAL; - if (unlikely(afinfo->family >= NPROTO)) - return -EAFNOSUPPORT; - spin_lock(&xfrm_policy_afinfo_lock); - if (unlikely(xfrm_policy_afinfo[afinfo->family] != NULL)) - err = -EEXIST; - else { - struct dst_ops *dst_ops = afinfo->dst_ops; - if (likely(dst_ops->kmem_cachep == NULL)) - dst_ops->kmem_cachep = xfrm_dst_cache; - if (likely(dst_ops->check == NULL)) - dst_ops->check = xfrm_dst_check; - if (likely(dst_ops->default_advmss == NULL)) - dst_ops->default_advmss = xfrm_default_advmss; - if (likely(dst_ops->mtu == NULL)) - dst_ops->mtu = xfrm_mtu; - if (likely(dst_ops->negative_advice == NULL)) - dst_ops->negative_advice = xfrm_negative_advice; - if (likely(dst_ops->link_failure == NULL)) - dst_ops->link_failure = xfrm_link_failure; - if (likely(dst_ops->neigh_lookup == NULL)) - dst_ops->neigh_lookup = xfrm_neigh_lookup; - if (likely(afinfo->garbage_collect == NULL)) - afinfo->garbage_collect = xfrm_garbage_collect_deferred; - rcu_assign_pointer(xfrm_policy_afinfo[afinfo->family], afinfo); - } - spin_unlock(&xfrm_policy_afinfo_lock); - - return err; -} -EXPORT_SYMBOL(xfrm_policy_register_afinfo); - -int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo) -{ - int err = 0; - if (unlikely(afinfo == NULL)) - return -EINVAL; - if (unlikely(afinfo->family >= NPROTO)) - return -EAFNOSUPPORT; - spin_lock(&xfrm_policy_afinfo_lock); - if (likely(xfrm_policy_afinfo[afinfo->family] != NULL)) { - if (unlikely(xfrm_policy_afinfo[afinfo->family] != afinfo)) - err = -EINVAL; - else - RCU_INIT_POINTER(xfrm_policy_afinfo[afinfo->family], - NULL); - } - spin_unlock(&xfrm_policy_afinfo_lock); - if (!err) { - struct dst_ops *dst_ops = afinfo->dst_ops; - - synchronize_rcu(); - - dst_ops->kmem_cachep = NULL; - dst_ops->check = NULL; - dst_ops->negative_advice = NULL; - dst_ops->link_failure = NULL; - afinfo->garbage_collect = NULL; - } - return err; -} -EXPORT_SYMBOL(xfrm_policy_unregister_afinfo); - -static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr) -{ - struct net_device *dev = netdev_notifier_info_to_dev(ptr); - - switch (event) { - case NETDEV_DOWN: - xfrm_garbage_collect(dev_net(dev)); - } - return NOTIFY_DONE; -} - -static struct notifier_block xfrm_dev_notifier = { - .notifier_call = xfrm_dev_event, -}; - -#ifdef CONFIG_XFRM_STATISTICS -static int __net_init xfrm_statistics_init(struct net *net) -{ - int rv; - net->mib.xfrm_statistics = alloc_percpu(struct linux_xfrm_mib); - if (!net->mib.xfrm_statistics) - return -ENOMEM; - rv = xfrm_proc_init(net); - if (rv < 0) - free_percpu(net->mib.xfrm_statistics); - return rv; -} - -static void xfrm_statistics_fini(struct net *net) -{ - xfrm_proc_fini(net); - free_percpu(net->mib.xfrm_statistics); -} -#else -static int __net_init xfrm_statistics_init(struct net *net) -{ - return 0; -} - -static void xfrm_statistics_fini(struct net *net) -{ -} -#endif - -static int __net_init xfrm_policy_init(struct net *net) -{ - unsigned int hmask, sz; - int dir; - - if (net_eq(net, &init_net)) - xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache", - sizeof(struct xfrm_dst), - 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, - NULL); - - hmask = 8 - 1; - sz = (hmask+1) * sizeof(struct hlist_head); - - net->xfrm.policy_byidx = xfrm_hash_alloc(sz); - if (!net->xfrm.policy_byidx) - goto out_byidx; - net->xfrm.policy_idx_hmask = hmask; - - for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { - struct xfrm_policy_hash *htab; - - net->xfrm.policy_count[dir] = 0; - net->xfrm.policy_count[XFRM_POLICY_MAX + dir] = 0; - INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]); - - htab = &net->xfrm.policy_bydst[dir]; - htab->table = xfrm_hash_alloc(sz); - if (!htab->table) - goto out_bydst; - htab->hmask = hmask; - htab->dbits4 = 32; - htab->sbits4 = 32; - htab->dbits6 = 128; - htab->sbits6 = 128; - } - net->xfrm.policy_hthresh.lbits4 = 32; - net->xfrm.policy_hthresh.rbits4 = 32; - net->xfrm.policy_hthresh.lbits6 = 128; - net->xfrm.policy_hthresh.rbits6 = 128; - - seqlock_init(&net->xfrm.policy_hthresh.lock); - - INIT_LIST_HEAD(&net->xfrm.policy_all); - INIT_WORK(&net->xfrm.policy_hash_work, xfrm_hash_resize); - INIT_WORK(&net->xfrm.policy_hthresh.work, xfrm_hash_rebuild); - if (net_eq(net, &init_net)) - register_netdevice_notifier(&xfrm_dev_notifier); - return 0; - -out_bydst: - for (dir--; dir >= 0; dir--) { - struct xfrm_policy_hash *htab; - - htab = &net->xfrm.policy_bydst[dir]; - xfrm_hash_free(htab->table, sz); - } - xfrm_hash_free(net->xfrm.policy_byidx, sz); -out_byidx: - return -ENOMEM; -} - -static void xfrm_policy_fini(struct net *net) -{ - unsigned int sz; - int dir; - - flush_work(&net->xfrm.policy_hash_work); -#ifdef CONFIG_XFRM_SUB_POLICY - xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, false); -#endif - xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, false); - - WARN_ON(!list_empty(&net->xfrm.policy_all)); - - for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { - struct xfrm_policy_hash *htab; - - WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir])); - - htab = &net->xfrm.policy_bydst[dir]; - sz = (htab->hmask + 1) * sizeof(struct hlist_head); - WARN_ON(!hlist_empty(htab->table)); - xfrm_hash_free(htab->table, sz); - } - - sz = (net->xfrm.policy_idx_hmask + 1) * sizeof(struct hlist_head); - WARN_ON(!hlist_empty(net->xfrm.policy_byidx)); - xfrm_hash_free(net->xfrm.policy_byidx, sz); -} - -static int __net_init xfrm_net_init(struct net *net) -{ - int rv; - - rv = xfrm_statistics_init(net); - if (rv < 0) - goto out_statistics; - rv = xfrm_state_init(net); - if (rv < 0) - goto out_state; - rv = xfrm_policy_init(net); - if (rv < 0) - goto out_policy; - rv = xfrm_sysctl_init(net); - if (rv < 0) - goto out_sysctl; - rv = flow_cache_init(net); - if (rv < 0) - goto out; - - /* Initialize the per-net locks here */ - spin_lock_init(&net->xfrm.xfrm_state_lock); - spin_lock_init(&net->xfrm.xfrm_policy_lock); - mutex_init(&net->xfrm.xfrm_cfg_mutex); - - return 0; - -out: - xfrm_sysctl_fini(net); -out_sysctl: - xfrm_policy_fini(net); -out_policy: - xfrm_state_fini(net); -out_state: - xfrm_statistics_fini(net); -out_statistics: - return rv; -} - -static void __net_exit xfrm_net_exit(struct net *net) -{ - flow_cache_fini(net); - xfrm_sysctl_fini(net); - xfrm_policy_fini(net); - xfrm_state_fini(net); - xfrm_statistics_fini(net); -} - -static struct pernet_operations __net_initdata xfrm_net_ops = { - .init = xfrm_net_init, - .exit = xfrm_net_exit, -}; - -void __init xfrm_init(void) -{ - register_pernet_subsys(&xfrm_net_ops); - seqcount_init(&xfrm_policy_hash_generation); - xfrm_input_init(); -} - -#ifdef CONFIG_AUDITSYSCALL -static void xfrm_audit_common_policyinfo(struct xfrm_policy *xp, - struct audit_buffer *audit_buf) -{ - struct xfrm_sec_ctx *ctx = xp->security; - struct xfrm_selector *sel = &xp->selector; - - if (ctx) - audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", - ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str); - - switch (sel->family) { - case AF_INET: - audit_log_format(audit_buf, " src=%pI4", &sel->saddr.a4); - if (sel->prefixlen_s != 32) - audit_log_format(audit_buf, " src_prefixlen=%d", - sel->prefixlen_s); - audit_log_format(audit_buf, " dst=%pI4", &sel->daddr.a4); - if (sel->prefixlen_d != 32) - audit_log_format(audit_buf, " dst_prefixlen=%d", - sel->prefixlen_d); - break; - case AF_INET6: - audit_log_format(audit_buf, " src=%pI6", sel->saddr.a6); - if (sel->prefixlen_s != 128) - audit_log_format(audit_buf, " src_prefixlen=%d", - sel->prefixlen_s); - audit_log_format(audit_buf, " dst=%pI6", sel->daddr.a6); - if (sel->prefixlen_d != 128) - audit_log_format(audit_buf, " dst_prefixlen=%d", - sel->prefixlen_d); - break; - } -} - -void xfrm_audit_policy_add(struct xfrm_policy *xp, int result, bool task_valid) -{ - struct audit_buffer *audit_buf; - - audit_buf = xfrm_audit_start("SPD-add"); - if (audit_buf == NULL) - return; - xfrm_audit_helper_usrinfo(task_valid, audit_buf); - audit_log_format(audit_buf, " res=%u", result); - xfrm_audit_common_policyinfo(xp, audit_buf); - audit_log_end(audit_buf); -} -EXPORT_SYMBOL_GPL(xfrm_audit_policy_add); - -void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result, - bool task_valid) -{ - struct audit_buffer *audit_buf; - - audit_buf = xfrm_audit_start("SPD-delete"); - if (audit_buf == NULL) - return; - xfrm_audit_helper_usrinfo(task_valid, audit_buf); - audit_log_format(audit_buf, " res=%u", result); - xfrm_audit_common_policyinfo(xp, audit_buf); - audit_log_end(audit_buf); -} -EXPORT_SYMBOL_GPL(xfrm_audit_policy_delete); -#endif - -#ifdef CONFIG_XFRM_MIGRATE -static bool xfrm_migrate_selector_match(const struct xfrm_selector *sel_cmp, - const struct xfrm_selector *sel_tgt) -{ - if (sel_cmp->proto == IPSEC_ULPROTO_ANY) { - if (sel_tgt->family == sel_cmp->family && - xfrm_addr_equal(&sel_tgt->daddr, &sel_cmp->daddr, - sel_cmp->family) && - xfrm_addr_equal(&sel_tgt->saddr, &sel_cmp->saddr, - sel_cmp->family) && - sel_tgt->prefixlen_d == sel_cmp->prefixlen_d && - sel_tgt->prefixlen_s == sel_cmp->prefixlen_s) { - return true; - } - } else { - if (memcmp(sel_tgt, sel_cmp, sizeof(*sel_tgt)) == 0) { - return true; - } - } - return false; -} - -static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *sel, - u8 dir, u8 type, struct net *net) -{ - struct xfrm_policy *pol, *ret = NULL; - struct hlist_head *chain; - u32 priority = ~0U; - - spin_lock_bh(&net->xfrm.xfrm_policy_lock); - chain = policy_hash_direct(net, &sel->daddr, &sel->saddr, sel->family, dir); - hlist_for_each_entry(pol, chain, bydst) { - if (xfrm_migrate_selector_match(sel, &pol->selector) && - pol->type == type) { - ret = pol; - priority = ret->priority; - break; - } - } - chain = &net->xfrm.policy_inexact[dir]; - hlist_for_each_entry(pol, chain, bydst) { - if ((pol->priority >= priority) && ret) - break; - - if (xfrm_migrate_selector_match(sel, &pol->selector) && - pol->type == type) { - ret = pol; - break; - } - } - - xfrm_pol_hold(ret); - - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); - - return ret; -} - -static int migrate_tmpl_match(const struct xfrm_migrate *m, const struct xfrm_tmpl *t) -{ - int match = 0; - - if (t->mode == m->mode && t->id.proto == m->proto && - (m->reqid == 0 || t->reqid == m->reqid)) { - switch (t->mode) { - case XFRM_MODE_TUNNEL: - case XFRM_MODE_BEET: - if (xfrm_addr_equal(&t->id.daddr, &m->old_daddr, - m->old_family) && - xfrm_addr_equal(&t->saddr, &m->old_saddr, - m->old_family)) { - match = 1; - } - break; - case XFRM_MODE_TRANSPORT: - /* in case of transport mode, template does not store - any IP addresses, hence we just compare mode and - protocol */ - match = 1; - break; - default: - break; - } - } - return match; -} - -/* update endpoint address(es) of template(s) */ -static int xfrm_policy_migrate(struct xfrm_policy *pol, - struct xfrm_migrate *m, int num_migrate) -{ - struct xfrm_migrate *mp; - int i, j, n = 0; - - write_lock_bh(&pol->lock); - if (unlikely(pol->walk.dead)) { - /* target policy has been deleted */ - write_unlock_bh(&pol->lock); - return -ENOENT; - } - - for (i = 0; i < pol->xfrm_nr; i++) { - for (j = 0, mp = m; j < num_migrate; j++, mp++) { - if (!migrate_tmpl_match(mp, &pol->xfrm_vec[i])) - continue; - n++; - if (pol->xfrm_vec[i].mode != XFRM_MODE_TUNNEL && - pol->xfrm_vec[i].mode != XFRM_MODE_BEET) - continue; - /* update endpoints */ - memcpy(&pol->xfrm_vec[i].id.daddr, &mp->new_daddr, - sizeof(pol->xfrm_vec[i].id.daddr)); - memcpy(&pol->xfrm_vec[i].saddr, &mp->new_saddr, - sizeof(pol->xfrm_vec[i].saddr)); - pol->xfrm_vec[i].encap_family = mp->new_family; - /* flush bundles */ - atomic_inc(&pol->genid); - } - } - - write_unlock_bh(&pol->lock); - - if (!n) - return -ENODATA; - - return 0; -} - -static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate) -{ - int i, j; - - if (num_migrate < 1 || num_migrate > XFRM_MAX_DEPTH) - return -EINVAL; - - for (i = 0; i < num_migrate; i++) { - if (xfrm_addr_equal(&m[i].old_daddr, &m[i].new_daddr, - m[i].old_family) && - xfrm_addr_equal(&m[i].old_saddr, &m[i].new_saddr, - m[i].old_family)) - return -EINVAL; - if (xfrm_addr_any(&m[i].new_daddr, m[i].new_family) || - xfrm_addr_any(&m[i].new_saddr, m[i].new_family)) - return -EINVAL; - - /* check if there is any duplicated entry */ - for (j = i + 1; j < num_migrate; j++) { - if (!memcmp(&m[i].old_daddr, &m[j].old_daddr, - sizeof(m[i].old_daddr)) && - !memcmp(&m[i].old_saddr, &m[j].old_saddr, - sizeof(m[i].old_saddr)) && - m[i].proto == m[j].proto && - m[i].mode == m[j].mode && - m[i].reqid == m[j].reqid && - m[i].old_family == m[j].old_family) - return -EINVAL; - } - } - - return 0; -} - -int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, - struct xfrm_migrate *m, int num_migrate, - struct xfrm_kmaddress *k, struct net *net) -{ - int i, err, nx_cur = 0, nx_new = 0; - struct xfrm_policy *pol = NULL; - struct xfrm_state *x, *xc; - struct xfrm_state *x_cur[XFRM_MAX_DEPTH]; - struct xfrm_state *x_new[XFRM_MAX_DEPTH]; - struct xfrm_migrate *mp; - - if ((err = xfrm_migrate_check(m, num_migrate)) < 0) - goto out; - - /* Stage 1 - find policy */ - if ((pol = xfrm_migrate_policy_find(sel, dir, type, net)) == NULL) { - err = -ENOENT; - goto out; - } - - /* Stage 2 - find and update state(s) */ - for (i = 0, mp = m; i < num_migrate; i++, mp++) { - if ((x = xfrm_migrate_state_find(mp, net))) { - x_cur[nx_cur] = x; - nx_cur++; - if ((xc = xfrm_state_migrate(x, mp))) { - x_new[nx_new] = xc; - nx_new++; - } else { - err = -ENODATA; - goto restore_state; - } - } - } - - /* Stage 3 - update policy */ - if ((err = xfrm_policy_migrate(pol, m, num_migrate)) < 0) - goto restore_state; - - /* Stage 4 - delete old state(s) */ - if (nx_cur) { - xfrm_states_put(x_cur, nx_cur); - xfrm_states_delete(x_cur, nx_cur); - } - - /* Stage 5 - announce */ - km_migrate(sel, dir, type, m, num_migrate, k); - - xfrm_pol_put(pol); - - return 0; -out: - return err; - -restore_state: - if (pol) - xfrm_pol_put(pol); - if (nx_cur) - xfrm_states_put(x_cur, nx_cur); - if (nx_new) - xfrm_states_delete(x_new, nx_new); - - return err; -} -EXPORT_SYMBOL(xfrm_migrate); -#endif diff --git a/src/linux/net/xfrm/xfrm_replay.c b/src/linux/net/xfrm/xfrm_replay.c deleted file mode 100644 index cdc2e2e..0000000 --- a/src/linux/net/xfrm/xfrm_replay.c +++ /dev/null @@ -1,605 +0,0 @@ -/* - * xfrm_replay.c - xfrm replay detection, derived from xfrm_state.c. - * - * Copyright (C) 2010 secunet Security Networks AG - * Copyright (C) 2010 Steffen Klassert - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include -#include - -u32 xfrm_replay_seqhi(struct xfrm_state *x, __be32 net_seq) -{ - u32 seq, seq_hi, bottom; - struct xfrm_replay_state_esn *replay_esn = x->replay_esn; - - if (!(x->props.flags & XFRM_STATE_ESN)) - return 0; - - seq = ntohl(net_seq); - seq_hi = replay_esn->seq_hi; - bottom = replay_esn->seq - replay_esn->replay_window + 1; - - if (likely(replay_esn->seq >= replay_esn->replay_window - 1)) { - /* A. same subspace */ - if (unlikely(seq < bottom)) - seq_hi++; - } else { - /* B. window spans two subspaces */ - if (unlikely(seq >= bottom)) - seq_hi--; - } - - return seq_hi; -} - -static void xfrm_replay_notify(struct xfrm_state *x, int event) -{ - struct km_event c; - /* we send notify messages in case - * 1. we updated on of the sequence numbers, and the seqno difference - * is at least x->replay_maxdiff, in this case we also update the - * timeout of our timer function - * 2. if x->replay_maxage has elapsed since last update, - * and there were changes - * - * The state structure must be locked! - */ - - switch (event) { - case XFRM_REPLAY_UPDATE: - if (!x->replay_maxdiff || - ((x->replay.seq - x->preplay.seq < x->replay_maxdiff) && - (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff))) { - if (x->xflags & XFRM_TIME_DEFER) - event = XFRM_REPLAY_TIMEOUT; - else - return; - } - - break; - - case XFRM_REPLAY_TIMEOUT: - if (memcmp(&x->replay, &x->preplay, - sizeof(struct xfrm_replay_state)) == 0) { - x->xflags |= XFRM_TIME_DEFER; - return; - } - - break; - } - - memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state)); - c.event = XFRM_MSG_NEWAE; - c.data.aevent = event; - km_state_notify(x, &c); - - if (x->replay_maxage && - !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) - x->xflags &= ~XFRM_TIME_DEFER; -} - -static int xfrm_replay_overflow(struct xfrm_state *x, struct sk_buff *skb) -{ - int err = 0; - struct net *net = xs_net(x); - - if (x->type->flags & XFRM_TYPE_REPLAY_PROT) { - XFRM_SKB_CB(skb)->seq.output.low = ++x->replay.oseq; - XFRM_SKB_CB(skb)->seq.output.hi = 0; - if (unlikely(x->replay.oseq == 0)) { - x->replay.oseq--; - xfrm_audit_state_replay_overflow(x, skb); - err = -EOVERFLOW; - - return err; - } - if (xfrm_aevent_is_on(net)) - x->repl->notify(x, XFRM_REPLAY_UPDATE); - } - - return err; -} - -static int xfrm_replay_check(struct xfrm_state *x, - struct sk_buff *skb, __be32 net_seq) -{ - u32 diff; - u32 seq = ntohl(net_seq); - - if (!x->props.replay_window) - return 0; - - if (unlikely(seq == 0)) - goto err; - - if (likely(seq > x->replay.seq)) - return 0; - - diff = x->replay.seq - seq; - if (diff >= x->props.replay_window) { - x->stats.replay_window++; - goto err; - } - - if (x->replay.bitmap & (1U << diff)) { - x->stats.replay++; - goto err; - } - return 0; - -err: - xfrm_audit_state_replay(x, skb, net_seq); - return -EINVAL; -} - -static void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq) -{ - u32 diff; - u32 seq = ntohl(net_seq); - - if (!x->props.replay_window) - return; - - if (seq > x->replay.seq) { - diff = seq - x->replay.seq; - if (diff < x->props.replay_window) - x->replay.bitmap = ((x->replay.bitmap) << diff) | 1; - else - x->replay.bitmap = 1; - x->replay.seq = seq; - } else { - diff = x->replay.seq - seq; - x->replay.bitmap |= (1U << diff); - } - - if (xfrm_aevent_is_on(xs_net(x))) - x->repl->notify(x, XFRM_REPLAY_UPDATE); -} - -static int xfrm_replay_overflow_bmp(struct xfrm_state *x, struct sk_buff *skb) -{ - int err = 0; - struct xfrm_replay_state_esn *replay_esn = x->replay_esn; - struct net *net = xs_net(x); - - if (x->type->flags & XFRM_TYPE_REPLAY_PROT) { - XFRM_SKB_CB(skb)->seq.output.low = ++replay_esn->oseq; - XFRM_SKB_CB(skb)->seq.output.hi = 0; - if (unlikely(replay_esn->oseq == 0)) { - replay_esn->oseq--; - xfrm_audit_state_replay_overflow(x, skb); - err = -EOVERFLOW; - - return err; - } - if (xfrm_aevent_is_on(net)) - x->repl->notify(x, XFRM_REPLAY_UPDATE); - } - - return err; -} - -static int xfrm_replay_check_bmp(struct xfrm_state *x, - struct sk_buff *skb, __be32 net_seq) -{ - unsigned int bitnr, nr; - struct xfrm_replay_state_esn *replay_esn = x->replay_esn; - u32 pos; - u32 seq = ntohl(net_seq); - u32 diff = replay_esn->seq - seq; - - if (!replay_esn->replay_window) - return 0; - - if (unlikely(seq == 0)) - goto err; - - if (likely(seq > replay_esn->seq)) - return 0; - - if (diff >= replay_esn->replay_window) { - x->stats.replay_window++; - goto err; - } - - pos = (replay_esn->seq - 1) % replay_esn->replay_window; - - if (pos >= diff) - bitnr = (pos - diff) % replay_esn->replay_window; - else - bitnr = replay_esn->replay_window - (diff - pos); - - nr = bitnr >> 5; - bitnr = bitnr & 0x1F; - if (replay_esn->bmp[nr] & (1U << bitnr)) - goto err_replay; - - return 0; - -err_replay: - x->stats.replay++; -err: - xfrm_audit_state_replay(x, skb, net_seq); - return -EINVAL; -} - -static void xfrm_replay_advance_bmp(struct xfrm_state *x, __be32 net_seq) -{ - unsigned int bitnr, nr, i; - u32 diff; - struct xfrm_replay_state_esn *replay_esn = x->replay_esn; - u32 seq = ntohl(net_seq); - u32 pos; - - if (!replay_esn->replay_window) - return; - - pos = (replay_esn->seq - 1) % replay_esn->replay_window; - - if (seq > replay_esn->seq) { - diff = seq - replay_esn->seq; - - if (diff < replay_esn->replay_window) { - for (i = 1; i < diff; i++) { - bitnr = (pos + i) % replay_esn->replay_window; - nr = bitnr >> 5; - bitnr = bitnr & 0x1F; - replay_esn->bmp[nr] &= ~(1U << bitnr); - } - } else { - nr = (replay_esn->replay_window - 1) >> 5; - for (i = 0; i <= nr; i++) - replay_esn->bmp[i] = 0; - } - - bitnr = (pos + diff) % replay_esn->replay_window; - replay_esn->seq = seq; - } else { - diff = replay_esn->seq - seq; - - if (pos >= diff) - bitnr = (pos - diff) % replay_esn->replay_window; - else - bitnr = replay_esn->replay_window - (diff - pos); - } - - nr = bitnr >> 5; - bitnr = bitnr & 0x1F; - replay_esn->bmp[nr] |= (1U << bitnr); - - if (xfrm_aevent_is_on(xs_net(x))) - x->repl->notify(x, XFRM_REPLAY_UPDATE); -} - -static void xfrm_replay_notify_bmp(struct xfrm_state *x, int event) -{ - struct km_event c; - struct xfrm_replay_state_esn *replay_esn = x->replay_esn; - struct xfrm_replay_state_esn *preplay_esn = x->preplay_esn; - - /* we send notify messages in case - * 1. we updated on of the sequence numbers, and the seqno difference - * is at least x->replay_maxdiff, in this case we also update the - * timeout of our timer function - * 2. if x->replay_maxage has elapsed since last update, - * and there were changes - * - * The state structure must be locked! - */ - - switch (event) { - case XFRM_REPLAY_UPDATE: - if (!x->replay_maxdiff || - ((replay_esn->seq - preplay_esn->seq < x->replay_maxdiff) && - (replay_esn->oseq - preplay_esn->oseq - < x->replay_maxdiff))) { - if (x->xflags & XFRM_TIME_DEFER) - event = XFRM_REPLAY_TIMEOUT; - else - return; - } - - break; - - case XFRM_REPLAY_TIMEOUT: - if (memcmp(x->replay_esn, x->preplay_esn, - xfrm_replay_state_esn_len(replay_esn)) == 0) { - x->xflags |= XFRM_TIME_DEFER; - return; - } - - break; - } - - memcpy(x->preplay_esn, x->replay_esn, - xfrm_replay_state_esn_len(replay_esn)); - c.event = XFRM_MSG_NEWAE; - c.data.aevent = event; - km_state_notify(x, &c); - - if (x->replay_maxage && - !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) - x->xflags &= ~XFRM_TIME_DEFER; -} - -static void xfrm_replay_notify_esn(struct xfrm_state *x, int event) -{ - u32 seq_diff, oseq_diff; - struct km_event c; - struct xfrm_replay_state_esn *replay_esn = x->replay_esn; - struct xfrm_replay_state_esn *preplay_esn = x->preplay_esn; - - /* we send notify messages in case - * 1. we updated on of the sequence numbers, and the seqno difference - * is at least x->replay_maxdiff, in this case we also update the - * timeout of our timer function - * 2. if x->replay_maxage has elapsed since last update, - * and there were changes - * - * The state structure must be locked! - */ - - switch (event) { - case XFRM_REPLAY_UPDATE: - if (x->replay_maxdiff) { - if (replay_esn->seq_hi == preplay_esn->seq_hi) - seq_diff = replay_esn->seq - preplay_esn->seq; - else - seq_diff = ~preplay_esn->seq + replay_esn->seq - + 1; - - if (replay_esn->oseq_hi == preplay_esn->oseq_hi) - oseq_diff = replay_esn->oseq - - preplay_esn->oseq; - else - oseq_diff = ~preplay_esn->oseq - + replay_esn->oseq + 1; - - if (seq_diff >= x->replay_maxdiff || - oseq_diff >= x->replay_maxdiff) - break; - } - - if (x->xflags & XFRM_TIME_DEFER) - event = XFRM_REPLAY_TIMEOUT; - else - return; - - break; - - case XFRM_REPLAY_TIMEOUT: - if (memcmp(x->replay_esn, x->preplay_esn, - xfrm_replay_state_esn_len(replay_esn)) == 0) { - x->xflags |= XFRM_TIME_DEFER; - return; - } - - break; - } - - memcpy(x->preplay_esn, x->replay_esn, - xfrm_replay_state_esn_len(replay_esn)); - c.event = XFRM_MSG_NEWAE; - c.data.aevent = event; - km_state_notify(x, &c); - - if (x->replay_maxage && - !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) - x->xflags &= ~XFRM_TIME_DEFER; -} - -static int xfrm_replay_overflow_esn(struct xfrm_state *x, struct sk_buff *skb) -{ - int err = 0; - struct xfrm_replay_state_esn *replay_esn = x->replay_esn; - struct net *net = xs_net(x); - - if (x->type->flags & XFRM_TYPE_REPLAY_PROT) { - XFRM_SKB_CB(skb)->seq.output.low = ++replay_esn->oseq; - XFRM_SKB_CB(skb)->seq.output.hi = replay_esn->oseq_hi; - - if (unlikely(replay_esn->oseq == 0)) { - XFRM_SKB_CB(skb)->seq.output.hi = ++replay_esn->oseq_hi; - - if (replay_esn->oseq_hi == 0) { - replay_esn->oseq--; - replay_esn->oseq_hi--; - xfrm_audit_state_replay_overflow(x, skb); - err = -EOVERFLOW; - - return err; - } - } - if (xfrm_aevent_is_on(net)) - x->repl->notify(x, XFRM_REPLAY_UPDATE); - } - - return err; -} - -static int xfrm_replay_check_esn(struct xfrm_state *x, - struct sk_buff *skb, __be32 net_seq) -{ - unsigned int bitnr, nr; - u32 diff; - struct xfrm_replay_state_esn *replay_esn = x->replay_esn; - u32 pos; - u32 seq = ntohl(net_seq); - u32 wsize = replay_esn->replay_window; - u32 top = replay_esn->seq; - u32 bottom = top - wsize + 1; - - if (!wsize) - return 0; - - if (unlikely(seq == 0 && replay_esn->seq_hi == 0 && - (replay_esn->seq < replay_esn->replay_window - 1))) - goto err; - - diff = top - seq; - - if (likely(top >= wsize - 1)) { - /* A. same subspace */ - if (likely(seq > top) || seq < bottom) - return 0; - } else { - /* B. window spans two subspaces */ - if (likely(seq > top && seq < bottom)) - return 0; - if (seq >= bottom) - diff = ~seq + top + 1; - } - - if (diff >= replay_esn->replay_window) { - x->stats.replay_window++; - goto err; - } - - pos = (replay_esn->seq - 1) % replay_esn->replay_window; - - if (pos >= diff) - bitnr = (pos - diff) % replay_esn->replay_window; - else - bitnr = replay_esn->replay_window - (diff - pos); - - nr = bitnr >> 5; - bitnr = bitnr & 0x1F; - if (replay_esn->bmp[nr] & (1U << bitnr)) - goto err_replay; - - return 0; - -err_replay: - x->stats.replay++; -err: - xfrm_audit_state_replay(x, skb, net_seq); - return -EINVAL; -} - -static int xfrm_replay_recheck_esn(struct xfrm_state *x, - struct sk_buff *skb, __be32 net_seq) -{ - if (unlikely(XFRM_SKB_CB(skb)->seq.input.hi != - htonl(xfrm_replay_seqhi(x, net_seq)))) { - x->stats.replay_window++; - return -EINVAL; - } - - return xfrm_replay_check_esn(x, skb, net_seq); -} - -static void xfrm_replay_advance_esn(struct xfrm_state *x, __be32 net_seq) -{ - unsigned int bitnr, nr, i; - int wrap; - u32 diff, pos, seq, seq_hi; - struct xfrm_replay_state_esn *replay_esn = x->replay_esn; - - if (!replay_esn->replay_window) - return; - - seq = ntohl(net_seq); - pos = (replay_esn->seq - 1) % replay_esn->replay_window; - seq_hi = xfrm_replay_seqhi(x, net_seq); - wrap = seq_hi - replay_esn->seq_hi; - - if ((!wrap && seq > replay_esn->seq) || wrap > 0) { - if (likely(!wrap)) - diff = seq - replay_esn->seq; - else - diff = ~replay_esn->seq + seq + 1; - - if (diff < replay_esn->replay_window) { - for (i = 1; i < diff; i++) { - bitnr = (pos + i) % replay_esn->replay_window; - nr = bitnr >> 5; - bitnr = bitnr & 0x1F; - replay_esn->bmp[nr] &= ~(1U << bitnr); - } - } else { - nr = (replay_esn->replay_window - 1) >> 5; - for (i = 0; i <= nr; i++) - replay_esn->bmp[i] = 0; - } - - bitnr = (pos + diff) % replay_esn->replay_window; - replay_esn->seq = seq; - - if (unlikely(wrap > 0)) - replay_esn->seq_hi++; - } else { - diff = replay_esn->seq - seq; - - if (pos >= diff) - bitnr = (pos - diff) % replay_esn->replay_window; - else - bitnr = replay_esn->replay_window - (diff - pos); - } - - nr = bitnr >> 5; - bitnr = bitnr & 0x1F; - replay_esn->bmp[nr] |= (1U << bitnr); - - if (xfrm_aevent_is_on(xs_net(x))) - x->repl->notify(x, XFRM_REPLAY_UPDATE); -} - -static const struct xfrm_replay xfrm_replay_legacy = { - .advance = xfrm_replay_advance, - .check = xfrm_replay_check, - .recheck = xfrm_replay_check, - .notify = xfrm_replay_notify, - .overflow = xfrm_replay_overflow, -}; - -static const struct xfrm_replay xfrm_replay_bmp = { - .advance = xfrm_replay_advance_bmp, - .check = xfrm_replay_check_bmp, - .recheck = xfrm_replay_check_bmp, - .notify = xfrm_replay_notify_bmp, - .overflow = xfrm_replay_overflow_bmp, -}; - -static const struct xfrm_replay xfrm_replay_esn = { - .advance = xfrm_replay_advance_esn, - .check = xfrm_replay_check_esn, - .recheck = xfrm_replay_recheck_esn, - .notify = xfrm_replay_notify_esn, - .overflow = xfrm_replay_overflow_esn, -}; - -int xfrm_init_replay(struct xfrm_state *x) -{ - struct xfrm_replay_state_esn *replay_esn = x->replay_esn; - - if (replay_esn) { - if (replay_esn->replay_window > - replay_esn->bmp_len * sizeof(__u32) * 8) - return -EINVAL; - - if (x->props.flags & XFRM_STATE_ESN) { - if (replay_esn->replay_window == 0) - return -EINVAL; - x->repl = &xfrm_replay_esn; - } else - x->repl = &xfrm_replay_bmp; - } else - x->repl = &xfrm_replay_legacy; - - return 0; -} -EXPORT_SYMBOL(xfrm_init_replay); diff --git a/src/linux/net/xfrm/xfrm_state.c b/src/linux/net/xfrm/xfrm_state.c deleted file mode 100644 index 419bf5d..0000000 --- a/src/linux/net/xfrm/xfrm_state.c +++ /dev/null @@ -1,2330 +0,0 @@ -/* - * xfrm_state.c - * - * Changes: - * Mitsuru KANDA @USAGI - * Kazunori MIYAZAWA @USAGI - * Kunihiro Ishiguro - * IPv6 support - * YOSHIFUJI Hideaki @USAGI - * Split up af-specific functions - * Derek Atkins - * Add UDP Encapsulation - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "xfrm_hash.h" - -#define xfrm_state_deref_prot(table, net) \ - rcu_dereference_protected((table), lockdep_is_held(&(net)->xfrm.xfrm_state_lock)) - -static void xfrm_state_gc_task(struct work_struct *work); - -/* Each xfrm_state may be linked to two tables: - - 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) - 2. Hash table by (daddr,family,reqid) to find what SAs exist for given - destination/tunnel endpoint. (output) - */ - -static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; -static __read_mostly seqcount_t xfrm_state_hash_generation = SEQCNT_ZERO(xfrm_state_hash_generation); - -static DECLARE_WORK(xfrm_state_gc_work, xfrm_state_gc_task); -static HLIST_HEAD(xfrm_state_gc_list); - -static inline bool xfrm_state_hold_rcu(struct xfrm_state __rcu *x) -{ - return atomic_inc_not_zero(&x->refcnt); -} - -static inline unsigned int xfrm_dst_hash(struct net *net, - const xfrm_address_t *daddr, - const xfrm_address_t *saddr, - u32 reqid, - unsigned short family) -{ - return __xfrm_dst_hash(daddr, saddr, reqid, family, net->xfrm.state_hmask); -} - -static inline unsigned int xfrm_src_hash(struct net *net, - const xfrm_address_t *daddr, - const xfrm_address_t *saddr, - unsigned short family) -{ - return __xfrm_src_hash(daddr, saddr, family, net->xfrm.state_hmask); -} - -static inline unsigned int -xfrm_spi_hash(struct net *net, const xfrm_address_t *daddr, - __be32 spi, u8 proto, unsigned short family) -{ - return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask); -} - -static void xfrm_hash_transfer(struct hlist_head *list, - struct hlist_head *ndsttable, - struct hlist_head *nsrctable, - struct hlist_head *nspitable, - unsigned int nhashmask) -{ - struct hlist_node *tmp; - struct xfrm_state *x; - - hlist_for_each_entry_safe(x, tmp, list, bydst) { - unsigned int h; - - h = __xfrm_dst_hash(&x->id.daddr, &x->props.saddr, - x->props.reqid, x->props.family, - nhashmask); - hlist_add_head_rcu(&x->bydst, ndsttable + h); - - h = __xfrm_src_hash(&x->id.daddr, &x->props.saddr, - x->props.family, - nhashmask); - hlist_add_head_rcu(&x->bysrc, nsrctable + h); - - if (x->id.spi) { - h = __xfrm_spi_hash(&x->id.daddr, x->id.spi, - x->id.proto, x->props.family, - nhashmask); - hlist_add_head_rcu(&x->byspi, nspitable + h); - } - } -} - -static unsigned long xfrm_hash_new_size(unsigned int state_hmask) -{ - return ((state_hmask + 1) << 1) * sizeof(struct hlist_head); -} - -static void xfrm_hash_resize(struct work_struct *work) -{ - struct net *net = container_of(work, struct net, xfrm.state_hash_work); - struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi; - unsigned long nsize, osize; - unsigned int nhashmask, ohashmask; - int i; - - nsize = xfrm_hash_new_size(net->xfrm.state_hmask); - ndst = xfrm_hash_alloc(nsize); - if (!ndst) - return; - nsrc = xfrm_hash_alloc(nsize); - if (!nsrc) { - xfrm_hash_free(ndst, nsize); - return; - } - nspi = xfrm_hash_alloc(nsize); - if (!nspi) { - xfrm_hash_free(ndst, nsize); - xfrm_hash_free(nsrc, nsize); - return; - } - - spin_lock_bh(&net->xfrm.xfrm_state_lock); - write_seqcount_begin(&xfrm_state_hash_generation); - - nhashmask = (nsize / sizeof(struct hlist_head)) - 1U; - odst = xfrm_state_deref_prot(net->xfrm.state_bydst, net); - for (i = net->xfrm.state_hmask; i >= 0; i--) - xfrm_hash_transfer(odst + i, ndst, nsrc, nspi, nhashmask); - - osrc = xfrm_state_deref_prot(net->xfrm.state_bysrc, net); - ospi = xfrm_state_deref_prot(net->xfrm.state_byspi, net); - ohashmask = net->xfrm.state_hmask; - - rcu_assign_pointer(net->xfrm.state_bydst, ndst); - rcu_assign_pointer(net->xfrm.state_bysrc, nsrc); - rcu_assign_pointer(net->xfrm.state_byspi, nspi); - net->xfrm.state_hmask = nhashmask; - - write_seqcount_end(&xfrm_state_hash_generation); - spin_unlock_bh(&net->xfrm.xfrm_state_lock); - - osize = (ohashmask + 1) * sizeof(struct hlist_head); - - synchronize_rcu(); - - xfrm_hash_free(odst, osize); - xfrm_hash_free(osrc, osize); - xfrm_hash_free(ospi, osize); -} - -static DEFINE_SPINLOCK(xfrm_state_afinfo_lock); -static struct xfrm_state_afinfo __rcu *xfrm_state_afinfo[NPROTO]; - -static DEFINE_SPINLOCK(xfrm_state_gc_lock); - -int __xfrm_state_delete(struct xfrm_state *x); - -int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); -bool km_is_alive(const struct km_event *c); -void km_state_expired(struct xfrm_state *x, int hard, u32 portid); - -static DEFINE_SPINLOCK(xfrm_type_lock); -int xfrm_register_type(const struct xfrm_type *type, unsigned short family) -{ - struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); - const struct xfrm_type **typemap; - int err = 0; - - if (unlikely(afinfo == NULL)) - return -EAFNOSUPPORT; - typemap = afinfo->type_map; - spin_lock_bh(&xfrm_type_lock); - - if (likely(typemap[type->proto] == NULL)) - typemap[type->proto] = type; - else - err = -EEXIST; - spin_unlock_bh(&xfrm_type_lock); - xfrm_state_put_afinfo(afinfo); - return err; -} -EXPORT_SYMBOL(xfrm_register_type); - -int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family) -{ - struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); - const struct xfrm_type **typemap; - int err = 0; - - if (unlikely(afinfo == NULL)) - return -EAFNOSUPPORT; - typemap = afinfo->type_map; - spin_lock_bh(&xfrm_type_lock); - - if (unlikely(typemap[type->proto] != type)) - err = -ENOENT; - else - typemap[type->proto] = NULL; - spin_unlock_bh(&xfrm_type_lock); - xfrm_state_put_afinfo(afinfo); - return err; -} -EXPORT_SYMBOL(xfrm_unregister_type); - -static const struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family) -{ - struct xfrm_state_afinfo *afinfo; - const struct xfrm_type **typemap; - const struct xfrm_type *type; - int modload_attempted = 0; - -retry: - afinfo = xfrm_state_get_afinfo(family); - if (unlikely(afinfo == NULL)) - return NULL; - typemap = afinfo->type_map; - - type = typemap[proto]; - if (unlikely(type && !try_module_get(type->owner))) - type = NULL; - if (!type && !modload_attempted) { - xfrm_state_put_afinfo(afinfo); - request_module("xfrm-type-%d-%d", family, proto); - modload_attempted = 1; - goto retry; - } - - xfrm_state_put_afinfo(afinfo); - return type; -} - -static void xfrm_put_type(const struct xfrm_type *type) -{ - module_put(type->owner); -} - -static DEFINE_SPINLOCK(xfrm_mode_lock); -int xfrm_register_mode(struct xfrm_mode *mode, int family) -{ - struct xfrm_state_afinfo *afinfo; - struct xfrm_mode **modemap; - int err; - - if (unlikely(mode->encap >= XFRM_MODE_MAX)) - return -EINVAL; - - afinfo = xfrm_state_get_afinfo(family); - if (unlikely(afinfo == NULL)) - return -EAFNOSUPPORT; - - err = -EEXIST; - modemap = afinfo->mode_map; - spin_lock_bh(&xfrm_mode_lock); - if (modemap[mode->encap]) - goto out; - - err = -ENOENT; - if (!try_module_get(afinfo->owner)) - goto out; - - mode->afinfo = afinfo; - modemap[mode->encap] = mode; - err = 0; - -out: - spin_unlock_bh(&xfrm_mode_lock); - xfrm_state_put_afinfo(afinfo); - return err; -} -EXPORT_SYMBOL(xfrm_register_mode); - -int xfrm_unregister_mode(struct xfrm_mode *mode, int family) -{ - struct xfrm_state_afinfo *afinfo; - struct xfrm_mode **modemap; - int err; - - if (unlikely(mode->encap >= XFRM_MODE_MAX)) - return -EINVAL; - - afinfo = xfrm_state_get_afinfo(family); - if (unlikely(afinfo == NULL)) - return -EAFNOSUPPORT; - - err = -ENOENT; - modemap = afinfo->mode_map; - spin_lock_bh(&xfrm_mode_lock); - if (likely(modemap[mode->encap] == mode)) { - modemap[mode->encap] = NULL; - module_put(mode->afinfo->owner); - err = 0; - } - - spin_unlock_bh(&xfrm_mode_lock); - xfrm_state_put_afinfo(afinfo); - return err; -} -EXPORT_SYMBOL(xfrm_unregister_mode); - -static struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family) -{ - struct xfrm_state_afinfo *afinfo; - struct xfrm_mode *mode; - int modload_attempted = 0; - - if (unlikely(encap >= XFRM_MODE_MAX)) - return NULL; - -retry: - afinfo = xfrm_state_get_afinfo(family); - if (unlikely(afinfo == NULL)) - return NULL; - - mode = afinfo->mode_map[encap]; - if (unlikely(mode && !try_module_get(mode->owner))) - mode = NULL; - if (!mode && !modload_attempted) { - xfrm_state_put_afinfo(afinfo); - request_module("xfrm-mode-%d-%d", family, encap); - modload_attempted = 1; - goto retry; - } - - xfrm_state_put_afinfo(afinfo); - return mode; -} - -static void xfrm_put_mode(struct xfrm_mode *mode) -{ - module_put(mode->owner); -} - -static void xfrm_state_gc_destroy(struct xfrm_state *x) -{ - tasklet_hrtimer_cancel(&x->mtimer); - del_timer_sync(&x->rtimer); - kfree(x->aead); - kfree(x->aalg); - kfree(x->ealg); - kfree(x->calg); - kfree(x->encap); - kfree(x->coaddr); - kfree(x->replay_esn); - kfree(x->preplay_esn); - if (x->inner_mode) - xfrm_put_mode(x->inner_mode); - if (x->inner_mode_iaf) - xfrm_put_mode(x->inner_mode_iaf); - if (x->outer_mode) - xfrm_put_mode(x->outer_mode); - if (x->type) { - x->type->destructor(x); - xfrm_put_type(x->type); - } - security_xfrm_state_free(x); - kfree(x); -} - -static void xfrm_state_gc_task(struct work_struct *work) -{ - struct xfrm_state *x; - struct hlist_node *tmp; - struct hlist_head gc_list; - - spin_lock_bh(&xfrm_state_gc_lock); - hlist_move_list(&xfrm_state_gc_list, &gc_list); - spin_unlock_bh(&xfrm_state_gc_lock); - - synchronize_rcu(); - - hlist_for_each_entry_safe(x, tmp, &gc_list, gclist) - xfrm_state_gc_destroy(x); -} - -static inline unsigned long make_jiffies(long secs) -{ - if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) - return MAX_SCHEDULE_TIMEOUT-1; - else - return secs*HZ; -} - -static enum hrtimer_restart xfrm_timer_handler(struct hrtimer *me) -{ - struct tasklet_hrtimer *thr = container_of(me, struct tasklet_hrtimer, timer); - struct xfrm_state *x = container_of(thr, struct xfrm_state, mtimer); - unsigned long now = get_seconds(); - long next = LONG_MAX; - int warn = 0; - int err = 0; - - spin_lock(&x->lock); - if (x->km.state == XFRM_STATE_DEAD) - goto out; - if (x->km.state == XFRM_STATE_EXPIRED) - goto expired; - if (x->lft.hard_add_expires_seconds) { - long tmo = x->lft.hard_add_expires_seconds + - x->curlft.add_time - now; - if (tmo <= 0) { - if (x->xflags & XFRM_SOFT_EXPIRE) { - /* enter hard expire without soft expire first?! - * setting a new date could trigger this. - * workarbound: fix x->curflt.add_time by below: - */ - x->curlft.add_time = now - x->saved_tmo - 1; - tmo = x->lft.hard_add_expires_seconds - x->saved_tmo; - } else - goto expired; - } - if (tmo < next) - next = tmo; - } - if (x->lft.hard_use_expires_seconds) { - long tmo = x->lft.hard_use_expires_seconds + - (x->curlft.use_time ? : now) - now; - if (tmo <= 0) - goto expired; - if (tmo < next) - next = tmo; - } - if (x->km.dying) - goto resched; - if (x->lft.soft_add_expires_seconds) { - long tmo = x->lft.soft_add_expires_seconds + - x->curlft.add_time - now; - if (tmo <= 0) { - warn = 1; - x->xflags &= ~XFRM_SOFT_EXPIRE; - } else if (tmo < next) { - next = tmo; - x->xflags |= XFRM_SOFT_EXPIRE; - x->saved_tmo = tmo; - } - } - if (x->lft.soft_use_expires_seconds) { - long tmo = x->lft.soft_use_expires_seconds + - (x->curlft.use_time ? : now) - now; - if (tmo <= 0) - warn = 1; - else if (tmo < next) - next = tmo; - } - - x->km.dying = warn; - if (warn) - km_state_expired(x, 0, 0); -resched: - if (next != LONG_MAX) { - tasklet_hrtimer_start(&x->mtimer, ktime_set(next, 0), HRTIMER_MODE_REL); - } - - goto out; - -expired: - if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) - x->km.state = XFRM_STATE_EXPIRED; - - err = __xfrm_state_delete(x); - if (!err) - km_state_expired(x, 1, 0); - - xfrm_audit_state_delete(x, err ? 0 : 1, true); - -out: - spin_unlock(&x->lock); - return HRTIMER_NORESTART; -} - -static void xfrm_replay_timer_handler(unsigned long data); - -struct xfrm_state *xfrm_state_alloc(struct net *net) -{ - struct xfrm_state *x; - - x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC); - - if (x) { - write_pnet(&x->xs_net, net); - atomic_set(&x->refcnt, 1); - atomic_set(&x->tunnel_users, 0); - INIT_LIST_HEAD(&x->km.all); - INIT_HLIST_NODE(&x->bydst); - INIT_HLIST_NODE(&x->bysrc); - INIT_HLIST_NODE(&x->byspi); - tasklet_hrtimer_init(&x->mtimer, xfrm_timer_handler, - CLOCK_BOOTTIME, HRTIMER_MODE_ABS); - setup_timer(&x->rtimer, xfrm_replay_timer_handler, - (unsigned long)x); - x->curlft.add_time = get_seconds(); - x->lft.soft_byte_limit = XFRM_INF; - x->lft.soft_packet_limit = XFRM_INF; - x->lft.hard_byte_limit = XFRM_INF; - x->lft.hard_packet_limit = XFRM_INF; - x->replay_maxage = 0; - x->replay_maxdiff = 0; - x->inner_mode = NULL; - x->inner_mode_iaf = NULL; - spin_lock_init(&x->lock); - } - return x; -} -EXPORT_SYMBOL(xfrm_state_alloc); - -void __xfrm_state_destroy(struct xfrm_state *x) -{ - WARN_ON(x->km.state != XFRM_STATE_DEAD); - - spin_lock_bh(&xfrm_state_gc_lock); - hlist_add_head(&x->gclist, &xfrm_state_gc_list); - spin_unlock_bh(&xfrm_state_gc_lock); - schedule_work(&xfrm_state_gc_work); -} -EXPORT_SYMBOL(__xfrm_state_destroy); - -int __xfrm_state_delete(struct xfrm_state *x) -{ - struct net *net = xs_net(x); - int err = -ESRCH; - - if (x->km.state != XFRM_STATE_DEAD) { - x->km.state = XFRM_STATE_DEAD; - spin_lock(&net->xfrm.xfrm_state_lock); - list_del(&x->km.all); - hlist_del_rcu(&x->bydst); - hlist_del_rcu(&x->bysrc); - if (x->id.spi) - hlist_del_rcu(&x->byspi); - net->xfrm.state_num--; - spin_unlock(&net->xfrm.xfrm_state_lock); - - /* All xfrm_state objects are created by xfrm_state_alloc. - * The xfrm_state_alloc call gives a reference, and that - * is what we are dropping here. - */ - xfrm_state_put(x); - err = 0; - } - - return err; -} -EXPORT_SYMBOL(__xfrm_state_delete); - -int xfrm_state_delete(struct xfrm_state *x) -{ - int err; - - spin_lock_bh(&x->lock); - err = __xfrm_state_delete(x); - spin_unlock_bh(&x->lock); - - return err; -} -EXPORT_SYMBOL(xfrm_state_delete); - -#ifdef CONFIG_SECURITY_NETWORK_XFRM -static inline int -xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid) -{ - int i, err = 0; - - for (i = 0; i <= net->xfrm.state_hmask; i++) { - struct xfrm_state *x; - - hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { - if (xfrm_id_proto_match(x->id.proto, proto) && - (err = security_xfrm_state_delete(x)) != 0) { - xfrm_audit_state_delete(x, 0, task_valid); - return err; - } - } - } - - return err; -} -#else -static inline int -xfrm_state_flush_secctx_check(struct net *net, u8 proto, bool task_valid) -{ - return 0; -} -#endif - -int xfrm_state_flush(struct net *net, u8 proto, bool task_valid) -{ - int i, err = 0, cnt = 0; - - spin_lock_bh(&net->xfrm.xfrm_state_lock); - err = xfrm_state_flush_secctx_check(net, proto, task_valid); - if (err) - goto out; - - err = -ESRCH; - for (i = 0; i <= net->xfrm.state_hmask; i++) { - struct xfrm_state *x; -restart: - hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { - if (!xfrm_state_kern(x) && - xfrm_id_proto_match(x->id.proto, proto)) { - xfrm_state_hold(x); - spin_unlock_bh(&net->xfrm.xfrm_state_lock); - - err = xfrm_state_delete(x); - xfrm_audit_state_delete(x, err ? 0 : 1, - task_valid); - xfrm_state_put(x); - if (!err) - cnt++; - - spin_lock_bh(&net->xfrm.xfrm_state_lock); - goto restart; - } - } - } - if (cnt) - err = 0; - -out: - spin_unlock_bh(&net->xfrm.xfrm_state_lock); - return err; -} -EXPORT_SYMBOL(xfrm_state_flush); - -void xfrm_sad_getinfo(struct net *net, struct xfrmk_sadinfo *si) -{ - spin_lock_bh(&net->xfrm.xfrm_state_lock); - si->sadcnt = net->xfrm.state_num; - si->sadhcnt = net->xfrm.state_hmask; - si->sadhmcnt = xfrm_state_hashmax; - spin_unlock_bh(&net->xfrm.xfrm_state_lock); -} -EXPORT_SYMBOL(xfrm_sad_getinfo); - -static int -xfrm_init_tempstate(struct xfrm_state *x, const struct flowi *fl, - const struct xfrm_tmpl *tmpl, - const xfrm_address_t *daddr, const xfrm_address_t *saddr, - unsigned short family) -{ - struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); - if (!afinfo) - return -1; - afinfo->init_tempsel(&x->sel, fl); - - if (family != tmpl->encap_family) { - xfrm_state_put_afinfo(afinfo); - afinfo = xfrm_state_get_afinfo(tmpl->encap_family); - if (!afinfo) - return -1; - } - afinfo->init_temprop(x, tmpl, daddr, saddr); - xfrm_state_put_afinfo(afinfo); - return 0; -} - -static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark, - const xfrm_address_t *daddr, - __be32 spi, u8 proto, - unsigned short family) -{ - unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); - struct xfrm_state *x; - - hlist_for_each_entry_rcu(x, net->xfrm.state_byspi + h, byspi) { - if (x->props.family != family || - x->id.spi != spi || - x->id.proto != proto || - !xfrm_addr_equal(&x->id.daddr, daddr, family)) - continue; - - if ((mark & x->mark.m) != x->mark.v) - continue; - if (!xfrm_state_hold_rcu(x)) - continue; - return x; - } - - return NULL; -} - -static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, u32 mark, - const xfrm_address_t *daddr, - const xfrm_address_t *saddr, - u8 proto, unsigned short family) -{ - unsigned int h = xfrm_src_hash(net, daddr, saddr, family); - struct xfrm_state *x; - - hlist_for_each_entry_rcu(x, net->xfrm.state_bysrc + h, bysrc) { - if (x->props.family != family || - x->id.proto != proto || - !xfrm_addr_equal(&x->id.daddr, daddr, family) || - !xfrm_addr_equal(&x->props.saddr, saddr, family)) - continue; - - if ((mark & x->mark.m) != x->mark.v) - continue; - if (!xfrm_state_hold_rcu(x)) - continue; - return x; - } - - return NULL; -} - -static inline struct xfrm_state * -__xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) -{ - struct net *net = xs_net(x); - u32 mark = x->mark.v & x->mark.m; - - if (use_spi) - return __xfrm_state_lookup(net, mark, &x->id.daddr, - x->id.spi, x->id.proto, family); - else - return __xfrm_state_lookup_byaddr(net, mark, - &x->id.daddr, - &x->props.saddr, - x->id.proto, family); -} - -static void xfrm_hash_grow_check(struct net *net, int have_hash_collision) -{ - if (have_hash_collision && - (net->xfrm.state_hmask + 1) < xfrm_state_hashmax && - net->xfrm.state_num > net->xfrm.state_hmask) - schedule_work(&net->xfrm.state_hash_work); -} - -static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x, - const struct flowi *fl, unsigned short family, - struct xfrm_state **best, int *acq_in_progress, - int *error) -{ - /* Resolution logic: - * 1. There is a valid state with matching selector. Done. - * 2. Valid state with inappropriate selector. Skip. - * - * Entering area of "sysdeps". - * - * 3. If state is not valid, selector is temporary, it selects - * only session which triggered previous resolution. Key - * manager will do something to install a state with proper - * selector. - */ - if (x->km.state == XFRM_STATE_VALID) { - if ((x->sel.family && - !xfrm_selector_match(&x->sel, fl, x->sel.family)) || - !security_xfrm_state_pol_flow_match(x, pol, fl)) - return; - - if (!*best || - (*best)->km.dying > x->km.dying || - ((*best)->km.dying == x->km.dying && - (*best)->curlft.add_time < x->curlft.add_time)) - *best = x; - } else if (x->km.state == XFRM_STATE_ACQ) { - *acq_in_progress = 1; - } else if (x->km.state == XFRM_STATE_ERROR || - x->km.state == XFRM_STATE_EXPIRED) { - if (xfrm_selector_match(&x->sel, fl, x->sel.family) && - security_xfrm_state_pol_flow_match(x, pol, fl)) - *error = -ESRCH; - } -} - -struct xfrm_state * -xfrm_state_find(const xfrm_address_t *daddr, const xfrm_address_t *saddr, - const struct flowi *fl, struct xfrm_tmpl *tmpl, - struct xfrm_policy *pol, int *err, - unsigned short family) -{ - static xfrm_address_t saddr_wildcard = { }; - struct net *net = xp_net(pol); - unsigned int h, h_wildcard; - struct xfrm_state *x, *x0, *to_put; - int acquire_in_progress = 0; - int error = 0; - struct xfrm_state *best = NULL; - u32 mark = pol->mark.v & pol->mark.m; - unsigned short encap_family = tmpl->encap_family; - unsigned int sequence; - struct km_event c; - - to_put = NULL; - - sequence = read_seqcount_begin(&xfrm_state_hash_generation); - - rcu_read_lock(); - h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, encap_family); - hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h, bydst) { - if (x->props.family == encap_family && - x->props.reqid == tmpl->reqid && - (mark & x->mark.m) == x->mark.v && - !(x->props.flags & XFRM_STATE_WILDRECV) && - xfrm_state_addr_check(x, daddr, saddr, encap_family) && - tmpl->mode == x->props.mode && - tmpl->id.proto == x->id.proto && - (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) - xfrm_state_look_at(pol, x, fl, encap_family, - &best, &acquire_in_progress, &error); - } - if (best || acquire_in_progress) - goto found; - - h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, encap_family); - hlist_for_each_entry_rcu(x, net->xfrm.state_bydst + h_wildcard, bydst) { - if (x->props.family == encap_family && - x->props.reqid == tmpl->reqid && - (mark & x->mark.m) == x->mark.v && - !(x->props.flags & XFRM_STATE_WILDRECV) && - xfrm_addr_equal(&x->id.daddr, daddr, encap_family) && - tmpl->mode == x->props.mode && - tmpl->id.proto == x->id.proto && - (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) - xfrm_state_look_at(pol, x, fl, encap_family, - &best, &acquire_in_progress, &error); - } - -found: - x = best; - if (!x && !error && !acquire_in_progress) { - if (tmpl->id.spi && - (x0 = __xfrm_state_lookup(net, mark, daddr, tmpl->id.spi, - tmpl->id.proto, encap_family)) != NULL) { - to_put = x0; - error = -EEXIST; - goto out; - } - - c.net = net; - /* If the KMs have no listeners (yet...), avoid allocating an SA - * for each and every packet - garbage collection might not - * handle the flood. - */ - if (!km_is_alive(&c)) { - error = -ESRCH; - goto out; - } - - x = xfrm_state_alloc(net); - if (x == NULL) { - error = -ENOMEM; - goto out; - } - /* Initialize temporary state matching only - * to current session. */ - xfrm_init_tempstate(x, fl, tmpl, daddr, saddr, family); - memcpy(&x->mark, &pol->mark, sizeof(x->mark)); - - error = security_xfrm_state_alloc_acquire(x, pol->security, fl->flowi_secid); - if (error) { - x->km.state = XFRM_STATE_DEAD; - to_put = x; - x = NULL; - goto out; - } - - if (km_query(x, tmpl, pol) == 0) { - spin_lock_bh(&net->xfrm.xfrm_state_lock); - x->km.state = XFRM_STATE_ACQ; - list_add(&x->km.all, &net->xfrm.state_all); - hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h); - h = xfrm_src_hash(net, daddr, saddr, encap_family); - hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h); - if (x->id.spi) { - h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, encap_family); - hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h); - } - x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; - tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL); - net->xfrm.state_num++; - xfrm_hash_grow_check(net, x->bydst.next != NULL); - spin_unlock_bh(&net->xfrm.xfrm_state_lock); - } else { - x->km.state = XFRM_STATE_DEAD; - to_put = x; - x = NULL; - error = -ESRCH; - } - } -out: - if (x) { - if (!xfrm_state_hold_rcu(x)) { - *err = -EAGAIN; - x = NULL; - } - } else { - *err = acquire_in_progress ? -EAGAIN : error; - } - rcu_read_unlock(); - if (to_put) - xfrm_state_put(to_put); - - if (read_seqcount_retry(&xfrm_state_hash_generation, sequence)) { - *err = -EAGAIN; - if (x) { - xfrm_state_put(x); - x = NULL; - } - } - - return x; -} - -struct xfrm_state * -xfrm_stateonly_find(struct net *net, u32 mark, - xfrm_address_t *daddr, xfrm_address_t *saddr, - unsigned short family, u8 mode, u8 proto, u32 reqid) -{ - unsigned int h; - struct xfrm_state *rx = NULL, *x = NULL; - - spin_lock_bh(&net->xfrm.xfrm_state_lock); - h = xfrm_dst_hash(net, daddr, saddr, reqid, family); - hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { - if (x->props.family == family && - x->props.reqid == reqid && - (mark & x->mark.m) == x->mark.v && - !(x->props.flags & XFRM_STATE_WILDRECV) && - xfrm_state_addr_check(x, daddr, saddr, family) && - mode == x->props.mode && - proto == x->id.proto && - x->km.state == XFRM_STATE_VALID) { - rx = x; - break; - } - } - - if (rx) - xfrm_state_hold(rx); - spin_unlock_bh(&net->xfrm.xfrm_state_lock); - - - return rx; -} -EXPORT_SYMBOL(xfrm_stateonly_find); - -struct xfrm_state *xfrm_state_lookup_byspi(struct net *net, __be32 spi, - unsigned short family) -{ - struct xfrm_state *x; - struct xfrm_state_walk *w; - - spin_lock_bh(&net->xfrm.xfrm_state_lock); - list_for_each_entry(w, &net->xfrm.state_all, all) { - x = container_of(w, struct xfrm_state, km); - if (x->props.family != family || - x->id.spi != spi) - continue; - - xfrm_state_hold(x); - spin_unlock_bh(&net->xfrm.xfrm_state_lock); - return x; - } - spin_unlock_bh(&net->xfrm.xfrm_state_lock); - return NULL; -} -EXPORT_SYMBOL(xfrm_state_lookup_byspi); - -static void __xfrm_state_insert(struct xfrm_state *x) -{ - struct net *net = xs_net(x); - unsigned int h; - - list_add(&x->km.all, &net->xfrm.state_all); - - h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr, - x->props.reqid, x->props.family); - hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h); - - h = xfrm_src_hash(net, &x->id.daddr, &x->props.saddr, x->props.family); - hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h); - - if (x->id.spi) { - h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, - x->props.family); - - hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h); - } - - tasklet_hrtimer_start(&x->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL); - if (x->replay_maxage) - mod_timer(&x->rtimer, jiffies + x->replay_maxage); - - net->xfrm.state_num++; - - xfrm_hash_grow_check(net, x->bydst.next != NULL); -} - -/* net->xfrm.xfrm_state_lock is held */ -static void __xfrm_state_bump_genids(struct xfrm_state *xnew) -{ - struct net *net = xs_net(xnew); - unsigned short family = xnew->props.family; - u32 reqid = xnew->props.reqid; - struct xfrm_state *x; - unsigned int h; - u32 mark = xnew->mark.v & xnew->mark.m; - - h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); - hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { - if (x->props.family == family && - x->props.reqid == reqid && - (mark & x->mark.m) == x->mark.v && - xfrm_addr_equal(&x->id.daddr, &xnew->id.daddr, family) && - xfrm_addr_equal(&x->props.saddr, &xnew->props.saddr, family)) - x->genid++; - } -} - -void xfrm_state_insert(struct xfrm_state *x) -{ - struct net *net = xs_net(x); - - spin_lock_bh(&net->xfrm.xfrm_state_lock); - __xfrm_state_bump_genids(x); - __xfrm_state_insert(x); - spin_unlock_bh(&net->xfrm.xfrm_state_lock); -} -EXPORT_SYMBOL(xfrm_state_insert); - -/* net->xfrm.xfrm_state_lock is held */ -static struct xfrm_state *__find_acq_core(struct net *net, - const struct xfrm_mark *m, - unsigned short family, u8 mode, - u32 reqid, u8 proto, - const xfrm_address_t *daddr, - const xfrm_address_t *saddr, - int create) -{ - unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family); - struct xfrm_state *x; - u32 mark = m->v & m->m; - - hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { - if (x->props.reqid != reqid || - x->props.mode != mode || - x->props.family != family || - x->km.state != XFRM_STATE_ACQ || - x->id.spi != 0 || - x->id.proto != proto || - (mark & x->mark.m) != x->mark.v || - !xfrm_addr_equal(&x->id.daddr, daddr, family) || - !xfrm_addr_equal(&x->props.saddr, saddr, family)) - continue; - - xfrm_state_hold(x); - return x; - } - - if (!create) - return NULL; - - x = xfrm_state_alloc(net); - if (likely(x)) { - switch (family) { - case AF_INET: - x->sel.daddr.a4 = daddr->a4; - x->sel.saddr.a4 = saddr->a4; - x->sel.prefixlen_d = 32; - x->sel.prefixlen_s = 32; - x->props.saddr.a4 = saddr->a4; - x->id.daddr.a4 = daddr->a4; - break; - - case AF_INET6: - x->sel.daddr.in6 = daddr->in6; - x->sel.saddr.in6 = saddr->in6; - x->sel.prefixlen_d = 128; - x->sel.prefixlen_s = 128; - x->props.saddr.in6 = saddr->in6; - x->id.daddr.in6 = daddr->in6; - break; - } - - x->km.state = XFRM_STATE_ACQ; - x->id.proto = proto; - x->props.family = family; - x->props.mode = mode; - x->props.reqid = reqid; - x->mark.v = m->v; - x->mark.m = m->m; - x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; - xfrm_state_hold(x); - tasklet_hrtimer_start(&x->mtimer, ktime_set(net->xfrm.sysctl_acq_expires, 0), HRTIMER_MODE_REL); - list_add(&x->km.all, &net->xfrm.state_all); - hlist_add_head_rcu(&x->bydst, net->xfrm.state_bydst + h); - h = xfrm_src_hash(net, daddr, saddr, family); - hlist_add_head_rcu(&x->bysrc, net->xfrm.state_bysrc + h); - - net->xfrm.state_num++; - - xfrm_hash_grow_check(net, x->bydst.next != NULL); - } - - return x; -} - -static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq); - -int xfrm_state_add(struct xfrm_state *x) -{ - struct net *net = xs_net(x); - struct xfrm_state *x1, *to_put; - int family; - int err; - u32 mark = x->mark.v & x->mark.m; - int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); - - family = x->props.family; - - to_put = NULL; - - spin_lock_bh(&net->xfrm.xfrm_state_lock); - - x1 = __xfrm_state_locate(x, use_spi, family); - if (x1) { - to_put = x1; - x1 = NULL; - err = -EEXIST; - goto out; - } - - if (use_spi && x->km.seq) { - x1 = __xfrm_find_acq_byseq(net, mark, x->km.seq); - if (x1 && ((x1->id.proto != x->id.proto) || - !xfrm_addr_equal(&x1->id.daddr, &x->id.daddr, family))) { - to_put = x1; - x1 = NULL; - } - } - - if (use_spi && !x1) - x1 = __find_acq_core(net, &x->mark, family, x->props.mode, - x->props.reqid, x->id.proto, - &x->id.daddr, &x->props.saddr, 0); - - __xfrm_state_bump_genids(x); - __xfrm_state_insert(x); - err = 0; - -out: - spin_unlock_bh(&net->xfrm.xfrm_state_lock); - - if (x1) { - xfrm_state_delete(x1); - xfrm_state_put(x1); - } - - if (to_put) - xfrm_state_put(to_put); - - return err; -} -EXPORT_SYMBOL(xfrm_state_add); - -#ifdef CONFIG_XFRM_MIGRATE -static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig) -{ - struct net *net = xs_net(orig); - struct xfrm_state *x = xfrm_state_alloc(net); - if (!x) - goto out; - - memcpy(&x->id, &orig->id, sizeof(x->id)); - memcpy(&x->sel, &orig->sel, sizeof(x->sel)); - memcpy(&x->lft, &orig->lft, sizeof(x->lft)); - x->props.mode = orig->props.mode; - x->props.replay_window = orig->props.replay_window; - x->props.reqid = orig->props.reqid; - x->props.family = orig->props.family; - x->props.saddr = orig->props.saddr; - - if (orig->aalg) { - x->aalg = xfrm_algo_auth_clone(orig->aalg); - if (!x->aalg) - goto error; - } - x->props.aalgo = orig->props.aalgo; - - if (orig->aead) { - x->aead = xfrm_algo_aead_clone(orig->aead); - if (!x->aead) - goto error; - } - if (orig->ealg) { - x->ealg = xfrm_algo_clone(orig->ealg); - if (!x->ealg) - goto error; - } - x->props.ealgo = orig->props.ealgo; - - if (orig->calg) { - x->calg = xfrm_algo_clone(orig->calg); - if (!x->calg) - goto error; - } - x->props.calgo = orig->props.calgo; - - if (orig->encap) { - x->encap = kmemdup(orig->encap, sizeof(*x->encap), GFP_KERNEL); - if (!x->encap) - goto error; - } - - if (orig->coaddr) { - x->coaddr = kmemdup(orig->coaddr, sizeof(*x->coaddr), - GFP_KERNEL); - if (!x->coaddr) - goto error; - } - - if (orig->replay_esn) { - if (xfrm_replay_clone(x, orig)) - goto error; - } - - memcpy(&x->mark, &orig->mark, sizeof(x->mark)); - - if (xfrm_init_state(x) < 0) - goto error; - - x->props.flags = orig->props.flags; - x->props.extra_flags = orig->props.extra_flags; - - x->tfcpad = orig->tfcpad; - x->replay_maxdiff = orig->replay_maxdiff; - x->replay_maxage = orig->replay_maxage; - x->curlft.add_time = orig->curlft.add_time; - x->km.state = orig->km.state; - x->km.seq = orig->km.seq; - - return x; - - error: - xfrm_state_put(x); -out: - return NULL; -} - -struct xfrm_state *xfrm_migrate_state_find(struct xfrm_migrate *m, struct net *net) -{ - unsigned int h; - struct xfrm_state *x = NULL; - - spin_lock_bh(&net->xfrm.xfrm_state_lock); - - if (m->reqid) { - h = xfrm_dst_hash(net, &m->old_daddr, &m->old_saddr, - m->reqid, m->old_family); - hlist_for_each_entry(x, net->xfrm.state_bydst+h, bydst) { - if (x->props.mode != m->mode || - x->id.proto != m->proto) - continue; - if (m->reqid && x->props.reqid != m->reqid) - continue; - if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr, - m->old_family) || - !xfrm_addr_equal(&x->props.saddr, &m->old_saddr, - m->old_family)) - continue; - xfrm_state_hold(x); - break; - } - } else { - h = xfrm_src_hash(net, &m->old_daddr, &m->old_saddr, - m->old_family); - hlist_for_each_entry(x, net->xfrm.state_bysrc+h, bysrc) { - if (x->props.mode != m->mode || - x->id.proto != m->proto) - continue; - if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr, - m->old_family) || - !xfrm_addr_equal(&x->props.saddr, &m->old_saddr, - m->old_family)) - continue; - xfrm_state_hold(x); - break; - } - } - - spin_unlock_bh(&net->xfrm.xfrm_state_lock); - - return x; -} -EXPORT_SYMBOL(xfrm_migrate_state_find); - -struct xfrm_state *xfrm_state_migrate(struct xfrm_state *x, - struct xfrm_migrate *m) -{ - struct xfrm_state *xc; - - xc = xfrm_state_clone(x); - if (!xc) - return NULL; - - memcpy(&xc->id.daddr, &m->new_daddr, sizeof(xc->id.daddr)); - memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr)); - - /* add state */ - if (xfrm_addr_equal(&x->id.daddr, &m->new_daddr, m->new_family)) { - /* a care is needed when the destination address of the - state is to be updated as it is a part of triplet */ - xfrm_state_insert(xc); - } else { - if (xfrm_state_add(xc) < 0) - goto error; - } - - return xc; -error: - xfrm_state_put(xc); - return NULL; -} -EXPORT_SYMBOL(xfrm_state_migrate); -#endif - -int xfrm_state_update(struct xfrm_state *x) -{ - struct xfrm_state *x1, *to_put; - int err; - int use_spi = xfrm_id_proto_match(x->id.proto, IPSEC_PROTO_ANY); - struct net *net = xs_net(x); - - to_put = NULL; - - spin_lock_bh(&net->xfrm.xfrm_state_lock); - x1 = __xfrm_state_locate(x, use_spi, x->props.family); - - err = -ESRCH; - if (!x1) - goto out; - - if (xfrm_state_kern(x1)) { - to_put = x1; - err = -EEXIST; - goto out; - } - - if (x1->km.state == XFRM_STATE_ACQ) { - __xfrm_state_insert(x); - x = NULL; - } - err = 0; - -out: - spin_unlock_bh(&net->xfrm.xfrm_state_lock); - - if (to_put) - xfrm_state_put(to_put); - - if (err) - return err; - - if (!x) { - xfrm_state_delete(x1); - xfrm_state_put(x1); - return 0; - } - - err = -EINVAL; - spin_lock_bh(&x1->lock); - if (likely(x1->km.state == XFRM_STATE_VALID)) { - if (x->encap && x1->encap) - memcpy(x1->encap, x->encap, sizeof(*x1->encap)); - if (x->coaddr && x1->coaddr) { - memcpy(x1->coaddr, x->coaddr, sizeof(*x1->coaddr)); - } - if (!use_spi && memcmp(&x1->sel, &x->sel, sizeof(x1->sel))) - memcpy(&x1->sel, &x->sel, sizeof(x1->sel)); - memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); - x1->km.dying = 0; - - tasklet_hrtimer_start(&x1->mtimer, ktime_set(1, 0), HRTIMER_MODE_REL); - if (x1->curlft.use_time) - xfrm_state_check_expire(x1); - - err = 0; - x->km.state = XFRM_STATE_DEAD; - __xfrm_state_put(x); - } - spin_unlock_bh(&x1->lock); - - xfrm_state_put(x1); - - return err; -} -EXPORT_SYMBOL(xfrm_state_update); - -int xfrm_state_check_expire(struct xfrm_state *x) -{ - if (!x->curlft.use_time) - x->curlft.use_time = get_seconds(); - - if (x->curlft.bytes >= x->lft.hard_byte_limit || - x->curlft.packets >= x->lft.hard_packet_limit) { - x->km.state = XFRM_STATE_EXPIRED; - tasklet_hrtimer_start(&x->mtimer, ktime_set(0, 0), HRTIMER_MODE_REL); - return -EINVAL; - } - - if (!x->km.dying && - (x->curlft.bytes >= x->lft.soft_byte_limit || - x->curlft.packets >= x->lft.soft_packet_limit)) { - x->km.dying = 1; - km_state_expired(x, 0, 0); - } - return 0; -} -EXPORT_SYMBOL(xfrm_state_check_expire); - -struct xfrm_state * -xfrm_state_lookup(struct net *net, u32 mark, const xfrm_address_t *daddr, __be32 spi, - u8 proto, unsigned short family) -{ - struct xfrm_state *x; - - rcu_read_lock(); - x = __xfrm_state_lookup(net, mark, daddr, spi, proto, family); - rcu_read_unlock(); - return x; -} -EXPORT_SYMBOL(xfrm_state_lookup); - -struct xfrm_state * -xfrm_state_lookup_byaddr(struct net *net, u32 mark, - const xfrm_address_t *daddr, const xfrm_address_t *saddr, - u8 proto, unsigned short family) -{ - struct xfrm_state *x; - - spin_lock_bh(&net->xfrm.xfrm_state_lock); - x = __xfrm_state_lookup_byaddr(net, mark, daddr, saddr, proto, family); - spin_unlock_bh(&net->xfrm.xfrm_state_lock); - return x; -} -EXPORT_SYMBOL(xfrm_state_lookup_byaddr); - -struct xfrm_state * -xfrm_find_acq(struct net *net, const struct xfrm_mark *mark, u8 mode, u32 reqid, - u8 proto, const xfrm_address_t *daddr, - const xfrm_address_t *saddr, int create, unsigned short family) -{ - struct xfrm_state *x; - - spin_lock_bh(&net->xfrm.xfrm_state_lock); - x = __find_acq_core(net, mark, family, mode, reqid, proto, daddr, saddr, create); - spin_unlock_bh(&net->xfrm.xfrm_state_lock); - - return x; -} -EXPORT_SYMBOL(xfrm_find_acq); - -#ifdef CONFIG_XFRM_SUB_POLICY -int -xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, - unsigned short family, struct net *net) -{ - int err = 0; - struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); - if (!afinfo) - return -EAFNOSUPPORT; - - spin_lock_bh(&net->xfrm.xfrm_state_lock); /*FIXME*/ - if (afinfo->tmpl_sort) - err = afinfo->tmpl_sort(dst, src, n); - spin_unlock_bh(&net->xfrm.xfrm_state_lock); - xfrm_state_put_afinfo(afinfo); - return err; -} -EXPORT_SYMBOL(xfrm_tmpl_sort); - -int -xfrm_state_sort(struct xfrm_state **dst, struct xfrm_state **src, int n, - unsigned short family) -{ - int err = 0; - struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); - struct net *net = xs_net(*src); - - if (!afinfo) - return -EAFNOSUPPORT; - - spin_lock_bh(&net->xfrm.xfrm_state_lock); - if (afinfo->state_sort) - err = afinfo->state_sort(dst, src, n); - spin_unlock_bh(&net->xfrm.xfrm_state_lock); - xfrm_state_put_afinfo(afinfo); - return err; -} -EXPORT_SYMBOL(xfrm_state_sort); -#endif - -/* Silly enough, but I'm lazy to build resolution list */ - -static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) -{ - int i; - - for (i = 0; i <= net->xfrm.state_hmask; i++) { - struct xfrm_state *x; - - hlist_for_each_entry(x, net->xfrm.state_bydst+i, bydst) { - if (x->km.seq == seq && - (mark & x->mark.m) == x->mark.v && - x->km.state == XFRM_STATE_ACQ) { - xfrm_state_hold(x); - return x; - } - } - } - return NULL; -} - -struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 mark, u32 seq) -{ - struct xfrm_state *x; - - spin_lock_bh(&net->xfrm.xfrm_state_lock); - x = __xfrm_find_acq_byseq(net, mark, seq); - spin_unlock_bh(&net->xfrm.xfrm_state_lock); - return x; -} -EXPORT_SYMBOL(xfrm_find_acq_byseq); - -u32 xfrm_get_acqseq(void) -{ - u32 res; - static atomic_t acqseq; - - do { - res = atomic_inc_return(&acqseq); - } while (!res); - - return res; -} -EXPORT_SYMBOL(xfrm_get_acqseq); - -int verify_spi_info(u8 proto, u32 min, u32 max) -{ - switch (proto) { - case IPPROTO_AH: - case IPPROTO_ESP: - break; - - case IPPROTO_COMP: - /* IPCOMP spi is 16-bits. */ - if (max >= 0x10000) - return -EINVAL; - break; - - default: - return -EINVAL; - } - - if (min > max) - return -EINVAL; - - return 0; -} -EXPORT_SYMBOL(verify_spi_info); - -int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) -{ - struct net *net = xs_net(x); - unsigned int h; - struct xfrm_state *x0; - int err = -ENOENT; - __be32 minspi = htonl(low); - __be32 maxspi = htonl(high); - u32 mark = x->mark.v & x->mark.m; - - spin_lock_bh(&x->lock); - if (x->km.state == XFRM_STATE_DEAD) - goto unlock; - - err = 0; - if (x->id.spi) - goto unlock; - - err = -ENOENT; - - if (minspi == maxspi) { - x0 = xfrm_state_lookup(net, mark, &x->id.daddr, minspi, x->id.proto, x->props.family); - if (x0) { - xfrm_state_put(x0); - goto unlock; - } - x->id.spi = minspi; - } else { - u32 spi = 0; - for (h = 0; h < high-low+1; h++) { - spi = low + prandom_u32()%(high-low+1); - x0 = xfrm_state_lookup(net, mark, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); - if (x0 == NULL) { - x->id.spi = htonl(spi); - break; - } - xfrm_state_put(x0); - } - } - if (x->id.spi) { - spin_lock_bh(&net->xfrm.xfrm_state_lock); - h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family); - hlist_add_head_rcu(&x->byspi, net->xfrm.state_byspi + h); - spin_unlock_bh(&net->xfrm.xfrm_state_lock); - - err = 0; - } - -unlock: - spin_unlock_bh(&x->lock); - - return err; -} -EXPORT_SYMBOL(xfrm_alloc_spi); - -static bool __xfrm_state_filter_match(struct xfrm_state *x, - struct xfrm_address_filter *filter) -{ - if (filter) { - if ((filter->family == AF_INET || - filter->family == AF_INET6) && - x->props.family != filter->family) - return false; - - return addr_match(&x->props.saddr, &filter->saddr, - filter->splen) && - addr_match(&x->id.daddr, &filter->daddr, - filter->dplen); - } - return true; -} - -int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, - int (*func)(struct xfrm_state *, int, void*), - void *data) -{ - struct xfrm_state *state; - struct xfrm_state_walk *x; - int err = 0; - - if (walk->seq != 0 && list_empty(&walk->all)) - return 0; - - spin_lock_bh(&net->xfrm.xfrm_state_lock); - if (list_empty(&walk->all)) - x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all); - else - x = list_first_entry(&walk->all, struct xfrm_state_walk, all); - list_for_each_entry_from(x, &net->xfrm.state_all, all) { - if (x->state == XFRM_STATE_DEAD) - continue; - state = container_of(x, struct xfrm_state, km); - if (!xfrm_id_proto_match(state->id.proto, walk->proto)) - continue; - if (!__xfrm_state_filter_match(state, walk->filter)) - continue; - err = func(state, walk->seq, data); - if (err) { - list_move_tail(&walk->all, &x->all); - goto out; - } - walk->seq++; - } - if (walk->seq == 0) { - err = -ENOENT; - goto out; - } - list_del_init(&walk->all); -out: - spin_unlock_bh(&net->xfrm.xfrm_state_lock); - return err; -} -EXPORT_SYMBOL(xfrm_state_walk); - -void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto, - struct xfrm_address_filter *filter) -{ - INIT_LIST_HEAD(&walk->all); - walk->proto = proto; - walk->state = XFRM_STATE_DEAD; - walk->seq = 0; - walk->filter = filter; -} -EXPORT_SYMBOL(xfrm_state_walk_init); - -void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net) -{ - kfree(walk->filter); - - if (list_empty(&walk->all)) - return; - - spin_lock_bh(&net->xfrm.xfrm_state_lock); - list_del(&walk->all); - spin_unlock_bh(&net->xfrm.xfrm_state_lock); -} -EXPORT_SYMBOL(xfrm_state_walk_done); - -static void xfrm_replay_timer_handler(unsigned long data) -{ - struct xfrm_state *x = (struct xfrm_state *)data; - - spin_lock(&x->lock); - - if (x->km.state == XFRM_STATE_VALID) { - if (xfrm_aevent_is_on(xs_net(x))) - x->repl->notify(x, XFRM_REPLAY_TIMEOUT); - else - x->xflags |= XFRM_TIME_DEFER; - } - - spin_unlock(&x->lock); -} - -static LIST_HEAD(xfrm_km_list); - -void km_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c) -{ - struct xfrm_mgr *km; - - rcu_read_lock(); - list_for_each_entry_rcu(km, &xfrm_km_list, list) - if (km->notify_policy) - km->notify_policy(xp, dir, c); - rcu_read_unlock(); -} - -void km_state_notify(struct xfrm_state *x, const struct km_event *c) -{ - struct xfrm_mgr *km; - rcu_read_lock(); - list_for_each_entry_rcu(km, &xfrm_km_list, list) - if (km->notify) - km->notify(x, c); - rcu_read_unlock(); -} - -EXPORT_SYMBOL(km_policy_notify); -EXPORT_SYMBOL(km_state_notify); - -void km_state_expired(struct xfrm_state *x, int hard, u32 portid) -{ - struct km_event c; - - c.data.hard = hard; - c.portid = portid; - c.event = XFRM_MSG_EXPIRE; - km_state_notify(x, &c); -} - -EXPORT_SYMBOL(km_state_expired); -/* - * We send to all registered managers regardless of failure - * We are happy with one success -*/ -int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) -{ - int err = -EINVAL, acqret; - struct xfrm_mgr *km; - - rcu_read_lock(); - list_for_each_entry_rcu(km, &xfrm_km_list, list) { - acqret = km->acquire(x, t, pol); - if (!acqret) - err = acqret; - } - rcu_read_unlock(); - return err; -} -EXPORT_SYMBOL(km_query); - -int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) -{ - int err = -EINVAL; - struct xfrm_mgr *km; - - rcu_read_lock(); - list_for_each_entry_rcu(km, &xfrm_km_list, list) { - if (km->new_mapping) - err = km->new_mapping(x, ipaddr, sport); - if (!err) - break; - } - rcu_read_unlock(); - return err; -} -EXPORT_SYMBOL(km_new_mapping); - -void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 portid) -{ - struct km_event c; - - c.data.hard = hard; - c.portid = portid; - c.event = XFRM_MSG_POLEXPIRE; - km_policy_notify(pol, dir, &c); -} -EXPORT_SYMBOL(km_policy_expired); - -#ifdef CONFIG_XFRM_MIGRATE -int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, - const struct xfrm_migrate *m, int num_migrate, - const struct xfrm_kmaddress *k) -{ - int err = -EINVAL; - int ret; - struct xfrm_mgr *km; - - rcu_read_lock(); - list_for_each_entry_rcu(km, &xfrm_km_list, list) { - if (km->migrate) { - ret = km->migrate(sel, dir, type, m, num_migrate, k); - if (!ret) - err = ret; - } - } - rcu_read_unlock(); - return err; -} -EXPORT_SYMBOL(km_migrate); -#endif - -int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) -{ - int err = -EINVAL; - int ret; - struct xfrm_mgr *km; - - rcu_read_lock(); - list_for_each_entry_rcu(km, &xfrm_km_list, list) { - if (km->report) { - ret = km->report(net, proto, sel, addr); - if (!ret) - err = ret; - } - } - rcu_read_unlock(); - return err; -} -EXPORT_SYMBOL(km_report); - -bool km_is_alive(const struct km_event *c) -{ - struct xfrm_mgr *km; - bool is_alive = false; - - rcu_read_lock(); - list_for_each_entry_rcu(km, &xfrm_km_list, list) { - if (km->is_alive && km->is_alive(c)) { - is_alive = true; - break; - } - } - rcu_read_unlock(); - - return is_alive; -} -EXPORT_SYMBOL(km_is_alive); - -int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen) -{ - int err; - u8 *data; - struct xfrm_mgr *km; - struct xfrm_policy *pol = NULL; - - if (optlen <= 0 || optlen > PAGE_SIZE) - return -EMSGSIZE; - - data = kmalloc(optlen, GFP_KERNEL); - if (!data) - return -ENOMEM; - - err = -EFAULT; - if (copy_from_user(data, optval, optlen)) - goto out; - - err = -EINVAL; - rcu_read_lock(); - list_for_each_entry_rcu(km, &xfrm_km_list, list) { - pol = km->compile_policy(sk, optname, data, - optlen, &err); - if (err >= 0) - break; - } - rcu_read_unlock(); - - if (err >= 0) { - xfrm_sk_policy_insert(sk, err, pol); - xfrm_pol_put(pol); - err = 0; - } - -out: - kfree(data); - return err; -} -EXPORT_SYMBOL(xfrm_user_policy); - -static DEFINE_SPINLOCK(xfrm_km_lock); - -int xfrm_register_km(struct xfrm_mgr *km) -{ - spin_lock_bh(&xfrm_km_lock); - list_add_tail_rcu(&km->list, &xfrm_km_list); - spin_unlock_bh(&xfrm_km_lock); - return 0; -} -EXPORT_SYMBOL(xfrm_register_km); - -int xfrm_unregister_km(struct xfrm_mgr *km) -{ - spin_lock_bh(&xfrm_km_lock); - list_del_rcu(&km->list); - spin_unlock_bh(&xfrm_km_lock); - synchronize_rcu(); - return 0; -} -EXPORT_SYMBOL(xfrm_unregister_km); - -int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo) -{ - int err = 0; - if (unlikely(afinfo == NULL)) - return -EINVAL; - if (unlikely(afinfo->family >= NPROTO)) - return -EAFNOSUPPORT; - spin_lock_bh(&xfrm_state_afinfo_lock); - if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) - err = -EEXIST; - else - rcu_assign_pointer(xfrm_state_afinfo[afinfo->family], afinfo); - spin_unlock_bh(&xfrm_state_afinfo_lock); - return err; -} -EXPORT_SYMBOL(xfrm_state_register_afinfo); - -int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) -{ - int err = 0; - if (unlikely(afinfo == NULL)) - return -EINVAL; - if (unlikely(afinfo->family >= NPROTO)) - return -EAFNOSUPPORT; - spin_lock_bh(&xfrm_state_afinfo_lock); - if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) { - if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo)) - err = -EINVAL; - else - RCU_INIT_POINTER(xfrm_state_afinfo[afinfo->family], NULL); - } - spin_unlock_bh(&xfrm_state_afinfo_lock); - synchronize_rcu(); - return err; -} -EXPORT_SYMBOL(xfrm_state_unregister_afinfo); - -struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) -{ - struct xfrm_state_afinfo *afinfo; - if (unlikely(family >= NPROTO)) - return NULL; - rcu_read_lock(); - afinfo = rcu_dereference(xfrm_state_afinfo[family]); - if (unlikely(!afinfo)) - rcu_read_unlock(); - return afinfo; -} - -void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) -{ - rcu_read_unlock(); -} - -/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ -void xfrm_state_delete_tunnel(struct xfrm_state *x) -{ - if (x->tunnel) { - struct xfrm_state *t = x->tunnel; - - if (atomic_read(&t->tunnel_users) == 2) - xfrm_state_delete(t); - atomic_dec(&t->tunnel_users); - xfrm_state_put(t); - x->tunnel = NULL; - } -} -EXPORT_SYMBOL(xfrm_state_delete_tunnel); - -int xfrm_state_mtu(struct xfrm_state *x, int mtu) -{ - int res; - - spin_lock_bh(&x->lock); - if (x->km.state == XFRM_STATE_VALID && - x->type && x->type->get_mtu) - res = x->type->get_mtu(x, mtu); - else - res = mtu - x->props.header_len; - spin_unlock_bh(&x->lock); - return res; -} - -int __xfrm_init_state(struct xfrm_state *x, bool init_replay) -{ - struct xfrm_state_afinfo *afinfo; - struct xfrm_mode *inner_mode; - int family = x->props.family; - int err; - - err = -EAFNOSUPPORT; - afinfo = xfrm_state_get_afinfo(family); - if (!afinfo) - goto error; - - err = 0; - if (afinfo->init_flags) - err = afinfo->init_flags(x); - - xfrm_state_put_afinfo(afinfo); - - if (err) - goto error; - - err = -EPROTONOSUPPORT; - - if (x->sel.family != AF_UNSPEC) { - inner_mode = xfrm_get_mode(x->props.mode, x->sel.family); - if (inner_mode == NULL) - goto error; - - if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && - family != x->sel.family) { - xfrm_put_mode(inner_mode); - goto error; - } - - x->inner_mode = inner_mode; - } else { - struct xfrm_mode *inner_mode_iaf; - int iafamily = AF_INET; - - inner_mode = xfrm_get_mode(x->props.mode, x->props.family); - if (inner_mode == NULL) - goto error; - - if (!(inner_mode->flags & XFRM_MODE_FLAG_TUNNEL)) { - xfrm_put_mode(inner_mode); - goto error; - } - x->inner_mode = inner_mode; - - if (x->props.family == AF_INET) - iafamily = AF_INET6; - - inner_mode_iaf = xfrm_get_mode(x->props.mode, iafamily); - if (inner_mode_iaf) { - if (inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL) - x->inner_mode_iaf = inner_mode_iaf; - else - xfrm_put_mode(inner_mode_iaf); - } - } - - x->type = xfrm_get_type(x->id.proto, family); - if (x->type == NULL) - goto error; - - err = x->type->init_state(x); - if (err) - goto error; - - x->outer_mode = xfrm_get_mode(x->props.mode, family); - if (x->outer_mode == NULL) { - err = -EPROTONOSUPPORT; - goto error; - } - - if (init_replay) { - err = xfrm_init_replay(x); - if (err) - goto error; - } - - x->km.state = XFRM_STATE_VALID; - -error: - return err; -} - -EXPORT_SYMBOL(__xfrm_init_state); - -int xfrm_init_state(struct xfrm_state *x) -{ - return __xfrm_init_state(x, true); -} - -EXPORT_SYMBOL(xfrm_init_state); - -int __net_init xfrm_state_init(struct net *net) -{ - unsigned int sz; - - INIT_LIST_HEAD(&net->xfrm.state_all); - - sz = sizeof(struct hlist_head) * 8; - - net->xfrm.state_bydst = xfrm_hash_alloc(sz); - if (!net->xfrm.state_bydst) - goto out_bydst; - net->xfrm.state_bysrc = xfrm_hash_alloc(sz); - if (!net->xfrm.state_bysrc) - goto out_bysrc; - net->xfrm.state_byspi = xfrm_hash_alloc(sz); - if (!net->xfrm.state_byspi) - goto out_byspi; - net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1); - - net->xfrm.state_num = 0; - INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize); - spin_lock_init(&net->xfrm.xfrm_state_lock); - return 0; - -out_byspi: - xfrm_hash_free(net->xfrm.state_bysrc, sz); -out_bysrc: - xfrm_hash_free(net->xfrm.state_bydst, sz); -out_bydst: - return -ENOMEM; -} - -void xfrm_state_fini(struct net *net) -{ - unsigned int sz; - - flush_work(&net->xfrm.state_hash_work); - xfrm_state_flush(net, IPSEC_PROTO_ANY, false); - flush_work(&xfrm_state_gc_work); - - WARN_ON(!list_empty(&net->xfrm.state_all)); - - sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head); - WARN_ON(!hlist_empty(net->xfrm.state_byspi)); - xfrm_hash_free(net->xfrm.state_byspi, sz); - WARN_ON(!hlist_empty(net->xfrm.state_bysrc)); - xfrm_hash_free(net->xfrm.state_bysrc, sz); - WARN_ON(!hlist_empty(net->xfrm.state_bydst)); - xfrm_hash_free(net->xfrm.state_bydst, sz); -} - -#ifdef CONFIG_AUDITSYSCALL -static void xfrm_audit_helper_sainfo(struct xfrm_state *x, - struct audit_buffer *audit_buf) -{ - struct xfrm_sec_ctx *ctx = x->security; - u32 spi = ntohl(x->id.spi); - - if (ctx) - audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", - ctx->ctx_alg, ctx->ctx_doi, ctx->ctx_str); - - switch (x->props.family) { - case AF_INET: - audit_log_format(audit_buf, " src=%pI4 dst=%pI4", - &x->props.saddr.a4, &x->id.daddr.a4); - break; - case AF_INET6: - audit_log_format(audit_buf, " src=%pI6 dst=%pI6", - x->props.saddr.a6, x->id.daddr.a6); - break; - } - - audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); -} - -static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family, - struct audit_buffer *audit_buf) -{ - const struct iphdr *iph4; - const struct ipv6hdr *iph6; - - switch (family) { - case AF_INET: - iph4 = ip_hdr(skb); - audit_log_format(audit_buf, " src=%pI4 dst=%pI4", - &iph4->saddr, &iph4->daddr); - break; - case AF_INET6: - iph6 = ipv6_hdr(skb); - audit_log_format(audit_buf, - " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x", - &iph6->saddr, &iph6->daddr, - iph6->flow_lbl[0] & 0x0f, - iph6->flow_lbl[1], - iph6->flow_lbl[2]); - break; - } -} - -void xfrm_audit_state_add(struct xfrm_state *x, int result, bool task_valid) -{ - struct audit_buffer *audit_buf; - - audit_buf = xfrm_audit_start("SAD-add"); - if (audit_buf == NULL) - return; - xfrm_audit_helper_usrinfo(task_valid, audit_buf); - xfrm_audit_helper_sainfo(x, audit_buf); - audit_log_format(audit_buf, " res=%u", result); - audit_log_end(audit_buf); -} -EXPORT_SYMBOL_GPL(xfrm_audit_state_add); - -void xfrm_audit_state_delete(struct xfrm_state *x, int result, bool task_valid) -{ - struct audit_buffer *audit_buf; - - audit_buf = xfrm_audit_start("SAD-delete"); - if (audit_buf == NULL) - return; - xfrm_audit_helper_usrinfo(task_valid, audit_buf); - xfrm_audit_helper_sainfo(x, audit_buf); - audit_log_format(audit_buf, " res=%u", result); - audit_log_end(audit_buf); -} -EXPORT_SYMBOL_GPL(xfrm_audit_state_delete); - -void xfrm_audit_state_replay_overflow(struct xfrm_state *x, - struct sk_buff *skb) -{ - struct audit_buffer *audit_buf; - u32 spi; - - audit_buf = xfrm_audit_start("SA-replay-overflow"); - if (audit_buf == NULL) - return; - xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); - /* don't record the sequence number because it's inherent in this kind - * of audit message */ - spi = ntohl(x->id.spi); - audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); - audit_log_end(audit_buf); -} -EXPORT_SYMBOL_GPL(xfrm_audit_state_replay_overflow); - -void xfrm_audit_state_replay(struct xfrm_state *x, - struct sk_buff *skb, __be32 net_seq) -{ - struct audit_buffer *audit_buf; - u32 spi; - - audit_buf = xfrm_audit_start("SA-replayed-pkt"); - if (audit_buf == NULL) - return; - xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); - spi = ntohl(x->id.spi); - audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", - spi, spi, ntohl(net_seq)); - audit_log_end(audit_buf); -} -EXPORT_SYMBOL_GPL(xfrm_audit_state_replay); - -void xfrm_audit_state_notfound_simple(struct sk_buff *skb, u16 family) -{ - struct audit_buffer *audit_buf; - - audit_buf = xfrm_audit_start("SA-notfound"); - if (audit_buf == NULL) - return; - xfrm_audit_helper_pktinfo(skb, family, audit_buf); - audit_log_end(audit_buf); -} -EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound_simple); - -void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family, - __be32 net_spi, __be32 net_seq) -{ - struct audit_buffer *audit_buf; - u32 spi; - - audit_buf = xfrm_audit_start("SA-notfound"); - if (audit_buf == NULL) - return; - xfrm_audit_helper_pktinfo(skb, family, audit_buf); - spi = ntohl(net_spi); - audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", - spi, spi, ntohl(net_seq)); - audit_log_end(audit_buf); -} -EXPORT_SYMBOL_GPL(xfrm_audit_state_notfound); - -void xfrm_audit_state_icvfail(struct xfrm_state *x, - struct sk_buff *skb, u8 proto) -{ - struct audit_buffer *audit_buf; - __be32 net_spi; - __be32 net_seq; - - audit_buf = xfrm_audit_start("SA-icv-failure"); - if (audit_buf == NULL) - return; - xfrm_audit_helper_pktinfo(skb, x->props.family, audit_buf); - if (xfrm_parse_spi(skb, proto, &net_spi, &net_seq) == 0) { - u32 spi = ntohl(net_spi); - audit_log_format(audit_buf, " spi=%u(0x%x) seqno=%u", - spi, spi, ntohl(net_seq)); - } - audit_log_end(audit_buf); -} -EXPORT_SYMBOL_GPL(xfrm_audit_state_icvfail); -#endif /* CONFIG_AUDITSYSCALL */ diff --git a/src/linux/net/xfrm/xfrm_sysctl.c b/src/linux/net/xfrm/xfrm_sysctl.c deleted file mode 100644 index 35a7e79..0000000 --- a/src/linux/net/xfrm/xfrm_sysctl.c +++ /dev/null @@ -1,86 +0,0 @@ -#include -#include -#include -#include - -static void __net_init __xfrm_sysctl_init(struct net *net) -{ - net->xfrm.sysctl_aevent_etime = XFRM_AE_ETIME; - net->xfrm.sysctl_aevent_rseqth = XFRM_AE_SEQT_SIZE; - net->xfrm.sysctl_larval_drop = 1; - net->xfrm.sysctl_acq_expires = 30; -} - -#ifdef CONFIG_SYSCTL -static struct ctl_table xfrm_table[] = { - { - .procname = "xfrm_aevent_etime", - .maxlen = sizeof(u32), - .mode = 0644, - .proc_handler = proc_douintvec - }, - { - .procname = "xfrm_aevent_rseqth", - .maxlen = sizeof(u32), - .mode = 0644, - .proc_handler = proc_douintvec - }, - { - .procname = "xfrm_larval_drop", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - { - .procname = "xfrm_acq_expires", - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = proc_dointvec - }, - {} -}; - -int __net_init xfrm_sysctl_init(struct net *net) -{ - struct ctl_table *table; - - __xfrm_sysctl_init(net); - - table = kmemdup(xfrm_table, sizeof(xfrm_table), GFP_KERNEL); - if (!table) - goto out_kmemdup; - table[0].data = &net->xfrm.sysctl_aevent_etime; - table[1].data = &net->xfrm.sysctl_aevent_rseqth; - table[2].data = &net->xfrm.sysctl_larval_drop; - table[3].data = &net->xfrm.sysctl_acq_expires; - - /* Don't export sysctls to unprivileged users */ - if (net->user_ns != &init_user_ns) - table[0].procname = NULL; - - net->xfrm.sysctl_hdr = register_net_sysctl(net, "net/core", table); - if (!net->xfrm.sysctl_hdr) - goto out_register; - return 0; - -out_register: - kfree(table); -out_kmemdup: - return -ENOMEM; -} - -void __net_exit xfrm_sysctl_fini(struct net *net) -{ - struct ctl_table *table; - - table = net->xfrm.sysctl_hdr->ctl_table_arg; - unregister_net_sysctl_table(net->xfrm.sysctl_hdr); - kfree(table); -} -#else -int __net_init xfrm_sysctl_init(struct net *net) -{ - __xfrm_sysctl_init(net); - return 0; -} -#endif diff --git a/src/linux/samples/Kconfig b/src/linux/samples/Kconfig deleted file mode 100644 index a6d2a43..0000000 --- a/src/linux/samples/Kconfig +++ /dev/null @@ -1,108 +0,0 @@ -menuconfig SAMPLES - bool "Sample kernel code" - help - You can build and test sample kernel code here. - -if SAMPLES - -config SAMPLE_TRACE_EVENTS - tristate "Build trace_events examples -- loadable modules only" - depends on EVENT_TRACING && m - help - This build trace event example modules. - -config SAMPLE_TRACE_PRINTK - tristate "Build trace_printk module - tests various trace_printk formats" - depends on EVENT_TRACING && m - help - This builds a module that calls trace_printk() and can be used to - test various trace_printk() calls from a module. - -config SAMPLE_KOBJECT - tristate "Build kobject examples -- loadable modules only" - depends on m - help - This config option will allow you to build a number of - different kobject sample modules showing how to use kobjects, - ksets, and ktypes properly. - - If in doubt, say "N" here. - -config SAMPLE_KPROBES - tristate "Build kprobes examples -- loadable modules only" - depends on KPROBES && m - help - This build several kprobes example modules. - -config SAMPLE_KRETPROBES - tristate "Build kretprobes example -- loadable modules only" - default m - depends on SAMPLE_KPROBES && KRETPROBES - -config SAMPLE_HW_BREAKPOINT - tristate "Build kernel hardware breakpoint examples -- loadable module only" - depends on HAVE_HW_BREAKPOINT && m - help - This builds kernel hardware breakpoint example modules. - -config SAMPLE_KFIFO - tristate "Build kfifo examples -- loadable modules only" - depends on m - help - This config option will allow you to build a number of - different kfifo sample modules showing how to use the - generic kfifo API. - - If in doubt, say "N" here. - -config SAMPLE_KDB - tristate "Build kdb command example -- loadable modules only" - depends on KGDB_KDB && m - help - Build an example of how to dynamically add the hello - command to the kdb shell. - -config SAMPLE_RPMSG_CLIENT - tristate "Build rpmsg client sample -- loadable modules only" - depends on RPMSG && m - help - Build an rpmsg client sample driver, which demonstrates how - to communicate with an AMP-configured remote processor over - the rpmsg bus. - -config SAMPLE_LIVEPATCH - tristate "Build live patching sample -- loadable modules only" - depends on LIVEPATCH && m - help - Builds a sample live patch that replaces the procfs handler - for /proc/cmdline to print "this has been live patched". - -config SAMPLE_CONFIGFS - tristate "Build configfs patching sample -- loadable modules only" - depends on CONFIGFS_FS && m - help - Builds a sample configfs interface. - -config SAMPLE_CONNECTOR - tristate "Build connector sample -- loadable modules only" - depends on CONNECTOR && m - help - When enabled, this builds both a sample kernel module for - the connector interface and a user space tool to communicate - with it. - See also Documentation/connector/connector.txt - -config SAMPLE_SECCOMP - tristate "Build seccomp sample code -- loadable modules only" - depends on SECCOMP_FILTER && m - help - Build samples of seccomp filters using various methods of - BPF filter construction. - -config SAMPLE_BLACKFIN_GPTIMERS - tristate "Build blackfin gptimers sample code -- loadable modules only" - depends on BLACKFIN && BFIN_GPTIMERS && m - help - Build samples of blackfin gptimers sample module. - -endif # SAMPLES diff --git a/src/linux/samples/auxdisplay/.gitignore b/src/linux/samples/auxdisplay/.gitignore deleted file mode 100644 index 7af2228..0000000 --- a/src/linux/samples/auxdisplay/.gitignore +++ /dev/null @@ -1 +0,0 @@ -cfag12864b-example diff --git a/src/linux/samples/connector/.gitignore b/src/linux/samples/connector/.gitignore deleted file mode 100644 index d2b9c32..0000000 --- a/src/linux/samples/connector/.gitignore +++ /dev/null @@ -1 +0,0 @@ -ucon diff --git a/src/linux/samples/hidraw/.gitignore b/src/linux/samples/hidraw/.gitignore deleted file mode 100644 index 05e51a6..0000000 --- a/src/linux/samples/hidraw/.gitignore +++ /dev/null @@ -1 +0,0 @@ -hid-example diff --git a/src/linux/samples/mei/.gitignore b/src/linux/samples/mei/.gitignore deleted file mode 100644 index f356b81..0000000 --- a/src/linux/samples/mei/.gitignore +++ /dev/null @@ -1 +0,0 @@ -mei-amt-version diff --git a/src/linux/samples/mic/mpssd/.gitignore b/src/linux/samples/mic/mpssd/.gitignore deleted file mode 100644 index 8b7c72f..0000000 --- a/src/linux/samples/mic/mpssd/.gitignore +++ /dev/null @@ -1 +0,0 @@ -mpssd diff --git a/src/linux/samples/seccomp/.gitignore b/src/linux/samples/seccomp/.gitignore deleted file mode 100644 index 78fb781..0000000 --- a/src/linux/samples/seccomp/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -bpf-direct -bpf-fancy -dropper diff --git a/src/linux/samples/timers/.gitignore b/src/linux/samples/timers/.gitignore deleted file mode 100644 index c5c45d7..0000000 --- a/src/linux/samples/timers/.gitignore +++ /dev/null @@ -1 +0,0 @@ -hpet_example diff --git a/src/linux/samples/watchdog/.gitignore b/src/linux/samples/watchdog/.gitignore deleted file mode 100644 index ff0ebb5..0000000 --- a/src/linux/samples/watchdog/.gitignore +++ /dev/null @@ -1 +0,0 @@ -watchdog-simple diff --git a/src/linux/scripts/.gitignore b/src/linux/scripts/.gitignore deleted file mode 100644 index 800da64..0000000 --- a/src/linux/scripts/.gitignore +++ /dev/null @@ -1,18 +0,0 @@ -# -# Generated files -# -conmakehash -kallsyms -kallsyms.exe -pnmtologo -unifdef -unifdef.exe -ihex2fw -recordmcount -docproc -check-lc_ctype -sortextable -asn1_compiler -extract-cert -sign-file -insert-sys-cert diff --git a/src/linux/scripts/Kbuild.include b/src/linux/scripts/Kbuild.include deleted file mode 100644 index 1792198..0000000 --- a/src/linux/scripts/Kbuild.include +++ /dev/null @@ -1,395 +0,0 @@ -#### -# kbuild: Generic definitions - -# Convenient variables -comma := , -quote := " -squote := ' -empty := -space := $(empty) $(empty) -space_escape := _-_SPACE_-_ - -### -# Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o -dot-target = $(dir $@).$(notdir $@) - -### -# The temporary file to save gcc -MD generated dependencies must not -# contain a comma -depfile = $(subst $(comma),_,$(dot-target).d) - -### -# filename of target with directory and extension stripped -basetarget = $(basename $(notdir $@)) - -### -# filename of first prerequisite with directory and extension stripped -baseprereq = $(basename $(notdir $<)) - -### -# Escape single quote for use in echo statements -escsq = $(subst $(squote),'\$(squote)',$1) - -### -# Easy method for doing a status message - kecho := : - quiet_kecho := echo -silent_kecho := : -kecho := $($(quiet)kecho) - -### -# filechk is used to check if the content of a generated file is updated. -# Sample usage: -# define filechk_sample -# echo $KERNELRELEASE -# endef -# version.h : Makefile -# $(call filechk,sample) -# The rule defined shall write to stdout the content of the new file. -# The existing file will be compared with the new one. -# - If no file exist it is created -# - If the content differ the new file is used -# - If they are equal no change, and no timestamp update -# - stdin is piped in from the first prerequisite ($<) so one has -# to specify a valid file as first prerequisite (often the kbuild file) -define filechk - $(Q)set -e; \ - $(kecho) ' CHK $@'; \ - mkdir -p $(dir $@); \ - $(filechk_$(1)) < $< > $@.tmp; \ - if [ -r $@ ] && cmp -s $@ $@.tmp; then \ - rm -f $@.tmp; \ - else \ - $(kecho) ' UPD $@'; \ - mv -f $@.tmp $@; \ - fi -endef - -###### -# gcc support functions -# See documentation in Documentation/kbuild/makefiles.txt - -# cc-cross-prefix -# Usage: CROSS_COMPILE := $(call cc-cross-prefix, m68k-linux-gnu- m68k-linux-) -# Return first prefix where a prefix$(CC) is found in PATH. -# If no $(CC) found in PATH with listed prefixes return nothing -cc-cross-prefix = \ - $(word 1, $(foreach c,$(1), \ - $(shell set -e; \ - if (which $(strip $(c))$(CC)) > /dev/null 2>&1 ; then \ - echo $(c); \ - fi))) - -# output directory for tests below -TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/) - -# try-run -# Usage: option = $(call try-run, $(CC)...-o "$$TMP",option-ok,otherwise) -# Exit code chooses option. "$$TMP" is can be used as temporary file and -# is automatically cleaned up. -try-run = $(shell set -e; \ - TMP="$(TMPOUT).$$$$.tmp"; \ - TMPO="$(TMPOUT).$$$$.o"; \ - if ($(1)) >/dev/null 2>&1; \ - then echo "$(2)"; \ - else echo "$(3)"; \ - fi; \ - rm -f "$$TMP" "$$TMPO") - -# as-option -# Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,) - -as-option = $(call try-run,\ - $(CC) $(KBUILD_CFLAGS) $(1) -c -x assembler /dev/null -o "$$TMP",$(1),$(2)) - -# as-instr -# Usage: cflags-y += $(call as-instr,instr,option1,option2) - -as-instr = $(call try-run,\ - printf "%b\n" "$(1)" | $(CC) $(KBUILD_AFLAGS) -c -x assembler -o "$$TMP" -,$(2),$(3)) - -# Do not attempt to build with gcc plugins during cc-option tests. -# (And this uses delayed resolution so the flags will be up to date.) -CC_OPTION_CFLAGS = $(filter-out $(GCC_PLUGINS_CFLAGS),$(KBUILD_CFLAGS)) - -# cc-option -# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586) - -cc-option = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2)) - -# cc-option-yn -# Usage: flag := $(call cc-option-yn,-march=winchip-c6) -cc-option-yn = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) $(1) -c -x c /dev/null -o "$$TMP",y,n) - -# cc-option-align -# Prefix align with either -falign or -malign -cc-option-align = $(subst -functions=0,,\ - $(call cc-option,-falign-functions=0,-malign-functions=0)) - -# cc-disable-warning -# Usage: cflags-y += $(call cc-disable-warning,unused-but-set-variable) -cc-disable-warning = $(call try-run,\ - $(CC) $(KBUILD_CPPFLAGS) $(CC_OPTION_CFLAGS) -W$(strip $(1)) -c -x c /dev/null -o "$$TMP",-Wno-$(strip $(1))) - -# cc-name -# Expands to either gcc or clang -cc-name = $(shell $(CC) -v 2>&1 | grep -q "clang version" && echo clang || echo gcc) - -# cc-version -cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC)) - -# cc-fullversion -cc-fullversion = $(shell $(CONFIG_SHELL) \ - $(srctree)/scripts/gcc-version.sh -p $(CC)) - -# cc-ifversion -# Usage: EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1) -cc-ifversion = $(shell [ $(cc-version) $(1) $(2) ] && echo $(3) || echo $(4)) - -# cc-ldoption -# Usage: ldflags += $(call cc-ldoption, -Wl$(comma)--hash-style=both) -cc-ldoption = $(call try-run,\ - $(CC) $(1) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2)) - -# ld-option -# Usage: LDFLAGS += $(call ld-option, -X) -ld-option = $(call try-run,\ - $(CC) -x c /dev/null -c -o "$$TMPO" ; $(LD) $(1) "$$TMPO" -o "$$TMP",$(1),$(2)) - -# ar-option -# Usage: KBUILD_ARFLAGS := $(call ar-option,D) -# Important: no spaces around options -ar-option = $(call try-run, $(AR) rc$(1) "$$TMP",$(1),$(2)) - -# ld-version -# Note this is mainly for HJ Lu's 3 number binutil versions -ld-version = $(shell $(LD) --version | $(srctree)/scripts/ld-version.sh) - -# ld-ifversion -# Usage: $(call ld-ifversion, -ge, 22252, y) -ld-ifversion = $(shell [ $(ld-version) $(1) $(2) ] && echo $(3) || echo $(4)) - -###### - -### -# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj= -# Usage: -# $(Q)$(MAKE) $(build)=dir -build := -f $(srctree)/scripts/Makefile.build obj - -### -# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.modbuiltin obj= -# Usage: -# $(Q)$(MAKE) $(modbuiltin)=dir -modbuiltin := -f $(srctree)/scripts/Makefile.modbuiltin obj - -### -# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.dtbinst obj= -# Usage: -# $(Q)$(MAKE) $(dtbinst)=dir -dtbinst := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.dtbinst obj - -### -# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj= -# Usage: -# $(Q)$(MAKE) $(clean)=dir -clean := -f $(srctree)/scripts/Makefile.clean obj - -### -# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.headersinst obj= -# Usage: -# $(Q)$(MAKE) $(hdr-inst)=dir -hdr-inst := -f $(srctree)/scripts/Makefile.headersinst obj - -# Prefix -I with $(srctree) if it is not an absolute path. -# skip if -I has no parameter -addtree = $(if $(patsubst -I%,%,$(1)), \ -$(if $(filter-out -I/% -I./% -I../%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1)),$(1))) - -# Find all -I options and call addtree -flags = $(foreach o,$($(1)),$(if $(filter -I%,$(o)),$(call addtree,$(o)),$(o))) - -# echo command. -# Short version is used, if $(quiet) equals `quiet_', otherwise full one. -echo-cmd = $(if $($(quiet)cmd_$(1)),\ - echo ' $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';) - -# printing commands -cmd = @$(echo-cmd) $(cmd_$(1)) - -# Add $(obj)/ for paths that are not absolute -objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o))) - -### -# if_changed - execute command if any prerequisite is newer than -# target, or command line has changed -# if_changed_dep - as if_changed, but uses fixdep to reveal dependencies -# including used config symbols -# if_changed_rule - as if_changed but execute rule instead -# See Documentation/kbuild/makefiles.txt for more info - -ifneq ($(KBUILD_NOCMDDEP),1) -# Check if both arguments are the same including their order. Result is empty -# string if equal. User may override this check using make KBUILD_NOCMDDEP=1 -arg-check = $(filter-out $(subst $(space),$(space_escape),$(strip $(cmd_$@))), \ - $(subst $(space),$(space_escape),$(strip $(cmd_$1)))) -else -arg-check = $(if $(strip $(cmd_$@)),,1) -endif - -# Replace >$< with >$$< to preserve $ when reloading the .cmd file -# (needed for make) -# Replace >#< with >\#< to avoid starting a comment in the .cmd file -# (needed for make) -# Replace >'< with >'\''< to be able to enclose the whole string in '...' -# (needed for the shell) -make-cmd = $(call escsq,$(subst \#,\\\#,$(subst $$,$$$$,$(cmd_$(1))))) - -# Find any prerequisites that is newer than target or that does not exist. -# PHONY targets skipped in both cases. -any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^) - -# Execute command if command has changed or prerequisite(s) are updated. -# -if_changed = $(if $(strip $(any-prereq) $(arg-check)), \ - @set -e; \ - $(echo-cmd) $(cmd_$(1)); \ - printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd, @:) - -# Execute the command and also postprocess generated .d dependencies file. -if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ), \ - @set -e; \ - $(cmd_and_fixdep), @:) - -ifndef CONFIG_TRIM_UNUSED_KSYMS - -cmd_and_fixdep = \ - $(echo-cmd) $(cmd_$(1)); \ - scripts/basic/fixdep $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp;\ - rm -f $(depfile); \ - mv -f $(dot-target).tmp $(dot-target).cmd; - -else - -# Filter out exported kernel symbol names from the preprocessor output. -# See also __KSYM_DEPS__ in include/linux/export.h. -# We disable the depfile generation here, so as not to overwrite the existing -# depfile while fixdep is parsing it. -flags_nodeps = $(filter-out -Wp$(comma)-M%, $($(1))) -ksym_dep_filter = \ - case "$(1)" in \ - cc_*_c|cpp_i_c) \ - $(CPP) $(call flags_nodeps,c_flags) -D__KSYM_DEPS__ $< ;; \ - as_*_S|cpp_s_S) \ - $(CPP) $(call flags_nodeps,a_flags) -D__KSYM_DEPS__ $< ;; \ - boot*|build*|*cpp_lds_S|dtc|host*|vdso*) : ;; \ - *) echo "Don't know how to preprocess $(1)" >&2; false ;; \ - esac | tr ";" "\n" | sed -rn 's/^.*=== __KSYM_(.*) ===.*$$/KSYM_\1/p' - -cmd_and_fixdep = \ - $(echo-cmd) $(cmd_$(1)); \ - $(ksym_dep_filter) | \ - scripts/basic/fixdep -e $(depfile) $@ '$(make-cmd)' \ - > $(dot-target).tmp; \ - rm -f $(depfile); \ - mv -f $(dot-target).tmp $(dot-target).cmd; - -endif - -# Usage: $(call if_changed_rule,foo) -# Will check if $(cmd_foo) or any of the prerequisites changed, -# and if so will execute $(rule_foo). -if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ), \ - @set -e; \ - $(rule_$(1)), @:) - -### -# why - tell why a a target got build -# enabled by make V=2 -# Output (listed in the order they are checked): -# (1) - due to target is PHONY -# (2) - due to target missing -# (3) - due to: file1.h file2.h -# (4) - due to command line change -# (5) - due to missing .cmd file -# (6) - due to target not in $(targets) -# (1) PHONY targets are always build -# (2) No target, so we better build it -# (3) Prerequisite is newer than target -# (4) The command line stored in the file named dir/.target.cmd -# differed from actual command line. This happens when compiler -# options changes -# (5) No dir/.target.cmd file (used to store command line) -# (6) No dir/.target.cmd file and target not listed in $(targets) -# This is a good hint that there is a bug in the kbuild file -ifeq ($(KBUILD_VERBOSE),2) -why = \ - $(if $(filter $@, $(PHONY)),- due to target is PHONY, \ - $(if $(wildcard $@), \ - $(if $(strip $(any-prereq)),- due to: $(any-prereq), \ - $(if $(arg-check), \ - $(if $(cmd_$@),- due to command line change, \ - $(if $(filter $@, $(targets)), \ - - due to missing .cmd file, \ - - due to $(notdir $@) not in $$(targets) \ - ) \ - ) \ - ) \ - ), \ - - due to target missing \ - ) \ - ) - -echo-why = $(call escsq, $(strip $(why))) -endif - -############################################################################### -# -# When a Kconfig string contains a filename, it is suitable for -# passing to shell commands. It is surrounded by double-quotes, and -# any double-quotes or backslashes within it are escaped by -# backslashes. -# -# This is no use for dependencies or $(wildcard). We need to strip the -# surrounding quotes and the escaping from quotes and backslashes, and -# we *do* need to escape any spaces in the string. So, for example: -# -# Usage: $(eval $(call config_filename,FOO)) -# -# Defines FOO_FILENAME based on the contents of the CONFIG_FOO option, -# transformed as described above to be suitable for use within the -# makefile. -# -# Also, if the filename is a relative filename and exists in the source -# tree but not the build tree, define FOO_SRCPREFIX as $(srctree)/ to -# be prefixed to *both* command invocation and dependencies. -# -# Note: We also print the filenames in the quiet_cmd_foo text, and -# perhaps ought to have a version specially escaped for that purpose. -# But it's only cosmetic, and $(patsubst "%",%,$(CONFIG_FOO)) is good -# enough. It'll strip the quotes in the common case where there's no -# space and it's a simple filename, and it'll retain the quotes when -# there's a space. There are some esoteric cases in which it'll print -# the wrong thing, but we don't really care. The actual dependencies -# and commands *do* get it right, with various combinations of single -# and double quotes, backslashes and spaces in the filenames. -# -############################################################################### -# -define config_filename -ifneq ($$(CONFIG_$(1)),"") -$(1)_FILENAME := $$(subst \\,\,$$(subst \$$(quote),$$(quote),$$(subst $$(space_escape),\$$(space),$$(patsubst "%",%,$$(subst $$(space),$$(space_escape),$$(CONFIG_$(1))))))) -ifneq ($$(patsubst /%,%,$$(firstword $$($(1)_FILENAME))),$$(firstword $$($(1)_FILENAME))) -else -ifeq ($$(wildcard $$($(1)_FILENAME)),) -ifneq ($$(wildcard $$(srctree)/$$($(1)_FILENAME)),) -$(1)_SRCPREFIX := $(srctree)/ -endif -endif -endif -endif -endef -# -############################################################################### diff --git a/src/linux/scripts/Makefile b/src/linux/scripts/Makefile deleted file mode 100644 index 3966074..0000000 --- a/src/linux/scripts/Makefile +++ /dev/null @@ -1,52 +0,0 @@ -### -# scripts contains sources for various helper programs used throughout -# the kernel for the build process. -# --------------------------------------------------------------------------- -# kallsyms: Find all symbols in vmlinux -# pnmttologo: Convert pnm files to logo files -# conmakehash: Create chartable -# conmakehash: Create arrays for initializing the kernel console tables -# docproc: Used in Documentation/DocBook -# check-lc_ctype: Used in Documentation/DocBook - -HOST_EXTRACFLAGS += -I$(srctree)/tools/include - -hostprogs-$(CONFIG_KALLSYMS) += kallsyms -hostprogs-$(CONFIG_LOGO) += pnmtologo -hostprogs-$(CONFIG_VT) += conmakehash -hostprogs-$(BUILD_C_RECORDMCOUNT) += recordmcount -hostprogs-$(CONFIG_BUILDTIME_EXTABLE_SORT) += sortextable -hostprogs-$(CONFIG_ASN1) += asn1_compiler -hostprogs-$(CONFIG_MODULE_SIG) += sign-file -hostprogs-$(CONFIG_SYSTEM_TRUSTED_KEYRING) += extract-cert -hostprogs-$(CONFIG_SYSTEM_EXTRA_CERTIFICATE) += insert-sys-cert - -HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include -HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include -HOSTLOADLIBES_sign-file = -lcrypto -HOSTLOADLIBES_extract-cert = -lcrypto - -always := $(hostprogs-y) $(hostprogs-m) - -# The following hostprogs-y programs are only build on demand -hostprogs-y += unifdef docproc check-lc_ctype - -# These targets are used internally to avoid "is up to date" messages -PHONY += build_unifdef build_docproc build_check-lc_ctype -build_unifdef: $(obj)/unifdef - @: -build_docproc: $(obj)/docproc - @: -build_check-lc_ctype: $(obj)/check-lc_ctype - @: - -subdir-$(CONFIG_MODVERSIONS) += genksyms -ifeq ($(findstring elf,$(if $(CONFIG_OUTPUT_FORMAT),$(CONFIG_OUTPUT_FORMAT),elf)),elf) -subdir-y += mod -endif -subdir-$(CONFIG_SECURITY_SELINUX) += selinux -subdir-$(CONFIG_DTC) += dtc -subdir-$(CONFIG_GDB_SCRIPTS) += gdb - -# Let clean descend into subdirs -subdir- += basic kconfig package gcc-plugins diff --git a/src/linux/scripts/Makefile.asm-generic b/src/linux/scripts/Makefile.asm-generic deleted file mode 100644 index e4d017d..0000000 --- a/src/linux/scripts/Makefile.asm-generic +++ /dev/null @@ -1,38 +0,0 @@ -# include/asm-generic contains a lot of files that are used -# verbatim by several architectures. -# -# This Makefile reads the file arch/$(SRCARCH)/include/asm/Kbuild -# and for each file listed in this file with generic-y creates -# a small wrapper file in $(obj) (arch/$(SRCARCH)/include/generated/asm) - -kbuild-file := $(srctree)/arch/$(SRCARCH)/include/$(src)/Kbuild --include $(kbuild-file) - -include scripts/Kbuild.include - -# Create output directory if not already present -_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj)) - -# Stale wrappers when the corresponding files are removed from generic-y -# need removing. -generated-y := $(generic-y) $(genhdr-y) $(generated-y) -all-files := $(patsubst %, $(obj)/%, $(generated-y)) -old-headers := $(wildcard $(obj)/*.h) -unwanted := $(filter-out $(all-files),$(old-headers)) - -quiet_cmd_wrap = WRAP $@ -cmd_wrap = echo "\#include " >$@ - -quiet_cmd_remove = REMOVE $(unwanted) -cmd_remove = rm -f $(unwanted) - -all: $(patsubst %, $(obj)/%, $(generic-y)) FORCE - $(if $(unwanted),$(call cmd,remove),) - @: - -$(obj)/%.h: - $(call cmd,wrap) - -PHONY += FORCE -.PHONY: $(PHONY) -FORCE: ; diff --git a/src/linux/scripts/Makefile.build b/src/linux/scripts/Makefile.build deleted file mode 100644 index 7675d11..0000000 --- a/src/linux/scripts/Makefile.build +++ /dev/null @@ -1,568 +0,0 @@ -# ========================================================================== -# Building -# ========================================================================== - -src := $(obj) - -PHONY := __build -__build: - -# Init all relevant variables used in kbuild files so -# 1) they have correct type -# 2) they do not inherit any value from the environment -obj-y := -obj-m := -lib-y := -lib-m := -always := -targets := -subdir-y := -subdir-m := -EXTRA_AFLAGS := -EXTRA_CFLAGS := -EXTRA_CPPFLAGS := -EXTRA_LDFLAGS := -asflags-y := -ccflags-y := -cppflags-y := -ldflags-y := - -subdir-asflags-y := -subdir-ccflags-y := - -# Read auto.conf if it exists, otherwise ignore --include include/config/auto.conf - -include scripts/Kbuild.include - -# For backward compatibility check that these variables do not change -save-cflags := $(CFLAGS) - -# The filename Kbuild has precedence over Makefile -kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) -kbuild-file := $(if $(wildcard $(kbuild-dir)/Kbuild),$(kbuild-dir)/Kbuild,$(kbuild-dir)/Makefile) -include $(kbuild-file) - -# If the save-* variables changed error out -ifeq ($(KBUILD_NOPEDANTIC),) - ifneq ("$(save-cflags)","$(CFLAGS)") - $(error CFLAGS was changed in "$(kbuild-file)". Fix it to use ccflags-y) - endif -endif - -include scripts/Makefile.lib - -ifdef host-progs -ifneq ($(hostprogs-y),$(host-progs)) -$(warning kbuild: $(obj)/Makefile - Usage of host-progs is deprecated. Please replace with hostprogs-y!) -hostprogs-y += $(host-progs) -endif -endif - -# Do not include host rules unless needed -ifneq ($(hostprogs-y)$(hostprogs-m)$(hostlibs-y)$(hostlibs-m)$(hostcxxlibs-y)$(hostcxxlibs-m),) -include scripts/Makefile.host -endif - -ifneq ($(KBUILD_SRC),) -# Create output directory if not already present -_dummy := $(shell [ -d $(obj) ] || mkdir -p $(obj)) - -# Create directories for object files if directory does not exist -# Needed when obj-y := dir/file.o syntax is used -_dummy := $(foreach d,$(obj-dirs), $(shell [ -d $(d) ] || mkdir -p $(d))) -endif - -ifndef obj -$(warning kbuild: Makefile.build is included improperly) -endif - -# =========================================================================== - -ifneq ($(strip $(lib-y) $(lib-m) $(lib-)),) -lib-target := $(obj)/lib.a -obj-y += $(obj)/lib-ksyms.o -endif - -ifneq ($(strip $(obj-y) $(obj-m) $(obj-) $(subdir-m) $(lib-target)),) -builtin-target := $(obj)/built-in.o -endif - -modorder-target := $(obj)/modules.order - -# We keep a list of all modules in $(MODVERDIR) - -__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \ - $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \ - $(subdir-ym) $(always) - @: - -# Linus' kernel sanity checking tool -ifneq ($(KBUILD_CHECKSRC),0) - ifeq ($(KBUILD_CHECKSRC),2) - quiet_cmd_force_checksrc = CHECK $< - cmd_force_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ; - else - quiet_cmd_checksrc = CHECK $< - cmd_checksrc = $(CHECK) $(CHECKFLAGS) $(c_flags) $< ; - endif -endif - -# Do section mismatch analysis for each module/built-in.o -ifdef CONFIG_DEBUG_SECTION_MISMATCH - cmd_secanalysis = ; scripts/mod/modpost $@ -endif - -# Compile C sources (.c) -# --------------------------------------------------------------------------- - -# Default is built-in, unless we know otherwise -modkern_cflags = \ - $(if $(part-of-module), \ - $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE), \ - $(KBUILD_CFLAGS_KERNEL) $(CFLAGS_KERNEL)) -quiet_modtag := $(empty) $(empty) - -$(real-objs-m) : part-of-module := y -$(real-objs-m:.o=.i) : part-of-module := y -$(real-objs-m:.o=.s) : part-of-module := y -$(real-objs-m:.o=.lst): part-of-module := y - -$(real-objs-m) : quiet_modtag := [M] -$(real-objs-m:.o=.i) : quiet_modtag := [M] -$(real-objs-m:.o=.s) : quiet_modtag := [M] -$(real-objs-m:.o=.lst): quiet_modtag := [M] - -$(obj-m) : quiet_modtag := [M] - -# Default for not multi-part modules -modname = $(basetarget) - -$(multi-objs-m) : modname = $(modname-multi) -$(multi-objs-m:.o=.i) : modname = $(modname-multi) -$(multi-objs-m:.o=.s) : modname = $(modname-multi) -$(multi-objs-m:.o=.lst) : modname = $(modname-multi) -$(multi-objs-y) : modname = $(modname-multi) -$(multi-objs-y:.o=.i) : modname = $(modname-multi) -$(multi-objs-y:.o=.s) : modname = $(modname-multi) -$(multi-objs-y:.o=.lst) : modname = $(modname-multi) - -quiet_cmd_cc_s_c = CC $(quiet_modtag) $@ -cmd_cc_s_c = $(CC) $(c_flags) $(DISABLE_LTO) -fverbose-asm -S -o $@ $< - -$(obj)/%.s: $(src)/%.c FORCE - $(call if_changed_dep,cc_s_c) - -quiet_cmd_cpp_i_c = CPP $(quiet_modtag) $@ -cmd_cpp_i_c = $(CPP) $(c_flags) -o $@ $< - -$(obj)/%.i: $(src)/%.c FORCE - $(call if_changed_dep,cpp_i_c) - -# These mirror gensymtypes_S and co below, keep them in synch. -cmd_gensymtypes_c = \ - $(CPP) -D__GENKSYMS__ $(c_flags) $< | \ - $(GENKSYMS) $(if $(1), -T $(2)) \ - $(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX)) \ - $(if $(KBUILD_PRESERVE),-p) \ - -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null)) - -quiet_cmd_cc_symtypes_c = SYM $(quiet_modtag) $@ -cmd_cc_symtypes_c = \ - set -e; \ - $(call cmd_gensymtypes_c,true,$@) >/dev/null; \ - test -s $@ || rm -f $@ - -$(obj)/%.symtypes : $(src)/%.c FORCE - $(call cmd,cc_symtypes_c) - -# C (.c) files -# The C file is compiled and updated dependency information is generated. -# (See cmd_cc_o_c + relevant part of rule_cc_o_c) - -quiet_cmd_cc_o_c = CC $(quiet_modtag) $@ - -ifndef CONFIG_MODVERSIONS -cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< - -else -# When module versioning is enabled the following steps are executed: -# o compile a .tmp_.o from .c -# o if .tmp_.o doesn't contain a __ksymtab version, i.e. does -# not export symbols, we just rename .tmp_.o to .o and -# are done. -# o otherwise, we calculate symbol versions using the good old -# genksyms on the preprocessed source and postprocess them in a way -# that they are usable as a linker script -# o generate .o from .tmp_.o using the linker to -# replace the unresolved symbols __crc_exported_symbol with -# the actual value of the checksum generated by genksyms - -cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $< - -cmd_modversions_c = \ - if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ - $(call cmd_gensymtypes_c,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ - > $(@D)/.tmp_$(@F:.o=.ver); \ - \ - $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \ - -T $(@D)/.tmp_$(@F:.o=.ver); \ - rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \ - else \ - mv -f $(@D)/.tmp_$(@F) $@; \ - fi; -endif - -ifdef CONFIG_FTRACE_MCOUNT_RECORD -ifdef BUILD_C_RECORDMCOUNT -ifeq ("$(origin RECORDMCOUNT_WARN)", "command line") - RECORDMCOUNT_FLAGS = -w -endif -# Due to recursion, we must skip empty.o. -# The empty.o file is created in the make process in order to determine -# the target endianness and word size. It is made before all other C -# files, including recordmcount. -sub_cmd_record_mcount = \ - if [ $(@) != "scripts/mod/empty.o" ]; then \ - $(objtree)/scripts/recordmcount $(RECORDMCOUNT_FLAGS) "$(@)"; \ - fi; -recordmcount_source := $(srctree)/scripts/recordmcount.c \ - $(srctree)/scripts/recordmcount.h -else -sub_cmd_record_mcount = set -e ; perl $(srctree)/scripts/recordmcount.pl "$(ARCH)" \ - "$(if $(CONFIG_CPU_BIG_ENDIAN),big,little)" \ - "$(if $(CONFIG_64BIT),64,32)" \ - "$(OBJDUMP)" "$(OBJCOPY)" "$(CC) $(KBUILD_CFLAGS)" \ - "$(LD)" "$(NM)" "$(RM)" "$(MV)" \ - "$(if $(part-of-module),1,0)" "$(@)"; -recordmcount_source := $(srctree)/scripts/recordmcount.pl -endif -cmd_record_mcount = \ - if [ "$(findstring $(CC_FLAGS_FTRACE),$(_c_flags))" = \ - "$(CC_FLAGS_FTRACE)" ]; then \ - $(sub_cmd_record_mcount) \ - fi; -endif - -ifdef CONFIG_STACK_VALIDATION -ifneq ($(SKIP_STACK_VALIDATION),1) - -__objtool_obj := $(objtree)/tools/objtool/objtool - -objtool_args = check -ifndef CONFIG_FRAME_POINTER -objtool_args += --no-fp -endif - -# 'OBJECT_FILES_NON_STANDARD := y': skip objtool checking for a directory -# 'OBJECT_FILES_NON_STANDARD_foo.o := 'y': skip objtool checking for a file -# 'OBJECT_FILES_NON_STANDARD_foo.o := 'n': override directory skip for a file -cmd_objtool = $(if $(patsubst y%,, \ - $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n), \ - $(__objtool_obj) $(objtool_args) "$(@)";) -objtool_obj = $(if $(patsubst y%,, \ - $(OBJECT_FILES_NON_STANDARD_$(basetarget).o)$(OBJECT_FILES_NON_STANDARD)n), \ - $(__objtool_obj)) - -endif # SKIP_STACK_VALIDATION -endif # CONFIG_STACK_VALIDATION - -define rule_cc_o_c - $(call echo-cmd,checksrc) $(cmd_checksrc) \ - $(call cmd_and_fixdep,cc_o_c) \ - $(cmd_modversions_c) \ - $(cmd_objtool) \ - $(call echo-cmd,record_mcount) $(cmd_record_mcount) -endef - -define rule_as_o_S - $(call cmd_and_fixdep,as_o_S) \ - $(cmd_modversions_S) \ - $(cmd_objtool) -endef - -# List module undefined symbols (or empty line if not enabled) -ifdef CONFIG_TRIM_UNUSED_KSYMS -cmd_undef_syms = $(NM) $@ | sed -n 's/^ \+U //p' | xargs echo -else -cmd_undef_syms = echo -endif - -# Built-in and composite module parts -$(obj)/%.o: $(src)/%.c $(recordmcount_source) $(objtool_obj) FORCE - $(call cmd,force_checksrc) - $(call if_changed_rule,cc_o_c) - -# Single-part modules are special since we need to mark them in $(MODVERDIR) - -$(single-used-m): $(obj)/%.o: $(src)/%.c $(recordmcount_source) $(objtool_obj) FORCE - $(call cmd,force_checksrc) - $(call if_changed_rule,cc_o_c) - @{ echo $(@:.o=.ko); echo $@; \ - $(cmd_undef_syms); } > $(MODVERDIR)/$(@F:.o=.mod) - -quiet_cmd_cc_lst_c = MKLST $@ - cmd_cc_lst_c = $(CC) $(c_flags) -g -c -o $*.o $< && \ - $(CONFIG_SHELL) $(srctree)/scripts/makelst $*.o \ - System.map $(OBJDUMP) > $@ - -$(obj)/%.lst: $(src)/%.c FORCE - $(call if_changed_dep,cc_lst_c) - -# Compile assembler sources (.S) -# --------------------------------------------------------------------------- - -modkern_aflags := $(KBUILD_AFLAGS_KERNEL) $(AFLAGS_KERNEL) - -$(real-objs-m) : modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE) -$(real-objs-m:.o=.s): modkern_aflags := $(KBUILD_AFLAGS_MODULE) $(AFLAGS_MODULE) - -# .S file exports must have their C prototypes defined in asm/asm-prototypes.h -# or a file that it includes, in order to get versioned symbols. We build a -# dummy C file that includes asm-prototypes and the EXPORT_SYMBOL lines from -# the .S file (with trailing ';'), and run genksyms on that, to extract vers. -# -# This is convoluted. The .S file must first be preprocessed to run guards and -# expand names, then the resulting exports must be constructed into plain -# EXPORT_SYMBOL(symbol); to build our dummy C file, and that gets preprocessed -# to make the genksyms input. -# -# These mirror gensymtypes_c and co above, keep them in synch. -cmd_gensymtypes_S = \ - (echo "\#include " ; \ - echo "\#include " ; \ - $(CPP) $(a_flags) $< | \ - grep "\<___EXPORT_SYMBOL\>" | \ - sed 's/.*___EXPORT_SYMBOL[[:space:]]*\([a-zA-Z0-9_]*\)[[:space:]]*,.*/EXPORT_SYMBOL(\1);/' ) | \ - $(CPP) -D__GENKSYMS__ $(c_flags) -xc - | \ - $(GENKSYMS) $(if $(1), -T $(2)) \ - $(patsubst y,-s _,$(CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX)) \ - $(if $(KBUILD_PRESERVE),-p) \ - -r $(firstword $(wildcard $(2:.symtypes=.symref) /dev/null)) - -quiet_cmd_cc_symtypes_S = SYM $(quiet_modtag) $@ -cmd_cc_symtypes_S = \ - set -e; \ - $(call cmd_gensymtypes_S,true,$@) >/dev/null; \ - test -s $@ || rm -f $@ - -$(obj)/%.symtypes : $(src)/%.S FORCE - $(call cmd,cc_symtypes_S) - - -quiet_cmd_cpp_s_S = CPP $(quiet_modtag) $@ -cmd_cpp_s_S = $(CPP) $(a_flags) -o $@ $< - -$(obj)/%.s: $(src)/%.S FORCE - $(call if_changed_dep,cpp_s_S) - -quiet_cmd_as_o_S = AS $(quiet_modtag) $@ - -ifndef CONFIG_MODVERSIONS -cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< - -else - -ASM_PROTOTYPES := $(wildcard $(srctree)/arch/$(SRCARCH)/include/asm/asm-prototypes.h) - -ifeq ($(ASM_PROTOTYPES),) -cmd_as_o_S = $(CC) $(a_flags) -c -o $@ $< - -else - -# versioning matches the C process described above, with difference that -# we parse asm-prototypes.h C header to get function definitions. - -cmd_as_o_S = $(CC) $(a_flags) -c -o $(@D)/.tmp_$(@F) $< - -cmd_modversions_S = \ - if $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ - $(call cmd_gensymtypes_S,$(KBUILD_SYMTYPES),$(@:.o=.symtypes)) \ - > $(@D)/.tmp_$(@F:.o=.ver); \ - \ - $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \ - -T $(@D)/.tmp_$(@F:.o=.ver); \ - rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \ - else \ - mv -f $(@D)/.tmp_$(@F) $@; \ - fi; -endif -endif - -$(obj)/%.o: $(src)/%.S $(objtool_obj) FORCE - $(call if_changed_rule,as_o_S) - -targets += $(real-objs-y) $(real-objs-m) $(lib-y) -targets += $(extra-y) $(MAKECMDGOALS) $(always) - -# Linker scripts preprocessor (.lds.S -> .lds) -# --------------------------------------------------------------------------- -quiet_cmd_cpp_lds_S = LDS $@ - cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -C -U$(ARCH) \ - -D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $< - -$(obj)/%.lds: $(src)/%.lds.S FORCE - $(call if_changed_dep,cpp_lds_S) - -# ASN.1 grammar -# --------------------------------------------------------------------------- -quiet_cmd_asn1_compiler = ASN.1 $@ - cmd_asn1_compiler = $(objtree)/scripts/asn1_compiler $< \ - $(subst .h,.c,$@) $(subst .c,.h,$@) - -.PRECIOUS: $(objtree)/$(obj)/%-asn1.c $(objtree)/$(obj)/%-asn1.h - -$(obj)/%-asn1.c $(obj)/%-asn1.h: $(src)/%.asn1 $(objtree)/scripts/asn1_compiler - $(call cmd,asn1_compiler) - -# Build the compiled-in targets -# --------------------------------------------------------------------------- - -# To build objects in subdirs, we need to descend into the directories -$(sort $(subdir-obj-y)): $(subdir-ym) ; - -# -# Rule to compile a set of .o files into one .o file -# -ifdef builtin-target - -ifdef CONFIG_THIN_ARCHIVES - cmd_make_builtin = rm -f $@; $(AR) rcST$(KBUILD_ARFLAGS) - cmd_make_empty_builtin = rm -f $@; $(AR) rcST$(KBUILD_ARFLAGS) - quiet_cmd_link_o_target = AR $@ -else - cmd_make_builtin = $(LD) $(ld_flags) -r -o - cmd_make_empty_builtin = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) - quiet_cmd_link_o_target = LD $@ -endif - -# If the list of objects to link is empty, just create an empty built-in.o -cmd_link_o_target = $(if $(strip $(obj-y)),\ - $(cmd_make_builtin) $@ $(filter $(obj-y), $^) \ - $(cmd_secanalysis),\ - $(cmd_make_empty_builtin) $@) - -$(builtin-target): $(obj-y) FORCE - $(call if_changed,link_o_target) - -targets += $(builtin-target) -endif # builtin-target - -# -# Rule to create modules.order file -# -# Create commands to either record .ko file or cat modules.order from -# a subdirectory -modorder-cmds = \ - $(foreach m, $(modorder), \ - $(if $(filter %/modules.order, $m), \ - cat $m;, echo kernel/$m;)) - -$(modorder-target): $(subdir-ym) FORCE - $(Q)(cat /dev/null; $(modorder-cmds)) > $@ - -# -# Rule to compile a set of .o files into one .a file -# -ifdef lib-target -quiet_cmd_link_l_target = AR $@ - -ifdef CONFIG_THIN_ARCHIVES - cmd_link_l_target = rm -f $@; $(AR) rcsT$(KBUILD_ARFLAGS) $@ $(lib-y) -else - cmd_link_l_target = rm -f $@; $(AR) rcs$(KBUILD_ARFLAGS) $@ $(lib-y) -endif - -$(lib-target): $(lib-y) FORCE - $(call if_changed,link_l_target) - -targets += $(lib-target) - -dummy-object = $(obj)/.lib_exports.o -ksyms-lds = $(dot-target).lds -ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX -ref_prefix = EXTERN(_ -else -ref_prefix = EXTERN( -endif - -quiet_cmd_export_list = EXPORTS $@ -cmd_export_list = $(OBJDUMP) -h $< | \ - sed -ne '/___ksymtab/{s/.*+/$(ref_prefix)/;s/ .*/)/;p}' >$(ksyms-lds);\ - rm -f $(dummy-object);\ - $(AR) rcs$(KBUILD_ARFLAGS) $(dummy-object);\ - $(LD) $(ld_flags) -r -o $@ -T $(ksyms-lds) $(dummy-object);\ - rm $(dummy-object) $(ksyms-lds) - -$(obj)/lib-ksyms.o: $(lib-target) FORCE - $(call if_changed,export_list) - -targets += $(obj)/lib-ksyms.o - -endif - -# -# Rule to link composite objects -# -# Composite objects are specified in kbuild makefile as follows: -# -objs := -# or -# -y := -# or -# -m := -# The -m syntax only works if is a module -link_multi_deps = \ -$(filter $(addprefix $(obj)/, \ -$($(subst $(obj)/,,$(@:.o=-objs))) \ -$($(subst $(obj)/,,$(@:.o=-y))) \ -$($(subst $(obj)/,,$(@:.o=-m)))), $^) - -quiet_cmd_link_multi-y = LD $@ -cmd_link_multi-y = $(LD) $(ld_flags) -r -o $@ $(link_multi_deps) $(cmd_secanalysis) - -quiet_cmd_link_multi-m = LD [M] $@ -cmd_link_multi-m = $(cmd_link_multi-y) - -$(multi-used-y): FORCE - $(call if_changed,link_multi-y) -$(call multi_depend, $(multi-used-y), .o, -objs -y) - -$(multi-used-m): FORCE - $(call if_changed,link_multi-m) - @{ echo $(@:.o=.ko); echo $(link_multi_deps); \ - $(cmd_undef_syms); } > $(MODVERDIR)/$(@F:.o=.mod) -$(call multi_depend, $(multi-used-m), .o, -objs -y -m) - -targets += $(multi-used-y) $(multi-used-m) - - -# Descending -# --------------------------------------------------------------------------- - -PHONY += $(subdir-ym) -$(subdir-ym): - $(Q)$(MAKE) $(build)=$@ - -# Add FORCE to the prequisites of a target to force it to be always rebuilt. -# --------------------------------------------------------------------------- - -PHONY += FORCE - -FORCE: - -# Read all saved command lines and dependencies for the $(targets) we -# may be building above, using $(if_changed{,_dep}). As an -# optimization, we don't need to read them if the target does not -# exist, we will rebuild anyway in that case. - -targets := $(wildcard $(sort $(targets))) -cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd)) - -ifneq ($(cmd_files),) - include $(cmd_files) -endif - -# Declare the contents of the .PHONY variable as phony. We keep that -# information in a variable se we can use it in if_changed and friends. - -.PHONY: $(PHONY) diff --git a/src/linux/scripts/Makefile.extrawarn b/src/linux/scripts/Makefile.extrawarn deleted file mode 100644 index 7c321a6..0000000 --- a/src/linux/scripts/Makefile.extrawarn +++ /dev/null @@ -1,72 +0,0 @@ -# ========================================================================== -# -# make W=... settings -# -# W=1 - warnings that may be relevant and does not occur too often -# W=2 - warnings that occur quite often but may still be relevant -# W=3 - the more obscure warnings, can most likely be ignored -# -# $(call cc-option, -W...) handles gcc -W.. options which -# are not supported by all versions of the compiler -# ========================================================================== - -ifeq ("$(origin W)", "command line") - export KBUILD_ENABLE_EXTRA_GCC_CHECKS := $(W) -endif - -ifdef KBUILD_ENABLE_EXTRA_GCC_CHECKS -warning- := $(empty) - -warning-1 := -Wextra -Wunused -Wno-unused-parameter -warning-1 += -Wmissing-declarations -warning-1 += -Wmissing-format-attribute -warning-1 += $(call cc-option, -Wmissing-prototypes) -warning-1 += -Wold-style-definition -warning-1 += $(call cc-option, -Wmissing-include-dirs) -warning-1 += $(call cc-option, -Wunused-but-set-variable) -warning-1 += $(call cc-option, -Wunused-const-variable) -warning-1 += $(call cc-disable-warning, missing-field-initializers) -warning-1 += $(call cc-disable-warning, sign-compare) - -warning-2 := -Waggregate-return -warning-2 += -Wcast-align -warning-2 += -Wdisabled-optimization -warning-2 += -Wnested-externs -warning-2 += -Wshadow -warning-2 += $(call cc-option, -Wlogical-op) -warning-2 += $(call cc-option, -Wmissing-field-initializers) -warning-2 += $(call cc-option, -Wsign-compare) -warning-2 += $(call cc-option, -Wmaybe-uninitialized) - -warning-3 := -Wbad-function-cast -warning-3 += -Wcast-qual -warning-3 += -Wconversion -warning-3 += -Wpacked -warning-3 += -Wpadded -warning-3 += -Wpointer-arith -warning-3 += -Wredundant-decls -warning-3 += -Wswitch-default -warning-3 += $(call cc-option, -Wpacked-bitfield-compat) -warning-3 += $(call cc-option, -Wvla) - -warning := $(warning-$(findstring 1, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) -warning += $(warning-$(findstring 2, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) -warning += $(warning-$(findstring 3, $(KBUILD_ENABLE_EXTRA_GCC_CHECKS))) - -ifeq ("$(strip $(warning))","") - $(error W=$(KBUILD_ENABLE_EXTRA_GCC_CHECKS) is unknown) -endif - -KBUILD_CFLAGS += $(warning) -else - -ifeq ($(cc-name),clang) -KBUILD_CFLAGS += $(call cc-disable-warning, initializer-overrides) -KBUILD_CFLAGS += $(call cc-disable-warning, unused-value) -KBUILD_CFLAGS += $(call cc-disable-warning, format) -KBUILD_CFLAGS += $(call cc-disable-warning, unknown-warning-option) -KBUILD_CFLAGS += $(call cc-disable-warning, sign-compare) -KBUILD_CFLAGS += $(call cc-disable-warning, format-zero-length) -KBUILD_CFLAGS += $(call cc-disable-warning, uninitialized) -endif -endif diff --git a/src/linux/scripts/Makefile.gcc-plugins b/src/linux/scripts/Makefile.gcc-plugins deleted file mode 100644 index 060d2cb..0000000 --- a/src/linux/scripts/Makefile.gcc-plugins +++ /dev/null @@ -1,67 +0,0 @@ -ifdef CONFIG_GCC_PLUGINS - __PLUGINCC := $(call cc-ifversion, -ge, 0408, $(HOSTCXX), $(HOSTCC)) - PLUGINCC := $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-plugin.sh "$(__PLUGINCC)" "$(HOSTCXX)" "$(CC)") - - SANCOV_PLUGIN := -fplugin=$(objtree)/scripts/gcc-plugins/sancov_plugin.so - - gcc-plugin-$(CONFIG_GCC_PLUGIN_CYC_COMPLEXITY) += cyc_complexity_plugin.so - - gcc-plugin-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) += latent_entropy_plugin.so - gcc-plugin-cflags-$(CONFIG_GCC_PLUGIN_LATENT_ENTROPY) += -DLATENT_ENTROPY_PLUGIN - ifdef CONFIG_PAX_LATENT_ENTROPY - DISABLE_LATENT_ENTROPY_PLUGIN += -fplugin-arg-latent_entropy_plugin-disable - endif - - ifdef CONFIG_GCC_PLUGIN_SANCOV - ifeq ($(CFLAGS_KCOV),) - # It is needed because of the gcc-plugin.sh and gcc version checks. - gcc-plugin-$(CONFIG_GCC_PLUGIN_SANCOV) += sancov_plugin.so - - ifneq ($(PLUGINCC),) - CFLAGS_KCOV := $(SANCOV_PLUGIN) - else - $(warning warning: cannot use CONFIG_KCOV: -fsanitize-coverage=trace-pc is not supported by compiler) - endif - endif - endif - - GCC_PLUGINS_CFLAGS := $(strip $(addprefix -fplugin=$(objtree)/scripts/gcc-plugins/, $(gcc-plugin-y)) $(gcc-plugin-cflags-y)) - - export PLUGINCC GCC_PLUGINS_CFLAGS GCC_PLUGIN GCC_PLUGIN_SUBDIR - export SANCOV_PLUGIN DISABLE_LATENT_ENTROPY_PLUGIN - - ifneq ($(PLUGINCC),) - # SANCOV_PLUGIN can be only in CFLAGS_KCOV because avoid duplication. - GCC_PLUGINS_CFLAGS := $(filter-out $(SANCOV_PLUGIN), $(GCC_PLUGINS_CFLAGS)) - endif - - KBUILD_CFLAGS += $(GCC_PLUGINS_CFLAGS) - GCC_PLUGIN := $(gcc-plugin-y) - GCC_PLUGIN_SUBDIR := $(gcc-plugin-subdir-y) -endif - -# If plugins aren't supported, abort the build before hard-to-read compiler -# errors start getting spewed by the main build. -PHONY += gcc-plugins-check -gcc-plugins-check: FORCE -ifdef CONFIG_GCC_PLUGINS - ifeq ($(PLUGINCC),) - ifneq ($(GCC_PLUGINS_CFLAGS),) - ifeq ($(call cc-ifversion, -ge, 0405, y), y) - $(Q)$(srctree)/scripts/gcc-plugin.sh --show-error "$(__PLUGINCC)" "$(HOSTCXX)" "$(CC)" || true - @echo "Cannot use CONFIG_GCC_PLUGINS: your gcc installation does not support plugins, perhaps the necessary headers are missing?" >&2 && exit 1 - else - @echo "Cannot use CONFIG_GCC_PLUGINS: your gcc version does not support plugins, you should upgrade it to at least gcc 4.5" >&2 && exit 1 - endif - endif - endif -endif - @: - -# Actually do the build, if requested. -PHONY += gcc-plugins -gcc-plugins: scripts_basic gcc-plugins-check -ifdef CONFIG_GCC_PLUGINS - $(Q)$(MAKE) $(build)=scripts/gcc-plugins -endif - @: diff --git a/src/linux/scripts/Makefile.host b/src/linux/scripts/Makefile.host deleted file mode 100644 index 45b5b1a..0000000 --- a/src/linux/scripts/Makefile.host +++ /dev/null @@ -1,181 +0,0 @@ -# ========================================================================== -# Building binaries on the host system -# Binaries are used during the compilation of the kernel, for example -# to preprocess a data file. -# -# Both C and C++ are supported, but preferred language is C for such utilities. -# -# Sample syntax (see Documentation/kbuild/makefiles.txt for reference) -# hostprogs-y := bin2hex -# Will compile bin2hex.c and create an executable named bin2hex -# -# hostprogs-y := lxdialog -# lxdialog-objs := checklist.o lxdialog.o -# Will compile lxdialog.c and checklist.c, and then link the executable -# lxdialog, based on checklist.o and lxdialog.o -# -# hostprogs-y := qconf -# qconf-cxxobjs := qconf.o -# qconf-objs := menu.o -# Will compile qconf as a C++ program, and menu as a C program. -# They are linked as C++ code to the executable qconf - -# hostcc-option -# Usage: cflags-y += $(call hostcc-option,-march=winchip-c6,-march=i586) - -hostcc-option = $(call try-run,\ - $(HOSTCC) $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) $(1) -c -x c /dev/null -o "$$TMP",$(1),$(2)) - -__hostprogs := $(sort $(hostprogs-y) $(hostprogs-m)) -host-cshlib := $(sort $(hostlibs-y) $(hostlibs-m)) -host-cxxshlib := $(sort $(hostcxxlibs-y) $(hostcxxlibs-m)) - -# C code -# Executables compiled from a single .c file -host-csingle := $(foreach m,$(__hostprogs), \ - $(if $($(m)-objs)$($(m)-cxxobjs),,$(m))) - -# C executables linked based on several .o files -host-cmulti := $(foreach m,$(__hostprogs),\ - $(if $($(m)-cxxobjs),,$(if $($(m)-objs),$(m)))) - -# Object (.o) files compiled from .c files -host-cobjs := $(sort $(foreach m,$(__hostprogs),$($(m)-objs))) - -# C++ code -# C++ executables compiled from at least one .cc file -# and zero or more .c files -host-cxxmulti := $(foreach m,$(__hostprogs),$(if $($(m)-cxxobjs),$(m))) - -# C++ Object (.o) files compiled from .cc files -host-cxxobjs := $(sort $(foreach m,$(host-cxxmulti),$($(m)-cxxobjs))) - -# Object (.o) files used by the shared libaries -host-cshobjs := $(sort $(foreach m,$(host-cshlib),$($(m:.so=-objs)))) -host-cxxshobjs := $(sort $(foreach m,$(host-cxxshlib),$($(m:.so=-objs)))) - -# output directory for programs/.o files -# hostprogs-y := tools/build may have been specified. -# Retrieve also directory of .o files from prog-objs or prog-cxxobjs notation -host-objdirs := $(dir $(__hostprogs) $(host-cobjs) $(host-cxxobjs)) - -host-objdirs := $(strip $(sort $(filter-out ./,$(host-objdirs)))) - - -__hostprogs := $(addprefix $(obj)/,$(__hostprogs)) -host-csingle := $(addprefix $(obj)/,$(host-csingle)) -host-cmulti := $(addprefix $(obj)/,$(host-cmulti)) -host-cobjs := $(addprefix $(obj)/,$(host-cobjs)) -host-cxxmulti := $(addprefix $(obj)/,$(host-cxxmulti)) -host-cxxobjs := $(addprefix $(obj)/,$(host-cxxobjs)) -host-cshlib := $(addprefix $(obj)/,$(host-cshlib)) -host-cxxshlib := $(addprefix $(obj)/,$(host-cxxshlib)) -host-cshobjs := $(addprefix $(obj)/,$(host-cshobjs)) -host-cxxshobjs := $(addprefix $(obj)/,$(host-cxxshobjs)) -host-objdirs := $(addprefix $(obj)/,$(host-objdirs)) - -obj-dirs += $(host-objdirs) - -##### -# Handle options to gcc. Support building with separate output directory - -_hostc_flags = $(HOSTCFLAGS) $(HOST_EXTRACFLAGS) \ - $(HOSTCFLAGS_$(basetarget).o) -_hostcxx_flags = $(HOSTCXXFLAGS) $(HOST_EXTRACXXFLAGS) \ - $(HOSTCXXFLAGS_$(basetarget).o) - -ifeq ($(KBUILD_SRC),) -__hostc_flags = $(_hostc_flags) -__hostcxx_flags = $(_hostcxx_flags) -else -__hostc_flags = -I$(obj) $(call flags,_hostc_flags) -__hostcxx_flags = -I$(obj) $(call flags,_hostcxx_flags) -endif - -hostc_flags = -Wp,-MD,$(depfile) $(__hostc_flags) -hostcxx_flags = -Wp,-MD,$(depfile) $(__hostcxx_flags) - -##### -# Compile programs on the host - -# Create executable from a single .c file -# host-csingle -> Executable -quiet_cmd_host-csingle = HOSTCC $@ - cmd_host-csingle = $(HOSTCC) $(hostc_flags) -o $@ $< \ - $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) -$(host-csingle): $(obj)/%: $(src)/%.c FORCE - $(call if_changed_dep,host-csingle) - -# Link an executable based on list of .o files, all plain c -# host-cmulti -> executable -quiet_cmd_host-cmulti = HOSTLD $@ - cmd_host-cmulti = $(HOSTCC) $(HOSTLDFLAGS) -o $@ \ - $(addprefix $(obj)/,$($(@F)-objs)) \ - $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) -$(host-cmulti): FORCE - $(call if_changed,host-cmulti) -$(call multi_depend, $(host-cmulti), , -objs) - -# Create .o file from a single .c file -# host-cobjs -> .o -quiet_cmd_host-cobjs = HOSTCC $@ - cmd_host-cobjs = $(HOSTCC) $(hostc_flags) -c -o $@ $< -$(host-cobjs): $(obj)/%.o: $(src)/%.c FORCE - $(call if_changed_dep,host-cobjs) - -# Link an executable based on list of .o files, a mixture of .c and .cc -# host-cxxmulti -> executable -quiet_cmd_host-cxxmulti = HOSTLD $@ - cmd_host-cxxmulti = $(HOSTCXX) $(HOSTLDFLAGS) -o $@ \ - $(foreach o,objs cxxobjs,\ - $(addprefix $(obj)/,$($(@F)-$(o)))) \ - $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) -$(host-cxxmulti): FORCE - $(call if_changed,host-cxxmulti) -$(call multi_depend, $(host-cxxmulti), , -objs -cxxobjs) - -# Create .o file from a single .cc (C++) file -quiet_cmd_host-cxxobjs = HOSTCXX $@ - cmd_host-cxxobjs = $(HOSTCXX) $(hostcxx_flags) -c -o $@ $< -$(host-cxxobjs): $(obj)/%.o: $(src)/%.cc FORCE - $(call if_changed_dep,host-cxxobjs) - -# Compile .c file, create position independent .o file -# host-cshobjs -> .o -quiet_cmd_host-cshobjs = HOSTCC -fPIC $@ - cmd_host-cshobjs = $(HOSTCC) $(hostc_flags) -fPIC -c -o $@ $< -$(host-cshobjs): $(obj)/%.o: $(src)/%.c FORCE - $(call if_changed_dep,host-cshobjs) - -# Compile .c file, create position independent .o file -# Note that plugin capable gcc versions can be either C or C++ based -# therefore plugin source files have to be compilable in both C and C++ mode. -# This is why a C++ compiler is invoked on a .c file. -# host-cxxshobjs -> .o -quiet_cmd_host-cxxshobjs = HOSTCXX -fPIC $@ - cmd_host-cxxshobjs = $(HOSTCXX) $(hostcxx_flags) -fPIC -c -o $@ $< -$(host-cxxshobjs): $(obj)/%.o: $(src)/%.c FORCE - $(call if_changed_dep,host-cxxshobjs) - -# Link a shared library, based on position independent .o files -# *.o -> .so shared library (host-cshlib) -quiet_cmd_host-cshlib = HOSTLLD -shared $@ - cmd_host-cshlib = $(HOSTCC) $(HOSTLDFLAGS) -shared -o $@ \ - $(addprefix $(obj)/,$($(@F:.so=-objs))) \ - $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) -$(host-cshlib): FORCE - $(call if_changed,host-cshlib) -$(call multi_depend, $(host-cshlib), .so, -objs) - -# Link a shared library, based on position independent .o files -# *.o -> .so shared library (host-cxxshlib) -quiet_cmd_host-cxxshlib = HOSTLLD -shared $@ - cmd_host-cxxshlib = $(HOSTCXX) $(HOSTLDFLAGS) -shared -o $@ \ - $(addprefix $(obj)/,$($(@F:.so=-objs))) \ - $(HOST_LOADLIBES) $(HOSTLOADLIBES_$(@F)) -$(host-cxxshlib): FORCE - $(call if_changed,host-cxxshlib) -$(call multi_depend, $(host-cxxshlib), .so, -objs) - -targets += $(host-csingle) $(host-cmulti) $(host-cobjs)\ - $(host-cxxmulti) $(host-cxxobjs) $(host-cshlib) $(host-cshobjs) $(host-cxxshlib) $(host-cxxshobjs) diff --git a/src/linux/scripts/Makefile.kasan b/src/linux/scripts/Makefile.kasan deleted file mode 100644 index 37323b0..0000000 --- a/src/linux/scripts/Makefile.kasan +++ /dev/null @@ -1,31 +0,0 @@ -ifdef CONFIG_KASAN -ifdef CONFIG_KASAN_INLINE - call_threshold := 10000 -else - call_threshold := 0 -endif - -KASAN_SHADOW_OFFSET ?= $(CONFIG_KASAN_SHADOW_OFFSET) - -CFLAGS_KASAN_MINIMAL := -fsanitize=kernel-address - -CFLAGS_KASAN := $(call cc-option, -fsanitize=kernel-address \ - -fasan-shadow-offset=$(KASAN_SHADOW_OFFSET) \ - --param asan-stack=1 --param asan-globals=1 \ - --param asan-instrumentation-with-call-threshold=$(call_threshold)) - -ifeq ($(call cc-option, $(CFLAGS_KASAN_MINIMAL) -Werror),) - ifneq ($(CONFIG_COMPILE_TEST),y) - $(warning Cannot use CONFIG_KASAN: \ - -fsanitize=kernel-address is not supported by compiler) - endif -else - ifeq ($(CFLAGS_KASAN),) - ifneq ($(CONFIG_COMPILE_TEST),y) - $(warning CONFIG_KASAN: compiler does not support all options.\ - Trying minimal configuration) - endif - CFLAGS_KASAN := $(CFLAGS_KASAN_MINIMAL) - endif -endif -endif diff --git a/src/linux/scripts/Makefile.lib b/src/linux/scripts/Makefile.lib deleted file mode 100644 index 0a07f90..0000000 --- a/src/linux/scripts/Makefile.lib +++ /dev/null @@ -1,410 +0,0 @@ -# Backward compatibility -asflags-y += $(EXTRA_AFLAGS) -ccflags-y += $(EXTRA_CFLAGS) -cppflags-y += $(EXTRA_CPPFLAGS) -ldflags-y += $(EXTRA_LDFLAGS) - -# -# flags that take effect in sub directories -export KBUILD_SUBDIR_ASFLAGS := $(KBUILD_SUBDIR_ASFLAGS) $(subdir-asflags-y) -export KBUILD_SUBDIR_CCFLAGS := $(KBUILD_SUBDIR_CCFLAGS) $(subdir-ccflags-y) - -# Figure out what we need to build from the various variables -# =========================================================================== - -# When an object is listed to be built compiled-in and modular, -# only build the compiled-in version - -obj-m := $(filter-out $(obj-y),$(obj-m)) - -# Libraries are always collected in one lib file. -# Filter out objects already built-in - -lib-y := $(filter-out $(obj-y), $(sort $(lib-y) $(lib-m))) - - -# Handle objects in subdirs -# --------------------------------------------------------------------------- -# o if we encounter foo/ in $(obj-y), replace it by foo/built-in.o -# and add the directory to the list of dirs to descend into: $(subdir-y) -# o if we encounter foo/ in $(obj-m), remove it from $(obj-m) -# and add the directory to the list of dirs to descend into: $(subdir-m) - -# Determine modorder. -# Unfortunately, we don't have information about ordering between -y -# and -m subdirs. Just put -y's first. -modorder := $(patsubst %/,%/modules.order, $(filter %/, $(obj-y)) $(obj-m:.o=.ko)) - -__subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y))) -subdir-y += $(__subdir-y) -__subdir-m := $(patsubst %/,%,$(filter %/, $(obj-m))) -subdir-m += $(__subdir-m) -obj-y := $(patsubst %/, %/built-in.o, $(obj-y)) -obj-m := $(filter-out %/, $(obj-m)) - -# Subdirectories we need to descend into - -subdir-ym := $(sort $(subdir-y) $(subdir-m)) - -# if $(foo-objs) exists, foo.o is a composite object -multi-used-y := $(sort $(foreach m,$(obj-y), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))), $(m)))) -multi-used-m := $(sort $(foreach m,$(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m))), $(m)))) -multi-used := $(multi-used-y) $(multi-used-m) -single-used-m := $(sort $(filter-out $(multi-used-m),$(obj-m))) - -# Build list of the parts of our composite objects, our composite -# objects depend on those (obviously) -multi-objs-y := $(foreach m, $(multi-used-y), $($(m:.o=-objs)) $($(m:.o=-y))) -multi-objs-m := $(foreach m, $(multi-used-m), $($(m:.o=-objs)) $($(m:.o=-y))) -multi-objs := $(multi-objs-y) $(multi-objs-m) - -# $(subdir-obj-y) is the list of objects in $(obj-y) which uses dir/ to -# tell kbuild to descend -subdir-obj-y := $(filter %/built-in.o, $(obj-y)) - -# $(obj-dirs) is a list of directories that contain object files -obj-dirs := $(dir $(multi-objs) $(obj-y)) - -# Replace multi-part objects by their individual parts, look at local dir only -real-objs-y := $(foreach m, $(filter-out $(subdir-obj-y), $(obj-y)), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y))),$($(m:.o=-objs)) $($(m:.o=-y)),$(m))) $(extra-y) -real-objs-m := $(foreach m, $(obj-m), $(if $(strip $($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m))),$($(m:.o=-objs)) $($(m:.o=-y)) $($(m:.o=-m)),$(m))) - -# Add subdir path - -extra-y := $(addprefix $(obj)/,$(extra-y)) -always := $(addprefix $(obj)/,$(always)) -targets := $(addprefix $(obj)/,$(targets)) -modorder := $(addprefix $(obj)/,$(modorder)) -obj-y := $(addprefix $(obj)/,$(obj-y)) -obj-m := $(addprefix $(obj)/,$(obj-m)) -lib-y := $(addprefix $(obj)/,$(lib-y)) -subdir-obj-y := $(addprefix $(obj)/,$(subdir-obj-y)) -real-objs-y := $(addprefix $(obj)/,$(real-objs-y)) -real-objs-m := $(addprefix $(obj)/,$(real-objs-m)) -single-used-m := $(addprefix $(obj)/,$(single-used-m)) -multi-used-y := $(addprefix $(obj)/,$(multi-used-y)) -multi-used-m := $(addprefix $(obj)/,$(multi-used-m)) -multi-objs-y := $(addprefix $(obj)/,$(multi-objs-y)) -multi-objs-m := $(addprefix $(obj)/,$(multi-objs-m)) -subdir-ym := $(addprefix $(obj)/,$(subdir-ym)) -obj-dirs := $(addprefix $(obj)/,$(obj-dirs)) - -# These flags are needed for modversions and compiling, so we define them here -# already -# $(modname_flags) #defines KBUILD_MODNAME as the name of the module it will -# end up in (or would, if it gets compiled in) -# Note: Files that end up in two or more modules are compiled without the -# KBUILD_MODNAME definition. The reason is that any made-up name would -# differ in different configs. -name-fix = $(squote)$(quote)$(subst $(comma),_,$(subst -,_,$1))$(quote)$(squote) -basename_flags = -DKBUILD_BASENAME=$(call name-fix,$(basetarget)) -modname_flags = $(if $(filter 1,$(words $(modname))),\ - -DKBUILD_MODNAME=$(call name-fix,$(modname))) - -orig_c_flags = $(KBUILD_CPPFLAGS) $(KBUILD_CFLAGS) $(KBUILD_SUBDIR_CCFLAGS) \ - $(ccflags-y) $(CFLAGS_$(basetarget).o) -_c_flags = $(filter-out $(CFLAGS_REMOVE_$(basetarget).o), $(orig_c_flags)) -orig_a_flags = $(KBUILD_CPPFLAGS) $(KBUILD_AFLAGS) $(KBUILD_SUBDIR_ASFLAGS) \ - $(asflags-y) $(AFLAGS_$(basetarget).o) -_a_flags = $(filter-out $(AFLAGS_REMOVE_$(basetarget).o), $(orig_a_flags)) -_cpp_flags = $(KBUILD_CPPFLAGS) $(cppflags-y) $(CPPFLAGS_$(@F)) - -# -# Enable gcov profiling flags for a file, directory or for all files depending -# on variables GCOV_PROFILE_obj.o, GCOV_PROFILE and CONFIG_GCOV_PROFILE_ALL -# (in this order) -# -ifeq ($(CONFIG_GCOV_KERNEL),y) -_c_flags += $(if $(patsubst n%,, \ - $(GCOV_PROFILE_$(basetarget).o)$(GCOV_PROFILE)$(CONFIG_GCOV_PROFILE_ALL)), \ - $(CFLAGS_GCOV)) -endif - -# -# Enable address sanitizer flags for kernel except some files or directories -# we don't want to check (depends on variables KASAN_SANITIZE_obj.o, KASAN_SANITIZE) -# -ifeq ($(CONFIG_KASAN),y) -_c_flags += $(if $(patsubst n%,, \ - $(KASAN_SANITIZE_$(basetarget).o)$(KASAN_SANITIZE)y), \ - $(CFLAGS_KASAN)) -endif - -ifeq ($(CONFIG_UBSAN),y) -_c_flags += $(if $(patsubst n%,, \ - $(UBSAN_SANITIZE_$(basetarget).o)$(UBSAN_SANITIZE)$(CONFIG_UBSAN_SANITIZE_ALL)), \ - $(CFLAGS_UBSAN)) -endif - -ifeq ($(CONFIG_KCOV),y) -_c_flags += $(if $(patsubst n%,, \ - $(KCOV_INSTRUMENT_$(basetarget).o)$(KCOV_INSTRUMENT)$(CONFIG_KCOV_INSTRUMENT_ALL)), \ - $(CFLAGS_KCOV)) -endif - -# If building the kernel in a separate objtree expand all occurrences -# of -Idir to -I$(srctree)/dir except for absolute paths (starting with '/'). - -ifeq ($(KBUILD_SRC),) -__c_flags = $(_c_flags) -__a_flags = $(_a_flags) -__cpp_flags = $(_cpp_flags) -else - -# -I$(obj) locates generated .h files -# $(call addtree,-I$(obj)) locates .h files in srctree, from generated .c files -# and locates generated .h files -# FIXME: Replace both with specific CFLAGS* statements in the makefiles -__c_flags = $(if $(obj),-I$(srctree)/$(src) -I$(obj)) \ - $(call flags,_c_flags) -__a_flags = $(call flags,_a_flags) -__cpp_flags = $(call flags,_cpp_flags) -endif - -c_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ - $(__c_flags) $(modkern_cflags) \ - $(basename_flags) $(modname_flags) - -a_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ - $(__a_flags) $(modkern_aflags) - -cpp_flags = -Wp,-MD,$(depfile) $(NOSTDINC_FLAGS) $(LINUXINCLUDE) \ - $(__cpp_flags) - -ld_flags = $(LDFLAGS) $(ldflags-y) - -dtc_cpp_flags = -Wp,-MD,$(depfile).pre.tmp -nostdinc \ - -I$(srctree)/arch/$(SRCARCH)/boot/dts \ - -I$(srctree)/arch/$(SRCARCH)/boot/dts/include \ - -I$(srctree)/drivers/of/testcase-data \ - -undef -D__DTS__ - -# Finds the multi-part object the current object will be linked into -modname-multi = $(sort $(foreach m,$(multi-used),\ - $(if $(filter $(subst $(obj)/,,$*.o), $($(m:.o=-objs)) $($(m:.o=-y))),$(m:.o=)))) - -# Useful for describing the dependency of composite objects -# Usage: -# $(call multi_depend, multi_used_targets, suffix_to_remove, suffix_to_add) -define multi_depend -$(foreach m, $(notdir $1), \ - $(eval $(obj)/$m: \ - $(addprefix $(obj)/, $(foreach s, $3, $($(m:%$(strip $2)=%$(s))))))) -endef - -ifdef REGENERATE_PARSERS - -# GPERF -# --------------------------------------------------------------------------- -quiet_cmd_gperf = GPERF $@ - cmd_gperf = gperf -t --output-file $@ -a -C -E -g -k 1,3,$$ -p -t $< - -.PRECIOUS: $(src)/%.hash.c_shipped -$(src)/%.hash.c_shipped: $(src)/%.gperf - $(call cmd,gperf) - -# LEX -# --------------------------------------------------------------------------- -LEX_PREFIX = $(if $(LEX_PREFIX_${baseprereq}),$(LEX_PREFIX_${baseprereq}),yy) - -quiet_cmd_flex = LEX $@ - cmd_flex = flex -o$@ -L -P $(LEX_PREFIX) $< - -.PRECIOUS: $(src)/%.lex.c_shipped -$(src)/%.lex.c_shipped: $(src)/%.l - $(call cmd,flex) - -# YACC -# --------------------------------------------------------------------------- -YACC_PREFIX = $(if $(YACC_PREFIX_${baseprereq}),$(YACC_PREFIX_${baseprereq}),yy) - -quiet_cmd_bison = YACC $@ - cmd_bison = bison -o$@ -t -l -p $(YACC_PREFIX) $< - -.PRECIOUS: $(src)/%.tab.c_shipped -$(src)/%.tab.c_shipped: $(src)/%.y - $(call cmd,bison) - -quiet_cmd_bison_h = YACC $@ - cmd_bison_h = bison -o/dev/null --defines=$@ -t -l -p $(YACC_PREFIX) $< - -.PRECIOUS: $(src)/%.tab.h_shipped -$(src)/%.tab.h_shipped: $(src)/%.y - $(call cmd,bison_h) - -endif - -# Shipped files -# =========================================================================== - -quiet_cmd_shipped = SHIPPED $@ -cmd_shipped = cat $< > $@ - -$(obj)/%: $(src)/%_shipped - $(call cmd,shipped) - -# Commands useful for building a boot image -# =========================================================================== -# -# Use as following: -# -# target: source(s) FORCE -# $(if_changed,ld/objcopy/gzip) -# -# and add target to extra-y so that we know we have to -# read in the saved command line - -# Linking -# --------------------------------------------------------------------------- - -quiet_cmd_ld = LD $@ -cmd_ld = $(LD) $(LDFLAGS) $(ldflags-y) $(LDFLAGS_$(@F)) \ - $(filter-out FORCE,$^) -o $@ - -# Objcopy -# --------------------------------------------------------------------------- - -quiet_cmd_objcopy = OBJCOPY $@ -cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@ - -# Gzip -# --------------------------------------------------------------------------- - -quiet_cmd_gzip = GZIP $@ -cmd_gzip = (cat $(filter-out FORCE,$^) | gzip -n -f -9 > $@) || \ - (rm -f $@ ; false) - -# DTC -# --------------------------------------------------------------------------- -DTC ?= $(objtree)/scripts/dtc/dtc - -# Disable noisy checks by default -ifeq ($(KBUILD_ENABLE_EXTRA_GCC_CHECKS),) -DTC_FLAGS += -Wno-unit_address_vs_reg -endif - -# Generate an assembly file to wrap the output of the device tree compiler -quiet_cmd_dt_S_dtb= DTB $@ -cmd_dt_S_dtb= \ -( \ - echo '\#include '; \ - echo '.section .dtb.init.rodata,"a"'; \ - echo '.balign STRUCT_ALIGNMENT'; \ - echo '.global __dtb_$(*F)_begin'; \ - echo '__dtb_$(*F)_begin:'; \ - echo '.incbin "$<" '; \ - echo '__dtb_$(*F)_end:'; \ - echo '.global __dtb_$(*F)_end'; \ - echo '.balign STRUCT_ALIGNMENT'; \ -) > $@ - -$(obj)/%.dtb.S: $(obj)/%.dtb - $(call cmd,dt_S_dtb) - -quiet_cmd_dtc = DTC $@ -cmd_dtc = mkdir -p $(dir ${dtc-tmp}) ; \ - $(CPP) $(dtc_cpp_flags) -x assembler-with-cpp -o $(dtc-tmp) $< ; \ - $(DTC) -O dtb -o $@ -b 0 \ - -i $(dir $<) $(DTC_FLAGS) \ - -d $(depfile).dtc.tmp $(dtc-tmp) ; \ - cat $(depfile).pre.tmp $(depfile).dtc.tmp > $(depfile) - -$(obj)/%.dtb: $(src)/%.dts FORCE - $(call if_changed_dep,dtc) - -dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp) - -# Bzip2 -# --------------------------------------------------------------------------- - -# Bzip2 and LZMA do not include size in file... so we have to fake that; -# append the size as a 32-bit littleendian number as gzip does. -size_append = printf $(shell \ -dec_size=0; \ -for F in $1; do \ - fsize=$$(stat -c "%s" $$F); \ - dec_size=$$(expr $$dec_size + $$fsize); \ -done; \ -printf "%08x\n" $$dec_size | \ - sed 's/\(..\)/\1 /g' | { \ - read ch0 ch1 ch2 ch3; \ - for ch in $$ch3 $$ch2 $$ch1 $$ch0; do \ - printf '%s%03o' '\\' $$((0x$$ch)); \ - done; \ - } \ -) - -quiet_cmd_bzip2 = BZIP2 $@ -cmd_bzip2 = (cat $(filter-out FORCE,$^) | \ - bzip2 -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ - (rm -f $@ ; false) - -# Lzma -# --------------------------------------------------------------------------- - -quiet_cmd_lzma = LZMA $@ -cmd_lzma = (cat $(filter-out FORCE,$^) | \ - lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ - (rm -f $@ ; false) - -quiet_cmd_lzo = LZO $@ -cmd_lzo = (cat $(filter-out FORCE,$^) | \ - lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ - (rm -f $@ ; false) - -quiet_cmd_lz4 = LZ4 $@ -cmd_lz4 = (cat $(filter-out FORCE,$^) | \ - lz4c -l -c1 stdin stdout && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ - (rm -f $@ ; false) - -# U-Boot mkimage -# --------------------------------------------------------------------------- - -MKIMAGE := $(srctree)/scripts/mkuboot.sh - -# SRCARCH just happens to match slightly more than ARCH (on sparc), so reduces -# the number of overrides in arch makefiles -UIMAGE_ARCH ?= $(SRCARCH) -UIMAGE_COMPRESSION ?= $(if $(2),$(2),none) -UIMAGE_OPTS-y ?= -UIMAGE_TYPE ?= kernel -UIMAGE_LOADADDR ?= arch_must_set_this -UIMAGE_ENTRYADDR ?= $(UIMAGE_LOADADDR) -UIMAGE_NAME ?= 'Linux-$(KERNELRELEASE)' -UIMAGE_IN ?= $< -UIMAGE_OUT ?= $@ - -quiet_cmd_uimage = UIMAGE $(UIMAGE_OUT) - cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(UIMAGE_ARCH) -O linux \ - -C $(UIMAGE_COMPRESSION) $(UIMAGE_OPTS-y) \ - -T $(UIMAGE_TYPE) \ - -a $(UIMAGE_LOADADDR) -e $(UIMAGE_ENTRYADDR) \ - -n $(UIMAGE_NAME) -d $(UIMAGE_IN) $(UIMAGE_OUT) - -# XZ -# --------------------------------------------------------------------------- -# Use xzkern to compress the kernel image and xzmisc to compress other things. -# -# xzkern uses a big LZMA2 dictionary since it doesn't increase memory usage -# of the kernel decompressor. A BCJ filter is used if it is available for -# the target architecture. xzkern also appends uncompressed size of the data -# using size_append. The .xz format has the size information available at -# the end of the file too, but it's in more complex format and it's good to -# avoid changing the part of the boot code that reads the uncompressed size. -# Note that the bytes added by size_append will make the xz tool think that -# the file is corrupt. This is expected. -# -# xzmisc doesn't use size_append, so it can be used to create normal .xz -# files. xzmisc uses smaller LZMA2 dictionary than xzkern, because a very -# big dictionary would increase the memory usage too much in the multi-call -# decompression mode. A BCJ filter isn't used either. -quiet_cmd_xzkern = XZKERN $@ -cmd_xzkern = (cat $(filter-out FORCE,$^) | \ - sh $(srctree)/scripts/xz_wrap.sh && \ - $(call size_append, $(filter-out FORCE,$^))) > $@ || \ - (rm -f $@ ; false) - -quiet_cmd_xzmisc = XZMISC $@ -cmd_xzmisc = (cat $(filter-out FORCE,$^) | \ - xz --check=crc32 --lzma2=dict=1MiB) > $@ || \ - (rm -f $@ ; false) diff --git a/src/linux/scripts/Makefile.modpost b/src/linux/scripts/Makefile.modpost deleted file mode 100644 index 16923ba..0000000 --- a/src/linux/scripts/Makefile.modpost +++ /dev/null @@ -1,157 +0,0 @@ -# =========================================================================== -# Module versions -# =========================================================================== -# -# Stage one of module building created the following: -# a) The individual .o files used for the module -# b) A .o file which is the .o files above linked together -# c) A .mod file in $(MODVERDIR)/, listing the name of the -# the preliminary .o file, plus all .o files - -# Stage 2 is handled by this file and does the following -# 1) Find all modules from the files listed in $(MODVERDIR)/ -# 2) modpost is then used to -# 3) create one .mod.c file pr. module -# 4) create one Module.symvers file with CRC for all exported symbols -# 5) compile all .mod.c files -# 6) final link of the module to a file - -# Step 3 is used to place certain information in the module's ELF -# section, including information such as: -# Version magic (see include/linux/vermagic.h for full details) -# - Kernel release -# - SMP is CONFIG_SMP -# - PREEMPT is CONFIG_PREEMPT -# - GCC Version -# Module info -# - Module version (MODULE_VERSION) -# - Module alias'es (MODULE_ALIAS) -# - Module license (MODULE_LICENSE) -# - See include/linux/module.h for more details - -# Step 4 is solely used to allow module versioning in external modules, -# where the CRC of each module is retrieved from the Module.symvers file. - -# KBUILD_MODPOST_WARN can be set to avoid error out in case of undefined -# symbols in the final module linking stage -# KBUILD_MODPOST_NOFINAL can be set to skip the final link of modules. -# This is solely useful to speed up test compiles -PHONY := _modpost -_modpost: __modpost - -include include/config/auto.conf -include scripts/Kbuild.include - -# When building external modules load the Kbuild file to retrieve EXTRA_SYMBOLS info -ifneq ($(KBUILD_EXTMOD),) - -# set src + obj - they may be used when building the .mod.c file -obj := $(KBUILD_EXTMOD) -src := $(obj) - -# Include the module's Makefile to find KBUILD_EXTRA_SYMBOLS -include $(if $(wildcard $(KBUILD_EXTMOD)/Kbuild), \ - $(KBUILD_EXTMOD)/Kbuild, $(KBUILD_EXTMOD)/Makefile) -endif - -include scripts/Makefile.lib - -kernelsymfile := $(objtree)/Module.symvers -modulesymfile := $(firstword $(KBUILD_EXTMOD))/Module.symvers - -# Step 1), find all modules listed in $(MODVERDIR)/ -MODLISTCMD := find $(MODVERDIR) -name '*.mod' | xargs -r grep -h '\.ko$$' | sort -u -__modules := $(shell $(MODLISTCMD)) -modules := $(patsubst %.o,%.ko, $(wildcard $(__modules:.ko=.o))) - -# Stop after building .o files if NOFINAL is set. Makes compile tests quicker -_modpost: $(if $(KBUILD_MODPOST_NOFINAL), $(modules:.ko:.o),$(modules)) - -# Step 2), invoke modpost -# Includes step 3,4 -modpost = scripts/mod/modpost \ - $(if $(CONFIG_MODVERSIONS),-m) \ - $(if $(CONFIG_MODULE_SRCVERSION_ALL),-a,) \ - $(if $(KBUILD_EXTMOD),-i,-o) $(kernelsymfile) \ - $(if $(KBUILD_EXTMOD),-I $(modulesymfile)) \ - $(if $(KBUILD_EXTRA_SYMBOLS), $(patsubst %, -e %,$(KBUILD_EXTRA_SYMBOLS))) \ - $(if $(KBUILD_EXTMOD),-o $(modulesymfile)) \ - $(if $(CONFIG_DEBUG_SECTION_MISMATCH),,-S) \ - $(if $(CONFIG_SECTION_MISMATCH_WARN_ONLY),,-E) \ - $(if $(KBUILD_EXTMOD)$(KBUILD_MODPOST_WARN),-w) - -MODPOST_OPT=$(subst -i,-n,$(filter -i,$(MAKEFLAGS))) - -# We can go over command line length here, so be careful. -quiet_cmd_modpost = MODPOST $(words $(filter-out vmlinux FORCE, $^)) modules - cmd_modpost = $(MODLISTCMD) | sed 's/\.ko$$/.o/' | $(modpost) $(MODPOST_OPT) -s -T - - -PHONY += __modpost -__modpost: $(modules:.ko=.o) FORCE - $(call cmd,modpost) $(wildcard vmlinux) - -quiet_cmd_kernel-mod = MODPOST $@ - cmd_kernel-mod = $(modpost) $@ - -vmlinux.o: FORCE - $(call cmd,kernel-mod) - -# Declare generated files as targets for modpost -$(symverfile): __modpost ; -$(modules:.ko=.mod.c): __modpost ; - - -# Step 5), compile all *.mod.c files - -# modname is set to make c_flags define KBUILD_MODNAME -modname = $(notdir $(@:.mod.o=)) - -quiet_cmd_cc_o_c = CC $@ - cmd_cc_o_c = $(CC) $(c_flags) $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE) \ - -c -o $@ $< - -$(modules:.ko=.mod.o): %.mod.o: %.mod.c FORCE - $(call if_changed_dep,cc_o_c) - -targets += $(modules:.ko=.mod.o) - -ARCH_POSTLINK := $(wildcard $(srctree)/arch/$(SRCARCH)/Makefile.postlink) - -# Step 6), final link of the modules with optional arch pass after final link -quiet_cmd_ld_ko_o = LD [M] $@ - cmd_ld_ko_o = \ - $(LD) -r $(LDFLAGS) \ - $(KBUILD_LDFLAGS_MODULE) $(LDFLAGS_MODULE) \ - -o $@ $(filter-out FORCE,$^) ; \ - $(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) $@, true) - -$(modules): %.ko :%.o %.mod.o FORCE - +$(call if_changed,ld_ko_o) - -targets += $(modules) - - -# Add FORCE to the prequisites of a target to force it to be always rebuilt. -# --------------------------------------------------------------------------- - -PHONY += FORCE - -FORCE: - -# Read all saved command lines and dependencies for the $(targets) we -# may be building above, using $(if_changed{,_dep}). As an -# optimization, we don't need to read them if the target does not -# exist, we will rebuild anyway in that case. - -targets := $(wildcard $(sort $(targets))) -cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd)) - -ifneq ($(cmd_files),) - include $(cmd_files) -endif - - -# Declare the contents of the .PHONY variable as phony. We keep that -# information in a variable se we can use it in if_changed and friends. - -.PHONY: $(PHONY) diff --git a/src/linux/scripts/Makefile.ubsan b/src/linux/scripts/Makefile.ubsan deleted file mode 100644 index 3b1b138..0000000 --- a/src/linux/scripts/Makefile.ubsan +++ /dev/null @@ -1,24 +0,0 @@ -ifdef CONFIG_UBSAN - CFLAGS_UBSAN += $(call cc-option, -fsanitize=shift) - CFLAGS_UBSAN += $(call cc-option, -fsanitize=integer-divide-by-zero) - CFLAGS_UBSAN += $(call cc-option, -fsanitize=unreachable) - CFLAGS_UBSAN += $(call cc-option, -fsanitize=vla-bound) - CFLAGS_UBSAN += $(call cc-option, -fsanitize=signed-integer-overflow) - CFLAGS_UBSAN += $(call cc-option, -fsanitize=bounds) - CFLAGS_UBSAN += $(call cc-option, -fsanitize=object-size) - CFLAGS_UBSAN += $(call cc-option, -fsanitize=returns-nonnull-attribute) - CFLAGS_UBSAN += $(call cc-option, -fsanitize=bool) - CFLAGS_UBSAN += $(call cc-option, -fsanitize=enum) - -ifdef CONFIG_UBSAN_ALIGNMENT - CFLAGS_UBSAN += $(call cc-option, -fsanitize=alignment) -endif - -ifdef CONFIG_UBSAN_NULL - CFLAGS_UBSAN += $(call cc-option, -fsanitize=null) -endif - - # -fsanitize=* options makes GCC less smart than usual and - # increase number of 'maybe-uninitialized false-positives - CFLAGS_UBSAN += $(call cc-option, -Wno-maybe-uninitialized) -endif diff --git a/src/linux/scripts/basic/.gitignore b/src/linux/scripts/basic/.gitignore deleted file mode 100644 index 52d8dfe..0000000 --- a/src/linux/scripts/basic/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -fixdep -fixdep.exe -bin2c -bin2c.exe diff --git a/src/linux/scripts/basic/Makefile b/src/linux/scripts/basic/Makefile deleted file mode 100644 index ec10d93..0000000 --- a/src/linux/scripts/basic/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -### -# Makefile.basic lists the most basic programs used during the build process. -# The programs listed herein are what are needed to do the basic stuff, -# such as fix file dependencies. -# This initial step is needed to avoid files to be recompiled -# when kernel configuration changes (which is what happens when -# .config is included by main Makefile. -# --------------------------------------------------------------------------- -# fixdep: Used to generate dependency information during build process - -hostprogs-y := fixdep -hostprogs-$(CONFIG_BUILD_BIN2C) += bin2c -always := $(hostprogs-y) - -# fixdep is needed to compile other host programs -$(addprefix $(obj)/,$(filter-out fixdep,$(always))): $(obj)/fixdep diff --git a/src/linux/scripts/basic/fixdep.c b/src/linux/scripts/basic/fixdep.c deleted file mode 100644 index fff818b..0000000 --- a/src/linux/scripts/basic/fixdep.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - * "Optimize" a list of dependencies as spit out by gcc -MD - * for the kernel build - * =========================================================================== - * - * Author Kai Germaschewski - * Copyright 2002 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * - * Introduction: - * - * gcc produces a very nice and correct list of dependencies which - * tells make when to remake a file. - * - * To use this list as-is however has the drawback that virtually - * every file in the kernel includes autoconf.h. - * - * If the user re-runs make *config, autoconf.h will be - * regenerated. make notices that and will rebuild every file which - * includes autoconf.h, i.e. basically all files. This is extremely - * annoying if the user just changed CONFIG_HIS_DRIVER from n to m. - * - * So we play the same trick that "mkdep" played before. We replace - * the dependency on autoconf.h by a dependency on every config - * option which is mentioned in any of the listed prequisites. - * - * kconfig populates a tree in include/config/ with an empty file - * for each config symbol and when the configuration is updated - * the files representing changed config options are touched - * which then let make pick up the changes and the files that use - * the config symbols are rebuilt. - * - * So if the user changes his CONFIG_HIS_DRIVER option, only the objects - * which depend on "include/linux/config/his/driver.h" will be rebuilt, - * so most likely only his driver ;-) - * - * The idea above dates, by the way, back to Michael E Chastain, AFAIK. - * - * So to get dependencies right, there are two issues: - * o if any of the files the compiler read changed, we need to rebuild - * o if the command line given to the compile the file changed, we - * better rebuild as well. - * - * The former is handled by using the -MD output, the later by saving - * the command line used to compile the old object and comparing it - * to the one we would now use. - * - * Again, also this idea is pretty old and has been discussed on - * kbuild-devel a long time ago. I don't have a sensibly working - * internet connection right now, so I rather don't mention names - * without double checking. - * - * This code here has been based partially based on mkdep.c, which - * says the following about its history: - * - * Copyright abandoned, Michael Chastain, . - * This is a C version of syncdep.pl by Werner Almesberger. - * - * - * It is invoked as - * - * fixdep - * - * and will read the dependency file - * - * The transformed dependency snipped is written to stdout. - * - * It first generates a line - * - * cmd_ = - * - * and then basically copies the ..d file to stdout, in the - * process filtering out the dependency on autoconf.h and adding - * dependencies on include/config/my/option.h for every - * CONFIG_MY_OPTION encountered in any of the prequisites. - * - * It will also filter out all the dependencies on *.ver. We need - * to make sure that the generated version checksum are globally up - * to date before even starting the recursive build, so it's too late - * at this point anyway. - * - * We don't even try to really parse the header files, but - * merely grep, i.e. if CONFIG_FOO is mentioned in a comment, it will - * be picked up as well. It's not a problem with respect to - * correctness, since that can only give too many dependencies, thus - * we cannot miss a rebuild. Since people tend to not mention totally - * unrelated CONFIG_ options all over the place, it's not an - * efficiency problem either. - * - * (Note: it'd be easy to port over the complete mkdep state machine, - * but I don't think the added complexity is worth it) - */ -/* - * Note 2: if somebody writes HELLO_CONFIG_BOOM in a file, it will depend onto - * CONFIG_BOOM. This could seem a bug (not too hard to fix), but please do not - * fix it! Some UserModeLinux files (look at arch/um/) call CONFIG_BOOM as - * UML_CONFIG_BOOM, to avoid conflicts with /usr/include/linux/autoconf.h, - * through arch/um/include/uml-config.h; this fixdep "bug" makes sure that - * those files will have correct dependencies. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -int insert_extra_deps; -char *target; -char *depfile; -char *cmdline; - -static void usage(void) -{ - fprintf(stderr, "Usage: fixdep [-e] \n"); - fprintf(stderr, " -e insert extra dependencies given on stdin\n"); - exit(1); -} - -/* - * Print out the commandline prefixed with cmd_ := - */ -static void print_cmdline(void) -{ - printf("cmd_%s := %s\n\n", target, cmdline); -} - -/* - * Print out a dependency path from a symbol name - */ -static void print_config(const char *m, int slen) -{ - int c, i; - - printf(" $(wildcard include/config/"); - for (i = 0; i < slen; i++) { - c = m[i]; - if (c == '_') - c = '/'; - else - c = tolower(c); - putchar(c); - } - printf(".h) \\\n"); -} - -static void do_extra_deps(void) -{ - if (insert_extra_deps) { - char buf[80]; - while(fgets(buf, sizeof(buf), stdin)) { - int len = strlen(buf); - if (len < 2 || buf[len-1] != '\n') { - fprintf(stderr, "fixdep: bad data on stdin\n"); - exit(1); - } - print_config(buf, len-1); - } - } -} - -struct item { - struct item *next; - unsigned int len; - unsigned int hash; - char name[0]; -}; - -#define HASHSZ 256 -static struct item *hashtab[HASHSZ]; - -static unsigned int strhash(const char *str, unsigned int sz) -{ - /* fnv32 hash */ - unsigned int i, hash = 2166136261U; - - for (i = 0; i < sz; i++) - hash = (hash ^ str[i]) * 0x01000193; - return hash; -} - -/* - * Lookup a value in the configuration string. - */ -static int is_defined_config(const char *name, int len, unsigned int hash) -{ - struct item *aux; - - for (aux = hashtab[hash % HASHSZ]; aux; aux = aux->next) { - if (aux->hash == hash && aux->len == len && - memcmp(aux->name, name, len) == 0) - return 1; - } - return 0; -} - -/* - * Add a new value to the configuration string. - */ -static void define_config(const char *name, int len, unsigned int hash) -{ - struct item *aux = malloc(sizeof(*aux) + len); - - if (!aux) { - perror("fixdep:malloc"); - exit(1); - } - memcpy(aux->name, name, len); - aux->len = len; - aux->hash = hash; - aux->next = hashtab[hash % HASHSZ]; - hashtab[hash % HASHSZ] = aux; -} - -/* - * Record the use of a CONFIG_* word. - */ -static void use_config(const char *m, int slen) -{ - unsigned int hash = strhash(m, slen); - - if (is_defined_config(m, slen, hash)) - return; - - define_config(m, slen, hash); - print_config(m, slen); -} - -static void parse_config_file(const char *p) -{ - const char *q, *r; - - while ((p = strstr(p, "CONFIG_"))) { - p += 7; - q = p; - while (*q && (isalnum(*q) || *q == '_')) - q++; - if (memcmp(q - 7, "_MODULE", 7) == 0) - r = q - 7; - else - r = q; - if (r > p) - use_config(p, r - p); - p = q; - } -} - -/* test if s ends in sub */ -static int strrcmp(const char *s, const char *sub) -{ - int slen = strlen(s); - int sublen = strlen(sub); - - if (sublen > slen) - return 1; - - return memcmp(s + slen - sublen, sub, sublen); -} - -static void do_config_file(const char *filename) -{ - struct stat st; - int fd; - char *map; - - fd = open(filename, O_RDONLY); - if (fd < 0) { - fprintf(stderr, "fixdep: error opening config file: "); - perror(filename); - exit(2); - } - if (fstat(fd, &st) < 0) { - fprintf(stderr, "fixdep: error fstat'ing config file: "); - perror(filename); - exit(2); - } - if (st.st_size == 0) { - close(fd); - return; - } - map = malloc(st.st_size + 1); - if (!map) { - perror("fixdep: malloc"); - close(fd); - return; - } - if (read(fd, map, st.st_size) != st.st_size) { - perror("fixdep: read"); - close(fd); - return; - } - map[st.st_size] = '\0'; - close(fd); - - parse_config_file(map); - - free(map); -} - -/* - * Important: The below generated source_foo.o and deps_foo.o variable - * assignments are parsed not only by make, but also by the rather simple - * parser in scripts/mod/sumversion.c. - */ -static void parse_dep_file(void *map, size_t len) -{ - char *m = map; - char *end = m + len; - char *p; - char s[PATH_MAX]; - int is_target; - int saw_any_target = 0; - int is_first_dep = 0; - - while (m < end) { - /* Skip any "white space" */ - while (m < end && (*m == ' ' || *m == '\\' || *m == '\n')) - m++; - /* Find next "white space" */ - p = m; - while (p < end && *p != ' ' && *p != '\\' && *p != '\n') - p++; - /* Is the token we found a target name? */ - is_target = (*(p-1) == ':'); - /* Don't write any target names into the dependency file */ - if (is_target) { - /* The /next/ file is the first dependency */ - is_first_dep = 1; - } else { - /* Save this token/filename */ - memcpy(s, m, p-m); - s[p - m] = 0; - - /* Ignore certain dependencies */ - if (strrcmp(s, "include/generated/autoconf.h") && - strrcmp(s, "include/generated/autoksyms.h") && - strrcmp(s, "arch/um/include/uml-config.h") && - strrcmp(s, "include/linux/kconfig.h") && - strrcmp(s, ".ver")) { - /* - * Do not list the source file as dependency, - * so that kbuild is not confused if a .c file - * is rewritten into .S or vice versa. Storing - * it in source_* is needed for modpost to - * compute srcversions. - */ - if (is_first_dep) { - /* - * If processing the concatenation of - * multiple dependency files, only - * process the first target name, which - * will be the original source name, - * and ignore any other target names, - * which will be intermediate temporary - * files. - */ - if (!saw_any_target) { - saw_any_target = 1; - printf("source_%s := %s\n\n", - target, s); - printf("deps_%s := \\\n", - target); - } - is_first_dep = 0; - } else - printf(" %s \\\n", s); - do_config_file(s); - } - } - /* - * Start searching for next token immediately after the first - * "whitespace" character that follows this token. - */ - m = p + 1; - } - - if (!saw_any_target) { - fprintf(stderr, "fixdep: parse error; no targets found\n"); - exit(1); - } - - do_extra_deps(); - - printf("\n%s: $(deps_%s)\n\n", target, target); - printf("$(deps_%s):\n", target); -} - -static void print_deps(void) -{ - struct stat st; - int fd; - void *map; - - fd = open(depfile, O_RDONLY); - if (fd < 0) { - fprintf(stderr, "fixdep: error opening depfile: "); - perror(depfile); - exit(2); - } - if (fstat(fd, &st) < 0) { - fprintf(stderr, "fixdep: error fstat'ing depfile: "); - perror(depfile); - exit(2); - } - if (st.st_size == 0) { - fprintf(stderr,"fixdep: %s is empty\n",depfile); - close(fd); - return; - } - map = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if ((long) map == -1) { - perror("fixdep: mmap"); - close(fd); - return; - } - - parse_dep_file(map, st.st_size); - - munmap(map, st.st_size); - - close(fd); -} - -int main(int argc, char *argv[]) -{ - if (argc == 5 && !strcmp(argv[1], "-e")) { - insert_extra_deps = 1; - argv++; - } else if (argc != 4) - usage(); - - depfile = argv[1]; - target = argv[2]; - cmdline = argv[3]; - - print_cmdline(); - print_deps(); - - return 0; -} diff --git a/src/linux/scripts/checksyscalls.sh b/src/linux/scripts/checksyscalls.sh deleted file mode 100755 index 2c9082b..0000000 --- a/src/linux/scripts/checksyscalls.sh +++ /dev/null @@ -1,216 +0,0 @@ -#!/bin/sh -# -# Check if current architecture are missing any function calls compared -# to i386. -# i386 define a number of legacy system calls that are i386 specific -# and listed below so they are ignored. -# -# Usage: -# checksyscalls.sh gcc gcc-options -# - -ignore_list() { -cat << EOF -#include -#include - -/* *at */ -#define __IGNORE_open /* openat */ -#define __IGNORE_link /* linkat */ -#define __IGNORE_unlink /* unlinkat */ -#define __IGNORE_mknod /* mknodat */ -#define __IGNORE_chmod /* fchmodat */ -#define __IGNORE_chown /* fchownat */ -#define __IGNORE_mkdir /* mkdirat */ -#define __IGNORE_rmdir /* unlinkat */ -#define __IGNORE_lchown /* fchownat */ -#define __IGNORE_access /* faccessat */ -#define __IGNORE_rename /* renameat2 */ -#define __IGNORE_readlink /* readlinkat */ -#define __IGNORE_symlink /* symlinkat */ -#define __IGNORE_utimes /* futimesat */ -#if BITS_PER_LONG == 64 -#define __IGNORE_stat /* fstatat */ -#define __IGNORE_lstat /* fstatat */ -#else -#define __IGNORE_stat64 /* fstatat64 */ -#define __IGNORE_lstat64 /* fstatat64 */ -#endif - -/* Missing flags argument */ -#define __IGNORE_renameat /* renameat2 */ - -/* CLOEXEC flag */ -#define __IGNORE_pipe /* pipe2 */ -#define __IGNORE_dup2 /* dup3 */ -#define __IGNORE_epoll_create /* epoll_create1 */ -#define __IGNORE_inotify_init /* inotify_init1 */ -#define __IGNORE_eventfd /* eventfd2 */ -#define __IGNORE_signalfd /* signalfd4 */ - -/* MMU */ -#ifndef CONFIG_MMU -#define __IGNORE_madvise -#define __IGNORE_mbind -#define __IGNORE_mincore -#define __IGNORE_mlock -#define __IGNORE_mlockall -#define __IGNORE_munlock -#define __IGNORE_munlockall -#define __IGNORE_mprotect -#define __IGNORE_msync -#define __IGNORE_migrate_pages -#define __IGNORE_move_pages -#define __IGNORE_remap_file_pages -#define __IGNORE_get_mempolicy -#define __IGNORE_set_mempolicy -#define __IGNORE_swapoff -#define __IGNORE_swapon -#endif - -/* System calls for 32-bit kernels only */ -#if BITS_PER_LONG == 64 -#define __IGNORE_sendfile64 -#define __IGNORE_ftruncate64 -#define __IGNORE_truncate64 -#define __IGNORE_stat64 -#define __IGNORE_lstat64 -#define __IGNORE_fstat64 -#define __IGNORE_fcntl64 -#define __IGNORE_fadvise64_64 -#define __IGNORE_fstatat64 -#define __IGNORE_fstatfs64 -#define __IGNORE_statfs64 -#define __IGNORE_llseek -#define __IGNORE_mmap2 -#else -#define __IGNORE_sendfile -#define __IGNORE_ftruncate -#define __IGNORE_truncate -#define __IGNORE_stat -#define __IGNORE_lstat -#define __IGNORE_fstat -#define __IGNORE_fcntl -#define __IGNORE_fadvise64 -#define __IGNORE_newfstatat -#define __IGNORE_fstatfs -#define __IGNORE_statfs -#define __IGNORE_lseek -#define __IGNORE_mmap -#endif - -/* i386-specific or historical system calls */ -#define __IGNORE_break -#define __IGNORE_stty -#define __IGNORE_gtty -#define __IGNORE_ftime -#define __IGNORE_prof -#define __IGNORE_lock -#define __IGNORE_mpx -#define __IGNORE_ulimit -#define __IGNORE_profil -#define __IGNORE_ioperm -#define __IGNORE_iopl -#define __IGNORE_idle -#define __IGNORE_modify_ldt -#define __IGNORE_ugetrlimit -#define __IGNORE_vm86 -#define __IGNORE_vm86old -#define __IGNORE_set_thread_area -#define __IGNORE_get_thread_area -#define __IGNORE_madvise1 -#define __IGNORE_oldstat -#define __IGNORE_oldfstat -#define __IGNORE_oldlstat -#define __IGNORE_oldolduname -#define __IGNORE_olduname -#define __IGNORE_umount -#define __IGNORE_waitpid -#define __IGNORE_stime -#define __IGNORE_nice -#define __IGNORE_signal -#define __IGNORE_sigaction -#define __IGNORE_sgetmask -#define __IGNORE_sigsuspend -#define __IGNORE_sigpending -#define __IGNORE_ssetmask -#define __IGNORE_readdir -#define __IGNORE_socketcall -#define __IGNORE_ipc -#define __IGNORE_sigreturn -#define __IGNORE_sigprocmask -#define __IGNORE_bdflush -#define __IGNORE__llseek -#define __IGNORE__newselect -#define __IGNORE_create_module -#define __IGNORE_query_module -#define __IGNORE_get_kernel_syms -#define __IGNORE_sysfs -#define __IGNORE_uselib -#define __IGNORE__sysctl - -/* ... including the "new" 32-bit uid syscalls */ -#define __IGNORE_lchown32 -#define __IGNORE_getuid32 -#define __IGNORE_getgid32 -#define __IGNORE_geteuid32 -#define __IGNORE_getegid32 -#define __IGNORE_setreuid32 -#define __IGNORE_setregid32 -#define __IGNORE_getgroups32 -#define __IGNORE_setgroups32 -#define __IGNORE_fchown32 -#define __IGNORE_setresuid32 -#define __IGNORE_getresuid32 -#define __IGNORE_setresgid32 -#define __IGNORE_getresgid32 -#define __IGNORE_chown32 -#define __IGNORE_setuid32 -#define __IGNORE_setgid32 -#define __IGNORE_setfsuid32 -#define __IGNORE_setfsgid32 - -/* these can be expressed using other calls */ -#define __IGNORE_alarm /* setitimer */ -#define __IGNORE_creat /* open */ -#define __IGNORE_fork /* clone */ -#define __IGNORE_futimesat /* utimensat */ -#define __IGNORE_getpgrp /* getpgid */ -#define __IGNORE_getdents /* getdents64 */ -#define __IGNORE_pause /* sigsuspend */ -#define __IGNORE_poll /* ppoll */ -#define __IGNORE_select /* pselect6 */ -#define __IGNORE_epoll_wait /* epoll_pwait */ -#define __IGNORE_time /* gettimeofday */ -#define __IGNORE_uname /* newuname */ -#define __IGNORE_ustat /* statfs */ -#define __IGNORE_utime /* utimes */ -#define __IGNORE_vfork /* clone */ - -/* sync_file_range had a stupid ABI. Allow sync_file_range2 instead */ -#ifdef __NR_sync_file_range2 -#define __IGNORE_sync_file_range -#endif - -/* Unmerged syscalls for AFS, STREAMS, etc. */ -#define __IGNORE_afs_syscall -#define __IGNORE_getpmsg -#define __IGNORE_putpmsg -#define __IGNORE_vserver -EOF -} - -syscall_list() { - grep '^[0-9]' "$1" | sort -n | ( - while read nr abi name entry ; do - cat < /dev/null diff --git a/src/linux/scripts/dtc/.gitignore b/src/linux/scripts/dtc/.gitignore deleted file mode 100644 index cdabdc9..0000000 --- a/src/linux/scripts/dtc/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -dtc -dtc-lexer.lex.c -dtc-parser.tab.c -dtc-parser.tab.h diff --git a/src/linux/scripts/gcc-goto.sh b/src/linux/scripts/gcc-goto.sh deleted file mode 100755 index c9469d3..0000000 --- a/src/linux/scripts/gcc-goto.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/sh -# Test for gcc 'asm goto' support -# Copyright (C) 2010, Jason Baron - -cat << "END" | $@ -x c - -c -o /dev/null >/dev/null 2>&1 && echo "y" -int main(void) -{ -#if defined(__arm__) || defined(__aarch64__) - /* - * Not related to asm goto, but used by jump label - * and broken on some ARM GCC versions (see GCC Bug 48637). - */ - static struct { int dummy; int state; } tp; - asm (".long %c0" :: "i" (&tp.state)); -#endif - -entry: - asm goto ("" :::: entry); - return 0; -} -END diff --git a/src/linux/scripts/gcc-version.sh b/src/linux/scripts/gcc-version.sh deleted file mode 100755 index 7f2126d..0000000 --- a/src/linux/scripts/gcc-version.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh -# -# gcc-version [-p] gcc-command -# -# Prints the gcc version of `gcc-command' in a canonical 4-digit form -# such as `0295' for gcc-2.95, `0303' for gcc-3.3, etc. -# -# With the -p option, prints the patchlevel as well, for example `029503' for -# gcc-2.95.3, `030301' for gcc-3.3.1, etc. -# - -if [ "$1" = "-p" ] ; then - with_patchlevel=1; - shift; -fi - -compiler="$*" - -if [ ${#compiler} -eq 0 ]; then - echo "Error: No compiler specified." - printf "Usage:\n\t$0 \n" - exit 1 -fi - -MAJOR=$(echo __GNUC__ | $compiler -E -x c - | tail -n 1) -MINOR=$(echo __GNUC_MINOR__ | $compiler -E -x c - | tail -n 1) -if [ "x$with_patchlevel" != "x" ] ; then - PATCHLEVEL=$(echo __GNUC_PATCHLEVEL__ | $compiler -E -x c - | tail -n 1) - printf "%02d%02d%02d\\n" $MAJOR $MINOR $PATCHLEVEL -else - printf "%02d%02d\\n" $MAJOR $MINOR -fi diff --git a/src/linux/scripts/gdb/linux/.gitignore b/src/linux/scripts/gdb/linux/.gitignore deleted file mode 100644 index 2573543..0000000 --- a/src/linux/scripts/gdb/linux/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.pyc -*.pyo -constants.py diff --git a/src/linux/scripts/genksyms/.gitignore b/src/linux/scripts/genksyms/.gitignore deleted file mode 100644 index 86dc07a..0000000 --- a/src/linux/scripts/genksyms/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -*.hash.c -*.lex.c -*.tab.c -*.tab.h -genksyms diff --git a/src/linux/scripts/headers_install.sh b/src/linux/scripts/headers_install.sh deleted file mode 100755 index fdebd66..0000000 --- a/src/linux/scripts/headers_install.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/sh - -if [ $# -lt 2 ] -then - echo "Usage: headers_install.sh OUTDIR SRCDIR [FILES...]" - echo - echo "Prepares kernel header files for use by user space, by removing" - echo "all compiler.h definitions and #includes, removing any" - echo "#ifdef __KERNEL__ sections, and putting __underscores__ around" - echo "asm/inline/volatile keywords." - echo - echo "OUTDIR: directory to write each userspace header FILE to." - echo "SRCDIR: source directory where files are picked." - echo "FILES: list of header files to operate on." - - exit 1 -fi - -# Grab arguments - -OUTDIR="$1" -shift -SRCDIR="$1" -shift - -# Iterate through files listed on command line - -FILE= -trap 'rm -f "$OUTDIR/$FILE" "$OUTDIR/$FILE.sed"' EXIT -for i in "$@" -do - FILE="$(basename "$i")" - sed -r \ - -e 's/([ \t(])(__user|__force|__iomem)[ \t]/\1/g' \ - -e 's/__attribute_const__([ \t]|$)/\1/g' \ - -e 's@^#include @@' \ - -e 's/(^|[^a-zA-Z0-9])__packed([^a-zA-Z0-9_]|$)/\1__attribute__((packed))\2/g' \ - -e 's/(^|[ \t(])(inline|asm|volatile)([ \t(]|$)/\1__\2__\3/g' \ - -e 's@#(ifndef|define|endif[ \t]*/[*])[ \t]*_UAPI@#\1 @' \ - "$SRCDIR/$i" > "$OUTDIR/$FILE.sed" || exit 1 - scripts/unifdef -U__KERNEL__ -D__EXPORTED_HEADERS__ "$OUTDIR/$FILE.sed" \ - > "$OUTDIR/$FILE" - [ $? -gt 1 ] && exit 1 - rm -f "$OUTDIR/$FILE.sed" -done -trap - EXIT diff --git a/src/linux/scripts/kallsyms.c b/src/linux/scripts/kallsyms.c deleted file mode 100644 index 1c1d46f..0000000 --- a/src/linux/scripts/kallsyms.c +++ /dev/null @@ -1,790 +0,0 @@ -/* Generate assembler source containing symbol information - * - * Copyright 2002 by Kai Germaschewski - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Usage: nm -n vmlinux | scripts/kallsyms [--all-symbols] > symbols.S - * - * Table compression uses all the unused char codes on the symbols and - * maps these to the most used substrings (tokens). For instance, it might - * map char code 0xF7 to represent "write_" and then in every symbol where - * "write_" appears it can be replaced by 0xF7, saving 5 bytes. - * The used codes themselves are also placed in the table so that the - * decompresion can work without "special cases". - * Applied to kernel symbols, this usually produces a compression ratio - * of about 50%. - * - */ - -#include -#include -#include -#include -#include - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) -#endif - -#define KSYM_NAME_LEN 128 - -struct sym_entry { - unsigned long long addr; - unsigned int len; - unsigned int start_pos; - unsigned char *sym; - unsigned int percpu_absolute; -}; - -struct addr_range { - const char *start_sym, *end_sym; - unsigned long long start, end; -}; - -static unsigned long long _text; -static unsigned long long relative_base; -static struct addr_range text_ranges[] = { - { "_stext", "_etext" }, - { "_sinittext", "_einittext" }, - { "_stext_l1", "_etext_l1" }, /* Blackfin on-chip L1 inst SRAM */ - { "_stext_l2", "_etext_l2" }, /* Blackfin on-chip L2 SRAM */ -}; -#define text_range_text (&text_ranges[0]) -#define text_range_inittext (&text_ranges[1]) - -static struct addr_range percpu_range = { - "__per_cpu_start", "__per_cpu_end", -1ULL, 0 -}; - -static struct sym_entry *table; -static unsigned int table_size, table_cnt; -static int all_symbols; -static int use_data_section; -static int absolute_percpu; -static char symbol_prefix_char = '\0'; -static int base_relative; - -int token_profit[0x10000]; - -/* the table that holds the result of the compression */ -unsigned char best_table[256][2]; -unsigned char best_table_len[256]; - - -static void usage(void) -{ - fprintf(stderr, "Usage: kallsyms [--all-symbols] " - "[--use-data-section] " - "[--symbol-prefix=] " - "[--page-offset=] " - "[--base-relative] < in.map > out.S\n"); - exit(1); -} - -/* - * This ignores the intensely annoying "mapping symbols" found - * in ARM ELF files: $a, $t and $d. - */ -static inline int is_arm_mapping_symbol(const char *str) -{ - return str[0] == '$' && strchr("axtd", str[1]) - && (str[2] == '\0' || str[2] == '.'); -} - -static int check_symbol_range(const char *sym, unsigned long long addr, - struct addr_range *ranges, int entries) -{ - size_t i; - struct addr_range *ar; - - for (i = 0; i < entries; ++i) { - ar = &ranges[i]; - - if (strcmp(sym, ar->start_sym) == 0) { - ar->start = addr; - return 0; - } else if (strcmp(sym, ar->end_sym) == 0) { - ar->end = addr; - return 0; - } - } - - return 1; -} - -static int read_symbol(FILE *in, struct sym_entry *s) -{ - char str[500]; - char *sym, stype; - int rc; - - rc = fscanf(in, "%llx %c %499s\n", &s->addr, &stype, str); - if (rc != 3) { - if (rc != EOF && fgets(str, 500, in) == NULL) - fprintf(stderr, "Read error or end of file.\n"); - return -1; - } - if (strlen(str) > KSYM_NAME_LEN) { - fprintf(stderr, "Symbol %s too long for kallsyms (%zu vs %d).\n" - "Please increase KSYM_NAME_LEN both in kernel and kallsyms.c\n", - str, strlen(str), KSYM_NAME_LEN); - return -1; - } - - sym = str; - /* skip prefix char */ - if (symbol_prefix_char && str[0] == symbol_prefix_char) - sym++; - - /* Ignore most absolute/undefined (?) symbols. */ - if (strcmp(sym, "_text") == 0) - _text = s->addr; - else if (check_symbol_range(sym, s->addr, text_ranges, - ARRAY_SIZE(text_ranges)) == 0) - /* nothing to do */; - else if (toupper(stype) == 'A') - { - /* Keep these useful absolute symbols */ - if (strcmp(sym, "__kernel_syscall_via_break") && - strcmp(sym, "__kernel_syscall_via_epc") && - strcmp(sym, "__kernel_sigtramp") && - strcmp(sym, "__gp")) - return -1; - - } - else if (toupper(stype) == 'U' || - is_arm_mapping_symbol(sym)) - return -1; - /* exclude also MIPS ELF local symbols ($L123 instead of .L123) */ - else if (str[0] == '$') - return -1; - /* exclude debugging symbols */ - else if (stype == 'N') - return -1; - - /* include the type field in the symbol name, so that it gets - * compressed together */ - s->len = strlen(str) + 1; - s->sym = malloc(s->len + 1); - if (!s->sym) { - fprintf(stderr, "kallsyms failure: " - "unable to allocate required amount of memory\n"); - exit(EXIT_FAILURE); - } - strcpy((char *)s->sym + 1, str); - s->sym[0] = stype; - - s->percpu_absolute = 0; - - /* Record if we've found __per_cpu_start/end. */ - check_symbol_range(sym, s->addr, &percpu_range, 1); - - return 0; -} - -static int symbol_in_range(struct sym_entry *s, struct addr_range *ranges, - int entries) -{ - size_t i; - struct addr_range *ar; - - for (i = 0; i < entries; ++i) { - ar = &ranges[i]; - - if (s->addr >= ar->start && s->addr <= ar->end) - return 1; - } - - return 0; -} - -static int symbol_valid(struct sym_entry *s) -{ - /* Symbols which vary between passes. Passes 1 and 2 must have - * identical symbol lists. The kallsyms_* symbols below are only added - * after pass 1, they would be included in pass 2 when --all-symbols is - * specified so exclude them to get a stable symbol list. - */ - static char *special_symbols[] = { - "kallsyms_addresses", - "kallsyms_offsets", - "kallsyms_relative_base", - "kallsyms_num_syms", - "kallsyms_names", - "kallsyms_markers", - "kallsyms_token_table", - "kallsyms_token_index", - - /* Exclude linker generated symbols which vary between passes */ - "_SDA_BASE_", /* ppc */ - "_SDA2_BASE_", /* ppc */ - NULL }; - - static char *special_suffixes[] = { - "_veneer", /* arm */ - "_from_arm", /* arm */ - "_from_thumb", /* arm */ - NULL }; - - int i; - char *sym_name = (char *)s->sym + 1; - - /* skip prefix char */ - if (symbol_prefix_char && *sym_name == symbol_prefix_char) - sym_name++; - - - /* if --all-symbols is not specified, then symbols outside the text - * and inittext sections are discarded */ - if (!all_symbols) { - if (symbol_in_range(s, text_ranges, - ARRAY_SIZE(text_ranges)) == 0) - return 0; - /* Corner case. Discard any symbols with the same value as - * _etext _einittext; they can move between pass 1 and 2 when - * the kallsyms data are added. If these symbols move then - * they may get dropped in pass 2, which breaks the kallsyms - * rules. - */ - if ((s->addr == text_range_text->end && - strcmp(sym_name, - text_range_text->end_sym)) || - (s->addr == text_range_inittext->end && - strcmp(sym_name, - text_range_inittext->end_sym))) - return 0; - } - - /* Exclude symbols which vary between passes. */ - for (i = 0; special_symbols[i]; i++) - if (strcmp(sym_name, special_symbols[i]) == 0) - return 0; - - for (i = 0; special_suffixes[i]; i++) { - int l = strlen(sym_name) - strlen(special_suffixes[i]); - - if (l >= 0 && strcmp(sym_name + l, special_suffixes[i]) == 0) - return 0; - } - - return 1; -} - -static void read_map(FILE *in) -{ - while (!feof(in)) { - if (table_cnt >= table_size) { - table_size += 10000; - table = realloc(table, sizeof(*table) * table_size); - if (!table) { - fprintf(stderr, "out of memory\n"); - exit (1); - } - } - if (read_symbol(in, &table[table_cnt]) == 0) { - table[table_cnt].start_pos = table_cnt; - table_cnt++; - } - } -} - -static void output_label(char *label) -{ - if (symbol_prefix_char) - printf(".globl %c%s\n", symbol_prefix_char, label); - else - printf(".globl %s\n", label); - printf("\tALGN\n"); - if (symbol_prefix_char) - printf("%c%s:\n", symbol_prefix_char, label); - else - printf("%s:\n", label); -} - -/* uncompress a compressed symbol. When this function is called, the best table - * might still be compressed itself, so the function needs to be recursive */ -static int expand_symbol(unsigned char *data, int len, char *result) -{ - int c, rlen, total=0; - - while (len) { - c = *data; - /* if the table holds a single char that is the same as the one - * we are looking for, then end the search */ - if (best_table[c][0]==c && best_table_len[c]==1) { - *result++ = c; - total++; - } else { - /* if not, recurse and expand */ - rlen = expand_symbol(best_table[c], best_table_len[c], result); - total += rlen; - result += rlen; - } - data++; - len--; - } - *result=0; - - return total; -} - -static int symbol_absolute(struct sym_entry *s) -{ - return s->percpu_absolute; -} - -static void write_src(void) -{ - unsigned int i, k, off; - unsigned int best_idx[256]; - unsigned int *markers; - char buf[KSYM_NAME_LEN]; - - printf("#include \n"); - printf("#if BITS_PER_LONG == 64\n"); - printf("#define PTR .quad\n"); - printf("#define ALGN .align 8\n"); - printf("#else\n"); - printf("#define PTR .long\n"); - printf("#define ALGN .align 4\n"); - printf("#endif\n"); - - if (use_data_section) - printf("\t.section .data\n"); - else - printf("\t.section .rodata, \"a\"\n"); - - /* Provide proper symbols relocatability by their relativeness - * to a fixed anchor point in the runtime image, either '_text' - * for absolute address tables, in which case the linker will - * emit the final addresses at build time. Otherwise, use the - * offset relative to the lowest value encountered of all relative - * symbols, and emit non-relocatable fixed offsets that will be fixed - * up at runtime. - * - * The symbol names cannot be used to construct normal symbol - * references as the list of symbols contains symbols that are - * declared static and are private to their .o files. This prevents - * .tmp_kallsyms.o or any other object from referencing them. - */ - if (!base_relative) - output_label("kallsyms_addresses"); - else - output_label("kallsyms_offsets"); - - for (i = 0; i < table_cnt; i++) { - if (base_relative) { - long long offset; - int overflow; - - if (!absolute_percpu) { - offset = table[i].addr - relative_base; - overflow = (offset < 0 || offset > UINT_MAX); - } else if (symbol_absolute(&table[i])) { - offset = table[i].addr; - overflow = (offset < 0 || offset > INT_MAX); - } else { - offset = relative_base - table[i].addr - 1; - overflow = (offset < INT_MIN || offset >= 0); - } - if (overflow) { - fprintf(stderr, "kallsyms failure: " - "%s symbol value %#llx out of range in relative mode\n", - symbol_absolute(&table[i]) ? "absolute" : "relative", - table[i].addr); - exit(EXIT_FAILURE); - } - printf("\t.long\t%#x\n", (int)offset); - } else if (!symbol_absolute(&table[i])) { - if (_text <= table[i].addr) - printf("\tPTR\t_text + %#llx\n", - table[i].addr - _text); - else - printf("\tPTR\t_text - %#llx\n", - _text - table[i].addr); - } else { - printf("\tPTR\t%#llx\n", table[i].addr); - } - } - printf("\n"); - - if (base_relative) { - output_label("kallsyms_relative_base"); - printf("\tPTR\t_text - %#llx\n", _text - relative_base); - printf("\n"); - } - - output_label("kallsyms_num_syms"); - printf("\tPTR\t%d\n", table_cnt); - printf("\n"); - - /* table of offset markers, that give the offset in the compressed stream - * every 256 symbols */ - markers = malloc(sizeof(unsigned int) * ((table_cnt + 255) / 256)); - if (!markers) { - fprintf(stderr, "kallsyms failure: " - "unable to allocate required memory\n"); - exit(EXIT_FAILURE); - } - - output_label("kallsyms_names"); - off = 0; - for (i = 0; i < table_cnt; i++) { - if ((i & 0xFF) == 0) - markers[i >> 8] = off; - - printf("\t.byte 0x%02x", table[i].len); - for (k = 0; k < table[i].len; k++) - printf(", 0x%02x", table[i].sym[k]); - printf("\n"); - - off += table[i].len + 1; - } - printf("\n"); - - output_label("kallsyms_markers"); - for (i = 0; i < ((table_cnt + 255) >> 8); i++) - printf("\tPTR\t%d\n", markers[i]); - printf("\n"); - - free(markers); - - output_label("kallsyms_token_table"); - off = 0; - for (i = 0; i < 256; i++) { - best_idx[i] = off; - expand_symbol(best_table[i], best_table_len[i], buf); - printf("\t.asciz\t\"%s\"\n", buf); - off += strlen(buf) + 1; - } - printf("\n"); - - output_label("kallsyms_token_index"); - for (i = 0; i < 256; i++) - printf("\t.short\t%d\n", best_idx[i]); - printf("\n"); -} - - -/* table lookup compression functions */ - -/* count all the possible tokens in a symbol */ -static void learn_symbol(unsigned char *symbol, int len) -{ - int i; - - for (i = 0; i < len - 1; i++) - token_profit[ symbol[i] + (symbol[i + 1] << 8) ]++; -} - -/* decrease the count for all the possible tokens in a symbol */ -static void forget_symbol(unsigned char *symbol, int len) -{ - int i; - - for (i = 0; i < len - 1; i++) - token_profit[ symbol[i] + (symbol[i + 1] << 8) ]--; -} - -/* remove all the invalid symbols from the table and do the initial token count */ -static void build_initial_tok_table(void) -{ - unsigned int i, pos; - - pos = 0; - for (i = 0; i < table_cnt; i++) { - if ( symbol_valid(&table[i]) ) { - if (pos != i) - table[pos] = table[i]; - learn_symbol(table[pos].sym, table[pos].len); - pos++; - } - } - table_cnt = pos; -} - -static void *find_token(unsigned char *str, int len, unsigned char *token) -{ - int i; - - for (i = 0; i < len - 1; i++) { - if (str[i] == token[0] && str[i+1] == token[1]) - return &str[i]; - } - return NULL; -} - -/* replace a given token in all the valid symbols. Use the sampled symbols - * to update the counts */ -static void compress_symbols(unsigned char *str, int idx) -{ - unsigned int i, len, size; - unsigned char *p1, *p2; - - for (i = 0; i < table_cnt; i++) { - - len = table[i].len; - p1 = table[i].sym; - - /* find the token on the symbol */ - p2 = find_token(p1, len, str); - if (!p2) continue; - - /* decrease the counts for this symbol's tokens */ - forget_symbol(table[i].sym, len); - - size = len; - - do { - *p2 = idx; - p2++; - size -= (p2 - p1); - memmove(p2, p2 + 1, size); - p1 = p2; - len--; - - if (size < 2) break; - - /* find the token on the symbol */ - p2 = find_token(p1, size, str); - - } while (p2); - - table[i].len = len; - - /* increase the counts for this symbol's new tokens */ - learn_symbol(table[i].sym, len); - } -} - -/* search the token with the maximum profit */ -static int find_best_token(void) -{ - int i, best, bestprofit; - - bestprofit=-10000; - best = 0; - - for (i = 0; i < 0x10000; i++) { - if (token_profit[i] > bestprofit) { - best = i; - bestprofit = token_profit[i]; - } - } - return best; -} - -/* this is the core of the algorithm: calculate the "best" table */ -static void optimize_result(void) -{ - int i, best; - - /* using the '\0' symbol last allows compress_symbols to use standard - * fast string functions */ - for (i = 255; i >= 0; i--) { - - /* if this table slot is empty (it is not used by an actual - * original char code */ - if (!best_table_len[i]) { - - /* find the token with the breates profit value */ - best = find_best_token(); - if (token_profit[best] == 0) - break; - - /* place it in the "best" table */ - best_table_len[i] = 2; - best_table[i][0] = best & 0xFF; - best_table[i][1] = (best >> 8) & 0xFF; - - /* replace this token in all the valid symbols */ - compress_symbols(best_table[i], i); - } - } -} - -/* start by placing the symbols that are actually used on the table */ -static void insert_real_symbols_in_table(void) -{ - unsigned int i, j, c; - - memset(best_table, 0, sizeof(best_table)); - memset(best_table_len, 0, sizeof(best_table_len)); - - for (i = 0; i < table_cnt; i++) { - for (j = 0; j < table[i].len; j++) { - c = table[i].sym[j]; - best_table[c][0]=c; - best_table_len[c]=1; - } - } -} - -static void optimize_token_table(void) -{ - build_initial_tok_table(); - - insert_real_symbols_in_table(); - - /* When valid symbol is not registered, exit to error */ - if (!table_cnt) { - fprintf(stderr, "No valid symbol.\n"); - exit(1); - } - - optimize_result(); -} - -/* guess for "linker script provide" symbol */ -static int may_be_linker_script_provide_symbol(const struct sym_entry *se) -{ - const char *symbol = (char *)se->sym + 1; - int len = se->len - 1; - - if (len < 8) - return 0; - - if (symbol[0] != '_' || symbol[1] != '_') - return 0; - - /* __start_XXXXX */ - if (!memcmp(symbol + 2, "start_", 6)) - return 1; - - /* __stop_XXXXX */ - if (!memcmp(symbol + 2, "stop_", 5)) - return 1; - - /* __end_XXXXX */ - if (!memcmp(symbol + 2, "end_", 4)) - return 1; - - /* __XXXXX_start */ - if (!memcmp(symbol + len - 6, "_start", 6)) - return 1; - - /* __XXXXX_end */ - if (!memcmp(symbol + len - 4, "_end", 4)) - return 1; - - return 0; -} - -static int prefix_underscores_count(const char *str) -{ - const char *tail = str; - - while (*tail == '_') - tail++; - - return tail - str; -} - -static int compare_symbols(const void *a, const void *b) -{ - const struct sym_entry *sa; - const struct sym_entry *sb; - int wa, wb; - - sa = a; - sb = b; - - /* sort by address first */ - if (sa->addr > sb->addr) - return 1; - if (sa->addr < sb->addr) - return -1; - - /* sort by "weakness" type */ - wa = (sa->sym[0] == 'w') || (sa->sym[0] == 'W'); - wb = (sb->sym[0] == 'w') || (sb->sym[0] == 'W'); - if (wa != wb) - return wa - wb; - - /* sort by "linker script provide" type */ - wa = may_be_linker_script_provide_symbol(sa); - wb = may_be_linker_script_provide_symbol(sb); - if (wa != wb) - return wa - wb; - - /* sort by the number of prefix underscores */ - wa = prefix_underscores_count((const char *)sa->sym + 1); - wb = prefix_underscores_count((const char *)sb->sym + 1); - if (wa != wb) - return wa - wb; - - /* sort by initial order, so that other symbols are left undisturbed */ - return sa->start_pos - sb->start_pos; -} - -static void sort_symbols(void) -{ - qsort(table, table_cnt, sizeof(struct sym_entry), compare_symbols); -} - -static void make_percpus_absolute(void) -{ - unsigned int i; - - for (i = 0; i < table_cnt; i++) - if (symbol_in_range(&table[i], &percpu_range, 1)) { - /* - * Keep the 'A' override for percpu symbols to - * ensure consistent behavior compared to older - * versions of this tool. - */ - table[i].sym[0] = 'A'; - table[i].percpu_absolute = 1; - } -} - -/* find the minimum non-absolute symbol address */ -static void record_relative_base(void) -{ - unsigned int i; - - relative_base = -1ULL; - for (i = 0; i < table_cnt; i++) - if (!symbol_absolute(&table[i]) && - table[i].addr < relative_base) - relative_base = table[i].addr; -} - -int main(int argc, char **argv) -{ - if (argc >= 2) { - int i; - for (i = 1; i < argc; i++) { - if(strcmp(argv[i], "--all-symbols") == 0) - all_symbols = 1; - else if (strcmp(argv[i], "--absolute-percpu") == 0) - absolute_percpu = 1; - else if (strcmp(argv[i], "--use-data-section") == 0) - use_data_section = 1; - else if (strncmp(argv[i], "--symbol-prefix=", 16) == 0) { - char *p = &argv[i][16]; - /* skip quote */ - if ((*p == '"' && *(p+2) == '"') || (*p == '\'' && *(p+2) == '\'')) - p++; - symbol_prefix_char = *p; - } else if (strcmp(argv[i], "--base-relative") == 0) - base_relative = 1; - else - usage(); - } - } else if (argc != 1) - usage(); - - read_map(stdin); - if (absolute_percpu) - make_percpus_absolute(); - if (base_relative) - record_relative_base(); - sort_symbols(); - optimize_token_table(); - write_src(); - - return 0; -} diff --git a/src/linux/scripts/kconfig/.gitignore b/src/linux/scripts/kconfig/.gitignore deleted file mode 100644 index 235fcbf..0000000 --- a/src/linux/scripts/kconfig/.gitignore +++ /dev/null @@ -1,23 +0,0 @@ -# -# Generated files -# -config* -*.lex.c -*.tab.c -*.tab.h -zconf.hash.c -*.moc -gconf.glade.h -*.pot -*.mo - -# -# configuration programs -# -conf -conf.exe -mconf -nconf -qconf -gconf -kxgettext diff --git a/src/linux/scripts/kconfig/Makefile b/src/linux/scripts/kconfig/Makefile deleted file mode 100644 index 90a091b..0000000 --- a/src/linux/scripts/kconfig/Makefile +++ /dev/null @@ -1,296 +0,0 @@ -# =========================================================================== -# Kernel configuration targets -# These targets are used from top-level makefile - -PHONY += xconfig gconfig menuconfig config silentoldconfig update-po-config \ - localmodconfig localyesconfig - -ifdef KBUILD_KCONFIG -Kconfig := $(KBUILD_KCONFIG) -else -Kconfig := Kconfig -endif - -ifeq ($(quiet),silent_) -silent := -s -endif - -# We need this, in case the user has it in its environment -unexport CONFIG_ - -xconfig: $(obj)/qconf - $< $(silent) $(Kconfig) - -gconfig: $(obj)/gconf - $< $(silent) $(Kconfig) - -menuconfig: $(obj)/mconf - $< $(silent) $(Kconfig) - -config: $(obj)/conf - $< $(silent) --oldaskconfig $(Kconfig) - -nconfig: $(obj)/nconf - $< $(silent) $(Kconfig) - -silentoldconfig: $(obj)/conf - $(Q)mkdir -p include/config include/generated - $(Q)test -e include/generated/autoksyms.h || \ - touch include/generated/autoksyms.h - $< $(silent) --$@ $(Kconfig) - -localyesconfig localmodconfig: $(obj)/streamline_config.pl $(obj)/conf - $(Q)mkdir -p include/config include/generated - $(Q)perl $< --$@ $(srctree) $(Kconfig) > .tmp.config - $(Q)if [ -f .config ]; then \ - cmp -s .tmp.config .config || \ - (mv -f .config .config.old.1; \ - mv -f .tmp.config .config; \ - $(obj)/conf $(silent) --silentoldconfig $(Kconfig); \ - mv -f .config.old.1 .config.old) \ - else \ - mv -f .tmp.config .config; \ - $(obj)/conf $(silent) --silentoldconfig $(Kconfig); \ - fi - $(Q)rm -f .tmp.config - -# Create new linux.pot file -# Adjust charset to UTF-8 in .po file to accept UTF-8 in Kconfig files -update-po-config: $(obj)/kxgettext $(obj)/gconf.glade.h - $(Q)$(kecho) " GEN config.pot" - $(Q)xgettext --default-domain=linux \ - --add-comments --keyword=_ --keyword=N_ \ - --from-code=UTF-8 \ - --files-from=$(srctree)/scripts/kconfig/POTFILES.in \ - --directory=$(srctree) --directory=$(objtree) \ - --output $(obj)/config.pot - $(Q)sed -i s/CHARSET/UTF-8/ $(obj)/config.pot - $(Q)(for i in `ls $(srctree)/arch/*/Kconfig \ - $(srctree)/arch/*/um/Kconfig`; \ - do \ - $(kecho) " GEN $$i"; \ - $(obj)/kxgettext $$i \ - >> $(obj)/config.pot; \ - done ) - $(Q)$(kecho) " GEN linux.pot" - $(Q)msguniq --sort-by-file --to-code=UTF-8 $(obj)/config.pot \ - --output $(obj)/linux.pot - $(Q)rm -f $(obj)/config.pot - -# These targets map 1:1 to the commandline options of 'conf' -simple-targets := oldconfig allnoconfig allyesconfig allmodconfig \ - alldefconfig randconfig listnewconfig olddefconfig -PHONY += $(simple-targets) - -$(simple-targets): $(obj)/conf - $< $(silent) --$@ $(Kconfig) - -PHONY += oldnoconfig savedefconfig defconfig - -# oldnoconfig is an alias of olddefconfig, because people already are dependent -# on its behavior (sets new symbols to their default value but not 'n') with the -# counter-intuitive name. -oldnoconfig: olddefconfig - -savedefconfig: $(obj)/conf - $< $(silent) --$@=defconfig $(Kconfig) - -defconfig: $(obj)/conf -ifeq ($(KBUILD_DEFCONFIG),) - $< $(silent) --defconfig $(Kconfig) -else -ifneq ($(wildcard $(srctree)/arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG)),) - @$(kecho) "*** Default configuration is based on '$(KBUILD_DEFCONFIG)'" - $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$(KBUILD_DEFCONFIG) $(Kconfig) -else - @$(kecho) "*** Default configuration is based on target '$(KBUILD_DEFCONFIG)'" - $(Q)$(MAKE) -f $(srctree)/Makefile $(KBUILD_DEFCONFIG) -endif -endif - -%_defconfig: $(obj)/conf - $(Q)$< $(silent) --defconfig=arch/$(SRCARCH)/configs/$@ $(Kconfig) - -configfiles=$(wildcard $(srctree)/kernel/configs/$@ $(srctree)/arch/$(SRCARCH)/configs/$@) - -%.config: $(obj)/conf - $(if $(call configfiles),, $(error No configuration exists for this target on this architecture)) - $(Q)$(CONFIG_SHELL) $(srctree)/scripts/kconfig/merge_config.sh -m .config $(configfiles) - +$(Q)yes "" | $(MAKE) -f $(srctree)/Makefile oldconfig - -PHONY += kvmconfig -kvmconfig: kvm_guest.config - @: - -PHONY += xenconfig -xenconfig: xen.config - @: - -PHONY += tinyconfig -tinyconfig: - $(Q)$(MAKE) -f $(srctree)/Makefile allnoconfig tiny.config - -# Help text used by make help -help: - @echo ' config - Update current config utilising a line-oriented program' - @echo ' nconfig - Update current config utilising a ncurses menu based' - @echo ' program' - @echo ' menuconfig - Update current config utilising a menu based program' - @echo ' xconfig - Update current config utilising a Qt based front-end' - @echo ' gconfig - Update current config utilising a GTK+ based front-end' - @echo ' oldconfig - Update current config utilising a provided .config as base' - @echo ' localmodconfig - Update current config disabling modules not loaded' - @echo ' localyesconfig - Update current config converting local mods to core' - @echo ' silentoldconfig - Same as oldconfig, but quietly, additionally update deps' - @echo ' defconfig - New config with default from ARCH supplied defconfig' - @echo ' savedefconfig - Save current config as ./defconfig (minimal config)' - @echo ' allnoconfig - New config where all options are answered with no' - @echo ' allyesconfig - New config where all options are accepted with yes' - @echo ' allmodconfig - New config selecting modules when possible' - @echo ' alldefconfig - New config with all symbols set to default' - @echo ' randconfig - New config with random answer to all options' - @echo ' listnewconfig - List new options' - @echo ' olddefconfig - Same as silentoldconfig but sets new symbols to their' - @echo ' default value' - @echo ' kvmconfig - Enable additional options for kvm guest kernel support' - @echo ' xenconfig - Enable additional options for xen dom0 and guest kernel support' - @echo ' tinyconfig - Configure the tiniest possible kernel' - -# lxdialog stuff -check-lxdialog := $(srctree)/$(src)/lxdialog/check-lxdialog.sh - -# Use recursively expanded variables so we do not call gcc unless -# we really need to do so. (Do not call gcc as part of make mrproper) -HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags) \ - -DLOCALE - -# =========================================================================== -# Shared Makefile for the various kconfig executables: -# conf: Used for defconfig, oldconfig and related targets -# nconf: Used for the nconfig target. -# Utilizes ncurses -# mconf: Used for the menuconfig target -# Utilizes the lxdialog package -# qconf: Used for the xconfig target -# Based on Qt which needs to be installed to compile it -# gconf: Used for the gconfig target -# Based on GTK+ which needs to be installed to compile it -# object files used by all kconfig flavours - -lxdialog := lxdialog/checklist.o lxdialog/util.o lxdialog/inputbox.o -lxdialog += lxdialog/textbox.o lxdialog/yesno.o lxdialog/menubox.o - -conf-objs := conf.o zconf.tab.o -mconf-objs := mconf.o zconf.tab.o $(lxdialog) -nconf-objs := nconf.o zconf.tab.o nconf.gui.o -kxgettext-objs := kxgettext.o zconf.tab.o -qconf-cxxobjs := qconf.o -qconf-objs := zconf.tab.o -gconf-objs := gconf.o zconf.tab.o - -hostprogs-y := conf nconf mconf kxgettext qconf gconf - -clean-files := qconf.moc .tmp_qtcheck .tmp_gtkcheck -clean-files += zconf.tab.c zconf.lex.c zconf.hash.c gconf.glade.h -clean-files += config.pot linux.pot - -# Check that we have the required ncurses stuff installed for lxdialog (menuconfig) -PHONY += $(obj)/dochecklxdialog -$(addprefix $(obj)/,$(lxdialog)): $(obj)/dochecklxdialog -$(obj)/dochecklxdialog: - $(Q)$(CONFIG_SHELL) $(check-lxdialog) -check $(HOSTCC) $(HOST_EXTRACFLAGS) $(HOSTLOADLIBES_mconf) - -always := dochecklxdialog - -# Add environment specific flags -HOST_EXTRACFLAGS += $(shell $(CONFIG_SHELL) $(srctree)/$(src)/check.sh $(HOSTCC) $(HOSTCFLAGS)) - -# generated files seem to need this to find local include files -HOSTCFLAGS_zconf.lex.o := -I$(src) -HOSTCFLAGS_zconf.tab.o := -I$(src) - -LEX_PREFIX_zconf := zconf -YACC_PREFIX_zconf := zconf - -HOSTLOADLIBES_qconf = $(KC_QT_LIBS) -HOSTCXXFLAGS_qconf.o = $(KC_QT_CFLAGS) - -HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` -HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \ - -Wno-missing-prototypes - -HOSTLOADLIBES_mconf = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC)) - -HOSTLOADLIBES_nconf = $(shell \ - pkg-config --libs menuw panelw ncursesw 2>/dev/null \ - || pkg-config --libs menu panel ncurses 2>/dev/null \ - || echo "-lmenu -lpanel -lncurses" ) -$(obj)/qconf.o: $(obj)/.tmp_qtcheck - -ifeq ($(MAKECMDGOALS),xconfig) -$(obj)/.tmp_qtcheck: $(src)/Makefile --include $(obj)/.tmp_qtcheck - -# Qt needs some extra effort... -$(obj)/.tmp_qtcheck: - @set -e; $(kecho) " CHECK qt"; \ - if pkg-config --exists Qt5Core; then \ - cflags="-std=c++11 -fPIC `pkg-config --cflags Qt5Core Qt5Gui Qt5Widgets`"; \ - libs=`pkg-config --libs Qt5Core Qt5Gui Qt5Widgets`; \ - moc=`pkg-config --variable=host_bins Qt5Core`/moc; \ - elif pkg-config --exists QtCore; then \ - cflags=`pkg-config --cflags QtCore QtGui`; \ - libs=`pkg-config --libs QtCore QtGui`; \ - moc=`pkg-config --variable=moc_location QtCore`; \ - else \ - echo >&2 "*"; \ - echo >&2 "* Could not find Qt via pkg-config."; \ - echo >&2 "* Please install either Qt 4.8 or 5.x. and make sure it's in PKG_CONFIG_PATH"; \ - echo >&2 "*"; \ - exit 1; \ - fi; \ - echo "KC_QT_CFLAGS=$$cflags" > $@; \ - echo "KC_QT_LIBS=$$libs" >> $@; \ - echo "KC_QT_MOC=$$moc" >> $@ -endif - -$(obj)/gconf.o: $(obj)/.tmp_gtkcheck - -ifeq ($(MAKECMDGOALS),gconfig) --include $(obj)/.tmp_gtkcheck - -# GTK+ needs some extra effort, too... -$(obj)/.tmp_gtkcheck: - @if `pkg-config --exists gtk+-2.0 gmodule-2.0 libglade-2.0`; then \ - if `pkg-config --atleast-version=2.0.0 gtk+-2.0`; then \ - touch $@; \ - else \ - echo >&2 "*"; \ - echo >&2 "* GTK+ is present but version >= 2.0.0 is required."; \ - echo >&2 "*"; \ - false; \ - fi \ - else \ - echo >&2 "*"; \ - echo >&2 "* Unable to find the GTK+ installation. Please make sure that"; \ - echo >&2 "* the GTK+ 2.0 development package is correctly installed..."; \ - echo >&2 "* You need gtk+-2.0, glib-2.0 and libglade-2.0."; \ - echo >&2 "*"; \ - false; \ - fi -endif - -$(obj)/zconf.tab.o: $(obj)/zconf.lex.c $(obj)/zconf.hash.c - -$(obj)/qconf.o: $(obj)/qconf.moc - -quiet_cmd_moc = MOC $@ - cmd_moc = $(KC_QT_MOC) -i $< -o $@ - -$(obj)/%.moc: $(src)/%.h $(obj)/.tmp_qtcheck - $(call cmd,moc) - -# Extract gconf menu items for i18n support -$(obj)/gconf.glade.h: $(obj)/gconf.glade - $(Q)intltool-extract --type=gettext/glade --srcdir=$(srctree) \ - $(obj)/gconf.glade diff --git a/src/linux/scripts/kconfig/check.sh b/src/linux/scripts/kconfig/check.sh deleted file mode 100755 index 55b79ba..0000000 --- a/src/linux/scripts/kconfig/check.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/sh -# Needed for systems without gettext -$* -x c -o /dev/null - > /dev/null 2>&1 << EOF -#include -int main() -{ - gettext(""); - return 0; -} -EOF -if [ ! "$?" -eq "0" ]; then - echo -DKBUILD_NO_NLS; -fi diff --git a/src/linux/scripts/kconfig/conf.c b/src/linux/scripts/kconfig/conf.c deleted file mode 100644 index 866369f..0000000 --- a/src/linux/scripts/kconfig/conf.c +++ /dev/null @@ -1,723 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "lkc.h" - -static void conf(struct menu *menu); -static void check_conf(struct menu *menu); -static void xfgets(char *str, int size, FILE *in); - -enum input_mode { - oldaskconfig, - silentoldconfig, - oldconfig, - allnoconfig, - allyesconfig, - allmodconfig, - alldefconfig, - randconfig, - defconfig, - savedefconfig, - listnewconfig, - olddefconfig, -} input_mode = oldaskconfig; - -static int indent = 1; -static int tty_stdio; -static int valid_stdin = 1; -static int sync_kconfig; -static int conf_cnt; -static char line[PATH_MAX]; -static struct menu *rootEntry; - -static void print_help(struct menu *menu) -{ - struct gstr help = str_new(); - - menu_get_ext_help(menu, &help); - - printf("\n%s\n", str_get(&help)); - str_free(&help); -} - -static void strip(char *str) -{ - char *p = str; - int l; - - while ((isspace(*p))) - p++; - l = strlen(p); - if (p != str) - memmove(str, p, l + 1); - if (!l) - return; - p = str + l - 1; - while ((isspace(*p))) - *p-- = 0; -} - -static void check_stdin(void) -{ - if (!valid_stdin) { - printf(_("aborted!\n\n")); - printf(_("Console input/output is redirected. ")); - printf(_("Run 'make oldconfig' to update configuration.\n\n")); - exit(1); - } -} - -static int conf_askvalue(struct symbol *sym, const char *def) -{ - enum symbol_type type = sym_get_type(sym); - - if (!sym_has_value(sym)) - printf(_("(NEW) ")); - - line[0] = '\n'; - line[1] = 0; - - if (!sym_is_changable(sym)) { - printf("%s\n", def); - line[0] = '\n'; - line[1] = 0; - return 0; - } - - switch (input_mode) { - case oldconfig: - case silentoldconfig: - if (sym_has_value(sym)) { - printf("%s\n", def); - return 0; - } - check_stdin(); - /* fall through */ - case oldaskconfig: - fflush(stdout); - xfgets(line, sizeof(line), stdin); - if (!tty_stdio) - printf("\n"); - return 1; - default: - break; - } - - switch (type) { - case S_INT: - case S_HEX: - case S_STRING: - printf("%s\n", def); - return 1; - default: - ; - } - printf("%s", line); - return 1; -} - -static int conf_string(struct menu *menu) -{ - struct symbol *sym = menu->sym; - const char *def; - - while (1) { - printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); - printf("(%s) ", sym->name); - def = sym_get_string_value(sym); - if (sym_get_string_value(sym)) - printf("[%s] ", def); - if (!conf_askvalue(sym, def)) - return 0; - switch (line[0]) { - case '\n': - break; - case '?': - /* print help */ - if (line[1] == '\n') { - print_help(menu); - def = NULL; - break; - } - /* fall through */ - default: - line[strlen(line)-1] = 0; - def = line; - } - if (def && sym_set_string_value(sym, def)) - return 0; - } -} - -static int conf_sym(struct menu *menu) -{ - struct symbol *sym = menu->sym; - tristate oldval, newval; - - while (1) { - printf("%*s%s ", indent - 1, "", _(menu->prompt->text)); - if (sym->name) - printf("(%s) ", sym->name); - putchar('['); - oldval = sym_get_tristate_value(sym); - switch (oldval) { - case no: - putchar('N'); - break; - case mod: - putchar('M'); - break; - case yes: - putchar('Y'); - break; - } - if (oldval != no && sym_tristate_within_range(sym, no)) - printf("/n"); - if (oldval != mod && sym_tristate_within_range(sym, mod)) - printf("/m"); - if (oldval != yes && sym_tristate_within_range(sym, yes)) - printf("/y"); - if (menu_has_help(menu)) - printf("/?"); - printf("] "); - if (!conf_askvalue(sym, sym_get_string_value(sym))) - return 0; - strip(line); - - switch (line[0]) { - case 'n': - case 'N': - newval = no; - if (!line[1] || !strcmp(&line[1], "o")) - break; - continue; - case 'm': - case 'M': - newval = mod; - if (!line[1]) - break; - continue; - case 'y': - case 'Y': - newval = yes; - if (!line[1] || !strcmp(&line[1], "es")) - break; - continue; - case 0: - newval = oldval; - break; - case '?': - goto help; - default: - continue; - } - if (sym_set_tristate_value(sym, newval)) - return 0; -help: - print_help(menu); - } -} - -static int conf_choice(struct menu *menu) -{ - struct symbol *sym, *def_sym; - struct menu *child; - bool is_new; - - sym = menu->sym; - is_new = !sym_has_value(sym); - if (sym_is_changable(sym)) { - conf_sym(menu); - sym_calc_value(sym); - switch (sym_get_tristate_value(sym)) { - case no: - return 1; - case mod: - return 0; - case yes: - break; - } - } else { - switch (sym_get_tristate_value(sym)) { - case no: - return 1; - case mod: - printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); - return 0; - case yes: - break; - } - } - - while (1) { - int cnt, def; - - printf("%*s%s\n", indent - 1, "", _(menu_get_prompt(menu))); - def_sym = sym_get_choice_value(sym); - cnt = def = 0; - line[0] = 0; - for (child = menu->list; child; child = child->next) { - if (!menu_is_visible(child)) - continue; - if (!child->sym) { - printf("%*c %s\n", indent, '*', _(menu_get_prompt(child))); - continue; - } - cnt++; - if (child->sym == def_sym) { - def = cnt; - printf("%*c", indent, '>'); - } else - printf("%*c", indent, ' '); - printf(" %d. %s", cnt, _(menu_get_prompt(child))); - if (child->sym->name) - printf(" (%s)", child->sym->name); - if (!sym_has_value(child->sym)) - printf(_(" (NEW)")); - printf("\n"); - } - printf(_("%*schoice"), indent - 1, ""); - if (cnt == 1) { - printf("[1]: 1\n"); - goto conf_childs; - } - printf("[1-%d", cnt); - if (menu_has_help(menu)) - printf("?"); - printf("]: "); - switch (input_mode) { - case oldconfig: - case silentoldconfig: - if (!is_new) { - cnt = def; - printf("%d\n", cnt); - break; - } - check_stdin(); - /* fall through */ - case oldaskconfig: - fflush(stdout); - xfgets(line, sizeof(line), stdin); - strip(line); - if (line[0] == '?') { - print_help(menu); - continue; - } - if (!line[0]) - cnt = def; - else if (isdigit(line[0])) - cnt = atoi(line); - else - continue; - break; - default: - break; - } - - conf_childs: - for (child = menu->list; child; child = child->next) { - if (!child->sym || !menu_is_visible(child)) - continue; - if (!--cnt) - break; - } - if (!child) - continue; - if (line[0] && line[strlen(line) - 1] == '?') { - print_help(child); - continue; - } - sym_set_choice_value(sym, child->sym); - for (child = child->list; child; child = child->next) { - indent += 2; - conf(child); - indent -= 2; - } - return 1; - } -} - -static void conf(struct menu *menu) -{ - struct symbol *sym; - struct property *prop; - struct menu *child; - - if (!menu_is_visible(menu)) - return; - - sym = menu->sym; - prop = menu->prompt; - if (prop) { - const char *prompt; - - switch (prop->type) { - case P_MENU: - if ((input_mode == silentoldconfig || - input_mode == listnewconfig || - input_mode == olddefconfig) && - rootEntry != menu) { - check_conf(menu); - return; - } - /* fall through */ - case P_COMMENT: - prompt = menu_get_prompt(menu); - if (prompt) - printf("%*c\n%*c %s\n%*c\n", - indent, '*', - indent, '*', _(prompt), - indent, '*'); - default: - ; - } - } - - if (!sym) - goto conf_childs; - - if (sym_is_choice(sym)) { - conf_choice(menu); - if (sym->curr.tri != mod) - return; - goto conf_childs; - } - - switch (sym->type) { - case S_INT: - case S_HEX: - case S_STRING: - conf_string(menu); - break; - default: - conf_sym(menu); - break; - } - -conf_childs: - if (sym) - indent += 2; - for (child = menu->list; child; child = child->next) - conf(child); - if (sym) - indent -= 2; -} - -static void check_conf(struct menu *menu) -{ - struct symbol *sym; - struct menu *child; - - if (!menu_is_visible(menu)) - return; - - sym = menu->sym; - if (sym && !sym_has_value(sym)) { - if (sym_is_changable(sym) || - (sym_is_choice(sym) && sym_get_tristate_value(sym) == yes)) { - if (input_mode == listnewconfig) { - if (sym->name && !sym_is_choice_value(sym)) { - printf("%s%s\n", CONFIG_, sym->name); - } - } else if (input_mode != olddefconfig) { - if (!conf_cnt++) - printf(_("*\n* Restart config...\n*\n")); - rootEntry = menu_get_parent_menu(menu); - conf(rootEntry); - } - } - } - - for (child = menu->list; child; child = child->next) - check_conf(child); -} - -static struct option long_opts[] = { - {"oldaskconfig", no_argument, NULL, oldaskconfig}, - {"oldconfig", no_argument, NULL, oldconfig}, - {"silentoldconfig", no_argument, NULL, silentoldconfig}, - {"defconfig", optional_argument, NULL, defconfig}, - {"savedefconfig", required_argument, NULL, savedefconfig}, - {"allnoconfig", no_argument, NULL, allnoconfig}, - {"allyesconfig", no_argument, NULL, allyesconfig}, - {"allmodconfig", no_argument, NULL, allmodconfig}, - {"alldefconfig", no_argument, NULL, alldefconfig}, - {"randconfig", no_argument, NULL, randconfig}, - {"listnewconfig", no_argument, NULL, listnewconfig}, - {"olddefconfig", no_argument, NULL, olddefconfig}, - /* - * oldnoconfig is an alias of olddefconfig, because people already - * are dependent on its behavior(sets new symbols to their default - * value but not 'n') with the counter-intuitive name. - */ - {"oldnoconfig", no_argument, NULL, olddefconfig}, - {NULL, 0, NULL, 0} -}; - -static void conf_usage(const char *progname) -{ - - printf("Usage: %s [-s] [option] \n", progname); - printf("[option] is _one_ of the following:\n"); - printf(" --listnewconfig List new options\n"); - printf(" --oldaskconfig Start a new configuration using a line-oriented program\n"); - printf(" --oldconfig Update a configuration using a provided .config as base\n"); - printf(" --silentoldconfig Same as oldconfig, but quietly, additionally update deps\n"); - printf(" --olddefconfig Same as silentoldconfig but sets new symbols to their default value\n"); - printf(" --oldnoconfig An alias of olddefconfig\n"); - printf(" --defconfig New config with default defined in \n"); - printf(" --savedefconfig Save the minimal current configuration to \n"); - printf(" --allnoconfig New config where all options are answered with no\n"); - printf(" --allyesconfig New config where all options are answered with yes\n"); - printf(" --allmodconfig New config where all options are answered with mod\n"); - printf(" --alldefconfig New config with all symbols set to default\n"); - printf(" --randconfig New config with random answer to all options\n"); -} - -int main(int ac, char **av) -{ - const char *progname = av[0]; - int opt; - const char *name, *defconfig_file = NULL /* gcc uninit */; - struct stat tmpstat; - - setlocale(LC_ALL, ""); - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); - - tty_stdio = isatty(0) && isatty(1) && isatty(2); - - while ((opt = getopt_long(ac, av, "s", long_opts, NULL)) != -1) { - if (opt == 's') { - conf_set_message_callback(NULL); - continue; - } - input_mode = (enum input_mode)opt; - switch (opt) { - case silentoldconfig: - sync_kconfig = 1; - break; - case defconfig: - case savedefconfig: - defconfig_file = optarg; - break; - case randconfig: - { - struct timeval now; - unsigned int seed; - char *seed_env; - - /* - * Use microseconds derived seed, - * compensate for systems where it may be zero - */ - gettimeofday(&now, NULL); - seed = (unsigned int)((now.tv_sec + 1) * (now.tv_usec + 1)); - - seed_env = getenv("KCONFIG_SEED"); - if( seed_env && *seed_env ) { - char *endp; - int tmp = (int)strtol(seed_env, &endp, 0); - if (*endp == '\0') { - seed = tmp; - } - } - fprintf( stderr, "KCONFIG_SEED=0x%X\n", seed ); - srand(seed); - break; - } - case oldaskconfig: - case oldconfig: - case allnoconfig: - case allyesconfig: - case allmodconfig: - case alldefconfig: - case listnewconfig: - case olddefconfig: - break; - case '?': - conf_usage(progname); - exit(1); - break; - } - } - if (ac == optind) { - printf(_("%s: Kconfig file missing\n"), av[0]); - conf_usage(progname); - exit(1); - } - name = av[optind]; - conf_parse(name); - //zconfdump(stdout); - if (sync_kconfig) { - name = conf_get_configname(); - if (stat(name, &tmpstat)) { - fprintf(stderr, _("***\n" - "*** Configuration file \"%s\" not found!\n" - "***\n" - "*** Please run some configurator (e.g. \"make oldconfig\" or\n" - "*** \"make menuconfig\" or \"make xconfig\").\n" - "***\n"), name); - exit(1); - } - } - - switch (input_mode) { - case defconfig: - if (!defconfig_file) - defconfig_file = conf_get_default_confname(); - if (conf_read(defconfig_file)) { - printf(_("***\n" - "*** Can't find default configuration \"%s\"!\n" - "***\n"), defconfig_file); - exit(1); - } - break; - case savedefconfig: - case silentoldconfig: - case oldaskconfig: - case oldconfig: - case listnewconfig: - case olddefconfig: - conf_read(NULL); - break; - case allnoconfig: - case allyesconfig: - case allmodconfig: - case alldefconfig: - case randconfig: - name = getenv("KCONFIG_ALLCONFIG"); - if (!name) - break; - if ((strcmp(name, "") != 0) && (strcmp(name, "1") != 0)) { - if (conf_read_simple(name, S_DEF_USER)) { - fprintf(stderr, - _("*** Can't read seed configuration \"%s\"!\n"), - name); - exit(1); - } - break; - } - switch (input_mode) { - case allnoconfig: name = "allno.config"; break; - case allyesconfig: name = "allyes.config"; break; - case allmodconfig: name = "allmod.config"; break; - case alldefconfig: name = "alldef.config"; break; - case randconfig: name = "allrandom.config"; break; - default: break; - } - if (conf_read_simple(name, S_DEF_USER) && - conf_read_simple("all.config", S_DEF_USER)) { - fprintf(stderr, - _("*** KCONFIG_ALLCONFIG set, but no \"%s\" or \"all.config\" file found\n"), - name); - exit(1); - } - break; - default: - break; - } - - if (sync_kconfig) { - if (conf_get_changed()) { - name = getenv("KCONFIG_NOSILENTUPDATE"); - if (name && *name) { - fprintf(stderr, - _("\n*** The configuration requires explicit update.\n\n")); - return 1; - } - } - valid_stdin = tty_stdio; - } - - switch (input_mode) { - case allnoconfig: - conf_set_all_new_symbols(def_no); - break; - case allyesconfig: - conf_set_all_new_symbols(def_yes); - break; - case allmodconfig: - conf_set_all_new_symbols(def_mod); - break; - case alldefconfig: - conf_set_all_new_symbols(def_default); - break; - case randconfig: - /* Really nothing to do in this loop */ - while (conf_set_all_new_symbols(def_random)) ; - break; - case defconfig: - conf_set_all_new_symbols(def_default); - break; - case savedefconfig: - break; - case oldaskconfig: - rootEntry = &rootmenu; - conf(&rootmenu); - input_mode = silentoldconfig; - /* fall through */ - case oldconfig: - case listnewconfig: - case olddefconfig: - case silentoldconfig: - /* Update until a loop caused no more changes */ - do { - conf_cnt = 0; - check_conf(&rootmenu); - } while (conf_cnt && - (input_mode != listnewconfig && - input_mode != olddefconfig)); - break; - } - - if (sync_kconfig) { - /* silentoldconfig is used during the build so we shall update autoconf. - * All other commands are only used to generate a config. - */ - if (conf_get_changed() && conf_write(NULL)) { - fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); - exit(1); - } - if (conf_write_autoconf()) { - fprintf(stderr, _("\n*** Error during update of the configuration.\n\n")); - return 1; - } - } else if (input_mode == savedefconfig) { - if (conf_write_defconfig(defconfig_file)) { - fprintf(stderr, _("n*** Error while saving defconfig to: %s\n\n"), - defconfig_file); - return 1; - } - } else if (input_mode != listnewconfig) { - if (conf_write(NULL)) { - fprintf(stderr, _("\n*** Error during writing of the configuration.\n\n")); - exit(1); - } - } - return 0; -} - -/* - * Helper function to facilitate fgets() by Jean Sacren. - */ -void xfgets(char *str, int size, FILE *in) -{ - if (fgets(str, size, in) == NULL) - fprintf(stderr, "\nError in reading or end of file.\n"); -} diff --git a/src/linux/scripts/kconfig/confdata.c b/src/linux/scripts/kconfig/confdata.c deleted file mode 100644 index 297b079..0000000 --- a/src/linux/scripts/kconfig/confdata.c +++ /dev/null @@ -1,1249 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "lkc.h" - -struct conf_printer { - void (*print_symbol)(FILE *, struct symbol *, const char *, void *); - void (*print_comment)(FILE *, const char *, void *); -}; - -static void conf_warning(const char *fmt, ...) - __attribute__ ((format (printf, 1, 2))); - -static void conf_message(const char *fmt, ...) - __attribute__ ((format (printf, 1, 2))); - -static const char *conf_filename; -static int conf_lineno, conf_warnings, conf_unsaved; - -const char conf_defname[] = "arch/$ARCH/defconfig"; - -static void conf_warning(const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "%s:%d:warning: ", conf_filename, conf_lineno); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); - conf_warnings++; -} - -static void conf_default_message_callback(const char *fmt, va_list ap) -{ - printf("#\n# "); - vprintf(fmt, ap); - printf("\n#\n"); -} - -static void (*conf_message_callback) (const char *fmt, va_list ap) = - conf_default_message_callback; -void conf_set_message_callback(void (*fn) (const char *fmt, va_list ap)) -{ - conf_message_callback = fn; -} - -static void conf_message(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - if (conf_message_callback) - conf_message_callback(fmt, ap); - va_end(ap); -} - -const char *conf_get_configname(void) -{ - char *name = getenv("KCONFIG_CONFIG"); - - return name ? name : ".config"; -} - -const char *conf_get_autoconfig_name(void) -{ - char *name = getenv("KCONFIG_AUTOCONFIG"); - - return name ? name : "include/config/auto.conf"; -} - -static char *conf_expand_value(const char *in) -{ - struct symbol *sym; - const char *src; - static char res_value[SYMBOL_MAXLENGTH]; - char *dst, name[SYMBOL_MAXLENGTH]; - - res_value[0] = 0; - dst = name; - while ((src = strchr(in, '$'))) { - strncat(res_value, in, src - in); - src++; - dst = name; - while (isalnum(*src) || *src == '_') - *dst++ = *src++; - *dst = 0; - sym = sym_lookup(name, 0); - sym_calc_value(sym); - strcat(res_value, sym_get_string_value(sym)); - in = src; - } - strcat(res_value, in); - - return res_value; -} - -char *conf_get_default_confname(void) -{ - struct stat buf; - static char fullname[PATH_MAX+1]; - char *env, *name; - - name = conf_expand_value(conf_defname); - env = getenv(SRCTREE); - if (env) { - sprintf(fullname, "%s/%s", env, name); - if (!stat(fullname, &buf)) - return fullname; - } - return name; -} - -static int conf_set_sym_val(struct symbol *sym, int def, int def_flags, char *p) -{ - char *p2; - - switch (sym->type) { - case S_TRISTATE: - if (p[0] == 'm') { - sym->def[def].tri = mod; - sym->flags |= def_flags; - break; - } - /* fall through */ - case S_BOOLEAN: - if (p[0] == 'y') { - sym->def[def].tri = yes; - sym->flags |= def_flags; - break; - } - if (p[0] == 'n') { - sym->def[def].tri = no; - sym->flags |= def_flags; - break; - } - if (def != S_DEF_AUTO) - conf_warning("symbol value '%s' invalid for %s", - p, sym->name); - return 1; - case S_OTHER: - if (*p != '"') { - for (p2 = p; *p2 && !isspace(*p2); p2++) - ; - sym->type = S_STRING; - goto done; - } - /* fall through */ - case S_STRING: - if (*p++ != '"') - break; - for (p2 = p; (p2 = strpbrk(p2, "\"\\")); p2++) { - if (*p2 == '"') { - *p2 = 0; - break; - } - memmove(p2, p2 + 1, strlen(p2)); - } - if (!p2) { - if (def != S_DEF_AUTO) - conf_warning("invalid string found"); - return 1; - } - /* fall through */ - case S_INT: - case S_HEX: - done: - if (sym_string_valid(sym, p)) { - sym->def[def].val = strdup(p); - sym->flags |= def_flags; - } else { - if (def != S_DEF_AUTO) - conf_warning("symbol value '%s' invalid for %s", - p, sym->name); - return 1; - } - break; - default: - ; - } - return 0; -} - -#define LINE_GROWTH 16 -static int add_byte(int c, char **lineptr, size_t slen, size_t *n) -{ - char *nline; - size_t new_size = slen + 1; - if (new_size > *n) { - new_size += LINE_GROWTH - 1; - new_size *= 2; - nline = realloc(*lineptr, new_size); - if (!nline) - return -1; - - *lineptr = nline; - *n = new_size; - } - - (*lineptr)[slen] = c; - - return 0; -} - -static ssize_t compat_getline(char **lineptr, size_t *n, FILE *stream) -{ - char *line = *lineptr; - size_t slen = 0; - - for (;;) { - int c = getc(stream); - - switch (c) { - case '\n': - if (add_byte(c, &line, slen, n) < 0) - goto e_out; - slen++; - /* fall through */ - case EOF: - if (add_byte('\0', &line, slen, n) < 0) - goto e_out; - *lineptr = line; - if (slen == 0) - return -1; - return slen; - default: - if (add_byte(c, &line, slen, n) < 0) - goto e_out; - slen++; - } - } - -e_out: - line[slen-1] = '\0'; - *lineptr = line; - return -1; -} - -int conf_read_simple(const char *name, int def) -{ - FILE *in = NULL; - char *line = NULL; - size_t line_asize = 0; - char *p, *p2; - struct symbol *sym; - int i, def_flags; - - if (name) { - in = zconf_fopen(name); - } else { - struct property *prop; - - name = conf_get_configname(); - in = zconf_fopen(name); - if (in) - goto load; - sym_add_change_count(1); - if (!sym_defconfig_list) - return 1; - - for_all_defaults(sym_defconfig_list, prop) { - if (expr_calc_value(prop->visible.expr) == no || - prop->expr->type != E_SYMBOL) - continue; - name = conf_expand_value(prop->expr->left.sym->name); - in = zconf_fopen(name); - if (in) { - conf_message(_("using defaults found in %s"), - name); - goto load; - } - } - } - if (!in) - return 1; - -load: - conf_filename = name; - conf_lineno = 0; - conf_warnings = 0; - conf_unsaved = 0; - - def_flags = SYMBOL_DEF << def; - for_all_symbols(i, sym) { - sym->flags |= SYMBOL_CHANGED; - sym->flags &= ~(def_flags|SYMBOL_VALID); - if (sym_is_choice(sym)) - sym->flags |= def_flags; - switch (sym->type) { - case S_INT: - case S_HEX: - case S_STRING: - if (sym->def[def].val) - free(sym->def[def].val); - /* fall through */ - default: - sym->def[def].val = NULL; - sym->def[def].tri = no; - } - } - - while (compat_getline(&line, &line_asize, in) != -1) { - conf_lineno++; - sym = NULL; - if (line[0] == '#') { - if (memcmp(line + 2, CONFIG_, strlen(CONFIG_))) - continue; - p = strchr(line + 2 + strlen(CONFIG_), ' '); - if (!p) - continue; - *p++ = 0; - if (strncmp(p, "is not set", 10)) - continue; - if (def == S_DEF_USER) { - sym = sym_find(line + 2 + strlen(CONFIG_)); - if (!sym) { - sym_add_change_count(1); - goto setsym; - } - } else { - sym = sym_lookup(line + 2 + strlen(CONFIG_), 0); - if (sym->type == S_UNKNOWN) - sym->type = S_BOOLEAN; - } - if (sym->flags & def_flags) { - conf_warning("override: reassigning to symbol %s", sym->name); - } - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - sym->def[def].tri = no; - sym->flags |= def_flags; - break; - default: - ; - } - } else if (memcmp(line, CONFIG_, strlen(CONFIG_)) == 0) { - p = strchr(line + strlen(CONFIG_), '='); - if (!p) - continue; - *p++ = 0; - p2 = strchr(p, '\n'); - if (p2) { - *p2-- = 0; - if (*p2 == '\r') - *p2 = 0; - } - if (def == S_DEF_USER) { - sym = sym_find(line + strlen(CONFIG_)); - if (!sym) { - sym_add_change_count(1); - goto setsym; - } - } else { - sym = sym_lookup(line + strlen(CONFIG_), 0); - if (sym->type == S_UNKNOWN) - sym->type = S_OTHER; - } - if (sym->flags & def_flags) { - conf_warning("override: reassigning to symbol %s", sym->name); - } - if (conf_set_sym_val(sym, def, def_flags, p)) - continue; - } else { - if (line[0] != '\r' && line[0] != '\n') - conf_warning("unexpected data: %.*s", - (int)strcspn(line, "\r\n"), line); - - continue; - } -setsym: - if (sym && sym_is_choice_value(sym)) { - struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); - switch (sym->def[def].tri) { - case no: - break; - case mod: - if (cs->def[def].tri == yes) { - conf_warning("%s creates inconsistent choice state", sym->name); - cs->flags &= ~def_flags; - } - break; - case yes: - if (cs->def[def].tri != no) - conf_warning("override: %s changes choice state", sym->name); - cs->def[def].val = sym; - break; - } - cs->def[def].tri = EXPR_OR(cs->def[def].tri, sym->def[def].tri); - } - } - free(line); - fclose(in); - return 0; -} - -int conf_read(const char *name) -{ - struct symbol *sym; - int i; - - sym_set_change_count(0); - - if (conf_read_simple(name, S_DEF_USER)) { - sym_calc_value(modules_sym); - return 1; - } - - sym_calc_value(modules_sym); - - for_all_symbols(i, sym) { - sym_calc_value(sym); - if (sym_is_choice(sym) || (sym->flags & SYMBOL_AUTO)) - continue; - if (sym_has_value(sym) && (sym->flags & SYMBOL_WRITE)) { - /* check that calculated value agrees with saved value */ - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - if (sym->def[S_DEF_USER].tri != sym_get_tristate_value(sym)) - break; - if (!sym_is_choice(sym)) - continue; - /* fall through */ - default: - if (!strcmp(sym->curr.val, sym->def[S_DEF_USER].val)) - continue; - break; - } - } else if (!sym_has_value(sym) && !(sym->flags & SYMBOL_WRITE)) - /* no previous value and not saved */ - continue; - conf_unsaved++; - /* maybe print value in verbose mode... */ - } - - for_all_symbols(i, sym) { - if (sym_has_value(sym) && !sym_is_choice_value(sym)) { - /* Reset values of generates values, so they'll appear - * as new, if they should become visible, but that - * doesn't quite work if the Kconfig and the saved - * configuration disagree. - */ - if (sym->visible == no && !conf_unsaved) - sym->flags &= ~SYMBOL_DEF_USER; - switch (sym->type) { - case S_STRING: - case S_INT: - case S_HEX: - /* Reset a string value if it's out of range */ - if (sym_string_within_range(sym, sym->def[S_DEF_USER].val)) - break; - sym->flags &= ~(SYMBOL_VALID|SYMBOL_DEF_USER); - conf_unsaved++; - break; - default: - break; - } - } - } - - sym_add_change_count(conf_warnings || conf_unsaved); - - return 0; -} - -/* - * Kconfig configuration printer - * - * This printer is used when generating the resulting configuration after - * kconfig invocation and `defconfig' files. Unset symbol might be omitted by - * passing a non-NULL argument to the printer. - * - */ -static void -kconfig_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) -{ - - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - if (*value == 'n') { - bool skip_unset = (arg != NULL); - - if (!skip_unset) - fprintf(fp, "# %s%s is not set\n", - CONFIG_, sym->name); - return; - } - break; - default: - break; - } - - fprintf(fp, "%s%s=%s\n", CONFIG_, sym->name, value); -} - -static void -kconfig_print_comment(FILE *fp, const char *value, void *arg) -{ - const char *p = value; - size_t l; - - for (;;) { - l = strcspn(p, "\n"); - fprintf(fp, "#"); - if (l) { - fprintf(fp, " "); - xfwrite(p, l, 1, fp); - p += l; - } - fprintf(fp, "\n"); - if (*p++ == '\0') - break; - } -} - -static struct conf_printer kconfig_printer_cb = -{ - .print_symbol = kconfig_print_symbol, - .print_comment = kconfig_print_comment, -}; - -/* - * Header printer - * - * This printer is used when generating the `include/generated/autoconf.h' file. - */ -static void -header_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) -{ - - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: { - const char *suffix = ""; - - switch (*value) { - case 'n': - break; - case 'm': - suffix = "_MODULE"; - /* fall through */ - default: - fprintf(fp, "#define %s%s%s 1\n", - CONFIG_, sym->name, suffix); - } - break; - } - case S_HEX: { - const char *prefix = ""; - - if (value[0] != '0' || (value[1] != 'x' && value[1] != 'X')) - prefix = "0x"; - fprintf(fp, "#define %s%s %s%s\n", - CONFIG_, sym->name, prefix, value); - break; - } - case S_STRING: - case S_INT: - fprintf(fp, "#define %s%s %s\n", - CONFIG_, sym->name, value); - break; - default: - break; - } - -} - -static void -header_print_comment(FILE *fp, const char *value, void *arg) -{ - const char *p = value; - size_t l; - - fprintf(fp, "/*\n"); - for (;;) { - l = strcspn(p, "\n"); - fprintf(fp, " *"); - if (l) { - fprintf(fp, " "); - xfwrite(p, l, 1, fp); - p += l; - } - fprintf(fp, "\n"); - if (*p++ == '\0') - break; - } - fprintf(fp, " */\n"); -} - -static struct conf_printer header_printer_cb = -{ - .print_symbol = header_print_symbol, - .print_comment = header_print_comment, -}; - -/* - * Tristate printer - * - * This printer is used when generating the `include/config/tristate.conf' file. - */ -static void -tristate_print_symbol(FILE *fp, struct symbol *sym, const char *value, void *arg) -{ - - if (sym->type == S_TRISTATE && *value != 'n') - fprintf(fp, "%s%s=%c\n", CONFIG_, sym->name, (char)toupper(*value)); -} - -static struct conf_printer tristate_printer_cb = -{ - .print_symbol = tristate_print_symbol, - .print_comment = kconfig_print_comment, -}; - -static void conf_write_symbol(FILE *fp, struct symbol *sym, - struct conf_printer *printer, void *printer_arg) -{ - const char *str; - - switch (sym->type) { - case S_OTHER: - case S_UNKNOWN: - break; - case S_STRING: - str = sym_get_string_value(sym); - str = sym_escape_string_value(str); - printer->print_symbol(fp, sym, str, printer_arg); - free((void *)str); - break; - default: - str = sym_get_string_value(sym); - printer->print_symbol(fp, sym, str, printer_arg); - } -} - -static void -conf_write_heading(FILE *fp, struct conf_printer *printer, void *printer_arg) -{ - char buf[256]; - - snprintf(buf, sizeof(buf), - "\n" - "Automatically generated file; DO NOT EDIT.\n" - "%s\n", - rootmenu.prompt->text); - - printer->print_comment(fp, buf, printer_arg); -} - -/* - * Write out a minimal config. - * All values that has default values are skipped as this is redundant. - */ -int conf_write_defconfig(const char *filename) -{ - struct symbol *sym; - struct menu *menu; - FILE *out; - - out = fopen(filename, "w"); - if (!out) - return 1; - - sym_clear_all_valid(); - - /* Traverse all menus to find all relevant symbols */ - menu = rootmenu.list; - - while (menu != NULL) - { - sym = menu->sym; - if (sym == NULL) { - if (!menu_is_visible(menu)) - goto next_menu; - } else if (!sym_is_choice(sym)) { - sym_calc_value(sym); - if (!(sym->flags & SYMBOL_WRITE)) - goto next_menu; - sym->flags &= ~SYMBOL_WRITE; - /* If we cannot change the symbol - skip */ - if (!sym_is_changable(sym)) - goto next_menu; - /* If symbol equals to default value - skip */ - if (strcmp(sym_get_string_value(sym), sym_get_string_default(sym)) == 0) - goto next_menu; - - /* - * If symbol is a choice value and equals to the - * default for a choice - skip. - * But only if value is bool and equal to "y" and - * choice is not "optional". - * (If choice is "optional" then all values can be "n") - */ - if (sym_is_choice_value(sym)) { - struct symbol *cs; - struct symbol *ds; - - cs = prop_get_symbol(sym_get_choice_prop(sym)); - ds = sym_choice_default(cs); - if (!sym_is_optional(cs) && sym == ds) { - if ((sym->type == S_BOOLEAN) && - sym_get_tristate_value(sym) == yes) - goto next_menu; - } - } - conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); - } -next_menu: - if (menu->list != NULL) { - menu = menu->list; - } - else if (menu->next != NULL) { - menu = menu->next; - } else { - while ((menu = menu->parent)) { - if (menu->next != NULL) { - menu = menu->next; - break; - } - } - } - } - fclose(out); - return 0; -} - -int conf_write(const char *name) -{ - FILE *out; - struct symbol *sym; - struct menu *menu; - const char *basename; - const char *str; - char dirname[PATH_MAX+1], tmpname[PATH_MAX+1], newname[PATH_MAX+1]; - char *env; - - dirname[0] = 0; - if (name && name[0]) { - struct stat st; - char *slash; - - if (!stat(name, &st) && S_ISDIR(st.st_mode)) { - strcpy(dirname, name); - strcat(dirname, "/"); - basename = conf_get_configname(); - } else if ((slash = strrchr(name, '/'))) { - int size = slash - name + 1; - memcpy(dirname, name, size); - dirname[size] = 0; - if (slash[1]) - basename = slash + 1; - else - basename = conf_get_configname(); - } else - basename = name; - } else - basename = conf_get_configname(); - - sprintf(newname, "%s%s", dirname, basename); - env = getenv("KCONFIG_OVERWRITECONFIG"); - if (!env || !*env) { - sprintf(tmpname, "%s.tmpconfig.%d", dirname, (int)getpid()); - out = fopen(tmpname, "w"); - } else { - *tmpname = 0; - out = fopen(newname, "w"); - } - if (!out) - return 1; - - conf_write_heading(out, &kconfig_printer_cb, NULL); - - if (!conf_get_changed()) - sym_clear_all_valid(); - - menu = rootmenu.list; - while (menu) { - sym = menu->sym; - if (!sym) { - if (!menu_is_visible(menu)) - goto next; - str = menu_get_prompt(menu); - fprintf(out, "\n" - "#\n" - "# %s\n" - "#\n", str); - } else if (!(sym->flags & SYMBOL_CHOICE)) { - sym_calc_value(sym); - if (!(sym->flags & SYMBOL_WRITE)) - goto next; - sym->flags &= ~SYMBOL_WRITE; - - conf_write_symbol(out, sym, &kconfig_printer_cb, NULL); - } - -next: - if (menu->list) { - menu = menu->list; - continue; - } - if (menu->next) - menu = menu->next; - else while ((menu = menu->parent)) { - if (menu->next) { - menu = menu->next; - break; - } - } - } - fclose(out); - - if (*tmpname) { - strcat(dirname, basename); - strcat(dirname, ".old"); - rename(newname, dirname); - if (rename(tmpname, newname)) - return 1; - } - - conf_message(_("configuration written to %s"), newname); - - sym_set_change_count(0); - - return 0; -} - -static int conf_split_config(void) -{ - const char *name; - char path[PATH_MAX+1]; - char *s, *d, c; - struct symbol *sym; - struct stat sb; - int res, i, fd; - - name = conf_get_autoconfig_name(); - conf_read_simple(name, S_DEF_AUTO); - sym_calc_value(modules_sym); - - if (chdir("include/config")) - return 1; - - res = 0; - for_all_symbols(i, sym) { - sym_calc_value(sym); - if ((sym->flags & SYMBOL_AUTO) || !sym->name) - continue; - if (sym->flags & SYMBOL_WRITE) { - if (sym->flags & SYMBOL_DEF_AUTO) { - /* - * symbol has old and new value, - * so compare them... - */ - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - if (sym_get_tristate_value(sym) == - sym->def[S_DEF_AUTO].tri) - continue; - break; - case S_STRING: - case S_HEX: - case S_INT: - if (!strcmp(sym_get_string_value(sym), - sym->def[S_DEF_AUTO].val)) - continue; - break; - default: - break; - } - } else { - /* - * If there is no old value, only 'no' (unset) - * is allowed as new value. - */ - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - if (sym_get_tristate_value(sym) == no) - continue; - break; - default: - break; - } - } - } else if (!(sym->flags & SYMBOL_DEF_AUTO)) - /* There is neither an old nor a new value. */ - continue; - /* else - * There is an old value, but no new value ('no' (unset) - * isn't saved in auto.conf, so the old value is always - * different from 'no'). - */ - - /* Replace all '_' and append ".h" */ - s = sym->name; - d = path; - while ((c = *s++)) { - c = tolower(c); - *d++ = (c == '_') ? '/' : c; - } - strcpy(d, ".h"); - - /* Assume directory path already exists. */ - fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd == -1) { - if (errno != ENOENT) { - res = 1; - break; - } - /* - * Create directory components, - * unless they exist already. - */ - d = path; - while ((d = strchr(d, '/'))) { - *d = 0; - if (stat(path, &sb) && mkdir(path, 0755)) { - res = 1; - goto out; - } - *d++ = '/'; - } - /* Try it again. */ - fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); - if (fd == -1) { - res = 1; - break; - } - } - close(fd); - } -out: - if (chdir("../..")) - return 1; - - return res; -} - -int conf_write_autoconf(void) -{ - struct symbol *sym; - const char *name; - FILE *out, *tristate, *out_h; - int i; - - sym_clear_all_valid(); - - file_write_dep("include/config/auto.conf.cmd"); - - if (conf_split_config()) - return 1; - - out = fopen(".tmpconfig", "w"); - if (!out) - return 1; - - tristate = fopen(".tmpconfig_tristate", "w"); - if (!tristate) { - fclose(out); - return 1; - } - - out_h = fopen(".tmpconfig.h", "w"); - if (!out_h) { - fclose(out); - fclose(tristate); - return 1; - } - - conf_write_heading(out, &kconfig_printer_cb, NULL); - - conf_write_heading(tristate, &tristate_printer_cb, NULL); - - conf_write_heading(out_h, &header_printer_cb, NULL); - - for_all_symbols(i, sym) { - sym_calc_value(sym); - if (!(sym->flags & SYMBOL_WRITE) || !sym->name) - continue; - - /* write symbol to auto.conf, tristate and header files */ - conf_write_symbol(out, sym, &kconfig_printer_cb, (void *)1); - - conf_write_symbol(tristate, sym, &tristate_printer_cb, (void *)1); - - conf_write_symbol(out_h, sym, &header_printer_cb, NULL); - } - fclose(out); - fclose(tristate); - fclose(out_h); - - name = getenv("KCONFIG_AUTOHEADER"); - if (!name) - name = "include/generated/autoconf.h"; - if (rename(".tmpconfig.h", name)) - return 1; - name = getenv("KCONFIG_TRISTATE"); - if (!name) - name = "include/config/tristate.conf"; - if (rename(".tmpconfig_tristate", name)) - return 1; - name = conf_get_autoconfig_name(); - /* - * This must be the last step, kbuild has a dependency on auto.conf - * and this marks the successful completion of the previous steps. - */ - if (rename(".tmpconfig", name)) - return 1; - - return 0; -} - -static int sym_change_count; -static void (*conf_changed_callback)(void); - -void sym_set_change_count(int count) -{ - int _sym_change_count = sym_change_count; - sym_change_count = count; - if (conf_changed_callback && - (bool)_sym_change_count != (bool)count) - conf_changed_callback(); -} - -void sym_add_change_count(int count) -{ - sym_set_change_count(count + sym_change_count); -} - -bool conf_get_changed(void) -{ - return sym_change_count; -} - -void conf_set_changed_callback(void (*fn)(void)) -{ - conf_changed_callback = fn; -} - -static bool randomize_choice_values(struct symbol *csym) -{ - struct property *prop; - struct symbol *sym; - struct expr *e; - int cnt, def; - - /* - * If choice is mod then we may have more items selected - * and if no then no-one. - * In both cases stop. - */ - if (csym->curr.tri != yes) - return false; - - prop = sym_get_choice_prop(csym); - - /* count entries in choice block */ - cnt = 0; - expr_list_for_each_sym(prop->expr, e, sym) - cnt++; - - /* - * find a random value and set it to yes, - * set the rest to no so we have only one set - */ - def = (rand() % cnt); - - cnt = 0; - expr_list_for_each_sym(prop->expr, e, sym) { - if (def == cnt++) { - sym->def[S_DEF_USER].tri = yes; - csym->def[S_DEF_USER].val = sym; - } - else { - sym->def[S_DEF_USER].tri = no; - } - sym->flags |= SYMBOL_DEF_USER; - /* clear VALID to get value calculated */ - sym->flags &= ~SYMBOL_VALID; - } - csym->flags |= SYMBOL_DEF_USER; - /* clear VALID to get value calculated */ - csym->flags &= ~(SYMBOL_VALID); - - return true; -} - -void set_all_choice_values(struct symbol *csym) -{ - struct property *prop; - struct symbol *sym; - struct expr *e; - - prop = sym_get_choice_prop(csym); - - /* - * Set all non-assinged choice values to no - */ - expr_list_for_each_sym(prop->expr, e, sym) { - if (!sym_has_value(sym)) - sym->def[S_DEF_USER].tri = no; - } - csym->flags |= SYMBOL_DEF_USER; - /* clear VALID to get value calculated */ - csym->flags &= ~(SYMBOL_VALID | SYMBOL_NEED_SET_CHOICE_VALUES); -} - -bool conf_set_all_new_symbols(enum conf_def_mode mode) -{ - struct symbol *sym, *csym; - int i, cnt, pby, pty, ptm; /* pby: probability of boolean = y - * pty: probability of tristate = y - * ptm: probability of tristate = m - */ - - pby = 50; pty = ptm = 33; /* can't go as the default in switch-case - * below, otherwise gcc whines about - * -Wmaybe-uninitialized */ - if (mode == def_random) { - int n, p[3]; - char *env = getenv("KCONFIG_PROBABILITY"); - n = 0; - while( env && *env ) { - char *endp; - int tmp = strtol( env, &endp, 10 ); - if( tmp >= 0 && tmp <= 100 ) { - p[n++] = tmp; - } else { - errno = ERANGE; - perror( "KCONFIG_PROBABILITY" ); - exit( 1 ); - } - env = (*endp == ':') ? endp+1 : endp; - if( n >=3 ) { - break; - } - } - switch( n ) { - case 1: - pby = p[0]; ptm = pby/2; pty = pby-ptm; - break; - case 2: - pty = p[0]; ptm = p[1]; pby = pty + ptm; - break; - case 3: - pby = p[0]; pty = p[1]; ptm = p[2]; - break; - } - - if( pty+ptm > 100 ) { - errno = ERANGE; - perror( "KCONFIG_PROBABILITY" ); - exit( 1 ); - } - } - bool has_changed = false; - - for_all_symbols(i, sym) { - if (sym_has_value(sym) || (sym->flags & SYMBOL_VALID)) - continue; - switch (sym_get_type(sym)) { - case S_BOOLEAN: - case S_TRISTATE: - has_changed = true; - switch (mode) { - case def_yes: - sym->def[S_DEF_USER].tri = yes; - break; - case def_mod: - sym->def[S_DEF_USER].tri = mod; - break; - case def_no: - if (sym->flags & SYMBOL_ALLNOCONFIG_Y) - sym->def[S_DEF_USER].tri = yes; - else - sym->def[S_DEF_USER].tri = no; - break; - case def_random: - sym->def[S_DEF_USER].tri = no; - cnt = rand() % 100; - if (sym->type == S_TRISTATE) { - if (cnt < pty) - sym->def[S_DEF_USER].tri = yes; - else if (cnt < (pty+ptm)) - sym->def[S_DEF_USER].tri = mod; - } else if (cnt < pby) - sym->def[S_DEF_USER].tri = yes; - break; - default: - continue; - } - if (!(sym_is_choice(sym) && mode == def_random)) - sym->flags |= SYMBOL_DEF_USER; - break; - default: - break; - } - - } - - sym_clear_all_valid(); - - /* - * We have different type of choice blocks. - * If curr.tri equals to mod then we can select several - * choice symbols in one block. - * In this case we do nothing. - * If curr.tri equals yes then only one symbol can be - * selected in a choice block and we set it to yes, - * and the rest to no. - */ - if (mode != def_random) { - for_all_symbols(i, csym) { - if ((sym_is_choice(csym) && !sym_has_value(csym)) || - sym_is_choice_value(csym)) - csym->flags |= SYMBOL_NEED_SET_CHOICE_VALUES; - } - } - - for_all_symbols(i, csym) { - if (sym_has_value(csym) || !sym_is_choice(csym)) - continue; - - sym_calc_value(csym); - if (mode == def_random) - has_changed = randomize_choice_values(csym); - else { - set_all_choice_values(csym); - has_changed = true; - } - } - - return has_changed; -} diff --git a/src/linux/scripts/kconfig/expr.c b/src/linux/scripts/kconfig/expr.c deleted file mode 100644 index cbf4996..0000000 --- a/src/linux/scripts/kconfig/expr.c +++ /dev/null @@ -1,1206 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include - -#include "lkc.h" - -#define DEBUG_EXPR 0 - -static int expr_eq(struct expr *e1, struct expr *e2); -static struct expr *expr_eliminate_yn(struct expr *e); - -struct expr *expr_alloc_symbol(struct symbol *sym) -{ - struct expr *e = xcalloc(1, sizeof(*e)); - e->type = E_SYMBOL; - e->left.sym = sym; - return e; -} - -struct expr *expr_alloc_one(enum expr_type type, struct expr *ce) -{ - struct expr *e = xcalloc(1, sizeof(*e)); - e->type = type; - e->left.expr = ce; - return e; -} - -struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2) -{ - struct expr *e = xcalloc(1, sizeof(*e)); - e->type = type; - e->left.expr = e1; - e->right.expr = e2; - return e; -} - -struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2) -{ - struct expr *e = xcalloc(1, sizeof(*e)); - e->type = type; - e->left.sym = s1; - e->right.sym = s2; - return e; -} - -struct expr *expr_alloc_and(struct expr *e1, struct expr *e2) -{ - if (!e1) - return e2; - return e2 ? expr_alloc_two(E_AND, e1, e2) : e1; -} - -struct expr *expr_alloc_or(struct expr *e1, struct expr *e2) -{ - if (!e1) - return e2; - return e2 ? expr_alloc_two(E_OR, e1, e2) : e1; -} - -struct expr *expr_copy(const struct expr *org) -{ - struct expr *e; - - if (!org) - return NULL; - - e = xmalloc(sizeof(*org)); - memcpy(e, org, sizeof(*org)); - switch (org->type) { - case E_SYMBOL: - e->left = org->left; - break; - case E_NOT: - e->left.expr = expr_copy(org->left.expr); - break; - case E_EQUAL: - case E_GEQ: - case E_GTH: - case E_LEQ: - case E_LTH: - case E_UNEQUAL: - e->left.sym = org->left.sym; - e->right.sym = org->right.sym; - break; - case E_AND: - case E_OR: - case E_LIST: - e->left.expr = expr_copy(org->left.expr); - e->right.expr = expr_copy(org->right.expr); - break; - default: - printf("can't copy type %d\n", e->type); - free(e); - e = NULL; - break; - } - - return e; -} - -void expr_free(struct expr *e) -{ - if (!e) - return; - - switch (e->type) { - case E_SYMBOL: - break; - case E_NOT: - expr_free(e->left.expr); - return; - case E_EQUAL: - case E_GEQ: - case E_GTH: - case E_LEQ: - case E_LTH: - case E_UNEQUAL: - break; - case E_OR: - case E_AND: - expr_free(e->left.expr); - expr_free(e->right.expr); - break; - default: - printf("how to free type %d?\n", e->type); - break; - } - free(e); -} - -static int trans_count; - -#define e1 (*ep1) -#define e2 (*ep2) - -static void __expr_eliminate_eq(enum expr_type type, struct expr **ep1, struct expr **ep2) -{ - if (e1->type == type) { - __expr_eliminate_eq(type, &e1->left.expr, &e2); - __expr_eliminate_eq(type, &e1->right.expr, &e2); - return; - } - if (e2->type == type) { - __expr_eliminate_eq(type, &e1, &e2->left.expr); - __expr_eliminate_eq(type, &e1, &e2->right.expr); - return; - } - if (e1->type == E_SYMBOL && e2->type == E_SYMBOL && - e1->left.sym == e2->left.sym && - (e1->left.sym == &symbol_yes || e1->left.sym == &symbol_no)) - return; - if (!expr_eq(e1, e2)) - return; - trans_count++; - expr_free(e1); expr_free(e2); - switch (type) { - case E_OR: - e1 = expr_alloc_symbol(&symbol_no); - e2 = expr_alloc_symbol(&symbol_no); - break; - case E_AND: - e1 = expr_alloc_symbol(&symbol_yes); - e2 = expr_alloc_symbol(&symbol_yes); - break; - default: - ; - } -} - -void expr_eliminate_eq(struct expr **ep1, struct expr **ep2) -{ - if (!e1 || !e2) - return; - switch (e1->type) { - case E_OR: - case E_AND: - __expr_eliminate_eq(e1->type, ep1, ep2); - default: - ; - } - if (e1->type != e2->type) switch (e2->type) { - case E_OR: - case E_AND: - __expr_eliminate_eq(e2->type, ep1, ep2); - default: - ; - } - e1 = expr_eliminate_yn(e1); - e2 = expr_eliminate_yn(e2); -} - -#undef e1 -#undef e2 - -static int expr_eq(struct expr *e1, struct expr *e2) -{ - int res, old_count; - - if (e1->type != e2->type) - return 0; - switch (e1->type) { - case E_EQUAL: - case E_GEQ: - case E_GTH: - case E_LEQ: - case E_LTH: - case E_UNEQUAL: - return e1->left.sym == e2->left.sym && e1->right.sym == e2->right.sym; - case E_SYMBOL: - return e1->left.sym == e2->left.sym; - case E_NOT: - return expr_eq(e1->left.expr, e2->left.expr); - case E_AND: - case E_OR: - e1 = expr_copy(e1); - e2 = expr_copy(e2); - old_count = trans_count; - expr_eliminate_eq(&e1, &e2); - res = (e1->type == E_SYMBOL && e2->type == E_SYMBOL && - e1->left.sym == e2->left.sym); - expr_free(e1); - expr_free(e2); - trans_count = old_count; - return res; - case E_LIST: - case E_RANGE: - case E_NONE: - /* panic */; - } - - if (DEBUG_EXPR) { - expr_fprint(e1, stdout); - printf(" = "); - expr_fprint(e2, stdout); - printf(" ?\n"); - } - - return 0; -} - -static struct expr *expr_eliminate_yn(struct expr *e) -{ - struct expr *tmp; - - if (e) switch (e->type) { - case E_AND: - e->left.expr = expr_eliminate_yn(e->left.expr); - e->right.expr = expr_eliminate_yn(e->right.expr); - if (e->left.expr->type == E_SYMBOL) { - if (e->left.expr->left.sym == &symbol_no) { - expr_free(e->left.expr); - expr_free(e->right.expr); - e->type = E_SYMBOL; - e->left.sym = &symbol_no; - e->right.expr = NULL; - return e; - } else if (e->left.expr->left.sym == &symbol_yes) { - free(e->left.expr); - tmp = e->right.expr; - *e = *(e->right.expr); - free(tmp); - return e; - } - } - if (e->right.expr->type == E_SYMBOL) { - if (e->right.expr->left.sym == &symbol_no) { - expr_free(e->left.expr); - expr_free(e->right.expr); - e->type = E_SYMBOL; - e->left.sym = &symbol_no; - e->right.expr = NULL; - return e; - } else if (e->right.expr->left.sym == &symbol_yes) { - free(e->right.expr); - tmp = e->left.expr; - *e = *(e->left.expr); - free(tmp); - return e; - } - } - break; - case E_OR: - e->left.expr = expr_eliminate_yn(e->left.expr); - e->right.expr = expr_eliminate_yn(e->right.expr); - if (e->left.expr->type == E_SYMBOL) { - if (e->left.expr->left.sym == &symbol_no) { - free(e->left.expr); - tmp = e->right.expr; - *e = *(e->right.expr); - free(tmp); - return e; - } else if (e->left.expr->left.sym == &symbol_yes) { - expr_free(e->left.expr); - expr_free(e->right.expr); - e->type = E_SYMBOL; - e->left.sym = &symbol_yes; - e->right.expr = NULL; - return e; - } - } - if (e->right.expr->type == E_SYMBOL) { - if (e->right.expr->left.sym == &symbol_no) { - free(e->right.expr); - tmp = e->left.expr; - *e = *(e->left.expr); - free(tmp); - return e; - } else if (e->right.expr->left.sym == &symbol_yes) { - expr_free(e->left.expr); - expr_free(e->right.expr); - e->type = E_SYMBOL; - e->left.sym = &symbol_yes; - e->right.expr = NULL; - return e; - } - } - break; - default: - ; - } - return e; -} - -/* - * bool FOO!=n => FOO - */ -struct expr *expr_trans_bool(struct expr *e) -{ - if (!e) - return NULL; - switch (e->type) { - case E_AND: - case E_OR: - case E_NOT: - e->left.expr = expr_trans_bool(e->left.expr); - e->right.expr = expr_trans_bool(e->right.expr); - break; - case E_UNEQUAL: - // FOO!=n -> FOO - if (e->left.sym->type == S_TRISTATE) { - if (e->right.sym == &symbol_no) { - e->type = E_SYMBOL; - e->right.sym = NULL; - } - } - break; - default: - ; - } - return e; -} - -/* - * e1 || e2 -> ? - */ -static struct expr *expr_join_or(struct expr *e1, struct expr *e2) -{ - struct expr *tmp; - struct symbol *sym1, *sym2; - - if (expr_eq(e1, e2)) - return expr_copy(e1); - if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) - return NULL; - if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) - return NULL; - if (e1->type == E_NOT) { - tmp = e1->left.expr; - if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) - return NULL; - sym1 = tmp->left.sym; - } else - sym1 = e1->left.sym; - if (e2->type == E_NOT) { - if (e2->left.expr->type != E_SYMBOL) - return NULL; - sym2 = e2->left.expr->left.sym; - } else - sym2 = e2->left.sym; - if (sym1 != sym2) - return NULL; - if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) - return NULL; - if (sym1->type == S_TRISTATE) { - if (e1->type == E_EQUAL && e2->type == E_EQUAL && - ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || - (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) { - // (a='y') || (a='m') -> (a!='n') - return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_no); - } - if (e1->type == E_EQUAL && e2->type == E_EQUAL && - ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || - (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) { - // (a='y') || (a='n') -> (a!='m') - return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_mod); - } - if (e1->type == E_EQUAL && e2->type == E_EQUAL && - ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || - (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) { - // (a='m') || (a='n') -> (a!='y') - return expr_alloc_comp(E_UNEQUAL, sym1, &symbol_yes); - } - } - if (sym1->type == S_BOOLEAN && sym1 == sym2) { - if ((e1->type == E_NOT && e1->left.expr->type == E_SYMBOL && e2->type == E_SYMBOL) || - (e2->type == E_NOT && e2->left.expr->type == E_SYMBOL && e1->type == E_SYMBOL)) - return expr_alloc_symbol(&symbol_yes); - } - - if (DEBUG_EXPR) { - printf("optimize ("); - expr_fprint(e1, stdout); - printf(") || ("); - expr_fprint(e2, stdout); - printf(")?\n"); - } - return NULL; -} - -static struct expr *expr_join_and(struct expr *e1, struct expr *e2) -{ - struct expr *tmp; - struct symbol *sym1, *sym2; - - if (expr_eq(e1, e2)) - return expr_copy(e1); - if (e1->type != E_EQUAL && e1->type != E_UNEQUAL && e1->type != E_SYMBOL && e1->type != E_NOT) - return NULL; - if (e2->type != E_EQUAL && e2->type != E_UNEQUAL && e2->type != E_SYMBOL && e2->type != E_NOT) - return NULL; - if (e1->type == E_NOT) { - tmp = e1->left.expr; - if (tmp->type != E_EQUAL && tmp->type != E_UNEQUAL && tmp->type != E_SYMBOL) - return NULL; - sym1 = tmp->left.sym; - } else - sym1 = e1->left.sym; - if (e2->type == E_NOT) { - if (e2->left.expr->type != E_SYMBOL) - return NULL; - sym2 = e2->left.expr->left.sym; - } else - sym2 = e2->left.sym; - if (sym1 != sym2) - return NULL; - if (sym1->type != S_BOOLEAN && sym1->type != S_TRISTATE) - return NULL; - - if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_yes) || - (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_yes)) - // (a) && (a='y') -> (a='y') - return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); - - if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_no) || - (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_no)) - // (a) && (a!='n') -> (a) - return expr_alloc_symbol(sym1); - - if ((e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_mod) || - (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_mod)) - // (a) && (a!='m') -> (a='y') - return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); - - if (sym1->type == S_TRISTATE) { - if (e1->type == E_EQUAL && e2->type == E_UNEQUAL) { - // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' - sym2 = e1->right.sym; - if ((e2->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) - return sym2 != e2->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) - : expr_alloc_symbol(&symbol_no); - } - if (e1->type == E_UNEQUAL && e2->type == E_EQUAL) { - // (a='b') && (a!='c') -> 'b'='c' ? 'n' : a='b' - sym2 = e2->right.sym; - if ((e1->right.sym->flags & SYMBOL_CONST) && (sym2->flags & SYMBOL_CONST)) - return sym2 != e1->right.sym ? expr_alloc_comp(E_EQUAL, sym1, sym2) - : expr_alloc_symbol(&symbol_no); - } - if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && - ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_no) || - (e1->right.sym == &symbol_no && e2->right.sym == &symbol_yes))) - // (a!='y') && (a!='n') -> (a='m') - return expr_alloc_comp(E_EQUAL, sym1, &symbol_mod); - - if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && - ((e1->right.sym == &symbol_yes && e2->right.sym == &symbol_mod) || - (e1->right.sym == &symbol_mod && e2->right.sym == &symbol_yes))) - // (a!='y') && (a!='m') -> (a='n') - return expr_alloc_comp(E_EQUAL, sym1, &symbol_no); - - if (e1->type == E_UNEQUAL && e2->type == E_UNEQUAL && - ((e1->right.sym == &symbol_mod && e2->right.sym == &symbol_no) || - (e1->right.sym == &symbol_no && e2->right.sym == &symbol_mod))) - // (a!='m') && (a!='n') -> (a='m') - return expr_alloc_comp(E_EQUAL, sym1, &symbol_yes); - - if ((e1->type == E_SYMBOL && e2->type == E_EQUAL && e2->right.sym == &symbol_mod) || - (e2->type == E_SYMBOL && e1->type == E_EQUAL && e1->right.sym == &symbol_mod) || - (e1->type == E_SYMBOL && e2->type == E_UNEQUAL && e2->right.sym == &symbol_yes) || - (e2->type == E_SYMBOL && e1->type == E_UNEQUAL && e1->right.sym == &symbol_yes)) - return NULL; - } - - if (DEBUG_EXPR) { - printf("optimize ("); - expr_fprint(e1, stdout); - printf(") && ("); - expr_fprint(e2, stdout); - printf(")?\n"); - } - return NULL; -} - -static void expr_eliminate_dups1(enum expr_type type, struct expr **ep1, struct expr **ep2) -{ -#define e1 (*ep1) -#define e2 (*ep2) - struct expr *tmp; - - if (e1->type == type) { - expr_eliminate_dups1(type, &e1->left.expr, &e2); - expr_eliminate_dups1(type, &e1->right.expr, &e2); - return; - } - if (e2->type == type) { - expr_eliminate_dups1(type, &e1, &e2->left.expr); - expr_eliminate_dups1(type, &e1, &e2->right.expr); - return; - } - if (e1 == e2) - return; - - switch (e1->type) { - case E_OR: case E_AND: - expr_eliminate_dups1(e1->type, &e1, &e1); - default: - ; - } - - switch (type) { - case E_OR: - tmp = expr_join_or(e1, e2); - if (tmp) { - expr_free(e1); expr_free(e2); - e1 = expr_alloc_symbol(&symbol_no); - e2 = tmp; - trans_count++; - } - break; - case E_AND: - tmp = expr_join_and(e1, e2); - if (tmp) { - expr_free(e1); expr_free(e2); - e1 = expr_alloc_symbol(&symbol_yes); - e2 = tmp; - trans_count++; - } - break; - default: - ; - } -#undef e1 -#undef e2 -} - -struct expr *expr_eliminate_dups(struct expr *e) -{ - int oldcount; - if (!e) - return e; - - oldcount = trans_count; - while (1) { - trans_count = 0; - switch (e->type) { - case E_OR: case E_AND: - expr_eliminate_dups1(e->type, &e, &e); - default: - ; - } - if (!trans_count) - break; - e = expr_eliminate_yn(e); - } - trans_count = oldcount; - return e; -} - -struct expr *expr_transform(struct expr *e) -{ - struct expr *tmp; - - if (!e) - return NULL; - switch (e->type) { - case E_EQUAL: - case E_GEQ: - case E_GTH: - case E_LEQ: - case E_LTH: - case E_UNEQUAL: - case E_SYMBOL: - case E_LIST: - break; - default: - e->left.expr = expr_transform(e->left.expr); - e->right.expr = expr_transform(e->right.expr); - } - - switch (e->type) { - case E_EQUAL: - if (e->left.sym->type != S_BOOLEAN) - break; - if (e->right.sym == &symbol_no) { - e->type = E_NOT; - e->left.expr = expr_alloc_symbol(e->left.sym); - e->right.sym = NULL; - break; - } - if (e->right.sym == &symbol_mod) { - printf("boolean symbol %s tested for 'm'? test forced to 'n'\n", e->left.sym->name); - e->type = E_SYMBOL; - e->left.sym = &symbol_no; - e->right.sym = NULL; - break; - } - if (e->right.sym == &symbol_yes) { - e->type = E_SYMBOL; - e->right.sym = NULL; - break; - } - break; - case E_UNEQUAL: - if (e->left.sym->type != S_BOOLEAN) - break; - if (e->right.sym == &symbol_no) { - e->type = E_SYMBOL; - e->right.sym = NULL; - break; - } - if (e->right.sym == &symbol_mod) { - printf("boolean symbol %s tested for 'm'? test forced to 'y'\n", e->left.sym->name); - e->type = E_SYMBOL; - e->left.sym = &symbol_yes; - e->right.sym = NULL; - break; - } - if (e->right.sym == &symbol_yes) { - e->type = E_NOT; - e->left.expr = expr_alloc_symbol(e->left.sym); - e->right.sym = NULL; - break; - } - break; - case E_NOT: - switch (e->left.expr->type) { - case E_NOT: - // !!a -> a - tmp = e->left.expr->left.expr; - free(e->left.expr); - free(e); - e = tmp; - e = expr_transform(e); - break; - case E_EQUAL: - case E_UNEQUAL: - // !a='x' -> a!='x' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = e->type == E_EQUAL ? E_UNEQUAL : E_EQUAL; - break; - case E_LEQ: - case E_GEQ: - // !a<='x' -> a>'x' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = e->type == E_LEQ ? E_GTH : E_LTH; - break; - case E_LTH: - case E_GTH: - // !a<'x' -> a>='x' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = e->type == E_LTH ? E_GEQ : E_LEQ; - break; - case E_OR: - // !(a || b) -> !a && !b - tmp = e->left.expr; - e->type = E_AND; - e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); - tmp->type = E_NOT; - tmp->right.expr = NULL; - e = expr_transform(e); - break; - case E_AND: - // !(a && b) -> !a || !b - tmp = e->left.expr; - e->type = E_OR; - e->right.expr = expr_alloc_one(E_NOT, tmp->right.expr); - tmp->type = E_NOT; - tmp->right.expr = NULL; - e = expr_transform(e); - break; - case E_SYMBOL: - if (e->left.expr->left.sym == &symbol_yes) { - // !'y' -> 'n' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = E_SYMBOL; - e->left.sym = &symbol_no; - break; - } - if (e->left.expr->left.sym == &symbol_mod) { - // !'m' -> 'm' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = E_SYMBOL; - e->left.sym = &symbol_mod; - break; - } - if (e->left.expr->left.sym == &symbol_no) { - // !'n' -> 'y' - tmp = e->left.expr; - free(e); - e = tmp; - e->type = E_SYMBOL; - e->left.sym = &symbol_yes; - break; - } - break; - default: - ; - } - break; - default: - ; - } - return e; -} - -int expr_contains_symbol(struct expr *dep, struct symbol *sym) -{ - if (!dep) - return 0; - - switch (dep->type) { - case E_AND: - case E_OR: - return expr_contains_symbol(dep->left.expr, sym) || - expr_contains_symbol(dep->right.expr, sym); - case E_SYMBOL: - return dep->left.sym == sym; - case E_EQUAL: - case E_GEQ: - case E_GTH: - case E_LEQ: - case E_LTH: - case E_UNEQUAL: - return dep->left.sym == sym || - dep->right.sym == sym; - case E_NOT: - return expr_contains_symbol(dep->left.expr, sym); - default: - ; - } - return 0; -} - -bool expr_depends_symbol(struct expr *dep, struct symbol *sym) -{ - if (!dep) - return false; - - switch (dep->type) { - case E_AND: - return expr_depends_symbol(dep->left.expr, sym) || - expr_depends_symbol(dep->right.expr, sym); - case E_SYMBOL: - return dep->left.sym == sym; - case E_EQUAL: - if (dep->left.sym == sym) { - if (dep->right.sym == &symbol_yes || dep->right.sym == &symbol_mod) - return true; - } - break; - case E_UNEQUAL: - if (dep->left.sym == sym) { - if (dep->right.sym == &symbol_no) - return true; - } - break; - default: - ; - } - return false; -} - -struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym) -{ - struct expr *e1, *e2; - - if (!e) { - e = expr_alloc_symbol(sym); - if (type == E_UNEQUAL) - e = expr_alloc_one(E_NOT, e); - return e; - } - switch (e->type) { - case E_AND: - e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym); - e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); - if (sym == &symbol_yes) - e = expr_alloc_two(E_AND, e1, e2); - if (sym == &symbol_no) - e = expr_alloc_two(E_OR, e1, e2); - if (type == E_UNEQUAL) - e = expr_alloc_one(E_NOT, e); - return e; - case E_OR: - e1 = expr_trans_compare(e->left.expr, E_EQUAL, sym); - e2 = expr_trans_compare(e->right.expr, E_EQUAL, sym); - if (sym == &symbol_yes) - e = expr_alloc_two(E_OR, e1, e2); - if (sym == &symbol_no) - e = expr_alloc_two(E_AND, e1, e2); - if (type == E_UNEQUAL) - e = expr_alloc_one(E_NOT, e); - return e; - case E_NOT: - return expr_trans_compare(e->left.expr, type == E_EQUAL ? E_UNEQUAL : E_EQUAL, sym); - case E_UNEQUAL: - case E_LTH: - case E_LEQ: - case E_GTH: - case E_GEQ: - case E_EQUAL: - if (type == E_EQUAL) { - if (sym == &symbol_yes) - return expr_copy(e); - if (sym == &symbol_mod) - return expr_alloc_symbol(&symbol_no); - if (sym == &symbol_no) - return expr_alloc_one(E_NOT, expr_copy(e)); - } else { - if (sym == &symbol_yes) - return expr_alloc_one(E_NOT, expr_copy(e)); - if (sym == &symbol_mod) - return expr_alloc_symbol(&symbol_yes); - if (sym == &symbol_no) - return expr_copy(e); - } - break; - case E_SYMBOL: - return expr_alloc_comp(type, e->left.sym, sym); - case E_LIST: - case E_RANGE: - case E_NONE: - /* panic */; - } - return NULL; -} - -enum string_value_kind { - k_string, - k_signed, - k_unsigned, - k_invalid -}; - -union string_value { - unsigned long long u; - signed long long s; -}; - -static enum string_value_kind expr_parse_string(const char *str, - enum symbol_type type, - union string_value *val) -{ - char *tail; - enum string_value_kind kind; - - errno = 0; - switch (type) { - case S_BOOLEAN: - case S_TRISTATE: - return k_string; - case S_INT: - val->s = strtoll(str, &tail, 10); - kind = k_signed; - break; - case S_HEX: - val->u = strtoull(str, &tail, 16); - kind = k_unsigned; - break; - case S_STRING: - case S_UNKNOWN: - val->s = strtoll(str, &tail, 0); - kind = k_signed; - break; - default: - return k_invalid; - } - return !errno && !*tail && tail > str && isxdigit(tail[-1]) - ? kind : k_string; -} - -tristate expr_calc_value(struct expr *e) -{ - tristate val1, val2; - const char *str1, *str2; - enum string_value_kind k1 = k_string, k2 = k_string; - union string_value lval = {}, rval = {}; - int res; - - if (!e) - return yes; - - switch (e->type) { - case E_SYMBOL: - sym_calc_value(e->left.sym); - return e->left.sym->curr.tri; - case E_AND: - val1 = expr_calc_value(e->left.expr); - val2 = expr_calc_value(e->right.expr); - return EXPR_AND(val1, val2); - case E_OR: - val1 = expr_calc_value(e->left.expr); - val2 = expr_calc_value(e->right.expr); - return EXPR_OR(val1, val2); - case E_NOT: - val1 = expr_calc_value(e->left.expr); - return EXPR_NOT(val1); - case E_EQUAL: - case E_GEQ: - case E_GTH: - case E_LEQ: - case E_LTH: - case E_UNEQUAL: - break; - default: - printf("expr_calc_value: %d?\n", e->type); - return no; - } - - sym_calc_value(e->left.sym); - sym_calc_value(e->right.sym); - str1 = sym_get_string_value(e->left.sym); - str2 = sym_get_string_value(e->right.sym); - - if (e->left.sym->type != S_STRING || e->right.sym->type != S_STRING) { - k1 = expr_parse_string(str1, e->left.sym->type, &lval); - k2 = expr_parse_string(str2, e->right.sym->type, &rval); - } - - if (k1 == k_string || k2 == k_string) - res = strcmp(str1, str2); - else if (k1 == k_invalid || k2 == k_invalid) { - if (e->type != E_EQUAL && e->type != E_UNEQUAL) { - printf("Cannot compare \"%s\" and \"%s\"\n", str1, str2); - return no; - } - res = strcmp(str1, str2); - } else if (k1 == k_unsigned || k2 == k_unsigned) - res = (lval.u > rval.u) - (lval.u < rval.u); - else /* if (k1 == k_signed && k2 == k_signed) */ - res = (lval.s > rval.s) - (lval.s < rval.s); - - switch(e->type) { - case E_EQUAL: - return res ? no : yes; - case E_GEQ: - return res >= 0 ? yes : no; - case E_GTH: - return res > 0 ? yes : no; - case E_LEQ: - return res <= 0 ? yes : no; - case E_LTH: - return res < 0 ? yes : no; - case E_UNEQUAL: - return res ? yes : no; - default: - printf("expr_calc_value: relation %d?\n", e->type); - return no; - } -} - -static int expr_compare_type(enum expr_type t1, enum expr_type t2) -{ - if (t1 == t2) - return 0; - switch (t1) { - case E_LEQ: - case E_LTH: - case E_GEQ: - case E_GTH: - if (t2 == E_EQUAL || t2 == E_UNEQUAL) - return 1; - case E_EQUAL: - case E_UNEQUAL: - if (t2 == E_NOT) - return 1; - case E_NOT: - if (t2 == E_AND) - return 1; - case E_AND: - if (t2 == E_OR) - return 1; - case E_OR: - if (t2 == E_LIST) - return 1; - case E_LIST: - if (t2 == 0) - return 1; - default: - return -1; - } - printf("[%dgt%d?]", t1, t2); - return 0; -} - -static inline struct expr * -expr_get_leftmost_symbol(const struct expr *e) -{ - - if (e == NULL) - return NULL; - - while (e->type != E_SYMBOL) - e = e->left.expr; - - return expr_copy(e); -} - -/* - * Given expression `e1' and `e2', returns the leaf of the longest - * sub-expression of `e1' not containing 'e2. - */ -struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2) -{ - struct expr *ret; - - switch (e1->type) { - case E_OR: - return expr_alloc_and( - expr_simplify_unmet_dep(e1->left.expr, e2), - expr_simplify_unmet_dep(e1->right.expr, e2)); - case E_AND: { - struct expr *e; - e = expr_alloc_and(expr_copy(e1), expr_copy(e2)); - e = expr_eliminate_dups(e); - ret = (!expr_eq(e, e1)) ? e1 : NULL; - expr_free(e); - break; - } - default: - ret = e1; - break; - } - - return expr_get_leftmost_symbol(ret); -} - -void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken) -{ - if (!e) { - fn(data, NULL, "y"); - return; - } - - if (expr_compare_type(prevtoken, e->type) > 0) - fn(data, NULL, "("); - switch (e->type) { - case E_SYMBOL: - if (e->left.sym->name) - fn(data, e->left.sym, e->left.sym->name); - else - fn(data, NULL, ""); - break; - case E_NOT: - fn(data, NULL, "!"); - expr_print(e->left.expr, fn, data, E_NOT); - break; - case E_EQUAL: - if (e->left.sym->name) - fn(data, e->left.sym, e->left.sym->name); - else - fn(data, NULL, ""); - fn(data, NULL, "="); - fn(data, e->right.sym, e->right.sym->name); - break; - case E_LEQ: - case E_LTH: - if (e->left.sym->name) - fn(data, e->left.sym, e->left.sym->name); - else - fn(data, NULL, ""); - fn(data, NULL, e->type == E_LEQ ? "<=" : "<"); - fn(data, e->right.sym, e->right.sym->name); - break; - case E_GEQ: - case E_GTH: - if (e->left.sym->name) - fn(data, e->left.sym, e->left.sym->name); - else - fn(data, NULL, ""); - fn(data, NULL, e->type == E_GEQ ? ">=" : ">"); - fn(data, e->right.sym, e->right.sym->name); - break; - case E_UNEQUAL: - if (e->left.sym->name) - fn(data, e->left.sym, e->left.sym->name); - else - fn(data, NULL, ""); - fn(data, NULL, "!="); - fn(data, e->right.sym, e->right.sym->name); - break; - case E_OR: - expr_print(e->left.expr, fn, data, E_OR); - fn(data, NULL, " || "); - expr_print(e->right.expr, fn, data, E_OR); - break; - case E_AND: - expr_print(e->left.expr, fn, data, E_AND); - fn(data, NULL, " && "); - expr_print(e->right.expr, fn, data, E_AND); - break; - case E_LIST: - fn(data, e->right.sym, e->right.sym->name); - if (e->left.expr) { - fn(data, NULL, " ^ "); - expr_print(e->left.expr, fn, data, E_LIST); - } - break; - case E_RANGE: - fn(data, NULL, "["); - fn(data, e->left.sym, e->left.sym->name); - fn(data, NULL, " "); - fn(data, e->right.sym, e->right.sym->name); - fn(data, NULL, "]"); - break; - default: - { - char buf[32]; - sprintf(buf, "", e->type); - fn(data, NULL, buf); - break; - } - } - if (expr_compare_type(prevtoken, e->type) > 0) - fn(data, NULL, ")"); -} - -static void expr_print_file_helper(void *data, struct symbol *sym, const char *str) -{ - xfwrite(str, strlen(str), 1, data); -} - -void expr_fprint(struct expr *e, FILE *out) -{ - expr_print(e, expr_print_file_helper, out, E_NONE); -} - -static void expr_print_gstr_helper(void *data, struct symbol *sym, const char *str) -{ - struct gstr *gs = (struct gstr*)data; - const char *sym_str = NULL; - - if (sym) - sym_str = sym_get_string_value(sym); - - if (gs->max_width) { - unsigned extra_length = strlen(str); - const char *last_cr = strrchr(gs->s, '\n'); - unsigned last_line_length; - - if (sym_str) - extra_length += 4 + strlen(sym_str); - - if (!last_cr) - last_cr = gs->s; - - last_line_length = strlen(gs->s) - (last_cr - gs->s); - - if ((last_line_length + extra_length) > gs->max_width) - str_append(gs, "\\\n"); - } - - str_append(gs, str); - if (sym && sym->type != S_UNKNOWN) - str_printf(gs, " [=%s]", sym_str); -} - -void expr_gstr_print(struct expr *e, struct gstr *gs) -{ - expr_print(e, expr_print_gstr_helper, gs, E_NONE); -} diff --git a/src/linux/scripts/kconfig/expr.h b/src/linux/scripts/kconfig/expr.h deleted file mode 100644 index 973b6f7..0000000 --- a/src/linux/scripts/kconfig/expr.h +++ /dev/null @@ -1,238 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#ifndef EXPR_H -#define EXPR_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include "list.h" -#ifndef __cplusplus -#include -#endif - -struct file { - struct file *next; - struct file *parent; - const char *name; - int lineno; -}; - -typedef enum tristate { - no, mod, yes -} tristate; - -enum expr_type { - E_NONE, E_OR, E_AND, E_NOT, - E_EQUAL, E_UNEQUAL, E_LTH, E_LEQ, E_GTH, E_GEQ, - E_LIST, E_SYMBOL, E_RANGE -}; - -union expr_data { - struct expr *expr; - struct symbol *sym; -}; - -struct expr { - enum expr_type type; - union expr_data left, right; -}; - -#define EXPR_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2)) -#define EXPR_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2)) -#define EXPR_NOT(dep) (2-(dep)) - -#define expr_list_for_each_sym(l, e, s) \ - for (e = (l); e && (s = e->right.sym); e = e->left.expr) - -struct expr_value { - struct expr *expr; - tristate tri; -}; - -struct symbol_value { - void *val; - tristate tri; -}; - -enum symbol_type { - S_UNKNOWN, S_BOOLEAN, S_TRISTATE, S_INT, S_HEX, S_STRING, S_OTHER -}; - -/* enum values are used as index to symbol.def[] */ -enum { - S_DEF_USER, /* main user value */ - S_DEF_AUTO, /* values read from auto.conf */ - S_DEF_DEF3, /* Reserved for UI usage */ - S_DEF_DEF4, /* Reserved for UI usage */ - S_DEF_COUNT -}; - -struct symbol { - struct symbol *next; - char *name; - enum symbol_type type; - struct symbol_value curr; - struct symbol_value def[S_DEF_COUNT]; - tristate visible; - int flags; - struct property *prop; - struct expr_value dir_dep; - struct expr_value rev_dep; -}; - -#define for_all_symbols(i, sym) for (i = 0; i < SYMBOL_HASHSIZE; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) - -#define SYMBOL_CONST 0x0001 /* symbol is const */ -#define SYMBOL_CHECK 0x0008 /* used during dependency checking */ -#define SYMBOL_CHOICE 0x0010 /* start of a choice block (null name) */ -#define SYMBOL_CHOICEVAL 0x0020 /* used as a value in a choice block */ -#define SYMBOL_VALID 0x0080 /* set when symbol.curr is calculated */ -#define SYMBOL_OPTIONAL 0x0100 /* choice is optional - values can be 'n' */ -#define SYMBOL_WRITE 0x0200 /* write symbol to file (KCONFIG_CONFIG) */ -#define SYMBOL_CHANGED 0x0400 /* ? */ -#define SYMBOL_AUTO 0x1000 /* value from environment variable */ -#define SYMBOL_CHECKED 0x2000 /* used during dependency checking */ -#define SYMBOL_WARNED 0x8000 /* warning has been issued */ - -/* Set when symbol.def[] is used */ -#define SYMBOL_DEF 0x10000 /* First bit of SYMBOL_DEF */ -#define SYMBOL_DEF_USER 0x10000 /* symbol.def[S_DEF_USER] is valid */ -#define SYMBOL_DEF_AUTO 0x20000 /* symbol.def[S_DEF_AUTO] is valid */ -#define SYMBOL_DEF3 0x40000 /* symbol.def[S_DEF_3] is valid */ -#define SYMBOL_DEF4 0x80000 /* symbol.def[S_DEF_4] is valid */ - -/* choice values need to be set before calculating this symbol value */ -#define SYMBOL_NEED_SET_CHOICE_VALUES 0x100000 - -/* Set symbol to y if allnoconfig; used for symbols that hide others */ -#define SYMBOL_ALLNOCONFIG_Y 0x200000 - -#define SYMBOL_MAXLENGTH 256 -#define SYMBOL_HASHSIZE 9973 - -/* A property represent the config options that can be associated - * with a config "symbol". - * Sample: - * config FOO - * default y - * prompt "foo prompt" - * select BAR - * config BAZ - * int "BAZ Value" - * range 1..255 - */ -enum prop_type { - P_UNKNOWN, - P_PROMPT, /* prompt "foo prompt" or "BAZ Value" */ - P_COMMENT, /* text associated with a comment */ - P_MENU, /* prompt associated with a menuconfig option */ - P_DEFAULT, /* default y */ - P_CHOICE, /* choice value */ - P_SELECT, /* select BAR */ - P_RANGE, /* range 7..100 (for a symbol) */ - P_ENV, /* value from environment variable */ - P_SYMBOL, /* where a symbol is defined */ -}; - -struct property { - struct property *next; /* next property - null if last */ - struct symbol *sym; /* the symbol for which the property is associated */ - enum prop_type type; /* type of property */ - const char *text; /* the prompt value - P_PROMPT, P_MENU, P_COMMENT */ - struct expr_value visible; - struct expr *expr; /* the optional conditional part of the property */ - struct menu *menu; /* the menu the property are associated with - * valid for: P_SELECT, P_RANGE, P_CHOICE, - * P_PROMPT, P_DEFAULT, P_MENU, P_COMMENT */ - struct file *file; /* what file was this property defined */ - int lineno; /* what lineno was this property defined */ -}; - -#define for_all_properties(sym, st, tok) \ - for (st = sym->prop; st; st = st->next) \ - if (st->type == (tok)) -#define for_all_defaults(sym, st) for_all_properties(sym, st, P_DEFAULT) -#define for_all_choices(sym, st) for_all_properties(sym, st, P_CHOICE) -#define for_all_prompts(sym, st) \ - for (st = sym->prop; st; st = st->next) \ - if (st->text) - -struct menu { - struct menu *next; - struct menu *parent; - struct menu *list; - struct symbol *sym; - struct property *prompt; - struct expr *visibility; - struct expr *dep; - unsigned int flags; - char *help; - struct file *file; - int lineno; - void *data; -}; - -#define MENU_CHANGED 0x0001 -#define MENU_ROOT 0x0002 - -struct jump_key { - struct list_head entries; - size_t offset; - struct menu *target; - int index; -}; - -#define JUMP_NB 9 - -extern struct file *file_list; -extern struct file *current_file; -struct file *lookup_file(const char *name); - -extern struct symbol symbol_yes, symbol_no, symbol_mod; -extern struct symbol *modules_sym; -extern struct symbol *sym_defconfig_list; -extern int cdebug; -struct expr *expr_alloc_symbol(struct symbol *sym); -struct expr *expr_alloc_one(enum expr_type type, struct expr *ce); -struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2); -struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2); -struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); -struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); -struct expr *expr_copy(const struct expr *org); -void expr_free(struct expr *e); -void expr_eliminate_eq(struct expr **ep1, struct expr **ep2); -tristate expr_calc_value(struct expr *e); -struct expr *expr_trans_bool(struct expr *e); -struct expr *expr_eliminate_dups(struct expr *e); -struct expr *expr_transform(struct expr *e); -int expr_contains_symbol(struct expr *dep, struct symbol *sym); -bool expr_depends_symbol(struct expr *dep, struct symbol *sym); -struct expr *expr_trans_compare(struct expr *e, enum expr_type type, struct symbol *sym); -struct expr *expr_simplify_unmet_dep(struct expr *e1, struct expr *e2); - -void expr_fprint(struct expr *e, FILE *out); -struct gstr; /* forward */ -void expr_gstr_print(struct expr *e, struct gstr *gs); - -static inline int expr_is_yes(struct expr *e) -{ - return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes); -} - -static inline int expr_is_no(struct expr *e) -{ - return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no); -} - -#ifdef __cplusplus -} -#endif - -#endif /* EXPR_H */ diff --git a/src/linux/scripts/kconfig/list.h b/src/linux/scripts/kconfig/list.h deleted file mode 100644 index 2cf23f0..0000000 --- a/src/linux/scripts/kconfig/list.h +++ /dev/null @@ -1,131 +0,0 @@ -#ifndef LIST_H -#define LIST_H - -/* - * Copied from include/linux/... - */ - -#undef offsetof -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) - -/** - * container_of - cast a member of a structure out to the containing structure - * @ptr: the pointer to the member. - * @type: the type of the container struct this is embedded in. - * @member: the name of the member within the struct. - * - */ -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - - -struct list_head { - struct list_head *next, *prev; -}; - - -#define LIST_HEAD_INIT(name) { &(name), &(name) } - -#define LIST_HEAD(name) \ - struct list_head name = LIST_HEAD_INIT(name) - -/** - * list_entry - get the struct for this entry - * @ptr: the &struct list_head pointer. - * @type: the type of the struct this is embedded in. - * @member: the name of the list_head within the struct. - */ -#define list_entry(ptr, type, member) \ - container_of(ptr, type, member) - -/** - * list_for_each_entry - iterate over list of given type - * @pos: the type * to use as a loop cursor. - * @head: the head for your list. - * @member: the name of the list_head within the struct. - */ -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -/** - * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry - * @pos: the type * to use as a loop cursor. - * @n: another type * to use as temporary storage - * @head: the head for your list. - * @member: the name of the list_head within the struct. - */ -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member), \ - n = list_entry(pos->member.next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -/** - * list_empty - tests whether a list is empty - * @head: the list to test. - */ -static inline int list_empty(const struct list_head *head) -{ - return head->next == head; -} - -/* - * Insert a new entry between two known consecutive entries. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_add(struct list_head *_new, - struct list_head *prev, - struct list_head *next) -{ - next->prev = _new; - _new->next = next; - _new->prev = prev; - prev->next = _new; -} - -/** - * list_add_tail - add a new entry - * @new: new entry to be added - * @head: list head to add it before - * - * Insert a new entry before the specified head. - * This is useful for implementing queues. - */ -static inline void list_add_tail(struct list_head *_new, struct list_head *head) -{ - __list_add(_new, head->prev, head); -} - -/* - * Delete a list entry by making the prev/next entries - * point to each other. - * - * This is only for internal list manipulation where we know - * the prev/next entries already! - */ -static inline void __list_del(struct list_head *prev, struct list_head *next) -{ - next->prev = prev; - prev->next = next; -} - -#define LIST_POISON1 ((void *) 0x00100100) -#define LIST_POISON2 ((void *) 0x00200200) -/** - * list_del - deletes entry from list. - * @entry: the element to delete from the list. - * Note: list_empty() on entry does not return true after this, the entry is - * in an undefined state. - */ -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = (struct list_head*)LIST_POISON1; - entry->prev = (struct list_head*)LIST_POISON2; -} -#endif diff --git a/src/linux/scripts/kconfig/lkc.h b/src/linux/scripts/kconfig/lkc.h deleted file mode 100644 index 91ca126..0000000 --- a/src/linux/scripts/kconfig/lkc.h +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#ifndef LKC_H -#define LKC_H - -#include "expr.h" - -#ifndef KBUILD_NO_NLS -# include -#else -static inline const char *gettext(const char *txt) { return txt; } -static inline void textdomain(const char *domainname) {} -static inline void bindtextdomain(const char *name, const char *dir) {} -static inline char *bind_textdomain_codeset(const char *dn, char *c) { return c; } -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#include "lkc_proto.h" - -#define SRCTREE "srctree" - -#ifndef PACKAGE -#define PACKAGE "linux" -#endif - -#define LOCALEDIR "/usr/share/locale" - -#define _(text) gettext(text) -#define N_(text) (text) - -#ifndef CONFIG_ -#define CONFIG_ "CONFIG_" -#endif -static inline const char *CONFIG_prefix(void) -{ - return getenv( "CONFIG_" ) ?: CONFIG_; -} -#undef CONFIG_ -#define CONFIG_ CONFIG_prefix() - -#define TF_COMMAND 0x0001 -#define TF_PARAM 0x0002 -#define TF_OPTION 0x0004 - -enum conf_def_mode { - def_default, - def_yes, - def_mod, - def_no, - def_random -}; - -#define T_OPT_MODULES 1 -#define T_OPT_DEFCONFIG_LIST 2 -#define T_OPT_ENV 3 -#define T_OPT_ALLNOCONFIG_Y 4 - -struct kconf_id { - int name; - int token; - unsigned int flags; - enum symbol_type stype; -}; - -void zconfdump(FILE *out); -void zconf_starthelp(void); -FILE *zconf_fopen(const char *name); -void zconf_initscan(const char *name); -void zconf_nextfile(const char *name); -int zconf_lineno(void); -const char *zconf_curname(void); - -/* confdata.c */ -const char *conf_get_configname(void); -const char *conf_get_autoconfig_name(void); -char *conf_get_default_confname(void); -void sym_set_change_count(int count); -void sym_add_change_count(int count); -bool conf_set_all_new_symbols(enum conf_def_mode mode); -void set_all_choice_values(struct symbol *csym); - -/* confdata.c and expr.c */ -static inline void xfwrite(const void *str, size_t len, size_t count, FILE *out) -{ - assert(len != 0); - - if (fwrite(str, len, count, out) != count) - fprintf(stderr, "Error in writing or end of file.\n"); -} - -/* menu.c */ -void _menu_init(void); -void menu_warn(struct menu *menu, const char *fmt, ...); -struct menu *menu_add_menu(void); -void menu_end_menu(void); -void menu_add_entry(struct symbol *sym); -void menu_end_entry(void); -void menu_add_dep(struct expr *dep); -void menu_add_visibility(struct expr *dep); -struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); -void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); -void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); -void menu_add_option(int token, char *arg); -void menu_finalize(struct menu *parent); -void menu_set_type(int type); - -/* util.c */ -struct file *file_lookup(const char *name); -int file_write_dep(const char *name); -void *xmalloc(size_t size); -void *xcalloc(size_t nmemb, size_t size); - -struct gstr { - size_t len; - char *s; - /* - * when max_width is not zero long lines in string s (if any) get - * wrapped not to exceed the max_width value - */ - int max_width; -}; -struct gstr str_new(void); -void str_free(struct gstr *gs); -void str_append(struct gstr *gs, const char *s); -void str_printf(struct gstr *gs, const char *fmt, ...); -const char *str_get(struct gstr *gs); - -/* symbol.c */ -extern struct expr *sym_env_list; - -void sym_init(void); -void sym_clear_all_valid(void); -struct symbol *sym_choice_default(struct symbol *sym); -const char *sym_get_string_default(struct symbol *sym); -struct symbol *sym_check_deps(struct symbol *sym); -struct property *prop_alloc(enum prop_type type, struct symbol *sym); -struct symbol *prop_get_symbol(struct property *prop); -struct property *sym_get_env_prop(struct symbol *sym); - -static inline tristate sym_get_tristate_value(struct symbol *sym) -{ - return sym->curr.tri; -} - - -static inline struct symbol *sym_get_choice_value(struct symbol *sym) -{ - return (struct symbol *)sym->curr.val; -} - -static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval) -{ - return sym_set_tristate_value(chval, yes); -} - -static inline bool sym_is_choice(struct symbol *sym) -{ - return sym->flags & SYMBOL_CHOICE ? true : false; -} - -static inline bool sym_is_choice_value(struct symbol *sym) -{ - return sym->flags & SYMBOL_CHOICEVAL ? true : false; -} - -static inline bool sym_is_optional(struct symbol *sym) -{ - return sym->flags & SYMBOL_OPTIONAL ? true : false; -} - -static inline bool sym_has_value(struct symbol *sym) -{ - return sym->flags & SYMBOL_DEF_USER ? true : false; -} - -#ifdef __cplusplus -} -#endif - -#endif /* LKC_H */ diff --git a/src/linux/scripts/kconfig/lkc_proto.h b/src/linux/scripts/kconfig/lkc_proto.h deleted file mode 100644 index d539871..0000000 --- a/src/linux/scripts/kconfig/lkc_proto.h +++ /dev/null @@ -1,52 +0,0 @@ -#include - -/* confdata.c */ -void conf_parse(const char *name); -int conf_read(const char *name); -int conf_read_simple(const char *name, int); -int conf_write_defconfig(const char *name); -int conf_write(const char *name); -int conf_write_autoconf(void); -bool conf_get_changed(void); -void conf_set_changed_callback(void (*fn)(void)); -void conf_set_message_callback(void (*fn)(const char *fmt, va_list ap)); - -/* menu.c */ -extern struct menu rootmenu; - -bool menu_is_empty(struct menu *menu); -bool menu_is_visible(struct menu *menu); -bool menu_has_prompt(struct menu *menu); -const char * menu_get_prompt(struct menu *menu); -struct menu * menu_get_root_menu(struct menu *menu); -struct menu * menu_get_parent_menu(struct menu *menu); -bool menu_has_help(struct menu *menu); -const char * menu_get_help(struct menu *menu); -struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head); -void menu_get_ext_help(struct menu *menu, struct gstr *help); - -/* symbol.c */ -extern struct symbol * symbol_hash[SYMBOL_HASHSIZE]; - -struct symbol * sym_lookup(const char *name, int flags); -struct symbol * sym_find(const char *name); -const char * sym_expand_string_value(const char *in); -const char * sym_escape_string_value(const char *in); -struct symbol ** sym_re_search(const char *pattern); -const char * sym_type_name(enum symbol_type type); -void sym_calc_value(struct symbol *sym); -enum symbol_type sym_get_type(struct symbol *sym); -bool sym_tristate_within_range(struct symbol *sym,tristate tri); -bool sym_set_tristate_value(struct symbol *sym,tristate tri); -tristate sym_toggle_tristate_value(struct symbol *sym); -bool sym_string_valid(struct symbol *sym, const char *newval); -bool sym_string_within_range(struct symbol *sym, const char *str); -bool sym_set_string_value(struct symbol *sym, const char *newval); -bool sym_is_changable(struct symbol *sym); -struct property * sym_get_choice_prop(struct symbol *sym); -const char * sym_get_string_value(struct symbol *sym); - -const char * prop_get_type_name(enum prop_type type); - -/* expr.c */ -void expr_print(struct expr *e, void (*fn)(void *, struct symbol *, const char *), void *data, int prevtoken); diff --git a/src/linux/scripts/kconfig/lxdialog/.gitignore b/src/linux/scripts/kconfig/lxdialog/.gitignore deleted file mode 100644 index 90b08ff..0000000 --- a/src/linux/scripts/kconfig/lxdialog/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -# -# Generated files -# -lxdialog diff --git a/src/linux/scripts/kconfig/lxdialog/check-lxdialog.sh b/src/linux/scripts/kconfig/lxdialog/check-lxdialog.sh deleted file mode 100755 index 5075ebf..0000000 --- a/src/linux/scripts/kconfig/lxdialog/check-lxdialog.sh +++ /dev/null @@ -1,91 +0,0 @@ -#!/bin/sh -# Check ncurses compatibility - -# What library to link -ldflags() -{ - pkg-config --libs ncursesw 2>/dev/null && exit - pkg-config --libs ncurses 2>/dev/null && exit - for ext in so a dll.a dylib ; do - for lib in ncursesw ncurses curses ; do - $cc -print-file-name=lib${lib}.${ext} | grep -q / - if [ $? -eq 0 ]; then - echo "-l${lib}" - exit - fi - done - done - exit 1 -} - -# Where is ncurses.h? -ccflags() -{ - if pkg-config --cflags ncursesw 2>/dev/null; then - echo '-DCURSES_LOC="" -DNCURSES_WIDECHAR=1' - elif pkg-config --cflags ncurses 2>/dev/null; then - echo '-DCURSES_LOC=""' - elif [ -f /usr/include/ncursesw/curses.h ]; then - echo '-I/usr/include/ncursesw -DCURSES_LOC=""' - echo ' -DNCURSES_WIDECHAR=1' - elif [ -f /usr/include/ncurses/ncurses.h ]; then - echo '-I/usr/include/ncurses -DCURSES_LOC=""' - elif [ -f /usr/include/ncurses/curses.h ]; then - echo '-I/usr/include/ncurses -DCURSES_LOC=""' - elif [ -f /usr/include/ncurses.h ]; then - echo '-DCURSES_LOC=""' - else - echo '-DCURSES_LOC=""' - fi -} - -# Temp file, try to clean up after us -tmp=.lxdialog.tmp -trap "rm -f $tmp" 0 1 2 3 15 - -# Check if we can link to ncurses -check() { - $cc -x c - -o $tmp 2>/dev/null <<'EOF' -#include CURSES_LOC -main() {} -EOF - if [ $? != 0 ]; then - echo " *** Unable to find the ncurses libraries or the" 1>&2 - echo " *** required header files." 1>&2 - echo " *** 'make menuconfig' requires the ncurses libraries." 1>&2 - echo " *** " 1>&2 - echo " *** Install ncurses (ncurses-devel) and try again." 1>&2 - echo " *** " 1>&2 - exit 1 - fi -} - -usage() { - printf "Usage: $0 [-check compiler options|-ccflags|-ldflags compiler options]\n" -} - -if [ $# -eq 0 ]; then - usage - exit 1 -fi - -cc="" -case "$1" in - "-check") - shift - cc="$@" - check - ;; - "-ccflags") - ccflags - ;; - "-ldflags") - shift - cc="$@" - ldflags - ;; - "*") - usage - exit 1 - ;; -esac diff --git a/src/linux/scripts/kconfig/menu.c b/src/linux/scripts/kconfig/menu.c deleted file mode 100644 index aed678e..0000000 --- a/src/linux/scripts/kconfig/menu.c +++ /dev/null @@ -1,697 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#include - -#include "lkc.h" - -static const char nohelp_text[] = "There is no help available for this option."; - -struct menu rootmenu; -static struct menu **last_entry_ptr; - -struct file *file_list; -struct file *current_file; - -void menu_warn(struct menu *menu, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "%s:%d:warning: ", menu->file->name, menu->lineno); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); -} - -static void prop_warn(struct property *prop, const char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - fprintf(stderr, "%s:%d:warning: ", prop->file->name, prop->lineno); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); -} - -void _menu_init(void) -{ - current_entry = current_menu = &rootmenu; - last_entry_ptr = &rootmenu.list; -} - -void menu_add_entry(struct symbol *sym) -{ - struct menu *menu; - - menu = xmalloc(sizeof(*menu)); - memset(menu, 0, sizeof(*menu)); - menu->sym = sym; - menu->parent = current_menu; - menu->file = current_file; - menu->lineno = zconf_lineno(); - - *last_entry_ptr = menu; - last_entry_ptr = &menu->next; - current_entry = menu; - if (sym) - menu_add_symbol(P_SYMBOL, sym, NULL); -} - -void menu_end_entry(void) -{ -} - -struct menu *menu_add_menu(void) -{ - menu_end_entry(); - last_entry_ptr = ¤t_entry->list; - return current_menu = current_entry; -} - -void menu_end_menu(void) -{ - last_entry_ptr = ¤t_menu->next; - current_menu = current_menu->parent; -} - -static struct expr *menu_check_dep(struct expr *e) -{ - if (!e) - return e; - - switch (e->type) { - case E_NOT: - e->left.expr = menu_check_dep(e->left.expr); - break; - case E_OR: - case E_AND: - e->left.expr = menu_check_dep(e->left.expr); - e->right.expr = menu_check_dep(e->right.expr); - break; - case E_SYMBOL: - /* change 'm' into 'm' && MODULES */ - if (e->left.sym == &symbol_mod) - return expr_alloc_and(e, expr_alloc_symbol(modules_sym)); - break; - default: - break; - } - return e; -} - -void menu_add_dep(struct expr *dep) -{ - current_entry->dep = expr_alloc_and(current_entry->dep, menu_check_dep(dep)); -} - -void menu_set_type(int type) -{ - struct symbol *sym = current_entry->sym; - - if (sym->type == type) - return; - if (sym->type == S_UNKNOWN) { - sym->type = type; - return; - } - menu_warn(current_entry, - "ignoring type redefinition of '%s' from '%s' to '%s'", - sym->name ? sym->name : "", - sym_type_name(sym->type), sym_type_name(type)); -} - -static struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) -{ - struct property *prop = prop_alloc(type, current_entry->sym); - - prop->menu = current_entry; - prop->expr = expr; - prop->visible.expr = menu_check_dep(dep); - - if (prompt) { - if (isspace(*prompt)) { - prop_warn(prop, "leading whitespace ignored"); - while (isspace(*prompt)) - prompt++; - } - if (current_entry->prompt && current_entry != &rootmenu) - prop_warn(prop, "prompt redefined"); - - /* Apply all upper menus' visibilities to actual prompts. */ - if(type == P_PROMPT) { - struct menu *menu = current_entry; - - while ((menu = menu->parent) != NULL) { - struct expr *dup_expr; - - if (!menu->visibility) - continue; - /* - * Do not add a reference to the - * menu's visibility expression but - * use a copy of it. Otherwise the - * expression reduction functions - * will modify expressions that have - * multiple references which can - * cause unwanted side effects. - */ - dup_expr = expr_copy(menu->visibility); - - prop->visible.expr - = expr_alloc_and(prop->visible.expr, - dup_expr); - } - } - - current_entry->prompt = prop; - } - prop->text = prompt; - - return prop; -} - -struct property *menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep) -{ - return menu_add_prop(type, prompt, NULL, dep); -} - -void menu_add_visibility(struct expr *expr) -{ - current_entry->visibility = expr_alloc_and(current_entry->visibility, - expr); -} - -void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep) -{ - menu_add_prop(type, NULL, expr, dep); -} - -void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep) -{ - menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep); -} - -void menu_add_option(int token, char *arg) -{ - switch (token) { - case T_OPT_MODULES: - if (modules_sym) - zconf_error("symbol '%s' redefines option 'modules'" - " already defined by symbol '%s'", - current_entry->sym->name, - modules_sym->name - ); - modules_sym = current_entry->sym; - break; - case T_OPT_DEFCONFIG_LIST: - if (!sym_defconfig_list) - sym_defconfig_list = current_entry->sym; - else if (sym_defconfig_list != current_entry->sym) - zconf_error("trying to redefine defconfig symbol"); - break; - case T_OPT_ENV: - prop_add_env(arg); - break; - case T_OPT_ALLNOCONFIG_Y: - current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y; - break; - } -} - -static int menu_validate_number(struct symbol *sym, struct symbol *sym2) -{ - return sym2->type == S_INT || sym2->type == S_HEX || - (sym2->type == S_UNKNOWN && sym_string_valid(sym, sym2->name)); -} - -static void sym_check_prop(struct symbol *sym) -{ - struct property *prop; - struct symbol *sym2; - for (prop = sym->prop; prop; prop = prop->next) { - switch (prop->type) { - case P_DEFAULT: - if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) && - prop->expr->type != E_SYMBOL) - prop_warn(prop, - "default for config symbol '%s'" - " must be a single symbol", sym->name); - if (prop->expr->type != E_SYMBOL) - break; - sym2 = prop_get_symbol(prop); - if (sym->type == S_HEX || sym->type == S_INT) { - if (!menu_validate_number(sym, sym2)) - prop_warn(prop, - "'%s': number is invalid", - sym->name); - } - break; - case P_SELECT: - sym2 = prop_get_symbol(prop); - if (sym->type != S_BOOLEAN && sym->type != S_TRISTATE) - prop_warn(prop, - "config symbol '%s' uses select, but is " - "not boolean or tristate", sym->name); - else if (sym2->type != S_UNKNOWN && - sym2->type != S_BOOLEAN && - sym2->type != S_TRISTATE) - prop_warn(prop, - "'%s' has wrong type. 'select' only " - "accept arguments of boolean and " - "tristate type", sym2->name); - break; - case P_RANGE: - if (sym->type != S_INT && sym->type != S_HEX) - prop_warn(prop, "range is only allowed " - "for int or hex symbols"); - if (!menu_validate_number(sym, prop->expr->left.sym) || - !menu_validate_number(sym, prop->expr->right.sym)) - prop_warn(prop, "range is invalid"); - break; - default: - ; - } - } -} - -void menu_finalize(struct menu *parent) -{ - struct menu *menu, *last_menu; - struct symbol *sym; - struct property *prop; - struct expr *parentdep, *basedep, *dep, *dep2, **ep; - - sym = parent->sym; - if (parent->list) { - if (sym && sym_is_choice(sym)) { - if (sym->type == S_UNKNOWN) { - /* find the first choice value to find out choice type */ - current_entry = parent; - for (menu = parent->list; menu; menu = menu->next) { - if (menu->sym && menu->sym->type != S_UNKNOWN) { - menu_set_type(menu->sym->type); - break; - } - } - } - /* set the type of the remaining choice values */ - for (menu = parent->list; menu; menu = menu->next) { - current_entry = menu; - if (menu->sym && menu->sym->type == S_UNKNOWN) - menu_set_type(sym->type); - } - parentdep = expr_alloc_symbol(sym); - } else if (parent->prompt) - parentdep = parent->prompt->visible.expr; - else - parentdep = parent->dep; - - for (menu = parent->list; menu; menu = menu->next) { - basedep = expr_transform(menu->dep); - basedep = expr_alloc_and(expr_copy(parentdep), basedep); - basedep = expr_eliminate_dups(basedep); - menu->dep = basedep; - if (menu->sym) - prop = menu->sym->prop; - else - prop = menu->prompt; - for (; prop; prop = prop->next) { - if (prop->menu != menu) - continue; - dep = expr_transform(prop->visible.expr); - dep = expr_alloc_and(expr_copy(basedep), dep); - dep = expr_eliminate_dups(dep); - if (menu->sym && menu->sym->type != S_TRISTATE) - dep = expr_trans_bool(dep); - prop->visible.expr = dep; - if (prop->type == P_SELECT) { - struct symbol *es = prop_get_symbol(prop); - es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, - expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); - } - } - } - for (menu = parent->list; menu; menu = menu->next) - menu_finalize(menu); - } else if (sym) { - basedep = parent->prompt ? parent->prompt->visible.expr : NULL; - basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); - basedep = expr_eliminate_dups(expr_transform(basedep)); - last_menu = NULL; - for (menu = parent->next; menu; menu = menu->next) { - dep = menu->prompt ? menu->prompt->visible.expr : menu->dep; - if (!expr_contains_symbol(dep, sym)) - break; - if (expr_depends_symbol(dep, sym)) - goto next; - dep = expr_trans_compare(dep, E_UNEQUAL, &symbol_no); - dep = expr_eliminate_dups(expr_transform(dep)); - dep2 = expr_copy(basedep); - expr_eliminate_eq(&dep, &dep2); - expr_free(dep); - if (!expr_is_yes(dep2)) { - expr_free(dep2); - break; - } - expr_free(dep2); - next: - menu_finalize(menu); - menu->parent = parent; - last_menu = menu; - } - if (last_menu) { - parent->list = parent->next; - parent->next = last_menu->next; - last_menu->next = NULL; - } - - sym->dir_dep.expr = expr_alloc_or(sym->dir_dep.expr, parent->dep); - } - for (menu = parent->list; menu; menu = menu->next) { - if (sym && sym_is_choice(sym) && - menu->sym && !sym_is_choice_value(menu->sym)) { - current_entry = menu; - menu->sym->flags |= SYMBOL_CHOICEVAL; - if (!menu->prompt) - menu_warn(menu, "choice value must have a prompt"); - for (prop = menu->sym->prop; prop; prop = prop->next) { - if (prop->type == P_DEFAULT) - prop_warn(prop, "defaults for choice " - "values not supported"); - if (prop->menu == menu) - continue; - if (prop->type == P_PROMPT && - prop->menu->parent->sym != sym) - prop_warn(prop, "choice value used outside its choice group"); - } - /* Non-tristate choice values of tristate choices must - * depend on the choice being set to Y. The choice - * values' dependencies were propagated to their - * properties above, so the change here must be re- - * propagated. - */ - if (sym->type == S_TRISTATE && menu->sym->type != S_TRISTATE) { - basedep = expr_alloc_comp(E_EQUAL, sym, &symbol_yes); - menu->dep = expr_alloc_and(basedep, menu->dep); - for (prop = menu->sym->prop; prop; prop = prop->next) { - if (prop->menu != menu) - continue; - prop->visible.expr = expr_alloc_and(expr_copy(basedep), - prop->visible.expr); - } - } - menu_add_symbol(P_CHOICE, sym, NULL); - prop = sym_get_choice_prop(sym); - for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr) - ; - *ep = expr_alloc_one(E_LIST, NULL); - (*ep)->right.sym = menu->sym; - } - if (menu->list && (!menu->prompt || !menu->prompt->text)) { - for (last_menu = menu->list; ; last_menu = last_menu->next) { - last_menu->parent = parent; - if (!last_menu->next) - break; - } - last_menu->next = menu->next; - menu->next = menu->list; - menu->list = NULL; - } - } - - if (sym && !(sym->flags & SYMBOL_WARNED)) { - if (sym->type == S_UNKNOWN) - menu_warn(parent, "config symbol defined without type"); - - if (sym_is_choice(sym) && !parent->prompt) - menu_warn(parent, "choice must have a prompt"); - - /* Check properties connected to this symbol */ - sym_check_prop(sym); - sym->flags |= SYMBOL_WARNED; - } - - if (sym && !sym_is_optional(sym) && parent->prompt) { - sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, - expr_alloc_and(parent->prompt->visible.expr, - expr_alloc_symbol(&symbol_mod))); - } -} - -bool menu_has_prompt(struct menu *menu) -{ - if (!menu->prompt) - return false; - return true; -} - -/* - * Determine if a menu is empty. - * A menu is considered empty if it contains no or only - * invisible entries. - */ -bool menu_is_empty(struct menu *menu) -{ - struct menu *child; - - for (child = menu->list; child; child = child->next) { - if (menu_is_visible(child)) - return(false); - } - return(true); -} - -bool menu_is_visible(struct menu *menu) -{ - struct menu *child; - struct symbol *sym; - tristate visible; - - if (!menu->prompt) - return false; - - if (menu->visibility) { - if (expr_calc_value(menu->visibility) == no) - return false; - } - - sym = menu->sym; - if (sym) { - sym_calc_value(sym); - visible = menu->prompt->visible.tri; - } else - visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr); - - if (visible != no) - return true; - - if (!sym || sym_get_tristate_value(menu->sym) == no) - return false; - - for (child = menu->list; child; child = child->next) { - if (menu_is_visible(child)) { - if (sym) - sym->flags |= SYMBOL_DEF_USER; - return true; - } - } - - return false; -} - -const char *menu_get_prompt(struct menu *menu) -{ - if (menu->prompt) - return menu->prompt->text; - else if (menu->sym) - return menu->sym->name; - return NULL; -} - -struct menu *menu_get_root_menu(struct menu *menu) -{ - return &rootmenu; -} - -struct menu *menu_get_parent_menu(struct menu *menu) -{ - enum prop_type type; - - for (; menu != &rootmenu; menu = menu->parent) { - type = menu->prompt ? menu->prompt->type : 0; - if (type == P_MENU) - break; - } - return menu; -} - -bool menu_has_help(struct menu *menu) -{ - return menu->help != NULL; -} - -const char *menu_get_help(struct menu *menu) -{ - if (menu->help) - return menu->help; - else - return ""; -} - -static void get_prompt_str(struct gstr *r, struct property *prop, - struct list_head *head) -{ - int i, j; - struct menu *submenu[8], *menu, *location = NULL; - struct jump_key *jump = NULL; - - str_printf(r, _("Prompt: %s\n"), _(prop->text)); - menu = prop->menu->parent; - for (i = 0; menu != &rootmenu && i < 8; menu = menu->parent) { - bool accessible = menu_is_visible(menu); - - submenu[i++] = menu; - if (location == NULL && accessible) - location = menu; - } - if (head && location) { - jump = xmalloc(sizeof(struct jump_key)); - - if (menu_is_visible(prop->menu)) { - /* - * There is not enough room to put the hint at the - * beginning of the "Prompt" line. Put the hint on the - * last "Location" line even when it would belong on - * the former. - */ - jump->target = prop->menu; - } else - jump->target = location; - - if (list_empty(head)) - jump->index = 0; - else - jump->index = list_entry(head->prev, struct jump_key, - entries)->index + 1; - - list_add_tail(&jump->entries, head); - } - - if (i > 0) { - str_printf(r, _(" Location:\n")); - for (j = 4; --i >= 0; j += 2) { - menu = submenu[i]; - if (jump && menu == location) - jump->offset = strlen(r->s); - str_printf(r, "%*c-> %s", j, ' ', - _(menu_get_prompt(menu))); - if (menu->sym) { - str_printf(r, " (%s [=%s])", menu->sym->name ? - menu->sym->name : _(""), - sym_get_string_value(menu->sym)); - } - str_append(r, "\n"); - } - } -} - -/* - * get property of type P_SYMBOL - */ -static struct property *get_symbol_prop(struct symbol *sym) -{ - struct property *prop = NULL; - - for_all_properties(sym, prop, P_SYMBOL) - break; - return prop; -} - -/* - * head is optional and may be NULL - */ -static void get_symbol_str(struct gstr *r, struct symbol *sym, - struct list_head *head) -{ - bool hit; - struct property *prop; - - if (sym && sym->name) { - str_printf(r, "Symbol: %s [=%s]\n", sym->name, - sym_get_string_value(sym)); - str_printf(r, "Type : %s\n", sym_type_name(sym->type)); - if (sym->type == S_INT || sym->type == S_HEX) { - prop = sym_get_range_prop(sym); - if (prop) { - str_printf(r, "Range : "); - expr_gstr_print(prop->expr, r); - str_append(r, "\n"); - } - } - } - for_all_prompts(sym, prop) - get_prompt_str(r, prop, head); - - prop = get_symbol_prop(sym); - if (prop) { - str_printf(r, _(" Defined at %s:%d\n"), prop->menu->file->name, - prop->menu->lineno); - if (!expr_is_yes(prop->visible.expr)) { - str_append(r, _(" Depends on: ")); - expr_gstr_print(prop->visible.expr, r); - str_append(r, "\n"); - } - } - - hit = false; - for_all_properties(sym, prop, P_SELECT) { - if (!hit) { - str_append(r, " Selects: "); - hit = true; - } else - str_printf(r, " && "); - expr_gstr_print(prop->expr, r); - } - if (hit) - str_append(r, "\n"); - if (sym->rev_dep.expr) { - str_append(r, _(" Selected by: ")); - expr_gstr_print(sym->rev_dep.expr, r); - str_append(r, "\n"); - } - str_append(r, "\n\n"); -} - -struct gstr get_relations_str(struct symbol **sym_arr, struct list_head *head) -{ - struct symbol *sym; - struct gstr res = str_new(); - int i; - - for (i = 0; sym_arr && (sym = sym_arr[i]); i++) - get_symbol_str(&res, sym, head); - if (!i) - str_append(&res, _("No matches found.\n")); - return res; -} - - -void menu_get_ext_help(struct menu *menu, struct gstr *help) -{ - struct symbol *sym = menu->sym; - const char *help_text = nohelp_text; - - if (menu_has_help(menu)) { - if (sym->name) - str_printf(help, "%s%s:\n\n", CONFIG_, sym->name); - help_text = menu_get_help(menu); - } - str_printf(help, "%s\n", _(help_text)); - if (sym) - get_symbol_str(help, sym, NULL); -} diff --git a/src/linux/scripts/kconfig/symbol.c b/src/linux/scripts/kconfig/symbol.c deleted file mode 100644 index 2432298..0000000 --- a/src/linux/scripts/kconfig/symbol.c +++ /dev/null @@ -1,1392 +0,0 @@ -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#include -#include - -#include "lkc.h" - -struct symbol symbol_yes = { - .name = "y", - .curr = { "y", yes }, - .flags = SYMBOL_CONST|SYMBOL_VALID, -}, symbol_mod = { - .name = "m", - .curr = { "m", mod }, - .flags = SYMBOL_CONST|SYMBOL_VALID, -}, symbol_no = { - .name = "n", - .curr = { "n", no }, - .flags = SYMBOL_CONST|SYMBOL_VALID, -}, symbol_empty = { - .name = "", - .curr = { "", no }, - .flags = SYMBOL_VALID, -}; - -struct symbol *sym_defconfig_list; -struct symbol *modules_sym; -tristate modules_val; - -struct expr *sym_env_list; - -static void sym_add_default(struct symbol *sym, const char *def) -{ - struct property *prop = prop_alloc(P_DEFAULT, sym); - - prop->expr = expr_alloc_symbol(sym_lookup(def, SYMBOL_CONST)); -} - -void sym_init(void) -{ - struct symbol *sym; - struct utsname uts; - static bool inited = false; - - if (inited) - return; - inited = true; - - uname(&uts); - - sym = sym_lookup("UNAME_RELEASE", 0); - sym->type = S_STRING; - sym->flags |= SYMBOL_AUTO; - sym_add_default(sym, uts.release); -} - -enum symbol_type sym_get_type(struct symbol *sym) -{ - enum symbol_type type = sym->type; - - if (type == S_TRISTATE) { - if (sym_is_choice_value(sym) && sym->visible == yes) - type = S_BOOLEAN; - else if (modules_val == no) - type = S_BOOLEAN; - } - return type; -} - -const char *sym_type_name(enum symbol_type type) -{ - switch (type) { - case S_BOOLEAN: - return "boolean"; - case S_TRISTATE: - return "tristate"; - case S_INT: - return "integer"; - case S_HEX: - return "hex"; - case S_STRING: - return "string"; - case S_UNKNOWN: - return "unknown"; - case S_OTHER: - break; - } - return "???"; -} - -struct property *sym_get_choice_prop(struct symbol *sym) -{ - struct property *prop; - - for_all_choices(sym, prop) - return prop; - return NULL; -} - -struct property *sym_get_env_prop(struct symbol *sym) -{ - struct property *prop; - - for_all_properties(sym, prop, P_ENV) - return prop; - return NULL; -} - -static struct property *sym_get_default_prop(struct symbol *sym) -{ - struct property *prop; - - for_all_defaults(sym, prop) { - prop->visible.tri = expr_calc_value(prop->visible.expr); - if (prop->visible.tri != no) - return prop; - } - return NULL; -} - -static struct property *sym_get_range_prop(struct symbol *sym) -{ - struct property *prop; - - for_all_properties(sym, prop, P_RANGE) { - prop->visible.tri = expr_calc_value(prop->visible.expr); - if (prop->visible.tri != no) - return prop; - } - return NULL; -} - -static long long sym_get_range_val(struct symbol *sym, int base) -{ - sym_calc_value(sym); - switch (sym->type) { - case S_INT: - base = 10; - break; - case S_HEX: - base = 16; - break; - default: - break; - } - return strtoll(sym->curr.val, NULL, base); -} - -static void sym_validate_range(struct symbol *sym) -{ - struct property *prop; - int base; - long long val, val2; - char str[64]; - - switch (sym->type) { - case S_INT: - base = 10; - break; - case S_HEX: - base = 16; - break; - default: - return; - } - prop = sym_get_range_prop(sym); - if (!prop) - return; - val = strtoll(sym->curr.val, NULL, base); - val2 = sym_get_range_val(prop->expr->left.sym, base); - if (val >= val2) { - val2 = sym_get_range_val(prop->expr->right.sym, base); - if (val <= val2) - return; - } - if (sym->type == S_INT) - sprintf(str, "%lld", val2); - else - sprintf(str, "0x%llx", val2); - sym->curr.val = strdup(str); -} - -static void sym_set_changed(struct symbol *sym) -{ - struct property *prop; - - sym->flags |= SYMBOL_CHANGED; - for (prop = sym->prop; prop; prop = prop->next) { - if (prop->menu) - prop->menu->flags |= MENU_CHANGED; - } -} - -static void sym_set_all_changed(void) -{ - struct symbol *sym; - int i; - - for_all_symbols(i, sym) - sym_set_changed(sym); -} - -static void sym_calc_visibility(struct symbol *sym) -{ - struct property *prop; - struct symbol *choice_sym = NULL; - tristate tri; - - /* any prompt visible? */ - tri = no; - - if (sym_is_choice_value(sym)) - choice_sym = prop_get_symbol(sym_get_choice_prop(sym)); - - for_all_prompts(sym, prop) { - prop->visible.tri = expr_calc_value(prop->visible.expr); - /* - * Tristate choice_values with visibility 'mod' are - * not visible if the corresponding choice's value is - * 'yes'. - */ - if (choice_sym && sym->type == S_TRISTATE && - prop->visible.tri == mod && choice_sym->curr.tri == yes) - prop->visible.tri = no; - - tri = EXPR_OR(tri, prop->visible.tri); - } - if (tri == mod && (sym->type != S_TRISTATE || modules_val == no)) - tri = yes; - if (sym->visible != tri) { - sym->visible = tri; - sym_set_changed(sym); - } - if (sym_is_choice_value(sym)) - return; - /* defaulting to "yes" if no explicit "depends on" are given */ - tri = yes; - if (sym->dir_dep.expr) - tri = expr_calc_value(sym->dir_dep.expr); - if (tri == mod) - tri = yes; - if (sym->dir_dep.tri != tri) { - sym->dir_dep.tri = tri; - sym_set_changed(sym); - } - tri = no; - if (sym->rev_dep.expr) - tri = expr_calc_value(sym->rev_dep.expr); - if (tri == mod && sym_get_type(sym) == S_BOOLEAN) - tri = yes; - if (sym->rev_dep.tri != tri) { - sym->rev_dep.tri = tri; - sym_set_changed(sym); - } -} - -/* - * Find the default symbol for a choice. - * First try the default values for the choice symbol - * Next locate the first visible choice value - * Return NULL if none was found - */ -struct symbol *sym_choice_default(struct symbol *sym) -{ - struct symbol *def_sym; - struct property *prop; - struct expr *e; - - /* any of the defaults visible? */ - for_all_defaults(sym, prop) { - prop->visible.tri = expr_calc_value(prop->visible.expr); - if (prop->visible.tri == no) - continue; - def_sym = prop_get_symbol(prop); - if (def_sym->visible != no) - return def_sym; - } - - /* just get the first visible value */ - prop = sym_get_choice_prop(sym); - expr_list_for_each_sym(prop->expr, e, def_sym) - if (def_sym->visible != no) - return def_sym; - - /* failed to locate any defaults */ - return NULL; -} - -static struct symbol *sym_calc_choice(struct symbol *sym) -{ - struct symbol *def_sym; - struct property *prop; - struct expr *e; - int flags; - - /* first calculate all choice values' visibilities */ - flags = sym->flags; - prop = sym_get_choice_prop(sym); - expr_list_for_each_sym(prop->expr, e, def_sym) { - sym_calc_visibility(def_sym); - if (def_sym->visible != no) - flags &= def_sym->flags; - } - - sym->flags &= flags | ~SYMBOL_DEF_USER; - - /* is the user choice visible? */ - def_sym = sym->def[S_DEF_USER].val; - if (def_sym && def_sym->visible != no) - return def_sym; - - def_sym = sym_choice_default(sym); - - if (def_sym == NULL) - /* no choice? reset tristate value */ - sym->curr.tri = no; - - return def_sym; -} - -void sym_calc_value(struct symbol *sym) -{ - struct symbol_value newval, oldval; - struct property *prop; - struct expr *e; - - if (!sym) - return; - - if (sym->flags & SYMBOL_VALID) - return; - - if (sym_is_choice_value(sym) && - sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) { - sym->flags &= ~SYMBOL_NEED_SET_CHOICE_VALUES; - prop = sym_get_choice_prop(sym); - sym_calc_value(prop_get_symbol(prop)); - } - - sym->flags |= SYMBOL_VALID; - - oldval = sym->curr; - - switch (sym->type) { - case S_INT: - case S_HEX: - case S_STRING: - newval = symbol_empty.curr; - break; - case S_BOOLEAN: - case S_TRISTATE: - newval = symbol_no.curr; - break; - default: - sym->curr.val = sym->name; - sym->curr.tri = no; - return; - } - if (!sym_is_choice_value(sym)) - sym->flags &= ~SYMBOL_WRITE; - - sym_calc_visibility(sym); - - /* set default if recursively called */ - sym->curr = newval; - - switch (sym_get_type(sym)) { - case S_BOOLEAN: - case S_TRISTATE: - if (sym_is_choice_value(sym) && sym->visible == yes) { - prop = sym_get_choice_prop(sym); - newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; - } else { - if (sym->visible != no) { - /* if the symbol is visible use the user value - * if available, otherwise try the default value - */ - sym->flags |= SYMBOL_WRITE; - if (sym_has_value(sym)) { - newval.tri = EXPR_AND(sym->def[S_DEF_USER].tri, - sym->visible); - goto calc_newval; - } - } - if (sym->rev_dep.tri != no) - sym->flags |= SYMBOL_WRITE; - if (!sym_is_choice(sym)) { - prop = sym_get_default_prop(sym); - if (prop) { - sym->flags |= SYMBOL_WRITE; - newval.tri = EXPR_AND(expr_calc_value(prop->expr), - prop->visible.tri); - } - } - calc_newval: - if (sym->dir_dep.tri == no && sym->rev_dep.tri != no) { - struct expr *e; - e = expr_simplify_unmet_dep(sym->rev_dep.expr, - sym->dir_dep.expr); - fprintf(stderr, "warning: ("); - expr_fprint(e, stderr); - fprintf(stderr, ") selects %s which has unmet direct dependencies (", - sym->name); - expr_fprint(sym->dir_dep.expr, stderr); - fprintf(stderr, ")\n"); - expr_free(e); - } - newval.tri = EXPR_OR(newval.tri, sym->rev_dep.tri); - } - if (newval.tri == mod && sym_get_type(sym) == S_BOOLEAN) - newval.tri = yes; - break; - case S_STRING: - case S_HEX: - case S_INT: - if (sym->visible != no) { - sym->flags |= SYMBOL_WRITE; - if (sym_has_value(sym)) { - newval.val = sym->def[S_DEF_USER].val; - break; - } - } - prop = sym_get_default_prop(sym); - if (prop) { - struct symbol *ds = prop_get_symbol(prop); - if (ds) { - sym->flags |= SYMBOL_WRITE; - sym_calc_value(ds); - newval.val = ds->curr.val; - } - } - break; - default: - ; - } - - sym->curr = newval; - if (sym_is_choice(sym) && newval.tri == yes) - sym->curr.val = sym_calc_choice(sym); - sym_validate_range(sym); - - if (memcmp(&oldval, &sym->curr, sizeof(oldval))) { - sym_set_changed(sym); - if (modules_sym == sym) { - sym_set_all_changed(); - modules_val = modules_sym->curr.tri; - } - } - - if (sym_is_choice(sym)) { - struct symbol *choice_sym; - - prop = sym_get_choice_prop(sym); - expr_list_for_each_sym(prop->expr, e, choice_sym) { - if ((sym->flags & SYMBOL_WRITE) && - choice_sym->visible != no) - choice_sym->flags |= SYMBOL_WRITE; - if (sym->flags & SYMBOL_CHANGED) - sym_set_changed(choice_sym); - } - } - - if (sym->flags & SYMBOL_AUTO) - sym->flags &= ~SYMBOL_WRITE; - - if (sym->flags & SYMBOL_NEED_SET_CHOICE_VALUES) - set_all_choice_values(sym); -} - -void sym_clear_all_valid(void) -{ - struct symbol *sym; - int i; - - for_all_symbols(i, sym) - sym->flags &= ~SYMBOL_VALID; - sym_add_change_count(1); - sym_calc_value(modules_sym); -} - -bool sym_tristate_within_range(struct symbol *sym, tristate val) -{ - int type = sym_get_type(sym); - - if (sym->visible == no) - return false; - - if (type != S_BOOLEAN && type != S_TRISTATE) - return false; - - if (type == S_BOOLEAN && val == mod) - return false; - if (sym->visible <= sym->rev_dep.tri) - return false; - if (sym_is_choice_value(sym) && sym->visible == yes) - return val == yes; - return val >= sym->rev_dep.tri && val <= sym->visible; -} - -bool sym_set_tristate_value(struct symbol *sym, tristate val) -{ - tristate oldval = sym_get_tristate_value(sym); - - if (oldval != val && !sym_tristate_within_range(sym, val)) - return false; - - if (!(sym->flags & SYMBOL_DEF_USER)) { - sym->flags |= SYMBOL_DEF_USER; - sym_set_changed(sym); - } - /* - * setting a choice value also resets the new flag of the choice - * symbol and all other choice values. - */ - if (sym_is_choice_value(sym) && val == yes) { - struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); - struct property *prop; - struct expr *e; - - cs->def[S_DEF_USER].val = sym; - cs->flags |= SYMBOL_DEF_USER; - prop = sym_get_choice_prop(cs); - for (e = prop->expr; e; e = e->left.expr) { - if (e->right.sym->visible != no) - e->right.sym->flags |= SYMBOL_DEF_USER; - } - } - - sym->def[S_DEF_USER].tri = val; - if (oldval != val) - sym_clear_all_valid(); - - return true; -} - -tristate sym_toggle_tristate_value(struct symbol *sym) -{ - tristate oldval, newval; - - oldval = newval = sym_get_tristate_value(sym); - do { - switch (newval) { - case no: - newval = mod; - break; - case mod: - newval = yes; - break; - case yes: - newval = no; - break; - } - if (sym_set_tristate_value(sym, newval)) - break; - } while (oldval != newval); - return newval; -} - -bool sym_string_valid(struct symbol *sym, const char *str) -{ - signed char ch; - - switch (sym->type) { - case S_STRING: - return true; - case S_INT: - ch = *str++; - if (ch == '-') - ch = *str++; - if (!isdigit(ch)) - return false; - if (ch == '0' && *str != 0) - return false; - while ((ch = *str++)) { - if (!isdigit(ch)) - return false; - } - return true; - case S_HEX: - if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) - str += 2; - ch = *str++; - do { - if (!isxdigit(ch)) - return false; - } while ((ch = *str++)); - return true; - case S_BOOLEAN: - case S_TRISTATE: - switch (str[0]) { - case 'y': case 'Y': - case 'm': case 'M': - case 'n': case 'N': - return true; - } - return false; - default: - return false; - } -} - -bool sym_string_within_range(struct symbol *sym, const char *str) -{ - struct property *prop; - long long val; - - switch (sym->type) { - case S_STRING: - return sym_string_valid(sym, str); - case S_INT: - if (!sym_string_valid(sym, str)) - return false; - prop = sym_get_range_prop(sym); - if (!prop) - return true; - val = strtoll(str, NULL, 10); - return val >= sym_get_range_val(prop->expr->left.sym, 10) && - val <= sym_get_range_val(prop->expr->right.sym, 10); - case S_HEX: - if (!sym_string_valid(sym, str)) - return false; - prop = sym_get_range_prop(sym); - if (!prop) - return true; - val = strtoll(str, NULL, 16); - return val >= sym_get_range_val(prop->expr->left.sym, 16) && - val <= sym_get_range_val(prop->expr->right.sym, 16); - case S_BOOLEAN: - case S_TRISTATE: - switch (str[0]) { - case 'y': case 'Y': - return sym_tristate_within_range(sym, yes); - case 'm': case 'M': - return sym_tristate_within_range(sym, mod); - case 'n': case 'N': - return sym_tristate_within_range(sym, no); - } - return false; - default: - return false; - } -} - -bool sym_set_string_value(struct symbol *sym, const char *newval) -{ - const char *oldval; - char *val; - int size; - - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - switch (newval[0]) { - case 'y': case 'Y': - return sym_set_tristate_value(sym, yes); - case 'm': case 'M': - return sym_set_tristate_value(sym, mod); - case 'n': case 'N': - return sym_set_tristate_value(sym, no); - } - return false; - default: - ; - } - - if (!sym_string_within_range(sym, newval)) - return false; - - if (!(sym->flags & SYMBOL_DEF_USER)) { - sym->flags |= SYMBOL_DEF_USER; - sym_set_changed(sym); - } - - oldval = sym->def[S_DEF_USER].val; - size = strlen(newval) + 1; - if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { - size += 2; - sym->def[S_DEF_USER].val = val = xmalloc(size); - *val++ = '0'; - *val++ = 'x'; - } else if (!oldval || strcmp(oldval, newval)) - sym->def[S_DEF_USER].val = val = xmalloc(size); - else - return true; - - strcpy(val, newval); - free((void *)oldval); - sym_clear_all_valid(); - - return true; -} - -/* - * Find the default value associated to a symbol. - * For tristate symbol handle the modules=n case - * in which case "m" becomes "y". - * If the symbol does not have any default then fallback - * to the fixed default values. - */ -const char *sym_get_string_default(struct symbol *sym) -{ - struct property *prop; - struct symbol *ds; - const char *str; - tristate val; - - sym_calc_visibility(sym); - sym_calc_value(modules_sym); - val = symbol_no.curr.tri; - str = symbol_empty.curr.val; - - /* If symbol has a default value look it up */ - prop = sym_get_default_prop(sym); - if (prop != NULL) { - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - /* The visibility may limit the value from yes => mod */ - val = EXPR_AND(expr_calc_value(prop->expr), prop->visible.tri); - break; - default: - /* - * The following fails to handle the situation - * where a default value is further limited by - * the valid range. - */ - ds = prop_get_symbol(prop); - if (ds != NULL) { - sym_calc_value(ds); - str = (const char *)ds->curr.val; - } - } - } - - /* Handle select statements */ - val = EXPR_OR(val, sym->rev_dep.tri); - - /* transpose mod to yes if modules are not enabled */ - if (val == mod) - if (!sym_is_choice_value(sym) && modules_sym->curr.tri == no) - val = yes; - - /* transpose mod to yes if type is bool */ - if (sym->type == S_BOOLEAN && val == mod) - val = yes; - - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - switch (val) { - case no: return "n"; - case mod: return "m"; - case yes: return "y"; - } - case S_INT: - case S_HEX: - return str; - case S_STRING: - return str; - case S_OTHER: - case S_UNKNOWN: - break; - } - return ""; -} - -const char *sym_get_string_value(struct symbol *sym) -{ - tristate val; - - switch (sym->type) { - case S_BOOLEAN: - case S_TRISTATE: - val = sym_get_tristate_value(sym); - switch (val) { - case no: - return "n"; - case mod: - sym_calc_value(modules_sym); - return (modules_sym->curr.tri == no) ? "n" : "m"; - case yes: - return "y"; - } - break; - default: - ; - } - return (const char *)sym->curr.val; -} - -bool sym_is_changable(struct symbol *sym) -{ - return sym->visible > sym->rev_dep.tri; -} - -static unsigned strhash(const char *s) -{ - /* fnv32 hash */ - unsigned hash = 2166136261U; - for (; *s; s++) - hash = (hash ^ *s) * 0x01000193; - return hash; -} - -struct symbol *sym_lookup(const char *name, int flags) -{ - struct symbol *symbol; - char *new_name; - int hash; - - if (name) { - if (name[0] && !name[1]) { - switch (name[0]) { - case 'y': return &symbol_yes; - case 'm': return &symbol_mod; - case 'n': return &symbol_no; - } - } - hash = strhash(name) % SYMBOL_HASHSIZE; - - for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { - if (symbol->name && - !strcmp(symbol->name, name) && - (flags ? symbol->flags & flags - : !(symbol->flags & (SYMBOL_CONST|SYMBOL_CHOICE)))) - return symbol; - } - new_name = strdup(name); - } else { - new_name = NULL; - hash = 0; - } - - symbol = xmalloc(sizeof(*symbol)); - memset(symbol, 0, sizeof(*symbol)); - symbol->name = new_name; - symbol->type = S_UNKNOWN; - symbol->flags |= flags; - - symbol->next = symbol_hash[hash]; - symbol_hash[hash] = symbol; - - return symbol; -} - -struct symbol *sym_find(const char *name) -{ - struct symbol *symbol = NULL; - int hash = 0; - - if (!name) - return NULL; - - if (name[0] && !name[1]) { - switch (name[0]) { - case 'y': return &symbol_yes; - case 'm': return &symbol_mod; - case 'n': return &symbol_no; - } - } - hash = strhash(name) % SYMBOL_HASHSIZE; - - for (symbol = symbol_hash[hash]; symbol; symbol = symbol->next) { - if (symbol->name && - !strcmp(symbol->name, name) && - !(symbol->flags & SYMBOL_CONST)) - break; - } - - return symbol; -} - -/* - * Expand symbol's names embedded in the string given in argument. Symbols' - * name to be expanded shall be prefixed by a '$'. Unknown symbol expands to - * the empty string. - */ -const char *sym_expand_string_value(const char *in) -{ - const char *src; - char *res; - size_t reslen; - - reslen = strlen(in) + 1; - res = xmalloc(reslen); - res[0] = '\0'; - - while ((src = strchr(in, '$'))) { - char *p, name[SYMBOL_MAXLENGTH]; - const char *symval = ""; - struct symbol *sym; - size_t newlen; - - strncat(res, in, src - in); - src++; - - p = name; - while (isalnum(*src) || *src == '_') - *p++ = *src++; - *p = '\0'; - - sym = sym_find(name); - if (sym != NULL) { - sym_calc_value(sym); - symval = sym_get_string_value(sym); - } - - newlen = strlen(res) + strlen(symval) + strlen(src) + 1; - if (newlen > reslen) { - reslen = newlen; - res = realloc(res, reslen); - } - - strcat(res, symval); - in = src; - } - strcat(res, in); - - return res; -} - -const char *sym_escape_string_value(const char *in) -{ - const char *p; - size_t reslen; - char *res; - size_t l; - - reslen = strlen(in) + strlen("\"\"") + 1; - - p = in; - for (;;) { - l = strcspn(p, "\"\\"); - p += l; - - if (p[0] == '\0') - break; - - reslen++; - p++; - } - - res = xmalloc(reslen); - res[0] = '\0'; - - strcat(res, "\""); - - p = in; - for (;;) { - l = strcspn(p, "\"\\"); - strncat(res, p, l); - p += l; - - if (p[0] == '\0') - break; - - strcat(res, "\\"); - strncat(res, p++, 1); - } - - strcat(res, "\""); - return res; -} - -struct sym_match { - struct symbol *sym; - off_t so, eo; -}; - -/* Compare matched symbols as thus: - * - first, symbols that match exactly - * - then, alphabetical sort - */ -static int sym_rel_comp(const void *sym1, const void *sym2) -{ - const struct sym_match *s1 = sym1; - const struct sym_match *s2 = sym2; - int exact1, exact2; - - /* Exact match: - * - if matched length on symbol s1 is the length of that symbol, - * then this symbol should come first; - * - if matched length on symbol s2 is the length of that symbol, - * then this symbol should come first. - * Note: since the search can be a regexp, both symbols may match - * exactly; if this is the case, we can't decide which comes first, - * and we fallback to sorting alphabetically. - */ - exact1 = (s1->eo - s1->so) == strlen(s1->sym->name); - exact2 = (s2->eo - s2->so) == strlen(s2->sym->name); - if (exact1 && !exact2) - return -1; - if (!exact1 && exact2) - return 1; - - /* As a fallback, sort symbols alphabetically */ - return strcmp(s1->sym->name, s2->sym->name); -} - -struct symbol **sym_re_search(const char *pattern) -{ - struct symbol *sym, **sym_arr = NULL; - struct sym_match *sym_match_arr = NULL; - int i, cnt, size; - regex_t re; - regmatch_t match[1]; - - cnt = size = 0; - /* Skip if empty */ - if (strlen(pattern) == 0) - return NULL; - if (regcomp(&re, pattern, REG_EXTENDED|REG_ICASE)) - return NULL; - - for_all_symbols(i, sym) { - if (sym->flags & SYMBOL_CONST || !sym->name) - continue; - if (regexec(&re, sym->name, 1, match, 0)) - continue; - if (cnt >= size) { - void *tmp; - size += 16; - tmp = realloc(sym_match_arr, size * sizeof(struct sym_match)); - if (!tmp) - goto sym_re_search_free; - sym_match_arr = tmp; - } - sym_calc_value(sym); - /* As regexec returned 0, we know we have a match, so - * we can use match[0].rm_[se]o without further checks - */ - sym_match_arr[cnt].so = match[0].rm_so; - sym_match_arr[cnt].eo = match[0].rm_eo; - sym_match_arr[cnt++].sym = sym; - } - if (sym_match_arr) { - qsort(sym_match_arr, cnt, sizeof(struct sym_match), sym_rel_comp); - sym_arr = malloc((cnt+1) * sizeof(struct symbol)); - if (!sym_arr) - goto sym_re_search_free; - for (i = 0; i < cnt; i++) - sym_arr[i] = sym_match_arr[i].sym; - sym_arr[cnt] = NULL; - } -sym_re_search_free: - /* sym_match_arr can be NULL if no match, but free(NULL) is OK */ - free(sym_match_arr); - regfree(&re); - - return sym_arr; -} - -/* - * When we check for recursive dependencies we use a stack to save - * current state so we can print out relevant info to user. - * The entries are located on the call stack so no need to free memory. - * Note insert() remove() must always match to properly clear the stack. - */ -static struct dep_stack { - struct dep_stack *prev, *next; - struct symbol *sym; - struct property *prop; - struct expr *expr; -} *check_top; - -static void dep_stack_insert(struct dep_stack *stack, struct symbol *sym) -{ - memset(stack, 0, sizeof(*stack)); - if (check_top) - check_top->next = stack; - stack->prev = check_top; - stack->sym = sym; - check_top = stack; -} - -static void dep_stack_remove(void) -{ - check_top = check_top->prev; - if (check_top) - check_top->next = NULL; -} - -/* - * Called when we have detected a recursive dependency. - * check_top point to the top of the stact so we use - * the ->prev pointer to locate the bottom of the stack. - */ -static void sym_check_print_recursive(struct symbol *last_sym) -{ - struct dep_stack *stack; - struct symbol *sym, *next_sym; - struct menu *menu = NULL; - struct property *prop; - struct dep_stack cv_stack; - - if (sym_is_choice_value(last_sym)) { - dep_stack_insert(&cv_stack, last_sym); - last_sym = prop_get_symbol(sym_get_choice_prop(last_sym)); - } - - for (stack = check_top; stack != NULL; stack = stack->prev) - if (stack->sym == last_sym) - break; - if (!stack) { - fprintf(stderr, "unexpected recursive dependency error\n"); - return; - } - - for (; stack; stack = stack->next) { - sym = stack->sym; - next_sym = stack->next ? stack->next->sym : last_sym; - prop = stack->prop; - if (prop == NULL) - prop = stack->sym->prop; - - /* for choice values find the menu entry (used below) */ - if (sym_is_choice(sym) || sym_is_choice_value(sym)) { - for (prop = sym->prop; prop; prop = prop->next) { - menu = prop->menu; - if (prop->menu) - break; - } - } - if (stack->sym == last_sym) - fprintf(stderr, "%s:%d:error: recursive dependency detected!\n", - prop->file->name, prop->lineno); - fprintf(stderr, "For a resolution refer to Documentation/kbuild/kconfig-language.txt\n"); - fprintf(stderr, "subsection \"Kconfig recursive dependency limitations\"\n"); - if (stack->expr) { - fprintf(stderr, "%s:%d:\tsymbol %s %s value contains %s\n", - prop->file->name, prop->lineno, - sym->name ? sym->name : "", - prop_get_type_name(prop->type), - next_sym->name ? next_sym->name : ""); - } else if (stack->prop) { - fprintf(stderr, "%s:%d:\tsymbol %s depends on %s\n", - prop->file->name, prop->lineno, - sym->name ? sym->name : "", - next_sym->name ? next_sym->name : ""); - } else if (sym_is_choice(sym)) { - fprintf(stderr, "%s:%d:\tchoice %s contains symbol %s\n", - menu->file->name, menu->lineno, - sym->name ? sym->name : "", - next_sym->name ? next_sym->name : ""); - } else if (sym_is_choice_value(sym)) { - fprintf(stderr, "%s:%d:\tsymbol %s is part of choice %s\n", - menu->file->name, menu->lineno, - sym->name ? sym->name : "", - next_sym->name ? next_sym->name : ""); - } else { - fprintf(stderr, "%s:%d:\tsymbol %s is selected by %s\n", - prop->file->name, prop->lineno, - sym->name ? sym->name : "", - next_sym->name ? next_sym->name : ""); - } - } - - if (check_top == &cv_stack) - dep_stack_remove(); -} - -static struct symbol *sym_check_expr_deps(struct expr *e) -{ - struct symbol *sym; - - if (!e) - return NULL; - switch (e->type) { - case E_OR: - case E_AND: - sym = sym_check_expr_deps(e->left.expr); - if (sym) - return sym; - return sym_check_expr_deps(e->right.expr); - case E_NOT: - return sym_check_expr_deps(e->left.expr); - case E_EQUAL: - case E_GEQ: - case E_GTH: - case E_LEQ: - case E_LTH: - case E_UNEQUAL: - sym = sym_check_deps(e->left.sym); - if (sym) - return sym; - return sym_check_deps(e->right.sym); - case E_SYMBOL: - return sym_check_deps(e->left.sym); - default: - break; - } - printf("Oops! How to check %d?\n", e->type); - return NULL; -} - -/* return NULL when dependencies are OK */ -static struct symbol *sym_check_sym_deps(struct symbol *sym) -{ - struct symbol *sym2; - struct property *prop; - struct dep_stack stack; - - dep_stack_insert(&stack, sym); - - sym2 = sym_check_expr_deps(sym->rev_dep.expr); - if (sym2) - goto out; - - for (prop = sym->prop; prop; prop = prop->next) { - if (prop->type == P_CHOICE || prop->type == P_SELECT) - continue; - stack.prop = prop; - sym2 = sym_check_expr_deps(prop->visible.expr); - if (sym2) - break; - if (prop->type != P_DEFAULT || sym_is_choice(sym)) - continue; - stack.expr = prop->expr; - sym2 = sym_check_expr_deps(prop->expr); - if (sym2) - break; - stack.expr = NULL; - } - -out: - dep_stack_remove(); - - return sym2; -} - -static struct symbol *sym_check_choice_deps(struct symbol *choice) -{ - struct symbol *sym, *sym2; - struct property *prop; - struct expr *e; - struct dep_stack stack; - - dep_stack_insert(&stack, choice); - - prop = sym_get_choice_prop(choice); - expr_list_for_each_sym(prop->expr, e, sym) - sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); - - choice->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); - sym2 = sym_check_sym_deps(choice); - choice->flags &= ~SYMBOL_CHECK; - if (sym2) - goto out; - - expr_list_for_each_sym(prop->expr, e, sym) { - sym2 = sym_check_sym_deps(sym); - if (sym2) - break; - } -out: - expr_list_for_each_sym(prop->expr, e, sym) - sym->flags &= ~SYMBOL_CHECK; - - if (sym2 && sym_is_choice_value(sym2) && - prop_get_symbol(sym_get_choice_prop(sym2)) == choice) - sym2 = choice; - - dep_stack_remove(); - - return sym2; -} - -struct symbol *sym_check_deps(struct symbol *sym) -{ - struct symbol *sym2; - struct property *prop; - - if (sym->flags & SYMBOL_CHECK) { - sym_check_print_recursive(sym); - return sym; - } - if (sym->flags & SYMBOL_CHECKED) - return NULL; - - if (sym_is_choice_value(sym)) { - struct dep_stack stack; - - /* for choice groups start the check with main choice symbol */ - dep_stack_insert(&stack, sym); - prop = sym_get_choice_prop(sym); - sym2 = sym_check_deps(prop_get_symbol(prop)); - dep_stack_remove(); - } else if (sym_is_choice(sym)) { - sym2 = sym_check_choice_deps(sym); - } else { - sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); - sym2 = sym_check_sym_deps(sym); - sym->flags &= ~SYMBOL_CHECK; - } - - if (sym2 && sym2 == sym) - sym2 = NULL; - - return sym2; -} - -struct property *prop_alloc(enum prop_type type, struct symbol *sym) -{ - struct property *prop; - struct property **propp; - - prop = xmalloc(sizeof(*prop)); - memset(prop, 0, sizeof(*prop)); - prop->type = type; - prop->sym = sym; - prop->file = current_file; - prop->lineno = zconf_lineno(); - - /* append property to the prop list of symbol */ - if (sym) { - for (propp = &sym->prop; *propp; propp = &(*propp)->next) - ; - *propp = prop; - } - - return prop; -} - -struct symbol *prop_get_symbol(struct property *prop) -{ - if (prop->expr && (prop->expr->type == E_SYMBOL || - prop->expr->type == E_LIST)) - return prop->expr->left.sym; - return NULL; -} - -const char *prop_get_type_name(enum prop_type type) -{ - switch (type) { - case P_PROMPT: - return "prompt"; - case P_ENV: - return "env"; - case P_COMMENT: - return "comment"; - case P_MENU: - return "menu"; - case P_DEFAULT: - return "default"; - case P_CHOICE: - return "choice"; - case P_SELECT: - return "select"; - case P_RANGE: - return "range"; - case P_SYMBOL: - return "symbol"; - case P_UNKNOWN: - break; - } - return "unknown"; -} - -static void prop_add_env(const char *env) -{ - struct symbol *sym, *sym2; - struct property *prop; - char *p; - - sym = current_entry->sym; - sym->flags |= SYMBOL_AUTO; - for_all_properties(sym, prop, P_ENV) { - sym2 = prop_get_symbol(prop); - if (strcmp(sym2->name, env)) - menu_warn(current_entry, "redefining environment symbol from %s", - sym2->name); - return; - } - - prop = prop_alloc(P_ENV, sym); - prop->expr = expr_alloc_symbol(sym_lookup(env, SYMBOL_CONST)); - - sym_env_list = expr_alloc_one(E_LIST, sym_env_list); - sym_env_list->right.sym = sym; - - p = getenv(env); - if (p) - sym_add_default(sym, p); - else - menu_warn(current_entry, "environment variable %s undefined", env); -} diff --git a/src/linux/scripts/kconfig/util.c b/src/linux/scripts/kconfig/util.c deleted file mode 100644 index 0e76042..0000000 --- a/src/linux/scripts/kconfig/util.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2002-2005 Roman Zippel - * Copyright (C) 2002-2005 Sam Ravnborg - * - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#include "lkc.h" - -/* file already present in list? If not add it */ -struct file *file_lookup(const char *name) -{ - struct file *file; - const char *file_name = sym_expand_string_value(name); - - for (file = file_list; file; file = file->next) { - if (!strcmp(name, file->name)) { - free((void *)file_name); - return file; - } - } - - file = xmalloc(sizeof(*file)); - memset(file, 0, sizeof(*file)); - file->name = file_name; - file->next = file_list; - file_list = file; - return file; -} - -/* write a dependency file as used by kbuild to track dependencies */ -int file_write_dep(const char *name) -{ - struct symbol *sym, *env_sym; - struct expr *e; - struct file *file; - FILE *out; - - if (!name) - name = ".kconfig.d"; - out = fopen("..config.tmp", "w"); - if (!out) - return 1; - fprintf(out, "deps_config := \\\n"); - for (file = file_list; file; file = file->next) { - if (file->next) - fprintf(out, "\t%s \\\n", file->name); - else - fprintf(out, "\t%s\n", file->name); - } - fprintf(out, "\n%s: \\\n" - "\t$(deps_config)\n\n", conf_get_autoconfig_name()); - - expr_list_for_each_sym(sym_env_list, e, sym) { - struct property *prop; - const char *value; - - prop = sym_get_env_prop(sym); - env_sym = prop_get_symbol(prop); - if (!env_sym) - continue; - value = getenv(env_sym->name); - if (!value) - value = ""; - fprintf(out, "ifneq \"$(%s)\" \"%s\"\n", env_sym->name, value); - fprintf(out, "%s: FORCE\n", conf_get_autoconfig_name()); - fprintf(out, "endif\n"); - } - - fprintf(out, "\n$(deps_config): ;\n"); - fclose(out); - rename("..config.tmp", name); - return 0; -} - - -/* Allocate initial growable string */ -struct gstr str_new(void) -{ - struct gstr gs; - gs.s = xmalloc(sizeof(char) * 64); - gs.len = 64; - gs.max_width = 0; - strcpy(gs.s, "\0"); - return gs; -} - -/* Free storage for growable string */ -void str_free(struct gstr *gs) -{ - if (gs->s) - free(gs->s); - gs->s = NULL; - gs->len = 0; -} - -/* Append to growable string */ -void str_append(struct gstr *gs, const char *s) -{ - size_t l; - if (s) { - l = strlen(gs->s) + strlen(s) + 1; - if (l > gs->len) { - gs->s = realloc(gs->s, l); - gs->len = l; - } - strcat(gs->s, s); - } -} - -/* Append printf formatted string to growable string */ -void str_printf(struct gstr *gs, const char *fmt, ...) -{ - va_list ap; - char s[10000]; /* big enough... */ - va_start(ap, fmt); - vsnprintf(s, sizeof(s), fmt, ap); - str_append(gs, s); - va_end(ap); -} - -/* Retrieve value of growable string */ -const char *str_get(struct gstr *gs) -{ - return gs->s; -} - -void *xmalloc(size_t size) -{ - void *p = malloc(size); - if (p) - return p; - fprintf(stderr, "Out of memory.\n"); - exit(1); -} - -void *xcalloc(size_t nmemb, size_t size) -{ - void *p = calloc(nmemb, size); - if (p) - return p; - fprintf(stderr, "Out of memory.\n"); - exit(1); -} diff --git a/src/linux/scripts/kconfig/zconf.hash.c_shipped b/src/linux/scripts/kconfig/zconf.hash.c_shipped deleted file mode 100644 index 360a62d..0000000 --- a/src/linux/scripts/kconfig/zconf.hash.c_shipped +++ /dev/null @@ -1,293 +0,0 @@ -/* ANSI-C code produced by gperf version 3.0.4 */ -/* Command-line: gperf -t --output-file scripts/kconfig/zconf.hash.c_shipped -a -C -E -g -k '1,3,$' -p -t scripts/kconfig/zconf.gperf */ - -#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ - && ('%' == 37) && ('&' == 38) && ('\'' == 39) && ('(' == 40) \ - && (')' == 41) && ('*' == 42) && ('+' == 43) && (',' == 44) \ - && ('-' == 45) && ('.' == 46) && ('/' == 47) && ('0' == 48) \ - && ('1' == 49) && ('2' == 50) && ('3' == 51) && ('4' == 52) \ - && ('5' == 53) && ('6' == 54) && ('7' == 55) && ('8' == 56) \ - && ('9' == 57) && (':' == 58) && (';' == 59) && ('<' == 60) \ - && ('=' == 61) && ('>' == 62) && ('?' == 63) && ('A' == 65) \ - && ('B' == 66) && ('C' == 67) && ('D' == 68) && ('E' == 69) \ - && ('F' == 70) && ('G' == 71) && ('H' == 72) && ('I' == 73) \ - && ('J' == 74) && ('K' == 75) && ('L' == 76) && ('M' == 77) \ - && ('N' == 78) && ('O' == 79) && ('P' == 80) && ('Q' == 81) \ - && ('R' == 82) && ('S' == 83) && ('T' == 84) && ('U' == 85) \ - && ('V' == 86) && ('W' == 87) && ('X' == 88) && ('Y' == 89) \ - && ('Z' == 90) && ('[' == 91) && ('\\' == 92) && (']' == 93) \ - && ('^' == 94) && ('_' == 95) && ('a' == 97) && ('b' == 98) \ - && ('c' == 99) && ('d' == 100) && ('e' == 101) && ('f' == 102) \ - && ('g' == 103) && ('h' == 104) && ('i' == 105) && ('j' == 106) \ - && ('k' == 107) && ('l' == 108) && ('m' == 109) && ('n' == 110) \ - && ('o' == 111) && ('p' == 112) && ('q' == 113) && ('r' == 114) \ - && ('s' == 115) && ('t' == 116) && ('u' == 117) && ('v' == 118) \ - && ('w' == 119) && ('x' == 120) && ('y' == 121) && ('z' == 122) \ - && ('{' == 123) && ('|' == 124) && ('}' == 125) && ('~' == 126)) -/* The character set is not based on ISO-646. */ -#error "gperf generated tables don't work with this execution character set. Please report a bug to ." -#endif - -#line 10 "scripts/kconfig/zconf.gperf" -struct kconf_id; - -static const struct kconf_id *kconf_id_lookup(register const char *str, register unsigned int len); -/* maximum key range = 71, duplicates = 0 */ - -#ifdef __GNUC__ -__inline -#else -#ifdef __cplusplus -inline -#endif -#endif -static unsigned int -kconf_id_hash (register const char *str, register unsigned int len) -{ - static const unsigned char asso_values[] = - { - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 0, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 5, 25, 25, - 0, 0, 0, 5, 0, 0, 73, 73, 5, 0, - 10, 5, 45, 73, 20, 20, 0, 15, 15, 73, - 20, 5, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, - 73, 73, 73, 73, 73, 73 - }; - register int hval = len; - - switch (hval) - { - default: - hval += asso_values[(unsigned char)str[2]]; - /*FALLTHROUGH*/ - case 2: - case 1: - hval += asso_values[(unsigned char)str[0]]; - break; - } - return hval + asso_values[(unsigned char)str[len - 1]]; -} - -struct kconf_id_strings_t - { - char kconf_id_strings_str2[sizeof("if")]; - char kconf_id_strings_str3[sizeof("int")]; - char kconf_id_strings_str5[sizeof("endif")]; - char kconf_id_strings_str7[sizeof("default")]; - char kconf_id_strings_str8[sizeof("tristate")]; - char kconf_id_strings_str9[sizeof("endchoice")]; - char kconf_id_strings_str10[sizeof("---help---")]; - char kconf_id_strings_str12[sizeof("def_tristate")]; - char kconf_id_strings_str13[sizeof("def_bool")]; - char kconf_id_strings_str14[sizeof("defconfig_list")]; - char kconf_id_strings_str17[sizeof("on")]; - char kconf_id_strings_str18[sizeof("optional")]; - char kconf_id_strings_str21[sizeof("option")]; - char kconf_id_strings_str22[sizeof("endmenu")]; - char kconf_id_strings_str23[sizeof("mainmenu")]; - char kconf_id_strings_str25[sizeof("menuconfig")]; - char kconf_id_strings_str27[sizeof("modules")]; - char kconf_id_strings_str28[sizeof("allnoconfig_y")]; - char kconf_id_strings_str29[sizeof("menu")]; - char kconf_id_strings_str31[sizeof("select")]; - char kconf_id_strings_str32[sizeof("comment")]; - char kconf_id_strings_str33[sizeof("env")]; - char kconf_id_strings_str35[sizeof("range")]; - char kconf_id_strings_str36[sizeof("choice")]; - char kconf_id_strings_str39[sizeof("bool")]; - char kconf_id_strings_str41[sizeof("source")]; - char kconf_id_strings_str42[sizeof("visible")]; - char kconf_id_strings_str43[sizeof("hex")]; - char kconf_id_strings_str46[sizeof("config")]; - char kconf_id_strings_str47[sizeof("boolean")]; - char kconf_id_strings_str51[sizeof("string")]; - char kconf_id_strings_str54[sizeof("help")]; - char kconf_id_strings_str56[sizeof("prompt")]; - char kconf_id_strings_str72[sizeof("depends")]; - }; -static const struct kconf_id_strings_t kconf_id_strings_contents = - { - "if", - "int", - "endif", - "default", - "tristate", - "endchoice", - "---help---", - "def_tristate", - "def_bool", - "defconfig_list", - "on", - "optional", - "option", - "endmenu", - "mainmenu", - "menuconfig", - "modules", - "allnoconfig_y", - "menu", - "select", - "comment", - "env", - "range", - "choice", - "bool", - "source", - "visible", - "hex", - "config", - "boolean", - "string", - "help", - "prompt", - "depends" - }; -#define kconf_id_strings ((const char *) &kconf_id_strings_contents) -#ifdef __GNUC__ -__inline -#if defined __GNUC_STDC_INLINE__ || defined __GNUC_GNU_INLINE__ -__attribute__ ((__gnu_inline__)) -#endif -#endif -const struct kconf_id * -kconf_id_lookup (register const char *str, register unsigned int len) -{ - enum - { - TOTAL_KEYWORDS = 34, - MIN_WORD_LENGTH = 2, - MAX_WORD_LENGTH = 14, - MIN_HASH_VALUE = 2, - MAX_HASH_VALUE = 72 - }; - - static const struct kconf_id wordlist[] = - { - {-1}, {-1}, -#line 26 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str2, T_IF, TF_COMMAND|TF_PARAM}, -#line 37 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str3, T_TYPE, TF_COMMAND, S_INT}, - {-1}, -#line 27 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str5, T_ENDIF, TF_COMMAND}, - {-1}, -#line 30 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str7, T_DEFAULT, TF_COMMAND, S_UNKNOWN}, -#line 32 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str8, T_TYPE, TF_COMMAND, S_TRISTATE}, -#line 20 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str9, T_ENDCHOICE, TF_COMMAND}, -#line 25 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str10, T_HELP, TF_COMMAND}, - {-1}, -#line 33 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str12, T_DEFAULT, TF_COMMAND, S_TRISTATE}, -#line 36 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str13, T_DEFAULT, TF_COMMAND, S_BOOLEAN}, -#line 46 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str14, T_OPT_DEFCONFIG_LIST,TF_OPTION}, - {-1}, {-1}, -#line 44 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str17, T_ON, TF_PARAM}, -#line 29 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str18, T_OPTIONAL, TF_COMMAND}, - {-1}, {-1}, -#line 43 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str21, T_OPTION, TF_COMMAND}, -#line 17 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str22, T_ENDMENU, TF_COMMAND}, -#line 15 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str23, T_MAINMENU, TF_COMMAND}, - {-1}, -#line 23 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str25, T_MENUCONFIG, TF_COMMAND}, - {-1}, -#line 45 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27, T_OPT_MODULES, TF_OPTION}, -#line 48 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28, T_OPT_ALLNOCONFIG_Y,TF_OPTION}, -#line 16 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29, T_MENU, TF_COMMAND}, - {-1}, -#line 40 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str31, T_SELECT, TF_COMMAND}, -#line 21 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str32, T_COMMENT, TF_COMMAND}, -#line 47 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str33, T_OPT_ENV, TF_OPTION}, - {-1}, -#line 41 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str35, T_RANGE, TF_COMMAND}, -#line 19 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str36, T_CHOICE, TF_COMMAND}, - {-1}, {-1}, -#line 34 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str39, T_TYPE, TF_COMMAND, S_BOOLEAN}, - {-1}, -#line 18 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str41, T_SOURCE, TF_COMMAND}, -#line 42 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str42, T_VISIBLE, TF_COMMAND}, -#line 38 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str43, T_TYPE, TF_COMMAND, S_HEX}, - {-1}, {-1}, -#line 22 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str46, T_CONFIG, TF_COMMAND}, -#line 35 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str47, T_TYPE, TF_COMMAND, S_BOOLEAN}, - {-1}, {-1}, {-1}, -#line 39 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str51, T_TYPE, TF_COMMAND, S_STRING}, - {-1}, {-1}, -#line 24 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str54, T_HELP, TF_COMMAND}, - {-1}, -#line 31 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str56, T_PROMPT, TF_COMMAND}, - {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, - {-1}, {-1}, {-1}, {-1}, {-1}, {-1}, -#line 28 "scripts/kconfig/zconf.gperf" - {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str72, T_DEPENDS, TF_COMMAND} - }; - - if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) - { - register int key = kconf_id_hash (str, len); - - if (key <= MAX_HASH_VALUE && key >= 0) - { - register int o = wordlist[key].name; - if (o >= 0) - { - register const char *s = o + kconf_id_strings; - - if (*str == *s && !strncmp (str + 1, s + 1, len - 1) && s[len] == '\0') - return &wordlist[key]; - } - } - } - return 0; -} -#line 49 "scripts/kconfig/zconf.gperf" - diff --git a/src/linux/scripts/kconfig/zconf.lex.c_shipped b/src/linux/scripts/kconfig/zconf.lex.c_shipped deleted file mode 100644 index 37fdf61..0000000 --- a/src/linux/scripts/kconfig/zconf.lex.c_shipped +++ /dev/null @@ -1,2473 +0,0 @@ - -#line 3 "scripts/kconfig/zconf.lex.c_shipped" - -#define YY_INT_ALIGNED short int - -/* A lexical scanner generated by flex */ - -#define yy_create_buffer zconf_create_buffer -#define yy_delete_buffer zconf_delete_buffer -#define yy_flex_debug zconf_flex_debug -#define yy_init_buffer zconf_init_buffer -#define yy_flush_buffer zconf_flush_buffer -#define yy_load_buffer_state zconf_load_buffer_state -#define yy_switch_to_buffer zconf_switch_to_buffer -#define yyin zconfin -#define yyleng zconfleng -#define yylex zconflex -#define yylineno zconflineno -#define yyout zconfout -#define yyrestart zconfrestart -#define yytext zconftext -#define yywrap zconfwrap -#define yyalloc zconfalloc -#define yyrealloc zconfrealloc -#define yyfree zconffree - -#define FLEX_SCANNER -#define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 -#define YY_FLEX_SUBMINOR_VERSION 35 -#if YY_FLEX_SUBMINOR_VERSION > 0 -#define FLEX_BETA -#endif - -/* First, we deal with platform-specific or compiler-specific issues. */ - -/* begin standard C headers. */ -#include -#include -#include -#include - -/* end standard C headers. */ - -/* flex integer type definitions */ - -#ifndef FLEXINT_H -#define FLEXINT_H - -/* C99 systems have . Non-C99 systems may or may not. */ - -#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - -/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, - * if you want the limit (max/min) macros for int types. - */ -#ifndef __STDC_LIMIT_MACROS -#define __STDC_LIMIT_MACROS 1 -#endif - -#include -typedef int8_t flex_int8_t; -typedef uint8_t flex_uint8_t; -typedef int16_t flex_int16_t; -typedef uint16_t flex_uint16_t; -typedef int32_t flex_int32_t; -typedef uint32_t flex_uint32_t; -#else -typedef signed char flex_int8_t; -typedef short int flex_int16_t; -typedef int flex_int32_t; -typedef unsigned char flex_uint8_t; -typedef unsigned short int flex_uint16_t; -typedef unsigned int flex_uint32_t; - -/* Limits of integral types. */ -#ifndef INT8_MIN -#define INT8_MIN (-128) -#endif -#ifndef INT16_MIN -#define INT16_MIN (-32767-1) -#endif -#ifndef INT32_MIN -#define INT32_MIN (-2147483647-1) -#endif -#ifndef INT8_MAX -#define INT8_MAX (127) -#endif -#ifndef INT16_MAX -#define INT16_MAX (32767) -#endif -#ifndef INT32_MAX -#define INT32_MAX (2147483647) -#endif -#ifndef UINT8_MAX -#define UINT8_MAX (255U) -#endif -#ifndef UINT16_MAX -#define UINT16_MAX (65535U) -#endif -#ifndef UINT32_MAX -#define UINT32_MAX (4294967295U) -#endif - -#endif /* ! C99 */ - -#endif /* ! FLEXINT_H */ - -#ifdef __cplusplus - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -/* C99 requires __STDC__ to be defined as 1. */ -#if defined (__STDC__) - -#define YY_USE_CONST - -#endif /* defined (__STDC__) */ -#endif /* ! __cplusplus */ - -#ifdef YY_USE_CONST -#define yyconst const -#else -#define yyconst -#endif - -/* Returned upon end-of-file. */ -#define YY_NULL 0 - -/* Promotes a possibly negative, possibly signed char to an unsigned - * integer for use as an array index. If the signed char is negative, - * we want to instead treat it as an 8-bit unsigned char, hence the - * double cast. - */ -#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) - -/* Enter a start condition. This macro really ought to take a parameter, - * but we do it the disgusting crufty way forced on us by the ()-less - * definition of BEGIN. - */ -#define BEGIN (yy_start) = 1 + 2 * - -/* Translate the current start state into a value that can be later handed - * to BEGIN to return to the state. The YYSTATE alias is for lex - * compatibility. - */ -#define YY_START (((yy_start) - 1) / 2) -#define YYSTATE YY_START - -/* Action number for EOF rule of a given start state. */ -#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) - -/* Special action meaning "start processing a new file". */ -#define YY_NEW_FILE zconfrestart(zconfin ) - -#define YY_END_OF_BUFFER_CHAR 0 - -/* Size of default input buffer. */ -#ifndef YY_BUF_SIZE -#ifdef __ia64__ -/* On IA-64, the buffer size is 16k, not 8k. - * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. - * Ditto for the __ia64__ case accordingly. - */ -#define YY_BUF_SIZE 32768 -#else -#define YY_BUF_SIZE 16384 -#endif /* __ia64__ */ -#endif - -/* The state buf must be large enough to hold one state per character in the main buffer. - */ -#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) - -#ifndef YY_TYPEDEF_YY_BUFFER_STATE -#define YY_TYPEDEF_YY_BUFFER_STATE -typedef struct yy_buffer_state *YY_BUFFER_STATE; -#endif - -extern int zconfleng; - -extern FILE *zconfin, *zconfout; - -#define EOB_ACT_CONTINUE_SCAN 0 -#define EOB_ACT_END_OF_FILE 1 -#define EOB_ACT_LAST_MATCH 2 - - #define YY_LESS_LINENO(n) - -/* Return all but the first "n" matched characters back to the input stream. */ -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up zconftext. */ \ - int yyless_macro_arg = (n); \ - YY_LESS_LINENO(yyless_macro_arg);\ - *yy_cp = (yy_hold_char); \ - YY_RESTORE_YY_MORE_OFFSET \ - (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ - YY_DO_BEFORE_ACTION; /* set up zconftext again */ \ - } \ - while ( 0 ) - -#define unput(c) yyunput( c, (yytext_ptr) ) - -#ifndef YY_TYPEDEF_YY_SIZE_T -#define YY_TYPEDEF_YY_SIZE_T -typedef size_t yy_size_t; -#endif - -#ifndef YY_STRUCT_YY_BUFFER_STATE -#define YY_STRUCT_YY_BUFFER_STATE -struct yy_buffer_state - { - FILE *yy_input_file; - - char *yy_ch_buf; /* input buffer */ - char *yy_buf_pos; /* current position in input buffer */ - - /* Size of input buffer in bytes, not including room for EOB - * characters. - */ - yy_size_t yy_buf_size; - - /* Number of characters read into yy_ch_buf, not including EOB - * characters. - */ - int yy_n_chars; - - /* Whether we "own" the buffer - i.e., we know we created it, - * and can realloc() it to grow it, and should free() it to - * delete it. - */ - int yy_is_our_buffer; - - /* Whether this is an "interactive" input source; if so, and - * if we're using stdio for input, then we want to use getc() - * instead of fread(), to make sure we stop fetching input after - * each newline. - */ - int yy_is_interactive; - - /* Whether we're considered to be at the beginning of a line. - * If so, '^' rules will be active on the next match, otherwise - * not. - */ - int yy_at_bol; - - int yy_bs_lineno; /**< The line count. */ - int yy_bs_column; /**< The column count. */ - - /* Whether to try to fill the input buffer when we reach the - * end of it. - */ - int yy_fill_buffer; - - int yy_buffer_status; - -#define YY_BUFFER_NEW 0 -#define YY_BUFFER_NORMAL 1 - /* When an EOF's been seen but there's still some text to process - * then we mark the buffer as YY_EOF_PENDING, to indicate that we - * shouldn't try reading from the input source any more. We might - * still have a bunch of tokens to match, though, because of - * possible backing-up. - * - * When we actually see the EOF, we change the status to "new" - * (via zconfrestart()), so that the user can continue scanning by - * just pointing zconfin at a new input file. - */ -#define YY_BUFFER_EOF_PENDING 2 - - }; -#endif /* !YY_STRUCT_YY_BUFFER_STATE */ - -/* Stack of input buffers. */ -static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ -static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ -static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ - -/* We provide macros for accessing buffer states in case in the - * future we want to put the buffer states in a more general - * "scanner state". - * - * Returns the top of the stack, or NULL. - */ -#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ - ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ - : NULL) - -/* Same as previous macro, but useful when we know that the buffer stack is not - * NULL or when we need an lvalue. For internal use only. - */ -#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] - -/* yy_hold_char holds the character lost when zconftext is formed. */ -static char yy_hold_char; -static int yy_n_chars; /* number of characters read into yy_ch_buf */ -int zconfleng; - -/* Points to current character in buffer. */ -static char *yy_c_buf_p = (char *) 0; -static int yy_init = 0; /* whether we need to initialize */ -static int yy_start = 0; /* start state number */ - -/* Flag which is used to allow zconfwrap()'s to do buffer switches - * instead of setting up a fresh zconfin. A bit of a hack ... - */ -static int yy_did_buffer_switch_on_eof; - -void zconfrestart (FILE *input_file ); -void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer ); -YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size ); -void zconf_delete_buffer (YY_BUFFER_STATE b ); -void zconf_flush_buffer (YY_BUFFER_STATE b ); -void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer ); -void zconfpop_buffer_state (void ); - -static void zconfensure_buffer_stack (void ); -static void zconf_load_buffer_state (void ); -static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file ); - -#define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER ) - -YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size ); -YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str ); -YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,int len ); - -void *zconfalloc (yy_size_t ); -void *zconfrealloc (void *,yy_size_t ); -void zconffree (void * ); - -#define yy_new_buffer zconf_create_buffer - -#define yy_set_interactive(is_interactive) \ - { \ - if ( ! YY_CURRENT_BUFFER ){ \ - zconfensure_buffer_stack (); \ - YY_CURRENT_BUFFER_LVALUE = \ - zconf_create_buffer(zconfin,YY_BUF_SIZE ); \ - } \ - YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ - } - -#define yy_set_bol(at_bol) \ - { \ - if ( ! YY_CURRENT_BUFFER ){\ - zconfensure_buffer_stack (); \ - YY_CURRENT_BUFFER_LVALUE = \ - zconf_create_buffer(zconfin,YY_BUF_SIZE ); \ - } \ - YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ - } - -#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) - -/* Begin user sect3 */ - -#define zconfwrap(n) 1 -#define YY_SKIP_YYWRAP - -typedef unsigned char YY_CHAR; - -FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0; - -typedef int yy_state_type; - -extern int zconflineno; - -int zconflineno = 1; - -extern char *zconftext; -#define yytext_ptr zconftext -static yyconst flex_int16_t yy_nxt[][18] = - { - { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 - }, - - { - 11, 12, 13, 14, 12, 12, 15, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12 - }, - - { - 11, 12, 13, 14, 12, 12, 15, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12 - }, - - { - 11, 16, 16, 17, 16, 16, 16, 16, 16, 16, - 16, 18, 16, 16, 16, 16, 16, 16 - }, - - { - 11, 16, 16, 17, 16, 16, 16, 16, 16, 16, - 16, 18, 16, 16, 16, 16, 16, 16 - - }, - - { - 11, 19, 20, 21, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19 - }, - - { - 11, 19, 20, 21, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 19, 19, 19, 19, 19 - }, - - { - 11, 22, 22, 23, 22, 24, 22, 22, 24, 22, - 22, 22, 22, 22, 22, 22, 25, 22 - }, - - { - 11, 22, 22, 23, 22, 24, 22, 22, 24, 22, - 22, 22, 22, 22, 22, 22, 25, 22 - }, - - { - 11, 26, 27, 28, 29, 30, 31, 32, 30, 33, - 34, 35, 35, 36, 37, 38, 39, 40 - - }, - - { - 11, 26, 27, 28, 29, 30, 31, 32, 30, 33, - 34, 35, 35, 36, 37, 38, 39, 40 - }, - - { - -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11, -11 - }, - - { - 11, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12, -12 - }, - - { - 11, -13, 41, 42, -13, -13, 43, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13, -13 - }, - - { - 11, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14, -14 - - }, - - { - 11, 44, 44, 45, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44 - }, - - { - 11, -16, -16, -16, -16, -16, -16, -16, -16, -16, - -16, -16, -16, -16, -16, -16, -16, -16 - }, - - { - 11, -17, -17, -17, -17, -17, -17, -17, -17, -17, - -17, -17, -17, -17, -17, -17, -17, -17 - }, - - { - 11, -18, -18, -18, -18, -18, -18, -18, -18, -18, - -18, 46, -18, -18, -18, -18, -18, -18 - }, - - { - 11, 47, 47, -19, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47 - - }, - - { - 11, -20, 48, 49, -20, -20, -20, -20, -20, -20, - -20, -20, -20, -20, -20, -20, -20, -20 - }, - - { - 11, 50, -21, -21, 50, 50, 50, 50, 50, 50, - 50, 50, 50, 50, 50, 50, 50, 50 - }, - - { - 11, 51, 51, 52, 51, -22, 51, 51, -22, 51, - 51, 51, 51, 51, 51, 51, -22, 51 - }, - - { - 11, -23, -23, -23, -23, -23, -23, -23, -23, -23, - -23, -23, -23, -23, -23, -23, -23, -23 - }, - - { - 11, -24, -24, -24, -24, -24, -24, -24, -24, -24, - -24, -24, -24, -24, -24, -24, -24, -24 - - }, - - { - 11, 53, 53, 54, 53, 53, 53, 53, 53, 53, - 53, 53, 53, 53, 53, 53, 53, 53 - }, - - { - 11, -26, -26, -26, -26, -26, -26, -26, -26, -26, - -26, -26, -26, -26, -26, -26, -26, -26 - }, - - { - 11, -27, 55, -27, -27, -27, -27, -27, -27, -27, - -27, -27, -27, -27, -27, -27, -27, -27 - }, - - { - 11, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, -28, -28, -28, -28, -28 - }, - - { - 11, -29, -29, -29, -29, -29, -29, -29, -29, -29, - -29, -29, -29, -29, 56, -29, -29, -29 - - }, - - { - 11, -30, -30, -30, -30, -30, -30, -30, -30, -30, - -30, -30, -30, -30, -30, -30, -30, -30 - }, - - { - 11, 57, 57, -31, 57, 57, 57, 57, 57, 57, - 57, 57, 57, 57, 57, 57, 57, 57 - }, - - { - 11, -32, -32, -32, -32, -32, -32, 58, -32, -32, - -32, -32, -32, -32, -32, -32, -32, -32 - }, - - { - 11, -33, -33, -33, -33, -33, -33, -33, -33, -33, - -33, -33, -33, -33, -33, -33, -33, -33 - }, - - { - 11, -34, -34, -34, -34, -34, -34, -34, -34, -34, - -34, -34, -34, -34, -34, -34, -34, -34 - - }, - - { - 11, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, 59, 59, -35, -35, -35, -35, -35 - }, - - { - 11, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, 60, -36, -36, -36 - }, - - { - 11, -37, -37, -37, -37, -37, -37, -37, -37, -37, - -37, -37, -37, -37, -37, -37, -37, -37 - }, - - { - 11, -38, -38, -38, -38, -38, -38, -38, -38, -38, - -38, -38, -38, -38, 61, -38, -38, -38 - }, - - { - 11, -39, -39, 62, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39, -39 - - }, - - { - 11, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40, 63 - }, - - { - 11, -41, 41, 42, -41, -41, 43, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41, -41 - }, - - { - 11, -42, -42, -42, -42, -42, -42, -42, -42, -42, - -42, -42, -42, -42, -42, -42, -42, -42 - }, - - { - 11, 44, 44, 45, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44 - }, - - { - 11, 44, 44, 45, 44, 44, 44, 44, 44, 44, - 44, 44, 44, 44, 44, 44, 44, 44 - - }, - - { - 11, -45, -45, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, -45, -45, -45 - }, - - { - 11, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, 46, -46, -46, -46, -46, -46, -46 - }, - - { - 11, 47, 47, -47, 47, 47, 47, 47, 47, 47, - 47, 47, 47, 47, 47, 47, 47, 47 - }, - - { - 11, -48, 48, 49, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48, -48 - }, - - { - 11, 50, -49, -49, 50, 50, 50, 50, 50, 50, - 50, 50, 50, 50, 50, 50, 50, 50 - - }, - - { - 11, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, -50, -50, -50, -50, -50, -50, -50 - }, - - { - 11, 51, 51, 52, 51, -51, 51, 51, -51, 51, - 51, 51, 51, 51, 51, 51, -51, 51 - }, - - { - 11, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, -52, -52 - }, - - { - 11, -53, -53, 54, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53, -53 - }, - - { - 11, -54, -54, -54, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54, -54, -54 - - }, - - { - 11, -55, 55, -55, -55, -55, -55, -55, -55, -55, - -55, -55, -55, -55, -55, -55, -55, -55 - }, - - { - 11, -56, -56, -56, -56, -56, -56, -56, -56, -56, - -56, -56, -56, -56, -56, -56, -56, -56 - }, - - { - 11, 57, 57, -57, 57, 57, 57, 57, 57, 57, - 57, 57, 57, 57, 57, 57, 57, 57 - }, - - { - 11, -58, -58, -58, -58, -58, -58, -58, -58, -58, - -58, -58, -58, -58, -58, -58, -58, -58 - }, - - { - 11, -59, -59, -59, -59, -59, -59, -59, -59, -59, - -59, 59, 59, -59, -59, -59, -59, -59 - - }, - - { - 11, -60, -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -60, -60, -60, -60 - }, - - { - 11, -61, -61, -61, -61, -61, -61, -61, -61, -61, - -61, -61, -61, -61, -61, -61, -61, -61 - }, - - { - 11, -62, -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -62, -62, -62, -62, -62, -62 - }, - - { - 11, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63 - }, - - } ; - -static yy_state_type yy_get_previous_state (void ); -static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); -static int yy_get_next_buffer (void ); -static void yy_fatal_error (yyconst char msg[] ); - -/* Done after the current pattern has been matched and before the - * corresponding action - sets up zconftext. - */ -#define YY_DO_BEFORE_ACTION \ - (yytext_ptr) = yy_bp; \ - zconfleng = (size_t) (yy_cp - yy_bp); \ - (yy_hold_char) = *yy_cp; \ - *yy_cp = '\0'; \ - (yy_c_buf_p) = yy_cp; - -#define YY_NUM_RULES 37 -#define YY_END_OF_BUFFER 38 -/* This struct is not used in this scanner, - but its presence is necessary. */ -struct yy_trans_info - { - flex_int32_t yy_verify; - flex_int32_t yy_nxt; - }; -static yyconst flex_int16_t yy_accept[64] = - { 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 38, 5, 4, 2, 3, 7, 8, 6, 36, 33, - 35, 28, 32, 31, 30, 26, 25, 21, 13, 20, - 23, 26, 11, 12, 22, 18, 14, 19, 26, 26, - 4, 2, 3, 3, 1, 6, 36, 33, 35, 34, - 28, 27, 30, 29, 25, 15, 23, 9, 22, 16, - 17, 24, 10 - } ; - -static yyconst flex_int32_t yy_ec[256] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 2, 4, 5, 6, 1, 1, 7, 8, 9, - 10, 1, 1, 1, 11, 12, 12, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 1, 1, 13, - 14, 15, 1, 1, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 1, 16, 1, 1, 11, 1, 11, 11, 11, 11, - - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 1, 17, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1 - } ; - -extern int zconf_flex_debug; -int zconf_flex_debug = 0; - -/* The intent behind this definition is that it'll catch - * any uses of REJECT which flex missed. - */ -#define REJECT reject_used_but_not_detected -#define yymore() yymore_used_but_not_detected -#define YY_MORE_ADJ 0 -#define YY_RESTORE_YY_MORE_OFFSET -char *zconftext; -#define YY_NO_INPUT 1 - -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#include -#include - -#include "lkc.h" - -#define START_STRSIZE 16 - -static struct { - struct file *file; - int lineno; -} current_pos; - -static char *text; -static int text_size, text_asize; - -struct buffer { - struct buffer *parent; - YY_BUFFER_STATE state; -}; - -struct buffer *current_buf; - -static int last_ts, first_ts; - -static void zconf_endhelp(void); -static void zconf_endfile(void); - -static void new_string(void) -{ - text = xmalloc(START_STRSIZE); - text_asize = START_STRSIZE; - text_size = 0; - *text = 0; -} - -static void append_string(const char *str, int size) -{ - int new_size = text_size + size + 1; - if (new_size > text_asize) { - new_size += START_STRSIZE - 1; - new_size &= -START_STRSIZE; - text = realloc(text, new_size); - text_asize = new_size; - } - memcpy(text + text_size, str, size); - text_size += size; - text[text_size] = 0; -} - -static void alloc_string(const char *str, int size) -{ - text = xmalloc(size + 1); - memcpy(text, str, size); - text[size] = 0; -} - -static void warn_ignored_character(char chr) -{ - fprintf(stderr, - "%s:%d:warning: ignoring unsupported character '%c'\n", - zconf_curname(), zconf_lineno(), chr); -} - -#define INITIAL 0 -#define COMMAND 1 -#define HELP 2 -#define STRING 3 -#define PARAM 4 - -#ifndef YY_NO_UNISTD_H -/* Special case for "unistd.h", since it is non-ANSI. We include it way - * down here because we want the user's section 1 to have been scanned first. - * The user has a chance to override it with an option. - */ -#include -#endif - -#ifndef YY_EXTRA_TYPE -#define YY_EXTRA_TYPE void * -#endif - -static int yy_init_globals (void ); - -/* Accessor methods to globals. - These are made visible to non-reentrant scanners for convenience. */ - -int zconflex_destroy (void ); - -int zconfget_debug (void ); - -void zconfset_debug (int debug_flag ); - -YY_EXTRA_TYPE zconfget_extra (void ); - -void zconfset_extra (YY_EXTRA_TYPE user_defined ); - -FILE *zconfget_in (void ); - -void zconfset_in (FILE * in_str ); - -FILE *zconfget_out (void ); - -void zconfset_out (FILE * out_str ); - -int zconfget_leng (void ); - -char *zconfget_text (void ); - -int zconfget_lineno (void ); - -void zconfset_lineno (int line_number ); - -/* Macros after this point can all be overridden by user definitions in - * section 1. - */ - -#ifndef YY_SKIP_YYWRAP -#ifdef __cplusplus -extern "C" int zconfwrap (void ); -#else -extern int zconfwrap (void ); -#endif -#endif - - static void yyunput (int c,char *buf_ptr ); - -#ifndef yytext_ptr -static void yy_flex_strncpy (char *,yyconst char *,int ); -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * ); -#endif - -#ifndef YY_NO_INPUT - -#ifdef __cplusplus -static int yyinput (void ); -#else -static int input (void ); -#endif - -#endif - -/* Amount of stuff to slurp up with each read. */ -#ifndef YY_READ_BUF_SIZE -#ifdef __ia64__ -/* On IA-64, the buffer size is 16k, not 8k */ -#define YY_READ_BUF_SIZE 16384 -#else -#define YY_READ_BUF_SIZE 8192 -#endif /* __ia64__ */ -#endif - -/* Copy whatever the last rule matched to the standard output. */ -#ifndef ECHO -/* This used to be an fputs(), but since the string might contain NUL's, - * we now use fwrite(). - */ -#define ECHO do { if (fwrite( zconftext, zconfleng, 1, zconfout )) {} } while (0) -#endif - -/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, - * is returned in "result". - */ -#ifndef YY_INPUT -#define YY_INPUT(buf,result,max_size) \ - errno=0; \ - while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \ - { \ - if( errno != EINTR) \ - { \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - break; \ - } \ - errno=0; \ - clearerr(zconfin); \ - }\ -\ - -#endif - -/* No semi-colon after return; correct usage is to write "yyterminate();" - - * we don't want an extra ';' after the "return" because that will cause - * some compilers to complain about unreachable statements. - */ -#ifndef yyterminate -#define yyterminate() return YY_NULL -#endif - -/* Number of entries by which start-condition stack grows. */ -#ifndef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#endif - -/* Report a fatal error. */ -#ifndef YY_FATAL_ERROR -#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) -#endif - -/* end tables serialization structures and prototypes */ - -/* Default declaration of generated scanner - a define so the user can - * easily add parameters. - */ -#ifndef YY_DECL -#define YY_DECL_IS_OURS 1 - -extern int zconflex (void); - -#define YY_DECL int zconflex (void) -#endif /* !YY_DECL */ - -/* Code executed at the beginning of each rule, after zconftext and zconfleng - * have been set up. - */ -#ifndef YY_USER_ACTION -#define YY_USER_ACTION -#endif - -/* Code executed at the end of each rule. */ -#ifndef YY_BREAK -#define YY_BREAK break; -#endif - -#define YY_RULE_SETUP \ - YY_USER_ACTION - -/** The main scanner function which does all the work. - */ -YY_DECL -{ - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; - - int str = 0; - int ts, i; - - if ( !(yy_init) ) - { - (yy_init) = 1; - -#ifdef YY_USER_INIT - YY_USER_INIT; -#endif - - if ( ! (yy_start) ) - (yy_start) = 1; /* first start state */ - - if ( ! zconfin ) - zconfin = stdin; - - if ( ! zconfout ) - zconfout = stdout; - - if ( ! YY_CURRENT_BUFFER ) { - zconfensure_buffer_stack (); - YY_CURRENT_BUFFER_LVALUE = - zconf_create_buffer(zconfin,YY_BUF_SIZE ); - } - - zconf_load_buffer_state( ); - } - - while ( 1 ) /* loops until end-of-file is reached */ - { - yy_cp = (yy_c_buf_p); - - /* Support of zconftext. */ - *yy_cp = (yy_hold_char); - - /* yy_bp points to the position in yy_ch_buf of the start of - * the current run. - */ - yy_bp = yy_cp; - - yy_current_state = (yy_start); -yy_match: - while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)] ]) > 0 ) - ++yy_cp; - - yy_current_state = -yy_current_state; - -yy_find_action: - yy_act = yy_accept[yy_current_state]; - - YY_DO_BEFORE_ACTION; - -do_action: /* This label is used only to access EOF actions. */ - - switch ( yy_act ) - { /* beginning of action switch */ -case 1: -/* rule 1 can match eol */ -case 2: -/* rule 2 can match eol */ -YY_RULE_SETUP -{ - current_file->lineno++; - return T_EOL; -} - YY_BREAK -case 3: -YY_RULE_SETUP - - YY_BREAK -case 4: -YY_RULE_SETUP -{ - BEGIN(COMMAND); -} - YY_BREAK -case 5: -YY_RULE_SETUP -{ - unput(zconftext[0]); - BEGIN(COMMAND); -} - YY_BREAK - -case 6: -YY_RULE_SETUP -{ - const struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng); - BEGIN(PARAM); - current_pos.file = current_file; - current_pos.lineno = current_file->lineno; - if (id && id->flags & TF_COMMAND) { - zconflval.id = id; - return id->token; - } - alloc_string(zconftext, zconfleng); - zconflval.string = text; - return T_WORD; - } - YY_BREAK -case 7: -YY_RULE_SETUP -warn_ignored_character(*zconftext); - YY_BREAK -case 8: -/* rule 8 can match eol */ -YY_RULE_SETUP -{ - BEGIN(INITIAL); - current_file->lineno++; - return T_EOL; - } - YY_BREAK - -case 9: -YY_RULE_SETUP -return T_AND; - YY_BREAK -case 10: -YY_RULE_SETUP -return T_OR; - YY_BREAK -case 11: -YY_RULE_SETUP -return T_OPEN_PAREN; - YY_BREAK -case 12: -YY_RULE_SETUP -return T_CLOSE_PAREN; - YY_BREAK -case 13: -YY_RULE_SETUP -return T_NOT; - YY_BREAK -case 14: -YY_RULE_SETUP -return T_EQUAL; - YY_BREAK -case 15: -YY_RULE_SETUP -return T_UNEQUAL; - YY_BREAK -case 16: -YY_RULE_SETUP -return T_LESS_EQUAL; - YY_BREAK -case 17: -YY_RULE_SETUP -return T_GREATER_EQUAL; - YY_BREAK -case 18: -YY_RULE_SETUP -return T_LESS; - YY_BREAK -case 19: -YY_RULE_SETUP -return T_GREATER; - YY_BREAK -case 20: -YY_RULE_SETUP -{ - str = zconftext[0]; - new_string(); - BEGIN(STRING); - } - YY_BREAK -case 21: -/* rule 21 can match eol */ -YY_RULE_SETUP -BEGIN(INITIAL); current_file->lineno++; return T_EOL; - YY_BREAK -case 22: -YY_RULE_SETUP -{ - const struct kconf_id *id = kconf_id_lookup(zconftext, zconfleng); - if (id && id->flags & TF_PARAM) { - zconflval.id = id; - return id->token; - } - alloc_string(zconftext, zconfleng); - zconflval.string = text; - return T_WORD; - } - YY_BREAK -case 23: -YY_RULE_SETUP -/* comment */ - YY_BREAK -case 24: -/* rule 24 can match eol */ -YY_RULE_SETUP -current_file->lineno++; - YY_BREAK -case 25: -YY_RULE_SETUP - - YY_BREAK -case 26: -YY_RULE_SETUP -warn_ignored_character(*zconftext); - YY_BREAK -case YY_STATE_EOF(PARAM): -{ - BEGIN(INITIAL); - } - YY_BREAK - -case 27: -/* rule 27 can match eol */ -*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ -(yy_c_buf_p) = yy_cp -= 1; -YY_DO_BEFORE_ACTION; /* set up zconftext again */ -YY_RULE_SETUP -{ - append_string(zconftext, zconfleng); - zconflval.string = text; - return T_WORD_QUOTE; - } - YY_BREAK -case 28: -YY_RULE_SETUP -{ - append_string(zconftext, zconfleng); - } - YY_BREAK -case 29: -/* rule 29 can match eol */ -*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ -(yy_c_buf_p) = yy_cp -= 1; -YY_DO_BEFORE_ACTION; /* set up zconftext again */ -YY_RULE_SETUP -{ - append_string(zconftext + 1, zconfleng - 1); - zconflval.string = text; - return T_WORD_QUOTE; - } - YY_BREAK -case 30: -YY_RULE_SETUP -{ - append_string(zconftext + 1, zconfleng - 1); - } - YY_BREAK -case 31: -YY_RULE_SETUP -{ - if (str == zconftext[0]) { - BEGIN(PARAM); - zconflval.string = text; - return T_WORD_QUOTE; - } else - append_string(zconftext, 1); - } - YY_BREAK -case 32: -/* rule 32 can match eol */ -YY_RULE_SETUP -{ - printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno()); - current_file->lineno++; - BEGIN(INITIAL); - return T_EOL; - } - YY_BREAK -case YY_STATE_EOF(STRING): -{ - BEGIN(INITIAL); - } - YY_BREAK - -case 33: -YY_RULE_SETUP -{ - ts = 0; - for (i = 0; i < zconfleng; i++) { - if (zconftext[i] == '\t') - ts = (ts & ~7) + 8; - else - ts++; - } - last_ts = ts; - if (first_ts) { - if (ts < first_ts) { - zconf_endhelp(); - return T_HELPTEXT; - } - ts -= first_ts; - while (ts > 8) { - append_string(" ", 8); - ts -= 8; - } - append_string(" ", ts); - } - } - YY_BREAK -case 34: -/* rule 34 can match eol */ -*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ -(yy_c_buf_p) = yy_cp -= 1; -YY_DO_BEFORE_ACTION; /* set up zconftext again */ -YY_RULE_SETUP -{ - current_file->lineno++; - zconf_endhelp(); - return T_HELPTEXT; - } - YY_BREAK -case 35: -/* rule 35 can match eol */ -YY_RULE_SETUP -{ - current_file->lineno++; - append_string("\n", 1); - } - YY_BREAK -case 36: -YY_RULE_SETUP -{ - while (zconfleng) { - if ((zconftext[zconfleng-1] != ' ') && (zconftext[zconfleng-1] != '\t')) - break; - zconfleng--; - } - append_string(zconftext, zconfleng); - if (!first_ts) - first_ts = last_ts; - } - YY_BREAK -case YY_STATE_EOF(HELP): -{ - zconf_endhelp(); - return T_HELPTEXT; - } - YY_BREAK - -case YY_STATE_EOF(INITIAL): -case YY_STATE_EOF(COMMAND): -{ - if (current_file) { - zconf_endfile(); - return T_EOL; - } - fclose(zconfin); - yyterminate(); -} - YY_BREAK -case 37: -YY_RULE_SETUP -YY_FATAL_ERROR( "flex scanner jammed" ); - YY_BREAK - - case YY_END_OF_BUFFER: - { - /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; - - /* Undo the effects of YY_DO_BEFORE_ACTION. */ - *yy_cp = (yy_hold_char); - YY_RESTORE_YY_MORE_OFFSET - - if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) - { - /* We're scanning a new file or input source. It's - * possible that this happened because the user - * just pointed zconfin at a new source and called - * zconflex(). If so, then we have to assure - * consistency between YY_CURRENT_BUFFER and our - * globals. Here is the right place to do so, because - * this is the first action (other than possibly a - * back-up) that will match for the new input source. - */ - (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; - YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin; - YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; - } - - /* Note that here we test for yy_c_buf_p "<=" to the position - * of the first EOB in the buffer, since yy_c_buf_p will - * already have been incremented past the NUL character - * (since all states make transitions on EOB to the - * end-of-buffer state). Contrast this with the test - * in input(). - */ - if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) - { /* This was really a NUL. */ - yy_state_type yy_next_state; - - (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state( ); - - /* Okay, we're now positioned to make the NUL - * transition. We couldn't have - * yy_get_previous_state() go ahead and do it - * for us because it doesn't know how to deal - * with the possibility of jamming (and we don't - * want to build jamming into it because then it - * will run more slowly). - */ - - yy_next_state = yy_try_NUL_trans( yy_current_state ); - - yy_bp = (yytext_ptr) + YY_MORE_ADJ; - - if ( yy_next_state ) - { - /* Consume the NUL. */ - yy_cp = ++(yy_c_buf_p); - yy_current_state = yy_next_state; - goto yy_match; - } - - else - { - yy_cp = (yy_c_buf_p); - goto yy_find_action; - } - } - - else switch ( yy_get_next_buffer( ) ) - { - case EOB_ACT_END_OF_FILE: - { - (yy_did_buffer_switch_on_eof) = 0; - - if ( zconfwrap( ) ) - { - /* Note: because we've taken care in - * yy_get_next_buffer() to have set up - * zconftext, we can now set up - * yy_c_buf_p so that if some total - * hoser (like flex itself) wants to - * call the scanner after we return the - * YY_NULL, it'll still work - another - * YY_NULL will get returned. - */ - (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; - - yy_act = YY_STATE_EOF(YY_START); - goto do_action; - } - - else - { - if ( ! (yy_did_buffer_switch_on_eof) ) - YY_NEW_FILE; - } - break; - } - - case EOB_ACT_CONTINUE_SCAN: - (yy_c_buf_p) = - (yytext_ptr) + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state( ); - - yy_cp = (yy_c_buf_p); - yy_bp = (yytext_ptr) + YY_MORE_ADJ; - goto yy_match; - - case EOB_ACT_LAST_MATCH: - (yy_c_buf_p) = - &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; - - yy_current_state = yy_get_previous_state( ); - - yy_cp = (yy_c_buf_p); - yy_bp = (yytext_ptr) + YY_MORE_ADJ; - goto yy_find_action; - } - break; - } - - default: - YY_FATAL_ERROR( - "fatal flex scanner internal error--no action found" ); - } /* end of action switch */ - } /* end of scanning one token */ -} /* end of zconflex */ - -/* yy_get_next_buffer - try to read in a new buffer - * - * Returns a code representing an action: - * EOB_ACT_LAST_MATCH - - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position - * EOB_ACT_END_OF_FILE - end of file - */ -static int yy_get_next_buffer (void) -{ - register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; - register char *source = (yytext_ptr); - register int number_to_move, i; - int ret_val; - - if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) - YY_FATAL_ERROR( - "fatal flex scanner internal error--end of buffer missed" ); - - if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) - { /* Don't try to fill the buffer, so this is an EOF. */ - if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) - { - /* We matched a single character, the EOB, so - * treat this as a final EOF. - */ - return EOB_ACT_END_OF_FILE; - } - - else - { - /* We matched some text prior to the EOB, first - * process it. - */ - return EOB_ACT_LAST_MATCH; - } - } - - /* Try to read more data. */ - - /* First move last chars to start of buffer. */ - number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; - - for ( i = 0; i < number_to_move; ++i ) - *(dest++) = *(source++); - - if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) - /* don't do the read, it's not guaranteed to return an EOF, - * just force an EOF - */ - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; - - else - { - int num_to_read = - YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; - - while ( num_to_read <= 0 ) - { /* Not enough room in the buffer - grow it. */ - - /* just a shorter name for the current buffer */ - YY_BUFFER_STATE b = YY_CURRENT_BUFFER; - - int yy_c_buf_p_offset = - (int) ((yy_c_buf_p) - b->yy_ch_buf); - - if ( b->yy_is_our_buffer ) - { - int new_size = b->yy_buf_size * 2; - - if ( new_size <= 0 ) - b->yy_buf_size += b->yy_buf_size / 8; - else - b->yy_buf_size *= 2; - - b->yy_ch_buf = (char *) - /* Include room in for 2 EOB chars. */ - zconfrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); - } - else - /* Can't grow it, we don't own it. */ - b->yy_ch_buf = 0; - - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( - "fatal error - scanner input buffer overflow" ); - - (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; - - num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - - number_to_move - 1; - - } - - if ( num_to_read > YY_READ_BUF_SIZE ) - num_to_read = YY_READ_BUF_SIZE; - - /* Read in more data. */ - YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), - (yy_n_chars), (size_t) num_to_read ); - - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); - } - - if ( (yy_n_chars) == 0 ) - { - if ( number_to_move == YY_MORE_ADJ ) - { - ret_val = EOB_ACT_END_OF_FILE; - zconfrestart(zconfin ); - } - - else - { - ret_val = EOB_ACT_LAST_MATCH; - YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = - YY_BUFFER_EOF_PENDING; - } - } - - else - ret_val = EOB_ACT_CONTINUE_SCAN; - - if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { - /* Extend the array by 50%, plus the number we really need. */ - yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) zconfrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); - if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); - } - - (yy_n_chars) += number_to_move; - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; - YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; - - (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; - - return ret_val; -} - -/* yy_get_previous_state - get the state just before the EOB char was reached */ - - static yy_state_type yy_get_previous_state (void) -{ - register yy_state_type yy_current_state; - register char *yy_cp; - - yy_current_state = (yy_start); - - for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) - { - yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)]; - } - - return yy_current_state; -} - -/* yy_try_NUL_trans - try to make a transition on the NUL character - * - * synopsis - * next_state = yy_try_NUL_trans( current_state ); - */ - static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) -{ - register int yy_is_jam; - - yy_current_state = yy_nxt[yy_current_state][1]; - yy_is_jam = (yy_current_state <= 0); - - return yy_is_jam ? 0 : yy_current_state; -} - - static void yyunput (int c, register char * yy_bp ) -{ - register char *yy_cp; - - yy_cp = (yy_c_buf_p); - - /* undo effects of setting up zconftext */ - *yy_cp = (yy_hold_char); - - if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) - { /* need to shift things up to make room */ - /* +2 for EOB chars. */ - register int number_to_move = (yy_n_chars) + 2; - register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ - YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; - register char *source = - &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; - - while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) - *--dest = *--source; - - yy_cp += (int) (dest - source); - yy_bp += (int) (dest - source); - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = - (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; - - if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) - YY_FATAL_ERROR( "flex scanner push-back overflow" ); - } - - *--yy_cp = (char) c; - - (yytext_ptr) = yy_bp; - (yy_hold_char) = *yy_cp; - (yy_c_buf_p) = yy_cp; -} - -#ifndef YY_NO_INPUT -#ifdef __cplusplus - static int yyinput (void) -#else - static int input (void) -#endif - -{ - int c; - - *(yy_c_buf_p) = (yy_hold_char); - - if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) - { - /* yy_c_buf_p now points to the character we want to return. - * If this occurs *before* the EOB characters, then it's a - * valid NUL; if not, then we've hit the end of the buffer. - */ - if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) - /* This was really a NUL. */ - *(yy_c_buf_p) = '\0'; - - else - { /* need more input */ - int offset = (yy_c_buf_p) - (yytext_ptr); - ++(yy_c_buf_p); - - switch ( yy_get_next_buffer( ) ) - { - case EOB_ACT_LAST_MATCH: - /* This happens because yy_g_n_b() - * sees that we've accumulated a - * token and flags that we need to - * try matching the token before - * proceeding. But for input(), - * there's no matching to consider. - * So convert the EOB_ACT_LAST_MATCH - * to EOB_ACT_END_OF_FILE. - */ - - /* Reset buffer status. */ - zconfrestart(zconfin ); - - /*FALLTHROUGH*/ - - case EOB_ACT_END_OF_FILE: - { - if ( zconfwrap( ) ) - return EOF; - - if ( ! (yy_did_buffer_switch_on_eof) ) - YY_NEW_FILE; -#ifdef __cplusplus - return yyinput(); -#else - return input(); -#endif - } - - case EOB_ACT_CONTINUE_SCAN: - (yy_c_buf_p) = (yytext_ptr) + offset; - break; - } - } - } - - c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ - *(yy_c_buf_p) = '\0'; /* preserve zconftext */ - (yy_hold_char) = *++(yy_c_buf_p); - - return c; -} -#endif /* ifndef YY_NO_INPUT */ - -/** Immediately switch to a different input stream. - * @param input_file A readable stream. - * - * @note This function does not reset the start condition to @c INITIAL . - */ - void zconfrestart (FILE * input_file ) -{ - - if ( ! YY_CURRENT_BUFFER ){ - zconfensure_buffer_stack (); - YY_CURRENT_BUFFER_LVALUE = - zconf_create_buffer(zconfin,YY_BUF_SIZE ); - } - - zconf_init_buffer(YY_CURRENT_BUFFER,input_file ); - zconf_load_buffer_state( ); -} - -/** Switch to a different input buffer. - * @param new_buffer The new input buffer. - * - */ - void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer ) -{ - - /* TODO. We should be able to replace this entire function body - * with - * zconfpop_buffer_state(); - * zconfpush_buffer_state(new_buffer); - */ - zconfensure_buffer_stack (); - if ( YY_CURRENT_BUFFER == new_buffer ) - return; - - if ( YY_CURRENT_BUFFER ) - { - /* Flush out information for old buffer. */ - *(yy_c_buf_p) = (yy_hold_char); - YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); - } - - YY_CURRENT_BUFFER_LVALUE = new_buffer; - zconf_load_buffer_state( ); - - /* We don't actually know whether we did this switch during - * EOF (zconfwrap()) processing, but the only time this flag - * is looked at is after zconfwrap() is called, so it's safe - * to go ahead and always set it. - */ - (yy_did_buffer_switch_on_eof) = 1; -} - -static void zconf_load_buffer_state (void) -{ - (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; - (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; - zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; - (yy_hold_char) = *(yy_c_buf_p); -} - -/** Allocate and initialize an input buffer state. - * @param file A readable stream. - * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. - * - * @return the allocated buffer state. - */ - YY_BUFFER_STATE zconf_create_buffer (FILE * file, int size ) -{ - YY_BUFFER_STATE b; - - b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" ); - - b->yy_buf_size = size; - - /* yy_ch_buf has to be 2 characters longer than the size given because - * we need to put in 2 end-of-buffer characters. - */ - b->yy_ch_buf = (char *) zconfalloc(b->yy_buf_size + 2 ); - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" ); - - b->yy_is_our_buffer = 1; - - zconf_init_buffer(b,file ); - - return b; -} - -/** Destroy the buffer. - * @param b a buffer created with zconf_create_buffer() - * - */ - void zconf_delete_buffer (YY_BUFFER_STATE b ) -{ - - if ( ! b ) - return; - - if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ - YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; - - if ( b->yy_is_our_buffer ) - zconffree((void *) b->yy_ch_buf ); - - zconffree((void *) b ); -} - -/* Initializes or reinitializes a buffer. - * This function is sometimes called more than once on the same buffer, - * such as during a zconfrestart() or at EOF. - */ - static void zconf_init_buffer (YY_BUFFER_STATE b, FILE * file ) - -{ - int oerrno = errno; - - zconf_flush_buffer(b ); - - b->yy_input_file = file; - b->yy_fill_buffer = 1; - - /* If b is the current buffer, then zconf_init_buffer was _probably_ - * called from zconfrestart() or through yy_get_next_buffer. - * In that case, we don't want to reset the lineno or column. - */ - if (b != YY_CURRENT_BUFFER){ - b->yy_bs_lineno = 1; - b->yy_bs_column = 0; - } - - b->yy_is_interactive = 0; - - errno = oerrno; -} - -/** Discard all buffered characters. On the next scan, YY_INPUT will be called. - * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. - * - */ - void zconf_flush_buffer (YY_BUFFER_STATE b ) -{ - if ( ! b ) - return; - - b->yy_n_chars = 0; - - /* We always need two end-of-buffer characters. The first causes - * a transition to the end-of-buffer state. The second causes - * a jam in that state. - */ - b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; - b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; - - b->yy_buf_pos = &b->yy_ch_buf[0]; - - b->yy_at_bol = 1; - b->yy_buffer_status = YY_BUFFER_NEW; - - if ( b == YY_CURRENT_BUFFER ) - zconf_load_buffer_state( ); -} - -/** Pushes the new state onto the stack. The new state becomes - * the current state. This function will allocate the stack - * if necessary. - * @param new_buffer The new state. - * - */ -void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer ) -{ - if (new_buffer == NULL) - return; - - zconfensure_buffer_stack(); - - /* This block is copied from zconf_switch_to_buffer. */ - if ( YY_CURRENT_BUFFER ) - { - /* Flush out information for old buffer. */ - *(yy_c_buf_p) = (yy_hold_char); - YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); - YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); - } - - /* Only push if top exists. Otherwise, replace top. */ - if (YY_CURRENT_BUFFER) - (yy_buffer_stack_top)++; - YY_CURRENT_BUFFER_LVALUE = new_buffer; - - /* copied from zconf_switch_to_buffer. */ - zconf_load_buffer_state( ); - (yy_did_buffer_switch_on_eof) = 1; -} - -/** Removes and deletes the top of the stack, if present. - * The next element becomes the new top. - * - */ -void zconfpop_buffer_state (void) -{ - if (!YY_CURRENT_BUFFER) - return; - - zconf_delete_buffer(YY_CURRENT_BUFFER ); - YY_CURRENT_BUFFER_LVALUE = NULL; - if ((yy_buffer_stack_top) > 0) - --(yy_buffer_stack_top); - - if (YY_CURRENT_BUFFER) { - zconf_load_buffer_state( ); - (yy_did_buffer_switch_on_eof) = 1; - } -} - -/* Allocates the stack if it does not exist. - * Guarantees space for at least one push. - */ -static void zconfensure_buffer_stack (void) -{ - int num_to_alloc; - - if (!(yy_buffer_stack)) { - - /* First allocation is just for 2 elements, since we don't know if this - * scanner will even need a stack. We use 2 instead of 1 to avoid an - * immediate realloc on the next call. - */ - num_to_alloc = 1; - (yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc - (num_to_alloc * sizeof(struct yy_buffer_state*) - ); - if ( ! (yy_buffer_stack) ) - YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" ); - - memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); - - (yy_buffer_stack_max) = num_to_alloc; - (yy_buffer_stack_top) = 0; - return; - } - - if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ - - /* Increase the buffer to prepare for a possible push. */ - int grow_size = 8 /* arbitrary grow size */; - - num_to_alloc = (yy_buffer_stack_max) + grow_size; - (yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc - ((yy_buffer_stack), - num_to_alloc * sizeof(struct yy_buffer_state*) - ); - if ( ! (yy_buffer_stack) ) - YY_FATAL_ERROR( "out of dynamic memory in zconfensure_buffer_stack()" ); - - /* zero only the new slots.*/ - memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); - (yy_buffer_stack_max) = num_to_alloc; - } -} - -/** Setup the input buffer state to scan directly from a user-specified character buffer. - * @param base the character buffer - * @param size the size in bytes of the character buffer - * - * @return the newly allocated buffer state object. - */ -YY_BUFFER_STATE zconf_scan_buffer (char * base, yy_size_t size ) -{ - YY_BUFFER_STATE b; - - if ( size < 2 || - base[size-2] != YY_END_OF_BUFFER_CHAR || - base[size-1] != YY_END_OF_BUFFER_CHAR ) - /* They forgot to leave room for the EOB's. */ - return 0; - - b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_buffer()" ); - - b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ - b->yy_buf_pos = b->yy_ch_buf = base; - b->yy_is_our_buffer = 0; - b->yy_input_file = 0; - b->yy_n_chars = b->yy_buf_size; - b->yy_is_interactive = 0; - b->yy_at_bol = 1; - b->yy_fill_buffer = 0; - b->yy_buffer_status = YY_BUFFER_NEW; - - zconf_switch_to_buffer(b ); - - return b; -} - -/** Setup the input buffer state to scan a string. The next call to zconflex() will - * scan from a @e copy of @a str. - * @param yystr a NUL-terminated string to scan - * - * @return the newly allocated buffer state object. - * @note If you want to scan bytes that may contain NUL values, then use - * zconf_scan_bytes() instead. - */ -YY_BUFFER_STATE zconf_scan_string (yyconst char * yystr ) -{ - - return zconf_scan_bytes(yystr,strlen(yystr) ); -} - -/** Setup the input buffer state to scan the given bytes. The next call to zconflex() will - * scan from a @e copy of @a bytes. - * @param yybytes the byte buffer to scan - * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. - * - * @return the newly allocated buffer state object. - */ -YY_BUFFER_STATE zconf_scan_bytes (yyconst char * yybytes, int _yybytes_len ) -{ - YY_BUFFER_STATE b; - char *buf; - yy_size_t n; - int i; - - /* Get memory for full buffer, including space for trailing EOB's. */ - n = _yybytes_len + 2; - buf = (char *) zconfalloc(n ); - if ( ! buf ) - YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" ); - - for ( i = 0; i < _yybytes_len; ++i ) - buf[i] = yybytes[i]; - - buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; - - b = zconf_scan_buffer(buf,n ); - if ( ! b ) - YY_FATAL_ERROR( "bad buffer in zconf_scan_bytes()" ); - - /* It's okay to grow etc. this buffer, and we should throw it - * away when we're done. - */ - b->yy_is_our_buffer = 1; - - return b; -} - -#ifndef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#endif - -static void yy_fatal_error (yyconst char* msg ) -{ - (void) fprintf( stderr, "%s\n", msg ); - exit( YY_EXIT_FAILURE ); -} - -/* Redefine yyless() so it works in section 3 code. */ - -#undef yyless -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up zconftext. */ \ - int yyless_macro_arg = (n); \ - YY_LESS_LINENO(yyless_macro_arg);\ - zconftext[zconfleng] = (yy_hold_char); \ - (yy_c_buf_p) = zconftext + yyless_macro_arg; \ - (yy_hold_char) = *(yy_c_buf_p); \ - *(yy_c_buf_p) = '\0'; \ - zconfleng = yyless_macro_arg; \ - } \ - while ( 0 ) - -/* Accessor methods (get/set functions) to struct members. */ - -/** Get the current line number. - * - */ -int zconfget_lineno (void) -{ - - return zconflineno; -} - -/** Get the input stream. - * - */ -FILE *zconfget_in (void) -{ - return zconfin; -} - -/** Get the output stream. - * - */ -FILE *zconfget_out (void) -{ - return zconfout; -} - -/** Get the length of the current token. - * - */ -int zconfget_leng (void) -{ - return zconfleng; -} - -/** Get the current token. - * - */ - -char *zconfget_text (void) -{ - return zconftext; -} - -/** Set the current line number. - * @param line_number - * - */ -void zconfset_lineno (int line_number ) -{ - - zconflineno = line_number; -} - -/** Set the input stream. This does not discard the current - * input buffer. - * @param in_str A readable stream. - * - * @see zconf_switch_to_buffer - */ -void zconfset_in (FILE * in_str ) -{ - zconfin = in_str ; -} - -void zconfset_out (FILE * out_str ) -{ - zconfout = out_str ; -} - -int zconfget_debug (void) -{ - return zconf_flex_debug; -} - -void zconfset_debug (int bdebug ) -{ - zconf_flex_debug = bdebug ; -} - -static int yy_init_globals (void) -{ - /* Initialization is the same as for the non-reentrant scanner. - * This function is called from zconflex_destroy(), so don't allocate here. - */ - - (yy_buffer_stack) = 0; - (yy_buffer_stack_top) = 0; - (yy_buffer_stack_max) = 0; - (yy_c_buf_p) = (char *) 0; - (yy_init) = 0; - (yy_start) = 0; - -/* Defined in main.c */ -#ifdef YY_STDINIT - zconfin = stdin; - zconfout = stdout; -#else - zconfin = (FILE *) 0; - zconfout = (FILE *) 0; -#endif - - /* For future reference: Set errno on error, since we are called by - * zconflex_init() - */ - return 0; -} - -/* zconflex_destroy is for both reentrant and non-reentrant scanners. */ -int zconflex_destroy (void) -{ - - /* Pop the buffer stack, destroying each element. */ - while(YY_CURRENT_BUFFER){ - zconf_delete_buffer(YY_CURRENT_BUFFER ); - YY_CURRENT_BUFFER_LVALUE = NULL; - zconfpop_buffer_state(); - } - - /* Destroy the stack itself. */ - zconffree((yy_buffer_stack) ); - (yy_buffer_stack) = NULL; - - /* Reset the globals. This is important in a non-reentrant scanner so the next time - * zconflex() is called, initialization will occur. */ - yy_init_globals( ); - - return 0; -} - -/* - * Internal utility routines. - */ - -#ifndef yytext_ptr -static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) -{ - register int i; - for ( i = 0; i < n; ++i ) - s1[i] = s2[i]; -} -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen (yyconst char * s ) -{ - register int n; - for ( n = 0; s[n]; ++n ) - ; - - return n; -} -#endif - -void *zconfalloc (yy_size_t size ) -{ - return (void *) malloc( size ); -} - -void *zconfrealloc (void * ptr, yy_size_t size ) -{ - /* The cast to (char *) in the following accommodates both - * implementations that use char* generic pointers, and those - * that use void* generic pointers. It works with the latter - * because both ANSI C and C++ allow castless assignment from - * any pointer type to void*, and deal with argument conversions - * as though doing an assignment. - */ - return (void *) realloc( (char *) ptr, size ); -} - -void zconffree (void * ptr ) -{ - free( (char *) ptr ); /* see zconfrealloc() for (char *) cast */ -} - -#define YYTABLES_NAME "yytables" - -void zconf_starthelp(void) -{ - new_string(); - last_ts = first_ts = 0; - BEGIN(HELP); -} - -static void zconf_endhelp(void) -{ - zconflval.string = text; - BEGIN(INITIAL); -} - -/* - * Try to open specified file with following names: - * ./name - * $(srctree)/name - * The latter is used when srctree is separate from objtree - * when compiling the kernel. - * Return NULL if file is not found. - */ -FILE *zconf_fopen(const char *name) -{ - char *env, fullname[PATH_MAX+1]; - FILE *f; - - f = fopen(name, "r"); - if (!f && name != NULL && name[0] != '/') { - env = getenv(SRCTREE); - if (env) { - sprintf(fullname, "%s/%s", env, name); - f = fopen(fullname, "r"); - } - } - return f; -} - -void zconf_initscan(const char *name) -{ - zconfin = zconf_fopen(name); - if (!zconfin) { - printf("can't find file %s\n", name); - exit(1); - } - - current_buf = xmalloc(sizeof(*current_buf)); - memset(current_buf, 0, sizeof(*current_buf)); - - current_file = file_lookup(name); - current_file->lineno = 1; -} - -void zconf_nextfile(const char *name) -{ - struct file *iter; - struct file *file = file_lookup(name); - struct buffer *buf = xmalloc(sizeof(*buf)); - memset(buf, 0, sizeof(*buf)); - - current_buf->state = YY_CURRENT_BUFFER; - zconfin = zconf_fopen(file->name); - if (!zconfin) { - printf("%s:%d: can't open file \"%s\"\n", - zconf_curname(), zconf_lineno(), file->name); - exit(1); - } - zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE)); - buf->parent = current_buf; - current_buf = buf; - - for (iter = current_file->parent; iter; iter = iter->parent ) { - if (!strcmp(current_file->name,iter->name) ) { - printf("%s:%d: recursive inclusion detected. " - "Inclusion path:\n current file : '%s'\n", - zconf_curname(), zconf_lineno(), - zconf_curname()); - iter = current_file->parent; - while (iter && \ - strcmp(iter->name,current_file->name)) { - printf(" included from: '%s:%d'\n", - iter->name, iter->lineno-1); - iter = iter->parent; - } - if (iter) - printf(" included from: '%s:%d'\n", - iter->name, iter->lineno+1); - exit(1); - } - } - file->lineno = 1; - file->parent = current_file; - current_file = file; -} - -static void zconf_endfile(void) -{ - struct buffer *parent; - - current_file = current_file->parent; - - parent = current_buf->parent; - if (parent) { - fclose(zconfin); - zconf_delete_buffer(YY_CURRENT_BUFFER); - zconf_switch_to_buffer(parent->state); - } - free(current_buf); - current_buf = parent; -} - -int zconf_lineno(void) -{ - return current_pos.lineno; -} - -const char *zconf_curname(void) -{ - return current_pos.file ? current_pos.file->name : ""; -} - diff --git a/src/linux/scripts/kconfig/zconf.tab.c_shipped b/src/linux/scripts/kconfig/zconf.tab.c_shipped deleted file mode 100644 index 7a4d658..0000000 --- a/src/linux/scripts/kconfig/zconf.tab.c_shipped +++ /dev/null @@ -1,2580 +0,0 @@ -/* A Bison parser, made by GNU Bison 2.5.1. */ - -/* Bison implementation for Yacc-like parsers in C - - Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc. - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . */ - -/* As a special exception, you may create a larger work that contains - part or all of the Bison parser skeleton and distribute that work - under terms of your choice, so long as that work isn't itself a - parser generator using the skeleton or a modified version thereof - as a parser skeleton. Alternatively, if you modify or redistribute - the parser skeleton itself, you may (at your option) remove this - special exception, which will cause the skeleton and the resulting - Bison output files to be licensed under the GNU General Public - License without this special exception. - - This special exception was added by the Free Software Foundation in - version 2.2 of Bison. */ - -/* C LALR(1) parser skeleton written by Richard Stallman, by - simplifying the original so-called "semantic" parser. */ - -/* All symbols defined below should begin with yy or YY, to avoid - infringing on user name space. This should be done even for local - variables, as they might otherwise be expanded by user macros. - There are some unavoidable exceptions within include files to - define necessary library symbols; they are noted "INFRINGES ON - USER NAME SPACE" below. */ - -/* Identify Bison output. */ -#define YYBISON 1 - -/* Bison version. */ -#define YYBISON_VERSION "2.5.1" - -/* Skeleton name. */ -#define YYSKELETON_NAME "yacc.c" - -/* Pure parsers. */ -#define YYPURE 0 - -/* Push parsers. */ -#define YYPUSH 0 - -/* Pull parsers. */ -#define YYPULL 1 - -/* Using locations. */ -#define YYLSP_NEEDED 0 - -/* Substitute the variable and function names. */ -#define yyparse zconfparse -#define yylex zconflex -#define yyerror zconferror -#define yylval zconflval -#define yychar zconfchar -#define yydebug zconfdebug -#define yynerrs zconfnerrs - - -/* Copy the first part of user declarations. */ - - -/* - * Copyright (C) 2002 Roman Zippel - * Released under the terms of the GNU GPL v2.0. - */ - -#include -#include -#include -#include -#include -#include - -#include "lkc.h" - -#define printd(mask, fmt...) if (cdebug & (mask)) printf(fmt) - -#define PRINTD 0x0001 -#define DEBUG_PARSE 0x0002 - -int cdebug = PRINTD; - -extern int zconflex(void); -static void zconfprint(const char *err, ...); -static void zconf_error(const char *err, ...); -static void zconferror(const char *err); -static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken); - -struct symbol *symbol_hash[SYMBOL_HASHSIZE]; - -static struct menu *current_menu, *current_entry; - - - - -# ifndef YY_NULL -# if defined __cplusplus && 201103L <= __cplusplus -# define YY_NULL nullptr -# else -# define YY_NULL 0 -# endif -# endif - -/* Enabling traces. */ -#ifndef YYDEBUG -# define YYDEBUG 1 -#endif - -/* Enabling verbose error messages. */ -#ifdef YYERROR_VERBOSE -# undef YYERROR_VERBOSE -# define YYERROR_VERBOSE 1 -#else -# define YYERROR_VERBOSE 0 -#endif - -/* Enabling the token table. */ -#ifndef YYTOKEN_TABLE -# define YYTOKEN_TABLE 0 -#endif - - -/* Tokens. */ -#ifndef YYTOKENTYPE -# define YYTOKENTYPE - /* Put the tokens into the symbol table, so that GDB and other debuggers - know about them. */ - enum yytokentype { - T_MAINMENU = 258, - T_MENU = 259, - T_ENDMENU = 260, - T_SOURCE = 261, - T_CHOICE = 262, - T_ENDCHOICE = 263, - T_COMMENT = 264, - T_CONFIG = 265, - T_MENUCONFIG = 266, - T_HELP = 267, - T_HELPTEXT = 268, - T_IF = 269, - T_ENDIF = 270, - T_DEPENDS = 271, - T_OPTIONAL = 272, - T_PROMPT = 273, - T_TYPE = 274, - T_DEFAULT = 275, - T_SELECT = 276, - T_RANGE = 277, - T_VISIBLE = 278, - T_OPTION = 279, - T_ON = 280, - T_WORD = 281, - T_WORD_QUOTE = 282, - T_UNEQUAL = 283, - T_LESS = 284, - T_LESS_EQUAL = 285, - T_GREATER = 286, - T_GREATER_EQUAL = 287, - T_CLOSE_PAREN = 288, - T_OPEN_PAREN = 289, - T_EOL = 290, - T_OR = 291, - T_AND = 292, - T_EQUAL = 293, - T_NOT = 294 - }; -#endif - - - -#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED -typedef union YYSTYPE -{ - - - char *string; - struct file *file; - struct symbol *symbol; - struct expr *expr; - struct menu *menu; - const struct kconf_id *id; - - - -} YYSTYPE; -# define YYSTYPE_IS_TRIVIAL 1 -# define yystype YYSTYPE /* obsolescent; will be withdrawn */ -# define YYSTYPE_IS_DECLARED 1 -#endif - - -/* Copy the second part of user declarations. */ - - -/* Include zconf.hash.c here so it can see the token constants. */ -#include "zconf.hash.c" - - - -#ifdef short -# undef short -#endif - -#ifdef YYTYPE_UINT8 -typedef YYTYPE_UINT8 yytype_uint8; -#else -typedef unsigned char yytype_uint8; -#endif - -#ifdef YYTYPE_INT8 -typedef YYTYPE_INT8 yytype_int8; -#elif (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -typedef signed char yytype_int8; -#else -typedef short int yytype_int8; -#endif - -#ifdef YYTYPE_UINT16 -typedef YYTYPE_UINT16 yytype_uint16; -#else -typedef unsigned short int yytype_uint16; -#endif - -#ifdef YYTYPE_INT16 -typedef YYTYPE_INT16 yytype_int16; -#else -typedef short int yytype_int16; -#endif - -#ifndef YYSIZE_T -# ifdef __SIZE_TYPE__ -# define YYSIZE_T __SIZE_TYPE__ -# elif defined size_t -# define YYSIZE_T size_t -# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -# include /* INFRINGES ON USER NAME SPACE */ -# define YYSIZE_T size_t -# else -# define YYSIZE_T unsigned int -# endif -#endif - -#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) - -#ifndef YY_ -# if defined YYENABLE_NLS && YYENABLE_NLS -# if ENABLE_NLS -# include /* INFRINGES ON USER NAME SPACE */ -# define YY_(msgid) dgettext ("bison-runtime", msgid) -# endif -# endif -# ifndef YY_ -# define YY_(msgid) msgid -# endif -#endif - -/* Suppress unused-variable warnings by "using" E. */ -#if ! defined lint || defined __GNUC__ -# define YYUSE(e) ((void) (e)) -#else -# define YYUSE(e) /* empty */ -#endif - -/* Identity function, used to suppress warnings about constant conditions. */ -#ifndef lint -# define YYID(n) (n) -#else -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static int -YYID (int yyi) -#else -static int -YYID (yyi) - int yyi; -#endif -{ - return yyi; -} -#endif - -#if ! defined yyoverflow || YYERROR_VERBOSE - -/* The parser invokes alloca or malloc; define the necessary symbols. */ - -# ifdef YYSTACK_USE_ALLOCA -# if YYSTACK_USE_ALLOCA -# ifdef __GNUC__ -# define YYSTACK_ALLOC __builtin_alloca -# elif defined __BUILTIN_VA_ARG_INCR -# include /* INFRINGES ON USER NAME SPACE */ -# elif defined _AIX -# define YYSTACK_ALLOC __alloca -# elif defined _MSC_VER -# include /* INFRINGES ON USER NAME SPACE */ -# define alloca _alloca -# else -# define YYSTACK_ALLOC alloca -# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -# include /* INFRINGES ON USER NAME SPACE */ - /* Use EXIT_SUCCESS as a witness for stdlib.h. */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -# endif -# endif -# endif -# endif -# endif - -# ifdef YYSTACK_ALLOC - /* Pacify GCC's `empty if-body' warning. */ -# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) -# ifndef YYSTACK_ALLOC_MAXIMUM - /* The OS might guarantee only one guard page at the bottom of the stack, - and a page size can be as small as 4096 bytes. So we cannot safely - invoke alloca (N) if N exceeds 4096. Use a slightly smaller number - to allow for a few compiler-allocated temporary stack slots. */ -# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ -# endif -# else -# define YYSTACK_ALLOC YYMALLOC -# define YYSTACK_FREE YYFREE -# ifndef YYSTACK_ALLOC_MAXIMUM -# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM -# endif -# if (defined __cplusplus && ! defined EXIT_SUCCESS \ - && ! ((defined YYMALLOC || defined malloc) \ - && (defined YYFREE || defined free))) -# include /* INFRINGES ON USER NAME SPACE */ -# ifndef EXIT_SUCCESS -# define EXIT_SUCCESS 0 -# endif -# endif -# ifndef YYMALLOC -# define YYMALLOC malloc -# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# ifndef YYFREE -# define YYFREE free -# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -void free (void *); /* INFRINGES ON USER NAME SPACE */ -# endif -# endif -# endif -#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ - - -#if (! defined yyoverflow \ - && (! defined __cplusplus \ - || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) - -/* A type that is properly aligned for any stack member. */ -union yyalloc -{ - yytype_int16 yyss_alloc; - YYSTYPE yyvs_alloc; -}; - -/* The size of the maximum gap between one aligned stack and the next. */ -# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) - -/* The size of an array large to enough to hold all stacks, each with - N elements. */ -# define YYSTACK_BYTES(N) \ - ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ - + YYSTACK_GAP_MAXIMUM) - -# define YYCOPY_NEEDED 1 - -/* Relocate STACK from its old location to the new one. The - local variables YYSIZE and YYSTACKSIZE give the old and new number of - elements in the stack, and YYPTR gives the new location of the - stack. Advance YYPTR to a properly aligned location for the next - stack. */ -# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ - do \ - { \ - YYSIZE_T yynewbytes; \ - YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ - Stack = &yyptr->Stack_alloc; \ - yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ - yyptr += yynewbytes / sizeof (*yyptr); \ - } \ - while (YYID (0)) - -#endif - -#if defined YYCOPY_NEEDED && YYCOPY_NEEDED -/* Copy COUNT objects from SRC to DST. The source and destination do - not overlap. */ -# ifndef YYCOPY -# if defined __GNUC__ && 1 < __GNUC__ -# define YYCOPY(Dst, Src, Count) \ - __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) -# else -# define YYCOPY(Dst, Src, Count) \ - do \ - { \ - YYSIZE_T yyi; \ - for (yyi = 0; yyi < (Count); yyi++) \ - (Dst)[yyi] = (Src)[yyi]; \ - } \ - while (YYID (0)) -# endif -# endif -#endif /* !YYCOPY_NEEDED */ - -/* YYFINAL -- State number of the termination state. */ -#define YYFINAL 11 -/* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 298 - -/* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 40 -/* YYNNTS -- Number of nonterminals. */ -#define YYNNTS 50 -/* YYNRULES -- Number of rules. */ -#define YYNRULES 122 -/* YYNRULES -- Number of states. */ -#define YYNSTATES 199 - -/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ -#define YYUNDEFTOK 2 -#define YYMAXUTOK 294 - -#define YYTRANSLATE(YYX) \ - ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) - -/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ -static const yytype_uint8 yytranslate[] = -{ - 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39 -}; - -#if YYDEBUG -/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in - YYRHS. */ -static const yytype_uint16 yyprhs[] = -{ - 0, 0, 3, 6, 8, 11, 13, 14, 17, 20, - 23, 26, 31, 36, 40, 42, 44, 46, 48, 50, - 52, 54, 56, 58, 60, 62, 64, 66, 68, 72, - 75, 79, 82, 86, 89, 90, 93, 96, 99, 102, - 105, 108, 112, 117, 122, 127, 133, 137, 138, 142, - 143, 146, 150, 153, 155, 159, 160, 163, 166, 169, - 172, 175, 180, 184, 187, 192, 193, 196, 200, 202, - 206, 207, 210, 213, 216, 220, 224, 228, 230, 234, - 235, 238, 241, 244, 248, 252, 255, 258, 261, 262, - 265, 268, 271, 276, 277, 280, 283, 286, 287, 290, - 292, 294, 297, 300, 303, 305, 308, 309, 312, 314, - 318, 322, 326, 330, 334, 338, 342, 345, 349, 353, - 355, 357, 358 -}; - -/* YYRHS -- A `-1'-separated list of the rules' RHS. */ -static const yytype_int8 yyrhs[] = -{ - 41, 0, -1, 85, 42, -1, 42, -1, 67, 43, - -1, 43, -1, -1, 43, 45, -1, 43, 59, -1, - 43, 71, -1, 43, 84, -1, 43, 26, 1, 35, - -1, 43, 44, 1, 35, -1, 43, 1, 35, -1, - 16, -1, 18, -1, 19, -1, 21, -1, 17, -1, - 22, -1, 20, -1, 23, -1, 35, -1, 65, -1, - 75, -1, 48, -1, 50, -1, 73, -1, 26, 1, - 35, -1, 1, 35, -1, 10, 26, 35, -1, 47, - 51, -1, 11, 26, 35, -1, 49, 51, -1, -1, - 51, 52, -1, 51, 53, -1, 51, 79, -1, 51, - 77, -1, 51, 46, -1, 51, 35, -1, 19, 82, - 35, -1, 18, 83, 86, 35, -1, 20, 87, 86, - 35, -1, 21, 26, 86, 35, -1, 22, 88, 88, - 86, 35, -1, 24, 54, 35, -1, -1, 54, 26, - 55, -1, -1, 38, 83, -1, 7, 89, 35, -1, - 56, 60, -1, 84, -1, 57, 62, 58, -1, -1, - 60, 61, -1, 60, 79, -1, 60, 77, -1, 60, - 35, -1, 60, 46, -1, 18, 83, 86, 35, -1, - 19, 82, 35, -1, 17, 35, -1, 20, 26, 86, - 35, -1, -1, 62, 45, -1, 14, 87, 85, -1, - 84, -1, 63, 66, 64, -1, -1, 66, 45, -1, - 66, 71, -1, 66, 59, -1, 3, 83, 85, -1, - 4, 83, 35, -1, 68, 80, 78, -1, 84, -1, - 69, 72, 70, -1, -1, 72, 45, -1, 72, 71, - -1, 72, 59, -1, 6, 83, 35, -1, 9, 83, - 35, -1, 74, 78, -1, 12, 35, -1, 76, 13, - -1, -1, 78, 79, -1, 78, 35, -1, 78, 46, - -1, 16, 25, 87, 35, -1, -1, 80, 81, -1, - 80, 35, -1, 23, 86, -1, -1, 83, 86, -1, - 26, -1, 27, -1, 5, 35, -1, 8, 35, -1, - 15, 35, -1, 35, -1, 85, 35, -1, -1, 14, - 87, -1, 88, -1, 88, 29, 88, -1, 88, 30, - 88, -1, 88, 31, 88, -1, 88, 32, 88, -1, - 88, 38, 88, -1, 88, 28, 88, -1, 34, 87, - 33, -1, 39, 87, -1, 87, 36, 87, -1, 87, - 37, 87, -1, 26, -1, 27, -1, -1, 26, -1 -}; - -/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ -static const yytype_uint16 yyrline[] = -{ - 0, 108, 108, 108, 110, 110, 112, 114, 115, 116, - 117, 118, 119, 123, 127, 127, 127, 127, 127, 127, - 127, 127, 131, 132, 133, 134, 135, 136, 140, 141, - 147, 155, 161, 169, 179, 181, 182, 183, 184, 185, - 186, 189, 197, 203, 213, 219, 225, 228, 230, 241, - 242, 247, 256, 261, 269, 272, 274, 275, 276, 277, - 278, 281, 287, 298, 304, 314, 316, 321, 329, 337, - 340, 342, 343, 344, 349, 356, 363, 368, 376, 379, - 381, 382, 383, 386, 394, 401, 408, 414, 421, 423, - 424, 425, 428, 436, 438, 439, 442, 449, 451, 456, - 457, 460, 461, 462, 466, 467, 470, 471, 474, 475, - 476, 477, 478, 479, 480, 481, 482, 483, 484, 487, - 488, 491, 492 -}; -#endif - -#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE -/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. - First, the terminals, then, starting at YYNTOKENS, nonterminals. */ -static const char *const yytname[] = -{ - "$end", "error", "$undefined", "T_MAINMENU", "T_MENU", "T_ENDMENU", - "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG", - "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS", - "T_OPTIONAL", "T_PROMPT", "T_TYPE", "T_DEFAULT", "T_SELECT", "T_RANGE", - "T_VISIBLE", "T_OPTION", "T_ON", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL", - "T_LESS", "T_LESS_EQUAL", "T_GREATER", "T_GREATER_EQUAL", - "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_EOL", "T_OR", "T_AND", "T_EQUAL", - "T_NOT", "$accept", "input", "start", "stmt_list", "option_name", - "common_stmt", "option_error", "config_entry_start", "config_stmt", - "menuconfig_entry_start", "menuconfig_stmt", "config_option_list", - "config_option", "symbol_option", "symbol_option_list", - "symbol_option_arg", "choice", "choice_entry", "choice_end", - "choice_stmt", "choice_option_list", "choice_option", "choice_block", - "if_entry", "if_end", "if_stmt", "if_block", "mainmenu_stmt", "menu", - "menu_entry", "menu_end", "menu_stmt", "menu_block", "source_stmt", - "comment", "comment_stmt", "help_start", "help", "depends_list", - "depends", "visibility_list", "visible", "prompt_stmt_opt", "prompt", - "end", "nl", "if_expr", "expr", "symbol", "word_opt", YY_NULL -}; -#endif - -# ifdef YYPRINT -/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to - token YYLEX-NUM. */ -static const yytype_uint16 yytoknum[] = -{ - 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289, 290, 291, 292, 293, 294 -}; -# endif - -/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ -static const yytype_uint8 yyr1[] = -{ - 0, 40, 41, 41, 42, 42, 43, 43, 43, 43, - 43, 43, 43, 43, 44, 44, 44, 44, 44, 44, - 44, 44, 45, 45, 45, 45, 45, 45, 46, 46, - 47, 48, 49, 50, 51, 51, 51, 51, 51, 51, - 51, 52, 52, 52, 52, 52, 53, 54, 54, 55, - 55, 56, 57, 58, 59, 60, 60, 60, 60, 60, - 60, 61, 61, 61, 61, 62, 62, 63, 64, 65, - 66, 66, 66, 66, 67, 68, 69, 70, 71, 72, - 72, 72, 72, 73, 74, 75, 76, 77, 78, 78, - 78, 78, 79, 80, 80, 80, 81, 82, 82, 83, - 83, 84, 84, 84, 85, 85, 86, 86, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 88, - 88, 89, 89 -}; - -/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ -static const yytype_uint8 yyr2[] = -{ - 0, 2, 2, 1, 2, 1, 0, 2, 2, 2, - 2, 4, 4, 3, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 3, 2, - 3, 2, 3, 2, 0, 2, 2, 2, 2, 2, - 2, 3, 4, 4, 4, 5, 3, 0, 3, 0, - 2, 3, 2, 1, 3, 0, 2, 2, 2, 2, - 2, 4, 3, 2, 4, 0, 2, 3, 1, 3, - 0, 2, 2, 2, 3, 3, 3, 1, 3, 0, - 2, 2, 2, 3, 3, 2, 2, 2, 0, 2, - 2, 2, 4, 0, 2, 2, 2, 0, 2, 1, - 1, 2, 2, 2, 1, 2, 0, 2, 1, 3, - 3, 3, 3, 3, 3, 3, 2, 3, 3, 1, - 1, 0, 1 -}; - -/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM. - Performed when YYTABLE doesn't specify something else to do. Zero - means the default is an error. */ -static const yytype_uint8 yydefact[] = -{ - 6, 0, 104, 0, 3, 0, 6, 6, 99, 100, - 0, 1, 0, 0, 0, 0, 121, 0, 0, 0, - 0, 0, 0, 14, 18, 15, 16, 20, 17, 19, - 21, 0, 22, 0, 7, 34, 25, 34, 26, 55, - 65, 8, 70, 23, 93, 79, 9, 27, 88, 24, - 10, 0, 105, 2, 74, 13, 0, 101, 0, 122, - 0, 102, 0, 0, 0, 119, 120, 0, 0, 0, - 108, 103, 0, 0, 0, 0, 0, 0, 0, 88, - 0, 0, 75, 83, 51, 84, 30, 32, 0, 116, - 0, 0, 67, 0, 0, 0, 0, 0, 0, 11, - 12, 0, 0, 0, 0, 97, 0, 0, 0, 47, - 0, 40, 39, 35, 36, 0, 38, 37, 0, 0, - 97, 0, 59, 60, 56, 58, 57, 66, 54, 53, - 71, 73, 69, 72, 68, 106, 95, 0, 94, 80, - 82, 78, 81, 77, 90, 91, 89, 115, 117, 118, - 114, 109, 110, 111, 112, 113, 29, 86, 0, 106, - 0, 106, 106, 106, 0, 0, 0, 87, 63, 106, - 0, 106, 0, 96, 0, 0, 41, 98, 0, 0, - 106, 49, 46, 28, 0, 62, 0, 107, 92, 42, - 43, 44, 0, 0, 48, 61, 64, 45, 50 -}; - -/* YYDEFGOTO[NTERM-NUM]. */ -static const yytype_int16 yydefgoto[] = -{ - -1, 3, 4, 5, 33, 34, 112, 35, 36, 37, - 38, 74, 113, 114, 165, 194, 39, 40, 128, 41, - 76, 124, 77, 42, 132, 43, 78, 6, 44, 45, - 141, 46, 80, 47, 48, 49, 115, 116, 81, 117, - 79, 138, 160, 161, 50, 7, 173, 69, 70, 60 -}; - -/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing - STATE-NUM. */ -#define YYPACT_NINF -91 -static const yytype_int16 yypact[] = -{ - 19, 37, -91, 13, -91, 79, -91, 20, -91, -91, - -16, -91, 21, 37, 25, 37, 41, 36, 37, 78, - 83, 31, 56, -91, -91, -91, -91, -91, -91, -91, - -91, 116, -91, 127, -91, -91, -91, -91, -91, -91, - -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, - -91, 147, -91, -91, 105, -91, 109, -91, 111, -91, - 114, -91, 136, 137, 142, -91, -91, 31, 31, 76, - 254, -91, 143, 146, 27, 115, 207, 258, 243, -14, - 243, 179, -91, -91, -91, -91, -91, -91, -7, -91, - 31, 31, 105, 51, 51, 51, 51, 51, 51, -91, - -91, 156, 168, 181, 37, 37, 31, 178, 51, -91, - 206, -91, -91, -91, -91, 196, -91, -91, 175, 37, - 37, 185, -91, -91, -91, -91, -91, -91, -91, -91, - -91, -91, -91, -91, -91, 214, -91, 230, -91, -91, - -91, -91, -91, -91, -91, -91, -91, -91, 183, -91, - -91, -91, -91, -91, -91, -91, -91, -91, 31, 214, - 194, 214, 45, 214, 51, 26, 195, -91, -91, 214, - 197, 214, 31, -91, 139, 208, -91, -91, 220, 224, - 214, 222, -91, -91, 226, -91, 227, 123, -91, -91, - -91, -91, 235, 37, -91, -91, -91, -91, -91 -}; - -/* YYPGOTO[NTERM-NUM]. */ -static const yytype_int16 yypgoto[] = -{ - -91, -91, 264, 268, -91, 30, -65, -91, -91, -91, - -91, 238, -91, -91, -91, -91, -91, -91, -91, -12, - -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, - -91, -5, -91, -91, -91, -91, -91, 200, 209, -61, - -91, -91, 170, -1, 65, 0, 118, -66, -90, -91 -}; - -/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If - positive, shift that token. If negative, reduce the rule which - number is the opposite. If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -86 -static const yytype_int16 yytable[] = -{ - 10, 88, 89, 150, 151, 152, 153, 154, 155, 135, - 54, 123, 56, 11, 58, 126, 145, 62, 164, 2, - 146, 136, 1, 1, 148, 149, 147, -31, 101, 90, - 91, -31, -31, -31, -31, -31, -31, -31, -31, 102, - 162, -31, -31, 103, -31, 104, 105, 106, 107, 108, - -31, 109, 181, 110, 2, 52, 55, 65, 66, 172, - 57, 182, 111, 8, 9, 67, 131, 59, 140, 92, - 68, 61, 145, 133, 180, 142, 146, 65, 66, -5, - 12, 90, 91, 13, 14, 15, 16, 17, 18, 19, - 20, 71, 174, 21, 22, 23, 24, 25, 26, 27, - 28, 29, 30, 159, 63, 31, 187, 127, 130, 64, - 139, 2, 90, 91, 32, -33, 101, 72, 169, -33, - -33, -33, -33, -33, -33, -33, -33, 102, 73, -33, - -33, 103, -33, 104, 105, 106, 107, 108, -33, 109, - 52, 110, 129, 134, 82, 143, 83, -4, 12, 84, - 111, 13, 14, 15, 16, 17, 18, 19, 20, 90, - 91, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 30, 85, 86, 31, 188, 90, 91, 87, 99, -85, - 101, 100, 32, -85, -85, -85, -85, -85, -85, -85, - -85, 156, 198, -85, -85, 103, -85, -85, -85, -85, - -85, -85, -85, 157, 163, 110, 158, 166, 101, 167, - 168, 171, -52, -52, 144, -52, -52, -52, -52, 102, - 91, -52, -52, 103, 118, 119, 120, 121, 172, 176, - 183, 101, 185, 110, -76, -76, -76, -76, -76, -76, - -76, -76, 122, 189, -76, -76, 103, 13, 14, 15, - 16, 17, 18, 19, 20, 190, 110, 21, 22, 191, - 193, 195, 196, 14, 15, 144, 17, 18, 19, 20, - 197, 53, 21, 22, 51, 75, 125, 175, 32, 177, - 178, 179, 93, 94, 95, 96, 97, 184, 137, 186, - 170, 0, 98, 32, 0, 0, 0, 0, 192 -}; - -#define yypact_value_is_default(yystate) \ - ((yystate) == (-91)) - -#define yytable_value_is_error(yytable_value) \ - YYID (0) - -static const yytype_int16 yycheck[] = -{ - 1, 67, 68, 93, 94, 95, 96, 97, 98, 23, - 10, 76, 13, 0, 15, 76, 81, 18, 108, 35, - 81, 35, 3, 3, 90, 91, 33, 0, 1, 36, - 37, 4, 5, 6, 7, 8, 9, 10, 11, 12, - 106, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 24, 26, 26, 35, 35, 35, 26, 27, 14, - 35, 35, 35, 26, 27, 34, 78, 26, 80, 69, - 39, 35, 137, 78, 164, 80, 137, 26, 27, 0, - 1, 36, 37, 4, 5, 6, 7, 8, 9, 10, - 11, 35, 158, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 104, 26, 26, 172, 77, 78, 26, - 80, 35, 36, 37, 35, 0, 1, 1, 119, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 1, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 35, 26, 77, 78, 35, 80, 35, 0, 1, 35, - 35, 4, 5, 6, 7, 8, 9, 10, 11, 36, - 37, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 35, 35, 26, 35, 36, 37, 35, 35, 0, - 1, 35, 35, 4, 5, 6, 7, 8, 9, 10, - 11, 35, 193, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 23, 35, 26, 26, 25, 1, 1, 13, - 35, 26, 5, 6, 35, 8, 9, 10, 11, 12, - 37, 14, 15, 16, 17, 18, 19, 20, 14, 35, - 35, 1, 35, 26, 4, 5, 6, 7, 8, 9, - 10, 11, 35, 35, 14, 15, 16, 4, 5, 6, - 7, 8, 9, 10, 11, 35, 26, 14, 15, 35, - 38, 35, 35, 5, 6, 35, 8, 9, 10, 11, - 35, 7, 14, 15, 6, 37, 76, 159, 35, 161, - 162, 163, 28, 29, 30, 31, 32, 169, 79, 171, - 120, -1, 38, 35, -1, -1, -1, -1, 180 -}; - -/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing - symbol of state STATE-NUM. */ -static const yytype_uint8 yystos[] = -{ - 0, 3, 35, 41, 42, 43, 67, 85, 26, 27, - 83, 0, 1, 4, 5, 6, 7, 8, 9, 10, - 11, 14, 15, 16, 17, 18, 19, 20, 21, 22, - 23, 26, 35, 44, 45, 47, 48, 49, 50, 56, - 57, 59, 63, 65, 68, 69, 71, 73, 74, 75, - 84, 43, 35, 42, 85, 35, 83, 35, 83, 26, - 89, 35, 83, 26, 26, 26, 27, 34, 39, 87, - 88, 35, 1, 1, 51, 51, 60, 62, 66, 80, - 72, 78, 35, 35, 35, 35, 35, 35, 87, 87, - 36, 37, 85, 28, 29, 30, 31, 32, 38, 35, - 35, 1, 12, 16, 18, 19, 20, 21, 22, 24, - 26, 35, 46, 52, 53, 76, 77, 79, 17, 18, - 19, 20, 35, 46, 61, 77, 79, 45, 58, 84, - 45, 59, 64, 71, 84, 23, 35, 78, 81, 45, - 59, 70, 71, 84, 35, 46, 79, 33, 87, 87, - 88, 88, 88, 88, 88, 88, 35, 35, 25, 83, - 82, 83, 87, 26, 88, 54, 1, 13, 35, 83, - 82, 26, 14, 86, 87, 86, 35, 86, 86, 86, - 88, 26, 35, 35, 86, 35, 86, 87, 35, 35, - 35, 35, 86, 38, 55, 35, 35, 35, 83 -}; - -#define yyerrok (yyerrstatus = 0) -#define yyclearin (yychar = YYEMPTY) -#define YYEMPTY (-2) -#define YYEOF 0 - -#define YYACCEPT goto yyacceptlab -#define YYABORT goto yyabortlab -#define YYERROR goto yyerrorlab - - -/* Like YYERROR except do call yyerror. This remains here temporarily - to ease the transition to the new meaning of YYERROR, for GCC. - Once GCC version 2 has supplanted version 1, this can go. However, - YYFAIL appears to be in use. Nevertheless, it is formally deprecated - in Bison 2.4.2's NEWS entry, where a plan to phase it out is - discussed. */ - -#define YYFAIL goto yyerrlab -#if defined YYFAIL - /* This is here to suppress warnings from the GCC cpp's - -Wunused-macros. Normally we don't worry about that warning, but - some users do, and we want to make it easy for users to remove - YYFAIL uses, which will produce warnings from Bison 2.5. */ -#endif - -#define YYRECOVERING() (!!yyerrstatus) - -#define YYBACKUP(Token, Value) \ -do \ - if (yychar == YYEMPTY) \ - { \ - yychar = (Token); \ - yylval = (Value); \ - YYPOPSTACK (yylen); \ - yystate = *yyssp; \ - goto yybackup; \ - } \ - else \ - { \ - yyerror (YY_("syntax error: cannot back up")); \ - YYERROR; \ - } \ -while (YYID (0)) - - -#define YYTERROR 1 -#define YYERRCODE 256 - - -/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. - If N is 0, then set CURRENT to the empty location which ends - the previous symbol: RHS[0] (always defined). */ - -#define YYRHSLOC(Rhs, K) ((Rhs)[K]) -#ifndef YYLLOC_DEFAULT -# define YYLLOC_DEFAULT(Current, Rhs, N) \ - do \ - if (YYID (N)) \ - { \ - (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ - (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ - (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ - (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ - } \ - else \ - { \ - (Current).first_line = (Current).last_line = \ - YYRHSLOC (Rhs, 0).last_line; \ - (Current).first_column = (Current).last_column = \ - YYRHSLOC (Rhs, 0).last_column; \ - } \ - while (YYID (0)) -#endif - - -/* This macro is provided for backward compatibility. */ - -#ifndef YY_LOCATION_PRINT -# define YY_LOCATION_PRINT(File, Loc) ((void) 0) -#endif - - -/* YYLEX -- calling `yylex' with the right arguments. */ - -#ifdef YYLEX_PARAM -# define YYLEX yylex (YYLEX_PARAM) -#else -# define YYLEX yylex () -#endif - -/* Enable debugging if requested. */ -#if YYDEBUG - -# ifndef YYFPRINTF -# include /* INFRINGES ON USER NAME SPACE */ -# define YYFPRINTF fprintf -# endif - -# define YYDPRINTF(Args) \ -do { \ - if (yydebug) \ - YYFPRINTF Args; \ -} while (YYID (0)) - -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ -do { \ - if (yydebug) \ - { \ - YYFPRINTF (stderr, "%s ", Title); \ - yy_symbol_print (stderr, \ - Type, Value); \ - YYFPRINTF (stderr, "\n"); \ - } \ -} while (YYID (0)) - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) -#else -static void -yy_symbol_value_print (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; -#endif -{ - FILE *yyo = yyoutput; - YYUSE (yyo); - if (!yyvaluep) - return; -# ifdef YYPRINT - if (yytype < YYNTOKENS) - YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); -# else - YYUSE (yyoutput); -# endif - switch (yytype) - { - default: - break; - } -} - - -/*--------------------------------. -| Print this symbol on YYOUTPUT. | -`--------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) -#else -static void -yy_symbol_print (yyoutput, yytype, yyvaluep) - FILE *yyoutput; - int yytype; - YYSTYPE const * const yyvaluep; -#endif -{ - if (yytype < YYNTOKENS) - YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); - else - YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); - - yy_symbol_value_print (yyoutput, yytype, yyvaluep); - YYFPRINTF (yyoutput, ")"); -} - -/*------------------------------------------------------------------. -| yy_stack_print -- Print the state stack from its BOTTOM up to its | -| TOP (included). | -`------------------------------------------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) -#else -static void -yy_stack_print (yybottom, yytop) - yytype_int16 *yybottom; - yytype_int16 *yytop; -#endif -{ - YYFPRINTF (stderr, "Stack now"); - for (; yybottom <= yytop; yybottom++) - { - int yybot = *yybottom; - YYFPRINTF (stderr, " %d", yybot); - } - YYFPRINTF (stderr, "\n"); -} - -# define YY_STACK_PRINT(Bottom, Top) \ -do { \ - if (yydebug) \ - yy_stack_print ((Bottom), (Top)); \ -} while (YYID (0)) - - -/*------------------------------------------------. -| Report that the YYRULE is going to be reduced. | -`------------------------------------------------*/ - -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yy_reduce_print (YYSTYPE *yyvsp, int yyrule) -#else -static void -yy_reduce_print (yyvsp, yyrule) - YYSTYPE *yyvsp; - int yyrule; -#endif -{ - int yynrhs = yyr2[yyrule]; - int yyi; - unsigned long int yylno = yyrline[yyrule]; - YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", - yyrule - 1, yylno); - /* The symbols being reduced. */ - for (yyi = 0; yyi < yynrhs; yyi++) - { - YYFPRINTF (stderr, " $%d = ", yyi + 1); - yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], - &(yyvsp[(yyi + 1) - (yynrhs)]) - ); - YYFPRINTF (stderr, "\n"); - } -} - -# define YY_REDUCE_PRINT(Rule) \ -do { \ - if (yydebug) \ - yy_reduce_print (yyvsp, Rule); \ -} while (YYID (0)) - -/* Nonzero means print parse trace. It is left uninitialized so that - multiple parsers can coexist. */ -int yydebug; -#else /* !YYDEBUG */ -# define YYDPRINTF(Args) -# define YY_SYMBOL_PRINT(Title, Type, Value, Location) -# define YY_STACK_PRINT(Bottom, Top) -# define YY_REDUCE_PRINT(Rule) -#endif /* !YYDEBUG */ - - -/* YYINITDEPTH -- initial size of the parser's stacks. */ -#ifndef YYINITDEPTH -# define YYINITDEPTH 200 -#endif - -/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only - if the built-in stack extension method is used). - - Do not make this value too large; the results are undefined if - YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) - evaluated with infinite-precision integer arithmetic. */ - -#ifndef YYMAXDEPTH -# define YYMAXDEPTH 10000 -#endif - - -#if YYERROR_VERBOSE - -# ifndef yystrlen -# if defined __GLIBC__ && defined _STRING_H -# define yystrlen strlen -# else -/* Return the length of YYSTR. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static YYSIZE_T -yystrlen (const char *yystr) -#else -static YYSIZE_T -yystrlen (yystr) - const char *yystr; -#endif -{ - YYSIZE_T yylen; - for (yylen = 0; yystr[yylen]; yylen++) - continue; - return yylen; -} -# endif -# endif - -# ifndef yystpcpy -# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE -# define yystpcpy stpcpy -# else -/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in - YYDEST. */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static char * -yystpcpy (char *yydest, const char *yysrc) -#else -static char * -yystpcpy (yydest, yysrc) - char *yydest; - const char *yysrc; -#endif -{ - char *yyd = yydest; - const char *yys = yysrc; - - while ((*yyd++ = *yys++) != '\0') - continue; - - return yyd - 1; -} -# endif -# endif - -# ifndef yytnamerr -/* Copy to YYRES the contents of YYSTR after stripping away unnecessary - quotes and backslashes, so that it's suitable for yyerror. The - heuristic is that double-quoting is unnecessary unless the string - contains an apostrophe, a comma, or backslash (other than - backslash-backslash). YYSTR is taken from yytname. If YYRES is - null, do not copy; instead, return the length of what the result - would have been. */ -static YYSIZE_T -yytnamerr (char *yyres, const char *yystr) -{ - if (*yystr == '"') - { - YYSIZE_T yyn = 0; - char const *yyp = yystr; - - for (;;) - switch (*++yyp) - { - case '\'': - case ',': - goto do_not_strip_quotes; - - case '\\': - if (*++yyp != '\\') - goto do_not_strip_quotes; - /* Fall through. */ - default: - if (yyres) - yyres[yyn] = *yyp; - yyn++; - break; - - case '"': - if (yyres) - yyres[yyn] = '\0'; - return yyn; - } - do_not_strip_quotes: ; - } - - if (! yyres) - return yystrlen (yystr); - - return yystpcpy (yyres, yystr) - yyres; -} -# endif - -/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message - about the unexpected token YYTOKEN for the state stack whose top is - YYSSP. - - Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is - not large enough to hold the message. In that case, also set - *YYMSG_ALLOC to the required number of bytes. Return 2 if the - required number of bytes is too large to store. */ -static int -yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, - yytype_int16 *yyssp, int yytoken) -{ - YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]); - YYSIZE_T yysize = yysize0; - YYSIZE_T yysize1; - enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; - /* Internationalized format string. */ - const char *yyformat = YY_NULL; - /* Arguments of yyformat. */ - char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; - /* Number of reported tokens (one for the "unexpected", one per - "expected"). */ - int yycount = 0; - - /* There are many possibilities here to consider: - - Assume YYFAIL is not used. It's too flawed to consider. See - - for details. YYERROR is fine as it does not invoke this - function. - - If this state is a consistent state with a default action, then - the only way this function was invoked is if the default action - is an error action. In that case, don't check for expected - tokens because there are none. - - The only way there can be no lookahead present (in yychar) is if - this state is a consistent state with a default action. Thus, - detecting the absence of a lookahead is sufficient to determine - that there is no unexpected or expected token to report. In that - case, just report a simple "syntax error". - - Don't assume there isn't a lookahead just because this state is a - consistent state with a default action. There might have been a - previous inconsistent state, consistent state with a non-default - action, or user semantic action that manipulated yychar. - - Of course, the expected token list depends on states to have - correct lookahead information, and it depends on the parser not - to perform extra reductions after fetching a lookahead from the - scanner and before detecting a syntax error. Thus, state merging - (from LALR or IELR) and default reductions corrupt the expected - token list. However, the list is correct for canonical LR with - one exception: it will still contain any token that will not be - accepted due to an error action in a later state. - */ - if (yytoken != YYEMPTY) - { - int yyn = yypact[*yyssp]; - yyarg[yycount++] = yytname[yytoken]; - if (!yypact_value_is_default (yyn)) - { - /* Start YYX at -YYN if negative to avoid negative indexes in - YYCHECK. In other words, skip the first -YYN actions for - this state because they are default actions. */ - int yyxbegin = yyn < 0 ? -yyn : 0; - /* Stay within bounds of both yycheck and yytname. */ - int yychecklim = YYLAST - yyn + 1; - int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; - int yyx; - - for (yyx = yyxbegin; yyx < yyxend; ++yyx) - if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR - && !yytable_value_is_error (yytable[yyx + yyn])) - { - if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) - { - yycount = 1; - yysize = yysize0; - break; - } - yyarg[yycount++] = yytname[yyx]; - yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]); - if (! (yysize <= yysize1 - && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; - } - } - } - - switch (yycount) - { -# define YYCASE_(N, S) \ - case N: \ - yyformat = S; \ - break - YYCASE_(0, YY_("syntax error")); - YYCASE_(1, YY_("syntax error, unexpected %s")); - YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); - YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); - YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); - YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); -# undef YYCASE_ - } - - yysize1 = yysize + yystrlen (yyformat); - if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) - return 2; - yysize = yysize1; - - if (*yymsg_alloc < yysize) - { - *yymsg_alloc = 2 * yysize; - if (! (yysize <= *yymsg_alloc - && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) - *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; - return 1; - } - - /* Avoid sprintf, as that infringes on the user's name space. - Don't have undefined behavior even if the translation - produced a string with the wrong number of "%s"s. */ - { - char *yyp = *yymsg; - int yyi = 0; - while ((*yyp = *yyformat) != '\0') - if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) - { - yyp += yytnamerr (yyp, yyarg[yyi++]); - yyformat += 2; - } - else - { - yyp++; - yyformat++; - } - } - return 0; -} -#endif /* YYERROR_VERBOSE */ - -/*-----------------------------------------------. -| Release the memory associated to this symbol. | -`-----------------------------------------------*/ - -/*ARGSUSED*/ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -static void -yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) -#else -static void -yydestruct (yymsg, yytype, yyvaluep) - const char *yymsg; - int yytype; - YYSTYPE *yyvaluep; -#endif -{ - YYUSE (yyvaluep); - - if (!yymsg) - yymsg = "Deleting"; - YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); - - switch (yytype) - { - case 57: /* "choice_entry" */ - - { - fprintf(stderr, "%s:%d: missing end statement for this entry\n", - (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); - if (current_menu == (yyvaluep->menu)) - menu_end_menu(); -}; - - break; - case 63: /* "if_entry" */ - - { - fprintf(stderr, "%s:%d: missing end statement for this entry\n", - (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); - if (current_menu == (yyvaluep->menu)) - menu_end_menu(); -}; - - break; - case 69: /* "menu_entry" */ - - { - fprintf(stderr, "%s:%d: missing end statement for this entry\n", - (yyvaluep->menu)->file->name, (yyvaluep->menu)->lineno); - if (current_menu == (yyvaluep->menu)) - menu_end_menu(); -}; - - break; - - default: - break; - } -} - - -/* Prevent warnings from -Wmissing-prototypes. */ -#ifdef YYPARSE_PARAM -#if defined __STDC__ || defined __cplusplus -int yyparse (void *YYPARSE_PARAM); -#else -int yyparse (); -#endif -#else /* ! YYPARSE_PARAM */ -#if defined __STDC__ || defined __cplusplus -int yyparse (void); -#else -int yyparse (); -#endif -#endif /* ! YYPARSE_PARAM */ - - -/* The lookahead symbol. */ -int yychar; - -/* The semantic value of the lookahead symbol. */ -YYSTYPE yylval; - -/* Number of syntax errors so far. */ -int yynerrs; - - -/*----------. -| yyparse. | -`----------*/ - -#ifdef YYPARSE_PARAM -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -int -yyparse (void *YYPARSE_PARAM) -#else -int -yyparse (YYPARSE_PARAM) - void *YYPARSE_PARAM; -#endif -#else /* ! YYPARSE_PARAM */ -#if (defined __STDC__ || defined __C99__FUNC__ \ - || defined __cplusplus || defined _MSC_VER) -int -yyparse (void) -#else -int -yyparse () - -#endif -#endif -{ - int yystate; - /* Number of tokens to shift before error messages enabled. */ - int yyerrstatus; - - /* The stacks and their tools: - `yyss': related to states. - `yyvs': related to semantic values. - - Refer to the stacks through separate pointers, to allow yyoverflow - to reallocate them elsewhere. */ - - /* The state stack. */ - yytype_int16 yyssa[YYINITDEPTH]; - yytype_int16 *yyss; - yytype_int16 *yyssp; - - /* The semantic value stack. */ - YYSTYPE yyvsa[YYINITDEPTH]; - YYSTYPE *yyvs; - YYSTYPE *yyvsp; - - YYSIZE_T yystacksize; - - int yyn; - int yyresult; - /* Lookahead token as an internal (translated) token number. */ - int yytoken; - /* The variables used to return semantic value and location from the - action routines. */ - YYSTYPE yyval; - -#if YYERROR_VERBOSE - /* Buffer for error messages, and its allocated size. */ - char yymsgbuf[128]; - char *yymsg = yymsgbuf; - YYSIZE_T yymsg_alloc = sizeof yymsgbuf; -#endif - -#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) - - /* The number of symbols on the RHS of the reduced rule. - Keep to zero when no symbol should be popped. */ - int yylen = 0; - - yytoken = 0; - yyss = yyssa; - yyvs = yyvsa; - yystacksize = YYINITDEPTH; - - YYDPRINTF ((stderr, "Starting parse\n")); - - yystate = 0; - yyerrstatus = 0; - yynerrs = 0; - yychar = YYEMPTY; /* Cause a token to be read. */ - - /* Initialize stack pointers. - Waste one element of value and location stack - so that they stay on the same level as the state stack. - The wasted elements are never initialized. */ - yyssp = yyss; - yyvsp = yyvs; - - goto yysetstate; - -/*------------------------------------------------------------. -| yynewstate -- Push a new state, which is found in yystate. | -`------------------------------------------------------------*/ - yynewstate: - /* In all cases, when you get here, the value and location stacks - have just been pushed. So pushing a state here evens the stacks. */ - yyssp++; - - yysetstate: - *yyssp = yystate; - - if (yyss + yystacksize - 1 <= yyssp) - { - /* Get the current used size of the three stacks, in elements. */ - YYSIZE_T yysize = yyssp - yyss + 1; - -#ifdef yyoverflow - { - /* Give user a chance to reallocate the stack. Use copies of - these so that the &'s don't force the real ones into - memory. */ - YYSTYPE *yyvs1 = yyvs; - yytype_int16 *yyss1 = yyss; - - /* Each stack pointer address is followed by the size of the - data in use in that stack, in bytes. This used to be a - conditional around just the two extra args, but that might - be undefined if yyoverflow is a macro. */ - yyoverflow (YY_("memory exhausted"), - &yyss1, yysize * sizeof (*yyssp), - &yyvs1, yysize * sizeof (*yyvsp), - &yystacksize); - - yyss = yyss1; - yyvs = yyvs1; - } -#else /* no yyoverflow */ -# ifndef YYSTACK_RELOCATE - goto yyexhaustedlab; -# else - /* Extend the stack our own way. */ - if (YYMAXDEPTH <= yystacksize) - goto yyexhaustedlab; - yystacksize *= 2; - if (YYMAXDEPTH < yystacksize) - yystacksize = YYMAXDEPTH; - - { - yytype_int16 *yyss1 = yyss; - union yyalloc *yyptr = - (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); - if (! yyptr) - goto yyexhaustedlab; - YYSTACK_RELOCATE (yyss_alloc, yyss); - YYSTACK_RELOCATE (yyvs_alloc, yyvs); -# undef YYSTACK_RELOCATE - if (yyss1 != yyssa) - YYSTACK_FREE (yyss1); - } -# endif -#endif /* no yyoverflow */ - - yyssp = yyss + yysize - 1; - yyvsp = yyvs + yysize - 1; - - YYDPRINTF ((stderr, "Stack size increased to %lu\n", - (unsigned long int) yystacksize)); - - if (yyss + yystacksize - 1 <= yyssp) - YYABORT; - } - - YYDPRINTF ((stderr, "Entering state %d\n", yystate)); - - if (yystate == YYFINAL) - YYACCEPT; - - goto yybackup; - -/*-----------. -| yybackup. | -`-----------*/ -yybackup: - - /* Do appropriate processing given the current state. Read a - lookahead token if we need one and don't already have one. */ - - /* First try to decide what to do without reference to lookahead token. */ - yyn = yypact[yystate]; - if (yypact_value_is_default (yyn)) - goto yydefault; - - /* Not known => get a lookahead token if don't already have one. */ - - /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ - if (yychar == YYEMPTY) - { - YYDPRINTF ((stderr, "Reading a token: ")); - yychar = YYLEX; - } - - if (yychar <= YYEOF) - { - yychar = yytoken = YYEOF; - YYDPRINTF ((stderr, "Now at end of input.\n")); - } - else - { - yytoken = YYTRANSLATE (yychar); - YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); - } - - /* If the proper action on seeing token YYTOKEN is to reduce or to - detect an error, take that action. */ - yyn += yytoken; - if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) - goto yydefault; - yyn = yytable[yyn]; - if (yyn <= 0) - { - if (yytable_value_is_error (yyn)) - goto yyerrlab; - yyn = -yyn; - goto yyreduce; - } - - /* Count tokens shifted since error; after three, turn off error - status. */ - if (yyerrstatus) - yyerrstatus--; - - /* Shift the lookahead token. */ - YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); - - /* Discard the shifted token. */ - yychar = YYEMPTY; - - yystate = yyn; - *++yyvsp = yylval; - - goto yynewstate; - - -/*-----------------------------------------------------------. -| yydefault -- do the default action for the current state. | -`-----------------------------------------------------------*/ -yydefault: - yyn = yydefact[yystate]; - if (yyn == 0) - goto yyerrlab; - goto yyreduce; - - -/*-----------------------------. -| yyreduce -- Do a reduction. | -`-----------------------------*/ -yyreduce: - /* yyn is the number of a rule to reduce with. */ - yylen = yyr2[yyn]; - - /* If YYLEN is nonzero, implement the default value of the action: - `$$ = $1'. - - Otherwise, the following line sets YYVAL to garbage. - This behavior is undocumented and Bison - users should not rely upon it. Assigning to YYVAL - unconditionally makes the parser a bit smaller, and it avoids a - GCC warning that YYVAL may be used uninitialized. */ - yyval = yyvsp[1-yylen]; - - - YY_REDUCE_PRINT (yyn); - switch (yyn) - { - case 10: - - { zconf_error("unexpected end statement"); } - break; - - case 11: - - { zconf_error("unknown statement \"%s\"", (yyvsp[(2) - (4)].string)); } - break; - - case 12: - - { - zconf_error("unexpected option \"%s\"", kconf_id_strings + (yyvsp[(2) - (4)].id)->name); -} - break; - - case 13: - - { zconf_error("invalid statement"); } - break; - - case 28: - - { zconf_error("unknown option \"%s\"", (yyvsp[(1) - (3)].string)); } - break; - - case 29: - - { zconf_error("invalid option"); } - break; - - case 30: - - { - struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0); - sym->flags |= SYMBOL_OPTIONAL; - menu_add_entry(sym); - printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); -} - break; - - case 31: - - { - menu_end_entry(); - printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); -} - break; - - case 32: - - { - struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), 0); - sym->flags |= SYMBOL_OPTIONAL; - menu_add_entry(sym); - printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); -} - break; - - case 33: - - { - if (current_entry->prompt) - current_entry->prompt->type = P_MENU; - else - zconfprint("warning: menuconfig statement without prompt"); - menu_end_entry(); - printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); -} - break; - - case 41: - - { - menu_set_type((yyvsp[(1) - (3)].id)->stype); - printd(DEBUG_PARSE, "%s:%d:type(%u)\n", - zconf_curname(), zconf_lineno(), - (yyvsp[(1) - (3)].id)->stype); -} - break; - - case 42: - - { - menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr)); - printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); -} - break; - - case 43: - - { - menu_add_expr(P_DEFAULT, (yyvsp[(2) - (4)].expr), (yyvsp[(3) - (4)].expr)); - if ((yyvsp[(1) - (4)].id)->stype != S_UNKNOWN) - menu_set_type((yyvsp[(1) - (4)].id)->stype); - printd(DEBUG_PARSE, "%s:%d:default(%u)\n", - zconf_curname(), zconf_lineno(), - (yyvsp[(1) - (4)].id)->stype); -} - break; - - case 44: - - { - menu_add_symbol(P_SELECT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr)); - printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); -} - break; - - case 45: - - { - menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,(yyvsp[(2) - (5)].symbol), (yyvsp[(3) - (5)].symbol)), (yyvsp[(4) - (5)].expr)); - printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); -} - break; - - case 48: - - { - const struct kconf_id *id = kconf_id_lookup((yyvsp[(2) - (3)].string), strlen((yyvsp[(2) - (3)].string))); - if (id && id->flags & TF_OPTION) - menu_add_option(id->token, (yyvsp[(3) - (3)].string)); - else - zconfprint("warning: ignoring unknown option %s", (yyvsp[(2) - (3)].string)); - free((yyvsp[(2) - (3)].string)); -} - break; - - case 49: - - { (yyval.string) = NULL; } - break; - - case 50: - - { (yyval.string) = (yyvsp[(2) - (2)].string); } - break; - - case 51: - - { - struct symbol *sym = sym_lookup((yyvsp[(2) - (3)].string), SYMBOL_CHOICE); - sym->flags |= SYMBOL_AUTO; - menu_add_entry(sym); - menu_add_expr(P_CHOICE, NULL, NULL); - printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); -} - break; - - case 52: - - { - (yyval.menu) = menu_add_menu(); -} - break; - - case 53: - - { - if (zconf_endtoken((yyvsp[(1) - (1)].id), T_CHOICE, T_ENDCHOICE)) { - menu_end_menu(); - printd(DEBUG_PARSE, "%s:%d:endchoice\n", zconf_curname(), zconf_lineno()); - } -} - break; - - case 61: - - { - menu_add_prompt(P_PROMPT, (yyvsp[(2) - (4)].string), (yyvsp[(3) - (4)].expr)); - printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); -} - break; - - case 62: - - { - if ((yyvsp[(1) - (3)].id)->stype == S_BOOLEAN || (yyvsp[(1) - (3)].id)->stype == S_TRISTATE) { - menu_set_type((yyvsp[(1) - (3)].id)->stype); - printd(DEBUG_PARSE, "%s:%d:type(%u)\n", - zconf_curname(), zconf_lineno(), - (yyvsp[(1) - (3)].id)->stype); - } else - YYERROR; -} - break; - - case 63: - - { - current_entry->sym->flags |= SYMBOL_OPTIONAL; - printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); -} - break; - - case 64: - - { - if ((yyvsp[(1) - (4)].id)->stype == S_UNKNOWN) { - menu_add_symbol(P_DEFAULT, sym_lookup((yyvsp[(2) - (4)].string), 0), (yyvsp[(3) - (4)].expr)); - printd(DEBUG_PARSE, "%s:%d:default\n", - zconf_curname(), zconf_lineno()); - } else - YYERROR; -} - break; - - case 67: - - { - printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); - menu_add_entry(NULL); - menu_add_dep((yyvsp[(2) - (3)].expr)); - (yyval.menu) = menu_add_menu(); -} - break; - - case 68: - - { - if (zconf_endtoken((yyvsp[(1) - (1)].id), T_IF, T_ENDIF)) { - menu_end_menu(); - printd(DEBUG_PARSE, "%s:%d:endif\n", zconf_curname(), zconf_lineno()); - } -} - break; - - case 74: - - { - menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL); -} - break; - - case 75: - - { - menu_add_entry(NULL); - menu_add_prompt(P_MENU, (yyvsp[(2) - (3)].string), NULL); - printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); -} - break; - - case 76: - - { - (yyval.menu) = menu_add_menu(); -} - break; - - case 77: - - { - if (zconf_endtoken((yyvsp[(1) - (1)].id), T_MENU, T_ENDMENU)) { - menu_end_menu(); - printd(DEBUG_PARSE, "%s:%d:endmenu\n", zconf_curname(), zconf_lineno()); - } -} - break; - - case 83: - - { - printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), (yyvsp[(2) - (3)].string)); - zconf_nextfile((yyvsp[(2) - (3)].string)); -} - break; - - case 84: - - { - menu_add_entry(NULL); - menu_add_prompt(P_COMMENT, (yyvsp[(2) - (3)].string), NULL); - printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); -} - break; - - case 85: - - { - menu_end_entry(); -} - break; - - case 86: - - { - printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); - zconf_starthelp(); -} - break; - - case 87: - - { - current_entry->help = (yyvsp[(2) - (2)].string); -} - break; - - case 92: - - { - menu_add_dep((yyvsp[(3) - (4)].expr)); - printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); -} - break; - - case 96: - - { - menu_add_visibility((yyvsp[(2) - (2)].expr)); -} - break; - - case 98: - - { - menu_add_prompt(P_PROMPT, (yyvsp[(1) - (2)].string), (yyvsp[(2) - (2)].expr)); -} - break; - - case 101: - - { (yyval.id) = (yyvsp[(1) - (2)].id); } - break; - - case 102: - - { (yyval.id) = (yyvsp[(1) - (2)].id); } - break; - - case 103: - - { (yyval.id) = (yyvsp[(1) - (2)].id); } - break; - - case 106: - - { (yyval.expr) = NULL; } - break; - - case 107: - - { (yyval.expr) = (yyvsp[(2) - (2)].expr); } - break; - - case 108: - - { (yyval.expr) = expr_alloc_symbol((yyvsp[(1) - (1)].symbol)); } - break; - - case 109: - - { (yyval.expr) = expr_alloc_comp(E_LTH, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); } - break; - - case 110: - - { (yyval.expr) = expr_alloc_comp(E_LEQ, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); } - break; - - case 111: - - { (yyval.expr) = expr_alloc_comp(E_GTH, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); } - break; - - case 112: - - { (yyval.expr) = expr_alloc_comp(E_GEQ, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); } - break; - - case 113: - - { (yyval.expr) = expr_alloc_comp(E_EQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); } - break; - - case 114: - - { (yyval.expr) = expr_alloc_comp(E_UNEQUAL, (yyvsp[(1) - (3)].symbol), (yyvsp[(3) - (3)].symbol)); } - break; - - case 115: - - { (yyval.expr) = (yyvsp[(2) - (3)].expr); } - break; - - case 116: - - { (yyval.expr) = expr_alloc_one(E_NOT, (yyvsp[(2) - (2)].expr)); } - break; - - case 117: - - { (yyval.expr) = expr_alloc_two(E_OR, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } - break; - - case 118: - - { (yyval.expr) = expr_alloc_two(E_AND, (yyvsp[(1) - (3)].expr), (yyvsp[(3) - (3)].expr)); } - break; - - case 119: - - { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), 0); free((yyvsp[(1) - (1)].string)); } - break; - - case 120: - - { (yyval.symbol) = sym_lookup((yyvsp[(1) - (1)].string), SYMBOL_CONST); free((yyvsp[(1) - (1)].string)); } - break; - - case 121: - - { (yyval.string) = NULL; } - break; - - - - default: break; - } - /* User semantic actions sometimes alter yychar, and that requires - that yytoken be updated with the new translation. We take the - approach of translating immediately before every use of yytoken. - One alternative is translating here after every semantic action, - but that translation would be missed if the semantic action invokes - YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or - if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an - incorrect destructor might then be invoked immediately. In the - case of YYERROR or YYBACKUP, subsequent parser actions might lead - to an incorrect destructor call or verbose syntax error message - before the lookahead is translated. */ - YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); - - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - - *++yyvsp = yyval; - - /* Now `shift' the result of the reduction. Determine what state - that goes to, based on the state we popped back to and the rule - number reduced by. */ - - yyn = yyr1[yyn]; - - yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; - if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) - yystate = yytable[yystate]; - else - yystate = yydefgoto[yyn - YYNTOKENS]; - - goto yynewstate; - - -/*------------------------------------. -| yyerrlab -- here on detecting error | -`------------------------------------*/ -yyerrlab: - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); - - /* If not already recovering from an error, report this error. */ - if (!yyerrstatus) - { - ++yynerrs; -#if ! YYERROR_VERBOSE - yyerror (YY_("syntax error")); -#else -# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ - yyssp, yytoken) - { - char const *yymsgp = YY_("syntax error"); - int yysyntax_error_status; - yysyntax_error_status = YYSYNTAX_ERROR; - if (yysyntax_error_status == 0) - yymsgp = yymsg; - else if (yysyntax_error_status == 1) - { - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); - yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); - if (!yymsg) - { - yymsg = yymsgbuf; - yymsg_alloc = sizeof yymsgbuf; - yysyntax_error_status = 2; - } - else - { - yysyntax_error_status = YYSYNTAX_ERROR; - yymsgp = yymsg; - } - } - yyerror (yymsgp); - if (yysyntax_error_status == 2) - goto yyexhaustedlab; - } -# undef YYSYNTAX_ERROR -#endif - } - - - - if (yyerrstatus == 3) - { - /* If just tried and failed to reuse lookahead token after an - error, discard it. */ - - if (yychar <= YYEOF) - { - /* Return failure if at end of input. */ - if (yychar == YYEOF) - YYABORT; - } - else - { - yydestruct ("Error: discarding", - yytoken, &yylval); - yychar = YYEMPTY; - } - } - - /* Else will try to reuse lookahead token after shifting the error - token. */ - goto yyerrlab1; - - -/*---------------------------------------------------. -| yyerrorlab -- error raised explicitly by YYERROR. | -`---------------------------------------------------*/ -yyerrorlab: - - /* Pacify compilers like GCC when the user code never invokes - YYERROR and the label yyerrorlab therefore never appears in user - code. */ - if (/*CONSTCOND*/ 0) - goto yyerrorlab; - - /* Do not reclaim the symbols of the rule which action triggered - this YYERROR. */ - YYPOPSTACK (yylen); - yylen = 0; - YY_STACK_PRINT (yyss, yyssp); - yystate = *yyssp; - goto yyerrlab1; - - -/*-------------------------------------------------------------. -| yyerrlab1 -- common code for both syntax error and YYERROR. | -`-------------------------------------------------------------*/ -yyerrlab1: - yyerrstatus = 3; /* Each real token shifted decrements this. */ - - for (;;) - { - yyn = yypact[yystate]; - if (!yypact_value_is_default (yyn)) - { - yyn += YYTERROR; - if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) - { - yyn = yytable[yyn]; - if (0 < yyn) - break; - } - } - - /* Pop the current state because it cannot handle the error token. */ - if (yyssp == yyss) - YYABORT; - - - yydestruct ("Error: popping", - yystos[yystate], yyvsp); - YYPOPSTACK (1); - yystate = *yyssp; - YY_STACK_PRINT (yyss, yyssp); - } - - *++yyvsp = yylval; - - - /* Shift the error token. */ - YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); - - yystate = yyn; - goto yynewstate; - - -/*-------------------------------------. -| yyacceptlab -- YYACCEPT comes here. | -`-------------------------------------*/ -yyacceptlab: - yyresult = 0; - goto yyreturn; - -/*-----------------------------------. -| yyabortlab -- YYABORT comes here. | -`-----------------------------------*/ -yyabortlab: - yyresult = 1; - goto yyreturn; - -#if !defined yyoverflow || YYERROR_VERBOSE -/*-------------------------------------------------. -| yyexhaustedlab -- memory exhaustion comes here. | -`-------------------------------------------------*/ -yyexhaustedlab: - yyerror (YY_("memory exhausted")); - yyresult = 2; - /* Fall through. */ -#endif - -yyreturn: - if (yychar != YYEMPTY) - { - /* Make sure we have latest lookahead translation. See comments at - user semantic actions for why this is necessary. */ - yytoken = YYTRANSLATE (yychar); - yydestruct ("Cleanup: discarding lookahead", - yytoken, &yylval); - } - /* Do not reclaim the symbols of the rule which action triggered - this YYABORT or YYACCEPT. */ - YYPOPSTACK (yylen); - YY_STACK_PRINT (yyss, yyssp); - while (yyssp != yyss) - { - yydestruct ("Cleanup: popping", - yystos[*yyssp], yyvsp); - YYPOPSTACK (1); - } -#ifndef yyoverflow - if (yyss != yyssa) - YYSTACK_FREE (yyss); -#endif -#if YYERROR_VERBOSE - if (yymsg != yymsgbuf) - YYSTACK_FREE (yymsg); -#endif - /* Make sure YYID is used. */ - return YYID (yyresult); -} - - - - - -void conf_parse(const char *name) -{ - struct symbol *sym; - int i; - - zconf_initscan(name); - - sym_init(); - _menu_init(); - rootmenu.prompt = menu_add_prompt(P_MENU, "Linux Kernel Configuration", NULL); - - if (getenv("ZCONF_DEBUG")) - zconfdebug = 1; - zconfparse(); - if (zconfnerrs) - exit(1); - if (!modules_sym) - modules_sym = sym_find( "n" ); - - rootmenu.prompt->text = _(rootmenu.prompt->text); - rootmenu.prompt->text = sym_expand_string_value(rootmenu.prompt->text); - - menu_finalize(&rootmenu); - for_all_symbols(i, sym) { - if (sym_check_deps(sym)) - zconfnerrs++; - } - if (zconfnerrs) - exit(1); - sym_set_change_count(1); -} - -static const char *zconf_tokenname(int token) -{ - switch (token) { - case T_MENU: return "menu"; - case T_ENDMENU: return "endmenu"; - case T_CHOICE: return "choice"; - case T_ENDCHOICE: return "endchoice"; - case T_IF: return "if"; - case T_ENDIF: return "endif"; - case T_DEPENDS: return "depends"; - case T_VISIBLE: return "visible"; - } - return ""; -} - -static bool zconf_endtoken(const struct kconf_id *id, int starttoken, int endtoken) -{ - if (id->token != endtoken) { - zconf_error("unexpected '%s' within %s block", - kconf_id_strings + id->name, zconf_tokenname(starttoken)); - zconfnerrs++; - return false; - } - if (current_menu->file != current_file) { - zconf_error("'%s' in different file than '%s'", - kconf_id_strings + id->name, zconf_tokenname(starttoken)); - fprintf(stderr, "%s:%d: location of the '%s'\n", - current_menu->file->name, current_menu->lineno, - zconf_tokenname(starttoken)); - zconfnerrs++; - return false; - } - return true; -} - -static void zconfprint(const char *err, ...) -{ - va_list ap; - - fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); - va_start(ap, err); - vfprintf(stderr, err, ap); - va_end(ap); - fprintf(stderr, "\n"); -} - -static void zconf_error(const char *err, ...) -{ - va_list ap; - - zconfnerrs++; - fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); - va_start(ap, err); - vfprintf(stderr, err, ap); - va_end(ap); - fprintf(stderr, "\n"); -} - -static void zconferror(const char *err) -{ - fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); -} - -static void print_quoted_string(FILE *out, const char *str) -{ - const char *p; - int len; - - putc('"', out); - while ((p = strchr(str, '"'))) { - len = p - str; - if (len) - fprintf(out, "%.*s", len, str); - fputs("\\\"", out); - str = p + 1; - } - fputs(str, out); - putc('"', out); -} - -static void print_symbol(FILE *out, struct menu *menu) -{ - struct symbol *sym = menu->sym; - struct property *prop; - - if (sym_is_choice(sym)) - fprintf(out, "\nchoice\n"); - else - fprintf(out, "\nconfig %s\n", sym->name); - switch (sym->type) { - case S_BOOLEAN: - fputs(" boolean\n", out); - break; - case S_TRISTATE: - fputs(" tristate\n", out); - break; - case S_STRING: - fputs(" string\n", out); - break; - case S_INT: - fputs(" integer\n", out); - break; - case S_HEX: - fputs(" hex\n", out); - break; - default: - fputs(" ???\n", out); - break; - } - for (prop = sym->prop; prop; prop = prop->next) { - if (prop->menu != menu) - continue; - switch (prop->type) { - case P_PROMPT: - fputs(" prompt ", out); - print_quoted_string(out, prop->text); - if (!expr_is_yes(prop->visible.expr)) { - fputs(" if ", out); - expr_fprint(prop->visible.expr, out); - } - fputc('\n', out); - break; - case P_DEFAULT: - fputs( " default ", out); - expr_fprint(prop->expr, out); - if (!expr_is_yes(prop->visible.expr)) { - fputs(" if ", out); - expr_fprint(prop->visible.expr, out); - } - fputc('\n', out); - break; - case P_CHOICE: - fputs(" #choice value\n", out); - break; - case P_SELECT: - fputs( " select ", out); - expr_fprint(prop->expr, out); - fputc('\n', out); - break; - case P_RANGE: - fputs( " range ", out); - expr_fprint(prop->expr, out); - fputc('\n', out); - break; - case P_MENU: - fputs( " menu ", out); - print_quoted_string(out, prop->text); - fputc('\n', out); - break; - default: - fprintf(out, " unknown prop %d!\n", prop->type); - break; - } - } - if (menu->help) { - int len = strlen(menu->help); - while (menu->help[--len] == '\n') - menu->help[len] = 0; - fprintf(out, " help\n%s\n", menu->help); - } -} - -void zconfdump(FILE *out) -{ - struct property *prop; - struct symbol *sym; - struct menu *menu; - - menu = rootmenu.list; - while (menu) { - if ((sym = menu->sym)) - print_symbol(out, menu); - else if ((prop = menu->prompt)) { - switch (prop->type) { - case P_COMMENT: - fputs("\ncomment ", out); - print_quoted_string(out, prop->text); - fputs("\n", out); - break; - case P_MENU: - fputs("\nmenu ", out); - print_quoted_string(out, prop->text); - fputs("\n", out); - break; - default: - ; - } - if (!expr_is_yes(prop->visible.expr)) { - fputs(" depends ", out); - expr_fprint(prop->visible.expr, out); - fputc('\n', out); - } - } - - if (menu->list) - menu = menu->list; - else if (menu->next) - menu = menu->next; - else while ((menu = menu->parent)) { - if (menu->prompt && menu->prompt->type == P_MENU) - fputs("\nendmenu\n", out); - if (menu->next) { - menu = menu->next; - break; - } - } - } -} - -#include "zconf.lex.c" -#include "util.c" -#include "confdata.c" -#include "expr.c" -#include "symbol.c" -#include "menu.c" - diff --git a/src/linux/scripts/link-vmlinux.sh b/src/linux/scripts/link-vmlinux.sh deleted file mode 100755 index b490a3d..0000000 --- a/src/linux/scripts/link-vmlinux.sh +++ /dev/null @@ -1,307 +0,0 @@ -#!/bin/sh -# -# link vmlinux -# -# vmlinux is linked from the objects selected by $(KBUILD_VMLINUX_INIT) and -# $(KBUILD_VMLINUX_MAIN). Most are built-in.o files from top-level directories -# in the kernel tree, others are specified in arch/$(ARCH)/Makefile. -# Ordering when linking is important, and $(KBUILD_VMLINUX_INIT) must be first. -# -# vmlinux -# ^ -# | -# +-< $(KBUILD_VMLINUX_INIT) -# | +--< init/version.o + more -# | -# +--< $(KBUILD_VMLINUX_MAIN) -# | +--< drivers/built-in.o mm/built-in.o + more -# | -# +-< ${kallsymso} (see description in KALLSYMS section) -# -# vmlinux version (uname -v) cannot be updated during normal -# descending-into-subdirs phase since we do not yet know if we need to -# update vmlinux. -# Therefore this step is delayed until just before final link of vmlinux. -# -# System.map is generated to document addresses of all kernel symbols - -# Error out on error -set -e - -# Nice output in kbuild format -# Will be supressed by "make -s" -info() -{ - if [ "${quiet}" != "silent_" ]; then - printf " %-7s %s\n" ${1} ${2} - fi -} - -# Thin archive build here makes a final archive with -# symbol table and indexes from vmlinux objects, which can be -# used as input to linker. -# -# Traditional incremental style of link does not require this step -# -# built-in.o output file -# -archive_builtin() -{ - if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then - info AR built-in.o - rm -f built-in.o; - ${AR} rcsT${KBUILD_ARFLAGS} built-in.o \ - ${KBUILD_VMLINUX_INIT} \ - ${KBUILD_VMLINUX_MAIN} - fi -} - -# Link of vmlinux.o used for section mismatch analysis -# ${1} output file -modpost_link() -{ - local objects - - if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then - objects="--whole-archive built-in.o" - else - objects="${KBUILD_VMLINUX_INIT} \ - --start-group \ - ${KBUILD_VMLINUX_MAIN} \ - --end-group" - fi - ${LD} ${LDFLAGS} -r -o ${1} ${objects} -} - -# Link of vmlinux -# ${1} - optional extra .o files -# ${2} - output file -vmlinux_link() -{ - local lds="${objtree}/${KBUILD_LDS}" - local objects - - if [ "${SRCARCH}" != "um" ]; then - if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then - objects="--whole-archive built-in.o ${1}" - else - objects="${KBUILD_VMLINUX_INIT} \ - --start-group \ - ${KBUILD_VMLINUX_MAIN} \ - --end-group \ - ${1}" - fi - - ${LD} ${LDFLAGS} ${LDFLAGS_vmlinux} -o ${2} \ - -T ${lds} ${objects} - else - if [ -n "${CONFIG_THIN_ARCHIVES}" ]; then - objects="-Wl,--whole-archive built-in.o ${1}" - else - objects="${KBUILD_VMLINUX_INIT} \ - -Wl,--start-group \ - ${KBUILD_VMLINUX_MAIN} \ - -Wl,--end-group \ - ${1}" - fi - - ${CC} ${CFLAGS_vmlinux} -o ${2} \ - -Wl,-T,${lds} \ - ${objects} \ - -lutil -lrt -lpthread - rm -f linux - fi -} - - -# Create ${2} .o file with all symbols from the ${1} object file -kallsyms() -{ - info KSYM ${2} - local kallsymopt; - - if [ -n "${CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX}" ]; then - kallsymopt="${kallsymopt} --symbol-prefix=_" - fi - - if [ -n "${CONFIG_KALLSYMS_ALL}" ]; then - kallsymopt="${kallsymopt} --all-symbols" - fi - - if [ -n "${CONFIG_KALLSYMS_ABSOLUTE_PERCPU}" ]; then - kallsymopt="${kallsymopt} --absolute-percpu" - fi - - if [ -n "${CONFIG_KALLSYMS_BASE_RELATIVE}" ]; then - kallsymopt="${kallsymopt} --base-relative" - fi - - if [ -n "${CONFIG_KALLSYMS_USE_DATA_SECTION}" ]; then - kallsymopt="${kallsymopt} --use-data-section" - fi - - local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \ - ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}" - - local afile="`basename ${2} .o`.S" - - ${NM} -n ${1} | scripts/kallsyms ${kallsymopt} > ${afile} - ${CC} ${aflags} -c -o ${2} ${afile} -} - -# Create map file with all symbols from ${1} -# See mksymap for additional details -mksysmap() -{ - ${CONFIG_SHELL} "${srctree}/scripts/mksysmap" ${1} ${2} -} - -sortextable() -{ - ${objtree}/scripts/sortextable ${1} -} - -# Delete output files in case of error -cleanup() -{ - rm -f .old_version - rm -f .tmp_System.map - rm -f .tmp_kallsyms* - rm -f .tmp_version - rm -f .tmp_vmlinux* - rm -f built-in.o - rm -f System.map - rm -f vmlinux - rm -f vmlinux.o -} - -on_exit() -{ - if [ $? -ne 0 ]; then - cleanup - fi -} -trap on_exit EXIT - -on_signals() -{ - exit 1 -} -trap on_signals HUP INT QUIT TERM - -# -# -# Use "make V=1" to debug this script -case "${KBUILD_VERBOSE}" in -*1*) - set -x - ;; -esac - -if [ "$1" = "clean" ]; then - cleanup - exit 0 -fi - -# We need access to CONFIG_ symbols -case "${KCONFIG_CONFIG}" in -*/*) - . "${KCONFIG_CONFIG}" - ;; -*) - # Force using a file from the current directory - . "./${KCONFIG_CONFIG}" -esac - -archive_builtin -if [ -e scripts/mod/modpost ]; then - #link vmlinux.o - info LD vmlinux.o - modpost_link vmlinux.o - - # modpost vmlinux.o to check for section mismatches - ${MAKE} -f "${srctree}/scripts/Makefile.modpost" vmlinux.o -fi - -# Update version -info GEN .version -if [ ! -r .version ]; then - rm -f .version; - echo 1 >.version; -else - mv .version .old_version; - expr 0$(cat .old_version) + 1 >.version; -fi; - -# final build of init/ -${MAKE} -f "${srctree}/scripts/Makefile.build" obj=init GCC_PLUGINS_CFLAGS="${GCC_PLUGINS_CFLAGS}" - -kallsymso="" -kallsyms_vmlinux="" -if [ -n "${CONFIG_KALLSYMS}" ]; then - - # kallsyms support - # Generate section listing all symbols and add it into vmlinux - # It's a three step process: - # 1) Link .tmp_vmlinux1 so it has all symbols and sections, - # but __kallsyms is empty. - # Running kallsyms on that gives us .tmp_kallsyms1.o with - # the right size - # 2) Link .tmp_vmlinux2 so it now has a __kallsyms section of - # the right size, but due to the added section, some - # addresses have shifted. - # From here, we generate a correct .tmp_kallsyms2.o - # 2a) We may use an extra pass as this has been necessary to - # woraround some alignment related bugs. - # KALLSYMS_EXTRA_PASS=1 is used to trigger this. - # 3) The correct ${kallsymso} is linked into the final vmlinux. - # - # a) Verify that the System.map from vmlinux matches the map from - # ${kallsymso}. - - kallsymso=.tmp_kallsyms2.o - kallsyms_vmlinux=.tmp_vmlinux2 - - # step 1 - vmlinux_link "" .tmp_vmlinux1 - kallsyms .tmp_vmlinux1 .tmp_kallsyms1.o - - # step 2 - vmlinux_link .tmp_kallsyms1.o .tmp_vmlinux2 - kallsyms .tmp_vmlinux2 .tmp_kallsyms2.o - - # step 2a - if [ -n "${KALLSYMS_EXTRA_PASS}" ]; then - kallsymso=.tmp_kallsyms3.o - kallsyms_vmlinux=.tmp_vmlinux3 - - vmlinux_link .tmp_kallsyms2.o .tmp_vmlinux3 - - kallsyms .tmp_vmlinux3 .tmp_kallsyms3.o - fi -fi - -info LD vmlinux -vmlinux_link "${kallsymso}" vmlinux - -if [ -n "${CONFIG_BUILDTIME_EXTABLE_SORT}" ]; then - info SORTEX vmlinux - sortextable vmlinux -fi - -info SYSMAP System.map -mksysmap vmlinux System.map - -# step a (see comment above) -if [ -n "${CONFIG_KALLSYMS}" ]; then - mksysmap ${kallsyms_vmlinux} .tmp_System.map - - if ! cmp -s System.map .tmp_System.map; then - echo >&2 Inconsistent kallsyms data - echo >&2 Try "make KALLSYMS_EXTRA_PASS=1" as a workaround - exit 1 - fi -fi - -# We made a new kernel - delete old version file -rm -f .old_version diff --git a/src/linux/scripts/mkcompile_h b/src/linux/scripts/mkcompile_h deleted file mode 100755 index 6fdc97e..0000000 --- a/src/linux/scripts/mkcompile_h +++ /dev/null @@ -1,100 +0,0 @@ -#!/bin/sh - -TARGET=$1 -ARCH=$2 -SMP=$3 -PREEMPT=$4 -CC=$5 - -vecho() { [ "${quiet}" = "silent_" ] || echo "$@" ; } - -# If compile.h exists already and we don't own autoconf.h -# (i.e. we're not the same user who did make *config), don't -# modify compile.h -# So "sudo make install" won't change the "compiled by " -# do "compiled by root" - -if [ -r $TARGET -a ! -O include/generated/autoconf.h ]; then - vecho " SKIPPED $TARGET" - exit 0 -fi - -# Do not expand names -set -f - -# Fix the language to get consistent output -LC_ALL=C -export LC_ALL - -if [ -z "$KBUILD_BUILD_VERSION" ]; then - if [ -r .version ]; then - VERSION=`cat .version` - else - VERSION=0 - echo 0 > .version - fi -else - VERSION=$KBUILD_BUILD_VERSION -fi - -if [ -z "$KBUILD_BUILD_TIMESTAMP" ]; then - TIMESTAMP=`date` -else - TIMESTAMP=$KBUILD_BUILD_TIMESTAMP -fi -if test -z "$KBUILD_BUILD_USER"; then - LINUX_COMPILE_BY=$(whoami | sed 's/\\/\\\\/') -else - LINUX_COMPILE_BY=$KBUILD_BUILD_USER -fi -if test -z "$KBUILD_BUILD_HOST"; then - LINUX_COMPILE_HOST=`hostname` -else - LINUX_COMPILE_HOST=$KBUILD_BUILD_HOST -fi - -UTS_VERSION="#$VERSION" -CONFIG_FLAGS="" -if [ -n "$SMP" ] ; then CONFIG_FLAGS="SMP"; fi -if [ -n "$PREEMPT" ] ; then CONFIG_FLAGS="$CONFIG_FLAGS PREEMPT"; fi -UTS_VERSION="$UTS_VERSION $CONFIG_FLAGS $TIMESTAMP" - -# Truncate to maximum length - -UTS_LEN=64 -UTS_TRUNCATE="cut -b -$UTS_LEN" - -# Generate a temporary compile.h - -( echo /\* This file is auto generated, version $VERSION \*/ - if [ -n "$CONFIG_FLAGS" ] ; then echo "/* $CONFIG_FLAGS */"; fi - - echo \#define UTS_MACHINE \"$ARCH\" - - echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\" - - echo \#define LINUX_COMPILE_BY \"`echo $LINUX_COMPILE_BY | $UTS_TRUNCATE`\" - echo \#define LINUX_COMPILE_HOST \"`echo $LINUX_COMPILE_HOST | $UTS_TRUNCATE`\" - - echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | grep ' version '`\" -) > .tmpcompile - -# Only replace the real compile.h if the new one is different, -# in order to preserve the timestamp and avoid unnecessary -# recompilations. -# We don't consider the file changed if only the date/time changed. -# A kernel config change will increase the generation number, thus -# causing compile.h to be updated (including date/time) due to the -# changed comment in the -# first line. - -if [ -r $TARGET ] && \ - grep -v 'UTS_VERSION' $TARGET > .tmpver.1 && \ - grep -v 'UTS_VERSION' .tmpcompile > .tmpver.2 && \ - cmp -s .tmpver.1 .tmpver.2; then - rm -f .tmpcompile -else - vecho " UPD $TARGET" - mv -f .tmpcompile $TARGET -fi -rm -f .tmpver.1 .tmpver.2 diff --git a/src/linux/scripts/mksysmap b/src/linux/scripts/mksysmap deleted file mode 100755 index a35acc0..0000000 --- a/src/linux/scripts/mksysmap +++ /dev/null @@ -1,44 +0,0 @@ -#!/bin/sh -x -# Based on the vmlinux file create the System.map file -# System.map is used by module-init tools and some debugging -# tools to retrieve the actual addresses of symbols in the kernel. -# -# Usage -# mksysmap vmlinux System.map - - -##### -# Generate System.map (actual filename passed as second argument) - -# $NM produces the following output: -# f0081e80 T alloc_vfsmnt - -# The second row specify the type of the symbol: -# A = Absolute -# B = Uninitialised data (.bss) -# C = Common symbol -# D = Initialised data -# G = Initialised data for small objects -# I = Indirect reference to another symbol -# N = Debugging symbol -# R = Read only -# S = Uninitialised data for small objects -# T = Text code symbol -# U = Undefined symbol -# V = Weak symbol -# W = Weak symbol -# Corresponding small letters are local symbols - -# For System.map filter away: -# a - local absolute symbols -# U - undefined global symbols -# N - debugging symbols -# w - local weak symbols - -# readprofile starts reading symbols when _stext is found, and -# continue until it finds a symbol which is not either of 'T', 't', -# 'W' or 'w'. __crc_ are 'A' and placed in the middle -# so we just ignore them to let readprofile continue to work. -# (At least sparc64 has __crc_ in the middle). - -$NM -n $1 | grep -v '\( [aNUw] \)\|\(__crc_\)\|\( \$[adt]\)\|\( .L\)' > $2 diff --git a/src/linux/scripts/mod/.gitignore b/src/linux/scripts/mod/.gitignore deleted file mode 100644 index cd67845..0000000 --- a/src/linux/scripts/mod/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -elfconfig.h -mk_elfconfig -modpost -modpost.exe -devicetable-offsets.h diff --git a/src/linux/scripts/mod/Makefile b/src/linux/scripts/mod/Makefile deleted file mode 100644 index 19d9bca..0000000 --- a/src/linux/scripts/mod/Makefile +++ /dev/null @@ -1,50 +0,0 @@ -OBJECT_FILES_NON_STANDARD := y - -hostprogs-y := modpost mk_elfconfig -always := $(hostprogs-y) empty.o - -modpost-objs := modpost.o file2alias.o sumversion.o - -devicetable-offsets-file := devicetable-offsets.h - -define sed-y - "/^->/{s:->#\(.*\):/* \1 */:; \ - s:^->\([^ ]*\) [\$$#]*\([-0-9]*\) \(.*\):#define \1 \2 /* \3 */:; \ - s:^->\([^ ]*\) [\$$#]*\([^ ]*\) \(.*\):#define \1 \2 /* \3 */:; \ - s:->::; p;}" -endef - -quiet_cmd_offsets = GEN $@ -define cmd_offsets - (set -e; \ - echo "#ifndef __DEVICETABLE_OFFSETS_H__"; \ - echo "#define __DEVICETABLE_OFFSETS_H__"; \ - echo "/*"; \ - echo " * DO NOT MODIFY."; \ - echo " *"; \ - echo " * This file was generated by Kbuild"; \ - echo " *"; \ - echo " */"; \ - echo ""; \ - sed -ne $(sed-y) $<; \ - echo ""; \ - echo "#endif" ) > $@ -endef - -$(obj)/$(devicetable-offsets-file): $(obj)/devicetable-offsets.s - $(call if_changed,offsets) - -targets += $(devicetable-offsets-file) devicetable-offsets.s - -# dependencies on generated files need to be listed explicitly - -$(obj)/modpost.o $(obj)/file2alias.o $(obj)/sumversion.o: $(obj)/elfconfig.h -$(obj)/file2alias.o: $(obj)/$(devicetable-offsets-file) - -quiet_cmd_elfconfig = MKELF $@ - cmd_elfconfig = $(obj)/mk_elfconfig < $< > $@ - -$(obj)/elfconfig.h: $(obj)/empty.o $(obj)/mk_elfconfig FORCE - $(call if_changed,elfconfig) - -targets += elfconfig.h diff --git a/src/linux/scripts/mod/devicetable-offsets.c b/src/linux/scripts/mod/devicetable-offsets.c deleted file mode 100644 index e4d90e5..0000000 --- a/src/linux/scripts/mod/devicetable-offsets.c +++ /dev/null @@ -1,210 +0,0 @@ -#include -#include - -#define DEVID(devid) DEFINE(SIZE_##devid, sizeof(struct devid)) -#define DEVID_FIELD(devid, field) \ - DEFINE(OFF_##devid##_##field, offsetof(struct devid, field)) - -int main(void) -{ - DEVID(usb_device_id); - DEVID_FIELD(usb_device_id, match_flags); - DEVID_FIELD(usb_device_id, idVendor); - DEVID_FIELD(usb_device_id, idProduct); - DEVID_FIELD(usb_device_id, bcdDevice_lo); - DEVID_FIELD(usb_device_id, bcdDevice_hi); - DEVID_FIELD(usb_device_id, bDeviceClass); - DEVID_FIELD(usb_device_id, bDeviceSubClass); - DEVID_FIELD(usb_device_id, bDeviceProtocol); - DEVID_FIELD(usb_device_id, bInterfaceClass); - DEVID_FIELD(usb_device_id, bInterfaceSubClass); - DEVID_FIELD(usb_device_id, bInterfaceProtocol); - DEVID_FIELD(usb_device_id, bInterfaceNumber); - - DEVID(hid_device_id); - DEVID_FIELD(hid_device_id, bus); - DEVID_FIELD(hid_device_id, group); - DEVID_FIELD(hid_device_id, vendor); - DEVID_FIELD(hid_device_id, product); - - DEVID(ieee1394_device_id); - DEVID_FIELD(ieee1394_device_id, match_flags); - DEVID_FIELD(ieee1394_device_id, vendor_id); - DEVID_FIELD(ieee1394_device_id, model_id); - DEVID_FIELD(ieee1394_device_id, specifier_id); - DEVID_FIELD(ieee1394_device_id, version); - - DEVID(pci_device_id); - DEVID_FIELD(pci_device_id, vendor); - DEVID_FIELD(pci_device_id, device); - DEVID_FIELD(pci_device_id, subvendor); - DEVID_FIELD(pci_device_id, subdevice); - DEVID_FIELD(pci_device_id, class); - DEVID_FIELD(pci_device_id, class_mask); - - DEVID(ccw_device_id); - DEVID_FIELD(ccw_device_id, match_flags); - DEVID_FIELD(ccw_device_id, cu_type); - DEVID_FIELD(ccw_device_id, cu_model); - DEVID_FIELD(ccw_device_id, dev_type); - DEVID_FIELD(ccw_device_id, dev_model); - - DEVID(ap_device_id); - DEVID_FIELD(ap_device_id, dev_type); - - DEVID(css_device_id); - DEVID_FIELD(css_device_id, type); - - DEVID(serio_device_id); - DEVID_FIELD(serio_device_id, type); - DEVID_FIELD(serio_device_id, proto); - DEVID_FIELD(serio_device_id, id); - DEVID_FIELD(serio_device_id, extra); - - DEVID(acpi_device_id); - DEVID_FIELD(acpi_device_id, id); - DEVID_FIELD(acpi_device_id, cls); - DEVID_FIELD(acpi_device_id, cls_msk); - - DEVID(pnp_device_id); - DEVID_FIELD(pnp_device_id, id); - - DEVID(pnp_card_device_id); - DEVID_FIELD(pnp_card_device_id, devs); - - DEVID(pcmcia_device_id); - DEVID_FIELD(pcmcia_device_id, match_flags); - DEVID_FIELD(pcmcia_device_id, manf_id); - DEVID_FIELD(pcmcia_device_id, card_id); - DEVID_FIELD(pcmcia_device_id, func_id); - DEVID_FIELD(pcmcia_device_id, function); - DEVID_FIELD(pcmcia_device_id, device_no); - DEVID_FIELD(pcmcia_device_id, prod_id_hash); - - DEVID(of_device_id); - DEVID_FIELD(of_device_id, name); - DEVID_FIELD(of_device_id, type); - DEVID_FIELD(of_device_id, compatible); - - DEVID(vio_device_id); - DEVID_FIELD(vio_device_id, type); - DEVID_FIELD(vio_device_id, compat); - - DEVID(input_device_id); - DEVID_FIELD(input_device_id, flags); - DEVID_FIELD(input_device_id, bustype); - DEVID_FIELD(input_device_id, vendor); - DEVID_FIELD(input_device_id, product); - DEVID_FIELD(input_device_id, version); - DEVID_FIELD(input_device_id, evbit); - DEVID_FIELD(input_device_id, keybit); - DEVID_FIELD(input_device_id, relbit); - DEVID_FIELD(input_device_id, absbit); - DEVID_FIELD(input_device_id, mscbit); - DEVID_FIELD(input_device_id, ledbit); - DEVID_FIELD(input_device_id, sndbit); - DEVID_FIELD(input_device_id, ffbit); - DEVID_FIELD(input_device_id, swbit); - - DEVID(eisa_device_id); - DEVID_FIELD(eisa_device_id, sig); - - DEVID(parisc_device_id); - DEVID_FIELD(parisc_device_id, hw_type); - DEVID_FIELD(parisc_device_id, hversion); - DEVID_FIELD(parisc_device_id, hversion_rev); - DEVID_FIELD(parisc_device_id, sversion); - - DEVID(sdio_device_id); - DEVID_FIELD(sdio_device_id, class); - DEVID_FIELD(sdio_device_id, vendor); - DEVID_FIELD(sdio_device_id, device); - - DEVID(ssb_device_id); - DEVID_FIELD(ssb_device_id, vendor); - DEVID_FIELD(ssb_device_id, coreid); - DEVID_FIELD(ssb_device_id, revision); - - DEVID(bcma_device_id); - DEVID_FIELD(bcma_device_id, manuf); - DEVID_FIELD(bcma_device_id, id); - DEVID_FIELD(bcma_device_id, rev); - DEVID_FIELD(bcma_device_id, class); - - DEVID(virtio_device_id); - DEVID_FIELD(virtio_device_id, device); - DEVID_FIELD(virtio_device_id, vendor); - - DEVID(hv_vmbus_device_id); - DEVID_FIELD(hv_vmbus_device_id, guid); - - DEVID(i2c_device_id); - DEVID_FIELD(i2c_device_id, name); - - DEVID(spi_device_id); - DEVID_FIELD(spi_device_id, name); - - DEVID(dmi_system_id); - DEVID_FIELD(dmi_system_id, matches); - - DEVID(platform_device_id); - DEVID_FIELD(platform_device_id, name); - - DEVID(mdio_device_id); - DEVID_FIELD(mdio_device_id, phy_id); - DEVID_FIELD(mdio_device_id, phy_id_mask); - - DEVID(zorro_device_id); - DEVID_FIELD(zorro_device_id, id); - - DEVID(isapnp_device_id); - DEVID_FIELD(isapnp_device_id, vendor); - DEVID_FIELD(isapnp_device_id, function); - - DEVID(ipack_device_id); - DEVID_FIELD(ipack_device_id, format); - DEVID_FIELD(ipack_device_id, vendor); - DEVID_FIELD(ipack_device_id, device); - - DEVID(amba_id); - DEVID_FIELD(amba_id, id); - DEVID_FIELD(amba_id, mask); - - DEVID(mips_cdmm_device_id); - DEVID_FIELD(mips_cdmm_device_id, type); - - DEVID(x86_cpu_id); - DEVID_FIELD(x86_cpu_id, feature); - DEVID_FIELD(x86_cpu_id, family); - DEVID_FIELD(x86_cpu_id, model); - DEVID_FIELD(x86_cpu_id, vendor); - - DEVID(cpu_feature); - DEVID_FIELD(cpu_feature, feature); - - DEVID(mei_cl_device_id); - DEVID_FIELD(mei_cl_device_id, name); - DEVID_FIELD(mei_cl_device_id, uuid); - DEVID_FIELD(mei_cl_device_id, version); - - DEVID(rio_device_id); - DEVID_FIELD(rio_device_id, did); - DEVID_FIELD(rio_device_id, vid); - DEVID_FIELD(rio_device_id, asm_did); - DEVID_FIELD(rio_device_id, asm_vid); - - DEVID(ulpi_device_id); - DEVID_FIELD(ulpi_device_id, vendor); - DEVID_FIELD(ulpi_device_id, product); - - DEVID(hda_device_id); - DEVID_FIELD(hda_device_id, vendor_id); - DEVID_FIELD(hda_device_id, rev_id); - DEVID_FIELD(hda_device_id, api_version); - - DEVID(fsl_mc_device_id); - DEVID_FIELD(fsl_mc_device_id, vendor); - DEVID_FIELD(fsl_mc_device_id, obj_type); - - return 0; -} diff --git a/src/linux/scripts/mod/empty.c b/src/linux/scripts/mod/empty.c deleted file mode 100644 index 49839cc..0000000 --- a/src/linux/scripts/mod/empty.c +++ /dev/null @@ -1 +0,0 @@ -/* empty file to figure out endianness / word size */ diff --git a/src/linux/scripts/mod/file2alias.c b/src/linux/scripts/mod/file2alias.c deleted file mode 100644 index 29d6699..0000000 --- a/src/linux/scripts/mod/file2alias.c +++ /dev/null @@ -1,1409 +0,0 @@ -/* Simple code to turn various tables in an ELF file into alias definitions. - * This deals with kernel datastructures where they should be - * dealt with: in the kernel source. - * - * Copyright 2002-2003 Rusty Russell, IBM Corporation - * 2003 Kai Germaschewski - * - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - */ - -#include "modpost.h" -#include "devicetable-offsets.h" - -/* We use the ELF typedefs for kernel_ulong_t but bite the bullet and - * use either stdint.h or inttypes.h for the rest. */ -#if KERNEL_ELFCLASS == ELFCLASS32 -typedef Elf32_Addr kernel_ulong_t; -#define BITS_PER_LONG 32 -#else -typedef Elf64_Addr kernel_ulong_t; -#define BITS_PER_LONG 64 -#endif -#ifdef __sun__ -#include -#else -#include -#endif - -#include -#include - -typedef uint32_t __u32; -typedef uint16_t __u16; -typedef unsigned char __u8; -typedef struct { - __u8 b[16]; -} uuid_le; - -/* Big exception to the "don't include kernel headers into userspace, which - * even potentially has different endianness and word sizes, since - * we handle those differences explicitly below */ -#include "../../include/linux/mod_devicetable.h" - -/* This array collects all instances that use the generic do_table */ -struct devtable { - const char *device_id; /* name of table, __mod___*_device_table. */ - unsigned long id_size; - void *function; -}; - -#define ___cat(a,b) a ## b -#define __cat(a,b) ___cat(a,b) - -/* we need some special handling for this host tool running eventually on - * Darwin. The Mach-O section handling is a bit different than ELF section - * handling. The differnces in detail are: - * a) we have segments which have sections - * b) we need a API call to get the respective section symbols */ -#if defined(__MACH__) -#include - -#define INIT_SECTION(name) do { \ - unsigned long name ## _len; \ - char *__cat(pstart_,name) = getsectdata("__TEXT", \ - #name, &__cat(name,_len)); \ - char *__cat(pstop_,name) = __cat(pstart_,name) + \ - __cat(name, _len); \ - __cat(__start_,name) = (void *)__cat(pstart_,name); \ - __cat(__stop_,name) = (void *)__cat(pstop_,name); \ - } while (0) -#define SECTION(name) __attribute__((section("__TEXT, " #name))) - -struct devtable **__start___devtable, **__stop___devtable; -#else -#define INIT_SECTION(name) /* no-op for ELF */ -#define SECTION(name) __attribute__((section(#name))) - -/* We construct a table of pointers in an ELF section (pointers generally - * go unpadded by gcc). ld creates boundary syms for us. */ -extern struct devtable *__start___devtable[], *__stop___devtable[]; -#endif /* __MACH__ */ - -#if !defined(__used) -# if __GNUC__ == 3 && __GNUC_MINOR__ < 3 -# define __used __attribute__((__unused__)) -# else -# define __used __attribute__((__used__)) -# endif -#endif - -/* Define a variable f that holds the value of field f of struct devid - * based at address m. - */ -#define DEF_FIELD(m, devid, f) \ - typeof(((struct devid *)0)->f) f = TO_NATIVE(*(typeof(f) *)((m) + OFF_##devid##_##f)) -/* Define a variable f that holds the address of field f of struct devid - * based at address m. Due to the way typeof works, for a field of type - * T[N] the variable has type T(*)[N], _not_ T*. - */ -#define DEF_FIELD_ADDR(m, devid, f) \ - typeof(((struct devid *)0)->f) *f = ((m) + OFF_##devid##_##f) - -/* Add a table entry. We test function type matches while we're here. */ -#define ADD_TO_DEVTABLE(device_id, type, function) \ - static struct devtable __cat(devtable,__LINE__) = { \ - device_id + 0*sizeof((function)((const char *)NULL, \ - (void *)NULL, \ - (char *)NULL)), \ - SIZE_##type, (function) }; \ - static struct devtable *SECTION(__devtable) __used \ - __cat(devtable_ptr,__LINE__) = &__cat(devtable,__LINE__) - -#define ADD(str, sep, cond, field) \ -do { \ - strcat(str, sep); \ - if (cond) \ - sprintf(str + strlen(str), \ - sizeof(field) == 1 ? "%02X" : \ - sizeof(field) == 2 ? "%04X" : \ - sizeof(field) == 4 ? "%08X" : "", \ - field); \ - else \ - sprintf(str + strlen(str), "*"); \ -} while(0) - -/* End in a wildcard, for future extension */ -static inline void add_wildcard(char *str) -{ - int len = strlen(str); - - if (str[len - 1] != '*') - strcat(str + len, "*"); -} - -static inline void add_uuid(char *str, uuid_le uuid) -{ - int len = strlen(str); - - sprintf(str + len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", - uuid.b[3], uuid.b[2], uuid.b[1], uuid.b[0], - uuid.b[5], uuid.b[4], uuid.b[7], uuid.b[6], - uuid.b[8], uuid.b[9], uuid.b[10], uuid.b[11], - uuid.b[12], uuid.b[13], uuid.b[14], uuid.b[15]); -} - -/** - * Check that sizeof(device_id type) are consistent with size of section - * in .o file. If in-consistent then userspace and kernel does not agree - * on actual size which is a bug. - * Also verify that the final entry in the table is all zeros. - * Ignore both checks if build host differ from target host and size differs. - **/ -static void device_id_check(const char *modname, const char *device_id, - unsigned long size, unsigned long id_size, - void *symval) -{ - int i; - - if (size % id_size || size < id_size) { - fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo " - "of the size of " - "section __mod_%s___device_table=%lu.\n" - "Fix definition of struct %s_device_id " - "in mod_devicetable.h\n", - modname, device_id, id_size, device_id, size, device_id); - } - /* Verify last one is a terminator */ - for (i = 0; i < id_size; i++ ) { - if (*(uint8_t*)(symval+size-id_size+i)) { - fprintf(stderr,"%s: struct %s_device_id is %lu bytes. " - "The last of %lu is:\n", - modname, device_id, id_size, size / id_size); - for (i = 0; i < id_size; i++ ) - fprintf(stderr,"0x%02x ", - *(uint8_t*)(symval+size-id_size+i) ); - fprintf(stderr,"\n"); - fatal("%s: struct %s_device_id is not terminated " - "with a NULL entry!\n", modname, device_id); - } - } -} - -/* USB is special because the bcdDevice can be matched against a numeric range */ -/* Looks like "usb:vNpNdNdcNdscNdpNicNiscNipNinN" */ -static void do_usb_entry(void *symval, - unsigned int bcdDevice_initial, int bcdDevice_initial_digits, - unsigned char range_lo, unsigned char range_hi, - unsigned char max, struct module *mod) -{ - char alias[500]; - DEF_FIELD(symval, usb_device_id, match_flags); - DEF_FIELD(symval, usb_device_id, idVendor); - DEF_FIELD(symval, usb_device_id, idProduct); - DEF_FIELD(symval, usb_device_id, bcdDevice_lo); - DEF_FIELD(symval, usb_device_id, bDeviceClass); - DEF_FIELD(symval, usb_device_id, bDeviceSubClass); - DEF_FIELD(symval, usb_device_id, bDeviceProtocol); - DEF_FIELD(symval, usb_device_id, bInterfaceClass); - DEF_FIELD(symval, usb_device_id, bInterfaceSubClass); - DEF_FIELD(symval, usb_device_id, bInterfaceProtocol); - DEF_FIELD(symval, usb_device_id, bInterfaceNumber); - - strcpy(alias, "usb:"); - ADD(alias, "v", match_flags&USB_DEVICE_ID_MATCH_VENDOR, - idVendor); - ADD(alias, "p", match_flags&USB_DEVICE_ID_MATCH_PRODUCT, - idProduct); - - strcat(alias, "d"); - if (bcdDevice_initial_digits) - sprintf(alias + strlen(alias), "%0*X", - bcdDevice_initial_digits, bcdDevice_initial); - if (range_lo == range_hi) - sprintf(alias + strlen(alias), "%X", range_lo); - else if (range_lo > 0 || range_hi < max) { - if (range_lo > 0x9 || range_hi < 0xA) - sprintf(alias + strlen(alias), - "[%X-%X]", - range_lo, - range_hi); - else { - sprintf(alias + strlen(alias), - range_lo < 0x9 ? "[%X-9" : "[%X", - range_lo); - sprintf(alias + strlen(alias), - range_hi > 0xA ? "A-%X]" : "%X]", - range_hi); - } - } - if (bcdDevice_initial_digits < (sizeof(bcdDevice_lo) * 2 - 1)) - strcat(alias, "*"); - - ADD(alias, "dc", match_flags&USB_DEVICE_ID_MATCH_DEV_CLASS, - bDeviceClass); - ADD(alias, "dsc", match_flags&USB_DEVICE_ID_MATCH_DEV_SUBCLASS, - bDeviceSubClass); - ADD(alias, "dp", match_flags&USB_DEVICE_ID_MATCH_DEV_PROTOCOL, - bDeviceProtocol); - ADD(alias, "ic", match_flags&USB_DEVICE_ID_MATCH_INT_CLASS, - bInterfaceClass); - ADD(alias, "isc", match_flags&USB_DEVICE_ID_MATCH_INT_SUBCLASS, - bInterfaceSubClass); - ADD(alias, "ip", match_flags&USB_DEVICE_ID_MATCH_INT_PROTOCOL, - bInterfaceProtocol); - ADD(alias, "in", match_flags&USB_DEVICE_ID_MATCH_INT_NUMBER, - bInterfaceNumber); - - add_wildcard(alias); - buf_printf(&mod->dev_table_buf, - "MODULE_ALIAS(\"%s\");\n", alias); -} - -/* Handles increment/decrement of BCD formatted integers */ -/* Returns the previous value, so it works like i++ or i-- */ -static unsigned int incbcd(unsigned int *bcd, - int inc, - unsigned char max, - size_t chars) -{ - unsigned int init = *bcd, i, j; - unsigned long long c, dec = 0; - - /* If bcd is not in BCD format, just increment */ - if (max > 0x9) { - *bcd += inc; - return init; - } - - /* Convert BCD to Decimal */ - for (i=0 ; i < chars ; i++) { - c = (*bcd >> (i << 2)) & 0xf; - c = c > 9 ? 9 : c; /* force to bcd just in case */ - for (j=0 ; j < i ; j++) - c = c * 10; - dec += c; - } - - /* Do our increment/decrement */ - dec += inc; - *bcd = 0; - - /* Convert back to BCD */ - for (i=0 ; i < chars ; i++) { - for (c=1,j=0 ; j < i ; j++) - c = c * 10; - c = (dec / c) % 10; - *bcd += c << (i << 2); - } - return init; -} - -static void do_usb_entry_multi(void *symval, struct module *mod) -{ - unsigned int devlo, devhi; - unsigned char chi, clo, max; - int ndigits; - - DEF_FIELD(symval, usb_device_id, match_flags); - DEF_FIELD(symval, usb_device_id, idVendor); - DEF_FIELD(symval, usb_device_id, idProduct); - DEF_FIELD(symval, usb_device_id, bcdDevice_lo); - DEF_FIELD(symval, usb_device_id, bcdDevice_hi); - DEF_FIELD(symval, usb_device_id, bDeviceClass); - DEF_FIELD(symval, usb_device_id, bInterfaceClass); - - devlo = match_flags & USB_DEVICE_ID_MATCH_DEV_LO ? - bcdDevice_lo : 0x0U; - devhi = match_flags & USB_DEVICE_ID_MATCH_DEV_HI ? - bcdDevice_hi : ~0x0U; - - /* Figure out if this entry is in bcd or hex format */ - max = 0x9; /* Default to decimal format */ - for (ndigits = 0 ; ndigits < sizeof(bcdDevice_lo) * 2 ; ndigits++) { - clo = (devlo >> (ndigits << 2)) & 0xf; - chi = ((devhi > 0x9999 ? 0x9999 : devhi) >> (ndigits << 2)) & 0xf; - if (clo > max || chi > max) { - max = 0xf; - break; - } - } - - /* - * Some modules (visor) have empty slots as placeholder for - * run-time specification that results in catch-all alias - */ - if (!(idVendor | idProduct | bDeviceClass | bInterfaceClass)) - return; - - /* Convert numeric bcdDevice range into fnmatch-able pattern(s) */ - for (ndigits = sizeof(bcdDevice_lo) * 2 - 1; devlo <= devhi; ndigits--) { - clo = devlo & 0xf; - chi = devhi & 0xf; - if (chi > max) /* If we are in bcd mode, truncate if necessary */ - chi = max; - devlo >>= 4; - devhi >>= 4; - - if (devlo == devhi || !ndigits) { - do_usb_entry(symval, devlo, ndigits, clo, chi, max, mod); - break; - } - - if (clo > 0x0) - do_usb_entry(symval, - incbcd(&devlo, 1, max, - sizeof(bcdDevice_lo) * 2), - ndigits, clo, max, max, mod); - - if (chi < max) - do_usb_entry(symval, - incbcd(&devhi, -1, max, - sizeof(bcdDevice_lo) * 2), - ndigits, 0x0, chi, max, mod); - } -} - -static void do_usb_table(void *symval, unsigned long size, - struct module *mod) -{ - unsigned int i; - const unsigned long id_size = SIZE_usb_device_id; - - device_id_check(mod->name, "usb", size, id_size, symval); - - /* Leave last one: it's the terminator. */ - size -= id_size; - - for (i = 0; i < size; i += id_size) - do_usb_entry_multi(symval + i, mod); -} - -static void do_of_entry_multi(void *symval, struct module *mod) -{ - char alias[500]; - int len; - char *tmp; - - DEF_FIELD_ADDR(symval, of_device_id, name); - DEF_FIELD_ADDR(symval, of_device_id, type); - DEF_FIELD_ADDR(symval, of_device_id, compatible); - - len = sprintf(alias, "of:N%sT%s", (*name)[0] ? *name : "*", - (*type)[0] ? *type : "*"); - - if ((*compatible)[0]) - sprintf(&alias[len], "%sC%s", (*type)[0] ? "*" : "", - *compatible); - - /* Replace all whitespace with underscores */ - for (tmp = alias; tmp && *tmp; tmp++) - if (isspace(*tmp)) - *tmp = '_'; - - buf_printf(&mod->dev_table_buf, "MODULE_ALIAS(\"%s\");\n", alias); - strcat(alias, "C"); - add_wildcard(alias); - buf_printf(&mod->dev_table_buf, "MODULE_ALIAS(\"%s\");\n", alias); -} - -static void do_of_table(void *symval, unsigned long size, - struct module *mod) -{ - unsigned int i; - const unsigned long id_size = SIZE_of_device_id; - - device_id_check(mod->name, "of", size, id_size, symval); - - /* Leave last one: it's the terminator. */ - size -= id_size; - - for (i = 0; i < size; i += id_size) - do_of_entry_multi(symval + i, mod); -} - -/* Looks like: hid:bNvNpN */ -static int do_hid_entry(const char *filename, - void *symval, char *alias) -{ - DEF_FIELD(symval, hid_device_id, bus); - DEF_FIELD(symval, hid_device_id, group); - DEF_FIELD(symval, hid_device_id, vendor); - DEF_FIELD(symval, hid_device_id, product); - - sprintf(alias, "hid:"); - ADD(alias, "b", bus != HID_BUS_ANY, bus); - ADD(alias, "g", group != HID_GROUP_ANY, group); - ADD(alias, "v", vendor != HID_ANY_ID, vendor); - ADD(alias, "p", product != HID_ANY_ID, product); - - return 1; -} -ADD_TO_DEVTABLE("hid", hid_device_id, do_hid_entry); - -/* Looks like: ieee1394:venNmoNspNverN */ -static int do_ieee1394_entry(const char *filename, - void *symval, char *alias) -{ - DEF_FIELD(symval, ieee1394_device_id, match_flags); - DEF_FIELD(symval, ieee1394_device_id, vendor_id); - DEF_FIELD(symval, ieee1394_device_id, model_id); - DEF_FIELD(symval, ieee1394_device_id, specifier_id); - DEF_FIELD(symval, ieee1394_device_id, version); - - strcpy(alias, "ieee1394:"); - ADD(alias, "ven", match_flags & IEEE1394_MATCH_VENDOR_ID, - vendor_id); - ADD(alias, "mo", match_flags & IEEE1394_MATCH_MODEL_ID, - model_id); - ADD(alias, "sp", match_flags & IEEE1394_MATCH_SPECIFIER_ID, - specifier_id); - ADD(alias, "ver", match_flags & IEEE1394_MATCH_VERSION, - version); - - add_wildcard(alias); - return 1; -} -ADD_TO_DEVTABLE("ieee1394", ieee1394_device_id, do_ieee1394_entry); - -/* Looks like: pci:vNdNsvNsdNbcNscNiN. */ -static int do_pci_entry(const char *filename, - void *symval, char *alias) -{ - /* Class field can be divided into these three. */ - unsigned char baseclass, subclass, interface, - baseclass_mask, subclass_mask, interface_mask; - - DEF_FIELD(symval, pci_device_id, vendor); - DEF_FIELD(symval, pci_device_id, device); - DEF_FIELD(symval, pci_device_id, subvendor); - DEF_FIELD(symval, pci_device_id, subdevice); - DEF_FIELD(symval, pci_device_id, class); - DEF_FIELD(symval, pci_device_id, class_mask); - - strcpy(alias, "pci:"); - ADD(alias, "v", vendor != PCI_ANY_ID, vendor); - ADD(alias, "d", device != PCI_ANY_ID, device); - ADD(alias, "sv", subvendor != PCI_ANY_ID, subvendor); - ADD(alias, "sd", subdevice != PCI_ANY_ID, subdevice); - - baseclass = (class) >> 16; - baseclass_mask = (class_mask) >> 16; - subclass = (class) >> 8; - subclass_mask = (class_mask) >> 8; - interface = class; - interface_mask = class_mask; - - if ((baseclass_mask != 0 && baseclass_mask != 0xFF) - || (subclass_mask != 0 && subclass_mask != 0xFF) - || (interface_mask != 0 && interface_mask != 0xFF)) { - warn("Can't handle masks in %s:%04X\n", - filename, class_mask); - return 0; - } - - ADD(alias, "bc", baseclass_mask == 0xFF, baseclass); - ADD(alias, "sc", subclass_mask == 0xFF, subclass); - ADD(alias, "i", interface_mask == 0xFF, interface); - add_wildcard(alias); - return 1; -} -ADD_TO_DEVTABLE("pci", pci_device_id, do_pci_entry); - -/* looks like: "ccw:tNmNdtNdmN" */ -static int do_ccw_entry(const char *filename, - void *symval, char *alias) -{ - DEF_FIELD(symval, ccw_device_id, match_flags); - DEF_FIELD(symval, ccw_device_id, cu_type); - DEF_FIELD(symval, ccw_device_id, cu_model); - DEF_FIELD(symval, ccw_device_id, dev_type); - DEF_FIELD(symval, ccw_device_id, dev_model); - - strcpy(alias, "ccw:"); - ADD(alias, "t", match_flags&CCW_DEVICE_ID_MATCH_CU_TYPE, - cu_type); - ADD(alias, "m", match_flags&CCW_DEVICE_ID_MATCH_CU_MODEL, - cu_model); - ADD(alias, "dt", match_flags&CCW_DEVICE_ID_MATCH_DEVICE_TYPE, - dev_type); - ADD(alias, "dm", match_flags&CCW_DEVICE_ID_MATCH_DEVICE_MODEL, - dev_model); - add_wildcard(alias); - return 1; -} -ADD_TO_DEVTABLE("ccw", ccw_device_id, do_ccw_entry); - -/* looks like: "ap:tN" */ -static int do_ap_entry(const char *filename, - void *symval, char *alias) -{ - DEF_FIELD(symval, ap_device_id, dev_type); - - sprintf(alias, "ap:t%02X*", dev_type); - return 1; -} -ADD_TO_DEVTABLE("ap", ap_device_id, do_ap_entry); - -/* looks like: "css:tN" */ -static int do_css_entry(const char *filename, - void *symval, char *alias) -{ - DEF_FIELD(symval, css_device_id, type); - - sprintf(alias, "css:t%01X", type); - return 1; -} -ADD_TO_DEVTABLE("css", css_device_id, do_css_entry); - -/* Looks like: "serio:tyNprNidNexN" */ -static int do_serio_entry(const char *filename, - void *symval, char *alias) -{ - DEF_FIELD(symval, serio_device_id, type); - DEF_FIELD(symval, serio_device_id, proto); - DEF_FIELD(symval, serio_device_id, id); - DEF_FIELD(symval, serio_device_id, extra); - - strcpy(alias, "serio:"); - ADD(alias, "ty", type != SERIO_ANY, type); - ADD(alias, "pr", proto != SERIO_ANY, proto); - ADD(alias, "id", id != SERIO_ANY, id); - ADD(alias, "ex", extra != SERIO_ANY, extra); - - add_wildcard(alias); - return 1; -} -ADD_TO_DEVTABLE("serio", serio_device_id, do_serio_entry); - -/* looks like: "acpi:ACPI0003" or "acpi:PNP0C0B" or "acpi:LNXVIDEO" or - * "acpi:bbsspp" (bb=base-class, ss=sub-class, pp=prog-if) - * - * NOTE: Each driver should use one of the following : _HID, _CIDs - * or _CLS. Also, bb, ss, and pp can be substituted with ?? - * as don't care byte. - */ -static int do_acpi_entry(const char *filename, - void *symval, char *alias) -{ - DEF_FIELD_ADDR(symval, acpi_device_id, id); - DEF_FIELD_ADDR(symval, acpi_device_id, cls); - DEF_FIELD_ADDR(symval, acpi_device_id, cls_msk); - - if (id && strlen((const char *)*id)) - sprintf(alias, "acpi*:%s:*", *id); - else if (cls) { - int i, byte_shift, cnt = 0; - unsigned int msk; - - sprintf(&alias[cnt], "acpi*:"); - cnt = 6; - for (i = 1; i <= 3; i++) { - byte_shift = 8 * (3-i); - msk = (*cls_msk >> byte_shift) & 0xFF; - if (msk) - sprintf(&alias[cnt], "%02x", - (*cls >> byte_shift) & 0xFF); - else - sprintf(&alias[cnt], "??"); - cnt += 2; - } - sprintf(&alias[cnt], ":*"); - } - return 1; -} -ADD_TO_DEVTABLE("acpi", acpi_device_id, do_acpi_entry); - -/* looks like: "pnp:dD" */ -static void do_pnp_device_entry(void *symval, unsigned long size, - struct module *mod) -{ - const unsigned long id_size = SIZE_pnp_device_id; - const unsigned int count = (size / id_size)-1; - unsigned int i; - - device_id_check(mod->name, "pnp", size, id_size, symval); - - for (i = 0; i < count; i++) { - DEF_FIELD_ADDR(symval + i*id_size, pnp_device_id, id); - char acpi_id[sizeof(*id)]; - int j; - - buf_printf(&mod->dev_table_buf, - "MODULE_ALIAS(\"pnp:d%s*\");\n", *id); - - /* fix broken pnp bus lowercasing */ - for (j = 0; j < sizeof(acpi_id); j++) - acpi_id[j] = toupper((*id)[j]); - buf_printf(&mod->dev_table_buf, - "MODULE_ALIAS(\"acpi*:%s:*\");\n", acpi_id); - } -} - -/* looks like: "pnp:dD" for every device of the card */ -static void do_pnp_card_entries(void *symval, unsigned long size, - struct module *mod) -{ - const unsigned long id_size = SIZE_pnp_card_device_id; - const unsigned int count = (size / id_size)-1; - unsigned int i; - - device_id_check(mod->name, "pnp", size, id_size, symval); - - for (i = 0; i < count; i++) { - unsigned int j; - DEF_FIELD_ADDR(symval + i*id_size, pnp_card_device_id, devs); - - for (j = 0; j < PNP_MAX_DEVICES; j++) { - const char *id = (char *)(*devs)[j].id; - int i2, j2; - int dup = 0; - - if (!id[0]) - break; - - /* find duplicate, already added value */ - for (i2 = 0; i2 < i && !dup; i2++) { - DEF_FIELD_ADDR(symval + i2*id_size, pnp_card_device_id, devs); - - for (j2 = 0; j2 < PNP_MAX_DEVICES; j2++) { - const char *id2 = (char *)(*devs)[j2].id; - - if (!id2[0]) - break; - - if (!strcmp(id, id2)) { - dup = 1; - break; - } - } - } - - /* add an individual alias for every device entry */ - if (!dup) { - char acpi_id[PNP_ID_LEN]; - int k; - - buf_printf(&mod->dev_table_buf, - "MODULE_ALIAS(\"pnp:d%s*\");\n", id); - - /* fix broken pnp bus lowercasing */ - for (k = 0; k < sizeof(acpi_id); k++) - acpi_id[k] = toupper(id[k]); - buf_printf(&mod->dev_table_buf, - "MODULE_ALIAS(\"acpi*:%s:*\");\n", acpi_id); - } - } - } -} - -/* Looks like: pcmcia:mNcNfNfnNpfnNvaNvbNvcNvdN. */ -static int do_pcmcia_entry(const char *filename, - void *symval, char *alias) -{ - unsigned int i; - DEF_FIELD(symval, pcmcia_device_id, match_flags); - DEF_FIELD(symval, pcmcia_device_id, manf_id); - DEF_FIELD(symval, pcmcia_device_id, card_id); - DEF_FIELD(symval, pcmcia_device_id, func_id); - DEF_FIELD(symval, pcmcia_device_id, function); - DEF_FIELD(symval, pcmcia_device_id, device_no); - DEF_FIELD_ADDR(symval, pcmcia_device_id, prod_id_hash); - - for (i=0; i<4; i++) { - (*prod_id_hash)[i] = TO_NATIVE((*prod_id_hash)[i]); - } - - strcpy(alias, "pcmcia:"); - ADD(alias, "m", match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID, - manf_id); - ADD(alias, "c", match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID, - card_id); - ADD(alias, "f", match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID, - func_id); - ADD(alias, "fn", match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION, - function); - ADD(alias, "pfn", match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO, - device_no); - ADD(alias, "pa", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1, (*prod_id_hash)[0]); - ADD(alias, "pb", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2, (*prod_id_hash)[1]); - ADD(alias, "pc", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3, (*prod_id_hash)[2]); - ADD(alias, "pd", match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4, (*prod_id_hash)[3]); - - add_wildcard(alias); - return 1; -} -ADD_TO_DEVTABLE("pcmcia", pcmcia_device_id, do_pcmcia_entry); - -static int do_vio_entry(const char *filename, void *symval, - char *alias) -{ - char *tmp; - DEF_FIELD_ADDR(symval, vio_device_id, type); - DEF_FIELD_ADDR(symval, vio_device_id, compat); - - sprintf(alias, "vio:T%sS%s", (*type)[0] ? *type : "*", - (*compat)[0] ? *compat : "*"); - - /* Replace all whitespace with underscores */ - for (tmp = alias; tmp && *tmp; tmp++) - if (isspace (*tmp)) - *tmp = '_'; - - add_wildcard(alias); - return 1; -} -ADD_TO_DEVTABLE("vio", vio_device_id, do_vio_entry); - -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) - -static void do_input(char *alias, - kernel_ulong_t *arr, unsigned int min, unsigned int max) -{ - unsigned int i; - - for (i = min / BITS_PER_LONG; i < max / BITS_PER_LONG + 1; i++) - arr[i] = TO_NATIVE(arr[i]); - for (i = min; i < max; i++) - if (arr[i / BITS_PER_LONG] & (1L << (i%BITS_PER_LONG))) - sprintf(alias + strlen(alias), "%X,*", i); -} - -/* input:b0v0p0e0-eXkXrXaXmXlXsXfXwX where X is comma-separated %02X. */ -static int do_input_entry(const char *filename, void *symval, - char *alias) -{ - DEF_FIELD(symval, input_device_id, flags); - DEF_FIELD(symval, input_device_id, bustype); - DEF_FIELD(symval, input_device_id, vendor); - DEF_FIELD(symval, input_device_id, product); - DEF_FIELD(symval, input_device_id, version); - DEF_FIELD_ADDR(symval, input_device_id, evbit); - DEF_FIELD_ADDR(symval, input_device_id, keybit); - DEF_FIELD_ADDR(symval, input_device_id, relbit); - DEF_FIELD_ADDR(symval, input_device_id, absbit); - DEF_FIELD_ADDR(symval, input_device_id, mscbit); - DEF_FIELD_ADDR(symval, input_device_id, ledbit); - DEF_FIELD_ADDR(symval, input_device_id, sndbit); - DEF_FIELD_ADDR(symval, input_device_id, ffbit); - DEF_FIELD_ADDR(symval, input_device_id, swbit); - - sprintf(alias, "input:"); - - ADD(alias, "b", flags & INPUT_DEVICE_ID_MATCH_BUS, bustype); - ADD(alias, "v", flags & INPUT_DEVICE_ID_MATCH_VENDOR, vendor); - ADD(alias, "p", flags & INPUT_DEVICE_ID_MATCH_PRODUCT, product); - ADD(alias, "e", flags & INPUT_DEVICE_ID_MATCH_VERSION, version); - - sprintf(alias + strlen(alias), "-e*"); - if (flags & INPUT_DEVICE_ID_MATCH_EVBIT) - do_input(alias, *evbit, 0, INPUT_DEVICE_ID_EV_MAX); - sprintf(alias + strlen(alias), "k*"); - if (flags & INPUT_DEVICE_ID_MATCH_KEYBIT) - do_input(alias, *keybit, - INPUT_DEVICE_ID_KEY_MIN_INTERESTING, - INPUT_DEVICE_ID_KEY_MAX); - sprintf(alias + strlen(alias), "r*"); - if (flags & INPUT_DEVICE_ID_MATCH_RELBIT) - do_input(alias, *relbit, 0, INPUT_DEVICE_ID_REL_MAX); - sprintf(alias + strlen(alias), "a*"); - if (flags & INPUT_DEVICE_ID_MATCH_ABSBIT) - do_input(alias, *absbit, 0, INPUT_DEVICE_ID_ABS_MAX); - sprintf(alias + strlen(alias), "m*"); - if (flags & INPUT_DEVICE_ID_MATCH_MSCIT) - do_input(alias, *mscbit, 0, INPUT_DEVICE_ID_MSC_MAX); - sprintf(alias + strlen(alias), "l*"); - if (flags & INPUT_DEVICE_ID_MATCH_LEDBIT) - do_input(alias, *ledbit, 0, INPUT_DEVICE_ID_LED_MAX); - sprintf(alias + strlen(alias), "s*"); - if (flags & INPUT_DEVICE_ID_MATCH_SNDBIT) - do_input(alias, *sndbit, 0, INPUT_DEVICE_ID_SND_MAX); - sprintf(alias + strlen(alias), "f*"); - if (flags & INPUT_DEVICE_ID_MATCH_FFBIT) - do_input(alias, *ffbit, 0, INPUT_DEVICE_ID_FF_MAX); - sprintf(alias + strlen(alias), "w*"); - if (flags & INPUT_DEVICE_ID_MATCH_SWBIT) - do_input(alias, *swbit, 0, INPUT_DEVICE_ID_SW_MAX); - return 1; -} -ADD_TO_DEVTABLE("input", input_device_id, do_input_entry); - -static int do_eisa_entry(const char *filename, void *symval, - char *alias) -{ - DEF_FIELD_ADDR(symval, eisa_device_id, sig); - if (sig[0]) - sprintf(alias, EISA_DEVICE_MODALIAS_FMT "*", *sig); - else - strcat(alias, "*"); - return 1; -} -ADD_TO_DEVTABLE("eisa", eisa_device_id, do_eisa_entry); - -/* Looks like: parisc:tNhvNrevNsvN */ -static int do_parisc_entry(const char *filename, void *symval, - char *alias) -{ - DEF_FIELD(symval, parisc_device_id, hw_type); - DEF_FIELD(symval, parisc_device_id, hversion); - DEF_FIELD(symval, parisc_device_id, hversion_rev); - DEF_FIELD(symval, parisc_device_id, sversion); - - strcpy(alias, "parisc:"); - ADD(alias, "t", hw_type != PA_HWTYPE_ANY_ID, hw_type); - ADD(alias, "hv", hversion != PA_HVERSION_ANY_ID, hversion); - ADD(alias, "rev", hversion_rev != PA_HVERSION_REV_ANY_ID, hversion_rev); - ADD(alias, "sv", sversion != PA_SVERSION_ANY_ID, sversion); - - add_wildcard(alias); - return 1; -} -ADD_TO_DEVTABLE("parisc", parisc_device_id, do_parisc_entry); - -/* Looks like: sdio:cNvNdN. */ -static int do_sdio_entry(const char *filename, - void *symval, char *alias) -{ - DEF_FIELD(symval, sdio_device_id, class); - DEF_FIELD(symval, sdio_device_id, vendor); - DEF_FIELD(symval, sdio_device_id, device); - - strcpy(alias, "sdio:"); - ADD(alias, "c", class != (__u8)SDIO_ANY_ID, class); - ADD(alias, "v", vendor != (__u16)SDIO_ANY_ID, vendor); - ADD(alias, "d", device != (__u16)SDIO_ANY_ID, device); - add_wildcard(alias); - return 1; -} -ADD_TO_DEVTABLE("sdio", sdio_device_id, do_sdio_entry); - -/* Looks like: ssb:vNidNrevN. */ -static int do_ssb_entry(const char *filename, - void *symval, char *alias) -{ - DEF_FIELD(symval, ssb_device_id, vendor); - DEF_FIELD(symval, ssb_device_id, coreid); - DEF_FIELD(symval, ssb_device_id, revision); - - strcpy(alias, "ssb:"); - ADD(alias, "v", vendor != SSB_ANY_VENDOR, vendor); - ADD(alias, "id", coreid != SSB_ANY_ID, coreid); - ADD(alias, "rev", revision != SSB_ANY_REV, revision); - add_wildcard(alias); - return 1; -} -ADD_TO_DEVTABLE("ssb", ssb_device_id, do_ssb_entry); - -/* Looks like: bcma:mNidNrevNclN. */ -static int do_bcma_entry(const char *filename, - void *symval, char *alias) -{ - DEF_FIELD(symval, bcma_device_id, manuf); - DEF_FIELD(symval, bcma_device_id, id); - DEF_FIELD(symval, bcma_device_id, rev); - DEF_FIELD(symval, bcma_device_id, class); - - strcpy(alias, "bcma:"); - ADD(alias, "m", manuf != BCMA_ANY_MANUF, manuf); - ADD(alias, "id", id != BCMA_ANY_ID, id); - ADD(alias, "rev", rev != BCMA_ANY_REV, rev); - ADD(alias, "cl", class != BCMA_ANY_CLASS, class); - add_wildcard(alias); - return 1; -} -ADD_TO_DEVTABLE("bcma", bcma_device_id, do_bcma_entry); - -/* Looks like: virtio:dNvN */ -static int do_virtio_entry(const char *filename, void *symval, - char *alias) -{ - DEF_FIELD(symval, virtio_device_id, device); - DEF_FIELD(symval, virtio_device_id, vendor); - - strcpy(alias, "virtio:"); - ADD(alias, "d", device != VIRTIO_DEV_ANY_ID, device); - ADD(alias, "v", vendor != VIRTIO_DEV_ANY_ID, vendor); - - add_wildcard(alias); - return 1; -} -ADD_TO_DEVTABLE("virtio", virtio_device_id, do_virtio_entry); - -/* - * Looks like: vmbus:guid - * Each byte of the guid will be represented by two hex characters - * in the name. - */ - -static int do_vmbus_entry(const char *filename, void *symval, - char *alias) -{ - int i; - DEF_FIELD_ADDR(symval, hv_vmbus_device_id, guid); - char guid_name[(sizeof(*guid) + 1) * 2]; - - for (i = 0; i < (sizeof(*guid) * 2); i += 2) - sprintf(&guid_name[i], "%02x", TO_NATIVE((guid->b)[i/2])); - - strcpy(alias, "vmbus:"); - strcat(alias, guid_name); - - return 1; -} -ADD_TO_DEVTABLE("vmbus", hv_vmbus_device_id, do_vmbus_entry); - -/* Looks like: i2c:S */ -static int do_i2c_entry(const char *filename, void *symval, - char *alias) -{ - DEF_FIELD_ADDR(symval, i2c_device_id, name); - sprintf(alias, I2C_MODULE_PREFIX "%s", *name); - - return 1; -} -ADD_TO_DEVTABLE("i2c", i2c_device_id, do_i2c_entry); - -/* Looks like: spi:S */ -static int do_spi_entry(const char *filename, void *symval, - char *alias) -{ - DEF_FIELD_ADDR(symval, spi_device_id, name); - sprintf(alias, SPI_MODULE_PREFIX "%s", *name); - - return 1; -} -ADD_TO_DEVTABLE("spi", spi_device_id, do_spi_entry); - -static const struct dmifield { - const char *prefix; - int field; -} dmi_fields[] = { - { "bvn", DMI_BIOS_VENDOR }, - { "bvr", DMI_BIOS_VERSION }, - { "bd", DMI_BIOS_DATE }, - { "svn", DMI_SYS_VENDOR }, - { "pn", DMI_PRODUCT_NAME }, - { "pvr", DMI_PRODUCT_VERSION }, - { "rvn", DMI_BOARD_VENDOR }, - { "rn", DMI_BOARD_NAME }, - { "rvr", DMI_BOARD_VERSION }, - { "cvn", DMI_CHASSIS_VENDOR }, - { "ct", DMI_CHASSIS_TYPE }, - { "cvr", DMI_CHASSIS_VERSION }, - { NULL, DMI_NONE } -}; - -static void dmi_ascii_filter(char *d, const char *s) -{ - /* Filter out characters we don't want to see in the modalias string */ - for (; *s; s++) - if (*s > ' ' && *s < 127 && *s != ':') - *(d++) = *s; - - *d = 0; -} - - -static int do_dmi_entry(const char *filename, void *symval, - char *alias) -{ - int i, j; - DEF_FIELD_ADDR(symval, dmi_system_id, matches); - sprintf(alias, "dmi*"); - - for (i = 0; i < ARRAY_SIZE(dmi_fields); i++) { - for (j = 0; j < 4; j++) { - if ((*matches)[j].slot && - (*matches)[j].slot == dmi_fields[i].field) { - sprintf(alias + strlen(alias), ":%s*", - dmi_fields[i].prefix); - dmi_ascii_filter(alias + strlen(alias), - (*matches)[j].substr); - strcat(alias, "*"); - } - } - } - - strcat(alias, ":"); - return 1; -} -ADD_TO_DEVTABLE("dmi", dmi_system_id, do_dmi_entry); - -static int do_platform_entry(const char *filename, - void *symval, char *alias) -{ - DEF_FIELD_ADDR(symval, platform_device_id, name); - sprintf(alias, PLATFORM_MODULE_PREFIX "%s", *name); - return 1; -} -ADD_TO_DEVTABLE("platform", platform_device_id, do_platform_entry); - -static int do_mdio_entry(const char *filename, - void *symval, char *alias) -{ - int i; - DEF_FIELD(symval, mdio_device_id, phy_id); - DEF_FIELD(symval, mdio_device_id, phy_id_mask); - - alias += sprintf(alias, MDIO_MODULE_PREFIX); - - for (i = 0; i < 32; i++) { - if (!((phy_id_mask >> (31-i)) & 1)) - *(alias++) = '?'; - else if ((phy_id >> (31-i)) & 1) - *(alias++) = '1'; - else - *(alias++) = '0'; - } - - /* Terminate the string */ - *alias = 0; - - return 1; -} -ADD_TO_DEVTABLE("mdio", mdio_device_id, do_mdio_entry); - -/* Looks like: zorro:iN. */ -static int do_zorro_entry(const char *filename, void *symval, - char *alias) -{ - DEF_FIELD(symval, zorro_device_id, id); - strcpy(alias, "zorro:"); - ADD(alias, "i", id != ZORRO_WILDCARD, id); - return 1; -} -ADD_TO_DEVTABLE("zorro", zorro_device_id, do_zorro_entry); - -/* looks like: "pnp:dD" */ -static int do_isapnp_entry(const char *filename, - void *symval, char *alias) -{ - DEF_FIELD(symval, isapnp_device_id, vendor); - DEF_FIELD(symval, isapnp_device_id, function); - sprintf(alias, "pnp:d%c%c%c%x%x%x%x*", - 'A' + ((vendor >> 2) & 0x3f) - 1, - 'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1, - 'A' + ((vendor >> 8) & 0x1f) - 1, - (function >> 4) & 0x0f, function & 0x0f, - (function >> 12) & 0x0f, (function >> 8) & 0x0f); - return 1; -} -ADD_TO_DEVTABLE("isapnp", isapnp_device_id, do_isapnp_entry); - -/* Looks like: "ipack:fNvNdN". */ -static int do_ipack_entry(const char *filename, - void *symval, char *alias) -{ - DEF_FIELD(symval, ipack_device_id, format); - DEF_FIELD(symval, ipack_device_id, vendor); - DEF_FIELD(symval, ipack_device_id, device); - strcpy(alias, "ipack:"); - ADD(alias, "f", format != IPACK_ANY_FORMAT, format); - ADD(alias, "v", vendor != IPACK_ANY_ID, vendor); - ADD(alias, "d", device != IPACK_ANY_ID, device); - add_wildcard(alias); - return 1; -} -ADD_TO_DEVTABLE("ipack", ipack_device_id, do_ipack_entry); - -/* - * Append a match expression for a single masked hex digit. - * outp points to a pointer to the character at which to append. - * *outp is updated on return to point just after the appended text, - * to facilitate further appending. - */ -static void append_nibble_mask(char **outp, - unsigned int nibble, unsigned int mask) -{ - char *p = *outp; - unsigned int i; - - switch (mask) { - case 0: - *p++ = '?'; - break; - - case 0xf: - p += sprintf(p, "%X", nibble); - break; - - default: - /* - * Dumbly emit a match pattern for all possible matching - * digits. This could be improved in some cases using ranges, - * but it has the advantage of being trivially correct, and is - * often optimal. - */ - *p++ = '['; - for (i = 0; i < 0x10; i++) - if ((i & mask) == nibble) - p += sprintf(p, "%X", i); - *p++ = ']'; - } - - /* Ensure that the string remains NUL-terminated: */ - *p = '\0'; - - /* Advance the caller's end-of-string pointer: */ - *outp = p; -} - -/* - * looks like: "amba:dN" - * - * N is exactly 8 digits, where each is an upper-case hex digit, or - * a ? or [] pattern matching exactly one digit. - */ -static int do_amba_entry(const char *filename, - void *symval, char *alias) -{ - unsigned int digit; - char *p = alias; - DEF_FIELD(symval, amba_id, id); - DEF_FIELD(symval, amba_id, mask); - - if ((id & mask) != id) - fatal("%s: Masked-off bit(s) of AMBA device ID are non-zero: " - "id=0x%08X, mask=0x%08X. Please fix this driver.\n", - filename, id, mask); - - p += sprintf(alias, "amba:d"); - for (digit = 0; digit < 8; digit++) - append_nibble_mask(&p, - (id >> (4 * (7 - digit))) & 0xf, - (mask >> (4 * (7 - digit))) & 0xf); - - return 1; -} -ADD_TO_DEVTABLE("amba", amba_id, do_amba_entry); - -/* - * looks like: "mipscdmm:tN" - * - * N is exactly 2 digits, where each is an upper-case hex digit, or - * a ? or [] pattern matching exactly one digit. - */ -static int do_mips_cdmm_entry(const char *filename, - void *symval, char *alias) -{ - DEF_FIELD(symval, mips_cdmm_device_id, type); - - sprintf(alias, "mipscdmm:t%02X*", type); - return 1; -} -ADD_TO_DEVTABLE("mipscdmm", mips_cdmm_device_id, do_mips_cdmm_entry); - -/* LOOKS like cpu:type:x86,venVVVVfamFFFFmodMMMM:feature:*,FEAT,* - * All fields are numbers. It would be nicer to use strings for vendor - * and feature, but getting those out of the build system here is too - * complicated. - */ - -static int do_x86cpu_entry(const char *filename, void *symval, - char *alias) -{ - DEF_FIELD(symval, x86_cpu_id, feature); - DEF_FIELD(symval, x86_cpu_id, family); - DEF_FIELD(symval, x86_cpu_id, model); - DEF_FIELD(symval, x86_cpu_id, vendor); - - strcpy(alias, "cpu:type:x86,"); - ADD(alias, "ven", vendor != X86_VENDOR_ANY, vendor); - ADD(alias, "fam", family != X86_FAMILY_ANY, family); - ADD(alias, "mod", model != X86_MODEL_ANY, model); - strcat(alias, ":feature:*"); - if (feature != X86_FEATURE_ANY) - sprintf(alias + strlen(alias), "%04X*", feature); - return 1; -} -ADD_TO_DEVTABLE("x86cpu", x86_cpu_id, do_x86cpu_entry); - -/* LOOKS like cpu:type:*:feature:*FEAT* */ -static int do_cpu_entry(const char *filename, void *symval, char *alias) -{ - DEF_FIELD(symval, cpu_feature, feature); - - sprintf(alias, "cpu:type:*:feature:*%04X*", feature); - return 1; -} -ADD_TO_DEVTABLE("cpu", cpu_feature, do_cpu_entry); - -/* Looks like: mei:S:uuid:N:* */ -static int do_mei_entry(const char *filename, void *symval, - char *alias) -{ - DEF_FIELD_ADDR(symval, mei_cl_device_id, name); - DEF_FIELD_ADDR(symval, mei_cl_device_id, uuid); - DEF_FIELD(symval, mei_cl_device_id, version); - - sprintf(alias, MEI_CL_MODULE_PREFIX); - sprintf(alias + strlen(alias), "%s:", (*name)[0] ? *name : "*"); - add_uuid(alias, *uuid); - ADD(alias, ":", version != MEI_CL_VERSION_ANY, version); - - strcat(alias, ":*"); - - return 1; -} -ADD_TO_DEVTABLE("mei", mei_cl_device_id, do_mei_entry); - -/* Looks like: rapidio:vNdNavNadN */ -static int do_rio_entry(const char *filename, - void *symval, char *alias) -{ - DEF_FIELD(symval, rio_device_id, did); - DEF_FIELD(symval, rio_device_id, vid); - DEF_FIELD(symval, rio_device_id, asm_did); - DEF_FIELD(symval, rio_device_id, asm_vid); - - strcpy(alias, "rapidio:"); - ADD(alias, "v", vid != RIO_ANY_ID, vid); - ADD(alias, "d", did != RIO_ANY_ID, did); - ADD(alias, "av", asm_vid != RIO_ANY_ID, asm_vid); - ADD(alias, "ad", asm_did != RIO_ANY_ID, asm_did); - - add_wildcard(alias); - return 1; -} -ADD_TO_DEVTABLE("rapidio", rio_device_id, do_rio_entry); - -/* Looks like: ulpi:vNpN */ -static int do_ulpi_entry(const char *filename, void *symval, - char *alias) -{ - DEF_FIELD(symval, ulpi_device_id, vendor); - DEF_FIELD(symval, ulpi_device_id, product); - - sprintf(alias, "ulpi:v%04xp%04x", vendor, product); - - return 1; -} -ADD_TO_DEVTABLE("ulpi", ulpi_device_id, do_ulpi_entry); - -/* Looks like: hdaudio:vNrNaN */ -static int do_hda_entry(const char *filename, void *symval, char *alias) -{ - DEF_FIELD(symval, hda_device_id, vendor_id); - DEF_FIELD(symval, hda_device_id, rev_id); - DEF_FIELD(symval, hda_device_id, api_version); - - strcpy(alias, "hdaudio:"); - ADD(alias, "v", vendor_id != 0, vendor_id); - ADD(alias, "r", rev_id != 0, rev_id); - ADD(alias, "a", api_version != 0, api_version); - - add_wildcard(alias); - return 1; -} -ADD_TO_DEVTABLE("hdaudio", hda_device_id, do_hda_entry); - -/* Looks like: fsl-mc:vNdN */ -static int do_fsl_mc_entry(const char *filename, void *symval, - char *alias) -{ - DEF_FIELD(symval, fsl_mc_device_id, vendor); - DEF_FIELD_ADDR(symval, fsl_mc_device_id, obj_type); - - sprintf(alias, "fsl-mc:v%08Xd%s", vendor, *obj_type); - return 1; -} -ADD_TO_DEVTABLE("fslmc", fsl_mc_device_id, do_fsl_mc_entry); - -/* Does namelen bytes of name exactly match the symbol? */ -static bool sym_is(const char *name, unsigned namelen, const char *symbol) -{ - if (namelen != strlen(symbol)) - return false; - - return memcmp(name, symbol, namelen) == 0; -} - -static void do_table(void *symval, unsigned long size, - unsigned long id_size, - const char *device_id, - void *function, - struct module *mod) -{ - unsigned int i; - char alias[500]; - int (*do_entry)(const char *, void *entry, char *alias) = function; - - device_id_check(mod->name, device_id, size, id_size, symval); - /* Leave last one: it's the terminator. */ - size -= id_size; - - for (i = 0; i < size; i += id_size) { - if (do_entry(mod->name, symval+i, alias)) { - buf_printf(&mod->dev_table_buf, - "MODULE_ALIAS(\"%s\");\n", alias); - } - } -} - -/* Create MODULE_ALIAS() statements. - * At this time, we cannot write the actual output C source yet, - * so we write into the mod->dev_table_buf buffer. */ -void handle_moddevtable(struct module *mod, struct elf_info *info, - Elf_Sym *sym, const char *symname) -{ - void *symval; - char *zeros = NULL; - const char *name, *identifier; - unsigned int namelen; - - /* We're looking for a section relative symbol */ - if (!sym->st_shndx || get_secindex(info, sym) >= info->num_sections) - return; - - /* We're looking for an object */ - if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT) - return; - - /* All our symbols are of form __mod____device_table. */ - name = strstr(symname, "__mod_"); - if (!name) - return; - name += strlen("__mod_"); - namelen = strlen(name); - if (namelen < strlen("_device_table")) - return; - if (strcmp(name + namelen - strlen("_device_table"), "_device_table")) - return; - identifier = strstr(name, "__"); - if (!identifier) - return; - namelen = identifier - name; - - /* Handle all-NULL symbols allocated into .bss */ - if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) { - zeros = calloc(1, sym->st_size); - symval = zeros; - } else { - symval = (void *)info->hdr - + info->sechdrs[get_secindex(info, sym)].sh_offset - + sym->st_value; - } - - /* First handle the "special" cases */ - if (sym_is(name, namelen, "usb")) - do_usb_table(symval, sym->st_size, mod); - if (sym_is(name, namelen, "of")) - do_of_table(symval, sym->st_size, mod); - else if (sym_is(name, namelen, "pnp")) - do_pnp_device_entry(symval, sym->st_size, mod); - else if (sym_is(name, namelen, "pnp_card")) - do_pnp_card_entries(symval, sym->st_size, mod); - else { - struct devtable **p; - INIT_SECTION(__devtable); - - for (p = __start___devtable; p < __stop___devtable; p++) { - if (sym_is(name, namelen, (*p)->device_id)) { - do_table(symval, sym->st_size, (*p)->id_size, - (*p)->device_id, (*p)->function, mod); - break; - } - } - } - free(zeros); -} - -/* Now add out buffered information to the generated C source */ -void add_moddevtable(struct buffer *buf, struct module *mod) -{ - buf_printf(buf, "\n"); - buf_write(buf, mod->dev_table_buf.p, mod->dev_table_buf.pos); - free(mod->dev_table_buf.p); -} diff --git a/src/linux/scripts/mod/mk_elfconfig.c b/src/linux/scripts/mod/mk_elfconfig.c deleted file mode 100644 index a4fd71d..0000000 --- a/src/linux/scripts/mod/mk_elfconfig.c +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include -#include -#include - -int -main(int argc, char **argv) -{ - unsigned char ei[EI_NIDENT]; - union { short s; char c[2]; } endian_test; - - if (fread(ei, 1, EI_NIDENT, stdin) != EI_NIDENT) { - fprintf(stderr, "Error: input truncated\n"); - return 1; - } - if (memcmp(ei, ELFMAG, SELFMAG) != 0) { - fprintf(stderr, "Error: not ELF\n"); - return 1; - } - switch (ei[EI_CLASS]) { - case ELFCLASS32: - printf("#define KERNEL_ELFCLASS ELFCLASS32\n"); - break; - case ELFCLASS64: - printf("#define KERNEL_ELFCLASS ELFCLASS64\n"); - break; - default: - exit(1); - } - switch (ei[EI_DATA]) { - case ELFDATA2LSB: - printf("#define KERNEL_ELFDATA ELFDATA2LSB\n"); - break; - case ELFDATA2MSB: - printf("#define KERNEL_ELFDATA ELFDATA2MSB\n"); - break; - default: - exit(1); - } - - if (sizeof(unsigned long) == 4) { - printf("#define HOST_ELFCLASS ELFCLASS32\n"); - } else if (sizeof(unsigned long) == 8) { - printf("#define HOST_ELFCLASS ELFCLASS64\n"); - } - - endian_test.s = 0x0102; - if (memcmp(endian_test.c, "\x01\x02", 2) == 0) - printf("#define HOST_ELFDATA ELFDATA2MSB\n"); - else if (memcmp(endian_test.c, "\x02\x01", 2) == 0) - printf("#define HOST_ELFDATA ELFDATA2LSB\n"); - else - exit(1); - - return 0; -} diff --git a/src/linux/scripts/mod/modpost.c b/src/linux/scripts/mod/modpost.c deleted file mode 100644 index bd83497..0000000 --- a/src/linux/scripts/mod/modpost.c +++ /dev/null @@ -1,2501 +0,0 @@ -/* Postprocess module symbol versions - * - * Copyright 2003 Kai Germaschewski - * Copyright 2002-2004 Rusty Russell, IBM Corporation - * Copyright 2006-2008 Sam Ravnborg - * Based in part on module-init-tools/depmod.c,file2alias - * - * This software may be used and distributed according to the terms - * of the GNU General Public License, incorporated herein by reference. - * - * Usage: modpost vmlinux module1.o module2.o ... - */ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include "modpost.h" -#include "../../include/generated/autoconf.h" -#include "../../include/linux/license.h" -#include "../../include/linux/export.h" - -/* Are we using CONFIG_MODVERSIONS? */ -static int modversions = 0; -/* Warn about undefined symbols? (do so if we have vmlinux) */ -static int have_vmlinux = 0; -/* Is CONFIG_MODULE_SRCVERSION_ALL set? */ -static int all_versions = 0; -/* If we are modposting external module set to 1 */ -static int external_module = 0; -/* Warn about section mismatch in vmlinux if set to 1 */ -static int vmlinux_section_warnings = 1; -/* Only warn about unresolved symbols */ -static int warn_unresolved = 0; -/* How a symbol is exported */ -static int sec_mismatch_count = 0; -static int sec_mismatch_verbose = 1; -static int sec_mismatch_fatal = 0; -/* ignore missing files */ -static int ignore_missing_files; - -enum export { - export_plain, export_unused, export_gpl, - export_unused_gpl, export_gpl_future, export_unknown -}; - -#define PRINTF __attribute__ ((format (printf, 1, 2))) - -PRINTF void fatal(const char *fmt, ...) -{ - va_list arglist; - - fprintf(stderr, "FATAL: "); - - va_start(arglist, fmt); - vfprintf(stderr, fmt, arglist); - va_end(arglist); - - exit(1); -} - -PRINTF void warn(const char *fmt, ...) -{ - va_list arglist; - - fprintf(stderr, "WARNING: "); - - va_start(arglist, fmt); - vfprintf(stderr, fmt, arglist); - va_end(arglist); -} - -PRINTF void merror(const char *fmt, ...) -{ - va_list arglist; - - fprintf(stderr, "ERROR: "); - - va_start(arglist, fmt); - vfprintf(stderr, fmt, arglist); - va_end(arglist); -} - -static inline bool strends(const char *str, const char *postfix) -{ - if (strlen(str) < strlen(postfix)) - return false; - - return strcmp(str + strlen(str) - strlen(postfix), postfix) == 0; -} - -static int is_vmlinux(const char *modname) -{ - const char *myname; - - myname = strrchr(modname, '/'); - if (myname) - myname++; - else - myname = modname; - - return (strcmp(myname, "vmlinux") == 0) || - (strcmp(myname, "vmlinux.o") == 0); -} - -void *do_nofail(void *ptr, const char *expr) -{ - if (!ptr) - fatal("modpost: Memory allocation failure: %s.\n", expr); - - return ptr; -} - -/* A list of all modules we processed */ -static struct module *modules; - -static struct module *find_module(char *modname) -{ - struct module *mod; - - for (mod = modules; mod; mod = mod->next) - if (strcmp(mod->name, modname) == 0) - break; - return mod; -} - -static struct module *new_module(const char *modname) -{ - struct module *mod; - char *p; - - mod = NOFAIL(malloc(sizeof(*mod))); - memset(mod, 0, sizeof(*mod)); - p = NOFAIL(strdup(modname)); - - /* strip trailing .o */ - if (strends(p, ".o")) { - p[strlen(p) - 2] = '\0'; - mod->is_dot_o = 1; - } - - /* add to list */ - mod->name = p; - mod->gpl_compatible = -1; - mod->next = modules; - modules = mod; - - return mod; -} - -/* A hash of all exported symbols, - * struct symbol is also used for lists of unresolved symbols */ - -#define SYMBOL_HASH_SIZE 1024 - -struct symbol { - struct symbol *next; - struct module *module; - unsigned int crc; - int crc_valid; - unsigned int weak:1; - unsigned int vmlinux:1; /* 1 if symbol is defined in vmlinux */ - unsigned int kernel:1; /* 1 if symbol is from kernel - * (only for external modules) **/ - unsigned int preloaded:1; /* 1 if symbol from Module.symvers, or crc */ - enum export export; /* Type of export */ - char name[0]; -}; - -static struct symbol *symbolhash[SYMBOL_HASH_SIZE]; - -/* This is based on the hash agorithm from gdbm, via tdb */ -static inline unsigned int tdb_hash(const char *name) -{ - unsigned value; /* Used to compute the hash value. */ - unsigned i; /* Used to cycle through random values. */ - - /* Set the initial value from the key size. */ - for (value = 0x238F13AF * strlen(name), i = 0; name[i]; i++) - value = (value + (((unsigned char *)name)[i] << (i*5 % 24))); - - return (1103515243 * value + 12345); -} - -/** - * Allocate a new symbols for use in the hash of exported symbols or - * the list of unresolved symbols per module - **/ -static struct symbol *alloc_symbol(const char *name, unsigned int weak, - struct symbol *next) -{ - struct symbol *s = NOFAIL(malloc(sizeof(*s) + strlen(name) + 1)); - - memset(s, 0, sizeof(*s)); - strcpy(s->name, name); - s->weak = weak; - s->next = next; - return s; -} - -/* For the hash of exported symbols */ -static struct symbol *new_symbol(const char *name, struct module *module, - enum export export) -{ - unsigned int hash; - struct symbol *new; - - hash = tdb_hash(name) % SYMBOL_HASH_SIZE; - new = symbolhash[hash] = alloc_symbol(name, 0, symbolhash[hash]); - new->module = module; - new->export = export; - return new; -} - -static struct symbol *find_symbol(const char *name) -{ - struct symbol *s; - - /* For our purposes, .foo matches foo. PPC64 needs this. */ - if (name[0] == '.') - name++; - - for (s = symbolhash[tdb_hash(name) % SYMBOL_HASH_SIZE]; s; s = s->next) { - if (strcmp(s->name, name) == 0) - return s; - } - return NULL; -} - -static const struct { - const char *str; - enum export export; -} export_list[] = { - { .str = "EXPORT_SYMBOL", .export = export_plain }, - { .str = "EXPORT_UNUSED_SYMBOL", .export = export_unused }, - { .str = "EXPORT_SYMBOL_GPL", .export = export_gpl }, - { .str = "EXPORT_UNUSED_SYMBOL_GPL", .export = export_unused_gpl }, - { .str = "EXPORT_SYMBOL_GPL_FUTURE", .export = export_gpl_future }, - { .str = "(unknown)", .export = export_unknown }, -}; - - -static const char *export_str(enum export ex) -{ - return export_list[ex].str; -} - -static enum export export_no(const char *s) -{ - int i; - - if (!s) - return export_unknown; - for (i = 0; export_list[i].export != export_unknown; i++) { - if (strcmp(export_list[i].str, s) == 0) - return export_list[i].export; - } - return export_unknown; -} - -static const char *sec_name(struct elf_info *elf, int secindex); - -#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0) - -static enum export export_from_secname(struct elf_info *elf, unsigned int sec) -{ - const char *secname = sec_name(elf, sec); - - if (strstarts(secname, "___ksymtab+")) - return export_plain; - else if (strstarts(secname, "___ksymtab_unused+")) - return export_unused; - else if (strstarts(secname, "___ksymtab_gpl+")) - return export_gpl; - else if (strstarts(secname, "___ksymtab_unused_gpl+")) - return export_unused_gpl; - else if (strstarts(secname, "___ksymtab_gpl_future+")) - return export_gpl_future; - else - return export_unknown; -} - -static enum export export_from_sec(struct elf_info *elf, unsigned int sec) -{ - if (sec == elf->export_sec) - return export_plain; - else if (sec == elf->export_unused_sec) - return export_unused; - else if (sec == elf->export_gpl_sec) - return export_gpl; - else if (sec == elf->export_unused_gpl_sec) - return export_unused_gpl; - else if (sec == elf->export_gpl_future_sec) - return export_gpl_future; - else - return export_unknown; -} - -/** - * Add an exported symbol - it may have already been added without a - * CRC, in this case just update the CRC - **/ -static struct symbol *sym_add_exported(const char *name, struct module *mod, - enum export export) -{ - struct symbol *s = find_symbol(name); - - if (!s) { - s = new_symbol(name, mod, export); - } else { - if (!s->preloaded) { - warn("%s: '%s' exported twice. Previous export " - "was in %s%s\n", mod->name, name, - s->module->name, - is_vmlinux(s->module->name) ?"":".ko"); - } else { - /* In case Module.symvers was out of date */ - s->module = mod; - } - } - s->preloaded = 0; - s->vmlinux = is_vmlinux(mod->name); - s->kernel = 0; - s->export = export; - return s; -} - -static void sym_update_crc(const char *name, struct module *mod, - unsigned int crc, enum export export) -{ - struct symbol *s = find_symbol(name); - - if (!s) { - s = new_symbol(name, mod, export); - /* Don't complain when we find it later. */ - s->preloaded = 1; - } - s->crc = crc; - s->crc_valid = 1; -} - -void *grab_file(const char *filename, unsigned long *size) -{ - struct stat st; - void *map = MAP_FAILED; - int fd; - - fd = open(filename, O_RDONLY); - if (fd < 0) - return NULL; - if (fstat(fd, &st)) - goto failed; - - *size = st.st_size; - map = mmap(NULL, *size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); - -failed: - close(fd); - if (map == MAP_FAILED) - return NULL; - return map; -} - -/** - * Return a copy of the next line in a mmap'ed file. - * spaces in the beginning of the line is trimmed away. - * Return a pointer to a static buffer. - **/ -char *get_next_line(unsigned long *pos, void *file, unsigned long size) -{ - static char line[4096]; - int skip = 1; - size_t len = 0; - signed char *p = (signed char *)file + *pos; - char *s = line; - - for (; *pos < size ; (*pos)++) { - if (skip && isspace(*p)) { - p++; - continue; - } - skip = 0; - if (*p != '\n' && (*pos < size)) { - len++; - *s++ = *p++; - if (len > 4095) - break; /* Too long, stop */ - } else { - /* End of string */ - *s = '\0'; - return line; - } - } - /* End of buffer */ - return NULL; -} - -void release_file(void *file, unsigned long size) -{ - munmap(file, size); -} - -static int parse_elf(struct elf_info *info, const char *filename) -{ - unsigned int i; - Elf_Ehdr *hdr; - Elf_Shdr *sechdrs; - Elf_Sym *sym; - const char *secstrings; - unsigned int symtab_idx = ~0U, symtab_shndx_idx = ~0U; - - hdr = grab_file(filename, &info->size); - if (!hdr) { - if (ignore_missing_files) { - fprintf(stderr, "%s: %s (ignored)\n", filename, - strerror(errno)); - return 0; - } - perror(filename); - exit(1); - } - info->hdr = hdr; - if (info->size < sizeof(*hdr)) { - /* file too small, assume this is an empty .o file */ - return 0; - } - /* Is this a valid ELF file? */ - if ((hdr->e_ident[EI_MAG0] != ELFMAG0) || - (hdr->e_ident[EI_MAG1] != ELFMAG1) || - (hdr->e_ident[EI_MAG2] != ELFMAG2) || - (hdr->e_ident[EI_MAG3] != ELFMAG3)) { - /* Not an ELF file - silently ignore it */ - return 0; - } - /* Fix endianness in ELF header */ - hdr->e_type = TO_NATIVE(hdr->e_type); - hdr->e_machine = TO_NATIVE(hdr->e_machine); - hdr->e_version = TO_NATIVE(hdr->e_version); - hdr->e_entry = TO_NATIVE(hdr->e_entry); - hdr->e_phoff = TO_NATIVE(hdr->e_phoff); - hdr->e_shoff = TO_NATIVE(hdr->e_shoff); - hdr->e_flags = TO_NATIVE(hdr->e_flags); - hdr->e_ehsize = TO_NATIVE(hdr->e_ehsize); - hdr->e_phentsize = TO_NATIVE(hdr->e_phentsize); - hdr->e_phnum = TO_NATIVE(hdr->e_phnum); - hdr->e_shentsize = TO_NATIVE(hdr->e_shentsize); - hdr->e_shnum = TO_NATIVE(hdr->e_shnum); - hdr->e_shstrndx = TO_NATIVE(hdr->e_shstrndx); - sechdrs = (void *)hdr + hdr->e_shoff; - info->sechdrs = sechdrs; - - /* Check if file offset is correct */ - if (hdr->e_shoff > info->size) { - fatal("section header offset=%lu in file '%s' is bigger than " - "filesize=%lu\n", (unsigned long)hdr->e_shoff, - filename, info->size); - return 0; - } - - if (hdr->e_shnum == SHN_UNDEF) { - /* - * There are more than 64k sections, - * read count from .sh_size. - */ - info->num_sections = TO_NATIVE(sechdrs[0].sh_size); - } - else { - info->num_sections = hdr->e_shnum; - } - if (hdr->e_shstrndx == SHN_XINDEX) { - info->secindex_strings = TO_NATIVE(sechdrs[0].sh_link); - } - else { - info->secindex_strings = hdr->e_shstrndx; - } - - /* Fix endianness in section headers */ - for (i = 0; i < info->num_sections; i++) { - sechdrs[i].sh_name = TO_NATIVE(sechdrs[i].sh_name); - sechdrs[i].sh_type = TO_NATIVE(sechdrs[i].sh_type); - sechdrs[i].sh_flags = TO_NATIVE(sechdrs[i].sh_flags); - sechdrs[i].sh_addr = TO_NATIVE(sechdrs[i].sh_addr); - sechdrs[i].sh_offset = TO_NATIVE(sechdrs[i].sh_offset); - sechdrs[i].sh_size = TO_NATIVE(sechdrs[i].sh_size); - sechdrs[i].sh_link = TO_NATIVE(sechdrs[i].sh_link); - sechdrs[i].sh_info = TO_NATIVE(sechdrs[i].sh_info); - sechdrs[i].sh_addralign = TO_NATIVE(sechdrs[i].sh_addralign); - sechdrs[i].sh_entsize = TO_NATIVE(sechdrs[i].sh_entsize); - } - /* Find symbol table. */ - secstrings = (void *)hdr + sechdrs[info->secindex_strings].sh_offset; - for (i = 1; i < info->num_sections; i++) { - const char *secname; - int nobits = sechdrs[i].sh_type == SHT_NOBITS; - - if (!nobits && sechdrs[i].sh_offset > info->size) { - fatal("%s is truncated. sechdrs[i].sh_offset=%lu > " - "sizeof(*hrd)=%zu\n", filename, - (unsigned long)sechdrs[i].sh_offset, - sizeof(*hdr)); - return 0; - } - secname = secstrings + sechdrs[i].sh_name; - if (strcmp(secname, ".modinfo") == 0) { - if (nobits) - fatal("%s has NOBITS .modinfo\n", filename); - info->modinfo = (void *)hdr + sechdrs[i].sh_offset; - info->modinfo_len = sechdrs[i].sh_size; - } else if (strcmp(secname, "__ksymtab") == 0) - info->export_sec = i; - else if (strcmp(secname, "__ksymtab_unused") == 0) - info->export_unused_sec = i; - else if (strcmp(secname, "__ksymtab_gpl") == 0) - info->export_gpl_sec = i; - else if (strcmp(secname, "__ksymtab_unused_gpl") == 0) - info->export_unused_gpl_sec = i; - else if (strcmp(secname, "__ksymtab_gpl_future") == 0) - info->export_gpl_future_sec = i; - - if (sechdrs[i].sh_type == SHT_SYMTAB) { - unsigned int sh_link_idx; - symtab_idx = i; - info->symtab_start = (void *)hdr + - sechdrs[i].sh_offset; - info->symtab_stop = (void *)hdr + - sechdrs[i].sh_offset + sechdrs[i].sh_size; - sh_link_idx = sechdrs[i].sh_link; - info->strtab = (void *)hdr + - sechdrs[sh_link_idx].sh_offset; - } - - /* 32bit section no. table? ("more than 64k sections") */ - if (sechdrs[i].sh_type == SHT_SYMTAB_SHNDX) { - symtab_shndx_idx = i; - info->symtab_shndx_start = (void *)hdr + - sechdrs[i].sh_offset; - info->symtab_shndx_stop = (void *)hdr + - sechdrs[i].sh_offset + sechdrs[i].sh_size; - } - } - if (!info->symtab_start) - fatal("%s has no symtab?\n", filename); - - /* Fix endianness in symbols */ - for (sym = info->symtab_start; sym < info->symtab_stop; sym++) { - sym->st_shndx = TO_NATIVE(sym->st_shndx); - sym->st_name = TO_NATIVE(sym->st_name); - sym->st_value = TO_NATIVE(sym->st_value); - sym->st_size = TO_NATIVE(sym->st_size); - } - - if (symtab_shndx_idx != ~0U) { - Elf32_Word *p; - if (symtab_idx != sechdrs[symtab_shndx_idx].sh_link) - fatal("%s: SYMTAB_SHNDX has bad sh_link: %u!=%u\n", - filename, sechdrs[symtab_shndx_idx].sh_link, - symtab_idx); - /* Fix endianness */ - for (p = info->symtab_shndx_start; p < info->symtab_shndx_stop; - p++) - *p = TO_NATIVE(*p); - } - - return 1; -} - -static void parse_elf_finish(struct elf_info *info) -{ - release_file(info->hdr, info->size); -} - -static int ignore_undef_symbol(struct elf_info *info, const char *symname) -{ - /* ignore __this_module, it will be resolved shortly */ - if (strcmp(symname, VMLINUX_SYMBOL_STR(__this_module)) == 0) - return 1; - /* ignore global offset table */ - if (strcmp(symname, "_GLOBAL_OFFSET_TABLE_") == 0) - return 1; - if (info->hdr->e_machine == EM_PPC) - /* Special register function linked on all modules during final link of .ko */ - if (strncmp(symname, "_restgpr_", sizeof("_restgpr_") - 1) == 0 || - strncmp(symname, "_savegpr_", sizeof("_savegpr_") - 1) == 0 || - strncmp(symname, "_rest32gpr_", sizeof("_rest32gpr_") - 1) == 0 || - strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0 || - strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 || - strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0) - return 1; - if (info->hdr->e_machine == EM_PPC64) - /* Special register function linked on all modules during final link of .ko */ - if (strncmp(symname, "_restgpr0_", sizeof("_restgpr0_") - 1) == 0 || - strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0 || - strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 || - strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0 || - strcmp(symname, ".TOC.") == 0) - return 1; - /* Do not ignore this symbol */ - return 0; -} - -#define CRC_PFX VMLINUX_SYMBOL_STR(__crc_) -#define KSYMTAB_PFX VMLINUX_SYMBOL_STR(__ksymtab_) - -static void handle_modversions(struct module *mod, struct elf_info *info, - Elf_Sym *sym, const char *symname) -{ - unsigned int crc; - enum export export; - - if ((!is_vmlinux(mod->name) || mod->is_dot_o) && - strncmp(symname, "__ksymtab", 9) == 0) - export = export_from_secname(info, get_secindex(info, sym)); - else - export = export_from_sec(info, get_secindex(info, sym)); - - /* CRC'd symbol */ - if (strncmp(symname, CRC_PFX, strlen(CRC_PFX)) == 0) { - crc = (unsigned int) sym->st_value; - sym_update_crc(symname + strlen(CRC_PFX), mod, crc, - export); - } - - switch (sym->st_shndx) { - case SHN_COMMON: - if (!strncmp(symname, "__gnu_lto_", sizeof("__gnu_lto_")-1)) { - /* Should warn here, but modpost runs before the linker */ - } else - warn("\"%s\" [%s] is COMMON symbol\n", symname, mod->name); - break; - case SHN_UNDEF: - /* undefined symbol */ - if (ELF_ST_BIND(sym->st_info) != STB_GLOBAL && - ELF_ST_BIND(sym->st_info) != STB_WEAK) - break; - if (ignore_undef_symbol(info, symname)) - break; -/* cope with newer glibc (2.3.4 or higher) STT_ definition in elf.h */ -#if defined(STT_REGISTER) || defined(STT_SPARC_REGISTER) -/* add compatibility with older glibc */ -#ifndef STT_SPARC_REGISTER -#define STT_SPARC_REGISTER STT_REGISTER -#endif - if (info->hdr->e_machine == EM_SPARC || - info->hdr->e_machine == EM_SPARCV9) { - /* Ignore register directives. */ - if (ELF_ST_TYPE(sym->st_info) == STT_SPARC_REGISTER) - break; - if (symname[0] == '.') { - char *munged = strdup(symname); - munged[0] = '_'; - munged[1] = toupper(munged[1]); - symname = munged; - } - } -#endif - -#ifdef CONFIG_HAVE_UNDERSCORE_SYMBOL_PREFIX - if (symname[0] != '_') - break; - else - symname++; -#endif - mod->unres = alloc_symbol(symname, - ELF_ST_BIND(sym->st_info) == STB_WEAK, - mod->unres); - break; - default: - /* All exported symbols */ - if (strncmp(symname, KSYMTAB_PFX, strlen(KSYMTAB_PFX)) == 0) { - sym_add_exported(symname + strlen(KSYMTAB_PFX), mod, - export); - } - if (strcmp(symname, VMLINUX_SYMBOL_STR(init_module)) == 0) - mod->has_init = 1; - if (strcmp(symname, VMLINUX_SYMBOL_STR(cleanup_module)) == 0) - mod->has_cleanup = 1; - break; - } -} - -/** - * Parse tag=value strings from .modinfo section - **/ -static char *next_string(char *string, unsigned long *secsize) -{ - /* Skip non-zero chars */ - while (string[0]) { - string++; - if ((*secsize)-- <= 1) - return NULL; - } - - /* Skip any zero padding. */ - while (!string[0]) { - string++; - if ((*secsize)-- <= 1) - return NULL; - } - return string; -} - -static char *get_next_modinfo(void *modinfo, unsigned long modinfo_len, - const char *tag, char *info) -{ - char *p; - unsigned int taglen = strlen(tag); - unsigned long size = modinfo_len; - - if (info) { - size -= info - (char *)modinfo; - modinfo = next_string(info, &size); - } - - for (p = modinfo; p; p = next_string(p, &size)) { - if (strncmp(p, tag, taglen) == 0 && p[taglen] == '=') - return p + taglen + 1; - } - return NULL; -} - -static char *get_modinfo(void *modinfo, unsigned long modinfo_len, - const char *tag) - -{ - return get_next_modinfo(modinfo, modinfo_len, tag, NULL); -} - -/** - * Test if string s ends in string sub - * return 0 if match - **/ -static int strrcmp(const char *s, const char *sub) -{ - int slen, sublen; - - if (!s || !sub) - return 1; - - slen = strlen(s); - sublen = strlen(sub); - - if ((slen == 0) || (sublen == 0)) - return 1; - - if (sublen > slen) - return 1; - - return memcmp(s + slen - sublen, sub, sublen); -} - -static const char *sym_name(struct elf_info *elf, Elf_Sym *sym) -{ - if (sym) - return elf->strtab + sym->st_name; - else - return "(unknown)"; -} - -static const char *sec_name(struct elf_info *elf, int secindex) -{ - Elf_Shdr *sechdrs = elf->sechdrs; - return (void *)elf->hdr + - elf->sechdrs[elf->secindex_strings].sh_offset + - sechdrs[secindex].sh_name; -} - -static const char *sech_name(struct elf_info *elf, Elf_Shdr *sechdr) -{ - return (void *)elf->hdr + - elf->sechdrs[elf->secindex_strings].sh_offset + - sechdr->sh_name; -} - -/* The pattern is an array of simple patterns. - * "foo" will match an exact string equal to "foo" - * "*foo" will match a string that ends with "foo" - * "foo*" will match a string that begins with "foo" - * "*foo*" will match a string that contains "foo" - */ -static int match(const char *sym, const char * const pat[]) -{ - const char *p; - while (*pat) { - p = *pat++; - const char *endp = p + strlen(p) - 1; - - /* "*foo*" */ - if (*p == '*' && *endp == '*') { - char *here, *bare = strndup(p + 1, strlen(p) - 2); - - here = strstr(sym, bare); - free(bare); - if (here != NULL) - return 1; - } - /* "*foo" */ - else if (*p == '*') { - if (strrcmp(sym, p + 1) == 0) - return 1; - } - /* "foo*" */ - else if (*endp == '*') { - if (strncmp(sym, p, strlen(p) - 1) == 0) - return 1; - } - /* no wildcards */ - else { - if (strcmp(p, sym) == 0) - return 1; - } - } - /* no match */ - return 0; -} - -/* sections that we do not want to do full section mismatch check on */ -static const char *const section_white_list[] = -{ - ".comment*", - ".debug*", - ".cranges", /* sh64 */ - ".zdebug*", /* Compressed debug sections. */ - ".GCC-command-line", /* mn10300 */ - ".GCC.command.line", /* record-gcc-switches, non mn10300 */ - ".mdebug*", /* alpha, score, mips etc. */ - ".pdr", /* alpha, score, mips etc. */ - ".stab*", - ".note*", - ".got*", - ".toc*", - ".xt.prop", /* xtensa */ - ".xt.lit", /* xtensa */ - ".arcextmap*", /* arc */ - ".gnu.linkonce.arcext*", /* arc : modules */ - ".cmem*", /* EZchip */ - ".fmt_slot*", /* EZchip */ - ".gnu.lto*", - NULL -}; - -/* - * This is used to find sections missing the SHF_ALLOC flag. - * The cause of this is often a section specified in assembler - * without "ax" / "aw". - */ -static void check_section(const char *modname, struct elf_info *elf, - Elf_Shdr *sechdr) -{ - const char *sec = sech_name(elf, sechdr); - - if (sechdr->sh_type == SHT_PROGBITS && - !(sechdr->sh_flags & SHF_ALLOC) && - !match(sec, section_white_list)) { - warn("%s (%s): unexpected non-allocatable section.\n" - "Did you forget to use \"ax\"/\"aw\" in a .S file?\n" - "Note that for example contains\n" - "section definitions for use in .S files.\n\n", - modname, sec); - } -} - - - -#define ALL_INIT_DATA_SECTIONS \ - ".init.setup", ".init.rodata", ".meminit.rodata", \ - ".init.data", ".meminit.data" -#define ALL_EXIT_DATA_SECTIONS \ - ".exit.data", ".memexit.data" - -#define ALL_INIT_TEXT_SECTIONS \ - ".init.text", ".meminit.text" -#define ALL_EXIT_TEXT_SECTIONS \ - ".exit.text", ".memexit.text" - -#define ALL_PCI_INIT_SECTIONS \ - ".pci_fixup_early", ".pci_fixup_header", ".pci_fixup_final", \ - ".pci_fixup_enable", ".pci_fixup_resume", \ - ".pci_fixup_resume_early", ".pci_fixup_suspend" - -#define ALL_XXXINIT_SECTIONS MEM_INIT_SECTIONS -#define ALL_XXXEXIT_SECTIONS MEM_EXIT_SECTIONS - -#define ALL_INIT_SECTIONS INIT_SECTIONS, ALL_XXXINIT_SECTIONS -#define ALL_EXIT_SECTIONS EXIT_SECTIONS, ALL_XXXEXIT_SECTIONS - -#define DATA_SECTIONS ".data", ".data.rel" -#define TEXT_SECTIONS ".text", ".text.unlikely", ".sched.text", \ - ".kprobes.text", ".cpuidle.text" -#define OTHER_TEXT_SECTIONS ".ref.text", ".head.text", ".spinlock.text", \ - ".fixup", ".entry.text", ".exception.text", ".text.*", \ - ".coldtext" - -#define INIT_SECTIONS ".init.*" -#define MEM_INIT_SECTIONS ".meminit.*" - -#define EXIT_SECTIONS ".exit.*" -#define MEM_EXIT_SECTIONS ".memexit.*" - -#define ALL_TEXT_SECTIONS ALL_INIT_TEXT_SECTIONS, ALL_EXIT_TEXT_SECTIONS, \ - TEXT_SECTIONS, OTHER_TEXT_SECTIONS - -/* init data sections */ -static const char *const init_data_sections[] = - { ALL_INIT_DATA_SECTIONS, NULL }; - -/* all init sections */ -static const char *const init_sections[] = { ALL_INIT_SECTIONS, NULL }; - -/* All init and exit sections (code + data) */ -static const char *const init_exit_sections[] = - {ALL_INIT_SECTIONS, ALL_EXIT_SECTIONS, NULL }; - -/* all text sections */ -static const char *const text_sections[] = { ALL_TEXT_SECTIONS, NULL }; - -/* data section */ -static const char *const data_sections[] = { DATA_SECTIONS, NULL }; - - -/* symbols in .data that may refer to init/exit sections */ -#define DEFAULT_SYMBOL_WHITE_LIST \ - "*driver", \ - "*_template", /* scsi uses *_template a lot */ \ - "*_timer", /* arm uses ops structures named _timer a lot */ \ - "*_sht", /* scsi also used *_sht to some extent */ \ - "*_ops", \ - "*_probe", \ - "*_probe_one", \ - "*_console" - -static const char *const head_sections[] = { ".head.text*", NULL }; -static const char *const linker_symbols[] = - { "__init_begin", "_sinittext", "_einittext", NULL }; -static const char *const optim_symbols[] = { "*.constprop.*", NULL }; - -enum mismatch { - TEXT_TO_ANY_INIT, - DATA_TO_ANY_INIT, - TEXT_TO_ANY_EXIT, - DATA_TO_ANY_EXIT, - XXXINIT_TO_SOME_INIT, - XXXEXIT_TO_SOME_EXIT, - ANY_INIT_TO_ANY_EXIT, - ANY_EXIT_TO_ANY_INIT, - EXPORT_TO_INIT_EXIT, - EXTABLE_TO_NON_TEXT, -}; - -/** - * Describe how to match sections on different criterias: - * - * @fromsec: Array of sections to be matched. - * - * @bad_tosec: Relocations applied to a section in @fromsec to a section in - * this array is forbidden (black-list). Can be empty. - * - * @good_tosec: Relocations applied to a section in @fromsec must be - * targetting sections in this array (white-list). Can be empty. - * - * @mismatch: Type of mismatch. - * - * @symbol_white_list: Do not match a relocation to a symbol in this list - * even if it is targetting a section in @bad_to_sec. - * - * @handler: Specific handler to call when a match is found. If NULL, - * default_mismatch_handler() will be called. - * - */ -struct sectioncheck { - const char *fromsec[20]; - const char *bad_tosec[20]; - const char *good_tosec[20]; - enum mismatch mismatch; - const char *symbol_white_list[20]; - void (*handler)(const char *modname, struct elf_info *elf, - const struct sectioncheck* const mismatch, - Elf_Rela *r, Elf_Sym *sym, const char *fromsec); - -}; - -static void extable_mismatch_handler(const char *modname, struct elf_info *elf, - const struct sectioncheck* const mismatch, - Elf_Rela *r, Elf_Sym *sym, - const char *fromsec); - -static const struct sectioncheck sectioncheck[] = { -/* Do not reference init/exit code/data from - * normal code and data - */ -{ - .fromsec = { TEXT_SECTIONS, NULL }, - .bad_tosec = { ALL_INIT_SECTIONS, NULL }, - .mismatch = TEXT_TO_ANY_INIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, -}, -{ - .fromsec = { DATA_SECTIONS, NULL }, - .bad_tosec = { ALL_XXXINIT_SECTIONS, NULL }, - .mismatch = DATA_TO_ANY_INIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, -}, -{ - .fromsec = { DATA_SECTIONS, NULL }, - .bad_tosec = { INIT_SECTIONS, NULL }, - .mismatch = DATA_TO_ANY_INIT, - .symbol_white_list = { - "*_template", "*_timer", "*_sht", "*_ops", - "*_probe", "*_probe_one", "*_console", NULL - }, -}, -{ - .fromsec = { TEXT_SECTIONS, NULL }, - .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, - .mismatch = TEXT_TO_ANY_EXIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, -}, -{ - .fromsec = { DATA_SECTIONS, NULL }, - .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, - .mismatch = DATA_TO_ANY_EXIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, -}, -/* Do not reference init code/data from meminit code/data */ -{ - .fromsec = { ALL_XXXINIT_SECTIONS, NULL }, - .bad_tosec = { INIT_SECTIONS, NULL }, - .mismatch = XXXINIT_TO_SOME_INIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, -}, -/* Do not reference exit code/data from memexit code/data */ -{ - .fromsec = { ALL_XXXEXIT_SECTIONS, NULL }, - .bad_tosec = { EXIT_SECTIONS, NULL }, - .mismatch = XXXEXIT_TO_SOME_EXIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, -}, -/* Do not use exit code/data from init code */ -{ - .fromsec = { ALL_INIT_SECTIONS, NULL }, - .bad_tosec = { ALL_EXIT_SECTIONS, NULL }, - .mismatch = ANY_INIT_TO_ANY_EXIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, -}, -/* Do not use init code/data from exit code */ -{ - .fromsec = { ALL_EXIT_SECTIONS, NULL }, - .bad_tosec = { ALL_INIT_SECTIONS, NULL }, - .mismatch = ANY_EXIT_TO_ANY_INIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, -}, -{ - .fromsec = { ALL_PCI_INIT_SECTIONS, NULL }, - .bad_tosec = { INIT_SECTIONS, NULL }, - .mismatch = ANY_INIT_TO_ANY_EXIT, - .symbol_white_list = { NULL }, -}, -/* Do not export init/exit functions or data */ -{ - .fromsec = { "__ksymtab*", NULL }, - .bad_tosec = { INIT_SECTIONS, EXIT_SECTIONS, NULL }, - .mismatch = EXPORT_TO_INIT_EXIT, - .symbol_white_list = { DEFAULT_SYMBOL_WHITE_LIST, NULL }, -}, -{ - .fromsec = { "__ex_table", NULL }, - /* If you're adding any new black-listed sections in here, consider - * adding a special 'printer' for them in scripts/check_extable. - */ - .bad_tosec = { ".altinstr_replacement", NULL }, - .good_tosec = {ALL_TEXT_SECTIONS , NULL}, - .mismatch = EXTABLE_TO_NON_TEXT, - .handler = extable_mismatch_handler, -} -}; - -static const struct sectioncheck *section_mismatch( - const char *fromsec, const char *tosec) -{ - int i; - int elems = sizeof(sectioncheck) / sizeof(struct sectioncheck); - const struct sectioncheck *check = §ioncheck[0]; - - /* - * The target section could be the SHT_NUL section when we're - * handling relocations to un-resolved symbols, trying to match it - * doesn't make much sense and causes build failures on parisc and - * mn10300 architectures. - */ - if (*tosec == '\0') - return NULL; - - for (i = 0; i < elems; i++) { - if (match(fromsec, check->fromsec)) { - if (check->bad_tosec[0] && match(tosec, check->bad_tosec)) - return check; - if (check->good_tosec[0] && !match(tosec, check->good_tosec)) - return check; - } - check++; - } - return NULL; -} - -/** - * Whitelist to allow certain references to pass with no warning. - * - * Pattern 1: - * If a module parameter is declared __initdata and permissions=0 - * then this is legal despite the warning generated. - * We cannot see value of permissions here, so just ignore - * this pattern. - * The pattern is identified by: - * tosec = .init.data - * fromsec = .data* - * atsym =__param* - * - * Pattern 1a: - * module_param_call() ops can refer to __init set function if permissions=0 - * The pattern is identified by: - * tosec = .init.text - * fromsec = .data* - * atsym = __param_ops_* - * - * Pattern 2: - * Many drivers utilise a *driver container with references to - * add, remove, probe functions etc. - * the pattern is identified by: - * tosec = init or exit section - * fromsec = data section - * atsym = *driver, *_template, *_sht, *_ops, *_probe, - * *probe_one, *_console, *_timer - * - * Pattern 3: - * Whitelist all references from .head.text to any init section - * - * Pattern 4: - * Some symbols belong to init section but still it is ok to reference - * these from non-init sections as these symbols don't have any memory - * allocated for them and symbol address and value are same. So even - * if init section is freed, its ok to reference those symbols. - * For ex. symbols marking the init section boundaries. - * This pattern is identified by - * refsymname = __init_begin, _sinittext, _einittext - * - * Pattern 5: - * GCC may optimize static inlines when fed constant arg(s) resulting - * in functions like cpumask_empty() -- generating an associated symbol - * cpumask_empty.constprop.3 that appears in the audit. If the const that - * is passed in comes from __init, like say nmi_ipi_mask, we get a - * meaningless section warning. May need to add isra symbols too... - * This pattern is identified by - * tosec = init section - * fromsec = text section - * refsymname = *.constprop.* - * - **/ -static int secref_whitelist(const struct sectioncheck *mismatch, - const char *fromsec, const char *fromsym, - const char *tosec, const char *tosym) -{ - /* Check for pattern 1 */ - if (match(tosec, init_data_sections) && - match(fromsec, data_sections) && - (strncmp(fromsym, "__param", strlen("__param")) == 0)) - return 0; - - /* Check for pattern 1a */ - if (strcmp(tosec, ".init.text") == 0 && - match(fromsec, data_sections) && - (strncmp(fromsym, "__param_ops_", strlen("__param_ops_")) == 0)) - return 0; - - /* Check for pattern 2 */ - if (match(tosec, init_exit_sections) && - match(fromsec, data_sections) && - match(fromsym, mismatch->symbol_white_list)) - return 0; - - /* Check for pattern 3 */ - if (match(fromsec, head_sections) && - match(tosec, init_sections)) - return 0; - - /* Check for pattern 4 */ - if (match(tosym, linker_symbols)) - return 0; - - /* Check for pattern 5 */ - if (match(fromsec, text_sections) && - match(tosec, init_sections) && - match(fromsym, optim_symbols)) - return 0; - - return 1; -} - -/** - * Find symbol based on relocation record info. - * In some cases the symbol supplied is a valid symbol so - * return refsym. If st_name != 0 we assume this is a valid symbol. - * In other cases the symbol needs to be looked up in the symbol table - * based on section and address. - * **/ -static Elf_Sym *find_elf_symbol(struct elf_info *elf, Elf64_Sword addr, - Elf_Sym *relsym) -{ - Elf_Sym *sym; - Elf_Sym *near = NULL; - Elf64_Sword distance = 20; - Elf64_Sword d; - unsigned int relsym_secindex; - - if (relsym->st_name != 0) - return relsym; - - relsym_secindex = get_secindex(elf, relsym); - for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { - if (get_secindex(elf, sym) != relsym_secindex) - continue; - if (ELF_ST_TYPE(sym->st_info) == STT_SECTION) - continue; - if (sym->st_value == addr) - return sym; - /* Find a symbol nearby - addr are maybe negative */ - d = sym->st_value - addr; - if (d < 0) - d = addr - sym->st_value; - if (d < distance) { - distance = d; - near = sym; - } - } - /* We need a close match */ - if (distance < 20) - return near; - else - return NULL; -} - -static inline int is_arm_mapping_symbol(const char *str) -{ - return str[0] == '$' && strchr("axtd", str[1]) - && (str[2] == '\0' || str[2] == '.'); -} - -/* - * If there's no name there, ignore it; likewise, ignore it if it's - * one of the magic symbols emitted used by current ARM tools. - * - * Otherwise if find_symbols_between() returns those symbols, they'll - * fail the whitelist tests and cause lots of false alarms ... fixable - * only by merging __exit and __init sections into __text, bloating - * the kernel (which is especially evil on embedded platforms). - */ -static inline int is_valid_name(struct elf_info *elf, Elf_Sym *sym) -{ - const char *name = elf->strtab + sym->st_name; - - if (!name || !strlen(name)) - return 0; - return !is_arm_mapping_symbol(name); -} - -/* - * Find symbols before or equal addr and after addr - in the section sec. - * If we find two symbols with equal offset prefer one with a valid name. - * The ELF format may have a better way to detect what type of symbol - * it is, but this works for now. - **/ -static Elf_Sym *find_elf_symbol2(struct elf_info *elf, Elf_Addr addr, - const char *sec) -{ - Elf_Sym *sym; - Elf_Sym *near = NULL; - Elf_Addr distance = ~0; - - for (sym = elf->symtab_start; sym < elf->symtab_stop; sym++) { - const char *symsec; - - if (is_shndx_special(sym->st_shndx)) - continue; - symsec = sec_name(elf, get_secindex(elf, sym)); - if (strcmp(symsec, sec) != 0) - continue; - if (!is_valid_name(elf, sym)) - continue; - if (sym->st_value <= addr) { - if ((addr - sym->st_value) < distance) { - distance = addr - sym->st_value; - near = sym; - } else if ((addr - sym->st_value) == distance) { - near = sym; - } - } - } - return near; -} - -/* - * Convert a section name to the function/data attribute - * .init.text => __init - * .memexitconst => __memconst - * etc. - * - * The memory of returned value has been allocated on a heap. The user of this - * method should free it after usage. -*/ -static char *sec2annotation(const char *s) -{ - if (match(s, init_exit_sections)) { - char *p = malloc(20); - char *r = p; - - *p++ = '_'; - *p++ = '_'; - if (*s == '.') - s++; - while (*s && *s != '.') - *p++ = *s++; - *p = '\0'; - if (*s == '.') - s++; - if (strstr(s, "rodata") != NULL) - strcat(p, "const "); - else if (strstr(s, "data") != NULL) - strcat(p, "data "); - else - strcat(p, " "); - return r; - } else { - return strdup(""); - } -} - -static int is_function(Elf_Sym *sym) -{ - if (sym) - return ELF_ST_TYPE(sym->st_info) == STT_FUNC; - else - return -1; -} - -static void print_section_list(const char * const list[20]) -{ - const char *const *s = list; - - while (*s) { - fprintf(stderr, "%s", *s); - s++; - if (*s) - fprintf(stderr, ", "); - } - fprintf(stderr, "\n"); -} - -static inline void get_pretty_name(int is_func, const char** name, const char** name_p) -{ - switch (is_func) { - case 0: *name = "variable"; *name_p = ""; break; - case 1: *name = "function"; *name_p = "()"; break; - default: *name = "(unknown reference)"; *name_p = ""; break; - } -} - -/* - * Print a warning about a section mismatch. - * Try to find symbols near it so user can find it. - * Check whitelist before warning - it may be a false positive. - */ -static void report_sec_mismatch(const char *modname, - const struct sectioncheck *mismatch, - const char *fromsec, - unsigned long long fromaddr, - const char *fromsym, - int from_is_func, - const char *tosec, const char *tosym, - int to_is_func) -{ - const char *from, *from_p; - const char *to, *to_p; - char *prl_from; - char *prl_to; - - sec_mismatch_count++; - if (!sec_mismatch_verbose) - return; - - get_pretty_name(from_is_func, &from, &from_p); - get_pretty_name(to_is_func, &to, &to_p); - - warn("%s(%s+0x%llx): Section mismatch in reference from the %s %s%s " - "to the %s %s:%s%s\n", - modname, fromsec, fromaddr, from, fromsym, from_p, to, tosec, - tosym, to_p); - - switch (mismatch->mismatch) { - case TEXT_TO_ANY_INIT: - prl_from = sec2annotation(fromsec); - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The function %s%s() references\n" - "the %s %s%s%s.\n" - "This is often because %s lacks a %s\n" - "annotation or the annotation of %s is wrong.\n", - prl_from, fromsym, - to, prl_to, tosym, to_p, - fromsym, prl_to, tosym); - free(prl_from); - free(prl_to); - break; - case DATA_TO_ANY_INIT: { - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The variable %s references\n" - "the %s %s%s%s\n" - "If the reference is valid then annotate the\n" - "variable with __init* or __refdata (see linux/init.h) " - "or name the variable:\n", - fromsym, to, prl_to, tosym, to_p); - print_section_list(mismatch->symbol_white_list); - free(prl_to); - break; - } - case TEXT_TO_ANY_EXIT: - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The function %s() references a %s in an exit section.\n" - "Often the %s %s%s has valid usage outside the exit section\n" - "and the fix is to remove the %sannotation of %s.\n", - fromsym, to, to, tosym, to_p, prl_to, tosym); - free(prl_to); - break; - case DATA_TO_ANY_EXIT: { - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The variable %s references\n" - "the %s %s%s%s\n" - "If the reference is valid then annotate the\n" - "variable with __exit* (see linux/init.h) or " - "name the variable:\n", - fromsym, to, prl_to, tosym, to_p); - print_section_list(mismatch->symbol_white_list); - free(prl_to); - break; - } - case XXXINIT_TO_SOME_INIT: - case XXXEXIT_TO_SOME_EXIT: - prl_from = sec2annotation(fromsec); - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The %s %s%s%s references\n" - "a %s %s%s%s.\n" - "If %s is only used by %s then\n" - "annotate %s with a matching annotation.\n", - from, prl_from, fromsym, from_p, - to, prl_to, tosym, to_p, - tosym, fromsym, tosym); - free(prl_from); - free(prl_to); - break; - case ANY_INIT_TO_ANY_EXIT: - prl_from = sec2annotation(fromsec); - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The %s %s%s%s references\n" - "a %s %s%s%s.\n" - "This is often seen when error handling " - "in the init function\n" - "uses functionality in the exit path.\n" - "The fix is often to remove the %sannotation of\n" - "%s%s so it may be used outside an exit section.\n", - from, prl_from, fromsym, from_p, - to, prl_to, tosym, to_p, - prl_to, tosym, to_p); - free(prl_from); - free(prl_to); - break; - case ANY_EXIT_TO_ANY_INIT: - prl_from = sec2annotation(fromsec); - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The %s %s%s%s references\n" - "a %s %s%s%s.\n" - "This is often seen when error handling " - "in the exit function\n" - "uses functionality in the init path.\n" - "The fix is often to remove the %sannotation of\n" - "%s%s so it may be used outside an init section.\n", - from, prl_from, fromsym, from_p, - to, prl_to, tosym, to_p, - prl_to, tosym, to_p); - free(prl_from); - free(prl_to); - break; - case EXPORT_TO_INIT_EXIT: - prl_to = sec2annotation(tosec); - fprintf(stderr, - "The symbol %s is exported and annotated %s\n" - "Fix this by removing the %sannotation of %s " - "or drop the export.\n", - tosym, prl_to, prl_to, tosym); - free(prl_to); - break; - case EXTABLE_TO_NON_TEXT: - fatal("There's a special handler for this mismatch type, " - "we should never get here."); - break; - } - fprintf(stderr, "\n"); -} - -static void default_mismatch_handler(const char *modname, struct elf_info *elf, - const struct sectioncheck* const mismatch, - Elf_Rela *r, Elf_Sym *sym, const char *fromsec) -{ - const char *tosec; - Elf_Sym *to; - Elf_Sym *from; - const char *tosym; - const char *fromsym; - - from = find_elf_symbol2(elf, r->r_offset, fromsec); - fromsym = sym_name(elf, from); - - if (!strncmp(fromsym, "reference___initcall", - sizeof("reference___initcall")-1)) - return; - - tosec = sec_name(elf, get_secindex(elf, sym)); - to = find_elf_symbol(elf, r->r_addend, sym); - tosym = sym_name(elf, to); - - /* check whitelist - we may ignore it */ - if (secref_whitelist(mismatch, - fromsec, fromsym, tosec, tosym)) { - report_sec_mismatch(modname, mismatch, - fromsec, r->r_offset, fromsym, - is_function(from), tosec, tosym, - is_function(to)); - } -} - -static int is_executable_section(struct elf_info* elf, unsigned int section_index) -{ - if (section_index > elf->num_sections) - fatal("section_index is outside elf->num_sections!\n"); - - return ((elf->sechdrs[section_index].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR); -} - -/* - * We rely on a gross hack in section_rel[a]() calling find_extable_entry_size() - * to know the sizeof(struct exception_table_entry) for the target architecture. - */ -static unsigned int extable_entry_size = 0; -static void find_extable_entry_size(const char* const sec, const Elf_Rela* r) -{ - /* - * If we're currently checking the second relocation within __ex_table, - * that relocation offset tells us the offsetof(struct - * exception_table_entry, fixup) which is equal to sizeof(struct - * exception_table_entry) divided by two. We use that to our advantage - * since there's no portable way to get that size as every architecture - * seems to go with different sized types. Not pretty but better than - * hard-coding the size for every architecture.. - */ - if (!extable_entry_size) - extable_entry_size = r->r_offset * 2; -} - -static inline bool is_extable_fault_address(Elf_Rela *r) -{ - /* - * extable_entry_size is only discovered after we've handled the - * _second_ relocation in __ex_table, so only abort when we're not - * handling the first reloc and extable_entry_size is zero. - */ - if (r->r_offset && extable_entry_size == 0) - fatal("extable_entry size hasn't been discovered!\n"); - - return ((r->r_offset == 0) || - (r->r_offset % extable_entry_size == 0)); -} - -#define is_second_extable_reloc(Start, Cur, Sec) \ - (((Cur) == (Start) + 1) && (strcmp("__ex_table", (Sec)) == 0)) - -static void report_extable_warnings(const char* modname, struct elf_info* elf, - const struct sectioncheck* const mismatch, - Elf_Rela* r, Elf_Sym* sym, - const char* fromsec, const char* tosec) -{ - Elf_Sym* fromsym = find_elf_symbol2(elf, r->r_offset, fromsec); - const char* fromsym_name = sym_name(elf, fromsym); - Elf_Sym* tosym = find_elf_symbol(elf, r->r_addend, sym); - const char* tosym_name = sym_name(elf, tosym); - const char* from_pretty_name; - const char* from_pretty_name_p; - const char* to_pretty_name; - const char* to_pretty_name_p; - - get_pretty_name(is_function(fromsym), - &from_pretty_name, &from_pretty_name_p); - get_pretty_name(is_function(tosym), - &to_pretty_name, &to_pretty_name_p); - - warn("%s(%s+0x%lx): Section mismatch in reference" - " from the %s %s%s to the %s %s:%s%s\n", - modname, fromsec, (long)r->r_offset, from_pretty_name, - fromsym_name, from_pretty_name_p, - to_pretty_name, tosec, tosym_name, to_pretty_name_p); - - if (!match(tosec, mismatch->bad_tosec) && - is_executable_section(elf, get_secindex(elf, sym))) - fprintf(stderr, - "The relocation at %s+0x%lx references\n" - "section \"%s\" which is not in the list of\n" - "authorized sections. If you're adding a new section\n" - "and/or if this reference is valid, add \"%s\" to the\n" - "list of authorized sections to jump to on fault.\n" - "This can be achieved by adding \"%s\" to \n" - "OTHER_TEXT_SECTIONS in scripts/mod/modpost.c.\n", - fromsec, (long)r->r_offset, tosec, tosec, tosec); -} - -static void extable_mismatch_handler(const char* modname, struct elf_info *elf, - const struct sectioncheck* const mismatch, - Elf_Rela* r, Elf_Sym* sym, - const char *fromsec) -{ - const char* tosec = sec_name(elf, get_secindex(elf, sym)); - - sec_mismatch_count++; - - if (sec_mismatch_verbose) - report_extable_warnings(modname, elf, mismatch, r, sym, - fromsec, tosec); - - if (match(tosec, mismatch->bad_tosec)) - fatal("The relocation at %s+0x%lx references\n" - "section \"%s\" which is black-listed.\n" - "Something is seriously wrong and should be fixed.\n" - "You might get more information about where this is\n" - "coming from by using scripts/check_extable.sh %s\n", - fromsec, (long)r->r_offset, tosec, modname); - else if (!is_executable_section(elf, get_secindex(elf, sym))) { - if (is_extable_fault_address(r)) - fatal("The relocation at %s+0x%lx references\n" - "section \"%s\" which is not executable, IOW\n" - "it is not possible for the kernel to fault\n" - "at that address. Something is seriously wrong\n" - "and should be fixed.\n", - fromsec, (long)r->r_offset, tosec); - else - fatal("The relocation at %s+0x%lx references\n" - "section \"%s\" which is not executable, IOW\n" - "the kernel will fault if it ever tries to\n" - "jump to it. Something is seriously wrong\n" - "and should be fixed.\n", - fromsec, (long)r->r_offset, tosec); - } -} - -static void check_section_mismatch(const char *modname, struct elf_info *elf, - Elf_Rela *r, Elf_Sym *sym, const char *fromsec) -{ - const char *tosec = sec_name(elf, get_secindex(elf, sym));; - const struct sectioncheck *mismatch = section_mismatch(fromsec, tosec); - - if (mismatch) { - if (mismatch->handler) - mismatch->handler(modname, elf, mismatch, - r, sym, fromsec); - else - default_mismatch_handler(modname, elf, mismatch, - r, sym, fromsec); - } -} - -static unsigned int *reloc_location(struct elf_info *elf, - Elf_Shdr *sechdr, Elf_Rela *r) -{ - Elf_Shdr *sechdrs = elf->sechdrs; - int section = sechdr->sh_info; - - return (void *)elf->hdr + sechdrs[section].sh_offset + - r->r_offset; -} - -static int addend_386_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) -{ - unsigned int r_typ = ELF_R_TYPE(r->r_info); - unsigned int *location = reloc_location(elf, sechdr, r); - - switch (r_typ) { - case R_386_32: - r->r_addend = TO_NATIVE(*location); - break; - case R_386_PC32: - r->r_addend = TO_NATIVE(*location) + 4; - /* For CONFIG_RELOCATABLE=y */ - if (elf->hdr->e_type == ET_EXEC) - r->r_addend += r->r_offset; - break; - } - return 0; -} - -#ifndef R_ARM_CALL -#define R_ARM_CALL 28 -#endif -#ifndef R_ARM_JUMP24 -#define R_ARM_JUMP24 29 -#endif - -#ifndef R_ARM_THM_CALL -#define R_ARM_THM_CALL 10 -#endif -#ifndef R_ARM_THM_JUMP24 -#define R_ARM_THM_JUMP24 30 -#endif -#ifndef R_ARM_THM_JUMP19 -#define R_ARM_THM_JUMP19 51 -#endif - -static int addend_arm_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) -{ - unsigned int r_typ = ELF_R_TYPE(r->r_info); - - switch (r_typ) { - case R_ARM_ABS32: - /* From ARM ABI: (S + A) | T */ - r->r_addend = (int)(long) - (elf->symtab_start + ELF_R_SYM(r->r_info)); - break; - case R_ARM_PC24: - case R_ARM_CALL: - case R_ARM_JUMP24: - case R_ARM_THM_CALL: - case R_ARM_THM_JUMP24: - case R_ARM_THM_JUMP19: - /* From ARM ABI: ((S + A) | T) - P */ - r->r_addend = (int)(long)(elf->hdr + - sechdr->sh_offset + - (r->r_offset - sechdr->sh_addr)); - break; - default: - return 1; - } - return 0; -} - -static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r) -{ - unsigned int r_typ = ELF_R_TYPE(r->r_info); - unsigned int *location = reloc_location(elf, sechdr, r); - unsigned int inst; - - if (r_typ == R_MIPS_HI16) - return 1; /* skip this */ - inst = TO_NATIVE(*location); - switch (r_typ) { - case R_MIPS_LO16: - r->r_addend = inst & 0xffff; - break; - case R_MIPS_26: - r->r_addend = (inst & 0x03ffffff) << 2; - break; - case R_MIPS_32: - r->r_addend = inst; - break; - } - return 0; -} - -static void section_rela(const char *modname, struct elf_info *elf, - Elf_Shdr *sechdr) -{ - Elf_Sym *sym; - Elf_Rela *rela; - Elf_Rela r; - unsigned int r_sym; - const char *fromsec; - - Elf_Rela *start = (void *)elf->hdr + sechdr->sh_offset; - Elf_Rela *stop = (void *)start + sechdr->sh_size; - - fromsec = sech_name(elf, sechdr); - fromsec += strlen(".rela"); - /* if from section (name) is know good then skip it */ - if (match(fromsec, section_white_list)) - return; - - for (rela = start; rela < stop; rela++) { - r.r_offset = TO_NATIVE(rela->r_offset); -#if KERNEL_ELFCLASS == ELFCLASS64 - if (elf->hdr->e_machine == EM_MIPS) { - unsigned int r_typ; - r_sym = ELF64_MIPS_R_SYM(rela->r_info); - r_sym = TO_NATIVE(r_sym); - r_typ = ELF64_MIPS_R_TYPE(rela->r_info); - r.r_info = ELF64_R_INFO(r_sym, r_typ); - } else { - r.r_info = TO_NATIVE(rela->r_info); - r_sym = ELF_R_SYM(r.r_info); - } -#else - r.r_info = TO_NATIVE(rela->r_info); - r_sym = ELF_R_SYM(r.r_info); -#endif - r.r_addend = TO_NATIVE(rela->r_addend); - sym = elf->symtab_start + r_sym; - /* Skip special sections */ - if (is_shndx_special(sym->st_shndx)) - continue; - if (is_second_extable_reloc(start, rela, fromsec)) - find_extable_entry_size(fromsec, &r); - check_section_mismatch(modname, elf, &r, sym, fromsec); - } -} - -static void section_rel(const char *modname, struct elf_info *elf, - Elf_Shdr *sechdr) -{ - Elf_Sym *sym; - Elf_Rel *rel; - Elf_Rela r; - unsigned int r_sym; - const char *fromsec; - - Elf_Rel *start = (void *)elf->hdr + sechdr->sh_offset; - Elf_Rel *stop = (void *)start + sechdr->sh_size; - - fromsec = sech_name(elf, sechdr); - fromsec += strlen(".rel"); - /* if from section (name) is know good then skip it */ - if (match(fromsec, section_white_list)) - return; - - for (rel = start; rel < stop; rel++) { - r.r_offset = TO_NATIVE(rel->r_offset); -#if KERNEL_ELFCLASS == ELFCLASS64 - if (elf->hdr->e_machine == EM_MIPS) { - unsigned int r_typ; - r_sym = ELF64_MIPS_R_SYM(rel->r_info); - r_sym = TO_NATIVE(r_sym); - r_typ = ELF64_MIPS_R_TYPE(rel->r_info); - r.r_info = ELF64_R_INFO(r_sym, r_typ); - } else { - r.r_info = TO_NATIVE(rel->r_info); - r_sym = ELF_R_SYM(r.r_info); - } -#else - r.r_info = TO_NATIVE(rel->r_info); - r_sym = ELF_R_SYM(r.r_info); -#endif - r.r_addend = 0; - switch (elf->hdr->e_machine) { - case EM_386: - if (addend_386_rel(elf, sechdr, &r)) - continue; - break; - case EM_ARM: - if (addend_arm_rel(elf, sechdr, &r)) - continue; - break; - case EM_MIPS: - if (addend_mips_rel(elf, sechdr, &r)) - continue; - break; - } - sym = elf->symtab_start + r_sym; - /* Skip special sections */ - if (is_shndx_special(sym->st_shndx)) - continue; - if (is_second_extable_reloc(start, rel, fromsec)) - find_extable_entry_size(fromsec, &r); - check_section_mismatch(modname, elf, &r, sym, fromsec); - } -} - -/** - * A module includes a number of sections that are discarded - * either when loaded or when used as built-in. - * For loaded modules all functions marked __init and all data - * marked __initdata will be discarded when the module has been initialized. - * Likewise for modules used built-in the sections marked __exit - * are discarded because __exit marked function are supposed to be called - * only when a module is unloaded which never happens for built-in modules. - * The check_sec_ref() function traverses all relocation records - * to find all references to a section that reference a section that will - * be discarded and warns about it. - **/ -static void check_sec_ref(struct module *mod, const char *modname, - struct elf_info *elf) -{ - int i; - Elf_Shdr *sechdrs = elf->sechdrs; - - /* Walk through all sections */ - for (i = 0; i < elf->num_sections; i++) { - check_section(modname, elf, &elf->sechdrs[i]); - /* We want to process only relocation sections and not .init */ - if (sechdrs[i].sh_type == SHT_RELA) - section_rela(modname, elf, &elf->sechdrs[i]); - else if (sechdrs[i].sh_type == SHT_REL) - section_rel(modname, elf, &elf->sechdrs[i]); - } -} - -static char *remove_dot(char *s) -{ - size_t n = strcspn(s, "."); - - if (n && s[n]) { - size_t m = strspn(s + n + 1, "0123456789"); - if (m && (s[n + m] == '.' || s[n + m] == 0)) - s[n] = 0; - } - return s; -} - -static void read_symbols(char *modname) -{ - const char *symname; - char *version; - char *license; - struct module *mod; - struct elf_info info = { }; - Elf_Sym *sym; - - if (!parse_elf(&info, modname)) - return; - - mod = new_module(modname); - - /* When there's no vmlinux, don't print warnings about - * unresolved symbols (since there'll be too many ;) */ - if (is_vmlinux(modname)) { - have_vmlinux = 1; - mod->skip = 1; - } - - license = get_modinfo(info.modinfo, info.modinfo_len, "license"); - if (info.modinfo && !license && !is_vmlinux(modname)) - warn("modpost: missing MODULE_LICENSE() in %s\n" - "see include/linux/module.h for " - "more information\n", modname); - while (license) { - if (license_is_gpl_compatible(license)) - mod->gpl_compatible = 1; - else { - mod->gpl_compatible = 0; - break; - } - license = get_next_modinfo(info.modinfo, info.modinfo_len, - "license", license); - } - - for (sym = info.symtab_start; sym < info.symtab_stop; sym++) { - symname = remove_dot(info.strtab + sym->st_name); - - handle_modversions(mod, &info, sym, symname); - handle_moddevtable(mod, &info, sym, symname); - } - if (!is_vmlinux(modname) || - (is_vmlinux(modname) && vmlinux_section_warnings)) - check_sec_ref(mod, modname, &info); - - version = get_modinfo(info.modinfo, info.modinfo_len, "version"); - if (version) - maybe_frob_rcs_version(modname, version, info.modinfo, - version - (char *)info.hdr); - if (version || (all_versions && !is_vmlinux(modname))) - get_src_version(modname, mod->srcversion, - sizeof(mod->srcversion)-1); - - parse_elf_finish(&info); - - /* Our trick to get versioning for module struct etc. - it's - * never passed as an argument to an exported function, so - * the automatic versioning doesn't pick it up, but it's really - * important anyhow */ - if (modversions) - mod->unres = alloc_symbol("module_layout", 0, mod->unres); -} - -static void read_symbols_from_files(const char *filename) -{ - FILE *in = stdin; - char fname[PATH_MAX]; - - if (strcmp(filename, "-") != 0) { - in = fopen(filename, "r"); - if (!in) - fatal("Can't open filenames file %s: %m", filename); - } - - while (fgets(fname, PATH_MAX, in) != NULL) { - if (strends(fname, "\n")) - fname[strlen(fname)-1] = '\0'; - read_symbols(fname); - } - - if (in != stdin) - fclose(in); -} - -#define SZ 500 - -/* We first write the generated file into memory using the - * following helper, then compare to the file on disk and - * only update the later if anything changed */ - -void __attribute__((format(printf, 2, 3))) buf_printf(struct buffer *buf, - const char *fmt, ...) -{ - char tmp[SZ]; - int len; - va_list ap; - - va_start(ap, fmt); - len = vsnprintf(tmp, SZ, fmt, ap); - buf_write(buf, tmp, len); - va_end(ap); -} - -void buf_write(struct buffer *buf, const char *s, int len) -{ - if (buf->size - buf->pos < len) { - buf->size += len + SZ; - buf->p = realloc(buf->p, buf->size); - } - strncpy(buf->p + buf->pos, s, len); - buf->pos += len; -} - -static void check_for_gpl_usage(enum export exp, const char *m, const char *s) -{ - const char *e = is_vmlinux(m) ?"":".ko"; - - switch (exp) { - case export_gpl: - fatal("modpost: GPL-incompatible module %s%s " - "uses GPL-only symbol '%s'\n", m, e, s); - break; - case export_unused_gpl: - fatal("modpost: GPL-incompatible module %s%s " - "uses GPL-only symbol marked UNUSED '%s'\n", m, e, s); - break; - case export_gpl_future: - warn("modpost: GPL-incompatible module %s%s " - "uses future GPL-only symbol '%s'\n", m, e, s); - break; - case export_plain: - case export_unused: - case export_unknown: - /* ignore */ - break; - } -} - -static void check_for_unused(enum export exp, const char *m, const char *s) -{ - const char *e = is_vmlinux(m) ?"":".ko"; - - switch (exp) { - case export_unused: - case export_unused_gpl: - warn("modpost: module %s%s " - "uses symbol '%s' marked UNUSED\n", m, e, s); - break; - default: - /* ignore */ - break; - } -} - -static void check_exports(struct module *mod) -{ - struct symbol *s, *exp; - - for (s = mod->unres; s; s = s->next) { - const char *basename; - exp = find_symbol(s->name); - if (!exp || exp->module == mod) - continue; - basename = strrchr(mod->name, '/'); - if (basename) - basename++; - else - basename = mod->name; - if (!mod->gpl_compatible) - check_for_gpl_usage(exp->export, basename, exp->name); - check_for_unused(exp->export, basename, exp->name); - } -} - -/** - * Header for the generated file - **/ -static void add_header(struct buffer *b, struct module *mod) -{ - buf_printf(b, "#include \n"); - buf_printf(b, "#include \n"); - buf_printf(b, "#include \n"); - buf_printf(b, "\n"); - buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n"); - buf_printf(b, "\n"); - buf_printf(b, "__visible struct module __this_module\n"); - buf_printf(b, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n"); - buf_printf(b, "\t.name = KBUILD_MODNAME,\n"); - if (mod->has_init) - buf_printf(b, "\t.init = init_module,\n"); - if (mod->has_cleanup) - buf_printf(b, "#ifdef CONFIG_MODULE_UNLOAD\n" - "\t.exit = cleanup_module,\n" - "#endif\n"); - buf_printf(b, "\t.arch = MODULE_ARCH_INIT,\n"); - buf_printf(b, "};\n"); -} - -static void add_intree_flag(struct buffer *b, int is_intree) -{ - if (is_intree) - buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n"); -} - -static void add_staging_flag(struct buffer *b, const char *name) -{ - static const char *staging_dir = "drivers/staging"; - - if (strncmp(staging_dir, name, strlen(staging_dir)) == 0) - buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n"); -} - -/* In kernel, this size is defined in linux/module.h; - * here we use Elf_Addr instead of long for covering cross-compile - */ -#define MODULE_NAME_LEN (64 - sizeof(Elf_Addr)) - -/** - * Record CRCs for unresolved symbols - **/ -static int add_versions(struct buffer *b, struct module *mod) -{ - struct symbol *s, *exp; - int err = 0; - - for (s = mod->unres; s; s = s->next) { - exp = find_symbol(s->name); - if (!exp || exp->module == mod) { - if (have_vmlinux && !s->weak) { - if (warn_unresolved) { - warn("\"%s\" [%s.ko] undefined!\n", - s->name, mod->name); - } else { - merror("\"%s\" [%s.ko] undefined!\n", - s->name, mod->name); - err = 1; - } - } - continue; - } - s->module = exp->module; - s->crc_valid = exp->crc_valid; - s->crc = exp->crc; - } - - if (!modversions) - return err; - - buf_printf(b, "\n"); - buf_printf(b, "static const struct modversion_info ____versions[]\n"); - buf_printf(b, "__used\n"); - buf_printf(b, "__attribute__((section(\"__versions\"))) = {\n"); - - for (s = mod->unres; s; s = s->next) { - if (!s->module) - continue; - if (!s->crc_valid) { - warn("\"%s\" [%s.ko] has no CRC!\n", - s->name, mod->name); - continue; - } - if (strlen(s->name) >= MODULE_NAME_LEN) { - merror("too long symbol \"%s\" [%s.ko]\n", - s->name, mod->name); - err = 1; - break; - } - buf_printf(b, "\t{ %#8x, __VMLINUX_SYMBOL_STR(%s) },\n", - s->crc, s->name); - } - - buf_printf(b, "};\n"); - - return err; -} - -static void add_depends(struct buffer *b, struct module *mod, - struct module *modules) -{ - struct symbol *s; - struct module *m; - int first = 1; - - for (m = modules; m; m = m->next) - m->seen = is_vmlinux(m->name); - - buf_printf(b, "\n"); - buf_printf(b, "static const char __module_depends[]\n"); - buf_printf(b, "__used\n"); - buf_printf(b, "__attribute__((section(\".modinfo\"))) =\n"); - buf_printf(b, "\"depends="); - for (s = mod->unres; s; s = s->next) { - const char *p; - if (!s->module) - continue; - - if (s->module->seen) - continue; - - s->module->seen = 1; - p = strrchr(s->module->name, '/'); - if (p) - p++; - else - p = s->module->name; - buf_printf(b, "%s%s", first ? "" : ",", p); - first = 0; - } - buf_printf(b, "\";\n"); -} - -static void add_srcversion(struct buffer *b, struct module *mod) -{ - if (mod->srcversion[0]) { - buf_printf(b, "\n"); - buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n", - mod->srcversion); - } -} - -static void write_if_changed(struct buffer *b, const char *fname) -{ - char *tmp; - FILE *file; - struct stat st; - - file = fopen(fname, "r"); - if (!file) - goto write; - - if (fstat(fileno(file), &st) < 0) - goto close_write; - - if (st.st_size != b->pos) - goto close_write; - - tmp = NOFAIL(malloc(b->pos)); - if (fread(tmp, 1, b->pos, file) != b->pos) - goto free_write; - - if (memcmp(tmp, b->p, b->pos) != 0) - goto free_write; - - free(tmp); - fclose(file); - return; - - free_write: - free(tmp); - close_write: - fclose(file); - write: - file = fopen(fname, "w"); - if (!file) { - perror(fname); - exit(1); - } - if (fwrite(b->p, 1, b->pos, file) != b->pos) { - perror(fname); - exit(1); - } - fclose(file); -} - -/* parse Module.symvers file. line format: - * 0x12345678symbolmodule[[export]something] - **/ -static void read_dump(const char *fname, unsigned int kernel) -{ - unsigned long size, pos = 0; - void *file = grab_file(fname, &size); - char *line; - - if (!file) - /* No symbol versions, silently ignore */ - return; - - while ((line = get_next_line(&pos, file, size))) { - char *symname, *modname, *d, *export, *end; - unsigned int crc; - struct module *mod; - struct symbol *s; - - if (!(symname = strchr(line, '\t'))) - goto fail; - *symname++ = '\0'; - if (!(modname = strchr(symname, '\t'))) - goto fail; - *modname++ = '\0'; - if ((export = strchr(modname, '\t')) != NULL) - *export++ = '\0'; - if (export && ((end = strchr(export, '\t')) != NULL)) - *end = '\0'; - crc = strtoul(line, &d, 16); - if (*symname == '\0' || *modname == '\0' || *d != '\0') - goto fail; - mod = find_module(modname); - if (!mod) { - if (is_vmlinux(modname)) - have_vmlinux = 1; - mod = new_module(modname); - mod->skip = 1; - } - s = sym_add_exported(symname, mod, export_no(export)); - s->kernel = kernel; - s->preloaded = 1; - sym_update_crc(symname, mod, crc, export_no(export)); - } - release_file(file, size); - return; -fail: - release_file(file, size); - fatal("parse error in symbol dump file\n"); -} - -/* For normal builds always dump all symbols. - * For external modules only dump symbols - * that are not read from kernel Module.symvers. - **/ -static int dump_sym(struct symbol *sym) -{ - if (!external_module) - return 1; - if (sym->vmlinux || sym->kernel) - return 0; - return 1; -} - -static void write_dump(const char *fname) -{ - struct buffer buf = { }; - struct symbol *symbol; - int n; - - for (n = 0; n < SYMBOL_HASH_SIZE ; n++) { - symbol = symbolhash[n]; - while (symbol) { - if (dump_sym(symbol)) - buf_printf(&buf, "0x%08x\t%s\t%s\t%s\n", - symbol->crc, symbol->name, - symbol->module->name, - export_str(symbol->export)); - symbol = symbol->next; - } - } - write_if_changed(&buf, fname); -} - -struct ext_sym_list { - struct ext_sym_list *next; - const char *file; -}; - -int main(int argc, char **argv) -{ - struct module *mod; - struct buffer buf = { }; - char *kernel_read = NULL, *module_read = NULL; - char *dump_write = NULL, *files_source = NULL; - int opt; - int err; - struct ext_sym_list *extsym_iter; - struct ext_sym_list *extsym_start = NULL; - - while ((opt = getopt(argc, argv, "i:I:e:mnsST:o:awM:K:E")) != -1) { - switch (opt) { - case 'i': - kernel_read = optarg; - break; - case 'I': - module_read = optarg; - external_module = 1; - break; - case 'e': - external_module = 1; - extsym_iter = - NOFAIL(malloc(sizeof(*extsym_iter))); - extsym_iter->next = extsym_start; - extsym_iter->file = optarg; - extsym_start = extsym_iter; - break; - case 'm': - modversions = 1; - break; - case 'n': - ignore_missing_files = 1; - break; - case 'o': - dump_write = optarg; - break; - case 'a': - all_versions = 1; - break; - case 's': - vmlinux_section_warnings = 0; - break; - case 'S': - sec_mismatch_verbose = 0; - break; - case 'T': - files_source = optarg; - break; - case 'w': - warn_unresolved = 1; - break; - case 'E': - sec_mismatch_fatal = 1; - break; - default: - exit(1); - } - } - - if (kernel_read) - read_dump(kernel_read, 1); - if (module_read) - read_dump(module_read, 0); - while (extsym_start) { - read_dump(extsym_start->file, 0); - extsym_iter = extsym_start->next; - free(extsym_start); - extsym_start = extsym_iter; - } - - while (optind < argc) - read_symbols(argv[optind++]); - - if (files_source) - read_symbols_from_files(files_source); - - for (mod = modules; mod; mod = mod->next) { - if (mod->skip) - continue; - check_exports(mod); - } - - err = 0; - - for (mod = modules; mod; mod = mod->next) { - char fname[PATH_MAX]; - - if (mod->skip) - continue; - - buf.pos = 0; - - add_header(&buf, mod); - add_intree_flag(&buf, !external_module); - add_staging_flag(&buf, mod->name); - err |= add_versions(&buf, mod); - add_depends(&buf, mod, modules); - add_moddevtable(&buf, mod); - add_srcversion(&buf, mod); - - sprintf(fname, "%s.mod.c", mod->name); - write_if_changed(&buf, fname); - } - if (dump_write) - write_dump(dump_write); - if (sec_mismatch_count) { - if (!sec_mismatch_verbose) { - warn("modpost: Found %d section mismatch(es).\n" - "To see full details build your kernel with:\n" - "'make CONFIG_DEBUG_SECTION_MISMATCH=y'\n", - sec_mismatch_count); - } - if (sec_mismatch_fatal) { - fatal("modpost: Section mismatches detected.\n" - "Set CONFIG_SECTION_MISMATCH_WARN_ONLY=y to allow them.\n"); - } - } - - return err; -} diff --git a/src/linux/scripts/mod/modpost.h b/src/linux/scripts/mod/modpost.h deleted file mode 100644 index 6a5e151..0000000 --- a/src/linux/scripts/mod/modpost.h +++ /dev/null @@ -1,193 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "elfconfig.h" - -/* On BSD-alike OSes elf.h defines these according to host's word size */ -#undef ELF_ST_BIND -#undef ELF_ST_TYPE -#undef ELF_R_SYM -#undef ELF_R_TYPE - -#if KERNEL_ELFCLASS == ELFCLASS32 - -#define Elf_Ehdr Elf32_Ehdr -#define Elf_Shdr Elf32_Shdr -#define Elf_Sym Elf32_Sym -#define Elf_Addr Elf32_Addr -#define Elf_Sword Elf64_Sword -#define Elf_Section Elf32_Half -#define ELF_ST_BIND ELF32_ST_BIND -#define ELF_ST_TYPE ELF32_ST_TYPE - -#define Elf_Rel Elf32_Rel -#define Elf_Rela Elf32_Rela -#define ELF_R_SYM ELF32_R_SYM -#define ELF_R_TYPE ELF32_R_TYPE -#else - -#define Elf_Ehdr Elf64_Ehdr -#define Elf_Shdr Elf64_Shdr -#define Elf_Sym Elf64_Sym -#define Elf_Addr Elf64_Addr -#define Elf_Sword Elf64_Sxword -#define Elf_Section Elf64_Half -#define ELF_ST_BIND ELF64_ST_BIND -#define ELF_ST_TYPE ELF64_ST_TYPE - -#define Elf_Rel Elf64_Rel -#define Elf_Rela Elf64_Rela -#define ELF_R_SYM ELF64_R_SYM -#define ELF_R_TYPE ELF64_R_TYPE -#endif - -/* The 64-bit MIPS ELF ABI uses an unusual reloc format. */ -typedef struct -{ - Elf32_Word r_sym; /* Symbol index */ - unsigned char r_ssym; /* Special symbol for 2nd relocation */ - unsigned char r_type3; /* 3rd relocation type */ - unsigned char r_type2; /* 2nd relocation type */ - unsigned char r_type1; /* 1st relocation type */ -} _Elf64_Mips_R_Info; - -typedef union -{ - Elf64_Xword r_info_number; - _Elf64_Mips_R_Info r_info_fields; -} _Elf64_Mips_R_Info_union; - -#define ELF64_MIPS_R_SYM(i) \ - ((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_sym) - -#define ELF64_MIPS_R_TYPE(i) \ - ((__extension__ (_Elf64_Mips_R_Info_union)(i)).r_info_fields.r_type1) - -#if KERNEL_ELFDATA != HOST_ELFDATA - -static inline void __endian(const void *src, void *dest, unsigned int size) -{ - unsigned int i; - for (i = 0; i < size; i++) - ((unsigned char*)dest)[i] = ((unsigned char*)src)[size - i-1]; -} - -#define TO_NATIVE(x) \ -({ \ - typeof(x) __x; \ - __endian(&(x), &(__x), sizeof(__x)); \ - __x; \ -}) - -#else /* endianness matches */ - -#define TO_NATIVE(x) (x) - -#endif - -#define NOFAIL(ptr) do_nofail((ptr), #ptr) -void *do_nofail(void *ptr, const char *expr); - -struct buffer { - char *p; - int pos; - int size; -}; - -void __attribute__((format(printf, 2, 3))) -buf_printf(struct buffer *buf, const char *fmt, ...); - -void -buf_write(struct buffer *buf, const char *s, int len); - -struct module { - struct module *next; - const char *name; - int gpl_compatible; - struct symbol *unres; - int seen; - int skip; - int has_init; - int has_cleanup; - struct buffer dev_table_buf; - char srcversion[25]; - int is_dot_o; -}; - -struct elf_info { - unsigned long size; - Elf_Ehdr *hdr; - Elf_Shdr *sechdrs; - Elf_Sym *symtab_start; - Elf_Sym *symtab_stop; - Elf_Section export_sec; - Elf_Section export_unused_sec; - Elf_Section export_gpl_sec; - Elf_Section export_unused_gpl_sec; - Elf_Section export_gpl_future_sec; - char *strtab; - char *modinfo; - unsigned int modinfo_len; - - /* support for 32bit section numbers */ - - unsigned int num_sections; /* max_secindex + 1 */ - unsigned int secindex_strings; - /* if Nth symbol table entry has .st_shndx = SHN_XINDEX, - * take shndx from symtab_shndx_start[N] instead */ - Elf32_Word *symtab_shndx_start; - Elf32_Word *symtab_shndx_stop; -}; - -static inline int is_shndx_special(unsigned int i) -{ - return i != SHN_XINDEX && i >= SHN_LORESERVE && i <= SHN_HIRESERVE; -} - -/* - * Move reserved section indices SHN_LORESERVE..SHN_HIRESERVE out of - * the way to -256..-1, to avoid conflicting with real section - * indices. - */ -#define SPECIAL(i) ((i) - (SHN_HIRESERVE + 1)) - -/* Accessor for sym->st_shndx, hides ugliness of "64k sections" */ -static inline unsigned int get_secindex(const struct elf_info *info, - const Elf_Sym *sym) -{ - if (is_shndx_special(sym->st_shndx)) - return SPECIAL(sym->st_shndx); - if (sym->st_shndx != SHN_XINDEX) - return sym->st_shndx; - return info->symtab_shndx_start[sym - info->symtab_start]; -} - -/* file2alias.c */ -extern unsigned int cross_build; -void handle_moddevtable(struct module *mod, struct elf_info *info, - Elf_Sym *sym, const char *symname); -void add_moddevtable(struct buffer *buf, struct module *mod); - -/* sumversion.c */ -void maybe_frob_rcs_version(const char *modfilename, - char *version, - void *modinfo, - unsigned long modinfo_offset); -void get_src_version(const char *modname, char sum[], unsigned sumlen); - -/* from modpost.c */ -void *grab_file(const char *filename, unsigned long *size); -char* get_next_line(unsigned long *pos, void *file, unsigned long size); -void release_file(void *file, unsigned long size); - -void fatal(const char *fmt, ...); -void warn(const char *fmt, ...); -void merror(const char *fmt, ...); diff --git a/src/linux/scripts/mod/sumversion.c b/src/linux/scripts/mod/sumversion.c deleted file mode 100644 index 944418d..0000000 --- a/src/linux/scripts/mod/sumversion.c +++ /dev/null @@ -1,519 +0,0 @@ -#include -#ifdef __sun__ -#include -#else -#include -#endif -#include -#include -#include -#include -#include "modpost.h" - -/* - * Stolen form Cryptographic API. - * - * MD4 Message Digest Algorithm (RFC1320). - * - * Implementation derived from Andrew Tridgell and Steve French's - * CIFS MD4 implementation, and the cryptoapi implementation - * originally based on the public domain implementation written - * by Colin Plumb in 1993. - * - * Copyright (c) Andrew Tridgell 1997-1998. - * Modified by Steve French (sfrench@us.ibm.com) 2002 - * Copyright (c) Cryptoapi developers. - * Copyright (c) 2002 David S. Miller (davem@redhat.com) - * Copyright (c) 2002 James Morris - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - */ -#define MD4_DIGEST_SIZE 16 -#define MD4_HMAC_BLOCK_SIZE 64 -#define MD4_BLOCK_WORDS 16 -#define MD4_HASH_WORDS 4 - -struct md4_ctx { - uint32_t hash[MD4_HASH_WORDS]; - uint32_t block[MD4_BLOCK_WORDS]; - uint64_t byte_count; -}; - -static inline uint32_t lshift(uint32_t x, unsigned int s) -{ - x &= 0xFFFFFFFF; - return ((x << s) & 0xFFFFFFFF) | (x >> (32 - s)); -} - -static inline uint32_t F(uint32_t x, uint32_t y, uint32_t z) -{ - return (x & y) | ((~x) & z); -} - -static inline uint32_t G(uint32_t x, uint32_t y, uint32_t z) -{ - return (x & y) | (x & z) | (y & z); -} - -static inline uint32_t H(uint32_t x, uint32_t y, uint32_t z) -{ - return x ^ y ^ z; -} - -#define ROUND1(a,b,c,d,k,s) (a = lshift(a + F(b,c,d) + k, s)) -#define ROUND2(a,b,c,d,k,s) (a = lshift(a + G(b,c,d) + k + (uint32_t)0x5A827999,s)) -#define ROUND3(a,b,c,d,k,s) (a = lshift(a + H(b,c,d) + k + (uint32_t)0x6ED9EBA1,s)) - -/* XXX: this stuff can be optimized */ -static inline void le32_to_cpu_array(uint32_t *buf, unsigned int words) -{ - while (words--) { - *buf = ntohl(*buf); - buf++; - } -} - -static inline void cpu_to_le32_array(uint32_t *buf, unsigned int words) -{ - while (words--) { - *buf = htonl(*buf); - buf++; - } -} - -static void md4_transform(uint32_t *hash, uint32_t const *in) -{ - uint32_t a, b, c, d; - - a = hash[0]; - b = hash[1]; - c = hash[2]; - d = hash[3]; - - ROUND1(a, b, c, d, in[0], 3); - ROUND1(d, a, b, c, in[1], 7); - ROUND1(c, d, a, b, in[2], 11); - ROUND1(b, c, d, a, in[3], 19); - ROUND1(a, b, c, d, in[4], 3); - ROUND1(d, a, b, c, in[5], 7); - ROUND1(c, d, a, b, in[6], 11); - ROUND1(b, c, d, a, in[7], 19); - ROUND1(a, b, c, d, in[8], 3); - ROUND1(d, a, b, c, in[9], 7); - ROUND1(c, d, a, b, in[10], 11); - ROUND1(b, c, d, a, in[11], 19); - ROUND1(a, b, c, d, in[12], 3); - ROUND1(d, a, b, c, in[13], 7); - ROUND1(c, d, a, b, in[14], 11); - ROUND1(b, c, d, a, in[15], 19); - - ROUND2(a, b, c, d,in[ 0], 3); - ROUND2(d, a, b, c, in[4], 5); - ROUND2(c, d, a, b, in[8], 9); - ROUND2(b, c, d, a, in[12], 13); - ROUND2(a, b, c, d, in[1], 3); - ROUND2(d, a, b, c, in[5], 5); - ROUND2(c, d, a, b, in[9], 9); - ROUND2(b, c, d, a, in[13], 13); - ROUND2(a, b, c, d, in[2], 3); - ROUND2(d, a, b, c, in[6], 5); - ROUND2(c, d, a, b, in[10], 9); - ROUND2(b, c, d, a, in[14], 13); - ROUND2(a, b, c, d, in[3], 3); - ROUND2(d, a, b, c, in[7], 5); - ROUND2(c, d, a, b, in[11], 9); - ROUND2(b, c, d, a, in[15], 13); - - ROUND3(a, b, c, d,in[ 0], 3); - ROUND3(d, a, b, c, in[8], 9); - ROUND3(c, d, a, b, in[4], 11); - ROUND3(b, c, d, a, in[12], 15); - ROUND3(a, b, c, d, in[2], 3); - ROUND3(d, a, b, c, in[10], 9); - ROUND3(c, d, a, b, in[6], 11); - ROUND3(b, c, d, a, in[14], 15); - ROUND3(a, b, c, d, in[1], 3); - ROUND3(d, a, b, c, in[9], 9); - ROUND3(c, d, a, b, in[5], 11); - ROUND3(b, c, d, a, in[13], 15); - ROUND3(a, b, c, d, in[3], 3); - ROUND3(d, a, b, c, in[11], 9); - ROUND3(c, d, a, b, in[7], 11); - ROUND3(b, c, d, a, in[15], 15); - - hash[0] += a; - hash[1] += b; - hash[2] += c; - hash[3] += d; -} - -static inline void md4_transform_helper(struct md4_ctx *ctx) -{ - le32_to_cpu_array(ctx->block, sizeof(ctx->block) / sizeof(uint32_t)); - md4_transform(ctx->hash, ctx->block); -} - -static void md4_init(struct md4_ctx *mctx) -{ - mctx->hash[0] = 0x67452301; - mctx->hash[1] = 0xefcdab89; - mctx->hash[2] = 0x98badcfe; - mctx->hash[3] = 0x10325476; - mctx->byte_count = 0; -} - -static void md4_update(struct md4_ctx *mctx, - const unsigned char *data, unsigned int len) -{ - const uint32_t avail = sizeof(mctx->block) - (mctx->byte_count & 0x3f); - - mctx->byte_count += len; - - if (avail > len) { - memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), - data, len); - return; - } - - memcpy((char *)mctx->block + (sizeof(mctx->block) - avail), - data, avail); - - md4_transform_helper(mctx); - data += avail; - len -= avail; - - while (len >= sizeof(mctx->block)) { - memcpy(mctx->block, data, sizeof(mctx->block)); - md4_transform_helper(mctx); - data += sizeof(mctx->block); - len -= sizeof(mctx->block); - } - - memcpy(mctx->block, data, len); -} - -static void md4_final_ascii(struct md4_ctx *mctx, char *out, unsigned int len) -{ - const unsigned int offset = mctx->byte_count & 0x3f; - char *p = (char *)mctx->block + offset; - int padding = 56 - (offset + 1); - - *p++ = 0x80; - if (padding < 0) { - memset(p, 0x00, padding + sizeof (uint64_t)); - md4_transform_helper(mctx); - p = (char *)mctx->block; - padding = 56; - } - - memset(p, 0, padding); - mctx->block[14] = mctx->byte_count << 3; - mctx->block[15] = mctx->byte_count >> 29; - le32_to_cpu_array(mctx->block, (sizeof(mctx->block) - - sizeof(uint64_t)) / sizeof(uint32_t)); - md4_transform(mctx->hash, mctx->block); - cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(uint32_t)); - - snprintf(out, len, "%08X%08X%08X%08X", - mctx->hash[0], mctx->hash[1], mctx->hash[2], mctx->hash[3]); -} - -static inline void add_char(unsigned char c, struct md4_ctx *md) -{ - md4_update(md, &c, 1); -} - -static int parse_string(const char *file, unsigned long len, - struct md4_ctx *md) -{ - unsigned long i; - - add_char(file[0], md); - for (i = 1; i < len; i++) { - add_char(file[i], md); - if (file[i] == '"' && file[i-1] != '\\') - break; - } - return i; -} - -static int parse_comment(const char *file, unsigned long len) -{ - unsigned long i; - - for (i = 2; i < len; i++) { - if (file[i-1] == '*' && file[i] == '/') - break; - } - return i; -} - -/* FIXME: Handle .s files differently (eg. # starts comments) --RR */ -static int parse_file(const char *fname, struct md4_ctx *md) -{ - char *file; - unsigned long i, len; - - file = grab_file(fname, &len); - if (!file) - return 0; - - for (i = 0; i < len; i++) { - /* Collapse and ignore \ and CR. */ - if (file[i] == '\\' && (i+1 < len) && file[i+1] == '\n') { - i++; - continue; - } - - /* Ignore whitespace */ - if (isspace(file[i])) - continue; - - /* Handle strings as whole units */ - if (file[i] == '"') { - i += parse_string(file+i, len - i, md); - continue; - } - - /* Comments: ignore */ - if (file[i] == '/' && file[i+1] == '*') { - i += parse_comment(file+i, len - i); - continue; - } - - add_char(file[i], md); - } - release_file(file, len); - return 1; -} -/* Check whether the file is a static library or not */ -static int is_static_library(const char *objfile) -{ - int len = strlen(objfile); - if (objfile[len - 2] == '.' && objfile[len - 1] == 'a') - return 1; - else - return 0; -} - -/* We have dir/file.o. Open dir/.file.o.cmd, look for source_ and deps_ line - * to figure out source files. */ -static int parse_source_files(const char *objfile, struct md4_ctx *md) -{ - char *cmd, *file, *line, *dir; - const char *base; - unsigned long flen, pos = 0; - int dirlen, ret = 0, check_files = 0; - - cmd = NOFAIL(malloc(strlen(objfile) + sizeof("..cmd"))); - - base = strrchr(objfile, '/'); - if (base) { - base++; - dirlen = base - objfile; - sprintf(cmd, "%.*s.%s.cmd", dirlen, objfile, base); - } else { - dirlen = 0; - sprintf(cmd, ".%s.cmd", objfile); - } - dir = NOFAIL(malloc(dirlen + 1)); - strncpy(dir, objfile, dirlen); - dir[dirlen] = '\0'; - - file = grab_file(cmd, &flen); - if (!file) { - warn("could not find %s for %s\n", cmd, objfile); - goto out; - } - - /* There will be a line like so: - deps_drivers/net/dummy.o := \ - drivers/net/dummy.c \ - $(wildcard include/config/net/fastroute.h) \ - include/linux/module.h \ - - Sum all files in the same dir or subdirs. - */ - while ((line = get_next_line(&pos, file, flen)) != NULL) { - char* p = line; - - if (strncmp(line, "source_", sizeof("source_")-1) == 0) { - p = strrchr(line, ' '); - if (!p) { - warn("malformed line: %s\n", line); - goto out_file; - } - p++; - if (!parse_file(p, md)) { - warn("could not open %s: %s\n", - p, strerror(errno)); - goto out_file; - } - continue; - } - if (strncmp(line, "deps_", sizeof("deps_")-1) == 0) { - check_files = 1; - continue; - } - if (!check_files) - continue; - - /* Continue until line does not end with '\' */ - if ( *(p + strlen(p)-1) != '\\') - break; - /* Terminate line at first space, to get rid of final ' \' */ - while (*p) { - if (isspace(*p)) { - *p = '\0'; - break; - } - p++; - } - - /* Check if this file is in same dir as objfile */ - if ((strstr(line, dir)+strlen(dir)-1) == strrchr(line, '/')) { - if (!parse_file(line, md)) { - warn("could not open %s: %s\n", - line, strerror(errno)); - goto out_file; - } - - } - - } - - /* Everyone parsed OK */ - ret = 1; -out_file: - release_file(file, flen); -out: - free(dir); - free(cmd); - return ret; -} - -/* Calc and record src checksum. */ -void get_src_version(const char *modname, char sum[], unsigned sumlen) -{ - void *file; - unsigned long len; - struct md4_ctx md; - char *sources, *end, *fname; - const char *basename; - char filelist[PATH_MAX + 1]; - char *modverdir = getenv("MODVERDIR"); - - if (!modverdir) - modverdir = "."; - - /* Source files for module are in .tmp_versions/modname.mod, - after the first line. */ - if (strrchr(modname, '/')) - basename = strrchr(modname, '/') + 1; - else - basename = modname; - snprintf(filelist, sizeof(filelist), "%s/%.*s.mod", modverdir, - (int) strlen(basename) - 2, basename); - - file = grab_file(filelist, &len); - if (!file) - /* not a module or .mod file missing - ignore */ - return; - - sources = strchr(file, '\n'); - if (!sources) { - warn("malformed versions file for %s\n", modname); - goto release; - } - - sources++; - end = strchr(sources, '\n'); - if (!end) { - warn("bad ending versions file for %s\n", modname); - goto release; - } - *end = '\0'; - - md4_init(&md); - while ((fname = strsep(&sources, " ")) != NULL) { - if (!*fname) - continue; - if (!(is_static_library(fname)) && - !parse_source_files(fname, &md)) - goto release; - } - - md4_final_ascii(&md, sum, sumlen); -release: - release_file(file, len); -} - -static void write_version(const char *filename, const char *sum, - unsigned long offset) -{ - int fd; - - fd = open(filename, O_RDWR); - if (fd < 0) { - warn("changing sum in %s failed: %s\n", - filename, strerror(errno)); - return; - } - - if (lseek(fd, offset, SEEK_SET) == (off_t)-1) { - warn("changing sum in %s:%lu failed: %s\n", - filename, offset, strerror(errno)); - goto out; - } - - if (write(fd, sum, strlen(sum)+1) != strlen(sum)+1) { - warn("writing sum in %s failed: %s\n", - filename, strerror(errno)); - goto out; - } -out: - close(fd); -} - -static int strip_rcs_crap(char *version) -{ - unsigned int len, full_len; - - if (strncmp(version, "$Revision", strlen("$Revision")) != 0) - return 0; - - /* Space for version string follows. */ - full_len = strlen(version) + strlen(version + strlen(version) + 1) + 2; - - /* Move string to start with version number: prefix will be - * $Revision$ or $Revision: */ - len = strlen("$Revision"); - if (version[len] == ':' || version[len] == '$') - len++; - while (isspace(version[len])) - len++; - memmove(version, version+len, full_len-len); - full_len -= len; - - /* Preserve up to next whitespace. */ - len = 0; - while (version[len] && !isspace(version[len])) - len++; - memmove(version + len, version + strlen(version), - full_len - strlen(version)); - return 1; -} - -/* Clean up RCS-style version numbers. */ -void maybe_frob_rcs_version(const char *modfilename, - char *version, - void *modinfo, - unsigned long version_offset) -{ - if (strip_rcs_crap(version)) - write_version(modfilename, version, version_offset); -} diff --git a/src/linux/scripts/selinux/genheaders/.gitignore b/src/linux/scripts/selinux/genheaders/.gitignore deleted file mode 100644 index 4c0b646..0000000 --- a/src/linux/scripts/selinux/genheaders/.gitignore +++ /dev/null @@ -1 +0,0 @@ -genheaders diff --git a/src/linux/scripts/selinux/mdp/.gitignore b/src/linux/scripts/selinux/mdp/.gitignore deleted file mode 100644 index 654546d..0000000 --- a/src/linux/scripts/selinux/mdp/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Generated file -mdp diff --git a/src/linux/scripts/setlocalversion b/src/linux/scripts/setlocalversion deleted file mode 100755 index 966dd39..0000000 --- a/src/linux/scripts/setlocalversion +++ /dev/null @@ -1,174 +0,0 @@ -#!/bin/sh -# -# This scripts adds local version information from the version -# control systems git, mercurial (hg) and subversion (svn). -# -# If something goes wrong, send a mail the kernel build mailinglist -# (see MAINTAINERS) and CC Nico Schottelius -# . -# -# - -usage() { - echo "Usage: $0 [--save-scmversion] [srctree]" >&2 - exit 1 -} - -scm_only=false -srctree=. -if test "$1" = "--save-scmversion"; then - scm_only=true - shift -fi -if test $# -gt 0; then - srctree=$1 - shift -fi -if test $# -gt 0 -o ! -d "$srctree"; then - usage -fi - -scm_version() -{ - local short - short=false - - cd "$srctree" - if test -e .scmversion; then - cat .scmversion - return - fi - if test "$1" = "--short"; then - short=true - fi - - # Check for git and a git repo. - if test -z "$(git rev-parse --show-cdup 2>/dev/null)" && - head=`git rev-parse --verify --short HEAD 2>/dev/null`; then - - # If we are at a tagged commit (like "v2.6.30-rc6"), we ignore - # it, because this version is defined in the top level Makefile. - if [ -z "`git describe --exact-match 2>/dev/null`" ]; then - - # If only the short version is requested, don't bother - # running further git commands - if $short; then - echo "+" - return - fi - # If we are past a tagged commit (like - # "v2.6.30-rc5-302-g72357d5"), we pretty print it. - if atag="`git describe 2>/dev/null`"; then - echo "$atag" | awk -F- '{printf("-%05d-%s", $(NF-1),$(NF))}' - - # If we don't have a tag at all we print -g{commitish}. - else - printf '%s%s' -g $head - fi - fi - - # Is this git on svn? - if git config --get svn-remote.svn.url >/dev/null; then - printf -- '-svn%s' "`git svn find-rev $head`" - fi - - # Check for uncommitted changes - if git diff-index --name-only HEAD | grep -qv "^scripts/package"; then - printf '%s' -dirty - fi - - # All done with git - return - fi - - # Check for mercurial and a mercurial repo. - if test -d .hg && hgid=`hg id 2>/dev/null`; then - # Do we have an tagged version? If so, latesttagdistance == 1 - if [ "`hg log -r . --template '{latesttagdistance}'`" == "1" ]; then - id=`hg log -r . --template '{latesttag}'` - printf '%s%s' -hg "$id" - else - tag=`printf '%s' "$hgid" | cut -d' ' -f2` - if [ -z "$tag" -o "$tag" = tip ]; then - id=`printf '%s' "$hgid" | sed 's/[+ ].*//'` - printf '%s%s' -hg "$id" - fi - fi - - # Are there uncommitted changes? - # These are represented by + after the changeset id. - case "$hgid" in - *+|*+\ *) printf '%s' -dirty ;; - esac - - # All done with mercurial - return - fi - - # Check for svn and a svn repo. - if rev=`LANG= LC_ALL= LC_MESSAGES=C svn info 2>/dev/null | grep '^Last Changed Rev'`; then - rev=`echo $rev | awk '{print $NF}'` - printf -- '-svn%s' "$rev" - - # All done with svn - return - fi -} - -collect_files() -{ - local file res - - for file; do - case "$file" in - *\~*) - continue - ;; - esac - if test -e "$file"; then - res="$res$(cat "$file")" - fi - done - echo "$res" -} - -if $scm_only; then - if test ! -e .scmversion; then - res=$(scm_version) - echo "$res" >.scmversion - fi - exit -fi - -if test -e include/config/auto.conf; then - . include/config/auto.conf -else - echo "Error: kernelrelease not valid - run 'make prepare' to update it" >&2 - exit 1 -fi - -# localversion* files in the build and source directory -res="$(collect_files localversion*)" -if test ! "$srctree" -ef .; then - res="$res$(collect_files "$srctree"/localversion*)" -fi - -# CONFIG_LOCALVERSION and LOCALVERSION (if set) -res="${res}${CONFIG_LOCALVERSION}${LOCALVERSION}" - -# scm version string if not at a tagged commit -if test "$CONFIG_LOCALVERSION_AUTO" = "y"; then - # full scm version string - res="$res$(scm_version)" -else - # append a plus sign if the repository is not in a clean - # annotated or signed tagged state (as git describe only - # looks at signed or annotated tags - git tag -a/-s) and - # LOCALVERSION= is not specified - if test "${LOCALVERSION+set}" != "set"; then - scm=$(scm_version --short) - res="$res${scm:++}" - fi -fi - -echo "$res" diff --git a/src/linux/scripts/unifdef.c b/src/linux/scripts/unifdef.c deleted file mode 100644 index 7493c0e..0000000 --- a/src/linux/scripts/unifdef.c +++ /dev/null @@ -1,1225 +0,0 @@ -/* - * Copyright (c) 2002 - 2011 Tony Finch - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -/* - * unifdef - remove ifdef'ed lines - * - * This code was derived from software contributed to Berkeley by Dave Yost. - * It was rewritten to support ANSI C by Tony Finch. The original version - * of unifdef carried the 4-clause BSD copyright licence. None of its code - * remains in this version (though some of the names remain) so it now - * carries a more liberal licence. - * - * Wishlist: - * provide an option which will append the name of the - * appropriate symbol after #else's and #endif's - * provide an option which will check symbols after - * #else's and #endif's to see that they match their - * corresponding #ifdef or #ifndef - * - * These require better buffer handling, which would also make - * it possible to handle all "dodgy" directives correctly. - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -const char copyright[] = - "@(#) $Version: unifdef-2.5 $\n" - "@(#) $Author: Tony Finch (dot@dotat.at) $\n" - "@(#) $URL: http://dotat.at/prog/unifdef $\n" -; - -/* types of input lines: */ -typedef enum { - LT_TRUEI, /* a true #if with ignore flag */ - LT_FALSEI, /* a false #if with ignore flag */ - LT_IF, /* an unknown #if */ - LT_TRUE, /* a true #if */ - LT_FALSE, /* a false #if */ - LT_ELIF, /* an unknown #elif */ - LT_ELTRUE, /* a true #elif */ - LT_ELFALSE, /* a false #elif */ - LT_ELSE, /* #else */ - LT_ENDIF, /* #endif */ - LT_DODGY, /* flag: directive is not on one line */ - LT_DODGY_LAST = LT_DODGY + LT_ENDIF, - LT_PLAIN, /* ordinary line */ - LT_EOF, /* end of file */ - LT_ERROR, /* unevaluable #if */ - LT_COUNT -} Linetype; - -static char const * const linetype_name[] = { - "TRUEI", "FALSEI", "IF", "TRUE", "FALSE", - "ELIF", "ELTRUE", "ELFALSE", "ELSE", "ENDIF", - "DODGY TRUEI", "DODGY FALSEI", - "DODGY IF", "DODGY TRUE", "DODGY FALSE", - "DODGY ELIF", "DODGY ELTRUE", "DODGY ELFALSE", - "DODGY ELSE", "DODGY ENDIF", - "PLAIN", "EOF", "ERROR" -}; - -/* state of #if processing */ -typedef enum { - IS_OUTSIDE, - IS_FALSE_PREFIX, /* false #if followed by false #elifs */ - IS_TRUE_PREFIX, /* first non-false #(el)if is true */ - IS_PASS_MIDDLE, /* first non-false #(el)if is unknown */ - IS_FALSE_MIDDLE, /* a false #elif after a pass state */ - IS_TRUE_MIDDLE, /* a true #elif after a pass state */ - IS_PASS_ELSE, /* an else after a pass state */ - IS_FALSE_ELSE, /* an else after a true state */ - IS_TRUE_ELSE, /* an else after only false states */ - IS_FALSE_TRAILER, /* #elifs after a true are false */ - IS_COUNT -} Ifstate; - -static char const * const ifstate_name[] = { - "OUTSIDE", "FALSE_PREFIX", "TRUE_PREFIX", - "PASS_MIDDLE", "FALSE_MIDDLE", "TRUE_MIDDLE", - "PASS_ELSE", "FALSE_ELSE", "TRUE_ELSE", - "FALSE_TRAILER" -}; - -/* state of comment parser */ -typedef enum { - NO_COMMENT = false, /* outside a comment */ - C_COMMENT, /* in a comment like this one */ - CXX_COMMENT, /* between // and end of line */ - STARTING_COMMENT, /* just after slash-backslash-newline */ - FINISHING_COMMENT, /* star-backslash-newline in a C comment */ - CHAR_LITERAL, /* inside '' */ - STRING_LITERAL /* inside "" */ -} Comment_state; - -static char const * const comment_name[] = { - "NO", "C", "CXX", "STARTING", "FINISHING", "CHAR", "STRING" -}; - -/* state of preprocessor line parser */ -typedef enum { - LS_START, /* only space and comments on this line */ - LS_HASH, /* only space, comments, and a hash */ - LS_DIRTY /* this line can't be a preprocessor line */ -} Line_state; - -static char const * const linestate_name[] = { - "START", "HASH", "DIRTY" -}; - -/* - * Minimum translation limits from ISO/IEC 9899:1999 5.2.4.1 - */ -#define MAXDEPTH 64 /* maximum #if nesting */ -#define MAXLINE 4096 /* maximum length of line */ -#define MAXSYMS 4096 /* maximum number of symbols */ - -/* - * Sometimes when editing a keyword the replacement text is longer, so - * we leave some space at the end of the tline buffer to accommodate this. - */ -#define EDITSLOP 10 - -/* - * For temporary filenames - */ -#define TEMPLATE "unifdef.XXXXXX" - -/* - * Globals. - */ - -static bool compblank; /* -B: compress blank lines */ -static bool lnblank; /* -b: blank deleted lines */ -static bool complement; /* -c: do the complement */ -static bool debugging; /* -d: debugging reports */ -static bool iocccok; /* -e: fewer IOCCC errors */ -static bool strictlogic; /* -K: keep ambiguous #ifs */ -static bool killconsts; /* -k: eval constant #ifs */ -static bool lnnum; /* -n: add #line directives */ -static bool symlist; /* -s: output symbol list */ -static bool symdepth; /* -S: output symbol depth */ -static bool text; /* -t: this is a text file */ - -static const char *symname[MAXSYMS]; /* symbol name */ -static const char *value[MAXSYMS]; /* -Dsym=value */ -static bool ignore[MAXSYMS]; /* -iDsym or -iUsym */ -static int nsyms; /* number of symbols */ - -static FILE *input; /* input file pointer */ -static const char *filename; /* input file name */ -static int linenum; /* current line number */ -static FILE *output; /* output file pointer */ -static const char *ofilename; /* output file name */ -static bool overwriting; /* output overwrites input */ -static char tempname[FILENAME_MAX]; /* used when overwriting */ - -static char tline[MAXLINE+EDITSLOP];/* input buffer plus space */ -static char *keyword; /* used for editing #elif's */ - -static const char *newline; /* input file format */ -static const char newline_unix[] = "\n"; -static const char newline_crlf[] = "\r\n"; - -static Comment_state incomment; /* comment parser state */ -static Line_state linestate; /* #if line parser state */ -static Ifstate ifstate[MAXDEPTH]; /* #if processor state */ -static bool ignoring[MAXDEPTH]; /* ignore comments state */ -static int stifline[MAXDEPTH]; /* start of current #if */ -static int depth; /* current #if nesting */ -static int delcount; /* count of deleted lines */ -static unsigned blankcount; /* count of blank lines */ -static unsigned blankmax; /* maximum recent blankcount */ -static bool constexpr; /* constant #if expression */ -static bool zerosyms = true; /* to format symdepth output */ -static bool firstsym; /* ditto */ - -static int exitstat; /* program exit status */ - -static void addsym(bool, bool, char *); -static void closeout(void); -static void debug(const char *, ...); -static void done(void); -static void error(const char *); -static int findsym(const char *); -static void flushline(bool); -static Linetype parseline(void); -static Linetype ifeval(const char **); -static void ignoreoff(void); -static void ignoreon(void); -static void keywordedit(const char *); -static void nest(void); -static void process(void); -static const char *skipargs(const char *); -static const char *skipcomment(const char *); -static const char *skipsym(const char *); -static void state(Ifstate); -static int strlcmp(const char *, const char *, size_t); -static void unnest(void); -static void usage(void); -static void version(void); - -#define endsym(c) (!isalnum((unsigned char)c) && c != '_') - -/* - * The main program. - */ -int -main(int argc, char *argv[]) -{ - int opt; - - while ((opt = getopt(argc, argv, "i:D:U:I:o:bBcdeKklnsStV")) != -1) - switch (opt) { - case 'i': /* treat stuff controlled by these symbols as text */ - /* - * For strict backwards-compatibility the U or D - * should be immediately after the -i but it doesn't - * matter much if we relax that requirement. - */ - opt = *optarg++; - if (opt == 'D') - addsym(true, true, optarg); - else if (opt == 'U') - addsym(true, false, optarg); - else - usage(); - break; - case 'D': /* define a symbol */ - addsym(false, true, optarg); - break; - case 'U': /* undef a symbol */ - addsym(false, false, optarg); - break; - case 'I': /* no-op for compatibility with cpp */ - break; - case 'b': /* blank deleted lines instead of omitting them */ - case 'l': /* backwards compatibility */ - lnblank = true; - break; - case 'B': /* compress blank lines around removed section */ - compblank = true; - break; - case 'c': /* treat -D as -U and vice versa */ - complement = true; - break; - case 'd': - debugging = true; - break; - case 'e': /* fewer errors from dodgy lines */ - iocccok = true; - break; - case 'K': /* keep ambiguous #ifs */ - strictlogic = true; - break; - case 'k': /* process constant #ifs */ - killconsts = true; - break; - case 'n': /* add #line directive after deleted lines */ - lnnum = true; - break; - case 'o': /* output to a file */ - ofilename = optarg; - break; - case 's': /* only output list of symbols that control #ifs */ - symlist = true; - break; - case 'S': /* list symbols with their nesting depth */ - symlist = symdepth = true; - break; - case 't': /* don't parse C comments */ - text = true; - break; - case 'V': /* print version */ - version(); - default: - usage(); - } - argc -= optind; - argv += optind; - if (compblank && lnblank) - errx(2, "-B and -b are mutually exclusive"); - if (argc > 1) { - errx(2, "can only do one file"); - } else if (argc == 1 && strcmp(*argv, "-") != 0) { - filename = *argv; - input = fopen(filename, "rb"); - if (input == NULL) - err(2, "can't open %s", filename); - } else { - filename = "[stdin]"; - input = stdin; - } - if (ofilename == NULL) { - ofilename = "[stdout]"; - output = stdout; - } else { - struct stat ist, ost; - if (stat(ofilename, &ost) == 0 && - fstat(fileno(input), &ist) == 0) - overwriting = (ist.st_dev == ost.st_dev - && ist.st_ino == ost.st_ino); - if (overwriting) { - const char *dirsep; - int ofd; - - dirsep = strrchr(ofilename, '/'); - if (dirsep != NULL) - snprintf(tempname, sizeof(tempname), - "%.*s/" TEMPLATE, - (int)(dirsep - ofilename), ofilename); - else - snprintf(tempname, sizeof(tempname), - TEMPLATE); - ofd = mkstemp(tempname); - if (ofd != -1) - output = fdopen(ofd, "wb+"); - if (output == NULL) - err(2, "can't create temporary file"); - fchmod(ofd, ist.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)); - } else { - output = fopen(ofilename, "wb"); - if (output == NULL) - err(2, "can't open %s", ofilename); - } - } - process(); - abort(); /* bug */ -} - -static void -version(void) -{ - const char *c = copyright; - for (;;) { - while (*++c != '$') - if (*c == '\0') - exit(0); - while (*++c != '$') - putc(*c, stderr); - putc('\n', stderr); - } -} - -static void -usage(void) -{ - fprintf(stderr, "usage: unifdef [-bBcdeKknsStV] [-Ipath]" - " [-Dsym[=val]] [-Usym] [-iDsym[=val]] [-iUsym] ... [file]\n"); - exit(2); -} - -/* - * A state transition function alters the global #if processing state - * in a particular way. The table below is indexed by the current - * processing state and the type of the current line. - * - * Nesting is handled by keeping a stack of states; some transition - * functions increase or decrease the depth. They also maintain the - * ignore state on a stack. In some complicated cases they have to - * alter the preprocessor directive, as follows. - * - * When we have processed a group that starts off with a known-false - * #if/#elif sequence (which has therefore been deleted) followed by a - * #elif that we don't understand and therefore must keep, we edit the - * latter into a #if to keep the nesting correct. We use strncpy() to - * overwrite the 4 byte token "elif" with "if " without a '\0' byte. - * - * When we find a true #elif in a group, the following block will - * always be kept and the rest of the sequence after the next #elif or - * #else will be discarded. We edit the #elif into a #else and the - * following directive to #endif since this has the desired behaviour. - * - * "Dodgy" directives are split across multiple lines, the most common - * example being a multi-line comment hanging off the right of the - * directive. We can handle them correctly only if there is no change - * from printing to dropping (or vice versa) caused by that directive. - * If the directive is the first of a group we have a choice between - * failing with an error, or passing it through unchanged instead of - * evaluating it. The latter is not the default to avoid questions from - * users about unifdef unexpectedly leaving behind preprocessor directives. - */ -typedef void state_fn(void); - -/* report an error */ -static void Eelif (void) { error("Inappropriate #elif"); } -static void Eelse (void) { error("Inappropriate #else"); } -static void Eendif(void) { error("Inappropriate #endif"); } -static void Eeof (void) { error("Premature EOF"); } -static void Eioccc(void) { error("Obfuscated preprocessor control line"); } -/* plain line handling */ -static void print (void) { flushline(true); } -static void drop (void) { flushline(false); } -/* output lacks group's start line */ -static void Strue (void) { drop(); ignoreoff(); state(IS_TRUE_PREFIX); } -static void Sfalse(void) { drop(); ignoreoff(); state(IS_FALSE_PREFIX); } -static void Selse (void) { drop(); state(IS_TRUE_ELSE); } -/* print/pass this block */ -static void Pelif (void) { print(); ignoreoff(); state(IS_PASS_MIDDLE); } -static void Pelse (void) { print(); state(IS_PASS_ELSE); } -static void Pendif(void) { print(); unnest(); } -/* discard this block */ -static void Dfalse(void) { drop(); ignoreoff(); state(IS_FALSE_TRAILER); } -static void Delif (void) { drop(); ignoreoff(); state(IS_FALSE_MIDDLE); } -static void Delse (void) { drop(); state(IS_FALSE_ELSE); } -static void Dendif(void) { drop(); unnest(); } -/* first line of group */ -static void Fdrop (void) { nest(); Dfalse(); } -static void Fpass (void) { nest(); Pelif(); } -static void Ftrue (void) { nest(); Strue(); } -static void Ffalse(void) { nest(); Sfalse(); } -/* variable pedantry for obfuscated lines */ -static void Oiffy (void) { if (!iocccok) Eioccc(); Fpass(); ignoreon(); } -static void Oif (void) { if (!iocccok) Eioccc(); Fpass(); } -static void Oelif (void) { if (!iocccok) Eioccc(); Pelif(); } -/* ignore comments in this block */ -static void Idrop (void) { Fdrop(); ignoreon(); } -static void Itrue (void) { Ftrue(); ignoreon(); } -static void Ifalse(void) { Ffalse(); ignoreon(); } -/* modify this line */ -static void Mpass (void) { strncpy(keyword, "if ", 4); Pelif(); } -static void Mtrue (void) { keywordedit("else"); state(IS_TRUE_MIDDLE); } -static void Melif (void) { keywordedit("endif"); state(IS_FALSE_TRAILER); } -static void Melse (void) { keywordedit("endif"); state(IS_FALSE_ELSE); } - -static state_fn * const trans_table[IS_COUNT][LT_COUNT] = { -/* IS_OUTSIDE */ -{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Eendif, - Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eendif, - print, done, abort }, -/* IS_FALSE_PREFIX */ -{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Strue, Sfalse,Selse, Dendif, - Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Eioccc,Eioccc,Eioccc,Eioccc, - drop, Eeof, abort }, -/* IS_TRUE_PREFIX */ -{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Dfalse,Dfalse,Dfalse,Delse, Dendif, - Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc, - print, Eeof, abort }, -/* IS_PASS_MIDDLE */ -{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Pelif, Mtrue, Delif, Pelse, Pendif, - Oiffy, Oiffy, Fpass, Oif, Oif, Pelif, Oelif, Oelif, Pelse, Pendif, - print, Eeof, abort }, -/* IS_FALSE_MIDDLE */ -{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Pelif, Mtrue, Delif, Pelse, Pendif, - Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc, - drop, Eeof, abort }, -/* IS_TRUE_MIDDLE */ -{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Melif, Melif, Melif, Melse, Pendif, - Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Pendif, - print, Eeof, abort }, -/* IS_PASS_ELSE */ -{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Pendif, - Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Pendif, - print, Eeof, abort }, -/* IS_FALSE_ELSE */ -{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Dendif, - Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Eioccc, - drop, Eeof, abort }, -/* IS_TRUE_ELSE */ -{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Dendif, - Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eioccc, - print, Eeof, abort }, -/* IS_FALSE_TRAILER */ -{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Dendif, - Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Eioccc, - drop, Eeof, abort } -/*TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF - TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF (DODGY) - PLAIN EOF ERROR */ -}; - -/* - * State machine utility functions - */ -static void -ignoreoff(void) -{ - if (depth == 0) - abort(); /* bug */ - ignoring[depth] = ignoring[depth-1]; -} -static void -ignoreon(void) -{ - ignoring[depth] = true; -} -static void -keywordedit(const char *replacement) -{ - snprintf(keyword, tline + sizeof(tline) - keyword, - "%s%s", replacement, newline); - print(); -} -static void -nest(void) -{ - if (depth > MAXDEPTH-1) - abort(); /* bug */ - if (depth == MAXDEPTH-1) - error("Too many levels of nesting"); - depth += 1; - stifline[depth] = linenum; -} -static void -unnest(void) -{ - if (depth == 0) - abort(); /* bug */ - depth -= 1; -} -static void -state(Ifstate is) -{ - ifstate[depth] = is; -} - -/* - * Write a line to the output or not, according to command line options. - */ -static void -flushline(bool keep) -{ - if (symlist) - return; - if (keep ^ complement) { - bool blankline = tline[strspn(tline, " \t\r\n")] == '\0'; - if (blankline && compblank && blankcount != blankmax) { - delcount += 1; - blankcount += 1; - } else { - if (lnnum && delcount > 0) - printf("#line %d%s", linenum, newline); - fputs(tline, output); - delcount = 0; - blankmax = blankcount = blankline ? blankcount + 1 : 0; - } - } else { - if (lnblank) - fputs(newline, output); - exitstat = 1; - delcount += 1; - blankcount = 0; - } - if (debugging) - fflush(output); -} - -/* - * The driver for the state machine. - */ -static void -process(void) -{ - /* When compressing blank lines, act as if the file - is preceded by a large number of blank lines. */ - blankmax = blankcount = 1000; - for (;;) { - Linetype lineval = parseline(); - trans_table[ifstate[depth]][lineval](); - debug("process line %d %s -> %s depth %d", - linenum, linetype_name[lineval], - ifstate_name[ifstate[depth]], depth); - } -} - -/* - * Flush the output and handle errors. - */ -static void -closeout(void) -{ - if (symdepth && !zerosyms) - printf("\n"); - if (fclose(output) == EOF) { - warn("couldn't write to %s", ofilename); - if (overwriting) { - unlink(tempname); - errx(2, "%s unchanged", filename); - } else { - exit(2); - } - } -} - -/* - * Clean up and exit. - */ -static void -done(void) -{ - if (incomment) - error("EOF in comment"); - closeout(); - if (overwriting && rename(tempname, ofilename) == -1) { - warn("couldn't rename temporary file"); - unlink(tempname); - errx(2, "%s unchanged", ofilename); - } - exit(exitstat); -} - -/* - * Parse a line and determine its type. We keep the preprocessor line - * parser state between calls in the global variable linestate, with - * help from skipcomment(). - */ -static Linetype -parseline(void) -{ - const char *cp; - int cursym; - int kwlen; - Linetype retval; - Comment_state wascomment; - - linenum++; - if (fgets(tline, MAXLINE, input) == NULL) - return (LT_EOF); - if (newline == NULL) { - if (strrchr(tline, '\n') == strrchr(tline, '\r') + 1) - newline = newline_crlf; - else - newline = newline_unix; - } - retval = LT_PLAIN; - wascomment = incomment; - cp = skipcomment(tline); - if (linestate == LS_START) { - if (*cp == '#') { - linestate = LS_HASH; - firstsym = true; - cp = skipcomment(cp + 1); - } else if (*cp != '\0') - linestate = LS_DIRTY; - } - if (!incomment && linestate == LS_HASH) { - keyword = tline + (cp - tline); - cp = skipsym(cp); - kwlen = cp - keyword; - /* no way can we deal with a continuation inside a keyword */ - if (strncmp(cp, "\\\r\n", 3) == 0 || - strncmp(cp, "\\\n", 2) == 0) - Eioccc(); - if (strlcmp("ifdef", keyword, kwlen) == 0 || - strlcmp("ifndef", keyword, kwlen) == 0) { - cp = skipcomment(cp); - if ((cursym = findsym(cp)) < 0) - retval = LT_IF; - else { - retval = (keyword[2] == 'n') - ? LT_FALSE : LT_TRUE; - if (value[cursym] == NULL) - retval = (retval == LT_TRUE) - ? LT_FALSE : LT_TRUE; - if (ignore[cursym]) - retval = (retval == LT_TRUE) - ? LT_TRUEI : LT_FALSEI; - } - cp = skipsym(cp); - } else if (strlcmp("if", keyword, kwlen) == 0) - retval = ifeval(&cp); - else if (strlcmp("elif", keyword, kwlen) == 0) - retval = ifeval(&cp) - LT_IF + LT_ELIF; - else if (strlcmp("else", keyword, kwlen) == 0) - retval = LT_ELSE; - else if (strlcmp("endif", keyword, kwlen) == 0) - retval = LT_ENDIF; - else { - linestate = LS_DIRTY; - retval = LT_PLAIN; - } - cp = skipcomment(cp); - if (*cp != '\0') { - linestate = LS_DIRTY; - if (retval == LT_TRUE || retval == LT_FALSE || - retval == LT_TRUEI || retval == LT_FALSEI) - retval = LT_IF; - if (retval == LT_ELTRUE || retval == LT_ELFALSE) - retval = LT_ELIF; - } - if (retval != LT_PLAIN && (wascomment || incomment)) { - retval += LT_DODGY; - if (incomment) - linestate = LS_DIRTY; - } - /* skipcomment normally changes the state, except - if the last line of the file lacks a newline, or - if there is too much whitespace in a directive */ - if (linestate == LS_HASH) { - size_t len = cp - tline; - if (fgets(tline + len, MAXLINE - len, input) == NULL) { - /* append the missing newline */ - strcpy(tline + len, newline); - cp += strlen(newline); - linestate = LS_START; - } else { - linestate = LS_DIRTY; - } - } - } - if (linestate == LS_DIRTY) { - while (*cp != '\0') - cp = skipcomment(cp + 1); - } - debug("parser line %d state %s comment %s line", linenum, - comment_name[incomment], linestate_name[linestate]); - return (retval); -} - -/* - * These are the binary operators that are supported by the expression - * evaluator. - */ -static Linetype op_strict(int *p, int v, Linetype at, Linetype bt) { - if(at == LT_IF || bt == LT_IF) return (LT_IF); - return (*p = v, v ? LT_TRUE : LT_FALSE); -} -static Linetype op_lt(int *p, Linetype at, int a, Linetype bt, int b) { - return op_strict(p, a < b, at, bt); -} -static Linetype op_gt(int *p, Linetype at, int a, Linetype bt, int b) { - return op_strict(p, a > b, at, bt); -} -static Linetype op_le(int *p, Linetype at, int a, Linetype bt, int b) { - return op_strict(p, a <= b, at, bt); -} -static Linetype op_ge(int *p, Linetype at, int a, Linetype bt, int b) { - return op_strict(p, a >= b, at, bt); -} -static Linetype op_eq(int *p, Linetype at, int a, Linetype bt, int b) { - return op_strict(p, a == b, at, bt); -} -static Linetype op_ne(int *p, Linetype at, int a, Linetype bt, int b) { - return op_strict(p, a != b, at, bt); -} -static Linetype op_or(int *p, Linetype at, int a, Linetype bt, int b) { - if (!strictlogic && (at == LT_TRUE || bt == LT_TRUE)) - return (*p = 1, LT_TRUE); - return op_strict(p, a || b, at, bt); -} -static Linetype op_and(int *p, Linetype at, int a, Linetype bt, int b) { - if (!strictlogic && (at == LT_FALSE || bt == LT_FALSE)) - return (*p = 0, LT_FALSE); - return op_strict(p, a && b, at, bt); -} - -/* - * An evaluation function takes three arguments, as follows: (1) a pointer to - * an element of the precedence table which lists the operators at the current - * level of precedence; (2) a pointer to an integer which will receive the - * value of the expression; and (3) a pointer to a char* that points to the - * expression to be evaluated and that is updated to the end of the expression - * when evaluation is complete. The function returns LT_FALSE if the value of - * the expression is zero, LT_TRUE if it is non-zero, LT_IF if the expression - * depends on an unknown symbol, or LT_ERROR if there is a parse failure. - */ -struct ops; - -typedef Linetype eval_fn(const struct ops *, int *, const char **); - -static eval_fn eval_table, eval_unary; - -/* - * The precedence table. Expressions involving binary operators are evaluated - * in a table-driven way by eval_table. When it evaluates a subexpression it - * calls the inner function with its first argument pointing to the next - * element of the table. Innermost expressions have special non-table-driven - * handling. - */ -static const struct ops { - eval_fn *inner; - struct op { - const char *str; - Linetype (*fn)(int *, Linetype, int, Linetype, int); - } op[5]; -} eval_ops[] = { - { eval_table, { { "||", op_or } } }, - { eval_table, { { "&&", op_and } } }, - { eval_table, { { "==", op_eq }, - { "!=", op_ne } } }, - { eval_unary, { { "<=", op_le }, - { ">=", op_ge }, - { "<", op_lt }, - { ">", op_gt } } } -}; - -/* - * Function for evaluating the innermost parts of expressions, - * viz. !expr (expr) number defined(symbol) symbol - * We reset the constexpr flag in the last two cases. - */ -static Linetype -eval_unary(const struct ops *ops, int *valp, const char **cpp) -{ - const char *cp; - char *ep; - int sym; - bool defparen; - Linetype lt; - - cp = skipcomment(*cpp); - if (*cp == '!') { - debug("eval%d !", ops - eval_ops); - cp++; - lt = eval_unary(ops, valp, &cp); - if (lt == LT_ERROR) - return (LT_ERROR); - if (lt != LT_IF) { - *valp = !*valp; - lt = *valp ? LT_TRUE : LT_FALSE; - } - } else if (*cp == '(') { - cp++; - debug("eval%d (", ops - eval_ops); - lt = eval_table(eval_ops, valp, &cp); - if (lt == LT_ERROR) - return (LT_ERROR); - cp = skipcomment(cp); - if (*cp++ != ')') - return (LT_ERROR); - } else if (isdigit((unsigned char)*cp)) { - debug("eval%d number", ops - eval_ops); - *valp = strtol(cp, &ep, 0); - if (ep == cp) - return (LT_ERROR); - lt = *valp ? LT_TRUE : LT_FALSE; - cp = skipsym(cp); - } else if (strncmp(cp, "defined", 7) == 0 && endsym(cp[7])) { - cp = skipcomment(cp+7); - debug("eval%d defined", ops - eval_ops); - if (*cp == '(') { - cp = skipcomment(cp+1); - defparen = true; - } else { - defparen = false; - } - sym = findsym(cp); - if (sym < 0) { - lt = LT_IF; - } else { - *valp = (value[sym] != NULL); - lt = *valp ? LT_TRUE : LT_FALSE; - } - cp = skipsym(cp); - cp = skipcomment(cp); - if (defparen && *cp++ != ')') - return (LT_ERROR); - constexpr = false; - } else if (!endsym(*cp)) { - debug("eval%d symbol", ops - eval_ops); - sym = findsym(cp); - cp = skipsym(cp); - if (sym < 0) { - lt = LT_IF; - cp = skipargs(cp); - } else if (value[sym] == NULL) { - *valp = 0; - lt = LT_FALSE; - } else { - *valp = strtol(value[sym], &ep, 0); - if (*ep != '\0' || ep == value[sym]) - return (LT_ERROR); - lt = *valp ? LT_TRUE : LT_FALSE; - cp = skipargs(cp); - } - constexpr = false; - } else { - debug("eval%d bad expr", ops - eval_ops); - return (LT_ERROR); - } - - *cpp = cp; - debug("eval%d = %d", ops - eval_ops, *valp); - return (lt); -} - -/* - * Table-driven evaluation of binary operators. - */ -static Linetype -eval_table(const struct ops *ops, int *valp, const char **cpp) -{ - const struct op *op; - const char *cp; - int val; - Linetype lt, rt; - - debug("eval%d", ops - eval_ops); - cp = *cpp; - lt = ops->inner(ops+1, valp, &cp); - if (lt == LT_ERROR) - return (LT_ERROR); - for (;;) { - cp = skipcomment(cp); - for (op = ops->op; op->str != NULL; op++) - if (strncmp(cp, op->str, strlen(op->str)) == 0) - break; - if (op->str == NULL) - break; - cp += strlen(op->str); - debug("eval%d %s", ops - eval_ops, op->str); - rt = ops->inner(ops+1, &val, &cp); - if (rt == LT_ERROR) - return (LT_ERROR); - lt = op->fn(valp, lt, *valp, rt, val); - } - - *cpp = cp; - debug("eval%d = %d", ops - eval_ops, *valp); - debug("eval%d lt = %s", ops - eval_ops, linetype_name[lt]); - return (lt); -} - -/* - * Evaluate the expression on a #if or #elif line. If we can work out - * the result we return LT_TRUE or LT_FALSE accordingly, otherwise we - * return just a generic LT_IF. - */ -static Linetype -ifeval(const char **cpp) -{ - int ret; - int val = 0; - - debug("eval %s", *cpp); - constexpr = killconsts ? false : true; - ret = eval_table(eval_ops, &val, cpp); - debug("eval = %d", val); - return (constexpr ? LT_IF : ret == LT_ERROR ? LT_IF : ret); -} - -/* - * Skip over comments, strings, and character literals and stop at the - * next character position that is not whitespace. Between calls we keep - * the comment state in the global variable incomment, and we also adjust - * the global variable linestate when we see a newline. - * XXX: doesn't cope with the buffer splitting inside a state transition. - */ -static const char * -skipcomment(const char *cp) -{ - if (text || ignoring[depth]) { - for (; isspace((unsigned char)*cp); cp++) - if (*cp == '\n') - linestate = LS_START; - return (cp); - } - while (*cp != '\0') - /* don't reset to LS_START after a line continuation */ - if (strncmp(cp, "\\\r\n", 3) == 0) - cp += 3; - else if (strncmp(cp, "\\\n", 2) == 0) - cp += 2; - else switch (incomment) { - case NO_COMMENT: - if (strncmp(cp, "/\\\r\n", 4) == 0) { - incomment = STARTING_COMMENT; - cp += 4; - } else if (strncmp(cp, "/\\\n", 3) == 0) { - incomment = STARTING_COMMENT; - cp += 3; - } else if (strncmp(cp, "/*", 2) == 0) { - incomment = C_COMMENT; - cp += 2; - } else if (strncmp(cp, "//", 2) == 0) { - incomment = CXX_COMMENT; - cp += 2; - } else if (strncmp(cp, "\'", 1) == 0) { - incomment = CHAR_LITERAL; - linestate = LS_DIRTY; - cp += 1; - } else if (strncmp(cp, "\"", 1) == 0) { - incomment = STRING_LITERAL; - linestate = LS_DIRTY; - cp += 1; - } else if (strncmp(cp, "\n", 1) == 0) { - linestate = LS_START; - cp += 1; - } else if (strchr(" \r\t", *cp) != NULL) { - cp += 1; - } else - return (cp); - continue; - case CXX_COMMENT: - if (strncmp(cp, "\n", 1) == 0) { - incomment = NO_COMMENT; - linestate = LS_START; - } - cp += 1; - continue; - case CHAR_LITERAL: - case STRING_LITERAL: - if ((incomment == CHAR_LITERAL && cp[0] == '\'') || - (incomment == STRING_LITERAL && cp[0] == '\"')) { - incomment = NO_COMMENT; - cp += 1; - } else if (cp[0] == '\\') { - if (cp[1] == '\0') - cp += 1; - else - cp += 2; - } else if (strncmp(cp, "\n", 1) == 0) { - if (incomment == CHAR_LITERAL) - error("unterminated char literal"); - else - error("unterminated string literal"); - } else - cp += 1; - continue; - case C_COMMENT: - if (strncmp(cp, "*\\\r\n", 4) == 0) { - incomment = FINISHING_COMMENT; - cp += 4; - } else if (strncmp(cp, "*\\\n", 3) == 0) { - incomment = FINISHING_COMMENT; - cp += 3; - } else if (strncmp(cp, "*/", 2) == 0) { - incomment = NO_COMMENT; - cp += 2; - } else - cp += 1; - continue; - case STARTING_COMMENT: - if (*cp == '*') { - incomment = C_COMMENT; - cp += 1; - } else if (*cp == '/') { - incomment = CXX_COMMENT; - cp += 1; - } else { - incomment = NO_COMMENT; - linestate = LS_DIRTY; - } - continue; - case FINISHING_COMMENT: - if (*cp == '/') { - incomment = NO_COMMENT; - cp += 1; - } else - incomment = C_COMMENT; - continue; - default: - abort(); /* bug */ - } - return (cp); -} - -/* - * Skip macro arguments. - */ -static const char * -skipargs(const char *cp) -{ - const char *ocp = cp; - int level = 0; - cp = skipcomment(cp); - if (*cp != '(') - return (cp); - do { - if (*cp == '(') - level++; - if (*cp == ')') - level--; - cp = skipcomment(cp+1); - } while (level != 0 && *cp != '\0'); - if (level == 0) - return (cp); - else - /* Rewind and re-detect the syntax error later. */ - return (ocp); -} - -/* - * Skip over an identifier. - */ -static const char * -skipsym(const char *cp) -{ - while (!endsym(*cp)) - ++cp; - return (cp); -} - -/* - * Look for the symbol in the symbol table. If it is found, we return - * the symbol table index, else we return -1. - */ -static int -findsym(const char *str) -{ - const char *cp; - int symind; - - cp = skipsym(str); - if (cp == str) - return (-1); - if (symlist) { - if (symdepth && firstsym) - printf("%s%3d", zerosyms ? "" : "\n", depth); - firstsym = zerosyms = false; - printf("%s%.*s%s", - symdepth ? " " : "", - (int)(cp-str), str, - symdepth ? "" : "\n"); - /* we don't care about the value of the symbol */ - return (0); - } - for (symind = 0; symind < nsyms; ++symind) { - if (strlcmp(symname[symind], str, cp-str) == 0) { - debug("findsym %s %s", symname[symind], - value[symind] ? value[symind] : ""); - return (symind); - } - } - return (-1); -} - -/* - * Add a symbol to the symbol table. - */ -static void -addsym(bool ignorethis, bool definethis, char *sym) -{ - int symind; - char *val; - - symind = findsym(sym); - if (symind < 0) { - if (nsyms >= MAXSYMS) - errx(2, "too many symbols"); - symind = nsyms++; - } - symname[symind] = sym; - ignore[symind] = ignorethis; - val = sym + (skipsym(sym) - sym); - if (definethis) { - if (*val == '=') { - value[symind] = val+1; - *val = '\0'; - } else if (*val == '\0') - value[symind] = "1"; - else - usage(); - } else { - if (*val != '\0') - usage(); - value[symind] = NULL; - } - debug("addsym %s=%s", symname[symind], - value[symind] ? value[symind] : "undef"); -} - -/* - * Compare s with n characters of t. - * The same as strncmp() except that it checks that s[n] == '\0'. - */ -static int -strlcmp(const char *s, const char *t, size_t n) -{ - while (n-- && *t != '\0') - if (*s != *t) - return ((unsigned char)*s - (unsigned char)*t); - else - ++s, ++t; - return ((unsigned char)*s); -} - -/* - * Diagnostics. - */ -static void -debug(const char *msg, ...) -{ - va_list ap; - - if (debugging) { - va_start(ap, msg); - vwarnx(msg, ap); - va_end(ap); - } -} - -static void -error(const char *msg) -{ - if (depth == 0) - warnx("%s: %d: %s", filename, linenum, msg); - else - warnx("%s: %d: %s (#if line %d depth %d)", - filename, linenum, msg, stifline[depth], depth); - closeout(); - errx(2, "output may be truncated"); -} diff --git a/src/linux/security/Kconfig b/src/linux/security/Kconfig deleted file mode 100644 index 118f454..0000000 --- a/src/linux/security/Kconfig +++ /dev/null @@ -1,208 +0,0 @@ -# -# Security configuration -# - -menu "Security options" - -source security/keys/Kconfig - -config SECURITY_DMESG_RESTRICT - bool "Restrict unprivileged access to the kernel syslog" - default n - help - This enforces restrictions on unprivileged users reading the kernel - syslog via dmesg(8). - - If this option is not selected, no restrictions will be enforced - unless the dmesg_restrict sysctl is explicitly set to (1). - - If you are unsure how to answer this question, answer N. - -config SECURITY - bool "Enable different security models" - depends on SYSFS - depends on MULTIUSER - help - This allows you to choose different security modules to be - configured into your kernel. - - If this option is not selected, the default Linux security - model will be used. - - If you are unsure how to answer this question, answer N. - -config SECURITYFS - bool "Enable the securityfs filesystem" - help - This will build the securityfs filesystem. It is currently used by - the TPM bios character driver and IMA, an integrity provider. It is - not used by SELinux or SMACK. - - If you are unsure how to answer this question, answer N. - -config SECURITY_NETWORK - bool "Socket and Networking Security Hooks" - depends on SECURITY - help - This enables the socket and networking security hooks. - If enabled, a security module can use these hooks to - implement socket and networking access controls. - If you are unsure how to answer this question, answer N. - -config SECURITY_NETWORK_XFRM - bool "XFRM (IPSec) Networking Security Hooks" - depends on XFRM && SECURITY_NETWORK - help - This enables the XFRM (IPSec) networking security hooks. - If enabled, a security module can use these hooks to - implement per-packet access controls based on labels - derived from IPSec policy. Non-IPSec communications are - designated as unlabelled, and only sockets authorized - to communicate unlabelled data can send without using - IPSec. - If you are unsure how to answer this question, answer N. - -config SECURITY_PATH - bool "Security hooks for pathname based access control" - depends on SECURITY - help - This enables the security hooks for pathname based access control. - If enabled, a security module can use these hooks to - implement pathname based access controls. - If you are unsure how to answer this question, answer N. - -config INTEL_TXT - bool "Enable Intel(R) Trusted Execution Technology (Intel(R) TXT)" - depends on HAVE_INTEL_TXT - help - This option enables support for booting the kernel with the - Trusted Boot (tboot) module. This will utilize - Intel(R) Trusted Execution Technology to perform a measured launch - of the kernel. If the system does not support Intel(R) TXT, this - will have no effect. - - Intel TXT will provide higher assurance of system configuration and - initial state as well as data reset protection. This is used to - create a robust initial kernel measurement and verification, which - helps to ensure that kernel security mechanisms are functioning - correctly. This level of protection requires a root of trust outside - of the kernel itself. - - Intel TXT also helps solve real end user concerns about having - confidence that their hardware is running the VMM or kernel that - it was configured with, especially since they may be responsible for - providing such assurances to VMs and services running on it. - - See for more information - about Intel(R) TXT. - See for more information about tboot. - See Documentation/intel_txt.txt for a description of how to enable - Intel TXT support in a kernel boot. - - If you are unsure as to whether this is required, answer N. - -config LSM_MMAP_MIN_ADDR - int "Low address space for LSM to protect from user allocation" - depends on SECURITY && SECURITY_SELINUX - default 32768 if ARM || (ARM64 && COMPAT) - default 65536 - help - This is the portion of low virtual memory which should be protected - from userspace allocation. Keeping a user from writing to low pages - can help reduce the impact of kernel NULL pointer bugs. - - For most ia64, ppc64 and x86 users with lots of address space - a value of 65536 is reasonable and should cause no problems. - On arm and other archs it should not be higher than 32768. - Programs which use vm86 functionality or have some need to map - this low address space will need the permission specific to the - systems running LSM. - -config HAVE_HARDENED_USERCOPY_ALLOCATOR - bool - help - The heap allocator implements __check_heap_object() for - validating memory ranges against heap object sizes in - support of CONFIG_HARDENED_USERCOPY. - -config HAVE_ARCH_HARDENED_USERCOPY - bool - help - The architecture supports CONFIG_HARDENED_USERCOPY by - calling check_object_size() just before performing the - userspace copies in the low level implementation of - copy_to_user() and copy_from_user(). - -config HARDENED_USERCOPY - bool "Harden memory copies between kernel and userspace" - depends on HAVE_ARCH_HARDENED_USERCOPY - depends on HAVE_HARDENED_USERCOPY_ALLOCATOR - select BUG - help - This option checks for obviously wrong memory regions when - copying memory to/from the kernel (via copy_to_user() and - copy_from_user() functions) by rejecting memory ranges that - are larger than the specified heap object, span multiple - separately allocates pages, are not on the process stack, - or are part of the kernel text. This kills entire classes - of heap overflow exploits and similar kernel memory exposures. - -config HARDENED_USERCOPY_PAGESPAN - bool "Refuse to copy allocations that span multiple pages" - depends on HARDENED_USERCOPY - depends on EXPERT - help - When a multi-page allocation is done without __GFP_COMP, - hardened usercopy will reject attempts to copy it. There are, - however, several cases of this in the kernel that have not all - been removed. This config is intended to be used only while - trying to find such users. - -source security/selinux/Kconfig -source security/smack/Kconfig -source security/tomoyo/Kconfig -source security/apparmor/Kconfig -source security/loadpin/Kconfig -source security/yama/Kconfig - -source security/integrity/Kconfig - -choice - prompt "Default security module" - default DEFAULT_SECURITY_SELINUX if SECURITY_SELINUX - default DEFAULT_SECURITY_SMACK if SECURITY_SMACK - default DEFAULT_SECURITY_TOMOYO if SECURITY_TOMOYO - default DEFAULT_SECURITY_APPARMOR if SECURITY_APPARMOR - default DEFAULT_SECURITY_DAC - - help - Select the security module that will be used by default if the - kernel parameter security= is not specified. - - config DEFAULT_SECURITY_SELINUX - bool "SELinux" if SECURITY_SELINUX=y - - config DEFAULT_SECURITY_SMACK - bool "Simplified Mandatory Access Control" if SECURITY_SMACK=y - - config DEFAULT_SECURITY_TOMOYO - bool "TOMOYO" if SECURITY_TOMOYO=y - - config DEFAULT_SECURITY_APPARMOR - bool "AppArmor" if SECURITY_APPARMOR=y - - config DEFAULT_SECURITY_DAC - bool "Unix Discretionary Access Controls" - -endchoice - -config DEFAULT_SECURITY - string - default "selinux" if DEFAULT_SECURITY_SELINUX - default "smack" if DEFAULT_SECURITY_SMACK - default "tomoyo" if DEFAULT_SECURITY_TOMOYO - default "apparmor" if DEFAULT_SECURITY_APPARMOR - default "" if DEFAULT_SECURITY_DAC - -endmenu - diff --git a/src/linux/security/Makefile b/src/linux/security/Makefile deleted file mode 100644 index f2d71cd..0000000 --- a/src/linux/security/Makefile +++ /dev/null @@ -1,31 +0,0 @@ -# -# Makefile for the kernel security code -# - -obj-$(CONFIG_KEYS) += keys/ -subdir-$(CONFIG_SECURITY_SELINUX) += selinux -subdir-$(CONFIG_SECURITY_SMACK) += smack -subdir-$(CONFIG_SECURITY_TOMOYO) += tomoyo -subdir-$(CONFIG_SECURITY_APPARMOR) += apparmor -subdir-$(CONFIG_SECURITY_YAMA) += yama -subdir-$(CONFIG_SECURITY_LOADPIN) += loadpin - -# always enable default capabilities -obj-y += commoncap.o -obj-$(CONFIG_MMU) += min_addr.o - -# Object file lists -obj-$(CONFIG_SECURITY) += security.o -obj-$(CONFIG_SECURITYFS) += inode.o -obj-$(CONFIG_SECURITY_SELINUX) += selinux/ -obj-$(CONFIG_SECURITY_SMACK) += smack/ -obj-$(CONFIG_AUDIT) += lsm_audit.o -obj-$(CONFIG_SECURITY_TOMOYO) += tomoyo/ -obj-$(CONFIG_SECURITY_APPARMOR) += apparmor/ -obj-$(CONFIG_SECURITY_YAMA) += yama/ -obj-$(CONFIG_SECURITY_LOADPIN) += loadpin/ -obj-$(CONFIG_CGROUP_DEVICE) += device_cgroup.o - -# Object integrity file lists -subdir-$(CONFIG_INTEGRITY) += integrity -obj-$(CONFIG_INTEGRITY) += integrity/ diff --git a/src/linux/security/apparmor/.gitignore b/src/linux/security/apparmor/.gitignore deleted file mode 100644 index 9cdec70..0000000 --- a/src/linux/security/apparmor/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# -# Generated include files -# -capability_names.h -rlim_names.h diff --git a/src/linux/security/apparmor/Kconfig b/src/linux/security/apparmor/Kconfig deleted file mode 100644 index be5e941..0000000 --- a/src/linux/security/apparmor/Kconfig +++ /dev/null @@ -1,56 +0,0 @@ -config SECURITY_APPARMOR - bool "AppArmor support" - depends on SECURITY && NET - select AUDIT - select SECURITY_PATH - select SECURITYFS - select SECURITY_NETWORK - default n - help - This enables the AppArmor security module. - Required userspace tools (if they are not included in your - distribution) and further information may be found at - http://apparmor.wiki.kernel.org - - If you are unsure how to answer this question, answer N. - -config SECURITY_APPARMOR_BOOTPARAM_VALUE - int "AppArmor boot parameter default value" - depends on SECURITY_APPARMOR - range 0 1 - default 1 - help - This option sets the default value for the kernel parameter - 'apparmor', which allows AppArmor to be enabled or disabled - at boot. If this option is set to 0 (zero), the AppArmor - kernel parameter will default to 0, disabling AppArmor at - boot. If this option is set to 1 (one), the AppArmor - kernel parameter will default to 1, enabling AppArmor at - boot. - - If you are unsure how to answer this question, answer 1. - -config SECURITY_APPARMOR_HASH - bool "Enable introspection of sha1 hashes for loaded profiles" - depends on SECURITY_APPARMOR - select CRYPTO - select CRYPTO_SHA1 - default y - - help - This option selects whether introspection of loaded policy - is available to userspace via the apparmor filesystem. - -config SECURITY_APPARMOR_HASH_DEFAULT - bool "Enable policy hash introspection by default" - depends on SECURITY_APPARMOR_HASH - default y - - help - This option selects whether sha1 hashing of loaded policy - is enabled by default. The generation of sha1 hashes for - loaded policy provide system administrators a quick way - to verify that policy in the kernel matches what is expected, - however it can slow down policy load on some devices. In - these cases policy hashing can be disabled by default and - enabled only if needed. diff --git a/src/linux/security/commoncap.c b/src/linux/security/commoncap.c deleted file mode 100644 index 8df676f..0000000 --- a/src/linux/security/commoncap.c +++ /dev/null @@ -1,1099 +0,0 @@ -/* Common capabilities, needed by capability.o. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* - * If a non-root user executes a setuid-root binary in - * !secure(SECURE_NOROOT) mode, then we raise capabilities. - * However if fE is also set, then the intent is for only - * the file capabilities to be applied, and the setuid-root - * bit is left on either to change the uid (plausible) or - * to get full privilege on a kernel without file capabilities - * support. So in that case we do not raise capabilities. - * - * Warn if that happens, once per boot. - */ -static void warn_setuid_and_fcaps_mixed(const char *fname) -{ - static int warned; - if (!warned) { - printk(KERN_INFO "warning: `%s' has both setuid-root and" - " effective capabilities. Therefore not raising all" - " capabilities.\n", fname); - warned = 1; - } -} - -/** - * cap_capable - Determine whether a task has a particular effective capability - * @cred: The credentials to use - * @ns: The user namespace in which we need the capability - * @cap: The capability to check for - * @audit: Whether to write an audit message or not - * - * Determine whether the nominated task has the specified capability amongst - * its effective set, returning 0 if it does, -ve if it does not. - * - * NOTE WELL: cap_has_capability() cannot be used like the kernel's capable() - * and has_capability() functions. That is, it has the reverse semantics: - * cap_has_capability() returns 0 when a task has a capability, but the - * kernel's capable() and has_capability() returns 1 for this case. - */ -int cap_capable(const struct cred *cred, struct user_namespace *targ_ns, - int cap, int audit) -{ - struct user_namespace *ns = targ_ns; - - /* See if cred has the capability in the target user namespace - * by examining the target user namespace and all of the target - * user namespace's parents. - */ - for (;;) { - /* Do we have the necessary capabilities? */ - if (ns == cred->user_ns) - return cap_raised(cred->cap_effective, cap) ? 0 : -EPERM; - - /* Have we tried all of the parent namespaces? */ - if (ns == &init_user_ns) - return -EPERM; - - /* - * The owner of the user namespace in the parent of the - * user namespace has all caps. - */ - if ((ns->parent == cred->user_ns) && uid_eq(ns->owner, cred->euid)) - return 0; - - /* - * If you have a capability in a parent user ns, then you have - * it over all children user namespaces as well. - */ - ns = ns->parent; - } - - /* We never get here */ -} - -/** - * cap_settime - Determine whether the current process may set the system clock - * @ts: The time to set - * @tz: The timezone to set - * - * Determine whether the current process may set the system clock and timezone - * information, returning 0 if permission granted, -ve if denied. - */ -int cap_settime(const struct timespec64 *ts, const struct timezone *tz) -{ - if (!capable(CAP_SYS_TIME)) - return -EPERM; - return 0; -} - -/** - * cap_ptrace_access_check - Determine whether the current process may access - * another - * @child: The process to be accessed - * @mode: The mode of attachment. - * - * If we are in the same or an ancestor user_ns and have all the target - * task's capabilities, then ptrace access is allowed. - * If we have the ptrace capability to the target user_ns, then ptrace - * access is allowed. - * Else denied. - * - * Determine whether a process may access another, returning 0 if permission - * granted, -ve if denied. - */ -int cap_ptrace_access_check(struct task_struct *child, unsigned int mode) -{ - int ret = 0; - const struct cred *cred, *child_cred; - const kernel_cap_t *caller_caps; - - rcu_read_lock(); - cred = current_cred(); - child_cred = __task_cred(child); - if (mode & PTRACE_MODE_FSCREDS) - caller_caps = &cred->cap_effective; - else - caller_caps = &cred->cap_permitted; - if (cred->user_ns == child_cred->user_ns && - cap_issubset(child_cred->cap_permitted, *caller_caps)) - goto out; - if (ns_capable(child_cred->user_ns, CAP_SYS_PTRACE)) - goto out; - ret = -EPERM; -out: - rcu_read_unlock(); - return ret; -} - -/** - * cap_ptrace_traceme - Determine whether another process may trace the current - * @parent: The task proposed to be the tracer - * - * If parent is in the same or an ancestor user_ns and has all current's - * capabilities, then ptrace access is allowed. - * If parent has the ptrace capability to current's user_ns, then ptrace - * access is allowed. - * Else denied. - * - * Determine whether the nominated task is permitted to trace the current - * process, returning 0 if permission is granted, -ve if denied. - */ -int cap_ptrace_traceme(struct task_struct *parent) -{ - int ret = 0; - const struct cred *cred, *child_cred; - - rcu_read_lock(); - cred = __task_cred(parent); - child_cred = current_cred(); - if (cred->user_ns == child_cred->user_ns && - cap_issubset(child_cred->cap_permitted, cred->cap_permitted)) - goto out; - if (has_ns_capability(parent, child_cred->user_ns, CAP_SYS_PTRACE)) - goto out; - ret = -EPERM; -out: - rcu_read_unlock(); - return ret; -} - -/** - * cap_capget - Retrieve a task's capability sets - * @target: The task from which to retrieve the capability sets - * @effective: The place to record the effective set - * @inheritable: The place to record the inheritable set - * @permitted: The place to record the permitted set - * - * This function retrieves the capabilities of the nominated task and returns - * them to the caller. - */ -int cap_capget(struct task_struct *target, kernel_cap_t *effective, - kernel_cap_t *inheritable, kernel_cap_t *permitted) -{ - const struct cred *cred; - - /* Derived from kernel/capability.c:sys_capget. */ - rcu_read_lock(); - cred = __task_cred(target); - *effective = cred->cap_effective; - *inheritable = cred->cap_inheritable; - *permitted = cred->cap_permitted; - rcu_read_unlock(); - return 0; -} - -/* - * Determine whether the inheritable capabilities are limited to the old - * permitted set. Returns 1 if they are limited, 0 if they are not. - */ -static inline int cap_inh_is_capped(void) -{ - - /* they are so limited unless the current task has the CAP_SETPCAP - * capability - */ - if (cap_capable(current_cred(), current_cred()->user_ns, - CAP_SETPCAP, SECURITY_CAP_AUDIT) == 0) - return 0; - return 1; -} - -/** - * cap_capset - Validate and apply proposed changes to current's capabilities - * @new: The proposed new credentials; alterations should be made here - * @old: The current task's current credentials - * @effective: A pointer to the proposed new effective capabilities set - * @inheritable: A pointer to the proposed new inheritable capabilities set - * @permitted: A pointer to the proposed new permitted capabilities set - * - * This function validates and applies a proposed mass change to the current - * process's capability sets. The changes are made to the proposed new - * credentials, and assuming no error, will be committed by the caller of LSM. - */ -int cap_capset(struct cred *new, - const struct cred *old, - const kernel_cap_t *effective, - const kernel_cap_t *inheritable, - const kernel_cap_t *permitted) -{ - if (cap_inh_is_capped() && - !cap_issubset(*inheritable, - cap_combine(old->cap_inheritable, - old->cap_permitted))) - /* incapable of using this inheritable set */ - return -EPERM; - - if (!cap_issubset(*inheritable, - cap_combine(old->cap_inheritable, - old->cap_bset))) - /* no new pI capabilities outside bounding set */ - return -EPERM; - - /* verify restrictions on target's new Permitted set */ - if (!cap_issubset(*permitted, old->cap_permitted)) - return -EPERM; - - /* verify the _new_Effective_ is a subset of the _new_Permitted_ */ - if (!cap_issubset(*effective, *permitted)) - return -EPERM; - - new->cap_effective = *effective; - new->cap_inheritable = *inheritable; - new->cap_permitted = *permitted; - - /* - * Mask off ambient bits that are no longer both permitted and - * inheritable. - */ - new->cap_ambient = cap_intersect(new->cap_ambient, - cap_intersect(*permitted, - *inheritable)); - if (WARN_ON(!cap_ambient_invariant_ok(new))) - return -EINVAL; - return 0; -} - -/* - * Clear proposed capability sets for execve(). - */ -static inline void bprm_clear_caps(struct linux_binprm *bprm) -{ - cap_clear(bprm->cred->cap_permitted); - bprm->cap_effective = false; -} - -/** - * cap_inode_need_killpriv - Determine if inode change affects privileges - * @dentry: The inode/dentry in being changed with change marked ATTR_KILL_PRIV - * - * Determine if an inode having a change applied that's marked ATTR_KILL_PRIV - * affects the security markings on that inode, and if it is, should - * inode_killpriv() be invoked or the change rejected? - * - * Returns 0 if granted; +ve if granted, but inode_killpriv() is required; and - * -ve to deny the change. - */ -int cap_inode_need_killpriv(struct dentry *dentry) -{ - struct inode *inode = d_backing_inode(dentry); - int error; - - error = __vfs_getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0); - return error > 0; -} - -/** - * cap_inode_killpriv - Erase the security markings on an inode - * @dentry: The inode/dentry to alter - * - * Erase the privilege-enhancing security markings on an inode. - * - * Returns 0 if successful, -ve on error. - */ -int cap_inode_killpriv(struct dentry *dentry) -{ - int error; - - error = __vfs_removexattr(dentry, XATTR_NAME_CAPS); - if (error == -EOPNOTSUPP) - error = 0; - return error; -} - -/* - * Calculate the new process capability sets from the capability sets attached - * to a file. - */ -static inline int bprm_caps_from_vfs_caps(struct cpu_vfs_cap_data *caps, - struct linux_binprm *bprm, - bool *effective, - bool *has_cap) -{ - struct cred *new = bprm->cred; - unsigned i; - int ret = 0; - - if (caps->magic_etc & VFS_CAP_FLAGS_EFFECTIVE) - *effective = true; - - if (caps->magic_etc & VFS_CAP_REVISION_MASK) - *has_cap = true; - - CAP_FOR_EACH_U32(i) { - __u32 permitted = caps->permitted.cap[i]; - __u32 inheritable = caps->inheritable.cap[i]; - - /* - * pP' = (X & fP) | (pI & fI) - * The addition of pA' is handled later. - */ - new->cap_permitted.cap[i] = - (new->cap_bset.cap[i] & permitted) | - (new->cap_inheritable.cap[i] & inheritable); - - if (permitted & ~new->cap_permitted.cap[i]) - /* insufficient to execute correctly */ - ret = -EPERM; - } - - /* - * For legacy apps, with no internal support for recognizing they - * do not have enough capabilities, we return an error if they are - * missing some "forced" (aka file-permitted) capabilities. - */ - return *effective ? ret : 0; -} - -/* - * Extract the on-exec-apply capability sets for an executable file. - */ -int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps) -{ - struct inode *inode = d_backing_inode(dentry); - __u32 magic_etc; - unsigned tocopy, i; - int size; - struct vfs_cap_data caps; - - memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data)); - - if (!inode) - return -ENODATA; - - size = __vfs_getxattr((struct dentry *)dentry, inode, - XATTR_NAME_CAPS, &caps, XATTR_CAPS_SZ); - if (size == -ENODATA || size == -EOPNOTSUPP) - /* no data, that's ok */ - return -ENODATA; - if (size < 0) - return size; - - if (size < sizeof(magic_etc)) - return -EINVAL; - - cpu_caps->magic_etc = magic_etc = le32_to_cpu(caps.magic_etc); - - switch (magic_etc & VFS_CAP_REVISION_MASK) { - case VFS_CAP_REVISION_1: - if (size != XATTR_CAPS_SZ_1) - return -EINVAL; - tocopy = VFS_CAP_U32_1; - break; - case VFS_CAP_REVISION_2: - if (size != XATTR_CAPS_SZ_2) - return -EINVAL; - tocopy = VFS_CAP_U32_2; - break; - default: - return -EINVAL; - } - - CAP_FOR_EACH_U32(i) { - if (i >= tocopy) - break; - cpu_caps->permitted.cap[i] = le32_to_cpu(caps.data[i].permitted); - cpu_caps->inheritable.cap[i] = le32_to_cpu(caps.data[i].inheritable); - } - - cpu_caps->permitted.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; - cpu_caps->inheritable.cap[CAP_LAST_U32] &= CAP_LAST_U32_VALID_MASK; - - return 0; -} - -/* - * Attempt to get the on-exec apply capability sets for an executable file from - * its xattrs and, if present, apply them to the proposed credentials being - * constructed by execve(). - */ -static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_cap) -{ - int rc = 0; - struct cpu_vfs_cap_data vcaps; - - bprm_clear_caps(bprm); - - if (!file_caps_enabled) - return 0; - - if (!mnt_may_suid(bprm->file->f_path.mnt)) - return 0; - - /* - * This check is redundant with mnt_may_suid() but is kept to make - * explicit that capability bits are limited to s_user_ns and its - * descendants. - */ - if (!current_in_userns(bprm->file->f_path.mnt->mnt_sb->s_user_ns)) - return 0; - - rc = get_vfs_caps_from_disk(bprm->file->f_path.dentry, &vcaps); - if (rc < 0) { - if (rc == -EINVAL) - printk(KERN_NOTICE "%s: get_vfs_caps_from_disk returned %d for %s\n", - __func__, rc, bprm->filename); - else if (rc == -ENODATA) - rc = 0; - goto out; - } - - rc = bprm_caps_from_vfs_caps(&vcaps, bprm, effective, has_cap); - if (rc == -EINVAL) - printk(KERN_NOTICE "%s: cap_from_disk returned %d for %s\n", - __func__, rc, bprm->filename); - -out: - if (rc) - bprm_clear_caps(bprm); - - return rc; -} - -/** - * cap_bprm_set_creds - Set up the proposed credentials for execve(). - * @bprm: The execution parameters, including the proposed creds - * - * Set up the proposed credentials for a new execution context being - * constructed by execve(). The proposed creds in @bprm->cred is altered, - * which won't take effect immediately. Returns 0 if successful, -ve on error. - */ -int cap_bprm_set_creds(struct linux_binprm *bprm) -{ - const struct cred *old = current_cred(); - struct cred *new = bprm->cred; - bool effective, has_cap = false, is_setid; - int ret; - kuid_t root_uid; - - if (WARN_ON(!cap_ambient_invariant_ok(old))) - return -EPERM; - - effective = false; - ret = get_file_caps(bprm, &effective, &has_cap); - if (ret < 0) - return ret; - - root_uid = make_kuid(new->user_ns, 0); - - if (!issecure(SECURE_NOROOT)) { - /* - * If the legacy file capability is set, then don't set privs - * for a setuid root binary run by a non-root user. Do set it - * for a root user just to cause least surprise to an admin. - */ - if (has_cap && !uid_eq(new->uid, root_uid) && uid_eq(new->euid, root_uid)) { - warn_setuid_and_fcaps_mixed(bprm->filename); - goto skip; - } - /* - * To support inheritance of root-permissions and suid-root - * executables under compatibility mode, we override the - * capability sets for the file. - * - * If only the real uid is 0, we do not set the effective bit. - */ - if (uid_eq(new->euid, root_uid) || uid_eq(new->uid, root_uid)) { - /* pP' = (cap_bset & ~0) | (pI & ~0) */ - new->cap_permitted = cap_combine(old->cap_bset, - old->cap_inheritable); - } - if (uid_eq(new->euid, root_uid)) - effective = true; - } -skip: - - /* if we have fs caps, clear dangerous personality flags */ - if (!cap_issubset(new->cap_permitted, old->cap_permitted)) - bprm->per_clear |= PER_CLEAR_ON_SETID; - - - /* Don't let someone trace a set[ug]id/setpcap binary with the revised - * credentials unless they have the appropriate permit. - * - * In addition, if NO_NEW_PRIVS, then ensure we get no new privs. - */ - is_setid = !uid_eq(new->euid, old->uid) || !gid_eq(new->egid, old->gid); - - if ((is_setid || - !cap_issubset(new->cap_permitted, old->cap_permitted)) && - bprm->unsafe & ~LSM_UNSAFE_PTRACE_CAP) { - /* downgrade; they get no more than they had, and maybe less */ - if (!capable(CAP_SETUID) || - (bprm->unsafe & LSM_UNSAFE_NO_NEW_PRIVS)) { - new->euid = new->uid; - new->egid = new->gid; - } - new->cap_permitted = cap_intersect(new->cap_permitted, - old->cap_permitted); - } - - new->suid = new->fsuid = new->euid; - new->sgid = new->fsgid = new->egid; - - /* File caps or setid cancels ambient. */ - if (has_cap || is_setid) - cap_clear(new->cap_ambient); - - /* - * Now that we've computed pA', update pP' to give: - * pP' = (X & fP) | (pI & fI) | pA' - */ - new->cap_permitted = cap_combine(new->cap_permitted, new->cap_ambient); - - /* - * Set pE' = (fE ? pP' : pA'). Because pA' is zero if fE is set, - * this is the same as pE' = (fE ? pP' : 0) | pA'. - */ - if (effective) - new->cap_effective = new->cap_permitted; - else - new->cap_effective = new->cap_ambient; - - if (WARN_ON(!cap_ambient_invariant_ok(new))) - return -EPERM; - - bprm->cap_effective = effective; - - /* - * Audit candidate if current->cap_effective is set - * - * We do not bother to audit if 3 things are true: - * 1) cap_effective has all caps - * 2) we are root - * 3) root is supposed to have all caps (SECURE_NOROOT) - * Since this is just a normal root execing a process. - * - * Number 1 above might fail if you don't have a full bset, but I think - * that is interesting information to audit. - */ - if (!cap_issubset(new->cap_effective, new->cap_ambient)) { - if (!cap_issubset(CAP_FULL_SET, new->cap_effective) || - !uid_eq(new->euid, root_uid) || !uid_eq(new->uid, root_uid) || - issecure(SECURE_NOROOT)) { - ret = audit_log_bprm_fcaps(bprm, new, old); - if (ret < 0) - return ret; - } - } - - new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); - - if (WARN_ON(!cap_ambient_invariant_ok(new))) - return -EPERM; - - return 0; -} - -/** - * cap_bprm_secureexec - Determine whether a secure execution is required - * @bprm: The execution parameters - * - * Determine whether a secure execution is required, return 1 if it is, and 0 - * if it is not. - * - * The credentials have been committed by this point, and so are no longer - * available through @bprm->cred. - */ -int cap_bprm_secureexec(struct linux_binprm *bprm) -{ - const struct cred *cred = current_cred(); - kuid_t root_uid = make_kuid(cred->user_ns, 0); - - if (!uid_eq(cred->uid, root_uid)) { - if (bprm->cap_effective) - return 1; - if (!cap_issubset(cred->cap_permitted, cred->cap_ambient)) - return 1; - } - - return (!uid_eq(cred->euid, cred->uid) || - !gid_eq(cred->egid, cred->gid)); -} - -/** - * cap_inode_setxattr - Determine whether an xattr may be altered - * @dentry: The inode/dentry being altered - * @name: The name of the xattr to be changed - * @value: The value that the xattr will be changed to - * @size: The size of value - * @flags: The replacement flag - * - * Determine whether an xattr may be altered or set on an inode, returning 0 if - * permission is granted, -ve if denied. - * - * This is used to make sure security xattrs don't get updated or set by those - * who aren't privileged to do so. - */ -int cap_inode_setxattr(struct dentry *dentry, const char *name, - const void *value, size_t size, int flags) -{ - if (!strcmp(name, XATTR_NAME_CAPS)) { - if (!capable(CAP_SETFCAP)) - return -EPERM; - return 0; - } - - if (!strncmp(name, XATTR_SECURITY_PREFIX, - sizeof(XATTR_SECURITY_PREFIX) - 1) && - !capable(CAP_SYS_ADMIN)) - return -EPERM; - return 0; -} - -/** - * cap_inode_removexattr - Determine whether an xattr may be removed - * @dentry: The inode/dentry being altered - * @name: The name of the xattr to be changed - * - * Determine whether an xattr may be removed from an inode, returning 0 if - * permission is granted, -ve if denied. - * - * This is used to make sure security xattrs don't get removed by those who - * aren't privileged to remove them. - */ -int cap_inode_removexattr(struct dentry *dentry, const char *name) -{ - if (!strcmp(name, XATTR_NAME_CAPS)) { - if (!capable(CAP_SETFCAP)) - return -EPERM; - return 0; - } - - if (!strncmp(name, XATTR_SECURITY_PREFIX, - sizeof(XATTR_SECURITY_PREFIX) - 1) && - !capable(CAP_SYS_ADMIN)) - return -EPERM; - return 0; -} - -/* - * cap_emulate_setxuid() fixes the effective / permitted capabilities of - * a process after a call to setuid, setreuid, or setresuid. - * - * 1) When set*uiding _from_ one of {r,e,s}uid == 0 _to_ all of - * {r,e,s}uid != 0, the permitted and effective capabilities are - * cleared. - * - * 2) When set*uiding _from_ euid == 0 _to_ euid != 0, the effective - * capabilities of the process are cleared. - * - * 3) When set*uiding _from_ euid != 0 _to_ euid == 0, the effective - * capabilities are set to the permitted capabilities. - * - * fsuid is handled elsewhere. fsuid == 0 and {r,e,s}uid!= 0 should - * never happen. - * - * -astor - * - * cevans - New behaviour, Oct '99 - * A process may, via prctl(), elect to keep its capabilities when it - * calls setuid() and switches away from uid==0. Both permitted and - * effective sets will be retained. - * Without this change, it was impossible for a daemon to drop only some - * of its privilege. The call to setuid(!=0) would drop all privileges! - * Keeping uid 0 is not an option because uid 0 owns too many vital - * files.. - * Thanks to Olaf Kirch and Peter Benie for spotting this. - */ -static inline void cap_emulate_setxuid(struct cred *new, const struct cred *old) -{ - kuid_t root_uid = make_kuid(old->user_ns, 0); - - if ((uid_eq(old->uid, root_uid) || - uid_eq(old->euid, root_uid) || - uid_eq(old->suid, root_uid)) && - (!uid_eq(new->uid, root_uid) && - !uid_eq(new->euid, root_uid) && - !uid_eq(new->suid, root_uid))) { - if (!issecure(SECURE_KEEP_CAPS)) { - cap_clear(new->cap_permitted); - cap_clear(new->cap_effective); - } - - /* - * Pre-ambient programs expect setresuid to nonroot followed - * by exec to drop capabilities. We should make sure that - * this remains the case. - */ - cap_clear(new->cap_ambient); - } - if (uid_eq(old->euid, root_uid) && !uid_eq(new->euid, root_uid)) - cap_clear(new->cap_effective); - if (!uid_eq(old->euid, root_uid) && uid_eq(new->euid, root_uid)) - new->cap_effective = new->cap_permitted; -} - -/** - * cap_task_fix_setuid - Fix up the results of setuid() call - * @new: The proposed credentials - * @old: The current task's current credentials - * @flags: Indications of what has changed - * - * Fix up the results of setuid() call before the credential changes are - * actually applied, returning 0 to grant the changes, -ve to deny them. - */ -int cap_task_fix_setuid(struct cred *new, const struct cred *old, int flags) -{ - switch (flags) { - case LSM_SETID_RE: - case LSM_SETID_ID: - case LSM_SETID_RES: - /* juggle the capabilities to follow [RES]UID changes unless - * otherwise suppressed */ - if (!issecure(SECURE_NO_SETUID_FIXUP)) - cap_emulate_setxuid(new, old); - break; - - case LSM_SETID_FS: - /* juggle the capabilties to follow FSUID changes, unless - * otherwise suppressed - * - * FIXME - is fsuser used for all CAP_FS_MASK capabilities? - * if not, we might be a bit too harsh here. - */ - if (!issecure(SECURE_NO_SETUID_FIXUP)) { - kuid_t root_uid = make_kuid(old->user_ns, 0); - if (uid_eq(old->fsuid, root_uid) && !uid_eq(new->fsuid, root_uid)) - new->cap_effective = - cap_drop_fs_set(new->cap_effective); - - if (!uid_eq(old->fsuid, root_uid) && uid_eq(new->fsuid, root_uid)) - new->cap_effective = - cap_raise_fs_set(new->cap_effective, - new->cap_permitted); - } - break; - - default: - return -EINVAL; - } - - return 0; -} - -/* - * Rationale: code calling task_setscheduler, task_setioprio, and - * task_setnice, assumes that - * . if capable(cap_sys_nice), then those actions should be allowed - * . if not capable(cap_sys_nice), but acting on your own processes, - * then those actions should be allowed - * This is insufficient now since you can call code without suid, but - * yet with increased caps. - * So we check for increased caps on the target process. - */ -static int cap_safe_nice(struct task_struct *p) -{ - int is_subset, ret = 0; - - rcu_read_lock(); - is_subset = cap_issubset(__task_cred(p)->cap_permitted, - current_cred()->cap_permitted); - if (!is_subset && !ns_capable(__task_cred(p)->user_ns, CAP_SYS_NICE)) - ret = -EPERM; - rcu_read_unlock(); - - return ret; -} - -/** - * cap_task_setscheduler - Detemine if scheduler policy change is permitted - * @p: The task to affect - * - * Detemine if the requested scheduler policy change is permitted for the - * specified task, returning 0 if permission is granted, -ve if denied. - */ -int cap_task_setscheduler(struct task_struct *p) -{ - return cap_safe_nice(p); -} - -/** - * cap_task_ioprio - Detemine if I/O priority change is permitted - * @p: The task to affect - * @ioprio: The I/O priority to set - * - * Detemine if the requested I/O priority change is permitted for the specified - * task, returning 0 if permission is granted, -ve if denied. - */ -int cap_task_setioprio(struct task_struct *p, int ioprio) -{ - return cap_safe_nice(p); -} - -/** - * cap_task_ioprio - Detemine if task priority change is permitted - * @p: The task to affect - * @nice: The nice value to set - * - * Detemine if the requested task priority change is permitted for the - * specified task, returning 0 if permission is granted, -ve if denied. - */ -int cap_task_setnice(struct task_struct *p, int nice) -{ - return cap_safe_nice(p); -} - -/* - * Implement PR_CAPBSET_DROP. Attempt to remove the specified capability from - * the current task's bounding set. Returns 0 on success, -ve on error. - */ -static int cap_prctl_drop(unsigned long cap) -{ - struct cred *new; - - if (!ns_capable(current_user_ns(), CAP_SETPCAP)) - return -EPERM; - if (!cap_valid(cap)) - return -EINVAL; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - cap_lower(new->cap_bset, cap); - return commit_creds(new); -} - -/** - * cap_task_prctl - Implement process control functions for this security module - * @option: The process control function requested - * @arg2, @arg3, @arg4, @arg5: The argument data for this function - * - * Allow process control functions (sys_prctl()) to alter capabilities; may - * also deny access to other functions not otherwise implemented here. - * - * Returns 0 or +ve on success, -ENOSYS if this function is not implemented - * here, other -ve on error. If -ENOSYS is returned, sys_prctl() and other LSM - * modules will consider performing the function. - */ -int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3, - unsigned long arg4, unsigned long arg5) -{ - const struct cred *old = current_cred(); - struct cred *new; - - switch (option) { - case PR_CAPBSET_READ: - if (!cap_valid(arg2)) - return -EINVAL; - return !!cap_raised(old->cap_bset, arg2); - - case PR_CAPBSET_DROP: - return cap_prctl_drop(arg2); - - /* - * The next four prctl's remain to assist with transitioning a - * system from legacy UID=0 based privilege (when filesystem - * capabilities are not in use) to a system using filesystem - * capabilities only - as the POSIX.1e draft intended. - * - * Note: - * - * PR_SET_SECUREBITS = - * issecure_mask(SECURE_KEEP_CAPS_LOCKED) - * | issecure_mask(SECURE_NOROOT) - * | issecure_mask(SECURE_NOROOT_LOCKED) - * | issecure_mask(SECURE_NO_SETUID_FIXUP) - * | issecure_mask(SECURE_NO_SETUID_FIXUP_LOCKED) - * - * will ensure that the current process and all of its - * children will be locked into a pure - * capability-based-privilege environment. - */ - case PR_SET_SECUREBITS: - if ((((old->securebits & SECURE_ALL_LOCKS) >> 1) - & (old->securebits ^ arg2)) /*[1]*/ - || ((old->securebits & SECURE_ALL_LOCKS & ~arg2)) /*[2]*/ - || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS)) /*[3]*/ - || (cap_capable(current_cred(), - current_cred()->user_ns, CAP_SETPCAP, - SECURITY_CAP_AUDIT) != 0) /*[4]*/ - /* - * [1] no changing of bits that are locked - * [2] no unlocking of locks - * [3] no setting of unsupported bits - * [4] doing anything requires privilege (go read about - * the "sendmail capabilities bug") - */ - ) - /* cannot change a locked bit */ - return -EPERM; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - new->securebits = arg2; - return commit_creds(new); - - case PR_GET_SECUREBITS: - return old->securebits; - - case PR_GET_KEEPCAPS: - return !!issecure(SECURE_KEEP_CAPS); - - case PR_SET_KEEPCAPS: - if (arg2 > 1) /* Note, we rely on arg2 being unsigned here */ - return -EINVAL; - if (issecure(SECURE_KEEP_CAPS_LOCKED)) - return -EPERM; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - if (arg2) - new->securebits |= issecure_mask(SECURE_KEEP_CAPS); - else - new->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); - return commit_creds(new); - - case PR_CAP_AMBIENT: - if (arg2 == PR_CAP_AMBIENT_CLEAR_ALL) { - if (arg3 | arg4 | arg5) - return -EINVAL; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - cap_clear(new->cap_ambient); - return commit_creds(new); - } - - if (((!cap_valid(arg3)) | arg4 | arg5)) - return -EINVAL; - - if (arg2 == PR_CAP_AMBIENT_IS_SET) { - return !!cap_raised(current_cred()->cap_ambient, arg3); - } else if (arg2 != PR_CAP_AMBIENT_RAISE && - arg2 != PR_CAP_AMBIENT_LOWER) { - return -EINVAL; - } else { - if (arg2 == PR_CAP_AMBIENT_RAISE && - (!cap_raised(current_cred()->cap_permitted, arg3) || - !cap_raised(current_cred()->cap_inheritable, - arg3) || - issecure(SECURE_NO_CAP_AMBIENT_RAISE))) - return -EPERM; - - new = prepare_creds(); - if (!new) - return -ENOMEM; - if (arg2 == PR_CAP_AMBIENT_RAISE) - cap_raise(new->cap_ambient, arg3); - else - cap_lower(new->cap_ambient, arg3); - return commit_creds(new); - } - - default: - /* No functionality available - continue with default */ - return -ENOSYS; - } -} - -/** - * cap_vm_enough_memory - Determine whether a new virtual mapping is permitted - * @mm: The VM space in which the new mapping is to be made - * @pages: The size of the mapping - * - * Determine whether the allocation of a new virtual mapping by the current - * task is permitted, returning 1 if permission is granted, 0 if not. - */ -int cap_vm_enough_memory(struct mm_struct *mm, long pages) -{ - int cap_sys_admin = 0; - - if (cap_capable(current_cred(), &init_user_ns, CAP_SYS_ADMIN, - SECURITY_CAP_NOAUDIT) == 0) - cap_sys_admin = 1; - return cap_sys_admin; -} - -/* - * cap_mmap_addr - check if able to map given addr - * @addr: address attempting to be mapped - * - * If the process is attempting to map memory below dac_mmap_min_addr they need - * CAP_SYS_RAWIO. The other parameters to this function are unused by the - * capability security module. Returns 0 if this mapping should be allowed - * -EPERM if not. - */ -int cap_mmap_addr(unsigned long addr) -{ - int ret = 0; - - if (addr < dac_mmap_min_addr) { - ret = cap_capable(current_cred(), &init_user_ns, CAP_SYS_RAWIO, - SECURITY_CAP_AUDIT); - /* set PF_SUPERPRIV if it turns out we allow the low mmap */ - if (ret == 0) - current->flags |= PF_SUPERPRIV; - } - return ret; -} - -int cap_mmap_file(struct file *file, unsigned long reqprot, - unsigned long prot, unsigned long flags) -{ - return 0; -} - -#ifdef CONFIG_SECURITY - -struct security_hook_list capability_hooks[] = { - LSM_HOOK_INIT(capable, cap_capable), - LSM_HOOK_INIT(settime, cap_settime), - LSM_HOOK_INIT(ptrace_access_check, cap_ptrace_access_check), - LSM_HOOK_INIT(ptrace_traceme, cap_ptrace_traceme), - LSM_HOOK_INIT(capget, cap_capget), - LSM_HOOK_INIT(capset, cap_capset), - LSM_HOOK_INIT(bprm_set_creds, cap_bprm_set_creds), - LSM_HOOK_INIT(bprm_secureexec, cap_bprm_secureexec), - LSM_HOOK_INIT(inode_need_killpriv, cap_inode_need_killpriv), - LSM_HOOK_INIT(inode_killpriv, cap_inode_killpriv), - LSM_HOOK_INIT(mmap_addr, cap_mmap_addr), - LSM_HOOK_INIT(mmap_file, cap_mmap_file), - LSM_HOOK_INIT(task_fix_setuid, cap_task_fix_setuid), - LSM_HOOK_INIT(task_prctl, cap_task_prctl), - LSM_HOOK_INIT(task_setscheduler, cap_task_setscheduler), - LSM_HOOK_INIT(task_setioprio, cap_task_setioprio), - LSM_HOOK_INIT(task_setnice, cap_task_setnice), - LSM_HOOK_INIT(vm_enough_memory, cap_vm_enough_memory), -}; - -void __init capability_add_hooks(void) -{ - security_add_hooks(capability_hooks, ARRAY_SIZE(capability_hooks)); -} - -#endif /* CONFIG_SECURITY */ diff --git a/src/linux/security/integrity/Kconfig b/src/linux/security/integrity/Kconfig deleted file mode 100644 index da95658..0000000 --- a/src/linux/security/integrity/Kconfig +++ /dev/null @@ -1,72 +0,0 @@ -# -config INTEGRITY - bool "Integrity subsystem" - depends on SECURITY - default y - help - This option enables the integrity subsystem, which is comprised - of a number of different components including the Integrity - Measurement Architecture (IMA), Extended Verification Module - (EVM), IMA-appraisal extension, digital signature verification - extension and audit measurement log support. - - Each of these components can be enabled/disabled separately. - Refer to the individual components for additional details. - -if INTEGRITY - -config INTEGRITY_SIGNATURE - bool "Digital signature verification using multiple keyrings" - depends on KEYS - default n - select SIGNATURE - help - This option enables digital signature verification support - using multiple keyrings. It defines separate keyrings for each - of the different use cases - evm, ima, and modules. - Different keyrings improves search performance, but also allow - to "lock" certain keyring to prevent adding new keys. - This is useful for evm and module keyrings, when keys are - usually only added from initramfs. - -config INTEGRITY_ASYMMETRIC_KEYS - bool "Enable asymmetric keys support" - depends on INTEGRITY_SIGNATURE - default n - select ASYMMETRIC_KEY_TYPE - select ASYMMETRIC_PUBLIC_KEY_SUBTYPE - select CRYPTO_RSA - select X509_CERTIFICATE_PARSER - help - This option enables digital signature verification using - asymmetric keys. - -config INTEGRITY_TRUSTED_KEYRING - bool "Require all keys on the integrity keyrings be signed" - depends on SYSTEM_TRUSTED_KEYRING - depends on INTEGRITY_ASYMMETRIC_KEYS - default y - help - This option requires that all keys added to the .ima and - .evm keyrings be signed by a key on the system trusted - keyring. - -config INTEGRITY_AUDIT - bool "Enables integrity auditing support " - depends on AUDIT - default y - help - In addition to enabling integrity auditing support, this - option adds a kernel parameter 'integrity_audit', which - controls the level of integrity auditing messages. - 0 - basic integrity auditing messages (default) - 1 - additional integrity auditing messages - - Additional informational integrity auditing messages would - be enabled by specifying 'integrity_audit=1' on the kernel - command line. - -source security/integrity/ima/Kconfig -source security/integrity/evm/Kconfig - -endif # if INTEGRITY diff --git a/src/linux/security/integrity/evm/Kconfig b/src/linux/security/integrity/evm/Kconfig deleted file mode 100644 index e825e0a..0000000 --- a/src/linux/security/integrity/evm/Kconfig +++ /dev/null @@ -1,61 +0,0 @@ -config EVM - bool "EVM support" - select KEYS - select ENCRYPTED_KEYS - select CRYPTO_HMAC - select CRYPTO_SHA1 - default n - help - EVM protects a file's security extended attributes against - integrity attacks. - - If you are unsure how to answer this question, answer N. - -config EVM_ATTR_FSUUID - bool "FSUUID (version 2)" - default y - depends on EVM - help - Include filesystem UUID for HMAC calculation. - - Default value is 'selected', which is former version 2. - if 'not selected', it is former version 1 - - WARNING: changing the HMAC calculation method or adding - additional info to the calculation, requires existing EVM - labeled file systems to be relabeled. - -config EVM_EXTRA_SMACK_XATTRS - bool "Additional SMACK xattrs" - depends on EVM && SECURITY_SMACK - default n - help - Include additional SMACK xattrs for HMAC calculation. - - In addition to the original security xattrs (eg. security.selinux, - security.SMACK64, security.capability, and security.ima) included - in the HMAC calculation, enabling this option includes newly defined - Smack xattrs: security.SMACK64EXEC, security.SMACK64TRANSMUTE and - security.SMACK64MMAP. - - WARNING: changing the HMAC calculation method or adding - additional info to the calculation, requires existing EVM - labeled file systems to be relabeled. - -config EVM_LOAD_X509 - bool "Load an X509 certificate onto the '.evm' trusted keyring" - depends on EVM && INTEGRITY_TRUSTED_KEYRING - default n - help - Load an X509 certificate onto the '.evm' trusted keyring. - - This option enables X509 certificate loading from the kernel - onto the '.evm' trusted keyring. A public key can be used to - verify EVM integrity starting from the 'init' process. - -config EVM_X509_PATH - string "EVM X509 certificate path" - depends on EVM_LOAD_X509 - default "/etc/keys/x509_evm.der" - help - This option defines X509 certificate path. diff --git a/src/linux/security/integrity/ima/Kconfig b/src/linux/security/integrity/ima/Kconfig deleted file mode 100644 index 5487827..0000000 --- a/src/linux/security/integrity/ima/Kconfig +++ /dev/null @@ -1,209 +0,0 @@ -# IBM Integrity Measurement Architecture -# -config IMA - bool "Integrity Measurement Architecture(IMA)" - select SECURITYFS - select CRYPTO - select CRYPTO_HMAC - select CRYPTO_MD5 - select CRYPTO_SHA1 - select CRYPTO_HASH_INFO - select TCG_TPM if HAS_IOMEM && !UML - select TCG_TIS if TCG_TPM && X86 - select TCG_IBMVTPM if TCG_TPM && PPC_PSERIES - help - The Trusted Computing Group(TCG) runtime Integrity - Measurement Architecture(IMA) maintains a list of hash - values of executables and other sensitive system files, - as they are read or executed. If an attacker manages - to change the contents of an important system file - being measured, we can tell. - - If your system has a TPM chip, then IMA also maintains - an aggregate integrity value over this list inside the - TPM hardware, so that the TPM can prove to a third party - whether or not critical system files have been modified. - Read - to learn more about IMA. - If unsure, say N. - -config IMA_MEASURE_PCR_IDX - int - depends on IMA - range 8 14 - default 10 - help - IMA_MEASURE_PCR_IDX determines the TPM PCR register index - that IMA uses to maintain the integrity aggregate of the - measurement list. If unsure, use the default 10. - -config IMA_LSM_RULES - bool - depends on IMA && AUDIT && (SECURITY_SELINUX || SECURITY_SMACK) - default y - help - Disabling this option will disregard LSM based policy rules. - -choice - prompt "Default template" - default IMA_NG_TEMPLATE - depends on IMA - help - Select the default IMA measurement template. - - The original 'ima' measurement list template contains a - hash, defined as 20 bytes, and a null terminated pathname, - limited to 255 characters. The 'ima-ng' measurement list - template permits both larger hash digests and longer - pathnames. - - config IMA_TEMPLATE - bool "ima" - config IMA_NG_TEMPLATE - bool "ima-ng (default)" - config IMA_SIG_TEMPLATE - bool "ima-sig" -endchoice - -config IMA_DEFAULT_TEMPLATE - string - depends on IMA - default "ima" if IMA_TEMPLATE - default "ima-ng" if IMA_NG_TEMPLATE - default "ima-sig" if IMA_SIG_TEMPLATE - -choice - prompt "Default integrity hash algorithm" - default IMA_DEFAULT_HASH_SHA1 - depends on IMA - help - Select the default hash algorithm used for the measurement - list, integrity appraisal and audit log. The compiled default - hash algorithm can be overwritten using the kernel command - line 'ima_hash=' option. - - config IMA_DEFAULT_HASH_SHA1 - bool "SHA1 (default)" - depends on CRYPTO_SHA1 - - config IMA_DEFAULT_HASH_SHA256 - bool "SHA256" - depends on CRYPTO_SHA256 && !IMA_TEMPLATE - - config IMA_DEFAULT_HASH_SHA512 - bool "SHA512" - depends on CRYPTO_SHA512 && !IMA_TEMPLATE - - config IMA_DEFAULT_HASH_WP512 - bool "WP512" - depends on CRYPTO_WP512 && !IMA_TEMPLATE -endchoice - -config IMA_DEFAULT_HASH - string - depends on IMA - default "sha1" if IMA_DEFAULT_HASH_SHA1 - default "sha256" if IMA_DEFAULT_HASH_SHA256 - default "sha512" if IMA_DEFAULT_HASH_SHA512 - default "wp512" if IMA_DEFAULT_HASH_WP512 - -config IMA_WRITE_POLICY - bool "Enable multiple writes to the IMA policy" - depends on IMA - default n - help - IMA policy can now be updated multiple times. The new rules get - appended to the original policy. Have in mind that the rules are - scanned in FIFO order so be careful when you design and add new ones. - - If unsure, say N. - -config IMA_READ_POLICY - bool "Enable reading back the current IMA policy" - depends on IMA - default y if IMA_WRITE_POLICY - default n if !IMA_WRITE_POLICY - help - It is often useful to be able to read back the IMA policy. It is - even more important after introducing CONFIG_IMA_WRITE_POLICY. - This option allows the root user to see the current policy rules. - -config IMA_APPRAISE - bool "Appraise integrity measurements" - depends on IMA - default n - help - This option enables local measurement integrity appraisal. - It requires the system to be labeled with a security extended - attribute containing the file hash measurement. To protect - the security extended attributes from offline attack, enable - and configure EVM. - - For more information on integrity appraisal refer to: - - If unsure, say N. - -config IMA_TRUSTED_KEYRING - bool "Require all keys on the .ima keyring be signed (deprecated)" - depends on IMA_APPRAISE && SYSTEM_TRUSTED_KEYRING - depends on INTEGRITY_ASYMMETRIC_KEYS - select INTEGRITY_TRUSTED_KEYRING - default y - help - This option requires that all keys added to the .ima - keyring be signed by a key on the system trusted keyring. - - This option is deprecated in favor of INTEGRITY_TRUSTED_KEYRING - -config IMA_KEYRINGS_PERMIT_SIGNED_BY_BUILTIN_OR_SECONDARY - bool "Permit keys validly signed by a built-in or secondary CA cert (EXPERIMENTAL)" - depends on SYSTEM_TRUSTED_KEYRING - depends on SECONDARY_TRUSTED_KEYRING - depends on INTEGRITY_ASYMMETRIC_KEYS - select INTEGRITY_TRUSTED_KEYRING - default n - help - Keys may be added to the IMA or IMA blacklist keyrings, if the - key is validly signed by a CA cert in the system built-in or - secondary trusted keyrings. - - Intermediate keys between those the kernel has compiled in and the - IMA keys to be added may be added to the system secondary keyring, - provided they are validly signed by a key already resident in the - built-in or secondary trusted keyrings. - -config IMA_BLACKLIST_KEYRING - bool "Create IMA machine owner blacklist keyrings (EXPERIMENTAL)" - depends on SYSTEM_TRUSTED_KEYRING - depends on IMA_TRUSTED_KEYRING - default n - help - This option creates an IMA blacklist keyring, which contains all - revoked IMA keys. It is consulted before any other keyring. If - the search is successful the requested operation is rejected and - an error is returned to the caller. - -config IMA_LOAD_X509 - bool "Load X509 certificate onto the '.ima' trusted keyring" - depends on IMA_TRUSTED_KEYRING - default n - help - File signature verification is based on the public keys - loaded on the .ima trusted keyring. These public keys are - X509 certificates signed by a trusted key on the - .system keyring. This option enables X509 certificate - loading from the kernel onto the '.ima' trusted keyring. - -config IMA_X509_PATH - string "IMA X509 certificate path" - depends on IMA_LOAD_X509 - default "/etc/keys/x509_ima.der" - help - This option defines IMA X509 certificate path. - -config IMA_APPRAISE_SIGNED_INIT - bool "Require signed user-space initialization" - depends on IMA_LOAD_X509 - default n - help - This option requires user-space init to be signed. diff --git a/src/linux/security/keys/Kconfig b/src/linux/security/keys/Kconfig deleted file mode 100644 index d942c7c..0000000 --- a/src/linux/security/keys/Kconfig +++ /dev/null @@ -1,98 +0,0 @@ -# -# Key management configuration -# - -config KEYS - bool "Enable access key retention support" - select ASSOCIATIVE_ARRAY - help - This option provides support for retaining authentication tokens and - access keys in the kernel. - - It also includes provision of methods by which such keys might be - associated with a process so that network filesystems, encryption - support and the like can find them. - - Furthermore, a special type of key is available that acts as keyring: - a searchable sequence of keys. Each process is equipped with access - to five standard keyrings: UID-specific, GID-specific, session, - process and thread. - - If you are unsure as to whether this is required, answer N. - -config PERSISTENT_KEYRINGS - bool "Enable register of persistent per-UID keyrings" - depends on KEYS - help - This option provides a register of persistent per-UID keyrings, - primarily aimed at Kerberos key storage. The keyrings are persistent - in the sense that they stay around after all processes of that UID - have exited, not that they survive the machine being rebooted. - - A particular keyring may be accessed by either the user whose keyring - it is or by a process with administrative privileges. The active - LSMs gets to rule on which admin-level processes get to access the - cache. - - Keyrings are created and added into the register upon demand and get - removed if they expire (a default timeout is set upon creation). - -config BIG_KEYS - bool "Large payload keys" - depends on KEYS - depends on TMPFS - depends on (CRYPTO_ANSI_CPRNG = y || CRYPTO_DRBG = y) - select CRYPTO_AES - select CRYPTO_ECB - select CRYPTO_RNG - help - This option provides support for holding large keys within the kernel - (for example Kerberos ticket caches). The data may be stored out to - swapspace by tmpfs. - - If you are unsure as to whether this is required, answer N. - -config TRUSTED_KEYS - tristate "TRUSTED KEYS" - depends on KEYS && TCG_TPM - select CRYPTO - select CRYPTO_HMAC - select CRYPTO_SHA1 - select CRYPTO_HASH_INFO - help - This option provides support for creating, sealing, and unsealing - keys in the kernel. Trusted keys are random number symmetric keys, - generated and RSA-sealed by the TPM. The TPM only unseals the keys, - if the boot PCRs and other criteria match. Userspace will only ever - see encrypted blobs. - - If you are unsure as to whether this is required, answer N. - -config ENCRYPTED_KEYS - tristate "ENCRYPTED KEYS" - depends on KEYS - select CRYPTO - select CRYPTO_HMAC - select CRYPTO_AES - select CRYPTO_CBC - select CRYPTO_SHA256 - select CRYPTO_RNG - help - This option provides support for create/encrypting/decrypting keys - in the kernel. Encrypted keys are kernel generated random numbers, - which are encrypted/decrypted with a 'master' symmetric key. The - 'master' key can be either a trusted-key or user-key type. - Userspace only ever sees/stores encrypted blobs. - - If you are unsure as to whether this is required, answer N. - -config KEY_DH_OPERATIONS - bool "Diffie-Hellman operations on retained keys" - depends on KEYS - select MPILIB - help - This option provides support for calculating Diffie-Hellman - public keys and shared secrets using values stored as keys - in the kernel. - - If you are unsure as to whether this is required, answer N. diff --git a/src/linux/security/loadpin/Kconfig b/src/linux/security/loadpin/Kconfig deleted file mode 100644 index dd01aa9..0000000 --- a/src/linux/security/loadpin/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -config SECURITY_LOADPIN - bool "Pin load of kernel files (modules, fw, etc) to one filesystem" - depends on SECURITY && BLOCK - help - Any files read through the kernel file reading interface - (kernel modules, firmware, kexec images, security policy) - can be pinned to the first filesystem used for loading. When - enabled, any files that come from other filesystems will be - rejected. This is best used on systems without an initrd that - have a root filesystem backed by a read-only device such as - dm-verity or a CDROM. - -config SECURITY_LOADPIN_ENABLED - bool "Enforce LoadPin at boot" - depends on SECURITY_LOADPIN - help - If selected, LoadPin will enforce pinning at boot. If not - selected, it can be enabled at boot with the kernel parameter - "loadpin.enabled=1". diff --git a/src/linux/security/selinux/.gitignore b/src/linux/security/selinux/.gitignore deleted file mode 100644 index 2e5040a..0000000 --- a/src/linux/security/selinux/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -av_permissions.h -flask.h diff --git a/src/linux/security/selinux/Kconfig b/src/linux/security/selinux/Kconfig deleted file mode 100644 index ea7e3ef..0000000 --- a/src/linux/security/selinux/Kconfig +++ /dev/null @@ -1,95 +0,0 @@ -config SECURITY_SELINUX - bool "NSA SELinux Support" - depends on SECURITY_NETWORK && AUDIT && NET && INET - select NETWORK_SECMARK - default n - help - This selects NSA Security-Enhanced Linux (SELinux). - You will also need a policy configuration and a labeled filesystem. - If you are unsure how to answer this question, answer N. - -config SECURITY_SELINUX_BOOTPARAM - bool "NSA SELinux boot parameter" - depends on SECURITY_SELINUX - default n - help - This option adds a kernel parameter 'selinux', which allows SELinux - to be disabled at boot. If this option is selected, SELinux - functionality can be disabled with selinux=0 on the kernel - command line. The purpose of this option is to allow a single - kernel image to be distributed with SELinux built in, but not - necessarily enabled. - - If you are unsure how to answer this question, answer N. - -config SECURITY_SELINUX_BOOTPARAM_VALUE - int "NSA SELinux boot parameter default value" - depends on SECURITY_SELINUX_BOOTPARAM - range 0 1 - default 1 - help - This option sets the default value for the kernel parameter - 'selinux', which allows SELinux to be disabled at boot. If this - option is set to 0 (zero), the SELinux kernel parameter will - default to 0, disabling SELinux at bootup. If this option is - set to 1 (one), the SELinux kernel parameter will default to 1, - enabling SELinux at bootup. - - If you are unsure how to answer this question, answer 1. - -config SECURITY_SELINUX_DISABLE - bool "NSA SELinux runtime disable" - depends on SECURITY_SELINUX - default n - help - This option enables writing to a selinuxfs node 'disable', which - allows SELinux to be disabled at runtime prior to the policy load. - SELinux will then remain disabled until the next boot. - This option is similar to the selinux=0 boot parameter, but is to - support runtime disabling of SELinux, e.g. from /sbin/init, for - portability across platforms where boot parameters are difficult - to employ. - - If you are unsure how to answer this question, answer N. - -config SECURITY_SELINUX_DEVELOP - bool "NSA SELinux Development Support" - depends on SECURITY_SELINUX - default y - help - This enables the development support option of NSA SELinux, - which is useful for experimenting with SELinux and developing - policies. If unsure, say Y. With this option enabled, the - kernel will start in permissive mode (log everything, deny nothing) - unless you specify enforcing=1 on the kernel command line. You - can interactively toggle the kernel between enforcing mode and - permissive mode (if permitted by the policy) via /selinux/enforce. - -config SECURITY_SELINUX_AVC_STATS - bool "NSA SELinux AVC Statistics" - depends on SECURITY_SELINUX - default y - help - This option collects access vector cache statistics to - /selinux/avc/cache_stats, which may be monitored via - tools such as avcstat. - -config SECURITY_SELINUX_CHECKREQPROT_VALUE - int "NSA SELinux checkreqprot default value" - depends on SECURITY_SELINUX - range 0 1 - default 0 - help - This option sets the default value for the 'checkreqprot' flag - that determines whether SELinux checks the protection requested - by the application or the protection that will be applied by the - kernel (including any implied execute for read-implies-exec) for - mmap and mprotect calls. If this option is set to 0 (zero), - SELinux will default to checking the protection that will be applied - by the kernel. If this option is set to 1 (one), SELinux will - default to checking the protection requested by the application. - The checkreqprot flag may be changed from the default via the - 'checkreqprot=' boot parameter. It may also be changed at runtime - via /selinux/checkreqprot if authorized by policy. - - If you are unsure how to answer this question, answer 0. diff --git a/src/linux/security/smack/Kconfig b/src/linux/security/smack/Kconfig deleted file mode 100644 index 923b120..0000000 --- a/src/linux/security/smack/Kconfig +++ /dev/null @@ -1,54 +0,0 @@ -config SECURITY_SMACK - bool "Simplified Mandatory Access Control Kernel Support" - depends on NET - depends on INET - depends on SECURITY - select NETLABEL - select SECURITY_NETWORK - default n - help - This selects the Simplified Mandatory Access Control Kernel. - Smack is useful for sensitivity, integrity, and a variety - of other mandatory security schemes. - If you are unsure how to answer this question, answer N. - -config SECURITY_SMACK_BRINGUP - bool "Reporting on access granted by Smack rules" - depends on SECURITY_SMACK - default n - help - Enable the bring-up ("b") access mode in Smack rules. - When access is granted by a rule with the "b" mode a - message about the access requested is generated. The - intention is that a process can be granted a wide set - of access initially with the bringup mode set on the - rules. The developer can use the information to - identify which rules are necessary and what accesses - may be inappropriate. The developer can reduce the - access rule set once the behavior is well understood. - This is a superior mechanism to the oft abused - "permissive" mode of other systems. - If you are unsure how to answer this question, answer N. - -config SECURITY_SMACK_NETFILTER - bool "Packet marking using secmarks for netfilter" - depends on SECURITY_SMACK - depends on NETWORK_SECMARK - depends on NETFILTER - default n - help - This enables security marking of network packets using - Smack labels. - If you are unsure how to answer this question, answer N. - -config SECURITY_SMACK_APPEND_SIGNALS - bool "Treat delivering signals as an append operation" - depends on SECURITY_SMACK - default n - help - Sending a signal has been treated as a write operation to the - receiving process. If this option is selected, the delivery - will be an append operation instead. This makes it possible - to differentiate between delivering a network packet and - delivering a signal in the Smack rules. - If you are unsure how to answer this question, answer N. diff --git a/src/linux/security/tomoyo/.gitignore b/src/linux/security/tomoyo/.gitignore deleted file mode 100644 index dc0f220..0000000 --- a/src/linux/security/tomoyo/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -builtin-policy.h -policy/*.conf diff --git a/src/linux/security/tomoyo/Kconfig b/src/linux/security/tomoyo/Kconfig deleted file mode 100644 index 404dce6..0000000 --- a/src/linux/security/tomoyo/Kconfig +++ /dev/null @@ -1,76 +0,0 @@ -config SECURITY_TOMOYO - bool "TOMOYO Linux Support" - depends on SECURITY - depends on NET - select SECURITYFS - select SECURITY_PATH - select SECURITY_NETWORK - select SRCU - select BUILD_BIN2C - default n - help - This selects TOMOYO Linux, pathname-based access control. - Required userspace tools and further information may be - found at . - If you are unsure how to answer this question, answer N. - -config SECURITY_TOMOYO_MAX_ACCEPT_ENTRY - int "Default maximal count for learning mode" - default 2048 - range 0 2147483647 - depends on SECURITY_TOMOYO - help - This is the default value for maximal ACL entries - that are automatically appended into policy at "learning mode". - Some programs access thousands of objects, so running - such programs in "learning mode" dulls the system response - and consumes much memory. - This is the safeguard for such programs. - -config SECURITY_TOMOYO_MAX_AUDIT_LOG - int "Default maximal count for audit log" - default 1024 - range 0 2147483647 - depends on SECURITY_TOMOYO - help - This is the default value for maximal entries for - audit logs that the kernel can hold on memory. - You can read the log via /sys/kernel/security/tomoyo/audit. - If you don't need audit logs, you may set this value to 0. - -config SECURITY_TOMOYO_OMIT_USERSPACE_LOADER - bool "Activate without calling userspace policy loader." - default n - depends on SECURITY_TOMOYO - ---help--- - Say Y here if you want to activate access control as soon as built-in - policy was loaded. This option will be useful for systems where - operations which can lead to the hijacking of the boot sequence are - needed before loading the policy. For example, you can activate - immediately after loading the fixed part of policy which will allow - only operations needed for mounting a partition which contains the - variant part of policy and verifying (e.g. running GPG check) and - loading the variant part of policy. Since you can start using - enforcing mode from the beginning, you can reduce the possibility of - hijacking the boot sequence. - -config SECURITY_TOMOYO_POLICY_LOADER - string "Location of userspace policy loader" - default "/sbin/tomoyo-init" - depends on SECURITY_TOMOYO - depends on !SECURITY_TOMOYO_OMIT_USERSPACE_LOADER - ---help--- - This is the default pathname of policy loader which is called before - activation. You can override this setting via TOMOYO_loader= kernel - command line option. - -config SECURITY_TOMOYO_ACTIVATION_TRIGGER - string "Trigger for calling userspace policy loader" - default "/sbin/init" - depends on SECURITY_TOMOYO - depends on !SECURITY_TOMOYO_OMIT_USERSPACE_LOADER - ---help--- - This is the default pathname of activation trigger. - You can override this setting via TOMOYO_trigger= kernel command line - option. For example, if you pass init=/bin/systemd option, you may - want to also pass TOMOYO_trigger=/bin/systemd option. diff --git a/src/linux/security/yama/Kconfig b/src/linux/security/yama/Kconfig deleted file mode 100644 index 90c605e..0000000 --- a/src/linux/security/yama/Kconfig +++ /dev/null @@ -1,12 +0,0 @@ -config SECURITY_YAMA - bool "Yama support" - depends on SECURITY - default n - help - This selects Yama, which extends DAC support with additional - system-wide security settings beyond regular Linux discretionary - access controls. Currently available is ptrace scope restriction. - Like capabilities, this security module stacks with other LSMs. - Further information can be found in Documentation/security/Yama.txt. - - If you are unsure how to answer this question, answer N. diff --git a/src/linux/sound/Kconfig b/src/linux/sound/Kconfig deleted file mode 100644 index 5a240e0..0000000 --- a/src/linux/sound/Kconfig +++ /dev/null @@ -1,136 +0,0 @@ -menuconfig SOUND - tristate "Sound card support" - depends on HAS_IOMEM - help - If you have a sound card in your computer, i.e. if it can say more - than an occasional beep, say Y. Be sure to have all the information - about your sound card and its configuration down (I/O port, - interrupt and DMA channel), because you will be asked for it. - - You want to read the Sound-HOWTO, available from - . General information about - the modular sound system is contained in the files - . The file - contains some slightly - outdated but still useful information as well. Newer sound - driver documentation is found in . - - If you have a PnP sound card and you want to configure it at boot - time using the ISA PnP tools (read - ), then you need to - compile the sound card support as a module and load that module - after the PnP configuration is finished. To do this, choose M here - and read ; the module - will be called soundcore. - -if SOUND - -config SOUND_OSS_CORE - bool - default n - -config SOUND_OSS_CORE_PRECLAIM - bool "Preclaim OSS device numbers" - depends on SOUND_OSS_CORE - default y - help - With this option enabled, the kernel will claim all OSS device - numbers if any OSS support (native or emulation) is enabled - whether the respective module is loaded or not and try to load the - appropriate module using sound-slot/service-* and char-major-* - module aliases when one of the device numbers is opened. With - this option disabled, kernel will only claim actually in-use - device numbers and opening a missing device will generate only the - standard char-major-* aliases. - - The only visible difference is use of additional module aliases - and whether OSS sound devices appear multiple times in - /proc/devices. sound-slot/service-* module aliases are scheduled - to be removed (ie. PRECLAIM won't be available) and this option is - to make the transition easier. This option can be overridden - during boot using the kernel parameter soundcore.preclaim_oss. - - Disabling this allows alternative OSS implementations. - - If unsure, say Y. - -source "sound/oss/dmasound/Kconfig" - -if !M68K && !UML - -menuconfig SND - tristate "Advanced Linux Sound Architecture" - help - Say 'Y' or 'M' to enable ALSA (Advanced Linux Sound Architecture), - the new base sound system. - - For more information, see - -if SND - -source "sound/core/Kconfig" - -source "sound/drivers/Kconfig" - -source "sound/isa/Kconfig" - -source "sound/pci/Kconfig" - -source "sound/hda/Kconfig" - -source "sound/ppc/Kconfig" - -source "sound/aoa/Kconfig" - -source "sound/arm/Kconfig" - -source "sound/atmel/Kconfig" - -source "sound/spi/Kconfig" - -source "sound/mips/Kconfig" - -source "sound/sh/Kconfig" - -# the following will depend on the order of config. -# here assuming USB is defined before ALSA -source "sound/usb/Kconfig" - -source "sound/firewire/Kconfig" - -# the following will depend on the order of config. -# here assuming PCMCIA is defined before ALSA -source "sound/pcmcia/Kconfig" - -source "sound/sparc/Kconfig" - -source "sound/parisc/Kconfig" - -source "sound/soc/Kconfig" - -endif # SND - -menuconfig SOUND_PRIME - tristate "Open Sound System (DEPRECATED)" - select SOUND_OSS_CORE - help - Say 'Y' or 'M' to enable Open Sound System drivers. - -if SOUND_PRIME - -source "sound/oss/Kconfig" - -endif # SOUND_PRIME - -endif # !M68K - -endif # SOUND - -# AC97_BUS is used from both sound and ucb1400 -config AC97_BUS - tristate - help - This is used to avoid config and link hard dependencies between the - sound subsystem and other function drivers completely unrelated to - sound although they're sharing the AC97 bus. Concerned drivers - should "select" this. diff --git a/src/linux/sound/Makefile b/src/linux/sound/Makefile deleted file mode 100644 index c41bdf5..0000000 --- a/src/linux/sound/Makefile +++ /dev/null @@ -1,18 +0,0 @@ -# Makefile for the Linux sound card driver -# - -obj-$(CONFIG_SOUND) += soundcore.o -obj-$(CONFIG_SOUND_PRIME) += oss/ -obj-$(CONFIG_DMASOUND) += oss/ -obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ - firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/ -obj-$(CONFIG_SND_AOA) += aoa/ - -# This one must be compilable even if sound is configured out -obj-$(CONFIG_AC97_BUS) += ac97_bus.o - -ifeq ($(CONFIG_SND),y) - obj-y += last.o -endif - -soundcore-objs := sound_core.o diff --git a/src/linux/sound/aoa/Kconfig b/src/linux/sound/aoa/Kconfig deleted file mode 100644 index c081e18..0000000 --- a/src/linux/sound/aoa/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -menuconfig SND_AOA - tristate "Apple Onboard Audio driver" - depends on PPC_PMAC - select SND_PCM - ---help--- - This option enables the new driver for the various - Apple Onboard Audio components. - -if SND_AOA - -source "sound/aoa/fabrics/Kconfig" - -source "sound/aoa/codecs/Kconfig" - -source "sound/aoa/soundbus/Kconfig" - -endif # SND_AOA diff --git a/src/linux/sound/aoa/codecs/Kconfig b/src/linux/sound/aoa/codecs/Kconfig deleted file mode 100644 index 0c68e32..0000000 --- a/src/linux/sound/aoa/codecs/Kconfig +++ /dev/null @@ -1,24 +0,0 @@ -config SND_AOA_ONYX - tristate "support Onyx chip" - select I2C - select I2C_POWERMAC - ---help--- - This option enables support for the Onyx (pcm3052) - codec chip found in the latest Apple machines - (most of those with digital audio output). - -config SND_AOA_TAS - tristate "support TAS chips" - select I2C - select I2C_POWERMAC - ---help--- - This option enables support for the tas chips - found in a lot of Apple Machines, especially - iBooks and PowerBooks without digital. - -config SND_AOA_TOONIE - tristate "support Toonie chip" - ---help--- - This option enables support for the toonie codec - found in the Mac Mini. If you have a Mac Mini and - want to hear sound, select this option. diff --git a/src/linux/sound/aoa/fabrics/Kconfig b/src/linux/sound/aoa/fabrics/Kconfig deleted file mode 100644 index 3ca475a..0000000 --- a/src/linux/sound/aoa/fabrics/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config SND_AOA_FABRIC_LAYOUT - tristate "layout-id fabric" - select SND_AOA_SOUNDBUS - select SND_AOA_SOUNDBUS_I2S - ---help--- - This enables the layout-id fabric for the Apple Onboard - Audio driver, the module holding it all together - based on the device-tree's layout-id property. - - If you are unsure and have a later Apple machine, - compile it as a module. diff --git a/src/linux/sound/aoa/soundbus/Kconfig b/src/linux/sound/aoa/soundbus/Kconfig deleted file mode 100644 index 839d113..0000000 --- a/src/linux/sound/aoa/soundbus/Kconfig +++ /dev/null @@ -1,14 +0,0 @@ -config SND_AOA_SOUNDBUS - tristate "Apple Soundbus support" - select SND_PCM - ---help--- - This option enables the generic driver for the soundbus - support on Apple machines. - - It is required for the sound bus implementations. - -config SND_AOA_SOUNDBUS_I2S - tristate "I2S bus support" - depends on SND_AOA_SOUNDBUS && PCI - ---help--- - This option enables support for Apple I2S busses. diff --git a/src/linux/sound/arm/Kconfig b/src/linux/sound/arm/Kconfig deleted file mode 100644 index 65171f6..0000000 --- a/src/linux/sound/arm/Kconfig +++ /dev/null @@ -1,43 +0,0 @@ -# ALSA ARM drivers - -menuconfig SND_ARM - bool "ARM sound devices" - depends on ARM - default y - help - Support for sound devices specific to ARM architectures. - Drivers that are implemented on ASoC can be found in - "ALSA for SoC audio support" section. - -if SND_ARM - -config SND_ARMAACI - tristate "ARM PrimeCell PL041 AC Link support" - depends on ARM_AMBA - select SND_PCM - select SND_AC97_CODEC - -config SND_PXA2XX_PCM - tristate - select SND_PCM - -config SND_PXA2XX_AC97 - tristate "AC97 driver for the Intel PXA2xx chip" - depends on ARCH_PXA - select SND_PXA2XX_PCM - select SND_AC97_CODEC - select SND_PXA2XX_LIB - select SND_PXA2XX_LIB_AC97 - help - Say Y or M if you want to support any AC97 codec attached to - the PXA2xx AC97 interface. - -endif # SND_ARM - -config SND_PXA2XX_LIB - tristate - select SND_AC97_CODEC if SND_PXA2XX_LIB_AC97 - select SND_DMAENGINE_PCM - -config SND_PXA2XX_LIB_AC97 - bool diff --git a/src/linux/sound/atmel/Kconfig b/src/linux/sound/atmel/Kconfig deleted file mode 100644 index 94de43a..0000000 --- a/src/linux/sound/atmel/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -menu "Atmel devices (AVR32 and AT91)" - depends on AVR32 || ARCH_AT91 - -config SND_ATMEL_ABDAC - tristate "Atmel Audio Bitstream DAC (ABDAC) driver" - select SND_PCM - depends on DW_DMAC && AVR32 - help - ALSA sound driver for the Atmel Audio Bitstream DAC (ABDAC). - -config SND_ATMEL_AC97C - tristate "Atmel AC97 Controller (AC97C) driver" - select SND_PCM - select SND_AC97_CODEC - depends on (DW_DMAC && AVR32) || ARCH_AT91 - help - ALSA sound driver for the Atmel AC97 controller. - -endmenu diff --git a/src/linux/sound/core/Kconfig b/src/linux/sound/core/Kconfig deleted file mode 100644 index 9749f9e..0000000 --- a/src/linux/sound/core/Kconfig +++ /dev/null @@ -1,228 +0,0 @@ -# ALSA soundcard-configuration -config SND_TIMER - tristate - -config SND_PCM - tristate - select SND_TIMER if SND_PCM_TIMER - -config SND_PCM_ELD - bool - -config SND_PCM_IEC958 - bool - -config SND_DMAENGINE_PCM - tristate - -config SND_HWDEP - tristate - -config SND_RAWMIDI - tristate - -config SND_COMPRESS_OFFLOAD - tristate - -config SND_JACK - bool - -# enable input device support in jack layer -config SND_JACK_INPUT_DEV - bool - depends on SND_JACK - default y if INPUT=y || INPUT=SND - -config SND_SEQUENCER - tristate "Sequencer support" - select SND_TIMER - help - Say Y or M to enable MIDI sequencer and router support. This - feature allows routing and enqueueing of MIDI events. Events - can be processed at a given time. - - Many programs require this feature, so you should enable it - unless you know what you're doing. - -config SND_SEQ_DUMMY - tristate "Sequencer dummy client" - depends on SND_SEQUENCER - help - Say Y here to enable the dummy sequencer client. This client - is a simple MIDI-through client: all normal input events are - redirected to the output port immediately. - - You don't need this unless you want to connect many MIDI - devices or applications together. - - To compile this driver as a module, choose M here: the module - will be called snd-seq-dummy. - -config SND_OSSEMUL - select SOUND_OSS_CORE - bool - -config SND_MIXER_OSS - tristate "OSS Mixer API" - select SND_OSSEMUL - help - To enable OSS mixer API emulation (/dev/mixer*), say Y here - and read . - - Many programs still use the OSS API, so say Y. - - To compile this driver as a module, choose M here: the module - will be called snd-mixer-oss. - -config SND_PCM_OSS - tristate "OSS PCM (digital audio) API" - select SND_OSSEMUL - select SND_PCM - help - To enable OSS digital audio (PCM) emulation (/dev/dsp*), say Y - here and read . - - Many programs still use the OSS API, so say Y. - - To compile this driver as a module, choose M here: the module - will be called snd-pcm-oss. - -config SND_PCM_OSS_PLUGINS - bool "OSS PCM (digital audio) API - Include plugin system" - depends on SND_PCM_OSS - default y - help - If you disable this option, the ALSA's OSS PCM API will not - support conversion of channels, formats and rates. It will - behave like most of new OSS/Free drivers in 2.4/2.6 kernels. - -config SND_PCM_TIMER - bool "PCM timer interface" if EXPERT - default y - help - If you disable this option, pcm timer will be unavailable, so - those stubs that use pcm timer (e.g. dmix, dsnoop & co) may work - incorrectlly. - - For some embedded devices, we may disable it to reduce memory - footprint, about 20KB on x86_64 platform. - -config SND_SEQUENCER_OSS - bool "OSS Sequencer API" - depends on SND_SEQUENCER - select SND_OSSEMUL - help - Say Y here to enable OSS sequencer emulation (both - /dev/sequencer and /dev/music interfaces). - - Many programs still use the OSS API, so say Y. - - If you choose M in "Sequencer support" (SND_SEQUENCER), - this will be compiled as a module. The module will be called - snd-seq-oss. - -config SND_HRTIMER - tristate "HR-timer backend support" - depends on HIGH_RES_TIMERS - select SND_TIMER - help - Say Y here to enable HR-timer backend for ALSA timer. ALSA uses - the hrtimer as a precise timing source. The ALSA sequencer code - also can use this timing source. - - To compile this driver as a module, choose M here: the module - will be called snd-hrtimer. - -config SND_SEQ_HRTIMER_DEFAULT - bool "Use HR-timer as default sequencer timer" - depends on SND_HRTIMER && SND_SEQUENCER - default y - help - Say Y here to use the HR-timer backend as the default sequencer - timer. - -config SND_DYNAMIC_MINORS - bool "Dynamic device file minor numbers" - help - If you say Y here, the minor numbers of ALSA device files in - /dev/snd/ are allocated dynamically. This allows you to have - more than 8 sound cards, but requires a dynamic device file - system like udev. - - If you are unsure about this, say N here. - -config SND_MAX_CARDS - int "Max number of sound cards" - range 4 256 - default 32 - depends on SND_DYNAMIC_MINORS - help - Specify the max number of sound cards that can be assigned - on a single machine. - -config SND_SUPPORT_OLD_API - bool "Support old ALSA API" - default y - help - Say Y here to support the obsolete ALSA PCM API (ver.0.9.0 rc3 - or older). - -config SND_PROC_FS - bool "Sound Proc FS Support" if EXPERT - depends on PROC_FS - default y - help - Say 'N' to disable Sound proc FS, which may reduce code size about - 9KB on x86_64 platform. - If unsure say Y. - -config SND_VERBOSE_PROCFS - bool "Verbose procfs contents" - depends on SND_PROC_FS - default y - help - Say Y here to include code for verbose procfs contents (provides - useful information to developers when a problem occurs). On the - other side, it makes the ALSA subsystem larger. - -config SND_VERBOSE_PRINTK - bool "Verbose printk" - help - Say Y here to enable verbose log messages. These messages - will help to identify source file and position containing - printed messages. - - You don't need this unless you're debugging ALSA. - -config SND_DEBUG - bool "Debug" - help - Say Y here to enable ALSA debug code. - -config SND_DEBUG_VERBOSE - bool "More verbose debug" - depends on SND_DEBUG - help - Say Y here to enable extra-verbose debugging messages. - - Let me repeat: it enables EXTRA-VERBOSE DEBUGGING messages. - So, say Y only if you are ready to be annoyed. - -config SND_PCM_XRUN_DEBUG - bool "Enable PCM ring buffer overrun/underrun debugging" - default n - depends on SND_DEBUG && SND_VERBOSE_PROCFS - help - Say Y to enable the PCM ring buffer overrun/underrun debugging. - It is usually not required, but if you have trouble with - sound clicking when system is loaded, it may help to determine - the process or driver which causes the scheduling gaps. - -config SND_VMASTER - bool - -config SND_DMA_SGBUF - def_bool y - depends on X86 - -source "sound/core/seq/Kconfig" diff --git a/src/linux/sound/core/seq/Kconfig b/src/linux/sound/core/seq/Kconfig deleted file mode 100644 index b851fd8..0000000 --- a/src/linux/sound/core/seq/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -# define SND_XXX_SEQ to min(SND_SEQUENCER,SND_XXX) - -config SND_RAWMIDI_SEQ - def_tristate SND_SEQUENCER && SND_RAWMIDI - -config SND_OPL3_LIB_SEQ - def_tristate SND_SEQUENCER && SND_OPL3_LIB - -config SND_OPL4_LIB_SEQ - def_tristate SND_SEQUENCER && SND_OPL4_LIB - -config SND_SBAWE_SEQ - def_tristate SND_SEQUENCER && SND_SBAWE - -config SND_EMU10K1_SEQ - def_tristate SND_SEQUENCER && SND_EMU10K1 diff --git a/src/linux/sound/drivers/Kconfig b/src/linux/sound/drivers/Kconfig deleted file mode 100644 index 8545da9..0000000 --- a/src/linux/sound/drivers/Kconfig +++ /dev/null @@ -1,223 +0,0 @@ -config SND_MPU401_UART - tristate - select SND_RAWMIDI - -config SND_OPL3_LIB - tristate - select SND_TIMER - select SND_HWDEP - -config SND_OPL4_LIB - tristate - select SND_TIMER - select SND_HWDEP - -config SND_VX_LIB - tristate - select FW_LOADER - select SND_HWDEP - select SND_PCM - -config SND_AC97_CODEC - tristate - select SND_PCM - select AC97_BUS - select SND_VMASTER - -menuconfig SND_DRIVERS - bool "Generic sound devices" - default y - help - Support for generic sound devices. - -if SND_DRIVERS - -config SND_PCSP - tristate "PC-Speaker support (READ HELP!)" - depends on PCSPKR_PLATFORM && X86 && HIGH_RES_TIMERS - depends on INPUT - select SND_PCM - help - If you don't have a sound card in your computer, you can include a - driver for the PC speaker which allows it to act like a primitive - sound card. - This driver also replaces the pcspkr driver for beeps. - - You can compile this as a module which will be called snd-pcsp. - - WARNING: if you already have a soundcard, enabling this - driver may lead to a problem. Namely, it may get loaded - before the other sound driver of yours, making the - pc-speaker a default sound device. Which is likely not - what you want. To make this driver play nicely with other - sound driver, you can add this in a configuration file under - /etc/modprobe.d/ directory: - options snd-pcsp index=2 - - You don't need this driver if you only want your pc-speaker to beep. - You don't need this driver if you have a tablet piezo beeper - in your PC instead of the real speaker. - - Say N if you have a sound card. - Say M if you don't. - Say Y only if you really know what you do. - -config SND_DUMMY - tristate "Dummy (/dev/null) soundcard" - select SND_PCM - help - Say Y here to include the dummy driver. This driver does - nothing, but emulates various mixer controls and PCM devices. - - You don't need this unless you're testing the hardware support - of programs using the ALSA API. - - To compile this driver as a module, choose M here: the module - will be called snd-dummy. - -config SND_ALOOP - tristate "Generic loopback driver (PCM)" - select SND_PCM - help - Say 'Y' or 'M' to include support for the PCM loopback device. - This module returns played samples back to the user space using - the standard ALSA PCM device. The devices are routed 0->1 and - 1->0, where first number is the playback PCM device and second - number is the capture device. Module creates two PCM devices and - configured number of substreams (see the pcm_substreams module - parameter). - - The loopback device allows time sychronization with an external - timing source using the time shift universal control (+-20% - of system time). - - To compile this driver as a module, choose M here: the module - will be called snd-aloop. - -config SND_VIRMIDI - tristate "Virtual MIDI soundcard" - depends on SND_SEQUENCER - select SND_TIMER - select SND_RAWMIDI - help - Say Y here to include the virtual MIDI driver. This driver - allows to connect applications using raw MIDI devices to - sequencer clients. - - If you don't know what MIDI is, say N here. - - To compile this driver as a module, choose M here: the module - will be called snd-virmidi. - -config SND_MTPAV - tristate "MOTU MidiTimePiece AV multiport MIDI" - select SND_RAWMIDI - help - To use a MOTU MidiTimePiece AV multiport MIDI adapter - connected to the parallel port, say Y here and make sure that - the standard parallel port driver isn't used for the port. - - To compile this driver as a module, choose M here: the module - will be called snd-mtpav. - -config SND_MTS64 - tristate "ESI Miditerminal 4140 driver" - depends on PARPORT - select SND_RAWMIDI - help - The ESI Miditerminal 4140 is a 4 In 4 Out MIDI Interface with - additional SMPTE Timecode capabilities for the parallel port. - - Say 'Y' to include support for this device. - - To compile this driver as a module, chose 'M' here: the module - will be called snd-mts64. - -config SND_SERIAL_U16550 - tristate "UART16550 serial MIDI driver" - select SND_RAWMIDI - help - To include support for MIDI serial port interfaces, say Y here - and read . - This driver works with serial UARTs 16550 and better. - - This driver accesses the serial port hardware directly, so - make sure that the standard serial driver isn't used or - deactivated with setserial before loading this driver. - - To compile this driver as a module, choose M here: the module - will be called snd-serial-u16550. - -config SND_MPU401 - tristate "Generic MPU-401 UART driver" - select SND_MPU401_UART - help - Say Y here to include support for MIDI ports compatible with - the Roland MPU-401 interface in UART mode. - - To compile this driver as a module, choose M here: the module - will be called snd-mpu401. - -config SND_PORTMAN2X4 - tristate "Portman 2x4 driver" - depends on PARPORT - select SND_RAWMIDI - help - Say Y here to include support for Midiman Portman 2x4 parallel - port MIDI device. - - To compile this driver as a module, choose M here: the module - will be called snd-portman2x4. - -config SND_ML403_AC97CR - tristate "Xilinx ML403 AC97 Controller Reference" - depends on XILINX_VIRTEX - select SND_AC97_CODEC - help - Say Y here to include support for the - opb_ac97_controller_ref_v1_00_a ip core found in Xilinx's ML403 - reference design. - - To compile this driver as a module, choose M here: the module - will be called snd-ml403_ac97cr. - -config SND_AC97_POWER_SAVE - bool "AC97 Power-Saving Mode" - depends on SND_AC97_CODEC - default n - help - Say Y here to enable the aggressive power-saving support of - AC97 codecs. In this mode, the power-mode is dynamically - controlled at each open/close. - - The mode is activated by passing 'power_save=X' to the - snd-ac97-codec driver module, where 'X' is the time-out - value, a nonnegative integer that specifies how many - seconds of idle time the driver must count before it may - put the AC97 into power-save mode; a value of 0 (zero) - disables the use of this power-save mode. - - After the snd-ac97-codec driver module has been loaded, - the 'power_save' parameter can be set via sysfs as follows: - - echo 10 > /sys/module/snd_ac97_codec/parameters/power_save - - In this case, the time-out is set to 10 seconds; setting - the time-out to 1 second (the minimum activation value) - isn't recommended because many applications try to reopen - the device frequently. A value of 10 seconds would be a - good choice for normal operations. - - See Documentation/sound/alsa/powersave.txt for more details. - -config SND_AC97_POWER_SAVE_DEFAULT - int "Default time-out for AC97 power-save mode" - depends on SND_AC97_POWER_SAVE - default 0 - help - The default time-out value in seconds for AC97 automatic - power-save mode. 0 means to disable the power-save mode. - - See SND_AC97_POWER_SAVE for more details. - -endif # SND_DRIVERS diff --git a/src/linux/sound/firewire/Kconfig b/src/linux/sound/firewire/Kconfig deleted file mode 100644 index ab894ed..0000000 --- a/src/linux/sound/firewire/Kconfig +++ /dev/null @@ -1,142 +0,0 @@ -menuconfig SND_FIREWIRE - bool "FireWire sound devices" - depends on FIREWIRE - default y - help - Support for IEEE-1394/FireWire/iLink sound devices. - -if SND_FIREWIRE && FIREWIRE - -config SND_FIREWIRE_LIB - tristate - select SND_PCM - select SND_RAWMIDI - -config SND_DICE - tristate "DICE-based DACs support" - select SND_HWDEP - select SND_FIREWIRE_LIB - help - Say Y here to include support for many DACs based on the DICE - chip family (DICE-II/Jr/Mini) which TC Applied Technologies produces. - - To compile this driver as a module, choose M here: the module - will be called snd-dice. - -config SND_OXFW - tristate "Oxford Semiconductor FW970/971 chipset support" - select SND_FIREWIRE_LIB - select SND_HWDEP - help - Say Y here to include support for FireWire devices based on - Oxford Semiconductor FW970/971 chipset. - * Griffin Firewave - * LaCie Firewire Speakers - * Behringer F-Control Audio 202 - * Mackie(Loud) Onyx-i series (former models) - * Mackie(Loud) Onyx Satellite - * Mackie(Loud) Tapco Link.Firewire - * Mackie(Loud) d.2 pro/d.4 pro - * Mackie(Loud) U.420/U.420d - * TASCAM FireOne - * Stanton Controllers & Systems 1 Deck/Mixer - - To compile this driver as a module, choose M here: the module - will be called snd-oxfw. - -config SND_ISIGHT - tristate "Apple iSight microphone" - select SND_FIREWIRE_LIB - help - Say Y here to include support for the front and rear microphones - of the Apple iSight web camera. - - To compile this driver as a module, choose M here: the module - will be called snd-isight. - -config SND_FIREWORKS - tristate "Echo Fireworks board module support" - select SND_FIREWIRE_LIB - select SND_HWDEP - help - Say Y here to include support for FireWire devices based - on Echo Digital Audio Fireworks board: - * Mackie Onyx 400F/1200F - * Echo AudioFire12/8(until 2009 July) - * Echo AudioFire2/4/Pre8/8(since 2009 July) - * Echo Fireworks 8/HDMI - * Gibson Robot Interface Pack/GoldTop - - To compile this driver as a module, choose M here: the module - will be called snd-fireworks. - -config SND_BEBOB - tristate "BridgeCo DM1000/DM1100/DM1500 with BeBoB firmware" - select SND_FIREWIRE_LIB - select SND_HWDEP - help - Say Y here to include support for FireWire devices based - on BridgeCo DM1000/DM1100/DM1500 with BeBoB firmware: - * Edirol FA-66/FA-101 - * PreSonus FIREBOX/FIREPOD/FP10/Inspire1394 - * BridgeCo RDAudio1/Audio5 - * Mackie Onyx 1220/1620/1640 (FireWire I/O Card) - * Mackie d.2 (FireWire Option) - * Stanton FinalScratch 2 (ScratchAmp) - * Tascam IF-FW/DM - * Behringer XENIX UFX 1204/1604 - * Behringer Digital Mixer X32 series (X-UF Card) - * Behringer FCA610/1616 - * Apogee Rosetta 200/400 (X-FireWire card) - * Apogee DA/AD/DD-16X (X-FireWire card) - * Apogee Ensemble - * ESI QuataFire 610 - * AcousticReality eARMasterOne - * CME MatrixKFW - * Phonic Helix Board 12 MkII/18 MkII/24 MkII - * Phonic Helix Board 12 Universal/18 Universal/24 Universal - * Lynx Aurora 8/16 (LT-FW) - * ICON FireXon - * PrismSound Orpheus/ADA-8XR - * TerraTec PHASE 24 FW/PHASE X24 FW/PHASE 88 Rack FW - * TerraTec EWS MIC2/EWS MIC8 - * TerraTec Aureon 7.1 FireWire - * Yamaha GO44/GO46 - * Focusrite Saffire/Saffire LE/SaffirePro10 IO/SaffirePro26 IO - * M-Audio FireWire410/AudioPhile/Solo - * M-Audio Ozonic/NRV10/ProfireLightBridge - * M-Audio FireWire 1814/ProjectMix IO - * Digidesign Mbox 2 Pro - - To compile this driver as a module, choose M here: the module - will be called snd-bebob. - -config SND_FIREWIRE_DIGI00X - tristate "Digidesign Digi 002/003 family support" - select SND_FIREWIRE_LIB - select SND_HWDEP - help - Say Y here to include support for Digidesign Digi 002/003 family. - * Digi 002 Console - * Digi 002 Rack - * Digi 003 Console - * Digi 003 Rack - * Digi 003 Rack+ - - To compile this driver as a module, choose M here: the module - will be called snd-firewire-digi00x. - -config SND_FIREWIRE_TASCAM - tristate "TASCAM FireWire series support" - select SND_FIREWIRE_LIB - select SND_HWDEP - help - Say Y here to include support for TASCAM. - * FW-1884 - * FW-1082 - * FW-1804 - - To compile this driver as a module, choose M here: the module - will be called snd-firewire-tascam. - -endif # SND_FIREWIRE diff --git a/src/linux/sound/hda/Kconfig b/src/linux/sound/hda/Kconfig deleted file mode 100644 index 3129546..0000000 --- a/src/linux/sound/hda/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -config SND_HDA_CORE - tristate - select REGMAP - -config SND_HDA_DSP_LOADER - bool - -config SND_HDA_I915 - bool - default y - depends on DRM_I915 - depends on SND_HDA_CORE - -config SND_HDA_EXT_CORE - tristate - select SND_HDA_CORE - -config SND_HDA_PREALLOC_SIZE - int "Pre-allocated buffer size for HD-audio driver" - range 0 32768 - default 64 - help - Specifies the default pre-allocated buffer-size in kB for the - HD-audio driver. A larger buffer (e.g. 2048) is preferred - for systems using PulseAudio. The default 64 is chosen just - for compatibility reasons. - - Note that the pre-allocation size can be changed dynamically - via a proc file (/proc/asound/card*/pcm*/sub*/prealloc), too. diff --git a/src/linux/sound/isa/Kconfig b/src/linux/sound/isa/Kconfig deleted file mode 100644 index 37adcc6..0000000 --- a/src/linux/sound/isa/Kconfig +++ /dev/null @@ -1,462 +0,0 @@ -# ALSA ISA drivers - -config SND_WSS_LIB - tristate - select SND_PCM - select SND_TIMER - -config SND_SB_COMMON - tristate - -config SND_SB8_DSP - tristate - select SND_PCM - select SND_SB_COMMON - -config SND_SB16_DSP - tristate - select SND_PCM - select SND_SB_COMMON - -menuconfig SND_ISA - bool "ISA sound devices" - depends on ISA && ISA_DMA_API - default y - help - Support for sound devices connected via the ISA bus. - -if SND_ISA - -config SND_ADLIB - tristate "AdLib FM card" - select SND_OPL3_LIB - help - Say Y here to include support for AdLib FM cards. - - To compile this driver as a module, choose M here: the module - will be called snd-adlib. - -config SND_AD1816A - tristate "Analog Devices SoundPort AD1816A" - depends on PNP - select ISAPNP - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_PCM - select SND_TIMER - help - Say Y here to include support for Analog Devices SoundPort - AD1816A or compatible sound chips. - - To compile this driver as a module, choose M here: the module - will be called snd-ad1816a. - -config SND_AD1848 - tristate "Generic AD1848/CS4248 driver" - select SND_WSS_LIB - help - Say Y here to include support for AD1848 (Analog Devices) or - CS4248 (Cirrus Logic - Crystal Semiconductors) chips. - - For newer chips from Cirrus Logic, use the CS4231 or CS4232+ - drivers. - - To compile this driver as a module, choose M here: the module - will be called snd-ad1848. - -config SND_ALS100 - tristate "Diamond Tech. DT-019x and Avance Logic ALSxxx" - depends on PNP - select ISAPNP - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_SB16_DSP - help - Say Y here to include support for soundcards based on the - Diamond Technologies DT-019X or Avance Logic chips: ALS007, - ALS100, ALS110, ALS120 and ALS200 chips. - - To compile this driver as a module, choose M here: the module - will be called snd-als100. - -config SND_AZT1605 - tristate "Aztech AZT1605 Driver" - depends on SND - select SND_WSS_LIB - select SND_MPU401_UART - select SND_OPL3_LIB - help - Say Y here to include support for Aztech Sound Galaxy cards - based on the AZT1605 chipset. - - To compile this driver as a module, choose M here: the module - will be called snd-azt1605. - -config SND_AZT2316 - tristate "Aztech AZT2316 Driver" - depends on SND - select SND_WSS_LIB - select SND_MPU401_UART - select SND_OPL3_LIB - help - Say Y here to include support for Aztech Sound Galaxy cards - based on the AZT2316 chipset. - - To compile this driver as a module, choose M here: the module - will be called snd-azt2316. - -config SND_AZT2320 - tristate "Aztech Systems AZT2320" - depends on PNP - select ISAPNP - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_WSS_LIB - help - Say Y here to include support for soundcards based on the - Aztech Systems AZT2320 chip. - - To compile this driver as a module, choose M here: the module - will be called snd-azt2320. - -config SND_CMI8328 - tristate "C-Media CMI8328" - select SND_WSS_LIB - select SND_OPL3_LIB - select SND_MPU401_UART - help - Say Y here to include support for soundcards based on the - C-Media CMI8328 chip. - - To compile this driver as a module, choose M here: the module - will be called snd-cmi8328. - -config SND_CMI8330 - tristate "C-Media CMI8330" - select SND_WSS_LIB - select SND_SB16_DSP - select SND_OPL3_LIB - select SND_MPU401_UART - help - Say Y here to include support for soundcards based on the - C-Media CMI8330 chip. - - To compile this driver as a module, choose M here: the module - will be called snd-cmi8330. - -config SND_CS4231 - tristate "Generic Cirrus Logic CS4231 driver" - select SND_MPU401_UART - select SND_WSS_LIB - help - Say Y here to include support for CS4231 chips from Cirrus - Logic - Crystal Semiconductors. - - To compile this driver as a module, choose M here: the module - will be called snd-cs4231. - -config SND_CS4236 - tristate "Generic Cirrus Logic CS4232/CS4236+ driver" - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_WSS_LIB - help - Say Y to include support for CS4232,CS4235,CS4236,CS4237B, - CS4238B,CS4239 chips from Cirrus Logic - Crystal - Semiconductors. - - To compile this driver as a module, choose M here: the module - will be called snd-cs4236. - -config SND_ES1688 - tristate "Generic ESS ES688/ES1688 and ES968 PnP driver" - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_PCM - help - Say Y here to include support for ESS AudioDrive ES688 or - ES1688 chips. Also, this module support cards with ES968 PnP chip. - - To compile this driver as a module, choose M here: the module - will be called snd-es1688. - -config SND_ES18XX - tristate "Generic ESS ES18xx driver" - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_PCM - help - Say Y here to include support for ESS AudioDrive ES18xx chips. - - To compile this driver as a module, choose M here: the module - will be called snd-es18xx. - -config SND_SC6000 - tristate "Gallant SC-6000/6600/7000 and Audio Excel DSP 16" - depends on HAS_IOPORT_MAP - select SND_WSS_LIB - select SND_OPL3_LIB - select SND_MPU401_UART - help - Say Y here to include support for Gallant SC-6000, SC-6600, SC-7000 - cards and clones: - Audio Excel DSP 16 and Zoltrix AV302. - - These cards are based on CompuMedia ASC-9308 or ASC-9408 chips. - - To compile this driver as a module, choose M here: the module - will be called snd-sc6000. - -config SND_GUSCLASSIC - tristate "Gravis UltraSound Classic" - select SND_RAWMIDI - select SND_PCM - select SND_TIMER - help - Say Y here to include support for Gravis UltraSound Classic - soundcards. - - To compile this driver as a module, choose M here: the module - will be called snd-gusclassic. - -config SND_GUSEXTREME - tristate "Gravis UltraSound Extreme" - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_PCM - select SND_TIMER - help - Say Y here to include support for Gravis UltraSound Extreme - soundcards. - - To compile this driver as a module, choose M here: the module - will be called snd-gusextreme. - -config SND_GUSMAX - tristate "Gravis UltraSound MAX" - select SND_RAWMIDI - select SND_WSS_LIB - help - Say Y here to include support for Gravis UltraSound MAX - soundcards. - - To compile this driver as a module, choose M here: the module - will be called snd-gusmax. - -config SND_INTERWAVE - tristate "AMD InterWave, Gravis UltraSound PnP" - depends on PNP - select SND_RAWMIDI - select SND_WSS_LIB - help - Say Y here to include support for AMD InterWave based - soundcards (Gravis UltraSound Plug & Play, STB SoundRage32, - MED3210, Dynasonic Pro, Panasonic PCA761AW). - - To compile this driver as a module, choose M here: the module - will be called snd-interwave. - -config SND_INTERWAVE_STB - tristate "AMD InterWave + TEA6330T (UltraSound 32-Pro)" - depends on PNP - select SND_RAWMIDI - select SND_WSS_LIB - help - Say Y here to include support for AMD InterWave based - soundcards with a TEA6330T bass and treble regulator - (UltraSound 32-Pro). - - To compile this driver as a module, choose M here: the module - will be called snd-interwave-stb. - -config SND_JAZZ16 - tristate "Media Vision Jazz16 card and compatibles" - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_SB8_DSP - help - Say Y here to include support for soundcards based on the - Media Vision Jazz16 chipset: digital chip MVD1216 (Jazz16), - codec MVA416 (CS4216) and mixer MVA514 (ICS2514). - Media Vision's Jazz16 cards were sold under names Pro Sonic 16, - Premium 3-D and Pro 3-D. There were also OEMs cards with the - Jazz16 chipset. - - To compile this driver as a module, choose M here: the module - will be called snd-jazz16. - -config SND_OPL3SA2 - tristate "Yamaha OPL3-SA2/SA3" - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_WSS_LIB - help - Say Y here to include support for Yamaha OPL3-SA2 and OPL3-SA3 - chips. - - To compile this driver as a module, choose M here: the module - will be called snd-opl3sa2. - -config SND_OPTI92X_AD1848 - tristate "OPTi 82C92x - AD1848" - select SND_OPL3_LIB - select SND_OPL4_LIB - select SND_MPU401_UART - select SND_WSS_LIB - help - Say Y here to include support for soundcards based on Opti - 82C92x or OTI-601 chips and using an AD1848 codec. - - To compile this driver as a module, choose M here: the module - will be called snd-opti92x-ad1848. - -config SND_OPTI92X_CS4231 - tristate "OPTi 82C92x - CS4231" - select SND_OPL3_LIB - select SND_OPL4_LIB - select SND_MPU401_UART - select SND_WSS_LIB - help - Say Y here to include support for soundcards based on Opti - 82C92x chips and using a CS4231 codec. - - To compile this driver as a module, choose M here: the module - will be called snd-opti92x-cs4231. - -config SND_OPTI93X - tristate "OPTi 82C93x" - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_WSS_LIB - help - Say Y here to include support for soundcards based on Opti - 82C93x chips. - - To compile this driver as a module, choose M here: the module - will be called snd-opti93x. - -config SND_MIRO - tristate "Miro miroSOUND PCM1pro/PCM12/PCM20radio driver" - select SND_OPL4_LIB - select SND_WSS_LIB - select SND_MPU401_UART - select SND_PCM - help - Say 'Y' or 'M' to include support for Miro miroSOUND PCM1 pro, - miroSOUND PCM12 and miroSOUND PCM20 Radio soundcards. - - To compile this driver as a module, choose M here: the module - will be called snd-miro. - -config SND_SB8 - tristate "Sound Blaster 1.0/2.0/Pro (8-bit)" - select SND_OPL3_LIB - select SND_RAWMIDI - select SND_SB8_DSP - help - Say Y here to include support for Creative Sound Blaster 1.0/ - 2.0/Pro (8-bit) or 100% compatible soundcards. - - To compile this driver as a module, choose M here: the module - will be called snd-sb8. - -config SND_SB16 - tristate "Sound Blaster 16 (PnP)" - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_SB16_DSP - help - Say Y here to include support for Sound Blaster 16 soundcards - (including the Plug and Play version). - - To compile this driver as a module, choose M here: the module - will be called snd-sb16. - -config SND_SBAWE - tristate "Sound Blaster AWE (32,64) (PnP)" - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_SB16_DSP - help - Say Y here to include support for Sound Blaster AWE soundcards - (including the Plug and Play version). - - To compile this driver as a module, choose M here: the module - will be called snd-sbawe. - -config SND_SB16_CSP - bool "Sound Blaster 16/AWE CSP support" - depends on (SND_SB16 || SND_SBAWE) && (BROKEN || !PPC) - select FW_LOADER - help - Say Y here to include support for the CSP core. This special - coprocessor can do variable tasks like various compression and - decompression algorithms. - -config SND_SSCAPE - tristate "Ensoniq SoundScape driver" - select SND_MPU401_UART - select SND_WSS_LIB - select FW_LOADER - help - Say Y here to include support for Ensoniq SoundScape - and Ensoniq OEM soundcards. - - The PCM audio is supported on SoundScape Classic, Elite, PnP - and VIVO cards. The supported OEM cards are SPEA Media FX and - Reveal SC-600. - The MIDI support is very experimental and requires binary - firmware files called "scope.cod" and "sndscape.co?" where the - ? is digit 0, 1, 2, 3 or 4. The firmware files can be found - in DOS or Windows driver packages. One has to put the firmware - files into the /lib/firmware directory. - - To compile this driver as a module, choose M here: the module - will be called snd-sscape. - -config SND_WAVEFRONT - tristate "Turtle Beach Maui,Tropez,Tropez+ (Wavefront)" - select FW_LOADER - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_WSS_LIB - help - Say Y here to include support for Turtle Beach Maui, Tropez - and Tropez+ soundcards based on the Wavefront chip. - - To compile this driver as a module, choose M here: the module - will be called snd-wavefront. - -config SND_MSND_PINNACLE - tristate "Turtle Beach MultiSound Pinnacle/Fiji driver" - depends on X86 - select FW_LOADER - select SND_MPU401_UART - select SND_PCM - help - Say Y to include support for Turtle Beach MultiSound Pinnacle/ - Fiji soundcards. - - To compile this driver as a module, choose M here: the module - will be called snd-msnd-pinnacle. - -config SND_MSND_CLASSIC - tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey" - depends on X86 - select FW_LOADER - select SND_MPU401_UART - select SND_PCM - help - Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or - Monterey (not for the Pinnacle or Fiji). - - See for important information - about this driver. Note that it has been discontinued, but the - Voyetra Turtle Beach knowledge base entry for it is still available - at . - - To compile this driver as a module, choose M here: the module - will be called snd-msnd-classic. - -endif # SND_ISA - diff --git a/src/linux/sound/mips/Kconfig b/src/linux/sound/mips/Kconfig deleted file mode 100644 index 4a47050..0000000 --- a/src/linux/sound/mips/Kconfig +++ /dev/null @@ -1,27 +0,0 @@ -# ALSA MIPS drivers - -menuconfig SND_MIPS - bool "MIPS sound devices" - depends on MIPS - default y - help - Support for sound devices of MIPS architectures. - -if SND_MIPS - -config SND_SGI_O2 - tristate "SGI O2 Audio" - depends on SGI_IP32 - select SND_PCM - help - Sound support for the SGI O2 Workstation. - -config SND_SGI_HAL2 - tristate "SGI HAL2 Audio" - depends on SGI_HAS_HAL2 - select SND_PCM - help - Sound support for the SGI Indy and Indigo2 Workstation. - -endif # SND_MIPS - diff --git a/src/linux/sound/oss/.gitignore b/src/linux/sound/oss/.gitignore deleted file mode 100644 index 12a3920..0000000 --- a/src/linux/sound/oss/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -#Ignore generated files -pss_boot.h -trix_boot.h diff --git a/src/linux/sound/oss/Kconfig b/src/linux/sound/oss/Kconfig deleted file mode 100644 index 4033fe5..0000000 --- a/src/linux/sound/oss/Kconfig +++ /dev/null @@ -1,533 +0,0 @@ -# 18 Apr 1998, Michael Elizabeth Chastain, -# More hacking for modularisation. -# -# Prompt user for primary drivers. - -config SOUND_BCM_CS4297A - tristate "Crystal Sound CS4297a (for Swarm)" - depends on SIBYTE_SWARM - help - The BCM91250A has a Crystal CS4297a on synchronous serial - port B (in addition to the DB-9 serial port). Say Y or M - here to enable the sound chip instead of the UART. Also - note that CONFIG_KGDB should not be enabled at the same - time, since it also attempts to use this UART port. - -config SOUND_MSNDCLAS - tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey" - depends on (m || !STANDALONE) && ISA - help - Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or - Monterey (not for the Pinnacle or Fiji). - - See for important information - about this driver. Note that it has been discontinued, but the - Voyetra Turtle Beach knowledge base entry for it is still available - at . - -comment "Compiled-in MSND Classic support requires firmware during compilation." - depends on SOUND_PRIME && SOUND_MSNDCLAS=y - -config MSNDCLAS_HAVE_BOOT - bool - depends on SOUND_MSNDCLAS=y && !STANDALONE - default y - -config MSNDCLAS_INIT_FILE - string "Full pathname of MSNDINIT.BIN firmware file" - depends on SOUND_MSNDCLAS - default "/etc/sound/msndinit.bin" - help - The MultiSound cards have two firmware files which are required for - operation, and are not currently included. These files can be - obtained from Turtle Beach. See - for information on how to - obtain this. - -config MSNDCLAS_PERM_FILE - string "Full pathname of MSNDPERM.BIN firmware file" - depends on SOUND_MSNDCLAS - default "/etc/sound/msndperm.bin" - help - The MultiSound cards have two firmware files which are required for - operation, and are not currently included. These files can be - obtained from Turtle Beach. See - for information on how to - obtain this. - -config MSNDCLAS_IRQ - int "MSND Classic IRQ 5, 7, 9, 10, 11, 12" - depends on SOUND_MSNDCLAS=y - default "5" - help - Interrupt Request line for the MultiSound Classic and related cards. - -config MSNDCLAS_MEM - hex "MSND Classic memory B0000, C8000, D0000, D8000, E0000, E8000" - depends on SOUND_MSNDCLAS=y - default "D0000" - help - Memory-mapped I/O base address for the MultiSound Classic and - related cards. - -config MSNDCLAS_IO - hex "MSND Classic I/O 210, 220, 230, 240, 250, 260, 290, 3E0" - depends on SOUND_MSNDCLAS=y - default "290" - help - I/O port address for the MultiSound Classic and related cards. - -config SOUND_MSNDPIN - tristate "Support for Turtle Beach MultiSound Pinnacle, Fiji" - depends on (m || !STANDALONE) && ISA - help - Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji. - See for important information - about this driver. Note that it has been discontinued, but the - Voyetra Turtle Beach knowledge base entry for it is still available - at . - -comment "Compiled-in MSND Pinnacle support requires firmware during compilation." - depends on SOUND_PRIME && SOUND_MSNDPIN=y - -config MSNDPIN_HAVE_BOOT - bool - depends on SOUND_MSNDPIN=y - default y - -config MSNDPIN_INIT_FILE - string "Full pathname of PNDSPINI.BIN firmware file" - depends on SOUND_MSNDPIN - default "/etc/sound/pndspini.bin" - help - The MultiSound cards have two firmware files which are required - for operation, and are not currently included. These files can be - obtained from Turtle Beach. See - for information on how to - obtain this. - -config MSNDPIN_PERM_FILE - string "Full pathname of PNDSPERM.BIN firmware file" - depends on SOUND_MSNDPIN - default "/etc/sound/pndsperm.bin" - help - The MultiSound cards have two firmware files which are required for - operation, and are not currently included. These files can be - obtained from Turtle Beach. See - for information on how to - obtain this. - -config MSNDPIN_IRQ - int "MSND Pinnacle IRQ 5, 7, 9, 10, 11, 12" - depends on SOUND_MSNDPIN=y - default "5" - help - Interrupt request line for the primary synthesizer on MultiSound - Pinnacle and Fiji sound cards. - -config MSNDPIN_MEM - hex "MSND Pinnacle memory B0000, C8000, D0000, D8000, E0000, E8000" - depends on SOUND_MSNDPIN=y - default "D0000" - help - Memory-mapped I/O base address for the primary synthesizer on - MultiSound Pinnacle and Fiji sound cards. - -config MSNDPIN_IO - hex "MSND Pinnacle I/O 210, 220, 230, 240, 250, 260, 290, 3E0" - depends on SOUND_MSNDPIN=y - default "290" - help - Memory-mapped I/O base address for the primary synthesizer on - MultiSound Pinnacle and Fiji sound cards. - -config MSNDPIN_DIGITAL - bool "MSND Pinnacle has S/PDIF I/O" - depends on SOUND_MSNDPIN=y - help - If you have the S/PDIF daughter board for the Pinnacle or Fiji, - answer Y here; otherwise, say N. If you have this, you will be able - to play and record from the S/PDIF port (digital signal). See - for information on how to make - use of this capability. - -config MSNDPIN_NONPNP - bool "MSND Pinnacle non-PnP Mode" - depends on SOUND_MSNDPIN=y - help - The Pinnacle and Fiji card resources can be configured either with - PnP, or through a configuration port. Say Y here if your card is NOT - in PnP mode. For the Pinnacle, configuration in non-PnP mode allows - use of the IDE and joystick peripherals on the card as well; these - do not show up when the card is in PnP mode. Specifying zero for any - resource of a device will disable the device. If you are running the - card in PnP mode, you must say N here and use isapnptools to - configure the card's resources. - -comment "MSND Pinnacle DSP section will be configured to above parameters." - depends on SOUND_MSNDPIN=y && MSNDPIN_NONPNP - -config MSNDPIN_CFG - hex "MSND Pinnacle config port 250,260,270" - depends on MSNDPIN_NONPNP - default "250" - help - This is the port which the Pinnacle and Fiji uses to configure the - card's resources when not in PnP mode. If your card is in PnP mode, - then be sure to say N to the previous option, "MSND Pinnacle Non-PnP - Mode". - -comment "Pinnacle-specific Device Configuration (0 disables)" - depends on SOUND_MSNDPIN=y && MSNDPIN_NONPNP - -config MSNDPIN_MPU_IO - hex "MSND Pinnacle MPU I/O (e.g. 330)" - depends on MSNDPIN_NONPNP - default "0" - help - Memory-mapped I/O base address for the Kurzweil daughterboard - synthesizer on MultiSound Pinnacle and Fiji sound cards. - -config MSNDPIN_MPU_IRQ - int "MSND Pinnacle MPU IRQ (e.g. 9)" - depends on MSNDPIN_NONPNP - default "0" - help - Interrupt request number for the Kurzweil daughterboard - synthesizer on MultiSound Pinnacle and Fiji sound cards. - -config MSNDPIN_IDE_IO0 - hex "MSND Pinnacle IDE I/O 0 (e.g. 170)" - depends on MSNDPIN_NONPNP - default "0" - help - CD-ROM drive 0 memory-mapped I/O base address for the MultiSound - Pinnacle and Fiji sound cards. - -config MSNDPIN_IDE_IO1 - hex "MSND Pinnacle IDE I/O 1 (e.g. 376)" - depends on MSNDPIN_NONPNP - default "0" - help - CD-ROM drive 1 memory-mapped I/O base address for the MultiSound - Pinnacle and Fiji sound cards. - -config MSNDPIN_IDE_IRQ - int "MSND Pinnacle IDE IRQ (e.g. 15)" - depends on MSNDPIN_NONPNP - default "0" - help - Interrupt request number for the IDE CD-ROM interface on the - MultiSound Pinnacle and Fiji sound cards. - -config MSNDPIN_JOYSTICK_IO - hex "MSND Pinnacle joystick I/O (e.g. 200)" - depends on MSNDPIN_NONPNP - default "0" - help - Memory-mapped I/O base address for the joystick port on MultiSound - Pinnacle and Fiji sound cards. - -config MSND_FIFOSIZE - int "MSND buffer size (kB)" - depends on SOUND_MSNDPIN=y || SOUND_MSNDCLAS=y - default "128" - help - Configures the size of each audio buffer, in kilobytes, for - recording and playing in the MultiSound drivers (both the Classic - and Pinnacle). Larger values reduce the chance of data overruns at - the expense of overall latency. If unsure, use the default. - -menuconfig SOUND_OSS - tristate "OSS sound modules" - depends on ISA_DMA_API && (VIRT_TO_BUS || ARCH_RPC || ARCH_NETWINDER) - depends on !GENERIC_ISA_DMA_SUPPORT_BROKEN - help - OSS is the Open Sound System suite of sound card drivers. They make - sound programming easier since they provide a common API. Say Y or - M here (the module will be called sound) if you haven't found a - driver for your sound card above, then pick your driver from the - list below. - -if SOUND_OSS - -config SOUND_TRACEINIT - bool "Verbose initialisation" - help - Verbose soundcard initialization -- affects the format of autoprobe - and initialization messages at boot time. - -config SOUND_DMAP - bool "Persistent DMA buffers" - ---help--- - Linux can often have problems allocating DMA buffers for ISA sound - cards on machines with more than 16MB of RAM. This is because ISA - DMA buffers must exist below the 16MB boundary and it is quite - possible that a large enough free block in this region cannot be - found after the machine has been running for a while. If you say Y - here the DMA buffers (64Kb) will be allocated at boot time and kept - until the shutdown. This option is only useful if you said Y to - "OSS sound modules", above. If you said M to "OSS sound modules" - then you can get the persistent DMA buffer functionality by passing - the command-line argument "dmabuf=1" to the sound module. - - Say Y unless you have 16MB or more RAM or a PCI sound card. - -config SOUND_VMIDI - tristate "Loopback MIDI device support" - help - Support for MIDI loopback on port 1 or 2. - -config SOUND_TRIX - tristate "MediaTrix AudioTrix Pro support" - help - Answer Y if you have the AudioTriX Pro sound card manufactured - by MediaTrix. - -config TRIX_HAVE_BOOT - bool "Have TRXPRO.HEX firmware file" - depends on SOUND_TRIX=y && !STANDALONE - help - The MediaTrix AudioTrix Pro has an on-board microcontroller which - needs to be initialized by downloading the code from the file - TRXPRO.HEX in the DOS driver directory. If you don't have the - TRXPRO.HEX file handy you may skip this step. However, the SB and - MPU-401 modes of AudioTrix Pro will not work without this file! - -config TRIX_BOOT_FILE - string "Full pathname of TRXPRO.HEX firmware file" - depends on TRIX_HAVE_BOOT - default "/etc/sound/trxpro.hex" - help - Enter the full pathname of your TRXPRO.HEX file, starting from /. - -config SOUND_MSS - tristate "Microsoft Sound System support" - ---help--- - Again think carefully before answering Y to this question. It's - safe to answer Y if you have the original Windows Sound System card - made by Microsoft or Aztech SG 16 Pro (or NX16 Pro). Also you may - say Y in case your card is NOT among these: - - ATI Stereo F/X, AdLib, Audio Excell DSP16, Cardinal DSP16, - Ensoniq SoundScape (and compatibles made by Reveal and Spea), - Gravis Ultrasound, Gravis Ultrasound ACE, Gravis Ultrasound Max, - Gravis Ultrasound with 16 bit option, Logitech Sound Man 16, - Logitech SoundMan Games, Logitech SoundMan Wave, MAD16 Pro (OPTi - 82C929), Media Vision Jazz16, MediaTriX AudioTriX Pro, Microsoft - Windows Sound System (MSS/WSS), Mozart (OAK OTI-601), Orchid - SW32, Personal Sound System (PSS), Pro Audio Spectrum 16, Pro - Audio Studio 16, Pro Sonic 16, Roland MPU-401 MIDI interface, - Sound Blaster 1.0, Sound Blaster 16, Sound Blaster 16ASP, Sound - Blaster 2.0, Sound Blaster AWE32, Sound Blaster Pro, TI TM4000M - notebook, ThunderBoard, Turtle Beach Tropez, Yamaha FM - synthesizers (OPL2, OPL3 and OPL4), 6850 UART MIDI Interface. - - For cards having native support in VoxWare, consult the card - specific instructions in . - Some drivers have their own MSS support and saying Y to this option - will cause a conflict. - - If you compile the driver into the kernel, you have to add - "ad1848=,,,[,]" to the kernel command - line. - -config SOUND_MPU401 - tristate "MPU-401 support (NOT for SB16)" - ---help--- - Be careful with this question. The MPU401 interface is supported by - all sound cards. However, some natively supported cards have their - own driver for MPU401. Enabling this MPU401 option with these cards - will cause a conflict. Also, enabling MPU401 on a system that - doesn't really have a MPU401 could cause some trouble. If your card - was in the list of supported cards, look at the card specific - instructions in the file. It - is safe to answer Y if you have a true MPU401 MIDI interface card. - - If you compile the driver into the kernel, you have to add - "mpu401=," to the kernel command line. - -config SOUND_PAS - tristate "ProAudioSpectrum 16 support" - ---help--- - Answer Y only if you have a Pro Audio Spectrum 16, ProAudio Studio - 16 or Logitech SoundMan 16 sound card. Answer N if you have some - other card made by Media Vision or Logitech since those are not - PAS16 compatible. Please read . - It is not necessary to add Sound Blaster support separately; it - is included in PAS support. - - If you compile the driver into the kernel, you have to add - "pas2=,,,,,,, - to the kernel command line. - -config PAS_JOYSTICK - bool "Enable PAS16 joystick port" - depends on SOUND_PAS=y - help - Say Y here to enable the Pro Audio Spectrum 16's auxiliary joystick - port. - -config SOUND_PSS - tristate "PSS (AD1848, ADSP-2115, ESC614) support" - help - Answer Y or M if you have an Orchid SW32, Cardinal DSP16, Beethoven - ADSP-16 or some other card based on the PSS chipset (AD1848 codec + - ADSP-2115 DSP chip + Echo ESC614 ASIC CHIP). For more information on - how to compile it into the kernel or as a module see the file - . - - If you compile the driver into the kernel, you have to add - "pss=,,,,," to the kernel - command line. - -config PSS_MIXER - bool "Enable PSS mixer (Beethoven ADSP-16 and other compatible)" - depends on SOUND_PSS - help - Answer Y for Beethoven ADSP-16. You may try to say Y also for other - cards if they have master volume, bass, treble, and you can't - control it under Linux. If you answer N for Beethoven ADSP-16, you - can't control master volume, bass, treble and synth volume. - - If you said M to "PSS support" above, you may enable or disable this - PSS mixer with the module parameter pss_mixer. For more information - see the file . - -config PSS_HAVE_BOOT - bool "Have DSPxxx.LD firmware file" - depends on SOUND_PSS && !STANDALONE - help - If you have the DSPxxx.LD file or SYNTH.LD file for you card, say Y - to include this file. Without this file the synth device (OPL) may - not work. - -config PSS_BOOT_FILE - string "Full pathname of DSPxxx.LD firmware file" - depends on PSS_HAVE_BOOT - default "/etc/sound/dsp001.ld" - help - Enter the full pathname of your DSPxxx.LD file or SYNTH.LD file, - starting from /. - -config SOUND_SB - tristate "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support" - ---help--- - Answer Y if you have an original Sound Blaster card made by Creative - Labs or a 100% hardware compatible clone (like the Thunderboard or - SM Games). For an unknown card you may answer Y if the card claims - to be Sound Blaster-compatible. - - Please read the file . - - You should also say Y here for cards based on the Avance Logic - ALS-007 and ALS-1X0 chips (read ) and - for cards based on ESS chips (read - and - ). If you have an IBM Mwave - card, say Y here and read . - - If you compile the driver into the kernel and don't want to use - isapnp, you have to add "sb=,,," to the kernel - command line. - - You can say M here to compile this driver as a module; the module is - called sb. - -config SOUND_YM3812 - tristate "Yamaha FM synthesizer (YM3812/OPL-3) support" - ---help--- - Answer Y if your card has a FM chip made by Yamaha (OPL2/OPL3/OPL4). - Answering Y is usually a safe and recommended choice, however some - cards may have software (TSR) FM emulation. Enabling FM support with - these cards may cause trouble (I don't currently know of any such - cards, however). Please read the file - if your card has an OPL3 chip. - - If you compile the driver into the kernel, you have to add - "opl3=" to the kernel command line. - - If unsure, say Y. - -config SOUND_UART6850 - tristate "6850 UART support" - help - This option enables support for MIDI interfaces based on the 6850 - UART chip. This interface is rarely found on sound cards. It's safe - to answer N to this question. - - If you compile the driver into the kernel, you have to add - "uart6850=," to the kernel command line. - -config SOUND_AEDSP16 - tristate "Gallant Audio Cards (SC-6000 and SC-6600 based)" - ---help--- - Answer Y if you have a Gallant's Audio Excel DSP 16 card. This - driver supports Audio Excel DSP 16 but not the III nor PnP versions - of this card. - - The Gallant's Audio Excel DSP 16 card can emulate either an SBPro or - a Microsoft Sound System card, so you should have said Y to either - "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support" - or "Microsoft Sound System support", above, and you need to answer - the "MSS emulation" and "SBPro emulation" questions below - accordingly. You should say Y to one and only one of these two - questions. - - Read the file and the head of - as well as - to get more information - about this driver and its configuration. - -config SC6600 - bool "SC-6600 based audio cards (new Audio Excel DSP 16)" - depends on SOUND_AEDSP16 - help - The SC6600 is the new version of DSP mounted on the Audio Excel DSP - 16 cards. Find in the manual the FCC ID of your audio card and - answer Y if you have an SC6600 DSP. - -config SC6600_JOY - bool "Activate SC-6600 Joystick Interface" - depends on SC6600 - help - Say Y here in order to use the joystick interface of the Audio Excel - DSP 16 card. - -config SC6600_CDROM - int "SC-6600 CDROM Interface (4=None, 3=IDE, 1=Panasonic, 0=?Sony?)" - depends on SC6600 - default "4" - help - This is used to activate the CD-ROM interface of the Audio Excel - DSP 16 card. Enter: 0 for Sony, 1 for Panasonic, 2 for IDE, 4 for no - CD-ROM present. - -config SC6600_CDROMBASE - hex "SC-6600 CDROM Interface I/O Address" - depends on SC6600 - default "0" - help - Base I/O port address for the CD-ROM interface of the Audio Excel - DSP 16 card. - -config SOUND_VIDC - tristate "VIDC 16-bit sound" - depends on ARM && ARCH_ACORN - help - 16-bit support for the VIDC onboard sound hardware found on Acorn - machines. - -config SOUND_WAVEARTIST - tristate "Netwinder WaveArtist" - depends on ARM && ARCH_NETWINDER - help - Say Y here to include support for the Rockwell WaveArtist sound - system. This driver is mainly for the NetWinder. - -config SOUND_KAHLUA - tristate "XpressAudio Sound Blaster emulation" - depends on SOUND_SB - -endif # SOUND_OSS - diff --git a/src/linux/sound/oss/dmasound/Kconfig b/src/linux/sound/oss/dmasound/Kconfig deleted file mode 100644 index f456574..0000000 --- a/src/linux/sound/oss/dmasound/Kconfig +++ /dev/null @@ -1,45 +0,0 @@ -config DMASOUND_ATARI - tristate "Atari DMA sound support" - depends on ATARI && SOUND - select DMASOUND - help - If you want to use the internal audio of your Atari in Linux, answer - Y to this question. This will provide a Sun-like /dev/audio, - compatible with the Linux/i386 sound system. Otherwise, say N. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you - want). If you want to compile it as a module, say M here and read - . - -config DMASOUND_PAULA - tristate "Amiga DMA sound support" - depends on AMIGA && SOUND - select DMASOUND - help - If you want to use the internal audio of your Amiga in Linux, answer - Y to this question. This will provide a Sun-like /dev/audio, - compatible with the Linux/i386 sound system. Otherwise, say N. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you - want). If you want to compile it as a module, say M here and read - . - -config DMASOUND_Q40 - tristate "Q40 sound support" - depends on Q40 && SOUND - select DMASOUND - help - If you want to use the internal audio of your Q40 in Linux, answer - Y to this question. This will provide a Sun-like /dev/audio, - compatible with the Linux/i386 sound system. Otherwise, say N. - - This driver is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you - want). If you want to compile it as a module, say M here and read - . - -config DMASOUND - tristate - select SOUND_OSS_CORE diff --git a/src/linux/sound/parisc/Kconfig b/src/linux/sound/parisc/Kconfig deleted file mode 100644 index 9b61d95..0000000 --- a/src/linux/sound/parisc/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -# ALSA PA-RISC drivers - -menuconfig SND_GSC - bool "GSC sound devices" - depends on GSC - default y - help - Support for GSC sound devices on PA-RISC architectures. - -if SND_GSC - -config SND_HARMONY - tristate "Harmony/Vivace sound chip" - select SND_PCM - help - Say 'Y' or 'M' to include support for the Harmony/Vivace sound - chip found in most GSC-based PA-RISC workstations. It's frequently - provided as part of the Lasi multi-function IC. - -endif # SND_GSC diff --git a/src/linux/sound/pci/Kconfig b/src/linux/sound/pci/Kconfig deleted file mode 100644 index 32151d8..0000000 --- a/src/linux/sound/pci/Kconfig +++ /dev/null @@ -1,904 +0,0 @@ -# ALSA PCI drivers - -menuconfig SND_PCI - bool "PCI sound devices" - depends on PCI - default y - help - Support for sound devices connected via the PCI bus. - -if SND_PCI - -config SND_AD1889 - tristate "Analog Devices AD1889" - select SND_AC97_CODEC - help - Say Y here to include support for the integrated AC97 sound - device found in particular on the Hewlett-Packard [BCJ]-xxx0 - class PA-RISC workstations, using the AD1819 codec. - - To compile this as a module, choose M here: the module - will be called snd-ad1889. - -config SND_ALS300 - tristate "Avance Logic ALS300/ALS300+" - select SND_PCM - select SND_AC97_CODEC - select SND_OPL3_LIB - depends on ZONE_DMA - help - Say 'Y' or 'M' to include support for Avance Logic ALS300/ALS300+ - - To compile this driver as a module, choose M here: the module - will be called snd-als300 - -config SND_ALS4000 - tristate "Avance Logic ALS4000" - depends on ISA_DMA_API - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_PCM - select SND_SB_COMMON - help - Say Y here to include support for soundcards based on Avance Logic - ALS4000 chips. - - To compile this driver as a module, choose M here: the module - will be called snd-als4000. - -config SND_ALI5451 - tristate "ALi M5451 PCI Audio Controller" - select SND_MPU401_UART - select SND_AC97_CODEC - depends on ZONE_DMA - help - Say Y here to include support for the integrated AC97 sound - device on motherboards using the ALi M5451 Audio Controller - (M1535/M1535D/M1535+/M1535D+ south bridges). Newer chipsets - use the "Intel/SiS/nVidia/AMD/ALi AC97 Controller" driver. - - To compile this driver as a module, choose M here: the module - will be called snd-ali5451. - -config SND_ASIHPI - tristate "AudioScience ASIxxxx" - depends on X86 - select FW_LOADER - select SND_PCM - select SND_HWDEP - help - Say Y here to include support for AudioScience ASI sound cards. - - To compile this driver as a module, choose M here: the module - will be called snd-asihpi. - -config SND_ATIIXP - tristate "ATI IXP AC97 Controller" - select SND_AC97_CODEC - help - Say Y here to include support for the integrated AC97 sound - device on motherboards with ATI chipsets (ATI IXP 150/200/250/ - 300/400). - - To compile this driver as a module, choose M here: the module - will be called snd-atiixp. - -config SND_ATIIXP_MODEM - tristate "ATI IXP Modem" - select SND_AC97_CODEC - help - Say Y here to include support for the integrated MC97 modem on - motherboards with ATI chipsets (ATI IXP 150/200/250). - - To compile this driver as a module, choose M here: the module - will be called snd-atiixp-modem. - -config SND_AU8810 - tristate "Aureal Advantage" - select SND_MPU401_UART - select SND_AC97_CODEC - help - Say Y here to include support for Aureal Advantage soundcards. - - Supported features: Hardware Mixer, SRC, EQ and SPDIF output. - 3D support code is in place, but not yet useable. For more info, - email the ALSA developer list, or . - - To compile this driver as a module, choose M here: the module - will be called snd-au8810. - -config SND_AU8820 - tristate "Aureal Vortex" - select SND_MPU401_UART - select SND_AC97_CODEC - help - Say Y here to include support for Aureal Vortex soundcards. - - Supported features: Hardware Mixer and SRC. For more info, email - the ALSA developer list, or . - - To compile this driver as a module, choose M here: the module - will be called snd-au8820. - -config SND_AU8830 - tristate "Aureal Vortex 2" - select SND_MPU401_UART - select SND_AC97_CODEC - help - Say Y here to include support for Aureal Vortex 2 soundcards. - - Supported features: Hardware Mixer, SRC, EQ and SPDIF output. - 3D support code is in place, but not yet useable. For more info, - email the ALSA developer list, or . - - To compile this driver as a module, choose M here: the module - will be called snd-au8830. - -config SND_AW2 - tristate "Emagic Audiowerk 2" - help - Say Y here to include support for Emagic Audiowerk 2 soundcards. - - Supported features: Analog and SPDIF output. Analog or SPDIF input. - Note: Switch between analog and digital input does not always work. - It can produce continuous noise. The workaround is to switch again - (and again) between digital and analog input until it works. - - To compile this driver as a module, choose M here: the module - will be called snd-aw2. - - -config SND_AZT3328 - tristate "Aztech AZF3328 / PCI168" - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_PCM - select SND_RAWMIDI - select SND_AC97_CODEC - select SND_TIMER - depends on ZONE_DMA - help - Say Y here to include support for Aztech AZF3328 (PCI168) - soundcards. - - Supported features: AC97-"conformant" mixer, MPU401/OPL3, analog I/O - (16bit/8bit, many sample rates [<= 66.2kHz], NO hardware mixing), - Digital Enhanced Game Port, 1.024MHz multimedia sequencer timer, - ext. codec (I2S port), onboard amp (4W/4Ohms/ch), suspend/resume. - - To compile this driver as a module, choose M here: the module - will be called snd-azt3328. - -config SND_BT87X - tristate "Bt87x Audio Capture" - select SND_PCM - help - If you want to record audio from TV cards based on - Brooktree Bt878/Bt879 chips, say Y here and read - . - - To compile this driver as a module, choose M here: the module - will be called snd-bt87x. - -config SND_BT87X_OVERCLOCK - bool "Bt87x Audio overclocking" - depends on SND_BT87X - help - Say Y here if 448000 Hz isn't enough for you and you want to - record from the analog input with up to 1792000 Hz. - - Higher sample rates won't hurt your hardware, but audio - quality may suffer. - -config SND_CA0106 - tristate "SB Audigy LS / Live 24bit" - select SND_AC97_CODEC - select SND_RAWMIDI - select SND_VMASTER - help - Say Y here to include support for the Sound Blaster Audigy LS - and Live 24bit. - - To compile this driver as a module, choose M here: the module - will be called snd-ca0106. - -config SND_CMIPCI - tristate "C-Media 8338, 8738, 8768, 8770" - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_PCM - help - If you want to use soundcards based on C-Media CMI8338, CMI8738, - CMI8768 or CMI8770 chips, say Y here and read - . - - To compile this driver as a module, choose M here: the module - will be called snd-cmipci. - -config SND_OXYGEN_LIB - tristate - -config SND_OXYGEN - tristate "C-Media 8786, 8787, 8788 (Oxygen)" - select SND_OXYGEN_LIB - select SND_PCM - select SND_MPU401_UART - help - Say Y here to include support for sound cards based on the - C-Media CMI8788 (Oxygen HD Audio) chip: - * Asound A-8788 - * Asus Xonar DG/DGX - * AuzenTech X-Meridian - * AuzenTech X-Meridian 2G - * Bgears b-Enspirer - * Club3D Theatron DTS - * HT-Omega Claro (plus) - * HT-Omega Claro halo (XT) - * Kuroutoshikou CMI8787-HG2PCI - * Razer Barracuda AC-1 - * Sondigo Inferno - * TempoTec/MediaTek HiFier Fantasia - * TempoTec/MediaTek HiFier Serenade - - To compile this driver as a module, choose M here: the module - will be called snd-oxygen. - -config SND_CS4281 - tristate "Cirrus Logic (Sound Fusion) CS4281" - select SND_OPL3_LIB - select SND_RAWMIDI - select SND_AC97_CODEC - help - Say Y here to include support for Cirrus Logic CS4281 chips. - - To compile this driver as a module, choose M here: the module - will be called snd-cs4281. - -config SND_CS46XX - tristate "Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x" - select SND_RAWMIDI - select SND_AC97_CODEC - select FW_LOADER - help - Say Y here to include support for Cirrus Logic CS4610/CS4612/ - CS4614/CS4615/CS4622/CS4624/CS4630/CS4280 chips. - - To compile this driver as a module, choose M here: the module - will be called snd-cs46xx. - -config SND_CS46XX_NEW_DSP - bool "Cirrus Logic (Sound Fusion) New DSP support" - depends on SND_CS46XX - default y - help - Say Y here to use a new DSP image for SPDIF and dual codecs. - - This works better than the old code, so say Y. - -config SND_CS5530 - tristate "CS5530 Audio" - depends on ISA_DMA_API && (X86_32 || COMPILE_TEST) - select SND_SB16_DSP - help - Say Y here to include support for audio on Cyrix/NatSemi CS5530 chips. - - To compile this driver as a module, choose M here: the module - will be called snd-cs5530. - -config SND_CS5535AUDIO - tristate "CS5535/CS5536 Audio" - depends on X86_32 || MIPS || COMPILE_TEST - select SND_PCM - select SND_AC97_CODEC - help - Say Y here to include support for audio on CS5535 chips. It is - referred to as NS CS5535 IO or AMD CS5535 IO companion in - various literature. This driver also supports the CS5536 audio - device. However, for both chips, on certain boards, you may - need to use ac97_quirk=hp_only if your board has physically - mapped headphone out to master output. If that works for you, - send lspci -vvv output to the mailing list so that your board - can be identified in the quirks list. - - To compile this driver as a module, choose M here: the module - will be called snd-cs5535audio. - -config SND_CTXFI - tristate "Creative Sound Blaster X-Fi" - select SND_PCM - help - If you want to use soundcards based on Creative Sound Blastr X-Fi - boards with 20k1 or 20k2 chips, say Y here. - - To compile this driver as a module, choose M here: the module - will be called snd-ctxfi. - -config SND_DARLA20 - tristate "(Echoaudio) Darla20" - select FW_LOADER - select SND_PCM - help - Say 'Y' or 'M' to include support for Echoaudio Darla. - - To compile this driver as a module, choose M here: the module - will be called snd-darla20 - -config SND_GINA20 - tristate "(Echoaudio) Gina20" - select FW_LOADER - select SND_PCM - help - Say 'Y' or 'M' to include support for Echoaudio Gina. - - To compile this driver as a module, choose M here: the module - will be called snd-gina20 - -config SND_LAYLA20 - tristate "(Echoaudio) Layla20" - select FW_LOADER - select SND_RAWMIDI - select SND_PCM - help - Say 'Y' or 'M' to include support for Echoaudio Layla. - - To compile this driver as a module, choose M here: the module - will be called snd-layla20 - -config SND_DARLA24 - tristate "(Echoaudio) Darla24" - select FW_LOADER - select SND_PCM - help - Say 'Y' or 'M' to include support for Echoaudio Darla24. - - To compile this driver as a module, choose M here: the module - will be called snd-darla24 - -config SND_GINA24 - tristate "(Echoaudio) Gina24" - select FW_LOADER - select SND_PCM - help - Say 'Y' or 'M' to include support for Echoaudio Gina24. - - To compile this driver as a module, choose M here: the module - will be called snd-gina24 - -config SND_LAYLA24 - tristate "(Echoaudio) Layla24" - select FW_LOADER - select SND_RAWMIDI - select SND_PCM - help - Say 'Y' or 'M' to include support for Echoaudio Layla24. - - To compile this driver as a module, choose M here: the module - will be called snd-layla24 - -config SND_MONA - tristate "(Echoaudio) Mona" - select FW_LOADER - select SND_RAWMIDI - select SND_PCM - help - Say 'Y' or 'M' to include support for Echoaudio Mona. - - To compile this driver as a module, choose M here: the module - will be called snd-mona - -config SND_MIA - tristate "(Echoaudio) Mia" - select FW_LOADER - select SND_RAWMIDI - select SND_PCM - help - Say 'Y' or 'M' to include support for Echoaudio Mia and Mia-midi. - - To compile this driver as a module, choose M here: the module - will be called snd-mia - -config SND_ECHO3G - tristate "(Echoaudio) 3G cards" - select FW_LOADER - select SND_RAWMIDI - select SND_PCM - help - Say 'Y' or 'M' to include support for Echoaudio Gina3G and Layla3G. - - To compile this driver as a module, choose M here: the module - will be called snd-echo3g - -config SND_INDIGO - tristate "(Echoaudio) Indigo" - select FW_LOADER - select SND_PCM - help - Say 'Y' or 'M' to include support for Echoaudio Indigo. - - To compile this driver as a module, choose M here: the module - will be called snd-indigo - -config SND_INDIGOIO - tristate "(Echoaudio) Indigo IO" - select FW_LOADER - select SND_PCM - help - Say 'Y' or 'M' to include support for Echoaudio Indigo IO. - - To compile this driver as a module, choose M here: the module - will be called snd-indigoio - -config SND_INDIGODJ - tristate "(Echoaudio) Indigo DJ" - select FW_LOADER - select SND_PCM - help - Say 'Y' or 'M' to include support for Echoaudio Indigo DJ. - - To compile this driver as a module, choose M here: the module - will be called snd-indigodj - -config SND_INDIGOIOX - tristate "(Echoaudio) Indigo IOx" - select FW_LOADER - select SND_PCM - help - Say 'Y' or 'M' to include support for Echoaudio Indigo IOx. - - To compile this driver as a module, choose M here: the module - will be called snd-indigoiox - -config SND_INDIGODJX - tristate "(Echoaudio) Indigo DJx" - select FW_LOADER - select SND_PCM - help - Say 'Y' or 'M' to include support for Echoaudio Indigo DJx. - - To compile this driver as a module, choose M here: the module - will be called snd-indigodjx - -config SND_EMU10K1 - tristate "Emu10k1 (SB Live!, Audigy, E-mu APS)" - select FW_LOADER - select SND_HWDEP - select SND_RAWMIDI - select SND_AC97_CODEC - select SND_TIMER - depends on ZONE_DMA - help - Say Y to include support for Sound Blaster PCI 512, Live!, - Audigy and E-mu APS (partially supported) soundcards. - - The confusing multitude of mixer controls is documented in - and - . - - To compile this driver as a module, choose M here: the module - will be called snd-emu10k1. - -config SND_EMU10K1X - tristate "Emu10k1X (Dell OEM Version)" - select SND_AC97_CODEC - select SND_RAWMIDI - depends on ZONE_DMA - help - Say Y here to include support for the Dell OEM version of the - Sound Blaster Live!. - - To compile this driver as a module, choose M here: the module - will be called snd-emu10k1x. - -config SND_ENS1370 - tristate "(Creative) Ensoniq AudioPCI 1370" - select SND_RAWMIDI - select SND_PCM - help - Say Y here to include support for Ensoniq AudioPCI ES1370 chips. - - To compile this driver as a module, choose M here: the module - will be called snd-ens1370. - -config SND_ENS1371 - tristate "(Creative) Ensoniq AudioPCI 1371/1373" - select SND_RAWMIDI - select SND_AC97_CODEC - help - Say Y here to include support for Ensoniq AudioPCI ES1371 chips and - Sound Blaster PCI 64 or 128 soundcards. - - To compile this driver as a module, choose M here: the module - will be called snd-ens1371. - -config SND_ES1938 - tristate "ESS ES1938/1946/1969 (Solo-1)" - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_AC97_CODEC - depends on ZONE_DMA - help - Say Y here to include support for soundcards based on ESS Solo-1 - (ES1938, ES1946, ES1969) chips. - - To compile this driver as a module, choose M here: the module - will be called snd-es1938. - -config SND_ES1968 - tristate "ESS ES1968/1978 (Maestro-1/2/2E)" - select SND_MPU401_UART - select SND_AC97_CODEC - depends on ZONE_DMA - help - Say Y here to include support for soundcards based on ESS Maestro - 1/2/2E chips. - - To compile this driver as a module, choose M here: the module - will be called snd-es1968. - -config SND_ES1968_INPUT - bool "Enable input device for es1968 volume buttons" - depends on SND_ES1968 - depends on INPUT=y || INPUT=SND_ES1968 - help - If you say Y here, you will get an input device which reports - keypresses for the volume buttons connected to the es1968 chip. - If you say N the buttons will directly control the master volume. - It is recommended to say Y. - -config SND_ES1968_RADIO - bool "Enable TEA5757 radio tuner support for es1968" - depends on SND_ES1968 - depends on MEDIA_RADIO_SUPPORT - depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_ES1968 - select RADIO_ADAPTERS - select RADIO_TEA575X - - help - Say Y here to include support for TEA5757 radio tuner integrated on - some MediaForte cards (e.g. SF64-PCE2). - -config SND_FM801 - tristate "ForteMedia FM801" - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_AC97_CODEC - help - Say Y here to include support for soundcards based on the ForteMedia - FM801 chip. - - To compile this driver as a module, choose M here: the module - will be called snd-fm801. - -config SND_FM801_TEA575X_BOOL - bool "ForteMedia FM801 + TEA5757 tuner" - depends on SND_FM801 - depends on MEDIA_RADIO_SUPPORT - depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_FM801 - select RADIO_ADAPTERS - select RADIO_TEA575X - help - Say Y here to include support for soundcards based on the ForteMedia - FM801 chip with a TEA5757 tuner (MediaForte SF256-PCS, SF256-PCP and - SF64-PCR) into the snd-fm801 driver. - -config SND_HDSP - tristate "RME Hammerfall DSP Audio" - select FW_LOADER - select SND_HWDEP - select SND_RAWMIDI - select SND_PCM - help - Say Y here to include support for RME Hammerfall DSP Audio - soundcards. - - To compile this driver as a module, choose M here: the module - will be called snd-hdsp. - -comment "Don't forget to add built-in firmwares for HDSP driver" - depends on SND_HDSP=y - -config SND_HDSPM - tristate "RME Hammerfall DSP MADI/RayDAT/AIO" - select SND_HWDEP - select SND_RAWMIDI - select SND_PCM - help - Say Y here to include support for RME Hammerfall DSP MADI, - RayDAT and AIO soundcards. - - To compile this driver as a module, choose M here: the module - will be called snd-hdspm. - -config SND_ICE1712 - tristate "ICEnsemble ICE1712 (Envy24)" - select SND_MPU401_UART - select SND_AC97_CODEC - select BITREVERSE - depends on ZONE_DMA - help - Say Y here to include support for soundcards based on the - ICE1712 (Envy24) chip. - - Currently supported hardware is: M-Audio Delta 1010(LT), - DiO 2496, 66, 44, 410, Audiophile 24/96; Digigram VX442; - TerraTec EWX 24/96, EWS 88MT/D, DMX 6Fire, Phase 88; - Hoontech SoundTrack DSP 24/Value/Media7.1; Event EZ8; - Lionstracs Mediastation, Terrasoniq TS 88. - - To compile this driver as a module, choose M here: the module - will be called snd-ice1712. - -config SND_ICE1724 - tristate "ICE/VT1724/1720 (Envy24HT/PT)" - select SND_RAWMIDI - select SND_AC97_CODEC - select SND_VMASTER - help - Say Y here to include support for soundcards based on - ICE/VT1724/1720 (Envy24HT/PT) chips. - - Currently supported hardware is: AMP AUDIO2000; M-Audio - Revolution 5.1, 7.1, Audiophile 192; TerraTec Aureon 5.1 Sky, - 7.1 Space/Universe, Phase 22/28; Onkyo SE-90PCI, SE-200PCI; - AudioTrak Prodigy 192, 7.1 (HIFI/LT/XT), HD2; Hercules - Fortissimo IV; ESI Juli@; Pontis MS300; EGO-SYS WaveTerminal - 192M; Albatron K8X800 Pro II; Chaintech ZNF3-150/250, 9CJS, - AV-710; Shuttle SN25P; Philips PSC724 Ultimate Edge. - - To compile this driver as a module, choose M here: the module - will be called snd-ice1724. - -config SND_INTEL8X0 - tristate "Intel/SiS/nVidia/AMD/ALi AC97 Controller" - select SND_AC97_CODEC - help - Say Y here to include support for the integrated AC97 sound - device on motherboards with Intel/SiS/nVidia/AMD chipsets, or - ALi chipsets using the M5455 Audio Controller. (There is a - separate driver for ALi M5451 Audio Controllers.) - - To compile this driver as a module, choose M here: the module - will be called snd-intel8x0. - -config SND_INTEL8X0M - tristate "Intel/SiS/nVidia/AMD MC97 Modem" - select SND_AC97_CODEC - help - Say Y here to include support for the integrated MC97 modem on - motherboards with Intel/SiS/nVidia/AMD chipsets. - - To compile this driver as a module, choose M here: the module - will be called snd-intel8x0m. - -config SND_KORG1212 - tristate "Korg 1212 IO" - select SND_PCM - help - Say Y here to include support for Korg 1212IO soundcards. - - To compile this driver as a module, choose M here: the module - will be called snd-korg1212. - -config SND_LOLA - tristate "Digigram Lola" - select SND_PCM - help - Say Y to include support for Digigram Lola boards. - - To compile this driver as a module, choose M here: the module - will be called snd-lola. - -config SND_LX6464ES - tristate "Digigram LX6464ES" - depends on HAS_IOPORT_MAP - select SND_PCM - help - Say Y here to include support for Digigram LX6464ES boards. - - To compile this driver as a module, choose M here: the module - will be called snd-lx6464es. - - -config SND_MAESTRO3 - tristate "ESS Allegro/Maestro3" - select SND_AC97_CODEC - depends on ZONE_DMA - help - Say Y here to include support for soundcards based on ESS Maestro 3 - (Allegro) chips. - - To compile this driver as a module, choose M here: the module - will be called snd-maestro3. - -config SND_MAESTRO3_INPUT - bool "Enable input device for maestro3 volume buttons" - depends on SND_MAESTRO3 - depends on INPUT=y || INPUT=SND_MAESTRO3 - help - If you say Y here, you will get an input device which reports - keypresses for the volume buttons connected to the maestro3 chip. - If you say N the buttons will directly control the master volume. - It is recommended to say Y. - -config SND_MIXART - tristate "Digigram miXart" - select FW_LOADER - select SND_HWDEP - select SND_PCM - help - If you want to use Digigram miXart soundcards, say Y here and - read . - - To compile this driver as a module, choose M here: the module - will be called snd-mixart. - -config SND_NM256 - tristate "NeoMagic NM256AV/ZX" - select SND_AC97_CODEC - help - Say Y here to include support for NeoMagic NM256AV/ZX chips. - - To compile this driver as a module, choose M here: the module - will be called snd-nm256. - -config SND_PCXHR - tristate "Digigram PCXHR" - select FW_LOADER - select SND_PCM - select SND_HWDEP - help - Say Y here to include support for Digigram PCXHR boards. - - To compile this driver as a module, choose M here: the module - will be called snd-pcxhr. - -config SND_RIPTIDE - tristate "Conexant Riptide" - select FW_LOADER - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_AC97_CODEC - help - Say 'Y' or 'M' to include support for Conexant Riptide chip. - - To compile this driver as a module, choose M here: the module - will be called snd-riptide - -config SND_RME32 - tristate "RME Digi32, 32/8, 32 PRO" - select SND_PCM - help - Say Y to include support for RME Digi32, Digi32 PRO and - Digi32/8 (Sek'd Prodif32, Prodif96 and Prodif Gold) audio - devices. - - To compile this driver as a module, choose M here: the module - will be called snd-rme32. - -config SND_RME96 - tristate "RME Digi96, 96/8, 96/8 PRO" - select SND_PCM - help - Say Y here to include support for RME Digi96, Digi96/8 and - Digi96/8 PRO/PAD/PST soundcards. - - To compile this driver as a module, choose M here: the module - will be called snd-rme96. - -config SND_RME9652 - tristate "RME Digi9652 (Hammerfall)" - select SND_PCM - help - Say Y here to include support for RME Hammerfall (RME - Digi9652/Digi9636) soundcards. - - To compile this driver as a module, choose M here: the module - will be called snd-rme9652. - -config SND_SE6X - tristate "Studio Evolution SE6X" - depends on SND_OXYGEN=n && SND_VIRTUOSO=n # PCI ID conflict - select SND_OXYGEN_LIB - select SND_PCM - select SND_MPU401_UART - help - Say Y or M here only if you actually have this sound card. - -config SND_SIS7019 - tristate "SiS 7019 Audio Accelerator" - depends on X86_32 - select SND_AC97_CODEC - depends on ZONE_DMA - help - Say Y here to include support for the SiS 7019 Audio Accelerator. - - To compile this driver as a module, choose M here: the module - will be called snd-sis7019. - -config SND_SONICVIBES - tristate "S3 SonicVibes" - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_AC97_CODEC - depends on ZONE_DMA - help - Say Y here to include support for soundcards based on the S3 - SonicVibes chip. - - To compile this driver as a module, choose M here: the module - will be called snd-sonicvibes. - -config SND_TRIDENT - tristate "Trident 4D-Wave DX/NX; SiS 7018" - select SND_MPU401_UART - select SND_AC97_CODEC - depends on ZONE_DMA - help - Say Y here to include support for soundcards based on Trident - 4D-Wave DX/NX or SiS 7018 chips. - - To compile this driver as a module, choose M here: the module - will be called snd-trident. - -config SND_VIA82XX - tristate "VIA 82C686A/B, 8233/8235 AC97 Controller" - select SND_MPU401_UART - select SND_AC97_CODEC - help - Say Y here to include support for the integrated AC97 sound - device on motherboards with VIA chipsets. - - To compile this driver as a module, choose M here: the module - will be called snd-via82xx. - -config SND_VIA82XX_MODEM - tristate "VIA 82C686A/B, 8233 based Modems" - select SND_AC97_CODEC - help - Say Y here to include support for the integrated MC97 modem on - motherboards with VIA chipsets. - - To compile this driver as a module, choose M here: the module - will be called snd-via82xx-modem. - -config SND_VIRTUOSO - tristate "Asus Virtuoso 66/100/200 (Xonar)" - select SND_OXYGEN_LIB - select SND_PCM - select SND_MPU401_UART - select SND_JACK - help - Say Y here to include support for sound cards based on the - Asus AV66/AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, DS, DSX, - Essence ST (Deluxe), and Essence STX (II). - Support for the HDAV1.3 (Deluxe) and HDAV1.3 Slim is experimental; - for the Xense, missing. - - To compile this driver as a module, choose M here: the module - will be called snd-virtuoso. - -config SND_VX222 - tristate "Digigram VX222" - select SND_VX_LIB - help - Say Y here to include support for Digigram VX222 soundcards. - - To compile this driver as a module, choose M here: the module - will be called snd-vx222. - -config SND_YMFPCI - tristate "Yamaha YMF724/740/744/754" - select SND_OPL3_LIB - select SND_MPU401_UART - select SND_AC97_CODEC - select SND_TIMER - help - Say Y here to include support for Yamaha PCI audio chips - - YMF724, YMF724F, YMF740, YMF740C, YMF744, YMF754. - - To compile this driver as a module, choose M here: the module - will be called snd-ymfpci. - -endif # SND_PCI - -source "sound/pci/hda/Kconfig" diff --git a/src/linux/sound/pci/hda/Kconfig b/src/linux/sound/pci/hda/Kconfig deleted file mode 100644 index 7f3b5ed..0000000 --- a/src/linux/sound/pci/hda/Kconfig +++ /dev/null @@ -1,228 +0,0 @@ -menu "HD-Audio" - -config SND_HDA - tristate - select SND_PCM - select SND_VMASTER - select SND_JACK - select SND_HDA_CORE - -config SND_HDA_INTEL - tristate "HD Audio PCI" - depends on SND_PCI - select SND_HDA - help - Say Y here to include support for Intel "High Definition - Audio" (Azalia) and its compatible devices. - - This option enables the HD-audio controller. Don't forget - to choose the appropriate codec options below. - - To compile this driver as a module, choose M here: the module - will be called snd-hda-intel. - -config SND_HDA_TEGRA - tristate "NVIDIA Tegra HD Audio" - depends on ARCH_TEGRA - select SND_HDA - help - Say Y here to support the HDA controller present in NVIDIA - Tegra SoCs - - This options enables support for the HD Audio controller - present in some NVIDIA Tegra SoCs, used to communicate audio - to the HDMI output. - - To compile this driver as a module, choose M here: the module - will be called snd-hda-tegra. - -if SND_HDA - -config SND_HDA_HWDEP - bool "Build hwdep interface for HD-audio driver" - select SND_HWDEP - help - Say Y here to build a hwdep interface for HD-audio driver. - This interface can be used for out-of-band communication - with codecs for debugging purposes. - -config SND_HDA_RECONFIG - bool "Allow dynamic codec reconfiguration" - help - Say Y here to enable the HD-audio codec re-configuration feature. - It allows user to clear the whole codec configuration, change the - codec setup, add extra verbs, and re-configure the codec dynamically. - - Note that this item alone doesn't provide the sysfs interface, but - enables the feature just for the patch loader below. - If you need the traditional sysfs entries for the manual interaction, - turn on CONFIG_SND_HDA_HWDEP as well. - -config SND_HDA_INPUT_BEEP - bool "Support digital beep via input layer" - depends on INPUT=y || INPUT=SND_HDA - help - Say Y here to build a digital beep interface for HD-audio - driver. This interface is used to generate digital beeps. - -config SND_HDA_INPUT_BEEP_MODE - int "Digital beep registration mode (0=off, 1=on)" - depends on SND_HDA_INPUT_BEEP=y - default "1" - range 0 1 - help - Set 0 to disable the digital beep interface for HD-audio by default. - Set 1 to always enable the digital beep interface for HD-audio by - default. - -config SND_HDA_PATCH_LOADER - bool "Support initialization patch loading for HD-audio" - select FW_LOADER - select SND_HDA_RECONFIG - help - Say Y here to allow the HD-audio driver to load a pseudo - firmware file ("patch") for overriding the BIOS setup at - start up. The "patch" file can be specified via patch module - option, such as patch=hda-init. - -config SND_HDA_CODEC_REALTEK - tristate "Build Realtek HD-audio codec support" - select SND_HDA_GENERIC - select INPUT - help - Say Y or M here to include Realtek HD-audio codec support in - snd-hda-intel driver, such as ALC880. - -comment "Set to Y if you want auto-loading the codec driver" - depends on SND_HDA=y && SND_HDA_CODEC_REALTEK=m - -config SND_HDA_CODEC_ANALOG - tristate "Build Analog Device HD-audio codec support" - select SND_HDA_GENERIC - help - Say Y or M here to include Analog Device HD-audio codec support in - snd-hda-intel driver, such as AD1986A. - -comment "Set to Y if you want auto-loading the codec driver" - depends on SND_HDA=y && SND_HDA_CODEC_ANALOG=m - -config SND_HDA_CODEC_SIGMATEL - tristate "Build IDT/Sigmatel HD-audio codec support" - select SND_HDA_GENERIC - help - Say Y or M here to include IDT (Sigmatel) HD-audio codec support in - snd-hda-intel driver, such as STAC9200. - -comment "Set to Y if you want auto-loading the codec driver" - depends on SND_HDA=y && SND_HDA_CODEC_SIGMATEL=m - -config SND_HDA_CODEC_VIA - tristate "Build VIA HD-audio codec support" - select SND_HDA_GENERIC - help - Say Y or M here to include VIA HD-audio codec support in - snd-hda-intel driver, such as VT1708. - -comment "Set to Y if you want auto-loading the codec driver" - depends on SND_HDA=y && SND_HDA_CODEC_VIA=m - -config SND_HDA_CODEC_HDMI - tristate "Build HDMI/DisplayPort HD-audio codec support" - help - Say Y or M here to include HDMI and DisplayPort HD-audio codec - support in snd-hda-intel driver. This includes all AMD/ATI, - Intel and Nvidia HDMI/DisplayPort codecs. - -comment "Set to Y if you want auto-loading the codec driver" - depends on SND_HDA=y && SND_HDA_CODEC_HDMI=m - -config SND_HDA_CODEC_CIRRUS - tristate "Build Cirrus Logic codec support" - select SND_HDA_GENERIC - help - Say Y or M here to include Cirrus Logic codec support in - snd-hda-intel driver, such as CS4206. - -comment "Set to Y if you want auto-loading the codec driver" - depends on SND_HDA=y && SND_HDA_CODEC_CIRRUS=m - -config SND_HDA_CODEC_CONEXANT - tristate "Build Conexant HD-audio codec support" - select SND_HDA_GENERIC - help - Say Y or M here to include Conexant HD-audio codec support in - snd-hda-intel driver, such as CX20549. - -comment "Set to Y if you want auto-loading the codec driver" - depends on SND_HDA=y && SND_HDA_CODEC_CONEXANT=m - -config SND_HDA_CODEC_CA0110 - tristate "Build Creative CA0110-IBG codec support" - select SND_HDA_GENERIC - help - Say Y or M here to include Creative CA0110-IBG codec support in - snd-hda-intel driver, found on some Creative X-Fi cards. - -comment "Set to Y if you want auto-loading the codec driver" - depends on SND_HDA=y && SND_HDA_CODEC_CA0110=m - -config SND_HDA_CODEC_CA0132 - tristate "Build Creative CA0132 codec support" - help - Say Y or M here to include Creative CA0132 codec support in - snd-hda-intel driver. - -comment "Set to Y if you want auto-loading the codec driver" - depends on SND_HDA=y && SND_HDA_CODEC_CA0132=m - -config SND_HDA_CODEC_CA0132_DSP - bool "Support new DSP code for CA0132 codec" - depends on SND_HDA_CODEC_CA0132 - select SND_HDA_DSP_LOADER - select FW_LOADER - help - Say Y here to enable the DSP for Creative CA0132 for extended - features like equalizer or echo cancellation. - - Note that this option requires the external firmware file - (ctefx.bin). - -config SND_HDA_CODEC_CMEDIA - tristate "Build C-Media HD-audio codec support" - select SND_HDA_GENERIC - help - Say Y or M here to include C-Media HD-audio codec support in - snd-hda-intel driver, such as CMI9880. - -comment "Set to Y if you want auto-loading the codec driver" - depends on SND_HDA=y && SND_HDA_CODEC_CMEDIA=m - -config SND_HDA_CODEC_SI3054 - tristate "Build Silicon Labs 3054 HD-modem codec support" - help - Say Y or M here to include Silicon Labs 3054 HD-modem codec - (and compatibles) support in snd-hda-intel driver. - -comment "Set to Y if you want auto-loading the codec driver" - depends on SND_HDA=y && SND_HDA_CODEC_SI3054=m - -config SND_HDA_GENERIC - tristate "Enable generic HD-audio codec parser" - help - Say Y or M here to enable the generic HD-audio codec parser - in snd-hda-intel driver. - -comment "Set to Y if you want auto-loading the codec driver" - depends on SND_HDA=y && SND_HDA_GENERIC=m - -config SND_HDA_POWER_SAVE_DEFAULT - int "Default time-out for HD-audio power-save mode" - depends on PM - default 0 - help - The default time-out value in seconds for HD-audio automatic - power-save mode. 0 means to disable the power-save mode. - -endif - -endmenu diff --git a/src/linux/sound/pcmcia/Kconfig b/src/linux/sound/pcmcia/Kconfig deleted file mode 100644 index 7fbb190..0000000 --- a/src/linux/sound/pcmcia/Kconfig +++ /dev/null @@ -1,33 +0,0 @@ -# ALSA PCMCIA drivers - -menuconfig SND_PCMCIA - bool "PCMCIA sound devices" - depends on PCMCIA - default y - help - Support for sound devices connected via the PCMCIA bus. - -if SND_PCMCIA && PCMCIA - -config SND_VXPOCKET - tristate "Digigram VXpocket" - select SND_VX_LIB - help - Say Y here to include support for Digigram VXpocket and - VXpocket 440 soundcards. - - To compile this driver as a module, choose M here: the module - will be called snd-vxpocket. - -config SND_PDAUDIOCF - tristate "Sound Core PDAudioCF" - select SND_PCM - help - Say Y here to include support for Sound Core PDAudioCF - soundcards. - - To compile this driver as a module, choose M here: the module - will be called snd-pdaudiocf. - -endif # SND_PCMCIA - diff --git a/src/linux/sound/ppc/Kconfig b/src/linux/sound/ppc/Kconfig deleted file mode 100644 index 0519c60..0000000 --- a/src/linux/sound/ppc/Kconfig +++ /dev/null @@ -1,52 +0,0 @@ -# ALSA PowerMac drivers - -menuconfig SND_PPC - bool "PowerPC sound devices" - depends on PPC - default y - help - Support for sound devices specific to PowerPC architectures. - -if SND_PPC - -config SND_POWERMAC - tristate "PowerMac (AWACS, DACA, Burgundy, Tumbler, Keywest)" - depends on I2C && INPUT && PPC_PMAC - select SND_PCM - select SND_VMASTER - help - Say Y here to include support for the integrated sound device. - - To compile this driver as a module, choose M here: the module - will be called snd-powermac. - -config SND_POWERMAC_AUTO_DRC - bool "Toggle DRC automatically at headphone/line plug-in" - depends on SND_POWERMAC - default y - help - Say Y here to enable the automatic toggle of DRC (dynamic - range compression) on Tumbler/Snapper. - If this feature is enabled, DRC is turned off when the - headphone/line jack is plugged, and turned on when unplugged. - - Note that you can turn on/off DRC manually even without this - option. - -config SND_PS3 - tristate "PS3 Audio support" - depends on PS3_PS3AV - select SND_PCM - default m - help - Say Y here to include support for audio on the PS3 - - To compile this driver as a module, choose M here: the module - will be called snd_ps3. - -config SND_PS3_DEFAULT_START_DELAY - int "Startup delay time in ms" - depends on SND_PS3 - default "2000" - -endif # SND_PPC diff --git a/src/linux/sound/sh/Kconfig b/src/linux/sound/sh/Kconfig deleted file mode 100644 index 61139f3..0000000 --- a/src/linux/sound/sh/Kconfig +++ /dev/null @@ -1,31 +0,0 @@ -# ALSA SH drivers - -menuconfig SND_SUPERH - bool "SUPERH sound devices" - depends on SUPERH - default y - help - Support for sound devices specific to SUPERH architectures. - Drivers that are implemented on ASoC can be found in - "ALSA for SoC audio support" section. - -if SND_SUPERH - -config SND_AICA - tristate "Dreamcast Yamaha AICA sound" - depends on SH_DREAMCAST - select SND_PCM - select G2_DMA - help - ALSA Sound driver for the SEGA Dreamcast console. - -config SND_SH_DAC_AUDIO - tristate "SuperH DAC audio support" - depends on SND - depends on CPU_SH3 && HIGH_RES_TIMERS - select SND_PCM - help - Say Y here to include support for the on-chip DAC. - -endif # SND_SUPERH - diff --git a/src/linux/sound/soc/Kconfig b/src/linux/sound/soc/Kconfig deleted file mode 100644 index 182d92e..0000000 --- a/src/linux/sound/soc/Kconfig +++ /dev/null @@ -1,80 +0,0 @@ -# -# SoC audio configuration -# - -menuconfig SND_SOC - tristate "ALSA for SoC audio support" - select SND_PCM - select AC97_BUS if SND_SOC_AC97_BUS - select SND_JACK - select REGMAP_I2C if I2C - select REGMAP_SPI if SPI_MASTER - ---help--- - - If you want ASoC support, you should say Y here and also to the - specific driver for your SoC platform below. - - ASoC provides power efficient ALSA support for embedded battery powered - SoC based systems like PDA's, Phones and Personal Media Players. - - This ASoC audio support can also be built as a module. If so, the module - will be called snd-soc-core. - -if SND_SOC - -config SND_SOC_AC97_BUS - bool - -config SND_SOC_GENERIC_DMAENGINE_PCM - bool - select SND_DMAENGINE_PCM - -config SND_SOC_COMPRESS - bool - select SND_COMPRESS_OFFLOAD - -config SND_SOC_TOPOLOGY - bool - -# All the supported SoCs -source "sound/soc/adi/Kconfig" -source "sound/soc/amd/Kconfig" -source "sound/soc/atmel/Kconfig" -source "sound/soc/au1x/Kconfig" -source "sound/soc/bcm/Kconfig" -source "sound/soc/blackfin/Kconfig" -source "sound/soc/cirrus/Kconfig" -source "sound/soc/davinci/Kconfig" -source "sound/soc/dwc/Kconfig" -source "sound/soc/fsl/Kconfig" -source "sound/soc/jz4740/Kconfig" -source "sound/soc/nuc900/Kconfig" -source "sound/soc/omap/Kconfig" -source "sound/soc/kirkwood/Kconfig" -source "sound/soc/img/Kconfig" -source "sound/soc/intel/Kconfig" -source "sound/soc/mediatek/Kconfig" -source "sound/soc/mxs/Kconfig" -source "sound/soc/pxa/Kconfig" -source "sound/soc/qcom/Kconfig" -source "sound/soc/rockchip/Kconfig" -source "sound/soc/samsung/Kconfig" -source "sound/soc/sh/Kconfig" -source "sound/soc/sirf/Kconfig" -source "sound/soc/spear/Kconfig" -source "sound/soc/sti/Kconfig" -source "sound/soc/sunxi/Kconfig" -source "sound/soc/tegra/Kconfig" -source "sound/soc/txx9/Kconfig" -source "sound/soc/ux500/Kconfig" -source "sound/soc/xtensa/Kconfig" -source "sound/soc/zte/Kconfig" - -# Supported codecs -source "sound/soc/codecs/Kconfig" - -# generic frame-work -source "sound/soc/generic/Kconfig" - -endif # SND_SOC - diff --git a/src/linux/sound/soc/adi/Kconfig b/src/linux/sound/soc/adi/Kconfig deleted file mode 100644 index dd763f5..0000000 --- a/src/linux/sound/soc/adi/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -config SND_SOC_ADI - tristate "Audio support for Analog Devices reference designs" - depends on MICROBLAZE || ARCH_ZYNQ || COMPILE_TEST - help - Audio support for various reference designs by Analog Devices. - -config SND_SOC_ADI_AXI_I2S - tristate "AXI-I2S support" - depends on SND_SOC_ADI - select SND_SOC_GENERIC_DMAENGINE_PCM - select REGMAP_MMIO - help - ASoC driver for the Analog Devices AXI-I2S softcore peripheral. - -config SND_SOC_ADI_AXI_SPDIF - tristate "AXI-SPDIF support" - depends on SND_SOC_ADI - select SND_SOC_GENERIC_DMAENGINE_PCM - select REGMAP_MMIO - help - ASoC driver for the Analog Devices AXI-SPDIF softcore peripheral. diff --git a/src/linux/sound/soc/amd/Kconfig b/src/linux/sound/soc/amd/Kconfig deleted file mode 100644 index 78187eb..0000000 --- a/src/linux/sound/soc/amd/Kconfig +++ /dev/null @@ -1,4 +0,0 @@ -config SND_SOC_AMD_ACP - tristate "AMD Audio Coprocessor support" - help - This option enables ACP DMA support on AMD platform. diff --git a/src/linux/sound/soc/atmel/Kconfig b/src/linux/sound/soc/atmel/Kconfig deleted file mode 100644 index 22aec9a..0000000 --- a/src/linux/sound/soc/atmel/Kconfig +++ /dev/null @@ -1,81 +0,0 @@ -config SND_ATMEL_SOC - tristate "SoC Audio for the Atmel System-on-Chip" - depends on HAS_IOMEM - help - Say Y or M if you want to add support for codecs attached to - the ATMEL SSC interface. You will also need - to select the audio interfaces to support below. - -if SND_ATMEL_SOC - -config SND_ATMEL_SOC_PDC - tristate - depends on HAS_DMA - default m if SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=m - default y if SND_ATMEL_SOC_SSC_PDC=y || (SND_ATMEL_SOC_SSC_PDC=m && SND_ATMEL_SOC_SSC=y) - -config SND_ATMEL_SOC_SSC_PDC - tristate - -config SND_ATMEL_SOC_DMA - tristate - select SND_SOC_GENERIC_DMAENGINE_PCM - default m if SND_ATMEL_SOC_SSC_DMA=m && SND_ATMEL_SOC_SSC=m - default y if SND_ATMEL_SOC_SSC_DMA=y || (SND_ATMEL_SOC_SSC_DMA=m && SND_ATMEL_SOC_SSC=y) - -config SND_ATMEL_SOC_SSC_DMA - tristate - -config SND_ATMEL_SOC_SSC - tristate - default y if SND_ATMEL_SOC_SSC_DMA=y || SND_ATMEL_SOC_SSC_PDC=y - default m if SND_ATMEL_SOC_SSC_DMA=m || SND_ATMEL_SOC_SSC_PDC=m - -config SND_AT91_SOC_SAM9G20_WM8731 - tristate "SoC Audio support for WM8731-based At91sam9g20 evaluation board" - depends on ARCH_AT91 || COMPILE_TEST - depends on ATMEL_SSC && SND_SOC_I2C_AND_SPI - select SND_ATMEL_SOC_SSC_PDC - select SND_SOC_WM8731 - help - Say Y if you want to add support for SoC audio on WM8731-based - AT91sam9g20 evaluation board. - -config SND_ATMEL_SOC_WM8904 - tristate "Atmel ASoC driver for boards using WM8904 codec" - depends on ARCH_AT91 || COMPILE_TEST - depends on ATMEL_SSC && I2C - select SND_ATMEL_SOC_SSC_DMA - select SND_SOC_WM8904 - help - Say Y if you want to add support for Atmel ASoC driver for boards using - WM8904 codec. - -config SND_AT91_SOC_SAM9X5_WM8731 - tristate "SoC Audio support for WM8731-based at91sam9x5 board" - depends on ARCH_AT91 || COMPILE_TEST - depends on ATMEL_SSC && SND_SOC_I2C_AND_SPI - select SND_ATMEL_SOC_SSC_DMA - select SND_SOC_WM8731 - help - Say Y if you want to add support for audio SoC on an - at91sam9x5 based board that is using WM8731 codec. - -config SND_ATMEL_SOC_CLASSD - tristate "Atmel ASoC driver for boards using CLASSD" - depends on ARCH_AT91 || COMPILE_TEST - select SND_ATMEL_SOC_DMA - select REGMAP_MMIO - help - Say Y if you want to add support for Atmel ASoC driver for boards using - CLASSD. - -config SND_ATMEL_SOC_PDMIC - tristate "Atmel ASoC driver for boards using PDMIC" - depends on OF && (ARCH_AT91 || COMPILE_TEST) - select SND_SOC_GENERIC_DMAENGINE_PCM - select REGMAP_MMIO - help - Say Y if you want to add support for Atmel ASoC driver for boards using - PDMIC. -endif diff --git a/src/linux/sound/soc/au1x/Kconfig b/src/linux/sound/soc/au1x/Kconfig deleted file mode 100644 index a561040..0000000 --- a/src/linux/sound/soc/au1x/Kconfig +++ /dev/null @@ -1,64 +0,0 @@ -## -## Au1200/Au1550/Au1300 PSC + DBDMA -## -config SND_SOC_AU1XPSC - tristate "SoC Audio for Au12xx/Au13xx/Au1550" - depends on MIPS_ALCHEMY - help - This option enables support for the Programmable Serial - Controllers in AC97 and I2S mode, and the Descriptor-Based DMA - Controller (DBDMA) as found on the Au12xx/Au13xx/Au1550 SoC. - -config SND_SOC_AU1XPSC_I2S - tristate - -config SND_SOC_AU1XPSC_AC97 - tristate - select AC97_BUS - select SND_AC97_CODEC - select SND_SOC_AC97_BUS - -## -## Au1000/1500/1100 DMA + AC97C/I2SC -## -config SND_SOC_AU1XAUDIO - tristate "SoC Audio for Au1000/Au1500/Au1100" - depends on MIPS_ALCHEMY - help - This is a driver set for the AC97 unit and the - old DMA controller as found on the Au1000/Au1500/Au1100 chips. - -config SND_SOC_AU1XAC97C - tristate - select AC97_BUS - select SND_AC97_CODEC - select SND_SOC_AC97_BUS - -config SND_SOC_AU1XI2SC - tristate - - -## -## Boards -## -config SND_SOC_DB1000 - tristate "DB1000 Audio support" - depends on SND_SOC_AU1XAUDIO - select SND_SOC_AU1XAC97C - select SND_SOC_AC97_CODEC - help - Select this option to enable AC97 audio on the early DB1x00 series - of boards (DB1000/DB1500/DB1100). - -config SND_SOC_DB1200 - tristate "DB1200/DB1300/DB1550 Audio support" - depends on SND_SOC_AU1XPSC - select SND_SOC_AU1XPSC_AC97 - select SND_SOC_AC97_CODEC - select SND_SOC_WM9712 - select SND_SOC_AU1XPSC_I2S - select SND_SOC_WM8731 - help - Select this option to enable audio (AC97 and I2S) on the - Alchemy/AMD/RMI/NetLogic Db1200, Db1550 and Db1300 evaluation boards. - If you need Db1300 touchscreen support, you definitely want to say Y. diff --git a/src/linux/sound/soc/bcm/Kconfig b/src/linux/sound/soc/bcm/Kconfig deleted file mode 100644 index d528aac..0000000 --- a/src/linux/sound/soc/bcm/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config SND_BCM2835_SOC_I2S - tristate "SoC Audio support for the Broadcom BCM2835 I2S module" - depends on ARCH_BCM2835 || COMPILE_TEST - select SND_SOC_GENERIC_DMAENGINE_PCM - select REGMAP_MMIO - help - Say Y or M if you want to add support for codecs attached to - the BCM2835 I2S interface. You will also need - to select the audio interfaces to support below. - -config SND_SOC_CYGNUS - tristate "SoC platform audio for Broadcom Cygnus chips" - depends on ARCH_BCM_CYGNUS || COMPILE_TEST - help - Say Y if you want to add support for ASoC audio on Broadcom - Cygnus chips (bcm958300, bcm958305, bcm911360) - - If you don't know what to do here, say N. \ No newline at end of file diff --git a/src/linux/sound/soc/blackfin/Kconfig b/src/linux/sound/soc/blackfin/Kconfig deleted file mode 100644 index 6410aa2..0000000 --- a/src/linux/sound/soc/blackfin/Kconfig +++ /dev/null @@ -1,205 +0,0 @@ -config SND_BF5XX_I2S - tristate "SoC I2S Audio for the ADI Blackfin chip" - depends on BLACKFIN - select SND_BF5XX_SOC_SPORT if !BF60x - select SND_BF6XX_SOC_SPORT if BF60x - help - Say Y or M if you want to add support for codecs attached to - the Blackfin SPORT (synchronous serial ports) interface in I2S - mode (supports single stereo In/Out). - You will also need to select the audio interfaces to support below. - -config SND_BF5XX_SOC_SSM2602 - tristate "SoC SSM2602 Audio Codec Add-On Card support" - depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI - select SND_BF5XX_SOC_I2S if !BF60x - select SND_BF6XX_SOC_I2S if BF60x - select SND_SOC_SSM2602_SPI if SPI_MASTER - select SND_SOC_SSM2602_I2C if I2C - help - Say Y if you want to add support for the Analog Devices - SSM2602 Audio Codec Add-On Card. - -config SND_SOC_BFIN_EVAL_ADAU1701 - tristate "Support for the EVAL-ADAU1701MINIZ board on Blackfin eval boards" - depends on SND_BF5XX_I2S && I2C - select SND_BF5XX_SOC_I2S - select SND_SOC_ADAU1701 - help - Say Y if you want to add support for the Analog Devices EVAL-ADAU1701MINIZ - board connected to one of the Blackfin evaluation boards like the - BF5XX-STAMP or BF5XX-EZKIT. - -config SND_SOC_BFIN_EVAL_ADAU1373 - tristate "Support for the EVAL-ADAU1373 board on Blackfin eval boards" - depends on SND_BF5XX_I2S && I2C - select SND_BF5XX_SOC_I2S - select SND_SOC_ADAU1373 - help - Say Y if you want to add support for the Analog Devices EVAL-ADAU1373 - board connected to one of the Blackfin evaluation boards like the - BF5XX-STAMP or BF5XX-EZKIT. - - Note: This driver assumes that first ADAU1373 DAI is connected to the - first SPORT port on the BF5XX board. - -config SND_SOC_BFIN_EVAL_ADAU1X61 - tristate "Support for the EVAL-ADAU1X61 board on Blackfin eval boards" - depends on SND_BF5XX_I2S && I2C - select SND_BF5XX_SOC_I2S - select SND_SOC_ADAU1761_I2C - help - Say Y if you want to add support for the Analog Devices EVAL-ADAU1X61 - board connected to one of the Blackfin evaluation boards like the - BF5XX-STAMP or BF5XX-EZKIT. - - Note: This driver assumes that the ADAU1X61 is connected to the - first SPORT port on the BF5XX board. - -config SND_SOC_BFIN_EVAL_ADAU1X81 - tristate "Support for the EVAL-ADAU1X81 boards on Blackfin eval boards" - depends on SND_BF5XX_I2S && I2C - select SND_BF5XX_SOC_I2S - select SND_SOC_ADAU1781_I2C - help - Say Y if you want to add support for the Analog Devices EVAL-ADAU1X81 - board connected to one of the Blackfin evaluation boards like the - BF5XX-STAMP or BF5XX-EZKIT. - - Note: This driver assumes that the ADAU1X81 is connected to the - first SPORT port on the BF5XX board. - -config SND_SOC_BFIN_EVAL_ADAV80X - tristate "Support for the EVAL-ADAV80X boards on Blackfin eval boards" - depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI - select SND_BF5XX_SOC_I2S - select SND_SOC_ADAV801 if SPI_MASTER - select SND_SOC_ADAV803 if I2C - help - Say Y if you want to add support for the Analog Devices EVAL-ADAV801 or - EVAL-ADAV803 board connected to one of the Blackfin evaluation boards - like the BF5XX-STAMP or BF5XX-EZKIT. - - Note: This driver assumes that the ADAV80X digital record and playback - interfaces are connected to the first SPORT port on the BF5XX board. - -config SND_BF5XX_SOC_AD1836 - tristate "SoC AD1836 Audio support for BF5xx" - depends on SND_BF5XX_I2S && SPI_MASTER - select SND_BF5XX_SOC_I2S - select SND_SOC_AD1836 - help - Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT. - -config SND_BF5XX_SOC_AD193X - tristate "SoC AD193X Audio support for Blackfin" - depends on SND_BF5XX_I2S && SND_SOC_I2C_AND_SPI - select SND_BF5XX_SOC_I2S - select SND_SOC_AD193X_I2C if I2C - select SND_SOC_AD193X_SPI if SPI_MASTER - help - Say Y if you want to add support for AD193X codec on Blackfin. - This driver supports AD1936, AD1937, AD1938 and AD1939. - -config SND_BF5XX_SOC_AD73311 - tristate "SoC AD73311 Audio support for Blackfin" - depends on SND_BF5XX_I2S - select SND_BF5XX_SOC_I2S - select SND_SOC_AD73311 - help - Say Y if you want to add support for AD73311 codec on Blackfin. - -config SND_BFIN_AD73311_SE - int "PF pin for AD73311L Chip Select" - depends on SND_BF5XX_SOC_AD73311 - default 4 - help - Enter the GPIO used to control AD73311's SE pin. Acceptable - values are 0 to 7 - -config SND_BF5XX_AC97 - tristate "SoC AC97 Audio for the ADI BF5xx chip" - depends on BLACKFIN - select AC97_BUS - select SND_SOC_AC97_BUS - select SND_BF5XX_SOC_SPORT - select SND_BF5XX_SOC_AC97 - help - Say Y or M if you want to add support for codecs attached to - the Blackfin SPORT (synchronous serial ports) interface in slot 16 - mode (pseudo AC97 interface). - You will also need to select the audio interfaces to support below. - - Note: - AC97 codecs which do not implement the slot-16 mode will not function - properly with this driver. This driver is known to work with the - Analog Devices line of AC97 codecs. - -config SND_BF5XX_MMAP_SUPPORT - bool "Enable MMAP Support" - depends on SND_BF5XX_AC97 - default y - help - Say y if you want AC97 driver to support mmap mode. - We introduce an intermediate buffer to simulate mmap. - -config SND_BF5XX_MULTICHAN_SUPPORT - bool "Enable Multichannel Support" - depends on SND_BF5XX_AC97 - default n - help - Say y if you want AC97 driver to support up to 5.1 channel audio. - this mode will consume much more memory for DMA. - -config SND_BF5XX_HAVE_COLD_RESET - bool "BOARD has COLD Reset GPIO" - depends on SND_BF5XX_AC97 - default y if BFIN548_EZKIT - default n if !BFIN548_EZKIT - -config SND_BF5XX_RESET_GPIO_NUM - int "Set a GPIO for cold reset" - depends on SND_BF5XX_HAVE_COLD_RESET - range 0 159 - default 19 if BFIN548_EZKIT - default 5 if BFIN537_STAMP - default 0 - help - Set the correct GPIO for RESET the sound chip. - -config SND_BF5XX_SOC_AD1980 - tristate "SoC AD1980/1 Audio support for BF5xx (Obsolete)" - depends on SND_BF5XX_AC97 - select SND_BF5XX_SOC_AC97 - select SND_SOC_AD1980 - help - Say Y if you want to add support for SoC audio on BF5xx STAMP/EZKIT. - - Warning: - Because Analog Devices Inc. discontinued the ad1980 sound chip since - Sep. 2009, this ad1980 driver is not maintained, tested and supported - by ADI now. - -config SND_BF5XX_SOC_SPORT - tristate - -config SND_BF6XX_SOC_SPORT - tristate - -config SND_BF5XX_SOC_I2S - tristate - -config SND_BF6XX_SOC_I2S - tristate - -config SND_BF5XX_SOC_AC97 - tristate - -config SND_BF5XX_SPORT_NUM - int "Set a SPORT for Sound chip" - depends on (SND_BF5XX_SOC_SPORT || SND_BF6XX_SOC_SPORT) - range 0 3 if BF54x - range 0 1 if !BF54x - default 0 - help - Set the correct SPORT for sound chip. diff --git a/src/linux/sound/soc/cirrus/Kconfig b/src/linux/sound/soc/cirrus/Kconfig deleted file mode 100644 index c7cd60f..0000000 --- a/src/linux/sound/soc/cirrus/Kconfig +++ /dev/null @@ -1,43 +0,0 @@ -config SND_EP93XX_SOC - tristate "SoC Audio support for the Cirrus Logic EP93xx series" - depends on ARCH_EP93XX || COMPILE_TEST - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y or M if you want to add support for codecs attached to - the EP93xx I2S or AC97 interfaces. - -config SND_EP93XX_SOC_I2S - tristate - -config SND_EP93XX_SOC_AC97 - tristate - select AC97_BUS - select SND_SOC_AC97_BUS - -config SND_EP93XX_SOC_SNAPPERCL15 - tristate "SoC Audio support for Bluewater Systems Snapper CL15 module" - depends on SND_EP93XX_SOC && MACH_SNAPPER_CL15 && I2C - select SND_EP93XX_SOC_I2S - select SND_SOC_TLV320AIC23_I2C - help - Say Y or M here if you want to add support for I2S audio on the - Bluewater Systems Snapper CL15 module. - -config SND_EP93XX_SOC_SIMONE - tristate "SoC Audio support for Simplemachines Sim.One board" - depends on SND_EP93XX_SOC && MACH_SIM_ONE - select SND_EP93XX_SOC_AC97 - select SND_SOC_AC97_CODEC - help - Say Y or M here if you want to add support for AC97 audio on the - Simplemachines Sim.One board. - -config SND_EP93XX_SOC_EDB93XX - tristate "SoC Audio support for Cirrus Logic EDB93xx boards" - depends on SND_EP93XX_SOC && (MACH_EDB9301 || MACH_EDB9302 || MACH_EDB9302A || MACH_EDB9307A || MACH_EDB9315A) - select SND_EP93XX_SOC_I2S - select SND_SOC_CS4271_I2C if I2C - select SND_SOC_CS4271_SPI if SPI_MASTER - help - Say Y or M here if you want to add support for I2S audio on the - Cirrus Logic EDB93xx boards. diff --git a/src/linux/sound/soc/codecs/Kconfig b/src/linux/sound/soc/codecs/Kconfig deleted file mode 100644 index c67667b..0000000 --- a/src/linux/sound/soc/codecs/Kconfig +++ /dev/null @@ -1,1092 +0,0 @@ -# Helper to resolve issues with configs that have SPI enabled but I2C -# modular, meaning we can't build the codec driver in with I2C support. -# We use an ordered list of conditional defaults to pick the appropriate -# setting - SPI can't be modular so that case doesn't need to be covered. -config SND_SOC_I2C_AND_SPI - tristate - default m if I2C=m - default y if I2C=y - default y if SPI_MASTER=y - -menu "CODEC drivers" - -config SND_SOC_ALL_CODECS - tristate "Build all ASoC CODEC drivers" - depends on COMPILE_TEST - select SND_SOC_88PM860X if MFD_88PM860X - select SND_SOC_L3 - select SND_SOC_AB8500_CODEC if ABX500_CORE - select SND_SOC_AC97_CODEC - select SND_SOC_AD1836 if SPI_MASTER - select SND_SOC_AD193X_SPI if SPI_MASTER - select SND_SOC_AD193X_I2C if I2C - select SND_SOC_AD1980 if SND_SOC_AC97_BUS - select SND_SOC_AD73311 - select SND_SOC_ADAU1373 if I2C - select SND_SOC_ADAU1761_I2C if I2C - select SND_SOC_ADAU1761_SPI if SPI - select SND_SOC_ADAU1781_I2C if I2C - select SND_SOC_ADAU1781_SPI if SPI - select SND_SOC_ADAV801 if SPI_MASTER - select SND_SOC_ADAV803 if I2C - select SND_SOC_ADAU1977_SPI if SPI_MASTER - select SND_SOC_ADAU1977_I2C if I2C - select SND_SOC_ADAU1701 if I2C - select SND_SOC_ADAU7002 - select SND_SOC_ADS117X - select SND_SOC_AK4104 if SPI_MASTER - select SND_SOC_AK4535 if I2C - select SND_SOC_AK4554 - select SND_SOC_AK4613 if I2C - select SND_SOC_AK4641 if I2C - select SND_SOC_AK4642 if I2C - select SND_SOC_AK4671 if I2C - select SND_SOC_AK5386 - select SND_SOC_ALC5623 if I2C - select SND_SOC_ALC5632 if I2C - select SND_SOC_BT_SCO - select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC - select SND_SOC_CS35L32 if I2C - select SND_SOC_CS35L33 if I2C - select SND_SOC_CS42L51_I2C if I2C - select SND_SOC_CS42L52 if I2C && INPUT - select SND_SOC_CS42L56 if I2C && INPUT - select SND_SOC_CS42L73 if I2C - select SND_SOC_CS4265 if I2C - select SND_SOC_CS4270 if I2C - select SND_SOC_CS4271_I2C if I2C - select SND_SOC_CS4271_SPI if SPI_MASTER - select SND_SOC_CS42XX8_I2C if I2C - select SND_SOC_CS4349 if I2C - select SND_SOC_CS47L24 if MFD_CS47L24 - select SND_SOC_CS53L30 if I2C - select SND_SOC_CX20442 if TTY - select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI - select SND_SOC_DA7213 if I2C - select SND_SOC_DA7218 if I2C - select SND_SOC_DA7219 if I2C - select SND_SOC_DA732X if I2C - select SND_SOC_DA9055 if I2C - select SND_SOC_DMIC - select SND_SOC_ES8328_SPI if SPI_MASTER - select SND_SOC_ES8328_I2C if I2C - select SND_SOC_GTM601 - select SND_SOC_HDAC_HDMI - select SND_SOC_ICS43432 - select SND_SOC_INNO_RK3036 - select SND_SOC_ISABELLE if I2C - select SND_SOC_JZ4740_CODEC - select SND_SOC_LM4857 if I2C - select SND_SOC_LM49453 if I2C - select SND_SOC_MAX98088 if I2C - select SND_SOC_MAX98090 if I2C - select SND_SOC_MAX98095 if I2C - select SND_SOC_MAX98357A if GPIOLIB - select SND_SOC_MAX98371 if I2C - select SND_SOC_MAX9867 if I2C - select SND_SOC_MAX98925 if I2C - select SND_SOC_MAX98926 if I2C - select SND_SOC_MAX9850 if I2C - select SND_SOC_MAX9860 if I2C - select SND_SOC_MAX9768 if I2C - select SND_SOC_MAX9877 if I2C - select SND_SOC_MC13783 if MFD_MC13XXX - select SND_SOC_ML26124 if I2C - select SND_SOC_NAU8810 if I2C - select SND_SOC_NAU8825 if I2C - select SND_SOC_HDMI_CODEC - select SND_SOC_PCM1681 if I2C - select SND_SOC_PCM179X_I2C if I2C - select SND_SOC_PCM179X_SPI if SPI_MASTER - select SND_SOC_PCM3008 - select SND_SOC_PCM3168A_I2C if I2C - select SND_SOC_PCM3168A_SPI if SPI_MASTER - select SND_SOC_PCM5102A - select SND_SOC_PCM512x_I2C if I2C - select SND_SOC_PCM512x_SPI if SPI_MASTER - select SND_SOC_RT286 if I2C - select SND_SOC_RT298 if I2C - select SND_SOC_RT5514 if I2C - select SND_SOC_RT5616 if I2C - select SND_SOC_RT5631 if I2C - select SND_SOC_RT5640 if I2C - select SND_SOC_RT5645 if I2C - select SND_SOC_RT5651 if I2C - select SND_SOC_RT5659 if I2C - select SND_SOC_RT5660 if I2C - select SND_SOC_RT5663 if I2C - select SND_SOC_RT5670 if I2C - select SND_SOC_RT5677 if I2C && SPI_MASTER - select SND_SOC_SGTL5000 if I2C - select SND_SOC_SI476X if MFD_SI476X_CORE - select SND_SOC_SIRF_AUDIO_CODEC - select SND_SOC_SN95031 if INTEL_SCU_IPC - select SND_SOC_SPDIF - select SND_SOC_SSM2518 if I2C - select SND_SOC_SSM2602_SPI if SPI_MASTER - select SND_SOC_SSM2602_I2C if I2C - select SND_SOC_SSM4567 if I2C - select SND_SOC_STA32X if I2C - select SND_SOC_STA350 if I2C - select SND_SOC_STA529 if I2C - select SND_SOC_STAC9766 if SND_SOC_AC97_BUS - select SND_SOC_STI_SAS - select SND_SOC_TAS2552 if I2C - select SND_SOC_TAS5086 if I2C - select SND_SOC_TAS571X if I2C - select SND_SOC_TAS5720 if I2C - select SND_SOC_TFA9879 if I2C - select SND_SOC_TLV320AIC23_I2C if I2C - select SND_SOC_TLV320AIC23_SPI if SPI_MASTER - select SND_SOC_TLV320AIC26 if SPI_MASTER - select SND_SOC_TLV320AIC31XX if I2C - select SND_SOC_TLV320AIC32X4_I2C if I2C - select SND_SOC_TLV320AIC32X4_SPI if SPI_MASTER - select SND_SOC_TLV320AIC3X if I2C - select SND_SOC_TPA6130A2 if I2C - select SND_SOC_TLV320DAC33 if I2C - select SND_SOC_TS3A227E if I2C - select SND_SOC_TWL4030 if TWL4030_CORE - select SND_SOC_TWL6040 if TWL6040_CORE - select SND_SOC_UDA134X - select SND_SOC_UDA1380 if I2C - select SND_SOC_WL1273 if MFD_WL1273_CORE - select SND_SOC_WM0010 if SPI_MASTER - select SND_SOC_WM1250_EV1 if I2C - select SND_SOC_WM2000 if I2C - select SND_SOC_WM2200 if I2C - select SND_SOC_WM5100 if I2C - select SND_SOC_WM5102 if MFD_WM5102 - select SND_SOC_WM5110 if MFD_WM5110 - select SND_SOC_WM8350 if MFD_WM8350 - select SND_SOC_WM8400 if MFD_WM8400 - select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI - select SND_SOC_WM8523 if I2C - select SND_SOC_WM8580 if I2C - select SND_SOC_WM8711 if SND_SOC_I2C_AND_SPI - select SND_SOC_WM8727 - select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI - select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI - select SND_SOC_WM8737 if SND_SOC_I2C_AND_SPI - select SND_SOC_WM8741 if SND_SOC_I2C_AND_SPI - select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI - select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI - select SND_SOC_WM8770 if SPI_MASTER - select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI - select SND_SOC_WM8782 - select SND_SOC_WM8804_I2C if I2C - select SND_SOC_WM8804_SPI if SPI_MASTER - select SND_SOC_WM8900 if I2C - select SND_SOC_WM8903 if I2C - select SND_SOC_WM8904 if I2C - select SND_SOC_WM8940 if I2C - select SND_SOC_WM8955 if I2C - select SND_SOC_WM8960 if I2C - select SND_SOC_WM8961 if I2C - select SND_SOC_WM8962 if I2C && INPUT - select SND_SOC_WM8971 if I2C - select SND_SOC_WM8974 if I2C - select SND_SOC_WM8978 if I2C - select SND_SOC_WM8983 if SND_SOC_I2C_AND_SPI - select SND_SOC_WM8985 if SND_SOC_I2C_AND_SPI - select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI - select SND_SOC_WM8990 if I2C - select SND_SOC_WM8991 if I2C - select SND_SOC_WM8993 if I2C - select SND_SOC_WM8994 if MFD_WM8994 - select SND_SOC_WM8995 if SND_SOC_I2C_AND_SPI - select SND_SOC_WM8996 if I2C - select SND_SOC_WM8997 if MFD_WM8997 - select SND_SOC_WM8998 if MFD_WM8998 - select SND_SOC_WM9081 if I2C - select SND_SOC_WM9090 if I2C - select SND_SOC_WM9705 if SND_SOC_AC97_BUS - select SND_SOC_WM9712 if SND_SOC_AC97_BUS - select SND_SOC_WM9713 if SND_SOC_AC97_BUS - help - Normally ASoC codec drivers are only built if a machine driver which - uses them is also built since they are only usable with a machine - driver. Selecting this option will allow these drivers to be built - without an explicit machine driver for test and development purposes. - - Support for the bus types used to access the codecs to be built must - be selected separately. - - If unsure select "N". - -config SND_SOC_88PM860X - tristate - -config SND_SOC_ARIZONA - tristate - default y if SND_SOC_CS47L24=y - default y if SND_SOC_WM5102=y - default y if SND_SOC_WM5110=y - default y if SND_SOC_WM8997=y - default y if SND_SOC_WM8998=y - default m if SND_SOC_CS47L24=m - default m if SND_SOC_WM5102=m - default m if SND_SOC_WM5110=m - default m if SND_SOC_WM8997=m - default m if SND_SOC_WM8998=m - -config SND_SOC_WM_HUBS - tristate - default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y - default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m - -config SND_SOC_WM_ADSP - tristate - select SND_SOC_COMPRESS - default y if SND_SOC_CS47L24=y - default y if SND_SOC_WM5102=y - default y if SND_SOC_WM5110=y - default y if SND_SOC_WM2200=y - default m if SND_SOC_CS47L24=m - default m if SND_SOC_WM5102=m - default m if SND_SOC_WM5110=m - default m if SND_SOC_WM2200=m - -config SND_SOC_AB8500_CODEC - tristate - -config SND_SOC_AC97_CODEC - tristate "Build generic ASoC AC97 CODEC driver" - select SND_AC97_CODEC - select SND_SOC_AC97_BUS - -config SND_SOC_AD1836 - tristate - -config SND_SOC_AD193X - tristate - -config SND_SOC_AD193X_SPI - tristate - select SND_SOC_AD193X - -config SND_SOC_AD193X_I2C - tristate - select SND_SOC_AD193X - -config SND_SOC_AD1980 - select REGMAP_AC97 - tristate - -config SND_SOC_AD73311 - tristate - -config SND_SOC_ADAU_UTILS - tristate - -config SND_SOC_ADAU1373 - tristate - select SND_SOC_ADAU_UTILS - -config SND_SOC_ADAU1701 - tristate "Analog Devices ADAU1701 CODEC" - depends on I2C - select SND_SOC_SIGMADSP_I2C - -config SND_SOC_ADAU17X1 - tristate - select SND_SOC_SIGMADSP_REGMAP - select SND_SOC_ADAU_UTILS - -config SND_SOC_ADAU1761 - tristate - select SND_SOC_ADAU17X1 - -config SND_SOC_ADAU1761_I2C - tristate - select SND_SOC_ADAU1761 - select REGMAP_I2C - -config SND_SOC_ADAU1761_SPI - tristate - select SND_SOC_ADAU1761 - select REGMAP_SPI - -config SND_SOC_ADAU1781 - select SND_SOC_ADAU17X1 - tristate - -config SND_SOC_ADAU1781_I2C - tristate - select SND_SOC_ADAU1781 - select REGMAP_I2C - -config SND_SOC_ADAU1781_SPI - tristate - select SND_SOC_ADAU1781 - select REGMAP_SPI - -config SND_SOC_ADAU1977 - tristate - -config SND_SOC_ADAU1977_SPI - tristate - select SND_SOC_ADAU1977 - select REGMAP_SPI - -config SND_SOC_ADAU1977_I2C - tristate - select SND_SOC_ADAU1977 - select REGMAP_I2C - -config SND_SOC_ADAU7002 - tristate "Analog Devices ADAU7002 Stereo PDM-to-I2S/TDM Converter" - -config SND_SOC_ADAV80X - tristate - -config SND_SOC_ADAV801 - tristate - select SND_SOC_ADAV80X - -config SND_SOC_ADAV803 - tristate - select SND_SOC_ADAV80X - -config SND_SOC_ADS117X - tristate - -config SND_SOC_AK4104 - tristate "AKM AK4104 CODEC" - depends on SPI_MASTER - -config SND_SOC_AK4535 - tristate - -config SND_SOC_AK4554 - tristate "AKM AK4554 CODEC" - -config SND_SOC_AK4613 - tristate "AKM AK4613 CODEC" - depends on I2C - -config SND_SOC_AK4641 - tristate - -config SND_SOC_AK4642 - tristate "AKM AK4642 CODEC" - depends on I2C - -config SND_SOC_AK4671 - tristate - -config SND_SOC_AK5386 - tristate "AKM AK5638 CODEC" - -config SND_SOC_ALC5623 - tristate "Realtek ALC5623 CODEC" - depends on I2C - -config SND_SOC_ALC5632 - tristate - -config SND_SOC_BT_SCO - tristate "Dummy BT SCO codec driver" - -config SND_SOC_CQ0093VC - tristate - -config SND_SOC_CS35L32 - tristate "Cirrus Logic CS35L32 CODEC" - depends on I2C - -config SND_SOC_CS35L33 - tristate "Cirrus Logic CS35L33 CODEC" - depends on I2C - -config SND_SOC_CS42L51 - tristate - -config SND_SOC_CS42L51_I2C - tristate "Cirrus Logic CS42L51 CODEC (I2C)" - depends on I2C - select SND_SOC_CS42L51 - -config SND_SOC_CS42L52 - tristate "Cirrus Logic CS42L52 CODEC" - depends on I2C && INPUT - -config SND_SOC_CS42L56 - tristate "Cirrus Logic CS42L56 CODEC" - depends on I2C && INPUT - -config SND_SOC_CS42L73 - tristate "Cirrus Logic CS42L73 CODEC" - depends on I2C - -config SND_SOC_CS4265 - tristate "Cirrus Logic CS4265 CODEC" - depends on I2C - select REGMAP_I2C - -# Cirrus Logic CS4270 Codec -config SND_SOC_CS4270 - tristate "Cirrus Logic CS4270 CODEC" - depends on I2C - -# Cirrus Logic CS4270 Codec VD = 3.3V Errata -# Select if you are affected by the errata where the part will not function -# if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will -# not select any sample rates that require MCLK to be divided by 1.5. -config SND_SOC_CS4270_VD33_ERRATA - bool - depends on SND_SOC_CS4270 - -config SND_SOC_CS4271 - tristate - -config SND_SOC_CS4271_I2C - tristate "Cirrus Logic CS4271 CODEC (I2C)" - depends on I2C - select SND_SOC_CS4271 - select REGMAP_I2C - -config SND_SOC_CS4271_SPI - tristate "Cirrus Logic CS4271 CODEC (SPI)" - depends on SPI_MASTER - select SND_SOC_CS4271 - select REGMAP_SPI - -config SND_SOC_CS42XX8 - tristate - -config SND_SOC_CS42XX8_I2C - tristate "Cirrus Logic CS42448/CS42888 CODEC (I2C)" - depends on I2C - select SND_SOC_CS42XX8 - select REGMAP_I2C - -# Cirrus Logic CS4349 HiFi DAC -config SND_SOC_CS4349 - tristate "Cirrus Logic CS4349 CODEC" - depends on I2C - -config SND_SOC_CS47L24 - tristate - -# Cirrus Logic Quad-Channel ADC -config SND_SOC_CS53L30 - tristate "Cirrus Logic CS53L30 CODEC" - depends on I2C - -config SND_SOC_CX20442 - tristate - depends on TTY - -config SND_SOC_JZ4740_CODEC - select REGMAP_MMIO - tristate - -config SND_SOC_L3 - tristate - -config SND_SOC_DA7210 - tristate - -config SND_SOC_DA7213 - tristate - -config SND_SOC_DA7218 - tristate - -config SND_SOC_DA7219 - tristate - -config SND_SOC_DA732X - tristate - -config SND_SOC_DA9055 - tristate - -config SND_SOC_DMIC - tristate - -config SND_SOC_HDMI_CODEC - tristate - select SND_PCM_ELD - select SND_PCM_IEC958 - select HDMI - -config SND_SOC_ES8328 - tristate "Everest Semi ES8328 CODEC" - -config SND_SOC_ES8328_I2C - tristate - select SND_SOC_ES8328 - -config SND_SOC_ES8328_SPI - tristate - select SND_SOC_ES8328 - -config SND_SOC_GTM601 - tristate 'GTM601 UMTS modem audio codec' - -config SND_SOC_HDAC_HDMI - tristate - select SND_HDA_EXT_CORE - select SND_PCM_ELD - select HDMI - -config SND_SOC_ICS43432 - tristate - -config SND_SOC_INNO_RK3036 - tristate "Inno codec driver for RK3036 SoC" - select REGMAP_MMIO - -config SND_SOC_ISABELLE - tristate - -config SND_SOC_LM49453 - tristate - -config SND_SOC_MAX98088 - tristate - -config SND_SOC_MAX98090 - tristate - -config SND_SOC_MAX98095 - tristate - -config SND_SOC_MAX98357A - tristate - -config SND_SOC_MAX98371 - tristate - -config SND_SOC_MAX98504 - tristate "Maxim MAX98504 speaker amplifier" - depends on I2C - -config SND_SOC_MAX9867 - tristate - -config SND_SOC_MAX98925 - tristate - -config SND_SOC_MAX98926 - tristate - -config SND_SOC_MAX9850 - tristate - -config SND_SOC_MAX9860 - tristate "Maxim MAX9860 Mono Audio Voice Codec" - depends on I2C - select REGMAP_I2C - -config SND_SOC_PCM1681 - tristate "Texas Instruments PCM1681 CODEC" - depends on I2C - -config SND_SOC_PCM179X - tristate - -config SND_SOC_PCM179X_I2C - tristate "Texas Instruments PCM179X CODEC (I2C)" - depends on I2C - select SND_SOC_PCM179X - help - Enable support for Texas Instruments PCM179x CODEC. - Select this if your PCM179x is connected via an I2C bus. - -config SND_SOC_PCM179X_SPI - tristate "Texas Instruments PCM179X CODEC (SPI)" - depends on SPI_MASTER - select SND_SOC_PCM179X - help - Enable support for Texas Instruments PCM179x CODEC. - Select this if your PCM179x is connected via an SPI bus. - -config SND_SOC_PCM3008 - tristate - -config SND_SOC_PCM3168A - tristate - -config SND_SOC_PCM3168A_I2C - tristate "Texas Instruments PCM3168A CODEC - I2C" - depends on I2C - select SND_SOC_PCM3168A - select REGMAP_I2C - -config SND_SOC_PCM3168A_SPI - tristate "Texas Instruments PCM3168A CODEC - SPI" - depends on SPI_MASTER - select SND_SOC_PCM3168A - select REGMAP_SPI - -config SND_SOC_PCM5102A - tristate - -config SND_SOC_PCM512x - tristate - -config SND_SOC_PCM512x_I2C - tristate "Texas Instruments PCM512x CODECs - I2C" - depends on I2C - select SND_SOC_PCM512x - select REGMAP_I2C - -config SND_SOC_PCM512x_SPI - tristate "Texas Instruments PCM512x CODECs - SPI" - depends on SPI_MASTER - select SND_SOC_PCM512x - select REGMAP_SPI - -config SND_SOC_RL6231 - tristate - default y if SND_SOC_RT5514=y - default y if SND_SOC_RT5616=y - default y if SND_SOC_RT5640=y - default y if SND_SOC_RT5645=y - default y if SND_SOC_RT5651=y - default y if SND_SOC_RT5659=y - default y if SND_SOC_RT5660=y - default y if SND_SOC_RT5663=y - default y if SND_SOC_RT5670=y - default y if SND_SOC_RT5677=y - default m if SND_SOC_RT5514=m - default m if SND_SOC_RT5616=m - default m if SND_SOC_RT5640=m - default m if SND_SOC_RT5645=m - default m if SND_SOC_RT5651=m - default m if SND_SOC_RT5659=m - default m if SND_SOC_RT5660=m - default m if SND_SOC_RT5663=m - default m if SND_SOC_RT5670=m - default m if SND_SOC_RT5677=m - -config SND_SOC_RL6347A - tristate - default y if SND_SOC_RT286=y - default y if SND_SOC_RT298=y - default m if SND_SOC_RT286=m - default m if SND_SOC_RT298=m - -config SND_SOC_RT286 - tristate - select SND_SOC_RT5663 - depends on I2C - -config SND_SOC_RT298 - tristate - depends on I2C - -config SND_SOC_RT5514 - tristate - -config SND_SOC_RT5514_SPI - tristate - -config SND_SOC_RT5616 - tristate "Realtek RT5616 CODEC" - depends on I2C - -config SND_SOC_RT5631 - tristate "Realtek ALC5631/RT5631 CODEC" - depends on I2C - -config SND_SOC_RT5640 - tristate - -config SND_SOC_RT5645 - tristate - -config SND_SOC_RT5651 - tristate - -config SND_SOC_RT5659 - tristate - -config SND_SOC_RT5660 - tristate - -config SND_SOC_RT5663 - tristate - -config SND_SOC_RT5670 - tristate - -config SND_SOC_RT5677 - tristate - select REGMAP_I2C - select REGMAP_IRQ - -config SND_SOC_RT5677_SPI - tristate - default SND_SOC_RT5677 && SPI - -#Freescale sgtl5000 codec -config SND_SOC_SGTL5000 - tristate "Freescale SGTL5000 CODEC" - depends on I2C - -config SND_SOC_SI476X - tristate - -config SND_SOC_SIGMADSP - tristate - select CRC32 - -config SND_SOC_SIGMADSP_I2C - tristate - select SND_SOC_SIGMADSP - -config SND_SOC_SIGMADSP_REGMAP - tristate - select SND_SOC_SIGMADSP - -config SND_SOC_SIRF_AUDIO_CODEC - tristate "SiRF SoC internal audio codec" - select REGMAP_MMIO - -config SND_SOC_SN95031 - tristate - -config SND_SOC_SPDIF - tristate "S/PDIF CODEC" - -config SND_SOC_SSM2518 - tristate - -config SND_SOC_SSM2602 - tristate - -config SND_SOC_SSM2602_SPI - tristate "Analog Devices SSM2602 CODEC - SPI" - depends on SPI_MASTER - select SND_SOC_SSM2602 - select REGMAP_SPI - -config SND_SOC_SSM2602_I2C - tristate "Analog Devices SSM2602 CODEC - I2C" - depends on I2C - select SND_SOC_SSM2602 - select REGMAP_I2C - -config SND_SOC_SSM4567 - tristate "Analog Devices ssm4567 amplifier driver support" - depends on I2C - -config SND_SOC_STA32X - tristate "STA326, STA328 and STA329 speaker amplifier" - depends on I2C - select REGMAP_I2C - -config SND_SOC_STA350 - tristate "STA350 speaker amplifier" - depends on I2C - -config SND_SOC_STA529 - tristate - -config SND_SOC_STAC9766 - tristate - -config SND_SOC_STI_SAS - tristate "codec Audio support for STI SAS codec" - -config SND_SOC_TAS2552 - tristate "Texas Instruments TAS2552 Mono Audio amplifier" - depends on I2C - -config SND_SOC_TAS5086 - tristate "Texas Instruments TAS5086 speaker amplifier" - depends on I2C - -config SND_SOC_TAS571X - tristate "Texas Instruments TAS5711/TAS5717/TAS5719/TAS5721 power amplifiers" - depends on I2C - -config SND_SOC_TAS5720 - tristate "Texas Instruments TAS5720 Mono Audio amplifier" - depends on I2C - help - Enable support for Texas Instruments TAS5720L/M high-efficiency mono - Class-D audio power amplifiers. - -config SND_SOC_TFA9879 - tristate "NXP Semiconductors TFA9879 amplifier" - depends on I2C - -config SND_SOC_TLV320AIC23 - tristate - -config SND_SOC_TLV320AIC23_I2C - tristate "Texas Instruments TLV320AIC23 audio CODEC - I2C" - depends on I2C - select SND_SOC_TLV320AIC23 - -config SND_SOC_TLV320AIC23_SPI - tristate "Texas Instruments TLV320AIC23 audio CODEC - SPI" - depends on SPI_MASTER - select SND_SOC_TLV320AIC23 - -config SND_SOC_TLV320AIC26 - tristate - depends on SPI - -config SND_SOC_TLV320AIC31XX - tristate "Texas Instruments TLV320AIC31xx CODECs" - depends on I2C - select REGMAP_I2C - -config SND_SOC_TLV320AIC32X4 - tristate - -config SND_SOC_TLV320AIC32X4_I2C - tristate - depends on I2C - select SND_SOC_TLV320AIC32X4 - -config SND_SOC_TLV320AIC32X4_SPI - tristate - depends on SPI_MASTER - select SND_SOC_TLV320AIC32X4 - -config SND_SOC_TLV320AIC3X - tristate "Texas Instruments TLV320AIC3x CODECs" - depends on I2C - -config SND_SOC_TLV320DAC33 - tristate - -config SND_SOC_TS3A227E - tristate "TI Headset/Mic detect and keypress chip" - depends on I2C - -config SND_SOC_TWL4030 - select MFD_TWL4030_AUDIO - tristate - -config SND_SOC_TWL6040 - tristate - -config SND_SOC_UDA134X - tristate - -config SND_SOC_UDA1380 - tristate - -config SND_SOC_WL1273 - tristate - -config SND_SOC_WM0010 - tristate - -config SND_SOC_WM1250_EV1 - tristate - -config SND_SOC_WM2000 - tristate - -config SND_SOC_WM2200 - tristate - -config SND_SOC_WM5100 - tristate - -config SND_SOC_WM5102 - tristate - -config SND_SOC_WM5110 - tristate - -config SND_SOC_WM8350 - tristate - -config SND_SOC_WM8400 - tristate - -config SND_SOC_WM8510 - tristate "Wolfson Microelectronics WM8510 CODEC" - depends on SND_SOC_I2C_AND_SPI - -config SND_SOC_WM8523 - tristate "Wolfson Microelectronics WM8523 DAC" - depends on I2C - -config SND_SOC_WM8580 - tristate "Wolfson Microelectronics WM8523 CODEC" - depends on I2C - -config SND_SOC_WM8711 - tristate "Wolfson Microelectronics WM8711 CODEC" - depends on SND_SOC_I2C_AND_SPI - -config SND_SOC_WM8727 - tristate - -config SND_SOC_WM8728 - tristate "Wolfson Microelectronics WM8728 DAC" - depends on SND_SOC_I2C_AND_SPI - -config SND_SOC_WM8731 - tristate "Wolfson Microelectronics WM8731 CODEC" - depends on SND_SOC_I2C_AND_SPI - -config SND_SOC_WM8737 - tristate "Wolfson Microelectronics WM8737 ADC" - depends on SND_SOC_I2C_AND_SPI - -config SND_SOC_WM8741 - tristate "Wolfson Microelectronics WM8737 DAC" - depends on SND_SOC_I2C_AND_SPI - -config SND_SOC_WM8750 - tristate "Wolfson Microelectronics WM8750 CODEC" - depends on SND_SOC_I2C_AND_SPI - -config SND_SOC_WM8753 - tristate "Wolfson Microelectronics WM8753 CODEC" - depends on SND_SOC_I2C_AND_SPI - -config SND_SOC_WM8770 - tristate "Wolfson Microelectronics WM8770 CODEC" - depends on SPI_MASTER - -config SND_SOC_WM8776 - tristate "Wolfson Microelectronics WM8776 CODEC" - depends on SND_SOC_I2C_AND_SPI - -config SND_SOC_WM8782 - tristate - -config SND_SOC_WM8804 - tristate - -config SND_SOC_WM8804_I2C - tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver I2C" - depends on I2C - select SND_SOC_WM8804 - select REGMAP_I2C - -config SND_SOC_WM8804_SPI - tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver SPI" - depends on SPI_MASTER - select SND_SOC_WM8804 - select REGMAP_SPI - -config SND_SOC_WM8900 - tristate - -config SND_SOC_WM8903 - tristate "Wolfson Microelectronics WM8903 CODEC" - depends on I2C - -config SND_SOC_WM8904 - tristate - -config SND_SOC_WM8940 - tristate - -config SND_SOC_WM8955 - tristate - -config SND_SOC_WM8960 - tristate "Wolfson Microelectronics WM8960 CODEC" - depends on I2C - -config SND_SOC_WM8961 - tristate - -config SND_SOC_WM8962 - tristate "Wolfson Microelectronics WM8962 CODEC" - depends on I2C && INPUT - -config SND_SOC_WM8971 - tristate - -config SND_SOC_WM8974 - tristate "Wolfson Microelectronics WM8974 codec" - depends on I2C - -config SND_SOC_WM8978 - tristate "Wolfson Microelectronics WM8978 codec" - depends on I2C - -config SND_SOC_WM8983 - tristate - -config SND_SOC_WM8985 - tristate "Wolfson Microelectronics WM8985 and WM8758 codec driver" - depends on SND_SOC_I2C_AND_SPI - -config SND_SOC_WM8988 - tristate - -config SND_SOC_WM8990 - tristate - -config SND_SOC_WM8991 - tristate - -config SND_SOC_WM8993 - tristate - -config SND_SOC_WM8994 - tristate - -config SND_SOC_WM8995 - tristate - -config SND_SOC_WM8996 - tristate - -config SND_SOC_WM8997 - tristate - -config SND_SOC_WM8998 - tristate - -config SND_SOC_WM9081 - tristate - -config SND_SOC_WM9090 - tristate - -config SND_SOC_WM9705 - tristate - -config SND_SOC_WM9712 - tristate - -config SND_SOC_WM9713 - tristate - select REGMAP_AC97 - -# Amp -config SND_SOC_LM4857 - tristate - -config SND_SOC_MAX9768 - tristate - -config SND_SOC_MAX9877 - tristate - -config SND_SOC_MC13783 - tristate - -config SND_SOC_ML26124 - tristate - -config SND_SOC_NAU8810 - tristate "Nuvoton Technology Corporation NAU88C10 CODEC" - depends on I2C - -config SND_SOC_NAU8825 - tristate - -config SND_SOC_TPA6130A2 - tristate "Texas Instruments TPA6130A2 headphone amplifier" - depends on I2C - -endmenu diff --git a/src/linux/sound/soc/davinci/Kconfig b/src/linux/sound/soc/davinci/Kconfig deleted file mode 100644 index 6b732d8..0000000 --- a/src/linux/sound/soc/davinci/Kconfig +++ /dev/null @@ -1,106 +0,0 @@ -config SND_DAVINCI_SOC - tristate - depends on ARCH_DAVINCI - select SND_EDMA_SOC - -config SND_EDMA_SOC - tristate "SoC Audio for Texas Instruments chips using eDMA" - depends on TI_EDMA - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y or M here if you want audio support for TI SoC which uses eDMA. - The following line of SoCs are supported by this platform driver: - - daVinci devices - - AM335x - - AM437x/AM438x - - DRA7xx family - -config SND_DAVINCI_SOC_I2S - tristate "DaVinci Multichannel Buffered Serial Port (McBSP) support" - depends on SND_EDMA_SOC - help - Say Y or M here if you want to have support for McBSP IP found in - Texas Instruments DaVinci DA850 SoCs. - -config SND_DAVINCI_SOC_MCASP - tristate "Multichannel Audio Serial Port (McASP) support" - depends on SND_OMAP_SOC || SND_EDMA_SOC - help - Say Y or M here if you want to have support for McASP IP found in - various Texas Instruments SoCs like: - - daVinci devices - - Sitara line of SoCs (AM335x, AM438x, etc) - - DRA7x devices - -config SND_DAVINCI_SOC_VCIF - tristate - -config SND_DAVINCI_SOC_GENERIC_EVM - tristate - select SND_SOC_TLV320AIC3X - select SND_DAVINCI_SOC_MCASP - -config SND_AM33XX_SOC_EVM - tristate "SoC Audio for the AM33XX chip based boards" - depends on SND_EDMA_SOC && SOC_AM33XX && I2C - select SND_DAVINCI_SOC_GENERIC_EVM - help - Say Y or M if you want to add support for SoC audio on AM33XX - boards using McASP and TLV320AIC3X codec. For example AM335X-EVM, - AM335X-EVMSK, and BeagelBone with AudioCape boards have this - setup. - -config SND_DAVINCI_SOC_EVM - tristate "SoC Audio support for DaVinci DM6446, DM355 or DM365 EVM" - depends on SND_EDMA_SOC && I2C - depends on MACH_DAVINCI_EVM || MACH_DAVINCI_DM355_EVM || MACH_DAVINCI_DM365_EVM - select SND_DAVINCI_SOC_GENERIC_EVM - help - Say Y if you want to add support for SoC audio on TI - DaVinci DM6446, DM355 or DM365 EVM platforms. - -choice - prompt "DM365 codec select" - depends on SND_DAVINCI_SOC_EVM - depends on MACH_DAVINCI_DM365_EVM - -config SND_DM365_AIC3X_CODEC - tristate "Audio Codec - AIC3101" - help - Say Y if you want to add support for AIC3101 audio codec - -config SND_DM365_VOICE_CODEC - tristate "Voice Codec - CQ93VC" - select MFD_DAVINCI_VOICECODEC - select SND_DAVINCI_SOC_VCIF - select SND_SOC_CQ0093VC - help - Say Y if you want to add support for SoC On-chip voice codec -endchoice - -config SND_DM6467_SOC_EVM - tristate "SoC Audio support for DaVinci DM6467 EVM" - depends on SND_EDMA_SOC && MACH_DAVINCI_DM6467_EVM && I2C - select SND_DAVINCI_SOC_GENERIC_EVM - select SND_SOC_SPDIF - - help - Say Y if you want to add support for SoC audio on TI - -config SND_DA830_SOC_EVM - tristate "SoC Audio support for DA830/OMAP-L137 EVM" - depends on SND_EDMA_SOC && MACH_DAVINCI_DA830_EVM && I2C - select SND_DAVINCI_SOC_GENERIC_EVM - - help - Say Y if you want to add support for SoC audio on TI - DA830/OMAP-L137 EVM - -config SND_DA850_SOC_EVM - tristate "SoC Audio support for DA850/OMAP-L138 EVM" - depends on SND_EDMA_SOC && MACH_DAVINCI_DA850_EVM && I2C - select SND_DAVINCI_SOC_GENERIC_EVM - help - Say Y if you want to add support for SoC audio on TI - DA850/OMAP-L138 EVM - diff --git a/src/linux/sound/soc/dwc/Kconfig b/src/linux/sound/soc/dwc/Kconfig deleted file mode 100644 index c297efe..0000000 --- a/src/linux/sound/soc/dwc/Kconfig +++ /dev/null @@ -1,19 +0,0 @@ -config SND_DESIGNWARE_I2S - tristate "Synopsys I2S Device Driver" - depends on CLKDEV_LOOKUP - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y or M if you want to add support for I2S driver for - Synopsys desigwnware I2S device. The device supports upto - maximum of 8 channels each for play and record. - -config SND_DESIGNWARE_PCM - tristate "PCM PIO extension for I2S driver" - depends on SND_DESIGNWARE_I2S - help - Say Y, M or N if you want to add a custom ALSA extension that registers - a PCM and uses PIO to transfer data. - - This functionality is specially suited for I2S devices that don't have - DMA support. - diff --git a/src/linux/sound/soc/fsl/Kconfig b/src/linux/sound/soc/fsl/Kconfig deleted file mode 100644 index 19bdcac..0000000 --- a/src/linux/sound/soc/fsl/Kconfig +++ /dev/null @@ -1,302 +0,0 @@ -menu "SoC Audio for Freescale CPUs" - -comment "Common SoC Audio options for Freescale CPUs:" - -config SND_SOC_FSL_ASRC - tristate "Asynchronous Sample Rate Converter (ASRC) module support" - depends on HAS_DMA - select REGMAP_MMIO - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y if you want to add Asynchronous Sample Rate Converter (ASRC) - support for the Freescale CPUs. - This option is only useful for out-of-tree drivers since - in-tree drivers select it automatically. - -config SND_SOC_FSL_SAI - tristate "Synchronous Audio Interface (SAI) module support" - select REGMAP_MMIO - select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y if you want to add Synchronous Audio Interface (SAI) - support for the Freescale CPUs. - This option is only useful for out-of-tree drivers since - in-tree drivers select it automatically. - -config SND_SOC_FSL_SSI - tristate "Synchronous Serial Interface module (SSI) support" - select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n - select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && (MXC_TZIC || MXC_AVIC) - select REGMAP_MMIO - help - Say Y if you want to add Synchronous Serial Interface (SSI) - support for the Freescale CPUs. - This option is only useful for out-of-tree drivers since - in-tree drivers select it automatically. - -config SND_SOC_FSL_SPDIF - tristate "Sony/Philips Digital Interface (S/PDIF) module support" - select REGMAP_MMIO - select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n - select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && (MXC_TZIC || MXC_AVIC) - help - Say Y if you want to add Sony/Philips Digital Interface (SPDIF) - support for the Freescale CPUs. - This option is only useful for out-of-tree drivers since - in-tree drivers select it automatically. - -config SND_SOC_FSL_ESAI - tristate "Enhanced Serial Audio Interface (ESAI) module support" - select REGMAP_MMIO - select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n - help - Say Y if you want to add Enhanced Synchronous Audio Interface - (ESAI) support for the Freescale CPUs. - This option is only useful for out-of-tree drivers since - in-tree drivers select it automatically. - -config SND_SOC_FSL_UTILS - tristate - -config SND_SOC_IMX_PCM_DMA - tristate - select SND_SOC_GENERIC_DMAENGINE_PCM - -config SND_SOC_IMX_AUDMUX - tristate "Digital Audio Mux module support" - help - Say Y if you want to add Digital Audio Mux (AUDMUX) support - for the ARM i.MX CPUs. - This option is only useful for out-of-tree drivers since - in-tree drivers select it automatically. - -config SND_POWERPC_SOC - tristate "SoC Audio for Freescale PowerPC CPUs" - depends on FSL_SOC || PPC_MPC52xx - help - Say Y or M if you want to add support for codecs attached to - the PowerPC CPUs. - -config SND_IMX_SOC - tristate "SoC Audio for Freescale i.MX CPUs" - depends on ARCH_MXC || COMPILE_TEST - help - Say Y or M if you want to add support for codecs attached to - the i.MX CPUs. - -if SND_POWERPC_SOC - -config SND_MPC52xx_DMA - tristate - -config SND_SOC_POWERPC_DMA - tristate - -comment "SoC Audio support for Freescale PPC boards:" - -config SND_SOC_MPC8610_HPCD - tristate "ALSA SoC support for the Freescale MPC8610 HPCD board" - # I2C is necessary for the CS4270 driver - depends on MPC8610_HPCD && I2C - select SND_SOC_FSL_SSI - select SND_SOC_FSL_UTILS - select SND_SOC_POWERPC_DMA - select SND_SOC_CS4270 - select SND_SOC_CS4270_VD33_ERRATA - default y if MPC8610_HPCD - help - Say Y if you want to enable audio on the Freescale MPC8610 HPCD. - -config SND_SOC_P1022_DS - tristate "ALSA SoC support for the Freescale P1022 DS board" - # I2C is necessary for the WM8776 driver - depends on P1022_DS && I2C - select SND_SOC_FSL_SSI - select SND_SOC_FSL_UTILS - select SND_SOC_POWERPC_DMA - select SND_SOC_WM8776 - default y if P1022_DS - help - Say Y if you want to enable audio on the Freescale P1022 DS board. - This will also include the Wolfson Microelectronics WM8776 codec - driver. - -config SND_SOC_P1022_RDK - tristate "ALSA SoC support for the Freescale / iVeia P1022 RDK board" - # I2C is necessary for the WM8960 driver - depends on P1022_RDK && I2C - select SND_SOC_FSL_SSI - select SND_SOC_FSL_UTILS - select SND_SOC_POWERPC_DMA - select SND_SOC_WM8960 - default y if P1022_RDK - help - Say Y if you want to enable audio on the Freescale / iVeia - P1022 RDK board. This will also include the Wolfson - Microelectronics WM8960 codec driver. - -config SND_SOC_MPC5200_I2S - tristate "Freescale MPC5200 PSC in I2S mode driver" - depends on PPC_MPC52xx && PPC_BESTCOMM - select SND_MPC52xx_DMA - select PPC_BESTCOMM_GEN_BD - help - Say Y here to support the MPC5200 PSCs in I2S mode. - -config SND_SOC_MPC5200_AC97 - tristate "Freescale MPC5200 PSC in AC97 mode driver" - depends on PPC_MPC52xx && PPC_BESTCOMM - select SND_SOC_AC97_BUS - select SND_MPC52xx_DMA - select PPC_BESTCOMM_GEN_BD - help - Say Y here to support the MPC5200 PSCs in AC97 mode. - -config SND_MPC52xx_SOC_PCM030 - tristate "SoC AC97 Audio support for Phytec pcm030 and WM9712" - depends on PPC_MPC5200_SIMPLE - select SND_SOC_MPC5200_AC97 - select SND_SOC_WM9712 - help - Say Y if you want to add support for sound on the Phytec pcm030 - baseboard. - -config SND_MPC52xx_SOC_EFIKA - tristate "SoC AC97 Audio support for bbplan Efika and STAC9766" - depends on PPC_EFIKA - select SND_SOC_MPC5200_AC97 - select SND_SOC_STAC9766 - help - Say Y if you want to add support for sound on the Efika. - -endif # SND_POWERPC_SOC - -if SND_IMX_SOC - -config SND_SOC_IMX_SSI - tristate - select SND_SOC_FSL_UTILS - -config SND_SOC_IMX_PCM_FIQ - tristate - select FIQ - -comment "SoC Audio support for Freescale i.MX boards:" - -config SND_MXC_SOC_WM1133_EV1 - tristate "Audio on the i.MX31ADS with WM1133-EV1 fitted" - depends on MACH_MX31ADS_WM1133_EV1 - select SND_SOC_WM8350 - select SND_SOC_IMX_PCM_FIQ - select SND_SOC_IMX_AUDMUX - select SND_SOC_IMX_SSI - help - Enable support for audio on the i.MX31ADS with the WM1133-EV1 - PMIC board with WM8835x fitted. - -config SND_SOC_MX27VIS_AIC32X4 - tristate "SoC audio support for Visstrim M10 boards" - depends on MACH_IMX27_VISSTRIM_M10 && I2C - select SND_SOC_TLV320AIC32X4 - select SND_SOC_IMX_PCM_DMA - select SND_SOC_IMX_AUDMUX - select SND_SOC_IMX_SSI - help - Say Y if you want to add support for SoC audio on Visstrim SM10 - board with TLV320AIC32X4 codec. - -config SND_SOC_PHYCORE_AC97 - tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards" - depends on MACH_PCM043 || MACH_PCA100 - select SND_SOC_AC97_BUS - select SND_SOC_WM9712 - select SND_SOC_IMX_PCM_FIQ - select SND_SOC_IMX_AUDMUX - select SND_SOC_IMX_SSI - help - Say Y if you want to add support for SoC audio on Phytec phyCORE - and phyCARD boards in AC97 mode - -config SND_SOC_EUKREA_TLV320 - tristate "Eukrea TLV320" - depends on ARCH_MXC && I2C - select SND_SOC_TLV320AIC23_I2C - select SND_SOC_IMX_AUDMUX - select SND_SOC_IMX_SSI - select SND_SOC_FSL_SSI - select SND_SOC_IMX_PCM_DMA - help - Enable I2S based access to the TLV320AIC23B codec attached - to the SSI interface - -config SND_SOC_IMX_WM8962 - tristate "SoC Audio support for i.MX boards with wm8962" - depends on OF && I2C && INPUT - select SND_SOC_WM8962 - select SND_SOC_IMX_PCM_DMA - select SND_SOC_IMX_AUDMUX - select SND_SOC_FSL_SSI - help - Say Y if you want to add support for SoC audio on an i.MX board with - a wm8962 codec. - -config SND_SOC_IMX_ES8328 - tristate "SoC Audio support for i.MX boards with the ES8328 codec" - depends on OF && (I2C || SPI) - select SND_SOC_ES8328_I2C if I2C - select SND_SOC_ES8328_SPI if SPI_MASTER - select SND_SOC_IMX_PCM_DMA - select SND_SOC_IMX_AUDMUX - select SND_SOC_FSL_SSI - help - Say Y if you want to add support for the ES8328 audio codec connected - via SSI/I2S over either SPI or I2C. - -config SND_SOC_IMX_SGTL5000 - tristate "SoC Audio support for i.MX boards with sgtl5000" - depends on OF && I2C - select SND_SOC_SGTL5000 - select SND_SOC_IMX_PCM_DMA - select SND_SOC_IMX_AUDMUX - select SND_SOC_FSL_SSI - help - Say Y if you want to add support for SoC audio on an i.MX board with - a sgtl5000 codec. - -config SND_SOC_IMX_SPDIF - tristate "SoC Audio support for i.MX boards with S/PDIF" - select SND_SOC_IMX_PCM_DMA - select SND_SOC_FSL_SPDIF - help - SoC Audio support for i.MX boards with S/PDIF - Say Y if you want to add support for SoC audio on an i.MX board with - a S/DPDIF. - -config SND_SOC_IMX_MC13783 - tristate "SoC Audio support for I.MX boards with mc13783" - depends on MFD_MC13XXX && ARM - select SND_SOC_IMX_SSI - select SND_SOC_IMX_AUDMUX - select SND_SOC_MC13783 - select SND_SOC_IMX_PCM_DMA - -config SND_SOC_FSL_ASOC_CARD - tristate "Generic ASoC Sound Card with ASRC support" - depends on OF && I2C - # enforce SND_SOC_FSL_ASOC_CARD=m if SND_AC97_CODEC=m: - depends on SND_AC97_CODEC || SND_AC97_CODEC=n - select SND_SOC_IMX_AUDMUX - select SND_SOC_IMX_PCM_DMA - select SND_SOC_FSL_ESAI - select SND_SOC_FSL_SAI - select SND_SOC_FSL_SSI - help - ALSA SoC Audio support with ASRC feature for Freescale SoCs that have - ESAI/SAI/SSI and connect with external CODECs such as WM8962, CS42888, - CS4271, CS4272 and SGTL5000. - Say Y if you want to add support for Freescale Generic ASoC Sound Card. - -endif # SND_IMX_SOC - -endmenu diff --git a/src/linux/sound/soc/generic/Kconfig b/src/linux/sound/soc/generic/Kconfig deleted file mode 100644 index d023959..0000000 --- a/src/linux/sound/soc/generic/Kconfig +++ /dev/null @@ -1,16 +0,0 @@ -config SND_SIMPLE_CARD_UTILS - tristate - -config SND_SIMPLE_CARD - tristate "ASoC Simple sound card support" - select SND_SIMPLE_CARD_UTILS - help - This option enables generic simple sound card support - -config SND_SIMPLE_SCU_CARD - tristate "ASoC Simple SCU sound card support" - depends on OF - select SND_SIMPLE_CARD_UTILS - help - This option enables generic simple SCU sound card support. - It supports DPCM of multi CPU single Codec system. diff --git a/src/linux/sound/soc/img/Kconfig b/src/linux/sound/soc/img/Kconfig deleted file mode 100644 index 857a951..0000000 --- a/src/linux/sound/soc/img/Kconfig +++ /dev/null @@ -1,52 +0,0 @@ -config SND_SOC_IMG - bool "Audio support for Imagination Technologies designs" - help - Audio support for Imagination Technologies audio hardware - -config SND_SOC_IMG_I2S_IN - tristate "Imagination I2S Input Device Driver" - depends on SND_SOC_IMG - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y or M if you want to add support for I2S in driver for - Imagination Technologies I2S in device. - -config SND_SOC_IMG_I2S_OUT - tristate "Imagination I2S Output Device Driver" - depends on SND_SOC_IMG - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y or M if you want to add support for I2S out driver for - Imagination Technologies I2S out device. - -config SND_SOC_IMG_PARALLEL_OUT - tristate "Imagination Parallel Output Device Driver" - depends on SND_SOC_IMG - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y or M if you want to add support for parallel out driver for - Imagination Technologies parallel out device. - -config SND_SOC_IMG_SPDIF_IN - tristate "Imagination SPDIF Input Device Driver" - depends on SND_SOC_IMG - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y or M if you want to add support for SPDIF input driver for - Imagination Technologies SPDIF input device. - -config SND_SOC_IMG_SPDIF_OUT - tristate "Imagination SPDIF Output Device Driver" - depends on SND_SOC_IMG - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y or M if you want to add support for SPDIF out driver for - Imagination Technologies SPDIF out device. - - -config SND_SOC_IMG_PISTACHIO_INTERNAL_DAC - tristate "Support for Pistachio SoC Internal DAC Driver" - depends on SND_SOC_IMG - help - Say Y or M if you want to add support for Pistachio internal DAC - driver for Imagination Technologies Pistachio internal DAC device. diff --git a/src/linux/sound/soc/intel/Kconfig b/src/linux/sound/soc/intel/Kconfig deleted file mode 100644 index fd5d1e0..0000000 --- a/src/linux/sound/soc/intel/Kconfig +++ /dev/null @@ -1,262 +0,0 @@ -config SND_MFLD_MACHINE - tristate "SOC Machine Audio driver for Intel Medfield MID platform" - depends on INTEL_SCU_IPC - select SND_SOC_SN95031 - select SND_SST_MFLD_PLATFORM - select SND_SST_IPC_PCI - help - This adds support for ASoC machine driver for Intel(R) MID Medfield platform - used as alsa device in audio substem in Intel(R) MID devices - Say Y if you have such a device. - If unsure select "N". - -config SND_SST_MFLD_PLATFORM - tristate - select SND_SOC_COMPRESS - -config SND_SST_IPC - tristate - -config SND_SST_IPC_PCI - tristate - select SND_SST_IPC - -config SND_SST_IPC_ACPI - tristate - select SND_SST_IPC - select SND_SOC_INTEL_SST - select IOSF_MBI - -config SND_SOC_INTEL_SST - tristate - select SND_SOC_INTEL_SST_ACPI if ACPI - select SND_SOC_INTEL_SST_MATCH if ACPI - depends on (X86 || COMPILE_TEST) - -# firmware stuff depends DW_DMAC_CORE; since there is no depends-on from -# the reverse selection, each machine driver needs to select -# SND_SOC_INTEL_SST_FIRMWARE carefully depending on DW_DMAC_CORE -config SND_SOC_INTEL_SST_FIRMWARE - tristate - -config SND_SOC_INTEL_SST_ACPI - tristate - -config SND_SOC_INTEL_SST_MATCH - tristate - -config SND_SOC_INTEL_HASWELL - tristate - select SND_SOC_INTEL_SST_FIRMWARE - -config SND_SOC_INTEL_BAYTRAIL - tristate - -config SND_SOC_INTEL_HASWELL_MACH - tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint" - depends on X86_INTEL_LPSS && I2C && I2C_DESIGNWARE_PLATFORM - depends on DW_DMAC_CORE - select SND_SOC_INTEL_SST - select SND_SOC_INTEL_HASWELL - select SND_SOC_RT5640 - help - This adds support for the Lynxpoint Audio DSP on Intel(R) Haswell - Ultrabook platforms. - Say Y if you have such a device. - If unsure select "N". - -config SND_SOC_INTEL_BXT_DA7219_MAX98357A_MACH - tristate "ASoC Audio driver for Broxton with DA7219 and MAX98357A in I2S Mode" - depends on X86 && ACPI && I2C - select SND_SOC_INTEL_SST - select SND_SOC_INTEL_SKYLAKE - select SND_SOC_DA7219 - select SND_SOC_MAX98357A - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - select SND_HDA_DSP_LOADER - help - This adds support for ASoC machine driver for Broxton-P platforms - with DA7219 + MAX98357A I2S audio codec. - Say Y if you have such a device. - If unsure select "N". - -config SND_SOC_INTEL_BXT_RT298_MACH - tristate "ASoC Audio driver for Broxton with RT298 I2S mode" - depends on X86 && ACPI && I2C - select SND_SOC_INTEL_SST - select SND_SOC_INTEL_SKYLAKE - select SND_SOC_RT298 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - select SND_HDA_DSP_LOADER - help - This adds support for ASoC machine driver for Broxton platforms - with RT286 I2S audio codec. - Say Y if you have such a device. - If unsure select "N". - -config SND_SOC_INTEL_BYT_RT5640_MACH - tristate "ASoC Audio driver for Intel Baytrail with RT5640 codec" - depends on X86_INTEL_LPSS && I2C - depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n) - select SND_SOC_INTEL_SST - select SND_SOC_INTEL_SST_FIRMWARE - select SND_SOC_INTEL_BAYTRAIL - select SND_SOC_RT5640 - help - This adds audio driver for Intel Baytrail platform based boards - with the RT5640 audio codec. This driver is deprecated, use - SND_SOC_INTEL_BYTCR_RT5640_MACH instead for better functionality. - -config SND_SOC_INTEL_BYT_MAX98090_MACH - tristate "ASoC Audio driver for Intel Baytrail with MAX98090 codec" - depends on X86_INTEL_LPSS && I2C - depends on DW_DMAC_CORE && (SND_SST_IPC_ACPI = n) - select SND_SOC_INTEL_SST - select SND_SOC_INTEL_SST_FIRMWARE - select SND_SOC_INTEL_BAYTRAIL - select SND_SOC_MAX98090 - help - This adds audio driver for Intel Baytrail platform based boards - with the MAX98090 audio codec. - -config SND_SOC_INTEL_BDW_RT5677_MACH - tristate "ASoC Audio driver for Intel Broadwell with RT5677 codec" - depends on X86_INTEL_LPSS && GPIOLIB && I2C && DW_DMAC - depends on DW_DMAC_CORE=y - select SND_SOC_INTEL_SST - select SND_SOC_INTEL_HASWELL - select SND_SOC_RT5677 - help - This adds support for Intel Broadwell platform based boards with - the RT5677 audio codec. - -config SND_SOC_INTEL_BROADWELL_MACH - tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint" - depends on X86_INTEL_LPSS && I2C && DW_DMAC && \ - I2C_DESIGNWARE_PLATFORM - depends on DW_DMAC_CORE - select SND_SOC_INTEL_SST - select SND_SOC_INTEL_HASWELL - select SND_SOC_RT286 - help - This adds support for the Wilcatpoint Audio DSP on Intel(R) Broadwell - Ultrabook platforms. - Say Y if you have such a device. - If unsure select "N". - -config SND_SOC_INTEL_BYTCR_RT5640_MACH - tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5640 codec" - depends on X86 && I2C && ACPI - select SND_SOC_RT5640 - select SND_SST_MFLD_PLATFORM - select SND_SST_IPC_ACPI - select SND_SOC_INTEL_SST_MATCH if ACPI - help - This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR - platforms with RT5640 audio codec. - Say Y if you have such a device. - If unsure select "N". - -config SND_SOC_INTEL_BYTCR_RT5651_MACH - tristate "ASoC Audio driver for Intel Baytrail and Baytrail-CR with RT5651 codec" - depends on X86 && I2C && ACPI - select SND_SOC_RT5651 - select SND_SST_MFLD_PLATFORM - select SND_SST_IPC_ACPI - select SND_SOC_INTEL_SST_MATCH if ACPI - help - This adds support for ASoC machine driver for Intel(R) Baytrail and Baytrail-CR - platforms with RT5651 audio codec. - Say Y if you have such a device. - If unsure select "N". - -config SND_SOC_INTEL_CHT_BSW_RT5672_MACH - tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec" - depends on X86_INTEL_LPSS && I2C && ACPI - select SND_SOC_RT5670 - select SND_SST_MFLD_PLATFORM - select SND_SST_IPC_ACPI - select SND_SOC_INTEL_SST_MATCH if ACPI - help - This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell - platforms with RT5672 audio codec. - Say Y if you have such a device. - If unsure select "N". - -config SND_SOC_INTEL_CHT_BSW_RT5645_MACH - tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5645/5650 codec" - depends on X86_INTEL_LPSS && I2C && ACPI - select SND_SOC_RT5645 - select SND_SST_MFLD_PLATFORM - select SND_SST_IPC_ACPI - select SND_SOC_INTEL_SST_MATCH if ACPI - help - This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell - platforms with RT5645/5650 audio codec. - If unsure select "N". - -config SND_SOC_INTEL_CHT_BSW_MAX98090_TI_MACH - tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with MAX98090 & TI codec" - depends on X86_INTEL_LPSS && I2C && ACPI - select SND_SOC_MAX98090 - select SND_SOC_TS3A227E - select SND_SST_MFLD_PLATFORM - select SND_SST_IPC_ACPI - select SND_SOC_INTEL_SST_MATCH if ACPI - help - This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell - platforms with MAX98090 audio codec it also can support TI jack chip as aux device. - If unsure select "N". - -config SND_SOC_INTEL_SKYLAKE - tristate - select SND_HDA_EXT_CORE - select SND_HDA_DSP_LOADER - select SND_SOC_TOPOLOGY - select SND_SOC_INTEL_SST - -config SND_SOC_INTEL_SKL_RT286_MACH - tristate "ASoC Audio driver for SKL with RT286 I2S mode" - depends on X86 && ACPI && I2C - select SND_SOC_INTEL_SST - select SND_SOC_INTEL_SKYLAKE - select SND_SOC_RT286 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC machine driver for Skylake platforms - with RT286 I2S audio codec. - Say Y if you have such a device. - If unsure select "N". - -config SND_SOC_INTEL_SKL_NAU88L25_SSM4567_MACH - tristate "ASoC Audio driver for SKL with NAU88L25 and SSM4567 in I2S Mode" - depends on X86_INTEL_LPSS && I2C - select SND_SOC_INTEL_SST - select SND_SOC_INTEL_SKYLAKE - select SND_SOC_NAU8825 - select SND_SOC_SSM4567 - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for NAU88L25 + SSM4567. - Say Y if you have such a device. - If unsure select "N". - -config SND_SOC_INTEL_SKL_NAU88L25_MAX98357A_MACH - tristate "ASoC Audio driver for SKL with NAU88L25 and MAX98357A in I2S Mode" - depends on X86_INTEL_LPSS && I2C - select SND_SOC_INTEL_SST - select SND_SOC_INTEL_SKYLAKE - select SND_SOC_NAU8825 - select SND_SOC_MAX98357A - select SND_SOC_DMIC - select SND_SOC_HDAC_HDMI - help - This adds support for ASoC Onboard Codec I2S machine driver. This will - create an alsa sound card for NAU88L25 + MAX98357A. - Say Y if you have such a device. - If unsure select "N". diff --git a/src/linux/sound/soc/jz4740/Kconfig b/src/linux/sound/soc/jz4740/Kconfig deleted file mode 100644 index 1a354a6..0000000 --- a/src/linux/sound/soc/jz4740/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -config SND_JZ4740_SOC - tristate "SoC Audio for Ingenic JZ4740 SoC" - depends on MACH_JZ4740 || COMPILE_TEST - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y or M if you want to add support for codecs attached to - the JZ4740 I2S interface. You will also need to select the audio - interfaces to support below. - -if SND_JZ4740_SOC - -config SND_JZ4740_SOC_I2S - tristate "SoC Audio (I2S protocol) for Ingenic JZ4740 SoC" - depends on HAS_IOMEM - help - Say Y if you want to use I2S protocol and I2S codec on Ingenic JZ4740 - based boards. - -config SND_JZ4740_SOC_QI_LB60 - tristate "SoC Audio support for Qi LB60" - depends on HAS_IOMEM - depends on JZ4740_QI_LB60 || COMPILE_TEST - select SND_JZ4740_SOC_I2S - select SND_SOC_JZ4740_CODEC - help - Say Y if you want to add support for ASoC audio on the Qi LB60 board - a.k.a Qi Ben NanoNote. - -endif diff --git a/src/linux/sound/soc/kirkwood/Kconfig b/src/linux/sound/soc/kirkwood/Kconfig deleted file mode 100644 index bc3c7b5..0000000 --- a/src/linux/sound/soc/kirkwood/Kconfig +++ /dev/null @@ -1,18 +0,0 @@ -config SND_KIRKWOOD_SOC - tristate "SoC Audio for the Marvell Kirkwood and Dove chips" - depends on ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST - depends on HAS_DMA - help - Say Y or M if you want to add support for codecs attached to - the Kirkwood I2S interface. You will also need to select the - audio interfaces to support below. - -config SND_KIRKWOOD_SOC_ARMADA370_DB - tristate "SoC Audio support for Armada 370 DB" - depends on SND_KIRKWOOD_SOC && (ARCH_MVEBU || COMPILE_TEST) && I2C - select SND_SOC_CS42L51 - select SND_SOC_SPDIF - help - Say Y if you want to add support for SoC audio on - the Armada 370 Development Board. - diff --git a/src/linux/sound/soc/mediatek/Kconfig b/src/linux/sound/soc/mediatek/Kconfig deleted file mode 100644 index 05cf809..0000000 --- a/src/linux/sound/soc/mediatek/Kconfig +++ /dev/null @@ -1,77 +0,0 @@ -config SND_SOC_MEDIATEK - tristate - -config SND_SOC_MT2701 - tristate "ASoC support for Mediatek MT2701 chip" - depends on ARCH_MEDIATEK - select SND_SOC_MEDIATEK - help - This adds ASoC driver for Mediatek MT2701 boards - that can be used with other codecs. - Select Y if you have such device. - If unsure select "N". - -config SND_SOC_MT2701_CS42448 - tristate "ASoc Audio driver for MT2701 with CS42448 codec" - depends on SND_SOC_MT2701 - select SND_SOC_CS42XX8_I2C - select SND_SOC_BT_SCO - help - This adds ASoC driver for Mediatek MT2701 boards - with the CS42448 codecs. - Select Y if you have such device. - If unsure select "N". - -config SND_SOC_MT8173 - tristate "ASoC support for Mediatek MT8173 chip" - depends on ARCH_MEDIATEK - select SND_SOC_MEDIATEK - help - This adds ASoC platform driver support for Mediatek MT8173 chip - that can be used with other codecs. - Select Y if you have such device. - Ex: MT8173 - -config SND_SOC_MT8173_MAX98090 - tristate "ASoC Audio driver for MT8173 with MAX98090 codec" - depends on SND_SOC_MT8173 && I2C - select SND_SOC_MAX98090 - help - This adds ASoC driver for Mediatek MT8173 boards - with the MAX98090 audio codec. - Select Y if you have such device. - If unsure select "N". - -config SND_SOC_MT8173_RT5650 - tristate "ASoC Audio driver for MT8173 with RT5650 codec" - depends on SND_SOC_MT8173 && I2C - select SND_SOC_RT5645 - select SND_SOC_HDMI_CODEC - help - This adds ASoC driver for Mediatek MT8173 boards - with the RT5650 audio codec. - Select Y if you have such device. - If unsure select "N". - -config SND_SOC_MT8173_RT5650_RT5514 - tristate "ASoC Audio driver for MT8173 with RT5650 RT5514 codecs" - depends on SND_SOC_MT8173 && I2C - select SND_SOC_RT5645 - select SND_SOC_RT5514 - help - This adds ASoC driver for Mediatek MT8173 boards - with the RT5650 and RT5514 codecs. - Select Y if you have such device. - If unsure select "N". - -config SND_SOC_MT8173_RT5650_RT5676 - tristate "ASoC Audio driver for MT8173 with RT5650 RT5676 codecs" - depends on SND_SOC_MT8173 && I2C - select SND_SOC_RT5645 - select SND_SOC_RT5677 - select SND_SOC_HDMI_CODEC - help - This adds ASoC driver for Mediatek MT8173 boards - with the RT5650 and RT5676 codecs. - Select Y if you have such device. - If unsure select "N". diff --git a/src/linux/sound/soc/mxs/Kconfig b/src/linux/sound/soc/mxs/Kconfig deleted file mode 100644 index 219235c..0000000 --- a/src/linux/sound/soc/mxs/Kconfig +++ /dev/null @@ -1,21 +0,0 @@ -menuconfig SND_MXS_SOC - tristate "SoC Audio for Freescale MXS CPUs" - depends on ARCH_MXS || COMPILE_TEST - depends on COMMON_CLK - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y or M if you want to add support for codecs attached to - the MXS SAIF interface. - - -if SND_MXS_SOC - -config SND_SOC_MXS_SGTL5000 - tristate "SoC Audio support for MXS boards with sgtl5000" - depends on I2C - select SND_SOC_SGTL5000 - help - Say Y if you want to add support for SoC audio on an MXS board with - a sgtl5000 codec. - -endif # SND_MXS_SOC diff --git a/src/linux/sound/soc/nuc900/Kconfig b/src/linux/sound/soc/nuc900/Kconfig deleted file mode 100644 index 7f0c954..0000000 --- a/src/linux/sound/soc/nuc900/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -## -## NUC900 series AC97 API -## -config SND_SOC_NUC900 - tristate "SoC Audio for NUC900 series" - depends on ARCH_W90X900 - select SND_SOC_NUC900_AC97 - help - This option enables support for AC97 mode on the NUC900 SoC. - -config SND_SOC_NUC900_AC97 - tristate - select AC97_BUS - select SND_AC97_CODEC - select SND_SOC_AC97_BUS - - -## -## Boards -## -config SND_SOC_NUC900EVB - tristate "NUC900 AC97 support for demo board" - depends on SND_SOC_NUC900 - select SND_SOC_NUC900_AC97 - select SND_SOC_AC97_CODEC - help - Select this option to enable audio (AC97) on the - NUC900 demoboard. diff --git a/src/linux/sound/soc/omap/Kconfig b/src/linux/sound/soc/omap/Kconfig deleted file mode 100644 index f5451c7..0000000 --- a/src/linux/sound/soc/omap/Kconfig +++ /dev/null @@ -1,125 +0,0 @@ -config SND_OMAP_SOC - tristate "SoC Audio for the Texas Instruments OMAP chips" - depends on (ARCH_OMAP && DMA_OMAP) || (ARM && COMPILE_TEST) - select SND_DMAENGINE_PCM - -config SND_OMAP_SOC_DMIC - tristate - -config SND_OMAP_SOC_MCBSP - tristate - -config SND_OMAP_SOC_MCPDM - tristate - -config SND_OMAP_SOC_HDMI_AUDIO - tristate "HDMI audio support for OMAP4+ based SoCs" - depends on SND_OMAP_SOC - help - For HDMI audio to work OMAPDSS HDMI support should be - enabled. - The hdmi audio driver implements cpu-dai component using the - callbacks provided by OMAPDSS and registers the component - under DSS HDMI device. Omap-pcm is registered for platform - component also under DSS HDMI device. Dummy codec is used as - as codec component. The hdmi audio driver implements also - the card and registers it under its own platform device. - The device for the driver is registered by OMAPDSS hdmi - driver. - -config SND_OMAP_SOC_N810 - tristate "SoC Audio support for Nokia N810" - depends on SND_OMAP_SOC && MACH_NOKIA_N810 && I2C - depends on OMAP_MUX - select SND_OMAP_SOC_MCBSP - select SND_SOC_TLV320AIC3X - help - Say Y if you want to add support for SoC audio on Nokia N810. - -config SND_OMAP_SOC_RX51 - tristate "SoC Audio support for Nokia N900 (RX-51)" - depends on SND_OMAP_SOC && ARM && I2C - select SND_OMAP_SOC_MCBSP - select SND_SOC_TLV320AIC3X - select SND_SOC_TPA6130A2 - depends on GPIOLIB - help - Say Y if you want to add support for SoC audio on Nokia N900 - cellphone. - -config SND_OMAP_SOC_AMS_DELTA - tristate "SoC Audio support for Amstrad E3 (Delta) videophone" - depends on SND_OMAP_SOC && MACH_AMS_DELTA && TTY - select SND_OMAP_SOC_MCBSP - select SND_SOC_CX20442 - help - Say Y if you want to add support for SoC audio device connected to - a handset and a speakerphone found on Amstrad E3 (Delta) videophone. - - Note that in order to get those devices fully supported, you have to - build the kernel with standard serial port driver included and - configured for at least 4 ports. Then, from userspace, you must load - a line discipline #19 on the modem (ttyS3) serial line. The simplest - way to achieve this is to install util-linux-ng and use the included - ldattach utility. This can be started automatically from udev, - a simple rule like this one should do the trick (it does for me): - ACTION=="add", KERNEL=="controlC0", \ - RUN+="/usr/sbin/ldattach 19 /dev/ttyS3" - -config SND_OMAP_SOC_OSK5912 - tristate "SoC Audio support for omap osk5912" - depends on SND_OMAP_SOC && MACH_OMAP_OSK && I2C - select SND_OMAP_SOC_MCBSP - select SND_SOC_TLV320AIC23_I2C - help - Say Y if you want to add support for SoC audio on osk5912. - -config SND_OMAP_SOC_AM3517EVM - tristate "SoC Audio support for OMAP3517 / AM3517 EVM" - depends on SND_OMAP_SOC && MACH_OMAP3517EVM && I2C - select SND_OMAP_SOC_MCBSP - select SND_SOC_TLV320AIC23_I2C - help - Say Y if you want to add support for SoC audio on the OMAP3517 / AM3517 - EVM. - -config SND_OMAP_SOC_OMAP_TWL4030 - tristate "SoC Audio support for TI SoC based boards with twl4030 codec" - depends on TWL4030_CORE && SND_OMAP_SOC - select SND_OMAP_SOC_MCBSP - select SND_SOC_TWL4030 - help - Say Y if you want to add support for SoC audio on TI SoC based boards - using twl4030 as c codec. This driver currently supports: - - Beagleboard or Devkit8000 - - Gumstix Overo or CompuLab CM-T35/CM-T3730 - - IGEP v2 - - OMAP3EVM - - SDP3430 - - Zoom2 - -config SND_OMAP_SOC_OMAP_ABE_TWL6040 - tristate "SoC Audio support for OMAP boards using ABE and twl6040 codec" - depends on TWL6040_CORE && SND_OMAP_SOC && COMMON_CLK - depends on ARCH_OMAP4 || (SOC_OMAP5 && MFD_PALMAS) || COMPILE_TEST - select SND_OMAP_SOC_DMIC - select SND_OMAP_SOC_MCPDM - select SND_SOC_TWL6040 - select SND_SOC_DMIC - select COMMON_CLK_PALMAS if (SOC_OMAP5 && MFD_PALMAS) - select CLK_TWL6040 - help - Say Y if you want to add support for SoC audio on OMAP boards using - ABE and twl6040 codec. This driver currently supports: - - SDP4430/Blaze boards - - PandaBoard (4430) - - PandaBoardES (4460) - - omap5-uevm (5432) - -config SND_OMAP_SOC_OMAP3_PANDORA - tristate "SoC Audio support for OMAP3 Pandora" - depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA - select SND_OMAP_SOC_MCBSP - select SND_SOC_TWL4030 - help - Say Y if you want to add support for SoC audio on the OMAP3 Pandora. diff --git a/src/linux/sound/soc/pxa/Kconfig b/src/linux/sound/soc/pxa/Kconfig deleted file mode 100644 index 823b5a2..0000000 --- a/src/linux/sound/soc/pxa/Kconfig +++ /dev/null @@ -1,217 +0,0 @@ -config SND_PXA2XX_SOC - tristate "SoC Audio for the Intel PXA2xx chip" - depends on ARCH_PXA - select SND_PXA2XX_LIB - help - Say Y or M if you want to add support for codecs attached to - the PXA2xx AC97, I2S or SSP interface. You will also need - to select the audio interfaces to support below. - -config SND_MMP_SOC - bool "Soc Audio for Marvell MMP chips" - depends on ARCH_MMP - select MMP_SRAM - select SND_SOC_GENERIC_DMAENGINE_PCM - select SND_ARM - help - Say Y if you want to add support for codecs attached to - the MMP SSPA interface. - -config SND_PXA2XX_AC97 - tristate - select SND_AC97_CODEC - -config SND_PXA2XX_SOC_AC97 - tristate - select AC97_BUS - select SND_PXA2XX_LIB_AC97 - select SND_SOC_AC97_BUS - -config SND_PXA2XX_SOC_I2S - tristate - -config SND_PXA_SOC_SSP - tristate - select PXA_SSP - -config SND_MMP_SOC_SSPA - tristate - -config SND_PXA2XX_SOC_CORGI - tristate "SoC Audio support for Sharp Zaurus SL-C7x0" - depends on SND_PXA2XX_SOC && PXA_SHARP_C7xx && I2C - select SND_PXA2XX_SOC_I2S - select SND_SOC_WM8731 - help - Say Y if you want to add support for SoC audio on Sharp - Zaurus SL-C7x0 models (Corgi, Shepherd, Husky). - -config SND_PXA2XX_SOC_SPITZ - tristate "SoC Audio support for Sharp Zaurus SL-Cxx00" - depends on SND_PXA2XX_SOC && PXA_SHARP_Cxx00 && I2C - select SND_PXA2XX_SOC_I2S - select SND_SOC_WM8750 - help - Say Y if you want to add support for SoC audio on Sharp - Zaurus SL-Cxx00 models (Spitz, Borzoi and Akita). - -config SND_PXA2XX_SOC_Z2 - tristate "SoC Audio support for Zipit Z2" - depends on SND_PXA2XX_SOC && MACH_ZIPIT2 && I2C - select SND_PXA2XX_SOC_I2S - select SND_SOC_WM8750 - help - Say Y if you want to add support for SoC audio on Zipit Z2. - -config SND_PXA2XX_SOC_POODLE - tristate "SoC Audio support for Poodle" - depends on SND_PXA2XX_SOC && MACH_POODLE && I2C - select SND_PXA2XX_SOC_I2S - select SND_SOC_WM8731 - help - Say Y if you want to add support for SoC audio on Sharp - Zaurus SL-5600 model (Poodle). - -config SND_PXA2XX_SOC_TOSA - tristate "SoC AC97 Audio support for Tosa" - depends on SND_PXA2XX_SOC && MACH_TOSA - depends on MFD_TC6393XB - select SND_PXA2XX_SOC_AC97 - select SND_SOC_WM9712 - help - Say Y if you want to add support for SoC audio on Sharp - Zaurus SL-C6000x models (Tosa). - -config SND_PXA2XX_SOC_E740 - tristate "SoC AC97 Audio support for e740" - depends on SND_PXA2XX_SOC && MACH_E740 - select SND_SOC_WM9705 - select SND_PXA2XX_SOC_AC97 - help - Say Y if you want to add support for SoC audio on the - toshiba e740 PDA - -config SND_PXA2XX_SOC_E750 - tristate "SoC AC97 Audio support for e750" - depends on SND_PXA2XX_SOC && MACH_E750 - select SND_SOC_WM9705 - select SND_PXA2XX_SOC_AC97 - help - Say Y if you want to add support for SoC audio on the - toshiba e750 PDA - -config SND_PXA2XX_SOC_E800 - tristate "SoC AC97 Audio support for e800" - depends on SND_PXA2XX_SOC && MACH_E800 - select SND_SOC_WM9712 - select SND_PXA2XX_SOC_AC97 - help - Say Y if you want to add support for SoC audio on the - Toshiba e800 PDA - -config SND_PXA2XX_SOC_EM_X270 - tristate "SoC Audio support for CompuLab EM-x270, eXeda and CM-X300" - depends on SND_PXA2XX_SOC && (MACH_EM_X270 || MACH_EXEDA || \ - MACH_CM_X300) - select SND_PXA2XX_SOC_AC97 - select SND_SOC_WM9712 - help - Say Y if you want to add support for SoC audio on - CompuLab EM-x270, eXeda and CM-X300 machines. - -config SND_PXA2XX_SOC_PALM27X - bool "SoC Audio support for Palm T|X, T5, E2 and LifeDrive" - depends on SND_PXA2XX_SOC && (MACH_PALMLD || MACH_PALMTX || \ - MACH_PALMT5 || MACH_PALMTE2) - select SND_PXA2XX_SOC_AC97 - select SND_SOC_WM9712 - help - Say Y if you want to add support for SoC audio on - Palm T|X, T5, E2 or LifeDrive handheld computer. - -config SND_PXA910_SOC - tristate "SoC Audio for Marvell PXA910 chip" - depends on ARCH_MMP && SND - select SND_PCM - help - Say Y if you want to add support for SoC audio on the - Marvell PXA910 reference platform. - -config SND_SOC_TTC_DKB - tristate "SoC Audio support for TTC DKB" - depends on SND_PXA910_SOC && MACH_TTC_DKB && I2C=y - select PXA_SSP - select SND_PXA_SOC_SSP - select SND_MMP_SOC - select MFD_88PM860X - select SND_SOC_88PM860X - help - Say Y if you want to add support for SoC audio on TTC DKB - - -config SND_SOC_ZYLONITE - tristate "SoC Audio support for Marvell Zylonite" - depends on SND_PXA2XX_SOC && MACH_ZYLONITE - select SND_PXA2XX_SOC_AC97 - select SND_PXA_SOC_SSP - select SND_SOC_WM9713 - help - Say Y if you want to add support for SoC audio on the - Marvell Zylonite reference platform. - -config SND_SOC_RAUMFELD - tristate "SoC Audio support Raumfeld audio adapter" - depends on SND_PXA2XX_SOC && (MACH_RAUMFELD_SPEAKER || MACH_RAUMFELD_CONNECTOR) - depends on I2C && SPI_MASTER - select SND_PXA_SOC_SSP - select SND_SOC_CS4270 - select SND_SOC_AK4104 - help - Say Y if you want to add support for SoC audio on Raumfeld devices - -config SND_PXA2XX_SOC_HX4700 - tristate "SoC Audio support for HP iPAQ hx4700" - depends on SND_PXA2XX_SOC && MACH_H4700 && I2C - select SND_PXA2XX_SOC_I2S - select SND_SOC_AK4641 - help - Say Y if you want to add support for SoC audio on the - HP iPAQ hx4700. - -config SND_PXA2XX_SOC_MAGICIAN - tristate "SoC Audio support for HTC Magician" - depends on SND_PXA2XX_SOC && MACH_MAGICIAN && I2C - select SND_PXA2XX_SOC_I2S - select SND_PXA_SOC_SSP - select SND_SOC_UDA1380 - help - Say Y if you want to add support for SoC audio on the - HTC Magician. - -config SND_PXA2XX_SOC_MIOA701 - tristate "SoC Audio support for MIO A701" - depends on SND_PXA2XX_SOC && MACH_MIOA701 - select SND_PXA2XX_SOC_AC97 - select SND_SOC_WM9713 - help - Say Y if you want to add support for SoC audio on the - MIO A701. - -config SND_PXA2XX_SOC_IMOTE2 - tristate "SoC Audio support for IMote 2" - depends on SND_PXA2XX_SOC && MACH_INTELMOTE2 && I2C - select SND_PXA2XX_SOC_I2S - select SND_SOC_WM8940 - help - Say Y if you want to add support for SoC audio on the - IMote 2. - -config SND_MMP_SOC_BROWNSTONE - tristate "SoC Audio support for Marvell Brownstone" - depends on SND_MMP_SOC && MACH_BROWNSTONE && I2C - select SND_MMP_SOC_SSPA - select MFD_WM8994 - select SND_SOC_WM8994 - help - Say Y if you want to add support for SoC audio on the - Marvell Brownstone reference platform. diff --git a/src/linux/sound/soc/qcom/Kconfig b/src/linux/sound/soc/qcom/Kconfig deleted file mode 100644 index 8ec9a07..0000000 --- a/src/linux/sound/soc/qcom/Kconfig +++ /dev/null @@ -1,45 +0,0 @@ -config SND_SOC_QCOM - tristate "ASoC support for QCOM platforms" - depends on ARCH_QCOM || COMPILE_TEST - help - Say Y or M if you want to add support to use audio devices - in Qualcomm Technologies SOC-based platforms. - -config SND_SOC_LPASS_CPU - tristate - select REGMAP_MMIO - -config SND_SOC_LPASS_PLATFORM - tristate - depends on HAS_DMA - select REGMAP_MMIO - -config SND_SOC_LPASS_IPQ806X - tristate - depends on HAS_DMA - select SND_SOC_LPASS_CPU - select SND_SOC_LPASS_PLATFORM - -config SND_SOC_LPASS_APQ8016 - tristate - depends on HAS_DMA - select SND_SOC_LPASS_CPU - select SND_SOC_LPASS_PLATFORM - -config SND_SOC_STORM - tristate "ASoC I2S support for Storm boards" - depends on SND_SOC_QCOM && HAS_DMA - select SND_SOC_LPASS_IPQ806X - select SND_SOC_MAX98357A - help - Say Y or M if you want add support for SoC audio on the - Qualcomm Technologies IPQ806X-based Storm board. - -config SND_SOC_APQ8016_SBC - tristate "SoC Audio support for APQ8016 SBC platforms" - depends on SND_SOC_QCOM && HAS_DMA - select SND_SOC_LPASS_APQ8016 - help - Support for Qualcomm Technologies LPASS audio block in - APQ8016 SOC-based systems. - Say Y if you want to use audio devices on MI2S. diff --git a/src/linux/sound/soc/rockchip/Kconfig b/src/linux/sound/soc/rockchip/Kconfig deleted file mode 100644 index c783f9a..0000000 --- a/src/linux/sound/soc/rockchip/Kconfig +++ /dev/null @@ -1,55 +0,0 @@ -config SND_SOC_ROCKCHIP - tristate "ASoC support for Rockchip" - depends on COMPILE_TEST || ARCH_ROCKCHIP - help - Say Y or M if you want to add support for codecs attached to - the Rockchip SoCs' Audio interfaces. You will also need to - select the audio interfaces to support below. - -config SND_SOC_ROCKCHIP_I2S - tristate "Rockchip I2S Device Driver" - depends on CLKDEV_LOOKUP && SND_SOC_ROCKCHIP - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y or M if you want to add support for I2S driver for - Rockchip I2S device. The device supports upto maximum of - 8 channels each for play and record. - -config SND_SOC_ROCKCHIP_SPDIF - tristate "Rockchip SPDIF Device Driver" - depends on CLKDEV_LOOKUP && SND_SOC_ROCKCHIP - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y or M if you want to add support for SPDIF driver for - Rockchip SPDIF transceiver device. - -config SND_SOC_ROCKCHIP_MAX98090 - tristate "ASoC support for Rockchip boards using a MAX98090 codec" - depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && CLKDEV_LOOKUP - select SND_SOC_ROCKCHIP_I2S - select SND_SOC_MAX98090 - select SND_SOC_TS3A227E - help - Say Y or M here if you want to add support for SoC audio on Rockchip - boards using the MAX98090 codec, such as Veyron. - -config SND_SOC_ROCKCHIP_RT5645 - tristate "ASoC support for Rockchip boards using a RT5645/RT5650 codec" - depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && CLKDEV_LOOKUP - select SND_SOC_ROCKCHIP_I2S - select SND_SOC_RT5645 - help - Say Y or M here if you want to add support for SoC audio on Rockchip - boards using the RT5645/RT5650 codec, such as Veyron. - -config SND_SOC_RK3399_GRU_SOUND - tristate "ASoC support multiple codecs for Rockchip RK3399 GRU boards" - depends on SND_SOC_ROCKCHIP && I2C && GPIOLIB && CLKDEV_LOOKUP && SPI - select SND_SOC_ROCKCHIP_I2S - select SND_SOC_MAX98357A - select SND_SOC_RT5514 - select SND_SOC_DA7219 - select SND_SOC_RT5514_SPI - help - Say Y or M here if you want to add support multiple codecs for SoC - audio on Rockchip RK3399 GRU boards. diff --git a/src/linux/sound/soc/samsung/Kconfig b/src/linux/sound/soc/samsung/Kconfig deleted file mode 100644 index f6023b4..0000000 --- a/src/linux/sound/soc/samsung/Kconfig +++ /dev/null @@ -1,232 +0,0 @@ -menuconfig SND_SOC_SAMSUNG - tristate "ASoC support for Samsung" - depends on (PLAT_SAMSUNG || ARCH_EXYNOS) - select SND_SOC_GENERIC_DMAENGINE_PCM - ---help--- - Say Y or M if you want to add support for codecs attached to - the Samsung SoCs' Audio interfaces. You will also need to - select the audio interfaces to support below. - -if SND_SOC_SAMSUNG - -config SND_S3C24XX_I2S - tristate - -config SND_S3C_I2SV2_SOC - tristate - -config SND_S3C2412_SOC_I2S - tristate - select SND_S3C_I2SV2_SOC - -config SND_SAMSUNG_PCM - tristate "Samsung PCM interface support" - -config SND_SAMSUNG_AC97 - tristate - select SND_SOC_AC97_BUS - -config SND_SAMSUNG_SPDIF - tristate "Samsung SPDIF transmitter support" - select SND_SOC_SPDIF - -config SND_SAMSUNG_I2S - tristate "Samsung I2S interface support" - -config SND_SOC_SAMSUNG_NEO1973_WM8753 - tristate "Audio support for Openmoko Neo1973 Smartphones (GTA02)" - depends on MACH_NEO1973_GTA02 - select SND_S3C24XX_I2S - select SND_SOC_WM8753 - select SND_SOC_BT_SCO - help - Say Y here to enable audio support for the Openmoko Neo1973 - Smartphones. - -config SND_SOC_SAMSUNG_JIVE_WM8750 - tristate "SoC I2S Audio support for Jive" - depends on MACH_JIVE && I2C - select SND_SOC_WM8750 - select SND_S3C2412_SOC_I2S - help - Say Y if you want to add support for SoC audio on the Jive. - -config SND_SOC_SAMSUNG_SMDK_WM8580 - tristate "SoC I2S Audio support for WM8580 on SMDK" - depends on MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 - depends on I2C - select SND_SOC_WM8580 - select SND_SAMSUNG_I2S - help - Say Y if you want to add support for SoC audio on the SMDKs. - -config SND_SOC_SAMSUNG_SMDK_WM8994 - tristate "SoC I2S Audio support for WM8994 on SMDK" - depends on I2C=y - select MFD_WM8994 - select SND_SOC_WM8994 - select SND_SAMSUNG_I2S - help - Say Y if you want to add support for SoC audio on the SMDKs. - -config SND_SOC_SAMSUNG_SMDK2443_WM9710 - tristate "SoC AC97 Audio support for SMDK2443 - WM9710" - depends on MACH_SMDK2443 - select AC97_BUS - select SND_SOC_AC97_CODEC - select SND_SAMSUNG_AC97 - help - Say Y if you want to add support for SoC audio on smdk2443 - with the WM9710. - -config SND_SOC_SAMSUNG_LN2440SBC_ALC650 - tristate "SoC AC97 Audio support for LN2440SBC - ALC650" - depends on ARCH_S3C24XX - select AC97_BUS - select SND_SOC_AC97_CODEC - select SND_SAMSUNG_AC97 - help - Say Y if you want to add support for SoC audio on ln2440sbc - with the ALC650. - -config SND_SOC_SAMSUNG_S3C24XX_UDA134X - tristate "SoC I2S Audio support UDA134X wired to a S3C24XX" - depends on ARCH_S3C24XX - select SND_S3C24XX_I2S - select SND_SOC_L3 - select SND_SOC_UDA134X - -config SND_SOC_SAMSUNG_SIMTEC - tristate - help - Internal node for common S3C24XX/Simtec suppor - -config SND_SOC_SAMSUNG_SIMTEC_TLV320AIC23 - tristate "SoC I2S Audio support for TLV320AIC23 on Simtec boards" - depends on ARCH_S3C24XX && I2C - select SND_S3C24XX_I2S - select SND_SOC_TLV320AIC23_I2C - select SND_SOC_SAMSUNG_SIMTEC - -config SND_SOC_SAMSUNG_SIMTEC_HERMES - tristate "SoC I2S Audio support for Simtec Hermes board" - depends on ARCH_S3C24XX && I2C - select SND_S3C24XX_I2S - select SND_SOC_TLV320AIC3X - select SND_SOC_SAMSUNG_SIMTEC - -config SND_SOC_SAMSUNG_H1940_UDA1380 - tristate "Audio support for the HP iPAQ H1940" - depends on ARCH_H1940 && I2C - select SND_S3C24XX_I2S - select SND_SOC_UDA1380 - help - This driver provides audio support for HP iPAQ h1940 PDA. - -config SND_SOC_SAMSUNG_RX1950_UDA1380 - tristate "Audio support for the HP iPAQ RX1950" - depends on MACH_RX1950 && I2C - select SND_S3C24XX_I2S - select SND_SOC_UDA1380 - help - This driver provides audio support for HP iPAQ RX1950 PDA. - -config SND_SOC_SAMSUNG_SMDK_WM9713 - tristate "SoC AC97 Audio support for SMDK with WM9713" - depends on MACH_SMDK6410 || MACH_SMDKC100 || MACH_SMDKV210 || MACH_SMDKC110 - select SND_SOC_WM9713 - select SND_SAMSUNG_AC97 - help - Say Y if you want to add support for SoC audio on the SMDK. - -config SND_SOC_SMARTQ - tristate "SoC I2S Audio support for SmartQ board" - depends on MACH_SMARTQ && I2C - select SND_SAMSUNG_I2S - select SND_SOC_WM8750 - -config SND_SOC_SAMSUNG_SMDK_SPDIF - tristate "SoC S/PDIF Audio support for SMDK" - select SND_SAMSUNG_SPDIF - help - Say Y if you want to add support for SoC S/PDIF audio on the SMDK. - -config SND_SOC_SMDK_WM8580_PCM - tristate "SoC PCM Audio support for WM8580 on SMDK" - depends on MACH_SMDKV210 || MACH_SMDKC110 - depends on I2C - select SND_SOC_WM8580 - select SND_SAMSUNG_PCM - help - Say Y if you want to add support for SoC audio on the SMDK. - -config SND_SOC_SMDK_WM8994_PCM - tristate "SoC PCM Audio support for WM8994 on SMDK" - depends on I2C=y - select MFD_WM8994 - select SND_SOC_WM8994 - select SND_SAMSUNG_PCM - help - Say Y if you want to add support for SoC audio on the SMDK - -config SND_SOC_SPEYSIDE - tristate "Audio support for Wolfson Speyside" - depends on I2C && SPI_MASTER - depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST - select SND_SAMSUNG_I2S - select SND_SOC_WM8996 - select SND_SOC_WM9081 - select SND_SOC_WM0010 - select SND_SOC_WM1250_EV1 - -config SND_SOC_TOBERMORY - tristate "Audio support for Wolfson Tobermory" - depends on INPUT && I2C - depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST - select SND_SAMSUNG_I2S - select SND_SOC_WM8962 - -config SND_SOC_BELLS - tristate "Audio support for Wolfson Bells" - depends on MFD_ARIZONA && I2C && SPI_MASTER - depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST - select SND_SAMSUNG_I2S - select SND_SOC_WM5102 - select SND_SOC_WM5110 - select SND_SOC_WM9081 - select SND_SOC_WM0010 - select SND_SOC_WM1250_EV1 - -config SND_SOC_LOWLAND - tristate "Audio support for Wolfson Lowland" - depends on I2C - depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST - select SND_SAMSUNG_I2S - select SND_SOC_WM5100 - select SND_SOC_WM9081 - -config SND_SOC_LITTLEMILL - tristate "Audio support for Wolfson Littlemill" - depends on I2C - depends on MACH_WLF_CRAGG_6410 || COMPILE_TEST - select SND_SAMSUNG_I2S - select MFD_WM8994 - select SND_SOC_WM8994 - -config SND_SOC_SNOW - tristate "Audio support for Google Snow boards" - depends on I2C - select SND_SOC_MAX98090 - select SND_SOC_MAX98095 - select SND_SAMSUNG_I2S - help - Say Y if you want to add audio support for various Snow - boards based on Exynos5 series of SoCs. - -config SND_SOC_ARNDALE_RT5631_ALC5631 - tristate "Audio support for RT5631(ALC5631) on Arndale Board" - depends on I2C - select SND_SAMSUNG_I2S - select SND_SOC_RT5631 - -endif #SND_SOC_SAMSUNG diff --git a/src/linux/sound/soc/sh/Kconfig b/src/linux/sound/soc/sh/Kconfig deleted file mode 100644 index 6db6405..0000000 --- a/src/linux/sound/soc/sh/Kconfig +++ /dev/null @@ -1,66 +0,0 @@ -menu "SoC Audio support for SuperH" - depends on SUPERH || ARCH_SHMOBILE - -config SND_SOC_PCM_SH7760 - tristate "SoC Audio support for Renesas SH7760" - depends on CPU_SUBTYPE_SH7760 && SH_DMABRG - help - Enable this option for SH7760 AC97/I2S audio support. - - -## -## Audio unit modules -## - -config SND_SOC_SH4_HAC - tristate - select AC97_BUS - select SND_SOC_AC97_BUS - -config SND_SOC_SH4_SSI - tristate - -config SND_SOC_SH4_FSI - tristate "SH4 FSI support" - select SND_SIMPLE_CARD - help - This option enables FSI sound support - -config SND_SOC_SH4_SIU - tristate - depends on (SUPERH || ARCH_SHMOBILE) && HAVE_CLK - select DMA_ENGINE - select DMADEVICES - select SH_DMAE - select FW_LOADER - -config SND_SOC_RCAR - tristate "R-Car series SRU/SCU/SSIU/SSI support" - depends on COMMON_CLK - select SND_SIMPLE_CARD - select REGMAP_MMIO - help - This option enables R-Car SRU/SCU/SSIU/SSI sound support - -## -## Boards -## - -config SND_SH7760_AC97 - tristate "SH7760 AC97 sound support" - depends on CPU_SUBTYPE_SH7760 && SND_SOC_PCM_SH7760 - select SND_SOC_SH4_HAC - select SND_SOC_AC97_CODEC - help - This option enables generic sound support for the first - AC97 unit of the SH7760. - -config SND_SIU_MIGOR - tristate "SIU sound support on Migo-R" - depends on SH_MIGOR && I2C - select SND_SOC_SH4_SIU - select SND_SOC_WM8978 - help - This option enables sound support for the SH7722 Migo-R board - -endmenu diff --git a/src/linux/sound/soc/sirf/Kconfig b/src/linux/sound/soc/sirf/Kconfig deleted file mode 100644 index 840058d..0000000 --- a/src/linux/sound/soc/sirf/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -config SND_SOC_SIRF - tristate "SoC Audio for the SiRF SoC chips" - depends on ARCH_SIRF || COMPILE_TEST - select SND_SOC_GENERIC_DMAENGINE_PCM - -config SND_SOC_SIRF_AUDIO - tristate "SoC Audio support for SiRF internal audio codec" - depends on SND_SOC_SIRF - select SND_SOC_SIRF_AUDIO_CODEC - select SND_SOC_SIRF_AUDIO_PORT - -config SND_SOC_SIRF_AUDIO_PORT - select REGMAP_MMIO - tristate - -config SND_SOC_SIRF_USP - tristate "SoC Audio (I2S protocol) for SiRF SoC USP interface" - depends on SND_SOC_SIRF - select REGMAP_MMIO - tristate diff --git a/src/linux/sound/soc/spear/Kconfig b/src/linux/sound/soc/spear/Kconfig deleted file mode 100644 index 4fb9141..0000000 --- a/src/linux/sound/soc/spear/Kconfig +++ /dev/null @@ -1,9 +0,0 @@ -config SND_SPEAR_SOC - tristate - select SND_SOC_GENERIC_DMAENGINE_PCM - -config SND_SPEAR_SPDIF_OUT - tristate - -config SND_SPEAR_SPDIF_IN - tristate diff --git a/src/linux/sound/soc/sti/Kconfig b/src/linux/sound/soc/sti/Kconfig deleted file mode 100644 index 64a6900..0000000 --- a/src/linux/sound/soc/sti/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -# -# STM SoC audio configuration -# -menuconfig SND_SOC_STI - tristate "SoC Audio support for STI System-On-Chip" - depends on SND_SOC - depends on ARCH_STI || COMPILE_TEST - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y if you want to enable ASoC-support for - any of the STI platforms (e.g. STIH416). diff --git a/src/linux/sound/soc/sunxi/Kconfig b/src/linux/sound/soc/sunxi/Kconfig deleted file mode 100644 index dd23682..0000000 --- a/src/linux/sound/soc/sunxi/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -menu "Allwinner SoC Audio support" - depends on ARCH_SUNXI || COMPILE_TEST - -config SND_SUN4I_CODEC - tristate "Allwinner A10 Codec Support" - select SND_SOC_GENERIC_DMAENGINE_PCM - select REGMAP_MMIO - help - Select Y or M to add support for the Codec embedded in the Allwinner - A10 and affiliated SoCs. - -config SND_SUN4I_I2S - tristate "Allwinner A10 I2S Support" - select SND_SOC_GENERIC_DMAENGINE_PCM - select REGMAP_MMIO - help - Say Y or M if you want to add support for codecs attached to - the Allwinner A10 I2S. You will also need to select the - individual machine drivers to support below. - -config SND_SUN4I_SPDIF - tristate "Allwinner A10 SPDIF Support" - depends on OF - select SND_SOC_GENERIC_DMAENGINE_PCM - select REGMAP_MMIO - help - Say Y or M to add support for the S/PDIF audio block in the Allwinner - A10 and affiliated SoCs. -endmenu diff --git a/src/linux/sound/soc/tegra/Kconfig b/src/linux/sound/soc/tegra/Kconfig deleted file mode 100644 index efbe8d4..0000000 --- a/src/linux/sound/soc/tegra/Kconfig +++ /dev/null @@ -1,151 +0,0 @@ -config SND_SOC_TEGRA - tristate "SoC Audio for the Tegra System-on-Chip" - depends on (ARCH_TEGRA && TEGRA20_APB_DMA) || COMPILE_TEST - depends on COMMON_CLK - depends on RESET_CONTROLLER - select REGMAP_MMIO - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y or M here if you want support for SoC audio on Tegra. - -config SND_SOC_TEGRA20_AC97 - tristate - depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC - select SND_SOC_AC97_BUS - select SND_SOC_TEGRA20_DAS - help - Say Y or M if you want to add support for codecs attached to the - Tegra20 AC97 interface. You will also need to select the individual - machine drivers to support below. - -config SND_SOC_TEGRA20_DAS - tristate - depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC - help - Say Y or M if you want to add support for the Tegra20 DAS module. - You will also need to select the individual machine drivers to - support below. - -config SND_SOC_TEGRA20_I2S - tristate - depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC - select SND_SOC_TEGRA20_DAS - help - Say Y or M if you want to add support for codecs attached to the - Tegra20 I2S interface. You will also need to select the individual - machine drivers to support below. - -config SND_SOC_TEGRA20_SPDIF - tristate - depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC - default m - help - Say Y or M if you want to add support for the Tegra20 SPDIF interface. - You will also need to select the individual machine drivers to support - below. - -config SND_SOC_TEGRA30_AHUB - tristate - depends on SND_SOC_TEGRA && ARCH_TEGRA_3x_SOC - help - Say Y or M if you want to add support for the Tegra20 AHUB module. - You will also need to select the individual machine drivers to - support below. - -config SND_SOC_TEGRA30_I2S - tristate - depends on SND_SOC_TEGRA && ARCH_TEGRA_3x_SOC - select SND_SOC_TEGRA30_AHUB - help - Say Y or M if you want to add support for codecs attached to the - Tegra30 I2S interface. You will also need to select the individual - machine drivers to support below. - -config SND_SOC_TEGRA_RT5640 - tristate "SoC Audio support for Tegra boards using an RT5640 codec" - depends on SND_SOC_TEGRA && I2C && GPIOLIB - select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC - select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC - select SND_SOC_RT5640 - help - Say Y or M here if you want to add support for SoC audio on Tegra - boards using the RT5640 codec, such as Dalmore. - -config SND_SOC_TEGRA_WM8753 - tristate "SoC Audio support for Tegra boards using a WM8753 codec" - depends on SND_SOC_TEGRA && I2C && GPIOLIB - select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC - select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC - select SND_SOC_WM8753 - help - Say Y or M here if you want to add support for SoC audio on Tegra - boards using the WM8753 codec, such as Whistler. - -config SND_SOC_TEGRA_WM8903 - tristate "SoC Audio support for Tegra boards using a WM8903 codec" - depends on SND_SOC_TEGRA && I2C && GPIOLIB - select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC - select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC - select SND_SOC_WM8903 - help - Say Y or M here if you want to add support for SoC audio on Tegra - boards using the WM8093 codec. Currently, the supported boards are - Harmony, Ventana, Seaboard, Kaen, and Aebl. - -config SND_SOC_TEGRA_WM9712 - tristate "SoC Audio support for Tegra boards using a WM9712 codec" - depends on SND_SOC_TEGRA && ARCH_TEGRA_2x_SOC && GPIOLIB - select SND_SOC_TEGRA20_AC97 - select SND_SOC_WM9712 - help - Say Y or M here if you want to add support for SoC audio on Tegra - boards using the WM9712 (or compatible) codec. - -config SND_SOC_TEGRA_TRIMSLICE - tristate "SoC Audio support for TrimSlice board" - depends on SND_SOC_TEGRA && I2C - select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC - select SND_SOC_TLV320AIC23_I2C - help - Say Y or M here if you want to add support for SoC audio on the - TrimSlice platform. - -config SND_SOC_TEGRA_ALC5632 - tristate "SoC Audio support for Tegra boards using an ALC5632 codec" - depends on SND_SOC_TEGRA && I2C && GPIOLIB - select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC - select SND_SOC_ALC5632 - help - Say Y or M here if you want to add support for SoC audio on the - Toshiba AC100 netbook. - -config SND_SOC_TEGRA_MAX98090 - tristate "SoC Audio support for Tegra boards using a MAX98090 codec" - depends on SND_SOC_TEGRA && I2C && GPIOLIB - select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC - select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC - select SND_SOC_MAX98090 - help - Say Y or M here if you want to add support for SoC audio on Tegra - boards using the MAX98090 codec, such as Venice2. - -config SND_SOC_TEGRA_RT5677 - tristate "SoC Audio support for Tegra boards using a RT5677 codec" - depends on SND_SOC_TEGRA && I2C && GPIOLIB - select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC - select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC - select SND_SOC_RT5677 - help - Say Y or M here if you want to add support for SoC audio on Tegra - boards using the RT5677 codec, such as Ryu. - -config SND_SOC_TEGRA_SGTL5000 - tristate "SoC Audio support for Tegra boards using a SGTL5000 codec" - depends on SND_SOC_TEGRA && I2C && GPIOLIB - select SND_SOC_TEGRA20_I2S if ARCH_TEGRA_2x_SOC - select SND_SOC_TEGRA30_I2S if ARCH_TEGRA_3x_SOC - select SND_SOC_SGTL5000 - help - Say Y or M here if you want to add support for SoC audio on Tegra - boards using the SGTL5000 codec, such as Apalis T30, Apalis TK1 or - Colibri T30. diff --git a/src/linux/sound/soc/txx9/Kconfig b/src/linux/sound/soc/txx9/Kconfig deleted file mode 100644 index ebc9327..0000000 --- a/src/linux/sound/soc/txx9/Kconfig +++ /dev/null @@ -1,29 +0,0 @@ -## -## TXx9 ACLC -## -config SND_SOC_TXX9ACLC - tristate "SoC Audio for TXx9" - depends on HAS_TXX9_ACLC && TXX9_DMAC - help - This option enables support for the AC Link Controllers in TXx9 SoC. - -config HAS_TXX9_ACLC - bool - -config SND_SOC_TXX9ACLC_AC97 - tristate - select AC97_BUS - select SND_AC97_CODEC - select SND_SOC_AC97_BUS - - -## -## Boards -## -config SND_SOC_TXX9ACLC_GENERIC - tristate "Generic TXx9 ACLC sound machine" - depends on SND_SOC_TXX9ACLC - select SND_SOC_TXX9ACLC_AC97 - select SND_SOC_AC97_CODEC - help - This is a generic AC97 sound machine for use in TXx9 based systems. diff --git a/src/linux/sound/soc/ux500/Kconfig b/src/linux/sound/soc/ux500/Kconfig deleted file mode 100644 index aa50118..0000000 --- a/src/linux/sound/soc/ux500/Kconfig +++ /dev/null @@ -1,32 +0,0 @@ -# -# Ux500 SoC audio configuration -# -menuconfig SND_SOC_UX500 - tristate "SoC Audio support for Ux500 platform" - depends on SND_SOC - depends on MFD_DB8500_PRCMU - help - Say Y if you want to enable ASoC-support for - any of the Ux500 platforms (e.g. U8500). - -config SND_SOC_UX500_PLAT_MSP_I2S - tristate - depends on SND_SOC_UX500 - -config SND_SOC_UX500_PLAT_DMA - tristate "Platform - DB8500 (DMA)" - depends on SND_SOC_UX500 - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y if you want to enable the Ux500 platform-driver. - -config SND_SOC_UX500_MACH_MOP500 - tristate "Machine - MOP500 (Ux500 + AB8500)" - depends on AB8500_CORE && AB8500_GPADC && SND_SOC_UX500 - select SND_SOC_AB8500_CODEC - select SND_SOC_UX500_PLAT_MSP_I2S - select SND_SOC_UX500_PLAT_DMA - help - Select this to enable the MOP500 machine-driver. - This will enable platform-drivers for: Ux500 - This will enable codec-drivers for: AB8500 diff --git a/src/linux/sound/soc/xtensa/Kconfig b/src/linux/sound/soc/xtensa/Kconfig deleted file mode 100644 index c201beb..0000000 --- a/src/linux/sound/soc/xtensa/Kconfig +++ /dev/null @@ -1,7 +0,0 @@ -config SND_SOC_XTFPGA_I2S - tristate "XTFPGA I2S master" - select REGMAP_MMIO - help - Say Y or M if you want to add support for codecs attached to the - I2S interface on XTFPGA daughter board. You will also need to select - the drivers for the rest of XTFPGA audio subsystem. diff --git a/src/linux/sound/soc/zte/Kconfig b/src/linux/sound/soc/zte/Kconfig deleted file mode 100644 index c47eb25..0000000 --- a/src/linux/sound/soc/zte/Kconfig +++ /dev/null @@ -1,17 +0,0 @@ -config ZX296702_SPDIF - tristate "ZX296702 spdif" - depends on SOC_ZX296702 || COMPILE_TEST - depends on COMMON_CLK - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y or M if you want to add support for codecs attached to the - zx296702 spdif interface - -config ZX296702_I2S - tristate "ZX296702 i2s" - depends on SOC_ZX296702 || COMPILE_TEST - depends on COMMON_CLK - select SND_SOC_GENERIC_DMAENGINE_PCM - help - Say Y or M if you want to add support for codecs attached to the - zx296702 i2s interface diff --git a/src/linux/sound/sparc/Kconfig b/src/linux/sound/sparc/Kconfig deleted file mode 100644 index dfcd386..0000000 --- a/src/linux/sound/sparc/Kconfig +++ /dev/null @@ -1,42 +0,0 @@ -# ALSA Sparc drivers - -menuconfig SND_SPARC - bool "Sparc sound devices" - depends on SPARC - default y - help - Support for sound devices specific to Sun SPARC architectures. - -if SND_SPARC - -config SND_SUN_AMD7930 - tristate "Sun AMD7930" - depends on SBUS - select SND_PCM - help - Say Y here to include support for AMD7930 sound device on Sun. - - To compile this driver as a module, choose M here: the module - will be called snd-sun-amd7930. - -config SND_SUN_CS4231 - tristate "Sun CS4231" - select SND_PCM - select SND_TIMER - help - Say Y here to include support for CS4231 sound device on Sun. - - To compile this driver as a module, choose M here: the module - will be called snd-sun-cs4231. - -config SND_SUN_DBRI - tristate "Sun DBRI" - depends on SBUS - select SND_PCM - help - Say Y here to include support for DBRI sound device on Sun. - - To compile this driver as a module, choose M here: the module - will be called snd-sun-dbri. - -endif # SND_SPARC diff --git a/src/linux/sound/spi/Kconfig b/src/linux/sound/spi/Kconfig deleted file mode 100644 index e6485be..0000000 --- a/src/linux/sound/spi/Kconfig +++ /dev/null @@ -1,38 +0,0 @@ -#SPI drivers - -menuconfig SND_SPI - bool "SPI sound devices" - depends on SPI - default y - help - Support for sound devices connected via the SPI bus. - -if SND_SPI - -config SND_AT73C213 - tristate "Atmel AT73C213 DAC driver" - depends on ATMEL_SSC - select SND_PCM - help - Say Y here if you want to use the Atmel AT73C213 external DAC. This - DAC can be found on Atmel development boards. - - This driver requires the Atmel SSC driver for sound sink, a - peripheral found on most AT91 and AVR32 microprocessors. - - To compile this driver as a module, choose M here: the module will be - called snd-at73c213. - -config SND_AT73C213_TARGET_BITRATE - int "Target bitrate for AT73C213" - depends on SND_AT73C213 - default "48000" - range 8000 50000 - help - Sets the target bitrate for the bitrate calculator in the driver. - Limited by hardware to be between 8000 Hz and 50000 Hz. - - Set to 48000 Hz by default. - -endif # SND_SPI - diff --git a/src/linux/sound/usb/Kconfig b/src/linux/sound/usb/Kconfig deleted file mode 100644 index a452ad7..0000000 --- a/src/linux/sound/usb/Kconfig +++ /dev/null @@ -1,166 +0,0 @@ -# ALSA USB drivers - -menuconfig SND_USB - bool "USB sound devices" - depends on USB - default y - help - Support for sound devices connected via the USB bus. - -if SND_USB && USB - -config SND_USB_AUDIO - tristate "USB Audio/MIDI driver" - select SND_HWDEP - select SND_RAWMIDI - select SND_PCM - select BITREVERSE - help - Say Y here to include support for USB audio and USB MIDI - devices. - - To compile this driver as a module, choose M here: the module - will be called snd-usb-audio. - -config SND_USB_UA101 - tristate "Edirol UA-101/UA-1000 driver" - select SND_PCM - select SND_RAWMIDI - help - Say Y here to include support for the Edirol UA-101 and UA-1000 - audio/MIDI interfaces. - - To compile this driver as a module, choose M here: the module - will be called snd-ua101. - -config SND_USB_USX2Y - tristate "Tascam US-122, US-224 and US-428 USB driver" - depends on X86 || PPC || ALPHA - select SND_HWDEP - select SND_RAWMIDI - select SND_PCM - help - Say Y here to include support for Tascam USB Audio/MIDI - interfaces or controllers US-122, US-224 and US-428. - - To compile this driver as a module, choose M here: the module - will be called snd-usb-usx2y. - -config SND_USB_CAIAQ - tristate "Native Instruments USB audio devices" - select SND_HWDEP - select SND_RAWMIDI - select SND_PCM - help - Say Y here to include support for caiaq USB audio interfaces, - namely: - - * Native Instruments RigKontrol2 - * Native Instruments RigKontrol3 - * Native Instruments Kore Controller - * Native Instruments Kore Controller 2 - * Native Instruments Audio Kontrol 1 - * Native Instruments Audio 2 DJ - * Native Instruments Audio 4 DJ - * Native Instruments Audio 8 DJ - * Native Instruments Traktor Audio 2 - * Native Instruments Guitar Rig Session I/O - * Native Instruments Guitar Rig mobile - * Native Instruments Traktor Kontrol X1 - * Native Instruments Traktor Kontrol S4 - * Native Instruments Maschine Controller - - To compile this driver as a module, choose M here: the module - will be called snd-usb-caiaq. - -config SND_USB_CAIAQ_INPUT - bool "enable input device for controllers" - depends on SND_USB_CAIAQ - depends on INPUT=y || INPUT=SND_USB_CAIAQ - help - Say Y here to support input controllers like buttons, knobs, - alpha dials and analog pedals on the following products: - - * Native Instruments RigKontrol2 - * Native Instruments RigKontrol3 - * Native Instruments Kore Controller - * Native Instruments Kore Controller 2 - * Native Instruments Audio Kontrol 1 - * Native Instruments Traktor Kontrol S4 - * Native Instruments Maschine Controller - -config SND_USB_US122L - tristate "Tascam US-122L USB driver" - depends on X86 - select SND_HWDEP - select SND_RAWMIDI - help - Say Y here to include support for Tascam US-122L USB Audio/MIDI - interfaces. - - To compile this driver as a module, choose M here: the module - will be called snd-usb-us122l. - -config SND_USB_6FIRE - tristate "TerraTec DMX 6Fire USB" - select FW_LOADER - select BITREVERSE - select SND_RAWMIDI - select SND_PCM - select SND_VMASTER - help - Say Y here to include support for TerraTec 6fire DMX USB interface. - - You will need firmware files in order to be able to use the device - after it has been coldstarted. An install script for the firmware - and further help can be found at - http://sixfireusb.sourceforge.net - -config SND_USB_HIFACE - tristate "M2Tech hiFace USB-SPDIF driver" - select SND_PCM - help - Select this option to include support for M2Tech hiFace USB-SPDIF - interface. - - This driver supports the original M2Tech hiFace and some other - compatible devices. The supported products are: - - * M2Tech Young - * M2Tech hiFace - * M2Tech North Star - * M2Tech W4S Young - * M2Tech Corrson - * M2Tech AUDIA - * M2Tech SL Audio - * M2Tech Empirical - * M2Tech Rockna - * M2Tech Pathos - * M2Tech Metronome - * M2Tech CAD - * M2Tech Audio Esclusive - * M2Tech Rotel - * M2Tech Eeaudio - * The Chord Company CHORD - * AVA Group A/S Vitus - - To compile this driver as a module, choose M here: the module - will be called snd-usb-hiface. - -config SND_BCD2000 - tristate "Behringer BCD2000 MIDI driver" - select SND_RAWMIDI - help - Say Y here to include MIDI support for the Behringer BCD2000 DJ - controller. - - Audio support is still work-in-progress at - https://github.com/anyc/snd-usb-bcd2000 - - To compile this driver as a module, choose M here: the module - will be called snd-bcd2000. - -source "sound/usb/line6/Kconfig" - -endif # SND_USB - diff --git a/src/linux/sound/usb/line6/Kconfig b/src/linux/sound/usb/line6/Kconfig deleted file mode 100644 index 39b4003..0000000 --- a/src/linux/sound/usb/line6/Kconfig +++ /dev/null @@ -1,43 +0,0 @@ -config SND_USB_LINE6 - tristate - select SND_RAWMIDI - select SND_PCM - select SND_HWDEP - -config SND_USB_POD - tristate "Line 6 POD USB support" - select SND_USB_LINE6 - help - This is a driver for PODxt and other similar devices, - supporting the following features: - * Reading/writing individual parameters - * Reading/writing complete channel, effects setup, and amp - setup data - * Channel switching - * Virtual MIDI interface - * Tuner access - * Playback/capture/mixer device for any ALSA-compatible PCM - audio application - * Signal routing (record clean/processed guitar signal, - re-amping) - -config SND_USB_PODHD - tristate "Line 6 POD X3/HD300/400/500 USB support" - select SND_USB_LINE6 - help - This is a driver for POD X3, HD300, 400 and 500 devices. - -config SND_USB_TONEPORT - tristate "TonePort GX, UX1 and UX2 USB support" - select SND_USB_LINE6 - select NEW_LEDS - select LEDS_CLASS - help - This is a driver for TonePort GX, UX1 and UX2 devices. - -config SND_USB_VARIAX - tristate "Variax Workbench USB support" - select SND_USB_LINE6 - help - This is a driver for Variax Workbench device. - diff --git a/src/linux/tools/accounting/.gitignore b/src/linux/tools/accounting/.gitignore deleted file mode 100644 index 8648520..0000000 --- a/src/linux/tools/accounting/.gitignore +++ /dev/null @@ -1 +0,0 @@ -getdelays diff --git a/src/linux/tools/build/.gitignore b/src/linux/tools/build/.gitignore deleted file mode 100644 index a776371..0000000 --- a/src/linux/tools/build/.gitignore +++ /dev/null @@ -1 +0,0 @@ -fixdep diff --git a/src/linux/tools/build/Build.include b/src/linux/tools/build/Build.include deleted file mode 100644 index 1dcb95e..0000000 --- a/src/linux/tools/build/Build.include +++ /dev/null @@ -1,98 +0,0 @@ -### -# build: Generic definitions -# -# Lots of this code have been borrowed or heavily inspired from parts -# of kbuild code, which is not credited, but mostly developed by: -# -# Copyright (C) Sam Ravnborg , 2015 -# Copyright (C) Linus Torvalds , 2015 -# - -### -# Convenient variables -comma := , -squote := ' - -### -# Name of target with a '.' as filename prefix. foo/bar.o => foo/.bar.o -dot-target = $(dir $@).$(notdir $@) - -### -# filename of target with directory and extension stripped -basetarget = $(basename $(notdir $@)) - -### -# The temporary file to save gcc -MD generated dependencies must not -# contain a comma -depfile = $(subst $(comma),_,$(dot-target).d) - -### -# Check if both arguments has same arguments. Result is empty string if equal. -arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \ - $(filter-out $(cmd_$@), $(cmd_$(1))) ) - -### -# Escape single quote for use in echo statements -escsq = $(subst $(squote),'\$(squote)',$1) - -# Echo command -# Short version is used, if $(quiet) equals `quiet_', otherwise full one. -echo-cmd = $(if $($(quiet)cmd_$(1)),\ - echo ' $(call escsq,$($(quiet)cmd_$(1)))';) - -### -# Replace >$< with >$$< to preserve $ when reloading the .cmd file -# (needed for make) -# Replace >#< with >\#< to avoid starting a comment in the .cmd file -# (needed for make) -# Replace >'< with >'\''< to be able to enclose the whole string in '...' -# (needed for the shell) -make-cmd = $(call escsq,$(subst \#,\\\#,$(subst $$,$$$$,$(cmd_$(1))))) - -### -# Find any prerequisites that is newer than target or that does not exist. -# PHONY targets skipped in both cases. -any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^) - -### -# Copy dependency data into .cmd file -# - gcc -M dependency info -# - command line to create object 'cmd_object :=' -dep-cmd = $(if $(wildcard $(fixdep)), \ - $(fixdep) $(depfile) $@ '$(make-cmd)' > $(dot-target).tmp; \ - rm -f $(depfile); \ - mv -f $(dot-target).tmp $(dot-target).cmd, \ - printf '\# cannot find fixdep (%s)\n' $(fixdep) > $(dot-target).cmd; \ - printf '\# using basic dep data\n\n' >> $(dot-target).cmd; \ - cat $(depfile) >> $(dot-target).cmd; \ - printf '%s\n' 'cmd_$@ := $(make-cmd)' >> $(dot-target).cmd) - -### -# if_changed_dep - execute command if any prerequisite is newer than -# target, or command line has changed and update -# dependencies in the cmd file -if_changed_dep = $(if $(strip $(any-prereq) $(arg-check)), \ - @set -e; \ - $(echo-cmd) $(cmd_$(1)) && $(dep-cmd)) - -# if_changed - execute command if any prerequisite is newer than -# target, or command line has changed -if_changed = $(if $(strip $(any-prereq) $(arg-check)), \ - @set -e; \ - $(echo-cmd) $(cmd_$(1)); \ - printf '%s\n' 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd) - -### -# C flags to be used in rule definitions, includes: -# - depfile generation -# - global $(CFLAGS) -# - per target C flags -# - per object C flags -# - BUILD_STR macro to allow '-D"$(variable)"' constructs -c_flags = -Wp,-MD,$(depfile),-MT,$@ $(CFLAGS) -D"BUILD_STR(s)=\#s" $(CFLAGS_$(basetarget).o) $(CFLAGS_$(obj)) -cxx_flags = -Wp,-MD,$(depfile),-MT,$@ $(CXXFLAGS) -D"BUILD_STR(s)=\#s" $(CXXFLAGS_$(basetarget).o) $(CXXFLAGS_$(obj)) - -### -## HOSTCC C flags - -host_c_flags = -Wp,-MD,$(depfile),-MT,$@ $(CHOSTFLAGS) -D"BUILD_STR(s)=\#s" $(CHOSTFLAGS_$(basetarget).o) $(CHOSTFLAGS_$(obj)) diff --git a/src/linux/tools/build/Makefile.build b/src/linux/tools/build/Makefile.build deleted file mode 100644 index 99c0ccd..0000000 --- a/src/linux/tools/build/Makefile.build +++ /dev/null @@ -1,157 +0,0 @@ -### -# Main build makefile. -# -# Lots of this code have been borrowed or heavily inspired from parts -# of kbuild code, which is not credited, but mostly developed by: -# -# Copyright (C) Sam Ravnborg , 2015 -# Copyright (C) Linus Torvalds , 2015 -# - -PHONY := __build -__build: - -ifeq ($(V),1) - quiet = - Q = -else - quiet=quiet_ - Q=@ -endif - -build-dir := $(srctree)/tools/build - -# Define $(fixdep) for dep-cmd function -ifeq ($(OUTPUT),) - fixdep := $(build-dir)/fixdep -else - fixdep := $(OUTPUT)/fixdep -endif - -# Generic definitions -include $(build-dir)/Build.include - -# do not force detected configuration --include $(OUTPUT).config-detected - -# Init all relevant variables used in build files so -# 1) they have correct type -# 2) they do not inherit any value from the environment -subdir-y := -obj-y := -subdir-y := -subdir-obj-y := - -# Build definitions -build-file := $(dir)/Build --include $(build-file) - -quiet_cmd_flex = FLEX $@ -quiet_cmd_bison = BISON $@ - -# Create directory unless it exists -quiet_cmd_mkdir = MKDIR $(dir $@) - cmd_mkdir = mkdir -p $(dir $@) - rule_mkdir = $(if $(wildcard $(dir $@)),,@$(call echo-cmd,mkdir) $(cmd_mkdir)) - -# Compile command -quiet_cmd_cc_o_c = CC $@ - cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< - -quiet_cmd_host_cc_o_c = HOSTCC $@ - cmd_host_cc_o_c = $(HOSTCC) $(host_c_flags) -c -o $@ $< - -quiet_cmd_cxx_o_c = CXX $@ - cmd_cxx_o_c = $(CXX) $(cxx_flags) -c -o $@ $< - -quiet_cmd_cpp_i_c = CPP $@ - cmd_cpp_i_c = $(CC) $(c_flags) -E -o $@ $< - -quiet_cmd_cc_s_c = AS $@ - cmd_cc_s_c = $(CC) $(c_flags) -S -o $@ $< - -quiet_cmd_gen = GEN $@ - -# Link agregate command -# If there's nothing to link, create empty $@ object. -quiet_cmd_ld_multi = LD $@ - cmd_ld_multi = $(if $(strip $(obj-y)),\ - $(LD) -r -o $@ $(filter $(obj-y),$^),rm -f $@; $(AR) rcs $@) - -quiet_cmd_host_ld_multi = HOSTLD $@ - cmd_host_ld_multi = $(if $(strip $(obj-y)),\ - $(HOSTLD) -r -o $@ $(filter $(obj-y),$^),rm -f $@; $(HOSTAR) rcs $@) - -ifneq ($(filter $(obj),$(hostprogs)),) - host = host_ -endif - -# Build rules -$(OUTPUT)%.o: %.c FORCE - $(call rule_mkdir) - $(call if_changed_dep,$(host)cc_o_c) - -$(OUTPUT)%.o: %.cpp FORCE - $(call rule_mkdir) - $(call if_changed_dep,cxx_o_c) - -$(OUTPUT)%.o: %.S FORCE - $(call rule_mkdir) - $(call if_changed_dep,$(host)cc_o_c) - -$(OUTPUT)%.i: %.c FORCE - $(call rule_mkdir) - $(call if_changed_dep,cpp_i_c) - -$(OUTPUT)%.s: %.S FORCE - $(call rule_mkdir) - $(call if_changed_dep,cpp_i_c) - -$(OUTPUT)%.s: %.c FORCE - $(call rule_mkdir) - $(call if_changed_dep,cc_s_c) - -# Gather build data: -# obj-y - list of build objects -# subdir-y - list of directories to nest -# subdir-obj-y - list of directories objects 'dir/$(obj)-in.o' -obj-y := $($(obj)-y) -subdir-y := $(patsubst %/,%,$(filter %/, $(obj-y))) -obj-y := $(patsubst %/, %/$(obj)-in.o, $(obj-y)) -subdir-obj-y := $(filter %/$(obj)-in.o, $(obj-y)) - -# '$(OUTPUT)/dir' prefix to all objects -objprefix := $(subst ./,,$(OUTPUT)$(dir)/) -obj-y := $(addprefix $(objprefix),$(obj-y)) -subdir-obj-y := $(addprefix $(objprefix),$(subdir-obj-y)) - -# Final '$(obj)-in.o' object -in-target := $(objprefix)$(obj)-in.o - -PHONY += $(subdir-y) - -$(subdir-y): - $(Q)$(MAKE) -f $(build-dir)/Makefile.build dir=$(dir)/$@ obj=$(obj) - -$(sort $(subdir-obj-y)): $(subdir-y) ; - -$(in-target): $(obj-y) FORCE - $(call rule_mkdir) - $(call if_changed,$(host)ld_multi) - -__build: $(in-target) - @: - -PHONY += FORCE -FORCE: - -# Include all cmd files to get all the dependency rules -# for all objects included -targets := $(wildcard $(sort $(obj-y) $(in-target) $(MAKECMDGOALS))) -cmd_files := $(wildcard $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd)) - -ifneq ($(cmd_files),) - include $(cmd_files) -endif - -.PHONY: $(PHONY) diff --git a/src/linux/tools/build/feature/.gitignore b/src/linux/tools/build/feature/.gitignore deleted file mode 100644 index 09b335b..0000000 --- a/src/linux/tools/build/feature/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.d -*.bin -*.output diff --git a/src/linux/tools/cgroup/.gitignore b/src/linux/tools/cgroup/.gitignore deleted file mode 100644 index 633cd9b..0000000 --- a/src/linux/tools/cgroup/.gitignore +++ /dev/null @@ -1 +0,0 @@ -cgroup_event_listener diff --git a/src/linux/tools/laptop/dslm/.gitignore b/src/linux/tools/laptop/dslm/.gitignore deleted file mode 100644 index 9fc984e..0000000 --- a/src/linux/tools/laptop/dslm/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dslm diff --git a/src/linux/tools/lguest/.gitignore b/src/linux/tools/lguest/.gitignore deleted file mode 100644 index 8d9a838..0000000 --- a/src/linux/tools/lguest/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -lguest -include diff --git a/src/linux/tools/lib/bpf/.gitignore b/src/linux/tools/lib/bpf/.gitignore deleted file mode 100644 index f81e549..0000000 --- a/src/linux/tools/lib/bpf/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -libbpf_version.h -FEATURE-DUMP.libbpf diff --git a/src/linux/tools/lib/lockdep/.gitignore b/src/linux/tools/lib/lockdep/.gitignore deleted file mode 100644 index cc0e7a9..0000000 --- a/src/linux/tools/lib/lockdep/.gitignore +++ /dev/null @@ -1 +0,0 @@ -liblockdep.so.* diff --git a/src/linux/tools/lib/traceevent/.gitignore b/src/linux/tools/lib/traceevent/.gitignore deleted file mode 100644 index 9e9f25f..0000000 --- a/src/linux/tools/lib/traceevent/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -TRACEEVENT-CFLAGS -libtraceevent-dynamic-list -libtraceevent.so.* diff --git a/src/linux/tools/lkl/.gitignore b/src/linux/tools/lkl/.gitignore deleted file mode 100644 index 9ad5c0c..0000000 --- a/src/linux/tools/lkl/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -tests/boot -fs2tar -cptofs -cpfromfs -lklfuse -tests/valgrind*.xml -*.exe -*.dll -tests/net-test diff --git a/src/linux/tools/lkl/Makefile b/src/linux/tools/lkl/Makefile deleted file mode 100644 index f055632..0000000 --- a/src/linux/tools/lkl/Makefile +++ /dev/null @@ -1,193 +0,0 @@ -# Do not use make's built-in rules -# (this improves performance and avoids hard-to-debug behaviour); -# also do not print "Entering directory..." messages from make -.SUFFIXES: -MAKEFLAGS += -r --no-print-directory - -ifeq ($(V),1) - Q = -else - Q = @ -endif - -# default target -all: - --include ../scripts/Makefile.include - -# By default we want to use gcc (as does Linux), especially as the clang -# cross toolchain does not use prefixed names -CC := $(CROSS_COMPILE)gcc -LD := $(CROSS_COMPILE)$(LD) -AR := $(CROSS_COMPILE)$(AR) -export CC LD AR - -EXESUF := -SOSUF := .so - -PREFIX := /usr - -ifeq (,$(srctree)) - srctree := $(patsubst %/,%,$(dir $(shell pwd))) - srctree := $(patsubst %/,%,$(dir $(srctree))) -endif -export srctree - - -# Target build configuration - -export CFLAGS += -I$(OUTPUT)/include -Iinclude -Wall -g -O2 -Wextra \ - -Wno-unused-parameter \ - -Wno-missing-field-initializers -fno-strict-aliasing - -OUTPUT_FORMAT = $(shell $(LD) -r -print-output-format) - -ifneq (,$(filter $(OUTPUT_FORMAT),elf64-x86-64 elf32-i386 elf64-x86-64-freebsd elf32-littlearm)) - OUTPUT_DEF = $(shell echo | $(CC) -dM -E -) - CFLAGS += -fPIC -pthread - ifeq (,$(filter $(OUTPUT_DEF),__ANDROID__)) - LDLIBS += -lrt -lpthread - endif - export CONFIG_AUTO_LKL_POSIX_HOST=y - CFLAGS += -DCONFIG_AUTO_LKL_POSIX_HOST - - # Intel DPDK configuration - ifeq ($(dpdk),yes) - export CONFIG_AUTO_LKL_VIRTIO_NET_DPDK=y - RTE_SDK ?= $(shell pwd)/dpdk-2.2.0 - RTE_TARGET ?= build - CFLAGS += -I$(RTE_SDK)/$(RTE_TARGET)/include -msse4.2 -mpopcnt - CFLAGS += -DCONFIG_AUTO_LKL_VIRTIO_NET_DPDK - LDFLAGS +=-L$(RTE_SDK)/$(RTE_TARGET)/lib - LDFLAGS +=-Wl,--whole-archive -ldpdk -Wl,--no-whole-archive -lm -ldl - endif - # Virtual Distributed Ethernet configuration - ifeq ($(vde),yes) - export CONFIG_AUTO_LKL_VIRTIO_NET_VDE=y - CFLAGS += -DCONFIG_AUTO_LKL_VIRTIO_NET_VDE - LDLIBS += $(shell pkg-config --libs vdeplug) - endif -else ifneq (,$(filter $(OUTPUT_FORMAT),pe-i386)) - KOPT = "KALLSYMS_EXTRA_PASS=1" - LDLIBS += -lws2_32 - EXESUF := .exe - SOSUF := .dll - export CONFIG_AUTO_LKL_NT_HOST=y - CFLAGS += -DCONFIG_AUTO_LKL_NT_HOST -else - $(error Unrecognized platform: $(OUTPUT_FORMAT)) -endif - -ifneq ($(OUTPUT),) -OUTPUT := $(OUTPUT)/tools/lkl/ -else -OUTPUT := $(CURDIR)/ -endif -export OUTPUT - -ALL_PROGRAMS := $(OUTPUT)lklfuse$(EXESUF) $(OUTPUT)cptofs$(EXESUF) $(OUTPUT)cpfromfs$(EXESUF) $(OUTPUT)fs2tar$(EXESUF) -ALL_LIBRARIES := $(OUTPUT)liblkl.a $(OUTPUT)liblkl$(SOSUF) $(OUTPUT)liblkl-hijack$(SOSUF) - -static: $(OUTPUT)liblkl.a -shared: $(OUTPUT)liblkl$(SOSUF) -hijack: $(OUTPUT)liblkl-hijack$(SOSUF) - -$(OUTPUT)liblkl$(SOSUF): $(OUTPUT)lib/lkl-in.o $(OUTPUT)lib/lkl.o -$(OUTPUT)liblkl$(SOSUF): LDFLAGS += -shared - -$(OUTPUT)liblkl-hijack$(SOSUF): $(OUTPUT)lib/hijack/hijack-in.o $(OUTPUT)liblkl.a -$(OUTPUT)liblkl-hijack$(SOSUF): LDFLAGS += -shared -nodefaultlibs -$(OUTPUT)liblkl-hijack$(SOSUF): LDLIBS += -ldl - -$(OUTPUT)lklfuse$(EXESUF): $(OUTPUT)lklfuse-in.o $(OUTPUT)liblkl.a -$(OUTPUT)lklfuse$(EXESUF): LDLIBS += -lfuse - -$(OUTPUT)fs2tar$(EXESUF): $(OUTPUT)fs2tar-in.o $(OUTPUT)liblkl.a -$(OUTPUT)fs2tar$(EXESUF): LDLIBS += -larchive -ifneq (,$(filter $(OUTPUT_FORMAT),elf64-x86-64-freebsd)) - $(OUTPUT)fs2tar$(EXESUF): LDLIBS += -largp -endif - -$(OUTPUT)cptofs$(EXESUF): $(OUTPUT)cptofs-in.o $(OUTPUT)liblkl.a -ifneq (,$(filter $(OUTPUT_FORMAT),elf64-x86-64-freebsd)) - $(OUTPUT)cptofs$(EXESUF): LDLIBS += -largp -endif - - -TEST_TARGETS := test valgrind gdb - -$(OUTPUT)tests/boot: $(OUTPUT)tests/boot-in.o $(OUTPUT)liblkl.a -$(OUTPUT)tests/net-test: $(OUTPUT)tests/net-test-in.o $(OUTPUT)liblkl.a -$(TEST_TARGETS): $(OUTPUT)tests/boot $(OUTPUT)tests/net-test - -# because of libdl, liblkl-hijack will not compile on windows -# fortunately, the test target will handle a missing libhijack.so correctly -ifeq (,$(filter $(OUTPUT_FORMAT),pe-i386 elf32-littlearm)) - test: liblkl-hijack$(SOSUF) -endif - -$(OUTPUT)%-in.o: $(OUTPUT)lib/lkl.o FORCE - $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(patsubst %/,%,$(dir $*)) obj=$(notdir $*) - -$(OUTPUT)lib/lkl.o: - $(Q)$(MAKE) -C ../.. ARCH=lkl $(KOPT) defconfig - $(Q)$(MAKE) -C ../.. ARCH=lkl $(KOPT) install INSTALL_PATH=$(OUTPUT) - -$(OUTPUT)liblkl.a: $(OUTPUT)lib/lkl-in.o $(OUTPUT)lib/lkl.o - $(QUIET_AR)$(AR) -rc $@ $^ - -$(OUTPUT)liblkl$(SOSUF) $(OUTPUT)liblkl-hijack$(SOSUF) $(OUTPUT)lklfuse$(EXESUF) $(OUTPUT)fs2tar$(EXESUF) $(OUTPUT)cptofs$(EXESUF) $(OUTPUT)tests/boot $(OUTPUT)tests/net-test: - $(QUIET_LINK)$(CC) $(LDFLAGS) -o $@ $^ $(LDLIBS) - -$(OUTPUT)cpfromfs$(EXESUF): cptofs$(EXESUF) - $(Q)if ! [ -e $@ ]; then ln -s $< $@; fi - -# because of argp and fuse, none of the binaries will compile on windows -# because of libdl, liblkl-hijack will not compile on windows -# arm-android neither for the moment -ifneq (,$(filter $(OUTPUT_FORMAT),pe-i386)) - all: $(filter-out $(OUTPUT)liblkl-hijack$(SOSUF), $(ALL_LIBRARIES)) -else ifneq (,$(filter $(OUTPUT_DEF),__ANDROID__)) - all: $(filter-out $(OUTPUT)liblkl-hijack$(SOSUF), $(ALL_LIBRARIES)) -else ifneq (,$(filter $(OUTPUT_FORMAT),elf32-littlearm)) - all: $(filter-out $(OUTPUT)liblkl-hijack$(SOSUF), $(ALL_LIBRARIES)) $(ALL_PROGRAMS) -else - all: $(ALL_PROGRAMS) $(ALL_LIBRARIES) -endif - -clean: - $(call QUIET_CLEAN, objects)find $(OUTPUT) -name '*.o' -delete -o -name '\.*.cmd'\ - -delete -o -name '\.*.d' -delete - $(call QUIET_CLEAN, headers)$(RM) -r $(OUTPUT)/include/lkl/ - $(call QUIET_CLEAN, "host libraries")$(RM) $(OUTPUT)/liblkl.a liblkl$(SOSUF) - $(call QUIET_CLEAN, "hijack library")$(RM) $(OUTPUT)/liblkl-hijack$(SOSUF) - $(call QUIET_CLEAN, programs)$(RM) $(ALL_PROGRAMS) - $(call QUIET_CLEAN, tests)$(RM) tests/boot tests/net-test - -$(TEST_TARGETS): - $(MAKE) -C tests $@ - - -headers_install: - $(call QUIET_INSTALL, headers) \ - install -d $(DESTDIR)$(PREFIX)/include ; \ - install -m 644 include/lkl.h include/lkl_host.h $(DESTDIR)$(PREFIX)/include ; \ - cp -r $(OUTPUT)include/lkl $(DESTDIR)$(PREFIX)/include - -libraries_install: $(ALL_LIBRARIES) - $(call QUIET_INSTALL, libraries) \ - install -d $(DESTDIR)$(PREFIX)/lib ; \ - install -m 644 $(ALL_LIBRARIES) $(DESTDIR)$(PREFIX)/lib - -programs_install: $(ALL_PROGRAMS) - $(call QUIET_INSTALL, programs) \ - install -d $(DESTDIR)$(PREFIX)/bin ; \ - install -m 755 $(ALL_PROGRAMS) $(DESTDIR)$(PREFIX)/bin - -install: headers_install libraries_install programs_install - - -FORCE: ; -.PHONY: all clean $(TEST_TARGETS) FORCE -.PHONY: headers_install libraries_install programs_install install -.NOTPARALLEL : lib/lkl.o diff --git a/src/linux/tools/lkl/include/.gitignore b/src/linux/tools/lkl/include/.gitignore deleted file mode 100644 index c41a463..0000000 --- a/src/linux/tools/lkl/include/.gitignore +++ /dev/null @@ -1 +0,0 @@ -lkl/ \ No newline at end of file diff --git a/src/linux/tools/lkl/include/lkl.h b/src/linux/tools/lkl/include/lkl.h deleted file mode 100644 index a4fb9f2..0000000 --- a/src/linux/tools/lkl/include/lkl.h +++ /dev/null @@ -1,468 +0,0 @@ -#ifndef _LKL_H -#define _LKL_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define _LKL_LIBC_COMPAT_H - -#ifdef __cplusplus -#define class __lkl__class -#endif -#include -#ifdef __cplusplus -#undef class -#endif - -#if __LKL__BITS_PER_LONG == 64 -#define lkl_sys_stat lkl_sys_newstat -#define lkl_sys_lstat lkl_sys_newlstat -#define lkl_sys_fstatat lkl_sys_newfstatat -#define lkl_sys_fstat lkl_sys_newfstat -#else -#define lkl_stat lkl_stat64 -#define lkl_sys_stat lkl_sys_stat64 -#define lkl_sys_lstat lkl_sys_lstat64 -#define lkl_sys_truncate lkl_sys_truncate64 -#define lkl_sys_ftruncate lkl_sys_ftruncate64 -#define lkl_sys_sendfile lkl_sys_sendfile64 -#define lkl_sys_fstatat lkl_sys_fstatat64 -#define lkl_sys_fstat lkl_sys_fstat64 -#define lkl_sys_fcntl lkl_sys_fcntl64 - -#define lkl_statfs lkl_statfs64 - -static inline int lkl_sys_statfs(const char *path, struct lkl_statfs *buf) -{ - return lkl_sys_statfs64(path, sizeof(*buf), buf); -} - -static inline int lkl_sys_fstatfs(unsigned int fd, struct lkl_statfs *buf) -{ - return lkl_sys_fstatfs64(fd, sizeof(*buf), buf); -} - -#endif - -#ifdef __lkl__NR_llseek -/** - * lkl_sys_lseek - wrapper for lkl_sys_llseek - */ -static inline long long lkl_sys_lseek(unsigned int fd, __lkl__kernel_loff_t off, - unsigned int whence) -{ - long long res; - long ret = lkl_sys_llseek(fd, off >> 32, off & 0xffffffff, &res, whence); - - return ret < 0 ? ret : res; -} -#endif - -static inline void *lkl_sys_mmap(void *addr, size_t length, int prot, int flags, - int fd, off_t offset) -{ - return (void *)lkl_sys_mmap_pgoff((long)addr, length, prot, flags, fd, - offset >> 12); -} - -#define lkl_sys_mmap2 lkl_sys_mmap_pgoff - -/** - * lkl_strerror - returns a string describing the given error code - * - * @err - error code - * @returns - string for the given error code - */ -const char *lkl_strerror(int err); - -/** - * lkl_perror - prints a string describing the given error code - * - * @msg - prefix for the error message - * @err - error code - */ -void lkl_perror(char *msg, int err); - -/** - * struct lkl_dev_blk_ops - block device host operations, defined in lkl_host.h. - */ -struct lkl_dev_blk_ops; - -/** - * lkl_disk - host disk handle - * - * @dev - a pointer to 'virtio_blk_dev' structure for this disk - * @fd - a POSIX file descriptor that can be used by preadv/pwritev - * @handle - an NT file handle that can be used by ReadFile/WriteFile - */ -struct lkl_disk { - void *dev; - union { - int fd; - void *handle; - }; - struct lkl_dev_blk_ops *ops; -}; - -/** - * lkl_disk_add - add a new disk - * - * @disk - the host disk handle - * @returns a disk id (0 is valid) or a strictly negative value in case of error - */ -int lkl_disk_add(struct lkl_disk *disk); - -/** - * lkl_disk_remove - remove a disk - * - * This function makes a cleanup of the @disk's virtio_dev structure - * that was initialized by lkl_disk_add before. - * - * @disk - the host disk handle - */ -int lkl_disk_remove(struct lkl_disk disk); - -/** - * lkl_get_virtio_blkdev - get device id of a disk (partition) - * - * This function returns the device id for the given disk. - * - * @disk_id - the disk id identifying the disk - * @part - disk partition or zero for full disk - * @pdevid - pointer to memory where dev id will be returned - * @returns - 0 on success, a negative value on error - */ -int lkl_get_virtio_blkdev(int disk_id, unsigned int part, uint32_t *pdevid); - - -/** - * lkl_mount_dev - mount a disk - * - * This functions creates a device file for the given disk, creates a mount - * point and mounts the device over the mount point. - * - * @disk_id - the disk id identifying the disk to be mounted - * @part - disk partition or zero for full disk - * @fs_type - filesystem type - * @flags - mount flags - * @opts - additional filesystem specific mount options - * @mnt_str - a string that will be filled by this function with the path where - * the filesystem has been mounted - * @mnt_str_len - size of mnt_str - * @returns - 0 on success, a negative value on error - */ -long lkl_mount_dev(unsigned int disk_id, unsigned int part, const char *fs_type, - int flags, const char *opts, - char *mnt_str, unsigned int mnt_str_len); - -/** - * lkl_umount_dev - umount a disk - * - * This functions umounts the given disks and removes the device file and the - * mount point. - * - * @disk_id - the disk id identifying the disk to be mounted - * @part - disk partition or zero for full disk - * @flags - umount flags - * @timeout_ms - timeout to wait for the kernel to flush closed files so that - * umount can succeed - * @returns - 0 on success, a negative value on error - */ -long lkl_umount_dev(unsigned int disk_id, unsigned int part, int flags, - long timeout_ms); - -/** - * lkl_umount_timeout - umount filesystem with timeout - * - * @path - the path to unmount - * @flags - umount flags - * @timeout_ms - timeout to wait for the kernel to flush closed files so that - * umount can succeed - * @returns - 0 on success, a negative value on error - */ -long lkl_umount_timeout(char *path, int flags, long timeout_ms); - -/** - * lkl_opendir - open a directory - * - * @path - directory path - * @err - pointer to store the error in case of failure - * @returns - a handle to be used when calling lkl_readdir - */ -struct lkl_dir *lkl_opendir(const char *path, int *err); - -/** - * lkl_fdopendir - open a directory - * - * @fd - file descriptor - * @err - pointer to store the error in case of failure - * @returns - a handle to be used when calling lkl_readdir - */ -struct lkl_dir *lkl_fdopendir(int fd, int *err); - -/** - * lkl_rewinddir - reset directory stream - * - * @dir - the directory handler as returned by lkl_opendir - */ -void lkl_rewinddir(struct lkl_dir *dir); - -/** - * lkl_closedir - close the directory - * - * @dir - the directory handler as returned by lkl_opendir - */ -int lkl_closedir(struct lkl_dir *dir); - -/** - * lkl_readdir - get the next available entry of the directory - * - * @dir - the directory handler as returned by lkl_opendir - * @returns - a lkl_dirent64 entry or NULL if the end of the directory stream is - * reached or if an error occurred; check lkl_errdir() to distinguish between - * errors or end of the directory stream - */ -struct lkl_linux_dirent64 *lkl_readdir(struct lkl_dir *dir); - -/** - * lkl_errdir - checks if an error occurred during the last lkl_readdir call - * - * @dir - the directory handler as returned by lkl_opendir - * @returns - 0 if no error occurred, or a negative value otherwise - */ -int lkl_errdir(struct lkl_dir *dir); - -/** - * lkl_dirfd - gets the file descriptor associated with the directory handle - * - * @dir - the directory handle as returned by lkl_opendir - * @returns - a positive value,which is the LKL file descriptor associated with - * the directory handle, or a negative value otherwise - */ -int lkl_dirfd(struct lkl_dir *dir); - -/** - * lkl_if_up - activate network interface - * - * @ifindex - the ifindex of the interface - * @returns - return 0 if no error: otherwise negative value returns - */ -int lkl_if_up(int ifindex); - -/** - * lkl_if_down - deactivate network interface - * - * @ifindex - the ifindex of the interface - * @returns - return 0 if no error: otherwise negative value returns - */ -int lkl_if_down(int ifindex); - -/** - * lkl_if_set_mtu - set MTU on interface - * - * @ifindex - the ifindex of the interface - * @mtu - the requested MTU size - * @returns - return 0 if no error: otherwise negative value returns - */ -int lkl_if_set_mtu(int ifindex, int mtu); - -/** - * lkl_if_set_ipv4 - set IPv4 address on interface - * - * @ifindex - the ifindex of the interface - * @addr - 4-byte IP address (i.e., struct in_addr) - * @netmask_len - prefix length of the @addr - * @returns - return 0 if no error: otherwise negative value returns - */ -int lkl_if_set_ipv4(int ifindex, unsigned int addr, unsigned int netmask_len); - -/** - * lkl_set_ipv4_gateway - add an IPv4 default route - * - * @addr - 4-byte IP address of the gateway (i.e., struct in_addr) - * @returns - return 0 if no error: otherwise negative value returns - */ -int lkl_set_ipv4_gateway(unsigned int addr); - -/** - * lkl_if_set_ipv6 - set IPv6 address on interface - * must be called after interface is up. - * - * @ifindex - the ifindex of the interface - * @addr - 16-byte IPv6 address (i.e., struct in6_addr) - * @netprefix_len - prefix length of the @addr - * @returns - return 0 if no error: otherwise negative value returns - */ -int lkl_if_set_ipv6(int ifindex, void* addr, unsigned int netprefix_len); - -/** - * lkl_set_ipv6_gateway - add an IPv6 default route - * - * @addr - 16-byte IPv6 address of the gateway (i.e., struct in6_addr) - * @returns - return 0 if no error: otherwise negative value returns - */ -int lkl_set_ipv6_gateway(void* addr); - -/** - * lkl_netdev - host network device handle, defined in lkl_host.h. - */ -struct lkl_netdev; - -/** -* lkl_netdev_args - arguments to lkl_netdev_add -* @mac - optional MAC address for the device -* @offload - offload bits for the device -*/ -struct lkl_netdev_args { - void *mac; - unsigned int offload; -}; - -/** - * lkl_netdev_add - add a new network device - * - * Must be called before calling lkl_start_kernel. - * - * @nd - the network device host handle - * @args - arguments that configs the netdev. Can be NULL - * @returns a network device id (0 is valid) or a strictly negative value in - * case of error - */ - -int lkl_netdev_add(struct lkl_netdev *nd, struct lkl_netdev_args* args); - -/** -* lkl_netdev_remove - remove a previously added network device -* -* Attempts to release all resources held by a network device created -* via lkl_netdev_add. -* -* @id - the network device id, as return by @lkl_netdev_add -*/ -void lkl_netdev_remove(int id); - -/** - * lkl_netdev_free - frees a network device - * - * @nd - the network device to free - */ -void lkl_netdev_free(struct lkl_netdev *nd); - -/** - * lkl_netdev_get_ifindex - retrieve the interface index for a given network - * device id - * - * @id - the network device id - * @returns the interface index or a stricly negative value in case of error - */ -int lkl_netdev_get_ifindex(int id); - -/** - * lkl_netdev_tap_create - create TAP net_device for the virtio net backend - * - * @ifname - interface name for the TAP device. need to be configured - * on host in advance - * @offload - offload bits for the device - */ -struct lkl_netdev *lkl_netdev_tap_create(const char *ifname, int offload); - -/** - * lkl_netdev_dpdk_create - create DPDK net_device for the virtio net backend - * - * @ifname - interface name for the DPDK device. The name for DPDK device is - * only used for an internal use. - */ -struct lkl_netdev *lkl_netdev_dpdk_create(const char *ifname); - -/** - * lkl_netdev_vde_create - create VDE net_device for the virtio net backend - * - * @switch_path - path to the VDE switch directory. Needs to be started on host - * in advance. - */ -struct lkl_netdev *lkl_netdev_vde_create(const char *switch_path); - -/** - * lkl_netdev_raw_create - create raw socket net_device for the virtio net - * backend - * - * @ifname - interface name for the snoop device. - */ -struct lkl_netdev *lkl_netdev_raw_create(const char *ifname); - -/** - * lkl_netdev_macvtap_create - create macvtap net_device for the virtio - * net backend - * - * @path - a file name for the macvtap device. need to be configured - * on host in advance - * @offload - offload bits for the device - */ -struct lkl_netdev *lkl_netdev_macvtap_create(const char *path, int offload); - -/* - * lkl_register_dbg_handler- register a signal handler that loads a debug lib. - * - * The signal handler is triggered by Ctrl-Z. It creates a new pthread which - * call dbg_entrance(). - * - * If you run the program from shell script, make sure you ignore SIGTSTP by - * "trap '' TSTP" in the shell script. - */ -void lkl_register_dbg_handler(); - -/** - * lkl_add_neighbor - add a permanent arp entry - * @ifindex - the ifindex of the interface - * @af - address family of the ip address. Must be LKL_AF_INET or LKL_AF_INET6 - * @ip - ip address of the entry in network byte order - * @mac - mac address of the entry - */ -int lkl_add_neighbor(int ifindex, int af, void* addr, void* mac); - -/** - * lkl_mount_fs - mount a file system type like proc, sys - * @fstype - file system type. e.g. proc, sys - * @returns - 0 on success. 1 if it's already mounted. negative on failure. - */ -int lkl_mount_fs(char *fstype); - -/** - * lkl_if_add_ip - add an ip address - * @ifindex - the ifindex of the interface - * @af - address family of the ip address. Must be LKL_AF_INET or LKL_AF_INET6 - * @addr - ip address of the entry in network byte order - * @netprefix_len - prefix length of the @addr - */ -int lkl_if_add_ip(int ifindex, int af, void *addr, unsigned int netprefix_len); - -/** - * lkl_if_del_ip - add an ip address - * @ifindex - the ifindex of the interface - * @af - address family of the ip address. Must be LKL_AF_INET or LKL_AF_INET6 - * @addr - ip address of the entry in network byte order - * @netprefix_len - prefix length of the @addr - */ -int lkl_if_del_ip(int ifindex, int af, void *addr, unsigned int netprefix_len); - -/** - * lkl_if_wait_ipv6_dad - wait for DAD to be done for a ipv6 address - * must be called after interface is up - * - * @ifindex - the ifindex of the interface - * @addr - ip address of the entry in network byte order - */ -int lkl_if_wait_ipv6_dad(int ifindex, void *addr); - -/** - * lkl_set_fd_limit - set the maximum number of file descriptors allowed - * @fd_limit - fd max limit - */ -int lkl_set_fd_limit(unsigned int fd_limit); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/linux/tools/lkl/include/lkl_host.h b/src/linux/tools/lkl/include/lkl_host.h deleted file mode 100644 index 3b85031..0000000 --- a/src/linux/tools/lkl/include/lkl_host.h +++ /dev/null @@ -1,158 +0,0 @@ -#ifndef _LKL_HOST_H -#define _LKL_HOST_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -extern struct lkl_host_operations lkl_host_ops; - -/** - * lkl_printf - print a message via the host print operation - * - * @fmt: printf like format string - */ -int lkl_printf(const char *fmt, ...); - -extern char lkl_virtio_devs[4096]; - -#ifdef CONFIG_AUTO_LKL_POSIX_HOST -#include -#else -struct iovec { - void *iov_base; - size_t iov_len; -}; -#endif - -extern struct lkl_dev_blk_ops lkl_dev_blk_ops; - -/** - * struct lkl_blk_req - block device request - * - * @type: type of request - * @prio: priority of request - currently unused - * @sector: offset in units 512 bytes for read / write requests - * @buf: an array of buffers to be used for read / write requests - * @count: the number of buffers - */ -struct lkl_blk_req { -#define LKL_DEV_BLK_TYPE_READ 0 -#define LKL_DEV_BLK_TYPE_WRITE 1 -#define LKL_DEV_BLK_TYPE_FLUSH 4 -#define LKL_DEV_BLK_TYPE_FLUSH_OUT 5 - unsigned int type; - unsigned int prio; - unsigned long long sector; - struct iovec *buf; - int count; -}; - -/** - * struct lkl_dev_blk_ops - block device host operations - */ -struct lkl_dev_blk_ops { - /** - * @get_capacity: returns the disk capacity in bytes - * - * @disk - the disk for which the capacity is requested; - * @res - pointer to receive the capacity, in bytes; - * @returns - 0 in case of success, negative value in case of error - */ - int (*get_capacity)(struct lkl_disk disk, unsigned long long *res); -#define LKL_DEV_BLK_STATUS_OK 0 -#define LKL_DEV_BLK_STATUS_IOERR 1 -#define LKL_DEV_BLK_STATUS_UNSUP 2 - /** - * @request: issue a block request - * - * @disk - the disk the request is issued to; - * @req - a request described by &struct lkl_blk_req - */ - int (*request)(struct lkl_disk disk, struct lkl_blk_req *req); -}; - -struct lkl_netdev { - struct lkl_dev_net_ops *ops; - uint8_t has_vnet_hdr: 1; -}; - -/** - * struct lkl_dev_net_ops - network device host operations - */ -struct lkl_dev_net_ops { - /** - * @tx: writes a L2 packet into the net device - * - * The data buffer can only hold 0 or 1 complete packets. - * - * @nd - pointer to the network device; - * @iov - pointer to the buffer vector; - * @cnt - # of vectors in iov. - * - * @returns number of bytes transmitted - */ - int (*tx)(struct lkl_netdev *nd, struct iovec *iov, int cnt); - - /** - * @rx: reads a packet from the net device. - * - * It must only read one complete packet if present. - * - * If the buffer is too small for the packet, the implementation may - * decide to drop it or trim it. - * - * @nd - pointer to the network device - * @iov - pointer to the buffer vector to store the packet - * @cnt - # of vectors in iov. - * - * @returns number of bytes read for success or < 0 if error - */ - int (*rx)(struct lkl_netdev *nd, struct iovec *iov, int cnt); - -#define LKL_DEV_NET_POLL_RX 1 -#define LKL_DEV_NET_POLL_TX 2 -#define LKL_DEV_NET_POLL_HUP 4 - - /** - * @poll: polls a net device - * - * Supports the following events: LKL_DEV_NET_POLL_RX - * (readable), LKL_DEV_NET_POLL_TX (writable) or - * LKL_DEV_NET_POLL_HUP (the close operations has been issued - * and we need to clean up). Blocks until one event is - * available. - * - * @nd - pointer to the network device - * - * @returns - LKL_DEV_NET_POLL_RX, LKL_DEV_NET_POLL_TX, - * LKL_DEV_NET_POLL_HUP or a negative value for errors - */ - int (*poll)(struct lkl_netdev *nd); - - /** - * @poll_hup: make poll wakeup and return LKL_DEV_NET_POLL_HUP - * - * @nd - pointer to the network device - */ - void (*poll_hup)(struct lkl_netdev *nd); - - /** - * @free: frees a network device - * - * Implementation must release its resources and free the network device - * structure. - * - * @nd - pointer to the network device - */ - void (*free)(struct lkl_netdev *nd); -}; - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/linux/tools/lkl/lib/.gitignore b/src/linux/tools/lkl/lib/.gitignore deleted file mode 100644 index 427ae02..0000000 --- a/src/linux/tools/lkl/lib/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -lkl.o -liblkl.a - diff --git a/src/linux/tools/lkl/lib/Build b/src/linux/tools/lkl/lib/Build deleted file mode 100644 index 468878b..0000000 --- a/src/linux/tools/lkl/lib/Build +++ /dev/null @@ -1,22 +0,0 @@ -CFLAGS_posix-host.o += -D_FILE_OFFSET_BITS=64 -CFLAGS_virtio_net_vde.o += $(shell pkg-config --cflags vdeplug) -CFLAGS_nt-host.o += -D_WIN32_WINNT=0x0600 - -lkl-y += fs.o -lkl-y += iomem.o -lkl-y += net.o -lkl-y += jmp_buf.o -lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += posix-host.o -lkl-$(CONFIG_AUTO_LKL_NT_HOST) += nt-host.o -lkl-y += utils.o -lkl-y += virtio_blk.o -lkl-y += virtio.o -lkl-y += dbg.o -lkl-y += dbg_handler.o -lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net.o -lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net_fd.o -lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net_tap.o -lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net_raw.o -lkl-$(CONFIG_AUTO_LKL_POSIX_HOST) += virtio_net_macvtap.o -lkl-$(CONFIG_AUTO_LKL_VIRTIO_NET_DPDK) += virtio_net_dpdk.o -lkl-$(CONFIG_AUTO_LKL_VIRTIO_NET_VDE) += virtio_net_vde.o diff --git a/src/linux/tools/lkl/lib/dbg.c b/src/linux/tools/lkl/lib/dbg.c deleted file mode 100644 index 70dcec7..0000000 --- a/src/linux/tools/lkl/lib/dbg.c +++ /dev/null @@ -1,274 +0,0 @@ -#include -#include -#include -#include -#include -#include - -static const char* PROMOTE = "$"; -#define str(x) #x -#define xstr(s) str(s) -#define MAX_BUF 100 -static char cmd[MAX_BUF]; -static char argv[10][MAX_BUF]; -static int argc = 0; -static char cur_dir[MAX_BUF] = "/"; - -static char* normalize_path(const char * src, size_t src_len) { - char* res; - unsigned int res_len; - const char* ptr = src; - const char* end = &src[src_len]; - const char* next; - - res = malloc((src_len > 0 ? src_len : 1) + 1); - res_len = 0; - - for (ptr = src; ptr < end; ptr=next+1) { - size_t len; - next = memchr(ptr, '/', end-ptr); - if (next == NULL) { - next = end; - } - len = next-ptr; - switch(len) { - case 2: - if (ptr[0] == '.' && ptr[1] == '.') { - const char * slash = strrchr(res, '/'); - if (slash != NULL) { - res_len = slash - res; - } - continue; - } - break; - case 1: - if (ptr[0] == '.') { - continue; - } - break; - case 0: - continue; - } - res[res_len++] = '/'; - memcpy(&res[res_len], ptr, len); - res_len += len; - } - if (res_len == 0) { - res[res_len++] = '/'; - } - res[res_len] = '\0'; - return res; -} - -static void build_path(char* path) { - char* npath; - - strcpy(path, cur_dir); - if (argc >=1) { - if (argv[0][0] == '/') strncpy(path, argv[0], LKL_PATH_MAX); - else { - strncat(path, "/", LKL_PATH_MAX - strlen(path) - 1); - strncat(path, argv[0], LKL_PATH_MAX - strlen(path) - 1); - } - } - npath = normalize_path(path, strlen(path)); - strcpy(path, npath); - free(npath); -} - -static void help() { - const char *msg = - "cat FILE\n" - "\tShow content of FILE\n" - "cd [DIR]\n" - "\tChange directory to DIR\n" - "exit\n" - "\tExit the debug session\n" - "help\n" - "\tShow this message\n" - "ls [DIR]\n" - "\tList files in DIR\n" - "mount FSTYPE\n" - "\tMount FSTYPE as /FSTYPE\n" - "overwrite FILE\n" - "\tOverwrite content of FILE from stdin\n" - "pwd\n" - "\tShow current directory\n" - ; - printf("%s", msg); -} - -static void ls() { - char path[LKL_PATH_MAX]; - struct lkl_dir* dir; - struct lkl_linux_dirent64* de; - int err; - - build_path(path); - dir = lkl_opendir(path, &err); - if (dir) { - do { - de = lkl_readdir(dir); - if (de) { - printf("%s\n", de->d_name); - } else { - err = lkl_errdir(dir); - if (err != 0) { - fprintf(stderr, "%s\n", - lkl_strerror(err)); - } - break; - } - } while(1); - lkl_closedir(dir); - } else { - fprintf(stderr, "%s: %s\n", path, lkl_strerror(err)); - } -} - -static void cd() { - char path[LKL_PATH_MAX]; - struct lkl_dir* dir; - int err; - - build_path(path); - dir = lkl_opendir(path, &err); - if (dir) { - strcpy(cur_dir, path); - lkl_closedir(dir); - } else { - fprintf(stderr, "%s: %s\n", path, lkl_strerror(err)); - } -} - -static void mount() { - char* fstype; - int ret = 0; - - if (argc != 1) { - fprintf(stderr, "%s\n", "One argument is needed."); - return; - } - - fstype = argv[0]; - ret = lkl_mount_fs(fstype); - if (ret == 1) - fprintf(stderr, "%s is already mounted.\n", fstype); -} - -static void cat() { - char path[LKL_PATH_MAX]; - int ret; - char buf[1024]; - int fd; - - if (argc != 1) { - fprintf(stderr, "%s\n", "One argument is needed."); - return; - } - - build_path(path); - fd = lkl_sys_open(path, LKL_O_RDONLY, 0); - - if (fd < 0) { - fprintf(stderr, "lkl_sys_open %s: %s\n", - path, lkl_strerror(fd)); - return; - } - - while ((ret = lkl_sys_read(fd, buf, sizeof(buf) - 1)) > 0) { - buf[ret] = '\0'; - printf("%s", buf); - } - - if (ret) { - fprintf(stderr, "lkl_sys_read %s: %s\n", - path, lkl_strerror(ret)); - } - lkl_sys_close(fd); -} - -static void overwrite() { - char path[LKL_PATH_MAX]; - int ret; - int fd; - char buf[1024]; - - build_path(path); - fd = lkl_sys_open(path, LKL_O_WRONLY | LKL_O_CREAT, 0); - if (fd < 0) { - fprintf(stderr, "lkl_sys_open %s: %s\n", - path, lkl_strerror(fd)); - return; - } - printf("Input the content and stop by hitting Ctrl-D:\n"); - while(fgets(buf, 1023, stdin)) { - ret = lkl_sys_write(fd, buf, strlen(buf)); - if (ret < 0) { - fprintf(stderr, "lkl_sys_write %s: %s\n", - path, lkl_strerror(fd)); - } - } - lkl_sys_close(fd); -} - -static void pwd() { - printf("%s\n", cur_dir); -} - -static int parse_cmd(char* input) { - char* token; - token = strtok(input, " "); - if (token) strcpy(cmd, token); - else return -1; - - argc = 0; - token = strtok(NULL, " "); - while(token) { - if (argc >=10) { - fprintf(stderr, "To many args > 10\n"); - return -1; - } - strcpy(argv[argc++], token); - token = strtok(NULL, " "); - } - return 0; -} - -static void run_cmd() { - if(strcmp(cmd, "cat") == 0) cat(); - else if(strcmp(cmd, "cd") == 0) cd(); - else if(strcmp(cmd, "help") == 0) help(); - else if(strcmp(cmd, "ls") == 0) ls(); - else if(strcmp(cmd, "mount") == 0) mount(); - else if(strcmp(cmd, "overwrite") == 0) overwrite(); - else if(strcmp(cmd, "pwd") == 0) pwd(); - else { - fprintf(stderr, "Unknown command: %s\n", cmd); - } -} - -void dbg_entrance() { - char input[MAX_BUF + 1]; - int ret; - int c; - - printf("Type help to see a list of commands\n"); - do { - printf("%s ", PROMOTE); - ret = scanf("%" xstr(MAX_BUF) "[^\n]s", input); - while ((c = getchar()) != '\n' && c != EOF); - if (ret == 0) continue; - if (ret != 1 && errno != EINTR) { - perror("scanf"); - continue; - } - if (strlen(input) == MAX_BUF) { - fprintf(stderr, "Too long input > %d\n", MAX_BUF - 1); - continue; - } - if (parse_cmd(input)) continue; - if (strcmp(cmd, "exit") == 0) break; - run_cmd(); - } while(1); -} diff --git a/src/linux/tools/lkl/lib/dbg_handler.c b/src/linux/tools/lkl/lib/dbg_handler.c deleted file mode 100644 index a88dd91..0000000 --- a/src/linux/tools/lkl/lib/dbg_handler.c +++ /dev/null @@ -1,39 +0,0 @@ -#include -#include - -extern void dbg_entrance(); -static int dbg_running = 0; - -static void dbg_thread(void* arg) { - lkl_host_ops.thread_detach(); - printf("======Enter Debug======\n"); - dbg_entrance(); - printf("======Exit Debug======\n"); - dbg_running = 0; -} - -void dbg_handler(int signum) { - /* We don't care about the possible race on dbg_running. */ - if (dbg_running) { - fprintf(stderr, "A debug lib is running\n"); - return; - } - dbg_running = 1; - lkl_host_ops.thread_create(&dbg_thread, NULL); -} - -#ifndef __MINGW32__ -#include -void lkl_register_dbg_handler() { - struct sigaction sa; - sigemptyset(&sa.sa_mask); - sa.sa_handler = dbg_handler; - if (sigaction(SIGTSTP, &sa, NULL) == -1) { - perror("sigaction"); - } -} -#else -void lkl_register_dbg_handler() { - fprintf(stderr, "lkl_register_dbg_handler is not implemented.\n"); -} -#endif diff --git a/src/linux/tools/lkl/lib/endian.h b/src/linux/tools/lkl/lib/endian.h deleted file mode 100644 index c95bc2b..0000000 --- a/src/linux/tools/lkl/lib/endian.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef _LKL_LIB_ENDIAN_H -#define _LKL_LIB_ENDIAN_H - -#if defined(__FreeBSD__) -#include -#elif defined(__ANDROID__) -#include -#define le16toh(x) letoh16(x) -#define le32toh(x) letoh32(x) -#define le64toh(x) letoh64(x) -#elif defined(__MINGW32__) -#include -#define le32toh(x) (x) -#define le16toh(x) (x) -#define htole32(x) (x) -#define htole16(x) (x) -#define le64toh(x) (x) -#define htobe32(x) htonl(x) -#define htobe16(x) htons(x) -#define be32toh(x) ntohl(x) -#define be16toh(x) ntohs(x) -#else -#include -#endif - -#ifndef htonl -#define htonl(x) htobe32(x) -#define htons(x) htobe16(x) -#define ntohl(x) be32toh(x) -#define ntohs(x) be16toh(x) -#endif - -#endif /* _LKL_LIB_ENDIAN_H */ diff --git a/src/linux/tools/lkl/lib/fs.c b/src/linux/tools/lkl/lib/fs.c deleted file mode 100644 index b56a5a3..0000000 --- a/src/linux/tools/lkl/lib/fs.c +++ /dev/null @@ -1,421 +0,0 @@ -#include -#include -#include -#include -#include - -#include "virtio.h" - -#define MAX_FSTYPE_LEN 50 -int lkl_mount_fs(char *fstype) -{ - char dir[MAX_FSTYPE_LEN+2] = "/"; - int flags = 0, ret = 0; - - strncat(dir, fstype, MAX_FSTYPE_LEN); - - /* Create with regular umask */ - ret = lkl_sys_mkdir(dir, 0xff); - if (ret && ret != -LKL_EEXIST) { - lkl_perror("mount_fs mkdir", ret); - return ret; - } - - /* We have no use for nonzero flags right now */ - ret = lkl_sys_mount("none", dir, fstype, flags, NULL); - if (ret && ret != -LKL_EBUSY) { - lkl_sys_rmdir(dir); - return ret; - } - - if (ret == -LKL_EBUSY) - return 1; - return 0; -} - -static uint32_t new_encode_dev(unsigned int major, unsigned int minor) -{ - return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12); -} - -static int startswith(const char *str, const char *pre) -{ - return strncmp(pre, str, strlen(pre)) == 0; -} - -static int get_node_with_prefix(const char *path, const char *prefix, - char *result, unsigned int result_len) -{ - struct lkl_dir *dir = NULL; - struct lkl_linux_dirent64 *dirent; - int ret; - - dir = lkl_opendir(path, &ret); - if (!dir) - return ret; - - ret = -LKL_ENOENT; - - while ((dirent = lkl_readdir(dir))) { - if (startswith(dirent->d_name, prefix)) { - if (strlen(dirent->d_name) + 1 > result_len) { - ret = -LKL_ENOMEM; - break; - } - memcpy(result, dirent->d_name, strlen(dirent->d_name)); - result[strlen(dirent->d_name)] = '\0'; - ret = 0; - break; - } - } - - lkl_closedir(dir); - - return ret; -} - -static int encode_dev_from_sysfs(const char *sysfs_path, uint32_t *pdevid) -{ - int ret; - long fd; - int major, minor; - char buf[16] = { 0, }; - - fd = lkl_sys_open(sysfs_path, LKL_O_RDONLY, 0); - if (fd < 0) - return fd; - - ret = lkl_sys_read(fd, buf, sizeof(buf)); - if (ret < 0) - goto out_close; - - if (ret == sizeof(buf)) { - ret = -LKL_ENOBUFS; - goto out_close; - } - - ret = sscanf(buf, "%d:%d", &major, &minor); - if (ret != 2) { - ret = -LKL_EINVAL; - goto out_close; - } - - *pdevid = new_encode_dev(major, minor); - ret = 0; - -out_close: - lkl_sys_close(fd); - - return ret; -} - -#define SYSFS_DEV_VIRTIO_PLATFORM_PATH \ - "/sysfs/devices/platform/virtio-mmio.%d.auto" -#define SYSFS_DEV_VIRTIO_CMDLINE_PATH \ - "/sysfs/devices/virtio-mmio-cmdline/virtio-mmio.%d" - -struct abuf { - char *mem, *ptr; - unsigned int len; -}; - -static int snprintf_append(struct abuf *buf, const char *fmt, ...) -{ - int ret; - va_list args; - - if (!buf->ptr) - buf->ptr = buf->mem; - - va_start(args, fmt); - ret = vsnprintf(buf->ptr, buf->len - (buf->ptr - buf->mem), fmt, args); - va_end(args); - - if (ret < 0 || (ret >= (buf->len - (buf->ptr - buf->mem)))) - return -LKL_ENOMEM; - - buf->ptr += ret; - - return 0; -} - -int lkl_get_virtio_blkdev(int disk_id, unsigned int part, uint32_t *pdevid) -{ - char sysfs_path[LKL_PATH_MAX]; - char virtio_name[LKL_PATH_MAX]; - char disk_name[LKL_PATH_MAX]; - struct abuf sysfs_path_buf = { - .mem = sysfs_path, - .len = sizeof(sysfs_path), - }; - char *fmt; - int ret; - - if (disk_id < 0) - return -LKL_EINVAL; - - ret = lkl_mount_fs("sysfs"); - if (ret < 0) - return ret; - - if ((uint32_t) disk_id >= virtio_get_num_bootdevs()) { - fmt = SYSFS_DEV_VIRTIO_PLATFORM_PATH; - disk_id -= virtio_get_num_bootdevs(); - } else { - fmt = SYSFS_DEV_VIRTIO_CMDLINE_PATH; - } - - ret = snprintf_append(&sysfs_path_buf, fmt, disk_id); - if (ret) - return ret; - - ret = get_node_with_prefix(sysfs_path, "virtio", virtio_name, - sizeof(virtio_name)); - if (ret) - return ret; - - ret = snprintf_append(&sysfs_path_buf, "/%s/block", virtio_name); - if (ret) - return ret; - - ret = get_node_with_prefix(sysfs_path, "vd", disk_name, - sizeof(disk_name)); - if (ret) - return ret; - - if (!part) - ret = snprintf_append(&sysfs_path_buf, "/%s/dev", disk_name); - else - ret = snprintf_append(&sysfs_path_buf, "/%s/%s%d/dev", - disk_name, disk_name, part); - if (ret) - return ret; - - return encode_dev_from_sysfs(sysfs_path, pdevid); -} - -long lkl_mount_dev(unsigned int disk_id, unsigned int part, - const char *fs_type, int flags, - const char *data, char *mnt_str, unsigned int mnt_str_len) -{ - char dev_str[] = { "/dev/xxxxxxxx" }; - unsigned int dev; - int err; - char _data[4096]; /* FIXME: PAGE_SIZE is not exported by LKL */ - - if (mnt_str_len < sizeof(dev_str)) - return -LKL_ENOMEM; - - err = lkl_get_virtio_blkdev(disk_id, part, &dev); - if (err < 0) - return err; - - snprintf(dev_str, sizeof(dev_str), "/dev/%08x", dev); - snprintf(mnt_str, mnt_str_len, "/mnt/%08x", dev); - - err = lkl_sys_access("/dev", LKL_S_IRWXO); - if (err < 0) { - if (err == -LKL_ENOENT) - err = lkl_sys_mkdir("/dev", 0700); - if (err < 0) - return err; - } - - err = lkl_sys_mknod(dev_str, LKL_S_IFBLK | 0600, dev); - if (err < 0) - return err; - - err = lkl_sys_access("/mnt", LKL_S_IRWXO); - if (err < 0) { - if (err == -LKL_ENOENT) - err = lkl_sys_mkdir("/mnt", 0700); - if (err < 0) - return err; - } - - err = lkl_sys_mkdir(mnt_str, 0700); - if (err < 0) { - lkl_sys_unlink(dev_str); - return err; - } - - /* kernel always copies a full page */ - if (data) { - strncpy(_data, data, sizeof(_data)); - _data[sizeof(_data) - 1] = 0; - } else { - _data[0] = 0; - } - - err = lkl_sys_mount(dev_str, mnt_str, (char *)fs_type, flags, _data); - if (err < 0) { - lkl_sys_unlink(dev_str); - lkl_sys_rmdir(mnt_str); - return err; - } - - return 0; -} - -long lkl_umount_timeout(char *path, int flags, long timeout_ms) -{ - long incr = 10000000; /* 10 ms */ - struct lkl_timespec ts = { - .tv_sec = 0, - .tv_nsec = incr, - }; - long err; - - do { - err = lkl_sys_umount(path, flags); - if (err == -LKL_EBUSY) { - lkl_sys_nanosleep(&ts, NULL); - timeout_ms -= incr / 1000000; - } - } while (err == -LKL_EBUSY && timeout_ms > 0); - - return err; -} - -long lkl_umount_dev(unsigned int disk_id, unsigned int part, int flags, - long timeout_ms) -{ - char dev_str[] = { "/dev/xxxxxxxx" }; - char mnt_str[] = { "/mnt/xxxxxxxx" }; - unsigned int dev; - int err; - - err = lkl_get_virtio_blkdev(disk_id, part, &dev); - if (err < 0) - return err; - - snprintf(dev_str, sizeof(dev_str), "/dev/%08x", dev); - snprintf(mnt_str, sizeof(mnt_str), "/mnt/%08x", dev); - - err = lkl_umount_timeout(mnt_str, flags, timeout_ms); - if (err) - return err; - - err = lkl_sys_unlink(dev_str); - if (err) - return err; - - return lkl_sys_rmdir(mnt_str); -} - -struct lkl_dir { - int fd; - char buf[1024]; - char *pos; - int len; -}; - -static struct lkl_dir *lkl_dir_alloc(int *err) -{ - struct lkl_dir *dir = lkl_host_ops.mem_alloc(sizeof(struct lkl_dir)); - - if (!dir) { - *err = -LKL_ENOMEM; - return NULL; - } - - dir->len = 0; - dir->pos = NULL; - - return dir; -} - -struct lkl_dir *lkl_opendir(const char *path, int *err) -{ - struct lkl_dir *dir = lkl_dir_alloc(err); - - if (!dir) - return NULL; - - dir->fd = lkl_sys_open(path, LKL_O_RDONLY | LKL_O_DIRECTORY, 0); - if (dir->fd < 0) { - *err = dir->fd; - lkl_host_ops.mem_free(dir); - return NULL; - } - - return dir; -} - -struct lkl_dir *lkl_fdopendir(int fd, int *err) -{ - struct lkl_dir *dir = lkl_dir_alloc(err); - - if (!dir) - return NULL; - - dir->fd = fd; - - return dir; -} - -void lkl_rewinddir(struct lkl_dir *dir) -{ - lkl_sys_lseek(dir->fd, 0, SEEK_SET); - dir->len = 0; - dir->pos = NULL; -} - -int lkl_closedir(struct lkl_dir *dir) -{ - int ret; - - ret = lkl_sys_close(dir->fd); - lkl_host_ops.mem_free(dir); - - return ret; -} - -struct lkl_linux_dirent64 *lkl_readdir(struct lkl_dir *dir) -{ - struct lkl_linux_dirent64 *de; - - if (dir->len < 0) - return NULL; - - if (!dir->pos || dir->pos - dir->buf >= dir->len) - goto read_buf; - -return_de: - de = (struct lkl_linux_dirent64 *)dir->pos; - dir->pos += de->d_reclen; - - return de; - -read_buf: - dir->pos = NULL; - de = (struct lkl_linux_dirent64 *)dir->buf; - dir->len = lkl_sys_getdents64(dir->fd, de, sizeof(dir->buf)); - if (dir->len <= 0) - return NULL; - - dir->pos = dir->buf; - goto return_de; -} - -int lkl_errdir(struct lkl_dir *dir) -{ - if (dir->len >= 0) - return 0; - - return dir->len; -} - -int lkl_dirfd(struct lkl_dir *dir) -{ - return dir->fd; -} - -int lkl_set_fd_limit(unsigned int fd_limit) -{ - struct lkl_rlimit rlim = { - .rlim_cur = fd_limit, - .rlim_max = fd_limit, - }; - return lkl_sys_setrlimit(LKL_RLIMIT_NOFILE, &rlim); -} diff --git a/src/linux/tools/lkl/lib/iomem.c b/src/linux/tools/lkl/lib/iomem.c deleted file mode 100644 index 90545b9..0000000 --- a/src/linux/tools/lkl/lib/iomem.c +++ /dev/null @@ -1,87 +0,0 @@ -#include -#include -#include - -#include "iomem.h" - -#define IOMEM_OFFSET_BITS 24 -#define MAX_IOMEM_REGIONS 256 - -#define IOMEM_ADDR_TO_INDEX(addr) \ - (((uintptr_t)addr) >> IOMEM_OFFSET_BITS) -#define IOMEM_ADDR_TO_OFFSET(addr) \ - (((uintptr_t)addr) & ((1 << IOMEM_OFFSET_BITS) - 1)) -#define IOMEM_INDEX_TO_ADDR(i) \ - (void *)(uintptr_t)(i << IOMEM_OFFSET_BITS) - -static struct iomem_region { - void *data; - int size; - const struct lkl_iomem_ops *ops; -} iomem_regions[MAX_IOMEM_REGIONS]; - -void* register_iomem(void *data, int size, const struct lkl_iomem_ops *ops) -{ - int i; - - if (size > (1 << IOMEM_OFFSET_BITS) - 1) - return NULL; - - for (i = 1; i < MAX_IOMEM_REGIONS; i++) - if (!iomem_regions[i].ops) - break; - - if (i >= MAX_IOMEM_REGIONS) - return NULL; - - iomem_regions[i].data = data; - iomem_regions[i].size = size; - iomem_regions[i].ops = ops; - return IOMEM_INDEX_TO_ADDR(i); -} - -void unregister_iomem(void *base) -{ - unsigned int index = IOMEM_ADDR_TO_INDEX(base); - - if (index >= MAX_IOMEM_REGIONS) { - lkl_printf("%s: invalid iomem_addr %p\n", __func__, base); - return; - } - - iomem_regions[index].size = 0; - iomem_regions[index].ops = NULL; -} - -void *lkl_ioremap(long addr, int size) -{ - int index = IOMEM_ADDR_TO_INDEX(addr); - struct iomem_region *iomem = &iomem_regions[index]; - - if (index >= MAX_IOMEM_REGIONS) - return NULL; - - if (iomem->ops && size <= iomem->size) - return IOMEM_INDEX_TO_ADDR(index); - - return NULL; -} - -int lkl_iomem_access(const volatile void *addr, void *res, int size, int write) -{ - int index = IOMEM_ADDR_TO_INDEX(addr); - struct iomem_region *iomem = &iomem_regions[index]; - int offset = IOMEM_ADDR_TO_OFFSET(addr); - int ret; - - if (index > MAX_IOMEM_REGIONS || !iomem_regions[index].ops || - offset + size > iomem_regions[index].size) - return -1; - - if (write) - ret = iomem->ops->write(iomem->data, offset, res, size); - else - ret = iomem->ops->read(iomem->data, offset, res, size); - - return ret; -} diff --git a/src/linux/tools/lkl/lib/iomem.h b/src/linux/tools/lkl/lib/iomem.h deleted file mode 100644 index 42b1d6a..0000000 --- a/src/linux/tools/lkl/lib/iomem.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _LKL_LIB_IOMEM_H -#define _LKL_LIB_IOMEM_H - -struct lkl_iomem_ops { - int (*read)(void *data, int offset, void *res, int size); - int (*write)(void *data, int offset, void *value, int size); -}; - -void* register_iomem(void *data, int size, const struct lkl_iomem_ops *ops); -void unregister_iomem(void *iomem_base); -void *lkl_ioremap(long addr, int size); -int lkl_iomem_access(const volatile void *addr, void *res, int size, int write); - -#endif /* _LKL_LIB_IOMEM_H */ diff --git a/src/linux/tools/lkl/lib/jmp_buf.c b/src/linux/tools/lkl/lib/jmp_buf.c deleted file mode 100644 index 4cce84b..0000000 --- a/src/linux/tools/lkl/lib/jmp_buf.c +++ /dev/null @@ -1,13 +0,0 @@ -#include -#include - -void jmp_buf_set(struct lkl_jmp_buf *jmpb, void (*f)(void)) -{ - if (!setjmp(*((jmp_buf *)jmpb->buf))) - f(); -} - -void jmp_buf_longjmp(struct lkl_jmp_buf *jmpb, int val) -{ - longjmp(*((jmp_buf *)jmpb->buf), val); -} diff --git a/src/linux/tools/lkl/lib/jmp_buf.h b/src/linux/tools/lkl/lib/jmp_buf.h deleted file mode 100644 index 98ae220..0000000 --- a/src/linux/tools/lkl/lib/jmp_buf.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _LKL_LIB_JMP_BUF_H -#define _LKL_LIB_JMP_BUF_H - -void jmp_buf_set(struct lkl_jmp_buf *jmpb, void (*f)(void)); -void jmp_buf_longjmp(struct lkl_jmp_buf *jmpb, int val); - -#endif diff --git a/src/linux/tools/lkl/lib/net.c b/src/linux/tools/lkl/lib/net.c deleted file mode 100644 index 1e5b7eb..0000000 --- a/src/linux/tools/lkl/lib/net.c +++ /dev/null @@ -1,531 +0,0 @@ -#include -#include -#include "endian.h" -#include - -static inline void set_sockaddr(struct lkl_sockaddr_in *sin, unsigned int addr, - unsigned short port) -{ - sin->sin_family = LKL_AF_INET; - sin->sin_addr.lkl_s_addr = addr; - sin->sin_port = port; -} - -static inline int ifindex_to_name(int sock, struct lkl_ifreq *ifr, int ifindex) -{ - ifr->lkl_ifr_ifindex = ifindex; - return lkl_sys_ioctl(sock, LKL_SIOCGIFNAME, (long)ifr); -} - -int lkl_if_up(int ifindex) -{ - struct lkl_ifreq ifr; - int err, sock = lkl_sys_socket(LKL_AF_INET, LKL_SOCK_DGRAM, 0); - - if (sock < 0) - return sock; - err = ifindex_to_name(sock, &ifr, ifindex); - if (err < 0) - return err; - - err = lkl_sys_ioctl(sock, LKL_SIOCGIFFLAGS, (long)&ifr); - if (!err) { - ifr.lkl_ifr_flags |= LKL_IFF_UP; - err = lkl_sys_ioctl(sock, LKL_SIOCSIFFLAGS, (long)&ifr); - } - - lkl_sys_close(sock); - - return err; -} - -int lkl_if_down(int ifindex) -{ - struct lkl_ifreq ifr; - int err, sock; - - sock = lkl_sys_socket(LKL_AF_INET, LKL_SOCK_DGRAM, 0); - if (sock < 0) - return sock; - - err = ifindex_to_name(sock, &ifr, ifindex); - if (err < 0) - return err; - - err = lkl_sys_ioctl(sock, LKL_SIOCGIFFLAGS, (long)&ifr); - if (!err) { - ifr.lkl_ifr_flags &= ~LKL_IFF_UP; - err = lkl_sys_ioctl(sock, LKL_SIOCSIFFLAGS, (long)&ifr); - } - - lkl_sys_close(sock); - - return err; -} - -int lkl_if_set_mtu(int ifindex, int mtu) -{ - struct lkl_ifreq ifr; - int err, sock; - - sock = lkl_sys_socket(LKL_AF_INET, LKL_SOCK_DGRAM, 0); - if (sock < 0) - return sock; - - err = ifindex_to_name(sock, &ifr, ifindex); - if (err < 0) - return err; - - ifr.lkl_ifr_mtu = mtu; - - err = lkl_sys_ioctl(sock, LKL_SIOCSIFMTU, (long)&ifr); - - lkl_sys_close(sock); - - return err; -} - -int lkl_if_set_ipv4(int ifindex, unsigned int addr, unsigned int netmask_len) -{ - return lkl_if_add_ip(ifindex, LKL_AF_INET, &addr, netmask_len); -} - -int lkl_set_ipv4_gateway(unsigned int addr) -{ - struct lkl_rtentry re; - int err, sock = lkl_sys_socket(LKL_AF_INET, LKL_SOCK_DGRAM, 0); - - if (sock < 0) - return sock; - - memset(&re, 0, sizeof(re)); - set_sockaddr((struct lkl_sockaddr_in *) &re.rt_dst, 0, 0); - set_sockaddr((struct lkl_sockaddr_in *) &re.rt_genmask, 0, 0); - set_sockaddr((struct lkl_sockaddr_in *) &re.rt_gateway, addr, 0); - re.rt_flags = LKL_RTF_UP | LKL_RTF_GATEWAY; - err = lkl_sys_ioctl(sock, LKL_SIOCADDRT, (long)&re); - lkl_sys_close(sock); - - return err; -} - -int lkl_set_ipv6_gateway(void* addr) -{ - int err, sock; - struct lkl_in6_rtmsg route; - - sock = lkl_sys_socket(LKL_AF_INET6, LKL_SOCK_DGRAM, 0); - if (sock < 0) - return sock; - memset(&route, 0, sizeof(route)); - memcpy(&route.rtmsg_gateway, addr, sizeof(struct lkl_in6_addr)); - route.rtmsg_flags = LKL_RTF_UP | LKL_RTF_GATEWAY; - - err = lkl_sys_ioctl(sock, LKL_SIOCADDRT, (long)&route); - lkl_sys_close(sock); - return err; -} - -int lkl_netdev_get_ifindex(int id) -{ - struct lkl_ifreq ifr; - int sock, ret; - - sock = lkl_sys_socket(LKL_AF_INET, LKL_SOCK_DGRAM, 0); - if (sock < 0) - return sock; - - snprintf(ifr.lkl_ifr_name, sizeof(ifr.lkl_ifr_name), "eth%d", id); - ret = lkl_sys_ioctl(sock, LKL_SIOCGIFINDEX, (long)&ifr); - lkl_sys_close(sock); - - return ret < 0 ? ret : ifr.lkl_ifr_ifindex; -} - -static int netlink_sock(unsigned int groups) -{ - struct lkl_sockaddr_nl la; - int fd, err; - - fd = lkl_sys_socket(LKL_AF_NETLINK, LKL_SOCK_DGRAM, LKL_NETLINK_ROUTE); - if (fd < 0) - return fd; - - memset(&la, 0, sizeof(la)); - la.nl_family = LKL_AF_NETLINK; - la.nl_groups = groups; - err = lkl_sys_bind(fd, (struct lkl_sockaddr *)&la, sizeof(la)); - if (err < 0) - return err; - - return fd; -} - -static int parse_rtattr(struct lkl_rtattr *tb[], int max, - struct lkl_rtattr *rta, int len) -{ - unsigned short type; - - memset(tb, 0, sizeof(struct lkl_rtattr *) * (max + 1)); - while (LKL_RTA_OK(rta, len)) { - type = rta->rta_type; - if ((type <= max) && (!tb[type])) - tb[type] = rta; - rta = LKL_RTA_NEXT(rta, len); - } - if (len) - lkl_printf("!!!Deficit %d, rta_len=%d\n", len, - rta->rta_len); - return 0; -} - -struct addr_filter { - unsigned int ifindex; - void *addr; -}; - -static unsigned int get_ifa_flags(struct lkl_ifaddrmsg *ifa, - struct lkl_rtattr *ifa_flags_attr) -{ - return ifa_flags_attr ? *(unsigned int *)LKL_RTA_DATA(ifa_flags_attr) : - ifa->ifa_flags; -} - -/* returns: - * 0 - dad succeed. - * -1 - dad failed or other error. - * 1 - should wait for new msg. - */ -static int check_ipv6_dad(struct lkl_sockaddr_nl *nladdr, - struct lkl_nlmsghdr *n, void *arg) -{ - struct addr_filter *filter = arg; - struct lkl_ifaddrmsg *ifa = LKL_NLMSG_DATA(n); - struct lkl_rtattr *rta_tb[LKL_IFA_MAX+1]; - unsigned int ifa_flags; - int len = n->nlmsg_len; - - if (n->nlmsg_type != LKL_RTM_NEWADDR) - return 1; - - len -= LKL_NLMSG_LENGTH(sizeof(*ifa)); - if (len < 0) { - lkl_printf("BUG: wrong nlmsg len %d\n", len); - return -1; - } - - parse_rtattr(rta_tb, LKL_IFA_MAX, LKL_IFA_RTA(ifa), - n->nlmsg_len - LKL_NLMSG_LENGTH(sizeof(*ifa))); - - ifa_flags = get_ifa_flags(ifa, rta_tb[LKL_IFA_FLAGS]); - - if (ifa->ifa_index != filter->ifindex) - return 1; - if (ifa->ifa_family != LKL_AF_INET6) - return 1; - - if (!rta_tb[LKL_IFA_LOCAL]) - rta_tb[LKL_IFA_LOCAL] = rta_tb[LKL_IFA_ADDRESS]; - - if (!rta_tb[LKL_IFA_LOCAL] || - (filter->addr && memcmp(LKL_RTA_DATA(rta_tb[LKL_IFA_LOCAL]), - filter->addr, 16))) { - return 1; - } - if (ifa_flags & LKL_IFA_F_DADFAILED) { - lkl_printf("IPV6 DAD failed.\n"); - return -1; - } - if (!(ifa_flags & LKL_IFA_F_TENTATIVE)) - return 0; - return 1; -} - -/* Copied from iproute2/lib/ */ -static int rtnl_listen(int fd, int (*handler)(struct lkl_sockaddr_nl *nladdr, - struct lkl_nlmsghdr *, void *), - void *arg) -{ - int status; - struct lkl_nlmsghdr *h; - struct lkl_sockaddr_nl nladdr = { .nl_family = LKL_AF_NETLINK }; - struct lkl_iovec iov; - struct lkl_user_msghdr msg = { - .msg_name = &nladdr, - .msg_namelen = sizeof(nladdr), - .msg_iov = &iov, - .msg_iovlen = 1, - }; - char buf[16384]; - - iov.iov_base = buf; - while (1) { - iov.iov_len = sizeof(buf); - status = lkl_sys_recvmsg(fd, &msg, 0); - - if (status < 0) { - if (status == -LKL_EINTR || status == -LKL_EAGAIN) - continue; - lkl_printf("netlink receive error %s (%d)\n", - lkl_strerror(status), status); - if (status == -LKL_ENOBUFS) - continue; - return status; - } - if (status == 0) { - lkl_printf("EOF on netlink\n"); - return -1; - } - if (msg.msg_namelen != sizeof(nladdr)) { - lkl_printf("Sender address length == %d\n", - msg.msg_namelen); - return -1; - } - - for (h = (struct lkl_nlmsghdr *)buf; - (unsigned int)status >= sizeof(*h);) { - int err; - int len = h->nlmsg_len; - int l = len - sizeof(*h); - - if (l < 0 || len > status) { - if (msg.msg_flags & LKL_MSG_TRUNC) { - lkl_printf("Truncated message\n"); - return -1; - } - lkl_printf("!!!malformed message: len=%d\n", - len); - return -1; - } - - err = handler(&nladdr, h, arg); - if (err <= 0) - return err; - - status -= LKL_NLMSG_ALIGN(len); - h = (struct lkl_nlmsghdr *)((char *)h + - LKL_NLMSG_ALIGN(len)); - } - if (msg.msg_flags & LKL_MSG_TRUNC) { - lkl_printf("Message truncated\n"); - continue; - } - if (status) { - lkl_printf("!!!Remnant of size %d\n", status); - return -1; - } - } -} - -int lkl_if_wait_ipv6_dad(int ifindex, void *addr) -{ - struct addr_filter filter = {.ifindex = ifindex, .addr = addr}; - int fd, ret; - struct { - struct lkl_nlmsghdr nlmsg_info; - struct lkl_ifaddrmsg ifaddrmsg_info; - } req; - - fd = netlink_sock(1 << (LKL_RTNLGRP_IPV6_IFADDR - 1)); - if (fd < 0) - return fd; - - memset(&req, 0, sizeof(req)); - req.nlmsg_info.nlmsg_len = - LKL_NLMSG_LENGTH(sizeof(struct lkl_ifaddrmsg)); - req.nlmsg_info.nlmsg_flags = LKL_NLM_F_REQUEST | LKL_NLM_F_DUMP; - req.nlmsg_info.nlmsg_type = LKL_RTM_GETADDR; - req.ifaddrmsg_info.ifa_family = LKL_AF_INET6; - req.ifaddrmsg_info.ifa_index = ifindex; - ret = lkl_sys_send(fd, &req, req.nlmsg_info.nlmsg_len, 0); - if (ret < 0) { - lkl_perror("lkl_sys_send", ret); - return ret; - } - ret = rtnl_listen(fd, check_ipv6_dad, (void *)&filter); - lkl_sys_close(fd); - return ret; -} - -int lkl_if_set_ipv6(int ifindex, void *addr, unsigned int netprefix_len) -{ - int err = lkl_if_add_ip(ifindex, LKL_AF_INET6, addr, netprefix_len); - if (err) - return err; - return lkl_if_wait_ipv6_dad(ifindex, addr); -} - -/* returns: - * 0 - succeed. - * < 0 - error number. - * 1 - should wait for new msg. - */ -static int check_error(struct lkl_sockaddr_nl *nladdr, struct lkl_nlmsghdr *n, - void *arg) -{ - unsigned int s = *(unsigned int *)arg; - - if (nladdr->nl_pid != 0 || n->nlmsg_seq != s) { - /* Don't forget to skip that message. */ - return 1; - } - - if (n->nlmsg_type == LKL_NLMSG_ERROR) { - struct lkl_nlmsgerr *err = - (struct lkl_nlmsgerr *)LKL_NLMSG_DATA(n); - int l = n->nlmsg_len - sizeof(*n); - - if (l < (int)sizeof(struct lkl_nlmsgerr)) - lkl_printf("ERROR truncated\n"); - else if (!err->error) - return 0; - - lkl_printf("RTNETLINK answers: %s\n", - lkl_strerror(-err->error)); - return err->error; - } - lkl_printf("Unexpected reply!!!\n"); - return -1; -} - -static unsigned int seq; -static int rtnl_talk(int fd, struct lkl_nlmsghdr *n) -{ - int status; - struct lkl_sockaddr_nl nladdr = {.nl_family = LKL_AF_NETLINK}; - struct lkl_iovec iov = {.iov_base = (void *)n, .iov_len = n->nlmsg_len}; - struct lkl_user_msghdr msg = { - .msg_name = &nladdr, - .msg_namelen = sizeof(nladdr), - .msg_iov = &iov, - .msg_iovlen = 1, - }; - - n->nlmsg_seq = seq; - n->nlmsg_flags |= LKL_NLM_F_ACK; - - status = lkl_sys_sendmsg(fd, &msg, 0); - if (status < 0) { - lkl_perror("Cannot talk to rtnetlink", status); - return status; - } - - status = rtnl_listen(fd, check_error, (void *)&seq); - seq++; - return status; -} - -static int addattr_l(struct lkl_nlmsghdr *n, unsigned int maxlen, - int type, const void *data, int alen) -{ - int len = LKL_RTA_LENGTH(alen); - struct lkl_rtattr *rta; - - if (LKL_NLMSG_ALIGN(n->nlmsg_len) + LKL_RTA_ALIGN(len) > maxlen) { - lkl_printf("addattr_l ERROR: message exceeded bound of %d\n", - maxlen); - return -1; - } - rta = ((struct lkl_rtattr *) (((void *) (n)) + - LKL_NLMSG_ALIGN(n->nlmsg_len))); - rta->rta_type = type; - rta->rta_len = len; - memcpy(LKL_RTA_DATA(rta), data, alen); - n->nlmsg_len = LKL_NLMSG_ALIGN(n->nlmsg_len) + LKL_RTA_ALIGN(len); - return 0; -} - -int lkl_add_neighbor(int ifindex, int af, void* ip, void* mac) -{ - struct { - struct lkl_nlmsghdr n; - struct lkl_ndmsg r; - char buf[1024]; - } req = { - .n.nlmsg_len = LKL_NLMSG_LENGTH(sizeof(struct lkl_ndmsg)), - .n.nlmsg_type = LKL_RTM_NEWNEIGH, - .n.nlmsg_flags = LKL_NLM_F_REQUEST | - LKL_NLM_F_CREATE | LKL_NLM_F_REPLACE, - .r.ndm_family = af, - .r.ndm_ifindex = ifindex, - .r.ndm_state = LKL_NUD_PERMANENT, - - }; - int err, addr_sz; - int fd; - - if (af == LKL_AF_INET) - addr_sz = 4; - else if (af == LKL_AF_INET6) - addr_sz = 16; - else { - lkl_printf("Bad address family: %d\n", af); - return -1; - } - - fd = netlink_sock(0); - if (fd < 0) - return fd; - - // create the IP attribute - addattr_l(&req.n, sizeof(req), LKL_NDA_DST, ip, addr_sz); - - // create the MAC attribute - addattr_l(&req.n, sizeof(req), LKL_NDA_LLADDR, mac, 6); - - err = rtnl_talk(fd, &req.n); - lkl_sys_close(fd); - return err; -} - -static int ipaddr_modify(int cmd, int flags, int ifindex, int af, void *addr, - unsigned int netprefix_len) -{ - struct { - struct lkl_nlmsghdr n; - struct lkl_ifaddrmsg ifa; - char buf[256]; - } req = { - .n.nlmsg_len = LKL_NLMSG_LENGTH(sizeof(struct lkl_ifaddrmsg)), - .n.nlmsg_flags = LKL_NLM_F_REQUEST | flags, - .n.nlmsg_type = cmd, - .ifa.ifa_family = af, - .ifa.ifa_prefixlen = netprefix_len, - .ifa.ifa_index = ifindex, - }; - int err, addr_sz; - int fd; - - if (af == LKL_AF_INET) - addr_sz = 4; - else if (af == LKL_AF_INET6) - addr_sz = 16; - else { - lkl_printf("Bad address family: %d\n", af); - return -1; - } - - fd = netlink_sock(0); - if (fd < 0) - return fd; - - // create the IP attribute - addattr_l(&req.n, sizeof(req), LKL_IFA_LOCAL, addr, addr_sz); - - err = rtnl_talk(fd, &req.n); - - lkl_sys_close(fd); - return err; -} - -int lkl_if_add_ip(int ifindex, int af, void *addr, unsigned int netprefix_len) -{ - return ipaddr_modify(LKL_RTM_NEWADDR, LKL_NLM_F_CREATE | LKL_NLM_F_EXCL, - ifindex, af, addr, netprefix_len); -} - -int lkl_if_del_ip(int ifindex, int af, void *addr, unsigned int netprefix_len) -{ - return ipaddr_modify(LKL_RTM_DELADDR, 0, ifindex, af, - addr, netprefix_len); -} diff --git a/src/linux/tools/lkl/lib/nt-host.c b/src/linux/tools/lkl/lib/nt-host.c deleted file mode 100644 index a10bc09..0000000 --- a/src/linux/tools/lkl/lib/nt-host.c +++ /dev/null @@ -1,372 +0,0 @@ -#include -#include -#include -#undef s_addr -#include -#include "iomem.h" -#include "jmp_buf.h" - -#define DIFF_1601_TO_1970_IN_100NS (11644473600L * 10000000L) - -struct lkl_mutex { - int recursive; - HANDLE handle; -}; - -struct lkl_sem { - HANDLE sem; -}; - -struct lkl_tls_key { - DWORD key; -}; - -static struct lkl_sem *sem_alloc(int count) -{ - struct lkl_sem *sem = malloc(sizeof(struct lkl_sem)); - - sem->sem = CreateSemaphore(NULL, count, 100, NULL); - return sem; -} - -static void sem_up(struct lkl_sem *sem) -{ - ReleaseSemaphore(sem->sem, 1, NULL); -} - -static void sem_down(struct lkl_sem *sem) -{ - WaitForSingleObject(sem->sem, INFINITE); -} - -static void sem_free(struct lkl_sem *sem) -{ - CloseHandle(sem->sem); - free(sem); -} - -static struct lkl_mutex *mutex_alloc(int recursive) -{ - struct lkl_mutex *_mutex = malloc(sizeof(struct lkl_mutex)); - if (!_mutex) - return NULL; - - if (recursive) - _mutex->handle = CreateMutex(0, FALSE, 0); - else - _mutex->handle = CreateSemaphore(NULL, 1, 100, NULL); - _mutex->recursive = recursive; - return _mutex; -} - -static void mutex_lock(struct lkl_mutex *mutex) -{ - WaitForSingleObject(mutex->handle, INFINITE); -} - -static void mutex_unlock(struct lkl_mutex *_mutex) -{ - if (_mutex->recursive) - ReleaseMutex(_mutex->handle); - else - ReleaseSemaphore(_mutex->handle, 1, NULL); -} - -static void mutex_free(struct lkl_mutex *_mutex) -{ - CloseHandle(_mutex->handle); - free(_mutex); -} - -static lkl_thread_t thread_create(void (*fn)(void *), void *arg) -{ - DWORD WINAPI (*win_fn)(LPVOID arg) = (DWORD WINAPI (*)(LPVOID))fn; - HANDLE h = CreateThread(NULL, 0, win_fn, arg, 0, NULL); - - if (!h) - return 0; - - return GetThreadId(h); -} - -static void thread_detach(void) -{ -} - -static void thread_exit(void) -{ - ExitThread(0); -} - -static int thread_join(lkl_thread_t tid) -{ - int ret; - HANDLE *h; - - h = OpenThread(SYNCHRONIZE, FALSE, tid); - if (!h) - lkl_printf("%s: can't get thread handle\n", __func__); - - ret = WaitForSingleObject(h, INFINITE); - if (ret) - lkl_printf("%s: %d\n", __func__, ret); - - CloseHandle(h); - - return ret ? -1 : 0; -} - -static lkl_thread_t thread_self(void) -{ - return GetThreadId(GetCurrentThread()); -} - -static int thread_equal(lkl_thread_t a, lkl_thread_t b) -{ - return a == b; -} - -static struct lkl_tls_key *tls_alloc(void (*destructor)(void *)) -{ - struct lkl_tls_key *ret = malloc(sizeof(struct lkl_tls_key)); - - ret->key = FlsAlloc((PFLS_CALLBACK_FUNCTION)destructor); - if (ret->key == TLS_OUT_OF_INDEXES) { - free(ret); - return NULL; - } - return ret; -} - -static void tls_free(struct lkl_tls_key *key) -{ - /* setting to NULL first to prevent the callback from being called */ - FlsSetValue(key->key, NULL); - FlsFree(key->key); - free(key); -} - -static int tls_set(struct lkl_tls_key *key, void *data) -{ - return FlsSetValue(key->key, data) ? 0 : -1; -} - -static void *tls_get(struct lkl_tls_key *key) -{ - return FlsGetValue(key->key); -} - - -/* - * With 64 bits, we can cover about 583 years at a nanosecond resolution. - * Windows counts time from 1601 so we do have about 100 years before we - * overflow. - */ -static unsigned long long time_ns(void) -{ - SYSTEMTIME st; - FILETIME ft; - ULARGE_INTEGER uli; - - GetSystemTime(&st); - SystemTimeToFileTime(&st, &ft); - uli.LowPart = ft.dwLowDateTime; - uli.HighPart = ft.dwHighDateTime; - - return (uli.QuadPart - DIFF_1601_TO_1970_IN_100NS) * 100; -} - -struct timer { - HANDLE queue; - void (*callback)(void *); - void *arg; -}; - -static void *timer_alloc(void (*fn)(void *), void *arg) -{ - struct timer *t; - - t = malloc(sizeof(*t)); - if (!t) - return NULL; - - t->queue = CreateTimerQueue(); - if (!t->queue) { - free(t); - return NULL; - } - - t->callback = fn; - t->arg = arg; - - return t; -} - -static void CALLBACK timer_callback(void *arg, BOOLEAN TimerOrWaitFired) -{ - struct timer *t = (struct timer *)arg; - - if (TimerOrWaitFired) - t->callback(t->arg); -} - -static int timer_set_oneshot(void *timer, unsigned long ns) -{ - struct timer *t = (struct timer *)timer; - HANDLE tmp; - - return !CreateTimerQueueTimer(&tmp, t->queue, timer_callback, t, - ns / 1000000, 0, 0); -} - -static void timer_free(void *timer) -{ - struct timer *t = (struct timer *)timer; - HANDLE completion; - - completion = CreateEvent(NULL, FALSE, FALSE, NULL); - DeleteTimerQueueEx(t->queue, completion); - WaitForSingleObject(completion, INFINITE); - free(t); -} - -static void panic(void) -{ - int *x = NULL; - - *x = 1; - assert(0); -} - -static void print(const char *str, int len) -{ - write(1, str, len); -} - -static long gettid(void) -{ - return GetCurrentThreadId(); -} - -static void *mem_alloc(unsigned long size) -{ - return malloc(size); -} - -struct lkl_host_operations lkl_host_ops = { - .panic = panic, - .thread_create = thread_create, - .thread_detach = thread_detach, - .thread_exit = thread_exit, - .thread_join = thread_join, - .thread_self = thread_self, - .thread_equal = thread_equal, - .sem_alloc = sem_alloc, - .sem_free = sem_free, - .sem_up = sem_up, - .sem_down = sem_down, - .mutex_alloc = mutex_alloc, - .mutex_free = mutex_free, - .mutex_lock = mutex_lock, - .mutex_unlock = mutex_unlock, - .tls_alloc = tls_alloc, - .tls_free = tls_free, - .tls_set = tls_set, - .tls_get = tls_get, - .time = time_ns, - .timer_alloc = timer_alloc, - .timer_set_oneshot = timer_set_oneshot, - .timer_free = timer_free, - .print = print, - .mem_alloc = mem_alloc, - .mem_free = free, - .ioremap = lkl_ioremap, - .iomem_access = lkl_iomem_access, - .virtio_devices = lkl_virtio_devs, - .gettid = gettid, - .jmp_buf_set = jmp_buf_set, - .jmp_buf_longjmp = jmp_buf_longjmp, -}; - -int handle_get_capacity(struct lkl_disk disk, unsigned long long *res) -{ - LARGE_INTEGER tmp; - - if (!GetFileSizeEx(disk.handle, &tmp)) - return -1; - - *res = tmp.QuadPart; - return 0; -} - -static int blk_request(struct lkl_disk disk, struct lkl_blk_req *req) -{ - unsigned long long offset = req->sector * 512; - OVERLAPPED ov = { 0, }; - int err = 0, ret; - - switch (req->type) { - case LKL_DEV_BLK_TYPE_READ: - case LKL_DEV_BLK_TYPE_WRITE: - { - int i; - - for (i = 0; i < req->count; i++) { - DWORD res; - struct iovec *buf = &req->buf[i]; - - ov.Offset = offset & 0xffffffff; - ov.OffsetHigh = offset >> 32; - - if (req->type == LKL_DEV_BLK_TYPE_READ) - ret = ReadFile(disk.handle, buf->iov_base, - buf->iov_len, &res, &ov); - else - ret = WriteFile(disk.handle, buf->iov_base, - buf->iov_len, &res, &ov); - if (!ret) { - lkl_printf("%s: I/O error: %d\n", __func__, - GetLastError()); - err = -1; - goto out; - } - - if (res != buf->iov_len) { - lkl_printf("%s: I/O error: short: %d %d\n", - res, buf->iov_len); - err = -1; - goto out; - } - - offset += buf->iov_len; - } - break; - } - case LKL_DEV_BLK_TYPE_FLUSH: - case LKL_DEV_BLK_TYPE_FLUSH_OUT: - ret = FlushFileBuffers(disk.handle); - if (!ret) - err = 1; - break; - default: - return LKL_DEV_BLK_STATUS_UNSUP; - } - -out: - if (err < 0) - return LKL_DEV_BLK_STATUS_IOERR; - - return LKL_DEV_BLK_STATUS_OK; -} - -struct lkl_dev_blk_ops lkl_dev_blk_ops = { - .get_capacity = handle_get_capacity, - .request = blk_request, -}; - -/* Needed to resolve linker error on Win32. We don't really support - * any network IO on Windows, anyway, so there's no loss here. */ -int lkl_netdevs_remove(void) -{ - return 0; -} diff --git a/src/linux/tools/lkl/lib/posix-host.c b/src/linux/tools/lkl/lib/posix-host.c deleted file mode 100644 index 33c577b..0000000 --- a/src/linux/tools/lkl/lib/posix-host.c +++ /dev/null @@ -1,426 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "iomem.h" -#include "jmp_buf.h" - -/* Let's see if the host has semaphore.h */ -#include - -#ifdef _POSIX_SEMAPHORES -#include -/* TODO(pscollins): We don't support fork() for now, but maybe one day - * we will? */ -#define SHARE_SEM 0 -#endif /* _POSIX_SEMAPHORES */ - -static void print(const char *str, int len) -{ - int ret __attribute__((unused)); - - ret = write(STDOUT_FILENO, str, len); -} - -struct lkl_mutex { - pthread_mutex_t mutex; -}; - -struct lkl_sem { -#ifdef _POSIX_SEMAPHORES - sem_t sem; -#else - pthread_mutex_t lock; - int count; - pthread_cond_t cond; -#endif /* _POSIX_SEMAPHORES */ -}; - -struct lkl_tls_key { - pthread_key_t key; -}; - -#define WARN_UNLESS(exp) do { \ - if (exp < 0) \ - lkl_printf("%s: %s\n", #exp, strerror(errno)); \ - } while (0) - -static int _warn_pthread(int ret, char *str_exp) -{ - if (ret > 0) - lkl_printf("%s: %s\n", str_exp, strerror(ret)); - - return ret; -} - - -/* pthread_* functions use the reverse convention */ -#define WARN_PTHREAD(exp) _warn_pthread(exp, #exp) - -static struct lkl_sem *sem_alloc(int count) -{ - struct lkl_sem *sem; - - sem = malloc(sizeof(*sem)); - if (!sem) - return NULL; - -#ifdef _POSIX_SEMAPHORES - if (sem_init(&sem->sem, SHARE_SEM, count) < 0) { - lkl_printf("sem_init: %s\n", strerror(errno)); - free(sem); - return NULL; - } -#else - pthread_mutex_init(&sem->lock, NULL); - sem->count = count; - WARN_PTHREAD(pthread_cond_init(&sem->cond, NULL)); -#endif /* _POSIX_SEMAPHORES */ - - return sem; -} - -static void sem_free(struct lkl_sem *sem) -{ -#ifdef _POSIX_SEMAPHORES - WARN_UNLESS(sem_destroy(&sem->sem)); -#else - WARN_PTHREAD(pthread_cond_destroy(&sem->cond)); - WARN_PTHREAD(pthread_mutex_destroy(&sem->lock)); -#endif /* _POSIX_SEMAPHORES */ - free(sem); -} - -static void sem_up(struct lkl_sem *sem) -{ -#ifdef _POSIX_SEMAPHORES - WARN_UNLESS(sem_post(&sem->sem)); -#else - WARN_PTHREAD(pthread_mutex_lock(&sem->lock)); - sem->count++; - if (sem->count > 0) - WARN_PTHREAD(pthread_cond_signal(&sem->cond)); - WARN_PTHREAD(pthread_mutex_unlock(&sem->lock)); -#endif /* _POSIX_SEMAPHORES */ - -} - -static void sem_down(struct lkl_sem *sem) -{ -#ifdef _POSIX_SEMAPHORES - int err; - - do { - err = sem_wait(&sem->sem); - } while (err < 0 && errno == EINTR); - if (err < 0 && errno != EINTR) - lkl_printf("sem_wait: %s\n", strerror(errno)); -#else - WARN_PTHREAD(pthread_mutex_lock(&sem->lock)); - while (sem->count <= 0) - WARN_PTHREAD(pthread_cond_wait(&sem->cond, &sem->lock)); - sem->count--; - WARN_PTHREAD(pthread_mutex_unlock(&sem->lock)); -#endif /* _POSIX_SEMAPHORES */ -} - -static struct lkl_mutex *mutex_alloc(int recursive) -{ - struct lkl_mutex *_mutex = malloc(sizeof(struct lkl_mutex)); - pthread_mutex_t *mutex = NULL; - pthread_mutexattr_t attr; - - if (!_mutex) - return NULL; - - mutex = &_mutex->mutex; - WARN_PTHREAD(pthread_mutexattr_init(&attr)); - - /* PTHREAD_MUTEX_ERRORCHECK is *very* useful for debugging, - * but has some overhead, so we provide an option to turn it - * off. */ -#ifdef DEBUG - if (!recursive) - WARN_PTHREAD(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)); -#endif /* DEBUG */ - - if (recursive) - WARN_PTHREAD(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)); - - WARN_PTHREAD(pthread_mutex_init(mutex, &attr)); - - return _mutex; -} - -static void mutex_lock(struct lkl_mutex *mutex) -{ - WARN_PTHREAD(pthread_mutex_lock(&mutex->mutex)); -} - -static void mutex_unlock(struct lkl_mutex *_mutex) -{ - pthread_mutex_t *mutex = &_mutex->mutex; - WARN_PTHREAD(pthread_mutex_unlock(mutex)); -} - -static void mutex_free(struct lkl_mutex *_mutex) -{ - pthread_mutex_t *mutex = &_mutex->mutex; - WARN_PTHREAD(pthread_mutex_destroy(mutex)); - free(_mutex); -} - -static lkl_thread_t thread_create(void (*fn)(void *), void *arg) -{ - pthread_t thread; - if (WARN_PTHREAD(pthread_create(&thread, NULL, (void* (*)(void *))fn, arg))) - return 0; - else - return (lkl_thread_t) thread; -} - -static void thread_detach(void) -{ - WARN_PTHREAD(pthread_detach(pthread_self())); -} - -static void thread_exit(void) -{ - pthread_exit(NULL); -} - -static int thread_join(lkl_thread_t tid) -{ - if (WARN_PTHREAD(pthread_join((pthread_t)tid, NULL))) - return -1; - else - return 0; -} - -static lkl_thread_t thread_self(void) -{ - return (lkl_thread_t)pthread_self(); -} - -static int thread_equal(lkl_thread_t a, lkl_thread_t b) -{ - return pthread_equal(a, b); -} - -static struct lkl_tls_key *tls_alloc(void (*destructor)(void *)) -{ - struct lkl_tls_key *ret = malloc(sizeof(struct lkl_tls_key)); - - if (WARN_PTHREAD(pthread_key_create(&ret->key, destructor))) { - free(ret); - return NULL; - } - return ret; -} - -static void tls_free(struct lkl_tls_key *key) -{ - WARN_PTHREAD(pthread_key_delete(key->key)); - free(key); -} - -static int tls_set(struct lkl_tls_key *key, void *data) -{ - if (WARN_PTHREAD(pthread_setspecific(key->key, data))) - return -1; - return 0; -} - -static void *tls_get(struct lkl_tls_key *key) -{ - return pthread_getspecific(key->key); -} - -static unsigned long long time_ns(void) -{ - struct timespec ts; - - clock_gettime(CLOCK_MONOTONIC, &ts); - - return 1e9*ts.tv_sec + ts.tv_nsec; -} - -static void *timer_alloc(void (*fn)(void *), void *arg) -{ - int err; - timer_t timer; - struct sigevent se = { - .sigev_notify = SIGEV_THREAD, - .sigev_value = { - .sival_ptr = arg, - }, - .sigev_notify_function = (void (*)(union sigval))fn, - }; - - err = timer_create(CLOCK_REALTIME, &se, &timer); - if (err) - return NULL; - - return (void *)(long)timer; -} - -static int timer_set_oneshot(void *_timer, unsigned long ns) -{ - timer_t timer = (timer_t)(long)_timer; - struct itimerspec ts = { - .it_value = { - .tv_sec = ns / 1000000000, - .tv_nsec = ns % 1000000000, - }, - }; - - return timer_settime(timer, 0, &ts, NULL); -} - -static void timer_free(void *_timer) -{ - timer_t timer = (timer_t)(long)_timer; - - timer_delete(timer); -} - -static void panic(void) -{ - assert(0); -} - -static long _gettid(void) -{ -#ifdef __FreeBSD__ - return (long)pthread_self(); -#else - return syscall(SYS_gettid); -#endif -} - -struct lkl_host_operations lkl_host_ops = { - .panic = panic, - .thread_create = thread_create, - .thread_detach = thread_detach, - .thread_exit = thread_exit, - .thread_join = thread_join, - .thread_self = thread_self, - .thread_equal = thread_equal, - .sem_alloc = sem_alloc, - .sem_free = sem_free, - .sem_up = sem_up, - .sem_down = sem_down, - .mutex_alloc = mutex_alloc, - .mutex_free = mutex_free, - .mutex_lock = mutex_lock, - .mutex_unlock = mutex_unlock, - .tls_alloc = tls_alloc, - .tls_free = tls_free, - .tls_set = tls_set, - .tls_get = tls_get, - .time = time_ns, - .timer_alloc = timer_alloc, - .timer_set_oneshot = timer_set_oneshot, - .timer_free = timer_free, - .print = print, - .mem_alloc = malloc, - .mem_free = free, - .ioremap = lkl_ioremap, - .iomem_access = lkl_iomem_access, - .virtio_devices = lkl_virtio_devs, - .gettid = _gettid, - .jmp_buf_set = jmp_buf_set, - .jmp_buf_longjmp = jmp_buf_longjmp, -}; - -static int fd_get_capacity(struct lkl_disk disk, unsigned long long *res) -{ - off_t off; - - off = lseek(disk.fd, 0, SEEK_END); - if (off < 0) - return -1; - - *res = off; - return 0; -} - -static int do_rw(ssize_t (*fn)(), struct lkl_disk disk, struct lkl_blk_req *req) -{ - off_t off = req->sector * 512; - void *addr; - int len; - int i; - int ret = 0; - - for (i = 0; i < req->count; i++) { - - addr = req->buf[i].iov_base; - len = req->buf[i].iov_len; - - do { - ret = fn(disk.fd, addr, len, off); - - if (ret <= 0) { - ret = -1; - goto out; - } - - addr += ret; - len -= ret; - off += ret; - - } while (len); - } - -out: - return ret; -} - -static int blk_request(struct lkl_disk disk, struct lkl_blk_req *req) -{ - int err = 0; - - switch (req->type) { - case LKL_DEV_BLK_TYPE_READ: - err = do_rw(pread, disk, req); - break; - case LKL_DEV_BLK_TYPE_WRITE: - err = do_rw(pwrite, disk, req); - break; - case LKL_DEV_BLK_TYPE_FLUSH: - case LKL_DEV_BLK_TYPE_FLUSH_OUT: -#ifdef __linux__ - err = fdatasync(disk.fd); -#else - err = fsync(disk.fd); -#endif - break; - default: - return LKL_DEV_BLK_STATUS_UNSUP; - } - - if (err < 0) - return LKL_DEV_BLK_STATUS_IOERR; - - return LKL_DEV_BLK_STATUS_OK; -} - -struct lkl_dev_blk_ops lkl_dev_blk_ops = { - .get_capacity = fd_get_capacity, - .request = blk_request, -}; - diff --git a/src/linux/tools/lkl/lib/utils.c b/src/linux/tools/lkl/lib/utils.c deleted file mode 100644 index b4631e0..0000000 --- a/src/linux/tools/lkl/lib/utils.c +++ /dev/null @@ -1,207 +0,0 @@ -#include -#include -#include - -static const char * const lkl_err_strings[] = { - "Success", - "Operation not permitted", - "No such file or directory", - "No such process", - "Interrupted system call", - "I/O error", - "No such device or address", - "Argument list too long", - "Exec format error", - "Bad file number", - "No child processes", - "Try again", - "Out of memory", - "Permission denied", - "Bad address", - "Block device required", - "Device or resource busy", - "File exists", - "Cross-device link", - "No such device", - "Not a directory", - "Is a directory", - "Invalid argument", - "File table overflow", - "Too many open files", - "Not a typewriter", - "Text file busy", - "File too large", - "No space left on device", - "Illegal seek", - "Read-only file system", - "Too many links", - "Broken pipe", - "Math argument out of domain of func", - "Math result not representable", - "Resource deadlock would occur", - "File name too long", - "No record locks available", - "Invalid system call number", - "Directory not empty", - "Too many symbolic links encountered", - "Bad error code", /* EWOULDBLOCK is EAGAIN */ - "No message of desired type", - "Identifier removed", - "Channel number out of range", - "Level 2 not synchronized", - "Level 3 halted", - "Level 3 reset", - "Link number out of range", - "Protocol driver not attached", - "No CSI structure available", - "Level 2 halted", - "Invalid exchange", - "Invalid request descriptor", - "Exchange full", - "No anode", - "Invalid request code", - "Invalid slot", - "Bad error code", /* EDEADLOCK is EDEADLK */ - "Bad font file format", - "Device not a stream", - "No data available", - "Timer expired", - "Out of streams resources", - "Machine is not on the network", - "Package not installed", - "Object is remote", - "Link has been severed", - "Advertise error", - "Srmount error", - "Communication error on send", - "Protocol error", - "Multihop attempted", - "RFS specific error", - "Not a data message", - "Value too large for defined data type", - "Name not unique on network", - "File descriptor in bad state", - "Remote address changed", - "Can not access a needed shared library", - "Accessing a corrupted shared library", - ".lib section in a.out corrupted", - "Attempting to link in too many shared libraries", - "Cannot exec a shared library directly", - "Illegal byte sequence", - "Interrupted system call should be restarted", - "Streams pipe error", - "Too many users", - "Socket operation on non-socket", - "Destination address required", - "Message too long", - "Protocol wrong type for socket", - "Protocol not available", - "Protocol not supported", - "Socket type not supported", - "Operation not supported on transport endpoint", - "Protocol family not supported", - "Address family not supported by protocol", - "Address already in use", - "Cannot assign requested address", - "Network is down", - "Network is unreachable", - "Network dropped connection because of reset", - "Software caused connection abort", - "Connection reset by peer", - "No buffer space available", - "Transport endpoint is already connected", - "Transport endpoint is not connected", - "Cannot send after transport endpoint shutdown", - "Too many references: cannot splice", - "Connection timed out", - "Connection refused", - "Host is down", - "No route to host", - "Operation already in progress", - "Operation now in progress", - "Stale file handle", - "Structure needs cleaning", - "Not a XENIX named type file", - "No XENIX semaphores available", - "Is a named type file", - "Remote I/O error", - "Quota exceeded", - "No medium found", - "Wrong medium type", - "Operation Canceled", - "Required key not available", - "Key has expired", - "Key has been revoked", - "Key was rejected by service", - "Owner died", - "State not recoverable", - "Operation not possible due to RF-kill", - "Memory page has hardware error", -}; - -const char *lkl_strerror(int err) -{ - if (err < 0) - err = -err; - - if ((size_t)err >= sizeof(lkl_err_strings) / sizeof(const char *)) - return "Bad error code"; - - return lkl_err_strings[err]; -} - -void lkl_perror(char *msg, int err) -{ - const char *err_msg = lkl_strerror(err); - /* We need to use 'real' printf because lkl_host_ops.print can - * be turned off when debugging is off. */ - lkl_printf("%s: %s\n", msg, err_msg); -} - -static int lkl_vprintf(const char *fmt, va_list args) -{ - int n; - char *buffer; - va_list copy; - - if (!lkl_host_ops.print) - return 0; - - va_copy(copy, args); - n = vsnprintf(NULL, 0, fmt, copy); - va_end(copy); - - buffer = lkl_host_ops.mem_alloc(n + 1); - if (!buffer) - return -1; - - vsnprintf(buffer, n + 1, fmt, args); - - lkl_host_ops.print(buffer, n); - lkl_host_ops.mem_free(buffer); - - return n; -} - -int lkl_printf(const char *fmt, ...) -{ - int n; - va_list args; - - va_start(args, fmt); - n = lkl_vprintf(fmt, args); - va_end(args); - - return n; -} - -void lkl_bug(const char *fmt, ...) -{ - va_list args; - - va_start(args, fmt); - lkl_vprintf(fmt, args); - va_end(args); - - lkl_host_ops.panic(); -} diff --git a/src/linux/tools/lkl/lib/virtio.c b/src/linux/tools/lkl/lib/virtio.c deleted file mode 100644 index 5e1cecb..0000000 --- a/src/linux/tools/lkl/lib/virtio.c +++ /dev/null @@ -1,628 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include "iomem.h" -#include "virtio.h" -#include "endian.h" - -#define VIRTIO_DEV_MAGIC 0x74726976 -#define VIRTIO_DEV_VERSION 2 - -#define VIRTIO_MMIO_MAGIC_VALUE 0x000 -#define VIRTIO_MMIO_VERSION 0x004 -#define VIRTIO_MMIO_DEVICE_ID 0x008 -#define VIRTIO_MMIO_VENDOR_ID 0x00c -#define VIRTIO_MMIO_DEVICE_FEATURES 0x010 -#define VIRTIO_MMIO_DEVICE_FEATURES_SEL 0x014 -#define VIRTIO_MMIO_DRIVER_FEATURES 0x020 -#define VIRTIO_MMIO_DRIVER_FEATURES_SEL 0x024 -#define VIRTIO_MMIO_QUEUE_SEL 0x030 -#define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034 -#define VIRTIO_MMIO_QUEUE_NUM 0x038 -#define VIRTIO_MMIO_QUEUE_READY 0x044 -#define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 -#define VIRTIO_MMIO_INTERRUPT_STATUS 0x060 -#define VIRTIO_MMIO_INTERRUPT_ACK 0x064 -#define VIRTIO_MMIO_STATUS 0x070 -#define VIRTIO_MMIO_QUEUE_DESC_LOW 0x080 -#define VIRTIO_MMIO_QUEUE_DESC_HIGH 0x084 -#define VIRTIO_MMIO_QUEUE_AVAIL_LOW 0x090 -#define VIRTIO_MMIO_QUEUE_AVAIL_HIGH 0x094 -#define VIRTIO_MMIO_QUEUE_USED_LOW 0x0a0 -#define VIRTIO_MMIO_QUEUE_USED_HIGH 0x0a4 -#define VIRTIO_MMIO_CONFIG_GENERATION 0x0fc -#define VIRTIO_MMIO_CONFIG 0x100 -#define VIRTIO_MMIO_INT_VRING 0x01 -#define VIRTIO_MMIO_INT_CONFIG 0x02 - -#define BIT(x) (1ULL << x) - -#define virtio_panic(msg, ...) do { \ - lkl_printf("LKL virtio error" msg, ##__VA_ARGS__); \ - lkl_host_ops.panic(); \ - } while (0) - -struct virtio_queue { - uint32_t num_max; - uint32_t num; - uint32_t ready; - uint32_t max_merge_len; - - struct lkl_vring_desc *desc; - struct lkl_vring_avail *avail; - struct lkl_vring_used *used; - uint16_t last_avail_idx; - uint16_t last_used_idx_signaled; -}; - -struct _virtio_req { - struct virtio_req req; - struct virtio_dev *dev; - struct virtio_queue *q; - uint16_t idx; -}; - - -static inline uint16_t virtio_get_used_event(struct virtio_queue *q) -{ - return q->avail->ring[q->num]; -} - -static inline void virtio_set_avail_event(struct virtio_queue *q, uint16_t val) -{ - *((uint16_t *)&q->used->ring[q->num]) = val; -} - -static inline void virtio_deliver_irq(struct virtio_dev *dev) -{ - dev->int_status |= VIRTIO_MMIO_INT_VRING; - /* Make sure all memory writes before are visible to the driver. */ - __sync_synchronize(); - lkl_trigger_irq(dev->irq); -} - -static inline uint16_t virtio_get_used_idx(struct virtio_queue *q) -{ - return le16toh(q->used->idx); -} - -static inline void virtio_add_used(struct virtio_queue *q, uint16_t used_idx, - uint16_t avail_idx, uint16_t len) -{ - uint16_t desc_idx = q->avail->ring[avail_idx & (q->num - 1)]; - - used_idx = used_idx & (q->num - 1); - q->used->ring[used_idx].id = desc_idx; - q->used->ring[used_idx].len = htole16(len); -} - -/* - * Make sure all memory writes before are visible to the driver before updating - * the idx. We need it here even we already have one in virtio_deliver_irq() - * because there might already be an driver thread reading the idx and dequeuing - * used buffers. - */ -static inline void virtio_sync_used_idx(struct virtio_queue *q, uint16_t idx) -{ - __sync_synchronize(); - q->used->idx = htole16(idx); -} - -#define min_len(a, b) (a < b ? a : b) - -void virtio_req_complete(struct virtio_req *req, uint32_t len) -{ - int send_irq = 0; - struct _virtio_req *_req = container_of(req, struct _virtio_req, req); - struct virtio_queue *q = _req->q; - uint16_t avail_idx = _req->idx; - uint16_t used_idx = virtio_get_used_idx(_req->q); - int i; - - /* - * We've potentially used up multiple (non-chained) descriptors and have - * to create one "used" entry for each descriptor we've consumed. - */ - for (i = 0; i < req->buf_count; i++) { - uint16_t used_len; - - if (!q->max_merge_len) - used_len = len; - else - used_len = min_len(len, req->buf[i].iov_len); - - virtio_add_used(q, used_idx++, avail_idx++, used_len); - - len -= used_len; - if (!len) - break; - } - virtio_sync_used_idx(q, used_idx); - q->last_avail_idx = avail_idx; - - /* - * Triggers the irq whenever there is no available buffer. - */ - if (q->last_avail_idx == le16toh(q->avail->idx)) - send_irq = 1; - - /* - * There are two rings: q->avail and q->used for each of the rx and tx - * queues that are used to pass buffers between kernel driver and the - * virtio device implementation. - * - * Kernel maitains the first one and appends buffers to it. In rx queue, - * it's empty buffers kernel offers to store received packets. In tx - * queue, it's buffers containing packets to transmit. Kernel notifies - * the device by mmio write (see VIRTIO_MMIO_QUEUE_NOTIFY below). - * - * The virtio device (here in this file) maintains the - * q->used and appends buffer to it after consuming it from q->avail. - * - * The device needs to notify the driver by triggering irq here. The - * LKL_VIRTIO_RING_F_EVENT_IDX is enabled in this implementation so - * kernel can set virtio_get_used_event(q) to tell the device to "only - * trigger the irq when this item in q->used ring is populated." - * - * Because driver and device are run in two different threads. When - * driver sets virtio_get_used_event(q), q->used->idx may already be - * increased to a larger one. So we need to trigger the irq when - * virtio_get_used_event(q) < q->used->idx. - * - * To avoid unnessary irqs for each packet after - * virtio_get_used_event(q) < q->used->idx, last_used_idx_signaled is - * stored and irq is only triggered if - * last_used_idx_signaled <= virtio_get_used_event(q) < q->used->idx - * - * This is what lkl_vring_need_event() checks and it evens covers the - * case when those numbers wrap up. - */ - if (send_irq || lkl_vring_need_event(le16toh(virtio_get_used_event(q)), - virtio_get_used_idx(q), - q->last_used_idx_signaled)) { - q->last_used_idx_signaled = virtio_get_used_idx(q); - virtio_deliver_irq(_req->dev); - } -} - -/* - * Grab the vring_desc from the queue at the appropriate index in the - * queue's circular buffer, converting from little-endian to - * the host's endianness. - */ -static inline -struct lkl_vring_desc *vring_desc_at_le_idx(struct virtio_queue *q, - __lkl__virtio16 le_idx) -{ - return &q->desc[le16toh(le_idx) & (q->num -1)]; -} - -static inline -struct lkl_vring_desc *vring_desc_at_avail_idx(struct virtio_queue *q, - uint16_t idx) -{ - uint16_t desc_idx = q->avail->ring[idx & (q->num - 1)]; - - return vring_desc_at_le_idx(q, desc_idx); -} - -/* Initialize buf to hold the same info as the vring_desc */ -static void add_dev_buf_from_vring_desc(struct virtio_req *req, - struct lkl_vring_desc *vring_desc) -{ - struct iovec *buf = &req->buf[req->buf_count++]; - - buf->iov_base = (void *)(uintptr_t)le64toh(vring_desc->addr); - buf->iov_len = le32toh(vring_desc->len); - - if (!(buf->iov_base && buf->iov_len)) - virtio_panic("bad vring_desc: %p %d\n", - buf->iov_base, buf->iov_len); - - req->total_len += buf->iov_len; -} - -static struct lkl_vring_desc *get_next_desc(struct virtio_queue *q, - struct lkl_vring_desc *desc, - uint16_t *idx) -{ - uint16_t desc_idx; - - if (q->max_merge_len) { - if (++(*idx) == le16toh(q->avail->idx)) - return NULL; - desc_idx = q->avail->ring[*idx & (q->num - 1)]; - return vring_desc_at_le_idx(q, desc_idx); - } - - if (!(le16toh(desc->flags) & LKL_VRING_DESC_F_NEXT)) - return NULL; - return vring_desc_at_le_idx(q, desc->next); -} - -/* - * Below there are two distinctly different (per packet) buffer allocation - * schemes for us to deal with: - * - * 1. One or more descriptors chained through "next" as indicated by the - * LKL_VRING_DESC_F_NEXT flag, - * 2. One or more descriptors from the ring sequentially, as many as are - * available and needed. This is the RX only "mergeable_rx_bufs" mode. - * The mode is entered when the VIRTIO_NET_F_MRG_RXBUF device feature - * is enabled. - */ -static int virtio_process_one(struct virtio_dev *dev, int qidx) -{ - struct virtio_queue *q = &dev->queue[qidx]; - uint16_t idx = q->last_avail_idx; - struct _virtio_req _req = { - .dev = dev, - .q = q, - .idx = idx, - }; - struct virtio_req *req = &_req.req; - struct lkl_vring_desc *desc = vring_desc_at_avail_idx(q, _req.idx); - - do { - add_dev_buf_from_vring_desc(req, desc); - if (q->max_merge_len && req->total_len > q->max_merge_len) - break; - desc = get_next_desc(q, desc, &idx); - } while (desc && req->buf_count < VIRTIO_REQ_MAX_BUFS); - - if (desc && le16toh(desc->flags) & LKL_VRING_DESC_F_NEXT) - virtio_panic("too many chained bufs"); - - return dev->ops->enqueue(dev, qidx, req); -} - -/* NB: we can enter this function two different ways in the case of - * netdevs --- either through a tx/rx thread poll (which the LKL - * scheduler knows nothing about) or through virtio_write called - * inside an interrupt handler, so to be safe, it's not enough to - * synchronize only the tx/rx polling threads. - * - * At the moment, it seems like only netdevs require the - * synchronization we do here (i.e. locking around operations on a - * particular virtqueue, with dev->ops->acquire_queue), since they - * have these two different entry points, one of which isn't managed - * by the LKL scheduler. So only devs corresponding to netdevs will - * have non-NULL acquire/release_queue. - * - * In the future, this may change. If you see errors thrown in virtio - * driver code by block/console devices, you should be suspicious of - * the synchronization going on here. - */ -void virtio_process_queue(struct virtio_dev *dev, uint32_t qidx) -{ - struct virtio_queue *q = &dev->queue[qidx]; - - if (!q->ready) - return; - - if (dev->ops->acquire_queue) - dev->ops->acquire_queue(dev, qidx); - - while (q->last_avail_idx != le16toh(q->avail->idx)) { - /* - * Make sure following loads happens after loading - * q->avail->idx. - */ - __sync_synchronize(); - if (virtio_process_one(dev, qidx) < 0) - break; - if (q->last_avail_idx == le16toh(q->avail->idx)) - virtio_set_avail_event(q, q->avail->idx); - } - - if (dev->ops->release_queue) - dev->ops->release_queue(dev, qidx); -} - -static inline uint32_t virtio_read_device_features(struct virtio_dev *dev) -{ - if (dev->device_features_sel) - return (uint32_t)(dev->device_features >> 32); - - return (uint32_t)dev->device_features; -} - -static inline void virtio_write_driver_features(struct virtio_dev *dev, - uint32_t val) -{ - uint64_t tmp; - - if (dev->driver_features_sel) { - tmp = dev->driver_features & 0xFFFFFFFF; - dev->driver_features = tmp | (uint64_t)val << 32; - } else { - tmp = dev->driver_features & 0xFFFFFFFF00000000; - dev->driver_features = tmp | val; - } -} - -static int virtio_read(void *data, int offset, void *res, int size) -{ - uint32_t val; - struct virtio_dev *dev = (struct virtio_dev *)data; - - if (offset >= VIRTIO_MMIO_CONFIG) { - offset -= VIRTIO_MMIO_CONFIG; - if (offset + size > dev->config_len) - return -LKL_EINVAL; - memcpy(res, dev->config_data + offset, size); - return 0; - } - - if (size != sizeof(uint32_t)) - return -LKL_EINVAL; - - switch (offset) { - case VIRTIO_MMIO_MAGIC_VALUE: - val = VIRTIO_DEV_MAGIC; - break; - case VIRTIO_MMIO_VERSION: - val = VIRTIO_DEV_VERSION; - break; - case VIRTIO_MMIO_DEVICE_ID: - val = dev->device_id; - break; - case VIRTIO_MMIO_VENDOR_ID: - val = dev->vendor_id; - break; - case VIRTIO_MMIO_DEVICE_FEATURES: - val = virtio_read_device_features(dev); - break; - case VIRTIO_MMIO_QUEUE_NUM_MAX: - val = dev->queue[dev->queue_sel].num_max; - break; - case VIRTIO_MMIO_QUEUE_READY: - val = dev->queue[dev->queue_sel].ready; - break; - case VIRTIO_MMIO_INTERRUPT_STATUS: - val = dev->int_status; - break; - case VIRTIO_MMIO_STATUS: - val = dev->status; - break; - case VIRTIO_MMIO_CONFIG_GENERATION: - val = dev->config_gen; - break; - default: - return -1; - } - - *(uint32_t *)res = htole32(val); - - return 0; -} - -static inline void set_ptr_low(void **ptr, uint32_t val) -{ - uint64_t tmp = (uintptr_t)*ptr; - - tmp = (tmp & 0xFFFFFFFF00000000) | val; - *ptr = (void *)(long)tmp; -} - -static inline void set_ptr_high(void **ptr, uint32_t val) -{ - uint64_t tmp = (uintptr_t)*ptr; - - tmp = (tmp & 0x00000000FFFFFFFF) | ((uint64_t)val << 32); - *ptr = (void *)(long)tmp; -} - -static inline void set_status(struct virtio_dev *dev, uint32_t val) -{ - if ((val & LKL_VIRTIO_CONFIG_S_FEATURES_OK) && - (!(dev->driver_features & BIT(LKL_VIRTIO_F_VERSION_1)) || - !(dev->driver_features & BIT(LKL_VIRTIO_RING_F_EVENT_IDX)) || - dev->ops->check_features(dev))) - val &= ~LKL_VIRTIO_CONFIG_S_FEATURES_OK; - dev->status = val; -} - -static int virtio_write(void *data, int offset, void *res, int size) -{ - struct virtio_dev *dev = (struct virtio_dev *)data; - struct virtio_queue *q = &dev->queue[dev->queue_sel]; - uint32_t val; - int ret = 0; - - if (offset >= VIRTIO_MMIO_CONFIG) { - offset -= VIRTIO_MMIO_CONFIG; - - if (offset + size >= dev->config_len) - return -LKL_EINVAL; - memcpy(dev->config_data + offset, res, size); - return 0; - } - - if (size != sizeof(uint32_t)) - return -LKL_EINVAL; - - val = le32toh(*(uint32_t *)res); - - switch (offset) { - case VIRTIO_MMIO_DEVICE_FEATURES_SEL: - if (val > 1) - return -LKL_EINVAL; - dev->device_features_sel = val; - break; - case VIRTIO_MMIO_DRIVER_FEATURES_SEL: - if (val > 1) - return -LKL_EINVAL; - dev->driver_features_sel = val; - break; - case VIRTIO_MMIO_DRIVER_FEATURES: - virtio_write_driver_features(dev, val); - break; - case VIRTIO_MMIO_QUEUE_SEL: - dev->queue_sel = val; - break; - case VIRTIO_MMIO_QUEUE_NUM: - dev->queue[dev->queue_sel].num = val; - break; - case VIRTIO_MMIO_QUEUE_READY: - dev->queue[dev->queue_sel].ready = val; - break; - case VIRTIO_MMIO_QUEUE_NOTIFY: - virtio_process_queue(dev, val); - break; - case VIRTIO_MMIO_INTERRUPT_ACK: - dev->int_status = 0; - break; - case VIRTIO_MMIO_STATUS: - set_status(dev, val); - break; - case VIRTIO_MMIO_QUEUE_DESC_LOW: - set_ptr_low((void **)&q->desc, val); - break; - case VIRTIO_MMIO_QUEUE_DESC_HIGH: - set_ptr_high((void **)&q->desc, val); - break; - case VIRTIO_MMIO_QUEUE_AVAIL_LOW: - set_ptr_low((void **)&q->avail, val); - break; - case VIRTIO_MMIO_QUEUE_AVAIL_HIGH: - set_ptr_high((void **)&q->avail, val); - break; - case VIRTIO_MMIO_QUEUE_USED_LOW: - set_ptr_low((void **)&q->used, val); - break; - case VIRTIO_MMIO_QUEUE_USED_HIGH: - set_ptr_high((void **)&q->used, val); - break; - default: - ret = -1; - } - - return ret; -} - -static const struct lkl_iomem_ops virtio_ops = { - .read = virtio_read, - .write = virtio_write, -}; - -char lkl_virtio_devs[4096]; -static char *devs = lkl_virtio_devs; -static uint32_t lkl_num_virtio_boot_devs; - -void virtio_set_queue_max_merge_len(struct virtio_dev *dev, int q, int len) -{ - dev->queue[q].max_merge_len = len; -} - -int virtio_dev_setup(struct virtio_dev *dev, int queues, int num_max) -{ - int qsize = queues * sizeof(*dev->queue); - int avail, mmio_size; - int i; - int num_bytes; - int ret; - - dev->irq = lkl_get_free_irq("virtio"); - if (dev->irq < 0) - return dev->irq; - - dev->device_features |= BIT(LKL_VIRTIO_F_VERSION_1) | - BIT(LKL_VIRTIO_RING_F_EVENT_IDX); - dev->queue = lkl_host_ops.mem_alloc(qsize); - if (!dev->queue) - return -LKL_ENOMEM; - - memset(dev->queue, 0, qsize); - for (i = 0; i < queues; i++) - dev->queue[i].num_max = num_max; - - mmio_size = VIRTIO_MMIO_CONFIG + dev->config_len; - dev->base = register_iomem(dev, mmio_size, &virtio_ops); - if (!dev->base) { - lkl_host_ops.mem_free(dev->queue); - return -LKL_ENOMEM; - } - - if (!lkl_is_running()) { - avail = sizeof(lkl_virtio_devs) - (devs - lkl_virtio_devs); - num_bytes = snprintf(devs, avail, " virtio_mmio.device=%d@0x%"PRIxPTR":%d", - mmio_size, (uintptr_t) dev->base, dev->irq); - if (num_bytes < 0 || num_bytes >= avail) { - lkl_put_irq(dev->irq, "virtio"); - unregister_iomem(dev->base); - lkl_host_ops.mem_free(dev->queue); - return -LKL_ENOMEM; - } - devs += num_bytes; - dev->virtio_mmio_id = lkl_num_virtio_boot_devs++; - } else { - ret = - lkl_sys_virtio_mmio_device_add((long)dev->base, mmio_size, - dev->irq); - if (ret < 0) { - lkl_printf("can't register mmio device\n"); - return -1; - } - dev->virtio_mmio_id = lkl_num_virtio_boot_devs + ret; - } - - return 0; -} - -int virtio_dev_cleanup(struct virtio_dev *dev) -{ - char devname[100]; - long fd, ret; - long mount_ret; - - if (!lkl_is_running()) - goto skip_unbind; - - mount_ret = lkl_mount_fs("sysfs"); - if (mount_ret < 0) - return mount_ret; - - if (dev->virtio_mmio_id >= virtio_get_num_bootdevs()) - ret = snprintf(devname, sizeof(devname), "virtio-mmio.%d.auto", - dev->virtio_mmio_id - virtio_get_num_bootdevs()); - else - ret = snprintf(devname, sizeof(devname), "virtio-mmio.%d", - dev->virtio_mmio_id); - if (ret < 0 || (size_t) ret >= sizeof(devname)) - return -LKL_ENOMEM; - - fd = lkl_sys_open("/sysfs/bus/platform/drivers/virtio-mmio/unbind", - LKL_O_WRONLY, 0); - if (fd < 0) - return fd; - - ret = lkl_sys_write(fd, devname, strlen(devname)); - if (ret < 0) - return ret; - - ret = lkl_sys_close(fd); - if (ret < 0) - return ret; - - if (mount_ret == 0) { - ret = lkl_sys_umount("/sysfs", 0); - if (ret < 0) - return ret; - } - -skip_unbind: - lkl_put_irq(dev->irq, "virtio"); - unregister_iomem(dev->base); - lkl_host_ops.mem_free(dev->queue); - - return 0; -} - -uint32_t virtio_get_num_bootdevs(void) -{ - return lkl_num_virtio_boot_devs; -} diff --git a/src/linux/tools/lkl/lib/virtio.h b/src/linux/tools/lkl/lib/virtio.h deleted file mode 100644 index e011378..0000000 --- a/src/linux/tools/lkl/lib/virtio.h +++ /dev/null @@ -1,92 +0,0 @@ -#ifndef _LKL_LIB_VIRTIO_H -#define _LKL_LIB_VIRTIO_H - -#include -#include - -#define PAGE_SIZE 4096 - -/* The following are copied from skbuff.h */ -#if (65536/PAGE_SIZE + 1) < 16 -#define MAX_SKB_FRAGS 16UL -#else -#define MAX_SKB_FRAGS (65536/PAGE_SIZE + 1) -#endif - -#define VIRTIO_REQ_MAX_BUFS (MAX_SKB_FRAGS + 2) - -struct virtio_req { - uint16_t buf_count; - struct iovec buf[VIRTIO_REQ_MAX_BUFS]; - uint32_t total_len; -}; - -struct virtio_dev; - -struct virtio_dev_ops { - int (*check_features)(struct virtio_dev *dev); - /** - * enqueue - queues the request for processing - * - * Note that the curret implementation assumes that the requests are - * processed synchronous and, as such, @virtio_req_complete must be - * called by from this function. - * - * @dev - virtio device - * @q - queue index - * - * @returns a negative value if the request has not been queued for - * processing in which case the virtio device is resposible for - * restaring the queue processing by calling @virtio_process_queue at a - * later time; 0 or a positive value means that the request has been - * queued for processing - */ - int (*enqueue)(struct virtio_dev *dev, int q, struct virtio_req *req); - /* - * Acquire/release a lock on the specified queue. Only implemented by - * netdevs, all other devices have NULL acquire/release function - * pointers. - */ - void (*acquire_queue)(struct virtio_dev *dev, int queue_idx); - void (*release_queue)(struct virtio_dev *dev, int queue_idx); -}; - -struct virtio_dev { - uint32_t device_id; - uint32_t vendor_id; - uint64_t device_features; - uint32_t device_features_sel; - uint64_t driver_features; - uint32_t driver_features_sel; - uint32_t queue_sel; - struct virtio_queue *queue; - uint32_t queue_notify; - uint32_t int_status; - uint32_t status; - uint32_t config_gen; - - struct virtio_dev_ops *ops; - int irq; - void *config_data; - int config_len; - void *base; - uint32_t virtio_mmio_id; -}; - -int virtio_dev_setup(struct virtio_dev *dev, int queues, int num_max); -int virtio_dev_cleanup(struct virtio_dev *dev); -uint32_t virtio_get_num_bootdevs(void); -/** - * virtio_req_complete - complete a virtio request - * - * @req - the request to be completed - * @len - the total size in bytes of the completed request - */ -void virtio_req_complete(struct virtio_req *req, uint32_t len); -void virtio_process_queue(struct virtio_dev *dev, uint32_t qidx); -void virtio_set_queue_max_merge_len(struct virtio_dev *dev, int q, int len); - -#define container_of(ptr, type, member) \ - (type *)((char *)(ptr) - __builtin_offsetof(type, member)) - -#endif /* _LKL_LIB_VIRTIO_H */ diff --git a/src/linux/tools/lkl/lib/virtio_blk.c b/src/linux/tools/lkl/lib/virtio_blk.c deleted file mode 100644 index 7770c05..0000000 --- a/src/linux/tools/lkl/lib/virtio_blk.c +++ /dev/null @@ -1,131 +0,0 @@ -#include -#include "virtio.h" -#include "endian.h" - -struct virtio_blk_dev { - struct virtio_dev dev; - struct lkl_virtio_blk_config config; - struct lkl_dev_blk_ops *ops; - struct lkl_disk disk; -}; - -struct virtio_blk_req_trailer { - uint8_t status; -}; - -static int blk_check_features(struct virtio_dev *dev) -{ - if (dev->driver_features == dev->device_features) - return 0; - - return -LKL_EINVAL; -} - -static int blk_enqueue(struct virtio_dev *dev, int q, struct virtio_req *req) -{ - struct virtio_blk_dev *blk_dev; - struct lkl_virtio_blk_outhdr *h; - struct virtio_blk_req_trailer *t; - struct lkl_blk_req lkl_req; - - if (req->buf_count < 3) { - lkl_printf("virtio_blk: no status buf\n"); - goto out; - } - - h = req->buf[0].iov_base; - t = req->buf[req->buf_count - 1].iov_base; - blk_dev = container_of(dev, struct virtio_blk_dev, dev); - - t->status = LKL_DEV_BLK_STATUS_IOERR; - - if (req->buf[0].iov_len != sizeof(*h)) { - lkl_printf("virtio_blk: bad header buf\n"); - goto out; - } - - if (req->buf[req->buf_count - 1].iov_len != sizeof(*t)) { - lkl_printf("virtio_blk: bad status buf\n"); - goto out; - } - - lkl_req.type = le32toh(h->type); - lkl_req.prio = le32toh(h->ioprio); - lkl_req.sector = le32toh(h->sector); - lkl_req.buf = &req->buf[1]; - lkl_req.count = req->buf_count - 2; - - t->status = blk_dev->ops->request(blk_dev->disk, &lkl_req); - -out: - virtio_req_complete(req, 0); - return 0; -} - -static struct virtio_dev_ops blk_ops = { - .check_features = blk_check_features, - .enqueue = blk_enqueue, -}; - - -int lkl_disk_add(struct lkl_disk *disk) -{ - struct virtio_blk_dev *dev; - unsigned long long capacity; - int ret; - - dev = lkl_host_ops.mem_alloc(sizeof(*dev)); - if (!dev) - return -LKL_ENOMEM; - - disk->dev = dev; - - dev->dev.device_id = LKL_VIRTIO_ID_BLOCK; - dev->dev.vendor_id = 0; - dev->dev.device_features = 0; - dev->dev.config_gen = 0; - dev->dev.config_data = &dev->config; - dev->dev.config_len = sizeof(dev->config); - dev->dev.ops = &blk_ops; - if (disk->ops) - dev->ops = disk->ops; - else - dev->ops = &lkl_dev_blk_ops; - dev->disk = *disk; - - ret = dev->ops->get_capacity(*disk, &capacity); - if (ret) { - ret = -LKL_ENOMEM; - goto out_free; - } - dev->config.capacity = capacity / 512; - - ret = virtio_dev_setup(&dev->dev, 1, 32); - if (ret) - goto out_free; - - return dev->dev.virtio_mmio_id; - -out_free: - lkl_host_ops.mem_free(dev); - - return ret; -} - -int lkl_disk_remove(struct lkl_disk disk) -{ - struct virtio_blk_dev *dev; - int ret; - - dev = (struct virtio_blk_dev *)disk.dev; - if (!dev) - return -LKL_EINVAL; - - ret = virtio_dev_cleanup(&dev->dev); - if (ret < 0) - return ret; - - lkl_host_ops.mem_free(dev); - - return 0; -} diff --git a/src/linux/tools/lkl/lib/virtio_net.c b/src/linux/tools/lkl/lib/virtio_net.c deleted file mode 100644 index a06c213..0000000 --- a/src/linux/tools/lkl/lib/virtio_net.c +++ /dev/null @@ -1,317 +0,0 @@ -#include -#include -#include "virtio.h" -#include "endian.h" - -#include - -#define netdev_of(x) (container_of(x, struct virtio_net_dev, dev)) -#define BIT(x) (1ULL << x) - -/* We always have 2 queues on a netdev: one for tx, one for rx. */ -#define RX_QUEUE_IDX 0 -#define TX_QUEUE_IDX 1 - -#define NUM_QUEUES (TX_QUEUE_IDX + 1) -#define QUEUE_DEPTH 128 - -/* In fact, we'll hit the limit on the devs string below long before - * we hit this, but it's good enough for now. */ -#define MAX_NET_DEVS 16 - -#ifdef DEBUG -#define bad_request(s) do { \ - lkl_printf("%s\n", s); \ - panic(); \ - } while (0) -#else -#define bad_request(s) lkl_printf("virtio_net: %s\n", s); -#endif /* DEBUG */ - -struct virtio_net_dev { - struct virtio_dev dev; - struct lkl_virtio_net_config config; - struct lkl_netdev *nd; - struct lkl_mutex **queue_locks; - lkl_thread_t poll_tid; -}; - -static int net_check_features(struct virtio_dev *dev) -{ - if (dev->driver_features == dev->device_features) - return 0; - - return -LKL_EINVAL; -} - -static void net_acquire_queue(struct virtio_dev *dev, int queue_idx) -{ - lkl_host_ops.mutex_lock(netdev_of(dev)->queue_locks[queue_idx]); -} - -static void net_release_queue(struct virtio_dev *dev, int queue_idx) -{ - lkl_host_ops.mutex_unlock(netdev_of(dev)->queue_locks[queue_idx]); -} - -/* - * The buffers passed through "req" from the virtio_net driver always starts - * with a vnet_hdr. We need to check the backend device if it expects vnet_hdr - * and adjust buffer offset accordingly. - */ -static int net_enqueue(struct virtio_dev *dev, int q, struct virtio_req *req) -{ - struct lkl_virtio_net_hdr_v1 *header; - struct virtio_net_dev *net_dev; - struct iovec *iov; - int ret; - - header = req->buf[0].iov_base; - net_dev = netdev_of(dev); - /* - * The backend device does not expect a vnet_hdr so adjust buf - * accordingly. (We make adjustment to req->buf so it can be used - * directly for the tx/rx call but remember to undo the change after the - * call. Note that it's ok to pass iov with entry's len==0. The caller - * will skip to the next entry correctly. - */ - if (!net_dev->nd->has_vnet_hdr) { - req->buf[0].iov_base += sizeof(*header); - req->buf[0].iov_len -= sizeof(*header); - } - iov = req->buf; - - /* Pick which virtqueue to send the buffer(s) to */ - if (q == TX_QUEUE_IDX) { - ret = net_dev->nd->ops->tx(net_dev->nd, iov, req->buf_count); - if (ret < 0) - return -1; - } else if (q == RX_QUEUE_IDX) { - int i, len; - - ret = net_dev->nd->ops->rx(net_dev->nd, iov, req->buf_count); - if (ret < 0) - return -1; - if (net_dev->nd->has_vnet_hdr) { - /* - * If the number of bytes returned exactly matches the - * total space in the iov then there is a good chance we - * did not supply a large enough buffer for the whole - * pkt, i.e., pkt has been truncated. This is only - * likely to happen under mergeable RX buffer mode. - */ - if (req->total_len == (unsigned int)ret) - lkl_printf("PKT is likely truncated! len=%d\n", - ret); - } else { - header->flags = 0; - header->gso_type = LKL_VIRTIO_NET_HDR_GSO_NONE; - } - /* - * Have to compute how many descriptors we've consumed (really - * only matters to the the mergeable RX mode) and return it - * through "num_buffers". - */ - for (i = 0, len = ret; len > 0; i++) - len -= req->buf[i].iov_len; - header->num_buffers = i; - - if (dev->device_features & BIT(LKL_VIRTIO_NET_F_GUEST_CSUM)) - header->flags = LKL_VIRTIO_NET_HDR_F_DATA_VALID; - } else { - bad_request("tried to push on non-existent queue"); - return -1; - } - if (!net_dev->nd->has_vnet_hdr) { - /* Undo the adjustment */ - req->buf[0].iov_base -= sizeof(*header); - req->buf[0].iov_len += sizeof(*header); - ret += sizeof(struct lkl_virtio_net_hdr_v1); - } - virtio_req_complete(req, ret); - return 0; -} - -static struct virtio_dev_ops net_ops = { - .check_features = net_check_features, - .enqueue = net_enqueue, - .acquire_queue = net_acquire_queue, - .release_queue = net_release_queue, -}; - -void poll_thread(void *arg) -{ - struct virtio_net_dev *dev = arg; - - /* Synchronization is handled in virtio_process_queue */ - do { - int ret = dev->nd->ops->poll(dev->nd); - - if (ret < 0) { - lkl_printf("virtio net poll error: %d\n", ret); - continue; - } - if (ret & LKL_DEV_NET_POLL_HUP) - break; - if (ret & LKL_DEV_NET_POLL_RX) - virtio_process_queue(&dev->dev, 0); - if (ret & LKL_DEV_NET_POLL_TX) - virtio_process_queue(&dev->dev, 1); - } while (1); -} - -struct virtio_net_dev *registered_devs[MAX_NET_DEVS]; -static int registered_dev_idx = 0; - -static int dev_register(struct virtio_net_dev *dev) -{ - if (registered_dev_idx == MAX_NET_DEVS) { - lkl_printf("Too many virtio_net devices!\n"); - /* This error code is a little bit of a lie */ - return -LKL_ENOMEM; - } else { - /* registered_dev_idx is incremented by the caller */ - registered_devs[registered_dev_idx] = dev; - return 0; - } -} - -static void free_queue_locks(struct lkl_mutex **queues, int num_queues) -{ - int i = 0; - if (!queues) - return; - - for (i = 0; i < num_queues; i++) - lkl_host_ops.mutex_free(queues[i]); - - lkl_host_ops.mem_free(queues); -} - -static struct lkl_mutex **init_queue_locks(int num_queues) -{ - int i; - struct lkl_mutex **ret = lkl_host_ops.mem_alloc( - sizeof(struct lkl_mutex*) * num_queues); - if (!ret) - return NULL; - - for (i = 0; i < num_queues; i++) { - ret[i] = lkl_host_ops.mutex_alloc(1); - if (!ret[i]) { - free_queue_locks(ret, i); - return NULL; - } - } - - return ret; -} - -int lkl_netdev_add(struct lkl_netdev *nd, struct lkl_netdev_args* args) -{ - struct virtio_net_dev *dev; - int ret = -LKL_ENOMEM; - - dev = lkl_host_ops.mem_alloc(sizeof(*dev)); - if (!dev) - return -LKL_ENOMEM; - - memset(dev, 0, sizeof(*dev)); - - dev->dev.device_id = LKL_VIRTIO_ID_NET; - if (args) { - if (args->mac) { - dev->dev.device_features |= BIT(LKL_VIRTIO_NET_F_MAC); - memcpy(dev->config.mac, args->mac, LKL_ETH_ALEN); - } - dev->dev.device_features |= args->offload; - - } - dev->dev.config_data = &dev->config; - dev->dev.config_len = sizeof(dev->config); - dev->dev.ops = &net_ops; - dev->nd = nd; - dev->queue_locks = init_queue_locks(NUM_QUEUES); - - if (!dev->queue_locks) - goto out_free; - - /* - * MUST match the number of queue locks we initialized. We could init - * the queues in virtio_dev_setup to help enforce this, but netdevs are - * the only flavor that need these locks, so it's better to do it - * here. - */ - ret = virtio_dev_setup(&dev->dev, NUM_QUEUES, QUEUE_DEPTH); - - if (ret) - goto out_free; - - /* - * We may receive upto 64KB TSO packet so collect as many descriptors as - * there are available up to 64KB in total len. - */ - if (dev->dev.device_features & BIT(LKL_VIRTIO_NET_F_MRG_RXBUF)) - virtio_set_queue_max_merge_len(&dev->dev, RX_QUEUE_IDX, 65536); - - dev->poll_tid = lkl_host_ops.thread_create(poll_thread, dev); - if (dev->poll_tid == 0) - goto out_cleanup_dev; - - ret = dev_register(dev); - if (ret < 0) - goto out_cleanup_dev; - - return registered_dev_idx++; - -out_cleanup_dev: - virtio_dev_cleanup(&dev->dev); - -out_free: - if (dev->queue_locks) - free_queue_locks(dev->queue_locks, NUM_QUEUES); - lkl_host_ops.mem_free(dev); - - return ret; -} - -/* Return 0 for success, -1 for failure. */ -void lkl_netdev_remove(int id) -{ - struct virtio_net_dev *dev; - int ret; - - if (id >= registered_dev_idx) { - lkl_printf("%s: invalid id: %d\n", __func__, id); - return; - } - - dev = registered_devs[id]; - - dev->nd->ops->poll_hup(dev->nd); - lkl_host_ops.thread_join(dev->poll_tid); - - ret = lkl_netdev_get_ifindex(id); - if (ret < 0) { - lkl_printf("%s: failed to get ifindex for id %d: %s\n", - __func__, id, lkl_strerror(ret)); - return; - } - - ret = lkl_if_down(ret); - if (ret < 0) { - lkl_printf("%s: failed to put interface id %d down: %s\n", - __func__, id, lkl_strerror(ret)); - return; - } - - virtio_dev_cleanup(&dev->dev); - - free_queue_locks(dev->queue_locks, NUM_QUEUES); - lkl_host_ops.mem_free(dev); -} - -void lkl_netdev_free(struct lkl_netdev *nd) -{ - nd->ops->free(nd); -} diff --git a/src/linux/tools/lkl/lib/virtio_net_fd.c b/src/linux/tools/lkl/lib/virtio_net_fd.c deleted file mode 100644 index 6fa09ca..0000000 --- a/src/linux/tools/lkl/lib/virtio_net_fd.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * POSIX file descriptor based virtual network interface feature for - * LKL Copyright (c) 2015,2016 Ryo Nakamura, Hajime Tazaki - * - * Author: Ryo Nakamura - * Hajime Tazaki - * Octavian Purdila - * - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "virtio.h" -#include "virtio_net_fd.h" - -struct lkl_netdev_fd { - struct lkl_netdev dev; - /* file-descriptor based device */ - int fd; - /* - * Controlls the poll mask for fd. Can be acccessed concurrently from - * poll, tx, or rx routines but there is no need for syncronization - * because: - * - * (a) TX and RX routines set different variables so even if they update - * at the same time there is no race condition - * - * (b) Even if poll and TX / RX update at the same time poll cannot - * stall: when poll resets the poll variable we know that TX / RX will - * run which means that eventually the poll variable will be set. - */ - int poll_tx, poll_rx; - /* controle pipe */ - int pipe[2]; -}; - -static int fd_net_tx(struct lkl_netdev *nd, struct iovec *iov, int cnt) -{ - int ret; - struct lkl_netdev_fd *nd_fd = - container_of(nd, struct lkl_netdev_fd, dev); - - do { - ret = writev(nd_fd->fd, iov, cnt); - } while (ret == -1 && errno == EINTR); - - if (ret < 0) { - if (errno != EAGAIN) { - perror("write to fd netdev fails"); - } else { - char tmp; - - nd_fd->poll_tx = 1; - if (write(nd_fd->pipe[1], &tmp, 1) <= 0) - perror("virtio net fd pipe write"); - } - } - return ret; -} - -static int fd_net_rx(struct lkl_netdev *nd, struct iovec *iov, int cnt) -{ - int ret; - struct lkl_netdev_fd *nd_fd = - container_of(nd, struct lkl_netdev_fd, dev); - - do { - ret = readv(nd_fd->fd, (struct iovec *)iov, cnt); - } while (ret == -1 && errno == EINTR); - - if (ret < 0) { - if (errno != EAGAIN) { - perror("virtio net fd read"); - } else { - char tmp; - - nd_fd->poll_rx = 1; - if (write(nd_fd->pipe[1], &tmp, 1) < 0) - perror("virtio net fd pipe write"); - } - } - return ret; -} - -static int fd_net_poll(struct lkl_netdev *nd) -{ - struct lkl_netdev_fd *nd_fd = - container_of(nd, struct lkl_netdev_fd, dev); - struct pollfd pfds[2] = { - { - .fd = nd_fd->fd, - }, - { - .fd = nd_fd->pipe[0], - .events = POLLIN, - }, - }; - int ret; - - if (nd_fd->poll_rx) - pfds[0].events |= POLLIN|POLLPRI; - if (nd_fd->poll_tx) - pfds[0].events |= POLLOUT; - - do { - ret = poll(pfds, 2, -1); - } while (ret == -1 && errno == EINTR); - - if (ret < 0) { - perror("virtio net fd poll"); - return 0; - } - - if (pfds[1].revents & (POLLHUP|POLLNVAL)) - return LKL_DEV_NET_POLL_HUP; - - if (pfds[1].revents & POLLIN) { - char tmp[PIPE_BUF]; - - ret = read(nd_fd->pipe[0], tmp, PIPE_BUF); - if (ret == 0) - return LKL_DEV_NET_POLL_HUP; - if (ret < 0) - perror("virtio net fd pipe read"); - } - - ret = 0; - - if (pfds[0].revents & (POLLIN|POLLPRI)) { - nd_fd->poll_rx = 0; - ret |= LKL_DEV_NET_POLL_RX; - } - - if (pfds[0].revents & POLLOUT) { - nd_fd->poll_tx = 0; - ret |= LKL_DEV_NET_POLL_TX; - } - - return ret; -} - -static void fd_net_poll_hup(struct lkl_netdev *nd) -{ - struct lkl_netdev_fd *nd_fd = - container_of(nd, struct lkl_netdev_fd, dev); - - /* this will cause a POLLHUP / POLLNVAL in the poll function */ - close(nd_fd->pipe[0]); - close(nd_fd->pipe[1]); -} - -static void fd_net_free(struct lkl_netdev *nd) -{ - struct lkl_netdev_fd *nd_fd = - container_of(nd, struct lkl_netdev_fd, dev); - - close(nd_fd->fd); - free(nd_fd); -} - -struct lkl_dev_net_ops fd_net_ops = { - .tx = fd_net_tx, - .rx = fd_net_rx, - .poll = fd_net_poll, - .poll_hup = fd_net_poll_hup, - .free = fd_net_free, -}; - -struct lkl_netdev *lkl_register_netdev_fd(int fd) -{ - struct lkl_netdev_fd *nd; - - nd = malloc(sizeof(*nd)); - if (!nd) { - fprintf(stderr, "fdnet: failed to allocate memory\n"); - /* TODO: propagate the error state, maybe use errno for that? */ - return NULL; - } - - memset(nd, 0, sizeof(*nd)); - - nd->fd = fd; - if (pipe(nd->pipe) < 0) { - perror("pipe"); - free(nd); - return NULL; - } - - if (fcntl(nd->pipe[0], F_SETFL, O_NONBLOCK) < 0) { - perror("fnctl"); - close(nd->pipe[0]); - close(nd->pipe[1]); - free(nd); - return NULL; - } - - nd->dev.ops = &fd_net_ops; - return &nd->dev; -} diff --git a/src/linux/tools/lkl/lib/virtio_net_fd.h b/src/linux/tools/lkl/lib/virtio_net_fd.h deleted file mode 100644 index 5c1921b..0000000 --- a/src/linux/tools/lkl/lib/virtio_net_fd.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef _VIRTIO_NET_FD_H -#define _VIRTIO_NET_FD_H - -struct ifreq; - -/** - * lkl_register_netdev_linux_fdnet - register a file descriptor-based network - * device as a NIC - * - * @fd - a POSIX file descriptor number for input/output - * @returns a struct lkl_netdev_linux_fdnet entry for virtio-net - */ -struct lkl_netdev *lkl_register_netdev_fd(int fd); - - -/** - * lkl_netdev_tap_init - initialize tap related structure fot lkl_netdev. - * - * @path - the path to open the device. - * @offload - offload bits for the device - * @ifr - struct ifreq for ioctl. - */ -struct lkl_netdev *lkl_netdev_tap_init(const char *path, int offload, - struct ifreq *ifr); - -#endif /* _VIRTIO_NET_FD_H*/ diff --git a/src/linux/tools/lkl/lib/virtio_net_macvtap.c b/src/linux/tools/lkl/lib/virtio_net_macvtap.c deleted file mode 100644 index 1e97b74..0000000 --- a/src/linux/tools/lkl/lib/virtio_net_macvtap.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * macvtap based virtual network interface feature for LKL - * Copyright (c) 2016 Hajime Tazaki - * - * Author: Hajime Tazaki - * - * Current implementation is linux-specific. - */ - -/* - * You need to configure host device in advance. - * - * sudo ip link add link eth0 name vtap0 type macvtap mode passthru - * sudo ip link set dev vtap0 up - * sudo chown thehajime /dev/tap22 - */ - -#include -#include - -#include "virtio.h" -#include "virtio_net_fd.h" - -struct lkl_netdev *lkl_netdev_macvtap_create(const char *path, int offload) -{ - struct ifreq ifr = { - .ifr_flags = IFF_TAP | IFF_NO_PI, - }; - - return lkl_netdev_tap_init(path, offload, &ifr); -} diff --git a/src/linux/tools/lkl/lib/virtio_net_raw.c b/src/linux/tools/lkl/lib/virtio_net_raw.c deleted file mode 100644 index 1161e94..0000000 --- a/src/linux/tools/lkl/lib/virtio_net_raw.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * raw socket based virtual network interface feature for LKL - * Copyright (c) 2015,2016 Ryo Nakamura, Hajime Tazaki - * - * Author: Ryo Nakamura - * Hajime Tazaki - * - * Current implementation is linux-specific. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "virtio.h" -#include "virtio_net_fd.h" - -/* since Linux 3.14 (man 7 packet) */ -#ifndef PACKET_QDISC_BYPASS -#define PACKET_QDISC_BYPASS 20 -#endif - -struct lkl_netdev *lkl_netdev_raw_create(const char *ifname) -{ - int ret; - struct sockaddr_ll ll; - int fd, fd_flags, val; - - fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); - if (fd < 0) { - perror("socket"); - return NULL; - } - - memset(&ll, 0, sizeof(ll)); - ll.sll_family = PF_PACKET; - ll.sll_ifindex = if_nametoindex(ifname); - ll.sll_protocol = htons(ETH_P_ALL); - ret = bind(fd, (struct sockaddr *)&ll, sizeof(ll)); - if (ret) { - perror("bind"); - close(fd); - return NULL; - } - - val = 1; - ret = setsockopt(fd, SOL_PACKET, PACKET_QDISC_BYPASS, &val, - sizeof(val)); - if (ret) - perror("PACKET_QDISC_BYPASS, ignoring"); - - fd_flags = fcntl(fd, F_GETFD, NULL); - fcntl(fd, F_SETFL, fd_flags | O_NONBLOCK); - - return lkl_register_netdev_fd(fd); -} diff --git a/src/linux/tools/lkl/lib/virtio_net_tap.c b/src/linux/tools/lkl/lib/virtio_net_tap.c deleted file mode 100644 index 60bf1fd..0000000 --- a/src/linux/tools/lkl/lib/virtio_net_tap.c +++ /dev/null @@ -1,91 +0,0 @@ -/* - * tun/tap based virtual network interface feature for LKL - * Copyright (c) 2015,2016 Ryo Nakamura, Hajime Tazaki - * - * Author: Ryo Nakamura - * Hajime Tazaki - * Octavian Purdila - * - * Current implementation is linux-specific. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "virtio.h" -#include "virtio_net_fd.h" - -#define BIT(x) (1ULL << x) - -struct lkl_netdev *lkl_netdev_tap_init(const char *path, int offload, - struct ifreq *ifr) -{ - struct lkl_netdev *nd; - int fd, ret, tap_arg = 0, vnet_hdr_sz = 0; - - if (offload & BIT(LKL_VIRTIO_NET_F_GUEST_CSUM)) - tap_arg |= TUN_F_CSUM; - if (offload & (BIT(LKL_VIRTIO_NET_F_GUEST_TSO4) | - BIT(LKL_VIRTIO_NET_F_MRG_RXBUF))) - tap_arg |= TUN_F_TSO4 | TUN_F_CSUM; - - if (tap_arg || (offload & (BIT(LKL_VIRTIO_NET_F_CSUM) | - BIT(LKL_VIRTIO_NET_F_HOST_TSO4)))) { - ifr->ifr_flags |= IFF_VNET_HDR; - vnet_hdr_sz = sizeof(struct lkl_virtio_net_hdr_v1); - } - - - fd = open(path, O_RDWR|O_NONBLOCK); - if (fd < 0) { - perror("open"); - return NULL; - } - - ret = ioctl(fd, TUNSETIFF, ifr); - if (ret < 0) { - fprintf(stderr, "%s: failed to attach to: %s\n", - path, strerror(errno)); - close(fd); - return NULL; - } - if (vnet_hdr_sz && ioctl(fd, TUNSETVNETHDRSZ, &vnet_hdr_sz) != 0) { - fprintf(stderr, "%s: failed to TUNSETVNETHDRSZ to: %s\n", - path, strerror(errno)); - close(fd); - return NULL; - } - if (ioctl(fd, TUNSETOFFLOAD, tap_arg) != 0) { - fprintf(stderr, "%s: failed to TUNSETOFFLOAD: %s\n", - path, strerror(errno)); - close(fd); - return NULL; - } - nd = lkl_register_netdev_fd(fd); - if (!nd) { - perror("failed to register to."); - close(fd); - return NULL; - } - - nd->has_vnet_hdr = (vnet_hdr_sz != 0); - return nd; -} - -struct lkl_netdev *lkl_netdev_tap_create(const char *ifname, int offload) -{ - char *path = "/dev/net/tun"; - struct ifreq ifr = { - .ifr_flags = IFF_TAP | IFF_NO_PI, - }; - - strncpy(ifr.ifr_name, ifname, IFNAMSIZ); - - return lkl_netdev_tap_init(path, offload, &ifr); -} diff --git a/src/linux/tools/objtool/.gitignore b/src/linux/tools/objtool/.gitignore deleted file mode 100644 index d3102c8..0000000 --- a/src/linux/tools/objtool/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -arch/x86/insn/inat-tables.c -objtool -fixdep diff --git a/src/linux/tools/pcmcia/.gitignore b/src/linux/tools/pcmcia/.gitignore deleted file mode 100644 index 53d0813..0000000 --- a/src/linux/tools/pcmcia/.gitignore +++ /dev/null @@ -1 +0,0 @@ -crc32hash diff --git a/src/linux/tools/perf/.gitignore b/src/linux/tools/perf/.gitignore deleted file mode 100644 index 3db3db9..0000000 --- a/src/linux/tools/perf/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -PERF-CFLAGS -PERF-GUI-VARS -PERF-VERSION-FILE -FEATURE-DUMP -perf -perf-read-vdso32 -perf-read-vdsox32 -perf-help -perf-record -perf-report -perf-stat -perf-top -perf*.1 -perf*.xml -perf*.html -common-cmds.h -perf.data -perf.data.old -output.svg -perf-archive -perf-with-kcore -tags -TAGS -cscope* -config.mak -config.mak.autogen -*-bison.* -*-flex.* -*.pyc -*.pyo -.config-detected -util/intel-pt-decoder/inat-tables.c -arch/*/include/generated/ diff --git a/src/linux/tools/perf/tests/.gitignore b/src/linux/tools/perf/tests/.gitignore deleted file mode 100644 index 8cc30e7..0000000 --- a/src/linux/tools/perf/tests/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -llvm-src-base.c -llvm-src-kbuild.c -llvm-src-prologue.c -llvm-src-relocation.c diff --git a/src/linux/tools/power/cpupower/.gitignore b/src/linux/tools/power/cpupower/.gitignore deleted file mode 100644 index d42073f..0000000 --- a/src/linux/tools/power/cpupower/.gitignore +++ /dev/null @@ -1,29 +0,0 @@ -.libs -libcpupower.so -libcpupower.so.0 -libcpupower.so.0.0.0 -build/ccdv -cpufreq-info -cpufreq-set -cpufreq-aperf -lib/.libs -lib/cpufreq.lo -lib/cpufreq.o -lib/proc.lo -lib/proc.o -lib/sysfs.lo -lib/sysfs.o -po/cpupowerutils.pot -po/*.gmo -utils/cpufreq-info.o -utils/cpufreq-set.o -utils/cpufreq-aperf.o -cpupower -bench/cpufreq-bench -debug/kernel/Module.symvers -debug/i386/centrino-decode -debug/i386/dump_psb -debug/i386/intel_gsic -debug/i386/powernow-k8-decode -debug/x86_64/centrino-decode -debug/x86_64/powernow-k8-decode diff --git a/src/linux/tools/power/x86/turbostat/.gitignore b/src/linux/tools/power/x86/turbostat/.gitignore deleted file mode 100644 index 7521370..0000000 --- a/src/linux/tools/power/x86/turbostat/.gitignore +++ /dev/null @@ -1 +0,0 @@ -turbostat diff --git a/src/linux/tools/scripts/Makefile.include b/src/linux/tools/scripts/Makefile.include deleted file mode 100644 index 8abbef1..0000000 --- a/src/linux/tools/scripts/Makefile.include +++ /dev/null @@ -1,84 +0,0 @@ -ifneq ($(O),) -ifeq ($(origin O), command line) - dummy := $(if $(shell test -d $(O) || echo $(O)),$(error O=$(O) does not exist),) - ABSOLUTE_O := $(shell cd $(O) ; pwd) - OUTPUT := $(ABSOLUTE_O)/$(if $(subdir),$(subdir)/) - COMMAND_O := O=$(ABSOLUTE_O) -ifeq ($(objtree),) - objtree := $(O) -endif -endif -endif - -# check that the output directory actually exists -ifneq ($(OUTPUT),) -OUTDIR := $(shell cd $(OUTPUT) && /bin/pwd) -$(if $(OUTDIR),, $(error output directory "$(OUTPUT)" does not exist)) -endif - -# -# Include saner warnings here, which can catch bugs: -# -EXTRA_WARNINGS := -Wbad-function-cast -EXTRA_WARNINGS += -Wdeclaration-after-statement -EXTRA_WARNINGS += -Wformat-security -EXTRA_WARNINGS += -Wformat-y2k -EXTRA_WARNINGS += -Winit-self -EXTRA_WARNINGS += -Wmissing-declarations -EXTRA_WARNINGS += -Wmissing-prototypes -EXTRA_WARNINGS += -Wnested-externs -EXTRA_WARNINGS += -Wno-system-headers -EXTRA_WARNINGS += -Wold-style-definition -EXTRA_WARNINGS += -Wpacked -EXTRA_WARNINGS += -Wredundant-decls -EXTRA_WARNINGS += -Wshadow -EXTRA_WARNINGS += -Wstrict-aliasing=3 -EXTRA_WARNINGS += -Wstrict-prototypes -EXTRA_WARNINGS += -Wswitch-default -EXTRA_WARNINGS += -Wswitch-enum -EXTRA_WARNINGS += -Wundef -EXTRA_WARNINGS += -Wwrite-strings -EXTRA_WARNINGS += -Wformat - -ifneq ($(findstring $(MAKEFLAGS), w),w) -PRINT_DIR = --no-print-directory -else -NO_SUBDIR = : -endif - -# -# Define a callable command for descending to a new directory -# -# Call by doing: $(call descend,directory[,target]) -# -descend = \ - +mkdir -p $(OUTPUT)$(1) && \ - $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2) - -QUIET_SUBDIR0 = +$(MAKE) $(COMMAND_O) -C # space to separate -C and subdir -QUIET_SUBDIR1 = - -ifneq ($(findstring $(MAKEFLAGS),s),s) - ifneq ($(V),1) - QUIET_CC = @echo ' CC '$@; - QUIET_CC_FPIC = @echo ' CC FPIC '$@; - QUIET_AR = @echo ' AR '$@; - QUIET_LINK = @echo ' LINK '$@; - QUIET_MKDIR = @echo ' MKDIR '$@; - QUIET_GEN = @echo ' GEN '$@; - QUIET_SUBDIR0 = +@subdir= - QUIET_SUBDIR1 = ;$(NO_SUBDIR) \ - echo ' SUBDIR '$$subdir; \ - $(MAKE) $(PRINT_DIR) -C $$subdir - QUIET_FLEX = @echo ' FLEX '$@; - QUIET_BISON = @echo ' BISON '$@; - - descend = \ - +@echo ' DESCEND '$(1); \ - mkdir -p $(OUTPUT)$(1) && \ - $(MAKE) $(COMMAND_O) subdir=$(if $(subdir),$(subdir)/$(1),$(1)) $(PRINT_DIR) -C $(1) $(2) - - QUIET_CLEAN = @printf ' CLEAN %s\n' $1; - QUIET_INSTALL = @printf ' INSTALL %s\n' $1; - endif -endif diff --git a/src/linux/tools/spi/.gitignore b/src/linux/tools/spi/.gitignore deleted file mode 100644 index 4280576..0000000 --- a/src/linux/tools/spi/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -spidev_fdx -spidev_test diff --git a/src/linux/tools/testing/radix-tree/.gitignore b/src/linux/tools/testing/radix-tree/.gitignore deleted file mode 100644 index 11d888c..0000000 --- a/src/linux/tools/testing/radix-tree/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -main -radix-tree.c diff --git a/src/linux/tools/testing/selftests/breakpoints/.gitignore b/src/linux/tools/testing/selftests/breakpoints/.gitignore deleted file mode 100644 index a23bb4a..0000000 --- a/src/linux/tools/testing/selftests/breakpoints/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -breakpoint_test -step_after_suspend_test diff --git a/src/linux/tools/testing/selftests/capabilities/.gitignore b/src/linux/tools/testing/selftests/capabilities/.gitignore deleted file mode 100644 index b732dd0..0000000 --- a/src/linux/tools/testing/selftests/capabilities/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -test_execve -validate_cap diff --git a/src/linux/tools/testing/selftests/efivarfs/.gitignore b/src/linux/tools/testing/selftests/efivarfs/.gitignore deleted file mode 100644 index 3361849..0000000 --- a/src/linux/tools/testing/selftests/efivarfs/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -create-read -open-unlink diff --git a/src/linux/tools/testing/selftests/exec/.gitignore b/src/linux/tools/testing/selftests/exec/.gitignore deleted file mode 100644 index 64073e0..0000000 --- a/src/linux/tools/testing/selftests/exec/.gitignore +++ /dev/null @@ -1,9 +0,0 @@ -subdir* -script* -execveat -execveat.symlink -execveat.moved -execveat.path.ephemeral -execveat.ephemeral -execveat.denatured -xxxxxxxx* \ No newline at end of file diff --git a/src/linux/tools/testing/selftests/filesystems/.gitignore b/src/linux/tools/testing/selftests/filesystems/.gitignore deleted file mode 100644 index 31d6e42..0000000 --- a/src/linux/tools/testing/selftests/filesystems/.gitignore +++ /dev/null @@ -1 +0,0 @@ -dnotify_test diff --git a/src/linux/tools/testing/selftests/futex/functional/.gitignore b/src/linux/tools/testing/selftests/futex/functional/.gitignore deleted file mode 100644 index a09f570..0000000 --- a/src/linux/tools/testing/selftests/futex/functional/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -futex_requeue_pi -futex_requeue_pi_mismatched_ops -futex_requeue_pi_signal_restart -futex_wait_private_mapped_file -futex_wait_timeout -futex_wait_uninitialized_heap -futex_wait_wouldblock diff --git a/src/linux/tools/testing/selftests/ia64/.gitignore b/src/linux/tools/testing/selftests/ia64/.gitignore deleted file mode 100644 index ab806ed..0000000 --- a/src/linux/tools/testing/selftests/ia64/.gitignore +++ /dev/null @@ -1 +0,0 @@ -aliasing-test diff --git a/src/linux/tools/testing/selftests/ipc/.gitignore b/src/linux/tools/testing/selftests/ipc/.gitignore deleted file mode 100644 index 84b66a3..0000000 --- a/src/linux/tools/testing/selftests/ipc/.gitignore +++ /dev/null @@ -1 +0,0 @@ -msgque_test diff --git a/src/linux/tools/testing/selftests/kcmp/.gitignore b/src/linux/tools/testing/selftests/kcmp/.gitignore deleted file mode 100644 index 5a9b373..0000000 --- a/src/linux/tools/testing/selftests/kcmp/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -kcmp_test -kcmp-test-file diff --git a/src/linux/tools/testing/selftests/media_tests/.gitignore b/src/linux/tools/testing/selftests/media_tests/.gitignore deleted file mode 100644 index 8745eba..0000000 --- a/src/linux/tools/testing/selftests/media_tests/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -media_device_test -media_device_open -video_device_test diff --git a/src/linux/tools/testing/selftests/membarrier/.gitignore b/src/linux/tools/testing/selftests/membarrier/.gitignore deleted file mode 100644 index 020c44f..0000000 --- a/src/linux/tools/testing/selftests/membarrier/.gitignore +++ /dev/null @@ -1 +0,0 @@ -membarrier_test diff --git a/src/linux/tools/testing/selftests/memfd/.gitignore b/src/linux/tools/testing/selftests/memfd/.gitignore deleted file mode 100644 index afe87c4..0000000 --- a/src/linux/tools/testing/selftests/memfd/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -fuse_mnt -fuse_test -memfd_test -memfd-test-file diff --git a/src/linux/tools/testing/selftests/mount/.gitignore b/src/linux/tools/testing/selftests/mount/.gitignore deleted file mode 100644 index 856ad41..0000000 --- a/src/linux/tools/testing/selftests/mount/.gitignore +++ /dev/null @@ -1 +0,0 @@ -unprivileged-remount-test diff --git a/src/linux/tools/testing/selftests/mqueue/.gitignore b/src/linux/tools/testing/selftests/mqueue/.gitignore deleted file mode 100644 index d8d4237..0000000 --- a/src/linux/tools/testing/selftests/mqueue/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -mq_open_tests -mq_perf_tests diff --git a/src/linux/tools/testing/selftests/net/.gitignore b/src/linux/tools/testing/selftests/net/.gitignore deleted file mode 100644 index 0840684..0000000 --- a/src/linux/tools/testing/selftests/net/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -socket -psock_fanout -psock_tpacket -reuseport_bpf -reuseport_bpf_cpu -reuseport_dualstack diff --git a/src/linux/tools/testing/selftests/networking/timestamping/.gitignore b/src/linux/tools/testing/selftests/networking/timestamping/.gitignore deleted file mode 100644 index 9e69e98..0000000 --- a/src/linux/tools/testing/selftests/networking/timestamping/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -timestamping -txtimestamp -hwtstamp_config diff --git a/src/linux/tools/testing/selftests/powerpc/alignment/.gitignore b/src/linux/tools/testing/selftests/powerpc/alignment/.gitignore deleted file mode 100644 index 1d980e3..0000000 --- a/src/linux/tools/testing/selftests/powerpc/alignment/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -copy_unaligned -copy_first_unaligned -paste_unaligned -paste_last_unaligned -copy_paste_unaligned_common diff --git a/src/linux/tools/testing/selftests/powerpc/benchmarks/.gitignore b/src/linux/tools/testing/selftests/powerpc/benchmarks/.gitignore deleted file mode 100644 index bce49eb..0000000 --- a/src/linux/tools/testing/selftests/powerpc/benchmarks/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -gettimeofday -context_switch -mmap_bench -futex_bench \ No newline at end of file diff --git a/src/linux/tools/testing/selftests/powerpc/context_switch/.gitignore b/src/linux/tools/testing/selftests/powerpc/context_switch/.gitignore deleted file mode 100644 index c1431af..0000000 --- a/src/linux/tools/testing/selftests/powerpc/context_switch/.gitignore +++ /dev/null @@ -1 +0,0 @@ -cp_abort diff --git a/src/linux/tools/testing/selftests/powerpc/copyloops/.gitignore b/src/linux/tools/testing/selftests/powerpc/copyloops/.gitignore deleted file mode 100644 index 25a192f..0000000 --- a/src/linux/tools/testing/selftests/powerpc/copyloops/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -copyuser_64 -copyuser_power7 -memcpy_64 -memcpy_power7 diff --git a/src/linux/tools/testing/selftests/powerpc/copyloops/copyuser_64.S b/src/linux/tools/testing/selftests/powerpc/copyloops/copyuser_64.S deleted file mode 120000 index f1c418a..0000000 --- a/src/linux/tools/testing/selftests/powerpc/copyloops/copyuser_64.S +++ /dev/null @@ -1 +0,0 @@ -../../../../../arch/powerpc/lib/copyuser_64.S \ No newline at end of file diff --git a/src/linux/tools/testing/selftests/powerpc/copyloops/copyuser_power7.S b/src/linux/tools/testing/selftests/powerpc/copyloops/copyuser_power7.S deleted file mode 120000 index 4786895..0000000 --- a/src/linux/tools/testing/selftests/powerpc/copyloops/copyuser_power7.S +++ /dev/null @@ -1 +0,0 @@ -../../../../../arch/powerpc/lib/copyuser_power7.S \ No newline at end of file diff --git a/src/linux/tools/testing/selftests/powerpc/copyloops/memcpy_64.S b/src/linux/tools/testing/selftests/powerpc/copyloops/memcpy_64.S deleted file mode 120000 index cce33fb..0000000 --- a/src/linux/tools/testing/selftests/powerpc/copyloops/memcpy_64.S +++ /dev/null @@ -1 +0,0 @@ -../../../../../arch/powerpc/lib/memcpy_64.S \ No newline at end of file diff --git a/src/linux/tools/testing/selftests/powerpc/copyloops/memcpy_power7.S b/src/linux/tools/testing/selftests/powerpc/copyloops/memcpy_power7.S deleted file mode 120000 index 0d6fbfa..0000000 --- a/src/linux/tools/testing/selftests/powerpc/copyloops/memcpy_power7.S +++ /dev/null @@ -1 +0,0 @@ -../../../../../arch/powerpc/lib/memcpy_power7.S \ No newline at end of file diff --git a/src/linux/tools/testing/selftests/powerpc/dscr/.gitignore b/src/linux/tools/testing/selftests/powerpc/dscr/.gitignore deleted file mode 100644 index b585c6c..0000000 --- a/src/linux/tools/testing/selftests/powerpc/dscr/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -dscr_default_test -dscr_explicit_test -dscr_inherit_exec_test -dscr_inherit_test -dscr_sysfs_test -dscr_sysfs_thread_test -dscr_user_test diff --git a/src/linux/tools/testing/selftests/powerpc/math/.gitignore b/src/linux/tools/testing/selftests/powerpc/math/.gitignore deleted file mode 100644 index 50ded63..0000000 --- a/src/linux/tools/testing/selftests/powerpc/math/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -fpu_syscall -vmx_syscall -fpu_preempt -vmx_preempt -fpu_signal -vmx_signal -vsx_preempt diff --git a/src/linux/tools/testing/selftests/powerpc/mm/.gitignore b/src/linux/tools/testing/selftests/powerpc/mm/.gitignore deleted file mode 100644 index e715a3f..0000000 --- a/src/linux/tools/testing/selftests/powerpc/mm/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -hugetlb_vs_thp_test -subpage_prot -tempfile -prot_sao \ No newline at end of file diff --git a/src/linux/tools/testing/selftests/powerpc/pmu/.gitignore b/src/linux/tools/testing/selftests/powerpc/pmu/.gitignore deleted file mode 100644 index e748f33..0000000 --- a/src/linux/tools/testing/selftests/powerpc/pmu/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -count_instructions -l3_bank_test -per_event_excludes diff --git a/src/linux/tools/testing/selftests/powerpc/pmu/ebb/.gitignore b/src/linux/tools/testing/selftests/powerpc/pmu/ebb/.gitignore deleted file mode 100644 index 44b7df1..0000000 --- a/src/linux/tools/testing/selftests/powerpc/pmu/ebb/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -reg_access_test -event_attributes_test -cycles_test -cycles_with_freeze_test -pmc56_overflow_test -ebb_vs_cpu_event_test -cpu_event_vs_ebb_test -cpu_event_pinned_vs_ebb_test -task_event_vs_ebb_test -task_event_pinned_vs_ebb_test -multi_ebb_procs_test -multi_counter_test -pmae_handling_test -close_clears_pmcc_test -instruction_count_test -fork_cleanup_test -ebb_on_child_test -ebb_on_willing_child_test -back_to_back_ebbs_test -lost_exception_test -no_handler_test -cycles_with_mmcr2_test -ebb_lmr -ebb_lmr_regs \ No newline at end of file diff --git a/src/linux/tools/testing/selftests/powerpc/primitives/.gitignore b/src/linux/tools/testing/selftests/powerpc/primitives/.gitignore deleted file mode 100644 index 4cc4e31..0000000 --- a/src/linux/tools/testing/selftests/powerpc/primitives/.gitignore +++ /dev/null @@ -1 +0,0 @@ -load_unaligned_zeropad diff --git a/src/linux/tools/testing/selftests/powerpc/primitives/asm/asm-compat.h b/src/linux/tools/testing/selftests/powerpc/primitives/asm/asm-compat.h deleted file mode 120000 index b14255e..0000000 --- a/src/linux/tools/testing/selftests/powerpc/primitives/asm/asm-compat.h +++ /dev/null @@ -1 +0,0 @@ -../.././../../../../arch/powerpc/include/asm/asm-compat.h \ No newline at end of file diff --git a/src/linux/tools/testing/selftests/powerpc/primitives/word-at-a-time.h b/src/linux/tools/testing/selftests/powerpc/primitives/word-at-a-time.h deleted file mode 120000 index eb74401..0000000 --- a/src/linux/tools/testing/selftests/powerpc/primitives/word-at-a-time.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../arch/powerpc/include/asm/word-at-a-time.h \ No newline at end of file diff --git a/src/linux/tools/testing/selftests/powerpc/signal/.gitignore b/src/linux/tools/testing/selftests/powerpc/signal/.gitignore deleted file mode 100644 index 1b89224..0000000 --- a/src/linux/tools/testing/selftests/powerpc/signal/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -signal -signal_tm diff --git a/src/linux/tools/testing/selftests/powerpc/stringloops/.gitignore b/src/linux/tools/testing/selftests/powerpc/stringloops/.gitignore deleted file mode 100644 index 0b43da7..0000000 --- a/src/linux/tools/testing/selftests/powerpc/stringloops/.gitignore +++ /dev/null @@ -1 +0,0 @@ -memcmp diff --git a/src/linux/tools/testing/selftests/powerpc/stringloops/memcmp_64.S b/src/linux/tools/testing/selftests/powerpc/stringloops/memcmp_64.S deleted file mode 120000 index 9bc87e4..0000000 --- a/src/linux/tools/testing/selftests/powerpc/stringloops/memcmp_64.S +++ /dev/null @@ -1 +0,0 @@ -../../../../../arch/powerpc/lib/memcmp_64.S \ No newline at end of file diff --git a/src/linux/tools/testing/selftests/powerpc/switch_endian/.gitignore b/src/linux/tools/testing/selftests/powerpc/switch_endian/.gitignore deleted file mode 100644 index 89e762e..0000000 --- a/src/linux/tools/testing/selftests/powerpc/switch_endian/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -switch_endian_test -check-reversed.S diff --git a/src/linux/tools/testing/selftests/powerpc/syscalls/.gitignore b/src/linux/tools/testing/selftests/powerpc/syscalls/.gitignore deleted file mode 100644 index f0f3fcc..0000000 --- a/src/linux/tools/testing/selftests/powerpc/syscalls/.gitignore +++ /dev/null @@ -1 +0,0 @@ -ipc_unmuxed diff --git a/src/linux/tools/testing/selftests/powerpc/tm/.gitignore b/src/linux/tools/testing/selftests/powerpc/tm/.gitignore deleted file mode 100644 index 4276217..0000000 --- a/src/linux/tools/testing/selftests/powerpc/tm/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -tm-resched-dscr -tm-syscall -tm-signal-msr-resv -tm-signal-stack -tm-vmxcopy -tm-fork -tm-tar -tm-tmspr -tm-exec -tm-signal-context-chk-fpu -tm-signal-context-chk-gpr -tm-signal-context-chk-vmx -tm-signal-context-chk-vsx diff --git a/src/linux/tools/testing/selftests/powerpc/vphn/.gitignore b/src/linux/tools/testing/selftests/powerpc/vphn/.gitignore deleted file mode 100644 index 7c04395..0000000 --- a/src/linux/tools/testing/selftests/powerpc/vphn/.gitignore +++ /dev/null @@ -1 +0,0 @@ -test-vphn diff --git a/src/linux/tools/testing/selftests/powerpc/vphn/vphn.c b/src/linux/tools/testing/selftests/powerpc/vphn/vphn.c deleted file mode 120000 index 186b906..0000000 --- a/src/linux/tools/testing/selftests/powerpc/vphn/vphn.c +++ /dev/null @@ -1 +0,0 @@ -../../../../../arch/powerpc/mm/vphn.c \ No newline at end of file diff --git a/src/linux/tools/testing/selftests/powerpc/vphn/vphn.h b/src/linux/tools/testing/selftests/powerpc/vphn/vphn.h deleted file mode 120000 index 7131efe..0000000 --- a/src/linux/tools/testing/selftests/powerpc/vphn/vphn.h +++ /dev/null @@ -1 +0,0 @@ -../../../../../arch/powerpc/mm/vphn.h \ No newline at end of file diff --git a/src/linux/tools/testing/selftests/prctl/.gitignore b/src/linux/tools/testing/selftests/prctl/.gitignore deleted file mode 100644 index 0b5c274..0000000 --- a/src/linux/tools/testing/selftests/prctl/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -disable-tsc-ctxt-sw-stress-test -disable-tsc-on-off-stress-test -disable-tsc-test diff --git a/src/linux/tools/testing/selftests/ptp/.gitignore b/src/linux/tools/testing/selftests/ptp/.gitignore deleted file mode 100644 index f562e49..0000000 --- a/src/linux/tools/testing/selftests/ptp/.gitignore +++ /dev/null @@ -1 +0,0 @@ -testptp diff --git a/src/linux/tools/testing/selftests/ptrace/.gitignore b/src/linux/tools/testing/selftests/ptrace/.gitignore deleted file mode 100644 index b3e59d4..0000000 --- a/src/linux/tools/testing/selftests/ptrace/.gitignore +++ /dev/null @@ -1 +0,0 @@ -peeksiginfo diff --git a/src/linux/tools/testing/selftests/rcutorture/.gitignore b/src/linux/tools/testing/selftests/rcutorture/.gitignore deleted file mode 100644 index 05838f6..0000000 --- a/src/linux/tools/testing/selftests/rcutorture/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -initrd -linux-2.6 -b[0-9]* -rcu-test-image -res -*.swp diff --git a/src/linux/tools/testing/selftests/seccomp/.gitignore b/src/linux/tools/testing/selftests/seccomp/.gitignore deleted file mode 100644 index 346d83c..0000000 --- a/src/linux/tools/testing/selftests/seccomp/.gitignore +++ /dev/null @@ -1 +0,0 @@ -seccomp_bpf diff --git a/src/linux/tools/testing/selftests/size/.gitignore b/src/linux/tools/testing/selftests/size/.gitignore deleted file mode 100644 index 189b781..0000000 --- a/src/linux/tools/testing/selftests/size/.gitignore +++ /dev/null @@ -1 +0,0 @@ -get_size diff --git a/src/linux/tools/testing/selftests/timers/.gitignore b/src/linux/tools/testing/selftests/timers/.gitignore deleted file mode 100644 index 68f3fc7..0000000 --- a/src/linux/tools/testing/selftests/timers/.gitignore +++ /dev/null @@ -1,19 +0,0 @@ -alarmtimer-suspend -change_skew -clocksource-switch -inconsistency-check -leap-a-day -leapcrash -mqueue-lat -nanosleep -nsleep-lat -posix_timers -raw_skew -rtctest -set-2038 -set-tai -set-timer-lat -skew_consistency -threadtest -valid-adjtimex -adjtick diff --git a/src/linux/tools/testing/selftests/vDSO/.gitignore b/src/linux/tools/testing/selftests/vDSO/.gitignore deleted file mode 100644 index 133bf9e..0000000 --- a/src/linux/tools/testing/selftests/vDSO/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -vdso_test -vdso_standalone_test_x86 diff --git a/src/linux/tools/testing/selftests/vm/.gitignore b/src/linux/tools/testing/selftests/vm/.gitignore deleted file mode 100644 index 142c565..0000000 --- a/src/linux/tools/testing/selftests/vm/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -hugepage-mmap -hugepage-shm -map_hugetlb -thuge-gen -compaction_test -mlock2-tests -on-fault-limit -transhuge-stress -userfaultfd -mlock-intersect-test diff --git a/src/linux/tools/testing/selftests/watchdog/.gitignore b/src/linux/tools/testing/selftests/watchdog/.gitignore deleted file mode 100644 index 5aac515..0000000 --- a/src/linux/tools/testing/selftests/watchdog/.gitignore +++ /dev/null @@ -1 +0,0 @@ -watchdog-test diff --git a/src/linux/tools/testing/selftests/x86/.gitignore b/src/linux/tools/testing/selftests/x86/.gitignore deleted file mode 100644 index 15034fe..0000000 --- a/src/linux/tools/testing/selftests/x86/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*_32 -*_64 diff --git a/src/linux/tools/thermal/tmon/.gitignore b/src/linux/tools/thermal/tmon/.gitignore deleted file mode 100644 index 06e96be..0000000 --- a/src/linux/tools/thermal/tmon/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/tmon diff --git a/src/linux/tools/usb/usbip/.gitignore b/src/linux/tools/usb/usbip/.gitignore deleted file mode 100644 index 9aad9e3..0000000 --- a/src/linux/tools/usb/usbip/.gitignore +++ /dev/null @@ -1,28 +0,0 @@ -Makefile -Makefile.in -aclocal.m4 -autom4te.cache/ -config.guess -config.h -config.h.in -config.log -config.status -config.sub -configure -depcomp -install-sh -libsrc/Makefile -libsrc/Makefile.in -libtool -ltmain.sh -missing -src/Makefile -src/Makefile.in -stamp-h1 -libsrc/libusbip.la -libsrc/libusbip_la-names.lo -libsrc/libusbip_la-usbip_common.lo -libsrc/libusbip_la-usbip_host_driver.lo -libsrc/libusbip_la-vhci_driver.lo -src/usbip -src/usbipd diff --git a/src/linux/tools/virtio/.gitignore b/src/linux/tools/virtio/.gitignore deleted file mode 100644 index 1cfbb01..0000000 --- a/src/linux/tools/virtio/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.d -virtio_test -vringh_test diff --git a/src/linux/tools/vm/.gitignore b/src/linux/tools/vm/.gitignore deleted file mode 100644 index 44f095f..0000000 --- a/src/linux/tools/vm/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -slabinfo -page-types diff --git a/src/linux/usr/.gitignore b/src/linux/usr/.gitignore deleted file mode 100644 index 8e48117..0000000 --- a/src/linux/usr/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# -# Generated files -# -gen_init_cpio -initramfs_data.cpio -initramfs_data.cpio.gz -initramfs_data.cpio.bz2 -initramfs_data.cpio.lzma -initramfs_list -include diff --git a/src/linux/usr/Kconfig b/src/linux/usr/Kconfig deleted file mode 100644 index 572dcf7..0000000 --- a/src/linux/usr/Kconfig +++ /dev/null @@ -1,100 +0,0 @@ -# -# Configuration for initramfs -# - -config INITRAMFS_SOURCE - string "Initramfs source file(s)" - default "" - help - This can be either a single cpio archive with a .cpio suffix or a - space-separated list of directories and files for building the - initramfs image. A cpio archive should contain a filesystem archive - to be used as an initramfs image. Directories should contain a - filesystem layout to be included in the initramfs image. Files - should contain entries according to the format described by the - "usr/gen_init_cpio" program in the kernel tree. - - When multiple directories and files are specified then the - initramfs image will be the aggregate of all of them. - - See for more details. - - If you are not sure, leave it blank. - -config INITRAMFS_ROOT_UID - int "User ID to map to 0 (user root)" - depends on INITRAMFS_SOURCE!="" - default "0" - help - This setting is only meaningful if the INITRAMFS_SOURCE is - contains a directory. Setting this user ID (UID) to something - other than "0" will cause all files owned by that UID to be - owned by user root in the initial ramdisk image. - - If you are not sure, leave it set to "0". - -config INITRAMFS_ROOT_GID - int "Group ID to map to 0 (group root)" - depends on INITRAMFS_SOURCE!="" - default "0" - help - This setting is only meaningful if the INITRAMFS_SOURCE is - contains a directory. Setting this group ID (GID) to something - other than "0" will cause all files owned by that GID to be - owned by group root in the initial ramdisk image. - - If you are not sure, leave it set to "0". - -config RD_GZIP - bool "Support initial ramdisks compressed using gzip" - depends on BLK_DEV_INITRD - default y - select DECOMPRESS_GZIP - help - Support loading of a gzip encoded initial ramdisk or cpio buffer. - If unsure, say Y. - -config RD_BZIP2 - bool "Support initial ramdisks compressed using bzip2" - default y - depends on BLK_DEV_INITRD - select DECOMPRESS_BZIP2 - help - Support loading of a bzip2 encoded initial ramdisk or cpio buffer - If unsure, say N. - -config RD_LZMA - bool "Support initial ramdisks compressed using LZMA" - default y - depends on BLK_DEV_INITRD - select DECOMPRESS_LZMA - help - Support loading of a LZMA encoded initial ramdisk or cpio buffer - If unsure, say N. - -config RD_XZ - bool "Support initial ramdisks compressed using XZ" - depends on BLK_DEV_INITRD - default y - select DECOMPRESS_XZ - help - Support loading of a XZ encoded initial ramdisk or cpio buffer. - If unsure, say N. - -config RD_LZO - bool "Support initial ramdisks compressed using LZO" - default y - depends on BLK_DEV_INITRD - select DECOMPRESS_LZO - help - Support loading of a LZO encoded initial ramdisk or cpio buffer - If unsure, say N. - -config RD_LZ4 - bool "Support initial ramdisks compressed using LZ4" - default y - depends on BLK_DEV_INITRD - select DECOMPRESS_LZ4 - help - Support loading of a LZ4 encoded initial ramdisk or cpio buffer - If unsure, say N. diff --git a/src/linux/usr/Makefile b/src/linux/usr/Makefile deleted file mode 100644 index e767f01..0000000 --- a/src/linux/usr/Makefile +++ /dev/null @@ -1,74 +0,0 @@ -# -# kbuild file for usr/ - including initramfs image -# - -klibcdirs:; -PHONY += klibcdirs - - -# Bzip2 -suffix_$(CONFIG_RD_BZIP2) = .bz2 - -# Lzma -suffix_$(CONFIG_RD_LZMA) = .lzma - -# XZ -suffix_$(CONFIG_RD_XZ) = .xz - -# Lzo -suffix_$(CONFIG_RD_LZO) = .lzo - -# Lz4 -suffix_$(CONFIG_RD_LZ4) = .lz4 - -# Gzip -suffix_$(CONFIG_RD_GZIP) = .gz - -AFLAGS_initramfs_data.o += -DINITRAMFS_IMAGE="usr/initramfs_data.cpio$(suffix_y)" - -# Generate builtin.o based on initramfs_data.o -obj-$(CONFIG_BLK_DEV_INITRD) := initramfs_data.o - -# initramfs_data.o contains the compressed initramfs_data.cpio image. -# The image is included using .incbin, a dependency which is not -# tracked automatically. -$(obj)/initramfs_data.o: $(obj)/initramfs_data.cpio$(suffix_y) FORCE - -##### -# Generate the initramfs cpio archive - -hostprogs-y := gen_init_cpio -initramfs := $(CONFIG_SHELL) $(srctree)/scripts/gen_initramfs_list.sh -ramfs-input := $(if $(filter-out "",$(CONFIG_INITRAMFS_SOURCE)), \ - $(shell echo $(CONFIG_INITRAMFS_SOURCE)),-d) -ramfs-args := \ - $(if $(CONFIG_INITRAMFS_ROOT_UID), -u $(CONFIG_INITRAMFS_ROOT_UID)) \ - $(if $(CONFIG_INITRAMFS_ROOT_GID), -g $(CONFIG_INITRAMFS_ROOT_GID)) - -# .initramfs_data.cpio.d is used to identify all files included -# in initramfs and to detect if any files are added/removed. -# Removed files are identified by directory timestamp being updated -# The dependency list is generated by gen_initramfs.sh -l -ifneq ($(wildcard $(obj)/.initramfs_data.cpio.d),) - include $(obj)/.initramfs_data.cpio.d -endif - -quiet_cmd_initfs = GEN $@ - cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input) - -targets := initramfs_data.cpio.gz initramfs_data.cpio.bz2 \ - initramfs_data.cpio.lzma initramfs_data.cpio.xz \ - initramfs_data.cpio.lzo initramfs_data.cpio.lz4 \ - initramfs_data.cpio -# do not try to update files included in initramfs -$(deps_initramfs): ; - -$(deps_initramfs): klibcdirs -# We rebuild initramfs_data.cpio if: -# 1) Any included file is newer then initramfs_data.cpio -# 2) There are changes in which files are included (added or deleted) -# 3) If gen_init_cpio are newer than initramfs_data.cpio -# 4) arguments to gen_initramfs.sh changes -$(obj)/initramfs_data.cpio$(suffix_y): $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs - $(Q)$(initramfs) -l $(ramfs-input) > $(obj)/.initramfs_data.cpio.d - $(call if_changed,initfs) diff --git a/src/linux/virt/Makefile b/src/linux/virt/Makefile deleted file mode 100644 index be78347..0000000 --- a/src/linux/virt/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-y += lib/ diff --git a/src/linux/virt/lib/Kconfig b/src/linux/virt/lib/Kconfig deleted file mode 100644 index 89a414f..0000000 --- a/src/linux/virt/lib/Kconfig +++ /dev/null @@ -1,2 +0,0 @@ -config IRQ_BYPASS_MANAGER - tristate diff --git a/src/linux/virt/lib/Makefile b/src/linux/virt/lib/Makefile deleted file mode 100644 index 901228d..0000000 --- a/src/linux/virt/lib/Makefile +++ /dev/null @@ -1 +0,0 @@ -obj-$(CONFIG_IRQ_BYPASS_MANAGER) += irqbypass.o